diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b563059ecd5aedccdb100dee02ec0fa1d16164d1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openacc/cupti_openacc.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openacc/cupti_openacc.h new file mode 100644 index 0000000000000000000000000000000000000000..b7ea50da7beb2187e77f7606dd70faed0e4b4add --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openacc/cupti_openacc.h @@ -0,0 +1,98 @@ +/* + * Copyright 2017 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#include + +#if !defined(_CUPTI_OPENACC_H_) +#define _CUPTI_OPENACC_H_ + +#ifndef CUPTIAPI +#ifdef _WIN32 +#define CUPTIAPI __stdcall +#else +#define CUPTIAPI +#endif +#endif + +#if defined(__LP64__) +#define CUPTILP64 1 +#elif defined(_WIN64) +#define CUPTILP64 1 +#else +#undef CUPTILP64 +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \brief Initialize OpenACC support + * + * \param profRegister function of type acc_prof_reg as obtained from acc_register_library + * \param profUnregister function of type acc_prof_reg as obtained from acc_register_library + * \param profLookup function of type acc_prof_lookup as obtained from acc_register_library + */ +CUptiResult CUPTIAPI +cuptiOpenACCInitialize(void *profRegister, void *profUnregister, void *profLookup); + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /*_CUPTI_OPENACC_H_*/ + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openmp/cupti_openmp.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openmp/cupti_openmp.h new file mode 100644 index 0000000000000000000000000000000000000000..303dd42878fb02774d872c197ccc27b17f2af69e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openmp/cupti_openmp.h @@ -0,0 +1,100 @@ +/* + * Copyright 2018 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#include +#include "Openmp/omp-tools.h" + +#if !defined(_CUPTI_OPENMP_H_) +#define _CUPTI_OPENMP_H_ + +#ifndef CUPTIAPI +#ifdef _WIN32 +#define CUPTIAPI __stdcall +#else +#define CUPTIAPI +#endif +#endif + +#if defined(__LP64__) +#define CUPTILP64 1 +#elif defined(_WIN64) +#define CUPTILP64 1 +#else +#undef CUPTILP64 +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \brief Initialize OPENMP support (deprecated, used before OpenMP 5.0) + * + */ +int CUPTIAPI cuptiOpenMpInitialize(ompt_function_lookup_t ompt_fn_lookup, const char *runtime_version, unsigned int ompt_version); + +/** + * \brief Initialize OPENMP support + * + */ +int CUPTIAPI cuptiOpenMpInitialize_v2(ompt_function_lookup_t lookup, int initial_device_num, ompt_data_t *tool_data); + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /*_CUPTI_OPENMP_H_*/ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openmp/omp-tools.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openmp/omp-tools.h new file mode 100644 index 0000000000000000000000000000000000000000..276967d07e8f8c0f7686e5b3b15151edf2415ae7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/Openmp/omp-tools.h @@ -0,0 +1,1083 @@ +/* + * include/50/omp-tools.h.var + */ + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.txt for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __OMPT__ +#define __OMPT__ + +/***************************************************************************** + * system include files + *****************************************************************************/ + +#include +#include + +/***************************************************************************** + * iteration macros + *****************************************************************************/ + +#define FOREACH_OMPT_INQUIRY_FN(macro) \ + macro (ompt_enumerate_states) \ + macro (ompt_enumerate_mutex_impls) \ + \ + macro (ompt_set_callback) \ + macro (ompt_get_callback) \ + \ + macro (ompt_get_state) \ + \ + macro (ompt_get_parallel_info) \ + macro (ompt_get_task_info) \ + macro (ompt_get_task_memory) \ + macro (ompt_get_thread_data) \ + macro (ompt_get_unique_id) \ + macro (ompt_finalize_tool) \ + \ + macro(ompt_get_num_procs) \ + macro(ompt_get_num_places) \ + macro(ompt_get_place_proc_ids) \ + macro(ompt_get_place_num) \ + macro(ompt_get_partition_place_nums) \ + macro(ompt_get_proc_id) \ + \ + macro(ompt_get_target_info) \ + macro(ompt_get_num_devices) + +#define FOREACH_OMPT_STATE(macro) \ + \ + /* first available state */ \ + macro (ompt_state_undefined, 0x102) /* undefined thread state */ \ + \ + /* work states (0..15) */ \ + macro (ompt_state_work_serial, 0x000) /* working outside parallel */ \ + macro (ompt_state_work_parallel, 0x001) /* working within parallel */ \ + macro (ompt_state_work_reduction, 0x002) /* performing a reduction */ \ + \ + /* barrier wait states (16..31) */ \ + macro (ompt_state_wait_barrier, 0x010) /* waiting at a barrier */ \ + macro (ompt_state_wait_barrier_implicit_parallel, 0x011) \ + /* implicit barrier at the end of parallel region */\ + macro (ompt_state_wait_barrier_implicit_workshare, 0x012) \ + /* implicit barrier at the end of worksharing */ \ + macro (ompt_state_wait_barrier_implicit, 0x013) /* implicit barrier */ \ + macro (ompt_state_wait_barrier_explicit, 0x014) /* explicit barrier */ \ + \ + /* task wait states (32..63) */ \ + macro (ompt_state_wait_taskwait, 0x020) /* waiting at a taskwait */ \ + macro (ompt_state_wait_taskgroup, 0x021) /* waiting at a taskgroup */ \ + \ + /* mutex wait states (64..127) */ \ + macro (ompt_state_wait_mutex, 0x040) \ + macro (ompt_state_wait_lock, 0x041) /* waiting for lock */ \ + macro (ompt_state_wait_critical, 0x042) /* waiting for critical */ \ + macro (ompt_state_wait_atomic, 0x043) /* waiting for atomic */ \ + macro (ompt_state_wait_ordered, 0x044) /* waiting for ordered */ \ + \ + /* target wait states (128..255) */ \ + macro (ompt_state_wait_target, 0x080) /* waiting for target region */ \ + macro (ompt_state_wait_target_map, 0x081) /* waiting for target data mapping operation */ \ + macro (ompt_state_wait_target_update, 0x082) /* waiting for target update operation */ \ + \ + /* misc (256..511) */ \ + macro (ompt_state_idle, 0x100) /* waiting for work */ \ + macro (ompt_state_overhead, 0x101) /* overhead excluding wait states */ \ + \ + /* implementation-specific states (512..) */ + + +#define FOREACH_KMP_MUTEX_IMPL(macro) \ + macro (kmp_mutex_impl_none, 0) /* unknown implementation */ \ + macro (kmp_mutex_impl_spin, 1) /* based on spin */ \ + macro (kmp_mutex_impl_queuing, 2) /* based on some fair policy */ \ + macro (kmp_mutex_impl_speculative, 3) /* based on HW-supported speculation */ + +#define FOREACH_OMPT_EVENT(macro) \ + \ + /*--- Mandatory Events ---*/ \ + macro (ompt_callback_thread_begin, ompt_callback_thread_begin_t, 1) /* thread begin */ \ + macro (ompt_callback_thread_end, ompt_callback_thread_end_t, 2) /* thread end */ \ + \ + macro (ompt_callback_parallel_begin, ompt_callback_parallel_begin_t, 3) /* parallel begin */ \ + macro (ompt_callback_parallel_end, ompt_callback_parallel_end_t, 4) /* parallel end */ \ + \ + macro (ompt_callback_task_create, ompt_callback_task_create_t, 5) /* task begin */ \ + macro (ompt_callback_task_schedule, ompt_callback_task_schedule_t, 6) /* task schedule */ \ + macro (ompt_callback_implicit_task, ompt_callback_implicit_task_t, 7) /* implicit task */ \ + \ + macro (ompt_callback_target, ompt_callback_target_t, 8) /* target */ \ + macro (ompt_callback_target_data_op, ompt_callback_target_data_op_t, 9) /* target data op */ \ + macro (ompt_callback_target_submit, ompt_callback_target_submit_t, 10) /* target submit */ \ + \ + macro (ompt_callback_control_tool, ompt_callback_control_tool_t, 11) /* control tool */ \ + \ + macro (ompt_callback_device_initialize, ompt_callback_device_initialize_t, 12) /* device initialize */ \ + macro (ompt_callback_device_finalize, ompt_callback_device_finalize_t, 13) /* device finalize */ \ + \ + macro (ompt_callback_device_load, ompt_callback_device_load_t, 14) /* device load */ \ + macro (ompt_callback_device_unload, ompt_callback_device_unload_t, 15) /* device unload */ \ + \ + /* Optional Events */ \ + macro (ompt_callback_sync_region_wait, ompt_callback_sync_region_t, 16) /* sync region wait begin or end */ \ + \ + macro (ompt_callback_mutex_released, ompt_callback_mutex_t, 17) /* mutex released */ \ + \ + macro (ompt_callback_dependences, ompt_callback_dependences_t, 18) /* report task dependences */ \ + macro (ompt_callback_task_dependence, ompt_callback_task_dependence_t, 19) /* report task dependence */ \ + \ + macro (ompt_callback_work, ompt_callback_work_t, 20) /* task at work begin or end */ \ + \ + macro (ompt_callback_master, ompt_callback_master_t, 21) /* task at master begin or end */ \ + \ + macro (ompt_callback_target_map, ompt_callback_target_map_t, 22) /* target map */ \ + \ + macro (ompt_callback_sync_region, ompt_callback_sync_region_t, 23) /* sync region begin or end */ \ + \ + macro (ompt_callback_lock_init, ompt_callback_mutex_acquire_t, 24) /* lock init */ \ + macro (ompt_callback_lock_destroy, ompt_callback_mutex_t, 25) /* lock destroy */ \ + \ + macro (ompt_callback_mutex_acquire, ompt_callback_mutex_acquire_t, 26) /* mutex acquire */ \ + macro (ompt_callback_mutex_acquired, ompt_callback_mutex_t, 27) /* mutex acquired */ \ + \ + macro (ompt_callback_nest_lock, ompt_callback_nest_lock_t, 28) /* nest lock */ \ + \ + macro (ompt_callback_flush, ompt_callback_flush_t, 29) /* after executing flush */ \ + \ + macro (ompt_callback_cancel, ompt_callback_cancel_t, 30) /* cancel innermost binding region */ \ + \ + macro (ompt_callback_reduction, ompt_callback_sync_region_t, 31) /* reduction */ \ + \ + macro (ompt_callback_dispatch, ompt_callback_dispatch_t, 32) /* dispatch of work */ + +/***************************************************************************** + * implementation specific types + *****************************************************************************/ + +typedef enum kmp_mutex_impl_t { +#define kmp_mutex_impl_macro(impl, code) impl = code, + FOREACH_KMP_MUTEX_IMPL(kmp_mutex_impl_macro) +#undef kmp_mutex_impl_macro +} kmp_mutex_impl_t; + +/***************************************************************************** + * definitions generated from spec + *****************************************************************************/ + +typedef enum ompt_callbacks_t { + ompt_callback_thread_begin = 1, + ompt_callback_thread_end = 2, + ompt_callback_parallel_begin = 3, + ompt_callback_parallel_end = 4, + ompt_callback_task_create = 5, + ompt_callback_task_schedule = 6, + ompt_callback_implicit_task = 7, + ompt_callback_target = 8, + ompt_callback_target_data_op = 9, + ompt_callback_target_submit = 10, + ompt_callback_control_tool = 11, + ompt_callback_device_initialize = 12, + ompt_callback_device_finalize = 13, + ompt_callback_device_load = 14, + ompt_callback_device_unload = 15, + ompt_callback_sync_region_wait = 16, + ompt_callback_mutex_released = 17, + ompt_callback_dependences = 18, + ompt_callback_task_dependence = 19, + ompt_callback_work = 20, + ompt_callback_master = 21, + ompt_callback_target_map = 22, + ompt_callback_sync_region = 23, + ompt_callback_lock_init = 24, + ompt_callback_lock_destroy = 25, + ompt_callback_mutex_acquire = 26, + ompt_callback_mutex_acquired = 27, + ompt_callback_nest_lock = 28, + ompt_callback_flush = 29, + ompt_callback_cancel = 30, + ompt_callback_reduction = 31, + ompt_callback_dispatch = 32 +} ompt_callbacks_t; + +typedef enum ompt_record_t { + ompt_record_ompt = 1, + ompt_record_native = 2, + ompt_record_invalid = 3 +} ompt_record_t; + +typedef enum ompt_record_native_t { + ompt_record_native_info = 1, + ompt_record_native_event = 2 +} ompt_record_native_t; + +typedef enum ompt_set_result_t { + ompt_set_error = 0, + ompt_set_never = 1, + ompt_set_impossible = 2, + ompt_set_sometimes = 3, + ompt_set_sometimes_paired = 4, + ompt_set_always = 5 +} ompt_set_result_t; + +typedef uint64_t ompt_id_t; + +typedef uint64_t ompt_device_time_t; + +typedef uint64_t ompt_buffer_cursor_t; + +typedef enum ompt_thread_t { + ompt_thread_initial = 1, + ompt_thread_worker = 2, + ompt_thread_other = 3, + ompt_thread_unknown = 4 +} ompt_thread_t; + +typedef enum ompt_scope_endpoint_t { + ompt_scope_begin = 1, + ompt_scope_end = 2 +} ompt_scope_endpoint_t; + +typedef enum ompt_dispatch_t { + ompt_dispatch_iteration = 1, + ompt_dispatch_section = 2 +} ompt_dispatch_t; + +typedef enum ompt_sync_region_t { + ompt_sync_region_barrier = 1, + ompt_sync_region_barrier_implicit = 2, + ompt_sync_region_barrier_explicit = 3, + ompt_sync_region_barrier_implementation = 4, + ompt_sync_region_taskwait = 5, + ompt_sync_region_taskgroup = 6, + ompt_sync_region_reduction = 7 +} ompt_sync_region_t; + +typedef enum ompt_target_data_op_t { + ompt_target_data_alloc = 1, + ompt_target_data_transfer_to_device = 2, + ompt_target_data_transfer_from_device = 3, + ompt_target_data_delete = 4, + ompt_target_data_associate = 5, + ompt_target_data_disassociate = 6 +} ompt_target_data_op_t; + +typedef enum ompt_work_t { + ompt_work_loop = 1, + ompt_work_sections = 2, + ompt_work_single_executor = 3, + ompt_work_single_other = 4, + ompt_work_workshare = 5, + ompt_work_distribute = 6, + ompt_work_taskloop = 7 +} ompt_work_t; + +typedef enum ompt_mutex_t { + ompt_mutex_lock = 1, + ompt_mutex_test_lock = 2, + ompt_mutex_nest_lock = 3, + ompt_mutex_test_nest_lock = 4, + ompt_mutex_critical = 5, + ompt_mutex_atomic = 6, + ompt_mutex_ordered = 7 +} ompt_mutex_t; + +typedef enum ompt_native_mon_flag_t { + ompt_native_data_motion_explicit = 0x01, + ompt_native_data_motion_implicit = 0x02, + ompt_native_kernel_invocation = 0x04, + ompt_native_kernel_execution = 0x08, + ompt_native_driver = 0x10, + ompt_native_runtime = 0x20, + ompt_native_overhead = 0x40, + ompt_native_idleness = 0x80 +} ompt_native_mon_flag_t; + +typedef enum ompt_task_flag_t { + ompt_task_initial = 0x00000001, + ompt_task_implicit = 0x00000002, + ompt_task_explicit = 0x00000004, + ompt_task_target = 0x00000008, + ompt_task_undeferred = 0x08000000, + ompt_task_untied = 0x10000000, + ompt_task_final = 0x20000000, + ompt_task_mergeable = 0x40000000, + ompt_task_merged = 0x80000000 +} ompt_task_flag_t; + +typedef enum ompt_task_status_t { + ompt_task_complete = 1, + ompt_task_yield = 2, + ompt_task_cancel = 3, + ompt_task_detach = 4, + ompt_task_early_fulfill = 5, + ompt_task_late_fulfill = 6, + ompt_task_switch = 7 +} ompt_task_status_t; + +typedef enum ompt_target_t { + ompt_target = 1, + ompt_target_enter_data = 2, + ompt_target_exit_data = 3, + ompt_target_update = 4 +} ompt_target_t; + +typedef enum ompt_parallel_flag_t { + ompt_parallel_invoker_program = 0x00000001, + ompt_parallel_invoker_runtime = 0x00000002, + ompt_parallel_league = 0x40000000, + ompt_parallel_team = 0x80000000 +} ompt_parallel_flag_t; + +typedef enum ompt_target_map_flag_t { + ompt_target_map_flag_to = 0x01, + ompt_target_map_flag_from = 0x02, + ompt_target_map_flag_alloc = 0x04, + ompt_target_map_flag_release = 0x08, + ompt_target_map_flag_delete = 0x10, + ompt_target_map_flag_implicit = 0x20 +} ompt_target_map_flag_t; + +typedef enum ompt_dependence_type_t { + ompt_dependence_type_in = 1, + ompt_dependence_type_out = 2, + ompt_dependence_type_inout = 3, + ompt_dependence_type_mutexinoutset = 4, + ompt_dependence_type_source = 5, + ompt_dependence_type_sink = 6 +} ompt_dependence_type_t; + +typedef enum ompt_cancel_flag_t { + ompt_cancel_parallel = 0x01, + ompt_cancel_sections = 0x02, + ompt_cancel_loop = 0x04, + ompt_cancel_taskgroup = 0x08, + ompt_cancel_activated = 0x10, + ompt_cancel_detected = 0x20, + ompt_cancel_discarded_task = 0x40 +} ompt_cancel_flag_t; + +typedef uint64_t ompt_hwid_t; + +typedef uint64_t ompt_wait_id_t; + +typedef enum ompt_frame_flag_t { + ompt_frame_runtime = 0x00, + ompt_frame_application = 0x01, + ompt_frame_cfa = 0x10, + ompt_frame_framepointer = 0x20, + ompt_frame_stackaddress = 0x30 +} ompt_frame_flag_t; + +typedef enum ompt_state_t { + ompt_state_work_serial = 0x000, + ompt_state_work_parallel = 0x001, + ompt_state_work_reduction = 0x002, + + ompt_state_wait_barrier = 0x010, + ompt_state_wait_barrier_implicit_parallel = 0x011, + ompt_state_wait_barrier_implicit_workshare = 0x012, + ompt_state_wait_barrier_implicit = 0x013, + ompt_state_wait_barrier_explicit = 0x014, + + ompt_state_wait_taskwait = 0x020, + ompt_state_wait_taskgroup = 0x021, + + ompt_state_wait_mutex = 0x040, + ompt_state_wait_lock = 0x041, + ompt_state_wait_critical = 0x042, + ompt_state_wait_atomic = 0x043, + ompt_state_wait_ordered = 0x044, + + ompt_state_wait_target = 0x080, + ompt_state_wait_target_map = 0x081, + ompt_state_wait_target_update = 0x082, + + ompt_state_idle = 0x100, + ompt_state_overhead = 0x101, + ompt_state_undefined = 0x102 +} ompt_state_t; + +typedef uint64_t (*ompt_get_unique_id_t) (void); + +typedef uint64_t ompd_size_t; + +typedef uint64_t ompd_wait_id_t; + +typedef uint64_t ompd_addr_t; +typedef int64_t ompd_word_t; +typedef uint64_t ompd_seg_t; + +typedef uint64_t ompd_device_t; + +typedef uint64_t ompd_thread_id_t; + +typedef enum ompd_scope_t { + ompd_scope_global = 1, + ompd_scope_address_space = 2, + ompd_scope_thread = 3, + ompd_scope_parallel = 4, + ompd_scope_implicit_task = 5, + ompd_scope_task = 6 +} ompd_scope_t; + +typedef uint64_t ompd_icv_id_t; + +typedef enum ompd_rc_t { + ompd_rc_ok = 0, + ompd_rc_unavailable = 1, + ompd_rc_stale_handle = 2, + ompd_rc_bad_input = 3, + ompd_rc_error = 4, + ompd_rc_unsupported = 5, + ompd_rc_needs_state_tracking = 6, + ompd_rc_incompatible = 7, + ompd_rc_device_read_error = 8, + ompd_rc_device_write_error = 9, + ompd_rc_nomem = 10, +} ompd_rc_t; + +typedef void (*ompt_interface_fn_t) (void); + +typedef ompt_interface_fn_t (*ompt_function_lookup_t) ( + const char *interface_function_name +); + +typedef union ompt_data_t { + uint64_t value; + void *ptr; +} ompt_data_t; + +typedef struct ompt_frame_t { + ompt_data_t exit_frame; + ompt_data_t enter_frame; + int exit_frame_flags; + int enter_frame_flags; +} ompt_frame_t; + +typedef void (*ompt_callback_t) (void); + +typedef void ompt_device_t; + +typedef void ompt_buffer_t; + +typedef void (*ompt_callback_buffer_request_t) ( + int device_num, + ompt_buffer_t **buffer, + size_t *bytes +); + +typedef void (*ompt_callback_buffer_complete_t) ( + int device_num, + ompt_buffer_t *buffer, + size_t bytes, + ompt_buffer_cursor_t begin, + int buffer_owned +); + +typedef void (*ompt_finalize_t) ( + ompt_data_t *tool_data +); + +typedef int (*ompt_initialize_t) ( + ompt_function_lookup_t lookup, + int initial_device_num, + ompt_data_t *tool_data +); + +typedef struct ompt_start_tool_result_t { + ompt_initialize_t initialize; + ompt_finalize_t finalize; + ompt_data_t tool_data; +} ompt_start_tool_result_t; + +typedef struct ompt_record_abstract_t { + ompt_record_native_t rclass; + const char *type; + ompt_device_time_t start_time; + ompt_device_time_t end_time; + ompt_hwid_t hwid; +} ompt_record_abstract_t; + +typedef struct ompt_dependence_t { + ompt_data_t variable; + ompt_dependence_type_t dependence_type; +} ompt_dependence_t; + +typedef int (*ompt_enumerate_states_t) ( + int current_state, + int *next_state, + const char **next_state_name +); + +typedef int (*ompt_enumerate_mutex_impls_t) ( + int current_impl, + int *next_impl, + const char **next_impl_name +); + +typedef ompt_set_result_t (*ompt_set_callback_t) ( + ompt_callbacks_t event, + ompt_callback_t callback +); + +typedef int (*ompt_get_callback_t) ( + ompt_callbacks_t event, + ompt_callback_t *callback +); + +typedef ompt_data_t *(*ompt_get_thread_data_t) (void); + +typedef int (*ompt_get_num_procs_t) (void); + +typedef int (*ompt_get_num_places_t) (void); + +typedef int (*ompt_get_place_proc_ids_t) ( + int place_num, + int ids_size, + int *ids +); + +typedef int (*ompt_get_place_num_t) (void); + +typedef int (*ompt_get_partition_place_nums_t) ( + int place_nums_size, + int *place_nums +); + +typedef int (*ompt_get_proc_id_t) (void); + +typedef int (*ompt_get_state_t) ( + ompt_wait_id_t *wait_id +); + +typedef int (*ompt_get_parallel_info_t) ( + int ancestor_level, + ompt_data_t **parallel_data, + int *team_size +); + +typedef int (*ompt_get_task_info_t) ( + int ancestor_level, + int *flags, + ompt_data_t **task_data, + ompt_frame_t **task_frame, + ompt_data_t **parallel_data, + int *thread_num +); + +typedef int (*ompt_get_task_memory_t)( + void **addr, + size_t *size, + int block +); + +typedef int (*ompt_get_target_info_t) ( + uint64_t *device_num, + ompt_id_t *target_id, + ompt_id_t *host_op_id +); + +typedef int (*ompt_get_num_devices_t) (void); + +typedef void (*ompt_finalize_tool_t) (void); + +typedef int (*ompt_get_device_num_procs_t) ( + ompt_device_t *device +); + +typedef ompt_device_time_t (*ompt_get_device_time_t) ( + ompt_device_t *device +); + +typedef double (*ompt_translate_time_t) ( + ompt_device_t *device, + ompt_device_time_t time +); + +typedef ompt_set_result_t (*ompt_set_trace_ompt_t) ( + ompt_device_t *device, + unsigned int enable, + unsigned int etype +); + +typedef ompt_set_result_t (*ompt_set_trace_native_t) ( + ompt_device_t *device, + int enable, + int flags +); + +typedef int (*ompt_start_trace_t) ( + ompt_device_t *device, + ompt_callback_buffer_request_t request, + ompt_callback_buffer_complete_t complete +); + +typedef int (*ompt_pause_trace_t) ( + ompt_device_t *device, + int begin_pause +); + +typedef int (*ompt_flush_trace_t) ( + ompt_device_t *device +); + +typedef int (*ompt_stop_trace_t) ( + ompt_device_t *device +); + +typedef int (*ompt_advance_buffer_cursor_t) ( + ompt_device_t *device, + ompt_buffer_t *buffer, + size_t size, + ompt_buffer_cursor_t current, + ompt_buffer_cursor_t *next +); + +typedef ompt_record_t (*ompt_get_record_type_t) ( + ompt_buffer_t *buffer, + ompt_buffer_cursor_t current +); + +typedef void *(*ompt_get_record_native_t) ( + ompt_buffer_t *buffer, + ompt_buffer_cursor_t current, + ompt_id_t *host_op_id +); + +typedef ompt_record_abstract_t * +(*ompt_get_record_abstract_t) ( + void *native_record +); + +typedef void (*ompt_callback_thread_begin_t) ( + ompt_thread_t thread_type, + ompt_data_t *thread_data +); + +typedef struct ompt_record_thread_begin_t { + ompt_thread_t thread_type; +} ompt_record_thread_begin_t; + +typedef void (*ompt_callback_thread_end_t) ( + ompt_data_t *thread_data +); + +typedef void (*ompt_callback_parallel_begin_t) ( + ompt_data_t *encountering_task_data, + const ompt_frame_t *encountering_task_frame, + ompt_data_t *parallel_data, + unsigned int requested_parallelism, + int flags, + const void *codeptr_ra +); + +typedef struct ompt_record_parallel_begin_t { + ompt_id_t encountering_task_id; + ompt_id_t parallel_id; + unsigned int requested_parallelism; + int flags; + const void *codeptr_ra; +} ompt_record_parallel_begin_t; + +typedef void (*ompt_callback_parallel_end_t) ( + ompt_data_t *parallel_data, + ompt_data_t *encountering_task_data, + int flags, + const void *codeptr_ra +); + +typedef struct ompt_record_parallel_end_t { + ompt_id_t parallel_id; + ompt_id_t encountering_task_id; + int flags; + const void *codeptr_ra; +} ompt_record_parallel_end_t; + +typedef void (*ompt_callback_work_t) ( + ompt_work_t wstype, + ompt_scope_endpoint_t endpoint, + ompt_data_t *parallel_data, + ompt_data_t *task_data, + uint64_t count, + const void *codeptr_ra +); + +typedef struct ompt_record_work_t { + ompt_work_t wstype; + ompt_scope_endpoint_t endpoint; + ompt_id_t parallel_id; + ompt_id_t task_id; + uint64_t count; + const void *codeptr_ra; +} ompt_record_work_t; + +typedef void (*ompt_callback_dispatch_t) ( + ompt_data_t *parallel_data, + ompt_data_t *task_data, + ompt_dispatch_t kind, + ompt_data_t instance +); + +typedef struct ompt_record_dispatch_t { + ompt_id_t parallel_id; + ompt_id_t task_id; + ompt_dispatch_t kind; + ompt_data_t instance; +} ompt_record_dispatch_t; + +typedef void (*ompt_callback_task_create_t) ( + ompt_data_t *encountering_task_data, + const ompt_frame_t *encountering_task_frame, + ompt_data_t *new_task_data, + int flags, + int has_dependences, + const void *codeptr_ra +); + +typedef struct ompt_record_task_create_t { + ompt_id_t encountering_task_id; + ompt_id_t new_task_id; + int flags; + int has_dependences; + const void *codeptr_ra; +} ompt_record_task_create_t; + +typedef void (*ompt_callback_dependences_t) ( + ompt_data_t *task_data, + const ompt_dependence_t *deps, + int ndeps +); + +typedef struct ompt_record_dependences_t { + ompt_id_t task_id; + ompt_dependence_t dep; + int ndeps; +} ompt_record_dependences_t; + +typedef void (*ompt_callback_task_dependence_t) ( + ompt_data_t *src_task_data, + ompt_data_t *sink_task_data +); + +typedef struct ompt_record_task_dependence_t { + ompt_id_t src_task_id; + ompt_id_t sink_task_id; +} ompt_record_task_dependence_t; + +typedef void (*ompt_callback_task_schedule_t) ( + ompt_data_t *prior_task_data, + ompt_task_status_t prior_task_status, + ompt_data_t *next_task_data +); + +typedef struct ompt_record_task_schedule_t { + ompt_id_t prior_task_id; + ompt_task_status_t prior_task_status; + ompt_id_t next_task_id; +} ompt_record_task_schedule_t; + +typedef void (*ompt_callback_implicit_task_t) ( + ompt_scope_endpoint_t endpoint, + ompt_data_t *parallel_data, + ompt_data_t *task_data, + unsigned int actual_parallelism, + unsigned int index, + int flags +); + +typedef struct ompt_record_implicit_task_t { + ompt_scope_endpoint_t endpoint; + ompt_id_t parallel_id; + ompt_id_t task_id; + unsigned int actual_parallelism; + unsigned int index; + int flags; +} ompt_record_implicit_task_t; + +typedef void (*ompt_callback_master_t) ( + ompt_scope_endpoint_t endpoint, + ompt_data_t *parallel_data, + ompt_data_t *task_data, + const void *codeptr_ra +); + +typedef struct ompt_record_master_t { + ompt_scope_endpoint_t endpoint; + ompt_id_t parallel_id; + ompt_id_t task_id; + const void *codeptr_ra; +} ompt_record_master_t; + +typedef void (*ompt_callback_sync_region_t) ( + ompt_sync_region_t kind, + ompt_scope_endpoint_t endpoint, + ompt_data_t *parallel_data, + ompt_data_t *task_data, + const void *codeptr_ra +); + +typedef struct ompt_record_sync_region_t { + ompt_sync_region_t kind; + ompt_scope_endpoint_t endpoint; + ompt_id_t parallel_id; + ompt_id_t task_id; + const void *codeptr_ra; +} ompt_record_sync_region_t; + +typedef void (*ompt_callback_mutex_acquire_t) ( + ompt_mutex_t kind, + unsigned int hint, + unsigned int impl, + ompt_wait_id_t wait_id, + const void *codeptr_ra +); + +typedef struct ompt_record_mutex_acquire_t { + ompt_mutex_t kind; + unsigned int hint; + unsigned int impl; + ompt_wait_id_t wait_id; + const void *codeptr_ra; +} ompt_record_mutex_acquire_t; + +typedef void (*ompt_callback_mutex_t) ( + ompt_mutex_t kind, + ompt_wait_id_t wait_id, + const void *codeptr_ra +); + +typedef struct ompt_record_mutex_t { + ompt_mutex_t kind; + ompt_wait_id_t wait_id; + const void *codeptr_ra; +} ompt_record_mutex_t; + +typedef void (*ompt_callback_nest_lock_t) ( + ompt_scope_endpoint_t endpoint, + ompt_wait_id_t wait_id, + const void *codeptr_ra +); + +typedef struct ompt_record_nest_lock_t { + ompt_scope_endpoint_t endpoint; + ompt_wait_id_t wait_id; + const void *codeptr_ra; +} ompt_record_nest_lock_t; + +typedef void (*ompt_callback_flush_t) ( + ompt_data_t *thread_data, + const void *codeptr_ra +); + +typedef struct ompt_record_flush_t { + const void *codeptr_ra; +} ompt_record_flush_t; + +typedef void (*ompt_callback_cancel_t) ( + ompt_data_t *task_data, + int flags, + const void *codeptr_ra +); + +typedef struct ompt_record_cancel_t { + ompt_id_t task_id; + int flags; + const void *codeptr_ra; +} ompt_record_cancel_t; + +typedef void (*ompt_callback_device_initialize_t) ( + int device_num, + const char *type, + ompt_device_t *device, + ompt_function_lookup_t lookup, + const char *documentation +); + +typedef void (*ompt_callback_device_finalize_t) ( + int device_num +); + +typedef void (*ompt_callback_device_load_t) ( + int device_num, + const char *filename, + int64_t offset_in_file, + void *vma_in_file, + size_t bytes, + void *host_addr, + void *device_addr, + uint64_t module_id +); + +typedef void (*ompt_callback_device_unload_t) ( + int device_num, + uint64_t module_id +); + +typedef void (*ompt_callback_target_data_op_t) ( + ompt_id_t target_id, + ompt_id_t host_op_id, + ompt_target_data_op_t optype, + void *src_addr, + int src_device_num, + void *dest_addr, + int dest_device_num, + size_t bytes, + const void *codeptr_ra +); + +typedef struct ompt_record_target_data_op_t { + ompt_id_t host_op_id; + ompt_target_data_op_t optype; + void *src_addr; + int src_device_num; + void *dest_addr; + int dest_device_num; + size_t bytes; + ompt_device_time_t end_time; + const void *codeptr_ra; +} ompt_record_target_data_op_t; + +typedef void (*ompt_callback_target_t) ( + ompt_target_t kind, + ompt_scope_endpoint_t endpoint, + int device_num, + ompt_data_t *task_data, + ompt_id_t target_id, + const void *codeptr_ra +); + +typedef struct ompt_record_target_t { + ompt_target_t kind; + ompt_scope_endpoint_t endpoint; + int device_num; + ompt_id_t task_id; + ompt_id_t target_id; + const void *codeptr_ra; +} ompt_record_target_t; + +typedef void (*ompt_callback_target_map_t) ( + ompt_id_t target_id, + unsigned int nitems, + void **host_addr, + void **device_addr, + size_t *bytes, + unsigned int *mapping_flags, + const void *codeptr_ra +); + +typedef struct ompt_record_target_map_t { + ompt_id_t target_id; + unsigned int nitems; + void **host_addr; + void **device_addr; + size_t *bytes; + unsigned int *mapping_flags; + const void *codeptr_ra; +} ompt_record_target_map_t; + +typedef void (*ompt_callback_target_submit_t) ( + ompt_id_t target_id, + ompt_id_t host_op_id, + unsigned int requested_num_teams +); + +typedef struct ompt_record_target_kernel_t { + ompt_id_t host_op_id; + unsigned int requested_num_teams; + unsigned int granted_num_teams; + ompt_device_time_t end_time; +} ompt_record_target_kernel_t; + +typedef int (*ompt_callback_control_tool_t) ( + uint64_t command, + uint64_t modifier, + void *arg, + const void *codeptr_ra +); + +typedef struct ompt_record_control_tool_t { + uint64_t command; + uint64_t modifier; + const void *codeptr_ra; +} ompt_record_control_tool_t; + +typedef struct ompd_address_t { + ompd_seg_t segment; + ompd_addr_t address; +} ompd_address_t; + +typedef struct ompd_frame_info_t { + ompd_address_t frame_address; + ompd_word_t frame_flag; +} ompd_frame_info_t; + +typedef struct _ompd_aspace_handle ompd_address_space_handle_t; +typedef struct _ompd_thread_handle ompd_thread_handle_t; +typedef struct _ompd_parallel_handle ompd_parallel_handle_t; +typedef struct _ompd_task_handle ompd_task_handle_t; + +typedef struct _ompd_aspace_cont ompd_address_space_context_t; +typedef struct _ompd_thread_cont ompd_thread_context_t; + +typedef struct ompd_device_type_sizes_t { + uint8_t sizeof_char; + uint8_t sizeof_short; + uint8_t sizeof_int; + uint8_t sizeof_long; + uint8_t sizeof_long_long; + uint8_t sizeof_pointer; +} ompd_device_type_sizes_t; + +typedef struct ompt_record_ompt_t { + ompt_callbacks_t type; + ompt_device_time_t time; + ompt_id_t thread_id; + ompt_id_t target_id; + union { + ompt_record_thread_begin_t thread_begin; + ompt_record_parallel_begin_t parallel_begin; + ompt_record_parallel_end_t parallel_end; + ompt_record_work_t work; + ompt_record_dispatch_t dispatch; + ompt_record_task_create_t task_create; + ompt_record_dependences_t dependences; + ompt_record_task_dependence_t task_dependence; + ompt_record_task_schedule_t task_schedule; + ompt_record_implicit_task_t implicit_task; + ompt_record_master_t master; + ompt_record_sync_region_t sync_region; + ompt_record_mutex_acquire_t mutex_acquire; + ompt_record_mutex_t mutex; + ompt_record_nest_lock_t nest_lock; + ompt_record_flush_t flush; + ompt_record_cancel_t cancel; + ompt_record_target_t target; + ompt_record_target_data_op_t target_data_op; + ompt_record_target_map_t target_map; + ompt_record_target_kernel_t target_kernel; + ompt_record_control_tool_t control_tool; + } record; +} ompt_record_ompt_t; + +typedef ompt_record_ompt_t *(*ompt_get_record_ompt_t) ( + ompt_buffer_t *buffer, + ompt_buffer_cursor_t current +); + +#define ompt_id_none 0 +#define ompt_data_none {0} +#define ompt_time_none 0 +#define ompt_hwid_none 0 +#define ompt_addr_none ~0 +#define ompt_mutex_impl_none 0 +#define ompt_wait_id_none 0 + +#define ompd_segment_none 0 + +#endif /* __OMPT__ */ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78056707cc7b1bc06731c2d6b118284bb13bcf2f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cuda_stdint.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cuda_stdint.h new file mode 100644 index 0000000000000000000000000000000000000000..8a9814410e4b6fb4f07ad9edc8394e956b77dbcd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cuda_stdint.h @@ -0,0 +1,112 @@ +/* + * Copyright 2009-2017 NVIDIA Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __cuda_stdint_h__ +#define __cuda_stdint_h__ + +// Compiler-specific treatment for C99's stdint.h +// +// By default, this header will use the standard headers (so it +// is your responsibility to make sure they are available), except +// on MSVC before Visual Studio 2010, when they were not provided. +// To support old MSVC, a few of the commonly-used definitions are +// provided here. If more definitions are needed, add them here, +// or replace these definitions with a complete implementation, +// such as the ones available from Google, Boost, or MSVC10. You +// can prevent the definition of any of these types (in order to +// use your own) by #defining CU_STDINT_TYPES_ALREADY_DEFINED. + +#if !defined(CU_STDINT_TYPES_ALREADY_DEFINED) + +// In VS including stdint.h forces the C++ runtime dep - provide an opt-out +// (CU_STDINT_VS_FORCE_NO_STDINT_H) for users that care (notably static +// cudart). +#if defined(_MSC_VER) && ((_MSC_VER < 1600) || defined(CU_STDINT_VS_FORCE_NO_STDINT_H)) + +// These definitions can be used with MSVC 8 and 9, +// which don't ship with stdint.h: + +typedef unsigned char uint8_t; + +typedef short int16_t; +typedef unsigned short uint16_t; + +// To keep it consistent with all MSVC build. define those types +// in the exact same way they are defined with the MSVC headers +#if defined(_MSC_VER) +typedef signed char int8_t; + +typedef int int32_t; +typedef unsigned int uint32_t; + +typedef long long int64_t; +typedef unsigned long long uint64_t; +#else +typedef char int8_t; + +typedef long int32_t; +typedef unsigned long uint32_t; + +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#endif + +#elif defined(__DJGPP__) + +// These definitions can be used when compiling +// C code with DJGPP, which only provides stdint.h +// when compiling C++ code with TR1 enabled. + +typedef char int8_t; +typedef unsigned char uint8_t; + +typedef short int16_t; +typedef unsigned short uint16_t; + +typedef long int32_t; +typedef unsigned long uint32_t; + +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#else + +// Use standard headers, as specified by C99 and C++ TR1. +// Known to be provided by: +// - gcc/glibc, supported by all versions of glibc +// - djgpp, supported since 2001 +// - MSVC, supported by Visual Studio 2010 and later + +#include + +#endif + +#endif // !defined(CU_STDINT_TYPES_ALREADY_DEFINED) + + +#endif // file guard diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti.h new file mode 100644 index 0000000000000000000000000000000000000000..be316531dcfd846bcea8feadf3604437ce2447a1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti.h @@ -0,0 +1,123 @@ +/* + * Copyright 2010-2017 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_H_) +#define _CUPTI_H_ + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifdef NOMINMAX +#include +#else +#define NOMINMAX +#include +#undef NOMINMAX +#endif +#endif + +#include +#include +#include + +/* Activity, callback, event and metric APIs */ +#include +#include +#include +#include + +/* Runtime, driver, and nvtx function identifiers */ +#include +#include +#include + +/* To support function parameter structures for obsoleted API. See + cuda.h for the actual definition of these structures. */ +typedef unsigned int CUdeviceptr_v1; +typedef struct CUDA_MEMCPY2D_v1_st { int dummy; } CUDA_MEMCPY2D_v1; +typedef struct CUDA_MEMCPY3D_v1_st { int dummy; } CUDA_MEMCPY3D_v1; +typedef struct CUDA_ARRAY_DESCRIPTOR_v1_st { int dummy; } CUDA_ARRAY_DESCRIPTOR_v1; +typedef struct CUDA_ARRAY3D_DESCRIPTOR_v1_st { int dummy; } CUDA_ARRAY3D_DESCRIPTOR_v1; + +/* Function parameter structures */ +#include +#include + +/* The following parameter structures cannot be included unless a + header that defines GL_VERSION is included before including them. + If these are needed then make sure such a header is included + already. */ +#ifdef GL_VERSION +#include +#include +#endif + +//#include + +/* The following parameter structures cannot be included by default as + they are not guaranteed to be available on all systems. Uncomment + the includes that are available, or use the include explicitly. */ +#if defined(__linux__) +//#include +//#include +#endif + +#ifdef _WIN32 +//#include +//#include +//#include +//#include +//#include +//#include +#endif + +#endif /*_CUPTI_H_*/ + + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_activity.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_activity.h new file mode 100644 index 0000000000000000000000000000000000000000..cdb6b76f8d66e986b20bd481fbeb0a12a791e5a5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_activity.h @@ -0,0 +1,8065 @@ +/* + * Copyright 2011-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_ACTIVITY_H_) +#define _CUPTI_ACTIVITY_H_ + +/** + * Deprecated APIs and structures have been moved to the + * header :doc: `cupti_activity_deprecated.h`, which is included at + * the bottom of this file. Header cupti_activity.h contains + * only the latest version of APIs and structures. + */ + +#include +#include +#include +#include +#include + +#if defined(CUPTI_DIRECTIVE_SUPPORT) +#include +#include +#endif + +#include + +#define CUPTI_UNIFIED_MEMORY_CPU_DEVICE_ID ((uint32_t) 0xFFFFFFFFU) +#define CUPTI_INVALID_CONTEXT_ID ((uint32_t) 0xFFFFFFFFU) +#define CUPTI_INVALID_STREAM_ID ((uint32_t) 0xFFFFFFFFU) +#define CUPTI_INVALID_CHANNEL_ID ((uint32_t) 0xFFFFFFFFU) + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +#define invalidNumaId ((uint32_t) 0xFFFFFFFF) + +/** + * \defgroup CUPTI_ACTIVITY_API CUPTI Activity API + * Functions, types, and enums that implement the CUPTI Activity API. + * @{ + */ + +/** + * \brief The kinds of activity records. + * + * Each activity record kind represents information about a GPU or an + * activity occurring on a CPU or GPU. Each kind is associated with a + * activity record structure that holds the information associated + * with the kind. + * \see CUpti_Activity + * \see CUpti_ActivityAPI + * \see CUpti_ActivityContext + * \see CUpti_ActivityContext2 + * \see CUpti_ActivityContext3 + * \see CUpti_ActivityDevice + * \see CUpti_ActivityDevice2 + * \see CUpti_ActivityDevice3 + * \see CUpti_ActivityDevice4 + * \see CUpti_ActivityDeviceAttribute + * \see CUpti_ActivityEvent + * \see CUpti_ActivityEventInstance + * \see CUpti_ActivityKernel + * \see CUpti_ActivityKernel2 + * \see CUpti_ActivityKernel3 + * \see CUpti_ActivityKernel4 + * \see CUpti_ActivityKernel5 + * \see CUpti_ActivityKernel6 + * \see CUpti_ActivityKernel7 + * \see CUpti_ActivityKernel8 + * \see CUpti_ActivityKernel9 + * \see CUpti_ActivityCdpKernel + * \see CUpti_ActivityPreemption + * \see CUpti_ActivityMemcpy + * \see CUpti_ActivityMemcpy3 + * \see CUpti_ActivityMemcpy4 + * \see CUpti_ActivityMemcpy5 + * \see CUpti_ActivityMemcpy6 + * \see CUpti_ActivityMemcpyPtoP + * \see CUpti_ActivityMemcpyPtoP2 + * \see CUpti_ActivityMemcpyPtoP3 + * \see CUpti_ActivityMemcpyPtoP4 + * \see CUpti_ActivityMemset + * \see CUpti_ActivityMemset2 + * \see CUpti_ActivityMemset3 + * \see CUpti_ActivityMemset4 + * \see CUpti_ActivityMemory + * \see CUpti_ActivityMemory2 + * \see CUpti_ActivityMemory3 + * \see CUpti_ActivityMemory4 + * \see CUpti_ActivityMemoryPool + * \see CUpti_ActivityMemoryPool2 + * \see CUpti_ActivityMetric + * \see CUpti_ActivityMetricInstance + * \see CUpti_ActivityName + * \see CUpti_ActivityMarker + * \see CUpti_ActivityMarker2 + * \see CUpti_ActivityMarkerData + * \see CUpti_ActivitySourceLocator + * \see CUpti_ActivityGlobalAccess + * \see CUpti_ActivityGlobalAccess2 + * \see CUpti_ActivityGlobalAccess3 + * \see CUpti_ActivityBranch + * \see CUpti_ActivityBranch2 + * \see CUpti_ActivityOverhead3 + * \see CUpti_ActivityEnvironment + * \see CUpti_ActivityInstructionExecution + * \see CUpti_ActivityUnifiedMemoryCounter + * \see CUpti_ActivityFunction + * \see CUpti_ActivityModule + * \see CUpti_ActivitySharedAccess + * \see CUpti_ActivityPCSampling + * \see CUpti_ActivityPCSampling2 + * \see CUpti_ActivityPCSampling3 + * \see CUpti_ActivityPCSamplingRecordInfo + * \see CUpti_ActivityCudaEvent2 + * \see CUpti_ActivityStream + * \see CUpti_ActivitySynchronization2 + * \see CUpti_ActivityInstructionCorrelation + * \see CUpti_ActivityExternalCorrelation + * \see CUpti_ActivityUnifiedMemoryCounter3 + * \see CUpti_ActivityOpenAccData + * \see CUpti_ActivityOpenAccLaunch + * \see CUpti_ActivityOpenAccOther + * \see CUpti_ActivityOpenMp + * \see CUpti_ActivityNvLink + * \see CUpti_ActivityNvLink2 + * \see CUpti_ActivityNvLink3 + * \see CUpti_ActivityNvLink4 + * \see CUpti_ActivityPcie + * \see CUpti_ActivityConfidentialComputeRotation + */ + +typedef enum { + /** + * The activity record is invalid. + */ + CUPTI_ACTIVITY_KIND_INVALID = 0, + + /** + * A host<->host, host<->device, or device<->device memory copy. + * For peer to peer memory copy, use the kind CUPTI_ACTIVITY_KIND_MEMCPY2. + * The corresponding activity record structure is \ref + * CUpti_ActivityMemcpy6. + */ + CUPTI_ACTIVITY_KIND_MEMCPY = 1, + + /** + * A memory set executing on the GPU. The corresponding activity + * record structure is \ref CUpti_ActivityMemset4. + */ + CUPTI_ACTIVITY_KIND_MEMSET = 2, + + /** + * A kernel executing on the GPU. This activity kind may significantly change + * the overall performance characteristics of the application because all + * kernel executions are serialized on the GPU. Other activity kind for kernel + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL doesn't break kernel concurrency. + * The corresponding activity record structure is \ref CUpti_ActivityKernel9. + */ + CUPTI_ACTIVITY_KIND_KERNEL = 3, + + /** + * A CUDA driver API function execution. The corresponding activity + * record structure is \ref CUpti_ActivityAPI. + */ + CUPTI_ACTIVITY_KIND_DRIVER = 4, + + /** + * A CUDA runtime API function execution. The corresponding activity + * record structure is \ref CUpti_ActivityAPI. + */ + CUPTI_ACTIVITY_KIND_RUNTIME = 5, + + /** + * A performance counter (aka event) value. The corresponding activity record + * structure is \ref CUpti_ActivityEvent. This activity cannot be directly + * enabled or disabled. Information collected using the Event API. + * can be stored in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_EVENT = 6, + + /** + * A performance metric value. The corresponding activity record structure is + * \ref CUpti_ActivityMetric. This activity cannot be directly + * enabled or disabled. Information collected using the Metric API. + * can be stored in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_METRIC = 7, + + /** + * Information about a CUDA device. The corresponding activity record + * structure is \ref CUpti_ActivityDevice5. + */ + CUPTI_ACTIVITY_KIND_DEVICE = 8, + + /** + * Information about a CUDA context. The corresponding activity record + * structure is \ref CUpti_ActivityContext3. + */ + CUPTI_ACTIVITY_KIND_CONTEXT = 9, + + /** + * A kernel executing on the GPU. This activity kind doesn't break + * kernel concurrency. The corresponding activity record structure + * is \ref CUpti_ActivityKernel9. + */ + CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL = 10, + + /** + * Resource naming done via NVTX APIs for thread, device, context, etc. + * The corresponding activity record structure is \ref CUpti_ActivityName. + */ + CUPTI_ACTIVITY_KIND_NAME = 11, + + /** + * Instantaneous, start, or end NVTX marker. The corresponding activity + * record structure is \ref CUpti_ActivityMarker2. + */ + CUPTI_ACTIVITY_KIND_MARKER = 12, + + /** + * Extended, optional, data about a NVTX marker. User must enable + * CUPTI_ACTIVITY_KIND_MARKER as well to get records for marker data. + * The corresponding activity record structure is \ref CUpti_ActivityMarkerData. + */ + CUPTI_ACTIVITY_KIND_MARKER_DATA = 13, + + /** + * Source information about source level result. The corresponding + * activity record structure is \ref CUpti_ActivitySourceLocator. + * In CUDA 12.6, this kind is deprecated for Volta and later GPU architectures + * in favor of SASS Metric APIs from the header cupti_sass_metrics.h. + */ + CUPTI_ACTIVITY_KIND_SOURCE_LOCATOR = 14, + + /** + * Results for source-level global access. The + * corresponding activity record structure is \ref + * CUpti_ActivityGlobalAccess3. + * In CUDA 12.6, this kind is deprecated for Volta and later GPU architectures + * in favor of SASS Metric APIs from the header cupti_sass_metrics.h. + */ + CUPTI_ACTIVITY_KIND_GLOBAL_ACCESS = 15, + + /** + * Results for source-level branch. The corresponding + * activity record structure is \ref CUpti_ActivityBranch2. + * In CUDA 12.6, this kind is deprecated for Volta and later GPU architectures + * in favor of SASS Metric APIs from the header cupti_sass_metrics.h. + */ + CUPTI_ACTIVITY_KIND_BRANCH = 16, + + /** + * Overhead added by CUPTI, Compiler, CUDA driver etc. The + * corresponding activity record structure is + * \ref CUpti_ActivityOverhead3. + */ + CUPTI_ACTIVITY_KIND_OVERHEAD = 17, + + /** + * A CDP (CUDA Dynamic Parallel) kernel executing on the GPU. The + * corresponding activity record structure is \ref + * CUpti_ActivityCdpKernel. This activity cannot be directly + * enabled or disabled. It is enabled and disabled through + * concurrent kernel activity i.e. _CONCURRENT_KERNEL. + */ + CUPTI_ACTIVITY_KIND_CDP_KERNEL = 18, + /** + * Preemption activity record indicating a preemption of a CDP (CUDA + * Dynamic Parallel) kernel executing on the GPU. The corresponding + * activity record structure is \ref CUpti_ActivityPreemption. + */ + CUPTI_ACTIVITY_KIND_PREEMPTION = 19, + + /** + * Environment activity records indicating power, clock, thermal, + * etc. levels of the GPU. The corresponding activity record + * structure is \ref CUpti_ActivityEnvironment. + */ + CUPTI_ACTIVITY_KIND_ENVIRONMENT = 20, + + /** + * An performance counter value associated with a specific event domain + * instance. The corresponding activity record structure is \ref + * CUpti_ActivityEventInstance. This activity cannot be directly + * enabled or disabled. Information collected using the Event API. + * can be stored in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_EVENT_INSTANCE = 21, + + /** + * A peer to peer memory copy. The corresponding activity record + * structure is \ref CUpti_ActivityMemcpyPtoP4. + */ + CUPTI_ACTIVITY_KIND_MEMCPY2 = 22, + + /** + * A performance metric value associated with a specific metric domain + * instance. The corresponding activity record structure is \ref + * CUpti_ActivityMetricInstance. This activity cannot be directly + * enabled or disabled. Information collected using the Metric API. + * can be stored in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_METRIC_INSTANCE = 23, + + /** + * Results for source-level instruction execution. + * The corresponding activity record structure is \ref + * CUpti_ActivityInstructionExecution. + * In CUDA 12.6, this kind is deprecated for Volta and later GPU architectures + * in favor of SASS Metric APIs from the header cupti_sass_metrics.h. + */ + CUPTI_ACTIVITY_KIND_INSTRUCTION_EXECUTION = 24, + + /** + * Unified Memory counter record. The corresponding activity + * record structure is \ref CUpti_ActivityUnifiedMemoryCounter3. + */ + CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER = 25, + + /** + * Device global/function record. The corresponding activity + * record structure is \ref CUpti_ActivityFunction. + */ + CUPTI_ACTIVITY_KIND_FUNCTION = 26, + + /** + * CUDA Module record. The corresponding activity + * record structure is \ref CUpti_ActivityModule. + * This activity cannot be directly enabled or disabled. + * Information collected using the module callback can be + * be stored in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_MODULE = 27, + + /** + * A device attribute value. The corresponding activity record + * structure is \ref CUpti_ActivityDeviceAttribute. + * This activity cannot be directly enabled or disabled. + * Information collected using attributes CUpti_DeviceAttribute + * or CUdevice_attribute can be stored in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_DEVICE_ATTRIBUTE = 28, + + /** + * Results for source-level shared access. The + * corresponding activity record structure is \ref + * CUpti_ActivitySharedAccess. + * In CUDA 12.6, this kind is deprecated for Volta and later GPU architectures + * in favor of SASS Metric APIs from the header cupti_sass_metrics.h. + */ + CUPTI_ACTIVITY_KIND_SHARED_ACCESS = 29, + + /** + * PC sampling information for kernels. This will serialize + * kernels. The corresponding activity record structure + * is \ref CUpti_ActivityPCSampling3. In CUDA 12.5, this kind + * is deprecated for Volta and later GPU architectures in favor + * of PC Sampling APIs from the header cupti_pcsampling.h which + * allows concurrent kernel execution. + */ + CUPTI_ACTIVITY_KIND_PC_SAMPLING = 30, + + /** + * Summary information about PC sampling records. The + * corresponding activity record structure is \ref + * CUpti_ActivityPCSamplingRecordInfo. In CUDA 12.5, this kind + * is deprecated for Volta and later GPU architectures in favor + * of PC Sampling APIs from the header cupti_pcsampling.h. + */ + CUPTI_ACTIVITY_KIND_PC_SAMPLING_RECORD_INFO = 31, + + /** + * SASS/Source line-by-line correlation record. + * This will generate sass/source correlation for functions that have source + * level analysis or pc sampling results. The records will be generated only + * when either of source level analysis or pc sampling activity is enabled. + * The corresponding activity record structure is \ref + * CUpti_ActivityInstructionCorrelation. + * In CUDA 12.6, this kind is deprecated for Volta and later GPU architectures + * in favor of SASS Metric APIs from the header cupti_sass_metrics.h. + */ + CUPTI_ACTIVITY_KIND_INSTRUCTION_CORRELATION = 32, + + /** + * OpenACC data events. + * The corresponding activity record structure is \ref + * CUpti_ActivityOpenAccData. + */ + CUPTI_ACTIVITY_KIND_OPENACC_DATA = 33, + + /** + * OpenACC launch events. + * The corresponding activity record structure is \ref + * CUpti_ActivityOpenAccLaunch. + */ + CUPTI_ACTIVITY_KIND_OPENACC_LAUNCH = 34, + + /** + * OpenACC other events. + * The corresponding activity record structure is \ref + * CUpti_ActivityOpenAccOther. + */ + CUPTI_ACTIVITY_KIND_OPENACC_OTHER = 35, + + /** + * Information about a CUDA event (cudaEvent). This activity cannot be + * directly enabled or disabled. It is enabled and disabled through + * the activity CUPTI_ACTIVITY_KIND_SYNCHRONIZATION. + * The corresponding activity record structure is \ref + * CUpti_ActivityCudaEvent2. + */ + CUPTI_ACTIVITY_KIND_CUDA_EVENT = 36, + + /** + * Information about a CUDA stream. The + * corresponding activity record structure is \ref + * CUpti_ActivityStream. + */ + CUPTI_ACTIVITY_KIND_STREAM = 37, + + /** + * Records for CUDA synchronization primitives. The + * corresponding activity record structure is \ref + * CUpti_ActivitySynchronization2. + */ + CUPTI_ACTIVITY_KIND_SYNCHRONIZATION = 38, + + /** + * Records for correlation of different programming APIs. The + * corresponding activity record structure is \ref + * CUpti_ActivityExternalCorrelation. + */ + CUPTI_ACTIVITY_KIND_EXTERNAL_CORRELATION = 39, + + /** + * NVLink topology information. + * The corresponding activity record structure is \ref + * CUpti_ActivityNvLink4. + */ + CUPTI_ACTIVITY_KIND_NVLINK = 40, + + /** + * Instantaneous Event information. + * The corresponding activity record structure is \ref + * CUpti_ActivityInstantaneousEvent. + * This activity can not be directly enabled or disabled. + * Information collected using the Event API can be stored + * in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_INSTANTANEOUS_EVENT = 41, + + /** + * Instantaneous Event information for a specific event + * domain instance. + * The corresponding activity record structure is \ref + * CUpti_ActivityInstantaneousEventInstance. + * This activity can not be directly enabled or disabled. + * Information collected using the Event API can be stored + * in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_INSTANTANEOUS_EVENT_INSTANCE = 42, + + /** + * Instantaneous Metric information + * The corresponding activity record structure is \ref + * CUpti_ActivityInstantaneousMetric. + * This activity cannot be directly enabled or disabled. + * Information collected using the Metric API can be stored + * in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_INSTANTANEOUS_METRIC = 43, + + /** + * Instantaneous Metric information for a specific metric + * domain instance. + * The corresponding activity record structure is \ref + * CUpti_ActivityInstantaneousMetricInstance. + * This activity cannot be directly enabled or disabled. + * Information collected using the Metric API can be stored + * in the corresponding activity record. + */ + CUPTI_ACTIVITY_KIND_INSTANTANEOUS_METRIC_INSTANCE = 44, + + /** + * Memory activity tracking allocation and freeing of the memory + * The corresponding activity record structure is \ref + * CUpti_ActivityMemory. + */ + CUPTI_ACTIVITY_KIND_MEMORY = 45, + + /** + * PCI devices information used for PCI topology. + * The corresponding activity record structure is \ref + * CUpti_ActivityPcie. + */ + CUPTI_ACTIVITY_KIND_PCIE = 46, + + /** + * OpenMP parallel events. + * The corresponding activity record structure is \ref + * CUpti_ActivityOpenMp. + */ + CUPTI_ACTIVITY_KIND_OPENMP = 47, + + /** + * A CUDA driver kernel launch occurring outside of any + * public API function execution. Tools can handle these + * like records for driver API launch functions, although + * the cbid field is not used here. + * The corresponding activity record structure is \ref + * CUpti_ActivityAPI. + */ + CUPTI_ACTIVITY_KIND_INTERNAL_LAUNCH_API = 48, + + /** + * Memory activity tracking allocation and freeing of the memory + * The corresponding activity record structure is \ref + * CUpti_ActivityMemory4. + */ + CUPTI_ACTIVITY_KIND_MEMORY2 = 49, + + /** + * Memory pool activity tracking creation, destruction and + * trimming of the memory pool. + * The corresponding activity record structure is \ref + * CUpti_ActivityMemoryPool2. + */ + CUPTI_ACTIVITY_KIND_MEMORY_POOL = 50, + + /** + * Activity record for graph-level information. + * The corresponding activity record structure is + * \ref CUpti_ActivityGraphTrace2. + */ + CUPTI_ACTIVITY_KIND_GRAPH_TRACE = 51, + + /** + * JIT (Just-in-time) operation tracking. + * The corresponding activity record structure is \ref + * CUpti_ActivityJit. + */ + CUPTI_ACTIVITY_KIND_JIT = 52, + + /** + * This activity can not be directly enabled or disabled. + * It is enabled when CUPTI_ACTIVITY_KIND_GRAPH_TRACE is enabled + * and device graph trace is enabled through API cuptiActivityEnableDeviceGraph(). + * The corresponding activity record structure is + * \ref CUpti_ActivityDeviceGraphTrace. + */ + CUPTI_ACTIVITY_KIND_DEVICE_GRAPH_TRACE = 53, + + /** + * Tracing batches of copies that are to be decompressed. + * The corresponding activity record structure is \ref + * CUpti_ActivityMemDecompress. + */ + CUPTI_ACTIVITY_KIND_MEM_DECOMPRESS = 54, + + + + /** + * Count of supported activity kinds. + */ + CUPTI_ACTIVITY_KIND_COUNT, + + CUPTI_ACTIVITY_KIND_FORCE_INT = 0x7fffffff +} CUpti_ActivityKind; + +/** + * \brief The kinds of activity objects. + * \see CUpti_ActivityObjectKindId + */ +typedef enum { + /** + * The object kind is not known. + */ + CUPTI_ACTIVITY_OBJECT_UNKNOWN = 0, + + /** + * A process. + */ + CUPTI_ACTIVITY_OBJECT_PROCESS = 1, + + /** + * A thread. + */ + CUPTI_ACTIVITY_OBJECT_THREAD = 2, + + /** + * A device. + */ + CUPTI_ACTIVITY_OBJECT_DEVICE = 3, + + /** + * A context. + */ + CUPTI_ACTIVITY_OBJECT_CONTEXT = 4, + + /** + * A stream. + */ + CUPTI_ACTIVITY_OBJECT_STREAM = 5, + + CUPTI_ACTIVITY_OBJECT_FORCE_INT = 0x7fffffff +} CUpti_ActivityObjectKind; + +/** + * \brief Identifiers for object kinds as specified by + * CUpti_ActivityObjectKind. + * \see CUpti_ActivityObjectKind + */ +typedef union { + /** + * A process object requires that we identify the process ID. A + * thread object requires that we identify both the process and + * thread ID. + */ + struct { + uint32_t processId; + uint32_t threadId; + } pt; + + /** + * A device object requires that we identify the device ID. A + * context object requires that we identify both the device and + * context ID. A stream object requires that we identify device, + * context, and stream ID. + */ + struct { + uint32_t deviceId; + uint32_t contextId; + uint32_t streamId; + } dcs; +} CUpti_ActivityObjectKindId; + +/** + * \brief The structure to provide additional data for CUPTI_ACTIVITY_OVERHEAD_COMMAND_BUFFER_FULL. + */ +typedef struct { + /** + * The remaining space in the command buffer. This field will always be zero + * when the command buffer is full, making it not useful in such cases. + * + */ + uint32_t commandBufferLength; + /** + * The channel ID of the command buffer. + * + */ + uint32_t channelID; + /** + * The channel type of the command buffer. + * + */ + uint32_t channelType; +} CUpti_ActivityOverheadCommandBufferFullData; + +/** + * \brief The kinds of activity overhead. + */ +typedef enum { + /** + * The overhead kind is not known. + */ + CUPTI_ACTIVITY_OVERHEAD_UNKNOWN = 0, + + /** + * Compiler overhead. + */ + CUPTI_ACTIVITY_OVERHEAD_DRIVER_COMPILER = 1, + + /** + * Activity buffer flush overhead. + */ + CUPTI_ACTIVITY_OVERHEAD_CUPTI_BUFFER_FLUSH = 1<<16, + + /** + * CUPTI instrumentation overhead. + */ + CUPTI_ACTIVITY_OVERHEAD_CUPTI_INSTRUMENTATION = 2<<16, + + /** + * CUPTI resource creation and destruction overhead. + */ + CUPTI_ACTIVITY_OVERHEAD_CUPTI_RESOURCE = 3<<16, + + /** + * CUDA Runtime triggered module loading overhead. + */ + CUPTI_ACTIVITY_OVERHEAD_RUNTIME_TRIGGERED_MODULE_LOADING = 4<<16, + + /** + * Lazy function loading overhead. + */ + CUPTI_ACTIVITY_OVERHEAD_LAZY_FUNCTION_LOADING = 5<<16, + + /** + * Overhead due to lack of command buffer space. + * Refer CUpti_ActivityOverheadCommandBufferFullData for more details. + */ + CUPTI_ACTIVITY_OVERHEAD_COMMAND_BUFFER_FULL = 6<<16, + + /** + * Overhead due to activity buffer request. + */ + CUPTI_ACTIVITY_OVERHEAD_ACTIVITY_BUFFER_REQUEST = 7<<16, + + /** + * Overhead due to UVM activity initialization. + */ + CUPTI_ACTIVITY_OVERHEAD_UVM_ACTIVITY_INIT = 8<<16, + + CUPTI_ACTIVITY_OVERHEAD_FORCE_INT = 0x7fffffff +} CUpti_ActivityOverheadKind; + +/** + * \brief The kind of a compute API. + */ +typedef enum { + /** + * The compute API is not known. + */ + CUPTI_ACTIVITY_COMPUTE_API_UNKNOWN = 0, + + /** + * The compute APIs are for CUDA. + */ + CUPTI_ACTIVITY_COMPUTE_API_CUDA = 1, + + /** + * The compute APIs are for CUDA running + * in MPS (Multi-Process Service) environment. + */ + CUPTI_ACTIVITY_COMPUTE_API_CUDA_MPS = 2, + + CUPTI_ACTIVITY_COMPUTE_API_FORCE_INT = 0x7fffffff +} CUpti_ActivityComputeApiKind; + +/** + * \brief Flags associated with activity records. + * + * Activity record flags. Flags can be combined by bitwise OR to + * associated multiple flags with an activity record. Each flag is + * specific to a certain activity kind, as noted below. + */ +typedef enum { + /** + * Indicates the activity record has no flags. + */ + CUPTI_ACTIVITY_FLAG_NONE = 0, + + /** + * Indicates the activity represents a device that supports + * concurrent kernel execution. Valid for + * CUPTI_ACTIVITY_KIND_DEVICE. + */ + CUPTI_ACTIVITY_FLAG_DEVICE_CONCURRENT_KERNELS = 1 << 0, + + /** + * Indicates if the activity represents a CUdevice_attribute value + * or a CUpti_DeviceAttribute value. Valid for + * CUPTI_ACTIVITY_KIND_DEVICE_ATTRIBUTE. + */ + CUPTI_ACTIVITY_FLAG_DEVICE_ATTRIBUTE_CUDEVICE = 1 << 0, + + /** + * Indicates the activity represents an asynchronous memcpy + * operation. Valid for CUPTI_ACTIVITY_KIND_MEMCPY. + */ + CUPTI_ACTIVITY_FLAG_MEMCPY_ASYNC = 1 << 0, + + /** + * Indicates the activity represents an instantaneous marker. Valid + * for CUPTI_ACTIVITY_KIND_MARKER. + */ + CUPTI_ACTIVITY_FLAG_MARKER_INSTANTANEOUS = 1 << 0, + + /** + * Indicates the activity represents a region start marker. Valid + * for CUPTI_ACTIVITY_KIND_MARKER. + */ + CUPTI_ACTIVITY_FLAG_MARKER_START = 1 << 1, + + /** + * Indicates the activity represents a region end marker. Valid for + * CUPTI_ACTIVITY_KIND_MARKER. + */ + CUPTI_ACTIVITY_FLAG_MARKER_END = 1 << 2, + + /** + * Indicates the activity represents an attempt to acquire a user + * defined synchronization object. + * Valid for CUPTI_ACTIVITY_KIND_MARKER. + */ + CUPTI_ACTIVITY_FLAG_MARKER_SYNC_ACQUIRE = 1 << 3, + + /** + * Indicates the activity represents success in acquiring the + * user defined synchronization object. + * Valid for CUPTI_ACTIVITY_KIND_MARKER. + */ + CUPTI_ACTIVITY_FLAG_MARKER_SYNC_ACQUIRE_SUCCESS = 1 << 4, + + /** + * Indicates the activity represents failure in acquiring the + * user defined synchronization object. + * Valid for CUPTI_ACTIVITY_KIND_MARKER. + */ + CUPTI_ACTIVITY_FLAG_MARKER_SYNC_ACQUIRE_FAILED = 1 << 5, + + /** + * Indicates the activity represents releasing a reservation on + * user defined synchronization object. + * Valid for CUPTI_ACTIVITY_KIND_MARKER. + */ + CUPTI_ACTIVITY_FLAG_MARKER_SYNC_RELEASE = 1 << 6, + + /** + * Indicates the activity represents a marker that does not specify + * a color. Valid for CUPTI_ACTIVITY_KIND_MARKER_DATA. + */ + CUPTI_ACTIVITY_FLAG_MARKER_COLOR_NONE = 1 << 0, + + /** + * Indicates the activity represents a marker that specifies a color + * in alpha-red-green-blue format. Valid for + * CUPTI_ACTIVITY_KIND_MARKER_DATA. + */ + CUPTI_ACTIVITY_FLAG_MARKER_COLOR_ARGB = 1 << 1, + + /** + * The number of bytes requested by each thread + * Valid for CUpti_ActivityGlobalAccess3. + */ + CUPTI_ACTIVITY_FLAG_GLOBAL_ACCESS_KIND_SIZE_MASK = 0xFF << 0, + + /** + * If bit in this flag is set, the access was load, else it is a + * store access. Valid for CUpti_ActivityGlobalAccess3. + */ + CUPTI_ACTIVITY_FLAG_GLOBAL_ACCESS_KIND_LOAD = 1 << 8, + + /** + * If this bit in flag is set, the load access was cached else it is + * uncached. Valid for CUpti_ActivityGlobalAccess3. + */ + CUPTI_ACTIVITY_FLAG_GLOBAL_ACCESS_KIND_CACHED = 1 << 9, + + /** + * If this bit in flag is set, the metric value overflowed. Valid + * for CUpti_ActivityMetric and CUpti_ActivityMetricInstance. + */ + CUPTI_ACTIVITY_FLAG_METRIC_OVERFLOWED = 1 << 0, + + /** + * If this bit in flag is set, the metric value couldn't be + * calculated. This occurs when a value(s) required to calculate the + * metric is missing. Valid for CUpti_ActivityMetric and + * CUpti_ActivityMetricInstance. + */ + CUPTI_ACTIVITY_FLAG_METRIC_VALUE_INVALID = 1 << 1, + + /** + * If this bit in flag is set, the source level metric value couldn't be + * calculated. This occurs when a value(s) required to calculate the + * source level metric cannot be evaluated. + * Valid for CUpti_ActivityInstructionExecution. + */ + CUPTI_ACTIVITY_FLAG_INSTRUCTION_VALUE_INVALID = 1 << 0, + + /** + * The mask for the instruction class, \ref CUpti_ActivityInstructionClass + * Valid for CUpti_ActivityInstructionExecution and + * CUpti_ActivityInstructionCorrelation + */ + CUPTI_ACTIVITY_FLAG_INSTRUCTION_CLASS_MASK = 0xFF << 1, + + /** + * When calling cuptiActivityFlushAll, this flag + * can be set to force CUPTI to flush all records in the buffer, whether + * finished or not + */ + CUPTI_ACTIVITY_FLAG_FLUSH_FORCED = 1 << 0, + + /** + * The number of bytes requested by each thread + * Valid for CUpti_ActivitySharedAccess. + */ + CUPTI_ACTIVITY_FLAG_SHARED_ACCESS_KIND_SIZE_MASK = 0xFF << 0, + + /** + * If bit in this flag is set, the access was load, else it is a + * store access. Valid for CUpti_ActivitySharedAccess. + */ + CUPTI_ACTIVITY_FLAG_SHARED_ACCESS_KIND_LOAD = 1 << 8, + + /** + * Indicates the activity represents an asynchronous memset + * operation. Valid for CUPTI_ACTIVITY_KIND_MEMSET. + */ + CUPTI_ACTIVITY_FLAG_MEMSET_ASYNC = 1 << 0, + + /** + * Indicates the activity represents thrashing in CPU. + * Valid for counter of kind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING in + * CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER + */ + CUPTI_ACTIVITY_FLAG_THRASHING_IN_CPU = 1 << 0, + + /** + * Indicates the activity represents page throttling in CPU. + * Valid for counter of kind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING in + * CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER + */ + CUPTI_ACTIVITY_FLAG_THROTTLING_IN_CPU = 1 << 0, + + CUPTI_ACTIVITY_FLAG_FORCE_INT = 0x7fffffff +} CUpti_ActivityFlag; + +/** + * \brief The stall reason for PC sampling activity. + */ +typedef enum { + /** + * Invalid reason + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_INVALID = 0, + + /** + * No stall, instruction is selected for issue + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_NONE = 1, + + /** + * Warp is blocked because next instruction is not yet available, + * because of instruction cache miss, or because of branching effects + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_INST_FETCH = 2, + + /** + * Instruction is waiting on an arithmetic dependency + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_EXEC_DEPENDENCY = 3, + + /** + * Warp is blocked because it is waiting for a memory access to complete. + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_MEMORY_DEPENDENCY = 4, + + /** + * Texture sub-system is fully utilized or has too many outstanding requests. + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_TEXTURE = 5, + + /** + * Warp is blocked as it is waiting at __syncthreads() or at memory barrier. + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_SYNC = 6, + + /** + * Warp is blocked waiting for __constant__ memory and immediate memory access to complete. + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_CONSTANT_MEMORY_DEPENDENCY = 7, + + /** + * Compute operation cannot be performed due to the required resources not + * being available. + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_PIPE_BUSY = 8, + + /** + * Warp is blocked because there are too many pending memory operations. + * In Kepler architecture it often indicates high number of memory replays. + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_MEMORY_THROTTLE = 9, + + /** + * Warp was ready to issue, but some other warp issued instead. + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_NOT_SELECTED = 10, + + /** + * Miscellaneous reasons + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_OTHER = 11, + + /** + * Sleeping. + */ + CUPTI_ACTIVITY_PC_SAMPLING_STALL_SLEEPING = 12, + + CUPTI_ACTIVITY_PC_SAMPLING_STALL_FORCE_INT = 0x7fffffff +} CUpti_ActivityPCSamplingStallReason; + +/** + * \brief Sampling period for PC sampling method + * + * Sampling period can be set using \ref cuptiActivityConfigurePCSampling + */ +typedef enum { + /** + * The PC sampling period is not set. + */ + CUPTI_ACTIVITY_PC_SAMPLING_PERIOD_INVALID = 0, + + /** + * Minimum sampling period available on the device. + */ + CUPTI_ACTIVITY_PC_SAMPLING_PERIOD_MIN = 1, + + /** + * Sampling period in lower range. + */ + CUPTI_ACTIVITY_PC_SAMPLING_PERIOD_LOW = 2, + + /** + * Medium sampling period. + */ + CUPTI_ACTIVITY_PC_SAMPLING_PERIOD_MID = 3, + + /** + * Sampling period in higher range. + */ + CUPTI_ACTIVITY_PC_SAMPLING_PERIOD_HIGH = 4, + + /** + * Maximum sampling period available on the device. + */ + CUPTI_ACTIVITY_PC_SAMPLING_PERIOD_MAX = 5, + + CUPTI_ACTIVITY_PC_SAMPLING_PERIOD_FORCE_INT = 0x7fffffff +} CUpti_ActivityPCSamplingPeriod; + +/** + * \brief The kind of a memory copy, indicating the source and + * destination targets of the copy. + * + * Each kind represents the source and destination targets of a memory + * copy. Targets are host, device, and array. + */ +typedef enum { + /** + * The memory copy kind is not known. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_UNKNOWN = 0, + + /** + * A host to device memory copy. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_HTOD = 1, + + /** + * A device to host memory copy. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_DTOH = 2, + + /** + * A host to device array memory copy. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_HTOA = 3, + + /** + * A device array to host memory copy. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_ATOH = 4, + + /** + * A device array to device array memory copy. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_ATOA = 5, + + /** + * A device array to device memory copy. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_ATOD = 6, + + /** + * A device to device array memory copy. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_DTOA = 7, + + /** + * A device to device memory copy on the same device. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_DTOD = 8, + + /** + * A host to host memory copy. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_HTOH = 9, + + /** + * A peer to peer memory copy across different devices. + */ + CUPTI_ACTIVITY_MEMCPY_KIND_PTOP = 10, + + CUPTI_ACTIVITY_MEMCPY_KIND_FORCE_INT = 0x7fffffff +} CUpti_ActivityMemcpyKind; + +/** + * \brief The kinds of memory accessed by a memory operation/copy. + * + * Each kind represents the type of the memory + * accessed by a memory operation/copy. + */ +typedef enum { + /** + * The memory kind is unknown. + */ + CUPTI_ACTIVITY_MEMORY_KIND_UNKNOWN = 0, + + /** + * The memory is pageable. + */ + CUPTI_ACTIVITY_MEMORY_KIND_PAGEABLE = 1, + + /** + * The memory is pinned. + */ + CUPTI_ACTIVITY_MEMORY_KIND_PINNED = 2, + + /** + * The memory is on the device. + */ + CUPTI_ACTIVITY_MEMORY_KIND_DEVICE = 3, + + /** + * The memory is an array. + */ + CUPTI_ACTIVITY_MEMORY_KIND_ARRAY = 4, + + /** + * The memory is managed + */ + CUPTI_ACTIVITY_MEMORY_KIND_MANAGED = 5, + + /** + * The memory is device static + */ + CUPTI_ACTIVITY_MEMORY_KIND_DEVICE_STATIC = 6, + + /** + * The memory is managed static + */ + CUPTI_ACTIVITY_MEMORY_KIND_MANAGED_STATIC = 7, + + CUPTI_ACTIVITY_MEMORY_KIND_FORCE_INT = 0x7fffffff +} CUpti_ActivityMemoryKind; + +/** + * \brief The kind of a preemption activity. + */ +typedef enum { + /** + * The preemption kind is not known. + */ + CUPTI_ACTIVITY_PREEMPTION_KIND_UNKNOWN = 0, + + /** + * Preemption to save CDP block. + */ + CUPTI_ACTIVITY_PREEMPTION_KIND_SAVE = 1, + + /** + * Preemption to restore CDP block. + */ + CUPTI_ACTIVITY_PREEMPTION_KIND_RESTORE = 2, + + CUPTI_ACTIVITY_PREEMPTION_KIND_FORCE_INT = 0x7fffffff +} CUpti_ActivityPreemptionKind; + +/** + * \brief The kind of environment data. Used to indicate what type of + * data is being reported by an environment activity record. + */ +typedef enum { + /** + * Unknown data. + */ + CUPTI_ACTIVITY_ENVIRONMENT_UNKNOWN = 0, + + /** + * The environment data is related to speed. + */ + CUPTI_ACTIVITY_ENVIRONMENT_SPEED = 1, + + /** + * The environment data is related to temperature. + */ + CUPTI_ACTIVITY_ENVIRONMENT_TEMPERATURE = 2, + + /** + * The environment data is related to power. + */ + CUPTI_ACTIVITY_ENVIRONMENT_POWER = 3, + + /** + * The environment data is related to cooling. + */ + CUPTI_ACTIVITY_ENVIRONMENT_COOLING = 4, + + CUPTI_ACTIVITY_ENVIRONMENT_COUNT, + + CUPTI_ACTIVITY_ENVIRONMENT_KIND_FORCE_INT = 0x7fffffff +} CUpti_ActivityEnvironmentKind; + +/** + * \brief Reasons for clock throttling. + * + * The possible reasons that a clock can be throttled. There can be + * more than one reason that a clock is being throttled so these types + * can be combined by bitwise OR. These are used in the + * clocksThrottleReason field in the Environment Activity Record. + */ +typedef enum { + /** + * Nothing is running on the GPU and the clocks are dropping to idle + * state. + */ + CUPTI_CLOCKS_THROTTLE_REASON_GPU_IDLE = 0x00000001, + + /** + * The GPU clocks are limited by a user specified limit. + */ + CUPTI_CLOCKS_THROTTLE_REASON_USER_DEFINED_CLOCKS = 0x00000002, + + /** + * A software power scaling algorithm is reducing the clocks below + * requested clocks. + */ + CUPTI_CLOCKS_THROTTLE_REASON_SW_POWER_CAP = 0x00000004, + + /** + * Hardware slowdown to reduce the clock by a factor of two or more + * is engaged. This is an indicator of one of the following: 1) + * Temperature is too high, 2) External power brake assertion is + * being triggered (e.g. by the system power supply), 3) Change in + * power state. + */ + CUPTI_CLOCKS_THROTTLE_REASON_HW_SLOWDOWN = 0x00000008, + + /** + * Some unspecified factor is reducing the clocks. + */ + CUPTI_CLOCKS_THROTTLE_REASON_UNKNOWN = 0x80000000, + + /** + * Throttle reason is not supported for this GPU. + */ + CUPTI_CLOCKS_THROTTLE_REASON_UNSUPPORTED = 0x40000000, + + /** + * No clock throttling. + */ + CUPTI_CLOCKS_THROTTLE_REASON_NONE = 0x00000000, + + CUPTI_CLOCKS_THROTTLE_REASON_FORCE_INT = 0x7fffffff +} CUpti_EnvironmentClocksThrottleReason; + +/** + * \brief Scope of the unified memory counter (deprecated in CUDA 7.0) + */ +typedef enum { + /** + * The unified memory counter scope is not known. + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_SCOPE_UNKNOWN = 0, + + /** + * Collect unified memory counter for single process on one device + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_SCOPE_PROCESS_SINGLE_DEVICE = 1, + + /** + * Collect unified memory counter for single process across all devices + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_SCOPE_PROCESS_ALL_DEVICES = 2, + + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_SCOPE_COUNT, + + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_SCOPE_FORCE_INT = 0x7fffffff +} CUpti_ActivityUnifiedMemoryCounterScope; + +/** + * \brief Kind of the Unified Memory counter + * + * Many activities are associated with Unified Memory mechanism; among them + * are transfers from host to device, device to host, page fault at + * host side. + */ +typedef enum { + /** + * The unified memory counter kind is not known. + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_UNKNOWN = 0, + + /** + * Number of bytes transferred from host to device + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD = 1, + + /** + * Number of bytes transferred from device to host + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH = 2, + + /** + * Number of CPU page faults, this is only supported on 64 bit + * Linux and Mac platforms + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT = 3, + + /** + * Number of GPU page faults, this is only supported on devices with + * compute capability 6.0 and higher and 64 bit Linux platforms + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT = 4, + + /** + * Thrashing occurs when data is frequently accessed by + * multiple processors and has to be constantly migrated around + * to achieve data locality. In this case the overhead of migration + * may exceed the benefits of locality. + * This is only supported on 64 bit Linux platforms. + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING = 5, + + /** + * Throttling is a prevention technique used by the driver to avoid + * further thrashing. Here, the driver doesn't service the fault for + * one of the contending processors for a specific period of time, + * so that the other processor can run at full-speed. + * This is only supported on 64 bit Linux platforms. + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING = 6, + + /** + * In case throttling does not help, the driver tries to pin the memory + * to a processor for a specific period of time. One of the contending + * processors will have slow access to the memory, while the other will + * have fast access. + * This is only supported on 64 bit Linux platforms. + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP = 7, + + /** + * Number of bytes transferred from one device to another device. + * This is only supported on 64 bit Linux platforms. + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOD = 8, + + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_COUNT, + + CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_FORCE_INT = 0x7fffffff +} CUpti_ActivityUnifiedMemoryCounterKind; + +/** + * \brief Memory access type for unified memory page faults + * + * This is valid for \ref CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT + * and \ref CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT + */ +typedef enum { + /** + * The unified memory access type is not known + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_ACCESS_TYPE_UNKNOWN = 0, + + /** + * The page fault was triggered by read memory instruction + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_ACCESS_TYPE_READ = 1, + + /** + * The page fault was triggered by write memory instruction + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_ACCESS_TYPE_WRITE = 2, + + /** + * The page fault was triggered by atomic memory instruction + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_ACCESS_TYPE_ATOMIC = 3, + + /** + * The page fault was triggered by memory prefetch operation + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_ACCESS_TYPE_PREFETCH = 4 +} CUpti_ActivityUnifiedMemoryAccessType; + +/** + * \brief Migration cause of the Unified Memory counter + * + * This is valid for \ref CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD and + * \ref CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH + */ +typedef enum { + /** + * The unified memory migration cause is not known + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_MIGRATION_CAUSE_UNKNOWN = 0, + + /** + * The unified memory migrated due to an explicit call from + * the user e.g. cudaMemPrefetchAsync + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_MIGRATION_CAUSE_USER = 1, + + /** + * The unified memory migrated to guarantee data coherence + * e.g. CPU/GPU faults on Pascal+ and kernel launch on pre-Pascal GPUs + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_MIGRATION_CAUSE_COHERENCE = 2, + + /** + * The unified memory was speculatively migrated by the UVM driver + * before being accessed by the destination processor to improve + * performance + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_MIGRATION_CAUSE_PREFETCH = 3, + + /** + * The unified memory migrated to the CPU because it was evicted to make + * room for another block of memory on the GPU + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_MIGRATION_CAUSE_EVICTION = 4, + + /** + * The unified memory migrated to another processor because of access counter + * notifications. Only frequently accessed pages are migrated between CPU and GPU, or + * between peer GPUs. + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_MIGRATION_CAUSE_ACCESS_COUNTERS = 5, +} CUpti_ActivityUnifiedMemoryMigrationCause; + +/** + * \brief Remote memory map cause of the Unified Memory counter + * + * This is valid for \ref CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP + */ +typedef enum { + /** + * The cause of mapping to remote memory was unknown + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_REMOTE_MAP_CAUSE_UNKNOWN = 0, + + /** + * Mapping to remote memory was added to maintain data coherence. + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_REMOTE_MAP_CAUSE_COHERENCE = 1, + + /** + * Mapping to remote memory was added to prevent further thrashing + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_REMOTE_MAP_CAUSE_THRASHING = 2, + + /** + * Mapping to remote memory was added to enforce the hints + * specified by the programmer or by performance heuristics of the + * UVM driver + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_REMOTE_MAP_CAUSE_POLICY = 3, + + /** + * Mapping to remote memory was added because there is no more + * memory available on the processor and eviction was not + * possible + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_REMOTE_MAP_CAUSE_OUT_OF_MEMORY = 4, + + /** + * Mapping to remote memory was added after the memory was + * evicted to make room for another block of memory on the GPU + */ + CUPTI_ACTIVITY_UNIFIED_MEMORY_REMOTE_MAP_CAUSE_EVICTION = 5, +} CUpti_ActivityUnifiedMemoryRemoteMapCause; + +/** + * \brief SASS instruction classification. + * + * The sass instruction are broadly divided into different class. Each enum represents a classification. + */ +typedef enum { + /** + * The instruction class is not known. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_UNKNOWN = 0, + + /** + * Represents a 32 bit floating point operation. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_FP_32 = 1, + + /** + * Represents a 64 bit floating point operation. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_FP_64 = 2, + + /** + * Represents an integer operation. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_INTEGER = 3, + + /** + * Represents a bit conversion operation. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_BIT_CONVERSION = 4, + + /** + * Represents a control flow instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_CONTROL_FLOW = 5, + + /** + * Represents a global load-store instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_GLOBAL = 6, + + /** + * Represents a shared load-store instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_SHARED = 7, + + /** + * Represents a local load-store instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_LOCAL = 8, + + /** + * Represents a generic load-store instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_GENERIC = 9, + + /** + * Represents a surface load-store instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_SURFACE = 10, + + /** + * Represents a constant load instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_CONSTANT = 11, + + /** + * Represents a texture load-store instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_TEXTURE = 12, + + /** + * Represents a global atomic instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_GLOBAL_ATOMIC = 13, + + /** + * Represents a shared atomic instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_SHARED_ATOMIC = 14, + + /** + * Represents a surface atomic instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_SURFACE_ATOMIC = 15, + + /** + * Represents a inter-thread communication instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_INTER_THREAD_COMMUNICATION = 16, + + /** + * Represents a barrier instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_BARRIER = 17, + + /** + * Represents some miscellaneous instructions which do not fit in the above classification. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_MISCELLANEOUS = 18, + + /** + * Represents a 16 bit floating point operation. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_FP_16 = 19, + + /** + * Represents uniform instruction. + */ + CUPTI_ACTIVITY_INSTRUCTION_CLASS_UNIFORM = 20, + + CUPTI_ACTIVITY_INSTRUCTION_CLASS_KIND_FORCE_INT = 0x7fffffff +} CUpti_ActivityInstructionClass; + +/** + * \brief Partitioned global caching option + */ +typedef enum { + /** + * Partitioned global cache config unknown. + */ + CUPTI_ACTIVITY_PARTITIONED_GLOBAL_CACHE_CONFIG_UNKNOWN = 0, + + /** + * Partitioned global cache not supported. + */ + CUPTI_ACTIVITY_PARTITIONED_GLOBAL_CACHE_CONFIG_NOT_SUPPORTED = 1, + + /** + * Partitioned global cache config off. + */ + CUPTI_ACTIVITY_PARTITIONED_GLOBAL_CACHE_CONFIG_OFF = 2, + + /** + * Partitioned global cache config on. + */ + CUPTI_ACTIVITY_PARTITIONED_GLOBAL_CACHE_CONFIG_ON = 3, + + CUPTI_ACTIVITY_PARTITIONED_GLOBAL_CACHE_CONFIG_FORCE_INT = 0x7fffffff +} CUpti_ActivityPartitionedGlobalCacheConfig; + +/** + * \brief Synchronization type. + * + * The types of synchronization to be used with + * CUpti_ActivitySynchronization2. + */ + +typedef enum { + /** + * Unknown data. + */ + CUPTI_ACTIVITY_SYNCHRONIZATION_TYPE_UNKNOWN = 0, + + /** + * Event synchronize API. + */ + CUPTI_ACTIVITY_SYNCHRONIZATION_TYPE_EVENT_SYNCHRONIZE = 1, + + /** + * Stream wait event API. + */ + CUPTI_ACTIVITY_SYNCHRONIZATION_TYPE_STREAM_WAIT_EVENT = 2, + + /** + * Stream synchronize API. + */ + CUPTI_ACTIVITY_SYNCHRONIZATION_TYPE_STREAM_SYNCHRONIZE = 3, + + /** + * Context synchronize API. + */ + CUPTI_ACTIVITY_SYNCHRONIZATION_TYPE_CONTEXT_SYNCHRONIZE = 4, + + CUPTI_ACTIVITY_SYNCHRONIZATION_TYPE_FORCE_INT = 0x7fffffff +} CUpti_ActivitySynchronizationType; + +/** + * \brief stream type. + * + * The types of stream to be used with CUpti_ActivityStream. + */ + +typedef enum { + /** + * Unknown data. + */ + CUPTI_ACTIVITY_STREAM_CREATE_FLAG_UNKNOWN = 0, + + /** + * Default stream. + */ + CUPTI_ACTIVITY_STREAM_CREATE_FLAG_DEFAULT = 1, + + /** + * Non-blocking stream. + */ + CUPTI_ACTIVITY_STREAM_CREATE_FLAG_NON_BLOCKING = 2, + + /** + * Null stream. + */ + CUPTI_ACTIVITY_STREAM_CREATE_FLAG_NULL = 3, + + /** + * Stream create Mask + */ + CUPTI_ACTIVITY_STREAM_CREATE_MASK = 0xFFFF, + + CUPTI_ACTIVITY_STREAM_CREATE_FLAG_FORCE_INT = 0x7fffffff +} CUpti_ActivityStreamFlag; + +/** +* \brief Link flags. +* +* Describes link properties, to be used with CUpti_ActivityNvLink. +*/ + +typedef enum { + /** + * The flag is invalid. + */ + CUPTI_LINK_FLAG_INVALID = 0, + + /** + * Is peer to peer access supported by this link. + */ + CUPTI_LINK_FLAG_PEER_ACCESS = (1 << 1), + + /** + * Is system memory access supported by this link. + */ + CUPTI_LINK_FLAG_SYSMEM_ACCESS = (1 << 2), + + /** + * Is peer atomic access supported by this link. + */ + CUPTI_LINK_FLAG_PEER_ATOMICS = (1 << 3), + + /** + * Is system memory atomic access supported by this link. + */ + CUPTI_LINK_FLAG_SYSMEM_ATOMICS = (1 << 4), + + CUPTI_LINK_FLAG_FORCE_INT = 0x7fffffff +} CUpti_LinkFlag; + +/** +* \brief Memory operation types. +* +* Describes the type of memory operation, to be used with CUpti_ActivityMemory4. +*/ + +typedef enum { + /** + * The operation is invalid. + */ + CUPTI_ACTIVITY_MEMORY_OPERATION_TYPE_INVALID = 0, + + /** + * Memory is allocated. + */ + CUPTI_ACTIVITY_MEMORY_OPERATION_TYPE_ALLOCATION = 1, + + /** + * Memory is released. + */ + CUPTI_ACTIVITY_MEMORY_OPERATION_TYPE_RELEASE = 2, + + CUPTI_ACTIVITY_MEMORY_OPERATION_TYPE_FORCE_INT = 0x7fffffff +} CUpti_ActivityMemoryOperationType; + +/** +* \brief Memory pool types. +* +* Describes the type of memory pool, to be used with CUpti_ActivityMemory4. +*/ + +typedef enum { + /** + * The operation is invalid. + */ + CUPTI_ACTIVITY_MEMORY_POOL_TYPE_INVALID = 0, + + /** + * Memory pool is local to the process. + */ + CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL = 1, + + /** + * Memory pool is imported by the process. + */ + CUPTI_ACTIVITY_MEMORY_POOL_TYPE_IMPORTED = 2, + + CUPTI_ACTIVITY_MEMORY_POOL_TYPE_FORCE_INT = 0x7fffffff +} CUpti_ActivityMemoryPoolType; + +/** +* \brief Memory pool operation types. +* +* Describes the type of memory pool operation, to be used with CUpti_ActivityMemoryPool2. +*/ + +typedef enum { + /** + * The operation is invalid. + */ + CUPTI_ACTIVITY_MEMORY_POOL_OPERATION_TYPE_INVALID = 0, + + /** + * Memory pool is created. + */ + CUPTI_ACTIVITY_MEMORY_POOL_OPERATION_TYPE_CREATED = 1, + + /** + * Memory pool is destroyed. + */ + CUPTI_ACTIVITY_MEMORY_POOL_OPERATION_TYPE_DESTROYED = 2, + + /** + * Memory pool is trimmed. + */ + CUPTI_ACTIVITY_MEMORY_POOL_OPERATION_TYPE_TRIMMED = 3, + + CUPTI_ACTIVITY_MEMORY_POOL_OPERATION_TYPE_FORCE_INT = 0x7fffffff +} CUpti_ActivityMemoryPoolOperationType; + +typedef enum { + CUPTI_CHANNEL_TYPE_INVALID = 0, + + /** + * Channel is used for standard work launch and tracking + */ + CUPTI_CHANNEL_TYPE_COMPUTE = 1, + + /** + * Channel is used by an asynchronous copy engine + * For confidential compute configurations, work launch and + * completion are done using the copy engines. + */ + CUPTI_CHANNEL_TYPE_ASYNC_MEMCPY = 2, + + + /** + * Channel is used for memory decompression operations + */ + CUPTI_CHANNEL_TYPE_DECOMP , + + CUPTI_CHANNEL_TYPE_FORCE_INT = 0x7fffffff +} CUpti_ChannelType; + +/** +* \brief CIG (CUDA in Graphics) Modes. +* +* Describes the CIG modes associated with the CUDA context. +*/ + +typedef enum +{ + /** + * Regular (non-CIG) mode + */ + CUPTI_CONTEXT_CIG_MODE_NONE = 0, + /** + * CIG mode + */ + CUPTI_CONTEXT_CIG_MODE_CIG = 1, + /** + * CIG fallback mode + */ + CUPTI_CONTEXT_CIG_MODE_CIG_FALLBACK = 2, + + CUPTI_CONTEXT_CIG_MODE_FORCE_INT = 0x7fffffff +} CUpti_ContextCigMode; + +/** + * The source-locator ID that indicates an unknown source + * location. There is not an actual CUpti_ActivitySourceLocator object + * corresponding to this value. + */ +#define CUPTI_SOURCE_LOCATOR_ID_UNKNOWN 0 + +/** + * An invalid function index ID. + */ +#define CUPTI_FUNCTION_INDEX_ID_INVALID 0 + +/** + * An invalid/unknown correlation ID. A correlation ID of this value + * indicates that there is no correlation for the activity record. + */ +#define CUPTI_CORRELATION_ID_UNKNOWN 0 + +/** + * An invalid/unknown grid ID. + */ +#define CUPTI_GRID_ID_UNKNOWN 0LL + +/** + * An invalid/unknown timestamp for a start, end, queued, submitted, + * or completed time. + */ +#define CUPTI_TIMESTAMP_UNKNOWN 0LL + +/** + * An invalid/unknown value. + */ +#define CUPTI_SYNCHRONIZATION_INVALID_VALUE ((uint32_t) 0xFFFFFFFFU) + +/** + * An invalid/unknown process id. + */ +#define CUPTI_AUTO_BOOST_INVALID_CLIENT_PID 0 + +/** + * Invalid/unknown NVLink port number. +*/ +#define CUPTI_NVLINK_INVALID_PORT -1 + +/** + * Maximum NVLink port numbers. +*/ +#define CUPTI_MAX_NVLINK_PORTS 32 + +/** + * An invalid/unknown value for decompressed bytes. +*/ +#define CUPTI_DECOMPRESSED_BYTES_UNKNOWN 0LL + +START_PACKED_ALIGNMENT +/** + * \brief Unified Memory counters configuration structure + * + * This structure controls the enable/disable of the various + * Unified Memory counters consisting of scope, kind and other parameters. + * See function \ref cuptiActivityConfigureUnifiedMemoryCounter + */ +typedef struct PACKED_ALIGNMENT { + /** + * Unified Memory counter Counter scope. (deprecated in CUDA 7.0) + */ + CUpti_ActivityUnifiedMemoryCounterScope scope; + + /** + * Unified Memory counter Counter kind + */ + CUpti_ActivityUnifiedMemoryCounterKind kind; + + /** + * Device id of the target device. This is relevant only + * for single device scopes. (deprecated in CUDA 7.0) + */ + uint32_t deviceId; + + /** + * Control to enable/disable the counter. To enable the counter + * set it to non-zero value while disable is indicated by zero. + */ + uint32_t enable; +} CUpti_ActivityUnifiedMemoryCounterConfig; + +/** + * \brief Device auto boost state structure + * + * This structure defines auto boost state for a device. + * See function \ref cuptiGetAutoBoostState + */ +typedef struct PACKED_ALIGNMENT { + /** + * Returned auto boost state. 1 is returned in case auto boost is enabled, 0 + * otherwise + */ + uint32_t enabled; + + /** + * Id of process that has set the current boost state. The value will be + * CUPTI_AUTO_BOOST_INVALID_CLIENT_PID if the user does not have the + * permission to query process ids or there is an error in querying the + * process id. + */ + uint32_t pid; + +} CUpti_ActivityAutoBoostState; + +/** + * \brief PC sampling configuration structure + * + * This structure defines the pc sampling configuration. + * + * See function \ref cuptiActivityConfigurePCSampling + */ +typedef struct PACKED_ALIGNMENT { + /** + * Size of configuration structure. + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + uint32_t size; + + /** + * There are 5 level provided for sampling period. The level + * internally maps to a period in terms of cycles. Same level can + * map to different number of cycles on different gpus. No of + * cycles will be chosen to minimize information loss. The period + * chosen will be given by samplingPeriodInCycles in + * \ref CUpti_ActivityPCSamplingRecordInfo for each kernel instance. + */ + CUpti_ActivityPCSamplingPeriod samplingPeriod; + + /** + * This will override the period set by samplingPeriod. Value 0 in samplingPeriod2 will be + * considered as samplingPeriod2 should not be used and samplingPeriod should be used. + * Valid values for samplingPeriod2 are between 5 to 31 both inclusive. + * This will set the sampling period to (2^samplingPeriod2) cycles. + */ + uint32_t samplingPeriod2; +} CUpti_ActivityPCSamplingConfig; + +/** + * \brief The base activity record. + * + * The activity API uses a CUpti_Activity as a generic representation + * for any activity. The 'kind' field is used to determine the + * specific activity kind, and from that the CUpti_Activity object can + * be cast to the specific activity record type appropriate for that kind. + * + * Note that all activity record types are padded and aligned to + * ensure that each member of the record is naturally aligned. + * + * \see CUpti_ActivityKind + */ +typedef struct PACKED_ALIGNMENT { + /** + * The kind of this activity. + */ + CUpti_ActivityKind kind; +} CUpti_Activity; + +/** + * \brief The activity record for memory copies. + * + * This activity record represents a memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the memory copy. + */ + uint32_t correlationId; + + /** + * The runtime correlation ID of the memory copy. Each memory copy + * is assigned a unique runtime correlation ID that is identical to + * the correlation ID in the runtime API activity record that + * launched the memory copy. + */ + uint32_t runtimeCorrelationId; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint64_t graphNodeId; + + /** + * The unique ID of the graph that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint32_t graphId; + + /** + * The ID of the HW channel on which the memory copy is occurring. + */ + uint32_t channelID; + + /** + * The type of the channel + */ + CUpti_ChannelType channelType; + + /** + * Reserved for internal use. + */ + uint32_t pad2; + + /** + * The total number of memcopy operations traced in this record. + * This field is valid for memcpy operations happening using + * MemcpyBatchAsync APIs in CUDA. + * In MemcpyBatchAsync APIs, multiple memcpy operations are batched + * together for optimization purposes based on certain heuristics. + * For other memcpy operations, this field will be 1. + */ + uint64_t copyCount; +} CUpti_ActivityMemcpy6; + +/** + * \brief The activity record for peer-to-peer memory copies. + * + * This activity record represents a peer-to-peer memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY2). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY2. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see + * CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The ID of the device where memory is being copied from. + */ + uint32_t srcDeviceId; + + /** + * The ID of the context owning the memory being copied from. + */ + uint32_t srcContextId; + + /** + * The ID of the device where memory is being copied to. + */ + uint32_t dstDeviceId; + + /** + * The ID of the context owning the memory being copied to. + */ + uint32_t dstContextId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory copy. + */ + uint32_t correlationId; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed the memcpy through graph launch. + * This field will be 0 if memcpy is not done using graph launch. + */ + uint64_t graphNodeId; + + /** + * The unique ID of the graph that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint32_t graphId; + + /** + * The ID of the HW channel on which the memory copy is occurring. + */ + uint32_t channelID; + + /** + * The type of the channel + */ + CUpti_ChannelType channelType; +} CUpti_ActivityMemcpyPtoP4; + +/** + * \brief The activity record for memset. + * + * This activity record represents a memory set operation + * (CUPTI_ACTIVITY_KIND_MEMSET). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMSET. + */ + CUpti_ActivityKind kind; + + /** + * The value being assigned to memory by the memory set. + */ + uint32_t value; + + /** + * The number of bytes being set by the memory set. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory set, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory set. + */ + uint64_t start; + + /** + * The end timestamp for the memory set, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory set. + */ + uint64_t end; + + /** + * The ID of the device where the memory set is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory set is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory set is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory set. Each memory set is assigned + * a unique correlation ID that is identical to the correlation ID + * in the driver API activity record that launched the memory set. + */ + uint32_t correlationId; + + /** + * The flags associated with the memset. \see CUpti_ActivityFlag + */ + uint16_t flags; + + /** + * The memory kind of the memory set \see CUpti_ActivityMemoryKind + */ + uint16_t memoryKind; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed this memset through graph launch. + * This field will be 0 if the memset is not executed through graph launch. + */ + uint64_t graphNodeId; + + /** + * The unique ID of the graph that executed this memset through graph launch. + * This field will be 0 if the memset is not executed through graph launch. + */ + uint32_t graphId; + + /** + * The ID of the HW channel on which the memory set is occurring. + */ + uint32_t channelID; + + /** + * The type of the channel + */ + CUpti_ChannelType channelType; + + /** + * Undefined. Reserved for internal use + */ + uint32_t pad2; +} CUpti_ActivityMemset4; + +/** + * \brief The activity record for memory. + * + * This activity record represents a memory allocation and free operation + * (CUPTI_ACTIVITY_KIND_MEMORY). + * This activity record provides a single record for the memory + * allocation and memory release operations. + * + * Note: It is recommended to move to the new activity record \ref CUpti_ActivityMemory4 + * enabled using the kind \ref CUPTI_ACTIVITY_KIND_MEMORY2. + * \ref CUpti_ActivityMemory4 provides separate records for memory + * allocation and memory release operations. This allows to correlate the + * corresponding driver and runtime API activity record with the memory operation. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMORY + */ + CUpti_ActivityKind kind; + + /** + * The memory kind requested by the user + */ + CUpti_ActivityMemoryKind memoryKind; + + /** + * The virtual address of the allocation + */ + uint64_t address; + + /** + * The number of bytes of memory allocated. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory operation, i.e. + * the time when memory was allocated, in ns. + */ + uint64_t start; + + /** + * The end timestamp for the memory operation, i.e. + * the time when memory was freed, in ns. + * This will be 0 if memory is not freed in the application + */ + uint64_t end; + + /** + * The program counter of the allocation of memory + */ + uint64_t allocPC; + + /** + * The program counter of the freeing of memory. This will + * be 0 if memory is not freed in the application + */ + uint64_t freePC; + + /** + * The ID of the process to which this record belongs to. + */ + uint32_t processId; + + /** + * The ID of the device where the memory allocation is taking place. + */ + uint32_t deviceId; + + /** + * The ID of the context. If context is NULL, \p contextId is set to CUPTI_INVALID_CONTEXT_ID. + */ + uint32_t contextId; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Variable name. This name is shared across all activity + * records representing the same symbol, and so should not be + * modified. + */ + const char* name; +} CUpti_ActivityMemory; + +/** + * \brief The activity record for memory. + * + * This activity record represents a memory allocation and free operation + * (CUPTI_ACTIVITY_KIND_MEMORY2). + * This activity record provides separate records for memory allocation and + * memory release operations. + * This allows to correlate the corresponding driver and runtime API + * activity record with the memory operation. + * + * Note: This activity record is an upgrade over \ref CUpti_ActivityMemory + * enabled using the kind \ref CUPTI_ACTIVITY_KIND_MEMORY. + * \ref CUpti_ActivityMemory provides a single record for the memory + * allocation and memory release operations. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMORY2 + */ + CUpti_ActivityKind kind; + + /** + * The memory operation requested by the user, \ref CUpti_ActivityMemoryOperationType. + */ + CUpti_ActivityMemoryOperationType memoryOperationType; + + /** + * The memory kind requested by the user, \ref CUpti_ActivityMemoryKind. + */ + CUpti_ActivityMemoryKind memoryKind; + + /** + * The correlation ID of the memory operation. Each memory operation is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory operation. + */ + uint32_t correlationId; + + /** + * The virtual address of the allocation. + */ + uint64_t address; + + /** + * The number of bytes of memory allocated. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory operation, in ns. + */ + uint64_t timestamp; + + /** + * The program counter of the memory operation. + */ + uint64_t PC; + + /** + * The ID of the process to which this record belongs to. + */ + uint32_t processId; + + /** + * The ID of the device where the memory operation is taking place. + */ + uint32_t deviceId; + + /** + * The ID of the context. If context is NULL, \p contextId is set to CUPTI_INVALID_CONTEXT_ID. + */ + uint32_t contextId; + + /** + * The ID of the stream. If memory operation is not async, \p streamId is set to CUPTI_INVALID_STREAM_ID. + */ + uint32_t streamId; + + /** + * Variable name. This name is shared across all activity + * records representing the same symbol, and so should not be + * modified. + */ + const char* name; + + /** + * \p isAsync is set if memory operation happens through async memory APIs. + */ + uint32_t isAsync; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad1; +#endif + + /** + * The memory pool configuration used for the memory operations. + */ + struct PACKED_ALIGNMENT { + /** + * The type of the memory pool, \ref CUpti_ActivityMemoryPoolType + */ + CUpti_ActivityMemoryPoolType memoryPoolType; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad2; +#endif + + /** + * The base address of the memory pool. + */ + uint64_t address; + + /** + * The release threshold of the memory pool in bytes. \p releaseThreshold is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t releaseThreshold; + + /** + * The size of memory pool in bytes and the processId of the memory pools + * \p size is valid if \p memoryPoolType is + * CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + * \p processId is valid if \p memoryPoolType is + * CUPTI_ACTIVITY_MEMORY_POOL_TYPE_IMPORTED, \ref CUpti_ActivityMemoryPoolType + */ + union { + uint64_t size; + uint64_t processId; + } pool; + + /** + * The utilized size of the memory pool. \p utilizedSize is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t utilizedSize; + } memoryPoolConfig; + + /** + * The shared object or binary that the memory allocation request comes from. + */ + const char* source; +} CUpti_ActivityMemory4; + +/** + * \brief The activity record for memory pool. + * + * This activity record represents a memory pool creation, destruction and + * trimming (CUPTI_ACTIVITY_KIND_MEMORY_POOL). + * This activity record provides separate records for memory pool creation, + * destruction and trimming operations. + * This allows to correlate the corresponding driver and runtime API + * activity record with the memory pool operation. + * + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMORY_POOL + */ + CUpti_ActivityKind kind; + + /** + * The memory operation requested by the user, \ref CUpti_ActivityMemoryPoolOperationType. + */ + CUpti_ActivityMemoryPoolOperationType memoryPoolOperationType; + + /** + * The type of the memory pool, \ref CUpti_ActivityMemoryPoolType + */ + CUpti_ActivityMemoryPoolType memoryPoolType; + + /** + * The correlation ID of the memory pool operation. Each memory pool + * operation is assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory operation. + */ + uint32_t correlationId; + + /** + * The ID of the process to which this record belongs to. + */ + uint32_t processId; + + /** + * The ID of the device where the memory pool is created. + */ + uint32_t deviceId; + + /** + * The minimum bytes to keep of the memory pool. \p minBytesToKeep is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_OPERATION_TYPE_TRIMMED, + * \ref CUpti_ActivityMemoryPoolOperationType + */ + size_t minBytesToKeep; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The virtual address of the allocation. + */ + uint64_t address; + + /** + * The size of the memory pool operation in bytes. \p size is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t size; + + /** + * The release threshold of the memory pool. \p releaseThreshold is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t releaseThreshold; + + /** + * The start timestamp for the memory operation, in ns. + */ + uint64_t timestamp; + + /** + * The utilized size of the memory pool. \p utilizedSize is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t utilizedSize; +} CUpti_ActivityMemoryPool2; + +/** + * \brief The type of the CUDA kernel launch. + */ +typedef enum { + /** + * The kernel was launched via a regular kernel call + */ + CUPTI_ACTIVITY_LAUNCH_TYPE_REGULAR = 0, + + /** + * The kernel was launched via API \ref cudaLaunchCooperativeKernel() or + * \ref cuLaunchCooperativeKernel() + */ + CUPTI_ACTIVITY_LAUNCH_TYPE_COOPERATIVE_SINGLE_DEVICE = 1, + + /** + * The kernel was launched via API \ref cudaLaunchCooperativeKernelMultiDevice() or + * \ref cuLaunchCooperativeKernelMultiDevice() + */ + CUPTI_ACTIVITY_LAUNCH_TYPE_COOPERATIVE_MULTI_DEVICE = 2, + + /** + * The kernel was launched as a CBL commandlist + */ + CUPTI_ACTIVITY_LAUNCH_TYPE_CBL_COMMANDLIST = 3, +} CUpti_ActivityLaunchType; + +/** + * \brief The shared memory limit per block config for a kernel + * This should be used to set 'cudaOccFuncShmemConfig' field in occupancy calculator API + */ +typedef enum { + /** The shared memory limit config is default + */ + CUPTI_FUNC_SHMEM_LIMIT_DEFAULT = 0x00, + + /** User has opted for a higher dynamic shared memory limit using function attribute + * 'cudaFuncAttributeMaxDynamicSharedMemorySize' for runtime API or + * CU_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES for driver API + */ + CUPTI_FUNC_SHMEM_LIMIT_OPTIN = 0x01, + + CUPTI_FUNC_SHMEM_LIMIT_FORCE_INT = 0x7fffffff +} CUpti_FuncShmemLimitConfig; + +/** + * \brief The activity record for kernel. + * + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL) + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL or + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + /** + * For devices with compute capability 7.0+ cacheConfig values are not updated + * in case field isSharedMemoryCarveoutRequested is set + */ + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The partitioned global caching requested for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheRequested; + + /** + * The partitioned global caching executed for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. Partitioned global caching can be + * automatically disabled if the occupancy requirement of the launch cannot + * support caching. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheExecuted; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The completed timestamp for the kernel execution, in ns. It + * represents the completion of all it's child kernels and the + * kernel itself. A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the completion time is unknown. + */ + uint64_t completed; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes (deprecated in CUDA 11.8). + * Refer field localMemoryTotal_v2 + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel is assigned a unique + * grid ID at runtime. + */ + int64_t gridId; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The timestamp when the kernel is queued up in the command buffer, in ns. + * A value of CUPTI_TIMESTAMP_UNKNOWN indicates that the queued time + * could not be collected for the kernel. This timestamp is not collected + * by default. Use API \ref cuptiActivityEnableLatencyTimestamps() to + * enable collection. + * + * Command buffer is a buffer written by CUDA driver to send commands + * like kernel launch, memory copy etc to the GPU. All launches of CUDA + * kernels are asynchronous with respect to the host, the host requests + * the launch by writing commands into the command buffer, then returns + * without checking the GPU's progress. + */ + uint64_t queued; + + /** + * The timestamp when the command buffer containing the kernel launch + * is submitted to the GPU, in ns. A value of CUPTI_TIMESTAMP_UNKNOWN + * indicates that the submitted time could not be collected for the kernel. + * This timestamp is not collected by default. Use API \ref + * cuptiActivityEnableLatencyTimestamps() to enable collection. + */ + uint64_t submitted; + + /** + * The indicates if the kernel was executed via a regular launch or via a + * single/multi device cooperative launch. \see CUpti_ActivityLaunchType + */ + uint8_t launchType; + + /** + * This indicates if CU_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT was + * updated for the kernel launch + */ + uint8_t isSharedMemoryCarveoutRequested; + + /** + * Shared memory carveout value requested for the function in percentage of + * the total resource. The value will be updated only if field + * isSharedMemoryCarveoutRequested is set. + */ + uint8_t sharedMemoryCarveoutRequested; + + /** + * Undefined. Reserved for internal use. + */ + uint8_t padding; + + /** + * Shared memory size set by the driver. + */ + uint32_t sharedMemoryExecuted; + + /** + * The unique ID of the graph node that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint64_t graphNodeId; + + /** + * The shared memory limit config for the kernel. This field shows whether user has opted for a + * higher per block limit of dynamic shared memory. + */ + CUpti_FuncShmemLimitConfig shmemLimitConfig; + + /** + * The unique ID of the graph that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint32_t graphId; + + /** + * The pointer to the access policy window. The structure CUaccessPolicyWindow is + * defined in cuda.h. + */ + CUaccessPolicyWindow *pAccessPolicyWindow; + + /** + * The ID of the HW channel on which the kernel is launched. + */ + uint32_t channelID; + + /** + * The type of the channel + */ + CUpti_ChannelType channelType; + + /** + * The X-dimension cluster size for the kernel. + * Field is valid for devices with compute capability 9.0 and higher + */ + uint32_t clusterX; + + /** + * The Y-dimension cluster size for the kernel. + * Field is valid for devices with compute capability 9.0 and higher + */ + uint32_t clusterY; + + /** + * The Z-dimension cluster size for the kernel. + * Field is valid for devices with compute capability 9.0 and higher + */ + uint32_t clusterZ; + + /** + * The cluster scheduling policy for the kernel. Refer CUclusterSchedulingPolicy + * Field is valid for devices with compute capability 9.0 and higher + */ + uint32_t clusterSchedulingPolicy; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint64_t localMemoryTotal_v2; + + /** + * The maximum cluster size for the kernel + */ + uint32_t maxPotentialClusterSize; + + /** + * The maximum clusters that could co-exist on the target device for the kernel + */ + uint32_t maxActiveClusters; +} CUpti_ActivityKernel9; + +/** + * \brief The activity record for CDP (CUDA Dynamic Parallelism) + * kernel. + * + * This activity record represents a CDP kernel execution. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_CDP_KERNEL + */ + CUpti_ActivityKind kind; + + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel execution + * is assigned a unique grid ID. + */ + int64_t gridId; + + /** + * The grid ID of the parent kernel. + */ + int64_t parentGridId; + + /** + * The timestamp when kernel is queued up, in ns. A value of + * CUPTI_TIMESTAMP_UNKNOWN indicates that the queued time is + * unknown. + */ + uint64_t queued; + + /** + * The timestamp when kernel is submitted to the gpu, in ns. A value + * of CUPTI_TIMESTAMP_UNKNOWN indicates that the submission time is + * unknown. + */ + uint64_t submitted; + + /** + * The timestamp when kernel is marked as completed, in ns. A value + * of CUPTI_TIMESTAMP_UNKNOWN indicates that the completion time is + * unknown. + */ + uint64_t completed; + + /** + * The X-dimension of the parent block. + */ + uint32_t parentBlockX; + + /** + * The Y-dimension of the parent block. + */ + uint32_t parentBlockY; + + /** + * The Z-dimension of the parent block. + */ + uint32_t parentBlockZ; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; +} CUpti_ActivityCdpKernel; + +/** + * \brief The activity record for a preemption of a CDP kernel. + * + * This activity record represents a preemption of a CDP kernel. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_PREEMPTION + */ + CUpti_ActivityKind kind; + + /** + * kind of the preemption + */ + CUpti_ActivityPreemptionKind preemptionKind; + + /** + * The timestamp of the preemption, in ns. A value of 0 indicates + * that timestamp information could not be collected for the + * preemption. + */ + uint64_t timestamp; + + /** + * The grid-id of the block that is preempted + */ + int64_t gridId; + + /** + * The X-dimension of the block that is preempted + */ + uint32_t blockX; + + /** + * The Y-dimension of the block that is preempted + */ + uint32_t blockY; + + /** + * The Z-dimension of the block that is preempted + */ + uint32_t blockZ; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityPreemption; + +/** + * \brief The activity record for a driver or runtime API invocation. + * + * This activity record represents an invocation of a driver or + * runtime API (CUPTI_ACTIVITY_KIND_DRIVER and + * CUPTI_ACTIVITY_KIND_RUNTIME). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_DRIVER, + * CUPTI_ACTIVITY_KIND_RUNTIME, or CUPTI_ACTIVITY_KIND_INTERNAL_LAUNCH_API. + */ + CUpti_ActivityKind kind; + + /** + * The ID of the driver or runtime function. + */ + CUpti_CallbackId cbid; + + /** + * The start timestamp for the function, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the function. + */ + uint64_t start; + + /** + * The end timestamp for the function, in ns. A value of 0 for both + * the start and end timestamps indicates that timestamp information + * could not be collected for the function. + */ + uint64_t end; + + /** + * The ID of the process where the driver or runtime CUDA function + * is executing. + */ + uint32_t processId; + + /** + * The ID of the thread where the driver or runtime CUDA function is + * executing. + */ + uint32_t threadId; + + /** + * The correlation ID of the driver or runtime CUDA function. Each + * function invocation is assigned a unique correlation ID that is + * identical to the correlation ID in the memcpy, memset, or kernel + * activity record that is associated with this function. + */ + uint32_t correlationId; + + /** + * The return value for the function. For a CUDA driver function + * with will be a CUresult value, and for a CUDA runtime function + * this will be a cudaError_t value. + */ + uint32_t returnValue; +} CUpti_ActivityAPI; + +/** + * \brief The activity record for a CUPTI event. + * + * This activity record represents a CUPTI event value + * (CUPTI_ACTIVITY_KIND_EVENT). This activity record kind is not + * produced by the activity API but is included for completeness and + * ease-of-use. Profile frameworks built on top of CUPTI that collect + * event data may choose to use this type to store the collected event + * data. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_EVENT. + */ + CUpti_ActivityKind kind; + + /** + * The event ID. + */ + CUpti_EventID id; + + /** + * The event value. + */ + uint64_t value; + + /** + * The event domain ID. + */ + CUpti_EventDomainID domain; + + /** + * The correlation ID of the event. Use of this ID is user-defined, + * but typically this ID value will equal the correlation ID of the + * kernel for which the event was gathered. + */ + uint32_t correlationId; +} CUpti_ActivityEvent; + +/** + * \brief The activity record for a CUPTI event with instance + * information. + * + * This activity record represents the a CUPTI event value for a + * specific event domain instance + * (CUPTI_ACTIVITY_KIND_EVENT_INSTANCE). This activity record kind is + * not produced by the activity API but is included for completeness + * and ease-of-use. Profile frameworks built on top of CUPTI that + * collect event data may choose to use this type to store the + * collected event data. This activity record should be used when + * event domain instance information needs to be associated with the + * event. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be + * CUPTI_ACTIVITY_KIND_EVENT_INSTANCE. + */ + CUpti_ActivityKind kind; + + /** + * The event ID. + */ + CUpti_EventID id; + + /** + * The event domain ID. + */ + CUpti_EventDomainID domain; + + /** + * The event domain instance. + */ + uint32_t instance; + + /** + * The event value. + */ + uint64_t value; + + /** + * The correlation ID of the event. Use of this ID is user-defined, + * but typically this ID value will equal the correlation ID of the + * kernel for which the event was gathered. + */ + uint32_t correlationId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityEventInstance; + +/** + * \brief The activity record for a CUPTI metric. + * + * This activity record represents the collection of a CUPTI metric + * value (CUPTI_ACTIVITY_KIND_METRIC). This activity record kind is not + * produced by the activity API but is included for completeness and + * ease-of-use. Profile frameworks built on top of CUPTI that collect + * metric data may choose to use this type to store the collected metric + * data. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_METRIC. + */ + CUpti_ActivityKind kind; + + /** + * The metric ID. + */ + CUpti_MetricID id; + + /** + * The metric value. + */ + CUpti_MetricValue value; + + /** + * The correlation ID of the metric. Use of this ID is user-defined, + * but typically this ID value will equal the correlation ID of the + * kernel for which the metric was gathered. + */ + uint32_t correlationId; + + /** + * The properties of this metric. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * Undefined. Reserved for internal use. + */ + uint8_t pad[3]; +} CUpti_ActivityMetric; + +/** + * \brief The activity record for a CUPTI metric with instance + * information. + * + * This activity record represents a CUPTI metric value + * for a specific metric domain instance + * (CUPTI_ACTIVITY_KIND_METRIC_INSTANCE). This activity record kind + * is not produced by the activity API but is included for + * completeness and ease-of-use. Profile frameworks built on top of + * CUPTI that collect metric data may choose to use this type to store + * the collected metric data. This activity record should be used when + * metric domain instance information needs to be associated with the + * metric. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be + * CUPTI_ACTIVITY_KIND_METRIC_INSTANCE. + */ + CUpti_ActivityKind kind; + + /** + * The metric ID. + */ + CUpti_MetricID id; + + /** + * The metric value. + */ + CUpti_MetricValue value; + + /** + * The metric domain instance. + */ + uint32_t instance; + + /** + * The correlation ID of the metric. Use of this ID is user-defined, + * but typically this ID value will equal the correlation ID of the + * kernel for which the metric was gathered. + */ + uint32_t correlationId; + + /** + * The properties of this metric. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * Undefined. Reserved for internal use. + */ + uint8_t pad[7]; +} CUpti_ActivityMetricInstance; + +/** + * \brief The activity record for source locator. + * + * This activity record represents a source locator + * (CUPTI_ACTIVITY_KIND_SOURCE_LOCATOR). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_SOURCE_LOCATOR. + */ + CUpti_ActivityKind kind; + + /** + * The ID for the source path, will be used in all the source level + * results. + */ + uint32_t id; + + /** + * The line number in the source . + */ + uint32_t lineNumber; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The path for the file. + */ + const char *fileName; +} CUpti_ActivitySourceLocator; + +/** + * \brief The activity record for source-level global + * access. + * + * This activity records the locations of the global + * accesses in the source (CUPTI_ACTIVITY_KIND_GLOBAL_ACCESS). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_GLOBAL_ACCESS. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this global access. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * The number of times this instruction was executed per warp. It will be incremented + * when at least one of thread among warp is active with predicate and condition code + * evaluating to true. + */ + uint32_t executed; + + /** + * The pc offset for the access. + */ + uint64_t pcOffset; + + /** + * This increments each time when this instruction is executed by number of + * threads that executed this instruction with predicate and condition code + * evaluating to true. + */ + uint64_t threadsExecuted; + + /** + * The total number of 32 bytes transactions to L2 cache generated by this + access + */ + uint64_t l2_transactions; + + /** + * The minimum number of L2 transactions possible based on the access pattern. + */ + uint64_t theoreticalL2Transactions; +} CUpti_ActivityGlobalAccess3; + +/** + * \brief The activity record for source level result + * branch. + * + * This activity record the locations of the branches in the + * source (CUPTI_ACTIVITY_KIND_BRANCH). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_BRANCH. + */ + CUpti_ActivityKind kind; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * The pc offset for the branch. + */ + uint32_t pcOffset; + + /** + * Number of times this branch diverged + */ + uint32_t diverged; + + /** + * This increments each time when this instruction is executed by number + * of threads that executed this instruction + */ + uint64_t threadsExecuted; + + /** + * The number of times this instruction was executed per warp. It will be incremented + * regardless of predicate or condition code. + */ + uint32_t executed; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityBranch2; + +/** + * \brief The activity record for a device. (CUDA 11.6 onwards) + * + * This activity record represents information about a GPU device + * (CUPTI_ACTIVITY_KIND_DEVICE). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_DEVICE. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the device. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The global memory bandwidth available on the device, in + * kBytes/sec. + */ + uint64_t globalMemoryBandwidth; + + /** + * The amount of global memory on the device, in bytes. + */ + uint64_t globalMemorySize; + + /** + * The amount of constant memory on the device, in bytes. + */ + uint32_t constantMemorySize; + + /** + * The size of the L2 cache on the device, in bytes. + */ + uint32_t l2CacheSize; + + /** + * The number of threads per warp on the device. + */ + uint32_t numThreadsPerWarp; + + /** + * The core clock rate of the device, in kHz. + */ + uint32_t coreClockRate; + + /** + * Number of memory copy engines on the device. + */ + uint32_t numMemcpyEngines; + + /** + * Number of multiprocessors on the device. + */ + uint32_t numMultiprocessors; + + /** + * The maximum "instructions per cycle" possible on each device + * multiprocessor. + */ + uint32_t maxIPC; + + /** + * Maximum number of warps that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxWarpsPerMultiprocessor; + + /** + * Maximum number of blocks that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxBlocksPerMultiprocessor; + + /** + * Maximum amount of shared memory available per multiprocessor, in bytes. + */ + uint32_t maxSharedMemoryPerMultiprocessor; + + /** + * Maximum number of 32-bit registers available per multiprocessor. + */ + uint32_t maxRegistersPerMultiprocessor; + + /** + * Maximum number of registers that can be allocated to a block. + */ + uint32_t maxRegistersPerBlock; + + /** + * Maximum amount of shared memory that can be assigned to a block, + * in bytes. + */ + uint32_t maxSharedMemoryPerBlock; + + /** + * Maximum number of threads allowed in a block. + */ + uint32_t maxThreadsPerBlock; + + /** + * Maximum allowed X dimension for a block. + */ + uint32_t maxBlockDimX; + + /** + * Maximum allowed Y dimension for a block. + */ + uint32_t maxBlockDimY; + + /** + * Maximum allowed Z dimension for a block. + */ + uint32_t maxBlockDimZ; + + /** + * Maximum allowed X dimension for a grid. + */ + uint32_t maxGridDimX; + + /** + * Maximum allowed Y dimension for a grid. + */ + uint32_t maxGridDimY; + + /** + * Maximum allowed Z dimension for a grid. + */ + uint32_t maxGridDimZ; + + /** + * Compute capability for the device, major number. + */ + uint32_t computeCapabilityMajor; + + /** + * Compute capability for the device, minor number. + */ + uint32_t computeCapabilityMinor; + + /** + * The device ID. + */ + uint32_t id; + + /** + * ECC enabled flag for device + */ + uint32_t eccEnabled; + + /** + * The device UUID. This value is the globally unique immutable + * alphanumeric identifier of the device. + */ + CUuuid uuid; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The device name. This name is shared across all activity records + * representing instances of the device, and so should not be + * modified. + */ + const char *name; + + /** + * Flag to indicate whether the device is visible to CUDA. Users can + * set the device visibility using CUDA_VISIBLE_DEVICES environment + */ + uint8_t isCudaVisible; + + /** + * MIG enabled flag for device + */ + uint8_t isMigEnabled; + + uint8_t reserved[6]; + + /** + * GPU Instance id for MIG enabled devices. + * If mig mode is disabled value is set to UINT32_MAX + */ + uint32_t gpuInstanceId; + + /** + * Compute Instance id for MIG enabled devices. + * If mig mode is disabled value is set to UINT32_MAX + */ + uint32_t computeInstanceId; + + /** + * The MIG UUID. This value is the globally unique immutable + * alphanumeric identifier of the device. + */ + CUuuid migUuid; + + /** + * Numa (Non-uniform memory access) information for device + * GPU is a NUMA node or not + */ + uint32_t isNumaNode; + + /** + * Numa (Non-uniform memory access) information for device + * NUMA node ID of the GPU memory + * if GPU is not a NUMA node, it returns invalidNumaId + */ + uint32_t numaId; +} CUpti_ActivityDevice5; + +/** + * \brief The activity record for a device attribute. + * + * This activity record represents information about a GPU device: + * either a CUpti_DeviceAttribute or CUdevice_attribute value + * (CUPTI_ACTIVITY_KIND_DEVICE_ATTRIBUTE). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be + * CUPTI_ACTIVITY_KIND_DEVICE_ATTRIBUTE. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the device. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The ID of the device that this attribute applies to. + */ + uint32_t deviceId; + + /** + * The attribute, either a CUpti_DeviceAttribute or + * CUdevice_attribute. Flag + * CUPTI_ACTIVITY_FLAG_DEVICE_ATTRIBUTE_CUDEVICE is used to indicate + * what kind of attribute this is. If + * CUPTI_ACTIVITY_FLAG_DEVICE_ATTRIBUTE_CUDEVICE is 1 then + * CUdevice_attribute field is value, otherwise + * CUpti_DeviceAttribute field is valid. + */ + union { + CUdevice_attribute cu; + CUpti_DeviceAttribute cupti; + } attribute; + + /** + * The value for the attribute. See CUpti_DeviceAttribute and + * CUdevice_attribute for the type of the value for a given + * attribute. + */ + union { + double vDouble; + uint32_t vUint32; + uint64_t vUint64; + int32_t vInt32; + int64_t vInt64; + } value; +} CUpti_ActivityDeviceAttribute; + +/** + * \brief The activity record for a context. + * + * This activity record represents information about a context + * (CUPTI_ACTIVITY_KIND_CONTEXT). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_CONTEXT. + */ + CUpti_ActivityKind kind; + + /** + * The context ID. + */ + uint32_t contextId; + + /** + * The device ID. + */ + uint32_t deviceId; + + /** + * The compute API kind. \see CUpti_ActivityComputeApiKind + */ + uint16_t computeApiKind; + + /** + * The ID for the NULL stream in this context + */ + uint16_t nullStreamId; + + /** + * The ID of the parent context. It would be 0 if + * context does not have parent + */ + uint32_t parentContextId; + + /** + * This field indicates whether the context is a green context + */ + uint8_t isGreenContext; + + uint8_t padding; + + /** + * Number of multiprocessors assigned to the green context + * Invalid if the field 'isGreenContext' is 0 + */ + uint16_t numMultiprocessors; + + /** + * This field indicates the CIG mode + */ + CUpti_ContextCigMode cigMode; + + uint32_t padding2; + +} CUpti_ActivityContext3; + +/** + * \brief The activity record providing a name. + * + * This activity record provides a name for a device, context, thread, + * etc. and other resource naming done via NVTX APIs + * (CUPTI_ACTIVITY_KIND_NAME). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_NAME. + */ + CUpti_ActivityKind kind; + + /** + * The kind of activity object being named. + */ + CUpti_ActivityObjectKind objectKind; + + /** + * The identifier for the activity object. 'objectKind' indicates + * which ID is valid for this record. + */ + CUpti_ActivityObjectKindId objectId; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The name. + */ + const char *name; + +} CUpti_ActivityName; + +/** + * \brief The activity record providing a marker which is an + * instantaneous point in time. + * + * The marker is specified with a descriptive name and unique id + * (CUPTI_ACTIVITY_KIND_MARKER). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MARKER. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the marker. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The timestamp for the marker, in ns. A value of 0 indicates that + * timestamp information could not be collected for the marker. + */ + uint64_t timestamp; + + /** + * The marker ID. + */ + uint32_t id; + + /** + * The kind of activity object associated with this marker. + */ + CUpti_ActivityObjectKind objectKind; + + /** + * The identifier for the activity object associated with this + * marker. 'objectKind' indicates which ID is valid for this record. + */ + CUpti_ActivityObjectKindId objectId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; + + + /** + * The marker name for an instantaneous or start marker. This will + * be NULL for an end marker. + */ + const char *name; + + /** + * The name of the domain to which this marker belongs to. + * This will be NULL for default domain. + */ + const char *domain; + +} CUpti_ActivityMarker2; + +/** + * \brief The activity record providing detailed information for a marker. + * + * User must enable CUPTI_ACTIVITY_KIND_MARKER as well + * to get records for marker data. + * The marker data contains color, payload, and category. + * (CUPTI_ACTIVITY_KIND_MARKER_DATA). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be + * CUPTI_ACTIVITY_KIND_MARKER_DATA. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the marker. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The marker ID. + */ + uint32_t id; + + /** + * Defines the payload format for the value associated with the marker. + */ + CUpti_MetricValueKind payloadKind; + + /** + * The payload value. + */ + CUpti_MetricValue payload; + + /** + * The color for the marker. + */ + uint32_t color; + + /** + * The category for the marker. + */ + uint32_t category; + +} CUpti_ActivityMarkerData; + +/** + * \brief The activity record for CUPTI and driver overheads. + * + * This activity record provides CUPTI and driver overhead information + * (CUPTI_ACTIVITY_KIND_OVERHEAD). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_OVERHEAD. + */ + CUpti_ActivityKind kind; + + /** + * The kind of overhead, CUPTI, DRIVER, COMPILER etc. + */ + CUpti_ActivityOverheadKind overheadKind; + + /** + * The kind of activity object that the overhead is associated with. + */ + CUpti_ActivityObjectKind objectKind; + + /** + * The identifier for the activity object. 'objectKind' indicates + * which ID is valid for this record. + */ + CUpti_ActivityObjectKindId objectId; + + /** + * The start timestamp for the overhead, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the overhead. + */ + uint64_t start; + + /** + * The end timestamp for the overhead, in ns. A value of 0 for both + * the start and end timestamps indicates that timestamp information + * could not be collected for the overhead. + */ + uint64_t end; + + /** + * The correlation ID of the overhead operation to which + * records belong to. This ID is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the overhead operation. + * In some cases, it can be zero, such as for CUPTI_ACTIVITY_OVERHEAD_CUPTI_BUFFER_FLUSH records. + */ + uint32_t correlationId; + + /** + * Reserved for internal use. + */ + uint32_t reserved0; + + /** + * Pointer to the struct with additional details about the overhead. + * Refer CUpti_ActivityOverheadKind enum and the corresponding structure to typecast and access additional overhead data. + * Client is responsible for freeing this memory using the free function when done. + */ + void *overheadData; + +} CUpti_ActivityOverhead3; + +/** + * \brief The activity record for CUPTI environmental data. + * + * This activity record provides CUPTI environmental data, include + * power, clocks, and thermals. This information is sampled at + * various rates and returned in this activity record. The consumer + * of the record needs to check the environmentKind field to figure + * out what kind of environmental record this is. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_ENVIRONMENT. + */ + CUpti_ActivityKind kind; + + /** + * The ID of the device + */ + uint32_t deviceId; + + /** + * The timestamp when this sample was retrieved, in ns. A value of 0 + * indicates that timestamp information could not be collected for + * the marker. + */ + uint64_t timestamp; + + /** + * The kind of data reported in this record. + */ + CUpti_ActivityEnvironmentKind environmentKind; + + union { + /** + * Data returned for CUPTI_ACTIVITY_ENVIRONMENT_SPEED environment + * kind. + */ + struct { + /** + * The SM frequency in MHz + */ + uint32_t smClock; + + /** + * The memory frequency in MHz + */ + uint32_t memoryClock; + + /** + * The PCIe link generation. + */ + uint32_t pcieLinkGen; + + /** + * The PCIe link width. + */ + uint32_t pcieLinkWidth; + + /** + * The clocks throttle reasons. + */ + CUpti_EnvironmentClocksThrottleReason clocksThrottleReasons; + } speed; + + /** + * Data returned for CUPTI_ACTIVITY_ENVIRONMENT_TEMPERATURE + * environment kind. + */ + struct { + /** + * The GPU temperature in degrees C. + */ + uint32_t gpuTemperature; + } temperature; + + /** + * Data returned for CUPTI_ACTIVITY_ENVIRONMENT_POWER environment kind. + * The power in milliwatts consumed by GPU and associated circuitry. + * The power in milliwatts that will trigger power management algorithm. + */ + struct { + + uint32_t power; + uint32_t powerLimit; + } power; + + /** + * Data returned for CUPTI_ACTIVITY_ENVIRONMENT_COOLING + * environment kind. + */ + struct { + /** + * The fan speed as percentage of maximum. + */ + uint32_t fanSpeed; + } cooling; + } data; +} CUpti_ActivityEnvironment; + +/** + * \brief The activity record for source-level instruction execution. + * + * This activity records result for source level instruction execution. + * (CUPTI_ACTIVITY_KIND_INSTRUCTION_EXECUTION). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_INSTRUCTION_EXECUTION. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this instruction execution. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * The pc offset for the instruction. + */ + uint32_t pcOffset; + + /** + * This increments each time when this instruction is executed by number + * of threads that executed this instruction, regardless of predicate or condition code. + */ + uint64_t threadsExecuted; + + /** + * This increments each time when this instruction is executed by number + * of threads that executed this instruction with predicate and condition code evaluating to true. + */ + uint64_t notPredOffThreadsExecuted; + + /** + * The number of times this instruction was executed per warp. It will be incremented + * regardless of predicate or condition code. + */ + uint32_t executed; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityInstructionExecution; + +/** + * \brief The activity record for PC sampling. + * + * This activity records information obtained by sampling PC + * (CUPTI_ACTIVITY_KIND_PC_SAMPLING). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_PC_SAMPLING. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this instruction. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * Number of times the PC was sampled with the stallReason in the record. + * These samples indicate that no instruction was issued in that cycle from + * the warp scheduler from where the warp was sampled. + * Field is valid for devices with compute capability 6.0 and higher + */ + uint32_t latencySamples; + + /** + * Number of times the PC was sampled with the stallReason in the record. + * The same PC can be sampled with different stall reasons. The count includes + * latencySamples. + */ + uint32_t samples; + + /** + * Current stall reason. Includes one of the reasons from + * \ref CUpti_ActivityPCSamplingStallReason + */ + CUpti_ActivityPCSamplingStallReason stallReason; + + /** + * The pc offset for the instruction. + */ + uint64_t pcOffset; +} CUpti_ActivityPCSampling3; + +/** + * \brief The activity record for record status for PC sampling. + * + * This activity records information obtained by sampling PC + * (CUPTI_ACTIVITY_KIND_PC_SAMPLING_RECORD_INFO). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_PC_SAMPLING_RECORD_INFO. + */ + CUpti_ActivityKind kind; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Number of times the PC was sampled for this kernel instance including all + * dropped samples. + */ + uint64_t totalSamples; + + /** + * Number of samples that were dropped by hardware due to backpressure/overflow. + */ + uint64_t droppedSamples; + /** + * Sampling period in terms of number of cycles . + */ + uint64_t samplingPeriodInCycles; +} CUpti_ActivityPCSamplingRecordInfo; + +/** + * \brief The activity record for Unified Memory counters (CUDA 7.0 and beyond) + * + * This activity record represents a Unified Memory counter + * (CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER + */ + CUpti_ActivityKind kind; + + /** + * The Unified Memory counter kind + */ + CUpti_ActivityUnifiedMemoryCounterKind counterKind; + + /** + * Value of the counter + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD, + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH, + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THREASHING and + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP, it is the size of the + * memory region in bytes. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT, it + * is the number of page fault groups for the same page. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT, + * it is the program counter for the instruction that caused fault. + */ + uint64_t value; + + /** + * The start timestamp of the counter, in ns. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD and + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH, timestamp is + * captured when activity starts on GPU. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT and + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT, timestamp is + * captured when CUDA driver started processing the fault. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING, timestamp + * is captured when CUDA driver detected thrashing of memory region. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING, + * timestamp is captured when throttling operation was started by CUDA driver. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP, + * timestamp is captured when CUDA driver has pushed all required operations + * to the processor specified by dstId. + */ + uint64_t start; + + /** + * The end timestamp of the counter, in ns. + * Ignore this field if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD and + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH, timestamp is + * captured when activity finishes on GPU. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT, timestamp is + * captured when CUDA driver queues the replay of faulting memory accesses on the GPU + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING, timestamp + * is captured when throttling operation was finished by CUDA driver + */ + uint64_t end; + + /** + * This is the virtual base address of the page/s being transferred. For cpu and + * gpu faults, the virtual address for the page that faulted. + */ + uint64_t address; + + /** + * The ID of the source CPU/device involved in the memory transfer, page fault, thrashing, + * throttling or remote map operation. For counterKind + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING, it is a bitwise ORing of the + * device IDs fighting for the memory region, ONLY if there are less than 32 devices. Ignore this field if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT + */ + uint32_t srcId; + + /** + * The ID of the destination CPU/device involved in the memory transfer or remote map + * operation. Ignore this field if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING + */ + uint32_t dstId; + + /** + * The ID of the stream causing the transfer. + * This value of this field is invalid. + */ + uint32_t streamId; + + /** + * The ID of the process to which this record belongs to. + */ + uint32_t processId; + + /** + * The flags associated with this record. See enums \ref CUpti_ActivityUnifiedMemoryAccessType + * if counterKind is CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT + * and \ref CUpti_ActivityUnifiedMemoryMigrationCause if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD + * and \ref CUpti_ActivityUnifiedMemoryRemoteMapCause if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP and \ref CUpti_ActivityFlag + * if counterKind is CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING + */ + uint32_t flags; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; + + /** + * \brief The bitmask of devices involved in the operation. + * + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING, it is a bitwise ORing of the + * device IDs fighting for the memory region. processors[0] represents the device ID of the device 0 to device 63, + * processors[1] represents device ID of device 64 to device 127 and so on. + * Ignore this field if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_DTOD or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_FAULT_REPLAY + */ + uint64_t processors[5]; +} CUpti_ActivityUnifiedMemoryCounter3; + +/** + * \brief The activity record for global/device functions. + * + * This activity records function name and corresponding module + * information. + * (CUPTI_ACTIVITY_KIND_FUNCTION). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_FUNCTION. + */ + CUpti_ActivityKind kind; + + /** + * ID to uniquely identify the record + */ + uint32_t id; + + /** + * The ID of the context where the function is launched. + */ + uint32_t contextId; + + /** + * The module ID in which this global/device function is present. + */ + uint32_t moduleId; + + /** + * The function's unique symbol index in the module. + */ + uint32_t functionIndex; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The name of the function. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; +} CUpti_ActivityFunction; + +/** + * \brief The activity record for a CUDA module. + * + * This activity record represents a CUDA module + * (CUPTI_ACTIVITY_KIND_MODULE). This activity record kind is not + * produced by the activity API but is included for completeness and + * ease-of-use. Profile frameworks built on top of CUPTI that collect + * module data from the module callback may choose to use this type to + * store the collected module data. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MODULE. + */ + CUpti_ActivityKind kind; + + /** + * The ID of the context where the module is loaded. + */ + uint32_t contextId; + + /** + * The module ID. + */ + uint32_t id; + + /** + * The cubin size. + */ + uint32_t cubinSize; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The pointer to cubin. + */ + const void *cubin; +} CUpti_ActivityModule; + +/** + * \brief The activity record for source-level shared + * access. + * + * This activity records the locations of the shared + * accesses in the source + * (CUPTI_ACTIVITY_KIND_SHARED_ACCESS). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_SHARED_ACCESS. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this shared access. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * The pc offset for the access. + */ + uint32_t pcOffset; + + /** + * This increments each time when this instruction is executed by number + * of threads that executed this instruction with predicate and condition code evaluating to true. + */ + uint64_t threadsExecuted; + + /** + * The total number of shared memory transactions generated by this access + */ + uint64_t sharedTransactions; + + /** + * The minimum number of shared memory transactions possible based on the access pattern. + */ + uint64_t theoreticalSharedTransactions; + + /** + * The number of times this instruction was executed per warp. It will be incremented + * when at least one of thread among warp is active with predicate and condition code + * evaluating to true. + */ + uint32_t executed; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivitySharedAccess; + +/** + * \brief The activity record for CUDA event. + * + * This activity is used to track recorded events. + * (CUPTI_ACTIVITY_KIND_CUDA_EVENT). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_CUDA_EVENT. + */ + CUpti_ActivityKind kind; + + /** + * The correlation ID of the API to which this result is associated. + */ + uint32_t correlationId; + + /** + * The ID of the context where the event was recorded. + */ + uint32_t contextId; + + /** + * The compute stream where the event was recorded. + */ + uint32_t streamId; + + /** + * A unique event ID to identify the event record. + */ + uint32_t eventId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; + + /** + * The ID of the device where the event was recorded. + */ + uint32_t deviceId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad2; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The device-side timestamp on CUDA event record. + * Timestamp is in nanoseconds. + */ + uint64_t deviceTimestamp; + /** + * A unique ID to associate event synchronization records + * with the latest CUDA Event record. Similar field is added + * in CUpti_ActivitySynchronization2 to associate CUDA Event + * record to the synchronization record. + * + * The same CUDA event can be used multiple times, so the + * event id will not be unique to correlate the synchronization + * record with the latest CUDA Event record. + * This field will be unique and can be used to do the required + * correlation. + */ + uint64_t cudaEventSyncId; +} CUpti_ActivityCudaEvent2; + +/** + * \brief The activity record for CUDA stream. + * + * This activity is used to track created streams. + * (CUPTI_ACTIVITY_KIND_STREAM). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_STREAM. + */ + CUpti_ActivityKind kind; + /** + * The ID of the context where the stream was created. + */ + uint32_t contextId; + + /** + * A unique stream ID to identify the stream. + */ + uint32_t streamId; + + /** + * The clamped priority for the stream. + */ + uint32_t priority; + + /** + * Flags associated with the stream. + */ + CUpti_ActivityStreamFlag flag; + + /** + * The correlation ID of the API to which this result is associated. + */ + uint32_t correlationId; +} CUpti_ActivityStream; + +/** + * \brief The activity record for synchronization management. + * + * This activity is used to track various CUDA synchronization APIs. + * (CUPTI_ACTIVITY_KIND_SYNCHRONIZATION). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_SYNCHRONIZATION. + */ + CUpti_ActivityKind kind; + + /** + * The type of record. + */ + CUpti_ActivitySynchronizationType type; + + /** + * The start timestamp for the function, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the function. + */ + uint64_t start; + + /** + * The end timestamp for the function, in ns. A value of 0 for both + * the start and end timestamps indicates that timestamp information + * could not be collected for the function. + */ + uint64_t end; + + /** + * The correlation ID of the API to which this result is associated. + */ + uint32_t correlationId; + + /** + * The ID of the context for which the synchronization API is called. + * In case of context synchronization API it is the context id for which the API is called. + * In case of stream/event synchronization it is the ID of the context where the stream/event was created. + */ + uint32_t contextId; + + /** + * The compute stream for which the synchronization API is called. + * A CUPTI_SYNCHRONIZATION_INVALID_VALUE value indicate the field is not applicable for this record. + * Not valid for cuCtxSynchronize, cuEventSynchronize. + */ + uint32_t streamId; + + /** + * The event ID for which the synchronization API is called. + * A CUPTI_SYNCHRONIZATION_INVALID_VALUE value indicate the field is not applicable for this record. + * Not valid for cuCtxSynchronize, cuStreamSynchronize. + */ + uint32_t cudaEventId; + + /** + * A unique ID to associate event synchronization records + * with the latest CUDA Event record. Similar field is added + * in CUpti_ActivityCudaEvent2 to associate synchronization + * record to the CUDA Event record. + * + * The same CUDA event can be used multiple times, so the + * event id will not be unique to correlate the synchronization + * record with the latest CUDA Event record. + * This field will be unique and can be used to do the required + * correlation. + * + * A CUPTI_SYNCHRONIZATION_INVALID_VALUE value indicates that + * the field is not applicable for this record. + * Valid only for synchronization records related to CUDA Events. + */ + uint64_t cudaEventSyncId; + + /** + * The return value for the synchronization record. + * Use cuptiActivityEnableAllSyncRecords API to enable/disable + * collection of synchronization records with return value being + * non-zero. This will be a CUresult value. + */ + uint32_t returnValue; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivitySynchronization2; + +/** + * \brief The activity record for source-level sass/source + * line-by-line correlation. + * + * This activity records source level sass/source correlation + * information. + * (CUPTI_ACTIVITY_KIND_INSTRUCTION_CORRELATION). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_INSTRUCTION_CORRELATION. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this instruction. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * The pc offset for the instruction. + */ + uint32_t pcOffset; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityInstructionCorrelation; + +/** + * \brief The OpenAcc event kind for OpenAcc activity records. + * + * \see CUpti_ActivityKindOpenAcc + */ +typedef enum { + CUPTI_OPENACC_EVENT_KIND_INVALID = 0, + CUPTI_OPENACC_EVENT_KIND_DEVICE_INIT = 1, + CUPTI_OPENACC_EVENT_KIND_DEVICE_SHUTDOWN = 2, + CUPTI_OPENACC_EVENT_KIND_RUNTIME_SHUTDOWN = 3, + CUPTI_OPENACC_EVENT_KIND_ENQUEUE_LAUNCH = 4, + CUPTI_OPENACC_EVENT_KIND_ENQUEUE_UPLOAD = 5, + CUPTI_OPENACC_EVENT_KIND_ENQUEUE_DOWNLOAD = 6, + CUPTI_OPENACC_EVENT_KIND_WAIT = 7, + CUPTI_OPENACC_EVENT_KIND_IMPLICIT_WAIT = 8, + CUPTI_OPENACC_EVENT_KIND_COMPUTE_CONSTRUCT = 9, + CUPTI_OPENACC_EVENT_KIND_UPDATE = 10, + CUPTI_OPENACC_EVENT_KIND_ENTER_DATA = 11, + CUPTI_OPENACC_EVENT_KIND_EXIT_DATA = 12, + CUPTI_OPENACC_EVENT_KIND_CREATE = 13, + CUPTI_OPENACC_EVENT_KIND_DELETE = 14, + CUPTI_OPENACC_EVENT_KIND_ALLOC = 15, + CUPTI_OPENACC_EVENT_KIND_FREE = 16, + CUPTI_OPENACC_EVENT_KIND_FORCE_INT = 0x7fffffff +} CUpti_OpenAccEventKind; + +/** + * \brief The OpenAcc parent construct kind for OpenAcc activity records. + */ +typedef enum { + CUPTI_OPENACC_CONSTRUCT_KIND_UNKNOWN = 0, + CUPTI_OPENACC_CONSTRUCT_KIND_PARALLEL = 1, + CUPTI_OPENACC_CONSTRUCT_KIND_KERNELS = 2, + CUPTI_OPENACC_CONSTRUCT_KIND_LOOP = 3, + CUPTI_OPENACC_CONSTRUCT_KIND_DATA = 4, + CUPTI_OPENACC_CONSTRUCT_KIND_ENTER_DATA = 5, + CUPTI_OPENACC_CONSTRUCT_KIND_EXIT_DATA = 6, + CUPTI_OPENACC_CONSTRUCT_KIND_HOST_DATA = 7, + CUPTI_OPENACC_CONSTRUCT_KIND_ATOMIC = 8, + CUPTI_OPENACC_CONSTRUCT_KIND_DECLARE = 9, + CUPTI_OPENACC_CONSTRUCT_KIND_INIT = 10, + CUPTI_OPENACC_CONSTRUCT_KIND_SHUTDOWN = 11, + CUPTI_OPENACC_CONSTRUCT_KIND_SET = 12, + CUPTI_OPENACC_CONSTRUCT_KIND_UPDATE = 13, + CUPTI_OPENACC_CONSTRUCT_KIND_ROUTINE = 14, + CUPTI_OPENACC_CONSTRUCT_KIND_WAIT = 15, + CUPTI_OPENACC_CONSTRUCT_KIND_RUNTIME_API = 16, + CUPTI_OPENACC_CONSTRUCT_KIND_FORCE_INT = 0x7fffffff + +} CUpti_OpenAccConstructKind; + +typedef enum { + CUPTI_OPENMP_EVENT_KIND_INVALID = 0, + CUPTI_OPENMP_EVENT_KIND_PARALLEL = 1, + CUPTI_OPENMP_EVENT_KIND_TASK = 2, + CUPTI_OPENMP_EVENT_KIND_THREAD = 3, + CUPTI_OPENMP_EVENT_KIND_IDLE = 4, + CUPTI_OPENMP_EVENT_KIND_WAIT_BARRIER = 5, + CUPTI_OPENMP_EVENT_KIND_WAIT_TASKWAIT = 6, + CUPTI_OPENMP_EVENT_KIND_FORCE_INT = 0x7fffffff +} CUpti_OpenMpEventKind; + +/** + * \brief The base activity record for OpenAcc records. + * + * The OpenACC activity API part uses a CUpti_ActivityOpenAcc as a generic + * representation for any OpenACC activity. The 'kind' field is used to determine the + * specific activity kind, and from that the CUpti_ActivityOpenAcc object can + * be cast to the specific OpenACC activity record type appropriate for that kind. + * + * Note that all OpenACC activity record types are padded and aligned to + * ensure that each member of the record is naturally aligned. + * + * \see CUpti_ActivityKind + */ +typedef struct PACKED_ALIGNMENT { + /** + * The kind of this activity. + */ + CUpti_ActivityKind kind; + + /** + * CUPTI OpenACC event kind (\see CUpti_OpenAccEventKind) + */ + CUpti_OpenAccEventKind eventKind; + + /** + * CUPTI OpenACC parent construct kind (\see CUpti_OpenAccConstructKind) + * + * Note that for applications using PGI OpenACC runtime < 16.1, this + * will always be CUPTI_OPENACC_CONSTRUCT_KIND_UNKNOWN. + */ + CUpti_OpenAccConstructKind parentConstruct; + + /** + * Version number + */ + uint32_t version; + + /** + * 1 for any implicit event, such as an implicit wait at a synchronous data construct + * 0 otherwise + */ + uint32_t implicit; + + /** + * Device type + */ + uint32_t deviceType; + + /** + * Device number + */ + uint32_t deviceNumber; + + /** + * ThreadId + */ + uint32_t threadId; + + /** + * Value of async() clause of the corresponding directive + */ + uint64_t async; + + /** + * Internal asynchronous queue number used + */ + uint64_t asyncMap; + + /** + * The line number of the directive or program construct or the starting line + * number of the OpenACC construct corresponding to the event. + * A zero value means the line number is not known. + */ + uint32_t lineNo; + + /** + * For an OpenACC construct, this contains the line number of the end + * of the construct. A zero value means the line number is not known. + */ + uint32_t endLineNo; + + /** + * The line number of the first line of the function named in funcName. + * A zero value means the line number is not known. + */ + uint32_t funcLineNo; + + /** + * The last line number of the function named in funcName. + * A zero value means the line number is not known. + */ + uint32_t funcEndLineNo; + + /** + * CUPTI start timestamp + */ + uint64_t start; + + /** + * CUPTI end timestamp + */ + uint64_t end; + + /** + * CUDA device id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuDeviceId; + + /** + * CUDA context id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuContextId; + + /** + * CUDA stream id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuStreamId; + + /** + * The ID of the process where the OpenACC activity is executing. + */ + uint32_t cuProcessId; + + /** + * The ID of the thread where the OpenACC activity is executing. + */ + uint32_t cuThreadId; + + /** + * The OpenACC correlation ID. + * Valid only if deviceType is acc_device_nvidia. + * If not 0, it uniquely identifies this record. It is identical to the + * externalId in the preceding external correlation record of type + * CUPTI_EXTERNAL_CORRELATION_KIND_OPENACC. + */ + uint32_t externalId; + + /* + * A pointer to null-terminated string containing the name of or path to + * the source file, if known, or a null pointer if not. + */ + const char *srcFile; + + /* + * A pointer to a null-terminated string containing the name of the + * function in which the event occurred. + */ + const char *funcName; +} CUpti_ActivityOpenAcc; + +/** + * \brief The activity record for OpenACC data. + * + * (CUPTI_ACTIVITY_KIND_OPENACC_DATA). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_OPENACC_DATA. + */ + CUpti_ActivityKind kind; + + /** + * CUPTI OpenACC event kind (\see CUpti_OpenAccEventKind) + */ + CUpti_OpenAccEventKind eventKind; + + /* + * CUPTI OpenACC parent construct kind (\see CUpti_OpenAccConstructKind) + * + * Note that for applications using PGI OpenACC runtime < 16.1, this + * will always be CUPTI_OPENACC_CONSTRUCT_KIND_UNKNOWN. + */ + CUpti_OpenAccConstructKind parentConstruct; + + /* + * Version number + */ + uint32_t version; + + /* + * 1 for any implicit event, such as an implicit wait at a synchronous data construct + * 0 otherwise + */ + uint32_t implicit; + + /* + * Device type + */ + uint32_t deviceType; + + /* + * Device number + */ + uint32_t deviceNumber; + + /** + * ThreadId + */ + uint32_t threadId; + + /* + * Value of async() clause of the corresponding directive + */ + uint64_t async; + + /* + * Internal asynchronous queue number used + */ + uint64_t asyncMap; + + /* + * The line number of the directive or program construct or the starting line + * number of the OpenACC construct corresponding to the event. + * A negative or zero value means the line number is not known. + */ + uint32_t lineNo; + + /* + * For an OpenACC construct, this contains the line number of the end + * of the construct. A negative or zero value means the line number is not known. + */ + uint32_t endLineNo; + + /* + * The line number of the first line of the function named in func_name. + * A negative or zero value means the line number is not known. + */ + uint32_t funcLineNo; + + /* + * The last line number of the function named in func_name. + * A negative or zero value means the line number is not known. + */ + uint32_t funcEndLineNo; + + /** + * CUPTI start timestamp + */ + uint64_t start; + + /** + * CUPTI end timestamp + */ + uint64_t end; + + /** + * CUDA device id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuDeviceId; + + /** + * CUDA context id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuContextId; + + /** + * CUDA stream id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuStreamId; + + /** + * The ID of the process where the OpenACC activity is executing. + */ + uint32_t cuProcessId; + + /** + * The ID of the thread where the OpenACC activity is executing. + */ + uint32_t cuThreadId; + + /** + * The OpenACC correlation ID. + * Valid only if deviceType is acc_device_nvidia. + * If not 0, it uniquely identifies this record. It is identical to the + * externalId in the preceding external correlation record of type + * CUPTI_EXTERNAL_CORRELATION_KIND_OPENACC. + */ + uint32_t externalId; + + /* + * A pointer to null-terminated string containing the name of or path to + * the source file, if known, or a null pointer if not. + */ + const char *srcFile; + + /* + * A pointer to a null-terminated string containing the name of the + * function in which the event occurred. + */ + const char *funcName; + + /* --- end of common CUpti_ActivityOpenAcc part --- */ + + /** + * Number of bytes + */ + uint64_t bytes; + + /** + * Host pointer if available + */ + uint64_t hostPtr; + + /** + * Device pointer if available + */ + uint64_t devicePtr; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad1; +#endif + + /* + * A pointer to null-terminated string containing the name of the variable + * for which this event is triggered, if known, or a null pointer if not. + */ + const char *varName; + +} CUpti_ActivityOpenAccData; + +/** + * \brief The activity record for OpenACC launch. + * + * (CUPTI_ACTIVITY_KIND_OPENACC_LAUNCH). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_OPENACC_LAUNCH. + */ + CUpti_ActivityKind kind; + + /** + * CUPTI OpenACC event kind (\see CUpti_OpenAccEventKind) + */ + CUpti_OpenAccEventKind eventKind; + + /** + * CUPTI OpenACC parent construct kind (\see CUpti_OpenAccConstructKind) + * + * Note that for applications using PGI OpenACC runtime < 16.1, this + * will always be CUPTI_OPENACC_CONSTRUCT_KIND_UNKNOWN. + */ + CUpti_OpenAccConstructKind parentConstruct; + + /** + * Version number + */ + uint32_t version; + + /** + * 1 for any implicit event, such as an implicit wait at a synchronous data construct + * 0 otherwise + */ + uint32_t implicit; + + /** + * Device type + */ + uint32_t deviceType; + + /** + * Device number + */ + uint32_t deviceNumber; + + /** + * ThreadId + */ + uint32_t threadId; + + /** + * Value of async() clause of the corresponding directive + */ + uint64_t async; + + /** + * Internal asynchronous queue number used + */ + uint64_t asyncMap; + + /** + * The line number of the directive or program construct or the starting line + * number of the OpenACC construct corresponding to the event. + * A negative or zero value means the line number is not known. + */ + uint32_t lineNo; + + /** + * For an OpenACC construct, this contains the line number of the end + * of the construct. A negative or zero value means the line number is not known. + */ + uint32_t endLineNo; + + /** + * The line number of the first line of the function named in func_name. + * A negative or zero value means the line number is not known. + */ + uint32_t funcLineNo; + + /** + * The last line number of the function named in func_name. + * A negative or zero value means the line number is not known. + */ + uint32_t funcEndLineNo; + + /** + * CUPTI start timestamp + */ + uint64_t start; + + /** + * CUPTI end timestamp + */ + uint64_t end; + + /** + * CUDA device id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuDeviceId; + + /** + * CUDA context id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuContextId; + + /** + * CUDA stream id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuStreamId; + + /** + * The ID of the process where the OpenACC activity is executing. + */ + uint32_t cuProcessId; + + /** + * The ID of the thread where the OpenACC activity is executing. + */ + uint32_t cuThreadId; + + /** + * The OpenACC correlation ID. + * Valid only if deviceType is acc_device_nvidia. + * If not 0, it uniquely identifies this record. It is identical to the + * externalId in the preceding external correlation record of type + * CUPTI_EXTERNAL_CORRELATION_KIND_OPENACC. + */ + uint32_t externalId; + + /** + * A pointer to null-terminated string containing the name of or path to + * the source file, if known, or a null pointer if not. + */ + const char *srcFile; + + /** + * A pointer to a null-terminated string containing the name of the + * function in which the event occurred. + */ + const char *funcName; + + /* --- end of common CUpti_ActivityOpenAcc part --- */ + + /** + * The number of gangs created for this kernel launch + */ + uint64_t numGangs; + + /** + * The number of workers created for this kernel launch + */ + uint64_t numWorkers; + + /** + * The number of vector lanes created for this kernel launch + */ + uint64_t vectorLength; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad1; +#endif + + /** + * A pointer to null-terminated string containing the name of the + * kernel being launched, if known, or a null pointer if not. + */ + const char *kernelName; + +} CUpti_ActivityOpenAccLaunch; + +/** + * \brief The activity record for OpenACC other. + * + * (CUPTI_ACTIVITY_KIND_OPENACC_OTHER). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_OPENACC_OTHER. + */ + CUpti_ActivityKind kind; + + /** + * CUPTI OpenACC event kind (\see CUpti_OpenAccEventKind) + */ + CUpti_OpenAccEventKind eventKind; + + /** + * CUPTI OpenACC parent construct kind (\see CUpti_OpenAccConstructKind) + * + * Note that for applications using PGI OpenACC runtime < 16.1, this + * will always be CUPTI_OPENACC_CONSTRUCT_KIND_UNKNOWN. + */ + CUpti_OpenAccConstructKind parentConstruct; + + /** + * Version number + */ + uint32_t version; + + /** + * 1 for any implicit event, such as an implicit wait at a synchronous data construct + * 0 otherwise + */ + uint32_t implicit; + + /** + * Device type + */ + uint32_t deviceType; + + /** + * Device number + */ + uint32_t deviceNumber; + + /** + * ThreadId + */ + uint32_t threadId; + + /** + * Value of async() clause of the corresponding directive + */ + uint64_t async; + + /** + * Internal asynchronous queue number used + */ + uint64_t asyncMap; + + /** + * The line number of the directive or program construct or the starting line + * number of the OpenACC construct corresponding to the event. + * A negative or zero value means the line number is not known. + */ + uint32_t lineNo; + + /** + * For an OpenACC construct, this contains the line number of the end + * of the construct. A negative or zero value means the line number is not known. + */ + uint32_t endLineNo; + + /** + * The line number of the first line of the function named in func_name. + * A negative or zero value means the line number is not known. + */ + uint32_t funcLineNo; + + /** + * The last line number of the function named in func_name. + * A negative or zero value means the line number is not known. + */ + uint32_t funcEndLineNo; + + /** + * CUPTI start timestamp + */ + uint64_t start; + + /** + * CUPTI end timestamp + */ + uint64_t end; + + /** + * CUDA device id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuDeviceId; + + /** + * CUDA context id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuContextId; + + /** + * CUDA stream id + * Valid only if deviceType is acc_device_nvidia. + */ + uint32_t cuStreamId; + + /** + * The ID of the process where the OpenACC activity is executing. + */ + uint32_t cuProcessId; + + /** + * The ID of the thread where the OpenACC activity is executing. + */ + uint32_t cuThreadId; + + /** + * The OpenACC correlation ID. + * Valid only if deviceType is acc_device_nvidia. + * If not 0, it uniquely identifies this record. It is identical to the + * externalId in the preceding external correlation record of type + * CUPTI_EXTERNAL_CORRELATION_KIND_OPENACC. + */ + uint32_t externalId; + + /** + * A pointer to null-terminated string containing the name of or path to + * the source file, if known, or a null pointer if not. + */ + const char *srcFile; + + /** + * A pointer to a null-terminated string containing the name of the + * function in which the event occurred. + */ + const char *funcName; + + /* --- end of common CUpti_ActivityOpenAcc part --- */ +} CUpti_ActivityOpenAccOther; + +/** + * \brief The base activity record for OpenMp records. + * + * \see CUpti_ActivityKind + */ +typedef struct PACKED_ALIGNMENT { + + /** + * The kind of this activity. + */ + CUpti_ActivityKind kind; + + /** + * CUPTI OpenMP event kind (\see CUpti_OpenMpEventKind) + */ + CUpti_OpenMpEventKind eventKind; + + /** + * Version number + */ + uint32_t version; + + /** + * ThreadId + */ + uint32_t threadId; + + /** + * CUPTI start timestamp + */ + uint64_t start; + + /** + * CUPTI end timestamp + */ + uint64_t end; + + /** + * The ID of the process where the OpenMP activity is executing. + */ + uint32_t cuProcessId; + + /** + * The ID of the thread where the OpenMP activity is executing. + */ + uint32_t cuThreadId; +} CUpti_ActivityOpenMp; + +/** + * \brief The kind of external APIs supported for correlation. + * + * Custom correlation kinds are reserved for usage in external tools. + * + * \see CUpti_ActivityExternalCorrelation + */ +typedef enum { + CUPTI_EXTERNAL_CORRELATION_KIND_INVALID = 0, + + /** + * The external API is unknown to CUPTI + */ + CUPTI_EXTERNAL_CORRELATION_KIND_UNKNOWN = 1, + + /** + * The external API is OpenACC + */ + CUPTI_EXTERNAL_CORRELATION_KIND_OPENACC = 2, + + /** + * The external API is custom0 + */ + CUPTI_EXTERNAL_CORRELATION_KIND_CUSTOM0 = 3, + + /** + * The external API is custom1 + */ + CUPTI_EXTERNAL_CORRELATION_KIND_CUSTOM1 = 4, + + /** + * The external API is custom2 + */ + CUPTI_EXTERNAL_CORRELATION_KIND_CUSTOM2 = 5, + + /** + * Add new kinds before this line + */ + CUPTI_EXTERNAL_CORRELATION_KIND_SIZE, + + CUPTI_EXTERNAL_CORRELATION_KIND_FORCE_INT = 0x7fffffff +} CUpti_ExternalCorrelationKind; + +/** + * \brief The activity record for correlation with external records + * + * This activity record correlates native CUDA records (e.g. CUDA Driver API, + * kernels, memcpys, ...) with records from external APIs such as OpenACC. + * (CUPTI_ACTIVITY_KIND_EXTERNAL_CORRELATION). + * + * \see CUpti_ActivityKind + */ +typedef struct PACKED_ALIGNMENT { + /** + * The kind of this activity. + */ + CUpti_ActivityKind kind; + + /** + * The kind of external API this record correlated to. + */ + CUpti_ExternalCorrelationKind externalKind; + + /** + * The correlation ID of the associated non-CUDA API record. + * The exact field in the associated external record depends + * on that record's activity kind (\see externalKind). + */ + uint64_t externalId; + + /** + * The correlation ID of the associated CUDA driver or runtime API record. + */ + uint32_t correlationId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t reserved; +} CUpti_ActivityExternalCorrelation; + +/** +* \brief The device type for device connected to NVLink. +*/ +typedef enum { + CUPTI_DEV_TYPE_INVALID = 0, + + /** + * The device type is GPU. + */ + CUPTI_DEV_TYPE_GPU = 1, + + /** + * The device type is NVLink processing unit in CPU. + */ + CUPTI_DEV_TYPE_NPU = 2, + + CUPTI_DEV_TYPE_FORCE_INT = 0x7fffffff +} CUpti_DevType; + +/** +* \brief NVLink information. +* +* This structure gives capabilities of each logical NVLink connection between two devices, +* gpu<->gpu or gpu<->CPU which can be used to understand the topology. +*/ + +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_NVLINK. + */ + CUpti_ActivityKind kind; + + /** + * NvLink version. + */ + uint32_t nvlinkVersion; + + /** + * Type of device 0 \ref CUpti_DevType + */ + CUpti_DevType typeDev0; + + /** + * Type of device 1 \ref CUpti_DevType + */ + CUpti_DevType typeDev1; + + /** + * If typeDev0 is CUPTI_DEV_TYPE_GPU, UUID for device 0. \ref CUpti_ActivityDevice5. + * If typeDev0 is CUPTI_DEV_TYPE_NPU, struct npu for NPU. + */ + union { + CUuuid uuidDev; + struct { + /** + * Index of the NPU. First index will always be zero. + */ + uint32_t index; + + /** + * Domain ID of NPU. On Linux, this can be queried using lspci. + */ + uint32_t domainId; + } npu; + } idDev0; + + /** + * If typeDev1 is CUPTI_DEV_TYPE_GPU, UUID for device 1. \ref CUpti_ActivityDevice5. + * If typeDev1 is CUPTI_DEV_TYPE_NPU, struct npu for NPU. + */ + union { + CUuuid uuidDev; + struct { + + /** + * Index of the NPU. First index will always be zero. + */ + uint32_t index; + + /** + * Domain ID of NPU. On Linux, this can be queried using lspci. + */ + uint32_t domainId; + } npu; + } idDev1; + + /** + * Flag gives capabilities of the link \see CUpti_LinkFlag + */ + uint32_t flag; + + /** + * Number of physical NVLinks present between two devices. + */ + uint32_t physicalNvLinkCount; + + /** + * Port numbers for maximum 32 NVLinks connected to device 0. + * If typeDev0 is CUPTI_DEV_TYPE_NPU, ignore this field. + * In case of invalid/unknown port number, this field will be set + * to value CUPTI_NVLINK_INVALID_PORT. + * This will be used to correlate the metric values to individual + * physical link and attribute traffic to the logical NVLink in + * the topology. + */ + int8_t portDev0[CUPTI_MAX_NVLINK_PORTS]; + + /** + * Port numbers for maximum 32 NVLinks connected to device 1. + * If typeDev1 is CUPTI_DEV_TYPE_NPU, ignore this field. + * In case of invalid/unknown port number, this field will be set + * to value CUPTI_NVLINK_INVALID_PORT. + * This will be used to correlate the metric values to individual + * physical link and attribute traffic to the logical NVLink in + * the topology. + */ + int8_t portDev1[CUPTI_MAX_NVLINK_PORTS]; + + /** + * Bandwidth of NVLink in kbytes/sec + */ + uint64_t bandwidth; + + /** + * NVSwitch is connected as an intermediate node. + */ + uint8_t nvswitchConnected; + + /** + * Undefined. reserved for internal use + */ + uint8_t pad[7]; +} CUpti_ActivityNvLink4; + +#define CUPTI_MAX_GPUS 32 +/** + * Field to differentiate whether PCIE Activity record + * is of a GPU or a PCI Bridge + */ +typedef enum { + /** + * PCIE GPU record + */ + CUPTI_PCIE_DEVICE_TYPE_GPU = 0, + + /** + * PCIE Bridge record + */ + CUPTI_PCIE_DEVICE_TYPE_BRIDGE = 1, + + CUPTI_PCIE_DEVICE_TYPE_FORCE_INT = 0x7fffffff +} CUpti_PcieDeviceType; + +/** + * \brief PCI devices information required to construct topology + * + * This structure gives capabilities of GPU and PCI bridge connected to the PCIE bus + * which can be used to understand the topology. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_PCIE. + */ + CUpti_ActivityKind kind; + + /** + * Type of device in topology, \ref CUpti_PcieDeviceType. If type is + * CUPTI_PCIE_DEVICE_TYPE_GPU use devId for id and gpuAttr and if type is + * CUPTI_PCIE_DEVICE_TYPE_BRIDGE use bridgeId for id and bridgeAttr. + */ + CUpti_PcieDeviceType type; + + /** + * A unique identifier for GPU or Bridge in Topology + */ + union { + /** + * GPU device ID + */ + CUdevice devId; + + /** + * A unique identifier for Bridge in the Topology + */ + uint32_t bridgeId; + } id; + + /** + * Domain for the GPU or Bridge, required to identify which PCIE bus it belongs to in + * multiple NUMA systems. + */ + uint32_t domain; + + /** + * PCIE Generation of GPU or Bridge. + */ + uint16_t pcieGeneration; + + /** + * Link rate of the GPU or bridge in gigatransfers per second (GT/s) + */ + uint16_t linkRate; + + /** + * Link width of the GPU or bridge + */ + uint16_t linkWidth; + + /** + * Upstream bus ID for the GPU or PCI bridge. Required to identify which bus it is + * connected to in the topology. + */ + uint16_t upstreamBus; + + /** + * Attributes for more information about GPU (gpuAttr) or PCI Bridge (bridgeAttr) + */ + union { + struct { + /** + * UUID for the device. \ref CUpti_ActivityDevice5. + */ + CUuuid uuidDev; + + /** + * CUdevice with which this device has P2P capability. + * This can also be obtained by querying cuDeviceCanAccessPeer or + * cudaDeviceCanAccessPeer APIs + */ + CUdevice peerDev[CUPTI_MAX_GPUS]; + } gpuAttr; + + struct { + /** + * The downstream bus number, used to search downstream devices/bridges connected + * to this bridge. + */ + uint16_t secondaryBus; + + /** + * Device ID of the bridge + */ + uint16_t deviceId; + + /** + * Vendor ID of the bridge + */ + uint16_t vendorId; + + /** + * Padding for alignment + */ + uint16_t pad0; + } bridgeAttr; + } attr; +} CUpti_ActivityPcie; + +/** + * \brief PCIE Generation. + * + * Enumeration of PCIE Generation for + * pcie activity attribute pcieGeneration + */ +typedef enum { + /** + * PCIE Generation 1 + */ + CUPTI_PCIE_GEN_GEN1 = 1, + + /** + * PCIE Generation 2 + */ + CUPTI_PCIE_GEN_GEN2 = 2, + + /** + * PCIE Generation 3 + */ + CUPTI_PCIE_GEN_GEN3 = 3, + + /** + * PCIE Generation 4 + */ + CUPTI_PCIE_GEN_GEN4 = 4, + + /** + * PCIE Generation 5 + */ + CUPTI_PCIE_GEN_GEN5 = 5, + + /** + * PCIE Generation 6 + */ + CUPTI_PCIE_GEN_GEN6 = 6, + + CUPTI_PCIE_GEN_FORCE_INT = 0x7fffffff +} CUpti_PcieGen; + + +/** + * \brief The activity record for an instantaneous CUPTI event. + * + * This activity record represents a CUPTI event value + * (CUPTI_ACTIVITY_KIND_EVENT) sampled at a particular instant. + * This activity record kind is not produced by the activity API but is + * included for completeness and ease-of-use. Profiler frameworks built on + * top of CUPTI that collect event data at a particular time may choose to + * use this type to store the collected event data. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_INSTANTANEOUS_EVENT. + */ + CUpti_ActivityKind kind; + + /** + * The event ID. + */ + CUpti_EventID id; + + /** + * The event value. + */ + uint64_t value; + + /** + * The timestamp at which event is sampled + */ + uint64_t timestamp; + + /** + * The device id + */ + uint32_t deviceId; + + /** + * Undefined. reserved for internal use + */ + uint32_t reserved; +} CUpti_ActivityInstantaneousEvent; + +/** + * \brief The activity record for an instantaneous CUPTI event + * with event domain instance information. + * + * This activity record represents the a CUPTI event value for a + * specific event domain instance + * (CUPTI_ACTIVITY_KIND_EVENT_INSTANCE) sampled at a particular instant. + * This activity record kind is not produced by the activity API but is + * included for completeness and ease-of-use. Profiler frameworks built on + * top of CUPTI that collect event data may choose to use this type to store the + * collected event data. This activity record should be used when + * event domain instance information needs to be associated with the + * event. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_INSTANTANEOUS_EVENT_INSTANCE. + */ + CUpti_ActivityKind kind; + + /** + * The event ID. + */ + CUpti_EventID id; + + /** + * The event value. + */ + uint64_t value; + + /** + * The timestamp at which event is sampled + */ + uint64_t timestamp; + + /** + * The device id + */ + uint32_t deviceId; + + /** + * The event domain instance + */ + uint8_t instance; + + /** + * Undefined. reserved for internal use + */ + uint8_t pad[3]; +} CUpti_ActivityInstantaneousEventInstance; + +/** + * \brief The activity record for an instantaneous CUPTI metric. + * + * This activity record represents the collection of a CUPTI metric + * value (CUPTI_ACTIVITY_KIND_METRIC) at a particular instance. + * This activity record kind is not produced by the activity API but + * is included for completeness and ease-of-use. Profiler frameworks built + * on top of CUPTI that collect metric data may choose to use this type to + * store the collected metric data. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_INSTANTANEOUS_METRIC. + */ + CUpti_ActivityKind kind; + + /** + * The metric ID. + */ + CUpti_MetricID id; + + /** + * The metric value. + */ + CUpti_MetricValue value; + + /** + * The timestamp at which metric is sampled + */ + uint64_t timestamp; + + /** + * The device id + */ + uint32_t deviceId; + + /** + * The properties of this metric. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * Undefined. reserved for internal use + */ + uint8_t pad[3]; +} CUpti_ActivityInstantaneousMetric; + +/** + * \brief The instantaneous activity record for a CUPTI metric with instance + * information. + + * This activity record represents a CUPTI metric value + * for a specific metric domain instance + * (CUPTI_ACTIVITY_KIND_METRIC_INSTANCE) sampled at a particular time. This + * activity record kind is not produced by the activity API but is included for + * completeness and ease-of-use. Profiler frameworks built on top of + * CUPTI that collect metric data may choose to use this type to store + * the collected metric data. This activity record should be used when + * metric domain instance information needs to be associated with the + * metric. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_INSTANTANEOUS_METRIC_INSTANCE. + */ + CUpti_ActivityKind kind; + + /** + * The metric ID. + */ + CUpti_MetricID id; + + /** + * The metric value. + */ + CUpti_MetricValue value; + + /** + * The timestamp at which metric is sampled + */ + uint64_t timestamp; + + /** + * The device id + */ + uint32_t deviceId; + + /** + * The properties of this metric. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The metric domain instance + */ + uint8_t instance; + + /** + * Undefined. reserved for internal use + */ + uint8_t pad[2]; +} CUpti_ActivityInstantaneousMetricInstance; + +/** + * \brief The types of JIT entry. + * + * To be used in CUpti_ActivityJit. + */ +typedef enum { + CUPTI_ACTIVITY_JIT_ENTRY_INVALID= 0, + + /** + * PTX to CUBIN. + */ + CUPTI_ACTIVITY_JIT_ENTRY_PTX_TO_CUBIN = 1, + + /** + * NVVM-IR to PTX + */ + CUPTI_ACTIVITY_JIT_ENTRY_NVVM_IR_TO_PTX = 2, + + CUPTI_ACTIVITY_JIT_ENTRY_TYPE_FORCE_INT = 0x7fffffff +} CUpti_ActivityJitEntryType; + +/** + * \brief The types of JIT compilation operations. + * + * To be used in CUpti_ActivityJit. + */ + +typedef enum { + CUPTI_ACTIVITY_JIT_OPERATION_INVALID = 0, + /** + * Loaded from the compute cache. + */ + CUPTI_ACTIVITY_JIT_OPERATION_CACHE_LOAD = 1, + + /** + * Stored in the compute cache. + */ + CUPTI_ACTIVITY_JIT_OPERATION_CACHE_STORE = 2, + + /** + * JIT compilation. + */ + CUPTI_ACTIVITY_JIT_OPERATION_COMPILE = 3, + + CUPTI_ACTIVITY_JIT_OPERATION_TYPE_FORCE_INT = 0x7fffffff +} CUpti_ActivityJitOperationType; + +/** + * \brief The activity record for JIT operations. + * This activity represents the JIT operations (compile, load, store) of a CUmodule + * from the Compute Cache. + * Gives the exact hashed path of where the cached module is loaded from, + * or where the module will be stored after Just-In-Time (JIT) compilation. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind must be CUPTI_ACTIVITY_KIND_JIT. + */ + CUpti_ActivityKind kind; + + /** + * The JIT entry type. + */ + CUpti_ActivityJitEntryType jitEntryType; + + /** + * The JIT operation type. + */ + CUpti_ActivityJitOperationType jitOperationType; + + /** + * The device ID. + */ + uint32_t deviceId; + + /** + * The start timestamp for the JIT operation, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the JIT operation. + */ + uint64_t start; + + /** + * The end timestamp for the JIT operation, in ns. A value of 0 for both + * the start and end timestamps indicates that timestamp information + * could not be collected for the JIT operation. + */ + uint64_t end; + + /** + * The correlation ID of the JIT operation to which + * records belong to. Each JIT operation is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the JIT operation. + */ + uint32_t correlationId; + + /** + * Internal use. + */ + uint32_t padding; + + /** + * The correlation ID to correlate JIT compilation, load and store operations. + * Each JIT compilation unit is assigned a unique correlation ID + * at the time of the JIT compilation. This correlation id can be used + * to find the matching JIT cache load/store records. + */ + uint64_t jitOperationCorrelationId; + + /** + * The size of compute cache. + */ + uint64_t cacheSize; + + /** + * The path where the fat binary is cached. + */ + const char* cachePath; + + /** + * The ID of the process where the JIT operation is executing. + */ + uint32_t processId; + + /** + * The ID of the thread where the JIT operation is executing. + */ + uint32_t threadId; +} CUpti_ActivityJit2; + + +/** + * \brief The activity record for trace of graph execution. + * + * This activity record represents execution for a graph without giving visibility + * about the execution of its nodes. This is intended to reduce overheads in tracing + * each node. The activity kind is CUPTI_ACTIVITY_KIND_GRAPH_TRACE + */ +typedef struct { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_GRAPH_TRACE + */ + CUpti_ActivityKind kind; + + /** + * The correlation ID of the graph launch. Each graph launch is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the graph. + */ + uint32_t correlationId; + + /** + * The start timestamp for the graph execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the graph. + */ + uint64_t start; + + /** + * The end timestamp for the graph execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the graph. + */ + uint64_t end; + + /** + * The ID of the device where the first node of the graph is executed. + * If this is INT_MAX, then the start is on the host. + */ + uint32_t deviceId; + + /** + * The unique ID of the graph that is launched. + */ + uint32_t graphId; + + /** + * The ID of the context where the first node of the graph is executed. + * If this is INT_MAX, then the start is on the host. + */ + uint32_t contextId; + + /** + * The ID of the stream where the graph is being launched. + */ + uint32_t streamId; + + /** + * This field is reserved for internal use + */ + void *reserved; + + /** + * The ID of the device where last node of the graph is executed + */ + uint32_t endDeviceId; + + /** + * The ID of the context where the last node of the graph is executed. + */ + uint32_t endContextId; +} CUpti_ActivityGraphTrace2; + +/** + * \brief The launch mode for device graph execution. + */ +typedef enum { + CUPTI_DEVICE_GRAPH_LAUNCH_MODE_INVALID = 0, + CUPTI_DEVICE_GRAPH_LAUNCH_MODE_FIRE_AND_FORGET = 1, + CUPTI_DEVICE_GRAPH_LAUNCH_MODE_TAIL = 2, + CUPTI_DEVICE_GRAPH_LAUNCH_MODE_FIRE_AND_FORGET_AS_SIBLING = 3, +} CUpti_DeviceGraphLaunchMode; + +/** + * \brief The activity record for trace of device graph execution. + * + * This activity record represents execution for a device launched graph without giving visibility + * about the execution of its nodes. This is intended to reduce overheads in tracing + * each node. The activity kind is CUPTI_ACTIVITY_KIND_DEVICE_GRAPH_TRACE + */ +typedef struct { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_DEVICE_GRAPH_TRACE + */ + CUpti_ActivityKind kind; + + /** + * The ID of the device where the first node of the graph is executed. + */ + uint32_t deviceId; + + /** + * The start timestamp for the graph execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the graph. + */ + uint64_t start; + + /** + * The end timestamp for the graph execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the graph. + */ + uint64_t end; + + /** + * The unique ID of the graph that is launched. + */ + uint32_t graphId; + + /** + * The unique ID of the graph that has launched this graph. + */ + uint32_t launcherGraphId; + + /** + * The type of launch. See \ref CUpti_DeviceGraphLaunchMode + */ + uint32_t deviceLaunchMode; + + /** + * The ID of the context where the first node of the graph is executed. + */ + uint32_t contextId; + + /** + * The ID of the stream where the graph is being launched. + */ + uint64_t streamId; + + /** + * This field is reserved for internal use + */ + void *reserved; + +} CUpti_ActivityDeviceGraphTrace; + +/** + * \brief The activity record for trace of decompression operations. + * + * This activity record represents execution for a batch of decompression operatios. + * The activity kind is CUPTI_ACTIVITY_KIND_MEM_DECOMPRESS + */ +typedef struct { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEM_DECOMPRESS + */ + CUpti_ActivityKind kind; + + /** + * The ID of the device. + */ + uint32_t deviceId; + + /** + * The ID of the context. + */ + uint32_t contextId; + + /** + * The ID of the stream. + */ + uint32_t streamId; + + /** + * The ID of the HW channel on which the memory copy is occurring. + */ + uint32_t channelID; + + /** + * The type of the channel + */ + CUpti_ChannelType channelType; + + /** + * The correlation ID of the decompression operations. Each operation is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the operation. + */ + uint32_t correlationId; + + /** + * The number of operations in the batch. + */ + uint32_t numberOfOperations; + + /** + * The number of bytes to be read and decompressed in the + * batch operation. + */ + uint64_t sourceBytes; + + /** + * This field is reserved for internal use + */ + void *reserved0; + + /** + * The start timestamp. + * A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the start time is unknown. + */ + uint64_t start; + + /** + * The end timestamp. + * A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the start time is unknown. + */ + uint64_t end; +} CUpti_ActivityMemDecompress; + +END_PACKED_ALIGNMENT + +/** + * \brief Activity attributes. + * + * These attributes are used to control the behavior of the activity + * API. + */ +typedef enum { + /** + * The device memory size (in bytes) reserved for storing profiling data for concurrent + * kernels (activity kind \ref CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL), memcopies and memsets + * for each buffer on a context. The value is a size_t. + * + * There is a limit on how many device buffers can be allocated per context. User + * can query and set this limit using the attribute + * \ref CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_POOL_LIMIT. + * CUPTI doesn't pre-allocate all the buffers, it pre-allocates only those many + * buffers as set by the attribute \ref CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_PRE_ALLOCATE_VALUE. + * When all of the data in a buffer is consumed, it is added in the reuse pool, and + * CUPTI picks a buffer from this pool when a new buffer is needed. Thus memory + * footprint does not scale with the kernel count. Applications with the high density + * of kernels, memcopies and memsets might result in having CUPTI to allocate more device buffers. + * CUPTI allocates another buffer only when it runs out of the buffers in the + * reuse pool. + * + * Since buffer allocation happens in the main application thread, this might result + * in stalls in the critical path. CUPTI pre-allocates 3 buffers of the same size to + * mitigate this issue. User can query and set the pre-allocation limit using the + * attribute \ref CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_PRE_ALLOCATE_VALUE. + * + * Having larger buffer size leaves less device memory for the application. + * Having smaller buffer size increases the risk of dropping timestamps for + * records if too many kernels or memcopies or memsets are launched at one time. + * + * This value only applies to new buffer allocations. Set this value before initializing + * CUDA or before creating a context to ensure it is considered for the following allocations. + * + * The default value is 3200000 (~3MB) which can accommodate profiling data + * up to 100,000 kernels, memcopies and memsets combined. + * + * Note: Starting with the CUDA 12.0 Update 1 release, CUPTI allocates profiling buffer in the + * device memory by default as this might help in improving the performance of the + * tracing run. Refer to the description of the attribute + * \ref CUPTI_ACTIVITY_ATTR_MEM_ALLOCATION_TYPE_HOST_PINNED for more details. + * Size of the memory and maximum number of pools are still controlled by the attributes + * \ref CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_SIZE and \ref CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_POOL_LIMIT. + * + * Note: The actual amount of device memory per buffer reserved by CUPTI might be larger. + */ + CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_SIZE = 0, + + /** + * The device memory size (in bytes) reserved for storing profiling + * data for CDP operations for each buffer on a context. The + * value is a size_t. + * + * Having larger buffer size means less flush operations but + * consumes more device memory. This value only applies to new + * allocations. + * + * Set this value before initializing CUDA or before creating a + * context to ensure it is considered for the following allocations. + * + * The default value is 8388608 (8MB). + * + * Note: The actual amount of device memory per context reserved by + * CUPTI might be larger. + */ + CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_SIZE_CDP = 1, + + /** + * The maximum number of device memory buffers per context. The value is a size_t. + * + * For an application with high rate of kernel launches, memcopies and memsets having a bigger pool + * limit helps in timestamp collection for all these activities at the expense of a larger memory footprint. + * Refer to the description of the attribute \ref CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_SIZE + * for more details. + * + * Setting this value will not modify the number of memory buffers + * currently stored. + * + * Set this value before initializing CUDA to ensure the limit is + * not exceeded. + * + * The default value is 250. + */ + CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_POOL_LIMIT = 2, + + /** + * This attribute is not supported starting with CUDA 12.3 + * CUPTI no longer uses profiling semaphore pool to store profiling data. + * + * There is a limit on how many semaphore pools can be allocated per context. User + * can query and set this limit using the attribute + * \ref CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_POOL_LIMIT. + * CUPTI doesn't pre-allocate all the semaphore pools, it pre-allocates only those many + * semaphore pools as set by the attribute \ref CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_PRE_ALLOCATE_VALUE. + * When all of the data in a semaphore pool is consumed, it is added in the reuse pool, and + * CUPTI picks a semaphore pool from the reuse pool when a new semaphore pool is needed. Thus memory + * footprint does not scale with the kernel count. Applications with the high density + * of kernels might result in having CUPTI to allocate more semaphore pools. + * CUPTI allocates another semaphore pool only when it runs out of the semaphore pools in the + * reuse pool. + * + * Since semaphore pool allocation happens in the main application thread, this might result + * in stalls in the critical path. CUPTI pre-allocates 3 semaphore pools of the same size to + * mitigate this issue. User can query and set the pre-allocation limit using the + * attribute \ref CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_PRE_ALLOCATE_VALUE. + * + * Having larger semaphore pool size leaves less device memory for the application. + * Having smaller semaphore pool size increases the risk of dropping timestamps for + * kernel records if too many kernels are issued/launched at one time. + * + * This value only applies to new semaphore pool allocations. Set this value before initializing + * CUDA or before creating a context to ensure it is considered for the following allocations. + * + * The default value is 25000 which can accommodate profiling data for upto 25,000 kernels. + * + */ + CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_POOL_SIZE = 3, + + /** + * This attribute is not supported starting with CUDA 12.3 + * CUPTI no longer uses profiling semaphore pool to store profiling data. + * + * The maximum number of profiling semaphore pools per context. The value is a size_t. + * + * Refer to the description of the attribute \ref CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_POOL_SIZE + * for more details. + * + * Set this value before initializing CUDA to ensure the limit is not exceeded. + * + * The default value is 250. + */ + CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_POOL_LIMIT = 4, + + /** + * The flag to indicate whether user should provide activity buffer of zero value. + * The value is a uint8_t. + * + * If the value of this attribute is non-zero, user should provide + * a zero value buffer in the \ref CUpti_BuffersCallbackRequestFunc. + * If the user does not provide a zero value buffer after setting this to non-zero, + * the activity buffer may contain some uninitialized values when CUPTI returns it in + * \ref CUpti_BuffersCallbackCompleteFunc + * + * If the value of this attribute is zero, CUPTI will initialize the user buffer + * received in the \ref CUpti_BuffersCallbackRequestFunc to zero before filling it. + * If the user sets this to zero, a few stalls may appear in critical path because CUPTI + * will zero out the buffer in the main thread. + * Set this value before returning from \ref CUpti_BuffersCallbackRequestFunc to + * ensure it is considered for all the subsequent user buffers. + * + * The default value is 0. + */ + CUPTI_ACTIVITY_ATTR_ZEROED_OUT_ACTIVITY_BUFFER = 5, + + /** + * Number of device buffers to pre-allocate for a context during the initialization phase. + * The value is a size_t. + * + * Refer to the description of the attribute \ref CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_SIZE + * for details. + * + * This value must be less than the maximum number of device buffers set using + * the attribute \ref CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_POOL_LIMIT + * + * Set this value before initializing CUDA or before creating a context to ensure it + * is considered by the CUPTI. + * + * The default value is set to 3 to ping pong between these buffers (if possible). + */ + CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_PRE_ALLOCATE_VALUE = 6, + + /** + * This attribute is not supported starting with CUDA 12.3 + * CUPTI no longer uses profiling semaphore pool to store profiling data. + * + * Number of profiling semaphore pools to pre-allocate for a context during the + * initialization phase. The value is a size_t. + * + * Refer to the description of the attribute \ref CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_POOL_SIZE + * for details. + * + * This value must be less than the maximum number of profiling semaphore pools set + * using the attribute \ref CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_POOL_LIMIT + * + * Set this value before initializing CUDA or before creating a context to ensure it + * is considered by the CUPTI. + * + * The default value is set to 3 to ping pong between these pools (if possible). + */ + CUPTI_ACTIVITY_ATTR_PROFILING_SEMAPHORE_PRE_ALLOCATE_VALUE = 7, + + /** + * Allocate page-locked (pinned) host memory for storing profiling data for concurrent + * kernels, memcopies and memsets for each buffer on a context. The value is a uint8_t. + * + * Starting with the CUDA 11.2 release, CUPTI allocates profiling buffer in the pinned host + * memory by default as this might help in improving the performance of the tracing run. + * Allocating excessive amounts of pinned memory may degrade system performance, since it + * reduces the amount of memory available to the system for paging. For this reason user + * might want to change the location from pinned host memory to device memory by setting + * value of this attribute to 0. + * + * Using page-locked (pinned) host memory buffers is not supported on confidential computing + * devices. On setting this attribute to 1, CUPTI will return CUPTI_ERROR_NOT_SUPPORTED. + * + * The default value is 1. + */ + CUPTI_ACTIVITY_ATTR_MEM_ALLOCATION_TYPE_HOST_PINNED = 8, + + /** + * Request activity buffers per-thread to store CUPTI activity records + * in the activity buffer on per-thread basis. The value is a uint8_t. + * + * The attribute should be set before registering the buffer callbacks using + * cuptiActivityRegisterCallbacks API and before any of the CUPTI activity kinds are enabled. + * This makes sure that all the records are stored in activity buffers allocated per-thread. + * Changing this attribute in the middle of the profiling session will result in undefined behavior. + * + * The default value is 0. + */ + CUPTI_ACTIVITY_ATTR_PER_THREAD_ACTIVITY_BUFFER, + + + + CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_FORCE_INT = 0x7fffffff +} CUpti_ActivityAttribute; + +/** + * \brief Thread-Id types. + * + * CUPTI uses different methods to obtain the thread-id depending on the + * support and the underlying platform. This enum documents these methods + * for each type. APIs \ref cuptiSetThreadIdType and \ref cuptiGetThreadIdType + * can be used to set and get the thread-id type. + */ +typedef enum { + /** + * Default type + * Windows uses API GetCurrentThreadId() + * Linux/Mac/Android/QNX use POSIX pthread API pthread_self() + */ + CUPTI_ACTIVITY_THREAD_ID_TYPE_DEFAULT = 0, + + /** + * This type is based on the system API available on the underlying platform + * and thread-id obtained is supposed to be unique for the process lifetime. + * Windows uses API GetCurrentThreadId() + * Linux uses syscall SYS_gettid + * Mac uses syscall SYS_thread_selfid + * Android/QNX use gettid() + */ + CUPTI_ACTIVITY_THREAD_ID_TYPE_SYSTEM = 1, + + /** + * Add new enums before this field. + */ + CUPTI_ACTIVITY_THREAD_ID_TYPE_SIZE = 2, + + CUPTI_ACTIVITY_THREAD_ID_TYPE_FORCE_INT = 0x7fffffff +} CUpti_ActivityThreadIdType; + +/** + * \brief Get the CUPTI timestamp. + * + * Returns a timestamp normalized to correspond with the start and end + * timestamps reported in the CUPTI activity records. The timestamp is + * reported in nanoseconds. + * + * \param timestamp Returns the CUPTI timestamp + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p timestamp is NULL + */ +CUptiResult CUPTIAPI cuptiGetTimestamp(uint64_t *timestamp); + +/** + * \brief Get the ID of a context. + * + * Get the ID of a context. + * + * \param context The context + * \param contextId Returns a process-unique ID for the context + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_CONTEXT The context is NULL or not valid. + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p contextId is NULL + */ +CUptiResult CUPTIAPI cuptiGetContextId(CUcontext context, uint32_t *contextId); + +/** + * \brief Get the ID of a stream. + * + * Get the ID of a stream. The stream ID is unique within a context + * (i.e. all streams within a context will have unique stream + * IDs). + * + * \param context If non-NULL then the stream is checked to ensure + * that it belongs to this context. Typically this parameter should be + * null. + * \param stream The stream + * \param streamId Returns a context-unique ID for the stream + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_STREAM if unable to get stream ID, or + * if \p context is non-NULL and \p stream does not belong to the + * context + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p streamId is NULL + * + * **DEPRECATED** This method is deprecated as of CUDA 8.0. + * Use method cuptiGetStreamIdEx instead. + */ +CUptiResult CUPTIAPI cuptiGetStreamId(CUcontext context, CUstream stream, uint32_t *streamId); + +/** +* \brief Get the ID of a stream. +* +* Get the ID of a stream. The stream ID is unique within a context +* (i.e. all streams within a context will have unique stream +* IDs). +* +* \param context If non-NULL then the stream is checked to ensure +* that it belongs to this context. Typically this parameter should be +* null. +* \param stream The stream +* \param perThreadStream Flag to indicate if program is compiled for per-thread streams +* \param streamId Returns a context-unique ID for the stream +* +* \retval CUPTI_SUCCESS +* \retval CUPTI_ERROR_NOT_INITIALIZED +* \retval CUPTI_ERROR_INVALID_STREAM if unable to get stream ID, or +* if \p context is non-NULL and \p stream does not belong to the +* context +* \retval CUPTI_ERROR_INVALID_PARAMETER if \p streamId is NULL +*/ +CUptiResult CUPTIAPI cuptiGetStreamIdEx(CUcontext context, CUstream stream, uint8_t perThreadStream, uint32_t *streamId); + +/** + * \brief Get the ID of a device + * + * If \p context is NULL, returns the ID of the device that contains + * the currently active context. If \p context is non-NULL, returns + * the ID of the device which contains that context. Operates in a + * similar manner to cudaGetDevice() or cuCtxGetDevice() but may be + * called from within callback functions. + * + * \param context The context, or NULL to indicate the current context. + * \param deviceId Returns the ID of the device that is current for + * the calling thread. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE if unable to get device ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p deviceId is NULL + */ +CUptiResult CUPTIAPI cuptiGetDeviceId(CUcontext context, uint32_t *deviceId); + +/** + * \brief Get the unique ID of a graph node + * + * Returns the unique ID of the CUDA graph node. + * + * \param node The graph node. + * \param nodeId Returns the unique ID of the node + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p node is NULL + */ +CUptiResult CUPTIAPI cuptiGetGraphNodeId(CUgraphNode node, uint64_t *nodeId); + +/** + * \brief Get the unique ID of graph + * + * Returns the unique ID of CUDA graph. + * + * \param graph The graph. + * \param pId Returns the unique ID of the graph + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p graph is NULL + */ +CUptiResult CUPTIAPI cuptiGetGraphId(CUgraph graph, uint32_t *pId); + +/** + * \brief Get the unique ID of executable graph + * + * Returns the unique ID of executable CUDA graph. + * + * \param graphExec The executable graph. + * \param pId Returns the unique ID of the executable graph + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p graph is NULL + */ +CUptiResult CUPTIAPI cuptiGetGraphExecId(CUgraphExec graphExec, uint32_t *pId); + +/** + * \brief Enable collection of a specific kind of activity record. + * + * Enable collection of a specific kind of activity record. Multiple + * kinds can be enabled by calling this function multiple times. By + * default all activity kinds are disabled for collection. + * + * \param kind The kind of activity record to collect + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_NOT_COMPATIBLE if the activity kind cannot be enabled + * \retval CUPTI_ERROR_INVALID_KIND if the activity kind is not supported + */ +CUptiResult CUPTIAPI cuptiActivityEnable(CUpti_ActivityKind kind); + +/** + * \brief Enable collection of a specific kind of activity record. For certain activity kinds + * it dumps existing records. + * + * In general, the behavior of this API is similar to the API \ref cuptiActivityEnable i.e. it + * enables the collection of a specific kind of activity record. + * Additionally, this API can help in dumping the records for activities which happened in + * the past before enabling the corresponding activity kind. + * The API allows to get records for the current resource allocations done in CUDA + * For CUPTI_ACTIVITY_KIND_DEVICE, existing device records are dumped + * For CUPTI_ACTIVITY_KIND_CONTEXT, existing context records are dumped + * For CUPTI_ACTIVITY_KIND_STREAM, existing stream records are dumped + * For CUPTI_ACTIVITY_KIND_ NVLINK, existing NVLINK records are dumped + * For CUPTI_ACTIVITY_KIND_PCIE, existing PCIE records are dumped + * For other activities, the behavior is similar to the API \ref cuptiActivityEnable + * + * Device records are emitted in CUPTI on CUDA driver initialization. Those records + * can only be retrieved by the user if CUPTI is attached before CUDA initialization. + * Context and stream records are emitted on context and stream creation. + * The use case of the API is to provide the records for CUDA resources + * (contexts/streams/devices) that are currently active if user late attaches CUPTI. + * + * Before calling this function, the user must register buffer callbacks + * to get the activity records by calling \ref cuptiActivityRegisterCallbacks. + * If the user does not register the buffers and calls API \ref cuptiActivityEnableAndDump, + * then CUPTI will enable the activity kind but not provide any records for that + * activity kind. + * + * \param kind The kind of activity record to collect + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_UNKNOWN if buffer is not initialized. + * \retval CUPTI_ERROR_NOT_COMPATIBLE if the activity kind cannot be enabled + * \retval CUPTI_ERROR_INVALID_KIND if the activity kind is not supported + */ +CUptiResult CUPTIAPI cuptiActivityEnableAndDump(CUpti_ActivityKind kind); + +/** + * \brief Disable collection of a specific kind of activity record. + * + * Disable collection of a specific kind of activity record. Multiple + * kinds can be disabled by calling this function multiple times. By + * default all activity kinds are disabled for collection. + * + * \param kind The kind of activity record to stop collecting + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_KIND if the activity kind is not supported + */ +CUptiResult CUPTIAPI cuptiActivityDisable(CUpti_ActivityKind kind); + +/** + * \brief Enable collection of a specific kind of activity record for + * a context. + * + * Enable collection of a specific kind of activity record for a + * context. This setting done by this API will supersede the global + * settings for activity records enabled by \ref cuptiActivityEnable. + * Multiple kinds can be enabled by calling this function multiple + * times. + * + * \param context The context for which activity is to be enabled + * \param kind The kind of activity record to collect + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_NOT_COMPATIBLE if the activity kind cannot be enabled + * \retval CUPTI_ERROR_INVALID_KIND if the activity kind is not supported + */ +CUptiResult CUPTIAPI cuptiActivityEnableContext(CUcontext context, CUpti_ActivityKind kind); + +/** + * \brief Disable collection of a specific kind of activity record for + * a context. + * + * Disable collection of a specific kind of activity record for a context. + * This setting done by this API will supersede the global settings + * for activity records. + * Multiple kinds can be enabled by calling this function multiple times. + * + * \param context The context for which activity is to be disabled + * \param kind The kind of activity record to stop collecting + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_KIND if the activity kind is not supported + */ +CUptiResult CUPTIAPI cuptiActivityDisableContext(CUcontext context, CUpti_ActivityKind kind); + +/** + * \brief Get the number of activity records that were dropped of + * insufficient buffer space. + * + * Get the number of records that were dropped because of insufficient + * buffer space. The dropped count includes records that could not be + * recorded because CUPTI did not have activity buffer space available + * for the record (because the CUpti_BuffersCallbackRequestFunc + * callback did not return an empty buffer of sufficient size) and + * also CDP records that could not be record because the device-size + * buffer was full (size is controlled by the + * CUPTI_ACTIVITY_ATTR_DEVICE_BUFFER_SIZE_CDP attribute). The dropped + * count maintained for the queue is reset to zero when this function + * is called. + * + * \param context The context, or NULL to get dropped count from global queue + * \param streamId The stream ID + * \param dropped The number of records that were dropped since the last call + * to this function. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p dropped is NULL + */ +CUptiResult CUPTIAPI cuptiActivityGetNumDroppedRecords(CUcontext context, uint32_t streamId, + size_t *dropped); + +/** + * \brief Iterate over the activity records in a buffer. + * + * This is a helper function to iterate over the activity records in a + * buffer. A buffer of activity records is typically obtained by + * receiving a CUpti_BuffersCallbackCompleteFunc callback. Stop iterating + * the buffer when an error occurs. + * + * An example of typical usage: + * \code + * CUpti_Activity *record = NULL; + * CUptiResult status = CUPTI_SUCCESS; + * do { + * status = cuptiActivityGetNextRecord(buffer, validSize, &record); + * if(status == CUPTI_SUCCESS) { + * // Use record here... + * } + * else if (status == CUPTI_ERROR_MAX_LIMIT_REACHED) + * break; + * else if (status == CUPTI_ERROR_INVALID_KIND) + * break; + * else { + * goto Error; + * } + * } while (1); + * \endcode + * + * \param buffer The buffer containing activity records + * \param record Inputs the previous record returned by + * cuptiActivityGetNextRecord and returns the next activity record + * from the buffer. If input value is NULL, returns the first activity + * record in the buffer. Records of certain kinds like CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL + * may contain invalid (0) timestamps, indicating that no timing information could + * be collected for lack of device memory. + * \param validBufferSizeBytes The number of valid bytes in the buffer. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_MAX_LIMIT_REACHED if no more records in the buffer + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p buffer is NULL. + * \retval CUPTI_ERROR_INVALID_KIND if activity record is either incomplete or invalid + */ +CUptiResult CUPTIAPI cuptiActivityGetNextRecord(uint8_t* buffer, size_t validBufferSizeBytes, + CUpti_Activity **record); + +/** + * \brief Function type for callback used by CUPTI to request an empty + * buffer for storing activity records. + * + * This callback function signals the CUPTI client that an activity + * buffer is needed by CUPTI. The activity buffer is used by CUPTI to + * store activity records. The callback function can decline the + * request by setting \p *buffer to NULL. In this case CUPTI may drop + * activity records. + * + * \param buffer Returns the new buffer. If set to NULL then no buffer + * is returned. + * \param size Returns the size of the returned buffer. + * \param maxNumRecords Returns the maximum number of records that + * should be placed in the buffer. If 0 then the buffer is filled with + * as many records as possible. If > 0 the buffer is filled with at + * most that many records before it is returned. + */ +typedef void (CUPTIAPI *CUpti_BuffersCallbackRequestFunc)( + uint8_t **buffer, + size_t *size, + size_t *maxNumRecords); + +/** + * \brief Function type for callback used by CUPTI to return a buffer + * of activity records. + * + * This callback function returns to the CUPTI client a buffer + * containing activity records. The buffer contains \p validSize + * bytes of activity records which should be read using + * cuptiActivityGetNextRecord. The number of dropped records can be + * read using cuptiActivityGetNumDroppedRecords. After this call CUPTI + * relinquished ownership of the buffer and will not use it + * anymore. The client may return the buffer to CUPTI using the + * CUpti_BuffersCallbackRequestFunc callback. + * Note: CUDA 6.0 onwards, all buffers returned by this callback are + * global buffers i.e. there is no context/stream specific buffer. + * User needs to parse the global buffer to extract the context/stream + * specific activity records. + * + * \param context The context this buffer is associated with. If NULL, the + * buffer is associated with the global activities. This field is deprecated + * as of CUDA 6.0 and will always be NULL. + * \param streamId The stream id this buffer is associated with. + * This field is deprecated as of CUDA 6.0 and will always be NULL. + * \param buffer The activity record buffer. + * \param size The total size of the buffer in bytes as set in + * CUpti_BuffersCallbackRequestFunc. + * \param validSize The number of valid bytes in the buffer. + */ +typedef void (CUPTIAPI *CUpti_BuffersCallbackCompleteFunc)( + CUcontext context, + uint32_t streamId, + uint8_t *buffer, + size_t size, + size_t validSize); + +/** + * \brief Registers callback functions with CUPTI for activity buffer + * handling. + * + * This function registers two callback functions to be used in asynchronous + * buffer handling. If registered, activity record buffers are handled using + * asynchronous requested/completed callbacks from CUPTI. + * + * Registering these callbacks prevents the client from using CUPTI's + * blocking enqueue/dequeue functions. + * + * \param funcBufferRequested callback which is invoked when an empty + * buffer is requested by CUPTI + * \param funcBufferCompleted callback which is invoked when a buffer + * containing activity records is available from CUPTI + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if either \p + * funcBufferRequested or \p funcBufferCompleted is NULL + */ +CUptiResult CUPTIAPI cuptiActivityRegisterCallbacks(CUpti_BuffersCallbackRequestFunc funcBufferRequested, + CUpti_BuffersCallbackCompleteFunc funcBufferCompleted); + +/** + * \brief Wait for all activity records to be delivered via the + * completion callback. + * + * This function does not return until all activity records associated + * with the specified context/stream are returned to the CUPTI client + * using the callback registered in cuptiActivityRegisterCallbacks. To + * ensure that all activity records are complete, the requested + * stream(s), if any, are synchronized. + * + * If \p context is NULL, the global activity records (i.e. those not + * associated with a particular stream) are flushed (in this case no + * streams are synchronized). If \p context is a valid CUcontext and + * \p streamId is 0, the buffers of all streams of this context are + * flushed. Otherwise, the buffers of the specified stream in this + * context is flushed. + * + * Before calling this function, the buffer handling callback api + * must be activated by calling cuptiActivityRegisterCallbacks. + * + * \param context A valid CUcontext or NULL. + * \param streamId The stream ID. + * \param flag The flag can be set to indicate a forced flush. See CUpti_ActivityFlag + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_CUPTI_ERROR_INVALID_OPERATION if not preceded + * by a successful call to cuptiActivityRegisterCallbacks + * \retval CUPTI_ERROR_UNKNOWN an internal error occurred + * + * **DEPRECATED** This method is deprecated + * CONTEXT and STREAMID will be ignored. Use cuptiActivityFlushAll + * to flush all data. + */ +CUptiResult CUPTIAPI cuptiActivityFlush(CUcontext context, uint32_t streamId, uint32_t flag); + +/** + * \brief Request to deliver activity records via the buffer completion callback. + * + * This function returns the activity records associated with all contexts/streams + * (and the global buffers not associated with any stream) to the CUPTI client + * using the callback registered in cuptiActivityRegisterCallbacks. + * + * This is a blocking call but it doesn't issue any CUDA synchronization calls + * implicitly thus it's not guaranteed that all activities are completed on the + * underlying devices. Activity record is considered as completed if it has all + * the information filled up including the timestamps if any. It is the client's + * responsibility to issue necessary CUDA synchronization calls before calling + * this function if all activity records with complete information are expected + * to be delivered. + * + * Behavior of the function based on the input flag: + * (-) ::For default flush i.e. when flag is set as 0, it returns all the + * activity buffers which have all the activity records completed, buffers need not + * to be full though. It doesn't return buffers which have one or more incomplete + * records. Default flush can be done at a regular interval in a separate thread. + * (-) ::For forced flush i.e. when flag CUPTI_ACTIVITY_FLAG_FLUSH_FORCED is passed + * to the function, it returns all the activity buffers including the ones which have + * one or more incomplete activity records. It's suggested for clients to do the + * force flush before the termination of the profiling session to allow remaining + * buffers to be delivered. In general, it can be done in the at-exit handler. + * + * Before calling this function, the buffer handling callback api must be activated + * by calling cuptiActivityRegisterCallbacks. + * + * \param flag The flag can be set to indicate a forced flush. See CUpti_ActivityFlag + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_OPERATION if not preceded by a + * successful call to cuptiActivityRegisterCallbacks + * \retval CUPTI_ERROR_UNKNOWN an internal error occurred + * + * \see cuptiActivityFlushPeriod + */ +CUptiResult CUPTIAPI cuptiActivityFlushAll(uint32_t flag); + +/** + * \brief Read an activity API attribute. + * + * Read an activity API attribute and return it in \p *value. + * + * \param attr The attribute to read + * \param valueSize Size of buffer pointed by the value, and + * returns the number of bytes written to \p value + * \param value Returns the value of the attribute + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value is NULL, or + * if \p attr is not an activity attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT Indicates that + * the \p value buffer is too small to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiActivityGetAttribute(CUpti_ActivityAttribute attr, + size_t *valueSize, void* value); + +/** + * \brief Write an activity API attribute. + * + * Write an activity API attribute. + * + * \param attr The attribute to write + * \param valueSize The size, in bytes, of the value + * \param value The attribute value to write + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value is NULL, or + * if \p attr is not an activity attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT Indicates that + * the \p value buffer is too small to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiActivitySetAttribute(CUpti_ActivityAttribute attr, + size_t *valueSize, void* value); + + +/** + * \brief Set Unified Memory Counter configuration. + * + * Set the configuration before enabling the corresponding activity kind + * CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER. + * The API should be called after CUDA driver initialization. + * + * \param config A pointer to \ref CUpti_ActivityUnifiedMemoryCounterConfig structures + * containing Unified Memory counter configuration. + * \param count Number of Unified Memory counter configuration structures + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p config is NULL or + * any parameter in the \p config structures is not a valid value + * \retval CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED One potential reason is that + * platform (OS/arch) does not support the unified memory counters + * \retval CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_ON_DEVICE Indicates that the device + * does not support the unified memory counters + * \retval CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_ON_NON_P2P_DEVICES Indicates that + * multi-GPU configuration without P2P support between any pair of devices + * does not support the unified memory counters + */ +CUptiResult CUPTIAPI cuptiActivityConfigureUnifiedMemoryCounter(CUpti_ActivityUnifiedMemoryCounterConfig *config, uint32_t count); + +/** + * \brief Get auto boost state + * + * The profiling results can be inconsistent in case auto boost is enabled. + * CUPTI tries to disable auto boost while profiling. It can fail to disable in + * cases where user does not have the permissions or CUDA_AUTO_BOOST env + * variable is set. The function can be used to query whether auto boost is + * enabled. + * + * \param context A valid CUcontext. + * \param state A pointer to \ref CUpti_ActivityAutoBoostState structure which + * contains the current state and the id of the process that has requested the + * current state + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p CUcontext or \p state is NULL + * \retval CUPTI_ERROR_NOT_SUPPORTED Indicates that the device does not support auto boost + * \retval CUPTI_ERROR_UNKNOWN an internal error occurred + */ +CUptiResult CUPTIAPI cuptiGetAutoBoostState(CUcontext context, CUpti_ActivityAutoBoostState *state); + +/** + * \brief Set PC sampling configuration. + * + * For Pascal and older GPU architectures this API must be called before enabling + * activity kind CUPTI_ACTIVITY_KIND_PC_SAMPLING. There is no such requirement + * for Volta and newer GPU architectures. + * + * For Volta and newer GPU architectures if this API is called in the middle of + * execution, PC sampling configuration will be updated for subsequent kernel launches. + * + * \param ctx The context + * \param config A pointer to \ref CUpti_ActivityPCSamplingConfig structure + * containing PC sampling configuration. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_OPERATION if this api is called while + * some valid event collection method is set. + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p config is NULL or + * any parameter in the \p config structures is not a valid value + * \retval CUPTI_ERROR_NOT_SUPPORTED Indicates that the system/device + * does not support the unified memory counters + */ +CUptiResult CUPTIAPI cuptiActivityConfigurePCSampling(CUcontext ctx, CUpti_ActivityPCSamplingConfig *config); + +/** + * \brief Returns the last error from a cupti call or callback + * + * Returns the last error that has been produced by any of the cupti api calls + * or the callback in the same host thread and resets it to CUPTI_SUCCESS. + */ +CUptiResult CUPTIAPI cuptiGetLastError(void); + +/** + * \brief Set the thread-id type + * + * CUPTI uses the method corresponding to set type to generate the thread-id. + * See enum \ref CUpti_ActivityThreadIdType for the list of methods. + * Activity records having thread-id field contain the same value. + * Thread id type must not be changed during the profiling session to + * avoid thread-id value mismatch across activity records. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_SUPPORTED if \p type is not supported on the platform + */ +CUptiResult CUPTIAPI cuptiSetThreadIdType(CUpti_ActivityThreadIdType type); + +/** + * \brief Get the thread-id type + * + * Returns the thread-id type used in CUPTI + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p type is NULL + */ +CUptiResult CUPTIAPI cuptiGetThreadIdType(CUpti_ActivityThreadIdType *type); + +/** +* \brief Check support for a compute capability +* +* This function is used to check the support for a device based on +* it's compute capability. It sets the \p support when the compute +* capability is supported by the current version of CUPTI, and clears +* it otherwise. This version of CUPTI might not support all GPUs sharing +* the same compute capability. It is suggested to use API \ref +* cuptiDeviceSupported which provides correct information. +* +* \param major The major revision number of the compute capability +* \param minor The minor revision number of the compute capability +* \param support Pointer to an integer to return the support status +* +* \retval CUPTI_SUCCESS +* \retval CUPTI_ERROR_INVALID_PARAMETER if \p support is NULL +* +* \sa ::cuptiDeviceSupported +*/ +CUptiResult CUPTIAPI cuptiComputeCapabilitySupported(int major, int minor, int *support); + +/** +* \brief Check support for a compute device +* +* This function is used to check the support for a compute device. +* It sets the \p support when the device is supported by the current +* version of CUPTI, and clears it otherwise. +* +* \param dev The device handle returned by CUDA Driver API cuDeviceGet +* \param support Pointer to an integer to return the support status +* +* \retval CUPTI_SUCCESS +* \retval CUPTI_ERROR_INVALID_PARAMETER if \p support is NULL +* \retval CUPTI_ERROR_INVALID_DEVICE if \p dev is not a valid device +* +* \sa ::cuptiComputeCapabilitySupported +*/ +CUptiResult CUPTIAPI cuptiDeviceSupported(CUdevice dev, int *support); + +/** + * This indicates the virtualization mode in which CUDA device is running + */ +typedef enum { + /** + * No virtualization mode is associated with the device + * i.e. it's a baremetal GPU + */ + CUPTI_DEVICE_VIRTUALIZATION_MODE_NONE = 0, + /** + * The device is associated with the pass-through GPU. + * In this mode, an entire physical GPU is directly assigned + * to one virtual machine (VM). + */ + CUPTI_DEVICE_VIRTUALIZATION_MODE_PASS_THROUGH = 1, + /** + * The device is associated with the virtual GPU (vGPU). + * In this mode multiple virtual machines (VMs) have simultaneous, + * direct access to a single physical GPU. + */ + CUPTI_DEVICE_VIRTUALIZATION_MODE_VIRTUAL_GPU = 2, + + CUPTI_DEVICE_VIRTUALIZATION_MODE_FORCE_INT = 0x7fffffff +} CUpti_DeviceVirtualizationMode; + +/** + * \brief Query the virtualization mode of the device + * + * This function is used to query the virtualization mode of the CUDA device. + * + * \param dev The device handle returned by CUDA Driver API cuDeviceGet + * \param mode Pointer to an CUpti_DeviceVirtualizationMode to return the virtualization mode + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_DEVICE if \p dev is not a valid device + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p mode is NULL + * + */ +CUptiResult CUPTIAPI cuptiDeviceVirtualizationMode(CUdevice dev, CUpti_DeviceVirtualizationMode *mode); + +/** + * \brief Detach CUPTI from the running process + * + * This API detaches the CUPTI from the running process. It destroys and cleans up all the + * resources associated with CUPTI in the current process. After CUPTI detaches from the process, + * the process will keep on running with no CUPTI attached to it. + * For safe operation of the API, it is recommended this API is invoked from the exit callsite + * of any of the CUDA Driver or Runtime API. Otherwise CUPTI client needs to make sure that + * required CUDA synchronization and CUPTI activity buffer flush is done before calling the API. + * Sample code showing the usage of the API in the cupti callback handler code: + * \code + void CUPTIAPI + cuptiCallbackHandler(void *userdata, CUpti_CallbackDomain domain, + CUpti_CallbackId cbid, void *cbdata) + { + const CUpti_CallbackData *cbInfo = (CUpti_CallbackData *)cbdata; + + // Take this code path when CUPTI detach is requested + if (detachCupti) { + switch(domain) + { + case CUPTI_CB_DOMAIN_RUNTIME_API: + case CUPTI_CB_DOMAIN_DRIVER_API: + if (cbInfo->callbackSite == CUPTI_API_EXIT) { + // call the CUPTI detach API + cuptiFinalize(); + } + break; + default: + break; + } + } + } + \endcode + */ +CUptiResult CUPTIAPI cuptiFinalize(void); + +/** + * \brief Push an external correlation id for the calling thread + * + * This function notifies CUPTI that the calling thread is entering an external API region. + * When a CUPTI activity API record is created while within an external API region and + * CUPTI_ACTIVITY_KIND_EXTERNAL_CORRELATION is enabled, the activity API record will + * be preceded by a CUpti_ActivityExternalCorrelation record for each \ref CUpti_ExternalCorrelationKind. + * + * \param kind The kind of external API activities should be correlated with. + * \param id External correlation id. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER The external API kind is invalid + */ +CUptiResult CUPTIAPI cuptiActivityPushExternalCorrelationId(CUpti_ExternalCorrelationKind kind, uint64_t id); + +/** + * \brief Pop an external correlation id for the calling thread + * + * This function notifies CUPTI that the calling thread is leaving an external API region. + * + * \param kind The kind of external API activities should be correlated with. + * \param lastId If the function returns successful, contains the last external correlation id for this \p kind, can be NULL. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER The external API kind is invalid. + * \retval CUPTI_ERROR_QUEUE_EMPTY No external id is currently associated with \p kind. + */ +CUptiResult CUPTIAPI cuptiActivityPopExternalCorrelationId(CUpti_ExternalCorrelationKind kind, uint64_t *lastId); + +/** + * \brief Controls the collection of queued and submitted timestamps for kernels. + * + * This API is used to control the collection of queued and submitted timestamps + * for kernels whose records are provided through the struct \ref CUpti_ActivityKernel9. + * Default value is 0, i.e. these timestamps are not collected. This API needs + * to be called before initialization of CUDA and this setting should not be + * changed during the profiling session. + * + * This API is not supported if the HW trace is enabled through the API \ref cuptiActivityEnableHWTrace. + * \param enable is a boolean, denoting whether these timestamps should be + * collected + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + */ +CUptiResult CUPTIAPI cuptiActivityEnableLatencyTimestamps(uint8_t enable); + +/** + * \brief Sets the flush period for the worker thread + * + * CUPTI creates a worker thread to minimize the perturbance for the application created + * threads. CUPTI offloads certain operations from the application threads to the worker + * thread, this includes synchronization of profiling resources between host and device, + * delivery of the activity buffers to the client using the callback registered in + * cuptiActivityRegisterCallbacks. For performance reasons, CUPTI wakes up the worker + * thread based on certain heuristics. + * + * This API is used to control the flush period of the worker thread. This setting will + * override the CUPTI heuristics. Setting time to zero disables the periodic flush and + * restores the default behavior. + * + * Periodic flush can return only those activity buffers which are full and have all the + * activity records completed. + * + * It's allowed to use the API \ref cuptiActivityFlushAll to flush the data on-demand, even + * when client sets the periodic flush. + * + * \param time flush period in milliseconds (ms) + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * + * \see cuptiActivityFlushAll + */ +CUptiResult CUPTIAPI cuptiActivityFlushPeriod(uint32_t time); + +/** + * \brief Controls the collection of launch attributes for kernels. + * + * This API is used to control the collection of launch attributes for kernels whose + * records are provided through the struct \ref CUpti_ActivityKernel9. + * Default value is 0, i.e. these attributes are not collected. + * + * \param enable is a boolean denoting whether these launch attributes should be collected + */ +CUptiResult CUPTIAPI cuptiActivityEnableLaunchAttributes(uint8_t enable); + +/** + * \brief Function type for callback used by CUPTI to request a timestamp + * to be used in activity records. + * + * This callback function signals the CUPTI client that a timestamp needs + * to be returned. This timestamp would be treated as normalized timestamp + * to be used for various purposes in CUPTI. For example to store start and + * end timestamps reported in the CUPTI activity records. + * The returned timestamp must be in nanoseconds. + * + * \sa ::cuptiActivityRegisterTimestampCallback + */ +typedef uint64_t (CUPTIAPI *CUpti_TimestampCallbackFunc)(void); + +/** + * \brief Registers callback function with CUPTI for providing timestamp. + * + * This function registers a callback function to obtain timestamp of user's + * choice instead of using CUPTI provided timestamp. + * By default CUPTI uses different methods, based on the underlying platform, + * to retrieve the timestamp + * Linux and Android use clock_gettime(CLOCK_REALTIME, ..) + * Windows uses QueryPerformanceCounter() + * QNX uses ClockCycles() + * Timestamps retrieved using these methods are converted to nanosecond if needed + * before usage. + * + * Timestamps for GPU activities such as kernels, memory copies and memset operations are + * recorded directly on the GPU. To provide a unified and normalized view of these timestamps + * in relation to CPU time, CUPTI performs a linear interpolation to convert GPU timestamps + * into CPU timestamps during post-processing. + * For activities where timestamps are captured on the GPU, the timestamp callback is invoked + * during the post-processing phase, while converting GPU timestamps into CPU timestamps. + * For activities for which timestamps are captured directly on the CPU, the timestamp callback + * is invoked immediately at the time of the activity. + * + * The registration of timestamp callback should be done before any of the CUPTI + * activity kinds are enabled to make sure that all the records report the timestamp using + * the callback function registered through cuptiActivityRegisterTimestampCallback API. + * + * Changing the timestamp callback function in CUPTI through + * cuptiActivityRegisterTimestampCallback API in the middle of the profiling + * session can cause records generated prior to the change to report + * timestamps through previous timestamp method. + * + * \param funcTimestamp callback which is invoked when a timestamp is + * needed by CUPTI + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p funcTimestamp is NULL + * \retval CUPTI_ERROR_NOT_INITIALIZED + */ +CUptiResult CUPTIAPI cuptiActivityRegisterTimestampCallback(CUpti_TimestampCallbackFunc funcTimestamp); + +/** + * \brief Controls the collection of records for device launched graphs. + * + * This API is used to control the collection of records for device launched graphs. + * Default value is 0, i.e. these records are not collected. This API needs + * to be called before initialization of CUDA and this setting should not be + * changed during the profiling session. + * + * \param enable is a boolean, denoting whether these records should be + * collected + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + */ +CUptiResult CUPTIAPI cuptiActivityEnableDeviceGraph(uint8_t enable); + +/** + * \brief Controls the collection of activity records for specific CUDA Driver APIs. + * + * Activity kind CUPTI_ACTIVITY_KIND_DRIVER controls the collection of either all + * CUDA Driver APIs or none. API cuptiActivityEnableDriverApi can be used for fine-grained + * control, it allows enabling/disabling tracing of a specific set of CUDA Driver APIs. + * To disable collection of a small set of CUDA Driver APIs, user can + * first enable the collection of all Driver APIs using the activity kind + * CUPTI_ACTIVITY_KIND_DRIVER and call this API to disable specific Driver APIs. + * And to enable the collection of a small set of CUDA Driver APIs, user can + * call this API without using the activity kind CUPTI_ACTIVITY_KIND_DRIVER. + * + * Note: Activity kind CUPTI_ACTIVITY_KIND_DRIVER overrides the settings done by this API + * if it is called after the API. + * + * \param cbid callback id of the CUDA Driver API. This can be found in the header cupti_driver_cbid.h. + * \param enable is a boolean, denoting whether to enable or disable the collection + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + */ +CUptiResult CUPTIAPI cuptiActivityEnableDriverApi(CUpti_CallbackId cbid, uint8_t enable); + +/** + * \brief Controls the collection of activity records for specific CUDA Runtime APIs. + * + * Activity kind CUPTI_ACTIVITY_KIND_RUNTIME controls the collection of either all + * CUDA Runtime APIs or none. API cuptiActivityEnableRuntimeApi can be used for fine-grained + * control, it allows enabling/disabling tracing of a specific set of CUDA Runtime APIs. + * To disable collection of a small set of CUDA Runtime APIs, user can + * first enable the collection of all Runtime APIs using the activity kind + * CUPTI_ACTIVITY_KIND_RUNTIME and call this API to disable specific Runtime APIs. + * And to enable the collection of a small set of CUDA Runtime APIs, user can + * call this API without using the activity kind CUPTI_ACTIVITY_KIND_RUNTIME. + * + * Note: Activity kind CUPTI_ACTIVITY_KIND_RUNTIME overrides the settings done by this API + * if it is called after the API. + * + * \param cbid callback id of the CUDA Runtime API. This can be found in the header cupti_runtime_cbid.h. + * \param enable is a boolean, denoting whether to enable or disable the collection + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + */ +CUptiResult CUPTIAPI cuptiActivityEnableRuntimeApi(CUpti_CallbackId cbid, uint8_t enable); + +/** + * \brief Enables the collection of CUDA kernel timestamps through HW events. + * + * This API enables the collection of CUDA kernel timestamps through HW events instead + * of the traditional SW instrumentation and semaphore based approach. + * This option is only available on Blackwell architecture. + * This API should be called after driver is initialized. + * + * \param enable is a boolean, denoting whether to enable or disable the collection through HW events + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED if CUPTI is not initialized or the CUDA driver is not initialized + * \retval CUPTI_ERROR_NOT_SUPPORTED if HW trace cannot be enabled on the current platform + * \retval CUPTI_ERROR_VIRTUALIZED_DEVICE_NOT_SUPPORTED + * \retval CUPTI_ERROR_CONFIDENTIAL_COMPUTING_NOT_SUPPORTED + * \retval CUPTI_ERROR_CMP_DEVICE_NOT_SUPPORTED + * \retval CUPTI_ERROR_MIG_DEVICE_NOT_SUPPORTED + * \retval CUPTI_ERROR_SLI_DEVICE_NOT_SUPPORTED + * \retval CUPTI_ERROR_WSL_DEVICE_NOT_SUPPORTED + */ +CUptiResult CUPTIAPI cuptiActivityEnableHWTrace(uint8_t enable); + + +/** + * \brief Enables tracking the source library for memory allocation requests. + * + * This API is used to control whether or not we track the source library of + * memory allocation requests. Default value is 0, i.e. it is not tracked. The + * activity kind CUPTI_ACTIVITY_KIND_MEMORY2 needs to be enabled, and if this flag is + * set, we get the full path of the shared object responsible for the GPU memory allocation + * request in the member source in the CUpti_ActivityMemory4 records. Also note that this feature + * adds runtime overhead. + * + * \param enable is a boolean, denoting whether the source library of the memory allocation + * request needs to be tracked + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED +*/ +CUptiResult CUPTIAPI cuptiActivityEnableAllocationSource (uint8_t enable); + +/** + * \brief Enables collecting records for all synchronization operations. + * + * CUPTI provides CUDA event query and stream query records via CUPTI_ACTIVTIY_KIND_SYNCHRONIZATION. + * Using this API, CUPTI client can enable to record all CUDA event query and stream query records + * even if the event has not yet been completed and all operations on stream have not yet been completed + * respectively. + * + * By default, the record is only generated if all captured work has been completed for the CUDA event. + * By default, the record is only generated if all operations have been completed on the stream. + * + * \param enable is a boolean, denoting whether to enable or disable the collection of all CUDA event query + * and stream query records + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + */ +CUptiResult CUPTIAPI cuptiActivityEnableAllSyncRecords(uint8_t enable); + +/** @} */ /* END CUPTI_ACTIVITY_API */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +// Including deprecated structures of CUPTI_ACTIVITY_API +#include "cupti_activity_deprecated.h" + +#endif /*_CUPTI_ACTIVITY_H_*/ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_activity_deprecated.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_activity_deprecated.h new file mode 100644 index 0000000000000000000000000000000000000000..f9d725499ffa13ac7de864719abee2baa88d6c13 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_activity_deprecated.h @@ -0,0 +1,5335 @@ +/* + * Copyright 2011-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_ACTIVITY_DEPRECATED_H_) +#define _CUPTI_ACTIVITY_DEPRECATED_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \brief The kinds of activity records. + * + * Each activity record kind represents information about a GPU or an + * activity occurring on a CPU or GPU. Each kind is associated with a + * activity record structure that holds the information associated + * with the kind. + * \see CUpti_ActivityOverhead + * \see CUpti_ActivityOverhead2 + * \see CUpti_ActivityDevice + * \see CUpti_ActivityDevice2 + * \see CUpti_ActivityDevice3 + * \see CUpti_ActivityDevice4 + * \see CUpti_ActivityKernel + * \see CUpti_ActivityKernel2 + * \see CUpti_ActivityKernel3 + * \see CUpti_ActivityKernel4 + * \see CUpti_ActivityKernel5 + * \see CUpti_ActivityKernel6 + * \see CUpti_ActivityKernel7 + * \see CUpti_ActivityKernel8 + * \see CUpti_ActivityMemcpy + * \see CUpti_ActivityMemcpy3 + * \see CUpti_ActivityMemcpy4 + * \see CUpti_ActivityMemcpyPtoP + * \see CUpti_ActivityMemcpyPtoP2 + * \see CUpti_ActivityMemcpyPtoP3 + * \see CUpti_ActivityMemset + * \see CUpti_ActivityMemset2 + * \see CUpti_ActivityMemset3 + * \see CUpti_ActivityMemory2 + * \see CUpti_ActivityMemory3 + * \see CUpti_ActivityMemoryPool + * \see CUpti_ActivityMarker + * \see CUpti_ActivityGlobalAccess + * \see CUpti_ActivityGlobalAccess2 + * \see CUpti_ActivityBranch + * \see CUpti_ActivityPCSampling + * \see CUpti_ActivityPCSampling2 + * \see CUpti_ActivityUnifiedMemoryCounter + * \see CUpti_ActivityUnifiedMemoryCounter2 + * \see CUpti_ActivityNvLink + * \see CUpti_ActivityNvLink2 + * \see CUpti_ActivityNvLink3 + */ + +/** + * \brief The activity record for CUPTI and driver overheads. + * (Deprecated in CUDA 12.2) + * + * This activity record provides CUPTI and driver overhead information + * (CUPTI_ACTIVITY_OVERHEAD). These records are now reported using + * CUpti_ActivityOverhead3 + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_OVERHEAD. + */ + CUpti_ActivityKind kind; + + /** + * The kind of overhead, CUPTI, DRIVER, COMPILER etc. + */ + CUpti_ActivityOverheadKind overheadKind; + + /** + * The kind of activity object that the overhead is associated with. + */ + CUpti_ActivityObjectKind objectKind; + + /** + * The identifier for the activity object. 'objectKind' indicates + * which ID is valid for this record. + */ + CUpti_ActivityObjectKindId objectId; + + /** + * The start timestamp for the overhead, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the overhead. + */ + uint64_t start; + + /** + * The end timestamp for the overhead, in ns. A value of 0 for both + * the start and end timestamps indicates that timestamp information + * could not be collected for the overhead. + */ + uint64_t end; +} CUpti_ActivityOverhead; + +/** + * \brief The activity record for CUPTI and driver overheads. + * + * This activity record provides CUPTI and driver overhead information + * (CUPTI_ACTIVITY_OVERHEAD). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_OVERHEAD. + */ + CUpti_ActivityKind kind; + + /** + * The kind of overhead, CUPTI, DRIVER, COMPILER etc. + */ + CUpti_ActivityOverheadKind overheadKind; + + /** + * The kind of activity object that the overhead is associated with. + */ + CUpti_ActivityObjectKind objectKind; + + /** + * The identifier for the activity object. 'objectKind' indicates + * which ID is valid for this record. + */ + CUpti_ActivityObjectKindId objectId; + + /** + * The start timestamp for the overhead, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the overhead. + */ + uint64_t start; + + /** + * The end timestamp for the overhead, in ns. A value of 0 for both + * the start and end timestamps indicates that timestamp information + * could not be collected for the overhead. + */ + uint64_t end; + + /** + * The correlation ID of the overhead operation to which + * records belong to. This ID is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the overhead operation. + * In some cases, it can be zero, such as for CUPTI_ACTIVITY_OVERHEAD_CUPTI_BUFFER_FLUSH records. + */ + uint32_t correlationId; + + /** + * Reserved for internal use. + */ + uint32_t reserved0; +} CUpti_ActivityOverhead2; + +/** + * \brief The activity record for a device. (deprecated) + * + * This activity record represents information about a GPU device + * (CUPTI_ACTIVITY_KIND_DEVICE). + * Device activity is now reported using the + * CUpti_ActivityDevice5 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_DEVICE. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the device. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The global memory bandwidth available on the device, in + * kBytes/sec. + */ + uint64_t globalMemoryBandwidth; + + /** + * The amount of global memory on the device, in bytes. + */ + uint64_t globalMemorySize; + + /** + * The amount of constant memory on the device, in bytes. + */ + uint32_t constantMemorySize; + + /** + * The size of the L2 cache on the device, in bytes. + */ + uint32_t l2CacheSize; + + /** + * The number of threads per warp on the device. + */ + uint32_t numThreadsPerWarp; + + /** + * The core clock rate of the device, in kHz. + */ + uint32_t coreClockRate; + + /** + * Number of memory copy engines on the device. + */ + uint32_t numMemcpyEngines; + + /** + * Number of multiprocessors on the device. + */ + uint32_t numMultiprocessors; + + /** + * The maximum "instructions per cycle" possible on each device + * multiprocessor. + */ + uint32_t maxIPC; + + /** + * Maximum number of warps that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxWarpsPerMultiprocessor; + + /** + * Maximum number of blocks that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxBlocksPerMultiprocessor; + + /** + * Maximum number of registers that can be allocated to a block. + */ + uint32_t maxRegistersPerBlock; + + /** + * Maximum amount of shared memory that can be assigned to a block, + * in bytes. + */ + uint32_t maxSharedMemoryPerBlock; + + /** + * Maximum number of threads allowed in a block. + */ + uint32_t maxThreadsPerBlock; + + /** + * Maximum allowed X dimension for a block. + */ + uint32_t maxBlockDimX; + + /** + * Maximum allowed Y dimension for a block. + */ + uint32_t maxBlockDimY; + + /** + * Maximum allowed Z dimension for a block. + */ + uint32_t maxBlockDimZ; + + /** + * Maximum allowed X dimension for a grid. + */ + uint32_t maxGridDimX; + + /** + * Maximum allowed Y dimension for a grid. + */ + uint32_t maxGridDimY; + + /** + * Maximum allowed Z dimension for a grid. + */ + uint32_t maxGridDimZ; + + /** + * Compute capability for the device, major number. + */ + uint32_t computeCapabilityMajor; + + /** + * Compute capability for the device, minor number. + */ + uint32_t computeCapabilityMinor; + + /** + * The device ID. + */ + uint32_t id; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The device name. This name is shared across all activity records + * representing instances of the device, and so should not be + * modified. + */ + const char *name; +} CUpti_ActivityDevice; + +/** + * \brief The activity record for a device. (deprecated) + * + * This activity record represents information about a GPU device + * (CUPTI_ACTIVITY_KIND_DEVICE). + * Device activity is now reported using the + * CUpti_ActivityDevice5 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_DEVICE. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the device. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The global memory bandwidth available on the device, in + * kBytes/sec. + */ + uint64_t globalMemoryBandwidth; + + /** + * The amount of global memory on the device, in bytes. + */ + uint64_t globalMemorySize; + + /** + * The amount of constant memory on the device, in bytes. + */ + uint32_t constantMemorySize; + + /** + * The size of the L2 cache on the device, in bytes. + */ + uint32_t l2CacheSize; + + /** + * The number of threads per warp on the device. + */ + uint32_t numThreadsPerWarp; + + /** + * The core clock rate of the device, in kHz. + */ + uint32_t coreClockRate; + + /** + * Number of memory copy engines on the device. + */ + uint32_t numMemcpyEngines; + + /** + * Number of multiprocessors on the device. + */ + uint32_t numMultiprocessors; + + /** + * The maximum "instructions per cycle" possible on each device + * multiprocessor. + */ + uint32_t maxIPC; + + /** + * Maximum number of warps that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxWarpsPerMultiprocessor; + + /** + * Maximum number of blocks that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxBlocksPerMultiprocessor; + + /** + * Maximum amount of shared memory available per multiprocessor, in bytes. + */ + uint32_t maxSharedMemoryPerMultiprocessor; + + /** + * Maximum number of 32-bit registers available per multiprocessor. + */ + uint32_t maxRegistersPerMultiprocessor; + + /** + * Maximum number of registers that can be allocated to a block. + */ + uint32_t maxRegistersPerBlock; + + /** + * Maximum amount of shared memory that can be assigned to a block, + * in bytes. + */ + uint32_t maxSharedMemoryPerBlock; + + /** + * Maximum number of threads allowed in a block. + */ + uint32_t maxThreadsPerBlock; + + /** + * Maximum allowed X dimension for a block. + */ + uint32_t maxBlockDimX; + + /** + * Maximum allowed Y dimension for a block. + */ + uint32_t maxBlockDimY; + + /** + * Maximum allowed Z dimension for a block. + */ + uint32_t maxBlockDimZ; + + /** + * Maximum allowed X dimension for a grid. + */ + uint32_t maxGridDimX; + + /** + * Maximum allowed Y dimension for a grid. + */ + uint32_t maxGridDimY; + + /** + * Maximum allowed Z dimension for a grid. + */ + uint32_t maxGridDimZ; + + /** + * Compute capability for the device, major number. + */ + uint32_t computeCapabilityMajor; + + /** + * Compute capability for the device, minor number. + */ + uint32_t computeCapabilityMinor; + + /** + * The device ID. + */ + uint32_t id; + + /** + * ECC enabled flag for device + */ + uint32_t eccEnabled; + + /** + * The device UUID. This value is the globally unique immutable + * alphanumeric identifier of the device. + */ + CUuuid uuid; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The device name. This name is shared across all activity records + * representing instances of the device, and so should not be + * modified. + */ + const char *name; +} CUpti_ActivityDevice2; + +/** + * \brief The activity record for a device. (CUDA 7.0 onwards) + * + * This activity record represents information about a GPU device + * (CUPTI_ACTIVITY_KIND_DEVICE). + * Device activity is now reported using the + * CUpti_ActivityDevice5 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_DEVICE. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the device. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The global memory bandwidth available on the device, in + * kBytes/sec. + */ + uint64_t globalMemoryBandwidth; + + /** + * The amount of global memory on the device, in bytes. + */ + uint64_t globalMemorySize; + + /** + * The amount of constant memory on the device, in bytes. + */ + uint32_t constantMemorySize; + + /** + * The size of the L2 cache on the device, in bytes. + */ + uint32_t l2CacheSize; + + /** + * The number of threads per warp on the device. + */ + uint32_t numThreadsPerWarp; + + /** + * The core clock rate of the device, in kHz. + */ + uint32_t coreClockRate; + + /** + * Number of memory copy engines on the device. + */ + uint32_t numMemcpyEngines; + + /** + * Number of multiprocessors on the device. + */ + uint32_t numMultiprocessors; + + /** + * The maximum "instructions per cycle" possible on each device + * multiprocessor. + */ + uint32_t maxIPC; + + /** + * Maximum number of warps that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxWarpsPerMultiprocessor; + + /** + * Maximum number of blocks that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxBlocksPerMultiprocessor; + + /** + * Maximum amount of shared memory available per multiprocessor, in bytes. + */ + uint32_t maxSharedMemoryPerMultiprocessor; + + /** + * Maximum number of 32-bit registers available per multiprocessor. + */ + uint32_t maxRegistersPerMultiprocessor; + + /** + * Maximum number of registers that can be allocated to a block. + */ + uint32_t maxRegistersPerBlock; + + /** + * Maximum amount of shared memory that can be assigned to a block, + * in bytes. + */ + uint32_t maxSharedMemoryPerBlock; + + /** + * Maximum number of threads allowed in a block. + */ + uint32_t maxThreadsPerBlock; + + /** + * Maximum allowed X dimension for a block. + */ + uint32_t maxBlockDimX; + + /** + * Maximum allowed Y dimension for a block. + */ + uint32_t maxBlockDimY; + + /** + * Maximum allowed Z dimension for a block. + */ + uint32_t maxBlockDimZ; + + /** + * Maximum allowed X dimension for a grid. + */ + uint32_t maxGridDimX; + + /** + * Maximum allowed Y dimension for a grid. + */ + uint32_t maxGridDimY; + + /** + * Maximum allowed Z dimension for a grid. + */ + uint32_t maxGridDimZ; + + /** + * Compute capability for the device, major number. + */ + uint32_t computeCapabilityMajor; + + /** + * Compute capability for the device, minor number. + */ + uint32_t computeCapabilityMinor; + + /** + * The device ID. + */ + uint32_t id; + + /** + * ECC enabled flag for device + */ + uint32_t eccEnabled; + + /** + * The device UUID. This value is the globally unique immutable + * alphanumeric identifier of the device. + */ + CUuuid uuid; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The device name. This name is shared across all activity records + * representing instances of the device, and so should not be + * modified. + */ + const char *name; + + /** + * Flag to indicate whether the device is visible to CUDA. Users can + * set the device visibility using CUDA_VISIBLE_DEVICES environment + */ + uint8_t isCudaVisible; + + uint8_t reserved[7]; +} CUpti_ActivityDevice3; + +/** + * \brief The activity record for a device. (CUDA 11.6 onwards) + * + * This activity record represents information about a GPU device + * (CUPTI_ACTIVITY_KIND_DEVICE). + * Device activity is now reported using the + * CUpti_ActivityDevice5 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_DEVICE. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the device. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The global memory bandwidth available on the device, in + * kBytes/sec. + */ + uint64_t globalMemoryBandwidth; + + /** + * The amount of global memory on the device, in bytes. + */ + uint64_t globalMemorySize; + + /** + * The amount of constant memory on the device, in bytes. + */ + uint32_t constantMemorySize; + + /** + * The size of the L2 cache on the device, in bytes. + */ + uint32_t l2CacheSize; + + /** + * The number of threads per warp on the device. + */ + uint32_t numThreadsPerWarp; + + /** + * The core clock rate of the device, in kHz. + */ + uint32_t coreClockRate; + + /** + * Number of memory copy engines on the device. + */ + uint32_t numMemcpyEngines; + + /** + * Number of multiprocessors on the device. + */ + uint32_t numMultiprocessors; + + /** + * The maximum "instructions per cycle" possible on each device + * multiprocessor. + */ + uint32_t maxIPC; + + /** + * Maximum number of warps that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxWarpsPerMultiprocessor; + + /** + * Maximum number of blocks that can be present on a multiprocessor + * at any given time. + */ + uint32_t maxBlocksPerMultiprocessor; + + /** + * Maximum amount of shared memory available per multiprocessor, in bytes. + */ + uint32_t maxSharedMemoryPerMultiprocessor; + + /** + * Maximum number of 32-bit registers available per multiprocessor. + */ + uint32_t maxRegistersPerMultiprocessor; + + /** + * Maximum number of registers that can be allocated to a block. + */ + uint32_t maxRegistersPerBlock; + + /** + * Maximum amount of shared memory that can be assigned to a block, + * in bytes. + */ + uint32_t maxSharedMemoryPerBlock; + + /** + * Maximum number of threads allowed in a block. + */ + uint32_t maxThreadsPerBlock; + + /** + * Maximum allowed X dimension for a block. + */ + uint32_t maxBlockDimX; + + /** + * Maximum allowed Y dimension for a block. + */ + uint32_t maxBlockDimY; + + /** + * Maximum allowed Z dimension for a block. + */ + uint32_t maxBlockDimZ; + + /** + * Maximum allowed X dimension for a grid. + */ + uint32_t maxGridDimX; + + /** + * Maximum allowed Y dimension for a grid. + */ + uint32_t maxGridDimY; + + /** + * Maximum allowed Z dimension for a grid. + */ + uint32_t maxGridDimZ; + + /** + * Compute capability for the device, major number. + */ + uint32_t computeCapabilityMajor; + + /** + * Compute capability for the device, minor number. + */ + uint32_t computeCapabilityMinor; + + /** + * The device ID. + */ + uint32_t id; + + /** + * ECC enabled flag for device + */ + uint32_t eccEnabled; + + /** + * The device UUID. This value is the globally unique immutable + * alphanumeric identifier of the device. + */ + CUuuid uuid; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The device name. This name is shared across all activity records + * representing instances of the device, and so should not be + * modified. + */ + const char *name; + + /** + * Flag to indicate whether the device is visible to CUDA. Users can + * set the device visibility using CUDA_VISIBLE_DEVICES environment + */ + uint8_t isCudaVisible; + + /** + * MIG enabled flag for device + */ + uint8_t isMigEnabled; + + uint8_t reserved[6]; + + /** + * GPU Instance id for MIG enabled devices. + * If mig mode is disabled value is set to UINT32_MAX + */ + uint32_t gpuInstanceId; + + /** + * Compute Instance id for MIG enabled devices. + * If mig mode is disabled value is set to UINT32_MAX + */ + uint32_t computeInstanceId; + + /** + * The MIG UUID. This value is the globally unique immutable + * alphanumeric identifier of the device. + */ + CUuuid migUuid; + +} CUpti_ActivityDevice4; + +/** + * \brief The activity record for kernel. (deprecated) + * + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL) but is no longer generated + * by CUPTI. Kernel activities are now reported using the + * CUpti_ActivityKernel9 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL + * or CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t cacheConfigRequested; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t cacheConfigExecuted; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the kernel. + */ + uint32_t correlationId; + + /** + * The runtime correlation ID of the kernel. Each kernel execution + * is assigned a unique runtime correlation ID that is identical to + * the correlation ID in the runtime API activity record that + * launched the kernel. + */ + uint32_t runtimeCorrelationId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; +} CUpti_ActivityKernel; + +/** + * \brief The activity record for kernel. (deprecated) + * + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL) but is no longer generated + * by CUPTI. Kernel activities are now reported using the + * CUpti_ActivityKernel9 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL or + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The completed timestamp for the kernel execution, in ns. It + * represents the completion of all it's child kernels and the + * kernel itself. A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the completion time is unknown. + */ + uint64_t completed; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel is assigned a unique + * grid ID at runtime. + */ + int64_t gridId; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; +} CUpti_ActivityKernel2; + +/** + * \brief The activity record for a kernel (CUDA 6.5(with sm_52 support) onwards). + * (deprecated in CUDA 9.0) + * + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL). + * Kernel activities are now reported using the CUpti_ActivityKernel9 activity + * record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL or + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The partitioned global caching requested for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheRequested; + + /** + * The partitioned global caching executed for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. Partitioned global caching can be + * automatically disabled if the occupancy requirement of the launch cannot + * support caching. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheExecuted; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The completed timestamp for the kernel execution, in ns. It + * represents the completion of all it's child kernels and the + * kernel itself. A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the completion time is unknown. + */ + uint64_t completed; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel is assigned a unique + * grid ID at runtime. + */ + int64_t gridId; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; +} CUpti_ActivityKernel3; + +/** + * \brief The activity record for a kernel (CUDA 9.0(with sm_70 support) onwards). + * (deprecated in CUDA 11.0) + * + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL). + * Kernel activities are now reported using the CUpti_ActivityKernel9 activity + * record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL or + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + /** + * For devices with compute capability 7.0+ cacheConfig values are not updated + * in case field isSharedMemoryCarveoutRequested is set + */ + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The partitioned global caching requested for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheRequested; + + /** + * The partitioned global caching executed for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. Partitioned global caching can be + * automatically disabled if the occupancy requirement of the launch cannot + * support caching. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheExecuted; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The completed timestamp for the kernel execution, in ns. It + * represents the completion of all it's child kernels and the + * kernel itself. A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the completion time is unknown. + */ + uint64_t completed; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel is assigned a unique + * grid ID at runtime. + */ + int64_t gridId; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The timestamp when the kernel is queued up in the command buffer, in ns. + * A value of CUPTI_TIMESTAMP_UNKNOWN indicates that the queued time + * could not be collected for the kernel. This timestamp is not collected + * by default. Use API \ref cuptiActivityEnableLatencyTimestamps() to + * enable collection. + * + * Command buffer is a buffer written by CUDA driver to send commands + * like kernel launch, memory copy etc to the GPU. All launches of CUDA + * kernels are asynchronous with respect to the host, the host requests + * the launch by writing commands into the command buffer, then returns + * without checking the GPU's progress. + */ + uint64_t queued; + + /** + * The timestamp when the command buffer containing the kernel launch + * is submitted to the GPU, in ns. A value of CUPTI_TIMESTAMP_UNKNOWN + * indicates that the submitted time could not be collected for the kernel. + * This timestamp is not collected by default. Use API \ref + * cuptiActivityEnableLatencyTimestamps() to enable collection. + */ + uint64_t submitted; + + /** + * The indicates if the kernel was executed via a regular launch or via a + * single/multi device cooperative launch. \see CUpti_ActivityLaunchType + */ + uint8_t launchType; + + /** + * This indicates if CU_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT was + * updated for the kernel launch + */ + uint8_t isSharedMemoryCarveoutRequested; + + /** + * Shared memory carveout value requested for the function in percentage of + * the total resource. The value will be updated only if field + * isSharedMemoryCarveoutRequested is set. + */ + uint8_t sharedMemoryCarveoutRequested; + + /** + * Undefined. Reserved for internal use. + */ + uint8_t padding; + + /** + * Shared memory size set by the driver. + */ + uint32_t sharedMemoryExecuted; +} CUpti_ActivityKernel4; + +/** + * \brief The activity record for a kernel (CUDA 11.0(with sm_80 support) onwards). + * (deprecated in CUDA 11.2) + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL) but is no longer generated + * by CUPTI. Kernel activities are now reported using the + * CUpti_ActivityKernel9 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL or + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + /** + * For devices with compute capability 7.0+ cacheConfig values are not updated + * in case field isSharedMemoryCarveoutRequested is set + */ + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The partitioned global caching requested for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheRequested; + + /** + * The partitioned global caching executed for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. Partitioned global caching can be + * automatically disabled if the occupancy requirement of the launch cannot + * support caching. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheExecuted; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The completed timestamp for the kernel execution, in ns. It + * represents the completion of all it's child kernels and the + * kernel itself. A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the completion time is unknown. + */ + uint64_t completed; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel is assigned a unique + * grid ID at runtime. + */ + int64_t gridId; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The timestamp when the kernel is queued up in the command buffer, in ns. + * A value of CUPTI_TIMESTAMP_UNKNOWN indicates that the queued time + * could not be collected for the kernel. This timestamp is not collected + * by default. Use API \ref cuptiActivityEnableLatencyTimestamps() to + * enable collection. + * + * Command buffer is a buffer written by CUDA driver to send commands + * like kernel launch, memory copy etc to the GPU. All launches of CUDA + * kernels are asynchronous with respect to the host, the host requests + * the launch by writing commands into the command buffer, then returns + * without checking the GPU's progress. + */ + uint64_t queued; + + /** + * The timestamp when the command buffer containing the kernel launch + * is submitted to the GPU, in ns. A value of CUPTI_TIMESTAMP_UNKNOWN + * indicates that the submitted time could not be collected for the kernel. + * This timestamp is not collected by default. Use API \ref + * cuptiActivityEnableLatencyTimestamps() to enable collection. + */ + uint64_t submitted; + + /** + * The indicates if the kernel was executed via a regular launch or via a + * single/multi device cooperative launch. \see CUpti_ActivityLaunchType + */ + uint8_t launchType; + + /** + * This indicates if CU_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT was + * updated for the kernel launch + */ + uint8_t isSharedMemoryCarveoutRequested; + + /** + * Shared memory carveout value requested for the function in percentage of + * the total resource. The value will be updated only if field + * isSharedMemoryCarveoutRequested is set. + */ + uint8_t sharedMemoryCarveoutRequested; + + /** + * Undefined. Reserved for internal use. + */ + uint8_t padding; + + /** + * Shared memory size set by the driver. + */ + uint32_t sharedMemoryExecuted; + + /** + * The unique ID of the graph node that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint64_t graphNodeId; + + /** + * The shared memory limit config for the kernel. This field shows whether user has opted for a + * higher per block limit of dynamic shared memory. + */ + CUpti_FuncShmemLimitConfig shmemLimitConfig; + + /** + * The unique ID of the graph that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint32_t graphId; +} CUpti_ActivityKernel5; + +/** + * \brief The activity record for kernel. (deprecated in CUDA 11.6) + * + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL) but is no longer generated + * by CUPTI. Kernel activities are now reported using the + * CUpti_ActivityKernel9 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL or + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + /** + * For devices with compute capability 7.0+ cacheConfig values are not updated + * in case field isSharedMemoryCarveoutRequested is set + */ + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The partitioned global caching requested for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheRequested; + + /** + * The partitioned global caching executed for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. Partitioned global caching can be + * automatically disabled if the occupancy requirement of the launch cannot + * support caching. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheExecuted; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The completed timestamp for the kernel execution, in ns. It + * represents the completion of all it's child kernels and the + * kernel itself. A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the completion time is unknown. + */ + uint64_t completed; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel is assigned a unique + * grid ID at runtime. + */ + int64_t gridId; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The timestamp when the kernel is queued up in the command buffer, in ns. + * A value of CUPTI_TIMESTAMP_UNKNOWN indicates that the queued time + * could not be collected for the kernel. This timestamp is not collected + * by default. Use API \ref cuptiActivityEnableLatencyTimestamps() to + * enable collection. + * + * Command buffer is a buffer written by CUDA driver to send commands + * like kernel launch, memory copy etc to the GPU. All launches of CUDA + * kernels are asynchronous with respect to the host, the host requests + * the launch by writing commands into the command buffer, then returns + * without checking the GPU's progress. + */ + uint64_t queued; + + /** + * The timestamp when the command buffer containing the kernel launch + * is submitted to the GPU, in ns. A value of CUPTI_TIMESTAMP_UNKNOWN + * indicates that the submitted time could not be collected for the kernel. + * This timestamp is not collected by default. Use API \ref + * cuptiActivityEnableLatencyTimestamps() to enable collection. + */ + uint64_t submitted; + + /** + * The indicates if the kernel was executed via a regular launch or via a + * single/multi device cooperative launch. \see CUpti_ActivityLaunchType + */ + uint8_t launchType; + + /** + * This indicates if CU_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT was + * updated for the kernel launch + */ + uint8_t isSharedMemoryCarveoutRequested; + + /** + * Shared memory carveout value requested for the function in percentage of + * the total resource. The value will be updated only if field + * isSharedMemoryCarveoutRequested is set. + */ + uint8_t sharedMemoryCarveoutRequested; + + /** + * Undefined. Reserved for internal use. + */ + uint8_t padding; + + /** + * Shared memory size set by the driver. + */ + uint32_t sharedMemoryExecuted; + + /** + * The unique ID of the graph node that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint64_t graphNodeId; + + /** + * The shared memory limit config for the kernel. This field shows whether user has opted for a + * higher per block limit of dynamic shared memory. + */ + CUpti_FuncShmemLimitConfig shmemLimitConfig; + + /** + * The unique ID of the graph that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint32_t graphId; + + /** + * The pointer to the access policy window. The structure CUaccessPolicyWindow is + * defined in cuda.h. + */ + CUaccessPolicyWindow *pAccessPolicyWindow; +} CUpti_ActivityKernel6; + +/** + * \brief The activity record for kernel. (deprecated in CUDA 11.8) + * + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL) but is no longer generated + * by CUPTI. Kernel activities are now reported using the + * CUpti_ActivityKernel9 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL or + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + /** + * For devices with compute capability 7.0+ cacheConfig values are not updated + * in case field isSharedMemoryCarveoutRequested is set + */ + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The partitioned global caching requested for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheRequested; + + /** + * The partitioned global caching executed for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. Partitioned global caching can be + * automatically disabled if the occupancy requirement of the launch cannot + * support caching. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheExecuted; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The completed timestamp for the kernel execution, in ns. It + * represents the completion of all it's child kernels and the + * kernel itself. A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the completion time is unknown. + */ + uint64_t completed; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel is assigned a unique + * grid ID at runtime. + */ + int64_t gridId; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The timestamp when the kernel is queued up in the command buffer, in ns. + * A value of CUPTI_TIMESTAMP_UNKNOWN indicates that the queued time + * could not be collected for the kernel. This timestamp is not collected + * by default. Use API \ref cuptiActivityEnableLatencyTimestamps() to + * enable collection. + * + * Command buffer is a buffer written by CUDA driver to send commands + * like kernel launch, memory copy etc to the GPU. All launches of CUDA + * kernels are asynchronous with respect to the host, the host requests + * the launch by writing commands into the command buffer, then returns + * without checking the GPU's progress. + */ + uint64_t queued; + + /** + * The timestamp when the command buffer containing the kernel launch + * is submitted to the GPU, in ns. A value of CUPTI_TIMESTAMP_UNKNOWN + * indicates that the submitted time could not be collected for the kernel. + * This timestamp is not collected by default. Use API \ref + * cuptiActivityEnableLatencyTimestamps() to enable collection. + */ + uint64_t submitted; + + /** + * The indicates if the kernel was executed via a regular launch or via a + * single/multi device cooperative launch. \see CUpti_ActivityLaunchType + */ + uint8_t launchType; + + /** + * This indicates if CU_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT was + * updated for the kernel launch + */ + uint8_t isSharedMemoryCarveoutRequested; + + /** + * Shared memory carveout value requested for the function in percentage of + * the total resource. The value will be updated only if field + * isSharedMemoryCarveoutRequested is set. + */ + uint8_t sharedMemoryCarveoutRequested; + + /** + * Undefined. Reserved for internal use. + */ + uint8_t padding; + + /** + * Shared memory size set by the driver. + */ + uint32_t sharedMemoryExecuted; + + /** + * The unique ID of the graph node that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint64_t graphNodeId; + + /** + * The shared memory limit config for the kernel. This field shows whether user has opted for a + * higher per block limit of dynamic shared memory. + */ + CUpti_FuncShmemLimitConfig shmemLimitConfig; + + /** + * The unique ID of the graph that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint32_t graphId; + + /** + * The pointer to the access policy window. The structure CUaccessPolicyWindow is + * defined in cuda.h. + */ + CUaccessPolicyWindow *pAccessPolicyWindow; + + /** + * The ID of the HW channel on which the kernel is launched. + */ + uint32_t channelID; + + /** + * The type of the channel + */ + CUpti_ChannelType channelType; +} CUpti_ActivityKernel7; + +/** + * \brief The activity record for kernel. + * + * This activity record represents a kernel execution + * (CUPTI_ACTIVITY_KIND_KERNEL and + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL) + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_KERNEL or + * CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL. + */ + CUpti_ActivityKind kind; + + /** + * For devices with compute capability 7.0+ cacheConfig values are not updated + * in case field isSharedMemoryCarveoutRequested is set + */ + union { + uint8_t both; + struct { + /** + * The cache configuration requested by the kernel. The value is one + * of the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t requested:4; + + /** + * The cache configuration used for the kernel. The value is one of + * the CUfunc_cache enumeration values from cuda.h. + */ + uint8_t executed:4; + } config; + } cacheConfig; + + /** + * The shared memory configuration used for the kernel. The value is one of + * the CUsharedconfig enumeration values from cuda.h. + */ + uint8_t sharedMemoryConfig; + + /** + * The number of registers required for each thread executing the + * kernel. + */ + uint16_t registersPerThread; + + /** + * The partitioned global caching requested for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheRequested; + + /** + * The partitioned global caching executed for the kernel. Partitioned + * global caching is required to enable caching on certain chips, such as + * devices with compute capability 5.2. Partitioned global caching can be + * automatically disabled if the occupancy requirement of the launch cannot + * support caching. + */ + CUpti_ActivityPartitionedGlobalCacheConfig partitionedGlobalCacheExecuted; + + /** + * The start timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t start; + + /** + * The end timestamp for the kernel execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the kernel. + */ + uint64_t end; + + /** + * The completed timestamp for the kernel execution, in ns. It + * represents the completion of all it's child kernels and the + * kernel itself. A value of CUPTI_TIMESTAMP_UNKNOWN indicates that + * the completion time is unknown. + */ + uint64_t completed; + + /** + * The ID of the device where the kernel is executing. + */ + uint32_t deviceId; + + /** + * The ID of the context where the kernel is executing. + */ + uint32_t contextId; + + /** + * The ID of the stream where the kernel is executing. + */ + uint32_t streamId; + + /** + * The X-dimension grid size for the kernel. + */ + int32_t gridX; + + /** + * The Y-dimension grid size for the kernel. + */ + int32_t gridY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t gridZ; + + /** + * The X-dimension block size for the kernel. + */ + int32_t blockX; + + /** + * The Y-dimension block size for the kernel. + */ + int32_t blockY; + + /** + * The Z-dimension grid size for the kernel. + */ + int32_t blockZ; + + /** + * The static shared memory allocated for the kernel, in bytes. + */ + int32_t staticSharedMemory; + + /** + * The dynamic shared memory reserved for the kernel, in bytes. + */ + int32_t dynamicSharedMemory; + + /** + * The amount of local memory reserved for each thread, in bytes. + */ + uint32_t localMemoryPerThread; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes (deprecated in CUDA 11.8). + * Refer field localMemoryTotal_v2 + */ + uint32_t localMemoryTotal; + + /** + * The correlation ID of the kernel. Each kernel execution is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the kernel. + */ + uint32_t correlationId; + + /** + * The grid ID of the kernel. Each kernel is assigned a unique + * grid ID at runtime. + */ + int64_t gridId; + + /** + * The name of the kernel. This name is shared across all activity + * records representing the same kernel, and so should not be + * modified. + */ + const char *name; + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The timestamp when the kernel is queued up in the command buffer, in ns. + * A value of CUPTI_TIMESTAMP_UNKNOWN indicates that the queued time + * could not be collected for the kernel. This timestamp is not collected + * by default. Use API \ref cuptiActivityEnableLatencyTimestamps() to + * enable collection. + * + * Command buffer is a buffer written by CUDA driver to send commands + * like kernel launch, memory copy etc to the GPU. All launches of CUDA + * kernels are asynchronous with respect to the host, the host requests + * the launch by writing commands into the command buffer, then returns + * without checking the GPU's progress. + */ + uint64_t queued; + + /** + * The timestamp when the command buffer containing the kernel launch + * is submitted to the GPU, in ns. A value of CUPTI_TIMESTAMP_UNKNOWN + * indicates that the submitted time could not be collected for the kernel. + * This timestamp is not collected by default. Use API \ref + * cuptiActivityEnableLatencyTimestamps() to enable collection. + */ + uint64_t submitted; + + /** + * The indicates if the kernel was executed via a regular launch or via a + * single/multi device cooperative launch. \see CUpti_ActivityLaunchType + */ + uint8_t launchType; + + /** + * This indicates if CU_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT was + * updated for the kernel launch + */ + uint8_t isSharedMemoryCarveoutRequested; + + /** + * Shared memory carveout value requested for the function in percentage of + * the total resource. The value will be updated only if field + * isSharedMemoryCarveoutRequested is set. + */ + uint8_t sharedMemoryCarveoutRequested; + + /** + * Undefined. Reserved for internal use. + */ + uint8_t padding; + + /** + * Shared memory size set by the driver. + */ + uint32_t sharedMemoryExecuted; + + /** + * The unique ID of the graph node that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint64_t graphNodeId; + + /** + * The shared memory limit config for the kernel. This field shows whether user has opted for a + * higher per block limit of dynamic shared memory. + */ + CUpti_FuncShmemLimitConfig shmemLimitConfig; + + /** + * The unique ID of the graph that launched this kernel through graph launch APIs. + * This field will be 0 if the kernel is not launched through graph launch APIs. + */ + uint32_t graphId; + + /** + * The pointer to the access policy window. The structure CUaccessPolicyWindow is + * defined in cuda.h. + */ + CUaccessPolicyWindow *pAccessPolicyWindow; + + /** + * The ID of the HW channel on which the kernel is launched. + */ + uint32_t channelID; + + /** + * The type of the channel + */ + CUpti_ChannelType channelType; + + /** + * The X-dimension cluster size for the kernel. + * Field is valid for devices with compute capability 9.0 and higher + */ + uint32_t clusterX; + + /** + * The Y-dimension cluster size for the kernel. + * Field is valid for devices with compute capability 9.0 and higher + */ + uint32_t clusterY; + + /** + * The Z-dimension cluster size for the kernel. + * Field is valid for devices with compute capability 9.0 and higher + */ + uint32_t clusterZ; + + /** + * The cluster scheduling policy for the kernel. Refer CUclusterSchedulingPolicy + * Field is valid for devices with compute capability 9.0 and higher + */ + uint32_t clusterSchedulingPolicy; + + /** + * The total amount of local memory reserved for the kernel, in + * bytes. + */ + uint64_t localMemoryTotal_v2; +} CUpti_ActivityKernel8; + +/** + * \brief The activity record for memory copies. (deprecated) + * + * This activity record represents a memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the memory copy. + */ + uint32_t correlationId; + + /** + * The runtime correlation ID of the memory copy. Each memory copy + * is assigned a unique runtime correlation ID that is identical to + * the correlation ID in the runtime API activity record that + * launched the memory copy. + */ + uint32_t runtimeCorrelationId; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; +} CUpti_ActivityMemcpy; + +/** + * \brief The activity record for memory copies. (deprecated in CUDA 11.1) + * + * This activity record represents a memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the memory copy. + */ + uint32_t correlationId; + + /** + * The runtime correlation ID of the memory copy. Each memory copy + * is assigned a unique runtime correlation ID that is identical to + * the correlation ID in the runtime API activity record that + * launched the memory copy. + */ + uint32_t runtimeCorrelationId; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint64_t graphNodeId; +} CUpti_ActivityMemcpy3; + +/** + * \brief The activity record for memory copies. (deprecated in CUDA 11.6) + * + * This activity record represents a memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the memory copy. + */ + uint32_t correlationId; + + /** + * The runtime correlation ID of the memory copy. Each memory copy + * is assigned a unique runtime correlation ID that is identical to + * the correlation ID in the runtime API activity record that + * launched the memory copy. + */ + uint32_t runtimeCorrelationId; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint64_t graphNodeId; + + /** + * The unique ID of the graph that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint32_t graphId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t padding; +} CUpti_ActivityMemcpy4; + +/** + * \brief The activity record for peer-to-peer memory copies. + * + * This activity record represents a peer-to-peer memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY2) but is no longer generated + * by CUPTI. Peer-to-peer memory copy activities are now reported using the + * CUpti_ActivityMemcpyPtoP2 activity record.. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY2. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see + * CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The ID of the device where memory is being copied from. + */ + uint32_t srcDeviceId; + + /** + * The ID of the context owning the memory being copied from. + */ + uint32_t srcContextId; + + /** + * The ID of the device where memory is being copied to. + */ + uint32_t dstDeviceId; + + /** + * The ID of the context owning the memory being copied to. + */ + uint32_t dstContextId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory copy. + */ + uint32_t correlationId; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; +} CUpti_ActivityMemcpyPtoP; + +typedef CUpti_ActivityMemcpyPtoP CUpti_ActivityMemcpy2; + +/** + * \brief The activity record for peer-to-peer memory copies. + * (deprecated in CUDA 11.1) + * + * This activity record represents a peer-to-peer memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY2). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY2. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see + * CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The ID of the device where memory is being copied from. + */ + uint32_t srcDeviceId; + + /** + * The ID of the context owning the memory being copied from. + */ + uint32_t srcContextId; + + /** + * The ID of the device where memory is being copied to. + */ + uint32_t dstDeviceId; + + /** + * The ID of the context owning the memory being copied to. + */ + uint32_t dstContextId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory copy. + */ + uint32_t correlationId; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed the memcpy through graph launch. + * This field will be 0 if memcpy is not done using graph launch. + */ + uint64_t graphNodeId; +} CUpti_ActivityMemcpyPtoP2; + +/** + * \brief The activity record for peer-to-peer memory copies. + * (deprecated in CUDA 11.6) + * + * This activity record represents a peer-to-peer memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY2). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY2. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see + * CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The ID of the device where memory is being copied from. + */ + uint32_t srcDeviceId; + + /** + * The ID of the context owning the memory being copied from. + */ + uint32_t srcContextId; + + /** + * The ID of the device where memory is being copied to. + */ + uint32_t dstDeviceId; + + /** + * The ID of the context owning the memory being copied to. + */ + uint32_t dstContextId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory copy. + */ + uint32_t correlationId; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed the memcpy through graph launch. + * This field will be 0 if memcpy is not done using graph launch. + */ + uint64_t graphNodeId; + + /** + * The unique ID of the graph that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint32_t graphId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t padding; +} CUpti_ActivityMemcpyPtoP3; + +/** + * \brief The activity record for memset. (deprecated) + * + * This activity record represents a memory set operation + * (CUPTI_ACTIVITY_KIND_MEMSET). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMSET. + */ + CUpti_ActivityKind kind; + + /** + * The value being assigned to memory by the memory set. + */ + uint32_t value; + + /** + * The number of bytes being set by the memory set. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory set, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory set. + */ + uint64_t start; + + /** + * The end timestamp for the memory set, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory set. + */ + uint64_t end; + + /** + * The ID of the device where the memory set is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory set is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory set is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory set. Each memory set is assigned + * a unique correlation ID that is identical to the correlation ID + * in the driver API activity record that launched the memory set. + */ + uint32_t correlationId; + + /** + * The flags associated with the memset. \see CUpti_ActivityFlag + */ + uint16_t flags; + + /** + * The memory kind of the memory set \see CUpti_ActivityMemoryKind + */ + uint16_t memoryKind; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; +} CUpti_ActivityMemset; + +/** + * \brief The activity record for memset. (deprecated in CUDA 11.1) + * + * This activity record represents a memory set operation + * (CUPTI_ACTIVITY_KIND_MEMSET). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMSET. + */ + CUpti_ActivityKind kind; + + /** + * The value being assigned to memory by the memory set. + */ + uint32_t value; + + /** + * The number of bytes being set by the memory set. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory set, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory set. + */ + uint64_t start; + + /** + * The end timestamp for the memory set, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory set. + */ + uint64_t end; + + /** + * The ID of the device where the memory set is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory set is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory set is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory set. Each memory set is assigned + * a unique correlation ID that is identical to the correlation ID + * in the driver API activity record that launched the memory set. + */ + uint32_t correlationId; + + /** + * The flags associated with the memset. \see CUpti_ActivityFlag + */ + uint16_t flags; + + /** + * The memory kind of the memory set \see CUpti_ActivityMemoryKind + */ + uint16_t memoryKind; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed this memset through graph launch. + * This field will be 0 if the memset is not executed through graph launch. + */ + uint64_t graphNodeId; +} CUpti_ActivityMemset2; + +/** + * \brief The activity record for memset. (deprecated in CUDA 11.6) + * + * This activity record represents a memory set operation + * (CUPTI_ACTIVITY_KIND_MEMSET). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMSET. + */ + CUpti_ActivityKind kind; + + /** + * The value being assigned to memory by the memory set. + */ + uint32_t value; + + /** + * The number of bytes being set by the memory set. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory set, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory set. + */ + uint64_t start; + + /** + * The end timestamp for the memory set, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory set. + */ + uint64_t end; + + /** + * The ID of the device where the memory set is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory set is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory set is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory set. Each memory set is assigned + * a unique correlation ID that is identical to the correlation ID + * in the driver API activity record that launched the memory set. + */ + uint32_t correlationId; + + /** + * The flags associated with the memset. \see CUpti_ActivityFlag + */ + uint16_t flags; + + /** + * The memory kind of the memory set \see CUpti_ActivityMemoryKind + */ + uint16_t memoryKind; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed this memset through graph launch. + * This field will be 0 if the memset is not executed through graph launch. + */ + uint64_t graphNodeId; + + /** + * The unique ID of the graph that executed this memset through graph launch. + * This field will be 0 if the memset is not executed through graph launch. + */ + uint32_t graphId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t padding; +} CUpti_ActivityMemset3; + +/** + * \brief The activity record for memory. + * + * This activity record represents a memory allocation and free operation + * (CUPTI_ACTIVITY_KIND_MEMORY2). + * This activity record provides separate records for memory allocation and + * memory release operations. + * This allows to correlate the corresponding driver and runtime API + * activity record with the memory operation. + * + * Note: This activity record is an upgrade over \ref CUpti_ActivityMemory + * enabled using the kind \ref CUPTI_ACTIVITY_KIND_MEMORY. + * \ref CUpti_ActivityMemory provides a single record for the memory + * allocation and memory release operations. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMORY2 + */ + CUpti_ActivityKind kind; + + /** + * The memory operation requested by the user, \ref CUpti_ActivityMemoryOperationType. + */ + CUpti_ActivityMemoryOperationType memoryOperationType; + + /** + * The memory kind requested by the user, \ref CUpti_ActivityMemoryKind. + */ + CUpti_ActivityMemoryKind memoryKind; + + /** + * The correlation ID of the memory operation. Each memory operation is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory operation. + */ + uint32_t correlationId; + + /** + * The virtual address of the allocation. + */ + uint64_t address; + + /** + * The number of bytes of memory allocated. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory operation, in ns. + */ + uint64_t timestamp; + + /** + * The program counter of the memory operation. + */ + uint64_t PC; + + /** + * The ID of the process to which this record belongs to. + */ + uint32_t processId; + + /** + * The ID of the device where the memory operation is taking place. + */ + uint32_t deviceId; + + /** + * The ID of the context. If context is NULL, \p contextId is set to CUPTI_INVALID_CONTEXT_ID. + */ + uint32_t contextId; + + /** + * The ID of the stream. If memory operation is not async, \p streamId is set to CUPTI_INVALID_STREAM_ID. + */ + uint32_t streamId; + + /** + * Variable name. This name is shared across all activity + * records representing the same symbol, and so should not be + * modified. + */ + const char* name; + + /** + * \p isAsync is set if memory operation happens through async memory APIs. + */ + uint32_t isAsync; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad1; +#endif + + /** + * The memory pool configuration used for the memory operations. + */ + struct { + /** + * The type of the memory pool, \ref CUpti_ActivityMemoryPoolType + */ + CUpti_ActivityMemoryPoolType memoryPoolType; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad2; +#endif + + /** + * The base address of the memory pool. + */ + uint64_t address; + + /** + * The release threshold of the memory pool in bytes. \p releaseThreshold is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t releaseThreshold; + + /** + * The size of the memory pool in bytes and the processID of the memory pool. + * \p size is valid if \p memoryPoolType is + * CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + * \p processId is valid if \p memoryPoolType is + * CUPTI_ACTIVITY_MEMORY_POOL_TYPE_IMPORTED, \ref CUpti_ActivityMemoryPoolType. + */ + union { + uint64_t size; + uint64_t processId; + } pool; + } memoryPoolConfig; + +} CUpti_ActivityMemory2; + +/** + * \brief The activity record for memory. + * + * This activity record represents a memory allocation and free operation + * (CUPTI_ACTIVITY_KIND_MEMORY2). + * This activity record provides separate records for memory allocation and + * memory release operations. + * This allows to correlate the corresponding driver and runtime API + * activity record with the memory operation. + * + * Note: This activity record is an upgrade over \ref CUpti_ActivityMemory2 + * enabled using the kind \ref CUPTI_ACTIVITY_KIND_MEMORY. + * \ref CUpti_ActivityMemory provides a single record for the memory + * allocation and memory release operations. + */ + +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMORY2 + */ + CUpti_ActivityKind kind; + + /** + * The memory operation requested by the user, \ref CUpti_ActivityMemoryOperationType. + */ + CUpti_ActivityMemoryOperationType memoryOperationType; + + /** + * The memory kind requested by the user, \ref CUpti_ActivityMemoryKind. + */ + CUpti_ActivityMemoryKind memoryKind; + + /** + * The correlation ID of the memory operation. Each memory operation is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory operation. + */ + uint32_t correlationId; + + /** + * The virtual address of the allocation. + */ + uint64_t address; + + /** + * The number of bytes of memory allocated. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory operation, in ns. + */ + uint64_t timestamp; + + /** + * The program counter of the memory operation. + */ + uint64_t PC; + + /** + * The ID of the process to which this record belongs to. + */ + uint32_t processId; + + /** + * The ID of the device where the memory operation is taking place. + */ + uint32_t deviceId; + + /** + * The ID of the context. If context is NULL, \p contextId is set to CUPTI_INVALID_CONTEXT_ID. + */ + uint32_t contextId; + + /** + * The ID of the stream. If memory operation is not async, \p streamId is set to CUPTI_INVALID_STREAM_ID. + */ + uint32_t streamId; + + /** + * Variable name. This name is shared across all activity + * records representing the same symbol, and so should not be + * modified. + */ + const char* name; + + /** + * \p isAsync is set if memory operation happens through async memory APIs. + */ + uint32_t isAsync; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad1; +#endif + + /** + * The memory pool configuration used for the memory operations. + */ + struct PACKED_ALIGNMENT { + /** + * The type of the memory pool, \ref CUpti_ActivityMemoryPoolType + */ + CUpti_ActivityMemoryPoolType memoryPoolType; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad2; +#endif + + /** + * The base address of the memory pool. + */ + uint64_t address; + + /** + * The release threshold of the memory pool in bytes. \p releaseThreshold is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t releaseThreshold; + + /** + * The size of memory pool in bytes and the processId of the memory pools + * \p size is valid if \p memoryPoolType is + * CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + * \p processId is valid if \p memoryPoolType is + * CUPTI_ACTIVITY_MEMORY_POOL_TYPE_IMPORTED, \ref CUpti_ActivityMemoryPoolType + */ + union { + uint64_t size; + uint64_t processId; + } pool; + + /** + * The utilized size of the memory pool. \p utilizedSize is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t utilizedSize; + } memoryPoolConfig; + +} CUpti_ActivityMemory3; + +/** + * \brief The activity record for memory pool. + * + * This activity record represents a memory pool creation, destruction and + * trimming (CUPTI_ACTIVITY_KIND_MEMORY_POOL). + * This activity record provides separate records for memory pool creation, + * destruction and trimming operations. + * This allows to correlate the corresponding driver and runtime API + * activity record with the memory pool operation. + * + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMORY_POOL + */ + CUpti_ActivityKind kind; + + /** + * The memory operation requested by the user, \ref CUpti_ActivityMemoryPoolOperationType. + */ + CUpti_ActivityMemoryPoolOperationType memoryPoolOperationType; + + /** + * The type of the memory pool, \ref CUpti_ActivityMemoryPoolType + */ + CUpti_ActivityMemoryPoolType memoryPoolType; + + /** + * The correlation ID of the memory pool operation. Each memory pool + * operation is assigned a unique correlation ID that is identical to the + * correlation ID in the driver and runtime API activity record that + * launched the memory operation. + */ + uint32_t correlationId; + + /** + * The ID of the process to which this record belongs to. + */ + uint32_t processId; + + /** + * The ID of the device where the memory pool is created. + */ + uint32_t deviceId; + + /** + * The minimum bytes to keep of the memory pool. \p minBytesToKeep is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_OPERATION_TYPE_TRIMMED, + * \ref CUpti_ActivityMemoryPoolOperationType + */ + size_t minBytesToKeep; + +#ifndef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The virtual address of the allocation. + */ + uint64_t address; + + /** + * The size of the memory pool operation in bytes. \p size is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t size; + + /** + * The release threshold of the memory pool. \p releaseThreshold is + * valid for CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL, \ref CUpti_ActivityMemoryPoolType. + */ + uint64_t releaseThreshold; + + /** + * The start timestamp for the memory operation, in ns. + */ + uint64_t timestamp; +} CUpti_ActivityMemoryPool; + +/** + * \brief The activity record providing a marker which is an + * instantaneous point in time. (deprecated in CUDA 8.0) + * + * The marker is specified with a descriptive name and unique id + * (CUPTI_ACTIVITY_KIND_MARKER). + * Marker activity is now reported using the + * CUpti_ActivityMarker2 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MARKER. + */ + CUpti_ActivityKind kind; + + /** + * The flags associated with the marker. \see CUpti_ActivityFlag + */ + CUpti_ActivityFlag flags; + + /** + * The timestamp for the marker, in ns. A value of 0 indicates that + * timestamp information could not be collected for the marker. + */ + uint64_t timestamp; + + /** + * The marker ID. + */ + uint32_t id; + + /** + * The kind of activity object associated with this marker. + */ + CUpti_ActivityObjectKind objectKind; + + /** + * The identifier for the activity object associated with this + * marker. 'objectKind' indicates which ID is valid for this record. + */ + CUpti_ActivityObjectKindId objectId; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * The marker name for an instantaneous or start marker. This will + * be NULL for an end marker. + */ + const char *name; + +} CUpti_ActivityMarker; + +/** + * \brief The activity record for source-level global + * access. (deprecated) + * + * This activity records the locations of the global + * accesses in the source (CUPTI_ACTIVITY_KIND_GLOBAL_ACCESS). + * Global access activities are now reported using the + * CUpti_ActivityGlobalAccess3 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_GLOBAL_ACCESS. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this global access. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * The pc offset for the access. + */ + uint32_t pcOffset; + + /** + * The number of times this instruction was executed per warp. It will be incremented + * when at least one of thread among warp is active with predicate and condition code + * evaluating to true. + */ + uint32_t executed; + + /** + * This increments each time when this instruction is executed by number + * of threads that executed this instruction with predicate and condition code evaluating to true. + */ + uint64_t threadsExecuted; + + /** + * The total number of 32 bytes transactions to L2 cache generated by this access + */ + uint64_t l2_transactions; +} CUpti_ActivityGlobalAccess; + +/** + * \brief The activity record for source-level global + * access. (deprecated in CUDA 9.0) + * + * This activity records the locations of the global + * accesses in the source (CUPTI_ACTIVITY_KIND_GLOBAL_ACCESS). + * Global access activities are now reported using the + * CUpti_ActivityGlobalAccess3 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_GLOBAL_ACCESS. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this global access. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * The pc offset for the access. + */ + uint32_t pcOffset; + + /** + * This increments each time when this instruction is executed by number + * of threads that executed this instruction with predicate and condition code evaluating to true. + */ + uint64_t threadsExecuted; + + /** + * The total number of 32 bytes transactions to L2 cache generated by this access + */ + uint64_t l2_transactions; + + /** + * The minimum number of L2 transactions possible based on the access pattern. + */ + uint64_t theoreticalL2Transactions; + + /** + * The number of times this instruction was executed per warp. It will be incremented + * when at least one of thread among warp is active with predicate and condition code + * evaluating to true. + */ + uint32_t executed; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityGlobalAccess2; + +/** + * \brief The activity record for source level result + * branch. (deprecated) + * + * This activity record the locations of the branches in the + * source (CUPTI_ACTIVITY_KIND_BRANCH). + * Branch activities are now reported using the + * CUpti_ActivityBranch2 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_BRANCH. + */ + CUpti_ActivityKind kind; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * The pc offset for the branch. + */ + uint32_t pcOffset; + + /** + * The number of times this instruction was executed per warp. It will be incremented + * regardless of predicate or condition code. + */ + uint32_t executed; + + /** + * Number of times this branch diverged + */ + uint32_t diverged; + + /** + * This increments each time when this instruction is executed by number + * of threads that executed this instruction + */ + uint64_t threadsExecuted; +} CUpti_ActivityBranch; + +/** + * \brief The activity record for PC sampling. (deprecated in CUDA 8.0) + * + * This activity records information obtained by sampling PC + * (CUPTI_ACTIVITY_KIND_PC_SAMPLING). + * PC sampling activities are now reported using the + * CUpti_ActivityPCSampling2 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_PC_SAMPLING. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this instruction. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * The pc offset for the instruction. + */ + uint32_t pcOffset; + + /** + * Number of times the PC was sampled with the stallReason in the record. + * The same PC can be sampled with different stall reasons. + */ + uint32_t samples; + + /** + * Current stall reason. Includes one of the reasons from + * \ref CUpti_ActivityPCSamplingStallReason + */ + CUpti_ActivityPCSamplingStallReason stallReason; +} CUpti_ActivityPCSampling; + +/** + * \brief The activity record for PC sampling. (deprecated in CUDA 9.0) + * + * This activity records information obtained by sampling PC + * (CUPTI_ACTIVITY_KIND_PC_SAMPLING). + * PC sampling activities are now reported using the + * CUpti_ActivityPCSampling3 activity record. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_PC_SAMPLING. + */ + CUpti_ActivityKind kind; + + /** + * The properties of this instruction. + */ + CUpti_ActivityFlag flags; + + /** + * The ID for source locator. + */ + uint32_t sourceLocatorId; + + /** + * The correlation ID of the kernel to which this result is associated. + */ + uint32_t correlationId; + + /** + * Correlation ID with global/device function name + */ + uint32_t functionId; + + /** + * The pc offset for the instruction. + */ + uint32_t pcOffset; + + /** + * Number of times the PC was sampled with the stallReason in the record. + * These samples indicate that no instruction was issued in that cycle from + * the warp scheduler from where the warp was sampled. + * Field is valid for devices with compute capability 6.0 and higher + */ + uint32_t latencySamples; + + /** + * Number of times the PC was sampled with the stallReason in the record. + * The same PC can be sampled with different stall reasons. The count includes + * latencySamples. + */ + uint32_t samples; + + /** + * Current stall reason. Includes one of the reasons from + * \ref CUpti_ActivityPCSamplingStallReason + */ + CUpti_ActivityPCSamplingStallReason stallReason; + + uint32_t pad; +} CUpti_ActivityPCSampling2; + +/** + * \brief The activity record for Unified Memory counters (deprecated in CUDA 7.0) + * + * This activity record represents a Unified Memory counter + * (CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER + */ + CUpti_ActivityKind kind; + + /** + * The Unified Memory counter kind. See \ref CUpti_ActivityUnifiedMemoryCounterKind + */ + CUpti_ActivityUnifiedMemoryCounterKind counterKind; + + /** + * Scope of the Unified Memory counter. See \ref CUpti_ActivityUnifiedMemoryCounterScope + */ + CUpti_ActivityUnifiedMemoryCounterScope scope; + + /** + * The ID of the device involved in the memory transfer operation. + * It is not relevant if the scope of the counter is global (all devices). + */ + uint32_t deviceId; + + /** + * Value of the counter + * + */ + uint64_t value; + + /** + * The timestamp when this sample was retrieved, in ns. A value of 0 + * indicates that timestamp information could not be collected + */ + uint64_t timestamp; + + /** + * The ID of the process to which this record belongs to. In case of + * global scope, processId is undefined. + */ + uint32_t processId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityUnifiedMemoryCounter; + +/** + * \brief The activity record for Unified Memory counters (deprecated in 12.8) + * + * This activity record represents a Unified Memory counter + * (CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER). + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER + */ + CUpti_ActivityKind kind; + + /** + * The Unified Memory counter kind + */ + CUpti_ActivityUnifiedMemoryCounterKind counterKind; + + /** + * Value of the counter + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD, + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH, + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THREASHING and + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP, it is the size of the + * memory region in bytes. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT, it + * is the number of page fault groups for the same page. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT, + * it is the program counter for the instruction that caused fault. + */ + uint64_t value; + + /** + * The start timestamp of the counter, in ns. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD and + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH, timestamp is + * captured when activity starts on GPU. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT and + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT, timestamp is + * captured when CUDA driver started processing the fault. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING, timestamp + * is captured when CUDA driver detected thrashing of memory region. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING, + * timestamp is captured when throttling operation was started by CUDA driver. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP, + * timestamp is captured when CUDA driver has pushed all required operations + * to the processor specified by dstId. + */ + uint64_t start; + + /** + * The end timestamp of the counter, in ns. + * Ignore this field if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD and + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_DTOH, timestamp is + * captured when activity finishes on GPU. + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT, timestamp is + * captured when CUDA driver queues the replay of faulting memory accesses on the GPU + * For counterKind CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING, timestamp + * is captured when throttling operation was finished by CUDA driver + */ + uint64_t end; + + /** + * This is the virtual base address of the page/s being transferred. For cpu and + * gpu faults, the virtual address for the page that faulted. + */ + uint64_t address; + + /** + * The ID of the source CPU/device involved in the memory transfer, page fault, thrashing, + * throttling or remote map operation. For counterKind + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING, it is a bitwise ORing of the + * device IDs fighting for the memory region. Ignore this field if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT + */ + uint32_t srcId; + + /** + * The ID of the destination CPU/device involved in the memory transfer or remote map + * operation. Ignore this field if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_CPU_PAGE_FAULT_COUNT or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING + */ + uint32_t dstId; + + /** + * The ID of the stream causing the transfer. + * This value of this field is invalid. + */ + uint32_t streamId; + + /** + * The ID of the process to which this record belongs to. + */ + uint32_t processId; + + /** + * The flags associated with this record. See enums \ref CUpti_ActivityUnifiedMemoryAccessType + * if counterKind is CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_GPU_PAGE_FAULT + * and \ref CUpti_ActivityUnifiedMemoryMigrationCause if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_BYTES_TRANSFER_HTOD + * and \ref CUpti_ActivityUnifiedMemoryRemoteMapCause if counterKind is + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_REMOTE_MAP and \ref CUpti_ActivityFlag + * if counterKind is CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THRASHING or + * CUPTI_ACTIVITY_UNIFIED_MEMORY_COUNTER_KIND_THROTTLING + */ + uint32_t flags; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityUnifiedMemoryCounter2; + +/** +* \brief NVLink information. (deprecated in CUDA 9.0) +* +* This structure gives capabilities of each logical NVLink connection between two devices, +* gpu<->gpu or gpu<->CPU which can be used to understand the topology. +* NVLink information are now reported using the +* CUpti_ActivityNvLink2 activity record. +*/ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_NVLINK. + */ + CUpti_ActivityKind kind; + + /** + * NVLink version. + */ + uint32_t nvlinkVersion; + + /** + * Type of device 0 \ref CUpti_DevType + */ + CUpti_DevType typeDev0; + + /** + * Type of device 1 \ref CUpti_DevType + */ + CUpti_DevType typeDev1; + + /** + * If typeDev0 is CUPTI_DEV_TYPE_GPU, UUID for device 0. \ref CUpti_ActivityDevice5. + * If typeDev0 is CUPTI_DEV_TYPE_NPU, struct npu for NPU. + */ + union { + CUuuid uuidDev; + struct { + /** + * Index of the NPU. First index will always be zero. + */ + uint32_t index; + + /** + * Domain ID of NPU. On Linux, this can be queried using lspci. + */ + uint32_t domainId; + } npu; + } idDev0; + + /** + * If typeDev1 is CUPTI_DEV_TYPE_GPU, UUID for device 1. \ref CUpti_ActivityDevice5. + * If typeDev1 is CUPTI_DEV_TYPE_NPU, struct npu for NPU. + */ + union { + CUuuid uuidDev; + struct { + /** + * Index of the NPU. First index will always be zero. + */ + uint32_t index; + + /** + * Domain ID of NPU. On Linux, this can be queried using lspci. + */ + uint32_t domainId; + } npu; + } idDev1; + + /** + * Flag gives capabilities of the link \see CUpti_LinkFlag + */ + uint32_t flag; + + /** + * Number of physical NVLinks present between two devices. + */ + uint32_t physicalNvLinkCount; + + /** + * Port numbers for maximum 4 NVLinks connected to device 0. + * If typeDev0 is CUPTI_DEV_TYPE_NPU, ignore this field. + * In case of invalid/unknown port number, this field will be set + * to value CUPTI_NVLINK_INVALID_PORT. + * This will be used to correlate the metric values to individual + * physical link and attribute traffic to the logical NVLink in + * the topology. + */ + int8_t portDev0[4]; + + /** + * Port numbers for maximum 4 NVLinks connected to device 1. + * If typeDev1 is CUPTI_DEV_TYPE_NPU, ignore this field. + * In case of invalid/unknown port number, this field will be set + * to value CUPTI_NVLINK_INVALID_PORT. + * This will be used to correlate the metric values to individual + * physical link and attribute traffic to the logical NVLink in + * the topology. + */ + int8_t portDev1[4]; + + /** + * Bandwidth of NVLink in kbytes/sec + */ + uint64_t bandwidth; +} CUpti_ActivityNvLink; + +/** +* \brief NVLink information. (deprecated in CUDA 10.0) +* +* This structure gives capabilities of each logical NVLink connection between two devices, +* gpu<->gpu or gpu<->CPU which can be used to understand the topology. +* NvLink information are now reported using the +* CUpti_ActivityNvLink4 activity record. +*/ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_NVLINK. + */ + CUpti_ActivityKind kind; + + /** + * NvLink version. + */ + uint32_t nvlinkVersion; + + /** + * Type of device 0 \ref CUpti_DevType + */ + CUpti_DevType typeDev0; + + /** + * Type of device 1 \ref CUpti_DevType + */ + CUpti_DevType typeDev1; + + /** + * If typeDev0 is CUPTI_DEV_TYPE_GPU, UUID for device 0. \ref CUpti_ActivityDevice5. + * If typeDev0 is CUPTI_DEV_TYPE_NPU, struct npu for NPU. + */ + union { + CUuuid uuidDev; + struct { + /** + * Index of the NPU. First index will always be zero. + */ + uint32_t index; + + /** + * Domain ID of NPU. On Linux, this can be queried using lspci. + */ + uint32_t domainId; + } npu; + } idDev0; + + /** + * If typeDev1 is CUPTI_DEV_TYPE_GPU, UUID for device 1. \ref CUpti_ActivityDevice5. + * If typeDev1 is CUPTI_DEV_TYPE_NPU, struct npu for NPU. + */ + union { + CUuuid uuidDev; + struct { + /** + * Index of the NPU. First index will always be zero. + */ + uint32_t index; + + /** + * Domain ID of NPU. On Linux, this can be queried using lspci. + */ + uint32_t domainId; + } npu; + } idDev1; + + /** + * Flag gives capabilities of the link \see CUpti_LinkFlag + */ + uint32_t flag; + + /** + * Number of physical NVLinks present between two devices. + */ + uint32_t physicalNvLinkCount; + + /** + * Port numbers for maximum 16 NVLinks connected to device 0. + * If typeDev0 is CUPTI_DEV_TYPE_NPU, ignore this field. + * In case of invalid/unknown port number, this field will be set + * to value CUPTI_NVLINK_INVALID_PORT. + * This will be used to correlate the metric values to individual + * physical link and attribute traffic to the logical NVLink in + * the topology. + */ + int8_t portDev0[CUPTI_MAX_NVLINK_PORTS]; + + /** + * Port numbers for maximum 16 NVLinks connected to device 1. + * If typeDev1 is CUPTI_DEV_TYPE_NPU, ignore this field. + * In case of invalid/unknown port number, this field will be set + * to value CUPTI_NVLINK_INVALID_PORT. + * This will be used to correlate the metric values to individual + * physical link and attribute traffic to the logical NVLink in + * the topology. + */ + int8_t portDev1[CUPTI_MAX_NVLINK_PORTS]; + + /** + * Bandwidth of NVLink in kbytes/sec + */ + uint64_t bandwidth; +} CUpti_ActivityNvLink2; + +/** +* \brief NVLink information. +* +* This structure gives capabilities of each logical NVLink connection between two devices, +* gpu<->gpu or gpu<->CPU which can be used to understand the topology. +* NvLink information are now reported using the +* CUpti_ActivityNvLink4 activity record. +*/ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_NVLINK. + */ + CUpti_ActivityKind kind; + /** + * NvLink version. + */ + uint32_t nvlinkVersion; + + /** + * Type of device 0 \ref CUpti_DevType + */ + CUpti_DevType typeDev0; + + /** + * Type of device 1 \ref CUpti_DevType + */ + CUpti_DevType typeDev1; + + /** + * If typeDev0 is CUPTI_DEV_TYPE_GPU, UUID for device 0. \ref CUpti_ActivityDevice5. + * If typeDev0 is CUPTI_DEV_TYPE_NPU, struct npu for NPU. + */ + union { + CUuuid uuidDev; + struct { + /** + * Index of the NPU. First index will always be zero. + */ + uint32_t index; + + /** + * Domain ID of NPU. On Linux, this can be queried using lspci. + */ + uint32_t domainId; + } npu; + } idDev0; + + /** + * If typeDev1 is CUPTI_DEV_TYPE_GPU, UUID for device 1. \ref CUpti_ActivityDevice5. + * If typeDev1 is CUPTI_DEV_TYPE_NPU, struct npu for NPU. + */ + union { + CUuuid uuidDev; + struct { + /** + * Index of the NPU. First index will always be zero. + */ + uint32_t index; + + /** + * Domain ID of NPU. On Linux, this can be queried using lspci. + */ + uint32_t domainId; + } npu; + } idDev1; + + /** + * Flag gives capabilities of the link \see CUpti_LinkFlag + */ + uint32_t flag; + + /** + * Number of physical NVLinks present between two devices. + */ + uint32_t physicalNvLinkCount; + + /** + * Port numbers for maximum 16 NVLinks connected to device 0. + * If typeDev0 is CUPTI_DEV_TYPE_NPU, ignore this field. + * In case of invalid/unknown port number, this field will be set + * to value CUPTI_NVLINK_INVALID_PORT. + * This will be used to correlate the metric values to individual + * physical link and attribute traffic to the logical NVLink in + * the topology. + */ + int8_t portDev0[CUPTI_MAX_NVLINK_PORTS]; + + /** + * Port numbers for maximum 16 NVLinks connected to device 1. + * If typeDev1 is CUPTI_DEV_TYPE_NPU, ignore this field. + * In case of invalid/unknown port number, this field will be set + * to value CUPTI_NVLINK_INVALID_PORT. + * This will be used to correlate the metric values to individual + * physical link and attribute traffic to the logical NVLink in + * the topology. + */ + int8_t portDev1[CUPTI_MAX_NVLINK_PORTS]; + + /** + * Bandwidth of NVLink in kbytes/sec + */ + uint64_t bandwidth; + + /** + * NVSwitch is connected as an intermediate node. + */ + uint8_t nvswitchConnected; + + /** + * Undefined. reserved for internal use + */ + uint8_t pad[7]; +} CUpti_ActivityNvLink3; + +/** + * \brief The activity record for trace of graph execution. + * + * This activity record represents execution for a graph without giving visibility + * about the execution of its nodes. This is intended to reduce overheads in tracing + * each node. The activity kind is CUPTI_ACTIVITY_KIND_GRAPH_TRACE + * Graph trace activity is now reported using CUpti_ActivityGraphTrace2 record. + */ +typedef struct { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_GRAPH_TRACE + */ + CUpti_ActivityKind kind; + + /** + * The correlation ID of the graph launch. Each graph launch is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the graph. + */ + uint32_t correlationId; + + /** + * The start timestamp for the graph execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the graph. + */ + uint64_t start; + + /** + * The end timestamp for the graph execution, in ns. A value of 0 + * for both the start and end timestamps indicates that timestamp + * information could not be collected for the graph. + */ + uint64_t end; + + /** + * The ID of the device where the graph execution is occurring. + */ + uint32_t deviceId; + + /** + * The unique ID of the graph that is launched. + */ + uint32_t graphId; + + /** + * The ID of the context where the graph is being launched. + */ + uint32_t contextId; + + /** + * The ID of the stream where the graph is being launched. + */ + uint32_t streamId; + + /** + * This field is reserved for internal use + */ + void *reserved; +} CUpti_ActivityGraphTrace; + +/** + * \brief The activity record for a context. + * + * This activity record represents information about a context + * (CUPTI_ACTIVITY_KIND_CONTEXT). + * Context activity is now reported using CUpti_ActivityContext3 record + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_CONTEXT. + */ + CUpti_ActivityKind kind; + + /** + * The context ID. + */ + uint32_t contextId; + + /** + * The device ID. + */ + uint32_t deviceId; + + /** + * The compute API kind. \see CUpti_ActivityComputeApiKind + */ + uint16_t computeApiKind; + + /** + * The ID for the NULL stream in this context + */ + uint16_t nullStreamId; +} CUpti_ActivityContext; + +/** + * \brief The activity record for a context. + * + * This activity record represents information about a context + * (CUPTI_ACTIVITY_KIND_CONTEXT). + * Context activity is now reported using CUpti_ActivityContext3 record + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_CONTEXT. + */ + CUpti_ActivityKind kind; + + /** + * The context ID. + */ + uint32_t contextId; + + /** + * The device ID. + */ + uint32_t deviceId; + + /** + * The compute API kind. \see CUpti_ActivityComputeApiKind + */ + uint16_t computeApiKind; + + /** + * The ID for the NULL stream in this context + */ + uint16_t nullStreamId; + + /** + * The ID of the parent context. It would be 0 if + * context does not have parent + */ + uint32_t parentContextId; + + /** + * This field indicates whether the context is a green context + */ + uint8_t isGreenContext; + + uint8_t padding; + + /** + * Number of multiprocessors assigned to the green context + * Invalid if the field 'isGreenContext' is 0 + */ + uint16_t numMultiprocessors; +} CUpti_ActivityContext2; + +/** + * \brief The activity record for JIT operations. + * This activity represents the JIT operations (compile, load, store) of a CUmodule + * from the Compute Cache. + * Gives the exact hashed path of where the cached module is loaded from, + * or where the module will be stored after Just-In-Time (JIT) compilation. + * + * JIT activity is now reported using CUpti_ActivityJit2 record + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind must be CUPTI_ACTIVITY_KIND_JIT. + */ + CUpti_ActivityKind kind; + + /** + * The JIT entry type. + */ + CUpti_ActivityJitEntryType jitEntryType; + + /** + * The JIT operation type. + */ + CUpti_ActivityJitOperationType jitOperationType; + + /** + * The device ID. + */ + uint32_t deviceId; + + /** + * The start timestamp for the JIT operation, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the JIT operation. + */ + uint64_t start; + + /** + * The end timestamp for the JIT operation, in ns. A value of 0 for both + * the start and end timestamps indicates that timestamp information + * could not be collected for the JIT operation. + */ + uint64_t end; + + /** + * The correlation ID of the JIT operation to which + * records belong to. Each JIT operation is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver or runtime API activity record that + * launched the JIT operation. + */ + uint32_t correlationId; + + /** + * Internal use. + */ + uint32_t padding; + + /** + * The correlation ID to correlate JIT compilation, load and store operations. + * Each JIT compilation unit is assigned a unique correlation ID + * at the time of the JIT compilation. This correlation id can be used + * to find the matching JIT cache load/store records. + */ + uint64_t jitOperationCorrelationId; + + /** + * The size of compute cache. + */ + uint64_t cacheSize; + + /** + * The path where the fat binary is cached. + */ + const char* cachePath; +} CUpti_ActivityJit; + +/** + * \brief The activity record for CUDA event. + * + * This activity is used to track recorded events. + * (CUPTI_ACTIVITY_KIND_CUDA_EVENT). + * + * Structure deprecated in CUDA 12.8: Refer to CUpti_ActivityCudaEvent2 + * for the latest structure. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_CUDA_EVENT. + */ + CUpti_ActivityKind kind; + + /** + * The correlation ID of the API to which this result is associated. + */ + uint32_t correlationId; + + /** + * The ID of the context where the event was recorded. + */ + uint32_t contextId; + + /** + * The compute stream where the event was recorded. + */ + uint32_t streamId; + + /** + * A unique event ID to identify the event record. + */ + uint32_t eventId; + + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +} CUpti_ActivityCudaEvent; + +/** + * \brief The activity record for synchronization management. + * + * This activity is used to track various CUDA synchronization APIs. + * (CUPTI_ACTIVITY_KIND_SYNCHRONIZATION). + * + * Structure deprecated in CUDA 12.8: Refer to CUpti_ActivitySynchronization2 + * for the latest structure. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_SYNCHRONIZATION. + */ + CUpti_ActivityKind kind; + + /** + * The type of record. + */ + CUpti_ActivitySynchronizationType type; + + /** + * The start timestamp for the function, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the function. + */ + uint64_t start; + + /** + * The end timestamp for the function, in ns. A value of 0 for both + * the start and end timestamps indicates that timestamp information + * could not be collected for the function. + */ + uint64_t end; + + /** + * The correlation ID of the API to which this result is associated. + */ + uint32_t correlationId; + + /** + * The ID of the context for which the synchronization API is called. + * In case of context synchronization API it is the context id for which the API is called. + * In case of stream/event synchronization it is the ID of the context where the stream/event was created. + */ + uint32_t contextId; + + /** + * The compute stream for which the synchronization API is called. + * A CUPTI_SYNCHRONIZATION_INVALID_VALUE value indicate the field is not applicable for this record. + * Not valid for cuCtxSynchronize, cuEventSynchronize. + */ + uint32_t streamId; + + /** + * The event ID for which the synchronization API is called. + * A CUPTI_SYNCHRONIZATION_INVALID_VALUE value indicate the field is not applicable for this record. + * Not valid for cuCtxSynchronize, cuStreamSynchronize. + */ + uint32_t cudaEventId; +} CUpti_ActivitySynchronization; + +/** + * \brief The activity record for memory copies. + * + * This activity record represents a memory copy + * (CUPTI_ACTIVITY_KIND_MEMCPY). + * + * Structure deprecated in CUDA 12.8: Refer to CUpti_ActivityMemcpy6 + * for the latest structure. + */ +typedef struct PACKED_ALIGNMENT { + /** + * The activity record kind, must be CUPTI_ACTIVITY_KIND_MEMCPY. + */ + CUpti_ActivityKind kind; + + /** + * The kind of the memory copy, stored as a byte to reduce record + * size. \see CUpti_ActivityMemcpyKind + */ + uint8_t copyKind; + + /** + * The source memory kind read by the memory copy, stored as a byte + * to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t srcKind; + + /** + * The destination memory kind read by the memory copy, stored as a + * byte to reduce record size. \see CUpti_ActivityMemoryKind + */ + uint8_t dstKind; + + /** + * The flags associated with the memory copy. \see CUpti_ActivityFlag + */ + uint8_t flags; + + /** + * The number of bytes transferred by the memory copy. + */ + uint64_t bytes; + + /** + * The start timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t start; + + /** + * The end timestamp for the memory copy, in ns. A value of 0 for + * both the start and end timestamps indicates that timestamp + * information could not be collected for the memory copy. + */ + uint64_t end; + + /** + * The ID of the device where the memory copy is occurring. + */ + uint32_t deviceId; + + /** + * The ID of the context where the memory copy is occurring. + */ + uint32_t contextId; + + /** + * The ID of the stream where the memory copy is occurring. + */ + uint32_t streamId; + + /** + * The correlation ID of the memory copy. Each memory copy is + * assigned a unique correlation ID that is identical to the + * correlation ID in the driver API activity record that launched + * the memory copy. + */ + uint32_t correlationId; + + /** + * The runtime correlation ID of the memory copy. Each memory copy + * is assigned a unique runtime correlation ID that is identical to + * the correlation ID in the runtime API activity record that + * launched the memory copy. + */ + uint32_t runtimeCorrelationId; + +#ifdef CUPTILP64 + /** + * Undefined. Reserved for internal use. + */ + uint32_t pad; +#endif + + /** + * Undefined. Reserved for internal use. + */ + void *reserved0; + + /** + * The unique ID of the graph node that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint64_t graphNodeId; + + /** + * The unique ID of the graph that executed this memcpy through graph launch. + * This field will be 0 if the memcpy is not done through graph launch. + */ + uint32_t graphId; + + /** + * The ID of the HW channel on which the memory copy is occurring. + */ + uint32_t channelID; + + /** + * The type of the channel + */ + CUpti_ChannelType channelType; + + /** + * Reserved for internal use. + */ + uint32_t pad2; +} CUpti_ActivityMemcpy5; + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /*_CUPTI_ACTIVITY_DEPRECATED_H_*/ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_callbacks.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_callbacks.h new file mode 100644 index 0000000000000000000000000000000000000000..7dc1c94b2a6dc2cbab63af058ccec71f822cf63b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_callbacks.h @@ -0,0 +1,863 @@ +/* + * Copyright 2010-2023 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(__CUPTI_CALLBACKS_H__) +#define __CUPTI_CALLBACKS_H__ + +#include +#include +#include +#include +#include + +#ifndef CUPTIAPI +#ifdef _WIN32 +#define CUPTIAPI __stdcall +#else +#define CUPTIAPI +#endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_CALLBACK_API CUPTI Callback API + * Functions, types, and enums that implement the CUPTI Callback API. + * @{ + */ + +/** + * \brief Specifies the point in an API call that a callback is issued. + * + * Specifies the point in an API call that a callback is issued. This + * value is communicated to the callback function via \ref + * CUpti_CallbackData::callbackSite. + */ +typedef enum { + /** + * The callback is at the entry of the API call. + */ + CUPTI_API_ENTER = 0, + /** + * The callback is at the exit of the API call. + */ + CUPTI_API_EXIT = 1, + CUPTI_API_CBSITE_FORCE_INT = 0x7fffffff +} CUpti_ApiCallbackSite; + +/** + * \brief Callback domains. + * + * Callback domains. Each domain represents callback points for a + * group of related API functions or CUDA driver activity. + */ +typedef enum { + /** + * Invalid domain. + */ + CUPTI_CB_DOMAIN_INVALID = 0, + /** + * Domain containing callback points for all driver API functions. + */ + CUPTI_CB_DOMAIN_DRIVER_API = 1, + /** + * Domain containing callback points for all runtime API + * functions. + */ + CUPTI_CB_DOMAIN_RUNTIME_API = 2, + /** + * Domain containing callback points for CUDA resource tracking. + */ + CUPTI_CB_DOMAIN_RESOURCE = 3, + /** + * Domain containing callback points for CUDA synchronization. + */ + CUPTI_CB_DOMAIN_SYNCHRONIZE = 4, + /** + * Domain containing callback points for NVTX API functions. + */ + CUPTI_CB_DOMAIN_NVTX = 5, + /** + * Domain containing callback points for various states. + */ + CUPTI_CB_DOMAIN_STATE = 6, + + CUPTI_CB_DOMAIN_SIZE, + + CUPTI_CB_DOMAIN_FORCE_INT = 0x7fffffff +} CUpti_CallbackDomain; + +/** + * \brief Callback IDs for resource domain. + * + * Callback IDs for resource domain, CUPTI_CB_DOMAIN_RESOURCE. This + * value is communicated to the callback function via the \p cbid + * parameter. + */ +typedef enum { + /** + * Invalid resource callback ID. + */ + CUPTI_CBID_RESOURCE_INVALID = 0, + /** + * A new context has been created. + */ + CUPTI_CBID_RESOURCE_CONTEXT_CREATED = 1, + /** + * A context is about to be destroyed. + */ + CUPTI_CBID_RESOURCE_CONTEXT_DESTROY_STARTING = 2, + /** + * A new stream has been created. + */ + CUPTI_CBID_RESOURCE_STREAM_CREATED = 3, + /** + * A stream is about to be destroyed. + */ + CUPTI_CBID_RESOURCE_STREAM_DESTROY_STARTING = 4, + /** + * The driver has finished initializing. + */ + CUPTI_CBID_RESOURCE_CU_INIT_FINISHED = 5, + /** + * A module has been loaded. + */ + CUPTI_CBID_RESOURCE_MODULE_LOADED = 6, + /** + * A module is about to be unloaded. + */ + CUPTI_CBID_RESOURCE_MODULE_UNLOAD_STARTING = 7, + /** + * The current module which is being profiled. + */ + CUPTI_CBID_RESOURCE_MODULE_PROFILED = 8, + /** + * CUDA graph has been created. + */ + CUPTI_CBID_RESOURCE_GRAPH_CREATED = 9, + /** + * CUDA graph is about to be destroyed. + */ + CUPTI_CBID_RESOURCE_GRAPH_DESTROY_STARTING = 10, + /** + * CUDA graph is cloned. + */ + CUPTI_CBID_RESOURCE_GRAPH_CLONED = 11, + /** + * CUDA graph node is about to be created + */ + CUPTI_CBID_RESOURCE_GRAPHNODE_CREATE_STARTING = 12, + /** + * CUDA graph node is created. + */ + CUPTI_CBID_RESOURCE_GRAPHNODE_CREATED = 13, + /** + * CUDA graph node is about to be destroyed. + */ + CUPTI_CBID_RESOURCE_GRAPHNODE_DESTROY_STARTING = 14, + /** + * Dependency on a CUDA graph node is created. + */ + CUPTI_CBID_RESOURCE_GRAPHNODE_DEPENDENCY_CREATED = 15, + /** + * Dependency on a CUDA graph node is destroyed. + */ + CUPTI_CBID_RESOURCE_GRAPHNODE_DEPENDENCY_DESTROY_STARTING = 16, + /** + * An executable CUDA graph is about to be created. + */ + CUPTI_CBID_RESOURCE_GRAPHEXEC_CREATE_STARTING = 17, + /** + * An executable CUDA graph is created. + */ + CUPTI_CBID_RESOURCE_GRAPHEXEC_CREATED = 18, + /** + * An executable CUDA graph is about to be destroyed. + */ + CUPTI_CBID_RESOURCE_GRAPHEXEC_DESTROY_STARTING = 19, + /** + * CUDA graph node is cloned. + */ + CUPTI_CBID_RESOURCE_GRAPHNODE_CLONED = 20, + /** + * CUDA stream attribute is changed. + */ + CUPTI_CBID_RESOURCE_STREAM_ATTRIBUTE_CHANGED = 21, + + CUPTI_CBID_RESOURCE_SIZE, + CUPTI_CBID_RESOURCE_FORCE_INT = 0x7fffffff +} CUpti_CallbackIdResource; + +/** + * \brief Callback IDs for synchronization domain. + * + * Callback IDs for synchronization domain, + * CUPTI_CB_DOMAIN_SYNCHRONIZE. This value is communicated to the + * callback function via the \p cbid parameter. + */ +typedef enum { + /** + * Invalid synchronize callback ID. + */ + CUPTI_CBID_SYNCHRONIZE_INVALID = 0, + /** + * Stream synchronization has completed for the stream. + */ + CUPTI_CBID_SYNCHRONIZE_STREAM_SYNCHRONIZED = 1, + /** + * Context synchronization has completed for the context. + */ + CUPTI_CBID_SYNCHRONIZE_CONTEXT_SYNCHRONIZED = 2, + CUPTI_CBID_SYNCHRONIZE_SIZE, + CUPTI_CBID_SYNCHRONIZE_FORCE_INT = 0x7fffffff +} CUpti_CallbackIdSync; + + +/** + * \brief Callback IDs for state domain. + * + * Callback IDs for state domain, + * CUPTI_CB_DOMAIN_STATE. This value is communicated to the + * callback function via the \p cbid parameter. + */ +typedef enum { + /** + * Invalid state callback ID. + */ + CUPTI_CBID_STATE_INVALID = 0, + /** + * Notification of fatal errors - high impact, non-recoverable + * When encountered, CUPTI automatically invokes cuptiFinalize() + * User can control behavior of the application in future from + * receiving this callback - such as continuing without profiling, or + * terminating the whole application. + */ + CUPTI_CBID_STATE_FATAL_ERROR = 1, + /** + * Notification of non fatal errors - high impact, but recoverable + * This notification is not issued in the current release. + */ + CUPTI_CBID_STATE_ERROR = 2, + /** + * Notification of warnings - low impact, recoverable. + */ + CUPTI_CBID_STATE_WARNING = 3, + + CUPTI_CBID_STATE_SIZE, + CUPTI_CBID_STATE_FORCE_INT = 0x7fffffff +} CUpti_CallbackIdState; + + +/** + * \brief Data passed into a runtime or driver API callback function. + * + * Data passed into a runtime or driver API callback function as the + * \p cbdata argument to \ref CUpti_CallbackFunc. The \p cbdata will + * be this type for \p domain equal to CUPTI_CB_DOMAIN_DRIVER_API or + * CUPTI_CB_DOMAIN_RUNTIME_API. The callback data is valid only within + * the invocation of the callback function that is passed the data. If + * you need to retain some data for use outside of the callback, you + * must make a copy of that data. For example, if you make a shallow + * copy of CUpti_CallbackData within a callback, you cannot + * dereference \p functionParams outside of that callback to access + * the function parameters. \p functionName is an exception: the + * string pointed to by \p functionName is a global constant and so + * may be accessed outside of the callback. + */ +typedef struct { + /** + * Point in the runtime or driver function from where the callback + * was issued. + */ + CUpti_ApiCallbackSite callbackSite; + + /** + * Name of the runtime or driver API function which issued the + * callback. This string is a global constant and so may be + * accessed outside of the callback. + */ + const char *functionName; + + /** + * Pointer to the arguments passed to the runtime or driver API + * call. See generated_cuda_runtime_api_meta.h and + * generated_cuda_meta.h for structure definitions for the + * parameters for each runtime and driver API function. + */ + const void *functionParams; + + /** + * Pointer to the return value of the runtime or driver API + * call. This field is only valid within the exit::CUPTI_API_EXIT + * callback. For a runtime API \p functionReturnValue points to a + * \p cudaError_t. For a driver API \p functionReturnValue points + * to a \p CUresult. + */ + void *functionReturnValue; + + /** + * Name of the symbol operated on by the runtime or driver API + * function which issued the callback. This entry is valid only for + * driver and runtime launch callbacks, where it returns the name of + * the kernel. + */ + const char *symbolName; + + /** + * Driver context current to the thread, or null if no context is + * current. This value can change from the entry to exit callback + * of a runtime API function if the runtime initializes a context. + */ + CUcontext context; + + /** + * Unique ID for the CUDA context associated with the thread. The + * UIDs are assigned sequentially as contexts are created and are + * unique within a process. + */ + uint32_t contextUid; + + /** + * Pointer to data shared between the entry and exit callbacks of + * a given runtime or drive API function invocation. This field + * can be used to pass 64-bit values from the entry callback to + * the corresponding exit callback. + */ + uint64_t *correlationData; + + /** + * The activity record correlation ID for this callback. For a + * driver domain callback (i.e. \p domain + * CUPTI_CB_DOMAIN_DRIVER_API) this ID will equal the correlation ID + * in the CUpti_ActivityAPI record corresponding to the CUDA driver + * function call. For a runtime domain callback (i.e. \p domain + * CUPTI_CB_DOMAIN_RUNTIME_API) this ID will equal the correlation + * ID in the CUpti_ActivityAPI record corresponding to the CUDA + * runtime function call. Within the callback, this ID can be + * recorded to correlate user data with the activity record. This + * field is new in 4.1. + */ + uint32_t correlationId; + +} CUpti_CallbackData; + +/** + * \brief Data passed into a resource callback function. + * + * Data passed into a resource callback function as the \p cbdata + * argument to \ref CUpti_CallbackFunc. The \p cbdata will be this + * type for \p domain equal to CUPTI_CB_DOMAIN_RESOURCE. The callback + * data is valid only within the invocation of the callback function + * that is passed the data. If you need to retain some data for use + * outside of the callback, you must make a copy of that data. + */ +typedef struct { + /** + * For CUPTI_CBID_RESOURCE_CONTEXT_CREATED and + * CUPTI_CBID_RESOURCE_CONTEXT_DESTROY_STARTING, the context being + * created or destroyed. For CUPTI_CBID_RESOURCE_STREAM_CREATED and + * CUPTI_CBID_RESOURCE_STREAM_DESTROY_STARTING, the context + * containing the stream being created or destroyed. + */ + CUcontext context; + + union { + /** + * For CUPTI_CBID_RESOURCE_STREAM_CREATED and + * CUPTI_CBID_RESOURCE_STREAM_DESTROY_STARTING, the stream being + * created or destroyed. + */ + CUstream stream; + } resourceHandle; + + /** + * Reserved for future use. + */ + void *resourceDescriptor; +} CUpti_ResourceData; + + +/** + * \brief Module data passed into a resource callback function. + * + * CUDA module data passed into a resource callback function as the \p cbdata + * argument to \ref CUpti_CallbackFunc. The \p cbdata will be this + * type for \p domain equal to CUPTI_CB_DOMAIN_RESOURCE. The module + * data is valid only within the invocation of the callback function + * that is passed the data. If you need to retain some data for use + * outside of the callback, you must make a copy of that data. + */ + +typedef struct { + /** + * Identifier to associate with the CUDA module. + */ + uint32_t moduleId; + + /** + * The size of the cubin. + */ + size_t cubinSize; + + /** + * Pointer to the associated cubin. + */ + const char *pCubin; +} CUpti_ModuleResourceData; + +/** + * \brief CUDA graphs data passed into a resource callback function. + * + * CUDA graphs data passed into a resource callback function as the \p cbdata + * argument to \ref CUpti_CallbackFunc. The \p cbdata will be this + * type for \p domain equal to CUPTI_CB_DOMAIN_RESOURCE. The graph + * data is valid only within the invocation of the callback function + * that is passed the data. If you need to retain some data for use + * outside of the callback, you must make a copy of that data. + */ + +typedef struct { + /** + * CUDA graph + */ + CUgraph graph; + /** + * The original CUDA graph from which \param graph is cloned + */ + CUgraph originalGraph; + /** + * CUDA graph node + */ + CUgraphNode node; + /** + * The original CUDA graph node from which \param node is cloned + */ + CUgraphNode originalNode; + /** + * Type of the \param node + */ + CUgraphNodeType nodeType; + /** + * The dependent graph node + * The size of the array is \param numDependencies. + */ + CUgraphNode dependency; + /** + * CUDA executable graph + */ + CUgraphExec graphExec; +} CUpti_GraphData; + +/** + * \brief Data passed into a synchronize callback function. + * + * Data passed into a synchronize callback function as the \p cbdata + * argument to \ref CUpti_CallbackFunc. The \p cbdata will be this + * type for \p domain equal to CUPTI_CB_DOMAIN_SYNCHRONIZE. The + * callback data is valid only within the invocation of the callback + * function that is passed the data. If you need to retain some data + * for use outside of the callback, you must make a copy of that data. + */ +typedef struct { + /** + * The context of the stream being synchronized. + */ + CUcontext context; + /** + * The stream being synchronized. + */ + CUstream stream; +} CUpti_SynchronizeData; + +/** + * \brief Data passed into a NVTX callback function. + * + * Data passed into a NVTX callback function as the \p cbdata argument + * to \ref CUpti_CallbackFunc. The \p cbdata will be this type for \p + * domain equal to CUPTI_CB_DOMAIN_NVTX. Unless otherwise notes, the + * callback data is valid only within the invocation of the callback + * function that is passed the data. If you need to retain some data + * for use outside of the callback, you must make a copy of that data. + */ +typedef struct { + /** + * Name of the NVTX API function which issued the callback. This + * string is a global constant and so may be accessed outside of the + * callback. + */ + const char *functionName; + + /** + * Pointer to the arguments passed to the NVTX API call. See + * generated_nvtx_meta.h for structure definitions for the + * parameters for each NVTX API function. + */ + const void *functionParams; + + /** + * Pointer to the return value of the NVTX API call. See + * nvToolsExt.h for each NVTX API function's return value. + */ + const void *functionReturnValue; +} CUpti_NvtxData; + +/** + * \brief Stream attribute data passed into a resource callback function + * for CUPTI_CBID_RESOURCE_STREAM_ATTRIBUTE_CHANGED callback + + * Data passed into a resource callback function as the \p cbdata + * argument to \ref CUpti_CallbackFunc. The \p cbdata will be this + * type for \p domain equal to CUPTI_CB_DOMAIN_RESOURCE. The + * stream attribute data is valid only within the invocation of the callback + * function that is passed the data. If you need to retain some data + * for use outside of the callback, you must make a copy of that data. + */ +typedef struct { + /** + * The CUDA stream handle for the attribute + */ + CUstream stream; + + /** + * The type of the CUDA stream attribute + */ + CUstreamAttrID attr; + + /** + * The value of the CUDA stream attribute + */ + const CUstreamAttrValue *value; +} CUpti_StreamAttrData; + +/** + * \brief Data passed into a State callback function. + * + * Data passed into a State callback function as the \p cbdata argument + * to \ref CUpti_CallbackFunc. The \p cbdata will be this type for \p + * domain equal to CUPTI_CB_DOMAIN_STATE and callback Ids belonging to CUpti_CallbackIdState. + * Unless otherwise noted, the callback data is valid only within the invocation of the callback + * function that is passed the data. If you need to retain some data + * for use outside of the callback, you must make a copy of that data. + */ +typedef struct { + union { + /** + * Data passed along with the callback Ids + * Enum CUpti_CallbackIdState used to denote callback ids + */ + struct { + /** + * Error code + */ + CUptiResult result; + /** + * String containing more details. It can be NULL. + */ + const char *message; + } notification; + }; +} CUpti_StateData; + +/** + * \brief An ID for a driver API, runtime API, resource or + * synchronization callback. + * + * An ID for a driver API, runtime API, resource or synchronization + * callback. Within a driver API callback this should be interpreted + * as a CUpti_driver_api_trace_cbid value (these values are defined in + * cupti_driver_cbid.h). Within a runtime API callback this should be + * interpreted as a CUpti_runtime_api_trace_cbid value (these values + * are defined in cupti_runtime_cbid.h). Within a resource API + * callback this should be interpreted as a \ref + * CUpti_CallbackIdResource value. Within a synchronize API callback + * this should be interpreted as a \ref CUpti_CallbackIdSync value. + */ +typedef uint32_t CUpti_CallbackId; + +/** + * \brief Function type for a callback. + * + * Function type for a callback. The type of the data passed to the + * callback in \p cbdata depends on the \p domain. If \p domain is + * CUPTI_CB_DOMAIN_DRIVER_API or CUPTI_CB_DOMAIN_RUNTIME_API the type + * of \p cbdata will be CUpti_CallbackData. If \p domain is + * CUPTI_CB_DOMAIN_RESOURCE the type of \p cbdata will be + * CUpti_ResourceData. If \p domain is CUPTI_CB_DOMAIN_SYNCHRONIZE the + * type of \p cbdata will be CUpti_SynchronizeData. If \p domain is + * CUPTI_CB_DOMAIN_NVTX the type of \p cbdata will be CUpti_NvtxData. + * + * \param userdata User data supplied at subscription of the callback + * \param domain The domain of the callback + * \param cbid The ID of the callback + * \param cbdata Data passed to the callback. + */ +typedef void (CUPTIAPI *CUpti_CallbackFunc)( + void *userdata, + CUpti_CallbackDomain domain, + CUpti_CallbackId cbid, + const void *cbdata); + +/** + * \brief A callback subscriber. + */ +typedef struct CUpti_Subscriber_st *CUpti_SubscriberHandle; + +/** + * \brief Pointer to an array of callback domains. + */ +typedef CUpti_CallbackDomain *CUpti_DomainTable; + +/** + * \brief Get the available callback domains. + * + * Returns in \p *domainTable an array of size \p *domainCount of all + * the available callback domains. + * \note \b Thread-safety: this function is thread safe. + * + * \param domainCount Returns number of callback domains + * \param domainTable Returns pointer to array of available callback domains + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_NOT_INITIALIZED if unable to initialize CUPTI + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p domainCount or \p domainTable are NULL + */ +CUptiResult CUPTIAPI cuptiSupportedDomains(size_t *domainCount, + CUpti_DomainTable *domainTable); + +/** + * \brief Initialize a callback subscriber with a callback function + * and user data. + * + * Initializes a callback subscriber with a callback function and + * (optionally) a pointer to user data. The returned subscriber handle + * can be used to enable and disable the callback for specific domains + * and callback IDs. + * \note Only a single subscriber can be registered at a time. To ensure + * that no other CUPTI client interrupts the profiling session, it's the + * responsibility of all the CUPTI clients to call this function before + * starting the profling session. In case profiling session is already + * started by another CUPTI client, this function returns the error code + * CUPTI_ERROR_MULTIPLE_SUBSCRIBERS_NOT_SUPPORTED. + * Note that this function returns the same error when application is + * launched using NVIDIA tools like nvprof, Visual Profiler, Nsight Systems, + * Nsight Compute, cuda-gdb and cuda-memcheck. + * \note This function does not enable any callbacks. + * \note \b Thread-safety: this function is thread safe. + * + * \param subscriber Returns handle to initialize subscriber + * \param callback The callback function + * \param userdata A pointer to user data. This data will be passed to + * the callback function via the \p userdata parameter. + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_NOT_INITIALIZED if unable to initialize CUPTI + * \retval CUPTI_ERROR_MULTIPLE_SUBSCRIBERS_NOT_SUPPORTED if there is already a CUPTI subscriber + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p subscriber is NULL + */ +CUptiResult CUPTIAPI cuptiSubscribe(CUpti_SubscriberHandle *subscriber, + CUpti_CallbackFunc callback, + void *userdata); + +/** + * \brief Unregister a callback subscriber. + * + * Removes a callback subscriber so that no future callbacks will be + * issued to that subscriber. + * \note \b Thread-safety: this function is thread safe. + * + * \param subscriber Handle to the initialize subscriber + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_NOT_INITIALIZED if unable to initialized CUPTI + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p subscriber is NULL or not initialized + */ +CUptiResult CUPTIAPI cuptiUnsubscribe(CUpti_SubscriberHandle subscriber); + +/** + * \brief Get the current enabled/disabled state of a callback for a specific + * domain and function ID. + * + * Returns non-zero in \p *enable if the callback for a domain and + * callback ID is enabled, and zero if not enabled. + * + * \note \b Thread-safety: a subscriber must serialize access to + * cuptiGetCallbackState, cuptiEnableCallback, cuptiEnableDomain, and + * cuptiEnableAllDomains. For example, if cuptiGetCallbackState(sub, + * d, c) and cuptiEnableCallback(sub, d, c) are called concurrently, + * the results are undefined. + * + * \param enable Returns non-zero if callback enabled, zero if not enabled + * \param subscriber Handle to the initialize subscriber + * \param domain The domain of the callback + * \param cbid The ID of the callback + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_NOT_INITIALIZED if unable to initialized CUPTI + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p enabled is NULL, or if \p + * subscriber, \p domain or \p cbid is invalid. + */ +CUptiResult CUPTIAPI cuptiGetCallbackState(uint32_t *enable, + CUpti_SubscriberHandle subscriber, + CUpti_CallbackDomain domain, + CUpti_CallbackId cbid); + +/** + * \brief Enable or disabled callbacks for a specific domain and + * callback ID. + * + * Enable or disabled callbacks for a subscriber for a specific domain + * and callback ID. + * + * \note \b Thread-safety: a subscriber must serialize access to + * cuptiGetCallbackState, cuptiEnableCallback, cuptiEnableDomain, and + * cuptiEnableAllDomains. For example, if cuptiGetCallbackState(sub, + * d, c) and cuptiEnableCallback(sub, d, c) are called concurrently, + * the results are undefined. + * + * \param enable New enable state for the callback. Zero disables the + * callback, non-zero enables the callback. + * \param subscriber - Handle to callback subscription + * \param domain The domain of the callback + * \param cbid The ID of the callback + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_NOT_INITIALIZED if unable to initialized CUPTI + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p subscriber, \p domain or \p + * cbid is invalid. + */ +CUptiResult CUPTIAPI cuptiEnableCallback(uint32_t enable, + CUpti_SubscriberHandle subscriber, + CUpti_CallbackDomain domain, + CUpti_CallbackId cbid); + +/** + * \brief Enable or disabled all callbacks for a specific domain. + * + * Enable or disabled all callbacks for a specific domain. + * + * \note \b Thread-safety: a subscriber must serialize access to + * cuptiGetCallbackState, cuptiEnableCallback, cuptiEnableDomain, and + * cuptiEnableAllDomains. For example, if cuptiGetCallbackEnabled(sub, + * d, *) and cuptiEnableDomain(sub, d) are called concurrently, the + * results are undefined. + * + * \param enable New enable state for all callbacks in the + * domain. Zero disables all callbacks, non-zero enables all + * callbacks. + * \param subscriber - Handle to callback subscription + * \param domain The domain of the callback + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_NOT_INITIALIZED if unable to initialized CUPTI + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p subscriber or \p domain is invalid + */ +CUptiResult CUPTIAPI cuptiEnableDomain(uint32_t enable, + CUpti_SubscriberHandle subscriber, + CUpti_CallbackDomain domain); + +/** + * \brief Enable or disable all callbacks in all domains. + * + * Enable or disable all callbacks in all domains. + * + * \note \b Thread-safety: a subscriber must serialize access to + * cuptiGetCallbackState, cuptiEnableCallback, cuptiEnableDomain, and + * cuptiEnableAllDomains. For example, if cuptiGetCallbackState(sub, + * d, *) and cuptiEnableAllDomains(sub) are called concurrently, the + * results are undefined. + * + * \param enable New enable state for all callbacks in all + * domain. Zero disables all callbacks, non-zero enables all + * callbacks. + * \param subscriber - Handle to callback subscription + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_NOT_INITIALIZED if unable to initialized CUPTI + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p subscriber is invalid + */ +CUptiResult CUPTIAPI cuptiEnableAllDomains(uint32_t enable, + CUpti_SubscriberHandle subscriber); + +/** + * \brief Get the name of a callback for a specific domain and callback ID. + * + * Returns a pointer to the name c_string in \p **name. + * + * \note \b Names are available only for the DRIVER and RUNTIME domains. + * + * \param domain The domain of the callback + * \param cbid The ID of the callback + * \param name Returns pointer to the name string on success, NULL otherwise + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p name is NULL, or if + * \p domain or \p cbid is invalid. + */ +CUptiResult CUPTIAPI cuptiGetCallbackName(CUpti_CallbackDomain domain, + uint32_t cbid, + const char **name); + +/** @} */ /* END CUPTI_CALLBACK_API */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif // file guard + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_checkpoint.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_checkpoint.h new file mode 100644 index 0000000000000000000000000000000000000000..36eeddc4e2b7bfd1902ce313d71f173db70beaef --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_checkpoint.h @@ -0,0 +1,127 @@ +#pragma once + +#include +#include + +#include +#include + +namespace NV { namespace Cupti { namespace Checkpoint { + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \defgroup CUPTI_CHECKPOINT_API CUPTI Checkpoint API + * Functions, types, and enums that implement the CUPTI Checkpoint API. + * @{ + */ + +/** + * \brief Specifies optimization options for a checkpoint, may be OR'd together to specify multiple options. + */ +typedef enum +{ + CUPTI_CHECKPOINT_OPT_NONE = 0, //!< Default behavior + CUPTI_CHECKPOINT_OPT_TRANSFER = 1, //!< Determine which mem blocks have changed, and only restore those. This optimization is cached, which means cuptiCheckpointRestore must always be called at the same point in the application when this option is enabled, or the result may be incorrect. +} CUpti_CheckpointOptimizations; + +/** + * \brief Configuration and handle for a CUPTI Checkpoint + * + * A CUptiCheckpoint object should be initialized with desired options prior to passing into any + * CUPTI Checkpoint API function. The first call into a Checkpoint API function will initialize internal + * state based on these options. Subsequent changes to these options will not have any effect. + * + * Checkpoint data is saved in device, host, and filesystem space. There are options to reserve memory + * at each level (device, host, filesystem) which are intended to allow a guarantee that a certain amount + * of memory will remain free for use after the checkpoint is saved. + * Note, however, that falling back to slower levels of memory (host, and then filesystem) to save the checkpoint + * will result in performance degradation. + * Currently, the filesystem limitation is not implemented. Note that falling back to filesystem storage may + * significantly impact the performance for saving and restoring a checkpoint. + */ +typedef struct +{ + size_t structSize; //!< [in] Must be set to CUpti_Checkpoint_STRUCT_SIZE + + CUcontext ctx; //!< [in] Set to context to save from, or will use current context if NULL + + size_t reserveDeviceMB; //!< [in] Restrict checkpoint from using last N MB of device memory (-1 = use no device memory) + size_t reserveHostMB; //!< [in] Restrict checkpoint from using last N MB of host memory (-1 = use no host memory) + uint8_t allowOverwrite; //!< [in] Boolean, Allow checkpoint to save over existing checkpoint + uint8_t optimizations; //!< [in] Mask of CUpti_CheckpointOptimizations flags for this checkpoint + + void * pPriv; //!< [in] Assign to NULL +} CUpti_Checkpoint; + +#define CUpti_Checkpoint_STRUCT_SIZE \ +(offsetof(CUpti_Checkpoint, pPriv) + \ +sizeof(((CUpti_Checkpoint*)(nullptr))->pPriv)) + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \brief Initialize and save a checkpoint of the device state associated with the handle context + * + * Uses the handle options to configure and save a checkpoint of the device state associated with the specified context. + * + * \param handle A pointer to a CUpti_Checkpoint object + * + * \retval CUPTI_SUCCESS if a checkpoint was successfully initialized and saved + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p handle does not appear to refer to a valid CUpti_Checkpoint + * \retval CUPTI_ERROR_INVALID_CONTEXT + * \retval CUPTI_ERROR_INVALID_DEVICE if device associated with context is not compatible with checkpoint API + * \retval CUPTI_ERROR_INVALID_OPERATION if Save is requested over an existing checkpoint, but \p allowOverwrite was not originally specified + * \retval CUPTI_ERROR_OUT_OF_MEMORY if as configured, not enough backing storage space to save the checkpoint + */ +CUptiResult cuptiCheckpointSave(CUpti_Checkpoint * const handle); + +/** + * \brief Restore a checkpoint to the device associated with its context + * + * Restores device, pinned, and allocated memory to the state when the checkpoint was saved + * + * \param handle A pointer to a previously saved CUpti_Checkpoint object + * + * \retval CUTPI_SUCCESS if the checkpoint was successfully restored + * \retval CUPTI_ERROR_NOT_INITIALIZED if the checkpoint was not previously initialized + * \retval CUPTI_ERROR_INVALID_CONTEXT + * \retval CUPTI_ERROR_INVALID_PARAMETER if the handle appears invalid + * \retval CUPTI_ERROR_UNKNOWN if the restore or optimization operation fails + */ +CUptiResult cuptiCheckpointRestore(CUpti_Checkpoint * const handle); + +/** + * \brief Free the backing data for a checkpoint + * + * Frees all associated device, host memory and filesystem storage used for this context. + * After freeing a handle, it may be re-used as if it was new - options may be re-configured and will + * take effect on the next call to \p cuptiCheckpointSave. + * + * \param handle A pointer to a previously saved CUpti_Checkpoint object + * + * \retval CUPTI_SUCCESS if the handle was successfully freed + * \retval CUPTI_ERROR_INVALID_PARAMETER if the handle was already freed or appears invalid + * \retval CUPTI_ERROR_INVALID_CONTEXT if the context is no longer valid + */ +CUptiResult cuptiCheckpointFree(CUpti_Checkpoint * const handle); + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +// Exit namespace NV::Cupti::Checkpoint +}}} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_common.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_common.h new file mode 100644 index 0000000000000000000000000000000000000000..96d228c4df3c1f090a4979bfe10132e080042fef --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_common.h @@ -0,0 +1,93 @@ +/* + * Copyright 2023 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(__CUPTI_COMMON_H__) +#define __CUPTI_COMMON_H__ + +#ifndef CUPTIAPI +#ifdef _WIN32 +#define CUPTIAPI __stdcall +#else +#define CUPTIAPI +#endif +#endif + +#ifndef CUPTIUTILAPI +#ifdef _WIN32 +#define CUPTIUTILAPI __stdcall +#else +#define CUPTIUTILAPI +#endif +#endif + +#if defined(__LP64__) +#define CUPTILP64 1 +#elif defined(_WIN64) +#define CUPTILP64 1 +#else +#undef CUPTILP64 +#endif + +#define ACTIVITY_RECORD_ALIGNMENT 8 +#if defined(_WIN32) // Windows 32- and 64-bit +#define START_PACKED_ALIGNMENT __pragma(pack(push,1)) // exact fit - no padding +#define PACKED_ALIGNMENT __declspec(align(ACTIVITY_RECORD_ALIGNMENT)) +#define END_PACKED_ALIGNMENT __pragma(pack(pop)) +#elif defined(__GNUC__) // GCC +#define START_PACKED_ALIGNMENT +#define PACKED_ALIGNMENT __attribute__ ((__packed__)) __attribute__ ((aligned (ACTIVITY_RECORD_ALIGNMENT))) +#define END_PACKED_ALIGNMENT +#else // all other compilers +#define START_PACKED_ALIGNMENT +#define PACKED_ALIGNMENT +#define END_PACKED_ALIGNMENT +#endif + +#endif /*__CUPTI_COMMON_H__*/ + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_driver_cbid.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_driver_cbid.h new file mode 100644 index 0000000000000000000000000000000000000000..4b23832372a3a69c7bfbf0aa188b0417d9270be6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_driver_cbid.h @@ -0,0 +1,799 @@ + +// ************************************************************************* +// Definitions of indices for API functions, unique across entire API +// ************************************************************************* + +// This file is generated. Any changes you make will be lost during the next clean build. +// CUDA public interface, for type definitions and cu* function prototypes + +#if !defined(_CUPTI_DRIVER_CBID_H_) +#define _CUPTI_DRIVER_CBID_H_ + +typedef enum CUpti_driver_api_trace_cbid_enum { + CUPTI_DRIVER_TRACE_CBID_INVALID = 0, + CUPTI_DRIVER_TRACE_CBID_cuInit = 1, + CUPTI_DRIVER_TRACE_CBID_cuDriverGetVersion = 2, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGet = 3, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetCount = 4, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetName = 5, + CUPTI_DRIVER_TRACE_CBID_cuDeviceComputeCapability = 6, + CUPTI_DRIVER_TRACE_CBID_cuDeviceTotalMem = 7, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetProperties = 8, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetAttribute = 9, + CUPTI_DRIVER_TRACE_CBID_cuCtxCreate = 10, + CUPTI_DRIVER_TRACE_CBID_cuCtxDestroy = 11, + CUPTI_DRIVER_TRACE_CBID_cuCtxAttach = 12, + CUPTI_DRIVER_TRACE_CBID_cuCtxDetach = 13, + CUPTI_DRIVER_TRACE_CBID_cuCtxPushCurrent = 14, + CUPTI_DRIVER_TRACE_CBID_cuCtxPopCurrent = 15, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetDevice = 16, + CUPTI_DRIVER_TRACE_CBID_cuCtxSynchronize = 17, + CUPTI_DRIVER_TRACE_CBID_cuModuleLoad = 18, + CUPTI_DRIVER_TRACE_CBID_cuModuleLoadData = 19, + CUPTI_DRIVER_TRACE_CBID_cuModuleLoadDataEx = 20, + CUPTI_DRIVER_TRACE_CBID_cuModuleLoadFatBinary = 21, + CUPTI_DRIVER_TRACE_CBID_cuModuleUnload = 22, + CUPTI_DRIVER_TRACE_CBID_cuModuleGetFunction = 23, + CUPTI_DRIVER_TRACE_CBID_cuModuleGetGlobal = 24, + CUPTI_DRIVER_TRACE_CBID_cu64ModuleGetGlobal = 25, + CUPTI_DRIVER_TRACE_CBID_cuModuleGetTexRef = 26, + CUPTI_DRIVER_TRACE_CBID_cuMemGetInfo = 27, + CUPTI_DRIVER_TRACE_CBID_cu64MemGetInfo = 28, + CUPTI_DRIVER_TRACE_CBID_cuMemAlloc = 29, + CUPTI_DRIVER_TRACE_CBID_cu64MemAlloc = 30, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocPitch = 31, + CUPTI_DRIVER_TRACE_CBID_cu64MemAllocPitch = 32, + CUPTI_DRIVER_TRACE_CBID_cuMemFree = 33, + CUPTI_DRIVER_TRACE_CBID_cu64MemFree = 34, + CUPTI_DRIVER_TRACE_CBID_cuMemGetAddressRange = 35, + CUPTI_DRIVER_TRACE_CBID_cu64MemGetAddressRange = 36, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocHost = 37, + CUPTI_DRIVER_TRACE_CBID_cuMemFreeHost = 38, + CUPTI_DRIVER_TRACE_CBID_cuMemHostAlloc = 39, + CUPTI_DRIVER_TRACE_CBID_cuMemHostGetDevicePointer = 40, + CUPTI_DRIVER_TRACE_CBID_cu64MemHostGetDevicePointer = 41, + CUPTI_DRIVER_TRACE_CBID_cuMemHostGetFlags = 42, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoD = 43, + CUPTI_DRIVER_TRACE_CBID_cu64MemcpyHtoD = 44, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoH = 45, + CUPTI_DRIVER_TRACE_CBID_cu64MemcpyDtoH = 46, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoD = 47, + CUPTI_DRIVER_TRACE_CBID_cu64MemcpyDtoD = 48, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoA = 49, + CUPTI_DRIVER_TRACE_CBID_cu64MemcpyDtoA = 50, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoD = 51, + CUPTI_DRIVER_TRACE_CBID_cu64MemcpyAtoD = 52, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoA = 53, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoH = 54, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoA = 55, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2D = 56, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2DUnaligned = 57, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3D = 58, + CUPTI_DRIVER_TRACE_CBID_cu64Memcpy3D = 59, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoDAsync = 60, + CUPTI_DRIVER_TRACE_CBID_cu64MemcpyHtoDAsync = 61, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoHAsync = 62, + CUPTI_DRIVER_TRACE_CBID_cu64MemcpyDtoHAsync = 63, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoDAsync = 64, + CUPTI_DRIVER_TRACE_CBID_cu64MemcpyDtoDAsync = 65, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoAAsync = 66, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoHAsync = 67, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2DAsync = 68, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DAsync = 69, + CUPTI_DRIVER_TRACE_CBID_cu64Memcpy3DAsync = 70, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD8 = 71, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD8 = 72, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD16 = 73, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD16 = 74, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD32 = 75, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD32 = 76, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D8 = 77, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD2D8 = 78, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D16 = 79, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD2D16 = 80, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D32 = 81, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD2D32 = 82, + CUPTI_DRIVER_TRACE_CBID_cuFuncSetBlockShape = 83, + CUPTI_DRIVER_TRACE_CBID_cuFuncSetSharedSize = 84, + CUPTI_DRIVER_TRACE_CBID_cuFuncGetAttribute = 85, + CUPTI_DRIVER_TRACE_CBID_cuFuncSetCacheConfig = 86, + CUPTI_DRIVER_TRACE_CBID_cuArrayCreate = 87, + CUPTI_DRIVER_TRACE_CBID_cuArrayGetDescriptor = 88, + CUPTI_DRIVER_TRACE_CBID_cuArrayDestroy = 89, + CUPTI_DRIVER_TRACE_CBID_cuArray3DCreate = 90, + CUPTI_DRIVER_TRACE_CBID_cuArray3DGetDescriptor = 91, + CUPTI_DRIVER_TRACE_CBID_cuTexRefCreate = 92, + CUPTI_DRIVER_TRACE_CBID_cuTexRefDestroy = 93, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetArray = 94, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetAddress = 95, + CUPTI_DRIVER_TRACE_CBID_cu64TexRefSetAddress = 96, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetAddress2D = 97, + CUPTI_DRIVER_TRACE_CBID_cu64TexRefSetAddress2D = 98, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetFormat = 99, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetAddressMode = 100, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetFilterMode = 101, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetFlags = 102, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetAddress = 103, + CUPTI_DRIVER_TRACE_CBID_cu64TexRefGetAddress = 104, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetArray = 105, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetAddressMode = 106, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetFilterMode = 107, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetFormat = 108, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetFlags = 109, + CUPTI_DRIVER_TRACE_CBID_cuParamSetSize = 110, + CUPTI_DRIVER_TRACE_CBID_cuParamSeti = 111, + CUPTI_DRIVER_TRACE_CBID_cuParamSetf = 112, + CUPTI_DRIVER_TRACE_CBID_cuParamSetv = 113, + CUPTI_DRIVER_TRACE_CBID_cuParamSetTexRef = 114, + CUPTI_DRIVER_TRACE_CBID_cuLaunch = 115, + CUPTI_DRIVER_TRACE_CBID_cuLaunchGrid = 116, + CUPTI_DRIVER_TRACE_CBID_cuLaunchGridAsync = 117, + CUPTI_DRIVER_TRACE_CBID_cuEventCreate = 118, + CUPTI_DRIVER_TRACE_CBID_cuEventRecord = 119, + CUPTI_DRIVER_TRACE_CBID_cuEventQuery = 120, + CUPTI_DRIVER_TRACE_CBID_cuEventSynchronize = 121, + CUPTI_DRIVER_TRACE_CBID_cuEventDestroy = 122, + CUPTI_DRIVER_TRACE_CBID_cuEventElapsedTime = 123, + CUPTI_DRIVER_TRACE_CBID_cuStreamCreate = 124, + CUPTI_DRIVER_TRACE_CBID_cuStreamQuery = 125, + CUPTI_DRIVER_TRACE_CBID_cuStreamSynchronize = 126, + CUPTI_DRIVER_TRACE_CBID_cuStreamDestroy = 127, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsUnregisterResource = 128, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsSubResourceGetMappedArray = 129, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsResourceGetMappedPointer = 130, + CUPTI_DRIVER_TRACE_CBID_cu64GraphicsResourceGetMappedPointer = 131, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsResourceSetMapFlags = 132, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsMapResources = 133, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsUnmapResources = 134, + CUPTI_DRIVER_TRACE_CBID_cuGetExportTable = 135, + CUPTI_DRIVER_TRACE_CBID_cuCtxSetLimit = 136, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetLimit = 137, + CUPTI_DRIVER_TRACE_CBID_cuD3D10GetDevice = 138, + CUPTI_DRIVER_TRACE_CBID_cuD3D10CtxCreate = 139, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsD3D10RegisterResource = 140, + CUPTI_DRIVER_TRACE_CBID_cuD3D10RegisterResource = 141, + CUPTI_DRIVER_TRACE_CBID_cuD3D10UnregisterResource = 142, + CUPTI_DRIVER_TRACE_CBID_cuD3D10MapResources = 143, + CUPTI_DRIVER_TRACE_CBID_cuD3D10UnmapResources = 144, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceSetMapFlags = 145, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetMappedArray = 146, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetMappedPointer = 147, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetMappedSize = 148, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetMappedPitch = 149, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetSurfaceDimensions = 150, + CUPTI_DRIVER_TRACE_CBID_cuD3D11GetDevice = 151, + CUPTI_DRIVER_TRACE_CBID_cuD3D11CtxCreate = 152, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsD3D11RegisterResource = 153, + CUPTI_DRIVER_TRACE_CBID_cuD3D9GetDevice = 154, + CUPTI_DRIVER_TRACE_CBID_cuD3D9CtxCreate = 155, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsD3D9RegisterResource = 156, + CUPTI_DRIVER_TRACE_CBID_cuD3D9GetDirect3DDevice = 157, + CUPTI_DRIVER_TRACE_CBID_cuD3D9RegisterResource = 158, + CUPTI_DRIVER_TRACE_CBID_cuD3D9UnregisterResource = 159, + CUPTI_DRIVER_TRACE_CBID_cuD3D9MapResources = 160, + CUPTI_DRIVER_TRACE_CBID_cuD3D9UnmapResources = 161, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceSetMapFlags = 162, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetSurfaceDimensions = 163, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetMappedArray = 164, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetMappedPointer = 165, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetMappedSize = 166, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetMappedPitch = 167, + CUPTI_DRIVER_TRACE_CBID_cuD3D9Begin = 168, + CUPTI_DRIVER_TRACE_CBID_cuD3D9End = 169, + CUPTI_DRIVER_TRACE_CBID_cuD3D9RegisterVertexBuffer = 170, + CUPTI_DRIVER_TRACE_CBID_cuD3D9MapVertexBuffer = 171, + CUPTI_DRIVER_TRACE_CBID_cuD3D9UnmapVertexBuffer = 172, + CUPTI_DRIVER_TRACE_CBID_cuD3D9UnregisterVertexBuffer = 173, + CUPTI_DRIVER_TRACE_CBID_cuGLCtxCreate = 174, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsGLRegisterBuffer = 175, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsGLRegisterImage = 176, + CUPTI_DRIVER_TRACE_CBID_cuWGLGetDevice = 177, + CUPTI_DRIVER_TRACE_CBID_cuGLInit = 178, + CUPTI_DRIVER_TRACE_CBID_cuGLRegisterBufferObject = 179, + CUPTI_DRIVER_TRACE_CBID_cuGLMapBufferObject = 180, + CUPTI_DRIVER_TRACE_CBID_cuGLUnmapBufferObject = 181, + CUPTI_DRIVER_TRACE_CBID_cuGLUnregisterBufferObject = 182, + CUPTI_DRIVER_TRACE_CBID_cuGLSetBufferObjectMapFlags = 183, + CUPTI_DRIVER_TRACE_CBID_cuGLMapBufferObjectAsync = 184, + CUPTI_DRIVER_TRACE_CBID_cuGLUnmapBufferObjectAsync = 185, + CUPTI_DRIVER_TRACE_CBID_cuVDPAUGetDevice = 186, + CUPTI_DRIVER_TRACE_CBID_cuVDPAUCtxCreate = 187, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsVDPAURegisterVideoSurface = 188, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsVDPAURegisterOutputSurface = 189, + CUPTI_DRIVER_TRACE_CBID_cuModuleGetSurfRef = 190, + CUPTI_DRIVER_TRACE_CBID_cuSurfRefCreate = 191, + CUPTI_DRIVER_TRACE_CBID_cuSurfRefDestroy = 192, + CUPTI_DRIVER_TRACE_CBID_cuSurfRefSetFormat = 193, + CUPTI_DRIVER_TRACE_CBID_cuSurfRefSetArray = 194, + CUPTI_DRIVER_TRACE_CBID_cuSurfRefGetFormat = 195, + CUPTI_DRIVER_TRACE_CBID_cuSurfRefGetArray = 196, + CUPTI_DRIVER_TRACE_CBID_cu64DeviceTotalMem = 197, + CUPTI_DRIVER_TRACE_CBID_cu64D3D10ResourceGetMappedPointer = 198, + CUPTI_DRIVER_TRACE_CBID_cu64D3D10ResourceGetMappedSize = 199, + CUPTI_DRIVER_TRACE_CBID_cu64D3D10ResourceGetMappedPitch = 200, + CUPTI_DRIVER_TRACE_CBID_cu64D3D10ResourceGetSurfaceDimensions = 201, + CUPTI_DRIVER_TRACE_CBID_cu64D3D9ResourceGetSurfaceDimensions = 202, + CUPTI_DRIVER_TRACE_CBID_cu64D3D9ResourceGetMappedPointer = 203, + CUPTI_DRIVER_TRACE_CBID_cu64D3D9ResourceGetMappedSize = 204, + CUPTI_DRIVER_TRACE_CBID_cu64D3D9ResourceGetMappedPitch = 205, + CUPTI_DRIVER_TRACE_CBID_cu64D3D9MapVertexBuffer = 206, + CUPTI_DRIVER_TRACE_CBID_cu64GLMapBufferObject = 207, + CUPTI_DRIVER_TRACE_CBID_cu64GLMapBufferObjectAsync = 208, + CUPTI_DRIVER_TRACE_CBID_cuD3D11GetDevices = 209, + CUPTI_DRIVER_TRACE_CBID_cuD3D11CtxCreateOnDevice = 210, + CUPTI_DRIVER_TRACE_CBID_cuD3D10GetDevices = 211, + CUPTI_DRIVER_TRACE_CBID_cuD3D10CtxCreateOnDevice = 212, + CUPTI_DRIVER_TRACE_CBID_cuD3D9GetDevices = 213, + CUPTI_DRIVER_TRACE_CBID_cuD3D9CtxCreateOnDevice = 214, + CUPTI_DRIVER_TRACE_CBID_cu64MemHostAlloc = 215, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD8Async = 216, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD8Async = 217, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD16Async = 218, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD16Async = 219, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD32Async = 220, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD32Async = 221, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D8Async = 222, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD2D8Async = 223, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D16Async = 224, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD2D16Async = 225, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D32Async = 226, + CUPTI_DRIVER_TRACE_CBID_cu64MemsetD2D32Async = 227, + CUPTI_DRIVER_TRACE_CBID_cu64ArrayCreate = 228, + CUPTI_DRIVER_TRACE_CBID_cu64ArrayGetDescriptor = 229, + CUPTI_DRIVER_TRACE_CBID_cu64Array3DCreate = 230, + CUPTI_DRIVER_TRACE_CBID_cu64Array3DGetDescriptor = 231, + CUPTI_DRIVER_TRACE_CBID_cu64Memcpy2D = 232, + CUPTI_DRIVER_TRACE_CBID_cu64Memcpy2DUnaligned = 233, + CUPTI_DRIVER_TRACE_CBID_cu64Memcpy2DAsync = 234, + CUPTI_DRIVER_TRACE_CBID_cuCtxCreate_v2 = 235, + CUPTI_DRIVER_TRACE_CBID_cuD3D10CtxCreate_v2 = 236, + CUPTI_DRIVER_TRACE_CBID_cuD3D11CtxCreate_v2 = 237, + CUPTI_DRIVER_TRACE_CBID_cuD3D9CtxCreate_v2 = 238, + CUPTI_DRIVER_TRACE_CBID_cuGLCtxCreate_v2 = 239, + CUPTI_DRIVER_TRACE_CBID_cuVDPAUCtxCreate_v2 = 240, + CUPTI_DRIVER_TRACE_CBID_cuModuleGetGlobal_v2 = 241, + CUPTI_DRIVER_TRACE_CBID_cuMemGetInfo_v2 = 242, + CUPTI_DRIVER_TRACE_CBID_cuMemAlloc_v2 = 243, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocPitch_v2 = 244, + CUPTI_DRIVER_TRACE_CBID_cuMemFree_v2 = 245, + CUPTI_DRIVER_TRACE_CBID_cuMemGetAddressRange_v2 = 246, + CUPTI_DRIVER_TRACE_CBID_cuMemHostGetDevicePointer_v2 = 247, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy_v2 = 248, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD8_v2 = 249, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD16_v2 = 250, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD32_v2 = 251, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D8_v2 = 252, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D16_v2 = 253, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D32_v2 = 254, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetAddress_v2 = 255, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetAddress2D_v2 = 256, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetAddress_v2 = 257, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsResourceGetMappedPointer_v2 = 258, + CUPTI_DRIVER_TRACE_CBID_cuDeviceTotalMem_v2 = 259, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetMappedPointer_v2 = 260, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetMappedSize_v2 = 261, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetMappedPitch_v2 = 262, + CUPTI_DRIVER_TRACE_CBID_cuD3D10ResourceGetSurfaceDimensions_v2 = 263, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetSurfaceDimensions_v2 = 264, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetMappedPointer_v2 = 265, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetMappedSize_v2 = 266, + CUPTI_DRIVER_TRACE_CBID_cuD3D9ResourceGetMappedPitch_v2 = 267, + CUPTI_DRIVER_TRACE_CBID_cuD3D9MapVertexBuffer_v2 = 268, + CUPTI_DRIVER_TRACE_CBID_cuGLMapBufferObject_v2 = 269, + CUPTI_DRIVER_TRACE_CBID_cuGLMapBufferObjectAsync_v2 = 270, + CUPTI_DRIVER_TRACE_CBID_cuMemHostAlloc_v2 = 271, + CUPTI_DRIVER_TRACE_CBID_cuArrayCreate_v2 = 272, + CUPTI_DRIVER_TRACE_CBID_cuArrayGetDescriptor_v2 = 273, + CUPTI_DRIVER_TRACE_CBID_cuArray3DCreate_v2 = 274, + CUPTI_DRIVER_TRACE_CBID_cuArray3DGetDescriptor_v2 = 275, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoD_v2 = 276, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoDAsync_v2 = 277, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoH_v2 = 278, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoHAsync_v2 = 279, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoD_v2 = 280, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoDAsync_v2 = 281, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoH_v2 = 282, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoHAsync_v2 = 283, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoD_v2 = 284, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoA_v2 = 285, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoA_v2 = 286, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2D_v2 = 287, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2DUnaligned_v2 = 288, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2DAsync_v2 = 289, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3D_v2 = 290, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DAsync_v2 = 291, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoA_v2 = 292, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoAAsync_v2 = 293, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocHost_v2 = 294, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitEvent = 295, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetApiVersion = 296, + CUPTI_DRIVER_TRACE_CBID_cuD3D10GetDirect3DDevice = 297, + CUPTI_DRIVER_TRACE_CBID_cuD3D11GetDirect3DDevice = 298, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetCacheConfig = 299, + CUPTI_DRIVER_TRACE_CBID_cuCtxSetCacheConfig = 300, + CUPTI_DRIVER_TRACE_CBID_cuMemHostRegister = 301, + CUPTI_DRIVER_TRACE_CBID_cuMemHostUnregister = 302, + CUPTI_DRIVER_TRACE_CBID_cuCtxSetCurrent = 303, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetCurrent = 304, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy = 305, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAsync = 306, + CUPTI_DRIVER_TRACE_CBID_cuLaunchKernel = 307, + CUPTI_DRIVER_TRACE_CBID_cuProfilerStart = 308, + CUPTI_DRIVER_TRACE_CBID_cuProfilerStop = 309, + CUPTI_DRIVER_TRACE_CBID_cuPointerGetAttribute = 310, + CUPTI_DRIVER_TRACE_CBID_cuProfilerInitialize = 311, + CUPTI_DRIVER_TRACE_CBID_cuDeviceCanAccessPeer = 312, + CUPTI_DRIVER_TRACE_CBID_cuCtxEnablePeerAccess = 313, + CUPTI_DRIVER_TRACE_CBID_cuCtxDisablePeerAccess = 314, + CUPTI_DRIVER_TRACE_CBID_cuMemPeerRegister = 315, + CUPTI_DRIVER_TRACE_CBID_cuMemPeerUnregister = 316, + CUPTI_DRIVER_TRACE_CBID_cuMemPeerGetDevicePointer = 317, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyPeer = 318, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyPeerAsync = 319, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DPeer = 320, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DPeerAsync = 321, + CUPTI_DRIVER_TRACE_CBID_cuCtxDestroy_v2 = 322, + CUPTI_DRIVER_TRACE_CBID_cuCtxPushCurrent_v2 = 323, + CUPTI_DRIVER_TRACE_CBID_cuCtxPopCurrent_v2 = 324, + CUPTI_DRIVER_TRACE_CBID_cuEventDestroy_v2 = 325, + CUPTI_DRIVER_TRACE_CBID_cuStreamDestroy_v2 = 326, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetAddress2D_v3 = 327, + CUPTI_DRIVER_TRACE_CBID_cuIpcGetMemHandle = 328, + CUPTI_DRIVER_TRACE_CBID_cuIpcOpenMemHandle = 329, + CUPTI_DRIVER_TRACE_CBID_cuIpcCloseMemHandle = 330, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetByPCIBusId = 331, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetPCIBusId = 332, + CUPTI_DRIVER_TRACE_CBID_cuGLGetDevices = 333, + CUPTI_DRIVER_TRACE_CBID_cuIpcGetEventHandle = 334, + CUPTI_DRIVER_TRACE_CBID_cuIpcOpenEventHandle = 335, + CUPTI_DRIVER_TRACE_CBID_cuCtxSetSharedMemConfig = 336, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetSharedMemConfig = 337, + CUPTI_DRIVER_TRACE_CBID_cuFuncSetSharedMemConfig = 338, + CUPTI_DRIVER_TRACE_CBID_cuTexObjectCreate = 339, + CUPTI_DRIVER_TRACE_CBID_cuTexObjectDestroy = 340, + CUPTI_DRIVER_TRACE_CBID_cuTexObjectGetResourceDesc = 341, + CUPTI_DRIVER_TRACE_CBID_cuTexObjectGetTextureDesc = 342, + CUPTI_DRIVER_TRACE_CBID_cuSurfObjectCreate = 343, + CUPTI_DRIVER_TRACE_CBID_cuSurfObjectDestroy = 344, + CUPTI_DRIVER_TRACE_CBID_cuSurfObjectGetResourceDesc = 345, + CUPTI_DRIVER_TRACE_CBID_cuStreamAddCallback = 346, + CUPTI_DRIVER_TRACE_CBID_cuMipmappedArrayCreate = 347, + CUPTI_DRIVER_TRACE_CBID_cuMipmappedArrayGetLevel = 348, + CUPTI_DRIVER_TRACE_CBID_cuMipmappedArrayDestroy = 349, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetMipmappedArray = 350, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetMipmapFilterMode = 351, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetMipmapLevelBias = 352, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetMipmapLevelClamp = 353, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetMaxAnisotropy = 354, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetMipmappedArray = 355, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetMipmapFilterMode = 356, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetMipmapLevelBias = 357, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetMipmapLevelClamp = 358, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetMaxAnisotropy = 359, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsResourceGetMappedMipmappedArray = 360, + CUPTI_DRIVER_TRACE_CBID_cuTexObjectGetResourceViewDesc = 361, + CUPTI_DRIVER_TRACE_CBID_cuLinkCreate = 362, + CUPTI_DRIVER_TRACE_CBID_cuLinkAddData = 363, + CUPTI_DRIVER_TRACE_CBID_cuLinkAddFile = 364, + CUPTI_DRIVER_TRACE_CBID_cuLinkComplete = 365, + CUPTI_DRIVER_TRACE_CBID_cuLinkDestroy = 366, + CUPTI_DRIVER_TRACE_CBID_cuStreamCreateWithPriority = 367, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetPriority = 368, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetFlags = 369, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetStreamPriorityRange = 370, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocManaged = 371, + CUPTI_DRIVER_TRACE_CBID_cuGetErrorString = 372, + CUPTI_DRIVER_TRACE_CBID_cuGetErrorName = 373, + CUPTI_DRIVER_TRACE_CBID_cuOccupancyMaxActiveBlocksPerMultiprocessor = 374, + CUPTI_DRIVER_TRACE_CBID_cuCompilePtx = 375, + CUPTI_DRIVER_TRACE_CBID_cuBinaryFree = 376, + CUPTI_DRIVER_TRACE_CBID_cuStreamAttachMemAsync = 377, + CUPTI_DRIVER_TRACE_CBID_cuPointerSetAttribute = 378, + CUPTI_DRIVER_TRACE_CBID_cuMemHostRegister_v2 = 379, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsResourceSetMapFlags_v2 = 380, + CUPTI_DRIVER_TRACE_CBID_cuLinkCreate_v2 = 381, + CUPTI_DRIVER_TRACE_CBID_cuLinkAddData_v2 = 382, + CUPTI_DRIVER_TRACE_CBID_cuLinkAddFile_v2 = 383, + CUPTI_DRIVER_TRACE_CBID_cuOccupancyMaxPotentialBlockSize = 384, + CUPTI_DRIVER_TRACE_CBID_cuGLGetDevices_v2 = 385, + CUPTI_DRIVER_TRACE_CBID_cuDevicePrimaryCtxRetain = 386, + CUPTI_DRIVER_TRACE_CBID_cuDevicePrimaryCtxRelease = 387, + CUPTI_DRIVER_TRACE_CBID_cuDevicePrimaryCtxSetFlags = 388, + CUPTI_DRIVER_TRACE_CBID_cuDevicePrimaryCtxReset = 389, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsEGLRegisterImage = 390, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetFlags = 391, + CUPTI_DRIVER_TRACE_CBID_cuDevicePrimaryCtxGetState = 392, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamConsumerConnect = 393, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamConsumerDisconnect = 394, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamConsumerAcquireFrame = 395, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamConsumerReleaseFrame = 396, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoD_v2_ptds = 397, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoH_v2_ptds = 398, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoD_v2_ptds = 399, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoA_v2_ptds = 400, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoD_v2_ptds = 401, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoA_v2_ptds = 402, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoH_v2_ptds = 403, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoA_v2_ptds = 404, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2D_v2_ptds = 405, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2DUnaligned_v2_ptds = 406, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3D_v2_ptds = 407, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy_ptds = 408, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyPeer_ptds = 409, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DPeer_ptds = 410, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD8_v2_ptds = 411, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD16_v2_ptds = 412, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD32_v2_ptds = 413, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D8_v2_ptds = 414, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D16_v2_ptds = 415, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D32_v2_ptds = 416, + CUPTI_DRIVER_TRACE_CBID_cuGLMapBufferObject_v2_ptds = 417, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAsync_ptsz = 418, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoAAsync_v2_ptsz = 419, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyAtoHAsync_v2_ptsz = 420, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyHtoDAsync_v2_ptsz = 421, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoHAsync_v2_ptsz = 422, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyDtoDAsync_v2_ptsz = 423, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy2DAsync_v2_ptsz = 424, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DAsync_v2_ptsz = 425, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyPeerAsync_ptsz = 426, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DPeerAsync_ptsz = 427, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD8Async_ptsz = 428, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD16Async_ptsz = 429, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD32Async_ptsz = 430, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D8Async_ptsz = 431, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D16Async_ptsz = 432, + CUPTI_DRIVER_TRACE_CBID_cuMemsetD2D32Async_ptsz = 433, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetPriority_ptsz = 434, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetFlags_ptsz = 435, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitEvent_ptsz = 436, + CUPTI_DRIVER_TRACE_CBID_cuStreamAddCallback_ptsz = 437, + CUPTI_DRIVER_TRACE_CBID_cuStreamAttachMemAsync_ptsz = 438, + CUPTI_DRIVER_TRACE_CBID_cuStreamQuery_ptsz = 439, + CUPTI_DRIVER_TRACE_CBID_cuStreamSynchronize_ptsz = 440, + CUPTI_DRIVER_TRACE_CBID_cuEventRecord_ptsz = 441, + CUPTI_DRIVER_TRACE_CBID_cuLaunchKernel_ptsz = 442, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsMapResources_ptsz = 443, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsUnmapResources_ptsz = 444, + CUPTI_DRIVER_TRACE_CBID_cuGLMapBufferObjectAsync_v2_ptsz = 445, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamProducerConnect = 446, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamProducerDisconnect = 447, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamProducerPresentFrame = 448, + CUPTI_DRIVER_TRACE_CBID_cuGraphicsResourceGetMappedEglFrame = 449, + CUPTI_DRIVER_TRACE_CBID_cuPointerGetAttributes = 450, + CUPTI_DRIVER_TRACE_CBID_cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags = 451, + CUPTI_DRIVER_TRACE_CBID_cuOccupancyMaxPotentialBlockSizeWithFlags = 452, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamProducerReturnFrame = 453, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetP2PAttribute = 454, + CUPTI_DRIVER_TRACE_CBID_cuTexRefSetBorderColor = 455, + CUPTI_DRIVER_TRACE_CBID_cuTexRefGetBorderColor = 456, + CUPTI_DRIVER_TRACE_CBID_cuMemAdvise = 457, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitValue32 = 458, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitValue32_ptsz = 459, + CUPTI_DRIVER_TRACE_CBID_cuStreamWriteValue32 = 460, + CUPTI_DRIVER_TRACE_CBID_cuStreamWriteValue32_ptsz = 461, + CUPTI_DRIVER_TRACE_CBID_cuStreamBatchMemOp = 462, + CUPTI_DRIVER_TRACE_CBID_cuStreamBatchMemOp_ptsz = 463, + CUPTI_DRIVER_TRACE_CBID_cuNVNbufferGetPointer = 464, + CUPTI_DRIVER_TRACE_CBID_cuNVNtextureGetArray = 465, + CUPTI_DRIVER_TRACE_CBID_cuNNSetAllocator = 466, + CUPTI_DRIVER_TRACE_CBID_cuMemPrefetchAsync = 467, + CUPTI_DRIVER_TRACE_CBID_cuMemPrefetchAsync_ptsz = 468, + CUPTI_DRIVER_TRACE_CBID_cuEventCreateFromNVNSync = 469, + CUPTI_DRIVER_TRACE_CBID_cuEGLStreamConsumerConnectWithFlags = 470, + CUPTI_DRIVER_TRACE_CBID_cuMemRangeGetAttribute = 471, + CUPTI_DRIVER_TRACE_CBID_cuMemRangeGetAttributes = 472, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitValue64 = 473, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitValue64_ptsz = 474, + CUPTI_DRIVER_TRACE_CBID_cuStreamWriteValue64 = 475, + CUPTI_DRIVER_TRACE_CBID_cuStreamWriteValue64_ptsz = 476, + CUPTI_DRIVER_TRACE_CBID_cuLaunchCooperativeKernel = 477, + CUPTI_DRIVER_TRACE_CBID_cuLaunchCooperativeKernel_ptsz = 478, + CUPTI_DRIVER_TRACE_CBID_cuEventCreateFromEGLSync = 479, + CUPTI_DRIVER_TRACE_CBID_cuLaunchCooperativeKernelMultiDevice = 480, + CUPTI_DRIVER_TRACE_CBID_cuFuncSetAttribute = 481, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetUuid = 482, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCtx = 483, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCtx_ptsz = 484, + CUPTI_DRIVER_TRACE_CBID_cuImportExternalMemory = 485, + CUPTI_DRIVER_TRACE_CBID_cuExternalMemoryGetMappedBuffer = 486, + CUPTI_DRIVER_TRACE_CBID_cuExternalMemoryGetMappedMipmappedArray = 487, + CUPTI_DRIVER_TRACE_CBID_cuDestroyExternalMemory = 488, + CUPTI_DRIVER_TRACE_CBID_cuImportExternalSemaphore = 489, + CUPTI_DRIVER_TRACE_CBID_cuSignalExternalSemaphoresAsync = 490, + CUPTI_DRIVER_TRACE_CBID_cuSignalExternalSemaphoresAsync_ptsz = 491, + CUPTI_DRIVER_TRACE_CBID_cuWaitExternalSemaphoresAsync = 492, + CUPTI_DRIVER_TRACE_CBID_cuWaitExternalSemaphoresAsync_ptsz = 493, + CUPTI_DRIVER_TRACE_CBID_cuDestroyExternalSemaphore = 494, + CUPTI_DRIVER_TRACE_CBID_cuStreamBeginCapture = 495, + CUPTI_DRIVER_TRACE_CBID_cuStreamBeginCapture_ptsz = 496, + CUPTI_DRIVER_TRACE_CBID_cuStreamEndCapture = 497, + CUPTI_DRIVER_TRACE_CBID_cuStreamEndCapture_ptsz = 498, + CUPTI_DRIVER_TRACE_CBID_cuStreamIsCapturing = 499, + CUPTI_DRIVER_TRACE_CBID_cuStreamIsCapturing_ptsz = 500, + CUPTI_DRIVER_TRACE_CBID_cuGraphCreate = 501, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddKernelNode = 502, + CUPTI_DRIVER_TRACE_CBID_cuGraphKernelNodeGetParams = 503, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddMemcpyNode = 504, + CUPTI_DRIVER_TRACE_CBID_cuGraphMemcpyNodeGetParams = 505, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddMemsetNode = 506, + CUPTI_DRIVER_TRACE_CBID_cuGraphMemsetNodeGetParams = 507, + CUPTI_DRIVER_TRACE_CBID_cuGraphMemsetNodeSetParams = 508, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeGetType = 509, + CUPTI_DRIVER_TRACE_CBID_cuGraphGetRootNodes = 510, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeGetDependencies = 511, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeGetDependentNodes = 512, + CUPTI_DRIVER_TRACE_CBID_cuGraphInstantiate = 513, + CUPTI_DRIVER_TRACE_CBID_cuGraphLaunch = 514, + CUPTI_DRIVER_TRACE_CBID_cuGraphLaunch_ptsz = 515, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecDestroy = 516, + CUPTI_DRIVER_TRACE_CBID_cuGraphDestroy = 517, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddDependencies = 518, + CUPTI_DRIVER_TRACE_CBID_cuGraphRemoveDependencies = 519, + CUPTI_DRIVER_TRACE_CBID_cuGraphMemcpyNodeSetParams = 520, + CUPTI_DRIVER_TRACE_CBID_cuGraphKernelNodeSetParams = 521, + CUPTI_DRIVER_TRACE_CBID_cuGraphDestroyNode = 522, + CUPTI_DRIVER_TRACE_CBID_cuGraphClone = 523, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeFindInClone = 524, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddChildGraphNode = 525, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddEmptyNode = 526, + CUPTI_DRIVER_TRACE_CBID_cuLaunchHostFunc = 527, + CUPTI_DRIVER_TRACE_CBID_cuLaunchHostFunc_ptsz = 528, + CUPTI_DRIVER_TRACE_CBID_cuGraphChildGraphNodeGetGraph = 529, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddHostNode = 530, + CUPTI_DRIVER_TRACE_CBID_cuGraphHostNodeGetParams = 531, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetLuid = 532, + CUPTI_DRIVER_TRACE_CBID_cuGraphHostNodeSetParams = 533, + CUPTI_DRIVER_TRACE_CBID_cuGraphGetNodes = 534, + CUPTI_DRIVER_TRACE_CBID_cuGraphGetEdges = 535, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCaptureInfo = 536, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCaptureInfo_ptsz = 537, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecKernelNodeSetParams = 538, + CUPTI_DRIVER_TRACE_CBID_cuStreamBeginCapture_v2 = 539, + CUPTI_DRIVER_TRACE_CBID_cuStreamBeginCapture_v2_ptsz = 540, + CUPTI_DRIVER_TRACE_CBID_cuThreadExchangeStreamCaptureMode = 541, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetNvSciSyncAttributes = 542, + CUPTI_DRIVER_TRACE_CBID_cuOccupancyAvailableDynamicSMemPerBlock = 543, + CUPTI_DRIVER_TRACE_CBID_cuDevicePrimaryCtxRelease_v2 = 544, + CUPTI_DRIVER_TRACE_CBID_cuDevicePrimaryCtxReset_v2 = 545, + CUPTI_DRIVER_TRACE_CBID_cuDevicePrimaryCtxSetFlags_v2 = 546, + CUPTI_DRIVER_TRACE_CBID_cuMemAddressReserve = 547, + CUPTI_DRIVER_TRACE_CBID_cuMemAddressFree = 548, + CUPTI_DRIVER_TRACE_CBID_cuMemCreate = 549, + CUPTI_DRIVER_TRACE_CBID_cuMemRelease = 550, + CUPTI_DRIVER_TRACE_CBID_cuMemMap = 551, + CUPTI_DRIVER_TRACE_CBID_cuMemUnmap = 552, + CUPTI_DRIVER_TRACE_CBID_cuMemSetAccess = 553, + CUPTI_DRIVER_TRACE_CBID_cuMemExportToShareableHandle = 554, + CUPTI_DRIVER_TRACE_CBID_cuMemImportFromShareableHandle = 555, + CUPTI_DRIVER_TRACE_CBID_cuMemGetAllocationGranularity = 556, + CUPTI_DRIVER_TRACE_CBID_cuMemGetAllocationPropertiesFromHandle = 557, + CUPTI_DRIVER_TRACE_CBID_cuMemGetAccess = 558, + CUPTI_DRIVER_TRACE_CBID_cuStreamSetFlags = 559, + CUPTI_DRIVER_TRACE_CBID_cuStreamSetFlags_ptsz = 560, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecUpdate = 561, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecMemcpyNodeSetParams = 562, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecMemsetNodeSetParams = 563, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecHostNodeSetParams = 564, + CUPTI_DRIVER_TRACE_CBID_cuMemRetainAllocationHandle = 565, + CUPTI_DRIVER_TRACE_CBID_cuFuncGetModule = 566, + CUPTI_DRIVER_TRACE_CBID_cuIpcOpenMemHandle_v2 = 567, + CUPTI_DRIVER_TRACE_CBID_cuCtxResetPersistingL2Cache = 568, + CUPTI_DRIVER_TRACE_CBID_cuGraphKernelNodeCopyAttributes = 569, + CUPTI_DRIVER_TRACE_CBID_cuGraphKernelNodeGetAttribute = 570, + CUPTI_DRIVER_TRACE_CBID_cuGraphKernelNodeSetAttribute = 571, + CUPTI_DRIVER_TRACE_CBID_cuStreamCopyAttributes = 572, + CUPTI_DRIVER_TRACE_CBID_cuStreamCopyAttributes_ptsz = 573, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetAttribute = 574, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetAttribute_ptsz = 575, + CUPTI_DRIVER_TRACE_CBID_cuStreamSetAttribute = 576, + CUPTI_DRIVER_TRACE_CBID_cuStreamSetAttribute_ptsz = 577, + CUPTI_DRIVER_TRACE_CBID_cuGraphInstantiate_v2 = 578, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetTexture1DLinearMaxWidth = 579, + CUPTI_DRIVER_TRACE_CBID_cuGraphUpload = 580, + CUPTI_DRIVER_TRACE_CBID_cuGraphUpload_ptsz = 581, + CUPTI_DRIVER_TRACE_CBID_cuArrayGetSparseProperties = 582, + CUPTI_DRIVER_TRACE_CBID_cuMipmappedArrayGetSparseProperties = 583, + CUPTI_DRIVER_TRACE_CBID_cuMemMapArrayAsync = 584, + CUPTI_DRIVER_TRACE_CBID_cuMemMapArrayAsync_ptsz = 585, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecChildGraphNodeSetParams = 586, + CUPTI_DRIVER_TRACE_CBID_cuEventRecordWithFlags = 587, + CUPTI_DRIVER_TRACE_CBID_cuEventRecordWithFlags_ptsz = 588, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddEventRecordNode = 589, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddEventWaitNode = 590, + CUPTI_DRIVER_TRACE_CBID_cuGraphEventRecordNodeGetEvent = 591, + CUPTI_DRIVER_TRACE_CBID_cuGraphEventWaitNodeGetEvent = 592, + CUPTI_DRIVER_TRACE_CBID_cuGraphEventRecordNodeSetEvent = 593, + CUPTI_DRIVER_TRACE_CBID_cuGraphEventWaitNodeSetEvent = 594, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecEventRecordNodeSetEvent = 595, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecEventWaitNodeSetEvent = 596, + CUPTI_DRIVER_TRACE_CBID_cuArrayGetPlane = 597, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocAsync = 598, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocAsync_ptsz = 599, + CUPTI_DRIVER_TRACE_CBID_cuMemFreeAsync = 600, + CUPTI_DRIVER_TRACE_CBID_cuMemFreeAsync_ptsz = 601, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolTrimTo = 602, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolSetAttribute = 603, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolGetAttribute = 604, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolSetAccess = 605, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetDefaultMemPool = 606, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolCreate = 607, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolDestroy = 608, + CUPTI_DRIVER_TRACE_CBID_cuDeviceSetMemPool = 609, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetMemPool = 610, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocFromPoolAsync = 611, + CUPTI_DRIVER_TRACE_CBID_cuMemAllocFromPoolAsync_ptsz = 612, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolExportToShareableHandle = 613, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolImportFromShareableHandle = 614, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolExportPointer = 615, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolImportPointer = 616, + CUPTI_DRIVER_TRACE_CBID_cuMemPoolGetAccess = 617, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddExternalSemaphoresSignalNode = 618, + CUPTI_DRIVER_TRACE_CBID_cuGraphExternalSemaphoresSignalNodeGetParams = 619, + CUPTI_DRIVER_TRACE_CBID_cuGraphExternalSemaphoresSignalNodeSetParams = 620, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddExternalSemaphoresWaitNode = 621, + CUPTI_DRIVER_TRACE_CBID_cuGraphExternalSemaphoresWaitNodeGetParams = 622, + CUPTI_DRIVER_TRACE_CBID_cuGraphExternalSemaphoresWaitNodeSetParams = 623, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecExternalSemaphoresSignalNodeSetParams = 624, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecExternalSemaphoresWaitNodeSetParams = 625, + CUPTI_DRIVER_TRACE_CBID_cuGetProcAddress = 626, + CUPTI_DRIVER_TRACE_CBID_cuFlushGPUDirectRDMAWrites = 627, + CUPTI_DRIVER_TRACE_CBID_cuGraphDebugDotPrint = 628, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCaptureInfo_v2 = 629, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCaptureInfo_v2_ptsz = 630, + CUPTI_DRIVER_TRACE_CBID_cuStreamUpdateCaptureDependencies = 631, + CUPTI_DRIVER_TRACE_CBID_cuStreamUpdateCaptureDependencies_ptsz = 632, + CUPTI_DRIVER_TRACE_CBID_cuUserObjectCreate = 633, + CUPTI_DRIVER_TRACE_CBID_cuUserObjectRetain = 634, + CUPTI_DRIVER_TRACE_CBID_cuUserObjectRelease = 635, + CUPTI_DRIVER_TRACE_CBID_cuGraphRetainUserObject = 636, + CUPTI_DRIVER_TRACE_CBID_cuGraphReleaseUserObject = 637, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddMemAllocNode = 638, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddMemFreeNode = 639, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGraphMemTrim = 640, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetGraphMemAttribute = 641, + CUPTI_DRIVER_TRACE_CBID_cuDeviceSetGraphMemAttribute = 642, + CUPTI_DRIVER_TRACE_CBID_cuGraphInstantiateWithFlags = 643, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetExecAffinitySupport = 644, + CUPTI_DRIVER_TRACE_CBID_cuCtxCreate_v3 = 645, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetExecAffinity = 646, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetUuid_v2 = 647, + CUPTI_DRIVER_TRACE_CBID_cuGraphMemAllocNodeGetParams = 648, + CUPTI_DRIVER_TRACE_CBID_cuGraphMemFreeNodeGetParams = 649, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeSetEnabled = 650, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeGetEnabled = 651, + CUPTI_DRIVER_TRACE_CBID_cuLaunchKernelEx = 652, + CUPTI_DRIVER_TRACE_CBID_cuLaunchKernelEx_ptsz = 653, + CUPTI_DRIVER_TRACE_CBID_cuArrayGetMemoryRequirements = 654, + CUPTI_DRIVER_TRACE_CBID_cuMipmappedArrayGetMemoryRequirements = 655, + CUPTI_DRIVER_TRACE_CBID_cuGraphInstantiateWithParams = 656, + CUPTI_DRIVER_TRACE_CBID_cuGraphInstantiateWithParams_ptsz = 657, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecGetFlags = 658, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitValue32_v2 = 659, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitValue32_v2_ptsz = 660, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitValue64_v2 = 661, + CUPTI_DRIVER_TRACE_CBID_cuStreamWaitValue64_v2_ptsz = 662, + CUPTI_DRIVER_TRACE_CBID_cuStreamWriteValue32_v2 = 663, + CUPTI_DRIVER_TRACE_CBID_cuStreamWriteValue32_v2_ptsz = 664, + CUPTI_DRIVER_TRACE_CBID_cuStreamWriteValue64_v2 = 665, + CUPTI_DRIVER_TRACE_CBID_cuStreamWriteValue64_v2_ptsz = 666, + CUPTI_DRIVER_TRACE_CBID_cuStreamBatchMemOp_v2 = 667, + CUPTI_DRIVER_TRACE_CBID_cuStreamBatchMemOp_v2_ptsz = 668, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddBatchMemOpNode = 669, + CUPTI_DRIVER_TRACE_CBID_cuGraphBatchMemOpNodeGetParams = 670, + CUPTI_DRIVER_TRACE_CBID_cuGraphBatchMemOpNodeSetParams = 671, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecBatchMemOpNodeSetParams = 672, + CUPTI_DRIVER_TRACE_CBID_cuModuleGetLoadingMode = 673, + CUPTI_DRIVER_TRACE_CBID_cuMemGetHandleForAddressRange = 674, + CUPTI_DRIVER_TRACE_CBID_cuOccupancyMaxPotentialClusterSize = 675, + CUPTI_DRIVER_TRACE_CBID_cuOccupancyMaxActiveClusters = 676, + CUPTI_DRIVER_TRACE_CBID_cuGetProcAddress_v2 = 677, + CUPTI_DRIVER_TRACE_CBID_cuLibraryLoadData = 678, + CUPTI_DRIVER_TRACE_CBID_cuLibraryLoadFromFile = 679, + CUPTI_DRIVER_TRACE_CBID_cuLibraryUnload = 680, + CUPTI_DRIVER_TRACE_CBID_cuLibraryGetKernel = 681, + CUPTI_DRIVER_TRACE_CBID_cuLibraryGetModule = 682, + CUPTI_DRIVER_TRACE_CBID_cuKernelGetFunction = 683, + CUPTI_DRIVER_TRACE_CBID_cuLibraryGetGlobal = 684, + CUPTI_DRIVER_TRACE_CBID_cuLibraryGetManaged = 685, + CUPTI_DRIVER_TRACE_CBID_cuKernelGetAttribute = 686, + CUPTI_DRIVER_TRACE_CBID_cuKernelSetAttribute = 687, + CUPTI_DRIVER_TRACE_CBID_cuKernelSetCacheConfig = 688, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddKernelNode_v2 = 689, + CUPTI_DRIVER_TRACE_CBID_cuGraphKernelNodeGetParams_v2 = 690, + CUPTI_DRIVER_TRACE_CBID_cuGraphKernelNodeSetParams_v2 = 691, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecKernelNodeSetParams_v2 = 692, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetId = 693, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetId_ptsz = 694, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetId = 695, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecUpdate_v2 = 696, + CUPTI_DRIVER_TRACE_CBID_cuTensorMapEncodeTiled = 697, + CUPTI_DRIVER_TRACE_CBID_cuTensorMapEncodeIm2col = 698, + CUPTI_DRIVER_TRACE_CBID_cuTensorMapReplaceAddress = 699, + CUPTI_DRIVER_TRACE_CBID_cuLibraryGetUnifiedFunction = 700, + CUPTI_DRIVER_TRACE_CBID_cuCoredumpGetAttribute = 701, + CUPTI_DRIVER_TRACE_CBID_cuCoredumpGetAttributeGlobal = 702, + CUPTI_DRIVER_TRACE_CBID_cuCoredumpSetAttribute = 703, + CUPTI_DRIVER_TRACE_CBID_cuCoredumpSetAttributeGlobal = 704, + CUPTI_DRIVER_TRACE_CBID_cuCtxSetFlags = 705, + CUPTI_DRIVER_TRACE_CBID_cuMulticastCreate = 706, + CUPTI_DRIVER_TRACE_CBID_cuMulticastAddDevice = 707, + CUPTI_DRIVER_TRACE_CBID_cuMulticastBindMem = 708, + CUPTI_DRIVER_TRACE_CBID_cuMulticastBindAddr = 709, + CUPTI_DRIVER_TRACE_CBID_cuMulticastUnbind = 710, + CUPTI_DRIVER_TRACE_CBID_cuMulticastGetGranularity = 711, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddNode = 712, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeSetParams = 713, + CUPTI_DRIVER_TRACE_CBID_cuGraphExecNodeSetParams = 714, + CUPTI_DRIVER_TRACE_CBID_cuMemAdvise_v2 = 715, + CUPTI_DRIVER_TRACE_CBID_cuMemPrefetchAsync_v2 = 716, + CUPTI_DRIVER_TRACE_CBID_cuMemPrefetchAsync_v2_ptsz = 717, + CUPTI_DRIVER_TRACE_CBID_cuFuncGetName = 718, + CUPTI_DRIVER_TRACE_CBID_cuKernelGetName = 719, + CUPTI_DRIVER_TRACE_CBID_cuStreamBeginCaptureToGraph = 720, + CUPTI_DRIVER_TRACE_CBID_cuStreamBeginCaptureToGraph_ptsz = 721, + CUPTI_DRIVER_TRACE_CBID_cuGraphConditionalHandleCreate = 722, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddNode_v2 = 723, + CUPTI_DRIVER_TRACE_CBID_cuGraphGetEdges_v2 = 724, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeGetDependencies_v2 = 725, + CUPTI_DRIVER_TRACE_CBID_cuGraphNodeGetDependentNodes_v2 = 726, + CUPTI_DRIVER_TRACE_CBID_cuGraphAddDependencies_v2 = 727, + CUPTI_DRIVER_TRACE_CBID_cuGraphRemoveDependencies_v2 = 728, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCaptureInfo_v3 = 729, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCaptureInfo_v3_ptsz = 730, + CUPTI_DRIVER_TRACE_CBID_cuStreamUpdateCaptureDependencies_v2 = 731, + CUPTI_DRIVER_TRACE_CBID_cuStreamUpdateCaptureDependencies_v2_ptsz = 732, + CUPTI_DRIVER_TRACE_CBID_cuFuncGetParamInfo = 733, + CUPTI_DRIVER_TRACE_CBID_cuKernelGetParamInfo = 734, + CUPTI_DRIVER_TRACE_CBID_cuDeviceRegisterAsyncNotification = 735, + CUPTI_DRIVER_TRACE_CBID_cuDeviceUnregisterAsyncNotification = 736, + CUPTI_DRIVER_TRACE_CBID_cuModuleGetFunctionCount = 737, + CUPTI_DRIVER_TRACE_CBID_cuModuleEnumerateFunctions = 738, + CUPTI_DRIVER_TRACE_CBID_cuLibraryGetKernelCount = 739, + CUPTI_DRIVER_TRACE_CBID_cuLibraryEnumerateKernels = 740, + CUPTI_DRIVER_TRACE_CBID_cuFuncIsLoaded = 741, + CUPTI_DRIVER_TRACE_CBID_cuFuncLoad = 742, + CUPTI_DRIVER_TRACE_CBID_cuGreenCtxCreate = 743, + CUPTI_DRIVER_TRACE_CBID_cuGreenCtxDestroy = 744, + CUPTI_DRIVER_TRACE_CBID_cuDeviceGetDevResource = 745, + CUPTI_DRIVER_TRACE_CBID_cuCtxGetDevResource = 746, + CUPTI_DRIVER_TRACE_CBID_cuGreenCtxGetDevResource = 747, + CUPTI_DRIVER_TRACE_CBID_cuDevResourceGenerateDesc = 748, + CUPTI_DRIVER_TRACE_CBID_cuGreenCtxRecordEvent = 749, + CUPTI_DRIVER_TRACE_CBID_cuGreenCtxWaitEvent = 750, + CUPTI_DRIVER_TRACE_CBID_cuDevSmResourceSplitByCount = 751, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetGreenCtx = 752, + CUPTI_DRIVER_TRACE_CBID_cuCtxFromGreenCtx = 753, + CUPTI_DRIVER_TRACE_CBID_cuKernelGetLibrary = 754, + CUPTI_DRIVER_TRACE_CBID_cuCtxRecordEvent = 755, + CUPTI_DRIVER_TRACE_CBID_cuCtxWaitEvent = 756, + CUPTI_DRIVER_TRACE_CBID_cuCtxCreate_v4 = 757, + CUPTI_DRIVER_TRACE_CBID_cuGreenCtxStreamCreate = 758, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCtx_v2 = 759, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetCtx_v2_ptsz = 760, + CUPTI_DRIVER_TRACE_CBID_cuMemBatchDecompressAsync = 761, + CUPTI_DRIVER_TRACE_CBID_cuMemBatchDecompressAsync_ptsz = 762, + CUPTI_DRIVER_TRACE_CBID_cuLogsRegisterCallback = 763, + CUPTI_DRIVER_TRACE_CBID_cuLogsUnregisterCallback = 764, + CUPTI_DRIVER_TRACE_CBID_cuLogsCurrent = 765, + CUPTI_DRIVER_TRACE_CBID_cuLogsDumpToFile = 766, + CUPTI_DRIVER_TRACE_CBID_cuLogsDumpToMemory = 767, + CUPTI_DRIVER_TRACE_CBID_cuCheckpointProcessGetRestoreThreadId = 768, + CUPTI_DRIVER_TRACE_CBID_cuCheckpointProcessGetState = 769, + CUPTI_DRIVER_TRACE_CBID_cuCheckpointProcessLock = 770, + CUPTI_DRIVER_TRACE_CBID_cuCheckpointProcessCheckpoint = 771, + CUPTI_DRIVER_TRACE_CBID_cuCheckpointProcessRestore = 772, + CUPTI_DRIVER_TRACE_CBID_cuCheckpointProcessUnlock = 773, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetDevice = 774, + CUPTI_DRIVER_TRACE_CBID_cuStreamGetDevice_ptsz = 775, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyBatchAsync = 776, + CUPTI_DRIVER_TRACE_CBID_cuMemcpyBatchAsync_ptsz = 777, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DBatchAsync = 778, + CUPTI_DRIVER_TRACE_CBID_cuMemcpy3DBatchAsync_ptsz = 779, + CUPTI_DRIVER_TRACE_CBID_cuEventElapsedTime_v2 = 780, + CUPTI_DRIVER_TRACE_CBID_cuTensorMapEncodeIm2colWide = 781, + CUPTI_DRIVER_TRACE_CBID_SIZE = 782, + CUPTI_DRIVER_TRACE_CBID_FORCE_INT = 0x7fffffff +} CUpti_driver_api_trace_cbid; + +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_events.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_events.h new file mode 100644 index 0000000000000000000000000000000000000000..2e4aebc2a1389e8693f02df9b6e3be1e90490870 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_events.h @@ -0,0 +1,1349 @@ +/* + * Copyright 2010-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_EVENTS_H_) +#define _CUPTI_EVENTS_H_ + +#include +#include +#include +#include + +#ifndef CUPTIAPI +#ifdef _WIN32 +#define CUPTIAPI __stdcall +#else +#define CUPTIAPI +#endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_EVENT_API CUPTI Event API + * Functions, types, and enums that implement the CUPTI Event API. + * + * \note The CUPTI event API from the header cupti_events.h is not supported on devices + * with compute capability 7.5 and higher (i.e. Turing and later GPU architectures). + * This API is deprecated in CUDA 12.8 release and will be removed in a future CUDA release. + * This is replaced by the host profiling API in the header cupti_profiler_host.h and + * target profiling API in the header cupti_range_profiler.h which are supported on + * devices with compute capability 7.0 and higher (i.e. Volta and later GPU architectures). + * + * @{ + */ + +/** + * \brief ID for an event. + * + * An event represents a countable activity, action, or occurrence on + * the device. + */ +typedef uint32_t CUpti_EventID; + +/** + * \brief ID for an event domain. + * + * ID for an event domain. An event domain represents a group of + * related events. A device may have multiple instances of a domain, + * indicating that the device can simultaneously record multiple + * instances of each event within that domain. + */ +typedef uint32_t CUpti_EventDomainID; + +/** + * \brief A group of events. + * + * An event group is a collection of events that are managed + * together. All events in an event group must belong to the same + * domain. + */ +typedef void *CUpti_EventGroup; + +/** + * \brief Device class. + * + * Enumeration of device classes for device attribute + * CUPTI_DEVICE_ATTR_DEVICE_CLASS. + */ +typedef enum { + CUPTI_DEVICE_ATTR_DEVICE_CLASS_TESLA = 0, + CUPTI_DEVICE_ATTR_DEVICE_CLASS_QUADRO = 1, + CUPTI_DEVICE_ATTR_DEVICE_CLASS_GEFORCE = 2, + CUPTI_DEVICE_ATTR_DEVICE_CLASS_TEGRA = 3, +} CUpti_DeviceAttributeDeviceClass; + +/** + * \brief Device attributes. + * + * CUPTI device attributes. These attributes can be read using \ref + * cuptiDeviceGetAttribute. + */ +typedef enum { + /** + * Number of event IDs for a device. Value is a uint32_t. + */ + CUPTI_DEVICE_ATTR_MAX_EVENT_ID = 1, + /** + * Number of event domain IDs for a device. Value is a uint32_t. + */ + CUPTI_DEVICE_ATTR_MAX_EVENT_DOMAIN_ID = 2, + /** + * Get global memory bandwidth in Kbytes/sec. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_GLOBAL_MEMORY_BANDWIDTH = 3, + /** + * Get theoretical maximum number of instructions per cycle. Value + * is a uint32_t. + */ + CUPTI_DEVICE_ATTR_INSTRUCTION_PER_CYCLE = 4, + /** + * Get theoretical maximum number of single precision instructions + * that can be executed per second. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_INSTRUCTION_THROUGHPUT_SINGLE_PRECISION = 5, + /** + * Get number of frame buffers for device. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_MAX_FRAME_BUFFERS = 6, + /** + * Get PCIE link rate in Mega bits/sec for device. Return 0 if bus-type + * is non-PCIE. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_PCIE_LINK_RATE = 7, + /** + * Get PCIE link width for device. Return 0 if bus-type + * is non-PCIE. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_PCIE_LINK_WIDTH = 8, + /** + * Get PCIE generation for device. Return 0 if bus-type + * is non-PCIE. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_PCIE_GEN = 9, + /** + * Get the class for the device. Value is a + * CUpti_DeviceAttributeDeviceClass. + */ + CUPTI_DEVICE_ATTR_DEVICE_CLASS = 10, + /** + * Get the peak single precision flop per cycle. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_FLOP_SP_PER_CYCLE = 11, + /** + * Get the peak double precision flop per cycle. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_FLOP_DP_PER_CYCLE = 12, + /** + * Get number of L2 units. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_MAX_L2_UNITS = 13, + /** + * Get the maximum shared memory for the CU_FUNC_CACHE_PREFER_SHARED + * preference. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_MAX_SHARED_MEMORY_CACHE_CONFIG_PREFER_SHARED = 14, + /** + * Get the maximum shared memory for the CU_FUNC_CACHE_PREFER_L1 + * preference. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_MAX_SHARED_MEMORY_CACHE_CONFIG_PREFER_L1 = 15, + /** + * Get the maximum shared memory for the CU_FUNC_CACHE_PREFER_EQUAL + * preference. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_MAX_SHARED_MEMORY_CACHE_CONFIG_PREFER_EQUAL = 16, + /** + * Get the peak half precision flop per cycle. Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_FLOP_HP_PER_CYCLE = 17, + /** + * Check if Nvlink is connected to device. Returns 1, if at least one + * Nvlink is connected to the device, returns 0 otherwise. + * Value is a uint32_t. + */ + CUPTI_DEVICE_ATTR_NVLINK_PRESENT = 18, + /** + * Check if Nvlink is present between GPU and CPU. Returns Bandwidth, + * in Bytes/sec, if Nvlink is present, returns 0 otherwise. + * Value is a uint64_t. + */ + CUPTI_DEVICE_ATTR_GPU_CPU_NVLINK_BW = 19, + /** + * Check if NVSwitch is present in the underlying topology. + * Returns 1, if present, returns 0 otherwise. + * Value is a uint32_t. + */ + CUPTI_DEVICE_ATTR_NVSWITCH_PRESENT = 20, + CUPTI_DEVICE_ATTR_FORCE_INT = 0x7fffffff, +} CUpti_DeviceAttribute; + +/** + * \brief Event domain attributes. + * + * Event domain attributes. Except where noted, all the attributes can + * be read using either \ref cuptiDeviceGetEventDomainAttribute or + * \ref cuptiEventDomainGetAttribute. + */ +typedef enum { + /** + * Event domain name. Value is a null terminated const c-string. + */ + CUPTI_EVENT_DOMAIN_ATTR_NAME = 0, + /** + * Number of instances of the domain for which event counts will be + * collected. The domain may have additional instances that cannot + * be profiled (see CUPTI_EVENT_DOMAIN_ATTR_TOTAL_INSTANCE_COUNT). + * Can be read only with \ref + * cuptiDeviceGetEventDomainAttribute. Value is a uint32_t. + */ + CUPTI_EVENT_DOMAIN_ATTR_INSTANCE_COUNT = 1, + /** + * Total number of instances of the domain, including instances that + * cannot be profiled. Use CUPTI_EVENT_DOMAIN_ATTR_INSTANCE_COUNT + * to get the number of instances that can be profiled. Can be read + * only with \ref cuptiDeviceGetEventDomainAttribute. Value is a + * uint32_t. + */ + CUPTI_EVENT_DOMAIN_ATTR_TOTAL_INSTANCE_COUNT = 3, + /** + * Collection method used for events contained in the event domain. + * Value is a \ref CUpti_EventCollectionMethod. + */ + CUPTI_EVENT_DOMAIN_ATTR_COLLECTION_METHOD = 4, + + CUPTI_EVENT_DOMAIN_ATTR_FORCE_INT = 0x7fffffff, +} CUpti_EventDomainAttribute; + +/** + * \brief The collection method used for an event. + * + * The collection method indicates how an event is collected. + */ +typedef enum { + /** + * Event is collected using a hardware global performance monitor. + */ + CUPTI_EVENT_COLLECTION_METHOD_PM = 0, + /** + * Event is collected using a hardware SM performance monitor. + */ + CUPTI_EVENT_COLLECTION_METHOD_SM = 1, + /** + * Event is collected using software instrumentation. + */ + CUPTI_EVENT_COLLECTION_METHOD_INSTRUMENTED = 2, + /** + * Event is collected using NvLink throughput counter method. + */ + CUPTI_EVENT_COLLECTION_METHOD_NVLINK_TC = 3, + CUPTI_EVENT_COLLECTION_METHOD_FORCE_INT = 0x7fffffff +} CUpti_EventCollectionMethod; + +/** + * \brief Event group attributes. + * + * Event group attributes. These attributes can be read using \ref + * cuptiEventGroupGetAttribute. Attributes marked [rw] can also be + * written using \ref cuptiEventGroupSetAttribute. + */ +typedef enum { + /** + * The domain to which the event group is bound. This attribute is + * set when the first event is added to the group. Value is a + * CUpti_EventDomainID. + */ + CUPTI_EVENT_GROUP_ATTR_EVENT_DOMAIN_ID = 0, + /** + * [rw] Profile all the instances of the domain for this + * eventgroup. This feature can be used to get load balancing + * across all instances of a domain. Value is an integer. + */ + CUPTI_EVENT_GROUP_ATTR_PROFILE_ALL_DOMAIN_INSTANCES = 1, + /** + * [rw] Reserved for user data. + */ + CUPTI_EVENT_GROUP_ATTR_USER_DATA = 2, + /** + * Number of events in the group. Value is a uint32_t. + */ + CUPTI_EVENT_GROUP_ATTR_NUM_EVENTS = 3, + /** + * Enumerates events in the group. Value is a pointer to buffer of + * size sizeof(CUpti_EventID) * num_of_events in the eventgroup. + * num_of_events can be queried using + * CUPTI_EVENT_GROUP_ATTR_NUM_EVENTS. + */ + CUPTI_EVENT_GROUP_ATTR_EVENTS = 4, + /** + * Number of instances of the domain bound to this event group that + * will be counted. Value is a uint32_t. + */ + CUPTI_EVENT_GROUP_ATTR_INSTANCE_COUNT = 5, + /** + * Event group scope can be set to CUPTI_EVENT_PROFILING_SCOPE_DEVICE or + * CUPTI_EVENT_PROFILING_SCOPE_CONTEXT for an eventGroup, before + * adding any event. + * Sets the scope of eventgroup as CUPTI_EVENT_PROFILING_SCOPE_DEVICE or + * CUPTI_EVENT_PROFILING_SCOPE_CONTEXT when the scope of the events + * that will be added is CUPTI_EVENT_PROFILING_SCOPE_BOTH. + * If profiling scope of event is either + * CUPTI_EVENT_PROFILING_SCOPE_DEVICE or CUPTI_EVENT_PROFILING_SCOPE_CONTEXT + * then setting this attribute will not affect the default scope. + * It is not allowed to add events of different scope to same eventgroup. + * Value is a uint32_t. + */ + CUPTI_EVENT_GROUP_ATTR_PROFILING_SCOPE = 6, + CUPTI_EVENT_GROUP_ATTR_FORCE_INT = 0x7fffffff, +} CUpti_EventGroupAttribute; + +/** +* \brief Profiling scope for event. +* +* Profiling scope of event indicates if the event can be collected at context +* scope or device scope or both i.e. it can be collected at any of context or +* device scope. +*/ +typedef enum { + /** + * Event is collected at context scope. + */ + CUPTI_EVENT_PROFILING_SCOPE_CONTEXT = 0, + /** + * Event is collected at device scope. + */ + CUPTI_EVENT_PROFILING_SCOPE_DEVICE = 1, + /** + * Event can be collected at device or context scope. + * The scope can be set using \ref cuptiEventGroupSetAttribute API. + */ + CUPTI_EVENT_PROFILING_SCOPE_BOTH = 2, + CUPTI_EVENT_PROFILING_SCOPE_FORCE_INT = 0x7fffffff +} CUpti_EventProfilingScope; + +/** + * \brief Event attributes. + * + * Event attributes. These attributes can be read using \ref + * cuptiEventGetAttribute. + */ +typedef enum { + /** + * Event name. Value is a null terminated const c-string. + */ + CUPTI_EVENT_ATTR_NAME = 0, + /** + * Short description of event. Value is a null terminated const + * c-string. + */ + CUPTI_EVENT_ATTR_SHORT_DESCRIPTION = 1, + /** + * Long description of event. Value is a null terminated const + * c-string. + */ + CUPTI_EVENT_ATTR_LONG_DESCRIPTION = 2, + /** + * Category of event. Value is CUpti_EventCategory. + */ + CUPTI_EVENT_ATTR_CATEGORY = 3, + /** + * Profiling scope of the events. It can be either device or context or both. + * Value is a \ref CUpti_EventProfilingScope. + */ + CUPTI_EVENT_ATTR_PROFILING_SCOPE = 5, + + CUPTI_EVENT_ATTR_FORCE_INT = 0x7fffffff, +} CUpti_EventAttribute; + +/** + * \brief Event collection modes. + * + * The event collection mode determines the period over which the + * events within the enabled event groups will be collected. + */ +typedef enum { + /** + * Events are collected for the entire duration between the + * cuptiEventGroupEnable and cuptiEventGroupDisable calls. + * Event values are reset when the events are read. + * For CUDA toolkit v6.0 and older this was the default mode. + */ + CUPTI_EVENT_COLLECTION_MODE_CONTINUOUS = 0, + /** + * Events are collected only for the durations of kernel executions + * that occur between the cuptiEventGroupEnable and + * cuptiEventGroupDisable calls. Event collection begins when a + * kernel execution begins, and stops when kernel execution + * completes. Event values are reset to zero when each kernel + * execution begins. If multiple kernel executions occur between the + * cuptiEventGroupEnable and cuptiEventGroupDisable calls then the + * event values must be read after each kernel launch if those + * events need to be associated with the specific kernel launch. + * Note that collection in this mode may significantly change the + * overall performance characteristics of the application because + * kernel executions that occur between the cuptiEventGroupEnable and + * cuptiEventGroupDisable calls are serialized on the GPU. + * This is the default mode from CUDA toolkit v6.5 + */ + CUPTI_EVENT_COLLECTION_MODE_KERNEL = 1, + CUPTI_EVENT_COLLECTION_MODE_FORCE_INT = 0x7fffffff +} CUpti_EventCollectionMode; + +/** + * \brief An event category. + * + * Each event is assigned to a category that represents the general + * type of the event. A event's category is accessed using \ref + * cuptiEventGetAttribute and the CUPTI_EVENT_ATTR_CATEGORY attribute. + */ +typedef enum { + /** + * An instruction related event. + */ + CUPTI_EVENT_CATEGORY_INSTRUCTION = 0, + /** + * A memory related event. + */ + CUPTI_EVENT_CATEGORY_MEMORY = 1, + /** + * A cache related event. + */ + CUPTI_EVENT_CATEGORY_CACHE = 2, + /** + * A profile-trigger event. + */ + CUPTI_EVENT_CATEGORY_PROFILE_TRIGGER = 3, + /** + * A system event. + */ + CUPTI_EVENT_CATEGORY_SYSTEM = 4, + CUPTI_EVENT_CATEGORY_FORCE_INT = 0x7fffffff +} CUpti_EventCategory; + +/** + * \brief The overflow value for a CUPTI event. + * + * The CUPTI event value that indicates an overflow. + */ +#define CUPTI_EVENT_OVERFLOW ((uint64_t)0xFFFFFFFFFFFFFFFFULL) + +/** + * \brief The value that indicates the event value is invalid + */ +#define CUPTI_EVENT_INVALID ((uint64_t)0xFFFFFFFFFFFFFFFEULL) + +/** + * \brief Flags for cuptiEventGroupReadEvent an + * cuptiEventGroupReadAllEvents. + * + * Flags for \ref cuptiEventGroupReadEvent an \ref + * cuptiEventGroupReadAllEvents. + */ +typedef enum { + /** + * No flags. + */ + CUPTI_EVENT_READ_FLAG_NONE = 0, + CUPTI_EVENT_READ_FLAG_FORCE_INT = 0x7fffffff, +} CUpti_ReadEventFlags; + + +/** + * \brief A set of event groups. + * + * A set of event groups. When returned by \ref + * cuptiEventGroupSetsCreate and \ref cuptiMetricCreateEventGroupSets + * a set indicates that event groups that can be enabled at the same + * time (i.e. all the events in the set can be collected + * simultaneously). + */ +typedef struct { + /** + * The number of event groups in the set. + */ + uint32_t numEventGroups; + /** + * An array of \p numEventGroups event groups. + */ + CUpti_EventGroup *eventGroups; +} CUpti_EventGroupSet; + +/** + * \brief A set of event group sets. + * + * A set of event group sets. When returned by \ref + * cuptiEventGroupSetsCreate and \ref cuptiMetricCreateEventGroupSets + * a CUpti_EventGroupSets indicates the number of passes required to + * collect all the events, and the event groups that should be + * collected during each pass. + */ +typedef struct { + /** + * Number of event group sets. + */ + uint32_t numSets; + /** + * An array of \p numSets event group sets. + */ + CUpti_EventGroupSet *sets; +} CUpti_EventGroupSets; + +/** + * \brief Set the event collection mode. + * + * Set the event collection mode for a \p context. The \p mode + * controls the event collection behavior of all events in event + * groups created in the \p context. This API is invalid in kernel + * replay mode. + * \note \b Thread-safety: this function is thread safe. + * + * \param context The context + * \param mode The event collection mode + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_CONTEXT + * \retval CUPTI_ERROR_INVALID_OPERATION if called when replay mode is enabled + * \retval CUPTI_ERROR_NOT_SUPPORTED if mode is not supported on the device + */ + +CUptiResult CUPTIAPI cuptiSetEventCollectionMode(CUcontext context, + CUpti_EventCollectionMode mode); + +/** + * \brief Read a device attribute. + * + * Read a device attribute and return it in \p *value. + * \note \b Thread-safety: this function is thread safe. + * + * \param device The CUDA device + * \param attrib The attribute to read + * \param valueSize Size of buffer pointed by the value, and + * returns the number of bytes written to \p value + * \param value Returns the value of the attribute + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value + * is NULL, or if \p attrib is not a device attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT For non-c-string + * attribute values, indicates that the \p value buffer is too small + * to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiDeviceGetAttribute(CUdevice device, + CUpti_DeviceAttribute attrib, + size_t *valueSize, + void *value); + +/** + * \brief Get the number of domains for a device. + * + * Returns the number of domains in \p numDomains for a device. + * \note \b Thread-safety: this function is thread safe. + * + * \param device The CUDA device + * \param numDomains Returns the number of domains + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p numDomains is NULL + */ +CUptiResult CUPTIAPI cuptiDeviceGetNumEventDomains(CUdevice device, + uint32_t *numDomains); + +/** + * \brief Get the event domains for a device. + * + * Returns the event domains IDs in \p domainArray for a device. The + * size of the \p domainArray buffer is given by \p + * *arraySizeBytes. The size of the \p domainArray buffer must be at + * least \p numdomains * sizeof(CUpti_EventDomainID) or else all + * domains will not be returned. The value returned in \p + * *arraySizeBytes contains the number of bytes returned in \p + * domainArray. + * \note \b Thread-safety: this function is thread safe. + * + * \param device The CUDA device + * \param arraySizeBytes The size of \p domainArray in bytes, and + * returns the number of bytes written to \p domainArray + * \param domainArray Returns the IDs of the event domains for the device + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p arraySizeBytes or + * \p domainArray are NULL + */ +CUptiResult CUPTIAPI cuptiDeviceEnumEventDomains(CUdevice device, + size_t *arraySizeBytes, + CUpti_EventDomainID *domainArray); + +/** + * \brief Read an event domain attribute. + * + * Returns an event domain attribute in \p *value. The size of the \p + * value buffer is given by \p *valueSize. The value returned in \p + * *valueSize contains the number of bytes returned in \p value. + * + * If the attribute value is a c-string that is longer than \p + * *valueSize, then only the first \p *valueSize characters will be + * returned and there will be no terminating null byte. + * \note \b Thread-safety: this function is thread safe. + * + * \param device The CUDA device + * \param eventDomain ID of the event domain + * \param attrib The event domain attribute to read + * \param valueSize The size of the \p value buffer in bytes, and + * returns the number of bytes written to \p value + * \param value Returns the attribute's value + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE + * \retval CUPTI_ERROR_INVALID_EVENT_DOMAIN_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value + * is NULL, or if \p attrib is not an event domain attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT For non-c-string + * attribute values, indicates that the \p value buffer is too small + * to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiDeviceGetEventDomainAttribute(CUdevice device, + CUpti_EventDomainID eventDomain, + CUpti_EventDomainAttribute attrib, + size_t *valueSize, + void *value); + +/** + * \brief Get the number of event domains available on any device. + * + * Returns the total number of event domains available on any + * CUDA-capable device. + * \note \b Thread-safety: this function is thread safe. + * + * \param numDomains Returns the number of domains + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p numDomains is NULL + */ +CUptiResult CUPTIAPI cuptiGetNumEventDomains(uint32_t *numDomains); + +/** + * \brief Get the event domains available on any device. + * + * Returns all the event domains available on any CUDA-capable device. + * Event domain IDs are returned in \p domainArray. The size of the \p + * domainArray buffer is given by \p *arraySizeBytes. The size of the + * \p domainArray buffer must be at least \p numDomains * + * sizeof(CUpti_EventDomainID) or all domains will not be + * returned. The value returned in \p *arraySizeBytes contains the + * number of bytes returned in \p domainArray. + * \note \b Thread-safety: this function is thread safe. + * + * \param arraySizeBytes The size of \p domainArray in bytes, and + * returns the number of bytes written to \p domainArray + * \param domainArray Returns all the event domains + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p arraySizeBytes or + * \p domainArray are NULL + */ +CUptiResult CUPTIAPI cuptiEnumEventDomains(size_t *arraySizeBytes, + CUpti_EventDomainID *domainArray); + +/** + * \brief Read an event domain attribute. + * + * Returns an event domain attribute in \p *value. The size of the \p + * value buffer is given by \p *valueSize. The value returned in \p + * *valueSize contains the number of bytes returned in \p value. + * + * If the attribute value is a c-string that is longer than \p + * *valueSize, then only the first \p *valueSize characters will be + * returned and there will be no terminating null byte. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventDomain ID of the event domain + * \param attrib The event domain attribute to read + * \param valueSize The size of the \p value buffer in bytes, and + * returns the number of bytes written to \p value + * \param value Returns the attribute's value + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_EVENT_DOMAIN_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value + * is NULL, or if \p attrib is not an event domain attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT For non-c-string + * attribute values, indicates that the \p value buffer is too small + * to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiEventDomainGetAttribute(CUpti_EventDomainID eventDomain, + CUpti_EventDomainAttribute attrib, + size_t *valueSize, + void *value); + +/** + * \brief Get number of events in a domain. + * + * Returns the number of events in \p numEvents for a domain. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventDomain ID of the event domain + * \param numEvents Returns the number of events in the domain + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_EVENT_DOMAIN_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p numEvents is NULL + */ +CUptiResult CUPTIAPI cuptiEventDomainGetNumEvents(CUpti_EventDomainID eventDomain, + uint32_t *numEvents); + +/** + * \brief Get the events in a domain. + * + * Returns the event IDs in \p eventArray for a domain. The size of + * the \p eventArray buffer is given by \p *arraySizeBytes. The size + * of the \p eventArray buffer must be at least \p numdomainevents * + * sizeof(CUpti_EventID) or else all events will not be returned. The + * value returned in \p *arraySizeBytes contains the number of bytes + * returned in \p eventArray. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventDomain ID of the event domain + * \param arraySizeBytes The size of \p eventArray in bytes, and + * returns the number of bytes written to \p eventArray + * \param eventArray Returns the IDs of the events in the domain + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_EVENT_DOMAIN_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p arraySizeBytes or \p + * eventArray are NULL + */ +CUptiResult CUPTIAPI cuptiEventDomainEnumEvents(CUpti_EventDomainID eventDomain, + size_t *arraySizeBytes, + CUpti_EventID *eventArray); + +/** + * \brief Get an event attribute. + * + * Returns an event attribute in \p *value. The size of the \p + * value buffer is given by \p *valueSize. The value returned in \p + * *valueSize contains the number of bytes returned in \p value. + * + * If the attribute value is a c-string that is longer than \p + * *valueSize, then only the first \p *valueSize characters will be + * returned and there will be no terminating null byte. + * \note \b Thread-safety: this function is thread safe. + * + * \param event ID of the event + * \param attrib The event attribute to read + * \param valueSize The size of the \p value buffer in bytes, and + * returns the number of bytes written to \p value + * \param value Returns the attribute's value + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_EVENT_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value + * is NULL, or if \p attrib is not an event attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT For non-c-string + * attribute values, indicates that the \p value buffer is too small + * to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiEventGetAttribute(CUpti_EventID event, + CUpti_EventAttribute attrib, + size_t *valueSize, + void *value); + +/** + * \brief Find an event by name. + * + * Find an event by name and return the event ID in \p *event. + * \note \b Thread-safety: this function is thread safe. + * + * \param device The CUDA device + * \param eventName The name of the event to find + * \param event Returns the ID of the found event or undefined if + * unable to find the event + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE + * \retval CUPTI_ERROR_INVALID_EVENT_NAME if unable to find an event + * with name \p eventName. In this case \p *event is undefined + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventName or \p event are NULL + */ +CUptiResult CUPTIAPI cuptiEventGetIdFromName(CUdevice device, + const char *eventName, + CUpti_EventID *event); + +/** + * \brief Create a new event group for a context. + * + * Creates a new event group for \p context and returns the new group + * in \p *eventGroup. + * \note \p flags are reserved for future use and should be set to zero. + * \note \b Thread-safety: this function is thread safe. + * + * \param context The context for the event group + * \param eventGroup Returns the new event group + * \param flags Reserved - must be zero + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_CONTEXT + * \retval CUPTI_ERROR_OUT_OF_MEMORY + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupCreate(CUcontext context, + CUpti_EventGroup *eventGroup, + uint32_t flags); + +/** + * \brief Destroy an event group. + * + * Destroy an \p eventGroup and free its resources. An event group + * cannot be destroyed if it is enabled. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroup The event group to destroy + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_OPERATION if the event group is enabled + * \retval CUPTI_ERROR_INVALID_PARAMETER if eventGroup is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupDestroy(CUpti_EventGroup eventGroup); + +/** + * \brief Read an event group attribute. + * + * Read an event group attribute and return it in \p *value. + * \note \b Thread-safety: this function is thread safe but client + * must guard against simultaneous destruction or modification of \p + * eventGroup (for example, client must guard against simultaneous + * calls to \ref cuptiEventGroupDestroy, \ref cuptiEventGroupAddEvent, + * etc.), and must guard against simultaneous destruction of the + * context in which \p eventGroup was created (for example, client + * must guard against simultaneous calls to cudaDeviceReset, + * cuCtxDestroy, etc.). + * + * \param eventGroup The event group + * \param attrib The attribute to read + * \param valueSize Size of buffer pointed by the value, and + * returns the number of bytes written to \p value + * \param value Returns the value of the attribute + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value + * is NULL, or if \p attrib is not an eventgroup attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT For non-c-string + * attribute values, indicates that the \p value buffer is too small + * to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiEventGroupGetAttribute(CUpti_EventGroup eventGroup, + CUpti_EventGroupAttribute attrib, + size_t *valueSize, + void *value); + +/** + * \brief Write an event group attribute. + * + * Write an event group attribute. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroup The event group + * \param attrib The attribute to write + * \param valueSize The size, in bytes, of the value + * \param value The attribute value to write + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value + * is NULL, or if \p attrib is not an event group attribute, or if + * \p attrib is not a writable attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT Indicates that + * the \p value buffer is too small to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiEventGroupSetAttribute(CUpti_EventGroup eventGroup, + CUpti_EventGroupAttribute attrib, + size_t valueSize, + void *value); + +/** + * \brief Add an event to an event group. + * + * Add an event to an event group. The event add can fail for a number of reasons: + * \li The event group is enabled + * \li The event does not belong to the same event domain as the + * events that are already in the event group + * \li Device limitations on the events that can belong to the same group + * \li The event group is full + * + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroup The event group + * \param event The event to add to the group + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_EVENT_ID + * \retval CUPTI_ERROR_OUT_OF_MEMORY + * \retval CUPTI_ERROR_INVALID_OPERATION if \p eventGroup is enabled + * \retval CUPTI_ERROR_NOT_COMPATIBLE if \p event belongs to a + * different event domain than the events already in \p eventGroup, or + * if a device limitation prevents \p event from being collected at + * the same time as the events already in \p eventGroup + * \retval CUPTI_ERROR_MAX_LIMIT_REACHED if \p eventGroup is full + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupAddEvent(CUpti_EventGroup eventGroup, + CUpti_EventID event); + +/** + * \brief Remove an event from an event group. + * + * Remove \p event from the an event group. The event cannot be + * removed if the event group is enabled. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroup The event group + * \param event The event to remove from the group + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_EVENT_ID + * \retval CUPTI_ERROR_INVALID_OPERATION if \p eventGroup is enabled + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupRemoveEvent(CUpti_EventGroup eventGroup, + CUpti_EventID event); + +/** + * \brief Remove all events from an event group. + * + * Remove all events from an event group. Events cannot be removed if + * the event group is enabled. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroup The event group + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_OPERATION if \p eventGroup is enabled + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupRemoveAllEvents(CUpti_EventGroup eventGroup); + +/** + * \brief Zero all the event counts in an event group. + * + * Zero all the event counts in an event group. + * \note \b Thread-safety: this function is thread safe but client + * must guard against simultaneous destruction or modification of \p + * eventGroup (for example, client must guard against simultaneous + * calls to \ref cuptiEventGroupDestroy, \ref cuptiEventGroupAddEvent, + * etc.), and must guard against simultaneous destruction of the + * context in which \p eventGroup was created (for example, client + * must guard against simultaneous calls to cudaDeviceReset, + * cuCtxDestroy, etc.). + * + * \param eventGroup The event group + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_HARDWARE + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupResetAllEvents(CUpti_EventGroup eventGroup); + +/** + * \brief Enable an event group. + * + * Enable an event group. Enabling an event group zeros the value of + * all the events in the group and then starts collection of those + * events. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroup The event group + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_HARDWARE + * \retval CUPTI_ERROR_NOT_READY if \p eventGroup does not contain any events + * \retval CUPTI_ERROR_NOT_COMPATIBLE if \p eventGroup cannot be + * enabled due to other already enabled event groups + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup is NULL + * \retval CUPTI_ERROR_HARDWARE_BUSY if another client is profiling + * and hardware is busy + */ +CUptiResult CUPTIAPI cuptiEventGroupEnable(CUpti_EventGroup eventGroup); + +/** + * \brief Disable an event group. + * + * Disable an event group. Disabling an event group stops collection + * of events contained in the group. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroup The event group + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_HARDWARE + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupDisable(CUpti_EventGroup eventGroup); + +/** + * \brief Read the value for an event in an event group. + * + * Read the value for an event in an event group. The event value is + * returned in the \p eventValueBuffer buffer. \p + * eventValueBufferSizeBytes indicates the size of the \p + * eventValueBuffer buffer. The buffer must be at least sizeof(uint64) + * if ::CUPTI_EVENT_GROUP_ATTR_PROFILE_ALL_DOMAIN_INSTANCES is not set + * on the group containing the event. The buffer must be at least + * (sizeof(uint64) * number of domain instances) if + * ::CUPTI_EVENT_GROUP_ATTR_PROFILE_ALL_DOMAIN_INSTANCES is set on the + * group. + * + * If any instance of an event counter overflows, the value returned + * for that event instance will be ::CUPTI_EVENT_OVERFLOW. + * + * The only allowed value for \p flags is ::CUPTI_EVENT_READ_FLAG_NONE. + * + * Reading an event from a disabled event group is not allowed. After + * being read, an event's value is reset to zero. + * \note \b Thread-safety: this function is thread safe but client + * must guard against simultaneous destruction or modification of \p + * eventGroup (for example, client must guard against simultaneous + * calls to \ref cuptiEventGroupDestroy, \ref cuptiEventGroupAddEvent, + * etc.), and must guard against simultaneous destruction of the + * context in which \p eventGroup was created (for example, client + * must guard against simultaneous calls to cudaDeviceReset, + * cuCtxDestroy, etc.). If \ref cuptiEventGroupResetAllEvents is + * called simultaneously with this function, then returned event + * values are undefined. + * + * \param eventGroup The event group + * \param flags Flags controlling the reading mode + * \param event The event to read + * \param eventValueBufferSizeBytes The size of \p eventValueBuffer + * in bytes, and returns the number of bytes written to \p + * eventValueBuffer + * \param eventValueBuffer Returns the event value(s) + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_EVENT_ID + * \retval CUPTI_ERROR_HARDWARE + * \retval CUPTI_ERROR_INVALID_OPERATION if \p eventGroup is disabled + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup, \p + * eventValueBufferSizeBytes or \p eventValueBuffer is NULL + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT if size of \p eventValueBuffer + * is not sufficient + */ +CUptiResult CUPTIAPI cuptiEventGroupReadEvent(CUpti_EventGroup eventGroup, + CUpti_ReadEventFlags flags, + CUpti_EventID event, + size_t *eventValueBufferSizeBytes, + uint64_t *eventValueBuffer); + +/** + * \brief Read the values for all the events in an event group. + * + * Read the values for all the events in an event group. The event + * values are returned in the \p eventValueBuffer buffer. \p + * eventValueBufferSizeBytes indicates the size of \p + * eventValueBuffer. The buffer must be at least (sizeof(uint64) * + * number of events in group) if + * ::CUPTI_EVENT_GROUP_ATTR_PROFILE_ALL_DOMAIN_INSTANCES is not set on + * the group containing the events. The buffer must be at least + * (sizeof(uint64) * number of domain instances * number of events in + * group) if ::CUPTI_EVENT_GROUP_ATTR_PROFILE_ALL_DOMAIN_INSTANCES is + * set on the group. + * + * The data format returned in \p eventValueBuffer is: + * - domain instance 0: event0 event1 ... eventN + * - domain instance 1: event0 event1 ... eventN + * - ... + * - domain instance M: event0 event1 ... eventN + * + * The event order in \p eventValueBuffer is returned in \p + * eventIdArray. The size of \p eventIdArray is specified in \p + * eventIdArraySizeBytes. The size should be at least + * (sizeof(CUpti_EventID) * number of events in group). + * + * If any instance of any event counter overflows, the value returned + * for that event instance will be ::CUPTI_EVENT_OVERFLOW. + * + * The only allowed value for \p flags is ::CUPTI_EVENT_READ_FLAG_NONE. + * + * Reading events from a disabled event group is not allowed. After + * being read, an event's value is reset to zero. + * \note \b Thread-safety: this function is thread safe but client + * must guard against simultaneous destruction or modification of \p + * eventGroup (for example, client must guard against simultaneous + * calls to \ref cuptiEventGroupDestroy, \ref cuptiEventGroupAddEvent, + * etc.), and must guard against simultaneous destruction of the + * context in which \p eventGroup was created (for example, client + * must guard against simultaneous calls to cudaDeviceReset, + * cuCtxDestroy, etc.). If \ref cuptiEventGroupResetAllEvents is + * called simultaneously with this function, then returned event + * values are undefined. + * + * \param eventGroup The event group + * \param flags Flags controlling the reading mode + * \param eventValueBufferSizeBytes The size of \p eventValueBuffer in + * bytes, and returns the number of bytes written to \p + * eventValueBuffer + * \param eventValueBuffer Returns the event values + * \param eventIdArraySizeBytes The size of \p eventIdArray in bytes, + * and returns the number of bytes written to \p eventIdArray + * \param eventIdArray Returns the IDs of the events in the same order + * as the values return in eventValueBuffer. + * \param numEventIdsRead Returns the number of event IDs returned + * in \p eventIdArray + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_HARDWARE + * \retval CUPTI_ERROR_INVALID_OPERATION if \p eventGroup is disabled + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroup, \p + * eventValueBufferSizeBytes, \p eventValueBuffer, \p + * eventIdArraySizeBytes, \p eventIdArray or \p numEventIdsRead is + * NULL + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT if size of \p eventValueBuffer + * or \p eventIdArray is not sufficient + */ +CUptiResult CUPTIAPI cuptiEventGroupReadAllEvents(CUpti_EventGroup eventGroup, + CUpti_ReadEventFlags flags, + size_t *eventValueBufferSizeBytes, + uint64_t *eventValueBuffer, + size_t *eventIdArraySizeBytes, + CUpti_EventID *eventIdArray, + size_t *numEventIdsRead); + +/** + * \brief For a set of events, get the grouping that indicates the + * number of passes and the event groups necessary to collect the + * events. + * + * The number of events that can be collected simultaneously varies by + * device and by the type of the events. When events can be collected + * simultaneously, they may need to be grouped into multiple event + * groups because they are from different event domains. This function + * takes a set of events and determines how many passes are required + * to collect all those events, and which events can be collected + * simultaneously in each pass. + * + * The CUpti_EventGroupSets returned in \p eventGroupPasses indicates + * how many passes are required to collect the events with the \p + * numSets field. Within each event group set, the \p sets array + * indicates the event groups that should be collected on each pass. + * \note \b Thread-safety: this function is thread safe, but client + * must guard against another thread simultaneously destroying \p + * context. + * + * \param context The context for event collection + * \param eventIdArraySizeBytes Size of \p eventIdArray in bytes + * \param eventIdArray Array of event IDs that need to be grouped + * \param eventGroupPasses Returns a CUpti_EventGroupSets object that + * indicates the number of passes required to collect the events and + * the events to collect on each pass + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_CONTEXT + * \retval CUPTI_ERROR_INVALID_EVENT_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventIdArray or + * \p eventGroupPasses is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupSetsCreate(CUcontext context, + size_t eventIdArraySizeBytes, + CUpti_EventID *eventIdArray, + CUpti_EventGroupSets **eventGroupPasses); + +/** + * \brief Destroy a event group sets object. + * + * Destroy a CUpti_EventGroupSets object. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroupSets The object to destroy + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_OPERATION if any of the event groups + * contained in the sets is enabled + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroupSets is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupSetsDestroy(CUpti_EventGroupSets *eventGroupSets); + + +/** + * \brief Enable an event group set. + * + * Enable a set of event groups. Enabling a set of event groups zeros the value of + * all the events in all the groups and then starts collection of those events. + * \note \b Thread-safety: this function is thread safe. + * + * \param eventGroupSet The pointer to the event group set + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_HARDWARE + * \retval CUPTI_ERROR_NOT_READY if \p eventGroup does not contain any events + * \retval CUPTI_ERROR_NOT_COMPATIBLE if \p eventGroup cannot be + * enabled due to other already enabled event groups + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroupSet is NULL + * \retval CUPTI_ERROR_HARDWARE_BUSY if other client is profiling and hardware is + * busy + */ +CUptiResult CUPTIAPI cuptiEventGroupSetEnable(CUpti_EventGroupSet *eventGroupSet); + +/** + * \brief Disable an event group set. + * + * Disable a set of event groups. Disabling a set of event groups + * stops collection of events contained in the groups. + * \note \b Thread-safety: this function is thread safe. + * \note \b If this call fails, some of the event groups in the set may be disabled + * and other event groups may remain enabled. + * + * \param eventGroupSet The pointer to the event group set + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_HARDWARE + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventGroupSet is NULL + */ +CUptiResult CUPTIAPI cuptiEventGroupSetDisable(CUpti_EventGroupSet *eventGroupSet); + +/** + * \brief Enable kernel replay mode. + * + * Set profiling mode for the context to replay mode. In this mode, + * any number of events can be collected in one run of the kernel. The + * event collection mode will automatically switch to + * CUPTI_EVENT_COLLECTION_MODE_KERNEL. In this mode, \ref + * cuptiSetEventCollectionMode will return + * CUPTI_ERROR_INVALID_OPERATION. + * \note \b Kernels might take longer to run if many events are enabled. + * \note \b Thread-safety: this function is thread safe. + * + * \param context The context + * \retval CUPTI_SUCCESS + */ +CUptiResult CUPTIAPI cuptiEnableKernelReplayMode(CUcontext context); + +/** + * \brief Disable kernel replay mode. + * + * Set profiling mode for the context to non-replay (default) + * mode. Event collection mode will be set to + * CUPTI_EVENT_COLLECTION_MODE_KERNEL. All previously enabled + * event groups and event group sets will be disabled. + * \note \b Thread-safety: this function is thread safe. + * + * \param context The context + * \retval CUPTI_SUCCESS + */ +CUptiResult CUPTIAPI cuptiDisableKernelReplayMode(CUcontext context); + +/** + * \brief Function type for getting updates on kernel replay. + * + * \param kernelName The mangled kernel name + * \param numReplaysDone Number of replays done so far + * \param customData Pointer of any custom data passed in when subscribing + */ +typedef void (CUPTIAPI *CUpti_KernelReplayUpdateFunc)( + const char *kernelName, + int numReplaysDone, + void *customData); + +/** + * \brief Subscribe to kernel replay updates. + * + * When subscribed, the function pointer passed in will be called each time a + * kernel run is finished during kernel replay. Previously subscribed function + * pointer will be replaced. Pass in NULL as the function pointer unsubscribes + * the update. + * + * \param updateFunc The update function pointer + * \param customData Pointer to any custom data + * \retval CUPTI_SUCCESS + */ +CUptiResult CUPTIAPI cuptiKernelReplaySubscribeUpdate(CUpti_KernelReplayUpdateFunc updateFunc, void *customData); + +/** @} */ /* END CUPTI_EVENT_API */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /*_CUPTI_EVENTS_H_*/ + + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_metrics.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_metrics.h new file mode 100644 index 0000000000000000000000000000000000000000..64b7f2d14580320f1ec938da5ea356add191ec3c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_metrics.h @@ -0,0 +1,824 @@ +/* + * Copyright 2011-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_METRIC_H_) +#define _CUPTI_METRIC_H_ + +#include +#include +#include +#include + +#ifndef CUPTIAPI +#ifdef _WIN32 +#define CUPTIAPI __stdcall +#else +#define CUPTIAPI +#endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_METRIC_API CUPTI Metric API + * Functions, types, and enums that implement the CUPTI Metric API. + * + * \note The CUPTI metric API from the header cupti_metrics.h is not supported on devices + * with compute capability 7.5 and higher (i.e. Turing and later GPU architectures). + * This API is deprecated in CUDA 12.8 release and will be removed in a future CUDA release. + * This is replaced by the host profiling API in the header cupti_profiler_host.h and + * target profiling API in the header cupti_range_profiler.h which are supported on + * devices with compute capability 7.0 and higher (i.e. Volta and later GPU architectures). + * + * @{ + */ + +/** + * \brief ID for a metric. + * + * A metric provides a measure of some aspect of the device. + */ +typedef uint32_t CUpti_MetricID; + +/** + * \brief A metric category. + * + * Each metric is assigned to a category that represents the general + * type of the metric. A metric's category is accessed using \ref + * cuptiMetricGetAttribute and the CUPTI_METRIC_ATTR_CATEGORY + * attribute. + */ +typedef enum { + /** + * A memory related metric. + */ + CUPTI_METRIC_CATEGORY_MEMORY = 0, + /** + * An instruction related metric. + */ + CUPTI_METRIC_CATEGORY_INSTRUCTION = 1, + /** + * A multiprocessor related metric. + */ + CUPTI_METRIC_CATEGORY_MULTIPROCESSOR = 2, + /** + * A cache related metric. + */ + CUPTI_METRIC_CATEGORY_CACHE = 3, + /** + * A texture related metric. + */ + CUPTI_METRIC_CATEGORY_TEXTURE = 4, + /** + *A Nvlink related metric. + */ + CUPTI_METRIC_CATEGORY_NVLINK = 5, + /** + *A PCIe related metric. + */ + CUPTI_METRIC_CATEGORY_PCIE = 6, + CUPTI_METRIC_CATEGORY_FORCE_INT = 0x7fffffff, +} CUpti_MetricCategory; + +/** + * \brief A metric evaluation mode. + * + * A metric can be evaluated per hardware instance to know the load balancing + * across instances of a domain or the metric can be evaluated in aggregate mode + * when the events involved in metric evaluation are from different event + * domains. It might be possible to evaluate some metrics in both + * modes for convenience. A metric's evaluation mode is accessed using \ref + * CUpti_MetricEvaluationMode and the CUPTI_METRIC_ATTR_EVALUATION_MODE + * attribute. + */ +typedef enum { + /** + * If this bit is set, the metric can be profiled for each instance of the + * domain. The event values passed to \ref cuptiMetricGetValue can contain + * values for one instance of the domain. And \ref cuptiMetricGetValue can + * be called for each instance. + */ + CUPTI_METRIC_EVALUATION_MODE_PER_INSTANCE = 1, + /** + * If this bit is set, the metric can be profiled over all instances. The + * event values passed to \ref cuptiMetricGetValue can be aggregated values + * of events for all instances of the domain. + */ + CUPTI_METRIC_EVALUATION_MODE_AGGREGATE = 1 << 1, + CUPTI_METRIC_EVALUATION_MODE_FORCE_INT = 0x7fffffff, +} CUpti_MetricEvaluationMode; + +/** + * \brief Kinds of metric values. + * + * Metric values can be one of several different kinds. Corresponding + * to each kind is a member of the CUpti_MetricValue union. The metric + * value returned by \ref cuptiMetricGetValue should be accessed using + * the appropriate member of that union based on its value kind. + */ +typedef enum { + /** + * The metric value is a 64-bit double. + */ + CUPTI_METRIC_VALUE_KIND_DOUBLE = 0, + /** + * The metric value is a 64-bit unsigned integer. + */ + CUPTI_METRIC_VALUE_KIND_UINT64 = 1, + /** + * The metric value is a percentage represented by a 64-bit + * double. For example, 57.5% is represented by the value 57.5. + */ + CUPTI_METRIC_VALUE_KIND_PERCENT = 2, + /** + * The metric value is a throughput represented by a 64-bit + * integer. The unit for throughput values is bytes/second. + */ + CUPTI_METRIC_VALUE_KIND_THROUGHPUT = 3, + /** + * The metric value is a 64-bit signed integer. + */ + CUPTI_METRIC_VALUE_KIND_INT64 = 4, + /** + * The metric value is a utilization level, as represented by + * CUpti_MetricValueUtilizationLevel. + */ + CUPTI_METRIC_VALUE_KIND_UTILIZATION_LEVEL = 5, + + CUPTI_METRIC_VALUE_KIND_FORCE_INT = 0x7fffffff +} CUpti_MetricValueKind; + +/** + * \brief Enumeration of utilization levels for metrics values of kind + * CUPTI_METRIC_VALUE_KIND_UTILIZATION_LEVEL. Utilization values can + * vary from IDLE (0) to MAX (10) but the enumeration only provides + * specific names for a few values. + */ +typedef enum { + CUPTI_METRIC_VALUE_UTILIZATION_IDLE = 0, + CUPTI_METRIC_VALUE_UTILIZATION_LOW = 2, + CUPTI_METRIC_VALUE_UTILIZATION_MID = 5, + CUPTI_METRIC_VALUE_UTILIZATION_HIGH = 8, + CUPTI_METRIC_VALUE_UTILIZATION_MAX = 10, + CUPTI_METRIC_VALUE_UTILIZATION_FORCE_INT = 0x7fffffff +} CUpti_MetricValueUtilizationLevel; + +/** + * \brief Metric attributes. + * + * Metric attributes describe properties of a metric. These attributes + * can be read using \ref cuptiMetricGetAttribute. + */ +typedef enum { + /** + * Metric name. Value is a null terminated const c-string. + */ + CUPTI_METRIC_ATTR_NAME = 0, + /** + * Short description of metric. Value is a null terminated const c-string. + */ + CUPTI_METRIC_ATTR_SHORT_DESCRIPTION = 1, + /** + * Long description of metric. Value is a null terminated const c-string. + */ + CUPTI_METRIC_ATTR_LONG_DESCRIPTION = 2, + /** + * Category of the metric. Value is of type CUpti_MetricCategory. + */ + CUPTI_METRIC_ATTR_CATEGORY = 3, + /** + * Value type of the metric. Value is of type CUpti_MetricValueKind. + */ + CUPTI_METRIC_ATTR_VALUE_KIND = 4, + /** + * Metric evaluation mode. Value is of type CUpti_MetricEvaluationMode. + */ + CUPTI_METRIC_ATTR_EVALUATION_MODE = 5, + CUPTI_METRIC_ATTR_FORCE_INT = 0x7fffffff, +} CUpti_MetricAttribute; + +/** + * \brief A metric value. + * + * Metric values can be one of several different kinds. Corresponding + * to each kind is a member of the CUpti_MetricValue union. The metric + * value returned by \ref cuptiMetricGetValue should be accessed using + * the appropriate member of that union based on its value kind. + */ +typedef union { + /* + * Value for CUPTI_METRIC_VALUE_KIND_DOUBLE. + */ + double metricValueDouble; + /* + * Value for CUPTI_METRIC_VALUE_KIND_UINT64. + */ + uint64_t metricValueUint64; + /* + * Value for CUPTI_METRIC_VALUE_KIND_INT64. + */ + int64_t metricValueInt64; + /* + * Value for CUPTI_METRIC_VALUE_KIND_PERCENT. For example, 57.5% is + * represented by the value 57.5. + */ + double metricValuePercent; + /* + * Value for CUPTI_METRIC_VALUE_KIND_THROUGHPUT. The unit for + * throughput values is bytes/second. + */ + uint64_t metricValueThroughput; + /* + * Value for CUPTI_METRIC_VALUE_KIND_UTILIZATION_LEVEL. + */ + CUpti_MetricValueUtilizationLevel metricValueUtilizationLevel; +} CUpti_MetricValue; + +/** + * \brief Device class. + * + * Enumeration of device classes for metric property + * CUPTI_METRIC_PROPERTY_DEVICE_CLASS. + */ +typedef enum { + CUPTI_METRIC_PROPERTY_DEVICE_CLASS_TESLA = 0, + CUPTI_METRIC_PROPERTY_DEVICE_CLASS_QUADRO = 1, + CUPTI_METRIC_PROPERTY_DEVICE_CLASS_GEFORCE = 2, + CUPTI_METRIC_PROPERTY_DEVICE_CLASS_TEGRA = 3, +} CUpti_MetricPropertyDeviceClass; + +/** + * \brief Metric device properties. + * + * Metric device properties describe device properties which are needed for a metric. + * Some of these properties can be collected using cuDeviceGetAttribute. + */ +typedef enum { + /* + * Number of multiprocessors on a device. This can be collected + * using value of \param CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT of + * cuDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_MULTIPROCESSOR_COUNT, + /* + * Maximum number of warps on a multiprocessor. This can be + * collected using ratio of value of \param + * CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR and \param + * CU_DEVICE_ATTRIBUTE_WARP_SIZE of cuDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_WARPS_PER_MULTIPROCESSOR, + /* + * GPU Time for kernel in ns. This should be profiled using CUPTI + * Activity API. + */ + CUPTI_METRIC_PROPERTY_KERNEL_GPU_TIME, + /* + * Clock rate for device in KHz. This should be collected using + * value of \param CU_DEVICE_ATTRIBUTE_CLOCK_RATE of + * cuDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_CLOCK_RATE, + /* + * Number of Frame buffer units for device. This should be collected + * using value of \param CUPTI_DEVICE_ATTRIBUTE_MAX_FRAME_BUFFERS of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_FRAME_BUFFER_COUNT, + /* + * Global memory bandwidth in KBytes/sec. This should be collected + * using value of \param CUPTI_DEVICE_ATTR_GLOBAL_MEMORY_BANDWIDTH + * of cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_GLOBAL_MEMORY_BANDWIDTH, + /* + * PCIE link rate in Mega bits/sec. This should be collected using + * value of \param CUPTI_DEVICE_ATTR_PCIE_LINK_RATE of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_PCIE_LINK_RATE, + /* + * PCIE link width for device. This should be collected using + * value of \param CUPTI_DEVICE_ATTR_PCIE_LINK_WIDTH of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_PCIE_LINK_WIDTH, + /* + * PCIE generation for device. This should be collected using + * value of \param CUPTI_DEVICE_ATTR_PCIE_GEN of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_PCIE_GEN, + /* + * The device class. This should be collected using + * value of \param CUPTI_DEVICE_ATTR_DEVICE_CLASS of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_DEVICE_CLASS, + /* + * Peak single precision floating point operations that + * can be performed in one cycle by the device. + * This should be collected using value of + * \param CUPTI_DEVICE_ATTR_FLOP_SP_PER_CYCLE of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_FLOP_SP_PER_CYCLE, + /* + * Peak double precision floating point operations that + * can be performed in one cycle by the device. + * This should be collected using value of + * \param CUPTI_DEVICE_ATTR_FLOP_DP_PER_CYCLE of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_FLOP_DP_PER_CYCLE, + /* + * Number of L2 units on a device. This can be collected + * using value of \param CUPTI_DEVICE_ATTR_MAX_L2_UNITS of + * cuDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_L2_UNITS, + /* + * Whether ECC support is enabled on the device. This can be + * collected using value of \param CU_DEVICE_ATTRIBUTE_ECC_ENABLED of + * cuDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_ECC_ENABLED, + /* + * Peak half precision floating point operations that + * can be performed in one cycle by the device. + * This should be collected using value of + * \param CUPTI_DEVICE_ATTR_FLOP_HP_PER_CYCLE of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_FLOP_HP_PER_CYCLE, + /* + * NVLINK Bandwitdh for device. This should be collected + * using value of \param CUPTI_DEVICE_ATTR_GPU_CPU_NVLINK_BW of + * cuptiDeviceGetAttribute. + */ + CUPTI_METRIC_PROPERTY_GPU_CPU_NVLINK_BANDWIDTH, +} CUpti_MetricPropertyID; + +/** + * \brief Get the total number of metrics available on any device. + * + * Returns the total number of metrics available on any CUDA-capable + * devices. + * + * \param numMetrics Returns the number of metrics + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p numMetrics is NULL +*/ +CUptiResult CUPTIAPI cuptiGetNumMetrics(uint32_t *numMetrics); + +/** + * \brief Get all the metrics available on any device. + * + * Returns the metric IDs in \p metricArray for all CUDA-capable + * devices. The size of the \p metricArray buffer is given by \p + * *arraySizeBytes. The size of the \p metricArray buffer must be at + * least \p numMetrics * sizeof(CUpti_MetricID) or all metric IDs will + * not be returned. The value returned in \p *arraySizeBytes contains + * the number of bytes returned in \p metricArray. + * + * \param arraySizeBytes The size of \p metricArray in bytes, and + * returns the number of bytes written to \p metricArray + * \param metricArray Returns the IDs of the metrics + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p arraySizeBytes or + * \p metricArray are NULL +*/ +CUptiResult CUPTIAPI cuptiEnumMetrics(size_t *arraySizeBytes, + CUpti_MetricID *metricArray); + +/** + * \brief Get the number of metrics for a device. + * + * Returns the number of metrics available for a device. + * + * \param device The CUDA device + * \param numMetrics Returns the number of metrics available for the + * device + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p numMetrics is NULL + */ +CUptiResult CUPTIAPI cuptiDeviceGetNumMetrics(CUdevice device, + uint32_t *numMetrics); + +/** + * \brief Get the metrics for a device. + * + * Returns the metric IDs in \p metricArray for a device. The size of + * the \p metricArray buffer is given by \p *arraySizeBytes. The size + * of the \p metricArray buffer must be at least \p numMetrics * + * sizeof(CUpti_MetricID) or else all metric IDs will not be + * returned. The value returned in \p *arraySizeBytes contains the + * number of bytes returned in \p metricArray. + * + * \param device The CUDA device + * \param arraySizeBytes The size of \p metricArray in bytes, and + * returns the number of bytes written to \p metricArray + * \param metricArray Returns the IDs of the metrics for the device + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p arraySizeBytes or + * \p metricArray are NULL + */ +CUptiResult CUPTIAPI cuptiDeviceEnumMetrics(CUdevice device, + size_t *arraySizeBytes, + CUpti_MetricID *metricArray); + +/** + * \brief Get a metric attribute. + * + * Returns a metric attribute in \p *value. The size of the \p + * value buffer is given by \p *valueSize. The value returned in \p + * *valueSize contains the number of bytes returned in \p value. + * + * If the attribute value is a c-string that is longer than \p + * *valueSize, then only the first \p *valueSize characters will be + * returned and there will be no terminating null byte. + * + * \param metric ID of the metric + * \param attrib The metric attribute to read + * \param valueSize The size of the \p value buffer in bytes, and + * returns the number of bytes written to \p value + * \param value Returns the attribute's value + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_METRIC_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p valueSize or \p value + * is NULL, or if \p attrib is not a metric attribute + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT For non-c-string + * attribute values, indicates that the \p value buffer is too small + * to hold the attribute value. + */ +CUptiResult CUPTIAPI cuptiMetricGetAttribute(CUpti_MetricID metric, + CUpti_MetricAttribute attrib, + size_t *valueSize, + void *value); + +/** + * \brief Find an metric by name. + * + * Find a metric by name and return the metric ID in \p *metric. + * + * \param device The CUDA device + * \param metricName The name of metric to find + * \param metric Returns the ID of the found metric or undefined if + * unable to find the metric + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_DEVICE + * \retval CUPTI_ERROR_INVALID_METRIC_NAME if unable to find a metric + * with name \p metricName. In this case \p *metric is undefined + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p metricName or \p + * metric are NULL. + */ +CUptiResult CUPTIAPI cuptiMetricGetIdFromName(CUdevice device, + const char *metricName, + CUpti_MetricID *metric); + +/** + * \brief Get number of events required to calculate a metric. + * + * Returns the number of events in \p numEvents that are required to + * calculate a metric. + * + * \param metric ID of the metric + * \param numEvents Returns the number of events required for the metric + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_METRIC_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p numEvents is NULL + */ +CUptiResult CUPTIAPI cuptiMetricGetNumEvents(CUpti_MetricID metric, + uint32_t *numEvents); + +/** + * \brief Get the events required to calculating a metric. + * + * Gets the event IDs in \p eventIdArray required to calculate a \p + * metric. The size of the \p eventIdArray buffer is given by \p + * *eventIdArraySizeBytes and must be at least \p numEvents * + * sizeof(CUpti_EventID) or all events will not be returned. The value + * returned in \p *eventIdArraySizeBytes contains the number of bytes + * returned in \p eventIdArray. + * + * \param metric ID of the metric + * \param eventIdArraySizeBytes The size of \p eventIdArray in bytes, + * and returns the number of bytes written to \p eventIdArray + * \param eventIdArray Returns the IDs of the events required to + * calculate \p metric + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_METRIC_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p eventIdArraySizeBytes or \p + * eventIdArray are NULL. + */ +CUptiResult CUPTIAPI cuptiMetricEnumEvents(CUpti_MetricID metric, + size_t *eventIdArraySizeBytes, + CUpti_EventID *eventIdArray); + +/** + * \brief Get number of properties required to calculate a metric. + * + * Returns the number of properties in \p numProp that are required to + * calculate a metric. + * + * \param metric ID of the metric + * \param numProp Returns the number of properties required for the + * metric + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_METRIC_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p numProp is NULL + */ +CUptiResult CUPTIAPI cuptiMetricGetNumProperties(CUpti_MetricID metric, + uint32_t *numProp); + +/** + * \brief Get the properties required to calculating a metric. + * + * Gets the property IDs in \p propIdArray required to calculate a \p + * metric. The size of the \p propIdArray buffer is given by \p + * *propIdArraySizeBytes and must be at least \p numProp * + * sizeof(CUpti_DeviceAttribute) or all properties will not be + * returned. The value returned in \p *propIdArraySizeBytes contains + * the number of bytes returned in \p propIdArray. + * + * \param metric ID of the metric + * \param propIdArraySizeBytes The size of \p propIdArray in bytes, + * and returns the number of bytes written to \p propIdArray + * \param propIdArray Returns the IDs of the properties required to + * calculate \p metric + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_METRIC_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p propIdArraySizeBytes or \p + * propIdArray are NULL. + */ +CUptiResult CUPTIAPI cuptiMetricEnumProperties(CUpti_MetricID metric, + size_t *propIdArraySizeBytes, + CUpti_MetricPropertyID *propIdArray); + + +/** + * \brief For a metric get the groups of events that must be collected + * in the same pass. + * + * For a metric get the groups of events that must be collected in the + * same pass to ensure that the metric is calculated correctly. If the + * events are not collected as specified then the metric value may be + * inaccurate. + * + * The function returns NULL if a metric does not have any required + * event group. In this case the events needed for the metric can be + * grouped in any manner for collection. + * + * \param context The context for event collection + * \param metric The metric ID + * \param eventGroupSets Returns a CUpti_EventGroupSets object that + * indicates the events that must be collected in the same pass to + * ensure the metric is calculated correctly. Returns NULL if no + * grouping is required for metric + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_METRIC_ID + */ +CUptiResult CUPTIAPI cuptiMetricGetRequiredEventGroupSets(CUcontext context, + CUpti_MetricID metric, + CUpti_EventGroupSets **eventGroupSets); + +/** + * \brief For a set of metrics, get the grouping that indicates the + * number of passes and the event groups necessary to collect the + * events required for those metrics. + * + * For a set of metrics, get the grouping that indicates the number of + * passes and the event groups necessary to collect the events + * required for those metrics. + * + * \see cuptiEventGroupSetsCreate for details on event group set + * creation. + * + * \param context The context for event collection + * \param metricIdArraySizeBytes Size of the metricIdArray in bytes + * \param metricIdArray Array of metric IDs + * \param eventGroupPasses Returns a CUpti_EventGroupSets object that + * indicates the number of passes required to collect the events and + * the events to collect on each pass + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_CONTEXT + * \retval CUPTI_ERROR_INVALID_METRIC_ID + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p metricIdArray or + * \p eventGroupPasses is NULL + */ +CUptiResult CUPTIAPI cuptiMetricCreateEventGroupSets(CUcontext context, + size_t metricIdArraySizeBytes, + CUpti_MetricID *metricIdArray, + CUpti_EventGroupSets **eventGroupPasses); + +/** + * \brief Calculate the value for a metric. + * + * Use the events collected for a metric to calculate the metric + * value. Metric value evaluation depends on the evaluation mode + * \ref CUpti_MetricEvaluationMode that the metric supports. + * If a metric has evaluation mode as CUPTI_METRIC_EVALUATION_MODE_PER_INSTANCE, + * then it assumes that the input event value is for one domain instance. + * If a metric has evaluation mode as CUPTI_METRIC_EVALUATION_MODE_AGGREGATE, + * it assumes that input event values are + * normalized to represent all domain instances on a device. For the + * most accurate metric collection, the events required for the metric + * should be collected for all profiled domain instances. For example, + * to collect all instances of an event, set the + * CUPTI_EVENT_GROUP_ATTR_PROFILE_ALL_DOMAIN_INSTANCES attribute on + * the group containing the event to 1. The normalized value for the + * event is then: (\p sum_event_values * \p totalInstanceCount) / \p + * instanceCount, where \p sum_event_values is the summation of the + * event values across all profiled domain instances, \p + * totalInstanceCount is obtained from querying + * CUPTI_EVENT_DOMAIN_ATTR_TOTAL_INSTANCE_COUNT and \p instanceCount + * is obtained from querying CUPTI_EVENT_GROUP_ATTR_INSTANCE_COUNT (or + * CUPTI_EVENT_DOMAIN_ATTR_INSTANCE_COUNT). + * + * \param device The CUDA device that the metric is being calculated for + * \param metric The metric ID + * \param eventIdArraySizeBytes The size of \p eventIdArray in bytes + * \param eventIdArray The event IDs required to calculate \p metric + * \param eventValueArraySizeBytes The size of \p eventValueArray in bytes + * \param eventValueArray The normalized event values required to + * calculate \p metric. The values must be order to match the order of + * events in \p eventIdArray + * \param timeDuration The duration over which the events were + * collected, in ns + * \param metricValue Returns the value for the metric + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_METRIC_ID + * \retval CUPTI_ERROR_INVALID_OPERATION + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT if the + * eventIdArray does not contain all the events needed for metric + * \retval CUPTI_ERROR_INVALID_EVENT_VALUE if any of the + * event values required for the metric is CUPTI_EVENT_OVERFLOW + * \retval CUPTI_ERROR_INVALID_METRIC_VALUE if the computed metric value + * cannot be represented in the metric's value type. For example, + * if the metric value type is unsigned and the computed metric value is negative + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p metricValue, + * \p eventIdArray or \p eventValueArray is NULL + */ +CUptiResult CUPTIAPI cuptiMetricGetValue(CUdevice device, + CUpti_MetricID metric, + size_t eventIdArraySizeBytes, + CUpti_EventID *eventIdArray, + size_t eventValueArraySizeBytes, + uint64_t *eventValueArray, + uint64_t timeDuration, + CUpti_MetricValue *metricValue); + +/** + * \brief Calculate the value for a metric. + * + * Use the events and properties collected for a metric to calculate + * the metric value. Metric value evaluation depends on the evaluation + * mode \ref CUpti_MetricEvaluationMode that the metric supports. If + * a metric has evaluation mode as + * CUPTI_METRIC_EVALUATION_MODE_PER_INSTANCE, then it assumes that the + * input event value is for one domain instance. If a metric has + * evaluation mode as CUPTI_METRIC_EVALUATION_MODE_AGGREGATE, it + * assumes that input event values are normalized to represent all + * domain instances on a device. For the most accurate metric + * collection, the events required for the metric should be collected + * for all profiled domain instances. For example, to collect all + * instances of an event, set the + * CUPTI_EVENT_GROUP_ATTR_PROFILE_ALL_DOMAIN_INSTANCES attribute on + * the group containing the event to 1. The normalized value for the + * event is then: (\p sum_event_values * \p totalInstanceCount) / \p + * instanceCount, where \p sum_event_values is the summation of the + * event values across all profiled domain instances, \p + * totalInstanceCount is obtained from querying + * CUPTI_EVENT_DOMAIN_ATTR_TOTAL_INSTANCE_COUNT and \p instanceCount + * is obtained from querying CUPTI_EVENT_GROUP_ATTR_INSTANCE_COUNT (or + * CUPTI_EVENT_DOMAIN_ATTR_INSTANCE_COUNT). + * + * \param metric The metric ID + * \param eventIdArraySizeBytes The size of \p eventIdArray in bytes + * \param eventIdArray The event IDs required to calculate \p metric + * \param eventValueArraySizeBytes The size of \p eventValueArray in bytes + * \param eventValueArray The normalized event values required to + * calculate \p metric. The values must be order to match the order of + * events in \p eventIdArray + * \param propIdArraySizeBytes The size of \p propIdArray in bytes + * \param propIdArray The metric property IDs required to calculate \p metric + * \param propValueArraySizeBytes The size of \p propValueArray in bytes + * \param propValueArray The metric property values required to + * calculate \p metric. The values must be order to match the order of + * metric properties in \p propIdArray + * \param metricValue Returns the value for the metric + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_NOT_INITIALIZED + * \retval CUPTI_ERROR_INVALID_METRIC_ID + * \retval CUPTI_ERROR_INVALID_OPERATION + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT if the + * eventIdArray does not contain all the events needed for metric + * \retval CUPTI_ERROR_INVALID_EVENT_VALUE if any of the + * event values required for the metric is CUPTI_EVENT_OVERFLOW + * \retval CUPTI_ERROR_NOT_COMPATIBLE if the computed metric value + * cannot be represented in the metric's value type. For example, + * if the metric value type is unsigned and the computed metric value is negative + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p metricValue, + * \p eventIdArray or \p eventValueArray is NULL + */ +CUptiResult CUPTIAPI cuptiMetricGetValue2(CUpti_MetricID metric, + size_t eventIdArraySizeBytes, + CUpti_EventID *eventIdArray, + size_t eventValueArraySizeBytes, + uint64_t *eventValueArray, + size_t propIdArraySizeBytes, + CUpti_MetricPropertyID *propIdArray, + size_t propValueArraySizeBytes, + uint64_t *propValueArray, + CUpti_MetricValue *metricValue); + +/** @} */ /* END CUPTI_METRIC_API */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /*_CUPTI_METRIC_H_*/ + + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_nvtx_cbid.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_nvtx_cbid.h new file mode 100644 index 0000000000000000000000000000000000000000..5ad8c85e6e674b9a016580be88d3c5a2d2619990 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_nvtx_cbid.h @@ -0,0 +1,111 @@ +/* + * Copyright 2013-2017 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +typedef enum { + CUPTI_CBID_NVTX_INVALID = 0, + CUPTI_CBID_NVTX_nvtxMarkA = 1, + CUPTI_CBID_NVTX_nvtxMarkW = 2, + CUPTI_CBID_NVTX_nvtxMarkEx = 3, + CUPTI_CBID_NVTX_nvtxRangeStartA = 4, + CUPTI_CBID_NVTX_nvtxRangeStartW = 5, + CUPTI_CBID_NVTX_nvtxRangeStartEx = 6, + CUPTI_CBID_NVTX_nvtxRangeEnd = 7, + CUPTI_CBID_NVTX_nvtxRangePushA = 8, + CUPTI_CBID_NVTX_nvtxRangePushW = 9, + CUPTI_CBID_NVTX_nvtxRangePushEx = 10, + CUPTI_CBID_NVTX_nvtxRangePop = 11, + CUPTI_CBID_NVTX_nvtxNameCategoryA = 12, + CUPTI_CBID_NVTX_nvtxNameCategoryW = 13, + CUPTI_CBID_NVTX_nvtxNameOsThreadA = 14, + CUPTI_CBID_NVTX_nvtxNameOsThreadW = 15, + CUPTI_CBID_NVTX_nvtxNameCuDeviceA = 16, + CUPTI_CBID_NVTX_nvtxNameCuDeviceW = 17, + CUPTI_CBID_NVTX_nvtxNameCuContextA = 18, + CUPTI_CBID_NVTX_nvtxNameCuContextW = 19, + CUPTI_CBID_NVTX_nvtxNameCuStreamA = 20, + CUPTI_CBID_NVTX_nvtxNameCuStreamW = 21, + CUPTI_CBID_NVTX_nvtxNameCuEventA = 22, + CUPTI_CBID_NVTX_nvtxNameCuEventW = 23, + CUPTI_CBID_NVTX_nvtxNameCudaDeviceA = 24, + CUPTI_CBID_NVTX_nvtxNameCudaDeviceW = 25, + CUPTI_CBID_NVTX_nvtxNameCudaStreamA = 26, + CUPTI_CBID_NVTX_nvtxNameCudaStreamW = 27, + CUPTI_CBID_NVTX_nvtxNameCudaEventA = 28, + CUPTI_CBID_NVTX_nvtxNameCudaEventW = 29, + CUPTI_CBID_NVTX_nvtxDomainMarkEx = 30, + CUPTI_CBID_NVTX_nvtxDomainRangeStartEx = 31, + CUPTI_CBID_NVTX_nvtxDomainRangeEnd = 32, + CUPTI_CBID_NVTX_nvtxDomainRangePushEx = 33, + CUPTI_CBID_NVTX_nvtxDomainRangePop = 34, + CUPTI_CBID_NVTX_nvtxDomainResourceCreate = 35, + CUPTI_CBID_NVTX_nvtxDomainResourceDestroy = 36, + CUPTI_CBID_NVTX_nvtxDomainNameCategoryA = 37, + CUPTI_CBID_NVTX_nvtxDomainNameCategoryW = 38, + CUPTI_CBID_NVTX_nvtxDomainRegisterStringA = 39, + CUPTI_CBID_NVTX_nvtxDomainRegisterStringW = 40, + CUPTI_CBID_NVTX_nvtxDomainCreateA = 41, + CUPTI_CBID_NVTX_nvtxDomainCreateW = 42, + CUPTI_CBID_NVTX_nvtxDomainDestroy = 43, + CUPTI_CBID_NVTX_nvtxDomainSyncUserCreate = 44, + CUPTI_CBID_NVTX_nvtxDomainSyncUserDestroy = 45, + CUPTI_CBID_NVTX_nvtxDomainSyncUserAcquireStart = 46, + CUPTI_CBID_NVTX_nvtxDomainSyncUserAcquireFailed = 47, + CUPTI_CBID_NVTX_nvtxDomainSyncUserAcquireSuccess = 48, + CUPTI_CBID_NVTX_nvtxDomainSyncUserReleasing = 49, + CUPTI_CBID_NVTX_SIZE, + CUPTI_CBID_NVTX_FORCE_INT = 0x7fffffff +} CUpti_nvtx_api_trace_cbid; + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pcsampling.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pcsampling.h new file mode 100644 index 0000000000000000000000000000000000000000..97f42d14b938204b3b79c4ca1356b88896bcae35 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pcsampling.h @@ -0,0 +1,936 @@ +/* + * Copyright 2020-2022 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_PCSAMPLING_H_) +#define _CUPTI_PCSAMPLING_H_ + +#include +#include +#include +#include "cupti_result.h" +#include "cupti_common.h" + + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_PCSAMPLING_API CUPTI PC Sampling API + * Functions, types, and enums that implement the CUPTI PC Sampling API. + * @{ + */ + +#ifndef CUPTI_PCSAMPLING_STRUCT_SIZE +#define CUPTI_PCSAMPLING_STRUCT_SIZE(type_, lastfield_) (offsetof(type_, lastfield_) + sizeof(((type_*)0)->lastfield_)) +#endif + +#ifndef CUPTI_STALL_REASON_STRING_SIZE +#define CUPTI_STALL_REASON_STRING_SIZE 128 +#endif + +/** + * \brief PC Sampling collection mode + */ +typedef enum +{ + /** + * INVALID Value + */ + CUPTI_PC_SAMPLING_COLLECTION_MODE_INVALID = 0, + /** + * Continuous mode. Kernels are not serialized in this mode. + */ + CUPTI_PC_SAMPLING_COLLECTION_MODE_CONTINUOUS = 1, + /** + * Serialized mode. Kernels are serialized in this mode. + */ + CUPTI_PC_SAMPLING_COLLECTION_MODE_KERNEL_SERIALIZED = 2, +} CUpti_PCSamplingCollectionMode; + +/** + * \brief PC Sampling stall reasons + */ +typedef struct PACKED_ALIGNMENT +{ + /** + * [r] Collected stall reason index + */ + uint32_t pcSamplingStallReasonIndex; + /** + * [r] Number of times the PC was sampled with the stallReason. + */ + uint32_t samples; +} CUpti_PCSamplingStallReason; + +/** + * \brief PC Sampling data + */ +typedef struct PACKED_ALIGNMENT +{ + /** + * [w] Size of the data structure. + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [r] Unique cubin id + */ + uint64_t cubinCrc; + /** + * [r] PC offset + */ + uint64_t pcOffset; + /** + * The function's unique symbol index in the module. + */ + uint32_t functionIndex; + /** + * Padding + */ + uint32_t pad; + /** + * [r] The function name. This name string might be shared across all the records + * including records from activity APIs representing the same function, and so it should not be + * modified or freed until post processing of all the records is done. Once done, it is user’s responsibility to + * free the memory using free() function. + */ + char* functionName; + /** + * [r] Collected stall reason count + */ + size_t stallReasonCount; + /** + * [r] Stall reason id + * Total samples + */ + CUpti_PCSamplingStallReason *stallReason; + /** + * The correlation ID of the kernel to which this result is associated. Only valid for serialized mode of pc sampling collection. + * For continous mode of collection the correlationId will be set to 0. + */ + uint32_t correlationId; +} CUpti_PCSamplingPCData; + +/** + * \brief PC Sampling output data format + */ +typedef enum +{ + CUPTI_PC_SAMPLING_OUTPUT_DATA_FORMAT_INVALID = 0, + /** + * HW buffer data will be parsed during collection of data + */ + CUPTI_PC_SAMPLING_OUTPUT_DATA_FORMAT_PARSED = 1, +} CUpti_PCSamplingOutputDataFormat; + +/** + * \brief Collected PC Sampling data + * + */ +typedef struct PACKED_ALIGNMENT +{ + /** + * [w] Size of the data structure. + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Number of PCs to be collected + */ + size_t collectNumPcs; + /** + * [r] Number of samples collected across all PCs. + * It includes samples for user modules, samples for non-user kernels and dropped samples. + * It includes counts for all non selected stall reasons. + * CUPTI does not provide PC records for non-user kernels. + * CUPTI does not provide PC records for instructions for which all selected stall reason metrics counts are zero. + */ + uint64_t totalSamples; + /** + * [r] Number of samples that were dropped by hardware due to backpressure/overflow. + */ + uint64_t droppedSamples; + /** + * [r] Number of PCs collected + */ + size_t totalNumPcs; + /** + * [r] Number of PCs available for collection + */ + size_t remainingNumPcs; + /** + * [r] Unique identifier for each range. + * Data collected across multiple ranges in multiple buffers can be identified using range id. + */ + uint64_t rangeId; + /** + * [r] Profiled PC data + * This data struct should have enough memory to collect number of PCs mentioned in \brief collectNumPcs + */ + CUpti_PCSamplingPCData *pPcData; + /** + * [r] Number of samples collected across all non user kernels PCs. + * It includes samples for non-user kernels. + * It includes counts for all non selected stall reasons as well. + * CUPTI does not provide PC records for non-user kernels. + */ + uint64_t nonUsrKernelsTotalSamples; + + /** + * [r] Status of the hardware buffer. + * CUPTI returns the error code CUPTI_ERROR_OUT_OF_MEMORY when hardware buffer is full. + * When hardware buffer is full, user will get pc data as 0. To mitigate this issue, one or more of the below options can be tried: + * 1. Increase the hardware buffer size using the attribute CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_HARDWARE_BUFFER_SIZE + * 2. Decrease the thread sleep span using the attribute CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_WORKER_THREAD_PERIODIC_SLEEP_SPAN + * 3. Decrease the sampling frequency using the attribute CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_SAMPLING_PERIOD + */ + uint8_t hardwareBufferFull; +} CUpti_PCSamplingData; + +/** + * \brief PC Sampling configuration attributes + * + * PC Sampling configuration attribute types. These attributes can be read + * using \ref cuptiPCSamplingGetConfigurationAttribute and can be written + * using \ref cuptiPCSamplingSetConfigurationAttribute. Attributes marked + * [r] can only be read using \ref cuptiPCSamplingGetConfigurationAttribute + * [w] can only be written using \ref cuptiPCSamplingSetConfigurationAttribute + * [rw] can be read using \ref cuptiPCSamplingGetConfigurationAttribute and + * written using \ref cuptiPCSamplingSetConfigurationAttribute + */ +typedef enum +{ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_INVALID = 0, + /** + * [rw] Sampling period for PC Sampling. + * DEFAULT - CUPTI defined value based on number of SMs + * Valid values for the sampling + * periods are between 5 to 31 both inclusive. This will set the + * sampling period to (2^samplingPeriod) cycles. + * For e.g. for sampling period = 5 to 31, cycles = 32, 64, 128,..., 2^31 + * Value is a uint32_t + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_SAMPLING_PERIOD = 1, + /** + * [w] Number of stall reasons to collect. + * DEFAULT - All stall reasons will be collected + * Value is a size_t + * [w] Stall reasons to collect + * DEFAULT - All stall reasons will be collected + * Input value should be a pointer pointing to array of stall reason indexes + * containing all the stall reason indexes to collect. + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_STALL_REASON = 2, + /** + * [rw] Size of SW buffer for raw PC counter data downloaded from HW buffer + * DEFAULT - 1 MB, which can accommodate approximately 5500 PCs + * with all stall reasons + * Approximately it takes 16 Bytes (and some fixed size memory) + * to accommodate one PC with one stall reason + * For e.g. 1 PC with 1 stall reason = 32 Bytes + * 1 PC with 2 stall reason = 48 Bytes + * 1 PC with 4 stall reason = 96 Bytes + * Value is a size_t + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_SCRATCH_BUFFER_SIZE = 3, + /** + * [rw] Size of HW buffer in bytes + * DEFAULT - 512 MB + * If sampling period is too less, HW buffer can overflow + * and drop PC data + * Value is a size_t + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_HARDWARE_BUFFER_SIZE = 4, + /** + * [rw] PC Sampling collection mode + * DEFAULT - CUPTI_PC_SAMPLING_COLLECTION_MODE_CONTINUOUS + * Input value should be of type \ref CUpti_PCSamplingCollectionMode. + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_COLLECTION_MODE = 5, + /** + * [rw] Control over PC Sampling data collection range + * Default - 0 + * 1 - Allows user to start and stop PC Sampling using APIs - + * \ref cuptiPCSamplingStart() - Start PC Sampling + * \ref cuptiPCSamplingStop() - Stop PC Sampling + * Value is a uint32_t + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_ENABLE_START_STOP_CONTROL = 6, + /** + * [w] Value for output data format + * Default - CUPTI_PC_SAMPLING_OUTPUT_DATA_FORMAT_PARSED + * Input value should be of type \ref CUpti_PCSamplingOutputDataFormat. + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_OUTPUT_DATA_FORMAT = 7, + /** + * [w] Data buffer to hold collected PC Sampling data PARSED_DATA + * Default - none. + * Buffer type is void * which can point to PARSED_DATA + * Refer \ref CUpti_PCSamplingData for buffer format for PARSED_DATA + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_SAMPLING_DATA_BUFFER = 8, + /** + * [rw] Control sleep time of the worker threads created by CUPTI for various PC sampling operations. + * CUPTI creates multiple worker threads to offload certain operations to these threads. This includes decoding of HW data to + * the CUPTI PC sampling data and correlating PC data to SASS instructions. CUPTI wakes up these threads periodically. + * Default - 100 milliseconds. + * Value is a uint32_t + */ + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_WORKER_THREAD_PERIODIC_SLEEP_SPAN = 9, + CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_FORCE_INT = 0x7fffffff, +} CUpti_PCSamplingConfigurationAttributeType; + +/** + * \brief PC sampling configuration information structure + * + * This structure provides \ref CUpti_PCSamplingConfigurationAttributeType which can be configured + * or queried for PC sampling configuration + */ +typedef struct +{ + /** + * Refer \ref CUpti_PCSamplingConfigurationAttributeType for all supported attribute types + */ + CUpti_PCSamplingConfigurationAttributeType attributeType; + /* + * Configure or query status for \p attributeType + * CUPTI_SUCCESS for valid \p attributeType and \p attributeData + * CUPTI_ERROR_INVALID_OPERATION if \p attributeData is not valid + * CUPTI_ERROR_INVALID_PARAMETER if \p attributeType is not valid + */ + CUptiResult attributeStatus; + union + { + /** + * Invalid Value + */ + struct + { + uint64_t data[3]; + } invalidData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_SAMPLING_PERIOD + */ + struct + { + uint32_t samplingPeriod; + } samplingPeriodData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_STALL_REASON + */ + struct + { + size_t stallReasonCount; + uint32_t *pStallReasonIndex; + } stallReasonData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_SCRATCH_BUFFER_SIZE + */ + struct + { + size_t scratchBufferSize; + } scratchBufferSizeData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_HARDWARE_BUFFER_SIZE + */ + struct + { + size_t hardwareBufferSize; + } hardwareBufferSizeData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_COLLECTION_MODE + */ + struct + { + CUpti_PCSamplingCollectionMode collectionMode; + } collectionModeData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_ENABLE_START_STOP_CONTROL + */ + struct + { + uint32_t enableStartStopControl; + } enableStartStopControlData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_OUTPUT_DATA_FORMAT + */ + struct + { + CUpti_PCSamplingOutputDataFormat outputDataFormat; + } outputDataFormatData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_SAMPLING_DATA_BUFFER + */ + struct + { + void *samplingDataBuffer; + } samplingDataBufferData; + /** + * Refer \ref CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_WORKER_THREAD_PERIODIC_SLEEP_SPAN + */ + struct + { + uint32_t workerThreadPeriodicSleepSpan; + } workerThreadPeriodicSleepSpanData; + + } attributeData; +} CUpti_PCSamplingConfigurationInfo; + +/** + * \brief PC sampling configuration structure + * + * This structure configures PC sampling using \ref cuptiPCSamplingSetConfigurationAttribute + * and queries PC sampling default configuration using \ref cuptiPCSamplingGetConfigurationAttribute + */ +typedef struct +{ + /** + * [w] Size of the data structure i.e. CUpti_PCSamplingConfigurationInfoParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Assign to NULL + */ + void* pPriv; + /** + * [w] CUcontext + */ + CUcontext ctx; + /** + * [w] Number of attributes to configure using \ref cuptiPCSamplingSetConfigurationAttribute or query + * using \ref cuptiPCSamplingGetConfigurationAttribute + */ + size_t numAttributes; + /** + * Refer \ref CUpti_PCSamplingConfigurationInfo + */ + CUpti_PCSamplingConfigurationInfo *pPCSamplingConfigurationInfo; +} CUpti_PCSamplingConfigurationInfoParams; +#define CUpti_PCSamplingConfigurationInfoParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_PCSamplingConfigurationInfoParams,pPCSamplingConfigurationInfo) + +/** + * \brief Write PC Sampling configuration attribute. + * + * \param pParams A pointer to \ref CUpti_PCSamplingConfigurationInfoParams + * containing PC sampling configuration. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called with + * some invalid \p attrib. + * \retval CUPTI_ERROR_INVALID_PARAMETER if attribute \p value is not valid + * or any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingSetConfigurationAttribute(CUpti_PCSamplingConfigurationInfoParams *pParams); + +/** + * \brief Read PC Sampling configuration attribute. + * + * \param pParams A pointer to \ref CUpti_PCSamplingConfigurationInfoParams + * containing PC sampling configuration. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called with + * some invalid attribute. + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p attrib is not valid + * or any \p pParams is not valid + * \retval CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT indicates that + * the \p value buffer is too small to hold the attribute value + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingGetConfigurationAttribute(CUpti_PCSamplingConfigurationInfoParams *pParams); + +/** + * \brief Params for cuptiPCSamplingEnable + */ +typedef struct +{ + /** + * [w] Size of the data structure i.e. CUpti_PCSamplingGetDataParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Assign to NULL + */ + void* pPriv; + /** + * [w] CUcontext + */ + CUcontext ctx; + /** + * \param pcSamplingData Data buffer to hold collected PC Sampling data PARSED_DATA + * Buffer type is void * which can point to PARSED_DATA + * Refer \ref CUpti_PCSamplingData for buffer format for PARSED_DATA + */ + void *pcSamplingData; +} CUpti_PCSamplingGetDataParams; +#define CUpti_PCSamplingGetDataParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_PCSamplingGetDataParams, pcSamplingData) +/** + * \brief Flush GPU PC sampling data periodically. + * + * Flushing of GPU PC Sampling data is required at following point to maintain uniqueness of PCs: + * For \brief CUPTI_PC_SAMPLING_COLLECTION_MODE_CONTINUOUS, after every module load-unload-load + * For \brief CUPTI_PC_SAMPLING_COLLECTION_MODE_KERNEL_SERIALIZED, after every kernel ends + * If configuration option \brief CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_ENABLE_START_STOP_CONTROL + * is enabled, then after every range end i.e. \brief cuptiPCSamplingStop() + * + * If application is profiled in \brief CUPTI_PC_SAMPLING_COLLECTION_MODE_CONTINUOUS, with disabled + * \brief CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_ENABLE_START_STOP_CONTROL, and there is no module unload, + * user can collect data in two ways: + * Use \brief cuptiPCSamplingGetData() API periodically + * Use \brief cuptiPCSamplingDisable() on application exit and read GPU PC sampling data from sampling + * data buffer passed during configuration. + * Note: In case, \brief cuptiPCSamplingGetData() API is not called periodically, then sampling data buffer + * passed during configuration should be large enough to hold all PCs data. + * \brief cuptiPCSamplingGetData() API never does device synchronization. + * It is possible that when the API is called there is some unconsumed data from the HW buffer. In this case + * CUPTI provides only the data available with it at that moment. + * + * \param pParams A pointer to \ref CUpti_PCSamplingGetDataParams + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called without + * enabling PC sampling. + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * \retval CUPTI_ERROR_OUT_OF_MEMORY indicates that the HW buffer is full + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingGetData(CUpti_PCSamplingGetDataParams *pParams); + +/** + * \brief Params for cuptiPCSamplingEnable + */ +typedef struct +{ + /** + * [w] Size of the data structure i.e. CUpti_PCSamplingEnableParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Assign to NULL + */ + void* pPriv; + /** + * [w] CUcontext + */ + CUcontext ctx; +} CUpti_PCSamplingEnableParams; +#define CUpti_PCSamplingEnableParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_PCSamplingEnableParams, ctx) + +/** + * \brief Enable PC sampling. + * + * \param pParams A pointer to \ref CUpti_PCSamplingEnableParams + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingEnable(CUpti_PCSamplingEnableParams *pParams); + +/** + * \brief Params for cuptiPCSamplingDisable + */ +typedef struct +{ + /** + * [w] Size of the data structure i.e. CUpti_PCSamplingDisableParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Assign to NULL + */ + void* pPriv; + /** + * [w] CUcontext + */ + CUcontext ctx; +} CUpti_PCSamplingDisableParams; +#define CUpti_PCSamplingDisableParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_PCSamplingDisableParams, ctx) + +/** + * \brief Disable PC sampling. + * + * For application which doesn't destroy the CUDA context explicitly, + * this API does the PC Sampling tear-down, joins threads and copies PC records in the buffer provided + * during the PC sampling configuration. PC records which can't be accommodated in the buffer are discarded. + * + * \param pParams A pointer to \ref CUpti_PCSamplingDisableParams + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingDisable(CUpti_PCSamplingDisableParams *pParams); + +/** + * \brief Params for cuptiPCSamplingStart + */ +typedef struct +{ + /** + * [w] Size of the data structure i.e. CUpti_PCSamplingStartParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Assign to NULL + */ + void* pPriv; + /** + * [w] CUcontext + */ + CUcontext ctx; +} CUpti_PCSamplingStartParams; +#define CUpti_PCSamplingStartParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_PCSamplingStartParams, ctx) + +/** + * \brief Start PC sampling. + * + * User can collect PC Sampling data for user-defined range specified by Start/Stop APIs. + * This API can be used to mark starting of range. Set configuration option + * \brief CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_ENABLE_START_STOP_CONTROL to use this API. + * + * \param pParams A pointer to \ref CUpti_PCSamplingStartParams + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called with + * incorrect PC Sampling configuration. + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingStart(CUpti_PCSamplingStartParams *pParams); + +/** + * \brief Params for cuptiPCSamplingStop + */ +typedef struct +{ + /** + * [w] Size of the data structure i.e. CUpti_PCSamplingStopParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Assign to NULL + */ + void* pPriv; + /** + * [w] CUcontext + */ + CUcontext ctx; +} CUpti_PCSamplingStopParams; +#define CUpti_PCSamplingStopParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_PCSamplingStopParams, ctx) + +/** + * \brief Stop PC sampling. + * + * User can collect PC Sampling data for user-defined range specified by Start/Stop APIs. + * This API can be used to mark end of range. Set configuration option + * \brief CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_ENABLE_START_STOP_CONTROL to use this API. + * + * \param pParams A pointer to \ref CUpti_PCSamplingStopParams + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called with + * incorrect PC Sampling configuration. + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingStop(CUpti_PCSamplingStopParams *pParams); + +/** + * \brief Params for cuptiPCSamplingGetNumStallReasons + */ +typedef struct +{ + /** + * [w] Size of the data structure i.e. CUpti_PCSamplingGetNumStallReasonsParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Assign to NULL + */ + void* pPriv; + /** + * [w] CUcontext + */ + CUcontext ctx; + /** + * [r] Number of stall reasons + */ + size_t *numStallReasons; +} CUpti_PCSamplingGetNumStallReasonsParams; +#define CUpti_PCSamplingGetNumStallReasonsParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_PCSamplingGetNumStallReasonsParams, numStallReasons) + +/** + * \brief Get PC sampling stall reason count. + * + * \param pParams A pointer to \ref CUpti_PCSamplingGetNumStallReasonsParams + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingGetNumStallReasons(CUpti_PCSamplingGetNumStallReasonsParams *pParams); + +/** + * \brief Params for cuptiPCSamplingGetStallReasons + */ +typedef struct +{ + /** + * [w] Size of the data structure i.e. CUpti_PCSamplingGetStallReasonsParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Assign to NULL + */ + void* pPriv; + /** + * [w] CUcontext + */ + CUcontext ctx; + /** + * [w] Number of stall reasons + */ + size_t numStallReasons; + /** + * [r] Stall reason index + */ + uint32_t *stallReasonIndex; + /** + * [r] Stall reasons name + */ + char **stallReasons; +} CUpti_PCSamplingGetStallReasonsParams; +#define CUpti_PCSamplingGetStallReasonsParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_PCSamplingGetStallReasonsParams, stallReasons) + +/** + * \brief Get PC sampling stall reasons. + * + * \param pParams A pointer to \ref CUpti_PCSamplingGetStallReasonsParams + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device + * does not support the API + */ +CUptiResult CUPTIAPI cuptiPCSamplingGetStallReasons(CUpti_PCSamplingGetStallReasonsParams *pParams); + + +/** + * \brief Params for cuptiGetSassToSourceCorrelation + */ +typedef struct CUpti_GetSassToSourceCorrelationParams { + /** + * [w] Size of the data structure i.e. CUpti_GetSassToSourceCorrelationParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Pointer to cubin binary where function belongs. + */ + const void* cubin; + /** + * [w] Function name to which PC belongs. + */ + const char *functionName; + /** + * [w] Size of cubin binary. + */ + size_t cubinSize; + /** + * [r] Line number in the source code. + */ + uint32_t lineNumber; + /** + * [w] PC offset + */ + uint64_t pcOffset; + /** + * [r] Path for the source file. + */ + char *fileName; + /** + * [r] Path for the directory of source file. + */ + char *dirName; +} CUpti_GetSassToSourceCorrelationParams; + +#define CUpti_GetSassToSourceCorrelationParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_GetSassToSourceCorrelationParams, dirName) + +/** + * \brief SASS to Source correlation. + * + * \param pParams A pointer to \ref CUpti_GetSassToSourceCorrelationParams + * + * It is expected from user to free allocated memory for fileName and dirName after use. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if either of the parameters cubin or functionName + * is NULL or cubinSize is zero or size field is not set correctly. + * \retval CUPTI_ERROR_INVALID_MODULE provided cubin is invalid. + * \retval CUPTI_ERROR_UNKNOWN an internal error occurred. + * This error code is also used for cases when the function is not present in the module. + * A better error code will be returned in the future release. + */ +CUptiResult CUPTIAPI cuptiGetSassToSourceCorrelation(CUpti_GetSassToSourceCorrelationParams *pParams); + +/** + * \brief Params for cuptiGetCubinCrc + */ +typedef struct { + /** + * [w] Size of configuration structure. + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * [w] Size of cubin binary. + */ + size_t cubinSize; + /** + * [w] Pointer to cubin binary + */ + const void* cubin; + /** + * [r] Computed CRC will be stored in it. + */ + uint64_t cubinCrc; +} CUpti_GetCubinCrcParams; +#define CUpti_GetCubinCrcParamsSize CUPTI_PCSAMPLING_STRUCT_SIZE(CUpti_GetCubinCrcParams, cubinCrc) + +/** + * \brief Get the CRC of cubin. + * + * This function returns the CRC of provided cubin binary. + * + * \param pParams A pointer to \ref CUpti_GetCubinCrcParams + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if parameter cubin is NULL or + * provided cubinSize is zero or size field is not set. + */ +CUptiResult CUPTIAPI cuptiGetCubinCrc(CUpti_GetCubinCrcParams *pParams); + +/** + * \brief Function type for callback used by CUPTI to request crc of + * loaded module. + * + * This callback function ask for crc of provided module in function. + * The provided crc will be stored in PC sampling records i.e. in the field 'cubinCrc' of the PC sampling + * struct CUpti_PCSamplingPCData. The CRC is uses during the offline source correlation to uniquely identify the module. + * + * \param cubin The pointer to cubin binary + * \param cubinSize The size of cubin binary. + * \param cubinCrc Returns the computed crc of cubin. + */ +typedef void (CUPTIAPI *CUpti_ComputeCrcCallbackFunc)( + const void* cubin, + size_t cubinSize, + uint64_t *cubinCrc); + +/** + * \brief Register callback function with CUPTI to use + * your own algorithm to compute cubin crc. + * + * This function registers a callback function and it gets called + * from CUPTI when a CUDA module is loaded. + * + * \param funcComputeCubinCrc callback is invoked when a CUDA module + * is loaded. + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p funcComputeCubinCrc is NULL. + */ +CUptiResult CUPTIAPI cuptiRegisterComputeCrcCallback(CUpti_ComputeCrcCallbackFunc funcComputeCubinCrc); + +/** @} */ /* END CUPTI_PCSAMPLING_API */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /*_CUPTI_PCSAMPLING_H_*/ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pcsampling_util.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pcsampling_util.h new file mode 100644 index 0000000000000000000000000000000000000000..595d6028fbf2ff9a3bbffaafe90ec80f7d512533 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pcsampling_util.h @@ -0,0 +1,402 @@ +#if !defined(_CUPTI_PCSAMPLING_UTIL_H_) +#define _CUPTI_PCSAMPLING_UTIL_H_ + +#include +#include + +#include + +#ifndef CUPTI_UTIL_STRUCT_SIZE +#define CUPTI_UTIL_STRUCT_SIZE(type_, lastfield_) (offsetof(type_, lastfield_) + sizeof(((type_*)0)->lastfield_)) +#endif + +#ifndef CHECK_PC_SAMPLING_STRUCT_FIELD_EXISTS +#define CHECK_PC_SAMPLING_STRUCT_FIELD_EXISTS(type, member, structSize) \ + (offsetof(type, member) < structSize) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) + #pragma GCC visibility push(default) +#endif + +namespace CUPTI { namespace PcSamplingUtil { + +/** + * \defgroup CUPTI_PCSAMPLING_UTILITY CUPTI PC Sampling Utility API + * Functions, types, and enums that implement the CUPTI PC Sampling Utility API. + * @{ + */ + +/** + * \brief Header info will be stored in file. + */ +typedef struct PACKED_ALIGNMENT { + /** + * Version of file format. + */ + uint32_t version; + /** + * Total number of buffers present in the file. + */ + uint32_t totalBuffers; +} Header; + +/** + * \brief BufferInfo will be stored in the file for every buffer + * i.e for every call of UtilDumpPcSamplingBufferInFile() API. + */ +typedef struct PACKED_ALIGNMENT { + /** + * Total number of PC records. + */ + uint64_t recordCount; + /** + * Count of all stall reasons supported on the GPU + */ + size_t numStallReasons; + /** + * Total number of stall reasons in single record. + */ + uint64_t numSelectedStallReasons; + /** + * Buffer size in Bytes. + */ + uint64_t bufferByteSize; +} BufferInfo; + +/** + * \brief All available stall reasons name and respective indexes + * will be stored in it. + */ +typedef struct PACKED_ALIGNMENT { + /** + * Number of all available stall reasons + */ + size_t numStallReasons; + /** + * Stall reasons names of all available stall reasons + */ + char **stallReasons; + /** + * Stall reason index of all available stall reasons + */ + uint32_t *stallReasonIndex; +} PcSamplingStallReasons; + +/** + * \brief CUPTI PC sampling buffer types. + * + */ +typedef enum { + /** + * Invalid buffer type. + */ + PC_SAMPLING_BUFFER_INVALID = 0, + /** + * Refers to CUpti_PCSamplingData buffer. + */ + PC_SAMPLING_BUFFER_PC_TO_COUNTER_DATA = 1 +} PcSamplingBufferType; + +/** + * \brief CUPTI PC sampling utility API result codes. + * + * Error and result codes returned by CUPTI PC sampling utility API. + */ +typedef enum { + /** + * No error + */ + CUPTI_UTIL_SUCCESS = 0, + /** + * One or more of the parameters are invalid. + */ + CUPTI_UTIL_ERROR_INVALID_PARAMETER = 1, + /** + * Unable to create a new file + */ + CUPTI_UTIL_ERROR_UNABLE_TO_CREATE_FILE = 2, + /** + * Unable to open a file + */ + CUPTI_UTIL_ERROR_UNABLE_TO_OPEN_FILE = 3, + /** + * Read or write operation failed + */ + CUPTI_UTIL_ERROR_READ_WRITE_OPERATION_FAILED = 4, + /** + * Provided file handle is corrupted. + */ + CUPTI_UTIL_ERROR_FILE_HANDLE_CORRUPTED = 5, + /** + * seek operation failed. + */ + CUPTI_UTIL_ERROR_SEEK_OPERATION_FAILED = 6, + /** + * Unable to allocate enough memory to perform the requested + * operation. + */ + CUPTI_UTIL_ERROR_OUT_OF_MEMORY = 7, + /** + * An unknown internal error has occurred. + */ + CUPTI_UTIL_ERROR_UNKNOWN = 999, + CUPTI_UTIL_ERROR_FORCE_INT = 0x7fffffff +} CUptiUtilResult; + +/** + * \brief Params for \ref CuptiUtilPutPcSampData + */ +typedef struct { + /** + * Size of the data structure i.e. CUpti_PCSamplingDisableParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * Type of buffer to store in file + */ + PcSamplingBufferType bufferType; + /** + * PC sampling buffer. + */ + void *pSamplingData; + /** + * Number of configured attributes + */ + size_t numAttributes; + /** + * Refer \ref CUpti_PCSamplingConfigurationInfo + * It is expected to provide configuration details of at least + * CUPTI_PC_SAMPLING_CONFIGURATION_ATTR_TYPE_STALL_REASON attribute. + */ + CUpti_PCSamplingConfigurationInfo *pPCSamplingConfigurationInfo; + /** + * Refer \ref PcSamplingStallReasons. + */ + PcSamplingStallReasons *pPcSamplingStallReasons; + /** + * File name to store buffer into it. + */ + const char* fileName; +} CUptiUtil_PutPcSampDataParams; +#define CUptiUtil_PutPcSampDataParamsSize CUPTI_UTIL_STRUCT_SIZE(CUptiUtil_PutPcSampDataParams, fileName) + +/** + * \brief Dump PC sampling data into the file. + * + * This API can be called multiple times. + * It will append buffer in the file. + * For every buffer it will store BufferInfo + * so that before retrieving data it will help to allocate buffer + * to store retrieved data. + * This API creates file if file does not present. + * If stallReasonIndex or stallReasons pointer of \ref CUptiUtil_PutPcSampDataParams is NULL + * then stall reasons data will not be stored in file. + * It is expected to store all available stall reason data at least once to refer it during + * offline correlation. + * + * \retval CUPTI_UTIL_SUCCESS + * \retval CUPTI_UTIL_ERROR_INVALID_PARAMETER error out if buffer type is invalid + * or if either of pSamplingData, pParams pointer is NULL or stall reason configuration details not provided + * or filename is empty. + * \retval CUPTI_UTIL_ERROR_UNABLE_TO_CREATE_FILE + * \retval CUPTI_UTIL_ERROR_UNABLE_TO_OPEN_FILE + * \retval CUPTI_UTIL_ERROR_READ_WRITE_OPERATION_FAILED + */ +CUptiUtilResult CUPTIUTILAPI CuptiUtilPutPcSampData(CUptiUtil_PutPcSampDataParams *pParams); + +/** + * \brief Params for \ref CuptiUtilGetHeaderData + */ +typedef struct { + /** + * Size of the data structure i.e. CUpti_PCSamplingDisableParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * File handle. + */ + std::ifstream *fileHandler; + /** + * Header Info. + */ + Header headerInfo; + +} CUptiUtil_GetHeaderDataParams; +#define CUptiUtil_GetHeaderDataParamsSize CUPTI_UTIL_STRUCT_SIZE(CUptiUtil_GetHeaderDataParams, headerInfo) + +/** + * \brief Get header data of file. + * + * This API must be called once initially while retrieving data from file. + * \ref Header structure, it gives info about total number + * of buffers present in the file. + * + * \retval CUPTI_UTIL_SUCCESS + * \retval CUPTI_UTIL_ERROR_INVALID_PARAMETER error out if either of pParam or fileHandle is NULL or param struct size is incorrect. + * \retval CUPTI_UTIL_ERROR_FILE_HANDLE_CORRUPTED file handle is not in good state to read data from file + * \retval CUPTI_UTIL_ERROR_READ_WRITE_OPERATION_FAILED failed to read data from file. + */ +CUptiUtilResult CUPTIUTILAPI CuptiUtilGetHeaderData(CUptiUtil_GetHeaderDataParams *pParams); + +/** + * \brief Params for \ref CuptiUtilGetBufferInfo + */ +typedef struct { + /** + * Size of the data structure i.e. CUpti_PCSamplingDisableParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * File handle. + */ + std::ifstream *fileHandler; + /** + * Buffer Info. + */ + BufferInfo bufferInfoData; +} CUptiUtil_GetBufferInfoParams; +#define CUptiUtil_GetBufferInfoParamsSize CUPTI_UTIL_STRUCT_SIZE(CUptiUtil_GetBufferInfoParams, bufferInfoData) + +/** + * \brief Get buffer info data of file. + * + * This API must be called every time before calling CuptiUtilGetPcSampData API. + * \ref BufferInfo structure, it gives info about recordCount and stallReasonCount + * of every record in the buffer. This will help to allocate exact buffer to retrieve data into it. + * + * \retval CUPTI_UTIL_SUCCESS + * \retval CUPTI_UTIL_ERROR_INVALID_PARAMETER error out if either of pParam or fileHandle is NULL or param struct size is incorrect. + * \retval CUPTI_UTIL_ERROR_FILE_HANDLE_CORRUPTED file handle is not in good state to read data from file. + * \retval CUPTI_UTIL_ERROR_READ_WRITE_OPERATION_FAILED failed to read data from file. + */ +CUptiUtilResult CUPTIUTILAPI CuptiUtilGetBufferInfo(CUptiUtil_GetBufferInfoParams *pParams); + +/** + * \brief Params for \ref CuptiUtilGetPcSampData + */ +typedef struct { + /** + * Size of the data structure i.e. CUpti_PCSamplingDisableParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * File handle. + */ + std::ifstream *fileHandler; + /** + * Type of buffer to store in file + */ + PcSamplingBufferType bufferType; + /** + * Pointer to collected buffer info using \ref CuptiUtilGetBufferInfo + */ + BufferInfo *pBufferInfoData; + /** + * Pointer to allocated memory to store retrieved data from file. + */ + void *pSamplingData; + /** + * Number of configuration attributes + */ + size_t numAttributes; + /** + * Refer \ref CUpti_PCSamplingConfigurationInfo + */ + CUpti_PCSamplingConfigurationInfo *pPCSamplingConfigurationInfo; + /** + * Refer \ref PcSamplingStallReasons. + * For stallReasons field of \ref PcSamplingStallReasons it is expected to + * allocate memory for each string element of array. + */ + PcSamplingStallReasons *pPcSamplingStallReasons; +} CUptiUtil_GetPcSampDataParams; +#define CUptiUtil_GetPcSampDataParamsSize CUPTI_UTIL_STRUCT_SIZE(CUptiUtil_GetPcSampDataParams, pPcSamplingStallReasons) + +/** + * \brief Retrieve PC sampling data from file into allocated buffer. + * + * This API must be called after CuptiUtilGetBufferInfo API. + * It will retrieve data from file into allocated buffer. + * + * \retval CUPTI_UTIL_SUCCESS + * \retval CUPTI_UTIL_ERROR_INVALID_PARAMETER error out if buffer type is invalid + * or if either of pSampData, pParams is NULL. If pPcSamplingStallReasons is not NULL then + * error out if either of stallReasonIndex, stallReasons or stallReasons array element pointer is NULL. + * or filename is empty. + * \retval CUPTI_UTIL_ERROR_READ_WRITE_OPERATION_FAILED + * \retval CUPTI_UTIL_ERROR_FILE_HANDLE_CORRUPTED file handle is not in good state to read data from file. + */ +CUptiUtilResult CUPTIUTILAPI CuptiUtilGetPcSampData(CUptiUtil_GetPcSampDataParams *pParams); + +/** + * \brief Params for \ref CuptiUtilMergePcSampData + */ +typedef struct +{ + /** + * Size of the data structure i.e. CUpti_PCSamplingDisableParamsSize + * CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + * available in the structure. Used to preserve backward compatibility. + */ + size_t size; + /** + * Number of buffers to merge. + */ + size_t numberOfBuffers; + /** + * Pointer to array of buffers to merge + */ + CUpti_PCSamplingData *PcSampDataBuffer; + /** + * Pointer to array of merged buffers as per the range id. + */ + CUpti_PCSamplingData **MergedPcSampDataBuffers; + /** + * Number of merged buffers. + */ + size_t *numMergedBuffer; +} CUptiUtil_MergePcSampDataParams; +#define CUptiUtil_MergePcSampDataParamsSize CUPTI_UTIL_STRUCT_SIZE(CUptiUtil_MergePcSampDataParams, numMergedBuffer) + +/** + * \brief Merge PC sampling data range id wise. + * + * This API merge PC sampling data range id wise. + * It allocates memory for merged data and fill data in it + * and provide buffer pointer in MergedPcSampDataBuffers field. + * It is expected from user to free merge data buffers after use. + * + * \retval CUPTI_UTIL_SUCCESS + * \retval CUPTI_UTIL_ERROR_INVALID_PARAMETER error out if param struct size is invalid + * or count of buffers to merge is invalid i.e less than 1 + * or either of PcSampDataBuffer, MergedPcSampDataBuffers, numMergedBuffer is NULL + * \retval CUPTI_UTIL_ERROR_OUT_OF_MEMORY Unable to allocate memory for merged buffer. + */ +CUptiUtilResult CUPTIUTILAPI CuptiUtilMergePcSampData(CUptiUtil_MergePcSampDataParams *pParams); + +/** @} */ /* END CUPTI_PCSAMPLING_UTILITY */ + +} } + +#if defined(__GNUC__) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pmsampling.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pmsampling.h new file mode 100644 index 0000000000000000000000000000000000000000..ba4171b6710564b56bc7e8e64e46c3674fe6c58c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_pmsampling.h @@ -0,0 +1,490 @@ +/* + * Copyright 2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_PMSAMPLING_H_) +#define _CUPTI_PMSAMPLING_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +#ifndef CUPTI_PROFILER_STRUCT_SIZE +#define CUPTI_PROFILER_STRUCT_SIZE(type_, lastfield_) (offsetof(type_, lastfield_) + sizeof(((type_*)0)->lastfield_)) +#endif + +/* CUPTI PM sampling APIs */ +/** + * \defgroup CUPTI_PM_SAMPLING_API CUPTI PM Sampling API + * Functions to enable, disable, start, stop, and decode PM sampling. + * @{ + */ +typedef struct CUpti_PmSampling_Object CUpti_PmSampling_Object; + +typedef enum CUpti_PmSampling_TriggerMode +{ + /// The trigger is based off of the SYSCLK frequency, note SYS frequency by default is variable. + /// the sample interval (set in the struct CUpti_PmSampling_SetConfig_Params) is in terms of clocks. + CUPTI_PM_SAMPLING_TRIGGER_MODE_GPU_SYSCLK_INTERVAL = 0, + /// The trigger is based off of a fixed frequency source. + /// The sample interval (set in the struct CUpti_PmSampling_SetConfig_Params) is in terms of nanoseconds. + /// Note: This trigger mode is not supported on Turing GPU architecture and GA100 GPU. + /// It is supported on Ampere GA10x and later GPU architectures. + CUPTI_PM_SAMPLING_TRIGGER_MODE_GPU_TIME_INTERVAL = 1, + CUPTI_PM_SAMPLING_TRIGGER_MODE_COUNT +} CUpti_PmSampling_TriggerMode; + +typedef enum CUpti_PmSampling_DecodeStopReason +{ + CUPTI_PM_SAMPLING_DECODE_STOP_REASON_OTHER = 0, + /// Counter data image is full. + CUPTI_PM_SAMPLING_DECODE_STOP_REASON_COUNTER_DATA_FULL, + /// All the records in the hardware buffer is decoded. + CUPTI_PM_SAMPLING_DECODE_STOP_REASON_END_OF_RECORDS, + CUPTI_PM_SAMPLING_DECODE_STOP_REASON_COUNT +} CUpti_PmSampling_DecodeStopReason; + +typedef enum CUpti_PmSampling_HardwareBuffer_AppendMode +{ + /// Keep the oldest records in the hardware buffer. + /// CUPTI will report error for overflow in case hardware buffer is getting filled up. + CUPTI_PM_SAMPLING_HARDWARE_BUFFER_APPEND_MODE_KEEP_OLDEST = 0, + /// Keep the latest records in the hardware buffer. + /// Note: This mode is not supported on Turing GPU architecture. + /// It is supported on Ampere and later GPU architectures. + CUPTI_PM_SAMPLING_HARDWARE_BUFFER_APPEND_MODE_KEEP_LATEST = 1 +} CUpti_PmSampling_HardwareBuffer_AppendMode; + +/** + * \brief Params for cuptiPmSamplingSetConfig + */ +typedef struct CUpti_PmSampling_SetConfig_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; + /// [in] Size of the config image. + size_t configSize; + /// [in] Config image. + const uint8_t* pConfig; + /// [in] The hardware buffer size in which raw PM sampling data + /// will be stored. These samples will be decoded to counter data + /// image with \ref cuptiPmSamplingDecodeData call. + size_t hardwareBufferSize; + /// [in] For the trigger mode `CUPTI_PM_SAMPLING_TRIGGER_MODE_GPU_SYSCLK_INTERVAL`, sampling interval + /// is the number of sys clock cycles. For the trigger mode `CUPTI_PM_SAMPLING_TRIGGER_MODE_GPU_TIME_INTERVAL`, + /// sampling interval is in nanoseconds. + uint64_t samplingInterval; + /// [in] Trigger mode. + /// Note: CUPTI_PM_SAMPLING_TRIGGER_MODE_GPU_TIME_INTERVAL is not supported in Turing and GA100. + /// Supported from GA10x onwards. + CUpti_PmSampling_TriggerMode triggerMode; + /// [in] Append mode for the records in hardware buffer. + /// For KEEP_OLDEST mode, all the records will be kept in the buffer and in case hardware buffer is getting filled up. + /// overflow will be set to 1 in \ref CUpti_PmSampling_DecodeData_Params. For KEEP_LATEST mode, the new records will + /// overwrite the oldest records in the buffer in case of filled buffer. + CUpti_PmSampling_HardwareBuffer_AppendMode hwBufferAppendMode; +} CUpti_PmSampling_SetConfig_Params; + +#define CUpti_PmSampling_SetConfig_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_SetConfig_Params, hwBufferAppendMode) + +/** + * \brief Set the configuration for PM sampling like sampling interval, maximum number of samples + * filled in HW buffer, trigger mode and the config image which has scheduling info for metric collection. + * + * \param pParams A pointer to \ref CUpti_PmSampling_SetConfig_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED for config image which require multiple passes for data collection + */ +CUptiResult CUPTIAPI cuptiPmSamplingSetConfig(CUpti_PmSampling_SetConfig_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingEnable + */ +typedef struct CUpti_PmSampling_Enable_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Device index. + size_t deviceIndex; + /// [out] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; +} CUpti_PmSampling_Enable_Params; + +#define CUpti_PmSampling_Enable_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_Enable_Params, pPmSamplingObject) + +/** + * \brief Create a PM sampling object and enable PM sampling on the CUDA device. + * + * \param pParams A pointer to \ref CUpti_PmSampling_Enable_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_OUT_OF_MEMORY if memory allocation fails while creating the PM sampling object + * \retval CUPTI_ERROR_INVALID_OPERATION if PM sampling is already enabled on the device + * \retval CUPTI_ERROR_INSUFFICIENT_PRIVILEGES if the user does not have sufficient privileges to perform the operation + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingEnable(CUpti_PmSampling_Enable_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingDisable + */ +typedef struct CUpti_PmSampling_Disable_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; +} CUpti_PmSampling_Disable_Params; + +#define CUpti_PmSampling_Disable_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_Disable_Params, pPmSamplingObject) + +/** + * \brief Disable PM sampling on the CUDA device and destroy the PM sampling object. + * + * \param pParams A pointer to \ref CUpti_PmSampling_Disable_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingDisable(CUpti_PmSampling_Disable_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingStart + */ +typedef struct CUpti_PmSampling_Start_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; +} CUpti_PmSampling_Start_Params; + +#define CUpti_PmSampling_Start_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_Start_Params, pPmSamplingObject) + +/** + * \brief Start the PM sampling. The GPU will start collecting the metrics data + * periodically based on trigger type and sampling interval passed in CUpti_PmSampling_SetConfig_Params. + * The collected data will be stored in the hardware buffer. + * + * \param pParams A pointer to \ref CUpti_PmSampling_Start_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if PM sampling Start is called without enabling PM sampling, + * and PM sampling is already started + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingStart(CUpti_PmSampling_Start_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingStop + */ +typedef struct CUpti_PmSampling_Stop_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; +} CUpti_PmSampling_Stop_Params; + +#define CUpti_PmSampling_Stop_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_Stop_Params, pPmSamplingObject) + +/** + * \brief Stop the PM sampling. The GPU will stop collecting the metrics data. + * + * \param pParams A pointer to \ref CUpti_PmSampling_Stop_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if PM sampling Stop is called without enabling PM sampling, + * and PM sampling is already stopped + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingStop(CUpti_PmSampling_Stop_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingDecodeData + */ +typedef struct CUpti_PmSampling_DecodeData_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; + /// [in] Counter data image. + uint8_t* pCounterDataImage; + /// [in] Size of the counter data image. + size_t counterDataImageSize; + /// [out] decode stop reason + CUpti_PmSampling_DecodeStopReason decodeStopReason; + /// [out] overflow status for hardware buffer. + /// To avoid overflow, either increase the maxSamples values in + /// \ref CUpti_PmSampling_SetConfig_Params or reduce the sampling interval. + uint8_t overflow; +} CUpti_PmSampling_DecodeData_Params; + +#define CUpti_PmSampling_DecodeData_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_DecodeData_Params, overflow) + +/** + * \brief Decode the metrics data stored in the hardware buffer to the counter data image. + * + * + * \param pParams A pointer to \ref CUpti_PmSampling_DecodeData_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if PM sampling DecodeData is called without enabling PM sampling + * \retval CUPTI_ERROR_OUT_OF_MEMORY if there is record overflow in the hardware buffer + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingDecodeData(CUpti_PmSampling_DecodeData_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingGetCounterData + */ +typedef struct CUpti_PmSampling_GetCounterAvailability_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Device index. + size_t deviceIndex; + /// [inout] Size of the counter availability image. When pCounterAvailabilityImage is NULL, + /// this field is used to return the size of the counter availability image. + size_t counterAvailabilityImageSize; + /// [out] Counter availability image. + uint8_t* pCounterAvailabilityImage; +} CUpti_PmSampling_GetCounterAvailability_Params; +#define CUpti_PmSampling_GetCounterAvailability_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_GetCounterAvailability_Params, pCounterAvailabilityImage) + +/** + * \brief Query counter availibility information in a buffer which can be used to filter unavailable raw metrics on host. + * Note: This API may fail, if any profiling or sampling session is active on the specified device. + * + * \param pParams A pointer to \ref CUpti_PmSampling_GetCounterAvailability_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INSUFFICIENT_PRIVILEGES if the user does not have sufficient privileges to perform the operation + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingGetCounterAvailability(CUpti_PmSampling_GetCounterAvailability_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingGetCounterDataSize + */ +typedef struct CUpti_PmSampling_GetCounterDataSize_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; + /// [in] Names of the metrics to be collected. + const char** pMetricNames; + /// [in] Number of metrics to be collected. + size_t numMetrics; + /// [in] Maximum number of samples to be stored in the counter data image. + uint32_t maxSamples; + /// [out] Size of the counter data image. + size_t counterDataSize; +} CUpti_PmSampling_GetCounterDataSize_Params; +#define CUpti_PmSampling_GetCounterDataSize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_GetCounterDataSize_Params, counterDataSize) + +/** + * \brief Query the size of the counter data image which will be used to store the metrics data. + * User need to allocate the memory for the counter data image based on the size returned by this API. + * + * \param pParams A pointer to \ref CUpti_PmSampling_GetCounterDataSize_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if PM sampling GetCounterDataSize is called without enabling PM sampling + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingGetCounterDataSize(CUpti_PmSampling_GetCounterDataSize_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingCounterDataImageInitialize + */ +typedef struct CUpti_PmSampling_CounterDataImage_Initialize_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; + /// [in] Size of the counter data image. + size_t counterDataSize; + /// [in] Counter data image. + uint8_t* pCounterData; +} CUpti_PmSampling_CounterDataImage_Initialize_Params; +#define CUpti_PmSampling_CounterDataImage_Initialize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_CounterDataImage_Initialize_Params, pCounterData) + +/** + * \brief Initialize the counter data to CUPTI record format for storing the metric data. + * + * \param pParams A pointer to \ref CUpti_PmSampling_CounterDataImage_Initialize_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if PM sampling CounterDataInitialize is called without enabling PM sampling + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingCounterDataImageInitialize(CUpti_PmSampling_CounterDataImage_Initialize_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingGetCounterDataInfo + */ +typedef struct CUpti_PmSampling_GetCounterDataInfo_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Counter data image. + const uint8_t* pCounterDataImage; + /// [in] Size of the counter data image. + size_t counterDataImageSize; + /// [out] Number of samples in the counter data image. + size_t numTotalSamples; + /// [out] Number of populated samples. + size_t numPopulatedSamples; + /// [out] Number of samples that have been completed. + size_t numCompletedSamples; +} CUpti_PmSampling_GetCounterDataInfo_Params; +#define CUpti_PmSampling_GetCounterDataInfo_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_GetCounterDataInfo_Params, numCompletedSamples) + +/** + * \brief Get the counter data info like number of samples, number of populated + * samples and number of completed samples in a counter data image. + * + * \param pParams A pointer to \ref CUpti_PmSampling_GetCounterDataInfo_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingGetCounterDataInfo(CUpti_PmSampling_GetCounterDataInfo_Params* pParams); + +/** + * \brief Params for cuptiPmSamplingCounterDataGetSampleInfo + */ +typedef struct CUpti_PmSampling_CounterData_GetSampleInfo_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] PM sampling object. + CUpti_PmSampling_Object* pPmSamplingObject; + /// [in] Counter data image. + const uint8_t* pCounterDataImage; + /// [in] Size of the counter data image. + size_t counterDataImageSize; + /// [in] Index of the sample. + size_t sampleIndex; + /// [out] Start time of the sample. + uint64_t startTimestamp; + /// [out] End time of the sample. + uint64_t endTimestamp; +} CUpti_PmSampling_CounterData_GetSampleInfo_Params; +#define CUpti_PmSampling_CounterData_GetSampleInfo_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_PmSampling_CounterData_GetSampleInfo_Params, endTimestamp) + +/** + * \brief Get the sample info (start and end time stamp) for the given sample index. + * Each sample is distinguished by the start and end time stamp. + * + * \param pParams A pointer to \ref CUpti_PmSampling_CounterData_GetSampleInfo_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiPmSamplingCounterDataGetSampleInfo(CUpti_PmSampling_CounterData_GetSampleInfo_Params* pParams); + +/** @} */ /* END CUPTI_PMSAMPLING_API */ +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CUPTI_PMSAMPLING_H_ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_profiler_host.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_profiler_host.h new file mode 100644 index 0000000000000000000000000000000000000000..4e38ceb160791ae51fd681623d45dba1c688dda1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_profiler_host.h @@ -0,0 +1,541 @@ +/* + * Copyright 2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_PROFILER_HOST_H_) +#define _CUPTI_PROFILER_HOST_H_ + +/* +CUPTI profiler host API's +This file contains the CUPTI profiling host API's. +*/ +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_PROFILER_HOST_API CUPTI Profiler Host API + * Functions, types, and enums that implement the CUPTI Profiler Host API. + * @{ + */ +#ifndef CUPTI_PROFILER_STRUCT_SIZE +#define CUPTI_PROFILER_STRUCT_SIZE(type_, lastfield_) (offsetof(type_, lastfield_) + sizeof(((type_*)0)->lastfield_)) +#endif + +typedef enum CUpti_MetricType +{ + CUPTI_METRIC_TYPE_COUNTER = 0, + CUPTI_METRIC_TYPE_RATIO, + CUPTI_METRIC_TYPE_THROUGHPUT, + CUPTI_METRIC_TYPE__COUNT +} CUpti_MetricType; + +typedef enum CUpti_ProfilerType +{ + CUPTI_PROFILER_TYPE_RANGE_PROFILER, + CUPTI_PROFILER_TYPE_PM_SAMPLING, + CUPTI_PROFILER_TYPE_PROFILER_INVALID +} CUpti_ProfilerType; + +typedef struct CUpti_Profiler_Host_Object CUpti_Profiler_Host_Object; + +/** + * \brief Params for cuptiProfilerHostInitialize + */ +typedef struct CUpti_Profiler_Host_Initialize_Params +{ + /// [in] Size of the data structure. + /// CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + /// available in the structure. Used to preserve backward compatibility. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] the profiler kind one from CUpti_ProfilerType + CUpti_ProfilerType profilerType; + /// [in] accepted for chips supported at the time-of-release. + const char* pChipName; + /// [in] buffer with counter availability image - required for future chip support + const uint8_t* pCounterAvailabilityImage; + /// [out] binary blob allocated by CUPTI and operations associated with this object. + CUpti_Profiler_Host_Object* pHostObject; +} CUpti_Profiler_Host_Initialize_Params; + +#define CUpti_Profiler_Host_Initialize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_Initialize_Params, pHostObject) + +/** + * \brief Create and initialize the profiler host object (CUpti_Profiler_Host_Object). + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_Initialize_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostInitialize(CUpti_Profiler_Host_Initialize_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostDeinitialize + */ +typedef struct CUpti_Profiler_Host_Deinitialize_Params +{ + /// [in] Size of the data structure. + /// CUPTI client should set the size of the structure. It will be used in CUPTI to check what fields are + /// available in the structure. Used to preserve backward compatibility. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] reference to the profiler host object allocated by CUPTI in cuptiProfilerHostInitialize + struct CUpti_Profiler_Host_Object* pHostObject; +} CUpti_Profiler_Host_Deinitialize_Params; + +#define CUpti_Profiler_Host_Deinitialize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_Deinitialize_Params, pHostObject) + +/** + * \brief Deinitialize and destroy the profiler host object (CUpti_Profiler_Host_Object). + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_Deinitialize_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostDeinitialize(CUpti_Profiler_Host_Deinitialize_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetSupportedChips + */ +typedef struct CUpti_Profiler_Host_GetSupportedChips_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [out] number of supported chips + size_t numChips; + /// [out] list of supported chips + const char* const* ppChipNames; +} CUpti_Profiler_Host_GetSupportedChips_Params; + +#define CUpti_Profiler_Host_GetSupportedChips_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetSupportedChips_Params, ppChipNames) + +/** + * \brief Get the list of supported chips. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetSupportedChips_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetSupportedChips(CUpti_Profiler_Host_GetSupportedChips_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetSupportedMetrics + */ +typedef struct CUpti_Profiler_Host_GetBaseMetrics_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] reference to the profiler host object allocated by CUPTI in cuptiProfilerHostInitialize + struct CUpti_Profiler_Host_Object* pHostObject; + /// [in] metric type (counter, ratio, throughput) + CUpti_MetricType metricType; + /// [out] list of base metrics supported of queried metric type for the chip + const char** ppMetricNames; + /// [out] number of metrics + size_t numMetrics; +} CUpti_Profiler_Host_GetBaseMetrics_Params; + +#define CUpti_Profiler_Host_GetBaseMetrics_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetBaseMetrics_Params, numMetrics) + +/** + * \brief Get the list of supported base metrics for the chip. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetBaseMetrics_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetBaseMetrics(CUpti_Profiler_Host_GetBaseMetrics_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetSubMetrics + */ +typedef struct CUpti_Profiler_Host_GetSubMetrics_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] reference to the profiler host object allocated by CUPTI in cuptiProfilerHostInitialize + CUpti_Profiler_Host_Object* pHostObject; + /// [in] the metric type for queried metric + CUpti_MetricType metricType; + /// [in] metric name for which sub-metric will be listed + const char* pMetricName; + /// [out] number of submetrics supported + size_t numOfSubmetrics; + /// [out] list of submetrics supported for the metric. + const char** ppSubMetrics; +} CUpti_Profiler_Host_GetSubMetrics_Params; + +#define CUpti_Profiler_Host_GetSubMetrics_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetSubMetrics_Params, ppSubMetrics) + +/** + * \brief Get the list of supported sub-metrics for the metric. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetSubMetrics_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_METRIC_NAME if the metric name is not valid or not supported for the chip + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetSubMetrics(CUpti_Profiler_Host_GetSubMetrics_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetMetricProperties + */ +typedef struct CUpti_Profiler_Host_GetMetricProperties_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] reference to the profiler host object allocated by CUPTI in cuptiProfilerHostInitialize + CUpti_Profiler_Host_Object* pHostObject; + /// [in] metric name for which its properties will be listed + const char* pMetricName; + /// [out] a short description about the metric + const char* pDescription; + /// [out] associated hw unit for the metric + const char* pHwUnit; + /// [out] the dimension of the metric values + const char* pDimUnit; + /// [out] the metric type (counter, ratio or throughput) + CUpti_MetricType metricType; +} CUpti_Profiler_Host_GetMetricProperties_Params; + +#define CUpti_Profiler_Host_GetMetricProperties_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetMetricProperties_Params, metricType) + +/** + * \brief Get the properties of the metric. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetMetricProperties_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_METRIC_NAME if the metric name is not valid or not supported for the chip + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetMetricProperties(CUpti_Profiler_Host_GetMetricProperties_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetRangeName + */ +typedef struct CUpti_Profiler_Host_GetRangeName_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] the counter data image where profiling data has been decoded + const uint8_t* pCounterDataImage; + /// [in] size of counter data image + size_t counterDataImageSize; + /// [in] range index for which the range name will be queried + size_t rangeIndex; + /// [in] used in case of nested ranges, default="/". Range1Range2 + const char* delimiter; + /// [out] the range name. + /// Note: that the CUPTI allocate the memory internal and + /// its user responsibility to free up the allocated memory + const char* pRangeName; +} CUpti_Profiler_Host_GetRangeName_Params; + +#define CUpti_Profiler_Host_GetRangeName_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetRangeName_Params, pRangeName) + +/** + * \brief Get the range name for the range index stored in the counter data. + * In Range profiler, for Auto range mode the range name will be numeric value + * assigned to the kernel based on execution order. For user range mode, the + * name of range will be based on the range name provided by the user using + * Push range API. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetRangeName_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetRangeName(CUpti_Profiler_Host_GetRangeName_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostEvaluateToGpuValues + */ +typedef struct CUpti_Profiler_Host_EvaluateToGpuValues_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] reference to the profiler host object allocated by CUPTI in cuptiProfilerHostInitialize + CUpti_Profiler_Host_Object* pHostObject; + /// [in] the counter data image where profiling data has been decoded + const uint8_t* pCounterDataImage; + /// [in] size of counter data image + size_t counterDataImageSize; + /// [in] range index for which the range name will be queried + size_t rangeIndex; + /// [in] the metrics for which GPU values will be evaluated for the range + const char** ppMetricNames; + /// [in] number of metrics + size_t numMetrics; + /// [out] output value for given metric and range index + double* pMetricValues; +} CUpti_Profiler_Host_EvaluateToGpuValues_Params; + +#define CUpti_Profiler_Host_EvaluateToGpuValues_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_EvaluateToGpuValues_Params, pMetricValues) + +/** + * \brief Evaluate the metric values for the range index stored in the counter data. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_EvaluateToGpuValues_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_METRIC_NAME if the metric name is not valid or not supported for the chip + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostEvaluateToGpuValues(CUpti_Profiler_Host_EvaluateToGpuValues_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostConfigAddMetrics + */ +typedef struct CUpti_Profiler_Host_ConfigAddMetrics_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] reference to the profiler host object allocated by CUPTI in cuptiProfilerHostInitialize + struct CUpti_Profiler_Host_Object* pHostObject; + /// [in] metric names for which config image will be generated + const char** ppMetricNames; + /// [in] number of metrics + size_t numMetrics; +} CUpti_Profiler_Host_ConfigAddMetrics_Params; + +#define CUpti_Profiler_Host_ConfigAddMetrics_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_ConfigAddMetrics_Params, numMetrics) + +/** + * \brief Add the metrics to the profiler host object for generating the config image. + * The config image will have the required information to schedule the metrics for + * collecting the profiling data. + * Note: PM sampling only supports single pass config image. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_ConfigAddMetrics_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_METRIC_NAME if the metric name is not valid or not supported for the chip + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostConfigAddMetrics(CUpti_Profiler_Host_ConfigAddMetrics_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetConfigImageSize + */ +typedef struct CUpti_Profiler_Host_GetConfigImageSize_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] reference to the profiler host object allocated by CUPTI in cuptiProfilerHostInitialize + CUpti_Profiler_Host_Object* pHostObject; + /// [out] the size of config image, users need to allocate the buffer for storing + size_t configImageSize; +} CUpti_Profiler_Host_GetConfigImageSize_Params; + +#define CUpti_Profiler_Host_GetConfigImageSize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetConfigImageSize_Params, configImageSize) + +/** + * \brief Get the size of the config image for the metrics added to the profiler host object. + * Users need to allocate the buffer for storing the config image. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetConfigImageSize_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetConfigImageSize(CUpti_Profiler_Host_GetConfigImageSize_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetConfigImage + */ +typedef struct CUpti_Profiler_Host_GetConfigImage_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] reference to the profiler host object allocated by CUPTI in cuptiProfilerHostInitialize + CUpti_Profiler_Host_Object* pHostObject; + /// [in] Number of bytes allocated for pBuffer + size_t configImageSize; + /// [out] Buffer receiving the config image + uint8_t* pConfigImage; +} CUpti_Profiler_Host_GetConfigImage_Params; + +#define CUpti_Profiler_Host_GetConfigImage_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetConfigImage_Params, pConfigImage) + +/** + * \brief Get the config image for the metrics added to the profiler host object. + * User will pass the allocated buffer to store the config image. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetConfigImage_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetConfigImage(CUpti_Profiler_Host_GetConfigImage_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetNumOfPasses + */ +typedef struct CUpti_Profiler_Host_GetNumOfPasses_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] Number of bytes allocated for pConfigImage + size_t configImageSize; + /// [in] the config image buffer + uint8_t* pConfigImage; + /// [out] number of passes required for profiling scheduled metrics in the config image + size_t numOfPasses; +} CUpti_Profiler_Host_GetNumOfPasses_Params; + +#define CUpti_Profiler_Host_GetNumOfPasses_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetNumOfPasses_Params, numOfPasses) + +/** + * \brief Get the number of passes required for profiling the scheduled metrics in the config image. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetNumOfPasses_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetNumOfPasses(CUpti_Profiler_Host_GetNumOfPasses_Params* pParams); + +/** + * \brief Params for cuptiProfilerHostGetMaxNumHardwareMetricsPerPass + */ +typedef struct CUpti_Profiler_Host_GetMaxNumHardwareMetricsPerPass_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Assign to NULL + void* pPriv; + /// [in] the profiler kind one from CUpti_ProfilerType + CUpti_ProfilerType profilerType; + /// [in] accepted for chips supported at the time-of-release. + const char* pChipName; + /// [in] buffer with counter availability image - required for future chip support + uint8_t* pCounterAvailabilityImage; + /// [out] maximum number of metrics that can be scheduled in a pass + size_t maxMetricsPerPass; +} CUpti_Profiler_Host_GetMaxNumHardwareMetricsPerPass_Params; + +#define CUpti_Profiler_Host_GetMaxNumHardwareMetricsPerPass_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Host_GetMaxNumHardwareMetricsPerPass_Params, maxMetricsPerPass) + +/** + * \brief Get the maximum number of hardware metrics (metric names which doesn't include _sass_ keyword) + * that can be scheduled in a single pass for a chip. While this represents a theoretical upper limit, + * practical constraints may prevent reaching this threshold for a specific set of metrics. Furthermore, + * the maximum achievable value is contingent upon the characteristics and architecture of the chip in question. + * + * Use cuptiProfilerHostGetNumOfPasses API for getting the actual number of passes required for the + * for collecting the profiling data for the scheduled metrics in a config image. + * + * \param pParams A pointer to \ref CUpti_Profiler_Host_GetMaxNumHardwareMetricsPerPass_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiProfilerHostGetMaxNumHardwareMetricsPerPass(CUpti_Profiler_Host_GetMaxNumHardwareMetricsPerPass_Params* pParams); + +/** @} */ /* END CUPTI_METRIC_API */ +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif \ No newline at end of file diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_profiler_target.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_profiler_target.h new file mode 100644 index 0000000000000000000000000000000000000000..a8fc197073dcb3bdec1a7349d136ac03434dc932 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_profiler_target.h @@ -0,0 +1,602 @@ +/* + * Copyright 2011-2023 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_PROFILER_TARGET_H_) +#define _CUPTI_PROFILER_TARGET_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_PROFILER_API CUPTI Profiling API + * Functions, types, and enums that implement the CUPTI Profiling API. + * @{ + */ +#ifndef CUPTI_PROFILER_STRUCT_SIZE +#define CUPTI_PROFILER_STRUCT_SIZE(type_, lastfield_) (offsetof(type_, lastfield_) + sizeof(((type_*)0)->lastfield_)) +#endif + +/** + * \brief Profiler range attribute + * + * A metric enabled in the session's configuration is collected separately per unique range-stack in the pass. + * This is an attribute to collect metrics around each kernel in a profiling session or in an user defined range. + */ +typedef enum +{ + /** + * Invalid value + */ + CUPTI_Range_INVALID, + /** + * Ranges are auto defined around each kernel in a profiling session + */ + CUPTI_AutoRange, + /** + * A range in which metric data to be collected is defined by the user + */ + CUPTI_UserRange, + /** + * Range count + */ + CUPTI_Range_COUNT, +} CUpti_ProfilerRange; + +/** + * \brief Profiler replay attribute + * + * For metrics which require multipass collection, a replay of the GPU kernel(s) is required. + * This is an attribute which specify how the replay of the kernel(s) to be measured is done. + */ +typedef enum +{ + /** + * Invalid Value + */ + CUPTI_Replay_INVALID, + /** + * Replay is done by CUPTI user around the process + */ + CUPTI_ApplicationReplay, + /** + * Replay is done around kernel implicitly by CUPTI + */ + CUPTI_KernelReplay, + /** + * Replay is done by CUPTI user within a process + */ + CUPTI_UserReplay, + /** + * Replay count + */ + CUPTI_Replay_COUNT, +} CUpti_ProfilerReplayMode; + +/** + * \brief Default parameter for cuptiProfilerInitialize + */ +typedef struct CUpti_Profiler_Initialize_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_Initialize_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + +} CUpti_Profiler_Initialize_Params; +#define CUpti_Profiler_Initialize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_Initialize_Params, pPriv) + +/** + * \brief Default parameter for cuptiProfilerDeInitialize + */ +typedef struct CUpti_Profiler_DeInitialize_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_DeInitialize_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + +} CUpti_Profiler_DeInitialize_Params; +#define CUpti_Profiler_DeInitialize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_DeInitialize_Params, pPriv) + +/** + * \brief Initializes the profiler interface + * + * Loads the required libraries in the process address space. + * Sets up the hooks with the CUDA driver. + */ +CUptiResult CUPTIAPI cuptiProfilerInitialize(CUpti_Profiler_Initialize_Params *pParams); + +/** + * \brief DeInitializes the profiler interface + */ +CUptiResult CUPTIAPI cuptiProfilerDeInitialize(CUpti_Profiler_DeInitialize_Params *pParams); + +/** + * \brief Input parameter to define the counterDataImage + */ +typedef struct CUpti_Profiler_CounterDataImageOptions +{ + size_t structSize; //!< [in] CUpti_Profiler_CounterDataImageOptions_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + const uint8_t* pCounterDataPrefix; /**< [in] Address of CounterDataPrefix generated from NVPW_CounterDataBuilder_GetCounterDataPrefix(). + Must be align(8).*/ + size_t counterDataPrefixSize; //!< [in] Size of CounterDataPrefix generated from NVPW_CounterDataBuilder_GetCounterDataPrefix(). + uint32_t maxNumRanges; //!< [in] Maximum number of ranges that can be profiled + uint32_t maxNumRangeTreeNodes; //!< [in] Maximum number of RangeTree nodes; must be >= maxNumRanges + uint32_t maxRangeNameLength; //!< [in] Maximum string length of each RangeName, including the trailing NULL character +} CUpti_Profiler_CounterDataImageOptions; +#define CUpti_Profiler_CounterDataImageOptions_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_CounterDataImageOptions, maxRangeNameLength) + +/** + * \brief Params for cuptiProfilerCounterDataImageCalculateSize + */ +typedef struct CUpti_Profiler_CounterDataImage_CalculateSize_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_CounterDataImage_CalculateSize_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + size_t sizeofCounterDataImageOptions; //!< [in] CUpti_Profiler_CounterDataImageOptions_STRUCT_SIZE + const CUpti_Profiler_CounterDataImageOptions* pOptions; //!< [in] Pointer to Counter Data Image Options + size_t counterDataImageSize; //!< [out] +} CUpti_Profiler_CounterDataImage_CalculateSize_Params; +#define CUpti_Profiler_CounterDataImage_CalculateSize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_CounterDataImage_CalculateSize_Params, counterDataImageSize) + +/** + * \brief Params for cuptiProfilerCounterDataImageInitialize + */ +typedef struct CUpti_Profiler_CounterDataImage_Initialize_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_CounterDataImage_Initialize_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + size_t sizeofCounterDataImageOptions; //!< [in] CUpti_Profiler_CounterDataImageOptions_STRUCT_SIZE + const CUpti_Profiler_CounterDataImageOptions* pOptions; //!< [in] Pointer to Counter Data Image Options + size_t counterDataImageSize; //!< [in] Size calculated from cuptiProfilerCounterDataImageCalculateSize + uint8_t* pCounterDataImage; //!< [in] The buffer to be initialized. +} CUpti_Profiler_CounterDataImage_Initialize_Params; +#define CUpti_Profiler_CounterDataImage_Initialize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_CounterDataImage_Initialize_Params, pCounterDataImage) + +/** + * \brief A CounterData image allocates space for values for each counter for each range. + * + * User borne the resposibility of managing the counterDataImage allocations. + * CounterDataPrefix contains meta data about the metrics that will be stored in counterDataImage. + * Use these APIs to calculate the allocation size and initialize counterData image. + */ +CUptiResult CUPTIAPI cuptiProfilerCounterDataImageCalculateSize(CUpti_Profiler_CounterDataImage_CalculateSize_Params* pParams); +CUptiResult CUPTIAPI cuptiProfilerCounterDataImageInitialize(CUpti_Profiler_CounterDataImage_Initialize_Params* pParams); + +/** + * \brief Params for cuptiProfilerCounterDataImageCalculateScratchBufferSize + */ +typedef struct CUpti_Profiler_CounterDataImage_CalculateScratchBufferSize_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_CounterDataImage_CalculateScratchBufferSize_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + size_t counterDataImageSize; //!< [in] size calculated from cuptiProfilerCounterDataImageCalculateSize + uint8_t* pCounterDataImage; //!< [in] + size_t counterDataScratchBufferSize; //!< [out] +} CUpti_Profiler_CounterDataImage_CalculateScratchBufferSize_Params; +#define CUpti_Profiler_CounterDataImage_CalculateScratchBufferSize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_CounterDataImage_CalculateScratchBufferSize_Params, counterDataScratchBufferSize) + +/** + * \brief Params for cuptiProfilerCounterDataImageInitializeScratchBuffer + */ +typedef struct CUpti_Profiler_CounterDataImage_InitializeScratchBuffer_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_CounterDataImage_InitializeScratchBuffer_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + size_t counterDataImageSize; //!< [in] size calculated from cuptiProfilerCounterDataImageCalculateSize + uint8_t* pCounterDataImage; //!< [in] + size_t counterDataScratchBufferSize; //!< [in] size calculated using cuptiProfilerCounterDataImageCalculateScratchBufferSize + uint8_t* pCounterDataScratchBuffer; //!< [in] the scratch buffer to be initialized. +} CUpti_Profiler_CounterDataImage_InitializeScratchBuffer_Params; +#define CUpti_Profiler_CounterDataImage_InitializeScratchBuffer_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_CounterDataImage_InitializeScratchBuffer_Params, pCounterDataScratchBuffer) + +/** + * \brief A temporary storage for CounterData image needed for internal operations + * + * Use these APIs to calculate the allocation size and initialize counterData image scratch buffer. + */ +CUptiResult CUPTIAPI cuptiProfilerCounterDataImageCalculateScratchBufferSize(CUpti_Profiler_CounterDataImage_CalculateScratchBufferSize_Params* pParams); +CUptiResult CUPTIAPI cuptiProfilerCounterDataImageInitializeScratchBuffer(CUpti_Profiler_CounterDataImage_InitializeScratchBuffer_Params* pParams); + +/** + * \brief Params for cuptiProfilerBeginSession + */ +typedef struct CUpti_Profiler_BeginSession_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_BeginSession_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used + size_t counterDataImageSize; //!< [in] size calculated from cuptiProfilerCounterDataImageCalculateSize + uint8_t* pCounterDataImage; //!< [in] address of CounterDataImage + size_t counterDataScratchBufferSize; //!< [in] size calculated from cuptiProfilerCounterDataImageInitializeScratchBuffer + uint8_t* pCounterDataScratchBuffer; //!< [in] address of CounterDataImage scratch buffer + uint8_t bDumpCounterDataInFile; //!< [in] [optional] + const char* pCounterDataFilePath; //!< [in] [optional] + CUpti_ProfilerRange range; //!< [in] CUpti_ProfilerRange + CUpti_ProfilerReplayMode replayMode; //!< [in] CUpti_ProfilerReplayMode + /* Replay options, required when replay is done by cupti user */ + size_t maxRangesPerPass; //!< [in] Maximum number of ranges that can be recorded in a single pass. + size_t maxLaunchesPerPass; //!< [in] Maximum number of kernel launches that can be recorded in a single pass; must be >= maxRangesPerPass. + +} CUpti_Profiler_BeginSession_Params; +#define CUpti_Profiler_BeginSession_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_BeginSession_Params, maxLaunchesPerPass) +/** + * \brief Params for cuptiProfilerEndSession + */ +typedef struct CUpti_Profiler_EndSession_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_EndSession_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used +} CUpti_Profiler_EndSession_Params; +#define CUpti_Profiler_EndSession_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_EndSession_Params, ctx) + +/** + * \brief Begin profiling session sets up the profiling on the device + * + * Although, it doesn't start the profiling but GPU resources needed for profiling are allocated. + * Outside of a session, the GPU will return to its normal operating state. + */ +CUptiResult CUPTIAPI cuptiProfilerBeginSession(CUpti_Profiler_BeginSession_Params* pParams); +/** + * \brief Ends profiling session + * + * Frees up the GPU resources acquired for profiling. + * Outside of a session, the GPU will return to it's normal operating state. + */ +CUptiResult CUPTIAPI cuptiProfilerEndSession(CUpti_Profiler_EndSession_Params* pParams); + +/** + * \brief Params for cuptiProfilerSetConfig + */ +typedef struct CUpti_Profiler_SetConfig_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_SetConfig_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used + const uint8_t* pConfig; //!< [in] Config created by NVPW_RawMetricsConfig_GetConfigImage(). Must be align(8). + size_t configSize; //!< [in] size of config + uint16_t minNestingLevel; //!< [in] the lowest nesting level to be profiled; must be >= 1 + uint16_t numNestingLevels; //!< [in] the number of nesting levels to profile; must be >= 1 + size_t passIndex; //!< [in] Set this to zero for in-app replay; set this to the output of EndPass() for application replay + uint16_t targetNestingLevel; //!< [in] Set this to minNestingLevel for in-app replay; set this to the output of EndPass() for application +} CUpti_Profiler_SetConfig_Params; + +#define CUpti_Profiler_SetConfig_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_SetConfig_Params, targetNestingLevel) + +/** + * \brief Params for cuptiProfilerUnsetConfig + */ +typedef struct CUpti_Profiler_UnsetConfig_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_UnsetConfig_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used +} CUpti_Profiler_UnsetConfig_Params; +#define CUpti_Profiler_UnsetConfig_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_UnsetConfig_Params, ctx) + +/** + * \brief Set metrics configuration to be profiled + * + * Use these APIs to set the config to profile in a session. It can be used for advanced cases such as where multiple + * configurations are collected into a single CounterData Image on the need basis, without restarting the session. + */ +CUptiResult CUPTIAPI cuptiProfilerSetConfig(CUpti_Profiler_SetConfig_Params* pParams); +/** + * \brief Unset metrics configuration profiled + * + */ +CUptiResult CUPTIAPI cuptiProfilerUnsetConfig(CUpti_Profiler_UnsetConfig_Params* pParams); + +/** + * \brief Params for cuptiProfilerBeginPass + */ +typedef struct CUpti_Profiler_BeginPass_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_BeginPass_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used +} CUpti_Profiler_BeginPass_Params; +#define CUpti_Profiler_BeginPass_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_BeginPass_Params, ctx) + +/** + * \brief Params for cuptiProfilerEndPass + */ +typedef struct CUpti_Profiler_EndPass_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_EndPass_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used + uint16_t targetNestingLevel; //! [out] The targetNestingLevel that will be collected by the *next* BeginPass. + size_t passIndex; //!< [out] The passIndex that will be collected by the *next* BeginPass + uint8_t allPassesSubmitted; //!< [out] becomes true when the last pass has been queued to the GPU +} CUpti_Profiler_EndPass_Params; +#define CUpti_Profiler_EndPass_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_EndPass_Params, allPassesSubmitted) + +/** + * \brief Replay API: used for multipass collection. + + * These APIs are used if user chooses to replay by itself \ref CUPTI_UserReplay or \ref CUPTI_ApplicationReplay + * for multipass collection of the metrics configurations. + * It's a no-op in case of \ref CUPTI_KernelReplay. + */ +CUptiResult CUPTIAPI cuptiProfilerBeginPass(CUpti_Profiler_BeginPass_Params* pParams); + +/** + * \brief Replay API: used for multipass collection. + + * These APIs are used if user chooses to replay by itself \ref CUPTI_UserReplay or \ref CUPTI_ApplicationReplay + * for multipass collection of the metrics configurations. + * Its a no-op in case of \ref CUPTI_KernelReplay. + * Returns information for next pass. + */ +CUptiResult CUPTIAPI cuptiProfilerEndPass(CUpti_Profiler_EndPass_Params* pParams); + +/** + * \brief Params for cuptiProfilerEnableProfiling + */ +typedef struct CUpti_Profiler_EnableProfiling_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_EnableProfiling_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used +} CUpti_Profiler_EnableProfiling_Params; +#define CUpti_Profiler_EnableProfiling_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_EnableProfiling_Params, ctx) + +/** + * \brief Params for cuptiProfilerDisableProfiling + */ +typedef struct CUpti_Profiler_DisableProfiling_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_DisableProfiling_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used +} CUpti_Profiler_DisableProfiling_Params; +#define CUpti_Profiler_DisableProfiling_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_DisableProfiling_Params, ctx) + +/** + * \brief Enables Profiling + * + * In \ref CUPTI_AutoRange, these APIs are used to enable/disable profiling for the kernels to be executed in + * a profiling session. + */ +CUptiResult CUPTIAPI cuptiProfilerEnableProfiling(CUpti_Profiler_EnableProfiling_Params* pParams); + +/** + * \brief Disable Profiling + * + * In \ref CUPTI_AutoRange, these APIs are used to enable/disable profiling for the kernels to be executed in + * a profiling session. + */ +CUptiResult CUPTIAPI cuptiProfilerDisableProfiling(CUpti_Profiler_DisableProfiling_Params* pParams); + +/** + * \brief Params for cuptiProfilerIsPassCollected + */ +typedef struct CUpti_Profiler_IsPassCollected_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_IsPassCollected_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used + size_t numRangesDropped; //!< [out] number of ranges whose data was dropped in the processed pass + size_t numTraceBytesDropped; //!< [out] number of bytes not written to TraceBuffer due to buffer full + uint8_t onePassCollected; //!< [out] true if a pass was successfully decoded + uint8_t allPassesCollected; //!< [out] becomes true when the last pass has been decoded +} CUpti_Profiler_IsPassCollected_Params; +#define CUpti_Profiler_IsPassCollected_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_IsPassCollected_Params, allPassesCollected) + +/** + * \brief Asynchronous call to query if the submitted pass to GPU is collected + * + */ +CUptiResult CUPTIAPI cuptiProfilerIsPassCollected(CUpti_Profiler_IsPassCollected_Params* pParams); + +/** + * \brief Params for cuptiProfilerFlushCounterData + */ +typedef struct CUpti_Profiler_FlushCounterData_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_FlushCounterData_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used + size_t numRangesDropped; //!< [out] number of ranges whose data was dropped in the processed passes + size_t numTraceBytesDropped; //!< [out] number of bytes not written to TraceBuffer due to buffer full +} CUpti_Profiler_FlushCounterData_Params; +#define CUpti_Profiler_FlushCounterData_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_FlushCounterData_Params, numTraceBytesDropped) + +/** + * \brief Decode all the submitted passes + * + * Flush Counter data API to ensure every pass is decoded into the counterDataImage passed at beginSession. + * This will cause the CPU/GPU sync to collect all the undecoded pass. + */ +CUptiResult CUPTIAPI cuptiProfilerFlushCounterData(CUpti_Profiler_FlushCounterData_Params* pParams); + +typedef struct CUpti_Profiler_PushRange_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_PushRange_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used + const char* pRangeName; //!< [in] specifies the range for subsequent launches; must not be NULL + size_t rangeNameLength; //!< [in] assign to strlen(pRangeName) if known; if set to zero, the library will call strlen() +} CUpti_Profiler_PushRange_Params; +#define CUpti_Profiler_PushRange_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_PushRange_Params, rangeNameLength) + +typedef struct CUpti_Profiler_PopRange_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_PopRange_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used +} CUpti_Profiler_PopRange_Params; +#define CUpti_Profiler_PopRange_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_PopRange_Params, ctx) + + +/** + * \brief Range API's : Push user range + * + * Counter data is collected per unique range-stack. Identified by a string label passsed by the user. + * It's an invalid operation in case of \ref CUPTI_AutoRange. + */ +CUptiResult CUPTIAPI cuptiProfilerPushRange(CUpti_Profiler_PushRange_Params *pParams); + +/** + * \brief Range API's : Pop user range + * + * Counter data is collected per unique range-stack. Identified by a string label passsed by the user. + * It's an invalid operation in case of \ref CUPTI_AutoRange. + */ +CUptiResult CUPTIAPI cuptiProfilerPopRange(CUpti_Profiler_PopRange_Params *pParams); + +/** + * \brief Params for cuptiProfilerGetCounterAvailability + */ +typedef struct CUpti_Profiler_GetCounterAvailability_Params +{ + size_t structSize; //!< [in] CUpti_Profiler_GetCounterAvailability_Params_STRUCT_SIZE + void* pPriv; //!< [in] assign to NULL + CUcontext ctx; //!< [in] if NULL, the current CUcontext is used + size_t counterAvailabilityImageSize; //!< [in/out] If `pCounterAvailabilityImage` is NULL, then the required size is returned in + //!< `counterAvailabilityImageSize`, otherwise `counterAvailabilityImageSize` should be set to the size of + //!< `pCounterAvailabilityImage`, and on return it would be overwritten with number of actual bytes copied + uint8_t* pCounterAvailabilityImage; //!< [in] buffer receiving counter availability image, may be NULL +} CUpti_Profiler_GetCounterAvailability_Params; +#define CUpti_Profiler_GetCounterAvailability_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_GetCounterAvailability_Params, pCounterAvailabilityImage) + +/** + * \brief Query counter availibility + * + * Use this API to query counter availability information in a buffer which can be used to filter unavailable raw metrics on host. + * Note: This API may fail, if any profiling or sampling session is active on the specified context or its device. + */ +CUptiResult CUPTIAPI cuptiProfilerGetCounterAvailability(CUpti_Profiler_GetCounterAvailability_Params *pParams); + +/// Generic support level enum for CUPTI +typedef enum +{ + CUPTI_PROFILER_CONFIGURATION_UNKNOWN = 0, //!< Configuration support level unknown - either detection code errored out before setting this value, or unable to determine it + CUPTI_PROFILER_CONFIGURATION_UNSUPPORTED, //!< Profiling is unavailable. For specific feature fields, this means that the current configuration of this feature does not work with profiling. For instance, SLI-enabled devices do not support profiling, and this value would be returned for SLI on an SLI-enabled device. + CUPTI_PROFILER_CONFIGURATION_DISABLED, //!< Profiling would be available for this configuration, but was disabled by the system + CUPTI_PROFILER_CONFIGURATION_SUPPORTED //!< Profiling is supported. For specific feature fields, this means that the current configuration of this feature works with profiling. For instance, SLI-enabled devices do not support profiling, and this value would only be returned for devices which are not SLI-enabled. +} CUpti_Profiler_Support_Level; + +/** + * \brief Profiler API types + */ +typedef enum +{ + CUPTI_PROFILER_RANGE_PROFILING = 0, //!< CUPTI APIs for range based profiling (cuptiProfiler*) + CUPTI_PROFILER_PC_SAMPLING, //!< CUPTI APIs collecting pc sampling data (cuptiPcSampling*) + CUPTI_PROFILER_SASS_METRICS, //!< CUPTI APIs collecting SASS metrics data (cuptiSassMetrics*) + CUPTI_PROFILER_PM_SAMPLING, //!< CUPTI APIs collecting PM Sampling data (cuptiPmSampling*) + CUPTI_PROFILER_UNKNOWN +} CUpti_Profiler_API; + +/** + * \brief Params for cuptiProfilerDeviceSupported + */ +typedef struct +{ + size_t structSize; //!< [in] Must be CUpti_Profiler_DeviceSupported_Params_STRUCT_SIZE + void *pPriv; //!< [in] assign to NULL + CUdevice cuDevice; //!< [in] if NULL, the current CUcontext is used + + CUpti_Profiler_Support_Level isSupported; //!< [out] overall SUPPORTED / UNSUPPORTED flag representing whether Profiling and PC Sampling APIs work on the given device and configuration. SUPPORTED if all following flags are SUPPORTED, UNSUPPORTED otherwise. + + CUpti_Profiler_Support_Level architecture; //!< [out] SUPPORTED if the device architecture level supports the Profiling API (Compute Capability >= 7.0), UNSUPPORTED otherwise + CUpti_Profiler_Support_Level sli; //!< [out] SUPPORTED if SLI is not enabled, UNSUPPORTED otherwise + CUpti_Profiler_Support_Level vGpu; //!< [out] SUPPORTED if vGPU is supported and profiling is enabled, DISABLED if profiling is supported but not enabled, UNSUPPORTED otherwise + CUpti_Profiler_Support_Level confidentialCompute; //!< [out] SUPPORTED if confidential compute is not enabled, UNSUPPORTED otherwise + CUpti_Profiler_Support_Level cmp; //!< [out] SUPPORTED if not NVIDIA Crypto Mining Processors (CMP), UNSUPPORTED otherwise + CUpti_Profiler_Support_Level wsl; //!< [out] SUPPORTED if WSL supported, UNSUPPORTED otherwise + CUpti_Profiler_API api; //!< [in] the CUPTI API type for which device support will be checked +} CUpti_Profiler_DeviceSupported_Params; +#define CUpti_Profiler_DeviceSupported_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Profiler_DeviceSupported_Params, api) + +/** + * \brief Query device compatibility with Profiling API + * + * Use this call to determine whether a compute device and configuration are compatible with the Profiling API. + * If the configuration does not support profiling, one of several flags will indicate why. + */ +CUptiResult CUPTIAPI cuptiProfilerDeviceSupported(CUpti_Profiler_DeviceSupported_Params *pParams); + +/** @} */ /* END CUPTI_METRIC_API */ +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*_CUPTI_PROFILER_TARGET_H_*/ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_range_profiler.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_range_profiler.h new file mode 100644 index 0000000000000000000000000000000000000000..ebcb25c0921bf473df943d63f476b877fdec2d66 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_range_profiler.h @@ -0,0 +1,465 @@ +/* + * Copyright 2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_RANGE_PROFILER_H_) +#define _CUPTI_RANGE_PROFILER_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_RANGE_PROFILER_API CUPTI Range Profiling API + * Functions, types, and enums that implement the CUPTI Range Profiling API. + * @{ + */ +#ifndef CUPTI_PROFILER_STRUCT_SIZE +#define CUPTI_PROFILER_STRUCT_SIZE(type_, lastfield_) (offsetof(type_, lastfield_) + sizeof(((type_*)0)->lastfield_)) +#endif + + +typedef struct CUpti_RangeProfiler_Object CUpti_RangeProfiler_Object; + +/** + * \brief Params for cuptiRangeProfilerSetConfig + */ +typedef struct CUpti_RangeProfiler_SetConfig_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Range Profiler Object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; + /// [in] Size of the config image. + size_t configSize; + /// [in] Config image. + const uint8_t* pConfig; + /// [in] Size of the counter data image. + size_t counterDataImageSize; + /// [in] Counter data image. + uint8_t* pCounterDataImage; + /// [in] Profiling Range mode. + CUpti_ProfilerRange range; + /// [in] Replay mode. + CUpti_ProfilerReplayMode replayMode; + /// [in] Maximum number of ranges that can be profiled in a pass. + size_t maxRangesPerPass; + /// [in] number of nesting level to be profiled. For Auto range mode, this should be set to 1. + uint16_t numNestingLevels; + /// [in] minimum nesting level to be profiled. + uint16_t minNestingLevel; + /// [in] Pass index for the replay session. + size_t passIndex; + /// [in] Target nesting level for the replay session. + uint16_t targetNestingLevel; +} CUpti_RangeProfiler_SetConfig_Params; + +#define CUpti_RangeProfiler_SetConfig_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_SetConfig_Params, targetNestingLevel) + +/** + * \brief Set the configuration for range profiler like maximum number of ranges per pass, number of nesting levels, + * range and replay mode and the config image which has scheduling info for metric collection. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_SetConfig_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + */ +CUptiResult CUPTIAPI cuptiRangeProfilerSetConfig(CUpti_RangeProfiler_SetConfig_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerEnable + */ +typedef struct CUpti_RangeProfiler_Enable_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Context to be used for profiling. + CUcontext ctx; + /// [out] Range Profiler Object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; +} CUpti_RangeProfiler_Enable_Params; +#define CUpti_RangeProfiler_Enable_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_Enable_Params, pRangeProfilerObject) + +/** + * \brief Create a range profiler object and enable range profiling on the CUDA context. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_Enable_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_OUT_OF_MEMORY if memory allocation fails while creating the PM sampling object + * \retval CUPTI_ERROR_INSUFFICIENT_PRIVILEGES if the user does not have sufficient privileges to perform the operation + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiRangeProfilerEnable(CUpti_RangeProfiler_Enable_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerDisable + */ +typedef struct CUpti_RangeProfiler_Disable_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Range Profiler Object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; +} CUpti_RangeProfiler_Disable_Params; +#define CUpti_RangeProfiler_Disable_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_Disable_Params, pRangeProfilerObject) + +/** + * \brief Disable the range profiler on the CUDA context and destroy the range profiler object. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_Disable_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + */ +CUptiResult CUPTIAPI cuptiRangeProfilerDisable(CUpti_RangeProfiler_Disable_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerStart + */ +typedef struct CUpti_RangeProfiler_Start_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Range Profiler Object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; +} CUpti_RangeProfiler_Start_Params; +#define CUpti_RangeProfiler_Start_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_Start_Params, pRangeProfilerObject) + +/** + * \brief Start the range profiler. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_Start_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if range profiler Start is called without enabling range profiler + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiRangeProfilerStart(CUpti_RangeProfiler_Start_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerStop + */ +typedef struct CUpti_RangeProfiler_Stop_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Range Profiler Object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; + /// [out] pass index for the replay session. + size_t passIndex; + /// [out] target nesting level for the replay session. + size_t targetNestingLevel; + /// [out] 1 if all passes are submitted to GPU for collection, 0 otherwise. + uint8_t isAllPassSubmitted; +} CUpti_RangeProfiler_Stop_Params; +#define CUpti_RangeProfiler_Stop_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_Stop_Params, isAllPassSubmitted) + +/** + * \brief Stop the range profiler. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_Stop_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if range profiler Stop is called without enabling range profiler + * \retval CUPTI_ERROR_UNKNOWN for any internal error + */ +CUptiResult CUPTIAPI cuptiRangeProfilerStop(CUpti_RangeProfiler_Stop_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerPushRange + */ +typedef struct CUpti_RangeProfiler_PushRange_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Range Profiler Object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; + /// [in] Name of the range to be profiled (only valid for User range mode). + const char* pRangeName; +} CUpti_RangeProfiler_PushRange_Params; +#define CUpti_RangeProfiler_PushRange_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_PushRange_Params, pRangeName) + +/** + * \brief Add a new range to the Range Profiler with a given range name. + * For nested ranges, this API should be called again for the innermost range. For profiling the nested + * range, users need to set the values for minNestingLevel and numNestingLevels in the SetConfig API. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_PushRange_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if range profiler PushRange is called without enabling range profiler + * \retval CUPTI_ERROR_UNKNOWN for any internal error +*/ +CUptiResult CUPTIAPI cuptiRangeProfilerPushRange(CUpti_RangeProfiler_PushRange_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerPopRange + */ +typedef struct CUpti_RangeProfiler_PopRange_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Range Profiler Object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; +} CUpti_RangeProfiler_PopRange_Params; +#define CUpti_RangeProfiler_PopRange_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_PopRange_Params, pRangeProfilerObject) + +/** + * \brief pop the current range to the Range Profiler. + * The number of pop range API call should be same as number of push ranges in the same order. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_PopRange_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if range profiler PopRange is called without enabling range profiler + * \retval CUPTI_ERROR_UNKNOWN for any internal error +*/ +CUptiResult CUPTIAPI cuptiRangeProfilerPopRange(CUpti_RangeProfiler_PopRange_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerDecodeData + */ +typedef struct CUpti_RangeProfiler_DecodeData_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Range Profiler Object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; + /// [out] Number of ranges dropped in the processed passes. + size_t numOfRangeDropped; +} CUpti_RangeProfiler_DecodeData_Params; +#define CUpti_RangeProfiler_DecodeData_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_DecodeData_Params, numOfRangeDropped) + +/** + * \brief Decode the profiling data stored in the hardware to the counter data image passed in the + * SetConfig API. This API should be called after cuptiRangeProfilerStop. The counter data image + * will be updated with the profiling data for the ranges profiled. + * + * For the cases where the number of ranges counter data image can store is less than the number of ranges + * profiled (= maxRangesPerPass in SetConfig API), the counter data image will report dropped ranges. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_DecodeData_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if range profiler DecodeData is called without enabling range profiler + * \retval CUPTI_ERROR_UNKNOWN for any internal error +*/ +CUptiResult CUPTIAPI cuptiRangeProfilerDecodeData(CUpti_RangeProfiler_DecodeData_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerGetCounterDataSize + */ +typedef struct CUpti_RangeProfiler_GetCounterDataSize_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Periodic sampler object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; + /// [in] Names of the metrics to be collected. + const char** pMetricNames; + /// [in] Number of metrics to be collected. + size_t numMetrics; + /// [in] Maximum number of ranges to be stored in the counter data image. + size_t maxNumOfRanges; + /// [in] Maximum number of RangeTree nodes; must be >= maxNumOfRanges + uint32_t maxNumRangeTreeNodes; + /// [out] Size of the counter data image. + size_t counterDataSize; +} CUpti_RangeProfiler_GetCounterDataSize_Params; +#define CUpti_RangeProfiler_GetCounterDataSize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_GetCounterDataSize_Params, counterDataSize) + +/** + * \brief Get the size of the counter data image required to store the profiling data for the ranges profiled. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_GetCounterDataSize_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if range profiler GetCounterDataSize is called without enabling range profiler + * \retval CUPTI_ERROR_UNKNOWN for any internal error +*/ +CUptiResult CUPTIAPI cuptiRangeProfilerGetCounterDataSize(CUpti_RangeProfiler_GetCounterDataSize_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerCounterDataImageInitialize + */ +typedef struct CUpti_RangeProfiler_CounterDataImage_Initialize_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Periodic sampler object. + CUpti_RangeProfiler_Object* pRangeProfilerObject; + /// [in] Size of the counter data image. + size_t counterDataSize; + /// [in] Counter data image. + uint8_t* pCounterData; +} CUpti_RangeProfiler_CounterDataImage_Initialize_Params; +#define CUpti_RangeProfiler_CounterDataImage_Initialize_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_CounterDataImage_Initialize_Params, pCounterData) + +/** + * \brief Initialize the counter data image with the profiling data for the ranges profiled. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_CounterDataImage_Initialize_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_OPERATION if range profiler CounterDataImageInitialize is called without enabling range profiler + * \retval CUPTI_ERROR_UNKNOWN for any internal error +*/ +CUptiResult CUPTIAPI cuptiRangeProfilerCounterDataImageInitialize(CUpti_RangeProfiler_CounterDataImage_Initialize_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerGetCounterDataInfo + */ +typedef struct CUpti_RangeProfiler_GetCounterDataInfo_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Counter data image. + const uint8_t* pCounterDataImage; + /// [in] Size of the counter data image. + size_t counterDataImageSize; + /// [out] Number of ranges in the counter data image. + size_t numTotalRanges; +} CUpti_RangeProfiler_GetCounterDataInfo_Params; +#define CUpti_RangeProfiler_GetCounterDataInfo_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_GetCounterDataInfo_Params, numTotalRanges) + +/** + * \brief Get the number of ranges stored in the counter data image. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_GetCounterDataInfo_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error +*/ +CUptiResult CUPTIAPI cuptiRangeProfilerGetCounterDataInfo(CUpti_RangeProfiler_GetCounterDataInfo_Params* pParams); + +/** + * \brief Params for cuptiRangeProfilerCounterDataGetRangeInfo + */ +typedef struct CUpti_RangeProfiler_CounterData_GetRangeInfo_Params +{ + /// [in] Size of the data structure. + size_t structSize; + /// [in] Set to NULL. + void* pPriv; + /// [in] Counter data image. + const uint8_t* pCounterDataImage; + /// [in] Size of the counter data image. + size_t counterDataImageSize; + /// [in] Index of the sample. + size_t rangeIndex; + /// [in] range delimiter. + const char* rangeDelimiter; + /// [out] RangeName; + const char* rangeName; +} CUpti_RangeProfiler_CounterData_GetRangeInfo_Params; +#define CUpti_RangeProfiler_CounterData_GetRangeInfo_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_RangeProfiler_CounterData_GetRangeInfo_Params, rangeName) + +/** + * \brief Get the range name for the given range index. + * + * \param pParams A pointer to \ref CUpti_RangeProfiler_CounterData_GetRangeInfo_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_UNKNOWN for any internal error +*/ +CUptiResult CUPTIAPI cuptiRangeProfilerCounterDataGetRangeInfo(CUpti_RangeProfiler_CounterData_GetRangeInfo_Params* pParams); + + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*_CUPTI_RANGE_PROFILER_H_*/ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_result.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_result.h new file mode 100644 index 0000000000000000000000000000000000000000..10371ac621b2472086a4d68af4dc9bdc91f8e417 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_result.h @@ -0,0 +1,360 @@ +/* + * Copyright 2010-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_RESULT_H_) +#define _CUPTI_RESULT_H_ + +#ifndef CUPTIAPI +#ifdef _WIN32 +#define CUPTIAPI __stdcall +#else +#define CUPTIAPI +#endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_RESULT_API CUPTI Result Codes + * Error and result codes returned by CUPTI functions. + * @{ + */ + +/** + * \brief CUPTI result codes. + * + * Error and result codes returned by CUPTI functions. + */ +typedef enum { + /** + * No error. + */ + CUPTI_SUCCESS = 0, + /** + * One or more of the parameters is invalid. + */ + CUPTI_ERROR_INVALID_PARAMETER = 1, + /** + * The device does not correspond to a valid CUDA device. + */ + CUPTI_ERROR_INVALID_DEVICE = 2, + /** + * The context is NULL or not valid. + */ + CUPTI_ERROR_INVALID_CONTEXT = 3, + /** + * The event domain id is invalid. + */ + CUPTI_ERROR_INVALID_EVENT_DOMAIN_ID = 4, + /** + * The event id is invalid. + */ + CUPTI_ERROR_INVALID_EVENT_ID = 5, + /** + * The event name is invalid. + */ + CUPTI_ERROR_INVALID_EVENT_NAME = 6, + /** + * The current operation cannot be performed due to dependency on + * other factors. + */ + CUPTI_ERROR_INVALID_OPERATION = 7, + /** + * Unable to allocate enough memory to perform the requested + * operation. + */ + CUPTI_ERROR_OUT_OF_MEMORY = 8, + /** + * An error occurred on the performance monitoring hardware. + */ + CUPTI_ERROR_HARDWARE = 9, + /** + * The output buffer size is not sufficient to return all + * requested data. + */ + CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT = 10, + /** + * API is not implemented. + */ + CUPTI_ERROR_API_NOT_IMPLEMENTED = 11, + /** + * The maximum limit is reached. + */ + CUPTI_ERROR_MAX_LIMIT_REACHED = 12, + /** + * The object is not yet ready to perform the requested operation. + */ + CUPTI_ERROR_NOT_READY = 13, + /** + * The current operation is not compatible with the current state + * of the object + */ + CUPTI_ERROR_NOT_COMPATIBLE = 14, + /** + * CUPTI is unable to initialize its connection to the CUDA + * driver. + */ + CUPTI_ERROR_NOT_INITIALIZED = 15, + /** + * The metric id is invalid. + */ + CUPTI_ERROR_INVALID_METRIC_ID = 16, + /** + * The metric name is invalid. + */ + CUPTI_ERROR_INVALID_METRIC_NAME = 17, + /** + * The queue is empty. + */ + CUPTI_ERROR_QUEUE_EMPTY = 18, + /** + * Invalid handle (internal?). + */ + CUPTI_ERROR_INVALID_HANDLE = 19, + /** + * Invalid stream. + */ + CUPTI_ERROR_INVALID_STREAM = 20, + /** + * Invalid kind. + */ + CUPTI_ERROR_INVALID_KIND = 21, + /** + * Invalid event value. + */ + CUPTI_ERROR_INVALID_EVENT_VALUE = 22, + /** + * CUPTI is disabled due to conflicts with other enabled profilers + */ + CUPTI_ERROR_DISABLED = 23, + /** + * Invalid module. + */ + CUPTI_ERROR_INVALID_MODULE = 24, + /** + * Invalid metric value. + */ + CUPTI_ERROR_INVALID_METRIC_VALUE = 25, + /** + * The performance monitoring hardware is in use by other client. + */ + CUPTI_ERROR_HARDWARE_BUSY = 26, + /** + * The attempted operation is not supported on the current + * system or device. + */ + CUPTI_ERROR_NOT_SUPPORTED = 27, + /** + * Unified memory profiling is not supported on the system. + * Potential reason could be unsupported OS or architecture. + */ + CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED = 28, + /** + * Unified memory profiling is not supported on the device + */ + CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_ON_DEVICE = 29, + /** + * Unified memory profiling is not supported on a multi-GPU + * configuration without P2P support between any pair of devices + */ + CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_ON_NON_P2P_DEVICES = 30, + /** + * Unified memory profiling is not supported under the + * Multi-Process Service (MPS) environment. CUDA 7.5 removes this + * restriction. + */ + CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_WITH_MPS = 31, + /** + * In CUDA 9.0, devices with compute capability 7.0 don't + * support CDP tracing + */ + CUPTI_ERROR_CDP_TRACING_NOT_SUPPORTED = 32, + /** + * Profiling on virtualized GPU is not supported. + */ + CUPTI_ERROR_VIRTUALIZED_DEVICE_NOT_SUPPORTED = 33, + /** + * Profiling results might be incorrect for CUDA applications + * compiled with nvcc version older than 9.0 for devices with + * compute capability 6.0 and 6.1. + * Profiling session will continue and CUPTI will notify it using this error code. + * User is advised to recompile the application code with nvcc version 9.0 or later. + * Ignore this warning if code is already compiled with the recommended nvcc version. + */ + CUPTI_ERROR_CUDA_COMPILER_NOT_COMPATIBLE = 34, + /** + * User doesn't have sufficient privileges which are required to + * start the profiling session. + * One possible reason for this may be that the NVIDIA driver or your system + * administrator may have restricted access to the NVIDIA GPU performance counters. + * To learn how to resolve this issue and find more information, please visit + * https://developer.nvidia.com/CUPTI_ERROR_INSUFFICIENT_PRIVILEGES + */ + CUPTI_ERROR_INSUFFICIENT_PRIVILEGES = 35, + /** + * Legacy CUPTI Profiling API i.e. event API from the header cupti_events.h and + * metric API from the header cupti_metrics.h are not compatible with the + * Profiling API in the header cupti_profiler_target.h and Perfworks metrics API + * in the headers nvperf_host.h and nvperf_target.h. + */ + CUPTI_ERROR_OLD_PROFILER_API_INITIALIZED = 36, + /** + * Missing definition of the OpenACC API routine in the linked OpenACC library. + * + * One possible reason is that OpenACC library is linked statically in the + * user application, which might not have the definition of all the OpenACC + * API routines needed for the OpenACC profiling, as compiler might ignore + * definitions for the functions not used in the application. This issue + * can be mitigated by linking the OpenACC library dynamically. + */ + CUPTI_ERROR_OPENACC_UNDEFINED_ROUTINE = 37, + /** + * Legacy CUPTI Profiling API i.e. event API from the header cupti_events.h and + * metric API from the header cupti_metrics.h are not supported on devices with + * compute capability 7.5 and higher (i.e. Turing and later GPU architectures). + * These APIs are deprecated in the CUDA 12.8 release and will be removed in a future CUDA release. + * These are replaced by the host profiling API in the header cupti_profiler_host.h and + * target profiling API in the header cupti_range_profiler.h which are supported on + * devices with compute capability 7.0 and higher (i.e. Volta and later GPU + * architectures). + */ + CUPTI_ERROR_LEGACY_PROFILER_NOT_SUPPORTED = 38, + /** + * CUPTI doesn't allow multiple callback subscribers. Only a single subscriber + * can be registered at a time. + * Same error code is used when application is launched using NVIDIA tools + * like nvprof, Visual Profiler, Nsight Systems, Nsight Compute, cuda-gdb and + * cuda-memcheck. + */ + CUPTI_ERROR_MULTIPLE_SUBSCRIBERS_NOT_SUPPORTED = 39, + /** + * Profiling on virtualized GPU is not allowed by hypervisor. + */ + CUPTI_ERROR_VIRTUALIZED_DEVICE_INSUFFICIENT_PRIVILEGES = 40, + /** + * Profiling and tracing are not allowed when confidential computing mode + * is enabled. + */ + CUPTI_ERROR_CONFIDENTIAL_COMPUTING_NOT_SUPPORTED = 41, + /** + * CUPTI does not support NVIDIA Crypto Mining Processors (CMP). + * For more information, please visit https://developer.nvidia.com/ERR_NVCMPGPU + */ + CUPTI_ERROR_CMP_DEVICE_NOT_SUPPORTED = 42, + /** + * Profiling on Multi-instance GPU (MIG) is not supported. + */ + CUPTI_ERROR_MIG_DEVICE_NOT_SUPPORTED = 43, + /** + * Profiling on SLI device is not supported. + */ + CUPTI_ERROR_SLI_DEVICE_NOT_SUPPORTED = 44, + /** + * Profiling on WSL device is not supported. + */ + CUPTI_ERROR_WSL_DEVICE_NOT_SUPPORTED = 45, + /** + * An unknown internal error has occurred. + */ + CUPTI_ERROR_UNKNOWN = 999, + CUPTI_ERROR_FORCE_INT = 0x7fffffff +} CUptiResult; + +/** + * \brief Get the descriptive string for a CUptiResult. + * + * Return the descriptive string for a CUptiResult in \p *str. + * \note \b Thread-safety: this function is thread safe. + * + * \param result The result to get the string for + * \param str Returns the string + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p str is NULL or \p + * result is not a valid CUptiResult + */ +CUptiResult CUPTIAPI cuptiGetResultString(CUptiResult result, const char **str); + +/** + * @brief Get the descriptive message corresponding to error codes returned + * by CUPTI. + * + * Return the descriptive error message for a CUptiResult in \p *str. + * \note \b Thread-safety: this function is thread safe. + * + * \param result The result to get the descriptive error message for + * \param str Returns the error message string + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p str is NULL or \p + * result is not a valid CUptiResult + * + */ + +CUptiResult CUPTIAPI cuptiGetErrorMessage(CUptiResult result, const char **str); + +/** @} */ /* END CUPTI_RESULT_API */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /*_CUPTI_RESULT_H_*/ + + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_runtime_cbid.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_runtime_cbid.h new file mode 100644 index 0000000000000000000000000000000000000000..16b41e475fcfcf76e6507949699cd04c594becc9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_runtime_cbid.h @@ -0,0 +1,504 @@ + +// ************************************************************************* +// Definitions of indices for API functions, unique across entire API +// ************************************************************************* + +// This file is generated. Any changes you make will be lost during the next clean build. +// CUDA public interface, for type definitions and cu* function prototypes + +#if !defined(_CUPTI_RUNTIME_CBID_H) +#define _CUPTI_RUNTIME_CBID_H + +typedef enum CUpti_runtime_api_trace_cbid_enum { + CUPTI_RUNTIME_TRACE_CBID_INVALID = 0, + CUPTI_RUNTIME_TRACE_CBID_cudaDriverGetVersion_v3020 = 1, + CUPTI_RUNTIME_TRACE_CBID_cudaRuntimeGetVersion_v3020 = 2, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDeviceCount_v3020 = 3, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDeviceProperties_v3020 = 4, + CUPTI_RUNTIME_TRACE_CBID_cudaChooseDevice_v3020 = 5, + CUPTI_RUNTIME_TRACE_CBID_cudaGetChannelDesc_v3020 = 6, + CUPTI_RUNTIME_TRACE_CBID_cudaCreateChannelDesc_v3020 = 7, + CUPTI_RUNTIME_TRACE_CBID_cudaConfigureCall_v3020 = 8, + CUPTI_RUNTIME_TRACE_CBID_cudaSetupArgument_v3020 = 9, + CUPTI_RUNTIME_TRACE_CBID_cudaGetLastError_v3020 = 10, + CUPTI_RUNTIME_TRACE_CBID_cudaPeekAtLastError_v3020 = 11, + CUPTI_RUNTIME_TRACE_CBID_cudaGetErrorString_v3020 = 12, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunch_v3020 = 13, + CUPTI_RUNTIME_TRACE_CBID_cudaFuncSetCacheConfig_v3020 = 14, + CUPTI_RUNTIME_TRACE_CBID_cudaFuncGetAttributes_v3020 = 15, + CUPTI_RUNTIME_TRACE_CBID_cudaSetDevice_v3020 = 16, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDevice_v3020 = 17, + CUPTI_RUNTIME_TRACE_CBID_cudaSetValidDevices_v3020 = 18, + CUPTI_RUNTIME_TRACE_CBID_cudaSetDeviceFlags_v3020 = 19, + CUPTI_RUNTIME_TRACE_CBID_cudaMalloc_v3020 = 20, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocPitch_v3020 = 21, + CUPTI_RUNTIME_TRACE_CBID_cudaFree_v3020 = 22, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocArray_v3020 = 23, + CUPTI_RUNTIME_TRACE_CBID_cudaFreeArray_v3020 = 24, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocHost_v3020 = 25, + CUPTI_RUNTIME_TRACE_CBID_cudaFreeHost_v3020 = 26, + CUPTI_RUNTIME_TRACE_CBID_cudaHostAlloc_v3020 = 27, + CUPTI_RUNTIME_TRACE_CBID_cudaHostGetDevicePointer_v3020 = 28, + CUPTI_RUNTIME_TRACE_CBID_cudaHostGetFlags_v3020 = 29, + CUPTI_RUNTIME_TRACE_CBID_cudaMemGetInfo_v3020 = 30, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy_v3020 = 31, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2D_v3020 = 32, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyToArray_v3020 = 33, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DToArray_v3020 = 34, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyFromArray_v3020 = 35, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DFromArray_v3020 = 36, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyArrayToArray_v3020 = 37, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DArrayToArray_v3020 = 38, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyToSymbol_v3020 = 39, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyFromSymbol_v3020 = 40, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyAsync_v3020 = 41, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyToArrayAsync_v3020 = 42, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyFromArrayAsync_v3020 = 43, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DAsync_v3020 = 44, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DToArrayAsync_v3020 = 45, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DFromArrayAsync_v3020 = 46, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyToSymbolAsync_v3020 = 47, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyFromSymbolAsync_v3020 = 48, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset_v3020 = 49, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset2D_v3020 = 50, + CUPTI_RUNTIME_TRACE_CBID_cudaMemsetAsync_v3020 = 51, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset2DAsync_v3020 = 52, + CUPTI_RUNTIME_TRACE_CBID_cudaGetSymbolAddress_v3020 = 53, + CUPTI_RUNTIME_TRACE_CBID_cudaGetSymbolSize_v3020 = 54, + CUPTI_RUNTIME_TRACE_CBID_cudaBindTexture_v3020 = 55, + CUPTI_RUNTIME_TRACE_CBID_cudaBindTexture2D_v3020 = 56, + CUPTI_RUNTIME_TRACE_CBID_cudaBindTextureToArray_v3020 = 57, + CUPTI_RUNTIME_TRACE_CBID_cudaUnbindTexture_v3020 = 58, + CUPTI_RUNTIME_TRACE_CBID_cudaGetTextureAlignmentOffset_v3020 = 59, + CUPTI_RUNTIME_TRACE_CBID_cudaGetTextureReference_v3020 = 60, + CUPTI_RUNTIME_TRACE_CBID_cudaBindSurfaceToArray_v3020 = 61, + CUPTI_RUNTIME_TRACE_CBID_cudaGetSurfaceReference_v3020 = 62, + CUPTI_RUNTIME_TRACE_CBID_cudaGLSetGLDevice_v3020 = 63, + CUPTI_RUNTIME_TRACE_CBID_cudaGLRegisterBufferObject_v3020 = 64, + CUPTI_RUNTIME_TRACE_CBID_cudaGLMapBufferObject_v3020 = 65, + CUPTI_RUNTIME_TRACE_CBID_cudaGLUnmapBufferObject_v3020 = 66, + CUPTI_RUNTIME_TRACE_CBID_cudaGLUnregisterBufferObject_v3020 = 67, + CUPTI_RUNTIME_TRACE_CBID_cudaGLSetBufferObjectMapFlags_v3020 = 68, + CUPTI_RUNTIME_TRACE_CBID_cudaGLMapBufferObjectAsync_v3020 = 69, + CUPTI_RUNTIME_TRACE_CBID_cudaGLUnmapBufferObjectAsync_v3020 = 70, + CUPTI_RUNTIME_TRACE_CBID_cudaWGLGetDevice_v3020 = 71, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsGLRegisterImage_v3020 = 72, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsGLRegisterBuffer_v3020 = 73, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsUnregisterResource_v3020 = 74, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsResourceSetMapFlags_v3020 = 75, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsMapResources_v3020 = 76, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsUnmapResources_v3020 = 77, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsResourceGetMappedPointer_v3020 = 78, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsSubResourceGetMappedArray_v3020 = 79, + CUPTI_RUNTIME_TRACE_CBID_cudaVDPAUGetDevice_v3020 = 80, + CUPTI_RUNTIME_TRACE_CBID_cudaVDPAUSetVDPAUDevice_v3020 = 81, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsVDPAURegisterVideoSurface_v3020 = 82, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsVDPAURegisterOutputSurface_v3020 = 83, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D11GetDevice_v3020 = 84, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D11GetDevices_v3020 = 85, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D11SetDirect3DDevice_v3020 = 86, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsD3D11RegisterResource_v3020 = 87, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10GetDevice_v3020 = 88, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10GetDevices_v3020 = 89, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10SetDirect3DDevice_v3020 = 90, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsD3D10RegisterResource_v3020 = 91, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10RegisterResource_v3020 = 92, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10UnregisterResource_v3020 = 93, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10MapResources_v3020 = 94, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10UnmapResources_v3020 = 95, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10ResourceSetMapFlags_v3020 = 96, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10ResourceGetSurfaceDimensions_v3020 = 97, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10ResourceGetMappedArray_v3020 = 98, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10ResourceGetMappedPointer_v3020 = 99, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10ResourceGetMappedSize_v3020 = 100, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10ResourceGetMappedPitch_v3020 = 101, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9GetDevice_v3020 = 102, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9GetDevices_v3020 = 103, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9SetDirect3DDevice_v3020 = 104, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9GetDirect3DDevice_v3020 = 105, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsD3D9RegisterResource_v3020 = 106, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9RegisterResource_v3020 = 107, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9UnregisterResource_v3020 = 108, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9MapResources_v3020 = 109, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9UnmapResources_v3020 = 110, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9ResourceSetMapFlags_v3020 = 111, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9ResourceGetSurfaceDimensions_v3020 = 112, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9ResourceGetMappedArray_v3020 = 113, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9ResourceGetMappedPointer_v3020 = 114, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9ResourceGetMappedSize_v3020 = 115, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9ResourceGetMappedPitch_v3020 = 116, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9Begin_v3020 = 117, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9End_v3020 = 118, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9RegisterVertexBuffer_v3020 = 119, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9UnregisterVertexBuffer_v3020 = 120, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9MapVertexBuffer_v3020 = 121, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D9UnmapVertexBuffer_v3020 = 122, + CUPTI_RUNTIME_TRACE_CBID_cudaThreadExit_v3020 = 123, + CUPTI_RUNTIME_TRACE_CBID_cudaSetDoubleForDevice_v3020 = 124, + CUPTI_RUNTIME_TRACE_CBID_cudaSetDoubleForHost_v3020 = 125, + CUPTI_RUNTIME_TRACE_CBID_cudaThreadSynchronize_v3020 = 126, + CUPTI_RUNTIME_TRACE_CBID_cudaThreadGetLimit_v3020 = 127, + CUPTI_RUNTIME_TRACE_CBID_cudaThreadSetLimit_v3020 = 128, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamCreate_v3020 = 129, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamDestroy_v3020 = 130, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamSynchronize_v3020 = 131, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamQuery_v3020 = 132, + CUPTI_RUNTIME_TRACE_CBID_cudaEventCreate_v3020 = 133, + CUPTI_RUNTIME_TRACE_CBID_cudaEventCreateWithFlags_v3020 = 134, + CUPTI_RUNTIME_TRACE_CBID_cudaEventRecord_v3020 = 135, + CUPTI_RUNTIME_TRACE_CBID_cudaEventDestroy_v3020 = 136, + CUPTI_RUNTIME_TRACE_CBID_cudaEventSynchronize_v3020 = 137, + CUPTI_RUNTIME_TRACE_CBID_cudaEventQuery_v3020 = 138, + CUPTI_RUNTIME_TRACE_CBID_cudaEventElapsedTime_v3020 = 139, + CUPTI_RUNTIME_TRACE_CBID_cudaMalloc3D_v3020 = 140, + CUPTI_RUNTIME_TRACE_CBID_cudaMalloc3DArray_v3020 = 141, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset3D_v3020 = 142, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset3DAsync_v3020 = 143, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3D_v3020 = 144, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3DAsync_v3020 = 145, + CUPTI_RUNTIME_TRACE_CBID_cudaThreadSetCacheConfig_v3020 = 146, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamWaitEvent_v3020 = 147, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D11GetDirect3DDevice_v3020 = 148, + CUPTI_RUNTIME_TRACE_CBID_cudaD3D10GetDirect3DDevice_v3020 = 149, + CUPTI_RUNTIME_TRACE_CBID_cudaThreadGetCacheConfig_v3020 = 150, + CUPTI_RUNTIME_TRACE_CBID_cudaPointerGetAttributes_v4000 = 151, + CUPTI_RUNTIME_TRACE_CBID_cudaHostRegister_v4000 = 152, + CUPTI_RUNTIME_TRACE_CBID_cudaHostUnregister_v4000 = 153, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceCanAccessPeer_v4000 = 154, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceEnablePeerAccess_v4000 = 155, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceDisablePeerAccess_v4000 = 156, + CUPTI_RUNTIME_TRACE_CBID_cudaPeerRegister_v4000 = 157, + CUPTI_RUNTIME_TRACE_CBID_cudaPeerUnregister_v4000 = 158, + CUPTI_RUNTIME_TRACE_CBID_cudaPeerGetDevicePointer_v4000 = 159, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyPeer_v4000 = 160, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyPeerAsync_v4000 = 161, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3DPeer_v4000 = 162, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3DPeerAsync_v4000 = 163, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceReset_v3020 = 164, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceSynchronize_v3020 = 165, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetLimit_v3020 = 166, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceSetLimit_v3020 = 167, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetCacheConfig_v3020 = 168, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceSetCacheConfig_v3020 = 169, + CUPTI_RUNTIME_TRACE_CBID_cudaProfilerInitialize_v4000 = 170, + CUPTI_RUNTIME_TRACE_CBID_cudaProfilerStart_v4000 = 171, + CUPTI_RUNTIME_TRACE_CBID_cudaProfilerStop_v4000 = 172, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetByPCIBusId_v4010 = 173, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetPCIBusId_v4010 = 174, + CUPTI_RUNTIME_TRACE_CBID_cudaGLGetDevices_v4010 = 175, + CUPTI_RUNTIME_TRACE_CBID_cudaIpcGetEventHandle_v4010 = 176, + CUPTI_RUNTIME_TRACE_CBID_cudaIpcOpenEventHandle_v4010 = 177, + CUPTI_RUNTIME_TRACE_CBID_cudaIpcGetMemHandle_v4010 = 178, + CUPTI_RUNTIME_TRACE_CBID_cudaIpcOpenMemHandle_v4010 = 179, + CUPTI_RUNTIME_TRACE_CBID_cudaIpcCloseMemHandle_v4010 = 180, + CUPTI_RUNTIME_TRACE_CBID_cudaArrayGetInfo_v4010 = 181, + CUPTI_RUNTIME_TRACE_CBID_cudaFuncSetSharedMemConfig_v4020 = 182, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetSharedMemConfig_v4020 = 183, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceSetSharedMemConfig_v4020 = 184, + CUPTI_RUNTIME_TRACE_CBID_cudaCreateTextureObject_v5000 = 185, + CUPTI_RUNTIME_TRACE_CBID_cudaDestroyTextureObject_v5000 = 186, + CUPTI_RUNTIME_TRACE_CBID_cudaGetTextureObjectResourceDesc_v5000 = 187, + CUPTI_RUNTIME_TRACE_CBID_cudaGetTextureObjectTextureDesc_v5000 = 188, + CUPTI_RUNTIME_TRACE_CBID_cudaCreateSurfaceObject_v5000 = 189, + CUPTI_RUNTIME_TRACE_CBID_cudaDestroySurfaceObject_v5000 = 190, + CUPTI_RUNTIME_TRACE_CBID_cudaGetSurfaceObjectResourceDesc_v5000 = 191, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocMipmappedArray_v5000 = 192, + CUPTI_RUNTIME_TRACE_CBID_cudaGetMipmappedArrayLevel_v5000 = 193, + CUPTI_RUNTIME_TRACE_CBID_cudaFreeMipmappedArray_v5000 = 194, + CUPTI_RUNTIME_TRACE_CBID_cudaBindTextureToMipmappedArray_v5000 = 195, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsResourceGetMappedMipmappedArray_v5000 = 196, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamAddCallback_v5000 = 197, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamCreateWithFlags_v5000 = 198, + CUPTI_RUNTIME_TRACE_CBID_cudaGetTextureObjectResourceViewDesc_v5000 = 199, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetAttribute_v5000 = 200, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamDestroy_v5050 = 201, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamCreateWithPriority_v5050 = 202, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetPriority_v5050 = 203, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetFlags_v5050 = 204, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetStreamPriorityRange_v5050 = 205, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocManaged_v6000 = 206, + CUPTI_RUNTIME_TRACE_CBID_cudaOccupancyMaxActiveBlocksPerMultiprocessor_v6000 = 207, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamAttachMemAsync_v6000 = 208, + CUPTI_RUNTIME_TRACE_CBID_cudaGetErrorName_v6050 = 209, + CUPTI_RUNTIME_TRACE_CBID_cudaOccupancyMaxActiveBlocksPerMultiprocessor_v6050 = 210, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernel_v7000 = 211, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDeviceFlags_v7000 = 212, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunch_ptsz_v7000 = 213, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernel_ptsz_v7000 = 214, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy_ptds_v7000 = 215, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2D_ptds_v7000 = 216, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyToArray_ptds_v7000 = 217, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DToArray_ptds_v7000 = 218, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyFromArray_ptds_v7000 = 219, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DFromArray_ptds_v7000 = 220, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyArrayToArray_ptds_v7000 = 221, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DArrayToArray_ptds_v7000 = 222, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyToSymbol_ptds_v7000 = 223, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyFromSymbol_ptds_v7000 = 224, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyAsync_ptsz_v7000 = 225, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyToArrayAsync_ptsz_v7000 = 226, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyFromArrayAsync_ptsz_v7000 = 227, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DAsync_ptsz_v7000 = 228, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DToArrayAsync_ptsz_v7000 = 229, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy2DFromArrayAsync_ptsz_v7000 = 230, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyToSymbolAsync_ptsz_v7000 = 231, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyFromSymbolAsync_ptsz_v7000 = 232, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset_ptds_v7000 = 233, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset2D_ptds_v7000 = 234, + CUPTI_RUNTIME_TRACE_CBID_cudaMemsetAsync_ptsz_v7000 = 235, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset2DAsync_ptsz_v7000 = 236, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetPriority_ptsz_v7000 = 237, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetFlags_ptsz_v7000 = 238, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamSynchronize_ptsz_v7000 = 239, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamQuery_ptsz_v7000 = 240, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamAttachMemAsync_ptsz_v7000 = 241, + CUPTI_RUNTIME_TRACE_CBID_cudaEventRecord_ptsz_v7000 = 242, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset3D_ptds_v7000 = 243, + CUPTI_RUNTIME_TRACE_CBID_cudaMemset3DAsync_ptsz_v7000 = 244, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3D_ptds_v7000 = 245, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3DAsync_ptsz_v7000 = 246, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamWaitEvent_ptsz_v7000 = 247, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamAddCallback_ptsz_v7000 = 248, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3DPeer_ptds_v7000 = 249, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3DPeerAsync_ptsz_v7000 = 250, + CUPTI_RUNTIME_TRACE_CBID_cudaOccupancyMaxActiveBlocksPerMultiprocessorWithFlags_v7000 = 251, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPrefetchAsync_v8000 = 252, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPrefetchAsync_ptsz_v8000 = 253, + CUPTI_RUNTIME_TRACE_CBID_cudaMemAdvise_v8000 = 254, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetP2PAttribute_v8000 = 255, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsEGLRegisterImage_v7000 = 256, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamConsumerConnect_v7000 = 257, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamConsumerDisconnect_v7000 = 258, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamConsumerAcquireFrame_v7000 = 259, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamConsumerReleaseFrame_v7000 = 260, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamProducerConnect_v7000 = 261, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamProducerDisconnect_v7000 = 262, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamProducerPresentFrame_v7000 = 263, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamProducerReturnFrame_v7000 = 264, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphicsResourceGetMappedEglFrame_v7000 = 265, + CUPTI_RUNTIME_TRACE_CBID_cudaMemRangeGetAttribute_v8000 = 266, + CUPTI_RUNTIME_TRACE_CBID_cudaMemRangeGetAttributes_v8000 = 267, + CUPTI_RUNTIME_TRACE_CBID_cudaEGLStreamConsumerConnectWithFlags_v7000 = 268, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchCooperativeKernel_v9000 = 269, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchCooperativeKernel_ptsz_v9000 = 270, + CUPTI_RUNTIME_TRACE_CBID_cudaEventCreateFromEGLSync_v9000 = 271, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchCooperativeKernelMultiDevice_v9000 = 272, + CUPTI_RUNTIME_TRACE_CBID_cudaFuncSetAttribute_v9000 = 273, + CUPTI_RUNTIME_TRACE_CBID_cudaImportExternalMemory_v10000 = 274, + CUPTI_RUNTIME_TRACE_CBID_cudaExternalMemoryGetMappedBuffer_v10000 = 275, + CUPTI_RUNTIME_TRACE_CBID_cudaExternalMemoryGetMappedMipmappedArray_v10000 = 276, + CUPTI_RUNTIME_TRACE_CBID_cudaDestroyExternalMemory_v10000 = 277, + CUPTI_RUNTIME_TRACE_CBID_cudaImportExternalSemaphore_v10000 = 278, + CUPTI_RUNTIME_TRACE_CBID_cudaSignalExternalSemaphoresAsync_v10000 = 279, + CUPTI_RUNTIME_TRACE_CBID_cudaSignalExternalSemaphoresAsync_ptsz_v10000 = 280, + CUPTI_RUNTIME_TRACE_CBID_cudaWaitExternalSemaphoresAsync_v10000 = 281, + CUPTI_RUNTIME_TRACE_CBID_cudaWaitExternalSemaphoresAsync_ptsz_v10000 = 282, + CUPTI_RUNTIME_TRACE_CBID_cudaDestroyExternalSemaphore_v10000 = 283, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchHostFunc_v10000 = 284, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchHostFunc_ptsz_v10000 = 285, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphCreate_v10000 = 286, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphKernelNodeGetParams_v10000 = 287, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphKernelNodeSetParams_v10000 = 288, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddKernelNode_v10000 = 289, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddMemcpyNode_v10000 = 290, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemcpyNodeGetParams_v10000 = 291, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemcpyNodeSetParams_v10000 = 292, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddMemsetNode_v10000 = 293, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemsetNodeGetParams_v10000 = 294, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemsetNodeSetParams_v10000 = 295, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddHostNode_v10000 = 296, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphHostNodeGetParams_v10000 = 297, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddChildGraphNode_v10000 = 298, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphChildGraphNodeGetGraph_v10000 = 299, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddEmptyNode_v10000 = 300, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphClone_v10000 = 301, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeFindInClone_v10000 = 302, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeGetType_v10000 = 303, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphGetRootNodes_v10000 = 304, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeGetDependencies_v10000 = 305, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeGetDependentNodes_v10000 = 306, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddDependencies_v10000 = 307, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphRemoveDependencies_v10000 = 308, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphDestroyNode_v10000 = 309, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphInstantiate_v10000 = 310, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphLaunch_v10000 = 311, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphLaunch_ptsz_v10000 = 312, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecDestroy_v10000 = 313, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphDestroy_v10000 = 314, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamBeginCapture_v10000 = 315, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamBeginCapture_ptsz_v10000 = 316, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamIsCapturing_v10000 = 317, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamIsCapturing_ptsz_v10000 = 318, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamEndCapture_v10000 = 319, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamEndCapture_ptsz_v10000 = 320, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphHostNodeSetParams_v10000 = 321, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphGetNodes_v10000 = 322, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphGetEdges_v10000 = 323, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetCaptureInfo_v10010 = 324, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetCaptureInfo_ptsz_v10010 = 325, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecKernelNodeSetParams_v10010 = 326, + CUPTI_RUNTIME_TRACE_CBID_cudaThreadExchangeStreamCaptureMode_v10010 = 327, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetNvSciSyncAttributes_v10020 = 328, + CUPTI_RUNTIME_TRACE_CBID_cudaOccupancyAvailableDynamicSMemPerBlock_v10200 = 329, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamSetFlags_v10200 = 330, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamSetFlags_ptsz_v10200 = 331, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecMemcpyNodeSetParams_v10020 = 332, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecMemsetNodeSetParams_v10020 = 333, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecHostNodeSetParams_v10020 = 334, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecUpdate_v10020 = 335, + CUPTI_RUNTIME_TRACE_CBID_cudaGetFuncBySymbol_v11000 = 336, + CUPTI_RUNTIME_TRACE_CBID_cudaCtxResetPersistingL2Cache_v11000 = 337, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphKernelNodeCopyAttributes_v11000 = 338, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphKernelNodeGetAttribute_v11000 = 339, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphKernelNodeSetAttribute_v11000 = 340, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamCopyAttributes_v11000 = 341, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamCopyAttributes_ptsz_v11000 = 342, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetAttribute_v11000 = 343, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetAttribute_ptsz_v11000 = 344, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamSetAttribute_v11000 = 345, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamSetAttribute_ptsz_v11000 = 346, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetTexture1DLinearMaxWidth_v11010 = 347, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphUpload_v10000 = 348, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphUpload_ptsz_v10000 = 349, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddMemcpyNodeToSymbol_v11010 = 350, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddMemcpyNodeFromSymbol_v11010 = 351, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddMemcpyNode1D_v11010 = 352, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemcpyNodeSetParamsToSymbol_v11010 = 353, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemcpyNodeSetParamsFromSymbol_v11010 = 354, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemcpyNodeSetParams1D_v11010 = 355, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecMemcpyNodeSetParamsToSymbol_v11010 = 356, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecMemcpyNodeSetParamsFromSymbol_v11010 = 357, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecMemcpyNodeSetParams1D_v11010 = 358, + CUPTI_RUNTIME_TRACE_CBID_cudaArrayGetSparseProperties_v11010 = 359, + CUPTI_RUNTIME_TRACE_CBID_cudaMipmappedArrayGetSparseProperties_v11010 = 360, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecChildGraphNodeSetParams_v11010 = 361, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddEventRecordNode_v11010 = 362, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphEventRecordNodeGetEvent_v11010 = 363, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphEventRecordNodeSetEvent_v11010 = 364, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddEventWaitNode_v11010 = 365, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphEventWaitNodeGetEvent_v11010 = 366, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphEventWaitNodeSetEvent_v11010 = 367, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecEventRecordNodeSetEvent_v11010 = 368, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecEventWaitNodeSetEvent_v11010 = 369, + CUPTI_RUNTIME_TRACE_CBID_cudaEventRecordWithFlags_v11010 = 370, + CUPTI_RUNTIME_TRACE_CBID_cudaEventRecordWithFlags_ptsz_v11010 = 371, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetDefaultMemPool_v11020 = 372, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocAsync_v11020 = 373, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocAsync_ptsz_v11020 = 374, + CUPTI_RUNTIME_TRACE_CBID_cudaFreeAsync_v11020 = 375, + CUPTI_RUNTIME_TRACE_CBID_cudaFreeAsync_ptsz_v11020 = 376, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolTrimTo_v11020 = 377, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolSetAttribute_v11020 = 378, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolGetAttribute_v11020 = 379, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolSetAccess_v11020 = 380, + CUPTI_RUNTIME_TRACE_CBID_cudaArrayGetPlane_v11020 = 381, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolGetAccess_v11020 = 382, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolCreate_v11020 = 383, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolDestroy_v11020 = 384, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceSetMemPool_v11020 = 385, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetMemPool_v11020 = 386, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolExportToShareableHandle_v11020 = 387, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolImportFromShareableHandle_v11020 = 388, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolExportPointer_v11020 = 389, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPoolImportPointer_v11020 = 390, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocFromPoolAsync_v11020 = 391, + CUPTI_RUNTIME_TRACE_CBID_cudaMallocFromPoolAsync_ptsz_v11020 = 392, + CUPTI_RUNTIME_TRACE_CBID_cudaSignalExternalSemaphoresAsync_v2_v11020 = 393, + CUPTI_RUNTIME_TRACE_CBID_cudaSignalExternalSemaphoresAsync_v2_ptsz_v11020 = 394, + CUPTI_RUNTIME_TRACE_CBID_cudaWaitExternalSemaphoresAsync_v2_v11020 = 395, + CUPTI_RUNTIME_TRACE_CBID_cudaWaitExternalSemaphoresAsync_v2_ptsz_v11020 = 396, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddExternalSemaphoresSignalNode_v11020 = 397, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExternalSemaphoresSignalNodeGetParams_v11020 = 398, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExternalSemaphoresSignalNodeSetParams_v11020 = 399, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddExternalSemaphoresWaitNode_v11020 = 400, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExternalSemaphoresWaitNodeGetParams_v11020 = 401, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExternalSemaphoresWaitNodeSetParams_v11020 = 402, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecExternalSemaphoresSignalNodeSetParams_v11020 = 403, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecExternalSemaphoresWaitNodeSetParams_v11020 = 404, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceFlushGPUDirectRDMAWrites_v11030 = 405, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDriverEntryPoint_v11030 = 406, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDriverEntryPoint_ptsz_v11030 = 407, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphDebugDotPrint_v11030 = 408, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetCaptureInfo_v2_v11030 = 409, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetCaptureInfo_v2_ptsz_v11030 = 410, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamUpdateCaptureDependencies_v11030 = 411, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamUpdateCaptureDependencies_ptsz_v11030 = 412, + CUPTI_RUNTIME_TRACE_CBID_cudaUserObjectCreate_v11030 = 413, + CUPTI_RUNTIME_TRACE_CBID_cudaUserObjectRetain_v11030 = 414, + CUPTI_RUNTIME_TRACE_CBID_cudaUserObjectRelease_v11030 = 415, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphRetainUserObject_v11030 = 416, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphReleaseUserObject_v11030 = 417, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphInstantiateWithFlags_v11040 = 418, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddMemAllocNode_v11040 = 419, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemAllocNodeGetParams_v11040 = 420, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddMemFreeNode_v11040 = 421, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphMemFreeNodeGetParams_v11040 = 422, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGraphMemTrim_v11040 = 423, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceGetGraphMemAttribute_v11040 = 424, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceSetGraphMemAttribute_v11040 = 425, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeSetEnabled_v11060 = 426, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeGetEnabled_v11060 = 427, + CUPTI_RUNTIME_TRACE_CBID_cudaArrayGetMemoryRequirements_v11060 = 428, + CUPTI_RUNTIME_TRACE_CBID_cudaMipmappedArrayGetMemoryRequirements_v11060 = 429, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernelExC_v11060 = 430, + CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernelExC_ptsz_v11060 = 431, + CUPTI_RUNTIME_TRACE_CBID_cudaOccupancyMaxPotentialClusterSize_v11070 = 432, + CUPTI_RUNTIME_TRACE_CBID_cudaOccupancyMaxActiveClusters_v11070 = 433, + CUPTI_RUNTIME_TRACE_CBID_cudaCreateTextureObject_v2_v11080 = 434, + CUPTI_RUNTIME_TRACE_CBID_cudaGetTextureObjectTextureDesc_v2_v11080 = 435, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphInstantiateWithParams_v12000 = 436, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphInstantiateWithParams_ptsz_v12000 = 437, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecGetFlags_v12000 = 438, + CUPTI_RUNTIME_TRACE_CBID_cudaGetKernel_v12000 = 439, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDeviceProperties_v2_v12000 = 440, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetId_v12000 = 441, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetId_ptsz_v12000 = 442, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphInstantiate_v12000 = 443, + CUPTI_RUNTIME_TRACE_CBID_cudaInitDevice_v12000 = 444, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddNode_v12020 = 445, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeSetParams_v12020 = 446, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphExecNodeSetParams_v12020 = 447, + CUPTI_RUNTIME_TRACE_CBID_cudaMemAdvise_v2_v12020 = 448, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPrefetchAsync_v2_v12020 = 449, + CUPTI_RUNTIME_TRACE_CBID_cudaMemPrefetchAsync_v2_ptsz_v12020 = 450, + CUPTI_RUNTIME_TRACE_CBID_cudaFuncGetName_v12030 = 451, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamBeginCaptureToGraph_v12030 = 452, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamBeginCaptureToGraph_ptsz_v12030 = 453, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphConditionalHandleCreate_v12030 = 454, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphGetEdges_v2_v12030 = 455, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeGetDependencies_v2_v12030 = 456, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphNodeGetDependentNodes_v2_v12030 = 457, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddDependencies_v2_v12030 = 458, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphRemoveDependencies_v2_v12030 = 459, + CUPTI_RUNTIME_TRACE_CBID_cudaGraphAddNode_v2_v12030 = 460, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetCaptureInfo_v3_v12030 = 461, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetCaptureInfo_v3_ptsz_v12030 = 462, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamUpdateCaptureDependencies_v2_v12030 = 463, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamUpdateCaptureDependencies_v2_ptsz_v12030 = 464, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceRegisterAsyncNotification_v12040 = 465, + CUPTI_RUNTIME_TRACE_CBID_cudaDeviceUnregisterAsyncNotification_v12040 = 466, + CUPTI_RUNTIME_TRACE_CBID_cudaFuncGetParamInfo_v12040 = 467, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDriverEntryPointByVersion_v12050 = 468, + CUPTI_RUNTIME_TRACE_CBID_cudaGetDriverEntryPointByVersion_ptsz_v12050 = 469, + CUPTI_RUNTIME_TRACE_CBID_cuda470_v12060 = 470, + CUPTI_RUNTIME_TRACE_CBID_cuda471_v12060 = 471, + CUPTI_RUNTIME_TRACE_CBID_cuda472_v12060 = 472, + CUPTI_RUNTIME_TRACE_CBID_cuda473_v12060 = 473, + CUPTI_RUNTIME_TRACE_CBID_cuda474_v12060 = 474, + CUPTI_RUNTIME_TRACE_CBID_cuda475_v12060 = 475, + CUPTI_RUNTIME_TRACE_CBID_cuda476_v12060 = 476, + CUPTI_RUNTIME_TRACE_CBID_cuda477_v12060 = 477, + CUPTI_RUNTIME_TRACE_CBID_cuda478_v12060 = 478, + CUPTI_RUNTIME_TRACE_CBID_cuda479_v12060 = 479, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetDevice_v12080 = 480, + CUPTI_RUNTIME_TRACE_CBID_cudaStreamGetDevice_ptsz_v12080 = 481, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyBatchAsync_v12080 = 482, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyBatchAsync_ptsz_v12080 = 483, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3DBatchAsync_v12080 = 484, + CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy3DBatchAsync_ptsz_v12080 = 485, + CUPTI_RUNTIME_TRACE_CBID_cudaEventElapsedTime_v2_v12080 = 486, + CUPTI_RUNTIME_TRACE_CBID_SIZE = 487, + CUPTI_RUNTIME_TRACE_CBID_FORCE_INT = 0x7fffffff +} CUpti_runtime_api_trace_cbid; + +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_sass_metrics.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_sass_metrics.h new file mode 100644 index 0000000000000000000000000000000000000000..acb59cf8e5882a5ff13b4a1b0fdc6bc7b0ec47f7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_sass_metrics.h @@ -0,0 +1,436 @@ +/* + * Copyright 2023 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_SASS_METRICS_H_) +#define _CUPTI_SASS_METRICS_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_SASS_METRICS_API CUPTI SASS Metrics API + * Functions, types, and enums that implement the CUPTI SASS Metrics API. + * @{ + */ + +typedef enum +{ + /// SASS metric data will be collected at GPU level. + /// In CUpti_SassMetricsGetDataProperties_Params struct the numOfInstances will be equal to 1 + CUPTI_SASS_METRICS_OUTPUT_GRANULARITY_GPU = 0, + + /// SASS metric data will be collected at SM level + /// In CUpti_SassMetricsGetDataProperties_Params struct the numOfInstances will be equal to number of SMs in the GPU + CUPTI_SASS_METRICS_OUTPUT_GRANULARITY_SM = 1, + + /// SASS metric data will be collected at SM sub-partition level + /// In CUpti_SassMetricsGetDataProperties_Params struct the numOfInstances will be equal to number of SM sub-partitions in the GPU + CUPTI_SASS_METRICS_OUTPUT_GRANULARITY_SMSP = 2, + + CUPTI_SASS_METRICS_OUTPUT_GRANULARITY_INVALID +} CUpti_SassMetrics_OutputGranularity; + +typedef struct CUpti_SassMetrics_MetricDetails +{ + /// unique ID for the SASS metric + uint64_t metricId; + /// metric name + const char* pMetricName; + /// metric description + const char* pMetricDescription; +} CUpti_SassMetrics_MetricDetails; + +/** + * \brief Params for cuptiSassMetricsGetNumOfMetrics + */ +typedef struct CUpti_SassMetrics_GetNumOfMetrics_Params +{ + /// [in] should be equal to CUpti_SassMetrics_GetNumOfMetrics_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] chip name for which metrics will be queried + const char* pChipName; + /// [out] number of metrics supported for the queried chip + size_t numOfMetrics; +} CUpti_SassMetrics_GetNumOfMetrics_Params; + +#define CUpti_SassMetrics_GetNumOfMetrics_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetrics_GetNumOfMetrics_Params, numOfMetrics) + +/** + * \brief Get the number of supported SASS metrics for the chip. + * + * \param pParams A pointer to \ref CUpti_SassMetrics_GetNumOfMetrics_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric collection + */ +CUptiResult CUPTIAPI cuptiSassMetricsGetNumOfMetrics(CUpti_SassMetrics_GetNumOfMetrics_Params* pParams); + +/** + * \brief Params for cuptiSassMetricsGetMetrics + */ +typedef struct CUpti_SassMetrics_GetMetrics_Params +{ + /// [in] should be equal to CUpti_SassMetrics_GetMetrics_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] chip name for which metrics will be queried + const char* pChipName; + /// [in] number of metrics supported for the queried chip (can be queried using cuptiSassMetricsGetNumOfMetrics()) + size_t numOfMetrics; + /// [out] list of metrics supported for queried chip + CUpti_SassMetrics_MetricDetails* pMetricsList; +} CUpti_SassMetrics_GetMetrics_Params; +#define CUpti_SassMetrics_GetMetrics_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetrics_GetMetrics_Params, pMetricsList) + +/** + * \brief Get the list of all supported SASS metrics for the chip. + * + * \param pParams A pointer to \ref CUpti_SassMetrics_GetMetrics_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric collection + */ +CUptiResult CUPTIAPI cuptiSassMetricsGetMetrics(CUpti_SassMetrics_GetMetrics_Params* pParams); + +/** + * \brief Params for cuptiSassMetricsGetProperties + */ +typedef struct CUpti_SassMetrics_GetProperties_Params +{ + /// [in] should be equal to CUpti_SassMetrics_GetProperties_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] chip name for which metric will be queried + const char* pChipName; + /// [in] metric name + const char* pMetricName; + /// [out] returns the metric ID and the metric description + CUpti_SassMetrics_MetricDetails metric; +} CUpti_SassMetrics_GetProperties_Params; +#define CUpti_SassMetrics_GetProperties_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetrics_GetProperties_Params, metric) + +/** + * \brief Get metric properties for the queried metric. + * For a given metric the results will be put in CUpti_SassMetrics_MetricDetails which + * stores metric ID, description of the metric. + * + * \param pParams A pointer to \ref CUpti_SassMetrics_GetProperties_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric data collection + */ +CUptiResult CUPTIAPI cuptiSassMetricsGetProperties(CUpti_SassMetrics_GetProperties_Params *pParams); + +typedef struct CUpti_SassMetrics_Config +{ + /// [in] unique id for the SASS metric, can be queried using cuptiSassMetricsGetProperties() + uint64_t metricId; + /// [in] CUpti_SassMetrics_OutputGranularity + uint8_t outputGranularity; +} CUpti_SassMetrics_Config; + +/** + * \brief Params for cuptiSassMetricsSetConfig + */ +typedef struct CUpti_SassMetricsSetConfig_Params +{ + /// [in] equal to CUpti_SassMetricsSetConfig_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] num of metric configs, will be equal to number of metrics queried + size_t numOfMetricConfig; + /// [in] list of metric config generated for given sass metrics + CUpti_SassMetrics_Config* pConfigs; + /// [in] device index for which config will be set, user can call this once for + /// the device on which the the SASS metric data will be collected + uint32_t deviceIndex; +} CUpti_SassMetricsSetConfig_Params; +#define CUpti_SassMetricsSetConfig_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetricsSetConfig_Params, deviceIndex) + +/** + * \brief Set config for the SASS metric data collection for a device. + * User need to call this API before calling any of the SASS metric data collection APIs. + * Each set config API call need to be followed by cuptiSassPatchingUnSetConfig API + * before calling the cuptiSassMetricsSetConfig() API again for the same device. + * + * \param pParams A pointer to \ref CUpti_SassMetricsSetConfig_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_CONTEXT if any cuda context has not been created prior to this API call + * \retval CUPTI_ERROR_INVALID_OPERATION if this is called multiple times for the device without calling unset config API + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric data collection + */ +CUptiResult CUPTIAPI cuptiSassMetricsSetConfig(CUpti_SassMetricsSetConfig_Params *pParams); + +/** + * \brief Params for cuptiSassMetricsUnsetConfig + */ +typedef struct CUpti_SassMetricsUnsetConfig_Params +{ + /// [in] equal to CUpti_SassMetricsUnsetConfig_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] device index for which SASS metric data collection config will get reset, user need to call this API for + /// all the devices on which the the SASS metric data collection have been configured. + uint32_t deviceIndex; +} CUpti_SassMetricsUnsetConfig_Params; +#define CUpti_SassMetricsUnsetConfig_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetricsUnsetConfig_Params, deviceIndex) + +/** + * \brief Unset config API will reset the SASS metric data collection configuration for the device. + * Once this API called CUPTI will deallocate all the memory allocated and remove all + * the configuration for SASS metric data collection. User can only call this API for a device where + * cuptiSassMetricsSetConfig() API has been called earlier for the device. + * + * \param pParams A pointer to \ref CUpti_SassMetricsSetConfig_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_INVALID_CONTEXT if any cuda context has not been created prior to this API call + * \retval CUPTI_ERROR_INVALID_OPERATION if this is called multiple times for the device without calling set config API + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric data collection + */ +CUptiResult CUPTIAPI cuptiSassMetricsUnsetConfig(CUpti_SassMetricsUnsetConfig_Params *pParams); + +/** + * \brief Params for cuptiSassMetricsEnable + */ +typedef struct CUpti_SassMetricsEnable_Params +{ + /// [in] equal to CUpti_SassMetricsEnable_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] CUDA context on which SASS metric data collection will be enabled. + /// If set NULL, default context will be consider for SASS metric data collection. + CUcontext ctx; + /// [in] if false, all the functions will patched regardless of their execution with cuptiSassMetricsEnable() API call. + /// when this parameter is set to true, metric data collection for the function will be done at the very first execution in the enable/disble + /// range. + uint8_t enableLazyPatching; +} CUpti_SassMetricsEnable_Params; +#define CUpti_SassMetricsEnable_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetricsEnable_Params, enableLazyPatching) + +/** + * \brief Sass metric data collection enable API will mark the start of a range, between which kernel + * will be profiled for SASS metrics. + * + * \param pParams A pointer to \ref CUpti_SassMetricsEnable_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric data collection + * \retval CUPTI_ERROR_INVALID_CONTEXT if any cuda context has not been created prior to this API call + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called multiple times for a cuda context without calling + * cuptiSassMetricsDisable() API or called before cuptiSassMetricsSetConfig() API call. + */ +CUptiResult CUPTIAPI cuptiSassMetricsEnable(CUpti_SassMetricsEnable_Params* pParams); + +/** + * \brief Params for cuptiSassMetricsDisable + */ +typedef struct CUpti_SassMetricsDisable_Params +{ + /// [in] equal to CUpti_SassMetricsDisable_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] CUDA context on which SASS metric data collection will be disabled. + /// If set NULL, default context will be consider for SASS metric data collection. + CUcontext ctx; + /// [out] Num of dropped SASS records will be equal to numOfPatchedInstructions * numOfInstances. + /// Number of dropped records will be zero when data is flushed prior to calling the disable API. + size_t numOfDroppedRecords; +} CUpti_SassMetricsDisable_Params; +#define CUpti_SassMetricsDisable_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetricsDisable_Params, numOfDroppedRecords) + +/** + * \brief SASS metric data collection disable API will mark the end of a range, any kernel launched after this + * API call will not be profiled for the SASS metrics. + * + * \param pParams A pointer to \ref CUpti_SassMetricsDisable_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric data collection + * \retval CUPTI_ERROR_INVALID_CONTEXT if any cuda context has not been created prior to this API call + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called multiple times for a cuda context without calling + * cuptiSassMetricsEnable() API or called before cuptiSassMetricsSetConfig() API call. + */ +CUptiResult CUPTIAPI cuptiSassMetricsDisable(CUpti_SassMetricsDisable_Params* pParams); + +/** + * \brief Params for cuptiSassMetricsGetDataProperties + */ +typedef struct CUpti_SassMetricsGetDataProperties_Params +{ + /// [in] equal to CUpti_SassMetricsGetDataProperties_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] CUDA context on which SASS metric data collection was enabled. + /// If set NULL, default context will be consider for SASS metric data collection. + CUcontext ctx; + /// [out] total number of SASS records has been collected + size_t numOfPatchedInstructionRecords; + /// [out] number of instances for each metric value per instruction. + /// This will depend on CUpti_SassPatching_OutputGranularity level set for the metric config. + size_t numOfInstances; +} CUpti_SassMetricsGetDataProperties_Params; + +#define CUpti_SassMetricsGetDataProperties_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetricsGetDataProperties_Params, numOfInstances) +/** + * \brief SASS metric data properties API will give the data regarding number of instances of a metric + * value and number of SASS instruction data has been collected. The number of instances of a metric + * will vary as per user set the output granularity level with CUpti_SassMetrics_OutputGranularity value. + * User need to allocate memory for retriving the SASS data using cuptiSassMetricsFlushData() API. + * + * \param pParams A pointer to \ref CUpti_SassMetricsGetDataProperties_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric data collection + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called outside the enable/disable range. + */ +CUptiResult CUPTIAPI cuptiSassMetricsGetDataProperties(CUpti_SassMetricsGetDataProperties_Params* pParams); + +typedef struct CUpti_SassMetrics_InstanceValue +{ + // unique id of the metric + uint64_t metricId; + // metric value + uint64_t value; +} CUpti_SassMetrics_InstanceValue; +#define CUpti_SassMetrics_InstanceValue_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetrics_InstanceValue, value) + +typedef struct CUpti_SassMetrics_Data +{ + /// [in] equal to CUpti_SassMetricsFlushData_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [out] Unique cubin id + uint32_t cubinCrc; + /// [out] function's unique symbol index in the module. + uint32_t functionIndex; + /// [out] The function name + const char* functionName; + /// [out] pc offset for the function in a module + uint32_t pcOffset; + /// [out] array of size equal to number of instances per metric, which contains the metric ID and metric value. + CUpti_SassMetrics_InstanceValue* pInstanceValues; +} CUpti_SassMetrics_Data; + +/** + * \brief Params for cuptiSassMetricsFlushData + */ +typedef struct CUpti_SassMetricsFlushData_Params +{ + /// [in] equal to CUpti_SassMetricsFlushData_Params_STRUCT_SIZE + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] CUDA context on which SASS metric data collection was enabled. + /// If set NULL, default context will be consider for SASS metric data collection. + CUcontext ctx; + /// [in] number of patched instruction record will be retrived, user can call cuptiSassMetricsGetDataProperties() + /// for getting total number of records available. + size_t numOfPatchedInstructionRecords; + /// [in] number of patched instruction record instances for a metric, user can call cuptiSassMetricsGetDataProperties() + /// for getting total number of instances for each record per metric available. + size_t numOfInstances; + /// [out] + CUpti_SassMetrics_Data* pMetricsData; +} CUpti_SassMetricsFlushData_Params; +#define CUpti_SassMetricsFlushData_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_SassMetricsFlushData_Params, numOfInstances) + +/** + * \brief Flush SASS metrics data from CUPTI internal buffer to the user buffer. + * User needs to allocate the buffer for retrieving the data. The number of records collected + * can be queried using the API cuptiSassMetricsGetDataProperties(). + * + * \param pParams A pointer to \ref CUpti_SassMetricsFlushData_Params + * + * \retval CUPTI_SUCCESS + * \retval CUPTI_ERROR_INVALID_PARAMETER if any \p pParams is not valid + * \retval CUPTI_ERROR_NOT_SUPPORTED indicates that the system/device doesn't support SASS metric data collection. + * \retval CUPTI_ERROR_INVALID_OPERATION if this API is called outside the enable/disable range. + */ +CUptiResult CUPTIAPI cuptiSassMetricsFlushData(CUpti_SassMetricsFlushData_Params* pParams); + +/** @} */ /* END CUPTI_SASS_METRICS_API */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CUPTI_SASS_METRICS_H_ \ No newline at end of file diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_target.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_target.h new file mode 100644 index 0000000000000000000000000000000000000000..e4b625d45c65288fa2ea7dc05819ee4dfc4cbdd3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_target.h @@ -0,0 +1,43 @@ +#if !defined(_CUPTI_TARGET_H_) +#define _CUPTI_TARGET_H_ + +/* +CUPTI profiler target API's +This file contains the CUPTI profiling API's. +*/ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +#ifndef CUPTI_PROFILER_STRUCT_SIZE +#define CUPTI_PROFILER_STRUCT_SIZE(type_, lastfield_) (offsetof(type_, lastfield_) + sizeof(((type_*)0)->lastfield_)) +#endif + +typedef struct CUpti_Device_GetChipName_Params +{ + size_t structSize; //!< [in] + void* pPriv; //!< [in] assign to NULL + + size_t deviceIndex; //!< [in] + const char* pChipName; //!< [out] +} CUpti_Device_GetChipName_Params; + +#define CUpti_Device_GetChipName_Params_STRUCT_SIZE CUPTI_PROFILER_STRUCT_SIZE(CUpti_Device_GetChipName_Params, pChipName) +CUptiResult CUPTIAPI cuptiDeviceGetChipName(CUpti_Device_GetChipName_Params *pParams); + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_version.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_version.h new file mode 100644 index 0000000000000000000000000000000000000000..9a8808ea022b4116a1177e6f78d34d0f39604344 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/cupti_version.h @@ -0,0 +1,137 @@ +/* + * Copyright 2010-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(_CUPTI_VERSION_H_) +#define _CUPTI_VERSION_H_ + +#include +#include + +#ifndef CUPTIAPI +#ifdef _WIN32 +#define CUPTIAPI __stdcall +#else +#define CUPTIAPI +#endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +/** + * \defgroup CUPTI_VERSION_API CUPTI Version + * Function and macro to determine the CUPTI version. + * @{ + */ + +/** + * \brief The API version for this implementation of CUPTI. + * + * The API version for this implementation of CUPTI. This define along + * with \ref cuptiGetVersion can be used to dynamically detect if the + * version of CUPTI compiled against matches the version of the loaded + * CUPTI library. + * + * v1 : CUDAToolsSDK 4.0 + * v2 : CUDAToolsSDK 4.1 + * v3 : CUDA Toolkit 5.0 + * v4 : CUDA Toolkit 5.5 + * v5 : CUDA Toolkit 6.0 + * v6 : CUDA Toolkit 6.5 + * v7 : CUDA Toolkit 6.5(with sm_52 support) + * v8 : CUDA Toolkit 7.0 + * v9 : CUDA Toolkit 8.0 + * v10 : CUDA Toolkit 9.0 + * v11 : CUDA Toolkit 9.1 + * v12 : CUDA Toolkit 10.0, 10.1 and 10.2 + * v13 : CUDA Toolkit 11.0 + * v14 : CUDA Toolkit 11.1 + * v15 : CUDA Toolkit 11.2, 11.3 and 11.4 + * v16 : CUDA Toolkit 11.5 + * v17 : CUDA Toolkit 11.6 + * v18 : CUDA Toolkit 11.8 + * v19 : CUDA Toolkit 12.0 + * v20 : CUDA Toolkit 12.2 + * v21 : CUDA Toolkit 12.3 + * v22 : CUDA Toolkit 12.4 + * v23 : CUDA Toolkit 12.5 + * v24 : CUDA Toolkit 12.6 + * v26 : CUDA Toolkit 12.8 + */ +#define CUPTI_API_VERSION 26 + +/** + * \brief Get the CUPTI API version. + * + * Return the API version in \p *version. + * + * \param version Returns the version + * + * \retval CUPTI_SUCCESS on success + * \retval CUPTI_ERROR_INVALID_PARAMETER if \p version is NULL + * \sa CUPTI_API_VERSION + */ +CUptiResult CUPTIAPI cuptiGetVersion(uint32_t *version); + +/** @} */ /* END CUPTI_VERSION_API */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /*_CUPTI_VERSION_H_*/ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudaGL_meta.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudaGL_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..7a52e194b265d32f61d47bd3081f4958755bff46 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudaGL_meta.h @@ -0,0 +1,116 @@ +// This file is generated. Any changes you make will be lost during the next clean build. + +// Dependent includes +#ifdef __APPLE__ +#include +#else +#include +#endif + +// CUDA public interface, for type definitions and cu* function prototypes +#include "cudaGL.h" + + +// ************************************************************************* +// Definitions of structs to hold parameters for each function +// ************************************************************************* + +typedef struct cuGraphicsGLRegisterBuffer_params_st { + CUgraphicsResource *pCudaResource; + GLuint buffer; + unsigned int Flags; +} cuGraphicsGLRegisterBuffer_params; + +typedef struct cuGraphicsGLRegisterImage_params_st { + CUgraphicsResource *pCudaResource; + GLuint image; + GLenum target; + unsigned int Flags; +} cuGraphicsGLRegisterImage_params; + +typedef struct cuGLGetDevices_v2_params_st { + unsigned int *pCudaDeviceCount; + CUdevice *pCudaDevices; + unsigned int cudaDeviceCount; + CUGLDeviceList deviceList; +} cuGLGetDevices_v2_params; + +typedef struct cuGLCtxCreate_v2_params_st { + CUcontext *pCtx; + unsigned int Flags; + CUdevice device; +} cuGLCtxCreate_v2_params; + +typedef struct cuGLRegisterBufferObject_params_st { + GLuint buffer; +} cuGLRegisterBufferObject_params; + +typedef struct cuGLMapBufferObject_v2_ptds_params_st { + CUdeviceptr *dptr; + size_t *size; + GLuint buffer; +} cuGLMapBufferObject_v2_ptds_params; + +typedef struct cuGLUnmapBufferObject_params_st { + GLuint buffer; +} cuGLUnmapBufferObject_params; + +typedef struct cuGLUnregisterBufferObject_params_st { + GLuint buffer; +} cuGLUnregisterBufferObject_params; + +typedef struct cuGLSetBufferObjectMapFlags_params_st { + GLuint buffer; + unsigned int Flags; +} cuGLSetBufferObjectMapFlags_params; + +typedef struct cuGLMapBufferObjectAsync_v2_ptsz_params_st { + CUdeviceptr *dptr; + size_t *size; + GLuint buffer; + CUstream hStream; +} cuGLMapBufferObjectAsync_v2_ptsz_params; + +typedef struct cuGLUnmapBufferObjectAsync_params_st { + GLuint buffer; + CUstream hStream; +} cuGLUnmapBufferObjectAsync_params; + +typedef struct cuGLGetDevices_params_st { + unsigned int *pCudaDeviceCount; + CUdevice *pCudaDevices; + unsigned int cudaDeviceCount; + CUGLDeviceList deviceList; +} cuGLGetDevices_params; + +typedef struct cuGLMapBufferObject_v2_params_st { + CUdeviceptr *dptr; + size_t *size; + GLuint buffer; +} cuGLMapBufferObject_v2_params; + +typedef struct cuGLMapBufferObjectAsync_v2_params_st { + CUdeviceptr *dptr; + size_t *size; + GLuint buffer; + CUstream hStream; +} cuGLMapBufferObjectAsync_v2_params; + +typedef struct cuGLCtxCreate_params_st { + CUcontext *pCtx; + unsigned int Flags; + CUdevice device; +} cuGLCtxCreate_params; + +typedef struct cuGLMapBufferObject_params_st { + CUdeviceptr_v1 *dptr; + unsigned int *size; + GLuint buffer; +} cuGLMapBufferObject_params; + +typedef struct cuGLMapBufferObjectAsync_params_st { + CUdeviceptr_v1 *dptr; + unsigned int *size; + GLuint buffer; + CUstream hStream; +} cuGLMapBufferObjectAsync_params; diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudaVDPAU_meta.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudaVDPAU_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..abc603c8d9be21e012a9b1641330c2e203d623b2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudaVDPAU_meta.h @@ -0,0 +1,46 @@ +// This file is generated. Any changes you make will be lost during the next clean build. + +// Dependent includes +#include + +// CUDA public interface, for type definitions and cu* function prototypes +#include "cudaVDPAU.h" + + +// ************************************************************************* +// Definitions of structs to hold parameters for each function +// ************************************************************************* + +typedef struct cuVDPAUGetDevice_params_st { + CUdevice *pDevice; + VdpDevice vdpDevice; + VdpGetProcAddress *vdpGetProcAddress; +} cuVDPAUGetDevice_params; + +typedef struct cuVDPAUCtxCreate_v2_params_st { + CUcontext *pCtx; + unsigned int flags; + CUdevice device; + VdpDevice vdpDevice; + VdpGetProcAddress *vdpGetProcAddress; +} cuVDPAUCtxCreate_v2_params; + +typedef struct cuGraphicsVDPAURegisterVideoSurface_params_st { + CUgraphicsResource *pCudaResource; + VdpVideoSurface vdpSurface; + unsigned int flags; +} cuGraphicsVDPAURegisterVideoSurface_params; + +typedef struct cuGraphicsVDPAURegisterOutputSurface_params_st { + CUgraphicsResource *pCudaResource; + VdpOutputSurface vdpSurface; + unsigned int flags; +} cuGraphicsVDPAURegisterOutputSurface_params; + +typedef struct cuVDPAUCtxCreate_params_st { + CUcontext *pCtx; + unsigned int flags; + CUdevice device; + VdpDevice vdpDevice; + VdpGetProcAddress *vdpGetProcAddress; +} cuVDPAUCtxCreate_params; diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_gl_interop_meta.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_gl_interop_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..eaba3ac5a760e338f1edc191609f6fa2a32adee7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_gl_interop_meta.h @@ -0,0 +1,71 @@ +// This file is generated. Any changes you make will be lost during the next clean build. + +// CUDA public interface, for type definitions and api function prototypes +#include "cuda_gl_interop.h" + +// ************************************************************************* +// Definitions of structs to hold parameters for each function +// ************************************************************************* + +// Currently used parameter trace structures +typedef struct cudaGLGetDevices_v4010_params_st { + unsigned int *pCudaDeviceCount; + int *pCudaDevices; + unsigned int cudaDeviceCount; + enum cudaGLDeviceList deviceList; +} cudaGLGetDevices_v4010_params; + +typedef struct cudaGraphicsGLRegisterImage_v3020_params_st { + struct cudaGraphicsResource **resource; + GLuint image; + GLenum target; + unsigned int flags; +} cudaGraphicsGLRegisterImage_v3020_params; + +typedef struct cudaGraphicsGLRegisterBuffer_v3020_params_st { + struct cudaGraphicsResource **resource; + GLuint buffer; + unsigned int flags; +} cudaGraphicsGLRegisterBuffer_v3020_params; + +typedef struct cudaGLSetGLDevice_v3020_params_st { + int device; +} cudaGLSetGLDevice_v3020_params; + +typedef struct cudaGLRegisterBufferObject_v3020_params_st { + GLuint bufObj; +} cudaGLRegisterBufferObject_v3020_params; + +typedef struct cudaGLMapBufferObject_v3020_params_st { + void **devPtr; + GLuint bufObj; +} cudaGLMapBufferObject_v3020_params; + +typedef struct cudaGLUnmapBufferObject_v3020_params_st { + GLuint bufObj; +} cudaGLUnmapBufferObject_v3020_params; + +typedef struct cudaGLUnregisterBufferObject_v3020_params_st { + GLuint bufObj; +} cudaGLUnregisterBufferObject_v3020_params; + +typedef struct cudaGLSetBufferObjectMapFlags_v3020_params_st { + GLuint bufObj; + unsigned int flags; +} cudaGLSetBufferObjectMapFlags_v3020_params; + +typedef struct cudaGLMapBufferObjectAsync_v3020_params_st { + void **devPtr; + GLuint bufObj; + cudaStream_t stream; +} cudaGLMapBufferObjectAsync_v3020_params; + +typedef struct cudaGLUnmapBufferObjectAsync_v3020_params_st { + GLuint bufObj; + cudaStream_t stream; +} cudaGLUnmapBufferObjectAsync_v3020_params; + +// Parameter trace structures for removed functions + + +// End of parameter trace structures diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_meta.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..954db0ad73e2eb029918f595ddee452aa9afd0e3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_meta.h @@ -0,0 +1,3718 @@ +// This file is generated. Any changes you make will be lost during the next clean build. + +// No dependent includes + +// CUDA public interface, for type definitions and cu* function prototypes +#include "cuda.h" + + +// ************************************************************************* +// Definitions of structs to hold parameters for each function +// ************************************************************************* + +typedef struct cuGetErrorString_params_st { + CUresult error; + const char **pStr; +} cuGetErrorString_params; + +typedef struct cuGetErrorName_params_st { + CUresult error; + const char **pStr; +} cuGetErrorName_params; + +typedef struct cuInit_params_st { + unsigned int Flags; +} cuInit_params; + +typedef struct cuDriverGetVersion_params_st { + int *driverVersion; +} cuDriverGetVersion_params; + +typedef struct cuDeviceGet_params_st { + CUdevice *device; + int ordinal; +} cuDeviceGet_params; + +typedef struct cuDeviceGetCount_params_st { + int *count; +} cuDeviceGetCount_params; + +typedef struct cuDeviceGetName_params_st { + char *name; + int len; + CUdevice dev; +} cuDeviceGetName_params; + +typedef struct cuDeviceGetUuid_params_st { + CUuuid *uuid; + CUdevice dev; +} cuDeviceGetUuid_params; + +typedef struct cuDeviceGetUuid_v2_params_st { + CUuuid *uuid; + CUdevice dev; +} cuDeviceGetUuid_v2_params; + +typedef struct cuDeviceGetLuid_params_st { + char *luid; + unsigned int *deviceNodeMask; + CUdevice dev; +} cuDeviceGetLuid_params; + +typedef struct cuDeviceTotalMem_v2_params_st { + size_t *bytes; + CUdevice dev; +} cuDeviceTotalMem_v2_params; + +typedef struct cuDeviceGetTexture1DLinearMaxWidth_params_st { + size_t *maxWidthInElements; + CUarray_format format; + unsigned numChannels; + CUdevice dev; +} cuDeviceGetTexture1DLinearMaxWidth_params; + +typedef struct cuDeviceGetAttribute_params_st { + int *pi; + CUdevice_attribute attrib; + CUdevice dev; +} cuDeviceGetAttribute_params; + +typedef struct cuDeviceGetNvSciSyncAttributes_params_st { + void *nvSciSyncAttrList; + CUdevice dev; + int flags; +} cuDeviceGetNvSciSyncAttributes_params; + +typedef struct cuDeviceSetMemPool_params_st { + CUdevice dev; + CUmemoryPool pool; +} cuDeviceSetMemPool_params; + +typedef struct cuDeviceGetMemPool_params_st { + CUmemoryPool *pool; + CUdevice dev; +} cuDeviceGetMemPool_params; + +typedef struct cuDeviceGetDefaultMemPool_params_st { + CUmemoryPool *pool_out; + CUdevice dev; +} cuDeviceGetDefaultMemPool_params; + +typedef struct cuDeviceGetExecAffinitySupport_params_st { + int *pi; + CUexecAffinityType type; + CUdevice dev; +} cuDeviceGetExecAffinitySupport_params; + +typedef struct cuFlushGPUDirectRDMAWrites_params_st { + CUflushGPUDirectRDMAWritesTarget target; + CUflushGPUDirectRDMAWritesScope scope; +} cuFlushGPUDirectRDMAWrites_params; + +typedef struct cuDeviceGetProperties_params_st { + CUdevprop *prop; + CUdevice dev; +} cuDeviceGetProperties_params; + +typedef struct cuDeviceComputeCapability_params_st { + int *major; + int *minor; + CUdevice dev; +} cuDeviceComputeCapability_params; + +typedef struct cuDevicePrimaryCtxRetain_params_st { + CUcontext *pctx; + CUdevice dev; +} cuDevicePrimaryCtxRetain_params; + +typedef struct cuDevicePrimaryCtxRelease_v2_params_st { + CUdevice dev; +} cuDevicePrimaryCtxRelease_v2_params; + +typedef struct cuDevicePrimaryCtxSetFlags_v2_params_st { + CUdevice dev; + unsigned int flags; +} cuDevicePrimaryCtxSetFlags_v2_params; + +typedef struct cuDevicePrimaryCtxGetState_params_st { + CUdevice dev; + unsigned int *flags; + int *active; +} cuDevicePrimaryCtxGetState_params; + +typedef struct cuDevicePrimaryCtxReset_v2_params_st { + CUdevice dev; +} cuDevicePrimaryCtxReset_v2_params; + +typedef struct cuCtxCreate_v2_params_st { + CUcontext *pctx; + unsigned int flags; + CUdevice dev; +} cuCtxCreate_v2_params; + +typedef struct cuCtxCreate_v3_params_st { + CUcontext *pctx; + CUexecAffinityParam *paramsArray; + int numParams; + unsigned int flags; + CUdevice dev; +} cuCtxCreate_v3_params; + +typedef struct cuCtxCreate_v4_params_st { + CUcontext *pctx; + CUctxCreateParams *ctxCreateParams; + unsigned int flags; + CUdevice dev; +} cuCtxCreate_v4_params; + +typedef struct cuCtxDestroy_v2_params_st { + CUcontext ctx; +} cuCtxDestroy_v2_params; + +typedef struct cuCtxPushCurrent_v2_params_st { + CUcontext ctx; +} cuCtxPushCurrent_v2_params; + +typedef struct cuCtxPopCurrent_v2_params_st { + CUcontext *pctx; +} cuCtxPopCurrent_v2_params; + +typedef struct cuCtxSetCurrent_params_st { + CUcontext ctx; +} cuCtxSetCurrent_params; + +typedef struct cuCtxGetCurrent_params_st { + CUcontext *pctx; +} cuCtxGetCurrent_params; + +typedef struct cuCtxGetDevice_params_st { + CUdevice *device; +} cuCtxGetDevice_params; + +typedef struct cuCtxGetFlags_params_st { + unsigned int *flags; +} cuCtxGetFlags_params; + +typedef struct cuCtxSetFlags_params_st { + unsigned int flags; +} cuCtxSetFlags_params; + +typedef struct cuCtxGetId_params_st { + CUcontext ctx; + unsigned long long *ctxId; +} cuCtxGetId_params; + +typedef struct cuCtxSetLimit_params_st { + CUlimit limit; + size_t value; +} cuCtxSetLimit_params; + +typedef struct cuCtxGetLimit_params_st { + size_t *pvalue; + CUlimit limit; +} cuCtxGetLimit_params; + +typedef struct cuCtxGetCacheConfig_params_st { + CUfunc_cache *pconfig; +} cuCtxGetCacheConfig_params; + +typedef struct cuCtxSetCacheConfig_params_st { + CUfunc_cache config; +} cuCtxSetCacheConfig_params; + +typedef struct cuCtxGetApiVersion_params_st { + CUcontext ctx; + unsigned int *version; +} cuCtxGetApiVersion_params; + +typedef struct cuCtxGetStreamPriorityRange_params_st { + int *leastPriority; + int *greatestPriority; +} cuCtxGetStreamPriorityRange_params; + +typedef struct cuCtxGetExecAffinity_params_st { + CUexecAffinityParam *pExecAffinity; + CUexecAffinityType type; +} cuCtxGetExecAffinity_params; + +typedef struct cuCtxRecordEvent_params_st { + CUcontext hCtx; + CUevent hEvent; +} cuCtxRecordEvent_params; + +typedef struct cuCtxWaitEvent_params_st { + CUcontext hCtx; + CUevent hEvent; +} cuCtxWaitEvent_params; + +typedef struct cuCtxAttach_params_st { + CUcontext *pctx; + unsigned int flags; +} cuCtxAttach_params; + +typedef struct cuCtxDetach_params_st { + CUcontext ctx; +} cuCtxDetach_params; + +typedef struct cuCtxGetSharedMemConfig_params_st { + CUsharedconfig *pConfig; +} cuCtxGetSharedMemConfig_params; + +typedef struct cuCtxSetSharedMemConfig_params_st { + CUsharedconfig config; +} cuCtxSetSharedMemConfig_params; + +typedef struct cuModuleLoad_params_st { + CUmodule *module; + const char *fname; +} cuModuleLoad_params; + +typedef struct cuModuleLoadData_params_st { + CUmodule *module; + const void *image; +} cuModuleLoadData_params; + +typedef struct cuModuleLoadDataEx_params_st { + CUmodule *module; + const void *image; + unsigned int numOptions; + CUjit_option *options; + void **optionValues; +} cuModuleLoadDataEx_params; + +typedef struct cuModuleLoadFatBinary_params_st { + CUmodule *module; + const void *fatCubin; +} cuModuleLoadFatBinary_params; + +typedef struct cuModuleUnload_params_st { + CUmodule hmod; +} cuModuleUnload_params; + +typedef struct cuModuleGetLoadingMode_params_st { + CUmoduleLoadingMode *mode; +} cuModuleGetLoadingMode_params; + +typedef struct cuModuleGetFunction_params_st { + CUfunction *hfunc; + CUmodule hmod; + const char *name; +} cuModuleGetFunction_params; + +typedef struct cuModuleGetFunctionCount_params_st { + unsigned int *count; + CUmodule mod; +} cuModuleGetFunctionCount_params; + +typedef struct cuModuleEnumerateFunctions_params_st { + CUfunction *functions; + unsigned int numFunctions; + CUmodule mod; +} cuModuleEnumerateFunctions_params; + +typedef struct cuModuleGetGlobal_v2_params_st { + CUdeviceptr *dptr; + size_t *bytes; + CUmodule hmod; + const char *name; +} cuModuleGetGlobal_v2_params; + +typedef struct cuLinkCreate_v2_params_st { + unsigned int numOptions; + CUjit_option *options; + void **optionValues; + CUlinkState *stateOut; +} cuLinkCreate_v2_params; + +typedef struct cuLinkAddData_v2_params_st { + CUlinkState state; + CUjitInputType type; + void *data; + size_t size; + const char *name; + unsigned int numOptions; + CUjit_option *options; + void **optionValues; +} cuLinkAddData_v2_params; + +typedef struct cuLinkAddFile_v2_params_st { + CUlinkState state; + CUjitInputType type; + const char *path; + unsigned int numOptions; + CUjit_option *options; + void **optionValues; +} cuLinkAddFile_v2_params; + +typedef struct cuLinkComplete_params_st { + CUlinkState state; + void **cubinOut; + size_t *sizeOut; +} cuLinkComplete_params; + +typedef struct cuLinkDestroy_params_st { + CUlinkState state; +} cuLinkDestroy_params; + +typedef struct cuModuleGetTexRef_params_st { + CUtexref *pTexRef; + CUmodule hmod; + const char *name; +} cuModuleGetTexRef_params; + +typedef struct cuModuleGetSurfRef_params_st { + CUsurfref *pSurfRef; + CUmodule hmod; + const char *name; +} cuModuleGetSurfRef_params; + +typedef struct cuLibraryLoadData_params_st { + CUlibrary *library; + const void *code; + CUjit_option *jitOptions; + void **jitOptionsValues; + unsigned int numJitOptions; + CUlibraryOption *libraryOptions; + void **libraryOptionValues; + unsigned int numLibraryOptions; +} cuLibraryLoadData_params; + +typedef struct cuLibraryLoadFromFile_params_st { + CUlibrary *library; + const char *fileName; + CUjit_option *jitOptions; + void **jitOptionsValues; + unsigned int numJitOptions; + CUlibraryOption *libraryOptions; + void **libraryOptionValues; + unsigned int numLibraryOptions; +} cuLibraryLoadFromFile_params; + +typedef struct cuLibraryUnload_params_st { + CUlibrary library; +} cuLibraryUnload_params; + +typedef struct cuLibraryGetKernel_params_st { + CUkernel *pKernel; + CUlibrary library; + const char *name; +} cuLibraryGetKernel_params; + +typedef struct cuLibraryGetKernelCount_params_st { + unsigned int *count; + CUlibrary lib; +} cuLibraryGetKernelCount_params; + +typedef struct cuLibraryEnumerateKernels_params_st { + CUkernel *kernels; + unsigned int numKernels; + CUlibrary lib; +} cuLibraryEnumerateKernels_params; + +typedef struct cuLibraryGetModule_params_st { + CUmodule *pMod; + CUlibrary library; +} cuLibraryGetModule_params; + +typedef struct cuKernelGetFunction_params_st { + CUfunction *pFunc; + CUkernel kernel; +} cuKernelGetFunction_params; + +typedef struct cuKernelGetLibrary_params_st { + CUlibrary *pLib; + CUkernel kernel; +} cuKernelGetLibrary_params; + +typedef struct cuLibraryGetGlobal_params_st { + CUdeviceptr *dptr; + size_t *bytes; + CUlibrary library; + const char *name; +} cuLibraryGetGlobal_params; + +typedef struct cuLibraryGetManaged_params_st { + CUdeviceptr *dptr; + size_t *bytes; + CUlibrary library; + const char *name; +} cuLibraryGetManaged_params; + +typedef struct cuLibraryGetUnifiedFunction_params_st { + void **fptr; + CUlibrary library; + const char *symbol; +} cuLibraryGetUnifiedFunction_params; + +typedef struct cuKernelGetAttribute_params_st { + int *pi; + CUfunction_attribute attrib; + CUkernel kernel; + CUdevice dev; +} cuKernelGetAttribute_params; + +typedef struct cuKernelSetAttribute_params_st { + CUfunction_attribute attrib; + int val; + CUkernel kernel; + CUdevice dev; +} cuKernelSetAttribute_params; + +typedef struct cuKernelSetCacheConfig_params_st { + CUkernel kernel; + CUfunc_cache config; + CUdevice dev; +} cuKernelSetCacheConfig_params; + +typedef struct cuKernelGetName_params_st { + const char **name; + CUkernel hfunc; +} cuKernelGetName_params; + +typedef struct cuKernelGetParamInfo_params_st { + CUkernel kernel; + size_t paramIndex; + size_t *paramOffset; + size_t *paramSize; +} cuKernelGetParamInfo_params; + +typedef struct cuMemGetInfo_v2_params_st { + size_t *free; + size_t *total; +} cuMemGetInfo_v2_params; + +typedef struct cuMemAlloc_v2_params_st { + CUdeviceptr *dptr; + size_t bytesize; +} cuMemAlloc_v2_params; + +typedef struct cuMemAllocPitch_v2_params_st { + CUdeviceptr *dptr; + size_t *pPitch; + size_t WidthInBytes; + size_t Height; + unsigned int ElementSizeBytes; +} cuMemAllocPitch_v2_params; + +typedef struct cuMemFree_v2_params_st { + CUdeviceptr dptr; +} cuMemFree_v2_params; + +typedef struct cuMemGetAddressRange_v2_params_st { + CUdeviceptr *pbase; + size_t *psize; + CUdeviceptr dptr; +} cuMemGetAddressRange_v2_params; + +typedef struct cuMemAllocHost_v2_params_st { + void **pp; + size_t bytesize; +} cuMemAllocHost_v2_params; + +typedef struct cuMemFreeHost_params_st { + void *p; +} cuMemFreeHost_params; + +typedef struct cuMemHostAlloc_params_st { + void **pp; + size_t bytesize; + unsigned int Flags; +} cuMemHostAlloc_params; + +typedef struct cuMemHostGetDevicePointer_v2_params_st { + CUdeviceptr *pdptr; + void *p; + unsigned int Flags; +} cuMemHostGetDevicePointer_v2_params; + +typedef struct cuMemHostGetFlags_params_st { + unsigned int *pFlags; + void *p; +} cuMemHostGetFlags_params; + +typedef struct cuMemAllocManaged_params_st { + CUdeviceptr *dptr; + size_t bytesize; + unsigned int flags; +} cuMemAllocManaged_params; + +typedef struct cuDeviceRegisterAsyncNotification_params_st { + CUdevice device; + CUasyncCallback callbackFunc; + void *userData; + CUasyncCallbackHandle *callback; +} cuDeviceRegisterAsyncNotification_params; + +typedef struct cuDeviceUnregisterAsyncNotification_params_st { + CUdevice device; + CUasyncCallbackHandle callback; +} cuDeviceUnregisterAsyncNotification_params; + +typedef struct cuDeviceGetByPCIBusId_params_st { + CUdevice *dev; + const char *pciBusId; +} cuDeviceGetByPCIBusId_params; + +typedef struct cuDeviceGetPCIBusId_params_st { + char *pciBusId; + int len; + CUdevice dev; +} cuDeviceGetPCIBusId_params; + +typedef struct cuIpcGetEventHandle_params_st { + CUipcEventHandle *pHandle; + CUevent event; +} cuIpcGetEventHandle_params; + +typedef struct cuIpcOpenEventHandle_params_st { + CUevent *phEvent; + CUipcEventHandle handle; +} cuIpcOpenEventHandle_params; + +typedef struct cuIpcGetMemHandle_params_st { + CUipcMemHandle *pHandle; + CUdeviceptr dptr; +} cuIpcGetMemHandle_params; + +typedef struct cuIpcOpenMemHandle_v2_params_st { + CUdeviceptr *pdptr; + CUipcMemHandle handle; + unsigned int Flags; +} cuIpcOpenMemHandle_v2_params; + +typedef struct cuIpcCloseMemHandle_params_st { + CUdeviceptr dptr; +} cuIpcCloseMemHandle_params; + +typedef struct cuMemHostRegister_v2_params_st { + void *p; + size_t bytesize; + unsigned int Flags; +} cuMemHostRegister_v2_params; + +typedef struct cuMemHostUnregister_params_st { + void *p; +} cuMemHostUnregister_params; + +typedef struct cuMemcpy_ptds_params_st { + CUdeviceptr dst; + CUdeviceptr src; + size_t ByteCount; +} cuMemcpy_ptds_params; + +typedef struct cuMemcpyPeer_ptds_params_st { + CUdeviceptr dstDevice; + CUcontext dstContext; + CUdeviceptr srcDevice; + CUcontext srcContext; + size_t ByteCount; +} cuMemcpyPeer_ptds_params; + +typedef struct cuMemcpyHtoD_v2_ptds_params_st { + CUdeviceptr dstDevice; + const void *srcHost; + size_t ByteCount; +} cuMemcpyHtoD_v2_ptds_params; + +typedef struct cuMemcpyDtoH_v2_ptds_params_st { + void *dstHost; + CUdeviceptr srcDevice; + size_t ByteCount; +} cuMemcpyDtoH_v2_ptds_params; + +typedef struct cuMemcpyDtoD_v2_ptds_params_st { + CUdeviceptr dstDevice; + CUdeviceptr srcDevice; + size_t ByteCount; +} cuMemcpyDtoD_v2_ptds_params; + +typedef struct cuMemcpyDtoA_v2_ptds_params_st { + CUarray dstArray; + size_t dstOffset; + CUdeviceptr srcDevice; + size_t ByteCount; +} cuMemcpyDtoA_v2_ptds_params; + +typedef struct cuMemcpyAtoD_v2_ptds_params_st { + CUdeviceptr dstDevice; + CUarray srcArray; + size_t srcOffset; + size_t ByteCount; +} cuMemcpyAtoD_v2_ptds_params; + +typedef struct cuMemcpyHtoA_v2_ptds_params_st { + CUarray dstArray; + size_t dstOffset; + const void *srcHost; + size_t ByteCount; +} cuMemcpyHtoA_v2_ptds_params; + +typedef struct cuMemcpyAtoH_v2_ptds_params_st { + void *dstHost; + CUarray srcArray; + size_t srcOffset; + size_t ByteCount; +} cuMemcpyAtoH_v2_ptds_params; + +typedef struct cuMemcpyAtoA_v2_ptds_params_st { + CUarray dstArray; + size_t dstOffset; + CUarray srcArray; + size_t srcOffset; + size_t ByteCount; +} cuMemcpyAtoA_v2_ptds_params; + +typedef struct cuMemcpy2D_v2_ptds_params_st { + const CUDA_MEMCPY2D *pCopy; +} cuMemcpy2D_v2_ptds_params; + +typedef struct cuMemcpy2DUnaligned_v2_ptds_params_st { + const CUDA_MEMCPY2D *pCopy; +} cuMemcpy2DUnaligned_v2_ptds_params; + +typedef struct cuMemcpy3D_v2_ptds_params_st { + const CUDA_MEMCPY3D *pCopy; +} cuMemcpy3D_v2_ptds_params; + +typedef struct cuMemcpy3DPeer_ptds_params_st { + const CUDA_MEMCPY3D_PEER *pCopy; +} cuMemcpy3DPeer_ptds_params; + +typedef struct cuMemcpyAsync_ptsz_params_st { + CUdeviceptr dst; + CUdeviceptr src; + size_t ByteCount; + CUstream hStream; +} cuMemcpyAsync_ptsz_params; + +typedef struct cuMemcpyPeerAsync_ptsz_params_st { + CUdeviceptr dstDevice; + CUcontext dstContext; + CUdeviceptr srcDevice; + CUcontext srcContext; + size_t ByteCount; + CUstream hStream; +} cuMemcpyPeerAsync_ptsz_params; + +typedef struct cuMemcpyHtoDAsync_v2_ptsz_params_st { + CUdeviceptr dstDevice; + const void *srcHost; + size_t ByteCount; + CUstream hStream; +} cuMemcpyHtoDAsync_v2_ptsz_params; + +typedef struct cuMemcpyDtoHAsync_v2_ptsz_params_st { + void *dstHost; + CUdeviceptr srcDevice; + size_t ByteCount; + CUstream hStream; +} cuMemcpyDtoHAsync_v2_ptsz_params; + +typedef struct cuMemcpyDtoDAsync_v2_ptsz_params_st { + CUdeviceptr dstDevice; + CUdeviceptr srcDevice; + size_t ByteCount; + CUstream hStream; +} cuMemcpyDtoDAsync_v2_ptsz_params; + +typedef struct cuMemcpyHtoAAsync_v2_ptsz_params_st { + CUarray dstArray; + size_t dstOffset; + const void *srcHost; + size_t ByteCount; + CUstream hStream; +} cuMemcpyHtoAAsync_v2_ptsz_params; + +typedef struct cuMemcpyAtoHAsync_v2_ptsz_params_st { + void *dstHost; + CUarray srcArray; + size_t srcOffset; + size_t ByteCount; + CUstream hStream; +} cuMemcpyAtoHAsync_v2_ptsz_params; + +typedef struct cuMemcpy2DAsync_v2_ptsz_params_st { + const CUDA_MEMCPY2D *pCopy; + CUstream hStream; +} cuMemcpy2DAsync_v2_ptsz_params; + +typedef struct cuMemcpy3DAsync_v2_ptsz_params_st { + const CUDA_MEMCPY3D *pCopy; + CUstream hStream; +} cuMemcpy3DAsync_v2_ptsz_params; + +typedef struct cuMemcpy3DPeerAsync_ptsz_params_st { + const CUDA_MEMCPY3D_PEER *pCopy; + CUstream hStream; +} cuMemcpy3DPeerAsync_ptsz_params; + +typedef struct cuMemcpyBatchAsync_ptsz_params_st { + CUdeviceptr *dsts; + CUdeviceptr *srcs; + size_t *sizes; + size_t count; + CUmemcpyAttributes *attrs; + size_t *attrsIdxs; + size_t numAttrs; + size_t *failIdx; + CUstream hStream; +} cuMemcpyBatchAsync_ptsz_params; + +typedef struct cuMemcpy3DBatchAsync_ptsz_params_st { + size_t numOps; + CUDA_MEMCPY3D_BATCH_OP *opList; + size_t *failIdx; + unsigned long long flags; + CUstream hStream; +} cuMemcpy3DBatchAsync_ptsz_params; + +typedef struct cuMemsetD8_v2_ptds_params_st { + CUdeviceptr dstDevice; + unsigned char uc; + size_t N; +} cuMemsetD8_v2_ptds_params; + +typedef struct cuMemsetD16_v2_ptds_params_st { + CUdeviceptr dstDevice; + unsigned short us; + size_t N; +} cuMemsetD16_v2_ptds_params; + +typedef struct cuMemsetD32_v2_ptds_params_st { + CUdeviceptr dstDevice; + unsigned int ui; + size_t N; +} cuMemsetD32_v2_ptds_params; + +typedef struct cuMemsetD2D8_v2_ptds_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned char uc; + size_t Width; + size_t Height; +} cuMemsetD2D8_v2_ptds_params; + +typedef struct cuMemsetD2D16_v2_ptds_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned short us; + size_t Width; + size_t Height; +} cuMemsetD2D16_v2_ptds_params; + +typedef struct cuMemsetD2D32_v2_ptds_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned int ui; + size_t Width; + size_t Height; +} cuMemsetD2D32_v2_ptds_params; + +typedef struct cuMemsetD8Async_ptsz_params_st { + CUdeviceptr dstDevice; + unsigned char uc; + size_t N; + CUstream hStream; +} cuMemsetD8Async_ptsz_params; + +typedef struct cuMemsetD16Async_ptsz_params_st { + CUdeviceptr dstDevice; + unsigned short us; + size_t N; + CUstream hStream; +} cuMemsetD16Async_ptsz_params; + +typedef struct cuMemsetD32Async_ptsz_params_st { + CUdeviceptr dstDevice; + unsigned int ui; + size_t N; + CUstream hStream; +} cuMemsetD32Async_ptsz_params; + +typedef struct cuMemsetD2D8Async_ptsz_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned char uc; + size_t Width; + size_t Height; + CUstream hStream; +} cuMemsetD2D8Async_ptsz_params; + +typedef struct cuMemsetD2D16Async_ptsz_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned short us; + size_t Width; + size_t Height; + CUstream hStream; +} cuMemsetD2D16Async_ptsz_params; + +typedef struct cuMemsetD2D32Async_ptsz_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned int ui; + size_t Width; + size_t Height; + CUstream hStream; +} cuMemsetD2D32Async_ptsz_params; + +typedef struct cuArrayCreate_v2_params_st { + CUarray *pHandle; + const CUDA_ARRAY_DESCRIPTOR *pAllocateArray; +} cuArrayCreate_v2_params; + +typedef struct cuArrayGetDescriptor_v2_params_st { + CUDA_ARRAY_DESCRIPTOR *pArrayDescriptor; + CUarray hArray; +} cuArrayGetDescriptor_v2_params; + +typedef struct cuArrayGetSparseProperties_params_st { + CUDA_ARRAY_SPARSE_PROPERTIES *sparseProperties; + CUarray array; +} cuArrayGetSparseProperties_params; + +typedef struct cuMipmappedArrayGetSparseProperties_params_st { + CUDA_ARRAY_SPARSE_PROPERTIES *sparseProperties; + CUmipmappedArray mipmap; +} cuMipmappedArrayGetSparseProperties_params; + +typedef struct cuArrayGetMemoryRequirements_params_st { + CUDA_ARRAY_MEMORY_REQUIREMENTS *memoryRequirements; + CUarray array; + CUdevice device; +} cuArrayGetMemoryRequirements_params; + +typedef struct cuMipmappedArrayGetMemoryRequirements_params_st { + CUDA_ARRAY_MEMORY_REQUIREMENTS *memoryRequirements; + CUmipmappedArray mipmap; + CUdevice device; +} cuMipmappedArrayGetMemoryRequirements_params; + +typedef struct cuArrayGetPlane_params_st { + CUarray *pPlaneArray; + CUarray hArray; + unsigned int planeIdx; +} cuArrayGetPlane_params; + +typedef struct cuArrayDestroy_params_st { + CUarray hArray; +} cuArrayDestroy_params; + +typedef struct cuArray3DCreate_v2_params_st { + CUarray *pHandle; + const CUDA_ARRAY3D_DESCRIPTOR *pAllocateArray; +} cuArray3DCreate_v2_params; + +typedef struct cuArray3DGetDescriptor_v2_params_st { + CUDA_ARRAY3D_DESCRIPTOR *pArrayDescriptor; + CUarray hArray; +} cuArray3DGetDescriptor_v2_params; + +typedef struct cuMipmappedArrayCreate_params_st { + CUmipmappedArray *pHandle; + const CUDA_ARRAY3D_DESCRIPTOR *pMipmappedArrayDesc; + unsigned int numMipmapLevels; +} cuMipmappedArrayCreate_params; + +typedef struct cuMipmappedArrayGetLevel_params_st { + CUarray *pLevelArray; + CUmipmappedArray hMipmappedArray; + unsigned int level; +} cuMipmappedArrayGetLevel_params; + +typedef struct cuMipmappedArrayDestroy_params_st { + CUmipmappedArray hMipmappedArray; +} cuMipmappedArrayDestroy_params; + +typedef struct cuMemGetHandleForAddressRange_params_st { + void *handle; + CUdeviceptr dptr; + size_t size; + CUmemRangeHandleType handleType; + unsigned long long flags; +} cuMemGetHandleForAddressRange_params; + +typedef struct cuMemBatchDecompressAsync_ptsz_params_st { + CUmemDecompressParams *paramsArray; + size_t count; + unsigned int flags; + size_t *errorIndex; + CUstream stream; +} cuMemBatchDecompressAsync_ptsz_params; + +typedef struct cuMemAddressReserve_params_st { + CUdeviceptr *ptr; + size_t size; + size_t alignment; + CUdeviceptr addr; + unsigned long long flags; +} cuMemAddressReserve_params; + +typedef struct cuMemAddressFree_params_st { + CUdeviceptr ptr; + size_t size; +} cuMemAddressFree_params; + +typedef struct cuMemCreate_params_st { + CUmemGenericAllocationHandle *handle; + size_t size; + const CUmemAllocationProp *prop; + unsigned long long flags; +} cuMemCreate_params; + +typedef struct cuMemRelease_params_st { + CUmemGenericAllocationHandle handle; +} cuMemRelease_params; + +typedef struct cuMemMap_params_st { + CUdeviceptr ptr; + size_t size; + size_t offset; + CUmemGenericAllocationHandle handle; + unsigned long long flags; +} cuMemMap_params; + +typedef struct cuMemMapArrayAsync_ptsz_params_st { + CUarrayMapInfo *mapInfoList; + unsigned int count; + CUstream hStream; +} cuMemMapArrayAsync_ptsz_params; + +typedef struct cuMemUnmap_params_st { + CUdeviceptr ptr; + size_t size; +} cuMemUnmap_params; + +typedef struct cuMemSetAccess_params_st { + CUdeviceptr ptr; + size_t size; + const CUmemAccessDesc *desc; + size_t count; +} cuMemSetAccess_params; + +typedef struct cuMemGetAccess_params_st { + unsigned long long *flags; + const CUmemLocation *location; + CUdeviceptr ptr; +} cuMemGetAccess_params; + +typedef struct cuMemExportToShareableHandle_params_st { + void *shareableHandle; + CUmemGenericAllocationHandle handle; + CUmemAllocationHandleType handleType; + unsigned long long flags; +} cuMemExportToShareableHandle_params; + +typedef struct cuMemImportFromShareableHandle_params_st { + CUmemGenericAllocationHandle *handle; + void *osHandle; + CUmemAllocationHandleType shHandleType; +} cuMemImportFromShareableHandle_params; + +typedef struct cuMemGetAllocationGranularity_params_st { + size_t *granularity; + const CUmemAllocationProp *prop; + CUmemAllocationGranularity_flags option; +} cuMemGetAllocationGranularity_params; + +typedef struct cuMemGetAllocationPropertiesFromHandle_params_st { + CUmemAllocationProp *prop; + CUmemGenericAllocationHandle handle; +} cuMemGetAllocationPropertiesFromHandle_params; + +typedef struct cuMemRetainAllocationHandle_params_st { + CUmemGenericAllocationHandle *handle; + void *addr; +} cuMemRetainAllocationHandle_params; + +typedef struct cuMemFreeAsync_ptsz_params_st { + CUdeviceptr dptr; + CUstream hStream; +} cuMemFreeAsync_ptsz_params; + +typedef struct cuMemAllocAsync_ptsz_params_st { + CUdeviceptr *dptr; + size_t bytesize; + CUstream hStream; +} cuMemAllocAsync_ptsz_params; + +typedef struct cuMemPoolTrimTo_params_st { + CUmemoryPool pool; + size_t minBytesToKeep; +} cuMemPoolTrimTo_params; + +typedef struct cuMemPoolSetAttribute_params_st { + CUmemoryPool pool; + CUmemPool_attribute attr; + void *value; +} cuMemPoolSetAttribute_params; + +typedef struct cuMemPoolGetAttribute_params_st { + CUmemoryPool pool; + CUmemPool_attribute attr; + void *value; +} cuMemPoolGetAttribute_params; + +typedef struct cuMemPoolSetAccess_params_st { + CUmemoryPool pool; + const CUmemAccessDesc *map; + size_t count; +} cuMemPoolSetAccess_params; + +typedef struct cuMemPoolGetAccess_params_st { + CUmemAccess_flags *flags; + CUmemoryPool memPool; + CUmemLocation *location; +} cuMemPoolGetAccess_params; + +typedef struct cuMemPoolCreate_params_st { + CUmemoryPool *pool; + const CUmemPoolProps *poolProps; +} cuMemPoolCreate_params; + +typedef struct cuMemPoolDestroy_params_st { + CUmemoryPool pool; +} cuMemPoolDestroy_params; + +typedef struct cuMemAllocFromPoolAsync_ptsz_params_st { + CUdeviceptr *dptr; + size_t bytesize; + CUmemoryPool pool; + CUstream hStream; +} cuMemAllocFromPoolAsync_ptsz_params; + +typedef struct cuMemPoolExportToShareableHandle_params_st { + void *handle_out; + CUmemoryPool pool; + CUmemAllocationHandleType handleType; + unsigned long long flags; +} cuMemPoolExportToShareableHandle_params; + +typedef struct cuMemPoolImportFromShareableHandle_params_st { + CUmemoryPool *pool_out; + void *handle; + CUmemAllocationHandleType handleType; + unsigned long long flags; +} cuMemPoolImportFromShareableHandle_params; + +typedef struct cuMemPoolExportPointer_params_st { + CUmemPoolPtrExportData *shareData_out; + CUdeviceptr ptr; +} cuMemPoolExportPointer_params; + +typedef struct cuMemPoolImportPointer_params_st { + CUdeviceptr *ptr_out; + CUmemoryPool pool; + CUmemPoolPtrExportData *shareData; +} cuMemPoolImportPointer_params; + +typedef struct cuMulticastCreate_params_st { + CUmemGenericAllocationHandle *mcHandle; + const CUmulticastObjectProp *prop; +} cuMulticastCreate_params; + +typedef struct cuMulticastAddDevice_params_st { + CUmemGenericAllocationHandle mcHandle; + CUdevice dev; +} cuMulticastAddDevice_params; + +typedef struct cuMulticastBindMem_params_st { + CUmemGenericAllocationHandle mcHandle; + size_t mcOffset; + CUmemGenericAllocationHandle memHandle; + size_t memOffset; + size_t size; + unsigned long long flags; +} cuMulticastBindMem_params; + +typedef struct cuMulticastBindAddr_params_st { + CUmemGenericAllocationHandle mcHandle; + size_t mcOffset; + CUdeviceptr memptr; + size_t size; + unsigned long long flags; +} cuMulticastBindAddr_params; + +typedef struct cuMulticastUnbind_params_st { + CUmemGenericAllocationHandle mcHandle; + CUdevice dev; + size_t mcOffset; + size_t size; +} cuMulticastUnbind_params; + +typedef struct cuMulticastGetGranularity_params_st { + size_t *granularity; + const CUmulticastObjectProp *prop; + CUmulticastGranularity_flags option; +} cuMulticastGetGranularity_params; + +typedef struct cuPointerGetAttribute_params_st { + void *data; + CUpointer_attribute attribute; + CUdeviceptr ptr; +} cuPointerGetAttribute_params; + +typedef struct cuMemPrefetchAsync_ptsz_params_st { + CUdeviceptr devPtr; + size_t count; + CUdevice dstDevice; + CUstream hStream; +} cuMemPrefetchAsync_ptsz_params; + +typedef struct cuMemPrefetchAsync_v2_ptsz_params_st { + CUdeviceptr devPtr; + size_t count; + CUmemLocation location; + unsigned int flags; + CUstream hStream; +} cuMemPrefetchAsync_v2_ptsz_params; + +typedef struct cuMemAdvise_params_st { + CUdeviceptr devPtr; + size_t count; + CUmem_advise advice; + CUdevice device; +} cuMemAdvise_params; + +typedef struct cuMemAdvise_v2_params_st { + CUdeviceptr devPtr; + size_t count; + CUmem_advise advice; + CUmemLocation location; +} cuMemAdvise_v2_params; + +typedef struct cuMemRangeGetAttribute_params_st { + void *data; + size_t dataSize; + CUmem_range_attribute attribute; + CUdeviceptr devPtr; + size_t count; +} cuMemRangeGetAttribute_params; + +typedef struct cuMemRangeGetAttributes_params_st { + void **data; + size_t *dataSizes; + CUmem_range_attribute *attributes; + size_t numAttributes; + CUdeviceptr devPtr; + size_t count; +} cuMemRangeGetAttributes_params; + +typedef struct cuPointerSetAttribute_params_st { + const void *value; + CUpointer_attribute attribute; + CUdeviceptr ptr; +} cuPointerSetAttribute_params; + +typedef struct cuPointerGetAttributes_params_st { + unsigned int numAttributes; + CUpointer_attribute *attributes; + void **data; + CUdeviceptr ptr; +} cuPointerGetAttributes_params; + +typedef struct cuStreamCreate_params_st { + CUstream *phStream; + unsigned int Flags; +} cuStreamCreate_params; + +typedef struct cuStreamCreateWithPriority_params_st { + CUstream *phStream; + unsigned int flags; + int priority; +} cuStreamCreateWithPriority_params; + +typedef struct cuStreamGetPriority_ptsz_params_st { + CUstream hStream; + int *priority; +} cuStreamGetPriority_ptsz_params; + +typedef struct cuStreamGetDevice_ptsz_params_st { + CUstream hStream; + CUdevice *device; +} cuStreamGetDevice_ptsz_params; + +typedef struct cuStreamGetFlags_ptsz_params_st { + CUstream hStream; + unsigned int *flags; +} cuStreamGetFlags_ptsz_params; + +typedef struct cuStreamGetId_ptsz_params_st { + CUstream hStream; + unsigned long long *streamId; +} cuStreamGetId_ptsz_params; + +typedef struct cuStreamGetCtx_ptsz_params_st { + CUstream hStream; + CUcontext *pctx; +} cuStreamGetCtx_ptsz_params; + +typedef struct cuStreamGetCtx_v2_ptsz_params_st { + CUstream hStream; + CUcontext *pCtx; + CUgreenCtx *pGreenCtx; +} cuStreamGetCtx_v2_ptsz_params; + +typedef struct cuStreamWaitEvent_ptsz_params_st { + CUstream hStream; + CUevent hEvent; + unsigned int Flags; +} cuStreamWaitEvent_ptsz_params; + +typedef struct cuStreamAddCallback_ptsz_params_st { + CUstream hStream; + CUstreamCallback callback; + void *userData; + unsigned int flags; +} cuStreamAddCallback_ptsz_params; + +typedef struct cuStreamBeginCapture_v2_ptsz_params_st { + CUstream hStream; + CUstreamCaptureMode mode; +} cuStreamBeginCapture_v2_ptsz_params; + +typedef struct cuStreamBeginCaptureToGraph_ptsz_params_st { + CUstream hStream; + CUgraph hGraph; + const CUgraphNode *dependencies; + const CUgraphEdgeData *dependencyData; + size_t numDependencies; + CUstreamCaptureMode mode; +} cuStreamBeginCaptureToGraph_ptsz_params; + +typedef struct cuThreadExchangeStreamCaptureMode_params_st { + CUstreamCaptureMode *mode; +} cuThreadExchangeStreamCaptureMode_params; + +typedef struct cuStreamEndCapture_ptsz_params_st { + CUstream hStream; + CUgraph *phGraph; +} cuStreamEndCapture_ptsz_params; + +typedef struct cuStreamIsCapturing_ptsz_params_st { + CUstream hStream; + CUstreamCaptureStatus *captureStatus; +} cuStreamIsCapturing_ptsz_params; + +typedef struct cuStreamGetCaptureInfo_v2_ptsz_params_st { + CUstream hStream; + CUstreamCaptureStatus *captureStatus_out; + cuuint64_t *id_out; + CUgraph *graph_out; + const CUgraphNode **dependencies_out; + size_t *numDependencies_out; +} cuStreamGetCaptureInfo_v2_ptsz_params; + +typedef struct cuStreamGetCaptureInfo_v3_ptsz_params_st { + CUstream hStream; + CUstreamCaptureStatus *captureStatus_out; + cuuint64_t *id_out; + CUgraph *graph_out; + const CUgraphNode **dependencies_out; + const CUgraphEdgeData **edgeData_out; + size_t *numDependencies_out; +} cuStreamGetCaptureInfo_v3_ptsz_params; + +typedef struct cuStreamUpdateCaptureDependencies_ptsz_params_st { + CUstream hStream; + CUgraphNode *dependencies; + size_t numDependencies; + unsigned int flags; +} cuStreamUpdateCaptureDependencies_ptsz_params; + +typedef struct cuStreamUpdateCaptureDependencies_v2_ptsz_params_st { + CUstream hStream; + CUgraphNode *dependencies; + const CUgraphEdgeData *dependencyData; + size_t numDependencies; + unsigned int flags; +} cuStreamUpdateCaptureDependencies_v2_ptsz_params; + +typedef struct cuStreamAttachMemAsync_ptsz_params_st { + CUstream hStream; + CUdeviceptr dptr; + size_t length; + unsigned int flags; +} cuStreamAttachMemAsync_ptsz_params; + +typedef struct cuStreamQuery_ptsz_params_st { + CUstream hStream; +} cuStreamQuery_ptsz_params; + +typedef struct cuStreamSynchronize_ptsz_params_st { + CUstream hStream; +} cuStreamSynchronize_ptsz_params; + +typedef struct cuStreamDestroy_v2_params_st { + CUstream hStream; +} cuStreamDestroy_v2_params; + +typedef struct cuStreamCopyAttributes_ptsz_params_st { + CUstream dst; + CUstream src; +} cuStreamCopyAttributes_ptsz_params; + +typedef struct cuStreamGetAttribute_ptsz_params_st { + CUstream hStream; + CUstreamAttrID attr; + CUstreamAttrValue *value_out; +} cuStreamGetAttribute_ptsz_params; + +typedef struct cuStreamSetAttribute_ptsz_params_st { + CUstream hStream; + CUstreamAttrID attr; + const CUstreamAttrValue *value; +} cuStreamSetAttribute_ptsz_params; + +typedef struct cuEventCreate_params_st { + CUevent *phEvent; + unsigned int Flags; +} cuEventCreate_params; + +typedef struct cuEventRecord_ptsz_params_st { + CUevent hEvent; + CUstream hStream; +} cuEventRecord_ptsz_params; + +typedef struct cuEventRecordWithFlags_ptsz_params_st { + CUevent hEvent; + CUstream hStream; + unsigned int flags; +} cuEventRecordWithFlags_ptsz_params; + +typedef struct cuEventQuery_params_st { + CUevent hEvent; +} cuEventQuery_params; + +typedef struct cuEventSynchronize_params_st { + CUevent hEvent; +} cuEventSynchronize_params; + +typedef struct cuEventDestroy_v2_params_st { + CUevent hEvent; +} cuEventDestroy_v2_params; + +typedef struct cuEventElapsedTime_params_st { + float *pMilliseconds; + CUevent hStart; + CUevent hEnd; +} cuEventElapsedTime_params; + +typedef struct cuEventElapsedTime_v2_params_st { + float *pMilliseconds; + CUevent hStart; + CUevent hEnd; +} cuEventElapsedTime_v2_params; + +typedef struct cuImportExternalMemory_params_st { + CUexternalMemory *extMem_out; + const CUDA_EXTERNAL_MEMORY_HANDLE_DESC *memHandleDesc; +} cuImportExternalMemory_params; + +typedef struct cuExternalMemoryGetMappedBuffer_params_st { + CUdeviceptr *devPtr; + CUexternalMemory extMem; + const CUDA_EXTERNAL_MEMORY_BUFFER_DESC *bufferDesc; +} cuExternalMemoryGetMappedBuffer_params; + +typedef struct cuExternalMemoryGetMappedMipmappedArray_params_st { + CUmipmappedArray *mipmap; + CUexternalMemory extMem; + const CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC *mipmapDesc; +} cuExternalMemoryGetMappedMipmappedArray_params; + +typedef struct cuDestroyExternalMemory_params_st { + CUexternalMemory extMem; +} cuDestroyExternalMemory_params; + +typedef struct cuImportExternalSemaphore_params_st { + CUexternalSemaphore *extSem_out; + const CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC *semHandleDesc; +} cuImportExternalSemaphore_params; + +typedef struct cuSignalExternalSemaphoresAsync_ptsz_params_st { + const CUexternalSemaphore *extSemArray; + const CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS *paramsArray; + unsigned int numExtSems; + CUstream stream; +} cuSignalExternalSemaphoresAsync_ptsz_params; + +typedef struct cuWaitExternalSemaphoresAsync_ptsz_params_st { + const CUexternalSemaphore *extSemArray; + const CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS *paramsArray; + unsigned int numExtSems; + CUstream stream; +} cuWaitExternalSemaphoresAsync_ptsz_params; + +typedef struct cuDestroyExternalSemaphore_params_st { + CUexternalSemaphore extSem; +} cuDestroyExternalSemaphore_params; + +typedef struct cuStreamWaitValue32_v2_ptsz_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint32_t value; + unsigned int flags; +} cuStreamWaitValue32_v2_ptsz_params; + +typedef struct cuStreamWaitValue64_v2_ptsz_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint64_t value; + unsigned int flags; +} cuStreamWaitValue64_v2_ptsz_params; + +typedef struct cuStreamWriteValue32_v2_ptsz_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint32_t value; + unsigned int flags; +} cuStreamWriteValue32_v2_ptsz_params; + +typedef struct cuStreamWriteValue64_v2_ptsz_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint64_t value; + unsigned int flags; +} cuStreamWriteValue64_v2_ptsz_params; + +typedef struct cuStreamBatchMemOp_v2_ptsz_params_st { + CUstream stream; + unsigned int count; + CUstreamBatchMemOpParams *paramArray; + unsigned int flags; +} cuStreamBatchMemOp_v2_ptsz_params; + +typedef struct cuFuncGetAttribute_params_st { + int *pi; + CUfunction_attribute attrib; + CUfunction hfunc; +} cuFuncGetAttribute_params; + +typedef struct cuFuncSetAttribute_params_st { + CUfunction hfunc; + CUfunction_attribute attrib; + int value; +} cuFuncSetAttribute_params; + +typedef struct cuFuncSetCacheConfig_params_st { + CUfunction hfunc; + CUfunc_cache config; +} cuFuncSetCacheConfig_params; + +typedef struct cuFuncGetModule_params_st { + CUmodule *hmod; + CUfunction hfunc; +} cuFuncGetModule_params; + +typedef struct cuFuncGetName_params_st { + const char **name; + CUfunction hfunc; +} cuFuncGetName_params; + +typedef struct cuFuncGetParamInfo_params_st { + CUfunction func; + size_t paramIndex; + size_t *paramOffset; + size_t *paramSize; +} cuFuncGetParamInfo_params; + +typedef struct cuFuncIsLoaded_params_st { + CUfunctionLoadingState *state; + CUfunction function; +} cuFuncIsLoaded_params; + +typedef struct cuFuncLoad_params_st { + CUfunction function; +} cuFuncLoad_params; + +typedef struct cuLaunchKernel_ptsz_params_st { + CUfunction f; + unsigned int gridDimX; + unsigned int gridDimY; + unsigned int gridDimZ; + unsigned int blockDimX; + unsigned int blockDimY; + unsigned int blockDimZ; + unsigned int sharedMemBytes; + CUstream hStream; + void **kernelParams; + void **extra; +} cuLaunchKernel_ptsz_params; + +typedef struct cuLaunchKernelEx_ptsz_params_st { + const CUlaunchConfig *config; + CUfunction f; + void **kernelParams; + void **extra; +} cuLaunchKernelEx_ptsz_params; + +typedef struct cuLaunchCooperativeKernel_ptsz_params_st { + CUfunction f; + unsigned int gridDimX; + unsigned int gridDimY; + unsigned int gridDimZ; + unsigned int blockDimX; + unsigned int blockDimY; + unsigned int blockDimZ; + unsigned int sharedMemBytes; + CUstream hStream; + void **kernelParams; +} cuLaunchCooperativeKernel_ptsz_params; + +typedef struct cuLaunchCooperativeKernelMultiDevice_params_st { + CUDA_LAUNCH_PARAMS *launchParamsList; + unsigned int numDevices; + unsigned int flags; +} cuLaunchCooperativeKernelMultiDevice_params; + +typedef struct cuLaunchHostFunc_ptsz_params_st { + CUstream hStream; + CUhostFn fn; + void *userData; +} cuLaunchHostFunc_ptsz_params; + +typedef struct cuFuncSetBlockShape_params_st { + CUfunction hfunc; + int x; + int y; + int z; +} cuFuncSetBlockShape_params; + +typedef struct cuFuncSetSharedSize_params_st { + CUfunction hfunc; + unsigned int bytes; +} cuFuncSetSharedSize_params; + +typedef struct cuParamSetSize_params_st { + CUfunction hfunc; + unsigned int numbytes; +} cuParamSetSize_params; + +typedef struct cuParamSeti_params_st { + CUfunction hfunc; + int offset; + unsigned int value; +} cuParamSeti_params; + +typedef struct cuParamSetf_params_st { + CUfunction hfunc; + int offset; + float value; +} cuParamSetf_params; + +typedef struct cuParamSetv_params_st { + CUfunction hfunc; + int offset; + void *ptr; + unsigned int numbytes; +} cuParamSetv_params; + +typedef struct cuLaunch_params_st { + CUfunction f; +} cuLaunch_params; + +typedef struct cuLaunchGrid_params_st { + CUfunction f; + int grid_width; + int grid_height; +} cuLaunchGrid_params; + +typedef struct cuLaunchGridAsync_params_st { + CUfunction f; + int grid_width; + int grid_height; + CUstream hStream; +} cuLaunchGridAsync_params; + +typedef struct cuParamSetTexRef_params_st { + CUfunction hfunc; + int texunit; + CUtexref hTexRef; +} cuParamSetTexRef_params; + +typedef struct cuFuncSetSharedMemConfig_params_st { + CUfunction hfunc; + CUsharedconfig config; +} cuFuncSetSharedMemConfig_params; + +typedef struct cuGraphCreate_params_st { + CUgraph *phGraph; + unsigned int flags; +} cuGraphCreate_params; + +typedef struct cuGraphAddKernelNode_v2_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + const CUDA_KERNEL_NODE_PARAMS *nodeParams; +} cuGraphAddKernelNode_v2_params; + +typedef struct cuGraphKernelNodeGetParams_v2_params_st { + CUgraphNode hNode; + CUDA_KERNEL_NODE_PARAMS *nodeParams; +} cuGraphKernelNodeGetParams_v2_params; + +typedef struct cuGraphKernelNodeSetParams_v2_params_st { + CUgraphNode hNode; + const CUDA_KERNEL_NODE_PARAMS *nodeParams; +} cuGraphKernelNodeSetParams_v2_params; + +typedef struct cuGraphAddMemcpyNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + const CUDA_MEMCPY3D *copyParams; + CUcontext ctx; +} cuGraphAddMemcpyNode_params; + +typedef struct cuGraphMemcpyNodeGetParams_params_st { + CUgraphNode hNode; + CUDA_MEMCPY3D *nodeParams; +} cuGraphMemcpyNodeGetParams_params; + +typedef struct cuGraphMemcpyNodeSetParams_params_st { + CUgraphNode hNode; + const CUDA_MEMCPY3D *nodeParams; +} cuGraphMemcpyNodeSetParams_params; + +typedef struct cuGraphAddMemsetNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + const CUDA_MEMSET_NODE_PARAMS *memsetParams; + CUcontext ctx; +} cuGraphAddMemsetNode_params; + +typedef struct cuGraphMemsetNodeGetParams_params_st { + CUgraphNode hNode; + CUDA_MEMSET_NODE_PARAMS *nodeParams; +} cuGraphMemsetNodeGetParams_params; + +typedef struct cuGraphMemsetNodeSetParams_params_st { + CUgraphNode hNode; + const CUDA_MEMSET_NODE_PARAMS *nodeParams; +} cuGraphMemsetNodeSetParams_params; + +typedef struct cuGraphAddHostNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + const CUDA_HOST_NODE_PARAMS *nodeParams; +} cuGraphAddHostNode_params; + +typedef struct cuGraphHostNodeGetParams_params_st { + CUgraphNode hNode; + CUDA_HOST_NODE_PARAMS *nodeParams; +} cuGraphHostNodeGetParams_params; + +typedef struct cuGraphHostNodeSetParams_params_st { + CUgraphNode hNode; + const CUDA_HOST_NODE_PARAMS *nodeParams; +} cuGraphHostNodeSetParams_params; + +typedef struct cuGraphAddChildGraphNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + CUgraph childGraph; +} cuGraphAddChildGraphNode_params; + +typedef struct cuGraphChildGraphNodeGetGraph_params_st { + CUgraphNode hNode; + CUgraph *phGraph; +} cuGraphChildGraphNodeGetGraph_params; + +typedef struct cuGraphAddEmptyNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; +} cuGraphAddEmptyNode_params; + +typedef struct cuGraphAddEventRecordNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + CUevent event; +} cuGraphAddEventRecordNode_params; + +typedef struct cuGraphEventRecordNodeGetEvent_params_st { + CUgraphNode hNode; + CUevent *event_out; +} cuGraphEventRecordNodeGetEvent_params; + +typedef struct cuGraphEventRecordNodeSetEvent_params_st { + CUgraphNode hNode; + CUevent event; +} cuGraphEventRecordNodeSetEvent_params; + +typedef struct cuGraphAddEventWaitNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + CUevent event; +} cuGraphAddEventWaitNode_params; + +typedef struct cuGraphEventWaitNodeGetEvent_params_st { + CUgraphNode hNode; + CUevent *event_out; +} cuGraphEventWaitNodeGetEvent_params; + +typedef struct cuGraphEventWaitNodeSetEvent_params_st { + CUgraphNode hNode; + CUevent event; +} cuGraphEventWaitNodeSetEvent_params; + +typedef struct cuGraphAddExternalSemaphoresSignalNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + const CUDA_EXT_SEM_SIGNAL_NODE_PARAMS *nodeParams; +} cuGraphAddExternalSemaphoresSignalNode_params; + +typedef struct cuGraphExternalSemaphoresSignalNodeGetParams_params_st { + CUgraphNode hNode; + CUDA_EXT_SEM_SIGNAL_NODE_PARAMS *params_out; +} cuGraphExternalSemaphoresSignalNodeGetParams_params; + +typedef struct cuGraphExternalSemaphoresSignalNodeSetParams_params_st { + CUgraphNode hNode; + const CUDA_EXT_SEM_SIGNAL_NODE_PARAMS *nodeParams; +} cuGraphExternalSemaphoresSignalNodeSetParams_params; + +typedef struct cuGraphAddExternalSemaphoresWaitNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + const CUDA_EXT_SEM_WAIT_NODE_PARAMS *nodeParams; +} cuGraphAddExternalSemaphoresWaitNode_params; + +typedef struct cuGraphExternalSemaphoresWaitNodeGetParams_params_st { + CUgraphNode hNode; + CUDA_EXT_SEM_WAIT_NODE_PARAMS *params_out; +} cuGraphExternalSemaphoresWaitNodeGetParams_params; + +typedef struct cuGraphExternalSemaphoresWaitNodeSetParams_params_st { + CUgraphNode hNode; + const CUDA_EXT_SEM_WAIT_NODE_PARAMS *nodeParams; +} cuGraphExternalSemaphoresWaitNodeSetParams_params; + +typedef struct cuGraphAddBatchMemOpNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + const CUDA_BATCH_MEM_OP_NODE_PARAMS *nodeParams; +} cuGraphAddBatchMemOpNode_params; + +typedef struct cuGraphBatchMemOpNodeGetParams_params_st { + CUgraphNode hNode; + CUDA_BATCH_MEM_OP_NODE_PARAMS *nodeParams_out; +} cuGraphBatchMemOpNodeGetParams_params; + +typedef struct cuGraphBatchMemOpNodeSetParams_params_st { + CUgraphNode hNode; + const CUDA_BATCH_MEM_OP_NODE_PARAMS *nodeParams; +} cuGraphBatchMemOpNodeSetParams_params; + +typedef struct cuGraphExecBatchMemOpNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + const CUDA_BATCH_MEM_OP_NODE_PARAMS *nodeParams; +} cuGraphExecBatchMemOpNodeSetParams_params; + +typedef struct cuGraphAddMemAllocNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + CUDA_MEM_ALLOC_NODE_PARAMS *nodeParams; +} cuGraphAddMemAllocNode_params; + +typedef struct cuGraphMemAllocNodeGetParams_params_st { + CUgraphNode hNode; + CUDA_MEM_ALLOC_NODE_PARAMS *params_out; +} cuGraphMemAllocNodeGetParams_params; + +typedef struct cuGraphAddMemFreeNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + CUdeviceptr dptr; +} cuGraphAddMemFreeNode_params; + +typedef struct cuGraphMemFreeNodeGetParams_params_st { + CUgraphNode hNode; + CUdeviceptr *dptr_out; +} cuGraphMemFreeNodeGetParams_params; + +typedef struct cuDeviceGraphMemTrim_params_st { + CUdevice device; +} cuDeviceGraphMemTrim_params; + +typedef struct cuDeviceGetGraphMemAttribute_params_st { + CUdevice device; + CUgraphMem_attribute attr; + void *value; +} cuDeviceGetGraphMemAttribute_params; + +typedef struct cuDeviceSetGraphMemAttribute_params_st { + CUdevice device; + CUgraphMem_attribute attr; + void *value; +} cuDeviceSetGraphMemAttribute_params; + +typedef struct cuGraphClone_params_st { + CUgraph *phGraphClone; + CUgraph originalGraph; +} cuGraphClone_params; + +typedef struct cuGraphNodeFindInClone_params_st { + CUgraphNode *phNode; + CUgraphNode hOriginalNode; + CUgraph hClonedGraph; +} cuGraphNodeFindInClone_params; + +typedef struct cuGraphNodeGetType_params_st { + CUgraphNode hNode; + CUgraphNodeType *type; +} cuGraphNodeGetType_params; + +typedef struct cuGraphGetNodes_params_st { + CUgraph hGraph; + CUgraphNode *nodes; + size_t *numNodes; +} cuGraphGetNodes_params; + +typedef struct cuGraphGetRootNodes_params_st { + CUgraph hGraph; + CUgraphNode *rootNodes; + size_t *numRootNodes; +} cuGraphGetRootNodes_params; + +typedef struct cuGraphGetEdges_params_st { + CUgraph hGraph; + CUgraphNode *from; + CUgraphNode *to; + size_t *numEdges; +} cuGraphGetEdges_params; + +typedef struct cuGraphGetEdges_v2_params_st { + CUgraph hGraph; + CUgraphNode *from; + CUgraphNode *to; + CUgraphEdgeData *edgeData; + size_t *numEdges; +} cuGraphGetEdges_v2_params; + +typedef struct cuGraphNodeGetDependencies_params_st { + CUgraphNode hNode; + CUgraphNode *dependencies; + size_t *numDependencies; +} cuGraphNodeGetDependencies_params; + +typedef struct cuGraphNodeGetDependencies_v2_params_st { + CUgraphNode hNode; + CUgraphNode *dependencies; + CUgraphEdgeData *edgeData; + size_t *numDependencies; +} cuGraphNodeGetDependencies_v2_params; + +typedef struct cuGraphNodeGetDependentNodes_params_st { + CUgraphNode hNode; + CUgraphNode *dependentNodes; + size_t *numDependentNodes; +} cuGraphNodeGetDependentNodes_params; + +typedef struct cuGraphNodeGetDependentNodes_v2_params_st { + CUgraphNode hNode; + CUgraphNode *dependentNodes; + CUgraphEdgeData *edgeData; + size_t *numDependentNodes; +} cuGraphNodeGetDependentNodes_v2_params; + +typedef struct cuGraphAddDependencies_params_st { + CUgraph hGraph; + const CUgraphNode *from; + const CUgraphNode *to; + size_t numDependencies; +} cuGraphAddDependencies_params; + +typedef struct cuGraphAddDependencies_v2_params_st { + CUgraph hGraph; + const CUgraphNode *from; + const CUgraphNode *to; + const CUgraphEdgeData *edgeData; + size_t numDependencies; +} cuGraphAddDependencies_v2_params; + +typedef struct cuGraphRemoveDependencies_params_st { + CUgraph hGraph; + const CUgraphNode *from; + const CUgraphNode *to; + size_t numDependencies; +} cuGraphRemoveDependencies_params; + +typedef struct cuGraphRemoveDependencies_v2_params_st { + CUgraph hGraph; + const CUgraphNode *from; + const CUgraphNode *to; + const CUgraphEdgeData *edgeData; + size_t numDependencies; +} cuGraphRemoveDependencies_v2_params; + +typedef struct cuGraphDestroyNode_params_st { + CUgraphNode hNode; +} cuGraphDestroyNode_params; + +typedef struct cuGraphInstantiateWithFlags_params_st { + CUgraphExec *phGraphExec; + CUgraph hGraph; + unsigned long long flags; +} cuGraphInstantiateWithFlags_params; + +typedef struct cuGraphInstantiateWithParams_ptsz_params_st { + CUgraphExec *phGraphExec; + CUgraph hGraph; + CUDA_GRAPH_INSTANTIATE_PARAMS *instantiateParams; +} cuGraphInstantiateWithParams_ptsz_params; + +typedef struct cuGraphExecGetFlags_params_st { + CUgraphExec hGraphExec; + cuuint64_t *flags; +} cuGraphExecGetFlags_params; + +typedef struct cuGraphExecKernelNodeSetParams_v2_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + const CUDA_KERNEL_NODE_PARAMS *nodeParams; +} cuGraphExecKernelNodeSetParams_v2_params; + +typedef struct cuGraphExecMemcpyNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + const CUDA_MEMCPY3D *copyParams; + CUcontext ctx; +} cuGraphExecMemcpyNodeSetParams_params; + +typedef struct cuGraphExecMemsetNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + const CUDA_MEMSET_NODE_PARAMS *memsetParams; + CUcontext ctx; +} cuGraphExecMemsetNodeSetParams_params; + +typedef struct cuGraphExecHostNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + const CUDA_HOST_NODE_PARAMS *nodeParams; +} cuGraphExecHostNodeSetParams_params; + +typedef struct cuGraphExecChildGraphNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + CUgraph childGraph; +} cuGraphExecChildGraphNodeSetParams_params; + +typedef struct cuGraphExecEventRecordNodeSetEvent_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + CUevent event; +} cuGraphExecEventRecordNodeSetEvent_params; + +typedef struct cuGraphExecEventWaitNodeSetEvent_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + CUevent event; +} cuGraphExecEventWaitNodeSetEvent_params; + +typedef struct cuGraphExecExternalSemaphoresSignalNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + const CUDA_EXT_SEM_SIGNAL_NODE_PARAMS *nodeParams; +} cuGraphExecExternalSemaphoresSignalNodeSetParams_params; + +typedef struct cuGraphExecExternalSemaphoresWaitNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + const CUDA_EXT_SEM_WAIT_NODE_PARAMS *nodeParams; +} cuGraphExecExternalSemaphoresWaitNodeSetParams_params; + +typedef struct cuGraphNodeSetEnabled_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + unsigned int isEnabled; +} cuGraphNodeSetEnabled_params; + +typedef struct cuGraphNodeGetEnabled_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + unsigned int *isEnabled; +} cuGraphNodeGetEnabled_params; + +typedef struct cuGraphUpload_ptsz_params_st { + CUgraphExec hGraphExec; + CUstream hStream; +} cuGraphUpload_ptsz_params; + +typedef struct cuGraphLaunch_ptsz_params_st { + CUgraphExec hGraphExec; + CUstream hStream; +} cuGraphLaunch_ptsz_params; + +typedef struct cuGraphExecDestroy_params_st { + CUgraphExec hGraphExec; +} cuGraphExecDestroy_params; + +typedef struct cuGraphDestroy_params_st { + CUgraph hGraph; +} cuGraphDestroy_params; + +typedef struct cuGraphExecUpdate_v2_params_st { + CUgraphExec hGraphExec; + CUgraph hGraph; + CUgraphExecUpdateResultInfo *resultInfo; +} cuGraphExecUpdate_v2_params; + +typedef struct cuGraphKernelNodeCopyAttributes_params_st { + CUgraphNode dst; + CUgraphNode src; +} cuGraphKernelNodeCopyAttributes_params; + +typedef struct cuGraphKernelNodeGetAttribute_params_st { + CUgraphNode hNode; + CUkernelNodeAttrID attr; + CUkernelNodeAttrValue *value_out; +} cuGraphKernelNodeGetAttribute_params; + +typedef struct cuGraphKernelNodeSetAttribute_params_st { + CUgraphNode hNode; + CUkernelNodeAttrID attr; + const CUkernelNodeAttrValue *value; +} cuGraphKernelNodeSetAttribute_params; + +typedef struct cuGraphDebugDotPrint_params_st { + CUgraph hGraph; + const char *path; + unsigned int flags; +} cuGraphDebugDotPrint_params; + +typedef struct cuUserObjectCreate_params_st { + CUuserObject *object_out; + void *ptr; + CUhostFn destroy; + unsigned int initialRefcount; + unsigned int flags; +} cuUserObjectCreate_params; + +typedef struct cuUserObjectRetain_params_st { + CUuserObject object; + unsigned int count; +} cuUserObjectRetain_params; + +typedef struct cuUserObjectRelease_params_st { + CUuserObject object; + unsigned int count; +} cuUserObjectRelease_params; + +typedef struct cuGraphRetainUserObject_params_st { + CUgraph graph; + CUuserObject object; + unsigned int count; + unsigned int flags; +} cuGraphRetainUserObject_params; + +typedef struct cuGraphReleaseUserObject_params_st { + CUgraph graph; + CUuserObject object; + unsigned int count; +} cuGraphReleaseUserObject_params; + +typedef struct cuGraphAddNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + CUgraphNodeParams *nodeParams; +} cuGraphAddNode_params; + +typedef struct cuGraphAddNode_v2_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + const CUgraphEdgeData *dependencyData; + size_t numDependencies; + CUgraphNodeParams *nodeParams; +} cuGraphAddNode_v2_params; + +typedef struct cuGraphNodeSetParams_params_st { + CUgraphNode hNode; + CUgraphNodeParams *nodeParams; +} cuGraphNodeSetParams_params; + +typedef struct cuGraphExecNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + CUgraphNodeParams *nodeParams; +} cuGraphExecNodeSetParams_params; + +typedef struct cuGraphConditionalHandleCreate_params_st { + CUgraphConditionalHandle *pHandle_out; + CUgraph hGraph; + CUcontext ctx; + unsigned int defaultLaunchValue; + unsigned int flags; +} cuGraphConditionalHandleCreate_params; + +typedef struct cuOccupancyMaxActiveBlocksPerMultiprocessor_params_st { + int *numBlocks; + CUfunction func; + int blockSize; + size_t dynamicSMemSize; +} cuOccupancyMaxActiveBlocksPerMultiprocessor_params; + +typedef struct cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags_params_st { + int *numBlocks; + CUfunction func; + int blockSize; + size_t dynamicSMemSize; + unsigned int flags; +} cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags_params; + +typedef struct cuOccupancyMaxPotentialBlockSize_params_st { + int *minGridSize; + int *blockSize; + CUfunction func; + CUoccupancyB2DSize blockSizeToDynamicSMemSize; + size_t dynamicSMemSize; + int blockSizeLimit; +} cuOccupancyMaxPotentialBlockSize_params; + +typedef struct cuOccupancyMaxPotentialBlockSizeWithFlags_params_st { + int *minGridSize; + int *blockSize; + CUfunction func; + CUoccupancyB2DSize blockSizeToDynamicSMemSize; + size_t dynamicSMemSize; + int blockSizeLimit; + unsigned int flags; +} cuOccupancyMaxPotentialBlockSizeWithFlags_params; + +typedef struct cuOccupancyAvailableDynamicSMemPerBlock_params_st { + size_t *dynamicSmemSize; + CUfunction func; + int numBlocks; + int blockSize; +} cuOccupancyAvailableDynamicSMemPerBlock_params; + +typedef struct cuOccupancyMaxPotentialClusterSize_params_st { + int *clusterSize; + CUfunction func; + const CUlaunchConfig *config; +} cuOccupancyMaxPotentialClusterSize_params; + +typedef struct cuOccupancyMaxActiveClusters_params_st { + int *numClusters; + CUfunction func; + const CUlaunchConfig *config; +} cuOccupancyMaxActiveClusters_params; + +typedef struct cuTexRefSetArray_params_st { + CUtexref hTexRef; + CUarray hArray; + unsigned int Flags; +} cuTexRefSetArray_params; + +typedef struct cuTexRefSetMipmappedArray_params_st { + CUtexref hTexRef; + CUmipmappedArray hMipmappedArray; + unsigned int Flags; +} cuTexRefSetMipmappedArray_params; + +typedef struct cuTexRefSetAddress_v2_params_st { + size_t *ByteOffset; + CUtexref hTexRef; + CUdeviceptr dptr; + size_t bytes; +} cuTexRefSetAddress_v2_params; + +typedef struct cuTexRefSetAddress2D_v3_params_st { + CUtexref hTexRef; + const CUDA_ARRAY_DESCRIPTOR *desc; + CUdeviceptr dptr; + size_t Pitch; +} cuTexRefSetAddress2D_v3_params; + +typedef struct cuTexRefSetFormat_params_st { + CUtexref hTexRef; + CUarray_format fmt; + int NumPackedComponents; +} cuTexRefSetFormat_params; + +typedef struct cuTexRefSetAddressMode_params_st { + CUtexref hTexRef; + int dim; + CUaddress_mode am; +} cuTexRefSetAddressMode_params; + +typedef struct cuTexRefSetFilterMode_params_st { + CUtexref hTexRef; + CUfilter_mode fm; +} cuTexRefSetFilterMode_params; + +typedef struct cuTexRefSetMipmapFilterMode_params_st { + CUtexref hTexRef; + CUfilter_mode fm; +} cuTexRefSetMipmapFilterMode_params; + +typedef struct cuTexRefSetMipmapLevelBias_params_st { + CUtexref hTexRef; + float bias; +} cuTexRefSetMipmapLevelBias_params; + +typedef struct cuTexRefSetMipmapLevelClamp_params_st { + CUtexref hTexRef; + float minMipmapLevelClamp; + float maxMipmapLevelClamp; +} cuTexRefSetMipmapLevelClamp_params; + +typedef struct cuTexRefSetMaxAnisotropy_params_st { + CUtexref hTexRef; + unsigned int maxAniso; +} cuTexRefSetMaxAnisotropy_params; + +typedef struct cuTexRefSetBorderColor_params_st { + CUtexref hTexRef; + float *pBorderColor; +} cuTexRefSetBorderColor_params; + +typedef struct cuTexRefSetFlags_params_st { + CUtexref hTexRef; + unsigned int Flags; +} cuTexRefSetFlags_params; + +typedef struct cuTexRefGetAddress_v2_params_st { + CUdeviceptr *pdptr; + CUtexref hTexRef; +} cuTexRefGetAddress_v2_params; + +typedef struct cuTexRefGetArray_params_st { + CUarray *phArray; + CUtexref hTexRef; +} cuTexRefGetArray_params; + +typedef struct cuTexRefGetMipmappedArray_params_st { + CUmipmappedArray *phMipmappedArray; + CUtexref hTexRef; +} cuTexRefGetMipmappedArray_params; + +typedef struct cuTexRefGetAddressMode_params_st { + CUaddress_mode *pam; + CUtexref hTexRef; + int dim; +} cuTexRefGetAddressMode_params; + +typedef struct cuTexRefGetFilterMode_params_st { + CUfilter_mode *pfm; + CUtexref hTexRef; +} cuTexRefGetFilterMode_params; + +typedef struct cuTexRefGetFormat_params_st { + CUarray_format *pFormat; + int *pNumChannels; + CUtexref hTexRef; +} cuTexRefGetFormat_params; + +typedef struct cuTexRefGetMipmapFilterMode_params_st { + CUfilter_mode *pfm; + CUtexref hTexRef; +} cuTexRefGetMipmapFilterMode_params; + +typedef struct cuTexRefGetMipmapLevelBias_params_st { + float *pbias; + CUtexref hTexRef; +} cuTexRefGetMipmapLevelBias_params; + +typedef struct cuTexRefGetMipmapLevelClamp_params_st { + float *pminMipmapLevelClamp; + float *pmaxMipmapLevelClamp; + CUtexref hTexRef; +} cuTexRefGetMipmapLevelClamp_params; + +typedef struct cuTexRefGetMaxAnisotropy_params_st { + int *pmaxAniso; + CUtexref hTexRef; +} cuTexRefGetMaxAnisotropy_params; + +typedef struct cuTexRefGetBorderColor_params_st { + float *pBorderColor; + CUtexref hTexRef; +} cuTexRefGetBorderColor_params; + +typedef struct cuTexRefGetFlags_params_st { + unsigned int *pFlags; + CUtexref hTexRef; +} cuTexRefGetFlags_params; + +typedef struct cuTexRefCreate_params_st { + CUtexref *pTexRef; +} cuTexRefCreate_params; + +typedef struct cuTexRefDestroy_params_st { + CUtexref hTexRef; +} cuTexRefDestroy_params; + +typedef struct cuSurfRefSetArray_params_st { + CUsurfref hSurfRef; + CUarray hArray; + unsigned int Flags; +} cuSurfRefSetArray_params; + +typedef struct cuSurfRefGetArray_params_st { + CUarray *phArray; + CUsurfref hSurfRef; +} cuSurfRefGetArray_params; + +typedef struct cuTexObjectCreate_params_st { + CUtexObject *pTexObject; + const CUDA_RESOURCE_DESC *pResDesc; + const CUDA_TEXTURE_DESC *pTexDesc; + const CUDA_RESOURCE_VIEW_DESC *pResViewDesc; +} cuTexObjectCreate_params; + +typedef struct cuTexObjectDestroy_params_st { + CUtexObject texObject; +} cuTexObjectDestroy_params; + +typedef struct cuTexObjectGetResourceDesc_params_st { + CUDA_RESOURCE_DESC *pResDesc; + CUtexObject texObject; +} cuTexObjectGetResourceDesc_params; + +typedef struct cuTexObjectGetTextureDesc_params_st { + CUDA_TEXTURE_DESC *pTexDesc; + CUtexObject texObject; +} cuTexObjectGetTextureDesc_params; + +typedef struct cuTexObjectGetResourceViewDesc_params_st { + CUDA_RESOURCE_VIEW_DESC *pResViewDesc; + CUtexObject texObject; +} cuTexObjectGetResourceViewDesc_params; + +typedef struct cuSurfObjectCreate_params_st { + CUsurfObject *pSurfObject; + const CUDA_RESOURCE_DESC *pResDesc; +} cuSurfObjectCreate_params; + +typedef struct cuSurfObjectDestroy_params_st { + CUsurfObject surfObject; +} cuSurfObjectDestroy_params; + +typedef struct cuSurfObjectGetResourceDesc_params_st { + CUDA_RESOURCE_DESC *pResDesc; + CUsurfObject surfObject; +} cuSurfObjectGetResourceDesc_params; + +typedef struct cuTensorMapEncodeTiled_params_st { + CUtensorMap *tensorMap; + CUtensorMapDataType tensorDataType; + cuuint32_t tensorRank; + void *globalAddress; + const cuuint64_t *globalDim; + const cuuint64_t *globalStrides; + const cuuint32_t *boxDim; + const cuuint32_t *elementStrides; + CUtensorMapInterleave interleave; + CUtensorMapSwizzle swizzle; + CUtensorMapL2promotion l2Promotion; + CUtensorMapFloatOOBfill oobFill; +} cuTensorMapEncodeTiled_params; + +typedef struct cuTensorMapEncodeIm2col_params_st { + CUtensorMap *tensorMap; + CUtensorMapDataType tensorDataType; + cuuint32_t tensorRank; + void *globalAddress; + const cuuint64_t *globalDim; + const cuuint64_t *globalStrides; + const int *pixelBoxLowerCorner; + const int *pixelBoxUpperCorner; + cuuint32_t channelsPerPixel; + cuuint32_t pixelsPerColumn; + const cuuint32_t *elementStrides; + CUtensorMapInterleave interleave; + CUtensorMapSwizzle swizzle; + CUtensorMapL2promotion l2Promotion; + CUtensorMapFloatOOBfill oobFill; +} cuTensorMapEncodeIm2col_params; + +typedef struct cuTensorMapReplaceAddress_params_st { + CUtensorMap *tensorMap; + void *globalAddress; +} cuTensorMapReplaceAddress_params; + +typedef struct cuDeviceCanAccessPeer_params_st { + int *canAccessPeer; + CUdevice dev; + CUdevice peerDev; +} cuDeviceCanAccessPeer_params; + +typedef struct cuCtxEnablePeerAccess_params_st { + CUcontext peerContext; + unsigned int Flags; +} cuCtxEnablePeerAccess_params; + +typedef struct cuCtxDisablePeerAccess_params_st { + CUcontext peerContext; +} cuCtxDisablePeerAccess_params; + +typedef struct cuDeviceGetP2PAttribute_params_st { + int *value; + CUdevice_P2PAttribute attrib; + CUdevice srcDevice; + CUdevice dstDevice; +} cuDeviceGetP2PAttribute_params; + +typedef struct cuGraphicsUnregisterResource_params_st { + CUgraphicsResource resource; +} cuGraphicsUnregisterResource_params; + +typedef struct cuGraphicsSubResourceGetMappedArray_params_st { + CUarray *pArray; + CUgraphicsResource resource; + unsigned int arrayIndex; + unsigned int mipLevel; +} cuGraphicsSubResourceGetMappedArray_params; + +typedef struct cuGraphicsResourceGetMappedMipmappedArray_params_st { + CUmipmappedArray *pMipmappedArray; + CUgraphicsResource resource; +} cuGraphicsResourceGetMappedMipmappedArray_params; + +typedef struct cuGraphicsResourceGetMappedPointer_v2_params_st { + CUdeviceptr *pDevPtr; + size_t *pSize; + CUgraphicsResource resource; +} cuGraphicsResourceGetMappedPointer_v2_params; + +typedef struct cuGraphicsResourceSetMapFlags_v2_params_st { + CUgraphicsResource resource; + unsigned int flags; +} cuGraphicsResourceSetMapFlags_v2_params; + +typedef struct cuGraphicsMapResources_ptsz_params_st { + unsigned int count; + CUgraphicsResource *resources; + CUstream hStream; +} cuGraphicsMapResources_ptsz_params; + +typedef struct cuGraphicsUnmapResources_ptsz_params_st { + unsigned int count; + CUgraphicsResource *resources; + CUstream hStream; +} cuGraphicsUnmapResources_ptsz_params; + +typedef struct cuGetProcAddress_v2_params_st { + const char *symbol; + void **pfn; + int cudaVersion; + cuuint64_t flags; + CUdriverProcAddressQueryResult *symbolStatus; +} cuGetProcAddress_v2_params; + +typedef struct cuCoredumpGetAttribute_params_st { + CUcoredumpSettings attrib; + void *value; + size_t *size; +} cuCoredumpGetAttribute_params; + +typedef struct cuCoredumpGetAttributeGlobal_params_st { + CUcoredumpSettings attrib; + void *value; + size_t *size; +} cuCoredumpGetAttributeGlobal_params; + +typedef struct cuCoredumpSetAttribute_params_st { + CUcoredumpSettings attrib; + void *value; + size_t *size; +} cuCoredumpSetAttribute_params; + +typedef struct cuCoredumpSetAttributeGlobal_params_st { + CUcoredumpSettings attrib; + void *value; + size_t *size; +} cuCoredumpSetAttributeGlobal_params; + +typedef struct cuGetExportTable_params_st { + const void **ppExportTable; + const CUuuid *pExportTableId; +} cuGetExportTable_params; + +typedef struct cuGreenCtxCreate_params_st { + CUgreenCtx *phCtx; + CUdevResourceDesc desc; + CUdevice dev; + unsigned int flags; +} cuGreenCtxCreate_params; + +typedef struct cuGreenCtxDestroy_params_st { + CUgreenCtx hCtx; +} cuGreenCtxDestroy_params; + +typedef struct cuCtxFromGreenCtx_params_st { + CUcontext *pContext; + CUgreenCtx hCtx; +} cuCtxFromGreenCtx_params; + +typedef struct cuDeviceGetDevResource_params_st { + CUdevice device; + CUdevResource *resource; + CUdevResourceType type; +} cuDeviceGetDevResource_params; + +typedef struct cuCtxGetDevResource_params_st { + CUcontext hCtx; + CUdevResource *resource; + CUdevResourceType type; +} cuCtxGetDevResource_params; + +typedef struct cuGreenCtxGetDevResource_params_st { + CUgreenCtx hCtx; + CUdevResource *resource; + CUdevResourceType type; +} cuGreenCtxGetDevResource_params; + +typedef struct cuDevSmResourceSplitByCount_params_st { + CUdevResource *result; + unsigned int *nbGroups; + const CUdevResource *input; + CUdevResource *remaining; + unsigned int useFlags; + unsigned int minCount; +} cuDevSmResourceSplitByCount_params; + +typedef struct cuDevResourceGenerateDesc_params_st { + CUdevResourceDesc *phDesc; + CUdevResource *resources; + unsigned int nbResources; +} cuDevResourceGenerateDesc_params; + +typedef struct cuGreenCtxRecordEvent_params_st { + CUgreenCtx hCtx; + CUevent hEvent; +} cuGreenCtxRecordEvent_params; + +typedef struct cuGreenCtxWaitEvent_params_st { + CUgreenCtx hCtx; + CUevent hEvent; +} cuGreenCtxWaitEvent_params; + +typedef struct cuStreamGetGreenCtx_params_st { + CUstream hStream; + CUgreenCtx *phCtx; +} cuStreamGetGreenCtx_params; + +typedef struct cuGreenCtxStreamCreate_params_st { + CUstream *phStream; + CUgreenCtx greenCtx; + unsigned int flags; + int priority; +} cuGreenCtxStreamCreate_params; + +typedef struct cuMemHostRegister_params_st { + void *p; + size_t bytesize; + unsigned int Flags; +} cuMemHostRegister_params; + +typedef struct cuGraphicsResourceSetMapFlags_params_st { + CUgraphicsResource resource; + unsigned int flags; +} cuGraphicsResourceSetMapFlags_params; + +typedef struct cuLinkCreate_params_st { + unsigned int numOptions; + CUjit_option *options; + void **optionValues; + CUlinkState *stateOut; +} cuLinkCreate_params; + +typedef struct cuLinkAddData_params_st { + CUlinkState state; + CUjitInputType type; + void *data; + size_t size; + const char *name; + unsigned int numOptions; + CUjit_option *options; + void **optionValues; +} cuLinkAddData_params; + +typedef struct cuLinkAddFile_params_st { + CUlinkState state; + CUjitInputType type; + const char *path; + unsigned int numOptions; + CUjit_option *options; + void **optionValues; +} cuLinkAddFile_params; + +typedef struct cuTexRefSetAddress2D_v2_params_st { + CUtexref hTexRef; + const CUDA_ARRAY_DESCRIPTOR *desc; + CUdeviceptr dptr; + size_t Pitch; +} cuTexRefSetAddress2D_v2_params; + +typedef struct cuDeviceTotalMem_params_st { + unsigned int *bytes; + CUdevice dev; +} cuDeviceTotalMem_params; + +typedef struct cuCtxCreate_params_st { + CUcontext *pctx; + unsigned int flags; + CUdevice dev; +} cuCtxCreate_params; + +typedef struct cuModuleGetGlobal_params_st { + CUdeviceptr_v1 *dptr; + unsigned int *bytes; + CUmodule hmod; + const char *name; +} cuModuleGetGlobal_params; + +typedef struct cuMemGetInfo_params_st { + unsigned int *free; + unsigned int *total; +} cuMemGetInfo_params; + +typedef struct cuMemAlloc_params_st { + CUdeviceptr_v1 *dptr; + unsigned int bytesize; +} cuMemAlloc_params; + +typedef struct cuMemAllocPitch_params_st { + CUdeviceptr_v1 *dptr; + unsigned int *pPitch; + unsigned int WidthInBytes; + unsigned int Height; + unsigned int ElementSizeBytes; +} cuMemAllocPitch_params; + +typedef struct cuMemFree_params_st { + CUdeviceptr_v1 dptr; +} cuMemFree_params; + +typedef struct cuMemGetAddressRange_params_st { + CUdeviceptr_v1 *pbase; + unsigned int *psize; + CUdeviceptr_v1 dptr; +} cuMemGetAddressRange_params; + +typedef struct cuMemAllocHost_params_st { + void **pp; + unsigned int bytesize; +} cuMemAllocHost_params; + +typedef struct cuMemHostGetDevicePointer_params_st { + CUdeviceptr_v1 *pdptr; + void *p; + unsigned int Flags; +} cuMemHostGetDevicePointer_params; + +typedef struct cuMemcpyHtoD_params_st { + CUdeviceptr_v1 dstDevice; + const void *srcHost; + unsigned int ByteCount; +} cuMemcpyHtoD_params; + +typedef struct cuMemcpyDtoH_params_st { + void *dstHost; + CUdeviceptr_v1 srcDevice; + unsigned int ByteCount; +} cuMemcpyDtoH_params; + +typedef struct cuMemcpyDtoD_params_st { + CUdeviceptr_v1 dstDevice; + CUdeviceptr_v1 srcDevice; + unsigned int ByteCount; +} cuMemcpyDtoD_params; + +typedef struct cuMemcpyDtoA_params_st { + CUarray dstArray; + unsigned int dstOffset; + CUdeviceptr_v1 srcDevice; + unsigned int ByteCount; +} cuMemcpyDtoA_params; + +typedef struct cuMemcpyAtoD_params_st { + CUdeviceptr_v1 dstDevice; + CUarray srcArray; + unsigned int srcOffset; + unsigned int ByteCount; +} cuMemcpyAtoD_params; + +typedef struct cuMemcpyHtoA_params_st { + CUarray dstArray; + unsigned int dstOffset; + const void *srcHost; + unsigned int ByteCount; +} cuMemcpyHtoA_params; + +typedef struct cuMemcpyAtoH_params_st { + void *dstHost; + CUarray srcArray; + unsigned int srcOffset; + unsigned int ByteCount; +} cuMemcpyAtoH_params; + +typedef struct cuMemcpyAtoA_params_st { + CUarray dstArray; + unsigned int dstOffset; + CUarray srcArray; + unsigned int srcOffset; + unsigned int ByteCount; +} cuMemcpyAtoA_params; + +typedef struct cuMemcpyHtoAAsync_params_st { + CUarray dstArray; + unsigned int dstOffset; + const void *srcHost; + unsigned int ByteCount; + CUstream hStream; +} cuMemcpyHtoAAsync_params; + +typedef struct cuMemcpyAtoHAsync_params_st { + void *dstHost; + CUarray srcArray; + unsigned int srcOffset; + unsigned int ByteCount; + CUstream hStream; +} cuMemcpyAtoHAsync_params; + +typedef struct cuMemcpy2D_params_st { + const CUDA_MEMCPY2D_v1 *pCopy; +} cuMemcpy2D_params; + +typedef struct cuMemcpy2DUnaligned_params_st { + const CUDA_MEMCPY2D_v1 *pCopy; +} cuMemcpy2DUnaligned_params; + +typedef struct cuMemcpy3D_params_st { + const CUDA_MEMCPY3D_v1 *pCopy; +} cuMemcpy3D_params; + +typedef struct cuMemcpyHtoDAsync_params_st { + CUdeviceptr_v1 dstDevice; + const void *srcHost; + unsigned int ByteCount; + CUstream hStream; +} cuMemcpyHtoDAsync_params; + +typedef struct cuMemcpyDtoHAsync_params_st { + void *dstHost; + CUdeviceptr_v1 srcDevice; + unsigned int ByteCount; + CUstream hStream; +} cuMemcpyDtoHAsync_params; + +typedef struct cuMemcpyDtoDAsync_params_st { + CUdeviceptr_v1 dstDevice; + CUdeviceptr_v1 srcDevice; + unsigned int ByteCount; + CUstream hStream; +} cuMemcpyDtoDAsync_params; + +typedef struct cuMemcpy2DAsync_params_st { + const CUDA_MEMCPY2D_v1 *pCopy; + CUstream hStream; +} cuMemcpy2DAsync_params; + +typedef struct cuMemcpy3DAsync_params_st { + const CUDA_MEMCPY3D_v1 *pCopy; + CUstream hStream; +} cuMemcpy3DAsync_params; + +typedef struct cuMemsetD8_params_st { + CUdeviceptr_v1 dstDevice; + unsigned char uc; + unsigned int N; +} cuMemsetD8_params; + +typedef struct cuMemsetD16_params_st { + CUdeviceptr_v1 dstDevice; + unsigned short us; + unsigned int N; +} cuMemsetD16_params; + +typedef struct cuMemsetD32_params_st { + CUdeviceptr_v1 dstDevice; + unsigned int ui; + unsigned int N; +} cuMemsetD32_params; + +typedef struct cuMemsetD2D8_params_st { + CUdeviceptr_v1 dstDevice; + unsigned int dstPitch; + unsigned char uc; + unsigned int Width; + unsigned int Height; +} cuMemsetD2D8_params; + +typedef struct cuMemsetD2D16_params_st { + CUdeviceptr_v1 dstDevice; + unsigned int dstPitch; + unsigned short us; + unsigned int Width; + unsigned int Height; +} cuMemsetD2D16_params; + +typedef struct cuMemsetD2D32_params_st { + CUdeviceptr_v1 dstDevice; + unsigned int dstPitch; + unsigned int ui; + unsigned int Width; + unsigned int Height; +} cuMemsetD2D32_params; + +typedef struct cuArrayCreate_params_st { + CUarray *pHandle; + const CUDA_ARRAY_DESCRIPTOR_v1 *pAllocateArray; +} cuArrayCreate_params; + +typedef struct cuArrayGetDescriptor_params_st { + CUDA_ARRAY_DESCRIPTOR_v1 *pArrayDescriptor; + CUarray hArray; +} cuArrayGetDescriptor_params; + +typedef struct cuArray3DCreate_params_st { + CUarray *pHandle; + const CUDA_ARRAY3D_DESCRIPTOR_v1 *pAllocateArray; +} cuArray3DCreate_params; + +typedef struct cuArray3DGetDescriptor_params_st { + CUDA_ARRAY3D_DESCRIPTOR_v1 *pArrayDescriptor; + CUarray hArray; +} cuArray3DGetDescriptor_params; + +typedef struct cuTexRefSetAddress_params_st { + unsigned int *ByteOffset; + CUtexref hTexRef; + CUdeviceptr_v1 dptr; + unsigned int bytes; +} cuTexRefSetAddress_params; + +typedef struct cuTexRefSetAddress2D_params_st { + CUtexref hTexRef; + const CUDA_ARRAY_DESCRIPTOR_v1 *desc; + CUdeviceptr_v1 dptr; + unsigned int Pitch; +} cuTexRefSetAddress2D_params; + +typedef struct cuTexRefGetAddress_params_st { + CUdeviceptr_v1 *pdptr; + CUtexref hTexRef; +} cuTexRefGetAddress_params; + +typedef struct cuGraphicsResourceGetMappedPointer_params_st { + CUdeviceptr_v1 *pDevPtr; + unsigned int *pSize; + CUgraphicsResource resource; +} cuGraphicsResourceGetMappedPointer_params; + +typedef struct cuCtxDestroy_params_st { + CUcontext ctx; +} cuCtxDestroy_params; + +typedef struct cuCtxPopCurrent_params_st { + CUcontext *pctx; +} cuCtxPopCurrent_params; + +typedef struct cuCtxPushCurrent_params_st { + CUcontext ctx; +} cuCtxPushCurrent_params; + +typedef struct cuStreamDestroy_params_st { + CUstream hStream; +} cuStreamDestroy_params; + +typedef struct cuEventDestroy_params_st { + CUevent hEvent; +} cuEventDestroy_params; + +typedef struct cuDevicePrimaryCtxRelease_params_st { + CUdevice dev; +} cuDevicePrimaryCtxRelease_params; + +typedef struct cuDevicePrimaryCtxReset_params_st { + CUdevice dev; +} cuDevicePrimaryCtxReset_params; + +typedef struct cuDevicePrimaryCtxSetFlags_params_st { + CUdevice dev; + unsigned int flags; +} cuDevicePrimaryCtxSetFlags_params; + +typedef struct cuMemcpyHtoD_v2_params_st { + CUdeviceptr dstDevice; + const void *srcHost; + size_t ByteCount; +} cuMemcpyHtoD_v2_params; + +typedef struct cuMemcpyDtoH_v2_params_st { + void *dstHost; + CUdeviceptr srcDevice; + size_t ByteCount; +} cuMemcpyDtoH_v2_params; + +typedef struct cuMemcpyDtoD_v2_params_st { + CUdeviceptr dstDevice; + CUdeviceptr srcDevice; + size_t ByteCount; +} cuMemcpyDtoD_v2_params; + +typedef struct cuMemcpyDtoA_v2_params_st { + CUarray dstArray; + size_t dstOffset; + CUdeviceptr srcDevice; + size_t ByteCount; +} cuMemcpyDtoA_v2_params; + +typedef struct cuMemcpyAtoD_v2_params_st { + CUdeviceptr dstDevice; + CUarray srcArray; + size_t srcOffset; + size_t ByteCount; +} cuMemcpyAtoD_v2_params; + +typedef struct cuMemcpyHtoA_v2_params_st { + CUarray dstArray; + size_t dstOffset; + const void *srcHost; + size_t ByteCount; +} cuMemcpyHtoA_v2_params; + +typedef struct cuMemcpyAtoH_v2_params_st { + void *dstHost; + CUarray srcArray; + size_t srcOffset; + size_t ByteCount; +} cuMemcpyAtoH_v2_params; + +typedef struct cuMemcpyAtoA_v2_params_st { + CUarray dstArray; + size_t dstOffset; + CUarray srcArray; + size_t srcOffset; + size_t ByteCount; +} cuMemcpyAtoA_v2_params; + +typedef struct cuMemcpyHtoAAsync_v2_params_st { + CUarray dstArray; + size_t dstOffset; + const void *srcHost; + size_t ByteCount; + CUstream hStream; +} cuMemcpyHtoAAsync_v2_params; + +typedef struct cuMemcpyAtoHAsync_v2_params_st { + void *dstHost; + CUarray srcArray; + size_t srcOffset; + size_t ByteCount; + CUstream hStream; +} cuMemcpyAtoHAsync_v2_params; + +typedef struct cuMemcpy2D_v2_params_st { + const CUDA_MEMCPY2D *pCopy; +} cuMemcpy2D_v2_params; + +typedef struct cuMemcpy2DUnaligned_v2_params_st { + const CUDA_MEMCPY2D *pCopy; +} cuMemcpy2DUnaligned_v2_params; + +typedef struct cuMemcpy3D_v2_params_st { + const CUDA_MEMCPY3D *pCopy; +} cuMemcpy3D_v2_params; + +typedef struct cuMemcpyHtoDAsync_v2_params_st { + CUdeviceptr dstDevice; + const void *srcHost; + size_t ByteCount; + CUstream hStream; +} cuMemcpyHtoDAsync_v2_params; + +typedef struct cuMemcpyDtoHAsync_v2_params_st { + void *dstHost; + CUdeviceptr srcDevice; + size_t ByteCount; + CUstream hStream; +} cuMemcpyDtoHAsync_v2_params; + +typedef struct cuMemcpyDtoDAsync_v2_params_st { + CUdeviceptr dstDevice; + CUdeviceptr srcDevice; + size_t ByteCount; + CUstream hStream; +} cuMemcpyDtoDAsync_v2_params; + +typedef struct cuMemcpy2DAsync_v2_params_st { + const CUDA_MEMCPY2D *pCopy; + CUstream hStream; +} cuMemcpy2DAsync_v2_params; + +typedef struct cuMemcpy3DAsync_v2_params_st { + const CUDA_MEMCPY3D *pCopy; + CUstream hStream; +} cuMemcpy3DAsync_v2_params; + +typedef struct cuMemsetD8_v2_params_st { + CUdeviceptr dstDevice; + unsigned char uc; + size_t N; +} cuMemsetD8_v2_params; + +typedef struct cuMemsetD16_v2_params_st { + CUdeviceptr dstDevice; + unsigned short us; + size_t N; +} cuMemsetD16_v2_params; + +typedef struct cuMemsetD32_v2_params_st { + CUdeviceptr dstDevice; + unsigned int ui; + size_t N; +} cuMemsetD32_v2_params; + +typedef struct cuMemsetD2D8_v2_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned char uc; + size_t Width; + size_t Height; +} cuMemsetD2D8_v2_params; + +typedef struct cuMemsetD2D16_v2_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned short us; + size_t Width; + size_t Height; +} cuMemsetD2D16_v2_params; + +typedef struct cuMemsetD2D32_v2_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned int ui; + size_t Width; + size_t Height; +} cuMemsetD2D32_v2_params; + +typedef struct cuMemcpy_params_st { + CUdeviceptr dst; + CUdeviceptr src; + size_t ByteCount; +} cuMemcpy_params; + +typedef struct cuMemcpyAsync_params_st { + CUdeviceptr dst; + CUdeviceptr src; + size_t ByteCount; + CUstream hStream; +} cuMemcpyAsync_params; + +typedef struct cuMemcpyPeer_params_st { + CUdeviceptr dstDevice; + CUcontext dstContext; + CUdeviceptr srcDevice; + CUcontext srcContext; + size_t ByteCount; +} cuMemcpyPeer_params; + +typedef struct cuMemcpyPeerAsync_params_st { + CUdeviceptr dstDevice; + CUcontext dstContext; + CUdeviceptr srcDevice; + CUcontext srcContext; + size_t ByteCount; + CUstream hStream; +} cuMemcpyPeerAsync_params; + +typedef struct cuMemcpy3DPeer_params_st { + const CUDA_MEMCPY3D_PEER *pCopy; +} cuMemcpy3DPeer_params; + +typedef struct cuMemcpy3DPeerAsync_params_st { + const CUDA_MEMCPY3D_PEER *pCopy; + CUstream hStream; +} cuMemcpy3DPeerAsync_params; + +typedef struct cuMemcpyBatchAsync_params_st { + CUdeviceptr *dsts; + CUdeviceptr *srcs; + size_t *sizes; + size_t count; + CUmemcpyAttributes *attrs; + size_t *attrsIdxs; + size_t numAttrs; + size_t *failIdx; + CUstream hStream; +} cuMemcpyBatchAsync_params; + +typedef struct cuMemcpy3DBatchAsync_params_st { + size_t numOps; + CUDA_MEMCPY3D_BATCH_OP *opList; + size_t *failIdx; + unsigned long long flags; + CUstream hStream; +} cuMemcpy3DBatchAsync_params; + +typedef struct cuMemsetD8Async_params_st { + CUdeviceptr dstDevice; + unsigned char uc; + size_t N; + CUstream hStream; +} cuMemsetD8Async_params; + +typedef struct cuMemsetD16Async_params_st { + CUdeviceptr dstDevice; + unsigned short us; + size_t N; + CUstream hStream; +} cuMemsetD16Async_params; + +typedef struct cuMemsetD32Async_params_st { + CUdeviceptr dstDevice; + unsigned int ui; + size_t N; + CUstream hStream; +} cuMemsetD32Async_params; + +typedef struct cuMemsetD2D8Async_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned char uc; + size_t Width; + size_t Height; + CUstream hStream; +} cuMemsetD2D8Async_params; + +typedef struct cuMemsetD2D16Async_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned short us; + size_t Width; + size_t Height; + CUstream hStream; +} cuMemsetD2D16Async_params; + +typedef struct cuMemsetD2D32Async_params_st { + CUdeviceptr dstDevice; + size_t dstPitch; + unsigned int ui; + size_t Width; + size_t Height; + CUstream hStream; +} cuMemsetD2D32Async_params; + +typedef struct cuStreamGetPriority_params_st { + CUstream hStream; + int *priority; +} cuStreamGetPriority_params; + +typedef struct cuStreamGetId_params_st { + CUstream hStream; + unsigned long long *streamId; +} cuStreamGetId_params; + +typedef struct cuStreamGetFlags_params_st { + CUstream hStream; + unsigned int *flags; +} cuStreamGetFlags_params; + +typedef struct cuStreamGetDevice_params_st { + CUstream hStream; + CUdevice *device; +} cuStreamGetDevice_params; + +typedef struct cuStreamGetCtx_params_st { + CUstream hStream; + CUcontext *pctx; +} cuStreamGetCtx_params; + +typedef struct cuStreamGetCtx_v2_params_st { + CUstream hStream; + CUcontext *pCtx; + CUgreenCtx *pGreenCtx; +} cuStreamGetCtx_v2_params; + +typedef struct cuStreamWaitEvent_params_st { + CUstream hStream; + CUevent hEvent; + unsigned int Flags; +} cuStreamWaitEvent_params; + +typedef struct cuStreamAddCallback_params_st { + CUstream hStream; + CUstreamCallback callback; + void *userData; + unsigned int flags; +} cuStreamAddCallback_params; + +typedef struct cuStreamAttachMemAsync_params_st { + CUstream hStream; + CUdeviceptr dptr; + size_t length; + unsigned int flags; +} cuStreamAttachMemAsync_params; + +typedef struct cuStreamQuery_params_st { + CUstream hStream; +} cuStreamQuery_params; + +typedef struct cuStreamSynchronize_params_st { + CUstream hStream; +} cuStreamSynchronize_params; + +typedef struct cuEventRecord_params_st { + CUevent hEvent; + CUstream hStream; +} cuEventRecord_params; + +typedef struct cuEventRecordWithFlags_params_st { + CUevent hEvent; + CUstream hStream; + unsigned int flags; +} cuEventRecordWithFlags_params; + +typedef struct cuLaunchKernel_params_st { + CUfunction f; + unsigned int gridDimX; + unsigned int gridDimY; + unsigned int gridDimZ; + unsigned int blockDimX; + unsigned int blockDimY; + unsigned int blockDimZ; + unsigned int sharedMemBytes; + CUstream hStream; + void **kernelParams; + void **extra; +} cuLaunchKernel_params; + +typedef struct cuLaunchKernelEx_params_st { + const CUlaunchConfig *config; + CUfunction f; + void **kernelParams; + void **extra; +} cuLaunchKernelEx_params; + +typedef struct cuLaunchHostFunc_params_st { + CUstream hStream; + CUhostFn fn; + void *userData; +} cuLaunchHostFunc_params; + +typedef struct cuGraphicsMapResources_params_st { + unsigned int count; + CUgraphicsResource *resources; + CUstream hStream; +} cuGraphicsMapResources_params; + +typedef struct cuGraphicsUnmapResources_params_st { + unsigned int count; + CUgraphicsResource *resources; + CUstream hStream; +} cuGraphicsUnmapResources_params; + +typedef struct cuStreamWriteValue32_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint32_t value; + unsigned int flags; +} cuStreamWriteValue32_params; + +typedef struct cuStreamWaitValue32_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint32_t value; + unsigned int flags; +} cuStreamWaitValue32_params; + +typedef struct cuStreamWriteValue64_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint64_t value; + unsigned int flags; +} cuStreamWriteValue64_params; + +typedef struct cuStreamWaitValue64_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint64_t value; + unsigned int flags; +} cuStreamWaitValue64_params; + +typedef struct cuStreamBatchMemOp_params_st { + CUstream stream; + unsigned int count; + CUstreamBatchMemOpParams *paramArray; + unsigned int flags; +} cuStreamBatchMemOp_params; + +typedef struct cuStreamWriteValue32_ptsz_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint32_t value; + unsigned int flags; +} cuStreamWriteValue32_ptsz_params; + +typedef struct cuStreamWaitValue32_ptsz_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint32_t value; + unsigned int flags; +} cuStreamWaitValue32_ptsz_params; + +typedef struct cuStreamWriteValue64_ptsz_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint64_t value; + unsigned int flags; +} cuStreamWriteValue64_ptsz_params; + +typedef struct cuStreamWaitValue64_ptsz_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint64_t value; + unsigned int flags; +} cuStreamWaitValue64_ptsz_params; + +typedef struct cuStreamBatchMemOp_ptsz_params_st { + CUstream stream; + unsigned int count; + CUstreamBatchMemOpParams *paramArray; + unsigned int flags; +} cuStreamBatchMemOp_ptsz_params; + +typedef struct cuStreamWriteValue32_v2_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint32_t value; + unsigned int flags; +} cuStreamWriteValue32_v2_params; + +typedef struct cuStreamWaitValue32_v2_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint32_t value; + unsigned int flags; +} cuStreamWaitValue32_v2_params; + +typedef struct cuStreamWriteValue64_v2_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint64_t value; + unsigned int flags; +} cuStreamWriteValue64_v2_params; + +typedef struct cuStreamWaitValue64_v2_params_st { + CUstream stream; + CUdeviceptr addr; + cuuint64_t value; + unsigned int flags; +} cuStreamWaitValue64_v2_params; + +typedef struct cuStreamBatchMemOp_v2_params_st { + CUstream stream; + unsigned int count; + CUstreamBatchMemOpParams *paramArray; + unsigned int flags; +} cuStreamBatchMemOp_v2_params; + +typedef struct cuMemPrefetchAsync_params_st { + CUdeviceptr devPtr; + size_t count; + CUdevice dstDevice; + CUstream hStream; +} cuMemPrefetchAsync_params; + +typedef struct cuMemPrefetchAsync_v2_params_st { + CUdeviceptr devPtr; + size_t count; + CUmemLocation location; + unsigned int flags; + CUstream hStream; +} cuMemPrefetchAsync_v2_params; + +typedef struct cuLaunchCooperativeKernel_params_st { + CUfunction f; + unsigned int gridDimX; + unsigned int gridDimY; + unsigned int gridDimZ; + unsigned int blockDimX; + unsigned int blockDimY; + unsigned int blockDimZ; + unsigned int sharedMemBytes; + CUstream hStream; + void **kernelParams; +} cuLaunchCooperativeKernel_params; + +typedef struct cuSignalExternalSemaphoresAsync_params_st { + const CUexternalSemaphore *extSemArray; + const CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS *paramsArray; + unsigned int numExtSems; + CUstream stream; +} cuSignalExternalSemaphoresAsync_params; + +typedef struct cuWaitExternalSemaphoresAsync_params_st { + const CUexternalSemaphore *extSemArray; + const CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS *paramsArray; + unsigned int numExtSems; + CUstream stream; +} cuWaitExternalSemaphoresAsync_params; + +typedef struct cuStreamBeginCapture_params_st { + CUstream hStream; +} cuStreamBeginCapture_params; + +typedef struct cuStreamBeginCapture_ptsz_params_st { + CUstream hStream; +} cuStreamBeginCapture_ptsz_params; + +typedef struct cuStreamBeginCapture_v2_params_st { + CUstream hStream; + CUstreamCaptureMode mode; +} cuStreamBeginCapture_v2_params; + +typedef struct cuStreamBeginCaptureToGraph_params_st { + CUstream hStream; + CUgraph hGraph; + const CUgraphNode *dependencies; + const CUgraphEdgeData *dependencyData; + size_t numDependencies; + CUstreamCaptureMode mode; +} cuStreamBeginCaptureToGraph_params; + +typedef struct cuStreamEndCapture_params_st { + CUstream hStream; + CUgraph *phGraph; +} cuStreamEndCapture_params; + +typedef struct cuStreamIsCapturing_params_st { + CUstream hStream; + CUstreamCaptureStatus *captureStatus; +} cuStreamIsCapturing_params; + +typedef struct cuStreamGetCaptureInfo_params_st { + CUstream hStream; + CUstreamCaptureStatus *captureStatus_out; + cuuint64_t *id_out; +} cuStreamGetCaptureInfo_params; + +typedef struct cuStreamGetCaptureInfo_ptsz_params_st { + CUstream hStream; + CUstreamCaptureStatus *captureStatus_out; + cuuint64_t *id_out; +} cuStreamGetCaptureInfo_ptsz_params; + +typedef struct cuStreamGetCaptureInfo_v2_params_st { + CUstream hStream; + CUstreamCaptureStatus *captureStatus_out; + cuuint64_t *id_out; + CUgraph *graph_out; + const CUgraphNode **dependencies_out; + size_t *numDependencies_out; +} cuStreamGetCaptureInfo_v2_params; + +typedef struct cuStreamGetCaptureInfo_v3_params_st { + CUstream hStream; + CUstreamCaptureStatus *captureStatus_out; + cuuint64_t *id_out; + CUgraph *graph_out; + const CUgraphNode **dependencies_out; + const CUgraphEdgeData **edgeData_out; + size_t *numDependencies_out; +} cuStreamGetCaptureInfo_v3_params; + +typedef struct cuGraphAddKernelNode_params_st { + CUgraphNode *phGraphNode; + CUgraph hGraph; + const CUgraphNode *dependencies; + size_t numDependencies; + const CUDA_KERNEL_NODE_PARAMS_v1 *nodeParams; +} cuGraphAddKernelNode_params; + +typedef struct cuGraphKernelNodeGetParams_params_st { + CUgraphNode hNode; + CUDA_KERNEL_NODE_PARAMS_v1 *nodeParams; +} cuGraphKernelNodeGetParams_params; + +typedef struct cuGraphKernelNodeSetParams_params_st { + CUgraphNode hNode; + const CUDA_KERNEL_NODE_PARAMS_v1 *nodeParams; +} cuGraphKernelNodeSetParams_params; + +typedef struct cuGraphExecKernelNodeSetParams_params_st { + CUgraphExec hGraphExec; + CUgraphNode hNode; + const CUDA_KERNEL_NODE_PARAMS_v1 *nodeParams; +} cuGraphExecKernelNodeSetParams_params; + +typedef struct cuGraphInstantiateWithParams_params_st { + CUgraphExec *phGraphExec; + CUgraph hGraph; + CUDA_GRAPH_INSTANTIATE_PARAMS *instantiateParams; +} cuGraphInstantiateWithParams_params; + +typedef struct cuGraphExecUpdate_params_st { + CUgraphExec hGraphExec; + CUgraph hGraph; + CUgraphNode *hErrorNode_out; + CUgraphExecUpdateResult *updateResult_out; +} cuGraphExecUpdate_params; + +typedef struct cuGraphUpload_params_st { + CUgraphExec hGraph; + CUstream hStream; +} cuGraphUpload_params; + +typedef struct cuGraphLaunch_params_st { + CUgraphExec hGraph; + CUstream hStream; +} cuGraphLaunch_params; + +typedef struct cuStreamCopyAttributes_params_st { + CUstream dstStream; + CUstream srcStream; +} cuStreamCopyAttributes_params; + +typedef struct cuStreamGetAttribute_params_st { + CUstream hStream; + CUstreamAttrID attr; + CUstreamAttrValue *value; +} cuStreamGetAttribute_params; + +typedef struct cuStreamSetAttribute_params_st { + CUstream hStream; + CUstreamAttrID attr; + const CUstreamAttrValue *param; +} cuStreamSetAttribute_params; + +typedef struct cuIpcOpenMemHandle_params_st { + CUdeviceptr *pdptr; + CUipcMemHandle handle; + unsigned int Flags; +} cuIpcOpenMemHandle_params; + +typedef struct cuGraphInstantiate_params_st { + CUgraphExec *phGraphExec; + CUgraph hGraph; + CUgraphNode *phErrorNode; + char *logBuffer; + size_t bufferSize; +} cuGraphInstantiate_params; + +typedef struct cuGraphInstantiate_v2_params_st { + CUgraphExec *phGraphExec; + CUgraph hGraph; + CUgraphNode *phErrorNode; + char *logBuffer; + size_t bufferSize; +} cuGraphInstantiate_v2_params; + +typedef struct cuMemMapArrayAsync_params_st { + CUarrayMapInfo *mapInfoList; + unsigned int count; + CUstream hStream; +} cuMemMapArrayAsync_params; + +typedef struct cuMemFreeAsync_params_st { + CUdeviceptr dptr; + CUstream hStream; +} cuMemFreeAsync_params; + +typedef struct cuMemAllocAsync_params_st { + CUdeviceptr *dptr; + size_t bytesize; + CUstream hStream; +} cuMemAllocAsync_params; + +typedef struct cuMemAllocFromPoolAsync_params_st { + CUdeviceptr *dptr; + size_t bytesize; + CUmemoryPool pool; + CUstream hStream; +} cuMemAllocFromPoolAsync_params; + +typedef struct cuStreamUpdateCaptureDependencies_params_st { + CUstream hStream; + CUgraphNode *dependencies; + size_t numDependencies; + unsigned int flags; +} cuStreamUpdateCaptureDependencies_params; + +typedef struct cuStreamUpdateCaptureDependencies_v2_params_st { + CUstream hStream; + CUgraphNode *dependencies; + const CUgraphEdgeData *dependencyData; + size_t numDependencies; + unsigned int flags; +} cuStreamUpdateCaptureDependencies_v2_params; + +typedef struct cuMemBatchDecompressAsync_params_st { + CUmemDecompressParams *paramsArray; + size_t count; + unsigned int flags; + size_t *errorIndex; + CUstream stream; +} cuMemBatchDecompressAsync_params; + +typedef struct cuGetProcAddress_params_st { + const char *symbol; + void **pfn; + int cudaVersion; + cuuint64_t flags; +} cuGetProcAddress_params; + +typedef struct cuCheckpointProcessGetRestoreThreadId_params_st { + int pid; + int *tid; +} cuCheckpointProcessGetRestoreThreadId_params; + +typedef struct cuCheckpointProcessGetState_params_st { + int pid; + CUprocessState *state; +} cuCheckpointProcessGetState_params; + +typedef struct cuCheckpointProcessLock_params_st { + int pid; + CUcheckpointLockArgs *args; +} cuCheckpointProcessLock_params; + +typedef struct cuCheckpointProcessCheckpoint_params_st { + int pid; + CUcheckpointCheckpointArgs *args; +} cuCheckpointProcessCheckpoint_params; + +typedef struct cuCheckpointProcessRestore_params_st { + int pid; + CUcheckpointRestoreArgs *args; +} cuCheckpointProcessRestore_params; + +typedef struct cuCheckpointProcessUnlock_params_st { + int pid; + CUcheckpointUnlockArgs *args; +} cuCheckpointProcessUnlock_params; diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_runtime_api_meta.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_runtime_api_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..52321905dd0a82e550332f5d67b03fd4612860e7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_runtime_api_meta.h @@ -0,0 +1,2372 @@ +// This file is generated. Any changes you make will be lost during the next clean build. + +// CUDA public interface, for type definitions and api function prototypes +#include "cuda_runtime_api.h" + +// ************************************************************************* +// Definitions of structs to hold parameters for each function +// ************************************************************************* + +// Currently used parameter trace structures +typedef struct cudaDeviceSetLimit_v3020_params_st { + enum cudaLimit limit; + size_t value; +} cudaDeviceSetLimit_v3020_params; + +typedef struct cudaDeviceGetLimit_v3020_params_st { + size_t *pValue; + enum cudaLimit limit; +} cudaDeviceGetLimit_v3020_params; + +typedef struct cudaDeviceGetTexture1DLinearMaxWidth_v11010_params_st { + size_t *maxWidthInElements; + const struct cudaChannelFormatDesc *fmtDesc; + int device; +} cudaDeviceGetTexture1DLinearMaxWidth_v11010_params; + +typedef struct cudaDeviceGetCacheConfig_v3020_params_st { + enum cudaFuncCache *pCacheConfig; +} cudaDeviceGetCacheConfig_v3020_params; + +typedef struct cudaDeviceGetStreamPriorityRange_v5050_params_st { + int *leastPriority; + int *greatestPriority; +} cudaDeviceGetStreamPriorityRange_v5050_params; + +typedef struct cudaDeviceSetCacheConfig_v3020_params_st { + enum cudaFuncCache cacheConfig; +} cudaDeviceSetCacheConfig_v3020_params; + +typedef struct cudaDeviceGetByPCIBusId_v4010_params_st { + int *device; + const char *pciBusId; +} cudaDeviceGetByPCIBusId_v4010_params; + +typedef struct cudaDeviceGetPCIBusId_v4010_params_st { + char *pciBusId; + int len; + int device; +} cudaDeviceGetPCIBusId_v4010_params; + +typedef struct cudaIpcGetEventHandle_v4010_params_st { + cudaIpcEventHandle_t *handle; + cudaEvent_t event; +} cudaIpcGetEventHandle_v4010_params; + +typedef struct cudaIpcOpenEventHandle_v4010_params_st { + cudaEvent_t *event; + cudaIpcEventHandle_t handle; +} cudaIpcOpenEventHandle_v4010_params; + +typedef struct cudaIpcGetMemHandle_v4010_params_st { + cudaIpcMemHandle_t *handle; + void *devPtr; +} cudaIpcGetMemHandle_v4010_params; + +typedef struct cudaIpcOpenMemHandle_v4010_params_st { + void **devPtr; + cudaIpcMemHandle_t handle; + unsigned int flags; +} cudaIpcOpenMemHandle_v4010_params; + +typedef struct cudaIpcCloseMemHandle_v4010_params_st { + void *devPtr; +} cudaIpcCloseMemHandle_v4010_params; + +typedef struct cudaDeviceFlushGPUDirectRDMAWrites_v11030_params_st { + enum cudaFlushGPUDirectRDMAWritesTarget target; + enum cudaFlushGPUDirectRDMAWritesScope scope; +} cudaDeviceFlushGPUDirectRDMAWrites_v11030_params; + +typedef struct cudaDeviceRegisterAsyncNotification_v12040_params_st { + int device; + cudaAsyncCallback callbackFunc; + void *userData; + cudaAsyncCallbackHandle_t *callback; +} cudaDeviceRegisterAsyncNotification_v12040_params; + +typedef struct cudaDeviceUnregisterAsyncNotification_v12040_params_st { + int device; + cudaAsyncCallbackHandle_t callback; +} cudaDeviceUnregisterAsyncNotification_v12040_params; + +typedef struct cudaDeviceGetSharedMemConfig_v4020_params_st { + enum cudaSharedMemConfig *pConfig; +} cudaDeviceGetSharedMemConfig_v4020_params; + +typedef struct cudaDeviceSetSharedMemConfig_v4020_params_st { + enum cudaSharedMemConfig config; +} cudaDeviceSetSharedMemConfig_v4020_params; + +typedef struct cudaGetErrorName_v6050_params_st { + cudaError_t error; +} cudaGetErrorName_v6050_params; + +typedef struct cudaGetErrorString_v3020_params_st { + cudaError_t error; +} cudaGetErrorString_v3020_params; + +typedef struct cudaGetDeviceCount_v3020_params_st { + int *count; +} cudaGetDeviceCount_v3020_params; + +typedef struct cudaGetDeviceProperties_v2_v12000_params_st { + struct cudaDeviceProp *prop; + int device; +} cudaGetDeviceProperties_v2_v12000_params; + +typedef struct cudaDeviceGetAttribute_v5000_params_st { + int *value; + enum cudaDeviceAttr attr; + int device; +} cudaDeviceGetAttribute_v5000_params; + +typedef struct cudaDeviceGetDefaultMemPool_v11020_params_st { + cudaMemPool_t *memPool; + int device; +} cudaDeviceGetDefaultMemPool_v11020_params; + +typedef struct cudaDeviceSetMemPool_v11020_params_st { + int device; + cudaMemPool_t memPool; +} cudaDeviceSetMemPool_v11020_params; + +typedef struct cudaDeviceGetMemPool_v11020_params_st { + cudaMemPool_t *memPool; + int device; +} cudaDeviceGetMemPool_v11020_params; + +typedef struct cudaDeviceGetNvSciSyncAttributes_v10020_params_st { + void *nvSciSyncAttrList; + int device; + int flags; +} cudaDeviceGetNvSciSyncAttributes_v10020_params; + +typedef struct cudaDeviceGetP2PAttribute_v8000_params_st { + int *value; + enum cudaDeviceP2PAttr attr; + int srcDevice; + int dstDevice; +} cudaDeviceGetP2PAttribute_v8000_params; + +typedef struct cudaChooseDevice_v3020_params_st { + int *device; + const struct cudaDeviceProp *prop; +} cudaChooseDevice_v3020_params; + +typedef struct cudaInitDevice_v12000_params_st { + int device; + unsigned int deviceFlags; + unsigned int flags; +} cudaInitDevice_v12000_params; + +typedef struct cudaSetDevice_v3020_params_st { + int device; +} cudaSetDevice_v3020_params; + +typedef struct cudaGetDevice_v3020_params_st { + int *device; +} cudaGetDevice_v3020_params; + +typedef struct cudaSetValidDevices_v3020_params_st { + int *device_arr; + int len; +} cudaSetValidDevices_v3020_params; + +typedef struct cudaSetDeviceFlags_v3020_params_st { + unsigned int flags; +} cudaSetDeviceFlags_v3020_params; + +typedef struct cudaGetDeviceFlags_v7000_params_st { + unsigned int *flags; +} cudaGetDeviceFlags_v7000_params; + +typedef struct cudaStreamCreate_v3020_params_st { + cudaStream_t *pStream; +} cudaStreamCreate_v3020_params; + +typedef struct cudaStreamCreateWithFlags_v5000_params_st { + cudaStream_t *pStream; + unsigned int flags; +} cudaStreamCreateWithFlags_v5000_params; + +typedef struct cudaStreamCreateWithPriority_v5050_params_st { + cudaStream_t *pStream; + unsigned int flags; + int priority; +} cudaStreamCreateWithPriority_v5050_params; + +typedef struct cudaStreamGetPriority_ptsz_v7000_params_st { + cudaStream_t hStream; + int *priority; +} cudaStreamGetPriority_ptsz_v7000_params; + +typedef struct cudaStreamGetFlags_ptsz_v7000_params_st { + cudaStream_t hStream; + unsigned int *flags; +} cudaStreamGetFlags_ptsz_v7000_params; + +typedef struct cudaStreamGetId_ptsz_v12000_params_st { + cudaStream_t hStream; + unsigned long long *streamId; +} cudaStreamGetId_ptsz_v12000_params; + +typedef struct cudaStreamGetDevice_ptsz_v12080_params_st { + cudaStream_t hStream; + int *device; +} cudaStreamGetDevice_ptsz_v12080_params; + +typedef struct cudaStreamCopyAttributes_ptsz_v11000_params_st { + cudaStream_t dst; + cudaStream_t src; +} cudaStreamCopyAttributes_ptsz_v11000_params; + +typedef struct cudaStreamGetAttribute_ptsz_v11000_params_st { + cudaStream_t hStream; + cudaStreamAttrID attr; + cudaStreamAttrValue *value_out; +} cudaStreamGetAttribute_ptsz_v11000_params; + +typedef struct cudaStreamSetAttribute_ptsz_v11000_params_st { + cudaStream_t hStream; + cudaStreamAttrID attr; + const cudaStreamAttrValue *value; +} cudaStreamSetAttribute_ptsz_v11000_params; + +typedef struct cudaStreamDestroy_v5050_params_st { + cudaStream_t stream; +} cudaStreamDestroy_v5050_params; + +typedef struct cudaStreamWaitEvent_ptsz_v7000_params_st { + cudaStream_t stream; + cudaEvent_t event; + unsigned int flags; +} cudaStreamWaitEvent_ptsz_v7000_params; + +typedef struct cudaStreamAddCallback_ptsz_v7000_params_st { + cudaStream_t stream; + cudaStreamCallback_t callback; + void *userData; + unsigned int flags; +} cudaStreamAddCallback_ptsz_v7000_params; + +typedef struct cudaStreamSynchronize_ptsz_v7000_params_st { + cudaStream_t stream; +} cudaStreamSynchronize_ptsz_v7000_params; + +typedef struct cudaStreamQuery_ptsz_v7000_params_st { + cudaStream_t stream; +} cudaStreamQuery_ptsz_v7000_params; + +typedef struct cudaStreamAttachMemAsync_ptsz_v7000_params_st { + cudaStream_t stream; + void *devPtr; + size_t length; + unsigned int flags; +} cudaStreamAttachMemAsync_ptsz_v7000_params; + +typedef struct cudaStreamBeginCapture_ptsz_v10000_params_st { + cudaStream_t stream; + enum cudaStreamCaptureMode mode; +} cudaStreamBeginCapture_ptsz_v10000_params; + +typedef struct cudaStreamBeginCaptureToGraph_ptsz_v12030_params_st { + cudaStream_t stream; + cudaGraph_t graph; + const cudaGraphNode_t *dependencies; + const cudaGraphEdgeData *dependencyData; + size_t numDependencies; + enum cudaStreamCaptureMode mode; +} cudaStreamBeginCaptureToGraph_ptsz_v12030_params; + +typedef struct cudaThreadExchangeStreamCaptureMode_v10010_params_st { + enum cudaStreamCaptureMode *mode; +} cudaThreadExchangeStreamCaptureMode_v10010_params; + +typedef struct cudaStreamEndCapture_ptsz_v10000_params_st { + cudaStream_t stream; + cudaGraph_t *pGraph; +} cudaStreamEndCapture_ptsz_v10000_params; + +typedef struct cudaStreamIsCapturing_ptsz_v10000_params_st { + cudaStream_t stream; + enum cudaStreamCaptureStatus *pCaptureStatus; +} cudaStreamIsCapturing_ptsz_v10000_params; + +typedef struct cudaStreamGetCaptureInfo_v2_ptsz_v11030_params_st { + cudaStream_t stream; + enum cudaStreamCaptureStatus *captureStatus_out; + unsigned long long *id_out; + cudaGraph_t *graph_out; + const cudaGraphNode_t **dependencies_out; + size_t *numDependencies_out; +} cudaStreamGetCaptureInfo_v2_ptsz_v11030_params; + +typedef struct cudaStreamGetCaptureInfo_v3_ptsz_v12030_params_st { + cudaStream_t stream; + enum cudaStreamCaptureStatus *captureStatus_out; + unsigned long long *id_out; + cudaGraph_t *graph_out; + const cudaGraphNode_t **dependencies_out; + const cudaGraphEdgeData **edgeData_out; + size_t *numDependencies_out; +} cudaStreamGetCaptureInfo_v3_ptsz_v12030_params; + +typedef struct cudaStreamUpdateCaptureDependencies_ptsz_v11030_params_st { + cudaStream_t stream; + cudaGraphNode_t *dependencies; + size_t numDependencies; + unsigned int flags; +} cudaStreamUpdateCaptureDependencies_ptsz_v11030_params; + +typedef struct cudaStreamUpdateCaptureDependencies_v2_ptsz_v12030_params_st { + cudaStream_t stream; + cudaGraphNode_t *dependencies; + const cudaGraphEdgeData *dependencyData; + size_t numDependencies; + unsigned int flags; +} cudaStreamUpdateCaptureDependencies_v2_ptsz_v12030_params; + +typedef struct cudaEventCreate_v3020_params_st { + cudaEvent_t *event; +} cudaEventCreate_v3020_params; + +typedef struct cudaEventCreateWithFlags_v3020_params_st { + cudaEvent_t *event; + unsigned int flags; +} cudaEventCreateWithFlags_v3020_params; + +typedef struct cudaEventRecord_ptsz_v7000_params_st { + cudaEvent_t event; + cudaStream_t stream; +} cudaEventRecord_ptsz_v7000_params; + +typedef struct cudaEventRecordWithFlags_ptsz_v11010_params_st { + cudaEvent_t event; + cudaStream_t stream; + unsigned int flags; +} cudaEventRecordWithFlags_ptsz_v11010_params; + +typedef struct cudaEventQuery_v3020_params_st { + cudaEvent_t event; +} cudaEventQuery_v3020_params; + +typedef struct cudaEventSynchronize_v3020_params_st { + cudaEvent_t event; +} cudaEventSynchronize_v3020_params; + +typedef struct cudaEventDestroy_v3020_params_st { + cudaEvent_t event; +} cudaEventDestroy_v3020_params; + +typedef struct cudaEventElapsedTime_v3020_params_st { + float *ms; + cudaEvent_t start; + cudaEvent_t end; +} cudaEventElapsedTime_v3020_params; + +typedef struct cudaEventElapsedTime_v2_v12080_params_st { + float *ms; + cudaEvent_t start; + cudaEvent_t end; +} cudaEventElapsedTime_v2_v12080_params; + +typedef struct cudaImportExternalMemory_v10000_params_st { + cudaExternalMemory_t *extMem_out; + const struct cudaExternalMemoryHandleDesc *memHandleDesc; +} cudaImportExternalMemory_v10000_params; + +typedef struct cudaExternalMemoryGetMappedBuffer_v10000_params_st { + void **devPtr; + cudaExternalMemory_t extMem; + const struct cudaExternalMemoryBufferDesc *bufferDesc; +} cudaExternalMemoryGetMappedBuffer_v10000_params; + +typedef struct cudaExternalMemoryGetMappedMipmappedArray_v10000_params_st { + cudaMipmappedArray_t *mipmap; + cudaExternalMemory_t extMem; + const struct cudaExternalMemoryMipmappedArrayDesc *mipmapDesc; +} cudaExternalMemoryGetMappedMipmappedArray_v10000_params; + +typedef struct cudaDestroyExternalMemory_v10000_params_st { + cudaExternalMemory_t extMem; +} cudaDestroyExternalMemory_v10000_params; + +typedef struct cudaImportExternalSemaphore_v10000_params_st { + cudaExternalSemaphore_t *extSem_out; + const struct cudaExternalSemaphoreHandleDesc *semHandleDesc; +} cudaImportExternalSemaphore_v10000_params; + +typedef struct cudaSignalExternalSemaphoresAsync_v2_ptsz_v11020_params_st { + const cudaExternalSemaphore_t *extSemArray; + const struct cudaExternalSemaphoreSignalParams *paramsArray; + unsigned int numExtSems; + cudaStream_t stream; +} cudaSignalExternalSemaphoresAsync_v2_ptsz_v11020_params; + +typedef struct cudaWaitExternalSemaphoresAsync_v2_ptsz_v11020_params_st { + const cudaExternalSemaphore_t *extSemArray; + const struct cudaExternalSemaphoreWaitParams *paramsArray; + unsigned int numExtSems; + cudaStream_t stream; +} cudaWaitExternalSemaphoresAsync_v2_ptsz_v11020_params; + +typedef struct cudaDestroyExternalSemaphore_v10000_params_st { + cudaExternalSemaphore_t extSem; +} cudaDestroyExternalSemaphore_v10000_params; + +typedef struct cudaLaunchKernel_ptsz_v7000_params_st { + const void *func; + dim3 gridDim; + dim3 blockDim; + void **args; + size_t sharedMem; + cudaStream_t stream; +} cudaLaunchKernel_ptsz_v7000_params; + +typedef struct cudaLaunchKernelExC_ptsz_v11060_params_st { + const cudaLaunchConfig_t *config; + const void *func; + void **args; +} cudaLaunchKernelExC_ptsz_v11060_params; + +typedef struct cudaLaunchCooperativeKernel_ptsz_v9000_params_st { + const void *func; + dim3 gridDim; + dim3 blockDim; + void **args; + size_t sharedMem; + cudaStream_t stream; +} cudaLaunchCooperativeKernel_ptsz_v9000_params; + +typedef struct cudaLaunchCooperativeKernelMultiDevice_v9000_params_st { + struct cudaLaunchParams *launchParamsList; + unsigned int numDevices; + unsigned int flags; +} cudaLaunchCooperativeKernelMultiDevice_v9000_params; + +typedef struct cudaFuncSetCacheConfig_v3020_params_st { + const void *func; + enum cudaFuncCache cacheConfig; +} cudaFuncSetCacheConfig_v3020_params; + +typedef struct cudaFuncGetAttributes_v3020_params_st { + struct cudaFuncAttributes *attr; + const void *func; +} cudaFuncGetAttributes_v3020_params; + +typedef struct cudaFuncSetAttribute_v9000_params_st { + const void *func; + enum cudaFuncAttribute attr; + int value; +} cudaFuncSetAttribute_v9000_params; + +typedef struct cudaFuncGetName_v12030_params_st { + const char **name; + const void *func; +} cudaFuncGetName_v12030_params; + +typedef struct cudaFuncGetParamInfo_v12040_params_st { + const void *func; + size_t paramIndex; + size_t *paramOffset; + size_t *paramSize; +} cudaFuncGetParamInfo_v12040_params; + +typedef struct cudaLaunchHostFunc_ptsz_v10000_params_st { + cudaStream_t stream; + cudaHostFn_t fn; + void *userData; +} cudaLaunchHostFunc_ptsz_v10000_params; + +typedef struct cudaFuncSetSharedMemConfig_v4020_params_st { + const void *func; + enum cudaSharedMemConfig config; +} cudaFuncSetSharedMemConfig_v4020_params; + +typedef struct cudaOccupancyMaxActiveBlocksPerMultiprocessor_v6050_params_st { + int *numBlocks; + const void *func; + int blockSize; + size_t dynamicSMemSize; +} cudaOccupancyMaxActiveBlocksPerMultiprocessor_v6050_params; + +typedef struct cudaOccupancyAvailableDynamicSMemPerBlock_v10200_params_st { + size_t *dynamicSmemSize; + const void *func; + int numBlocks; + int blockSize; +} cudaOccupancyAvailableDynamicSMemPerBlock_v10200_params; + +typedef struct cudaOccupancyMaxActiveBlocksPerMultiprocessorWithFlags_v7000_params_st { + int *numBlocks; + const void *func; + int blockSize; + size_t dynamicSMemSize; + unsigned int flags; +} cudaOccupancyMaxActiveBlocksPerMultiprocessorWithFlags_v7000_params; + +typedef struct cudaOccupancyMaxPotentialClusterSize_v11070_params_st { + int *clusterSize; + const void *func; + const cudaLaunchConfig_t *launchConfig; +} cudaOccupancyMaxPotentialClusterSize_v11070_params; + +typedef struct cudaOccupancyMaxActiveClusters_v11070_params_st { + int *numClusters; + const void *func; + const cudaLaunchConfig_t *launchConfig; +} cudaOccupancyMaxActiveClusters_v11070_params; + +typedef struct cudaMallocManaged_v6000_params_st { + void **devPtr; + size_t size; + unsigned int flags; +} cudaMallocManaged_v6000_params; + +typedef struct cudaMalloc_v3020_params_st { + void **devPtr; + size_t size; +} cudaMalloc_v3020_params; + +typedef struct cudaMallocHost_v3020_params_st { + void **ptr; + size_t size; +} cudaMallocHost_v3020_params; + +typedef struct cudaMallocPitch_v3020_params_st { + void **devPtr; + size_t *pitch; + size_t width; + size_t height; +} cudaMallocPitch_v3020_params; + +typedef struct cudaMallocArray_v3020_params_st { + cudaArray_t *array; + const struct cudaChannelFormatDesc *desc; + size_t width; + size_t height; + unsigned int flags; +} cudaMallocArray_v3020_params; + +typedef struct cudaFree_v3020_params_st { + void *devPtr; +} cudaFree_v3020_params; + +typedef struct cudaFreeHost_v3020_params_st { + void *ptr; +} cudaFreeHost_v3020_params; + +typedef struct cudaFreeArray_v3020_params_st { + cudaArray_t array; +} cudaFreeArray_v3020_params; + +typedef struct cudaFreeMipmappedArray_v5000_params_st { + cudaMipmappedArray_t mipmappedArray; +} cudaFreeMipmappedArray_v5000_params; + +typedef struct cudaHostAlloc_v3020_params_st { + void **pHost; + size_t size; + unsigned int flags; +} cudaHostAlloc_v3020_params; + +typedef struct cudaHostRegister_v4000_params_st { + void *ptr; + size_t size; + unsigned int flags; +} cudaHostRegister_v4000_params; + +typedef struct cudaHostUnregister_v4000_params_st { + void *ptr; +} cudaHostUnregister_v4000_params; + +typedef struct cudaHostGetDevicePointer_v3020_params_st { + void **pDevice; + void *pHost; + unsigned int flags; +} cudaHostGetDevicePointer_v3020_params; + +typedef struct cudaHostGetFlags_v3020_params_st { + unsigned int *pFlags; + void *pHost; +} cudaHostGetFlags_v3020_params; + +typedef struct cudaMalloc3D_v3020_params_st { + struct cudaPitchedPtr *pitchedDevPtr; + struct cudaExtent extent; +} cudaMalloc3D_v3020_params; + +typedef struct cudaMalloc3DArray_v3020_params_st { + cudaArray_t *array; + const struct cudaChannelFormatDesc *desc; + struct cudaExtent extent; + unsigned int flags; +} cudaMalloc3DArray_v3020_params; + +typedef struct cudaMallocMipmappedArray_v5000_params_st { + cudaMipmappedArray_t *mipmappedArray; + const struct cudaChannelFormatDesc *desc; + struct cudaExtent extent; + unsigned int numLevels; + unsigned int flags; +} cudaMallocMipmappedArray_v5000_params; + +typedef struct cudaGetMipmappedArrayLevel_v5000_params_st { + cudaArray_t *levelArray; + cudaMipmappedArray_const_t mipmappedArray; + unsigned int level; +} cudaGetMipmappedArrayLevel_v5000_params; + +typedef struct cudaMemcpy3D_ptds_v7000_params_st { + const struct cudaMemcpy3DParms *p; +} cudaMemcpy3D_ptds_v7000_params; + +typedef struct cudaMemcpy3DPeer_ptds_v7000_params_st { + const struct cudaMemcpy3DPeerParms *p; +} cudaMemcpy3DPeer_ptds_v7000_params; + +typedef struct cudaMemcpy3DAsync_ptsz_v7000_params_st { + const struct cudaMemcpy3DParms *p; + cudaStream_t stream; +} cudaMemcpy3DAsync_ptsz_v7000_params; + +typedef struct cudaMemcpy3DPeerAsync_ptsz_v7000_params_st { + const struct cudaMemcpy3DPeerParms *p; + cudaStream_t stream; +} cudaMemcpy3DPeerAsync_ptsz_v7000_params; + +typedef struct cudaMemGetInfo_v3020_params_st { + size_t *free; + size_t *total; +} cudaMemGetInfo_v3020_params; + +typedef struct cudaArrayGetInfo_v4010_params_st { + struct cudaChannelFormatDesc *desc; + struct cudaExtent *extent; + unsigned int *flags; + cudaArray_t array; +} cudaArrayGetInfo_v4010_params; + +typedef struct cudaArrayGetPlane_v11020_params_st { + cudaArray_t *pPlaneArray; + cudaArray_t hArray; + unsigned int planeIdx; +} cudaArrayGetPlane_v11020_params; + +typedef struct cudaArrayGetMemoryRequirements_v11060_params_st { + struct cudaArrayMemoryRequirements *memoryRequirements; + cudaArray_t array; + int device; +} cudaArrayGetMemoryRequirements_v11060_params; + +typedef struct cudaMipmappedArrayGetMemoryRequirements_v11060_params_st { + struct cudaArrayMemoryRequirements *memoryRequirements; + cudaMipmappedArray_t mipmap; + int device; +} cudaMipmappedArrayGetMemoryRequirements_v11060_params; + +typedef struct cudaArrayGetSparseProperties_v11010_params_st { + struct cudaArraySparseProperties *sparseProperties; + cudaArray_t array; +} cudaArrayGetSparseProperties_v11010_params; + +typedef struct cudaMipmappedArrayGetSparseProperties_v11010_params_st { + struct cudaArraySparseProperties *sparseProperties; + cudaMipmappedArray_t mipmap; +} cudaMipmappedArrayGetSparseProperties_v11010_params; + +typedef struct cudaMemcpy_ptds_v7000_params_st { + void *dst; + const void *src; + size_t count; + enum cudaMemcpyKind kind; +} cudaMemcpy_ptds_v7000_params; + +typedef struct cudaMemcpyPeer_v4000_params_st { + void *dst; + int dstDevice; + const void *src; + int srcDevice; + size_t count; +} cudaMemcpyPeer_v4000_params; + +typedef struct cudaMemcpy2D_ptds_v7000_params_st { + void *dst; + size_t dpitch; + const void *src; + size_t spitch; + size_t width; + size_t height; + enum cudaMemcpyKind kind; +} cudaMemcpy2D_ptds_v7000_params; + +typedef struct cudaMemcpy2DToArray_ptds_v7000_params_st { + cudaArray_t dst; + size_t wOffset; + size_t hOffset; + const void *src; + size_t spitch; + size_t width; + size_t height; + enum cudaMemcpyKind kind; +} cudaMemcpy2DToArray_ptds_v7000_params; + +typedef struct cudaMemcpy2DFromArray_ptds_v7000_params_st { + void *dst; + size_t dpitch; + cudaArray_const_t src; + size_t wOffset; + size_t hOffset; + size_t width; + size_t height; + enum cudaMemcpyKind kind; +} cudaMemcpy2DFromArray_ptds_v7000_params; + +typedef struct cudaMemcpy2DArrayToArray_ptds_v7000_params_st { + cudaArray_t dst; + size_t wOffsetDst; + size_t hOffsetDst; + cudaArray_const_t src; + size_t wOffsetSrc; + size_t hOffsetSrc; + size_t width; + size_t height; + enum cudaMemcpyKind kind; +} cudaMemcpy2DArrayToArray_ptds_v7000_params; + +typedef struct cudaMemcpyToSymbol_ptds_v7000_params_st { + const void *symbol; + const void *src; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaMemcpyToSymbol_ptds_v7000_params; + +typedef struct cudaMemcpyFromSymbol_ptds_v7000_params_st { + void *dst; + const void *symbol; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaMemcpyFromSymbol_ptds_v7000_params; + +typedef struct cudaMemcpyAsync_ptsz_v7000_params_st { + void *dst; + const void *src; + size_t count; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyAsync_ptsz_v7000_params; + +typedef struct cudaMemcpyPeerAsync_v4000_params_st { + void *dst; + int dstDevice; + const void *src; + int srcDevice; + size_t count; + cudaStream_t stream; +} cudaMemcpyPeerAsync_v4000_params; + +typedef struct cudaMemcpyBatchAsync_ptsz_v12080_params_st { + void **dsts; + void **srcs; + size_t *sizes; + size_t count; + struct cudaMemcpyAttributes *attrs; + size_t *attrsIdxs; + size_t numAttrs; + size_t *failIdx; + cudaStream_t stream; +} cudaMemcpyBatchAsync_ptsz_v12080_params; + +typedef struct cudaMemcpy3DBatchAsync_ptsz_v12080_params_st { + size_t numOps; + struct cudaMemcpy3DBatchOp *opList; + size_t *failIdx; + unsigned long long flags; + cudaStream_t stream; +} cudaMemcpy3DBatchAsync_ptsz_v12080_params; + +typedef struct cudaMemcpy2DAsync_ptsz_v7000_params_st { + void *dst; + size_t dpitch; + const void *src; + size_t spitch; + size_t width; + size_t height; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpy2DAsync_ptsz_v7000_params; + +typedef struct cudaMemcpy2DToArrayAsync_ptsz_v7000_params_st { + cudaArray_t dst; + size_t wOffset; + size_t hOffset; + const void *src; + size_t spitch; + size_t width; + size_t height; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpy2DToArrayAsync_ptsz_v7000_params; + +typedef struct cudaMemcpy2DFromArrayAsync_ptsz_v7000_params_st { + void *dst; + size_t dpitch; + cudaArray_const_t src; + size_t wOffset; + size_t hOffset; + size_t width; + size_t height; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpy2DFromArrayAsync_ptsz_v7000_params; + +typedef struct cudaMemcpyToSymbolAsync_ptsz_v7000_params_st { + const void *symbol; + const void *src; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyToSymbolAsync_ptsz_v7000_params; + +typedef struct cudaMemcpyFromSymbolAsync_ptsz_v7000_params_st { + void *dst; + const void *symbol; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyFromSymbolAsync_ptsz_v7000_params; + +typedef struct cudaMemset_ptds_v7000_params_st { + void *devPtr; + int value; + size_t count; +} cudaMemset_ptds_v7000_params; + +typedef struct cudaMemset2D_ptds_v7000_params_st { + void *devPtr; + size_t pitch; + int value; + size_t width; + size_t height; +} cudaMemset2D_ptds_v7000_params; + +typedef struct cudaMemset3D_ptds_v7000_params_st { + struct cudaPitchedPtr pitchedDevPtr; + int value; + struct cudaExtent extent; +} cudaMemset3D_ptds_v7000_params; + +typedef struct cudaMemsetAsync_ptsz_v7000_params_st { + void *devPtr; + int value; + size_t count; + cudaStream_t stream; +} cudaMemsetAsync_ptsz_v7000_params; + +typedef struct cudaMemset2DAsync_ptsz_v7000_params_st { + void *devPtr; + size_t pitch; + int value; + size_t width; + size_t height; + cudaStream_t stream; +} cudaMemset2DAsync_ptsz_v7000_params; + +typedef struct cudaMemset3DAsync_ptsz_v7000_params_st { + struct cudaPitchedPtr pitchedDevPtr; + int value; + struct cudaExtent extent; + cudaStream_t stream; +} cudaMemset3DAsync_ptsz_v7000_params; + +typedef struct cudaGetSymbolAddress_v3020_params_st { + void **devPtr; + const void *symbol; +} cudaGetSymbolAddress_v3020_params; + +typedef struct cudaGetSymbolSize_v3020_params_st { + size_t *size; + const void *symbol; +} cudaGetSymbolSize_v3020_params; + +typedef struct cudaMemPrefetchAsync_ptsz_v8000_params_st { + const void *devPtr; + size_t count; + int dstDevice; + cudaStream_t stream; +} cudaMemPrefetchAsync_ptsz_v8000_params; + +typedef struct cudaMemPrefetchAsync_v2_ptsz_v12020_params_st { + const void *devPtr; + size_t count; + struct cudaMemLocation location; + unsigned int flags; + cudaStream_t stream; +} cudaMemPrefetchAsync_v2_ptsz_v12020_params; + +typedef struct cudaMemAdvise_v8000_params_st { + const void *devPtr; + size_t count; + enum cudaMemoryAdvise advice; + int device; +} cudaMemAdvise_v8000_params; + +typedef struct cudaMemAdvise_v2_v12020_params_st { + const void *devPtr; + size_t count; + enum cudaMemoryAdvise advice; + struct cudaMemLocation location; +} cudaMemAdvise_v2_v12020_params; + +typedef struct cudaMemRangeGetAttribute_v8000_params_st { + void *data; + size_t dataSize; + enum cudaMemRangeAttribute attribute; + const void *devPtr; + size_t count; +} cudaMemRangeGetAttribute_v8000_params; + +typedef struct cudaMemRangeGetAttributes_v8000_params_st { + void **data; + size_t *dataSizes; + enum cudaMemRangeAttribute *attributes; + size_t numAttributes; + const void *devPtr; + size_t count; +} cudaMemRangeGetAttributes_v8000_params; + +typedef struct cudaMemcpyToArray_ptds_v7000_params_st { + cudaArray_t dst; + size_t wOffset; + size_t hOffset; + const void *src; + size_t count; + enum cudaMemcpyKind kind; +} cudaMemcpyToArray_ptds_v7000_params; + +typedef struct cudaMemcpyFromArray_ptds_v7000_params_st { + void *dst; + cudaArray_const_t src; + size_t wOffset; + size_t hOffset; + size_t count; + enum cudaMemcpyKind kind; +} cudaMemcpyFromArray_ptds_v7000_params; + +typedef struct cudaMemcpyArrayToArray_ptds_v7000_params_st { + cudaArray_t dst; + size_t wOffsetDst; + size_t hOffsetDst; + cudaArray_const_t src; + size_t wOffsetSrc; + size_t hOffsetSrc; + size_t count; + enum cudaMemcpyKind kind; +} cudaMemcpyArrayToArray_ptds_v7000_params; + +typedef struct cudaMemcpyToArrayAsync_ptsz_v7000_params_st { + cudaArray_t dst; + size_t wOffset; + size_t hOffset; + const void *src; + size_t count; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyToArrayAsync_ptsz_v7000_params; + +typedef struct cudaMemcpyFromArrayAsync_ptsz_v7000_params_st { + void *dst; + cudaArray_const_t src; + size_t wOffset; + size_t hOffset; + size_t count; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyFromArrayAsync_ptsz_v7000_params; + +typedef struct cudaMallocAsync_ptsz_v11020_params_st { + void **devPtr; + size_t size; + cudaStream_t hStream; +} cudaMallocAsync_ptsz_v11020_params; + +typedef struct cudaFreeAsync_ptsz_v11020_params_st { + void *devPtr; + cudaStream_t hStream; +} cudaFreeAsync_ptsz_v11020_params; + +typedef struct cudaMemPoolTrimTo_v11020_params_st { + cudaMemPool_t memPool; + size_t minBytesToKeep; +} cudaMemPoolTrimTo_v11020_params; + +typedef struct cudaMemPoolSetAttribute_v11020_params_st { + cudaMemPool_t memPool; + enum cudaMemPoolAttr attr; + void *value; +} cudaMemPoolSetAttribute_v11020_params; + +typedef struct cudaMemPoolGetAttribute_v11020_params_st { + cudaMemPool_t memPool; + enum cudaMemPoolAttr attr; + void *value; +} cudaMemPoolGetAttribute_v11020_params; + +typedef struct cudaMemPoolSetAccess_v11020_params_st { + cudaMemPool_t memPool; + const struct cudaMemAccessDesc *descList; + size_t count; +} cudaMemPoolSetAccess_v11020_params; + +typedef struct cudaMemPoolGetAccess_v11020_params_st { + enum cudaMemAccessFlags *flags; + cudaMemPool_t memPool; + struct cudaMemLocation *location; +} cudaMemPoolGetAccess_v11020_params; + +typedef struct cudaMemPoolCreate_v11020_params_st { + cudaMemPool_t *memPool; + const struct cudaMemPoolProps *poolProps; +} cudaMemPoolCreate_v11020_params; + +typedef struct cudaMemPoolDestroy_v11020_params_st { + cudaMemPool_t memPool; +} cudaMemPoolDestroy_v11020_params; + +typedef struct cudaMallocFromPoolAsync_ptsz_v11020_params_st { + void **ptr; + size_t size; + cudaMemPool_t memPool; + cudaStream_t stream; +} cudaMallocFromPoolAsync_ptsz_v11020_params; + +typedef struct cudaMemPoolExportToShareableHandle_v11020_params_st { + void *shareableHandle; + cudaMemPool_t memPool; + enum cudaMemAllocationHandleType handleType; + unsigned int flags; +} cudaMemPoolExportToShareableHandle_v11020_params; + +typedef struct cudaMemPoolImportFromShareableHandle_v11020_params_st { + cudaMemPool_t *memPool; + void *shareableHandle; + enum cudaMemAllocationHandleType handleType; + unsigned int flags; +} cudaMemPoolImportFromShareableHandle_v11020_params; + +typedef struct cudaMemPoolExportPointer_v11020_params_st { + struct cudaMemPoolPtrExportData *exportData; + void *ptr; +} cudaMemPoolExportPointer_v11020_params; + +typedef struct cudaMemPoolImportPointer_v11020_params_st { + void **ptr; + cudaMemPool_t memPool; + struct cudaMemPoolPtrExportData *exportData; +} cudaMemPoolImportPointer_v11020_params; + +typedef struct cudaPointerGetAttributes_v4000_params_st { + struct cudaPointerAttributes *attributes; + const void *ptr; +} cudaPointerGetAttributes_v4000_params; + +typedef struct cudaDeviceCanAccessPeer_v4000_params_st { + int *canAccessPeer; + int device; + int peerDevice; +} cudaDeviceCanAccessPeer_v4000_params; + +typedef struct cudaDeviceEnablePeerAccess_v4000_params_st { + int peerDevice; + unsigned int flags; +} cudaDeviceEnablePeerAccess_v4000_params; + +typedef struct cudaDeviceDisablePeerAccess_v4000_params_st { + int peerDevice; +} cudaDeviceDisablePeerAccess_v4000_params; + +typedef struct cudaGraphicsUnregisterResource_v3020_params_st { + cudaGraphicsResource_t resource; +} cudaGraphicsUnregisterResource_v3020_params; + +typedef struct cudaGraphicsResourceSetMapFlags_v3020_params_st { + cudaGraphicsResource_t resource; + unsigned int flags; +} cudaGraphicsResourceSetMapFlags_v3020_params; + +typedef struct cudaGraphicsMapResources_v3020_params_st { + int count; + cudaGraphicsResource_t *resources; + cudaStream_t stream; +} cudaGraphicsMapResources_v3020_params; + +typedef struct cudaGraphicsUnmapResources_v3020_params_st { + int count; + cudaGraphicsResource_t *resources; + cudaStream_t stream; +} cudaGraphicsUnmapResources_v3020_params; + +typedef struct cudaGraphicsResourceGetMappedPointer_v3020_params_st { + void **devPtr; + size_t *size; + cudaGraphicsResource_t resource; +} cudaGraphicsResourceGetMappedPointer_v3020_params; + +typedef struct cudaGraphicsSubResourceGetMappedArray_v3020_params_st { + cudaArray_t *array; + cudaGraphicsResource_t resource; + unsigned int arrayIndex; + unsigned int mipLevel; +} cudaGraphicsSubResourceGetMappedArray_v3020_params; + +typedef struct cudaGraphicsResourceGetMappedMipmappedArray_v5000_params_st { + cudaMipmappedArray_t *mipmappedArray; + cudaGraphicsResource_t resource; +} cudaGraphicsResourceGetMappedMipmappedArray_v5000_params; + +typedef struct cudaGetChannelDesc_v3020_params_st { + struct cudaChannelFormatDesc *desc; + cudaArray_const_t array; +} cudaGetChannelDesc_v3020_params; + +typedef struct cudaCreateChannelDesc_v3020_params_st { + int x; + int y; + int z; + int w; + enum cudaChannelFormatKind f; +} cudaCreateChannelDesc_v3020_params; + +typedef struct cudaCreateTextureObject_v5000_params_st { + cudaTextureObject_t *pTexObject; + const struct cudaResourceDesc *pResDesc; + const struct cudaTextureDesc *pTexDesc; + const struct cudaResourceViewDesc *pResViewDesc; +} cudaCreateTextureObject_v5000_params; + +typedef struct cudaDestroyTextureObject_v5000_params_st { + cudaTextureObject_t texObject; +} cudaDestroyTextureObject_v5000_params; + +typedef struct cudaGetTextureObjectResourceDesc_v5000_params_st { + struct cudaResourceDesc *pResDesc; + cudaTextureObject_t texObject; +} cudaGetTextureObjectResourceDesc_v5000_params; + +typedef struct cudaGetTextureObjectTextureDesc_v5000_params_st { + struct cudaTextureDesc *pTexDesc; + cudaTextureObject_t texObject; +} cudaGetTextureObjectTextureDesc_v5000_params; + +typedef struct cudaGetTextureObjectResourceViewDesc_v5000_params_st { + struct cudaResourceViewDesc *pResViewDesc; + cudaTextureObject_t texObject; +} cudaGetTextureObjectResourceViewDesc_v5000_params; + +typedef struct cudaCreateSurfaceObject_v5000_params_st { + cudaSurfaceObject_t *pSurfObject; + const struct cudaResourceDesc *pResDesc; +} cudaCreateSurfaceObject_v5000_params; + +typedef struct cudaDestroySurfaceObject_v5000_params_st { + cudaSurfaceObject_t surfObject; +} cudaDestroySurfaceObject_v5000_params; + +typedef struct cudaGetSurfaceObjectResourceDesc_v5000_params_st { + struct cudaResourceDesc *pResDesc; + cudaSurfaceObject_t surfObject; +} cudaGetSurfaceObjectResourceDesc_v5000_params; + +typedef struct cudaDriverGetVersion_v3020_params_st { + int *driverVersion; +} cudaDriverGetVersion_v3020_params; + +typedef struct cudaRuntimeGetVersion_v3020_params_st { + int *runtimeVersion; +} cudaRuntimeGetVersion_v3020_params; + +typedef struct cudaGraphCreate_v10000_params_st { + cudaGraph_t *pGraph; + unsigned int flags; +} cudaGraphCreate_v10000_params; + +typedef struct cudaGraphAddKernelNode_v10000_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + const struct cudaKernelNodeParams *pNodeParams; +} cudaGraphAddKernelNode_v10000_params; + +typedef struct cudaGraphKernelNodeGetParams_v10000_params_st { + cudaGraphNode_t node; + struct cudaKernelNodeParams *pNodeParams; +} cudaGraphKernelNodeGetParams_v10000_params; + +typedef struct cudaGraphKernelNodeSetParams_v10000_params_st { + cudaGraphNode_t node; + const struct cudaKernelNodeParams *pNodeParams; +} cudaGraphKernelNodeSetParams_v10000_params; + +typedef struct cudaGraphKernelNodeCopyAttributes_v11000_params_st { + cudaGraphNode_t hSrc; + cudaGraphNode_t hDst; +} cudaGraphKernelNodeCopyAttributes_v11000_params; + +typedef struct cudaGraphKernelNodeGetAttribute_v11000_params_st { + cudaGraphNode_t hNode; + cudaKernelNodeAttrID attr; + cudaKernelNodeAttrValue *value_out; +} cudaGraphKernelNodeGetAttribute_v11000_params; + +typedef struct cudaGraphKernelNodeSetAttribute_v11000_params_st { + cudaGraphNode_t hNode; + cudaKernelNodeAttrID attr; + const cudaKernelNodeAttrValue *value; +} cudaGraphKernelNodeSetAttribute_v11000_params; + +typedef struct cudaGraphAddMemcpyNode_v10000_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + const struct cudaMemcpy3DParms *pCopyParams; +} cudaGraphAddMemcpyNode_v10000_params; + +typedef struct cudaGraphAddMemcpyNodeToSymbol_v11010_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + const void *symbol; + const void *src; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaGraphAddMemcpyNodeToSymbol_v11010_params; + +typedef struct cudaGraphAddMemcpyNodeFromSymbol_v11010_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + void *dst; + const void *symbol; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaGraphAddMemcpyNodeFromSymbol_v11010_params; + +typedef struct cudaGraphAddMemcpyNode1D_v11010_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + void *dst; + const void *src; + size_t count; + enum cudaMemcpyKind kind; +} cudaGraphAddMemcpyNode1D_v11010_params; + +typedef struct cudaGraphMemcpyNodeGetParams_v10000_params_st { + cudaGraphNode_t node; + struct cudaMemcpy3DParms *pNodeParams; +} cudaGraphMemcpyNodeGetParams_v10000_params; + +typedef struct cudaGraphMemcpyNodeSetParams_v10000_params_st { + cudaGraphNode_t node; + const struct cudaMemcpy3DParms *pNodeParams; +} cudaGraphMemcpyNodeSetParams_v10000_params; + +typedef struct cudaGraphMemcpyNodeSetParamsToSymbol_v11010_params_st { + cudaGraphNode_t node; + const void *symbol; + const void *src; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaGraphMemcpyNodeSetParamsToSymbol_v11010_params; + +typedef struct cudaGraphMemcpyNodeSetParamsFromSymbol_v11010_params_st { + cudaGraphNode_t node; + void *dst; + const void *symbol; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaGraphMemcpyNodeSetParamsFromSymbol_v11010_params; + +typedef struct cudaGraphMemcpyNodeSetParams1D_v11010_params_st { + cudaGraphNode_t node; + void *dst; + const void *src; + size_t count; + enum cudaMemcpyKind kind; +} cudaGraphMemcpyNodeSetParams1D_v11010_params; + +typedef struct cudaGraphAddMemsetNode_v10000_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + const struct cudaMemsetParams *pMemsetParams; +} cudaGraphAddMemsetNode_v10000_params; + +typedef struct cudaGraphMemsetNodeGetParams_v10000_params_st { + cudaGraphNode_t node; + struct cudaMemsetParams *pNodeParams; +} cudaGraphMemsetNodeGetParams_v10000_params; + +typedef struct cudaGraphMemsetNodeSetParams_v10000_params_st { + cudaGraphNode_t node; + const struct cudaMemsetParams *pNodeParams; +} cudaGraphMemsetNodeSetParams_v10000_params; + +typedef struct cudaGraphAddHostNode_v10000_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + const struct cudaHostNodeParams *pNodeParams; +} cudaGraphAddHostNode_v10000_params; + +typedef struct cudaGraphHostNodeGetParams_v10000_params_st { + cudaGraphNode_t node; + struct cudaHostNodeParams *pNodeParams; +} cudaGraphHostNodeGetParams_v10000_params; + +typedef struct cudaGraphHostNodeSetParams_v10000_params_st { + cudaGraphNode_t node; + const struct cudaHostNodeParams *pNodeParams; +} cudaGraphHostNodeSetParams_v10000_params; + +typedef struct cudaGraphAddChildGraphNode_v10000_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + cudaGraph_t childGraph; +} cudaGraphAddChildGraphNode_v10000_params; + +typedef struct cudaGraphChildGraphNodeGetGraph_v10000_params_st { + cudaGraphNode_t node; + cudaGraph_t *pGraph; +} cudaGraphChildGraphNodeGetGraph_v10000_params; + +typedef struct cudaGraphAddEmptyNode_v10000_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; +} cudaGraphAddEmptyNode_v10000_params; + +typedef struct cudaGraphAddEventRecordNode_v11010_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + cudaEvent_t event; +} cudaGraphAddEventRecordNode_v11010_params; + +typedef struct cudaGraphEventRecordNodeGetEvent_v11010_params_st { + cudaGraphNode_t node; + cudaEvent_t *event_out; +} cudaGraphEventRecordNodeGetEvent_v11010_params; + +typedef struct cudaGraphEventRecordNodeSetEvent_v11010_params_st { + cudaGraphNode_t node; + cudaEvent_t event; +} cudaGraphEventRecordNodeSetEvent_v11010_params; + +typedef struct cudaGraphAddEventWaitNode_v11010_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + cudaEvent_t event; +} cudaGraphAddEventWaitNode_v11010_params; + +typedef struct cudaGraphEventWaitNodeGetEvent_v11010_params_st { + cudaGraphNode_t node; + cudaEvent_t *event_out; +} cudaGraphEventWaitNodeGetEvent_v11010_params; + +typedef struct cudaGraphEventWaitNodeSetEvent_v11010_params_st { + cudaGraphNode_t node; + cudaEvent_t event; +} cudaGraphEventWaitNodeSetEvent_v11010_params; + +typedef struct cudaGraphAddExternalSemaphoresSignalNode_v11020_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + const struct cudaExternalSemaphoreSignalNodeParams *nodeParams; +} cudaGraphAddExternalSemaphoresSignalNode_v11020_params; + +typedef struct cudaGraphExternalSemaphoresSignalNodeGetParams_v11020_params_st { + cudaGraphNode_t hNode; + struct cudaExternalSemaphoreSignalNodeParams *params_out; +} cudaGraphExternalSemaphoresSignalNodeGetParams_v11020_params; + +typedef struct cudaGraphExternalSemaphoresSignalNodeSetParams_v11020_params_st { + cudaGraphNode_t hNode; + const struct cudaExternalSemaphoreSignalNodeParams *nodeParams; +} cudaGraphExternalSemaphoresSignalNodeSetParams_v11020_params; + +typedef struct cudaGraphAddExternalSemaphoresWaitNode_v11020_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + const struct cudaExternalSemaphoreWaitNodeParams *nodeParams; +} cudaGraphAddExternalSemaphoresWaitNode_v11020_params; + +typedef struct cudaGraphExternalSemaphoresWaitNodeGetParams_v11020_params_st { + cudaGraphNode_t hNode; + struct cudaExternalSemaphoreWaitNodeParams *params_out; +} cudaGraphExternalSemaphoresWaitNodeGetParams_v11020_params; + +typedef struct cudaGraphExternalSemaphoresWaitNodeSetParams_v11020_params_st { + cudaGraphNode_t hNode; + const struct cudaExternalSemaphoreWaitNodeParams *nodeParams; +} cudaGraphExternalSemaphoresWaitNodeSetParams_v11020_params; + +typedef struct cudaGraphAddMemAllocNode_v11040_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + struct cudaMemAllocNodeParams *nodeParams; +} cudaGraphAddMemAllocNode_v11040_params; + +typedef struct cudaGraphMemAllocNodeGetParams_v11040_params_st { + cudaGraphNode_t node; + struct cudaMemAllocNodeParams *params_out; +} cudaGraphMemAllocNodeGetParams_v11040_params; + +typedef struct cudaGraphAddMemFreeNode_v11040_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + void *dptr; +} cudaGraphAddMemFreeNode_v11040_params; + +typedef struct cudaGraphMemFreeNodeGetParams_v11040_params_st { + cudaGraphNode_t node; + void *dptr_out; +} cudaGraphMemFreeNodeGetParams_v11040_params; + +typedef struct cudaDeviceGraphMemTrim_v11040_params_st { + int device; +} cudaDeviceGraphMemTrim_v11040_params; + +typedef struct cudaDeviceGetGraphMemAttribute_v11040_params_st { + int device; + enum cudaGraphMemAttributeType attr; + void *value; +} cudaDeviceGetGraphMemAttribute_v11040_params; + +typedef struct cudaDeviceSetGraphMemAttribute_v11040_params_st { + int device; + enum cudaGraphMemAttributeType attr; + void *value; +} cudaDeviceSetGraphMemAttribute_v11040_params; + +typedef struct cudaGraphClone_v10000_params_st { + cudaGraph_t *pGraphClone; + cudaGraph_t originalGraph; +} cudaGraphClone_v10000_params; + +typedef struct cudaGraphNodeFindInClone_v10000_params_st { + cudaGraphNode_t *pNode; + cudaGraphNode_t originalNode; + cudaGraph_t clonedGraph; +} cudaGraphNodeFindInClone_v10000_params; + +typedef struct cudaGraphNodeGetType_v10000_params_st { + cudaGraphNode_t node; + enum cudaGraphNodeType *pType; +} cudaGraphNodeGetType_v10000_params; + +typedef struct cudaGraphGetNodes_v10000_params_st { + cudaGraph_t graph; + cudaGraphNode_t *nodes; + size_t *numNodes; +} cudaGraphGetNodes_v10000_params; + +typedef struct cudaGraphGetRootNodes_v10000_params_st { + cudaGraph_t graph; + cudaGraphNode_t *pRootNodes; + size_t *pNumRootNodes; +} cudaGraphGetRootNodes_v10000_params; + +typedef struct cudaGraphGetEdges_v10000_params_st { + cudaGraph_t graph; + cudaGraphNode_t *from; + cudaGraphNode_t *to; + size_t *numEdges; +} cudaGraphGetEdges_v10000_params; + +typedef struct cudaGraphGetEdges_v2_v12030_params_st { + cudaGraph_t graph; + cudaGraphNode_t *from; + cudaGraphNode_t *to; + cudaGraphEdgeData *edgeData; + size_t *numEdges; +} cudaGraphGetEdges_v2_v12030_params; + +typedef struct cudaGraphNodeGetDependencies_v10000_params_st { + cudaGraphNode_t node; + cudaGraphNode_t *pDependencies; + size_t *pNumDependencies; +} cudaGraphNodeGetDependencies_v10000_params; + +typedef struct cudaGraphNodeGetDependencies_v2_v12030_params_st { + cudaGraphNode_t node; + cudaGraphNode_t *pDependencies; + cudaGraphEdgeData *edgeData; + size_t *pNumDependencies; +} cudaGraphNodeGetDependencies_v2_v12030_params; + +typedef struct cudaGraphNodeGetDependentNodes_v10000_params_st { + cudaGraphNode_t node; + cudaGraphNode_t *pDependentNodes; + size_t *pNumDependentNodes; +} cudaGraphNodeGetDependentNodes_v10000_params; + +typedef struct cudaGraphNodeGetDependentNodes_v2_v12030_params_st { + cudaGraphNode_t node; + cudaGraphNode_t *pDependentNodes; + cudaGraphEdgeData *edgeData; + size_t *pNumDependentNodes; +} cudaGraphNodeGetDependentNodes_v2_v12030_params; + +typedef struct cudaGraphAddDependencies_v10000_params_st { + cudaGraph_t graph; + const cudaGraphNode_t *from; + const cudaGraphNode_t *to; + size_t numDependencies; +} cudaGraphAddDependencies_v10000_params; + +typedef struct cudaGraphAddDependencies_v2_v12030_params_st { + cudaGraph_t graph; + const cudaGraphNode_t *from; + const cudaGraphNode_t *to; + const cudaGraphEdgeData *edgeData; + size_t numDependencies; +} cudaGraphAddDependencies_v2_v12030_params; + +typedef struct cudaGraphRemoveDependencies_v10000_params_st { + cudaGraph_t graph; + const cudaGraphNode_t *from; + const cudaGraphNode_t *to; + size_t numDependencies; +} cudaGraphRemoveDependencies_v10000_params; + +typedef struct cudaGraphRemoveDependencies_v2_v12030_params_st { + cudaGraph_t graph; + const cudaGraphNode_t *from; + const cudaGraphNode_t *to; + const cudaGraphEdgeData *edgeData; + size_t numDependencies; +} cudaGraphRemoveDependencies_v2_v12030_params; + +typedef struct cudaGraphDestroyNode_v10000_params_st { + cudaGraphNode_t node; +} cudaGraphDestroyNode_v10000_params; + +typedef struct cudaGraphInstantiate_v12000_params_st { + cudaGraphExec_t *pGraphExec; + cudaGraph_t graph; + unsigned long long flags; +} cudaGraphInstantiate_v12000_params; + +typedef struct cudaGraphInstantiateWithFlags_v11040_params_st { + cudaGraphExec_t *pGraphExec; + cudaGraph_t graph; + unsigned long long flags; +} cudaGraphInstantiateWithFlags_v11040_params; + +typedef struct cudaGraphInstantiateWithParams_ptsz_v12000_params_st { + cudaGraphExec_t *pGraphExec; + cudaGraph_t graph; + cudaGraphInstantiateParams *instantiateParams; +} cudaGraphInstantiateWithParams_ptsz_v12000_params; + +typedef struct cudaGraphExecGetFlags_v12000_params_st { + cudaGraphExec_t graphExec; + unsigned long long *flags; +} cudaGraphExecGetFlags_v12000_params; + +typedef struct cudaGraphExecKernelNodeSetParams_v10010_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t node; + const struct cudaKernelNodeParams *pNodeParams; +} cudaGraphExecKernelNodeSetParams_v10010_params; + +typedef struct cudaGraphExecMemcpyNodeSetParams_v10020_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t node; + const struct cudaMemcpy3DParms *pNodeParams; +} cudaGraphExecMemcpyNodeSetParams_v10020_params; + +typedef struct cudaGraphExecMemcpyNodeSetParamsToSymbol_v11010_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t node; + const void *symbol; + const void *src; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaGraphExecMemcpyNodeSetParamsToSymbol_v11010_params; + +typedef struct cudaGraphExecMemcpyNodeSetParamsFromSymbol_v11010_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t node; + void *dst; + const void *symbol; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaGraphExecMemcpyNodeSetParamsFromSymbol_v11010_params; + +typedef struct cudaGraphExecMemcpyNodeSetParams1D_v11010_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t node; + void *dst; + const void *src; + size_t count; + enum cudaMemcpyKind kind; +} cudaGraphExecMemcpyNodeSetParams1D_v11010_params; + +typedef struct cudaGraphExecMemsetNodeSetParams_v10020_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t node; + const struct cudaMemsetParams *pNodeParams; +} cudaGraphExecMemsetNodeSetParams_v10020_params; + +typedef struct cudaGraphExecHostNodeSetParams_v10020_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t node; + const struct cudaHostNodeParams *pNodeParams; +} cudaGraphExecHostNodeSetParams_v10020_params; + +typedef struct cudaGraphExecChildGraphNodeSetParams_v11010_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t node; + cudaGraph_t childGraph; +} cudaGraphExecChildGraphNodeSetParams_v11010_params; + +typedef struct cudaGraphExecEventRecordNodeSetEvent_v11010_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t hNode; + cudaEvent_t event; +} cudaGraphExecEventRecordNodeSetEvent_v11010_params; + +typedef struct cudaGraphExecEventWaitNodeSetEvent_v11010_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t hNode; + cudaEvent_t event; +} cudaGraphExecEventWaitNodeSetEvent_v11010_params; + +typedef struct cudaGraphExecExternalSemaphoresSignalNodeSetParams_v11020_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t hNode; + const struct cudaExternalSemaphoreSignalNodeParams *nodeParams; +} cudaGraphExecExternalSemaphoresSignalNodeSetParams_v11020_params; + +typedef struct cudaGraphExecExternalSemaphoresWaitNodeSetParams_v11020_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t hNode; + const struct cudaExternalSemaphoreWaitNodeParams *nodeParams; +} cudaGraphExecExternalSemaphoresWaitNodeSetParams_v11020_params; + +typedef struct cudaGraphNodeSetEnabled_v11060_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t hNode; + unsigned int isEnabled; +} cudaGraphNodeSetEnabled_v11060_params; + +typedef struct cudaGraphNodeGetEnabled_v11060_params_st { + cudaGraphExec_t hGraphExec; + cudaGraphNode_t hNode; + unsigned int *isEnabled; +} cudaGraphNodeGetEnabled_v11060_params; + +typedef struct cudaGraphExecUpdate_v10020_params_st { + cudaGraphExec_t hGraphExec; + cudaGraph_t hGraph; + cudaGraphExecUpdateResultInfo *resultInfo; +} cudaGraphExecUpdate_v10020_params; + +typedef struct cudaGraphUpload_ptsz_v10000_params_st { + cudaGraphExec_t graphExec; + cudaStream_t stream; +} cudaGraphUpload_ptsz_v10000_params; + +typedef struct cudaGraphLaunch_ptsz_v10000_params_st { + cudaGraphExec_t graphExec; + cudaStream_t stream; +} cudaGraphLaunch_ptsz_v10000_params; + +typedef struct cudaGraphExecDestroy_v10000_params_st { + cudaGraphExec_t graphExec; +} cudaGraphExecDestroy_v10000_params; + +typedef struct cudaGraphDestroy_v10000_params_st { + cudaGraph_t graph; +} cudaGraphDestroy_v10000_params; + +typedef struct cudaGraphDebugDotPrint_v11030_params_st { + cudaGraph_t graph; + const char *path; + unsigned int flags; +} cudaGraphDebugDotPrint_v11030_params; + +typedef struct cudaUserObjectCreate_v11030_params_st { + cudaUserObject_t *object_out; + void *ptr; + cudaHostFn_t destroy; + unsigned int initialRefcount; + unsigned int flags; +} cudaUserObjectCreate_v11030_params; + +typedef struct cudaUserObjectRetain_v11030_params_st { + cudaUserObject_t object; + unsigned int count; +} cudaUserObjectRetain_v11030_params; + +typedef struct cudaUserObjectRelease_v11030_params_st { + cudaUserObject_t object; + unsigned int count; +} cudaUserObjectRelease_v11030_params; + +typedef struct cudaGraphRetainUserObject_v11030_params_st { + cudaGraph_t graph; + cudaUserObject_t object; + unsigned int count; + unsigned int flags; +} cudaGraphRetainUserObject_v11030_params; + +typedef struct cudaGraphReleaseUserObject_v11030_params_st { + cudaGraph_t graph; + cudaUserObject_t object; + unsigned int count; +} cudaGraphReleaseUserObject_v11030_params; + +typedef struct cudaGraphAddNode_v12020_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + size_t numDependencies; + struct cudaGraphNodeParams *nodeParams; +} cudaGraphAddNode_v12020_params; + +typedef struct cudaGraphAddNode_v2_v12030_params_st { + cudaGraphNode_t *pGraphNode; + cudaGraph_t graph; + const cudaGraphNode_t *pDependencies; + const cudaGraphEdgeData *dependencyData; + size_t numDependencies; + struct cudaGraphNodeParams *nodeParams; +} cudaGraphAddNode_v2_v12030_params; + +typedef struct cudaGraphNodeSetParams_v12020_params_st { + cudaGraphNode_t node; + struct cudaGraphNodeParams *nodeParams; +} cudaGraphNodeSetParams_v12020_params; + +typedef struct cudaGraphExecNodeSetParams_v12020_params_st { + cudaGraphExec_t graphExec; + cudaGraphNode_t node; + struct cudaGraphNodeParams *nodeParams; +} cudaGraphExecNodeSetParams_v12020_params; + +typedef struct cudaGraphConditionalHandleCreate_v12030_params_st { + cudaGraphConditionalHandle *pHandle_out; + cudaGraph_t graph; + unsigned int defaultLaunchValue; + unsigned int flags; +} cudaGraphConditionalHandleCreate_v12030_params; + +typedef struct cudaGetDriverEntryPoint_ptsz_v11030_params_st { + const char *symbol; + void **funcPtr; + unsigned long long flags; + enum cudaDriverEntryPointQueryResult *driverStatus; +} cudaGetDriverEntryPoint_ptsz_v11030_params; + +typedef struct cudaGetDriverEntryPointByVersion_ptsz_v12050_params_st { + const char *symbol; + void **funcPtr; + unsigned int cudaVersion; + unsigned long long flags; + enum cudaDriverEntryPointQueryResult *driverStatus; +} cudaGetDriverEntryPointByVersion_ptsz_v12050_params; + +typedef struct cudaGetFuncBySymbol_v11000_params_st { + cudaFunction_t *functionPtr; + const void *symbolPtr; +} cudaGetFuncBySymbol_v11000_params; + +typedef struct cudaGetKernel_v12000_params_st { + cudaKernel_t *kernelPtr; + const void *entryFuncAddr; +} cudaGetKernel_v12000_params; + +typedef struct cudaMemcpy_v3020_params_st { + void *dst; + const void *src; + size_t count; + enum cudaMemcpyKind kind; +} cudaMemcpy_v3020_params; + +typedef struct cudaMemcpyToSymbol_v3020_params_st { + const void *symbol; + const void *src; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaMemcpyToSymbol_v3020_params; + +typedef struct cudaMemcpyFromSymbol_v3020_params_st { + void *dst; + const void *symbol; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; +} cudaMemcpyFromSymbol_v3020_params; + +typedef struct cudaMemcpy2D_v3020_params_st { + void *dst; + size_t dpitch; + const void *src; + size_t spitch; + size_t width; + size_t height; + enum cudaMemcpyKind kind; +} cudaMemcpy2D_v3020_params; + +typedef struct cudaMemcpyToArray_v3020_params_st { + cudaArray_t dst; + size_t wOffset; + size_t hOffset; + const void *src; + size_t count; + enum cudaMemcpyKind kind; +} cudaMemcpyToArray_v3020_params; + +typedef struct cudaMemcpy2DToArray_v3020_params_st { + cudaArray_t dst; + size_t wOffset; + size_t hOffset; + const void *src; + size_t spitch; + size_t width; + size_t height; + enum cudaMemcpyKind kind; +} cudaMemcpy2DToArray_v3020_params; + +typedef struct cudaMemcpyFromArray_v3020_params_st { + void *dst; + cudaArray_const_t src; + size_t wOffset; + size_t hOffset; + size_t count; + enum cudaMemcpyKind kind; +} cudaMemcpyFromArray_v3020_params; + +typedef struct cudaMemcpy2DFromArray_v3020_params_st { + void *dst; + size_t dpitch; + cudaArray_const_t src; + size_t wOffset; + size_t hOffset; + size_t width; + size_t height; + enum cudaMemcpyKind kind; +} cudaMemcpy2DFromArray_v3020_params; + +typedef struct cudaMemcpyArrayToArray_v3020_params_st { + cudaArray_t dst; + size_t wOffsetDst; + size_t hOffsetDst; + cudaArray_const_t src; + size_t wOffsetSrc; + size_t hOffsetSrc; + size_t count; + enum cudaMemcpyKind kind; +} cudaMemcpyArrayToArray_v3020_params; + +typedef struct cudaMemcpy2DArrayToArray_v3020_params_st { + cudaArray_t dst; + size_t wOffsetDst; + size_t hOffsetDst; + cudaArray_const_t src; + size_t wOffsetSrc; + size_t hOffsetSrc; + size_t width; + size_t height; + enum cudaMemcpyKind kind; +} cudaMemcpy2DArrayToArray_v3020_params; + +typedef struct cudaMemcpy3D_v3020_params_st { + const struct cudaMemcpy3DParms *p; +} cudaMemcpy3D_v3020_params; + +typedef struct cudaMemcpy3DPeer_v4000_params_st { + const struct cudaMemcpy3DPeerParms *p; +} cudaMemcpy3DPeer_v4000_params; + +typedef struct cudaMemcpyBatchAsync_v12080_params_st { + void **dsts; + void **srcs; + size_t *sizes; + size_t count; + struct cudaMemcpyAttributes *attrs; + size_t *attrsIdxs; + size_t numAttrs; + size_t *failIdx; + cudaStream_t stream; +} cudaMemcpyBatchAsync_v12080_params; + +typedef struct cudaMemcpy3DBatchAsync_v12080_params_st { + size_t numOps; + struct cudaMemcpy3DBatchOp *opList; + size_t *failIdx; + unsigned long long flags; + cudaStream_t stream; +} cudaMemcpy3DBatchAsync_v12080_params; + +typedef struct cudaMemset_v3020_params_st { + void *devPtr; + int value; + size_t count; +} cudaMemset_v3020_params; + +typedef struct cudaMemset2D_v3020_params_st { + void *devPtr; + size_t pitch; + int value; + size_t width; + size_t height; +} cudaMemset2D_v3020_params; + +typedef struct cudaMemset3D_v3020_params_st { + struct cudaPitchedPtr pitchedDevPtr; + int value; + struct cudaExtent extent; +} cudaMemset3D_v3020_params; + +typedef struct cudaMemcpyAsync_v3020_params_st { + void *dst; + const void *src; + size_t count; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyAsync_v3020_params; + +typedef struct cudaMemcpyToSymbolAsync_v3020_params_st { + const void *symbol; + const void *src; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyToSymbolAsync_v3020_params; + +typedef struct cudaMemcpyFromSymbolAsync_v3020_params_st { + void *dst; + const void *symbol; + size_t count; + size_t offset; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyFromSymbolAsync_v3020_params; + +typedef struct cudaMemcpy2DAsync_v3020_params_st { + void *dst; + size_t dpitch; + const void *src; + size_t spitch; + size_t width; + size_t height; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpy2DAsync_v3020_params; + +typedef struct cudaMemcpyToArrayAsync_v3020_params_st { + cudaArray_t dst; + size_t wOffset; + size_t hOffset; + const void *src; + size_t count; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyToArrayAsync_v3020_params; + +typedef struct cudaMemcpy2DToArrayAsync_v3020_params_st { + cudaArray_t dst; + size_t wOffset; + size_t hOffset; + const void *src; + size_t spitch; + size_t width; + size_t height; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpy2DToArrayAsync_v3020_params; + +typedef struct cudaMemcpyFromArrayAsync_v3020_params_st { + void *dst; + cudaArray_const_t src; + size_t wOffset; + size_t hOffset; + size_t count; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpyFromArrayAsync_v3020_params; + +typedef struct cudaMemcpy2DFromArrayAsync_v3020_params_st { + void *dst; + size_t dpitch; + cudaArray_const_t src; + size_t wOffset; + size_t hOffset; + size_t width; + size_t height; + enum cudaMemcpyKind kind; + cudaStream_t stream; +} cudaMemcpy2DFromArrayAsync_v3020_params; + +typedef struct cudaMemcpy3DAsync_v3020_params_st { + const struct cudaMemcpy3DParms *p; + cudaStream_t stream; +} cudaMemcpy3DAsync_v3020_params; + +typedef struct cudaMemcpy3DPeerAsync_v4000_params_st { + const struct cudaMemcpy3DPeerParms *p; + cudaStream_t stream; +} cudaMemcpy3DPeerAsync_v4000_params; + +typedef struct cudaMemsetAsync_v3020_params_st { + void *devPtr; + int value; + size_t count; + cudaStream_t stream; +} cudaMemsetAsync_v3020_params; + +typedef struct cudaMemset2DAsync_v3020_params_st { + void *devPtr; + size_t pitch; + int value; + size_t width; + size_t height; + cudaStream_t stream; +} cudaMemset2DAsync_v3020_params; + +typedef struct cudaMemset3DAsync_v3020_params_st { + struct cudaPitchedPtr pitchedDevPtr; + int value; + struct cudaExtent extent; + cudaStream_t stream; +} cudaMemset3DAsync_v3020_params; + +typedef struct cudaStreamQuery_v3020_params_st { + cudaStream_t stream; +} cudaStreamQuery_v3020_params; + +typedef struct cudaStreamGetDevice_v12080_params_st { + cudaStream_t hStream; + int *device; +} cudaStreamGetDevice_v12080_params; + +typedef struct cudaStreamGetFlags_v5050_params_st { + cudaStream_t hStream; + unsigned int *flags; +} cudaStreamGetFlags_v5050_params; + +typedef struct cudaStreamGetId_v12000_params_st { + cudaStream_t hStream; + unsigned long long *streamId; +} cudaStreamGetId_v12000_params; + +typedef struct cudaStreamGetPriority_v5050_params_st { + cudaStream_t hStream; + int *priority; +} cudaStreamGetPriority_v5050_params; + +typedef struct cudaEventRecord_v3020_params_st { + cudaEvent_t event; + cudaStream_t stream; +} cudaEventRecord_v3020_params; + +typedef struct cudaEventRecordWithFlags_v11010_params_st { + cudaEvent_t event; + cudaStream_t stream; + unsigned int flags; +} cudaEventRecordWithFlags_v11010_params; + +typedef struct cudaStreamWaitEvent_v3020_params_st { + cudaStream_t stream; + cudaEvent_t event; + unsigned int flags; +} cudaStreamWaitEvent_v3020_params; + +typedef struct cudaStreamAddCallback_v5000_params_st { + cudaStream_t stream; + cudaStreamCallback_t callback; + void *userData; + unsigned int flags; +} cudaStreamAddCallback_v5000_params; + +typedef struct cudaStreamAttachMemAsync_v6000_params_st { + cudaStream_t stream; + void *devPtr; + size_t length; + unsigned int flags; +} cudaStreamAttachMemAsync_v6000_params; + +typedef struct cudaStreamSynchronize_v3020_params_st { + cudaStream_t stream; +} cudaStreamSynchronize_v3020_params; + +typedef struct cudaLaunchKernel_v7000_params_st { + const void *func; + dim3 gridDim; + dim3 blockDim; + void **args; + size_t sharedMem; + cudaStream_t stream; +} cudaLaunchKernel_v7000_params; + +typedef struct cudaLaunchKernelExC_v11060_params_st { + const cudaLaunchConfig_t *config; + const void *func; + void **args; +} cudaLaunchKernelExC_v11060_params; + +typedef struct cudaLaunchCooperativeKernel_v9000_params_st { + const void *func; + dim3 gridDim; + dim3 blockDim; + void **args; + size_t sharedMem; + cudaStream_t stream; +} cudaLaunchCooperativeKernel_v9000_params; + +typedef struct cudaLaunchHostFunc_v10000_params_st { + cudaStream_t stream; + cudaHostFn_t fn; + void *userData; +} cudaLaunchHostFunc_v10000_params; + +typedef struct cudaMemPrefetchAsync_v8000_params_st { + const void *devPtr; + size_t count; + int dstDevice; + cudaStream_t stream; +} cudaMemPrefetchAsync_v8000_params; + +typedef struct cudaMemPrefetchAsync_v2_v12020_params_st { + const void *devPtr; + size_t count; + struct cudaMemLocation location; + unsigned int flags; + cudaStream_t stream; +} cudaMemPrefetchAsync_v2_v12020_params; + +typedef struct cudaSignalExternalSemaphoresAsync_v10000_params_st { + const cudaExternalSemaphore_t *extSemArray; + const struct cudaExternalSemaphoreSignalParams_v1 *paramsArray; + unsigned int numExtSems; + cudaStream_t stream; +} cudaSignalExternalSemaphoresAsync_v10000_params; + +typedef struct cudaSignalExternalSemaphoresAsync_ptsz_v10000_params_st { + const cudaExternalSemaphore_t *extSemArray; + const struct cudaExternalSemaphoreSignalParams_v1 *paramsArray; + unsigned int numExtSems; + cudaStream_t stream; +} cudaSignalExternalSemaphoresAsync_ptsz_v10000_params; + +typedef struct cudaSignalExternalSemaphoresAsync_v2_v11020_params_st { + const cudaExternalSemaphore_t *extSemArray; + const struct cudaExternalSemaphoreSignalParams *paramsArray; + unsigned int numExtSems; + cudaStream_t stream; +} cudaSignalExternalSemaphoresAsync_v2_v11020_params; + +typedef struct cudaWaitExternalSemaphoresAsync_v10000_params_st { + const cudaExternalSemaphore_t *extSemArray; + const struct cudaExternalSemaphoreWaitParams_v1 *paramsArray; + unsigned int numExtSems; + cudaStream_t stream; +} cudaWaitExternalSemaphoresAsync_v10000_params; + +typedef struct cudaWaitExternalSemaphoresAsync_ptsz_v10000_params_st { + const cudaExternalSemaphore_t *extSemArray; + const struct cudaExternalSemaphoreWaitParams_v1 *paramsArray; + unsigned int numExtSems; + cudaStream_t stream; +} cudaWaitExternalSemaphoresAsync_ptsz_v10000_params; + +typedef struct cudaWaitExternalSemaphoresAsync_v2_v11020_params_st { + const cudaExternalSemaphore_t *extSemArray; + const struct cudaExternalSemaphoreWaitParams *paramsArray; + unsigned int numExtSems; + cudaStream_t stream; +} cudaWaitExternalSemaphoresAsync_v2_v11020_params; + +typedef struct cudaGraphInstantiateWithParams_v12000_params_st { + cudaGraphExec_t *pGraphExec; + cudaGraph_t graph; + cudaGraphInstantiateParams *instantiateParams; +} cudaGraphInstantiateWithParams_v12000_params; + +typedef struct cudaGraphUpload_v10000_params_st { + cudaGraphExec_t graphExec; + cudaStream_t stream; +} cudaGraphUpload_v10000_params; + +typedef struct cudaGraphLaunch_v10000_params_st { + cudaGraphExec_t graphExec; + cudaStream_t stream; +} cudaGraphLaunch_v10000_params; + +typedef struct cudaStreamBeginCapture_v10000_params_st { + cudaStream_t stream; + enum cudaStreamCaptureMode mode; +} cudaStreamBeginCapture_v10000_params; + +typedef struct cudaStreamBeginCaptureToGraph_v12030_params_st { + cudaStream_t stream; + cudaGraph_t graph; + const cudaGraphNode_t *dependencies; + const cudaGraphEdgeData *dependencyData; + size_t numDependencies; + enum cudaStreamCaptureMode mode; +} cudaStreamBeginCaptureToGraph_v12030_params; + +typedef struct cudaStreamEndCapture_v10000_params_st { + cudaStream_t stream; + cudaGraph_t *pGraph; +} cudaStreamEndCapture_v10000_params; + +typedef struct cudaStreamIsCapturing_v10000_params_st { + cudaStream_t stream; + enum cudaStreamCaptureStatus *pCaptureStatus; +} cudaStreamIsCapturing_v10000_params; + +typedef struct cudaStreamGetCaptureInfo_v10010_params_st { + cudaStream_t stream; + enum cudaStreamCaptureStatus *captureStatus_out; + unsigned long long *id_out; +} cudaStreamGetCaptureInfo_v10010_params; + +typedef struct cudaStreamGetCaptureInfo_ptsz_v10010_params_st { + cudaStream_t stream; + enum cudaStreamCaptureStatus *captureStatus_out; + unsigned long long *id_out; +} cudaStreamGetCaptureInfo_ptsz_v10010_params; + +typedef struct cudaStreamGetCaptureInfo_v2_v11030_params_st { + cudaStream_t stream; + enum cudaStreamCaptureStatus *captureStatus_out; + unsigned long long *id_out; + cudaGraph_t *graph_out; + const cudaGraphNode_t **dependencies_out; + size_t *numDependencies_out; +} cudaStreamGetCaptureInfo_v2_v11030_params; + +typedef struct cudaStreamGetCaptureInfo_v3_v12030_params_st { + cudaStream_t stream; + enum cudaStreamCaptureStatus *captureStatus_out; + unsigned long long *id_out; + cudaGraph_t *graph_out; + const cudaGraphNode_t **dependencies_out; + const cudaGraphEdgeData **edgeData_out; + size_t *numDependencies_out; +} cudaStreamGetCaptureInfo_v3_v12030_params; + +typedef struct cudaStreamUpdateCaptureDependencies_v11030_params_st { + cudaStream_t stream; + cudaGraphNode_t *dependencies; + size_t numDependencies; + unsigned int flags; +} cudaStreamUpdateCaptureDependencies_v11030_params; + +typedef struct cudaStreamUpdateCaptureDependencies_v2_v12030_params_st { + cudaStream_t stream; + cudaGraphNode_t *dependencies; + const cudaGraphEdgeData *dependencyData; + size_t numDependencies; + unsigned int flags; +} cudaStreamUpdateCaptureDependencies_v2_v12030_params; + +typedef struct cudaStreamCopyAttributes_v11000_params_st { + cudaStream_t dstStream; + cudaStream_t srcStream; +} cudaStreamCopyAttributes_v11000_params; + +typedef struct cudaStreamGetAttribute_v11000_params_st { + cudaStream_t stream; + cudaStreamAttrID attr; + cudaStreamAttrValue *value; +} cudaStreamGetAttribute_v11000_params; + +typedef struct cudaStreamSetAttribute_v11000_params_st { + cudaStream_t stream; + cudaStreamAttrID attr; + const cudaStreamAttrValue *param; +} cudaStreamSetAttribute_v11000_params; + +typedef struct cudaMallocAsync_v11020_params_st { + void **devPtr; + size_t size; + cudaStream_t hStream; +} cudaMallocAsync_v11020_params; + +typedef struct cudaFreeAsync_v11020_params_st { + void *devPtr; + cudaStream_t hStream; +} cudaFreeAsync_v11020_params; + +typedef struct cudaMallocFromPoolAsync_v11020_params_st { + void **ptr; + size_t size; + cudaMemPool_t memPool; + cudaStream_t stream; +} cudaMallocFromPoolAsync_v11020_params; + +typedef struct cudaGetDriverEntryPoint_v11030_params_st { + const char *symbol; + void **funcPtr; + unsigned long long flags; + enum cudaDriverEntryPointQueryResult *driverStatus; +} cudaGetDriverEntryPoint_v11030_params; + +typedef struct cudaGetDriverEntryPointByVersion_v12050_params_st { + const char *symbol; + void **funcPtr; + unsigned int cudaVersion; + unsigned long long flags; + enum cudaDriverEntryPointQueryResult *driverStatus; +} cudaGetDriverEntryPointByVersion_v12050_params; + +typedef struct cudaGetDeviceProperties_v3020_params_st { + struct cudaDeviceProp *prop; + int device; +} cudaGetDeviceProperties_v3020_params; + +// Parameter trace structures for removed functions + + +// End of parameter trace structures diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_vdpau_interop_meta.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_vdpau_interop_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..88e79d1957925c4bbacd381e9461d5072de88f24 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cuda_vdpau_interop_meta.h @@ -0,0 +1,38 @@ +// This file is generated. Any changes you make will be lost during the next clean build. + +// CUDA public interface, for type definitions and api function prototypes +#include "cuda_vdpau_interop.h" + +// ************************************************************************* +// Definitions of structs to hold parameters for each function +// ************************************************************************* + +// Currently used parameter trace structures +typedef struct cudaVDPAUGetDevice_v3020_params_st { + int *device; + VdpDevice vdpDevice; + VdpGetProcAddress *vdpGetProcAddress; +} cudaVDPAUGetDevice_v3020_params; + +typedef struct cudaVDPAUSetVDPAUDevice_v3020_params_st { + int device; + VdpDevice vdpDevice; + VdpGetProcAddress *vdpGetProcAddress; +} cudaVDPAUSetVDPAUDevice_v3020_params; + +typedef struct cudaGraphicsVDPAURegisterVideoSurface_v3020_params_st { + struct cudaGraphicsResource **resource; + VdpVideoSurface vdpSurface; + unsigned int flags; +} cudaGraphicsVDPAURegisterVideoSurface_v3020_params; + +typedef struct cudaGraphicsVDPAURegisterOutputSurface_v3020_params_st { + struct cudaGraphicsResource **resource; + VdpOutputSurface vdpSurface; + unsigned int flags; +} cudaGraphicsVDPAURegisterOutputSurface_v3020_params; + +// Parameter trace structures for removed functions + + +// End of parameter trace structures diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudart_removed_meta.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudart_removed_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..a0fc27a71bb3fc883db9fe7562eea3f28145430d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_cudart_removed_meta.h @@ -0,0 +1,162 @@ +// This file is generated. Any changes you make will be lost during the next clean build. + +// CUDA public interface, for type definitions and api function prototypes +#include "cudart_removed.h" + +// ************************************************************************* +// Definitions of structs to hold parameters for each function +// ************************************************************************* + +// Currently used parameter trace structures +typedef struct cudaStreamDestroy_v3020_params_st { + cudaStream_t stream; +} cudaStreamDestroy_v3020_params; + +typedef struct cudaOccupancyMaxActiveBlocksPerMultiprocessor_v6000_params_st { + int *numBlocks; + const void *func; + size_t numDynamicSmemBytes; +} cudaOccupancyMaxActiveBlocksPerMultiprocessor_v6000_params; + +typedef struct cudaConfigureCall_v3020_params_st { + dim3 gridDim; + dim3 blockDim; + size_t sharedMem __dv; + cudaStream_t stream __dv; +} cudaConfigureCall_v3020_params; + +typedef struct cudaSetupArgument_v3020_params_st { + const void *arg; + size_t size; + size_t offset; +} cudaSetupArgument_v3020_params; + +typedef struct cudaLaunch_v3020_params_st { + const void *func; +} cudaLaunch_v3020_params; + +typedef struct cudaLaunch_ptsz_v7000_params_st { + const void *func; +} cudaLaunch_ptsz_v7000_params; + +typedef struct cudaStreamSetFlags_v10200_params_st { + cudaStream_t hStream; + unsigned int flags; +} cudaStreamSetFlags_v10200_params; + +typedef struct cudaStreamSetFlags_ptsz_v10200_params_st { + cudaStream_t hStream; + unsigned int flags; +} cudaStreamSetFlags_ptsz_v10200_params; + +typedef struct cudaProfilerInitialize_v4000_params_st { + const char *configFile; + const char *outputFile; + cudaOutputMode_t outputMode; +} cudaProfilerInitialize_v4000_params; + +typedef struct cudaThreadSetLimit_v3020_params_st { + enum cudaLimit limit; + size_t value; +} cudaThreadSetLimit_v3020_params; + +typedef struct cudaThreadGetLimit_v3020_params_st { + size_t *pValue; + enum cudaLimit limit; +} cudaThreadGetLimit_v3020_params; + +typedef struct cudaThreadGetCacheConfig_v3020_params_st { + enum cudaFuncCache *pCacheConfig; +} cudaThreadGetCacheConfig_v3020_params; + +typedef struct cudaThreadSetCacheConfig_v3020_params_st { + enum cudaFuncCache cacheConfig; +} cudaThreadSetCacheConfig_v3020_params; + +typedef struct cudaSetDoubleForDevice_v3020_params_st { + double *d; +} cudaSetDoubleForDevice_v3020_params; + +typedef struct cudaSetDoubleForHost_v3020_params_st { + double *d; +} cudaSetDoubleForHost_v3020_params; + +typedef struct cudaCreateTextureObject_v2_v11080_params_st { + cudaTextureObject_t *pTexObject; + const struct cudaResourceDesc *pResDesc; + const struct cudaTextureDesc *pTexDesc; + const struct cudaResourceViewDesc *pResViewDesc; +} cudaCreateTextureObject_v2_v11080_params; + +typedef struct cudaGetTextureObjectTextureDesc_v2_v11080_params_st { + struct cudaTextureDesc *pTexDesc; + cudaTextureObject_t texObject; +} cudaGetTextureObjectTextureDesc_v2_v11080_params; + +typedef struct cudaBindTexture_v3020_params_st { + size_t *offset; + const struct textureReference *texref; + const void *devPtr; + const struct cudaChannelFormatDesc *desc; + size_t size __dv; +} cudaBindTexture_v3020_params; + +typedef struct cudaBindTexture2D_v3020_params_st { + size_t *offset; + const struct textureReference *texref; + const void *devPtr; + const struct cudaChannelFormatDesc *desc; + size_t width; + size_t height; + size_t pitch; +} cudaBindTexture2D_v3020_params; + +typedef struct cudaBindTextureToArray_v3020_params_st { + const struct textureReference *texref; + cudaArray_const_t array; + const struct cudaChannelFormatDesc *desc; +} cudaBindTextureToArray_v3020_params; + +typedef struct cudaBindTextureToMipmappedArray_v5000_params_st { + const struct textureReference *texref; + cudaMipmappedArray_const_t mipmappedArray; + const struct cudaChannelFormatDesc *desc; +} cudaBindTextureToMipmappedArray_v5000_params; + +typedef struct cudaUnbindTexture_v3020_params_st { + const struct textureReference *texref; +} cudaUnbindTexture_v3020_params; + +typedef struct cudaGetTextureAlignmentOffset_v3020_params_st { + size_t *offset; + const struct textureReference *texref; +} cudaGetTextureAlignmentOffset_v3020_params; + +typedef struct cudaGetTextureReference_v3020_params_st { + const struct textureReference **texref; + const void *symbol; +} cudaGetTextureReference_v3020_params; + +typedef struct cudaBindSurfaceToArray_v3020_params_st { + const struct surfaceReference *surfref; + cudaArray_const_t array; + const struct cudaChannelFormatDesc *desc; +} cudaBindSurfaceToArray_v3020_params; + +typedef struct cudaGetSurfaceReference_v3020_params_st { + const struct surfaceReference **surfref; + const void *symbol; +} cudaGetSurfaceReference_v3020_params; + +typedef struct cudaGraphInstantiate_v10000_params_st { + cudaGraphExec_t *pGraphExec; + cudaGraph_t graph; + cudaGraphNode_t *pErrorNode; + char *pLogBuffer; + size_t bufferSize; +} cudaGraphInstantiate_v10000_params; + +// Parameter trace structures for removed functions + + +// End of parameter trace structures diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_nvtx_meta.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_nvtx_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..ed8877e21f0651fe1564151090850694eb495cfb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/generated_nvtx_meta.h @@ -0,0 +1,247 @@ +/* + * Copyright 2013-2018 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility push(default) +#endif + +// ************************************************************************* +// Definitions of structs to hold parameters for each function +// ************************************************************************* + +typedef struct nvtxMarkEx_params_st { + const nvtxEventAttributes_t* eventAttrib; +} nvtxMarkEx_params; + +typedef struct nvtxMarkA_params_st { + const char* message; +} nvtxMarkA_params; + +typedef struct nvtxMarkW_params_st { + const wchar_t* message; +} nvtxMarkW_params; + +typedef struct nvtxRangeStartEx_params_st { + const nvtxEventAttributes_t* eventAttrib; +} nvtxRangeStartEx_params; + +typedef struct nvtxRangeStartA_params_st { + const char* message; +} nvtxRangeStartA_params; + +typedef struct nvtxRangeStartW_params_st { + const wchar_t* message; +} nvtxRangeStartW_params; + +typedef struct nvtxRangeEnd_params_st { + nvtxRangeId_t id; +} nvtxRangeEnd_params; + +typedef struct nvtxRangePushEx_params_st { + const nvtxEventAttributes_t* eventAttrib; +} nvtxRangePushEx_params; + +typedef struct nvtxRangePushA_params_st { + const char* message; +} nvtxRangePushA_params; + +typedef struct nvtxRangePushW_params_st { + const wchar_t* message; +} nvtxRangePushW_params; + +typedef struct nvtxRangePop_params_st { + /* WAR: Windows compiler doesn't allow empty structs */ + /* This field shouldn't be used */ + void *dummy; +} nvtxRangePop_params; + +typedef struct nvtxNameCategoryA_params_st { + uint32_t category; + const char* name; +} nvtxNameCategoryA_params; + +typedef struct nvtxNameCategoryW_params_st { + uint32_t category; + const wchar_t* name; +} nvtxNameCategoryW_params; + +typedef struct nvtxNameOsThreadA_params_st { + uint32_t threadId; + const char* name; +} nvtxNameOsThreadA_params; + +typedef struct nvtxNameOsThreadW_params_st { + uint32_t threadId; + const wchar_t* name; +} nvtxNameOsThreadW_params; + +typedef struct nvtxNameCuDeviceA_params_st { + CUdevice device; + const char* name; +} nvtxNameCuDeviceA_params; + +typedef struct nvtxNameCuDeviceW_params_st { + CUdevice device; + const wchar_t* name; +} nvtxNameCuDeviceW_params; + +typedef struct nvtxNameCuContextA_params_st { + CUcontext context; + const char* name; +} nvtxNameCuContextA_params; + +typedef struct nvtxNameCuContextW_params_st { + CUcontext context; + const wchar_t* name; +} nvtxNameCuContextW_params; + +typedef struct nvtxNameCuStreamA_params_st { + CUstream stream; + const char* name; +} nvtxNameCuStreamA_params; + +typedef struct nvtxNameCuStreamW_params_st { + CUstream stream; + const wchar_t* name; +} nvtxNameCuStreamW_params; + +typedef struct nvtxNameCuEventA_params_st { + CUevent event; + const char* name; +} nvtxNameCuEventA_params; + +typedef struct nvtxNameCuEventW_params_st { + CUevent event; + const wchar_t* name; +} nvtxNameCuEventW_params; + +typedef struct nvtxNameCudaDeviceA_params_st { + int device; + const char* name; +} nvtxNameCudaDeviceA_params; + +typedef struct nvtxNameCudaDeviceW_params_st { + int device; + const wchar_t* name; +} nvtxNameCudaDeviceW_params; + +typedef struct nvtxNameCudaStreamA_params_st { + cudaStream_t stream; + const char* name; +} nvtxNameCudaStreamA_params; + +typedef struct nvtxNameCudaStreamW_params_st { + cudaStream_t stream; + const wchar_t* name; +} nvtxNameCudaStreamW_params; + +typedef struct nvtxNameCudaEventA_params_st { + cudaEvent_t event; + const char* name; +} nvtxNameCudaEventA_params; + +typedef struct nvtxNameCudaEventW_params_st { + cudaEvent_t event; + const wchar_t* name; +} nvtxNameCudaEventW_params; + +typedef struct nvtxDomainCreateA_params_st { + const char* name; +} nvtxDomainCreateA_params; + +typedef struct nvtxDomainDestroy_params_st { + nvtxDomainHandle_t domain; +} nvtxDomainDestroy_params; + +typedef struct nvtxDomainMarkEx_params_st { + nvtxDomainHandle_t domain; + nvtxMarkEx_params core; +} nvtxDomainMarkEx_params; + +typedef struct nvtxDomainRangeStartEx_params_st { + nvtxDomainHandle_t domain; + nvtxRangeStartEx_params core; +} nvtxDomainRangeStartEx_params; + +typedef struct nvtxDomainRangeEnd_params_st { + nvtxDomainHandle_t domain; + nvtxRangeEnd_params core; +} nvtxDomainRangeEnd_params; + +typedef struct nvtxDomainRangePushEx_params_st { + nvtxDomainHandle_t domain; + nvtxRangePushEx_params core; +} nvtxDomainRangePushEx_params; + +typedef struct nvtxDomainRangePop_params_st { + nvtxDomainHandle_t domain; +} nvtxDomainRangePop_params; + +typedef struct nvtxSyncUserCreate_params_st { + nvtxDomainHandle_t domain; + const nvtxSyncUserAttributes_t* attribs; +} nvtxSyncUserCreate_params; + +typedef struct nvtxSyncUserCommon_params_st { + nvtxSyncUser_t handle; +} nvtxSyncUserCommon_params; + +typedef struct nvtxDomainRegisterStringA_params_st { + nvtxDomainHandle_t domain; + const char* string; +} nvtxDomainRegisterStringA_params; + +typedef struct nvtxDomainRegisterStringW_params_st { + nvtxDomainHandle_t domain; + const char* string; +} nvtxDomainRegisterStringW_params; + +#if defined(__GNUC__) && defined(CUPTI_LIB) + #pragma GCC visibility pop +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_common.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_common.h new file mode 100644 index 0000000000000000000000000000000000000000..0ed01f7bc2851f43678e58efe34fc5579cca3a35 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_common.h @@ -0,0 +1,393 @@ +#ifndef NVPERF_COMMON_H +#define NVPERF_COMMON_H + +/* + * Copyright 2014-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO USER: + * + * This source code is subject to NVIDIA ownership rights under U.S. and + * international Copyright laws. + * + * This software and the information contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and conditions + * of a form of NVIDIA software license agreement. + * + * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE + * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR + * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE + * OR PERFORMANCE OF THIS SOURCE CODE. + * + * U.S. Government End Users. This source code is a "commercial item" as + * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of + * "commercial computer software" and "commercial computer software + * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) + * and is provided to the U.S. Government only as a commercial end item. + * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through + * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the + * source code with only those rights set forth herein. + * + * Any use of this source code in individual and commercial software must + * include, in the user documentation and internal comments to the code, + * the above Disclaimer and U.S. Government End Users Notice. + */ + +#include +#include + +#if defined(__GNUC__) && defined(NVPA_SHARED_LIB) + #pragma GCC visibility push(default) + #if !defined(NVPW_LOCAL) + #define NVPW_LOCAL __attribute__ ((visibility ("hidden"))) + #endif +#else + #if !defined(NVPW_LOCAL) + #define NVPW_LOCAL + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file nvperf_common.h + */ + +#ifndef NVPERF_NVPA_STATUS_DEFINED +#define NVPERF_NVPA_STATUS_DEFINED + + /// Error codes. + typedef enum NVPA_Status + { + /// Success + NVPA_STATUS_SUCCESS = 0, + /// Generic error. + NVPA_STATUS_ERROR = 1, + /// Internal error. Please file a bug! + NVPA_STATUS_INTERNAL_ERROR = 2, + /// NVPW_InitializeTarget() or NVPW_InitializeHost() has not been called yet. + NVPA_STATUS_NOT_INITIALIZED = 3, + /// The NvPerf DLL/DSO could not be loaded during NVPW_Initialize*(). Please ensure they are placed in the + /// appropriate location that can be founder by a dynamic linker. And on Linux systems, confirm that the + /// LD_LIBRARY_PATH environment variable is set correctly. Alternatively, you may utilize + /// NVPW_SetLibraryLoadPaths() to define additional library search paths. + NVPA_STATUS_NOT_LOADED = 4, + /// The function was not found in this version of the NvPerf DLL/DSO. Or if you are directly calling + /// NVPA_GetProcAddress(), please ensure the function name is spelled correctly. + NVPA_STATUS_FUNCTION_NOT_FOUND = 5, + /// The request was intentionally not supported. + NVPA_STATUS_NOT_SUPPORTED = 6, + /// The request was not implemented by this version. + NVPA_STATUS_NOT_IMPLEMENTED = 7, + /// Invalid argument. + NVPA_STATUS_INVALID_ARGUMENT = 8, + /// UNUSED + NVPA_STATUS_INVALID_METRIC_ID = 9, + /// No driver has been loaded via NVPW_*_LoadDriver(). + NVPA_STATUS_DRIVER_NOT_LOADED = 10, + /// Failed memory allocation. + NVPA_STATUS_OUT_OF_MEMORY = 11, + /// UNUSED + NVPA_STATUS_INVALID_THREAD_STATE = 12, + /// UNUSED + NVPA_STATUS_FAILED_CONTEXT_ALLOC = 13, + /// The specified GPU is not supported. It is recommended to call IsGpuSupported() for more information + NVPA_STATUS_UNSUPPORTED_GPU = 14, + /// The installed NVIDIA driver is too old. + NVPA_STATUS_INSUFFICIENT_DRIVER_VERSION = 15, + /// UNUSED + NVPA_STATUS_OBJECT_NOT_REGISTERED = 16, + /// Profiling permission not granted; see https://developer.nvidia.com/nvidia-development-tools-solutions- + /// ERR_NVGPUCTRPERM-permission-issue-performance-counters + NVPA_STATUS_INSUFFICIENT_PRIVILEGE = 17, + /// UNUSED + NVPA_STATUS_INVALID_CONTEXT_STATE = 18, + /// UNUSED + NVPA_STATUS_INVALID_OBJECT_STATE = 19, + /// The request could not be fulfilled because a system resource is already in use. + NVPA_STATUS_RESOURCE_UNAVAILABLE = 20, + /// UNUSED + NVPA_STATUS_DRIVER_LOADED_TOO_LATE = 21, + /// The provided buffer is not large enough. + NVPA_STATUS_INSUFFICIENT_SPACE = 22, + /// UNUSED + NVPA_STATUS_OBJECT_MISMATCH = 23, + /// Virtualized GPU (vGPU) is not supported. + NVPA_STATUS_VIRTUALIZED_DEVICE_NOT_SUPPORTED = 24, + /// Profiling permission was not granted or the device was disabled. + NVPA_STATUS_PROFILING_NOT_ALLOWED = 25, + NVPA_STATUS__COUNT + } NVPA_Status; + + + inline void NVPW_NVPAStatusToString(NVPA_Status status, const char** ppStatusStr, const char** ppCommentStr) + { + switch (status) + { + case NVPA_STATUS_SUCCESS: + *ppStatusStr = "NVPA_STATUS_SUCCESS"; + *ppCommentStr = "Success"; + return; + case NVPA_STATUS_ERROR: + *ppStatusStr = "NVPA_STATUS_ERROR"; + *ppCommentStr = "Generic error."; + return; + case NVPA_STATUS_INTERNAL_ERROR: + *ppStatusStr = "NVPA_STATUS_INTERNAL_ERROR"; + *ppCommentStr = "Internal error. Please file a bug!"; + return; + case NVPA_STATUS_NOT_INITIALIZED: + *ppStatusStr = "NVPA_STATUS_NOT_INITIALIZED"; + *ppCommentStr = "NVPW_InitializeTarget() or NVPW_InitializeHost() has not been called yet."; + return; + case NVPA_STATUS_NOT_LOADED: + *ppStatusStr = "NVPA_STATUS_NOT_LOADED"; + *ppCommentStr = "The NvPerf DLL/DSO could not be loaded during NVPW_Initialize*(). Please ensure they are placed in the appropriate location that can be founder by a dynamic linker. And on Linux systems, confirm that the LD_LIBRARY_PATH environment variable is set correctly. Alternatively, you may utilize NVPW_SetLibraryLoadPaths() to define additional library search paths."; + return; + case NVPA_STATUS_FUNCTION_NOT_FOUND: + *ppStatusStr = "NVPA_STATUS_FUNCTION_NOT_FOUND"; + *ppCommentStr = "The function was not found in this version of the NvPerf DLL/DSO. Or if you are directly calling NVPA_GetProcAddress(), please ensure the function name is spelled correctly."; + return; + case NVPA_STATUS_NOT_SUPPORTED: + *ppStatusStr = "NVPA_STATUS_NOT_SUPPORTED"; + *ppCommentStr = "The request was intentionally not supported."; + return; + case NVPA_STATUS_NOT_IMPLEMENTED: + *ppStatusStr = "NVPA_STATUS_NOT_IMPLEMENTED"; + *ppCommentStr = "The request was not implemented by this version."; + return; + case NVPA_STATUS_INVALID_ARGUMENT: + *ppStatusStr = "NVPA_STATUS_INVALID_ARGUMENT"; + *ppCommentStr = "Invalid argument."; + return; + case NVPA_STATUS_INVALID_METRIC_ID: + *ppStatusStr = "NVPA_STATUS_INVALID_METRIC_ID"; + *ppCommentStr = "UNUSED"; + return; + case NVPA_STATUS_DRIVER_NOT_LOADED: + *ppStatusStr = "NVPA_STATUS_DRIVER_NOT_LOADED"; + *ppCommentStr = "No driver has been loaded via NVPW_*_LoadDriver()."; + return; + case NVPA_STATUS_OUT_OF_MEMORY: + *ppStatusStr = "NVPA_STATUS_OUT_OF_MEMORY"; + *ppCommentStr = "Failed memory allocation."; + return; + case NVPA_STATUS_INVALID_THREAD_STATE: + *ppStatusStr = "NVPA_STATUS_INVALID_THREAD_STATE"; + *ppCommentStr = "UNUSED"; + return; + case NVPA_STATUS_FAILED_CONTEXT_ALLOC: + *ppStatusStr = "NVPA_STATUS_FAILED_CONTEXT_ALLOC"; + *ppCommentStr = "UNUSED"; + return; + case NVPA_STATUS_UNSUPPORTED_GPU: + *ppStatusStr = "NVPA_STATUS_UNSUPPORTED_GPU"; + *ppCommentStr = "The specified GPU is not supported. It is recommended to call IsGpuSupported() for more information"; + return; + case NVPA_STATUS_INSUFFICIENT_DRIVER_VERSION: + *ppStatusStr = "NVPA_STATUS_INSUFFICIENT_DRIVER_VERSION"; + *ppCommentStr = "The installed NVIDIA driver is too old."; + return; + case NVPA_STATUS_OBJECT_NOT_REGISTERED: + *ppStatusStr = "NVPA_STATUS_OBJECT_NOT_REGISTERED"; + *ppCommentStr = "UNUSED"; + return; + case NVPA_STATUS_INSUFFICIENT_PRIVILEGE: + *ppStatusStr = "NVPA_STATUS_INSUFFICIENT_PRIVILEGE"; + *ppCommentStr = "Profiling permission not granted; see https://developer.nvidia.com/nvidia-development-tools-solutions-ERR_NVGPUCTRPERM-permission-issue-performance-counters"; + return; + case NVPA_STATUS_INVALID_CONTEXT_STATE: + *ppStatusStr = "NVPA_STATUS_INVALID_CONTEXT_STATE"; + *ppCommentStr = "UNUSED"; + return; + case NVPA_STATUS_INVALID_OBJECT_STATE: + *ppStatusStr = "NVPA_STATUS_INVALID_OBJECT_STATE"; + *ppCommentStr = "UNUSED"; + return; + case NVPA_STATUS_RESOURCE_UNAVAILABLE: + *ppStatusStr = "NVPA_STATUS_RESOURCE_UNAVAILABLE"; + *ppCommentStr = "The request could not be fulfilled because a system resource is already in use."; + return; + case NVPA_STATUS_DRIVER_LOADED_TOO_LATE: + *ppStatusStr = "NVPA_STATUS_DRIVER_LOADED_TOO_LATE"; + *ppCommentStr = "UNUSED"; + return; + case NVPA_STATUS_INSUFFICIENT_SPACE: + *ppStatusStr = "NVPA_STATUS_INSUFFICIENT_SPACE"; + *ppCommentStr = "The provided buffer is not large enough."; + return; + case NVPA_STATUS_OBJECT_MISMATCH: + *ppStatusStr = "NVPA_STATUS_OBJECT_MISMATCH"; + *ppCommentStr = "UNUSED"; + return; + case NVPA_STATUS_VIRTUALIZED_DEVICE_NOT_SUPPORTED: + *ppStatusStr = "NVPA_STATUS_VIRTUALIZED_DEVICE_NOT_SUPPORTED"; + *ppCommentStr = "Virtualized GPU (vGPU) is not supported."; + return; + case NVPA_STATUS_PROFILING_NOT_ALLOWED: + *ppStatusStr = "NVPA_STATUS_PROFILING_NOT_ALLOWED"; + *ppCommentStr = "Profiling permission was not granted or the device was disabled."; + return; + default: + *ppStatusStr = "Unrecognized status"; + *ppCommentStr = "This status is unrecognized. Is it coming from a newer version of NvPerf library?"; + return; + } + } + + +#endif // NVPERF_NVPA_STATUS_DEFINED + + +#ifndef NVPERF_NVPA_ACTIVITY_KIND_DEFINED +#define NVPERF_NVPA_ACTIVITY_KIND_DEFINED + + /// The configuration's activity-kind dictates which types of data may be collected. + typedef enum NVPA_ActivityKind + { + /// Invalid value. + NVPA_ACTIVITY_KIND_INVALID = 0, + /// A workload-centric activity for serialized and pipelined collection. + /// + /// Profiler is capable of collecting both serialized and pipelined metrics. The library introduces any + /// synchronization required to collect serialized metrics. + NVPA_ACTIVITY_KIND_PROFILER, + /// A realtime activity for sampling counters from the CPU or GPU. + NVPA_ACTIVITY_KIND_REALTIME_SAMPLED, + /// A realtime activity for profiling counters from the CPU or GPU without CPU/GPU synchronizations. + NVPA_ACTIVITY_KIND_REALTIME_PROFILER, + NVPA_ACTIVITY_KIND__COUNT + } NVPA_ActivityKind; + + +#endif // NVPERF_NVPA_ACTIVITY_KIND_DEFINED + + +#ifndef NVPERF_NVPA_BOOL_DEFINED +#define NVPERF_NVPA_BOOL_DEFINED + /// The type used for boolean values. + typedef uint8_t NVPA_Bool; +#endif // NVPERF_NVPA_BOOL_DEFINED + +#ifndef NVPA_STRUCT_SIZE +#define NVPA_STRUCT_SIZE(type_, lastfield_) (offsetof(type_, lastfield_) + sizeof(((type_*)0)->lastfield_)) +#endif // NVPA_STRUCT_SIZE + +#ifndef NVPW_FIELD_EXISTS +#define NVPW_FIELD_EXISTS(pParams_, name_) \ + ((pParams_)->structSize >= (size_t)((const uint8_t*)(&(pParams_)->name_) + sizeof(pParams_)->name_ - (const uint8_t*)(pParams_))) +#endif // NVPW_FIELD_EXISTS + + +#ifndef NVPERF_NVPA_GETPROCADDRESS_DEFINED +#define NVPERF_NVPA_GETPROCADDRESS_DEFINED + +typedef NVPA_Status (*NVPA_GenericFn)(void); + + + /// + /// Gets the address of an NvPerf API function. + /// + /// \return A function pointer to the function, or NULL if the function is not available. + /// + /// \param pFunctionName [in] Name of the function to retrieve. + NVPA_GenericFn NVPA_GetProcAddress(const char* pFunctionName); + +#endif + +#ifndef NVPERF_NVPW_SETLIBRARYLOADPATHS_DEFINED +#define NVPERF_NVPW_SETLIBRARYLOADPATHS_DEFINED + + + typedef struct NVPW_SetLibraryLoadPaths_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] number of paths in ppPaths + size_t numPaths; + /// [in] array of null-terminated paths + const char** ppPaths; + } NVPW_SetLibraryLoadPaths_Params; +#define NVPW_SetLibraryLoadPaths_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_SetLibraryLoadPaths_Params, ppPaths) + + /// Sets library search path for \ref NVPW_InitializeHost() and \ref NVPW_InitializeTarget(). + /// \ref NVPW_InitializeHost() and \ref NVPW_InitializeTarget load the NvPerf DLL/DSO. This function sets + /// ordered paths that will be searched with the LoadLibrary() or dlopen() call. + /// If load paths are set by this function, the default set of load paths + /// will not be attempted. + /// Each path must point at a directory (not a file name). + /// This function is not thread-safe. + /// Example Usage: + /// \code + /// const char* paths[] = { + /// "path1", "path2", etc + /// }; + /// NVPW_SetLibraryLoadPaths_Params params{NVPW_SetLibraryLoadPaths_Params_STRUCT_SIZE}; + /// params.numPaths = sizeof(paths)/sizeof(paths[0]); + /// params.ppPaths = paths; + /// NVPW_SetLibraryLoadPaths(¶ms); + /// NVPW_InitializeHost(); + /// params.numPaths = 0; + /// params.ppPaths = NULL; + /// NVPW_SetLibraryLoadPaths(¶ms); + /// \endcode + NVPA_Status NVPW_SetLibraryLoadPaths(NVPW_SetLibraryLoadPaths_Params* pParams); + + typedef struct NVPW_SetLibraryLoadPathsW_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] number of paths in ppwPaths + size_t numPaths; + /// [in] array of null-terminated paths + const wchar_t** ppwPaths; + } NVPW_SetLibraryLoadPathsW_Params; +#define NVPW_SetLibraryLoadPathsW_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_SetLibraryLoadPathsW_Params, ppwPaths) + + /// Sets library search path for \ref NVPW_InitializeHost() and \ref NVPW_InitializeTarget(). + /// \ref NVPW_InitializeHost() and \ref NVPW_InitializeTarget load the NvPerf DLL/DSO. This function sets + /// ordered paths that will be searched with the LoadLibrary() or dlopen() call. + /// If load paths are set by this function, the default set of load paths + /// will not be attempted. + /// Each path must point at a directory (not a file name). + /// This function is not thread-safe. + /// Example Usage: + /// \code + /// const wchar_t* wpaths[] = { + /// L"path1", L"path2", etc + /// }; + /// NVPW_SetLibraryLoadPathsW_Params params{NVPW_SetLibraryLoadPathsW_Params_STRUCT_SIZE}; + /// params.numPaths = sizeof(wpaths)/sizeof(wpaths[0]); + /// params.ppwPaths = wpaths; + /// NVPW_SetLibraryLoadPathsW(¶ms); + /// NVPW_InitializeHost(); + /// params.numPaths = 0; + /// params.ppwPaths = NULL; + /// NVPW_SetLibraryLoadPathsW(¶ms); + /// \endcode + NVPA_Status NVPW_SetLibraryLoadPathsW(NVPW_SetLibraryLoadPathsW_Params* pParams); + +#endif + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#if defined(__GNUC__) && defined(NVPA_SHARED_LIB) + #pragma GCC visibility pop +#endif + +#endif // NVPERF_COMMON_H diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_cuda_host.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_cuda_host.h new file mode 100644 index 0000000000000000000000000000000000000000..9b4533b25148b7cd28e0ed30be022893514415a5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_cuda_host.h @@ -0,0 +1,179 @@ +#ifndef NVPERF_CUDA_HOST_H +#define NVPERF_CUDA_HOST_H + +/* + * Copyright 2014-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO USER: + * + * This source code is subject to NVIDIA ownership rights under U.S. and + * international Copyright laws. + * + * This software and the information contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and conditions + * of a form of NVIDIA software license agreement. + * + * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE + * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR + * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE + * OR PERFORMANCE OF THIS SOURCE CODE. + * + * U.S. Government End Users. This source code is a "commercial item" as + * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of + * "commercial computer software" and "commercial computer software + * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) + * and is provided to the U.S. Government only as a commercial end item. + * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through + * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the + * source code with only those rights set forth herein. + * + * Any use of this source code in individual and commercial software must + * include, in the user documentation and internal comments to the code, + * the above Disclaimer and U.S. Government End Users Notice. + */ + +#include +#include +#include "nvperf_common.h" +#include "nvperf_host.h" + +#if defined(__GNUC__) && defined(NVPA_SHARED_LIB) + #pragma GCC visibility push(default) + #if !defined(NVPW_LOCAL) + #define NVPW_LOCAL __attribute__ ((visibility ("hidden"))) + #endif +#else + #if !defined(NVPW_LOCAL) + #define NVPW_LOCAL + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file nvperf_cuda_host.h + */ + + typedef struct NVPW_CUDA_RawMetricsConfig_Create_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + NVPA_ActivityKind activityKind; + /// [in] + const char* pChipName; + /// [out] new NVPA_RawMetricsConfig object + struct NVPA_RawMetricsConfig* pRawMetricsConfig; + } NVPW_CUDA_RawMetricsConfig_Create_Params; +#define NVPW_CUDA_RawMetricsConfig_Create_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CUDA_RawMetricsConfig_Create_Params, pRawMetricsConfig) + + NVPA_Status NVPW_CUDA_RawMetricsConfig_Create(NVPW_CUDA_RawMetricsConfig_Create_Params* pParams); + + typedef struct NVPW_CUDA_RawMetricsConfig_Create_V2_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + NVPA_ActivityKind activityKind; + /// [in] accepted for chips supported at the time-of-release. + const char* pChipName; + /// [in] buffer with counter availability image - required for future chip support + const uint8_t* pCounterAvailabilityImage; + /// [out] new NVPA_RawMetricsConfig object + struct NVPA_RawMetricsConfig* pRawMetricsConfig; + } NVPW_CUDA_RawMetricsConfig_Create_V2_Params; +#define NVPW_CUDA_RawMetricsConfig_Create_V2_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CUDA_RawMetricsConfig_Create_V2_Params, pRawMetricsConfig) + + /// Use either 'pChipName' or 'pCounterAvailabilityImage'. + NVPA_Status NVPW_CUDA_RawMetricsConfig_Create_V2(NVPW_CUDA_RawMetricsConfig_Create_V2_Params* pParams); + + typedef struct NVPW_CUDA_CounterDataBuilder_Create_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] accepted for chips supported at the time-of-release. + const char* pChipName; + /// [in] buffer with counter availability image - required for future chip support + const uint8_t* pCounterAvailabilityImage; + /// [out] new NVPA_CounterDataBuilder object + struct NVPA_CounterDataBuilder* pCounterDataBuilder; + } NVPW_CUDA_CounterDataBuilder_Create_Params; +#define NVPW_CUDA_CounterDataBuilder_Create_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CUDA_CounterDataBuilder_Create_Params, pCounterDataBuilder) + + /// Use either 'pChipName' or 'pCounterAvailabilityImage'. + NVPA_Status NVPW_CUDA_CounterDataBuilder_Create(NVPW_CUDA_CounterDataBuilder_Create_Params* pParams); + + typedef struct NVPW_MetricsEvaluator NVPW_MetricsEvaluator; + + typedef struct NVPW_CUDA_MetricsEvaluator_CalculateScratchBufferSize_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] accepted for chips supported at the time-of-release. + const char* pChipName; + /// [in] buffer with counter availability image - required for future chip support + const uint8_t* pCounterAvailabilityImage; + /// [out] + size_t scratchBufferSize; + } NVPW_CUDA_MetricsEvaluator_CalculateScratchBufferSize_Params; +#define NVPW_CUDA_MetricsEvaluator_CalculateScratchBufferSize_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CUDA_MetricsEvaluator_CalculateScratchBufferSize_Params, scratchBufferSize) + + /// Use either 'pChipName' or 'pCounterAvailabilityImage'. + NVPA_Status NVPW_CUDA_MetricsEvaluator_CalculateScratchBufferSize(NVPW_CUDA_MetricsEvaluator_CalculateScratchBufferSize_Params* pParams); + + typedef struct NVPW_CUDA_MetricsEvaluator_Initialize_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + uint8_t* pScratchBuffer; + /// [in] the size of the 'pScratchBuffer' array, should be at least the size of the 'scratchBufferSize' returned + /// by 'NVPW_CUDA_MetricsEvaluator_CalculateScratchBufferSize' + size_t scratchBufferSize; + /// [in] accepted for chips supported at the time-of-release. + const char* pChipName; + /// [in] buffer with counter availability image - required for future chip support + const uint8_t* pCounterAvailabilityImage; + /// [in] + const uint8_t* pCounterDataImage; + /// [in] must be provided if 'pCounterDataImage' is not NULL + size_t counterDataImageSize; + /// [out] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + } NVPW_CUDA_MetricsEvaluator_Initialize_Params; +#define NVPW_CUDA_MetricsEvaluator_Initialize_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CUDA_MetricsEvaluator_Initialize_Params, pMetricsEvaluator) + + /// Use one of 'pChipName', 'pCounterAvailabilityImage', or 'pCounterDataImage'. 'pChipName' or + /// 'pCounterAvailabilityImage' will create a metrics evaluator based on a virtual device while 'pCounterDataImage' + /// will create a metrics evaluator based on the actual device. + NVPA_Status NVPW_CUDA_MetricsEvaluator_Initialize(NVPW_CUDA_MetricsEvaluator_Initialize_Params* pParams); + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#if defined(__GNUC__) && defined(NVPA_SHARED_LIB) + #pragma GCC visibility pop +#endif + +#endif // NVPERF_CUDA_HOST_H diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_host.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_host.h new file mode 100644 index 0000000000000000000000000000000000000000..62a53528b64d6b3da8daf7058cec21781ae0e8cb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_host.h @@ -0,0 +1,1178 @@ +#ifndef NVPERF_HOST_H +#define NVPERF_HOST_H + +/* + * Copyright 2014-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO USER: + * + * This source code is subject to NVIDIA ownership rights under U.S. and + * international Copyright laws. + * + * This software and the information contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and conditions + * of a form of NVIDIA software license agreement. + * + * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE + * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR + * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE + * OR PERFORMANCE OF THIS SOURCE CODE. + * + * U.S. Government End Users. This source code is a "commercial item" as + * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of + * "commercial computer software" and "commercial computer software + * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) + * and is provided to the U.S. Government only as a commercial end item. + * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through + * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the + * source code with only those rights set forth herein. + * + * Any use of this source code in individual and commercial software must + * include, in the user documentation and internal comments to the code, + * the above Disclaimer and U.S. Government End Users Notice. + */ + +#include +#include +#include "nvperf_common.h" + +#if defined(__GNUC__) && defined(NVPA_SHARED_LIB) + #pragma GCC visibility push(default) + #if !defined(NVPW_LOCAL) + #define NVPW_LOCAL __attribute__ ((visibility ("hidden"))) + #endif +#else + #if !defined(NVPW_LOCAL) + #define NVPW_LOCAL + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file nvperf_host.h + */ + + +// Guard against multiple definition of NvPerf host types +#ifndef NVPERF_HOST_API_DEFINED +#define NVPERF_HOST_API_DEFINED + + +/***************************************************************************//** + * @name Host Configuration + * @{ + */ + + typedef struct NVPW_InitializeHost_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + } NVPW_InitializeHost_Params; +#define NVPW_InitializeHost_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_InitializeHost_Params, pPriv) + + /// Load the host library. + NVPA_Status NVPW_InitializeHost(NVPW_InitializeHost_Params* pParams); + + typedef struct NVPW_CounterData_CalculateCounterDataImageCopySize_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// The CounterDataPrefix generated from e.g. nvperf2 initdata or + /// NVPW_CounterDataBuilder_GetCounterDataPrefix(). Must be align(8). + const uint8_t* pCounterDataPrefix; + size_t counterDataPrefixSize; + /// max number of ranges that can be profiled + uint32_t maxNumRanges; + /// max number of RangeTree nodes; must be >= maxNumRanges + uint32_t maxNumRangeTreeNodes; + /// max string length of each RangeName, including the trailing NUL character + uint32_t maxRangeNameLength; + const uint8_t* pCounterDataSrc; + /// [out] required size of the copy buffer + size_t copyDataImageCounterSize; + } NVPW_CounterData_CalculateCounterDataImageCopySize_Params; +#define NVPW_CounterData_CalculateCounterDataImageCopySize_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterData_CalculateCounterDataImageCopySize_Params, copyDataImageCounterSize) + + NVPA_Status NVPW_CounterData_CalculateCounterDataImageCopySize(NVPW_CounterData_CalculateCounterDataImageCopySize_Params* pParams); + + typedef struct NVPW_CounterData_InitializeCounterDataImageCopy_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// The CounterDataPrefix generated from e.g. nvperf2 initdata or + /// NVPW_CounterDataBuilder_GetCounterDataPrefix(). Must be align(8). + const uint8_t* pCounterDataPrefix; + size_t counterDataPrefixSize; + /// max number of ranges that can be profiled + uint32_t maxNumRanges; + /// max number of RangeTree nodes; must be >= maxNumRanges + uint32_t maxNumRangeTreeNodes; + /// max string length of each RangeName, including the trailing NUL character + uint32_t maxRangeNameLength; + const uint8_t* pCounterDataSrc; + uint8_t* pCounterDataDst; + } NVPW_CounterData_InitializeCounterDataImageCopy_Params; +#define NVPW_CounterData_InitializeCounterDataImageCopy_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterData_InitializeCounterDataImageCopy_Params, pCounterDataDst) + + NVPA_Status NVPW_CounterData_InitializeCounterDataImageCopy(NVPW_CounterData_InitializeCounterDataImageCopy_Params* pParams); + + typedef struct NVPW_CounterData_ExtractCounterDataPrefix_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// The source buffer to extract the prefix from. + const uint8_t* pCounterDataSrc; + size_t counterDataSrcSize; + /// [in] If not NULL, the prefix will be copied into this buffer. + uint8_t* pCounterDataPrefix; + /// [inout] if 'pCounterDataPrefix' is NULL, size of counter data prefix will be returned; otherwise it should + /// be set to the size of buffer allocated for 'pCounterDataPrefix'. + size_t counterDataPrefixSize; + } NVPW_CounterData_ExtractCounterDataPrefix_Params; +#define NVPW_CounterData_ExtractCounterDataPrefix_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterData_ExtractCounterDataPrefix_Params, counterDataPrefixSize) + + NVPA_Status NVPW_CounterData_ExtractCounterDataPrefix(NVPW_CounterData_ExtractCounterDataPrefix_Params* pParams); + + typedef struct NVPA_CounterDataCombiner NVPA_CounterDataCombiner; + + typedef struct NVPW_CounterDataCombiner_Create_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// The destination counter data into which the source datas will be combined + uint8_t* pCounterDataDst; + /// [out] The created counter data combiner + NVPA_CounterDataCombiner* pCounterDataCombiner; + } NVPW_CounterDataCombiner_Create_Params; +#define NVPW_CounterDataCombiner_Create_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataCombiner_Create_Params, pCounterDataCombiner) + + NVPA_Status NVPW_CounterDataCombiner_Create(NVPW_CounterDataCombiner_Create_Params* pParams); + + typedef struct NVPW_CounterDataCombiner_Destroy_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_CounterDataCombiner* pCounterDataCombiner; + } NVPW_CounterDataCombiner_Destroy_Params; +#define NVPW_CounterDataCombiner_Destroy_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataCombiner_Destroy_Params, pCounterDataCombiner) + + NVPA_Status NVPW_CounterDataCombiner_Destroy(NVPW_CounterDataCombiner_Destroy_Params* pParams); + + typedef struct NVPW_CounterDataCombiner_CreateRange_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_CounterDataCombiner* pCounterDataCombiner; + size_t numDescriptions; + const char* const* ppDescriptions; + /// [out] + size_t rangeIndexDst; + } NVPW_CounterDataCombiner_CreateRange_Params; +#define NVPW_CounterDataCombiner_CreateRange_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataCombiner_CreateRange_Params, rangeIndexDst) + + NVPA_Status NVPW_CounterDataCombiner_CreateRange(NVPW_CounterDataCombiner_CreateRange_Params* pParams); + + typedef struct NVPW_CounterDataCombiner_CopyIntoRange_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + NVPA_CounterDataCombiner* pCounterDataCombiner; + /// [in] + size_t rangeIndexDst; + /// [in] + const uint8_t* pCounterDataSrc; + /// [in] + size_t rangeIndexSrc; + } NVPW_CounterDataCombiner_CopyIntoRange_Params; +#define NVPW_CounterDataCombiner_CopyIntoRange_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataCombiner_CopyIntoRange_Params, rangeIndexSrc) + + /// In order to use this API, the source counter data and the destination counter data must have identical counters + NVPA_Status NVPW_CounterDataCombiner_CopyIntoRange(NVPW_CounterDataCombiner_CopyIntoRange_Params* pParams); + + typedef struct NVPW_CounterDataCombiner_AccumulateIntoRange_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_CounterDataCombiner* pCounterDataCombiner; + size_t rangeIndexDst; + uint32_t dstMultiplier; + const uint8_t* pCounterDataSrc; + size_t rangeIndexSrc; + uint32_t srcMultiplier; + } NVPW_CounterDataCombiner_AccumulateIntoRange_Params; +#define NVPW_CounterDataCombiner_AccumulateIntoRange_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataCombiner_AccumulateIntoRange_Params, srcMultiplier) + + NVPA_Status NVPW_CounterDataCombiner_AccumulateIntoRange(NVPW_CounterDataCombiner_AccumulateIntoRange_Params* pParams); + + typedef struct NVPW_CounterDataCombiner_SumIntoRange_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_CounterDataCombiner* pCounterDataCombiner; + size_t rangeIndexDst; + const uint8_t* pCounterDataSrc; + size_t rangeIndexSrc; + } NVPW_CounterDataCombiner_SumIntoRange_Params; +#define NVPW_CounterDataCombiner_SumIntoRange_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataCombiner_SumIntoRange_Params, rangeIndexSrc) + + NVPA_Status NVPW_CounterDataCombiner_SumIntoRange(NVPW_CounterDataCombiner_SumIntoRange_Params* pParams); + + typedef struct NVPW_CounterDataCombiner_WeightedSumIntoRange_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_CounterDataCombiner* pCounterDataCombiner; + size_t rangeIndexDst; + double dstMultiplier; + const uint8_t* pCounterDataSrc; + size_t rangeIndexSrc; + double srcMultiplier; + } NVPW_CounterDataCombiner_WeightedSumIntoRange_Params; +#define NVPW_CounterDataCombiner_WeightedSumIntoRange_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataCombiner_WeightedSumIntoRange_Params, srcMultiplier) + + NVPA_Status NVPW_CounterDataCombiner_WeightedSumIntoRange(NVPW_CounterDataCombiner_WeightedSumIntoRange_Params* pParams); + +/** + * @} + ******************************************************************************/ + +/***************************************************************************//** + * @name Metrics Configuration + * @{ + */ + + typedef struct NVPA_RawMetricsConfig NVPA_RawMetricsConfig; + + typedef struct NVPA_RawMetricRequest + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// in + const char* pMetricName; + /// in + NVPA_Bool isolated; + /// in; ignored by AddMetric but observed by CounterData initialization + NVPA_Bool keepInstances; + } NVPA_RawMetricRequest; +#define NVPA_RAW_METRIC_REQUEST_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPA_RawMetricRequest, keepInstances) + + typedef struct NVPW_GetSupportedChipNames_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [out] + const char* const* ppChipNames; + /// [out] + size_t numChipNames; + } NVPW_GetSupportedChipNames_Params; +#define NVPW_GetSupportedChipNames_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_GetSupportedChipNames_Params, numChipNames) + + NVPA_Status NVPW_GetSupportedChipNames(NVPW_GetSupportedChipNames_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_Destroy_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_RawMetricsConfig* pRawMetricsConfig; + } NVPW_RawMetricsConfig_Destroy_Params; +#define NVPW_RawMetricsConfig_Destroy_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_Destroy_Params, pRawMetricsConfig) + + NVPA_Status NVPW_RawMetricsConfig_Destroy(NVPW_RawMetricsConfig_Destroy_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_SetCounterAvailability_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_RawMetricsConfig* pRawMetricsConfig; + /// [in] buffer with counter availability image + const uint8_t* pCounterAvailabilityImage; + } NVPW_RawMetricsConfig_SetCounterAvailability_Params; +#define NVPW_RawMetricsConfig_SetCounterAvailability_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_SetCounterAvailability_Params, pCounterAvailabilityImage) + + NVPA_Status NVPW_RawMetricsConfig_SetCounterAvailability(NVPW_RawMetricsConfig_SetCounterAvailability_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_BeginPassGroup_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_RawMetricsConfig* pRawMetricsConfig; + size_t maxPassCount; + } NVPW_RawMetricsConfig_BeginPassGroup_Params; +#define NVPW_RawMetricsConfig_BeginPassGroup_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_BeginPassGroup_Params, maxPassCount) + + NVPA_Status NVPW_RawMetricsConfig_BeginPassGroup(NVPW_RawMetricsConfig_BeginPassGroup_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_EndPassGroup_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_RawMetricsConfig* pRawMetricsConfig; + } NVPW_RawMetricsConfig_EndPassGroup_Params; +#define NVPW_RawMetricsConfig_EndPassGroup_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_EndPassGroup_Params, pRawMetricsConfig) + + NVPA_Status NVPW_RawMetricsConfig_EndPassGroup(NVPW_RawMetricsConfig_EndPassGroup_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_GetNumMetrics_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const NVPA_RawMetricsConfig* pRawMetricsConfig; + /// [out] + size_t numMetrics; + } NVPW_RawMetricsConfig_GetNumMetrics_Params; +#define NVPW_RawMetricsConfig_GetNumMetrics_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_GetNumMetrics_Params, numMetrics) + + NVPA_Status NVPW_RawMetricsConfig_GetNumMetrics(NVPW_RawMetricsConfig_GetNumMetrics_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_GetMetricProperties_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const NVPA_RawMetricsConfig* pRawMetricsConfig; + size_t metricIndex; + /// [out] + const char* pMetricName; + /// [out] + NVPA_Bool supportsPipelined; + /// [out] + NVPA_Bool supportsIsolated; + } NVPW_RawMetricsConfig_GetMetricProperties_Params; +#define NVPW_RawMetricsConfig_GetMetricProperties_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_GetMetricProperties_Params, supportsIsolated) + + NVPA_Status NVPW_RawMetricsConfig_GetMetricProperties(NVPW_RawMetricsConfig_GetMetricProperties_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_GetMetricProperties_V2_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const NVPA_RawMetricsConfig* pRawMetricsConfig; + size_t metricIndex; + /// [out] + const char* pMetricName; + } NVPW_RawMetricsConfig_GetMetricProperties_V2_Params; +#define NVPW_RawMetricsConfig_GetMetricProperties_V2_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_GetMetricProperties_V2_Params, pMetricName) + + NVPA_Status NVPW_RawMetricsConfig_GetMetricProperties_V2(NVPW_RawMetricsConfig_GetMetricProperties_V2_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_AddMetrics_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_RawMetricsConfig* pRawMetricsConfig; + const NVPA_RawMetricRequest* pRawMetricRequests; + size_t numMetricRequests; + } NVPW_RawMetricsConfig_AddMetrics_Params; +#define NVPW_RawMetricsConfig_AddMetrics_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_AddMetrics_Params, numMetricRequests) + + NVPA_Status NVPW_RawMetricsConfig_AddMetrics(NVPW_RawMetricsConfig_AddMetrics_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_IsAddMetricsPossible_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const NVPA_RawMetricsConfig* pRawMetricsConfig; + const NVPA_RawMetricRequest* pRawMetricRequests; + size_t numMetricRequests; + /// [out] + NVPA_Bool isPossible; + } NVPW_RawMetricsConfig_IsAddMetricsPossible_Params; +#define NVPW_RawMetricsConfig_IsAddMetricsPossible_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_IsAddMetricsPossible_Params, isPossible) + + NVPA_Status NVPW_RawMetricsConfig_IsAddMetricsPossible(NVPW_RawMetricsConfig_IsAddMetricsPossible_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_GenerateConfigImage_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_RawMetricsConfig* pRawMetricsConfig; + /// [in] If true, all existing pass groups may be merged to reduce number of passes. + /// If merge was successful, distribution of counters in passes may be updated as a side-effect. The effects + /// will be persistent in pRawMetricsConfig. + NVPA_Bool mergeAllPassGroups; + } NVPW_RawMetricsConfig_GenerateConfigImage_Params; +#define NVPW_RawMetricsConfig_GenerateConfigImage_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_GenerateConfigImage_Params, mergeAllPassGroups) + + /// This API may fail if called inside a pass group with `mergeAllPassGroups` = true. + NVPA_Status NVPW_RawMetricsConfig_GenerateConfigImage(NVPW_RawMetricsConfig_GenerateConfigImage_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_GetConfigImage_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const NVPA_RawMetricsConfig* pRawMetricsConfig; + /// [in] Number of bytes allocated for pBuffer + size_t bytesAllocated; + /// [out] [optional] Buffer receiving the config image + uint8_t* pBuffer; + /// [out] Count of bytes that would be copied into pBuffer + size_t bytesCopied; + } NVPW_RawMetricsConfig_GetConfigImage_Params; +#define NVPW_RawMetricsConfig_GetConfigImage_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_GetConfigImage_Params, bytesCopied) + + NVPA_Status NVPW_RawMetricsConfig_GetConfigImage(NVPW_RawMetricsConfig_GetConfigImage_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_GetNumPasses_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const NVPA_RawMetricsConfig* pRawMetricsConfig; + /// [out] + size_t numPipelinedPasses; + /// [out] + size_t numIsolatedPasses; + } NVPW_RawMetricsConfig_GetNumPasses_Params; +#define NVPW_RawMetricsConfig_GetNumPasses_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_GetNumPasses_Params, numIsolatedPasses) + + /// Total num passes = numPipelinedPasses + numIsolatedPasses * numNestingLevels + NVPA_Status NVPW_RawMetricsConfig_GetNumPasses(NVPW_RawMetricsConfig_GetNumPasses_Params* pParams); + + typedef struct NVPW_RawMetricsConfig_GetNumPasses_V2_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const NVPA_RawMetricsConfig* pRawMetricsConfig; + /// [out] + size_t numPasses; + } NVPW_RawMetricsConfig_GetNumPasses_V2_Params; +#define NVPW_RawMetricsConfig_GetNumPasses_V2_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_RawMetricsConfig_GetNumPasses_V2_Params, numPasses) + + /// Total num passes = numPasses * numNestingLevels + NVPA_Status NVPW_RawMetricsConfig_GetNumPasses_V2(NVPW_RawMetricsConfig_GetNumPasses_V2_Params* pParams); + + typedef struct NVPW_PeriodicSampler_Config_GetSocEstimatedSampleSize_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] Typically created by e.g. NVPW_RawMetricsConfig_GetConfigImage(), must be align(8). + const uint8_t* pConfig; + /// [in] + size_t configSize; + /// [out] + size_t sampleSize; + } NVPW_PeriodicSampler_Config_GetSocEstimatedSampleSize_Params; +#define NVPW_PeriodicSampler_Config_GetSocEstimatedSampleSize_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_PeriodicSampler_Config_GetSocEstimatedSampleSize_Params, sampleSize) + + /// Estimate per sample records size based on a virtual device + NVPA_Status NVPW_PeriodicSampler_Config_GetSocEstimatedSampleSize(NVPW_PeriodicSampler_Config_GetSocEstimatedSampleSize_Params* pParams); + + typedef struct NVPW_PeriodicSampler_Config_GetGpuEstimatedSampleSize_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] Typically created by e.g. NVPW_RawMetricsConfig_GetConfigImage(), must be align(8). + const uint8_t* pConfig; + /// [in] + size_t configSize; + /// [out] + size_t sampleSize; + } NVPW_PeriodicSampler_Config_GetGpuEstimatedSampleSize_Params; +#define NVPW_PeriodicSampler_Config_GetGpuEstimatedSampleSize_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_PeriodicSampler_Config_GetGpuEstimatedSampleSize_Params, sampleSize) + + /// Estimate per sample records size based on a virtual device + NVPA_Status NVPW_PeriodicSampler_Config_GetGpuEstimatedSampleSize(NVPW_PeriodicSampler_Config_GetGpuEstimatedSampleSize_Params* pParams); + +/** + * @} + ******************************************************************************/ + + typedef struct NVPW_Config_GetRawCounterInfo_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pConfig; + /// [in] + size_t configSize; + /// [in] + const char* pRawCounterName; + /// [inout] array containing indices of passes the counter resides in. 'pPassIndices' is in, '*pPassIndices' is + /// out. + size_t* pPassIndices; + /// [inout] if 'pPassIndices' is NULL, the count of passes this counter resides in will be returned; otherwise + /// it should be set to the capacity of 'pPassIndices' array, and on return, it will be overwritten to reflect + /// the actual count filled into 'pPassIndices' + size_t numPassIndices; + } NVPW_Config_GetRawCounterInfo_Params; +#define NVPW_Config_GetRawCounterInfo_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Config_GetRawCounterInfo_Params, numPassIndices) + + NVPA_Status NVPW_Config_GetRawCounterInfo(NVPW_Config_GetRawCounterInfo_Params* pParams); + + typedef struct NVPW_Config_GetRawCounters_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pConfig; + /// [in] + size_t configSize; + /// [in] + size_t passIndex; + /// [inout] array containing raw counter names. 'ppRawCounterNames' is in, '*ppRawCounterNames' is out. + const char** ppRawCounterNames; + /// [inout] if 'ppRawCounterNames' is NULL, the count of raw counters will be returned; otherwise it should be + /// set to the capacity of 'ppRawCounterNames' array, and on return, it will be overwritten to reflect the + /// actual count filled into 'ppRawCounterNames' + size_t numRawCounters; + } NVPW_Config_GetRawCounters_Params; +#define NVPW_Config_GetRawCounters_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Config_GetRawCounters_Params, numRawCounters) + + NVPA_Status NVPW_Config_GetRawCounters(NVPW_Config_GetRawCounters_Params* pParams); + +/***************************************************************************//** + * @name CounterData Creation + * @{ + */ + + typedef struct NVPA_CounterDataBuilder NVPA_CounterDataBuilder; + + typedef struct NVPW_CounterDataBuilder_Create_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [out] + NVPA_CounterDataBuilder* pCounterDataBuilder; + const char* pChipName; + } NVPW_CounterDataBuilder_Create_Params; +#define NVPW_CounterDataBuilder_Create_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataBuilder_Create_Params, pChipName) + + NVPA_Status NVPW_CounterDataBuilder_Create(NVPW_CounterDataBuilder_Create_Params* pParams); + + typedef struct NVPW_CounterDataBuilder_Destroy_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_CounterDataBuilder* pCounterDataBuilder; + } NVPW_CounterDataBuilder_Destroy_Params; +#define NVPW_CounterDataBuilder_Destroy_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataBuilder_Destroy_Params, pCounterDataBuilder) + + NVPA_Status NVPW_CounterDataBuilder_Destroy(NVPW_CounterDataBuilder_Destroy_Params* pParams); + + typedef struct NVPW_CounterDataBuilder_AddMetrics_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_CounterDataBuilder* pCounterDataBuilder; + const NVPA_RawMetricRequest* pRawMetricRequests; + size_t numMetricRequests; + } NVPW_CounterDataBuilder_AddMetrics_Params; +#define NVPW_CounterDataBuilder_AddMetrics_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataBuilder_AddMetrics_Params, numMetricRequests) + + NVPA_Status NVPW_CounterDataBuilder_AddMetrics(NVPW_CounterDataBuilder_AddMetrics_Params* pParams); + + typedef struct NVPW_CounterDataBuilder_GetCounterDataPrefix_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + NVPA_CounterDataBuilder* pCounterDataBuilder; + /// [in] Number of bytes allocated for pBuffer + size_t bytesAllocated; + /// [out] [optional] Buffer receiving the counter data prefix + uint8_t* pBuffer; + /// [out] Count of bytes that would be copied to pBuffer + size_t bytesCopied; + } NVPW_CounterDataBuilder_GetCounterDataPrefix_Params; +#define NVPW_CounterDataBuilder_GetCounterDataPrefix_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterDataBuilder_GetCounterDataPrefix_Params, bytesCopied) + + NVPA_Status NVPW_CounterDataBuilder_GetCounterDataPrefix(NVPW_CounterDataBuilder_GetCounterDataPrefix_Params* pParams); + +/** + * @} + ******************************************************************************/ + +/***************************************************************************//** + * @name Metrics Evaluator + * @{ + */ + + typedef struct NVPW_MetricsEvaluator NVPW_MetricsEvaluator; + +#ifndef NVPW_DIM_UNIT_DEFINED +#define NVPW_DIM_UNIT_DEFINED + typedef enum NVPW_DimUnitName + { + NVPW_DIM_UNIT_INVALID = 3518299157, + NVPW_DIM_UNIT_UNITLESS = 2126137902, + NVPW_DIM_UNIT_ATTRIBUTES = 3776338729, + NVPW_DIM_UNIT_BYTES = 3797850191, + NVPW_DIM_UNIT_CTAS = 1960564139, + NVPW_DIM_UNIT_CTC_CYCLES = 2224883873, + NVPW_DIM_UNIT_DRAM_CYCLES = 2650981327, + NVPW_DIM_UNIT_FBP_CYCLES = 1785238957, + NVPW_DIM_UNIT_FE_OPS = 2919159083, + NVPW_DIM_UNIT_GPC_CYCLES = 1222631184, + NVPW_DIM_UNIT_IDC_REQUESTS = 2012649669, + NVPW_DIM_UNIT_INSTRUCTIONS = 1418625543, + NVPW_DIM_UNIT_KILOBYTES = 1335980302, + NVPW_DIM_UNIT_L1DATA_BANK_ACCESSES = 1479493682, + NVPW_DIM_UNIT_L1DATA_BANK_CONFLICTS = 3433170787, + NVPW_DIM_UNIT_L1TEX_REQUESTS = 1306473767, + NVPW_DIM_UNIT_L1TEX_TAGS = 26573010, + NVPW_DIM_UNIT_L1TEX_WAVEFRONTS = 129373765, + NVPW_DIM_UNIT_L2_REQUESTS = 1143695106, + NVPW_DIM_UNIT_L2_SECTORS = 3424101564, + NVPW_DIM_UNIT_L2_TAGS = 3755612781, + NVPW_DIM_UNIT_LRC_REQUESTS = 2280914327, + NVPW_DIM_UNIT_LRC_SECTORS = 7212034, + NVPW_DIM_UNIT_MCC_CYCLES = 1826685787, + NVPW_DIM_UNIT_NANOSECONDS = 3047500672, + NVPW_DIM_UNIT_NVDLA_CYCLES = 3374059789, + NVPW_DIM_UNIT_NVENC_CYCLES = 2267185244, + NVPW_DIM_UNIT_NVLRX_CYCLES = 4059934930, + NVPW_DIM_UNIT_NVLTX_CYCLES = 1814350488, + NVPW_DIM_UNIT_OFA_CYCLES = 4290210307, + NVPW_DIM_UNIT_PCIE_CYCLES = 1230450943, + NVPW_DIM_UNIT_PERCENT = 1284354694, + NVPW_DIM_UNIT_PIXELS = 4227616663, + NVPW_DIM_UNIT_PIXEL_SHADER_BARRIERS = 3705502518, + NVPW_DIM_UNIT_PRIMITIVES = 2373084002, + NVPW_DIM_UNIT_PVAVPU_CYCLES = 2238259366, + NVPW_DIM_UNIT_PVA_CYCLES = 202044173, + NVPW_DIM_UNIT_QUADS = 1539753497, + NVPW_DIM_UNIT_REGISTERS = 2837260947, + NVPW_DIM_UNIT_SAMPLES = 746046551, + NVPW_DIM_UNIT_SECONDS = 1164825258, + NVPW_DIM_UNIT_SYSL2_REQUESTS = 2165109286, + NVPW_DIM_UNIT_SYSL2_SECTORS = 2268734175, + NVPW_DIM_UNIT_SYSL2_TAGS = 3308651352, + NVPW_DIM_UNIT_SYSLRC_REQUESTS = 3328245480, + NVPW_DIM_UNIT_SYSLRC_SECTORS = 1190477493, + NVPW_DIM_UNIT_SYS_CYCLES = 3310821688, + NVPW_DIM_UNIT_TEXELS = 1293214069, + NVPW_DIM_UNIT_THREADS = 164261907, + NVPW_DIM_UNIT_TMEM_ACCESSES = 3742902067, + NVPW_DIM_UNIT_VERTICES = 1873662209, + NVPW_DIM_UNIT_VIC_CYCLES = 103143588, + NVPW_DIM_UNIT_WARPS = 97951949, + NVPW_DIM_UNIT_WORKIDS = 1971113483, + NVPW_DIM_UNIT_WORKLOADS = 1728142656 + } NVPW_DimUnitName; +#endif //NVPW_DIM_UNIT_DEFINED + +#ifndef NVPW_HW_UNIT_DEFINED +#define NVPW_HW_UNIT_DEFINED + typedef enum NVPW_HwUnit + { + NVPW_HW_UNIT_INVALID = 3498035701, + NVPW_HW_UNIT_CROP = 2872137846, + NVPW_HW_UNIT_CTC = 4123164475, + NVPW_HW_UNIT_DRAM = 1662616918, + NVPW_HW_UNIT_DRAMC = 1401232876, + NVPW_HW_UNIT_FBP = 2947194306, + NVPW_HW_UNIT_FBPA = 690045803, + NVPW_HW_UNIT_FE = 2204924321, + NVPW_HW_UNIT_GPC = 1911735839, + NVPW_HW_UNIT_GPU = 1014363534, + NVPW_HW_UNIT_GR = 2933618517, + NVPW_HW_UNIT_IDC = 842765289, + NVPW_HW_UNIT_L1TEX = 893940957, + NVPW_HW_UNIT_LRC = 4004756136, + NVPW_HW_UNIT_LTS = 2333266697, + NVPW_HW_UNIT_MCC = 3980130194, + NVPW_HW_UNIT_NVDLA = 4201167892, + NVPW_HW_UNIT_NVENC = 207708260, + NVPW_HW_UNIT_NVLRX = 3091684901, + NVPW_HW_UNIT_NVLTX = 869679659, + NVPW_HW_UNIT_OFA = 70307371, + NVPW_HW_UNIT_PCIE = 3433264174, + NVPW_HW_UNIT_PDA = 345193251, + NVPW_HW_UNIT_PES = 804128425, + NVPW_HW_UNIT_PROP = 3339255507, + NVPW_HW_UNIT_PVA = 2565499490, + NVPW_HW_UNIT_PVAVPU = 1656645655, + NVPW_HW_UNIT_RASTER = 187932504, + NVPW_HW_UNIT_SM = 724224710, + NVPW_HW_UNIT_SMSP = 2837616917, + NVPW_HW_UNIT_SYS = 768990063, + NVPW_HW_UNIT_SYSLRC = 3247626950, + NVPW_HW_UNIT_SYSLTS = 4137740217, + NVPW_HW_UNIT_TPC = 1889024613, + NVPW_HW_UNIT_VAF = 753670509, + NVPW_HW_UNIT_VIC = 322439594, + NVPW_HW_UNIT_VPC = 275561583, + NVPW_HW_UNIT_ZCULL = 2401248356, + NVPW_HW_UNIT_ZROP = 979500456 + } NVPW_HwUnit; +#endif //NVPW_HW_UNIT_DEFINED + + typedef enum NVPW_RollupOp + { + NVPW_ROLLUP_OP_AVG = 0, + NVPW_ROLLUP_OP_MAX, + NVPW_ROLLUP_OP_MIN, + NVPW_ROLLUP_OP_SUM, + NVPW_ROLLUP_OP__COUNT + } NVPW_RollupOp; + + typedef enum NVPW_MetricType + { + NVPW_METRIC_TYPE_COUNTER = 0, + NVPW_METRIC_TYPE_RATIO, + NVPW_METRIC_TYPE_THROUGHPUT, + NVPW_METRIC_TYPE__COUNT + } NVPW_MetricType; + + typedef enum NVPW_Submetric + { + NVPW_SUBMETRIC_NONE = 0, + NVPW_SUBMETRIC_PEAK_SUSTAINED = 1, + NVPW_SUBMETRIC_PEAK_SUSTAINED_ACTIVE = 2, + NVPW_SUBMETRIC_PEAK_SUSTAINED_ACTIVE_PER_SECOND = 3, + NVPW_SUBMETRIC_PEAK_SUSTAINED_ELAPSED = 4, + NVPW_SUBMETRIC_PEAK_SUSTAINED_ELAPSED_PER_SECOND = 5, + NVPW_SUBMETRIC_PEAK_SUSTAINED_FRAME = 6, + NVPW_SUBMETRIC_PEAK_SUSTAINED_FRAME_PER_SECOND = 7, + NVPW_SUBMETRIC_PEAK_SUSTAINED_REGION = 8, + NVPW_SUBMETRIC_PEAK_SUSTAINED_REGION_PER_SECOND = 9, + NVPW_SUBMETRIC_PER_CYCLE_ACTIVE = 10, + NVPW_SUBMETRIC_PER_CYCLE_ELAPSED = 11, + NVPW_SUBMETRIC_PER_CYCLE_IN_FRAME = 12, + NVPW_SUBMETRIC_PER_CYCLE_IN_REGION = 13, + NVPW_SUBMETRIC_PER_SECOND = 14, + NVPW_SUBMETRIC_PCT_OF_PEAK_SUSTAINED_ACTIVE = 15, + NVPW_SUBMETRIC_PCT_OF_PEAK_SUSTAINED_ELAPSED = 16, + NVPW_SUBMETRIC_PCT_OF_PEAK_SUSTAINED_FRAME = 17, + NVPW_SUBMETRIC_PCT_OF_PEAK_SUSTAINED_REGION = 18, + NVPW_SUBMETRIC_MAX_RATE = 19, + NVPW_SUBMETRIC_PCT = 20, + NVPW_SUBMETRIC_RATIO = 21, + NVPW_SUBMETRIC__COUNT + } NVPW_Submetric; + + typedef struct NVPW_MetricEvalRequest + { + /// the metric index as in 'NVPW_MetricsEvaluator_GetMetricNames' + size_t metricIndex; + /// one of 'NVPW_MetricType' + uint8_t metricType; + /// one of 'NVPW_RollupOp', required for Counter and Throughput, doesn't apply to Ratio + uint8_t rollupOp; + /// one of 'NVPW_Submetric', required for Ratio and Throughput, optional for Counter + uint16_t submetric; + } NVPW_MetricEvalRequest; +#define NVPW_MetricEvalRequest_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricEvalRequest, submetric) + + typedef struct NVPW_DimUnitFactor + { + /// one of 'NVPW_DimUnitName' + uint32_t dimUnit; + int8_t exponent; + } NVPW_DimUnitFactor; +#define NVPW_DimUnitFactor_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_DimUnitFactor, exponent) + + typedef struct NVPW_MetricsEvaluator_Destroy_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + } NVPW_MetricsEvaluator_Destroy_Params; +#define NVPW_MetricsEvaluator_Destroy_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_Destroy_Params, pMetricsEvaluator) + + NVPA_Status NVPW_MetricsEvaluator_Destroy(NVPW_MetricsEvaluator_Destroy_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_GetMetricNames_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] one of 'NVPW_MetricType' + uint8_t metricType; + /// [out] + const char* pMetricNames; + /// [out] + const size_t* pMetricNameBeginIndices; + /// [out] + size_t numMetrics; + } NVPW_MetricsEvaluator_GetMetricNames_Params; +#define NVPW_MetricsEvaluator_GetMetricNames_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_GetMetricNames_Params, numMetrics) + + NVPA_Status NVPW_MetricsEvaluator_GetMetricNames(NVPW_MetricsEvaluator_GetMetricNames_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_GetMetricTypeAndIndex_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] can be either a base metric or a metric + const char* pMetricName; + /// [out] one of 'NVPW_MetricType' + uint8_t metricType; + /// [out] the metric index as in 'NVPW_MetricsEvaluator_GetMetricNames' + size_t metricIndex; + } NVPW_MetricsEvaluator_GetMetricTypeAndIndex_Params; +#define NVPW_MetricsEvaluator_GetMetricTypeAndIndex_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_GetMetricTypeAndIndex_Params, metricIndex) + + NVPA_Status NVPW_MetricsEvaluator_GetMetricTypeAndIndex(NVPW_MetricsEvaluator_GetMetricTypeAndIndex_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_ConvertMetricNameToMetricEvalRequest_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] + const char* pMetricName; + /// [inout] 'pMetricEvalRequest' is in, '*pMetricEvalRequest' is out + struct NVPW_MetricEvalRequest* pMetricEvalRequest; + /// [in] set to 'NVPW_MetricEvalRequest_STRUCT_SIZE' + size_t metricEvalRequestStructSize; + } NVPW_MetricsEvaluator_ConvertMetricNameToMetricEvalRequest_Params; +#define NVPW_MetricsEvaluator_ConvertMetricNameToMetricEvalRequest_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_ConvertMetricNameToMetricEvalRequest_Params, metricEvalRequestStructSize) + + NVPA_Status NVPW_MetricsEvaluator_ConvertMetricNameToMetricEvalRequest(NVPW_MetricsEvaluator_ConvertMetricNameToMetricEvalRequest_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_HwUnitToString_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] one of 'NVPW_HwUnit' + uint32_t hwUnit; + /// [out] + const char* pHwUnitName; + } NVPW_MetricsEvaluator_HwUnitToString_Params; +#define NVPW_MetricsEvaluator_HwUnitToString_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_HwUnitToString_Params, pHwUnitName) + + NVPA_Status NVPW_MetricsEvaluator_HwUnitToString(NVPW_MetricsEvaluator_HwUnitToString_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_GetCounterProperties_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] the metric index as in 'NVPW_MetricsEvaluator_GetMetricNames' + size_t counterIndex; + /// [out] + const char* pDescription; + /// [out] one of 'NVPW_HwUnit' + uint32_t hwUnit; + } NVPW_MetricsEvaluator_GetCounterProperties_Params; +#define NVPW_MetricsEvaluator_GetCounterProperties_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_GetCounterProperties_Params, hwUnit) + + NVPA_Status NVPW_MetricsEvaluator_GetCounterProperties(NVPW_MetricsEvaluator_GetCounterProperties_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_GetRatioMetricProperties_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] the metric index as in 'NVPW_MetricsEvaluator_GetMetricNames' + size_t ratioMetricIndex; + /// [out] + const char* pDescription; + /// [out] + uint64_t hwUnit; + } NVPW_MetricsEvaluator_GetRatioMetricProperties_Params; +#define NVPW_MetricsEvaluator_GetRatioMetricProperties_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_GetRatioMetricProperties_Params, hwUnit) + + NVPA_Status NVPW_MetricsEvaluator_GetRatioMetricProperties(NVPW_MetricsEvaluator_GetRatioMetricProperties_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_GetThroughputMetricProperties_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] the metric index as in 'NVPW_MetricsEvaluator_GetMetricNames' + size_t throughputMetricIndex; + /// [out] + const char* pDescription; + /// [out] + uint32_t hwUnit; + /// [out] number of constituent counters for the throughput metric + size_t numCounters; + /// [out] metric indices as in 'NVPW_MetricsEvaluator_GetMetricNames', valid if 'numCounters' > 0, otherwise + /// returned as nullptr + const size_t* pCounterIndices; + /// [out] number of constituent sub-throughputs for the throughput metric + size_t numSubThroughputs; + /// [out] metric indices as in 'NVPW_MetricsEvaluator_GetMetricNames', valid if 'numSubThroughputs' > 0, + /// otherwise returned as nullptr + const size_t* pSubThroughputIndices; + } NVPW_MetricsEvaluator_GetThroughputMetricProperties_Params; +#define NVPW_MetricsEvaluator_GetThroughputMetricProperties_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_GetThroughputMetricProperties_Params, pSubThroughputIndices) + + NVPA_Status NVPW_MetricsEvaluator_GetThroughputMetricProperties(NVPW_MetricsEvaluator_GetThroughputMetricProperties_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_GetSupportedSubmetrics_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] one of 'NVPW_MetricType' + uint8_t metricType; + /// [out] an array of 'NVPW_Submetric' + const uint16_t* pSupportedSubmetrics; + /// [out] + size_t numSupportedSubmetrics; + } NVPW_MetricsEvaluator_GetSupportedSubmetrics_Params; +#define NVPW_MetricsEvaluator_GetSupportedSubmetrics_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_GetSupportedSubmetrics_Params, numSupportedSubmetrics) + + NVPA_Status NVPW_MetricsEvaluator_GetSupportedSubmetrics(NVPW_MetricsEvaluator_GetSupportedSubmetrics_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_GetMetricRawDependencies_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] + const struct NVPW_MetricEvalRequest* pMetricEvalRequests; + /// [in] + size_t numMetricEvalRequests; + /// [in] set to 'NVPW_MetricEvalRequest_STRUCT_SIZE' + size_t metricEvalRequestStructSize; + /// [in] set to sizeof('NVPW_MetricEvalRequest') + size_t metricEvalRequestStrideSize; + /// [inout] 'ppRawDependencies' is in, '*ppRawDependencies' is out + const char** ppRawDependencies; + /// [inout] if 'ppRawDependencies' is NULL, number of raw dependencies available will be returned; otherwise it + /// should be set to the number of elements allocated for 'ppRawDependencies', and on return, it will be + /// overwritten by number of elements copied to 'ppRawDependencies' + size_t numRawDependencies; + /// [inout] 'ppOptionalRawDependencies' is in, '*ppOptionalRawDependencies' is out + const char** ppOptionalRawDependencies; + /// [inout] if 'ppOptionalRawDependencies' is NULL, number of optional raw dependencies available will be + /// returned; otherwise it should be set to the number of elements allocated for 'ppOptionalRawDependencies', + /// and on return, it will be overwritten by number of elements copied to 'ppOptionalRawDependencies' + size_t numOptionalRawDependencies; + } NVPW_MetricsEvaluator_GetMetricRawDependencies_Params; +#define NVPW_MetricsEvaluator_GetMetricRawDependencies_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_GetMetricRawDependencies_Params, numOptionalRawDependencies) + + NVPA_Status NVPW_MetricsEvaluator_GetMetricRawDependencies(NVPW_MetricsEvaluator_GetMetricRawDependencies_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_DimUnitToString_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] one of 'NVPW_DimUnitName' + uint32_t dimUnit; + /// [out] + const char* pSingularName; + /// [out] + const char* pPluralName; + } NVPW_MetricsEvaluator_DimUnitToString_Params; +#define NVPW_MetricsEvaluator_DimUnitToString_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_DimUnitToString_Params, pPluralName) + + NVPA_Status NVPW_MetricsEvaluator_DimUnitToString(NVPW_MetricsEvaluator_DimUnitToString_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_GetMetricDimUnits_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] + const struct NVPW_MetricEvalRequest* pMetricEvalRequest; + /// [in] set to 'NVPW_MetricEvalRequest_STRUCT_SIZE' + size_t metricEvalRequestStructSize; + /// [inout] 'pDimUnits' is in, '*pDimUnits' is out + NVPW_DimUnitFactor* pDimUnits; + /// [inout] if 'pDimUnits' is NULL, number of dim-units available will be returned; otherwise it should be set + /// to the number of elements allocated for 'pDimUnits', and on return, it will be overwritten by number of + /// elements copied to 'pDimUnits' + size_t numDimUnits; + /// [in] set to 'NVPW_DimUnitFactor_STRUCT_SIZE' + size_t dimUnitFactorStructSize; + } NVPW_MetricsEvaluator_GetMetricDimUnits_Params; +#define NVPW_MetricsEvaluator_GetMetricDimUnits_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_GetMetricDimUnits_Params, dimUnitFactorStructSize) + + NVPA_Status NVPW_MetricsEvaluator_GetMetricDimUnits(NVPW_MetricsEvaluator_GetMetricDimUnits_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_SetUserData_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] duration in ns of user defined frame + double frameDuration; + /// [in] duration in ns of user defined region + double regionDuration; + /// [in] + NVPA_Bool isolated; + } NVPW_MetricsEvaluator_SetUserData_Params; +#define NVPW_MetricsEvaluator_SetUserData_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_SetUserData_Params, isolated) + + NVPA_Status NVPW_MetricsEvaluator_SetUserData(NVPW_MetricsEvaluator_SetUserData_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_EvaluateToGpuValues_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] + const struct NVPW_MetricEvalRequest* pMetricEvalRequests; + /// [in] + size_t numMetricEvalRequests; + /// [in] set to 'NVPW_MetricEvalRequest_STRUCT_SIZE' + size_t metricEvalRequestStructSize; + /// [in] set to sizeof('NVPW_MetricEvalRequest') + size_t metricEvalRequestStrideSize; + /// [in] + const uint8_t* pCounterDataImage; + /// [in] + size_t counterDataImageSize; + /// [in] + size_t rangeIndex; + /// [in] + NVPA_Bool isolated; + /// [inout] 'pMetricValues' is in, '*pMetricValues' is out + double* pMetricValues; + } NVPW_MetricsEvaluator_EvaluateToGpuValues_Params; +#define NVPW_MetricsEvaluator_EvaluateToGpuValues_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_EvaluateToGpuValues_Params, pMetricValues) + + NVPA_Status NVPW_MetricsEvaluator_EvaluateToGpuValues(NVPW_MetricsEvaluator_EvaluateToGpuValues_Params* pParams); + + typedef struct NVPW_MetricsEvaluator_SetDeviceAttributes_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct NVPW_MetricsEvaluator* pMetricsEvaluator; + /// [in] + const uint8_t* pCounterDataImage; + /// [in] + size_t counterDataImageSize; + } NVPW_MetricsEvaluator_SetDeviceAttributes_Params; +#define NVPW_MetricsEvaluator_SetDeviceAttributes_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_MetricsEvaluator_SetDeviceAttributes_Params, counterDataImageSize) + + NVPA_Status NVPW_MetricsEvaluator_SetDeviceAttributes(NVPW_MetricsEvaluator_SetDeviceAttributes_Params* pParams); + +/** + * @} + ******************************************************************************/ + + +#endif // NVPERF_HOST_API_DEFINED + + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#if defined(__GNUC__) && defined(NVPA_SHARED_LIB) + #pragma GCC visibility pop +#endif + +#endif // NVPERF_HOST_H diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_target.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_target.h new file mode 100644 index 0000000000000000000000000000000000000000..b1c5c85b403c5ebb16d66882aa26c1f1db1d5089 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/include/nvperf_target.h @@ -0,0 +1,626 @@ +#ifndef NVPERF_TARGET_H +#define NVPERF_TARGET_H + +/* + * Copyright 2014-2024 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO USER: + * + * This source code is subject to NVIDIA ownership rights under U.S. and + * international Copyright laws. + * + * This software and the information contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and conditions + * of a form of NVIDIA software license agreement. + * + * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE + * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR + * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE + * OR PERFORMANCE OF THIS SOURCE CODE. + * + * U.S. Government End Users. This source code is a "commercial item" as + * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of + * "commercial computer software" and "commercial computer software + * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) + * and is provided to the U.S. Government only as a commercial end item. + * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through + * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the + * source code with only those rights set forth herein. + * + * Any use of this source code in individual and commercial software must + * include, in the user documentation and internal comments to the code, + * the above Disclaimer and U.S. Government End Users Notice. + */ + +#include +#include +#include "nvperf_common.h" + +#if defined(__GNUC__) && defined(NVPA_SHARED_LIB) + #pragma GCC visibility push(default) + #if !defined(NVPW_LOCAL) + #define NVPW_LOCAL __attribute__ ((visibility ("hidden"))) + #endif +#else + #if !defined(NVPW_LOCAL) + #define NVPW_LOCAL + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file nvperf_target.h + */ + +#ifndef NVPW_GPU_ARCHITECTURE_SUPPORT_LEVEL_DEFINED +#define NVPW_GPU_ARCHITECTURE_SUPPORT_LEVEL_DEFINED + /// GPU architecture support level + typedef enum NVPW_GpuArchitectureSupportLevel + { + NVPW_GPU_ARCHITECTURE_SUPPORT_LEVEL_UNKNOWN = 0, + NVPW_GPU_ARCHITECTURE_SUPPORT_LEVEL_UNSUPPORTED, + NVPW_GPU_ARCHITECTURE_SUPPORT_LEVEL_SUPPORTED + } NVPW_GpuArchitectureSupportLevel; +#endif //NVPW_GPU_ARCHITECTURE_SUPPORT_LEVEL_DEFINED + +#ifndef NVPW_SLI_SUPPORT_LEVEL_DEFINED +#define NVPW_SLI_SUPPORT_LEVEL_DEFINED + /// SLI configuration support level + typedef enum NVPW_SliSupportLevel + { + NVPW_SLI_SUPPORT_LEVEL_UNKNOWN = 0, + NVPW_SLI_SUPPORT_LEVEL_UNSUPPORTED, + /// Only Non-SLI configurations are supported. + NVPW_SLI_SUPPORT_LEVEL_SUPPORTED_NON_SLI_CONFIGURATION + } NVPW_SliSupportLevel; +#endif //NVPW_SLI_SUPPORT_LEVEL_DEFINED + +#ifndef NVPW_VGPU_SUPPORT_LEVEL_DEFINED +#define NVPW_VGPU_SUPPORT_LEVEL_DEFINED + /// Virtualized GPU configuration support level + typedef enum NVPW_VGpuSupportLevel + { + NVPW_VGPU_SUPPORT_LEVEL_UNKNOWN = 0, + NVPW_VGPU_SUPPORT_LEVEL_UNSUPPORTED, + /// Supported but not allowed by system admin. + NVPW_VGPU_SUPPORT_LEVEL_SUPPORTED_DISALLOWED, + NVPW_VGPU_SUPPORT_LEVEL_SUPPORTED_ALLOWED, + NVPW_VGPU_SUPPORT_LEVEL_SUPPORTED_NON_VGPU_CONFIGURATION + } NVPW_VGpuSupportLevel; +#endif //NVPW_VGPU_SUPPORT_LEVEL_DEFINED + +#ifndef NVPW_CONF_COMPUTE_SUPPORT_LEVEL_DEFINED +#define NVPW_CONF_COMPUTE_SUPPORT_LEVEL_DEFINED + /// Confidential Compute mode support level + typedef enum NVPW_ConfidentialComputeSupportLevel + { + NVPW_CONF_COMPUTE_SUPPORT_LEVEL_UNKNOWN = 0, + NVPW_CONF_COMPUTE_SUPPORT_LEVEL_UNSUPPORTED, + NVPW_CONF_COMPUTE_SUPPORT_LEVEL_SUPPORTED_NON_CONF_COMPUTE_CONFIGURATION, + NVPW_CONF_COMPUTE_SUPPORT_LEVEL_SUPPORTED_CONF_COMPUTE_DEVTOOLS_MODE + } NVPW_ConfidentialComputeSupportLevel; +#endif //NVPW_CONF_COMPUTE_SUPPORT_LEVEL_DEFINED + +#ifndef NVPW_CMP_SUPPORT_LEVEL_DEFINED +#define NVPW_CMP_SUPPORT_LEVEL_DEFINED + /// CMP support level + typedef enum NVPW_CmpSupportLevel + { + NVPW_CMP_SUPPORT_LEVEL_UNKNOWN = 0, + NVPW_CMP_SUPPORT_LEVEL_UNSUPPORTED, + NVPW_CMP_SUPPORT_LEVEL_SUPPORTED_NON_CMP_CONFIGURATON + } NVPW_CmpSupportLevel; +#endif //NVPW_CMP_SUPPORT_LEVEL_DEFINED + +#ifndef NVPW_WSL_SUPPORT_LEVEL_DEFINED +#define NVPW_WSL_SUPPORT_LEVEL_DEFINED + /// WSL support level + typedef enum NVPW_WslSupportLevel + { + NVPW_WSL_SUPPORT_LEVEL_UNKNOWN = 0, + NVPW_WSL_SUPPORT_LEVEL_UNSUPPORTED_INSUFFICIENT_DRIVER_VERSION, + NVPW_WSL_SUPPORT_LEVEL_SUPPORTED, + NVPW_WSL_SUPPORT_LEVEL_SUPPORTED_NON_WSL_CONFIGURATION + } NVPW_WslSupportLevel; +#endif //NVPW_WSL_SUPPORT_LEVEL_DEFINED + +#ifndef NVPW_MIG_SUPPORT_LEVEL_DEFINED +#define NVPW_MIG_SUPPORT_LEVEL_DEFINED + /// MIG support level + typedef enum NVPW_MigSupportLevel + { + NVPW_MIG_SUPPORT_LEVEL_UNKNOWN = 0, + NVPW_MIG_SUPPORT_LEVEL_UNSUPPORTED, + NVPW_MIG_SUPPORT_LEVEL_SUPPORTED, + NVPW_MIG_SUPPORT_LEVEL_SUPPORTED_NON_MIG_CONFIGURATION + } NVPW_MigSupportLevel; +#endif //NVPW_MIG_SUPPORT_LEVEL_DEFINED + + typedef struct NVPW_InitializeTarget_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + } NVPW_InitializeTarget_Params; +#define NVPW_InitializeTarget_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_InitializeTarget_Params, pPriv) + + /// Load the target library. + NVPA_Status NVPW_InitializeTarget(NVPW_InitializeTarget_Params* pParams); + + typedef struct NVPW_GetDeviceCount_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + size_t numDevices; + } NVPW_GetDeviceCount_Params; +#define NVPW_GetDeviceCount_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_GetDeviceCount_Params, numDevices) + + NVPA_Status NVPW_GetDeviceCount(NVPW_GetDeviceCount_Params* pParams); + + typedef struct NVPW_Device_GetNames_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + size_t deviceIndex; + const char* pDeviceName; + const char* pChipName; + } NVPW_Device_GetNames_Params; +#define NVPW_Device_GetNames_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Device_GetNames_Params, pChipName) + + NVPA_Status NVPW_Device_GetNames(NVPW_Device_GetNames_Params* pParams); + + typedef struct NVPW_PciBusId + { + /// The PCI domain on which the device bus resides. + uint32_t domain; + /// The bus on which the device resides. + uint16_t bus; + /// device ID. + uint16_t device; + } NVPW_PciBusId; +#define NVPW_PciBusId_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_PciBusId, device) + + typedef struct NVPW_Device_GetPciBusIds_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] caller-allocated array of NVPW_PciBusId, indexed by NVPW deviceIndex + NVPW_PciBusId* pBusIds; + /// [in] size of the pBusIDs array; use result from NVPW_GetDeviceCount + size_t numDevices; + } NVPW_Device_GetPciBusIds_Params; +#define NVPW_Device_GetPciBusIds_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Device_GetPciBusIds_Params, numDevices) + + NVPA_Status NVPW_Device_GetPciBusIds(NVPW_Device_GetPciBusIds_Params* pParams); + + +#define NVPW_DEVICE_MIG_GPU_INSTANCE_ID_INVALID 0xFFFFFFFFu +#define NVPW_DEVICE_MIG_GPU_INSTANCE_ID_FULLCHIP 0xFFFFFFFEu + + + typedef struct NVPW_Device_GetMigAttributes_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + size_t deviceIndex; + /// [out] + NVPA_Bool isMigPartition; + /// [out] + uint32_t gpuInstanceId; + /// [out] + uint32_t computeInstanceId; + } NVPW_Device_GetMigAttributes_Params; +#define NVPW_Device_GetMigAttributes_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Device_GetMigAttributes_Params, computeInstanceId) + + NVPA_Status NVPW_Device_GetMigAttributes(NVPW_Device_GetMigAttributes_Params* pParams); + + typedef struct NVPW_Adapter_GetDeviceIndex_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + struct IDXGIAdapter* pAdapter; + /// [in] + size_t sliIndex; + /// [out] + size_t deviceIndex; + } NVPW_Adapter_GetDeviceIndex_Params; +#define NVPW_Adapter_GetDeviceIndex_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Adapter_GetDeviceIndex_Params, deviceIndex) + + NVPA_Status NVPW_Adapter_GetDeviceIndex(NVPW_Adapter_GetDeviceIndex_Params* pParams); + + typedef struct NVPW_CounterData_GetNumRanges_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const uint8_t* pCounterDataImage; + size_t numRanges; + } NVPW_CounterData_GetNumRanges_Params; +#define NVPW_CounterData_GetNumRanges_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterData_GetNumRanges_Params, numRanges) + + NVPA_Status NVPW_CounterData_GetNumRanges(NVPW_CounterData_GetNumRanges_Params* pParams); + + typedef struct NVPW_CounterData_GetChipName_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pCounterDataImage; + /// [in] + size_t counterDataImageSize; + /// [out] + const char* pChipName; + } NVPW_CounterData_GetChipName_Params; +#define NVPW_CounterData_GetChipName_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterData_GetChipName_Params, pChipName) + + NVPA_Status NVPW_CounterData_GetChipName(NVPW_CounterData_GetChipName_Params* pParams); + + typedef struct NVPW_Config_GetNumPasses_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pConfig; + /// [out] + size_t numPipelinedPasses; + /// [out] + size_t numIsolatedPasses; + } NVPW_Config_GetNumPasses_Params; +#define NVPW_Config_GetNumPasses_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Config_GetNumPasses_Params, numIsolatedPasses) + + /// Total num passes = numPipelinedPasses + numIsolatedPasses * numNestingLevels + NVPA_Status NVPW_Config_GetNumPasses(NVPW_Config_GetNumPasses_Params* pParams); + + typedef struct NVPW_Config_GetNumPasses_V2_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pConfig; + /// [out] + size_t numPasses; + } NVPW_Config_GetNumPasses_V2_Params; +#define NVPW_Config_GetNumPasses_V2_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Config_GetNumPasses_V2_Params, numPasses) + + /// Total num passes = numPasses * numNestingLevels + NVPA_Status NVPW_Config_GetNumPasses_V2(NVPW_Config_GetNumPasses_V2_Params* pParams); + +#define NVPW_API_SET_CUDA_PROFILER 0x18209d0775b2f89dULL + +#define NVPW_API_SET_D3D11_PROFILER 0xca55c6738445db2bULL + +#define NVPW_API_SET_D3D12_PROFILER 0xc0c2d46dd7c7ad78ULL + +#define NVPW_API_SET_EGL_PROFILER 0x3c3747dae1f9565cULL + +#define NVPW_API_SET_GPU_PERIODICSAMPLER 0x9f4c2571fc0b2e8aULL + +#define NVPW_API_SET_METRICSEVALUATOR 0x0368a8768d811af9ULL + +#define NVPW_API_SET_METRICS_AD10X_COMP 0xbe57278e12cb5288ULL + +#define NVPW_API_SET_METRICS_AD10X_GRFX 0x5cbf0774f81bf491ULL + +#define NVPW_API_SET_METRICS_GA100_COMP 0x16b7d8c20d8b4915ULL + +#define NVPW_API_SET_METRICS_GA100_GRFX 0xc94eaabec04a94faULL + +#define NVPW_API_SET_METRICS_GA10X_COMP 0xb5d6391c2e299ab5ULL + +#define NVPW_API_SET_METRICS_GA10X_GRFX 0x6ebc121178b5ce0bULL + +#define NVPW_API_SET_METRICS_GV100_COMP 0x863705cc57919f72ULL + +#define NVPW_API_SET_METRICS_GV100_GRFX 0x9900da75d164fecfULL + +#define NVPW_API_SET_METRICS_GV11B_COMP 0xd3f79a859235848fULL + +#define NVPW_API_SET_METRICS_GV11B_GRFX 0xeb8e26220106e227ULL + +#define NVPW_API_SET_METRICS_TU10X_COMP 0x70f40be0afd35da8ULL + +#define NVPW_API_SET_METRICS_TU10X_GRFX 0xdf219cb838db6968ULL + +#define NVPW_API_SET_METRICS_TU11X_COMP 0xeb0069d7d0956678ULL + +#define NVPW_API_SET_METRICS_TU11X_GRFX 0x0977d9342bd62743ULL + +#define NVPW_API_SET_OPENGL_PROFILER 0xe4cd9ea40f2ee777ULL + +#define NVPW_API_SET_VULKAN_PROFILER 0x8c56b6a03d779689ULL + +#define NVPW_SDK_VERSION 0x1e128b6f001423fcULL + + typedef struct NVPW_QueryVersionNumber_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + uint64_t apiSet; + /// [out] + uint32_t major; + /// [out] + uint32_t minor; + /// [out] + uint32_t patch; + /// [out] + uint32_t relMajor; + /// [out] + uint32_t relMinor; + /// [out] + uint32_t relPatch; + } NVPW_QueryVersionNumber_Params; +#define NVPW_QueryVersionNumber_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_QueryVersionNumber_Params, relPatch) + + /// Query version number of an API set + NVPA_Status NVPW_QueryVersionNumber(NVPW_QueryVersionNumber_Params* pParams); + + typedef enum NVPW_Device_ClockStatus + { + /// clock status is unknown + NVPW_DEVICE_CLOCK_STATUS_UNKNOWN, + /// clocks are locked to rated tdp values - Deprecated, use NVPW_DEVICE_CLOCK_STATUS_LOCKED instead + NVPW_DEVICE_CLOCK_STATUS_LOCKED_TO_RATED_TDP, + /// clocks are not locked and can boost above rated tdp + NVPW_DEVICE_CLOCK_STATUS_BOOST_ENABLED, + /// clocks are not locked and will not go above rated tdp + NVPW_DEVICE_CLOCK_STATUS_BOOST_DISABLED, + /// clocks are locked + NVPW_DEVICE_CLOCK_STATUS_LOCKED, + /// clocks are not locked + NVPW_DEVICE_CLOCK_STATUS_UNLOCKED, + NVPW_DEVICE_CLOCK_STATUS__COUNT + } NVPW_Device_ClockStatus; + + typedef enum NVPW_Device_ClockLevel + { + /// clock level is invalid + NVPW_DEVICE_CLOCK_LEVEL_INVALID, + /// clock level is at rated tdp + NVPW_DEVICE_CLOCK_LEVEL_RATED_TDP, + /// clock level is at turbo boost + NVPW_DEVICE_CLOCK_LEVEL_TURBO_BOOST, + NVPW_DEVICE_CLOCK_LEVEL__COUNT + } NVPW_Device_ClockLevel; + + typedef struct NVPW_Device_GetClockStatus_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + size_t deviceIndex; + /// [in] + NVPW_Device_ClockStatus clockStatus; + /// [in] + NVPW_Device_ClockLevel clockLevel; + } NVPW_Device_GetClockStatus_Params; +#define NVPW_Device_GetClockStatus_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Device_GetClockStatus_Params, clockLevel) + + NVPA_Status NVPW_Device_GetClockStatus(NVPW_Device_GetClockStatus_Params* pParams); + + typedef enum NVPW_Device_ClockSetting + { + /// invalid op, specify valid clocks operation during profiling + NVPW_DEVICE_CLOCK_SETTING_INVALID, + /// default to driver/application config (normally unlocked and not boosted, but could be unlocked boosted, or + /// locked to rated TDP) + NVPW_DEVICE_CLOCK_SETTING_DEFAULT, + /// lock clocks at rated tdp base values + NVPW_DEVICE_CLOCK_SETTING_LOCK_TO_RATED_TDP, + /// lock clocks at turbo boost values + NVPW_DEVICE_CLOCK_SETTING_LOCK_TO_TURBO_BOOST, + NVPW_DEVICE_CLOCK_SETTING__COUNT + } NVPW_Device_ClockSetting; + + typedef struct NVPW_Device_SetClockSetting_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + size_t deviceIndex; + /// [in] + NVPW_Device_ClockSetting clockSetting; + } NVPW_Device_SetClockSetting_Params; +#define NVPW_Device_SetClockSetting_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Device_SetClockSetting_Params, clockSetting) + + NVPA_Status NVPW_Device_SetClockSetting(NVPW_Device_SetClockSetting_Params* pParams); + + typedef struct NVPW_CounterData_GetRangeDescriptions_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const uint8_t* pCounterDataImage; + size_t rangeIndex; + /// [inout] Number of descriptions allocated in ppDescriptions + size_t numDescriptions; + const char** ppDescriptions; + } NVPW_CounterData_GetRangeDescriptions_Params; +#define NVPW_CounterData_GetRangeDescriptions_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_CounterData_GetRangeDescriptions_Params, ppDescriptions) + + NVPA_Status NVPW_CounterData_GetRangeDescriptions(NVPW_CounterData_GetRangeDescriptions_Params* pParams); + + typedef struct NVPW_Profiler_CounterData_GetRangeDescriptions_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + const uint8_t* pCounterDataImage; + size_t rangeIndex; + /// [inout] Number of descriptions allocated in ppDescriptions + size_t numDescriptions; + const char** ppDescriptions; + } NVPW_Profiler_CounterData_GetRangeDescriptions_Params; +#define NVPW_Profiler_CounterData_GetRangeDescriptions_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_Profiler_CounterData_GetRangeDescriptions_Params, ppDescriptions) + + NVPA_Status NVPW_Profiler_CounterData_GetRangeDescriptions(NVPW_Profiler_CounterData_GetRangeDescriptions_Params* pParams); + +#ifndef NVPW_PERIODIC_SAMPLER_COUNTER_DATA_APPEND_MODE_DEFINED +#define NVPW_PERIODIC_SAMPLER_COUNTER_DATA_APPEND_MODE_DEFINED + typedef enum NVPW_PeriodicSampler_CounterData_AppendMode + { + NVPW_PERIODIC_SAMPLER_COUNTER_DATA_APPEND_MODE_LINEAR = 0, + NVPW_PERIODIC_SAMPLER_COUNTER_DATA_APPEND_MODE_CIRCULAR = 1, + NVPW_PERIODIC_SAMPLER_COUNTER_DATA_APPEND_MODE__COUNT + } NVPW_PeriodicSampler_CounterData_AppendMode; +#endif //NVPW_PERIODIC_SAMPLER_COUNTER_DATA_APPEND_MODE_DEFINED + + typedef struct NVPW_PeriodicSampler_CounterData_GetSampleTime_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pCounterDataImage; + /// [in] + size_t rangeIndex; + /// [out] + uint64_t timestampStart; + /// [out] + uint64_t timestampEnd; + } NVPW_PeriodicSampler_CounterData_GetSampleTime_Params; +#define NVPW_PeriodicSampler_CounterData_GetSampleTime_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_PeriodicSampler_CounterData_GetSampleTime_Params, timestampEnd) + + NVPA_Status NVPW_PeriodicSampler_CounterData_GetSampleTime(NVPW_PeriodicSampler_CounterData_GetSampleTime_Params* pParams); + + typedef struct NVPW_PeriodicSampler_CounterData_TrimInPlace_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + uint8_t* pCounterDataImage; + /// [in] + size_t counterDataImageSize; + /// [out] + size_t counterDataImageTrimmedSize; + } NVPW_PeriodicSampler_CounterData_TrimInPlace_Params; +#define NVPW_PeriodicSampler_CounterData_TrimInPlace_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_PeriodicSampler_CounterData_TrimInPlace_Params, counterDataImageTrimmedSize) + + NVPA_Status NVPW_PeriodicSampler_CounterData_TrimInPlace(NVPW_PeriodicSampler_CounterData_TrimInPlace_Params* pParams); + + typedef struct NVPW_PeriodicSampler_CounterData_GetInfo_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pCounterDataImage; + /// [in] + size_t counterDataImageSize; + /// [out] total number of ranges in the counter data + size_t numTotalRanges; + /// [out] if in "linear" mode, this API returns the number of "populated" ranges; if it's in "circular" mode, + /// then it returns the last "populated" range index + 1, when there is no such range, it returns 0. + size_t numPopulatedRanges; + /// [out] if in "linear" mode, this API returns the number of "completed" ranges; if it's in "circular" mode, + /// then it returns the last "completed" range index + 1, when there is no such range, it returns 0. + size_t numCompletedRanges; + } NVPW_PeriodicSampler_CounterData_GetInfo_Params; +#define NVPW_PeriodicSampler_CounterData_GetInfo_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_PeriodicSampler_CounterData_GetInfo_Params, numCompletedRanges) + + /// In periodic sampler, a range in counter data stores exactly one sample's data. For better performance, periodic + /// sampler may operate in an out-of-order fashion when populating sample data, i.e. it may not fully populate all + /// counters of a sample/range before starting to populate the next sample/range. As a result, we have two concepts + /// here, "populated" & "completed": a range is considered "populated" even if only partial counters have been + /// written; on the other hand, a range is only considered "completed" if all the collecting counters have been + /// written. + NVPA_Status NVPW_PeriodicSampler_CounterData_GetInfo(NVPW_PeriodicSampler_CounterData_GetInfo_Params* pParams); + + typedef struct NVPW_PeriodicSampler_CounterData_GetTriggerCount_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pCounterDataImage; + /// [in] + size_t counterDataImageSize; + /// [in] + size_t rangeIndex; + /// [out] + uint32_t triggerCount; + } NVPW_PeriodicSampler_CounterData_GetTriggerCount_Params; +#define NVPW_PeriodicSampler_CounterData_GetTriggerCount_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_PeriodicSampler_CounterData_GetTriggerCount_Params, triggerCount) + + NVPA_Status NVPW_PeriodicSampler_CounterData_GetTriggerCount(NVPW_PeriodicSampler_CounterData_GetTriggerCount_Params* pParams); + + typedef struct NVPW_PeriodicSampler_CounterData_IsDataComplete_Params + { + /// [in] + size_t structSize; + /// [in] assign to NULL + void* pPriv; + /// [in] + const uint8_t* pCounterDataImage; + /// [in] + size_t counterDataImageSize; + /// [in] + size_t rangeIndex; + /// [out] + NVPA_Bool isComplete; + } NVPW_PeriodicSampler_CounterData_IsDataComplete_Params; +#define NVPW_PeriodicSampler_CounterData_IsDataComplete_Params_STRUCT_SIZE NVPA_STRUCT_SIZE(NVPW_PeriodicSampler_CounterData_IsDataComplete_Params, isComplete) + + /// Checks whether a given sample's data is complete. See also 'NVPW_PeriodicSampler_CounterData_GetInfo' + NVPA_Status NVPW_PeriodicSampler_CounterData_IsDataComplete(NVPW_PeriodicSampler_CounterData_IsDataComplete_Params* pParams); + + + typedef struct NVPW_TimestampReport + { + uint32_t payload; + uint8_t reserved0004[4]; + uint64_t timestamp; + } NVPW_TimestampReport; + + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#if defined(__GNUC__) && defined(NVPA_SHARED_LIB) + #pragma GCC visibility pop +#endif + +#endif // NVPERF_TARGET_H diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/lib/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/lib/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/lib/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/lib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a159e561e962bacecee800c106c559cfb9c51e8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cuda_cupti/lib/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e71e52637d1c3b99c8fee3158595a9d211a4430 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/include/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/include/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/include/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/include/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..daa4591078011b2e279a3d024130d197c4ff2287 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/include/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/include/cufile.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/include/cufile.h new file mode 100644 index 0000000000000000000000000000000000000000..ffc3e05b7b786e36fdd700623f53319641c0e908 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/include/cufile.h @@ -0,0 +1,740 @@ +/* + * Copyright 1993-2023 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +/** + * @file cufile.h + * @brief cuFile C APIs + * + * This file contains all the C APIs to perform GPUDirect Storage supported IO operations + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/// @cond DOXYGEN_SKIP_MACRO +#ifndef __CUFILE_H_ +#define __CUFILE_H_ + +#include +#include + +#include +#include +#include + +#define CUFILEOP_BASE_ERR 5000 + +//Note :Data path errors are captured via standard error codes +#define CUFILEOP_STATUS_ENTRIES \ + CUFILE_OP(0, CU_FILE_SUCCESS, cufile success) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 1, CU_FILE_DRIVER_NOT_INITIALIZED, nvidia-fs driver is not loaded. Set allow_compat_mode to true in cufile.json file to enable compatible mode) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 2, CU_FILE_DRIVER_INVALID_PROPS, invalid property) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 3, CU_FILE_DRIVER_UNSUPPORTED_LIMIT, property range error) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 4, CU_FILE_DRIVER_VERSION_MISMATCH, nvidia-fs driver version mismatch) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 5, CU_FILE_DRIVER_VERSION_READ_ERROR, nvidia-fs driver version read error) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 6, CU_FILE_DRIVER_CLOSING, driver shutdown in progress) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 7, CU_FILE_PLATFORM_NOT_SUPPORTED, GPUDirect Storage not supported on current platform) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 8, CU_FILE_IO_NOT_SUPPORTED, GPUDirect Storage not supported on current file) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 9, CU_FILE_DEVICE_NOT_SUPPORTED, GPUDirect Storage not supported on current GPU) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 10, CU_FILE_NVFS_DRIVER_ERROR, nvidia-fs driver ioctl error) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 11, CU_FILE_CUDA_DRIVER_ERROR, CUDA Driver API error) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 12, CU_FILE_CUDA_POINTER_INVALID, invalid device pointer) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 13, CU_FILE_CUDA_MEMORY_TYPE_INVALID, invalid pointer memory type) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 14, CU_FILE_CUDA_POINTER_RANGE_ERROR, pointer range exceeds allocated address range) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 15, CU_FILE_CUDA_CONTEXT_MISMATCH, cuda context mismatch) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 16, CU_FILE_INVALID_MAPPING_SIZE, access beyond maximum pinned size) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 17, CU_FILE_INVALID_MAPPING_RANGE, access beyond mapped size) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 18, CU_FILE_INVALID_FILE_TYPE, unsupported file type) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 19, CU_FILE_INVALID_FILE_OPEN_FLAG, unsupported file open flags) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 20, CU_FILE_DIO_NOT_SET, fd direct IO not set) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 22, CU_FILE_INVALID_VALUE, invalid arguments) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 23, CU_FILE_MEMORY_ALREADY_REGISTERED, device pointer already registered) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 24, CU_FILE_MEMORY_NOT_REGISTERED, device pointer lookup failure) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 25, CU_FILE_PERMISSION_DENIED, driver or file access error) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 26, CU_FILE_DRIVER_ALREADY_OPEN, driver is already open) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 27, CU_FILE_HANDLE_NOT_REGISTERED, file descriptor is not registered) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 28, CU_FILE_HANDLE_ALREADY_REGISTERED, file descriptor is already registered) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 29, CU_FILE_DEVICE_NOT_FOUND, GPU device not found) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 30, CU_FILE_INTERNAL_ERROR, internal error) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 31, CU_FILE_GETNEWFD_FAILED, failed to obtain new file descriptor) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 33, CU_FILE_NVFS_SETUP_ERROR, NVFS driver initialization error) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 34, CU_FILE_IO_DISABLED, GPUDirect Storage disabled by config on current file)\ + CUFILE_OP(CUFILEOP_BASE_ERR + 35, CU_FILE_BATCH_SUBMIT_FAILED, failed to submit batch operation)\ + CUFILE_OP(CUFILEOP_BASE_ERR + 36, CU_FILE_GPU_MEMORY_PINNING_FAILED, failed to allocate pinned GPU Memory) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 37, CU_FILE_BATCH_FULL, queue full for batch operation) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 38, CU_FILE_ASYNC_NOT_SUPPORTED, cuFile stream operation not supported) \ + CUFILE_OP(CUFILEOP_BASE_ERR + 39, CU_FILE_IO_MAX_ERROR, GPUDirect Storage Max Error) + + +/** + * @brief cufileop status enum + * + * @note on success the error code is set to @ref CU_FILE_SUCCESS. + * @note The error code can be inspected using @ref IS_CUFILE_ERR and @ref CUFILE_ERRSTR. + * @note The error code if set to @ref CU_FILE_CUDA_DRIVER_ERROR, then cuda error can be inspected using @ref IS_CUDA_ERR and @ref CU_FILE_CUDA_ERR. + * @note Data path errors are captured via standard error codes + */ +typedef enum CUfileOpError { + /// @cond DOXYGEN_SKIP_MACRO + #define CUFILE_OP(code, name, string) name = code, + CUFILEOP_STATUS_ENTRIES + #undef CUFILE_OP + ///@endcond +} CUfileOpError; + +/// @endcond + +/** + * @brief cufileop status string + */ +static inline const char *cufileop_status_error(CUfileOpError status) +{ + switch (status) { + /// @cond DOXYGEN_SKIP_MACRO + #define CUFILE_OP(code, name, string) \ + case name: return #string; + CUFILEOP_STATUS_ENTRIES + #undef CUFILE_OP + ///@endcond + default:return "unknown cufile error"; + } +} + +/** + * @brief cufileop status string + */ +typedef struct CUfileError { + + CUfileOpError err; // cufile error + + CUresult cu_err; // cuda driver error + +}CUfileError_t; + +/** + * @brief error macros to inspect error status of type @ref CUfileOpError + */ + +#define IS_CUFILE_ERR(err) \ + (abs((err)) > CUFILEOP_BASE_ERR) + +#define CUFILE_ERRSTR(err) \ + cufileop_status_error((CUfileOpError)abs((err))) + +#define IS_CUDA_ERR(status) \ + ((status).err == CU_FILE_CUDA_DRIVER_ERROR) + +#define CU_FILE_CUDA_ERR(status) ((status).cu_err) + +/* driver properties */ +typedef enum CUfileDriverStatusFlags { + CU_FILE_LUSTRE_SUPPORTED = 0, /*!< Support for DDN LUSTRE */ + + CU_FILE_WEKAFS_SUPPORTED = 1, /*!< Support for WEKAFS */ + + CU_FILE_NFS_SUPPORTED = 2, /*!< Support for NFS */ + + CU_FILE_GPFS_SUPPORTED = 3, /*! < Support for GPFS */ + + CU_FILE_NVME_SUPPORTED = 4, /*!< Support for NVMe */ + + CU_FILE_NVMEOF_SUPPORTED = 5, /*!< Support for NVMeOF */ + + CU_FILE_SCSI_SUPPORTED = 6, /*!< Support for SCSI */ + + CU_FILE_SCALEFLUX_CSD_SUPPORTED = 7, /*!< Support for Scaleflux CSD*/ + + CU_FILE_NVMESH_SUPPORTED = 8, /*!< Support for NVMesh Block Dev*/ + CU_FILE_BEEGFS_SUPPORTED = 9, /*!< Support for BeeGFS */ + //10 is reserved for YRCloudFile + CU_FILE_NVME_P2P_SUPPORTED = 11, /*!< Support for NVMe using PCI P2PDMA */ + +}CUfileDriverStatusFlags_t; + +typedef enum CUfileDriverControlFlags { + CU_FILE_USE_POLL_MODE = 0 , /*!< use POLL mode. properties.use_poll_mode*/ + + CU_FILE_ALLOW_COMPAT_MODE = 1/*!< allow COMPATIBILITY mode. properties.allow_compat_mode*/ + +}CUfileDriverControlFlags_t; + +typedef enum CUfileFeatureFlags { + CU_FILE_DYN_ROUTING_SUPPORTED = 0, /*!< Support for Dynamic routing to handle devices across the PCIe bridges */ + + CU_FILE_BATCH_IO_SUPPORTED = 1, /*!< Unsupported */ + + CU_FILE_STREAMS_SUPPORTED = 2, /*!< Unsupported */ + + CU_FILE_PARALLEL_IO_SUPPORTED = 3 /*!< Unsupported */ +}CUfileFeatureFlags_t; + +typedef struct CUfileDrvProps { + struct { + unsigned int major_version; + + unsigned int minor_version; + + size_t poll_thresh_size; + + size_t max_direct_io_size; + + unsigned int dstatusflags; + + unsigned int dcontrolflags; + + } nvfs; + + unsigned int fflags; + + unsigned int max_device_cache_size; + + unsigned int per_buffer_cache_size; + + unsigned int max_device_pinned_mem_size; + + unsigned int max_batch_io_size; + unsigned int max_batch_io_timeout_msecs; +}CUfileDrvProps_t; + +typedef struct sockaddr sockaddr_t; + +typedef struct cufileRDMAInfo +{ + int version; + int desc_len; + const char *desc_str; +}cufileRDMAInfo_t; + +#define CU_FILE_RDMA_REGISTER 1 +#define CU_FILE_RDMA_RELAXED_ORDERING (1<<1) + + + +typedef struct CUfileFSOps { + /* NULL means discover using fstat */ + const char* (*fs_type) (void *handle); + + /* list of host addresses to use, NULL means no restriction */ + int (*getRDMADeviceList)(void *handle, sockaddr_t **hostaddrs); + + /* -1 no pref */ + int (*getRDMADevicePriority)(void *handle, char*, size_t, + loff_t, sockaddr_t* hostaddr); + + /* NULL means try VFS */ + ssize_t (*read) (void *handle, char*, size_t, loff_t, cufileRDMAInfo_t*); + ssize_t (*write) (void *handle, const char *, size_t, loff_t , cufileRDMAInfo_t*); +}CUfileFSOps_t; + +/* File Handle */ +enum CUfileFileHandleType { + CU_FILE_HANDLE_TYPE_OPAQUE_FD = 1, /*!< Linux based fd */ + + CU_FILE_HANDLE_TYPE_OPAQUE_WIN32 = 2, /*!< Windows based handle (unsupported) */ + + CU_FILE_HANDLE_TYPE_USERSPACE_FS = 3, /* Userspace based FS */ +}; + +typedef struct CUfileDescr_t { + enum CUfileFileHandleType type; /* type of file being registered */ + union { + int fd; /* Linux */ + void *handle; /* Windows */ + } handle; + const CUfileFSOps_t *fs_ops; /* file system operation table */ +}CUfileDescr_t; + +/** + * @brief File handle type + * + */ +typedef void* CUfileHandle_t; + + +#pragma GCC visibility push(default) + +/** + * @brief cuFileHandleRegister is required, and performs extra checking that is memoized to provide increased performance on later cuFile operations. + * + * @param fh @ref CUfileHandle_t opaque file handle for IO operations + * @param descr @ref CUfileDescr_t file descriptor (OS agnostic) + * + * @return CU_FILE_SUCCESS on successful completion. fh will be updated for use in @ref cuFileRead, @ref cuFileWrite, @ref cuFileHandleDeregister + * @return CU_FILE_DRIVER_NOT_INITIALIZED on failure to load driver + * @return CU_FILE_IO_NOT_SUPPORTED - if filesystem is not supported + * @return CU_FILE_INVALID_VALUE if null or bad api arguments + * @return CU_FILE_INVALID_FILE_OPEN_FLAG if file is opened with unsupported modes like no O_DIRECT + * @return CU_FILE_INVALID_FILE_TYPE if filepath is not valid or is not a regular file + * @return CU_FILE_HANDLE_ALREADY_REGISTERED if file handle/descriptor is already registered + * + * Description + * cuFileHandleRegister registers the open file descriptor for use with cuFile IO operations. + * + * This API will ensure that the file’s descriptor is checked for GPUDirect Storage support and returns a valid file handle on CU_FILE_SUCCESS. + * + * @note the file needs to be opened in O_DIRECT mode to support GPUDirect Storage. + * + * @see cuFileRead + * @see cuFileWrite + * @see cuFileHandleDeregister + * + */ +CUfileError_t cuFileHandleRegister(CUfileHandle_t *fh, CUfileDescr_t *descr); + +/** + * @brief releases a registered filehandle from cuFile + * + * @param fh @ref CUfileHandle_t file handle + * + * @return void + * + * @see cuFileHandleRegister + */ +void cuFileHandleDeregister(CUfileHandle_t fh); + +/** + * @brief register an existing cudaMalloced memory with cuFile to pin for GPUDirect Storage access or + * register host allocated memory with cuFile. + * + * @param bufPtr_base buffer pointer allocated + * @param length size of memory region from the above specified bufPtr + * @param flags CU_FILE_RDMA_REGISTER + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_NVFS_DRIVER_ERROR + * @return CU_FILE_INVALID_VALUE + * @return CU_FILE_CUDA_ERROR for unsuported memory type + * @return CU_FILE_MEMORY_ALREADY_REGISTERED on error + * @return CU_FILE_GPU_MEMORY_PINNING_FAILED if not enough pinned memory is available + * @note This memory will be use to perform GPU direct DMA from the supported storage. + * @warning This API is intended for usecases where the memory is used as streaming buffer that is reused across multiple cuFile IO operations before calling @ref cuFileBufDeregister + * + * @see cuFileBufDeregister + * @see cuFileRead + * @see cuFileWrite + */ +CUfileError_t cuFileBufRegister(const void *bufPtr_base, size_t length, int flags); + +/** + * @brief deregister an already registered device or host memory from cuFile + * + * @param bufPtr_base buffer pointer to deregister + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_INVALID_VALUE on invalid memory pointer or unregistered memory pointer + * + * @see cuFileBufRegister + * @see cuFileRead + * @see cuFileWrite + */ + +CUfileError_t cuFileBufDeregister(const void *bufPtr_base); + +/** + * @brief read data from a registered file handle to a specified device or host memory + * + * @param fh @ref CUfileHandle_t opaque file handle + * @param bufPtr_base base address of buffer in device or host memory + * @param size size bytes to read + * @param file_offset file-offset from begining of the file + * @param bufPtr_offset offset relative to the bufPtr_base pointer to read into. + * + * @return size of bytes successfully read + * @return -1 on error, in which case errno is set to indicate filesystem errors. + * @return all other errors will return a negative integer value of @ref CUfileOpError enum value. + * + * @note If the bufPtr is not registered with @ref cuFileBufRegister, the data will be buffered through preallocated pinned buffers if needed. + * @note This is useful for applications that need to perform IO to unaligned file offsets and/or size. This is also recommended + * for cases where the BAR1 memory size is smaller than the size of the allocated memory. + * + * @see cuFileBufRegister + * @see cuFileHandleRegister + * @see cuFileWrite + */ + +ssize_t cuFileRead(CUfileHandle_t fh, void *bufPtr_base, size_t size, off_t file_offset, off_t bufPtr_offset); + +/** + * @brief write data from a specified device or host memory to a registered file handle + * + * @param fh @ref CUfileHandle_t opaque file handle + * @param bufPtr_base base address of buffer in device or host memory + * @param size size bytes to write + * @param file_offset file-offset from begining of the file + * @param bufPtr_offset offset relative to the bufPtr_base pointer to write from. + * + * @return size of bytes successfully written + * @return -1 on error, in which case errno is set to indicate filesystem errors. + * @return all other errors will return a negative integer value of @ref CUfileOpError enum value. + * + * @note If the bufPtr is not registered with @ref cuFileBufRegister, the data will be buffered through preallocated pinned buffers if needed. + * @note This is useful for applications that need to perform IO to unaligned file offsets and/or size. This is also recommended + * for cases where the BAR1 memory size is smaller than the size of the allocated memory. + * + * @see cuFileBufRegister + * @see cuFileHandleRegister + * @see cuFileRead + */ + +ssize_t cuFileWrite(CUfileHandle_t fh, const void *bufPtr_base, size_t size, off_t file_offset, off_t bufPtr_offset); + +// CUFile Driver APIs + +/** + * @brief + * Initialize the cuFile library and open the nvidia-fs driver + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_DRIVER_NOT_INITIALIZED + * @return CU_FILE_DRIVER_VERSION_MISMATCH on driver version mismatch error + * + * @see cuFileDriverClose + */ +CUfileError_t cuFileDriverOpen(void); + +CUfileError_t cuFileDriverClose(void); +#define cuFileDriverClose cuFileDriverClose_v2 +/** + * @brief + * reset the cuFile library and release the nvidia-fs driver + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_DRIVER_CLOSING if there are any active IO operations using @ref cuFileRead or @ref cuFileWrite + * + * @see cuFileDriverOpen + */ +CUfileError_t cuFileDriverClose(void); + +/** + * @brief + * returns use count of cufile drivers at that moment by the process. + */ +long cuFileUseCount(void); + +/** + * @brief + * Gets the Driver session properties + * + * @return CU_FILE_SUCCESS on success + * + * @see cuFileDriverSetPollMode + * @see cuFileDriverSetMaxDirectIOSize + * @see cuFileDriverSetMaxCacheSize + * @see cuFileDriverSetMaxPinnedMemSize + */ +CUfileError_t cuFileDriverGetProperties(CUfileDrvProps_t *props); + +/** + * @brief + * Sets whether the Read/Write APIs use polling to do IO operations + * + * @param poll boolean to indicate whether to use poll mode or not + * @param poll_threshold_size max IO size to use for POLLING mode in KB + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_DRIVER_NOT_INITIALIZED if the driver is not initialized + * @return CU_FILE_DRIVER_VERSION_MISMATCH, CU_FILE_DRIVER_UNSUPPORTED_LIMIT on error + * + * @warning This is an advanced command and should be tuned based on available system memory + * + * @see cuFileDriverGetProperties + */ +CUfileError_t cuFileDriverSetPollMode(bool poll, size_t poll_threshold_size); + +/** + * @brief + * Control parameter to set max IO size(KB) used by the library to talk to nvidia-fs driver + * + * @param max_direct_io_size maximum allowed direct io size in KB + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_DRIVER_NOT_INITIALIZED if the driver is not initialized + * @return CU_FILE_DRIVER_VERSION_MISMATCH, CU_FILE_DRIVER_UNSUPPORTED_LIMIT on error + * + * @warning This is an advanced command and should be tuned based on available system memory + * + * @see cuFileDriverGetProperties + * + */ +CUfileError_t cuFileDriverSetMaxDirectIOSize(size_t max_direct_io_size); + +/** + * @brief + * Control parameter to set maximum GPU memory reserved per device by the library for internal buffering + * + * @param max_cache_size The maximum GPU buffer space per device used for internal use in KB + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_DRIVER_NOT_INITIALIZED if the driver is not initialized + * @return CU_FILE_DRIVER_VERSION_MISMATCH, CU_FILE_DRIVER_UNSUPPORTED_LIMIT on error + * + * @warning This is an advanced command and should be tuned based on supported GPU memory + * + * @see cuFileDriverGetProperties + */ +CUfileError_t cuFileDriverSetMaxCacheSize(size_t max_cache_size); + +/** + * @brief + * Sets maximum buffer space that is pinned in KB for use by @ref cuFileBufRegister + * + * @param max_pinned_size maximum buffer space that is pinned in KB + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_DRIVER_NOT_INITIALIZED if the driver is not initialized + * @return CU_FILE_DRIVER_VERSION_MISMATCH, CU_FILE_DRIVER_UNSUPPORTED_LIMIT on error + * + * @warning This is an advanced command and should be tuned based on supported GPU memory + * + * @see cuFileDriverGetProperties + * + */ +CUfileError_t cuFileDriverSetMaxPinnedMemSize(size_t max_pinned_size); + +//Experimental Batch API's + + +typedef enum CUfileOpcode { + CUFILE_READ = 0, + CUFILE_WRITE +}CUfileOpcode_t; + +typedef enum CUFILEStatus_enum { + CUFILE_WAITING = 0x000001, /* required value prior to submission */ + CUFILE_PENDING = 0x000002, /* once enqueued */ + CUFILE_INVALID = 0x000004, /* request was ill-formed or could not be enqueued */ + CUFILE_CANCELED = 0x000008, /* request successfully canceled */ + CUFILE_COMPLETE = 0x0000010, /* request successfully completed */ + CUFILE_TIMEOUT = 0x0000020, /* request timed out */ + CUFILE_FAILED = 0x0000040 /* unable to complete */ +}CUfileStatus_t; +typedef enum cufileBatchMode { + CUFILE_BATCH = 1, +} CUfileBatchMode_t; +typedef struct CUfileIOParams { + CUfileBatchMode_t mode; // Must be the very first field. + union { + struct { + void *devPtr_base; //This can be a device memory or a host memory pointer. + off_t file_offset; + off_t devPtr_offset; + size_t size; + }batch; + }u; + CUfileHandle_t fh; + CUfileOpcode_t opcode; + void *cookie; +}CUfileIOParams_t; +typedef struct CUfileIOEvents { + void *cookie; + CUfileStatus_t status; /* status of the operation */ + size_t ret; /* -ve error or amount of I/O done. */ +}CUfileIOEvents_t; + +typedef void* CUfileBatchHandle_t; + +CUfileError_t cuFileBatchIOSetUp(CUfileBatchHandle_t *batch_idp, unsigned nr); +CUfileError_t cuFileBatchIOSubmit(CUfileBatchHandle_t batch_idp, unsigned nr, CUfileIOParams_t *iocbp, unsigned int flags); +CUfileError_t cuFileBatchIOGetStatus(CUfileBatchHandle_t batch_idp, unsigned min_nr, unsigned* nr, + CUfileIOEvents_t *iocbp, struct timespec* timeout); +CUfileError_t cuFileBatchIOCancel(CUfileBatchHandle_t batch_idp); +void cuFileBatchIODestroy(CUfileBatchHandle_t batch_idp); + +//Async API's with cuda streams + +// cuFile stream API registration flags +// buffer pointer offset is set at submission time +#define CU_FILE_STREAM_FIXED_BUF_OFFSET 1 +// file offset is set at submission time +#define CU_FILE_STREAM_FIXED_FILE_OFFSET 2 +// file size is set at submission time +#define CU_FILE_STREAM_FIXED_FILE_SIZE 4 +// size, offset and buffer offset are 4k aligned +#define CU_FILE_STREAM_PAGE_ALIGNED_INPUTS 8 + +/** + *@brief + + * @param fh The cuFile handle for the file. + * @param bufPtr_base base address of buffer in device or host memory + * @param size_p pointer to size bytes to read + * @note *size_p if the size is not known at the time of submission, then must provide the max possible size for I/O request. + * @param file_offset_p pointer to file-offset from begining of the file + * @param bufPtr_offset_p pointer to offset relative to the bufPtr_base pointer to read into. + * @param bytes_read_p pointer to the number of bytes that were successfully read. + * @param CUstream stream cuda stream for the operation. + * + * @return size of bytes successfully read in *bytes_read_p + * @return -1 on error, in which case errno is set to indicate filesystem errors. + * @return all other errors will return a negative integer value of @ref CUfileOpError enum value. + * + * @note If the bufPtr_base is not registered with @ref cuFileBufRegister, the data will be buffered through preallocated pinned buffers. + * @note This is useful for applications that need to perform IO to unaligned file offsets and/or size. This is also recommended + * for cases where the BAR1 memory size is smaller than the size of the allocated memory. + * @note If the stream is registered with cuFileStreamRegister, the IO setup and teardown overhead will be reduced. + * @note on cuda stream errors, the user must call cuFileStreamDeregister to release any outstanding cuFile resources for the stream. + * + * + * @see cuFileBufRegister + * @see cuFileHandleRegister + * @see cuFileRead + * @see cuFileStreamRegister + * @see cuFileStreamDeregister + */ + +CUfileError_t cuFileReadAsync(CUfileHandle_t fh, void *bufPtr_base, + size_t *size_p, off_t *file_offset_p, off_t *bufPtr_offset_p, ssize_t *bytes_read_p, CUstream stream); + +/** + *@brief + +* @param fh The cuFile handle for the file. + * @param bufPtr_base base address of buffer in device or host memory + * @param size_p pointer to size bytes to write. + * @note *size_p if the size is not known at the time of submission, then must provide the max possible size for I/O request. + * @param file_offset_p pointer to file-offset from begining of the file + * @param bufPtr_offset_p pointer to offset relative to the bufPtr_base pointer to write from. + * @param bytes_written_p pointer to the number of bytes that were successfully written. + * @param CUstream cuda stream for the operation. + * + * @return size of bytes successfully written in *bytes_written_p + * @return -1 on error, in which case errno is set to indicate filesystem errors. + * @return all other errors will return a negative integer value of @ref CUfileOpError enum value. + * + * @note If the bufPtr_base is not registered with @ref cuFileBufRegister, the data will be buffered through preallocated pinned buffers. + * @note This is useful for applications that need to perform IO to unaligned file offsets and/or size. This is also recommended + * for cases where the BAR1 memory size is smaller than the size of the allocated memory. + * @note If the stream is registered with cuFileStreamRegister prior to this call, the IO setup and teardown overhead will be reduced. + * @note on cuda stream errors, the user must call cuFileStreamDeregister to release any outstanding cuFile resources for the stream. + * + * @see cuFileBufRegister + * @see cuFileHandleRegister + * @see cuFileWrite + * @see cuFileStreamRegister + * @see cuFileStreamDeregister + */ + +CUfileError_t cuFileWriteAsync(CUfileHandle_t fh, void *bufPtr_base, + size_t *size_p, off_t *file_offset_p, off_t *bufPtr_offset_p, ssize_t *bytes_written_p, CUstream stream); + +/** + *@brief + + * @param CUstream cuda stream for the operation. + * @param flags for the stream to improve the stream execution of IO based on input parameters. + * @note supported FLAGS are + * @note CU_FILE_STREAM_FIXED_BUF_OFFSET - buffer pointer offset is set at submission time + * @note CU_FILE_STREAM_FIXED_FILE_OFFSET - file offset is set at submission time + * @note CU_FILE_STREAM_FIXED_FILE_SIZE - file size is set at submission time + * @note CU_FILE_STREAM_PAGE_ALIGNED_INPUTS - size, offset and buffer offset are 4k aligned + * + * @note allocates resources needed to support cuFile operations asynchronously for the cuda stream + * @note This is useful for applications that need to perform IO to unaligned file offsets and/or size. This is also recommended + * for cases where the BAR1 memory size is smaller than the size of the allocated memory. + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_DRIVER_NOT_INITIALIZED if the driver is not initialized + * @return CU_FILE_INVALID_VALUE if the stream is invalid + * + * @see cuFileReadAsync + * @see cuFileWriteAsync + * @see cuFileStreamDeregister + */ + +CUfileError_t cuFileStreamRegister(CUstream stream, unsigned flags); + +/** + *@brief + + * @param CUstream cuda stream for the operation. + * + * @note deallocates resources used by previous cuFile asynchronous operations for the cuda stream + * @note highly recommend to call after cuda stream errors to release any outstanding cuFile resources for this stream + * @note must be called before cuStreamDestroy call for the specified stream. + * @note This is useful for applications that need to perform IO to unaligned file offsets and/or size. This is also recommended + * for cases where the BAR1 memory size is smaller than the size of the allocated memory. + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_DRIVER_NOT_INITIALIZED if the driver is not initialized + * @return CU_FILE_INVALID_VALUE if the stream is invalid + * + * @see cuFileReadAsync + * @see cuFileWriteAsync + * @see cuFileStreamRegister + */ + +CUfileError_t cuFileStreamDeregister(CUstream stream); + +/** + *@brief + + * @returns cufile library version. + * + * @The version is returned as (1000 major + 10 minor). + * @For example, CUFILE 1.7.0 would be represented by 1070. + * @note This is useful for applications that need to inquire the library. + * + * @return CU_FILE_SUCCESS on success + * @return CU_FILE_INVALID_VALUE if the input parameter is null. + * @return CU_FILE_DRIVER_VERSION_READ_ERROR if the version is not available. + * + */ + +CUfileError_t cuFileGetVersion(int *version); + +#pragma GCC visibility pop + +/// @cond DOXYGEN_SKIP_MACRO +#endif // CUFILE_H +/// @endcond +#ifdef __cplusplus +} +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/lib/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/lib/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/lib/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/lib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8868a3cc1b3a5fda603d993684686b403d53db8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/lib/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/lib/libcufile_rdma.so.1 b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/lib/libcufile_rdma.so.1 new file mode 100644 index 0000000000000000000000000000000000000000..ae4c65d661c568cf9eee2890c91ff2d8856254ab Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cufile/lib/libcufile_rdma.so.1 differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..370ede7969efc8ca07f93858416b95660d448eef Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f752b34152fee63396797a01e1c0cbedb180aeb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand.h new file mode 100644 index 0000000000000000000000000000000000000000..9fee5b2826d9fda5ed6b4a7f5a14bd71e2c70b23 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand.h @@ -0,0 +1,1080 @@ + + /* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(CURAND_H_) +#define CURAND_H_ + +/** + * \defgroup HOST Host API + * + * @{ + */ +#ifndef __CUDACC_RTC__ +#include +#endif + +#ifndef CURANDAPI +#ifdef _WIN32 +#define CURANDAPI __stdcall +#else +#define CURANDAPI +#endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +#define CURAND_VER_MAJOR 10 +#define CURAND_VER_MINOR 3 +#define CURAND_VER_PATCH 9 +#define CURAND_VER_BUILD 90 +#define CURAND_VERSION (CURAND_VER_MAJOR * 1000 + \ + CURAND_VER_MINOR * 100 + \ + CURAND_VER_PATCH) +/* CURAND Host API datatypes */ + +/** + * @{ + */ + +/** + * CURAND function call status types + */ +enum curandStatus { + CURAND_STATUS_SUCCESS = 0, ///< No errors + CURAND_STATUS_VERSION_MISMATCH = 100, ///< Header file and linked library version do not match + CURAND_STATUS_NOT_INITIALIZED = 101, ///< Generator not initialized + CURAND_STATUS_ALLOCATION_FAILED = 102, ///< Memory allocation failed + CURAND_STATUS_TYPE_ERROR = 103, ///< Generator is wrong type + CURAND_STATUS_OUT_OF_RANGE = 104, ///< Argument out of range + CURAND_STATUS_LENGTH_NOT_MULTIPLE = 105, ///< Length requested is not a multple of dimension + CURAND_STATUS_DOUBLE_PRECISION_REQUIRED = 106, ///< GPU does not have double precision required by MRG32k3a + CURAND_STATUS_LAUNCH_FAILURE = 201, ///< Kernel launch failure + CURAND_STATUS_PREEXISTING_FAILURE = 202, ///< Preexisting failure on library entry + CURAND_STATUS_INITIALIZATION_FAILED = 203, ///< Initialization of CUDA failed + CURAND_STATUS_ARCH_MISMATCH = 204, ///< Architecture mismatch, GPU does not support requested feature + CURAND_STATUS_INTERNAL_ERROR = 999 ///< Internal library error +}; + +/* + * CURAND function call status types +*/ +/** \cond UNHIDE_TYPEDEFS */ +typedef enum curandStatus curandStatus_t; +/** \endcond */ + +/** + * CURAND generator types + */ +enum curandRngType { + CURAND_RNG_TEST = 0, + CURAND_RNG_PSEUDO_DEFAULT = 100, ///< Default pseudorandom generator + CURAND_RNG_PSEUDO_XORWOW = 101, ///< XORWOW pseudorandom generator + CURAND_RNG_PSEUDO_MRG32K3A = 121, ///< MRG32k3a pseudorandom generator + CURAND_RNG_PSEUDO_MTGP32 = 141, ///< Mersenne Twister MTGP32 pseudorandom generator + CURAND_RNG_PSEUDO_MT19937 = 142, ///< Mersenne Twister MT19937 pseudorandom generator + CURAND_RNG_PSEUDO_PHILOX4_32_10 = 161, ///< PHILOX-4x32-10 pseudorandom generator + CURAND_RNG_QUASI_DEFAULT = 200, ///< Default quasirandom generator + CURAND_RNG_QUASI_SOBOL32 = 201, ///< Sobol32 quasirandom generator + CURAND_RNG_QUASI_SCRAMBLED_SOBOL32 = 202, ///< Scrambled Sobol32 quasirandom generator + CURAND_RNG_QUASI_SOBOL64 = 203, ///< Sobol64 quasirandom generator + CURAND_RNG_QUASI_SCRAMBLED_SOBOL64 = 204 ///< Scrambled Sobol64 quasirandom generator +}; + +/* + * CURAND generator types + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef enum curandRngType curandRngType_t; +/** \endcond */ + +/** + * CURAND ordering of results in memory + */ +enum curandOrdering { + CURAND_ORDERING_PSEUDO_BEST = 100, ///< Best ordering for pseudorandom results + CURAND_ORDERING_PSEUDO_DEFAULT = 101, ///< Specific default thread sequence for pseudorandom results, same as CURAND_ORDERING_PSEUDO_BEST + CURAND_ORDERING_PSEUDO_SEEDED = 102, ///< Specific seeding pattern for fast lower quality pseudorandom results + CURAND_ORDERING_PSEUDO_LEGACY = 103, ///< Specific legacy sequence for pseudorandom results, guaranteed to remain the same for all cuRAND release + CURAND_ORDERING_PSEUDO_DYNAMIC = 104, ///< Specific ordering adjusted to the device it is being executed on, provides the best performance + CURAND_ORDERING_QUASI_DEFAULT = 201 ///< Specific n-dimensional ordering for quasirandom results +}; + +/* + * CURAND ordering of results in memory + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef enum curandOrdering curandOrdering_t; +/** \endcond */ + +/** + * CURAND choice of direction vector set + */ +enum curandDirectionVectorSet { + CURAND_DIRECTION_VECTORS_32_JOEKUO6 = 101, ///< Specific set of 32-bit direction vectors generated from polynomials recommended by S. Joe and F. Y. Kuo, for up to 20,000 dimensions + CURAND_SCRAMBLED_DIRECTION_VECTORS_32_JOEKUO6 = 102, ///< Specific set of 32-bit direction vectors generated from polynomials recommended by S. Joe and F. Y. Kuo, for up to 20,000 dimensions, and scrambled + CURAND_DIRECTION_VECTORS_64_JOEKUO6 = 103, ///< Specific set of 64-bit direction vectors generated from polynomials recommended by S. Joe and F. Y. Kuo, for up to 20,000 dimensions + CURAND_SCRAMBLED_DIRECTION_VECTORS_64_JOEKUO6 = 104 ///< Specific set of 64-bit direction vectors generated from polynomials recommended by S. Joe and F. Y. Kuo, for up to 20,000 dimensions, and scrambled +}; + +/* + * CURAND choice of direction vector set + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef enum curandDirectionVectorSet curandDirectionVectorSet_t; +/** \endcond */ + +/** + * CURAND array of 32-bit direction vectors + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef unsigned int curandDirectionVectors32_t[32]; +/** \endcond */ + + /** + * CURAND array of 64-bit direction vectors + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef unsigned long long curandDirectionVectors64_t[64]; +/** \endcond **/ + +/** + * CURAND generator (opaque) + */ +struct curandGenerator_st; + +/** + * CURAND generator + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandGenerator_st *curandGenerator_t; +/** \endcond */ + +/** + * CURAND distribution + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef double curandDistribution_st; +typedef curandDistribution_st *curandDistribution_t; +typedef struct curandDistributionShift_st *curandDistributionShift_t; +/** \endcond */ +/** + * CURAND distribution M2 + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandDistributionM2Shift_st *curandDistributionM2Shift_t; +typedef struct curandHistogramM2_st *curandHistogramM2_t; +typedef unsigned int curandHistogramM2K_st; +typedef curandHistogramM2K_st *curandHistogramM2K_t; +typedef curandDistribution_st curandHistogramM2V_st; +typedef curandHistogramM2V_st *curandHistogramM2V_t; + +typedef struct curandDiscreteDistribution_st *curandDiscreteDistribution_t; +/** \endcond */ + +/* + * CURAND METHOD + */ +/** \cond UNHIDE_ENUMS */ +enum curandMethod { + CURAND_CHOOSE_BEST = 0, // choose best depends on args + CURAND_ITR = 1, + CURAND_KNUTH = 2, + CURAND_HITR = 3, + CURAND_M1 = 4, + CURAND_M2 = 5, + CURAND_BINARY_SEARCH = 6, + CURAND_DISCRETE_GAUSS = 7, + CURAND_REJECTION = 8, + CURAND_DEVICE_API = 9, + CURAND_FAST_REJECTION = 10, + CURAND_3RD = 11, + CURAND_DEFINITION = 12, + CURAND_POISSON = 13 +}; + +typedef enum curandMethod curandMethod_t; +/** \endcond */ + + +#ifndef __CUDACC_RTC__ + +/** + * @} + */ + +/** + * \brief Create new random number generator. + * + * Creates a new random number generator of type \p rng_type + * and returns it in \p *generator. + * + * Legal values for \p rng_type are: + * - CURAND_RNG_PSEUDO_DEFAULT + * - CURAND_RNG_PSEUDO_XORWOW + * - CURAND_RNG_PSEUDO_MRG32K3A + * - CURAND_RNG_PSEUDO_MTGP32 + * - CURAND_RNG_PSEUDO_MT19937 + * - CURAND_RNG_PSEUDO_PHILOX4_32_10 + * - CURAND_RNG_QUASI_DEFAULT + * - CURAND_RNG_QUASI_SOBOL32 + * - CURAND_RNG_QUASI_SCRAMBLED_SOBOL32 + * - CURAND_RNG_QUASI_SOBOL64 + * - CURAND_RNG_QUASI_SCRAMBLED_SOBOL64 + * + * When \p rng_type is CURAND_RNG_PSEUDO_DEFAULT, the type chosen + * is CURAND_RNG_PSEUDO_XORWOW. \n + * When \p rng_type is CURAND_RNG_QUASI_DEFAULT, + * the type chosen is CURAND_RNG_QUASI_SOBOL32. + * + * The default values for \p rng_type = CURAND_RNG_PSEUDO_XORWOW are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_PSEUDO_MRG32K3A are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_PSEUDO_MTGP32 are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_PSEUDO_MT19937 are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * * The default values for \p rng_type = CURAND_RNG_PSEUDO_PHILOX4_32_10 are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_QUASI_SOBOL32 are: + * - \p dimensions = 1 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_QUASI_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_QUASI_SOBOL64 are: + * - \p dimensions = 1 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_QUASI_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_QUASI_SCRAMBBLED_SOBOL32 are: + * - \p dimensions = 1 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_QUASI_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_QUASI_SCRAMBLED_SOBOL64 are: + * - \p dimensions = 1 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_QUASI_DEFAULT + * + * \param generator - Pointer to generator + * \param rng_type - Type of generator to create + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED, if memory could not be allocated \n + * - CURAND_STATUS_INITIALIZATION_FAILED if there was a problem setting up the GPU \n + * - CURAND_STATUS_VERSION_MISMATCH if the header file version does not match the + * dynamically linked library version \n + * - CURAND_STATUS_TYPE_ERROR if the value for \p rng_type is invalid \n + * - CURAND_STATUS_SUCCESS if generator was created successfully \n + * + */ +curandStatus_t CURANDAPI +curandCreateGenerator(curandGenerator_t *generator, curandRngType_t rng_type); + +/** + * \brief Create new host CPU random number generator. + * + * Creates a new host CPU random number generator of type \p rng_type + * and returns it in \p *generator. + * + * Legal values for \p rng_type are: + * - CURAND_RNG_PSEUDO_DEFAULT + * - CURAND_RNG_PSEUDO_XORWOW + * - CURAND_RNG_PSEUDO_MRG32K3A + * - CURAND_RNG_PSEUDO_MTGP32 + * - CURAND_RNG_PSEUDO_MT19937 + * - CURAND_RNG_PSEUDO_PHILOX4_32_10 + * - CURAND_RNG_QUASI_DEFAULT + * - CURAND_RNG_QUASI_SOBOL32 + * - CURAND_RNG_QUASI_SCRAMBLED_SOBOL32 + * - CURAND_RNG_QUASI_SOBOL64 + * - CURAND_RNG_QUASI_SCRAMBLED_SOBOL64 + * + * When \p rng_type is CURAND_RNG_PSEUDO_DEFAULT, the type chosen + * is CURAND_RNG_PSEUDO_XORWOW. \n + * When \p rng_type is CURAND_RNG_QUASI_DEFAULT, + * the type chosen is CURAND_RNG_QUASI_SOBOL32. + * + * The default values for \p rng_type = CURAND_RNG_PSEUDO_XORWOW are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_PSEUDO_MRG32K3A are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_PSEUDO_MTGP32 are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_PSEUDO_MT19937 are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * * The default values for \p rng_type = CURAND_RNG_PSEUDO_PHILOX4_32_10 are: + * - \p seed = 0 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_PSEUDO_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_QUASI_SOBOL32 are: + * - \p dimensions = 1 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_QUASI_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_QUASI_SOBOL64 are: + * - \p dimensions = 1 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_QUASI_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_QUASI_SCRAMBLED_SOBOL32 are: + * - \p dimensions = 1 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_QUASI_DEFAULT + * + * The default values for \p rng_type = CURAND_RNG_QUASI_SCRAMBLED_SOBOL64 are: + * - \p dimensions = 1 + * - \p offset = 0 + * - \p ordering = CURAND_ORDERING_QUASI_DEFAULT + * + * \param generator - Pointer to generator + * \param rng_type - Type of generator to create + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_INITIALIZATION_FAILED if there was a problem setting up the GPU \n + * - CURAND_STATUS_VERSION_MISMATCH if the header file version does not match the + * dynamically linked library version \n + * - CURAND_STATUS_TYPE_ERROR if the value for \p rng_type is invalid \n + * - CURAND_STATUS_SUCCESS if generator was created successfully \n + */ +curandStatus_t CURANDAPI +curandCreateGeneratorHost(curandGenerator_t *generator, curandRngType_t rng_type); + +/** + * \brief Destroy an existing generator. + * + * Destroy an existing generator and free all memory associated with its state. + * + * \param generator - Generator to destroy + * + * \return + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_SUCCESS if generator was destroyed successfully \n + */ +curandStatus_t CURANDAPI +curandDestroyGenerator(curandGenerator_t generator); + +/** + * \brief Return the version number of the library. + * + * Return in \p *version the version number of the dynamically linked CURAND + * library. The format is the same as CUDART_VERSION from the CUDA Runtime. + * The only supported configuration is CURAND version equal to CUDA Runtime + * version. + * + * \param version - CURAND library version + * + * \return + * - CURAND_STATUS_SUCCESS if the version number was successfully returned \n + */ +curandStatus_t CURANDAPI +curandGetVersion(int *version); + +/** +* \brief Return the value of the curand property. +* +* Return in \p *value the number for the property described by \p type of the +* dynamically linked CURAND library. +* +* \param type - CUDA library property +* \param value - integer value for the requested property +* +* \return +* - CURAND_STATUS_SUCCESS if the property value was successfully returned \n +* - CURAND_STATUS_OUT_OF_RANGE if the property type is not recognized \n +*/ +curandStatus_t CURANDAPI +curandGetProperty(libraryPropertyType type, int *value); + + +/** + * \brief Set the current stream for CURAND kernel launches. + * + * Set the current stream for CURAND kernel launches. All library functions + * will use this stream until set again. + * + * \param generator - Generator to modify + * \param stream - Stream to use or ::NULL for null stream + * + * \return + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_SUCCESS if stream was set successfully \n + */ +curandStatus_t CURANDAPI +curandSetStream(curandGenerator_t generator, cudaStream_t stream); + +/** + * \brief Set the seed value of the pseudo-random number generator. + * + * Set the seed value of the pseudorandom number generator. + * All values of seed are valid. Different seeds will produce different sequences. + * Different seeds will often not be statistically correlated with each other, + * but some pairs of seed values may generate sequences which are statistically correlated. + * + * \param generator - Generator to modify + * \param seed - Seed value + * + * \return + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_TYPE_ERROR if the generator is not a pseudorandom number generator \n + * - CURAND_STATUS_SUCCESS if generator seed was set successfully \n + */ +curandStatus_t CURANDAPI +curandSetPseudoRandomGeneratorSeed(curandGenerator_t generator, unsigned long long seed); + +/** + * \brief Set the absolute offset of the pseudo or quasirandom number generator. + * + * Set the absolute offset of the pseudo or quasirandom number generator. + * + * All values of offset are valid. The offset position is absolute, not + * relative to the current position in the sequence. + * + * \param generator - Generator to modify + * \param offset - Absolute offset position + * + * \return + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_SUCCESS if generator offset was set successfully \n + */ +curandStatus_t CURANDAPI +curandSetGeneratorOffset(curandGenerator_t generator, unsigned long long offset); + +/** + * \brief Set the ordering of results of the pseudo or quasirandom number generator. + * + * Set the ordering of results of the pseudo or quasirandom number generator. + * + * Legal values of \p order for pseudorandom generators are: + * - CURAND_ORDERING_PSEUDO_DEFAULT + * - CURAND_ORDERING_PSEUDO_BEST + * - CURAND_ORDERING_PSEUDO_SEEDED + * - CURAND_ORDERING_PSEUDO_LEGACY + * + * Legal values of \p order for quasirandom generators are: + * - CURAND_ORDERING_QUASI_DEFAULT + * + * \param generator - Generator to modify + * \param order - Ordering of results + * + * \return + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_OUT_OF_RANGE if the ordering is not valid \n + * - CURAND_STATUS_SUCCESS if generator ordering was set successfully \n + */ +curandStatus_t CURANDAPI +curandSetGeneratorOrdering(curandGenerator_t generator, curandOrdering_t order); + +/** + * \brief Set the number of dimensions. + * + * Set the number of dimensions to be generated by the quasirandom number + * generator. + * + * Legal values for \p num_dimensions are 1 to 20000. + * + * \param generator - Generator to modify + * \param num_dimensions - Number of dimensions + * + * \return + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_OUT_OF_RANGE if num_dimensions is not valid \n + * - CURAND_STATUS_TYPE_ERROR if the generator is not a quasirandom number generator \n + * - CURAND_STATUS_SUCCESS if generator ordering was set successfully \n + */ +curandStatus_t CURANDAPI +curandSetQuasiRandomGeneratorDimensions(curandGenerator_t generator, unsigned int num_dimensions); + +/** + * \brief Generate 32-bit pseudo or quasirandom numbers. + * + * Use \p generator to generate \p num 32-bit results into the device memory at + * \p outputPtr. The device memory must have been previously allocated and be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 32-bit values with every bit random. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param num - Number of random 32-bit values to generate + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_TYPE_ERROR if the generator is a 64 bit quasirandom generator. + * (use ::curandGenerateLongLong() with 64 bit quasirandom generators) + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerate(curandGenerator_t generator, unsigned int *outputPtr, size_t num); + +/** + * \brief Generate 64-bit quasirandom numbers. + * + * Use \p generator to generate \p num 64-bit results into the device memory at + * \p outputPtr. The device memory must have been previously allocated and be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 64-bit values with every bit random. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param num - Number of random 64-bit values to generate + * + * \return + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_TYPE_ERROR if the generator is not a 64 bit quasirandom generator\n + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerateLongLong(curandGenerator_t generator, unsigned long long *outputPtr, size_t num); + +/** + * \brief Generate uniformly distributed floats. + * + * Use \p generator to generate \p num float results into the device memory at + * \p outputPtr. The device memory must have been previously allocated and be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 32-bit floating point values between \p 0.0f and \p 1.0f, + * excluding \p 0.0f and including \p 1.0f. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param num - Number of floats to generate + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension \n + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerateUniform(curandGenerator_t generator, float *outputPtr, size_t num); + +/** + * \brief Generate uniformly distributed doubles. + * + * Use \p generator to generate \p num double results into the device memory at + * \p outputPtr. The device memory must have been previously allocated and be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 64-bit double precision floating point values between + * \p 0.0 and \p 1.0, excluding \p 0.0 and including \p 1.0. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param num - Number of doubles to generate + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension \n + * - CURAND_STATUS_DOUBLE_PRECISION_REQUIRED if the GPU does not support double precision \n + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerateUniformDouble(curandGenerator_t generator, double *outputPtr, size_t num); + +/** + * \brief Generate normally distributed doubles. + * + * Use \p generator to generate \p n float results into the device memory at + * \p outputPtr. The device memory must have been previously allocated and be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 32-bit floating point values with mean \p mean and standard + * deviation \p stddev. + * + * Normally distributed results are generated from pseudorandom generators + * with a Box-Muller transform, and so require \p n to be even. + * Quasirandom generators use an inverse cumulative distribution + * function to preserve dimensionality. + * + * There may be slight numerical differences between results generated + * on the GPU with generators created with ::curandCreateGenerator() + * and results calculated on the CPU with generators created with + * ::curandCreateGeneratorHost(). These differences arise because of + * differences in results for transcendental functions. In addition, + * future versions of CURAND may use newer versions of the CUDA math + * library, so different versions of CURAND may give slightly different + * numerical values. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param n - Number of floats to generate + * \param mean - Mean of normal distribution + * \param stddev - Standard deviation of normal distribution + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension, or is not a multiple + * of two for pseudorandom generators \n + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerateNormal(curandGenerator_t generator, float *outputPtr, + size_t n, float mean, float stddev); + +/** + * \brief Generate normally distributed doubles. + * + * Use \p generator to generate \p n double results into the device memory at + * \p outputPtr. The device memory must have been previously allocated and be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 64-bit floating point values with mean \p mean and standard + * deviation \p stddev. + * + * Normally distributed results are generated from pseudorandom generators + * with a Box-Muller transform, and so require \p n to be even. + * Quasirandom generators use an inverse cumulative distribution + * function to preserve dimensionality. + * + * There may be slight numerical differences between results generated + * on the GPU with generators created with ::curandCreateGenerator() + * and results calculated on the CPU with generators created with + * ::curandCreateGeneratorHost(). These differences arise because of + * differences in results for transcendental functions. In addition, + * future versions of CURAND may use newer versions of the CUDA math + * library, so different versions of CURAND may give slightly different + * numerical values. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param n - Number of doubles to generate + * \param mean - Mean of normal distribution + * \param stddev - Standard deviation of normal distribution + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension, or is not a multiple + * of two for pseudorandom generators \n + * - CURAND_STATUS_DOUBLE_PRECISION_REQUIRED if the GPU does not support double precision \n + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerateNormalDouble(curandGenerator_t generator, double *outputPtr, + size_t n, double mean, double stddev); + +/** + * \brief Generate log-normally distributed floats. + * + * Use \p generator to generate \p n float results into the device memory at + * \p outputPtr. The device memory must have been previously allocated and be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 32-bit floating point values with log-normal distribution based on + * an associated normal distribution with mean \p mean and standard deviation \p stddev. + * + * Normally distributed results are generated from pseudorandom generators + * with a Box-Muller transform, and so require \p n to be even. + * Quasirandom generators use an inverse cumulative distribution + * function to preserve dimensionality. + * The normally distributed results are transformed into log-normal distribution. + * + * There may be slight numerical differences between results generated + * on the GPU with generators created with ::curandCreateGenerator() + * and results calculated on the CPU with generators created with + * ::curandCreateGeneratorHost(). These differences arise because of + * differences in results for transcendental functions. In addition, + * future versions of CURAND may use newer versions of the CUDA math + * library, so different versions of CURAND may give slightly different + * numerical values. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param n - Number of floats to generate + * \param mean - Mean of associated normal distribution + * \param stddev - Standard deviation of associated normal distribution + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension, or is not a multiple + * of two for pseudorandom generators \n + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerateLogNormal(curandGenerator_t generator, float *outputPtr, + size_t n, float mean, float stddev); + +/** + * \brief Generate log-normally distributed doubles. + * + * Use \p generator to generate \p n double results into the device memory at + * \p outputPtr. The device memory must have been previously allocated and be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 64-bit floating point values with log-normal distribution based on + * an associated normal distribution with mean \p mean and standard deviation \p stddev. + * + * Normally distributed results are generated from pseudorandom generators + * with a Box-Muller transform, and so require \p n to be even. + * Quasirandom generators use an inverse cumulative distribution + * function to preserve dimensionality. + * The normally distributed results are transformed into log-normal distribution. + * + * There may be slight numerical differences between results generated + * on the GPU with generators created with ::curandCreateGenerator() + * and results calculated on the CPU with generators created with + * ::curandCreateGeneratorHost(). These differences arise because of + * differences in results for transcendental functions. In addition, + * future versions of CURAND may use newer versions of the CUDA math + * library, so different versions of CURAND may give slightly different + * numerical values. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param n - Number of doubles to generate + * \param mean - Mean of normal distribution + * \param stddev - Standard deviation of normal distribution + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension, or is not a multiple + * of two for pseudorandom generators \n + * - CURAND_STATUS_DOUBLE_PRECISION_REQUIRED if the GPU does not support double precision \n + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerateLogNormalDouble(curandGenerator_t generator, double *outputPtr, + size_t n, double mean, double stddev); + +/** + * \brief Construct the histogram array for a Poisson distribution. + * + * Construct the histogram array for the Poisson distribution with lambda \p lambda. + * For lambda greater than 2000, an approximation with a normal distribution is used. + * + * \param lambda - lambda for the Poisson distribution + * + * + * \param discrete_distribution - pointer to the histogram in device memory + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_DOUBLE_PRECISION_REQUIRED if the GPU does not support double precision \n + * - CURAND_STATUS_INITIALIZATION_FAILED if there was a problem setting up the GPU \n + * - CURAND_STATUS_NOT_INITIALIZED if the distribution pointer was null \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_OUT_OF_RANGE if lambda is non-positive or greater than 400,000 \n + * - CURAND_STATUS_SUCCESS if the histogram was generated successfully \n + */ + +curandStatus_t CURANDAPI +curandCreatePoissonDistribution(double lambda, curandDiscreteDistribution_t *discrete_distribution); + + + +/** + * \brief Destroy the histogram array for a discrete distribution (e.g. Poisson). + * + * Destroy the histogram array for a discrete distribution created by curandCreatePoissonDistribution. + * + * \param discrete_distribution - pointer to device memory where the histogram is stored + * + * \return + * - CURAND_STATUS_NOT_INITIALIZED if the histogram was never created \n + * - CURAND_STATUS_SUCCESS if the histogram was destroyed successfully \n + */ +curandStatus_t CURANDAPI +curandDestroyDistribution(curandDiscreteDistribution_t discrete_distribution); + + +/** + * \brief Generate Poisson-distributed unsigned ints. + * + * Use \p generator to generate \p n unsigned int results into device memory at + * \p outputPtr. The device memory must have been previously allocated and must be + * large enough to hold all the results. Launches are done with the stream + * set using ::curandSetStream(), or the null stream if no stream has been set. + * + * Results are 32-bit unsigned int point values with Poisson distribution, with lambda \p lambda. + * + * \param generator - Generator to use + * \param outputPtr - Pointer to device memory to store CUDA-generated results, or + * Pointer to host memory to store CPU-generated results + * \param n - Number of unsigned ints to generate + * \param lambda - lambda for the Poisson distribution + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_LENGTH_NOT_MULTIPLE if the number of output samples is + * not a multiple of the quasirandom dimension\n + * - CURAND_STATUS_DOUBLE_PRECISION_REQUIRED if the GPU or sm does not support double precision \n + * - CURAND_STATUS_OUT_OF_RANGE if lambda is non-positive or greater than 400,000 \n + * - CURAND_STATUS_SUCCESS if the results were generated successfully \n + */ + +curandStatus_t CURANDAPI +curandGeneratePoisson(curandGenerator_t generator, unsigned int *outputPtr, + size_t n, double lambda); +// just for internal usage +curandStatus_t CURANDAPI +curandGeneratePoissonMethod(curandGenerator_t generator, unsigned int *outputPtr, + size_t n, double lambda, curandMethod_t method); + + +curandStatus_t CURANDAPI +curandGenerateBinomial(curandGenerator_t generator, unsigned int *outputPtr, + size_t num, unsigned int n, double p); +// just for internal usage +curandStatus_t CURANDAPI +curandGenerateBinomialMethod(curandGenerator_t generator, + unsigned int *outputPtr, + size_t num, unsigned int n, double p, + curandMethod_t method); + + +/** + * \brief Setup starting states. + * + * Generate the starting state of the generator. This function is + * automatically called by generation functions such as + * ::curandGenerate() and ::curandGenerateUniform(). + * It can be called manually for performance testing reasons to separate + * timings for starting state generation and random number generation. + * + * \param generator - Generator to update + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if memory could not be allocated \n + * - CURAND_STATUS_NOT_INITIALIZED if the generator was never created \n + * - CURAND_STATUS_PREEXISTING_FAILURE if there was an existing error from + * a previous kernel launch \n + * - CURAND_STATUS_LAUNCH_FAILURE if the kernel launch failed for any reason \n + * - CURAND_STATUS_SUCCESS if the seeds were generated successfully \n + */ +curandStatus_t CURANDAPI +curandGenerateSeeds(curandGenerator_t generator); + +/** + * \brief Get direction vectors for 32-bit quasirandom number generation. + * + * Get a pointer to an array of direction vectors that can be used + * for quasirandom number generation. The resulting pointer will + * reference an array of direction vectors in host memory. + * + * The array contains vectors for many dimensions. Each dimension + * has 32 vectors. Each individual vector is an unsigned int. + * + * Legal values for \p set are: + * - CURAND_DIRECTION_VECTORS_32_JOEKUO6 (20,000 dimensions) + * - CURAND_SCRAMBLED_DIRECTION_VECTORS_32_JOEKUO6 (20,000 dimensions) + * + * \param vectors - Address of pointer in which to return direction vectors + * \param set - Which set of direction vectors to use + * + * \return + * - CURAND_STATUS_OUT_OF_RANGE if the choice of set is invalid \n + * - CURAND_STATUS_SUCCESS if the pointer was set successfully \n + */ +curandStatus_t CURANDAPI +curandGetDirectionVectors32(curandDirectionVectors32_t *vectors[], curandDirectionVectorSet_t set); + +/** + * \brief Get scramble constants for 32-bit scrambled Sobol' . + * + * Get a pointer to an array of scramble constants that can be used + * for quasirandom number generation. The resulting pointer will + * reference an array of unsinged ints in host memory. + * + * The array contains constants for many dimensions. Each dimension + * has a single unsigned int constant. + * + * \param constants - Address of pointer in which to return scramble constants + * + * \return + * - CURAND_STATUS_SUCCESS if the pointer was set successfully \n + */ +curandStatus_t CURANDAPI +curandGetScrambleConstants32(unsigned int * * constants); + +/** + * \brief Get direction vectors for 64-bit quasirandom number generation. + * + * Get a pointer to an array of direction vectors that can be used + * for quasirandom number generation. The resulting pointer will + * reference an array of direction vectors in host memory. + * + * The array contains vectors for many dimensions. Each dimension + * has 64 vectors. Each individual vector is an unsigned long long. + * + * Legal values for \p set are: + * - CURAND_DIRECTION_VECTORS_64_JOEKUO6 (20,000 dimensions) + * - CURAND_SCRAMBLED_DIRECTION_VECTORS_64_JOEKUO6 (20,000 dimensions) + * + * \param vectors - Address of pointer in which to return direction vectors + * \param set - Which set of direction vectors to use + * + * \return + * - CURAND_STATUS_OUT_OF_RANGE if the choice of set is invalid \n + * - CURAND_STATUS_SUCCESS if the pointer was set successfully \n + */ +curandStatus_t CURANDAPI +curandGetDirectionVectors64(curandDirectionVectors64_t *vectors[], curandDirectionVectorSet_t set); + +/** + * \brief Get scramble constants for 64-bit scrambled Sobol' . + * + * Get a pointer to an array of scramble constants that can be used + * for quasirandom number generation. The resulting pointer will + * reference an array of unsinged long longs in host memory. + * + * The array contains constants for many dimensions. Each dimension + * has a single unsigned long long constant. + * + * \param constants - Address of pointer in which to return scramble constants + * + * \return + * - CURAND_STATUS_SUCCESS if the pointer was set successfully \n + */ +curandStatus_t CURANDAPI +curandGetScrambleConstants64(unsigned long long * * constants); + +/** @} */ + +#endif // __CUDACC_RTC__ + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + + +#endif /* !defined(CURAND_H_) */ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_discrete.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_discrete.h new file mode 100644 index 0000000000000000000000000000000000000000..7e194487a0e2ec02abcb1dd8634c42141a148d84 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_discrete.h @@ -0,0 +1,87 @@ + /* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#if !defined(CURANDDISCRETE_H_) +#define CURANDDISCRETE_H_ + +struct curandDistributionShift_st { + curandDistribution_t probability; + curandDistribution_t host_probability; + unsigned int shift; + unsigned int length; + unsigned int host_gen; +}; + +struct curandHistogramM2_st { + curandHistogramM2V_t V; + curandHistogramM2V_t host_V; + curandHistogramM2K_t K; + curandHistogramM2K_t host_K; + unsigned int host_gen; +}; + + +struct curandDistributionM2Shift_st { + curandHistogramM2_t histogram; + curandHistogramM2_t host_histogram; + unsigned int shift; + unsigned int length; + unsigned int host_gen; +}; + +struct curandDiscreteDistribution_st { + curandDiscreteDistribution_t self_host_ptr; + curandDistributionM2Shift_t M2; + curandDistributionM2Shift_t host_M2; + double stddev; + double mean; + curandMethod_t method; + unsigned int host_gen; +}; + +#endif // !defined(CURANDDISCRETE_H_) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_discrete2.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_discrete2.h new file mode 100644 index 0000000000000000000000000000000000000000..ac827749840488f66d71f492c14dbec80b57a3d1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_discrete2.h @@ -0,0 +1,253 @@ + + /* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + + +#if !defined(CURAND_DISCRETE_H_) +#define CURAND_DISCRETE_H_ + +/** + * \defgroup DEVICE Device API + * + * @{ + */ + +#ifndef __CUDACC_RTC__ +#include +#endif // __CUDACC_RTC__ + +#include "curand_mrg32k3a.h" +#include "curand_mtgp32_kernel.h" +#include "curand_philox4x32_x.h" + + +template +QUALIFIERS unsigned int _curand_discrete(T x, curandDiscreteDistribution_t discrete_distribution){ + if (discrete_distribution->method == CURAND_M2){ + return _curand_M2_double(x, discrete_distribution->M2); + } + return (unsigned int)((discrete_distribution->stddev * _curand_normal_icdf_double(x)) + discrete_distribution->mean + 0.5); +} + + +template +QUALIFIERS unsigned int curand__discrete(STATE state, curandDiscreteDistribution_t discrete_distribution){ + if (discrete_distribution->method == CURAND_M2){ + return curand_M2_double(state, discrete_distribution->M2); + } + return (unsigned int)((discrete_distribution->stddev * curand_normal_double(state)) + discrete_distribution->mean + 0.5); //Round to nearest +} + +template +QUALIFIERS uint4 curand__discrete4(STATE state, curandDiscreteDistribution_t discrete_distribution){ + if (discrete_distribution->method == CURAND_M2){ + return curand_M2_double4(state, discrete_distribution->M2); + } + double4 _res; + uint4 result; + _res = curand_normal4_double(state); + result.x = (unsigned int)((discrete_distribution->stddev * _res.x) + discrete_distribution->mean + 0.5); //Round to nearest + result.y = (unsigned int)((discrete_distribution->stddev * _res.y) + discrete_distribution->mean + 0.5); //Round to nearest + result.z = (unsigned int)((discrete_distribution->stddev * _res.z) + discrete_distribution->mean + 0.5); //Round to nearest + result.w = (unsigned int)((discrete_distribution->stddev * _res.w) + discrete_distribution->mean + 0.5); //Round to nearest + return result; +} + +/* + * \brief Return a discrete distributed unsigned int from a XORWOW generator. + * + * Return a single discrete distributed unsigned int derived from a + * distribution defined by \p discrete_distribution from the XORWOW generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS unsigned int curand_discrete(curandStateXORWOW_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete(state, discrete_distribution); +} + +/* + * \brief Return a discrete distributed unsigned int from a Philox4_32_10 generator. + * + * Return a single discrete distributed unsigned int derived from a + * distribution defined by \p discrete_distribution from the Philox4_32_10 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS unsigned int curand_discrete(curandStatePhilox4_32_10_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete(state, discrete_distribution); +} + +/* + * \brief Return four discrete distributed unsigned ints from a Philox4_32_10 generator. + * + * Return four single discrete distributed unsigned ints derived from a + * distribution defined by \p discrete_distribution from the Philox4_32_10 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS uint4 curand_discrete4(curandStatePhilox4_32_10_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete4(state, discrete_distribution); +} +/* + * \brief Return a discrete distributed unsigned int from a MRG32k3a generator. + * + * Re turn a single discrete distributed unsigned int derived from a + * distribution defined by \p discrete_distribution from the MRG32k3a generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS unsigned int curand_discrete(curandStateMRG32k3a_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete(state, discrete_distribution); +} + +/* + * \brief Return a discrete distributed unsigned int from a MTGP32 generator. + * + * Return a single discrete distributed unsigned int derived from a + * distribution defined by \p discrete_distribution from the MTGP32 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS unsigned int curand_discrete(curandStateMtgp32_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete(state, discrete_distribution); +} + +/* + * \brief Return a discrete distributed unsigned int from a Sobol32 generator. + * + * Return a single discrete distributed unsigned int derived from a + * distribution defined by \p discrete_distribution from the Sobol32 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS unsigned int curand_discrete(curandStateSobol32_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete(state, discrete_distribution); +} + +/* + * \brief Return a discrete distributed unsigned int from a scrambled Sobol32 generator. + * + * Return a single discrete distributed unsigned int derived from a + * distribution defined by \p discrete_distribution from the scrambled Sobol32 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS unsigned int curand_discrete(curandStateScrambledSobol32_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete(state, discrete_distribution); +} + +/* + * \brief Return a discrete distributed unsigned int from a Sobol64 generator. + * + * Return a single discrete distributed unsigned int derived from a + * distribution defined by \p discrete_distribution from the Sobol64 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS unsigned int curand_discrete(curandStateSobol64_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete(state, discrete_distribution); +} + +/* + * \brief Return a discrete distributed unsigned int from a scrambled Sobol64 generator. + * + * Return a single discrete distributed unsigned int derived from a + * distribution defined by \p discrete_distribution from the scrambled Sobol64 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param discrete_distribution - ancillary structure for discrete distribution + * + * \return unsigned int distributed by distribution defined by \p discrete_distribution. + */ +QUALIFIERS unsigned int curand_discrete(curandStateScrambledSobol64_t *state, curandDiscreteDistribution_t discrete_distribution) +{ + return curand__discrete(state, discrete_distribution); +} + +#endif // !defined(CURAND_DISCRETE_H_) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_globals.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_globals.h new file mode 100644 index 0000000000000000000000000000000000000000..278d12b69727c4016fdb2452b8ee567f5c969fa0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_globals.h @@ -0,0 +1,93 @@ + /* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ +#ifndef CURAND_GLOBALS_H +#define CURAND_GLOBALS_H + +#define MAX_XOR_N (5) +#define SKIPAHEAD_BLOCKSIZE (4) +#define SKIPAHEAD_MASK ((1< + +#ifdef __CUDACC_RTC__ +#define CURAND_DETAIL_USE_CUDA_STL +#endif + +#if __cplusplus >= 201103L +# ifdef CURAND_DETAIL_USE_CUDA_STL +# define CURAND_STD cuda::std +# include +# else +# define CURAND_STD std +# include +# endif // CURAND_DETAIL_USE_CUDA_STL +#else +// To support C++03 compilation +# define CURAND_STD curand_detail +namespace curand_detail { + template + struct enable_if {}; + + template + struct enable_if { typedef T type; }; + + template + struct is_same { static const bool value = false; }; + + template + struct is_same { static const bool value = true; }; +} // namespace curand_detail +#endif // __cplusplus >= 201103L + +#ifndef __CUDACC_RTC__ +#include +#endif // __CUDACC_RTC__ + +#include "curand.h" +#include "curand_discrete.h" +#include "curand_precalc.h" +#include "curand_mrg32k3a.h" +#include "curand_mtgp32_kernel.h" +#include "curand_philox4x32_x.h" +#include "curand_globals.h" + +/* Test RNG */ +/* This generator uses the formula: + x_n = x_(n-1) + 1 mod 2^32 + x_0 = (unsigned int)seed * 3 + Subsequences are spaced 31337 steps apart. +*/ +struct curandStateTest { + unsigned int v; +}; + +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateTest curandStateTest_t; +/** \endcond */ + +/* XORSHIFT FAMILY RNGs */ +/* These generators are a family proposed by Marsaglia. They keep state + in 32 bit chunks, then use repeated shift and xor operations to scramble + the bits. The following generators are a combination of a simple Weyl + generator with an N variable XORSHIFT generator. +*/ + +/* XORSHIFT RNG */ +/* This generator uses the xorwow formula of +www.jstatsoft.org/v08/i14/paper page 5 +Has period 2^192 - 2^32. +*/ +/** + * CURAND XORWOW state + */ +struct curandStateXORWOW; + +/* + * Implementation details not in reference documentation */ +struct curandStateXORWOW { + unsigned int d, v[5]; + int boxmuller_flag; + int boxmuller_flag_double; + float boxmuller_extra; + double boxmuller_extra_double; +}; + +/* + * CURAND XORWOW state + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateXORWOW curandStateXORWOW_t; + +#define EXTRA_FLAG_NORMAL 0x00000001 +#define EXTRA_FLAG_LOG_NORMAL 0x00000002 +/** \endcond */ + +/* Combined Multiple Recursive Generators */ +/* These generators are a family proposed by L'Ecuyer. They keep state + in sets of doubles, then use repeated modular arithmetic multiply operations + to scramble the bits in each set, and combine the result. +*/ + +/* MRG32k3a RNG */ +/* This generator uses the MRG32k3A formula of +http://www.iro.umontreal.ca/~lecuyer/myftp/streams00/c++/streams4.pdf +Has period 2^191. +*/ + +/* moduli for the recursions */ +/** \cond UNHIDE_DEFINES */ +#define MRG32K3A_MOD1 4294967087. +#define MRG32K3A_MOD2 4294944443. + +/* Constants used in generation */ + +#define MRG32K3A_A12 1403580. +#define MRG32K3A_A13N 810728. +#define MRG32K3A_A21 527612. +#define MRG32K3A_A23N 1370589. +#define MRG32K3A_NORM (2.3283065498378288e-10) +// +// #define MRG32K3A_BITS_NORM ((double)((POW32_DOUBLE-1.0)/MOD1)) +// above constant, used verbatim, rounds differently on some host systems. +#define MRG32K3A_BITS_NORM 1.000000048662 + +/** \endcond */ + + + + +/** + * CURAND MRG32K3A state + */ +struct curandStateMRG32k3a; + +/* Implementation details not in reference documentation */ +struct curandStateMRG32k3a { + unsigned int s1[3]; + unsigned int s2[3]; + int boxmuller_flag; + int boxmuller_flag_double; + float boxmuller_extra; + double boxmuller_extra_double; +}; + +/* + * CURAND MRG32K3A state + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateMRG32k3a curandStateMRG32k3a_t; +/** \endcond */ + +/* SOBOL QRNG */ +/** + * CURAND Sobol32 state + */ +struct curandStateSobol32; + +/* Implementation details not in reference documentation */ +struct curandStateSobol32 { + unsigned int i, x, c; + unsigned int direction_vectors[32]; +}; + +/* + * CURAND Sobol32 state + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateSobol32 curandStateSobol32_t; +/** \endcond */ + +/** + * CURAND Scrambled Sobol32 state + */ +struct curandStateScrambledSobol32; + +/* Implementation details not in reference documentation */ +struct curandStateScrambledSobol32 { + unsigned int i, x, c; + unsigned int direction_vectors[32]; +}; + +/* + * CURAND Scrambled Sobol32 state + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateScrambledSobol32 curandStateScrambledSobol32_t; +/** \endcond */ + +/** + * CURAND Sobol64 state + */ +struct curandStateSobol64; + +/* Implementation details not in reference documentation */ +struct curandStateSobol64 { + unsigned long long i, x, c; + unsigned long long direction_vectors[64]; +}; + +/* + * CURAND Sobol64 state + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateSobol64 curandStateSobol64_t; +/** \endcond */ + +/** + * CURAND Scrambled Sobol64 state + */ +struct curandStateScrambledSobol64; + +/* Implementation details not in reference documentation */ +struct curandStateScrambledSobol64 { + unsigned long long i, x, c; + unsigned long long direction_vectors[64]; +}; + +/* + * CURAND Scrambled Sobol64 state + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateScrambledSobol64 curandStateScrambledSobol64_t; +/** \endcond */ + +/* + * Default RNG + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateXORWOW curandState_t; +typedef struct curandStateXORWOW curandState; +/** \endcond */ + +/****************************************************************************/ +/* Utility functions needed by RNGs */ +/****************************************************************************/ +/** \cond UNHIDE_UTILITIES */ +/* + multiply vector by matrix, store in result + matrix is n x n, measured in 32 bit units + matrix is stored in row major order + vector and result cannot be same pointer +*/ +template +QUALIFIERS void __curand_matvec_inplace(unsigned int *vector, unsigned int *matrix) +{ + unsigned int result[N] = { 0 }; + for(int i = 0; i < N; i++) { + #ifdef __CUDA_ARCH__ + #pragma unroll 16 + #endif + for(int j = 0; j < 32; j++) { + if(vector[i] & (1 << j)) { + for(int k = 0; k < N; k++) { + result[k] ^= matrix[N * (i * 32 + j) + k]; + } + } + } + } + for(int i = 0; i < N; i++) { + vector[i] = result[i]; + } +} + +QUALIFIERS void __curand_matvec(unsigned int *vector, unsigned int *matrix, + unsigned int *result, int n) +{ + for(int i = 0; i < n; i++) { + result[i] = 0; + } + for(int i = 0; i < n; i++) { + for(int j = 0; j < 32; j++) { + if(vector[i] & (1 << j)) { + for(int k = 0; k < n; k++) { + result[k] ^= matrix[n * (i * 32 + j) + k]; + } + } + } + } +} + +/* generate identity matrix */ +QUALIFIERS void __curand_matidentity(unsigned int *matrix, int n) +{ + int r; + for(int i = 0; i < n * 32; i++) { + for(int j = 0; j < n; j++) { + r = i & 31; + if(i / 32 == j) { + matrix[i * n + j] = (1 << r); + } else { + matrix[i * n + j] = 0; + } + } + } +} + +/* multiply matrixA by matrixB, store back in matrixA + matrixA and matrixB must not be same matrix */ +QUALIFIERS void __curand_matmat(unsigned int *matrixA, unsigned int *matrixB, int n) +{ + unsigned int result[MAX_XOR_N]; + for(int i = 0; i < n * 32; i++) { + __curand_matvec(matrixA + i * n, matrixB, result, n); + for(int j = 0; j < n; j++) { + matrixA[i * n + j] = result[j]; + } + } +} + +/* copy vectorA to vector */ +QUALIFIERS void __curand_veccopy(unsigned int *vector, unsigned int *vectorA, int n) +{ + for(int i = 0; i < n; i++) { + vector[i] = vectorA[i]; + } +} + +/* copy matrixA to matrix */ +QUALIFIERS void __curand_matcopy(unsigned int *matrix, unsigned int *matrixA, int n) +{ + for(int i = 0; i < n * n * 32; i++) { + matrix[i] = matrixA[i]; + } +} + +/* compute matrixA to power p, store result in matrix */ +QUALIFIERS void __curand_matpow(unsigned int *matrix, unsigned int *matrixA, + unsigned long long p, int n) +{ + unsigned int matrixR[MAX_XOR_N * MAX_XOR_N * 32]; + unsigned int matrixS[MAX_XOR_N * MAX_XOR_N * 32]; + __curand_matidentity(matrix, n); + __curand_matcopy(matrixR, matrixA, n); + while(p) { + if(p & 1) { + __curand_matmat(matrix, matrixR, n); + } + __curand_matcopy(matrixS, matrixR, n); + __curand_matmat(matrixR, matrixS, n); + p >>= 1; + } +} + +/****************************************************************************/ +/* Utility functions needed by MRG32k3a RNG */ +/* Matrix operations modulo some integer less than 2**32, done in */ +/* double precision floating point, with care not to overflow 53 bits */ +/****************************************************************************/ + +/* return i mod m. */ +/* assumes i and m are integers represented accurately in doubles */ + +QUALIFIERS double curand_MRGmod(double i, double m) +{ + double quo; + double rem; + quo = floor(i/m); + rem = i - (quo*m); + if (rem < 0.0) rem += m; + return rem; +} + +/* Multiplication modulo m. Inputs i and j less than 2**32 */ +/* Ensure intermediate results do not exceed 2**53 */ + +QUALIFIERS double curand_MRGmodMul(double i, double j, double m) +{ + double tempHi; + double tempLo; + + tempHi = floor(i/131072.0); + tempLo = i - (tempHi*131072.0); + tempLo = curand_MRGmod( curand_MRGmod( (tempHi * j), m) * 131072.0 + curand_MRGmod(tempLo * j, m),m); + + if (tempLo < 0.0) tempLo += m; + return tempLo; +} + +/* multiply 3 by 3 matrices of doubles, modulo m */ + +QUALIFIERS void curand_MRGmatMul3x3(unsigned int i1[][3],unsigned int i2[][3],unsigned int o[][3],double m) +{ + int i,j; + double temp[3][3]; + for (i=0; i<3; i++){ + for (j=0; j<3; j++){ + temp[i][j] = ( curand_MRGmodMul(i1[i][0], i2[0][j], m) + + curand_MRGmodMul(i1[i][1], i2[1][j], m) + + curand_MRGmodMul(i1[i][2], i2[2][j], m)); + temp[i][j] = curand_MRGmod( temp[i][j], m ); + } + } + for (i=0; i<3; i++){ + for (j=0; j<3; j++){ + o[i][j] = (unsigned int)temp[i][j]; + } + } +} + +/* multiply 3 by 3 matrix times 3 by 1 vector of doubles, modulo m */ + +QUALIFIERS void curand_MRGmatVecMul3x3( unsigned int i[][3], unsigned int v[], double m) +{ + int k; + double t[3]; + for (k = 0; k < 3; k++) { + t[k] = ( curand_MRGmodMul(i[k][0], v[0], m) + + curand_MRGmodMul(i[k][1], v[1], m) + + curand_MRGmodMul(i[k][2], v[2], m) ); + t[k] = curand_MRGmod( t[k], m ); + } + for (k = 0; k < 3; k++) { + v[k] = (unsigned int)t[k]; + } + +} + +/* raise a 3 by 3 matrix of doubles to a 64 bit integer power pow, modulo m */ +/* input is index zero of an array of 3 by 3 matrices m, */ +/* each m = m[0]**(2**index) */ + +QUALIFIERS void curand_MRGmatPow3x3( unsigned int in[][3][3], unsigned int o[][3], double m, unsigned long long pow ) +{ + int i,j; + for ( i = 0; i < 3; i++ ) { + for ( j = 0; j < 3; j++ ) { + o[i][j] = 0; + if ( i == j ) o[i][j] = 1; + } + } + i = 0; + curand_MRGmatVecMul3x3(o,o[0],m); + while (pow) { + if ( pow & 1ll ) { + curand_MRGmatMul3x3(in[i], o, o, m); + } + i++; + pow >>= 1; + } +} + +/* raise a 3 by 3 matrix of doubles to the power */ +/* 2 to the power (pow modulo 191), modulo m */ + +QUALIFIERS void curnand_MRGmatPow2Pow3x3( double in[][3], double o[][3], double m, unsigned long pow ) +{ + unsigned int temp[3][3]; + int i,j; + pow = pow % 191; + for ( i = 0; i < 3; i++ ) { + for ( j = 0; j < 3; j++ ) { + temp[i][j] = (unsigned int)in[i][j]; + } + } + while (pow) { + curand_MRGmatMul3x3(temp, temp, temp, m); + pow--; + } + for ( i = 0; i < 3; i++ ) { + for ( j = 0; j < 3; j++ ) { + o[i][j] = temp[i][j]; + } + } +} + +/** \endcond */ + +/****************************************************************************/ +/* Kernel implementations of RNGs */ +/****************************************************************************/ + +/* Test RNG */ + +QUALIFIERS void curand_init(unsigned long long seed, + unsigned long long subsequence, + unsigned long long offset, + curandStateTest_t *state) +{ + state->v = (unsigned int)(seed * 3) + (unsigned int)(subsequence * 31337) + \ + (unsigned int)offset; +} + + +QUALIFIERS unsigned int curand(curandStateTest_t *state) +{ + unsigned int r = state->v++; + return r; +} + +QUALIFIERS void skipahead(unsigned long long n, curandStateTest_t *state) +{ + state->v += (unsigned int)n; +} + +/* XORWOW RNG */ + +template +QUALIFIERS void __curand_generate_skipahead_matrix_xor(unsigned int matrix[]) +{ + T state; + // Generate matrix that advances one step + // matrix has n * n * 32 32-bit elements + // solve for matrix by stepping single bit states + for(int i = 0; i < 32 * n; i++) { + state.d = 0; + for(int j = 0; j < n; j++) { + state.v[j] = 0; + } + state.v[i / 32] = (1 << (i & 31)); + curand(&state); + for(int j = 0; j < n; j++) { + matrix[i * n + j] = state.v[j]; + } + } +} + +template +QUALIFIERS void _skipahead_scratch(unsigned long long x, T *state, unsigned int *scratch) +{ + // unsigned int matrix[n * n * 32]; + unsigned int *matrix = scratch; + // unsigned int matrixA[n * n * 32]; + unsigned int *matrixA = scratch + (n * n * 32); + // unsigned int vector[n]; + unsigned int *vector = scratch + (n * n * 32) + (n * n * 32); + // unsigned int result[n]; + unsigned int *result = scratch + (n * n * 32) + (n * n * 32) + n; + unsigned long long p = x; + for(int i = 0; i < n; i++) { + vector[i] = state->v[i]; + } + int matrix_num = 0; + while(p && (matrix_num < PRECALC_NUM_MATRICES - 1)) { + for(unsigned int t = 0; t < (p & PRECALC_BLOCK_MASK); t++) { +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + __curand_matvec(vector, precalc_xorwow_offset_matrix[matrix_num], result, n); +, + __curand_matvec(vector, precalc_xorwow_offset_matrix_host[matrix_num], result, n); +) + __curand_veccopy(vector, result, n); + } + p >>= PRECALC_BLOCK_SIZE; + matrix_num++; + } + if(p) { +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + __curand_matcopy(matrix, precalc_xorwow_offset_matrix[PRECALC_NUM_MATRICES - 1], n); + __curand_matcopy(matrixA, precalc_xorwow_offset_matrix[PRECALC_NUM_MATRICES - 1], n); +, + __curand_matcopy(matrix, precalc_xorwow_offset_matrix_host[PRECALC_NUM_MATRICES - 1], n); + __curand_matcopy(matrixA, precalc_xorwow_offset_matrix_host[PRECALC_NUM_MATRICES - 1], n); +) + } + while(p) { + for(unsigned int t = 0; t < (p & SKIPAHEAD_MASK); t++) { + __curand_matvec(vector, matrixA, result, n); + __curand_veccopy(vector, result, n); + } + p >>= SKIPAHEAD_BLOCKSIZE; + if(p) { + for(int i = 0; i < SKIPAHEAD_BLOCKSIZE; i++) { + __curand_matmat(matrix, matrixA, n); + __curand_matcopy(matrixA, matrix, n); + } + } + } + for(int i = 0; i < n; i++) { + state->v[i] = vector[i]; + } + state->d += 362437 * (unsigned int)x; +} + +template +QUALIFIERS void _skipahead_sequence_scratch(unsigned long long x, T *state, unsigned int *scratch) +{ + // unsigned int matrix[n * n * 32]; + unsigned int *matrix = scratch; + // unsigned int matrixA[n * n * 32]; + unsigned int *matrixA = scratch + (n * n * 32); + // unsigned int vector[n]; + unsigned int *vector = scratch + (n * n * 32) + (n * n * 32); + // unsigned int result[n]; + unsigned int *result = scratch + (n * n * 32) + (n * n * 32) + n; + unsigned long long p = x; + for(int i = 0; i < n; i++) { + vector[i] = state->v[i]; + } + int matrix_num = 0; + while(p && matrix_num < PRECALC_NUM_MATRICES - 1) { + for(unsigned int t = 0; t < (p & PRECALC_BLOCK_MASK); t++) { +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + __curand_matvec(vector, precalc_xorwow_matrix[matrix_num], result, n); +, + __curand_matvec(vector, precalc_xorwow_matrix_host[matrix_num], result, n); +) + __curand_veccopy(vector, result, n); + } + p >>= PRECALC_BLOCK_SIZE; + matrix_num++; + } + if(p) { +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + __curand_matcopy(matrix, precalc_xorwow_matrix[PRECALC_NUM_MATRICES - 1], n); + __curand_matcopy(matrixA, precalc_xorwow_matrix[PRECALC_NUM_MATRICES - 1], n); +, + __curand_matcopy(matrix, precalc_xorwow_matrix_host[PRECALC_NUM_MATRICES - 1], n); + __curand_matcopy(matrixA, precalc_xorwow_matrix_host[PRECALC_NUM_MATRICES - 1], n); +) + } + while(p) { + for(unsigned int t = 0; t < (p & SKIPAHEAD_MASK); t++) { + __curand_matvec(vector, matrixA, result, n); + __curand_veccopy(vector, result, n); + } + p >>= SKIPAHEAD_BLOCKSIZE; + if(p) { + for(int i = 0; i < SKIPAHEAD_BLOCKSIZE; i++) { + __curand_matmat(matrix, matrixA, n); + __curand_matcopy(matrixA, matrix, n); + } + } + } + for(int i = 0; i < n; i++) { + state->v[i] = vector[i]; + } + /* No update of state->d needed, guaranteed to be a multiple of 2^32 */ +} + +template +QUALIFIERS void _skipahead_inplace(const unsigned long long x, T *state) +{ + unsigned long long p = x; + int matrix_num = 0; + while(p) { + for(unsigned int t = 0; t < (p & PRECALC_BLOCK_MASK); t++) { +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + __curand_matvec_inplace(state->v, precalc_xorwow_offset_matrix[matrix_num]); +, + __curand_matvec_inplace(state->v, precalc_xorwow_offset_matrix_host[matrix_num]); +) + } + p >>= PRECALC_BLOCK_SIZE; + matrix_num++; + } + state->d += 362437 * (unsigned int)x; +} + +template +QUALIFIERS void _skipahead_sequence_inplace(unsigned long long x, T *state) +{ + int matrix_num = 0; + while(x) { + for(unsigned int t = 0; t < (x & PRECALC_BLOCK_MASK); t++) { +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + __curand_matvec_inplace(state->v, precalc_xorwow_matrix[matrix_num]); +, + __curand_matvec_inplace(state->v, precalc_xorwow_matrix_host[matrix_num]); +) + } + x >>= PRECALC_BLOCK_SIZE; + matrix_num++; + } + /* No update of state->d needed, guaranteed to be a multiple of 2^32 */ +} + +/** + * \brief Update XORWOW state to skip \p n elements. + * + * Update the XORWOW state in \p state to skip ahead \p n elements. + * + * All values of \p n are valid. Large values require more computation and so + * will take more time to complete. + * + * \param n - Number of elements to skip + * \param state - Pointer to state to update + */ +QUALIFIERS void skipahead(unsigned long long n, curandStateXORWOW_t *state) +{ + _skipahead_inplace(n, state); +} + +/** + * \brief Update XORWOW state to skip ahead \p n subsequences. + * + * Update the XORWOW state in \p state to skip ahead \p n subsequences. Each + * subsequence is \xmlonly267\endxmlonly elements long, so this means the function will skip ahead + * \xmlonly267\endxmlonly * n elements. + * + * All values of \p n are valid. Large values require more computation and so + * will take more time to complete. + * + * \param n - Number of subsequences to skip + * \param state - Pointer to state to update + */ +QUALIFIERS void skipahead_sequence(unsigned long long n, curandStateXORWOW_t *state) +{ + _skipahead_sequence_inplace(n, state); +} + +QUALIFIERS void _curand_init_scratch(unsigned long long seed, + unsigned long long subsequence, + unsigned long long offset, + curandStateXORWOW_t *state, + unsigned int *scratch) +{ + // Break up seed, apply salt + // Constants are arbitrary nonzero values + unsigned int s0 = ((unsigned int)seed) ^ 0xaad26b49UL; + unsigned int s1 = (unsigned int)(seed >> 32) ^ 0xf7dcefddUL; + // Simple multiplication to mix up bits + // Constants are arbitrary odd values + unsigned int t0 = 1099087573UL * s0; + unsigned int t1 = 2591861531UL * s1; + state->d = 6615241 + t1 + t0; + state->v[0] = 123456789UL + t0; + state->v[1] = 362436069UL ^ t0; + state->v[2] = 521288629UL + t1; + state->v[3] = 88675123UL ^ t1; + state->v[4] = 5783321UL + t0; + _skipahead_sequence_scratch(subsequence, state, scratch); + _skipahead_scratch(offset, state, scratch); + state->boxmuller_flag = 0; + state->boxmuller_flag_double = 0; + state->boxmuller_extra = 0.f; + state->boxmuller_extra_double = 0.; +} + +QUALIFIERS void _curand_init_inplace(unsigned long long seed, + unsigned long long subsequence, + unsigned long long offset, + curandStateXORWOW_t *state) +{ + // Break up seed, apply salt + // Constants are arbitrary nonzero values + unsigned int s0 = ((unsigned int)seed) ^ 0xaad26b49UL; + unsigned int s1 = (unsigned int)(seed >> 32) ^ 0xf7dcefddUL; + // Simple multiplication to mix up bits + // Constants are arbitrary odd values + unsigned int t0 = 1099087573UL * s0; + unsigned int t1 = 2591861531UL * s1; + state->d = 6615241 + t1 + t0; + state->v[0] = 123456789UL + t0; + state->v[1] = 362436069UL ^ t0; + state->v[2] = 521288629UL + t1; + state->v[3] = 88675123UL ^ t1; + state->v[4] = 5783321UL + t0; + _skipahead_sequence_inplace(subsequence, state); + _skipahead_inplace(offset, state); + state->boxmuller_flag = 0; + state->boxmuller_flag_double = 0; + state->boxmuller_extra = 0.f; + state->boxmuller_extra_double = 0.; +} + +/** + * \brief Initialize XORWOW state. + * + * Initialize XORWOW state in \p state with the given \p seed, \p subsequence, + * and \p offset. + * + * All input values of \p seed, \p subsequence, and \p offset are legal. Large + * values for \p subsequence and \p offset require more computation and so will + * take more time to complete. + * + * A value of 0 for \p seed sets the state to the values of the original + * published version of the \p xorwow algorithm. + * + * \param seed - Arbitrary bits to use as a seed + * \param subsequence - Subsequence to start at + * \param offset - Absolute offset into sequence + * \param state - Pointer to state to initialize + */ +QUALIFIERS void curand_init(unsigned long long seed, + unsigned long long subsequence, + unsigned long long offset, + curandStateXORWOW_t *state) +{ + _curand_init_inplace(seed, subsequence, offset, state); +} + +/** + * \brief Return 32-bits of pseudorandomness from an XORWOW generator. + * + * Return 32-bits of pseudorandomness from the XORWOW generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * + * \return 32-bits of pseudorandomness as an unsigned int, all bits valid to use. + */ +QUALIFIERS unsigned int curand(curandStateXORWOW_t *state) +{ + unsigned int t; + t = (state->v[0] ^ (state->v[0] >> 2)); + state->v[0] = state->v[1]; + state->v[1] = state->v[2]; + state->v[2] = state->v[3]; + state->v[3] = state->v[4]; + state->v[4] = (state->v[4] ^ (state->v[4] <<4)) ^ (t ^ (t << 1)); + state->d += 362437; + return state->v[4] + state->d; +} + + +/** + * \brief Return 32-bits of pseudorandomness from an Philox4_32_10 generator. + * + * Return 32-bits of pseudorandomness from the Philox4_32_10 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * + * \return 32-bits of pseudorandomness as an unsigned int, all bits valid to use. + */ + +QUALIFIERS unsigned int curand(curandStatePhilox4_32_10_t *state) +{ + // Maintain the invariant: output[STATE] is always "good" and + // is the next value to be returned by curand. + unsigned int ret; + switch(state->STATE++){ + default: + ret = state->output.x; + break; + case 1: + ret = state->output.y; + break; + case 2: + ret = state->output.z; + break; + case 3: + ret = state->output.w; + break; + } + if(state->STATE == 4){ + Philox_State_Incr(state); + state->output = curand_Philox4x32_10(state->ctr,state->key); + state->STATE = 0; + } + return ret; +} + +/** + * \brief Return tuple of 4 32-bit pseudorandoms from a Philox4_32_10 generator. + * + * Return 128 bits of pseudorandomness from the Philox4_32_10 generator in \p state, + * increment position of generator by four. + * + * \param state - Pointer to state to update + * + * \return 128-bits of pseudorandomness as a uint4, all bits valid to use. + */ + +QUALIFIERS uint4 curand4(curandStatePhilox4_32_10_t *state) +{ + uint4 r; + + uint4 tmp = state->output; + Philox_State_Incr(state); + state->output= curand_Philox4x32_10(state->ctr,state->key); + switch(state->STATE){ + case 0: + return tmp; + case 1: + r.x = tmp.y; + r.y = tmp.z; + r.z = tmp.w; + r.w = state->output.x; + break; + case 2: + r.x = tmp.z; + r.y = tmp.w; + r.z = state->output.x; + r.w = state->output.y; + break; + case 3: + r.x = tmp.w; + r.y = state->output.x; + r.z = state->output.y; + r.w = state->output.z; + break; + default: + // NOT possible but needed to avoid compiler warnings + return tmp; + } + return r; +} + +/** + * \brief Update Philox4_32_10 state to skip \p n elements. + * + * Update the Philox4_32_10 state in \p state to skip ahead \p n elements. + * + * All values of \p n are valid. + * + * \param n - Number of elements to skip + * \param state - Pointer to state to update + */ +QUALIFIERS void skipahead(unsigned long long n, curandStatePhilox4_32_10_t *state) +{ + state->STATE += (n & 3); + n /= 4; + if( state->STATE > 3 ){ + n += 1; + state->STATE -= 4; + } + Philox_State_Incr(state, n); + state->output = curand_Philox4x32_10(state->ctr,state->key); +} + +/** + * \brief Update Philox4_32_10 state to skip ahead \p n subsequences. + * + * Update the Philox4_32_10 state in \p state to skip ahead \p n subsequences. Each + * subsequence is \xmlonly266\endxmlonly elements long, so this means the function will skip ahead + * \xmlonly266\endxmlonly * n elements. + * + * All values of \p n are valid. + * + * \param n - Number of subsequences to skip + * \param state - Pointer to state to update + */ +QUALIFIERS void skipahead_sequence(unsigned long long n, curandStatePhilox4_32_10_t *state) +{ + Philox_State_Incr_hi(state, n); + state->output = curand_Philox4x32_10(state->ctr,state->key); +} + +/** + * \brief Initialize Philox4_32_10 state. + * + * Initialize Philox4_32_10 state in \p state with the given \p seed, p\ subsequence, + * and \p offset. + * + * All input values for \p seed, \p subseqence and \p offset are legal. Each of the + * \xmlonly264\endxmlonly possible + * values of seed selects an independent sequence of length + * \xmlonly2130\endxmlonly. + * The first + * \xmlonly266 * subsequence + offset\endxmlonly. + * values of the sequence are skipped. + * I.e., subsequences are of length + * \xmlonly266\endxmlonly. + * + * \param seed - Arbitrary bits to use as a seed + * \param subsequence - Subsequence to start at + * \param offset - Absolute offset into subsequence + * \param state - Pointer to state to initialize + */ +QUALIFIERS void curand_init(unsigned long long seed, + unsigned long long subsequence, + unsigned long long offset, + curandStatePhilox4_32_10_t *state) +{ + state->ctr = make_uint4(0, 0, 0, 0); + state->key.x = (unsigned int)seed; + state->key.y = (unsigned int)(seed>>32); + state->STATE = 0; + state->boxmuller_flag = 0; + state->boxmuller_flag_double = 0; + state->boxmuller_extra = 0.f; + state->boxmuller_extra_double = 0.; + skipahead_sequence(subsequence, state); + skipahead(offset, state); +} + + +/* MRG32k3a RNG */ + +/* Base generator for MRG32k3a */ +QUALIFIERS unsigned long long __curand_umad(GCC_UNUSED_PARAMETER unsigned int a, GCC_UNUSED_PARAMETER unsigned int b, GCC_UNUSED_PARAMETER unsigned long long c) +{ + unsigned long long r = 0; +NV_IF_TARGET(NV_PROVIDES_SM_61, + asm("mad.wide.u32 %0, %1, %2, %3;" + : "=l"(r) : "r"(a), "r"(b), "l"(c)); +) + return r; +} +QUALIFIERS unsigned long long __curand_umul(GCC_UNUSED_PARAMETER unsigned int a, GCC_UNUSED_PARAMETER unsigned int b) +{ + unsigned long long r = 0; +NV_IF_TARGET(NV_PROVIDES_SM_61, + asm("mul.wide.u32 %0, %1, %2;" + : "=l"(r) : "r"(a), "r"(b)); +) + return r; +} +QUALIFIERS double curand_MRG32k3a (curandStateMRG32k3a_t *state) +{ +NV_IF_TARGET(NV_PROVIDES_SM_61, + const unsigned int m1 = 4294967087u; + const unsigned int m2 = 4294944443u; + const unsigned int m1c = 209u; + const unsigned int m2c = 22853u; + const unsigned int a12 = 1403580u; + const unsigned int a13n = 810728u; + const unsigned int a21 = 527612u; + const unsigned int a23n = 1370589u; + + unsigned long long p1; + unsigned long long p2; + const unsigned long long p3 = __curand_umul(a13n, m1 - state->s1[0]); + p1 = __curand_umad(a12, state->s1[1], p3); + + // Putting addition inside and changing umul to umad + // slowed this function down on GV100 + p1 = __curand_umul(p1 >> 32, m1c) + (p1 & 0xffffffff); + if (p1 >= m1) p1 -= m1; + + state->s1[0] = state->s1[1]; state->s1[1] = state->s1[2]; state->s1[2] = p1; + const unsigned long long p4 = __curand_umul(a23n, m2 - state->s2[0]); + p2 = __curand_umad(a21, state->s2[2], p4); + + // Putting addition inside and changing umul to umad + // slowed this function down on GV100 + p2 = __curand_umul(p2 >> 32, m2c) + (p2 & 0xffffffff); + p2 = __curand_umul(p2 >> 32, m2c) + (p2 & 0xffffffff); + if (p2 >= m2) p2 -= m2; + + state->s2[0] = state->s2[1]; state->s2[1] = state->s2[2]; state->s2[2] = p2; + + const unsigned int p5 = (unsigned int)p1 - (unsigned int)p2; + if(p1 <= p2) return p5 + m1; + return p5; +) +NV_IF_TARGET(NV_IS_DEVICE, +/* nj's implementation */ + const double m1 = 4294967087.; + const double m2 = 4294944443.; + const double a12 = 1403580.; + const double a13n = 810728.; + const double a21 = 527612.; + const double a23n = 1370589.; + + const double rh1 = 2.3283065498378290e-010; /* (1.0 / m1)__hi */ + const double rl1 = -1.7354913086174288e-026; /* (1.0 / m1)__lo */ + const double rh2 = 2.3283188252407387e-010; /* (1.0 / m2)__hi */ + const double rl2 = 2.4081018096503646e-026; /* (1.0 / m2)__lo */ + + double q; + double p1; + double p2; + p1 = a12 * state->s1[1] - a13n * state->s1[0]; + q = trunc (fma (p1, rh1, p1 * rl1)); + p1 -= q * m1; + if (p1 < 0.0) p1 += m1; + state->s1[0] = state->s1[1]; state->s1[1] = state->s1[2]; state->s1[2] = (unsigned int)p1; + p2 = a21 * state->s2[2] - a23n * state->s2[0]; + q = trunc (fma (p2, rh2, p2 * rl2)); + p2 -= q * m2; + if (p2 < 0.0) p2 += m2; + state->s2[0] = state->s2[1]; state->s2[1] = state->s2[2]; state->s2[2] = (unsigned int)p2; + if (p1 <= p2) return (p1 - p2 + m1); + else return (p1 - p2); +) +/* end nj's implementation */ + double p1; + double p2; + double r; + p1 = (MRG32K3A_A12 * state->s1[1]) - (MRG32K3A_A13N * state->s1[0]); + p1 = curand_MRGmod(p1, MRG32K3A_MOD1); + if (p1 < 0.0) p1 += MRG32K3A_MOD1; + state->s1[0] = state->s1[1]; + state->s1[1] = state->s1[2]; + state->s1[2] = (unsigned int)p1; + p2 = (MRG32K3A_A21 * state->s2[2]) - (MRG32K3A_A23N * state->s2[0]); + p2 = curand_MRGmod(p2, MRG32K3A_MOD2); + if (p2 < 0) p2 += MRG32K3A_MOD2; + state->s2[0] = state->s2[1]; + state->s2[1] = state->s2[2]; + state->s2[2] = (unsigned int)p2; + r = p1 - p2; + if (r <= 0) r += MRG32K3A_MOD1; + return r; +} + + +/** + * \brief Return 32-bits of pseudorandomness from an MRG32k3a generator. + * + * Return 32-bits of pseudorandomness from the MRG32k3a generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * + * \return 32-bits of pseudorandomness as an unsigned int, all bits valid to use. + */ +QUALIFIERS unsigned int curand(curandStateMRG32k3a_t *state) +{ + double dRet; + dRet = (double)curand_MRG32k3a(state)*(double)MRG32K3A_BITS_NORM; + return (unsigned int)dRet; +} + + + +/** + * \brief Update MRG32k3a state to skip \p n elements. + * + * Update the MRG32k3a state in \p state to skip ahead \p n elements. + * + * All values of \p n are valid. Large values require more computation and so + * will take more time to complete. + * + * \param n - Number of elements to skip + * \param state - Pointer to state to update + */ +QUALIFIERS void skipahead(unsigned long long n, curandStateMRG32k3a_t *state) +{ + unsigned int t[3][3]; +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + curand_MRGmatPow3x3( mrg32k3aM1, t, MRG32K3A_MOD1, n); + curand_MRGmatVecMul3x3( t, state->s1, MRG32K3A_MOD1); + curand_MRGmatPow3x3(mrg32k3aM2, t, MRG32K3A_MOD2, n); + curand_MRGmatVecMul3x3( t, state->s2, MRG32K3A_MOD2); +, + curand_MRGmatPow3x3( mrg32k3aM1Host, t, MRG32K3A_MOD1, n); + curand_MRGmatVecMul3x3( t, state->s1, MRG32K3A_MOD1); + curand_MRGmatPow3x3(mrg32k3aM2Host, t, MRG32K3A_MOD2, n); + curand_MRGmatVecMul3x3( t, state->s2, MRG32K3A_MOD2); +) +} + +/** + * \brief Update MRG32k3a state to skip ahead \p n subsequences. + * + * Update the MRG32k3a state in \p state to skip ahead \p n subsequences. Each + * subsequence is \xmlonly2127\endxmlonly + * + * \xmlonly276\endxmlonly elements long, so this means the function will skip ahead + * \xmlonly267\endxmlonly * n elements. + * + * Valid values of \p n are 0 to \xmlonly251\endxmlonly. Note \p n will be masked to 51 bits + * + * \param n - Number of subsequences to skip + * \param state - Pointer to state to update + */ +QUALIFIERS void skipahead_subsequence(unsigned long long n, curandStateMRG32k3a_t *state) +{ + unsigned int t[3][3]; +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + curand_MRGmatPow3x3( mrg32k3aM1SubSeq, t, MRG32K3A_MOD1, n); + curand_MRGmatVecMul3x3( t, state->s1, MRG32K3A_MOD1); + curand_MRGmatPow3x3( mrg32k3aM2SubSeq, t, MRG32K3A_MOD2, n); + curand_MRGmatVecMul3x3( t, state->s2, MRG32K3A_MOD2); +, + curand_MRGmatPow3x3( mrg32k3aM1SubSeqHost, t, MRG32K3A_MOD1, n); + curand_MRGmatVecMul3x3( t, state->s1, MRG32K3A_MOD1); + curand_MRGmatPow3x3( mrg32k3aM2SubSeqHost, t, MRG32K3A_MOD2, n); + curand_MRGmatVecMul3x3( t, state->s2, MRG32K3A_MOD2); +) +} + +/** + * \brief Update MRG32k3a state to skip ahead \p n sequences. + * + * Update the MRG32k3a state in \p state to skip ahead \p n sequences. Each + * sequence is \xmlonly2127\endxmlonly elements long, so this means the function will skip ahead + * \xmlonly2127\endxmlonly * n elements. + * + * All values of \p n are valid. Large values require more computation and so + * will take more time to complete. + * + * \param n - Number of sequences to skip + * \param state - Pointer to state to update + */ +QUALIFIERS void skipahead_sequence(unsigned long long n, curandStateMRG32k3a_t *state) +{ + unsigned int t[3][3]; +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + curand_MRGmatPow3x3( mrg32k3aM1Seq, t, MRG32K3A_MOD1, n); + curand_MRGmatVecMul3x3( t, state->s1, MRG32K3A_MOD1); + curand_MRGmatPow3x3( mrg32k3aM2Seq, t, MRG32K3A_MOD2, n); + curand_MRGmatVecMul3x3( t, state->s2, MRG32K3A_MOD2); +, + curand_MRGmatPow3x3( mrg32k3aM1SeqHost, t, MRG32K3A_MOD1, n); + curand_MRGmatVecMul3x3( t, state->s1, MRG32K3A_MOD1); + curand_MRGmatPow3x3( mrg32k3aM2SeqHost, t, MRG32K3A_MOD2, n); + curand_MRGmatVecMul3x3( t, state->s2, MRG32K3A_MOD2); +) +} + + +/** + * \brief Initialize MRG32k3a state. + * + * Initialize MRG32k3a state in \p state with the given \p seed, \p subsequence, + * and \p offset. + * + * All input values of \p seed, \p subsequence, and \p offset are legal. + * \p subsequence will be truncated to 51 bits to avoid running into the next sequence + * + * A value of 0 for \p seed sets the state to the values of the original + * published version of the \p MRG32k3a algorithm. + * + * \param seed - Arbitrary bits to use as a seed + * \param subsequence - Subsequence to start at + * \param offset - Absolute offset into sequence + * \param state - Pointer to state to initialize + */ +QUALIFIERS void curand_init(unsigned long long seed, + unsigned long long subsequence, + unsigned long long offset, + curandStateMRG32k3a_t *state) +{ + int i; + for ( i=0; i<3; i++ ) { + state->s1[i] = 12345u; + state->s2[i] = 12345u; + } + if (seed != 0ull) { + unsigned int x1 = ((unsigned int)seed) ^ 0x55555555UL; + unsigned int x2 = (unsigned int)((seed >> 32) ^ 0xAAAAAAAAUL); + state->s1[0] = (unsigned int)curand_MRGmodMul(x1, state->s1[0], MRG32K3A_MOD1); + state->s1[1] = (unsigned int)curand_MRGmodMul(x2, state->s1[1], MRG32K3A_MOD1); + state->s1[2] = (unsigned int)curand_MRGmodMul(x1, state->s1[2], MRG32K3A_MOD1); + state->s2[0] = (unsigned int)curand_MRGmodMul(x2, state->s2[0], MRG32K3A_MOD2); + state->s2[1] = (unsigned int)curand_MRGmodMul(x1, state->s2[1], MRG32K3A_MOD2); + state->s2[2] = (unsigned int)curand_MRGmodMul(x2, state->s2[2], MRG32K3A_MOD2); + } + skipahead_subsequence( subsequence, state ); + skipahead( offset, state ); + state->boxmuller_flag = 0; + state->boxmuller_flag_double = 0; + state->boxmuller_extra = 0.f; + state->boxmuller_extra_double = 0.; +} + +/** + * \brief Update Sobol32 state to skip \p n elements. + * + * Update the Sobol32 state in \p state to skip ahead \p n elements. + * + * All values of \p n are valid. + * + * \param n - Number of elements to skip + * \param state - Pointer to state to update + */ +template +QUALIFIERS +typename CURAND_STD::enable_if::value || CURAND_STD::is_same::value>::type +skipahead(unsigned int n, T state) +{ + unsigned int i_gray; + state->x = state->c; + state->i += n; + /* Convert state->i to gray code */ + i_gray = state->i ^ (state->i >> 1); + for(unsigned int k = 0; k < 32; k++) { + if(i_gray & (1 << k)) { + state->x ^= state->direction_vectors[k]; + } + } + return; +} + +/** + * \brief Update Sobol64 state to skip \p n elements. + * + * Update the Sobol64 state in \p state to skip ahead \p n elements. + * + * All values of \p n are valid. + * + * \param n - Number of elements to skip + * \param state - Pointer to state to update + */ +template +QUALIFIERS +typename CURAND_STD::enable_if::value || CURAND_STD::is_same::value>::type +skipahead(unsigned long long n, T state) +{ + unsigned long long i_gray; + state->x = state->c; + state->i += n; + /* Convert state->i to gray code */ + i_gray = state->i ^ (state->i >> 1); + for(unsigned k = 0; k < 64; k++) { + if(i_gray & (1ULL << k)) { + state->x ^= state->direction_vectors[k]; + } + } + return; +} + +/** + * \brief Initialize Sobol32 state. + * + * Initialize Sobol32 state in \p state with the given \p direction \p vectors and + * \p offset. + * + * The direction vector is a device pointer to an array of 32 unsigned ints. + * All input values of \p offset are legal. + * + * \param direction_vectors - Pointer to array of 32 unsigned ints representing the + * direction vectors for the desired dimension + * \param offset - Absolute offset into sequence + * \param state - Pointer to state to initialize + */ +QUALIFIERS void curand_init(curandDirectionVectors32_t direction_vectors, + unsigned int offset, + curandStateSobol32_t *state) +{ + state->i = 0; + state->c = 0; + for(int i = 0; i < 32; i++) { + state->direction_vectors[i] = direction_vectors[i]; + } + state->x = 0; + skipahead(offset, state); +} +/** + * \brief Initialize Scrambled Sobol32 state. + * + * Initialize Sobol32 state in \p state with the given \p direction \p vectors and + * \p offset. + * + * The direction vector is a device pointer to an array of 32 unsigned ints. + * All input values of \p offset are legal. + * + * \param direction_vectors - Pointer to array of 32 unsigned ints representing the + direction vectors for the desired dimension + * \param scramble_c Scramble constant + * \param offset - Absolute offset into sequence + * \param state - Pointer to state to initialize + */ +QUALIFIERS void curand_init(curandDirectionVectors32_t direction_vectors, + unsigned int scramble_c, + unsigned int offset, + curandStateScrambledSobol32_t *state) +{ + state->i = 0; + state->c = scramble_c; + for(int i = 0; i < 32; i++) { + state->direction_vectors[i] = direction_vectors[i]; + } + state->x = state->c; + skipahead(offset, state); +} + +QUALIFIERS int __curand_find_trailing_zero(unsigned int x) +{ +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + int y = __ffs(~x); + if(y) + return y - 1; + return 31; +, + int i = 1; + while(x & 1) { + i++; + x >>= 1; + } + i = i - 1; + return i == 32 ? 31 : i; +) +} + +QUALIFIERS int __curand_find_trailing_zero(unsigned long long x) +{ +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + int y = __ffsll(~x); + if(y) + return y - 1; + return 63; +, + int i = 1; + while(x & 1) { + i++; + x >>= 1; + } + i = i - 1; + return i == 64 ? 63 : i; +) +} + +/** + * \brief Initialize Sobol64 state. + * + * Initialize Sobol64 state in \p state with the given \p direction \p vectors and + * \p offset. + * + * The direction vector is a device pointer to an array of 64 unsigned long longs. + * All input values of \p offset are legal. + * + * \param direction_vectors - Pointer to array of 64 unsigned long longs representing the + direction vectors for the desired dimension + * \param offset - Absolute offset into sequence + * \param state - Pointer to state to initialize + */ +QUALIFIERS void curand_init(curandDirectionVectors64_t direction_vectors, + unsigned long long offset, + curandStateSobol64_t *state) +{ + state->i = 0; + state->c = 0; + for(int i = 0; i < 64; i++) { + state->direction_vectors[i] = direction_vectors[i]; + } + state->x = 0; + skipahead(offset, state); +} + +/** + * \brief Initialize Scrambled Sobol64 state. + * + * Initialize Sobol64 state in \p state with the given \p direction \p vectors and + * \p offset. + * + * The direction vector is a device pointer to an array of 64 unsigned long longs. + * All input values of \p offset are legal. + * + * \param direction_vectors - Pointer to array of 64 unsigned long longs representing the + direction vectors for the desired dimension + * \param scramble_c Scramble constant + * \param offset - Absolute offset into sequence + * \param state - Pointer to state to initialize + */ +QUALIFIERS void curand_init(curandDirectionVectors64_t direction_vectors, + unsigned long long scramble_c, + unsigned long long offset, + curandStateScrambledSobol64_t *state) +{ + state->i = 0; + state->c = scramble_c; + for(int i = 0; i < 64; i++) { + state->direction_vectors[i] = direction_vectors[i]; + } + state->x = state->c; + skipahead(offset, state); +} + +/** + * \brief Return 32-bits of quasirandomness from a Sobol32 generator. + * + * Return 32-bits of quasirandomness from the Sobol32 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * + * \return 32-bits of quasirandomness as an unsigned int, all bits valid to use. + */ + +QUALIFIERS unsigned int curand(curandStateSobol32_t * state) +{ + /* Moving from i to i+1 element in gray code is flipping one bit, + the trailing zero bit of i + */ + unsigned int res = state->x; + state->x ^= state->direction_vectors[__curand_find_trailing_zero(state->i)]; + state->i ++; + return res; +} + +/** + * \brief Return 32-bits of quasirandomness from a scrambled Sobol32 generator. + * + * Return 32-bits of quasirandomness from the scrambled Sobol32 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * + * \return 32-bits of quasirandomness as an unsigned int, all bits valid to use. + */ + +QUALIFIERS unsigned int curand(curandStateScrambledSobol32_t * state) +{ + /* Moving from i to i+1 element in gray code is flipping one bit, + the trailing zero bit of i + */ + unsigned int res = state->x; + state->x ^= state->direction_vectors[__curand_find_trailing_zero(state->i)]; + state->i ++; + return res; +} + +/** + * \brief Return 64-bits of quasirandomness from a Sobol64 generator. + * + * Return 64-bits of quasirandomness from the Sobol64 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * + * \return 64-bits of quasirandomness as an unsigned long long, all bits valid to use. + */ + +QUALIFIERS unsigned long long curand(curandStateSobol64_t * state) +{ + /* Moving from i to i+1 element in gray code is flipping one bit, + the trailing zero bit of i + */ + unsigned long long res = state->x; + state->x ^= state->direction_vectors[__curand_find_trailing_zero(state->i)]; + state->i ++; + return res; +} + +/** + * \brief Return 64-bits of quasirandomness from a scrambled Sobol64 generator. + * + * Return 64-bits of quasirandomness from the scrambled Sobol32 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * + * \return 64-bits of quasirandomness as an unsigned long long, all bits valid to use. + */ + +QUALIFIERS unsigned long long curand(curandStateScrambledSobol64_t * state) +{ + /* Moving from i to i+1 element in gray code is flipping one bit, + the trailing zero bit of i + */ + unsigned long long res = state->x; + state->x ^= state->direction_vectors[__curand_find_trailing_zero(state->i)]; + state->i ++; + return res; +} + +#include "curand_uniform.h" +#include "curand_normal.h" +#include "curand_lognormal.h" +#include "curand_poisson.h" +#include "curand_discrete2.h" + +__device__ static inline unsigned int *__get_precalculated_matrix(int n) +{ + if(n == 0) { + return precalc_xorwow_matrix[n]; + } + if(n == 2) { + return precalc_xorwow_offset_matrix[n]; + } + return precalc_xorwow_matrix[n]; +} + +#ifndef __CUDACC_RTC__ +__host__ static inline unsigned int *__get_precalculated_matrix_host(int n) +{ + if(n == 1) { + return precalc_xorwow_matrix_host[n]; + } + if(n == 3) { + return precalc_xorwow_offset_matrix_host[n]; + } + return precalc_xorwow_matrix_host[n]; +} +#endif // #ifndef __CUDACC_RTC__ + +__device__ static inline unsigned int *__get_mrg32k3a_matrix(int n) +{ + if(n == 0) { + return mrg32k3aM1[n][0]; + } + if(n == 2) { + return mrg32k3aM2[n][0]; + } + if(n == 4) { + return mrg32k3aM1SubSeq[n][0]; + } + if(n == 6) { + return mrg32k3aM2SubSeq[n][0]; + } + if(n == 8) { + return mrg32k3aM1Seq[n][0]; + } + if(n == 10) { + return mrg32k3aM2Seq[n][0]; + } + return mrg32k3aM1[n][0]; +} + +#ifndef __CUDACC_RTC__ +__host__ static inline unsigned int *__get_mrg32k3a_matrix_host(int n) +{ + if(n == 1) { + return mrg32k3aM1Host[n][0]; + } + if(n == 3) { + return mrg32k3aM2Host[n][0]; + } + if(n == 5) { + return mrg32k3aM1SubSeqHost[n][0]; + } + if(n == 7) { + return mrg32k3aM2SubSeqHost[n][0]; + } + if(n == 9) { + return mrg32k3aM1SeqHost[n][0]; + } + if(n == 11) { + return mrg32k3aM2SeqHost[n][0]; + } + return mrg32k3aM1Host[n][0]; +} + +__host__ static inline double *__get__cr_lgamma_table_host(void) { + return __cr_lgamma_table; +} +#endif // #ifndef __CUDACC_RTC__ + +/** @} */ + +#endif // !defined(CURAND_KERNEL_H_) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_lognormal.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_lognormal.h new file mode 100644 index 0000000000000000000000000000000000000000..2ebb27599e54cef8325e0d43457f09283d13cb88 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_lognormal.h @@ -0,0 +1,697 @@ + + /* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + + +#if !defined(CURAND_LOGNORMAL_H_) +#define CURAND_LOGNORMAL_H_ + +/** + * \defgroup DEVICE Device API + * + * @{ + */ + +#ifndef __CUDACC_RTC__ +#include +#endif // __CUDACC_RTC__ + +#include "curand_mrg32k3a.h" +#include "curand_mtgp32_kernel.h" +#include "curand_philox4x32_x.h" + +/** + * \brief Return a log-normally distributed float from an XORWOW generator. + * + * Return a single log-normally distributed float derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the XORWOW generator in \p state, + * increment position of generator by one. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, transforms them to log-normal distribution, + * then returns them one at a time. + * See ::curand_log_normal2() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float curand_log_normal(curandStateXORWOW_t *state, float mean, float stddev) +{ + if(state->boxmuller_flag != EXTRA_FLAG_LOG_NORMAL) { + unsigned int x, y; + x = curand(state); + y = curand(state); + float2 v = _curand_box_muller(x, y); + state->boxmuller_extra = expf(mean + (stddev * v.y)); + state->boxmuller_flag = EXTRA_FLAG_LOG_NORMAL; + return expf(mean + (stddev * v.x)); + } + state->boxmuller_flag = 0; + return state->boxmuller_extra; +} + +/** + * \brief Return a log-normally distributed float from an Philox4_32_10 generator. + * + * Return a single log-normally distributed float derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Philox4_32_10 generator in \p state, + * increment position of generator by one. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, transforms them to log-normal distribution, + * then returns them one at a time. + * See ::curand_log_normal2() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float with mean \p mean and standard deviation \p stddev + */ + +QUALIFIERS float curand_log_normal(curandStatePhilox4_32_10_t *state, float mean, float stddev) +{ + if(state->boxmuller_flag != EXTRA_FLAG_LOG_NORMAL) { + unsigned int x, y; + x = curand(state); + y = curand(state); + float2 v = _curand_box_muller(x, y); + state->boxmuller_extra = expf(mean + (stddev * v.y)); + state->boxmuller_flag = EXTRA_FLAG_LOG_NORMAL; + return expf(mean + (stddev * v.x)); + } + state->boxmuller_flag = 0; + return state->boxmuller_extra; +} + +/** + * \brief Return two normally distributed floats from an XORWOW generator. + * + * Return two log-normally distributed floats derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the XORWOW generator in \p state, + * increment position of generator by two. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then transforms them to log-normal. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float2 where each element is from a + * distribution with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float2 curand_log_normal2(curandStateXORWOW_t *state, float mean, float stddev) +{ + float2 v = curand_box_muller(state); + v.x = expf(mean + (stddev * v.x)); + v.y = expf(mean + (stddev * v.y)); + return v; +} + +/** + * \brief Return two normally distributed floats from an Philox4_32_10 generator. + * + * Return two log-normally distributed floats derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Philox4_32_10 generator in \p state, + * increment position of generator by two. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then transforms them to log-normal. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float2 where each element is from a + * distribution with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float2 curand_log_normal2(curandStatePhilox4_32_10_t *state, float mean, float stddev) +{ + float2 v = curand_box_muller(state); + v.x = expf(mean + (stddev * v.x)); + v.y = expf(mean + (stddev * v.y)); + return v; +} +/** + * \brief Return four normally distributed floats from an Philox4_32_10 generator. + * + * Return four log-normally distributed floats derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Philox4_32_10 generator in \p state, + * increment position of generator by four. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then transforms them to log-normal. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float4 where each element is from a + * distribution with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float4 curand_log_normal4(curandStatePhilox4_32_10_t *state, float mean, float stddev) +{ + float4 v = curand_box_muller4(state); + v.x = expf(mean + (stddev * v.x)); + v.y = expf(mean + (stddev * v.y)); + v.z = expf(mean + (stddev * v.z)); + v.w = expf(mean + (stddev * v.w)); + return v; +} + +/** + * \brief Return a log-normally distributed float from an MRG32k3a generator. + * + * Return a single log-normally distributed float derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the MRG32k3a generator in \p state, + * increment position of generator by one. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, transforms them to log-normal distribution, + * then returns them one at a time. + * See ::curand_log_normal2() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float curand_log_normal(curandStateMRG32k3a_t *state, float mean, float stddev) +{ + if(state->boxmuller_flag != EXTRA_FLAG_LOG_NORMAL) { + float2 v = curand_box_muller_mrg(state); + state->boxmuller_extra = expf(mean + (stddev * v.y)); + state->boxmuller_flag = EXTRA_FLAG_LOG_NORMAL; + return expf(mean + (stddev * v.x)); + } + state->boxmuller_flag = 0; + return state->boxmuller_extra; +} + +/** + * \brief Return two normally distributed floats from an MRG32k3a generator. + * + * Return two log-normally distributed floats derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the MRG32k3a generator in \p state, + * increment position of generator by two. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then transforms them to log-normal. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float2 where each element is from a + * distribution with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float2 curand_log_normal2(curandStateMRG32k3a_t *state, float mean, float stddev) +{ + float2 v = curand_box_muller_mrg(state); + v.x = expf(mean + (stddev * v.x)); + v.y = expf(mean + (stddev * v.y)); + return v; +} + +/** + * \brief Return a log-normally distributed float from an MTGP32 generator. + * + * Return a single log-normally distributed float derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the MTGP32 generator in \p state, + * increment position of generator. + * + * The implementation uses the inverse cumulative distribution function + * to generate a normally distributed result, then transforms the result + * to log-normal. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float curand_log_normal(curandStateMtgp32_t *state, float mean, float stddev) +{ + return expf(mean + (stddev * _curand_normal_icdf(curand(state)))); +} + +/** + * \brief Return a log-normally distributed float from a Sobol32 generator. + * + * Return a single log-normally distributed float derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Sobol32 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate a normally distributed result, then transforms the result + * to log-normal. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float curand_log_normal(curandStateSobol32_t *state, float mean, float stddev) +{ + return expf(mean + (stddev * _curand_normal_icdf(curand(state)))); +} +/** + * \brief Return a log-normally distributed float from a scrambled Sobol32 generator. + * + * Return a single log-normally distributed float derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the scrambled Sobol32 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate a normally distributed result, then transforms the result + * to log-normal. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float curand_log_normal(curandStateScrambledSobol32_t *state, float mean, float stddev) +{ + return expf(mean + (stddev * _curand_normal_icdf(curand(state)))); +} + +/** + * \brief Return a log-normally distributed float from a Sobol64 generator. + * + * Return a single log-normally distributed float derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Sobol64 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results, then converts to log-normal + * distribution. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float curand_log_normal(curandStateSobol64_t *state, float mean, float stddev) +{ + return expf(mean + (stddev * _curand_normal_icdf(curand(state)))); +} + +/** + * \brief Return a log-normally distributed float from a scrambled Sobol64 generator. + * + * Return a single log-normally distributed float derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the scrambled Sobol64 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results, then converts to log-normal + * distribution. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed float with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS float curand_log_normal(curandStateScrambledSobol64_t *state, float mean, float stddev) +{ + return expf(mean + (stddev * _curand_normal_icdf(curand(state)))); +} + +/** + * \brief Return a log-normally distributed double from an XORWOW generator. + * + * Return a single normally distributed double derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the XORWOW generator in \p state, + * increment position of generator. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, transforms them to log-normal distribution, + * then returns them one at a time. + * See ::curand_log_normal2_double() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double with mean \p mean and standard deviation \p stddev + */ + +QUALIFIERS double curand_log_normal_double(curandStateXORWOW_t *state, double mean, double stddev) +{ + if(state->boxmuller_flag_double != EXTRA_FLAG_LOG_NORMAL) { + unsigned int x0, x1, y0, y1; + x0 = curand(state); + x1 = curand(state); + y0 = curand(state); + y1 = curand(state); + double2 v = _curand_box_muller_double(x0, x1, y0, y1); + state->boxmuller_extra_double = exp(mean + (stddev * v.y)); + state->boxmuller_flag_double = EXTRA_FLAG_LOG_NORMAL; + return exp(mean + (stddev * v.x)); + } + state->boxmuller_flag_double = 0; + return state->boxmuller_extra_double; +} + +/** + * \brief Return a log-normally distributed double from an Philox4_32_10 generator. + * + * Return a single normally distributed double derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Philox4_32_10 generator in \p state, + * increment position of generator. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, transforms them to log-normal distribution, + * then returns them one at a time. + * See ::curand_log_normal2_double() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double with mean \p mean and standard deviation \p stddev + */ + +QUALIFIERS double curand_log_normal_double(curandStatePhilox4_32_10_t *state, double mean, double stddev) +{ + if(state->boxmuller_flag_double != EXTRA_FLAG_LOG_NORMAL) { + uint4 _x; + _x = curand4(state); + double2 v = _curand_box_muller_double(_x.x, _x.y, _x.z, _x.w); + state->boxmuller_extra_double = exp(mean + (stddev * v.y)); + state->boxmuller_flag_double = EXTRA_FLAG_LOG_NORMAL; + return exp(mean + (stddev * v.x)); + } + state->boxmuller_flag_double = 0; + return state->boxmuller_extra_double; +} + + +/** + * \brief Return two log-normally distributed doubles from an XORWOW generator. + * + * Return two log-normally distributed doubles derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the XORWOW generator in \p state, + * increment position of generator by two. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, and transforms them to log-normal distribution,. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double2 where each element is from a + * distribution with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double2 curand_log_normal2_double(curandStateXORWOW_t *state, double mean, double stddev) +{ + double2 v = curand_box_muller_double(state); + v.x = exp(mean + (stddev * v.x)); + v.y = exp(mean + (stddev * v.y)); + return v; +} + +/** + * \brief Return two log-normally distributed doubles from an Philox4_32_10 generator. + * + * Return two log-normally distributed doubles derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Philox4_32_10 generator in \p state, + * increment position of generator by four. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, and transforms them to log-normal distribution,. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double4 where each element is from a + * distribution with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double2 curand_log_normal2_double(curandStatePhilox4_32_10_t *state, double mean, double stddev) +{ + double2 v = curand_box_muller2_double(state); + v.x = exp(mean + (stddev * v.x)); + v.y = exp(mean + (stddev * v.y)); + return v; +} +// nor part of API +QUALIFIERS double4 curand_log_normal4_double(curandStatePhilox4_32_10_t *state, double mean, double stddev) +{ + double4 v = curand_box_muller4_double(state); + v.x = exp(mean + (stddev * v.x)); + v.y = exp(mean + (stddev * v.y)); + v.z = exp(mean + (stddev * v.z)); + v.w = exp(mean + (stddev * v.w)); + return v; +} + +/** + * \brief Return a log-normally distributed double from an MRG32k3a generator. + * + * Return a single normally distributed double derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the MRG32k3a generator in \p state, + * increment position of generator. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, transforms them to log-normal distribution, + * then returns them one at a time. + * See ::curand_log_normal2_double() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double curand_log_normal_double(curandStateMRG32k3a_t *state, double mean, double stddev) +{ + if(state->boxmuller_flag_double != EXTRA_FLAG_LOG_NORMAL) { + double2 v = curand_box_muller_mrg_double(state); + state->boxmuller_extra_double = exp(mean + (stddev * v.y)); + state->boxmuller_flag_double = EXTRA_FLAG_LOG_NORMAL; + return exp(mean + (stddev * v.x)); + } + state->boxmuller_flag_double = 0; + return state->boxmuller_extra_double; +} + +/** + * \brief Return two log-normally distributed doubles from an MRG32k3a generator. + * + * Return two log-normally distributed doubles derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the MRG32k3a generator in \p state, + * increment position of generator by two. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, and transforms them to log-normal distribution,. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double2 where each element is from a + * distribution with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double2 curand_log_normal2_double(curandStateMRG32k3a_t *state, double mean, double stddev) +{ + double2 v = curand_box_muller_mrg_double(state); + v.x = exp(mean + (stddev * v.x)); + v.y = exp(mean + (stddev * v.y)); + return v; +} + +/** + * \brief Return a log-normally distributed double from an MTGP32 generator. + * + * Return a single log-normally distributed double derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the MTGP32 generator in \p state, + * increment position of generator. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results, and transforms them into + * log-normal distribution. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double curand_log_normal_double(curandStateMtgp32_t *state, double mean, double stddev) +{ + return exp(mean + (stddev * _curand_normal_icdf_double(curand(state)))); +} + +/** + * \brief Return a log-normally distributed double from a Sobol32 generator. + * + * Return a single log-normally distributed double derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Sobol32 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results, and transforms them into + * log-normal distribution. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double curand_log_normal_double(curandStateSobol32_t *state, double mean, double stddev) +{ + return exp(mean + (stddev * _curand_normal_icdf_double(curand(state)))); +} + +/** + * \brief Return a log-normally distributed double from a scrambled Sobol32 generator. + * + * Return a single log-normally distributed double derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the scrambled Sobol32 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results, and transforms them into + * log-normal distribution. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double curand_log_normal_double(curandStateScrambledSobol32_t *state, double mean, double stddev) +{ + return exp(mean + (stddev * _curand_normal_icdf_double(curand(state)))); +} + +/** + * \brief Return a log-normally distributed double from a Sobol64 generator. + * + * Return a single normally distributed double derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the Sobol64 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double curand_log_normal_double(curandStateSobol64_t *state, double mean, double stddev) +{ + return exp(mean + (stddev * _curand_normal_icdf_double(curand(state)))); +} + +/** + * \brief Return a log-normally distributed double from a scrambled Sobol64 generator. + * + * Return a single normally distributed double derived from a normal + * distribution with mean \p mean and standard deviation \p stddev + * from the scrambled Sobol64 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * \param mean - Mean of the related normal distribution + * \param stddev - Standard deviation of the related normal distribution + * + * \return Log-normally distributed double with mean \p mean and standard deviation \p stddev + */ +QUALIFIERS double curand_log_normal_double(curandStateScrambledSobol64_t *state, double mean, double stddev) +{ + return exp(mean + (stddev * _curand_normal_icdf_double(curand(state)))); +} + +#endif // !defined(CURAND_LOGNORMAL_H_) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mrg32k3a.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mrg32k3a.h new file mode 100644 index 0000000000000000000000000000000000000000..a052a9c3b3f45dcf1d7d0369d0d62d8c4719e3ee --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mrg32k3a.h @@ -0,0 +1,3721 @@ +/* + * Copyright 2010-2018 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ +#if !defined(CURAND_MRG32K3A_MATRICES_H_) +#define CURAND_MRG32K3A_MATRICES_H_ + +#if defined(__CUDACC_RDC__) && (__cplusplus >= 201703L) && defined(__cpp_inline_variables) +#define CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS inline __device__ +#else +#define CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS static __device__ +#endif + +#if (__cplusplus >= 201703L) && defined(__cpp_inline_variables) +#define CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS inline +#else +#define CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS static +#endif + + /* base matrices */ + + /* these are not actually used in the runtime code. They are */ + /* used in computing the skipahead matrices, and are included */ + /* for reference */ + /* + double M1[3][3] = { 0., 1., 0., + 0., 0., 1., + -810728., 1403580., 0. }; + + double M2[3][3] = { 0., 1., 0., + 0., 0., 1., + -1370589., 0., 527612. }; + + */ + + /* Base matrices to power 2 to the power n, n the first array index, from 0..63 */ +CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS unsigned int mrg32k3aM1[64][3][3] = { + { + { 0u, 1u, 0u }, + { 0u, 0u, 1u }, + { 4294156359u, 1403580u, 0u } + }, + { + { 0u, 0u, 1u }, + { 4294156359u, 1403580u, 0u }, + { 0u, 4294156359u, 1403580u } + }, + { + { 0u, 4294156359u, 1403580u }, + { 244671815u, 2941890554u, 4294156359u }, + { 149925673u, 489343630u, 2941890554u } + }, + { + { 1527363550u, 2758233149u, 1831234280u }, + { 4072640363u, 939574583u, 2758233149u }, + { 2064391165u, 3228066636u, 939574583u } + }, + { + { 736416029u, 2961816100u, 342112271u }, + { 387300998u, 1062452522u, 2961816100u }, + { 2955879160u, 340793741u, 1062452522u } + }, + { + { 1243502014u, 2218748291u, 1709215645u }, + { 2019641772u, 3847560959u, 2218748291u }, + { 3866010231u, 2305448679u, 3847560959u } + }, + { + { 3241775219u, 3453352062u, 3721871040u }, + { 4062454730u, 3015754u, 3453352062u }, + { 919711945u, 613405362u, 3015754u } + }, + { + { 1955221006u, 1414472808u, 1746037714u }, + { 3653507277u, 1644962013u, 1414472808u }, + { 3501544776u, 2336229602u, 1644962013u } + }, + { + { 1170096663u, 49135452u, 3441537107u }, + { 1857945175u, 1649398389u, 49135452u }, + { 333002869u, 3109147376u, 1649398389u } + }, + { + { 2299034194u, 2297111910u, 862649200u }, + { 1399961132u, 996706937u, 2297111910u }, + { 3439056503u, 1481993076u, 996706937u } + }, + { + { 4146310528u, 458782589u, 1007330283u }, + { 4241015765u, 3979619964u, 458782589u }, + { 553886495u, 2186897562u, 3979619964u } + }, + { + { 3630027893u, 2130448350u, 292773857u }, + { 1392525159u, 1299285967u, 2130448350u }, + { 2589171163u, 1217405758u, 1299285967u } + }, + { + { 892409263u, 1999175811u, 2979225418u }, + { 1996163538u, 2148702503u, 1999175811u }, + { 3922720782u, 103819730u, 2148702503u } + }, + { + { 1586003016u, 2114210471u, 3240775579u }, + { 2777288607u, 1400478398u, 2114210471u }, + { 3018215420u, 535326008u, 1400478398u } + }, + { + { 2188531273u, 1783231160u, 3576659343u }, + { 1908318389u, 379210133u, 1783231160u }, + { 554369329u, 250053591u, 379210133u } + }, + { + { 4022841636u, 3951951872u, 2143424240u }, + { 1046219306u, 1591992468u, 3951951872u }, + { 1510277444u, 381333958u, 1591992468u } + }, + { + { 2256493727u, 3715182130u, 642697923u }, + { 3615342722u, 3975008370u, 3715182130u }, + { 2405650329u, 754337639u, 3975008370u } + }, + { + { 1286664224u, 627406673u, 963516608u }, + { 1541344588u, 460768826u, 627406673u }, + { 1089892553u, 2717717970u, 460768826u } + }, + { + { 2956342842u, 3471097641u, 2353092905u }, + { 2996150472u, 420480221u, 3471097641u }, + { 2221681883u, 372736411u, 420480221u } + }, + { + { 420492906u, 153526651u, 3499730988u }, + { 2662640502u, 3278195133u, 153526651u }, + { 4086436419u, 2510762118u, 3278195133u } + }, + { + { 3310184147u, 2228376089u, 823220763u }, + { 3992771814u, 1693168425u, 2228376089u }, + { 2295790366u, 1401872772u, 1693168425u } + }, + { + { 2529428830u, 1497104068u, 4253248635u }, + { 3746310018u, 630867741u, 1497104068u }, + { 627043435u, 721725795u, 630867741u } + }, + { + { 2571072593u, 3039669025u, 1591031831u }, + { 526054481u, 661344445u, 3039669025u }, + { 4246010312u, 735391270u, 661344445u } + }, + { + { 1847312821u, 4042890210u, 4241772463u }, + { 606605705u, 2644799309u, 4042890210u }, + { 2658402822u, 1342278931u, 2644799309u } + }, + { + { 2409846784u, 1096138313u, 1416249993u }, + { 1501878241u, 138013862u, 1096138313u }, + { 1617749306u, 1975136163u, 138013862u } + }, + { + { 599453422u, 73950522u, 2965395603u }, + { 55354701u, 3855242202u, 73950522u }, + { 3981734504u, 3354399019u, 3855242202u } + }, + { + { 4271076381u, 813410089u, 3461955319u }, + { 1044920137u, 3029005516u, 813410089u }, + { 3501837362u, 3321539504u, 3029005516u } + }, + { + { 3058183515u, 941408572u, 1783998098u }, + { 1546486080u, 4116985007u, 941408572u }, + { 2247500745u, 1460625377u, 4116985007u } + }, + { + { 4216782514u, 3352801941u, 2315095646u }, + { 639029973u, 94451952u, 3352801941u }, + { 1242898773u, 3964593332u, 94451952u } + }, + { + { 2264905138u, 1926285644u, 1108147171u }, + { 2390706911u, 385258225u, 1926285644u }, + { 3569882325u, 3728744670u, 385258225u } + }, + { + { 270679073u, 1065683096u, 2992662885u }, + { 4196917281u, 2886425156u, 1065683096u }, + { 749134119u, 1849148167u, 2886425156u } + }, + { + { 35689930u, 1378151623u, 951629713u }, + { 673810920u, 948843427u, 1378151623u }, + { 3808868984u, 927013635u, 948843427u } + }, + { + { 1891490872u, 1130489594u, 3734864133u }, + { 1457450350u, 3362920032u, 1130489594u }, + { 638998846u, 1401175590u, 3362920032u } + }, + { + { 2254459023u, 2384691454u, 1730098031u }, + { 2844861718u, 1807491073u, 2384691454u }, + { 351423668u, 1570264155u, 1807491073u } + }, + { + { 3047429268u, 4245359555u, 2449575498u }, + { 1797081212u, 1237196477u, 4245359555u }, + { 143400628u, 3663731096u, 1237196477u } + }, + { + { 3313321106u, 4263819658u, 1047529624u }, + { 3719941673u, 3155049403u, 4263819658u }, + { 1981313839u, 4281524426u, 3155049403u } + }, + { + { 2005252417u, 3263186729u, 1535805957u }, + { 2951515865u, 1729281525u, 3263186729u }, + { 1141249417u, 2268963059u, 1729281525u } + }, + { + { 2367065164u, 83908466u, 4294308508u }, + { 1352516724u, 1416676049u, 83908466u }, + { 1040867745u, 1304732377u, 1416676049u } + }, + { + { 3214147257u, 1434230503u, 2944821434u }, + { 2753040912u, 4041536918u, 1434230503u }, + { 1317260239u, 338830578u, 4041536918u } + }, + { + { 300628476u, 2054743463u, 1499597869u }, + { 1762244284u, 1422043015u, 2054743463u }, + { 3581125669u, 1207561803u, 1422043015u } + }, + { + { 4171745404u, 4064983592u, 1934508265u }, + { 3049723261u, 1744636487u, 4064983592u }, + { 947753516u, 3952135907u, 1744636487u } + }, + { + { 1625369148u, 3577024659u, 2778677259u }, + { 1729967818u, 1049600974u, 3577024659u }, + { 2089137344u, 1569794605u, 1049600974u } + }, + { + { 1373068765u, 3958611830u, 569117280u }, + { 410042396u, 3551255470u, 3958611830u }, + { 869476379u, 1680625376u, 3551255470u } + }, + { + { 2108618602u, 2543645250u, 913717833u }, + { 2111984988u, 1012482542u, 2543645250u }, + { 2545745615u, 3141042890u, 1012482542u } + }, + { + { 1157293598u, 584852249u, 2272893205u }, + { 1631801979u, 3013855247u, 584852249u }, + { 3977310441u, 82049263u, 3013855247u } + }, + { + { 3580234334u, 3137526662u, 2403875621u }, + { 3580869206u, 3670086228u, 3137526662u }, + { 656744553u, 1764904195u, 3670086228u } + }, + { + { 2792496861u, 3634185196u, 3887031679u }, + { 3601823850u, 3464838365u, 3634185196u }, + { 3136165138u, 2842987937u, 3464838365u } + }, + { + { 1362557480u, 3230022138u, 4278720212u }, + { 3427386258u, 3848976950u, 3230022138u }, + { 2109817045u, 2441486578u, 3848976950u } + }, + { + { 1198519135u, 2007945401u, 3868481u }, + { 3335076429u, 2082683147u, 2007945401u }, + { 2341088247u, 888193479u, 2082683147u } + }, + { + { 3473925387u, 3193380570u, 565138859u }, + { 307060547u, 782210925u, 3193380570u }, + { 167617770u, 2180014252u, 782210925u } + }, + { + { 3811588895u, 3303532086u, 2766583698u }, + { 908630605u, 2665400165u, 3303532086u }, + { 2499994113u, 3316180851u, 2665400165u } + }, + { + { 4288926968u, 3033075037u, 1505732852u }, + { 1531633406u, 645804125u, 3033075037u }, + { 2942690261u, 2205365640u, 645804125u } + }, + { + { 3976196483u, 3651411522u, 1652430357u }, + { 1690405883u, 1294990760u, 3651411522u }, + { 209339647u, 3088484327u, 1294990760u } + }, + { + { 3171589548u, 2291131070u, 2093793287u }, + { 2997812074u, 4093879780u, 2291131070u }, + { 3255666800u, 858124816u, 4093879780u } + }, + { + { 4113016361u, 2999667479u, 3995043314u }, + { 1333973326u, 4007774239u, 2999667479u }, + { 3322921863u, 4278103786u, 4007774239u } + }, + { + { 925786347u, 2109676036u, 1879981040u }, + { 1701566570u, 1489702270u, 2109676036u }, + { 2719807628u, 158549605u, 1489702270u } + }, + { + { 2255405265u, 3460246357u, 218033453u }, + { 2135115875u, 359516994u, 3460246357u }, + { 3568862459u, 3114762683u, 359516994u } + }, + { + { 773148471u, 4117539411u, 3073622315u }, + { 3807175775u, 186466108u, 4117539411u }, + { 2842197411u, 651334129u, 186466108u } + }, + { + { 615242951u, 1475251263u, 3586439101u }, + { 1693917167u, 3058812486u, 1475251263u }, + { 568701600u, 1164226398u, 3058812486u } + }, + { + { 1632636204u, 15370275u, 2061555515u }, + { 4187505695u, 1741164221u, 15370275u }, + { 2882176274u, 3978412194u, 1741164221u } + }, + { + { 3446066703u, 344820524u, 74213775u }, + { 1008543583u, 2579620192u, 344820524u }, + { 3753911358u, 1538453821u, 2579620192u } + }, + { + { 3600859892u, 1269921024u, 4069458760u }, + { 2050939727u, 2222725697u, 1269921024u }, + { 3208347646u, 690898125u, 2222725697u } + }, + { + { 599407451u, 2806239788u, 1742216102u }, + { 975123999u, 764869161u, 2806239788u }, + { 2729710367u, 1845257036u, 764869161u } + }, + { + { 967330218u, 3464884028u, 3444447102u }, + { 580449578u, 1343714307u, 3464884028u }, + { 1775329096u, 4027221761u, 1343714307u } + } + }; + +#ifndef __CUDACC_RTC__ +CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS unsigned int mrg32k3aM1Host[64][3][3] = { + { + { 0u, 1u, 0u }, + { 0u, 0u, 1u }, + { 4294156359u, 1403580u, 0u } + }, + { + { 0u, 0u, 1u }, + { 4294156359u, 1403580u, 0u }, + { 0u, 4294156359u, 1403580u } + }, + { + { 0u, 4294156359u, 1403580u }, + { 244671815u, 2941890554u, 4294156359u }, + { 149925673u, 489343630u, 2941890554u } + }, + { + { 1527363550u, 2758233149u, 1831234280u }, + { 4072640363u, 939574583u, 2758233149u }, + { 2064391165u, 3228066636u, 939574583u } + }, + { + { 736416029u, 2961816100u, 342112271u }, + { 387300998u, 1062452522u, 2961816100u }, + { 2955879160u, 340793741u, 1062452522u } + }, + { + { 1243502014u, 2218748291u, 1709215645u }, + { 2019641772u, 3847560959u, 2218748291u }, + { 3866010231u, 2305448679u, 3847560959u } + }, + { + { 3241775219u, 3453352062u, 3721871040u }, + { 4062454730u, 3015754u, 3453352062u }, + { 919711945u, 613405362u, 3015754u } + }, + { + { 1955221006u, 1414472808u, 1746037714u }, + { 3653507277u, 1644962013u, 1414472808u }, + { 3501544776u, 2336229602u, 1644962013u } + }, + { + { 1170096663u, 49135452u, 3441537107u }, + { 1857945175u, 1649398389u, 49135452u }, + { 333002869u, 3109147376u, 1649398389u } + }, + { + { 2299034194u, 2297111910u, 862649200u }, + { 1399961132u, 996706937u, 2297111910u }, + { 3439056503u, 1481993076u, 996706937u } + }, + { + { 4146310528u, 458782589u, 1007330283u }, + { 4241015765u, 3979619964u, 458782589u }, + { 553886495u, 2186897562u, 3979619964u } + }, + { + { 3630027893u, 2130448350u, 292773857u }, + { 1392525159u, 1299285967u, 2130448350u }, + { 2589171163u, 1217405758u, 1299285967u } + }, + { + { 892409263u, 1999175811u, 2979225418u }, + { 1996163538u, 2148702503u, 1999175811u }, + { 3922720782u, 103819730u, 2148702503u } + }, + { + { 1586003016u, 2114210471u, 3240775579u }, + { 2777288607u, 1400478398u, 2114210471u }, + { 3018215420u, 535326008u, 1400478398u } + }, + { + { 2188531273u, 1783231160u, 3576659343u }, + { 1908318389u, 379210133u, 1783231160u }, + { 554369329u, 250053591u, 379210133u } + }, + { + { 4022841636u, 3951951872u, 2143424240u }, + { 1046219306u, 1591992468u, 3951951872u }, + { 1510277444u, 381333958u, 1591992468u } + }, + { + { 2256493727u, 3715182130u, 642697923u }, + { 3615342722u, 3975008370u, 3715182130u }, + { 2405650329u, 754337639u, 3975008370u } + }, + { + { 1286664224u, 627406673u, 963516608u }, + { 1541344588u, 460768826u, 627406673u }, + { 1089892553u, 2717717970u, 460768826u } + }, + { + { 2956342842u, 3471097641u, 2353092905u }, + { 2996150472u, 420480221u, 3471097641u }, + { 2221681883u, 372736411u, 420480221u } + }, + { + { 420492906u, 153526651u, 3499730988u }, + { 2662640502u, 3278195133u, 153526651u }, + { 4086436419u, 2510762118u, 3278195133u } + }, + { + { 3310184147u, 2228376089u, 823220763u }, + { 3992771814u, 1693168425u, 2228376089u }, + { 2295790366u, 1401872772u, 1693168425u } + }, + { + { 2529428830u, 1497104068u, 4253248635u }, + { 3746310018u, 630867741u, 1497104068u }, + { 627043435u, 721725795u, 630867741u } + }, + { + { 2571072593u, 3039669025u, 1591031831u }, + { 526054481u, 661344445u, 3039669025u }, + { 4246010312u, 735391270u, 661344445u } + }, + { + { 1847312821u, 4042890210u, 4241772463u }, + { 606605705u, 2644799309u, 4042890210u }, + { 2658402822u, 1342278931u, 2644799309u } + }, + { + { 2409846784u, 1096138313u, 1416249993u }, + { 1501878241u, 138013862u, 1096138313u }, + { 1617749306u, 1975136163u, 138013862u } + }, + { + { 599453422u, 73950522u, 2965395603u }, + { 55354701u, 3855242202u, 73950522u }, + { 3981734504u, 3354399019u, 3855242202u } + }, + { + { 4271076381u, 813410089u, 3461955319u }, + { 1044920137u, 3029005516u, 813410089u }, + { 3501837362u, 3321539504u, 3029005516u } + }, + { + { 3058183515u, 941408572u, 1783998098u }, + { 1546486080u, 4116985007u, 941408572u }, + { 2247500745u, 1460625377u, 4116985007u } + }, + { + { 4216782514u, 3352801941u, 2315095646u }, + { 639029973u, 94451952u, 3352801941u }, + { 1242898773u, 3964593332u, 94451952u } + }, + { + { 2264905138u, 1926285644u, 1108147171u }, + { 2390706911u, 385258225u, 1926285644u }, + { 3569882325u, 3728744670u, 385258225u } + }, + { + { 270679073u, 1065683096u, 2992662885u }, + { 4196917281u, 2886425156u, 1065683096u }, + { 749134119u, 1849148167u, 2886425156u } + }, + { + { 35689930u, 1378151623u, 951629713u }, + { 673810920u, 948843427u, 1378151623u }, + { 3808868984u, 927013635u, 948843427u } + }, + { + { 1891490872u, 1130489594u, 3734864133u }, + { 1457450350u, 3362920032u, 1130489594u }, + { 638998846u, 1401175590u, 3362920032u } + }, + { + { 2254459023u, 2384691454u, 1730098031u }, + { 2844861718u, 1807491073u, 2384691454u }, + { 351423668u, 1570264155u, 1807491073u } + }, + { + { 3047429268u, 4245359555u, 2449575498u }, + { 1797081212u, 1237196477u, 4245359555u }, + { 143400628u, 3663731096u, 1237196477u } + }, + { + { 3313321106u, 4263819658u, 1047529624u }, + { 3719941673u, 3155049403u, 4263819658u }, + { 1981313839u, 4281524426u, 3155049403u } + }, + { + { 2005252417u, 3263186729u, 1535805957u }, + { 2951515865u, 1729281525u, 3263186729u }, + { 1141249417u, 2268963059u, 1729281525u } + }, + { + { 2367065164u, 83908466u, 4294308508u }, + { 1352516724u, 1416676049u, 83908466u }, + { 1040867745u, 1304732377u, 1416676049u } + }, + { + { 3214147257u, 1434230503u, 2944821434u }, + { 2753040912u, 4041536918u, 1434230503u }, + { 1317260239u, 338830578u, 4041536918u } + }, + { + { 300628476u, 2054743463u, 1499597869u }, + { 1762244284u, 1422043015u, 2054743463u }, + { 3581125669u, 1207561803u, 1422043015u } + }, + { + { 4171745404u, 4064983592u, 1934508265u }, + { 3049723261u, 1744636487u, 4064983592u }, + { 947753516u, 3952135907u, 1744636487u } + }, + { + { 1625369148u, 3577024659u, 2778677259u }, + { 1729967818u, 1049600974u, 3577024659u }, + { 2089137344u, 1569794605u, 1049600974u } + }, + { + { 1373068765u, 3958611830u, 569117280u }, + { 410042396u, 3551255470u, 3958611830u }, + { 869476379u, 1680625376u, 3551255470u } + }, + { + { 2108618602u, 2543645250u, 913717833u }, + { 2111984988u, 1012482542u, 2543645250u }, + { 2545745615u, 3141042890u, 1012482542u } + }, + { + { 1157293598u, 584852249u, 2272893205u }, + { 1631801979u, 3013855247u, 584852249u }, + { 3977310441u, 82049263u, 3013855247u } + }, + { + { 3580234334u, 3137526662u, 2403875621u }, + { 3580869206u, 3670086228u, 3137526662u }, + { 656744553u, 1764904195u, 3670086228u } + }, + { + { 2792496861u, 3634185196u, 3887031679u }, + { 3601823850u, 3464838365u, 3634185196u }, + { 3136165138u, 2842987937u, 3464838365u } + }, + { + { 1362557480u, 3230022138u, 4278720212u }, + { 3427386258u, 3848976950u, 3230022138u }, + { 2109817045u, 2441486578u, 3848976950u } + }, + { + { 1198519135u, 2007945401u, 3868481u }, + { 3335076429u, 2082683147u, 2007945401u }, + { 2341088247u, 888193479u, 2082683147u } + }, + { + { 3473925387u, 3193380570u, 565138859u }, + { 307060547u, 782210925u, 3193380570u }, + { 167617770u, 2180014252u, 782210925u } + }, + { + { 3811588895u, 3303532086u, 2766583698u }, + { 908630605u, 2665400165u, 3303532086u }, + { 2499994113u, 3316180851u, 2665400165u } + }, + { + { 4288926968u, 3033075037u, 1505732852u }, + { 1531633406u, 645804125u, 3033075037u }, + { 2942690261u, 2205365640u, 645804125u } + }, + { + { 3976196483u, 3651411522u, 1652430357u }, + { 1690405883u, 1294990760u, 3651411522u }, + { 209339647u, 3088484327u, 1294990760u } + }, + { + { 3171589548u, 2291131070u, 2093793287u }, + { 2997812074u, 4093879780u, 2291131070u }, + { 3255666800u, 858124816u, 4093879780u } + }, + { + { 4113016361u, 2999667479u, 3995043314u }, + { 1333973326u, 4007774239u, 2999667479u }, + { 3322921863u, 4278103786u, 4007774239u } + }, + { + { 925786347u, 2109676036u, 1879981040u }, + { 1701566570u, 1489702270u, 2109676036u }, + { 2719807628u, 158549605u, 1489702270u } + }, + { + { 2255405265u, 3460246357u, 218033453u }, + { 2135115875u, 359516994u, 3460246357u }, + { 3568862459u, 3114762683u, 359516994u } + }, + { + { 773148471u, 4117539411u, 3073622315u }, + { 3807175775u, 186466108u, 4117539411u }, + { 2842197411u, 651334129u, 186466108u } + }, + { + { 615242951u, 1475251263u, 3586439101u }, + { 1693917167u, 3058812486u, 1475251263u }, + { 568701600u, 1164226398u, 3058812486u } + }, + { + { 1632636204u, 15370275u, 2061555515u }, + { 4187505695u, 1741164221u, 15370275u }, + { 2882176274u, 3978412194u, 1741164221u } + }, + { + { 3446066703u, 344820524u, 74213775u }, + { 1008543583u, 2579620192u, 344820524u }, + { 3753911358u, 1538453821u, 2579620192u } + }, + { + { 3600859892u, 1269921024u, 4069458760u }, + { 2050939727u, 2222725697u, 1269921024u }, + { 3208347646u, 690898125u, 2222725697u } + }, + { + { 599407451u, 2806239788u, 1742216102u }, + { 975123999u, 764869161u, 2806239788u }, + { 2729710367u, 1845257036u, 764869161u } + }, + { + { 967330218u, 3464884028u, 3444447102u }, + { 580449578u, 1343714307u, 3464884028u }, + { 1775329096u, 4027221761u, 1343714307u } + } + }; +#endif // ifndef __CUDACC_RTC__ + +CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS unsigned int mrg32k3aM2[64][3][3] = { + { + { 0u, 1u, 0u }, + { 0u, 0u, 1u }, + { 4293573854u, 0u, 527612u } + }, + { + { 0u, 0u, 1u }, + { 4293573854u, 0u, 527612u }, + { 2706407399u, 4293573854u, 3497978192u } + }, + { + { 2706407399u, 4293573854u, 3497978192u }, + { 1431525864u, 2706407399u, 3281754271u }, + { 97673890u, 1431525864u, 1673476130u } + }, + { + { 3405842137u, 2680076935u, 893509979u }, + { 4035147174u, 3405842137u, 3280220074u }, + { 2623373296u, 4035147174u, 361718588u } + }, + { + { 818368950u, 3790774567u, 3542344109u }, + { 1817134745u, 818368950u, 3321940838u }, + { 3493477402u, 1817134745u, 2854655037u } + }, + { + { 498682467u, 2928649385u, 811441367u }, + { 1777037472u, 498682467u, 479207863u }, + { 3058260025u, 1777037472u, 1528225099u } + }, + { + { 3893311647u, 3140922085u, 64039185u }, + { 82107183u, 3893311647u, 2655465224u }, + { 1674879036u, 82107183u, 1089381262u } + }, + { + { 28639152u, 3496041927u, 2231910770u }, + { 3174683233u, 28639152u, 2828785870u }, + { 3681140872u, 3174683233u, 3910194649u } + }, + { + { 1463826069u, 300842059u, 3313769518u }, + { 1799677538u, 1463826069u, 3174861078u }, + { 1882279394u, 1799677538u, 3509975160u } + }, + { + { 2092194020u, 184076987u, 2202401252u }, + { 3103629604u, 2092194020u, 3409560232u }, + { 4257445059u, 3103629604u, 2390202783u } + }, + { + { 812917091u, 2574011276u, 4168802395u }, + { 209817750u, 812917091u, 2974870628u }, + { 3238802184u, 209817750u, 3692836406u } + }, + { + { 477309738u, 3314523413u, 3442242150u }, + { 2755731404u, 477309738u, 2782713347u }, + { 1606221490u, 2755731404u, 1033463096u } + }, + { + { 2155469603u, 3326516116u, 3843369786u }, + { 288604458u, 2155469603u, 571673571u }, + { 1501677614u, 288604458u, 2928213494u } + }, + { + { 2082469029u, 749754403u, 3963963316u }, + { 2764859700u, 2082469029u, 3576428059u }, + { 2840894706u, 2764859700u, 1782279859u } + }, + { + { 3760163766u, 1041986082u, 1799196192u }, + { 1022129134u, 3760163766u, 1332558840u }, + { 276873446u, 1022129134u, 3979423632u } + }, + { + { 1021313167u, 1312544548u, 1716381787u }, + { 3037868518u, 1021313167u, 199085085u }, + { 2582787611u, 3037868518u, 3539882179u } + }, + { + { 2569413030u, 1631336015u, 2594942403u }, + { 1030618503u, 2569413030u, 3467650326u }, + { 1998739584u, 1030618503u, 3174552073u } + }, + { + { 2334639309u, 3114094203u, 601680947u }, + { 2110199318u, 2334639309u, 678342865u }, + { 1649523168u, 2110199318u, 2154948056u } + }, + { + { 563657176u, 191330473u, 1641595774u }, + { 780563537u, 563657176u, 3029522338u }, + { 2037330914u, 780563537u, 2084602709u } + }, + { + { 3414769923u, 1968799026u, 2238126504u }, + { 832866376u, 3414769923u, 3754780168u }, + { 2165145850u, 832866376u, 1594768331u } + }, + { + { 1646861218u, 2317984620u, 2301581548u }, + { 2672536210u, 1646861218u, 359763062u }, + { 2391283983u, 2672536210u, 1885870777u } + }, + { + { 841254072u, 3765813448u, 1635365181u }, + { 2013240130u, 841254072u, 605925849u }, + { 3743932305u, 2013240130u, 400681955u } + }, + { + { 1930213004u, 2072952279u, 3077694794u }, + { 3579956569u, 1930213004u, 2478539210u }, + { 1960229502u, 3579956569u, 1455652656u } + }, + { + { 1097613522u, 1784540933u, 1194440107u }, + { 321747515u, 1097613522u, 1225209584u }, + { 74521379u, 321747515u, 4288531000u } + }, + { + { 143812745u, 3254530816u, 3514348856u }, + { 769295000u, 143812745u, 2468210728u }, + { 1927161272u, 769295000u, 522705580u } + }, + { + { 2692035063u, 2596905012u, 1643240704u }, + { 1103432342u, 2692035063u, 1446182108u }, + { 4161111774u, 1103432342u, 3076435551u } + }, + { + { 2375319030u, 1391532370u, 3742334018u }, + { 1202100604u, 2375319030u, 4098434768u }, + { 2327872488u, 1202100604u, 1471526950u } + }, + { + { 4269164791u, 2795313144u, 2507855960u }, + { 4245372460u, 4269164791u, 4094914553u }, + { 3873219634u, 4245372460u, 1473695507u } + }, + { + { 513890845u, 1208902926u, 2870530442u }, + { 1984873167u, 513890845u, 1257532340u }, + { 1212627640u, 1984873167u, 2354363842u } + }, + { + { 1848364568u, 1552116673u, 3496528455u }, + { 4160778291u, 1848364568u, 141769900u }, + { 3611019106u, 4160778291u, 596424080u } + }, + { + { 364070020u, 3520039729u, 837362349u }, + { 2544671570u, 364070020u, 2188646679u }, + { 163978331u, 2544671570u, 672947816u } + }, + { + { 1192700714u, 3968150021u, 298357363u }, + { 635565666u, 1192700714u, 2589432341u }, + { 2548654227u, 635565666u, 3531570992u } + }, + { + { 2709640529u, 676525399u, 875361870u }, + { 1315499519u, 2709640529u, 3842690720u }, + { 3300994644u, 1315499519u, 2446760804u } + }, + { + { 2742149264u, 1410604392u, 3032350755u }, + { 3774935330u, 2742149264u, 597633965u }, + { 4085935803u, 3774935330u, 3952463556u } + }, + { + { 3878579563u, 845297523u, 1721916511u }, + { 2077922420u, 3878579563u, 3651360351u }, + { 2177255734u, 2077922420u, 3791239282u } + }, + { + { 1570315355u, 4252790045u, 3522351060u }, + { 2324624266u, 1570315355u, 3594939336u }, + { 1725087354u, 2324624266u, 1338343327u } + }, + { + { 2305761589u, 381933244u, 3663579047u }, + { 1355307047u, 2305761589u, 313617972u }, + { 992174375u, 1355307047u, 3881593435u } + }, + { + { 1667857811u, 1564715297u, 2263851601u }, + { 3791771273u, 1667857811u, 4196134923u }, + { 3347975047u, 3791771273u, 615040705u } + }, + { + { 4093947334u, 3454015638u, 2815567716u }, + { 4261953004u, 4093947334u, 3973733876u }, + { 2979573134u, 4261953004u, 3757047667u } + }, + { + { 250120061u, 570149551u, 1513430926u }, + { 3178644752u, 250120061u, 1701869032u }, + { 4172515680u, 3178644752u, 4213855850u } + }, + { + { 4158106802u, 3062358456u, 1815738463u }, + { 1379176112u, 4158106802u, 3926509890u }, + { 2842564878u, 1379176112u, 2852219546u } + }, + { + { 931848746u, 256263523u, 2633569246u }, + { 3284646837u, 931848746u, 2567084715u }, + { 415258465u, 3284646837u, 2017565947u } + }, + { + { 1648005210u, 1032291296u, 3987397422u }, + { 1831496020u, 1648005210u, 2829448427u }, + { 1821082272u, 1831496020u, 2917140265u } + }, + { + { 4161327077u, 489964129u, 3870847744u }, + { 1669447863u, 4161327077u, 4292947198u }, + { 1522417114u, 1669447863u, 2652286672u } + }, + { + { 1270934555u, 3136631324u, 505612043u }, + { 2981474723u, 1270934555u, 2528619024u }, + { 625182639u, 2981474723u, 1008985039u } + }, + { + { 280996820u, 143706137u, 3013099060u }, + { 1797675893u, 280996820u, 3743985508u }, + { 1123794455u, 1797675893u, 2460119169u } + }, + { + { 919218027u, 4154920441u, 1125672685u }, + { 3933041881u, 919218027u, 474242849u }, + { 564891116u, 3933041881u, 2263904321u } + }, + { + { 2920112852u, 1965329198u, 1177141043u }, + { 2135250851u, 2920112852u, 969184056u }, + { 296035385u, 2135250851u, 4267827987u } + }, + { + { 1481142942u, 4120754772u, 1088557292u }, + { 265491023u, 1481142942u, 2860005744u }, + { 301796252u, 265491023u, 1935975979u } + }, + { + { 2111859033u, 2813610100u, 1001476468u }, + { 73849832u, 2111859033u, 3980799998u }, + { 3330206241u, 73849832u, 1933943506u } + }, + { + { 1781286360u, 3661231931u, 3509383709u }, + { 2753158871u, 1781286360u, 3119883109u }, + { 3576525143u, 2753158871u, 551079002u } + }, + { + { 1185024844u, 587779104u, 1004942725u }, + { 3763632860u, 1185024844u, 947424568u }, + { 3811666068u, 3763632860u, 2352253462u } + }, + { + { 1310227170u, 218138208u, 3172947233u }, + { 766129426u, 1310227170u, 1808643264u }, + { 2226659371u, 766129426u, 3853798112u } + }, + { + { 2230902378u, 4243560874u, 2491962392u }, + { 3836629116u, 2230902378u, 3637515403u }, + { 2846140932u, 3836629116u, 3083355464u } + }, + { + { 999448569u, 1464488480u, 3344426626u }, + { 946166795u, 999448569u, 340856814u }, + { 3686999436u, 946166795u, 3231079441u } + }, + { + { 1226155368u, 3477563770u, 550006884u }, + { 2378667355u, 1226155368u, 1493409040u }, + { 260364836u, 2378667355u, 4133888397u } + }, + { + { 1277901832u, 310796286u, 2818511068u }, + { 3088910653u, 1277901832u, 3303406025u }, + { 2507911914u, 3088910653u, 3712928074u } + }, + { + { 481918378u, 339570348u, 1728801469u }, + { 1623163429u, 481918378u, 2209094694u }, + { 3146982514u, 1623163429u, 508445538u } + }, + { + { 3138921230u, 2381863183u, 1992357430u }, + { 1024510915u, 3138921230u, 2122851650u }, + { 1453455184u, 1024510915u, 941946604u } + }, + { + { 2465372719u, 1391015357u, 3328905025u }, + { 1821933605u, 2465372719u, 1343489680u }, + { 3648970313u, 1821933605u, 1816599716u } + }, + { + { 118634664u, 3358712512u, 2492792220u }, + { 348833376u, 118634664u, 2495544591u }, + { 3235582254u, 348833376u, 4043157504u } + }, + { + { 2303067090u, 3371139074u, 1967771133u }, + { 598630070u, 2303067090u, 1819012637u }, + { 2049250561u, 598630070u, 4093044926u } + }, + { + { 3035321857u, 3971176093u, 226779704u }, + { 3361614254u, 3035321857u, 2807125404u }, + { 326640887u, 3361614254u, 3147308542u } + }, + { + { 1774298149u, 4179629947u, 3145006948u }, + { 1688753503u, 1774298149u, 94869516u }, + { 2327946901u, 1688753503u, 2786835219u } + } + }; + +#ifndef __CUDACC_RTC__ +CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS unsigned int mrg32k3aM2Host[64][3][3] = { + { + { 0u, 1u, 0u }, + { 0u, 0u, 1u }, + { 4293573854u, 0u, 527612u } + }, + { + { 0u, 0u, 1u }, + { 4293573854u, 0u, 527612u }, + { 2706407399u, 4293573854u, 3497978192u } + }, + { + { 2706407399u, 4293573854u, 3497978192u }, + { 1431525864u, 2706407399u, 3281754271u }, + { 97673890u, 1431525864u, 1673476130u } + }, + { + { 3405842137u, 2680076935u, 893509979u }, + { 4035147174u, 3405842137u, 3280220074u }, + { 2623373296u, 4035147174u, 361718588u } + }, + { + { 818368950u, 3790774567u, 3542344109u }, + { 1817134745u, 818368950u, 3321940838u }, + { 3493477402u, 1817134745u, 2854655037u } + }, + { + { 498682467u, 2928649385u, 811441367u }, + { 1777037472u, 498682467u, 479207863u }, + { 3058260025u, 1777037472u, 1528225099u } + }, + { + { 3893311647u, 3140922085u, 64039185u }, + { 82107183u, 3893311647u, 2655465224u }, + { 1674879036u, 82107183u, 1089381262u } + }, + { + { 28639152u, 3496041927u, 2231910770u }, + { 3174683233u, 28639152u, 2828785870u }, + { 3681140872u, 3174683233u, 3910194649u } + }, + { + { 1463826069u, 300842059u, 3313769518u }, + { 1799677538u, 1463826069u, 3174861078u }, + { 1882279394u, 1799677538u, 3509975160u } + }, + { + { 2092194020u, 184076987u, 2202401252u }, + { 3103629604u, 2092194020u, 3409560232u }, + { 4257445059u, 3103629604u, 2390202783u } + }, + { + { 812917091u, 2574011276u, 4168802395u }, + { 209817750u, 812917091u, 2974870628u }, + { 3238802184u, 209817750u, 3692836406u } + }, + { + { 477309738u, 3314523413u, 3442242150u }, + { 2755731404u, 477309738u, 2782713347u }, + { 1606221490u, 2755731404u, 1033463096u } + }, + { + { 2155469603u, 3326516116u, 3843369786u }, + { 288604458u, 2155469603u, 571673571u }, + { 1501677614u, 288604458u, 2928213494u } + }, + { + { 2082469029u, 749754403u, 3963963316u }, + { 2764859700u, 2082469029u, 3576428059u }, + { 2840894706u, 2764859700u, 1782279859u } + }, + { + { 3760163766u, 1041986082u, 1799196192u }, + { 1022129134u, 3760163766u, 1332558840u }, + { 276873446u, 1022129134u, 3979423632u } + }, + { + { 1021313167u, 1312544548u, 1716381787u }, + { 3037868518u, 1021313167u, 199085085u }, + { 2582787611u, 3037868518u, 3539882179u } + }, + { + { 2569413030u, 1631336015u, 2594942403u }, + { 1030618503u, 2569413030u, 3467650326u }, + { 1998739584u, 1030618503u, 3174552073u } + }, + { + { 2334639309u, 3114094203u, 601680947u }, + { 2110199318u, 2334639309u, 678342865u }, + { 1649523168u, 2110199318u, 2154948056u } + }, + { + { 563657176u, 191330473u, 1641595774u }, + { 780563537u, 563657176u, 3029522338u }, + { 2037330914u, 780563537u, 2084602709u } + }, + { + { 3414769923u, 1968799026u, 2238126504u }, + { 832866376u, 3414769923u, 3754780168u }, + { 2165145850u, 832866376u, 1594768331u } + }, + { + { 1646861218u, 2317984620u, 2301581548u }, + { 2672536210u, 1646861218u, 359763062u }, + { 2391283983u, 2672536210u, 1885870777u } + }, + { + { 841254072u, 3765813448u, 1635365181u }, + { 2013240130u, 841254072u, 605925849u }, + { 3743932305u, 2013240130u, 400681955u } + }, + { + { 1930213004u, 2072952279u, 3077694794u }, + { 3579956569u, 1930213004u, 2478539210u }, + { 1960229502u, 3579956569u, 1455652656u } + }, + { + { 1097613522u, 1784540933u, 1194440107u }, + { 321747515u, 1097613522u, 1225209584u }, + { 74521379u, 321747515u, 4288531000u } + }, + { + { 143812745u, 3254530816u, 3514348856u }, + { 769295000u, 143812745u, 2468210728u }, + { 1927161272u, 769295000u, 522705580u } + }, + { + { 2692035063u, 2596905012u, 1643240704u }, + { 1103432342u, 2692035063u, 1446182108u }, + { 4161111774u, 1103432342u, 3076435551u } + }, + { + { 2375319030u, 1391532370u, 3742334018u }, + { 1202100604u, 2375319030u, 4098434768u }, + { 2327872488u, 1202100604u, 1471526950u } + }, + { + { 4269164791u, 2795313144u, 2507855960u }, + { 4245372460u, 4269164791u, 4094914553u }, + { 3873219634u, 4245372460u, 1473695507u } + }, + { + { 513890845u, 1208902926u, 2870530442u }, + { 1984873167u, 513890845u, 1257532340u }, + { 1212627640u, 1984873167u, 2354363842u } + }, + { + { 1848364568u, 1552116673u, 3496528455u }, + { 4160778291u, 1848364568u, 141769900u }, + { 3611019106u, 4160778291u, 596424080u } + }, + { + { 364070020u, 3520039729u, 837362349u }, + { 2544671570u, 364070020u, 2188646679u }, + { 163978331u, 2544671570u, 672947816u } + }, + { + { 1192700714u, 3968150021u, 298357363u }, + { 635565666u, 1192700714u, 2589432341u }, + { 2548654227u, 635565666u, 3531570992u } + }, + { + { 2709640529u, 676525399u, 875361870u }, + { 1315499519u, 2709640529u, 3842690720u }, + { 3300994644u, 1315499519u, 2446760804u } + }, + { + { 2742149264u, 1410604392u, 3032350755u }, + { 3774935330u, 2742149264u, 597633965u }, + { 4085935803u, 3774935330u, 3952463556u } + }, + { + { 3878579563u, 845297523u, 1721916511u }, + { 2077922420u, 3878579563u, 3651360351u }, + { 2177255734u, 2077922420u, 3791239282u } + }, + { + { 1570315355u, 4252790045u, 3522351060u }, + { 2324624266u, 1570315355u, 3594939336u }, + { 1725087354u, 2324624266u, 1338343327u } + }, + { + { 2305761589u, 381933244u, 3663579047u }, + { 1355307047u, 2305761589u, 313617972u }, + { 992174375u, 1355307047u, 3881593435u } + }, + { + { 1667857811u, 1564715297u, 2263851601u }, + { 3791771273u, 1667857811u, 4196134923u }, + { 3347975047u, 3791771273u, 615040705u } + }, + { + { 4093947334u, 3454015638u, 2815567716u }, + { 4261953004u, 4093947334u, 3973733876u }, + { 2979573134u, 4261953004u, 3757047667u } + }, + { + { 250120061u, 570149551u, 1513430926u }, + { 3178644752u, 250120061u, 1701869032u }, + { 4172515680u, 3178644752u, 4213855850u } + }, + { + { 4158106802u, 3062358456u, 1815738463u }, + { 1379176112u, 4158106802u, 3926509890u }, + { 2842564878u, 1379176112u, 2852219546u } + }, + { + { 931848746u, 256263523u, 2633569246u }, + { 3284646837u, 931848746u, 2567084715u }, + { 415258465u, 3284646837u, 2017565947u } + }, + { + { 1648005210u, 1032291296u, 3987397422u }, + { 1831496020u, 1648005210u, 2829448427u }, + { 1821082272u, 1831496020u, 2917140265u } + }, + { + { 4161327077u, 489964129u, 3870847744u }, + { 1669447863u, 4161327077u, 4292947198u }, + { 1522417114u, 1669447863u, 2652286672u } + }, + { + { 1270934555u, 3136631324u, 505612043u }, + { 2981474723u, 1270934555u, 2528619024u }, + { 625182639u, 2981474723u, 1008985039u } + }, + { + { 280996820u, 143706137u, 3013099060u }, + { 1797675893u, 280996820u, 3743985508u }, + { 1123794455u, 1797675893u, 2460119169u } + }, + { + { 919218027u, 4154920441u, 1125672685u }, + { 3933041881u, 919218027u, 474242849u }, + { 564891116u, 3933041881u, 2263904321u } + }, + { + { 2920112852u, 1965329198u, 1177141043u }, + { 2135250851u, 2920112852u, 969184056u }, + { 296035385u, 2135250851u, 4267827987u } + }, + { + { 1481142942u, 4120754772u, 1088557292u }, + { 265491023u, 1481142942u, 2860005744u }, + { 301796252u, 265491023u, 1935975979u } + }, + { + { 2111859033u, 2813610100u, 1001476468u }, + { 73849832u, 2111859033u, 3980799998u }, + { 3330206241u, 73849832u, 1933943506u } + }, + { + { 1781286360u, 3661231931u, 3509383709u }, + { 2753158871u, 1781286360u, 3119883109u }, + { 3576525143u, 2753158871u, 551079002u } + }, + { + { 1185024844u, 587779104u, 1004942725u }, + { 3763632860u, 1185024844u, 947424568u }, + { 3811666068u, 3763632860u, 2352253462u } + }, + { + { 1310227170u, 218138208u, 3172947233u }, + { 766129426u, 1310227170u, 1808643264u }, + { 2226659371u, 766129426u, 3853798112u } + }, + { + { 2230902378u, 4243560874u, 2491962392u }, + { 3836629116u, 2230902378u, 3637515403u }, + { 2846140932u, 3836629116u, 3083355464u } + }, + { + { 999448569u, 1464488480u, 3344426626u }, + { 946166795u, 999448569u, 340856814u }, + { 3686999436u, 946166795u, 3231079441u } + }, + { + { 1226155368u, 3477563770u, 550006884u }, + { 2378667355u, 1226155368u, 1493409040u }, + { 260364836u, 2378667355u, 4133888397u } + }, + { + { 1277901832u, 310796286u, 2818511068u }, + { 3088910653u, 1277901832u, 3303406025u }, + { 2507911914u, 3088910653u, 3712928074u } + }, + { + { 481918378u, 339570348u, 1728801469u }, + { 1623163429u, 481918378u, 2209094694u }, + { 3146982514u, 1623163429u, 508445538u } + }, + { + { 3138921230u, 2381863183u, 1992357430u }, + { 1024510915u, 3138921230u, 2122851650u }, + { 1453455184u, 1024510915u, 941946604u } + }, + { + { 2465372719u, 1391015357u, 3328905025u }, + { 1821933605u, 2465372719u, 1343489680u }, + { 3648970313u, 1821933605u, 1816599716u } + }, + { + { 118634664u, 3358712512u, 2492792220u }, + { 348833376u, 118634664u, 2495544591u }, + { 3235582254u, 348833376u, 4043157504u } + }, + { + { 2303067090u, 3371139074u, 1967771133u }, + { 598630070u, 2303067090u, 1819012637u }, + { 2049250561u, 598630070u, 4093044926u } + }, + { + { 3035321857u, 3971176093u, 226779704u }, + { 3361614254u, 3035321857u, 2807125404u }, + { 326640887u, 3361614254u, 3147308542u } + }, + { + { 1774298149u, 4179629947u, 3145006948u }, + { 1688753503u, 1774298149u, 94869516u }, + { 2327946901u, 1688753503u, 2786835219u } + } + }; + +#endif // ifndef __CUDACC_RTC__ + +/*Base matrices to power (2 to the power 76) to power 2 to power n + 1u, n the first array index, from 0..63*/ + +CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS unsigned int mrg32k3aM1SubSeq[56][3][3] = { + { + { 82758667u, 1871391091u, 4127413238u }, + { 3672831523u, 69195019u, 1871391091u }, + { 3672091415u, 3528743235u, 69195019u } + }, + { + { 3361372532u, 2329303404u, 99651939u }, + { 2008671965u, 2931758910u, 2329303404u }, + { 1113529483u, 2374097189u, 2931758910u } + }, + { + { 1831590873u, 1588259595u, 1314332382u }, + { 2385989343u, 2508077280u, 1588259595u }, + { 1787615788u, 661437137u, 2508077280u } + }, + { + { 2326052247u, 4183591379u, 4049009082u }, + { 2604529491u, 1453913233u, 4183591379u }, + { 2311925423u, 1805360390u, 1453913233u } + }, + { + { 3956367490u, 604461629u, 1257432102u }, + { 794711716u, 1155867175u, 604461629u }, + { 1777070788u, 429445904u, 1155867175u } + }, + { + { 1686241617u, 1257046062u, 1427609439u }, + { 490376081u, 387798431u, 1257046062u }, + { 235551485u, 1312672615u, 387798431u } + }, + { + { 2362447880u, 3445363024u, 3160262066u }, + { 2426867845u, 4194339866u, 3445363024u }, + { 1046144413u, 4177893681u, 4194339866u } + }, + { + { 4251175413u, 3559576374u, 3107663662u }, + { 697539134u, 1909472435u, 3559576374u }, + { 280754246u, 375835695u, 1909472435u } + }, + { + { 1099512970u, 712404985u, 1571467521u }, + { 546519870u, 1135109300u, 712404985u }, + { 3325312332u, 2352874613u, 1135109300u } + }, + { + { 1945425936u, 1653045514u, 381988982u }, + { 3733376326u, 414410025u, 1653045514u }, + { 1181583679u, 1185848176u, 414410025u } + }, + { + { 2526336124u, 3019211015u, 4215964965u }, + { 2683163472u, 4188191530u, 3019211015u }, + { 2964651598u, 293801056u, 4188191530u } + }, + { + { 1444052678u, 2253324417u, 39719589u }, + { 1880267534u, 2391992038u, 2253324417u }, + { 987740265u, 3691889508u, 2391992038u } + }, + { + { 166599066u, 2335494420u, 1232261118u }, + { 2227597731u, 2570600780u, 2335494420u }, + { 2700034538u, 3460843234u, 2570600780u } + }, + { + { 2511338360u, 1188954576u, 1251401239u }, + { 2511664974u, 292276982u, 1188954576u }, + { 697844082u, 3093661552u, 292276982u } + }, + { + { 3624650744u, 51993077u, 3540268009u }, + { 3252828938u, 3710319575u, 51993077u }, + { 2858628849u, 3910069381u, 3710319575u } + }, + { + { 655966702u, 754002362u, 1646581402u }, + { 1958331075u, 475572423u, 754002362u }, + { 3248619000u, 3228514800u, 475572423u } + }, + { + { 2760311307u, 4166372813u, 741596417u }, + { 2282679206u, 3090782630u, 4166372813u }, + { 3242468721u, 1628442374u, 3090782630u } + }, + { + { 4265279407u, 3532111852u, 1754687396u }, + { 500404765u, 2603727025u, 3532111852u }, + { 1428367254u, 3149485478u, 2603727025u } + }, + { + { 2873769531u, 2081104178u, 596284397u }, + { 4153800443u, 1261269623u, 2081104178u }, + { 3967600061u, 1830023157u, 1261269623u } + }, + { + { 278611533u, 2229285304u, 3443204327u }, + { 3110641420u, 77498444u, 2229285304u }, + { 3904070810u, 1070507239u, 77498444u } + }, + { + { 544639534u, 568528663u, 2177189807u }, + { 2475829068u, 121482268u, 568528663u }, + { 876978915u, 3116647617u, 121482268u } + }, + { + { 1547862823u, 2404658587u, 4191448009u }, + { 2158188804u, 2976916793u, 2404658587u }, + { 168571747u, 1691884706u, 2976916793u } + }, + { + { 3208213311u, 4212638780u, 3235157352u }, + { 671148556u, 2951207765u, 4212638780u }, + { 2075145516u, 2395485231u, 2951207765u } + }, + { + { 4080517315u, 2133433101u, 4043998180u }, + { 2044221845u, 867670560u, 2133433101u }, + { 834432416u, 3613001199u, 867670560u } + }, + { + { 4102885735u, 1319434267u, 2678775073u }, + { 740092580u, 607380970u, 1319434267u }, + { 2198271844u, 2610193258u, 607380970u } + }, + { + { 1165218048u, 1317690360u, 1189150958u }, + { 399240205u, 2507168618u, 1317690360u }, + { 2988334517u, 2687593413u, 2507168618u } + }, + { + { 1028861702u, 4082006648u, 338232527u }, + { 1888486946u, 1842080991u, 4082006648u }, + { 3903826366u, 3109935091u, 1842080991u } + }, + { + { 614134826u, 2261996505u, 2888080641u }, + { 710199359u, 2773979788u, 2261996505u }, + { 1144301620u, 2554371815u, 2773979788u } + }, + { + { 4056173823u, 1285620078u, 357420018u }, + { 2423072612u, 2309408315u, 1285620078u }, + { 1533175115u, 2760088020u, 2309408315u } + }, + { + { 4264130267u, 815015434u, 3142242173u }, + { 180649975u, 2500813569u, 815015434u }, + { 3378723563u, 829683767u, 2500813569u } + }, + { + { 4174387531u, 1030729435u, 2812778314u }, + { 1752988797u, 4044178729u, 1030729435u }, + { 467969301u, 554748104u, 4044178729u } + }, + { + { 1348429235u, 2928743274u, 3776082629u }, + { 3607529209u, 3069812185u, 2928743274u }, + { 2542432347u, 3208181168u, 3069812185u } + }, + { + { 4064845753u, 668285756u, 3816217625u }, + { 3713143233u, 1380634204u, 668285756u }, + { 3533700508u, 1192551435u, 1380634204u } + }, + { + { 1515684518u, 1706771705u, 728123349u }, + { 3174850469u, 2057456462u, 1706771705u }, + { 3410402985u, 2897339640u, 2057456462u } + }, + { + { 3082272717u, 531091457u, 1390161328u }, + { 3895139973u, 2171402857u, 531091457u }, + { 4030688141u, 3049703400u, 2171402857u } + }, + { + { 1241147206u, 3193892819u, 1244284192u }, + { 65180262u, 4065669017u, 3193892819u }, + { 1484817937u, 3661081858u, 4065669017u } + }, + { + { 1438760812u, 3491341751u, 3414470157u }, + { 2805337292u, 272266053u, 3491341751u }, + { 824109230u, 3202556526u, 272266053u } + }, + { + { 135412706u, 3627115412u, 2345042216u }, + { 1565169824u, 2166856449u, 3627115412u }, + { 1026946745u, 3467845248u, 2166856449u } + }, + { + { 1889419951u, 3256876154u, 1240505488u }, + { 1254783743u, 989966800u, 3256876154u }, + { 1995297400u, 3692472918u, 989966800u } + }, + { + { 3206226875u, 285700890u, 496017472u }, + { 2515316194u, 2129675196u, 285700890u }, + { 1863853990u, 2673457552u, 2129675196u } + }, + { + { 4163770641u, 255160418u, 772100749u }, + { 1987092456u, 3237660221u, 255160418u }, + { 1394381051u, 4216039401u, 3237660221u } + }, + { + { 2133915627u, 2713747584u, 627765421u }, + { 2300605925u, 35690583u, 2713747584u }, + { 2918902946u, 2638220304u, 35690583u } + }, + { + { 2587549655u, 998684270u, 4292130625u }, + { 1791772791u, 2820705344u, 998684270u }, + { 124590158u, 3831143549u, 2820705344u } + }, + { + { 978482299u, 3200877282u, 497605289u }, + { 3717741518u, 3737164414u, 3200877282u }, + { 4046686626u, 861393946u, 3737164414u } + }, + { + { 2665561897u, 300934584u, 3179822945u }, + { 893043137u, 2031413512u, 300934584u }, + { 3806926970u, 2413249929u, 2031413512u } + }, + { + { 1417581911u, 3071835354u, 2575196237u }, + { 4101127251u, 1375339216u, 3071835354u }, + { 847617977u, 3632503316u, 1375339216u } + }, + { + { 2747488994u, 3296604805u, 898095468u }, + { 1742777145u, 219265369u, 3296604805u }, + { 823714885u, 667779292u, 219265369u } + }, + { + { 2640209692u, 3040506537u, 3626115220u }, + { 161827078u, 852668118u, 3040506537u }, + { 3856381322u, 3360242076u, 852668118u } + }, + { + { 3734246393u, 4151553160u, 4177051283u }, + { 266522866u, 1731798531u, 4151553160u }, + { 632196679u, 3864297722u, 1731798531u } + }, + { + { 1694175127u, 1087914338u, 2384195794u }, + { 2764925057u, 505782858u, 1087914338u }, + { 3235634082u, 807915248u, 505782858u } + }, + { + { 2402749950u, 2353776151u, 75909174u }, + { 890570951u, 1752665661u, 2353776151u }, + { 3120241607u, 3862435696u, 1752665661u } + } + }; + +#ifndef __CUDACC_RTC__ +CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS unsigned int mrg32k3aM1SubSeqHost[56][3][3] = { + { + { 82758667u, 1871391091u, 4127413238u }, + { 3672831523u, 69195019u, 1871391091u }, + { 3672091415u, 3528743235u, 69195019u } + }, + { + { 3361372532u, 2329303404u, 99651939u }, + { 2008671965u, 2931758910u, 2329303404u }, + { 1113529483u, 2374097189u, 2931758910u } + }, + { + { 1831590873u, 1588259595u, 1314332382u }, + { 2385989343u, 2508077280u, 1588259595u }, + { 1787615788u, 661437137u, 2508077280u } + }, + { + { 2326052247u, 4183591379u, 4049009082u }, + { 2604529491u, 1453913233u, 4183591379u }, + { 2311925423u, 1805360390u, 1453913233u } + }, + { + { 3956367490u, 604461629u, 1257432102u }, + { 794711716u, 1155867175u, 604461629u }, + { 1777070788u, 429445904u, 1155867175u } + }, + { + { 1686241617u, 1257046062u, 1427609439u }, + { 490376081u, 387798431u, 1257046062u }, + { 235551485u, 1312672615u, 387798431u } + }, + { + { 2362447880u, 3445363024u, 3160262066u }, + { 2426867845u, 4194339866u, 3445363024u }, + { 1046144413u, 4177893681u, 4194339866u } + }, + { + { 4251175413u, 3559576374u, 3107663662u }, + { 697539134u, 1909472435u, 3559576374u }, + { 280754246u, 375835695u, 1909472435u } + }, + { + { 1099512970u, 712404985u, 1571467521u }, + { 546519870u, 1135109300u, 712404985u }, + { 3325312332u, 2352874613u, 1135109300u } + }, + { + { 1945425936u, 1653045514u, 381988982u }, + { 3733376326u, 414410025u, 1653045514u }, + { 1181583679u, 1185848176u, 414410025u } + }, + { + { 2526336124u, 3019211015u, 4215964965u }, + { 2683163472u, 4188191530u, 3019211015u }, + { 2964651598u, 293801056u, 4188191530u } + }, + { + { 1444052678u, 2253324417u, 39719589u }, + { 1880267534u, 2391992038u, 2253324417u }, + { 987740265u, 3691889508u, 2391992038u } + }, + { + { 166599066u, 2335494420u, 1232261118u }, + { 2227597731u, 2570600780u, 2335494420u }, + { 2700034538u, 3460843234u, 2570600780u } + }, + { + { 2511338360u, 1188954576u, 1251401239u }, + { 2511664974u, 292276982u, 1188954576u }, + { 697844082u, 3093661552u, 292276982u } + }, + { + { 3624650744u, 51993077u, 3540268009u }, + { 3252828938u, 3710319575u, 51993077u }, + { 2858628849u, 3910069381u, 3710319575u } + }, + { + { 655966702u, 754002362u, 1646581402u }, + { 1958331075u, 475572423u, 754002362u }, + { 3248619000u, 3228514800u, 475572423u } + }, + { + { 2760311307u, 4166372813u, 741596417u }, + { 2282679206u, 3090782630u, 4166372813u }, + { 3242468721u, 1628442374u, 3090782630u } + }, + { + { 4265279407u, 3532111852u, 1754687396u }, + { 500404765u, 2603727025u, 3532111852u }, + { 1428367254u, 3149485478u, 2603727025u } + }, + { + { 2873769531u, 2081104178u, 596284397u }, + { 4153800443u, 1261269623u, 2081104178u }, + { 3967600061u, 1830023157u, 1261269623u } + }, + { + { 278611533u, 2229285304u, 3443204327u }, + { 3110641420u, 77498444u, 2229285304u }, + { 3904070810u, 1070507239u, 77498444u } + }, + { + { 544639534u, 568528663u, 2177189807u }, + { 2475829068u, 121482268u, 568528663u }, + { 876978915u, 3116647617u, 121482268u } + }, + { + { 1547862823u, 2404658587u, 4191448009u }, + { 2158188804u, 2976916793u, 2404658587u }, + { 168571747u, 1691884706u, 2976916793u } + }, + { + { 3208213311u, 4212638780u, 3235157352u }, + { 671148556u, 2951207765u, 4212638780u }, + { 2075145516u, 2395485231u, 2951207765u } + }, + { + { 4080517315u, 2133433101u, 4043998180u }, + { 2044221845u, 867670560u, 2133433101u }, + { 834432416u, 3613001199u, 867670560u } + }, + { + { 4102885735u, 1319434267u, 2678775073u }, + { 740092580u, 607380970u, 1319434267u }, + { 2198271844u, 2610193258u, 607380970u } + }, + { + { 1165218048u, 1317690360u, 1189150958u }, + { 399240205u, 2507168618u, 1317690360u }, + { 2988334517u, 2687593413u, 2507168618u } + }, + { + { 1028861702u, 4082006648u, 338232527u }, + { 1888486946u, 1842080991u, 4082006648u }, + { 3903826366u, 3109935091u, 1842080991u } + }, + { + { 614134826u, 2261996505u, 2888080641u }, + { 710199359u, 2773979788u, 2261996505u }, + { 1144301620u, 2554371815u, 2773979788u } + }, + { + { 4056173823u, 1285620078u, 357420018u }, + { 2423072612u, 2309408315u, 1285620078u }, + { 1533175115u, 2760088020u, 2309408315u } + }, + { + { 4264130267u, 815015434u, 3142242173u }, + { 180649975u, 2500813569u, 815015434u }, + { 3378723563u, 829683767u, 2500813569u } + }, + { + { 4174387531u, 1030729435u, 2812778314u }, + { 1752988797u, 4044178729u, 1030729435u }, + { 467969301u, 554748104u, 4044178729u } + }, + { + { 1348429235u, 2928743274u, 3776082629u }, + { 3607529209u, 3069812185u, 2928743274u }, + { 2542432347u, 3208181168u, 3069812185u } + }, + { + { 4064845753u, 668285756u, 3816217625u }, + { 3713143233u, 1380634204u, 668285756u }, + { 3533700508u, 1192551435u, 1380634204u } + }, + { + { 1515684518u, 1706771705u, 728123349u }, + { 3174850469u, 2057456462u, 1706771705u }, + { 3410402985u, 2897339640u, 2057456462u } + }, + { + { 3082272717u, 531091457u, 1390161328u }, + { 3895139973u, 2171402857u, 531091457u }, + { 4030688141u, 3049703400u, 2171402857u } + }, + { + { 1241147206u, 3193892819u, 1244284192u }, + { 65180262u, 4065669017u, 3193892819u }, + { 1484817937u, 3661081858u, 4065669017u } + }, + { + { 1438760812u, 3491341751u, 3414470157u }, + { 2805337292u, 272266053u, 3491341751u }, + { 824109230u, 3202556526u, 272266053u } + }, + { + { 135412706u, 3627115412u, 2345042216u }, + { 1565169824u, 2166856449u, 3627115412u }, + { 1026946745u, 3467845248u, 2166856449u } + }, + { + { 1889419951u, 3256876154u, 1240505488u }, + { 1254783743u, 989966800u, 3256876154u }, + { 1995297400u, 3692472918u, 989966800u } + }, + { + { 3206226875u, 285700890u, 496017472u }, + { 2515316194u, 2129675196u, 285700890u }, + { 1863853990u, 2673457552u, 2129675196u } + }, + { + { 4163770641u, 255160418u, 772100749u }, + { 1987092456u, 3237660221u, 255160418u }, + { 1394381051u, 4216039401u, 3237660221u } + }, + { + { 2133915627u, 2713747584u, 627765421u }, + { 2300605925u, 35690583u, 2713747584u }, + { 2918902946u, 2638220304u, 35690583u } + }, + { + { 2587549655u, 998684270u, 4292130625u }, + { 1791772791u, 2820705344u, 998684270u }, + { 124590158u, 3831143549u, 2820705344u } + }, + { + { 978482299u, 3200877282u, 497605289u }, + { 3717741518u, 3737164414u, 3200877282u }, + { 4046686626u, 861393946u, 3737164414u } + }, + { + { 2665561897u, 300934584u, 3179822945u }, + { 893043137u, 2031413512u, 300934584u }, + { 3806926970u, 2413249929u, 2031413512u } + }, + { + { 1417581911u, 3071835354u, 2575196237u }, + { 4101127251u, 1375339216u, 3071835354u }, + { 847617977u, 3632503316u, 1375339216u } + }, + { + { 2747488994u, 3296604805u, 898095468u }, + { 1742777145u, 219265369u, 3296604805u }, + { 823714885u, 667779292u, 219265369u } + }, + { + { 2640209692u, 3040506537u, 3626115220u }, + { 161827078u, 852668118u, 3040506537u }, + { 3856381322u, 3360242076u, 852668118u } + }, + { + { 3734246393u, 4151553160u, 4177051283u }, + { 266522866u, 1731798531u, 4151553160u }, + { 632196679u, 3864297722u, 1731798531u } + }, + { + { 1694175127u, 1087914338u, 2384195794u }, + { 2764925057u, 505782858u, 1087914338u }, + { 3235634082u, 807915248u, 505782858u } + }, + { + { 2402749950u, 2353776151u, 75909174u }, + { 890570951u, 1752665661u, 2353776151u }, + { 3120241607u, 3862435696u, 1752665661u } + } + }; +#endif // #ifndef __CUDACC_RTC__ + +CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS unsigned int mrg32k3aM2SubSeq[56][3][3] = { + { + { 1511326704u, 3759209742u, 1610795712u }, + { 4292754251u, 1511326704u, 3889917532u }, + { 3859662829u, 4292754251u, 3708466080u } + }, + { + { 972103006u, 964807713u, 878035866u }, + { 4248550197u, 972103006u, 1926628839u }, + { 1448629089u, 4248550197u, 3196114006u } + }, + { + { 3497384788u, 3174249442u, 3182508868u }, + { 3864816447u, 3497384788u, 3038399593u }, + { 2546884738u, 3864816447u, 2980208068u } + }, + { + { 1776335558u, 1189944887u, 4095757548u }, + { 3813600746u, 1776335558u, 789475914u }, + { 4119698302u, 3813600746u, 2145357457u } + }, + { + { 4022832294u, 4130146837u, 1942923647u }, + { 1675130777u, 4022832294u, 916677004u }, + { 4089786548u, 1675130777u, 116540512u } + }, + { + { 165639584u, 1205513289u, 2037453462u }, + { 1444587280u, 165639584u, 161923120u }, + { 2617085459u, 1444587280u, 2006913311u } + }, + { + { 3458099202u, 3062421748u, 4052486999u }, + { 1064270720u, 3458099202u, 230768332u }, + { 4056228301u, 1064270720u, 2219267779u } + }, + { + { 296275263u, 3452455838u, 2081462173u }, + { 1789143993u, 296275263u, 3463234943u }, + { 2097389984u, 1789143993u, 3447191459u } + }, + { + { 2828288883u, 3866690251u, 410553827u }, + { 1587005542u, 2828288883u, 1469478670u }, + { 2766486018u, 1587005542u, 2627363449u } + }, + { + { 3288027530u, 412403981u, 2458742268u }, + { 4267121909u, 3288027530u, 138566505u }, + { 420803572u, 4267121909u, 4094554844u } + }, + { + { 3844599430u, 2430152838u, 3283485436u }, + { 2486244684u, 3844599430u, 4252427633u }, + { 3560842909u, 2486244684u, 3960267499u } + }, + { + { 67933059u, 1294996291u, 2657888382u }, + { 513233413u, 67933059u, 1379805031u }, + { 44564058u, 513233413u, 86971645u } + }, + { + { 2732588524u, 1866530072u, 818237694u }, + { 2540507736u, 2732588524u, 3257104212u }, + { 1164400003u, 2540507736u, 1124501551u } + }, + { + { 4199239222u, 3155848463u, 2121388468u }, + { 1135554501u, 4199239222u, 2056492193u }, + { 3251740389u, 1135554501u, 2343537248u } + }, + { + { 550710036u, 500329021u, 1075236085u }, + { 356444753u, 550710036u, 1634965500u }, + { 58733535u, 356444753u, 1261552815u } + }, + { + { 708689546u, 419139045u, 2012018174u }, + { 706488081u, 708689546u, 1113760995u }, + { 585555005u, 706488081u, 76092226u } + }, + { + { 1293182265u, 3168473803u, 366230236u }, + { 3319068849u, 1293182265u, 1085259665u }, + { 1675229290u, 3319068849u, 3912300371u } + }, + { + { 3186089068u, 4188864734u, 1211781402u }, + { 756122322u, 3186089068u, 578262892u }, + { 2518961174u, 756122322u, 1658665581u } + }, + { + { 1347291439u, 2050427676u, 736113023u }, + { 4102191254u, 1347291439u, 878627148u }, + { 1293500383u, 4102191254u, 745646810u } + }, + { + { 4196897331u, 3436564969u, 1900167098u }, + { 3108887846u, 4196897331u, 2697923227u }, + { 1405263476u, 3108887846u, 314631094u } + }, + { + { 958383622u, 3694638688u, 1150087061u }, + { 3770009830u, 958383622u, 793326651u }, + { 533700213u, 3770009830u, 1513734026u } + }, + { + { 4119603367u, 3479396923u, 3534176399u }, + { 3765397477u, 4119603367u, 1458031003u }, + { 3380901602u, 3765397477u, 2684083587u } + }, + { + { 980937351u, 2094378936u, 448446028u }, + { 1421333909u, 980937351u, 3405683645u }, + { 323724368u, 1421333909u, 338680738u } + }, + { + { 2942968846u, 4293637338u, 3549906544u }, + { 527851489u, 2942968846u, 3852871282u }, + { 4209198933u, 527851489u, 1091268872u } + }, + { + { 1975983015u, 2092556693u, 611187071u }, + { 3982652344u, 1975983015u, 3001736262u }, + { 2055073597u, 3982652344u, 1875181995u } + }, + { + { 2970221269u, 880904779u, 2447465272u }, + { 2888742196u, 2970221269u, 3521651749u }, + { 3019977656u, 2888742196u, 2712717326u } + }, + { + { 419134859u, 2976059897u, 747864206u }, + { 4101695717u, 419134859u, 4264593116u }, + { 2657991148u, 4101695717u, 2542621682u } + }, + { + { 4043135299u, 1612983166u, 1149778656u }, + { 1267010518u, 4043135299u, 3496325546u }, + { 3094232897u, 1267010518u, 2949176293u } + }, + { + { 3949395794u, 1774568686u, 2123036003u }, + { 2182983404u, 3949395794u, 2355671350u }, + { 2820933455u, 2182983404u, 513963325u } + }, + { + { 3046911698u, 2576744453u, 2492729814u }, + { 4277866093u, 3046911698u, 3146977604u }, + { 2249371766u, 4277866093u, 3622293976u } + }, + { + { 1391529818u, 423458502u, 2587125255u }, + { 3536237833u, 1391529818u, 985347517u }, + { 157623850u, 3536237833u, 1015566287u } + }, + { + { 48329260u, 2599277669u, 821961664u }, + { 902187690u, 48329260u, 1716556555u }, + { 4019658974u, 902187690u, 950730510u } + }, + { + { 1318489562u, 1530977112u, 3713577419u }, + { 4270158447u, 1318489562u, 1654940598u }, + { 2679964938u, 4270158447u, 1337075195u } + }, + { + { 770600793u, 3249576224u, 3578552768u }, + { 2710443459u, 770600793u, 2990852339u }, + { 3098163705u, 2710443459u, 522138188u } + }, + { + { 2803285489u, 1922250286u, 3164022812u }, + { 477609731u, 2803285489u, 2140252218u }, + { 2252852611u, 477609731u, 3058519788u } + }, + { + { 208329741u, 3633562083u, 3548346666u }, + { 3892091460u, 208329741u, 516833304u }, + { 3440632377u, 3892091460u, 1638833719u } + }, + { + { 1816075033u, 3570111203u, 959489356u }, + { 3482051486u, 1816075033u, 861657108u }, + { 3119495098u, 3482051486u, 2576849579u } + }, + { + { 4240216888u, 2891584407u, 2102314945u }, + { 4064489450u, 4240216888u, 1427441010u }, + { 2441164913u, 4064489450u, 3558527186u } + }, + { + { 2918371295u, 65155283u, 3469357011u }, + { 3579773554u, 2918371295u, 3494391959u }, + { 3266584309u, 3579773554u, 3837485479u } + }, + { + { 2959420453u, 1365016881u, 4082486022u }, + { 236489012u, 2959420453u, 3802558529u }, + { 2687043642u, 236489012u, 2547086826u } + }, + { + { 4185325422u, 2762854843u, 3200044912u }, + { 3664909559u, 4185325422u, 3543921700u }, + { 4240262918u, 3664909559u, 2853212443u } + }, + { + { 2618500928u, 4237264351u, 1470046497u }, + { 1893990098u, 2618500928u, 2982567031u }, + { 3017062825u, 1893990098u, 3195556801u } + }, + { + { 1868464655u, 3407681142u, 1652841784u }, + { 1678569574u, 1868464655u, 4162480901u }, + { 1477016185u, 1678569574u, 4145063890u } + }, + { + { 792188465u, 4251338402u, 2219407026u }, + { 3840340879u, 792188465u, 3493367465u }, + { 2979958414u, 3840340879u, 2338974139u } + }, + { + { 478845700u, 2378167062u, 882114621u }, + { 1674533845u, 478845700u, 3572905305u }, + { 3571222880u, 1674533845u, 1242316901u } + }, + { + { 2636090868u, 1972761498u, 71690719u }, + { 1228103463u, 2636090868u, 1280685025u }, + { 3741735502u, 1228103463u, 994061750u } + }, + { + { 1156725261u, 1100755307u, 221922891u }, + { 2892200461u, 1156725261u, 1505716533u }, + { 2287613563u, 2892200461u, 3689457190u } + }, + { + { 1387244644u, 3135090808u, 1243609165u }, + { 1724967466u, 1387244644u, 3296353235u }, + { 1064364031u, 1724967466u, 2107521044u } + }, + { + { 2822471992u, 2034317853u, 2071407475u }, + { 170903528u, 2822471992u, 1322162887u }, + { 2524982332u, 170903528u, 2656231333u } + }, + { + { 3653936868u, 3893194049u, 2484299328u }, + { 1313746234u, 3653936868u, 1705346273u }, + { 1397638018u, 1313746234u, 4015529545u } + }, + { + { 4129760842u, 1671665759u, 1677834656u }, + { 3200005334u, 4129760842u, 3486207172u }, + { 2850728736u, 3200005334u, 3076201597u } + } + }; + +#ifndef __CUDACC_RTC__ +CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS unsigned int mrg32k3aM2SubSeqHost[56][3][3] = { + { + { 1511326704u, 3759209742u, 1610795712u }, + { 4292754251u, 1511326704u, 3889917532u }, + { 3859662829u, 4292754251u, 3708466080u } + }, + { + { 972103006u, 964807713u, 878035866u }, + { 4248550197u, 972103006u, 1926628839u }, + { 1448629089u, 4248550197u, 3196114006u } + }, + { + { 3497384788u, 3174249442u, 3182508868u }, + { 3864816447u, 3497384788u, 3038399593u }, + { 2546884738u, 3864816447u, 2980208068u } + }, + { + { 1776335558u, 1189944887u, 4095757548u }, + { 3813600746u, 1776335558u, 789475914u }, + { 4119698302u, 3813600746u, 2145357457u } + }, + { + { 4022832294u, 4130146837u, 1942923647u }, + { 1675130777u, 4022832294u, 916677004u }, + { 4089786548u, 1675130777u, 116540512u } + }, + { + { 165639584u, 1205513289u, 2037453462u }, + { 1444587280u, 165639584u, 161923120u }, + { 2617085459u, 1444587280u, 2006913311u } + }, + { + { 3458099202u, 3062421748u, 4052486999u }, + { 1064270720u, 3458099202u, 230768332u }, + { 4056228301u, 1064270720u, 2219267779u } + }, + { + { 296275263u, 3452455838u, 2081462173u }, + { 1789143993u, 296275263u, 3463234943u }, + { 2097389984u, 1789143993u, 3447191459u } + }, + { + { 2828288883u, 3866690251u, 410553827u }, + { 1587005542u, 2828288883u, 1469478670u }, + { 2766486018u, 1587005542u, 2627363449u } + }, + { + { 3288027530u, 412403981u, 2458742268u }, + { 4267121909u, 3288027530u, 138566505u }, + { 420803572u, 4267121909u, 4094554844u } + }, + { + { 3844599430u, 2430152838u, 3283485436u }, + { 2486244684u, 3844599430u, 4252427633u }, + { 3560842909u, 2486244684u, 3960267499u } + }, + { + { 67933059u, 1294996291u, 2657888382u }, + { 513233413u, 67933059u, 1379805031u }, + { 44564058u, 513233413u, 86971645u } + }, + { + { 2732588524u, 1866530072u, 818237694u }, + { 2540507736u, 2732588524u, 3257104212u }, + { 1164400003u, 2540507736u, 1124501551u } + }, + { + { 4199239222u, 3155848463u, 2121388468u }, + { 1135554501u, 4199239222u, 2056492193u }, + { 3251740389u, 1135554501u, 2343537248u } + }, + { + { 550710036u, 500329021u, 1075236085u }, + { 356444753u, 550710036u, 1634965500u }, + { 58733535u, 356444753u, 1261552815u } + }, + { + { 708689546u, 419139045u, 2012018174u }, + { 706488081u, 708689546u, 1113760995u }, + { 585555005u, 706488081u, 76092226u } + }, + { + { 1293182265u, 3168473803u, 366230236u }, + { 3319068849u, 1293182265u, 1085259665u }, + { 1675229290u, 3319068849u, 3912300371u } + }, + { + { 3186089068u, 4188864734u, 1211781402u }, + { 756122322u, 3186089068u, 578262892u }, + { 2518961174u, 756122322u, 1658665581u } + }, + { + { 1347291439u, 2050427676u, 736113023u }, + { 4102191254u, 1347291439u, 878627148u }, + { 1293500383u, 4102191254u, 745646810u } + }, + { + { 4196897331u, 3436564969u, 1900167098u }, + { 3108887846u, 4196897331u, 2697923227u }, + { 1405263476u, 3108887846u, 314631094u } + }, + { + { 958383622u, 3694638688u, 1150087061u }, + { 3770009830u, 958383622u, 793326651u }, + { 533700213u, 3770009830u, 1513734026u } + }, + { + { 4119603367u, 3479396923u, 3534176399u }, + { 3765397477u, 4119603367u, 1458031003u }, + { 3380901602u, 3765397477u, 2684083587u } + }, + { + { 980937351u, 2094378936u, 448446028u }, + { 1421333909u, 980937351u, 3405683645u }, + { 323724368u, 1421333909u, 338680738u } + }, + { + { 2942968846u, 4293637338u, 3549906544u }, + { 527851489u, 2942968846u, 3852871282u }, + { 4209198933u, 527851489u, 1091268872u } + }, + { + { 1975983015u, 2092556693u, 611187071u }, + { 3982652344u, 1975983015u, 3001736262u }, + { 2055073597u, 3982652344u, 1875181995u } + }, + { + { 2970221269u, 880904779u, 2447465272u }, + { 2888742196u, 2970221269u, 3521651749u }, + { 3019977656u, 2888742196u, 2712717326u } + }, + { + { 419134859u, 2976059897u, 747864206u }, + { 4101695717u, 419134859u, 4264593116u }, + { 2657991148u, 4101695717u, 2542621682u } + }, + { + { 4043135299u, 1612983166u, 1149778656u }, + { 1267010518u, 4043135299u, 3496325546u }, + { 3094232897u, 1267010518u, 2949176293u } + }, + { + { 3949395794u, 1774568686u, 2123036003u }, + { 2182983404u, 3949395794u, 2355671350u }, + { 2820933455u, 2182983404u, 513963325u } + }, + { + { 3046911698u, 2576744453u, 2492729814u }, + { 4277866093u, 3046911698u, 3146977604u }, + { 2249371766u, 4277866093u, 3622293976u } + }, + { + { 1391529818u, 423458502u, 2587125255u }, + { 3536237833u, 1391529818u, 985347517u }, + { 157623850u, 3536237833u, 1015566287u } + }, + { + { 48329260u, 2599277669u, 821961664u }, + { 902187690u, 48329260u, 1716556555u }, + { 4019658974u, 902187690u, 950730510u } + }, + { + { 1318489562u, 1530977112u, 3713577419u }, + { 4270158447u, 1318489562u, 1654940598u }, + { 2679964938u, 4270158447u, 1337075195u } + }, + { + { 770600793u, 3249576224u, 3578552768u }, + { 2710443459u, 770600793u, 2990852339u }, + { 3098163705u, 2710443459u, 522138188u } + }, + { + { 2803285489u, 1922250286u, 3164022812u }, + { 477609731u, 2803285489u, 2140252218u }, + { 2252852611u, 477609731u, 3058519788u } + }, + { + { 208329741u, 3633562083u, 3548346666u }, + { 3892091460u, 208329741u, 516833304u }, + { 3440632377u, 3892091460u, 1638833719u } + }, + { + { 1816075033u, 3570111203u, 959489356u }, + { 3482051486u, 1816075033u, 861657108u }, + { 3119495098u, 3482051486u, 2576849579u } + }, + { + { 4240216888u, 2891584407u, 2102314945u }, + { 4064489450u, 4240216888u, 1427441010u }, + { 2441164913u, 4064489450u, 3558527186u } + }, + { + { 2918371295u, 65155283u, 3469357011u }, + { 3579773554u, 2918371295u, 3494391959u }, + { 3266584309u, 3579773554u, 3837485479u } + }, + { + { 2959420453u, 1365016881u, 4082486022u }, + { 236489012u, 2959420453u, 3802558529u }, + { 2687043642u, 236489012u, 2547086826u } + }, + { + { 4185325422u, 2762854843u, 3200044912u }, + { 3664909559u, 4185325422u, 3543921700u }, + { 4240262918u, 3664909559u, 2853212443u } + }, + { + { 2618500928u, 4237264351u, 1470046497u }, + { 1893990098u, 2618500928u, 2982567031u }, + { 3017062825u, 1893990098u, 3195556801u } + }, + { + { 1868464655u, 3407681142u, 1652841784u }, + { 1678569574u, 1868464655u, 4162480901u }, + { 1477016185u, 1678569574u, 4145063890u } + }, + { + { 792188465u, 4251338402u, 2219407026u }, + { 3840340879u, 792188465u, 3493367465u }, + { 2979958414u, 3840340879u, 2338974139u } + }, + { + { 478845700u, 2378167062u, 882114621u }, + { 1674533845u, 478845700u, 3572905305u }, + { 3571222880u, 1674533845u, 1242316901u } + }, + { + { 2636090868u, 1972761498u, 71690719u }, + { 1228103463u, 2636090868u, 1280685025u }, + { 3741735502u, 1228103463u, 994061750u } + }, + { + { 1156725261u, 1100755307u, 221922891u }, + { 2892200461u, 1156725261u, 1505716533u }, + { 2287613563u, 2892200461u, 3689457190u } + }, + { + { 1387244644u, 3135090808u, 1243609165u }, + { 1724967466u, 1387244644u, 3296353235u }, + { 1064364031u, 1724967466u, 2107521044u } + }, + { + { 2822471992u, 2034317853u, 2071407475u }, + { 170903528u, 2822471992u, 1322162887u }, + { 2524982332u, 170903528u, 2656231333u } + }, + { + { 3653936868u, 3893194049u, 2484299328u }, + { 1313746234u, 3653936868u, 1705346273u }, + { 1397638018u, 1313746234u, 4015529545u } + }, + { + { 4129760842u, 1671665759u, 1677834656u }, + { 3200005334u, 4129760842u, 3486207172u }, + { 2850728736u, 3200005334u, 3076201597u } + } + }; +#endif // #ifndef __CUDACC_RTC__ + /*Base matrices to power (2 to the power 127) to power 2 to power n+1u, n the first array index, from 0..63*/ + +CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS unsigned int mrg32k3aM1Seq[64][3][3] = { + { + { 2427906178u, 3580155704u, 949770784u }, + { 226153695u, 1230515664u, 3580155704u }, + { 1988835001u, 986791581u, 1230515664u } + }, + { + { 1774047142u, 3199155377u, 3106427820u }, + { 1901920839u, 4290900039u, 3199155377u }, + { 4178980191u, 280623348u, 4290900039u } + }, + { + { 3567524348u, 1934119675u, 3188270128u }, + { 2997767678u, 826363896u, 1934119675u }, + { 262952343u, 614326610u, 826363896u } + }, + { + { 1625613062u, 4288164505u, 2481284279u }, + { 4273461426u, 1177260757u, 4288164505u }, + { 305959988u, 4017252267u, 1177260757u } + }, + { + { 337929267u, 333342539u, 418300166u }, + { 2944208672u, 379097734u, 333342539u }, + { 2084056909u, 3625475947u, 379097734u } + }, + { + { 1189899255u, 1307754719u, 1214919992u }, + { 3736721708u, 3514751918u, 1307754719u }, + { 732435953u, 2021244538u, 3514751918u } + }, + { + { 4089172695u, 1533534334u, 525643282u }, + { 1497577018u, 1335684482u, 1533534334u }, + { 2079007086u, 3977541427u, 1335684482u } + }, + { + { 3075256652u, 2762754934u, 3846844247u }, + { 3057872364u, 3274545167u, 2762754934u }, + { 4028573983u, 938934351u, 3274545167u } + }, + { + { 2597859300u, 2880151048u, 2523330453u }, + { 1121709186u, 175667448u, 2880151048u }, + { 4182510911u, 1723133625u, 175667448u } + }, + { + { 484148868u, 1404283933u, 2982534313u }, + { 3736767353u, 3179865161u, 1404283933u }, + { 391120388u, 3758716888u, 3179865161u } + }, + { + { 2138867468u, 1128973399u, 2133702321u }, + { 1613561693u, 3622350766u, 1128973399u }, + { 1500151924u, 3759983985u, 3622350766u } + }, + { + { 3027706760u, 3786576552u, 2698781808u }, + { 2810527099u, 90498489u, 3786576552u }, + { 4220122612u, 1855245979u, 90498489u } + }, + { + { 3739389517u, 1110440720u, 917457922u }, + { 2163873618u, 3707591763u, 1110440720u }, + { 2667061910u, 2533383962u, 3707591763u } + }, + { + { 1545226000u, 1812182123u, 3693349190u }, + { 3422065122u, 3291428549u, 1812182123u }, + { 1193168720u, 2072837757u, 3291428549u } + }, + { + { 3230096243u, 2131723358u, 3262178024u }, + { 2882890127u, 4088518247u, 2131723358u }, + { 3991553306u, 1282224087u, 4088518247u } + }, + { + { 301207261u, 1722796810u, 3697719854u }, + { 3350228505u, 3410986694u, 1722796810u }, + { 3684514720u, 2846958957u, 3410986694u } + }, + { + { 1532963114u, 4236235786u, 3871128158u }, + { 3540401964u, 1285250577u, 4236235786u }, + { 1105070646u, 2764245175u, 1285250577u } + }, + { + { 210906218u, 3068599594u, 3034582784u }, + { 340633153u, 4004365908u, 3068599594u }, + { 4238928187u, 2299166464u, 4004365908u } + }, + { + { 2274701639u, 3955606166u, 3081246407u }, + { 3199954992u, 3948054919u, 3955606166u }, + { 2399101442u, 3438340286u, 3948054919u } + }, + { + { 504137100u, 1182303684u, 201533985u }, + { 4188299661u, 3042453580u, 1182303684u }, + { 2578519273u, 2674782930u, 3042453580u } + }, + { + { 1382964588u, 2578452047u, 3140440866u }, + { 261861891u, 1076783073u, 2578452047u }, + { 1634588989u, 164438428u, 1076783073u } + }, + { + { 2529186343u, 526867394u, 3102803247u }, + { 2687252475u, 2908898908u, 526867394u }, + { 1213100579u, 86050422u, 2908898908u } + }, + { + { 2690118316u, 538108523u, 790337895u }, + { 4193870709u, 1053552056u, 538108523u }, + { 1635227281u, 4002399925u, 1053552056u } + }, + { + { 2123712957u, 4205383007u, 1812304090u }, + { 1095349745u, 166243972u, 4205383007u }, + { 428569070u, 2128782357u, 166243972u } + }, + { + { 1330151766u, 3569679412u, 4107175982u }, + { 3808641551u, 3621125056u, 3569679412u }, + { 4262164578u, 1927692878u, 3621125056u } + }, + { + { 3606295184u, 2442739556u, 3894922338u }, + { 1629626641u, 2729678535u, 2442739556u }, + { 3379124758u, 4279360935u, 2729678535u } + }, + { + { 1052092278u, 4249024666u, 919210106u }, + { 3253349463u, 3629539480u, 4249024666u }, + { 852514024u, 4025926501u, 3629539480u } + }, + { + { 12394571u, 1252747620u, 2133571953u }, + { 4227339509u, 3197545170u, 1252747620u }, + { 1884529704u, 1976203831u, 3197545170u } + }, + { + { 2986331025u, 2671019282u, 2847338542u }, + { 3173738401u, 3542657885u, 2671019282u }, + { 745203060u, 1546667401u, 3542657885u } + }, + { + { 2613012997u, 2311336951u, 2911336433u }, + { 1493974713u, 92565032u, 2311336951u }, + { 2786645250u, 257065974u, 92565032u } + }, + { + { 3424925004u, 2776053372u, 2204068573u }, + { 3770626858u, 2509257810u, 2776053372u }, + { 2979919489u, 1146336783u, 2509257810u } + }, + { + { 1474384834u, 827894421u, 515339473u }, + { 1373055755u, 1949809417u, 827894421u }, + { 3088339524u, 1194193824u, 1949809417u } + }, + { + { 1825805135u, 1289872272u, 3700877161u }, + { 3433422861u, 4062509844u, 1289872272u }, + { 3019008744u, 2060641859u, 4062509844u } + }, + { + { 3842597153u, 4253338264u, 3424495942u }, + { 698444416u, 60268595u, 4253338264u }, + { 4096010585u, 47309624u, 60268595u } + }, + { + { 2662288323u, 2043518992u, 1593435980u }, + { 1330201507u, 3618850300u, 2043518992u }, + { 2538793204u, 271787962u, 3618850300u } + }, + { + { 741020448u, 997594656u, 2398808739u }, + { 1160477043u, 1522130854u, 997594656u }, + { 3036916315u, 2847712653u, 1522130854u } + }, + { + { 2654964886u, 1889728930u, 53329096u }, + { 2042322941u, 1621136330u, 1889728930u }, + { 1553642730u, 784545882u, 1621136330u } + }, + { + { 1715219514u, 2831829177u, 929124824u }, + { 997274536u, 404228189u, 2831829177u }, + { 1386575385u, 4107238699u, 404228189u } + }, + { + { 3928131551u, 2912523524u, 1840499723u }, + { 4216003022u, 2970489088u, 2912523524u }, + { 1158689953u, 1425511081u, 2970489088u } + }, + { + { 2807004452u, 2510299562u, 271603006u }, + { 2505735035u, 2370490899u, 2510299562u }, + { 10873814u, 2450376936u, 2370490899u } + }, + { + { 2000734342u, 1113679064u, 2502160539u }, + { 1475266926u, 2787925323u, 1113679064u }, + { 1475797635u, 3044470744u, 2787925323u } + }, + { + { 1457157056u, 1252556678u, 3073232607u }, + { 1926798761u, 3639907189u, 1252556678u }, + { 2067740348u, 2256217204u, 3639907189u } + }, + { + { 3740999688u, 1035400458u, 3162437311u }, + { 4126312242u, 686702830u, 1035400458u }, + { 1699805291u, 667792040u, 686702830u } + }, + { + { 2422495016u, 3203768688u, 1858240466u }, + { 848719394u, 4092709154u, 3203768688u }, + { 659945473u, 1863075174u, 4092709154u } + }, + { + { 246817944u, 871751352u, 2834051003u }, + { 3976202597u, 3721214025u, 871751352u }, + { 783929942u, 745295675u, 3721214025u } + }, + { + { 3811740424u, 3603608092u, 2365398362u }, + { 3826150877u, 2906557036u, 3603608092u }, + { 2300510686u, 966815948u, 2906557036u } + }, + { + { 2816329160u, 18201123u, 3367710570u }, + { 437309679u, 2220769388u, 18201123u }, + { 1346863388u, 705296543u, 2220769388u } + }, + { + { 3310028953u, 1662315499u, 132645114u }, + { 2572908401u, 3105849797u, 1662315499u }, + { 1937586849u, 1735620028u, 3105849797u } + }, + { + { 461386353u, 1359675853u, 3599822966u }, + { 106675209u, 2044154050u, 1359675853u }, + { 1787730088u, 1149892630u, 2044154050u } + }, + { + { 3303902397u, 345146034u, 1417149696u }, + { 2231869247u, 1116882637u, 345146034u }, + { 1846832385u, 79626976u, 1116882637u } + }, + { + { 2765049417u, 3117782790u, 1805260159u }, + { 3796182890u, 1101141726u, 3117782790u }, + { 224270120u, 1004001443u, 1101141726u } + }, + { + { 89118668u, 2494198515u, 1356989069u }, + { 2490435731u, 997151755u, 2494198515u }, + { 1175528637u, 3444341166u, 997151755u } + }, + { + { 2340639019u, 510225634u, 286119182u }, + { 2045217287u, 1194574818u, 510225634u }, + { 2662281592u, 1728500627u, 1194574818u } + }, + { + { 210787847u, 1189120688u, 2848040407u }, + { 1087786165u, 2343328484u, 1189120688u }, + { 3465141330u, 2893041005u, 2343328484u } + }, + { + { 3438170226u, 3236285682u, 962036916u }, + { 2873263091u, 215280489u, 3236285682u }, + { 730413847u, 1474823842u, 215280489u } + }, + { + { 1566461658u, 133010024u, 2886695328u }, + { 2835827516u, 653809404u, 133010024u }, + { 3082882924u, 3710942807u, 653809404u } + }, + { + { 4201558916u, 1263786956u, 326001602u }, + { 762846463u, 621546357u, 1263786956u }, + { 2697142404u, 1156650856u, 621546357u } + }, + { + { 2655768102u, 2339029465u, 2430211448u }, + { 2669906627u, 403962847u, 2339029465u }, + { 1483118807u, 639660658u, 403962847u } + }, + { + { 3508595200u, 4228486662u, 754946994u }, + { 1913148390u, 3500531602u, 4228486662u }, + { 24637u, 3773159052u, 3500531602u } + }, + { + { 4024866227u, 1143874914u, 3205058469u }, + { 2970344133u, 2873927273u, 1143874914u }, + { 2167114735u, 4095476435u, 2873927273u } + }, + { + { 1479401095u, 2958366486u, 3027708794u }, + { 2704486034u, 3574053987u, 2958366486u }, + { 3630964515u, 1276667706u, 3574053987u } + }, + { + { 2035927380u, 1363628533u, 818363998u }, + { 3023327955u, 3968427114u, 1363628533u }, + { 1284825950u, 2871663372u, 3968427114u } + }, + { + { 3827747418u, 3897287251u, 4106993377u }, + { 1527779946u, 3221052941u, 3897287251u }, + { 4178727866u, 4281160673u, 3221052941u } + }, + { + { 1174358892u, 2835476193u, 959978619u }, + { 850076464u, 3774782533u, 2835476193u }, + { 3880910680u, 3237990203u, 3774782533u } + } + }; + +#ifndef __CUDACC_RTC__ +CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS unsigned int mrg32k3aM1SeqHost[64][3][3] = { + { + { 2427906178u, 3580155704u, 949770784u }, + { 226153695u, 1230515664u, 3580155704u }, + { 1988835001u, 986791581u, 1230515664u } + }, + { + { 1774047142u, 3199155377u, 3106427820u }, + { 1901920839u, 4290900039u, 3199155377u }, + { 4178980191u, 280623348u, 4290900039u } + }, + { + { 3567524348u, 1934119675u, 3188270128u }, + { 2997767678u, 826363896u, 1934119675u }, + { 262952343u, 614326610u, 826363896u } + }, + { + { 1625613062u, 4288164505u, 2481284279u }, + { 4273461426u, 1177260757u, 4288164505u }, + { 305959988u, 4017252267u, 1177260757u } + }, + { + { 337929267u, 333342539u, 418300166u }, + { 2944208672u, 379097734u, 333342539u }, + { 2084056909u, 3625475947u, 379097734u } + }, + { + { 1189899255u, 1307754719u, 1214919992u }, + { 3736721708u, 3514751918u, 1307754719u }, + { 732435953u, 2021244538u, 3514751918u } + }, + { + { 4089172695u, 1533534334u, 525643282u }, + { 1497577018u, 1335684482u, 1533534334u }, + { 2079007086u, 3977541427u, 1335684482u } + }, + { + { 3075256652u, 2762754934u, 3846844247u }, + { 3057872364u, 3274545167u, 2762754934u }, + { 4028573983u, 938934351u, 3274545167u } + }, + { + { 2597859300u, 2880151048u, 2523330453u }, + { 1121709186u, 175667448u, 2880151048u }, + { 4182510911u, 1723133625u, 175667448u } + }, + { + { 484148868u, 1404283933u, 2982534313u }, + { 3736767353u, 3179865161u, 1404283933u }, + { 391120388u, 3758716888u, 3179865161u } + }, + { + { 2138867468u, 1128973399u, 2133702321u }, + { 1613561693u, 3622350766u, 1128973399u }, + { 1500151924u, 3759983985u, 3622350766u } + }, + { + { 3027706760u, 3786576552u, 2698781808u }, + { 2810527099u, 90498489u, 3786576552u }, + { 4220122612u, 1855245979u, 90498489u } + }, + { + { 3739389517u, 1110440720u, 917457922u }, + { 2163873618u, 3707591763u, 1110440720u }, + { 2667061910u, 2533383962u, 3707591763u } + }, + { + { 1545226000u, 1812182123u, 3693349190u }, + { 3422065122u, 3291428549u, 1812182123u }, + { 1193168720u, 2072837757u, 3291428549u } + }, + { + { 3230096243u, 2131723358u, 3262178024u }, + { 2882890127u, 4088518247u, 2131723358u }, + { 3991553306u, 1282224087u, 4088518247u } + }, + { + { 301207261u, 1722796810u, 3697719854u }, + { 3350228505u, 3410986694u, 1722796810u }, + { 3684514720u, 2846958957u, 3410986694u } + }, + { + { 1532963114u, 4236235786u, 3871128158u }, + { 3540401964u, 1285250577u, 4236235786u }, + { 1105070646u, 2764245175u, 1285250577u } + }, + { + { 210906218u, 3068599594u, 3034582784u }, + { 340633153u, 4004365908u, 3068599594u }, + { 4238928187u, 2299166464u, 4004365908u } + }, + { + { 2274701639u, 3955606166u, 3081246407u }, + { 3199954992u, 3948054919u, 3955606166u }, + { 2399101442u, 3438340286u, 3948054919u } + }, + { + { 504137100u, 1182303684u, 201533985u }, + { 4188299661u, 3042453580u, 1182303684u }, + { 2578519273u, 2674782930u, 3042453580u } + }, + { + { 1382964588u, 2578452047u, 3140440866u }, + { 261861891u, 1076783073u, 2578452047u }, + { 1634588989u, 164438428u, 1076783073u } + }, + { + { 2529186343u, 526867394u, 3102803247u }, + { 2687252475u, 2908898908u, 526867394u }, + { 1213100579u, 86050422u, 2908898908u } + }, + { + { 2690118316u, 538108523u, 790337895u }, + { 4193870709u, 1053552056u, 538108523u }, + { 1635227281u, 4002399925u, 1053552056u } + }, + { + { 2123712957u, 4205383007u, 1812304090u }, + { 1095349745u, 166243972u, 4205383007u }, + { 428569070u, 2128782357u, 166243972u } + }, + { + { 1330151766u, 3569679412u, 4107175982u }, + { 3808641551u, 3621125056u, 3569679412u }, + { 4262164578u, 1927692878u, 3621125056u } + }, + { + { 3606295184u, 2442739556u, 3894922338u }, + { 1629626641u, 2729678535u, 2442739556u }, + { 3379124758u, 4279360935u, 2729678535u } + }, + { + { 1052092278u, 4249024666u, 919210106u }, + { 3253349463u, 3629539480u, 4249024666u }, + { 852514024u, 4025926501u, 3629539480u } + }, + { + { 12394571u, 1252747620u, 2133571953u }, + { 4227339509u, 3197545170u, 1252747620u }, + { 1884529704u, 1976203831u, 3197545170u } + }, + { + { 2986331025u, 2671019282u, 2847338542u }, + { 3173738401u, 3542657885u, 2671019282u }, + { 745203060u, 1546667401u, 3542657885u } + }, + { + { 2613012997u, 2311336951u, 2911336433u }, + { 1493974713u, 92565032u, 2311336951u }, + { 2786645250u, 257065974u, 92565032u } + }, + { + { 3424925004u, 2776053372u, 2204068573u }, + { 3770626858u, 2509257810u, 2776053372u }, + { 2979919489u, 1146336783u, 2509257810u } + }, + { + { 1474384834u, 827894421u, 515339473u }, + { 1373055755u, 1949809417u, 827894421u }, + { 3088339524u, 1194193824u, 1949809417u } + }, + { + { 1825805135u, 1289872272u, 3700877161u }, + { 3433422861u, 4062509844u, 1289872272u }, + { 3019008744u, 2060641859u, 4062509844u } + }, + { + { 3842597153u, 4253338264u, 3424495942u }, + { 698444416u, 60268595u, 4253338264u }, + { 4096010585u, 47309624u, 60268595u } + }, + { + { 2662288323u, 2043518992u, 1593435980u }, + { 1330201507u, 3618850300u, 2043518992u }, + { 2538793204u, 271787962u, 3618850300u } + }, + { + { 741020448u, 997594656u, 2398808739u }, + { 1160477043u, 1522130854u, 997594656u }, + { 3036916315u, 2847712653u, 1522130854u } + }, + { + { 2654964886u, 1889728930u, 53329096u }, + { 2042322941u, 1621136330u, 1889728930u }, + { 1553642730u, 784545882u, 1621136330u } + }, + { + { 1715219514u, 2831829177u, 929124824u }, + { 997274536u, 404228189u, 2831829177u }, + { 1386575385u, 4107238699u, 404228189u } + }, + { + { 3928131551u, 2912523524u, 1840499723u }, + { 4216003022u, 2970489088u, 2912523524u }, + { 1158689953u, 1425511081u, 2970489088u } + }, + { + { 2807004452u, 2510299562u, 271603006u }, + { 2505735035u, 2370490899u, 2510299562u }, + { 10873814u, 2450376936u, 2370490899u } + }, + { + { 2000734342u, 1113679064u, 2502160539u }, + { 1475266926u, 2787925323u, 1113679064u }, + { 1475797635u, 3044470744u, 2787925323u } + }, + { + { 1457157056u, 1252556678u, 3073232607u }, + { 1926798761u, 3639907189u, 1252556678u }, + { 2067740348u, 2256217204u, 3639907189u } + }, + { + { 3740999688u, 1035400458u, 3162437311u }, + { 4126312242u, 686702830u, 1035400458u }, + { 1699805291u, 667792040u, 686702830u } + }, + { + { 2422495016u, 3203768688u, 1858240466u }, + { 848719394u, 4092709154u, 3203768688u }, + { 659945473u, 1863075174u, 4092709154u } + }, + { + { 246817944u, 871751352u, 2834051003u }, + { 3976202597u, 3721214025u, 871751352u }, + { 783929942u, 745295675u, 3721214025u } + }, + { + { 3811740424u, 3603608092u, 2365398362u }, + { 3826150877u, 2906557036u, 3603608092u }, + { 2300510686u, 966815948u, 2906557036u } + }, + { + { 2816329160u, 18201123u, 3367710570u }, + { 437309679u, 2220769388u, 18201123u }, + { 1346863388u, 705296543u, 2220769388u } + }, + { + { 3310028953u, 1662315499u, 132645114u }, + { 2572908401u, 3105849797u, 1662315499u }, + { 1937586849u, 1735620028u, 3105849797u } + }, + { + { 461386353u, 1359675853u, 3599822966u }, + { 106675209u, 2044154050u, 1359675853u }, + { 1787730088u, 1149892630u, 2044154050u } + }, + { + { 3303902397u, 345146034u, 1417149696u }, + { 2231869247u, 1116882637u, 345146034u }, + { 1846832385u, 79626976u, 1116882637u } + }, + { + { 2765049417u, 3117782790u, 1805260159u }, + { 3796182890u, 1101141726u, 3117782790u }, + { 224270120u, 1004001443u, 1101141726u } + }, + { + { 89118668u, 2494198515u, 1356989069u }, + { 2490435731u, 997151755u, 2494198515u }, + { 1175528637u, 3444341166u, 997151755u } + }, + { + { 2340639019u, 510225634u, 286119182u }, + { 2045217287u, 1194574818u, 510225634u }, + { 2662281592u, 1728500627u, 1194574818u } + }, + { + { 210787847u, 1189120688u, 2848040407u }, + { 1087786165u, 2343328484u, 1189120688u }, + { 3465141330u, 2893041005u, 2343328484u } + }, + { + { 3438170226u, 3236285682u, 962036916u }, + { 2873263091u, 215280489u, 3236285682u }, + { 730413847u, 1474823842u, 215280489u } + }, + { + { 1566461658u, 133010024u, 2886695328u }, + { 2835827516u, 653809404u, 133010024u }, + { 3082882924u, 3710942807u, 653809404u } + }, + { + { 4201558916u, 1263786956u, 326001602u }, + { 762846463u, 621546357u, 1263786956u }, + { 2697142404u, 1156650856u, 621546357u } + }, + { + { 2655768102u, 2339029465u, 2430211448u }, + { 2669906627u, 403962847u, 2339029465u }, + { 1483118807u, 639660658u, 403962847u } + }, + { + { 3508595200u, 4228486662u, 754946994u }, + { 1913148390u, 3500531602u, 4228486662u }, + { 24637u, 3773159052u, 3500531602u } + }, + { + { 4024866227u, 1143874914u, 3205058469u }, + { 2970344133u, 2873927273u, 1143874914u }, + { 2167114735u, 4095476435u, 2873927273u } + }, + { + { 1479401095u, 2958366486u, 3027708794u }, + { 2704486034u, 3574053987u, 2958366486u }, + { 3630964515u, 1276667706u, 3574053987u } + }, + { + { 2035927380u, 1363628533u, 818363998u }, + { 3023327955u, 3968427114u, 1363628533u }, + { 1284825950u, 2871663372u, 3968427114u } + }, + { + { 3827747418u, 3897287251u, 4106993377u }, + { 1527779946u, 3221052941u, 3897287251u }, + { 4178727866u, 4281160673u, 3221052941u } + }, + { + { 1174358892u, 2835476193u, 959978619u }, + { 850076464u, 3774782533u, 2835476193u }, + { 3880910680u, 3237990203u, 3774782533u } + } + }; +#endif // #ifndef __CUDACC_RTC__ + +CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS unsigned int mrg32k3aM2Seq[64][3][3] = { + { + { 1464411153u, 277697599u, 1610723613u }, + { 32183930u, 1464411153u, 1022607788u }, + { 2824425944u, 32183930u, 2093834863u } + }, + { + { 3492361727u, 1027004383u, 3167429889u }, + { 3674905362u, 3492361727u, 3572939265u }, + { 4270409313u, 3674905362u, 698814233u } + }, + { + { 880482061u, 205175925u, 4070445105u }, + { 2208329119u, 880482061u, 1933248566u }, + { 3741227945u, 2208329119u, 3962062826u } + }, + { + { 4184605179u, 1189429800u, 567967482u }, + { 107217966u, 4184605179u, 784865788u }, + { 549462420u, 107217966u, 3134382704u } + }, + { + { 2732536445u, 1231107067u, 3374588386u }, + { 409954030u, 2732536445u, 1044831206u }, + { 3398162498u, 409954030u, 3505648581u } + }, + { + { 2169560691u, 1076348534u, 637306236u }, + { 3704346564u, 2169560691u, 293694496u }, + { 632453145u, 3704346564u, 1609425246u } + }, + { + { 372115891u, 3928812480u, 2830541169u }, + { 3056527841u, 372115891u, 1924239834u }, + { 3044937468u, 3056527841u, 547142630u } + }, + { + { 1660852083u, 3635660815u, 1389092450u }, + { 1025573319u, 1660852083u, 3276803366u }, + { 4036331438u, 1025573319u, 4092197741u } + }, + { + { 1360732901u, 2887812973u, 4101068693u }, + { 52572783u, 1360732901u, 112458461u }, + { 2636566855u, 52572783u, 1136777988u } + }, + { + { 3455696508u, 536919193u, 3978804036u }, + { 3094157668u, 3455696508u, 3821833900u }, + { 2278849016u, 3094157668u, 2531965909u } + }, + { + { 2125991744u, 890897326u, 3790557569u }, + { 1433592392u, 2125991744u, 3671109604u }, + { 808215503u, 1433592392u, 2446306581u } + }, + { + { 3524411799u, 932865240u, 1838275365u }, + { 1789634890u, 3524411799u, 4130736474u }, + { 2252266098u, 1789634890u, 3048775967u } + }, + { + { 1773339925u, 948403862u, 1999624391u }, + { 983864203u, 1773339925u, 3734776305u }, + { 314407045u, 983864203u, 2648614071u } + }, + { + { 321802921u, 1099164995u, 2112167358u }, + { 3760936985u, 321802921u, 1003573324u }, + { 3758858458u, 3760936985u, 4014658840u } + }, + { + { 2196438580u, 805386227u, 4266375092u }, + { 4124675351u, 2196438580u, 2527961345u }, + { 94452540u, 4124675351u, 2825656399u } + }, + { + { 66735368u, 2228005807u, 4186703168u }, + { 2624855312u, 66735368u, 2708679078u }, + { 4098470056u, 2624855312u, 1773862183u } + }, + { + { 3072642883u, 2746897053u, 2690305546u }, + { 1105106652u, 3072642883u, 4047666135u }, + { 2862886282u, 1105106652u, 3597347398u } + }, + { + { 232906611u, 3873338256u, 4051554873u }, + { 3027413363u, 232906611u, 3159432673u }, + { 3872967050u, 3027413363u, 987156327u } + }, + { + { 1160686753u, 3676603152u, 1635979789u }, + { 1447386846u, 1160686753u, 2670438424u }, + { 816212890u, 1447386846u, 4288868534u } + }, + { + { 3825238244u, 1445162354u, 2362389441u }, + { 3440193648u, 3825238244u, 3520937545u }, + { 2652790808u, 3440193648u, 405299994u } + }, + { + { 1984094858u, 532165989u, 2027397575u }, + { 1455977136u, 1984094858u, 2433255524u }, + { 1039994763u, 1455977136u, 2069333087u } + }, + { + { 3680843319u, 2332949611u, 3516795313u }, + { 2033851810u, 3680843319u, 3843367307u }, + { 3686294589u, 2033851810u, 3912995069u } + }, + { + { 967423689u, 1724183394u, 635932799u }, + { 641380480u, 967423689u, 2145297779u }, + { 1723000412u, 641380480u, 455633660u } + }, + { + { 2130938335u, 1534972306u, 2511584766u }, + { 273828453u, 2130938335u, 3112810093u }, + { 4084843716u, 273828453u, 1399334152u } + }, + { + { 168278549u, 541167592u, 190177712u }, + { 403188859u, 168278549u, 2092073970u }, + { 58789558u, 403188859u, 2777887189u } + }, + { + { 634843389u, 4082275720u, 2092828966u }, + { 351187677u, 634843389u, 1312056270u }, + { 3347241070u, 351187677u, 2417192332u } + }, + { + { 443276110u, 1113643788u, 271102234u }, + { 3083745876u, 443276110u, 3370743767u }, + { 4200577503u, 3083745876u, 3298601960u } + }, + { + { 3533393557u, 764977733u, 3400275098u }, + { 144639933u, 3533393557u, 2646475951u }, + { 77963866u, 144639933u, 3794766611u } + }, + { + { 4064854722u, 1198665008u, 2872196602u }, + { 3274748603u, 4064854722u, 4164637970u }, + { 4238693771u, 3274748603u, 1981721347u } + }, + { + { 2279220396u, 2355957139u, 1417574285u }, + { 885864931u, 2279220396u, 1344421653u }, + { 1895527787u, 885864931u, 3726919367u } + }, + { + { 2898100178u, 2427331008u, 348923199u }, + { 3175444953u, 2898100178u, 4290541487u }, + { 246118669u, 3175444953u, 3410622769u } + }, + { + { 284442065u, 4064194676u, 2295560707u }, + { 4182706556u, 284442065u, 3696899246u }, + { 1201342255u, 4182706556u, 1145356382u } + }, + { + { 656615546u, 442908965u, 3724738272u }, + { 1624967553u, 656615546u, 798014134u }, + { 1157949454u, 1624967553u, 496247378u } + }, + { + { 265689579u, 675056541u, 3009083380u }, + { 3820679930u, 265689579u, 2961990151u }, + { 562287964u, 3820679930u, 1853486796u } + }, + { + { 1675739167u, 2319843005u, 760605578u }, + { 4161492847u, 1675739167u, 226142150u }, + { 1017447188u, 4161492847u, 3431158427u } + }, + { + { 1759873736u, 2334568602u, 2154570180u }, + { 1812793060u, 1759873736u, 2111094408u }, + { 1168460586u, 1812793060u, 2495653141u } + }, + { + { 317621194u, 868104288u, 664971082u }, + { 2340275074u, 317621194u, 2168960688u }, + { 725706104u, 2340275074u, 3532023115u } + }, + { + { 3926931954u, 2907684453u, 615601328u }, + { 1132340715u, 3926931954u, 676995757u }, + { 1154819290u, 1132340715u, 1662727700u } + }, + { + { 3921782078u, 3376494857u, 2969567377u }, + { 475345024u, 3921782078u, 4206379953u }, + { 1795936544u, 475345024u, 934679595u } + }, + { + { 3119292228u, 741613041u, 2083352304u }, + { 1047885963u, 3119292228u, 1581078542u }, + { 1065969969u, 1047885963u, 661718928u } + }, + { + { 3643472111u, 2870554228u, 3995474529u }, + { 3804264051u, 3643472111u, 1366457944u }, + { 1246805564u, 3804264051u, 993186530u } + }, + { + { 796711791u, 3878204845u, 3160293932u }, + { 255632881u, 796711791u, 3778927111u }, + { 3472564181u, 255632881u, 388382377u } + }, + { + { 1776984101u, 1742284034u, 3449763933u }, + { 1349354417u, 1776984101u, 1264780832u }, + { 715722511u, 1349354417u, 1213319489u } + }, + { + { 4261866865u, 1914382786u, 201872335u }, + { 614207188u, 4261866865u, 1853554849u }, + { 2046042882u, 614207188u, 3193186353u } + }, + { + { 2210205512u, 2847073169u, 3324925707u }, + { 1251969297u, 2210205512u, 3491451503u }, + { 470400916u, 1251969297u, 2184392547u } + }, + { + { 1523590942u, 2391111113u, 68341529u }, + { 295466806u, 1523590942u, 4143310876u }, + { 3527253079u, 295466806u, 4059123142u } + }, + { + { 1406902110u, 3735012720u, 1774518130u }, + { 1814959027u, 1406902110u, 1560544267u }, + { 346472965u, 1814959027u, 964257199u } + }, + { + { 855309653u, 4208503105u, 1518467541u }, + { 2025248418u, 855309653u, 4148125749u }, + { 1349947330u, 2025248418u, 1168504873u } + }, + { + { 2375338156u, 3629519168u, 409696181u }, + { 252401654u, 2375338156u, 3992097193u }, + { 2793725401u, 252401654u, 1350184085u } + }, + { + { 873141039u, 3885583138u, 361604799u }, + { 3554143374u, 873141039u, 894746180u }, + { 1919765327u, 3554143374u, 876210854u } + }, + { + { 246368794u, 1703793169u, 2317362874u }, + { 2300930144u, 246368794u, 2560214589u }, + { 2016163623u, 2300930144u, 1504276775u } + }, + { + { 1574610921u, 2147546631u, 4103450226u }, + { 107416526u, 1574610921u, 1773803959u }, + { 1402542742u, 107416526u, 550063800u } + }, + { + { 363388665u, 592194244u, 1746615522u }, + { 2637234667u, 363388665u, 4031408742u }, + { 2895130475u, 2637234667u, 296510335u } + }, + { + { 3997368560u, 3047771871u, 3178383826u }, + { 1160174754u, 3997368560u, 4027094919u }, + { 1234984211u, 1160174754u, 4226264344u } + }, + { + { 3303179301u, 4243968063u, 3235964171u }, + { 1776841674u, 3303179301u, 2867287469u }, + { 1500495759u, 1776841674u, 1708226553u } + }, + { + { 1482944153u, 3192311574u, 354466071u }, + { 3932773012u, 1482944153u, 389193591u }, + { 3350181058u, 3932773012u, 3398059015u } + }, + { + { 640968550u, 3226860971u, 922372912u }, + { 1254989667u, 640968550u, 2383815228u }, + { 2027371896u, 1254989667u, 2925300409u } + }, + { + { 2313146046u, 3910187183u, 1377591475u }, + { 1689291784u, 2313146046u, 4255405993u }, + { 1650609719u, 1689291784u, 1897624297u } + }, + { + { 3656310954u, 882924050u, 2702189958u }, + { 3185020283u, 3656310954u, 1923190496u }, + { 2449669145u, 3185020283u, 4235849984u } + }, + { + { 377232416u, 1498446142u, 4229103619u }, + { 3926377906u, 377232416u, 600268838u }, + { 511317726u, 3926377906u, 216160452u } + }, + { + { 1969399344u, 3273966859u, 4220943579u }, + { 3952111894u, 1969399344u, 575096961u }, + { 3815277103u, 3952111894u, 792177412u } + }, + { + { 2957238169u, 1410010554u, 1523740068u }, + { 3949237584u, 2957238169u, 74149658u }, + { 2564746147u, 3949237584u, 2557663578u } + }, + { + { 3377318569u, 1927835240u, 2556102508u }, + { 3022040116u, 3377318569u, 2549406364u }, + { 2387074241u, 3022040116u, 1477293711u } + }, + { + { 257306870u, 1748489735u, 547809226u }, + { 3708493374u, 257306870u, 4183546362u }, + { 4435502u, 3708493374u, 1607696753u } + } + }; + +#ifndef __CUDACC_RTC__ +CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS unsigned int mrg32k3aM2SeqHost[64][3][3] = { + { + { 1464411153u, 277697599u, 1610723613u }, + { 32183930u, 1464411153u, 1022607788u }, + { 2824425944u, 32183930u, 2093834863u } + }, + { + { 3492361727u, 1027004383u, 3167429889u }, + { 3674905362u, 3492361727u, 3572939265u }, + { 4270409313u, 3674905362u, 698814233u } + }, + { + { 880482061u, 205175925u, 4070445105u }, + { 2208329119u, 880482061u, 1933248566u }, + { 3741227945u, 2208329119u, 3962062826u } + }, + { + { 4184605179u, 1189429800u, 567967482u }, + { 107217966u, 4184605179u, 784865788u }, + { 549462420u, 107217966u, 3134382704u } + }, + { + { 2732536445u, 1231107067u, 3374588386u }, + { 409954030u, 2732536445u, 1044831206u }, + { 3398162498u, 409954030u, 3505648581u } + }, + { + { 2169560691u, 1076348534u, 637306236u }, + { 3704346564u, 2169560691u, 293694496u }, + { 632453145u, 3704346564u, 1609425246u } + }, + { + { 372115891u, 3928812480u, 2830541169u }, + { 3056527841u, 372115891u, 1924239834u }, + { 3044937468u, 3056527841u, 547142630u } + }, + { + { 1660852083u, 3635660815u, 1389092450u }, + { 1025573319u, 1660852083u, 3276803366u }, + { 4036331438u, 1025573319u, 4092197741u } + }, + { + { 1360732901u, 2887812973u, 4101068693u }, + { 52572783u, 1360732901u, 112458461u }, + { 2636566855u, 52572783u, 1136777988u } + }, + { + { 3455696508u, 536919193u, 3978804036u }, + { 3094157668u, 3455696508u, 3821833900u }, + { 2278849016u, 3094157668u, 2531965909u } + }, + { + { 2125991744u, 890897326u, 3790557569u }, + { 1433592392u, 2125991744u, 3671109604u }, + { 808215503u, 1433592392u, 2446306581u } + }, + { + { 3524411799u, 932865240u, 1838275365u }, + { 1789634890u, 3524411799u, 4130736474u }, + { 2252266098u, 1789634890u, 3048775967u } + }, + { + { 1773339925u, 948403862u, 1999624391u }, + { 983864203u, 1773339925u, 3734776305u }, + { 314407045u, 983864203u, 2648614071u } + }, + { + { 321802921u, 1099164995u, 2112167358u }, + { 3760936985u, 321802921u, 1003573324u }, + { 3758858458u, 3760936985u, 4014658840u } + }, + { + { 2196438580u, 805386227u, 4266375092u }, + { 4124675351u, 2196438580u, 2527961345u }, + { 94452540u, 4124675351u, 2825656399u } + }, + { + { 66735368u, 2228005807u, 4186703168u }, + { 2624855312u, 66735368u, 2708679078u }, + { 4098470056u, 2624855312u, 1773862183u } + }, + { + { 3072642883u, 2746897053u, 2690305546u }, + { 1105106652u, 3072642883u, 4047666135u }, + { 2862886282u, 1105106652u, 3597347398u } + }, + { + { 232906611u, 3873338256u, 4051554873u }, + { 3027413363u, 232906611u, 3159432673u }, + { 3872967050u, 3027413363u, 987156327u } + }, + { + { 1160686753u, 3676603152u, 1635979789u }, + { 1447386846u, 1160686753u, 2670438424u }, + { 816212890u, 1447386846u, 4288868534u } + }, + { + { 3825238244u, 1445162354u, 2362389441u }, + { 3440193648u, 3825238244u, 3520937545u }, + { 2652790808u, 3440193648u, 405299994u } + }, + { + { 1984094858u, 532165989u, 2027397575u }, + { 1455977136u, 1984094858u, 2433255524u }, + { 1039994763u, 1455977136u, 2069333087u } + }, + { + { 3680843319u, 2332949611u, 3516795313u }, + { 2033851810u, 3680843319u, 3843367307u }, + { 3686294589u, 2033851810u, 3912995069u } + }, + { + { 967423689u, 1724183394u, 635932799u }, + { 641380480u, 967423689u, 2145297779u }, + { 1723000412u, 641380480u, 455633660u } + }, + { + { 2130938335u, 1534972306u, 2511584766u }, + { 273828453u, 2130938335u, 3112810093u }, + { 4084843716u, 273828453u, 1399334152u } + }, + { + { 168278549u, 541167592u, 190177712u }, + { 403188859u, 168278549u, 2092073970u }, + { 58789558u, 403188859u, 2777887189u } + }, + { + { 634843389u, 4082275720u, 2092828966u }, + { 351187677u, 634843389u, 1312056270u }, + { 3347241070u, 351187677u, 2417192332u } + }, + { + { 443276110u, 1113643788u, 271102234u }, + { 3083745876u, 443276110u, 3370743767u }, + { 4200577503u, 3083745876u, 3298601960u } + }, + { + { 3533393557u, 764977733u, 3400275098u }, + { 144639933u, 3533393557u, 2646475951u }, + { 77963866u, 144639933u, 3794766611u } + }, + { + { 4064854722u, 1198665008u, 2872196602u }, + { 3274748603u, 4064854722u, 4164637970u }, + { 4238693771u, 3274748603u, 1981721347u } + }, + { + { 2279220396u, 2355957139u, 1417574285u }, + { 885864931u, 2279220396u, 1344421653u }, + { 1895527787u, 885864931u, 3726919367u } + }, + { + { 2898100178u, 2427331008u, 348923199u }, + { 3175444953u, 2898100178u, 4290541487u }, + { 246118669u, 3175444953u, 3410622769u } + }, + { + { 284442065u, 4064194676u, 2295560707u }, + { 4182706556u, 284442065u, 3696899246u }, + { 1201342255u, 4182706556u, 1145356382u } + }, + { + { 656615546u, 442908965u, 3724738272u }, + { 1624967553u, 656615546u, 798014134u }, + { 1157949454u, 1624967553u, 496247378u } + }, + { + { 265689579u, 675056541u, 3009083380u }, + { 3820679930u, 265689579u, 2961990151u }, + { 562287964u, 3820679930u, 1853486796u } + }, + { + { 1675739167u, 2319843005u, 760605578u }, + { 4161492847u, 1675739167u, 226142150u }, + { 1017447188u, 4161492847u, 3431158427u } + }, + { + { 1759873736u, 2334568602u, 2154570180u }, + { 1812793060u, 1759873736u, 2111094408u }, + { 1168460586u, 1812793060u, 2495653141u } + }, + { + { 317621194u, 868104288u, 664971082u }, + { 2340275074u, 317621194u, 2168960688u }, + { 725706104u, 2340275074u, 3532023115u } + }, + { + { 3926931954u, 2907684453u, 615601328u }, + { 1132340715u, 3926931954u, 676995757u }, + { 1154819290u, 1132340715u, 1662727700u } + }, + { + { 3921782078u, 3376494857u, 2969567377u }, + { 475345024u, 3921782078u, 4206379953u }, + { 1795936544u, 475345024u, 934679595u } + }, + { + { 3119292228u, 741613041u, 2083352304u }, + { 1047885963u, 3119292228u, 1581078542u }, + { 1065969969u, 1047885963u, 661718928u } + }, + { + { 3643472111u, 2870554228u, 3995474529u }, + { 3804264051u, 3643472111u, 1366457944u }, + { 1246805564u, 3804264051u, 993186530u } + }, + { + { 796711791u, 3878204845u, 3160293932u }, + { 255632881u, 796711791u, 3778927111u }, + { 3472564181u, 255632881u, 388382377u } + }, + { + { 1776984101u, 1742284034u, 3449763933u }, + { 1349354417u, 1776984101u, 1264780832u }, + { 715722511u, 1349354417u, 1213319489u } + }, + { + { 4261866865u, 1914382786u, 201872335u }, + { 614207188u, 4261866865u, 1853554849u }, + { 2046042882u, 614207188u, 3193186353u } + }, + { + { 2210205512u, 2847073169u, 3324925707u }, + { 1251969297u, 2210205512u, 3491451503u }, + { 470400916u, 1251969297u, 2184392547u } + }, + { + { 1523590942u, 2391111113u, 68341529u }, + { 295466806u, 1523590942u, 4143310876u }, + { 3527253079u, 295466806u, 4059123142u } + }, + { + { 1406902110u, 3735012720u, 1774518130u }, + { 1814959027u, 1406902110u, 1560544267u }, + { 346472965u, 1814959027u, 964257199u } + }, + { + { 855309653u, 4208503105u, 1518467541u }, + { 2025248418u, 855309653u, 4148125749u }, + { 1349947330u, 2025248418u, 1168504873u } + }, + { + { 2375338156u, 3629519168u, 409696181u }, + { 252401654u, 2375338156u, 3992097193u }, + { 2793725401u, 252401654u, 1350184085u } + }, + { + { 873141039u, 3885583138u, 361604799u }, + { 3554143374u, 873141039u, 894746180u }, + { 1919765327u, 3554143374u, 876210854u } + }, + { + { 246368794u, 1703793169u, 2317362874u }, + { 2300930144u, 246368794u, 2560214589u }, + { 2016163623u, 2300930144u, 1504276775u } + }, + { + { 1574610921u, 2147546631u, 4103450226u }, + { 107416526u, 1574610921u, 1773803959u }, + { 1402542742u, 107416526u, 550063800u } + }, + { + { 363388665u, 592194244u, 1746615522u }, + { 2637234667u, 363388665u, 4031408742u }, + { 2895130475u, 2637234667u, 296510335u } + }, + { + { 3997368560u, 3047771871u, 3178383826u }, + { 1160174754u, 3997368560u, 4027094919u }, + { 1234984211u, 1160174754u, 4226264344u } + }, + { + { 3303179301u, 4243968063u, 3235964171u }, + { 1776841674u, 3303179301u, 2867287469u }, + { 1500495759u, 1776841674u, 1708226553u } + }, + { + { 1482944153u, 3192311574u, 354466071u }, + { 3932773012u, 1482944153u, 389193591u }, + { 3350181058u, 3932773012u, 3398059015u } + }, + { + { 640968550u, 3226860971u, 922372912u }, + { 1254989667u, 640968550u, 2383815228u }, + { 2027371896u, 1254989667u, 2925300409u } + }, + { + { 2313146046u, 3910187183u, 1377591475u }, + { 1689291784u, 2313146046u, 4255405993u }, + { 1650609719u, 1689291784u, 1897624297u } + }, + { + { 3656310954u, 882924050u, 2702189958u }, + { 3185020283u, 3656310954u, 1923190496u }, + { 2449669145u, 3185020283u, 4235849984u } + }, + { + { 377232416u, 1498446142u, 4229103619u }, + { 3926377906u, 377232416u, 600268838u }, + { 511317726u, 3926377906u, 216160452u } + }, + { + { 1969399344u, 3273966859u, 4220943579u }, + { 3952111894u, 1969399344u, 575096961u }, + { 3815277103u, 3952111894u, 792177412u } + }, + { + { 2957238169u, 1410010554u, 1523740068u }, + { 3949237584u, 2957238169u, 74149658u }, + { 2564746147u, 3949237584u, 2557663578u } + }, + { + { 3377318569u, 1927835240u, 2556102508u }, + { 3022040116u, 3377318569u, 2549406364u }, + { 2387074241u, 3022040116u, 1477293711u } + }, + { + { 257306870u, 1748489735u, 547809226u }, + { 3708493374u, 257306870u, 4183546362u }, + { 4435502u, 3708493374u, 1607696753u } + } + }; +#endif // ifndef __CUDACC_RTC__ + +#ifdef CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS +#undef CURAND_MRG32K3A_MATRICES_DEVICE_QUALIFIERS +#endif + +#ifdef CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS +#undef CURAND_MRG32K3A_MATRICES_HOST_QUALIFIERS +#endif + +#endif /* !defined(CURAND_MRG32K3A_MATRICES_H_) */ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32.h new file mode 100644 index 0000000000000000000000000000000000000000..ab8a5a5b78629ba86dbb996a7561b415e90dfb53 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32.h @@ -0,0 +1,210 @@ +/* + * Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +#ifndef CURAND_MTGP32_H +#define CURAND_MTGP32_H +/* + * @file curand_mtgp32.h + * + * @brief Mersenne Twister for Graphic Processors (mtgp32), which + * generates 32-bit unsigned integers and single precision floating + * point numbers based on IEEE 754 format. + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (Hiroshima University) + * + */ +/* + * Copyright (c) 2009, 2010 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * Copyright (c) 2011 Mutsuo Saito, Makoto Matsumoto, Hiroshima + * University and University of Tokyo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Hiroshima University nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#define MTGPDC_MEXP 11213 +#define MTGPDC_N 351 +#define MTGPDC_FLOOR_2P 256 +#define MTGPDC_CEIL_2P 512 +#define MTGPDC_PARAM_TABLE mtgp32dc_params_fast_11213 +#define MTGP32_STATE_SIZE 1024 +#define MTGP32_STATE_MASK 1023 +#define CURAND_NUM_MTGP32_PARAMS 200 +#define MEXP 11213 +#define THREAD_NUM MTGPDC_FLOOR_2P +#define LARGE_SIZE (THREAD_NUM * 3) +#define TBL_SIZE 16 + +/** + * \addtogroup DEVICE Device API + * + * @{ + */ + +/* + * \struct MTGP32_PARAMS_FAST_T + * MTGP32 parameters. + * Some element is redundant to keep structure simple. + * + * \b pos is a pick up position which is selected to have good + * performance on graphic processors. 3 < \b pos < Q, where Q is a + * maximum number such that the size of status array - Q is a power of + * 2. For example, when \b mexp is 44497, size of 32-bit status array + * is 696, and Q is 184, then \b pos is between 4 and 183. This means + * 512 parallel calculations is allowed when \b mexp is 44497. + * + * \b poly_sha1 is SHA1 digest of the characteristic polynomial of + * state transition function. SHA1 is calculated based on printing + * form of the polynomial. This is important when we use parameters + * generated by the dynamic creator which + * + * \b mask This is a mask to make the dimension of state space have + * just Mersenne Prime. This is redundant. + */ + +struct mtgp32_params_fast; + +struct mtgp32_params_fast { + int mexp; /*< Mersenne exponent. This is redundant. */ + int pos; /*< pick up position. */ + int sh1; /*< shift value 1. 0 < sh1 < 32. */ + int sh2; /*< shift value 2. 0 < sh2 < 32. */ + unsigned int tbl[16]; /*< a small matrix. */ + unsigned int tmp_tbl[16]; /*< a small matrix for tempering. */ + unsigned int flt_tmp_tbl[16]; /*< a small matrix for tempering and + converting to float. */ + unsigned int mask; /*< This is a mask for state space */ + unsigned char poly_sha1[21]; /*< SHA1 digest */ +}; + +/** \cond UNHIDE_TYPEDEFS */ +typedef struct mtgp32_params_fast mtgp32_params_fast_t; +/** \endcond */ + +/* + * Generator Parameters. + */ +struct mtgp32_kernel_params; +struct mtgp32_kernel_params { + unsigned int pos_tbl[CURAND_NUM_MTGP32_PARAMS]; + unsigned int param_tbl[CURAND_NUM_MTGP32_PARAMS][TBL_SIZE]; + unsigned int temper_tbl[CURAND_NUM_MTGP32_PARAMS][TBL_SIZE]; + unsigned int single_temper_tbl[CURAND_NUM_MTGP32_PARAMS][TBL_SIZE]; + unsigned int sh1_tbl[CURAND_NUM_MTGP32_PARAMS]; + unsigned int sh2_tbl[CURAND_NUM_MTGP32_PARAMS]; + unsigned int mask[1]; +}; + +/** \cond UNHIDE_TYPEDEFS */ +typedef struct mtgp32_kernel_params mtgp32_kernel_params_t; +/** \endcond */ + + + +/* + * kernel I/O + * This structure must be initialized before first use. + */ + +/* MTGP (Mersenne Twister) RNG */ +/* This generator uses the Mersenne Twister algorithm of + * http://arxiv.org/abs/1005.4973v2 + * Has period 2^11213. +*/ + +/** + * CURAND MTGP32 state + */ +struct curandStateMtgp32; + +struct curandStateMtgp32 { + unsigned int s[MTGP32_STATE_SIZE]; + int offset; + int pIdx; + mtgp32_kernel_params_t * k; +}; + +/* + * CURAND MTGP32 state + */ +/** \cond UNHIDE_TYPEDEFS */ +typedef struct curandStateMtgp32 curandStateMtgp32_t; +/** \endcond */ + +/** @} */ + +#endif + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32_host.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32_host.h new file mode 100644 index 0000000000000000000000000000000000000000..7b9a2d31b314194e6999aeb7046db67b6c9e19ac --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32_host.h @@ -0,0 +1,516 @@ +/* + * Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +/* + * curand_mtgp32_host.h + * + * + * MTGP32-11213 + * + * Mersenne Twister RNG for the GPU + * + * The period of generated integers is 211213-1. + * + * This code generates 32-bit unsigned integers, and + * single precision floating point numbers uniformly distributed + * in the range [1, 2). (float r; 1.0 <= r < 2.0) + */ + +/* + * Copyright (c) 2009, 2010 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * Copyright (c) 2011 Mutsuo Saito, Makoto Matsumoto, Hiroshima + * University and University of Tokyo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Hiroshima University nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#if !defined CURAND_MTGP32_HOST_H +#define CURAND_MTGP32_HOST_H + +#if !defined(QUALIFIERS) +#define QUALIFIERS static inline __device__ +#endif + +#include +#include +#include +#include +#include "curand.h" +#include "curand_mtgp32.h" +#include "curand_mtgp32dc_p_11213.h" + + +/** + * \addtogroup DEVICE Device API + * + * @{ + */ + +static const unsigned int non_zero = 0x4d544750; + +/* + * This function represents a function used in the initialization + * by mtgp32_init_by_array() and mtgp32_init_by_str(). + * @param[in] x 32-bit integer + * @return 32-bit integer + */ +static __forceinline__ unsigned int ini_func1(unsigned int x) { + return (x ^ (x >> 27)) * (1664525); +} + +/* + * This function represents a function used in the initialization + * by mtgp32_init_by_array() and mtgp32_init_by_str(). + * @param[in] x 32-bit integer + * @return 32-bit integer + */ +static __forceinline__ unsigned int ini_func2(unsigned int x) { + return (x ^ (x >> 27)) * (1566083941); +} + +/* + * This function initializes the internal state array with a 32-bit + * integer seed. The allocated memory should be freed by calling + * mtgp32_free(). \b para should be one of the elements in the + * parameter table (mtgp32-param-ref.c). + * + * This function is call by cuda program, because cuda program uses + * another structure and another allocation method. + * + * @param[out] array MTGP internal status vector. + * @param[in] para parameter structure + * @param[in] seed a 32-bit integer used as the seed. + */ +static __forceinline__ __host__ +void mtgp32_init_state(unsigned int state[], + const mtgp32_params_fast_t *para, unsigned int seed) { + int i; + int size = para->mexp / 32 + 1; + unsigned int hidden_seed; + unsigned int tmp; + hidden_seed = para->tbl[4] ^ (para->tbl[8] << 16); + tmp = hidden_seed; + tmp += tmp >> 16; + tmp += tmp >> 8; + memset(state, tmp & 0xff, sizeof(unsigned int) * size); + state[0] = seed; + state[1] = hidden_seed; + for (i = 1; i < size; i++) { + state[i] ^= (1812433253) * (state[i - 1] ^ (state[i - 1] >> 30)) + i; + } +} + +/* + * This function initializes the internal state array + * with a 32-bit integer array. \b para should be one of the elements in + * the parameter table (mtgp32-param-ref.c). + * + * @param[out] mtgp32 MTGP structure. + * @param[in] para parameter structure + * @param[in] array a 32-bit integer array used as a seed. + * @param[in] length length of the array. + * @return CURAND_STATUS_SUCCESS + */ +static __forceinline__ __host__ +int mtgp32_init_by_array(unsigned int state[], + const mtgp32_params_fast_t *para, + unsigned int *array, int length) { + int i, j, count; + unsigned int r; + int lag; + int mid; + int size = para->mexp / 32 + 1; + unsigned int hidden_seed; + unsigned int tmp; + + if (size >= 623) { + lag = 11; + } else if (size >= 68) { + lag = 7; + } else if (size >= 39) { + lag = 5; + } else { + lag = 3; + } + mid = (size - lag) / 2; + + hidden_seed = para->tbl[4] ^ (para->tbl[8] << 16); + tmp = hidden_seed; + tmp += tmp >> 16; + tmp += tmp >> 8; + memset(state, tmp & 0xff, sizeof(unsigned int) * size); + state[0] = hidden_seed; + + if (length + 1 > size) { + count = length + 1; + } else { + count = size; + } + r = ini_func1(state[0] ^ state[mid] ^ state[size - 1]); + state[mid] += r; + r += length; + state[(mid + lag) % size] += r; + state[0] = r; + i = 1; + count--; + for (i = 1, j = 0; (j < count) && (j < length); j++) { + r = ini_func1(state[i] ^ state[(i + mid) % size] + ^ state[(i + size - 1) % size]); + state[(i + mid) % size] += r; + r += array[j] + i; + state[(i + mid + lag) % size] += r; + state[i] = r; + i = (i + 1) % size; + } + for (; j < count; j++) { + r = ini_func1(state[i] ^ state[(i + mid) % size] + ^ state[(i + size - 1) % size]); + state[(i + mid) % size] += r; + r += i; + state[(i + mid + lag) % size] += r; + state[i] = r; + i = (i + 1) % size; + } + for (j = 0; j < size; j++) { + r = ini_func2(state[i] + state[(i + mid) % size] + + state[(i + size - 1) % size]); + state[(i + mid) % size] ^= r; + r -= i; + state[(i + mid + lag) % size] ^= r; + state[i] = r; + i = (i + 1) % size; + } + if (state[size - 1] == 0) { + state[size - 1] = non_zero; + } + return 0; +} + +/* + * This function initializes the internal state array + * with a character array. \b para should be one of the elements in + * the parameter table (mtgp32-param-ref.c). + * This is the same algorithm with mtgp32_init_by_array(), but hope to + * be more useful. + * + * @param[out] mtgp32 MTGP structure. + * @param[in] para parameter structure + * @param[in] array a character array used as a seed. (terminated by zero.) + * @return memory allocation result. if 0 then O.K. + */ +static __forceinline__ __host__ +int mtgp32_init_by_str(unsigned int state[], + const mtgp32_params_fast_t *para, unsigned char *array) { + int i, j, count; + unsigned int r; + int lag; + int mid; + int size = para->mexp / 32 + 1; + int length = (unsigned int)strlen((char *)array); + unsigned int hidden_seed; + unsigned int tmp; + + if (size >= 623) { + lag = 11; + } else if (size >= 68) { + lag = 7; + } else if (size >= 39) { + lag = 5; + } else { + lag = 3; + } + mid = (size - lag) / 2; + + hidden_seed = para->tbl[4] ^ (para->tbl[8] << 16); + tmp = hidden_seed; + tmp += tmp >> 16; + tmp += tmp >> 8; + memset(state, tmp & 0xff, sizeof(unsigned int) * size); + state[0] = hidden_seed; + + if (length + 1 > size) { + count = length + 1; + } else { + count = size; + } + r = ini_func1(state[0] ^ state[mid] ^ state[size - 1]); + state[mid] += r; + r += length; + state[(mid + lag) % size] += r; + state[0] = r; + i = 1; + count--; + for (i = 1, j = 0; (j < count) && (j < length); j++) { + r = ini_func1(state[i] ^ state[(i + mid) % size] + ^ state[(i + size - 1) % size]); + state[(i + mid) % size] += r; + r += array[j] + i; + state[(i + mid + lag) % size] += r; + state[i] = r; + i = (i + 1) % size; + } + for (; j < count; j++) { + r = ini_func1(state[i] ^ state[(i + mid) % size] + ^ state[(i + size - 1) % size]); + state[(i + mid) % size] += r; + r += i; + state[(i + mid + lag) % size] += r; + state[i] = r; + i = (i + 1) % size; + } + for (j = 0; j < size; j++) { + r = ini_func2(state[i] + state[(i + mid) % size] + + state[(i + size - 1) % size]); + state[(i + mid) % size] ^= r; + r -= i; + state[(i + mid + lag) % size] ^= r; + state[i] = r; + i = (i + 1) % size; + } + if (state[size - 1] == 0) { + state[size - 1] = non_zero; + } + return 0; +} + +template +static __forceinline__ __host__ +curandStatus_t curandMakeMTGP32ConstantsImpl(const mtgp32_params_fast_t params[], ParamsType * p, const int block_num) +{ + const int size1 = sizeof(unsigned int) * block_num; + const int size2 = sizeof(unsigned int) * block_num * TBL_SIZE; + unsigned int *h_pos_tbl; + unsigned int *h_sh1_tbl; + unsigned int *h_sh2_tbl; + unsigned int *h_param_tbl; + unsigned int *h_temper_tbl; + unsigned int *h_single_temper_tbl; + unsigned int *h_mask; + curandStatus_t status = CURAND_STATUS_SUCCESS; + + h_pos_tbl = (unsigned int *)malloc(size1); + h_sh1_tbl = (unsigned int *)malloc(size1); + h_sh2_tbl = (unsigned int *)malloc(size1); + h_param_tbl = (unsigned int *)malloc(size2); + h_temper_tbl = (unsigned int *)malloc(size2); + h_single_temper_tbl = (unsigned int *)malloc(size2); + h_mask = (unsigned int *)malloc(sizeof(unsigned int)); + if (h_pos_tbl == NULL + || h_sh1_tbl == NULL + || h_sh2_tbl == NULL + || h_param_tbl == NULL + || h_temper_tbl == NULL + || h_single_temper_tbl == NULL + || h_mask == NULL) { + if (h_pos_tbl != NULL) free(h_pos_tbl); + if (h_sh1_tbl != NULL) free(h_sh1_tbl); + if (h_sh2_tbl != NULL) free(h_sh2_tbl); + if (h_param_tbl != NULL) free(h_param_tbl); + if (h_temper_tbl != NULL) free(h_temper_tbl); + if (h_single_temper_tbl != NULL) free(h_single_temper_tbl); + if (h_mask != NULL) free(h_mask); + status = CURAND_STATUS_ALLOCATION_FAILED; + } else { + + h_mask[0] = params[0].mask; + for (int i = 0; i < block_num; i++) { + h_pos_tbl[i] = params[i].pos; + h_sh1_tbl[i] = params[i].sh1; + h_sh2_tbl[i] = params[i].sh2; + for (int j = 0; j < TBL_SIZE; j++) { + h_param_tbl[i * TBL_SIZE + j] = params[i].tbl[j]; + h_temper_tbl[i * TBL_SIZE + j] = params[i].tmp_tbl[j]; + h_single_temper_tbl[i * TBL_SIZE + j] = params[i].flt_tmp_tbl[j]; + } + } + if (cudaMemcpy( p->pos_tbl, + h_pos_tbl, size1, cudaMemcpyHostToDevice) != cudaSuccess) + { + status = CURAND_STATUS_INITIALIZATION_FAILED; + } else + if (cudaMemcpy( p->sh1_tbl, + h_sh1_tbl, size1, cudaMemcpyHostToDevice) != cudaSuccess) + { + status = CURAND_STATUS_INITIALIZATION_FAILED; + } else + if (cudaMemcpy( p->sh2_tbl, + h_sh2_tbl, size1, cudaMemcpyHostToDevice) != cudaSuccess) + { + status = CURAND_STATUS_INITIALIZATION_FAILED; + } else + if (cudaMemcpy( p->param_tbl, + h_param_tbl, size2, cudaMemcpyHostToDevice) != cudaSuccess) + { + status = CURAND_STATUS_INITIALIZATION_FAILED; + } else + if (cudaMemcpy( p->temper_tbl, + h_temper_tbl, size2, cudaMemcpyHostToDevice) != cudaSuccess) + { + status = CURAND_STATUS_INITIALIZATION_FAILED; + } else + if (cudaMemcpy( p->single_temper_tbl, + h_single_temper_tbl, size2, cudaMemcpyHostToDevice) != cudaSuccess) + { + status = CURAND_STATUS_INITIALIZATION_FAILED; + } else + if (cudaMemcpy( p->mask, + h_mask, sizeof(unsigned int), cudaMemcpyHostToDevice) != cudaSuccess) + { + status = CURAND_STATUS_INITIALIZATION_FAILED; + } + } + if (h_pos_tbl != NULL) free(h_pos_tbl); + if (h_sh1_tbl != NULL) free(h_sh1_tbl); + if (h_sh2_tbl != NULL) free(h_sh2_tbl); + if (h_param_tbl != NULL) free(h_param_tbl); + if (h_temper_tbl != NULL) free(h_temper_tbl); + if (h_single_temper_tbl != NULL)free(h_single_temper_tbl); + if (h_mask != NULL) free(h_mask); + return status; +} + +/** + * \brief Set up constant parameters for the mtgp32 generator + * + * This host-side helper function re-organizes CURAND_NUM_MTGP32_PARAMS sets of + * generator parameters for use by kernel functions and copies the + * result to the specified location in device memory. + * + * \param params - Pointer to an array of type mtgp32_params_fast_t in host memory + * \param p - pointer to a structure of type mtgp32_kernel_params_t in device memory. + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if host memory could not be allocated + * - CURAND_STATUS_INITIALIZATION_FAILED if the copy to device memory failed + * - CURAND_STATUS_SUCCESS otherwise + */ +static __forceinline__ __host__ +curandStatus_t curandMakeMTGP32Constants(const mtgp32_params_fast_t params[], mtgp32_kernel_params_t * p) +{ + return curandMakeMTGP32ConstantsImpl(params, p, CURAND_NUM_MTGP32_PARAMS); +} + +/** + * \brief Set up initial states for the mtgp32 generator + * + * This host-side helper function initializes a number of states (one parameter set per state) for + * an mtgp32 generator. To accomplish this it allocates a state array in host memory, + * initializes that array, and copies the result to device memory. + * + * \param s - pointer to an array of states in device memory + * \param params - Pointer to an array of type mtgp32_params_fast_t in host memory + * \param k - pointer to a structure of type mtgp32_kernel_params_t in device memory + * \param n - number of parameter sets/states to initialize + * \param seed - seed value + * + * \return + * - CURAND_STATUS_ALLOCATION_FAILED if host memory state could not be allocated + * - CURAND_STATUS_INITIALIZATION_FAILED if the copy to device memory failed + * - CURAND_STATUS_SUCCESS otherwise + */ +static __forceinline__ __host__ +curandStatus_t CURANDAPI curandMakeMTGP32KernelState(curandStateMtgp32_t *s, + mtgp32_params_fast_t params[], + mtgp32_kernel_params_t *k, + int n, + unsigned long long seed) +{ + int i; + curandStatus_t status = CURAND_STATUS_SUCCESS; + curandStateMtgp32_t *h_status =(curandStateMtgp32_t *) malloc(sizeof(curandStateMtgp32_t) * n); + if (h_status == NULL) { + status = CURAND_STATUS_ALLOCATION_FAILED; + } else { + seed = seed ^ (seed >> 32); + for (i = 0; i < n; i++) { + mtgp32_init_state(&(h_status[i].s[0]), ¶ms[i],(unsigned int)seed + i + 1); + h_status[i].offset = 0; + h_status[i].pIdx = i; + h_status[i].k = k; + } + if (cudaMemcpy(s, h_status, + sizeof(curandStateMtgp32_t) * n, + cudaMemcpyHostToDevice) != cudaSuccess) { + status = CURAND_STATUS_INITIALIZATION_FAILED; + } + } + free(h_status); + return status; +} + +/** @} */ + +#endif + + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32_kernel.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32_kernel.h new file mode 100644 index 0000000000000000000000000000000000000000..087cdd0796d1e6d6731acd74a07718dfd1312275 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32_kernel.h @@ -0,0 +1,386 @@ +/* + * Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +/* + * curand_mtgp32_kernel.h + * + * + * MTGP32-11213 + * + * Mersenne Twister RNG for the GPU + * + * The period of generated integers is 211213-1. + * + * This code generates 32-bit unsigned integers, and + * single precision floating point numbers uniformly distributed + * in the range [1, 2). (float r; 1.0 <= r < 2.0) + */ + +/* + * Copyright (c) 2009, 2010 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * Copyright (c) 2011 Mutsuo Saito, Makoto Matsumoto, Hiroshima + * University and University of Tokyo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Hiroshima University nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#if !defined CURAND_MTGP32_KERNEL_H +#define CURAND_MTGP32_KERNEL_H + +#if !defined(QUALIFIERS) +#define QUALIFIERS static __forceinline__ __device__ +#endif + +#ifndef __CUDACC_RTC__ +#include +#include +#include +#include +#endif // ifndef __CUDACC_RTC__ +#include +#include "curand.h" +#include "curand_mtgp32.h" + +/** + * \addtogroup DEVICE Device API + * + * @{ + */ + +#ifndef __CUDA_ARCH__ +// define blockDim and threadIdx for host compatibility call +extern const dim3 blockDim; +extern const uint3 threadIdx; +#endif + + +/* + * The function of the recursion formula calculation. + * + * @param[in] X1 the farthest part of state array. + * @param[in] X2 the second farthest part of state array. + * @param[in] Y a part of state array. + * @param[in] bid block id. + * @return output + */ +QUALIFIERS unsigned int para_rec(mtgp32_kernel_params_t * k,unsigned int X1, unsigned int X2, unsigned int Y, int bid) { + unsigned int X = (X1 & k->mask[0]) ^ X2; + unsigned int MAT; + + X ^= X << k->sh1_tbl[bid]; + Y = X ^ (Y >> k->sh2_tbl[bid]); + MAT = k->param_tbl[bid][Y & 0x0f]; + return Y ^ MAT; +} + +/* + * The tempering function. + * + * @param[in] V the output value should be tempered. + * @param[in] T the tempering helper value. + * @param[in] bid block id. + * @return the tempered value. + */ +QUALIFIERS unsigned int temper(mtgp32_kernel_params_t * k,unsigned int V, unsigned int T, int bid) { + unsigned int MAT; + + T ^= T >> 16; + T ^= T >> 8; + MAT = k->temper_tbl[bid][T & 0x0f]; + return V ^ MAT; +} + +/* + * The tempering and converting function. + * By using the preset table, converting to IEEE format + * and tempering are done simultaneously. + * + * @param[in] V the output value should be tempered. + * @param[in] T the tempering helper value. + * @param[in] bid block id. + * @return the tempered and converted value. + */ +QUALIFIERS unsigned int temper_single(mtgp32_kernel_params_t * k,unsigned int V, unsigned int T, int bid) { + unsigned int MAT; + unsigned int r; + + T ^= T >> 16; + T ^= T >> 8; + MAT = k->single_temper_tbl[bid][T & 0x0f]; + r = (V >> 9) ^ MAT; + return r; +} + +/** + * \brief Return 32-bits of pseudorandomness from a mtgp32 generator. + * + * Return 32-bits of pseudorandomness from the mtgp32 generator in \p state, + * increment position of generator by the number of threads in the block. + * Note the number of threads in the block can not exceed 256. + * + * \param state - Pointer to state to update + * + * \return 32-bits of pseudorandomness as an unsigned int, all bits valid to use. + */ +QUALIFIERS unsigned int curand(curandStateMtgp32_t *state) +{ + unsigned int t; + unsigned int d; + int pos = state->k->pos_tbl[state->pIdx]; + unsigned int r; + unsigned int o; + + d = blockDim.z * blockDim.y * blockDim.x; + //assert( d <= 256 ); + t = (blockDim.z * blockDim.y * threadIdx.z) + (blockDim.x * threadIdx.y) + threadIdx.x; + r = para_rec(state->k, state->s[(t + state->offset) & MTGP32_STATE_MASK], + state->s[(t + state->offset + 1) & MTGP32_STATE_MASK], + state->s[(t + state->offset + pos) & MTGP32_STATE_MASK], + state->pIdx); + + state->s[(t + state->offset + MTGPDC_N) & MTGP32_STATE_MASK] = r; + o = temper(state->k, r, + state->s[(t + state->offset + pos -1) & MTGP32_STATE_MASK], + state->pIdx); +NV_IF_TARGET(NV_IS_DEVICE, + __syncthreads(); +) + if (t == 0) + { + state->offset = (state->offset + d) & MTGP32_STATE_MASK; + } +NV_IF_TARGET(NV_IS_DEVICE, + __syncthreads(); +) + return o; + +} +/** + * \brief Return 32-bits of pseudorandomness from a specific position in a mtgp32 generator. + * + * Return 32-bits of pseudorandomness from position \p index of the mtgp32 generator in \p state, + * increment position of generator by \p n positions, which must be the total number of positions + * upddated in the state by the thread block, for this invocation. + * + * Note : + * Thread indices must range from 0...\ n - 1. + * The number of positions updated may not exceed 256. + * A thread block may update more than one state, but a given state may not be updated by more than one thread block. + * + * \param state - Pointer to state to update + * \param index - Index (0..255) of the position within the state to draw from and update + * \param n - The total number of postions in this state that are being updated by this invocation + * + * \return 32-bits of pseudorandomness as an unsigned int, all bits valid to use. + */ +QUALIFIERS unsigned int curand_mtgp32_specific(curandStateMtgp32_t *state, unsigned char index, unsigned char n) +{ + unsigned int t; + int pos = state->k->pos_tbl[state->pIdx]; + unsigned int r; + unsigned int o; + + t = index; + r = para_rec(state->k, state->s[(t + state->offset) & MTGP32_STATE_MASK], + state->s[(t + state->offset + 1) & MTGP32_STATE_MASK], + state->s[(t + state->offset + pos) & MTGP32_STATE_MASK], + state->pIdx); + + state->s[(t + state->offset + MTGPDC_N) & MTGP32_STATE_MASK] = r; + o = temper(state->k, r, + state->s[(t + state->offset + pos -1) & MTGP32_STATE_MASK], + state->pIdx); +NV_IF_TARGET(NV_IS_DEVICE, + __syncthreads(); +) + if (index == 0) + { + state->offset = (state->offset + n) & MTGP32_STATE_MASK; + } +NV_IF_TARGET(NV_IS_DEVICE, + __syncthreads(); +) + return o; +} +/** + * \brief Return a uniformly distributed float from a mtgp32 generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the mtgp32 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * Note: This alternate derivation of a uniform float is provided for completeness + * with the original source + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_mtgp32_single(curandStateMtgp32_t *state) +{ + unsigned int t; + unsigned int d; + int pos = state->k->pos_tbl[state->pIdx]; + unsigned int r; + unsigned int o_u; + float o_f; + + + t = blockDim.z * blockDim.y; + d = t * blockDim.x; + //assert( d <= 256 ); + t += threadIdx.x; + r = para_rec(state->k, state->s[(t + state->offset) & MTGP32_STATE_MASK], + state->s[(t + state->offset + 1) & MTGP32_STATE_MASK], + state->s[(t + state->offset + pos) & MTGP32_STATE_MASK], + state->pIdx); + + state->s[t] = r; + o_u = temper_single(state->k, r, + state->s[(t + state->offset + pos -1) & MTGP32_STATE_MASK], + state->pIdx); +NV_IF_TARGET(NV_IS_DEVICE, + __syncthreads(); +) + if (threadIdx.x == 0) + { + state->offset = (state->offset + d) & MTGP32_STATE_MASK; + } +NV_IF_TARGET(NV_IS_DEVICE, + __syncthreads(); +) + memcpy(&o_f, &o_u, sizeof(o_u)); + return o_f; +} + +/** + * \brief Return a uniformly distributed float from a specific position in a mtgp32 generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from position \p index of the mtgp32 generator in \p state, and + * increment position of generator by \p n positions, which must be the total number of positions + * upddated in the state by the thread block, for this invocation. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * Note 1: + * Thread indices must range from 0...\p n - 1. + * The number of positions updated may not exceed 256. + * A thread block may update more than one state, but a given state may not be updated by more than one thread block. + * + * Note 2: This alternate derivation of a uniform float is provided for completeness + * with the original source + * + * \param state - Pointer to state to update + * \param index - Index (0..255) of the position within the state to draw from and update + * \param n - The total number of postions in this state that are being updated by this invocation + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_mtgp32_single_specific(curandStateMtgp32_t *state, unsigned char index, unsigned char n) +{ + unsigned int t; + int pos = state->k->pos_tbl[state->pIdx]; + unsigned int r; + unsigned int o_u; + float o_f; + + t = index; + r = para_rec(state->k, state->s[(t + state->offset) & MTGP32_STATE_MASK], + state->s[(t + state->offset + 1) & MTGP32_STATE_MASK], + state->s[(t + state->offset + pos) & MTGP32_STATE_MASK], + state->pIdx); + + state->s[t] = r; + o_u = temper_single(state->k, r, + state->s[(t + state->offset + pos -1) & MTGP32_STATE_MASK], + state->pIdx); +NV_IF_TARGET(NV_IS_DEVICE, + __syncthreads(); +) + if (threadIdx.x == 0) + { + state->offset = (state->offset + n) & MTGP32_STATE_MASK; + } +NV_IF_TARGET(NV_IS_DEVICE, + __syncthreads(); +) + memcpy(&o_f, &o_u, sizeof(o_u)); + return o_f; +} + +/** @} */ + +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32dc_p_11213.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32dc_p_11213.h new file mode 100644 index 0000000000000000000000000000000000000000..56a8994c7f2016e4cd2bed77cf6b6516a42f26be --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_mtgp32dc_p_11213.h @@ -0,0 +1,11710 @@ +/* + * Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * This source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * These Licensed Deliverables contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + +/* + * Multiple sets of generator parameters for Mersenne Twister + * with period 2**11213 -1 + */ +/* + * Copyright (c) 2009, 2010 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * Copyright (c) 2011 Mutsuo Saito, Makoto Matsumoto, Hiroshima + * University and University of Tokyo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Hiroshima University nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined CURAND_MTGP32DC_P_11213_H +#define CURAND_MTGP32DC_P_11213_H + +#include "curand_mtgp32.h" + + +#if (__cplusplus >= 201703L) && defined(__cpp_inline_variables) +inline const int mtgpdc_params_11213_num = 200; +#else +static const int mtgpdc_params_11213_num = 200; +#endif + +#if (__cplusplus >= 201703L) && defined(__cpp_inline_variables) +inline mtgp32_params_fast_t mtgp32dc_params_fast_11213[] +#else +static mtgp32_params_fast_t mtgp32dc_params_fast_11213[] +#endif + = { + { + /* No.0 delta:1599 weight:665 */ + 11213, + 88, + 19, + 5, + {(0x00000000), + (0xaba4d62c), + (0xbb076f87), + (0x10a3b9ab), + (0x22000000), + (0x89a4d62c), + (0x99076f87), + (0x32a3b9ab), + (0x000095ba), + (0xaba44396), + (0xbb07fa3d), + (0x10a32c11), + (0x220095ba), + (0x89a44396), + (0x9907fa3d), + (0x32a32c11)}, + {(0x00000000), + (0x06100000), + (0x25d80000), + (0x23c80000), + (0x282c0000), + (0x2e3c0000), + (0x0df40000), + (0x0be40000), + (0x3302de00), + (0x3512de00), + (0x16dade00), + (0x10cade00), + (0x1b2ede00), + (0x1d3ede00), + (0x3ef6de00), + (0x38e6de00)}, + {(0x3f800000), + (0x3f830800), + (0x3f92ec00), + (0x3f91e400), + (0x3f941600), + (0x3f971e00), + (0x3f86fa00), + (0x3f85f200), + (0x3f99816f), + (0x3f9a896f), + (0x3f8b6d6f), + (0x3f88656f), + (0x3f8d976f), + (0x3f8e9f6f), + (0x3f9f7b6f), + (0x3f9c736f)}, + (0xfff80000), + {0xcb,0xb0,0x3f,0xaa,0x65,0x0d,0xbd,0x1c,0x8c,0xc2, + 0x91,0x00,0x87,0x25,0x7f,0xf8,0x6f,0x23,0xf2,0x18,0x00} + }, + { + /* No.1 delta:1185 weight:1129 */ + 11213, + 84, + 15, + 12, + {(0x00000000), + (0x9a975707), + (0x75c21b11), + (0xef554c16), + (0x15500019), + (0x8fc7571e), + (0x60921b08), + (0xfa054c0f), + (0x0000d269), + (0x9a97856e), + (0x75c2c978), + (0xef559e7f), + (0x1550d270), + (0x8fc78577), + (0x6092c961), + (0xfa059e66)}, + {(0x00000000), + (0x00646c00), + (0x0810f000), + (0x08749c00), + (0x37028000), + (0x3766ec00), + (0x3f127000), + (0x3f761c00), + (0x00505e00), + (0x00343200), + (0x0840ae00), + (0x0824c200), + (0x3752de00), + (0x3736b200), + (0x3f422e00), + (0x3f264200)}, + {(0x3f800000), + (0x3f803236), + (0x3f840878), + (0x3f843a4e), + (0x3f9b8140), + (0x3f9bb376), + (0x3f9f8938), + (0x3f9fbb0e), + (0x3f80282f), + (0x3f801a19), + (0x3f842057), + (0x3f841261), + (0x3f9ba96f), + (0x3f9b9b59), + (0x3f9fa117), + (0x3f9f9321)}, + (0xfff80000), + {0x53,0xe0,0x89,0xe0,0x47,0x42,0x00,0xbd,0xe9,0x04, + 0xc9,0x11,0x5c,0xe3,0x97,0x94,0x94,0xd8,0xbb,0xfc,0x00} + }, + { + /* No.2 delta:2848 weight:755 */ + 11213, + 25, + 4, + 18, + {(0x00000000), + (0x507cbad4), + (0xe742103b), + (0xb73eaaef), + (0x71c00027), + (0x21bcbaf3), + (0x9682101c), + (0xc6feaac8), + (0x0000dd6c), + (0x507c67b8), + (0xe742cd57), + (0xb73e7783), + (0x71c0dd4b), + (0x21bc679f), + (0x9682cd70), + (0xc6fe77a4)}, + {(0x00000000), + (0x04210200), + (0x08040000), + (0x0c250200), + (0x11400000), + (0x15610200), + (0x19440000), + (0x1d650200), + (0x206f1e00), + (0x244e1c00), + (0x286b1e00), + (0x2c4a1c00), + (0x312f1e00), + (0x350e1c00), + (0x392b1e00), + (0x3d0a1c00)}, + {(0x3f800000), + (0x3f821081), + (0x3f840200), + (0x3f861281), + (0x3f88a000), + (0x3f8ab081), + (0x3f8ca200), + (0x3f8eb281), + (0x3f90378f), + (0x3f92270e), + (0x3f94358f), + (0x3f96250e), + (0x3f98978f), + (0x3f9a870e), + (0x3f9c958f), + (0x3f9e850e)}, + (0xfff80000), + {0x9e,0x64,0xa3,0x28,0x10,0x66,0x35,0x72,0xe3,0x07, + 0xf7,0xcf,0x5a,0xe3,0x57,0x6f,0x90,0x0c,0x28,0x79,0x00} + }, + { + /* No.3 delta:1100 weight:1261 */ + 11213, + 42, + 20, + 9, + {(0x00000000), + (0x3ef0ef20), + (0x9fddd9ea), + (0xa12d36ca), + (0x10300036), + (0x2ec0ef16), + (0x8fedd9dc), + (0xb11d36fc), + (0x00005ced), + (0x3ef0b3cd), + (0x9fdd8507), + (0xa12d6a27), + (0x10305cdb), + (0x2ec0b3fb), + (0x8fed8531), + (0xb11d6a11)}, + {(0x00000000), + (0x24470c00), + (0x00268200), + (0x24618e00), + (0x00530000), + (0x24140c00), + (0x00758200), + (0x24328e00), + (0x105c5e00), + (0x341b5200), + (0x107adc00), + (0x343dd000), + (0x100f5e00), + (0x34485200), + (0x1029dc00), + (0x346ed000)}, + {(0x3f800000), + (0x3f922386), + (0x3f801341), + (0x3f9230c7), + (0x3f802980), + (0x3f920a06), + (0x3f803ac1), + (0x3f921947), + (0x3f882e2f), + (0x3f9a0da9), + (0x3f883d6e), + (0x3f9a1ee8), + (0x3f8807af), + (0x3f9a2429), + (0x3f8814ee), + (0x3f9a3768)}, + (0xfff80000), + {0x9b,0x1d,0x8b,0x59,0x56,0x8e,0x7b,0x75,0x24,0x4a, + 0xaf,0x49,0x6e,0xcf,0xcb,0x5d,0x67,0x00,0x31,0xac,0x00} + }, + { + /* No.4 delta:5389 weight:1871 */ + 11213, + 22, + 1, + 5, + {(0x00000000), + (0xb004feb9), + (0x03b7c894), + (0xb3b3362d), + (0x0750004d), + (0xb754fef4), + (0x04e7c8d9), + (0xb4e33660), + (0x000049e4), + (0xb004b75d), + (0x03b78170), + (0xb3b37fc9), + (0x075049a9), + (0xb754b710), + (0x04e7813d), + (0xb4e37f84)}, + {(0x00000000), + (0x48698800), + (0x04010000), + (0x4c688800), + (0x60340000), + (0x285d8800), + (0x64350000), + (0x2c5c8800), + (0x20065e00), + (0x686fd600), + (0x24075e00), + (0x6c6ed600), + (0x40325e00), + (0x085bd600), + (0x44335e00), + (0x0c5ad600)}, + {(0x3f800000), + (0x3fa434c4), + (0x3f820080), + (0x3fa63444), + (0x3fb01a00), + (0x3f942ec4), + (0x3fb21a80), + (0x3f962e44), + (0x3f90032f), + (0x3fb437eb), + (0x3f9203af), + (0x3fb6376b), + (0x3fa0192f), + (0x3f842deb), + (0x3fa219af), + (0x3f862d6b)}, + (0xfff80000), + {0xbb,0x80,0x47,0x21,0x2c,0xbd,0xd4,0x7b,0xf3,0xb3, + 0xbd,0x4d,0x05,0x36,0xf5,0x4d,0xe7,0x89,0xdc,0x11,0x00} + }, + { + /* No.5 delta:2280 weight:1243 */ + 11213, + 11, + 16, + 1, + {(0x00000000), + (0x646a361c), + (0xe36e4823), + (0x87047e3f), + (0x2b20005f), + (0x4f4a3643), + (0xc84e487c), + (0xac247e60), + (0x0000caac), + (0x646afcb0), + (0xe36e828f), + (0x8704b493), + (0x2b20caf3), + (0x4f4afcef), + (0xc84e82d0), + (0xac24b4cc)}, + {(0x00000000), + (0xd49c4200), + (0x0b98f000), + (0xdf04b200), + (0x24007200), + (0xf09c3000), + (0x2f988200), + (0xfb04c000), + (0x5d311e00), + (0x89ad5c00), + (0x56a9ee00), + (0x8235ac00), + (0x79316c00), + (0xadad2e00), + (0x72a99c00), + (0xa635de00)}, + {(0x3f800000), + (0x3fea4e21), + (0x3f85cc78), + (0x3fef8259), + (0x3f920039), + (0x3ff84e18), + (0x3f97cc41), + (0x3ffd8260), + (0x3fae988f), + (0x3fc4d6ae), + (0x3fab54f7), + (0x3fc11ad6), + (0x3fbc98b6), + (0x3fd6d697), + (0x3fb954ce), + (0x3fd31aef)}, + (0xfff80000), + {0x24,0x94,0x81,0x62,0xb4,0x6f,0x10,0x4e,0x66,0xd1, + 0xb4,0xdd,0xa0,0x92,0x2e,0xdf,0x8d,0x6b,0x03,0xa3,0x00} + }, + { + /* No.6 delta:722 weight:1357 */ + 11213, + 76, + 16, + 6, + {(0x00000000), + (0x1bb96b3c), + (0x7c6323a4), + (0x67da4898), + (0x22400061), + (0x39f96b5d), + (0x5e2323c5), + (0x459a48f9), + (0x00004c61), + (0x1bb9275d), + (0x7c636fc5), + (0x67da04f9), + (0x22404c00), + (0x39f9273c), + (0x5e236fa4), + (0x459a0498)}, + {(0x00000000), + (0x08258800), + (0x1042c000), + (0x18674800), + (0x00203000), + (0x0805b800), + (0x1062f000), + (0x18477800), + (0x70c01e00), + (0x78e59600), + (0x6082de00), + (0x68a75600), + (0x70e02e00), + (0x78c5a600), + (0x60a2ee00), + (0x68876600)}, + {(0x3f800000), + (0x3f8412c4), + (0x3f882160), + (0x3f8c33a4), + (0x3f801018), + (0x3f8402dc), + (0x3f883178), + (0x3f8c23bc), + (0x3fb8600f), + (0x3fbc72cb), + (0x3fb0416f), + (0x3fb453ab), + (0x3fb87017), + (0x3fbc62d3), + (0x3fb05177), + (0x3fb443b3)}, + (0xfff80000), + {0x06,0x1a,0x0a,0x3e,0x05,0xb0,0xd2,0xab,0x76,0xef, + 0xe5,0xf6,0xe4,0x09,0x02,0x41,0x4b,0x21,0xef,0x76,0x00} + }, + { + /* No.7 delta:3952 weight:825 */ + 11213, + 11, + 15, + 16, + {(0x00000000), + (0xa49b7ddb), + (0xbc75e45f), + (0x18ee9984), + (0x75600076), + (0xd1fb7dad), + (0xc915e429), + (0x6d8e99f2), + (0x0000c4f9), + (0xa49bb922), + (0xbc7520a6), + (0x18ee5d7d), + (0x7560c48f), + (0xd1fbb954), + (0xc91520d0), + (0x6d8e5d0b)}, + {(0x00000000), + (0xf0015000), + (0x0a4c2c00), + (0xfa4d7c00), + (0x0482b000), + (0xf483e000), + (0x0ece9c00), + (0xfecfcc00), + (0x45105e00), + (0xb5110e00), + (0x4f5c7200), + (0xbf5d2200), + (0x4192ee00), + (0xb193be00), + (0x4bdec200), + (0xbbdf9200)}, + {(0x3f800000), + (0x3ff800a8), + (0x3f852616), + (0x3ffd26be), + (0x3f824158), + (0x3ffa41f0), + (0x3f87674e), + (0x3fff67e6), + (0x3fa2882f), + (0x3fda8887), + (0x3fa7ae39), + (0x3fdfae91), + (0x3fa0c977), + (0x3fd8c9df), + (0x3fa5ef61), + (0x3fddefc9)}, + (0xfff80000), + {0xa9,0x6f,0x34,0xf9,0xdd,0xff,0x0a,0x48,0x3c,0x3f, + 0x3e,0x6f,0x74,0x70,0x37,0x33,0x19,0xe4,0x24,0x9b,0x00} + }, + { + /* No.8 delta:4274 weight:1347 */ + 11213, + 42, + 6, + 11, + {(0x00000000), + (0x311b3c94), + (0xa1e0c93f), + (0x90fbf5ab), + (0x3c600082), + (0x0d7b3c16), + (0x9d80c9bd), + (0xac9bf529), + (0x0000b622), + (0x311b8ab6), + (0xa1e07f1d), + (0x90fb4389), + (0x3c60b6a0), + (0x0d7b8a34), + (0x9d807f9f), + (0xac9b430b)}, + {(0x00000000), + (0x80000000), + (0x00000000), + (0x80000000), + (0xc0000000), + (0x40000000), + (0xc0000000), + (0x40000000), + (0x20001e00), + (0xa0001e00), + (0x20001e00), + (0xa0001e00), + (0xe0001e00), + (0x60001e00), + (0xe0001e00), + (0x60001e00)}, + {(0x3f800000), + (0x3fc00000), + (0x3f800000), + (0x3fc00000), + (0x3fe00000), + (0x3fa00000), + (0x3fe00000), + (0x3fa00000), + (0x3f90000f), + (0x3fd0000f), + (0x3f90000f), + (0x3fd0000f), + (0x3ff0000f), + (0x3fb0000f), + (0x3ff0000f), + (0x3fb0000f)}, + (0xfff80000), + {0x3c,0x5a,0x73,0x0e,0xab,0x68,0x32,0x57,0x6f,0xe6, + 0x1d,0x93,0x6e,0xbd,0xef,0x1a,0x6f,0x25,0x1f,0x70,0x00} + }, + { + /* No.9 delta:1902 weight:1001 */ + 11213, + 60, + 6, + 11, + {(0x00000000), + (0xbc8ed6c0), + (0x4d9fbb3d), + (0xf1116dfd), + (0x8e70009d), + (0x32fed65d), + (0xc3efbba0), + (0x7f616d60), + (0x0000a00a), + (0xbc8e76ca), + (0x4d9f1b37), + (0xf111cdf7), + (0x8e70a097), + (0x32fe7657), + (0xc3ef1baa), + (0x7f61cd6a)}, + {(0x00000000), + (0xc0400400), + (0x00220000), + (0xc0620400), + (0x303e0000), + (0xf07e0400), + (0x301c0000), + (0xf05c0400), + (0x40021e00), + (0x80421a00), + (0x40201e00), + (0x80601a00), + (0x703c1e00), + (0xb07c1a00), + (0x701e1e00), + (0xb05e1a00)}, + {(0x3f800000), + (0x3fe02002), + (0x3f801100), + (0x3fe03102), + (0x3f981f00), + (0x3ff83f02), + (0x3f980e00), + (0x3ff82e02), + (0x3fa0010f), + (0x3fc0210d), + (0x3fa0100f), + (0x3fc0300d), + (0x3fb81e0f), + (0x3fd83e0d), + (0x3fb80f0f), + (0x3fd82f0d)}, + (0xfff80000), + {0x83,0x62,0x6c,0x11,0xe4,0x19,0x2b,0x9b,0x87,0x4d, + 0x8e,0x68,0xde,0x69,0x56,0xc5,0x44,0x33,0x4f,0x20,0x00} + }, + { + /* No.10 delta:1148 weight:927 */ + 11213, + 45, + 12, + 13, + {(0x00000000), + (0x06bc3338), + (0xdde8b9f9), + (0xdb548ac1), + (0xfb2000a5), + (0xfd9c339d), + (0x26c8b95c), + (0x20748a64), + (0x0000a4ec), + (0x06bc97d4), + (0xdde81d15), + (0xdb542e2d), + (0xfb20a449), + (0xfd9c9771), + (0x26c81db0), + (0x20742e88)}, + {(0x00000000), + (0x0c494c00), + (0x42040c00), + (0x4e4d4000), + (0x20090800), + (0x2c404400), + (0x620d0400), + (0x6e444800), + (0x10409e00), + (0x1c09d200), + (0x52449200), + (0x5e0dde00), + (0x30499600), + (0x3c00da00), + (0x724d9a00), + (0x7e04d600)}, + {(0x3f800000), + (0x3f8624a6), + (0x3fa10206), + (0x3fa726a0), + (0x3f900484), + (0x3f962022), + (0x3fb10682), + (0x3fb72224), + (0x3f88204f), + (0x3f8e04e9), + (0x3fa92249), + (0x3faf06ef), + (0x3f9824cb), + (0x3f9e006d), + (0x3fb926cd), + (0x3fbf026b)}, + (0xfff80000), + {0xf8,0x39,0x8a,0x36,0x0f,0x90,0x4f,0x3c,0x04,0x0c, + 0x0a,0x02,0xd4,0x04,0x1b,0xc9,0xc4,0x8e,0x15,0x55,0x00} + }, + { + /* No.11 delta:2163 weight:1669 */ + 11213, + 80, + 6, + 9, + {(0x00000000), + (0x247f444d), + (0xb70a5ab0), + (0x93751efd), + (0xc44000b5), + (0xe03f44f8), + (0x734a5a05), + (0x57351e48), + (0x0000554f), + (0x247f1102), + (0xb70a0fff), + (0x93754bb2), + (0xc44055fa), + (0xe03f11b7), + (0x734a0f4a), + (0x57354b07)}, + {(0x00000000), + (0x30200a00), + (0x106c0000), + (0x204c0a00), + (0x00180400), + (0x30380e00), + (0x10740400), + (0x20540e00), + (0x100a1e00), + (0x202a1400), + (0x00661e00), + (0x30461400), + (0x10121a00), + (0x20321000), + (0x007e1a00), + (0x305e1000)}, + {(0x3f800000), + (0x3f981005), + (0x3f883600), + (0x3f902605), + (0x3f800c02), + (0x3f981c07), + (0x3f883a02), + (0x3f902a07), + (0x3f88050f), + (0x3f90150a), + (0x3f80330f), + (0x3f98230a), + (0x3f88090d), + (0x3f901908), + (0x3f803f0d), + (0x3f982f08)}, + (0xfff80000), + {0x98,0xb0,0x30,0x32,0xcf,0x75,0x63,0xeb,0x3a,0xb6, + 0x4f,0x70,0x47,0x4e,0x6a,0xd1,0x7b,0x40,0xbd,0x90,0x00} + }, + { + /* No.12 delta:4985 weight:689 */ + 11213, + 81, + 8, + 18, + {(0x00000000), + (0xcdcab880), + (0xdedf1226), + (0x1315aaa6), + (0xd17000c6), + (0x1cbab846), + (0x0faf12e0), + (0xc265aa60), + (0x0000b647), + (0xcdca0ec7), + (0xdedfa461), + (0x13151ce1), + (0xd170b681), + (0x1cba0e01), + (0x0fafa4a7), + (0xc2651c27)}, + {(0x00000000), + (0x601c0000), + (0x08780000), + (0x68640000), + (0x00740000), + (0x60680000), + (0x080c0000), + (0x68100000), + (0x00a01e00), + (0x60bc1e00), + (0x08d81e00), + (0x68c41e00), + (0x00d41e00), + (0x60c81e00), + (0x08ac1e00), + (0x68b01e00)}, + {(0x3f800000), + (0x3fb00e00), + (0x3f843c00), + (0x3fb43200), + (0x3f803a00), + (0x3fb03400), + (0x3f840600), + (0x3fb40800), + (0x3f80500f), + (0x3fb05e0f), + (0x3f846c0f), + (0x3fb4620f), + (0x3f806a0f), + (0x3fb0640f), + (0x3f84560f), + (0x3fb4580f)}, + (0xfff80000), + {0x90,0xf2,0x51,0xc2,0x2d,0xc4,0x52,0x73,0x15,0xfa, + 0xeb,0xc3,0x64,0x51,0x48,0xf7,0xb1,0x26,0x38,0xb4,0x00} + }, + { + /* No.13 delta:6473 weight:513 */ + 11213, + 16, + 1, + 19, + {(0x00000000), + (0x2310a4f2), + (0x91c8cf8c), + (0xb2d86b7e), + (0x89c000d1), + (0xaad0a423), + (0x1808cf5d), + (0x3b186baf), + (0x0000f299), + (0x2310566b), + (0x91c83d15), + (0xb2d899e7), + (0x89c0f248), + (0xaad056ba), + (0x18083dc4), + (0x3b189936)}, + {(0x00000000), + (0x4c020000), + (0xa6800000), + (0xea820000), + (0x15000000), + (0x59020000), + (0xb3800000), + (0xff820000), + (0x29201e00), + (0x65221e00), + (0x8fa01e00), + (0xc3a21e00), + (0x3c201e00), + (0x70221e00), + (0x9aa01e00), + (0xd6a21e00)}, + {(0x3f800000), + (0x3fa60100), + (0x3fd34000), + (0x3ff54100), + (0x3f8a8000), + (0x3fac8100), + (0x3fd9c000), + (0x3fffc100), + (0x3f94900f), + (0x3fb2910f), + (0x3fc7d00f), + (0x3fe1d10f), + (0x3f9e100f), + (0x3fb8110f), + (0x3fcd500f), + (0x3feb510f)}, + (0xfff80000), + {0x89,0x7c,0x3c,0xc6,0x3d,0x0a,0xad,0xf2,0xa0,0xf5, + 0x0a,0x4c,0x4e,0x83,0xc5,0x45,0xdb,0xcb,0xb5,0x98,0x00} + }, + { + /* No.14 delta:1389 weight:725 */ + 11213, + 63, + 14, + 18, + {(0x00000000), + (0x81c7909c), + (0xecb46b0c), + (0x6d73fb90), + (0xf33000ef), + (0x72f79073), + (0x1f846be3), + (0x9e43fb7f), + (0x0000e902), + (0x81c7799e), + (0xecb4820e), + (0x6d731292), + (0xf330e9ed), + (0x72f77971), + (0x1f8482e1), + (0x9e43127d)}, + {(0x00000000), + (0x09001000), + (0x02010000), + (0x0b011000), + (0x00201800), + (0x09200800), + (0x02211800), + (0x0b210800), + (0x30039e00), + (0x39038e00), + (0x32029e00), + (0x3b028e00), + (0x30238600), + (0x39239600), + (0x32228600), + (0x3b229600)}, + {(0x3f800000), + (0x3f848008), + (0x3f810080), + (0x3f858088), + (0x3f80100c), + (0x3f849004), + (0x3f81108c), + (0x3f859084), + (0x3f9801cf), + (0x3f9c81c7), + (0x3f99014f), + (0x3f9d8147), + (0x3f9811c3), + (0x3f9c91cb), + (0x3f991143), + (0x3f9d914b)}, + (0xfff80000), + {0xb7,0x0b,0xee,0xcb,0xc6,0x29,0x7c,0xe3,0xc5,0x58, + 0x71,0xe7,0x4b,0xe5,0xc9,0x63,0xbd,0xa4,0x75,0xc7,0x00} + }, + { + /* No.15 delta:8365 weight:1135 */ + 11213, + 38, + 28, + 1, + {(0x00000000), + (0xe56c7b3b), + (0x759d951b), + (0x90f1ee20), + (0x1a6000fa), + (0xff0c7bc1), + (0x6ffd95e1), + (0x8a91eeda), + (0x00004474), + (0xe56c3f4f), + (0x759dd16f), + (0x90f1aa54), + (0x1a60448e), + (0xff0c3fb5), + (0x6ffdd195), + (0x8a91aaae)}, + {(0x00000000), + (0xc0410a00), + (0xe70c0400), + (0x274d0e00), + (0xfa3e8000), + (0x3a7f8a00), + (0x1d328400), + (0xdd738e00), + (0x20801e00), + (0xe0c11400), + (0xc78c1a00), + (0x07cd1000), + (0xdabe9e00), + (0x1aff9400), + (0x3db29a00), + (0xfdf39000)}, + {(0x3f800000), + (0x3fe02085), + (0x3ff38602), + (0x3f93a687), + (0x3ffd1f40), + (0x3f9d3fc5), + (0x3f8e9942), + (0x3feeb9c7), + (0x3f90400f), + (0x3ff0608a), + (0x3fe3c60d), + (0x3f83e688), + (0x3fed5f4f), + (0x3f8d7fca), + (0x3f9ed94d), + (0x3ffef9c8)}, + (0xfff80000), + {0xd2,0xa4,0x8f,0xf8,0x54,0x0f,0xe3,0x14,0x17,0xeb, + 0x17,0x78,0x41,0x78,0x69,0xbb,0x4b,0x01,0x85,0x8e,0x00} + }, + { + /* No.16 delta:6253 weight:641 */ + 11213, + 3, + 30, + 2, + {(0x00000000), + (0x83a2a3cb), + (0x52e0a64c), + (0xd1420587), + (0x9850010b), + (0x1bf2a2c0), + (0xcab0a747), + (0x4912048c), + (0x0000aaa5), + (0x83a2096e), + (0x52e00ce9), + (0xd142af22), + (0x9850abae), + (0x1bf20865), + (0xcab00de2), + (0x4912ae29)}, + {(0x00000000), + (0xe9100000), + (0x94d00000), + (0x7dc00000), + (0xdbcc0000), + (0x32dc0000), + (0x4f1c0000), + (0xa60c0000), + (0x09d01e00), + (0xe0c01e00), + (0x9d001e00), + (0x74101e00), + (0xd21c1e00), + (0x3b0c1e00), + (0x46cc1e00), + (0xafdc1e00)}, + {(0x3f800000), + (0x3ff48800), + (0x3fca6800), + (0x3fbee000), + (0x3fede600), + (0x3f996e00), + (0x3fa78e00), + (0x3fd30600), + (0x3f84e80f), + (0x3ff0600f), + (0x3fce800f), + (0x3fba080f), + (0x3fe90e0f), + (0x3f9d860f), + (0x3fa3660f), + (0x3fd7ee0f)}, + (0xfff80000), + {0xa6,0xc6,0x12,0x64,0xaf,0x79,0x40,0x50,0x7b,0xb9, + 0xa9,0xfa,0x9a,0xc0,0x7a,0xaf,0x63,0x83,0x39,0x6c,0x00} + }, + { + /* No.17 delta:5329 weight:467 */ + 11213, + 55, + 1, + 16, + {(0x00000000), + (0x2ce39cc8), + (0x6312ea87), + (0x4ff1764f), + (0x9ef00113), + (0xb2139ddb), + (0xfde2eb94), + (0xd101775c), + (0x00007ddc), + (0x2ce3e114), + (0x6312975b), + (0x4ff10b93), + (0x9ef07ccf), + (0xb213e007), + (0xfde29648), + (0xd1010a80)}, + {(0x00000000), + (0x0c021000), + (0xe3400000), + (0xef421000), + (0x02000000), + (0x0e021000), + (0xe1400000), + (0xed421000), + (0x50a01e00), + (0x5ca20e00), + (0xb3e01e00), + (0xbfe20e00), + (0x52a01e00), + (0x5ea20e00), + (0xb1e01e00), + (0xbde20e00)}, + {(0x3f800000), + (0x3f860108), + (0x3ff1a000), + (0x3ff7a108), + (0x3f810000), + (0x3f870108), + (0x3ff0a000), + (0x3ff6a108), + (0x3fa8500f), + (0x3fae5107), + (0x3fd9f00f), + (0x3fdff107), + (0x3fa9500f), + (0x3faf5107), + (0x3fd8f00f), + (0x3fdef107)}, + (0xfff80000), + {0xe4,0xb8,0x1d,0x0f,0x15,0xe2,0xd6,0xd2,0x30,0x67, + 0x18,0x06,0x38,0xd0,0x63,0x09,0x4d,0xc1,0xaa,0x48,0x00} + }, + { + /* No.18 delta:3046 weight:699 */ + 11213, + 9, + 9, + 15, + {(0x00000000), + (0x228294e5), + (0xc1861e7b), + (0xe3048a9e), + (0x6250012a), + (0x40d295cf), + (0xa3d61f51), + (0x81548bb4), + (0x00005800), + (0x2282cce5), + (0xc186467b), + (0xe304d29e), + (0x6250592a), + (0x40d2cdcf), + (0xa3d64751), + (0x8154d3b4)}, + {(0x00000000), + (0x57910c00), + (0xd07cc400), + (0x87edc800), + (0xa8036800), + (0xff926400), + (0x787fac00), + (0x2feea000), + (0x00521e00), + (0x57c31200), + (0xd02eda00), + (0x87bfd600), + (0xa8517600), + (0xffc07a00), + (0x782db200), + (0x2fbcbe00)}, + {(0x3f800000), + (0x3fabc886), + (0x3fe83e62), + (0x3fc3f6e4), + (0x3fd401b4), + (0x3fffc932), + (0x3fbc3fd6), + (0x3f97f750), + (0x3f80290f), + (0x3fabe189), + (0x3fe8176d), + (0x3fc3dfeb), + (0x3fd428bb), + (0x3fffe03d), + (0x3fbc16d9), + (0x3f97de5f)}, + (0xfff80000), + {0x3d,0xb7,0x41,0x11,0xf8,0x6e,0xe6,0x89,0x71,0x95, + 0x3b,0x7c,0x3a,0x38,0x60,0x12,0x4c,0xec,0xaa,0x83,0x00} + }, + { + /* No.19 delta:786 weight:1431 */ + 11213, + 75, + 17, + 6, + {(0x00000000), + (0x819ee5dc), + (0x4ffaa079), + (0xce6445a5), + (0xe6300137), + (0x67aee4eb), + (0xa9caa14e), + (0x28544492), + (0x00008a74), + (0x819e6fa8), + (0x4ffa2a0d), + (0xce64cfd1), + (0xe6308b43), + (0x67ae6e9f), + (0xa9ca2b3a), + (0x2854cee6)}, + {(0x00000000), + (0x98018000), + (0x20039800), + (0xb8021800), + (0x40104000), + (0xd811c000), + (0x6013d800), + (0xf8125800), + (0x00033e00), + (0x9802be00), + (0x2000a600), + (0xb8012600), + (0x40137e00), + (0xd812fe00), + (0x6010e600), + (0xf8116600)}, + {(0x3f800000), + (0x3fcc00c0), + (0x3f9001cc), + (0x3fdc010c), + (0x3fa00820), + (0x3fec08e0), + (0x3fb009ec), + (0x3ffc092c), + (0x3f80019f), + (0x3fcc015f), + (0x3f900053), + (0x3fdc0093), + (0x3fa009bf), + (0x3fec097f), + (0x3fb00873), + (0x3ffc08b3)}, + (0xfff80000), + {0x90,0xc1,0xc9,0xe7,0xea,0xaf,0xd9,0x5b,0x1f,0x93, + 0x8d,0xcd,0x9b,0xf4,0xbb,0x91,0x58,0xb2,0x03,0x70,0x00} + }, + { + /* No.20 delta:846 weight:909 */ + 11213, + 70, + 15, + 6, + {(0x00000000), + (0xc56d80c5), + (0x4bb862e9), + (0x8ed5e22c), + (0x92e00143), + (0x578d8186), + (0xd95863aa), + (0x1c35e36f), + (0x000095b5), + (0xc56d1570), + (0x4bb8f75c), + (0x8ed57799), + (0x92e094f6), + (0x578d1433), + (0xd958f61f), + (0x1c3576da)}, + {(0x00000000), + (0x20642000), + (0x2530d800), + (0x0554f800), + (0x01a05200), + (0x21c47200), + (0x24908a00), + (0x04f4aa00), + (0x00521e00), + (0x20363e00), + (0x2562c600), + (0x0506e600), + (0x01f24c00), + (0x21966c00), + (0x24c29400), + (0x04a6b400)}, + {(0x3f800000), + (0x3f903210), + (0x3f92986c), + (0x3f82aa7c), + (0x3f80d029), + (0x3f90e239), + (0x3f924845), + (0x3f827a55), + (0x3f80290f), + (0x3f901b1f), + (0x3f92b163), + (0x3f828373), + (0x3f80f926), + (0x3f90cb36), + (0x3f92614a), + (0x3f82535a)}, + (0xfff80000), + {0xd6,0xb1,0xe1,0x27,0x40,0x54,0x48,0x67,0x71,0xe5, + 0x2a,0x38,0xbf,0xa7,0x93,0x82,0x17,0xcd,0x71,0x33,0x00} + }, + { + /* No.21 delta:1909 weight:729 */ + 11213, + 63, + 15, + 17, + {(0x00000000), + (0x3c495454), + (0xf3a1ddf0), + (0xcfe889a4), + (0x1b200159), + (0x2769550d), + (0xe881dca9), + (0xd4c888fd), + (0x0000cd3b), + (0x3c49996f), + (0xf3a110cb), + (0xcfe8449f), + (0x1b20cc62), + (0x27699836), + (0xe8811192), + (0xd4c845c6)}, + {(0x00000000), + (0x08027000), + (0x9651d400), + (0x9e53a400), + (0x0040a400), + (0x0842d400), + (0x96117000), + (0x9e130000), + (0x006e9e00), + (0x086cee00), + (0x963f4a00), + (0x9e3d3a00), + (0x002e3a00), + (0x082c4a00), + (0x967fee00), + (0x9e7d9e00)}, + {(0x3f800000), + (0x3f840138), + (0x3fcb28ea), + (0x3fcf29d2), + (0x3f802052), + (0x3f84216a), + (0x3fcb08b8), + (0x3fcf0980), + (0x3f80374f), + (0x3f843677), + (0x3fcb1fa5), + (0x3fcf1e9d), + (0x3f80171d), + (0x3f841625), + (0x3fcb3ff7), + (0x3fcf3ecf)}, + (0xfff80000), + {0xc8,0xdc,0x70,0x0a,0x23,0xa5,0x20,0x35,0xa2,0xd7, + 0xd1,0x53,0xfc,0xe0,0xc1,0xde,0xc0,0x2b,0x65,0x4d,0x00} + }, + { + /* No.22 delta:2420 weight:985 */ + 11213, + 32, + 7, + 15, + {(0x00000000), + (0xd25d9ecf), + (0xb1288d77), + (0x637513b8), + (0xc3700160), + (0x112d9faf), + (0x72588c17), + (0xa00512d8), + (0x000093d5), + (0xd25d0d1a), + (0xb1281ea2), + (0x6375806d), + (0xc37092b5), + (0x112d0c7a), + (0x72581fc2), + (0xa005810d)}, + {(0x00000000), + (0x10134200), + (0x028b0000), + (0x12984200), + (0x50480000), + (0x405b4200), + (0x52c30000), + (0x42d04200), + (0x10ee5e00), + (0x00fd1c00), + (0x12655e00), + (0x02761c00), + (0x40a65e00), + (0x50b51c00), + (0x422d5e00), + (0x523e1c00)}, + {(0x3f800000), + (0x3f8809a1), + (0x3f814580), + (0x3f894c21), + (0x3fa82400), + (0x3fa02da1), + (0x3fa96180), + (0x3fa16821), + (0x3f88772f), + (0x3f807e8e), + (0x3f8932af), + (0x3f813b0e), + (0x3fa0532f), + (0x3fa85a8e), + (0x3fa116af), + (0x3fa91f0e)}, + (0xfff80000), + {0xd0,0xc2,0xd1,0x3e,0x09,0x41,0xc7,0x9c,0x09,0x33, + 0x25,0x5f,0x84,0x21,0xc4,0xcc,0xc5,0x43,0x2a,0x14,0x00} + }, + { + /* No.23 delta:985 weight:863 */ + 11213, + 70, + 12, + 10, + {(0x00000000), + (0x6e6163b2), + (0xa3cecdea), + (0xcdafae58), + (0xb670017d), + (0xd81162cf), + (0x15becc97), + (0x7bdfaf25), + (0x0000d554), + (0x6e61b6e6), + (0xa3ce18be), + (0xcdaf7b0c), + (0xb670d429), + (0xd811b79b), + (0x15be19c3), + (0x7bdf7a71)}, + {(0x00000000), + (0x0338d800), + (0x00545800), + (0x036c8000), + (0x01521000), + (0x026ac800), + (0x01064800), + (0x023e9000), + (0x0020de00), + (0x03180600), + (0x00748600), + (0x034c5e00), + (0x0172ce00), + (0x024a1600), + (0x01269600), + (0x021e4e00)}, + {(0x3f800000), + (0x3f819c6c), + (0x3f802a2c), + (0x3f81b640), + (0x3f80a908), + (0x3f813564), + (0x3f808324), + (0x3f811f48), + (0x3f80106f), + (0x3f818c03), + (0x3f803a43), + (0x3f81a62f), + (0x3f80b967), + (0x3f81250b), + (0x3f80934b), + (0x3f810f27)}, + (0xfff80000), + {0x57,0xda,0x1e,0x1e,0x0f,0xc1,0x5c,0xac,0x32,0x8f, + 0xe4,0x94,0x24,0xf0,0x86,0x24,0x1b,0xde,0x44,0x16,0x00} + }, + { + /* No.24 delta:1573 weight:1043 */ + 11213, + 58, + 21, + 2, + {(0x00000000), + (0xa6c80c3d), + (0x3502d818), + (0x93cad425), + (0xda700189), + (0x7cb80db4), + (0xef72d991), + (0x49bad5ac), + (0x0000cb8c), + (0xa6c8c7b1), + (0x35021394), + (0x93ca1fa9), + (0xda70ca05), + (0x7cb8c638), + (0xef72121d), + (0x49ba1e20)}, + {(0x00000000), + (0xd66f0400), + (0x014ca600), + (0xd723a200), + (0x00442a00), + (0xd62b2e00), + (0x01088c00), + (0xd7678800), + (0x0c835e00), + (0xdaec5a00), + (0x0dcff800), + (0xdba0fc00), + (0x0cc77400), + (0xdaa87000), + (0x0d8bd200), + (0xdbe4d600)}, + {(0x3f800000), + (0x3feb3782), + (0x3f80a653), + (0x3feb91d1), + (0x3f802215), + (0x3feb1597), + (0x3f808446), + (0x3febb3c4), + (0x3f8641af), + (0x3fed762d), + (0x3f86e7fc), + (0x3fedd07e), + (0x3f8663ba), + (0x3fed5438), + (0x3f86c5e9), + (0x3fedf26b)}, + (0xfff80000), + {0xd3,0x5b,0x43,0x3f,0x00,0x55,0xf8,0x40,0xfe,0x8f, + 0xd0,0xe0,0xac,0x48,0x50,0xf2,0x50,0x2a,0xb7,0xcf,0x00} + }, + { + /* No.25 delta:1860 weight:1169 */ + 11213, + 33, + 7, + 10, + {(0x00000000), + (0x3f9ccf17), + (0xcdd7a2a1), + (0xf24b6db6), + (0xf9c00195), + (0xc65cce82), + (0x3417a334), + (0x0b8b6c23), + (0x00006c32), + (0x3f9ca325), + (0xcdd7ce93), + (0xf24b0184), + (0xf9c06da7), + (0xc65ca2b0), + (0x3417cf06), + (0x0b8b0011)}, + {(0x00000000), + (0x043a0400), + (0x00714000), + (0x044b4400), + (0x10408400), + (0x147a8000), + (0x1031c400), + (0x140bc000), + (0x70049e00), + (0x743e9a00), + (0x7075de00), + (0x744fda00), + (0x60441a00), + (0x647e1e00), + (0x60355a00), + (0x640f5e00)}, + {(0x3f800000), + (0x3f821d02), + (0x3f8038a0), + (0x3f8225a2), + (0x3f882042), + (0x3f8a3d40), + (0x3f8818e2), + (0x3f8a05e0), + (0x3fb8024f), + (0x3fba1f4d), + (0x3fb83aef), + (0x3fba27ed), + (0x3fb0220d), + (0x3fb23f0f), + (0x3fb01aad), + (0x3fb207af)}, + (0xfff80000), + {0x6f,0x6a,0x15,0x14,0x9e,0x4e,0xca,0xcd,0xe1,0xfb, + 0x26,0x23,0xa0,0xa9,0x21,0x22,0xca,0x8c,0x68,0x8f,0x00} + }, + { + /* No.26 delta:2274 weight:1019 */ + 11213, + 18, + 7, + 13, + {(0x00000000), + (0x83f4f835), + (0x34e8f3fa), + (0xb71c0bcf), + (0xf21001a3), + (0x71e4f996), + (0xc6f8f259), + (0x450c0a6c), + (0x00009d49), + (0x83f4657c), + (0x34e86eb3), + (0xb71c9686), + (0xf2109cea), + (0x71e464df), + (0xc6f86f10), + (0x450c9725)}, + {(0x00000000), + (0x69050000), + (0x0b0a1800), + (0x620f1800), + (0x41a06000), + (0x28a56000), + (0x4aaa7800), + (0x23af7800), + (0x046b1e00), + (0x6d6e1e00), + (0x0f610600), + (0x66640600), + (0x45cb7e00), + (0x2cce7e00), + (0x4ec16600), + (0x27c46600)}, + {(0x3f800000), + (0x3fb48280), + (0x3f85850c), + (0x3fb1078c), + (0x3fa0d030), + (0x3f9452b0), + (0x3fa5553c), + (0x3f91d7bc), + (0x3f82358f), + (0x3fb6b70f), + (0x3f87b083), + (0x3fb33203), + (0x3fa2e5bf), + (0x3f96673f), + (0x3fa760b3), + (0x3f93e233)}, + (0xfff80000), + {0x6c,0xda,0xe3,0x3d,0xac,0x72,0x40,0x41,0xca,0xa3, + 0xf7,0xdf,0xff,0x2d,0x57,0xea,0x1f,0x8d,0x6c,0x04,0x00} + }, + { + /* No.27 delta:2503 weight:711 */ + 11213, + 9, + 12, + 13, + {(0x00000000), + (0xc54f7f87), + (0x6904a950), + (0xac4bd6d7), + (0x85c001bc), + (0x408f7e3b), + (0xecc4a8ec), + (0x298bd76b), + (0x00007b77), + (0xc54f04f0), + (0x6904d227), + (0xac4bada0), + (0x85c07acb), + (0x408f054c), + (0xecc4d39b), + (0x298bac1c)}, + {(0x00000000), + (0xc7002c00), + (0x5a61c800), + (0x9d61e400), + (0x12013800), + (0xd5011400), + (0x4860f000), + (0x8f60dc00), + (0xc8c01e00), + (0x0fc03200), + (0x92a1d600), + (0x55a1fa00), + (0xdac12600), + (0x1dc10a00), + (0x80a0ee00), + (0x47a0c200)}, + {(0x3f800000), + (0x3fe38016), + (0x3fad30e4), + (0x3fceb0f2), + (0x3f89009c), + (0x3fea808a), + (0x3fa43078), + (0x3fc7b06e), + (0x3fe4600f), + (0x3f87e019), + (0x3fc950eb), + (0x3faad0fd), + (0x3fed6093), + (0x3f8ee085), + (0x3fc05077), + (0x3fa3d061)}, + (0xfff80000), + {0xd6,0xd3,0xee,0x8e,0x9a,0x94,0x64,0x4c,0x3a,0x7b, + 0x1d,0x2f,0x64,0xef,0x67,0x33,0x0d,0x49,0x2e,0x20,0x00} + }, + { + /* No.28 delta:1642 weight:1597 */ + 11213, + 14, + 16, + 3, + {(0x00000000), + (0x8147d21a), + (0x627aba0f), + (0xe33d6815), + (0x279001c1), + (0xa6d7d3db), + (0x45eabbce), + (0xc4ad69d4), + (0x0000f4d1), + (0x814726cb), + (0x627a4ede), + (0xe33d9cc4), + (0x2790f510), + (0xa6d7270a), + (0x45ea4f1f), + (0xc4ad9d05)}, + {(0x00000000), + (0x210c6a00), + (0x0071b800), + (0x217dd200), + (0xcc021a00), + (0xed0e7000), + (0xcc73a200), + (0xed7fc800), + (0x41b2de00), + (0x60beb400), + (0x41c36600), + (0x60cf0c00), + (0x8db0c400), + (0xacbcae00), + (0x8dc17c00), + (0xaccd1600)}, + {(0x3f800000), + (0x3f908635), + (0x3f8038dc), + (0x3f90bee9), + (0x3fe6010d), + (0x3ff68738), + (0x3fe639d1), + (0x3ff6bfe4), + (0x3fa0d96f), + (0x3fb05f5a), + (0x3fa0e1b3), + (0x3fb06786), + (0x3fc6d862), + (0x3fd65e57), + (0x3fc6e0be), + (0x3fd6668b)}, + (0xfff80000), + {0x58,0xce,0x35,0x39,0xc0,0x04,0xad,0xd6,0xdd,0xb7, + 0x5d,0xf1,0xac,0xf9,0x85,0xea,0x3f,0x74,0x52,0x6d,0x00} + }, + { + /* No.29 delta:1888 weight:1763 */ + 11213, + 91, + 4, + 2, + {(0x00000000), + (0xa620066e), + (0x498ca8fb), + (0xefacae95), + (0xc3f001d3), + (0x65d007bd), + (0x8a7ca928), + (0x2c5caf46), + (0x0000927c), + (0xa6209412), + (0x498c3a87), + (0xefac3ce9), + (0xc3f093af), + (0x65d095c1), + (0x8a7c3b54), + (0x2c5c3d3a)}, + {(0x00000000), + (0x29909200), + (0x0074c600), + (0x29e45400), + (0x400e7000), + (0x699ee200), + (0x407ab600), + (0x69ea2400), + (0x44029e00), + (0x6d920c00), + (0x44765800), + (0x6de6ca00), + (0x040cee00), + (0x2d9c7c00), + (0x04782800), + (0x2de8ba00)}, + {(0x3f800000), + (0x3f94c849), + (0x3f803a63), + (0x3f94f22a), + (0x3fa00738), + (0x3fb4cf71), + (0x3fa03d5b), + (0x3fb4f512), + (0x3fa2014f), + (0x3fb6c906), + (0x3fa23b2c), + (0x3fb6f365), + (0x3f820677), + (0x3f96ce3e), + (0x3f823c14), + (0x3f96f45d)}, + (0xfff80000), + {0xbf,0x14,0xa8,0x90,0x29,0x75,0x15,0xde,0x68,0x12, + 0x39,0xb3,0x6e,0x2f,0xcb,0x19,0x1f,0xe6,0x2c,0x9b,0x00} + }, + { + /* No.30 delta:1194 weight:873 */ + 11213, + 90, + 10, + 14, + {(0x00000000), + (0xdd216696), + (0x738a5c01), + (0xaeab3a97), + (0x402001ec), + (0x9d01677a), + (0x33aa5ded), + (0xee8b3b7b), + (0x0000c5c9), + (0xdd21a35f), + (0x738a99c8), + (0xaeabff5e), + (0x4020c425), + (0x9d01a2b3), + (0x33aa9824), + (0xee8bfeb2)}, + {(0x00000000), + (0x193a0000), + (0x07a49000), + (0x1e9e9000), + (0x00658800), + (0x195f8800), + (0x07c11800), + (0x1efb1800), + (0x4456fe00), + (0x5d6cfe00), + (0x43f26e00), + (0x5ac86e00), + (0x44337600), + (0x5d097600), + (0x4397e600), + (0x5aade600)}, + {(0x3f800000), + (0x3f8c9d00), + (0x3f83d248), + (0x3f8f4f48), + (0x3f8032c4), + (0x3f8cafc4), + (0x3f83e08c), + (0x3f8f7d8c), + (0x3fa22b7f), + (0x3faeb67f), + (0x3fa1f937), + (0x3fad6437), + (0x3fa219bb), + (0x3fae84bb), + (0x3fa1cbf3), + (0x3fad56f3)}, + (0xfff80000), + {0x45,0xbe,0xc0,0x65,0xca,0x28,0x44,0x0e,0x06,0x4e, + 0xa0,0xbf,0x48,0xa8,0x8e,0x39,0x64,0x68,0xe1,0x30,0x00} + }, + { + /* No.31 delta:1509 weight:1313 */ + 11213, + 86, + 6, + 7, + {(0x00000000), + (0x41d73f34), + (0x0930d7f4), + (0x48e7e8c0), + (0x65b001f9), + (0x24673ecd), + (0x6c80d60d), + (0x2d57e939), + (0x00008ad2), + (0x41d7b5e6), + (0x09305d26), + (0x48e76212), + (0x65b08b2b), + (0x2467b41f), + (0x6c805cdf), + (0x2d5763eb)}, + {(0x00000000), + (0x02010000), + (0x10332000), + (0x12322000), + (0x10030000), + (0x12020000), + (0x00302000), + (0x02312000), + (0x403a9e00), + (0x423b9e00), + (0x5009be00), + (0x5208be00), + (0x50399e00), + (0x52389e00), + (0x400abe00), + (0x420bbe00)}, + {(0x3f800000), + (0x3f810080), + (0x3f881990), + (0x3f891910), + (0x3f880180), + (0x3f890100), + (0x3f801810), + (0x3f811890), + (0x3fa01d4f), + (0x3fa11dcf), + (0x3fa804df), + (0x3fa9045f), + (0x3fa81ccf), + (0x3fa91c4f), + (0x3fa0055f), + (0x3fa105df)}, + (0xfff80000), + {0x9f,0xb2,0x3a,0xbb,0xab,0xbd,0xc1,0x43,0x82,0x94, + 0x1f,0x8e,0xdf,0x89,0xbb,0xf6,0xee,0x6a,0x10,0x54,0x00} + }, + { + /* No.32 delta:3454 weight:869 */ + 11213, + 36, + 3, + 15, + {(0x00000000), + (0x1709ea04), + (0x8e9b8c43), + (0x99926647), + (0xdd100203), + (0xca19e807), + (0x538b8e40), + (0x44826444), + (0x0000f3b3), + (0x170919b7), + (0x8e9b7ff0), + (0x999295f4), + (0xdd10f1b0), + (0xca191bb4), + (0x538b7df3), + (0x448297f7)}, + {(0x00000000), + (0x28228000), + (0x1fc10000), + (0x37e38000), + (0x00400000), + (0x28628000), + (0x1f810000), + (0x37a38000), + (0x12b01e00), + (0x3a929e00), + (0x0d711e00), + (0x25539e00), + (0x12f01e00), + (0x3ad29e00), + (0x0d311e00), + (0x25139e00)}, + {(0x3f800000), + (0x3f941140), + (0x3f8fe080), + (0x3f9bf1c0), + (0x3f802000), + (0x3f943140), + (0x3f8fc080), + (0x3f9bd1c0), + (0x3f89580f), + (0x3f9d494f), + (0x3f86b88f), + (0x3f92a9cf), + (0x3f89780f), + (0x3f9d694f), + (0x3f86988f), + (0x3f9289cf)}, + (0xfff80000), + {0xbd,0x88,0xcf,0x70,0x9b,0x4f,0x1b,0xe7,0xe6,0xab, + 0x62,0x27,0x66,0xaf,0x36,0xbb,0x10,0x8b,0x27,0xd7,0x00} + }, + { + /* No.33 delta:1105 weight:1263 */ + 11213, + 40, + 9, + 3, + {(0x00000000), + (0x4406f6da), + (0xf592d5cb), + (0xb1942311), + (0xe0900211), + (0xa496f4cb), + (0x1502d7da), + (0x51042100), + (0x0000075b), + (0x4406f181), + (0xf592d290), + (0xb194244a), + (0xe090054a), + (0xa496f390), + (0x1502d081), + (0x5104265b)}, + {(0x00000000), + (0x10151000), + (0x10640000), + (0x00711000), + (0x20081800), + (0x301d0800), + (0x306c1800), + (0x20790800), + (0x00025e00), + (0x10174e00), + (0x10665e00), + (0x00734e00), + (0x200a4600), + (0x301f5600), + (0x306e4600), + (0x207b5600)}, + {(0x3f800000), + (0x3f880a88), + (0x3f883200), + (0x3f803888), + (0x3f90040c), + (0x3f980e84), + (0x3f98360c), + (0x3f903c84), + (0x3f80012f), + (0x3f880ba7), + (0x3f88332f), + (0x3f8039a7), + (0x3f900523), + (0x3f980fab), + (0x3f983723), + (0x3f903dab)}, + (0xfff80000), + {0x13,0x48,0x32,0x45,0xca,0x30,0xd6,0xa0,0xae,0xd3, + 0x68,0x38,0x03,0x61,0x73,0x81,0x24,0xd8,0x43,0xf3,0x00} + }, + { + /* No.34 delta:7663 weight:713 */ + 11213, + 62, + 2, + 15, + {(0x00000000), + (0x9fe7bf95), + (0x7e1ef3d4), + (0xe1f94c41), + (0x32e00221), + (0xad07bdb4), + (0x4cfef1f5), + (0xd3194e60), + (0x00005fc6), + (0x9fe7e053), + (0x7e1eac12), + (0xe1f91387), + (0x32e05de7), + (0xad07e272), + (0x4cfeae33), + (0xd31911a6)}, + {(0x00000000), + (0x00000000), + (0x00000000), + (0x00000000), + (0x20000000), + (0x20000000), + (0x20000000), + (0x20000000), + (0x50001e00), + (0x50001e00), + (0x50001e00), + (0x50001e00), + (0x70001e00), + (0x70001e00), + (0x70001e00), + (0x70001e00)}, + {(0x3f800000), + (0x3f800000), + (0x3f800000), + (0x3f800000), + (0x3f900000), + (0x3f900000), + (0x3f900000), + (0x3f900000), + (0x3fa8000f), + (0x3fa8000f), + (0x3fa8000f), + (0x3fa8000f), + (0x3fb8000f), + (0x3fb8000f), + (0x3fb8000f), + (0x3fb8000f)}, + (0xfff80000), + {0x05,0x3c,0xe6,0xed,0x20,0xd0,0x5e,0x82,0xc3,0x47, + 0x89,0x62,0x9a,0x00,0x4f,0xdf,0x8a,0xe2,0x89,0xe4,0x00} + }, + { + /* No.35 delta:1045 weight:1387 */ + 11213, + 66, + 18, + 8, + {(0x00000000), + (0xcc054daa), + (0x64ce00f1), + (0xa8cb4d5b), + (0xc6200238), + (0x0a254f92), + (0xa2ee02c9), + (0x6eeb4f63), + (0x00006fce), + (0xcc052264), + (0x64ce6f3f), + (0xa8cb2295), + (0xc6206df6), + (0x0a25205c), + (0xa2ee6d07), + (0x6eeb20ad)}, + {(0x00000000), + (0xd07d1a00), + (0x08927800), + (0xd8ef6200), + (0x00a4c000), + (0xd0d9da00), + (0x0836b800), + (0xd84ba200), + (0x00025e00), + (0xd07f4400), + (0x08902600), + (0xd8ed3c00), + (0x00a69e00), + (0xd0db8400), + (0x0834e600), + (0xd849fc00)}, + {(0x3f800000), + (0x3fe83e8d), + (0x3f84493c), + (0x3fec77b1), + (0x3f805260), + (0x3fe86ced), + (0x3f841b5c), + (0x3fec25d1), + (0x3f80012f), + (0x3fe83fa2), + (0x3f844813), + (0x3fec769e), + (0x3f80534f), + (0x3fe86dc2), + (0x3f841a73), + (0x3fec24fe)}, + (0xfff80000), + {0x53,0xdb,0x48,0x5e,0x80,0xb8,0xf7,0x7d,0xd4,0x43, + 0xc8,0x11,0x1f,0x88,0x87,0x4f,0x05,0x24,0x64,0x44,0x00} + }, + { + /* No.36 delta:2076 weight:1703 */ + 11213, + 75, + 9, + 2, + {(0x00000000), + (0xc42d5e09), + (0x3ecbb703), + (0xfae6e90a), + (0xe9b00243), + (0x2d9d5c4a), + (0xd77bb540), + (0x1356eb49), + (0x00003832), + (0xc42d663b), + (0x3ecb8f31), + (0xfae6d138), + (0xe9b03a71), + (0x2d9d6478), + (0xd77b8d72), + (0x1356d37b)}, + {(0x00000000), + (0x003c8000), + (0x00700000), + (0x004c8000), + (0x00080000), + (0x00348000), + (0x00780000), + (0x00448000), + (0x00021e00), + (0x003e9e00), + (0x00721e00), + (0x004e9e00), + (0x000a1e00), + (0x00369e00), + (0x007a1e00), + (0x00469e00)}, + {(0x3f800000), + (0x3f801e40), + (0x3f803800), + (0x3f802640), + (0x3f800400), + (0x3f801a40), + (0x3f803c00), + (0x3f802240), + (0x3f80010f), + (0x3f801f4f), + (0x3f80390f), + (0x3f80274f), + (0x3f80050f), + (0x3f801b4f), + (0x3f803d0f), + (0x3f80234f)}, + (0xfff80000), + {0x83,0xeb,0x26,0xe2,0x25,0xfd,0x8b,0x40,0xfc,0xd8, + 0x09,0x63,0xa1,0xb0,0x60,0x56,0xec,0x05,0xc2,0x27,0x00} + }, + { + /* No.37 delta:2017 weight:1375 */ + 11213, + 20, + 23, + 4, + {(0x00000000), + (0xf3dee608), + (0x43968c18), + (0xb0486a10), + (0x82100252), + (0x71cee45a), + (0xc1868e4a), + (0x32586842), + (0x0000b8e9), + (0xf3de5ee1), + (0x439634f1), + (0xb048d2f9), + (0x8210babb), + (0x71ce5cb3), + (0xc18636a3), + (0x3258d0ab)}, + {(0x00000000), + (0x0f350000), + (0x08b40000), + (0x07810000), + (0x20c1a000), + (0x2ff4a000), + (0x2875a000), + (0x2740a000), + (0x201c1e00), + (0x2f291e00), + (0x28a81e00), + (0x279d1e00), + (0x00ddbe00), + (0x0fe8be00), + (0x0869be00), + (0x075cbe00)}, + {(0x3f800000), + (0x3f879a80), + (0x3f845a00), + (0x3f83c080), + (0x3f9060d0), + (0x3f97fa50), + (0x3f943ad0), + (0x3f93a050), + (0x3f900e0f), + (0x3f97948f), + (0x3f94540f), + (0x3f93ce8f), + (0x3f806edf), + (0x3f87f45f), + (0x3f8434df), + (0x3f83ae5f)}, + (0xfff80000), + {0x64,0x1e,0x04,0xb6,0x86,0x5e,0xd5,0x07,0x5c,0xb3, + 0xbe,0x3a,0x1b,0xc8,0xe4,0x45,0x9e,0xc4,0xcf,0x11,0x00} + }, + { + /* No.38 delta:2221 weight:1197 */ + 11213, + 37, + 24, + 7, + {(0x00000000), + (0x4fb7bfce), + (0x968c3f7b), + (0xd93b80b5), + (0x11300267), + (0x5e87bda9), + (0x87bc3d1c), + (0xc80b82d2), + (0x000002b3), + (0x4fb7bd7d), + (0x968c3dc8), + (0xd93b8206), + (0x113000d4), + (0x5e87bf1a), + (0x87bc3faf), + (0xc80b8061)}, + {(0x00000000), + (0x207f2400), + (0x0138c000), + (0x2147e400), + (0x00160000), + (0x20692400), + (0x012ec000), + (0x2151e400), + (0x30127e00), + (0x106d5a00), + (0x312abe00), + (0x11559a00), + (0x30047e00), + (0x107b5a00), + (0x313cbe00), + (0x11439a00)}, + {(0x3f800000), + (0x3f903f92), + (0x3f809c60), + (0x3f90a3f2), + (0x3f800b00), + (0x3f903492), + (0x3f809760), + (0x3f90a8f2), + (0x3f98093f), + (0x3f8836ad), + (0x3f98955f), + (0x3f88aacd), + (0x3f98023f), + (0x3f883dad), + (0x3f989e5f), + (0x3f88a1cd)}, + (0xfff80000), + {0x56,0x6e,0x0e,0xb6,0x39,0x79,0xe8,0x2f,0xdb,0x3a, + 0xb8,0xa6,0xb7,0x15,0xb4,0x26,0x23,0x62,0x6c,0x7b,0x00} + }, + { + /* No.39 delta:3255 weight:871 */ + 11213, + 59, + 27, + 3, + {(0x00000000), + (0xd9be1e48), + (0x75016ef8), + (0xacbf70b0), + (0x0e00027a), + (0xd7be1c32), + (0x7b016c82), + (0xa2bf72ca), + (0x00004209), + (0xd9be5c41), + (0x75012cf1), + (0xacbf32b9), + (0x0e004073), + (0xd7be5e3b), + (0x7b012e8b), + (0xa2bf30c3)}, + {(0x00000000), + (0x14ad8000), + (0x05013000), + (0x11acb000), + (0x092e2000), + (0x1d83a000), + (0x0c2f1000), + (0x18829000), + (0x07501e00), + (0x13fd9e00), + (0x02512e00), + (0x16fcae00), + (0x0e7e3e00), + (0x1ad3be00), + (0x0b7f0e00), + (0x1fd28e00)}, + {(0x3f800000), + (0x3f8a56c0), + (0x3f828098), + (0x3f88d658), + (0x3f849710), + (0x3f8ec1d0), + (0x3f861788), + (0x3f8c4148), + (0x3f83a80f), + (0x3f89fecf), + (0x3f812897), + (0x3f8b7e57), + (0x3f873f1f), + (0x3f8d69df), + (0x3f85bf87), + (0x3f8fe947)}, + (0xfff80000), + {0xde,0x46,0xf8,0xe9,0xab,0x16,0xb9,0x71,0xfd,0x07, + 0x49,0x31,0xbb,0x29,0xb9,0xce,0xd3,0x1e,0x43,0x2e,0x00} + }, + { + /* No.40 delta:3532 weight:1325 */ + 11213, + 8, + 11, + 4, + {(0x00000000), + (0xe314ffbd), + (0x98f9b31f), + (0x7bed4ca2), + (0x71b0028c), + (0x92a4fd31), + (0xe949b193), + (0x0a5d4e2e), + (0x0000e823), + (0xe314179e), + (0x98f95b3c), + (0x7beda481), + (0x71b0eaaf), + (0x92a41512), + (0xe94959b0), + (0x0a5da60d)}, + {(0x00000000), + (0x0c000000), + (0x0a800000), + (0x06800000), + (0x16100000), + (0x1a100000), + (0x1c900000), + (0x10900000), + (0x95801e00), + (0x99801e00), + (0x9f001e00), + (0x93001e00), + (0x83901e00), + (0x8f901e00), + (0x89101e00), + (0x85101e00)}, + {(0x3f800000), + (0x3f860000), + (0x3f854000), + (0x3f834000), + (0x3f8b0800), + (0x3f8d0800), + (0x3f8e4800), + (0x3f884800), + (0x3fcac00f), + (0x3fccc00f), + (0x3fcf800f), + (0x3fc9800f), + (0x3fc1c80f), + (0x3fc7c80f), + (0x3fc4880f), + (0x3fc2880f)}, + (0xfff80000), + {0xc3,0xa5,0xf2,0x8c,0xb3,0x3e,0xd2,0x53,0x92,0x0c, + 0x01,0x4a,0x5c,0x0a,0x47,0xe9,0x85,0xa2,0xf5,0x7f,0x00} + }, + { + /* No.41 delta:5222 weight:1281 */ + 11213, + 90, + 27, + 2, + {(0x00000000), + (0xf1807db4), + (0x9f84df41), + (0x6e04a2f5), + (0x04200296), + (0xf5a07f22), + (0x9ba4ddd7), + (0x6a24a063), + (0x00005700), + (0xf1802ab4), + (0x9f848841), + (0x6e04f5f5), + (0x04205596), + (0xf5a02822), + (0x9ba48ad7), + (0x6a24f763)}, + {(0x00000000), + (0xe9519000), + (0x1a06a800), + (0xf3573800), + (0x0d032000), + (0xe452b000), + (0x17058800), + (0xfe541800), + (0x036ade00), + (0xea3b4e00), + (0x196c7600), + (0xf03de600), + (0x0e69fe00), + (0xe7386e00), + (0x146f5600), + (0xfd3ec600)}, + {(0x3f800000), + (0x3ff4a8c8), + (0x3f8d0354), + (0x3ff9ab9c), + (0x3f868190), + (0x3ff22958), + (0x3f8b82c4), + (0x3fff2a0c), + (0x3f81b56f), + (0x3ff51da7), + (0x3f8cb63b), + (0x3ff81ef3), + (0x3f8734ff), + (0x3ff39c37), + (0x3f8a37ab), + (0x3ffe9f63)}, + (0xfff80000), + {0x08,0x0d,0xba,0x61,0x69,0x6b,0x70,0x44,0xbf,0x27, + 0x4a,0xe9,0xcb,0x98,0x26,0xb9,0xb3,0x5d,0x82,0x3d,0x00} + }, + { + /* No.42 delta:1107 weight:1153 */ + 11213, + 48, + 16, + 10, + {(0x00000000), + (0x6adad7b8), + (0x649ee9f9), + (0x0e443e41), + (0x1b2002a0), + (0x71fad518), + (0x7fbeeb59), + (0x15643ce1), + (0x0000f400), + (0x6ada23b8), + (0x649e1df9), + (0x0e44ca41), + (0x1b20f6a0), + (0x71fa2118), + (0x7fbe1f59), + (0x1564c8e1)}, + {(0x00000000), + (0x09409c00), + (0x0060c000), + (0x09205c00), + (0x04104a00), + (0x0d50d600), + (0x04708a00), + (0x0d301600), + (0x00087e00), + (0x0948e200), + (0x0068be00), + (0x09282200), + (0x04183400), + (0x0d58a800), + (0x0478f400), + (0x0d386800)}, + {(0x3f800000), + (0x3f84a04e), + (0x3f803060), + (0x3f84902e), + (0x3f820825), + (0x3f86a86b), + (0x3f823845), + (0x3f86980b), + (0x3f80043f), + (0x3f84a471), + (0x3f80345f), + (0x3f849411), + (0x3f820c1a), + (0x3f86ac54), + (0x3f823c7a), + (0x3f869c34)}, + (0xfff80000), + {0xb4,0xff,0xa8,0x22,0xa3,0x34,0x7b,0xfd,0xd4,0xca, + 0xef,0x82,0x97,0x4e,0x9d,0x89,0xeb,0xb2,0x55,0x2c,0x00} + }, + { + /* No.43 delta:3289 weight:739 */ + 11213, + 90, + 3, + 15, + {(0x00000000), + (0x12510afd), + (0xc2094a89), + (0xd0584074), + (0x5ce002b7), + (0x4eb1084a), + (0x9ee9483e), + (0x8cb842c3), + (0x00009dee), + (0x12519713), + (0xc209d767), + (0xd058dd9a), + (0x5ce09f59), + (0x4eb195a4), + (0x9ee9d5d0), + (0x8cb8df2d)}, + {(0x00000000), + (0x0c230400), + (0x033c0000), + (0x0f1f0400), + (0x03b08000), + (0x0f938400), + (0x008c8000), + (0x0caf8400), + (0x08705e00), + (0x04535a00), + (0x0b4c5e00), + (0x076f5a00), + (0x0bc0de00), + (0x07e3da00), + (0x08fcde00), + (0x04dfda00)}, + {(0x3f800000), + (0x3f861182), + (0x3f819e00), + (0x3f878f82), + (0x3f81d840), + (0x3f87c9c2), + (0x3f804640), + (0x3f8657c2), + (0x3f84382f), + (0x3f8229ad), + (0x3f85a62f), + (0x3f83b7ad), + (0x3f85e06f), + (0x3f83f1ed), + (0x3f847e6f), + (0x3f826fed)}, + (0xfff80000), + {0x47,0xd8,0xbd,0x66,0xb2,0xe8,0x3c,0x2c,0x45,0x90, + 0x88,0x27,0x9c,0x8f,0x27,0x40,0xc8,0xd9,0x0e,0xd6,0x00} + }, + { + /* No.44 delta:1477 weight:1191 */ + 11213, + 33, + 20, + 2, + {(0x00000000), + (0x3f4d49c2), + (0xdca457bf), + (0xe3e91e7d), + (0x5d5002cf), + (0x621d4b0d), + (0x81f45570), + (0xbeb91cb2), + (0x0000c277), + (0x3f4d8bb5), + (0xdca495c8), + (0xe3e9dc0a), + (0x5d50c0b8), + (0x621d897a), + (0x81f49707), + (0xbeb9dec5)}, + {(0x00000000), + (0x0275b800), + (0x7149c400), + (0x733c7c00), + (0x1058c000), + (0x122d7800), + (0x61110400), + (0x6364bc00), + (0x006f3e00), + (0x021a8600), + (0x7126fa00), + (0x73534200), + (0x1037fe00), + (0x12424600), + (0x617e3a00), + (0x630b8200)}, + {(0x3f800000), + (0x3f813adc), + (0x3fb8a4e2), + (0x3fb99e3e), + (0x3f882c60), + (0x3f8916bc), + (0x3fb08882), + (0x3fb1b25e), + (0x3f80379f), + (0x3f810d43), + (0x3fb8937d), + (0x3fb9a9a1), + (0x3f881bff), + (0x3f892123), + (0x3fb0bf1d), + (0x3fb185c1)}, + (0xfff80000), + {0x43,0xbd,0xc4,0xf1,0xb1,0xd7,0x24,0x47,0xc5,0xd0, + 0xa4,0xbc,0xc9,0x66,0xb3,0x4b,0x26,0xd1,0x26,0x85,0x00} + }, + { + /* No.45 delta:1261 weight:1353 */ + 11213, + 24, + 18, + 5, + {(0x00000000), + (0xabac4677), + (0x903dfbe7), + (0x3b91bd90), + (0xf83002d0), + (0x539c44a7), + (0x680df937), + (0xc3a1bf40), + (0x00004840), + (0xabac0e37), + (0x903db3a7), + (0x3b91f5d0), + (0xf8304a90), + (0x539c0ce7), + (0x680db177), + (0xc3a1f700)}, + {(0x00000000), + (0x00762800), + (0x200acc00), + (0x207ce400), + (0x6ea81000), + (0x6ede3800), + (0x4ea2dc00), + (0x4ed4f400), + (0x004e1e00), + (0x00383600), + (0x2044d200), + (0x2032fa00), + (0x6ee60e00), + (0x6e902600), + (0x4eecc200), + (0x4e9aea00)}, + {(0x3f800000), + (0x3f803b14), + (0x3f900566), + (0x3f903e72), + (0x3fb75408), + (0x3fb76f1c), + (0x3fa7516e), + (0x3fa76a7a), + (0x3f80270f), + (0x3f801c1b), + (0x3f902269), + (0x3f90197d), + (0x3fb77307), + (0x3fb74813), + (0x3fa77661), + (0x3fa74d75)}, + (0xfff80000), + {0x1c,0x79,0xc4,0xaf,0x4a,0xca,0x6f,0x97,0x73,0x87, + 0xe2,0xfa,0x1b,0x02,0x4e,0xfc,0xc2,0xc5,0x85,0xa8,0x00} + }, + { + /* No.46 delta:2871 weight:1351 */ + 11213, + 24, + 4, + 11, + {(0x00000000), + (0x5f7bd2a5), + (0x9b479801), + (0xc43c4aa4), + (0x793002ea), + (0x264bd04f), + (0xe2779aeb), + (0xbd0c484e), + (0x0000737e), + (0x5f7ba1db), + (0x9b47eb7f), + (0xc43c39da), + (0x79307194), + (0x264ba331), + (0xe277e995), + (0xbd0c3b30)}, + {(0x00000000), + (0x0a8c0000), + (0x10810000), + (0x1a0d0000), + (0x00600800), + (0x0aec0800), + (0x10e10800), + (0x1a6d0800), + (0x40101e00), + (0x4a9c1e00), + (0x50911e00), + (0x5a1d1e00), + (0x40701600), + (0x4afc1600), + (0x50f11600), + (0x5a7d1600)}, + {(0x3f800000), + (0x3f854600), + (0x3f884080), + (0x3f8d0680), + (0x3f803004), + (0x3f857604), + (0x3f887084), + (0x3f8d3684), + (0x3fa0080f), + (0x3fa54e0f), + (0x3fa8488f), + (0x3fad0e8f), + (0x3fa0380b), + (0x3fa57e0b), + (0x3fa8788b), + (0x3fad3e8b)}, + (0xfff80000), + {0x23,0xc7,0xec,0x47,0xae,0x9d,0xf4,0x29,0xa3,0xce, + 0x13,0x6c,0x06,0x67,0x5b,0x3a,0xb2,0xac,0x33,0xdb,0x00} + }, + { + /* No.47 delta:4370 weight:1245 */ + 11213, + 26, + 30, + 4, + {(0x00000000), + (0x1af999ae), + (0x1bfe6053), + (0x0107f9fd), + (0xb1f002f1), + (0xab099b5f), + (0xaa0e62a2), + (0xb0f7fb0c), + (0x0000281b), + (0x1af9b1b5), + (0x1bfe4848), + (0x0107d1e6), + (0xb1f02aea), + (0xab09b344), + (0xaa0e4ab9), + (0xb0f7d317)}, + {(0x00000000), + (0x0c201000), + (0x03140000), + (0x0f341000), + (0xe4200800), + (0xe8001800), + (0xe7340800), + (0xeb141800), + (0x08001e00), + (0x04200e00), + (0x0b141e00), + (0x07340e00), + (0xec201600), + (0xe0000600), + (0xef341600), + (0xe3140600)}, + {(0x3f800000), + (0x3f861008), + (0x3f818a00), + (0x3f879a08), + (0x3ff21004), + (0x3ff4000c), + (0x3ff39a04), + (0x3ff58a0c), + (0x3f84000f), + (0x3f821007), + (0x3f858a0f), + (0x3f839a07), + (0x3ff6100b), + (0x3ff00003), + (0x3ff79a0b), + (0x3ff18a03)}, + (0xfff80000), + {0x98,0x58,0x06,0x9e,0x81,0x14,0x32,0xd7,0x93,0x32, + 0x65,0xc8,0x13,0x43,0x02,0x53,0x1e,0xd3,0xaf,0x94,0x00} + }, + { + /* No.48 delta:1177 weight:859 */ + 11213, + 75, + 13, + 16, + {(0x00000000), + (0x8e9ecf83), + (0xb438b3ee), + (0x3aa67c6d), + (0xbd800305), + (0x331ecc86), + (0x09b8b0eb), + (0x87267f68), + (0x0000d641), + (0x8e9e19c2), + (0xb43865af), + (0x3aa6aa2c), + (0xbd80d544), + (0x331e1ac7), + (0x09b866aa), + (0x8726a929)}, + {(0x00000000), + (0x0f7d1c00), + (0x76262000), + (0x795b3c00), + (0x41532000), + (0x4e2e3c00), + (0x37750000), + (0x38081c00), + (0x00429e00), + (0x0f3f8200), + (0x7664be00), + (0x7919a200), + (0x4111be00), + (0x4e6ca200), + (0x37379e00), + (0x384a8200)}, + {(0x3f800000), + (0x3f87be8e), + (0x3fbb1310), + (0x3fbcad9e), + (0x3fa0a990), + (0x3fa7171e), + (0x3f9bba80), + (0x3f9c040e), + (0x3f80214f), + (0x3f879fc1), + (0x3fbb325f), + (0x3fbc8cd1), + (0x3fa088df), + (0x3fa73651), + (0x3f9b9bcf), + (0x3f9c2541)}, + (0xfff80000), + {0xc9,0xe0,0x77,0x04,0x4f,0x92,0x96,0xd4,0x05,0xdc, + 0x3e,0x3c,0xa6,0xf3,0x8e,0x2d,0xdb,0xf2,0x8c,0xe4,0x00} + }, + { + /* No.49 delta:3224 weight:947 */ + 11213, + 65, + 7, + 13, + {(0x00000000), + (0x9221eadf), + (0x5003b0d0), + (0xc2225a0f), + (0x0d800317), + (0x9fa1e9c8), + (0x5d83b3c7), + (0xcfa25918), + (0x00005031), + (0x9221baee), + (0x5003e0e1), + (0xc2220a3e), + (0x0d805326), + (0x9fa1b9f9), + (0x5d83e3f6), + (0xcfa20929)}, + {(0x00000000), + (0x00400800), + (0x60600000), + (0x60200800), + (0x00000000), + (0x00400800), + (0x60600000), + (0x60200800), + (0x30101e00), + (0x30501600), + (0x50701e00), + (0x50301600), + (0x30101e00), + (0x30501600), + (0x50701e00), + (0x50301600)}, + {(0x3f800000), + (0x3f802004), + (0x3fb03000), + (0x3fb01004), + (0x3f800000), + (0x3f802004), + (0x3fb03000), + (0x3fb01004), + (0x3f98080f), + (0x3f98280b), + (0x3fa8380f), + (0x3fa8180b), + (0x3f98080f), + (0x3f98280b), + (0x3fa8380f), + (0x3fa8180b)}, + (0xfff80000), + {0xc1,0x70,0x72,0x7f,0xb1,0x1e,0x6e,0xc5,0xec,0xcc, + 0x69,0xd8,0x0b,0xba,0x4e,0x2c,0x73,0x46,0x81,0x52,0x00} + }, + { + /* No.50 delta:6665 weight:1221 */ + 11213, + 84, + 1, + 9, + {(0x00000000), + (0xbdb9b41e), + (0x9876c465), + (0x25cf707b), + (0x25c0032f), + (0x9879b731), + (0xbdb6c74a), + (0x000f7354), + (0x00003009), + (0xbdb98417), + (0x9876f46c), + (0x25cf4072), + (0x25c03326), + (0x98798738), + (0xbdb6f743), + (0x000f435d)}, + {(0x00000000), + (0x51000000), + (0x20000000), + (0x71000000), + (0x04200000), + (0x55200000), + (0x24200000), + (0x75200000), + (0x17201e00), + (0x46201e00), + (0x37201e00), + (0x66201e00), + (0x13001e00), + (0x42001e00), + (0x33001e00), + (0x62001e00)}, + {(0x3f800000), + (0x3fa88000), + (0x3f900000), + (0x3fb88000), + (0x3f821000), + (0x3faa9000), + (0x3f921000), + (0x3fba9000), + (0x3f8b900f), + (0x3fa3100f), + (0x3f9b900f), + (0x3fb3100f), + (0x3f89800f), + (0x3fa1000f), + (0x3f99800f), + (0x3fb1000f)}, + (0xfff80000), + {0xdf,0xd6,0xd2,0xb4,0x0a,0xa4,0x35,0xbe,0x0f,0xa6, + 0x48,0x42,0xfe,0x0c,0x0f,0xa3,0xa9,0x64,0x1b,0x93,0x00} + }, + { + /* No.51 delta:6604 weight:1075 */ + 11213, + 61, + 3, + 13, + {(0x00000000), + (0xe7ec9698), + (0xdc943f6e), + (0x3b78a9f6), + (0xdf600330), + (0x388c95a8), + (0x03f43c5e), + (0xe418aac6), + (0x000058c3), + (0xe7ecce5b), + (0xdc9467ad), + (0x3b78f135), + (0xdf605bf3), + (0x388ccd6b), + (0x03f4649d), + (0xe418f205)}, + {(0x00000000), + (0x80000000), + (0x50000000), + (0xd0000000), + (0x20000000), + (0xa0000000), + (0x70000000), + (0xf0000000), + (0x00001e00), + (0x80001e00), + (0x50001e00), + (0xd0001e00), + (0x20001e00), + (0xa0001e00), + (0x70001e00), + (0xf0001e00)}, + {(0x3f800000), + (0x3fc00000), + (0x3fa80000), + (0x3fe80000), + (0x3f900000), + (0x3fd00000), + (0x3fb80000), + (0x3ff80000), + (0x3f80000f), + (0x3fc0000f), + (0x3fa8000f), + (0x3fe8000f), + (0x3f90000f), + (0x3fd0000f), + (0x3fb8000f), + (0x3ff8000f)}, + (0xfff80000), + {0xf2,0x95,0xcc,0x96,0x13,0xa0,0x75,0xc2,0xea,0x1a, + 0x5c,0x2d,0xcc,0x41,0x22,0xf8,0x87,0x8d,0x52,0xc0,0x00} + }, + { + /* No.52 delta:980 weight:1115 */ + 11213, + 75, + 17, + 12, + {(0x00000000), + (0x619af787), + (0x463e8326), + (0x27a474a1), + (0xc5c00348), + (0xa45af4cf), + (0x83fe806e), + (0xe26477e9), + (0x00008ae3), + (0x619a7d64), + (0x463e09c5), + (0x27a4fe42), + (0xc5c089ab), + (0xa45a7e2c), + (0x83fe0a8d), + (0xe264fd0a)}, + {(0x00000000), + (0x107c1400), + (0x81204400), + (0x915c5000), + (0x00113400), + (0x106d2000), + (0x81317000), + (0x914d6400), + (0x000ede00), + (0x1072ca00), + (0x812e9a00), + (0x91528e00), + (0x001fea00), + (0x1063fe00), + (0x813fae00), + (0x9143ba00)}, + {(0x3f800000), + (0x3f883e0a), + (0x3fc09022), + (0x3fc8ae28), + (0x3f80089a), + (0x3f883690), + (0x3fc098b8), + (0x3fc8a6b2), + (0x3f80076f), + (0x3f883965), + (0x3fc0974d), + (0x3fc8a947), + (0x3f800ff5), + (0x3f8831ff), + (0x3fc09fd7), + (0x3fc8a1dd)}, + (0xfff80000), + {0x31,0x3b,0x59,0xba,0x4b,0xfa,0x15,0x6d,0x68,0x38, + 0xd0,0x59,0x4b,0xc5,0xee,0xd6,0xd1,0x72,0x77,0x56,0x00} + }, + { + /* No.53 delta:2128 weight:1031 */ + 11213, + 90, + 18, + 10, + {(0x00000000), + (0x54ddf61b), + (0x3289e26b), + (0x66541470), + (0x8c500359), + (0xd88df542), + (0xbed9e132), + (0xea041729), + (0x0000fb30), + (0x54dd0d2b), + (0x3289195b), + (0x6654ef40), + (0x8c50f869), + (0xd88d0e72), + (0xbed91a02), + (0xea04ec19)}, + {(0x00000000), + (0x80710000), + (0x704e0000), + (0xf03f0000), + (0x40450000), + (0xc0340000), + (0x300b0000), + (0xb07a0000), + (0x000c1e00), + (0x807d1e00), + (0x70421e00), + (0xf0331e00), + (0x40491e00), + (0xc0381e00), + (0x30071e00), + (0xb0761e00)}, + {(0x3f800000), + (0x3fc03880), + (0x3fb82700), + (0x3ff81f80), + (0x3fa02280), + (0x3fe01a00), + (0x3f980580), + (0x3fd83d00), + (0x3f80060f), + (0x3fc03e8f), + (0x3fb8210f), + (0x3ff8198f), + (0x3fa0248f), + (0x3fe01c0f), + (0x3f98038f), + (0x3fd83b0f)}, + (0xfff80000), + {0x2c,0x15,0xc7,0x91,0x8f,0xe7,0xba,0x43,0x56,0x9b, + 0xf8,0xd4,0x59,0xf2,0x0c,0x4e,0xf2,0x42,0x9a,0xfe,0x00} + }, + { + /* No.54 delta:2047 weight:935 */ + 11213, + 73, + 6, + 15, + {(0x00000000), + (0x1b3e4d84), + (0x40583cec), + (0x5b667168), + (0x82600363), + (0x995e4ee7), + (0xc2383f8f), + (0xd906720b), + (0x000025e9), + (0x1b3e686d), + (0x40581905), + (0x5b665481), + (0x8260268a), + (0x995e6b0e), + (0xc2381a66), + (0xd90657e2)}, + {(0x00000000), + (0x00524000), + (0x52804000), + (0x52d20000), + (0x00232000), + (0x00716000), + (0x52a36000), + (0x52f12000), + (0x21c51e00), + (0x21975e00), + (0x73455e00), + (0x73171e00), + (0x21e63e00), + (0x21b47e00), + (0x73667e00), + (0x73343e00)}, + {(0x3f800000), + (0x3f802920), + (0x3fa94020), + (0x3fa96900), + (0x3f801190), + (0x3f8038b0), + (0x3fa951b0), + (0x3fa97890), + (0x3f90e28f), + (0x3f90cbaf), + (0x3fb9a2af), + (0x3fb98b8f), + (0x3f90f31f), + (0x3f90da3f), + (0x3fb9b33f), + (0x3fb99a1f)}, + (0xfff80000), + {0x67,0xd5,0xbe,0x19,0x7f,0x4e,0x37,0xca,0xeb,0x0b, + 0x09,0x52,0xc2,0x91,0x23,0x02,0xb9,0xa6,0xdd,0x1e,0x00} + }, + { + /* No.55 delta:1367 weight:1089 */ + 11213, + 30, + 14, + 10, + {(0x00000000), + (0x3d4e7360), + (0xd47d559c), + (0xe93326fc), + (0x10e00371), + (0x2dae7011), + (0xc49d56ed), + (0xf9d3258d), + (0x0000f71b), + (0x3d4e847b), + (0xd47da287), + (0xe933d1e7), + (0x10e0f46a), + (0x2dae870a), + (0xc49da1f6), + (0xf9d3d296)}, + {(0x00000000), + (0x6b729000), + (0x206f1800), + (0x4b1d8800), + (0x00501a00), + (0x6b228a00), + (0x203f0200), + (0x4b4d9200), + (0x20103e00), + (0x4b62ae00), + (0x007f2600), + (0x6b0db600), + (0x20402400), + (0x4b32b400), + (0x002f3c00), + (0x6b5dac00)}, + {(0x3f800000), + (0x3fb5b948), + (0x3f90378c), + (0x3fa58ec4), + (0x3f80280d), + (0x3fb59145), + (0x3f901f81), + (0x3fa5a6c9), + (0x3f90081f), + (0x3fa5b157), + (0x3f803f93), + (0x3fb586db), + (0x3f902012), + (0x3fa5995a), + (0x3f80179e), + (0x3fb5aed6)}, + (0xfff80000), + {0x74,0x06,0xc4,0x94,0x50,0xc8,0x89,0xd9,0x6c,0x24, + 0x1b,0x4e,0x7f,0x96,0xbe,0x0a,0xb0,0xbb,0xa9,0x75,0x00} + }, + { + /* No.56 delta:1232 weight:1251 */ + 11213, + 56, + 20, + 8, + {(0x00000000), + (0x303bfd65), + (0x96ea74b0), + (0xa6d189d5), + (0x1d200385), + (0x2d1bfee0), + (0x8bca7735), + (0xbbf18a50), + (0x0000e0a3), + (0x303b1dc6), + (0x96ea9413), + (0xa6d16976), + (0x1d20e326), + (0x2d1b1e43), + (0x8bca9796), + (0xbbf16af3)}, + {(0x00000000), + (0x0e9c1400), + (0x00661e00), + (0x0efa0a00), + (0x20125000), + (0x2e8e4400), + (0x20744e00), + (0x2ee85a00), + (0x001abe00), + (0x0e86aa00), + (0x007ca000), + (0x0ee0b400), + (0x2008ee00), + (0x2e94fa00), + (0x206ef000), + (0x2ef2e400)}, + {(0x3f800000), + (0x3f874e0a), + (0x3f80330f), + (0x3f877d05), + (0x3f900928), + (0x3f974722), + (0x3f903a27), + (0x3f97742d), + (0x3f800d5f), + (0x3f874355), + (0x3f803e50), + (0x3f87705a), + (0x3f900477), + (0x3f974a7d), + (0x3f903778), + (0x3f977972)}, + (0xfff80000), + {0x9f,0xb8,0x5c,0x52,0x53,0x38,0x40,0xed,0x9b,0x43, + 0xe8,0x89,0x8c,0xd0,0x44,0x25,0x4b,0xbf,0xca,0xd0,0x00} + }, + { + /* No.57 delta:1379 weight:873 */ + 11213, + 89, + 13, + 1, + {(0x00000000), + (0xfacfdd0b), + (0x22ecafbf), + (0xd82372b4), + (0x85500390), + (0x7f9fde9b), + (0xa7bcac2f), + (0x5d737124), + (0x0000d423), + (0xfacf0928), + (0x22ec7b9c), + (0xd823a697), + (0x8550d7b3), + (0x7f9f0ab8), + (0xa7bc780c), + (0x5d73a507)}, + {(0x00000000), + (0x2c081000), + (0x05201800), + (0x29280800), + (0x20e00400), + (0x0ce81400), + (0x25c01c00), + (0x09c80c00), + (0x11481e00), + (0x3d400e00), + (0x14680600), + (0x38601600), + (0x31a81a00), + (0x1da00a00), + (0x34880200), + (0x18801200)}, + {(0x3f800000), + (0x3f960408), + (0x3f82900c), + (0x3f949404), + (0x3f907002), + (0x3f86740a), + (0x3f92e00e), + (0x3f84e406), + (0x3f88a40f), + (0x3f9ea007), + (0x3f8a3403), + (0x3f9c300b), + (0x3f98d40d), + (0x3f8ed005), + (0x3f9a4401), + (0x3f8c4009)}, + (0xfff80000), + {0x08,0x0f,0x24,0x9d,0x3a,0xba,0x6d,0xb4,0xb0,0x1a, + 0x1c,0x4b,0x44,0xe7,0x44,0xf7,0xc9,0x4a,0x5f,0x97,0x00} + }, + { + /* No.58 delta:904 weight:1097 */ + 11213, + 60, + 16, + 2, + {(0x00000000), + (0xda86476d), + (0x6c05798d), + (0xb6833ee0), + (0xb72003ae), + (0x6da644c3), + (0xdb257a23), + (0x01a33d4e), + (0x00001489), + (0xda8653e4), + (0x6c056d04), + (0xb6832a69), + (0xb7201727), + (0x6da6504a), + (0xdb256eaa), + (0x01a329c7)}, + {(0x00000000), + (0x0c74f000), + (0x0059a800), + (0x0c2d5800), + (0x02445000), + (0x0e30a000), + (0x021df800), + (0x0e690800), + (0x0902de00), + (0x05762e00), + (0x095b7600), + (0x052f8600), + (0x0b468e00), + (0x07327e00), + (0x0b1f2600), + (0x076bd600)}, + {(0x3f800000), + (0x3f863a78), + (0x3f802cd4), + (0x3f8616ac), + (0x3f812228), + (0x3f871850), + (0x3f810efc), + (0x3f873484), + (0x3f84816f), + (0x3f82bb17), + (0x3f84adbb), + (0x3f8297c3), + (0x3f85a347), + (0x3f83993f), + (0x3f858f93), + (0x3f83b5eb)}, + (0xfff80000), + {0xb8,0xe0,0xa0,0x3b,0x2e,0x11,0x17,0x83,0x7b,0x75, + 0x85,0x89,0xfa,0x1e,0x49,0xb4,0x5c,0xe6,0xb8,0xc1,0x00} + }, + { + /* No.59 delta:7724 weight:1539 */ + 11213, + 42, + 28, + 4, + {(0x00000000), + (0xdfefef22), + (0x804185a4), + (0x5fae6a86), + (0x54b003b3), + (0x8b5fec91), + (0xd4f18617), + (0x0b1e6935), + (0x00009211), + (0xdfef7d33), + (0x804117b5), + (0x5faef897), + (0x54b091a2), + (0x8b5f7e80), + (0xd4f11406), + (0x0b1efb24)}, + {(0x00000000), + (0x38020000), + (0x08014000), + (0x30034000), + (0x04000800), + (0x3c020800), + (0x0c014800), + (0x34034800), + (0x08001e00), + (0x30021e00), + (0x00015e00), + (0x38035e00), + (0x0c001600), + (0x34021600), + (0x04015600), + (0x3c035600)}, + {(0x3f800000), + (0x3f9c0100), + (0x3f8400a0), + (0x3f9801a0), + (0x3f820004), + (0x3f9e0104), + (0x3f8600a4), + (0x3f9a01a4), + (0x3f84000f), + (0x3f98010f), + (0x3f8000af), + (0x3f9c01af), + (0x3f86000b), + (0x3f9a010b), + (0x3f8200ab), + (0x3f9e01ab)}, + (0xfff80000), + {0x91,0xba,0x8c,0xac,0x44,0xa7,0x81,0xa7,0xed,0x37, + 0x7e,0x8d,0xaf,0xe5,0x08,0xe6,0xc7,0x1d,0xfd,0xe5,0x00} + }, + { + /* No.60 delta:2411 weight:1317 */ + 11213, + 13, + 24, + 5, + {(0x00000000), + (0x9dd3ce8f), + (0x90da0878), + (0x0d09c6f7), + (0xad8003cf), + (0x3053cd40), + (0x3d5a0bb7), + (0xa089c538), + (0x0000bcb0), + (0x9dd3723f), + (0x90dab4c8), + (0x0d097a47), + (0xad80bf7f), + (0x305371f0), + (0x3d5ab707), + (0xa0897988)}, + {(0x00000000), + (0x4c0b9800), + (0x0fa54000), + (0x43aed800), + (0x0067c000), + (0x4c6c5800), + (0x0fc28000), + (0x43c91800), + (0x0a105e00), + (0x461bc600), + (0x05b51e00), + (0x49be8600), + (0x0a779e00), + (0x467c0600), + (0x05d2de00), + (0x49d94600)}, + {(0x3f800000), + (0x3fa605cc), + (0x3f87d2a0), + (0x3fa1d76c), + (0x3f8033e0), + (0x3fa6362c), + (0x3f87e140), + (0x3fa1e48c), + (0x3f85082f), + (0x3fa30de3), + (0x3f82da8f), + (0x3fa4df43), + (0x3f853bcf), + (0x3fa33e03), + (0x3f82e96f), + (0x3fa4eca3)}, + (0xfff80000), + {0xac,0x0b,0xb8,0x4d,0x6f,0xbd,0x47,0x8b,0x3f,0x9c, + 0x92,0xd0,0x32,0xf9,0x89,0x38,0xda,0x67,0xea,0xbe,0x00} + }, + { + /* No.61 delta:1265 weight:827 */ + 11213, + 52, + 17, + 15, + {(0x00000000), + (0xa4b47608), + (0x36bc0fca), + (0x920879c2), + (0xdeb003d6), + (0x7a0475de), + (0xe80c0c1c), + (0x4cb87a14), + (0x0000fbcf), + (0xa4b48dc7), + (0x36bcf405), + (0x9208820d), + (0xdeb0f819), + (0x7a048e11), + (0xe80cf7d3), + (0x4cb881db)}, + {(0x00000000), + (0x0813ae00), + (0x20151000), + (0x2806be00), + (0x4029c000), + (0x483a6e00), + (0x603cd000), + (0x682f7e00), + (0x52035e00), + (0x5a10f000), + (0x72164e00), + (0x7a05e000), + (0x122a9e00), + (0x1a393000), + (0x323f8e00), + (0x3a2c2000)}, + {(0x3f800000), + (0x3f8409d7), + (0x3f900a88), + (0x3f94035f), + (0x3fa014e0), + (0x3fa41d37), + (0x3fb01e68), + (0x3fb417bf), + (0x3fa901af), + (0x3fad0878), + (0x3fb90b27), + (0x3fbd02f0), + (0x3f89154f), + (0x3f8d1c98), + (0x3f991fc7), + (0x3f9d1610)}, + (0xfff80000), + {0xb2,0x25,0x08,0xf6,0xcd,0xda,0xfa,0xdb,0x2f,0xe7, + 0x81,0x83,0x7f,0xb8,0x75,0x05,0xff,0x2c,0x1a,0x80,0x00} + }, + { + /* No.62 delta:3397 weight:1223 */ + 11213, + 44, + 3, + 7, + {(0x00000000), + (0x89ffcb3c), + (0xafe67560), + (0x2619be5c), + (0xf79003e8), + (0x7e6fc8d4), + (0x58767688), + (0xd189bdb4), + (0x0000dcdc), + (0x89ff17e0), + (0xafe6a9bc), + (0x26196280), + (0xf790df34), + (0x7e6f1408), + (0x5876aa54), + (0xd1896168)}, + {(0x00000000), + (0x00710000), + (0xb00e0800), + (0xb07f0800), + (0x90120000), + (0x90630000), + (0x201c0800), + (0x206d0800), + (0x40091e00), + (0x40781e00), + (0xf0071600), + (0xf0761600), + (0xd01b1e00), + (0xd06a1e00), + (0x60151600), + (0x60641600)}, + {(0x3f800000), + (0x3f803880), + (0x3fd80704), + (0x3fd83f84), + (0x3fc80900), + (0x3fc83180), + (0x3f900e04), + (0x3f903684), + (0x3fa0048f), + (0x3fa03c0f), + (0x3ff8038b), + (0x3ff83b0b), + (0x3fe80d8f), + (0x3fe8350f), + (0x3fb00a8b), + (0x3fb0320b)}, + (0xfff80000), + {0x65,0x92,0xc9,0x30,0xd4,0x39,0xe2,0xf8,0x3a,0x06, + 0x72,0x5a,0xf0,0xe9,0x6f,0x1d,0x41,0xb8,0x38,0xcb,0x00} + }, + { + /* No.63 delta:1253 weight:1063 */ + 11213, + 40, + 15, + 8, + {(0x00000000), + (0xf0f1fa2b), + (0xc095cbf9), + (0x306431d2), + (0x84c003f6), + (0x7431f9dd), + (0x4455c80f), + (0xb4a43224), + (0x000041b7), + (0xf0f1bb9c), + (0xc0958a4e), + (0x30647065), + (0x84c04241), + (0x7431b86a), + (0x445589b8), + (0xb4a47393)}, + {(0x00000000), + (0x000f4800), + (0x00c47000), + (0x00cb3800), + (0x001ec000), + (0x00118800), + (0x00dab000), + (0x00d5f800), + (0xc01d9e00), + (0xc012d600), + (0xc0d9ee00), + (0xc0d6a600), + (0xc0035e00), + (0xc00c1600), + (0xc0c72e00), + (0xc0c86600)}, + {(0x3f800000), + (0x3f8007a4), + (0x3f806238), + (0x3f80659c), + (0x3f800f60), + (0x3f8008c4), + (0x3f806d58), + (0x3f806afc), + (0x3fe00ecf), + (0x3fe0096b), + (0x3fe06cf7), + (0x3fe06b53), + (0x3fe001af), + (0x3fe0060b), + (0x3fe06397), + (0x3fe06433)}, + (0xfff80000), + {0x6a,0x42,0x24,0x72,0x49,0x2e,0x6c,0xc6,0x39,0xde, + 0x29,0x45,0x5e,0xba,0x3b,0xda,0xc6,0xb7,0x79,0xd2,0x00} + }, + { + /* No.64 delta:5028 weight:833 */ + 11213, + 40, + 3, + 16, + {(0x00000000), + (0x0fda9709), + (0xdb5d90d9), + (0xd48707d0), + (0x78500401), + (0x778a9308), + (0xa30d94d8), + (0xacd703d1), + (0x00000aa4), + (0x0fda9dad), + (0xdb5d9a7d), + (0xd4870d74), + (0x78500ea5), + (0x778a99ac), + (0xa30d9e7c), + (0xacd70975)}, + {(0x00000000), + (0x19200000), + (0x83a00000), + (0x9a800000), + (0x00800000), + (0x19a00000), + (0x83200000), + (0x9a000000), + (0x41001e00), + (0x58201e00), + (0xc2a01e00), + (0xdb801e00), + (0x41801e00), + (0x58a01e00), + (0xc2201e00), + (0xdb001e00)}, + {(0x3f800000), + (0x3f8c9000), + (0x3fc1d000), + (0x3fcd4000), + (0x3f804000), + (0x3f8cd000), + (0x3fc19000), + (0x3fcd0000), + (0x3fa0800f), + (0x3fac100f), + (0x3fe1500f), + (0x3fedc00f), + (0x3fa0c00f), + (0x3fac500f), + (0x3fe1100f), + (0x3fed800f)}, + (0xfff80000), + {0x7f,0xa7,0x79,0xc1,0x02,0x5a,0xb9,0x48,0xd7,0xc2, + 0x1b,0xde,0x64,0x28,0xca,0x0c,0xa1,0xb8,0xbd,0x71,0x00} + }, + { + /* No.65 delta:1199 weight:1181 */ + 11213, + 35, + 20, + 9, + {(0x00000000), + (0xf97f5fb7), + (0x820665df), + (0x7b793a68), + (0xeda00417), + (0x14df5ba0), + (0x6fa661c8), + (0x96d93e7f), + (0x0000be8a), + (0xf97fe13d), + (0x8206db55), + (0x7b7984e2), + (0xeda0ba9d), + (0x14dfe52a), + (0x6fa6df42), + (0x96d980f5)}, + {(0x00000000), + (0x0c163000), + (0x000c1000), + (0x0c1a2000), + (0xc0028000), + (0xcc14b000), + (0xc00e9000), + (0xcc18a000), + (0x7101de00), + (0x7d17ee00), + (0x710dce00), + (0x7d1bfe00), + (0xb1035e00), + (0xbd156e00), + (0xb10f4e00), + (0xbd197e00)}, + {(0x3f800000), + (0x3f860b18), + (0x3f800608), + (0x3f860d10), + (0x3fe00140), + (0x3fe60a58), + (0x3fe00748), + (0x3fe60c50), + (0x3fb880ef), + (0x3fbe8bf7), + (0x3fb886e7), + (0x3fbe8dff), + (0x3fd881af), + (0x3fde8ab7), + (0x3fd887a7), + (0x3fde8cbf)}, + (0xfff80000), + {0x44,0x09,0x7e,0x16,0x6a,0x0b,0xbf,0xd6,0xf6,0x83, + 0xc1,0x33,0x24,0x8d,0x24,0x40,0xc5,0xee,0xb0,0xd2,0x00} + }, + { + /* No.66 delta:1553 weight:539 */ + 11213, + 26, + 13, + 19, + {(0x00000000), + (0xc75eb6dc), + (0xfa4bc661), + (0x3d1570bd), + (0x6f600428), + (0xa83eb2f4), + (0x952bc249), + (0x52757495), + (0x0000df90), + (0xc75e694c), + (0xfa4b19f1), + (0x3d15af2d), + (0x6f60dbb8), + (0xa83e6d64), + (0x952b1dd9), + (0x5275ab05)}, + {(0x00000000), + (0x00521800), + (0x20647400), + (0x20366c00), + (0x60dc1800), + (0x608e0000), + (0x40b86c00), + (0x40ea7400), + (0x10341e00), + (0x10660600), + (0x30506a00), + (0x30027200), + (0x70e80600), + (0x70ba1e00), + (0x508c7200), + (0x50de6a00)}, + {(0x3f800000), + (0x3f80290c), + (0x3f90323a), + (0x3f901b36), + (0x3fb06e0c), + (0x3fb04700), + (0x3fa05c36), + (0x3fa0753a), + (0x3f881a0f), + (0x3f883303), + (0x3f982835), + (0x3f980139), + (0x3fb87403), + (0x3fb85d0f), + (0x3fa84639), + (0x3fa86f35)}, + (0xfff80000), + {0xe3,0x81,0xfe,0x0e,0xae,0xa6,0x17,0x99,0xb5,0xdc, + 0x36,0xa3,0xa9,0x84,0x5e,0xac,0xaf,0x0b,0xa6,0x5e,0x00} + }, + { + /* No.67 delta:1370 weight:1349 */ + 11213, + 50, + 8, + 4, + {(0x00000000), + (0xf2eee92e), + (0x184a48a6), + (0xeaa4a188), + (0x3cb00439), + (0xce5eed17), + (0x24fa4c9f), + (0xd614a5b1), + (0x0000c236), + (0xf2ee2b18), + (0x184a8a90), + (0xeaa463be), + (0x3cb0c60f), + (0xce5e2f21), + (0x24fa8ea9), + (0xd6146787)}, + {(0x00000000), + (0x40028000), + (0x70014000), + (0x3003c000), + (0x20002000), + (0x6002a000), + (0x50016000), + (0x1003e000), + (0x10001e00), + (0x50029e00), + (0x60015e00), + (0x2003de00), + (0x30003e00), + (0x7002be00), + (0x40017e00), + (0x0003fe00)}, + {(0x3f800000), + (0x3fa00140), + (0x3fb800a0), + (0x3f9801e0), + (0x3f900010), + (0x3fb00150), + (0x3fa800b0), + (0x3f8801f0), + (0x3f88000f), + (0x3fa8014f), + (0x3fb000af), + (0x3f9001ef), + (0x3f98001f), + (0x3fb8015f), + (0x3fa000bf), + (0x3f8001ff)}, + (0xfff80000), + {0xce,0xab,0xcf,0x53,0x4e,0xc1,0xc1,0xd0,0x64,0x84, + 0xd7,0xc3,0xad,0x13,0xad,0xf4,0xf7,0x14,0xe1,0xd6,0x00} + }, + { + /* No.68 delta:1769 weight:1053 */ + 11213, + 44, + 23, + 7, + {(0x00000000), + (0x1c10f784), + (0xb81f8711), + (0xa40f7095), + (0xd0d00449), + (0xccc0f3cd), + (0x68cf8358), + (0x74df74dc), + (0x00006582), + (0x1c109206), + (0xb81fe293), + (0xa40f1517), + (0xd0d061cb), + (0xccc0964f), + (0x68cfe6da), + (0x74df115e)}, + {(0x00000000), + (0x009da000), + (0x40746000), + (0x40e9c000), + (0x00028400), + (0x009f2400), + (0x4076e400), + (0x40eb4400), + (0x700bbe00), + (0x70961e00), + (0x307fde00), + (0x30e27e00), + (0x70093a00), + (0x70949a00), + (0x307d5a00), + (0x30e0fa00)}, + {(0x3f800000), + (0x3f804ed0), + (0x3fa03a30), + (0x3fa074e0), + (0x3f800142), + (0x3f804f92), + (0x3fa03b72), + (0x3fa075a2), + (0x3fb805df), + (0x3fb84b0f), + (0x3f983fef), + (0x3f98713f), + (0x3fb8049d), + (0x3fb84a4d), + (0x3f983ead), + (0x3f98707d)}, + (0xfff80000), + {0x25,0xc5,0x2b,0x7e,0x94,0x70,0x50,0xab,0x68,0x79, + 0xe0,0x34,0x49,0x1e,0xd3,0x2a,0xe2,0x9f,0xef,0x26,0x00} + }, + { + /* No.69 delta:1887 weight:1253 */ + 11213, + 64, + 9, + 8, + {(0x00000000), + (0x4cbf4fb8), + (0xcc209ffc), + (0x809fd044), + (0x7e700455), + (0x32cf4bed), + (0xb2509ba9), + (0xfeefd411), + (0x0000612d), + (0x4cbf2e95), + (0xcc20fed1), + (0x809fb169), + (0x7e706578), + (0x32cf2ac0), + (0xb250fa84), + (0xfeefb53c)}, + {(0x00000000), + (0x50090000), + (0x00035000), + (0x500a5000), + (0x04019000), + (0x54089000), + (0x0402c000), + (0x540bc000), + (0x05027e00), + (0x550b7e00), + (0x05012e00), + (0x55082e00), + (0x0103ee00), + (0x510aee00), + (0x0100be00), + (0x5109be00)}, + {(0x3f800000), + (0x3fa80480), + (0x3f8001a8), + (0x3fa80528), + (0x3f8200c8), + (0x3faa0448), + (0x3f820160), + (0x3faa05e0), + (0x3f82813f), + (0x3faa85bf), + (0x3f828097), + (0x3faa8417), + (0x3f8081f7), + (0x3fa88577), + (0x3f80805f), + (0x3fa884df)}, + (0xfff80000), + {0x1f,0x11,0x3a,0x53,0x30,0xf5,0x3a,0x92,0x69,0x8f, + 0x5e,0x40,0x86,0x58,0x16,0xa4,0x7f,0x33,0x04,0xc6,0x00} + }, + { + /* No.70 delta:1651 weight:1401 */ + 11213, + 35, + 9, + 8, + {(0x00000000), + (0xcaa73bcd), + (0x48ffa480), + (0x82589f4d), + (0x0b600460), + (0xc1c73fad), + (0x439fa0e0), + (0x89389b2d), + (0x0000d8fb), + (0xcaa7e336), + (0x48ff7c7b), + (0x825847b6), + (0x0b60dc9b), + (0xc1c7e756), + (0x439f781b), + (0x893843d6)}, + {(0x00000000), + (0x90604200), + (0x20222000), + (0xb0426200), + (0x5023a800), + (0xc043ea00), + (0x70018800), + (0xe061ca00), + (0x16031e00), + (0x86635c00), + (0x36213e00), + (0xa6417c00), + (0x4620b600), + (0xd640f400), + (0x66029600), + (0xf662d400)}, + {(0x3f800000), + (0x3fc83021), + (0x3f901110), + (0x3fd82131), + (0x3fa811d4), + (0x3fe021f5), + (0x3fb800c4), + (0x3ff030e5), + (0x3f8b018f), + (0x3fc331ae), + (0x3f9b109f), + (0x3fd320be), + (0x3fa3105b), + (0x3feb207a), + (0x3fb3014b), + (0x3ffb316a)}, + (0xfff80000), + {0xf7,0xac,0x3b,0x82,0x60,0x2e,0xa2,0x38,0xd5,0xbd, + 0x9e,0x07,0x19,0x05,0x37,0x68,0xa8,0x2b,0xcc,0x5b,0x00} + }, + { + /* No.71 delta:805 weight:1559 */ + 11213, + 85, + 17, + 2, + {(0x00000000), + (0x4ea39f4b), + (0xeedcca5e), + (0xa07f5515), + (0x1a80047d), + (0x54239b36), + (0xf45cce23), + (0xbaff5168), + (0x000051a3), + (0x4ea3cee8), + (0xeedc9bfd), + (0xa07f04b6), + (0x1a8055de), + (0x5423ca95), + (0xf45c9f80), + (0xbaff00cb)}, + {(0x00000000), + (0x0879e800), + (0x10141400), + (0x186dfc00), + (0x006c0800), + (0x0815e000), + (0x10781c00), + (0x1801f400), + (0x40237e00), + (0x485a9600), + (0x50376a00), + (0x584e8200), + (0x404f7600), + (0x48369e00), + (0x505b6200), + (0x58228a00)}, + {(0x3f800000), + (0x3f843cf4), + (0x3f880a0a), + (0x3f8c36fe), + (0x3f803604), + (0x3f840af0), + (0x3f883c0e), + (0x3f8c00fa), + (0x3fa011bf), + (0x3fa42d4b), + (0x3fa81bb5), + (0x3fac2741), + (0x3fa027bb), + (0x3fa41b4f), + (0x3fa82db1), + (0x3fac1145)}, + (0xfff80000), + {0x81,0x81,0xe0,0x37,0x51,0x1b,0x87,0x01,0xa3,0x40, + 0x70,0xd0,0xb9,0x63,0xbb,0xc0,0xe9,0x49,0x0b,0x62,0x00} + }, + { + /* No.72 delta:1929 weight:1383 */ + 11213, + 77, + 8, + 10, + {(0x00000000), + (0x9625646a), + (0xa06390e5), + (0x3646f48f), + (0x6c400487), + (0xfa6560ed), + (0xcc239462), + (0x5a06f008), + (0x00006232), + (0x96250658), + (0xa063f2d7), + (0x364696bd), + (0x6c4066b5), + (0xfa6502df), + (0xcc23f650), + (0x5a06923a)}, + {(0x00000000), + (0x60350000), + (0x08a08000), + (0x68958000), + (0x00120000), + (0x60270000), + (0x08b28000), + (0x68878000), + (0x60021e00), + (0x00371e00), + (0x68a29e00), + (0x08979e00), + (0x60101e00), + (0x00251e00), + (0x68b09e00), + (0x08859e00)}, + {(0x3f800000), + (0x3fb01a80), + (0x3f845040), + (0x3fb44ac0), + (0x3f800900), + (0x3fb01380), + (0x3f845940), + (0x3fb443c0), + (0x3fb0010f), + (0x3f801b8f), + (0x3fb4514f), + (0x3f844bcf), + (0x3fb0080f), + (0x3f80128f), + (0x3fb4584f), + (0x3f8442cf)}, + (0xfff80000), + {0xec,0xe8,0xd6,0x3f,0xf0,0x4f,0x6e,0xc9,0x92,0xb9, + 0x0b,0xf3,0x46,0x01,0x83,0x06,0xba,0xbb,0xfc,0x3c,0x00} + }, + { + /* No.73 delta:1312 weight:1037 */ + 11213, + 79, + 14, + 13, + {(0x00000000), + (0x3c3b4194), + (0x3b4a522a), + (0x077113be), + (0x70e00495), + (0x4cdb4501), + (0x4baa56bf), + (0x7791172b), + (0x00001842), + (0x3c3b59d6), + (0x3b4a4a68), + (0x07710bfc), + (0x70e01cd7), + (0x4cdb5d43), + (0x4baa4efd), + (0x77910f69)}, + {(0x00000000), + (0x5e1d3000), + (0x08002800), + (0x561d1800), + (0x00404000), + (0x5e5d7000), + (0x08406800), + (0x565d5800), + (0xa7841e00), + (0xf9992e00), + (0xaf843600), + (0xf1990600), + (0xa7c45e00), + (0xf9d96e00), + (0xafc47600), + (0xf1d94600)}, + {(0x3f800000), + (0x3faf0e98), + (0x3f840014), + (0x3fab0e8c), + (0x3f802020), + (0x3faf2eb8), + (0x3f842034), + (0x3fab2eac), + (0x3fd3c20f), + (0x3ffccc97), + (0x3fd7c21b), + (0x3ff8cc83), + (0x3fd3e22f), + (0x3ffcecb7), + (0x3fd7e23b), + (0x3ff8eca3)}, + (0xfff80000), + {0xe5,0x84,0x28,0x6a,0xc7,0xb8,0xff,0x35,0x7e,0x4a, + 0xd0,0x29,0x99,0x65,0xc9,0xf9,0x00,0xb5,0xa5,0x73,0x00} + }, + { + /* No.74 delta:1274 weight:753 */ + 11213, + 83, + 10, + 18, + {(0x00000000), + (0xdb6fd096), + (0x7bead936), + (0xa08509a0), + (0x059004a2), + (0xdeffd434), + (0x7e7add94), + (0xa5150d02), + (0x00003dd4), + (0xdb6fed42), + (0x7beae4e2), + (0xa0853474), + (0x05903976), + (0xdeffe9e0), + (0x7e7ae040), + (0xa51530d6)}, + {(0x00000000), + (0x0862a000), + (0x20176000), + (0x2875c000), + (0x21182000), + (0x297a8000), + (0x010f4000), + (0x096de000), + (0x100c1e00), + (0x186ebe00), + (0x301b7e00), + (0x3879de00), + (0x31143e00), + (0x39769e00), + (0x11035e00), + (0x1961fe00)}, + {(0x3f800000), + (0x3f843150), + (0x3f900bb0), + (0x3f943ae0), + (0x3f908c10), + (0x3f94bd40), + (0x3f8087a0), + (0x3f84b6f0), + (0x3f88060f), + (0x3f8c375f), + (0x3f980dbf), + (0x3f9c3cef), + (0x3f988a1f), + (0x3f9cbb4f), + (0x3f8881af), + (0x3f8cb0ff)}, + (0xfff80000), + {0x94,0x6b,0xe1,0x97,0xcf,0xd7,0x1d,0x69,0x3d,0xf1, + 0xd3,0x31,0x9b,0x3f,0x74,0x40,0xe4,0x78,0x37,0x93,0x00} + }, + { + /* No.75 delta:3240 weight:999 */ + 11213, + 25, + 3, + 14, + {(0x00000000), + (0x5231ede5), + (0x75f41157), + (0x27c5fcb2), + (0x231004bc), + (0x7121e959), + (0x56e415eb), + (0x04d5f80e), + (0x000014a2), + (0x5231f947), + (0x75f405f5), + (0x27c5e810), + (0x2310101e), + (0x7121fdfb), + (0x56e40149), + (0x04d5ecac)}, + {(0x00000000), + (0x09c10000), + (0x50f28000), + (0x59338000), + (0x12424000), + (0x1b834000), + (0x42b0c000), + (0x4b71c000), + (0x02361e00), + (0x0bf71e00), + (0x52c49e00), + (0x5b059e00), + (0x10745e00), + (0x19b55e00), + (0x4086de00), + (0x4947de00)}, + {(0x3f800000), + (0x3f84e080), + (0x3fa87940), + (0x3fac99c0), + (0x3f892120), + (0x3f8dc1a0), + (0x3fa15860), + (0x3fa5b8e0), + (0x3f811b0f), + (0x3f85fb8f), + (0x3fa9624f), + (0x3fad82cf), + (0x3f883a2f), + (0x3f8cdaaf), + (0x3fa0436f), + (0x3fa4a3ef)}, + (0xfff80000), + {0x22,0xa1,0x8f,0x2e,0x7e,0xb0,0x8f,0x95,0xab,0x7b, + 0xe4,0x15,0x6f,0x5a,0x78,0x2a,0xeb,0x47,0xfe,0xa6,0x00} + }, + { + /* No.76 delta:1884 weight:1457 */ + 11213, + 11, + 13, + 3, + {(0x00000000), + (0xb165bd1d), + (0x1f5b5cd1), + (0xae3ee1cc), + (0x07b004ca), + (0xb6d5b9d7), + (0x18eb581b), + (0xa98ee506), + (0x00000ebc), + (0xb165b3a1), + (0x1f5b526d), + (0xae3eef70), + (0x07b00a76), + (0xb6d5b76b), + (0x18eb56a7), + (0xa98eebba)}, + {(0x00000000), + (0x2a1ef400), + (0x43091000), + (0x6917e400), + (0x05182000), + (0x2f06d400), + (0x46113000), + (0x6c0fc400), + (0x20c41e00), + (0x0adaea00), + (0x63cd0e00), + (0x49d3fa00), + (0x25dc3e00), + (0x0fc2ca00), + (0x66d52e00), + (0x4ccbda00)}, + {(0x3f800000), + (0x3f950f7a), + (0x3fa18488), + (0x3fb48bf2), + (0x3f828c10), + (0x3f97836a), + (0x3fa30898), + (0x3fb607e2), + (0x3f90620f), + (0x3f856d75), + (0x3fb1e687), + (0x3fa4e9fd), + (0x3f92ee1f), + (0x3f87e165), + (0x3fb36a97), + (0x3fa665ed)}, + (0xfff80000), + {0x5f,0x66,0x78,0x0e,0x66,0x3f,0x37,0x9d,0x75,0xa2, + 0x49,0x78,0xb7,0x8c,0xf1,0x7c,0x84,0xf3,0xab,0x84,0x00} + }, + { + /* No.77 delta:1037 weight:1439 */ + 11213, + 43, + 15, + 7, + {(0x00000000), + (0x3b7738f7), + (0x2ee7f42b), + (0x1590ccdc), + (0x8c3004de), + (0xb7473c29), + (0xa2d7f0f5), + (0x99a0c802), + (0x0000b3f9), + (0x3b778b0e), + (0x2ee747d2), + (0x15907f25), + (0x8c30b727), + (0xb7478fd0), + (0xa2d7430c), + (0x99a07bfb)}, + {(0x00000000), + (0x20009400), + (0x70030800), + (0x50039c00), + (0x90011600), + (0xb0018200), + (0xe0021e00), + (0xc0028a00), + (0x40005e00), + (0x6000ca00), + (0x30035600), + (0x1003c200), + (0xd0014800), + (0xf001dc00), + (0xa0024000), + (0x8002d400)}, + {(0x3f800000), + (0x3f90004a), + (0x3fb80184), + (0x3fa801ce), + (0x3fc8008b), + (0x3fd800c1), + (0x3ff0010f), + (0x3fe00145), + (0x3fa0002f), + (0x3fb00065), + (0x3f9801ab), + (0x3f8801e1), + (0x3fe800a4), + (0x3ff800ee), + (0x3fd00120), + (0x3fc0016a)}, + (0xfff80000), + {0x4d,0xd9,0x1c,0xbc,0x61,0x94,0x41,0xb3,0x64,0x5a, + 0xe0,0x27,0x21,0x33,0x58,0x8a,0x3a,0x27,0xe7,0x61,0x00} + }, + { + /* No.78 delta:3771 weight:1149 */ + 11213, + 67, + 6, + 13, + {(0x00000000), + (0xeb935e7e), + (0x12dd9004), + (0xf94ece7a), + (0x518004ec), + (0xba135a92), + (0x435d94e8), + (0xa8ceca96), + (0x00002915), + (0xeb93776b), + (0x12ddb911), + (0xf94ee76f), + (0x51802df9), + (0xba137387), + (0x435dbdfd), + (0xa8cee383)}, + {(0x00000000), + (0x00600000), + (0x005c0000), + (0x003c0000), + (0xa7000000), + (0xa7600000), + (0xa75c0000), + (0xa73c0000), + (0x00381e00), + (0x00581e00), + (0x00641e00), + (0x00041e00), + (0xa7381e00), + (0xa7581e00), + (0xa7641e00), + (0xa7041e00)}, + {(0x3f800000), + (0x3f803000), + (0x3f802e00), + (0x3f801e00), + (0x3fd38000), + (0x3fd3b000), + (0x3fd3ae00), + (0x3fd39e00), + (0x3f801c0f), + (0x3f802c0f), + (0x3f80320f), + (0x3f80020f), + (0x3fd39c0f), + (0x3fd3ac0f), + (0x3fd3b20f), + (0x3fd3820f)}, + (0xfff80000), + {0x61,0xb9,0x79,0x4a,0xf6,0x0b,0x90,0x19,0x41,0xed, + 0xc7,0x02,0x30,0x6e,0x66,0x3a,0xa0,0x21,0x38,0x4d,0x00} + }, + { + /* No.79 delta:8905 weight:995 */ + 11213, + 37, + 2, + 14, + {(0x00000000), + (0xc386d224), + (0xa19cefca), + (0x621a3dee), + (0x73c004f0), + (0xb046d6d4), + (0xd25ceb3a), + (0x11da391e), + (0x00006023), + (0xc386b207), + (0xa19c8fe9), + (0x621a5dcd), + (0x73c064d3), + (0xb046b6f7), + (0xd25c8b19), + (0x11da593d)}, + {(0x00000000), + (0x50000000), + (0x60000000), + (0x30000000), + (0x00000000), + (0x50000000), + (0x60000000), + (0x30000000), + (0x10001e00), + (0x40001e00), + (0x70001e00), + (0x20001e00), + (0x10001e00), + (0x40001e00), + (0x70001e00), + (0x20001e00)}, + {(0x3f800000), + (0x3fa80000), + (0x3fb00000), + (0x3f980000), + (0x3f800000), + (0x3fa80000), + (0x3fb00000), + (0x3f980000), + (0x3f88000f), + (0x3fa0000f), + (0x3fb8000f), + (0x3f90000f), + (0x3f88000f), + (0x3fa0000f), + (0x3fb8000f), + (0x3f90000f)}, + (0xfff80000), + {0xcd,0x77,0xa6,0x4e,0x16,0x97,0x82,0x51,0x40,0x8c, + 0x23,0x3d,0x69,0x41,0x55,0xf4,0x6d,0xb5,0x97,0xc4,0x00} + }, + { + /* No.80 delta:1084 weight:1327 */ + 11213, + 41, + 20, + 7, + {(0x00000000), + (0x03b0124c), + (0x2709d148), + (0x24b9c304), + (0xd150050f), + (0xd2e01743), + (0xf659d447), + (0xf5e9c60b), + (0x0000e5a0), + (0x03b0f7ec), + (0x270934e8), + (0x24b926a4), + (0xd150e0af), + (0xd2e0f2e3), + (0xf65931e7), + (0xf5e923ab)}, + {(0x00000000), + (0x58fc3200), + (0x70059800), + (0x28f9aa00), + (0x00443a00), + (0x58b80800), + (0x7041a200), + (0x28bd9000), + (0x60225e00), + (0x38de6c00), + (0x1027c600), + (0x48dbf400), + (0x60666400), + (0x389a5600), + (0x1063fc00), + (0x489fce00)}, + {(0x3f800000), + (0x3fac7e19), + (0x3fb802cc), + (0x3f947cd5), + (0x3f80221d), + (0x3fac5c04), + (0x3fb820d1), + (0x3f945ec8), + (0x3fb0112f), + (0x3f9c6f36), + (0x3f8813e3), + (0x3fa46dfa), + (0x3fb03332), + (0x3f9c4d2b), + (0x3f8831fe), + (0x3fa44fe7)}, + (0xfff80000), + {0x17,0x06,0xb5,0x56,0x08,0x24,0x02,0x45,0x7d,0xec, + 0xaa,0x6e,0xee,0x42,0x3d,0x61,0xec,0x7b,0x95,0xda,0x00} + }, + { + /* No.81 delta:2107 weight:929 */ + 11213, + 68, + 7, + 13, + {(0x00000000), + (0xa2680084), + (0x72c07011), + (0xd0a87095), + (0xe9c00518), + (0x4ba8059c), + (0x9b007509), + (0x3968758d), + (0x000019d6), + (0xa2681952), + (0x72c069c7), + (0xd0a86943), + (0xe9c01cce), + (0x4ba81c4a), + (0x9b006cdf), + (0x39686c5b)}, + {(0x00000000), + (0x06214000), + (0x50182000), + (0x56396000), + (0x004c0000), + (0x066d4000), + (0x50542000), + (0x56756000), + (0x003abe00), + (0x061bfe00), + (0x50229e00), + (0x5603de00), + (0x0076be00), + (0x0657fe00), + (0x506e9e00), + (0x564fde00)}, + {(0x3f800000), + (0x3f8310a0), + (0x3fa80c10), + (0x3fab1cb0), + (0x3f802600), + (0x3f8336a0), + (0x3fa82a10), + (0x3fab3ab0), + (0x3f801d5f), + (0x3f830dff), + (0x3fa8114f), + (0x3fab01ef), + (0x3f803b5f), + (0x3f832bff), + (0x3fa8374f), + (0x3fab27ef)}, + (0xfff80000), + {0x06,0xc1,0x16,0x3a,0x4b,0xf5,0xcc,0xe4,0x06,0xc5, + 0x47,0x64,0xd8,0x26,0x6e,0xa3,0xd2,0xe3,0xfc,0x67,0x00} + }, + { + /* No.82 delta:1653 weight:993 */ + 11213, + 67, + 15, + 1, + {(0x00000000), + (0x205bddc2), + (0x51a5fb05), + (0x71fe26c7), + (0xbc800525), + (0x9cdbd8e7), + (0xed25fe20), + (0xcd7e23e2), + (0x0000ae60), + (0x205b73a2), + (0x51a55565), + (0x71fe88a7), + (0xbc80ab45), + (0x9cdb7687), + (0xed255040), + (0xcd7e8d82)}, + {(0x00000000), + (0x200d8e00), + (0x01004000), + (0x210dce00), + (0x1710c000), + (0x371d4e00), + (0x16108000), + (0x361d0e00), + (0x00409e00), + (0x204d1000), + (0x0140de00), + (0x214d5000), + (0x17505e00), + (0x375dd000), + (0x16501e00), + (0x365d9000)}, + {(0x3f800000), + (0x3f9006c7), + (0x3f808020), + (0x3f9086e7), + (0x3f8b8860), + (0x3f9b8ea7), + (0x3f8b0840), + (0x3f9b0e87), + (0x3f80204f), + (0x3f902688), + (0x3f80a06f), + (0x3f90a6a8), + (0x3f8ba82f), + (0x3f9baee8), + (0x3f8b280f), + (0x3f9b2ec8)}, + (0xfff80000), + {0x31,0x5a,0x14,0x56,0x22,0x69,0x71,0xb4,0xed,0xe9, + 0x57,0x3c,0xb3,0xa3,0xc2,0xd8,0x5c,0x3b,0xf9,0x7a,0x00} + }, + { + /* No.83 delta:2591 weight:1355 */ + 11213, + 78, + 3, + 3, + {(0x00000000), + (0x3fa6f3ae), + (0x11561526), + (0x2ef0e688), + (0x3f40053d), + (0x00e6f693), + (0x2e16101b), + (0x11b0e3b5), + (0x000038dd), + (0x3fa6cb73), + (0x11562dfb), + (0x2ef0de55), + (0x3f403de0), + (0x00e6ce4e), + (0x2e1628c6), + (0x11b0db68)}, + {(0x00000000), + (0x88264000), + (0x60420000), + (0xe8644000), + (0x20102000), + (0xa8366000), + (0x40522000), + (0xc8746000), + (0x00791e00), + (0x885f5e00), + (0x603b1e00), + (0xe81d5e00), + (0x20693e00), + (0xa84f7e00), + (0x402b3e00), + (0xc80d7e00)}, + {(0x3f800000), + (0x3fc41320), + (0x3fb02100), + (0x3ff43220), + (0x3f900810), + (0x3fd41b30), + (0x3fa02910), + (0x3fe43a30), + (0x3f803c8f), + (0x3fc42faf), + (0x3fb01d8f), + (0x3ff40eaf), + (0x3f90349f), + (0x3fd427bf), + (0x3fa0159f), + (0x3fe406bf)}, + (0xfff80000), + {0x95,0xde,0xea,0xd2,0x91,0x96,0x3a,0x31,0x18,0xb4, + 0x29,0x3c,0x05,0x83,0x13,0x20,0xa6,0xbb,0xfa,0x90,0x00} + }, + { + /* No.84 delta:1724 weight:1387 */ + 11213, + 31, + 24, + 7, + {(0x00000000), + (0x6f77a064), + (0x9d4e3ea4), + (0xf2399ec0), + (0xdab00543), + (0xb5c7a527), + (0x47fe3be7), + (0x28899b83), + (0x0000ba57), + (0x6f771a33), + (0x9d4e84f3), + (0xf2392497), + (0xdab0bf14), + (0xb5c71f70), + (0x47fe81b0), + (0x288921d4)}, + {(0x00000000), + (0x4052c800), + (0x403d7000), + (0x006fb800), + (0x01748400), + (0x41264c00), + (0x4149f400), + (0x011b3c00), + (0x30183e00), + (0x704af600), + (0x70254e00), + (0x30778600), + (0x316cba00), + (0x713e7200), + (0x7151ca00), + (0x31030200)}, + {(0x3f800000), + (0x3fa02964), + (0x3fa01eb8), + (0x3f8037dc), + (0x3f80ba42), + (0x3fa09326), + (0x3fa0a4fa), + (0x3f808d9e), + (0x3f980c1f), + (0x3fb8257b), + (0x3fb812a7), + (0x3f983bc3), + (0x3f98b65d), + (0x3fb89f39), + (0x3fb8a8e5), + (0x3f988181)}, + (0xfff80000), + {0x24,0x42,0xb5,0x8a,0x26,0x25,0x0b,0x43,0xb5,0xa1, + 0xfd,0xf3,0xef,0xe4,0x58,0x1d,0x2f,0x82,0x54,0xe1,0x00} + }, + { + /* No.85 delta:1315 weight:1167 */ + 11213, + 28, + 18, + 8, + {(0x00000000), + (0x7039a7b2), + (0x655a69d6), + (0x1563ce64), + (0x55800552), + (0x25b9a2e0), + (0x30da6c84), + (0x40e3cb36), + (0x0000db22), + (0x70397c90), + (0x655ab2f4), + (0x15631546), + (0x5580de70), + (0x25b979c2), + (0x30dab7a6), + (0x40e31014)}, + {(0x00000000), + (0x091ae000), + (0xc01fd200), + (0xc9053200), + (0x60072600), + (0x691dc600), + (0xa018f400), + (0xa9021400), + (0x40083e00), + (0x4912de00), + (0x8017ec00), + (0x890d0c00), + (0x200f1800), + (0x2915f800), + (0xe010ca00), + (0xe90a2a00)}, + {(0x3f800000), + (0x3f848d70), + (0x3fe00fe9), + (0x3fe48299), + (0x3fb00393), + (0x3fb48ee3), + (0x3fd00c7a), + (0x3fd4810a), + (0x3fa0041f), + (0x3fa4896f), + (0x3fc00bf6), + (0x3fc48686), + (0x3f90078c), + (0x3f948afc), + (0x3ff00865), + (0x3ff48515)}, + (0xfff80000), + {0x54,0x00,0xe5,0x09,0x83,0x8a,0xa3,0xac,0xe2,0x03, + 0xe4,0x5f,0x87,0xaa,0x93,0x3c,0x49,0xef,0xf1,0x12,0x00} + }, + { + /* No.86 delta:1805 weight:1023 */ + 11213, + 40, + 17, + 1, + {(0x00000000), + (0xd727963d), + (0x760f18b0), + (0xa1288e8d), + (0xe2d00563), + (0x35f7935e), + (0x94df1dd3), + (0x43f88bee), + (0x0000c942), + (0xd7275f7f), + (0x760fd1f2), + (0xa12847cf), + (0xe2d0cc21), + (0x35f75a1c), + (0x94dfd491), + (0x43f842ac)}, + {(0x00000000), + (0x207c0400), + (0x56934000), + (0x76ef4400), + (0x00009e00), + (0x207c9a00), + (0x5693de00), + (0x76efda00), + (0x20009e00), + (0x007c9a00), + (0x7693de00), + (0x56efda00), + (0x20000000), + (0x007c0400), + (0x76934000), + (0x56ef4400)}, + {(0x3f800000), + (0x3f903e02), + (0x3fab49a0), + (0x3fbb77a2), + (0x3f80004f), + (0x3f903e4d), + (0x3fab49ef), + (0x3fbb77ed), + (0x3f90004f), + (0x3f803e4d), + (0x3fbb49ef), + (0x3fab77ed), + (0x3f900000), + (0x3f803e02), + (0x3fbb49a0), + (0x3fab77a2)}, + (0xfff80000), + {0xc8,0x53,0x9a,0xab,0x96,0xd8,0xe7,0x02,0xe6,0xf1, + 0x74,0x36,0x00,0x32,0x32,0x6e,0x36,0xe4,0x78,0x88,0x00} + }, + { + /* No.87 delta:2165 weight:1423 */ + 11213, + 29, + 6, + 7, + {(0x00000000), + (0xb0a4f75d), + (0xd99a0020), + (0x693ef77d), + (0x0010057f), + (0xb0b4f222), + (0xd98a055f), + (0x692ef202), + (0x00002860), + (0xb0a4df3d), + (0xd99a2840), + (0x693edf1d), + (0x00102d1f), + (0xb0b4da42), + (0xd98a2d3f), + (0x692eda62)}, + {(0x00000000), + (0x00c02000), + (0x10102000), + (0x10d00000), + (0x700c0000), + (0x70cc2000), + (0x601c2000), + (0x60dc0000), + (0x00701e00), + (0x00b03e00), + (0x10603e00), + (0x10a01e00), + (0x707c1e00), + (0x70bc3e00), + (0x606c3e00), + (0x60ac1e00)}, + {(0x3f800000), + (0x3f806010), + (0x3f880810), + (0x3f886800), + (0x3fb80600), + (0x3fb86610), + (0x3fb00e10), + (0x3fb06e00), + (0x3f80380f), + (0x3f80581f), + (0x3f88301f), + (0x3f88500f), + (0x3fb83e0f), + (0x3fb85e1f), + (0x3fb0361f), + (0x3fb0560f)}, + (0xfff80000), + {0xc8,0x26,0xe1,0xb8,0xbd,0xd2,0x06,0x99,0x21,0x8b, + 0xa2,0x82,0x21,0x08,0x66,0x43,0x39,0x7d,0x22,0x3f,0x00} + }, + { + /* No.88 delta:2728 weight:929 */ + 11213, + 9, + 5, + 12, + {(0x00000000), + (0xba91b8b7), + (0x1f94657f), + (0xa505ddc8), + (0xc8900581), + (0x7201bd36), + (0xd70460fe), + (0x6d95d849), + (0x00009507), + (0xba912db0), + (0x1f94f078), + (0xa50548cf), + (0xc8909086), + (0x72012831), + (0xd704f5f9), + (0x6d954d4e)}, + {(0x00000000), + (0x74d60000), + (0x48810000), + (0x3c570000), + (0x07840000), + (0x73520000), + (0x4f050000), + (0x3bd30000), + (0xa0019e00), + (0xd4d79e00), + (0xe8809e00), + (0x9c569e00), + (0xa7859e00), + (0xd3539e00), + (0xef049e00), + (0x9bd29e00)}, + {(0x3f800000), + (0x3fba6b00), + (0x3fa44080), + (0x3f9e2b80), + (0x3f83c200), + (0x3fb9a900), + (0x3fa78280), + (0x3f9de980), + (0x3fd000cf), + (0x3fea6bcf), + (0x3ff4404f), + (0x3fce2b4f), + (0x3fd3c2cf), + (0x3fe9a9cf), + (0x3ff7824f), + (0x3fcde94f)}, + (0xfff80000), + {0xef,0x82,0x25,0x92,0x4d,0x84,0x32,0xcc,0x51,0x79, + 0xa6,0xf1,0xa8,0xb8,0xd3,0xc8,0xf4,0x1f,0x61,0x14,0x00} + }, + { + /* No.89 delta:1302 weight:829 */ + 11213, + 52, + 17, + 15, + {(0x00000000), + (0xff9c667b), + (0x076e42cb), + (0xf8f224b0), + (0x5a200593), + (0xa5bc63e8), + (0x5d4e4758), + (0xa2d22123), + (0x0000fbe9), + (0xff9c9d92), + (0x076eb922), + (0xf8f2df59), + (0x5a20fe7a), + (0xa5bc9801), + (0x5d4ebcb1), + (0xa2d2daca)}, + {(0x00000000), + (0x168c2000), + (0x08819000), + (0x1e0db000), + (0x8400d800), + (0x928cf800), + (0x8c814800), + (0x9a0d6800), + (0x0a023e00), + (0x1c8e1e00), + (0x0283ae00), + (0x140f8e00), + (0x8e02e600), + (0x988ec600), + (0x86837600), + (0x900f5600)}, + {(0x3f800000), + (0x3f8b4610), + (0x3f8440c8), + (0x3f8f06d8), + (0x3fc2006c), + (0x3fc9467c), + (0x3fc640a4), + (0x3fcd06b4), + (0x3f85011f), + (0x3f8e470f), + (0x3f8141d7), + (0x3f8a07c7), + (0x3fc70173), + (0x3fcc4763), + (0x3fc341bb), + (0x3fc807ab)}, + (0xfff80000), + {0x44,0x22,0x55,0x0c,0x46,0x02,0x05,0x6b,0x49,0xa7, + 0x79,0xcc,0xa0,0x5b,0x5c,0xeb,0x82,0xb3,0x48,0x1e,0x00} + }, + { + /* No.90 delta:1794 weight:683 */ + 11213, + 71, + 7, + 3, + {(0x00000000), + (0x28fcb37c), + (0x3de27e63), + (0x151ecd1f), + (0x99d005af), + (0xb12cb6d3), + (0xa4327bcc), + (0x8ccec8b0), + (0x0000473d), + (0x28fcf441), + (0x3de2395e), + (0x151e8a22), + (0x99d04292), + (0xb12cf1ee), + (0xa4323cf1), + (0x8cce8f8d)}, + {(0x00000000), + (0x00170000), + (0x00059200), + (0x00129200), + (0x61088000), + (0x611f8000), + (0x610d1200), + (0x611a1200), + (0x22825e00), + (0x22955e00), + (0x2287cc00), + (0x2290cc00), + (0x438ade00), + (0x439dde00), + (0x438f4c00), + (0x43984c00)}, + {(0x3f800000), + (0x3f800b80), + (0x3f8002c9), + (0x3f800949), + (0x3fb08440), + (0x3fb08fc0), + (0x3fb08689), + (0x3fb08d09), + (0x3f91412f), + (0x3f914aaf), + (0x3f9143e6), + (0x3f914866), + (0x3fa1c56f), + (0x3fa1ceef), + (0x3fa1c7a6), + (0x3fa1cc26)}, + (0xfff80000), + {0x63,0x96,0x53,0x66,0x89,0x8f,0x5a,0x0f,0x8c,0x80, + 0x0a,0x9a,0x17,0xd9,0x66,0x91,0xf8,0x92,0x97,0x62,0x00} + }, + { + /* No.91 delta:10527 weight:393 */ + 11213, + 5, + 2, + 19, + {(0x00000000), + (0x9ea45304), + (0x56ae02a1), + (0xc80a51a5), + (0x9ad005b9), + (0x047456bd), + (0xcc7e0718), + (0x52da541c), + (0x0000c554), + (0x9ea49650), + (0x56aec7f5), + (0xc80a94f1), + (0x9ad0c0ed), + (0x047493e9), + (0xcc7ec24c), + (0x52da9148)}, + {(0x00000000), + (0x64000000), + (0x0f800000), + (0x6b800000), + (0x00000000), + (0x64000000), + (0x0f800000), + (0x6b800000), + (0x00001e00), + (0x64001e00), + (0x0f801e00), + (0x6b801e00), + (0x00001e00), + (0x64001e00), + (0x0f801e00), + (0x6b801e00)}, + {(0x3f800000), + (0x3fb20000), + (0x3f87c000), + (0x3fb5c000), + (0x3f800000), + (0x3fb20000), + (0x3f87c000), + (0x3fb5c000), + (0x3f80000f), + (0x3fb2000f), + (0x3f87c00f), + (0x3fb5c00f), + (0x3f80000f), + (0x3fb2000f), + (0x3f87c00f), + (0x3fb5c00f)}, + (0xfff80000), + {0xd2,0x73,0xa3,0x8b,0x1a,0x90,0xef,0x94,0xe3,0x4a, + 0x16,0x2f,0x38,0x48,0xd9,0x68,0xf2,0xdf,0xe5,0xab,0x00} + }, + { + /* No.92 delta:2494 weight:1233 */ + 11213, + 7, + 21, + 4, + {(0x00000000), + (0x67c6fdcf), + (0x39165a15), + (0x5ed0a7da), + (0xa11005c0), + (0xc6d6f80f), + (0x98065fd5), + (0xffc0a21a), + (0x0000cdee), + (0x67c63021), + (0x391697fb), + (0x5ed06a34), + (0xa110c82e), + (0xc6d635e1), + (0x9806923b), + (0xffc06ff4)}, + {(0x00000000), + (0xc64d0800), + (0x67f58000), + (0xa1b88800), + (0x11ca8200), + (0xd7878a00), + (0x763f0200), + (0xb0720a00), + (0x4eb51e00), + (0x88f81600), + (0x29409e00), + (0xef0d9600), + (0x5f7f9c00), + (0x99329400), + (0x388a1c00), + (0xfec71400)}, + {(0x3f800000), + (0x3fe32684), + (0x3fb3fac0), + (0x3fd0dc44), + (0x3f88e541), + (0x3febc3c5), + (0x3fbb1f81), + (0x3fd83905), + (0x3fa75a8f), + (0x3fc47c0b), + (0x3f94a04f), + (0x3ff786cb), + (0x3fafbfce), + (0x3fcc994a), + (0x3f9c450e), + (0x3fff638a)}, + (0xfff80000), + {0x9e,0xa5,0x58,0x0a,0xe1,0x2c,0x68,0x94,0x2b,0x3f, + 0x4b,0xcd,0xe6,0xee,0x21,0x60,0xf3,0xf9,0x28,0xef,0x00} + }, + { + /* No.93 delta:2858 weight:713 */ + 11213, + 6, + 11, + 15, + {(0x00000000), + (0xce341fc2), + (0x74808815), + (0xbab497d7), + (0x396005de), + (0xf7541a1c), + (0x4de08dcb), + (0x83d49209), + (0x0000dee4), + (0xce34c126), + (0x748056f1), + (0xbab44933), + (0x3960db3a), + (0xf754c4f8), + (0x4de0532f), + (0x83d44ced)}, + {(0x00000000), + (0x0af25000), + (0x0c419c00), + (0x06b3cc00), + (0x82144400), + (0x88e61400), + (0x8e55d800), + (0x84a78800), + (0xe0053e00), + (0xeaf76e00), + (0xec44a200), + (0xe6b6f200), + (0x62117a00), + (0x68e32a00), + (0x6e50e600), + (0x64a2b600)}, + {(0x3f800000), + (0x3f857928), + (0x3f8620ce), + (0x3f8359e6), + (0x3fc10a22), + (0x3fc4730a), + (0x3fc72aec), + (0x3fc253c4), + (0x3ff0029f), + (0x3ff57bb7), + (0x3ff62251), + (0x3ff35b79), + (0x3fb108bd), + (0x3fb47195), + (0x3fb72873), + (0x3fb2515b)}, + (0xfff80000), + {0x67,0xfb,0x7b,0xdf,0x91,0xd7,0xa6,0xcb,0xfa,0x0c, + 0x9c,0xcf,0x32,0x59,0xd4,0x14,0x88,0x02,0x20,0xbd,0x00} + }, + { + /* No.94 delta:1428 weight:871 */ + 11213, + 51, + 24, + 3, + {(0x00000000), + (0x4055c0f5), + (0x3f9446d5), + (0x7fc18620), + (0xbd5005e5), + (0xfd05c510), + (0x82c44330), + (0xc29183c5), + (0x0000a8c2), + (0x40556837), + (0x3f94ee17), + (0x7fc12ee2), + (0xbd50ad27), + (0xfd056dd2), + (0x82c4ebf2), + (0xc2912b07)}, + {(0x00000000), + (0x6064a000), + (0x4ef89000), + (0x2e9c3000), + (0x08a1d000), + (0x68c57000), + (0x46594000), + (0x263de000), + (0x0c127e00), + (0x6c76de00), + (0x42eaee00), + (0x228e4e00), + (0x04b3ae00), + (0x64d70e00), + (0x4a4b3e00), + (0x2a2f9e00)}, + {(0x3f800000), + (0x3fb03250), + (0x3fa77c48), + (0x3f974e18), + (0x3f8450e8), + (0x3fb462b8), + (0x3fa32ca0), + (0x3f931ef0), + (0x3f86093f), + (0x3fb63b6f), + (0x3fa17577), + (0x3f914727), + (0x3f8259d7), + (0x3fb26b87), + (0x3fa5259f), + (0x3f9517cf)}, + (0xfff80000), + {0xfc,0xe1,0x89,0x6f,0x64,0xe4,0x4b,0x42,0xe3,0x27, + 0xa3,0x38,0x46,0x33,0x4f,0xf6,0x63,0x31,0xbb,0x80,0x00} + }, + { + /* No.95 delta:1914 weight:999 */ + 11213, + 43, + 8, + 13, + {(0x00000000), + (0x9c0723c5), + (0xc882db89), + (0x5485f84c), + (0x994005f3), + (0x05472636), + (0x51c2de7a), + (0xcdc5fdbf), + (0x000019bd), + (0x9c073a78), + (0xc882c234), + (0x5485e1f1), + (0x99401c4e), + (0x05473f8b), + (0x51c2c7c7), + (0xcdc5e402)}, + {(0x00000000), + (0x5061f000), + (0x105bc000), + (0x403a3000), + (0x00740400), + (0x5015f400), + (0x102fc400), + (0x404e3400), + (0x041c1e00), + (0x547dee00), + (0x1447de00), + (0x44262e00), + (0x04681a00), + (0x5409ea00), + (0x1433da00), + (0x44522a00)}, + {(0x3f800000), + (0x3fa830f8), + (0x3f882de0), + (0x3fa01d18), + (0x3f803a02), + (0x3fa80afa), + (0x3f8817e2), + (0x3fa0271a), + (0x3f820e0f), + (0x3faa3ef7), + (0x3f8a23ef), + (0x3fa21317), + (0x3f82340d), + (0x3faa04f5), + (0x3f8a19ed), + (0x3fa22915)}, + (0xfff80000), + {0xbf,0x5e,0xb4,0x48,0x47,0x8e,0xcb,0x36,0x4b,0x6a, + 0xc7,0x2c,0x1c,0xc9,0xdc,0x0d,0x4b,0x46,0x15,0xdf,0x00} + }, + { + /* No.96 delta:1078 weight:1383 */ + 11213, + 93, + 22, + 5, + {(0x00000000), + (0x4598c5d2), + (0x2a3c70f7), + (0x6fa4b525), + (0xf4e0060f), + (0xb178c3dd), + (0xdedc76f8), + (0x9b44b32a), + (0x0000ee71), + (0x45982ba3), + (0x2a3c9e86), + (0x6fa45b54), + (0xf4e0e87e), + (0xb1782dac), + (0xdedc9889), + (0x9b445d5b)}, + {(0x00000000), + (0x40220000), + (0x20738000), + (0x60518000), + (0x007e2000), + (0x405c2000), + (0x200da000), + (0x602fa000), + (0x80035e00), + (0xc0215e00), + (0xa070de00), + (0xe052de00), + (0x807d7e00), + (0xc05f7e00), + (0xa00efe00), + (0xe02cfe00)}, + {(0x3f800000), + (0x3fa01100), + (0x3f9039c0), + (0x3fb028c0), + (0x3f803f10), + (0x3fa02e10), + (0x3f9006d0), + (0x3fb017d0), + (0x3fc001af), + (0x3fe010af), + (0x3fd0386f), + (0x3ff0296f), + (0x3fc03ebf), + (0x3fe02fbf), + (0x3fd0077f), + (0x3ff0167f)}, + (0xfff80000), + {0xf7,0x01,0xdc,0x94,0xdb,0xfe,0x75,0xe3,0x41,0x0d, + 0xa7,0xcf,0xdb,0xc4,0xf8,0x63,0x39,0xf1,0x73,0x83,0x00} + }, + { + /* No.97 delta:1680 weight:855 */ + 11213, + 56, + 11, + 18, + {(0x00000000), + (0xed377fcb), + (0x935b7bcf), + (0x7e6c0404), + (0xb1b0061d), + (0x5c8779d6), + (0x22eb7dd2), + (0xcfdc0219), + (0x0000dc19), + (0xed37a3d2), + (0x935ba7d6), + (0x7e6cd81d), + (0xb1b0da04), + (0x5c87a5cf), + (0x22eba1cb), + (0xcfdcde00)}, + {(0x00000000), + (0x10100000), + (0x201c0000), + (0x300c0000), + (0x30000000), + (0x20100000), + (0x101c0000), + (0x000c0000), + (0x40051e00), + (0x50151e00), + (0x60191e00), + (0x70091e00), + (0x70051e00), + (0x60151e00), + (0x50191e00), + (0x40091e00)}, + {(0x3f800000), + (0x3f880800), + (0x3f900e00), + (0x3f980600), + (0x3f980000), + (0x3f900800), + (0x3f880e00), + (0x3f800600), + (0x3fa0028f), + (0x3fa80a8f), + (0x3fb00c8f), + (0x3fb8048f), + (0x3fb8028f), + (0x3fb00a8f), + (0x3fa80c8f), + (0x3fa0048f)}, + (0xfff80000), + {0xa7,0x90,0x32,0xf0,0xe5,0x54,0x81,0x86,0xda,0xa2, + 0x04,0x5e,0xda,0xe5,0xcd,0x25,0x97,0x20,0x5f,0xd8,0x00} + }, + { + /* No.98 delta:4818 weight:1887 */ + 11213, + 73, + 1, + 4, + {(0x00000000), + (0xf3234424), + (0xe4236cf9), + (0x170028dd), + (0x62d00623), + (0x91f34207), + (0x86f36ada), + (0x75d02efe), + (0x00003707), + (0xf3237323), + (0xe4235bfe), + (0x17001fda), + (0x62d03124), + (0x91f37500), + (0x86f35ddd), + (0x75d019f9)}, + {(0x00000000), + (0x40550000), + (0x40300000), + (0x00650000), + (0x7a81c000), + (0x3ad4c000), + (0x3ab1c000), + (0x7ae4c000), + (0x54351e00), + (0x14601e00), + (0x14051e00), + (0x54501e00), + (0x2eb4de00), + (0x6ee1de00), + (0x6e84de00), + (0x2ed1de00)}, + {(0x3f800000), + (0x3fa02a80), + (0x3fa01800), + (0x3f803280), + (0x3fbd40e0), + (0x3f9d6a60), + (0x3f9d58e0), + (0x3fbd7260), + (0x3faa1a8f), + (0x3f8a300f), + (0x3f8a028f), + (0x3faa280f), + (0x3f975a6f), + (0x3fb770ef), + (0x3fb7426f), + (0x3f9768ef)}, + (0xfff80000), + {0x78,0x4c,0x48,0x62,0xcb,0x43,0x6e,0xae,0x79,0x3f, + 0xa2,0x90,0xc7,0xd5,0xf6,0x2c,0x3a,0x94,0xf6,0x88,0x00} + }, + { + /* No.99 delta:4941 weight:807 */ + 11213, + 35, + 6, + 17, + {(0x00000000), + (0xceb13d37), + (0x6cab25b0), + (0xa21a1887), + (0x2d100639), + (0xe3a13b0e), + (0x41bb2389), + (0x8f0a1ebe), + (0x00002bd0), + (0xceb116e7), + (0x6cab0e60), + (0xa21a3357), + (0x2d102de9), + (0xe3a110de), + (0x41bb0859), + (0x8f0a356e)}, + {(0x00000000), + (0x07201000), + (0x42300200), + (0x45101200), + (0x40000000), + (0x47201000), + (0x02300200), + (0x05101200), + (0x70001e00), + (0x77200e00), + (0x32301c00), + (0x35100c00), + (0x30001e00), + (0x37200e00), + (0x72301c00), + (0x75100c00)}, + {(0x3f800000), + (0x3f839008), + (0x3fa11801), + (0x3fa28809), + (0x3fa00000), + (0x3fa39008), + (0x3f811801), + (0x3f828809), + (0x3fb8000f), + (0x3fbb9007), + (0x3f99180e), + (0x3f9a8806), + (0x3f98000f), + (0x3f9b9007), + (0x3fb9180e), + (0x3fba8806)}, + (0xfff80000), + {0x47,0x35,0x44,0x50,0x63,0x4a,0x6a,0xcd,0x53,0x03, + 0xdd,0x48,0x13,0x12,0x80,0xdf,0x0e,0x77,0xfa,0xf3,0x00} + }, + { + /* No.100 delta:1308 weight:863 */ + 11213, + 86, + 13, + 14, + {(0x00000000), + (0xc5ba19cb), + (0x67d04c0f), + (0xa26a55c4), + (0x36300642), + (0xf38a1f89), + (0x51e04a4d), + (0x945a5386), + (0x0000f011), + (0xc5bae9da), + (0x67d0bc1e), + (0xa26aa5d5), + (0x3630f653), + (0xf38aef98), + (0x51e0ba5c), + (0x945aa397)}, + {(0x00000000), + (0x09233a00), + (0x40645e00), + (0x49476400), + (0x1030a000), + (0x19139a00), + (0x5054fe00), + (0x5977c400), + (0x30c05e00), + (0x39e36400), + (0x70a40000), + (0x79873a00), + (0x20f0fe00), + (0x29d3c400), + (0x6094a000), + (0x69b79a00)}, + {(0x3f800000), + (0x3f84919d), + (0x3fa0322f), + (0x3fa4a3b2), + (0x3f881850), + (0x3f8c89cd), + (0x3fa82a7f), + (0x3facbbe2), + (0x3f98602f), + (0x3f9cf1b2), + (0x3fb85200), + (0x3fbcc39d), + (0x3f90787f), + (0x3f94e9e2), + (0x3fb04a50), + (0x3fb4dbcd)}, + (0xfff80000), + {0xbe,0xe1,0xe6,0x46,0x8d,0x04,0x11,0x44,0x1a,0x37, + 0x82,0xd9,0x6f,0xd6,0x9e,0xd5,0x25,0x58,0x1e,0xae,0x00} + }, + { + /* No.101 delta:3747 weight:693 */ + 11213, + 93, + 7, + 18, + {(0x00000000), + (0x34b395ad), + (0x437cf2d0), + (0x77cf677d), + (0xa770065c), + (0x93c393f1), + (0xe40cf48c), + (0xd0bf6121), + (0x0000f47f), + (0x34b361d2), + (0x437c06af), + (0x77cf9302), + (0xa770f223), + (0x93c3678e), + (0xe40c00f3), + (0xd0bf955e)}, + {(0x00000000), + (0x40700000), + (0x00580000), + (0x40280000), + (0x40680000), + (0x00180000), + (0x40300000), + (0x00400000), + (0x21601e00), + (0x61101e00), + (0x21381e00), + (0x61481e00), + (0x61081e00), + (0x21781e00), + (0x61501e00), + (0x21201e00)}, + {(0x3f800000), + (0x3fa03800), + (0x3f802c00), + (0x3fa01400), + (0x3fa03400), + (0x3f800c00), + (0x3fa01800), + (0x3f802000), + (0x3f90b00f), + (0x3fb0880f), + (0x3f909c0f), + (0x3fb0a40f), + (0x3fb0840f), + (0x3f90bc0f), + (0x3fb0a80f), + (0x3f90900f)}, + (0xfff80000), + {0xe2,0xf1,0x5a,0xc6,0xba,0x8b,0xae,0x08,0x43,0xcc, + 0x54,0xa6,0xe9,0x8f,0x81,0x0a,0x85,0xe3,0x5e,0xef,0x00} + }, + { + /* No.102 delta:3462 weight:1273 */ + 11213, + 55, + 23, + 8, + {(0x00000000), + (0xc3cc98c8), + (0xca3b10a5), + (0x09f7886d), + (0x18300660), + (0xdbfc9ea8), + (0xd20b16c5), + (0x11c78e0d), + (0x000030c4), + (0xc3cca80c), + (0xca3b2061), + (0x09f7b8a9), + (0x183036a4), + (0xdbfcae6c), + (0xd20b2601), + (0x11c7bec9)}, + {(0x00000000), + (0x08000000), + (0x00800000), + (0x08800000), + (0x88200000), + (0x80200000), + (0x88a00000), + (0x80a00000), + (0x03201e00), + (0x0b201e00), + (0x03a01e00), + (0x0ba01e00), + (0x8b001e00), + (0x83001e00), + (0x8b801e00), + (0x83801e00)}, + {(0x3f800000), + (0x3f840000), + (0x3f804000), + (0x3f844000), + (0x3fc41000), + (0x3fc01000), + (0x3fc45000), + (0x3fc05000), + (0x3f81900f), + (0x3f85900f), + (0x3f81d00f), + (0x3f85d00f), + (0x3fc5800f), + (0x3fc1800f), + (0x3fc5c00f), + (0x3fc1c00f)}, + (0xfff80000), + {0x43,0x1f,0x6f,0x01,0x80,0xf4,0x2e,0x31,0xcd,0xc1, + 0xb9,0x2f,0x6b,0x5c,0x0e,0x0b,0x35,0xa5,0x70,0x7e,0x00} + }, + { + /* No.103 delta:5054 weight:1635 */ + 11213, + 64, + 1, + 2, + {(0x00000000), + (0x4f30581d), + (0x5542c11f), + (0x1a729902), + (0x9da00670), + (0xd2905e6d), + (0xc8e2c76f), + (0x87d29f72), + (0x00007e47), + (0x4f30265a), + (0x5542bf58), + (0x1a72e745), + (0x9da07837), + (0xd290202a), + (0xc8e2b928), + (0x87d2e135)}, + {(0x00000000), + (0x0be21000), + (0x55018000), + (0x5ee39000), + (0x83944800), + (0x88765800), + (0xd695c800), + (0xdd77d800), + (0x00669e00), + (0x0b848e00), + (0x55671e00), + (0x5e850e00), + (0x83f2d600), + (0x8810c600), + (0xd6f35600), + (0xdd114600)}, + {(0x3f800000), + (0x3f85f108), + (0x3faa80c0), + (0x3faf71c8), + (0x3fc1ca24), + (0x3fc43b2c), + (0x3feb4ae4), + (0x3feebbec), + (0x3f80334f), + (0x3f85c247), + (0x3faab38f), + (0x3faf4287), + (0x3fc1f96b), + (0x3fc40863), + (0x3feb79ab), + (0x3fee88a3)}, + (0xfff80000), + {0x44,0x10,0x9f,0x8c,0xd9,0xbc,0x8e,0xb6,0xd5,0x14, + 0x72,0x32,0xdd,0xf2,0x3c,0xea,0xb3,0x38,0xb9,0x31,0x00} + }, + { + /* No.104 delta:2496 weight:907 */ + 11213, + 79, + 15, + 14, + {(0x00000000), + (0x5c0202d2), + (0x1c3f4858), + (0x403d4a8a), + (0xd2f0068f), + (0x8ef2045d), + (0xcecf4ed7), + (0x92cd4c05), + (0x0000d76d), + (0x5c02d5bf), + (0x1c3f9f35), + (0x403d9de7), + (0xd2f0d1e2), + (0x8ef2d330), + (0xcecf99ba), + (0x92cd9b68)}, + {(0x00000000), + (0x6b8d0400), + (0x1053a000), + (0x7bdea400), + (0x19807000), + (0x720d7400), + (0x09d3d000), + (0x625ed400), + (0x08441e00), + (0x63c91a00), + (0x1817be00), + (0x739aba00), + (0x11c46e00), + (0x7a496a00), + (0x0197ce00), + (0x6a1aca00)}, + {(0x3f800000), + (0x3fb5c682), + (0x3f8829d0), + (0x3fbdef52), + (0x3f8cc038), + (0x3fb906ba), + (0x3f84e9e8), + (0x3fb12f6a), + (0x3f84220f), + (0x3fb1e48d), + (0x3f8c0bdf), + (0x3fb9cd5d), + (0x3f88e237), + (0x3fbd24b5), + (0x3f80cbe7), + (0x3fb50d65)}, + (0xfff80000), + {0xb7,0xe4,0x3c,0x74,0x28,0xb1,0x2f,0xa4,0x5c,0x37, + 0xb1,0x69,0xd9,0x95,0x83,0xd9,0xa6,0x36,0x5b,0x12,0x00} + }, + { + /* No.105 delta:1174 weight:1019 */ + 11213, + 91, + 17, + 14, + {(0x00000000), + (0xa83f2177), + (0xa0b43c75), + (0x088b1d02), + (0x43300696), + (0xeb0f27e1), + (0xe3843ae3), + (0x4bbb1b94), + (0x00007f34), + (0xa83f5e43), + (0xa0b44341), + (0x088b6236), + (0x433079a2), + (0xeb0f58d5), + (0xe38445d7), + (0x4bbb64a0)}, + {(0x00000000), + (0x0115c000), + (0x90090000), + (0x911cc000), + (0x10422000), + (0x1157e000), + (0x804b2000), + (0x815ee000), + (0x10393e00), + (0x112cfe00), + (0x80303e00), + (0x8125fe00), + (0x007b1e00), + (0x016ede00), + (0x90721e00), + (0x9167de00)}, + {(0x3f800000), + (0x3f808ae0), + (0x3fc80480), + (0x3fc88e60), + (0x3f882110), + (0x3f88abf0), + (0x3fc02590), + (0x3fc0af70), + (0x3f881c9f), + (0x3f88967f), + (0x3fc0181f), + (0x3fc092ff), + (0x3f803d8f), + (0x3f80b76f), + (0x3fc8390f), + (0x3fc8b3ef)}, + (0xfff80000), + {0xe2,0x4f,0x2f,0xcb,0x05,0x76,0xce,0x0b,0xc7,0x7b, + 0xcc,0x65,0x06,0xce,0x2c,0x0c,0x3c,0xb6,0x2c,0x79,0x00} + }, + { + /* No.106 delta:1564 weight:925 */ + 11213, + 40, + 9, + 1, + {(0x00000000), + (0xd288f412), + (0x0b33c7cb), + (0xd9bb33d9), + (0xe0d006a8), + (0x3258f2ba), + (0xebe3c163), + (0x396b3571), + (0x00004470), + (0xd288b062), + (0x0b3383bb), + (0xd9bb77a9), + (0xe0d042d8), + (0x3258b6ca), + (0xebe38513), + (0x396b7101)}, + {(0x00000000), + (0x46794000), + (0x004d0000), + (0x46344000), + (0x007f0200), + (0x46064200), + (0x00320200), + (0x464b4200), + (0x00235e00), + (0x465a1e00), + (0x006e5e00), + (0x46171e00), + (0x005c5c00), + (0x46251c00), + (0x00115c00), + (0x46681c00)}, + {(0x3f800000), + (0x3fa33ca0), + (0x3f802680), + (0x3fa31a20), + (0x3f803f81), + (0x3fa30321), + (0x3f801901), + (0x3fa325a1), + (0x3f8011af), + (0x3fa32d0f), + (0x3f80372f), + (0x3fa30b8f), + (0x3f802e2e), + (0x3fa3128e), + (0x3f8008ae), + (0x3fa3340e)}, + (0xfff80000), + {0xc1,0x6e,0x8a,0x33,0x35,0x9f,0x07,0x03,0x76,0x11, + 0xe5,0x21,0xc3,0xdb,0x18,0x40,0x05,0xa0,0xd6,0x4c,0x00} + }, + { + /* No.107 delta:3386 weight:1851 */ + 11213, + 48, + 2, + 6, + {(0x00000000), + (0x5199ee9c), + (0x0606c085), + (0x579f2e19), + (0xe08006b0), + (0xb119e82c), + (0xe686c635), + (0xb71f28a9), + (0x000086be), + (0x51996822), + (0x0606463b), + (0x579fa8a7), + (0xe080800e), + (0xb1196e92), + (0xe686408b), + (0xb71fae17)}, + {(0x00000000), + (0x08250000), + (0x0a400800), + (0x02650800), + (0x10040000), + (0x18210000), + (0x1a440800), + (0x12610800), + (0x01081e00), + (0x092d1e00), + (0x0b481600), + (0x036d1600), + (0x110c1e00), + (0x19291e00), + (0x1b4c1600), + (0x13691600)}, + {(0x3f800000), + (0x3f841280), + (0x3f852004), + (0x3f813284), + (0x3f880200), + (0x3f8c1080), + (0x3f8d2204), + (0x3f893084), + (0x3f80840f), + (0x3f84968f), + (0x3f85a40b), + (0x3f81b68b), + (0x3f88860f), + (0x3f8c948f), + (0x3f8da60b), + (0x3f89b48b)}, + (0xfff80000), + {0x29,0x35,0xcb,0x9b,0x48,0x71,0x31,0x12,0x0b,0x2e, + 0xd3,0x98,0x06,0x50,0x05,0x3b,0xac,0x89,0x1a,0xaf,0x00} + }, + { + /* No.108 delta:2469 weight:1251 */ + 11213, + 31, + 7, + 1, + {(0x00000000), + (0x4efca9a0), + (0x3a920750), + (0x746eaef0), + (0x958006ce), + (0xdb7caf6e), + (0xaf12019e), + (0xe1eea83e), + (0x0000ee3c), + (0x4efc479c), + (0x3a92e96c), + (0x746e40cc), + (0x9580e8f2), + (0xdb7c4152), + (0xaf12efa2), + (0xe1ee4602)}, + {(0x00000000), + (0x405c0000), + (0x004ba200), + (0x4017a200), + (0x00600000), + (0x403c0000), + (0x002ba200), + (0x4077a200), + (0x80481e00), + (0xc0141e00), + (0x8003bc00), + (0xc05fbc00), + (0x80281e00), + (0xc0741e00), + (0x8063bc00), + (0xc03fbc00)}, + {(0x3f800000), + (0x3fa02e00), + (0x3f8025d1), + (0x3fa00bd1), + (0x3f803000), + (0x3fa01e00), + (0x3f8015d1), + (0x3fa03bd1), + (0x3fc0240f), + (0x3fe00a0f), + (0x3fc001de), + (0x3fe02fde), + (0x3fc0140f), + (0x3fe03a0f), + (0x3fc031de), + (0x3fe01fde)}, + (0xfff80000), + {0x05,0x56,0x79,0x8d,0xa1,0x79,0x94,0x9b,0xfd,0xfa, + 0xd1,0xd9,0x42,0x04,0x4f,0x21,0x8e,0xdb,0xe7,0xa3,0x00} + }, + { + /* No.109 delta:997 weight:681 */ + 11213, + 71, + 19, + 5, + {(0x00000000), + (0x21e405bb), + (0x4f97981d), + (0x6e739da6), + (0x01d006d7), + (0x2034036c), + (0x4e479eca), + (0x6fa39b71), + (0x0000e6b0), + (0x21e4e30b), + (0x4f977ead), + (0x6e737b16), + (0x01d0e067), + (0x2034e5dc), + (0x4e47787a), + (0x6fa37dc1)}, + {(0x00000000), + (0x40267000), + (0x0682d000), + (0x46a4a000), + (0x11832000), + (0x51a55000), + (0x1701f000), + (0x57278000), + (0x40581e00), + (0x007e6e00), + (0x46dace00), + (0x06fcbe00), + (0x51db3e00), + (0x11fd4e00), + (0x5759ee00), + (0x177f9e00)}, + {(0x3f800000), + (0x3fa01338), + (0x3f834168), + (0x3fa35250), + (0x3f88c190), + (0x3fa8d2a8), + (0x3f8b80f8), + (0x3fab93c0), + (0x3fa02c0f), + (0x3f803f37), + (0x3fa36d67), + (0x3f837e5f), + (0x3fa8ed9f), + (0x3f88fea7), + (0x3fabacf7), + (0x3f8bbfcf)}, + (0xfff80000), + {0x33,0x76,0x14,0x81,0x56,0x54,0xf0,0x4f,0x12,0x90, + 0xf4,0x03,0x95,0x9c,0x1a,0x38,0x51,0x80,0x32,0xaa,0x00} + }, + { + /* No.110 delta:2599 weight:829 */ + 11213, + 8, + 11, + 14, + {(0x00000000), + (0x4654c25e), + (0xa8eaa1d6), + (0xeebe6388), + (0x52a006e9), + (0x14f4c4b7), + (0xfa4aa73f), + (0xbc1e6561), + (0x000019ff), + (0x4654dba1), + (0xa8eab829), + (0xeebe7a77), + (0x52a01f16), + (0x14f4dd48), + (0xfa4abec0), + (0xbc1e7c9e)}, + {(0x00000000), + (0xfe272000), + (0x8207f000), + (0x7c20d000), + (0x4e344800), + (0xb0136800), + (0xcc33b800), + (0x32149800), + (0x01611e00), + (0xff463e00), + (0x8366ee00), + (0x7d41ce00), + (0x4f555600), + (0xb1727600), + (0xcd52a600), + (0x33758600)}, + {(0x3f800000), + (0x3fff1390), + (0x3fc103f8), + (0x3fbe1068), + (0x3fa71a24), + (0x3fd809b4), + (0x3fe619dc), + (0x3f990a4c), + (0x3f80b08f), + (0x3fffa31f), + (0x3fc1b377), + (0x3fbea0e7), + (0x3fa7aaab), + (0x3fd8b93b), + (0x3fe6a953), + (0x3f99bac3)}, + (0xfff80000), + {0xe0,0x6d,0x93,0xcf,0x6d,0x0f,0xa4,0xf7,0x93,0x3e, + 0x67,0xb4,0x20,0xb8,0x51,0x3a,0xe3,0xcd,0xf5,0xf9,0x00} + }, + { + /* No.111 delta:2048 weight:1649 */ + 11213, + 12, + 8, + 4, + {(0x00000000), + (0xbf40afc5), + (0xdef9c9b1), + (0x61b96674), + (0xfee006f8), + (0x41a0a93d), + (0x2019cf49), + (0x9f59608c), + (0x000056c5), + (0xbf40f900), + (0xdef99f74), + (0x61b930b1), + (0xfee0503d), + (0x41a0fff8), + (0x2019998c), + (0x9f593649)}, + {(0x00000000), + (0x2fa10c00), + (0x020b0000), + (0x2daa0c00), + (0x020ae000), + (0x2dabec00), + (0x0001e000), + (0x2fa0ec00), + (0x28021e00), + (0x07a31200), + (0x2a091e00), + (0x05a81200), + (0x2a08fe00), + (0x05a9f200), + (0x2803fe00), + (0x07a2f200)}, + {(0x3f800000), + (0x3f97d086), + (0x3f810580), + (0x3f96d506), + (0x3f810570), + (0x3f96d5f6), + (0x3f8000f0), + (0x3f97d076), + (0x3f94010f), + (0x3f83d189), + (0x3f95048f), + (0x3f82d409), + (0x3f95047f), + (0x3f82d4f9), + (0x3f9401ff), + (0x3f83d179)}, + (0xfff80000), + {0x4a,0x15,0xe8,0xf1,0x59,0x83,0x8e,0x52,0x8a,0x24, + 0xa4,0xb5,0x5d,0xfb,0x87,0xe0,0x22,0xe3,0x18,0x37,0x00} + }, + { + /* No.112 delta:2152 weight:1369 */ + 11213, + 81, + 6, + 10, + {(0x00000000), + (0xfbea0aeb), + (0xba6ad14d), + (0x4180dba6), + (0x21e00705), + (0xda0a0dee), + (0x9b8ad648), + (0x6060dca3), + (0x00003510), + (0xfbea3ffb), + (0xba6ae45d), + (0x4180eeb6), + (0x21e03215), + (0xda0a38fe), + (0x9b8ae358), + (0x6060e9b3)}, + {(0x00000000), + (0x01428000), + (0x04604000), + (0x0522c000), + (0x00081000), + (0x014a9000), + (0x04685000), + (0x052ad000), + (0x20261e00), + (0x21649e00), + (0x24465e00), + (0x2504de00), + (0x202e0e00), + (0x216c8e00), + (0x244e4e00), + (0x250cce00)}, + {(0x3f800000), + (0x3f80a140), + (0x3f823020), + (0x3f829160), + (0x3f800408), + (0x3f80a548), + (0x3f823428), + (0x3f829568), + (0x3f90130f), + (0x3f90b24f), + (0x3f92232f), + (0x3f92826f), + (0x3f901707), + (0x3f90b647), + (0x3f922727), + (0x3f928667)}, + (0xfff80000), + {0xfd,0x72,0xaa,0xc7,0x20,0x44,0x28,0xe5,0x03,0x3e, + 0xf9,0x6d,0xad,0x9f,0x51,0x0c,0x87,0xf6,0x43,0x0f,0x00} + }, + { + /* No.113 delta:1871 weight:1215 */ + 11213, + 61, + 14, + 10, + {(0x00000000), + (0x11856d8d), + (0xaac84415), + (0xbb4d2998), + (0xae00071a), + (0xbf856a97), + (0x04c8430f), + (0x154d2e82), + (0x0000cc65), + (0x1185a1e8), + (0xaac88870), + (0xbb4de5fd), + (0xae00cb7f), + (0xbf85a6f2), + (0x04c88f6a), + (0x154de2e7)}, + {(0x00000000), + (0x006d0000), + (0x00b10000), + (0x00dc0000), + (0x04490000), + (0x04240000), + (0x04f80000), + (0x04950000), + (0x00421e00), + (0x002f1e00), + (0x00f31e00), + (0x009e1e00), + (0x040b1e00), + (0x04661e00), + (0x04ba1e00), + (0x04d71e00)}, + {(0x3f800000), + (0x3f803680), + (0x3f805880), + (0x3f806e00), + (0x3f822480), + (0x3f821200), + (0x3f827c00), + (0x3f824a80), + (0x3f80210f), + (0x3f80178f), + (0x3f80798f), + (0x3f804f0f), + (0x3f82058f), + (0x3f82330f), + (0x3f825d0f), + (0x3f826b8f)}, + (0xfff80000), + {0x98,0xdb,0x7c,0xec,0x90,0x27,0x75,0x69,0x6c,0x3d, + 0x4c,0xec,0xa2,0x8e,0xab,0xef,0xd1,0x0c,0xbd,0x8c,0x00} + }, + { + /* No.114 delta:1950 weight:1011 */ + 11213, + 20, + 16, + 13, + {(0x00000000), + (0xbdc99be3), + (0xaafee229), + (0x173779ca), + (0x7300072e), + (0xcec99ccd), + (0xd9fee507), + (0x64377ee4), + (0x0000b504), + (0xbdc92ee7), + (0xaafe572d), + (0x1737ccce), + (0x7300b22a), + (0xcec929c9), + (0xd9fe5003), + (0x6437cbe0)}, + {(0x00000000), + (0x016ec000), + (0x8ce40000), + (0x8d8ac000), + (0x1c548000), + (0x1d3a4000), + (0x90b08000), + (0x91de4000), + (0x00869e00), + (0x01e85e00), + (0x8c629e00), + (0x8d0c5e00), + (0x1cd21e00), + (0x1dbcde00), + (0x90361e00), + (0x9158de00)}, + {(0x3f800000), + (0x3f80b760), + (0x3fc67200), + (0x3fc6c560), + (0x3f8e2a40), + (0x3f8e9d20), + (0x3fc85840), + (0x3fc8ef20), + (0x3f80434f), + (0x3f80f42f), + (0x3fc6314f), + (0x3fc6862f), + (0x3f8e690f), + (0x3f8ede6f), + (0x3fc81b0f), + (0x3fc8ac6f)}, + (0xfff80000), + {0xa7,0x22,0x09,0x2a,0x46,0xe2,0xa3,0x13,0x26,0x8f, + 0xa5,0xc6,0x28,0x12,0x57,0xb4,0x27,0x86,0xf1,0x1d,0x00} + }, + { + /* No.115 delta:1732 weight:1445 */ + 11213, + 29, + 17, + 7, + {(0x00000000), + (0xdb25076c), + (0x9bf7e9d5), + (0x40d2eeb9), + (0x95f00737), + (0x4ed5005b), + (0x0e07eee2), + (0xd522e98e), + (0x0000f5f0), + (0xdb25f29c), + (0x9bf71c25), + (0x40d21b49), + (0x95f0f2c7), + (0x4ed5f5ab), + (0x0e071b12), + (0xd5221c7e)}, + {(0x00000000), + (0x481e0000), + (0x80040000), + (0xc81a0000), + (0x007d0000), + (0x48630000), + (0x80790000), + (0xc8670000), + (0x40121e00), + (0x080c1e00), + (0xc0161e00), + (0x88081e00), + (0x406f1e00), + (0x08711e00), + (0xc06b1e00), + (0x88751e00)}, + {(0x3f800000), + (0x3fa40f00), + (0x3fc00200), + (0x3fe40d00), + (0x3f803e80), + (0x3fa43180), + (0x3fc03c80), + (0x3fe43380), + (0x3fa0090f), + (0x3f84060f), + (0x3fe00b0f), + (0x3fc4040f), + (0x3fa0378f), + (0x3f84388f), + (0x3fe0358f), + (0x3fc43a8f)}, + (0xfff80000), + {0xc2,0xbe,0xe6,0x5f,0xf5,0x28,0x34,0x1c,0x5e,0x2d, + 0xdb,0x99,0x36,0x5d,0x04,0x52,0x9e,0x76,0x9e,0xd5,0x00} + }, + { + /* No.116 delta:1707 weight:1245 */ + 11213, + 30, + 22, + 3, + {(0x00000000), + (0x0a5f3de8), + (0xcb7a16d6), + (0xc1252b3e), + (0xfcd0074b), + (0xf68f3aa3), + (0x37aa119d), + (0x3df52c75), + (0x00003bff), + (0x0a5f0617), + (0xcb7a2d29), + (0xc12510c1), + (0xfcd03cb4), + (0xf68f015c), + (0x37aa2a62), + (0x3df5178a)}, + {(0x00000000), + (0x402e8e00), + (0x0073d000), + (0x405d5e00), + (0x206d4000), + (0x6043ce00), + (0x201e9000), + (0x60301e00), + (0xd21dfe00), + (0x92337000), + (0xd26e2e00), + (0x9240a000), + (0xf270be00), + (0xb25e3000), + (0xf2036e00), + (0xb22de000)}, + {(0x3f800000), + (0x3fa01747), + (0x3f8039e8), + (0x3fa02eaf), + (0x3f9036a0), + (0x3fb021e7), + (0x3f900f48), + (0x3fb0180f), + (0x3fe90eff), + (0x3fc919b8), + (0x3fe93717), + (0x3fc92050), + (0x3ff9385f), + (0x3fd92f18), + (0x3ff901b7), + (0x3fd916f0)}, + (0xfff80000), + {0x30,0x04,0x85,0xba,0x89,0x2d,0x19,0x39,0x57,0x1c, + 0x54,0xa8,0xb5,0x0a,0x05,0x27,0x14,0x6a,0xed,0xe0,0x00} + }, + { + /* No.117 delta:2917 weight:1743 */ + 11213, + 37, + 3, + 6, + {(0x00000000), + (0x501b23d2), + (0x2770f82a), + (0x776bdbf8), + (0x67300751), + (0x372b2483), + (0x4040ff7b), + (0x105bdca9), + (0x000038d9), + (0x501b1b0b), + (0x2770c0f3), + (0x776be321), + (0x67303f88), + (0x372b1c5a), + (0x4040c7a2), + (0x105be470)}, + {(0x00000000), + (0x20542200), + (0x40387800), + (0x606c5a00), + (0x14402000), + (0x34140200), + (0x54785800), + (0x742c7a00), + (0x1840de00), + (0x3814fc00), + (0x5878a600), + (0x782c8400), + (0x0c00fe00), + (0x2c54dc00), + (0x4c388600), + (0x6c6ca400)}, + {(0x3f800000), + (0x3f902a11), + (0x3fa01c3c), + (0x3fb0362d), + (0x3f8a2010), + (0x3f9a0a01), + (0x3faa3c2c), + (0x3fba163d), + (0x3f8c206f), + (0x3f9c0a7e), + (0x3fac3c53), + (0x3fbc1642), + (0x3f86007f), + (0x3f962a6e), + (0x3fa61c43), + (0x3fb63652)}, + (0xfff80000), + {0x86,0x60,0xf6,0x24,0x0e,0xff,0xd7,0xe9,0x32,0x8f, + 0xa0,0x96,0x77,0x67,0x0e,0xec,0x2e,0x00,0x3b,0x13,0x00} + }, + { + /* No.118 delta:983 weight:1587 */ + 11213, + 62, + 19, + 4, + {(0x00000000), + (0x08eb784a), + (0x736759ff), + (0x7b8c21b5), + (0x0ca0076b), + (0x044b7f21), + (0x7fc75e94), + (0x772c26de), + (0x0000d939), + (0x08eba173), + (0x736780c6), + (0x7b8cf88c), + (0x0ca0de52), + (0x044ba618), + (0x7fc787ad), + (0x772cffe7)}, + {(0x00000000), + (0x041eba00), + (0x20637000), + (0x247dca00), + (0x20110000), + (0x240fba00), + (0x00727000), + (0x046cca00), + (0x10001e00), + (0x141ea400), + (0x30636e00), + (0x347dd400), + (0x30111e00), + (0x340fa400), + (0x10726e00), + (0x146cd400)}, + {(0x3f800000), + (0x3f820f5d), + (0x3f9031b8), + (0x3f923ee5), + (0x3f900880), + (0x3f9207dd), + (0x3f803938), + (0x3f823665), + (0x3f88000f), + (0x3f8a0f52), + (0x3f9831b7), + (0x3f9a3eea), + (0x3f98088f), + (0x3f9a07d2), + (0x3f883937), + (0x3f8a366a)}, + (0xfff80000), + {0x70,0x7f,0x78,0xb3,0x65,0x02,0xe0,0xb9,0x55,0x49, + 0xd9,0x60,0xa8,0xa5,0xd3,0x10,0x3b,0x08,0x55,0xfd,0x00} + }, + { + /* No.119 delta:1397 weight:1065 */ + 11213, + 57, + 14, + 11, + {(0x00000000), + (0x5e421ddc), + (0x638787c4), + (0x3dc59a18), + (0x8e00077d), + (0xd0421aa1), + (0xed8780b9), + (0xb3c59d65), + (0x0000840f), + (0x5e4299d3), + (0x638703cb), + (0x3dc51e17), + (0x8e008372), + (0xd0429eae), + (0xed8704b6), + (0xb3c5196a)}, + {(0x00000000), + (0x08e5ec00), + (0x245ea400), + (0x2cbb4800), + (0x00688000), + (0x088d6c00), + (0x24362400), + (0x2cd3c800), + (0x00111e00), + (0x08f4f200), + (0x244fba00), + (0x2caa5600), + (0x00799e00), + (0x089c7200), + (0x24273a00), + (0x2cc2d600)}, + {(0x3f800000), + (0x3f8472f6), + (0x3f922f52), + (0x3f965da4), + (0x3f803440), + (0x3f8446b6), + (0x3f921b12), + (0x3f9669e4), + (0x3f80088f), + (0x3f847a79), + (0x3f9227dd), + (0x3f96552b), + (0x3f803ccf), + (0x3f844e39), + (0x3f92139d), + (0x3f96616b)}, + (0xfff80000), + {0x72,0xeb,0x0e,0x84,0xe7,0xef,0x0c,0xb3,0x72,0xaf, + 0x80,0x06,0xbc,0xf9,0x33,0xf7,0x21,0x72,0x27,0x28,0x00} + }, + { + /* No.120 delta:1392 weight:827 */ + 11213, + 46, + 15, + 17, + {(0x00000000), + (0xa557bf77), + (0x097f4c89), + (0xac28f3fe), + (0xffa0078b), + (0x5af7b8fc), + (0xf6df4b02), + (0x5388f475), + (0x00006249), + (0xa557dd3e), + (0x097f2ec0), + (0xac2891b7), + (0xffa065c2), + (0x5af7dab5), + (0xf6df294b), + (0x5388963c)}, + {(0x00000000), + (0x68748400), + (0x4200ae00), + (0x2a742a00), + (0x1c086000), + (0x747ce400), + (0x5e08ce00), + (0x367c4a00), + (0x0046fe00), + (0x68327a00), + (0x42465000), + (0x2a32d400), + (0x1c4e9e00), + (0x743a1a00), + (0x5e4e3000), + (0x363ab400)}, + {(0x3f800000), + (0x3fb43a42), + (0x3fa10057), + (0x3f953a15), + (0x3f8e0430), + (0x3fba3e72), + (0x3faf0467), + (0x3f9b3e25), + (0x3f80237f), + (0x3fb4193d), + (0x3fa12328), + (0x3f95196a), + (0x3f8e274f), + (0x3fba1d0d), + (0x3faf2718), + (0x3f9b1d5a)}, + (0xfff80000), + {0x7c,0xb2,0x6a,0xff,0x78,0xfa,0xd6,0x78,0xf9,0xba, + 0x77,0x1d,0x84,0xb3,0xbb,0xcb,0xac,0xdf,0x51,0x54,0x00} + }, + { + /* No.121 delta:1663 weight:775 */ + 11213, + 82, + 9, + 17, + {(0x00000000), + (0x1fe0e7a6), + (0x67406a7f), + (0x78a08dd9), + (0xda30079d), + (0xc5d0e03b), + (0xbd706de2), + (0xa2908a44), + (0x000076e4), + (0x1fe09142), + (0x67401c9b), + (0x78a0fb3d), + (0xda307179), + (0xc5d096df), + (0xbd701b06), + (0xa290fca0)}, + {(0x00000000), + (0x100e1000), + (0x20734000), + (0x307d5000), + (0x5008e200), + (0x4006f200), + (0x707ba200), + (0x6075b200), + (0x3242de00), + (0x224cce00), + (0x12319e00), + (0x023f8e00), + (0x624a3c00), + (0x72442c00), + (0x42397c00), + (0x52376c00)}, + {(0x3f800000), + (0x3f880708), + (0x3f9039a0), + (0x3f983ea8), + (0x3fa80471), + (0x3fa00379), + (0x3fb83dd1), + (0x3fb03ad9), + (0x3f99216f), + (0x3f912667), + (0x3f8918cf), + (0x3f811fc7), + (0x3fb1251e), + (0x3fb92216), + (0x3fa11cbe), + (0x3fa91bb6)}, + (0xfff80000), + {0xa3,0xd8,0x55,0xcd,0x98,0xdc,0x68,0x95,0x68,0xdf, + 0xcf,0x56,0x03,0x2a,0x94,0x75,0x10,0xec,0x0a,0x47,0x00} + }, + { + /* No.122 delta:1328 weight:751 */ + 11213, + 67, + 14, + 18, + {(0x00000000), + (0x76bc3aa8), + (0xc37bdc20), + (0xb5c7e688), + (0x38b007ab), + (0x4e0c3d03), + (0xfbcbdb8b), + (0x8d77e123), + (0x0000bd02), + (0x76bc87aa), + (0xc37b6122), + (0xb5c75b8a), + (0x38b0baa9), + (0x4e0c8001), + (0xfbcb6689), + (0x8d775c21)}, + {(0x00000000), + (0x1112c200), + (0x18038000), + (0x09114200), + (0x00065000), + (0x11149200), + (0x1805d000), + (0x09171200), + (0x6001de00), + (0x71131c00), + (0x78025e00), + (0x69109c00), + (0x60078e00), + (0x71154c00), + (0x78040e00), + (0x6916cc00)}, + {(0x3f800000), + (0x3f888961), + (0x3f8c01c0), + (0x3f8488a1), + (0x3f800328), + (0x3f888a49), + (0x3f8c02e8), + (0x3f848b89), + (0x3fb000ef), + (0x3fb8898e), + (0x3fbc012f), + (0x3fb4884e), + (0x3fb003c7), + (0x3fb88aa6), + (0x3fbc0207), + (0x3fb48b66)}, + (0xfff80000), + {0x18,0x30,0x32,0x35,0xe2,0xb4,0xcd,0x94,0x5e,0x6b, + 0xe6,0x78,0x0b,0x92,0x24,0xbf,0x7c,0xc5,0xbd,0xe2,0x00} + }, + { + /* No.123 delta:1657 weight:573 */ + 11213, + 70, + 8, + 19, + {(0x00000000), + (0xfd59bd60), + (0xe0041fb5), + (0x1d5da2d5), + (0x836007b6), + (0x7e39bad6), + (0x63641803), + (0x9e3da563), + (0x0000b1f6), + (0xfd590c96), + (0xe004ae43), + (0x1d5d1323), + (0x8360b640), + (0x7e390b20), + (0x6364a9f5), + (0x9e3d1495)}, + {(0x00000000), + (0x57b14800), + (0x5868a400), + (0x0fd9ec00), + (0x084c7000), + (0x5ffd3800), + (0x5024d400), + (0x07959c00), + (0x10121e00), + (0x47a35600), + (0x487aba00), + (0x1fcbf200), + (0x185e6e00), + (0x4fef2600), + (0x4036ca00), + (0x17878200)}, + {(0x3f800000), + (0x3fabd8a4), + (0x3fac3452), + (0x3f87ecf6), + (0x3f842638), + (0x3faffe9c), + (0x3fa8126a), + (0x3f83cace), + (0x3f88090f), + (0x3fa3d1ab), + (0x3fa43d5d), + (0x3f8fe5f9), + (0x3f8c2f37), + (0x3fa7f793), + (0x3fa01b65), + (0x3f8bc3c1)}, + (0xfff80000), + {0x0b,0xcb,0xeb,0x33,0x75,0x01,0x5e,0xeb,0x92,0xfb, + 0x37,0xae,0xe0,0x31,0x80,0xa9,0x06,0x42,0x2b,0xd5,0x00} + }, + { + /* No.124 delta:1016 weight:1635 */ + 11213, + 80, + 18, + 2, + {(0x00000000), + (0x65b814ab), + (0x0b7c8e4e), + (0x6ec49ae5), + (0xe3e007c1), + (0x8658136a), + (0xe89c898f), + (0x8d249d24), + (0x00008bf0), + (0x65b89f5b), + (0x0b7c05be), + (0x6ec41115), + (0xe3e08c31), + (0x8658989a), + (0xe89c027f), + (0x8d2416d4)}, + {(0x00000000), + (0x110f9000), + (0x08401000), + (0x194f8000), + (0x20040000), + (0x310b9000), + (0x28441000), + (0x394b8000), + (0x00025e00), + (0x110dce00), + (0x08424e00), + (0x194dde00), + (0x20065e00), + (0x3109ce00), + (0x28464e00), + (0x3949de00)}, + {(0x3f800000), + (0x3f8887c8), + (0x3f842008), + (0x3f8ca7c0), + (0x3f900200), + (0x3f9885c8), + (0x3f942208), + (0x3f9ca5c0), + (0x3f80012f), + (0x3f8886e7), + (0x3f842127), + (0x3f8ca6ef), + (0x3f90032f), + (0x3f9884e7), + (0x3f942327), + (0x3f9ca4ef)}, + (0xfff80000), + {0xe8,0x1c,0x9d,0xcc,0x4a,0x97,0xc0,0xae,0x9d,0xce, + 0x1a,0xa4,0x45,0x9f,0x41,0xc4,0x83,0xd9,0x62,0x72,0x00} + }, + { + /* No.125 delta:1214 weight:1175 */ + 11213, + 28, + 16, + 7, + {(0x00000000), + (0x7b11b46d), + (0x3e529f7c), + (0x45432b11), + (0x05a007d2), + (0x7eb1b3bf), + (0x3bf298ae), + (0x40e32cc3), + (0x00001cdb), + (0x7b11a8b6), + (0x3e5283a7), + (0x454337ca), + (0x05a01b09), + (0x7eb1af64), + (0x3bf28475), + (0x40e33018)}, + {(0x00000000), + (0x4460cc00), + (0x50de6c00), + (0x14bea000), + (0x43011e00), + (0x0761d200), + (0x13df7200), + (0x57bfbe00), + (0x41807e00), + (0x05e0b200), + (0x115e1200), + (0x553ede00), + (0x02816000), + (0x46e1ac00), + (0x525f0c00), + (0x163fc000)}, + {(0x3f800000), + (0x3fa23066), + (0x3fa86f36), + (0x3f8a5f50), + (0x3fa1808f), + (0x3f83b0e9), + (0x3f89efb9), + (0x3fabdfdf), + (0x3fa0c03f), + (0x3f82f059), + (0x3f88af09), + (0x3faa9f6f), + (0x3f8140b0), + (0x3fa370d6), + (0x3fa92f86), + (0x3f8b1fe0)}, + (0xfff80000), + {0x5c,0x4c,0x7f,0xad,0xc2,0x0a,0xe3,0x36,0x3a,0x3f, + 0x3e,0x28,0x97,0x26,0xce,0xab,0xdb,0x12,0x07,0x20,0x00} + }, + { + /* No.126 delta:962 weight:1245 */ + 11213, + 78, + 18, + 5, + {(0x00000000), + (0xee0a807e), + (0xe937683b), + (0x073de845), + (0x14f007e9), + (0xfafa8797), + (0xfdc76fd2), + (0x13cdefac), + (0x0000f676), + (0xee0a7608), + (0xe9379e4d), + (0x073d1e33), + (0x14f0f19f), + (0xfafa71e1), + (0xfdc799a4), + (0x13cd19da)}, + {(0x00000000), + (0xb028bc00), + (0x08652400), + (0xb84d9800), + (0x14028600), + (0xa42a3a00), + (0x1c67a200), + (0xac4f1e00), + (0x00023e00), + (0xb02a8200), + (0x08671a00), + (0xb84fa600), + (0x1400b800), + (0xa4280400), + (0x1c659c00), + (0xac4d2000)}, + {(0x3f800000), + (0x3fd8145e), + (0x3f843292), + (0x3fdc26cc), + (0x3f8a0143), + (0x3fd2151d), + (0x3f8e33d1), + (0x3fd6278f), + (0x3f80011f), + (0x3fd81541), + (0x3f84338d), + (0x3fdc27d3), + (0x3f8a005c), + (0x3fd21402), + (0x3f8e32ce), + (0x3fd62690)}, + (0xfff80000), + {0x1f,0xae,0x0b,0x7d,0x23,0x0c,0x6e,0xd6,0x26,0xa9, + 0x92,0xbc,0x8f,0x01,0x36,0x36,0x07,0xe9,0x2c,0x7c,0x00} + }, + { + /* No.127 delta:4656 weight:1185 */ + 11213, + 57, + 4, + 13, + {(0x00000000), + (0x7d46d3c2), + (0x107426fc), + (0x6d32f53e), + (0x832007fe), + (0xfe66d43c), + (0x93542102), + (0xee12f2c0), + (0x00009ac7), + (0x7d464905), + (0x1074bc3b), + (0x6d326ff9), + (0x83209d39), + (0xfe664efb), + (0x9354bbc5), + (0xee126807)}, + {(0x00000000), + (0x18401000), + (0x14000000), + (0x0c401000), + (0x00000000), + (0x18401000), + (0x14000000), + (0x0c401000), + (0x10001e00), + (0x08400e00), + (0x04001e00), + (0x1c400e00), + (0x10001e00), + (0x08400e00), + (0x04001e00), + (0x1c400e00)}, + {(0x3f800000), + (0x3f8c2008), + (0x3f8a0000), + (0x3f862008), + (0x3f800000), + (0x3f8c2008), + (0x3f8a0000), + (0x3f862008), + (0x3f88000f), + (0x3f842007), + (0x3f82000f), + (0x3f8e2007), + (0x3f88000f), + (0x3f842007), + (0x3f82000f), + (0x3f8e2007)}, + (0xfff80000), + {0x2b,0xf5,0xba,0x2c,0x06,0x65,0xd9,0xae,0x19,0x02, + 0xa4,0xb4,0xe6,0x92,0x03,0x77,0xb7,0xb8,0x8c,0x23,0x00} + }, + { + /* No.128 delta:2214 weight:1371 */ + 11213, + 43, + 23, + 2, + {(0x00000000), + (0xe454d1ab), + (0x80c8a6d9), + (0x649c7772), + (0xb0f00808), + (0x54a4d9a3), + (0x3038aed1), + (0xd46c7f7a), + (0x00004f07), + (0xe4549eac), + (0x80c8e9de), + (0x649c3875), + (0xb0f0470f), + (0x54a496a4), + (0x3038e1d6), + (0xd46c307d)}, + {(0x00000000), + (0xca494000), + (0x00538000), + (0xca1ac000), + (0x10bd2000), + (0xdaf46000), + (0x10eea000), + (0xdaa7e000), + (0x18905e00), + (0xd2d91e00), + (0x18c3de00), + (0xd28a9e00), + (0x082d7e00), + (0xc2643e00), + (0x087efe00), + (0xc237be00)}, + {(0x3f800000), + (0x3fe524a0), + (0x3f8029c0), + (0x3fe50d60), + (0x3f885e90), + (0x3fed7a30), + (0x3f887750), + (0x3fed53f0), + (0x3f8c482f), + (0x3fe96c8f), + (0x3f8c61ef), + (0x3fe9454f), + (0x3f8416bf), + (0x3fe1321f), + (0x3f843f7f), + (0x3fe11bdf)}, + (0xfff80000), + {0xf5,0xb9,0x08,0x2c,0x6d,0x40,0xb0,0x38,0xb5,0x70, + 0x83,0x86,0xbb,0x54,0xe7,0x5e,0x64,0xf3,0x40,0x61,0x00} + }, + { + /* No.129 delta:886 weight:915 */ + 11213, + 70, + 12, + 5, + {(0x00000000), + (0x242c5090), + (0x10199a60), + (0x3435caf0), + (0xe9d00810), + (0xcdfc5880), + (0xf9c99270), + (0xdde5c2e0), + (0x00003567), + (0x242c65f7), + (0x1019af07), + (0x3435ff97), + (0xe9d03d77), + (0xcdfc6de7), + (0xf9c9a717), + (0xdde5f787)}, + {(0x00000000), + (0x004e4000), + (0x1009c000), + (0x10478000), + (0x0e025000), + (0x0e4c1000), + (0x1e0b9000), + (0x1e45d000), + (0x10345e00), + (0x107a1e00), + (0x003d9e00), + (0x0073de00), + (0x1e360e00), + (0x1e784e00), + (0x0e3fce00), + (0x0e718e00)}, + {(0x3f800000), + (0x3f802720), + (0x3f8804e0), + (0x3f8823c0), + (0x3f870128), + (0x3f872608), + (0x3f8f05c8), + (0x3f8f22e8), + (0x3f881a2f), + (0x3f883d0f), + (0x3f801ecf), + (0x3f8039ef), + (0x3f8f1b07), + (0x3f8f3c27), + (0x3f871fe7), + (0x3f8738c7)}, + (0xfff80000), + {0xae,0x65,0xce,0x51,0xe8,0x63,0xb5,0x45,0x7a,0xb5, + 0x06,0x3b,0x06,0x88,0x6c,0x62,0x83,0x37,0xc8,0xb9,0x00} + }, + { + /* No.130 delta:2602 weight:1519 */ + 11213, + 18, + 4, + 6, + {(0x00000000), + (0x4fa484d0), + (0x546a6e84), + (0x1bceea54), + (0x4a400828), + (0x05e48cf8), + (0x1e2a66ac), + (0x518ee27c), + (0x0000bda0), + (0x4fa43970), + (0x546ad324), + (0x1bce57f4), + (0x4a40b588), + (0x05e43158), + (0x1e2adb0c), + (0x518e5fdc)}, + {(0x00000000), + (0x13081400), + (0x928e3000), + (0x81862400), + (0x010e0000), + (0x12061400), + (0x93803000), + (0x80882400), + (0x10581e00), + (0x03500a00), + (0x82d62e00), + (0x91de3a00), + (0x11561e00), + (0x025e0a00), + (0x83d82e00), + (0x90d03a00)}, + {(0x3f800000), + (0x3f89840a), + (0x3fc94718), + (0x3fc0c312), + (0x3f808700), + (0x3f89030a), + (0x3fc9c018), + (0x3fc04412), + (0x3f882c0f), + (0x3f81a805), + (0x3fc16b17), + (0x3fc8ef1d), + (0x3f88ab0f), + (0x3f812f05), + (0x3fc1ec17), + (0x3fc8681d)}, + (0xfff80000), + {0x13,0xcb,0x05,0x11,0x83,0xac,0xeb,0x2f,0xe5,0x15, + 0x1a,0x0e,0x87,0xa3,0x4d,0xac,0x2b,0xc0,0xb1,0xf3,0x00} + }, + { + /* No.131 delta:1006 weight:1303 */ + 11213, + 69, + 16, + 7, + {(0x00000000), + (0xeb61a85a), + (0x9e89b6f4), + (0x75e81eae), + (0x4cc00837), + (0xa7a1a06d), + (0xd249bec3), + (0x39281699), + (0x00006d8a), + (0xeb61c5d0), + (0x9e89db7e), + (0x75e87324), + (0x4cc065bd), + (0xa7a1cde7), + (0xd249d349), + (0x39287b13)}, + {(0x00000000), + (0x20bcb000), + (0x51807000), + (0x713cc000), + (0x02a2a000), + (0x221e1000), + (0x5322d000), + (0x739e6000), + (0x00067e00), + (0x20bace00), + (0x51860e00), + (0x713abe00), + (0x02a4de00), + (0x22186e00), + (0x5324ae00), + (0x73981e00)}, + {(0x3f800000), + (0x3f905e58), + (0x3fa8c038), + (0x3fb89e60), + (0x3f815150), + (0x3f910f08), + (0x3fa99168), + (0x3fb9cf30), + (0x3f80033f), + (0x3f905d67), + (0x3fa8c307), + (0x3fb89d5f), + (0x3f81526f), + (0x3f910c37), + (0x3fa99257), + (0x3fb9cc0f)}, + (0xfff80000), + {0xbc,0xf3,0x6a,0x80,0xa6,0xee,0x61,0x78,0xa8,0x3d, + 0x8c,0xee,0x29,0x1b,0x5e,0xfd,0x0b,0xf8,0x0f,0x41,0x00} + }, + { + /* No.132 delta:2899 weight:1651 */ + 11213, + 57, + 3, + 7, + {(0x00000000), + (0x7a913b6d), + (0xeed573ba), + (0x944448d7), + (0xfbd00846), + (0x8141332b), + (0x15057bfc), + (0x6f944091), + (0x00003675), + (0x7a910d18), + (0xeed545cf), + (0x94447ea2), + (0xfbd03e33), + (0x8141055e), + (0x15054d89), + (0x6f9476e4)}, + {(0x00000000), + (0x28410000), + (0x92350000), + (0xba740000), + (0x00601000), + (0x28211000), + (0x92551000), + (0xba141000), + (0x20161e00), + (0x08571e00), + (0xb2231e00), + (0x9a621e00), + (0x20760e00), + (0x08370e00), + (0xb2430e00), + (0x9a020e00)}, + {(0x3f800000), + (0x3f942080), + (0x3fc91a80), + (0x3fdd3a00), + (0x3f803008), + (0x3f941088), + (0x3fc92a88), + (0x3fdd0a08), + (0x3f900b0f), + (0x3f842b8f), + (0x3fd9118f), + (0x3fcd310f), + (0x3f903b07), + (0x3f841b87), + (0x3fd92187), + (0x3fcd0107)}, + (0xfff80000), + {0xa3,0x9f,0x64,0xc5,0x74,0x6d,0x2d,0x17,0xe7,0x4d, + 0x9a,0xaf,0xeb,0xb2,0x24,0x54,0x22,0x7a,0x93,0x8c,0x00} + }, + { + /* No.133 delta:1681 weight:1015 */ + 11213, + 83, + 12, + 13, + {(0x00000000), + (0x9193fd4c), + (0x375d8e7c), + (0xa6ce7330), + (0xbf90085d), + (0x2e03f511), + (0x88cd8621), + (0x195e7b6d), + (0x0000af07), + (0x9193524b), + (0x375d217b), + (0xa6cedc37), + (0xbf90a75a), + (0x2e035a16), + (0x88cd2926), + (0x195ed46a)}, + {(0x00000000), + (0x10740800), + (0x200dc000), + (0x3079c800), + (0x2056f800), + (0x3022f000), + (0x005b3800), + (0x102f3000), + (0x20031e00), + (0x30771600), + (0x000ede00), + (0x107ad600), + (0x0055e600), + (0x1021ee00), + (0x20582600), + (0x302c2e00)}, + {(0x3f800000), + (0x3f883a04), + (0x3f9006e0), + (0x3f983ce4), + (0x3f902b7c), + (0x3f981178), + (0x3f802d9c), + (0x3f881798), + (0x3f90018f), + (0x3f983b8b), + (0x3f80076f), + (0x3f883d6b), + (0x3f802af3), + (0x3f8810f7), + (0x3f902c13), + (0x3f981617)}, + (0xfff80000), + {0x5d,0xf8,0x9e,0x34,0xb8,0x35,0x07,0x7f,0xd2,0xe0, + 0x4f,0x6e,0x48,0xe9,0xdf,0x81,0x9d,0xf1,0x95,0x7a,0x00} + }, + { + /* No.134 delta:2863 weight:755 */ + 11213, + 84, + 6, + 17, + {(0x00000000), + (0x61047d07), + (0x957fb46d), + (0xf47bc96a), + (0x58f00860), + (0x39f47567), + (0xcd8fbc0d), + (0xac8bc10a), + (0x0000e9c0), + (0x610494c7), + (0x957f5dad), + (0xf47b20aa), + (0x58f0e1a0), + (0x39f49ca7), + (0xcd8f55cd), + (0xac8b28ca)}, + {(0x00000000), + (0x007c0000), + (0x13020000), + (0x137e0000), + (0x00020000), + (0x007e0000), + (0x13000000), + (0x137c0000), + (0x20401e00), + (0x203c1e00), + (0x33421e00), + (0x333e1e00), + (0x20421e00), + (0x203e1e00), + (0x33401e00), + (0x333c1e00)}, + {(0x3f800000), + (0x3f803e00), + (0x3f898100), + (0x3f89bf00), + (0x3f800100), + (0x3f803f00), + (0x3f898000), + (0x3f89be00), + (0x3f90200f), + (0x3f901e0f), + (0x3f99a10f), + (0x3f999f0f), + (0x3f90210f), + (0x3f901f0f), + (0x3f99a00f), + (0x3f999e0f)}, + (0xfff80000), + {0xcf,0x5c,0xa5,0xf4,0x7e,0x51,0x25,0xe8,0xf1,0x2b, + 0x6a,0x13,0xd4,0x31,0xca,0x76,0x97,0x3d,0x44,0x1a,0x00} + }, + { + /* No.135 delta:1967 weight:665 */ + 11213, + 19, + 12, + 19, + {(0x00000000), + (0xabbc4cf0), + (0xdf51c626), + (0x74ed8ad6), + (0x74a00878), + (0xdf1c4488), + (0xabf1ce5e), + (0x004d82ae), + (0x0000858b), + (0xabbcc97b), + (0xdf5143ad), + (0x74ed0f5d), + (0x74a08df3), + (0xdf1cc103), + (0xabf14bd5), + (0x004d0725)}, + {(0x00000000), + (0x41001800), + (0x004bc000), + (0x414bd800), + (0x8b86e200), + (0xca86fa00), + (0x8bcd2200), + (0xcacd3a00), + (0x70061e00), + (0x31060600), + (0x704dde00), + (0x314dc600), + (0xfb80fc00), + (0xba80e400), + (0xfbcb3c00), + (0xbacb2400)}, + {(0x3f800000), + (0x3fa0800c), + (0x3f8025e0), + (0x3fa0a5ec), + (0x3fc5c371), + (0x3fe5437d), + (0x3fc5e691), + (0x3fe5669d), + (0x3fb8030f), + (0x3f988303), + (0x3fb826ef), + (0x3f98a6e3), + (0x3ffdc07e), + (0x3fdd4072), + (0x3ffde59e), + (0x3fdd6592)}, + (0xfff80000), + {0xa2,0xe2,0xa5,0xe0,0x11,0x34,0xcb,0xf8,0xfc,0xa2, + 0x71,0xc6,0xbf,0xe2,0xc1,0x23,0x58,0x95,0xf4,0x86,0x00} + }, + { + /* No.136 delta:918 weight:1551 */ + 11213, + 47, + 18, + 4, + {(0x00000000), + (0x09adadc4), + (0xf017020b), + (0xf9baafcf), + (0x03300880), + (0x0a9da544), + (0xf3270a8b), + (0xfa8aa74f), + (0x0000cfe7), + (0x09ad6223), + (0xf017cdec), + (0xf9ba6028), + (0x0330c767), + (0x0a9d6aa3), + (0xf327c56c), + (0xfa8a68a8)}, + {(0x00000000), + (0x18747400), + (0x204c5200), + (0x38382600), + (0x10026c00), + (0x08761800), + (0x304e3e00), + (0x283a4a00), + (0x10011e00), + (0x08756a00), + (0x304d4c00), + (0x28393800), + (0x00037200), + (0x18770600), + (0x204f2000), + (0x383b5400)}, + {(0x3f800000), + (0x3f8c3a3a), + (0x3f902629), + (0x3f9c1c13), + (0x3f880136), + (0x3f843b0c), + (0x3f98271f), + (0x3f941d25), + (0x3f88008f), + (0x3f843ab5), + (0x3f9826a6), + (0x3f941c9c), + (0x3f8001b9), + (0x3f8c3b83), + (0x3f902790), + (0x3f9c1daa)}, + (0xfff80000), + {0xfd,0x25,0x81,0xf4,0x6f,0xd2,0x73,0x0c,0x1d,0xf8, + 0x3c,0x0b,0xd2,0x33,0xf7,0x54,0x12,0xcd,0x88,0xa9,0x00} + }, + { + /* No.137 delta:4265 weight:777 */ + 11213, + 70, + 4, + 16, + {(0x00000000), + (0xab4eac1a), + (0x41078fcd), + (0xea4923d7), + (0x9d20089e), + (0x366ea484), + (0xdc278753), + (0x77692b49), + (0x0000022a), + (0xab4eae30), + (0x41078de7), + (0xea4921fd), + (0x9d200ab4), + (0x366ea6ae), + (0xdc278579), + (0x77692963)}, + {(0x00000000), + (0x39400800), + (0x00500000), + (0x39100800), + (0x002c0000), + (0x396c0800), + (0x007c0000), + (0x393c0800), + (0x5e881e00), + (0x67c81600), + (0x5ed81e00), + (0x67981600), + (0x5ea41e00), + (0x67e41600), + (0x5ef41e00), + (0x67b41600)}, + {(0x3f800000), + (0x3f9ca004), + (0x3f802800), + (0x3f9c8804), + (0x3f801600), + (0x3f9cb604), + (0x3f803e00), + (0x3f9c9e04), + (0x3faf440f), + (0x3fb3e40b), + (0x3faf6c0f), + (0x3fb3cc0b), + (0x3faf520f), + (0x3fb3f20b), + (0x3faf7a0f), + (0x3fb3da0b)}, + (0xfff80000), + {0x67,0x39,0x69,0x46,0xb6,0xab,0xda,0x03,0x1a,0xb9, + 0x33,0x5c,0x43,0x1d,0xc4,0x88,0x65,0xf4,0x6e,0x7c,0x00} + }, + { + /* No.138 delta:2916 weight:1245 */ + 11213, + 12, + 4, + 11, + {(0x00000000), + (0x8bd9bb70), + (0x6536d8cf), + (0xeeef63bf), + (0x83c008a3), + (0x0819b3d3), + (0xe6f6d06c), + (0x6d2f6b1c), + (0x00006357), + (0x8bd9d827), + (0x6536bb98), + (0xeeef00e8), + (0x83c06bf4), + (0x0819d084), + (0xe6f6b33b), + (0x6d2f084b)}, + {(0x00000000), + (0x10b20000), + (0x0c210800), + (0x1c930800), + (0x29540000), + (0x39e60000), + (0x25750800), + (0x35c70800), + (0x02001e00), + (0x12b21e00), + (0x0e211600), + (0x1e931600), + (0x2b541e00), + (0x3be61e00), + (0x27751600), + (0x37c71600)}, + {(0x3f800000), + (0x3f885900), + (0x3f861084), + (0x3f8e4984), + (0x3f94aa00), + (0x3f9cf300), + (0x3f92ba84), + (0x3f9ae384), + (0x3f81000f), + (0x3f89590f), + (0x3f87108b), + (0x3f8f498b), + (0x3f95aa0f), + (0x3f9df30f), + (0x3f93ba8b), + (0x3f9be38b)}, + (0xfff80000), + {0xf3,0xfa,0x1e,0x93,0x8b,0xfb,0x73,0xc0,0xf1,0x10, + 0x33,0xac,0x5f,0x6b,0x3c,0x07,0xa2,0x98,0x75,0xed,0x00} + }, + { + /* No.139 delta:2344 weight:1631 */ + 11213, + 19, + 8, + 7, + {(0x00000000), + (0xfee0d62f), + (0x304aad76), + (0xceaa7b59), + (0x871008b7), + (0x79f0de98), + (0xb75aa5c1), + (0x49ba73ee), + (0x00003b80), + (0xfee0edaf), + (0x304a96f6), + (0xceaa40d9), + (0x87103337), + (0x79f0e518), + (0xb75a9e41), + (0x49ba486e)}, + {(0x00000000), + (0x05204400), + (0x00640000), + (0x05444400), + (0x00510400), + (0x05714000), + (0x00350400), + (0x05154000), + (0x32861e00), + (0x37a65a00), + (0x32e21e00), + (0x37c25a00), + (0x32d71a00), + (0x37f75e00), + (0x32b31a00), + (0x37935e00)}, + {(0x3f800000), + (0x3f829022), + (0x3f803200), + (0x3f82a222), + (0x3f802882), + (0x3f82b8a0), + (0x3f801a82), + (0x3f828aa0), + (0x3f99430f), + (0x3f9bd32d), + (0x3f99710f), + (0x3f9be12d), + (0x3f996b8d), + (0x3f9bfbaf), + (0x3f99598d), + (0x3f9bc9af)}, + (0xfff80000), + {0xaf,0x4b,0x20,0xda,0xcd,0xb1,0xdf,0x23,0x89,0x9b, + 0x9d,0xaf,0x0b,0x97,0x1e,0x9f,0x61,0xe7,0xfc,0x34,0x00} + }, + { + /* No.140 delta:8901 weight:1275 */ + 11213, + 67, + 29, + 1, + {(0x00000000), + (0x10b888fe), + (0xd0c6c2fc), + (0xc07e4a02), + (0x93a008cd), + (0x83188033), + (0x4366ca31), + (0x53de42cf), + (0x00009412), + (0x10b81cec), + (0xd0c656ee), + (0xc07ede10), + (0x93a09cdf), + (0x83181421), + (0x43665e23), + (0x53ded6dd)}, + {(0x00000000), + (0xd4620000), + (0x7a000000), + (0xae620000), + (0x01000000), + (0xd5620000), + (0x7b000000), + (0xaf620000), + (0x20a01e00), + (0xf4c21e00), + (0x5aa01e00), + (0x8ec21e00), + (0x21a01e00), + (0xf5c21e00), + (0x5ba01e00), + (0x8fc21e00)}, + {(0x3f800000), + (0x3fea3100), + (0x3fbd0000), + (0x3fd73100), + (0x3f808000), + (0x3feab100), + (0x3fbd8000), + (0x3fd7b100), + (0x3f90500f), + (0x3ffa610f), + (0x3fad500f), + (0x3fc7610f), + (0x3f90d00f), + (0x3ffae10f), + (0x3fadd00f), + (0x3fc7e10f)}, + (0xfff80000), + {0x57,0x96,0xba,0x7d,0x3b,0x31,0xd7,0xac,0xb2,0xe9, + 0x75,0xcd,0xdb,0x72,0x76,0x05,0x30,0x7f,0xd3,0xa0,0x00} + }, + { + /* No.141 delta:3341 weight:741 */ + 11213, + 28, + 3, + 17, + {(0x00000000), + (0xac86815e), + (0xed762180), + (0x41f0a0de), + (0x81a008df), + (0x2d268981), + (0x6cd6295f), + (0xc050a801), + (0x00004e54), + (0xac86cf0a), + (0xed766fd4), + (0x41f0ee8a), + (0x81a0468b), + (0x2d26c7d5), + (0x6cd6670b), + (0xc050e655)}, + {(0x00000000), + (0x9a110000), + (0x0f440000), + (0x95550000), + (0x70020000), + (0xea130000), + (0x7f460000), + (0xe5570000), + (0x21561e00), + (0xbb471e00), + (0x2e121e00), + (0xb4031e00), + (0x51541e00), + (0xcb451e00), + (0x5e101e00), + (0xc4011e00)}, + {(0x3f800000), + (0x3fcd0880), + (0x3f87a200), + (0x3fcaaa80), + (0x3fb80100), + (0x3ff50980), + (0x3fbfa300), + (0x3ff2ab80), + (0x3f90ab0f), + (0x3fdda38f), + (0x3f97090f), + (0x3fda018f), + (0x3fa8aa0f), + (0x3fe5a28f), + (0x3faf080f), + (0x3fe2008f)}, + (0xfff80000), + {0xcc,0x1d,0x62,0xab,0x61,0x1e,0xfc,0xe5,0x74,0x60, + 0xa2,0x5f,0xd0,0xfe,0xff,0x0e,0xfb,0x75,0x83,0x88,0x00} + }, + { + /* No.142 delta:5114 weight:1233 */ + 11213, + 35, + 30, + 3, + {(0x00000000), + (0xb9cd2997), + (0xab1ac509), + (0x12d7ec9e), + (0x5b2008ea), + (0xe2ed217d), + (0xf03acde3), + (0x49f7e474), + (0x0000ef9a), + (0xb9cdc60d), + (0xab1a2a93), + (0x12d70304), + (0x5b20e770), + (0xe2edcee7), + (0xf03a2279), + (0x49f70bee)}, + {(0x00000000), + (0xaef05000), + (0x2d801000), + (0x83704000), + (0x2390a000), + (0x8d60f000), + (0x0e10b000), + (0xa0e0e000), + (0x01001e00), + (0xaff04e00), + (0x2c800e00), + (0x82705e00), + (0x2290be00), + (0x8c60ee00), + (0x0f10ae00), + (0xa1e0fe00)}, + {(0x3f800000), + (0x3fd77828), + (0x3f96c008), + (0x3fc1b820), + (0x3f91c850), + (0x3fc6b078), + (0x3f870858), + (0x3fd07070), + (0x3f80800f), + (0x3fd7f827), + (0x3f964007), + (0x3fc1382f), + (0x3f91485f), + (0x3fc63077), + (0x3f878857), + (0x3fd0f07f)}, + (0xfff80000), + {0xce,0x51,0x4c,0x65,0x7a,0xae,0xbf,0x6f,0xd6,0x0b, + 0x0c,0x85,0x1c,0x15,0xe3,0xbf,0x9f,0x2b,0xa1,0x5d,0x00} + }, + { + /* No.143 delta:2115 weight:1465 */ + 11213, + 11, + 20, + 4, + {(0x00000000), + (0x34795048), + (0x0b9d244e), + (0x3fe47406), + (0xc90008f2), + (0xfd7958ba), + (0xc29d2cbc), + (0xf6e47cf4), + (0x00008680), + (0x3479d6c8), + (0x0b9da2ce), + (0x3fe4f286), + (0xc9008e72), + (0xfd79de3a), + (0xc29daa3c), + (0xf6e4fa74)}, + {(0x00000000), + (0xc1592000), + (0x16984000), + (0xd7c16000), + (0x21226800), + (0xe07b4800), + (0x37ba2800), + (0xf6e30800), + (0x08345e00), + (0xc96d7e00), + (0x1eac1e00), + (0xdff53e00), + (0x29163600), + (0xe84f1600), + (0x3f8e7600), + (0xfed75600)}, + {(0x3f800000), + (0x3fe0ac90), + (0x3f8b4c20), + (0x3febe0b0), + (0x3f909134), + (0x3ff03da4), + (0x3f9bdd14), + (0x3ffb7184), + (0x3f841a2f), + (0x3fe4b6bf), + (0x3f8f560f), + (0x3feffa9f), + (0x3f948b1b), + (0x3ff4278b), + (0x3f9fc73b), + (0x3fff6bab)}, + (0xfff80000), + {0x5f,0xfb,0xd7,0xc9,0x75,0x94,0x0e,0x84,0xfd,0x2b, + 0xc3,0xaf,0xdd,0x54,0xe4,0x81,0x96,0x14,0x65,0x90,0x00} + }, + { + /* No.144 delta:1074 weight:843 */ + 11213, + 50, + 20, + 11, + {(0x00000000), + (0xa8afcf6f), + (0x497c3b6e), + (0xe1d3f401), + (0xa0800909), + (0x082fc666), + (0xe9fc3267), + (0x4153fd08), + (0x0000ec80), + (0xa8af23ef), + (0x497cd7ee), + (0xe1d31881), + (0xa080e589), + (0x082f2ae6), + (0xe9fcdee7), + (0x41531188)}, + {(0x00000000), + (0x00081200), + (0xd0708400), + (0xd0789600), + (0x70302a00), + (0x70383800), + (0xa040ae00), + (0xa048bc00), + (0x1040fe00), + (0x1048ec00), + (0xc0307a00), + (0xc0386800), + (0x6070d400), + (0x6078c600), + (0xb0005000), + (0xb0084200)}, + {(0x3f800000), + (0x3f800409), + (0x3fe83842), + (0x3fe83c4b), + (0x3fb81815), + (0x3fb81c1c), + (0x3fd02057), + (0x3fd0245e), + (0x3f88207f), + (0x3f882476), + (0x3fe0183d), + (0x3fe01c34), + (0x3fb0386a), + (0x3fb03c63), + (0x3fd80028), + (0x3fd80421)}, + (0xfff80000), + {0x95,0xfe,0x49,0x06,0x5e,0xae,0xca,0x7d,0x0a,0xce, + 0xf9,0x80,0x70,0xc2,0x03,0xa9,0x1c,0xc3,0x16,0x85,0x00} + }, + { + /* No.145 delta:2918 weight:721 */ + 11213, + 86, + 4, + 18, + {(0x00000000), + (0x3bebda5d), + (0x18b70390), + (0x235cd9cd), + (0x2c60091c), + (0x178bd341), + (0x34d70a8c), + (0x0f3cd0d1), + (0x00004f75), + (0x3beb9528), + (0x18b74ce5), + (0x235c96b8), + (0x2c604669), + (0x178b9c34), + (0x34d745f9), + (0x0f3c9fa4)}, + {(0x00000000), + (0x1e710200), + (0x09800000), + (0x17f10200), + (0x00c00000), + (0x1eb10200), + (0x09400000), + (0x17310200), + (0x30431e00), + (0x2e321c00), + (0x39c31e00), + (0x27b21c00), + (0x30831e00), + (0x2ef21c00), + (0x39031e00), + (0x27721c00)}, + {(0x3f800000), + (0x3f8f3881), + (0x3f84c000), + (0x3f8bf881), + (0x3f806000), + (0x3f8f5881), + (0x3f84a000), + (0x3f8b9881), + (0x3f98218f), + (0x3f97190e), + (0x3f9ce18f), + (0x3f93d90e), + (0x3f98418f), + (0x3f97790e), + (0x3f9c818f), + (0x3f93b90e)}, + (0xfff80000), + {0x3c,0x75,0x1b,0x34,0x56,0x7d,0x5c,0xdd,0x5a,0x41, + 0xb9,0x82,0x6d,0x1d,0xc3,0x11,0x62,0x1e,0xea,0x73,0x00} + }, + { + /* No.146 delta:2588 weight:993 */ + 11213, + 77, + 8, + 11, + {(0x00000000), + (0x29b76eba), + (0xb5519d7b), + (0x9ce6f3c1), + (0xac000920), + (0x85b7679a), + (0x1951945b), + (0x30e6fae1), + (0x00002499), + (0x29b74a23), + (0xb551b9e2), + (0x9ce6d758), + (0xac002db9), + (0x85b74303), + (0x1951b0c2), + (0x30e6de78)}, + {(0x00000000), + (0x00350000), + (0x086a0000), + (0x085f0000), + (0x085c0000), + (0x08690000), + (0x00360000), + (0x00030000), + (0x00519e00), + (0x00649e00), + (0x083b9e00), + (0x080e9e00), + (0x080d9e00), + (0x08389e00), + (0x00679e00), + (0x00529e00)}, + {(0x3f800000), + (0x3f801a80), + (0x3f843500), + (0x3f842f80), + (0x3f842e00), + (0x3f843480), + (0x3f801b00), + (0x3f800180), + (0x3f8028cf), + (0x3f80324f), + (0x3f841dcf), + (0x3f84074f), + (0x3f8406cf), + (0x3f841c4f), + (0x3f8033cf), + (0x3f80294f)}, + (0xfff80000), + {0x78,0x89,0x90,0x85,0x2f,0x08,0xc7,0x62,0xed,0x99, + 0x04,0xfb,0xe5,0x26,0x8d,0x20,0x08,0xbc,0xe0,0x01,0x00} + }, + { + /* No.147 delta:1196 weight:1067 */ + 11213, + 65, + 15, + 11, + {(0x00000000), + (0xe3c8118c), + (0x346df077), + (0xd7a5e1fb), + (0xff500936), + (0x1c9818ba), + (0xcb3df941), + (0x28f5e8cd), + (0x000057eb), + (0xe3c84667), + (0x346da79c), + (0xd7a5b610), + (0xff505edd), + (0x1c984f51), + (0xcb3daeaa), + (0x28f5bf26)}, + {(0x00000000), + (0x00411800), + (0x0c060000), + (0x0c471800), + (0x260a4800), + (0x264b5000), + (0x2a0c4800), + (0x2a4d5000), + (0x0003de00), + (0x0042c600), + (0x0c05de00), + (0x0c44c600), + (0x26099600), + (0x26488e00), + (0x2a0f9600), + (0x2a4e8e00)}, + {(0x3f800000), + (0x3f80208c), + (0x3f860300), + (0x3f86238c), + (0x3f930524), + (0x3f9325a8), + (0x3f950624), + (0x3f9526a8), + (0x3f8001ef), + (0x3f802163), + (0x3f8602ef), + (0x3f862263), + (0x3f9304cb), + (0x3f932447), + (0x3f9507cb), + (0x3f952747)}, + (0xfff80000), + {0x1f,0x15,0xcd,0x92,0x4b,0xcd,0x46,0xa5,0x75,0xd5, + 0x6e,0xf4,0x6d,0x40,0x10,0x3c,0xa0,0xd0,0x56,0x85,0x00} + }, + { + /* No.148 delta:995 weight:1397 */ + 11213, + 48, + 20, + 6, + {(0x00000000), + (0x81afe9a5), + (0xc7e54dd3), + (0x464aa476), + (0x42100942), + (0xc3bfe0e7), + (0x85f54491), + (0x045aad34), + (0x0000d573), + (0x81af3cd6), + (0xc7e598a0), + (0x464a7105), + (0x4210dc31), + (0xc3bf3594), + (0x85f591e2), + (0x045a7847)}, + {(0x00000000), + (0x0c8d6800), + (0x00660a00), + (0x0ceb6200), + (0x0190c600), + (0x0d1dae00), + (0x01f6cc00), + (0x0d7ba400), + (0x00423e00), + (0x0ccf5600), + (0x00243400), + (0x0ca95c00), + (0x01d2f800), + (0x0d5f9000), + (0x01b4f200), + (0x0d399a00)}, + {(0x3f800000), + (0x3f8646b4), + (0x3f803305), + (0x3f8675b1), + (0x3f80c863), + (0x3f868ed7), + (0x3f80fb66), + (0x3f86bdd2), + (0x3f80211f), + (0x3f8667ab), + (0x3f80121a), + (0x3f8654ae), + (0x3f80e97c), + (0x3f86afc8), + (0x3f80da79), + (0x3f869ccd)}, + (0xfff80000), + {0x89,0x5d,0x4d,0xfa,0x78,0x98,0x8a,0x59,0x89,0x1d, + 0x43,0x6d,0x08,0x21,0x0f,0x15,0xef,0xea,0xed,0x4f,0x00} + }, + { + /* No.149 delta:1807 weight:1017 */ + 11213, + 25, + 17, + 13, + {(0x00000000), + (0x95fafe23), + (0x258e5d0f), + (0xb074a32c), + (0x5b000950), + (0xcefaf773), + (0x7e8e545f), + (0xeb74aa7c), + (0x00007b8f), + (0x95fa85ac), + (0x258e2680), + (0xb074d8a3), + (0x5b0072df), + (0xcefa8cfc), + (0x7e8e2fd0), + (0xeb74d1f3)}, + {(0x00000000), + (0x40690000), + (0x107c4000), + (0x50154000), + (0x0061b000), + (0x4008b000), + (0x101df000), + (0x5074f000), + (0x10221e00), + (0x504b1e00), + (0x005e5e00), + (0x40375e00), + (0x1043ae00), + (0x502aae00), + (0x003fee00), + (0x4056ee00)}, + {(0x3f800000), + (0x3fa03480), + (0x3f883e20), + (0x3fa80aa0), + (0x3f8030d8), + (0x3fa00458), + (0x3f880ef8), + (0x3fa83a78), + (0x3f88110f), + (0x3fa8258f), + (0x3f802f2f), + (0x3fa01baf), + (0x3f8821d7), + (0x3fa81557), + (0x3f801ff7), + (0x3fa02b77)}, + (0xfff80000), + {0x29,0x89,0x68,0x24,0x4a,0xc0,0x9c,0xf5,0x79,0x14, + 0xc1,0x26,0xaa,0x3d,0xbf,0x1f,0xc1,0xbc,0x78,0x97,0x00} + }, + { + /* No.150 delta:2642 weight:975 */ + 11213, + 44, + 4, + 15, + {(0x00000000), + (0x3cf7745b), + (0x8a251fd4), + (0xb6d26b8f), + (0xc580096c), + (0xf9777d37), + (0x4fa516b8), + (0x735262e3), + (0x00007ddf), + (0x3cf70984), + (0x8a25620b), + (0xb6d21650), + (0xc58074b3), + (0xf97700e8), + (0x4fa56b67), + (0x73521f3c)}, + {(0x00000000), + (0x52780000), + (0x13600000), + (0x41180000), + (0x08cc0000), + (0x5ab40000), + (0x1bac0000), + (0x49d40000), + (0x02401e00), + (0x50381e00), + (0x11201e00), + (0x43581e00), + (0x0a8c1e00), + (0x58f41e00), + (0x19ec1e00), + (0x4b941e00)}, + {(0x3f800000), + (0x3fa93c00), + (0x3f89b000), + (0x3fa08c00), + (0x3f846600), + (0x3fad5a00), + (0x3f8dd600), + (0x3fa4ea00), + (0x3f81200f), + (0x3fa81c0f), + (0x3f88900f), + (0x3fa1ac0f), + (0x3f85460f), + (0x3fac7a0f), + (0x3f8cf60f), + (0x3fa5ca0f)}, + (0xfff80000), + {0x1c,0x8b,0x81,0x2c,0x97,0xf0,0xd6,0x0f,0xeb,0x28, + 0x7e,0xbd,0x56,0xe1,0x95,0x03,0x72,0xd1,0x0a,0x96,0x00} + }, + { + /* No.151 delta:962 weight:1023 */ + 11213, + 78, + 12, + 10, + {(0x00000000), + (0x171b50e0), + (0x997dbf57), + (0x8e66efb7), + (0x22d00977), + (0x35cb5997), + (0xbbadb620), + (0xacb6e6c0), + (0x00001c87), + (0x171b4c67), + (0x997da3d0), + (0x8e66f330), + (0x22d015f0), + (0x35cb4510), + (0xbbadaaa7), + (0xacb6fa47)}, + {(0x00000000), + (0x21821c00), + (0x10102200), + (0x31923e00), + (0x60023000), + (0x41802c00), + (0x70121200), + (0x51900e00), + (0xc100de00), + (0xe082c200), + (0xd110fc00), + (0xf092e000), + (0xa102ee00), + (0x8080f200), + (0xb112cc00), + (0x9090d000)}, + {(0x3f800000), + (0x3f90c10e), + (0x3f880811), + (0x3f98c91f), + (0x3fb00118), + (0x3fa0c016), + (0x3fb80909), + (0x3fa8c807), + (0x3fe0806f), + (0x3ff04161), + (0x3fe8887e), + (0x3ff84970), + (0x3fd08177), + (0x3fc04079), + (0x3fd88966), + (0x3fc84868)}, + (0xfff80000), + {0xb1,0xe6,0xdf,0x01,0xdd,0xa2,0x07,0x31,0x50,0x37, + 0xbf,0x34,0x2a,0x6d,0xfe,0xe7,0x69,0x32,0x01,0x60,0x00} + }, + { + /* No.152 delta:1302 weight:1041 */ + 11213, + 55, + 10, + 13, + {(0x00000000), + (0xd0556a8d), + (0x5e4d31d5), + (0x8e185b58), + (0xe6600989), + (0x36356304), + (0xb82d385c), + (0x687852d1), + (0x000019bb), + (0xd0557336), + (0x5e4d286e), + (0x8e1842e3), + (0xe6601032), + (0x36357abf), + (0xb82d21e7), + (0x68784b6a)}, + {(0x00000000), + (0x627c4000), + (0x3034a000), + (0x5248e000), + (0x00038000), + (0x627fc000), + (0x30372000), + (0x524b6000), + (0x80519e00), + (0xe22dde00), + (0xb0653e00), + (0xd2197e00), + (0x80521e00), + (0xe22e5e00), + (0xb066be00), + (0xd21afe00)}, + {(0x3f800000), + (0x3fb13e20), + (0x3f981a50), + (0x3fa92470), + (0x3f8001c0), + (0x3fb13fe0), + (0x3f981b90), + (0x3fa925b0), + (0x3fc028cf), + (0x3ff116ef), + (0x3fd8329f), + (0x3fe90cbf), + (0x3fc0290f), + (0x3ff1172f), + (0x3fd8335f), + (0x3fe90d7f)}, + (0xfff80000), + {0x9e,0x26,0x73,0xd6,0xbe,0x9b,0x5f,0x7d,0x6b,0x71, + 0x07,0x55,0x14,0xdf,0x70,0x0c,0x4a,0x9a,0xdd,0x23,0x00} + }, + { + /* No.153 delta:1084 weight:1123 */ + 11213, + 86, + 22, + 10, + {(0x00000000), + (0xa2a5f5b9), + (0x2b421269), + (0x89e7e7d0), + (0x54300991), + (0xf695fc28), + (0x7f721bf8), + (0xddd7ee41), + (0x0000dc1c), + (0xa2a529a5), + (0x2b42ce75), + (0x89e73bcc), + (0x5430d58d), + (0xf6952034), + (0x7f72c7e4), + (0xddd7325d)}, + {(0x00000000), + (0x40cc0000), + (0x50668000), + (0x10aa8000), + (0x0069f000), + (0x40a5f000), + (0x500f7000), + (0x10c37000), + (0x00131e00), + (0x40df1e00), + (0x50759e00), + (0x10b99e00), + (0x007aee00), + (0x40b6ee00), + (0x501c6e00), + (0x10d06e00)}, + {(0x3f800000), + (0x3fa06600), + (0x3fa83340), + (0x3f885540), + (0x3f8034f8), + (0x3fa052f8), + (0x3fa807b8), + (0x3f8861b8), + (0x3f80098f), + (0x3fa06f8f), + (0x3fa83acf), + (0x3f885ccf), + (0x3f803d77), + (0x3fa05b77), + (0x3fa80e37), + (0x3f886837)}, + (0xfff80000), + {0x27,0x0a,0x3f,0xdb,0x36,0x65,0x8b,0x9c,0x6c,0x3d, + 0xb3,0x81,0x6b,0x82,0xdc,0xaf,0x77,0xa0,0x5a,0x41,0x00} + }, + { + /* No.154 delta:1218 weight:1125 */ + 11213, + 33, + 17, + 9, + {(0x00000000), + (0xbc510269), + (0x187fd997), + (0xa42edbfe), + (0xb2d009a5), + (0x0e810bcc), + (0xaaafd032), + (0x16fed25b), + (0x00008c92), + (0xbc518efb), + (0x187f5505), + (0xa42e576c), + (0xb2d08537), + (0x0e81875e), + (0xaaaf5ca0), + (0x16fe5ec9)}, + {(0x00000000), + (0x4674aa00), + (0x20885800), + (0x66fcf200), + (0x010e8000), + (0x477a2a00), + (0x2186d800), + (0x67f27200), + (0x02c2be00), + (0x44b61400), + (0x224ae600), + (0x643e4c00), + (0x03cc3e00), + (0x45b89400), + (0x23446600), + (0x6530cc00)}, + {(0x3f800000), + (0x3fa33a55), + (0x3f90442c), + (0x3fb37e79), + (0x3f808740), + (0x3fa3bd15), + (0x3f90c36c), + (0x3fb3f939), + (0x3f81615f), + (0x3fa25b0a), + (0x3f912573), + (0x3fb21f26), + (0x3f81e61f), + (0x3fa2dc4a), + (0x3f91a233), + (0x3fb29866)}, + (0xfff80000), + {0xcd,0xbe,0xfa,0xd2,0x8e,0x1c,0x9f,0x67,0x49,0xe4, + 0xe4,0x6c,0xb2,0xe3,0x01,0xb2,0x56,0x77,0x18,0x40,0x00} + }, + { + /* No.155 delta:2783 weight:955 */ + 11213, + 59, + 3, + 7, + {(0x00000000), + (0xac2382ba), + (0x6ff1673d), + (0xc3d2e587), + (0x37a009b6), + (0x9b838b0c), + (0x58516e8b), + (0xf472ec31), + (0x0000a5f6), + (0xac23274c), + (0x6ff1c2cb), + (0xc3d24071), + (0x37a0ac40), + (0x9b832efa), + (0x5851cb7d), + (0xf47249c7)}, + {(0x00000000), + (0x14228400), + (0x00948000), + (0x14b60400), + (0x206a8400), + (0x34480000), + (0x20fe0400), + (0x34dc8000), + (0x40481e00), + (0x546a9a00), + (0x40dc9e00), + (0x54fe1a00), + (0x60229a00), + (0x74001e00), + (0x60b61a00), + (0x74949e00)}, + {(0x3f800000), + (0x3f8a1142), + (0x3f804a40), + (0x3f8a5b02), + (0x3f903542), + (0x3f9a2400), + (0x3f907f02), + (0x3f9a6e40), + (0x3fa0240f), + (0x3faa354d), + (0x3fa06e4f), + (0x3faa7f0d), + (0x3fb0114d), + (0x3fba000f), + (0x3fb05b0d), + (0x3fba4a4f)}, + (0xfff80000), + {0x12,0x6b,0xe6,0x1a,0xef,0x03,0x6a,0x5a,0xeb,0x44, + 0xd4,0xe8,0x31,0x17,0x3d,0x9b,0xd7,0xd8,0xc8,0xd2,0x00} + }, + { + /* No.156 delta:2681 weight:1401 */ + 11213, + 11, + 22, + 2, + {(0x00000000), + (0xfcaff0c3), + (0xee10c3a9), + (0x12bf336a), + (0x1ea009c1), + (0xe20ff902), + (0xf0b0ca68), + (0x0c1f3aab), + (0x0000a3d9), + (0xfcaf531a), + (0xee106070), + (0x12bf90b3), + (0x1ea0aa18), + (0xe20f5adb), + (0xf0b069b1), + (0x0c1f9972)}, + {(0x00000000), + (0x8f318000), + (0x0c949000), + (0x83a51000), + (0x61378000), + (0xee060000), + (0x6da31000), + (0xe2929000), + (0x4044de00), + (0xcf755e00), + (0x4cd04e00), + (0xc3e1ce00), + (0x21735e00), + (0xae42de00), + (0x2de7ce00), + (0xa2d64e00)}, + {(0x3f800000), + (0x3fc798c0), + (0x3f864a48), + (0x3fc1d288), + (0x3fb09bc0), + (0x3ff70300), + (0x3fb6d188), + (0x3ff14948), + (0x3fa0226f), + (0x3fe7baaf), + (0x3fa66827), + (0x3fe1f0e7), + (0x3f90b9af), + (0x3fd7216f), + (0x3f96f3e7), + (0x3fd16b27)}, + (0xfff80000), + {0x83,0x73,0xde,0x94,0x03,0x6f,0x08,0x85,0xc8,0x3c, + 0xf2,0x9a,0xb2,0x9d,0x8f,0xfe,0x34,0x78,0xe6,0x25,0x00} + }, + { + /* No.157 delta:4633 weight:903 */ + 11213, + 70, + 1, + 8, + {(0x00000000), + (0x4732d8c0), + (0x2145def8), + (0x66770638), + (0x8ec009da), + (0xc9f2d11a), + (0xaf85d722), + (0xe8b70fe2), + (0x000031b0), + (0x4732e970), + (0x2145ef48), + (0x66773788), + (0x8ec0386a), + (0xc9f2e0aa), + (0xaf85e692), + (0xe8b73e52)}, + {(0x00000000), + (0x10400000), + (0x24640000), + (0x34240000), + (0x81100000), + (0x91500000), + (0xa5740000), + (0xb5340000), + (0x08431e00), + (0x18031e00), + (0x2c271e00), + (0x3c671e00), + (0x89531e00), + (0x99131e00), + (0xad371e00), + (0xbd771e00)}, + {(0x3f800000), + (0x3f882000), + (0x3f923200), + (0x3f9a1200), + (0x3fc08800), + (0x3fc8a800), + (0x3fd2ba00), + (0x3fda9a00), + (0x3f84218f), + (0x3f8c018f), + (0x3f96138f), + (0x3f9e338f), + (0x3fc4a98f), + (0x3fcc898f), + (0x3fd69b8f), + (0x3fdebb8f)}, + (0xfff80000), + {0xdd,0x87,0x76,0x32,0x84,0x88,0x7a,0x5f,0x52,0x09, + 0x1f,0x36,0xae,0xfa,0x7b,0x5d,0xb4,0x87,0x91,0x59,0x00} + }, + { + /* No.158 delta:1376 weight:811 */ + 11213, + 58, + 16, + 14, + {(0x00000000), + (0xdc5d3a0a), + (0x023cad01), + (0xde61970b), + (0x286009e2), + (0xf43d33e8), + (0x2a5ca4e3), + (0xf6019ee9), + (0x00009c42), + (0xdc5da648), + (0x023c3143), + (0xde610b49), + (0x286095a0), + (0xf43dafaa), + (0x2a5c38a1), + (0xf60102ab)}, + {(0x00000000), + (0x50081000), + (0x305e0000), + (0x60561000), + (0x10324000), + (0x403a5000), + (0x206c4000), + (0x70645000), + (0x20011e00), + (0x70090e00), + (0x105f1e00), + (0x40570e00), + (0x30335e00), + (0x603b4e00), + (0x006d5e00), + (0x50654e00)}, + {(0x3f800000), + (0x3fa80408), + (0x3f982f00), + (0x3fb02b08), + (0x3f881920), + (0x3fa01d28), + (0x3f903620), + (0x3fb83228), + (0x3f90008f), + (0x3fb80487), + (0x3f882f8f), + (0x3fa02b87), + (0x3f9819af), + (0x3fb01da7), + (0x3f8036af), + (0x3fa832a7)}, + (0xfff80000), + {0x96,0xe0,0xc6,0xef,0x7f,0x51,0x3c,0x13,0xd3,0x63, + 0x80,0x54,0xc8,0x09,0xcc,0x33,0x8e,0x9a,0x15,0x91,0x00} + }, + { + /* No.159 delta:1647 weight:1099 */ + 11213, + 91, + 19, + 1, + {(0x00000000), + (0xeffea95b), + (0x587a7fdf), + (0xb784d684), + (0xe5b009ff), + (0x0a4ea0a4), + (0xbdca7620), + (0x5234df7b), + (0x00008677), + (0xeffe2f2c), + (0x587af9a8), + (0xb78450f3), + (0xe5b08f88), + (0x0a4e26d3), + (0xbdcaf057), + (0x5234590c)}, + {(0x00000000), + (0xc3463c00), + (0x20814400), + (0xe3c77800), + (0x04036400), + (0xc7455800), + (0x24822000), + (0xe7c41c00), + (0x66201e00), + (0xa5662200), + (0x46a15a00), + (0x85e76600), + (0x62237a00), + (0xa1654600), + (0x42a23e00), + (0x81e40200)}, + {(0x3f800000), + (0x3fe1a31e), + (0x3f9040a2), + (0x3ff1e3bc), + (0x3f8201b2), + (0x3fe3a2ac), + (0x3f924110), + (0x3ff3e20e), + (0x3fb3100f), + (0x3fd2b311), + (0x3fa350ad), + (0x3fc2f3b3), + (0x3fb111bd), + (0x3fd0b2a3), + (0x3fa1511f), + (0x3fc0f201)}, + (0xfff80000), + {0x6f,0x70,0x62,0xec,0x14,0x82,0xd2,0xb9,0xc0,0x8d, + 0xdc,0xae,0x07,0x77,0xb8,0x94,0x3f,0xc9,0xfa,0xe1,0x00} + }, + { + /* No.160 delta:2967 weight:901 */ + 11213, + 53, + 18, + 1, + {(0x00000000), + (0xaa302b40), + (0x85ec337a), + (0x2fdc183a), + (0x3dd00a0a), + (0x97e0214a), + (0xb83c3970), + (0x120c1230), + (0x00008c9b), + (0xaa30a7db), + (0x85ecbfe1), + (0x2fdc94a1), + (0x3dd08691), + (0x97e0add1), + (0xb83cb5eb), + (0x120c9eab)}, + {(0x00000000), + (0x0e4c0c00), + (0x81a28000), + (0x8fee8c00), + (0x01009400), + (0x0f4c9800), + (0x80a21400), + (0x8eee1800), + (0x09031e00), + (0x074f1200), + (0x88a19e00), + (0x86ed9200), + (0x08038a00), + (0x064f8600), + (0x89a10a00), + (0x87ed0600)}, + {(0x3f800000), + (0x3f872606), + (0x3fc0d140), + (0x3fc7f746), + (0x3f80804a), + (0x3f87a64c), + (0x3fc0510a), + (0x3fc7770c), + (0x3f84818f), + (0x3f83a789), + (0x3fc450cf), + (0x3fc376c9), + (0x3f8401c5), + (0x3f8327c3), + (0x3fc4d085), + (0x3fc3f683)}, + (0xfff80000), + {0xa5,0x57,0xd6,0x41,0xd4,0x56,0x49,0x1c,0xe3,0x86, + 0x35,0xfc,0x5c,0xaf,0xd9,0xba,0x3e,0xfe,0x47,0xfa,0x00} + }, + { + /* No.161 delta:1285 weight:1009 */ + 11213, + 44, + 22, + 9, + {(0x00000000), + (0xbd887100), + (0x6d55a627), + (0xd0ddd727), + (0x18000a1d), + (0xa5887b1d), + (0x7555ac3a), + (0xc8dddd3a), + (0x0000acfa), + (0xbd88ddfa), + (0x6d550add), + (0xd0dd7bdd), + (0x1800a6e7), + (0xa588d7e7), + (0x755500c0), + (0xc8dd71c0)}, + {(0x00000000), + (0x0fe36000), + (0x0045f000), + (0x0fa69000), + (0x121a2000), + (0x1df94000), + (0x125fd000), + (0x1dbcb000), + (0x00371e00), + (0x0fd47e00), + (0x0072ee00), + (0x0f918e00), + (0x122d3e00), + (0x1dce5e00), + (0x1268ce00), + (0x1d8bae00)}, + {(0x3f800000), + (0x3f87f1b0), + (0x3f8022f8), + (0x3f87d348), + (0x3f890d10), + (0x3f8efca0), + (0x3f892fe8), + (0x3f8ede58), + (0x3f801b8f), + (0x3f87ea3f), + (0x3f803977), + (0x3f87c8c7), + (0x3f89169f), + (0x3f8ee72f), + (0x3f893467), + (0x3f8ec5d7)}, + (0xfff80000), + {0xb3,0x0a,0x52,0x2b,0xc3,0xf3,0x8a,0x0b,0x60,0xcf, + 0x50,0x81,0xc0,0x03,0x13,0x44,0x56,0xfd,0xe5,0x6c,0x00} + }, + { + /* No.162 delta:3653 weight:1321 */ + 11213, + 77, + 4, + 1, + {(0x00000000), + (0x09eb7b50), + (0x4a578b30), + (0x43bcf060), + (0xc4b00a20), + (0xcd5b7170), + (0x8ee78110), + (0x870cfa40), + (0x000030d1), + (0x09eb4b81), + (0x4a57bbe1), + (0x43bcc0b1), + (0xc4b03af1), + (0xcd5b41a1), + (0x8ee7b1c1), + (0x870cca91)}, + {(0x00000000), + (0x20630000), + (0x00492000), + (0x202a2000), + (0x400a0000), + (0x60690000), + (0x40432000), + (0x60202000), + (0xc0027e00), + (0xe0617e00), + (0xc04b5e00), + (0xe0285e00), + (0x80087e00), + (0xa06b7e00), + (0x80415e00), + (0xa0225e00)}, + {(0x3f800000), + (0x3f903180), + (0x3f802490), + (0x3f901510), + (0x3fa00500), + (0x3fb03480), + (0x3fa02190), + (0x3fb01010), + (0x3fe0013f), + (0x3ff030bf), + (0x3fe025af), + (0x3ff0142f), + (0x3fc0043f), + (0x3fd035bf), + (0x3fc020af), + (0x3fd0112f)}, + (0xfff80000), + {0xed,0x0f,0x9e,0x5d,0x4b,0x7d,0x2e,0x4f,0xf8,0xa4, + 0xba,0x23,0xdc,0x1a,0x0e,0x40,0xa9,0xff,0xbf,0xfa,0x00} + }, + { + /* No.163 delta:1515 weight:829 */ + 11213, + 59, + 16, + 13, + {(0x00000000), + (0xd192fecc), + (0x1c86d46e), + (0xcd142aa2), + (0xeb900a31), + (0x3a02f4fd), + (0xf716de5f), + (0x26842093), + (0x00009c7b), + (0xd19262b7), + (0x1c864815), + (0xcd14b6d9), + (0xeb90964a), + (0x3a026886), + (0xf7164224), + (0x2684bce8)}, + {(0x00000000), + (0xc9688000), + (0x08400200), + (0xc1288200), + (0x082d4800), + (0xc145c800), + (0x006d4a00), + (0xc905ca00), + (0x312c1e00), + (0xf8449e00), + (0x396c1c00), + (0xf0049c00), + (0x39015600), + (0xf069d600), + (0x31415400), + (0xf829d400)}, + {(0x3f800000), + (0x3fe4b440), + (0x3f842001), + (0x3fe09441), + (0x3f8416a4), + (0x3fe0a2e4), + (0x3f8036a5), + (0x3fe482e5), + (0x3f98960f), + (0x3ffc224f), + (0x3f9cb60e), + (0x3ff8024e), + (0x3f9c80ab), + (0x3ff834eb), + (0x3f98a0aa), + (0x3ffc14ea)}, + (0xfff80000), + {0xe7,0xaa,0x57,0x85,0x45,0x30,0x30,0xea,0x81,0x55, + 0x14,0xf3,0xe1,0x42,0x5a,0xfc,0x05,0x1e,0xd3,0xf0,0x00} + }, + { + /* No.164 delta:5942 weight:1403 */ + 11213, + 49, + 28, + 3, + {(0x00000000), + (0x96bbff16), + (0x0e2dd758), + (0x9896284e), + (0xb5700a46), + (0x23cbf550), + (0xbb5ddd1e), + (0x2de62208), + (0x0000f8d9), + (0x96bb07cf), + (0x0e2d2f81), + (0x9896d097), + (0xb570f29f), + (0x23cb0d89), + (0xbb5d25c7), + (0x2de6dad1)}, + {(0x00000000), + (0x44940000), + (0x03b80000), + (0x472c0000), + (0x48600000), + (0x0cf40000), + (0x4bd80000), + (0x0f4c0000), + (0x00801e00), + (0x44141e00), + (0x03381e00), + (0x47ac1e00), + (0x48e01e00), + (0x0c741e00), + (0x4b581e00), + (0x0fcc1e00)}, + {(0x3f800000), + (0x3fa24a00), + (0x3f81dc00), + (0x3fa39600), + (0x3fa43000), + (0x3f867a00), + (0x3fa5ec00), + (0x3f87a600), + (0x3f80400f), + (0x3fa20a0f), + (0x3f819c0f), + (0x3fa3d60f), + (0x3fa4700f), + (0x3f863a0f), + (0x3fa5ac0f), + (0x3f87e60f)}, + (0xfff80000), + {0x76,0xb3,0x89,0x96,0x29,0x62,0x6a,0x7b,0xe7,0x6f, + 0x4a,0x6c,0x1f,0xbf,0x96,0x66,0x8d,0x45,0x5d,0x5c,0x00} + }, + { + /* No.165 delta:1776 weight:1045 */ + 11213, + 74, + 10, + 13, + {(0x00000000), + (0x24c994e7), + (0x7e990c2c), + (0x5a5098cb), + (0xb9000a51), + (0x9dc99eb6), + (0xc799067d), + (0xe350929a), + (0x0000dbdf), + (0x24c94f38), + (0x7e99d7f3), + (0x5a504314), + (0xb900d18e), + (0x9dc94569), + (0xc799dda2), + (0xe3504945)}, + {(0x00000000), + (0x00764000), + (0x000d4000), + (0x007b0000), + (0x102e6000), + (0x10582000), + (0x10232000), + (0x10556000), + (0x10065e00), + (0x10701e00), + (0x100b1e00), + (0x107d5e00), + (0x00283e00), + (0x005e7e00), + (0x00257e00), + (0x00533e00)}, + {(0x3f800000), + (0x3f803b20), + (0x3f8006a0), + (0x3f803d80), + (0x3f881730), + (0x3f882c10), + (0x3f881190), + (0x3f882ab0), + (0x3f88032f), + (0x3f88380f), + (0x3f88058f), + (0x3f883eaf), + (0x3f80141f), + (0x3f802f3f), + (0x3f8012bf), + (0x3f80299f)}, + (0xfff80000), + {0xfb,0xa8,0xac,0x3b,0xfe,0x8d,0xcc,0xf9,0x64,0x79, + 0xa4,0xdb,0x6d,0x8f,0x8a,0x6e,0xb9,0x91,0x4e,0xb0,0x00} + }, + { + /* No.166 delta:1278 weight:1311 */ + 11213, + 38, + 18, + 10, + {(0x00000000), + (0x1aa51933), + (0x7654762b), + (0x6cf16f18), + (0x06100a69), + (0x1cb5135a), + (0x70447c42), + (0x6ae16571), + (0x0000bdcd), + (0x1aa5a4fe), + (0x7654cbe6), + (0x6cf1d2d5), + (0x0610b7a4), + (0x1cb5ae97), + (0x7044c18f), + (0x6ae1d8bc)}, + {(0x00000000), + (0x1c020c00), + (0x10065600), + (0x0c045a00), + (0xa4030000), + (0xb8010c00), + (0xb4055600), + (0xa8075a00), + (0x51205e00), + (0x4d225200), + (0x41260800), + (0x5d240400), + (0xf5235e00), + (0xe9215200), + (0xe5250800), + (0xf9270400)}, + {(0x3f800000), + (0x3f8e0106), + (0x3f88032b), + (0x3f86022d), + (0x3fd20180), + (0x3fdc0086), + (0x3fda02ab), + (0x3fd403ad), + (0x3fa8902f), + (0x3fa69129), + (0x3fa09304), + (0x3fae9202), + (0x3ffa91af), + (0x3ff490a9), + (0x3ff29284), + (0x3ffc9382)}, + (0xfff80000), + {0xe2,0x4b,0xe1,0x7f,0x94,0x30,0x00,0x2c,0x65,0x3e, + 0x59,0x45,0xfa,0x87,0x44,0x25,0xe1,0x2d,0xb7,0xdb,0x00} + }, + { + /* No.167 delta:1582 weight:743 */ + 11213, + 80, + 9, + 17, + {(0x00000000), + (0xf8f257fd), + (0x26c7fb3f), + (0xde35acc2), + (0xba900a7d), + (0x42625d80), + (0x9c57f142), + (0x64a5a6bf), + (0x00008157), + (0xf8f2d6aa), + (0x26c77a68), + (0xde352d95), + (0xba908b2a), + (0x4262dcd7), + (0x9c577015), + (0x64a527e8)}, + {(0x00000000), + (0x884f0000), + (0x11035000), + (0x994c5000), + (0x2a02a800), + (0xa24da800), + (0x3b01f800), + (0xb34ef800), + (0x10041e00), + (0x984b1e00), + (0x01074e00), + (0x89484e00), + (0x3a06b600), + (0xb249b600), + (0x2b05e600), + (0xa34ae600)}, + {(0x3f800000), + (0x3fc42780), + (0x3f8881a8), + (0x3fcca628), + (0x3f950154), + (0x3fd126d4), + (0x3f9d80fc), + (0x3fd9a77c), + (0x3f88020f), + (0x3fcc258f), + (0x3f8083a7), + (0x3fc4a427), + (0x3f9d035b), + (0x3fd924db), + (0x3f9582f3), + (0x3fd1a573)}, + (0xfff80000), + {0xad,0x7a,0xb9,0x26,0x28,0x43,0xfc,0x1a,0x71,0x9d, + 0xfe,0xb1,0x4c,0x75,0x45,0xcd,0x8d,0xf2,0x4d,0x01,0x00} + }, + { + /* No.168 delta:7619 weight:787 */ + 11213, + 59, + 26, + 1, + {(0x00000000), + (0x98e8b6d9), + (0x521f6a74), + (0xcaf7dcad), + (0x53d00a8d), + (0xcb38bc54), + (0x01cf60f9), + (0x9927d620), + (0x0000f72a), + (0x98e841f3), + (0x521f9d5e), + (0xcaf72b87), + (0x53d0fda7), + (0xcb384b7e), + (0x01cf97d3), + (0x9927210a)}, + {(0x00000000), + (0x4e200000), + (0x70542000), + (0x3e742000), + (0x13942000), + (0x5db42000), + (0x63c00000), + (0x2de00000), + (0x08001e00), + (0x46201e00), + (0x78543e00), + (0x36743e00), + (0x1b943e00), + (0x55b43e00), + (0x6bc01e00), + (0x25e01e00)}, + {(0x3f800000), + (0x3fa71000), + (0x3fb82a10), + (0x3f9f3a10), + (0x3f89ca10), + (0x3faeda10), + (0x3fb1e000), + (0x3f96f000), + (0x3f84000f), + (0x3fa3100f), + (0x3fbc2a1f), + (0x3f9b3a1f), + (0x3f8dca1f), + (0x3faada1f), + (0x3fb5e00f), + (0x3f92f00f)}, + (0xfff80000), + {0xc1,0xeb,0x15,0xa4,0x17,0x5a,0x94,0xa3,0xdd,0x5b, + 0x7e,0x69,0x12,0x88,0xd9,0x94,0x36,0x81,0x7c,0x98,0x00} + }, + { + /* No.169 delta:1710 weight:1097 */ + 11213, + 57, + 14, + 11, + {(0x00000000), + (0x5e421ddc), + (0x638787c4), + (0x3dc59a18), + (0x8e000a9d), + (0xd0421741), + (0xed878d59), + (0xb3c59085), + (0x0000840f), + (0x5e4299d3), + (0x638703cb), + (0x3dc51e17), + (0x8e008e92), + (0xd042934e), + (0xed870956), + (0xb3c5148a)}, + {(0x00000000), + (0x4a752000), + (0xd0784000), + (0x9a0d6000), + (0x004c4000), + (0x4a396000), + (0xd0340000), + (0x9a412000), + (0x00005e00), + (0x4a757e00), + (0xd0781e00), + (0x9a0d3e00), + (0x004c1e00), + (0x4a393e00), + (0xd0345e00), + (0x9a417e00)}, + {(0x3f800000), + (0x3fa53a90), + (0x3fe83c20), + (0x3fcd06b0), + (0x3f802620), + (0x3fa51cb0), + (0x3fe81a00), + (0x3fcd2090), + (0x3f80002f), + (0x3fa53abf), + (0x3fe83c0f), + (0x3fcd069f), + (0x3f80260f), + (0x3fa51c9f), + (0x3fe81a2f), + (0x3fcd20bf)}, + (0xfff80000), + {0x63,0xf7,0x0a,0xee,0x1d,0x41,0x31,0xa9,0xfd,0x48, + 0x35,0xb8,0x86,0xd8,0xf7,0x25,0x29,0x14,0xb0,0x12,0x00} + }, + { + /* No.170 delta:4372 weight:995 */ + 11213, + 28, + 7, + 15, + {(0x00000000), + (0x655fb5a5), + (0x87997101), + (0xe2c6c4a4), + (0x59f00aaa), + (0x3cafbf0f), + (0xde697bab), + (0xbb36ce0e), + (0x0000365d), + (0x655f83f8), + (0x8799475c), + (0xe2c6f2f9), + (0x59f03cf7), + (0x3caf8952), + (0xde694df6), + (0xbb36f853)}, + {(0x00000000), + (0x81898800), + (0xd202e000), + (0x538b6800), + (0x08d64000), + (0x895fc800), + (0xdad4a000), + (0x5b5d2800), + (0x004a5e00), + (0x81c3d600), + (0xd248be00), + (0x53c13600), + (0x089c1e00), + (0x89159600), + (0xda9efe00), + (0x5b177600)}, + {(0x3f800000), + (0x3fc0c4c4), + (0x3fe90170), + (0x3fa9c5b4), + (0x3f846b20), + (0x3fc4afe4), + (0x3fed6a50), + (0x3fadae94), + (0x3f80252f), + (0x3fc0e1eb), + (0x3fe9245f), + (0x3fa9e09b), + (0x3f844e0f), + (0x3fc48acb), + (0x3fed4f7f), + (0x3fad8bbb)}, + (0xfff80000), + {0x89,0xf5,0x02,0x8f,0x88,0xdf,0x79,0x2c,0xc5,0x67, + 0x1f,0x9e,0xd5,0x1b,0xd9,0x5a,0x79,0x7f,0xca,0x71,0x00} + }, + { + /* No.171 delta:3023 weight:1549 */ + 11213, + 32, + 3, + 5, + {(0x00000000), + (0x3b134609), + (0x5b97bf87), + (0x6084f98e), + (0xdbb00aba), + (0xe0a34cb3), + (0x8027b53d), + (0xbb34f334), + (0x00000ea9), + (0x3b1348a0), + (0x5b97b12e), + (0x6084f727), + (0xdbb00413), + (0xe0a3421a), + (0x8027bb94), + (0xbb34fd9d)}, + {(0x00000000), + (0x04030000), + (0x00c10000), + (0x04c20000), + (0x304a8000), + (0x34498000), + (0x308b8000), + (0x34888000), + (0x00679e00), + (0x04649e00), + (0x00a69e00), + (0x04a59e00), + (0x302d1e00), + (0x342e1e00), + (0x30ec1e00), + (0x34ef1e00)}, + {(0x3f800000), + (0x3f820180), + (0x3f806080), + (0x3f826100), + (0x3f982540), + (0x3f9a24c0), + (0x3f9845c0), + (0x3f9a4440), + (0x3f8033cf), + (0x3f82324f), + (0x3f80534f), + (0x3f8252cf), + (0x3f98168f), + (0x3f9a170f), + (0x3f98760f), + (0x3f9a778f)}, + (0xfff80000), + {0x6a,0x8d,0xed,0xda,0x5f,0x16,0x85,0xea,0xd9,0x4c, + 0x66,0x31,0xe2,0x9c,0xc6,0x66,0x6d,0x10,0xa0,0xf9,0x00} + }, + { + /* No.172 delta:892 weight:1461 */ + 11213, + 41, + 18, + 4, + {(0x00000000), + (0x51c43b00), + (0x7d71cf7d), + (0x2cb5f47d), + (0x03f00ac3), + (0x523431c3), + (0x7e81c5be), + (0x2f45febe), + (0x0000fa3d), + (0x51c4c13d), + (0x7d713540), + (0x2cb50e40), + (0x03f0f0fe), + (0x5234cbfe), + (0x7e813f83), + (0x2f450483)}, + {(0x00000000), + (0x40672000), + (0x00508c00), + (0x4037ac00), + (0x00402000), + (0x40270000), + (0x0010ac00), + (0x40778c00), + (0x0e881e00), + (0x4eef3e00), + (0x0ed89200), + (0x4ebfb200), + (0x0ec83e00), + (0x4eaf1e00), + (0x0e98b200), + (0x4eff9200)}, + {(0x3f800000), + (0x3fa03390), + (0x3f802846), + (0x3fa01bd6), + (0x3f802010), + (0x3fa01380), + (0x3f800856), + (0x3fa03bc6), + (0x3f87440f), + (0x3fa7779f), + (0x3f876c49), + (0x3fa75fd9), + (0x3f87641f), + (0x3fa7578f), + (0x3f874c59), + (0x3fa77fc9)}, + (0xfff80000), + {0xc5,0x69,0xaf,0xb6,0xea,0x60,0x78,0x16,0x94,0x3a, + 0x36,0x01,0x5a,0xe7,0x99,0xcd,0x09,0x6a,0xda,0xea,0x00} + }, + { + /* No.173 delta:1013 weight:1115 */ + 11213, + 91, + 19, + 8, + {(0x00000000), + (0xd6aede60), + (0xdfd2815a), + (0x097c5f3a), + (0xbc400ad0), + (0x6aeed4b0), + (0x63928b8a), + (0xb53c55ea), + (0x000003b3), + (0xd6aeddd3), + (0xdfd282e9), + (0x097c5c89), + (0xbc400963), + (0x6aeed703), + (0x63928839), + (0xb53c5659)}, + {(0x00000000), + (0x24590000), + (0x08c14000), + (0x2c984000), + (0x80083800), + (0xa4513800), + (0x88c97800), + (0xac907800), + (0x50c09e00), + (0x74999e00), + (0x5801de00), + (0x7c58de00), + (0xd0c8a600), + (0xf491a600), + (0xd809e600), + (0xfc50e600)}, + {(0x3f800000), + (0x3f922c80), + (0x3f8460a0), + (0x3f964c20), + (0x3fc0041c), + (0x3fd2289c), + (0x3fc464bc), + (0x3fd6483c), + (0x3fa8604f), + (0x3fba4ccf), + (0x3fac00ef), + (0x3fbe2c6f), + (0x3fe86453), + (0x3ffa48d3), + (0x3fec04f3), + (0x3ffe2873)}, + (0xfff80000), + {0x55,0x6c,0x5c,0x20,0xdd,0xbb,0xa3,0xad,0x56,0x67, + 0x8f,0xcf,0xc9,0xb4,0xc5,0x0f,0x66,0xf7,0xb5,0xcc,0x00} + }, + { + /* No.174 delta:2582 weight:887 */ + 11213, + 40, + 4, + 1, + {(0x00000000), + (0x70c0d1b0), + (0x83972550), + (0xf357f4e0), + (0xbbc00ae0), + (0xcb00db50), + (0x38572fb0), + (0x4897fe00), + (0x0000df80), + (0x70c00e30), + (0x8397fad0), + (0xf3572b60), + (0xbbc0d560), + (0xcb0004d0), + (0x3857f030), + (0x48972180)}, + {(0x00000000), + (0x00b20200), + (0x00430000), + (0x00f10200), + (0x40024000), + (0x40b04200), + (0x40414000), + (0x40f34200), + (0x6401de00), + (0x64b3dc00), + (0x6442de00), + (0x64f0dc00), + (0x24039e00), + (0x24b19c00), + (0x24409e00), + (0x24f29c00)}, + {(0x3f800000), + (0x3f805901), + (0x3f802180), + (0x3f807881), + (0x3fa00120), + (0x3fa05821), + (0x3fa020a0), + (0x3fa079a1), + (0x3fb200ef), + (0x3fb259ee), + (0x3fb2216f), + (0x3fb2786e), + (0x3f9201cf), + (0x3f9258ce), + (0x3f92204f), + (0x3f92794e)}, + (0xfff80000), + {0x4c,0x34,0x96,0xf1,0x70,0xe5,0x52,0xb1,0x4d,0x38, + 0xa6,0x34,0x26,0x09,0x5c,0x6c,0x92,0xe6,0x3e,0xcb,0x00} + }, + { + /* No.175 delta:1962 weight:1531 */ + 11213, + 11, + 19, + 4, + {(0x00000000), + (0x91291aaa), + (0xdc02bffd), + (0x4d2ba557), + (0x1fc00af5), + (0x8ee9105f), + (0xc3c2b508), + (0x52ebafa2), + (0x0000add4), + (0x9129b77e), + (0xdc021229), + (0x4d2b0883), + (0x1fc0a721), + (0x8ee9bd8b), + (0xc3c218dc), + (0x52eb0276)}, + {(0x00000000), + (0x09ff0c00), + (0x09141600), + (0x00eb1a00), + (0x7510e000), + (0x7cefec00), + (0x7c04f600), + (0x75fbfa00), + (0x05509e00), + (0x0caf9200), + (0x0c448800), + (0x05bb8400), + (0x70407e00), + (0x79bf7200), + (0x79546800), + (0x70ab6400)}, + {(0x3f800000), + (0x3f84ff86), + (0x3f848a0b), + (0x3f80758d), + (0x3fba8870), + (0x3fbe77f6), + (0x3fbe027b), + (0x3fbafdfd), + (0x3f82a84f), + (0x3f8657c9), + (0x3f862244), + (0x3f82ddc2), + (0x3fb8203f), + (0x3fbcdfb9), + (0x3fbcaa34), + (0x3fb855b2)}, + (0xfff80000), + {0x6f,0x40,0xbd,0xae,0x48,0xc1,0x7d,0x5b,0x99,0x1a, + 0x4e,0x57,0x61,0x39,0x1e,0x68,0xb1,0xf7,0xc0,0xaa,0x00} + }, + { + /* No.176 delta:2277 weight:543 */ + 11213, + 33, + 7, + 19, + {(0x00000000), + (0x8044010b), + (0x62414b11), + (0xe2054a1a), + (0xbb700b06), + (0x3b340a0d), + (0xd9314017), + (0x5975411c), + (0x000099a5), + (0x804498ae), + (0x6241d2b4), + (0xe205d3bf), + (0xbb7092a3), + (0x3b3493a8), + (0xd931d9b2), + (0x5975d8b9)}, + {(0x00000000), + (0x0c3e0800), + (0x80be4000), + (0x8c804800), + (0x00483000), + (0x0c763800), + (0x80f67000), + (0x8cc87800), + (0x00791e00), + (0x0c471600), + (0x80c75e00), + (0x8cf95600), + (0x00312e00), + (0x0c0f2600), + (0x808f6e00), + (0x8cb16600)}, + {(0x3f800000), + (0x3f861f04), + (0x3fc05f20), + (0x3fc64024), + (0x3f802418), + (0x3f863b1c), + (0x3fc07b38), + (0x3fc6643c), + (0x3f803c8f), + (0x3f86238b), + (0x3fc063af), + (0x3fc67cab), + (0x3f801897), + (0x3f860793), + (0x3fc047b7), + (0x3fc658b3)}, + (0xfff80000), + {0xfc,0x12,0x23,0x4e,0x03,0xa3,0xf6,0xfd,0x28,0xb5, + 0xf1,0x0e,0x0a,0x5d,0xed,0x4a,0xd6,0x0c,0xfa,0x9a,0x00} + }, + { + /* No.177 delta:1331 weight:1179 */ + 11213, + 60, + 21, + 4, + {(0x00000000), + (0x8e46be68), + (0x9cb3a5d7), + (0x12f51bbf), + (0x3e600b12), + (0xb026b57a), + (0xa2d3aec5), + (0x2c9510ad), + (0x0000942c), + (0x8e462a44), + (0x9cb331fb), + (0x12f58f93), + (0x3e609f3e), + (0xb0262156), + (0xa2d33ae9), + (0x2c958481)}, + {(0x00000000), + (0x0940a800), + (0x388c9000), + (0x31cc3800), + (0x00608000), + (0x09202800), + (0x38ec1000), + (0x31acb800), + (0x005c7e00), + (0x091cd600), + (0x38d0ee00), + (0x31904600), + (0x003cfe00), + (0x097c5600), + (0x38b06e00), + (0x31f0c600)}, + {(0x3f800000), + (0x3f84a054), + (0x3f9c4648), + (0x3f98e61c), + (0x3f803040), + (0x3f849014), + (0x3f9c7608), + (0x3f98d65c), + (0x3f802e3f), + (0x3f848e6b), + (0x3f9c6877), + (0x3f98c823), + (0x3f801e7f), + (0x3f84be2b), + (0x3f9c5837), + (0x3f98f863)}, + (0xfff80000), + {0x71,0x3a,0xb0,0x71,0xe1,0x95,0x3c,0xba,0x23,0x00, + 0x7a,0xc6,0x93,0x4a,0xb7,0xb8,0xeb,0x00,0x24,0x8e,0x00} + }, + { + /* No.178 delta:3213 weight:657 */ + 11213, + 46, + 22, + 1, + {(0x00000000), + (0x53fdf1b0), + (0x32502578), + (0x61add4c8), + (0x46c00b28), + (0x153dfa98), + (0x74902e50), + (0x276ddfe0), + (0x00006d70), + (0x53fd9cc0), + (0x32504808), + (0x61adb9b8), + (0x46c06658), + (0x153d97e8), + (0x74904320), + (0x276db290)}, + {(0x00000000), + (0x44633a00), + (0x44038600), + (0x0060bc00), + (0x1819c200), + (0x5c7af800), + (0x5c1a4400), + (0x18797e00), + (0x21eade00), + (0x6589e400), + (0x65e95800), + (0x218a6200), + (0x39f31c00), + (0x7d902600), + (0x7df09a00), + (0x3993a000)}, + {(0x3f800000), + (0x3fa2319d), + (0x3fa201c3), + (0x3f80305e), + (0x3f8c0ce1), + (0x3fae3d7c), + (0x3fae0d22), + (0x3f8c3cbf), + (0x3f90f56f), + (0x3fb2c4f2), + (0x3fb2f4ac), + (0x3f90c531), + (0x3f9cf98e), + (0x3fbec813), + (0x3fbef84d), + (0x3f9cc9d0)}, + (0xfff80000), + {0x92,0xb2,0x66,0x1e,0x08,0xb8,0x0b,0x02,0x41,0xdc, + 0x45,0x04,0x59,0x65,0x0b,0x55,0x82,0x05,0xeb,0x6d,0x00} + }, + { + /* No.179 delta:4972 weight:1077 */ + 11213, + 16, + 7, + 11, + {(0x00000000), + (0xcf8962a9), + (0xb6d797a1), + (0x795ef508), + (0xfbb00b36), + (0x3439699f), + (0x4d679c97), + (0x82eefe3e), + (0x0000d59e), + (0xcf89b737), + (0xb6d7423f), + (0x795e2096), + (0xfbb0dea8), + (0x3439bc01), + (0x4d674909), + (0x82ee2ba0)}, + {(0x00000000), + (0x01000000), + (0x08000000), + (0x09000000), + (0x41800000), + (0x40800000), + (0x49800000), + (0x48800000), + (0x06801e00), + (0x07801e00), + (0x0e801e00), + (0x0f801e00), + (0x47001e00), + (0x46001e00), + (0x4f001e00), + (0x4e001e00)}, + {(0x3f800000), + (0x3f808000), + (0x3f840000), + (0x3f848000), + (0x3fa0c000), + (0x3fa04000), + (0x3fa4c000), + (0x3fa44000), + (0x3f83400f), + (0x3f83c00f), + (0x3f87400f), + (0x3f87c00f), + (0x3fa3800f), + (0x3fa3000f), + (0x3fa7800f), + (0x3fa7000f)}, + (0xfff80000), + {0x55,0xe1,0xc9,0x26,0x74,0x2c,0xed,0x5c,0x7b,0x89, + 0xe7,0x1d,0x6f,0x5d,0x02,0xe5,0x4a,0x19,0x8c,0x04,0x00} + }, + { + /* No.180 delta:2285 weight:1529 */ + 11213, + 16, + 5, + 9, + {(0x00000000), + (0x5766ef3b), + (0xaca2499c), + (0xfbc4a6a7), + (0x63800b4f), + (0x34e6e474), + (0xcf2242d3), + (0x9844ade8), + (0x0000a19a), + (0x57664ea1), + (0xaca2e806), + (0xfbc4073d), + (0x6380aad5), + (0x34e645ee), + (0xcf22e349), + (0x98440c72)}, + {(0x00000000), + (0x1901c200), + (0x88118000), + (0x91104200), + (0x02ef8000), + (0x1bee4200), + (0x8afe0000), + (0x93ffc200), + (0x3087be00), + (0x29867c00), + (0xb8963e00), + (0xa197fc00), + (0x32683e00), + (0x2b69fc00), + (0xba79be00), + (0xa3787c00)}, + {(0x3f800000), + (0x3f8c80e1), + (0x3fc408c0), + (0x3fc88821), + (0x3f8177c0), + (0x3f8df721), + (0x3fc57f00), + (0x3fc9ffe1), + (0x3f9843df), + (0x3f94c33e), + (0x3fdc4b1f), + (0x3fd0cbfe), + (0x3f99341f), + (0x3f95b4fe), + (0x3fdd3cdf), + (0x3fd1bc3e)}, + (0xfff80000), + {0x4b,0xb0,0xb5,0xae,0x6b,0x5e,0xea,0x44,0x3b,0xd2, + 0xcf,0xf3,0x8a,0x8d,0xff,0x98,0xeb,0xce,0xa2,0x22,0x00} + }, + { + /* No.181 delta:1320 weight:1461 */ + 11213, + 52, + 21, + 2, + {(0x00000000), + (0x2f3716e3), + (0x0af6f7a8), + (0x25c1e14b), + (0x67900b5a), + (0x48a71db9), + (0x6d66fcf2), + (0x4251ea11), + (0x0000adb5), + (0x2f37bb56), + (0x0af65a1d), + (0x25c14cfe), + (0x6790a6ef), + (0x48a7b00c), + (0x6d665147), + (0x425147a4)}, + {(0x00000000), + (0xc0295e00), + (0x1040c000), + (0xd0699e00), + (0x20fc7200), + (0xe0d52c00), + (0x30bcb200), + (0xf095ec00), + (0x10a2fe00), + (0xd08ba000), + (0x00e23e00), + (0xc0cb6000), + (0x305e8c00), + (0xf077d200), + (0x201e4c00), + (0xe0371200)}, + {(0x3f800000), + (0x3fe014af), + (0x3f882060), + (0x3fe834cf), + (0x3f907e39), + (0x3ff06a96), + (0x3f985e59), + (0x3ff84af6), + (0x3f88517f), + (0x3fe845d0), + (0x3f80711f), + (0x3fe065b0), + (0x3f982f46), + (0x3ff83be9), + (0x3f900f26), + (0x3ff01b89)}, + (0xfff80000), + {0xf7,0x30,0xe4,0xa1,0xb6,0x2c,0xff,0x05,0x23,0x13, + 0xd1,0x56,0xd7,0x7a,0x22,0x24,0xae,0xf7,0x34,0x52,0x00} + }, + { + /* No.182 delta:789 weight:1509 */ + 11213, + 74, + 16, + 6, + {(0x00000000), + (0xe416060b), + (0xd6bfa624), + (0x32a9a02f), + (0x56500b61), + (0xb2460d6a), + (0x80efad45), + (0x64f9ab4e), + (0x0000ce80), + (0xe416c88b), + (0xd6bf68a4), + (0x32a96eaf), + (0x5650c5e1), + (0xb246c3ea), + (0x80ef63c5), + (0x64f965ce)}, + {(0x00000000), + (0x804c0800), + (0x107ad000), + (0x9036d800), + (0x0055c400), + (0x8019cc00), + (0x102f1400), + (0x90631c00), + (0x00033e00), + (0x804f3600), + (0x1079ee00), + (0x9035e600), + (0x0056fa00), + (0x801af200), + (0x102c2a00), + (0x90602200)}, + {(0x3f800000), + (0x3fc02604), + (0x3f883d68), + (0x3fc81b6c), + (0x3f802ae2), + (0x3fc00ce6), + (0x3f88178a), + (0x3fc8318e), + (0x3f80019f), + (0x3fc0279b), + (0x3f883cf7), + (0x3fc81af3), + (0x3f802b7d), + (0x3fc00d79), + (0x3f881615), + (0x3fc83011)}, + (0xfff80000), + {0xa2,0xea,0x48,0x1e,0xb3,0x8f,0x99,0x75,0xba,0x12, + 0x9c,0xbf,0xf3,0xa0,0xb8,0x5d,0xc8,0x38,0xc4,0x74,0x00} + }, + { + /* No.183 delta:1268 weight:1109 */ + 11213, + 42, + 13, + 11, + {(0x00000000), + (0xf7ba01fd), + (0xaa8773ac), + (0x5d3d7251), + (0xa5b00b7d), + (0x520a0a80), + (0x0f3778d1), + (0xf88d792c), + (0x0000aaa0), + (0xf7baab5d), + (0xaa87d90c), + (0x5d3dd8f1), + (0xa5b0a1dd), + (0x520aa020), + (0x0f37d271), + (0xf88dd38c)}, + {(0x00000000), + (0x92abc000), + (0x00443800), + (0x92eff800), + (0x00c12000), + (0x926ae000), + (0x00851800), + (0x922ed800), + (0x02a3be00), + (0x90087e00), + (0x02e78600), + (0x904c4600), + (0x02629e00), + (0x90c95e00), + (0x0226a600), + (0x908d6600)}, + {(0x3f800000), + (0x3fc955e0), + (0x3f80221c), + (0x3fc977fc), + (0x3f806090), + (0x3fc93570), + (0x3f80428c), + (0x3fc9176c), + (0x3f8151df), + (0x3fc8043f), + (0x3f8173c3), + (0x3fc82623), + (0x3f81314f), + (0x3fc864af), + (0x3f811353), + (0x3fc846b3)}, + (0xfff80000), + {0xb0,0x87,0xce,0x22,0xcb,0xa4,0x10,0xdc,0xdb,0x3e, + 0x3c,0x67,0xae,0x3f,0xc0,0x11,0xf3,0xec,0xe2,0x06,0x00} + }, + { + /* No.184 delta:1092 weight:1295 */ + 11213, + 91, + 17, + 8, + {(0x00000000), + (0x2fa2608e), + (0x8f680761), + (0xa0ca67ef), + (0x13a00b8a), + (0x3c026b04), + (0x9cc80ceb), + (0xb36a6c65), + (0x00007f70), + (0x2fa21ffe), + (0x8f687811), + (0xa0ca189f), + (0x13a074fa), + (0x3c021474), + (0x9cc8739b), + (0xb36a1315)}, + {(0x00000000), + (0x089d6000), + (0x1a00e200), + (0x129d8200), + (0x40df4000), + (0x48422000), + (0x5adfa200), + (0x5242c200), + (0x01a6de00), + (0x093bbe00), + (0x1ba63c00), + (0x133b5c00), + (0x41799e00), + (0x49e4fe00), + (0x5b797c00), + (0x53e41c00)}, + {(0x3f800000), + (0x3f844eb0), + (0x3f8d0071), + (0x3f894ec1), + (0x3fa06fa0), + (0x3fa42110), + (0x3fad6fd1), + (0x3fa92161), + (0x3f80d36f), + (0x3f849ddf), + (0x3f8dd31e), + (0x3f899dae), + (0x3fa0bccf), + (0x3fa4f27f), + (0x3fadbcbe), + (0x3fa9f20e)}, + (0xfff80000), + {0xbd,0xb1,0x02,0x3f,0x46,0x65,0xe7,0x62,0xbf,0x9e, + 0x12,0xaa,0x33,0xbe,0x0c,0x5d,0x89,0x02,0x2c,0x11,0x00} + }, + { + /* No.185 delta:8146 weight:1071 */ + 11213, + 66, + 28, + 1, + {(0x00000000), + (0xc3e3a60c), + (0x80c000cd), + (0x4323a6c1), + (0xda800b97), + (0x1963ad9b), + (0x5a400b5a), + (0x99a3ad56), + (0x000058ad), + (0xc3e3fea1), + (0x80c05860), + (0x4323fe6c), + (0xda80533a), + (0x1963f536), + (0x5a4053f7), + (0x99a3f5fb)}, + {(0x00000000), + (0x89d10a00), + (0x403c0200), + (0xc9ed0800), + (0x53520000), + (0xda830a00), + (0x136e0200), + (0x9abf0800), + (0x61609e00), + (0xe8b19400), + (0x215c9c00), + (0xa88d9600), + (0x32329e00), + (0xbbe39400), + (0x720e9c00), + (0xfbdf9600)}, + {(0x3f800000), + (0x3fc4e885), + (0x3fa01e01), + (0x3fe4f684), + (0x3fa9a900), + (0x3fed4185), + (0x3f89b701), + (0x3fcd5f84), + (0x3fb0b04f), + (0x3ff458ca), + (0x3f90ae4e), + (0x3fd446cb), + (0x3f99194f), + (0x3fddf1ca), + (0x3fb9074e), + (0x3ffdefcb)}, + (0xfff80000), + {0xf7,0x3c,0x9c,0x40,0x28,0xb5,0xbe,0xbf,0x2e,0x97, + 0xa1,0x61,0x3b,0x82,0x2a,0x82,0x3c,0xa0,0xf4,0x90,0x00} + }, + { + /* No.186 delta:2697 weight:1957 */ + 11213, + 43, + 3, + 3, + {(0x00000000), + (0x7a0a48fc), + (0x29a53edd), + (0x53af7621), + (0x08f00ba0), + (0x72fa435c), + (0x2155357d), + (0x5b5f7d81), + (0x0000132f), + (0x7a0a5bd3), + (0x29a52df2), + (0x53af650e), + (0x08f0188f), + (0x72fa5073), + (0x21552652), + (0x5b5f6eae)}, + {(0x00000000), + (0xa2021000), + (0x1c21a000), + (0xbe23b000), + (0x00408000), + (0xa2429000), + (0x1c612000), + (0xbe633000), + (0x40201e00), + (0xe2220e00), + (0x5c01be00), + (0xfe03ae00), + (0x40609e00), + (0xe2628e00), + (0x5c413e00), + (0xfe432e00)}, + {(0x3f800000), + (0x3fd10108), + (0x3f8e10d0), + (0x3fdf11d8), + (0x3f802040), + (0x3fd12148), + (0x3f8e3090), + (0x3fdf3198), + (0x3fa0100f), + (0x3ff11107), + (0x3fae00df), + (0x3fff01d7), + (0x3fa0304f), + (0x3ff13147), + (0x3fae209f), + (0x3fff2197)}, + (0xfff80000), + {0x1a,0x79,0x8f,0xb2,0xec,0xc2,0xee,0xfc,0x66,0xa6, + 0x37,0x12,0x4d,0x78,0x6e,0xa1,0xb0,0x60,0x86,0x37,0x00} + }, + { + /* No.187 delta:2420 weight:1355 */ + 11213, + 28, + 24, + 3, + {(0x00000000), + (0x9580742c), + (0xce45a063), + (0x5bc5d44f), + (0x33f00bbf), + (0xa6707f93), + (0xfdb5abdc), + (0x6835dff0), + (0x000009ba), + (0x95807d96), + (0xce45a9d9), + (0x5bc5ddf5), + (0x33f00205), + (0xa6707629), + (0xfdb5a266), + (0x6835d64a)}, + {(0x00000000), + (0x40bf0200), + (0x00440200), + (0x40fb0000), + (0x3411d000), + (0x74aed200), + (0x3455d200), + (0x74ead000), + (0x9082de00), + (0xd03ddc00), + (0x90c6dc00), + (0xd079de00), + (0xa4930e00), + (0xe42c0c00), + (0xa4d70c00), + (0xe4680e00)}, + {(0x3f800000), + (0x3fa05f81), + (0x3f802201), + (0x3fa07d80), + (0x3f9a08e8), + (0x3fba5769), + (0x3f9a2ae9), + (0x3fba7568), + (0x3fc8416f), + (0x3fe81eee), + (0x3fc8636e), + (0x3fe83cef), + (0x3fd24987), + (0x3ff21606), + (0x3fd26b86), + (0x3ff23407)}, + (0xfff80000), + {0x20,0xe4,0x7d,0x6c,0xc4,0xf9,0x2b,0x4a,0x56,0x18, + 0x64,0xa0,0x86,0x2c,0x45,0x4a,0x42,0x3a,0x22,0x49,0x00} + }, + { + /* No.188 delta:1841 weight:735 */ + 11213, + 62, + 10, + 18, + {(0x00000000), + (0x179a1ef2), + (0x535f148e), + (0x44c50a7c), + (0x33700bc3), + (0x24ea1531), + (0x602f1f4d), + (0x77b501bf), + (0x0000df3e), + (0x179ac1cc), + (0x535fcbb0), + (0x44c5d542), + (0x3370d4fd), + (0x24eaca0f), + (0x602fc073), + (0x77b5de81)}, + {(0x00000000), + (0x30b90000), + (0x083c0000), + (0x38850000), + (0x40070000), + (0x70be0000), + (0x483b0000), + (0x78820000), + (0x10651e00), + (0x20dc1e00), + (0x18591e00), + (0x28e01e00), + (0x50621e00), + (0x60db1e00), + (0x585e1e00), + (0x68e71e00)}, + {(0x3f800000), + (0x3f985c80), + (0x3f841e00), + (0x3f9c4280), + (0x3fa00380), + (0x3fb85f00), + (0x3fa41d80), + (0x3fbc4100), + (0x3f88328f), + (0x3f906e0f), + (0x3f8c2c8f), + (0x3f94700f), + (0x3fa8310f), + (0x3fb06d8f), + (0x3fac2f0f), + (0x3fb4738f)}, + (0xfff80000), + {0x09,0x19,0x78,0xe9,0x81,0xea,0xdf,0x95,0x46,0x6b, + 0x4f,0xa1,0xca,0x2b,0xbc,0x8a,0x0b,0xaa,0x44,0xb8,0x00} + }, + { + /* No.189 delta:3318 weight:1469 */ + 11213, + 81, + 3, + 7, + {(0x00000000), + (0xfe728280), + (0xcc048331), + (0x327601b1), + (0x42200bd8), + (0xbc528958), + (0x8e2488e9), + (0x70560a69), + (0x0000d1a0), + (0xfe725320), + (0xcc045291), + (0x3276d011), + (0x4220da78), + (0xbc5258f8), + (0x8e245949), + (0x7056dbc9)}, + {(0x00000000), + (0x12010000), + (0x53002000), + (0x41012000), + (0x20414000), + (0x32404000), + (0x73416000), + (0x61406000), + (0x20321e00), + (0x32331e00), + (0x73323e00), + (0x61333e00), + (0x00735e00), + (0x12725e00), + (0x53737e00), + (0x41727e00)}, + {(0x3f800000), + (0x3f890080), + (0x3fa98010), + (0x3fa08090), + (0x3f9020a0), + (0x3f992020), + (0x3fb9a0b0), + (0x3fb0a030), + (0x3f90190f), + (0x3f99198f), + (0x3fb9991f), + (0x3fb0999f), + (0x3f8039af), + (0x3f89392f), + (0x3fa9b9bf), + (0x3fa0b93f)}, + (0xfff80000), + {0x0f,0xe8,0x93,0xf4,0x0e,0x7e,0xaf,0xe0,0x5d,0x20, + 0x58,0x92,0x06,0x7d,0x5b,0x05,0x6b,0x8a,0x33,0xbb,0x00} + }, + { + /* No.190 delta:1194 weight:821 */ + 11213, + 72, + 11, + 16, + {(0x00000000), + (0x44a385c2), + (0xca99870f), + (0x8e3a02cd), + (0x06c00be8), + (0x42638e2a), + (0xcc598ce7), + (0x88fa0925), + (0x00007bbf), + (0x44a3fe7d), + (0xca99fcb0), + (0x8e3a7972), + (0x06c07057), + (0x4263f595), + (0xcc59f758), + (0x88fa729a)}, + {(0x00000000), + (0x00527800), + (0x302f0400), + (0x307d7c00), + (0x20017000), + (0x20530800), + (0x102e7400), + (0x107c0c00), + (0x10429e00), + (0x1010e600), + (0x206d9a00), + (0x203fe200), + (0x3043ee00), + (0x30119600), + (0x006cea00), + (0x003e9200)}, + {(0x3f800000), + (0x3f80293c), + (0x3f981782), + (0x3f983ebe), + (0x3f9000b8), + (0x3f902984), + (0x3f88173a), + (0x3f883e06), + (0x3f88214f), + (0x3f880873), + (0x3f9036cd), + (0x3f901ff1), + (0x3f9821f7), + (0x3f9808cb), + (0x3f803675), + (0x3f801f49)}, + (0xfff80000), + {0xba,0xb7,0xd5,0xc8,0xec,0x6d,0xc1,0x0c,0x19,0x38, + 0x0f,0x27,0x93,0x3b,0xd8,0x74,0xa1,0x4e,0x45,0x89,0x00} + }, + { + /* No.191 delta:1166 weight:1045 */ + 11213, + 40, + 11, + 9, + {(0x00000000), + (0x212f4af4), + (0xf0432caf), + (0xd16c665b), + (0x11d00bf5), + (0x30ff4101), + (0xe193275a), + (0xc0bc6dae), + (0x0000755f), + (0x212f3fab), + (0xf04359f0), + (0xd16c1304), + (0x11d07eaa), + (0x30ff345e), + (0xe1935205), + (0xc0bc18f1)}, + {(0x00000000), + (0x08528000), + (0x70084000), + (0x785ac000), + (0x00196000), + (0x084be000), + (0x70112000), + (0x7843a000), + (0x0024fe00), + (0x08767e00), + (0x702cbe00), + (0x787e3e00), + (0x003d9e00), + (0x086f1e00), + (0x7035de00), + (0x78675e00)}, + {(0x3f800000), + (0x3f842940), + (0x3fb80420), + (0x3fbc2d60), + (0x3f800cb0), + (0x3f8425f0), + (0x3fb80890), + (0x3fbc21d0), + (0x3f80127f), + (0x3f843b3f), + (0x3fb8165f), + (0x3fbc3f1f), + (0x3f801ecf), + (0x3f84378f), + (0x3fb81aef), + (0x3fbc33af)}, + (0xfff80000), + {0xbf,0xbb,0x3f,0x17,0x6e,0x1a,0x3b,0x45,0x9b,0x2a, + 0x22,0x6a,0xf9,0xf5,0xba,0x97,0x3b,0x8a,0xec,0xd6,0x00} + }, + { + /* No.192 delta:4742 weight:1471 */ + 11213, + 27, + 4, + 6, + {(0x00000000), + (0x7fe173b6), + (0x51169f27), + (0x2ef7ec91), + (0x0a300c00), + (0x75d17fb6), + (0x5b269327), + (0x24c7e091), + (0x00001d00), + (0x7fe16eb6), + (0x51168227), + (0x2ef7f191), + (0x0a301100), + (0x75d162b6), + (0x5b268e27), + (0x24c7fd91)}, + {(0x00000000), + (0x41420000), + (0x00010000), + (0x41430000), + (0x29040000), + (0x68460000), + (0x29050000), + (0x68470000), + (0x00009e00), + (0x41429e00), + (0x00019e00), + (0x41439e00), + (0x29049e00), + (0x68469e00), + (0x29059e00), + (0x68479e00)}, + {(0x3f800000), + (0x3fa0a100), + (0x3f800080), + (0x3fa0a180), + (0x3f948200), + (0x3fb42300), + (0x3f948280), + (0x3fb42380), + (0x3f80004f), + (0x3fa0a14f), + (0x3f8000cf), + (0x3fa0a1cf), + (0x3f94824f), + (0x3fb4234f), + (0x3f9482cf), + (0x3fb423cf)}, + (0xfff80000), + {0xb4,0x7f,0x09,0x23,0xa8,0x3f,0x5e,0x9d,0x3e,0x97, + 0x19,0x94,0x35,0x0d,0xdb,0x3e,0xb7,0x43,0x15,0xd0,0x00} + }, + { + /* No.193 delta:3962 weight:1171 */ + 11213, + 92, + 2, + 13, + {(0x00000000), + (0x76b1ced9), + (0x928504d8), + (0xe434ca01), + (0x7b300c1a), + (0x0d81c2c3), + (0xe9b508c2), + (0x9f04c61b), + (0x0000b2d9), + (0x76b17c00), + (0x9285b601), + (0xe43478d8), + (0x7b30bec3), + (0x0d81701a), + (0xe9b5ba1b), + (0x9f0474c2)}, + {(0x00000000), + (0x08400000), + (0x06400000), + (0x0e000000), + (0x01200000), + (0x09600000), + (0x07600000), + (0x0f200000), + (0x04c01e00), + (0x0c801e00), + (0x02801e00), + (0x0ac01e00), + (0x05e01e00), + (0x0da01e00), + (0x03a01e00), + (0x0be01e00)}, + {(0x3f800000), + (0x3f842000), + (0x3f832000), + (0x3f870000), + (0x3f809000), + (0x3f84b000), + (0x3f83b000), + (0x3f879000), + (0x3f82600f), + (0x3f86400f), + (0x3f81400f), + (0x3f85600f), + (0x3f82f00f), + (0x3f86d00f), + (0x3f81d00f), + (0x3f85f00f)}, + (0xfff80000), + {0xdf,0x8e,0xab,0x00,0xdb,0xdc,0xe0,0x7a,0xb0,0x4c, + 0x05,0x23,0x25,0x58,0x15,0xac,0x74,0x97,0x22,0x21,0x00} + }, + { + /* No.194 delta:2215 weight:1499 */ + 11213, + 63, + 26, + 4, + {(0x00000000), + (0xad5d413b), + (0x166ef61d), + (0xbb33b726), + (0x9e000c20), + (0x335d4d1b), + (0x886efa3d), + (0x2533bb06), + (0x000077be), + (0xad5d3685), + (0x166e81a3), + (0xbb33c098), + (0x9e007b9e), + (0x335d3aa5), + (0x886e8d83), + (0x2533ccb8)}, + {(0x00000000), + (0x10720800), + (0x60810000), + (0x70f30800), + (0x300c0000), + (0x207e0800), + (0x508d0000), + (0x40ff0800), + (0x20023e00), + (0x30703600), + (0x40833e00), + (0x50f13600), + (0x100e3e00), + (0x007c3600), + (0x708f3e00), + (0x60fd3600)}, + {(0x3f800000), + (0x3f883904), + (0x3fb04080), + (0x3fb87984), + (0x3f980600), + (0x3f903f04), + (0x3fa84680), + (0x3fa07f84), + (0x3f90011f), + (0x3f98381b), + (0x3fa0419f), + (0x3fa8789b), + (0x3f88071f), + (0x3f803e1b), + (0x3fb8479f), + (0x3fb07e9b)}, + (0xfff80000), + {0x31,0xb8,0x64,0x9a,0xae,0xad,0xc8,0xf8,0x53,0x9b, + 0x64,0x2d,0x8c,0xb0,0xd2,0xa7,0x8e,0x2e,0xb2,0xc8,0x00} + }, + { + /* No.195 delta:1215 weight:463 */ + 11213, + 60, + 13, + 19, + {(0x00000000), + (0x60520e47), + (0xae8c1b90), + (0xcede15d7), + (0xc1c00c35), + (0xa1920272), + (0x6f4c17a5), + (0x0f1e19e2), + (0x0000fd60), + (0x6052f327), + (0xae8ce6f0), + (0xcedee8b7), + (0xc1c0f155), + (0xa192ff12), + (0x6f4ceac5), + (0x0f1ee482)}, + {(0x00000000), + (0x02e00000), + (0x10cd1200), + (0x122d1200), + (0x14101800), + (0x16f01800), + (0x04dd0a00), + (0x063d0a00), + (0x0057be00), + (0x02b7be00), + (0x109aac00), + (0x127aac00), + (0x1447a600), + (0x16a7a600), + (0x048ab400), + (0x066ab400)}, + {(0x3f800000), + (0x3f817000), + (0x3f886689), + (0x3f891689), + (0x3f8a080c), + (0x3f8b780c), + (0x3f826e85), + (0x3f831e85), + (0x3f802bdf), + (0x3f815bdf), + (0x3f884d56), + (0x3f893d56), + (0x3f8a23d3), + (0x3f8b53d3), + (0x3f82455a), + (0x3f83355a)}, + (0xfff80000), + {0x67,0xca,0xf4,0x9a,0x13,0x78,0x64,0xbc,0x60,0x6d, + 0x5b,0x5f,0x48,0x61,0x94,0x6f,0xdf,0x81,0x2c,0xe1,0x00} + }, + { + /* No.196 delta:939 weight:857 */ + 11213, + 51, + 11, + 2, + {(0x00000000), + (0xa61e8990), + (0x67d50999), + (0xc1cb8009), + (0xa3f00c49), + (0x05ee85d9), + (0xc42505d0), + (0x623b8c40), + (0x00000381), + (0xa61e8a11), + (0x67d50a18), + (0xc1cb8388), + (0xa3f00fc8), + (0x05ee8658), + (0xc4250651), + (0x623b8fc1)}, + {(0x00000000), + (0x08105000), + (0x0002b000), + (0x0812e000), + (0x90084c00), + (0x98181c00), + (0x900afc00), + (0x981aac00), + (0x01007e00), + (0x09102e00), + (0x0102ce00), + (0x09129e00), + (0x91083200), + (0x99186200), + (0x910a8200), + (0x991ad200)}, + {(0x3f800000), + (0x3f840828), + (0x3f800158), + (0x3f840970), + (0x3fc80426), + (0x3fcc0c0e), + (0x3fc8057e), + (0x3fcc0d56), + (0x3f80803f), + (0x3f848817), + (0x3f808167), + (0x3f84894f), + (0x3fc88419), + (0x3fcc8c31), + (0x3fc88541), + (0x3fcc8d69)}, + (0xfff80000), + {0x2c,0x79,0x20,0x40,0xe3,0x10,0xb7,0x11,0xcb,0xf4, + 0xba,0x4e,0xee,0x8b,0x5f,0x86,0xa9,0xdb,0x06,0x27,0x00} + }, + { + /* No.197 delta:1583 weight:1233 */ + 11213, + 26, + 20, + 8, + {(0x00000000), + (0x33fe7f24), + (0x88809fc9), + (0xbb7ee0ed), + (0x68600c55), + (0x5b9e7371), + (0xe0e0939c), + (0xd31eecb8), + (0x0000a12e), + (0x33fede0a), + (0x88803ee7), + (0xbb7e41c3), + (0x6860ad7b), + (0x5b9ed25f), + (0xe0e032b2), + (0xd31e4d96)}, + {(0x00000000), + (0x08750800), + (0x82099800), + (0x8a7c9000), + (0x40e2b000), + (0x4897b800), + (0xc2eb2800), + (0xca9e2000), + (0x004a5e00), + (0x083f5600), + (0x8243c600), + (0x8a36ce00), + (0x40a8ee00), + (0x48dde600), + (0xc2a17600), + (0xcad47e00)}, + {(0x3f800000), + (0x3f843a84), + (0x3fc104cc), + (0x3fc53e48), + (0x3fa07158), + (0x3fa44bdc), + (0x3fe17594), + (0x3fe54f10), + (0x3f80252f), + (0x3f841fab), + (0x3fc121e3), + (0x3fc51b67), + (0x3fa05477), + (0x3fa46ef3), + (0x3fe150bb), + (0x3fe56a3f)}, + (0xfff80000), + {0xb0,0x71,0x91,0x64,0xda,0x74,0xb8,0xc6,0x16,0x8c, + 0x5a,0x7e,0x26,0xea,0x75,0x3a,0x0b,0xa4,0xd9,0x97,0x00} + }, + { + /* No.198 delta:1565 weight:813 */ + 11213, + 89, + 7, + 10, + {(0x00000000), + (0x98a83f1e), + (0xcb779281), + (0x53dfad9f), + (0x20400c6a), + (0xb8e83374), + (0xeb379eeb), + (0x739fa1f5), + (0x000092fc), + (0x98a8ade2), + (0xcb77007d), + (0x53df3f63), + (0x20409e96), + (0xb8e8a188), + (0xeb370c17), + (0x739f3309)}, + {(0x00000000), + (0x467a0c00), + (0x04059800), + (0x427f9400), + (0x01093800), + (0x47733400), + (0x050ca000), + (0x4376ac00), + (0xc0e0fe00), + (0x869af200), + (0xc4e56600), + (0x829f6a00), + (0xc1e9c600), + (0x8793ca00), + (0xc5ec5e00), + (0x83965200)}, + {(0x3f800000), + (0x3fa33d06), + (0x3f8202cc), + (0x3fa13fca), + (0x3f80849c), + (0x3fa3b99a), + (0x3f828650), + (0x3fa1bb56), + (0x3fe0707f), + (0x3fc34d79), + (0x3fe272b3), + (0x3fc14fb5), + (0x3fe0f4e3), + (0x3fc3c9e5), + (0x3fe2f62f), + (0x3fc1cb29)}, + (0xfff80000), + {0x32,0x19,0xd6,0x71,0xe2,0x9d,0xf7,0x99,0x34,0xa0, + 0x5f,0x9a,0xcd,0x9f,0x42,0x5a,0x43,0x47,0xee,0xb2,0x00} + }, + { + /* No.199 delta:3921 weight:921 */ + 11213, + 49, + 3, + 15, + {(0x00000000), + (0xbb75ffa8), + (0xa0b33e2a), + (0x1bc6c182), + (0x9a200c78), + (0x2155f3d0), + (0x3a933252), + (0x81e6cdfa), + (0x000015a3), + (0xbb75ea0b), + (0xa0b32b89), + (0x1bc6d421), + (0x9a2019db), + (0x2155e673), + (0x3a9327f1), + (0x81e6d859)}, + {(0x00000000), + (0x45540800), + (0x07840400), + (0x42d00c00), + (0x08200000), + (0x4d740800), + (0x0fa40400), + (0x4af00c00), + (0x02201e00), + (0x47741600), + (0x05a41a00), + (0x40f01200), + (0x0a001e00), + (0x4f541600), + (0x0d841a00), + (0x48d01200)}, + {(0x3f800000), + (0x3fa2aa04), + (0x3f83c202), + (0x3fa16806), + (0x3f841000), + (0x3fa6ba04), + (0x3f87d202), + (0x3fa57806), + (0x3f81100f), + (0x3fa3ba0b), + (0x3f82d20d), + (0x3fa07809), + (0x3f85000f), + (0x3fa7aa0b), + (0x3f86c20d), + (0x3fa46809)}, + (0xfff80000), + {0x86,0x1e,0x5b,0xa8,0x8e,0x65,0x6f,0xc0,0xbc,0x92, + 0x81,0x1c,0x6d,0xbd,0x0f,0xd4,0x7e,0x57,0x5f,0x75,0x00} + } +}; + +#endif + + diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_normal.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_normal.h new file mode 100644 index 0000000000000000000000000000000000000000..e3c91001032acf253959df8b8a5464d038ee252b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_normal.h @@ -0,0 +1,840 @@ + + /* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + + +#if !defined(CURAND_NORMAL_H_) +#define CURAND_NORMAL_H_ + +/** + * \defgroup DEVICE Device API + * + * @{ + */ + +#ifndef __CUDACC_RTC__ +#include +#endif // __CUDACC_RTC__ +#include + +#include "curand_mrg32k3a.h" +#include "curand_mtgp32_kernel.h" +#include "curand_philox4x32_x.h" +#include "curand_normal_static.h" + +QUALIFIERS float2 _curand_box_muller(unsigned int x, unsigned int y) +{ + float2 result; + float u = x * CURAND_2POW32_INV + (CURAND_2POW32_INV/2); + float v = y * CURAND_2POW32_INV_2PI + (CURAND_2POW32_INV_2PI/2); + float s; +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + s = sqrtf(-2.0f * logf(u)); + __sincosf(v, &result.x, &result.y); +, + s = sqrtf(-2.0f * logf(u)); + result.x = sinf(v); + result.y = cosf(v); +) + result.x *= s; + result.y *= s; + return result; +} + +QUALIFIERS float2 curand_box_muller_mrg(curandStateMRG32k3a_t * state) +{ + float x, y; + x = curand_uniform(state); + y = curand_uniform(state) * CURAND_2PI; + float2 result; + float s; +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + s = sqrtf(-2.0f * logf(x)); + __sincosf(y, &result.x, &result.y); +, + s = sqrtf(-2.0f * logf(x)); + result.x = sinf(y); + result.y = cosf(y); +) + result.x *= s; + result.y *= s; + return result; +} + +QUALIFIERS double2 +_curand_box_muller_double(unsigned int x0, unsigned int x1, + unsigned int y0, unsigned int y1) +{ + double2 result; + unsigned long long zx = (unsigned long long)x0 ^ + ((unsigned long long)x1 << (53 - 32)); + double u = zx * CURAND_2POW53_INV_DOUBLE + (CURAND_2POW53_INV_DOUBLE/2.0); + unsigned long long zy = (unsigned long long)y0 ^ + ((unsigned long long)y1 << (53 - 32)); + double v = zy * (CURAND_2POW53_INV_DOUBLE*2.0) + CURAND_2POW53_INV_DOUBLE; + double s = sqrt(-2.0 * log(u)); + +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + sincospi(v, &result.x, &result.y); +, + result.x = sin(v*CURAND_PI_DOUBLE); + result.y = cos(v*CURAND_PI_DOUBLE); +) + result.x *= s; + result.y *= s; + + return result; +} + +QUALIFIERS double2 +curand_box_muller_mrg_double(curandStateMRG32k3a_t * state) +{ + double x, y; + double2 result; + x = curand_uniform_double(state); + y = curand_uniform_double(state) * 2.0; + + double s = sqrt(-2.0 * log(x)); +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + sincospi(y, &result.x, &result.y); +, + result.x = sin(y*CURAND_PI_DOUBLE); + result.y = cos(y*CURAND_PI_DOUBLE); +) + result.x *= s; + result.y *= s; + return result; +} + +template +QUALIFIERS float2 curand_box_muller(R *state) +{ + float2 result; + unsigned int x = curand(state); + unsigned int y = curand(state); + result = _curand_box_muller(x, y); + return result; +} + +template +QUALIFIERS float4 curand_box_muller4(R *state) +{ + float4 result; + float2 _result; + uint4 x = curand4(state); + //unsigned int y = curand(state); + _result = _curand_box_muller(x.x, x.y); + result.x = _result.x; + result.y = _result.y; + _result = _curand_box_muller(x.z, x.w); + result.z = _result.x; + result.w = _result.y; + return result; +} + +template +QUALIFIERS double2 curand_box_muller_double(R *state) +{ + double2 result; + unsigned int x0 = curand(state); + unsigned int x1 = curand(state); + unsigned int y0 = curand(state); + unsigned int y1 = curand(state); + result = _curand_box_muller_double(x0, x1, y0, y1); + return result; +} + +template +QUALIFIERS double2 curand_box_muller2_double(R *state) +{ + double2 result; + uint4 _x; + _x = curand4(state); + result = _curand_box_muller_double(_x.x, _x.y, _x.z, _x.w); + return result; +} + + +template +QUALIFIERS double4 curand_box_muller4_double(R *state) +{ + double4 result; + double2 _res1; + double2 _res2; + uint4 _x; + uint4 _y; + _x = curand4(state); + _y = curand4(state); + _res1 = _curand_box_muller_double(_x.x, _x.y, _x.z, _x.w); + _res2 = _curand_box_muller_double(_y.x, _y.y, _y.z, _y.w); + result.x = _res1.x; + result.y = _res1.y; + result.z = _res2.x; + result.w = _res2.y; + return result; +} + +//QUALIFIERS float _curand_normal_icdf(unsigned int x) +//{ +//#if __CUDA_ARCH__ > 0 || defined(HOST_HAVE_ERFCINVF) +// float s = CURAND_SQRT2; +// // Mirror to avoid loss of precision +// if(x > 0x80000000UL) { +// x = 0xffffffffUL - x; +// s = -s; +// } +// float p = x * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); +// // p is in (0, 0.5], 2p is in (0, 1] +// return s * erfcinvf(2.0f * p); +//#else +// x++; //suppress warnings +// return 0.0f; +//#endif +//} +// +//QUALIFIERS float _curand_normal_icdf(unsigned long long x) +//{ +//#if __CUDA_ARCH__ > 0 || defined(HOST_HAVE_ERFCINVF) +// unsigned int t = (unsigned int)(x >> 32); +// float s = CURAND_SQRT2; +// // Mirror to avoid loss of precision +// if(t > 0x80000000UL) { +// t = 0xffffffffUL - t; +// s = -s; +// } +// float p = t * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); +// // p is in (0, 0.5], 2p is in (0, 1] +// return s * erfcinvf(2.0f * p); +//#else +// x++; +// return 0.0f; +//#endif +//} +// +//QUALIFIERS double _curand_normal_icdf_double(unsigned int x) +//{ +//#if __CUDA_ARCH__ > 0 || defined(HOST_HAVE_ERFCINVF) +// double s = CURAND_SQRT2_DOUBLE; +// // Mirror to avoid loss of precision +// if(x > 0x80000000UL) { +// x = 0xffffffffUL - x; +// s = -s; +// } +// double p = x * CURAND_2POW32_INV_DOUBLE + (CURAND_2POW32_INV_DOUBLE/2.0); +// // p is in (0, 0.5], 2p is in (0, 1] +// return s * erfcinv(2.0 * p); +//#else +// x++; +// return 0.0; +//#endif +//} +// +//QUALIFIERS double _curand_normal_icdf_double(unsigned long long x) +//{ +//#if __CUDA_ARCH__ > 0 || defined(HOST_HAVE_ERFCINVF) +// double s = CURAND_SQRT2_DOUBLE; +// x >>= 11; +// // Mirror to avoid loss of precision +// if(x > 0x10000000000000UL) { +// x = 0x1fffffffffffffUL - x; +// s = -s; +// } +// double p = x * CURAND_2POW53_INV_DOUBLE + (CURAND_2POW53_INV_DOUBLE/2.0); +// // p is in (0, 0.5], 2p is in (0, 1] +// return s * erfcinv(2.0 * p); +//#else +// x++; +// return 0.0; +//#endif +//} +// + +/** + * \brief Return a normally distributed float from an XORWOW generator. + * + * Return a single normally distributed float with mean \p 0.0f and + * standard deviation \p 1.0f from the XORWOW generator in \p state, + * increment position of generator by one. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then returns them one at a time. + * See ::curand_normal2() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float curand_normal(curandStateXORWOW_t *state) +{ + if(state->boxmuller_flag != EXTRA_FLAG_NORMAL) { + unsigned int x, y; + x = curand(state); + y = curand(state); + float2 v = _curand_box_muller(x, y); + state->boxmuller_extra = v.y; + state->boxmuller_flag = EXTRA_FLAG_NORMAL; + return v.x; + } + state->boxmuller_flag = 0; + return state->boxmuller_extra; +} + +/** + * \brief Return a normally distributed float from an Philox4_32_10 generator. + * + * Return a single normally distributed float with mean \p 0.0f and + * standard deviation \p 1.0f from the Philox4_32_10 generator in \p state, + * increment position of generator by one. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then returns them one at a time. + * See ::curand_normal2() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float with mean \p 0.0f and standard deviation \p 1.0f + */ + +QUALIFIERS float curand_normal(curandStatePhilox4_32_10_t *state) +{ + if(state->boxmuller_flag != EXTRA_FLAG_NORMAL) { + unsigned int x, y; + x = curand(state); + y = curand(state); + float2 v = _curand_box_muller(x, y); + state->boxmuller_extra = v.y; + state->boxmuller_flag = EXTRA_FLAG_NORMAL; + return v.x; + } + state->boxmuller_flag = 0; + return state->boxmuller_extra; +} + + + +/** + * \brief Return a normally distributed float from an MRG32k3a generator. + * + * Return a single normally distributed float with mean \p 0.0f and + * standard deviation \p 1.0f from the MRG32k3a generator in \p state, + * increment position of generator by one. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then returns them one at a time. + * See ::curand_normal2() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float curand_normal(curandStateMRG32k3a_t *state) +{ + if(state->boxmuller_flag != EXTRA_FLAG_NORMAL) { + float2 v = curand_box_muller_mrg(state); + state->boxmuller_extra = v.y; + state->boxmuller_flag = EXTRA_FLAG_NORMAL; + return v.x; + } + state->boxmuller_flag = 0; + return state->boxmuller_extra; +} + +/** + * \brief Return two normally distributed floats from an XORWOW generator. + * + * Return two normally distributed floats with mean \p 0.0f and + * standard deviation \p 1.0f from the XORWOW generator in \p state, + * increment position of generator by two. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float2 where each element is from a + * distribution with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float2 curand_normal2(curandStateXORWOW_t *state) +{ + return curand_box_muller(state); +} +/** + * \brief Return two normally distributed floats from an Philox4_32_10 generator. + * + * Return two normally distributed floats with mean \p 0.0f and + * standard deviation \p 1.0f from the Philox4_32_10 generator in \p state, + * increment position of generator by two. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float2 where each element is from a + * distribution with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float2 curand_normal2(curandStatePhilox4_32_10_t *state) +{ + return curand_box_muller(state); +} + +/** + * \brief Return four normally distributed floats from an Philox4_32_10 generator. + * + * Return four normally distributed floats with mean \p 0.0f and + * standard deviation \p 1.0f from the Philox4_32_10 generator in \p state, + * increment position of generator by four. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float2 where each element is from a + * distribution with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float4 curand_normal4(curandStatePhilox4_32_10_t *state) +{ + return curand_box_muller4(state); +} + + + +/** + * \brief Return two normally distributed floats from an MRG32k3a generator. + * + * Return two normally distributed floats with mean \p 0.0f and + * standard deviation \p 1.0f from the MRG32k3a generator in \p state, + * increment position of generator by two. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float2 where each element is from a + * distribution with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float2 curand_normal2(curandStateMRG32k3a_t *state) +{ + return curand_box_muller_mrg(state); +} + +/** + * \brief Return a normally distributed float from a MTGP32 generator. + * + * Return a single normally distributed float with mean \p 0.0f and + * standard deviation \p 1.0f from the MTGP32 generator in \p state, + * increment position of generator. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float curand_normal(curandStateMtgp32_t *state) +{ + return _curand_normal_icdf(curand(state)); +} +/** + * \brief Return a normally distributed float from a Sobol32 generator. + * + * Return a single normally distributed float with mean \p 0.0f and + * standard deviation \p 1.0f from the Sobol32 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float curand_normal(curandStateSobol32_t *state) +{ + return _curand_normal_icdf(curand(state)); +} + +/** + * \brief Return a normally distributed float from a scrambled Sobol32 generator. + * + * Return a single normally distributed float with mean \p 0.0f and + * standard deviation \p 1.0f from the scrambled Sobol32 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float curand_normal(curandStateScrambledSobol32_t *state) +{ + return _curand_normal_icdf(curand(state)); +} + +/** + * \brief Return a normally distributed float from a Sobol64 generator. + * + * Return a single normally distributed float with mean \p 0.0f and + * standard deviation \p 1.0f from the Sobol64 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float curand_normal(curandStateSobol64_t *state) +{ + return _curand_normal_icdf(curand(state)); +} + +/** + * \brief Return a normally distributed float from a scrambled Sobol64 generator. + * + * Return a single normally distributed float with mean \p 0.0f and + * standard deviation \p 1.0f from the scrambled Sobol64 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed float with mean \p 0.0f and standard deviation \p 1.0f + */ +QUALIFIERS float curand_normal(curandStateScrambledSobol64_t *state) +{ + return _curand_normal_icdf(curand(state)); +} + +/** + * \brief Return a normally distributed double from an XORWOW generator. + * + * Return a single normally distributed double with mean \p 0.0 and + * standard deviation \p 1.0 from the XORWOW generator in \p state, + * increment position of generator. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then returns them one at a time. + * See ::curand_normal2_double() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double curand_normal_double(curandStateXORWOW_t *state) +{ + if(state->boxmuller_flag_double != EXTRA_FLAG_NORMAL) { + unsigned int x0, x1, y0, y1; + x0 = curand(state); + x1 = curand(state); + y0 = curand(state); + y1 = curand(state); + double2 v = _curand_box_muller_double(x0, x1, y0, y1); + state->boxmuller_extra_double = v.y; + state->boxmuller_flag_double = EXTRA_FLAG_NORMAL; + return v.x; + } + state->boxmuller_flag_double = 0; + return state->boxmuller_extra_double; +} + +/** + * \brief Return a normally distributed double from an Philox4_32_10 generator. + * + * Return a single normally distributed double with mean \p 0.0 and + * standard deviation \p 1.0 from the Philox4_32_10 generator in \p state, + * increment position of generator. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then returns them one at a time. + * See ::curand_normal2_double() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double with mean \p 0.0 and standard deviation \p 1.0 + */ + +QUALIFIERS double curand_normal_double(curandStatePhilox4_32_10_t *state) +{ + if(state->boxmuller_flag_double != EXTRA_FLAG_NORMAL) { + uint4 _x; + _x = curand4(state); + double2 v = _curand_box_muller_double(_x.x, _x.y, _x.z, _x.w); + state->boxmuller_extra_double = v.y; + state->boxmuller_flag_double = EXTRA_FLAG_NORMAL; + return v.x; + } + state->boxmuller_flag_double = 0; + return state->boxmuller_extra_double; +} + + +/** + * \brief Return a normally distributed double from an MRG32k3a generator. + * + * Return a single normally distributed double with mean \p 0.0 and + * standard deviation \p 1.0 from the XORWOW generator in \p state, + * increment position of generator. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results, then returns them one at a time. + * See ::curand_normal2_double() for a more efficient version that returns + * both results at once. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double curand_normal_double(curandStateMRG32k3a_t *state) +{ + if(state->boxmuller_flag_double != EXTRA_FLAG_NORMAL) { + double2 v = curand_box_muller_mrg_double(state); + state->boxmuller_extra_double = v.y; + state->boxmuller_flag_double = EXTRA_FLAG_NORMAL; + return v.x; + } + state->boxmuller_flag_double = 0; + return state->boxmuller_extra_double; +} + +/** + * \brief Return two normally distributed doubles from an XORWOW generator. + * + * Return two normally distributed doubles with mean \p 0.0 and + * standard deviation \p 1.0 from the XORWOW generator in \p state, + * increment position of generator by 2. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double2 where each element is from a + * distribution with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double2 curand_normal2_double(curandStateXORWOW_t *state) +{ + return curand_box_muller_double(state); +} + +/** + * \brief Return two normally distributed doubles from an Philox4_32_10 generator. + * + * Return two normally distributed doubles with mean \p 0.0 and + * standard deviation \p 1.0 from the Philox4_32_10 generator in \p state, + * increment position of generator by 2. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double2 where each element is from a + * distribution with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double2 curand_normal2_double(curandStatePhilox4_32_10_t *state) +{ + uint4 _x; + double2 result; + + _x = curand4(state); + double2 v1 = _curand_box_muller_double(_x.x, _x.y, _x.z, _x.w); + result.x = v1.x; + result.y = v1.y; + + return result; +} + + // not a part of API +QUALIFIERS double4 curand_normal4_double(curandStatePhilox4_32_10_t *state) +{ + uint4 _x; + uint4 _y; + double4 result; + + _x = curand4(state); + _y = curand4(state); + double2 v1 = _curand_box_muller_double(_x.x, _x.y, _x.z, _x.w); + double2 v2 = _curand_box_muller_double(_y.x, _y.y, _y.z, _y.w); + result.x = v1.x; + result.y = v1.y; + result.z = v2.x; + result.w = v2.y; + + return result; +} + + +/** + * \brief Return two normally distributed doubles from an MRG32k3a generator. + * + * Return two normally distributed doubles with mean \p 0.0 and + * standard deviation \p 1.0 from the MRG32k3a generator in \p state, + * increment position of generator. + * + * The implementation uses a Box-Muller transform to generate two + * normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double2 where each element is from a + * distribution with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double2 curand_normal2_double(curandStateMRG32k3a_t *state) +{ + return curand_box_muller_mrg_double(state); +} + +/** + * \brief Return a normally distributed double from an MTGP32 generator. + * + * Return a single normally distributed double with mean \p 0.0 and + * standard deviation \p 1.0 from the MTGP32 generator in \p state, + * increment position of generator. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double curand_normal_double(curandStateMtgp32_t *state) +{ + return _curand_normal_icdf_double(curand(state)); +} + +/** + * \brief Return a normally distributed double from an Sobol32 generator. + * + * Return a single normally distributed double with mean \p 0.0 and + * standard deviation \p 1.0 from the Sobol32 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double curand_normal_double(curandStateSobol32_t *state) +{ + return _curand_normal_icdf_double(curand(state)); +} + +/** + * \brief Return a normally distributed double from a scrambled Sobol32 generator. + * + * Return a single normally distributed double with mean \p 0.0 and + * standard deviation \p 1.0 from the scrambled Sobol32 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double curand_normal_double(curandStateScrambledSobol32_t *state) +{ + return _curand_normal_icdf_double(curand(state)); +} + +/** + * \brief Return a normally distributed double from a Sobol64 generator. + * + * Return a single normally distributed double with mean \p 0.0 and + * standard deviation \p 1.0 from the Sobol64 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double curand_normal_double(curandStateSobol64_t *state) +{ + return _curand_normal_icdf_double(curand(state)); +} + +/** + * \brief Return a normally distributed double from a scrambled Sobol64 generator. + * + * Return a single normally distributed double with mean \p 0.0 and + * standard deviation \p 1.0 from the scrambled Sobol64 generator in \p state, + * increment position of generator by one. + * + * The implementation uses the inverse cumulative distribution function + * to generate normally distributed results. + * + * \param state - Pointer to state to update + * + * \return Normally distributed double with mean \p 0.0 and standard deviation \p 1.0 + */ +QUALIFIERS double curand_normal_double(curandStateScrambledSobol64_t *state) +{ + return _curand_normal_icdf_double(curand(state)); +} +#endif // !defined(CURAND_NORMAL_H_) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_normal_static.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_normal_static.h new file mode 100644 index 0000000000000000000000000000000000000000..f731101c22504b9cb68c1c5694d6087bc66df18a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_normal_static.h @@ -0,0 +1,134 @@ + /* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ +#ifndef CURAND_NORMAL_STATIC_H +#define CURAND_NORMAL_STATIC_H + +#define QUALIFIERS_STATIC __host__ __device__ __forceinline__ + +#include +#if defined(HOST_HAVE_ERFCINVF) + #define IF_DEVICE_OR_HAVE_ERFCINVF(t, f) _NV_BLOCK_EXPAND(t) +#else + #define IF_DEVICE_OR_HAVE_ERFCINVF(t, f) NV_IF_ELSE_TARGET(NV_IS_DEVICE, t, f) +#endif + +QUALIFIERS_STATIC float _curand_normal_icdf(unsigned int x) +{ +IF_DEVICE_OR_HAVE_ERFCINVF( + float s = CURAND_SQRT2; + // Mirror to avoid loss of precision + if(x > 0x80000000UL) { + x = 0xffffffffUL - x; + s = -s; + } + float p = x * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); + // p is in (0, 0.5], 2p is in (0, 1] + return s * erfcinvf(2.0f * p); +, + x++; //suppress warnings + return 0.0f; +) +} + +QUALIFIERS_STATIC float _curand_normal_icdf(unsigned long long x) +{ +IF_DEVICE_OR_HAVE_ERFCINVF( + unsigned int t = (unsigned int)(x >> 32); + float s = CURAND_SQRT2; + // Mirror to avoid loss of precision + if(t > 0x80000000UL) { + t = 0xffffffffUL - t; + s = -s; + } + float p = t * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); + // p is in (0 - 0.5] 2p is in (0 - 1] + return s * erfcinvf(2.0f * p); +, + x++; + return 0.0f; +) +} + +QUALIFIERS_STATIC double _curand_normal_icdf_double(unsigned int x) +{ +IF_DEVICE_OR_HAVE_ERFCINVF( + double s = CURAND_SQRT2_DOUBLE; + // Mirror to avoid loss of precision + if(x > 0x80000000UL) { + x = 0xffffffffUL - x; + s = -s; + } + double p = x * CURAND_2POW32_INV_DOUBLE + (CURAND_2POW32_INV_DOUBLE/2.0); + // p is in (0 - 0.5] 2p is in (0 - 1] + return s * erfcinv(2.0 * p); +, + x++; + return 0.0; +) +} + +QUALIFIERS_STATIC double _curand_normal_icdf_double(unsigned long long x) +{ +IF_DEVICE_OR_HAVE_ERFCINVF( + double s = CURAND_SQRT2_DOUBLE; + x >>= 11; + // Mirror to avoid loss of precision + if(x > 0x10000000000000UL) { + x = 0x1fffffffffffffUL - x; + s = -s; + } + double p = x * CURAND_2POW53_INV_DOUBLE + (CURAND_2POW53_INV_DOUBLE/2.0); + // p is in (0 - 0.5] 2p is in (0 - 1] + return s * erfcinv(2.0 * p); +, + x++; + return 0.0; +) +} +#undef QUALIFIERS_STATIC +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_philox4x32_x.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_philox4x32_x.h new file mode 100644 index 0000000000000000000000000000000000000000..3dbda4a0ce9ef3e11460320728886f7feb10cf2d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_philox4x32_x.h @@ -0,0 +1,195 @@ +/* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ +/* + Copyright 2010-2011, D. E. Shaw Research. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of D. E. Shaw Research nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CURAND_PHILOX4X32_X__H_ +#define CURAND_PHILOX4X32_X__H_ +#include + +#if !defined(QUALIFIERS) +#define QUALIFIERS static __forceinline__ __device__ +#endif + +#define PHILOX_W32_0 (0x9E3779B9) +#define PHILOX_W32_1 (0xBB67AE85) +#define PHILOX_M4x32_0 (0xD2511F53) +#define PHILOX_M4x32_1 (0xCD9E8D57) + +struct curandStatePhilox4_32_10 { + uint4 ctr; + uint4 output; + uint2 key; + unsigned int STATE; + int boxmuller_flag; + int boxmuller_flag_double; + float boxmuller_extra; + double boxmuller_extra_double; +}; + +typedef struct curandStatePhilox4_32_10 curandStatePhilox4_32_10_t; + + +QUALIFIERS void Philox_State_Incr(curandStatePhilox4_32_10_t* s, unsigned long long n) +{ + unsigned int nlo = (unsigned int)(n); + unsigned int nhi = (unsigned int)(n>>32); + + s->ctr.x += nlo; + if( s->ctr.x < nlo ) + nhi++; + + s->ctr.y += nhi; + if(nhi <= s->ctr.y) + return; + if(++s->ctr.z) return; + ++s->ctr.w; +} + +QUALIFIERS void Philox_State_Incr_hi(curandStatePhilox4_32_10_t* s, unsigned long long n) +{ + unsigned int nlo = (unsigned int)(n); + unsigned int nhi = (unsigned int)(n>>32); + + s->ctr.z += nlo; + if( s->ctr.z < nlo ) + nhi++; + + s->ctr.w += nhi; +} + + + +QUALIFIERS void Philox_State_Incr(curandStatePhilox4_32_10_t* s) +{ + if(++s->ctr.x) return; + if(++s->ctr.y) return; + if(++s->ctr.z) return; + ++s->ctr.w; +} + + +QUALIFIERS unsigned int mulhilo32(unsigned int a, unsigned int b, unsigned int* hip) +{ +NV_IF_ELSE_TARGET(NV_IS_HOST, + // host code + unsigned long long product = ((unsigned long long)a) * ((unsigned long long)b); + *hip = product >> 32; + return (unsigned int)product; +, + // device code + *hip = __umulhi(a,b); + return a*b; +) +} + +QUALIFIERS uint4 _philox4x32round(uint4 ctr, uint2 key) +{ + unsigned int hi0; + unsigned int hi1; + unsigned int lo0 = mulhilo32(PHILOX_M4x32_0, ctr.x, &hi0); + unsigned int lo1 = mulhilo32(PHILOX_M4x32_1, ctr.z, &hi1); + + uint4 ret = {hi1^ctr.y^key.x, lo1, hi0^ctr.w^key.y, lo0}; + return ret; +} + +QUALIFIERS uint4 curand_Philox4x32_10( uint4 c, uint2 k) +{ + c = _philox4x32round(c, k); // 1 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + c = _philox4x32round(c, k); // 2 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + c = _philox4x32round(c, k); // 3 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + c = _philox4x32round(c, k); // 4 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + c = _philox4x32round(c, k); // 5 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + c = _philox4x32round(c, k); // 6 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + c = _philox4x32round(c, k); // 7 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + c = _philox4x32round(c, k); // 8 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + c = _philox4x32round(c, k); // 9 + k.x += PHILOX_W32_0; k.y += PHILOX_W32_1; + return _philox4x32round(c, k); // 10 +} + + +#endif diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_poisson.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_poisson.h new file mode 100644 index 0000000000000000000000000000000000000000..7881194cb868be14a197b581d7c82bf9dd16d617 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_poisson.h @@ -0,0 +1,763 @@ + + /* Copyright 2010-2014 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + + +#if !defined(CURAND_POISSON_H_) +#define CURAND_POISSON_H_ + +/** + * \defgroup DEVICE Device API + * + * @{ + */ + +#ifndef __CUDACC_RTC__ +#include +#endif // __CUDACC_RTC__ + +#include + +#include "curand_mrg32k3a.h" +#include "curand_mtgp32_kernel.h" +#include "curand_philox4x32_x.h" + +#define CR_CUDART_PI 3.1415926535897931e+0 +#define CR_CUDART_TWO_TO_52 4503599627370496.0 + + +QUALIFIERS float __cr_rsqrt(float a) +{ +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + asm ("rsqrt.approx.f32.ftz %0, %1;" : "=f"(a) : "f"(a)); +, + a = 1.0f / sqrtf (a); +) + return a; +} + +QUALIFIERS float __cr_exp (float a) +{ +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + a = a * 1.4426950408889634074; + asm ("ex2.approx.f32.ftz %0, %1;" : "=f"(a) : "f"(a)); +, + a = expf (a); +) + return a; +} + +QUALIFIERS float __cr_log (float a) +{ +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + asm ("lg2.approx.f32.ftz %0, %1;" : "=f"(a) : "f"(a)); + a = a * 0.69314718055994530942; +, + a = logf (a); +) + return a; +} + +QUALIFIERS float __cr_rcp (float a) +{ +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + asm ("rcp.approx.f32.ftz %0, %1;" : "=f"(a) : "f"(a)); +, + a = 1.0f / a; +) + return a; +} + +/* Computes regularized gamma function: gammainc(a,x)/gamma(a) */ +QUALIFIERS float __cr_pgammainc (float a, float x) +{ + float t, alpha, beta; + + /* First level parametrization constants */ + float ma1 = 1.43248035075540910f, + ma2 = 0.12400979329415655f, + ma3 = 0.00025361074907033f, + mb1 = 0.21096734870196546f, + mb2 = 1.97381164089999420f, + mb3 = 0.94201734077887530f; + + /* Second level parametrization constants (depends only on a) */ + + alpha = __cr_rsqrt (a - ma2); + alpha = ma1 * alpha + ma3; + beta = __cr_rsqrt (a - mb2); + beta = mb1 * beta + mb3; + + /* Final approximation (depends on a and x) */ + + t = a - x; + t = alpha * t - beta; + t = 1.0f + __cr_exp (t); + t = t * t; + t = __cr_rcp (t); + + /* Negative a,x or a,x=NAN requires special handling */ + //t = !(x > 0 && a >= 0) ? 0.0 : t; + + return t; +} + +/* Computes inverse of pgammainc */ +QUALIFIERS float __cr_pgammaincinv (float a, float y) +{ + float t, alpha, beta; + + /* First level parametrization constants */ + + float ma1 = 1.43248035075540910f, + ma2 = 0.12400979329415655f, + ma3 = 0.00025361074907033f, + mb1 = 0.21096734870196546f, + mb2 = 1.97381164089999420f, + mb3 = 0.94201734077887530f; + + /* Second level parametrization constants (depends only on a) */ + + alpha = __cr_rsqrt (a - ma2); + alpha = ma1 * alpha + ma3; + beta = __cr_rsqrt (a - mb2); + beta = mb1 * beta + mb3; + + /* Final approximation (depends on a and y) */ + + t = __cr_rsqrt (y) - 1.0f; + t = __cr_log (t); + t = beta + t; + t = - t * __cr_rcp (alpha) + a; + /* Negative a,x or a,x=NAN requires special handling */ + //t = !(y > 0 && a >= 0) ? 0.0 : t; + return t; +} + +#if defined(__CUDACC_RDC__) && (__cplusplus >= 201703L) && defined(__cpp_inline_variables) +inline __constant__ double __cr_lgamma_table [] = { +#else +static __constant__ double __cr_lgamma_table [] = { +#endif + 0.000000000000000000e-1, + 0.000000000000000000e-1, + 6.931471805599453094e-1, + 1.791759469228055001e0, + 3.178053830347945620e0, + 4.787491742782045994e0, + 6.579251212010100995e0, + 8.525161361065414300e0, + 1.060460290274525023e1 +}; + + +QUALIFIERS double __cr_lgamma_integer(int a) +{ + double s; + double t; + double fa = fabs((float)a); + double sum; + + if (a > 8) { + /* Stirling approximation; coefficients from Hart et al, "Computer + * Approximations", Wiley 1968. Approximation 5404. + */ + s = 1.0 / fa; + t = s * s; + sum = -0.1633436431e-2; + sum = sum * t + 0.83645878922e-3; + sum = sum * t - 0.5951896861197e-3; + sum = sum * t + 0.793650576493454e-3; + sum = sum * t - 0.277777777735865004e-2; + sum = sum * t + 0.833333333333331018375e-1; + sum = sum * s + 0.918938533204672; + s = 0.5 * log (fa); + t = fa - 0.5; + s = s * t; + t = s - fa; + s = s + sum; + t = t + s; + return t; + } else { +NV_IF_ELSE_TARGET(NV_IS_DEVICE, + return __cr_lgamma_table [(int) fa-1]; +, + switch(a) { + case 1: return 0.000000000000000000e-1; + case 2: return 0.000000000000000000e-1; + case 3: return 6.931471805599453094e-1; + case 4: return 1.791759469228055001e0; + case 5: return 3.178053830347945620e0; + case 6: return 4.787491742782045994e0; + case 7: return 6.579251212010100995e0; + case 8: return 8.525161361065414300e0; + default: return 1.060460290274525023e1; + } +) + } +} + +#define KNUTH_FLOAT_CONST 60.0 +template +// Donald E. Knuth Seminumerical Algorithms. The Art of Computer Programming, Volume 2 +QUALIFIERS unsigned int curand_poisson_knuth(T *state, float lambda) +{ + unsigned int k = 0; + float p = expf(lambda); + do{ + k++; + p *= curand_uniform(state); + }while (p > 1.0); + return k-1; +} + +template +// Donald E. Knuth Seminumerical Algorithms. The Art of Computer Programming, Volume 2 +QUALIFIERS uint4 curand_poisson_knuth4(T *state, float lambda) +{ + uint4 k = {0,0,0,0}; + float exp_lambda = expf(lambda); + float4 p={ exp_lambda,exp_lambda,exp_lambda,exp_lambda }; + do{ + k.x++; + p.x *= curand_uniform(state); + }while (p.x > 1.0); + do{ + k.y++; + p.y *= curand_uniform(state); + }while (p.y > 1.0); + do{ + k.z++; + p.z *= curand_uniform(state); + }while (p.z > 1.0); + do{ + k.w++; + p.w *= curand_uniform(state); + }while (p.w > 1.0); + + k.x--; + k.y--; + k.z--; + k.w--; + return k; +} + +template +// Marsaglia, Tsang, Wang Journal of Statistical Software, square histogram. +QUALIFIERS unsigned int _curand_M2_double(T x, curandDistributionM2Shift_t distributionM2) +{ + double u = _curand_uniform_double(x); + int j = (int) floor(distributionM2->length*u); + + double histogramVj; + unsigned int histogramKj; +NV_IF_ELSE_TARGET(NV_PROVIDES_SM_35, + histogramVj = __ldg( &(distributionM2->histogram->V[j])); + histogramKj = __ldg( &(distributionM2->histogram->K[j])); +, + histogramVj = distributionM2->histogram->V[j]; + histogramKj = distributionM2->histogram->K[j]; +) + //if (u < distributionM2->histogram->V[j]) return distributionM2->shift + j; + //return distributionM2->shift + distributionM2->histogram->K[j]; + if (u < histogramVj) return distributionM2->shift + j; + return distributionM2->shift + histogramKj; +} + +template +// Marsaglia, Tsang, Wang Journal of Statistical Software, square histogram. +QUALIFIERS uint4 _curand_M2_double4(T x, curandDistributionM2Shift_t distributionM2) +{ + double4 u; + uint4 result = {0,0,0,0}; + int4 flag = {1,1,1,1}; + + u.x = _curand_uniform_double(x.x); + u.y = _curand_uniform_double(x.y); + u.z = _curand_uniform_double(x.z); + u.w = _curand_uniform_double(x.w); + + int4 j; + j.x = (int) floor(distributionM2->length*u.x); + j.y = (int) floor(distributionM2->length*u.y); + j.z = (int) floor(distributionM2->length*u.z); + j.w = (int) floor(distributionM2->length*u.w); +// int result; + + double histogramVjx; + double histogramVjy; + double histogramVjz; + double histogramVjw; + unsigned int histogramKjx; + unsigned int histogramKjy; + unsigned int histogramKjz; + unsigned int histogramKjw; +NV_IF_ELSE_TARGET(NV_PROVIDES_SM_35, + histogramVjx = __ldg( &(distributionM2->histogram->V[j.x])); + histogramVjy = __ldg( &(distributionM2->histogram->V[j.y])); + histogramVjz = __ldg( &(distributionM2->histogram->V[j.z])); + histogramVjw = __ldg( &(distributionM2->histogram->V[j.w])); + + histogramKjx = __ldg( &(distributionM2->histogram->K[j.x])); + histogramKjy = __ldg( &(distributionM2->histogram->K[j.y])); + histogramKjz = __ldg( &(distributionM2->histogram->K[j.z])); + histogramKjw = __ldg( &(distributionM2->histogram->K[j.w])); +, + histogramVjx = distributionM2->histogram->V[j.x]; + histogramVjy = distributionM2->histogram->V[j.y]; + histogramVjz = distributionM2->histogram->V[j.z]; + histogramVjw = distributionM2->histogram->V[j.w]; + + histogramKjx = distributionM2->histogram->K[j.x]; + histogramKjy = distributionM2->histogram->K[j.y]; + histogramKjz = distributionM2->histogram->K[j.z]; + histogramKjw = distributionM2->histogram->K[j.w]; +) + + if (u.x < histogramVjx){ result.x = distributionM2->shift + j.x; flag.x = 0; } + if (u.y < histogramVjy){ result.y = distributionM2->shift + j.y; flag.y = 0; } + if (u.z < histogramVjz){ result.z = distributionM2->shift + j.z; flag.z = 0; } + if (u.w < histogramVjw){ result.w = distributionM2->shift + j.w; flag.w = 0; } + //return distributionM2->shift + distributionM2->histogram->K[j]; + + if(flag.x) result.x = distributionM2->shift + histogramKjx; + if(flag.y) result.y = distributionM2->shift + histogramKjy; + if(flag.z) result.z = distributionM2->shift + histogramKjz; + if(flag.w) result.w = distributionM2->shift + histogramKjw; + + return result; +} + +template +QUALIFIERS unsigned int curand_M2_double(STATE *state, curandDistributionM2Shift_t distributionM2) +{ + return _curand_M2_double(curand(state), distributionM2); +} + +template +QUALIFIERS uint4 curand_M2_double4(STATE *state, curandDistributionM2Shift_t distributionM2) +{ + return _curand_M2_double4(curand4(state), distributionM2); +} + + +template +QUALIFIERS unsigned int _curand_binary_search_double(T x, curandDistributionShift_t distribution) +{ + double u = _curand_uniform_double(x); + int min = 0; + int max = distribution->length-1; + do{ + int mid = (max + min)/2; + double probability_mid; +NV_IF_ELSE_TARGET(NV_PROVIDES_SM_35, + probability_mid = __ldg( &(distribution->probability[mid])); +, + probability_mid = distribution->probability[mid]; +) + if (u <= probability_mid){ + max = mid; + }else{ + min = mid+1; + } + }while (min < max); + return distribution->shift + min; +} + +template +QUALIFIERS unsigned int curand_binary_search_double(STATE *state, curandDistributionShift_t distribution) +{ + return _curand_binary_search_double(curand(state), distribution); +} + +// Generates uniformly distributed double values in range (0.0; 1.0) from uniformly distributed +// unsigned int. We can't use standard _curand_uniform_double since it can generate 1.0. +// This is required only for _curand_poisson_ITR_double. +QUALIFIERS double _curand_uniform_double_excluding_one(unsigned int x) +{ + return x * CURAND_2POW32_INV_DOUBLE + (CURAND_2POW32_INV_DOUBLE/2.0); +} + +// Overload for unsigned long long. +// This is required only for _curand_poisson_ITR_double. +QUALIFIERS double _curand_uniform_double_excluding_one(unsigned long long x) +{ + return (x >> 11) * CURAND_2POW53_INV_DOUBLE + (CURAND_2POW53_INV_DOUBLE/4.0); +} + +#define MAGIC_DOUBLE_CONST 500.0 +template +//George S. Fishman Discrete-event simulation: modeling, programming, and analysis +QUALIFIERS unsigned int _curand_poisson_ITR_double(T x, double lambda) +{ + double L,p = 1.0; + double q = 1.0; + unsigned int k = 0; + int pow=0; + // This algorithm requires u to be in (0;1) range, however, _curand_uniform_double + // returns a number in range (0;1]. If u is 1.0 the inner loop never ends. The + // following operation transforms the range from (0;1] to (0;1). + double u = _curand_uniform_double_excluding_one(x); + do{ + if (lambda > (double)(pow+MAGIC_DOUBLE_CONST)){ + L = exp(-MAGIC_DOUBLE_CONST); + }else{ + L = exp((double)(pow - lambda)); + } + p *= L; + q *= L; + pow += (int) MAGIC_DOUBLE_CONST; + while (u > q){ + k++; + p *= ((double)lambda / (double) k); + q += p; + } + }while((double)pow < lambda); + return k; +} + +template +/* Rejection Method for Poisson distribution based on gammainc approximation */ +QUALIFIERS unsigned int curand_poisson_gammainc(T state, float lambda){ + float y, x, t, z,v; + float logl = __cr_log (lambda); + while (true) { + y = curand_uniform (state); + x = __cr_pgammaincinv (lambda, y); + x = floorf (x); + z = curand_uniform (state); + v = (__cr_pgammainc (lambda, x + 1.0f) - __cr_pgammainc (lambda, x)) * 1.3f; + z = z*v; + t = (float)__cr_exp (-lambda + x * logl - (float)__cr_lgamma_integer ((int)(1.0f + x))); + if ((z < t) && (v>=1e-20)) + break; + } + return (unsigned int)x; +} + +template +/* Rejection Method for Poisson distribution based on gammainc approximation */ +QUALIFIERS uint4 curand_poisson_gammainc4(T state, float lambda){ + uint4 result; + float y, x, t, z,v; + float logl = __cr_log (lambda); + while (true) { + y = curand_uniform(state); + x = __cr_pgammaincinv (lambda, y); + x = floorf (x); + z = curand_uniform (state); + v = (__cr_pgammainc (lambda, x + 1.0f) - __cr_pgammainc (lambda, x)) * 1.3f; + z = z*v; + t = (float)__cr_exp (-lambda + x * logl - (float)__cr_lgamma_integer ((int)(1.0f + x))); + if ((z < t) && (v>=1e-20)) + break; + } + result.x = (unsigned int)x; + + while (true) { + y = curand_uniform(state); + x = __cr_pgammaincinv (lambda, y); + x = floorf (x); + z = curand_uniform (state); + v = (__cr_pgammainc (lambda, x + 1.0f) - __cr_pgammainc (lambda, x)) * 1.3f; + z = z*v; + t = (float)__cr_exp (-lambda + x * logl - (float)__cr_lgamma_integer ((int)(1.0f + x))); + if ((z < t) && (v>=1e-20)) + break; + } + result.y = (unsigned int)x; + + while (true) { + y = curand_uniform(state); + x = __cr_pgammaincinv (lambda, y); + x = floorf (x); + z = curand_uniform (state); + v = (__cr_pgammainc (lambda, x + 1.0f) - __cr_pgammainc (lambda, x)) * 1.3f; + z = z*v; + t = (float)__cr_exp (-lambda + x * logl - (float)__cr_lgamma_integer ((int)(1.0f + x))); + if ((z < t) && (v>=1e-20)) + break; + } + result.z = (unsigned int)x; + + while (true) { + y = curand_uniform(state); + x = __cr_pgammaincinv (lambda, y); + x = floorf (x); + z = curand_uniform (state); + v = (__cr_pgammainc (lambda, x + 1.0f) - __cr_pgammainc (lambda, x)) * 1.3f; + z = z*v; + t = (float)__cr_exp (-lambda + x * logl - (float)__cr_lgamma_integer ((int)(1.0f + x))); + if ((z < t) && (v>=1e-20)) + break; + } + result.w = (unsigned int)x; + + return result; +} +// Note below that the round to nearest integer, where needed,is done in line with code that +// assumes the range of values is < 2**32 + +template +QUALIFIERS unsigned int _curand_poisson(T x, double lambda) +{ + if (lambda < 1000) + return _curand_poisson_ITR_double(x, lambda); + return (unsigned int)((sqrt(lambda) * _curand_normal_icdf_double(x)) + lambda + 0.5); //Round to nearest +} + +template +QUALIFIERS unsigned int _curand_poisson_from_normal(T x, double lambda) +{ + return (unsigned int)((sqrt(lambda) * _curand_normal_icdf(x)) + lambda + 0.5); //Round to nearest +} + +template +QUALIFIERS unsigned int curand_poisson_from_normal(STATE state, double lambda) +{ + return (unsigned int)((sqrt(lambda) * curand_normal(state)) + lambda + 0.5); //Round to nearest +} + +template +QUALIFIERS uint4 curand_poisson_from_normal4(STATE state, double lambda) +{ + uint4 result; + float4 _res; + + _res = curand_normal4(state); + + result.x = (unsigned int)((sqrt(lambda) * _res.x) + lambda + 0.5); //Round to nearest + result.y = (unsigned int)((sqrt(lambda) * _res.y) + lambda + 0.5); //Round to nearest + result.z = (unsigned int)((sqrt(lambda) * _res.z) + lambda + 0.5); //Round to nearest + result.w = (unsigned int)((sqrt(lambda) * _res.w) + lambda + 0.5); //Round to nearest + return result; //Round to nearest +} + +/** + * \brief Return a Poisson-distributed unsigned int from a XORWOW generator. + * + * Return a single unsigned int from a Poisson + * distribution with lambda \p lambda from the XORWOW generator in \p state, + * increment the position of the generator by a variable amount, depending + * on the algorithm used. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ +QUALIFIERS unsigned int curand_poisson(curandStateXORWOW_t *state, double lambda) +{ + if (lambda < 64) + return curand_poisson_knuth(state, (float)lambda); + if (lambda > 4000) + return (unsigned int)((sqrt(lambda) * curand_normal_double(state)) + lambda + 0.5); //Round to nearest + return curand_poisson_gammainc(state, (float)lambda); +} + +/** + * \brief Return a Poisson-distributed unsigned int from a Philox4_32_10 generator. + * + * Return a single unsigned int from a Poisson + * distribution with lambda \p lambda from the Philox4_32_10 generator in \p state, + * increment the position of the generator by a variable amount, depending + * on the algorithm used. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ +QUALIFIERS unsigned int curand_poisson(curandStatePhilox4_32_10_t *state, double lambda) +{ + if (lambda < 64) + return curand_poisson_knuth(state, (float)lambda); + if (lambda > 4000) + return (unsigned int)((sqrt(lambda) * curand_normal_double(state)) + lambda + 0.5); //Round to nearest + return curand_poisson_gammainc(state, (float)lambda); +} +/** + * \brief Return four Poisson-distributed unsigned ints from a Philox4_32_10 generator. + * + * Return a four unsigned ints from a Poisson + * distribution with lambda \p lambda from the Philox4_32_10 generator in \p state, + * increment the position of the generator by a variable amount, depending + * on the algorithm used. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ +QUALIFIERS uint4 curand_poisson4(curandStatePhilox4_32_10_t *state, double lambda) +{ + uint4 result; + double4 _res; + if (lambda < 64) + return curand_poisson_knuth4(state, (float)lambda); + if (lambda > 4000) { + _res = curand_normal4_double(state); + result.x = (unsigned int)((sqrt(lambda) * _res.x) + lambda + 0.5); //Round to nearest + result.y = (unsigned int)((sqrt(lambda) * _res.y) + lambda + 0.5); //Round to nearest + result.z = (unsigned int)((sqrt(lambda) * _res.z) + lambda + 0.5); //Round to nearest + result.w = (unsigned int)((sqrt(lambda) * _res.w) + lambda + 0.5); //Round to nearest + return result; + } + return curand_poisson_gammainc4(state, (float)lambda); +} + + + +/** + * \brief Return a Poisson-distributed unsigned int from a MRG32k3A generator. + * + * Return a single unsigned int from a Poisson + * distribution with lambda \p lambda from the MRG32k3a generator in \p state, + * increment the position of the generator by a variable amount, depending + * on the algorithm used. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ +QUALIFIERS unsigned int curand_poisson(curandStateMRG32k3a_t *state, double lambda) +{ + if (lambda < 64) + return curand_poisson_knuth(state, (float)lambda); + if (lambda > 4000) + return (unsigned int)((sqrt(lambda) * curand_normal_double(state)) + lambda + 0.5); //Round to nearest + return curand_poisson_gammainc(state, (float)lambda); +} + +/** + * \brief Return a Poisson-distributed unsigned int from a MTGP32 generator. + * + * Return a single int from a Poisson + * distribution with lambda \p lambda from the MTGP32 generator in \p state, + * increment the position of the generator by one. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ +QUALIFIERS unsigned int curand_poisson(curandStateMtgp32_t *state, double lambda) +{ + return _curand_poisson(curand(state), lambda); +} + +/** + * \brief Return a Poisson-distributed unsigned int from a Sobol32 generator. + * + * Return a single unsigned int from a Poisson + * distribution with lambda \p lambda from the Sobol32 generator in \p state, + * increment the position of the generator by one. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ + +QUALIFIERS unsigned int curand_poisson(curandStateSobol32_t *state, double lambda) +{ + return _curand_poisson(curand(state), lambda); +} + +/** + * \brief Return a Poisson-distributed unsigned int from a scrambled Sobol32 generator. + * + * Return a single unsigned int from a Poisson + * distribution with lambda \p lambda from the scrambled Sobol32 generator in \p state, + * increment the position of the generator by one. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ +QUALIFIERS unsigned int curand_poisson(curandStateScrambledSobol32_t *state, double lambda) +{ + return _curand_poisson(curand(state), lambda); +} + +/** + * \brief Return a Poisson-distributed unsigned int from a Sobol64 generator. + * + * Return a single unsigned int from a Poisson + * distribution with lambda \p lambda from the Sobol64 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ +QUALIFIERS unsigned int curand_poisson(curandStateSobol64_t *state, double lambda) +{ + return _curand_poisson(curand(state), lambda); +} + +/** + * \brief Return a Poisson-distributed unsigned int from a scrambled Sobol64 generator. + * + * Return a single unsigned int from a Poisson + * distribution with lambda \p lambda from the scrambled Sobol64 generator in \p state, + * increment position of generator by one. + * + * \param state - Pointer to state to update + * \param lambda - Lambda of the Poisson distribution + * + * \return Poisson-distributed unsigned int with lambda \p lambda + */ +QUALIFIERS unsigned int curand_poisson(curandStateScrambledSobol64_t *state, double lambda) +{ + return _curand_poisson(curand(state), lambda); +} +#endif // !defined(CURAND_POISSON_H_) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_precalc.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_precalc.h new file mode 100644 index 0000000000000000000000000000000000000000..01818fb642856eb09f7e3fa0b8202d34c37c8566 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_precalc.h @@ -0,0 +1,3548 @@ +/* Copyright 2010-2012 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ +#if !defined(CURAND_XORWOW_PRECALCULATED_H_) +#define CURAND_XORWOW_PRECALCULATED_H_ + +#define PRECALC_NUM_MATRICES (32) +#define PRECALC_BLOCK_SIZE (2) +#define PRECALC_BLOCK_MASK ((1<= 201703L) && defined(__cpp_inline_variables) +#define CURAND_XORWOW_PRECALCULATED_DEVICE_QUALIFIERS inline __device__ +#else +#define CURAND_XORWOW_PRECALCULATED_DEVICE_QUALIFIERS static __device__ +#endif + +#if (__cplusplus >= 201703L) && defined(__cpp_inline_variables) +#define CURAND_XORWOW_PRECALCULATED_HOST_QUALIFIERS inline +#else +#define CURAND_XORWOW_PRECALCULATED_HOST_QUALIFIERS static +#endif +CURAND_XORWOW_PRECALCULATED_DEVICE_QUALIFIERS unsigned int precalc_xorwow_matrix[32][800] = { +{ +850664906UL, 2293210629UL, 1517805917UL, 1215500405UL, 1612415445UL, 645388200UL, 824349799UL, 3517232886UL, 4075591755UL, 3089899292UL, 4249786064UL, 3811424903UL, 1100783479UL, 53649761UL, 2817264826UL, 3159462529UL, 1654848550UL, 950025444UL, 3095510002UL, 4080567211UL, 4111078399UL, 3241719305UL, 2788212779UL, 4256963770UL, 2426893717UL, 4190211142UL, 1420776905UL, 3780537969UL, 1102912875UL, 1657948873UL, 3354905256UL, 2519610308UL, +515777663UL, 3396785394UL, 1832603711UL, 1154211550UL, 1915690212UL, 1933919046UL, 789578337UL, 337961173UL, 1359089498UL, 2249086205UL, 3417955173UL, 862571348UL, 528120760UL, 1265685672UL, 1970052076UL, 3585976752UL, 3645339918UL, 312171257UL, 1360991400UL, 1994321680UL, 2327168468UL, 2540437053UL, 1180483641UL, 2217962701UL, 182726833UL, 590204372UL, 1904496495UL, 2545607041UL, 3697978033UL, 1084030545UL, 3397906968UL, 2192325323UL, +2704204176UL, 1069092002UL, 2364406907UL, 1578647245UL, 3561974633UL, 3437665426UL, 1464127305UL, 1616628807UL, 2243114101UL, 3639967880UL, 1702613633UL, 2437350057UL, 39991274UL, 2024323584UL, 3795072940UL, 3604530798UL, 443099203UL, 643536212UL, 1919517328UL, 3931285769UL, 427935569UL, 276421624UL, 2492081750UL, 262729512UL, 3088549877UL, 2922650665UL, 1816283755UL, 4246096489UL, 842575914UL, 1460435650UL, 3050522190UL, 2640849794UL, +3697925816UL, 3465779075UL, 3856929655UL, 1365559780UL, 2897029415UL, 2747033756UL, 3611830629UL, 1891542518UL, 1897590206UL, 437451803UL, 677924906UL, 123809117UL, 3940574372UL, 687640291UL, 3488484529UL, 470218446UL, 1092571016UL, 1537938503UL, 1073323937UL, 611300083UL, 3809285994UL, 3975678726UL, 925845389UL, 2514775760UL, 2859302390UL, 2761919483UL, 993285307UL, 164095287UL, 3736193671UL, 2078946336UL, 1418537059UL, 1202525920UL, +4234029440UL, 1313593624UL, 2484428922UL, 1833969372UL, 661495122UL, 2217907395UL, 2795045321UL, 2950835531UL, 1402379354UL, 351314168UL, 1902476749UL, 1914974334UL, 2873973176UL, 1321203603UL, 3316118265UL, 3282193947UL, 1342191737UL, 793441242UL, 3281524559UL, 296088733UL, 487851702UL, 712098215UL, 1388727135UL, 1705533557UL, 3557800292UL, 399729516UL, 1355829467UL, 291276309UL, 421164833UL, 1318404599UL, 2064519128UL, 1161612642UL, +2076623594UL, 850664906UL, 2293210629UL, 1517805917UL, 1215500405UL, 3847487204UL, 645388200UL, 824349799UL, 3517232886UL, 4075591755UL, 2755872609UL, 4249786064UL, 3811424903UL, 1100783479UL, 53649761UL, 1417544262UL, 3159462529UL, 1654848550UL, 950025444UL, 3095510002UL, 1908900347UL, 4111078399UL, 3241719305UL, 2788212779UL, 4256963770UL, 3750258343UL, 4190211142UL, 1420776905UL, 3780537969UL, 1102912875UL, 1690550UL, 3354905256UL, +2519610308UL, 515777663UL, 3396785394UL, 2658162202UL, 1154211550UL, 1915690212UL, 1933919046UL, 789578337UL, 189880016UL, 1359089498UL, 2249086205UL, 3417955173UL, 862571348UL, 998719835UL, 1265685672UL, 1970052076UL, 3585976752UL, 3645339918UL, 2973042959UL, 1360991400UL, 1994321680UL, 2327168468UL, 2540437053UL, 2283905032UL, 2217962701UL, 182726833UL, 590204372UL, 1904496495UL, 110719262UL, 3697978033UL, 1084030545UL, 3397906968UL, +2192325323UL, 4133333579UL, 1069092002UL, 2364406907UL, 1578647245UL, 3561974633UL, 3629845331UL, 1464127305UL, 1616628807UL, 2243114101UL, 3639967880UL, 3256744141UL, 2437350057UL, 39991274UL, 2024323584UL, 3795072940UL, 1024703328UL, 443099203UL, 643536212UL, 1919517328UL, 3931285769UL, 2755167056UL, 276421624UL, 2492081750UL, 262729512UL, 3088549877UL, 2817867653UL, 1816283755UL, 4246096489UL, 842575914UL, 1460435650UL, 2276077438UL, +2640849794UL, 3697925816UL, 3465779075UL, 3856929655UL, 130551477UL, 2897029415UL, 2747033756UL, 3611830629UL, 1891542518UL, 804565809UL, 437451803UL, 677924906UL, 123809117UL, 3940574372UL, 2446610749UL, 3488484529UL, 470218446UL, 1092571016UL, 1537938503UL, 1502147484UL, 611300083UL, 3809285994UL, 3975678726UL, 925845389UL, 872826112UL, 2859302390UL, 2761919483UL, 993285307UL, 164095287UL, 3901654538UL, 2078946336UL, 1418537059UL, +1202525920UL, 4234029440UL, 704759480UL, 2484428922UL, 1833969372UL, 661495122UL, 2217907395UL, 3287413716UL, 2950835531UL, 1402379354UL, 351314168UL, 1902476749UL, 2033316109UL, 2873973176UL, 1321203603UL, 3316118265UL, 3282193947UL, 1316780684UL, 793441242UL, 3281524559UL, 296088733UL, 487851702UL, 314311643UL, 1388727135UL, 1705533557UL, 3557800292UL, 399729516UL, 1660074989UL, 291276309UL, 421164833UL, 1318404599UL, 2064519128UL, +3156334112UL, 2076623594UL, 850664906UL, 2293210629UL, 1517805917UL, 335452425UL, 3847487204UL, 645388200UL, 824349799UL, 3517232886UL, 954487767UL, 2755872609UL, 4249786064UL, 3811424903UL, 1100783479UL, 3408594583UL, 1417544262UL, 3159462529UL, 1654848550UL, 950025444UL, 324339737UL, 1908900347UL, 4111078399UL, 3241719305UL, 2788212779UL, 1890540205UL, 3750258343UL, 4190211142UL, 1420776905UL, 3780537969UL, 3716648585UL, 1690550UL, +3354905256UL, 2519610308UL, 515777663UL, 3758156132UL, 2658162202UL, 1154211550UL, 1915690212UL, 1933919046UL, 844149171UL, 189880016UL, 1359089498UL, 2249086205UL, 3417955173UL, 1031812215UL, 998719835UL, 1265685672UL, 1970052076UL, 3585976752UL, 3174204115UL, 2973042959UL, 1360991400UL, 1994321680UL, 2327168468UL, 714016907UL, 2283905032UL, 2217962701UL, 182726833UL, 590204372UL, 2151450260UL, 110719262UL, 3697978033UL, 1084030545UL, +3397906968UL, 767772303UL, 4133333579UL, 1069092002UL, 2364406907UL, 1578647245UL, 42955292UL, 3629845331UL, 1464127305UL, 1616628807UL, 2243114101UL, 3222189776UL, 3256744141UL, 2437350057UL, 39991274UL, 2024323584UL, 3142424684UL, 1024703328UL, 443099203UL, 643536212UL, 1919517328UL, 918511196UL, 2755167056UL, 276421624UL, 2492081750UL, 262729512UL, 4246877536UL, 2817867653UL, 1816283755UL, 4246096489UL, 842575914UL, 1425765936UL, +2276077438UL, 2640849794UL, 3697925816UL, 3465779075UL, 1491702526UL, 130551477UL, 2897029415UL, 2747033756UL, 3611830629UL, 1844578694UL, 804565809UL, 437451803UL, 677924906UL, 123809117UL, 3419189841UL, 2446610749UL, 3488484529UL, 470218446UL, 1092571016UL, 3272535988UL, 1502147484UL, 611300083UL, 3809285994UL, 3975678726UL, 2853681168UL, 872826112UL, 2859302390UL, 2761919483UL, 993285307UL, 1434560128UL, 3901654538UL, 2078946336UL, +1418537059UL, 1202525920UL, 2530097881UL, 704759480UL, 2484428922UL, 1833969372UL, 661495122UL, 503878844UL, 3287413716UL, 2950835531UL, 1402379354UL, 351314168UL, 4131886119UL, 2033316109UL, 2873973176UL, 1321203603UL, 3316118265UL, 237900321UL, 1316780684UL, 793441242UL, 3281524559UL, 296088733UL, 1730738847UL, 314311643UL, 1388727135UL, 1705533557UL, 3557800292UL, 1553835665UL, 1660074989UL, 291276309UL, 421164833UL, 1318404599UL, +964731488UL, 3156334112UL, 2076623594UL, 850664906UL, 2293210629UL, 1105350579UL, 335452425UL, 3847487204UL, 645388200UL, 824349799UL, 2789953706UL, 954487767UL, 2755872609UL, 4249786064UL, 3811424903UL, 3937839949UL, 3408594583UL, 1417544262UL, 3159462529UL, 1654848550UL, 624060530UL, 324339737UL, 1908900347UL, 4111078399UL, 3241719305UL, 2294919498UL, 1890540205UL, 3750258343UL, 4190211142UL, 1420776905UL, 2279133729UL, 3716648585UL, +1690550UL, 3354905256UL, 2519610308UL, 3563975602UL, 3758156132UL, 2658162202UL, 1154211550UL, 1915690212UL, 3505586122UL, 844149171UL, 189880016UL, 1359089498UL, 2249086205UL, 2389487504UL, 1031812215UL, 998719835UL, 1265685672UL, 1970052076UL, 2798611919UL, 3174204115UL, 2973042959UL, 1360991400UL, 1994321680UL, 1684134678UL, 714016907UL, 2283905032UL, 2217962701UL, 182726833UL, 1734988742UL, 2151450260UL, 110719262UL, 3697978033UL, +1084030545UL, 159906818UL, 767772303UL, 4133333579UL, 1069092002UL, 2364406907UL, 1290801202UL, 42955292UL, 3629845331UL, 1464127305UL, 1616628807UL, 987794861UL, 3222189776UL, 3256744141UL, 2437350057UL, 39991274UL, 3644076751UL, 3142424684UL, 1024703328UL, 443099203UL, 643536212UL, 1487589384UL, 918511196UL, 2755167056UL, 276421624UL, 2492081750UL, 137688638UL, 4246877536UL, 2817867653UL, 1816283755UL, 4246096489UL, 1518475380UL, +1425765936UL, 2276077438UL, 2640849794UL, 3697925816UL, 4226506771UL, 1491702526UL, 130551477UL, 2897029415UL, 2747033756UL, 2033599579UL, 1844578694UL, 804565809UL, 437451803UL, 677924906UL, 2749065512UL, 3419189841UL, 2446610749UL, 3488484529UL, 470218446UL, 290444026UL, 3272535988UL, 1502147484UL, 611300083UL, 3809285994UL, 2546040767UL, 2853681168UL, 872826112UL, 2859302390UL, 2761919483UL, 4097961150UL, 1434560128UL, 3901654538UL, +2078946336UL, 1418537059UL, 2725734455UL, 2530097881UL, 704759480UL, 2484428922UL, 1833969372UL, 3999408333UL, 503878844UL, 3287413716UL, 2950835531UL, 1402379354UL, 3861442503UL, 4131886119UL, 2033316109UL, 2873973176UL, 1321203603UL, 1267331405UL, 237900321UL, 1316780684UL, 793441242UL, 3281524559UL, 1273427916UL, 1730738847UL, 314311643UL, 1388727135UL, 1705533557UL, 1474310231UL, 1553835665UL, 1660074989UL, 291276309UL, 421164833UL, +3884815658UL, 3088049345UL, 3307042227UL, 3228948601UL, 1717605083UL, 1864502063UL, 3799516572UL, 2372822470UL, 2691586476UL, 1172840854UL, 1577099080UL, 870101866UL, 2139291021UL, 406996656UL, 255568268UL, 897760202UL, 674745664UL, 885214361UL, 3753233375UL, 3015215223UL, 1711461259UL, 3241363282UL, 2125360928UL, 2493601640UL, 2350228245UL, 3434627328UL, 2095642963UL, 3360932494UL, 3287396242UL, 4070512427UL, 3415702664UL, 1958354224UL, +3280206940UL, 3929504236UL, 3390499817UL, 4144225735UL, 3621750606UL, 3205006592UL, 3495743785UL, 269239326UL, 2181299371UL, 2898796651UL, 2613623219UL, 3988711298UL, 2162437858UL, 949553433UL, 3289670000UL, 3559525307UL, 3366925567UL, 2112148665UL, 955626393UL, 1790865381UL, 699223558UL, 3889584301UL, 1020750250UL, 4105283899UL, 2295851818UL, 4045668915UL, 2224770025UL, 766386910UL, 4265157386UL, 89139307UL, 2099710177UL, 1012450874UL, +1875492446UL, 1927399417UL, 767450812UL, 654474783UL, 4265293038UL, 4041215389UL, 4102336947UL, 4263617328UL, 2135826340UL, 2317231535UL, 3773895729UL, 403151111UL, 1400693138UL, 4255050194UL, 755369466UL, 2325764302UL, 2617301159UL, 4165707294UL, 1206304709UL, 2415645397UL, 4276004841UL, 1457022279UL, 662660652UL, 795140282UL, 828519889UL, 805830562UL, 1179976369UL, 2212548232UL, 755708248UL, 1034682071UL, 899950902UL, 1906046264UL, +1861009040UL, 310711525UL, 920739741UL, 2322414272UL, 3179236470UL, 81822135UL, 4111390320UL, 1800166783UL, 112253014UL, 688771939UL, 1050990794UL, 3124647483UL, 287052171UL, 1363630156UL, 3447798279UL, 1405733552UL, 3075862538UL, 1682808202UL, 1595154222UL, 1173705692UL, 680713285UL, 2748212230UL, 568610527UL, 3434965538UL, 1114942930UL, 2835858745UL, 2575992250UL, 3243355150UL, 2127580225UL, 1855934450UL, 3915941751UL, 2228679809UL, +1514780124UL, 1506688039UL, 1033083295UL, 793807083UL, 1120681149UL, 4105670165UL, 3999570340UL, 2083020131UL, 1213356023UL, 3684882757UL, 3375797774UL, 3577986103UL, 2092046164UL, 2593847443UL, 1826450612UL, 367828409UL, 3198272513UL, 1941316667UL, 943707510UL, 907134807UL, 2020457947UL, 1462193665UL, 2964617539UL, 4216491663UL, 2625270800UL, 2395371467UL, 3691003028UL, 3659016793UL, 2381847054UL, 3513105567UL, 3013019506UL, 2731245927UL, +}, +{ +1680024716UL, 2112340059UL, 3387475367UL, 2080916186UL, 1431532386UL, 3907378472UL, 2636491350UL, 2176128529UL, 2236616671UL, 3736851460UL, 2604001339UL, 3893075234UL, 3495918635UL, 4116370522UL, 1384310379UL, 3660102574UL, 2030233939UL, 2759207091UL, 49347923UL, 97526506UL, 2566932710UL, 1566181275UL, 3127827248UL, 578401670UL, 1499229308UL, 2581732444UL, 279715551UL, 809690877UL, 1438444015UL, 878935323UL, 1495277039UL, 3417305339UL, +2858903785UL, 3074075088UL, 603749086UL, 2370669734UL, 391683868UL, 3933465331UL, 2884128106UL, 1478317876UL, 1864988335UL, 2925823809UL, 4133578805UL, 218104493UL, 368652174UL, 1998600344UL, 1109346044UL, 1716435313UL, 415435111UL, 91393686UL, 2536620737UL, 1440068573UL, 481874870UL, 142128108UL, 988825519UL, 2077118779UL, 2858045339UL, 4068162251UL, 115593872UL, 1364244587UL, 3550167006UL, 3728768059UL, 1772423685UL, 2504624145UL, +248732306UL, 1412607307UL, 4081166331UL, 154438218UL, 1652901877UL, 3932533490UL, 3142799969UL, 3154073676UL, 3112018078UL, 2757873595UL, 2364830126UL, 2855791484UL, 793851407UL, 507785167UL, 263713916UL, 4060700051UL, 3291978358UL, 1584226715UL, 2546417990UL, 450747961UL, 2951067700UL, 2706009093UL, 1788578194UL, 4030171132UL, 2610979903UL, 573420740UL, 4269115622UL, 2180305819UL, 2646894726UL, 716649335UL, 3875715683UL, 853428184UL, +2436760738UL, 4190071217UL, 2754423535UL, 540698101UL, 4082489821UL, 741976046UL, 267559495UL, 1591532642UL, 2500610323UL, 3203248679UL, 147312102UL, 2772368222UL, 1412987047UL, 2295185573UL, 1932341300UL, 898396308UL, 1837129999UL, 3113914292UL, 2613354524UL, 3141601915UL, 276087167UL, 1887389351UL, 757801450UL, 3752353732UL, 2745818074UL, 1442953464UL, 3802648347UL, 223728071UL, 2169947402UL, 1338125300UL, 3642174036UL, 2794462634UL, +2326349851UL, 862746036UL, 3577092599UL, 627103363UL, 552173564UL, 4142604459UL, 2310329406UL, 583522272UL, 189323282UL, 1217612313UL, 73550248UL, 2434692829UL, 2757269706UL, 2392210091UL, 3032922600UL, 3573904125UL, 2897178037UL, 2632631469UL, 3085332665UL, 3775619904UL, 2563291734UL, 1351375865UL, 4043427793UL, 1803743084UL, 3112116579UL, 522940594UL, 2690374983UL, 2613871529UL, 3810037031UL, 1765642390UL, 534554747UL, 1930852049UL, +2264349344UL, 1680024716UL, 2112340059UL, 3387475367UL, 2080916186UL, 75966494UL, 3907378472UL, 2636491350UL, 2176128529UL, 2236616671UL, 2372987046UL, 2604001339UL, 3893075234UL, 3495918635UL, 4116370522UL, 534929913UL, 3660102574UL, 2030233939UL, 2759207091UL, 49347923UL, 987575186UL, 2566932710UL, 1566181275UL, 3127827248UL, 578401670UL, 3731513754UL, 2581732444UL, 279715551UL, 809690877UL, 1438444015UL, 2185866850UL, 1495277039UL, +3417305339UL, 2858903785UL, 3074075088UL, 4198538376UL, 2370669734UL, 391683868UL, 3933465331UL, 2884128106UL, 1400216510UL, 1864988335UL, 2925823809UL, 4133578805UL, 218104493UL, 2798390374UL, 1998600344UL, 1109346044UL, 1716435313UL, 415435111UL, 1892535124UL, 2536620737UL, 1440068573UL, 481874870UL, 142128108UL, 329082740UL, 2077118779UL, 2858045339UL, 4068162251UL, 115593872UL, 2644000449UL, 3550167006UL, 3728768059UL, 1772423685UL, +2504624145UL, 2140118619UL, 1412607307UL, 4081166331UL, 154438218UL, 1652901877UL, 3804911318UL, 3142799969UL, 3154073676UL, 3112018078UL, 2757873595UL, 50297646UL, 2855791484UL, 793851407UL, 507785167UL, 263713916UL, 3324588195UL, 3291978358UL, 1584226715UL, 2546417990UL, 450747961UL, 3455625012UL, 2706009093UL, 1788578194UL, 4030171132UL, 2610979903UL, 3835380965UL, 4269115622UL, 2180305819UL, 2646894726UL, 716649335UL, 2607142354UL, +853428184UL, 2436760738UL, 4190071217UL, 2754423535UL, 456808691UL, 4082489821UL, 741976046UL, 267559495UL, 1591532642UL, 2722205042UL, 3203248679UL, 147312102UL, 2772368222UL, 1412987047UL, 1950543946UL, 1932341300UL, 898396308UL, 1837129999UL, 3113914292UL, 428616392UL, 3141601915UL, 276087167UL, 1887389351UL, 757801450UL, 963534966UL, 2745818074UL, 1442953464UL, 3802648347UL, 223728071UL, 229039300UL, 1338125300UL, 3642174036UL, +2794462634UL, 2326349851UL, 206115203UL, 3577092599UL, 627103363UL, 552173564UL, 4142604459UL, 1492461846UL, 583522272UL, 189323282UL, 1217612313UL, 73550248UL, 3552211807UL, 2757269706UL, 2392210091UL, 3032922600UL, 3573904125UL, 810640644UL, 2632631469UL, 3085332665UL, 3775619904UL, 2563291734UL, 922608790UL, 4043427793UL, 1803743084UL, 3112116579UL, 522940594UL, 1785093944UL, 2613871529UL, 3810037031UL, 1765642390UL, 534554747UL, +3528050076UL, 2264349344UL, 1680024716UL, 2112340059UL, 3387475367UL, 3295682653UL, 75966494UL, 3907378472UL, 2636491350UL, 2176128529UL, 3574915532UL, 2372987046UL, 2604001339UL, 3893075234UL, 3495918635UL, 1280296085UL, 534929913UL, 3660102574UL, 2030233939UL, 2759207091UL, 299776535UL, 987575186UL, 2566932710UL, 1566181275UL, 3127827248UL, 3874691533UL, 3731513754UL, 2581732444UL, 279715551UL, 809690877UL, 3100791084UL, 2185866850UL, +1495277039UL, 3417305339UL, 2858903785UL, 1310351481UL, 4198538376UL, 2370669734UL, 391683868UL, 3933465331UL, 2749085130UL, 1400216510UL, 1864988335UL, 2925823809UL, 4133578805UL, 3352814594UL, 2798390374UL, 1998600344UL, 1109346044UL, 1716435313UL, 1571752941UL, 1892535124UL, 2536620737UL, 1440068573UL, 481874870UL, 2485033697UL, 329082740UL, 2077118779UL, 2858045339UL, 4068162251UL, 3837440666UL, 2644000449UL, 3550167006UL, 3728768059UL, +1772423685UL, 1176559812UL, 2140118619UL, 1412607307UL, 4081166331UL, 154438218UL, 2902622972UL, 3804911318UL, 3142799969UL, 3154073676UL, 3112018078UL, 2403391233UL, 50297646UL, 2855791484UL, 793851407UL, 507785167UL, 2351826747UL, 3324588195UL, 3291978358UL, 1584226715UL, 2546417990UL, 746876926UL, 3455625012UL, 2706009093UL, 1788578194UL, 4030171132UL, 3779307353UL, 3835380965UL, 4269115622UL, 2180305819UL, 2646894726UL, 2602235234UL, +2607142354UL, 853428184UL, 2436760738UL, 4190071217UL, 2066757692UL, 456808691UL, 4082489821UL, 741976046UL, 267559495UL, 3001080633UL, 2722205042UL, 3203248679UL, 147312102UL, 2772368222UL, 89950260UL, 1950543946UL, 1932341300UL, 898396308UL, 1837129999UL, 947911286UL, 428616392UL, 3141601915UL, 276087167UL, 1887389351UL, 2583987247UL, 963534966UL, 2745818074UL, 1442953464UL, 3802648347UL, 4229124441UL, 229039300UL, 1338125300UL, +3642174036UL, 2794462634UL, 2472155633UL, 206115203UL, 3577092599UL, 627103363UL, 552173564UL, 2586882739UL, 1492461846UL, 583522272UL, 189323282UL, 1217612313UL, 3501549884UL, 3552211807UL, 2757269706UL, 2392210091UL, 3032922600UL, 740675778UL, 810640644UL, 2632631469UL, 3085332665UL, 3775619904UL, 3643289881UL, 922608790UL, 4043427793UL, 1803743084UL, 3112116579UL, 2213337398UL, 1785093944UL, 2613871529UL, 3810037031UL, 1765642390UL, +762472016UL, 3528050076UL, 2264349344UL, 1680024716UL, 2112340059UL, 1372272974UL, 3295682653UL, 75966494UL, 3907378472UL, 2636491350UL, 3117471955UL, 3574915532UL, 2372987046UL, 2604001339UL, 3893075234UL, 915576383UL, 1280296085UL, 534929913UL, 3660102574UL, 2030233939UL, 346368350UL, 299776535UL, 987575186UL, 2566932710UL, 1566181275UL, 3535223896UL, 3874691533UL, 3731513754UL, 2581732444UL, 279715551UL, 2456894951UL, 3100791084UL, +2185866850UL, 1495277039UL, 3417305339UL, 1618871086UL, 1310351481UL, 4198538376UL, 2370669734UL, 391683868UL, 2009676005UL, 2749085130UL, 1400216510UL, 1864988335UL, 2925823809UL, 58955107UL, 3352814594UL, 2798390374UL, 1998600344UL, 1109346044UL, 3273979614UL, 1571752941UL, 1892535124UL, 2536620737UL, 1440068573UL, 1174168447UL, 2485033697UL, 329082740UL, 2077118779UL, 2858045339UL, 4062921629UL, 3837440666UL, 2644000449UL, 3550167006UL, +3728768059UL, 2642133401UL, 1176559812UL, 2140118619UL, 1412607307UL, 4081166331UL, 3124905304UL, 2902622972UL, 3804911318UL, 3142799969UL, 3154073676UL, 1449454613UL, 2403391233UL, 50297646UL, 2855791484UL, 793851407UL, 3514201526UL, 2351826747UL, 3324588195UL, 3291978358UL, 1584226715UL, 3636681672UL, 746876926UL, 3455625012UL, 2706009093UL, 1788578194UL, 3451519459UL, 3779307353UL, 3835380965UL, 4269115622UL, 2180305819UL, 3987989524UL, +2602235234UL, 2607142354UL, 853428184UL, 2436760738UL, 2151617107UL, 2066757692UL, 456808691UL, 4082489821UL, 741976046UL, 3590081269UL, 3001080633UL, 2722205042UL, 3203248679UL, 147312102UL, 3432947806UL, 89950260UL, 1950543946UL, 1932341300UL, 898396308UL, 3828432864UL, 947911286UL, 428616392UL, 3141601915UL, 276087167UL, 2517666433UL, 2583987247UL, 963534966UL, 2745818074UL, 1442953464UL, 2223986807UL, 4229124441UL, 229039300UL, +1338125300UL, 3642174036UL, 1053796945UL, 2472155633UL, 206115203UL, 3577092599UL, 627103363UL, 1113276084UL, 2586882739UL, 1492461846UL, 583522272UL, 189323282UL, 1490604990UL, 3501549884UL, 3552211807UL, 2757269706UL, 2392210091UL, 3545407532UL, 740675778UL, 810640644UL, 2632631469UL, 3085332665UL, 755862267UL, 3643289881UL, 922608790UL, 4043427793UL, 1803743084UL, 1954166630UL, 2213337398UL, 1785093944UL, 2613871529UL, 3810037031UL, +3042935707UL, 3162182177UL, 2791346436UL, 1901925289UL, 863100941UL, 3367519168UL, 1972623238UL, 3664303070UL, 604922059UL, 3026817982UL, 1436412310UL, 4096180631UL, 1597561857UL, 4206212303UL, 4127914332UL, 3228677359UL, 3985733659UL, 3597290113UL, 4251197894UL, 3451370603UL, 609679338UL, 3360835257UL, 1372239885UL, 638572328UL, 3806422284UL, 3974147336UL, 1804280837UL, 4209089291UL, 2021797469UL, 3557188838UL, 409727186UL, 2114649178UL, +687702120UL, 2542445992UL, 1235991799UL, 460479179UL, 2008348175UL, 887884478UL, 3942327811UL, 2999928223UL, 4171339789UL, 2286339235UL, 1293442231UL, 1575942850UL, 76122475UL, 1440527701UL, 2006558403UL, 1544148172UL, 895899367UL, 681826913UL, 4094701935UL, 3995413790UL, 1027509154UL, 2264990896UL, 1938238113UL, 213430250UL, 222469320UL, 609726517UL, 3581538106UL, 492802663UL, 120480843UL, 1720004062UL, 1132674507UL, 911082758UL, +2909148131UL, 566658805UL, 3964114445UL, 3483602509UL, 1793438750UL, 165562604UL, 3641830063UL, 2394205521UL, 3404874822UL, 1672998096UL, 916151953UL, 1141264477UL, 3171661340UL, 3803396219UL, 3018337382UL, 1863902683UL, 2474641928UL, 3250365071UL, 3897886220UL, 1219701051UL, 51332576UL, 1358614881UL, 1707407492UL, 3670647816UL, 923357625UL, 343687395UL, 3991339686UL, 3913575403UL, 1267727936UL, 4001357856UL, 3820224848UL, 2942896724UL, +3505936742UL, 1403285299UL, 1992762049UL, 567748449UL, 2202721585UL, 2781324216UL, 1724850068UL, 2408314541UL, 3073975813UL, 3992810029UL, 2475242354UL, 540562053UL, 2185198943UL, 3759352041UL, 3373885614UL, 1132999410UL, 1097554565UL, 4089342358UL, 3239542922UL, 2451748646UL, 407290679UL, 3188103200UL, 1708016248UL, 26848241UL, 2796711130UL, 3090711568UL, 4068389322UL, 3420916085UL, 3137567033UL, 2877819818UL, 22133454UL, 4629160UL, +3703695249UL, 1920151708UL, 1175452162UL, 130015299UL, 3331834713UL, 1099225384UL, 689254331UL, 1851083761UL, 2654970209UL, 3259297936UL, 3742819314UL, 3524284766UL, 2291819083UL, 3494031861UL, 16242889UL, 3545082774UL, 1997878108UL, 777447699UL, 4244916543UL, 3508640253UL, 3782278393UL, 2107258964UL, 2139074576UL, 1383217899UL, 2337934322UL, 3181899620UL, 1285955765UL, 2989610020UL, 3326862146UL, 1168587380UL, 801203532UL, 3020809957UL, +}, +{ +3810471203UL, 1017064446UL, 1595207573UL, 441087832UL, 3326746890UL, 3294064431UL, 167972517UL, 3625210015UL, 1011845006UL, 2980240819UL, 1778354660UL, 3041730987UL, 1598611350UL, 2015169745UL, 2321724978UL, 3390812967UL, 2432904511UL, 113261909UL, 3957193232UL, 3806115908UL, 2965828929UL, 2035392295UL, 3500116619UL, 2881232416UL, 1672212265UL, 1607201428UL, 425148945UL, 1262591961UL, 2221781268UL, 4215047456UL, 2148245850UL, 2787488981UL, +1077262192UL, 2085467561UL, 3053954888UL, 3584435116UL, 3013084787UL, 287099941UL, 1290407232UL, 4078552287UL, 2658945475UL, 4251530898UL, 2403086478UL, 2884923598UL, 3545110453UL, 4105390090UL, 343200643UL, 3189888821UL, 4086304363UL, 3466483195UL, 259435633UL, 2846377387UL, 497258846UL, 272775541UL, 985737911UL, 2957688879UL, 2180784344UL, 3434619542UL, 3643384838UL, 2228652440UL, 3107480718UL, 2208729807UL, 596436263UL, 3255120711UL, +3248886970UL, 519242965UL, 602979109UL, 1619614UL, 1391563565UL, 56262588UL, 1584463910UL, 1849038201UL, 728022295UL, 848624947UL, 1813827408UL, 428214945UL, 1246345586UL, 4213351865UL, 168985863UL, 456608054UL, 4277869380UL, 3886828599UL, 2264054549UL, 3110967170UL, 3138175314UL, 2649164828UL, 3369378320UL, 3648350039UL, 3524848759UL, 1468470706UL, 3558859222UL, 2669673235UL, 831851874UL, 4285651092UL, 4224147373UL, 1088456706UL, +231954609UL, 3118005852UL, 225508069UL, 883105389UL, 856371341UL, 2001356578UL, 639336670UL, 2363501707UL, 3622399552UL, 4024065226UL, 1093546838UL, 4263608561UL, 1852072422UL, 425195042UL, 2441102396UL, 296426333UL, 384641750UL, 3559334435UL, 1757327033UL, 1016016207UL, 3595686646UL, 24777793UL, 623926105UL, 2169195923UL, 1779396793UL, 646997837UL, 1459728476UL, 2644865980UL, 1994581089UL, 3956278544UL, 919592580UL, 2153558858UL, +2029633394UL, 3837501009UL, 4016560170UL, 484838096UL, 3652199054UL, 1971790561UL, 605295089UL, 637470291UL, 278970544UL, 3574824693UL, 295866521UL, 1755035156UL, 2542341803UL, 1588716357UL, 1502596918UL, 4124554133UL, 3547049843UL, 1768033045UL, 1531734630UL, 101448323UL, 3233017580UL, 1793222944UL, 3187853500UL, 186000900UL, 803444571UL, 2820254958UL, 2009384608UL, 2384668855UL, 2222812920UL, 633608665UL, 2028480056UL, 1258028235UL, +545095949UL, 3810471203UL, 1017064446UL, 1595207573UL, 441087832UL, 899068662UL, 3294064431UL, 167972517UL, 3625210015UL, 1011845006UL, 3951305793UL, 1778354660UL, 3041730987UL, 1598611350UL, 2015169745UL, 1885149424UL, 3390812967UL, 2432904511UL, 113261909UL, 3957193232UL, 3953443155UL, 2965828929UL, 2035392295UL, 3500116619UL, 2881232416UL, 329153573UL, 1607201428UL, 425148945UL, 1262591961UL, 2221781268UL, 78028761UL, 2148245850UL, +2787488981UL, 1077262192UL, 2085467561UL, 647235899UL, 3584435116UL, 3013084787UL, 287099941UL, 1290407232UL, 1467385694UL, 2658945475UL, 4251530898UL, 2403086478UL, 2884923598UL, 3489351040UL, 4105390090UL, 343200643UL, 3189888821UL, 4086304363UL, 3521512280UL, 259435633UL, 2846377387UL, 497258846UL, 272775541UL, 1367093111UL, 2957688879UL, 2180784344UL, 3434619542UL, 3643384838UL, 411877686UL, 3107480718UL, 2208729807UL, 596436263UL, +3255120711UL, 584605030UL, 519242965UL, 602979109UL, 1619614UL, 1391563565UL, 3902518209UL, 1584463910UL, 1849038201UL, 728022295UL, 848624947UL, 1932969318UL, 428214945UL, 1246345586UL, 4213351865UL, 168985863UL, 2770345237UL, 4277869380UL, 3886828599UL, 2264054549UL, 3110967170UL, 2953581033UL, 2649164828UL, 3369378320UL, 3648350039UL, 3524848759UL, 2380353977UL, 3558859222UL, 2669673235UL, 831851874UL, 4285651092UL, 1214052447UL, +1088456706UL, 231954609UL, 3118005852UL, 225508069UL, 1766983646UL, 856371341UL, 2001356578UL, 639336670UL, 2363501707UL, 1782816591UL, 4024065226UL, 1093546838UL, 4263608561UL, 1852072422UL, 1149716600UL, 2441102396UL, 296426333UL, 384641750UL, 3559334435UL, 2391309970UL, 1016016207UL, 3595686646UL, 24777793UL, 623926105UL, 362098678UL, 1779396793UL, 646997837UL, 1459728476UL, 2644865980UL, 3238673748UL, 3956278544UL, 919592580UL, +2153558858UL, 2029633394UL, 115778559UL, 4016560170UL, 484838096UL, 3652199054UL, 1971790561UL, 737357475UL, 637470291UL, 278970544UL, 3574824693UL, 295866521UL, 3989745853UL, 2542341803UL, 1588716357UL, 1502596918UL, 4124554133UL, 3016849744UL, 1768033045UL, 1531734630UL, 101448323UL, 3233017580UL, 4157527581UL, 3187853500UL, 186000900UL, 803444571UL, 2820254958UL, 1980528062UL, 2384668855UL, 2222812920UL, 633608665UL, 2028480056UL, +3166710281UL, 545095949UL, 3810471203UL, 1017064446UL, 1595207573UL, 693962828UL, 899068662UL, 3294064431UL, 167972517UL, 3625210015UL, 1486040398UL, 3951305793UL, 1778354660UL, 3041730987UL, 1598611350UL, 2859363132UL, 1885149424UL, 3390812967UL, 2432904511UL, 113261909UL, 664880478UL, 3953443155UL, 2965828929UL, 2035392295UL, 3500116619UL, 558081801UL, 329153573UL, 1607201428UL, 425148945UL, 1262591961UL, 3716247699UL, 78028761UL, +2148245850UL, 2787488981UL, 1077262192UL, 4206362947UL, 647235899UL, 3584435116UL, 3013084787UL, 287099941UL, 2536781098UL, 1467385694UL, 2658945475UL, 4251530898UL, 2403086478UL, 3075072413UL, 3489351040UL, 4105390090UL, 343200643UL, 3189888821UL, 2540485172UL, 3521512280UL, 259435633UL, 2846377387UL, 497258846UL, 2442427327UL, 1367093111UL, 2957688879UL, 2180784344UL, 3434619542UL, 1593967423UL, 411877686UL, 3107480718UL, 2208729807UL, +596436263UL, 1048686529UL, 584605030UL, 519242965UL, 602979109UL, 1619614UL, 2072745381UL, 3902518209UL, 1584463910UL, 1849038201UL, 728022295UL, 846033949UL, 1932969318UL, 428214945UL, 1246345586UL, 4213351865UL, 1066373275UL, 2770345237UL, 4277869380UL, 3886828599UL, 2264054549UL, 1877859690UL, 2953581033UL, 2649164828UL, 3369378320UL, 3648350039UL, 2537763389UL, 2380353977UL, 3558859222UL, 2669673235UL, 831851874UL, 522748140UL, +1214052447UL, 1088456706UL, 231954609UL, 3118005852UL, 1381269315UL, 1766983646UL, 856371341UL, 2001356578UL, 639336670UL, 667275675UL, 1782816591UL, 4024065226UL, 1093546838UL, 4263608561UL, 2057337961UL, 1149716600UL, 2441102396UL, 296426333UL, 384641750UL, 340523210UL, 2391309970UL, 1016016207UL, 3595686646UL, 24777793UL, 3094832341UL, 362098678UL, 1779396793UL, 646997837UL, 1459728476UL, 1169681568UL, 3238673748UL, 3956278544UL, +919592580UL, 2153558858UL, 388335108UL, 115778559UL, 4016560170UL, 484838096UL, 3652199054UL, 1764858181UL, 737357475UL, 637470291UL, 278970544UL, 3574824693UL, 3671458900UL, 3989745853UL, 2542341803UL, 1588716357UL, 1502596918UL, 2102871406UL, 3016849744UL, 1768033045UL, 1531734630UL, 101448323UL, 3964942332UL, 4157527581UL, 3187853500UL, 186000900UL, 803444571UL, 3425652083UL, 1980528062UL, 2384668855UL, 2222812920UL, 633608665UL, +3035373876UL, 3166710281UL, 545095949UL, 3810471203UL, 1017064446UL, 669282349UL, 693962828UL, 899068662UL, 3294064431UL, 167972517UL, 2007256988UL, 1486040398UL, 3951305793UL, 1778354660UL, 3041730987UL, 2827768941UL, 2859363132UL, 1885149424UL, 3390812967UL, 2432904511UL, 3700915653UL, 664880478UL, 3953443155UL, 2965828929UL, 2035392295UL, 1461208330UL, 558081801UL, 329153573UL, 1607201428UL, 425148945UL, 1700881129UL, 3716247699UL, +78028761UL, 2148245850UL, 2787488981UL, 2706775080UL, 4206362947UL, 647235899UL, 3584435116UL, 3013084787UL, 2958545221UL, 2536781098UL, 1467385694UL, 2658945475UL, 4251530898UL, 2241012567UL, 3075072413UL, 3489351040UL, 4105390090UL, 343200643UL, 490164649UL, 2540485172UL, 3521512280UL, 259435633UL, 2846377387UL, 4073611831UL, 2442427327UL, 1367093111UL, 2957688879UL, 2180784344UL, 1835510773UL, 1593967423UL, 411877686UL, 3107480718UL, +2208729807UL, 3306732468UL, 1048686529UL, 584605030UL, 519242965UL, 602979109UL, 2978864605UL, 2072745381UL, 3902518209UL, 1584463910UL, 1849038201UL, 3284115169UL, 846033949UL, 1932969318UL, 428214945UL, 1246345586UL, 194166002UL, 1066373275UL, 2770345237UL, 4277869380UL, 3886828599UL, 1874087886UL, 1877859690UL, 2953581033UL, 2649164828UL, 3369378320UL, 4145454028UL, 2537763389UL, 2380353977UL, 3558859222UL, 2669673235UL, 739345884UL, +522748140UL, 1214052447UL, 1088456706UL, 231954609UL, 3605603781UL, 1381269315UL, 1766983646UL, 856371341UL, 2001356578UL, 2049940324UL, 667275675UL, 1782816591UL, 4024065226UL, 1093546838UL, 152524382UL, 2057337961UL, 1149716600UL, 2441102396UL, 296426333UL, 3195130788UL, 340523210UL, 2391309970UL, 1016016207UL, 3595686646UL, 180492441UL, 3094832341UL, 362098678UL, 1779396793UL, 646997837UL, 2458167607UL, 1169681568UL, 3238673748UL, +3956278544UL, 919592580UL, 3421005218UL, 388335108UL, 115778559UL, 4016560170UL, 484838096UL, 2649676374UL, 1764858181UL, 737357475UL, 637470291UL, 278970544UL, 2236401278UL, 3671458900UL, 3989745853UL, 2542341803UL, 1588716357UL, 1241570134UL, 2102871406UL, 3016849744UL, 1768033045UL, 1531734630UL, 1765654724UL, 3964942332UL, 4157527581UL, 3187853500UL, 186000900UL, 2189716659UL, 3425652083UL, 1980528062UL, 2384668855UL, 2222812920UL, +3955466207UL, 2426547616UL, 3846752458UL, 3015538636UL, 2342593365UL, 3613176865UL, 3484860981UL, 4278370194UL, 1979143878UL, 1159739458UL, 3714038404UL, 396530346UL, 3276617756UL, 3293940597UL, 4050183149UL, 1418571985UL, 402563753UL, 2702853013UL, 2289900621UL, 2267058511UL, 3482161995UL, 3375026019UL, 1988640267UL, 3674438074UL, 4124612310UL, 1057883705UL, 434730475UL, 3210959778UL, 4102029739UL, 2140938750UL, 3176753074UL, 2356971512UL, +3969685288UL, 1556275580UL, 2648433428UL, 3959375381UL, 478841344UL, 1496991528UL, 3309714981UL, 569990368UL, 3660587501UL, 2550379574UL, 1177519842UL, 2652707373UL, 543943404UL, 1912551128UL, 2278132032UL, 1484596780UL, 3570913985UL, 2982401320UL, 1413776035UL, 3177275459UL, 3036211597UL, 1091740466UL, 3448424311UL, 1445187645UL, 3205024875UL, 3135795254UL, 823738729UL, 3742134467UL, 4066657438UL, 1226311678UL, 2403605393UL, 537573634UL, +3457409768UL, 1940233423UL, 1761431281UL, 1129427309UL, 2443661283UL, 3200814257UL, 4094866249UL, 2666869754UL, 604785127UL, 2213464116UL, 3002782918UL, 468024929UL, 2490681314UL, 3666681384UL, 1583346053UL, 3049668798UL, 3592153237UL, 2573082448UL, 3082970021UL, 1461796708UL, 832526980UL, 3728763274UL, 355291229UL, 4029588456UL, 832358279UL, 2125298737UL, 3681181038UL, 3245535160UL, 1333342738UL, 1868897492UL, 446790068UL, 1278093154UL, +2090118615UL, 4158925515UL, 4062165914UL, 822726809UL, 1154960183UL, 286518382UL, 1170424276UL, 2554691236UL, 3674133415UL, 2765714969UL, 2330865375UL, 1908307334UL, 3537287082UL, 410252600UL, 3977128218UL, 424210327UL, 2919071615UL, 2715518134UL, 64568844UL, 480972649UL, 2488797168UL, 1302817038UL, 2213995265UL, 4229997295UL, 2200797852UL, 109368057UL, 3033807022UL, 1907400078UL, 645977948UL, 1410909090UL, 3700787906UL, 3375062371UL, +629087832UL, 1344281719UL, 4249981139UL, 3457543297UL, 1218556849UL, 864222854UL, 1458445945UL, 914545469UL, 3451164212UL, 1088025757UL, 1129933985UL, 953788883UL, 2406172924UL, 170364546UL, 3505490646UL, 1027553899UL, 2864067776UL, 436854871UL, 1342782209UL, 761167471UL, 2660173631UL, 4159507498UL, 4172028400UL, 2442254644UL, 2110123720UL, 2315991253UL, 873066601UL, 1725470559UL, 3831299052UL, 678672031UL, 1585431329UL, 3495750550UL, +}, +{ +1998393432UL, 2665389278UL, 3989307699UL, 3267631636UL, 3861682977UL, 3243522970UL, 1243992413UL, 2200497260UL, 3821883021UL, 4187123083UL, 3451270040UL, 3044132745UL, 2101287249UL, 2340839784UL, 227040990UL, 1724350416UL, 3228881240UL, 3123386528UL, 4279362126UL, 3098224464UL, 2635534069UL, 3622906431UL, 206207480UL, 1894245533UL, 2152374527UL, 1011223653UL, 7271757UL, 2972858087UL, 207942127UL, 3355362797UL, 2593296740UL, 174093751UL, +3713822176UL, 4212355586UL, 3335605224UL, 1171716408UL, 2867257989UL, 1522213957UL, 2016192462UL, 4229688395UL, 2174928148UL, 1468226225UL, 3938290338UL, 493240317UL, 3229423344UL, 2585475729UL, 3112454413UL, 1881171707UL, 2555908056UL, 1997546352UL, 380428329UL, 3341885423UL, 3307510279UL, 3519476676UL, 3613100811UL, 2555826262UL, 109341943UL, 2382715395UL, 3883409616UL, 1593551879UL, 2163678014UL, 3379783137UL, 2810374300UL, 1516064864UL, +561144874UL, 316017838UL, 1899237567UL, 70857401UL, 3435185465UL, 4234661323UL, 2580352177UL, 32879620UL, 4171670150UL, 1986234067UL, 3589478191UL, 2073132526UL, 2603712175UL, 377997975UL, 2474419397UL, 3110698341UL, 812664089UL, 1778922726UL, 1686111212UL, 972784138UL, 3936486236UL, 2711468739UL, 423435866UL, 1661961159UL, 802312780UL, 1868728136UL, 1760295704UL, 3357409828UL, 215039860UL, 683184627UL, 4019111064UL, 3609261689UL, +2167554309UL, 1831085281UL, 3389357802UL, 4193421575UL, 628277197UL, 2900207619UL, 993609502UL, 3429627083UL, 2636466084UL, 3652352199UL, 1780133580UL, 1670387713UL, 4086070210UL, 4004540729UL, 783029246UL, 2165667566UL, 1739001057UL, 377639972UL, 1102689625UL, 1945278055UL, 3941185940UL, 3685368326UL, 1881761572UL, 2201338934UL, 801752UL, 2729497735UL, 492844690UL, 2998826141UL, 3844964457UL, 3679088359UL, 2196391660UL, 4222269404UL, +357321611UL, 3727170055UL, 1819614072UL, 2348798457UL, 4294366646UL, 1952884323UL, 3574345216UL, 2040734807UL, 232392443UL, 4183498179UL, 2614866055UL, 112120292UL, 3624018350UL, 3340709877UL, 3097507723UL, 1268833488UL, 3570501956UL, 3338260086UL, 293812421UL, 3683058169UL, 1147960351UL, 283731890UL, 2171233479UL, 1830154455UL, 4036602681UL, 1996981699UL, 132803834UL, 40256165UL, 2158110401UL, 3575159090UL, 3196553513UL, 3559872992UL, +3402884675UL, 1998393432UL, 2665389278UL, 3989307699UL, 3267631636UL, 3617519767UL, 3243522970UL, 1243992413UL, 2200497260UL, 3821883021UL, 3715729085UL, 3451270040UL, 3044132745UL, 2101287249UL, 2340839784UL, 3173635549UL, 1724350416UL, 3228881240UL, 3123386528UL, 4279362126UL, 2287520039UL, 2635534069UL, 3622906431UL, 206207480UL, 1894245533UL, 96723416UL, 1011223653UL, 7271757UL, 2972858087UL, 207942127UL, 1668335352UL, 2593296740UL, +174093751UL, 3713822176UL, 4212355586UL, 49226793UL, 1171716408UL, 2867257989UL, 1522213957UL, 2016192462UL, 118712412UL, 2174928148UL, 1468226225UL, 3938290338UL, 493240317UL, 3788174304UL, 2585475729UL, 3112454413UL, 1881171707UL, 2555908056UL, 3351139844UL, 380428329UL, 3341885423UL, 3307510279UL, 3519476676UL, 1368994724UL, 2555826262UL, 109341943UL, 2382715395UL, 3883409616UL, 1561509458UL, 2163678014UL, 3379783137UL, 2810374300UL, +1516064864UL, 2313252274UL, 316017838UL, 1899237567UL, 70857401UL, 3435185465UL, 2585770746UL, 2580352177UL, 32879620UL, 4171670150UL, 1986234067UL, 3317983509UL, 2073132526UL, 2603712175UL, 377997975UL, 2474419397UL, 908728599UL, 812664089UL, 1778922726UL, 1686111212UL, 972784138UL, 1992540005UL, 2711468739UL, 423435866UL, 1661961159UL, 802312780UL, 907108769UL, 1760295704UL, 3357409828UL, 215039860UL, 683184627UL, 2806826652UL, +3609261689UL, 2167554309UL, 1831085281UL, 3389357802UL, 2755692689UL, 628277197UL, 2900207619UL, 993609502UL, 3429627083UL, 3605915742UL, 3652352199UL, 1780133580UL, 1670387713UL, 4086070210UL, 3717326627UL, 783029246UL, 2165667566UL, 1739001057UL, 377639972UL, 2355216626UL, 1945278055UL, 3941185940UL, 3685368326UL, 1881761572UL, 4024097818UL, 801752UL, 2729497735UL, 492844690UL, 2998826141UL, 2719601647UL, 3679088359UL, 2196391660UL, +4222269404UL, 357321611UL, 1319821972UL, 1819614072UL, 2348798457UL, 4294366646UL, 1952884323UL, 3573866689UL, 2040734807UL, 232392443UL, 4183498179UL, 2614866055UL, 440744432UL, 3624018350UL, 3340709877UL, 3097507723UL, 1268833488UL, 224895395UL, 3338260086UL, 293812421UL, 3683058169UL, 1147960351UL, 3433425235UL, 2171233479UL, 1830154455UL, 4036602681UL, 1996981699UL, 2875889721UL, 40256165UL, 2158110401UL, 3575159090UL, 3196553513UL, +1094082574UL, 3402884675UL, 1998393432UL, 2665389278UL, 3989307699UL, 4068940467UL, 3617519767UL, 3243522970UL, 1243992413UL, 2200497260UL, 441678457UL, 3715729085UL, 3451270040UL, 3044132745UL, 2101287249UL, 2181502237UL, 3173635549UL, 1724350416UL, 3228881240UL, 3123386528UL, 1968352124UL, 2287520039UL, 2635534069UL, 3622906431UL, 206207480UL, 2065093599UL, 96723416UL, 1011223653UL, 7271757UL, 2972858087UL, 1094044749UL, 1668335352UL, +2593296740UL, 174093751UL, 3713822176UL, 2887397643UL, 49226793UL, 1171716408UL, 2867257989UL, 1522213957UL, 984348433UL, 118712412UL, 2174928148UL, 1468226225UL, 3938290338UL, 2279430036UL, 3788174304UL, 2585475729UL, 3112454413UL, 1881171707UL, 4247636500UL, 3351139844UL, 380428329UL, 3341885423UL, 3307510279UL, 2887754196UL, 1368994724UL, 2555826262UL, 109341943UL, 2382715395UL, 2836761616UL, 1561509458UL, 2163678014UL, 3379783137UL, +2810374300UL, 1635278016UL, 2313252274UL, 316017838UL, 1899237567UL, 70857401UL, 3481535811UL, 2585770746UL, 2580352177UL, 32879620UL, 4171670150UL, 2248003250UL, 3317983509UL, 2073132526UL, 2603712175UL, 377997975UL, 3286162818UL, 908728599UL, 812664089UL, 1778922726UL, 1686111212UL, 4024815755UL, 1992540005UL, 2711468739UL, 423435866UL, 1661961159UL, 2257259057UL, 907108769UL, 1760295704UL, 3357409828UL, 215039860UL, 3917391198UL, +2806826652UL, 3609261689UL, 2167554309UL, 1831085281UL, 4238043113UL, 2755692689UL, 628277197UL, 2900207619UL, 993609502UL, 2036092353UL, 3605915742UL, 3652352199UL, 1780133580UL, 1670387713UL, 118446953UL, 3717326627UL, 783029246UL, 2165667566UL, 1739001057UL, 203160626UL, 2355216626UL, 1945278055UL, 3941185940UL, 3685368326UL, 546361979UL, 4024097818UL, 801752UL, 2729497735UL, 492844690UL, 1023017124UL, 2719601647UL, 3679088359UL, +2196391660UL, 4222269404UL, 621859651UL, 1319821972UL, 1819614072UL, 2348798457UL, 4294366646UL, 1114888560UL, 3573866689UL, 2040734807UL, 232392443UL, 4183498179UL, 3959504609UL, 440744432UL, 3624018350UL, 3340709877UL, 3097507723UL, 3613295037UL, 224895395UL, 3338260086UL, 293812421UL, 3683058169UL, 1655305863UL, 3433425235UL, 2171233479UL, 1830154455UL, 4036602681UL, 3731384097UL, 2875889721UL, 40256165UL, 2158110401UL, 3575159090UL, +1847744924UL, 1094082574UL, 3402884675UL, 1998393432UL, 2665389278UL, 3781866777UL, 4068940467UL, 3617519767UL, 3243522970UL, 1243992413UL, 2723708256UL, 441678457UL, 3715729085UL, 3451270040UL, 3044132745UL, 4013832842UL, 2181502237UL, 3173635549UL, 1724350416UL, 3228881240UL, 2092292494UL, 1968352124UL, 2287520039UL, 2635534069UL, 3622906431UL, 3186333458UL, 2065093599UL, 96723416UL, 1011223653UL, 7271757UL, 649658033UL, 1094044749UL, +1668335352UL, 2593296740UL, 174093751UL, 4159420309UL, 2887397643UL, 49226793UL, 1171716408UL, 2867257989UL, 2590077953UL, 984348433UL, 118712412UL, 2174928148UL, 1468226225UL, 1065322711UL, 2279430036UL, 3788174304UL, 2585475729UL, 3112454413UL, 3932517386UL, 4247636500UL, 3351139844UL, 380428329UL, 3341885423UL, 1285273904UL, 2887754196UL, 1368994724UL, 2555826262UL, 109341943UL, 2318470582UL, 2836761616UL, 1561509458UL, 2163678014UL, +3379783137UL, 674658583UL, 1635278016UL, 2313252274UL, 316017838UL, 1899237567UL, 2192372173UL, 3481535811UL, 2585770746UL, 2580352177UL, 32879620UL, 300323274UL, 2248003250UL, 3317983509UL, 2073132526UL, 2603712175UL, 3086543917UL, 3286162818UL, 908728599UL, 812664089UL, 1778922726UL, 2263290659UL, 4024815755UL, 1992540005UL, 2711468739UL, 423435866UL, 819027349UL, 2257259057UL, 907108769UL, 1760295704UL, 3357409828UL, 1142221093UL, +3917391198UL, 2806826652UL, 3609261689UL, 2167554309UL, 4108155875UL, 4238043113UL, 2755692689UL, 628277197UL, 2900207619UL, 3041719497UL, 2036092353UL, 3605915742UL, 3652352199UL, 1780133580UL, 2397410862UL, 118446953UL, 3717326627UL, 783029246UL, 2165667566UL, 2721690354UL, 203160626UL, 2355216626UL, 1945278055UL, 3941185940UL, 2768842108UL, 546361979UL, 4024097818UL, 801752UL, 2729497735UL, 4045063232UL, 1023017124UL, 2719601647UL, +3679088359UL, 2196391660UL, 2666107451UL, 621859651UL, 1319821972UL, 1819614072UL, 2348798457UL, 3555102623UL, 1114888560UL, 3573866689UL, 2040734807UL, 232392443UL, 3359040541UL, 3959504609UL, 440744432UL, 3624018350UL, 3340709877UL, 1477919696UL, 3613295037UL, 224895395UL, 3338260086UL, 293812421UL, 4210187101UL, 1655305863UL, 3433425235UL, 2171233479UL, 1830154455UL, 4150241150UL, 3731384097UL, 2875889721UL, 40256165UL, 2158110401UL, +3350246687UL, 455561037UL, 2250400255UL, 3192153445UL, 3258870230UL, 1500391873UL, 4142878334UL, 1155955691UL, 1483275844UL, 4189436981UL, 323745948UL, 1976017426UL, 2804626790UL, 2717553615UL, 2315409034UL, 954508235UL, 3845175920UL, 3999878682UL, 1247696432UL, 1743319509UL, 2998248398UL, 3694350012UL, 4072006361UL, 191306987UL, 2816321878UL, 1324077734UL, 1083060006UL, 3406855480UL, 1619622379UL, 2160350UL, 3302238190UL, 3368021261UL, +3685228564UL, 3863934685UL, 771728612UL, 854205233UL, 2304696695UL, 421449207UL, 1265752117UL, 3852292419UL, 305345788UL, 1540622105UL, 1904883477UL, 833469256UL, 134406680UL, 3012455058UL, 4035477953UL, 2925192459UL, 1559200592UL, 3851612860UL, 718484562UL, 1377960276UL, 1586892849UL, 1361298269UL, 3417917896UL, 1281324499UL, 1012538763UL, 1350578667UL, 3946475598UL, 2982283954UL, 3548792804UL, 284542749UL, 1194648577UL, 3087899716UL, +3966595444UL, 2088330116UL, 3641652062UL, 327128507UL, 593906557UL, 1092448919UL, 2459189516UL, 4053392241UL, 3356198248UL, 2352376508UL, 470648997UL, 1017041256UL, 3234172340UL, 3928191489UL, 3266226858UL, 4219289150UL, 1229098319UL, 4275351308UL, 2720777751UL, 3566728718UL, 638322822UL, 2369792461UL, 2869492261UL, 3120083828UL, 1890399556UL, 3309991008UL, 3785452464UL, 4128660314UL, 3726791982UL, 167177896UL, 461294981UL, 3988638998UL, +2937794823UL, 3981029822UL, 1111681402UL, 2015965721UL, 7261806UL, 2669786265UL, 1083582734UL, 3270228881UL, 3892235938UL, 2695872715UL, 4246051290UL, 3214293333UL, 343604199UL, 3215604888UL, 661024127UL, 2931754053UL, 3787840039UL, 2053363765UL, 363432336UL, 112334132UL, 2871797223UL, 138911320UL, 3981126938UL, 2027332192UL, 1804730644UL, 590150270UL, 641538574UL, 6802174UL, 3551446076UL, 3908480472UL, 1004531022UL, 2097228524UL, +1919074232UL, 154482247UL, 121437972UL, 1215661323UL, 1178068273UL, 1097220699UL, 2823681422UL, 262636065UL, 2943371149UL, 1768780720UL, 3866040605UL, 1855991583UL, 3988248086UL, 629223947UL, 3380612330UL, 3552916762UL, 197596340UL, 573801686UL, 2049230598UL, 2910471867UL, 2686314264UL, 1726228846UL, 3516983332UL, 726840185UL, 1241204222UL, 2237574317UL, 70568042UL, 1932610099UL, 2221862221UL, 1510378092UL, 4050391637UL, 4077539568UL, +}, +{ +3872117793UL, 803220151UL, 70843412UL, 1661103032UL, 1976811457UL, 2186373604UL, 564259972UL, 1475436923UL, 2260980893UL, 4245534505UL, 1075107552UL, 3692990573UL, 370098873UL, 4045905424UL, 2420395420UL, 2332395402UL, 207483321UL, 622317750UL, 3004242500UL, 833623111UL, 3151161301UL, 1629139881UL, 352228793UL, 2439953368UL, 3183333619UL, 2703537080UL, 3218957129UL, 3164695888UL, 1741641842UL, 963394141UL, 4241612717UL, 1034476784UL, +2035880432UL, 3977821313UL, 1543311495UL, 3010014356UL, 1638490901UL, 2364265378UL, 3420329129UL, 333361555UL, 1133565821UL, 1450937015UL, 616059115UL, 3216393887UL, 3041978455UL, 3990855695UL, 1238628750UL, 512746184UL, 3256670217UL, 1616316512UL, 2791405051UL, 93474487UL, 2865892488UL, 1901471398UL, 2930857966UL, 2178431077UL, 2325598341UL, 3189256113UL, 1302432091UL, 808592927UL, 2945846737UL, 3487931071UL, 2018175258UL, 752981057UL, +1097082589UL, 1307115286UL, 175147508UL, 3611190164UL, 850238914UL, 3318706185UL, 199743319UL, 328621708UL, 3183670050UL, 3609998315UL, 4075306371UL, 3554549067UL, 2119566187UL, 1498503842UL, 1261870696UL, 2216745780UL, 950288337UL, 1117344941UL, 2150569143UL, 2899286760UL, 1594966374UL, 888858617UL, 35840654UL, 2829539211UL, 2511395669UL, 3607190544UL, 3278412778UL, 2249895907UL, 1320858068UL, 3576889788UL, 266766189UL, 1522426851UL, +1903494122UL, 1928370573UL, 2628132591UL, 3322025904UL, 220280169UL, 433606853UL, 1428961479UL, 986074592UL, 2128892987UL, 467697583UL, 1616913929UL, 325674890UL, 444442578UL, 649166208UL, 1689709565UL, 1493452467UL, 2222122038UL, 121114616UL, 2134348225UL, 3512035688UL, 1283058921UL, 4230441398UL, 3701238559UL, 337534132UL, 1418548715UL, 1190006478UL, 500654385UL, 1766924757UL, 1944680746UL, 940574010UL, 922744002UL, 186142284UL, +3131162902UL, 1693891092UL, 3031823448UL, 2143051534UL, 1429025284UL, 1487843160UL, 3606456133UL, 2079235652UL, 2447285474UL, 2669283767UL, 3232117829UL, 2490054343UL, 3225501736UL, 2911340385UL, 382319031UL, 1516937595UL, 622543191UL, 1388990570UL, 1749179860UL, 1924483707UL, 2593474505UL, 472539197UL, 122872799UL, 2586347240UL, 880588515UL, 4046335279UL, 1712182607UL, 4270737941UL, 1336703451UL, 3390078162UL, 382216945UL, 3733326081UL, +460422073UL, 3872117793UL, 803220151UL, 70843412UL, 1661103032UL, 250339760UL, 2186373604UL, 564259972UL, 1475436923UL, 2260980893UL, 657986735UL, 1075107552UL, 3692990573UL, 370098873UL, 4045905424UL, 3201950123UL, 2332395402UL, 207483321UL, 622317750UL, 3004242500UL, 3732213278UL, 3151161301UL, 1629139881UL, 352228793UL, 2439953368UL, 3572618926UL, 2703537080UL, 3218957129UL, 3164695888UL, 1741641842UL, 685933373UL, 4241612717UL, +1034476784UL, 2035880432UL, 3977821313UL, 3855995181UL, 3010014356UL, 1638490901UL, 2364265378UL, 3420329129UL, 2355603679UL, 1133565821UL, 1450937015UL, 616059115UL, 3216393887UL, 1733804102UL, 3990855695UL, 1238628750UL, 512746184UL, 3256670217UL, 2651059231UL, 2791405051UL, 93474487UL, 2865892488UL, 1901471398UL, 2113461797UL, 2178431077UL, 2325598341UL, 3189256113UL, 1302432091UL, 2986990416UL, 2945846737UL, 3487931071UL, 2018175258UL, +752981057UL, 2428033310UL, 1307115286UL, 175147508UL, 3611190164UL, 850238914UL, 1033628405UL, 199743319UL, 328621708UL, 3183670050UL, 3609998315UL, 4024297327UL, 3554549067UL, 2119566187UL, 1498503842UL, 1261870696UL, 290361143UL, 950288337UL, 1117344941UL, 2150569143UL, 2899286760UL, 168826051UL, 888858617UL, 35840654UL, 2829539211UL, 2511395669UL, 2890882060UL, 3278412778UL, 2249895907UL, 1320858068UL, 3576889788UL, 1794920145UL, +1522426851UL, 1903494122UL, 1928370573UL, 2628132591UL, 1251697758UL, 220280169UL, 433606853UL, 1428961479UL, 986074592UL, 2707115661UL, 467697583UL, 1616913929UL, 325674890UL, 444442578UL, 122781510UL, 1689709565UL, 1493452467UL, 2222122038UL, 121114616UL, 3425723636UL, 3512035688UL, 1283058921UL, 4230441398UL, 3701238559UL, 1646155473UL, 1418548715UL, 1190006478UL, 500654385UL, 1766924757UL, 3920475367UL, 940574010UL, 922744002UL, +186142284UL, 3131162902UL, 54639113UL, 3031823448UL, 2143051534UL, 1429025284UL, 1487843160UL, 4152687885UL, 2079235652UL, 2447285474UL, 2669283767UL, 3232117829UL, 1601035152UL, 3225501736UL, 2911340385UL, 382319031UL, 1516937595UL, 3508441679UL, 1388990570UL, 1749179860UL, 1924483707UL, 2593474505UL, 2835403456UL, 122872799UL, 2586347240UL, 880588515UL, 4046335279UL, 2958058367UL, 4270737941UL, 1336703451UL, 3390078162UL, 382216945UL, +450517882UL, 460422073UL, 3872117793UL, 803220151UL, 70843412UL, 2066343874UL, 250339760UL, 2186373604UL, 564259972UL, 1475436923UL, 1683787449UL, 657986735UL, 1075107552UL, 3692990573UL, 370098873UL, 2615082840UL, 3201950123UL, 2332395402UL, 207483321UL, 622317750UL, 2655424371UL, 3732213278UL, 3151161301UL, 1629139881UL, 352228793UL, 3236724760UL, 3572618926UL, 2703537080UL, 3218957129UL, 3164695888UL, 9775065UL, 685933373UL, +4241612717UL, 1034476784UL, 2035880432UL, 1621920075UL, 3855995181UL, 3010014356UL, 1638490901UL, 2364265378UL, 1509475888UL, 2355603679UL, 1133565821UL, 1450937015UL, 616059115UL, 3666188236UL, 1733804102UL, 3990855695UL, 1238628750UL, 512746184UL, 3900473826UL, 2651059231UL, 2791405051UL, 93474487UL, 2865892488UL, 222759186UL, 2113461797UL, 2178431077UL, 2325598341UL, 3189256113UL, 2505499508UL, 2986990416UL, 2945846737UL, 3487931071UL, +2018175258UL, 2766733928UL, 2428033310UL, 1307115286UL, 175147508UL, 3611190164UL, 1909211603UL, 1033628405UL, 199743319UL, 328621708UL, 3183670050UL, 1680331218UL, 4024297327UL, 3554549067UL, 2119566187UL, 1498503842UL, 3516256046UL, 290361143UL, 950288337UL, 1117344941UL, 2150569143UL, 3182619063UL, 168826051UL, 888858617UL, 35840654UL, 2829539211UL, 645798943UL, 2890882060UL, 3278412778UL, 2249895907UL, 1320858068UL, 1436708568UL, +1794920145UL, 1522426851UL, 1903494122UL, 1928370573UL, 3693049252UL, 1251697758UL, 220280169UL, 433606853UL, 1428961479UL, 3724415861UL, 2707115661UL, 467697583UL, 1616913929UL, 325674890UL, 1448052253UL, 122781510UL, 1689709565UL, 1493452467UL, 2222122038UL, 2177448198UL, 3425723636UL, 3512035688UL, 1283058921UL, 4230441398UL, 3050940272UL, 1646155473UL, 1418548715UL, 1190006478UL, 500654385UL, 1106232UL, 3920475367UL, 940574010UL, +922744002UL, 186142284UL, 4144806511UL, 54639113UL, 3031823448UL, 2143051534UL, 1429025284UL, 2067453848UL, 4152687885UL, 2079235652UL, 2447285474UL, 2669283767UL, 428527087UL, 1601035152UL, 3225501736UL, 2911340385UL, 382319031UL, 2565464472UL, 3508441679UL, 1388990570UL, 1749179860UL, 1924483707UL, 1737735237UL, 2835403456UL, 122872799UL, 2586347240UL, 880588515UL, 597822462UL, 2958058367UL, 4270737941UL, 1336703451UL, 3390078162UL, +2532634475UL, 450517882UL, 460422073UL, 3872117793UL, 803220151UL, 801648827UL, 2066343874UL, 250339760UL, 2186373604UL, 564259972UL, 3417948976UL, 1683787449UL, 657986735UL, 1075107552UL, 3692990573UL, 2235306692UL, 2615082840UL, 3201950123UL, 2332395402UL, 207483321UL, 699310933UL, 2655424371UL, 3732213278UL, 3151161301UL, 1629139881UL, 1152704006UL, 3236724760UL, 3572618926UL, 2703537080UL, 3218957129UL, 2726926336UL, 9775065UL, +685933373UL, 4241612717UL, 1034476784UL, 2398119652UL, 1621920075UL, 3855995181UL, 3010014356UL, 1638490901UL, 252854480UL, 1509475888UL, 2355603679UL, 1133565821UL, 1450937015UL, 2655911639UL, 3666188236UL, 1733804102UL, 3990855695UL, 1238628750UL, 1115900497UL, 3900473826UL, 2651059231UL, 2791405051UL, 93474487UL, 1862985957UL, 222759186UL, 2113461797UL, 2178431077UL, 2325598341UL, 4179075132UL, 2505499508UL, 2986990416UL, 2945846737UL, +3487931071UL, 564667776UL, 2766733928UL, 2428033310UL, 1307115286UL, 175147508UL, 1759077815UL, 1909211603UL, 1033628405UL, 199743319UL, 328621708UL, 2552816198UL, 1680331218UL, 4024297327UL, 3554549067UL, 2119566187UL, 2267805778UL, 3516256046UL, 290361143UL, 950288337UL, 1117344941UL, 2897506172UL, 3182619063UL, 168826051UL, 888858617UL, 35840654UL, 2035476068UL, 645798943UL, 2890882060UL, 3278412778UL, 2249895907UL, 3278449102UL, +1436708568UL, 1794920145UL, 1522426851UL, 1903494122UL, 1500763736UL, 3693049252UL, 1251697758UL, 220280169UL, 433606853UL, 3914497854UL, 3724415861UL, 2707115661UL, 467697583UL, 1616913929UL, 918435305UL, 1448052253UL, 122781510UL, 1689709565UL, 1493452467UL, 609575172UL, 2177448198UL, 3425723636UL, 3512035688UL, 1283058921UL, 3661181550UL, 3050940272UL, 1646155473UL, 1418548715UL, 1190006478UL, 1047301661UL, 1106232UL, 3920475367UL, +940574010UL, 922744002UL, 2510633517UL, 4144806511UL, 54639113UL, 3031823448UL, 2143051534UL, 3242814908UL, 2067453848UL, 4152687885UL, 2079235652UL, 2447285474UL, 736638210UL, 428527087UL, 1601035152UL, 3225501736UL, 2911340385UL, 1849570436UL, 2565464472UL, 3508441679UL, 1388990570UL, 1749179860UL, 84517579UL, 1737735237UL, 2835403456UL, 122872799UL, 2586347240UL, 4002124614UL, 597822462UL, 2958058367UL, 4270737941UL, 1336703451UL, +3078170472UL, 1186434751UL, 700631413UL, 1497890797UL, 1195347450UL, 2560167391UL, 1116697259UL, 1254138573UL, 747913260UL, 240954704UL, 3107512667UL, 360584144UL, 3422778960UL, 3516528389UL, 3301260366UL, 1254513537UL, 122269053UL, 1579582456UL, 873334104UL, 3918835024UL, 1731872444UL, 1974410416UL, 1811172641UL, 4172523062UL, 4092675777UL, 4124987343UL, 1936078756UL, 1757348689UL, 2694415512UL, 128641660UL, 1744777659UL, 3173116729UL, +983733754UL, 1430789547UL, 701906842UL, 3367232568UL, 3266433501UL, 3572590347UL, 1453272962UL, 2106553114UL, 993786201UL, 2149441250UL, 1295181065UL, 2962229026UL, 3709052556UL, 3255608941UL, 3677730029UL, 483873127UL, 102227292UL, 2626265293UL, 2018984578UL, 2266388762UL, 1191709548UL, 2152725916UL, 583672623UL, 2230473473UL, 1995194269UL, 1740347812UL, 2558095372UL, 3070195183UL, 3023333227UL, 2497183195UL, 1908755188UL, 773027539UL, +3646876518UL, 2272586839UL, 493318726UL, 2107067517UL, 2000805278UL, 2530829636UL, 3183628745UL, 677565332UL, 1497629423UL, 82094920UL, 2214054433UL, 2635367545UL, 470855467UL, 2184853389UL, 2942188934UL, 188335670UL, 3656661644UL, 1883526235UL, 3990873975UL, 1490784356UL, 4047548172UL, 3149642641UL, 3289988179UL, 2590918909UL, 2893039564UL, 2350687346UL, 4252624874UL, 15372456UL, 1614496594UL, 2364847678UL, 2604511825UL, 422365460UL, +4195174772UL, 3266964836UL, 2008671995UL, 54038434UL, 781948549UL, 1276017666UL, 2756376612UL, 2436825273UL, 1711863836UL, 3541493950UL, 3821378841UL, 1007557618UL, 345375815UL, 2081905201UL, 2227278118UL, 1185927141UL, 1082173792UL, 3567361925UL, 1940465859UL, 541632942UL, 1830210248UL, 3757851982UL, 775883450UL, 1666577465UL, 1004944607UL, 878440834UL, 2146344131UL, 4195798476UL, 370164841UL, 3649112729UL, 37066142UL, 2311278904UL, +1935745497UL, 2304799402UL, 4107299626UL, 1348526232UL, 2473609635UL, 3284032699UL, 2374292786UL, 1762329186UL, 857978496UL, 1039346432UL, 2621413355UL, 29961014UL, 3582263091UL, 4268542513UL, 3890612190UL, 3096173646UL, 2026544230UL, 3856142618UL, 2347115934UL, 319800326UL, 3255916105UL, 2430273059UL, 823505311UL, 874255188UL, 1401925393UL, 4203707857UL, 4259159566UL, 2606881118UL, 1978288664UL, 1447576038UL, 3860341401UL, 412510348UL, +}, +{ +4052471963UL, 683640040UL, 3043876021UL, 3466644483UL, 4222418025UL, 3035140128UL, 1466027937UL, 18198088UL, 3410320851UL, 3040963721UL, 488404231UL, 3157371815UL, 769336092UL, 3240417718UL, 808582581UL, 2075839263UL, 835026995UL, 3123726486UL, 3284240985UL, 1898453053UL, 3606056482UL, 512836002UL, 2715428547UL, 4182302879UL, 1644882480UL, 3160187826UL, 390292489UL, 980889545UL, 2776206633UL, 2482799995UL, 617042280UL, 3501667414UL, +689451808UL, 497018701UL, 238525753UL, 3890163301UL, 896679896UL, 1544533015UL, 3412477225UL, 3116575138UL, 4250402651UL, 3990990746UL, 819056741UL, 1459334146UL, 158377590UL, 3444755752UL, 8230450UL, 1378706455UL, 684191332UL, 3217423797UL, 2842520097UL, 1631477948UL, 2591254230UL, 959644473UL, 1020694107UL, 1748401915UL, 3452514983UL, 3892766171UL, 1227786994UL, 2086180800UL, 2394613217UL, 2091953150UL, 870094953UL, 2306851481UL, +571550601UL, 488878212UL, 873197214UL, 2630100528UL, 2067476907UL, 2162307009UL, 2026119728UL, 115875280UL, 2905867426UL, 248774881UL, 3110900450UL, 2236032812UL, 1888510348UL, 708001855UL, 996960491UL, 3514196956UL, 1407967546UL, 1826568876UL, 3659618284UL, 2614104317UL, 2230066308UL, 1055135881UL, 2537437343UL, 1858044413UL, 2608594891UL, 2750681169UL, 3241939420UL, 3966440877UL, 2375002886UL, 2417753441UL, 1405878685UL, 1081133199UL, +1496940727UL, 382467042UL, 2745477587UL, 1209424459UL, 811187075UL, 1385604734UL, 2623887355UL, 3443875720UL, 394141555UL, 4142998949UL, 4195414618UL, 1489846841UL, 2253433808UL, 1171450286UL, 84131191UL, 4387588UL, 2641405140UL, 3525405389UL, 3273000909UL, 423660319UL, 2366546732UL, 3698878607UL, 2161119729UL, 4263629085UL, 3029102089UL, 2692507376UL, 3266869596UL, 1658012061UL, 1960169440UL, 1002311379UL, 3724446882UL, 2004188516UL, +999513506UL, 2200093802UL, 4141037460UL, 351865836UL, 412875013UL, 1535823315UL, 3880657632UL, 3109944987UL, 3207577548UL, 3462087941UL, 584875517UL, 2635241084UL, 3834145971UL, 1693380373UL, 3524443732UL, 934775214UL, 1960588847UL, 2226778032UL, 1044609478UL, 12199016UL, 1120582000UL, 226430296UL, 665553142UL, 2570993348UL, 1685535237UL, 3325420136UL, 3925248326UL, 2855346376UL, 1205558328UL, 808835317UL, 3295908896UL, 4170076136UL, +2438272365UL, 4052471963UL, 683640040UL, 3043876021UL, 3466644483UL, 1385549869UL, 3035140128UL, 1466027937UL, 18198088UL, 3410320851UL, 2171386836UL, 488404231UL, 3157371815UL, 769336092UL, 3240417718UL, 2921774554UL, 2075839263UL, 835026995UL, 3123726486UL, 3284240985UL, 72352110UL, 3606056482UL, 512836002UL, 2715428547UL, 4182302879UL, 3869483469UL, 3160187826UL, 390292489UL, 980889545UL, 2776206633UL, 1385691983UL, 617042280UL, +3501667414UL, 689451808UL, 497018701UL, 2600411809UL, 3890163301UL, 896679896UL, 1544533015UL, 3412477225UL, 356556378UL, 4250402651UL, 3990990746UL, 819056741UL, 1459334146UL, 199003993UL, 3444755752UL, 8230450UL, 1378706455UL, 684191332UL, 1750733272UL, 2842520097UL, 1631477948UL, 2591254230UL, 959644473UL, 2113375576UL, 1748401915UL, 3452514983UL, 3892766171UL, 1227786994UL, 275473920UL, 2394613217UL, 2091953150UL, 870094953UL, +2306851481UL, 897057645UL, 488878212UL, 873197214UL, 2630100528UL, 2067476907UL, 944114068UL, 2026119728UL, 115875280UL, 2905867426UL, 248774881UL, 989201307UL, 2236032812UL, 1888510348UL, 708001855UL, 996960491UL, 2121706374UL, 1407967546UL, 1826568876UL, 3659618284UL, 2614104317UL, 2931815032UL, 1055135881UL, 2537437343UL, 1858044413UL, 2608594891UL, 1423973935UL, 3241939420UL, 3966440877UL, 2375002886UL, 2417753441UL, 2514473440UL, +1081133199UL, 1496940727UL, 382467042UL, 2745477587UL, 81977310UL, 811187075UL, 1385604734UL, 2623887355UL, 3443875720UL, 2100629879UL, 4142998949UL, 4195414618UL, 1489846841UL, 2253433808UL, 337182869UL, 84131191UL, 4387588UL, 2641405140UL, 3525405389UL, 661876463UL, 423660319UL, 2366546732UL, 3698878607UL, 2161119729UL, 309510684UL, 3029102089UL, 2692507376UL, 3266869596UL, 1658012061UL, 11119541UL, 1002311379UL, 3724446882UL, +2004188516UL, 999513506UL, 3486722046UL, 4141037460UL, 351865836UL, 412875013UL, 1535823315UL, 2818130700UL, 3109944987UL, 3207577548UL, 3462087941UL, 584875517UL, 322875622UL, 3834145971UL, 1693380373UL, 3524443732UL, 934775214UL, 3879414752UL, 2226778032UL, 1044609478UL, 12199016UL, 1120582000UL, 4207259464UL, 665553142UL, 2570993348UL, 1685535237UL, 3325420136UL, 553869152UL, 2855346376UL, 1205558328UL, 808835317UL, 3295908896UL, +470585896UL, 2438272365UL, 4052471963UL, 683640040UL, 3043876021UL, 1588419572UL, 1385549869UL, 3035140128UL, 1466027937UL, 18198088UL, 363815288UL, 2171386836UL, 488404231UL, 3157371815UL, 769336092UL, 2464768302UL, 2921774554UL, 2075839263UL, 835026995UL, 3123726486UL, 4229246330UL, 72352110UL, 3606056482UL, 512836002UL, 2715428547UL, 319830805UL, 3869483469UL, 3160187826UL, 390292489UL, 980889545UL, 2966401462UL, 1385691983UL, +617042280UL, 3501667414UL, 689451808UL, 4047377762UL, 2600411809UL, 3890163301UL, 896679896UL, 1544533015UL, 764316452UL, 356556378UL, 4250402651UL, 3990990746UL, 819056741UL, 965331966UL, 199003993UL, 3444755752UL, 8230450UL, 1378706455UL, 51902971UL, 1750733272UL, 2842520097UL, 1631477948UL, 2591254230UL, 426039404UL, 2113375576UL, 1748401915UL, 3452514983UL, 3892766171UL, 2833368447UL, 275473920UL, 2394613217UL, 2091953150UL, +870094953UL, 3524323828UL, 897057645UL, 488878212UL, 873197214UL, 2630100528UL, 3939852929UL, 944114068UL, 2026119728UL, 115875280UL, 2905867426UL, 3192643919UL, 989201307UL, 2236032812UL, 1888510348UL, 708001855UL, 2166012172UL, 2121706374UL, 1407967546UL, 1826568876UL, 3659618284UL, 135277096UL, 2931815032UL, 1055135881UL, 2537437343UL, 1858044413UL, 2588429924UL, 1423973935UL, 3241939420UL, 3966440877UL, 2375002886UL, 2477142003UL, +2514473440UL, 1081133199UL, 1496940727UL, 382467042UL, 1760129281UL, 81977310UL, 811187075UL, 1385604734UL, 2623887355UL, 4070531513UL, 2100629879UL, 4142998949UL, 4195414618UL, 1489846841UL, 2688068550UL, 337182869UL, 84131191UL, 4387588UL, 2641405140UL, 1837403234UL, 661876463UL, 423660319UL, 2366546732UL, 3698878607UL, 2916121190UL, 309510684UL, 3029102089UL, 2692507376UL, 3266869596UL, 303422295UL, 11119541UL, 1002311379UL, +3724446882UL, 2004188516UL, 2652711421UL, 3486722046UL, 4141037460UL, 351865836UL, 412875013UL, 113149471UL, 2818130700UL, 3109944987UL, 3207577548UL, 3462087941UL, 1443140792UL, 322875622UL, 3834145971UL, 1693380373UL, 3524443732UL, 901891935UL, 3879414752UL, 2226778032UL, 1044609478UL, 12199016UL, 2213168758UL, 4207259464UL, 665553142UL, 2570993348UL, 1685535237UL, 1114492412UL, 553869152UL, 2855346376UL, 1205558328UL, 808835317UL, +3266626294UL, 470585896UL, 2438272365UL, 4052471963UL, 683640040UL, 3581539398UL, 1588419572UL, 1385549869UL, 3035140128UL, 1466027937UL, 4075470388UL, 363815288UL, 2171386836UL, 488404231UL, 3157371815UL, 2759472233UL, 2464768302UL, 2921774554UL, 2075839263UL, 835026995UL, 1030654310UL, 4229246330UL, 72352110UL, 3606056482UL, 512836002UL, 961858496UL, 319830805UL, 3869483469UL, 3160187826UL, 390292489UL, 2366221117UL, 2966401462UL, +1385691983UL, 617042280UL, 3501667414UL, 295865937UL, 4047377762UL, 2600411809UL, 3890163301UL, 896679896UL, 21714884UL, 764316452UL, 356556378UL, 4250402651UL, 3990990746UL, 1012967081UL, 965331966UL, 199003993UL, 3444755752UL, 8230450UL, 1255302023UL, 51902971UL, 1750733272UL, 2842520097UL, 1631477948UL, 2321320272UL, 426039404UL, 2113375576UL, 1748401915UL, 3452514983UL, 2847013518UL, 2833368447UL, 275473920UL, 2394613217UL, +2091953150UL, 1250695522UL, 3524323828UL, 897057645UL, 488878212UL, 873197214UL, 1452317325UL, 3939852929UL, 944114068UL, 2026119728UL, 115875280UL, 4061820350UL, 3192643919UL, 989201307UL, 2236032812UL, 1888510348UL, 3986446165UL, 2166012172UL, 2121706374UL, 1407967546UL, 1826568876UL, 2910745432UL, 135277096UL, 2931815032UL, 1055135881UL, 2537437343UL, 2976455307UL, 2588429924UL, 1423973935UL, 3241939420UL, 3966440877UL, 2418897705UL, +2477142003UL, 2514473440UL, 1081133199UL, 1496940727UL, 1321648771UL, 1760129281UL, 81977310UL, 811187075UL, 1385604734UL, 17644628UL, 4070531513UL, 2100629879UL, 4142998949UL, 4195414618UL, 2697310527UL, 2688068550UL, 337182869UL, 84131191UL, 4387588UL, 1724191700UL, 1837403234UL, 661876463UL, 423660319UL, 2366546732UL, 693430992UL, 2916121190UL, 309510684UL, 3029102089UL, 2692507376UL, 3917396098UL, 303422295UL, 11119541UL, +1002311379UL, 3724446882UL, 841468294UL, 2652711421UL, 3486722046UL, 4141037460UL, 351865836UL, 1733384185UL, 113149471UL, 2818130700UL, 3109944987UL, 3207577548UL, 2326233100UL, 1443140792UL, 322875622UL, 3834145971UL, 1693380373UL, 1580706359UL, 901891935UL, 3879414752UL, 2226778032UL, 1044609478UL, 3805470822UL, 2213168758UL, 4207259464UL, 665553142UL, 2570993348UL, 3406548636UL, 1114492412UL, 553869152UL, 2855346376UL, 1205558328UL, +4287831475UL, 1329654114UL, 2347235746UL, 2477803138UL, 2962371859UL, 3610024283UL, 4197266903UL, 1162294689UL, 1746713323UL, 2815058477UL, 2152552186UL, 4214791071UL, 2382522482UL, 3713914466UL, 3974765132UL, 348354997UL, 1670276150UL, 2173074887UL, 381736894UL, 3866219357UL, 1919366695UL, 3635118824UL, 2298653261UL, 3534332682UL, 1627699897UL, 4168636618UL, 3787938690UL, 2144231271UL, 2067679462UL, 217001062UL, 2308928337UL, 1620415125UL, +3526559172UL, 749451561UL, 2456947371UL, 3543607786UL, 1893824735UL, 962598819UL, 2332807164UL, 1691114891UL, 2543992233UL, 2914780639UL, 1610287145UL, 1700599697UL, 3185174208UL, 552323208UL, 2367242224UL, 3797136972UL, 3415066418UL, 2468049249UL, 1677937401UL, 40445671UL, 2886682530UL, 2585715434UL, 194932329UL, 2994003812UL, 3099556382UL, 680852222UL, 135838738UL, 1371063256UL, 995454898UL, 3754526418UL, 803635682UL, 634588682UL, +3869250783UL, 2442285521UL, 1455637058UL, 570621479UL, 2512681851UL, 1220136924UL, 750260121UL, 2909903038UL, 1582019728UL, 955115170UL, 1608265445UL, 2157390890UL, 2303678604UL, 1568394164UL, 831914289UL, 1971271392UL, 1294799854UL, 1489945167UL, 442427880UL, 1305083700UL, 1211218668UL, 2380073713UL, 2798736785UL, 2193524273UL, 3227386915UL, 1636588977UL, 3612937642UL, 435113647UL, 1591761830UL, 536210039UL, 2475747073UL, 4223795480UL, +1786737271UL, 1444661534UL, 3249410301UL, 3333695212UL, 4169107188UL, 3280638635UL, 702659930UL, 1444127970UL, 225340755UL, 2255629368UL, 746584456UL, 3965677674UL, 2671132955UL, 2080717656UL, 2145343886UL, 3712441197UL, 368422910UL, 1297685674UL, 4076123901UL, 26214470UL, 2948764826UL, 40503299UL, 1198194334UL, 2100063637UL, 1966331612UL, 2189582064UL, 2064696934UL, 1797550642UL, 3469793941UL, 2868963812UL, 851437659UL, 240918534UL, +365060070UL, 3530600064UL, 39695324UL, 1753898837UL, 1286976449UL, 3131971360UL, 2406485219UL, 3365373704UL, 3224113403UL, 1651742834UL, 587601940UL, 1574206085UL, 3739575036UL, 1413669616UL, 38172232UL, 293127854UL, 4126190109UL, 1891744061UL, 787878666UL, 456643669UL, 4228710325UL, 2025132037UL, 1492133135UL, 3122840937UL, 969442079UL, 3272420439UL, 3836126369UL, 1877655562UL, 2766212758UL, 3867984746UL, 3348077578UL, 1841216706UL, +}, +{ +1676507466UL, 1017841240UL, 2992644565UL, 476936158UL, 2468072723UL, 3113105154UL, 1154120402UL, 460889625UL, 1942263502UL, 1761593999UL, 3020908939UL, 3078194866UL, 310971889UL, 1644896012UL, 3756044556UL, 3549937583UL, 3710822994UL, 3554313733UL, 2174654326UL, 4251063242UL, 2340485150UL, 950951909UL, 4288936895UL, 3744348848UL, 706644559UL, 1085927825UL, 1595992020UL, 3288724966UL, 1367247946UL, 2950094970UL, 3925419886UL, 2628739022UL, +2528254629UL, 3582224789UL, 3907345559UL, 3373329273UL, 4255542251UL, 1185418446UL, 4018656113UL, 2854344020UL, 1381160022UL, 3642438773UL, 4284399225UL, 935780030UL, 4142412144UL, 1263328494UL, 1154237693UL, 2684443667UL, 3067549398UL, 4253090033UL, 1251034970UL, 1874233020UL, 3222830495UL, 3866931656UL, 286048055UL, 3146635362UL, 1436483376UL, 2821876495UL, 3927829532UL, 2648886905UL, 2142862852UL, 1368937545UL, 2647327844UL, 1072219385UL, +2621337706UL, 3543274652UL, 911792564UL, 1204178178UL, 4127214323UL, 2821691380UL, 3101998294UL, 730811902UL, 1989156224UL, 2872353003UL, 278290276UL, 1390223786UL, 2657819643UL, 552729795UL, 1736270535UL, 2759207116UL, 1897013739UL, 3657020278UL, 1387364861UL, 1966588302UL, 1049203087UL, 486446521UL, 3675999281UL, 714737345UL, 686837530UL, 85509025UL, 3609089773UL, 2117061768UL, 3935682560UL, 3859508784UL, 4105287041UL, 1808988481UL, +83680601UL, 1464326680UL, 1657693523UL, 3318062731UL, 1391154023UL, 234460119UL, 3551348221UL, 2245244809UL, 3635923821UL, 2814385745UL, 3497626257UL, 916790795UL, 245338628UL, 2514528380UL, 3711787525UL, 2239286063UL, 1054058916UL, 3963706010UL, 3176203796UL, 2230543409UL, 2173597546UL, 3786733892UL, 1396036965UL, 1038764273UL, 2032556038UL, 3216540537UL, 3298170974UL, 1008892557UL, 141155464UL, 1863766055UL, 3931110690UL, 191299053UL, +2019139711UL, 2409528317UL, 739418419UL, 1377144055UL, 2876702705UL, 3911939673UL, 1197696462UL, 2814009721UL, 600813233UL, 1535885024UL, 1486280357UL, 3084650548UL, 2324695947UL, 2293284974UL, 2036339249UL, 3465600153UL, 1624446108UL, 327866771UL, 3356772175UL, 1826625240UL, 1947102360UL, 3661848193UL, 1421374867UL, 3228945021UL, 1358646008UL, 1067180174UL, 2190741258UL, 643362354UL, 109899594UL, 2064362635UL, 3249674888UL, 2165543887UL, +4180291913UL, 1676507466UL, 1017841240UL, 2992644565UL, 476936158UL, 3608467942UL, 3113105154UL, 1154120402UL, 460889625UL, 1942263502UL, 1862994005UL, 3020908939UL, 3078194866UL, 310971889UL, 1644896012UL, 693774191UL, 3549937583UL, 3710822994UL, 3554313733UL, 2174654326UL, 37658897UL, 2340485150UL, 950951909UL, 4288936895UL, 3744348848UL, 2258231402UL, 1085927825UL, 1595992020UL, 3288724966UL, 1367247946UL, 3850509554UL, 3925419886UL, +2628739022UL, 2528254629UL, 3582224789UL, 3124287811UL, 3373329273UL, 4255542251UL, 1185418446UL, 4018656113UL, 1989726178UL, 1381160022UL, 3642438773UL, 4284399225UL, 935780030UL, 3622052196UL, 1263328494UL, 1154237693UL, 2684443667UL, 3067549398UL, 2786224913UL, 1251034970UL, 1874233020UL, 3222830495UL, 3866931656UL, 1529490307UL, 3146635362UL, 1436483376UL, 2821876495UL, 3927829532UL, 979247444UL, 2142862852UL, 1368937545UL, 2647327844UL, +1072219385UL, 294065371UL, 3543274652UL, 911792564UL, 1204178178UL, 4127214323UL, 103582737UL, 3101998294UL, 730811902UL, 1989156224UL, 2872353003UL, 1885087777UL, 1390223786UL, 2657819643UL, 552729795UL, 1736270535UL, 3325206451UL, 1897013739UL, 3657020278UL, 1387364861UL, 1966588302UL, 2117065739UL, 486446521UL, 3675999281UL, 714737345UL, 686837530UL, 3946214694UL, 3609089773UL, 2117061768UL, 3935682560UL, 3859508784UL, 2916136885UL, +1808988481UL, 83680601UL, 1464326680UL, 1657693523UL, 3438751781UL, 1391154023UL, 234460119UL, 3551348221UL, 2245244809UL, 3948410079UL, 2814385745UL, 3497626257UL, 916790795UL, 245338628UL, 1767303496UL, 3711787525UL, 2239286063UL, 1054058916UL, 3963706010UL, 4140631909UL, 2230543409UL, 2173597546UL, 3786733892UL, 1396036965UL, 1116033475UL, 2032556038UL, 3216540537UL, 3298170974UL, 1008892557UL, 667272562UL, 1863766055UL, 3931110690UL, +191299053UL, 2019139711UL, 272901326UL, 739418419UL, 1377144055UL, 2876702705UL, 3911939673UL, 3839312742UL, 2814009721UL, 600813233UL, 1535885024UL, 1486280357UL, 4256065219UL, 2324695947UL, 2293284974UL, 2036339249UL, 3465600153UL, 1215859603UL, 327866771UL, 3356772175UL, 1826625240UL, 1947102360UL, 4240407984UL, 1421374867UL, 3228945021UL, 1358646008UL, 1067180174UL, 4100357988UL, 643362354UL, 109899594UL, 2064362635UL, 3249674888UL, +2898852084UL, 4180291913UL, 1676507466UL, 1017841240UL, 2992644565UL, 1569683812UL, 3608467942UL, 3113105154UL, 1154120402UL, 460889625UL, 966040649UL, 1862994005UL, 3020908939UL, 3078194866UL, 310971889UL, 786634113UL, 693774191UL, 3549937583UL, 3710822994UL, 3554313733UL, 1578429713UL, 37658897UL, 2340485150UL, 950951909UL, 4288936895UL, 2528123823UL, 2258231402UL, 1085927825UL, 1595992020UL, 3288724966UL, 3544041088UL, 3850509554UL, +3925419886UL, 2628739022UL, 2528254629UL, 2562145937UL, 3124287811UL, 3373329273UL, 4255542251UL, 1185418446UL, 3693565710UL, 1989726178UL, 1381160022UL, 3642438773UL, 4284399225UL, 3271478204UL, 3622052196UL, 1263328494UL, 1154237693UL, 2684443667UL, 3615401444UL, 2786224913UL, 1251034970UL, 1874233020UL, 3222830495UL, 2572413057UL, 1529490307UL, 3146635362UL, 1436483376UL, 2821876495UL, 3993894153UL, 979247444UL, 2142862852UL, 1368937545UL, +2647327844UL, 1353904396UL, 294065371UL, 3543274652UL, 911792564UL, 1204178178UL, 3165709748UL, 103582737UL, 3101998294UL, 730811902UL, 1989156224UL, 893293786UL, 1885087777UL, 1390223786UL, 2657819643UL, 552729795UL, 3388458110UL, 3325206451UL, 1897013739UL, 3657020278UL, 1387364861UL, 3025318046UL, 2117065739UL, 486446521UL, 3675999281UL, 714737345UL, 2085926890UL, 3946214694UL, 3609089773UL, 2117061768UL, 3935682560UL, 868009118UL, +2916136885UL, 1808988481UL, 83680601UL, 1464326680UL, 797410789UL, 3438751781UL, 1391154023UL, 234460119UL, 3551348221UL, 4068940987UL, 3948410079UL, 2814385745UL, 3497626257UL, 916790795UL, 3722456098UL, 1767303496UL, 3711787525UL, 2239286063UL, 1054058916UL, 2030352819UL, 4140631909UL, 2230543409UL, 2173597546UL, 3786733892UL, 3211336683UL, 1116033475UL, 2032556038UL, 3216540537UL, 3298170974UL, 2589589144UL, 667272562UL, 1863766055UL, +3931110690UL, 191299053UL, 1139480458UL, 272901326UL, 739418419UL, 1377144055UL, 2876702705UL, 1954361769UL, 3839312742UL, 2814009721UL, 600813233UL, 1535885024UL, 3587775605UL, 4256065219UL, 2324695947UL, 2293284974UL, 2036339249UL, 1534849280UL, 1215859603UL, 327866771UL, 3356772175UL, 1826625240UL, 720372669UL, 4240407984UL, 1421374867UL, 3228945021UL, 1358646008UL, 3409069246UL, 4100357988UL, 643362354UL, 109899594UL, 2064362635UL, +4243434294UL, 2898852084UL, 4180291913UL, 1676507466UL, 1017841240UL, 3243922356UL, 1569683812UL, 3608467942UL, 3113105154UL, 1154120402UL, 1479311403UL, 966040649UL, 1862994005UL, 3020908939UL, 3078194866UL, 1556392996UL, 786634113UL, 693774191UL, 3549937583UL, 3710822994UL, 920664071UL, 1578429713UL, 37658897UL, 2340485150UL, 950951909UL, 740197415UL, 2528123823UL, 2258231402UL, 1085927825UL, 1595992020UL, 2580760267UL, 3544041088UL, +3850509554UL, 3925419886UL, 2628739022UL, 3867556156UL, 2562145937UL, 3124287811UL, 3373329273UL, 4255542251UL, 3185271749UL, 3693565710UL, 1989726178UL, 1381160022UL, 3642438773UL, 3042165367UL, 3271478204UL, 3622052196UL, 1263328494UL, 1154237693UL, 1016814036UL, 3615401444UL, 2786224913UL, 1251034970UL, 1874233020UL, 2956086971UL, 2572413057UL, 1529490307UL, 3146635362UL, 1436483376UL, 1513970396UL, 3993894153UL, 979247444UL, 2142862852UL, +1368937545UL, 3275665128UL, 1353904396UL, 294065371UL, 3543274652UL, 911792564UL, 2209636872UL, 3165709748UL, 103582737UL, 3101998294UL, 730811902UL, 965151434UL, 893293786UL, 1885087777UL, 1390223786UL, 2657819643UL, 3278634059UL, 3388458110UL, 3325206451UL, 1897013739UL, 3657020278UL, 4293473749UL, 3025318046UL, 2117065739UL, 486446521UL, 3675999281UL, 620561205UL, 2085926890UL, 3946214694UL, 3609089773UL, 2117061768UL, 163384588UL, +868009118UL, 2916136885UL, 1808988481UL, 83680601UL, 10243015UL, 797410789UL, 3438751781UL, 1391154023UL, 234460119UL, 1278218413UL, 4068940987UL, 3948410079UL, 2814385745UL, 3497626257UL, 1233272798UL, 3722456098UL, 1767303496UL, 3711787525UL, 2239286063UL, 3968895688UL, 2030352819UL, 4140631909UL, 2230543409UL, 2173597546UL, 2866251044UL, 3211336683UL, 1116033475UL, 2032556038UL, 3216540537UL, 4233849723UL, 2589589144UL, 667272562UL, +1863766055UL, 3931110690UL, 2468422423UL, 1139480458UL, 272901326UL, 739418419UL, 1377144055UL, 4240143411UL, 1954361769UL, 3839312742UL, 2814009721UL, 600813233UL, 3976840004UL, 3587775605UL, 4256065219UL, 2324695947UL, 2293284974UL, 437604123UL, 1534849280UL, 1215859603UL, 327866771UL, 3356772175UL, 2757237699UL, 720372669UL, 4240407984UL, 1421374867UL, 3228945021UL, 3284801305UL, 3409069246UL, 4100357988UL, 643362354UL, 109899594UL, +1301585321UL, 2528806870UL, 1838904064UL, 448772403UL, 1097849740UL, 1899994097UL, 618309123UL, 1911948510UL, 2309256224UL, 1861398151UL, 905306403UL, 1067595802UL, 36868624UL, 3780886191UL, 835126206UL, 3190251977UL, 2672497726UL, 2085944002UL, 2912993968UL, 2493776706UL, 667136329UL, 1474890786UL, 2383346554UL, 943528949UL, 3376706013UL, 2495573574UL, 144956345UL, 793159960UL, 1591274917UL, 477107637UL, 1383815442UL, 67384899UL, +2355242218UL, 1687409818UL, 3801093871UL, 2108217811UL, 3455908733UL, 4172160797UL, 3935534685UL, 631067839UL, 1187677548UL, 2280856137UL, 3020767646UL, 2063176246UL, 3736904984UL, 2952933848UL, 2975164686UL, 4144473303UL, 34670977UL, 1250976509UL, 3484166554UL, 1532744745UL, 225700994UL, 1878713627UL, 2122358980UL, 1456610194UL, 2917522161UL, 2818947075UL, 102678939UL, 53743858UL, 2095250656UL, 4023979225UL, 3094092874UL, 4128760696UL, +3411610028UL, 3020200609UL, 2225866341UL, 586320946UL, 63813522UL, 1238216159UL, 2825692263UL, 2169937231UL, 3298517640UL, 1542128261UL, 2205544184UL, 1258655704UL, 2629012083UL, 4113650203UL, 3198617867UL, 2742310794UL, 3372657381UL, 3115904410UL, 1948638822UL, 1123521744UL, 1080429281UL, 4086706732UL, 4142693211UL, 817377147UL, 2570194641UL, 26001503UL, 2861456160UL, 4185725555UL, 2573003804UL, 1618628779UL, 2588489212UL, 3996192609UL, +1555844274UL, 1003123505UL, 1326350123UL, 1130583849UL, 3017128756UL, 74119042UL, 4041266437UL, 1938014170UL, 3528465794UL, 4203969698UL, 1913054398UL, 3617979809UL, 2218810167UL, 2453899816UL, 1997423206UL, 477446533UL, 303090065UL, 757937082UL, 1523238256UL, 3140505311UL, 1422588701UL, 3642014639UL, 1740624195UL, 1276017154UL, 3072526193UL, 3675105122UL, 1335122682UL, 4080595263UL, 2308519420UL, 3299182769UL, 1461978532UL, 3098694217UL, +2982399822UL, 3088698511UL, 586759229UL, 3548750902UL, 1449857891UL, 2866451663UL, 2525162286UL, 57294602UL, 4107991297UL, 1214672265UL, 2940391280UL, 4285346034UL, 3338216759UL, 737207923UL, 4264163846UL, 59219141UL, 2300024654UL, 1876616814UL, 1976543605UL, 783571061UL, 1724699622UL, 1967524469UL, 1650309916UL, 3322257631UL, 3975521122UL, 273342162UL, 1156754241UL, 185315896UL, 3368133921UL, 66314655UL, 4153777915UL, 3519901897UL, +}, +{ +3672467167UL, 68684525UL, 1738833632UL, 3081329135UL, 2583806115UL, 2291130512UL, 503032614UL, 3658059597UL, 571493931UL, 685537959UL, 3498787788UL, 422428426UL, 3879256913UL, 1173158320UL, 4000800121UL, 298972869UL, 1718342816UL, 2541691685UL, 2490502642UL, 2321452806UL, 4223212804UL, 1812334632UL, 3717655725UL, 4238191852UL, 3001307165UL, 2621896355UL, 2572404999UL, 3590094954UL, 760765206UL, 2293618001UL, 1392353032UL, 1733137169UL, +2674005018UL, 4067961151UL, 1505710487UL, 451078217UL, 2591688848UL, 12635611UL, 507045428UL, 694822241UL, 1789383090UL, 1140183890UL, 1720695967UL, 1994318191UL, 3340349873UL, 2793804971UL, 1054433135UL, 2345087879UL, 3179939285UL, 1651968615UL, 1793223686UL, 1055357758UL, 914271617UL, 483007580UL, 2127727816UL, 2754998083UL, 3179053982UL, 598442002UL, 1950227301UL, 213053613UL, 3566888111UL, 2832258993UL, 4260365359UL, 443662829UL, +1706542890UL, 3852730296UL, 3643260763UL, 2163607277UL, 1812905006UL, 171529637UL, 215187467UL, 2369406909UL, 1929000706UL, 2572441025UL, 2133955541UL, 810692262UL, 1337974799UL, 4030350704UL, 2159178715UL, 3769451556UL, 1026825278UL, 593628480UL, 1817383139UL, 878832429UL, 2253876350UL, 203612980UL, 2102950440UL, 3407143936UL, 1912362251UL, 1595387637UL, 2827580539UL, 305467658UL, 3292706746UL, 44135525UL, 4001933553UL, 3697343089UL, +760470915UL, 587414402UL, 1419378814UL, 2852774010UL, 3891626781UL, 2757016765UL, 1090707384UL, 3997074427UL, 1047182100UL, 2855539022UL, 36229159UL, 1591415533UL, 3471572739UL, 1237952140UL, 2614469314UL, 213338525UL, 886212578UL, 2620301943UL, 713590207UL, 2430496777UL, 1198164420UL, 2644841698UL, 3654164701UL, 36283572UL, 1461695896UL, 1770331341UL, 1641501876UL, 3470919184UL, 3181021559UL, 3053795110UL, 3533531372UL, 3134337355UL, +668308383UL, 388340999UL, 3221275220UL, 1589659138UL, 294382235UL, 1447443579UL, 690177534UL, 1799726917UL, 2838977761UL, 4172949119UL, 2360858031UL, 159385920UL, 2248389027UL, 1790015671UL, 3925738275UL, 1049918544UL, 4107349511UL, 1619955951UL, 4188275966UL, 1672572975UL, 2672697497UL, 1863413666UL, 747724021UL, 4037561738UL, 1605940213UL, 445253292UL, 3362434828UL, 610898209UL, 1473244091UL, 735444769UL, 1540599852UL, 2449351720UL, +1032410949UL, 3672467167UL, 68684525UL, 1738833632UL, 3081329135UL, 519684794UL, 2291130512UL, 503032614UL, 3658059597UL, 571493931UL, 2400186105UL, 3498787788UL, 422428426UL, 3879256913UL, 1173158320UL, 4120704752UL, 298972869UL, 1718342816UL, 2541691685UL, 2490502642UL, 1686027891UL, 4223212804UL, 1812334632UL, 3717655725UL, 4238191852UL, 642431972UL, 2621896355UL, 2572404999UL, 3590094954UL, 760765206UL, 2949609717UL, 1392353032UL, +1733137169UL, 2674005018UL, 4067961151UL, 1526077846UL, 451078217UL, 2591688848UL, 12635611UL, 507045428UL, 2417951415UL, 1789383090UL, 1140183890UL, 1720695967UL, 1994318191UL, 3465605863UL, 2793804971UL, 1054433135UL, 2345087879UL, 3179939285UL, 3079297626UL, 1793223686UL, 1055357758UL, 914271617UL, 483007580UL, 306802527UL, 2754998083UL, 3179053982UL, 598442002UL, 1950227301UL, 2473418737UL, 3566888111UL, 2832258993UL, 4260365359UL, +443662829UL, 2097776414UL, 3852730296UL, 3643260763UL, 2163607277UL, 1812905006UL, 3957721904UL, 215187467UL, 2369406909UL, 1929000706UL, 2572441025UL, 3779486126UL, 810692262UL, 1337974799UL, 4030350704UL, 2159178715UL, 1127012865UL, 1026825278UL, 593628480UL, 1817383139UL, 878832429UL, 361018423UL, 203612980UL, 2102950440UL, 3407143936UL, 1912362251UL, 1475218277UL, 2827580539UL, 305467658UL, 3292706746UL, 44135525UL, 1900092336UL, +3697343089UL, 760470915UL, 587414402UL, 1419378814UL, 343303227UL, 3891626781UL, 2757016765UL, 1090707384UL, 3997074427UL, 745490961UL, 2855539022UL, 36229159UL, 1591415533UL, 3471572739UL, 3920625546UL, 2614469314UL, 213338525UL, 886212578UL, 2620301943UL, 827771411UL, 2430496777UL, 1198164420UL, 2644841698UL, 3654164701UL, 2747674190UL, 1461695896UL, 1770331341UL, 1641501876UL, 3470919184UL, 919857376UL, 3053795110UL, 3533531372UL, +3134337355UL, 668308383UL, 201138876UL, 3221275220UL, 1589659138UL, 294382235UL, 1447443579UL, 4211579707UL, 1799726917UL, 2838977761UL, 4172949119UL, 2360858031UL, 416103844UL, 2248389027UL, 1790015671UL, 3925738275UL, 1049918544UL, 3481887924UL, 1619955951UL, 4188275966UL, 1672572975UL, 2672697497UL, 564854400UL, 747724021UL, 4037561738UL, 1605940213UL, 445253292UL, 604900912UL, 610898209UL, 1473244091UL, 735444769UL, 1540599852UL, +3036173307UL, 1032410949UL, 3672467167UL, 68684525UL, 1738833632UL, 973022696UL, 519684794UL, 2291130512UL, 503032614UL, 3658059597UL, 1500301452UL, 2400186105UL, 3498787788UL, 422428426UL, 3879256913UL, 3923611748UL, 4120704752UL, 298972869UL, 1718342816UL, 2541691685UL, 2323881484UL, 1686027891UL, 4223212804UL, 1812334632UL, 3717655725UL, 2109094458UL, 642431972UL, 2621896355UL, 2572404999UL, 3590094954UL, 1837882537UL, 2949609717UL, +1392353032UL, 1733137169UL, 2674005018UL, 3252348987UL, 1526077846UL, 451078217UL, 2591688848UL, 12635611UL, 3971261781UL, 2417951415UL, 1789383090UL, 1140183890UL, 1720695967UL, 2906966040UL, 3465605863UL, 2793804971UL, 1054433135UL, 2345087879UL, 915518921UL, 3079297626UL, 1793223686UL, 1055357758UL, 914271617UL, 791633499UL, 306802527UL, 2754998083UL, 3179053982UL, 598442002UL, 324402573UL, 2473418737UL, 3566888111UL, 2832258993UL, +4260365359UL, 2168046398UL, 2097776414UL, 3852730296UL, 3643260763UL, 2163607277UL, 2595175979UL, 3957721904UL, 215187467UL, 2369406909UL, 1929000706UL, 657446369UL, 3779486126UL, 810692262UL, 1337974799UL, 4030350704UL, 1865557469UL, 1127012865UL, 1026825278UL, 593628480UL, 1817383139UL, 3414354529UL, 361018423UL, 203612980UL, 2102950440UL, 3407143936UL, 1739372987UL, 1475218277UL, 2827580539UL, 305467658UL, 3292706746UL, 825045562UL, +1900092336UL, 3697343089UL, 760470915UL, 587414402UL, 2000637694UL, 343303227UL, 3891626781UL, 2757016765UL, 1090707384UL, 4015377800UL, 745490961UL, 2855539022UL, 36229159UL, 1591415533UL, 2208656873UL, 3920625546UL, 2614469314UL, 213338525UL, 886212578UL, 2729976209UL, 827771411UL, 2430496777UL, 1198164420UL, 2644841698UL, 1922667440UL, 2747674190UL, 1461695896UL, 1770331341UL, 1641501876UL, 357535311UL, 919857376UL, 3053795110UL, +3533531372UL, 3134337355UL, 1004072597UL, 201138876UL, 3221275220UL, 1589659138UL, 294382235UL, 1148950143UL, 4211579707UL, 1799726917UL, 2838977761UL, 4172949119UL, 892664404UL, 416103844UL, 2248389027UL, 1790015671UL, 3925738275UL, 2612357890UL, 3481887924UL, 1619955951UL, 4188275966UL, 1672572975UL, 2005534713UL, 564854400UL, 747724021UL, 4037561738UL, 1605940213UL, 2620990454UL, 604900912UL, 610898209UL, 1473244091UL, 735444769UL, +3571225334UL, 3036173307UL, 1032410949UL, 3672467167UL, 68684525UL, 3327351604UL, 973022696UL, 519684794UL, 2291130512UL, 503032614UL, 3814902238UL, 1500301452UL, 2400186105UL, 3498787788UL, 422428426UL, 1756753750UL, 3923611748UL, 4120704752UL, 298972869UL, 1718342816UL, 652903081UL, 2323881484UL, 1686027891UL, 4223212804UL, 1812334632UL, 1599640566UL, 2109094458UL, 642431972UL, 2621896355UL, 2572404999UL, 1668409355UL, 1837882537UL, +2949609717UL, 1392353032UL, 1733137169UL, 3691709793UL, 3252348987UL, 1526077846UL, 451078217UL, 2591688848UL, 3353622601UL, 3971261781UL, 2417951415UL, 1789383090UL, 1140183890UL, 4113853791UL, 2906966040UL, 3465605863UL, 2793804971UL, 1054433135UL, 2195882948UL, 915518921UL, 3079297626UL, 1793223686UL, 1055357758UL, 898713552UL, 791633499UL, 306802527UL, 2754998083UL, 3179053982UL, 2469350088UL, 324402573UL, 2473418737UL, 3566888111UL, +2832258993UL, 1377718274UL, 2168046398UL, 2097776414UL, 3852730296UL, 3643260763UL, 3492388484UL, 2595175979UL, 3957721904UL, 215187467UL, 2369406909UL, 4243449339UL, 657446369UL, 3779486126UL, 810692262UL, 1337974799UL, 3960230785UL, 1865557469UL, 1127012865UL, 1026825278UL, 593628480UL, 732793312UL, 3414354529UL, 361018423UL, 203612980UL, 2102950440UL, 2401792405UL, 1739372987UL, 1475218277UL, 2827580539UL, 305467658UL, 2454275289UL, +825045562UL, 1900092336UL, 3697343089UL, 760470915UL, 2146882409UL, 2000637694UL, 343303227UL, 3891626781UL, 2757016765UL, 3997473261UL, 4015377800UL, 745490961UL, 2855539022UL, 36229159UL, 2375394427UL, 2208656873UL, 3920625546UL, 2614469314UL, 213338525UL, 2055366274UL, 2729976209UL, 827771411UL, 2430496777UL, 1198164420UL, 1789631187UL, 1922667440UL, 2747674190UL, 1461695896UL, 1770331341UL, 4284442852UL, 357535311UL, 919857376UL, +3053795110UL, 3533531372UL, 2124270060UL, 1004072597UL, 201138876UL, 3221275220UL, 1589659138UL, 1418386120UL, 1148950143UL, 4211579707UL, 1799726917UL, 2838977761UL, 3540708069UL, 892664404UL, 416103844UL, 2248389027UL, 1790015671UL, 3936883UL, 2612357890UL, 3481887924UL, 1619955951UL, 4188275966UL, 2963623483UL, 2005534713UL, 564854400UL, 747724021UL, 4037561738UL, 3431155922UL, 2620990454UL, 604900912UL, 610898209UL, 1473244091UL, +3880001339UL, 2879060316UL, 3300897679UL, 3960972039UL, 3201086624UL, 3814462934UL, 3426650044UL, 1930881632UL, 1981178788UL, 2956279691UL, 4272406256UL, 372705521UL, 1359389771UL, 1590302979UL, 3940206208UL, 3817999127UL, 2527835456UL, 2739078164UL, 716997849UL, 3235607043UL, 2550297745UL, 3688700200UL, 354502605UL, 2285793656UL, 2339138034UL, 3912354142UL, 2262255668UL, 469322622UL, 1319943359UL, 1916101235UL, 200441823UL, 509436982UL, +2160284593UL, 1687919695UL, 4153615582UL, 495735041UL, 3694469424UL, 2086893117UL, 4223008799UL, 105344742UL, 1698033424UL, 1149223145UL, 4183918790UL, 4176151950UL, 415739351UL, 817762972UL, 3768072560UL, 1931430949UL, 2698979439UL, 3481477932UL, 1994322914UL, 4078299950UL, 1268233995UL, 3254069145UL, 91029129UL, 498234704UL, 1636613942UL, 3710087092UL, 3876816560UL, 3510446387UL, 3870169008UL, 1370156410UL, 2442498047UL, 2324396523UL, +1258730334UL, 621954739UL, 1053015373UL, 491820717UL, 3386515432UL, 2203703266UL, 120167176UL, 2383669740UL, 1038666440UL, 2927342870UL, 3583197824UL, 1236241846UL, 2474675929UL, 679052891UL, 2451259584UL, 2177706146UL, 606842882UL, 3546980104UL, 2289281509UL, 353873434UL, 2041926837UL, 1238346748UL, 2729109726UL, 2843938395UL, 2938124210UL, 2554443866UL, 1494477920UL, 693378319UL, 2020963566UL, 2000385949UL, 3744098787UL, 650307220UL, +2631327075UL, 1529128757UL, 595871428UL, 3206666562UL, 458062987UL, 875238192UL, 3729317374UL, 1368843921UL, 3478430230UL, 3234384578UL, 3232435428UL, 321359326UL, 994274524UL, 361184397UL, 4285497594UL, 915263578UL, 1486882838UL, 9988613UL, 829077170UL, 677216046UL, 4141828204UL, 165804609UL, 1086678519UL, 2933434608UL, 1351662802UL, 2640085040UL, 2611502932UL, 2033698714UL, 2008873254UL, 3995557835UL, 1020873906UL, 67873555UL, +2230337823UL, 1263800417UL, 1148712155UL, 3985159589UL, 2979503513UL, 2854714997UL, 1539343345UL, 2751484352UL, 1569100732UL, 2020758949UL, 2126757134UL, 3426641899UL, 2808587825UL, 1953320148UL, 1096398464UL, 1502907172UL, 3751230087UL, 765557661UL, 765290990UL, 3056075500UL, 2040620632UL, 422573751UL, 3613558930UL, 1741145769UL, 273531216UL, 837238736UL, 494297893UL, 2903251124UL, 1636782182UL, 4256592784UL, 3652746656UL, 4258393217UL, +}, +{ +2657510202UL, 270297201UL, 2970166904UL, 3151626326UL, 973127447UL, 1523852613UL, 598650578UL, 10289043UL, 1138773500UL, 1379558769UL, 2202575480UL, 1622690708UL, 181345079UL, 228706650UL, 2807760507UL, 3061024281UL, 2310359315UL, 3094465578UL, 4062753882UL, 2744510393UL, 3844622451UL, 1759718963UL, 2393602744UL, 977540509UL, 870449791UL, 1484134272UL, 2838962253UL, 3079492430UL, 2617141201UL, 3744868057UL, 994295425UL, 1302594555UL, +277777192UL, 1793039043UL, 1620482692UL, 2518563014UL, 1163760339UL, 2709515777UL, 4220588138UL, 531143270UL, 2528377633UL, 931694828UL, 1472659070UL, 900489303UL, 3538137811UL, 3849822545UL, 1304182427UL, 2423451948UL, 587259647UL, 296795227UL, 3843393378UL, 100570026UL, 1824916038UL, 3155192628UL, 1205830295UL, 2205840913UL, 2598785234UL, 2138099222UL, 1585588098UL, 1304106911UL, 2443465671UL, 3007665864UL, 3350433156UL, 3623458138UL, +629407548UL, 3209244941UL, 2102270358UL, 952701496UL, 2715374730UL, 2142960491UL, 2566649458UL, 2386659994UL, 4201648072UL, 367516884UL, 211986877UL, 3970312395UL, 4153651951UL, 3794120671UL, 614826776UL, 769672874UL, 2218713182UL, 236114529UL, 1614697510UL, 2420862368UL, 3471485219UL, 3080341429UL, 2394724619UL, 3585194114UL, 1394678495UL, 2137969611UL, 3955498999UL, 2765569351UL, 3084915757UL, 765232390UL, 1406483345UL, 2796499268UL, +2491128017UL, 1052428931UL, 1713430644UL, 3921576513UL, 3753414774UL, 973530327UL, 2545412294UL, 1841110931UL, 1174406073UL, 1104865218UL, 1586606252UL, 2612244473UL, 1407875673UL, 1823397519UL, 2613642581UL, 3163449384UL, 3129975397UL, 2059184961UL, 818092118UL, 3182607992UL, 1658516909UL, 2467681581UL, 1065789733UL, 799857247UL, 2492902195UL, 168866110UL, 2251316716UL, 1607684829UL, 2347941418UL, 2382781983UL, 3298500129UL, 3609200925UL, +3060374324UL, 2602420483UL, 2357812057UL, 3739699403UL, 3260652552UL, 205015857UL, 1936033273UL, 3955997259UL, 821264237UL, 1882720491UL, 159294165UL, 3197657094UL, 528058988UL, 2768830342UL, 805087358UL, 896645931UL, 1360375456UL, 3417488932UL, 3863200799UL, 4033907887UL, 983658874UL, 1828706965UL, 875027318UL, 1310362653UL, 3711487613UL, 4148261033UL, 3145162047UL, 485182003UL, 2633647498UL, 1369395018UL, 4163384029UL, 1827719274UL, +270658892UL, 2657510202UL, 270297201UL, 2970166904UL, 3151626326UL, 499420828UL, 1523852613UL, 598650578UL, 10289043UL, 1138773500UL, 640170086UL, 2202575480UL, 1622690708UL, 181345079UL, 228706650UL, 3957853780UL, 3061024281UL, 2310359315UL, 3094465578UL, 4062753882UL, 2049506087UL, 3844622451UL, 1759718963UL, 2393602744UL, 977540509UL, 2346891936UL, 1484134272UL, 2838962253UL, 3079492430UL, 2617141201UL, 2112540708UL, 994295425UL, +1302594555UL, 277777192UL, 1793039043UL, 981072592UL, 2518563014UL, 1163760339UL, 2709515777UL, 4220588138UL, 1992965594UL, 2528377633UL, 931694828UL, 1472659070UL, 900489303UL, 32461040UL, 3849822545UL, 1304182427UL, 2423451948UL, 587259647UL, 3728056788UL, 3843393378UL, 100570026UL, 1824916038UL, 3155192628UL, 1194916233UL, 2205840913UL, 2598785234UL, 2138099222UL, 1585588098UL, 2944318376UL, 2443465671UL, 3007665864UL, 3350433156UL, +3623458138UL, 1413669939UL, 3209244941UL, 2102270358UL, 952701496UL, 2715374730UL, 826676012UL, 2566649458UL, 2386659994UL, 4201648072UL, 367516884UL, 4272143576UL, 3970312395UL, 4153651951UL, 3794120671UL, 614826776UL, 4106382849UL, 2218713182UL, 236114529UL, 1614697510UL, 2420862368UL, 138091237UL, 3080341429UL, 2394724619UL, 3585194114UL, 1394678495UL, 2113895281UL, 3955498999UL, 2765569351UL, 3084915757UL, 765232390UL, 2247301699UL, +2796499268UL, 2491128017UL, 1052428931UL, 1713430644UL, 1076867271UL, 3753414774UL, 973530327UL, 2545412294UL, 1841110931UL, 3427639042UL, 1104865218UL, 1586606252UL, 2612244473UL, 1407875673UL, 2159805028UL, 2613642581UL, 3163449384UL, 3129975397UL, 2059184961UL, 1251595655UL, 3182607992UL, 1658516909UL, 2467681581UL, 1065789733UL, 524065102UL, 2492902195UL, 168866110UL, 2251316716UL, 1607684829UL, 877205873UL, 2382781983UL, 3298500129UL, +3609200925UL, 3060374324UL, 1983477493UL, 2357812057UL, 3739699403UL, 3260652552UL, 205015857UL, 3578808491UL, 3955997259UL, 821264237UL, 1882720491UL, 159294165UL, 3639531297UL, 528058988UL, 2768830342UL, 805087358UL, 896645931UL, 2309781073UL, 3417488932UL, 3863200799UL, 4033907887UL, 983658874UL, 3756437847UL, 875027318UL, 1310362653UL, 3711487613UL, 4148261033UL, 3264363953UL, 485182003UL, 2633647498UL, 1369395018UL, 4163384029UL, +184614728UL, 270658892UL, 2657510202UL, 270297201UL, 2970166904UL, 884907665UL, 499420828UL, 1523852613UL, 598650578UL, 10289043UL, 2023902217UL, 640170086UL, 2202575480UL, 1622690708UL, 181345079UL, 1358722197UL, 3957853780UL, 3061024281UL, 2310359315UL, 3094465578UL, 4156960892UL, 2049506087UL, 3844622451UL, 1759718963UL, 2393602744UL, 1018272187UL, 2346891936UL, 1484134272UL, 2838962253UL, 3079492430UL, 663361761UL, 2112540708UL, +994295425UL, 1302594555UL, 277777192UL, 4201292427UL, 981072592UL, 2518563014UL, 1163760339UL, 2709515777UL, 3301905324UL, 1992965594UL, 2528377633UL, 931694828UL, 1472659070UL, 3170286187UL, 32461040UL, 3849822545UL, 1304182427UL, 2423451948UL, 166213287UL, 3728056788UL, 3843393378UL, 100570026UL, 1824916038UL, 1534589402UL, 1194916233UL, 2205840913UL, 2598785234UL, 2138099222UL, 767439709UL, 2944318376UL, 2443465671UL, 3007665864UL, +3350433156UL, 257274072UL, 1413669939UL, 3209244941UL, 2102270358UL, 952701496UL, 893224047UL, 826676012UL, 2566649458UL, 2386659994UL, 4201648072UL, 1336000731UL, 4272143576UL, 3970312395UL, 4153651951UL, 3794120671UL, 2381517352UL, 4106382849UL, 2218713182UL, 236114529UL, 1614697510UL, 2427291612UL, 138091237UL, 3080341429UL, 2394724619UL, 3585194114UL, 1339840651UL, 2113895281UL, 3955498999UL, 2765569351UL, 3084915757UL, 1920073265UL, +2247301699UL, 2796499268UL, 2491128017UL, 1052428931UL, 1720704700UL, 1076867271UL, 3753414774UL, 973530327UL, 2545412294UL, 655938239UL, 3427639042UL, 1104865218UL, 1586606252UL, 2612244473UL, 748629647UL, 2159805028UL, 2613642581UL, 3163449384UL, 3129975397UL, 1868740512UL, 1251595655UL, 3182607992UL, 1658516909UL, 2467681581UL, 3092135795UL, 524065102UL, 2492902195UL, 168866110UL, 2251316716UL, 229376275UL, 877205873UL, 2382781983UL, +3298500129UL, 3609200925UL, 1270454086UL, 1983477493UL, 2357812057UL, 3739699403UL, 3260652552UL, 3976376418UL, 3578808491UL, 3955997259UL, 821264237UL, 1882720491UL, 2211365699UL, 3639531297UL, 528058988UL, 2768830342UL, 805087358UL, 1351870678UL, 2309781073UL, 3417488932UL, 3863200799UL, 4033907887UL, 2317721807UL, 3756437847UL, 875027318UL, 1310362653UL, 3711487613UL, 1929459086UL, 3264363953UL, 485182003UL, 2633647498UL, 1369395018UL, +2141675718UL, 184614728UL, 270658892UL, 2657510202UL, 270297201UL, 3337954073UL, 884907665UL, 499420828UL, 1523852613UL, 598650578UL, 3874207188UL, 2023902217UL, 640170086UL, 2202575480UL, 1622690708UL, 2020255059UL, 1358722197UL, 3957853780UL, 3061024281UL, 2310359315UL, 753738868UL, 4156960892UL, 2049506087UL, 3844622451UL, 1759718963UL, 1672276116UL, 1018272187UL, 2346891936UL, 1484134272UL, 2838962253UL, 1680679979UL, 663361761UL, +2112540708UL, 994295425UL, 1302594555UL, 1941500850UL, 4201292427UL, 981072592UL, 2518563014UL, 1163760339UL, 184357645UL, 3301905324UL, 1992965594UL, 2528377633UL, 931694828UL, 3462653134UL, 3170286187UL, 32461040UL, 3849822545UL, 1304182427UL, 396808784UL, 166213287UL, 3728056788UL, 3843393378UL, 100570026UL, 876691173UL, 1534589402UL, 1194916233UL, 2205840913UL, 2598785234UL, 4286653520UL, 767439709UL, 2944318376UL, 2443465671UL, +3007665864UL, 2793587144UL, 257274072UL, 1413669939UL, 3209244941UL, 2102270358UL, 2792966616UL, 893224047UL, 826676012UL, 2566649458UL, 2386659994UL, 798757973UL, 1336000731UL, 4272143576UL, 3970312395UL, 4153651951UL, 2930383268UL, 2381517352UL, 4106382849UL, 2218713182UL, 236114529UL, 1936008889UL, 2427291612UL, 138091237UL, 3080341429UL, 2394724619UL, 4157586029UL, 1339840651UL, 2113895281UL, 3955498999UL, 2765569351UL, 2243544114UL, +1920073265UL, 2247301699UL, 2796499268UL, 2491128017UL, 3372810009UL, 1720704700UL, 1076867271UL, 3753414774UL, 973530327UL, 484392041UL, 655938239UL, 3427639042UL, 1104865218UL, 1586606252UL, 1373046326UL, 748629647UL, 2159805028UL, 2613642581UL, 3163449384UL, 1558595520UL, 1868740512UL, 1251595655UL, 3182607992UL, 1658516909UL, 3503432306UL, 3092135795UL, 524065102UL, 2492902195UL, 168866110UL, 4106973392UL, 229376275UL, 877205873UL, +2382781983UL, 3298500129UL, 2366096961UL, 1270454086UL, 1983477493UL, 2357812057UL, 3739699403UL, 4223323197UL, 3976376418UL, 3578808491UL, 3955997259UL, 821264237UL, 1581729952UL, 2211365699UL, 3639531297UL, 528058988UL, 2768830342UL, 3946263978UL, 1351870678UL, 2309781073UL, 3417488932UL, 3863200799UL, 3948072426UL, 2317721807UL, 3756437847UL, 875027318UL, 1310362653UL, 3439391360UL, 1929459086UL, 3264363953UL, 485182003UL, 2633647498UL, +3576868480UL, 2527748673UL, 3116247125UL, 4020801612UL, 2594734840UL, 3308177137UL, 665011257UL, 40118275UL, 3584569179UL, 3399729283UL, 3867174947UL, 658488234UL, 1099195903UL, 2274511402UL, 1872529118UL, 2518961094UL, 2633598693UL, 4160728307UL, 449442630UL, 164837956UL, 1010805767UL, 605336924UL, 1178031445UL, 3949359502UL, 2585151633UL, 611885521UL, 293204651UL, 3389557188UL, 1172294301UL, 2503819061UL, 659842653UL, 504992348UL, +3762165683UL, 1799777932UL, 4161843209UL, 1924622448UL, 1006263939UL, 115233249UL, 2775142171UL, 3228632586UL, 885407023UL, 2514866293UL, 3615088636UL, 2488824172UL, 2631364137UL, 1454226414UL, 3888177876UL, 70646265UL, 2291458600UL, 2370783730UL, 1566625834UL, 3652033806UL, 4136806683UL, 2819973124UL, 3207365429UL, 989185345UL, 3343822313UL, 2580472874UL, 4077285847UL, 4032963783UL, 2883518039UL, 2253593637UL, 904631114UL, 2654790756UL, +2967911632UL, 2131672564UL, 1594073414UL, 2370718497UL, 3769371275UL, 1547951748UL, 2473303924UL, 651625138UL, 2159175883UL, 4062995539UL, 696224922UL, 3388626509UL, 100118553UL, 770731124UL, 2149458689UL, 3223175313UL, 3524052514UL, 2651241522UL, 78236806UL, 3212708723UL, 1045780878UL, 2257575290UL, 3709360831UL, 966829465UL, 61269250UL, 405063245UL, 331731998UL, 2472078870UL, 1138237364UL, 1135091387UL, 3245001409UL, 3817992705UL, +1738939574UL, 1397617581UL, 2896546651UL, 4207083421UL, 3802162100UL, 391930524UL, 1326819828UL, 85308067UL, 3235336831UL, 686989692UL, 1947564282UL, 842881662UL, 2887279866UL, 3850666935UL, 2001895525UL, 2673649961UL, 2106555006UL, 1762053005UL, 2334552700UL, 26094213UL, 1184502058UL, 2048598709UL, 4039640450UL, 1439363714UL, 1022688817UL, 1053169108UL, 170896272UL, 444231850UL, 1500204748UL, 1077470703UL, 1630597179UL, 1382588806UL, +138805391UL, 1636536505UL, 3118018426UL, 3461152216UL, 2486547351UL, 2045361316UL, 2976067436UL, 468876399UL, 1407419455UL, 3226137264UL, 414206328UL, 1011039713UL, 3537947031UL, 2359787831UL, 258556532UL, 3615987029UL, 3372097337UL, 3586352388UL, 1056198830UL, 1852291192UL, 3888893481UL, 746156045UL, 4203877603UL, 297851145UL, 2615507398UL, 1141098641UL, 1881412583UL, 3014341741UL, 2125186797UL, 229307235UL, 3476606674UL, 3553854689UL, +}, +{ +3768542219UL, 2777948797UL, 3328832678UL, 3488502819UL, 2708053041UL, 2217907094UL, 2133505056UL, 2218961277UL, 2148551748UL, 1420045625UL, 1709182366UL, 1816409641UL, 3791695288UL, 4207813971UL, 22588497UL, 2211317602UL, 616238454UL, 2394270012UL, 3212896041UL, 213408768UL, 2199328374UL, 3188624050UL, 811443809UL, 2818548979UL, 3150758902UL, 2022548260UL, 2462701924UL, 3793704672UL, 2358080321UL, 483288372UL, 450033142UL, 772942770UL, +2224873625UL, 241543410UL, 312552314UL, 1268067149UL, 915918620UL, 3906238422UL, 132545832UL, 3486041298UL, 2414090506UL, 3798383292UL, 2257004699UL, 130309284UL, 1158673651UL, 152325583UL, 3499865580UL, 4094273597UL, 1029041593UL, 93538481UL, 3963199522UL, 4215066819UL, 2851084137UL, 950351173UL, 2758084052UL, 3408506640UL, 2468905351UL, 3982226741UL, 3591899344UL, 2972879639UL, 3321078070UL, 252381865UL, 409397320UL, 741653003UL, +1936712854UL, 1198684021UL, 922916691UL, 10413506UL, 3546896248UL, 1704703870UL, 1479762464UL, 104399432UL, 4144557684UL, 68239720UL, 2666028745UL, 362625839UL, 2591539911UL, 2837165752UL, 2180226515UL, 4076543943UL, 2956460273UL, 312410753UL, 2566731139UL, 2532653524UL, 2399030172UL, 207904356UL, 354574195UL, 485696336UL, 3816686234UL, 3016971115UL, 4272692603UL, 2352732136UL, 33493163UL, 780255811UL, 4092242980UL, 4121521600UL, +2119254314UL, 42767673UL, 1081488778UL, 2757446871UL, 2267513620UL, 3472164720UL, 2750308207UL, 1707164045UL, 3125591821UL, 3236687597UL, 299194858UL, 537384087UL, 1695155491UL, 2078250102UL, 1705861659UL, 2416322096UL, 1692335914UL, 1178915980UL, 3405431297UL, 4059323309UL, 2014660182UL, 3847682866UL, 4037583683UL, 2629253995UL, 867809161UL, 2167953720UL, 2290558548UL, 417635396UL, 53496289UL, 1890906570UL, 2842247580UL, 807266805UL, +1226139132UL, 2067929784UL, 1697038549UL, 3312131466UL, 1234311530UL, 3199840935UL, 4185078776UL, 1807030355UL, 215385887UL, 845421530UL, 1350380353UL, 4209181096UL, 2576197887UL, 1275262872UL, 2806513944UL, 2718623701UL, 2779287384UL, 71403197UL, 219220133UL, 2181111477UL, 2000396844UL, 3595837555UL, 1232425455UL, 2630647391UL, 3280867676UL, 2622740782UL, 1578938469UL, 3624564545UL, 992324522UL, 3056113148UL, 3473635768UL, 3664935418UL, +1786902552UL, 3768542219UL, 2777948797UL, 3328832678UL, 3488502819UL, 2530862473UL, 2217907094UL, 2133505056UL, 2218961277UL, 2148551748UL, 4050672856UL, 1709182366UL, 1816409641UL, 3791695288UL, 4207813971UL, 4175126713UL, 2211317602UL, 616238454UL, 2394270012UL, 3212896041UL, 732700649UL, 2199328374UL, 3188624050UL, 811443809UL, 2818548979UL, 972036137UL, 2022548260UL, 2462701924UL, 3793704672UL, 2358080321UL, 1200725173UL, 450033142UL, +772942770UL, 2224873625UL, 241543410UL, 1907109304UL, 1268067149UL, 915918620UL, 3906238422UL, 132545832UL, 301668366UL, 2414090506UL, 3798383292UL, 2257004699UL, 130309284UL, 1228520287UL, 152325583UL, 3499865580UL, 4094273597UL, 1029041593UL, 3267460249UL, 3963199522UL, 4215066819UL, 2851084137UL, 950351173UL, 47361585UL, 3408506640UL, 2468905351UL, 3982226741UL, 3591899344UL, 1878226915UL, 3321078070UL, 252381865UL, 409397320UL, +741653003UL, 1716437506UL, 1198684021UL, 922916691UL, 10413506UL, 3546896248UL, 1591998796UL, 1479762464UL, 104399432UL, 4144557684UL, 68239720UL, 3810955599UL, 362625839UL, 2591539911UL, 2837165752UL, 2180226515UL, 3908378015UL, 2956460273UL, 312410753UL, 2566731139UL, 2532653524UL, 687490649UL, 207904356UL, 354574195UL, 485696336UL, 3816686234UL, 378445403UL, 4272692603UL, 2352732136UL, 33493163UL, 780255811UL, 1303281526UL, +4121521600UL, 2119254314UL, 42767673UL, 1081488778UL, 1734311274UL, 2267513620UL, 3472164720UL, 2750308207UL, 1707164045UL, 4212588163UL, 3236687597UL, 299194858UL, 537384087UL, 1695155491UL, 2250704950UL, 1705861659UL, 2416322096UL, 1692335914UL, 1178915980UL, 677982197UL, 4059323309UL, 2014660182UL, 3847682866UL, 4037583683UL, 1765435945UL, 867809161UL, 2167953720UL, 2290558548UL, 417635396UL, 2125103002UL, 1890906570UL, 2842247580UL, +807266805UL, 1226139132UL, 2056644398UL, 1697038549UL, 3312131466UL, 1234311530UL, 3199840935UL, 3063718636UL, 1807030355UL, 215385887UL, 845421530UL, 1350380353UL, 3610667273UL, 2576197887UL, 1275262872UL, 2806513944UL, 2718623701UL, 2492912955UL, 71403197UL, 219220133UL, 2181111477UL, 2000396844UL, 3465351710UL, 1232425455UL, 2630647391UL, 3280867676UL, 2622740782UL, 1331873639UL, 3624564545UL, 992324522UL, 3056113148UL, 3473635768UL, +782257020UL, 1786902552UL, 3768542219UL, 2777948797UL, 3328832678UL, 856888454UL, 2530862473UL, 2217907094UL, 2133505056UL, 2218961277UL, 3752437534UL, 4050672856UL, 1709182366UL, 1816409641UL, 3791695288UL, 1581813910UL, 4175126713UL, 2211317602UL, 616238454UL, 2394270012UL, 1796414157UL, 732700649UL, 2199328374UL, 3188624050UL, 811443809UL, 4225173324UL, 972036137UL, 2022548260UL, 2462701924UL, 3793704672UL, 1410793611UL, 1200725173UL, +450033142UL, 772942770UL, 2224873625UL, 3889840648UL, 1907109304UL, 1268067149UL, 915918620UL, 3906238422UL, 1249098244UL, 301668366UL, 2414090506UL, 3798383292UL, 2257004699UL, 1620796656UL, 1228520287UL, 152325583UL, 3499865580UL, 4094273597UL, 82853050UL, 3267460249UL, 3963199522UL, 4215066819UL, 2851084137UL, 1212493334UL, 47361585UL, 3408506640UL, 2468905351UL, 3982226741UL, 3195419905UL, 1878226915UL, 3321078070UL, 252381865UL, +409397320UL, 1584154733UL, 1716437506UL, 1198684021UL, 922916691UL, 10413506UL, 1734068880UL, 1591998796UL, 1479762464UL, 104399432UL, 4144557684UL, 1973878859UL, 3810955599UL, 362625839UL, 2591539911UL, 2837165752UL, 1727282404UL, 3908378015UL, 2956460273UL, 312410753UL, 2566731139UL, 3656295687UL, 687490649UL, 207904356UL, 354574195UL, 485696336UL, 355953909UL, 378445403UL, 4272692603UL, 2352732136UL, 33493163UL, 3784169684UL, +1303281526UL, 4121521600UL, 2119254314UL, 42767673UL, 2331527847UL, 1734311274UL, 2267513620UL, 3472164720UL, 2750308207UL, 820692528UL, 4212588163UL, 3236687597UL, 299194858UL, 537384087UL, 781151234UL, 2250704950UL, 1705861659UL, 2416322096UL, 1692335914UL, 4288008793UL, 677982197UL, 4059323309UL, 2014660182UL, 3847682866UL, 3328850880UL, 1765435945UL, 867809161UL, 2167953720UL, 2290558548UL, 542850707UL, 2125103002UL, 1890906570UL, +2842247580UL, 807266805UL, 3803006390UL, 2056644398UL, 1697038549UL, 3312131466UL, 1234311530UL, 809106036UL, 3063718636UL, 1807030355UL, 215385887UL, 845421530UL, 654189622UL, 3610667273UL, 2576197887UL, 1275262872UL, 2806513944UL, 1517875462UL, 2492912955UL, 71403197UL, 219220133UL, 2181111477UL, 3826277490UL, 3465351710UL, 1232425455UL, 2630647391UL, 3280867676UL, 3343597872UL, 1331873639UL, 3624564545UL, 992324522UL, 3056113148UL, +3725661598UL, 782257020UL, 1786902552UL, 3768542219UL, 2777948797UL, 3392298403UL, 856888454UL, 2530862473UL, 2217907094UL, 2133505056UL, 4160889036UL, 3752437534UL, 4050672856UL, 1709182366UL, 1816409641UL, 1282922706UL, 1581813910UL, 4175126713UL, 2211317602UL, 616238454UL, 3806252779UL, 1796414157UL, 732700649UL, 2199328374UL, 3188624050UL, 983474330UL, 4225173324UL, 972036137UL, 2022548260UL, 2462701924UL, 880446667UL, 1410793611UL, +1200725173UL, 450033142UL, 772942770UL, 3179870546UL, 3889840648UL, 1907109304UL, 1268067149UL, 915918620UL, 4261932110UL, 1249098244UL, 301668366UL, 2414090506UL, 3798383292UL, 471794009UL, 1620796656UL, 1228520287UL, 152325583UL, 3499865580UL, 1275109063UL, 82853050UL, 3267460249UL, 3963199522UL, 4215066819UL, 4209882674UL, 1212493334UL, 47361585UL, 3408506640UL, 2468905351UL, 1324785625UL, 3195419905UL, 1878226915UL, 3321078070UL, +252381865UL, 4259927884UL, 1584154733UL, 1716437506UL, 1198684021UL, 922916691UL, 1800164165UL, 1734068880UL, 1591998796UL, 1479762464UL, 104399432UL, 2774114308UL, 1973878859UL, 3810955599UL, 362625839UL, 2591539911UL, 2126614872UL, 1727282404UL, 3908378015UL, 2956460273UL, 312410753UL, 4098052715UL, 3656295687UL, 687490649UL, 207904356UL, 354574195UL, 937379582UL, 355953909UL, 378445403UL, 4272692603UL, 2352732136UL, 2694800574UL, +3784169684UL, 1303281526UL, 4121521600UL, 2119254314UL, 1741415022UL, 2331527847UL, 1734311274UL, 2267513620UL, 3472164720UL, 480821513UL, 820692528UL, 4212588163UL, 3236687597UL, 299194858UL, 1128762168UL, 781151234UL, 2250704950UL, 1705861659UL, 2416322096UL, 160918735UL, 4288008793UL, 677982197UL, 4059323309UL, 2014660182UL, 3354205317UL, 3328850880UL, 1765435945UL, 867809161UL, 2167953720UL, 3363861382UL, 542850707UL, 2125103002UL, +1890906570UL, 2842247580UL, 2459935488UL, 3803006390UL, 2056644398UL, 1697038549UL, 3312131466UL, 2378675900UL, 809106036UL, 3063718636UL, 1807030355UL, 215385887UL, 3528413525UL, 654189622UL, 3610667273UL, 2576197887UL, 1275262872UL, 993221887UL, 1517875462UL, 2492912955UL, 71403197UL, 219220133UL, 1805256638UL, 3826277490UL, 3465351710UL, 1232425455UL, 2630647391UL, 3718538519UL, 3343597872UL, 1331873639UL, 3624564545UL, 992324522UL, +3490576382UL, 2532191937UL, 1108692984UL, 802110050UL, 3984561242UL, 1973015939UL, 1351080551UL, 2382044123UL, 2393286227UL, 860228704UL, 179528099UL, 3569709850UL, 233527199UL, 3657599850UL, 3269634908UL, 3278075383UL, 4037814788UL, 952837871UL, 2050210570UL, 2376157484UL, 2566048929UL, 4200278597UL, 123440514UL, 573557299UL, 1585379806UL, 4012659271UL, 4000306490UL, 2508478465UL, 970078629UL, 4064973573UL, 645149301UL, 109544347UL, +647594029UL, 2097163688UL, 1515080116UL, 2142799649UL, 2519702653UL, 3122920796UL, 1952249156UL, 3932382760UL, 2155292687UL, 2517875978UL, 249059416UL, 4282787227UL, 2595461065UL, 1004349415UL, 2151451255UL, 2510715277UL, 3004500356UL, 3410567758UL, 344538405UL, 1946747709UL, 470298928UL, 1033671146UL, 4207801290UL, 1411375630UL, 3419808553UL, 3218285984UL, 3584735265UL, 811222695UL, 3898833227UL, 3535298390UL, 3764741581UL, 3927026520UL, +2850086968UL, 2818485449UL, 1963038474UL, 1871366998UL, 1900570117UL, 997663534UL, 746627295UL, 1827737271UL, 3814054979UL, 728285698UL, 1696496343UL, 1696888597UL, 1010837663UL, 1756050352UL, 785994134UL, 1436861536UL, 1949153732UL, 2360018842UL, 1703393654UL, 2248338006UL, 3884572674UL, 789998735UL, 1155994673UL, 2022469457UL, 223162974UL, 309571006UL, 725482797UL, 3909032036UL, 2531190541UL, 373676789UL, 1061107200UL, 4231921550UL, +558635876UL, 2773807977UL, 1860218585UL, 1150041015UL, 2252812038UL, 2413330952UL, 191909567UL, 3518171813UL, 3513416318UL, 2679253717UL, 3850755687UL, 1564154710UL, 324714884UL, 1600953447UL, 4095583159UL, 1796641692UL, 2518000547UL, 3621187982UL, 501166402UL, 2112782420UL, 1704276185UL, 2249859782UL, 3754293422UL, 1942321901UL, 1851019104UL, 240158224UL, 3181132144UL, 2281632719UL, 808029657UL, 1721710011UL, 2287207169UL, 3044484177UL, +2363339534UL, 805273402UL, 3696016147UL, 3549191229UL, 3353631259UL, 2946802391UL, 383414270UL, 300735554UL, 471515206UL, 1907815837UL, 1576327662UL, 3825043525UL, 2817119733UL, 1973847200UL, 1398317206UL, 2221853087UL, 501440864UL, 642467132UL, 494410179UL, 1191241925UL, 3549838846UL, 3621239619UL, 2640266286UL, 4140123024UL, 315957218UL, 3696758268UL, 2502777875UL, 2150738616UL, 1570099119UL, 2598276767UL, 3585886712UL, 230047417UL, +}, +{ +220882755UL, 630187688UL, 2600079656UL, 3103815531UL, 4259457395UL, 306940008UL, 760977254UL, 558299017UL, 73879495UL, 2342545344UL, 572800511UL, 3922797738UL, 3754011306UL, 698257357UL, 1274843132UL, 1455757442UL, 1014649591UL, 3205662508UL, 2997738251UL, 613949432UL, 2267018388UL, 2925762681UL, 3702061213UL, 299380602UL, 1711070497UL, 4140032336UL, 4134705925UL, 2836703879UL, 3776863395UL, 507121465UL, 3480792188UL, 1862887216UL, +247780795UL, 2528677869UL, 2881446422UL, 271754977UL, 833498724UL, 1489102731UL, 3636156177UL, 1839744487UL, 2011839858UL, 2353400914UL, 510437606UL, 561141583UL, 2979592314UL, 3844268262UL, 3011027242UL, 3113817193UL, 3491178377UL, 1448376742UL, 2478683391UL, 2597550150UL, 699310968UL, 1979488062UL, 277591964UL, 1312002175UL, 168047351UL, 1826859926UL, 2030631355UL, 3097860388UL, 1950614326UL, 4070838751UL, 4454933UL, 1890661188UL, +3929835227UL, 1008498572UL, 3301557438UL, 3906313590UL, 1240635175UL, 280935563UL, 113509402UL, 226900299UL, 1246395851UL, 1220916742UL, 2651515540UL, 2058590162UL, 1983114332UL, 2040467861UL, 780818345UL, 544262576UL, 2826997265UL, 349354812UL, 2360120613UL, 1181324247UL, 2380347783UL, 3938729706UL, 1610628643UL, 2008635822UL, 2937909233UL, 1583978206UL, 3589167073UL, 1942470196UL, 402177406UL, 2636510744UL, 3709747478UL, 2428569572UL, +4071828137UL, 2880315633UL, 1433558231UL, 1137076031UL, 3833202201UL, 2378168250UL, 1412413704UL, 3349323744UL, 1740721660UL, 3155643175UL, 2580327273UL, 3020661883UL, 1658910832UL, 2065649368UL, 3277572880UL, 3795585437UL, 1266185861UL, 2925935368UL, 4147230645UL, 203577834UL, 2230529041UL, 2864778434UL, 270386174UL, 2867122465UL, 2676624544UL, 2035972330UL, 500973884UL, 2983028740UL, 117131866UL, 1456450936UL, 429171245UL, 3921563262UL, +342800398UL, 255116920UL, 1219580025UL, 1549741331UL, 3832317567UL, 3750096895UL, 4036554472UL, 4099775516UL, 1451717480UL, 149159438UL, 3593827664UL, 1406572509UL, 27774796UL, 1138983585UL, 1577536190UL, 978350835UL, 2704344602UL, 95204061UL, 1507155668UL, 304760810UL, 1981315657UL, 3139306913UL, 3908131532UL, 3767856445UL, 3851422551UL, 2018732047UL, 2474676116UL, 2745551516UL, 1585868430UL, 1125303733UL, 3147584753UL, 2368921260UL, +1524991519UL, 220882755UL, 630187688UL, 2600079656UL, 3103815531UL, 2671841243UL, 306940008UL, 760977254UL, 558299017UL, 73879495UL, 1196617651UL, 572800511UL, 3922797738UL, 3754011306UL, 698257357UL, 1982654891UL, 1455757442UL, 1014649591UL, 3205662508UL, 2997738251UL, 3769735713UL, 2267018388UL, 2925762681UL, 3702061213UL, 299380602UL, 2224634157UL, 4140032336UL, 4134705925UL, 2836703879UL, 3776863395UL, 1027030708UL, 3480792188UL, +1862887216UL, 247780795UL, 2528677869UL, 300214141UL, 271754977UL, 833498724UL, 1489102731UL, 3636156177UL, 1683033001UL, 2011839858UL, 2353400914UL, 510437606UL, 561141583UL, 2832813585UL, 3844268262UL, 3011027242UL, 3113817193UL, 3491178377UL, 316500941UL, 2478683391UL, 2597550150UL, 699310968UL, 1979488062UL, 4092049617UL, 1312002175UL, 168047351UL, 1826859926UL, 2030631355UL, 2797906491UL, 1950614326UL, 4070838751UL, 4454933UL, +1890661188UL, 2602196847UL, 1008498572UL, 3301557438UL, 3906313590UL, 1240635175UL, 946440664UL, 113509402UL, 226900299UL, 1246395851UL, 1220916742UL, 1314772486UL, 2058590162UL, 1983114332UL, 2040467861UL, 780818345UL, 3064382079UL, 2826997265UL, 349354812UL, 2360120613UL, 1181324247UL, 3434653713UL, 3938729706UL, 1610628643UL, 2008635822UL, 2937909233UL, 2815835447UL, 3589167073UL, 1942470196UL, 402177406UL, 2636510744UL, 865459039UL, +2428569572UL, 4071828137UL, 2880315633UL, 1433558231UL, 1582478959UL, 3833202201UL, 2378168250UL, 1412413704UL, 3349323744UL, 3686787615UL, 3155643175UL, 2580327273UL, 3020661883UL, 1658910832UL, 3152644489UL, 3277572880UL, 3795585437UL, 1266185861UL, 2925935368UL, 3101079227UL, 203577834UL, 2230529041UL, 2864778434UL, 270386174UL, 3024925346UL, 2676624544UL, 2035972330UL, 500973884UL, 2983028740UL, 974511421UL, 1456450936UL, 429171245UL, +3921563262UL, 342800398UL, 1540218139UL, 1219580025UL, 1549741331UL, 3832317567UL, 3750096895UL, 2195381148UL, 4099775516UL, 1451717480UL, 149159438UL, 3593827664UL, 3715984838UL, 27774796UL, 1138983585UL, 1577536190UL, 978350835UL, 2060213898UL, 95204061UL, 1507155668UL, 304760810UL, 1981315657UL, 774471092UL, 3908131532UL, 3767856445UL, 3851422551UL, 2018732047UL, 1649125731UL, 2745551516UL, 1585868430UL, 1125303733UL, 3147584753UL, +1661721342UL, 1524991519UL, 220882755UL, 630187688UL, 2600079656UL, 3647143842UL, 2671841243UL, 306940008UL, 760977254UL, 558299017UL, 3406011854UL, 1196617651UL, 572800511UL, 3922797738UL, 3754011306UL, 2314291278UL, 1982654891UL, 1455757442UL, 1014649591UL, 3205662508UL, 3471741326UL, 3769735713UL, 2267018388UL, 2925762681UL, 3702061213UL, 1593850639UL, 2224634157UL, 4140032336UL, 4134705925UL, 2836703879UL, 3918266498UL, 1027030708UL, +3480792188UL, 1862887216UL, 247780795UL, 3383776045UL, 300214141UL, 271754977UL, 833498724UL, 1489102731UL, 2477093804UL, 1683033001UL, 2011839858UL, 2353400914UL, 510437606UL, 2361664959UL, 2832813585UL, 3844268262UL, 3011027242UL, 3113817193UL, 1468705704UL, 316500941UL, 2478683391UL, 2597550150UL, 699310968UL, 1593029686UL, 4092049617UL, 1312002175UL, 168047351UL, 1826859926UL, 3922295193UL, 2797906491UL, 1950614326UL, 4070838751UL, +4454933UL, 485374579UL, 2602196847UL, 1008498572UL, 3301557438UL, 3906313590UL, 2102043683UL, 946440664UL, 113509402UL, 226900299UL, 1246395851UL, 2635764090UL, 1314772486UL, 2058590162UL, 1983114332UL, 2040467861UL, 354791UL, 3064382079UL, 2826997265UL, 349354812UL, 2360120613UL, 2126504772UL, 3434653713UL, 3938729706UL, 1610628643UL, 2008635822UL, 2400061949UL, 2815835447UL, 3589167073UL, 1942470196UL, 402177406UL, 806469309UL, +865459039UL, 2428569572UL, 4071828137UL, 2880315633UL, 2512200928UL, 1582478959UL, 3833202201UL, 2378168250UL, 1412413704UL, 2767451252UL, 3686787615UL, 3155643175UL, 2580327273UL, 3020661883UL, 1040874588UL, 3152644489UL, 3277572880UL, 3795585437UL, 1266185861UL, 238446394UL, 3101079227UL, 203577834UL, 2230529041UL, 2864778434UL, 653319712UL, 3024925346UL, 2676624544UL, 2035972330UL, 500973884UL, 3839534784UL, 974511421UL, 1456450936UL, +429171245UL, 3921563262UL, 602320448UL, 1540218139UL, 1219580025UL, 1549741331UL, 3832317567UL, 1068872823UL, 2195381148UL, 4099775516UL, 1451717480UL, 149159438UL, 1699607068UL, 3715984838UL, 27774796UL, 1138983585UL, 1577536190UL, 837921790UL, 2060213898UL, 95204061UL, 1507155668UL, 304760810UL, 1446133066UL, 774471092UL, 3908131532UL, 3767856445UL, 3851422551UL, 2672625648UL, 1649125731UL, 2745551516UL, 1585868430UL, 1125303733UL, +2181520384UL, 1661721342UL, 1524991519UL, 220882755UL, 630187688UL, 1599074811UL, 3647143842UL, 2671841243UL, 306940008UL, 760977254UL, 3020017536UL, 3406011854UL, 1196617651UL, 572800511UL, 3922797738UL, 810584907UL, 2314291278UL, 1982654891UL, 1455757442UL, 1014649591UL, 1775783567UL, 3471741326UL, 3769735713UL, 2267018388UL, 2925762681UL, 319055602UL, 1593850639UL, 2224634157UL, 4140032336UL, 4134705925UL, 2794599326UL, 3918266498UL, +1027030708UL, 3480792188UL, 1862887216UL, 659607854UL, 3383776045UL, 300214141UL, 271754977UL, 833498724UL, 4054679386UL, 2477093804UL, 1683033001UL, 2011839858UL, 2353400914UL, 283191425UL, 2361664959UL, 2832813585UL, 3844268262UL, 3011027242UL, 137688840UL, 1468705704UL, 316500941UL, 2478683391UL, 2597550150UL, 1468220070UL, 1593029686UL, 4092049617UL, 1312002175UL, 168047351UL, 1602414610UL, 3922295193UL, 2797906491UL, 1950614326UL, +4070838751UL, 3858763082UL, 485374579UL, 2602196847UL, 1008498572UL, 3301557438UL, 2719858709UL, 2102043683UL, 946440664UL, 113509402UL, 226900299UL, 798285817UL, 2635764090UL, 1314772486UL, 2058590162UL, 1983114332UL, 2526463430UL, 354791UL, 3064382079UL, 2826997265UL, 349354812UL, 249430921UL, 2126504772UL, 3434653713UL, 3938729706UL, 1610628643UL, 967431506UL, 2400061949UL, 2815835447UL, 3589167073UL, 1942470196UL, 669129162UL, +806469309UL, 865459039UL, 2428569572UL, 4071828137UL, 3447449944UL, 2512200928UL, 1582478959UL, 3833202201UL, 2378168250UL, 1945768856UL, 2767451252UL, 3686787615UL, 3155643175UL, 2580327273UL, 2905624117UL, 1040874588UL, 3152644489UL, 3277572880UL, 3795585437UL, 3869959934UL, 238446394UL, 3101079227UL, 203577834UL, 2230529041UL, 1087760616UL, 653319712UL, 3024925346UL, 2676624544UL, 2035972330UL, 741014356UL, 3839534784UL, 974511421UL, +1456450936UL, 429171245UL, 598362053UL, 602320448UL, 1540218139UL, 1219580025UL, 1549741331UL, 401740328UL, 1068872823UL, 2195381148UL, 4099775516UL, 1451717480UL, 412110161UL, 1699607068UL, 3715984838UL, 27774796UL, 1138983585UL, 1531670562UL, 837921790UL, 2060213898UL, 95204061UL, 1507155668UL, 90279751UL, 1446133066UL, 774471092UL, 3908131532UL, 3767856445UL, 1136546910UL, 2672625648UL, 1649125731UL, 2745551516UL, 1585868430UL, +857721974UL, 1470900829UL, 64550776UL, 3252081369UL, 1649342279UL, 378546910UL, 3444980597UL, 3134750739UL, 1010105258UL, 1395608241UL, 1003208120UL, 3960524028UL, 3200241620UL, 3079969898UL, 1508044775UL, 4153769914UL, 2838198142UL, 773928818UL, 25836261UL, 3812652461UL, 3870603819UL, 931071963UL, 2565579710UL, 2930918109UL, 1091097445UL, 2223628368UL, 2934719684UL, 430797922UL, 2102409587UL, 720592077UL, 1675280068UL, 2578226918UL, +1316600845UL, 3427946098UL, 682896800UL, 1861125007UL, 251332674UL, 1502078012UL, 3020904394UL, 1458399451UL, 3088315263UL, 1635399147UL, 3605560130UL, 1755669804UL, 3754169290UL, 962708070UL, 3896576937UL, 3764679740UL, 2707457262UL, 3082551065UL, 1558451132UL, 1046028905UL, 3206335691UL, 731828142UL, 1765772975UL, 1195727587UL, 2664218451UL, 4234957963UL, 4073757168UL, 3230123616UL, 683981262UL, 607599877UL, 3659273671UL, 3230354324UL, +3393069074UL, 3250708814UL, 2229361194UL, 3923623619UL, 4093221649UL, 2441971643UL, 1787414237UL, 3603907850UL, 2254399656UL, 3508336126UL, 3578571587UL, 2383062806UL, 1012097006UL, 4250629546UL, 2086981615UL, 4190388250UL, 1399942361UL, 400707931UL, 3159618664UL, 2129750192UL, 911779896UL, 2736829998UL, 1909644954UL, 2168355517UL, 1583901478UL, 3468891177UL, 509297602UL, 769296769UL, 1865028750UL, 43276967UL, 3375387845UL, 2647467777UL, +1544731454UL, 3479333955UL, 4279441447UL, 485490313UL, 3523606596UL, 2880752852UL, 1946443431UL, 3760803481UL, 3115278477UL, 3693898557UL, 2387822435UL, 334412170UL, 2054111717UL, 269013084UL, 170401553UL, 3456013554UL, 3395842846UL, 508189059UL, 3398715186UL, 3862791669UL, 2741070272UL, 65318715UL, 1933435210UL, 4086198650UL, 3033193928UL, 1242412691UL, 3397363281UL, 3187419149UL, 1019508117UL, 562380742UL, 961415837UL, 2990412400UL, +3597720222UL, 2754100415UL, 1793508822UL, 966564784UL, 1875616532UL, 394646945UL, 1386107842UL, 2750810827UL, 2931007937UL, 3356489930UL, 2358364634UL, 3703772713UL, 3188884403UL, 2793590498UL, 3285138686UL, 515002680UL, 521510516UL, 887213583UL, 1873460781UL, 1583027667UL, 613895001UL, 557578628UL, 1892686243UL, 1974572772UL, 595831726UL, 229299738UL, 3847982294UL, 448248098UL, 1493822844UL, 3326405260UL, 2752463855UL, 128616819UL, +}, +{ +2014765631UL, 3938779303UL, 1811986049UL, 2101875601UL, 887194972UL, 3966228860UL, 3450775746UL, 4026039255UL, 4082308025UL, 432404123UL, 3181099213UL, 1228097256UL, 2368258457UL, 2953933351UL, 2582232464UL, 1657799516UL, 3525421629UL, 3927364159UL, 978138132UL, 3603597064UL, 342571522UL, 2100072168UL, 676229632UL, 2062864895UL, 3713317279UL, 4255773013UL, 1179492389UL, 3501226604UL, 1641801113UL, 2066614519UL, 3303232023UL, 1717768923UL, +2333501450UL, 4246883128UL, 1655087824UL, 1547897374UL, 754215285UL, 2832638094UL, 1365153701UL, 3309513970UL, 765738141UL, 1177808869UL, 324127419UL, 1171195868UL, 3494966448UL, 1714410667UL, 3645762436UL, 603810292UL, 489970006UL, 3126166124UL, 1616642501UL, 2646836239UL, 734727001UL, 118064420UL, 1164195304UL, 3692353914UL, 2267623847UL, 405457397UL, 2510437259UL, 3245015882UL, 2110859730UL, 967046702UL, 265790493UL, 3007163818UL, +3178475505UL, 1784447992UL, 3662964942UL, 1509963062UL, 1867864652UL, 1377871790UL, 4185567242UL, 657897796UL, 1762205546UL, 3895944199UL, 693988565UL, 2359023506UL, 1667660316UL, 478341078UL, 1898651054UL, 2352226314UL, 202416031UL, 855532642UL, 2290137962UL, 1573485803UL, 3675269487UL, 2346740592UL, 3111005795UL, 1741227661UL, 1222572879UL, 2176146608UL, 1595608675UL, 197451178UL, 1729118168UL, 876472937UL, 3201705210UL, 2315408645UL, +699968623UL, 2185639066UL, 3960900430UL, 539499973UL, 4226318752UL, 266371152UL, 2714506838UL, 945022093UL, 1378798863UL, 1925020181UL, 574417318UL, 1341455098UL, 3664225722UL, 3020780778UL, 3256613994UL, 2081255019UL, 3082744844UL, 3572803922UL, 1726854692UL, 1167777002UL, 557257486UL, 3577067012UL, 3806913480UL, 1578577194UL, 2631896730UL, 3937479909UL, 826138924UL, 670145071UL, 832017019UL, 715875283UL, 2008704579UL, 804955545UL, +4184114494UL, 867004874UL, 3586861289UL, 1190193155UL, 3288754776UL, 2271906590UL, 2007547109UL, 2206084232UL, 1621944575UL, 973990634UL, 3981493346UL, 1972746975UL, 1040348653UL, 2895228417UL, 691038334UL, 775610724UL, 3837025597UL, 714850057UL, 2912426839UL, 774555258UL, 3553866253UL, 2096154755UL, 1645117543UL, 3401470072UL, 2056183169UL, 2029528044UL, 3145728013UL, 1090530001UL, 49523828UL, 2228313334UL, 4013648604UL, 4289025873UL, +2749397923UL, 2014765631UL, 3938779303UL, 1811986049UL, 2101875601UL, 1575247143UL, 3966228860UL, 3450775746UL, 4026039255UL, 4082308025UL, 532118065UL, 3181099213UL, 1228097256UL, 2368258457UL, 2953933351UL, 896129082UL, 1657799516UL, 3525421629UL, 3927364159UL, 978138132UL, 3403930517UL, 342571522UL, 2100072168UL, 676229632UL, 2062864895UL, 38934050UL, 4255773013UL, 1179492389UL, 3501226604UL, 1641801113UL, 4195983797UL, 3303232023UL, +1717768923UL, 2333501450UL, 4246883128UL, 2854551758UL, 1547897374UL, 754215285UL, 2832638094UL, 1365153701UL, 1406220165UL, 765738141UL, 1177808869UL, 324127419UL, 1171195868UL, 625985592UL, 1714410667UL, 3645762436UL, 603810292UL, 489970006UL, 344948229UL, 1616642501UL, 2646836239UL, 734727001UL, 118064420UL, 3360380275UL, 3692353914UL, 2267623847UL, 405457397UL, 2510437259UL, 3697919521UL, 2110859730UL, 967046702UL, 265790493UL, +3007163818UL, 1395299303UL, 1784447992UL, 3662964942UL, 1509963062UL, 1867864652UL, 849544728UL, 4185567242UL, 657897796UL, 1762205546UL, 3895944199UL, 1219998053UL, 2359023506UL, 1667660316UL, 478341078UL, 1898651054UL, 943166064UL, 202416031UL, 855532642UL, 2290137962UL, 1573485803UL, 4238971908UL, 2346740592UL, 3111005795UL, 1741227661UL, 1222572879UL, 2670048596UL, 1595608675UL, 197451178UL, 1729118168UL, 876472937UL, 94688481UL, +2315408645UL, 699968623UL, 2185639066UL, 3960900430UL, 1224638706UL, 4226318752UL, 266371152UL, 2714506838UL, 945022093UL, 2683523818UL, 1925020181UL, 574417318UL, 1341455098UL, 3664225722UL, 1168593559UL, 3256613994UL, 2081255019UL, 3082744844UL, 3572803922UL, 2816021735UL, 1167777002UL, 557257486UL, 3577067012UL, 3806913480UL, 740433434UL, 2631896730UL, 3937479909UL, 826138924UL, 670145071UL, 4127240538UL, 715875283UL, 2008704579UL, +804955545UL, 4184114494UL, 1692532062UL, 3586861289UL, 1190193155UL, 3288754776UL, 2271906590UL, 922306057UL, 2206084232UL, 1621944575UL, 973990634UL, 3981493346UL, 3555073644UL, 1040348653UL, 2895228417UL, 691038334UL, 775610724UL, 1798939042UL, 714850057UL, 2912426839UL, 774555258UL, 3553866253UL, 4209859609UL, 1645117543UL, 3401470072UL, 2056183169UL, 2029528044UL, 2169159734UL, 1090530001UL, 49523828UL, 2228313334UL, 4013648604UL, +1499948031UL, 2749397923UL, 2014765631UL, 3938779303UL, 1811986049UL, 2169095159UL, 1575247143UL, 3966228860UL, 3450775746UL, 4026039255UL, 1220311069UL, 532118065UL, 3181099213UL, 1228097256UL, 2368258457UL, 649921441UL, 896129082UL, 1657799516UL, 3525421629UL, 3927364159UL, 2546335470UL, 3403930517UL, 342571522UL, 2100072168UL, 676229632UL, 3090148374UL, 38934050UL, 4255773013UL, 1179492389UL, 3501226604UL, 2613176152UL, 4195983797UL, +3303232023UL, 1717768923UL, 2333501450UL, 3923041739UL, 2854551758UL, 1547897374UL, 754215285UL, 2832638094UL, 731392091UL, 1406220165UL, 765738141UL, 1177808869UL, 324127419UL, 12876722UL, 625985592UL, 1714410667UL, 3645762436UL, 603810292UL, 2789313462UL, 344948229UL, 1616642501UL, 2646836239UL, 734727001UL, 3369486664UL, 3360380275UL, 3692353914UL, 2267623847UL, 405457397UL, 4284067044UL, 3697919521UL, 2110859730UL, 967046702UL, +265790493UL, 2779045063UL, 1395299303UL, 1784447992UL, 3662964942UL, 1509963062UL, 3233239196UL, 849544728UL, 4185567242UL, 657897796UL, 1762205546UL, 2086953994UL, 1219998053UL, 2359023506UL, 1667660316UL, 478341078UL, 4137166515UL, 943166064UL, 202416031UL, 855532642UL, 2290137962UL, 1053737970UL, 4238971908UL, 2346740592UL, 3111005795UL, 1741227661UL, 3570501235UL, 2670048596UL, 1595608675UL, 197451178UL, 1729118168UL, 4162077327UL, +94688481UL, 2315408645UL, 699968623UL, 2185639066UL, 2842562270UL, 1224638706UL, 4226318752UL, 266371152UL, 2714506838UL, 755620309UL, 2683523818UL, 1925020181UL, 574417318UL, 1341455098UL, 3323621213UL, 1168593559UL, 3256613994UL, 2081255019UL, 3082744844UL, 3845230416UL, 2816021735UL, 1167777002UL, 557257486UL, 3577067012UL, 66225918UL, 740433434UL, 2631896730UL, 3937479909UL, 826138924UL, 522548622UL, 4127240538UL, 715875283UL, +2008704579UL, 804955545UL, 22190845UL, 1692532062UL, 3586861289UL, 1190193155UL, 3288754776UL, 610751818UL, 922306057UL, 2206084232UL, 1621944575UL, 973990634UL, 1771882567UL, 3555073644UL, 1040348653UL, 2895228417UL, 691038334UL, 149995790UL, 1798939042UL, 714850057UL, 2912426839UL, 774555258UL, 2020442761UL, 4209859609UL, 1645117543UL, 3401470072UL, 2056183169UL, 460813741UL, 2169159734UL, 1090530001UL, 49523828UL, 2228313334UL, +504317288UL, 1499948031UL, 2749397923UL, 2014765631UL, 3938779303UL, 1175469033UL, 2169095159UL, 1575247143UL, 3966228860UL, 3450775746UL, 1032079910UL, 1220311069UL, 532118065UL, 3181099213UL, 1228097256UL, 3353583885UL, 649921441UL, 896129082UL, 1657799516UL, 3525421629UL, 2830418357UL, 2546335470UL, 3403930517UL, 342571522UL, 2100072168UL, 1099053459UL, 3090148374UL, 38934050UL, 4255773013UL, 1179492389UL, 1634035942UL, 2613176152UL, +4195983797UL, 3303232023UL, 1717768923UL, 4175785502UL, 3923041739UL, 2854551758UL, 1547897374UL, 754215285UL, 3674851127UL, 731392091UL, 1406220165UL, 765738141UL, 1177808869UL, 776475327UL, 12876722UL, 625985592UL, 1714410667UL, 3645762436UL, 759189800UL, 2789313462UL, 344948229UL, 1616642501UL, 2646836239UL, 1228911282UL, 3369486664UL, 3360380275UL, 3692353914UL, 2267623847UL, 3058856811UL, 4284067044UL, 3697919521UL, 2110859730UL, +967046702UL, 3601311392UL, 2779045063UL, 1395299303UL, 1784447992UL, 3662964942UL, 284169442UL, 3233239196UL, 849544728UL, 4185567242UL, 657897796UL, 905886381UL, 2086953994UL, 1219998053UL, 2359023506UL, 1667660316UL, 2784311626UL, 4137166515UL, 943166064UL, 202416031UL, 855532642UL, 895862877UL, 1053737970UL, 4238971908UL, 2346740592UL, 3111005795UL, 1509264114UL, 3570501235UL, 2670048596UL, 1595608675UL, 197451178UL, 3653040124UL, +4162077327UL, 94688481UL, 2315408645UL, 699968623UL, 1071988392UL, 2842562270UL, 1224638706UL, 4226318752UL, 266371152UL, 4214356293UL, 755620309UL, 2683523818UL, 1925020181UL, 574417318UL, 119162126UL, 3323621213UL, 1168593559UL, 3256613994UL, 2081255019UL, 1317924999UL, 3845230416UL, 2816021735UL, 1167777002UL, 557257486UL, 638058809UL, 66225918UL, 740433434UL, 2631896730UL, 3937479909UL, 411228024UL, 522548622UL, 4127240538UL, +715875283UL, 2008704579UL, 2246049355UL, 22190845UL, 1692532062UL, 3586861289UL, 1190193155UL, 4078828073UL, 610751818UL, 922306057UL, 2206084232UL, 1621944575UL, 907181435UL, 1771882567UL, 3555073644UL, 1040348653UL, 2895228417UL, 940846326UL, 149995790UL, 1798939042UL, 714850057UL, 2912426839UL, 3345560812UL, 2020442761UL, 4209859609UL, 1645117543UL, 3401470072UL, 2036328600UL, 460813741UL, 2169159734UL, 1090530001UL, 49523828UL, +510136795UL, 2233313725UL, 1046048857UL, 700202384UL, 926275751UL, 4104982908UL, 3910999868UL, 1125213128UL, 492681420UL, 3891914731UL, 956545470UL, 115696875UL, 2957144177UL, 77090391UL, 467732901UL, 2599813105UL, 3888976883UL, 2098926023UL, 2844817051UL, 2069408123UL, 2239429902UL, 3793992219UL, 3020240490UL, 1721698056UL, 3012473888UL, 1537226153UL, 725991171UL, 61376035UL, 381912667UL, 3904514327UL, 40015731UL, 4263210119UL, +2876064791UL, 2732785471UL, 2934318283UL, 3134934287UL, 3161129365UL, 3789733734UL, 2954419388UL, 2742205850UL, 3488450208UL, 3252908703UL, 410643191UL, 3246033194UL, 2846558783UL, 828879673UL, 2428687670UL, 389617242UL, 63987225UL, 439842832UL, 2635895570UL, 3468152776UL, 4086700701UL, 3370617315UL, 2400127386UL, 4266992260UL, 3026019128UL, 4225721108UL, 1328114488UL, 2808680961UL, 3574018824UL, 4060262451UL, 2329039960UL, 1165344648UL, +3635963149UL, 2414703792UL, 2269100254UL, 832995451UL, 2143875746UL, 1031309981UL, 2129333746UL, 2606784227UL, 805236091UL, 666141116UL, 2749351381UL, 53998350UL, 2270447972UL, 2092784991UL, 877961283UL, 3019419608UL, 2438459472UL, 2273921167UL, 332279281UL, 3759993687UL, 2465113760UL, 3732237006UL, 322823266UL, 491053374UL, 686619591UL, 4192648122UL, 4118497267UL, 1948902148UL, 988375775UL, 2098328675UL, 3107501958UL, 2979856583UL, +2274193457UL, 6179961UL, 188209161UL, 1491245003UL, 3005972885UL, 1658799053UL, 3420802262UL, 2128792168UL, 3272743598UL, 4163716849UL, 817350318UL, 3372322557UL, 1525295885UL, 490587460UL, 3634834949UL, 2584809384UL, 3638373352UL, 2603765126UL, 3223396315UL, 4021061386UL, 2143780551UL, 248332433UL, 3654752967UL, 27201989UL, 3994156272UL, 5505477UL, 4260955724UL, 1175998822UL, 2665646240UL, 866875674UL, 3569324422UL, 202962714UL, +896177244UL, 3146417201UL, 1168925859UL, 2228636445UL, 105395449UL, 2567482935UL, 1301265751UL, 3739617610UL, 2486939910UL, 1891847857UL, 2647840744UL, 1141826566UL, 3360553996UL, 4267671927UL, 2546157872UL, 1143297884UL, 2049385137UL, 4288036836UL, 3347190546UL, 3480408604UL, 2756408254UL, 2396048567UL, 1151717877UL, 2211243289UL, 4221659024UL, 21773193UL, 1665317870UL, 3116384869UL, 3231689469UL, 3689471824UL, 1520574310UL, 463615415UL, +}, +{ +2647200400UL, 1592194261UL, 1289872755UL, 2079982087UL, 3431487085UL, 1101851783UL, 3373292799UL, 2148994262UL, 2785319928UL, 3206527339UL, 2731839331UL, 1280366172UL, 1146205735UL, 2930495205UL, 2876978398UL, 3885758458UL, 2062812458UL, 2448488486UL, 192141900UL, 3861696664UL, 2677929258UL, 3606729729UL, 2920965773UL, 1156521508UL, 3168665640UL, 298794036UL, 957896625UL, 2606719899UL, 3699219026UL, 3120096333UL, 2531109351UL, 1920936462UL, +2848868175UL, 1406404729UL, 2956672675UL, 1376226240UL, 3667482110UL, 2551426756UL, 3433640449UL, 2603906744UL, 4217864690UL, 47671552UL, 2993859190UL, 1269153270UL, 3463588775UL, 1655126430UL, 3453916724UL, 2157890969UL, 252769449UL, 1583335064UL, 2560819344UL, 52639671UL, 39618615UL, 313192112UL, 2625914283UL, 2964928555UL, 4226359627UL, 4141969666UL, 183405146UL, 1455378225UL, 2994063945UL, 3146629795UL, 2992956289UL, 368634554UL, +4110058153UL, 1156556441UL, 3690317172UL, 906928962UL, 3773042217UL, 948650679UL, 4134172918UL, 2922802573UL, 1417921660UL, 291400676UL, 3120733115UL, 3225369425UL, 3200455006UL, 2207799613UL, 1766261260UL, 914727455UL, 1927023103UL, 572959294UL, 3447057855UL, 4042691162UL, 840021910UL, 4187195325UL, 3627831667UL, 1671506539UL, 242673485UL, 3330397756UL, 776552069UL, 684550924UL, 261597601UL, 1857936262UL, 1022869402UL, 4209077103UL, +14248159UL, 2366156245UL, 1910356465UL, 2020463550UL, 873419743UL, 4290775093UL, 3670978210UL, 1726974037UL, 784115717UL, 3574834402UL, 357805142UL, 3820795621UL, 1854247318UL, 1161642656UL, 3977404318UL, 2054677775UL, 1737374322UL, 2852015019UL, 4277252452UL, 1392810771UL, 3742661504UL, 1900815804UL, 1965911170UL, 3540183220UL, 2106191537UL, 3606954134UL, 2108636204UL, 2981827052UL, 2506861567UL, 184003599UL, 3319252632UL, 1370913077UL, +940955681UL, 2244100002UL, 3683661822UL, 3215832318UL, 3463899341UL, 134577035UL, 3404365179UL, 2262494389UL, 88039196UL, 114405083UL, 1071449574UL, 4008494055UL, 765981248UL, 758357266UL, 2564125377UL, 901977407UL, 955156196UL, 3900980822UL, 134031448UL, 2566915950UL, 3445833537UL, 3138903399UL, 2113076217UL, 713587277UL, 3396078039UL, 3987657193UL, 3004104774UL, 800324742UL, 652529813UL, 3999083342UL, 486108562UL, 2103591900UL, +104743736UL, 2647200400UL, 1592194261UL, 1289872755UL, 2079982087UL, 552781204UL, 1101851783UL, 3373292799UL, 2148994262UL, 2785319928UL, 1222851809UL, 2731839331UL, 1280366172UL, 1146205735UL, 2930495205UL, 942360591UL, 3885758458UL, 2062812458UL, 2448488486UL, 192141900UL, 1909229999UL, 2677929258UL, 3606729729UL, 2920965773UL, 1156521508UL, 2995805883UL, 298794036UL, 957896625UL, 2606719899UL, 3699219026UL, 2447513005UL, 2531109351UL, +1920936462UL, 2848868175UL, 1406404729UL, 2751142611UL, 1376226240UL, 3667482110UL, 2551426756UL, 3433640449UL, 3724189478UL, 4217864690UL, 47671552UL, 2993859190UL, 1269153270UL, 2144136371UL, 1655126430UL, 3453916724UL, 2157890969UL, 252769449UL, 2959496542UL, 2560819344UL, 52639671UL, 39618615UL, 313192112UL, 2367743540UL, 2964928555UL, 4226359627UL, 4141969666UL, 183405146UL, 2006751422UL, 2994063945UL, 3146629795UL, 2992956289UL, +368634554UL, 1529794973UL, 1156556441UL, 3690317172UL, 906928962UL, 3773042217UL, 2005599428UL, 4134172918UL, 2922802573UL, 1417921660UL, 291400676UL, 2664982078UL, 3225369425UL, 3200455006UL, 2207799613UL, 1766261260UL, 2623711877UL, 1927023103UL, 572959294UL, 3447057855UL, 4042691162UL, 3510199782UL, 4187195325UL, 3627831667UL, 1671506539UL, 242673485UL, 1978730938UL, 776552069UL, 684550924UL, 261597601UL, 1857936262UL, 3273582958UL, +4209077103UL, 14248159UL, 2366156245UL, 1910356465UL, 457933823UL, 873419743UL, 4290775093UL, 3670978210UL, 1726974037UL, 1414288023UL, 3574834402UL, 357805142UL, 3820795621UL, 1854247318UL, 2679386897UL, 3977404318UL, 2054677775UL, 1737374322UL, 2852015019UL, 2411291453UL, 1392810771UL, 3742661504UL, 1900815804UL, 1965911170UL, 3719529323UL, 2106191537UL, 3606954134UL, 2108636204UL, 2981827052UL, 3702357099UL, 184003599UL, 3319252632UL, +1370913077UL, 940955681UL, 4262675711UL, 3683661822UL, 3215832318UL, 3463899341UL, 134577035UL, 3494669542UL, 2262494389UL, 88039196UL, 114405083UL, 1071449574UL, 1060831201UL, 765981248UL, 758357266UL, 2564125377UL, 901977407UL, 3003279383UL, 3900980822UL, 134031448UL, 2566915950UL, 3445833537UL, 2846863035UL, 2113076217UL, 713587277UL, 3396078039UL, 3987657193UL, 2067196130UL, 800324742UL, 652529813UL, 3999083342UL, 486108562UL, +2321935002UL, 104743736UL, 2647200400UL, 1592194261UL, 1289872755UL, 466892855UL, 552781204UL, 1101851783UL, 3373292799UL, 2148994262UL, 3078568050UL, 1222851809UL, 2731839331UL, 1280366172UL, 1146205735UL, 1710937426UL, 942360591UL, 3885758458UL, 2062812458UL, 2448488486UL, 3418446265UL, 1909229999UL, 2677929258UL, 3606729729UL, 2920965773UL, 1103324742UL, 2995805883UL, 298794036UL, 957896625UL, 2606719899UL, 675602173UL, 2447513005UL, +2531109351UL, 1920936462UL, 2848868175UL, 1509959171UL, 2751142611UL, 1376226240UL, 3667482110UL, 2551426756UL, 2447143807UL, 3724189478UL, 4217864690UL, 47671552UL, 2993859190UL, 2821422976UL, 2144136371UL, 1655126430UL, 3453916724UL, 2157890969UL, 3665277070UL, 2959496542UL, 2560819344UL, 52639671UL, 39618615UL, 2817859210UL, 2367743540UL, 2964928555UL, 4226359627UL, 4141969666UL, 2856219617UL, 2006751422UL, 2994063945UL, 3146629795UL, +2992956289UL, 3176479073UL, 1529794973UL, 1156556441UL, 3690317172UL, 906928962UL, 97899274UL, 2005599428UL, 4134172918UL, 2922802573UL, 1417921660UL, 1492426675UL, 2664982078UL, 3225369425UL, 3200455006UL, 2207799613UL, 2275640124UL, 2623711877UL, 1927023103UL, 572959294UL, 3447057855UL, 1036984002UL, 3510199782UL, 4187195325UL, 3627831667UL, 1671506539UL, 1827895694UL, 1978730938UL, 776552069UL, 684550924UL, 261597601UL, 3493571621UL, +3273582958UL, 4209077103UL, 14248159UL, 2366156245UL, 211745521UL, 457933823UL, 873419743UL, 4290775093UL, 3670978210UL, 1909994881UL, 1414288023UL, 3574834402UL, 357805142UL, 3820795621UL, 1911700755UL, 2679386897UL, 3977404318UL, 2054677775UL, 1737374322UL, 213019511UL, 2411291453UL, 1392810771UL, 3742661504UL, 1900815804UL, 237536256UL, 3719529323UL, 2106191537UL, 3606954134UL, 2108636204UL, 665423205UL, 3702357099UL, 184003599UL, +3319252632UL, 1370913077UL, 3583034472UL, 4262675711UL, 3683661822UL, 3215832318UL, 3463899341UL, 4027471772UL, 3494669542UL, 2262494389UL, 88039196UL, 114405083UL, 3580272354UL, 1060831201UL, 765981248UL, 758357266UL, 2564125377UL, 2592170747UL, 3003279383UL, 3900980822UL, 134031448UL, 2566915950UL, 1722483656UL, 2846863035UL, 2113076217UL, 713587277UL, 3396078039UL, 244197359UL, 2067196130UL, 800324742UL, 652529813UL, 3999083342UL, +2310369213UL, 2321935002UL, 104743736UL, 2647200400UL, 1592194261UL, 1610483859UL, 466892855UL, 552781204UL, 1101851783UL, 3373292799UL, 2617595614UL, 3078568050UL, 1222851809UL, 2731839331UL, 1280366172UL, 808483717UL, 1710937426UL, 942360591UL, 3885758458UL, 2062812458UL, 3260452154UL, 3418446265UL, 1909229999UL, 2677929258UL, 3606729729UL, 341113837UL, 1103324742UL, 2995805883UL, 298794036UL, 957896625UL, 2309730124UL, 675602173UL, +2447513005UL, 2531109351UL, 1920936462UL, 2268824429UL, 1509959171UL, 2751142611UL, 1376226240UL, 3667482110UL, 2745634237UL, 2447143807UL, 3724189478UL, 4217864690UL, 47671552UL, 2787057737UL, 2821422976UL, 2144136371UL, 1655126430UL, 3453916724UL, 339095616UL, 3665277070UL, 2959496542UL, 2560819344UL, 52639671UL, 3200765881UL, 2817859210UL, 2367743540UL, 2964928555UL, 4226359627UL, 3206913703UL, 2856219617UL, 2006751422UL, 2994063945UL, +3146629795UL, 1042016834UL, 3176479073UL, 1529794973UL, 1156556441UL, 3690317172UL, 171871257UL, 97899274UL, 2005599428UL, 4134172918UL, 2922802573UL, 1501051393UL, 1492426675UL, 2664982078UL, 3225369425UL, 3200455006UL, 1356823782UL, 2275640124UL, 2623711877UL, 1927023103UL, 572959294UL, 319456586UL, 1036984002UL, 3510199782UL, 4187195325UL, 3627831667UL, 3026392291UL, 1827895694UL, 1978730938UL, 776552069UL, 684550924UL, 2862336749UL, +3493571621UL, 3273582958UL, 4209077103UL, 14248159UL, 1597498830UL, 211745521UL, 457933823UL, 873419743UL, 4290775093UL, 2990300609UL, 1909994881UL, 1414288023UL, 3574834402UL, 357805142UL, 1957211849UL, 1911700755UL, 2679386897UL, 3977404318UL, 2054677775UL, 1006075205UL, 213019511UL, 2411291453UL, 1392810771UL, 3742661504UL, 1443139437UL, 237536256UL, 3719529323UL, 2106191537UL, 3606954134UL, 2671394121UL, 665423205UL, 3702357099UL, +184003599UL, 3319252632UL, 1632983188UL, 3583034472UL, 4262675711UL, 3683661822UL, 3215832318UL, 4080585934UL, 4027471772UL, 3494669542UL, 2262494389UL, 88039196UL, 677218369UL, 3580272354UL, 1060831201UL, 765981248UL, 758357266UL, 1277026792UL, 2592170747UL, 3003279383UL, 3900980822UL, 134031448UL, 4189207981UL, 1722483656UL, 2846863035UL, 2113076217UL, 713587277UL, 2098603934UL, 244197359UL, 2067196130UL, 800324742UL, 652529813UL, +1307843279UL, 3205610699UL, 1606722715UL, 2749781905UL, 3500078806UL, 320007706UL, 4092615096UL, 608085660UL, 1869480444UL, 459160631UL, 3657609957UL, 1944540526UL, 2184854884UL, 3497113751UL, 2817682182UL, 3367276652UL, 2069300794UL, 1466691974UL, 3078806052UL, 3998756116UL, 2068892089UL, 1789981386UL, 4196184114UL, 4004623319UL, 3029515569UL, 3206332209UL, 3424306963UL, 1805804276UL, 899469644UL, 1149853995UL, 903917909UL, 1185042552UL, +447265042UL, 3579272434UL, 116409560UL, 2211704275UL, 1237721838UL, 3636618157UL, 3191931082UL, 2430339315UL, 3551966793UL, 1533877057UL, 1700891210UL, 3317627852UL, 828148584UL, 1733460943UL, 3866870689UL, 3970886915UL, 1624935507UL, 3236099078UL, 4209593953UL, 1951283095UL, 1579020365UL, 1165668813UL, 1423097998UL, 1294879824UL, 3406063424UL, 3313007028UL, 2090501113UL, 842064167UL, 729587893UL, 2949702260UL, 2099637920UL, 260436310UL, +1056109549UL, 657874983UL, 2734575906UL, 4088958435UL, 3265216971UL, 1081848592UL, 2593212854UL, 4028921684UL, 2868974814UL, 2299228627UL, 49944924UL, 955114665UL, 2844328062UL, 885136505UL, 4262681333UL, 977883895UL, 998890598UL, 2026602293UL, 87852872UL, 2197997810UL, 910583259UL, 3151223623UL, 3960726944UL, 1778982325UL, 3322631234UL, 2940402694UL, 1619768059UL, 1592832128UL, 1434542537UL, 2107314297UL, 1170789408UL, 3357335254UL, +3317662644UL, 1409884338UL, 73741139UL, 1093507243UL, 329113525UL, 4199840577UL, 442295615UL, 3348669654UL, 435948047UL, 1154137005UL, 3151357655UL, 2101029905UL, 2430218233UL, 2474305449UL, 2316834456UL, 1736616135UL, 1575712778UL, 370866908UL, 4256943043UL, 2805503887UL, 1099763491UL, 2473785999UL, 3215573143UL, 472701386UL, 3070116154UL, 3969279119UL, 3331310102UL, 3932945670UL, 1502564397UL, 1294139579UL, 3073834823UL, 3115143551UL, +3602082994UL, 3707103500UL, 2570195094UL, 1268510174UL, 3561337287UL, 112422529UL, 1483304061UL, 3712148969UL, 3729628891UL, 2741131557UL, 4035019342UL, 2395091348UL, 208448216UL, 607199897UL, 4049058939UL, 3463267226UL, 3821711834UL, 1697628853UL, 691151709UL, 3014869414UL, 11610545UL, 3895793639UL, 3019679196UL, 1246664817UL, 753245113UL, 2236232962UL, 4172861179UL, 4030183420UL, 2367787106UL, 2209331085UL, 4170801007UL, 3609895913UL, +}, +{ +930278208UL, 223382535UL, 720499309UL, 2613473585UL, 4173439516UL, 2132019243UL, 468054579UL, 1141433627UL, 1328639101UL, 3222455434UL, 4023859457UL, 892124224UL, 2940688706UL, 2894552260UL, 1595432126UL, 2558709596UL, 2057191226UL, 1116728192UL, 3767370344UL, 1457278707UL, 3171850455UL, 3733161247UL, 149922078UL, 3860652874UL, 743952057UL, 1024625539UL, 3982786483UL, 2077838781UL, 3713742913UL, 2790452624UL, 3014482913UL, 2928857967UL, +476371337UL, 611803300UL, 3000092437UL, 57069608UL, 1554852195UL, 1406780525UL, 2288998898UL, 460131340UL, 3945168588UL, 18495216UL, 547882902UL, 1624966119UL, 2229423551UL, 1492565146UL, 706052879UL, 2733955743UL, 1450476708UL, 2565285196UL, 2491601298UL, 850297175UL, 331472128UL, 3275065709UL, 3154247398UL, 1364512871UL, 1193063601UL, 579449294UL, 4097747196UL, 3572372000UL, 2712499116UL, 1172861307UL, 3964137156UL, 1300564854UL, +1057993198UL, 2785733262UL, 3548277076UL, 2572944411UL, 3299232577UL, 2031854568UL, 2468534978UL, 602097973UL, 2068619195UL, 2639336890UL, 1694467033UL, 1581263823UL, 809076686UL, 2892861850UL, 4042078087UL, 3178152001UL, 706023882UL, 3236709493UL, 3603158102UL, 2575690800UL, 2831218686UL, 2492604085UL, 207296828UL, 1561595438UL, 2961967115UL, 3304283504UL, 835276604UL, 3005485731UL, 58946395UL, 3979071161UL, 1560535337UL, 2679058432UL, +1061627241UL, 1142692919UL, 1476802977UL, 1306619165UL, 1297953898UL, 4282928317UL, 3630719944UL, 2305895643UL, 2656730970UL, 916308118UL, 4160016206UL, 3541795573UL, 4222235077UL, 1289754532UL, 1963633184UL, 3595798857UL, 2273299603UL, 1687478595UL, 2249344966UL, 2267127964UL, 2201115693UL, 917609614UL, 3731921025UL, 1634893875UL, 3039440017UL, 1122674005UL, 2906728840UL, 921166852UL, 3525309936UL, 633872502UL, 821930665UL, 3861074060UL, +3309559821UL, 304858441UL, 1530517912UL, 1140212033UL, 3168869568UL, 3223449972UL, 1343718360UL, 2831361172UL, 1723616626UL, 3675867172UL, 2586694335UL, 2374941766UL, 387033391UL, 1528180036UL, 1561421035UL, 2735360720UL, 3952587140UL, 13543969UL, 3987997725UL, 4273177532UL, 2200558169UL, 461920718UL, 459441276UL, 4225054447UL, 2248193798UL, 1103878063UL, 3027778665UL, 1844457031UL, 1364117386UL, 1575430424UL, 2276483962UL, 2665252582UL, +1572038262UL, 930278208UL, 223382535UL, 720499309UL, 2613473585UL, 4025056228UL, 2132019243UL, 468054579UL, 1141433627UL, 1328639101UL, 304940359UL, 4023859457UL, 892124224UL, 2940688706UL, 2894552260UL, 2006939659UL, 2558709596UL, 2057191226UL, 1116728192UL, 3767370344UL, 3026555841UL, 3171850455UL, 3733161247UL, 149922078UL, 3860652874UL, 2068299929UL, 1024625539UL, 3982786483UL, 2077838781UL, 3713742913UL, 2512419366UL, 3014482913UL, +2928857967UL, 476371337UL, 611803300UL, 259065762UL, 57069608UL, 1554852195UL, 1406780525UL, 2288998898UL, 2261401631UL, 3945168588UL, 18495216UL, 547882902UL, 1624966119UL, 3049748661UL, 1492565146UL, 706052879UL, 2733955743UL, 1450476708UL, 910808481UL, 2491601298UL, 850297175UL, 331472128UL, 3275065709UL, 3877736250UL, 1364512871UL, 1193063601UL, 579449294UL, 4097747196UL, 3029512053UL, 2712499116UL, 1172861307UL, 3964137156UL, +1300564854UL, 2398462790UL, 2785733262UL, 3548277076UL, 2572944411UL, 3299232577UL, 3497485227UL, 2468534978UL, 602097973UL, 2068619195UL, 2639336890UL, 4271191874UL, 1581263823UL, 809076686UL, 2892861850UL, 4042078087UL, 3046259144UL, 706023882UL, 3236709493UL, 3603158102UL, 2575690800UL, 591682100UL, 2492604085UL, 207296828UL, 1561595438UL, 2961967115UL, 3885379584UL, 835276604UL, 3005485731UL, 58946395UL, 3979071161UL, 2784795951UL, +2679058432UL, 1061627241UL, 1142692919UL, 1476802977UL, 2864266022UL, 1297953898UL, 4282928317UL, 3630719944UL, 2305895643UL, 3374260620UL, 916308118UL, 4160016206UL, 3541795573UL, 4222235077UL, 3025355241UL, 1963633184UL, 3595798857UL, 2273299603UL, 1687478595UL, 4115795122UL, 2267127964UL, 2201115693UL, 917609614UL, 3731921025UL, 2905712346UL, 3039440017UL, 1122674005UL, 2906728840UL, 921166852UL, 2881663141UL, 633872502UL, 821930665UL, +3861074060UL, 3309559821UL, 2816533968UL, 1530517912UL, 1140212033UL, 3168869568UL, 3223449972UL, 1894667948UL, 2831361172UL, 1723616626UL, 3675867172UL, 2586694335UL, 3974041178UL, 387033391UL, 1528180036UL, 1561421035UL, 2735360720UL, 2014321457UL, 13543969UL, 3987997725UL, 4273177532UL, 2200558169UL, 2259553303UL, 459441276UL, 4225054447UL, 2248193798UL, 1103878063UL, 3889361594UL, 1844457031UL, 1364117386UL, 1575430424UL, 2276483962UL, +3302182736UL, 1572038262UL, 930278208UL, 223382535UL, 720499309UL, 4173186621UL, 4025056228UL, 2132019243UL, 468054579UL, 1141433627UL, 2396654717UL, 304940359UL, 4023859457UL, 892124224UL, 2940688706UL, 2903529759UL, 2006939659UL, 2558709596UL, 2057191226UL, 1116728192UL, 715931354UL, 3026555841UL, 3171850455UL, 3733161247UL, 149922078UL, 3342675578UL, 2068299929UL, 1024625539UL, 3982786483UL, 2077838781UL, 1157097180UL, 2512419366UL, +3014482913UL, 2928857967UL, 476371337UL, 2192872017UL, 259065762UL, 57069608UL, 1554852195UL, 1406780525UL, 4165039782UL, 2261401631UL, 3945168588UL, 18495216UL, 547882902UL, 2453072030UL, 3049748661UL, 1492565146UL, 706052879UL, 2733955743UL, 2233423433UL, 910808481UL, 2491601298UL, 850297175UL, 331472128UL, 1154483111UL, 3877736250UL, 1364512871UL, 1193063601UL, 579449294UL, 690173400UL, 3029512053UL, 2712499116UL, 1172861307UL, +3964137156UL, 2683130322UL, 2398462790UL, 2785733262UL, 3548277076UL, 2572944411UL, 4075824857UL, 3497485227UL, 2468534978UL, 602097973UL, 2068619195UL, 2711665545UL, 4271191874UL, 1581263823UL, 809076686UL, 2892861850UL, 3558962856UL, 3046259144UL, 706023882UL, 3236709493UL, 3603158102UL, 274706518UL, 591682100UL, 2492604085UL, 207296828UL, 1561595438UL, 1532885415UL, 3885379584UL, 835276604UL, 3005485731UL, 58946395UL, 4143205928UL, +2784795951UL, 2679058432UL, 1061627241UL, 1142692919UL, 2539503297UL, 2864266022UL, 1297953898UL, 4282928317UL, 3630719944UL, 3333189589UL, 3374260620UL, 916308118UL, 4160016206UL, 3541795573UL, 1771535488UL, 3025355241UL, 1963633184UL, 3595798857UL, 2273299603UL, 1735171204UL, 4115795122UL, 2267127964UL, 2201115693UL, 917609614UL, 4220503034UL, 2905712346UL, 3039440017UL, 1122674005UL, 2906728840UL, 868453017UL, 2881663141UL, 633872502UL, +821930665UL, 3861074060UL, 1928586970UL, 2816533968UL, 1530517912UL, 1140212033UL, 3168869568UL, 1082127627UL, 1894667948UL, 2831361172UL, 1723616626UL, 3675867172UL, 496773835UL, 3974041178UL, 387033391UL, 1528180036UL, 1561421035UL, 2763161987UL, 2014321457UL, 13543969UL, 3987997725UL, 4273177532UL, 2110570579UL, 2259553303UL, 459441276UL, 4225054447UL, 2248193798UL, 53021618UL, 3889361594UL, 1844457031UL, 1364117386UL, 1575430424UL, +1105247032UL, 3302182736UL, 1572038262UL, 930278208UL, 223382535UL, 2159964170UL, 4173186621UL, 4025056228UL, 2132019243UL, 468054579UL, 1397544344UL, 2396654717UL, 304940359UL, 4023859457UL, 892124224UL, 2800429255UL, 2903529759UL, 2006939659UL, 2558709596UL, 2057191226UL, 296054924UL, 715931354UL, 3026555841UL, 3171850455UL, 3733161247UL, 863280930UL, 3342675578UL, 2068299929UL, 1024625539UL, 3982786483UL, 949122664UL, 1157097180UL, +2512419366UL, 3014482913UL, 2928857967UL, 2585465463UL, 2192872017UL, 259065762UL, 57069608UL, 1554852195UL, 3650462338UL, 4165039782UL, 2261401631UL, 3945168588UL, 18495216UL, 524715648UL, 2453072030UL, 3049748661UL, 1492565146UL, 706052879UL, 123143857UL, 2233423433UL, 910808481UL, 2491601298UL, 850297175UL, 3272095697UL, 1154483111UL, 3877736250UL, 1364512871UL, 1193063601UL, 2394240337UL, 690173400UL, 3029512053UL, 2712499116UL, +1172861307UL, 598335483UL, 2683130322UL, 2398462790UL, 2785733262UL, 3548277076UL, 678275336UL, 4075824857UL, 3497485227UL, 2468534978UL, 602097973UL, 1861912463UL, 2711665545UL, 4271191874UL, 1581263823UL, 809076686UL, 3324887617UL, 3558962856UL, 3046259144UL, 706023882UL, 3236709493UL, 1776103512UL, 274706518UL, 591682100UL, 2492604085UL, 207296828UL, 1739697610UL, 1532885415UL, 3885379584UL, 835276604UL, 3005485731UL, 2931144546UL, +4143205928UL, 2784795951UL, 2679058432UL, 1061627241UL, 1487949699UL, 2539503297UL, 2864266022UL, 1297953898UL, 4282928317UL, 4101955339UL, 3333189589UL, 3374260620UL, 916308118UL, 4160016206UL, 376029432UL, 1771535488UL, 3025355241UL, 1963633184UL, 3595798857UL, 2826786027UL, 1735171204UL, 4115795122UL, 2267127964UL, 2201115693UL, 2572535497UL, 4220503034UL, 2905712346UL, 3039440017UL, 1122674005UL, 2482828099UL, 868453017UL, 2881663141UL, +633872502UL, 821930665UL, 2579406681UL, 1928586970UL, 2816533968UL, 1530517912UL, 1140212033UL, 2547368381UL, 1082127627UL, 1894667948UL, 2831361172UL, 1723616626UL, 1903980411UL, 496773835UL, 3974041178UL, 387033391UL, 1528180036UL, 2681142643UL, 2763161987UL, 2014321457UL, 13543969UL, 3987997725UL, 2583502227UL, 2110570579UL, 2259553303UL, 459441276UL, 4225054447UL, 177868402UL, 53021618UL, 3889361594UL, 1844457031UL, 1364117386UL, +2369166739UL, 240269378UL, 689700242UL, 297384154UL, 1052178701UL, 2154172820UL, 614713903UL, 3000863907UL, 3916962502UL, 94341217UL, 2609111975UL, 1621831476UL, 4260159710UL, 694869580UL, 1708268072UL, 2751452128UL, 3843916827UL, 3400387883UL, 2394104046UL, 2348934617UL, 3263438569UL, 3818556032UL, 1695621950UL, 410888855UL, 347231182UL, 612084657UL, 1858306225UL, 3024940417UL, 2482215564UL, 2728249904UL, 2825132299UL, 329106327UL, +3333110741UL, 2742025573UL, 2947035922UL, 3758718780UL, 2191527983UL, 864130510UL, 2586839659UL, 662702978UL, 817620197UL, 2888275812UL, 3372817000UL, 2982240654UL, 2211025418UL, 2043458594UL, 498221898UL, 1559803796UL, 209509183UL, 3004637012UL, 2204871924UL, 2445352606UL, 4026842262UL, 3211433366UL, 3533095828UL, 4172447076UL, 865408944UL, 2797639687UL, 3201749441UL, 1286664278UL, 1158271235UL, 2641361834UL, 4261559289UL, 3643706696UL, +2017210420UL, 2067296744UL, 3548126272UL, 3846378526UL, 3885857009UL, 3013926193UL, 368948443UL, 3839554625UL, 2032663713UL, 4185819024UL, 4279332940UL, 137321733UL, 3515190288UL, 4281845500UL, 2738024944UL, 3350239126UL, 1456676856UL, 1246688651UL, 2478709188UL, 12570320UL, 989306366UL, 2347610707UL, 2849134988UL, 2351681449UL, 4063448910UL, 1193872626UL, 3645565330UL, 1863134777UL, 1345198234UL, 2504863006UL, 3815974850UL, 3075495578UL, +2400383333UL, 2727346254UL, 985812393UL, 1432182882UL, 3668977714UL, 231840487UL, 647229148UL, 274547428UL, 2856186783UL, 1273158535UL, 900081267UL, 1566366419UL, 562584841UL, 2247144789UL, 3522587233UL, 1686032132UL, 586483076UL, 1207387616UL, 3040778905UL, 2532774045UL, 3681992451UL, 1034866888UL, 4029685195UL, 3307070989UL, 2412903766UL, 3156200186UL, 2625083166UL, 4148004113UL, 1756566287UL, 2319065855UL, 2924909429UL, 3050022486UL, +2464491722UL, 1137782196UL, 2749457821UL, 790410752UL, 3511746957UL, 2277733721UL, 2871407058UL, 3858561909UL, 2176119631UL, 952943025UL, 2987154266UL, 120799539UL, 2862346597UL, 3689389598UL, 3329995989UL, 715438735UL, 1035277216UL, 3079684809UL, 677298106UL, 2364292665UL, 4110165256UL, 4096954153UL, 356732100UL, 2361282903UL, 4050817284UL, 2010946835UL, 1824397679UL, 4087204231UL, 4178036725UL, 4197370951UL, 503070461UL, 1879838906UL, +}, +{ +4117851084UL, 2941903397UL, 1156439261UL, 1922510465UL, 2925632294UL, 2272105738UL, 641404242UL, 3414739418UL, 2602896978UL, 672876430UL, 1998875331UL, 1325970749UL, 1633717408UL, 3567722815UL, 2088144733UL, 95705225UL, 580635702UL, 3543633503UL, 1469889369UL, 239816045UL, 2254984383UL, 1632695776UL, 2033839470UL, 4117902893UL, 509938588UL, 1291002316UL, 3600816069UL, 2962644092UL, 4269959520UL, 3161890066UL, 1908855486UL, 1177948589UL, +473118979UL, 3205649854UL, 2027137481UL, 227656706UL, 1485922673UL, 3380103860UL, 2080286336UL, 2588604114UL, 1727893393UL, 3602757903UL, 3126385963UL, 2101893784UL, 3058515017UL, 833779022UL, 719369683UL, 3768029740UL, 1123855192UL, 2580550821UL, 3694463505UL, 1137588651UL, 1724433728UL, 3847324234UL, 2368689516UL, 1226895255UL, 1126753016UL, 2557024841UL, 3187601018UL, 3790080711UL, 2423256074UL, 2463913828UL, 1753321774UL, 1621519784UL, +3456900204UL, 3550875802UL, 3783120790UL, 2740104077UL, 2010858632UL, 1569277627UL, 1492853575UL, 2182681191UL, 3866043645UL, 2566155095UL, 770150438UL, 2482504045UL, 3916834400UL, 222960658UL, 342285296UL, 3354506276UL, 1371039946UL, 3717269950UL, 3632913684UL, 2557531969UL, 3934379214UL, 1732115898UL, 1598596195UL, 1180866173UL, 3526785234UL, 2740387380UL, 3540138766UL, 338607286UL, 3262593182UL, 2413619772UL, 2248013920UL, 3557851982UL, +2470276596UL, 1549877186UL, 447909575UL, 4010548064UL, 282941857UL, 3418249797UL, 3300699992UL, 1957423733UL, 2615274674UL, 370155667UL, 1109991145UL, 933065597UL, 3947818943UL, 3221736239UL, 402503017UL, 4016454981UL, 3640556350UL, 243947268UL, 1175418215UL, 2752078014UL, 371928981UL, 3354635500UL, 3471578165UL, 2735623932UL, 445067764UL, 2732367763UL, 3225606514UL, 1214718589UL, 2197756425UL, 2134958042UL, 680726116UL, 3098695319UL, +2103463364UL, 4058022972UL, 2428195541UL, 2433504485UL, 4042288512UL, 2383438250UL, 3821638336UL, 2375226348UL, 806148488UL, 197247918UL, 768984129UL, 412771011UL, 4020619856UL, 3030619444UL, 3242554868UL, 282156707UL, 3718880754UL, 2938924979UL, 4189583150UL, 1604586306UL, 1245779881UL, 4006389745UL, 2437150739UL, 1749517801UL, 2903749036UL, 1247308303UL, 2580023735UL, 2457849017UL, 342934950UL, 216040419UL, 3176519601UL, 4151509434UL, +2404801649UL, 4117851084UL, 2941903397UL, 1156439261UL, 1922510465UL, 14864453UL, 2272105738UL, 641404242UL, 3414739418UL, 2602896978UL, 2179417586UL, 1998875331UL, 1325970749UL, 1633717408UL, 3567722815UL, 428880410UL, 95705225UL, 580635702UL, 3543633503UL, 1469889369UL, 3132946201UL, 2254984383UL, 1632695776UL, 2033839470UL, 4117902893UL, 3029657560UL, 1291002316UL, 3600816069UL, 2962644092UL, 4269959520UL, 397442545UL, 1908855486UL, +1177948589UL, 473118979UL, 3205649854UL, 990384909UL, 227656706UL, 1485922673UL, 3380103860UL, 2080286336UL, 3295033100UL, 1727893393UL, 3602757903UL, 3126385963UL, 2101893784UL, 1132286601UL, 833779022UL, 719369683UL, 3768029740UL, 1123855192UL, 283414013UL, 3694463505UL, 1137588651UL, 1724433728UL, 3847324234UL, 1735742473UL, 1226895255UL, 1126753016UL, 2557024841UL, 3187601018UL, 2090644528UL, 2423256074UL, 2463913828UL, 1753321774UL, +1621519784UL, 1037552449UL, 3550875802UL, 3783120790UL, 2740104077UL, 2010858632UL, 3730461081UL, 1492853575UL, 2182681191UL, 3866043645UL, 2566155095UL, 2782805925UL, 2482504045UL, 3916834400UL, 222960658UL, 342285296UL, 2406892654UL, 1371039946UL, 3717269950UL, 3632913684UL, 2557531969UL, 4071148456UL, 1732115898UL, 1598596195UL, 1180866173UL, 3526785234UL, 1110366522UL, 3540138766UL, 338607286UL, 3262593182UL, 2413619772UL, 995824548UL, +3557851982UL, 2470276596UL, 1549877186UL, 447909575UL, 2962194596UL, 282941857UL, 3418249797UL, 3300699992UL, 1957423733UL, 1859612288UL, 370155667UL, 1109991145UL, 933065597UL, 3947818943UL, 3005912276UL, 402503017UL, 4016454981UL, 3640556350UL, 243947268UL, 2884057401UL, 2752078014UL, 371928981UL, 3354635500UL, 3471578165UL, 908942821UL, 445067764UL, 2732367763UL, 3225606514UL, 1214718589UL, 4104754911UL, 2134958042UL, 680726116UL, +3098695319UL, 2103463364UL, 2946640978UL, 2428195541UL, 2433504485UL, 4042288512UL, 2383438250UL, 1252490765UL, 2375226348UL, 806148488UL, 197247918UL, 768984129UL, 2578888115UL, 4020619856UL, 3030619444UL, 3242554868UL, 282156707UL, 3433259466UL, 2938924979UL, 4189583150UL, 1604586306UL, 1245779881UL, 616758943UL, 2437150739UL, 1749517801UL, 2903749036UL, 1247308303UL, 2722580830UL, 2457849017UL, 342934950UL, 216040419UL, 3176519601UL, +545097903UL, 2404801649UL, 4117851084UL, 2941903397UL, 1156439261UL, 1253296096UL, 14864453UL, 2272105738UL, 641404242UL, 3414739418UL, 2989955985UL, 2179417586UL, 1998875331UL, 1325970749UL, 1633717408UL, 1896726594UL, 428880410UL, 95705225UL, 580635702UL, 3543633503UL, 3294258049UL, 3132946201UL, 2254984383UL, 1632695776UL, 2033839470UL, 829668922UL, 3029657560UL, 1291002316UL, 3600816069UL, 2962644092UL, 715635401UL, 397442545UL, +1908855486UL, 1177948589UL, 473118979UL, 443010703UL, 990384909UL, 227656706UL, 1485922673UL, 3380103860UL, 727464961UL, 3295033100UL, 1727893393UL, 3602757903UL, 3126385963UL, 3020775130UL, 1132286601UL, 833779022UL, 719369683UL, 3768029740UL, 2215591597UL, 283414013UL, 3694463505UL, 1137588651UL, 1724433728UL, 2124955521UL, 1735742473UL, 1226895255UL, 1126753016UL, 2557024841UL, 1719121879UL, 2090644528UL, 2423256074UL, 2463913828UL, +1753321774UL, 1283364713UL, 1037552449UL, 3550875802UL, 3783120790UL, 2740104077UL, 3326764615UL, 3730461081UL, 1492853575UL, 2182681191UL, 3866043645UL, 1353658829UL, 2782805925UL, 2482504045UL, 3916834400UL, 222960658UL, 2681616579UL, 2406892654UL, 1371039946UL, 3717269950UL, 3632913684UL, 2373372484UL, 4071148456UL, 1732115898UL, 1598596195UL, 1180866173UL, 3787873944UL, 1110366522UL, 3540138766UL, 338607286UL, 3262593182UL, 1714619779UL, +995824548UL, 3557851982UL, 2470276596UL, 1549877186UL, 2342751414UL, 2962194596UL, 282941857UL, 3418249797UL, 3300699992UL, 2080590834UL, 1859612288UL, 370155667UL, 1109991145UL, 933065597UL, 4126279826UL, 3005912276UL, 402503017UL, 4016454981UL, 3640556350UL, 618040940UL, 2884057401UL, 2752078014UL, 371928981UL, 3354635500UL, 2952377979UL, 908942821UL, 445067764UL, 2732367763UL, 3225606514UL, 935181950UL, 4104754911UL, 2134958042UL, +680726116UL, 3098695319UL, 652514936UL, 2946640978UL, 2428195541UL, 2433504485UL, 4042288512UL, 1834165243UL, 1252490765UL, 2375226348UL, 806148488UL, 197247918UL, 1459523569UL, 2578888115UL, 4020619856UL, 3030619444UL, 3242554868UL, 2222750155UL, 3433259466UL, 2938924979UL, 4189583150UL, 1604586306UL, 400149547UL, 616758943UL, 2437150739UL, 1749517801UL, 2903749036UL, 571531698UL, 2722580830UL, 2457849017UL, 342934950UL, 216040419UL, +3302138698UL, 545097903UL, 2404801649UL, 4117851084UL, 2941903397UL, 2926001994UL, 1253296096UL, 14864453UL, 2272105738UL, 641404242UL, 2446601571UL, 2989955985UL, 2179417586UL, 1998875331UL, 1325970749UL, 2470418771UL, 1896726594UL, 428880410UL, 95705225UL, 580635702UL, 95529058UL, 3294258049UL, 3132946201UL, 2254984383UL, 1632695776UL, 3381575123UL, 829668922UL, 3029657560UL, 1291002316UL, 3600816069UL, 332821128UL, 715635401UL, +397442545UL, 1908855486UL, 1177948589UL, 3324147260UL, 443010703UL, 990384909UL, 227656706UL, 1485922673UL, 3468390490UL, 727464961UL, 3295033100UL, 1727893393UL, 3602757903UL, 3849734062UL, 3020775130UL, 1132286601UL, 833779022UL, 719369683UL, 3336941985UL, 2215591597UL, 283414013UL, 3694463505UL, 1137588651UL, 1245145305UL, 2124955521UL, 1735742473UL, 1226895255UL, 1126753016UL, 1536376839UL, 1719121879UL, 2090644528UL, 2423256074UL, +2463913828UL, 4035794571UL, 1283364713UL, 1037552449UL, 3550875802UL, 3783120790UL, 4233012781UL, 3326764615UL, 3730461081UL, 1492853575UL, 2182681191UL, 654850701UL, 1353658829UL, 2782805925UL, 2482504045UL, 3916834400UL, 1556782509UL, 2681616579UL, 2406892654UL, 1371039946UL, 3717269950UL, 1227526114UL, 2373372484UL, 4071148456UL, 1732115898UL, 1598596195UL, 1777009717UL, 3787873944UL, 1110366522UL, 3540138766UL, 338607286UL, 1161080599UL, +1714619779UL, 995824548UL, 3557851982UL, 2470276596UL, 3162659171UL, 2342751414UL, 2962194596UL, 282941857UL, 3418249797UL, 1032034511UL, 2080590834UL, 1859612288UL, 370155667UL, 1109991145UL, 2568097099UL, 4126279826UL, 3005912276UL, 402503017UL, 4016454981UL, 3196575353UL, 618040940UL, 2884057401UL, 2752078014UL, 371928981UL, 4223799564UL, 2952377979UL, 908942821UL, 445067764UL, 2732367763UL, 174723563UL, 935181950UL, 4104754911UL, +2134958042UL, 680726116UL, 649687363UL, 652514936UL, 2946640978UL, 2428195541UL, 2433504485UL, 3735735592UL, 1834165243UL, 1252490765UL, 2375226348UL, 806148488UL, 3720638976UL, 1459523569UL, 2578888115UL, 4020619856UL, 3030619444UL, 283333114UL, 2222750155UL, 3433259466UL, 2938924979UL, 4189583150UL, 870522428UL, 400149547UL, 616758943UL, 2437150739UL, 1749517801UL, 999295363UL, 571531698UL, 2722580830UL, 2457849017UL, 342934950UL, +3151292467UL, 2839665217UL, 2452261456UL, 208520727UL, 2269948412UL, 344787478UL, 3987474076UL, 3770524881UL, 2718719281UL, 2537804795UL, 850790212UL, 639946566UL, 2073602691UL, 2316769983UL, 3577216077UL, 3538374748UL, 61447995UL, 3718817085UL, 1476398788UL, 3239144530UL, 3595014456UL, 454482110UL, 286330934UL, 2119173159UL, 1693518756UL, 1464218560UL, 1201825197UL, 1112746405UL, 2988579776UL, 1626663767UL, 2236015969UL, 4018896468UL, +1885926862UL, 671386673UL, 1583086162UL, 1114723892UL, 2936863300UL, 2620955107UL, 2628074015UL, 426673611UL, 3370181092UL, 3462245129UL, 3590185736UL, 2630441788UL, 171626554UL, 3647663038UL, 880996914UL, 1155913149UL, 2653278555UL, 508978149UL, 2031872445UL, 3041145171UL, 1339819022UL, 127509725UL, 1336955078UL, 727702092UL, 693349672UL, 999665905UL, 2287631318UL, 961427722UL, 3355851447UL, 821851136UL, 2370998072UL, 4027450519UL, +2054803464UL, 144596514UL, 3295312213UL, 2579322479UL, 2982266864UL, 4275468400UL, 179988815UL, 2123828208UL, 1486957870UL, 2484928010UL, 288096701UL, 1211834301UL, 1819157080UL, 3569000238UL, 4164201803UL, 3042117433UL, 2741571248UL, 3688451311UL, 29376415UL, 437788821UL, 994675658UL, 1014591996UL, 296335443UL, 363551454UL, 2628890394UL, 332401256UL, 2288239762UL, 3766239385UL, 317162173UL, 3721125104UL, 2296650899UL, 56428392UL, +3900411067UL, 2303724992UL, 3735005983UL, 1377320198UL, 612032498UL, 1171213235UL, 2494454628UL, 1894368149UL, 4124860986UL, 1694123597UL, 2306091209UL, 2075278956UL, 3898366152UL, 937522278UL, 32800830UL, 324902076UL, 2365753207UL, 2251160429UL, 1692543836UL, 2920424644UL, 119047416UL, 1821685115UL, 1486296407UL, 3055580738UL, 3711421730UL, 1522703457UL, 1422399573UL, 2515073038UL, 3788816887UL, 3490575947UL, 2395299159UL, 4248373284UL, +3383561277UL, 3128107243UL, 2344292809UL, 1806504793UL, 3087395022UL, 4113720664UL, 2749262038UL, 395148869UL, 1331347439UL, 2682558741UL, 1253966763UL, 4204248490UL, 2083995727UL, 2717069903UL, 4144872894UL, 1857751053UL, 2166276701UL, 1419950839UL, 1145170701UL, 3225260742UL, 211743500UL, 2746391743UL, 3333387219UL, 4115426799UL, 3801457092UL, 3327614811UL, 1460971336UL, 2256342146UL, 3186427137UL, 2684216499UL, 1035644397UL, 2948948308UL, +}, +{ +216975964UL, 4145824263UL, 2147471723UL, 4154469597UL, 161744273UL, 1299764439UL, 3468614543UL, 4190517158UL, 4124232403UL, 754999274UL, 208153182UL, 1442063188UL, 2940825403UL, 729331312UL, 2124186505UL, 1136411459UL, 1083787490UL, 442264548UL, 442338468UL, 464589685UL, 3509461223UL, 4241734851UL, 370778328UL, 4003105058UL, 3163637982UL, 3747133182UL, 1433548371UL, 1876378240UL, 536564977UL, 1171222160UL, 3268902719UL, 2725776746UL, +1547771137UL, 2818791461UL, 4129042013UL, 2677094853UL, 1594765197UL, 1556725424UL, 569252594UL, 2640731848UL, 2947042710UL, 2633188904UL, 1640957370UL, 1806863786UL, 2803403654UL, 2632220187UL, 2740076538UL, 383549855UL, 3211856699UL, 3933793958UL, 1988232112UL, 404006876UL, 1369488120UL, 1963339964UL, 609604643UL, 2488118016UL, 3936354252UL, 1980115609UL, 189069630UL, 860670414UL, 85775513UL, 2447581620UL, 886385122UL, 3047212472UL, +2470718978UL, 4044569663UL, 430717074UL, 1598133481UL, 1905362808UL, 2981511487UL, 1842297666UL, 2992320857UL, 1682119455UL, 1753461544UL, 700013801UL, 3025873251UL, 3413358770UL, 1673092091UL, 113651375UL, 2618875026UL, 1479752146UL, 81598739UL, 1530418117UL, 962911586UL, 778994423UL, 3944331100UL, 4116504755UL, 480712357UL, 1078821437UL, 1091665476UL, 3696871260UL, 2074607518UL, 3226459752UL, 3767432525UL, 768289441UL, 3142741843UL, +2969151790UL, 1814889320UL, 2122849610UL, 451935137UL, 2784993892UL, 1836517944UL, 1565951586UL, 1663606442UL, 1578543925UL, 33407321UL, 1445768530UL, 2156093253UL, 3164165477UL, 3093293932UL, 298945371UL, 2558835427UL, 1386275152UL, 2649603495UL, 893605644UL, 1147537351UL, 1889670166UL, 3203610476UL, 2598985714UL, 966335150UL, 3384227644UL, 2584671737UL, 552770393UL, 2430097209UL, 3085150053UL, 3633667948UL, 1319147485UL, 1999467843UL, +3676133150UL, 2314789604UL, 1443760911UL, 1552954684UL, 2411684219UL, 3708965016UL, 2607719926UL, 484007519UL, 491681421UL, 2498192461UL, 6342020UL, 4226570819UL, 2329860147UL, 1097040622UL, 1270325434UL, 2572535504UL, 918592905UL, 193599782UL, 4223250613UL, 1640082589UL, 1817957216UL, 2937344769UL, 3768793871UL, 2982566292UL, 1607453458UL, 4096207317UL, 696907828UL, 2431936270UL, 627206620UL, 3267100287UL, 1161821973UL, 2322099303UL, +1700245615UL, 216975964UL, 4145824263UL, 2147471723UL, 4154469597UL, 2836499116UL, 1299764439UL, 3468614543UL, 4190517158UL, 4124232403UL, 2176257299UL, 208153182UL, 1442063188UL, 2940825403UL, 729331312UL, 2954254860UL, 1136411459UL, 1083787490UL, 442264548UL, 442338468UL, 3098695824UL, 3509461223UL, 4241734851UL, 370778328UL, 4003105058UL, 2963948505UL, 3747133182UL, 1433548371UL, 1876378240UL, 536564977UL, 1565224991UL, 3268902719UL, +2725776746UL, 1547771137UL, 2818791461UL, 2118790546UL, 2677094853UL, 1594765197UL, 1556725424UL, 569252594UL, 610771792UL, 2947042710UL, 2633188904UL, 1640957370UL, 1806863786UL, 2121022793UL, 2632220187UL, 2740076538UL, 383549855UL, 3211856699UL, 14274926UL, 1988232112UL, 404006876UL, 1369488120UL, 1963339964UL, 1661081792UL, 2488118016UL, 3936354252UL, 1980115609UL, 189069630UL, 595192504UL, 85775513UL, 2447581620UL, 886385122UL, +3047212472UL, 1596069326UL, 4044569663UL, 430717074UL, 1598133481UL, 1905362808UL, 2670961612UL, 1842297666UL, 2992320857UL, 1682119455UL, 1753461544UL, 1121764918UL, 3025873251UL, 3413358770UL, 1673092091UL, 113651375UL, 1721474883UL, 1479752146UL, 81598739UL, 1530418117UL, 962911586UL, 3478535046UL, 3944331100UL, 4116504755UL, 480712357UL, 1078821437UL, 1456786415UL, 3696871260UL, 2074607518UL, 3226459752UL, 3767432525UL, 2947648865UL, +3142741843UL, 2969151790UL, 1814889320UL, 2122849610UL, 3367879697UL, 2784993892UL, 1836517944UL, 1565951586UL, 1663606442UL, 2621366329UL, 33407321UL, 1445768530UL, 2156093253UL, 3164165477UL, 619266142UL, 298945371UL, 2558835427UL, 1386275152UL, 2649603495UL, 97967685UL, 1147537351UL, 1889670166UL, 3203610476UL, 2598985714UL, 504495866UL, 3384227644UL, 2584671737UL, 552770393UL, 2430097209UL, 2168477293UL, 3633667948UL, 1319147485UL, +1999467843UL, 3676133150UL, 2755203144UL, 1443760911UL, 1552954684UL, 2411684219UL, 3708965016UL, 2301846628UL, 484007519UL, 491681421UL, 2498192461UL, 6342020UL, 318325395UL, 2329860147UL, 1097040622UL, 1270325434UL, 2572535504UL, 3458698828UL, 193599782UL, 4223250613UL, 1640082589UL, 1817957216UL, 1861636211UL, 3768793871UL, 2982566292UL, 1607453458UL, 4096207317UL, 1871072589UL, 2431936270UL, 627206620UL, 3267100287UL, 1161821973UL, +3904037207UL, 1700245615UL, 216975964UL, 4145824263UL, 2147471723UL, 2789343849UL, 2836499116UL, 1299764439UL, 3468614543UL, 4190517158UL, 639361502UL, 2176257299UL, 208153182UL, 1442063188UL, 2940825403UL, 2962998954UL, 2954254860UL, 1136411459UL, 1083787490UL, 442264548UL, 1812626669UL, 3098695824UL, 3509461223UL, 4241734851UL, 370778328UL, 1673951193UL, 2963948505UL, 3747133182UL, 1433548371UL, 1876378240UL, 3651623536UL, 1565224991UL, +3268902719UL, 2725776746UL, 1547771137UL, 1938402968UL, 2118790546UL, 2677094853UL, 1594765197UL, 1556725424UL, 3267956202UL, 610771792UL, 2947042710UL, 2633188904UL, 1640957370UL, 1448040688UL, 2121022793UL, 2632220187UL, 2740076538UL, 383549855UL, 300148175UL, 14274926UL, 1988232112UL, 404006876UL, 1369488120UL, 3313508750UL, 1661081792UL, 2488118016UL, 3936354252UL, 1980115609UL, 2631341293UL, 595192504UL, 85775513UL, 2447581620UL, +886385122UL, 2465820467UL, 1596069326UL, 4044569663UL, 430717074UL, 1598133481UL, 4191772516UL, 2670961612UL, 1842297666UL, 2992320857UL, 1682119455UL, 997741285UL, 1121764918UL, 3025873251UL, 3413358770UL, 1673092091UL, 1493832846UL, 1721474883UL, 1479752146UL, 81598739UL, 1530418117UL, 2762019274UL, 3478535046UL, 3944331100UL, 4116504755UL, 480712357UL, 448437372UL, 1456786415UL, 3696871260UL, 2074607518UL, 3226459752UL, 2507199309UL, +2947648865UL, 3142741843UL, 2969151790UL, 1814889320UL, 2268952501UL, 3367879697UL, 2784993892UL, 1836517944UL, 1565951586UL, 377207573UL, 2621366329UL, 33407321UL, 1445768530UL, 2156093253UL, 1325490318UL, 619266142UL, 298945371UL, 2558835427UL, 1386275152UL, 2662699426UL, 97967685UL, 1147537351UL, 1889670166UL, 3203610476UL, 1999783658UL, 504495866UL, 3384227644UL, 2584671737UL, 552770393UL, 1562106652UL, 2168477293UL, 3633667948UL, +1319147485UL, 1999467843UL, 2037219988UL, 2755203144UL, 1443760911UL, 1552954684UL, 2411684219UL, 1579607443UL, 2301846628UL, 484007519UL, 491681421UL, 2498192461UL, 745333677UL, 318325395UL, 2329860147UL, 1097040622UL, 1270325434UL, 208017379UL, 3458698828UL, 193599782UL, 4223250613UL, 1640082589UL, 4049245262UL, 1861636211UL, 3768793871UL, 2982566292UL, 1607453458UL, 2058912455UL, 1871072589UL, 2431936270UL, 627206620UL, 3267100287UL, +1186015034UL, 3904037207UL, 1700245615UL, 216975964UL, 4145824263UL, 2422827462UL, 2789343849UL, 2836499116UL, 1299764439UL, 3468614543UL, 2084839633UL, 639361502UL, 2176257299UL, 208153182UL, 1442063188UL, 4065931048UL, 2962998954UL, 2954254860UL, 1136411459UL, 1083787490UL, 465529524UL, 1812626669UL, 3098695824UL, 3509461223UL, 4241734851UL, 3818602366UL, 1673951193UL, 2963948505UL, 3747133182UL, 1433548371UL, 2475307467UL, 3651623536UL, +1565224991UL, 3268902719UL, 2725776746UL, 2374226870UL, 1938402968UL, 2118790546UL, 2677094853UL, 1594765197UL, 348828658UL, 3267956202UL, 610771792UL, 2947042710UL, 2633188904UL, 1713124265UL, 1448040688UL, 2121022793UL, 2632220187UL, 2740076538UL, 1400362266UL, 300148175UL, 14274926UL, 1988232112UL, 404006876UL, 3662575932UL, 3313508750UL, 1661081792UL, 2488118016UL, 3936354252UL, 3100635752UL, 2631341293UL, 595192504UL, 85775513UL, +2447581620UL, 2417839883UL, 2465820467UL, 1596069326UL, 4044569663UL, 430717074UL, 1093503127UL, 4191772516UL, 2670961612UL, 1842297666UL, 2992320857UL, 3292586028UL, 997741285UL, 1121764918UL, 3025873251UL, 3413358770UL, 222522839UL, 1493832846UL, 1721474883UL, 1479752146UL, 81598739UL, 3132900738UL, 2762019274UL, 3478535046UL, 3944331100UL, 4116504755UL, 3429405501UL, 448437372UL, 1456786415UL, 3696871260UL, 2074607518UL, 1492852861UL, +2507199309UL, 2947648865UL, 3142741843UL, 2969151790UL, 2186889362UL, 2268952501UL, 3367879697UL, 2784993892UL, 1836517944UL, 3169157745UL, 377207573UL, 2621366329UL, 33407321UL, 1445768530UL, 4266168148UL, 1325490318UL, 619266142UL, 298945371UL, 2558835427UL, 1447045944UL, 2662699426UL, 97967685UL, 1147537351UL, 1889670166UL, 3354555370UL, 1999783658UL, 504495866UL, 3384227644UL, 2584671737UL, 2489662408UL, 1562106652UL, 2168477293UL, +3633667948UL, 1319147485UL, 3353555249UL, 2037219988UL, 2755203144UL, 1443760911UL, 1552954684UL, 4137514176UL, 1579607443UL, 2301846628UL, 484007519UL, 491681421UL, 164627749UL, 745333677UL, 318325395UL, 2329860147UL, 1097040622UL, 3587444362UL, 208017379UL, 3458698828UL, 193599782UL, 4223250613UL, 1102471426UL, 4049245262UL, 1861636211UL, 3768793871UL, 2982566292UL, 1941698603UL, 2058912455UL, 1871072589UL, 2431936270UL, 627206620UL, +2511999766UL, 1406946444UL, 1571284360UL, 1416792763UL, 1774410400UL, 1655066897UL, 740531687UL, 2852637013UL, 1574342442UL, 3931672444UL, 2887289502UL, 3588598337UL, 1607795590UL, 1893126336UL, 4113959952UL, 250670029UL, 89330705UL, 2198706475UL, 133060312UL, 4033807246UL, 2161604768UL, 3871950931UL, 1820516188UL, 828316231UL, 3126087794UL, 3740050736UL, 543577819UL, 1589693651UL, 4210480257UL, 3844498352UL, 96010254UL, 2888517657UL, +2931088981UL, 2307454606UL, 2411141663UL, 4193964276UL, 918899600UL, 888509951UL, 3023902229UL, 1371276096UL, 2107726407UL, 3863079906UL, 3849297291UL, 1512401618UL, 3098628219UL, 487705749UL, 492891601UL, 345791371UL, 3230138831UL, 1022138839UL, 974682588UL, 3677932604UL, 2054641860UL, 3303576494UL, 1416653965UL, 1119635666UL, 1907978487UL, 4269977208UL, 2047880336UL, 205698774UL, 2401894999UL, 3253173123UL, 2603439113UL, 1295808319UL, +2965198050UL, 1718424301UL, 1605627562UL, 2860017421UL, 1619060227UL, 1130717786UL, 2992070906UL, 2964091191UL, 3192265220UL, 3860528275UL, 45139953UL, 3914023193UL, 1253834497UL, 3885013544UL, 3793695046UL, 3632364934UL, 4127361980UL, 3323804519UL, 4117285262UL, 4171102020UL, 1863837906UL, 2848174924UL, 1731389076UL, 2514130112UL, 3539384422UL, 2950752200UL, 1138137434UL, 4147328087UL, 3345958235UL, 2305097760UL, 974161669UL, 1739611700UL, +2522036172UL, 1196649816UL, 2395301283UL, 911135539UL, 1029496076UL, 1786766951UL, 1802412425UL, 3485017668UL, 2837835718UL, 1951207514UL, 1447650206UL, 2289702688UL, 2517625074UL, 2408021138UL, 2022522416UL, 719777136UL, 417238676UL, 1865171065UL, 801820378UL, 2836941189UL, 1148226009UL, 1713866138UL, 64608707UL, 1458585813UL, 3581572089UL, 2251042907UL, 1818903516UL, 3278072806UL, 2838874249UL, 2665607605UL, 3360214955UL, 2185961451UL, +410342713UL, 364484774UL, 2887998484UL, 2100888426UL, 1394314931UL, 1362560504UL, 3487221127UL, 3140021092UL, 3168968161UL, 1613267484UL, 290430673UL, 2588210538UL, 2493788232UL, 2641638765UL, 2971195072UL, 2749469779UL, 692014176UL, 3268150742UL, 387451740UL, 461249727UL, 3579417331UL, 3738405845UL, 385445455UL, 1464799053UL, 2786433795UL, 3370371952UL, 675344511UL, 4049011269UL, 2196568686UL, 4166285481UL, 2547135972UL, 119952106UL, +}, +{ +2307933966UL, 145940188UL, 4247815717UL, 2995341855UL, 3245382498UL, 1213200792UL, 232910392UL, 2718014238UL, 918321585UL, 3583102265UL, 3176078796UL, 937696513UL, 266558688UL, 1520650260UL, 3655025189UL, 1653323191UL, 538426778UL, 491545855UL, 4064663509UL, 2788350755UL, 3941259490UL, 3471552693UL, 1851151228UL, 3279627338UL, 845228710UL, 29883500UL, 1503432309UL, 593880175UL, 2488716480UL, 828058076UL, 3287933183UL, 3510981973UL, +3970051135UL, 3803049980UL, 898259836UL, 2890959433UL, 234437380UL, 201835406UL, 1523016285UL, 2419577439UL, 2943482079UL, 4219300984UL, 1490698759UL, 533411805UL, 1644926459UL, 4097374623UL, 265292490UL, 2694560848UL, 285667083UL, 1563945375UL, 3128365011UL, 95277844UL, 2938824634UL, 2717708621UL, 3374928056UL, 3672802273UL, 3445399260UL, 2422205637UL, 1106030557UL, 1269805720UL, 1781057614UL, 3491203689UL, 2454028630UL, 2158698380UL, +2578431870UL, 3540412661UL, 2206372988UL, 3138025266UL, 474100503UL, 3310048546UL, 126856999UL, 3144057206UL, 917199551UL, 3549528813UL, 343855771UL, 391118877UL, 1900257963UL, 1616289477UL, 3663959751UL, 1887891784UL, 697303016UL, 1346369879UL, 3634838543UL, 909311683UL, 3534738830UL, 2676838865UL, 3020679234UL, 1248902118UL, 1517698896UL, 414632197UL, 199589058UL, 2922557451UL, 3915079510UL, 1309075563UL, 3836275459UL, 2549095941UL, +1643088840UL, 1153547003UL, 2254144060UL, 3585420425UL, 915059870UL, 2410951596UL, 1876156254UL, 2384812180UL, 3893647829UL, 4119002503UL, 1535078752UL, 3888310943UL, 1483731374UL, 3915992153UL, 3662664617UL, 1065246672UL, 2307959656UL, 1845927873UL, 2075990232UL, 1346396900UL, 4218283385UL, 3427468026UL, 1518645158UL, 3092538772UL, 3383570452UL, 1317710387UL, 3390054918UL, 4222595168UL, 2468387909UL, 3864538174UL, 2442851586UL, 1858344050UL, +1537617445UL, 1090881039UL, 2055021834UL, 4011332463UL, 2797336692UL, 280272261UL, 3350338577UL, 1682666744UL, 1256176165UL, 2017003515UL, 3666229067UL, 4288064377UL, 3407437449UL, 2957152445UL, 3557139753UL, 4106922773UL, 2612653316UL, 3491950269UL, 1107293753UL, 2926461368UL, 1433860998UL, 1975669351UL, 1680462513UL, 4283282673UL, 168788571UL, 57021447UL, 3888396304UL, 2218068386UL, 2170981202UL, 1587568797UL, 2097820654UL, 1308061343UL, +4096726326UL, 2307933966UL, 145940188UL, 4247815717UL, 2995341855UL, 2894586378UL, 1213200792UL, 232910392UL, 2718014238UL, 918321585UL, 520434726UL, 3176078796UL, 937696513UL, 266558688UL, 1520650260UL, 645408471UL, 1653323191UL, 538426778UL, 491545855UL, 4064663509UL, 2605358672UL, 3941259490UL, 3471552693UL, 1851151228UL, 3279627338UL, 1290188176UL, 29883500UL, 1503432309UL, 593880175UL, 2488716480UL, 1172244224UL, 3287933183UL, +3510981973UL, 3970051135UL, 3803049980UL, 3836242189UL, 2890959433UL, 234437380UL, 201835406UL, 1523016285UL, 1720566850UL, 2943482079UL, 4219300984UL, 1490698759UL, 533411805UL, 982587365UL, 4097374623UL, 265292490UL, 2694560848UL, 285667083UL, 3905392425UL, 3128365011UL, 95277844UL, 2938824634UL, 2717708621UL, 262111126UL, 3672802273UL, 3445399260UL, 2422205637UL, 1106030557UL, 233401560UL, 1781057614UL, 3491203689UL, 2454028630UL, +2158698380UL, 3314008662UL, 3540412661UL, 2206372988UL, 3138025266UL, 474100503UL, 1150191741UL, 126856999UL, 3144057206UL, 917199551UL, 3549528813UL, 84516590UL, 391118877UL, 1900257963UL, 1616289477UL, 3663959751UL, 2831036790UL, 697303016UL, 1346369879UL, 3634838543UL, 909311683UL, 2206291004UL, 2676838865UL, 3020679234UL, 1248902118UL, 1517698896UL, 882506847UL, 199589058UL, 2922557451UL, 3915079510UL, 1309075563UL, 3675129276UL, +2549095941UL, 1643088840UL, 1153547003UL, 2254144060UL, 1702669516UL, 915059870UL, 2410951596UL, 1876156254UL, 2384812180UL, 393602062UL, 4119002503UL, 1535078752UL, 3888310943UL, 1483731374UL, 1135074988UL, 3662664617UL, 1065246672UL, 2307959656UL, 1845927873UL, 883002610UL, 1346396900UL, 4218283385UL, 3427468026UL, 1518645158UL, 1478839081UL, 3383570452UL, 1317710387UL, 3390054918UL, 4222595168UL, 3009846855UL, 3864538174UL, 2442851586UL, +1858344050UL, 1537617445UL, 2419526192UL, 2055021834UL, 4011332463UL, 2797336692UL, 280272261UL, 2937342669UL, 1682666744UL, 1256176165UL, 2017003515UL, 3666229067UL, 3563024742UL, 3407437449UL, 2957152445UL, 3557139753UL, 4106922773UL, 610182860UL, 3491950269UL, 1107293753UL, 2926461368UL, 1433860998UL, 2493047579UL, 1680462513UL, 4283282673UL, 168788571UL, 57021447UL, 2151356582UL, 2218068386UL, 2170981202UL, 1587568797UL, 2097820654UL, +2738927570UL, 4096726326UL, 2307933966UL, 145940188UL, 4247815717UL, 1887236689UL, 2894586378UL, 1213200792UL, 232910392UL, 2718014238UL, 2028538736UL, 520434726UL, 3176078796UL, 937696513UL, 266558688UL, 305624632UL, 645408471UL, 1653323191UL, 538426778UL, 491545855UL, 4188864445UL, 2605358672UL, 3941259490UL, 3471552693UL, 1851151228UL, 1720039364UL, 1290188176UL, 29883500UL, 1503432309UL, 593880175UL, 2595662526UL, 1172244224UL, +3287933183UL, 3510981973UL, 3970051135UL, 2763703998UL, 3836242189UL, 2890959433UL, 234437380UL, 201835406UL, 2652280530UL, 1720566850UL, 2943482079UL, 4219300984UL, 1490698759UL, 1968049758UL, 982587365UL, 4097374623UL, 265292490UL, 2694560848UL, 1165326939UL, 3905392425UL, 3128365011UL, 95277844UL, 2938824634UL, 2521869983UL, 262111126UL, 3672802273UL, 3445399260UL, 2422205637UL, 395183943UL, 233401560UL, 1781057614UL, 3491203689UL, +2454028630UL, 249721174UL, 3314008662UL, 3540412661UL, 2206372988UL, 3138025266UL, 1644439373UL, 1150191741UL, 126856999UL, 3144057206UL, 917199551UL, 1997133400UL, 84516590UL, 391118877UL, 1900257963UL, 1616289477UL, 3843764922UL, 2831036790UL, 697303016UL, 1346369879UL, 3634838543UL, 1901125181UL, 2206291004UL, 2676838865UL, 3020679234UL, 1248902118UL, 344347894UL, 882506847UL, 199589058UL, 2922557451UL, 3915079510UL, 2919277604UL, +3675129276UL, 2549095941UL, 1643088840UL, 1153547003UL, 3305575634UL, 1702669516UL, 915059870UL, 2410951596UL, 1876156254UL, 1416053196UL, 393602062UL, 4119002503UL, 1535078752UL, 3888310943UL, 3993632377UL, 1135074988UL, 3662664617UL, 1065246672UL, 2307959656UL, 1044670394UL, 883002610UL, 1346396900UL, 4218283385UL, 3427468026UL, 1792832168UL, 1478839081UL, 3383570452UL, 1317710387UL, 3390054918UL, 1596709924UL, 3009846855UL, 3864538174UL, +2442851586UL, 1858344050UL, 2428482265UL, 2419526192UL, 2055021834UL, 4011332463UL, 2797336692UL, 424213503UL, 2937342669UL, 1682666744UL, 1256176165UL, 2017003515UL, 717473071UL, 3563024742UL, 3407437449UL, 2957152445UL, 3557139753UL, 3319575432UL, 610182860UL, 3491950269UL, 1107293753UL, 2926461368UL, 3052637648UL, 2493047579UL, 1680462513UL, 4283282673UL, 168788571UL, 1401253163UL, 2151356582UL, 2218068386UL, 2170981202UL, 1587568797UL, +3994937670UL, 2738927570UL, 4096726326UL, 2307933966UL, 145940188UL, 3928146647UL, 1887236689UL, 2894586378UL, 1213200792UL, 232910392UL, 833120806UL, 2028538736UL, 520434726UL, 3176078796UL, 937696513UL, 3704968451UL, 305624632UL, 645408471UL, 1653323191UL, 538426778UL, 939335571UL, 4188864445UL, 2605358672UL, 3941259490UL, 3471552693UL, 2168499975UL, 1720039364UL, 1290188176UL, 29883500UL, 1503432309UL, 524387655UL, 2595662526UL, +1172244224UL, 3287933183UL, 3510981973UL, 2444664749UL, 2763703998UL, 3836242189UL, 2890959433UL, 234437380UL, 3272987579UL, 2652280530UL, 1720566850UL, 2943482079UL, 4219300984UL, 1045589319UL, 1968049758UL, 982587365UL, 4097374623UL, 265292490UL, 1077412791UL, 1165326939UL, 3905392425UL, 3128365011UL, 95277844UL, 2896038035UL, 2521869983UL, 262111126UL, 3672802273UL, 3445399260UL, 4273256145UL, 395183943UL, 233401560UL, 1781057614UL, +3491203689UL, 8343453UL, 249721174UL, 3314008662UL, 3540412661UL, 2206372988UL, 3738630867UL, 1644439373UL, 1150191741UL, 126856999UL, 3144057206UL, 65169501UL, 1997133400UL, 84516590UL, 391118877UL, 1900257963UL, 2914085557UL, 3843764922UL, 2831036790UL, 697303016UL, 1346369879UL, 2007568079UL, 1901125181UL, 2206291004UL, 2676838865UL, 3020679234UL, 2097032931UL, 344347894UL, 882506847UL, 199589058UL, 2922557451UL, 3740400148UL, +2919277604UL, 3675129276UL, 2549095941UL, 1643088840UL, 199560818UL, 3305575634UL, 1702669516UL, 915059870UL, 2410951596UL, 117939268UL, 1416053196UL, 393602062UL, 4119002503UL, 1535078752UL, 4281599711UL, 3993632377UL, 1135074988UL, 3662664617UL, 1065246672UL, 2854253374UL, 1044670394UL, 883002610UL, 1346396900UL, 4218283385UL, 803910659UL, 1792832168UL, 1478839081UL, 3383570452UL, 1317710387UL, 1311168874UL, 1596709924UL, 3009846855UL, +3864538174UL, 2442851586UL, 1967982878UL, 2428482265UL, 2419526192UL, 2055021834UL, 4011332463UL, 2725198749UL, 424213503UL, 2937342669UL, 1682666744UL, 1256176165UL, 713350501UL, 717473071UL, 3563024742UL, 3407437449UL, 2957152445UL, 2363682828UL, 3319575432UL, 610182860UL, 3491950269UL, 1107293753UL, 3429638328UL, 3052637648UL, 2493047579UL, 1680462513UL, 4283282673UL, 2672311163UL, 1401253163UL, 2151356582UL, 2218068386UL, 2170981202UL, +431601500UL, 4193143261UL, 2985267149UL, 1556712183UL, 4135181832UL, 285960576UL, 81711096UL, 57066962UL, 2646151573UL, 3692824605UL, 485132216UL, 2799654118UL, 903527523UL, 1210637484UL, 3195346614UL, 599540837UL, 1410108963UL, 3723542120UL, 1350764011UL, 1717225239UL, 239736775UL, 3946934722UL, 420024332UL, 589304817UL, 1331122625UL, 4294403247UL, 2009397371UL, 844641869UL, 166387728UL, 4093361096UL, 2342369656UL, 3958170613UL, +1660376297UL, 1259528150UL, 4240809115UL, 2875563845UL, 2613790323UL, 2869665108UL, 1414690635UL, 944649070UL, 3539368342UL, 199532147UL, 2707660205UL, 2258475730UL, 771169023UL, 158544851UL, 588872178UL, 2002019277UL, 4225148852UL, 641266809UL, 2133909450UL, 330112418UL, 1815776319UL, 1949213618UL, 3868452239UL, 2702722715UL, 2491030937UL, 468812562UL, 3226259052UL, 199165016UL, 436679774UL, 881956108UL, 1098105661UL, 68909298UL, +248572829UL, 339224422UL, 553849953UL, 3054752668UL, 701934162UL, 1898925107UL, 749060575UL, 987950022UL, 4040401060UL, 684345838UL, 3449205676UL, 2583450513UL, 433795092UL, 3559011048UL, 293161429UL, 3947766299UL, 3491895171UL, 1651265910UL, 1216468759UL, 1625512737UL, 412235874UL, 893680794UL, 2582820523UL, 1514322840UL, 2348781204UL, 2720801933UL, 3364999370UL, 2822073391UL, 2627166519UL, 3805500773UL, 177760590UL, 2210728920UL, +3136345252UL, 3226658259UL, 3982978003UL, 86264452UL, 536816704UL, 3489051867UL, 2161950016UL, 1375640747UL, 4116957650UL, 3676292350UL, 3001078542UL, 1379688752UL, 3059678152UL, 3740664918UL, 475697670UL, 539253230UL, 1256048653UL, 3819847913UL, 141216227UL, 3888391528UL, 3567424851UL, 4131097532UL, 2142453586UL, 3606575354UL, 3689715433UL, 2318212425UL, 3026095399UL, 2451038695UL, 4052322172UL, 1861782452UL, 3032216562UL, 4078403318UL, +2636775961UL, 2188864067UL, 3276459319UL, 2230349722UL, 3939784264UL, 831216291UL, 2483460713UL, 2571551493UL, 484276565UL, 3173595164UL, 4177831244UL, 4132249231UL, 2116763555UL, 1420812998UL, 2121017321UL, 2855491215UL, 1630144518UL, 2489688364UL, 411521312UL, 3713786536UL, 4177871972UL, 690465497UL, 855092147UL, 4271606539UL, 1265108699UL, 3757106624UL, 3151574897UL, 670335437UL, 3099376310UL, 3946436509UL, 1795346235UL, 4013409945UL, +}, +{ +650684252UL, 2220445579UL, 537394374UL, 571322423UL, 2781663439UL, 899394682UL, 364129622UL, 328438826UL, 1219862153UL, 830435885UL, 3278649457UL, 3072225531UL, 2838645991UL, 3150905380UL, 1251952499UL, 1751415553UL, 2034088483UL, 1437197870UL, 1907624878UL, 1786974150UL, 4207811086UL, 768131803UL, 2713210999UL, 4004509777UL, 3510764535UL, 2740991637UL, 3000313526UL, 1355959320UL, 938244439UL, 4093313692UL, 2476002145UL, 835527260UL, +2084758949UL, 4223775017UL, 91645393UL, 2251723899UL, 3159477758UL, 2008655575UL, 912220875UL, 1525327655UL, 2067948386UL, 2006141522UL, 450235614UL, 3945671083UL, 2852189452UL, 3804118704UL, 3302604345UL, 1712745267UL, 349281154UL, 19331179UL, 3423301791UL, 416995358UL, 2049170698UL, 684574142UL, 3271042138UL, 3438668017UL, 1645378852UL, 1995123150UL, 1835887948UL, 2347182898UL, 3828432892UL, 3710259931UL, 713144773UL, 3246285450UL, +2196135622UL, 1611287338UL, 2845388948UL, 3690657633UL, 2403178686UL, 2946296994UL, 2180908599UL, 3072014497UL, 3436535724UL, 2948908116UL, 3080353236UL, 1669938872UL, 3572731079UL, 1100892983UL, 308060688UL, 3092946261UL, 2725115972UL, 887278263UL, 991869336UL, 3597899723UL, 3454505181UL, 1108269267UL, 851855066UL, 1940998002UL, 3539084542UL, 3102161424UL, 965450940UL, 1942363226UL, 1430246588UL, 1368971075UL, 4251556311UL, 642683738UL, +3035789355UL, 1829444044UL, 4234626091UL, 671403403UL, 2809844786UL, 2251172733UL, 970188857UL, 3910072565UL, 1131847479UL, 3397535176UL, 3290884849UL, 861868157UL, 2811422184UL, 3280310458UL, 3502085520UL, 1499698865UL, 2446269873UL, 236680785UL, 1896103604UL, 1179896471UL, 83960622UL, 3303129336UL, 1191373247UL, 177898275UL, 3077388457UL, 1022975703UL, 2535144448UL, 8680269UL, 3602435630UL, 1810825915UL, 2293529378UL, 2307085218UL, +483894148UL, 2872435038UL, 2043868156UL, 3038491874UL, 3786518530UL, 3606440668UL, 3336713377UL, 120183042UL, 86901386UL, 2233164457UL, 2881782972UL, 3135264768UL, 2294460421UL, 2996668315UL, 658184098UL, 3558825846UL, 2386173040UL, 1950463910UL, 551627788UL, 2464303444UL, 893474565UL, 3277869222UL, 2852725906UL, 1191310725UL, 2398932683UL, 4164956002UL, 1689291769UL, 2619288187UL, 3429362702UL, 3205668166UL, 1668126623UL, 955771270UL, +2106753333UL, 650684252UL, 2220445579UL, 537394374UL, 571322423UL, 2369694095UL, 899394682UL, 364129622UL, 328438826UL, 1219862153UL, 4195985755UL, 3278649457UL, 3072225531UL, 2838645991UL, 3150905380UL, 2389919UL, 1751415553UL, 2034088483UL, 1437197870UL, 1907624878UL, 1516966376UL, 4207811086UL, 768131803UL, 2713210999UL, 4004509777UL, 1955929377UL, 2740991637UL, 3000313526UL, 1355959320UL, 938244439UL, 4263287583UL, 2476002145UL, +835527260UL, 2084758949UL, 4223775017UL, 110659216UL, 2251723899UL, 3159477758UL, 2008655575UL, 912220875UL, 2378803214UL, 2067948386UL, 2006141522UL, 450235614UL, 3945671083UL, 4112321452UL, 3804118704UL, 3302604345UL, 1712745267UL, 349281154UL, 3834044005UL, 3423301791UL, 416995358UL, 2049170698UL, 684574142UL, 3651360887UL, 3438668017UL, 1645378852UL, 1995123150UL, 1835887948UL, 1022257616UL, 3828432892UL, 3710259931UL, 713144773UL, +3246285450UL, 2485142597UL, 1611287338UL, 2845388948UL, 3690657633UL, 2403178686UL, 2201888000UL, 2180908599UL, 3072014497UL, 3436535724UL, 2948908116UL, 1647734358UL, 1669938872UL, 3572731079UL, 1100892983UL, 308060688UL, 592016509UL, 2725115972UL, 887278263UL, 991869336UL, 3597899723UL, 819708104UL, 1108269267UL, 851855066UL, 1940998002UL, 3539084542UL, 3156419045UL, 965450940UL, 1942363226UL, 1430246588UL, 1368971075UL, 224112021UL, +642683738UL, 3035789355UL, 1829444044UL, 4234626091UL, 314715303UL, 2809844786UL, 2251172733UL, 970188857UL, 3910072565UL, 155628632UL, 3397535176UL, 3290884849UL, 861868157UL, 2811422184UL, 1847583676UL, 3502085520UL, 1499698865UL, 2446269873UL, 236680785UL, 3698448762UL, 1179896471UL, 83960622UL, 3303129336UL, 1191373247UL, 1567908030UL, 3077388457UL, 1022975703UL, 2535144448UL, 8680269UL, 3979982957UL, 1810825915UL, 2293529378UL, +2307085218UL, 483894148UL, 4003402870UL, 2043868156UL, 3038491874UL, 3786518530UL, 3606440668UL, 3062185402UL, 120183042UL, 86901386UL, 2233164457UL, 2881782972UL, 3345668738UL, 2294460421UL, 2996668315UL, 658184098UL, 3558825846UL, 2121278529UL, 1950463910UL, 551627788UL, 2464303444UL, 893474565UL, 183176481UL, 2852725906UL, 1191310725UL, 2398932683UL, 4164956002UL, 788617081UL, 2619288187UL, 3429362702UL, 3205668166UL, 1668126623UL, +29124108UL, 2106753333UL, 650684252UL, 2220445579UL, 537394374UL, 725338795UL, 2369694095UL, 899394682UL, 364129622UL, 328438826UL, 1727397396UL, 4195985755UL, 3278649457UL, 3072225531UL, 2838645991UL, 583924693UL, 2389919UL, 1751415553UL, 2034088483UL, 1437197870UL, 1017611325UL, 1516966376UL, 4207811086UL, 768131803UL, 2713210999UL, 761144580UL, 1955929377UL, 2740991637UL, 3000313526UL, 1355959320UL, 840696976UL, 4263287583UL, +2476002145UL, 835527260UL, 2084758949UL, 3729075247UL, 110659216UL, 2251723899UL, 3159477758UL, 2008655575UL, 4127907945UL, 2378803214UL, 2067948386UL, 2006141522UL, 450235614UL, 3240776806UL, 4112321452UL, 3804118704UL, 3302604345UL, 1712745267UL, 1079549936UL, 3834044005UL, 3423301791UL, 416995358UL, 2049170698UL, 3913510119UL, 3651360887UL, 3438668017UL, 1645378852UL, 1995123150UL, 841590980UL, 1022257616UL, 3828432892UL, 3710259931UL, +713144773UL, 1272133892UL, 2485142597UL, 1611287338UL, 2845388948UL, 3690657633UL, 3083851146UL, 2201888000UL, 2180908599UL, 3072014497UL, 3436535724UL, 4162521870UL, 1647734358UL, 1669938872UL, 3572731079UL, 1100892983UL, 986584939UL, 592016509UL, 2725115972UL, 887278263UL, 991869336UL, 2711883653UL, 819708104UL, 1108269267UL, 851855066UL, 1940998002UL, 4050477073UL, 3156419045UL, 965450940UL, 1942363226UL, 1430246588UL, 4285490865UL, +224112021UL, 642683738UL, 3035789355UL, 1829444044UL, 4197159994UL, 314715303UL, 2809844786UL, 2251172733UL, 970188857UL, 3018833494UL, 155628632UL, 3397535176UL, 3290884849UL, 861868157UL, 2883971818UL, 1847583676UL, 3502085520UL, 1499698865UL, 2446269873UL, 2621709156UL, 3698448762UL, 1179896471UL, 83960622UL, 3303129336UL, 2192966710UL, 1567908030UL, 3077388457UL, 1022975703UL, 2535144448UL, 95661399UL, 3979982957UL, 1810825915UL, +2293529378UL, 2307085218UL, 485952375UL, 4003402870UL, 2043868156UL, 3038491874UL, 3786518530UL, 575288835UL, 3062185402UL, 120183042UL, 86901386UL, 2233164457UL, 2864966512UL, 3345668738UL, 2294460421UL, 2996668315UL, 658184098UL, 2892259673UL, 2121278529UL, 1950463910UL, 551627788UL, 2464303444UL, 2699734841UL, 183176481UL, 2852725906UL, 1191310725UL, 2398932683UL, 3505505465UL, 788617081UL, 2619288187UL, 3429362702UL, 3205668166UL, +2157859363UL, 29124108UL, 2106753333UL, 650684252UL, 2220445579UL, 978263237UL, 725338795UL, 2369694095UL, 899394682UL, 364129622UL, 3795063930UL, 1727397396UL, 4195985755UL, 3278649457UL, 3072225531UL, 1996768476UL, 583924693UL, 2389919UL, 1751415553UL, 2034088483UL, 1069211024UL, 1017611325UL, 1516966376UL, 4207811086UL, 768131803UL, 1365857736UL, 761144580UL, 1955929377UL, 2740991637UL, 3000313526UL, 1057560595UL, 840696976UL, +4263287583UL, 2476002145UL, 835527260UL, 76517292UL, 3729075247UL, 110659216UL, 2251723899UL, 3159477758UL, 3272987770UL, 4127907945UL, 2378803214UL, 2067948386UL, 2006141522UL, 1223694226UL, 3240776806UL, 4112321452UL, 3804118704UL, 3302604345UL, 2218568154UL, 1079549936UL, 3834044005UL, 3423301791UL, 416995358UL, 3661322119UL, 3913510119UL, 3651360887UL, 3438668017UL, 1645378852UL, 3606917602UL, 841590980UL, 1022257616UL, 3828432892UL, +3710259931UL, 1270853142UL, 1272133892UL, 2485142597UL, 1611287338UL, 2845388948UL, 131877212UL, 3083851146UL, 2201888000UL, 2180908599UL, 3072014497UL, 2459348479UL, 4162521870UL, 1647734358UL, 1669938872UL, 3572731079UL, 4285199726UL, 986584939UL, 592016509UL, 2725115972UL, 887278263UL, 3824306591UL, 2711883653UL, 819708104UL, 1108269267UL, 851855066UL, 190839383UL, 4050477073UL, 3156419045UL, 965450940UL, 1942363226UL, 1750931697UL, +4285490865UL, 224112021UL, 642683738UL, 3035789355UL, 1544088048UL, 4197159994UL, 314715303UL, 2809844786UL, 2251172733UL, 3155072709UL, 3018833494UL, 155628632UL, 3397535176UL, 3290884849UL, 4153861738UL, 2883971818UL, 1847583676UL, 3502085520UL, 1499698865UL, 1780983485UL, 2621709156UL, 3698448762UL, 1179896471UL, 83960622UL, 3849402190UL, 2192966710UL, 1567908030UL, 3077388457UL, 1022975703UL, 1639944917UL, 95661399UL, 3979982957UL, +1810825915UL, 2293529378UL, 3477014442UL, 485952375UL, 4003402870UL, 2043868156UL, 3038491874UL, 1482314580UL, 575288835UL, 3062185402UL, 120183042UL, 86901386UL, 3129494022UL, 2864966512UL, 3345668738UL, 2294460421UL, 2996668315UL, 1986664970UL, 2892259673UL, 2121278529UL, 1950463910UL, 551627788UL, 3105369079UL, 2699734841UL, 183176481UL, 2852725906UL, 1191310725UL, 3154591925UL, 3505505465UL, 788617081UL, 2619288187UL, 3429362702UL, +4204415531UL, 1321048315UL, 4247243973UL, 3085535935UL, 114618345UL, 2126710176UL, 1857709117UL, 3744103666UL, 304437872UL, 2388303947UL, 1802971382UL, 2099900439UL, 2543837819UL, 593111133UL, 3788847386UL, 1479546758UL, 4095492150UL, 240996968UL, 3423191009UL, 2666077260UL, 884572403UL, 2988847666UL, 928827215UL, 2549465610UL, 2773670136UL, 708214104UL, 2594951780UL, 1076989709UL, 2850313793UL, 1401578686UL, 4100639899UL, 2353261688UL, +1323066237UL, 31664438UL, 951240198UL, 3676836716UL, 3633113483UL, 3262159382UL, 981784748UL, 1172850762UL, 3106238289UL, 3118297408UL, 4207023277UL, 3362324732UL, 844983306UL, 3790928628UL, 4156848237UL, 2638267501UL, 1494090858UL, 3955182404UL, 1193294064UL, 4035152789UL, 2971914580UL, 2865046609UL, 3782329083UL, 120288587UL, 3300482994UL, 4268540970UL, 4183426205UL, 3572724103UL, 3287140971UL, 3038086532UL, 3210919007UL, 2171998100UL, +3958495101UL, 1589679371UL, 2880366694UL, 827575211UL, 1343189406UL, 364332706UL, 866065087UL, 33080625UL, 4284492640UL, 2277479989UL, 4110331130UL, 430538110UL, 3549886335UL, 3734345920UL, 3780943339UL, 638033279UL, 2684714509UL, 945721631UL, 49994267UL, 2394351381UL, 1996532760UL, 3201422203UL, 3509459657UL, 4118609520UL, 632454166UL, 696027759UL, 901486290UL, 1230453723UL, 4225865813UL, 4072619256UL, 3111686961UL, 1487480830UL, +4112016561UL, 1577020285UL, 2765241900UL, 2496609620UL, 1731271292UL, 6970479UL, 2936359283UL, 1541124937UL, 3705956773UL, 2349695021UL, 2247551804UL, 3759489710UL, 1321217706UL, 379586757UL, 2008242014UL, 1138475935UL, 3044902216UL, 1917596533UL, 2905651936UL, 3320601534UL, 1468557693UL, 4101437636UL, 374575138UL, 730079080UL, 995340259UL, 1430552870UL, 3860649629UL, 541396702UL, 3413070856UL, 3052797396UL, 3591116740UL, 2811484252UL, +2464310183UL, 1597327051UL, 3288232619UL, 1564716093UL, 2838386049UL, 264313861UL, 881377066UL, 4165178494UL, 1069189853UL, 1045737884UL, 2072266205UL, 2700673629UL, 2338724235UL, 837702541UL, 2603464957UL, 1548182143UL, 3565539962UL, 38172869UL, 1949065935UL, 3628598166UL, 2788698071UL, 3531182193UL, 1367529788UL, 3902468811UL, 1215323634UL, 1117475027UL, 3901912129UL, 2678279671UL, 597953858UL, 4082485755UL, 3696533122UL, 1078703353UL, +}, +{ +590004384UL, 3025338414UL, 1764374188UL, 20686172UL, 932343559UL, 1798441768UL, 1013577341UL, 4275903797UL, 853441141UL, 1065980978UL, 3665193407UL, 1555165047UL, 2962781443UL, 1822487181UL, 3329200135UL, 1527094489UL, 3805115799UL, 2252376033UL, 2137546519UL, 3632426270UL, 2439842864UL, 2525211849UL, 602876448UL, 1488163727UL, 3169015136UL, 832084039UL, 81097112UL, 994974428UL, 1945411347UL, 1020609213UL, 2863240894UL, 1639194881UL, +3078842449UL, 1885382385UL, 2595105518UL, 3857547190UL, 3654577058UL, 3853111480UL, 2237941224UL, 625422255UL, 3292783340UL, 750206381UL, 1002246874UL, 900879607UL, 820635221UL, 3318328110UL, 3980484559UL, 3924790669UL, 4260574943UL, 3658381114UL, 3673068643UL, 1319175627UL, 3620071157UL, 3914274380UL, 3310864044UL, 1529070914UL, 1760958838UL, 818806045UL, 3056976418UL, 2337737150UL, 2061530784UL, 1036243443UL, 2058675708UL, 1932546035UL, +1604709219UL, 1317296740UL, 2505350414UL, 624826181UL, 2710208816UL, 2208469912UL, 1930700024UL, 3769953790UL, 2092911082UL, 520309780UL, 3787727278UL, 684095804UL, 3697683979UL, 111440289UL, 4043494885UL, 1571375993UL, 1828801775UL, 3589061974UL, 3016563679UL, 2026002784UL, 3810490061UL, 2634997537UL, 2715287551UL, 1973545003UL, 3407971274UL, 3239387641UL, 2479429785UL, 324785401UL, 2622755198UL, 1525605325UL, 3280412074UL, 2453630352UL, +726090704UL, 4170024046UL, 248003549UL, 3319518538UL, 1331224401UL, 1203416669UL, 3497395173UL, 2465693133UL, 15303334UL, 267163358UL, 627307819UL, 294350450UL, 3691559013UL, 2491765952UL, 839609873UL, 1598505629UL, 3905396753UL, 583168080UL, 281403302UL, 1658629464UL, 1498139453UL, 2860737994UL, 148007837UL, 1439496901UL, 3226624586UL, 1708925351UL, 195473107UL, 1150552649UL, 2856922985UL, 1853471286UL, 1286593394UL, 2025932254UL, +1300583198UL, 3169702837UL, 1255226060UL, 3482666699UL, 1515557266UL, 1964035766UL, 1604627993UL, 641427670UL, 450188959UL, 1095230428UL, 293179001UL, 1293554079UL, 3022335608UL, 610535626UL, 1329467104UL, 3717935497UL, 1252385485UL, 441595535UL, 2937045243UL, 2846877561UL, 668719121UL, 3604154741UL, 1150714166UL, 1689640190UL, 2219487087UL, 2445975095UL, 3492083575UL, 377195836UL, 2727989292UL, 2460040634UL, 2910322481UL, 399050881UL, +3601292788UL, 590004384UL, 3025338414UL, 1764374188UL, 20686172UL, 3576058865UL, 1798441768UL, 1013577341UL, 4275903797UL, 853441141UL, 3862104007UL, 3665193407UL, 1555165047UL, 2962781443UL, 1822487181UL, 1058917817UL, 1527094489UL, 3805115799UL, 2252376033UL, 2137546519UL, 780594798UL, 2439842864UL, 2525211849UL, 602876448UL, 1488163727UL, 642430472UL, 832084039UL, 81097112UL, 994974428UL, 1945411347UL, 2231598766UL, 2863240894UL, +1639194881UL, 3078842449UL, 1885382385UL, 2387524763UL, 3857547190UL, 3654577058UL, 3853111480UL, 2237941224UL, 991026264UL, 3292783340UL, 750206381UL, 1002246874UL, 900879607UL, 1178067772UL, 3318328110UL, 3980484559UL, 3924790669UL, 4260574943UL, 1964983082UL, 3673068643UL, 1319175627UL, 3620071157UL, 3914274380UL, 992141498UL, 1529070914UL, 1760958838UL, 818806045UL, 3056976418UL, 3295305429UL, 2061530784UL, 1036243443UL, 2058675708UL, +1932546035UL, 3724542133UL, 1317296740UL, 2505350414UL, 624826181UL, 2710208816UL, 3359715256UL, 1930700024UL, 3769953790UL, 2092911082UL, 520309780UL, 1979908015UL, 684095804UL, 3697683979UL, 111440289UL, 4043494885UL, 3256907235UL, 1828801775UL, 3589061974UL, 3016563679UL, 2026002784UL, 1967781780UL, 2634997537UL, 2715287551UL, 1973545003UL, 3407971274UL, 391604110UL, 2479429785UL, 324785401UL, 2622755198UL, 1525605325UL, 462777294UL, +2453630352UL, 726090704UL, 4170024046UL, 248003549UL, 3125444318UL, 1331224401UL, 1203416669UL, 3497395173UL, 2465693133UL, 1610778556UL, 267163358UL, 627307819UL, 294350450UL, 3691559013UL, 3302305047UL, 839609873UL, 1598505629UL, 3905396753UL, 583168080UL, 1502262581UL, 1658629464UL, 1498139453UL, 2860737994UL, 148007837UL, 2973368511UL, 3226624586UL, 1708925351UL, 195473107UL, 1150552649UL, 522423348UL, 1853471286UL, 1286593394UL, +2025932254UL, 1300583198UL, 555770116UL, 1255226060UL, 3482666699UL, 1515557266UL, 1964035766UL, 877073175UL, 641427670UL, 450188959UL, 1095230428UL, 293179001UL, 4216364784UL, 3022335608UL, 610535626UL, 1329467104UL, 3717935497UL, 1665384485UL, 441595535UL, 2937045243UL, 2846877561UL, 668719121UL, 978801343UL, 1150714166UL, 1689640190UL, 2219487087UL, 2445975095UL, 3819595050UL, 377195836UL, 2727989292UL, 2460040634UL, 2910322481UL, +1200428010UL, 3601292788UL, 590004384UL, 3025338414UL, 1764374188UL, 3586255253UL, 3576058865UL, 1798441768UL, 1013577341UL, 4275903797UL, 1511067357UL, 3862104007UL, 3665193407UL, 1555165047UL, 2962781443UL, 2749766525UL, 1058917817UL, 1527094489UL, 3805115799UL, 2252376033UL, 817362043UL, 780594798UL, 2439842864UL, 2525211849UL, 602876448UL, 2309049006UL, 642430472UL, 832084039UL, 81097112UL, 994974428UL, 3148197354UL, 2231598766UL, +2863240894UL, 1639194881UL, 3078842449UL, 311769962UL, 2387524763UL, 3857547190UL, 3654577058UL, 3853111480UL, 1888597091UL, 991026264UL, 3292783340UL, 750206381UL, 1002246874UL, 2904195378UL, 1178067772UL, 3318328110UL, 3980484559UL, 3924790669UL, 4265386540UL, 1964983082UL, 3673068643UL, 1319175627UL, 3620071157UL, 1635921454UL, 992141498UL, 1529070914UL, 1760958838UL, 818806045UL, 3002614702UL, 3295305429UL, 2061530784UL, 1036243443UL, +2058675708UL, 2534375036UL, 3724542133UL, 1317296740UL, 2505350414UL, 624826181UL, 3042995618UL, 3359715256UL, 1930700024UL, 3769953790UL, 2092911082UL, 1870611696UL, 1979908015UL, 684095804UL, 3697683979UL, 111440289UL, 1111193348UL, 3256907235UL, 1828801775UL, 3589061974UL, 3016563679UL, 2203918092UL, 1967781780UL, 2634997537UL, 2715287551UL, 1973545003UL, 17967467UL, 391604110UL, 2479429785UL, 324785401UL, 2622755198UL, 3993572289UL, +462777294UL, 2453630352UL, 726090704UL, 4170024046UL, 813760479UL, 3125444318UL, 1331224401UL, 1203416669UL, 3497395173UL, 2528908686UL, 1610778556UL, 267163358UL, 627307819UL, 294350450UL, 4252461657UL, 3302305047UL, 839609873UL, 1598505629UL, 3905396753UL, 3407593947UL, 1502262581UL, 1658629464UL, 1498139453UL, 2860737994UL, 1137070983UL, 2973368511UL, 3226624586UL, 1708925351UL, 195473107UL, 1973834367UL, 522423348UL, 1853471286UL, +1286593394UL, 2025932254UL, 1636839834UL, 555770116UL, 1255226060UL, 3482666699UL, 1515557266UL, 4244619305UL, 877073175UL, 641427670UL, 450188959UL, 1095230428UL, 710341587UL, 4216364784UL, 3022335608UL, 610535626UL, 1329467104UL, 262034293UL, 1665384485UL, 441595535UL, 2937045243UL, 2846877561UL, 1059914271UL, 978801343UL, 1150714166UL, 1689640190UL, 2219487087UL, 258315233UL, 3819595050UL, 377195836UL, 2727989292UL, 2460040634UL, +1828274968UL, 1200428010UL, 3601292788UL, 590004384UL, 3025338414UL, 3487643146UL, 3586255253UL, 3576058865UL, 1798441768UL, 1013577341UL, 3609472816UL, 1511067357UL, 3862104007UL, 3665193407UL, 1555165047UL, 4188135767UL, 2749766525UL, 1058917817UL, 1527094489UL, 3805115799UL, 1547526585UL, 817362043UL, 780594798UL, 2439842864UL, 2525211849UL, 3949139098UL, 2309049006UL, 642430472UL, 832084039UL, 81097112UL, 2619711743UL, 3148197354UL, +2231598766UL, 2863240894UL, 1639194881UL, 3018692935UL, 311769962UL, 2387524763UL, 3857547190UL, 3654577058UL, 2418052942UL, 1888597091UL, 991026264UL, 3292783340UL, 750206381UL, 2501986418UL, 2904195378UL, 1178067772UL, 3318328110UL, 3980484559UL, 655757623UL, 4265386540UL, 1964983082UL, 3673068643UL, 1319175627UL, 1539823819UL, 1635921454UL, 992141498UL, 1529070914UL, 1760958838UL, 1840073710UL, 3002614702UL, 3295305429UL, 2061530784UL, +1036243443UL, 2212957003UL, 2534375036UL, 3724542133UL, 1317296740UL, 2505350414UL, 2754670042UL, 3042995618UL, 3359715256UL, 1930700024UL, 3769953790UL, 3307920786UL, 1870611696UL, 1979908015UL, 684095804UL, 3697683979UL, 326641529UL, 1111193348UL, 3256907235UL, 1828801775UL, 3589061974UL, 1408835557UL, 2203918092UL, 1967781780UL, 2634997537UL, 2715287551UL, 1958610929UL, 17967467UL, 391604110UL, 2479429785UL, 324785401UL, 3833051255UL, +3993572289UL, 462777294UL, 2453630352UL, 726090704UL, 1236380896UL, 813760479UL, 3125444318UL, 1331224401UL, 1203416669UL, 728276857UL, 2528908686UL, 1610778556UL, 267163358UL, 627307819UL, 4276734917UL, 4252461657UL, 3302305047UL, 839609873UL, 1598505629UL, 3827653659UL, 3407593947UL, 1502262581UL, 1658629464UL, 1498139453UL, 3636064463UL, 1137070983UL, 2973368511UL, 3226624586UL, 1708925351UL, 2288771247UL, 1973834367UL, 522423348UL, +1853471286UL, 1286593394UL, 798364204UL, 1636839834UL, 555770116UL, 1255226060UL, 3482666699UL, 2385578475UL, 4244619305UL, 877073175UL, 641427670UL, 450188959UL, 3502743047UL, 710341587UL, 4216364784UL, 3022335608UL, 610535626UL, 2388448039UL, 262034293UL, 1665384485UL, 441595535UL, 2937045243UL, 3028160550UL, 1059914271UL, 978801343UL, 1150714166UL, 1689640190UL, 169488023UL, 258315233UL, 3819595050UL, 377195836UL, 2727989292UL, +837094660UL, 3531987448UL, 1901453576UL, 3312447598UL, 1036467641UL, 2243300650UL, 3148869460UL, 1886274644UL, 4076707689UL, 257110870UL, 3118463831UL, 1165161057UL, 1118846497UL, 3446934363UL, 1514176098UL, 1362957326UL, 2629874126UL, 791374320UL, 1015673947UL, 4252955786UL, 2409207780UL, 3831311130UL, 1654475922UL, 3682733431UL, 780405105UL, 4059616372UL, 503333525UL, 1471514828UL, 2526848791UL, 607539645UL, 730408454UL, 1574159005UL, +1777808061UL, 1296178310UL, 1078855633UL, 878462103UL, 269337411UL, 750735378UL, 2599590920UL, 4206153248UL, 939121991UL, 3061289971UL, 2543431563UL, 1684736054UL, 2319658494UL, 77300347UL, 3222569207UL, 3882064339UL, 2201120493UL, 289098227UL, 3934209124UL, 2407620042UL, 2713079957UL, 2812644841UL, 115993752UL, 2545688211UL, 774350907UL, 939749505UL, 2242588062UL, 960853876UL, 296665594UL, 1367312411UL, 3370351589UL, 711706404UL, +3331136631UL, 1370376958UL, 2322438166UL, 577115138UL, 1472236592UL, 4029835216UL, 1122502809UL, 3490426739UL, 1930206806UL, 2074277138UL, 1360950220UL, 3797708387UL, 2007430804UL, 2257239461UL, 3889012648UL, 710165871UL, 763101711UL, 728019024UL, 652403220UL, 2517020147UL, 1801290767UL, 1478810019UL, 1057288808UL, 2879821959UL, 3916870020UL, 1480362189UL, 919816752UL, 375872647UL, 3236906236UL, 1504223782UL, 128306943UL, 1355826533UL, +2656243649UL, 390454690UL, 3848250363UL, 377480950UL, 358651174UL, 1337795904UL, 1925462532UL, 2421843219UL, 173144626UL, 886649902UL, 402617827UL, 932830871UL, 742712936UL, 4033430386UL, 1409945926UL, 3617206544UL, 2383446356UL, 3452204096UL, 615486157UL, 720696019UL, 1730134434UL, 3918468503UL, 1629431965UL, 2174079220UL, 325852294UL, 234479771UL, 1490297289UL, 3579002992UL, 3538738636UL, 139386548UL, 3067789050UL, 2078261059UL, +3552654276UL, 1774602596UL, 2105142163UL, 2768099869UL, 2265044995UL, 3680536732UL, 3601322356UL, 2848878442UL, 1166743022UL, 3508176959UL, 2186695985UL, 550278868UL, 3324775634UL, 384537301UL, 1019044102UL, 3354263542UL, 1942540686UL, 922714337UL, 3097711558UL, 3074228403UL, 3565076630UL, 3459053081UL, 4128383906UL, 1114387332UL, 2101424539UL, 1192649508UL, 58778130UL, 1651798895UL, 1752063480UL, 1728826905UL, 2225187635UL, 2463770127UL, +}, +{ +1978406995UL, 576106282UL, 2238958298UL, 2073551095UL, 624788087UL, 4231569260UL, 1853272808UL, 238274694UL, 2389334758UL, 410188028UL, 2293786099UL, 4243662908UL, 2317700970UL, 4050493361UL, 2348206908UL, 485250660UL, 1212732903UL, 169414736UL, 292623762UL, 1602229231UL, 2466348869UL, 3063669700UL, 1872890881UL, 1887188929UL, 3447638989UL, 162521682UL, 1470651713UL, 4036975255UL, 3423782623UL, 4043724693UL, 1686690883UL, 2610958712UL, +35940353UL, 78593759UL, 1565950713UL, 1304303952UL, 2004267248UL, 1417268036UL, 3328228522UL, 789915977UL, 2567452041UL, 3564175714UL, 1838409932UL, 1455795236UL, 22377452UL, 455201131UL, 3340286965UL, 184599544UL, 4102076073UL, 4007870762UL, 1470247063UL, 1579231003UL, 3544385556UL, 3408973464UL, 3759098465UL, 3243598964UL, 532452279UL, 1172265732UL, 3520978258UL, 2880513876UL, 41188252UL, 1663974668UL, 3444236420UL, 338981290UL, +2140558860UL, 3310465688UL, 552673362UL, 3277110106UL, 948036400UL, 1346056406UL, 3257468427UL, 4008294878UL, 3788890535UL, 2414511414UL, 3539325895UL, 3025695322UL, 3727849930UL, 3922840362UL, 535899902UL, 665898223UL, 1456499692UL, 354208792UL, 247894771UL, 2093316680UL, 2945209002UL, 1029298544UL, 976007759UL, 394966955UL, 1843302845UL, 3689202777UL, 1999949614UL, 1070472810UL, 4233404701UL, 667526747UL, 2313963966UL, 3519400667UL, +1548274317UL, 3272402139UL, 2570038689UL, 892260481UL, 3547254358UL, 1540409404UL, 3687395534UL, 3751445920UL, 546406228UL, 2167638865UL, 4234783150UL, 806401261UL, 1351195286UL, 1085913868UL, 3109267901UL, 1882610112UL, 1568734773UL, 239430641UL, 3971361190UL, 383932711UL, 149541490UL, 196701535UL, 108079452UL, 888590964UL, 1708559652UL, 3196290573UL, 2115587458UL, 3198525248UL, 3580113911UL, 3098818120UL, 4271558926UL, 3208851696UL, +3354604918UL, 3536923694UL, 1087345822UL, 2292802521UL, 3500230819UL, 411564772UL, 2408049547UL, 1215342690UL, 1707182109UL, 774540619UL, 1613606757UL, 836141085UL, 1061962136UL, 348765795UL, 2852610966UL, 3526215991UL, 2708801073UL, 3467537935UL, 472234793UL, 3944263763UL, 1782219410UL, 502724699UL, 3525703395UL, 1756411033UL, 1358811278UL, 3938603279UL, 3701976555UL, 3259537961UL, 628617330UL, 1553932236UL, 1974037630UL, 2090519666UL, +2185028543UL, 1978406995UL, 576106282UL, 2238958298UL, 2073551095UL, 638634424UL, 4231569260UL, 1853272808UL, 238274694UL, 2389334758UL, 3808551433UL, 2293786099UL, 4243662908UL, 2317700970UL, 4050493361UL, 957981276UL, 485250660UL, 1212732903UL, 169414736UL, 292623762UL, 1956197178UL, 2466348869UL, 3063669700UL, 1872890881UL, 1887188929UL, 1162224455UL, 162521682UL, 1470651713UL, 4036975255UL, 3423782623UL, 3243414978UL, 1686690883UL, +2610958712UL, 35940353UL, 78593759UL, 1648686849UL, 1304303952UL, 2004267248UL, 1417268036UL, 3328228522UL, 3740797237UL, 2567452041UL, 3564175714UL, 1838409932UL, 1455795236UL, 1045087636UL, 455201131UL, 3340286965UL, 184599544UL, 4102076073UL, 2685677331UL, 1470247063UL, 1579231003UL, 3544385556UL, 3408973464UL, 3832799869UL, 3243598964UL, 532452279UL, 1172265732UL, 3520978258UL, 531684354UL, 41188252UL, 1663974668UL, 3444236420UL, +338981290UL, 1286622338UL, 3310465688UL, 552673362UL, 3277110106UL, 948036400UL, 2987864230UL, 3257468427UL, 4008294878UL, 3788890535UL, 2414511414UL, 2613137548UL, 3025695322UL, 3727849930UL, 3922840362UL, 535899902UL, 3288883992UL, 1456499692UL, 354208792UL, 247894771UL, 2093316680UL, 3775770224UL, 1029298544UL, 976007759UL, 394966955UL, 1843302845UL, 1484214934UL, 1999949614UL, 1070472810UL, 4233404701UL, 667526747UL, 3708951530UL, +3519400667UL, 1548274317UL, 3272402139UL, 2570038689UL, 3457725296UL, 3547254358UL, 1540409404UL, 3687395534UL, 3751445920UL, 181641144UL, 2167638865UL, 4234783150UL, 806401261UL, 1351195286UL, 3457819598UL, 3109267901UL, 1882610112UL, 1568734773UL, 239430641UL, 4037392309UL, 383932711UL, 149541490UL, 196701535UL, 108079452UL, 1724276622UL, 1708559652UL, 3196290573UL, 2115587458UL, 3198525248UL, 3784683125UL, 3098818120UL, 4271558926UL, +3208851696UL, 3354604918UL, 149872004UL, 1087345822UL, 2292802521UL, 3500230819UL, 411564772UL, 4068437023UL, 1215342690UL, 1707182109UL, 774540619UL, 1613606757UL, 1062624488UL, 1061962136UL, 348765795UL, 2852610966UL, 3526215991UL, 1518538195UL, 3467537935UL, 472234793UL, 3944263763UL, 1782219410UL, 1835413488UL, 3525703395UL, 1756411033UL, 1358811278UL, 3938603279UL, 1054245423UL, 3259537961UL, 628617330UL, 1553932236UL, 1974037630UL, +2030751433UL, 2185028543UL, 1978406995UL, 576106282UL, 2238958298UL, 3877268821UL, 638634424UL, 4231569260UL, 1853272808UL, 238274694UL, 2482404724UL, 3808551433UL, 2293786099UL, 4243662908UL, 2317700970UL, 1955227186UL, 957981276UL, 485250660UL, 1212732903UL, 169414736UL, 1333246101UL, 1956197178UL, 2466348869UL, 3063669700UL, 1872890881UL, 3662049503UL, 1162224455UL, 162521682UL, 1470651713UL, 4036975255UL, 3593925064UL, 3243414978UL, +1686690883UL, 2610958712UL, 35940353UL, 2530174792UL, 1648686849UL, 1304303952UL, 2004267248UL, 1417268036UL, 1299827381UL, 3740797237UL, 2567452041UL, 3564175714UL, 1838409932UL, 4221368409UL, 1045087636UL, 455201131UL, 3340286965UL, 184599544UL, 486448047UL, 2685677331UL, 1470247063UL, 1579231003UL, 3544385556UL, 1404931688UL, 3832799869UL, 3243598964UL, 532452279UL, 1172265732UL, 3373048034UL, 531684354UL, 41188252UL, 1663974668UL, +3444236420UL, 1375188728UL, 1286622338UL, 3310465688UL, 552673362UL, 3277110106UL, 655980467UL, 2987864230UL, 3257468427UL, 4008294878UL, 3788890535UL, 763995173UL, 2613137548UL, 3025695322UL, 3727849930UL, 3922840362UL, 1850434657UL, 3288883992UL, 1456499692UL, 354208792UL, 247894771UL, 3440471938UL, 3775770224UL, 1029298544UL, 976007759UL, 394966955UL, 3298245949UL, 1484214934UL, 1999949614UL, 1070472810UL, 4233404701UL, 3788558253UL, +3708951530UL, 3519400667UL, 1548274317UL, 3272402139UL, 3117201719UL, 3457725296UL, 3547254358UL, 1540409404UL, 3687395534UL, 3871454027UL, 181641144UL, 2167638865UL, 4234783150UL, 806401261UL, 1627904858UL, 3457819598UL, 3109267901UL, 1882610112UL, 1568734773UL, 3178105921UL, 4037392309UL, 383932711UL, 149541490UL, 196701535UL, 424324376UL, 1724276622UL, 1708559652UL, 3196290573UL, 2115587458UL, 2946026327UL, 3784683125UL, 3098818120UL, +4271558926UL, 3208851696UL, 2551504859UL, 149872004UL, 1087345822UL, 2292802521UL, 3500230819UL, 3055410013UL, 4068437023UL, 1215342690UL, 1707182109UL, 774540619UL, 2466902579UL, 1062624488UL, 1061962136UL, 348765795UL, 2852610966UL, 355211123UL, 1518538195UL, 3467537935UL, 472234793UL, 3944263763UL, 3159176627UL, 1835413488UL, 3525703395UL, 1756411033UL, 1358811278UL, 2153206130UL, 1054245423UL, 3259537961UL, 628617330UL, 1553932236UL, +1741202495UL, 2030751433UL, 2185028543UL, 1978406995UL, 576106282UL, 2832311581UL, 3877268821UL, 638634424UL, 4231569260UL, 1853272808UL, 3103974717UL, 2482404724UL, 3808551433UL, 2293786099UL, 4243662908UL, 2607780401UL, 1955227186UL, 957981276UL, 485250660UL, 1212732903UL, 3214649174UL, 1333246101UL, 1956197178UL, 2466348869UL, 3063669700UL, 2428387069UL, 3662049503UL, 1162224455UL, 162521682UL, 1470651713UL, 3563435961UL, 3593925064UL, +3243414978UL, 1686690883UL, 2610958712UL, 1021669488UL, 2530174792UL, 1648686849UL, 1304303952UL, 2004267248UL, 1150095671UL, 1299827381UL, 3740797237UL, 2567452041UL, 3564175714UL, 1992360540UL, 4221368409UL, 1045087636UL, 455201131UL, 3340286965UL, 3795860292UL, 486448047UL, 2685677331UL, 1470247063UL, 1579231003UL, 3012017918UL, 1404931688UL, 3832799869UL, 3243598964UL, 532452279UL, 2740401823UL, 3373048034UL, 531684354UL, 41188252UL, +1663974668UL, 1239982773UL, 1375188728UL, 1286622338UL, 3310465688UL, 552673362UL, 2159084435UL, 655980467UL, 2987864230UL, 3257468427UL, 4008294878UL, 1526518186UL, 763995173UL, 2613137548UL, 3025695322UL, 3727849930UL, 4161669345UL, 1850434657UL, 3288883992UL, 1456499692UL, 354208792UL, 1648970767UL, 3440471938UL, 3775770224UL, 1029298544UL, 976007759UL, 292829454UL, 3298245949UL, 1484214934UL, 1999949614UL, 1070472810UL, 949984087UL, +3788558253UL, 3708951530UL, 3519400667UL, 1548274317UL, 3691975282UL, 3117201719UL, 3457725296UL, 3547254358UL, 1540409404UL, 3414085332UL, 3871454027UL, 181641144UL, 2167638865UL, 4234783150UL, 487427004UL, 1627904858UL, 3457819598UL, 3109267901UL, 1882610112UL, 2942538550UL, 3178105921UL, 4037392309UL, 383932711UL, 149541490UL, 528605550UL, 424324376UL, 1724276622UL, 1708559652UL, 3196290573UL, 2042399752UL, 2946026327UL, 3784683125UL, +3098818120UL, 4271558926UL, 2493686919UL, 2551504859UL, 149872004UL, 1087345822UL, 2292802521UL, 3257357826UL, 3055410013UL, 4068437023UL, 1215342690UL, 1707182109UL, 1101368233UL, 2466902579UL, 1062624488UL, 1061962136UL, 348765795UL, 377675640UL, 355211123UL, 1518538195UL, 3467537935UL, 472234793UL, 1918362523UL, 3159176627UL, 1835413488UL, 3525703395UL, 1756411033UL, 490591069UL, 2153206130UL, 1054245423UL, 3259537961UL, 628617330UL, +2464143505UL, 3547421156UL, 4181103091UL, 1646291356UL, 2711273600UL, 2961799099UL, 1443009342UL, 2191618308UL, 1193143275UL, 1858488142UL, 3741304147UL, 1479629752UL, 214641634UL, 1601114903UL, 3032545707UL, 5784133UL, 1466424840UL, 2251379876UL, 4054080092UL, 2965144328UL, 644228426UL, 1397556958UL, 422190032UL, 3059134799UL, 3779253493UL, 1314537880UL, 867798895UL, 3819721559UL, 3588436937UL, 670021879UL, 1070365654UL, 3339455790UL, +2963659516UL, 1662488399UL, 2336157317UL, 3427798652UL, 2782719134UL, 1317842084UL, 1576308528UL, 1129452059UL, 3400565954UL, 84977051UL, 3689257381UL, 3289717503UL, 3535165628UL, 3982356490UL, 173255911UL, 1929987033UL, 4221790572UL, 3473317939UL, 749060417UL, 2711561754UL, 316719217UL, 2359410057UL, 2014271053UL, 1432982162UL, 2107582322UL, 1899811989UL, 1394115707UL, 1134266213UL, 2334994542UL, 2475488907UL, 3238562415UL, 2410379210UL, +4147209396UL, 2446286513UL, 2194020199UL, 3068194593UL, 797186100UL, 1299000541UL, 1870322719UL, 2944499140UL, 1045779179UL, 2735528787UL, 3057750264UL, 2607876894UL, 1595833743UL, 3327636115UL, 3520489322UL, 3864068029UL, 3153522810UL, 2609437702UL, 1360208295UL, 2062444770UL, 3927110355UL, 1524755299UL, 1708215998UL, 3587488663UL, 2813888113UL, 686192293UL, 1078633032UL, 3066910876UL, 793688350UL, 3613674912UL, 387713910UL, 2660476731UL, +3032509241UL, 2353038709UL, 2212424333UL, 2110412913UL, 3631228061UL, 2765134272UL, 4025821789UL, 3324834269UL, 187577732UL, 1568270802UL, 2098502315UL, 2472645526UL, 2986813860UL, 1621191378UL, 3891512282UL, 1561648319UL, 2690491944UL, 3075246584UL, 3202791012UL, 315381589UL, 3645907425UL, 3532420114UL, 802256935UL, 1270128258UL, 2695868207UL, 4075358890UL, 3888212208UL, 510396943UL, 3683116722UL, 3943939501UL, 146061942UL, 733291914UL, +1402325031UL, 672641124UL, 2817168601UL, 2622398925UL, 3641379870UL, 2969146913UL, 4232866548UL, 1694492034UL, 3065141682UL, 234404736UL, 1921499010UL, 2300706258UL, 1304904939UL, 207802178UL, 2674605425UL, 2688377241UL, 2674991105UL, 2585496531UL, 2358858923UL, 2578793432UL, 3275116043UL, 228073476UL, 2936443283UL, 3713102344UL, 1629243323UL, 209348683UL, 3730808488UL, 275442226UL, 223820143UL, 2365614109UL, 3017206322UL, 1906208795UL, +}, +{ +1545504510UL, 1985586093UL, 2005504076UL, 2487099791UL, 2348737867UL, 2254755902UL, 3789154730UL, 3268946922UL, 99552511UL, 1369361877UL, 1888041043UL, 3105269579UL, 4044127396UL, 2380045264UL, 2970234287UL, 293292961UL, 1811276320UL, 1083136897UL, 3016497500UL, 950611584UL, 2165628367UL, 4140133899UL, 2402926185UL, 990501164UL, 2185997143UL, 1769871204UL, 721625457UL, 567446962UL, 1695515231UL, 1848699963UL, 4163520111UL, 2316975723UL, +4268269680UL, 1021066723UL, 517434635UL, 3827063239UL, 3483118065UL, 760366769UL, 3072996795UL, 3548263896UL, 2131401627UL, 4167855065UL, 410255606UL, 1992500865UL, 1322267629UL, 1599293552UL, 2389387938UL, 3721625360UL, 216375429UL, 2002236178UL, 1834631738UL, 1585275126UL, 3879559071UL, 2517667239UL, 1397456303UL, 4095227658UL, 589002062UL, 137665950UL, 3933018338UL, 1519132173UL, 3566494128UL, 3914066872UL, 3233332246UL, 855336825UL, +1882502420UL, 1081015168UL, 4148374722UL, 1683880703UL, 1161266344UL, 99374978UL, 733926790UL, 3520260556UL, 3643143173UL, 927318029UL, 398003191UL, 3472026294UL, 3518018860UL, 2319507998UL, 2650129369UL, 3781620600UL, 1294634949UL, 3977318486UL, 3068540117UL, 3732334866UL, 740308004UL, 1988900647UL, 2936479173UL, 2348744493UL, 1357856242UL, 3842428732UL, 3746094733UL, 214260739UL, 3493892012UL, 2358001919UL, 1775614809UL, 952871363UL, +1216985499UL, 2706067772UL, 1008517818UL, 4189424856UL, 1260334069UL, 2420035836UL, 311831945UL, 3409272605UL, 4266242510UL, 3590716427UL, 537257045UL, 3153762469UL, 1620749663UL, 3338743851UL, 3644831936UL, 3243426619UL, 783551642UL, 1305153827UL, 2026979662UL, 3164955857UL, 4082645339UL, 1633544228UL, 3389303153UL, 440623817UL, 204979344UL, 1674764841UL, 633231391UL, 4180702701UL, 1953210184UL, 2534954734UL, 4252100558UL, 2993632630UL, +4050264705UL, 678445398UL, 1502035091UL, 302442688UL, 493504779UL, 2321459487UL, 1141171231UL, 1507727159UL, 672678623UL, 4046722895UL, 65675127UL, 2936731189UL, 441159654UL, 832039862UL, 2252252769UL, 3090962795UL, 2839688755UL, 645344032UL, 2921087914UL, 2264738834UL, 2341060101UL, 778789539UL, 737962654UL, 2859693559UL, 2784310535UL, 493247978UL, 185832691UL, 3321631011UL, 641506549UL, 2652806878UL, 480335604UL, 2908694258UL, +984807024UL, 1545504510UL, 1985586093UL, 2005504076UL, 2487099791UL, 127488455UL, 2254755902UL, 3789154730UL, 3268946922UL, 99552511UL, 2160330513UL, 1888041043UL, 3105269579UL, 4044127396UL, 2380045264UL, 3185912634UL, 293292961UL, 1811276320UL, 1083136897UL, 3016497500UL, 116883339UL, 2165628367UL, 4140133899UL, 2402926185UL, 990501164UL, 4099344218UL, 1769871204UL, 721625457UL, 567446962UL, 1695515231UL, 1218419978UL, 4163520111UL, +2316975723UL, 4268269680UL, 1021066723UL, 237254804UL, 3827063239UL, 3483118065UL, 760366769UL, 3072996795UL, 1020639813UL, 2131401627UL, 4167855065UL, 410255606UL, 1992500865UL, 1887858126UL, 1599293552UL, 2389387938UL, 3721625360UL, 216375429UL, 2096265248UL, 1834631738UL, 1585275126UL, 3879559071UL, 2517667239UL, 3267338158UL, 4095227658UL, 589002062UL, 137665950UL, 3933018338UL, 3823062902UL, 3566494128UL, 3914066872UL, 3233332246UL, +855336825UL, 3240858503UL, 1081015168UL, 4148374722UL, 1683880703UL, 1161266344UL, 4034899335UL, 733926790UL, 3520260556UL, 3643143173UL, 927318029UL, 2130442867UL, 3472026294UL, 3518018860UL, 2319507998UL, 2650129369UL, 253769320UL, 1294634949UL, 3977318486UL, 3068540117UL, 3732334866UL, 3100107703UL, 1988900647UL, 2936479173UL, 2348744493UL, 1357856242UL, 477065277UL, 3746094733UL, 214260739UL, 3493892012UL, 2358001919UL, 52055911UL, +952871363UL, 1216985499UL, 2706067772UL, 1008517818UL, 2820619262UL, 1260334069UL, 2420035836UL, 311831945UL, 3409272605UL, 2066128794UL, 3590716427UL, 537257045UL, 3153762469UL, 1620749663UL, 2261931254UL, 3644831936UL, 3243426619UL, 783551642UL, 1305153827UL, 3937339872UL, 3164955857UL, 4082645339UL, 1633544228UL, 3389303153UL, 3304461891UL, 204979344UL, 1674764841UL, 633231391UL, 4180702701UL, 2649553051UL, 2534954734UL, 4252100558UL, +2993632630UL, 4050264705UL, 3777379050UL, 1502035091UL, 302442688UL, 493504779UL, 2321459487UL, 1795212504UL, 1507727159UL, 672678623UL, 4046722895UL, 65675127UL, 2810951967UL, 441159654UL, 832039862UL, 2252252769UL, 3090962795UL, 3317253399UL, 645344032UL, 2921087914UL, 2264738834UL, 2341060101UL, 1431934790UL, 737962654UL, 2859693559UL, 2784310535UL, 493247978UL, 555655767UL, 3321631011UL, 641506549UL, 2652806878UL, 480335604UL, +1837415425UL, 984807024UL, 1545504510UL, 1985586093UL, 2005504076UL, 2274320195UL, 127488455UL, 2254755902UL, 3789154730UL, 3268946922UL, 3812459919UL, 2160330513UL, 1888041043UL, 3105269579UL, 4044127396UL, 2341347785UL, 3185912634UL, 293292961UL, 1811276320UL, 1083136897UL, 825098089UL, 116883339UL, 2165628367UL, 4140133899UL, 2402926185UL, 4124720284UL, 4099344218UL, 1769871204UL, 721625457UL, 567446962UL, 3598160577UL, 1218419978UL, +4163520111UL, 2316975723UL, 4268269680UL, 923374392UL, 237254804UL, 3827063239UL, 3483118065UL, 760366769UL, 2263405553UL, 1020639813UL, 2131401627UL, 4167855065UL, 410255606UL, 3382265961UL, 1887858126UL, 1599293552UL, 2389387938UL, 3721625360UL, 3440586186UL, 2096265248UL, 1834631738UL, 1585275126UL, 3879559071UL, 711626863UL, 3267338158UL, 4095227658UL, 589002062UL, 137665950UL, 1190761134UL, 3823062902UL, 3566494128UL, 3914066872UL, +3233332246UL, 3844456625UL, 3240858503UL, 1081015168UL, 4148374722UL, 1683880703UL, 589447946UL, 4034899335UL, 733926790UL, 3520260556UL, 3643143173UL, 3202263729UL, 2130442867UL, 3472026294UL, 3518018860UL, 2319507998UL, 3458685425UL, 253769320UL, 1294634949UL, 3977318486UL, 3068540117UL, 702365700UL, 3100107703UL, 1988900647UL, 2936479173UL, 2348744493UL, 969926974UL, 477065277UL, 3746094733UL, 214260739UL, 3493892012UL, 2890740482UL, +52055911UL, 952871363UL, 1216985499UL, 2706067772UL, 1079370138UL, 2820619262UL, 1260334069UL, 2420035836UL, 311831945UL, 701108525UL, 2066128794UL, 3590716427UL, 537257045UL, 3153762469UL, 2900214585UL, 2261931254UL, 3644831936UL, 3243426619UL, 783551642UL, 3143067452UL, 3937339872UL, 3164955857UL, 4082645339UL, 1633544228UL, 1680728882UL, 3304461891UL, 204979344UL, 1674764841UL, 633231391UL, 689425572UL, 2649553051UL, 2534954734UL, +4252100558UL, 2993632630UL, 865432399UL, 3777379050UL, 1502035091UL, 302442688UL, 493504779UL, 1282312650UL, 1795212504UL, 1507727159UL, 672678623UL, 4046722895UL, 976003271UL, 2810951967UL, 441159654UL, 832039862UL, 2252252769UL, 726554843UL, 3317253399UL, 645344032UL, 2921087914UL, 2264738834UL, 1325395107UL, 1431934790UL, 737962654UL, 2859693559UL, 2784310535UL, 3876486226UL, 555655767UL, 3321631011UL, 641506549UL, 2652806878UL, +3848380198UL, 1837415425UL, 984807024UL, 1545504510UL, 1985586093UL, 3711682090UL, 2274320195UL, 127488455UL, 2254755902UL, 3789154730UL, 1595223697UL, 3812459919UL, 2160330513UL, 1888041043UL, 3105269579UL, 2773455385UL, 2341347785UL, 3185912634UL, 293292961UL, 1811276320UL, 3280464626UL, 825098089UL, 116883339UL, 2165628367UL, 4140133899UL, 3092114881UL, 4124720284UL, 4099344218UL, 1769871204UL, 721625457UL, 1514083147UL, 3598160577UL, +1218419978UL, 4163520111UL, 2316975723UL, 200993429UL, 923374392UL, 237254804UL, 3827063239UL, 3483118065UL, 677187089UL, 2263405553UL, 1020639813UL, 2131401627UL, 4167855065UL, 1892382552UL, 3382265961UL, 1887858126UL, 1599293552UL, 2389387938UL, 4153928364UL, 3440586186UL, 2096265248UL, 1834631738UL, 1585275126UL, 3348317504UL, 711626863UL, 3267338158UL, 4095227658UL, 589002062UL, 3125839176UL, 1190761134UL, 3823062902UL, 3566494128UL, +3914066872UL, 1320578396UL, 3844456625UL, 3240858503UL, 1081015168UL, 4148374722UL, 258762412UL, 589447946UL, 4034899335UL, 733926790UL, 3520260556UL, 4290301810UL, 3202263729UL, 2130442867UL, 3472026294UL, 3518018860UL, 2904238635UL, 3458685425UL, 253769320UL, 1294634949UL, 3977318486UL, 2517006218UL, 702365700UL, 3100107703UL, 1988900647UL, 2936479173UL, 3227096174UL, 969926974UL, 477065277UL, 3746094733UL, 214260739UL, 3868449115UL, +2890740482UL, 52055911UL, 952871363UL, 1216985499UL, 2857823043UL, 1079370138UL, 2820619262UL, 1260334069UL, 2420035836UL, 1843837226UL, 701108525UL, 2066128794UL, 3590716427UL, 537257045UL, 1202524172UL, 2900214585UL, 2261931254UL, 3644831936UL, 3243426619UL, 2113758468UL, 3143067452UL, 3937339872UL, 3164955857UL, 4082645339UL, 3987431298UL, 1680728882UL, 3304461891UL, 204979344UL, 1674764841UL, 2684386058UL, 689425572UL, 2649553051UL, +2534954734UL, 4252100558UL, 3511996574UL, 865432399UL, 3777379050UL, 1502035091UL, 302442688UL, 970989610UL, 1282312650UL, 1795212504UL, 1507727159UL, 672678623UL, 3080995547UL, 976003271UL, 2810951967UL, 441159654UL, 832039862UL, 2670291295UL, 726554843UL, 3317253399UL, 645344032UL, 2921087914UL, 3039207936UL, 1325395107UL, 1431934790UL, 737962654UL, 2859693559UL, 2452474228UL, 3876486226UL, 555655767UL, 3321631011UL, 641506549UL, +712394572UL, 931322445UL, 3691485988UL, 77755644UL, 3585967569UL, 1546642657UL, 1074481665UL, 1211742891UL, 2405208503UL, 1015438825UL, 3187019083UL, 2194891243UL, 1305917012UL, 3737279586UL, 2633137983UL, 1924729261UL, 72781059UL, 1412697099UL, 3828782214UL, 1637665425UL, 4170514983UL, 2248277352UL, 3793164712UL, 2365683667UL, 1287488796UL, 3240061130UL, 2411573225UL, 3237771995UL, 901649504UL, 4107276625UL, 1613775409UL, 741888560UL, +332459303UL, 850991886UL, 3249391248UL, 3550484151UL, 3689717953UL, 233288631UL, 2496730550UL, 3221264250UL, 3172144573UL, 1429937065UL, 1776357872UL, 1084763904UL, 1993209913UL, 4142869218UL, 3130780078UL, 18180577UL, 2819625557UL, 1978393449UL, 372704074UL, 3919523286UL, 1777756963UL, 188652529UL, 411213996UL, 62282979UL, 3775037518UL, 2534579861UL, 2966280971UL, 3863833471UL, 3228893189UL, 3123894696UL, 362579125UL, 1232030882UL, +575379775UL, 1019196436UL, 1914161190UL, 3649246842UL, 2192095564UL, 2368224476UL, 138396720UL, 1299868479UL, 507152626UL, 2129033575UL, 3801624222UL, 623352301UL, 1551535796UL, 3848329776UL, 2727905150UL, 1109499603UL, 3222756581UL, 3914846131UL, 3207366497UL, 3216028717UL, 3712661572UL, 1970542UL, 1320230637UL, 2583706801UL, 1341029904UL, 1903168049UL, 1244252579UL, 1885511879UL, 2426625042UL, 3082846847UL, 3858784104UL, 2263210027UL, +130350645UL, 956540733UL, 776729371UL, 2266749094UL, 2220603773UL, 2556170531UL, 263980324UL, 802194348UL, 697108594UL, 3634984969UL, 4251738712UL, 1831444758UL, 1209156358UL, 3089957258UL, 4195548426UL, 3641578987UL, 990686800UL, 2391278490UL, 2233755358UL, 1739784005UL, 2458544650UL, 340925249UL, 2442887806UL, 3503407512UL, 3058778909UL, 3619026333UL, 2289286518UL, 1296212011UL, 3879317178UL, 1210295163UL, 3113210467UL, 1578990986UL, +641384071UL, 2437977832UL, 1689385197UL, 1323268226UL, 861337916UL, 3532905860UL, 3735971843UL, 2294673483UL, 1032787575UL, 1868992735UL, 4260308791UL, 2091311463UL, 2354047234UL, 1005300697UL, 29821726UL, 2790044161UL, 3154591207UL, 1370229266UL, 3464848205UL, 3855301526UL, 544374401UL, 101012897UL, 4214903025UL, 1310520049UL, 14884434UL, 1438288148UL, 2118574986UL, 2360002070UL, 512167778UL, 4186534704UL, 3633828199UL, 493600836UL, +}, +{ +2932801042UL, 4101748508UL, 3363559072UL, 1213475638UL, 2400369070UL, 1726749444UL, 3175844814UL, 2600020277UL, 3779799804UL, 1886667522UL, 1228105891UL, 589138388UL, 3960459504UL, 450669757UL, 3773736740UL, 2107201112UL, 1437834675UL, 3618095315UL, 3662453347UL, 968349971UL, 1891706458UL, 2333451375UL, 4242907074UL, 3265111057UL, 3648168902UL, 4137035018UL, 105573058UL, 2075999861UL, 1053920954UL, 3768713177UL, 1836088599UL, 2015103258UL, +2649187541UL, 2717894301UL, 534937136UL, 3492326400UL, 2406499346UL, 617315838UL, 1384748442UL, 519804615UL, 524657043UL, 832148261UL, 156272480UL, 394759604UL, 2428809631UL, 3401589884UL, 2588359262UL, 3826333418UL, 2427993050UL, 3254067543UL, 2570694144UL, 2876613091UL, 2883884893UL, 613070434UL, 1599903665UL, 3476967713UL, 1729385632UL, 207879231UL, 1256308247UL, 2538975486UL, 2550001448UL, 1820975095UL, 915640692UL, 1633749116UL, +1294669585UL, 3257901643UL, 3193347552UL, 3369630539UL, 285165240UL, 2337727802UL, 1854640523UL, 1034379307UL, 1206304638UL, 889104297UL, 3084078942UL, 3485609519UL, 3903898589UL, 4274630316UL, 3290195566UL, 2071163950UL, 775170461UL, 551343738UL, 164916146UL, 1678786363UL, 123960948UL, 2721608023UL, 3463122611UL, 1525791510UL, 1531697627UL, 1457848578UL, 665433501UL, 1784274031UL, 3436850186UL, 3976095421UL, 383031580UL, 2146948399UL, +3137780800UL, 410458873UL, 381977170UL, 4264728702UL, 1515223147UL, 3358033956UL, 139804933UL, 438534588UL, 901342240UL, 1536972976UL, 184570377UL, 681864510UL, 844333847UL, 2515362910UL, 917461167UL, 2538721219UL, 4268394152UL, 680292330UL, 3420438710UL, 3784725677UL, 1983802086UL, 4165891809UL, 2369490764UL, 3808530114UL, 3391499460UL, 2509287180UL, 970129219UL, 2492785859UL, 3611863290UL, 1303524794UL, 2991964551UL, 1828774928UL, +3950385781UL, 3251583775UL, 14901408UL, 1890180396UL, 1306701779UL, 3161784071UL, 637842485UL, 2830070006UL, 3867491336UL, 1594948357UL, 2579795132UL, 479188700UL, 806498245UL, 3905876458UL, 3499065005UL, 3168076042UL, 769094339UL, 3769363696UL, 1241457026UL, 1073618847UL, 251335726UL, 2574341631UL, 2534047421UL, 3151952274UL, 534046859UL, 3264754113UL, 1325368288UL, 2131927230UL, 3229420672UL, 336348290UL, 3768781638UL, 2593952436UL, +849969290UL, 2932801042UL, 4101748508UL, 3363559072UL, 1213475638UL, 1710895496UL, 1726749444UL, 3175844814UL, 2600020277UL, 3779799804UL, 4044580435UL, 1228105891UL, 589138388UL, 3960459504UL, 450669757UL, 4253882965UL, 2107201112UL, 1437834675UL, 3618095315UL, 3662453347UL, 3625360228UL, 1891706458UL, 2333451375UL, 4242907074UL, 3265111057UL, 3638586625UL, 4137035018UL, 105573058UL, 2075999861UL, 1053920954UL, 3014895241UL, 1836088599UL, +2015103258UL, 2649187541UL, 2717894301UL, 701652515UL, 3492326400UL, 2406499346UL, 617315838UL, 1384748442UL, 1142040801UL, 524657043UL, 832148261UL, 156272480UL, 394759604UL, 944890908UL, 3401589884UL, 2588359262UL, 3826333418UL, 2427993050UL, 337891051UL, 2570694144UL, 2876613091UL, 2883884893UL, 613070434UL, 659063916UL, 3476967713UL, 1729385632UL, 207879231UL, 1256308247UL, 311608860UL, 2550001448UL, 1820975095UL, 915640692UL, +1633749116UL, 1772334285UL, 3257901643UL, 3193347552UL, 3369630539UL, 285165240UL, 2627441892UL, 1854640523UL, 1034379307UL, 1206304638UL, 889104297UL, 2289660031UL, 3485609519UL, 3903898589UL, 4274630316UL, 3290195566UL, 3572160580UL, 775170461UL, 551343738UL, 164916146UL, 1678786363UL, 3109616684UL, 2721608023UL, 3463122611UL, 1525791510UL, 1531697627UL, 3660976089UL, 665433501UL, 1784274031UL, 3436850186UL, 3976095421UL, 1696775162UL, +2146948399UL, 3137780800UL, 410458873UL, 381977170UL, 1669455215UL, 1515223147UL, 3358033956UL, 139804933UL, 438534588UL, 1738237971UL, 1536972976UL, 184570377UL, 681864510UL, 844333847UL, 770765754UL, 917461167UL, 2538721219UL, 4268394152UL, 680292330UL, 1993152157UL, 3784725677UL, 1983802086UL, 4165891809UL, 2369490764UL, 3411542022UL, 3391499460UL, 2509287180UL, 970129219UL, 2492785859UL, 1869391890UL, 1303524794UL, 2991964551UL, +1828774928UL, 3950385781UL, 4139486157UL, 14901408UL, 1890180396UL, 1306701779UL, 3161784071UL, 174545194UL, 2830070006UL, 3867491336UL, 1594948357UL, 2579795132UL, 4132973523UL, 806498245UL, 3905876458UL, 3499065005UL, 3168076042UL, 538076966UL, 3769363696UL, 1241457026UL, 1073618847UL, 251335726UL, 2085586137UL, 2534047421UL, 3151952274UL, 534046859UL, 3264754113UL, 643987981UL, 2131927230UL, 3229420672UL, 336348290UL, 3768781638UL, +3468816701UL, 849969290UL, 2932801042UL, 4101748508UL, 3363559072UL, 2524943673UL, 1710895496UL, 1726749444UL, 3175844814UL, 2600020277UL, 3677241699UL, 4044580435UL, 1228105891UL, 589138388UL, 3960459504UL, 3903077887UL, 4253882965UL, 2107201112UL, 1437834675UL, 3618095315UL, 2362822379UL, 3625360228UL, 1891706458UL, 2333451375UL, 4242907074UL, 2289503940UL, 3638586625UL, 4137035018UL, 105573058UL, 2075999861UL, 1299938293UL, 3014895241UL, +1836088599UL, 2015103258UL, 2649187541UL, 3727003343UL, 701652515UL, 3492326400UL, 2406499346UL, 617315838UL, 1627975589UL, 1142040801UL, 524657043UL, 832148261UL, 156272480UL, 3658645823UL, 944890908UL, 3401589884UL, 2588359262UL, 3826333418UL, 3645806126UL, 337891051UL, 2570694144UL, 2876613091UL, 2883884893UL, 2866570997UL, 659063916UL, 3476967713UL, 1729385632UL, 207879231UL, 298556768UL, 311608860UL, 2550001448UL, 1820975095UL, +915640692UL, 1014996737UL, 1772334285UL, 3257901643UL, 3193347552UL, 3369630539UL, 96395889UL, 2627441892UL, 1854640523UL, 1034379307UL, 1206304638UL, 2546521293UL, 2289660031UL, 3485609519UL, 3903898589UL, 4274630316UL, 2360048518UL, 3572160580UL, 775170461UL, 551343738UL, 164916146UL, 2068601014UL, 3109616684UL, 2721608023UL, 3463122611UL, 1525791510UL, 1228011534UL, 3660976089UL, 665433501UL, 1784274031UL, 3436850186UL, 1620580129UL, +1696775162UL, 2146948399UL, 3137780800UL, 410458873UL, 2753059283UL, 1669455215UL, 1515223147UL, 3358033956UL, 139804933UL, 2786429190UL, 1738237971UL, 1536972976UL, 184570377UL, 681864510UL, 358796749UL, 770765754UL, 917461167UL, 2538721219UL, 4268394152UL, 2355846025UL, 1993152157UL, 3784725677UL, 1983802086UL, 4165891809UL, 360259050UL, 3411542022UL, 3391499460UL, 2509287180UL, 970129219UL, 4055494275UL, 1869391890UL, 1303524794UL, +2991964551UL, 1828774928UL, 3508750618UL, 4139486157UL, 14901408UL, 1890180396UL, 1306701779UL, 3684762156UL, 174545194UL, 2830070006UL, 3867491336UL, 1594948357UL, 702781070UL, 4132973523UL, 806498245UL, 3905876458UL, 3499065005UL, 1372989388UL, 538076966UL, 3769363696UL, 1241457026UL, 1073618847UL, 3579114424UL, 2085586137UL, 2534047421UL, 3151952274UL, 534046859UL, 1882037168UL, 643987981UL, 2131927230UL, 3229420672UL, 336348290UL, +555833786UL, 3468816701UL, 849969290UL, 2932801042UL, 4101748508UL, 1095934625UL, 2524943673UL, 1710895496UL, 1726749444UL, 3175844814UL, 2287140069UL, 3677241699UL, 4044580435UL, 1228105891UL, 589138388UL, 1596938176UL, 3903077887UL, 4253882965UL, 2107201112UL, 1437834675UL, 2605388022UL, 2362822379UL, 3625360228UL, 1891706458UL, 2333451375UL, 174003035UL, 2289503940UL, 3638586625UL, 4137035018UL, 105573058UL, 697023108UL, 1299938293UL, +3014895241UL, 1836088599UL, 2015103258UL, 4128339205UL, 3727003343UL, 701652515UL, 3492326400UL, 2406499346UL, 426422678UL, 1627975589UL, 1142040801UL, 524657043UL, 832148261UL, 2461054373UL, 3658645823UL, 944890908UL, 3401589884UL, 2588359262UL, 3184255074UL, 3645806126UL, 337891051UL, 2570694144UL, 2876613091UL, 187151044UL, 2866570997UL, 659063916UL, 3476967713UL, 1729385632UL, 2811989057UL, 298556768UL, 311608860UL, 2550001448UL, +1820975095UL, 1806779934UL, 1014996737UL, 1772334285UL, 3257901643UL, 3193347552UL, 2145947779UL, 96395889UL, 2627441892UL, 1854640523UL, 1034379307UL, 2748996070UL, 2546521293UL, 2289660031UL, 3485609519UL, 3903898589UL, 452746826UL, 2360048518UL, 3572160580UL, 775170461UL, 551343738UL, 669098691UL, 2068601014UL, 3109616684UL, 2721608023UL, 3463122611UL, 22889155UL, 1228011534UL, 3660976089UL, 665433501UL, 1784274031UL, 227705324UL, +1620580129UL, 1696775162UL, 2146948399UL, 3137780800UL, 4267814323UL, 2753059283UL, 1669455215UL, 1515223147UL, 3358033956UL, 2806778033UL, 2786429190UL, 1738237971UL, 1536972976UL, 184570377UL, 3310279262UL, 358796749UL, 770765754UL, 917461167UL, 2538721219UL, 2247224091UL, 2355846025UL, 1993152157UL, 3784725677UL, 1983802086UL, 2399541755UL, 360259050UL, 3411542022UL, 3391499460UL, 2509287180UL, 2335541531UL, 4055494275UL, 1869391890UL, +1303524794UL, 2991964551UL, 392724462UL, 3508750618UL, 4139486157UL, 14901408UL, 1890180396UL, 2513331299UL, 3684762156UL, 174545194UL, 2830070006UL, 3867491336UL, 1887131931UL, 702781070UL, 4132973523UL, 806498245UL, 3905876458UL, 2263606492UL, 1372989388UL, 538076966UL, 3769363696UL, 1241457026UL, 170472774UL, 3579114424UL, 2085586137UL, 2534047421UL, 3151952274UL, 1488165272UL, 1882037168UL, 643987981UL, 2131927230UL, 3229420672UL, +1158405862UL, 1469009373UL, 4117356830UL, 4063868500UL, 2006417445UL, 2976934394UL, 2683607933UL, 3174943272UL, 2099974138UL, 2250858961UL, 205251124UL, 84783688UL, 1551294676UL, 224349432UL, 1893741756UL, 3680361724UL, 561624088UL, 251553631UL, 1654870642UL, 2195380145UL, 866503297UL, 1814519294UL, 905566144UL, 727763043UL, 1910034093UL, 1876316198UL, 3031876716UL, 2783769690UL, 2649650479UL, 2024342098UL, 2170858649UL, 2186613759UL, +2688207487UL, 881594599UL, 1010953695UL, 2768977700UL, 3341020856UL, 2446339960UL, 2648757147UL, 1317083878UL, 3301541769UL, 3574285525UL, 3331294407UL, 712581268UL, 3612116700UL, 3510601489UL, 2569879282UL, 3772968052UL, 332485239UL, 280920979UL, 716834274UL, 1863623285UL, 654670865UL, 1706917935UL, 1598315563UL, 2486805657UL, 2295746319UL, 635609792UL, 55141757UL, 4089183045UL, 145257162UL, 1921789879UL, 2833550514UL, 3798992859UL, +1532875864UL, 3668053062UL, 2749191097UL, 3412220447UL, 3383752088UL, 3191842833UL, 4167387125UL, 2438940746UL, 1453011669UL, 2747298308UL, 1057877757UL, 399006034UL, 132680506UL, 31671249UL, 1070386969UL, 2415113777UL, 3720335676UL, 3416473189UL, 1476808053UL, 785398955UL, 3335661823UL, 315496929UL, 1421907623UL, 1802371914UL, 3049258946UL, 1773374729UL, 382902076UL, 3262814446UL, 1774244917UL, 4064677234UL, 2281551331UL, 3019541390UL, +2445483046UL, 3059154103UL, 2147309319UL, 566587847UL, 216051987UL, 521013398UL, 2721884570UL, 3325443529UL, 1921922591UL, 1643064709UL, 1155714395UL, 1737031844UL, 2117338012UL, 1876262536UL, 3589621009UL, 3800806613UL, 1102108318UL, 1376914700UL, 539544394UL, 799741508UL, 1192097712UL, 2894663754UL, 567276527UL, 106814343UL, 3985577014UL, 422246623UL, 126568764UL, 4008211389UL, 4037889581UL, 2185357423UL, 2239644921UL, 2116447019UL, +1249715620UL, 2095747493UL, 4063243162UL, 3059330950UL, 1045571624UL, 1150656233UL, 3024439196UL, 3981904623UL, 1743764595UL, 4220253496UL, 3322182853UL, 2132911849UL, 2074342674UL, 198749193UL, 574306951UL, 3563262292UL, 3832626833UL, 2349475213UL, 182567249UL, 1530390173UL, 2066055611UL, 2609802571UL, 1392638962UL, 1495846580UL, 2356952332UL, 4029921749UL, 1731839848UL, 527880959UL, 1204112231UL, 938004695UL, 294300378UL, 1855457892UL, +}, +{ +1438083560UL, 1727969469UL, 703174449UL, 1296281193UL, 1386452240UL, 3304170302UL, 3048300096UL, 277697908UL, 2675939661UL, 3382564518UL, 1639425457UL, 2210719281UL, 3173605115UL, 1685375802UL, 1317820682UL, 1960916541UL, 4230888182UL, 1924357010UL, 3322827982UL, 1663716994UL, 976583570UL, 4146230815UL, 525755678UL, 3608894680UL, 1715438458UL, 1519478303UL, 2845291872UL, 1115405802UL, 2468673244UL, 2289739992UL, 46988928UL, 2559411080UL, +2466723374UL, 2995303634UL, 3871022237UL, 1794652692UL, 2424766096UL, 2849910020UL, 978542234UL, 1667051478UL, 3393290740UL, 1508376445UL, 4090541488UL, 1314139749UL, 1271060027UL, 3272019878UL, 4032394060UL, 757805987UL, 619143288UL, 1165760536UL, 225099797UL, 871754591UL, 2065691940UL, 2016593817UL, 1705071529UL, 2559080067UL, 2048856253UL, 3217759224UL, 2691334730UL, 1576829868UL, 3356759591UL, 1570481357UL, 1097065360UL, 852561431UL, +3559721965UL, 1403648739UL, 1772347635UL, 1196457607UL, 462142253UL, 761176322UL, 2209893444UL, 217724244UL, 3356132814UL, 2838131962UL, 3571552868UL, 1197135963UL, 3239010986UL, 2612283238UL, 2606429155UL, 2194090162UL, 4256137634UL, 935551404UL, 3057660021UL, 866672836UL, 1119670384UL, 1757615349UL, 649402076UL, 2814108193UL, 3312658713UL, 2627947214UL, 2982267121UL, 486762785UL, 2746076238UL, 2134737126UL, 4106010468UL, 3151832629UL, +2419694200UL, 2803791741UL, 2100250718UL, 3171079849UL, 1874606681UL, 1884940331UL, 926257211UL, 1940082331UL, 1024435222UL, 609478334UL, 2501896844UL, 518643063UL, 4285619138UL, 1054300997UL, 4024681853UL, 2287236199UL, 2891891855UL, 1519666047UL, 1919500932UL, 3880316442UL, 1994336737UL, 1025147784UL, 3433493260UL, 1647319600UL, 3298872174UL, 3744513628UL, 2918990402UL, 2649193481UL, 234630674UL, 1963357481UL, 1118148435UL, 2658522312UL, +2563194501UL, 2238556876UL, 1210050812UL, 748709882UL, 3894824022UL, 2575692519UL, 436044710UL, 3465014792UL, 3686094502UL, 2963529475UL, 3251316066UL, 2834750227UL, 789471563UL, 853201732UL, 4119014483UL, 1312738151UL, 2018934495UL, 542908921UL, 732294449UL, 2519981401UL, 1663929229UL, 4041419972UL, 3038382188UL, 3182489020UL, 353453260UL, 4074472601UL, 1187952022UL, 2118553383UL, 1068338764UL, 3699144039UL, 3129056770UL, 1419222328UL, +2666827910UL, 1438083560UL, 1727969469UL, 703174449UL, 1296281193UL, 2134413940UL, 3304170302UL, 3048300096UL, 277697908UL, 2675939661UL, 3817858752UL, 1639425457UL, 2210719281UL, 3173605115UL, 1685375802UL, 2587083472UL, 1960916541UL, 4230888182UL, 1924357010UL, 3322827982UL, 2582901426UL, 976583570UL, 4146230815UL, 525755678UL, 3608894680UL, 524232549UL, 1519478303UL, 2845291872UL, 1115405802UL, 2468673244UL, 591800699UL, 46988928UL, +2559411080UL, 2466723374UL, 2995303634UL, 2307625850UL, 1794652692UL, 2424766096UL, 2849910020UL, 978542234UL, 1284927074UL, 3393290740UL, 1508376445UL, 4090541488UL, 1314139749UL, 3508281898UL, 3272019878UL, 4032394060UL, 757805987UL, 619143288UL, 1846615167UL, 225099797UL, 871754591UL, 2065691940UL, 2016593817UL, 1193455869UL, 2559080067UL, 2048856253UL, 3217759224UL, 2691334730UL, 2665708717UL, 3356759591UL, 1570481357UL, 1097065360UL, +852561431UL, 1652864273UL, 1403648739UL, 1772347635UL, 1196457607UL, 462142253UL, 1222855287UL, 2209893444UL, 217724244UL, 3356132814UL, 2838131962UL, 3060983219UL, 1197135963UL, 3239010986UL, 2612283238UL, 2606429155UL, 4171729370UL, 4256137634UL, 935551404UL, 3057660021UL, 866672836UL, 75618353UL, 1757615349UL, 649402076UL, 2814108193UL, 3312658713UL, 3975515213UL, 2982267121UL, 486762785UL, 2746076238UL, 2134737126UL, 3251020123UL, +3151832629UL, 2419694200UL, 2803791741UL, 2100250718UL, 624531676UL, 1874606681UL, 1884940331UL, 926257211UL, 1940082331UL, 3678479182UL, 609478334UL, 2501896844UL, 518643063UL, 4285619138UL, 1725899979UL, 4024681853UL, 2287236199UL, 2891891855UL, 1519666047UL, 702508101UL, 3880316442UL, 1994336737UL, 1025147784UL, 3433493260UL, 4212959134UL, 3298872174UL, 3744513628UL, 2918990402UL, 2649193481UL, 1782150764UL, 1963357481UL, 1118148435UL, +2658522312UL, 2563194501UL, 3330122355UL, 1210050812UL, 748709882UL, 3894824022UL, 2575692519UL, 637240921UL, 3465014792UL, 3686094502UL, 2963529475UL, 3251316066UL, 1510158901UL, 789471563UL, 853201732UL, 4119014483UL, 1312738151UL, 3018953017UL, 542908921UL, 732294449UL, 2519981401UL, 1663929229UL, 2696317636UL, 3038382188UL, 3182489020UL, 353453260UL, 4074472601UL, 4249950407UL, 2118553383UL, 1068338764UL, 3699144039UL, 3129056770UL, +2334590922UL, 2666827910UL, 1438083560UL, 1727969469UL, 703174449UL, 1679528518UL, 2134413940UL, 3304170302UL, 3048300096UL, 277697908UL, 3417107827UL, 3817858752UL, 1639425457UL, 2210719281UL, 3173605115UL, 1858788112UL, 2587083472UL, 1960916541UL, 4230888182UL, 1924357010UL, 3692988029UL, 2582901426UL, 976583570UL, 4146230815UL, 525755678UL, 1122319464UL, 524232549UL, 1519478303UL, 2845291872UL, 1115405802UL, 205855120UL, 591800699UL, +46988928UL, 2559411080UL, 2466723374UL, 3358512221UL, 2307625850UL, 1794652692UL, 2424766096UL, 2849910020UL, 2865273283UL, 1284927074UL, 3393290740UL, 1508376445UL, 4090541488UL, 2453941323UL, 3508281898UL, 3272019878UL, 4032394060UL, 757805987UL, 3191753865UL, 1846615167UL, 225099797UL, 871754591UL, 2065691940UL, 1301630578UL, 1193455869UL, 2559080067UL, 2048856253UL, 3217759224UL, 3858428004UL, 2665708717UL, 3356759591UL, 1570481357UL, +1097065360UL, 3550687085UL, 1652864273UL, 1403648739UL, 1772347635UL, 1196457607UL, 2158802672UL, 1222855287UL, 2209893444UL, 217724244UL, 3356132814UL, 1954043011UL, 3060983219UL, 1197135963UL, 3239010986UL, 2612283238UL, 2156334822UL, 4171729370UL, 4256137634UL, 935551404UL, 3057660021UL, 3331206175UL, 75618353UL, 1757615349UL, 649402076UL, 2814108193UL, 1313890357UL, 3975515213UL, 2982267121UL, 486762785UL, 2746076238UL, 2023213803UL, +3251020123UL, 3151832629UL, 2419694200UL, 2803791741UL, 392313450UL, 624531676UL, 1874606681UL, 1884940331UL, 926257211UL, 3369012310UL, 3678479182UL, 609478334UL, 2501896844UL, 518643063UL, 3638013610UL, 1725899979UL, 4024681853UL, 2287236199UL, 2891891855UL, 429282096UL, 702508101UL, 3880316442UL, 1994336737UL, 1025147784UL, 1217486411UL, 4212959134UL, 3298872174UL, 3744513628UL, 2918990402UL, 1279832521UL, 1782150764UL, 1963357481UL, +1118148435UL, 2658522312UL, 2379123622UL, 3330122355UL, 1210050812UL, 748709882UL, 3894824022UL, 3987054169UL, 637240921UL, 3465014792UL, 3686094502UL, 2963529475UL, 2167876400UL, 1510158901UL, 789471563UL, 853201732UL, 4119014483UL, 1746447311UL, 3018953017UL, 542908921UL, 732294449UL, 2519981401UL, 1908715414UL, 2696317636UL, 3038382188UL, 3182489020UL, 353453260UL, 2132930364UL, 4249950407UL, 2118553383UL, 1068338764UL, 3699144039UL, +433893434UL, 2334590922UL, 2666827910UL, 1438083560UL, 1727969469UL, 1154725669UL, 1679528518UL, 2134413940UL, 3304170302UL, 3048300096UL, 31944135UL, 3417107827UL, 3817858752UL, 1639425457UL, 2210719281UL, 4203237786UL, 1858788112UL, 2587083472UL, 1960916541UL, 4230888182UL, 2712081548UL, 3692988029UL, 2582901426UL, 976583570UL, 4146230815UL, 3948659885UL, 1122319464UL, 524232549UL, 1519478303UL, 2845291872UL, 2881616509UL, 205855120UL, +591800699UL, 46988928UL, 2559411080UL, 3645011109UL, 3358512221UL, 2307625850UL, 1794652692UL, 2424766096UL, 3667888476UL, 2865273283UL, 1284927074UL, 3393290740UL, 1508376445UL, 1605429636UL, 2453941323UL, 3508281898UL, 3272019878UL, 4032394060UL, 3904681057UL, 3191753865UL, 1846615167UL, 225099797UL, 871754591UL, 696516502UL, 1301630578UL, 1193455869UL, 2559080067UL, 2048856253UL, 2589248412UL, 3858428004UL, 2665708717UL, 3356759591UL, +1570481357UL, 1884333722UL, 3550687085UL, 1652864273UL, 1403648739UL, 1772347635UL, 3418430008UL, 2158802672UL, 1222855287UL, 2209893444UL, 217724244UL, 4164333189UL, 1954043011UL, 3060983219UL, 1197135963UL, 3239010986UL, 2300947859UL, 2156334822UL, 4171729370UL, 4256137634UL, 935551404UL, 1258856668UL, 3331206175UL, 75618353UL, 1757615349UL, 649402076UL, 772455867UL, 1313890357UL, 3975515213UL, 2982267121UL, 486762785UL, 3671941628UL, +2023213803UL, 3251020123UL, 3151832629UL, 2419694200UL, 4264015999UL, 392313450UL, 624531676UL, 1874606681UL, 1884940331UL, 2460787316UL, 3369012310UL, 3678479182UL, 609478334UL, 2501896844UL, 2131090271UL, 3638013610UL, 1725899979UL, 4024681853UL, 2287236199UL, 455349830UL, 429282096UL, 702508101UL, 3880316442UL, 1994336737UL, 1727894434UL, 1217486411UL, 4212959134UL, 3298872174UL, 3744513628UL, 1120563681UL, 1279832521UL, 1782150764UL, +1963357481UL, 1118148435UL, 3362151087UL, 2379123622UL, 3330122355UL, 1210050812UL, 748709882UL, 2506587900UL, 3987054169UL, 637240921UL, 3465014792UL, 3686094502UL, 1265652315UL, 2167876400UL, 1510158901UL, 789471563UL, 853201732UL, 3472479264UL, 1746447311UL, 3018953017UL, 542908921UL, 732294449UL, 659090240UL, 1908715414UL, 2696317636UL, 3038382188UL, 3182489020UL, 174113867UL, 2132930364UL, 4249950407UL, 2118553383UL, 1068338764UL, +4115132848UL, 1714842877UL, 1153237667UL, 1015943026UL, 2014412384UL, 2478393613UL, 1340079052UL, 167685322UL, 1848482402UL, 3252973254UL, 638064461UL, 1599254200UL, 2525050247UL, 2813349060UL, 2415037971UL, 3274852801UL, 3415369586UL, 3216396500UL, 3147792606UL, 438338168UL, 2326605175UL, 2846648724UL, 3871841623UL, 287840506UL, 3218295001UL, 2562000356UL, 574276928UL, 418096348UL, 1798854554UL, 1913561074UL, 2025706546UL, 41907788UL, +3535708035UL, 1240819558UL, 208810147UL, 4062740265UL, 451865782UL, 2652508890UL, 3579720859UL, 1243967909UL, 2191937647UL, 2473947838UL, 1847359263UL, 2496539569UL, 4061942257UL, 1372849161UL, 2016697844UL, 1827460131UL, 1135062647UL, 1255573479UL, 3506657283UL, 3699699807UL, 3087913374UL, 1196140869UL, 4095306490UL, 830793530UL, 1289366065UL, 3268392251UL, 4119035690UL, 1631012325UL, 3410799501UL, 1470209122UL, 3057922764UL, 2895379380UL, +2654121201UL, 1984999545UL, 2258412956UL, 4267137150UL, 3396740662UL, 2480013857UL, 3845856317UL, 3669454152UL, 2438423716UL, 3191341994UL, 1571280634UL, 1423782557UL, 3279999352UL, 1886288620UL, 205278284UL, 793062897UL, 112852083UL, 69164746UL, 2218046933UL, 4206182754UL, 3021072495UL, 2157753215UL, 2875773583UL, 1453706073UL, 168681204UL, 3905840714UL, 4098714445UL, 3410804508UL, 1737239929UL, 1613207828UL, 2987997090UL, 1869303136UL, +3348561687UL, 3391148819UL, 1680062950UL, 4150476788UL, 2340622122UL, 11331065UL, 2250669421UL, 3003852975UL, 2145739501UL, 1627177260UL, 994260425UL, 1479134620UL, 2315299915UL, 1268765340UL, 285960682UL, 3801150032UL, 3948820512UL, 1677682247UL, 1735541155UL, 1914753931UL, 1965156079UL, 1875233710UL, 681418791UL, 2077804400UL, 1963479724UL, 2447942398UL, 269798686UL, 2740088859UL, 1974178779UL, 3373487761UL, 2879779843UL, 157827737UL, +3855390825UL, 2779173093UL, 2359181541UL, 3508102362UL, 4001266348UL, 3949912729UL, 3232414439UL, 472195874UL, 57835121UL, 1854343116UL, 3020785997UL, 2024437594UL, 2182964208UL, 3379376555UL, 1213864603UL, 307833006UL, 1029130725UL, 545051507UL, 4001695571UL, 2258480284UL, 896286117UL, 355474524UL, 2514583184UL, 2997458384UL, 3278715462UL, 1675341954UL, 3603020014UL, 2318410671UL, 2152785892UL, 4285597912UL, 35655711UL, 2087100216UL, +}, +{ +1671155UL, 472949658UL, 148656515UL, 1640075411UL, 930771231UL, 1601854390UL, 471598090UL, 2013359012UL, 3708325970UL, 1688441844UL, 736452516UL, 100585026UL, 1154373750UL, 4029833741UL, 3409420465UL, 192349301UL, 3804215437UL, 909027311UL, 2896874106UL, 3567276364UL, 1319305666UL, 3858990362UL, 3155018279UL, 3756192170UL, 3567813642UL, 228734829UL, 577956164UL, 2078807284UL, 1005987081UL, 1464380935UL, 112604551UL, 3865074232UL, +3776350052UL, 1112767766UL, 2947509331UL, 910887552UL, 4127297396UL, 851240323UL, 3136588838UL, 1639013085UL, 1154068086UL, 639126620UL, 2501600773UL, 3174842042UL, 3456593672UL, 80596481UL, 126970446UL, 2184239961UL, 1448001095UL, 689252599UL, 1087028487UL, 2905348107UL, 2502009404UL, 2156595397UL, 2149975474UL, 2201723284UL, 3908202640UL, 754508313UL, 2321393187UL, 787043244UL, 2575809693UL, 4172462501UL, 2322897687UL, 1899992264UL, +1854136781UL, 3575249683UL, 2939319477UL, 901605762UL, 676398674UL, 2849283587UL, 2992300101UL, 1513271778UL, 2797164148UL, 1914019034UL, 1889341710UL, 2739211008UL, 1954453463UL, 3279391005UL, 2899313529UL, 1412533980UL, 1291505093UL, 2884603001UL, 564097935UL, 3552741248UL, 2809901827UL, 1263126330UL, 860214490UL, 2168366043UL, 2681035029UL, 3226888214UL, 2902522885UL, 554804421UL, 1571065517UL, 3322453053UL, 4144256215UL, 126415290UL, +980853251UL, 1531963815UL, 3237470129UL, 1465444883UL, 2031491001UL, 2205009469UL, 1046577915UL, 828927962UL, 2170245718UL, 1090142292UL, 1667375106UL, 2522840205UL, 4047872402UL, 3862734726UL, 91588630UL, 3122782857UL, 929883614UL, 694999008UL, 1472139068UL, 1246663706UL, 3500613893UL, 4200173807UL, 186199942UL, 3890621040UL, 229752655UL, 1011692880UL, 2791828564UL, 2677625011UL, 791005643UL, 1754509337UL, 2321492983UL, 3512328605UL, +1294405891UL, 2845189858UL, 434175992UL, 3155484007UL, 2306406482UL, 3197931140UL, 22971924UL, 1521633702UL, 2366802562UL, 399245037UL, 2833224222UL, 2507478835UL, 3231711673UL, 3784114896UL, 1927919696UL, 783802899UL, 3408133710UL, 2278711709UL, 3001078924UL, 1223320630UL, 3246830042UL, 943189685UL, 4062534962UL, 1039971013UL, 2342241593UL, 3551623946UL, 322017346UL, 3585779636UL, 81127429UL, 3549929990UL, 2886997195UL, 1746081951UL, +4169018554UL, 1671155UL, 472949658UL, 148656515UL, 1640075411UL, 3772042754UL, 1601854390UL, 471598090UL, 2013359012UL, 3708325970UL, 321630853UL, 736452516UL, 100585026UL, 1154373750UL, 4029833741UL, 1926754199UL, 192349301UL, 3804215437UL, 909027311UL, 2896874106UL, 1138131968UL, 1319305666UL, 3858990362UL, 3155018279UL, 3756192170UL, 2489094664UL, 228734829UL, 577956164UL, 2078807284UL, 1005987081UL, 2678967510UL, 112604551UL, +3865074232UL, 3776350052UL, 1112767766UL, 626049886UL, 910887552UL, 4127297396UL, 851240323UL, 3136588838UL, 2142891352UL, 1154068086UL, 639126620UL, 2501600773UL, 3174842042UL, 3342870442UL, 80596481UL, 126970446UL, 2184239961UL, 1448001095UL, 3399719246UL, 1087028487UL, 2905348107UL, 2502009404UL, 2156595397UL, 14860817UL, 2201723284UL, 3908202640UL, 754508313UL, 2321393187UL, 90540547UL, 2575809693UL, 4172462501UL, 2322897687UL, +1899992264UL, 56239065UL, 3575249683UL, 2939319477UL, 901605762UL, 676398674UL, 412461711UL, 2992300101UL, 1513271778UL, 2797164148UL, 1914019034UL, 3660190396UL, 2739211008UL, 1954453463UL, 3279391005UL, 2899313529UL, 4193503742UL, 1291505093UL, 2884603001UL, 564097935UL, 3552741248UL, 2124229268UL, 1263126330UL, 860214490UL, 2168366043UL, 2681035029UL, 4086980935UL, 2902522885UL, 554804421UL, 1571065517UL, 3322453053UL, 1821678887UL, +126415290UL, 980853251UL, 1531963815UL, 3237470129UL, 2099629264UL, 2031491001UL, 2205009469UL, 1046577915UL, 828927962UL, 3447807375UL, 1090142292UL, 1667375106UL, 2522840205UL, 4047872402UL, 2255362927UL, 91588630UL, 3122782857UL, 929883614UL, 694999008UL, 4135967848UL, 1246663706UL, 3500613893UL, 4200173807UL, 186199942UL, 4182379872UL, 229752655UL, 1011692880UL, 2791828564UL, 2677625011UL, 397062412UL, 1754509337UL, 2321492983UL, +3512328605UL, 1294405891UL, 1028843071UL, 434175992UL, 3155484007UL, 2306406482UL, 3197931140UL, 3217107401UL, 1521633702UL, 2366802562UL, 399245037UL, 2833224222UL, 76017436UL, 3231711673UL, 3784114896UL, 1927919696UL, 783802899UL, 2157090897UL, 2278711709UL, 3001078924UL, 1223320630UL, 3246830042UL, 1197195551UL, 4062534962UL, 1039971013UL, 2342241593UL, 3551623946UL, 63853850UL, 3585779636UL, 81127429UL, 3549929990UL, 2886997195UL, +1335910186UL, 4169018554UL, 1671155UL, 472949658UL, 148656515UL, 3600963048UL, 3772042754UL, 1601854390UL, 471598090UL, 2013359012UL, 1181513377UL, 321630853UL, 736452516UL, 100585026UL, 1154373750UL, 2323956092UL, 1926754199UL, 192349301UL, 3804215437UL, 909027311UL, 2993842723UL, 1138131968UL, 1319305666UL, 3858990362UL, 3155018279UL, 2288945270UL, 2489094664UL, 228734829UL, 577956164UL, 2078807284UL, 1924581773UL, 2678967510UL, +112604551UL, 3865074232UL, 3776350052UL, 2127459222UL, 626049886UL, 910887552UL, 4127297396UL, 851240323UL, 547797457UL, 2142891352UL, 1154068086UL, 639126620UL, 2501600773UL, 2391654498UL, 3342870442UL, 80596481UL, 126970446UL, 2184239961UL, 824575673UL, 3399719246UL, 1087028487UL, 2905348107UL, 2502009404UL, 740197255UL, 14860817UL, 2201723284UL, 3908202640UL, 754508313UL, 4133980283UL, 90540547UL, 2575809693UL, 4172462501UL, +2322897687UL, 831222037UL, 56239065UL, 3575249683UL, 2939319477UL, 901605762UL, 1998632674UL, 412461711UL, 2992300101UL, 1513271778UL, 2797164148UL, 969149327UL, 3660190396UL, 2739211008UL, 1954453463UL, 3279391005UL, 1267183547UL, 4193503742UL, 1291505093UL, 2884603001UL, 564097935UL, 3378471970UL, 2124229268UL, 1263126330UL, 860214490UL, 2168366043UL, 867190357UL, 4086980935UL, 2902522885UL, 554804421UL, 1571065517UL, 497580674UL, +1821678887UL, 126415290UL, 980853251UL, 1531963815UL, 2259090956UL, 2099629264UL, 2031491001UL, 2205009469UL, 1046577915UL, 30458798UL, 3447807375UL, 1090142292UL, 1667375106UL, 2522840205UL, 748518306UL, 2255362927UL, 91588630UL, 3122782857UL, 929883614UL, 1016302700UL, 4135967848UL, 1246663706UL, 3500613893UL, 4200173807UL, 4149573092UL, 4182379872UL, 229752655UL, 1011692880UL, 2791828564UL, 2890696349UL, 397062412UL, 1754509337UL, +2321492983UL, 3512328605UL, 3005148093UL, 1028843071UL, 434175992UL, 3155484007UL, 2306406482UL, 1417194283UL, 3217107401UL, 1521633702UL, 2366802562UL, 399245037UL, 665389310UL, 76017436UL, 3231711673UL, 3784114896UL, 1927919696UL, 37004463UL, 2157090897UL, 2278711709UL, 3001078924UL, 1223320630UL, 1281902891UL, 1197195551UL, 4062534962UL, 1039971013UL, 2342241593UL, 836721481UL, 63853850UL, 3585779636UL, 81127429UL, 3549929990UL, +2541553478UL, 1335910186UL, 4169018554UL, 1671155UL, 472949658UL, 2086411677UL, 3600963048UL, 3772042754UL, 1601854390UL, 471598090UL, 3297781744UL, 1181513377UL, 321630853UL, 736452516UL, 100585026UL, 2296508711UL, 2323956092UL, 1926754199UL, 192349301UL, 3804215437UL, 314399580UL, 2993842723UL, 1138131968UL, 1319305666UL, 3858990362UL, 584746730UL, 2288945270UL, 2489094664UL, 228734829UL, 577956164UL, 3868048239UL, 1924581773UL, +2678967510UL, 112604551UL, 3865074232UL, 2091950990UL, 2127459222UL, 626049886UL, 910887552UL, 4127297396UL, 2494071916UL, 547797457UL, 2142891352UL, 1154068086UL, 639126620UL, 1159991153UL, 2391654498UL, 3342870442UL, 80596481UL, 126970446UL, 2276453681UL, 824575673UL, 3399719246UL, 1087028487UL, 2905348107UL, 874278393UL, 740197255UL, 14860817UL, 2201723284UL, 3908202640UL, 1189317351UL, 4133980283UL, 90540547UL, 2575809693UL, +4172462501UL, 746169572UL, 831222037UL, 56239065UL, 3575249683UL, 2939319477UL, 4148988439UL, 1998632674UL, 412461711UL, 2992300101UL, 1513271778UL, 1078781767UL, 969149327UL, 3660190396UL, 2739211008UL, 1954453463UL, 369522045UL, 1267183547UL, 4193503742UL, 1291505093UL, 2884603001UL, 2820350438UL, 3378471970UL, 2124229268UL, 1263126330UL, 860214490UL, 793306335UL, 867190357UL, 4086980935UL, 2902522885UL, 554804421UL, 1472297125UL, +497580674UL, 1821678887UL, 126415290UL, 980853251UL, 1628231485UL, 2259090956UL, 2099629264UL, 2031491001UL, 2205009469UL, 2562996945UL, 30458798UL, 3447807375UL, 1090142292UL, 1667375106UL, 3513508401UL, 748518306UL, 2255362927UL, 91588630UL, 3122782857UL, 435869165UL, 1016302700UL, 4135967848UL, 1246663706UL, 3500613893UL, 4156110437UL, 4149573092UL, 4182379872UL, 229752655UL, 1011692880UL, 1150278253UL, 2890696349UL, 397062412UL, +1754509337UL, 2321492983UL, 1126835971UL, 3005148093UL, 1028843071UL, 434175992UL, 3155484007UL, 4169948411UL, 1417194283UL, 3217107401UL, 1521633702UL, 2366802562UL, 1629830655UL, 665389310UL, 76017436UL, 3231711673UL, 3784114896UL, 2523153991UL, 37004463UL, 2157090897UL, 2278711709UL, 3001078924UL, 3770048208UL, 1281902891UL, 1197195551UL, 4062534962UL, 1039971013UL, 2710590100UL, 836721481UL, 63853850UL, 3585779636UL, 81127429UL, +3850118466UL, 1883009417UL, 1027645619UL, 2766570701UL, 529436174UL, 4182542040UL, 2027954186UL, 1551970336UL, 2476537298UL, 1601343216UL, 3847258834UL, 14764974UL, 2173280370UL, 4148127270UL, 2818930089UL, 4238274314UL, 1291010651UL, 276452076UL, 192067464UL, 4086351393UL, 37573517UL, 48008720UL, 1641547972UL, 3144774960UL, 2159884108UL, 4260412239UL, 4072883650UL, 801704944UL, 2475958420UL, 2719220408UL, 555871884UL, 3338968445UL, +1704817873UL, 1960791083UL, 3785650808UL, 948722806UL, 3591229899UL, 1776225011UL, 4086658524UL, 2675451845UL, 308053697UL, 3514232055UL, 2575301108UL, 1970226110UL, 3926325352UL, 770275431UL, 1432667716UL, 671201644UL, 1008866625UL, 1151827040UL, 11061406UL, 3492749345UL, 2398090284UL, 2479688660UL, 2275263177UL, 2452696627UL, 3239880878UL, 3206200433UL, 1520851097UL, 1517432473UL, 1468198490UL, 1756343506UL, 2477348626UL, 3684701600UL, +3173720911UL, 1034531154UL, 4092116810UL, 3546516359UL, 2085136160UL, 643024588UL, 1462240654UL, 1877398196UL, 3615581878UL, 1419408410UL, 3581360976UL, 1731324772UL, 1377343320UL, 3848152825UL, 2213533588UL, 2484549569UL, 2043594863UL, 224490427UL, 1298974897UL, 4279011954UL, 3970331393UL, 3795364604UL, 285230552UL, 2893090686UL, 2399312639UL, 2638905215UL, 3481427245UL, 3477537504UL, 2609821731UL, 867675919UL, 3395750357UL, 1969593211UL, +2390932014UL, 3164333009UL, 3032345429UL, 3054196992UL, 1655295657UL, 193598641UL, 1267960637UL, 1599091894UL, 3377410805UL, 1529073346UL, 1949183620UL, 1575927573UL, 1493246650UL, 2285478895UL, 797817618UL, 1736047766UL, 1537439339UL, 1422940895UL, 2210817855UL, 2888194544UL, 800138109UL, 1689425315UL, 87966703UL, 3800446188UL, 137301285UL, 3334431104UL, 1776710491UL, 4010349050UL, 2577018472UL, 3083459223UL, 672158271UL, 3379478560UL, +2445459713UL, 918903140UL, 2577376693UL, 273150303UL, 2300393435UL, 3529750006UL, 3941920515UL, 2590879584UL, 2005940914UL, 2533952036UL, 2918638361UL, 1907638097UL, 959011520UL, 1477207871UL, 2141548481UL, 2065858781UL, 3145892196UL, 3679867589UL, 1295127682UL, 1325838381UL, 3482593404UL, 1212565985UL, 3404887017UL, 709111097UL, 1714185234UL, 561489165UL, 3545430079UL, 359778601UL, 3034684349UL, 2235482356UL, 2263913966UL, 1397371482UL, +}, +{ +170295791UL, 2753410803UL, 2200994594UL, 14686027UL, 3460333923UL, 1523230564UL, 393272614UL, 1632665034UL, 2139771608UL, 2436912103UL, 375335282UL, 667585308UL, 3651645415UL, 1403132103UL, 4146144245UL, 786890392UL, 1349234364UL, 1278024517UL, 84921263UL, 3758850381UL, 4213552796UL, 2355655048UL, 1636349912UL, 172797504UL, 2490691729UL, 1233059003UL, 2593048824UL, 942056581UL, 953415060UL, 4250104075UL, 787552244UL, 1995239637UL, +2482815609UL, 767530774UL, 773778243UL, 841396894UL, 2718419035UL, 3363828032UL, 737774143UL, 4128182656UL, 2335090807UL, 1421795969UL, 2322011430UL, 2808330380UL, 2207840656UL, 1646731611UL, 492284258UL, 2339383764UL, 3439685708UL, 2316859204UL, 4055048437UL, 1700143892UL, 2980557654UL, 1353917552UL, 548777318UL, 1077538998UL, 2650679367UL, 2853583947UL, 2721899692UL, 4253535213UL, 3375043688UL, 3489699354UL, 2401362855UL, 3391605246UL, +914273272UL, 3060460082UL, 1409014396UL, 3313834796UL, 461914731UL, 82334736UL, 3200344474UL, 2743316601UL, 842885927UL, 613943741UL, 96056919UL, 3116963503UL, 305659983UL, 132158360UL, 239064402UL, 849530381UL, 543215927UL, 4250983939UL, 2719881954UL, 1950301886UL, 2760008207UL, 853237881UL, 3875675156UL, 1753566841UL, 1446648300UL, 1663885236UL, 2155720472UL, 1902508987UL, 4246118829UL, 383661834UL, 2420221467UL, 156828838UL, +2919782856UL, 499968148UL, 2538550321UL, 65231340UL, 1589837081UL, 3654438263UL, 467304037UL, 1000159563UL, 622643461UL, 1410713407UL, 491953742UL, 1003597552UL, 1972701846UL, 1534343952UL, 1934888620UL, 4214562113UL, 4154375443UL, 3612899079UL, 2132948514UL, 2599819225UL, 2676649952UL, 3147375990UL, 533258319UL, 3323553423UL, 4203909276UL, 668602384UL, 3979162921UL, 2360530772UL, 162121513UL, 8968884UL, 3647746035UL, 2830313226UL, +1736955603UL, 78142012UL, 1643270604UL, 1571637938UL, 4065571991UL, 2071640825UL, 2715113082UL, 3826814783UL, 1067370024UL, 1810581550UL, 2354204343UL, 3798962263UL, 1664654967UL, 3740539785UL, 3746164996UL, 4280983219UL, 3313400832UL, 3305556349UL, 4226011346UL, 839676594UL, 1785445494UL, 1248107478UL, 904240268UL, 3484988721UL, 2290931247UL, 2109493967UL, 3895901626UL, 1494555863UL, 3251796061UL, 40877237UL, 2914051470UL, 2810210896UL, +1428826975UL, 170295791UL, 2753410803UL, 2200994594UL, 14686027UL, 3263438011UL, 1523230564UL, 393272614UL, 1632665034UL, 2139771608UL, 1847095655UL, 375335282UL, 667585308UL, 3651645415UL, 1403132103UL, 1888152231UL, 786890392UL, 1349234364UL, 1278024517UL, 84921263UL, 317409190UL, 4213552796UL, 2355655048UL, 1636349912UL, 172797504UL, 891435579UL, 1233059003UL, 2593048824UL, 942056581UL, 953415060UL, 1606837225UL, 787552244UL, +1995239637UL, 2482815609UL, 767530774UL, 723338833UL, 841396894UL, 2718419035UL, 3363828032UL, 737774143UL, 1043554448UL, 2335090807UL, 1421795969UL, 2322011430UL, 2808330380UL, 2754923978UL, 1646731611UL, 492284258UL, 2339383764UL, 3439685708UL, 3985616488UL, 4055048437UL, 1700143892UL, 2980557654UL, 1353917552UL, 588678041UL, 1077538998UL, 2650679367UL, 2853583947UL, 2721899692UL, 992549416UL, 3375043688UL, 3489699354UL, 2401362855UL, +3391605246UL, 2111206241UL, 3060460082UL, 1409014396UL, 3313834796UL, 461914731UL, 749987143UL, 3200344474UL, 2743316601UL, 842885927UL, 613943741UL, 1572013294UL, 3116963503UL, 305659983UL, 132158360UL, 239064402UL, 2802105766UL, 543215927UL, 4250983939UL, 2719881954UL, 1950301886UL, 1025784309UL, 853237881UL, 3875675156UL, 1753566841UL, 1446648300UL, 2265992307UL, 2155720472UL, 1902508987UL, 4246118829UL, 383661834UL, 1291267638UL, +156828838UL, 2919782856UL, 499968148UL, 2538550321UL, 2108151330UL, 1589837081UL, 3654438263UL, 467304037UL, 1000159563UL, 611554173UL, 1410713407UL, 491953742UL, 1003597552UL, 1972701846UL, 1548061756UL, 1934888620UL, 4214562113UL, 4154375443UL, 3612899079UL, 3599839935UL, 2599819225UL, 2676649952UL, 3147375990UL, 533258319UL, 4213499273UL, 4203909276UL, 668602384UL, 3979162921UL, 2360530772UL, 197252548UL, 8968884UL, 3647746035UL, +2830313226UL, 1736955603UL, 791687787UL, 1643270604UL, 1571637938UL, 4065571991UL, 2071640825UL, 2026290282UL, 3826814783UL, 1067370024UL, 1810581550UL, 2354204343UL, 2679791787UL, 1664654967UL, 3740539785UL, 3746164996UL, 4280983219UL, 1690075221UL, 3305556349UL, 4226011346UL, 839676594UL, 1785445494UL, 935893161UL, 904240268UL, 3484988721UL, 2290931247UL, 2109493967UL, 1497667362UL, 1494555863UL, 3251796061UL, 40877237UL, 2914051470UL, +1936503212UL, 1428826975UL, 170295791UL, 2753410803UL, 2200994594UL, 3416506072UL, 3263438011UL, 1523230564UL, 393272614UL, 1632665034UL, 3223475136UL, 1847095655UL, 375335282UL, 667585308UL, 3651645415UL, 1628711405UL, 1888152231UL, 786890392UL, 1349234364UL, 1278024517UL, 3955811679UL, 317409190UL, 4213552796UL, 2355655048UL, 1636349912UL, 2875036620UL, 891435579UL, 1233059003UL, 2593048824UL, 942056581UL, 2852399035UL, 1606837225UL, +787552244UL, 1995239637UL, 2482815609UL, 3849697041UL, 723338833UL, 841396894UL, 2718419035UL, 3363828032UL, 2914796626UL, 1043554448UL, 2335090807UL, 1421795969UL, 2322011430UL, 1088985845UL, 2754923978UL, 1646731611UL, 492284258UL, 2339383764UL, 2345741058UL, 3985616488UL, 4055048437UL, 1700143892UL, 2980557654UL, 3047950756UL, 588678041UL, 1077538998UL, 2650679367UL, 2853583947UL, 1902113580UL, 992549416UL, 3375043688UL, 3489699354UL, +2401362855UL, 2822431025UL, 2111206241UL, 3060460082UL, 1409014396UL, 3313834796UL, 3661696135UL, 749987143UL, 3200344474UL, 2743316601UL, 842885927UL, 3902266797UL, 1572013294UL, 3116963503UL, 305659983UL, 132158360UL, 2399116869UL, 2802105766UL, 543215927UL, 4250983939UL, 2719881954UL, 1909593430UL, 1025784309UL, 853237881UL, 3875675156UL, 1753566841UL, 315928539UL, 2265992307UL, 2155720472UL, 1902508987UL, 4246118829UL, 4054781820UL, +1291267638UL, 156828838UL, 2919782856UL, 499968148UL, 2746436642UL, 2108151330UL, 1589837081UL, 3654438263UL, 467304037UL, 2376244866UL, 611554173UL, 1410713407UL, 491953742UL, 1003597552UL, 961109680UL, 1548061756UL, 1934888620UL, 4214562113UL, 4154375443UL, 3318608531UL, 3599839935UL, 2599819225UL, 2676649952UL, 3147375990UL, 3197943734UL, 4213499273UL, 4203909276UL, 668602384UL, 3979162921UL, 4241359084UL, 197252548UL, 8968884UL, +3647746035UL, 2830313226UL, 2057817762UL, 791687787UL, 1643270604UL, 1571637938UL, 4065571991UL, 961587641UL, 2026290282UL, 3826814783UL, 1067370024UL, 1810581550UL, 1525669339UL, 2679791787UL, 1664654967UL, 3740539785UL, 3746164996UL, 3971185743UL, 1690075221UL, 3305556349UL, 4226011346UL, 839676594UL, 4017546432UL, 935893161UL, 904240268UL, 3484988721UL, 2290931247UL, 2887434676UL, 1497667362UL, 1494555863UL, 3251796061UL, 40877237UL, +675451622UL, 1936503212UL, 1428826975UL, 170295791UL, 2753410803UL, 13691728UL, 3416506072UL, 3263438011UL, 1523230564UL, 393272614UL, 2875584734UL, 3223475136UL, 1847095655UL, 375335282UL, 667585308UL, 192306502UL, 1628711405UL, 1888152231UL, 786890392UL, 1349234364UL, 511851370UL, 3955811679UL, 317409190UL, 4213552796UL, 2355655048UL, 131052067UL, 2875036620UL, 891435579UL, 1233059003UL, 2593048824UL, 2915307792UL, 2852399035UL, +1606837225UL, 787552244UL, 1995239637UL, 886016481UL, 3849697041UL, 723338833UL, 841396894UL, 2718419035UL, 1765948302UL, 2914796626UL, 1043554448UL, 2335090807UL, 1421795969UL, 4270899906UL, 1088985845UL, 2754923978UL, 1646731611UL, 492284258UL, 1723935335UL, 2345741058UL, 3985616488UL, 4055048437UL, 1700143892UL, 2254566160UL, 3047950756UL, 588678041UL, 1077538998UL, 2650679367UL, 1004539894UL, 1902113580UL, 992549416UL, 3375043688UL, +3489699354UL, 2030140735UL, 2822431025UL, 2111206241UL, 3060460082UL, 1409014396UL, 3053214877UL, 3661696135UL, 749987143UL, 3200344474UL, 2743316601UL, 398855857UL, 3902266797UL, 1572013294UL, 3116963503UL, 305659983UL, 1626072332UL, 2399116869UL, 2802105766UL, 543215927UL, 4250983939UL, 1149058742UL, 1909593430UL, 1025784309UL, 853237881UL, 3875675156UL, 2709854504UL, 315928539UL, 2265992307UL, 2155720472UL, 1902508987UL, 4065691077UL, +4054781820UL, 1291267638UL, 156828838UL, 2919782856UL, 1004764391UL, 2746436642UL, 2108151330UL, 1589837081UL, 3654438263UL, 2380382984UL, 2376244866UL, 611554173UL, 1410713407UL, 491953742UL, 3149407591UL, 961109680UL, 1548061756UL, 1934888620UL, 4214562113UL, 1555853416UL, 3318608531UL, 3599839935UL, 2599819225UL, 2676649952UL, 1902647993UL, 3197943734UL, 4213499273UL, 4203909276UL, 668602384UL, 2188341510UL, 4241359084UL, 197252548UL, +8968884UL, 3647746035UL, 629654524UL, 2057817762UL, 791687787UL, 1643270604UL, 1571637938UL, 3066487639UL, 961587641UL, 2026290282UL, 3826814783UL, 1067370024UL, 2223613942UL, 1525669339UL, 2679791787UL, 1664654967UL, 3740539785UL, 3902060288UL, 3971185743UL, 1690075221UL, 3305556349UL, 4226011346UL, 3135081672UL, 4017546432UL, 935893161UL, 904240268UL, 3484988721UL, 2448752416UL, 2887434676UL, 1497667362UL, 1494555863UL, 3251796061UL, +1037186927UL, 1608759110UL, 3873834254UL, 59242551UL, 487334743UL, 2580513180UL, 3704829028UL, 3859157573UL, 3452402004UL, 783668920UL, 2394905786UL, 3179497902UL, 2576105629UL, 1552362163UL, 2138613992UL, 224944469UL, 3876873579UL, 3402518289UL, 1709606949UL, 4255868112UL, 1249055439UL, 3395879908UL, 2957760102UL, 346905231UL, 590629983UL, 1171021480UL, 4051081465UL, 3913643946UL, 3115845768UL, 1021908139UL, 2556028362UL, 3828177651UL, +2870156105UL, 899722025UL, 661756192UL, 3775551864UL, 1288569751UL, 3751947667UL, 3064664685UL, 2559273148UL, 2660772417UL, 2448044253UL, 3054357327UL, 3434913868UL, 1444728572UL, 3010819186UL, 3010362527UL, 1709131033UL, 3425689752UL, 2849921358UL, 3518017065UL, 3845809665UL, 3245724553UL, 1008739837UL, 3274032925UL, 2567688974UL, 1981389077UL, 1108638127UL, 470206543UL, 1097339633UL, 1714430226UL, 2321268672UL, 1149373331UL, 294569671UL, +4264586290UL, 4270574127UL, 2522456947UL, 230975563UL, 131504269UL, 541738544UL, 1380704847UL, 2946408074UL, 282744860UL, 246858261UL, 2037373985UL, 1769191691UL, 2174871838UL, 2097427065UL, 492251656UL, 1252290304UL, 3616248100UL, 3213248383UL, 1847973756UL, 647347869UL, 3015847616UL, 299045987UL, 866593289UL, 2009367463UL, 2448831631UL, 337965200UL, 1210654808UL, 1694878225UL, 853507918UL, 3373825966UL, 4262812941UL, 4279525028UL, +338822858UL, 1038097567UL, 3996799911UL, 755960212UL, 149304151UL, 1599868486UL, 4021605447UL, 3040297322UL, 3891899828UL, 1711866076UL, 900840696UL, 3675688669UL, 3070862438UL, 2611308185UL, 2359948129UL, 1158552196UL, 2094484627UL, 3077606843UL, 2119537593UL, 427023787UL, 3632076073UL, 2670551310UL, 3396099733UL, 1066081183UL, 1817788918UL, 324769315UL, 656687887UL, 202117575UL, 3106428593UL, 3730407212UL, 1661316263UL, 1215084998UL, +2025391552UL, 664352483UL, 1914686594UL, 9439399UL, 2548190484UL, 3127972014UL, 4008228378UL, 2645735658UL, 2191361716UL, 2211450148UL, 1863406291UL, 1179298131UL, 241880428UL, 2330159770UL, 3490494273UL, 1337382890UL, 747522461UL, 1060348557UL, 3618051469UL, 991193538UL, 1604905367UL, 2595102954UL, 1460144089UL, 3990194961UL, 44265425UL, 896268152UL, 9333748UL, 2850675977UL, 941433385UL, 2483544989UL, 3443750079UL, 2488690792UL, +}, +{ +824297644UL, 239464654UL, 4133652405UL, 1611614045UL, 102133367UL, 1780659362UL, 114934718UL, 3793050817UL, 3286619856UL, 1323742990UL, 3487325492UL, 468742651UL, 271433491UL, 3474195023UL, 479173886UL, 3282693508UL, 978269731UL, 1826990521UL, 3664994445UL, 1943608646UL, 2356793330UL, 2228748670UL, 4238523810UL, 2467714013UL, 1732683390UL, 2345218001UL, 3371637369UL, 1073602848UL, 844797255UL, 3881048480UL, 509186599UL, 1399427071UL, +3815270778UL, 1505666412UL, 2616384981UL, 2990167853UL, 3716581225UL, 3063486812UL, 1568307898UL, 3262882991UL, 1455926070UL, 3011806226UL, 3803364927UL, 849372289UL, 2382885729UL, 3071102985UL, 3838244574UL, 3219174218UL, 847830757UL, 1414310383UL, 3679389549UL, 1558413907UL, 2211822428UL, 339810803UL, 1051648907UL, 76928699UL, 3174194320UL, 3920525151UL, 2010088097UL, 4111092791UL, 3537133983UL, 1701410561UL, 3036563175UL, 4010986440UL, +1749862952UL, 159833659UL, 3406940095UL, 1041601178UL, 4005001553UL, 1663515026UL, 1728511107UL, 1496728329UL, 2359970426UL, 530862749UL, 3797637507UL, 2550923758UL, 1450321218UL, 21682904UL, 936804838UL, 3832989199UL, 3063256293UL, 3991708711UL, 986539283UL, 3775232150UL, 2867283706UL, 747477232UL, 946349345UL, 1010022077UL, 188204104UL, 2526787171UL, 2816843760UL, 1776005940UL, 2819738500UL, 1155856699UL, 2191793692UL, 3802193350UL, +1163036922UL, 645032560UL, 3122679267UL, 3311719932UL, 3757073707UL, 2464258247UL, 1360425558UL, 387981241UL, 1714916540UL, 411019237UL, 2248466094UL, 2878213113UL, 2742600760UL, 2763650927UL, 2526526309UL, 1093836264UL, 3819986000UL, 3754388150UL, 1731831799UL, 1441137152UL, 1625850961UL, 1182084155UL, 1596226376UL, 2389499892UL, 3923360808UL, 2439159233UL, 1623373213UL, 2513747479UL, 3651587995UL, 1040867254UL, 4208484711UL, 3489019765UL, +2141904813UL, 3666280633UL, 970464748UL, 2970978888UL, 1376163015UL, 1218588624UL, 2721249823UL, 707915046UL, 4262557484UL, 3237019195UL, 744279211UL, 364567144UL, 1997174860UL, 3215512870UL, 2758022574UL, 2677818352UL, 4198422061UL, 3016017869UL, 2243997977UL, 1029293722UL, 1820056287UL, 1090825999UL, 4135403724UL, 299239527UL, 874620372UL, 2995368704UL, 3219627293UL, 2431393692UL, 3470601754UL, 1809177571UL, 37446335UL, 1619184385UL, +675901368UL, 824297644UL, 239464654UL, 4133652405UL, 1611614045UL, 1918718045UL, 1780659362UL, 114934718UL, 3793050817UL, 3286619856UL, 3566342809UL, 3487325492UL, 468742651UL, 271433491UL, 3474195023UL, 77797025UL, 3282693508UL, 978269731UL, 1826990521UL, 3664994445UL, 1455182612UL, 2356793330UL, 2228748670UL, 4238523810UL, 2467714013UL, 1081984526UL, 2345218001UL, 3371637369UL, 1073602848UL, 844797255UL, 4125413817UL, 509186599UL, +1399427071UL, 3815270778UL, 1505666412UL, 891823593UL, 2990167853UL, 3716581225UL, 3063486812UL, 1568307898UL, 1753181930UL, 1455926070UL, 3011806226UL, 3803364927UL, 849372289UL, 4211525266UL, 3071102985UL, 3838244574UL, 3219174218UL, 847830757UL, 774013898UL, 3679389549UL, 1558413907UL, 2211822428UL, 339810803UL, 2282783575UL, 76928699UL, 3174194320UL, 3920525151UL, 2010088097UL, 3894905215UL, 3537133983UL, 1701410561UL, 3036563175UL, +4010986440UL, 676262036UL, 159833659UL, 3406940095UL, 1041601178UL, 4005001553UL, 3470687799UL, 1728511107UL, 1496728329UL, 2359970426UL, 530862749UL, 3081565689UL, 2550923758UL, 1450321218UL, 21682904UL, 936804838UL, 951873872UL, 3063256293UL, 3991708711UL, 986539283UL, 3775232150UL, 487381835UL, 747477232UL, 946349345UL, 1010022077UL, 188204104UL, 2898848241UL, 2816843760UL, 1776005940UL, 2819738500UL, 1155856699UL, 2432683643UL, +3802193350UL, 1163036922UL, 645032560UL, 3122679267UL, 22749078UL, 3757073707UL, 2464258247UL, 1360425558UL, 387981241UL, 3652130062UL, 411019237UL, 2248466094UL, 2878213113UL, 2742600760UL, 811608089UL, 2526526309UL, 1093836264UL, 3819986000UL, 3754388150UL, 415809552UL, 1441137152UL, 1625850961UL, 1182084155UL, 1596226376UL, 202609936UL, 3923360808UL, 2439159233UL, 1623373213UL, 2513747479UL, 4149563237UL, 1040867254UL, 4208484711UL, +3489019765UL, 2141904813UL, 718806958UL, 970464748UL, 2970978888UL, 1376163015UL, 1218588624UL, 2307367700UL, 707915046UL, 4262557484UL, 3237019195UL, 744279211UL, 1876395939UL, 1997174860UL, 3215512870UL, 2758022574UL, 2677818352UL, 2276158677UL, 3016017869UL, 2243997977UL, 1029293722UL, 1820056287UL, 3605618012UL, 4135403724UL, 299239527UL, 874620372UL, 2995368704UL, 872126519UL, 2431393692UL, 3470601754UL, 1809177571UL, 37446335UL, +2365355125UL, 675901368UL, 824297644UL, 239464654UL, 4133652405UL, 8139161UL, 1918718045UL, 1780659362UL, 114934718UL, 3793050817UL, 2424418256UL, 3566342809UL, 3487325492UL, 468742651UL, 271433491UL, 542129690UL, 77797025UL, 3282693508UL, 978269731UL, 1826990521UL, 2963435579UL, 1455182612UL, 2356793330UL, 2228748670UL, 4238523810UL, 2373300657UL, 1081984526UL, 2345218001UL, 3371637369UL, 1073602848UL, 2948610237UL, 4125413817UL, +509186599UL, 1399427071UL, 3815270778UL, 2870251133UL, 891823593UL, 2990167853UL, 3716581225UL, 3063486812UL, 2347504584UL, 1753181930UL, 1455926070UL, 3011806226UL, 3803364927UL, 3956554065UL, 4211525266UL, 3071102985UL, 3838244574UL, 3219174218UL, 2018597841UL, 774013898UL, 3679389549UL, 1558413907UL, 2211822428UL, 56072605UL, 2282783575UL, 76928699UL, 3174194320UL, 3920525151UL, 268031035UL, 3894905215UL, 3537133983UL, 1701410561UL, +3036563175UL, 366935627UL, 676262036UL, 159833659UL, 3406940095UL, 1041601178UL, 4125224603UL, 3470687799UL, 1728511107UL, 1496728329UL, 2359970426UL, 3570997128UL, 3081565689UL, 2550923758UL, 1450321218UL, 21682904UL, 604517910UL, 951873872UL, 3063256293UL, 3991708711UL, 986539283UL, 2414780630UL, 487381835UL, 747477232UL, 946349345UL, 1010022077UL, 3820353604UL, 2898848241UL, 2816843760UL, 1776005940UL, 2819738500UL, 1192624235UL, +2432683643UL, 3802193350UL, 1163036922UL, 645032560UL, 4050277201UL, 22749078UL, 3757073707UL, 2464258247UL, 1360425558UL, 1933406988UL, 3652130062UL, 411019237UL, 2248466094UL, 2878213113UL, 37869698UL, 811608089UL, 2526526309UL, 1093836264UL, 3819986000UL, 3999750910UL, 415809552UL, 1441137152UL, 1625850961UL, 1182084155UL, 1186617400UL, 202609936UL, 3923360808UL, 2439159233UL, 1623373213UL, 4226729056UL, 4149563237UL, 1040867254UL, +4208484711UL, 3489019765UL, 3728140516UL, 718806958UL, 970464748UL, 2970978888UL, 1376163015UL, 1307011711UL, 2307367700UL, 707915046UL, 4262557484UL, 3237019195UL, 4014387080UL, 1876395939UL, 1997174860UL, 3215512870UL, 2758022574UL, 1696763772UL, 2276158677UL, 3016017869UL, 2243997977UL, 1029293722UL, 1444214949UL, 3605618012UL, 4135403724UL, 299239527UL, 874620372UL, 1524158085UL, 872126519UL, 2431393692UL, 3470601754UL, 1809177571UL, +163166369UL, 2365355125UL, 675901368UL, 824297644UL, 239464654UL, 1626558353UL, 8139161UL, 1918718045UL, 1780659362UL, 114934718UL, 1885224714UL, 2424418256UL, 3566342809UL, 3487325492UL, 468742651UL, 1101039917UL, 542129690UL, 77797025UL, 3282693508UL, 978269731UL, 3659653445UL, 2963435579UL, 1455182612UL, 2356793330UL, 2228748670UL, 539062188UL, 2373300657UL, 1081984526UL, 2345218001UL, 3371637369UL, 2825652803UL, 2948610237UL, +4125413817UL, 509186599UL, 1399427071UL, 3197034620UL, 2870251133UL, 891823593UL, 2990167853UL, 3716581225UL, 3773712182UL, 2347504584UL, 1753181930UL, 1455926070UL, 3011806226UL, 3260276773UL, 3956554065UL, 4211525266UL, 3071102985UL, 3838244574UL, 201639236UL, 2018597841UL, 774013898UL, 3679389549UL, 1558413907UL, 2830702673UL, 56072605UL, 2282783575UL, 76928699UL, 3174194320UL, 1677734845UL, 268031035UL, 3894905215UL, 3537133983UL, +1701410561UL, 4240866153UL, 366935627UL, 676262036UL, 159833659UL, 3406940095UL, 4245889153UL, 4125224603UL, 3470687799UL, 1728511107UL, 1496728329UL, 3650277906UL, 3570997128UL, 3081565689UL, 2550923758UL, 1450321218UL, 3392011930UL, 604517910UL, 951873872UL, 3063256293UL, 3991708711UL, 2876003834UL, 2414780630UL, 487381835UL, 747477232UL, 946349345UL, 982266944UL, 3820353604UL, 2898848241UL, 2816843760UL, 1776005940UL, 3677715064UL, +1192624235UL, 2432683643UL, 3802193350UL, 1163036922UL, 1226669337UL, 4050277201UL, 22749078UL, 3757073707UL, 2464258247UL, 4197532785UL, 1933406988UL, 3652130062UL, 411019237UL, 2248466094UL, 3209426720UL, 37869698UL, 811608089UL, 2526526309UL, 1093836264UL, 535856568UL, 3999750910UL, 415809552UL, 1441137152UL, 1625850961UL, 2181491119UL, 1186617400UL, 202609936UL, 3923360808UL, 2439159233UL, 1823827533UL, 4226729056UL, 4149563237UL, +1040867254UL, 4208484711UL, 1101917521UL, 3728140516UL, 718806958UL, 970464748UL, 2970978888UL, 1574663259UL, 1307011711UL, 2307367700UL, 707915046UL, 4262557484UL, 2164217930UL, 4014387080UL, 1876395939UL, 1997174860UL, 3215512870UL, 1335157953UL, 1696763772UL, 2276158677UL, 3016017869UL, 2243997977UL, 324788481UL, 1444214949UL, 3605618012UL, 4135403724UL, 299239527UL, 4190629945UL, 1524158085UL, 872126519UL, 2431393692UL, 3470601754UL, +3701018280UL, 671547257UL, 4029965023UL, 1026428282UL, 1584875796UL, 3537698406UL, 3731126476UL, 2419795330UL, 993551117UL, 2126319514UL, 3557113304UL, 1014047757UL, 1407120210UL, 1977537539UL, 1338958570UL, 3249585389UL, 3661503659UL, 4240815680UL, 1866933898UL, 3205442033UL, 4247144816UL, 1422846419UL, 3847421981UL, 1383632066UL, 3589322376UL, 1816906043UL, 1310944471UL, 3646822098UL, 799529013UL, 3350558751UL, 2552899295UL, 4281235599UL, +4069668296UL, 4123814877UL, 3289565353UL, 1512974699UL, 111908081UL, 2535556715UL, 333570815UL, 3638041929UL, 1942569446UL, 20945397UL, 3784826827UL, 200406456UL, 2640512138UL, 38390336UL, 436784052UL, 3062106345UL, 1675333627UL, 709613078UL, 3479720979UL, 2726065658UL, 4072312748UL, 797389139UL, 3492082903UL, 3792395750UL, 983473383UL, 2984788349UL, 2030282907UL, 2246686378UL, 2451087141UL, 1799640566UL, 2182694041UL, 3226819076UL, +3573153299UL, 3658670545UL, 1197013516UL, 777601408UL, 4271704548UL, 1192713934UL, 1628497069UL, 681025927UL, 4078910773UL, 619496169UL, 1534725146UL, 1881987408UL, 2283881479UL, 1090218673UL, 4169123978UL, 2352195985UL, 2640116078UL, 3869558100UL, 2859177954UL, 3329803656UL, 4048903941UL, 1636589748UL, 2095007175UL, 4169840880UL, 2953611537UL, 2413740464UL, 3029624235UL, 778662441UL, 422412779UL, 412103280UL, 1701569571UL, 564088645UL, +469973310UL, 254302146UL, 3963642101UL, 555781470UL, 2983576224UL, 1757897888UL, 1420763962UL, 2176323176UL, 916790568UL, 3057610889UL, 196828641UL, 1435167402UL, 325046353UL, 1337309066UL, 2691769282UL, 3572566918UL, 2910149226UL, 3659418019UL, 2511762503UL, 3869838339UL, 1413312151UL, 1939339596UL, 801124461UL, 760477862UL, 2416958233UL, 3439465675UL, 3561763524UL, 1760392811UL, 1582406751UL, 1203071257UL, 755811399UL, 2675585013UL, +1150664766UL, 3515765747UL, 3419135844UL, 2076543342UL, 1191918544UL, 3644819073UL, 2195875022UL, 2909071148UL, 3385707813UL, 1151273265UL, 1467337419UL, 3570589492UL, 3742049917UL, 1609858615UL, 2964509119UL, 3747960348UL, 2825858640UL, 101501715UL, 1234710482UL, 750428334UL, 2870070395UL, 416615350UL, 4054039387UL, 3807926874UL, 3035407103UL, 1644560291UL, 2490941295UL, 963796562UL, 3233132139UL, 2590859502UL, 2845243609UL, 964355909UL, +}, +{ +2882980002UL, 2211288683UL, 872766101UL, 3713771728UL, 1429983118UL, 2069599564UL, 827699420UL, 1288565883UL, 2985727214UL, 3873174741UL, 2138389854UL, 3915615927UL, 2759028650UL, 3120611541UL, 385953581UL, 189931252UL, 2044235060UL, 4214733958UL, 1899137741UL, 1973215178UL, 494148492UL, 1550568689UL, 3646957712UL, 3764784141UL, 1114556979UL, 1411407684UL, 1194906295UL, 1718808623UL, 1809627046UL, 1413570172UL, 180837718UL, 2588730975UL, +1481586714UL, 2836300053UL, 1967135375UL, 4010897189UL, 3392273121UL, 3466021198UL, 1182364160UL, 1364130321UL, 1795412556UL, 330320182UL, 1165093128UL, 2125767818UL, 904192995UL, 51833064UL, 232302906UL, 1834422179UL, 476731510UL, 3484170517UL, 2373156680UL, 2610500049UL, 1688364249UL, 463611489UL, 3759685710UL, 62038708UL, 2357334250UL, 1230002441UL, 520303451UL, 3009758047UL, 1882263827UL, 2524779298UL, 1736323157UL, 3883037541UL, +1103650182UL, 1137565179UL, 3112310886UL, 3524287283UL, 3064002681UL, 4106308847UL, 3180534967UL, 2463036338UL, 1859639515UL, 1319061987UL, 354419222UL, 4108171950UL, 601260554UL, 705389180UL, 4081137445UL, 3461353436UL, 399768111UL, 3963945521UL, 2094962544UL, 630762046UL, 369047181UL, 3495709267UL, 3525452874UL, 314919391UL, 2152657907UL, 881476500UL, 3565507827UL, 2594931381UL, 579458905UL, 1767988684UL, 2678728511UL, 3416503939UL, +4150612567UL, 1015748208UL, 2059142720UL, 2725183490UL, 2998421769UL, 1644667445UL, 4221112143UL, 456578131UL, 3881530201UL, 190710543UL, 1721255927UL, 2274887963UL, 187713135UL, 2209254952UL, 2185750138UL, 2992229399UL, 482133467UL, 2758198810UL, 15147949UL, 536333711UL, 2296185346UL, 1103433779UL, 1573407789UL, 1357843567UL, 2927153963UL, 4157295398UL, 533935893UL, 3567030810UL, 1900900411UL, 509578395UL, 3810017456UL, 2134110040UL, +3347323570UL, 3497032747UL, 201278263UL, 3933249682UL, 3849960474UL, 2509123202UL, 3445521167UL, 1355284593UL, 2444811561UL, 2751112324UL, 1116246614UL, 511213077UL, 3412599909UL, 1712118363UL, 54054007UL, 442729047UL, 3077267414UL, 1532701769UL, 181534938UL, 1278069867UL, 3847149992UL, 2305860479UL, 4146252420UL, 2047690303UL, 361856758UL, 452490341UL, 636885000UL, 1733216839UL, 3788548638UL, 1094285639UL, 1349356222UL, 2760444511UL, +976767752UL, 2882980002UL, 2211288683UL, 872766101UL, 3713771728UL, 895830110UL, 2069599564UL, 827699420UL, 1288565883UL, 2985727214UL, 3377496544UL, 2138389854UL, 3915615927UL, 2759028650UL, 3120611541UL, 3254971483UL, 189931252UL, 2044235060UL, 4214733958UL, 1899137741UL, 2095055586UL, 494148492UL, 1550568689UL, 3646957712UL, 3764784141UL, 2869825005UL, 1411407684UL, 1194906295UL, 1718808623UL, 1809627046UL, 907760376UL, 180837718UL, +2588730975UL, 1481586714UL, 2836300053UL, 639229964UL, 4010897189UL, 3392273121UL, 3466021198UL, 1182364160UL, 3006792787UL, 1795412556UL, 330320182UL, 1165093128UL, 2125767818UL, 253264555UL, 51833064UL, 232302906UL, 1834422179UL, 476731510UL, 4284481518UL, 2373156680UL, 2610500049UL, 1688364249UL, 463611489UL, 4133115610UL, 62038708UL, 2357334250UL, 1230002441UL, 520303451UL, 1497001150UL, 1882263827UL, 2524779298UL, 1736323157UL, +3883037541UL, 3541909847UL, 1137565179UL, 3112310886UL, 3524287283UL, 3064002681UL, 3193060438UL, 3180534967UL, 2463036338UL, 1859639515UL, 1319061987UL, 111871878UL, 4108171950UL, 601260554UL, 705389180UL, 4081137445UL, 742999102UL, 399768111UL, 3963945521UL, 2094962544UL, 630762046UL, 3219207950UL, 3495709267UL, 3525452874UL, 314919391UL, 2152657907UL, 720863934UL, 3565507827UL, 2594931381UL, 579458905UL, 1767988684UL, 3958525287UL, +3416503939UL, 4150612567UL, 1015748208UL, 2059142720UL, 4227838648UL, 2998421769UL, 1644667445UL, 4221112143UL, 456578131UL, 302729329UL, 190710543UL, 1721255927UL, 2274887963UL, 187713135UL, 1293706587UL, 2185750138UL, 2992229399UL, 482133467UL, 2758198810UL, 2514965671UL, 536333711UL, 2296185346UL, 1103433779UL, 1573407789UL, 2237639577UL, 2927153963UL, 4157295398UL, 533935893UL, 3567030810UL, 3793156627UL, 509578395UL, 3810017456UL, +2134110040UL, 3347323570UL, 1358364UL, 201278263UL, 3933249682UL, 3849960474UL, 2509123202UL, 628476542UL, 1355284593UL, 2444811561UL, 2751112324UL, 1116246614UL, 3421170828UL, 3412599909UL, 1712118363UL, 54054007UL, 442729047UL, 325825294UL, 1532701769UL, 181534938UL, 1278069867UL, 3847149992UL, 2785457372UL, 4146252420UL, 2047690303UL, 361856758UL, 452490341UL, 1099532083UL, 1733216839UL, 3788548638UL, 1094285639UL, 1349356222UL, +3047068265UL, 976767752UL, 2882980002UL, 2211288683UL, 872766101UL, 366378371UL, 895830110UL, 2069599564UL, 827699420UL, 1288565883UL, 962962884UL, 3377496544UL, 2138389854UL, 3915615927UL, 2759028650UL, 3742489931UL, 3254971483UL, 189931252UL, 2044235060UL, 4214733958UL, 3073407497UL, 2095055586UL, 494148492UL, 1550568689UL, 3646957712UL, 758370067UL, 2869825005UL, 1411407684UL, 1194906295UL, 1718808623UL, 636166267UL, 907760376UL, +180837718UL, 2588730975UL, 1481586714UL, 705382583UL, 639229964UL, 4010897189UL, 3392273121UL, 3466021198UL, 3815622040UL, 3006792787UL, 1795412556UL, 330320182UL, 1165093128UL, 2956382339UL, 253264555UL, 51833064UL, 232302906UL, 1834422179UL, 3665645898UL, 4284481518UL, 2373156680UL, 2610500049UL, 1688364249UL, 2565987890UL, 4133115610UL, 62038708UL, 2357334250UL, 1230002441UL, 2397198293UL, 1497001150UL, 1882263827UL, 2524779298UL, +1736323157UL, 817630445UL, 3541909847UL, 1137565179UL, 3112310886UL, 3524287283UL, 1356492703UL, 3193060438UL, 3180534967UL, 2463036338UL, 1859639515UL, 3963974342UL, 111871878UL, 4108171950UL, 601260554UL, 705389180UL, 1776439965UL, 742999102UL, 399768111UL, 3963945521UL, 2094962544UL, 2007137733UL, 3219207950UL, 3495709267UL, 3525452874UL, 314919391UL, 3877039785UL, 720863934UL, 3565507827UL, 2594931381UL, 579458905UL, 2919403199UL, +3958525287UL, 3416503939UL, 4150612567UL, 1015748208UL, 960765392UL, 4227838648UL, 2998421769UL, 1644667445UL, 4221112143UL, 2402062799UL, 302729329UL, 190710543UL, 1721255927UL, 2274887963UL, 3958481548UL, 1293706587UL, 2185750138UL, 2992229399UL, 482133467UL, 3838280UL, 2514965671UL, 536333711UL, 2296185346UL, 1103433779UL, 3675282065UL, 2237639577UL, 2927153963UL, 4157295398UL, 533935893UL, 4172021805UL, 3793156627UL, 509578395UL, +3810017456UL, 2134110040UL, 3608998517UL, 1358364UL, 201278263UL, 3933249682UL, 3849960474UL, 2445690023UL, 628476542UL, 1355284593UL, 2444811561UL, 2751112324UL, 507378026UL, 3421170828UL, 3412599909UL, 1712118363UL, 54054007UL, 770634305UL, 325825294UL, 1532701769UL, 181534938UL, 1278069867UL, 4055596097UL, 2785457372UL, 4146252420UL, 2047690303UL, 361856758UL, 3439427065UL, 1099532083UL, 1733216839UL, 3788548638UL, 1094285639UL, +1633234274UL, 3047068265UL, 976767752UL, 2882980002UL, 2211288683UL, 3763615153UL, 366378371UL, 895830110UL, 2069599564UL, 827699420UL, 2457443913UL, 962962884UL, 3377496544UL, 2138389854UL, 3915615927UL, 3290989016UL, 3742489931UL, 3254971483UL, 189931252UL, 2044235060UL, 4275822963UL, 3073407497UL, 2095055586UL, 494148492UL, 1550568689UL, 1043420085UL, 758370067UL, 2869825005UL, 1411407684UL, 1194906295UL, 676378812UL, 636166267UL, +907760376UL, 180837718UL, 2588730975UL, 2971715054UL, 705382583UL, 639229964UL, 4010897189UL, 3392273121UL, 795184546UL, 3815622040UL, 3006792787UL, 1795412556UL, 330320182UL, 1990804460UL, 2956382339UL, 253264555UL, 51833064UL, 232302906UL, 836875615UL, 3665645898UL, 4284481518UL, 2373156680UL, 2610500049UL, 98106795UL, 2565987890UL, 4133115610UL, 62038708UL, 2357334250UL, 2761212145UL, 2397198293UL, 1497001150UL, 1882263827UL, +2524779298UL, 2381031747UL, 817630445UL, 3541909847UL, 1137565179UL, 3112310886UL, 2501374726UL, 1356492703UL, 3193060438UL, 3180534967UL, 2463036338UL, 3671733096UL, 3963974342UL, 111871878UL, 4108171950UL, 601260554UL, 1017043724UL, 1776439965UL, 742999102UL, 399768111UL, 3963945521UL, 2177838102UL, 2007137733UL, 3219207950UL, 3495709267UL, 3525452874UL, 3254054416UL, 3877039785UL, 720863934UL, 3565507827UL, 2594931381UL, 1994293489UL, +2919403199UL, 3958525287UL, 3416503939UL, 4150612567UL, 1976960210UL, 960765392UL, 4227838648UL, 2998421769UL, 1644667445UL, 2896792687UL, 2402062799UL, 302729329UL, 190710543UL, 1721255927UL, 2914584080UL, 3958481548UL, 1293706587UL, 2185750138UL, 2992229399UL, 810756083UL, 3838280UL, 2514965671UL, 536333711UL, 2296185346UL, 1776509588UL, 3675282065UL, 2237639577UL, 2927153963UL, 4157295398UL, 2048779551UL, 4172021805UL, 3793156627UL, +509578395UL, 3810017456UL, 3042185034UL, 3608998517UL, 1358364UL, 201278263UL, 3933249682UL, 3551449718UL, 2445690023UL, 628476542UL, 1355284593UL, 2444811561UL, 3480611728UL, 507378026UL, 3421170828UL, 3412599909UL, 1712118363UL, 1268921331UL, 770634305UL, 325825294UL, 1532701769UL, 181534938UL, 2645357587UL, 4055596097UL, 2785457372UL, 4146252420UL, 2047690303UL, 1994855609UL, 3439427065UL, 1099532083UL, 1733216839UL, 3788548638UL, +3516588243UL, 4058132193UL, 3940172101UL, 4043964688UL, 3377150021UL, 1381463736UL, 3320280180UL, 931260821UL, 2754727582UL, 1286176949UL, 1661126244UL, 2301263887UL, 2255977851UL, 1122646603UL, 1767549201UL, 162324152UL, 425506096UL, 3777762686UL, 13687528UL, 710105607UL, 1092739920UL, 2930179533UL, 568855389UL, 2476208631UL, 964360978UL, 2011445117UL, 3887128674UL, 2799005525UL, 2479086439UL, 814368438UL, 2018629666UL, 909662384UL, +231589584UL, 1422241284UL, 4035938208UL, 3570985552UL, 660700421UL, 603857869UL, 567385627UL, 3232044670UL, 291307502UL, 947817625UL, 3466590280UL, 3080261993UL, 947835229UL, 2925888682UL, 1817591844UL, 2652420575UL, 4150903445UL, 4055627313UL, 1715025966UL, 505331227UL, 1863531052UL, 2928506098UL, 947547681UL, 1117344443UL, 781457023UL, 607542746UL, 241559360UL, 3797150797UL, 105381589UL, 361541961UL, 3393121650UL, 3840152184UL, +2873171161UL, 3030026082UL, 1115171192UL, 1718221281UL, 96787532UL, 2556617898UL, 1237726058UL, 2876298621UL, 1052881200UL, 461661595UL, 2632346030UL, 1775614319UL, 2454951319UL, 3691637824UL, 4018448825UL, 1610472965UL, 3076493165UL, 1364200430UL, 2011206580UL, 1066672050UL, 706141458UL, 2064189273UL, 346938484UL, 2964350202UL, 3731612957UL, 2506635528UL, 2007045393UL, 3312126930UL, 2602035453UL, 988876930UL, 2960173442UL, 559685520UL, +2719943441UL, 891699839UL, 1151651090UL, 1223301894UL, 3666960271UL, 1330825927UL, 1681770552UL, 38877327UL, 3803211467UL, 4000053051UL, 3552560459UL, 3510286057UL, 2606732870UL, 721190747UL, 1933504723UL, 3110735238UL, 2333178561UL, 1577381363UL, 595257962UL, 4120745072UL, 960219089UL, 2591080970UL, 3354222743UL, 47827627UL, 3759509914UL, 304815919UL, 2643673615UL, 1381570381UL, 2103367217UL, 2440936991UL, 2376721005UL, 1483630814UL, +3137202706UL, 3075255640UL, 1743649605UL, 3649754571UL, 2550788713UL, 4281983459UL, 904183710UL, 4243944530UL, 2742129811UL, 3363501626UL, 3670239155UL, 4233018118UL, 2615012385UL, 1420298161UL, 1251344091UL, 2172588631UL, 1243035186UL, 1724496237UL, 762022558UL, 8747231UL, 334416849UL, 1219880856UL, 187900356UL, 2527057367UL, 1730455958UL, 3240238410UL, 906024910UL, 2351575735UL, 4207748622UL, 936139767UL, 1984289988UL, 285939331UL, +}, +{ +4246897171UL, 2217508286UL, 4117450683UL, 4110626546UL, 3753823387UL, 3977667932UL, 623718443UL, 2276396692UL, 3772091798UL, 2272323453UL, 710314822UL, 3733316262UL, 1497955597UL, 700242668UL, 3582720207UL, 1247731879UL, 336477088UL, 532374143UL, 1123157198UL, 123828173UL, 272472192UL, 2142741093UL, 2557920990UL, 4209595119UL, 2807266578UL, 1516814248UL, 4250883502UL, 1967663703UL, 215335417UL, 1252724071UL, 4267389372UL, 94668579UL, +1980152960UL, 968677393UL, 1237744359UL, 63833646UL, 2488747616UL, 700459471UL, 744977323UL, 40829823UL, 955400639UL, 37187948UL, 53133706UL, 2014551043UL, 1664982537UL, 3342787122UL, 1549278321UL, 1245110464UL, 3424539081UL, 2180485253UL, 2757636973UL, 3590044052UL, 2712703548UL, 1366894959UL, 1777449151UL, 1538653374UL, 168718075UL, 2435805251UL, 588815465UL, 3166271130UL, 3164200096UL, 417809976UL, 623036767UL, 340121872UL, +1792214783UL, 56330125UL, 3268029211UL, 1117100306UL, 345899179UL, 1547071836UL, 3657965225UL, 4109701299UL, 664937685UL, 2627187961UL, 149301108UL, 1764003230UL, 3177910586UL, 3081492846UL, 2295419724UL, 2553420882UL, 1506534805UL, 971284719UL, 3224921758UL, 3336906843UL, 1507395478UL, 1224379418UL, 4117299702UL, 1973783225UL, 3609783242UL, 4186900040UL, 3715175536UL, 3904547465UL, 459692505UL, 3546328518UL, 3071448159UL, 1300375875UL, +1805392236UL, 3072717072UL, 99113127UL, 4281059076UL, 1658649136UL, 1974081931UL, 3940966682UL, 2092428023UL, 4014384840UL, 1546542514UL, 1130620125UL, 4117533767UL, 3372991735UL, 3537429957UL, 2704347564UL, 2300583688UL, 915286167UL, 1553874575UL, 3466388216UL, 701000054UL, 349103195UL, 1554395274UL, 3140941933UL, 2874072684UL, 2630572105UL, 2794301280UL, 321399291UL, 1158058020UL, 3570908149UL, 122802750UL, 3012686842UL, 2588402967UL, +3420589812UL, 581016671UL, 193235885UL, 1558092297UL, 1233353728UL, 1080743465UL, 3292663441UL, 2188057155UL, 2715412992UL, 4274317234UL, 1657504087UL, 2554269340UL, 1079741964UL, 922252155UL, 569761460UL, 3215661310UL, 2450710288UL, 2491078689UL, 632504591UL, 2169581755UL, 2552457727UL, 2554414735UL, 3347573916UL, 681756629UL, 801451286UL, 3504956478UL, 1308297539UL, 3602650700UL, 3530372129UL, 4117441036UL, 1827438812UL, 2852602217UL, +570161747UL, 4246897171UL, 2217508286UL, 4117450683UL, 4110626546UL, 756072139UL, 3977667932UL, 623718443UL, 2276396692UL, 3772091798UL, 3829898369UL, 710314822UL, 3733316262UL, 1497955597UL, 700242668UL, 757539371UL, 1247731879UL, 336477088UL, 532374143UL, 1123157198UL, 2374238409UL, 272472192UL, 2142741093UL, 2557920990UL, 4209595119UL, 1632439709UL, 1516814248UL, 4250883502UL, 1967663703UL, 215335417UL, 1267642920UL, 4267389372UL, +94668579UL, 1980152960UL, 968677393UL, 2252616933UL, 63833646UL, 2488747616UL, 700459471UL, 744977323UL, 2711054317UL, 955400639UL, 37187948UL, 53133706UL, 2014551043UL, 1664498234UL, 3342787122UL, 1549278321UL, 1245110464UL, 3424539081UL, 496150741UL, 2757636973UL, 3590044052UL, 2712703548UL, 1366894959UL, 2066534443UL, 1538653374UL, 168718075UL, 2435805251UL, 588815465UL, 318307195UL, 3164200096UL, 417809976UL, 623036767UL, +340121872UL, 3426055217UL, 56330125UL, 3268029211UL, 1117100306UL, 345899179UL, 979486044UL, 3657965225UL, 4109701299UL, 664937685UL, 2627187961UL, 2747102301UL, 1764003230UL, 3177910586UL, 3081492846UL, 2295419724UL, 1088606857UL, 1506534805UL, 971284719UL, 3224921758UL, 3336906843UL, 984983218UL, 1224379418UL, 4117299702UL, 1973783225UL, 3609783242UL, 1044785427UL, 3715175536UL, 3904547465UL, 459692505UL, 3546328518UL, 2096978494UL, +1300375875UL, 1805392236UL, 3072717072UL, 99113127UL, 972796497UL, 1658649136UL, 1974081931UL, 3940966682UL, 2092428023UL, 2914458983UL, 1546542514UL, 1130620125UL, 4117533767UL, 3372991735UL, 947968718UL, 2704347564UL, 2300583688UL, 915286167UL, 1553874575UL, 2124709798UL, 701000054UL, 349103195UL, 1554395274UL, 3140941933UL, 2569019225UL, 2630572105UL, 2794301280UL, 321399291UL, 1158058020UL, 4051601694UL, 122802750UL, 3012686842UL, +2588402967UL, 3420589812UL, 1738150581UL, 193235885UL, 1558092297UL, 1233353728UL, 1080743465UL, 1527068788UL, 2188057155UL, 2715412992UL, 4274317234UL, 1657504087UL, 1543089352UL, 1079741964UL, 922252155UL, 569761460UL, 3215661310UL, 2869922986UL, 2491078689UL, 632504591UL, 2169581755UL, 2552457727UL, 2807462748UL, 3347573916UL, 681756629UL, 801451286UL, 3504956478UL, 3400676931UL, 3602650700UL, 3530372129UL, 4117441036UL, 1827438812UL, +4056234054UL, 570161747UL, 4246897171UL, 2217508286UL, 4117450683UL, 3321376103UL, 756072139UL, 3977667932UL, 623718443UL, 2276396692UL, 1340008665UL, 3829898369UL, 710314822UL, 3733316262UL, 1497955597UL, 2098292377UL, 757539371UL, 1247731879UL, 336477088UL, 532374143UL, 2210327641UL, 2374238409UL, 272472192UL, 2142741093UL, 2557920990UL, 3502520226UL, 1632439709UL, 1516814248UL, 4250883502UL, 1967663703UL, 499168780UL, 1267642920UL, +4267389372UL, 94668579UL, 1980152960UL, 2695928666UL, 2252616933UL, 63833646UL, 2488747616UL, 700459471UL, 4181471443UL, 2711054317UL, 955400639UL, 37187948UL, 53133706UL, 441944403UL, 1664498234UL, 3342787122UL, 1549278321UL, 1245110464UL, 2271611585UL, 496150741UL, 2757636973UL, 3590044052UL, 2712703548UL, 3009817799UL, 2066534443UL, 1538653374UL, 168718075UL, 2435805251UL, 734763537UL, 318307195UL, 3164200096UL, 417809976UL, +623036767UL, 4002728646UL, 3426055217UL, 56330125UL, 3268029211UL, 1117100306UL, 1435987728UL, 979486044UL, 3657965225UL, 4109701299UL, 664937685UL, 815527474UL, 2747102301UL, 1764003230UL, 3177910586UL, 3081492846UL, 63383766UL, 1088606857UL, 1506534805UL, 971284719UL, 3224921758UL, 2331024939UL, 984983218UL, 1224379418UL, 4117299702UL, 1973783225UL, 3998070267UL, 1044785427UL, 3715175536UL, 3904547465UL, 459692505UL, 2582830990UL, +2096978494UL, 1300375875UL, 1805392236UL, 3072717072UL, 321154403UL, 972796497UL, 1658649136UL, 1974081931UL, 3940966682UL, 3789726976UL, 2914458983UL, 1546542514UL, 1130620125UL, 4117533767UL, 3440681546UL, 947968718UL, 2704347564UL, 2300583688UL, 915286167UL, 474021937UL, 2124709798UL, 701000054UL, 349103195UL, 1554395274UL, 702752814UL, 2569019225UL, 2630572105UL, 2794301280UL, 321399291UL, 2406346046UL, 4051601694UL, 122802750UL, +3012686842UL, 2588402967UL, 1782259321UL, 1738150581UL, 193235885UL, 1558092297UL, 1233353728UL, 3935919190UL, 1527068788UL, 2188057155UL, 2715412992UL, 4274317234UL, 1722541048UL, 1543089352UL, 1079741964UL, 922252155UL, 569761460UL, 3384000986UL, 2869922986UL, 2491078689UL, 632504591UL, 2169581755UL, 3451609034UL, 2807462748UL, 3347573916UL, 681756629UL, 801451286UL, 2643408064UL, 3400676931UL, 3602650700UL, 3530372129UL, 4117441036UL, +3635077251UL, 4056234054UL, 570161747UL, 4246897171UL, 2217508286UL, 2364796923UL, 3321376103UL, 756072139UL, 3977667932UL, 623718443UL, 3792539489UL, 1340008665UL, 3829898369UL, 710314822UL, 3733316262UL, 876419217UL, 2098292377UL, 757539371UL, 1247731879UL, 336477088UL, 3307300788UL, 2210327641UL, 2374238409UL, 272472192UL, 2142741093UL, 4142392723UL, 3502520226UL, 1632439709UL, 1516814248UL, 4250883502UL, 3551852862UL, 499168780UL, +1267642920UL, 4267389372UL, 94668579UL, 1177286958UL, 2695928666UL, 2252616933UL, 63833646UL, 2488747616UL, 3571573975UL, 4181471443UL, 2711054317UL, 955400639UL, 37187948UL, 1485050393UL, 441944403UL, 1664498234UL, 3342787122UL, 1549278321UL, 518707274UL, 2271611585UL, 496150741UL, 2757636973UL, 3590044052UL, 305206687UL, 3009817799UL, 2066534443UL, 1538653374UL, 168718075UL, 1914032206UL, 734763537UL, 318307195UL, 3164200096UL, +417809976UL, 2062496275UL, 4002728646UL, 3426055217UL, 56330125UL, 3268029211UL, 1878869053UL, 1435987728UL, 979486044UL, 3657965225UL, 4109701299UL, 1558853775UL, 815527474UL, 2747102301UL, 1764003230UL, 3177910586UL, 681877401UL, 63383766UL, 1088606857UL, 1506534805UL, 971284719UL, 2546285777UL, 2331024939UL, 984983218UL, 1224379418UL, 4117299702UL, 539292757UL, 3998070267UL, 1044785427UL, 3715175536UL, 3904547465UL, 3854154565UL, +2582830990UL, 2096978494UL, 1300375875UL, 1805392236UL, 2586804198UL, 321154403UL, 972796497UL, 1658649136UL, 1974081931UL, 1718873863UL, 3789726976UL, 2914458983UL, 1546542514UL, 1130620125UL, 477866180UL, 3440681546UL, 947968718UL, 2704347564UL, 2300583688UL, 56071603UL, 474021937UL, 2124709798UL, 701000054UL, 349103195UL, 2431577249UL, 702752814UL, 2569019225UL, 2630572105UL, 2794301280UL, 211758134UL, 2406346046UL, 4051601694UL, +122802750UL, 3012686842UL, 2470642374UL, 1782259321UL, 1738150581UL, 193235885UL, 1558092297UL, 852353933UL, 3935919190UL, 1527068788UL, 2188057155UL, 2715412992UL, 543290606UL, 1722541048UL, 1543089352UL, 1079741964UL, 922252155UL, 1146820965UL, 3384000986UL, 2869922986UL, 2491078689UL, 632504591UL, 2936494996UL, 3451609034UL, 2807462748UL, 3347573916UL, 681756629UL, 3428474076UL, 2643408064UL, 3400676931UL, 3602650700UL, 3530372129UL, +3558016488UL, 304167301UL, 3073812276UL, 1253385329UL, 801639697UL, 1346336854UL, 3880416830UL, 1110804934UL, 2500585706UL, 1294233475UL, 1964132477UL, 1625651370UL, 2732590160UL, 310054807UL, 3350133555UL, 800839525UL, 3435579932UL, 2120216654UL, 407780291UL, 1228117799UL, 513334510UL, 1423091447UL, 3698882838UL, 2556406643UL, 1536483608UL, 998695315UL, 1619514015UL, 4197375975UL, 892985909UL, 993665758UL, 4160405430UL, 2379977763UL, +1423742790UL, 4286808034UL, 479280944UL, 3611297256UL, 3481820363UL, 1261889958UL, 455298115UL, 3955764756UL, 2406161837UL, 185873336UL, 3382956716UL, 3556168427UL, 3988426650UL, 2917586591UL, 1248672474UL, 2925146191UL, 1416331075UL, 290755159UL, 2845168299UL, 3301422441UL, 3771816588UL, 491352430UL, 2461746382UL, 1591975949UL, 604909111UL, 3595669760UL, 4079314041UL, 258321046UL, 1352583874UL, 999018951UL, 3150079914UL, 113122510UL, +743303046UL, 3205496412UL, 4267738054UL, 2567402806UL, 2181107494UL, 3266354249UL, 1941487496UL, 2742084900UL, 3758785335UL, 732694221UL, 2052988791UL, 1759288229UL, 1094292464UL, 1582835026UL, 2817864273UL, 666443657UL, 419482443UL, 2877435004UL, 2944696351UL, 2523539432UL, 301119182UL, 998264713UL, 2314419254UL, 3610447393UL, 1139414242UL, 1486351830UL, 3207929489UL, 384633091UL, 4056367270UL, 2348418835UL, 3773781885UL, 1963929818UL, +804929680UL, 1511023454UL, 3915948102UL, 1371942526UL, 2586212526UL, 130122933UL, 2030859646UL, 3730011315UL, 118408868UL, 632704878UL, 3559959612UL, 2926361713UL, 1401386286UL, 599210027UL, 2315051975UL, 157809758UL, 1148939942UL, 3060024350UL, 1464284678UL, 3209480975UL, 3961060416UL, 3481639206UL, 4113344379UL, 3475766200UL, 130581501UL, 1844026536UL, 2661594012UL, 3145812007UL, 3233175620UL, 2549419093UL, 2612966733UL, 1348260920UL, +740167863UL, 226231218UL, 2631972701UL, 2148020402UL, 3399479414UL, 1074946996UL, 30872114UL, 1342415612UL, 1071408471UL, 1141719547UL, 332346805UL, 1473336719UL, 4207932404UL, 3668838170UL, 3154502882UL, 3892070442UL, 2812790310UL, 13931822UL, 1150258251UL, 2369539473UL, 640926011UL, 2991135002UL, 2410382633UL, 548200125UL, 3977740663UL, 1245837867UL, 2378569399UL, 1561469990UL, 2437445882UL, 214387770UL, 3329587833UL, 281635893UL, +}, +{ +1720103319UL, 2201367526UL, 1415072072UL, 2446588589UL, 2195586017UL, 3817930623UL, 653121934UL, 2766514657UL, 765921436UL, 630082485UL, 2990883045UL, 3304472999UL, 471385134UL, 4097977544UL, 3749829028UL, 3587534772UL, 1064359851UL, 800061060UL, 2844220510UL, 389838005UL, 3681318140UL, 1515923235UL, 1885079324UL, 713031018UL, 1962734763UL, 2288160004UL, 1983331336UL, 1247350521UL, 4208372034UL, 1444837930UL, 3549494305UL, 4169715512UL, +701313302UL, 1118275019UL, 3118975645UL, 4153969630UL, 3516491181UL, 3601057044UL, 2509222288UL, 223064937UL, 899123842UL, 2574531231UL, 1386928111UL, 3790651401UL, 1300768348UL, 2038833061UL, 3736517792UL, 3850203561UL, 1679542285UL, 3391273474UL, 3862995487UL, 3118056386UL, 47128429UL, 2977525950UL, 3236389548UL, 1937040839UL, 4223233198UL, 2105119262UL, 721111284UL, 331726226UL, 68419013UL, 2575393464UL, 3648293304UL, 1448878851UL, +4186783614UL, 3696899986UL, 1270877069UL, 3351263117UL, 3918639273UL, 1472902162UL, 2767482392UL, 3549853842UL, 2353191576UL, 3353325530UL, 3072485271UL, 2689121900UL, 2335686695UL, 246689858UL, 2946177636UL, 1677728066UL, 1455723263UL, 3447540996UL, 2143976172UL, 1779511280UL, 3667361203UL, 1575502035UL, 849872082UL, 3527265600UL, 1443266215UL, 1320668722UL, 458373857UL, 3862342513UL, 699597603UL, 685707268UL, 948502001UL, 2501058653UL, +2254562046UL, 2210683894UL, 29088679UL, 1456231200UL, 2764392560UL, 4138068372UL, 3094591474UL, 1093749152UL, 1668875176UL, 3133003149UL, 4128702884UL, 652852832UL, 2211671337UL, 2231125160UL, 131729558UL, 3845605816UL, 3769660625UL, 1696592453UL, 728353643UL, 2751201502UL, 3496971733UL, 3349166522UL, 1005919830UL, 3411089601UL, 3754493523UL, 1994945529UL, 1604309774UL, 2083609686UL, 833983349UL, 2600153513UL, 1677348112UL, 207321473UL, +1051990507UL, 2135039620UL, 4239461390UL, 1574144998UL, 1070761856UL, 1990807569UL, 112704720UL, 2506523299UL, 2827487353UL, 4130754901UL, 1943274185UL, 3913701053UL, 1014850621UL, 3662772872UL, 4115124063UL, 1760146762UL, 3254829227UL, 800302547UL, 3602066837UL, 975658158UL, 2880018391UL, 714134831UL, 2696483406UL, 2351365577UL, 2811011071UL, 3505407160UL, 54109504UL, 424967367UL, 3759525737UL, 1726627246UL, 1110539071UL, 2339755764UL, +3356877114UL, 1720103319UL, 2201367526UL, 1415072072UL, 2446588589UL, 2499136377UL, 3817930623UL, 653121934UL, 2766514657UL, 765921436UL, 3794433488UL, 2990883045UL, 3304472999UL, 471385134UL, 4097977544UL, 3618516788UL, 3587534772UL, 1064359851UL, 800061060UL, 2844220510UL, 2319780070UL, 3681318140UL, 1515923235UL, 1885079324UL, 713031018UL, 11705290UL, 2288160004UL, 1983331336UL, 1247350521UL, 4208372034UL, 2508892029UL, 3549494305UL, +4169715512UL, 701313302UL, 1118275019UL, 1430522809UL, 4153969630UL, 3516491181UL, 3601057044UL, 2509222288UL, 1917025539UL, 899123842UL, 2574531231UL, 1386928111UL, 3790651401UL, 1219040401UL, 2038833061UL, 3736517792UL, 3850203561UL, 1679542285UL, 671522957UL, 3862995487UL, 3118056386UL, 47128429UL, 2977525950UL, 2762831063UL, 1937040839UL, 4223233198UL, 2105119262UL, 721111284UL, 1386688457UL, 68419013UL, 2575393464UL, 3648293304UL, +1448878851UL, 466405406UL, 3696899986UL, 1270877069UL, 3351263117UL, 3918639273UL, 94103836UL, 2767482392UL, 3549853842UL, 2353191576UL, 3353325530UL, 349361794UL, 2689121900UL, 2335686695UL, 246689858UL, 2946177636UL, 3232050945UL, 1455723263UL, 3447540996UL, 2143976172UL, 1779511280UL, 542837628UL, 1575502035UL, 849872082UL, 3527265600UL, 1443266215UL, 1867394883UL, 458373857UL, 3862342513UL, 699597603UL, 685707268UL, 4210562190UL, +2501058653UL, 2254562046UL, 2210683894UL, 29088679UL, 3647972960UL, 2764392560UL, 4138068372UL, 3094591474UL, 1093749152UL, 312511475UL, 3133003149UL, 4128702884UL, 652852832UL, 2211671337UL, 145492343UL, 131729558UL, 3845605816UL, 3769660625UL, 1696592453UL, 4223421915UL, 2751201502UL, 3496971733UL, 3349166522UL, 1005919830UL, 1656802049UL, 3754493523UL, 1994945529UL, 1604309774UL, 2083609686UL, 3032348100UL, 2600153513UL, 1677348112UL, +207321473UL, 1051990507UL, 3349078950UL, 4239461390UL, 1574144998UL, 1070761856UL, 1990807569UL, 2970449178UL, 2506523299UL, 2827487353UL, 4130754901UL, 1943274185UL, 445467699UL, 1014850621UL, 3662772872UL, 4115124063UL, 1760146762UL, 3738518624UL, 800302547UL, 3602066837UL, 975658158UL, 2880018391UL, 1553758240UL, 2696483406UL, 2351365577UL, 2811011071UL, 3505407160UL, 1259180427UL, 424967367UL, 3759525737UL, 1726627246UL, 1110539071UL, +2863575420UL, 3356877114UL, 1720103319UL, 2201367526UL, 1415072072UL, 1463388387UL, 2499136377UL, 3817930623UL, 653121934UL, 2766514657UL, 526940162UL, 3794433488UL, 2990883045UL, 3304472999UL, 471385134UL, 594057325UL, 3618516788UL, 3587534772UL, 1064359851UL, 800061060UL, 1001523010UL, 2319780070UL, 3681318140UL, 1515923235UL, 1885079324UL, 255576756UL, 11705290UL, 2288160004UL, 1983331336UL, 1247350521UL, 1108575113UL, 2508892029UL, +3549494305UL, 4169715512UL, 701313302UL, 524281295UL, 1430522809UL, 4153969630UL, 3516491181UL, 3601057044UL, 1816283752UL, 1917025539UL, 899123842UL, 2574531231UL, 1386928111UL, 1530966640UL, 1219040401UL, 2038833061UL, 3736517792UL, 3850203561UL, 1855689726UL, 671522957UL, 3862995487UL, 3118056386UL, 47128429UL, 1718476461UL, 2762831063UL, 1937040839UL, 4223233198UL, 2105119262UL, 176166283UL, 1386688457UL, 68419013UL, 2575393464UL, +3648293304UL, 4069820559UL, 466405406UL, 3696899986UL, 1270877069UL, 3351263117UL, 1645545933UL, 94103836UL, 2767482392UL, 3549853842UL, 2353191576UL, 4163887784UL, 349361794UL, 2689121900UL, 2335686695UL, 246689858UL, 1246040634UL, 3232050945UL, 1455723263UL, 3447540996UL, 2143976172UL, 2111249329UL, 542837628UL, 1575502035UL, 849872082UL, 3527265600UL, 1836050084UL, 1867394883UL, 458373857UL, 3862342513UL, 699597603UL, 3139537113UL, +4210562190UL, 2501058653UL, 2254562046UL, 2210683894UL, 3997617191UL, 3647972960UL, 2764392560UL, 4138068372UL, 3094591474UL, 2664795910UL, 312511475UL, 3133003149UL, 4128702884UL, 652852832UL, 1658020144UL, 145492343UL, 131729558UL, 3845605816UL, 3769660625UL, 2822578949UL, 4223421915UL, 2751201502UL, 3496971733UL, 3349166522UL, 1582873482UL, 1656802049UL, 3754493523UL, 1994945529UL, 1604309774UL, 1113569720UL, 3032348100UL, 2600153513UL, +1677348112UL, 207321473UL, 3169983987UL, 3349078950UL, 4239461390UL, 1574144998UL, 1070761856UL, 1308776367UL, 2970449178UL, 2506523299UL, 2827487353UL, 4130754901UL, 1403493846UL, 445467699UL, 1014850621UL, 3662772872UL, 4115124063UL, 340210579UL, 3738518624UL, 800302547UL, 3602066837UL, 975658158UL, 3367770843UL, 1553758240UL, 2696483406UL, 2351365577UL, 2811011071UL, 4162875353UL, 1259180427UL, 424967367UL, 3759525737UL, 1726627246UL, +1341806135UL, 2863575420UL, 3356877114UL, 1720103319UL, 2201367526UL, 2232383995UL, 1463388387UL, 2499136377UL, 3817930623UL, 653121934UL, 1756183481UL, 526940162UL, 3794433488UL, 2990883045UL, 3304472999UL, 2185125572UL, 594057325UL, 3618516788UL, 3587534772UL, 1064359851UL, 2933544964UL, 1001523010UL, 2319780070UL, 3681318140UL, 1515923235UL, 4147783641UL, 255576756UL, 11705290UL, 2288160004UL, 1983331336UL, 956739400UL, 1108575113UL, +2508892029UL, 3549494305UL, 4169715512UL, 142273913UL, 524281295UL, 1430522809UL, 4153969630UL, 3516491181UL, 986032639UL, 1816283752UL, 1917025539UL, 899123842UL, 2574531231UL, 1508271110UL, 1530966640UL, 1219040401UL, 2038833061UL, 3736517792UL, 458417668UL, 1855689726UL, 671522957UL, 3862995487UL, 3118056386UL, 284266432UL, 1718476461UL, 2762831063UL, 1937040839UL, 4223233198UL, 1605514069UL, 176166283UL, 1386688457UL, 68419013UL, +2575393464UL, 3650747541UL, 4069820559UL, 466405406UL, 3696899986UL, 1270877069UL, 678590674UL, 1645545933UL, 94103836UL, 2767482392UL, 3549853842UL, 398179945UL, 4163887784UL, 349361794UL, 2689121900UL, 2335686695UL, 3853658293UL, 1246040634UL, 3232050945UL, 1455723263UL, 3447540996UL, 2657693810UL, 2111249329UL, 542837628UL, 1575502035UL, 849872082UL, 2061659800UL, 1836050084UL, 1867394883UL, 458373857UL, 3862342513UL, 730568629UL, +3139537113UL, 4210562190UL, 2501058653UL, 2254562046UL, 449510786UL, 3997617191UL, 3647972960UL, 2764392560UL, 4138068372UL, 1939679536UL, 2664795910UL, 312511475UL, 3133003149UL, 4128702884UL, 4057510355UL, 1658020144UL, 145492343UL, 131729558UL, 3845605816UL, 3235632110UL, 2822578949UL, 4223421915UL, 2751201502UL, 3496971733UL, 4258920219UL, 1582873482UL, 1656802049UL, 3754493523UL, 1994945529UL, 1073499993UL, 1113569720UL, 3032348100UL, +2600153513UL, 1677348112UL, 3152835240UL, 3169983987UL, 3349078950UL, 4239461390UL, 1574144998UL, 2548972357UL, 1308776367UL, 2970449178UL, 2506523299UL, 2827487353UL, 2908066033UL, 1403493846UL, 445467699UL, 1014850621UL, 3662772872UL, 1685925089UL, 340210579UL, 3738518624UL, 800302547UL, 3602066837UL, 2264692610UL, 3367770843UL, 1553758240UL, 2696483406UL, 2351365577UL, 1686022564UL, 4162875353UL, 1259180427UL, 424967367UL, 3759525737UL, +70326173UL, 3028074555UL, 2568586198UL, 2513473964UL, 2923109510UL, 2265392251UL, 3760490867UL, 147487099UL, 386755149UL, 2152759137UL, 2716532213UL, 1153507474UL, 627929575UL, 847454712UL, 2426916452UL, 3861548980UL, 209825268UL, 1090299778UL, 1876886461UL, 976019203UL, 4290216337UL, 2278290065UL, 3302814528UL, 1567440061UL, 1874857224UL, 3794588915UL, 3218569451UL, 2335365199UL, 1959651923UL, 3366000689UL, 2374428382UL, 2126784887UL, +4123272655UL, 274837369UL, 1413111935UL, 1754627204UL, 1863684635UL, 4170025739UL, 2150019850UL, 4250751856UL, 3601214212UL, 2024081043UL, 334808859UL, 3921757513UL, 3870643644UL, 2864810945UL, 1004431888UL, 4283279830UL, 873365350UL, 2479791433UL, 3393478881UL, 3373502257UL, 1882140107UL, 2546676519UL, 1208428915UL, 268043238UL, 2292710623UL, 770651064UL, 2330160036UL, 2476488258UL, 2496037992UL, 118721504UL, 2289499985UL, 987994743UL, +3610346256UL, 3371795927UL, 2681434550UL, 2213200417UL, 3729194378UL, 1657623395UL, 402983380UL, 3618058500UL, 3487743585UL, 965523531UL, 819256729UL, 2544660729UL, 3273986506UL, 60894411UL, 1779152929UL, 3598159279UL, 3429317853UL, 2246402362UL, 3761392367UL, 3921798306UL, 947928110UL, 2394097908UL, 4004330264UL, 1180759989UL, 1624349051UL, 1750929499UL, 3889184770UL, 2052097704UL, 4092981046UL, 2913733578UL, 4241980897UL, 1127407450UL, +950788009UL, 2105033320UL, 473205730UL, 981905310UL, 2888856914UL, 798112239UL, 3377889612UL, 2273659507UL, 1157471194UL, 4269212574UL, 3575306012UL, 116024754UL, 1432668659UL, 1079598649UL, 3882002482UL, 3838480186UL, 823643071UL, 1244220618UL, 1227720039UL, 1343395654UL, 4277277976UL, 2612321540UL, 3013674017UL, 3658064522UL, 2573775167UL, 142767236UL, 2545708383UL, 1740478937UL, 809036862UL, 1492188594UL, 1294286248UL, 1093543858UL, +2944418375UL, 2981996479UL, 4067464923UL, 3071157685UL, 1938984450UL, 81707323UL, 337713546UL, 1849381296UL, 3447450393UL, 3551106302UL, 3394545269UL, 3167744716UL, 1815294624UL, 3244728913UL, 2462138247UL, 2286711732UL, 3023116169UL, 707366723UL, 1314169762UL, 1511231537UL, 2227622993UL, 2876600706UL, 4271030726UL, 2020521540UL, 2966596767UL, 3964589247UL, 1291306737UL, 883851756UL, 1355819080UL, 2834319249UL, 3825063450UL, 4205423325UL, +}, +{ +525214560UL, 1972466543UL, 1542775297UL, 3030388145UL, 2623763324UL, 1445252054UL, 2315649878UL, 2940376435UL, 1322155857UL, 2007925719UL, 899111545UL, 3946601974UL, 720416639UL, 566341007UL, 3830971140UL, 2379218430UL, 946001131UL, 324551023UL, 3792134824UL, 2419222364UL, 2507004728UL, 4050415702UL, 2934667964UL, 3435655480UL, 3738151878UL, 340092998UL, 429296098UL, 3804978739UL, 1547120540UL, 976306993UL, 1134820236UL, 288696971UL, +292350374UL, 423348923UL, 4250561112UL, 1380146522UL, 646098313UL, 3081299572UL, 3633231429UL, 2348008746UL, 3250735726UL, 3495239618UL, 1083361876UL, 2660545988UL, 97607299UL, 741626628UL, 2451882102UL, 607936604UL, 1566190301UL, 3752644837UL, 1626575269UL, 2569947980UL, 120166892UL, 1936167922UL, 2964570009UL, 2601765059UL, 2550590348UL, 1491574373UL, 1916644920UL, 2955888714UL, 3900360190UL, 396836243UL, 2417234534UL, 4219822777UL, +3017031315UL, 3848370775UL, 4113753945UL, 1038708316UL, 1227041843UL, 1287656330UL, 594136009UL, 1679465955UL, 1127853612UL, 445673212UL, 2491164616UL, 4234959779UL, 3670094401UL, 2810998507UL, 2091885715UL, 4213376041UL, 3724691332UL, 1428205363UL, 2351471476UL, 1863345709UL, 3172242044UL, 1435176883UL, 925973933UL, 3166951436UL, 2056462416UL, 489417029UL, 4029854347UL, 3002516723UL, 1597712463UL, 1200457469UL, 3909654542UL, 1352519428UL, +13398705UL, 3919269221UL, 371331154UL, 332347636UL, 3726033518UL, 2407091731UL, 2926199215UL, 3054175446UL, 3208807730UL, 584793525UL, 2706493003UL, 561190823UL, 2412132195UL, 2488492462UL, 3149885896UL, 3512276852UL, 2843032269UL, 2485506176UL, 4025325347UL, 4152622551UL, 4022346903UL, 331746013UL, 197533993UL, 3658414685UL, 2670729696UL, 3290854172UL, 2251426444UL, 3569225076UL, 2466203243UL, 658184940UL, 518096293UL, 52156682UL, +2398958685UL, 745491615UL, 3723004242UL, 2847276077UL, 1857504125UL, 633035220UL, 4057593658UL, 2783467746UL, 3122875931UL, 446601186UL, 2786851490UL, 261950076UL, 2843506874UL, 745391893UL, 1404094021UL, 2234513997UL, 315083019UL, 645865358UL, 2862243948UL, 1204315994UL, 3701151065UL, 663411328UL, 1924727700UL, 1905843757UL, 1483930049UL, 449616818UL, 3793968150UL, 1840668755UL, 1671024110UL, 4079375869UL, 4171670660UL, 2585904968UL, +3886777251UL, 525214560UL, 1972466543UL, 1542775297UL, 3030388145UL, 2530126952UL, 1445252054UL, 2315649878UL, 2940376435UL, 1322155857UL, 1599103627UL, 899111545UL, 3946601974UL, 720416639UL, 566341007UL, 4070101360UL, 2379218430UL, 946001131UL, 324551023UL, 3792134824UL, 2445126690UL, 2507004728UL, 4050415702UL, 2934667964UL, 3435655480UL, 2968121571UL, 340092998UL, 429296098UL, 3804978739UL, 1547120540UL, 3901803457UL, 1134820236UL, +288696971UL, 292350374UL, 423348923UL, 1589814289UL, 1380146522UL, 646098313UL, 3081299572UL, 3633231429UL, 670777956UL, 3250735726UL, 3495239618UL, 1083361876UL, 2660545988UL, 4050232394UL, 741626628UL, 2451882102UL, 607936604UL, 1566190301UL, 1132827700UL, 1626575269UL, 2569947980UL, 120166892UL, 1936167922UL, 1280520333UL, 2601765059UL, 2550590348UL, 1491574373UL, 1916644920UL, 1073889810UL, 3900360190UL, 396836243UL, 2417234534UL, +4219822777UL, 1754651820UL, 3848370775UL, 4113753945UL, 1038708316UL, 1227041843UL, 464826842UL, 594136009UL, 1679465955UL, 1127853612UL, 445673212UL, 4198686893UL, 4234959779UL, 3670094401UL, 2810998507UL, 2091885715UL, 416103731UL, 3724691332UL, 1428205363UL, 2351471476UL, 1863345709UL, 2637470915UL, 1435176883UL, 925973933UL, 3166951436UL, 2056462416UL, 2546319147UL, 4029854347UL, 3002516723UL, 1597712463UL, 1200457469UL, 681365672UL, +1352519428UL, 13398705UL, 3919269221UL, 371331154UL, 742849231UL, 3726033518UL, 2407091731UL, 2926199215UL, 3054175446UL, 1323833820UL, 584793525UL, 2706493003UL, 561190823UL, 2412132195UL, 3747238187UL, 3149885896UL, 3512276852UL, 2843032269UL, 2485506176UL, 3817319503UL, 4152622551UL, 4022346903UL, 331746013UL, 197533993UL, 99009902UL, 2670729696UL, 3290854172UL, 2251426444UL, 3569225076UL, 4199909720UL, 658184940UL, 518096293UL, +52156682UL, 2398958685UL, 1648201186UL, 3723004242UL, 2847276077UL, 1857504125UL, 633035220UL, 1394668680UL, 2783467746UL, 3122875931UL, 446601186UL, 2786851490UL, 2590549096UL, 2843506874UL, 745391893UL, 1404094021UL, 2234513997UL, 347299411UL, 645865358UL, 2862243948UL, 1204315994UL, 3701151065UL, 4028305509UL, 1924727700UL, 1905843757UL, 1483930049UL, 449616818UL, 2251238906UL, 1840668755UL, 1671024110UL, 4079375869UL, 4171670660UL, +4080554282UL, 3886777251UL, 525214560UL, 1972466543UL, 1542775297UL, 3280177496UL, 2530126952UL, 1445252054UL, 2315649878UL, 2940376435UL, 2094983509UL, 1599103627UL, 899111545UL, 3946601974UL, 720416639UL, 1446566513UL, 4070101360UL, 2379218430UL, 946001131UL, 324551023UL, 2945613775UL, 2445126690UL, 2507004728UL, 4050415702UL, 2934667964UL, 2815036731UL, 2968121571UL, 340092998UL, 429296098UL, 3804978739UL, 3298867574UL, 3901803457UL, +1134820236UL, 288696971UL, 292350374UL, 3280367987UL, 1589814289UL, 1380146522UL, 646098313UL, 3081299572UL, 2536311658UL, 670777956UL, 3250735726UL, 3495239618UL, 1083361876UL, 3726225049UL, 4050232394UL, 741626628UL, 2451882102UL, 607936604UL, 3460165725UL, 1132827700UL, 1626575269UL, 2569947980UL, 120166892UL, 2961109404UL, 1280520333UL, 2601765059UL, 2550590348UL, 1491574373UL, 755823086UL, 1073889810UL, 3900360190UL, 396836243UL, +2417234534UL, 3036027780UL, 1754651820UL, 3848370775UL, 4113753945UL, 1038708316UL, 3784147349UL, 464826842UL, 594136009UL, 1679465955UL, 1127853612UL, 2128970592UL, 4198686893UL, 4234959779UL, 3670094401UL, 2810998507UL, 421961324UL, 416103731UL, 3724691332UL, 1428205363UL, 2351471476UL, 3407618159UL, 2637470915UL, 1435176883UL, 925973933UL, 3166951436UL, 1274860184UL, 2546319147UL, 4029854347UL, 3002516723UL, 1597712463UL, 671480036UL, +681365672UL, 1352519428UL, 13398705UL, 3919269221UL, 1150967289UL, 742849231UL, 3726033518UL, 2407091731UL, 2926199215UL, 3106945136UL, 1323833820UL, 584793525UL, 2706493003UL, 561190823UL, 2013357219UL, 3747238187UL, 3149885896UL, 3512276852UL, 2843032269UL, 3595347994UL, 3817319503UL, 4152622551UL, 4022346903UL, 331746013UL, 367216863UL, 99009902UL, 2670729696UL, 3290854172UL, 2251426444UL, 3130148315UL, 4199909720UL, 658184940UL, +518096293UL, 52156682UL, 3004378899UL, 1648201186UL, 3723004242UL, 2847276077UL, 1857504125UL, 253542783UL, 1394668680UL, 2783467746UL, 3122875931UL, 446601186UL, 1228837642UL, 2590549096UL, 2843506874UL, 745391893UL, 1404094021UL, 1324404436UL, 347299411UL, 645865358UL, 2862243948UL, 1204315994UL, 1455458347UL, 4028305509UL, 1924727700UL, 1905843757UL, 1483930049UL, 330348422UL, 2251238906UL, 1840668755UL, 1671024110UL, 4079375869UL, +606568968UL, 4080554282UL, 3886777251UL, 525214560UL, 1972466543UL, 1703103913UL, 3280177496UL, 2530126952UL, 1445252054UL, 2315649878UL, 3946153427UL, 2094983509UL, 1599103627UL, 899111545UL, 3946601974UL, 2053673584UL, 1446566513UL, 4070101360UL, 2379218430UL, 946001131UL, 4184236551UL, 2945613775UL, 2445126690UL, 2507004728UL, 4050415702UL, 3890831500UL, 2815036731UL, 2968121571UL, 340092998UL, 429296098UL, 228493148UL, 3298867574UL, +3901803457UL, 1134820236UL, 288696971UL, 2321943990UL, 3280367987UL, 1589814289UL, 1380146522UL, 646098313UL, 1765624343UL, 2536311658UL, 670777956UL, 3250735726UL, 3495239618UL, 1772431608UL, 3726225049UL, 4050232394UL, 741626628UL, 2451882102UL, 3386124330UL, 3460165725UL, 1132827700UL, 1626575269UL, 2569947980UL, 860947846UL, 2961109404UL, 1280520333UL, 2601765059UL, 2550590348UL, 2298495740UL, 755823086UL, 1073889810UL, 3900360190UL, +396836243UL, 2702634902UL, 3036027780UL, 1754651820UL, 3848370775UL, 4113753945UL, 3836550212UL, 3784147349UL, 464826842UL, 594136009UL, 1679465955UL, 1500399122UL, 2128970592UL, 4198686893UL, 4234959779UL, 3670094401UL, 1632934875UL, 421961324UL, 416103731UL, 3724691332UL, 1428205363UL, 2330377177UL, 3407618159UL, 2637470915UL, 1435176883UL, 925973933UL, 2558479866UL, 1274860184UL, 2546319147UL, 4029854347UL, 3002516723UL, 1331271216UL, +671480036UL, 681365672UL, 1352519428UL, 13398705UL, 1532459856UL, 1150967289UL, 742849231UL, 3726033518UL, 2407091731UL, 1766120506UL, 3106945136UL, 1323833820UL, 584793525UL, 2706493003UL, 3817434387UL, 2013357219UL, 3747238187UL, 3149885896UL, 3512276852UL, 203757UL, 3595347994UL, 3817319503UL, 4152622551UL, 4022346903UL, 3438004885UL, 367216863UL, 99009902UL, 2670729696UL, 3290854172UL, 1092092654UL, 3130148315UL, 4199909720UL, +658184940UL, 518096293UL, 982576981UL, 3004378899UL, 1648201186UL, 3723004242UL, 2847276077UL, 33113683UL, 253542783UL, 1394668680UL, 2783467746UL, 3122875931UL, 3109404671UL, 1228837642UL, 2590549096UL, 2843506874UL, 745391893UL, 809710525UL, 1324404436UL, 347299411UL, 645865358UL, 2862243948UL, 3652256751UL, 1455458347UL, 4028305509UL, 1924727700UL, 1905843757UL, 2035132481UL, 330348422UL, 2251238906UL, 1840668755UL, 1671024110UL, +3593348393UL, 4151905045UL, 3398483770UL, 611142788UL, 1798029112UL, 2747225670UL, 2894981396UL, 2117120651UL, 3087941624UL, 416876364UL, 700011792UL, 63929447UL, 822005210UL, 3483417647UL, 3513365134UL, 3071572873UL, 1925919001UL, 2778688996UL, 3079943255UL, 1252316311UL, 91270196UL, 3469862149UL, 156659741UL, 1342755036UL, 3821302858UL, 1790046971UL, 289329863UL, 1357914395UL, 4143182690UL, 2590503919UL, 3242437796UL, 1341085928UL, +2685277054UL, 727602392UL, 2581493226UL, 3216496864UL, 2171373196UL, 3767765187UL, 1895767358UL, 1029452326UL, 851913526UL, 1746266839UL, 3370323171UL, 648118190UL, 3244211645UL, 2623946928UL, 3859087079UL, 384443034UL, 2026989771UL, 802104797UL, 2201121552UL, 725742304UL, 1673563239UL, 4045658814UL, 2682764476UL, 3032306650UL, 2725871420UL, 3467522540UL, 534803010UL, 1135606913UL, 871336950UL, 937160030UL, 3384357161UL, 641566845UL, +2267407903UL, 331847343UL, 787968740UL, 2673012251UL, 2066357778UL, 2740382722UL, 1638377946UL, 2260504282UL, 3513172717UL, 238548903UL, 2203496688UL, 630532448UL, 3702112076UL, 2635952931UL, 3344713216UL, 139406056UL, 2369004628UL, 3547213209UL, 2944858950UL, 1231203228UL, 616949630UL, 2619739101UL, 89360251UL, 2364353701UL, 1025345607UL, 4177965685UL, 62274372UL, 3059207586UL, 3303376016UL, 2919795870UL, 3676526103UL, 2689781822UL, +1062293263UL, 2684605838UL, 863975243UL, 723728777UL, 1057919510UL, 1708017843UL, 4264127977UL, 3013938022UL, 3958746896UL, 328415103UL, 1117948849UL, 751056929UL, 2442147201UL, 1781170563UL, 765377308UL, 961452970UL, 4247303973UL, 2233034754UL, 86997820UL, 3495561473UL, 3075957349UL, 3152032365UL, 1220657606UL, 708134514UL, 26714613UL, 3749542051UL, 1640668224UL, 2252760600UL, 1635050662UL, 947216628UL, 3612773344UL, 4089189500UL, +3647048119UL, 979491227UL, 4149824933UL, 3160885292UL, 2808843788UL, 998859510UL, 3903167193UL, 1728999561UL, 3673946130UL, 279338980UL, 2507635299UL, 1614929524UL, 302060483UL, 2874453052UL, 3798613814UL, 2013436766UL, 3514754020UL, 2923162106UL, 2658720327UL, 3498579091UL, 3292220096UL, 3796129102UL, 1907288796UL, 2820663603UL, 4276052248UL, 247755133UL, 2088596201UL, 3154955976UL, 3309397641UL, 3606171919UL, 1356791029UL, 1030266022UL, +}, +{ +3868946146UL, 1938156793UL, 1877502872UL, 1408917625UL, 1549117911UL, 2465501566UL, 4218547770UL, 2942249332UL, 2731789075UL, 2366036899UL, 1312641799UL, 2243363271UL, 2238839307UL, 384814263UL, 1552361757UL, 3521369641UL, 431721717UL, 3089625732UL, 1023760034UL, 53847139UL, 2240881978UL, 3178046414UL, 145135653UL, 1580878781UL, 3500228040UL, 3360910006UL, 3285542950UL, 3330062556UL, 2870158227UL, 1481496810UL, 4222704363UL, 2973046526UL, +435155769UL, 3234730070UL, 3306545960UL, 2539776908UL, 3991420334UL, 125389349UL, 2397544348UL, 2504790975UL, 886432257UL, 1804136430UL, 1506551086UL, 219847214UL, 890282686UL, 1489840806UL, 2536942497UL, 87527661UL, 1822718904UL, 3984956867UL, 2334419518UL, 4065487054UL, 992104547UL, 1566792845UL, 1068226712UL, 2622731799UL, 921431708UL, 2833392639UL, 640267449UL, 324907409UL, 3911698049UL, 2108189994UL, 1623761598UL, 52771719UL, +467926435UL, 2811768106UL, 3760723083UL, 906402727UL, 3438479463UL, 2064004404UL, 988123982UL, 563076447UL, 2979641383UL, 1366086397UL, 2078608605UL, 3868491514UL, 1077957067UL, 615363273UL, 1388831706UL, 1586480552UL, 4216838311UL, 3587550780UL, 2057048927UL, 2814838921UL, 2454041809UL, 180612020UL, 930406098UL, 4286819113UL, 2756562967UL, 3404265234UL, 3844482428UL, 467484533UL, 4122644954UL, 3517116598UL, 1887163240UL, 4217569180UL, +4191149652UL, 2756931330UL, 3702787956UL, 152166773UL, 146763911UL, 536678737UL, 481385008UL, 3681433244UL, 1194909733UL, 3713568496UL, 3927837202UL, 846842608UL, 687314083UL, 1144793694UL, 1062075916UL, 3017627145UL, 1296695243UL, 981862419UL, 2363304726UL, 3242788356UL, 3359957762UL, 4249190787UL, 1697910336UL, 3286799886UL, 1063822293UL, 3246091430UL, 743808559UL, 2137668568UL, 2812072749UL, 2303791182UL, 3161789548UL, 2911126624UL, +4087873192UL, 1813622227UL, 1272618849UL, 1882292328UL, 3861455677UL, 2921641470UL, 3079812494UL, 2814569163UL, 1975646942UL, 2826176621UL, 1896904368UL, 831552834UL, 2935863403UL, 449217054UL, 3688067832UL, 1048877596UL, 1613227043UL, 553867520UL, 3682575786UL, 3058863948UL, 4200858129UL, 4131625UL, 2434123776UL, 2235627905UL, 2905358693UL, 3429312266UL, 3363231514UL, 1182242507UL, 2792234422UL, 1843330053UL, 4192875151UL, 1088813348UL, +357805687UL, 3868946146UL, 1938156793UL, 1877502872UL, 1408917625UL, 30638250UL, 2465501566UL, 4218547770UL, 2942249332UL, 2731789075UL, 448998968UL, 1312641799UL, 2243363271UL, 2238839307UL, 384814263UL, 2229663001UL, 3521369641UL, 431721717UL, 3089625732UL, 1023760034UL, 790771414UL, 2240881978UL, 3178046414UL, 145135653UL, 1580878781UL, 847577516UL, 3360910006UL, 3285542950UL, 3330062556UL, 2870158227UL, 112738978UL, 4222704363UL, +2973046526UL, 435155769UL, 3234730070UL, 1135073835UL, 2539776908UL, 3991420334UL, 125389349UL, 2397544348UL, 1243128255UL, 886432257UL, 1804136430UL, 1506551086UL, 219847214UL, 875051553UL, 1489840806UL, 2536942497UL, 87527661UL, 1822718904UL, 1883615145UL, 2334419518UL, 4065487054UL, 992104547UL, 1566792845UL, 1037132511UL, 2622731799UL, 921431708UL, 2833392639UL, 640267449UL, 504304037UL, 3911698049UL, 2108189994UL, 1623761598UL, +52771719UL, 3969520254UL, 2811768106UL, 3760723083UL, 906402727UL, 3438479463UL, 3707538496UL, 988123982UL, 563076447UL, 2979641383UL, 1366086397UL, 3577913613UL, 3868491514UL, 1077957067UL, 615363273UL, 1388831706UL, 903353909UL, 4216838311UL, 3587550780UL, 2057048927UL, 2814838921UL, 3532304828UL, 180612020UL, 930406098UL, 4286819113UL, 2756562967UL, 1950528802UL, 3844482428UL, 467484533UL, 4122644954UL, 3517116598UL, 139409766UL, +4217569180UL, 4191149652UL, 2756931330UL, 3702787956UL, 504815033UL, 146763911UL, 536678737UL, 481385008UL, 3681433244UL, 2166865052UL, 3713568496UL, 3927837202UL, 846842608UL, 687314083UL, 135403542UL, 1062075916UL, 3017627145UL, 1296695243UL, 981862419UL, 2405232584UL, 3242788356UL, 3359957762UL, 4249190787UL, 1697910336UL, 3517294012UL, 1063822293UL, 3246091430UL, 743808559UL, 2137668568UL, 2962825355UL, 2303791182UL, 3161789548UL, +2911126624UL, 4087873192UL, 2344237973UL, 1272618849UL, 1882292328UL, 3861455677UL, 2921641470UL, 1062672856UL, 2814569163UL, 1975646942UL, 2826176621UL, 1896904368UL, 3172875195UL, 2935863403UL, 449217054UL, 3688067832UL, 1048877596UL, 983648949UL, 553867520UL, 3682575786UL, 3058863948UL, 4200858129UL, 2552994282UL, 2434123776UL, 2235627905UL, 2905358693UL, 3429312266UL, 461707508UL, 1182242507UL, 2792234422UL, 1843330053UL, 4192875151UL, +2557078297UL, 357805687UL, 3868946146UL, 1938156793UL, 1877502872UL, 1178921294UL, 30638250UL, 2465501566UL, 4218547770UL, 2942249332UL, 2597087237UL, 448998968UL, 1312641799UL, 2243363271UL, 2238839307UL, 3465588695UL, 2229663001UL, 3521369641UL, 431721717UL, 3089625732UL, 2420359327UL, 790771414UL, 2240881978UL, 3178046414UL, 145135653UL, 3411014139UL, 847577516UL, 3360910006UL, 3285542950UL, 3330062556UL, 4257518865UL, 112738978UL, +4222704363UL, 2973046526UL, 435155769UL, 1154160505UL, 1135073835UL, 2539776908UL, 3991420334UL, 125389349UL, 1396475349UL, 1243128255UL, 886432257UL, 1804136430UL, 1506551086UL, 3727497731UL, 875051553UL, 1489840806UL, 2536942497UL, 87527661UL, 2521823325UL, 1883615145UL, 2334419518UL, 4065487054UL, 992104547UL, 3431387970UL, 1037132511UL, 2622731799UL, 921431708UL, 2833392639UL, 780276883UL, 504304037UL, 3911698049UL, 2108189994UL, +1623761598UL, 1832564202UL, 3969520254UL, 2811768106UL, 3760723083UL, 906402727UL, 2319993554UL, 3707538496UL, 988123982UL, 563076447UL, 2979641383UL, 3703509163UL, 3577913613UL, 3868491514UL, 1077957067UL, 615363273UL, 3925135746UL, 903353909UL, 4216838311UL, 3587550780UL, 2057048927UL, 2129250845UL, 3532304828UL, 180612020UL, 930406098UL, 4286819113UL, 571849466UL, 1950528802UL, 3844482428UL, 467484533UL, 4122644954UL, 3696836546UL, +139409766UL, 4217569180UL, 4191149652UL, 2756931330UL, 84389584UL, 504815033UL, 146763911UL, 536678737UL, 481385008UL, 281139563UL, 2166865052UL, 3713568496UL, 3927837202UL, 846842608UL, 2123715146UL, 135403542UL, 1062075916UL, 3017627145UL, 1296695243UL, 4206227732UL, 2405232584UL, 3242788356UL, 3359957762UL, 4249190787UL, 2766470555UL, 3517294012UL, 1063822293UL, 3246091430UL, 743808559UL, 2821229002UL, 2962825355UL, 2303791182UL, +3161789548UL, 2911126624UL, 503886017UL, 2344237973UL, 1272618849UL, 1882292328UL, 3861455677UL, 4158985014UL, 1062672856UL, 2814569163UL, 1975646942UL, 2826176621UL, 4118784229UL, 3172875195UL, 2935863403UL, 449217054UL, 3688067832UL, 3556237148UL, 983648949UL, 553867520UL, 3682575786UL, 3058863948UL, 3200838331UL, 2552994282UL, 2434123776UL, 2235627905UL, 2905358693UL, 4178312045UL, 461707508UL, 1182242507UL, 2792234422UL, 1843330053UL, +3597816691UL, 2557078297UL, 357805687UL, 3868946146UL, 1938156793UL, 2168462050UL, 1178921294UL, 30638250UL, 2465501566UL, 4218547770UL, 4101101381UL, 2597087237UL, 448998968UL, 1312641799UL, 2243363271UL, 313553894UL, 3465588695UL, 2229663001UL, 3521369641UL, 431721717UL, 737541534UL, 2420359327UL, 790771414UL, 2240881978UL, 3178046414UL, 326569272UL, 3411014139UL, 847577516UL, 3360910006UL, 3285542950UL, 3098408987UL, 4257518865UL, +112738978UL, 4222704363UL, 2973046526UL, 3668411828UL, 1154160505UL, 1135073835UL, 2539776908UL, 3991420334UL, 2902976896UL, 1396475349UL, 1243128255UL, 886432257UL, 1804136430UL, 2162242501UL, 3727497731UL, 875051553UL, 1489840806UL, 2536942497UL, 2238214198UL, 2521823325UL, 1883615145UL, 2334419518UL, 4065487054UL, 1081167745UL, 3431387970UL, 1037132511UL, 2622731799UL, 921431708UL, 2612105434UL, 780276883UL, 504304037UL, 3911698049UL, +2108189994UL, 2518535877UL, 1832564202UL, 3969520254UL, 2811768106UL, 3760723083UL, 2894544992UL, 2319993554UL, 3707538496UL, 988123982UL, 563076447UL, 719340658UL, 3703509163UL, 3577913613UL, 3868491514UL, 1077957067UL, 2371417985UL, 3925135746UL, 903353909UL, 4216838311UL, 3587550780UL, 3146473377UL, 2129250845UL, 3532304828UL, 180612020UL, 930406098UL, 1054512059UL, 571849466UL, 1950528802UL, 3844482428UL, 467484533UL, 1437844285UL, +3696836546UL, 139409766UL, 4217569180UL, 4191149652UL, 1161452915UL, 84389584UL, 504815033UL, 146763911UL, 536678737UL, 3965987378UL, 281139563UL, 2166865052UL, 3713568496UL, 3927837202UL, 2566873330UL, 2123715146UL, 135403542UL, 1062075916UL, 3017627145UL, 3204726297UL, 4206227732UL, 2405232584UL, 3242788356UL, 3359957762UL, 2338319494UL, 2766470555UL, 3517294012UL, 1063822293UL, 3246091430UL, 1531757306UL, 2821229002UL, 2962825355UL, +2303791182UL, 3161789548UL, 2778326467UL, 503886017UL, 2344237973UL, 1272618849UL, 1882292328UL, 1725075819UL, 4158985014UL, 1062672856UL, 2814569163UL, 1975646942UL, 3822868823UL, 4118784229UL, 3172875195UL, 2935863403UL, 449217054UL, 2465297154UL, 3556237148UL, 983648949UL, 553867520UL, 3682575786UL, 4023654874UL, 3200838331UL, 2552994282UL, 2434123776UL, 2235627905UL, 3063253867UL, 4178312045UL, 461707508UL, 1182242507UL, 2792234422UL, +3673318927UL, 1249828417UL, 2772427670UL, 1052324962UL, 3106530204UL, 2843183862UL, 630633945UL, 4140139503UL, 1659674037UL, 1096812757UL, 1376150732UL, 2328468653UL, 1410746620UL, 4025107990UL, 3335632421UL, 2754906610UL, 1615859006UL, 285467698UL, 4013475548UL, 1287384555UL, 1191111485UL, 1999165134UL, 2396354947UL, 1628158236UL, 3586708909UL, 228664781UL, 2501369720UL, 2516229872UL, 2977432606UL, 1745869751UL, 750661412UL, 1142144084UL, +2705268946UL, 1728488244UL, 589587862UL, 3604281130UL, 3217245915UL, 2061424631UL, 1918958878UL, 1162850007UL, 438550637UL, 1774088146UL, 3237803593UL, 827476363UL, 404982536UL, 2344744845UL, 3416436851UL, 369597250UL, 287618335UL, 1349740180UL, 3489688427UL, 417859991UL, 3229729092UL, 3214122057UL, 3955335849UL, 3014669381UL, 2178319957UL, 1259991234UL, 2689513541UL, 2628816894UL, 3734652479UL, 4202568782UL, 3149274749UL, 497295490UL, +3427602420UL, 3229774907UL, 59257138UL, 856364156UL, 429586733UL, 1800559699UL, 1300239050UL, 1311125646UL, 257421988UL, 3749074142UL, 1648939149UL, 1914174865UL, 105489877UL, 3599116888UL, 2695725484UL, 1543985792UL, 3210070699UL, 1867126432UL, 3088920410UL, 953084407UL, 2185095866UL, 1427606476UL, 1572442276UL, 3322674991UL, 3578824788UL, 1156246244UL, 2938200612UL, 3409545464UL, 215820858UL, 2279282461UL, 3861049095UL, 1589517366UL, +208707366UL, 2741570297UL, 440313302UL, 864288468UL, 1564945290UL, 1050929272UL, 3037450392UL, 1101323242UL, 1200278943UL, 3005564105UL, 3847988630UL, 3251750599UL, 2608433412UL, 3106720723UL, 1522694503UL, 3857782840UL, 4282681349UL, 2229263718UL, 4106780914UL, 125648941UL, 1933617693UL, 2971178569UL, 3537872030UL, 448962137UL, 652123777UL, 2393871920UL, 3938047691UL, 244410098UL, 3110791961UL, 3122318189UL, 877378106UL, 3683644255UL, +4279094311UL, 3638987055UL, 667681197UL, 1679868535UL, 1938378101UL, 1331340184UL, 734163051UL, 3409564713UL, 955108672UL, 3969637663UL, 156515523UL, 1871394552UL, 590275639UL, 3237133664UL, 898438533UL, 2291347006UL, 644781653UL, 3575493549UL, 1206698159UL, 2484805619UL, 2931447110UL, 2411269190UL, 3866437145UL, 161562563UL, 3077166456UL, 792874130UL, 3193406610UL, 2500233218UL, 596837225UL, 3667458052UL, 3239960816UL, 2271901243UL, +}, +{ +3975736867UL, 2402230281UL, 4092718962UL, 3100052505UL, 3277909563UL, 2827154828UL, 1067483357UL, 3495429909UL, 426635932UL, 2702495453UL, 725679489UL, 3705541400UL, 1308182381UL, 27549785UL, 3000675918UL, 2982141597UL, 1090931027UL, 755020243UL, 3986354189UL, 2529541113UL, 452574019UL, 2384876926UL, 2147764179UL, 1360907484UL, 2072364695UL, 3034185952UL, 2765119653UL, 3279755577UL, 3828140333UL, 582568392UL, 4228353628UL, 701214306UL, +2460043371UL, 3943376509UL, 2443090800UL, 2481277520UL, 859309333UL, 2928621220UL, 1933644685UL, 3803162893UL, 3310629548UL, 2361261213UL, 790233558UL, 2517540072UL, 2823327610UL, 2952921690UL, 3295251862UL, 1089451775UL, 2637751681UL, 1648031370UL, 1343061717UL, 2355026672UL, 67684812UL, 4019593497UL, 2636283634UL, 1051433451UL, 51111285UL, 15338687UL, 3779021741UL, 3987886044UL, 70037785UL, 2009147353UL, 4236701871UL, 928261128UL, +2185183571UL, 2793993680UL, 2975111058UL, 3730415022UL, 3316612678UL, 823585671UL, 4153354125UL, 509071385UL, 2056228251UL, 4034784810UL, 96820040UL, 169863045UL, 932848332UL, 2282651407UL, 747279843UL, 1387211022UL, 2410099142UL, 3394315084UL, 3191572807UL, 4073182500UL, 3768455462UL, 3712420663UL, 3000991259UL, 249137656UL, 2477445202UL, 3952155443UL, 392730170UL, 4208559971UL, 24751401UL, 661761054UL, 1574175475UL, 2715927647UL, +985309803UL, 2570053358UL, 619269634UL, 3890591314UL, 1129119636UL, 3133886450UL, 328788870UL, 3449809720UL, 1380118080UL, 2719792059UL, 691527418UL, 3487733607UL, 3819095050UL, 3367871088UL, 709089170UL, 1057897966UL, 1938975941UL, 4082466714UL, 251564920UL, 3083496965UL, 1040123365UL, 295024253UL, 2788334176UL, 3430095934UL, 3641758945UL, 2029993123UL, 3231254260UL, 150555625UL, 2270671577UL, 2032382533UL, 2088497043UL, 1392075576UL, +644811077UL, 2122632989UL, 3224165725UL, 1571908345UL, 2558692460UL, 1493305706UL, 4064652450UL, 448105905UL, 699188129UL, 2017324335UL, 4286307548UL, 2415725473UL, 3976741021UL, 3526784185UL, 2882973520UL, 3420335125UL, 2034028744UL, 1425242390UL, 982315917UL, 2614735561UL, 2439972944UL, 2518992720UL, 3792239985UL, 3260669732UL, 2586472751UL, 3432756715UL, 1318634102UL, 3722487277UL, 3037304631UL, 433233786UL, 3750002877UL, 2504731459UL, +1111327015UL, 3975736867UL, 2402230281UL, 4092718962UL, 3100052505UL, 3521430425UL, 2827154828UL, 1067483357UL, 3495429909UL, 426635932UL, 2034644068UL, 725679489UL, 3705541400UL, 1308182381UL, 27549785UL, 3001720496UL, 2982141597UL, 1090931027UL, 755020243UL, 3986354189UL, 307638580UL, 452574019UL, 2384876926UL, 2147764179UL, 1360907484UL, 1701580099UL, 3034185952UL, 2765119653UL, 3279755577UL, 3828140333UL, 2659043235UL, 4228353628UL, +701214306UL, 2460043371UL, 3943376509UL, 2084857792UL, 2481277520UL, 859309333UL, 2928621220UL, 1933644685UL, 4152646669UL, 3310629548UL, 2361261213UL, 790233558UL, 2517540072UL, 481283060UL, 2952921690UL, 3295251862UL, 1089451775UL, 2637751681UL, 2915212660UL, 1343061717UL, 2355026672UL, 67684812UL, 4019593497UL, 3290479436UL, 1051433451UL, 51111285UL, 15338687UL, 3779021741UL, 1430944862UL, 70037785UL, 2009147353UL, 4236701871UL, +928261128UL, 2063919641UL, 2793993680UL, 2975111058UL, 3730415022UL, 3316612678UL, 2373806232UL, 4153354125UL, 509071385UL, 2056228251UL, 4034784810UL, 1912268707UL, 169863045UL, 932848332UL, 2282651407UL, 747279843UL, 3712980941UL, 2410099142UL, 3394315084UL, 3191572807UL, 4073182500UL, 4262344652UL, 3712420663UL, 3000991259UL, 249137656UL, 2477445202UL, 3374467273UL, 392730170UL, 4208559971UL, 24751401UL, 661761054UL, 1670592959UL, +2715927647UL, 985309803UL, 2570053358UL, 619269634UL, 830547082UL, 1129119636UL, 3133886450UL, 328788870UL, 3449809720UL, 202644333UL, 2719792059UL, 691527418UL, 3487733607UL, 3819095050UL, 1400269159UL, 709089170UL, 1057897966UL, 1938975941UL, 4082466714UL, 3393893128UL, 3083496965UL, 1040123365UL, 295024253UL, 2788334176UL, 1219456UL, 3641758945UL, 2029993123UL, 3231254260UL, 150555625UL, 3713963210UL, 2032382533UL, 2088497043UL, +1392075576UL, 644811077UL, 3733090890UL, 3224165725UL, 1571908345UL, 2558692460UL, 1493305706UL, 1678929187UL, 448105905UL, 699188129UL, 2017324335UL, 4286307548UL, 3368868963UL, 3976741021UL, 3526784185UL, 2882973520UL, 3420335125UL, 3233347584UL, 1425242390UL, 982315917UL, 2614735561UL, 2439972944UL, 4172908214UL, 3792239985UL, 3260669732UL, 2586472751UL, 3432756715UL, 1926157640UL, 3722487277UL, 3037304631UL, 433233786UL, 3750002877UL, +625648993UL, 1111327015UL, 3975736867UL, 2402230281UL, 4092718962UL, 1349560774UL, 3521430425UL, 2827154828UL, 1067483357UL, 3495429909UL, 2808148912UL, 2034644068UL, 725679489UL, 3705541400UL, 1308182381UL, 212242504UL, 3001720496UL, 2982141597UL, 1090931027UL, 755020243UL, 2510536004UL, 307638580UL, 452574019UL, 2384876926UL, 2147764179UL, 3227931749UL, 1701580099UL, 3034185952UL, 2765119653UL, 3279755577UL, 1054678914UL, 2659043235UL, +4228353628UL, 701214306UL, 2460043371UL, 381309305UL, 2084857792UL, 2481277520UL, 859309333UL, 2928621220UL, 891630344UL, 4152646669UL, 3310629548UL, 2361261213UL, 790233558UL, 1490030690UL, 481283060UL, 2952921690UL, 3295251862UL, 1089451775UL, 2025962691UL, 2915212660UL, 1343061717UL, 2355026672UL, 67684812UL, 2217081575UL, 3290479436UL, 1051433451UL, 51111285UL, 15338687UL, 3455020635UL, 1430944862UL, 70037785UL, 2009147353UL, +4236701871UL, 1155691935UL, 2063919641UL, 2793993680UL, 2975111058UL, 3730415022UL, 403147571UL, 2373806232UL, 4153354125UL, 509071385UL, 2056228251UL, 444685935UL, 1912268707UL, 169863045UL, 932848332UL, 2282651407UL, 2077207745UL, 3712980941UL, 2410099142UL, 3394315084UL, 3191572807UL, 640536184UL, 4262344652UL, 3712420663UL, 3000991259UL, 249137656UL, 368243227UL, 3374467273UL, 392730170UL, 4208559971UL, 24751401UL, 495648080UL, +1670592959UL, 2715927647UL, 985309803UL, 2570053358UL, 2181488546UL, 830547082UL, 1129119636UL, 3133886450UL, 328788870UL, 2497762979UL, 202644333UL, 2719792059UL, 691527418UL, 3487733607UL, 1976943620UL, 1400269159UL, 709089170UL, 1057897966UL, 1938975941UL, 2071351862UL, 3393893128UL, 3083496965UL, 1040123365UL, 295024253UL, 1440317859UL, 1219456UL, 3641758945UL, 2029993123UL, 3231254260UL, 952956380UL, 3713963210UL, 2032382533UL, +2088497043UL, 1392075576UL, 4180475645UL, 3733090890UL, 3224165725UL, 1571908345UL, 2558692460UL, 3482549931UL, 1678929187UL, 448105905UL, 699188129UL, 2017324335UL, 2431113987UL, 3368868963UL, 3976741021UL, 3526784185UL, 2882973520UL, 1900625235UL, 3233347584UL, 1425242390UL, 982315917UL, 2614735561UL, 1128074864UL, 4172908214UL, 3792239985UL, 3260669732UL, 2586472751UL, 4095880420UL, 1926157640UL, 3722487277UL, 3037304631UL, 433233786UL, +2927295412UL, 625648993UL, 1111327015UL, 3975736867UL, 2402230281UL, 259216032UL, 1349560774UL, 3521430425UL, 2827154828UL, 1067483357UL, 989690947UL, 2808148912UL, 2034644068UL, 725679489UL, 3705541400UL, 588787520UL, 212242504UL, 3001720496UL, 2982141597UL, 1090931027UL, 1235811382UL, 2510536004UL, 307638580UL, 452574019UL, 2384876926UL, 3536994565UL, 3227931749UL, 1701580099UL, 3034185952UL, 2765119653UL, 463890041UL, 1054678914UL, +2659043235UL, 4228353628UL, 701214306UL, 3085494195UL, 381309305UL, 2084857792UL, 2481277520UL, 859309333UL, 3760199179UL, 891630344UL, 4152646669UL, 3310629548UL, 2361261213UL, 2550680915UL, 1490030690UL, 481283060UL, 2952921690UL, 3295251862UL, 4195487760UL, 2025962691UL, 2915212660UL, 1343061717UL, 2355026672UL, 339445869UL, 2217081575UL, 3290479436UL, 1051433451UL, 51111285UL, 1113202216UL, 3455020635UL, 1430944862UL, 70037785UL, +2009147353UL, 3982848623UL, 1155691935UL, 2063919641UL, 2793993680UL, 2975111058UL, 1725337613UL, 403147571UL, 2373806232UL, 4153354125UL, 509071385UL, 1474832043UL, 444685935UL, 1912268707UL, 169863045UL, 932848332UL, 1500855137UL, 2077207745UL, 3712980941UL, 2410099142UL, 3394315084UL, 2800379966UL, 640536184UL, 4262344652UL, 3712420663UL, 3000991259UL, 1028021485UL, 368243227UL, 3374467273UL, 392730170UL, 4208559971UL, 108468246UL, +495648080UL, 1670592959UL, 2715927647UL, 985309803UL, 61959589UL, 2181488546UL, 830547082UL, 1129119636UL, 3133886450UL, 3912020361UL, 2497762979UL, 202644333UL, 2719792059UL, 691527418UL, 1984193076UL, 1976943620UL, 1400269159UL, 709089170UL, 1057897966UL, 2381612490UL, 2071351862UL, 3393893128UL, 3083496965UL, 1040123365UL, 391784014UL, 1440317859UL, 1219456UL, 3641758945UL, 2029993123UL, 2260373342UL, 952956380UL, 3713963210UL, +2032382533UL, 2088497043UL, 135943164UL, 4180475645UL, 3733090890UL, 3224165725UL, 1571908345UL, 2660287325UL, 3482549931UL, 1678929187UL, 448105905UL, 699188129UL, 4104693318UL, 2431113987UL, 3368868963UL, 3976741021UL, 3526784185UL, 113762138UL, 1900625235UL, 3233347584UL, 1425242390UL, 982315917UL, 599246177UL, 1128074864UL, 4172908214UL, 3792239985UL, 3260669732UL, 2309689974UL, 4095880420UL, 1926157640UL, 3722487277UL, 3037304631UL, +3765223460UL, 866296319UL, 1169380319UL, 2919436659UL, 3370646420UL, 1866719277UL, 3226685069UL, 4252262342UL, 1835269960UL, 1170376930UL, 1357078768UL, 269175192UL, 3826888026UL, 3430363541UL, 1920758494UL, 51532769UL, 2919489927UL, 1568325914UL, 3184357856UL, 43519013UL, 2108988015UL, 1398495041UL, 2844640139UL, 2317092036UL, 1774750014UL, 2690907136UL, 1834465421UL, 1106469655UL, 2149810726UL, 4265420439UL, 2048218411UL, 1399986034UL, +1361619115UL, 2504769226UL, 913700780UL, 2382994726UL, 4292849877UL, 1381838410UL, 250258264UL, 1828569640UL, 1732718872UL, 1869949326UL, 835188347UL, 4180489913UL, 3049522050UL, 535168392UL, 3972173823UL, 2763844722UL, 3401884753UL, 3750694101UL, 851518496UL, 1015521371UL, 1511969218UL, 1597622074UL, 3810841601UL, 3326003776UL, 3141062630UL, 552856274UL, 4059179808UL, 175647012UL, 3893497501UL, 1805118717UL, 1064213711UL, 2310866839UL, +1397146463UL, 1798096676UL, 279868399UL, 1926726615UL, 2773068510UL, 347721208UL, 4099183723UL, 509136218UL, 2833615756UL, 3960499694UL, 4236258712UL, 1765641675UL, 535748563UL, 354515646UL, 3307314159UL, 3160079941UL, 3252681800UL, 2568363625UL, 3818514182UL, 3738662353UL, 899056999UL, 2531772068UL, 647726503UL, 2895823632UL, 393777910UL, 1759531813UL, 2363148604UL, 2931477989UL, 3381169914UL, 3877595131UL, 2375539210UL, 557544627UL, +273611522UL, 2717517554UL, 1935966767UL, 1738732887UL, 29153600UL, 20993454UL, 3758163226UL, 1692844400UL, 2176938194UL, 378940221UL, 2888599759UL, 1173120554UL, 2732575460UL, 3912766812UL, 522606644UL, 1925230852UL, 3887440328UL, 2111843275UL, 3549473366UL, 922916775UL, 2889744544UL, 2970467682UL, 3039277863UL, 990580154UL, 55435595UL, 1665634070UL, 3043418336UL, 2792050230UL, 2762503138UL, 1402344059UL, 2099263558UL, 3945248675UL, +3925566467UL, 2413979948UL, 463637252UL, 3768636616UL, 3374572388UL, 2217956879UL, 791988933UL, 382210765UL, 1715859444UL, 3462446413UL, 971427992UL, 3255404695UL, 2001750035UL, 2214129237UL, 320812374UL, 3688098101UL, 920365480UL, 2819401059UL, 2932570681UL, 3749857130UL, 523943786UL, 1271514748UL, 4078439472UL, 3501181265UL, 2475869985UL, 1797996951UL, 2300820710UL, 3994893924UL, 1739992082UL, 2475950326UL, 3780826558UL, 1018851411UL, +}, + +}; +#ifndef __CUDACC_RTC__ +CURAND_XORWOW_PRECALCULATED_HOST_QUALIFIERS unsigned int precalc_xorwow_matrix_host[32][800] = { +{ +850664906UL, 2293210629UL, 1517805917UL, 1215500405UL, 1612415445UL, 645388200UL, 824349799UL, 3517232886UL, 4075591755UL, 3089899292UL, 4249786064UL, 3811424903UL, 1100783479UL, 53649761UL, 2817264826UL, 3159462529UL, 1654848550UL, 950025444UL, 3095510002UL, 4080567211UL, 4111078399UL, 3241719305UL, 2788212779UL, 4256963770UL, 2426893717UL, 4190211142UL, 1420776905UL, 3780537969UL, 1102912875UL, 1657948873UL, 3354905256UL, 2519610308UL, +515777663UL, 3396785394UL, 1832603711UL, 1154211550UL, 1915690212UL, 1933919046UL, 789578337UL, 337961173UL, 1359089498UL, 2249086205UL, 3417955173UL, 862571348UL, 528120760UL, 1265685672UL, 1970052076UL, 3585976752UL, 3645339918UL, 312171257UL, 1360991400UL, 1994321680UL, 2327168468UL, 2540437053UL, 1180483641UL, 2217962701UL, 182726833UL, 590204372UL, 1904496495UL, 2545607041UL, 3697978033UL, 1084030545UL, 3397906968UL, 2192325323UL, +2704204176UL, 1069092002UL, 2364406907UL, 1578647245UL, 3561974633UL, 3437665426UL, 1464127305UL, 1616628807UL, 2243114101UL, 3639967880UL, 1702613633UL, 2437350057UL, 39991274UL, 2024323584UL, 3795072940UL, 3604530798UL, 443099203UL, 643536212UL, 1919517328UL, 3931285769UL, 427935569UL, 276421624UL, 2492081750UL, 262729512UL, 3088549877UL, 2922650665UL, 1816283755UL, 4246096489UL, 842575914UL, 1460435650UL, 3050522190UL, 2640849794UL, +3697925816UL, 3465779075UL, 3856929655UL, 1365559780UL, 2897029415UL, 2747033756UL, 3611830629UL, 1891542518UL, 1897590206UL, 437451803UL, 677924906UL, 123809117UL, 3940574372UL, 687640291UL, 3488484529UL, 470218446UL, 1092571016UL, 1537938503UL, 1073323937UL, 611300083UL, 3809285994UL, 3975678726UL, 925845389UL, 2514775760UL, 2859302390UL, 2761919483UL, 993285307UL, 164095287UL, 3736193671UL, 2078946336UL, 1418537059UL, 1202525920UL, +4234029440UL, 1313593624UL, 2484428922UL, 1833969372UL, 661495122UL, 2217907395UL, 2795045321UL, 2950835531UL, 1402379354UL, 351314168UL, 1902476749UL, 1914974334UL, 2873973176UL, 1321203603UL, 3316118265UL, 3282193947UL, 1342191737UL, 793441242UL, 3281524559UL, 296088733UL, 487851702UL, 712098215UL, 1388727135UL, 1705533557UL, 3557800292UL, 399729516UL, 1355829467UL, 291276309UL, 421164833UL, 1318404599UL, 2064519128UL, 1161612642UL, +2076623594UL, 850664906UL, 2293210629UL, 1517805917UL, 1215500405UL, 3847487204UL, 645388200UL, 824349799UL, 3517232886UL, 4075591755UL, 2755872609UL, 4249786064UL, 3811424903UL, 1100783479UL, 53649761UL, 1417544262UL, 3159462529UL, 1654848550UL, 950025444UL, 3095510002UL, 1908900347UL, 4111078399UL, 3241719305UL, 2788212779UL, 4256963770UL, 3750258343UL, 4190211142UL, 1420776905UL, 3780537969UL, 1102912875UL, 1690550UL, 3354905256UL, +2519610308UL, 515777663UL, 3396785394UL, 2658162202UL, 1154211550UL, 1915690212UL, 1933919046UL, 789578337UL, 189880016UL, 1359089498UL, 2249086205UL, 3417955173UL, 862571348UL, 998719835UL, 1265685672UL, 1970052076UL, 3585976752UL, 3645339918UL, 2973042959UL, 1360991400UL, 1994321680UL, 2327168468UL, 2540437053UL, 2283905032UL, 2217962701UL, 182726833UL, 590204372UL, 1904496495UL, 110719262UL, 3697978033UL, 1084030545UL, 3397906968UL, +2192325323UL, 4133333579UL, 1069092002UL, 2364406907UL, 1578647245UL, 3561974633UL, 3629845331UL, 1464127305UL, 1616628807UL, 2243114101UL, 3639967880UL, 3256744141UL, 2437350057UL, 39991274UL, 2024323584UL, 3795072940UL, 1024703328UL, 443099203UL, 643536212UL, 1919517328UL, 3931285769UL, 2755167056UL, 276421624UL, 2492081750UL, 262729512UL, 3088549877UL, 2817867653UL, 1816283755UL, 4246096489UL, 842575914UL, 1460435650UL, 2276077438UL, +2640849794UL, 3697925816UL, 3465779075UL, 3856929655UL, 130551477UL, 2897029415UL, 2747033756UL, 3611830629UL, 1891542518UL, 804565809UL, 437451803UL, 677924906UL, 123809117UL, 3940574372UL, 2446610749UL, 3488484529UL, 470218446UL, 1092571016UL, 1537938503UL, 1502147484UL, 611300083UL, 3809285994UL, 3975678726UL, 925845389UL, 872826112UL, 2859302390UL, 2761919483UL, 993285307UL, 164095287UL, 3901654538UL, 2078946336UL, 1418537059UL, +1202525920UL, 4234029440UL, 704759480UL, 2484428922UL, 1833969372UL, 661495122UL, 2217907395UL, 3287413716UL, 2950835531UL, 1402379354UL, 351314168UL, 1902476749UL, 2033316109UL, 2873973176UL, 1321203603UL, 3316118265UL, 3282193947UL, 1316780684UL, 793441242UL, 3281524559UL, 296088733UL, 487851702UL, 314311643UL, 1388727135UL, 1705533557UL, 3557800292UL, 399729516UL, 1660074989UL, 291276309UL, 421164833UL, 1318404599UL, 2064519128UL, +3156334112UL, 2076623594UL, 850664906UL, 2293210629UL, 1517805917UL, 335452425UL, 3847487204UL, 645388200UL, 824349799UL, 3517232886UL, 954487767UL, 2755872609UL, 4249786064UL, 3811424903UL, 1100783479UL, 3408594583UL, 1417544262UL, 3159462529UL, 1654848550UL, 950025444UL, 324339737UL, 1908900347UL, 4111078399UL, 3241719305UL, 2788212779UL, 1890540205UL, 3750258343UL, 4190211142UL, 1420776905UL, 3780537969UL, 3716648585UL, 1690550UL, +3354905256UL, 2519610308UL, 515777663UL, 3758156132UL, 2658162202UL, 1154211550UL, 1915690212UL, 1933919046UL, 844149171UL, 189880016UL, 1359089498UL, 2249086205UL, 3417955173UL, 1031812215UL, 998719835UL, 1265685672UL, 1970052076UL, 3585976752UL, 3174204115UL, 2973042959UL, 1360991400UL, 1994321680UL, 2327168468UL, 714016907UL, 2283905032UL, 2217962701UL, 182726833UL, 590204372UL, 2151450260UL, 110719262UL, 3697978033UL, 1084030545UL, +3397906968UL, 767772303UL, 4133333579UL, 1069092002UL, 2364406907UL, 1578647245UL, 42955292UL, 3629845331UL, 1464127305UL, 1616628807UL, 2243114101UL, 3222189776UL, 3256744141UL, 2437350057UL, 39991274UL, 2024323584UL, 3142424684UL, 1024703328UL, 443099203UL, 643536212UL, 1919517328UL, 918511196UL, 2755167056UL, 276421624UL, 2492081750UL, 262729512UL, 4246877536UL, 2817867653UL, 1816283755UL, 4246096489UL, 842575914UL, 1425765936UL, +2276077438UL, 2640849794UL, 3697925816UL, 3465779075UL, 1491702526UL, 130551477UL, 2897029415UL, 2747033756UL, 3611830629UL, 1844578694UL, 804565809UL, 437451803UL, 677924906UL, 123809117UL, 3419189841UL, 2446610749UL, 3488484529UL, 470218446UL, 1092571016UL, 3272535988UL, 1502147484UL, 611300083UL, 3809285994UL, 3975678726UL, 2853681168UL, 872826112UL, 2859302390UL, 2761919483UL, 993285307UL, 1434560128UL, 3901654538UL, 2078946336UL, +1418537059UL, 1202525920UL, 2530097881UL, 704759480UL, 2484428922UL, 1833969372UL, 661495122UL, 503878844UL, 3287413716UL, 2950835531UL, 1402379354UL, 351314168UL, 4131886119UL, 2033316109UL, 2873973176UL, 1321203603UL, 3316118265UL, 237900321UL, 1316780684UL, 793441242UL, 3281524559UL, 296088733UL, 1730738847UL, 314311643UL, 1388727135UL, 1705533557UL, 3557800292UL, 1553835665UL, 1660074989UL, 291276309UL, 421164833UL, 1318404599UL, +964731488UL, 3156334112UL, 2076623594UL, 850664906UL, 2293210629UL, 1105350579UL, 335452425UL, 3847487204UL, 645388200UL, 824349799UL, 2789953706UL, 954487767UL, 2755872609UL, 4249786064UL, 3811424903UL, 3937839949UL, 3408594583UL, 1417544262UL, 3159462529UL, 1654848550UL, 624060530UL, 324339737UL, 1908900347UL, 4111078399UL, 3241719305UL, 2294919498UL, 1890540205UL, 3750258343UL, 4190211142UL, 1420776905UL, 2279133729UL, 3716648585UL, +1690550UL, 3354905256UL, 2519610308UL, 3563975602UL, 3758156132UL, 2658162202UL, 1154211550UL, 1915690212UL, 3505586122UL, 844149171UL, 189880016UL, 1359089498UL, 2249086205UL, 2389487504UL, 1031812215UL, 998719835UL, 1265685672UL, 1970052076UL, 2798611919UL, 3174204115UL, 2973042959UL, 1360991400UL, 1994321680UL, 1684134678UL, 714016907UL, 2283905032UL, 2217962701UL, 182726833UL, 1734988742UL, 2151450260UL, 110719262UL, 3697978033UL, +1084030545UL, 159906818UL, 767772303UL, 4133333579UL, 1069092002UL, 2364406907UL, 1290801202UL, 42955292UL, 3629845331UL, 1464127305UL, 1616628807UL, 987794861UL, 3222189776UL, 3256744141UL, 2437350057UL, 39991274UL, 3644076751UL, 3142424684UL, 1024703328UL, 443099203UL, 643536212UL, 1487589384UL, 918511196UL, 2755167056UL, 276421624UL, 2492081750UL, 137688638UL, 4246877536UL, 2817867653UL, 1816283755UL, 4246096489UL, 1518475380UL, +1425765936UL, 2276077438UL, 2640849794UL, 3697925816UL, 4226506771UL, 1491702526UL, 130551477UL, 2897029415UL, 2747033756UL, 2033599579UL, 1844578694UL, 804565809UL, 437451803UL, 677924906UL, 2749065512UL, 3419189841UL, 2446610749UL, 3488484529UL, 470218446UL, 290444026UL, 3272535988UL, 1502147484UL, 611300083UL, 3809285994UL, 2546040767UL, 2853681168UL, 872826112UL, 2859302390UL, 2761919483UL, 4097961150UL, 1434560128UL, 3901654538UL, +2078946336UL, 1418537059UL, 2725734455UL, 2530097881UL, 704759480UL, 2484428922UL, 1833969372UL, 3999408333UL, 503878844UL, 3287413716UL, 2950835531UL, 1402379354UL, 3861442503UL, 4131886119UL, 2033316109UL, 2873973176UL, 1321203603UL, 1267331405UL, 237900321UL, 1316780684UL, 793441242UL, 3281524559UL, 1273427916UL, 1730738847UL, 314311643UL, 1388727135UL, 1705533557UL, 1474310231UL, 1553835665UL, 1660074989UL, 291276309UL, 421164833UL, +3884815658UL, 3088049345UL, 3307042227UL, 3228948601UL, 1717605083UL, 1864502063UL, 3799516572UL, 2372822470UL, 2691586476UL, 1172840854UL, 1577099080UL, 870101866UL, 2139291021UL, 406996656UL, 255568268UL, 897760202UL, 674745664UL, 885214361UL, 3753233375UL, 3015215223UL, 1711461259UL, 3241363282UL, 2125360928UL, 2493601640UL, 2350228245UL, 3434627328UL, 2095642963UL, 3360932494UL, 3287396242UL, 4070512427UL, 3415702664UL, 1958354224UL, +3280206940UL, 3929504236UL, 3390499817UL, 4144225735UL, 3621750606UL, 3205006592UL, 3495743785UL, 269239326UL, 2181299371UL, 2898796651UL, 2613623219UL, 3988711298UL, 2162437858UL, 949553433UL, 3289670000UL, 3559525307UL, 3366925567UL, 2112148665UL, 955626393UL, 1790865381UL, 699223558UL, 3889584301UL, 1020750250UL, 4105283899UL, 2295851818UL, 4045668915UL, 2224770025UL, 766386910UL, 4265157386UL, 89139307UL, 2099710177UL, 1012450874UL, +1875492446UL, 1927399417UL, 767450812UL, 654474783UL, 4265293038UL, 4041215389UL, 4102336947UL, 4263617328UL, 2135826340UL, 2317231535UL, 3773895729UL, 403151111UL, 1400693138UL, 4255050194UL, 755369466UL, 2325764302UL, 2617301159UL, 4165707294UL, 1206304709UL, 2415645397UL, 4276004841UL, 1457022279UL, 662660652UL, 795140282UL, 828519889UL, 805830562UL, 1179976369UL, 2212548232UL, 755708248UL, 1034682071UL, 899950902UL, 1906046264UL, +1861009040UL, 310711525UL, 920739741UL, 2322414272UL, 3179236470UL, 81822135UL, 4111390320UL, 1800166783UL, 112253014UL, 688771939UL, 1050990794UL, 3124647483UL, 287052171UL, 1363630156UL, 3447798279UL, 1405733552UL, 3075862538UL, 1682808202UL, 1595154222UL, 1173705692UL, 680713285UL, 2748212230UL, 568610527UL, 3434965538UL, 1114942930UL, 2835858745UL, 2575992250UL, 3243355150UL, 2127580225UL, 1855934450UL, 3915941751UL, 2228679809UL, +1514780124UL, 1506688039UL, 1033083295UL, 793807083UL, 1120681149UL, 4105670165UL, 3999570340UL, 2083020131UL, 1213356023UL, 3684882757UL, 3375797774UL, 3577986103UL, 2092046164UL, 2593847443UL, 1826450612UL, 367828409UL, 3198272513UL, 1941316667UL, 943707510UL, 907134807UL, 2020457947UL, 1462193665UL, 2964617539UL, 4216491663UL, 2625270800UL, 2395371467UL, 3691003028UL, 3659016793UL, 2381847054UL, 3513105567UL, 3013019506UL, 2731245927UL, +}, +{ +1680024716UL, 2112340059UL, 3387475367UL, 2080916186UL, 1431532386UL, 3907378472UL, 2636491350UL, 2176128529UL, 2236616671UL, 3736851460UL, 2604001339UL, 3893075234UL, 3495918635UL, 4116370522UL, 1384310379UL, 3660102574UL, 2030233939UL, 2759207091UL, 49347923UL, 97526506UL, 2566932710UL, 1566181275UL, 3127827248UL, 578401670UL, 1499229308UL, 2581732444UL, 279715551UL, 809690877UL, 1438444015UL, 878935323UL, 1495277039UL, 3417305339UL, +2858903785UL, 3074075088UL, 603749086UL, 2370669734UL, 391683868UL, 3933465331UL, 2884128106UL, 1478317876UL, 1864988335UL, 2925823809UL, 4133578805UL, 218104493UL, 368652174UL, 1998600344UL, 1109346044UL, 1716435313UL, 415435111UL, 91393686UL, 2536620737UL, 1440068573UL, 481874870UL, 142128108UL, 988825519UL, 2077118779UL, 2858045339UL, 4068162251UL, 115593872UL, 1364244587UL, 3550167006UL, 3728768059UL, 1772423685UL, 2504624145UL, +248732306UL, 1412607307UL, 4081166331UL, 154438218UL, 1652901877UL, 3932533490UL, 3142799969UL, 3154073676UL, 3112018078UL, 2757873595UL, 2364830126UL, 2855791484UL, 793851407UL, 507785167UL, 263713916UL, 4060700051UL, 3291978358UL, 1584226715UL, 2546417990UL, 450747961UL, 2951067700UL, 2706009093UL, 1788578194UL, 4030171132UL, 2610979903UL, 573420740UL, 4269115622UL, 2180305819UL, 2646894726UL, 716649335UL, 3875715683UL, 853428184UL, +2436760738UL, 4190071217UL, 2754423535UL, 540698101UL, 4082489821UL, 741976046UL, 267559495UL, 1591532642UL, 2500610323UL, 3203248679UL, 147312102UL, 2772368222UL, 1412987047UL, 2295185573UL, 1932341300UL, 898396308UL, 1837129999UL, 3113914292UL, 2613354524UL, 3141601915UL, 276087167UL, 1887389351UL, 757801450UL, 3752353732UL, 2745818074UL, 1442953464UL, 3802648347UL, 223728071UL, 2169947402UL, 1338125300UL, 3642174036UL, 2794462634UL, +2326349851UL, 862746036UL, 3577092599UL, 627103363UL, 552173564UL, 4142604459UL, 2310329406UL, 583522272UL, 189323282UL, 1217612313UL, 73550248UL, 2434692829UL, 2757269706UL, 2392210091UL, 3032922600UL, 3573904125UL, 2897178037UL, 2632631469UL, 3085332665UL, 3775619904UL, 2563291734UL, 1351375865UL, 4043427793UL, 1803743084UL, 3112116579UL, 522940594UL, 2690374983UL, 2613871529UL, 3810037031UL, 1765642390UL, 534554747UL, 1930852049UL, +2264349344UL, 1680024716UL, 2112340059UL, 3387475367UL, 2080916186UL, 75966494UL, 3907378472UL, 2636491350UL, 2176128529UL, 2236616671UL, 2372987046UL, 2604001339UL, 3893075234UL, 3495918635UL, 4116370522UL, 534929913UL, 3660102574UL, 2030233939UL, 2759207091UL, 49347923UL, 987575186UL, 2566932710UL, 1566181275UL, 3127827248UL, 578401670UL, 3731513754UL, 2581732444UL, 279715551UL, 809690877UL, 1438444015UL, 2185866850UL, 1495277039UL, +3417305339UL, 2858903785UL, 3074075088UL, 4198538376UL, 2370669734UL, 391683868UL, 3933465331UL, 2884128106UL, 1400216510UL, 1864988335UL, 2925823809UL, 4133578805UL, 218104493UL, 2798390374UL, 1998600344UL, 1109346044UL, 1716435313UL, 415435111UL, 1892535124UL, 2536620737UL, 1440068573UL, 481874870UL, 142128108UL, 329082740UL, 2077118779UL, 2858045339UL, 4068162251UL, 115593872UL, 2644000449UL, 3550167006UL, 3728768059UL, 1772423685UL, +2504624145UL, 2140118619UL, 1412607307UL, 4081166331UL, 154438218UL, 1652901877UL, 3804911318UL, 3142799969UL, 3154073676UL, 3112018078UL, 2757873595UL, 50297646UL, 2855791484UL, 793851407UL, 507785167UL, 263713916UL, 3324588195UL, 3291978358UL, 1584226715UL, 2546417990UL, 450747961UL, 3455625012UL, 2706009093UL, 1788578194UL, 4030171132UL, 2610979903UL, 3835380965UL, 4269115622UL, 2180305819UL, 2646894726UL, 716649335UL, 2607142354UL, +853428184UL, 2436760738UL, 4190071217UL, 2754423535UL, 456808691UL, 4082489821UL, 741976046UL, 267559495UL, 1591532642UL, 2722205042UL, 3203248679UL, 147312102UL, 2772368222UL, 1412987047UL, 1950543946UL, 1932341300UL, 898396308UL, 1837129999UL, 3113914292UL, 428616392UL, 3141601915UL, 276087167UL, 1887389351UL, 757801450UL, 963534966UL, 2745818074UL, 1442953464UL, 3802648347UL, 223728071UL, 229039300UL, 1338125300UL, 3642174036UL, +2794462634UL, 2326349851UL, 206115203UL, 3577092599UL, 627103363UL, 552173564UL, 4142604459UL, 1492461846UL, 583522272UL, 189323282UL, 1217612313UL, 73550248UL, 3552211807UL, 2757269706UL, 2392210091UL, 3032922600UL, 3573904125UL, 810640644UL, 2632631469UL, 3085332665UL, 3775619904UL, 2563291734UL, 922608790UL, 4043427793UL, 1803743084UL, 3112116579UL, 522940594UL, 1785093944UL, 2613871529UL, 3810037031UL, 1765642390UL, 534554747UL, +3528050076UL, 2264349344UL, 1680024716UL, 2112340059UL, 3387475367UL, 3295682653UL, 75966494UL, 3907378472UL, 2636491350UL, 2176128529UL, 3574915532UL, 2372987046UL, 2604001339UL, 3893075234UL, 3495918635UL, 1280296085UL, 534929913UL, 3660102574UL, 2030233939UL, 2759207091UL, 299776535UL, 987575186UL, 2566932710UL, 1566181275UL, 3127827248UL, 3874691533UL, 3731513754UL, 2581732444UL, 279715551UL, 809690877UL, 3100791084UL, 2185866850UL, +1495277039UL, 3417305339UL, 2858903785UL, 1310351481UL, 4198538376UL, 2370669734UL, 391683868UL, 3933465331UL, 2749085130UL, 1400216510UL, 1864988335UL, 2925823809UL, 4133578805UL, 3352814594UL, 2798390374UL, 1998600344UL, 1109346044UL, 1716435313UL, 1571752941UL, 1892535124UL, 2536620737UL, 1440068573UL, 481874870UL, 2485033697UL, 329082740UL, 2077118779UL, 2858045339UL, 4068162251UL, 3837440666UL, 2644000449UL, 3550167006UL, 3728768059UL, +1772423685UL, 1176559812UL, 2140118619UL, 1412607307UL, 4081166331UL, 154438218UL, 2902622972UL, 3804911318UL, 3142799969UL, 3154073676UL, 3112018078UL, 2403391233UL, 50297646UL, 2855791484UL, 793851407UL, 507785167UL, 2351826747UL, 3324588195UL, 3291978358UL, 1584226715UL, 2546417990UL, 746876926UL, 3455625012UL, 2706009093UL, 1788578194UL, 4030171132UL, 3779307353UL, 3835380965UL, 4269115622UL, 2180305819UL, 2646894726UL, 2602235234UL, +2607142354UL, 853428184UL, 2436760738UL, 4190071217UL, 2066757692UL, 456808691UL, 4082489821UL, 741976046UL, 267559495UL, 3001080633UL, 2722205042UL, 3203248679UL, 147312102UL, 2772368222UL, 89950260UL, 1950543946UL, 1932341300UL, 898396308UL, 1837129999UL, 947911286UL, 428616392UL, 3141601915UL, 276087167UL, 1887389351UL, 2583987247UL, 963534966UL, 2745818074UL, 1442953464UL, 3802648347UL, 4229124441UL, 229039300UL, 1338125300UL, +3642174036UL, 2794462634UL, 2472155633UL, 206115203UL, 3577092599UL, 627103363UL, 552173564UL, 2586882739UL, 1492461846UL, 583522272UL, 189323282UL, 1217612313UL, 3501549884UL, 3552211807UL, 2757269706UL, 2392210091UL, 3032922600UL, 740675778UL, 810640644UL, 2632631469UL, 3085332665UL, 3775619904UL, 3643289881UL, 922608790UL, 4043427793UL, 1803743084UL, 3112116579UL, 2213337398UL, 1785093944UL, 2613871529UL, 3810037031UL, 1765642390UL, +762472016UL, 3528050076UL, 2264349344UL, 1680024716UL, 2112340059UL, 1372272974UL, 3295682653UL, 75966494UL, 3907378472UL, 2636491350UL, 3117471955UL, 3574915532UL, 2372987046UL, 2604001339UL, 3893075234UL, 915576383UL, 1280296085UL, 534929913UL, 3660102574UL, 2030233939UL, 346368350UL, 299776535UL, 987575186UL, 2566932710UL, 1566181275UL, 3535223896UL, 3874691533UL, 3731513754UL, 2581732444UL, 279715551UL, 2456894951UL, 3100791084UL, +2185866850UL, 1495277039UL, 3417305339UL, 1618871086UL, 1310351481UL, 4198538376UL, 2370669734UL, 391683868UL, 2009676005UL, 2749085130UL, 1400216510UL, 1864988335UL, 2925823809UL, 58955107UL, 3352814594UL, 2798390374UL, 1998600344UL, 1109346044UL, 3273979614UL, 1571752941UL, 1892535124UL, 2536620737UL, 1440068573UL, 1174168447UL, 2485033697UL, 329082740UL, 2077118779UL, 2858045339UL, 4062921629UL, 3837440666UL, 2644000449UL, 3550167006UL, +3728768059UL, 2642133401UL, 1176559812UL, 2140118619UL, 1412607307UL, 4081166331UL, 3124905304UL, 2902622972UL, 3804911318UL, 3142799969UL, 3154073676UL, 1449454613UL, 2403391233UL, 50297646UL, 2855791484UL, 793851407UL, 3514201526UL, 2351826747UL, 3324588195UL, 3291978358UL, 1584226715UL, 3636681672UL, 746876926UL, 3455625012UL, 2706009093UL, 1788578194UL, 3451519459UL, 3779307353UL, 3835380965UL, 4269115622UL, 2180305819UL, 3987989524UL, +2602235234UL, 2607142354UL, 853428184UL, 2436760738UL, 2151617107UL, 2066757692UL, 456808691UL, 4082489821UL, 741976046UL, 3590081269UL, 3001080633UL, 2722205042UL, 3203248679UL, 147312102UL, 3432947806UL, 89950260UL, 1950543946UL, 1932341300UL, 898396308UL, 3828432864UL, 947911286UL, 428616392UL, 3141601915UL, 276087167UL, 2517666433UL, 2583987247UL, 963534966UL, 2745818074UL, 1442953464UL, 2223986807UL, 4229124441UL, 229039300UL, +1338125300UL, 3642174036UL, 1053796945UL, 2472155633UL, 206115203UL, 3577092599UL, 627103363UL, 1113276084UL, 2586882739UL, 1492461846UL, 583522272UL, 189323282UL, 1490604990UL, 3501549884UL, 3552211807UL, 2757269706UL, 2392210091UL, 3545407532UL, 740675778UL, 810640644UL, 2632631469UL, 3085332665UL, 755862267UL, 3643289881UL, 922608790UL, 4043427793UL, 1803743084UL, 1954166630UL, 2213337398UL, 1785093944UL, 2613871529UL, 3810037031UL, +3042935707UL, 3162182177UL, 2791346436UL, 1901925289UL, 863100941UL, 3367519168UL, 1972623238UL, 3664303070UL, 604922059UL, 3026817982UL, 1436412310UL, 4096180631UL, 1597561857UL, 4206212303UL, 4127914332UL, 3228677359UL, 3985733659UL, 3597290113UL, 4251197894UL, 3451370603UL, 609679338UL, 3360835257UL, 1372239885UL, 638572328UL, 3806422284UL, 3974147336UL, 1804280837UL, 4209089291UL, 2021797469UL, 3557188838UL, 409727186UL, 2114649178UL, +687702120UL, 2542445992UL, 1235991799UL, 460479179UL, 2008348175UL, 887884478UL, 3942327811UL, 2999928223UL, 4171339789UL, 2286339235UL, 1293442231UL, 1575942850UL, 76122475UL, 1440527701UL, 2006558403UL, 1544148172UL, 895899367UL, 681826913UL, 4094701935UL, 3995413790UL, 1027509154UL, 2264990896UL, 1938238113UL, 213430250UL, 222469320UL, 609726517UL, 3581538106UL, 492802663UL, 120480843UL, 1720004062UL, 1132674507UL, 911082758UL, +2909148131UL, 566658805UL, 3964114445UL, 3483602509UL, 1793438750UL, 165562604UL, 3641830063UL, 2394205521UL, 3404874822UL, 1672998096UL, 916151953UL, 1141264477UL, 3171661340UL, 3803396219UL, 3018337382UL, 1863902683UL, 2474641928UL, 3250365071UL, 3897886220UL, 1219701051UL, 51332576UL, 1358614881UL, 1707407492UL, 3670647816UL, 923357625UL, 343687395UL, 3991339686UL, 3913575403UL, 1267727936UL, 4001357856UL, 3820224848UL, 2942896724UL, +3505936742UL, 1403285299UL, 1992762049UL, 567748449UL, 2202721585UL, 2781324216UL, 1724850068UL, 2408314541UL, 3073975813UL, 3992810029UL, 2475242354UL, 540562053UL, 2185198943UL, 3759352041UL, 3373885614UL, 1132999410UL, 1097554565UL, 4089342358UL, 3239542922UL, 2451748646UL, 407290679UL, 3188103200UL, 1708016248UL, 26848241UL, 2796711130UL, 3090711568UL, 4068389322UL, 3420916085UL, 3137567033UL, 2877819818UL, 22133454UL, 4629160UL, +3703695249UL, 1920151708UL, 1175452162UL, 130015299UL, 3331834713UL, 1099225384UL, 689254331UL, 1851083761UL, 2654970209UL, 3259297936UL, 3742819314UL, 3524284766UL, 2291819083UL, 3494031861UL, 16242889UL, 3545082774UL, 1997878108UL, 777447699UL, 4244916543UL, 3508640253UL, 3782278393UL, 2107258964UL, 2139074576UL, 1383217899UL, 2337934322UL, 3181899620UL, 1285955765UL, 2989610020UL, 3326862146UL, 1168587380UL, 801203532UL, 3020809957UL, +}, +{ +3810471203UL, 1017064446UL, 1595207573UL, 441087832UL, 3326746890UL, 3294064431UL, 167972517UL, 3625210015UL, 1011845006UL, 2980240819UL, 1778354660UL, 3041730987UL, 1598611350UL, 2015169745UL, 2321724978UL, 3390812967UL, 2432904511UL, 113261909UL, 3957193232UL, 3806115908UL, 2965828929UL, 2035392295UL, 3500116619UL, 2881232416UL, 1672212265UL, 1607201428UL, 425148945UL, 1262591961UL, 2221781268UL, 4215047456UL, 2148245850UL, 2787488981UL, +1077262192UL, 2085467561UL, 3053954888UL, 3584435116UL, 3013084787UL, 287099941UL, 1290407232UL, 4078552287UL, 2658945475UL, 4251530898UL, 2403086478UL, 2884923598UL, 3545110453UL, 4105390090UL, 343200643UL, 3189888821UL, 4086304363UL, 3466483195UL, 259435633UL, 2846377387UL, 497258846UL, 272775541UL, 985737911UL, 2957688879UL, 2180784344UL, 3434619542UL, 3643384838UL, 2228652440UL, 3107480718UL, 2208729807UL, 596436263UL, 3255120711UL, +3248886970UL, 519242965UL, 602979109UL, 1619614UL, 1391563565UL, 56262588UL, 1584463910UL, 1849038201UL, 728022295UL, 848624947UL, 1813827408UL, 428214945UL, 1246345586UL, 4213351865UL, 168985863UL, 456608054UL, 4277869380UL, 3886828599UL, 2264054549UL, 3110967170UL, 3138175314UL, 2649164828UL, 3369378320UL, 3648350039UL, 3524848759UL, 1468470706UL, 3558859222UL, 2669673235UL, 831851874UL, 4285651092UL, 4224147373UL, 1088456706UL, +231954609UL, 3118005852UL, 225508069UL, 883105389UL, 856371341UL, 2001356578UL, 639336670UL, 2363501707UL, 3622399552UL, 4024065226UL, 1093546838UL, 4263608561UL, 1852072422UL, 425195042UL, 2441102396UL, 296426333UL, 384641750UL, 3559334435UL, 1757327033UL, 1016016207UL, 3595686646UL, 24777793UL, 623926105UL, 2169195923UL, 1779396793UL, 646997837UL, 1459728476UL, 2644865980UL, 1994581089UL, 3956278544UL, 919592580UL, 2153558858UL, +2029633394UL, 3837501009UL, 4016560170UL, 484838096UL, 3652199054UL, 1971790561UL, 605295089UL, 637470291UL, 278970544UL, 3574824693UL, 295866521UL, 1755035156UL, 2542341803UL, 1588716357UL, 1502596918UL, 4124554133UL, 3547049843UL, 1768033045UL, 1531734630UL, 101448323UL, 3233017580UL, 1793222944UL, 3187853500UL, 186000900UL, 803444571UL, 2820254958UL, 2009384608UL, 2384668855UL, 2222812920UL, 633608665UL, 2028480056UL, 1258028235UL, +545095949UL, 3810471203UL, 1017064446UL, 1595207573UL, 441087832UL, 899068662UL, 3294064431UL, 167972517UL, 3625210015UL, 1011845006UL, 3951305793UL, 1778354660UL, 3041730987UL, 1598611350UL, 2015169745UL, 1885149424UL, 3390812967UL, 2432904511UL, 113261909UL, 3957193232UL, 3953443155UL, 2965828929UL, 2035392295UL, 3500116619UL, 2881232416UL, 329153573UL, 1607201428UL, 425148945UL, 1262591961UL, 2221781268UL, 78028761UL, 2148245850UL, +2787488981UL, 1077262192UL, 2085467561UL, 647235899UL, 3584435116UL, 3013084787UL, 287099941UL, 1290407232UL, 1467385694UL, 2658945475UL, 4251530898UL, 2403086478UL, 2884923598UL, 3489351040UL, 4105390090UL, 343200643UL, 3189888821UL, 4086304363UL, 3521512280UL, 259435633UL, 2846377387UL, 497258846UL, 272775541UL, 1367093111UL, 2957688879UL, 2180784344UL, 3434619542UL, 3643384838UL, 411877686UL, 3107480718UL, 2208729807UL, 596436263UL, +3255120711UL, 584605030UL, 519242965UL, 602979109UL, 1619614UL, 1391563565UL, 3902518209UL, 1584463910UL, 1849038201UL, 728022295UL, 848624947UL, 1932969318UL, 428214945UL, 1246345586UL, 4213351865UL, 168985863UL, 2770345237UL, 4277869380UL, 3886828599UL, 2264054549UL, 3110967170UL, 2953581033UL, 2649164828UL, 3369378320UL, 3648350039UL, 3524848759UL, 2380353977UL, 3558859222UL, 2669673235UL, 831851874UL, 4285651092UL, 1214052447UL, +1088456706UL, 231954609UL, 3118005852UL, 225508069UL, 1766983646UL, 856371341UL, 2001356578UL, 639336670UL, 2363501707UL, 1782816591UL, 4024065226UL, 1093546838UL, 4263608561UL, 1852072422UL, 1149716600UL, 2441102396UL, 296426333UL, 384641750UL, 3559334435UL, 2391309970UL, 1016016207UL, 3595686646UL, 24777793UL, 623926105UL, 362098678UL, 1779396793UL, 646997837UL, 1459728476UL, 2644865980UL, 3238673748UL, 3956278544UL, 919592580UL, +2153558858UL, 2029633394UL, 115778559UL, 4016560170UL, 484838096UL, 3652199054UL, 1971790561UL, 737357475UL, 637470291UL, 278970544UL, 3574824693UL, 295866521UL, 3989745853UL, 2542341803UL, 1588716357UL, 1502596918UL, 4124554133UL, 3016849744UL, 1768033045UL, 1531734630UL, 101448323UL, 3233017580UL, 4157527581UL, 3187853500UL, 186000900UL, 803444571UL, 2820254958UL, 1980528062UL, 2384668855UL, 2222812920UL, 633608665UL, 2028480056UL, +3166710281UL, 545095949UL, 3810471203UL, 1017064446UL, 1595207573UL, 693962828UL, 899068662UL, 3294064431UL, 167972517UL, 3625210015UL, 1486040398UL, 3951305793UL, 1778354660UL, 3041730987UL, 1598611350UL, 2859363132UL, 1885149424UL, 3390812967UL, 2432904511UL, 113261909UL, 664880478UL, 3953443155UL, 2965828929UL, 2035392295UL, 3500116619UL, 558081801UL, 329153573UL, 1607201428UL, 425148945UL, 1262591961UL, 3716247699UL, 78028761UL, +2148245850UL, 2787488981UL, 1077262192UL, 4206362947UL, 647235899UL, 3584435116UL, 3013084787UL, 287099941UL, 2536781098UL, 1467385694UL, 2658945475UL, 4251530898UL, 2403086478UL, 3075072413UL, 3489351040UL, 4105390090UL, 343200643UL, 3189888821UL, 2540485172UL, 3521512280UL, 259435633UL, 2846377387UL, 497258846UL, 2442427327UL, 1367093111UL, 2957688879UL, 2180784344UL, 3434619542UL, 1593967423UL, 411877686UL, 3107480718UL, 2208729807UL, +596436263UL, 1048686529UL, 584605030UL, 519242965UL, 602979109UL, 1619614UL, 2072745381UL, 3902518209UL, 1584463910UL, 1849038201UL, 728022295UL, 846033949UL, 1932969318UL, 428214945UL, 1246345586UL, 4213351865UL, 1066373275UL, 2770345237UL, 4277869380UL, 3886828599UL, 2264054549UL, 1877859690UL, 2953581033UL, 2649164828UL, 3369378320UL, 3648350039UL, 2537763389UL, 2380353977UL, 3558859222UL, 2669673235UL, 831851874UL, 522748140UL, +1214052447UL, 1088456706UL, 231954609UL, 3118005852UL, 1381269315UL, 1766983646UL, 856371341UL, 2001356578UL, 639336670UL, 667275675UL, 1782816591UL, 4024065226UL, 1093546838UL, 4263608561UL, 2057337961UL, 1149716600UL, 2441102396UL, 296426333UL, 384641750UL, 340523210UL, 2391309970UL, 1016016207UL, 3595686646UL, 24777793UL, 3094832341UL, 362098678UL, 1779396793UL, 646997837UL, 1459728476UL, 1169681568UL, 3238673748UL, 3956278544UL, +919592580UL, 2153558858UL, 388335108UL, 115778559UL, 4016560170UL, 484838096UL, 3652199054UL, 1764858181UL, 737357475UL, 637470291UL, 278970544UL, 3574824693UL, 3671458900UL, 3989745853UL, 2542341803UL, 1588716357UL, 1502596918UL, 2102871406UL, 3016849744UL, 1768033045UL, 1531734630UL, 101448323UL, 3964942332UL, 4157527581UL, 3187853500UL, 186000900UL, 803444571UL, 3425652083UL, 1980528062UL, 2384668855UL, 2222812920UL, 633608665UL, +3035373876UL, 3166710281UL, 545095949UL, 3810471203UL, 1017064446UL, 669282349UL, 693962828UL, 899068662UL, 3294064431UL, 167972517UL, 2007256988UL, 1486040398UL, 3951305793UL, 1778354660UL, 3041730987UL, 2827768941UL, 2859363132UL, 1885149424UL, 3390812967UL, 2432904511UL, 3700915653UL, 664880478UL, 3953443155UL, 2965828929UL, 2035392295UL, 1461208330UL, 558081801UL, 329153573UL, 1607201428UL, 425148945UL, 1700881129UL, 3716247699UL, +78028761UL, 2148245850UL, 2787488981UL, 2706775080UL, 4206362947UL, 647235899UL, 3584435116UL, 3013084787UL, 2958545221UL, 2536781098UL, 1467385694UL, 2658945475UL, 4251530898UL, 2241012567UL, 3075072413UL, 3489351040UL, 4105390090UL, 343200643UL, 490164649UL, 2540485172UL, 3521512280UL, 259435633UL, 2846377387UL, 4073611831UL, 2442427327UL, 1367093111UL, 2957688879UL, 2180784344UL, 1835510773UL, 1593967423UL, 411877686UL, 3107480718UL, +2208729807UL, 3306732468UL, 1048686529UL, 584605030UL, 519242965UL, 602979109UL, 2978864605UL, 2072745381UL, 3902518209UL, 1584463910UL, 1849038201UL, 3284115169UL, 846033949UL, 1932969318UL, 428214945UL, 1246345586UL, 194166002UL, 1066373275UL, 2770345237UL, 4277869380UL, 3886828599UL, 1874087886UL, 1877859690UL, 2953581033UL, 2649164828UL, 3369378320UL, 4145454028UL, 2537763389UL, 2380353977UL, 3558859222UL, 2669673235UL, 739345884UL, +522748140UL, 1214052447UL, 1088456706UL, 231954609UL, 3605603781UL, 1381269315UL, 1766983646UL, 856371341UL, 2001356578UL, 2049940324UL, 667275675UL, 1782816591UL, 4024065226UL, 1093546838UL, 152524382UL, 2057337961UL, 1149716600UL, 2441102396UL, 296426333UL, 3195130788UL, 340523210UL, 2391309970UL, 1016016207UL, 3595686646UL, 180492441UL, 3094832341UL, 362098678UL, 1779396793UL, 646997837UL, 2458167607UL, 1169681568UL, 3238673748UL, +3956278544UL, 919592580UL, 3421005218UL, 388335108UL, 115778559UL, 4016560170UL, 484838096UL, 2649676374UL, 1764858181UL, 737357475UL, 637470291UL, 278970544UL, 2236401278UL, 3671458900UL, 3989745853UL, 2542341803UL, 1588716357UL, 1241570134UL, 2102871406UL, 3016849744UL, 1768033045UL, 1531734630UL, 1765654724UL, 3964942332UL, 4157527581UL, 3187853500UL, 186000900UL, 2189716659UL, 3425652083UL, 1980528062UL, 2384668855UL, 2222812920UL, +3955466207UL, 2426547616UL, 3846752458UL, 3015538636UL, 2342593365UL, 3613176865UL, 3484860981UL, 4278370194UL, 1979143878UL, 1159739458UL, 3714038404UL, 396530346UL, 3276617756UL, 3293940597UL, 4050183149UL, 1418571985UL, 402563753UL, 2702853013UL, 2289900621UL, 2267058511UL, 3482161995UL, 3375026019UL, 1988640267UL, 3674438074UL, 4124612310UL, 1057883705UL, 434730475UL, 3210959778UL, 4102029739UL, 2140938750UL, 3176753074UL, 2356971512UL, +3969685288UL, 1556275580UL, 2648433428UL, 3959375381UL, 478841344UL, 1496991528UL, 3309714981UL, 569990368UL, 3660587501UL, 2550379574UL, 1177519842UL, 2652707373UL, 543943404UL, 1912551128UL, 2278132032UL, 1484596780UL, 3570913985UL, 2982401320UL, 1413776035UL, 3177275459UL, 3036211597UL, 1091740466UL, 3448424311UL, 1445187645UL, 3205024875UL, 3135795254UL, 823738729UL, 3742134467UL, 4066657438UL, 1226311678UL, 2403605393UL, 537573634UL, +3457409768UL, 1940233423UL, 1761431281UL, 1129427309UL, 2443661283UL, 3200814257UL, 4094866249UL, 2666869754UL, 604785127UL, 2213464116UL, 3002782918UL, 468024929UL, 2490681314UL, 3666681384UL, 1583346053UL, 3049668798UL, 3592153237UL, 2573082448UL, 3082970021UL, 1461796708UL, 832526980UL, 3728763274UL, 355291229UL, 4029588456UL, 832358279UL, 2125298737UL, 3681181038UL, 3245535160UL, 1333342738UL, 1868897492UL, 446790068UL, 1278093154UL, +2090118615UL, 4158925515UL, 4062165914UL, 822726809UL, 1154960183UL, 286518382UL, 1170424276UL, 2554691236UL, 3674133415UL, 2765714969UL, 2330865375UL, 1908307334UL, 3537287082UL, 410252600UL, 3977128218UL, 424210327UL, 2919071615UL, 2715518134UL, 64568844UL, 480972649UL, 2488797168UL, 1302817038UL, 2213995265UL, 4229997295UL, 2200797852UL, 109368057UL, 3033807022UL, 1907400078UL, 645977948UL, 1410909090UL, 3700787906UL, 3375062371UL, +629087832UL, 1344281719UL, 4249981139UL, 3457543297UL, 1218556849UL, 864222854UL, 1458445945UL, 914545469UL, 3451164212UL, 1088025757UL, 1129933985UL, 953788883UL, 2406172924UL, 170364546UL, 3505490646UL, 1027553899UL, 2864067776UL, 436854871UL, 1342782209UL, 761167471UL, 2660173631UL, 4159507498UL, 4172028400UL, 2442254644UL, 2110123720UL, 2315991253UL, 873066601UL, 1725470559UL, 3831299052UL, 678672031UL, 1585431329UL, 3495750550UL, +}, +{ +1998393432UL, 2665389278UL, 3989307699UL, 3267631636UL, 3861682977UL, 3243522970UL, 1243992413UL, 2200497260UL, 3821883021UL, 4187123083UL, 3451270040UL, 3044132745UL, 2101287249UL, 2340839784UL, 227040990UL, 1724350416UL, 3228881240UL, 3123386528UL, 4279362126UL, 3098224464UL, 2635534069UL, 3622906431UL, 206207480UL, 1894245533UL, 2152374527UL, 1011223653UL, 7271757UL, 2972858087UL, 207942127UL, 3355362797UL, 2593296740UL, 174093751UL, +3713822176UL, 4212355586UL, 3335605224UL, 1171716408UL, 2867257989UL, 1522213957UL, 2016192462UL, 4229688395UL, 2174928148UL, 1468226225UL, 3938290338UL, 493240317UL, 3229423344UL, 2585475729UL, 3112454413UL, 1881171707UL, 2555908056UL, 1997546352UL, 380428329UL, 3341885423UL, 3307510279UL, 3519476676UL, 3613100811UL, 2555826262UL, 109341943UL, 2382715395UL, 3883409616UL, 1593551879UL, 2163678014UL, 3379783137UL, 2810374300UL, 1516064864UL, +561144874UL, 316017838UL, 1899237567UL, 70857401UL, 3435185465UL, 4234661323UL, 2580352177UL, 32879620UL, 4171670150UL, 1986234067UL, 3589478191UL, 2073132526UL, 2603712175UL, 377997975UL, 2474419397UL, 3110698341UL, 812664089UL, 1778922726UL, 1686111212UL, 972784138UL, 3936486236UL, 2711468739UL, 423435866UL, 1661961159UL, 802312780UL, 1868728136UL, 1760295704UL, 3357409828UL, 215039860UL, 683184627UL, 4019111064UL, 3609261689UL, +2167554309UL, 1831085281UL, 3389357802UL, 4193421575UL, 628277197UL, 2900207619UL, 993609502UL, 3429627083UL, 2636466084UL, 3652352199UL, 1780133580UL, 1670387713UL, 4086070210UL, 4004540729UL, 783029246UL, 2165667566UL, 1739001057UL, 377639972UL, 1102689625UL, 1945278055UL, 3941185940UL, 3685368326UL, 1881761572UL, 2201338934UL, 801752UL, 2729497735UL, 492844690UL, 2998826141UL, 3844964457UL, 3679088359UL, 2196391660UL, 4222269404UL, +357321611UL, 3727170055UL, 1819614072UL, 2348798457UL, 4294366646UL, 1952884323UL, 3574345216UL, 2040734807UL, 232392443UL, 4183498179UL, 2614866055UL, 112120292UL, 3624018350UL, 3340709877UL, 3097507723UL, 1268833488UL, 3570501956UL, 3338260086UL, 293812421UL, 3683058169UL, 1147960351UL, 283731890UL, 2171233479UL, 1830154455UL, 4036602681UL, 1996981699UL, 132803834UL, 40256165UL, 2158110401UL, 3575159090UL, 3196553513UL, 3559872992UL, +3402884675UL, 1998393432UL, 2665389278UL, 3989307699UL, 3267631636UL, 3617519767UL, 3243522970UL, 1243992413UL, 2200497260UL, 3821883021UL, 3715729085UL, 3451270040UL, 3044132745UL, 2101287249UL, 2340839784UL, 3173635549UL, 1724350416UL, 3228881240UL, 3123386528UL, 4279362126UL, 2287520039UL, 2635534069UL, 3622906431UL, 206207480UL, 1894245533UL, 96723416UL, 1011223653UL, 7271757UL, 2972858087UL, 207942127UL, 1668335352UL, 2593296740UL, +174093751UL, 3713822176UL, 4212355586UL, 49226793UL, 1171716408UL, 2867257989UL, 1522213957UL, 2016192462UL, 118712412UL, 2174928148UL, 1468226225UL, 3938290338UL, 493240317UL, 3788174304UL, 2585475729UL, 3112454413UL, 1881171707UL, 2555908056UL, 3351139844UL, 380428329UL, 3341885423UL, 3307510279UL, 3519476676UL, 1368994724UL, 2555826262UL, 109341943UL, 2382715395UL, 3883409616UL, 1561509458UL, 2163678014UL, 3379783137UL, 2810374300UL, +1516064864UL, 2313252274UL, 316017838UL, 1899237567UL, 70857401UL, 3435185465UL, 2585770746UL, 2580352177UL, 32879620UL, 4171670150UL, 1986234067UL, 3317983509UL, 2073132526UL, 2603712175UL, 377997975UL, 2474419397UL, 908728599UL, 812664089UL, 1778922726UL, 1686111212UL, 972784138UL, 1992540005UL, 2711468739UL, 423435866UL, 1661961159UL, 802312780UL, 907108769UL, 1760295704UL, 3357409828UL, 215039860UL, 683184627UL, 2806826652UL, +3609261689UL, 2167554309UL, 1831085281UL, 3389357802UL, 2755692689UL, 628277197UL, 2900207619UL, 993609502UL, 3429627083UL, 3605915742UL, 3652352199UL, 1780133580UL, 1670387713UL, 4086070210UL, 3717326627UL, 783029246UL, 2165667566UL, 1739001057UL, 377639972UL, 2355216626UL, 1945278055UL, 3941185940UL, 3685368326UL, 1881761572UL, 4024097818UL, 801752UL, 2729497735UL, 492844690UL, 2998826141UL, 2719601647UL, 3679088359UL, 2196391660UL, +4222269404UL, 357321611UL, 1319821972UL, 1819614072UL, 2348798457UL, 4294366646UL, 1952884323UL, 3573866689UL, 2040734807UL, 232392443UL, 4183498179UL, 2614866055UL, 440744432UL, 3624018350UL, 3340709877UL, 3097507723UL, 1268833488UL, 224895395UL, 3338260086UL, 293812421UL, 3683058169UL, 1147960351UL, 3433425235UL, 2171233479UL, 1830154455UL, 4036602681UL, 1996981699UL, 2875889721UL, 40256165UL, 2158110401UL, 3575159090UL, 3196553513UL, +1094082574UL, 3402884675UL, 1998393432UL, 2665389278UL, 3989307699UL, 4068940467UL, 3617519767UL, 3243522970UL, 1243992413UL, 2200497260UL, 441678457UL, 3715729085UL, 3451270040UL, 3044132745UL, 2101287249UL, 2181502237UL, 3173635549UL, 1724350416UL, 3228881240UL, 3123386528UL, 1968352124UL, 2287520039UL, 2635534069UL, 3622906431UL, 206207480UL, 2065093599UL, 96723416UL, 1011223653UL, 7271757UL, 2972858087UL, 1094044749UL, 1668335352UL, +2593296740UL, 174093751UL, 3713822176UL, 2887397643UL, 49226793UL, 1171716408UL, 2867257989UL, 1522213957UL, 984348433UL, 118712412UL, 2174928148UL, 1468226225UL, 3938290338UL, 2279430036UL, 3788174304UL, 2585475729UL, 3112454413UL, 1881171707UL, 4247636500UL, 3351139844UL, 380428329UL, 3341885423UL, 3307510279UL, 2887754196UL, 1368994724UL, 2555826262UL, 109341943UL, 2382715395UL, 2836761616UL, 1561509458UL, 2163678014UL, 3379783137UL, +2810374300UL, 1635278016UL, 2313252274UL, 316017838UL, 1899237567UL, 70857401UL, 3481535811UL, 2585770746UL, 2580352177UL, 32879620UL, 4171670150UL, 2248003250UL, 3317983509UL, 2073132526UL, 2603712175UL, 377997975UL, 3286162818UL, 908728599UL, 812664089UL, 1778922726UL, 1686111212UL, 4024815755UL, 1992540005UL, 2711468739UL, 423435866UL, 1661961159UL, 2257259057UL, 907108769UL, 1760295704UL, 3357409828UL, 215039860UL, 3917391198UL, +2806826652UL, 3609261689UL, 2167554309UL, 1831085281UL, 4238043113UL, 2755692689UL, 628277197UL, 2900207619UL, 993609502UL, 2036092353UL, 3605915742UL, 3652352199UL, 1780133580UL, 1670387713UL, 118446953UL, 3717326627UL, 783029246UL, 2165667566UL, 1739001057UL, 203160626UL, 2355216626UL, 1945278055UL, 3941185940UL, 3685368326UL, 546361979UL, 4024097818UL, 801752UL, 2729497735UL, 492844690UL, 1023017124UL, 2719601647UL, 3679088359UL, +2196391660UL, 4222269404UL, 621859651UL, 1319821972UL, 1819614072UL, 2348798457UL, 4294366646UL, 1114888560UL, 3573866689UL, 2040734807UL, 232392443UL, 4183498179UL, 3959504609UL, 440744432UL, 3624018350UL, 3340709877UL, 3097507723UL, 3613295037UL, 224895395UL, 3338260086UL, 293812421UL, 3683058169UL, 1655305863UL, 3433425235UL, 2171233479UL, 1830154455UL, 4036602681UL, 3731384097UL, 2875889721UL, 40256165UL, 2158110401UL, 3575159090UL, +1847744924UL, 1094082574UL, 3402884675UL, 1998393432UL, 2665389278UL, 3781866777UL, 4068940467UL, 3617519767UL, 3243522970UL, 1243992413UL, 2723708256UL, 441678457UL, 3715729085UL, 3451270040UL, 3044132745UL, 4013832842UL, 2181502237UL, 3173635549UL, 1724350416UL, 3228881240UL, 2092292494UL, 1968352124UL, 2287520039UL, 2635534069UL, 3622906431UL, 3186333458UL, 2065093599UL, 96723416UL, 1011223653UL, 7271757UL, 649658033UL, 1094044749UL, +1668335352UL, 2593296740UL, 174093751UL, 4159420309UL, 2887397643UL, 49226793UL, 1171716408UL, 2867257989UL, 2590077953UL, 984348433UL, 118712412UL, 2174928148UL, 1468226225UL, 1065322711UL, 2279430036UL, 3788174304UL, 2585475729UL, 3112454413UL, 3932517386UL, 4247636500UL, 3351139844UL, 380428329UL, 3341885423UL, 1285273904UL, 2887754196UL, 1368994724UL, 2555826262UL, 109341943UL, 2318470582UL, 2836761616UL, 1561509458UL, 2163678014UL, +3379783137UL, 674658583UL, 1635278016UL, 2313252274UL, 316017838UL, 1899237567UL, 2192372173UL, 3481535811UL, 2585770746UL, 2580352177UL, 32879620UL, 300323274UL, 2248003250UL, 3317983509UL, 2073132526UL, 2603712175UL, 3086543917UL, 3286162818UL, 908728599UL, 812664089UL, 1778922726UL, 2263290659UL, 4024815755UL, 1992540005UL, 2711468739UL, 423435866UL, 819027349UL, 2257259057UL, 907108769UL, 1760295704UL, 3357409828UL, 1142221093UL, +3917391198UL, 2806826652UL, 3609261689UL, 2167554309UL, 4108155875UL, 4238043113UL, 2755692689UL, 628277197UL, 2900207619UL, 3041719497UL, 2036092353UL, 3605915742UL, 3652352199UL, 1780133580UL, 2397410862UL, 118446953UL, 3717326627UL, 783029246UL, 2165667566UL, 2721690354UL, 203160626UL, 2355216626UL, 1945278055UL, 3941185940UL, 2768842108UL, 546361979UL, 4024097818UL, 801752UL, 2729497735UL, 4045063232UL, 1023017124UL, 2719601647UL, +3679088359UL, 2196391660UL, 2666107451UL, 621859651UL, 1319821972UL, 1819614072UL, 2348798457UL, 3555102623UL, 1114888560UL, 3573866689UL, 2040734807UL, 232392443UL, 3359040541UL, 3959504609UL, 440744432UL, 3624018350UL, 3340709877UL, 1477919696UL, 3613295037UL, 224895395UL, 3338260086UL, 293812421UL, 4210187101UL, 1655305863UL, 3433425235UL, 2171233479UL, 1830154455UL, 4150241150UL, 3731384097UL, 2875889721UL, 40256165UL, 2158110401UL, +3350246687UL, 455561037UL, 2250400255UL, 3192153445UL, 3258870230UL, 1500391873UL, 4142878334UL, 1155955691UL, 1483275844UL, 4189436981UL, 323745948UL, 1976017426UL, 2804626790UL, 2717553615UL, 2315409034UL, 954508235UL, 3845175920UL, 3999878682UL, 1247696432UL, 1743319509UL, 2998248398UL, 3694350012UL, 4072006361UL, 191306987UL, 2816321878UL, 1324077734UL, 1083060006UL, 3406855480UL, 1619622379UL, 2160350UL, 3302238190UL, 3368021261UL, +3685228564UL, 3863934685UL, 771728612UL, 854205233UL, 2304696695UL, 421449207UL, 1265752117UL, 3852292419UL, 305345788UL, 1540622105UL, 1904883477UL, 833469256UL, 134406680UL, 3012455058UL, 4035477953UL, 2925192459UL, 1559200592UL, 3851612860UL, 718484562UL, 1377960276UL, 1586892849UL, 1361298269UL, 3417917896UL, 1281324499UL, 1012538763UL, 1350578667UL, 3946475598UL, 2982283954UL, 3548792804UL, 284542749UL, 1194648577UL, 3087899716UL, +3966595444UL, 2088330116UL, 3641652062UL, 327128507UL, 593906557UL, 1092448919UL, 2459189516UL, 4053392241UL, 3356198248UL, 2352376508UL, 470648997UL, 1017041256UL, 3234172340UL, 3928191489UL, 3266226858UL, 4219289150UL, 1229098319UL, 4275351308UL, 2720777751UL, 3566728718UL, 638322822UL, 2369792461UL, 2869492261UL, 3120083828UL, 1890399556UL, 3309991008UL, 3785452464UL, 4128660314UL, 3726791982UL, 167177896UL, 461294981UL, 3988638998UL, +2937794823UL, 3981029822UL, 1111681402UL, 2015965721UL, 7261806UL, 2669786265UL, 1083582734UL, 3270228881UL, 3892235938UL, 2695872715UL, 4246051290UL, 3214293333UL, 343604199UL, 3215604888UL, 661024127UL, 2931754053UL, 3787840039UL, 2053363765UL, 363432336UL, 112334132UL, 2871797223UL, 138911320UL, 3981126938UL, 2027332192UL, 1804730644UL, 590150270UL, 641538574UL, 6802174UL, 3551446076UL, 3908480472UL, 1004531022UL, 2097228524UL, +1919074232UL, 154482247UL, 121437972UL, 1215661323UL, 1178068273UL, 1097220699UL, 2823681422UL, 262636065UL, 2943371149UL, 1768780720UL, 3866040605UL, 1855991583UL, 3988248086UL, 629223947UL, 3380612330UL, 3552916762UL, 197596340UL, 573801686UL, 2049230598UL, 2910471867UL, 2686314264UL, 1726228846UL, 3516983332UL, 726840185UL, 1241204222UL, 2237574317UL, 70568042UL, 1932610099UL, 2221862221UL, 1510378092UL, 4050391637UL, 4077539568UL, +}, +{ +3872117793UL, 803220151UL, 70843412UL, 1661103032UL, 1976811457UL, 2186373604UL, 564259972UL, 1475436923UL, 2260980893UL, 4245534505UL, 1075107552UL, 3692990573UL, 370098873UL, 4045905424UL, 2420395420UL, 2332395402UL, 207483321UL, 622317750UL, 3004242500UL, 833623111UL, 3151161301UL, 1629139881UL, 352228793UL, 2439953368UL, 3183333619UL, 2703537080UL, 3218957129UL, 3164695888UL, 1741641842UL, 963394141UL, 4241612717UL, 1034476784UL, +2035880432UL, 3977821313UL, 1543311495UL, 3010014356UL, 1638490901UL, 2364265378UL, 3420329129UL, 333361555UL, 1133565821UL, 1450937015UL, 616059115UL, 3216393887UL, 3041978455UL, 3990855695UL, 1238628750UL, 512746184UL, 3256670217UL, 1616316512UL, 2791405051UL, 93474487UL, 2865892488UL, 1901471398UL, 2930857966UL, 2178431077UL, 2325598341UL, 3189256113UL, 1302432091UL, 808592927UL, 2945846737UL, 3487931071UL, 2018175258UL, 752981057UL, +1097082589UL, 1307115286UL, 175147508UL, 3611190164UL, 850238914UL, 3318706185UL, 199743319UL, 328621708UL, 3183670050UL, 3609998315UL, 4075306371UL, 3554549067UL, 2119566187UL, 1498503842UL, 1261870696UL, 2216745780UL, 950288337UL, 1117344941UL, 2150569143UL, 2899286760UL, 1594966374UL, 888858617UL, 35840654UL, 2829539211UL, 2511395669UL, 3607190544UL, 3278412778UL, 2249895907UL, 1320858068UL, 3576889788UL, 266766189UL, 1522426851UL, +1903494122UL, 1928370573UL, 2628132591UL, 3322025904UL, 220280169UL, 433606853UL, 1428961479UL, 986074592UL, 2128892987UL, 467697583UL, 1616913929UL, 325674890UL, 444442578UL, 649166208UL, 1689709565UL, 1493452467UL, 2222122038UL, 121114616UL, 2134348225UL, 3512035688UL, 1283058921UL, 4230441398UL, 3701238559UL, 337534132UL, 1418548715UL, 1190006478UL, 500654385UL, 1766924757UL, 1944680746UL, 940574010UL, 922744002UL, 186142284UL, +3131162902UL, 1693891092UL, 3031823448UL, 2143051534UL, 1429025284UL, 1487843160UL, 3606456133UL, 2079235652UL, 2447285474UL, 2669283767UL, 3232117829UL, 2490054343UL, 3225501736UL, 2911340385UL, 382319031UL, 1516937595UL, 622543191UL, 1388990570UL, 1749179860UL, 1924483707UL, 2593474505UL, 472539197UL, 122872799UL, 2586347240UL, 880588515UL, 4046335279UL, 1712182607UL, 4270737941UL, 1336703451UL, 3390078162UL, 382216945UL, 3733326081UL, +460422073UL, 3872117793UL, 803220151UL, 70843412UL, 1661103032UL, 250339760UL, 2186373604UL, 564259972UL, 1475436923UL, 2260980893UL, 657986735UL, 1075107552UL, 3692990573UL, 370098873UL, 4045905424UL, 3201950123UL, 2332395402UL, 207483321UL, 622317750UL, 3004242500UL, 3732213278UL, 3151161301UL, 1629139881UL, 352228793UL, 2439953368UL, 3572618926UL, 2703537080UL, 3218957129UL, 3164695888UL, 1741641842UL, 685933373UL, 4241612717UL, +1034476784UL, 2035880432UL, 3977821313UL, 3855995181UL, 3010014356UL, 1638490901UL, 2364265378UL, 3420329129UL, 2355603679UL, 1133565821UL, 1450937015UL, 616059115UL, 3216393887UL, 1733804102UL, 3990855695UL, 1238628750UL, 512746184UL, 3256670217UL, 2651059231UL, 2791405051UL, 93474487UL, 2865892488UL, 1901471398UL, 2113461797UL, 2178431077UL, 2325598341UL, 3189256113UL, 1302432091UL, 2986990416UL, 2945846737UL, 3487931071UL, 2018175258UL, +752981057UL, 2428033310UL, 1307115286UL, 175147508UL, 3611190164UL, 850238914UL, 1033628405UL, 199743319UL, 328621708UL, 3183670050UL, 3609998315UL, 4024297327UL, 3554549067UL, 2119566187UL, 1498503842UL, 1261870696UL, 290361143UL, 950288337UL, 1117344941UL, 2150569143UL, 2899286760UL, 168826051UL, 888858617UL, 35840654UL, 2829539211UL, 2511395669UL, 2890882060UL, 3278412778UL, 2249895907UL, 1320858068UL, 3576889788UL, 1794920145UL, +1522426851UL, 1903494122UL, 1928370573UL, 2628132591UL, 1251697758UL, 220280169UL, 433606853UL, 1428961479UL, 986074592UL, 2707115661UL, 467697583UL, 1616913929UL, 325674890UL, 444442578UL, 122781510UL, 1689709565UL, 1493452467UL, 2222122038UL, 121114616UL, 3425723636UL, 3512035688UL, 1283058921UL, 4230441398UL, 3701238559UL, 1646155473UL, 1418548715UL, 1190006478UL, 500654385UL, 1766924757UL, 3920475367UL, 940574010UL, 922744002UL, +186142284UL, 3131162902UL, 54639113UL, 3031823448UL, 2143051534UL, 1429025284UL, 1487843160UL, 4152687885UL, 2079235652UL, 2447285474UL, 2669283767UL, 3232117829UL, 1601035152UL, 3225501736UL, 2911340385UL, 382319031UL, 1516937595UL, 3508441679UL, 1388990570UL, 1749179860UL, 1924483707UL, 2593474505UL, 2835403456UL, 122872799UL, 2586347240UL, 880588515UL, 4046335279UL, 2958058367UL, 4270737941UL, 1336703451UL, 3390078162UL, 382216945UL, +450517882UL, 460422073UL, 3872117793UL, 803220151UL, 70843412UL, 2066343874UL, 250339760UL, 2186373604UL, 564259972UL, 1475436923UL, 1683787449UL, 657986735UL, 1075107552UL, 3692990573UL, 370098873UL, 2615082840UL, 3201950123UL, 2332395402UL, 207483321UL, 622317750UL, 2655424371UL, 3732213278UL, 3151161301UL, 1629139881UL, 352228793UL, 3236724760UL, 3572618926UL, 2703537080UL, 3218957129UL, 3164695888UL, 9775065UL, 685933373UL, +4241612717UL, 1034476784UL, 2035880432UL, 1621920075UL, 3855995181UL, 3010014356UL, 1638490901UL, 2364265378UL, 1509475888UL, 2355603679UL, 1133565821UL, 1450937015UL, 616059115UL, 3666188236UL, 1733804102UL, 3990855695UL, 1238628750UL, 512746184UL, 3900473826UL, 2651059231UL, 2791405051UL, 93474487UL, 2865892488UL, 222759186UL, 2113461797UL, 2178431077UL, 2325598341UL, 3189256113UL, 2505499508UL, 2986990416UL, 2945846737UL, 3487931071UL, +2018175258UL, 2766733928UL, 2428033310UL, 1307115286UL, 175147508UL, 3611190164UL, 1909211603UL, 1033628405UL, 199743319UL, 328621708UL, 3183670050UL, 1680331218UL, 4024297327UL, 3554549067UL, 2119566187UL, 1498503842UL, 3516256046UL, 290361143UL, 950288337UL, 1117344941UL, 2150569143UL, 3182619063UL, 168826051UL, 888858617UL, 35840654UL, 2829539211UL, 645798943UL, 2890882060UL, 3278412778UL, 2249895907UL, 1320858068UL, 1436708568UL, +1794920145UL, 1522426851UL, 1903494122UL, 1928370573UL, 3693049252UL, 1251697758UL, 220280169UL, 433606853UL, 1428961479UL, 3724415861UL, 2707115661UL, 467697583UL, 1616913929UL, 325674890UL, 1448052253UL, 122781510UL, 1689709565UL, 1493452467UL, 2222122038UL, 2177448198UL, 3425723636UL, 3512035688UL, 1283058921UL, 4230441398UL, 3050940272UL, 1646155473UL, 1418548715UL, 1190006478UL, 500654385UL, 1106232UL, 3920475367UL, 940574010UL, +922744002UL, 186142284UL, 4144806511UL, 54639113UL, 3031823448UL, 2143051534UL, 1429025284UL, 2067453848UL, 4152687885UL, 2079235652UL, 2447285474UL, 2669283767UL, 428527087UL, 1601035152UL, 3225501736UL, 2911340385UL, 382319031UL, 2565464472UL, 3508441679UL, 1388990570UL, 1749179860UL, 1924483707UL, 1737735237UL, 2835403456UL, 122872799UL, 2586347240UL, 880588515UL, 597822462UL, 2958058367UL, 4270737941UL, 1336703451UL, 3390078162UL, +2532634475UL, 450517882UL, 460422073UL, 3872117793UL, 803220151UL, 801648827UL, 2066343874UL, 250339760UL, 2186373604UL, 564259972UL, 3417948976UL, 1683787449UL, 657986735UL, 1075107552UL, 3692990573UL, 2235306692UL, 2615082840UL, 3201950123UL, 2332395402UL, 207483321UL, 699310933UL, 2655424371UL, 3732213278UL, 3151161301UL, 1629139881UL, 1152704006UL, 3236724760UL, 3572618926UL, 2703537080UL, 3218957129UL, 2726926336UL, 9775065UL, +685933373UL, 4241612717UL, 1034476784UL, 2398119652UL, 1621920075UL, 3855995181UL, 3010014356UL, 1638490901UL, 252854480UL, 1509475888UL, 2355603679UL, 1133565821UL, 1450937015UL, 2655911639UL, 3666188236UL, 1733804102UL, 3990855695UL, 1238628750UL, 1115900497UL, 3900473826UL, 2651059231UL, 2791405051UL, 93474487UL, 1862985957UL, 222759186UL, 2113461797UL, 2178431077UL, 2325598341UL, 4179075132UL, 2505499508UL, 2986990416UL, 2945846737UL, +3487931071UL, 564667776UL, 2766733928UL, 2428033310UL, 1307115286UL, 175147508UL, 1759077815UL, 1909211603UL, 1033628405UL, 199743319UL, 328621708UL, 2552816198UL, 1680331218UL, 4024297327UL, 3554549067UL, 2119566187UL, 2267805778UL, 3516256046UL, 290361143UL, 950288337UL, 1117344941UL, 2897506172UL, 3182619063UL, 168826051UL, 888858617UL, 35840654UL, 2035476068UL, 645798943UL, 2890882060UL, 3278412778UL, 2249895907UL, 3278449102UL, +1436708568UL, 1794920145UL, 1522426851UL, 1903494122UL, 1500763736UL, 3693049252UL, 1251697758UL, 220280169UL, 433606853UL, 3914497854UL, 3724415861UL, 2707115661UL, 467697583UL, 1616913929UL, 918435305UL, 1448052253UL, 122781510UL, 1689709565UL, 1493452467UL, 609575172UL, 2177448198UL, 3425723636UL, 3512035688UL, 1283058921UL, 3661181550UL, 3050940272UL, 1646155473UL, 1418548715UL, 1190006478UL, 1047301661UL, 1106232UL, 3920475367UL, +940574010UL, 922744002UL, 2510633517UL, 4144806511UL, 54639113UL, 3031823448UL, 2143051534UL, 3242814908UL, 2067453848UL, 4152687885UL, 2079235652UL, 2447285474UL, 736638210UL, 428527087UL, 1601035152UL, 3225501736UL, 2911340385UL, 1849570436UL, 2565464472UL, 3508441679UL, 1388990570UL, 1749179860UL, 84517579UL, 1737735237UL, 2835403456UL, 122872799UL, 2586347240UL, 4002124614UL, 597822462UL, 2958058367UL, 4270737941UL, 1336703451UL, +3078170472UL, 1186434751UL, 700631413UL, 1497890797UL, 1195347450UL, 2560167391UL, 1116697259UL, 1254138573UL, 747913260UL, 240954704UL, 3107512667UL, 360584144UL, 3422778960UL, 3516528389UL, 3301260366UL, 1254513537UL, 122269053UL, 1579582456UL, 873334104UL, 3918835024UL, 1731872444UL, 1974410416UL, 1811172641UL, 4172523062UL, 4092675777UL, 4124987343UL, 1936078756UL, 1757348689UL, 2694415512UL, 128641660UL, 1744777659UL, 3173116729UL, +983733754UL, 1430789547UL, 701906842UL, 3367232568UL, 3266433501UL, 3572590347UL, 1453272962UL, 2106553114UL, 993786201UL, 2149441250UL, 1295181065UL, 2962229026UL, 3709052556UL, 3255608941UL, 3677730029UL, 483873127UL, 102227292UL, 2626265293UL, 2018984578UL, 2266388762UL, 1191709548UL, 2152725916UL, 583672623UL, 2230473473UL, 1995194269UL, 1740347812UL, 2558095372UL, 3070195183UL, 3023333227UL, 2497183195UL, 1908755188UL, 773027539UL, +3646876518UL, 2272586839UL, 493318726UL, 2107067517UL, 2000805278UL, 2530829636UL, 3183628745UL, 677565332UL, 1497629423UL, 82094920UL, 2214054433UL, 2635367545UL, 470855467UL, 2184853389UL, 2942188934UL, 188335670UL, 3656661644UL, 1883526235UL, 3990873975UL, 1490784356UL, 4047548172UL, 3149642641UL, 3289988179UL, 2590918909UL, 2893039564UL, 2350687346UL, 4252624874UL, 15372456UL, 1614496594UL, 2364847678UL, 2604511825UL, 422365460UL, +4195174772UL, 3266964836UL, 2008671995UL, 54038434UL, 781948549UL, 1276017666UL, 2756376612UL, 2436825273UL, 1711863836UL, 3541493950UL, 3821378841UL, 1007557618UL, 345375815UL, 2081905201UL, 2227278118UL, 1185927141UL, 1082173792UL, 3567361925UL, 1940465859UL, 541632942UL, 1830210248UL, 3757851982UL, 775883450UL, 1666577465UL, 1004944607UL, 878440834UL, 2146344131UL, 4195798476UL, 370164841UL, 3649112729UL, 37066142UL, 2311278904UL, +1935745497UL, 2304799402UL, 4107299626UL, 1348526232UL, 2473609635UL, 3284032699UL, 2374292786UL, 1762329186UL, 857978496UL, 1039346432UL, 2621413355UL, 29961014UL, 3582263091UL, 4268542513UL, 3890612190UL, 3096173646UL, 2026544230UL, 3856142618UL, 2347115934UL, 319800326UL, 3255916105UL, 2430273059UL, 823505311UL, 874255188UL, 1401925393UL, 4203707857UL, 4259159566UL, 2606881118UL, 1978288664UL, 1447576038UL, 3860341401UL, 412510348UL, +}, +{ +4052471963UL, 683640040UL, 3043876021UL, 3466644483UL, 4222418025UL, 3035140128UL, 1466027937UL, 18198088UL, 3410320851UL, 3040963721UL, 488404231UL, 3157371815UL, 769336092UL, 3240417718UL, 808582581UL, 2075839263UL, 835026995UL, 3123726486UL, 3284240985UL, 1898453053UL, 3606056482UL, 512836002UL, 2715428547UL, 4182302879UL, 1644882480UL, 3160187826UL, 390292489UL, 980889545UL, 2776206633UL, 2482799995UL, 617042280UL, 3501667414UL, +689451808UL, 497018701UL, 238525753UL, 3890163301UL, 896679896UL, 1544533015UL, 3412477225UL, 3116575138UL, 4250402651UL, 3990990746UL, 819056741UL, 1459334146UL, 158377590UL, 3444755752UL, 8230450UL, 1378706455UL, 684191332UL, 3217423797UL, 2842520097UL, 1631477948UL, 2591254230UL, 959644473UL, 1020694107UL, 1748401915UL, 3452514983UL, 3892766171UL, 1227786994UL, 2086180800UL, 2394613217UL, 2091953150UL, 870094953UL, 2306851481UL, +571550601UL, 488878212UL, 873197214UL, 2630100528UL, 2067476907UL, 2162307009UL, 2026119728UL, 115875280UL, 2905867426UL, 248774881UL, 3110900450UL, 2236032812UL, 1888510348UL, 708001855UL, 996960491UL, 3514196956UL, 1407967546UL, 1826568876UL, 3659618284UL, 2614104317UL, 2230066308UL, 1055135881UL, 2537437343UL, 1858044413UL, 2608594891UL, 2750681169UL, 3241939420UL, 3966440877UL, 2375002886UL, 2417753441UL, 1405878685UL, 1081133199UL, +1496940727UL, 382467042UL, 2745477587UL, 1209424459UL, 811187075UL, 1385604734UL, 2623887355UL, 3443875720UL, 394141555UL, 4142998949UL, 4195414618UL, 1489846841UL, 2253433808UL, 1171450286UL, 84131191UL, 4387588UL, 2641405140UL, 3525405389UL, 3273000909UL, 423660319UL, 2366546732UL, 3698878607UL, 2161119729UL, 4263629085UL, 3029102089UL, 2692507376UL, 3266869596UL, 1658012061UL, 1960169440UL, 1002311379UL, 3724446882UL, 2004188516UL, +999513506UL, 2200093802UL, 4141037460UL, 351865836UL, 412875013UL, 1535823315UL, 3880657632UL, 3109944987UL, 3207577548UL, 3462087941UL, 584875517UL, 2635241084UL, 3834145971UL, 1693380373UL, 3524443732UL, 934775214UL, 1960588847UL, 2226778032UL, 1044609478UL, 12199016UL, 1120582000UL, 226430296UL, 665553142UL, 2570993348UL, 1685535237UL, 3325420136UL, 3925248326UL, 2855346376UL, 1205558328UL, 808835317UL, 3295908896UL, 4170076136UL, +2438272365UL, 4052471963UL, 683640040UL, 3043876021UL, 3466644483UL, 1385549869UL, 3035140128UL, 1466027937UL, 18198088UL, 3410320851UL, 2171386836UL, 488404231UL, 3157371815UL, 769336092UL, 3240417718UL, 2921774554UL, 2075839263UL, 835026995UL, 3123726486UL, 3284240985UL, 72352110UL, 3606056482UL, 512836002UL, 2715428547UL, 4182302879UL, 3869483469UL, 3160187826UL, 390292489UL, 980889545UL, 2776206633UL, 1385691983UL, 617042280UL, +3501667414UL, 689451808UL, 497018701UL, 2600411809UL, 3890163301UL, 896679896UL, 1544533015UL, 3412477225UL, 356556378UL, 4250402651UL, 3990990746UL, 819056741UL, 1459334146UL, 199003993UL, 3444755752UL, 8230450UL, 1378706455UL, 684191332UL, 1750733272UL, 2842520097UL, 1631477948UL, 2591254230UL, 959644473UL, 2113375576UL, 1748401915UL, 3452514983UL, 3892766171UL, 1227786994UL, 275473920UL, 2394613217UL, 2091953150UL, 870094953UL, +2306851481UL, 897057645UL, 488878212UL, 873197214UL, 2630100528UL, 2067476907UL, 944114068UL, 2026119728UL, 115875280UL, 2905867426UL, 248774881UL, 989201307UL, 2236032812UL, 1888510348UL, 708001855UL, 996960491UL, 2121706374UL, 1407967546UL, 1826568876UL, 3659618284UL, 2614104317UL, 2931815032UL, 1055135881UL, 2537437343UL, 1858044413UL, 2608594891UL, 1423973935UL, 3241939420UL, 3966440877UL, 2375002886UL, 2417753441UL, 2514473440UL, +1081133199UL, 1496940727UL, 382467042UL, 2745477587UL, 81977310UL, 811187075UL, 1385604734UL, 2623887355UL, 3443875720UL, 2100629879UL, 4142998949UL, 4195414618UL, 1489846841UL, 2253433808UL, 337182869UL, 84131191UL, 4387588UL, 2641405140UL, 3525405389UL, 661876463UL, 423660319UL, 2366546732UL, 3698878607UL, 2161119729UL, 309510684UL, 3029102089UL, 2692507376UL, 3266869596UL, 1658012061UL, 11119541UL, 1002311379UL, 3724446882UL, +2004188516UL, 999513506UL, 3486722046UL, 4141037460UL, 351865836UL, 412875013UL, 1535823315UL, 2818130700UL, 3109944987UL, 3207577548UL, 3462087941UL, 584875517UL, 322875622UL, 3834145971UL, 1693380373UL, 3524443732UL, 934775214UL, 3879414752UL, 2226778032UL, 1044609478UL, 12199016UL, 1120582000UL, 4207259464UL, 665553142UL, 2570993348UL, 1685535237UL, 3325420136UL, 553869152UL, 2855346376UL, 1205558328UL, 808835317UL, 3295908896UL, +470585896UL, 2438272365UL, 4052471963UL, 683640040UL, 3043876021UL, 1588419572UL, 1385549869UL, 3035140128UL, 1466027937UL, 18198088UL, 363815288UL, 2171386836UL, 488404231UL, 3157371815UL, 769336092UL, 2464768302UL, 2921774554UL, 2075839263UL, 835026995UL, 3123726486UL, 4229246330UL, 72352110UL, 3606056482UL, 512836002UL, 2715428547UL, 319830805UL, 3869483469UL, 3160187826UL, 390292489UL, 980889545UL, 2966401462UL, 1385691983UL, +617042280UL, 3501667414UL, 689451808UL, 4047377762UL, 2600411809UL, 3890163301UL, 896679896UL, 1544533015UL, 764316452UL, 356556378UL, 4250402651UL, 3990990746UL, 819056741UL, 965331966UL, 199003993UL, 3444755752UL, 8230450UL, 1378706455UL, 51902971UL, 1750733272UL, 2842520097UL, 1631477948UL, 2591254230UL, 426039404UL, 2113375576UL, 1748401915UL, 3452514983UL, 3892766171UL, 2833368447UL, 275473920UL, 2394613217UL, 2091953150UL, +870094953UL, 3524323828UL, 897057645UL, 488878212UL, 873197214UL, 2630100528UL, 3939852929UL, 944114068UL, 2026119728UL, 115875280UL, 2905867426UL, 3192643919UL, 989201307UL, 2236032812UL, 1888510348UL, 708001855UL, 2166012172UL, 2121706374UL, 1407967546UL, 1826568876UL, 3659618284UL, 135277096UL, 2931815032UL, 1055135881UL, 2537437343UL, 1858044413UL, 2588429924UL, 1423973935UL, 3241939420UL, 3966440877UL, 2375002886UL, 2477142003UL, +2514473440UL, 1081133199UL, 1496940727UL, 382467042UL, 1760129281UL, 81977310UL, 811187075UL, 1385604734UL, 2623887355UL, 4070531513UL, 2100629879UL, 4142998949UL, 4195414618UL, 1489846841UL, 2688068550UL, 337182869UL, 84131191UL, 4387588UL, 2641405140UL, 1837403234UL, 661876463UL, 423660319UL, 2366546732UL, 3698878607UL, 2916121190UL, 309510684UL, 3029102089UL, 2692507376UL, 3266869596UL, 303422295UL, 11119541UL, 1002311379UL, +3724446882UL, 2004188516UL, 2652711421UL, 3486722046UL, 4141037460UL, 351865836UL, 412875013UL, 113149471UL, 2818130700UL, 3109944987UL, 3207577548UL, 3462087941UL, 1443140792UL, 322875622UL, 3834145971UL, 1693380373UL, 3524443732UL, 901891935UL, 3879414752UL, 2226778032UL, 1044609478UL, 12199016UL, 2213168758UL, 4207259464UL, 665553142UL, 2570993348UL, 1685535237UL, 1114492412UL, 553869152UL, 2855346376UL, 1205558328UL, 808835317UL, +3266626294UL, 470585896UL, 2438272365UL, 4052471963UL, 683640040UL, 3581539398UL, 1588419572UL, 1385549869UL, 3035140128UL, 1466027937UL, 4075470388UL, 363815288UL, 2171386836UL, 488404231UL, 3157371815UL, 2759472233UL, 2464768302UL, 2921774554UL, 2075839263UL, 835026995UL, 1030654310UL, 4229246330UL, 72352110UL, 3606056482UL, 512836002UL, 961858496UL, 319830805UL, 3869483469UL, 3160187826UL, 390292489UL, 2366221117UL, 2966401462UL, +1385691983UL, 617042280UL, 3501667414UL, 295865937UL, 4047377762UL, 2600411809UL, 3890163301UL, 896679896UL, 21714884UL, 764316452UL, 356556378UL, 4250402651UL, 3990990746UL, 1012967081UL, 965331966UL, 199003993UL, 3444755752UL, 8230450UL, 1255302023UL, 51902971UL, 1750733272UL, 2842520097UL, 1631477948UL, 2321320272UL, 426039404UL, 2113375576UL, 1748401915UL, 3452514983UL, 2847013518UL, 2833368447UL, 275473920UL, 2394613217UL, +2091953150UL, 1250695522UL, 3524323828UL, 897057645UL, 488878212UL, 873197214UL, 1452317325UL, 3939852929UL, 944114068UL, 2026119728UL, 115875280UL, 4061820350UL, 3192643919UL, 989201307UL, 2236032812UL, 1888510348UL, 3986446165UL, 2166012172UL, 2121706374UL, 1407967546UL, 1826568876UL, 2910745432UL, 135277096UL, 2931815032UL, 1055135881UL, 2537437343UL, 2976455307UL, 2588429924UL, 1423973935UL, 3241939420UL, 3966440877UL, 2418897705UL, +2477142003UL, 2514473440UL, 1081133199UL, 1496940727UL, 1321648771UL, 1760129281UL, 81977310UL, 811187075UL, 1385604734UL, 17644628UL, 4070531513UL, 2100629879UL, 4142998949UL, 4195414618UL, 2697310527UL, 2688068550UL, 337182869UL, 84131191UL, 4387588UL, 1724191700UL, 1837403234UL, 661876463UL, 423660319UL, 2366546732UL, 693430992UL, 2916121190UL, 309510684UL, 3029102089UL, 2692507376UL, 3917396098UL, 303422295UL, 11119541UL, +1002311379UL, 3724446882UL, 841468294UL, 2652711421UL, 3486722046UL, 4141037460UL, 351865836UL, 1733384185UL, 113149471UL, 2818130700UL, 3109944987UL, 3207577548UL, 2326233100UL, 1443140792UL, 322875622UL, 3834145971UL, 1693380373UL, 1580706359UL, 901891935UL, 3879414752UL, 2226778032UL, 1044609478UL, 3805470822UL, 2213168758UL, 4207259464UL, 665553142UL, 2570993348UL, 3406548636UL, 1114492412UL, 553869152UL, 2855346376UL, 1205558328UL, +4287831475UL, 1329654114UL, 2347235746UL, 2477803138UL, 2962371859UL, 3610024283UL, 4197266903UL, 1162294689UL, 1746713323UL, 2815058477UL, 2152552186UL, 4214791071UL, 2382522482UL, 3713914466UL, 3974765132UL, 348354997UL, 1670276150UL, 2173074887UL, 381736894UL, 3866219357UL, 1919366695UL, 3635118824UL, 2298653261UL, 3534332682UL, 1627699897UL, 4168636618UL, 3787938690UL, 2144231271UL, 2067679462UL, 217001062UL, 2308928337UL, 1620415125UL, +3526559172UL, 749451561UL, 2456947371UL, 3543607786UL, 1893824735UL, 962598819UL, 2332807164UL, 1691114891UL, 2543992233UL, 2914780639UL, 1610287145UL, 1700599697UL, 3185174208UL, 552323208UL, 2367242224UL, 3797136972UL, 3415066418UL, 2468049249UL, 1677937401UL, 40445671UL, 2886682530UL, 2585715434UL, 194932329UL, 2994003812UL, 3099556382UL, 680852222UL, 135838738UL, 1371063256UL, 995454898UL, 3754526418UL, 803635682UL, 634588682UL, +3869250783UL, 2442285521UL, 1455637058UL, 570621479UL, 2512681851UL, 1220136924UL, 750260121UL, 2909903038UL, 1582019728UL, 955115170UL, 1608265445UL, 2157390890UL, 2303678604UL, 1568394164UL, 831914289UL, 1971271392UL, 1294799854UL, 1489945167UL, 442427880UL, 1305083700UL, 1211218668UL, 2380073713UL, 2798736785UL, 2193524273UL, 3227386915UL, 1636588977UL, 3612937642UL, 435113647UL, 1591761830UL, 536210039UL, 2475747073UL, 4223795480UL, +1786737271UL, 1444661534UL, 3249410301UL, 3333695212UL, 4169107188UL, 3280638635UL, 702659930UL, 1444127970UL, 225340755UL, 2255629368UL, 746584456UL, 3965677674UL, 2671132955UL, 2080717656UL, 2145343886UL, 3712441197UL, 368422910UL, 1297685674UL, 4076123901UL, 26214470UL, 2948764826UL, 40503299UL, 1198194334UL, 2100063637UL, 1966331612UL, 2189582064UL, 2064696934UL, 1797550642UL, 3469793941UL, 2868963812UL, 851437659UL, 240918534UL, +365060070UL, 3530600064UL, 39695324UL, 1753898837UL, 1286976449UL, 3131971360UL, 2406485219UL, 3365373704UL, 3224113403UL, 1651742834UL, 587601940UL, 1574206085UL, 3739575036UL, 1413669616UL, 38172232UL, 293127854UL, 4126190109UL, 1891744061UL, 787878666UL, 456643669UL, 4228710325UL, 2025132037UL, 1492133135UL, 3122840937UL, 969442079UL, 3272420439UL, 3836126369UL, 1877655562UL, 2766212758UL, 3867984746UL, 3348077578UL, 1841216706UL, +}, +{ +1676507466UL, 1017841240UL, 2992644565UL, 476936158UL, 2468072723UL, 3113105154UL, 1154120402UL, 460889625UL, 1942263502UL, 1761593999UL, 3020908939UL, 3078194866UL, 310971889UL, 1644896012UL, 3756044556UL, 3549937583UL, 3710822994UL, 3554313733UL, 2174654326UL, 4251063242UL, 2340485150UL, 950951909UL, 4288936895UL, 3744348848UL, 706644559UL, 1085927825UL, 1595992020UL, 3288724966UL, 1367247946UL, 2950094970UL, 3925419886UL, 2628739022UL, +2528254629UL, 3582224789UL, 3907345559UL, 3373329273UL, 4255542251UL, 1185418446UL, 4018656113UL, 2854344020UL, 1381160022UL, 3642438773UL, 4284399225UL, 935780030UL, 4142412144UL, 1263328494UL, 1154237693UL, 2684443667UL, 3067549398UL, 4253090033UL, 1251034970UL, 1874233020UL, 3222830495UL, 3866931656UL, 286048055UL, 3146635362UL, 1436483376UL, 2821876495UL, 3927829532UL, 2648886905UL, 2142862852UL, 1368937545UL, 2647327844UL, 1072219385UL, +2621337706UL, 3543274652UL, 911792564UL, 1204178178UL, 4127214323UL, 2821691380UL, 3101998294UL, 730811902UL, 1989156224UL, 2872353003UL, 278290276UL, 1390223786UL, 2657819643UL, 552729795UL, 1736270535UL, 2759207116UL, 1897013739UL, 3657020278UL, 1387364861UL, 1966588302UL, 1049203087UL, 486446521UL, 3675999281UL, 714737345UL, 686837530UL, 85509025UL, 3609089773UL, 2117061768UL, 3935682560UL, 3859508784UL, 4105287041UL, 1808988481UL, +83680601UL, 1464326680UL, 1657693523UL, 3318062731UL, 1391154023UL, 234460119UL, 3551348221UL, 2245244809UL, 3635923821UL, 2814385745UL, 3497626257UL, 916790795UL, 245338628UL, 2514528380UL, 3711787525UL, 2239286063UL, 1054058916UL, 3963706010UL, 3176203796UL, 2230543409UL, 2173597546UL, 3786733892UL, 1396036965UL, 1038764273UL, 2032556038UL, 3216540537UL, 3298170974UL, 1008892557UL, 141155464UL, 1863766055UL, 3931110690UL, 191299053UL, +2019139711UL, 2409528317UL, 739418419UL, 1377144055UL, 2876702705UL, 3911939673UL, 1197696462UL, 2814009721UL, 600813233UL, 1535885024UL, 1486280357UL, 3084650548UL, 2324695947UL, 2293284974UL, 2036339249UL, 3465600153UL, 1624446108UL, 327866771UL, 3356772175UL, 1826625240UL, 1947102360UL, 3661848193UL, 1421374867UL, 3228945021UL, 1358646008UL, 1067180174UL, 2190741258UL, 643362354UL, 109899594UL, 2064362635UL, 3249674888UL, 2165543887UL, +4180291913UL, 1676507466UL, 1017841240UL, 2992644565UL, 476936158UL, 3608467942UL, 3113105154UL, 1154120402UL, 460889625UL, 1942263502UL, 1862994005UL, 3020908939UL, 3078194866UL, 310971889UL, 1644896012UL, 693774191UL, 3549937583UL, 3710822994UL, 3554313733UL, 2174654326UL, 37658897UL, 2340485150UL, 950951909UL, 4288936895UL, 3744348848UL, 2258231402UL, 1085927825UL, 1595992020UL, 3288724966UL, 1367247946UL, 3850509554UL, 3925419886UL, +2628739022UL, 2528254629UL, 3582224789UL, 3124287811UL, 3373329273UL, 4255542251UL, 1185418446UL, 4018656113UL, 1989726178UL, 1381160022UL, 3642438773UL, 4284399225UL, 935780030UL, 3622052196UL, 1263328494UL, 1154237693UL, 2684443667UL, 3067549398UL, 2786224913UL, 1251034970UL, 1874233020UL, 3222830495UL, 3866931656UL, 1529490307UL, 3146635362UL, 1436483376UL, 2821876495UL, 3927829532UL, 979247444UL, 2142862852UL, 1368937545UL, 2647327844UL, +1072219385UL, 294065371UL, 3543274652UL, 911792564UL, 1204178178UL, 4127214323UL, 103582737UL, 3101998294UL, 730811902UL, 1989156224UL, 2872353003UL, 1885087777UL, 1390223786UL, 2657819643UL, 552729795UL, 1736270535UL, 3325206451UL, 1897013739UL, 3657020278UL, 1387364861UL, 1966588302UL, 2117065739UL, 486446521UL, 3675999281UL, 714737345UL, 686837530UL, 3946214694UL, 3609089773UL, 2117061768UL, 3935682560UL, 3859508784UL, 2916136885UL, +1808988481UL, 83680601UL, 1464326680UL, 1657693523UL, 3438751781UL, 1391154023UL, 234460119UL, 3551348221UL, 2245244809UL, 3948410079UL, 2814385745UL, 3497626257UL, 916790795UL, 245338628UL, 1767303496UL, 3711787525UL, 2239286063UL, 1054058916UL, 3963706010UL, 4140631909UL, 2230543409UL, 2173597546UL, 3786733892UL, 1396036965UL, 1116033475UL, 2032556038UL, 3216540537UL, 3298170974UL, 1008892557UL, 667272562UL, 1863766055UL, 3931110690UL, +191299053UL, 2019139711UL, 272901326UL, 739418419UL, 1377144055UL, 2876702705UL, 3911939673UL, 3839312742UL, 2814009721UL, 600813233UL, 1535885024UL, 1486280357UL, 4256065219UL, 2324695947UL, 2293284974UL, 2036339249UL, 3465600153UL, 1215859603UL, 327866771UL, 3356772175UL, 1826625240UL, 1947102360UL, 4240407984UL, 1421374867UL, 3228945021UL, 1358646008UL, 1067180174UL, 4100357988UL, 643362354UL, 109899594UL, 2064362635UL, 3249674888UL, +2898852084UL, 4180291913UL, 1676507466UL, 1017841240UL, 2992644565UL, 1569683812UL, 3608467942UL, 3113105154UL, 1154120402UL, 460889625UL, 966040649UL, 1862994005UL, 3020908939UL, 3078194866UL, 310971889UL, 786634113UL, 693774191UL, 3549937583UL, 3710822994UL, 3554313733UL, 1578429713UL, 37658897UL, 2340485150UL, 950951909UL, 4288936895UL, 2528123823UL, 2258231402UL, 1085927825UL, 1595992020UL, 3288724966UL, 3544041088UL, 3850509554UL, +3925419886UL, 2628739022UL, 2528254629UL, 2562145937UL, 3124287811UL, 3373329273UL, 4255542251UL, 1185418446UL, 3693565710UL, 1989726178UL, 1381160022UL, 3642438773UL, 4284399225UL, 3271478204UL, 3622052196UL, 1263328494UL, 1154237693UL, 2684443667UL, 3615401444UL, 2786224913UL, 1251034970UL, 1874233020UL, 3222830495UL, 2572413057UL, 1529490307UL, 3146635362UL, 1436483376UL, 2821876495UL, 3993894153UL, 979247444UL, 2142862852UL, 1368937545UL, +2647327844UL, 1353904396UL, 294065371UL, 3543274652UL, 911792564UL, 1204178178UL, 3165709748UL, 103582737UL, 3101998294UL, 730811902UL, 1989156224UL, 893293786UL, 1885087777UL, 1390223786UL, 2657819643UL, 552729795UL, 3388458110UL, 3325206451UL, 1897013739UL, 3657020278UL, 1387364861UL, 3025318046UL, 2117065739UL, 486446521UL, 3675999281UL, 714737345UL, 2085926890UL, 3946214694UL, 3609089773UL, 2117061768UL, 3935682560UL, 868009118UL, +2916136885UL, 1808988481UL, 83680601UL, 1464326680UL, 797410789UL, 3438751781UL, 1391154023UL, 234460119UL, 3551348221UL, 4068940987UL, 3948410079UL, 2814385745UL, 3497626257UL, 916790795UL, 3722456098UL, 1767303496UL, 3711787525UL, 2239286063UL, 1054058916UL, 2030352819UL, 4140631909UL, 2230543409UL, 2173597546UL, 3786733892UL, 3211336683UL, 1116033475UL, 2032556038UL, 3216540537UL, 3298170974UL, 2589589144UL, 667272562UL, 1863766055UL, +3931110690UL, 191299053UL, 1139480458UL, 272901326UL, 739418419UL, 1377144055UL, 2876702705UL, 1954361769UL, 3839312742UL, 2814009721UL, 600813233UL, 1535885024UL, 3587775605UL, 4256065219UL, 2324695947UL, 2293284974UL, 2036339249UL, 1534849280UL, 1215859603UL, 327866771UL, 3356772175UL, 1826625240UL, 720372669UL, 4240407984UL, 1421374867UL, 3228945021UL, 1358646008UL, 3409069246UL, 4100357988UL, 643362354UL, 109899594UL, 2064362635UL, +4243434294UL, 2898852084UL, 4180291913UL, 1676507466UL, 1017841240UL, 3243922356UL, 1569683812UL, 3608467942UL, 3113105154UL, 1154120402UL, 1479311403UL, 966040649UL, 1862994005UL, 3020908939UL, 3078194866UL, 1556392996UL, 786634113UL, 693774191UL, 3549937583UL, 3710822994UL, 920664071UL, 1578429713UL, 37658897UL, 2340485150UL, 950951909UL, 740197415UL, 2528123823UL, 2258231402UL, 1085927825UL, 1595992020UL, 2580760267UL, 3544041088UL, +3850509554UL, 3925419886UL, 2628739022UL, 3867556156UL, 2562145937UL, 3124287811UL, 3373329273UL, 4255542251UL, 3185271749UL, 3693565710UL, 1989726178UL, 1381160022UL, 3642438773UL, 3042165367UL, 3271478204UL, 3622052196UL, 1263328494UL, 1154237693UL, 1016814036UL, 3615401444UL, 2786224913UL, 1251034970UL, 1874233020UL, 2956086971UL, 2572413057UL, 1529490307UL, 3146635362UL, 1436483376UL, 1513970396UL, 3993894153UL, 979247444UL, 2142862852UL, +1368937545UL, 3275665128UL, 1353904396UL, 294065371UL, 3543274652UL, 911792564UL, 2209636872UL, 3165709748UL, 103582737UL, 3101998294UL, 730811902UL, 965151434UL, 893293786UL, 1885087777UL, 1390223786UL, 2657819643UL, 3278634059UL, 3388458110UL, 3325206451UL, 1897013739UL, 3657020278UL, 4293473749UL, 3025318046UL, 2117065739UL, 486446521UL, 3675999281UL, 620561205UL, 2085926890UL, 3946214694UL, 3609089773UL, 2117061768UL, 163384588UL, +868009118UL, 2916136885UL, 1808988481UL, 83680601UL, 10243015UL, 797410789UL, 3438751781UL, 1391154023UL, 234460119UL, 1278218413UL, 4068940987UL, 3948410079UL, 2814385745UL, 3497626257UL, 1233272798UL, 3722456098UL, 1767303496UL, 3711787525UL, 2239286063UL, 3968895688UL, 2030352819UL, 4140631909UL, 2230543409UL, 2173597546UL, 2866251044UL, 3211336683UL, 1116033475UL, 2032556038UL, 3216540537UL, 4233849723UL, 2589589144UL, 667272562UL, +1863766055UL, 3931110690UL, 2468422423UL, 1139480458UL, 272901326UL, 739418419UL, 1377144055UL, 4240143411UL, 1954361769UL, 3839312742UL, 2814009721UL, 600813233UL, 3976840004UL, 3587775605UL, 4256065219UL, 2324695947UL, 2293284974UL, 437604123UL, 1534849280UL, 1215859603UL, 327866771UL, 3356772175UL, 2757237699UL, 720372669UL, 4240407984UL, 1421374867UL, 3228945021UL, 3284801305UL, 3409069246UL, 4100357988UL, 643362354UL, 109899594UL, +1301585321UL, 2528806870UL, 1838904064UL, 448772403UL, 1097849740UL, 1899994097UL, 618309123UL, 1911948510UL, 2309256224UL, 1861398151UL, 905306403UL, 1067595802UL, 36868624UL, 3780886191UL, 835126206UL, 3190251977UL, 2672497726UL, 2085944002UL, 2912993968UL, 2493776706UL, 667136329UL, 1474890786UL, 2383346554UL, 943528949UL, 3376706013UL, 2495573574UL, 144956345UL, 793159960UL, 1591274917UL, 477107637UL, 1383815442UL, 67384899UL, +2355242218UL, 1687409818UL, 3801093871UL, 2108217811UL, 3455908733UL, 4172160797UL, 3935534685UL, 631067839UL, 1187677548UL, 2280856137UL, 3020767646UL, 2063176246UL, 3736904984UL, 2952933848UL, 2975164686UL, 4144473303UL, 34670977UL, 1250976509UL, 3484166554UL, 1532744745UL, 225700994UL, 1878713627UL, 2122358980UL, 1456610194UL, 2917522161UL, 2818947075UL, 102678939UL, 53743858UL, 2095250656UL, 4023979225UL, 3094092874UL, 4128760696UL, +3411610028UL, 3020200609UL, 2225866341UL, 586320946UL, 63813522UL, 1238216159UL, 2825692263UL, 2169937231UL, 3298517640UL, 1542128261UL, 2205544184UL, 1258655704UL, 2629012083UL, 4113650203UL, 3198617867UL, 2742310794UL, 3372657381UL, 3115904410UL, 1948638822UL, 1123521744UL, 1080429281UL, 4086706732UL, 4142693211UL, 817377147UL, 2570194641UL, 26001503UL, 2861456160UL, 4185725555UL, 2573003804UL, 1618628779UL, 2588489212UL, 3996192609UL, +1555844274UL, 1003123505UL, 1326350123UL, 1130583849UL, 3017128756UL, 74119042UL, 4041266437UL, 1938014170UL, 3528465794UL, 4203969698UL, 1913054398UL, 3617979809UL, 2218810167UL, 2453899816UL, 1997423206UL, 477446533UL, 303090065UL, 757937082UL, 1523238256UL, 3140505311UL, 1422588701UL, 3642014639UL, 1740624195UL, 1276017154UL, 3072526193UL, 3675105122UL, 1335122682UL, 4080595263UL, 2308519420UL, 3299182769UL, 1461978532UL, 3098694217UL, +2982399822UL, 3088698511UL, 586759229UL, 3548750902UL, 1449857891UL, 2866451663UL, 2525162286UL, 57294602UL, 4107991297UL, 1214672265UL, 2940391280UL, 4285346034UL, 3338216759UL, 737207923UL, 4264163846UL, 59219141UL, 2300024654UL, 1876616814UL, 1976543605UL, 783571061UL, 1724699622UL, 1967524469UL, 1650309916UL, 3322257631UL, 3975521122UL, 273342162UL, 1156754241UL, 185315896UL, 3368133921UL, 66314655UL, 4153777915UL, 3519901897UL, +}, +{ +3672467167UL, 68684525UL, 1738833632UL, 3081329135UL, 2583806115UL, 2291130512UL, 503032614UL, 3658059597UL, 571493931UL, 685537959UL, 3498787788UL, 422428426UL, 3879256913UL, 1173158320UL, 4000800121UL, 298972869UL, 1718342816UL, 2541691685UL, 2490502642UL, 2321452806UL, 4223212804UL, 1812334632UL, 3717655725UL, 4238191852UL, 3001307165UL, 2621896355UL, 2572404999UL, 3590094954UL, 760765206UL, 2293618001UL, 1392353032UL, 1733137169UL, +2674005018UL, 4067961151UL, 1505710487UL, 451078217UL, 2591688848UL, 12635611UL, 507045428UL, 694822241UL, 1789383090UL, 1140183890UL, 1720695967UL, 1994318191UL, 3340349873UL, 2793804971UL, 1054433135UL, 2345087879UL, 3179939285UL, 1651968615UL, 1793223686UL, 1055357758UL, 914271617UL, 483007580UL, 2127727816UL, 2754998083UL, 3179053982UL, 598442002UL, 1950227301UL, 213053613UL, 3566888111UL, 2832258993UL, 4260365359UL, 443662829UL, +1706542890UL, 3852730296UL, 3643260763UL, 2163607277UL, 1812905006UL, 171529637UL, 215187467UL, 2369406909UL, 1929000706UL, 2572441025UL, 2133955541UL, 810692262UL, 1337974799UL, 4030350704UL, 2159178715UL, 3769451556UL, 1026825278UL, 593628480UL, 1817383139UL, 878832429UL, 2253876350UL, 203612980UL, 2102950440UL, 3407143936UL, 1912362251UL, 1595387637UL, 2827580539UL, 305467658UL, 3292706746UL, 44135525UL, 4001933553UL, 3697343089UL, +760470915UL, 587414402UL, 1419378814UL, 2852774010UL, 3891626781UL, 2757016765UL, 1090707384UL, 3997074427UL, 1047182100UL, 2855539022UL, 36229159UL, 1591415533UL, 3471572739UL, 1237952140UL, 2614469314UL, 213338525UL, 886212578UL, 2620301943UL, 713590207UL, 2430496777UL, 1198164420UL, 2644841698UL, 3654164701UL, 36283572UL, 1461695896UL, 1770331341UL, 1641501876UL, 3470919184UL, 3181021559UL, 3053795110UL, 3533531372UL, 3134337355UL, +668308383UL, 388340999UL, 3221275220UL, 1589659138UL, 294382235UL, 1447443579UL, 690177534UL, 1799726917UL, 2838977761UL, 4172949119UL, 2360858031UL, 159385920UL, 2248389027UL, 1790015671UL, 3925738275UL, 1049918544UL, 4107349511UL, 1619955951UL, 4188275966UL, 1672572975UL, 2672697497UL, 1863413666UL, 747724021UL, 4037561738UL, 1605940213UL, 445253292UL, 3362434828UL, 610898209UL, 1473244091UL, 735444769UL, 1540599852UL, 2449351720UL, +1032410949UL, 3672467167UL, 68684525UL, 1738833632UL, 3081329135UL, 519684794UL, 2291130512UL, 503032614UL, 3658059597UL, 571493931UL, 2400186105UL, 3498787788UL, 422428426UL, 3879256913UL, 1173158320UL, 4120704752UL, 298972869UL, 1718342816UL, 2541691685UL, 2490502642UL, 1686027891UL, 4223212804UL, 1812334632UL, 3717655725UL, 4238191852UL, 642431972UL, 2621896355UL, 2572404999UL, 3590094954UL, 760765206UL, 2949609717UL, 1392353032UL, +1733137169UL, 2674005018UL, 4067961151UL, 1526077846UL, 451078217UL, 2591688848UL, 12635611UL, 507045428UL, 2417951415UL, 1789383090UL, 1140183890UL, 1720695967UL, 1994318191UL, 3465605863UL, 2793804971UL, 1054433135UL, 2345087879UL, 3179939285UL, 3079297626UL, 1793223686UL, 1055357758UL, 914271617UL, 483007580UL, 306802527UL, 2754998083UL, 3179053982UL, 598442002UL, 1950227301UL, 2473418737UL, 3566888111UL, 2832258993UL, 4260365359UL, +443662829UL, 2097776414UL, 3852730296UL, 3643260763UL, 2163607277UL, 1812905006UL, 3957721904UL, 215187467UL, 2369406909UL, 1929000706UL, 2572441025UL, 3779486126UL, 810692262UL, 1337974799UL, 4030350704UL, 2159178715UL, 1127012865UL, 1026825278UL, 593628480UL, 1817383139UL, 878832429UL, 361018423UL, 203612980UL, 2102950440UL, 3407143936UL, 1912362251UL, 1475218277UL, 2827580539UL, 305467658UL, 3292706746UL, 44135525UL, 1900092336UL, +3697343089UL, 760470915UL, 587414402UL, 1419378814UL, 343303227UL, 3891626781UL, 2757016765UL, 1090707384UL, 3997074427UL, 745490961UL, 2855539022UL, 36229159UL, 1591415533UL, 3471572739UL, 3920625546UL, 2614469314UL, 213338525UL, 886212578UL, 2620301943UL, 827771411UL, 2430496777UL, 1198164420UL, 2644841698UL, 3654164701UL, 2747674190UL, 1461695896UL, 1770331341UL, 1641501876UL, 3470919184UL, 919857376UL, 3053795110UL, 3533531372UL, +3134337355UL, 668308383UL, 201138876UL, 3221275220UL, 1589659138UL, 294382235UL, 1447443579UL, 4211579707UL, 1799726917UL, 2838977761UL, 4172949119UL, 2360858031UL, 416103844UL, 2248389027UL, 1790015671UL, 3925738275UL, 1049918544UL, 3481887924UL, 1619955951UL, 4188275966UL, 1672572975UL, 2672697497UL, 564854400UL, 747724021UL, 4037561738UL, 1605940213UL, 445253292UL, 604900912UL, 610898209UL, 1473244091UL, 735444769UL, 1540599852UL, +3036173307UL, 1032410949UL, 3672467167UL, 68684525UL, 1738833632UL, 973022696UL, 519684794UL, 2291130512UL, 503032614UL, 3658059597UL, 1500301452UL, 2400186105UL, 3498787788UL, 422428426UL, 3879256913UL, 3923611748UL, 4120704752UL, 298972869UL, 1718342816UL, 2541691685UL, 2323881484UL, 1686027891UL, 4223212804UL, 1812334632UL, 3717655725UL, 2109094458UL, 642431972UL, 2621896355UL, 2572404999UL, 3590094954UL, 1837882537UL, 2949609717UL, +1392353032UL, 1733137169UL, 2674005018UL, 3252348987UL, 1526077846UL, 451078217UL, 2591688848UL, 12635611UL, 3971261781UL, 2417951415UL, 1789383090UL, 1140183890UL, 1720695967UL, 2906966040UL, 3465605863UL, 2793804971UL, 1054433135UL, 2345087879UL, 915518921UL, 3079297626UL, 1793223686UL, 1055357758UL, 914271617UL, 791633499UL, 306802527UL, 2754998083UL, 3179053982UL, 598442002UL, 324402573UL, 2473418737UL, 3566888111UL, 2832258993UL, +4260365359UL, 2168046398UL, 2097776414UL, 3852730296UL, 3643260763UL, 2163607277UL, 2595175979UL, 3957721904UL, 215187467UL, 2369406909UL, 1929000706UL, 657446369UL, 3779486126UL, 810692262UL, 1337974799UL, 4030350704UL, 1865557469UL, 1127012865UL, 1026825278UL, 593628480UL, 1817383139UL, 3414354529UL, 361018423UL, 203612980UL, 2102950440UL, 3407143936UL, 1739372987UL, 1475218277UL, 2827580539UL, 305467658UL, 3292706746UL, 825045562UL, +1900092336UL, 3697343089UL, 760470915UL, 587414402UL, 2000637694UL, 343303227UL, 3891626781UL, 2757016765UL, 1090707384UL, 4015377800UL, 745490961UL, 2855539022UL, 36229159UL, 1591415533UL, 2208656873UL, 3920625546UL, 2614469314UL, 213338525UL, 886212578UL, 2729976209UL, 827771411UL, 2430496777UL, 1198164420UL, 2644841698UL, 1922667440UL, 2747674190UL, 1461695896UL, 1770331341UL, 1641501876UL, 357535311UL, 919857376UL, 3053795110UL, +3533531372UL, 3134337355UL, 1004072597UL, 201138876UL, 3221275220UL, 1589659138UL, 294382235UL, 1148950143UL, 4211579707UL, 1799726917UL, 2838977761UL, 4172949119UL, 892664404UL, 416103844UL, 2248389027UL, 1790015671UL, 3925738275UL, 2612357890UL, 3481887924UL, 1619955951UL, 4188275966UL, 1672572975UL, 2005534713UL, 564854400UL, 747724021UL, 4037561738UL, 1605940213UL, 2620990454UL, 604900912UL, 610898209UL, 1473244091UL, 735444769UL, +3571225334UL, 3036173307UL, 1032410949UL, 3672467167UL, 68684525UL, 3327351604UL, 973022696UL, 519684794UL, 2291130512UL, 503032614UL, 3814902238UL, 1500301452UL, 2400186105UL, 3498787788UL, 422428426UL, 1756753750UL, 3923611748UL, 4120704752UL, 298972869UL, 1718342816UL, 652903081UL, 2323881484UL, 1686027891UL, 4223212804UL, 1812334632UL, 1599640566UL, 2109094458UL, 642431972UL, 2621896355UL, 2572404999UL, 1668409355UL, 1837882537UL, +2949609717UL, 1392353032UL, 1733137169UL, 3691709793UL, 3252348987UL, 1526077846UL, 451078217UL, 2591688848UL, 3353622601UL, 3971261781UL, 2417951415UL, 1789383090UL, 1140183890UL, 4113853791UL, 2906966040UL, 3465605863UL, 2793804971UL, 1054433135UL, 2195882948UL, 915518921UL, 3079297626UL, 1793223686UL, 1055357758UL, 898713552UL, 791633499UL, 306802527UL, 2754998083UL, 3179053982UL, 2469350088UL, 324402573UL, 2473418737UL, 3566888111UL, +2832258993UL, 1377718274UL, 2168046398UL, 2097776414UL, 3852730296UL, 3643260763UL, 3492388484UL, 2595175979UL, 3957721904UL, 215187467UL, 2369406909UL, 4243449339UL, 657446369UL, 3779486126UL, 810692262UL, 1337974799UL, 3960230785UL, 1865557469UL, 1127012865UL, 1026825278UL, 593628480UL, 732793312UL, 3414354529UL, 361018423UL, 203612980UL, 2102950440UL, 2401792405UL, 1739372987UL, 1475218277UL, 2827580539UL, 305467658UL, 2454275289UL, +825045562UL, 1900092336UL, 3697343089UL, 760470915UL, 2146882409UL, 2000637694UL, 343303227UL, 3891626781UL, 2757016765UL, 3997473261UL, 4015377800UL, 745490961UL, 2855539022UL, 36229159UL, 2375394427UL, 2208656873UL, 3920625546UL, 2614469314UL, 213338525UL, 2055366274UL, 2729976209UL, 827771411UL, 2430496777UL, 1198164420UL, 1789631187UL, 1922667440UL, 2747674190UL, 1461695896UL, 1770331341UL, 4284442852UL, 357535311UL, 919857376UL, +3053795110UL, 3533531372UL, 2124270060UL, 1004072597UL, 201138876UL, 3221275220UL, 1589659138UL, 1418386120UL, 1148950143UL, 4211579707UL, 1799726917UL, 2838977761UL, 3540708069UL, 892664404UL, 416103844UL, 2248389027UL, 1790015671UL, 3936883UL, 2612357890UL, 3481887924UL, 1619955951UL, 4188275966UL, 2963623483UL, 2005534713UL, 564854400UL, 747724021UL, 4037561738UL, 3431155922UL, 2620990454UL, 604900912UL, 610898209UL, 1473244091UL, +3880001339UL, 2879060316UL, 3300897679UL, 3960972039UL, 3201086624UL, 3814462934UL, 3426650044UL, 1930881632UL, 1981178788UL, 2956279691UL, 4272406256UL, 372705521UL, 1359389771UL, 1590302979UL, 3940206208UL, 3817999127UL, 2527835456UL, 2739078164UL, 716997849UL, 3235607043UL, 2550297745UL, 3688700200UL, 354502605UL, 2285793656UL, 2339138034UL, 3912354142UL, 2262255668UL, 469322622UL, 1319943359UL, 1916101235UL, 200441823UL, 509436982UL, +2160284593UL, 1687919695UL, 4153615582UL, 495735041UL, 3694469424UL, 2086893117UL, 4223008799UL, 105344742UL, 1698033424UL, 1149223145UL, 4183918790UL, 4176151950UL, 415739351UL, 817762972UL, 3768072560UL, 1931430949UL, 2698979439UL, 3481477932UL, 1994322914UL, 4078299950UL, 1268233995UL, 3254069145UL, 91029129UL, 498234704UL, 1636613942UL, 3710087092UL, 3876816560UL, 3510446387UL, 3870169008UL, 1370156410UL, 2442498047UL, 2324396523UL, +1258730334UL, 621954739UL, 1053015373UL, 491820717UL, 3386515432UL, 2203703266UL, 120167176UL, 2383669740UL, 1038666440UL, 2927342870UL, 3583197824UL, 1236241846UL, 2474675929UL, 679052891UL, 2451259584UL, 2177706146UL, 606842882UL, 3546980104UL, 2289281509UL, 353873434UL, 2041926837UL, 1238346748UL, 2729109726UL, 2843938395UL, 2938124210UL, 2554443866UL, 1494477920UL, 693378319UL, 2020963566UL, 2000385949UL, 3744098787UL, 650307220UL, +2631327075UL, 1529128757UL, 595871428UL, 3206666562UL, 458062987UL, 875238192UL, 3729317374UL, 1368843921UL, 3478430230UL, 3234384578UL, 3232435428UL, 321359326UL, 994274524UL, 361184397UL, 4285497594UL, 915263578UL, 1486882838UL, 9988613UL, 829077170UL, 677216046UL, 4141828204UL, 165804609UL, 1086678519UL, 2933434608UL, 1351662802UL, 2640085040UL, 2611502932UL, 2033698714UL, 2008873254UL, 3995557835UL, 1020873906UL, 67873555UL, +2230337823UL, 1263800417UL, 1148712155UL, 3985159589UL, 2979503513UL, 2854714997UL, 1539343345UL, 2751484352UL, 1569100732UL, 2020758949UL, 2126757134UL, 3426641899UL, 2808587825UL, 1953320148UL, 1096398464UL, 1502907172UL, 3751230087UL, 765557661UL, 765290990UL, 3056075500UL, 2040620632UL, 422573751UL, 3613558930UL, 1741145769UL, 273531216UL, 837238736UL, 494297893UL, 2903251124UL, 1636782182UL, 4256592784UL, 3652746656UL, 4258393217UL, +}, +{ +2657510202UL, 270297201UL, 2970166904UL, 3151626326UL, 973127447UL, 1523852613UL, 598650578UL, 10289043UL, 1138773500UL, 1379558769UL, 2202575480UL, 1622690708UL, 181345079UL, 228706650UL, 2807760507UL, 3061024281UL, 2310359315UL, 3094465578UL, 4062753882UL, 2744510393UL, 3844622451UL, 1759718963UL, 2393602744UL, 977540509UL, 870449791UL, 1484134272UL, 2838962253UL, 3079492430UL, 2617141201UL, 3744868057UL, 994295425UL, 1302594555UL, +277777192UL, 1793039043UL, 1620482692UL, 2518563014UL, 1163760339UL, 2709515777UL, 4220588138UL, 531143270UL, 2528377633UL, 931694828UL, 1472659070UL, 900489303UL, 3538137811UL, 3849822545UL, 1304182427UL, 2423451948UL, 587259647UL, 296795227UL, 3843393378UL, 100570026UL, 1824916038UL, 3155192628UL, 1205830295UL, 2205840913UL, 2598785234UL, 2138099222UL, 1585588098UL, 1304106911UL, 2443465671UL, 3007665864UL, 3350433156UL, 3623458138UL, +629407548UL, 3209244941UL, 2102270358UL, 952701496UL, 2715374730UL, 2142960491UL, 2566649458UL, 2386659994UL, 4201648072UL, 367516884UL, 211986877UL, 3970312395UL, 4153651951UL, 3794120671UL, 614826776UL, 769672874UL, 2218713182UL, 236114529UL, 1614697510UL, 2420862368UL, 3471485219UL, 3080341429UL, 2394724619UL, 3585194114UL, 1394678495UL, 2137969611UL, 3955498999UL, 2765569351UL, 3084915757UL, 765232390UL, 1406483345UL, 2796499268UL, +2491128017UL, 1052428931UL, 1713430644UL, 3921576513UL, 3753414774UL, 973530327UL, 2545412294UL, 1841110931UL, 1174406073UL, 1104865218UL, 1586606252UL, 2612244473UL, 1407875673UL, 1823397519UL, 2613642581UL, 3163449384UL, 3129975397UL, 2059184961UL, 818092118UL, 3182607992UL, 1658516909UL, 2467681581UL, 1065789733UL, 799857247UL, 2492902195UL, 168866110UL, 2251316716UL, 1607684829UL, 2347941418UL, 2382781983UL, 3298500129UL, 3609200925UL, +3060374324UL, 2602420483UL, 2357812057UL, 3739699403UL, 3260652552UL, 205015857UL, 1936033273UL, 3955997259UL, 821264237UL, 1882720491UL, 159294165UL, 3197657094UL, 528058988UL, 2768830342UL, 805087358UL, 896645931UL, 1360375456UL, 3417488932UL, 3863200799UL, 4033907887UL, 983658874UL, 1828706965UL, 875027318UL, 1310362653UL, 3711487613UL, 4148261033UL, 3145162047UL, 485182003UL, 2633647498UL, 1369395018UL, 4163384029UL, 1827719274UL, +270658892UL, 2657510202UL, 270297201UL, 2970166904UL, 3151626326UL, 499420828UL, 1523852613UL, 598650578UL, 10289043UL, 1138773500UL, 640170086UL, 2202575480UL, 1622690708UL, 181345079UL, 228706650UL, 3957853780UL, 3061024281UL, 2310359315UL, 3094465578UL, 4062753882UL, 2049506087UL, 3844622451UL, 1759718963UL, 2393602744UL, 977540509UL, 2346891936UL, 1484134272UL, 2838962253UL, 3079492430UL, 2617141201UL, 2112540708UL, 994295425UL, +1302594555UL, 277777192UL, 1793039043UL, 981072592UL, 2518563014UL, 1163760339UL, 2709515777UL, 4220588138UL, 1992965594UL, 2528377633UL, 931694828UL, 1472659070UL, 900489303UL, 32461040UL, 3849822545UL, 1304182427UL, 2423451948UL, 587259647UL, 3728056788UL, 3843393378UL, 100570026UL, 1824916038UL, 3155192628UL, 1194916233UL, 2205840913UL, 2598785234UL, 2138099222UL, 1585588098UL, 2944318376UL, 2443465671UL, 3007665864UL, 3350433156UL, +3623458138UL, 1413669939UL, 3209244941UL, 2102270358UL, 952701496UL, 2715374730UL, 826676012UL, 2566649458UL, 2386659994UL, 4201648072UL, 367516884UL, 4272143576UL, 3970312395UL, 4153651951UL, 3794120671UL, 614826776UL, 4106382849UL, 2218713182UL, 236114529UL, 1614697510UL, 2420862368UL, 138091237UL, 3080341429UL, 2394724619UL, 3585194114UL, 1394678495UL, 2113895281UL, 3955498999UL, 2765569351UL, 3084915757UL, 765232390UL, 2247301699UL, +2796499268UL, 2491128017UL, 1052428931UL, 1713430644UL, 1076867271UL, 3753414774UL, 973530327UL, 2545412294UL, 1841110931UL, 3427639042UL, 1104865218UL, 1586606252UL, 2612244473UL, 1407875673UL, 2159805028UL, 2613642581UL, 3163449384UL, 3129975397UL, 2059184961UL, 1251595655UL, 3182607992UL, 1658516909UL, 2467681581UL, 1065789733UL, 524065102UL, 2492902195UL, 168866110UL, 2251316716UL, 1607684829UL, 877205873UL, 2382781983UL, 3298500129UL, +3609200925UL, 3060374324UL, 1983477493UL, 2357812057UL, 3739699403UL, 3260652552UL, 205015857UL, 3578808491UL, 3955997259UL, 821264237UL, 1882720491UL, 159294165UL, 3639531297UL, 528058988UL, 2768830342UL, 805087358UL, 896645931UL, 2309781073UL, 3417488932UL, 3863200799UL, 4033907887UL, 983658874UL, 3756437847UL, 875027318UL, 1310362653UL, 3711487613UL, 4148261033UL, 3264363953UL, 485182003UL, 2633647498UL, 1369395018UL, 4163384029UL, +184614728UL, 270658892UL, 2657510202UL, 270297201UL, 2970166904UL, 884907665UL, 499420828UL, 1523852613UL, 598650578UL, 10289043UL, 2023902217UL, 640170086UL, 2202575480UL, 1622690708UL, 181345079UL, 1358722197UL, 3957853780UL, 3061024281UL, 2310359315UL, 3094465578UL, 4156960892UL, 2049506087UL, 3844622451UL, 1759718963UL, 2393602744UL, 1018272187UL, 2346891936UL, 1484134272UL, 2838962253UL, 3079492430UL, 663361761UL, 2112540708UL, +994295425UL, 1302594555UL, 277777192UL, 4201292427UL, 981072592UL, 2518563014UL, 1163760339UL, 2709515777UL, 3301905324UL, 1992965594UL, 2528377633UL, 931694828UL, 1472659070UL, 3170286187UL, 32461040UL, 3849822545UL, 1304182427UL, 2423451948UL, 166213287UL, 3728056788UL, 3843393378UL, 100570026UL, 1824916038UL, 1534589402UL, 1194916233UL, 2205840913UL, 2598785234UL, 2138099222UL, 767439709UL, 2944318376UL, 2443465671UL, 3007665864UL, +3350433156UL, 257274072UL, 1413669939UL, 3209244941UL, 2102270358UL, 952701496UL, 893224047UL, 826676012UL, 2566649458UL, 2386659994UL, 4201648072UL, 1336000731UL, 4272143576UL, 3970312395UL, 4153651951UL, 3794120671UL, 2381517352UL, 4106382849UL, 2218713182UL, 236114529UL, 1614697510UL, 2427291612UL, 138091237UL, 3080341429UL, 2394724619UL, 3585194114UL, 1339840651UL, 2113895281UL, 3955498999UL, 2765569351UL, 3084915757UL, 1920073265UL, +2247301699UL, 2796499268UL, 2491128017UL, 1052428931UL, 1720704700UL, 1076867271UL, 3753414774UL, 973530327UL, 2545412294UL, 655938239UL, 3427639042UL, 1104865218UL, 1586606252UL, 2612244473UL, 748629647UL, 2159805028UL, 2613642581UL, 3163449384UL, 3129975397UL, 1868740512UL, 1251595655UL, 3182607992UL, 1658516909UL, 2467681581UL, 3092135795UL, 524065102UL, 2492902195UL, 168866110UL, 2251316716UL, 229376275UL, 877205873UL, 2382781983UL, +3298500129UL, 3609200925UL, 1270454086UL, 1983477493UL, 2357812057UL, 3739699403UL, 3260652552UL, 3976376418UL, 3578808491UL, 3955997259UL, 821264237UL, 1882720491UL, 2211365699UL, 3639531297UL, 528058988UL, 2768830342UL, 805087358UL, 1351870678UL, 2309781073UL, 3417488932UL, 3863200799UL, 4033907887UL, 2317721807UL, 3756437847UL, 875027318UL, 1310362653UL, 3711487613UL, 1929459086UL, 3264363953UL, 485182003UL, 2633647498UL, 1369395018UL, +2141675718UL, 184614728UL, 270658892UL, 2657510202UL, 270297201UL, 3337954073UL, 884907665UL, 499420828UL, 1523852613UL, 598650578UL, 3874207188UL, 2023902217UL, 640170086UL, 2202575480UL, 1622690708UL, 2020255059UL, 1358722197UL, 3957853780UL, 3061024281UL, 2310359315UL, 753738868UL, 4156960892UL, 2049506087UL, 3844622451UL, 1759718963UL, 1672276116UL, 1018272187UL, 2346891936UL, 1484134272UL, 2838962253UL, 1680679979UL, 663361761UL, +2112540708UL, 994295425UL, 1302594555UL, 1941500850UL, 4201292427UL, 981072592UL, 2518563014UL, 1163760339UL, 184357645UL, 3301905324UL, 1992965594UL, 2528377633UL, 931694828UL, 3462653134UL, 3170286187UL, 32461040UL, 3849822545UL, 1304182427UL, 396808784UL, 166213287UL, 3728056788UL, 3843393378UL, 100570026UL, 876691173UL, 1534589402UL, 1194916233UL, 2205840913UL, 2598785234UL, 4286653520UL, 767439709UL, 2944318376UL, 2443465671UL, +3007665864UL, 2793587144UL, 257274072UL, 1413669939UL, 3209244941UL, 2102270358UL, 2792966616UL, 893224047UL, 826676012UL, 2566649458UL, 2386659994UL, 798757973UL, 1336000731UL, 4272143576UL, 3970312395UL, 4153651951UL, 2930383268UL, 2381517352UL, 4106382849UL, 2218713182UL, 236114529UL, 1936008889UL, 2427291612UL, 138091237UL, 3080341429UL, 2394724619UL, 4157586029UL, 1339840651UL, 2113895281UL, 3955498999UL, 2765569351UL, 2243544114UL, +1920073265UL, 2247301699UL, 2796499268UL, 2491128017UL, 3372810009UL, 1720704700UL, 1076867271UL, 3753414774UL, 973530327UL, 484392041UL, 655938239UL, 3427639042UL, 1104865218UL, 1586606252UL, 1373046326UL, 748629647UL, 2159805028UL, 2613642581UL, 3163449384UL, 1558595520UL, 1868740512UL, 1251595655UL, 3182607992UL, 1658516909UL, 3503432306UL, 3092135795UL, 524065102UL, 2492902195UL, 168866110UL, 4106973392UL, 229376275UL, 877205873UL, +2382781983UL, 3298500129UL, 2366096961UL, 1270454086UL, 1983477493UL, 2357812057UL, 3739699403UL, 4223323197UL, 3976376418UL, 3578808491UL, 3955997259UL, 821264237UL, 1581729952UL, 2211365699UL, 3639531297UL, 528058988UL, 2768830342UL, 3946263978UL, 1351870678UL, 2309781073UL, 3417488932UL, 3863200799UL, 3948072426UL, 2317721807UL, 3756437847UL, 875027318UL, 1310362653UL, 3439391360UL, 1929459086UL, 3264363953UL, 485182003UL, 2633647498UL, +3576868480UL, 2527748673UL, 3116247125UL, 4020801612UL, 2594734840UL, 3308177137UL, 665011257UL, 40118275UL, 3584569179UL, 3399729283UL, 3867174947UL, 658488234UL, 1099195903UL, 2274511402UL, 1872529118UL, 2518961094UL, 2633598693UL, 4160728307UL, 449442630UL, 164837956UL, 1010805767UL, 605336924UL, 1178031445UL, 3949359502UL, 2585151633UL, 611885521UL, 293204651UL, 3389557188UL, 1172294301UL, 2503819061UL, 659842653UL, 504992348UL, +3762165683UL, 1799777932UL, 4161843209UL, 1924622448UL, 1006263939UL, 115233249UL, 2775142171UL, 3228632586UL, 885407023UL, 2514866293UL, 3615088636UL, 2488824172UL, 2631364137UL, 1454226414UL, 3888177876UL, 70646265UL, 2291458600UL, 2370783730UL, 1566625834UL, 3652033806UL, 4136806683UL, 2819973124UL, 3207365429UL, 989185345UL, 3343822313UL, 2580472874UL, 4077285847UL, 4032963783UL, 2883518039UL, 2253593637UL, 904631114UL, 2654790756UL, +2967911632UL, 2131672564UL, 1594073414UL, 2370718497UL, 3769371275UL, 1547951748UL, 2473303924UL, 651625138UL, 2159175883UL, 4062995539UL, 696224922UL, 3388626509UL, 100118553UL, 770731124UL, 2149458689UL, 3223175313UL, 3524052514UL, 2651241522UL, 78236806UL, 3212708723UL, 1045780878UL, 2257575290UL, 3709360831UL, 966829465UL, 61269250UL, 405063245UL, 331731998UL, 2472078870UL, 1138237364UL, 1135091387UL, 3245001409UL, 3817992705UL, +1738939574UL, 1397617581UL, 2896546651UL, 4207083421UL, 3802162100UL, 391930524UL, 1326819828UL, 85308067UL, 3235336831UL, 686989692UL, 1947564282UL, 842881662UL, 2887279866UL, 3850666935UL, 2001895525UL, 2673649961UL, 2106555006UL, 1762053005UL, 2334552700UL, 26094213UL, 1184502058UL, 2048598709UL, 4039640450UL, 1439363714UL, 1022688817UL, 1053169108UL, 170896272UL, 444231850UL, 1500204748UL, 1077470703UL, 1630597179UL, 1382588806UL, +138805391UL, 1636536505UL, 3118018426UL, 3461152216UL, 2486547351UL, 2045361316UL, 2976067436UL, 468876399UL, 1407419455UL, 3226137264UL, 414206328UL, 1011039713UL, 3537947031UL, 2359787831UL, 258556532UL, 3615987029UL, 3372097337UL, 3586352388UL, 1056198830UL, 1852291192UL, 3888893481UL, 746156045UL, 4203877603UL, 297851145UL, 2615507398UL, 1141098641UL, 1881412583UL, 3014341741UL, 2125186797UL, 229307235UL, 3476606674UL, 3553854689UL, +}, +{ +3768542219UL, 2777948797UL, 3328832678UL, 3488502819UL, 2708053041UL, 2217907094UL, 2133505056UL, 2218961277UL, 2148551748UL, 1420045625UL, 1709182366UL, 1816409641UL, 3791695288UL, 4207813971UL, 22588497UL, 2211317602UL, 616238454UL, 2394270012UL, 3212896041UL, 213408768UL, 2199328374UL, 3188624050UL, 811443809UL, 2818548979UL, 3150758902UL, 2022548260UL, 2462701924UL, 3793704672UL, 2358080321UL, 483288372UL, 450033142UL, 772942770UL, +2224873625UL, 241543410UL, 312552314UL, 1268067149UL, 915918620UL, 3906238422UL, 132545832UL, 3486041298UL, 2414090506UL, 3798383292UL, 2257004699UL, 130309284UL, 1158673651UL, 152325583UL, 3499865580UL, 4094273597UL, 1029041593UL, 93538481UL, 3963199522UL, 4215066819UL, 2851084137UL, 950351173UL, 2758084052UL, 3408506640UL, 2468905351UL, 3982226741UL, 3591899344UL, 2972879639UL, 3321078070UL, 252381865UL, 409397320UL, 741653003UL, +1936712854UL, 1198684021UL, 922916691UL, 10413506UL, 3546896248UL, 1704703870UL, 1479762464UL, 104399432UL, 4144557684UL, 68239720UL, 2666028745UL, 362625839UL, 2591539911UL, 2837165752UL, 2180226515UL, 4076543943UL, 2956460273UL, 312410753UL, 2566731139UL, 2532653524UL, 2399030172UL, 207904356UL, 354574195UL, 485696336UL, 3816686234UL, 3016971115UL, 4272692603UL, 2352732136UL, 33493163UL, 780255811UL, 4092242980UL, 4121521600UL, +2119254314UL, 42767673UL, 1081488778UL, 2757446871UL, 2267513620UL, 3472164720UL, 2750308207UL, 1707164045UL, 3125591821UL, 3236687597UL, 299194858UL, 537384087UL, 1695155491UL, 2078250102UL, 1705861659UL, 2416322096UL, 1692335914UL, 1178915980UL, 3405431297UL, 4059323309UL, 2014660182UL, 3847682866UL, 4037583683UL, 2629253995UL, 867809161UL, 2167953720UL, 2290558548UL, 417635396UL, 53496289UL, 1890906570UL, 2842247580UL, 807266805UL, +1226139132UL, 2067929784UL, 1697038549UL, 3312131466UL, 1234311530UL, 3199840935UL, 4185078776UL, 1807030355UL, 215385887UL, 845421530UL, 1350380353UL, 4209181096UL, 2576197887UL, 1275262872UL, 2806513944UL, 2718623701UL, 2779287384UL, 71403197UL, 219220133UL, 2181111477UL, 2000396844UL, 3595837555UL, 1232425455UL, 2630647391UL, 3280867676UL, 2622740782UL, 1578938469UL, 3624564545UL, 992324522UL, 3056113148UL, 3473635768UL, 3664935418UL, +1786902552UL, 3768542219UL, 2777948797UL, 3328832678UL, 3488502819UL, 2530862473UL, 2217907094UL, 2133505056UL, 2218961277UL, 2148551748UL, 4050672856UL, 1709182366UL, 1816409641UL, 3791695288UL, 4207813971UL, 4175126713UL, 2211317602UL, 616238454UL, 2394270012UL, 3212896041UL, 732700649UL, 2199328374UL, 3188624050UL, 811443809UL, 2818548979UL, 972036137UL, 2022548260UL, 2462701924UL, 3793704672UL, 2358080321UL, 1200725173UL, 450033142UL, +772942770UL, 2224873625UL, 241543410UL, 1907109304UL, 1268067149UL, 915918620UL, 3906238422UL, 132545832UL, 301668366UL, 2414090506UL, 3798383292UL, 2257004699UL, 130309284UL, 1228520287UL, 152325583UL, 3499865580UL, 4094273597UL, 1029041593UL, 3267460249UL, 3963199522UL, 4215066819UL, 2851084137UL, 950351173UL, 47361585UL, 3408506640UL, 2468905351UL, 3982226741UL, 3591899344UL, 1878226915UL, 3321078070UL, 252381865UL, 409397320UL, +741653003UL, 1716437506UL, 1198684021UL, 922916691UL, 10413506UL, 3546896248UL, 1591998796UL, 1479762464UL, 104399432UL, 4144557684UL, 68239720UL, 3810955599UL, 362625839UL, 2591539911UL, 2837165752UL, 2180226515UL, 3908378015UL, 2956460273UL, 312410753UL, 2566731139UL, 2532653524UL, 687490649UL, 207904356UL, 354574195UL, 485696336UL, 3816686234UL, 378445403UL, 4272692603UL, 2352732136UL, 33493163UL, 780255811UL, 1303281526UL, +4121521600UL, 2119254314UL, 42767673UL, 1081488778UL, 1734311274UL, 2267513620UL, 3472164720UL, 2750308207UL, 1707164045UL, 4212588163UL, 3236687597UL, 299194858UL, 537384087UL, 1695155491UL, 2250704950UL, 1705861659UL, 2416322096UL, 1692335914UL, 1178915980UL, 677982197UL, 4059323309UL, 2014660182UL, 3847682866UL, 4037583683UL, 1765435945UL, 867809161UL, 2167953720UL, 2290558548UL, 417635396UL, 2125103002UL, 1890906570UL, 2842247580UL, +807266805UL, 1226139132UL, 2056644398UL, 1697038549UL, 3312131466UL, 1234311530UL, 3199840935UL, 3063718636UL, 1807030355UL, 215385887UL, 845421530UL, 1350380353UL, 3610667273UL, 2576197887UL, 1275262872UL, 2806513944UL, 2718623701UL, 2492912955UL, 71403197UL, 219220133UL, 2181111477UL, 2000396844UL, 3465351710UL, 1232425455UL, 2630647391UL, 3280867676UL, 2622740782UL, 1331873639UL, 3624564545UL, 992324522UL, 3056113148UL, 3473635768UL, +782257020UL, 1786902552UL, 3768542219UL, 2777948797UL, 3328832678UL, 856888454UL, 2530862473UL, 2217907094UL, 2133505056UL, 2218961277UL, 3752437534UL, 4050672856UL, 1709182366UL, 1816409641UL, 3791695288UL, 1581813910UL, 4175126713UL, 2211317602UL, 616238454UL, 2394270012UL, 1796414157UL, 732700649UL, 2199328374UL, 3188624050UL, 811443809UL, 4225173324UL, 972036137UL, 2022548260UL, 2462701924UL, 3793704672UL, 1410793611UL, 1200725173UL, +450033142UL, 772942770UL, 2224873625UL, 3889840648UL, 1907109304UL, 1268067149UL, 915918620UL, 3906238422UL, 1249098244UL, 301668366UL, 2414090506UL, 3798383292UL, 2257004699UL, 1620796656UL, 1228520287UL, 152325583UL, 3499865580UL, 4094273597UL, 82853050UL, 3267460249UL, 3963199522UL, 4215066819UL, 2851084137UL, 1212493334UL, 47361585UL, 3408506640UL, 2468905351UL, 3982226741UL, 3195419905UL, 1878226915UL, 3321078070UL, 252381865UL, +409397320UL, 1584154733UL, 1716437506UL, 1198684021UL, 922916691UL, 10413506UL, 1734068880UL, 1591998796UL, 1479762464UL, 104399432UL, 4144557684UL, 1973878859UL, 3810955599UL, 362625839UL, 2591539911UL, 2837165752UL, 1727282404UL, 3908378015UL, 2956460273UL, 312410753UL, 2566731139UL, 3656295687UL, 687490649UL, 207904356UL, 354574195UL, 485696336UL, 355953909UL, 378445403UL, 4272692603UL, 2352732136UL, 33493163UL, 3784169684UL, +1303281526UL, 4121521600UL, 2119254314UL, 42767673UL, 2331527847UL, 1734311274UL, 2267513620UL, 3472164720UL, 2750308207UL, 820692528UL, 4212588163UL, 3236687597UL, 299194858UL, 537384087UL, 781151234UL, 2250704950UL, 1705861659UL, 2416322096UL, 1692335914UL, 4288008793UL, 677982197UL, 4059323309UL, 2014660182UL, 3847682866UL, 3328850880UL, 1765435945UL, 867809161UL, 2167953720UL, 2290558548UL, 542850707UL, 2125103002UL, 1890906570UL, +2842247580UL, 807266805UL, 3803006390UL, 2056644398UL, 1697038549UL, 3312131466UL, 1234311530UL, 809106036UL, 3063718636UL, 1807030355UL, 215385887UL, 845421530UL, 654189622UL, 3610667273UL, 2576197887UL, 1275262872UL, 2806513944UL, 1517875462UL, 2492912955UL, 71403197UL, 219220133UL, 2181111477UL, 3826277490UL, 3465351710UL, 1232425455UL, 2630647391UL, 3280867676UL, 3343597872UL, 1331873639UL, 3624564545UL, 992324522UL, 3056113148UL, +3725661598UL, 782257020UL, 1786902552UL, 3768542219UL, 2777948797UL, 3392298403UL, 856888454UL, 2530862473UL, 2217907094UL, 2133505056UL, 4160889036UL, 3752437534UL, 4050672856UL, 1709182366UL, 1816409641UL, 1282922706UL, 1581813910UL, 4175126713UL, 2211317602UL, 616238454UL, 3806252779UL, 1796414157UL, 732700649UL, 2199328374UL, 3188624050UL, 983474330UL, 4225173324UL, 972036137UL, 2022548260UL, 2462701924UL, 880446667UL, 1410793611UL, +1200725173UL, 450033142UL, 772942770UL, 3179870546UL, 3889840648UL, 1907109304UL, 1268067149UL, 915918620UL, 4261932110UL, 1249098244UL, 301668366UL, 2414090506UL, 3798383292UL, 471794009UL, 1620796656UL, 1228520287UL, 152325583UL, 3499865580UL, 1275109063UL, 82853050UL, 3267460249UL, 3963199522UL, 4215066819UL, 4209882674UL, 1212493334UL, 47361585UL, 3408506640UL, 2468905351UL, 1324785625UL, 3195419905UL, 1878226915UL, 3321078070UL, +252381865UL, 4259927884UL, 1584154733UL, 1716437506UL, 1198684021UL, 922916691UL, 1800164165UL, 1734068880UL, 1591998796UL, 1479762464UL, 104399432UL, 2774114308UL, 1973878859UL, 3810955599UL, 362625839UL, 2591539911UL, 2126614872UL, 1727282404UL, 3908378015UL, 2956460273UL, 312410753UL, 4098052715UL, 3656295687UL, 687490649UL, 207904356UL, 354574195UL, 937379582UL, 355953909UL, 378445403UL, 4272692603UL, 2352732136UL, 2694800574UL, +3784169684UL, 1303281526UL, 4121521600UL, 2119254314UL, 1741415022UL, 2331527847UL, 1734311274UL, 2267513620UL, 3472164720UL, 480821513UL, 820692528UL, 4212588163UL, 3236687597UL, 299194858UL, 1128762168UL, 781151234UL, 2250704950UL, 1705861659UL, 2416322096UL, 160918735UL, 4288008793UL, 677982197UL, 4059323309UL, 2014660182UL, 3354205317UL, 3328850880UL, 1765435945UL, 867809161UL, 2167953720UL, 3363861382UL, 542850707UL, 2125103002UL, +1890906570UL, 2842247580UL, 2459935488UL, 3803006390UL, 2056644398UL, 1697038549UL, 3312131466UL, 2378675900UL, 809106036UL, 3063718636UL, 1807030355UL, 215385887UL, 3528413525UL, 654189622UL, 3610667273UL, 2576197887UL, 1275262872UL, 993221887UL, 1517875462UL, 2492912955UL, 71403197UL, 219220133UL, 1805256638UL, 3826277490UL, 3465351710UL, 1232425455UL, 2630647391UL, 3718538519UL, 3343597872UL, 1331873639UL, 3624564545UL, 992324522UL, +3490576382UL, 2532191937UL, 1108692984UL, 802110050UL, 3984561242UL, 1973015939UL, 1351080551UL, 2382044123UL, 2393286227UL, 860228704UL, 179528099UL, 3569709850UL, 233527199UL, 3657599850UL, 3269634908UL, 3278075383UL, 4037814788UL, 952837871UL, 2050210570UL, 2376157484UL, 2566048929UL, 4200278597UL, 123440514UL, 573557299UL, 1585379806UL, 4012659271UL, 4000306490UL, 2508478465UL, 970078629UL, 4064973573UL, 645149301UL, 109544347UL, +647594029UL, 2097163688UL, 1515080116UL, 2142799649UL, 2519702653UL, 3122920796UL, 1952249156UL, 3932382760UL, 2155292687UL, 2517875978UL, 249059416UL, 4282787227UL, 2595461065UL, 1004349415UL, 2151451255UL, 2510715277UL, 3004500356UL, 3410567758UL, 344538405UL, 1946747709UL, 470298928UL, 1033671146UL, 4207801290UL, 1411375630UL, 3419808553UL, 3218285984UL, 3584735265UL, 811222695UL, 3898833227UL, 3535298390UL, 3764741581UL, 3927026520UL, +2850086968UL, 2818485449UL, 1963038474UL, 1871366998UL, 1900570117UL, 997663534UL, 746627295UL, 1827737271UL, 3814054979UL, 728285698UL, 1696496343UL, 1696888597UL, 1010837663UL, 1756050352UL, 785994134UL, 1436861536UL, 1949153732UL, 2360018842UL, 1703393654UL, 2248338006UL, 3884572674UL, 789998735UL, 1155994673UL, 2022469457UL, 223162974UL, 309571006UL, 725482797UL, 3909032036UL, 2531190541UL, 373676789UL, 1061107200UL, 4231921550UL, +558635876UL, 2773807977UL, 1860218585UL, 1150041015UL, 2252812038UL, 2413330952UL, 191909567UL, 3518171813UL, 3513416318UL, 2679253717UL, 3850755687UL, 1564154710UL, 324714884UL, 1600953447UL, 4095583159UL, 1796641692UL, 2518000547UL, 3621187982UL, 501166402UL, 2112782420UL, 1704276185UL, 2249859782UL, 3754293422UL, 1942321901UL, 1851019104UL, 240158224UL, 3181132144UL, 2281632719UL, 808029657UL, 1721710011UL, 2287207169UL, 3044484177UL, +2363339534UL, 805273402UL, 3696016147UL, 3549191229UL, 3353631259UL, 2946802391UL, 383414270UL, 300735554UL, 471515206UL, 1907815837UL, 1576327662UL, 3825043525UL, 2817119733UL, 1973847200UL, 1398317206UL, 2221853087UL, 501440864UL, 642467132UL, 494410179UL, 1191241925UL, 3549838846UL, 3621239619UL, 2640266286UL, 4140123024UL, 315957218UL, 3696758268UL, 2502777875UL, 2150738616UL, 1570099119UL, 2598276767UL, 3585886712UL, 230047417UL, +}, +{ +220882755UL, 630187688UL, 2600079656UL, 3103815531UL, 4259457395UL, 306940008UL, 760977254UL, 558299017UL, 73879495UL, 2342545344UL, 572800511UL, 3922797738UL, 3754011306UL, 698257357UL, 1274843132UL, 1455757442UL, 1014649591UL, 3205662508UL, 2997738251UL, 613949432UL, 2267018388UL, 2925762681UL, 3702061213UL, 299380602UL, 1711070497UL, 4140032336UL, 4134705925UL, 2836703879UL, 3776863395UL, 507121465UL, 3480792188UL, 1862887216UL, +247780795UL, 2528677869UL, 2881446422UL, 271754977UL, 833498724UL, 1489102731UL, 3636156177UL, 1839744487UL, 2011839858UL, 2353400914UL, 510437606UL, 561141583UL, 2979592314UL, 3844268262UL, 3011027242UL, 3113817193UL, 3491178377UL, 1448376742UL, 2478683391UL, 2597550150UL, 699310968UL, 1979488062UL, 277591964UL, 1312002175UL, 168047351UL, 1826859926UL, 2030631355UL, 3097860388UL, 1950614326UL, 4070838751UL, 4454933UL, 1890661188UL, +3929835227UL, 1008498572UL, 3301557438UL, 3906313590UL, 1240635175UL, 280935563UL, 113509402UL, 226900299UL, 1246395851UL, 1220916742UL, 2651515540UL, 2058590162UL, 1983114332UL, 2040467861UL, 780818345UL, 544262576UL, 2826997265UL, 349354812UL, 2360120613UL, 1181324247UL, 2380347783UL, 3938729706UL, 1610628643UL, 2008635822UL, 2937909233UL, 1583978206UL, 3589167073UL, 1942470196UL, 402177406UL, 2636510744UL, 3709747478UL, 2428569572UL, +4071828137UL, 2880315633UL, 1433558231UL, 1137076031UL, 3833202201UL, 2378168250UL, 1412413704UL, 3349323744UL, 1740721660UL, 3155643175UL, 2580327273UL, 3020661883UL, 1658910832UL, 2065649368UL, 3277572880UL, 3795585437UL, 1266185861UL, 2925935368UL, 4147230645UL, 203577834UL, 2230529041UL, 2864778434UL, 270386174UL, 2867122465UL, 2676624544UL, 2035972330UL, 500973884UL, 2983028740UL, 117131866UL, 1456450936UL, 429171245UL, 3921563262UL, +342800398UL, 255116920UL, 1219580025UL, 1549741331UL, 3832317567UL, 3750096895UL, 4036554472UL, 4099775516UL, 1451717480UL, 149159438UL, 3593827664UL, 1406572509UL, 27774796UL, 1138983585UL, 1577536190UL, 978350835UL, 2704344602UL, 95204061UL, 1507155668UL, 304760810UL, 1981315657UL, 3139306913UL, 3908131532UL, 3767856445UL, 3851422551UL, 2018732047UL, 2474676116UL, 2745551516UL, 1585868430UL, 1125303733UL, 3147584753UL, 2368921260UL, +1524991519UL, 220882755UL, 630187688UL, 2600079656UL, 3103815531UL, 2671841243UL, 306940008UL, 760977254UL, 558299017UL, 73879495UL, 1196617651UL, 572800511UL, 3922797738UL, 3754011306UL, 698257357UL, 1982654891UL, 1455757442UL, 1014649591UL, 3205662508UL, 2997738251UL, 3769735713UL, 2267018388UL, 2925762681UL, 3702061213UL, 299380602UL, 2224634157UL, 4140032336UL, 4134705925UL, 2836703879UL, 3776863395UL, 1027030708UL, 3480792188UL, +1862887216UL, 247780795UL, 2528677869UL, 300214141UL, 271754977UL, 833498724UL, 1489102731UL, 3636156177UL, 1683033001UL, 2011839858UL, 2353400914UL, 510437606UL, 561141583UL, 2832813585UL, 3844268262UL, 3011027242UL, 3113817193UL, 3491178377UL, 316500941UL, 2478683391UL, 2597550150UL, 699310968UL, 1979488062UL, 4092049617UL, 1312002175UL, 168047351UL, 1826859926UL, 2030631355UL, 2797906491UL, 1950614326UL, 4070838751UL, 4454933UL, +1890661188UL, 2602196847UL, 1008498572UL, 3301557438UL, 3906313590UL, 1240635175UL, 946440664UL, 113509402UL, 226900299UL, 1246395851UL, 1220916742UL, 1314772486UL, 2058590162UL, 1983114332UL, 2040467861UL, 780818345UL, 3064382079UL, 2826997265UL, 349354812UL, 2360120613UL, 1181324247UL, 3434653713UL, 3938729706UL, 1610628643UL, 2008635822UL, 2937909233UL, 2815835447UL, 3589167073UL, 1942470196UL, 402177406UL, 2636510744UL, 865459039UL, +2428569572UL, 4071828137UL, 2880315633UL, 1433558231UL, 1582478959UL, 3833202201UL, 2378168250UL, 1412413704UL, 3349323744UL, 3686787615UL, 3155643175UL, 2580327273UL, 3020661883UL, 1658910832UL, 3152644489UL, 3277572880UL, 3795585437UL, 1266185861UL, 2925935368UL, 3101079227UL, 203577834UL, 2230529041UL, 2864778434UL, 270386174UL, 3024925346UL, 2676624544UL, 2035972330UL, 500973884UL, 2983028740UL, 974511421UL, 1456450936UL, 429171245UL, +3921563262UL, 342800398UL, 1540218139UL, 1219580025UL, 1549741331UL, 3832317567UL, 3750096895UL, 2195381148UL, 4099775516UL, 1451717480UL, 149159438UL, 3593827664UL, 3715984838UL, 27774796UL, 1138983585UL, 1577536190UL, 978350835UL, 2060213898UL, 95204061UL, 1507155668UL, 304760810UL, 1981315657UL, 774471092UL, 3908131532UL, 3767856445UL, 3851422551UL, 2018732047UL, 1649125731UL, 2745551516UL, 1585868430UL, 1125303733UL, 3147584753UL, +1661721342UL, 1524991519UL, 220882755UL, 630187688UL, 2600079656UL, 3647143842UL, 2671841243UL, 306940008UL, 760977254UL, 558299017UL, 3406011854UL, 1196617651UL, 572800511UL, 3922797738UL, 3754011306UL, 2314291278UL, 1982654891UL, 1455757442UL, 1014649591UL, 3205662508UL, 3471741326UL, 3769735713UL, 2267018388UL, 2925762681UL, 3702061213UL, 1593850639UL, 2224634157UL, 4140032336UL, 4134705925UL, 2836703879UL, 3918266498UL, 1027030708UL, +3480792188UL, 1862887216UL, 247780795UL, 3383776045UL, 300214141UL, 271754977UL, 833498724UL, 1489102731UL, 2477093804UL, 1683033001UL, 2011839858UL, 2353400914UL, 510437606UL, 2361664959UL, 2832813585UL, 3844268262UL, 3011027242UL, 3113817193UL, 1468705704UL, 316500941UL, 2478683391UL, 2597550150UL, 699310968UL, 1593029686UL, 4092049617UL, 1312002175UL, 168047351UL, 1826859926UL, 3922295193UL, 2797906491UL, 1950614326UL, 4070838751UL, +4454933UL, 485374579UL, 2602196847UL, 1008498572UL, 3301557438UL, 3906313590UL, 2102043683UL, 946440664UL, 113509402UL, 226900299UL, 1246395851UL, 2635764090UL, 1314772486UL, 2058590162UL, 1983114332UL, 2040467861UL, 354791UL, 3064382079UL, 2826997265UL, 349354812UL, 2360120613UL, 2126504772UL, 3434653713UL, 3938729706UL, 1610628643UL, 2008635822UL, 2400061949UL, 2815835447UL, 3589167073UL, 1942470196UL, 402177406UL, 806469309UL, +865459039UL, 2428569572UL, 4071828137UL, 2880315633UL, 2512200928UL, 1582478959UL, 3833202201UL, 2378168250UL, 1412413704UL, 2767451252UL, 3686787615UL, 3155643175UL, 2580327273UL, 3020661883UL, 1040874588UL, 3152644489UL, 3277572880UL, 3795585437UL, 1266185861UL, 238446394UL, 3101079227UL, 203577834UL, 2230529041UL, 2864778434UL, 653319712UL, 3024925346UL, 2676624544UL, 2035972330UL, 500973884UL, 3839534784UL, 974511421UL, 1456450936UL, +429171245UL, 3921563262UL, 602320448UL, 1540218139UL, 1219580025UL, 1549741331UL, 3832317567UL, 1068872823UL, 2195381148UL, 4099775516UL, 1451717480UL, 149159438UL, 1699607068UL, 3715984838UL, 27774796UL, 1138983585UL, 1577536190UL, 837921790UL, 2060213898UL, 95204061UL, 1507155668UL, 304760810UL, 1446133066UL, 774471092UL, 3908131532UL, 3767856445UL, 3851422551UL, 2672625648UL, 1649125731UL, 2745551516UL, 1585868430UL, 1125303733UL, +2181520384UL, 1661721342UL, 1524991519UL, 220882755UL, 630187688UL, 1599074811UL, 3647143842UL, 2671841243UL, 306940008UL, 760977254UL, 3020017536UL, 3406011854UL, 1196617651UL, 572800511UL, 3922797738UL, 810584907UL, 2314291278UL, 1982654891UL, 1455757442UL, 1014649591UL, 1775783567UL, 3471741326UL, 3769735713UL, 2267018388UL, 2925762681UL, 319055602UL, 1593850639UL, 2224634157UL, 4140032336UL, 4134705925UL, 2794599326UL, 3918266498UL, +1027030708UL, 3480792188UL, 1862887216UL, 659607854UL, 3383776045UL, 300214141UL, 271754977UL, 833498724UL, 4054679386UL, 2477093804UL, 1683033001UL, 2011839858UL, 2353400914UL, 283191425UL, 2361664959UL, 2832813585UL, 3844268262UL, 3011027242UL, 137688840UL, 1468705704UL, 316500941UL, 2478683391UL, 2597550150UL, 1468220070UL, 1593029686UL, 4092049617UL, 1312002175UL, 168047351UL, 1602414610UL, 3922295193UL, 2797906491UL, 1950614326UL, +4070838751UL, 3858763082UL, 485374579UL, 2602196847UL, 1008498572UL, 3301557438UL, 2719858709UL, 2102043683UL, 946440664UL, 113509402UL, 226900299UL, 798285817UL, 2635764090UL, 1314772486UL, 2058590162UL, 1983114332UL, 2526463430UL, 354791UL, 3064382079UL, 2826997265UL, 349354812UL, 249430921UL, 2126504772UL, 3434653713UL, 3938729706UL, 1610628643UL, 967431506UL, 2400061949UL, 2815835447UL, 3589167073UL, 1942470196UL, 669129162UL, +806469309UL, 865459039UL, 2428569572UL, 4071828137UL, 3447449944UL, 2512200928UL, 1582478959UL, 3833202201UL, 2378168250UL, 1945768856UL, 2767451252UL, 3686787615UL, 3155643175UL, 2580327273UL, 2905624117UL, 1040874588UL, 3152644489UL, 3277572880UL, 3795585437UL, 3869959934UL, 238446394UL, 3101079227UL, 203577834UL, 2230529041UL, 1087760616UL, 653319712UL, 3024925346UL, 2676624544UL, 2035972330UL, 741014356UL, 3839534784UL, 974511421UL, +1456450936UL, 429171245UL, 598362053UL, 602320448UL, 1540218139UL, 1219580025UL, 1549741331UL, 401740328UL, 1068872823UL, 2195381148UL, 4099775516UL, 1451717480UL, 412110161UL, 1699607068UL, 3715984838UL, 27774796UL, 1138983585UL, 1531670562UL, 837921790UL, 2060213898UL, 95204061UL, 1507155668UL, 90279751UL, 1446133066UL, 774471092UL, 3908131532UL, 3767856445UL, 1136546910UL, 2672625648UL, 1649125731UL, 2745551516UL, 1585868430UL, +857721974UL, 1470900829UL, 64550776UL, 3252081369UL, 1649342279UL, 378546910UL, 3444980597UL, 3134750739UL, 1010105258UL, 1395608241UL, 1003208120UL, 3960524028UL, 3200241620UL, 3079969898UL, 1508044775UL, 4153769914UL, 2838198142UL, 773928818UL, 25836261UL, 3812652461UL, 3870603819UL, 931071963UL, 2565579710UL, 2930918109UL, 1091097445UL, 2223628368UL, 2934719684UL, 430797922UL, 2102409587UL, 720592077UL, 1675280068UL, 2578226918UL, +1316600845UL, 3427946098UL, 682896800UL, 1861125007UL, 251332674UL, 1502078012UL, 3020904394UL, 1458399451UL, 3088315263UL, 1635399147UL, 3605560130UL, 1755669804UL, 3754169290UL, 962708070UL, 3896576937UL, 3764679740UL, 2707457262UL, 3082551065UL, 1558451132UL, 1046028905UL, 3206335691UL, 731828142UL, 1765772975UL, 1195727587UL, 2664218451UL, 4234957963UL, 4073757168UL, 3230123616UL, 683981262UL, 607599877UL, 3659273671UL, 3230354324UL, +3393069074UL, 3250708814UL, 2229361194UL, 3923623619UL, 4093221649UL, 2441971643UL, 1787414237UL, 3603907850UL, 2254399656UL, 3508336126UL, 3578571587UL, 2383062806UL, 1012097006UL, 4250629546UL, 2086981615UL, 4190388250UL, 1399942361UL, 400707931UL, 3159618664UL, 2129750192UL, 911779896UL, 2736829998UL, 1909644954UL, 2168355517UL, 1583901478UL, 3468891177UL, 509297602UL, 769296769UL, 1865028750UL, 43276967UL, 3375387845UL, 2647467777UL, +1544731454UL, 3479333955UL, 4279441447UL, 485490313UL, 3523606596UL, 2880752852UL, 1946443431UL, 3760803481UL, 3115278477UL, 3693898557UL, 2387822435UL, 334412170UL, 2054111717UL, 269013084UL, 170401553UL, 3456013554UL, 3395842846UL, 508189059UL, 3398715186UL, 3862791669UL, 2741070272UL, 65318715UL, 1933435210UL, 4086198650UL, 3033193928UL, 1242412691UL, 3397363281UL, 3187419149UL, 1019508117UL, 562380742UL, 961415837UL, 2990412400UL, +3597720222UL, 2754100415UL, 1793508822UL, 966564784UL, 1875616532UL, 394646945UL, 1386107842UL, 2750810827UL, 2931007937UL, 3356489930UL, 2358364634UL, 3703772713UL, 3188884403UL, 2793590498UL, 3285138686UL, 515002680UL, 521510516UL, 887213583UL, 1873460781UL, 1583027667UL, 613895001UL, 557578628UL, 1892686243UL, 1974572772UL, 595831726UL, 229299738UL, 3847982294UL, 448248098UL, 1493822844UL, 3326405260UL, 2752463855UL, 128616819UL, +}, +{ +2014765631UL, 3938779303UL, 1811986049UL, 2101875601UL, 887194972UL, 3966228860UL, 3450775746UL, 4026039255UL, 4082308025UL, 432404123UL, 3181099213UL, 1228097256UL, 2368258457UL, 2953933351UL, 2582232464UL, 1657799516UL, 3525421629UL, 3927364159UL, 978138132UL, 3603597064UL, 342571522UL, 2100072168UL, 676229632UL, 2062864895UL, 3713317279UL, 4255773013UL, 1179492389UL, 3501226604UL, 1641801113UL, 2066614519UL, 3303232023UL, 1717768923UL, +2333501450UL, 4246883128UL, 1655087824UL, 1547897374UL, 754215285UL, 2832638094UL, 1365153701UL, 3309513970UL, 765738141UL, 1177808869UL, 324127419UL, 1171195868UL, 3494966448UL, 1714410667UL, 3645762436UL, 603810292UL, 489970006UL, 3126166124UL, 1616642501UL, 2646836239UL, 734727001UL, 118064420UL, 1164195304UL, 3692353914UL, 2267623847UL, 405457397UL, 2510437259UL, 3245015882UL, 2110859730UL, 967046702UL, 265790493UL, 3007163818UL, +3178475505UL, 1784447992UL, 3662964942UL, 1509963062UL, 1867864652UL, 1377871790UL, 4185567242UL, 657897796UL, 1762205546UL, 3895944199UL, 693988565UL, 2359023506UL, 1667660316UL, 478341078UL, 1898651054UL, 2352226314UL, 202416031UL, 855532642UL, 2290137962UL, 1573485803UL, 3675269487UL, 2346740592UL, 3111005795UL, 1741227661UL, 1222572879UL, 2176146608UL, 1595608675UL, 197451178UL, 1729118168UL, 876472937UL, 3201705210UL, 2315408645UL, +699968623UL, 2185639066UL, 3960900430UL, 539499973UL, 4226318752UL, 266371152UL, 2714506838UL, 945022093UL, 1378798863UL, 1925020181UL, 574417318UL, 1341455098UL, 3664225722UL, 3020780778UL, 3256613994UL, 2081255019UL, 3082744844UL, 3572803922UL, 1726854692UL, 1167777002UL, 557257486UL, 3577067012UL, 3806913480UL, 1578577194UL, 2631896730UL, 3937479909UL, 826138924UL, 670145071UL, 832017019UL, 715875283UL, 2008704579UL, 804955545UL, +4184114494UL, 867004874UL, 3586861289UL, 1190193155UL, 3288754776UL, 2271906590UL, 2007547109UL, 2206084232UL, 1621944575UL, 973990634UL, 3981493346UL, 1972746975UL, 1040348653UL, 2895228417UL, 691038334UL, 775610724UL, 3837025597UL, 714850057UL, 2912426839UL, 774555258UL, 3553866253UL, 2096154755UL, 1645117543UL, 3401470072UL, 2056183169UL, 2029528044UL, 3145728013UL, 1090530001UL, 49523828UL, 2228313334UL, 4013648604UL, 4289025873UL, +2749397923UL, 2014765631UL, 3938779303UL, 1811986049UL, 2101875601UL, 1575247143UL, 3966228860UL, 3450775746UL, 4026039255UL, 4082308025UL, 532118065UL, 3181099213UL, 1228097256UL, 2368258457UL, 2953933351UL, 896129082UL, 1657799516UL, 3525421629UL, 3927364159UL, 978138132UL, 3403930517UL, 342571522UL, 2100072168UL, 676229632UL, 2062864895UL, 38934050UL, 4255773013UL, 1179492389UL, 3501226604UL, 1641801113UL, 4195983797UL, 3303232023UL, +1717768923UL, 2333501450UL, 4246883128UL, 2854551758UL, 1547897374UL, 754215285UL, 2832638094UL, 1365153701UL, 1406220165UL, 765738141UL, 1177808869UL, 324127419UL, 1171195868UL, 625985592UL, 1714410667UL, 3645762436UL, 603810292UL, 489970006UL, 344948229UL, 1616642501UL, 2646836239UL, 734727001UL, 118064420UL, 3360380275UL, 3692353914UL, 2267623847UL, 405457397UL, 2510437259UL, 3697919521UL, 2110859730UL, 967046702UL, 265790493UL, +3007163818UL, 1395299303UL, 1784447992UL, 3662964942UL, 1509963062UL, 1867864652UL, 849544728UL, 4185567242UL, 657897796UL, 1762205546UL, 3895944199UL, 1219998053UL, 2359023506UL, 1667660316UL, 478341078UL, 1898651054UL, 943166064UL, 202416031UL, 855532642UL, 2290137962UL, 1573485803UL, 4238971908UL, 2346740592UL, 3111005795UL, 1741227661UL, 1222572879UL, 2670048596UL, 1595608675UL, 197451178UL, 1729118168UL, 876472937UL, 94688481UL, +2315408645UL, 699968623UL, 2185639066UL, 3960900430UL, 1224638706UL, 4226318752UL, 266371152UL, 2714506838UL, 945022093UL, 2683523818UL, 1925020181UL, 574417318UL, 1341455098UL, 3664225722UL, 1168593559UL, 3256613994UL, 2081255019UL, 3082744844UL, 3572803922UL, 2816021735UL, 1167777002UL, 557257486UL, 3577067012UL, 3806913480UL, 740433434UL, 2631896730UL, 3937479909UL, 826138924UL, 670145071UL, 4127240538UL, 715875283UL, 2008704579UL, +804955545UL, 4184114494UL, 1692532062UL, 3586861289UL, 1190193155UL, 3288754776UL, 2271906590UL, 922306057UL, 2206084232UL, 1621944575UL, 973990634UL, 3981493346UL, 3555073644UL, 1040348653UL, 2895228417UL, 691038334UL, 775610724UL, 1798939042UL, 714850057UL, 2912426839UL, 774555258UL, 3553866253UL, 4209859609UL, 1645117543UL, 3401470072UL, 2056183169UL, 2029528044UL, 2169159734UL, 1090530001UL, 49523828UL, 2228313334UL, 4013648604UL, +1499948031UL, 2749397923UL, 2014765631UL, 3938779303UL, 1811986049UL, 2169095159UL, 1575247143UL, 3966228860UL, 3450775746UL, 4026039255UL, 1220311069UL, 532118065UL, 3181099213UL, 1228097256UL, 2368258457UL, 649921441UL, 896129082UL, 1657799516UL, 3525421629UL, 3927364159UL, 2546335470UL, 3403930517UL, 342571522UL, 2100072168UL, 676229632UL, 3090148374UL, 38934050UL, 4255773013UL, 1179492389UL, 3501226604UL, 2613176152UL, 4195983797UL, +3303232023UL, 1717768923UL, 2333501450UL, 3923041739UL, 2854551758UL, 1547897374UL, 754215285UL, 2832638094UL, 731392091UL, 1406220165UL, 765738141UL, 1177808869UL, 324127419UL, 12876722UL, 625985592UL, 1714410667UL, 3645762436UL, 603810292UL, 2789313462UL, 344948229UL, 1616642501UL, 2646836239UL, 734727001UL, 3369486664UL, 3360380275UL, 3692353914UL, 2267623847UL, 405457397UL, 4284067044UL, 3697919521UL, 2110859730UL, 967046702UL, +265790493UL, 2779045063UL, 1395299303UL, 1784447992UL, 3662964942UL, 1509963062UL, 3233239196UL, 849544728UL, 4185567242UL, 657897796UL, 1762205546UL, 2086953994UL, 1219998053UL, 2359023506UL, 1667660316UL, 478341078UL, 4137166515UL, 943166064UL, 202416031UL, 855532642UL, 2290137962UL, 1053737970UL, 4238971908UL, 2346740592UL, 3111005795UL, 1741227661UL, 3570501235UL, 2670048596UL, 1595608675UL, 197451178UL, 1729118168UL, 4162077327UL, +94688481UL, 2315408645UL, 699968623UL, 2185639066UL, 2842562270UL, 1224638706UL, 4226318752UL, 266371152UL, 2714506838UL, 755620309UL, 2683523818UL, 1925020181UL, 574417318UL, 1341455098UL, 3323621213UL, 1168593559UL, 3256613994UL, 2081255019UL, 3082744844UL, 3845230416UL, 2816021735UL, 1167777002UL, 557257486UL, 3577067012UL, 66225918UL, 740433434UL, 2631896730UL, 3937479909UL, 826138924UL, 522548622UL, 4127240538UL, 715875283UL, +2008704579UL, 804955545UL, 22190845UL, 1692532062UL, 3586861289UL, 1190193155UL, 3288754776UL, 610751818UL, 922306057UL, 2206084232UL, 1621944575UL, 973990634UL, 1771882567UL, 3555073644UL, 1040348653UL, 2895228417UL, 691038334UL, 149995790UL, 1798939042UL, 714850057UL, 2912426839UL, 774555258UL, 2020442761UL, 4209859609UL, 1645117543UL, 3401470072UL, 2056183169UL, 460813741UL, 2169159734UL, 1090530001UL, 49523828UL, 2228313334UL, +504317288UL, 1499948031UL, 2749397923UL, 2014765631UL, 3938779303UL, 1175469033UL, 2169095159UL, 1575247143UL, 3966228860UL, 3450775746UL, 1032079910UL, 1220311069UL, 532118065UL, 3181099213UL, 1228097256UL, 3353583885UL, 649921441UL, 896129082UL, 1657799516UL, 3525421629UL, 2830418357UL, 2546335470UL, 3403930517UL, 342571522UL, 2100072168UL, 1099053459UL, 3090148374UL, 38934050UL, 4255773013UL, 1179492389UL, 1634035942UL, 2613176152UL, +4195983797UL, 3303232023UL, 1717768923UL, 4175785502UL, 3923041739UL, 2854551758UL, 1547897374UL, 754215285UL, 3674851127UL, 731392091UL, 1406220165UL, 765738141UL, 1177808869UL, 776475327UL, 12876722UL, 625985592UL, 1714410667UL, 3645762436UL, 759189800UL, 2789313462UL, 344948229UL, 1616642501UL, 2646836239UL, 1228911282UL, 3369486664UL, 3360380275UL, 3692353914UL, 2267623847UL, 3058856811UL, 4284067044UL, 3697919521UL, 2110859730UL, +967046702UL, 3601311392UL, 2779045063UL, 1395299303UL, 1784447992UL, 3662964942UL, 284169442UL, 3233239196UL, 849544728UL, 4185567242UL, 657897796UL, 905886381UL, 2086953994UL, 1219998053UL, 2359023506UL, 1667660316UL, 2784311626UL, 4137166515UL, 943166064UL, 202416031UL, 855532642UL, 895862877UL, 1053737970UL, 4238971908UL, 2346740592UL, 3111005795UL, 1509264114UL, 3570501235UL, 2670048596UL, 1595608675UL, 197451178UL, 3653040124UL, +4162077327UL, 94688481UL, 2315408645UL, 699968623UL, 1071988392UL, 2842562270UL, 1224638706UL, 4226318752UL, 266371152UL, 4214356293UL, 755620309UL, 2683523818UL, 1925020181UL, 574417318UL, 119162126UL, 3323621213UL, 1168593559UL, 3256613994UL, 2081255019UL, 1317924999UL, 3845230416UL, 2816021735UL, 1167777002UL, 557257486UL, 638058809UL, 66225918UL, 740433434UL, 2631896730UL, 3937479909UL, 411228024UL, 522548622UL, 4127240538UL, +715875283UL, 2008704579UL, 2246049355UL, 22190845UL, 1692532062UL, 3586861289UL, 1190193155UL, 4078828073UL, 610751818UL, 922306057UL, 2206084232UL, 1621944575UL, 907181435UL, 1771882567UL, 3555073644UL, 1040348653UL, 2895228417UL, 940846326UL, 149995790UL, 1798939042UL, 714850057UL, 2912426839UL, 3345560812UL, 2020442761UL, 4209859609UL, 1645117543UL, 3401470072UL, 2036328600UL, 460813741UL, 2169159734UL, 1090530001UL, 49523828UL, +510136795UL, 2233313725UL, 1046048857UL, 700202384UL, 926275751UL, 4104982908UL, 3910999868UL, 1125213128UL, 492681420UL, 3891914731UL, 956545470UL, 115696875UL, 2957144177UL, 77090391UL, 467732901UL, 2599813105UL, 3888976883UL, 2098926023UL, 2844817051UL, 2069408123UL, 2239429902UL, 3793992219UL, 3020240490UL, 1721698056UL, 3012473888UL, 1537226153UL, 725991171UL, 61376035UL, 381912667UL, 3904514327UL, 40015731UL, 4263210119UL, +2876064791UL, 2732785471UL, 2934318283UL, 3134934287UL, 3161129365UL, 3789733734UL, 2954419388UL, 2742205850UL, 3488450208UL, 3252908703UL, 410643191UL, 3246033194UL, 2846558783UL, 828879673UL, 2428687670UL, 389617242UL, 63987225UL, 439842832UL, 2635895570UL, 3468152776UL, 4086700701UL, 3370617315UL, 2400127386UL, 4266992260UL, 3026019128UL, 4225721108UL, 1328114488UL, 2808680961UL, 3574018824UL, 4060262451UL, 2329039960UL, 1165344648UL, +3635963149UL, 2414703792UL, 2269100254UL, 832995451UL, 2143875746UL, 1031309981UL, 2129333746UL, 2606784227UL, 805236091UL, 666141116UL, 2749351381UL, 53998350UL, 2270447972UL, 2092784991UL, 877961283UL, 3019419608UL, 2438459472UL, 2273921167UL, 332279281UL, 3759993687UL, 2465113760UL, 3732237006UL, 322823266UL, 491053374UL, 686619591UL, 4192648122UL, 4118497267UL, 1948902148UL, 988375775UL, 2098328675UL, 3107501958UL, 2979856583UL, +2274193457UL, 6179961UL, 188209161UL, 1491245003UL, 3005972885UL, 1658799053UL, 3420802262UL, 2128792168UL, 3272743598UL, 4163716849UL, 817350318UL, 3372322557UL, 1525295885UL, 490587460UL, 3634834949UL, 2584809384UL, 3638373352UL, 2603765126UL, 3223396315UL, 4021061386UL, 2143780551UL, 248332433UL, 3654752967UL, 27201989UL, 3994156272UL, 5505477UL, 4260955724UL, 1175998822UL, 2665646240UL, 866875674UL, 3569324422UL, 202962714UL, +896177244UL, 3146417201UL, 1168925859UL, 2228636445UL, 105395449UL, 2567482935UL, 1301265751UL, 3739617610UL, 2486939910UL, 1891847857UL, 2647840744UL, 1141826566UL, 3360553996UL, 4267671927UL, 2546157872UL, 1143297884UL, 2049385137UL, 4288036836UL, 3347190546UL, 3480408604UL, 2756408254UL, 2396048567UL, 1151717877UL, 2211243289UL, 4221659024UL, 21773193UL, 1665317870UL, 3116384869UL, 3231689469UL, 3689471824UL, 1520574310UL, 463615415UL, +}, +{ +2647200400UL, 1592194261UL, 1289872755UL, 2079982087UL, 3431487085UL, 1101851783UL, 3373292799UL, 2148994262UL, 2785319928UL, 3206527339UL, 2731839331UL, 1280366172UL, 1146205735UL, 2930495205UL, 2876978398UL, 3885758458UL, 2062812458UL, 2448488486UL, 192141900UL, 3861696664UL, 2677929258UL, 3606729729UL, 2920965773UL, 1156521508UL, 3168665640UL, 298794036UL, 957896625UL, 2606719899UL, 3699219026UL, 3120096333UL, 2531109351UL, 1920936462UL, +2848868175UL, 1406404729UL, 2956672675UL, 1376226240UL, 3667482110UL, 2551426756UL, 3433640449UL, 2603906744UL, 4217864690UL, 47671552UL, 2993859190UL, 1269153270UL, 3463588775UL, 1655126430UL, 3453916724UL, 2157890969UL, 252769449UL, 1583335064UL, 2560819344UL, 52639671UL, 39618615UL, 313192112UL, 2625914283UL, 2964928555UL, 4226359627UL, 4141969666UL, 183405146UL, 1455378225UL, 2994063945UL, 3146629795UL, 2992956289UL, 368634554UL, +4110058153UL, 1156556441UL, 3690317172UL, 906928962UL, 3773042217UL, 948650679UL, 4134172918UL, 2922802573UL, 1417921660UL, 291400676UL, 3120733115UL, 3225369425UL, 3200455006UL, 2207799613UL, 1766261260UL, 914727455UL, 1927023103UL, 572959294UL, 3447057855UL, 4042691162UL, 840021910UL, 4187195325UL, 3627831667UL, 1671506539UL, 242673485UL, 3330397756UL, 776552069UL, 684550924UL, 261597601UL, 1857936262UL, 1022869402UL, 4209077103UL, +14248159UL, 2366156245UL, 1910356465UL, 2020463550UL, 873419743UL, 4290775093UL, 3670978210UL, 1726974037UL, 784115717UL, 3574834402UL, 357805142UL, 3820795621UL, 1854247318UL, 1161642656UL, 3977404318UL, 2054677775UL, 1737374322UL, 2852015019UL, 4277252452UL, 1392810771UL, 3742661504UL, 1900815804UL, 1965911170UL, 3540183220UL, 2106191537UL, 3606954134UL, 2108636204UL, 2981827052UL, 2506861567UL, 184003599UL, 3319252632UL, 1370913077UL, +940955681UL, 2244100002UL, 3683661822UL, 3215832318UL, 3463899341UL, 134577035UL, 3404365179UL, 2262494389UL, 88039196UL, 114405083UL, 1071449574UL, 4008494055UL, 765981248UL, 758357266UL, 2564125377UL, 901977407UL, 955156196UL, 3900980822UL, 134031448UL, 2566915950UL, 3445833537UL, 3138903399UL, 2113076217UL, 713587277UL, 3396078039UL, 3987657193UL, 3004104774UL, 800324742UL, 652529813UL, 3999083342UL, 486108562UL, 2103591900UL, +104743736UL, 2647200400UL, 1592194261UL, 1289872755UL, 2079982087UL, 552781204UL, 1101851783UL, 3373292799UL, 2148994262UL, 2785319928UL, 1222851809UL, 2731839331UL, 1280366172UL, 1146205735UL, 2930495205UL, 942360591UL, 3885758458UL, 2062812458UL, 2448488486UL, 192141900UL, 1909229999UL, 2677929258UL, 3606729729UL, 2920965773UL, 1156521508UL, 2995805883UL, 298794036UL, 957896625UL, 2606719899UL, 3699219026UL, 2447513005UL, 2531109351UL, +1920936462UL, 2848868175UL, 1406404729UL, 2751142611UL, 1376226240UL, 3667482110UL, 2551426756UL, 3433640449UL, 3724189478UL, 4217864690UL, 47671552UL, 2993859190UL, 1269153270UL, 2144136371UL, 1655126430UL, 3453916724UL, 2157890969UL, 252769449UL, 2959496542UL, 2560819344UL, 52639671UL, 39618615UL, 313192112UL, 2367743540UL, 2964928555UL, 4226359627UL, 4141969666UL, 183405146UL, 2006751422UL, 2994063945UL, 3146629795UL, 2992956289UL, +368634554UL, 1529794973UL, 1156556441UL, 3690317172UL, 906928962UL, 3773042217UL, 2005599428UL, 4134172918UL, 2922802573UL, 1417921660UL, 291400676UL, 2664982078UL, 3225369425UL, 3200455006UL, 2207799613UL, 1766261260UL, 2623711877UL, 1927023103UL, 572959294UL, 3447057855UL, 4042691162UL, 3510199782UL, 4187195325UL, 3627831667UL, 1671506539UL, 242673485UL, 1978730938UL, 776552069UL, 684550924UL, 261597601UL, 1857936262UL, 3273582958UL, +4209077103UL, 14248159UL, 2366156245UL, 1910356465UL, 457933823UL, 873419743UL, 4290775093UL, 3670978210UL, 1726974037UL, 1414288023UL, 3574834402UL, 357805142UL, 3820795621UL, 1854247318UL, 2679386897UL, 3977404318UL, 2054677775UL, 1737374322UL, 2852015019UL, 2411291453UL, 1392810771UL, 3742661504UL, 1900815804UL, 1965911170UL, 3719529323UL, 2106191537UL, 3606954134UL, 2108636204UL, 2981827052UL, 3702357099UL, 184003599UL, 3319252632UL, +1370913077UL, 940955681UL, 4262675711UL, 3683661822UL, 3215832318UL, 3463899341UL, 134577035UL, 3494669542UL, 2262494389UL, 88039196UL, 114405083UL, 1071449574UL, 1060831201UL, 765981248UL, 758357266UL, 2564125377UL, 901977407UL, 3003279383UL, 3900980822UL, 134031448UL, 2566915950UL, 3445833537UL, 2846863035UL, 2113076217UL, 713587277UL, 3396078039UL, 3987657193UL, 2067196130UL, 800324742UL, 652529813UL, 3999083342UL, 486108562UL, +2321935002UL, 104743736UL, 2647200400UL, 1592194261UL, 1289872755UL, 466892855UL, 552781204UL, 1101851783UL, 3373292799UL, 2148994262UL, 3078568050UL, 1222851809UL, 2731839331UL, 1280366172UL, 1146205735UL, 1710937426UL, 942360591UL, 3885758458UL, 2062812458UL, 2448488486UL, 3418446265UL, 1909229999UL, 2677929258UL, 3606729729UL, 2920965773UL, 1103324742UL, 2995805883UL, 298794036UL, 957896625UL, 2606719899UL, 675602173UL, 2447513005UL, +2531109351UL, 1920936462UL, 2848868175UL, 1509959171UL, 2751142611UL, 1376226240UL, 3667482110UL, 2551426756UL, 2447143807UL, 3724189478UL, 4217864690UL, 47671552UL, 2993859190UL, 2821422976UL, 2144136371UL, 1655126430UL, 3453916724UL, 2157890969UL, 3665277070UL, 2959496542UL, 2560819344UL, 52639671UL, 39618615UL, 2817859210UL, 2367743540UL, 2964928555UL, 4226359627UL, 4141969666UL, 2856219617UL, 2006751422UL, 2994063945UL, 3146629795UL, +2992956289UL, 3176479073UL, 1529794973UL, 1156556441UL, 3690317172UL, 906928962UL, 97899274UL, 2005599428UL, 4134172918UL, 2922802573UL, 1417921660UL, 1492426675UL, 2664982078UL, 3225369425UL, 3200455006UL, 2207799613UL, 2275640124UL, 2623711877UL, 1927023103UL, 572959294UL, 3447057855UL, 1036984002UL, 3510199782UL, 4187195325UL, 3627831667UL, 1671506539UL, 1827895694UL, 1978730938UL, 776552069UL, 684550924UL, 261597601UL, 3493571621UL, +3273582958UL, 4209077103UL, 14248159UL, 2366156245UL, 211745521UL, 457933823UL, 873419743UL, 4290775093UL, 3670978210UL, 1909994881UL, 1414288023UL, 3574834402UL, 357805142UL, 3820795621UL, 1911700755UL, 2679386897UL, 3977404318UL, 2054677775UL, 1737374322UL, 213019511UL, 2411291453UL, 1392810771UL, 3742661504UL, 1900815804UL, 237536256UL, 3719529323UL, 2106191537UL, 3606954134UL, 2108636204UL, 665423205UL, 3702357099UL, 184003599UL, +3319252632UL, 1370913077UL, 3583034472UL, 4262675711UL, 3683661822UL, 3215832318UL, 3463899341UL, 4027471772UL, 3494669542UL, 2262494389UL, 88039196UL, 114405083UL, 3580272354UL, 1060831201UL, 765981248UL, 758357266UL, 2564125377UL, 2592170747UL, 3003279383UL, 3900980822UL, 134031448UL, 2566915950UL, 1722483656UL, 2846863035UL, 2113076217UL, 713587277UL, 3396078039UL, 244197359UL, 2067196130UL, 800324742UL, 652529813UL, 3999083342UL, +2310369213UL, 2321935002UL, 104743736UL, 2647200400UL, 1592194261UL, 1610483859UL, 466892855UL, 552781204UL, 1101851783UL, 3373292799UL, 2617595614UL, 3078568050UL, 1222851809UL, 2731839331UL, 1280366172UL, 808483717UL, 1710937426UL, 942360591UL, 3885758458UL, 2062812458UL, 3260452154UL, 3418446265UL, 1909229999UL, 2677929258UL, 3606729729UL, 341113837UL, 1103324742UL, 2995805883UL, 298794036UL, 957896625UL, 2309730124UL, 675602173UL, +2447513005UL, 2531109351UL, 1920936462UL, 2268824429UL, 1509959171UL, 2751142611UL, 1376226240UL, 3667482110UL, 2745634237UL, 2447143807UL, 3724189478UL, 4217864690UL, 47671552UL, 2787057737UL, 2821422976UL, 2144136371UL, 1655126430UL, 3453916724UL, 339095616UL, 3665277070UL, 2959496542UL, 2560819344UL, 52639671UL, 3200765881UL, 2817859210UL, 2367743540UL, 2964928555UL, 4226359627UL, 3206913703UL, 2856219617UL, 2006751422UL, 2994063945UL, +3146629795UL, 1042016834UL, 3176479073UL, 1529794973UL, 1156556441UL, 3690317172UL, 171871257UL, 97899274UL, 2005599428UL, 4134172918UL, 2922802573UL, 1501051393UL, 1492426675UL, 2664982078UL, 3225369425UL, 3200455006UL, 1356823782UL, 2275640124UL, 2623711877UL, 1927023103UL, 572959294UL, 319456586UL, 1036984002UL, 3510199782UL, 4187195325UL, 3627831667UL, 3026392291UL, 1827895694UL, 1978730938UL, 776552069UL, 684550924UL, 2862336749UL, +3493571621UL, 3273582958UL, 4209077103UL, 14248159UL, 1597498830UL, 211745521UL, 457933823UL, 873419743UL, 4290775093UL, 2990300609UL, 1909994881UL, 1414288023UL, 3574834402UL, 357805142UL, 1957211849UL, 1911700755UL, 2679386897UL, 3977404318UL, 2054677775UL, 1006075205UL, 213019511UL, 2411291453UL, 1392810771UL, 3742661504UL, 1443139437UL, 237536256UL, 3719529323UL, 2106191537UL, 3606954134UL, 2671394121UL, 665423205UL, 3702357099UL, +184003599UL, 3319252632UL, 1632983188UL, 3583034472UL, 4262675711UL, 3683661822UL, 3215832318UL, 4080585934UL, 4027471772UL, 3494669542UL, 2262494389UL, 88039196UL, 677218369UL, 3580272354UL, 1060831201UL, 765981248UL, 758357266UL, 1277026792UL, 2592170747UL, 3003279383UL, 3900980822UL, 134031448UL, 4189207981UL, 1722483656UL, 2846863035UL, 2113076217UL, 713587277UL, 2098603934UL, 244197359UL, 2067196130UL, 800324742UL, 652529813UL, +1307843279UL, 3205610699UL, 1606722715UL, 2749781905UL, 3500078806UL, 320007706UL, 4092615096UL, 608085660UL, 1869480444UL, 459160631UL, 3657609957UL, 1944540526UL, 2184854884UL, 3497113751UL, 2817682182UL, 3367276652UL, 2069300794UL, 1466691974UL, 3078806052UL, 3998756116UL, 2068892089UL, 1789981386UL, 4196184114UL, 4004623319UL, 3029515569UL, 3206332209UL, 3424306963UL, 1805804276UL, 899469644UL, 1149853995UL, 903917909UL, 1185042552UL, +447265042UL, 3579272434UL, 116409560UL, 2211704275UL, 1237721838UL, 3636618157UL, 3191931082UL, 2430339315UL, 3551966793UL, 1533877057UL, 1700891210UL, 3317627852UL, 828148584UL, 1733460943UL, 3866870689UL, 3970886915UL, 1624935507UL, 3236099078UL, 4209593953UL, 1951283095UL, 1579020365UL, 1165668813UL, 1423097998UL, 1294879824UL, 3406063424UL, 3313007028UL, 2090501113UL, 842064167UL, 729587893UL, 2949702260UL, 2099637920UL, 260436310UL, +1056109549UL, 657874983UL, 2734575906UL, 4088958435UL, 3265216971UL, 1081848592UL, 2593212854UL, 4028921684UL, 2868974814UL, 2299228627UL, 49944924UL, 955114665UL, 2844328062UL, 885136505UL, 4262681333UL, 977883895UL, 998890598UL, 2026602293UL, 87852872UL, 2197997810UL, 910583259UL, 3151223623UL, 3960726944UL, 1778982325UL, 3322631234UL, 2940402694UL, 1619768059UL, 1592832128UL, 1434542537UL, 2107314297UL, 1170789408UL, 3357335254UL, +3317662644UL, 1409884338UL, 73741139UL, 1093507243UL, 329113525UL, 4199840577UL, 442295615UL, 3348669654UL, 435948047UL, 1154137005UL, 3151357655UL, 2101029905UL, 2430218233UL, 2474305449UL, 2316834456UL, 1736616135UL, 1575712778UL, 370866908UL, 4256943043UL, 2805503887UL, 1099763491UL, 2473785999UL, 3215573143UL, 472701386UL, 3070116154UL, 3969279119UL, 3331310102UL, 3932945670UL, 1502564397UL, 1294139579UL, 3073834823UL, 3115143551UL, +3602082994UL, 3707103500UL, 2570195094UL, 1268510174UL, 3561337287UL, 112422529UL, 1483304061UL, 3712148969UL, 3729628891UL, 2741131557UL, 4035019342UL, 2395091348UL, 208448216UL, 607199897UL, 4049058939UL, 3463267226UL, 3821711834UL, 1697628853UL, 691151709UL, 3014869414UL, 11610545UL, 3895793639UL, 3019679196UL, 1246664817UL, 753245113UL, 2236232962UL, 4172861179UL, 4030183420UL, 2367787106UL, 2209331085UL, 4170801007UL, 3609895913UL, +}, +{ +930278208UL, 223382535UL, 720499309UL, 2613473585UL, 4173439516UL, 2132019243UL, 468054579UL, 1141433627UL, 1328639101UL, 3222455434UL, 4023859457UL, 892124224UL, 2940688706UL, 2894552260UL, 1595432126UL, 2558709596UL, 2057191226UL, 1116728192UL, 3767370344UL, 1457278707UL, 3171850455UL, 3733161247UL, 149922078UL, 3860652874UL, 743952057UL, 1024625539UL, 3982786483UL, 2077838781UL, 3713742913UL, 2790452624UL, 3014482913UL, 2928857967UL, +476371337UL, 611803300UL, 3000092437UL, 57069608UL, 1554852195UL, 1406780525UL, 2288998898UL, 460131340UL, 3945168588UL, 18495216UL, 547882902UL, 1624966119UL, 2229423551UL, 1492565146UL, 706052879UL, 2733955743UL, 1450476708UL, 2565285196UL, 2491601298UL, 850297175UL, 331472128UL, 3275065709UL, 3154247398UL, 1364512871UL, 1193063601UL, 579449294UL, 4097747196UL, 3572372000UL, 2712499116UL, 1172861307UL, 3964137156UL, 1300564854UL, +1057993198UL, 2785733262UL, 3548277076UL, 2572944411UL, 3299232577UL, 2031854568UL, 2468534978UL, 602097973UL, 2068619195UL, 2639336890UL, 1694467033UL, 1581263823UL, 809076686UL, 2892861850UL, 4042078087UL, 3178152001UL, 706023882UL, 3236709493UL, 3603158102UL, 2575690800UL, 2831218686UL, 2492604085UL, 207296828UL, 1561595438UL, 2961967115UL, 3304283504UL, 835276604UL, 3005485731UL, 58946395UL, 3979071161UL, 1560535337UL, 2679058432UL, +1061627241UL, 1142692919UL, 1476802977UL, 1306619165UL, 1297953898UL, 4282928317UL, 3630719944UL, 2305895643UL, 2656730970UL, 916308118UL, 4160016206UL, 3541795573UL, 4222235077UL, 1289754532UL, 1963633184UL, 3595798857UL, 2273299603UL, 1687478595UL, 2249344966UL, 2267127964UL, 2201115693UL, 917609614UL, 3731921025UL, 1634893875UL, 3039440017UL, 1122674005UL, 2906728840UL, 921166852UL, 3525309936UL, 633872502UL, 821930665UL, 3861074060UL, +3309559821UL, 304858441UL, 1530517912UL, 1140212033UL, 3168869568UL, 3223449972UL, 1343718360UL, 2831361172UL, 1723616626UL, 3675867172UL, 2586694335UL, 2374941766UL, 387033391UL, 1528180036UL, 1561421035UL, 2735360720UL, 3952587140UL, 13543969UL, 3987997725UL, 4273177532UL, 2200558169UL, 461920718UL, 459441276UL, 4225054447UL, 2248193798UL, 1103878063UL, 3027778665UL, 1844457031UL, 1364117386UL, 1575430424UL, 2276483962UL, 2665252582UL, +1572038262UL, 930278208UL, 223382535UL, 720499309UL, 2613473585UL, 4025056228UL, 2132019243UL, 468054579UL, 1141433627UL, 1328639101UL, 304940359UL, 4023859457UL, 892124224UL, 2940688706UL, 2894552260UL, 2006939659UL, 2558709596UL, 2057191226UL, 1116728192UL, 3767370344UL, 3026555841UL, 3171850455UL, 3733161247UL, 149922078UL, 3860652874UL, 2068299929UL, 1024625539UL, 3982786483UL, 2077838781UL, 3713742913UL, 2512419366UL, 3014482913UL, +2928857967UL, 476371337UL, 611803300UL, 259065762UL, 57069608UL, 1554852195UL, 1406780525UL, 2288998898UL, 2261401631UL, 3945168588UL, 18495216UL, 547882902UL, 1624966119UL, 3049748661UL, 1492565146UL, 706052879UL, 2733955743UL, 1450476708UL, 910808481UL, 2491601298UL, 850297175UL, 331472128UL, 3275065709UL, 3877736250UL, 1364512871UL, 1193063601UL, 579449294UL, 4097747196UL, 3029512053UL, 2712499116UL, 1172861307UL, 3964137156UL, +1300564854UL, 2398462790UL, 2785733262UL, 3548277076UL, 2572944411UL, 3299232577UL, 3497485227UL, 2468534978UL, 602097973UL, 2068619195UL, 2639336890UL, 4271191874UL, 1581263823UL, 809076686UL, 2892861850UL, 4042078087UL, 3046259144UL, 706023882UL, 3236709493UL, 3603158102UL, 2575690800UL, 591682100UL, 2492604085UL, 207296828UL, 1561595438UL, 2961967115UL, 3885379584UL, 835276604UL, 3005485731UL, 58946395UL, 3979071161UL, 2784795951UL, +2679058432UL, 1061627241UL, 1142692919UL, 1476802977UL, 2864266022UL, 1297953898UL, 4282928317UL, 3630719944UL, 2305895643UL, 3374260620UL, 916308118UL, 4160016206UL, 3541795573UL, 4222235077UL, 3025355241UL, 1963633184UL, 3595798857UL, 2273299603UL, 1687478595UL, 4115795122UL, 2267127964UL, 2201115693UL, 917609614UL, 3731921025UL, 2905712346UL, 3039440017UL, 1122674005UL, 2906728840UL, 921166852UL, 2881663141UL, 633872502UL, 821930665UL, +3861074060UL, 3309559821UL, 2816533968UL, 1530517912UL, 1140212033UL, 3168869568UL, 3223449972UL, 1894667948UL, 2831361172UL, 1723616626UL, 3675867172UL, 2586694335UL, 3974041178UL, 387033391UL, 1528180036UL, 1561421035UL, 2735360720UL, 2014321457UL, 13543969UL, 3987997725UL, 4273177532UL, 2200558169UL, 2259553303UL, 459441276UL, 4225054447UL, 2248193798UL, 1103878063UL, 3889361594UL, 1844457031UL, 1364117386UL, 1575430424UL, 2276483962UL, +3302182736UL, 1572038262UL, 930278208UL, 223382535UL, 720499309UL, 4173186621UL, 4025056228UL, 2132019243UL, 468054579UL, 1141433627UL, 2396654717UL, 304940359UL, 4023859457UL, 892124224UL, 2940688706UL, 2903529759UL, 2006939659UL, 2558709596UL, 2057191226UL, 1116728192UL, 715931354UL, 3026555841UL, 3171850455UL, 3733161247UL, 149922078UL, 3342675578UL, 2068299929UL, 1024625539UL, 3982786483UL, 2077838781UL, 1157097180UL, 2512419366UL, +3014482913UL, 2928857967UL, 476371337UL, 2192872017UL, 259065762UL, 57069608UL, 1554852195UL, 1406780525UL, 4165039782UL, 2261401631UL, 3945168588UL, 18495216UL, 547882902UL, 2453072030UL, 3049748661UL, 1492565146UL, 706052879UL, 2733955743UL, 2233423433UL, 910808481UL, 2491601298UL, 850297175UL, 331472128UL, 1154483111UL, 3877736250UL, 1364512871UL, 1193063601UL, 579449294UL, 690173400UL, 3029512053UL, 2712499116UL, 1172861307UL, +3964137156UL, 2683130322UL, 2398462790UL, 2785733262UL, 3548277076UL, 2572944411UL, 4075824857UL, 3497485227UL, 2468534978UL, 602097973UL, 2068619195UL, 2711665545UL, 4271191874UL, 1581263823UL, 809076686UL, 2892861850UL, 3558962856UL, 3046259144UL, 706023882UL, 3236709493UL, 3603158102UL, 274706518UL, 591682100UL, 2492604085UL, 207296828UL, 1561595438UL, 1532885415UL, 3885379584UL, 835276604UL, 3005485731UL, 58946395UL, 4143205928UL, +2784795951UL, 2679058432UL, 1061627241UL, 1142692919UL, 2539503297UL, 2864266022UL, 1297953898UL, 4282928317UL, 3630719944UL, 3333189589UL, 3374260620UL, 916308118UL, 4160016206UL, 3541795573UL, 1771535488UL, 3025355241UL, 1963633184UL, 3595798857UL, 2273299603UL, 1735171204UL, 4115795122UL, 2267127964UL, 2201115693UL, 917609614UL, 4220503034UL, 2905712346UL, 3039440017UL, 1122674005UL, 2906728840UL, 868453017UL, 2881663141UL, 633872502UL, +821930665UL, 3861074060UL, 1928586970UL, 2816533968UL, 1530517912UL, 1140212033UL, 3168869568UL, 1082127627UL, 1894667948UL, 2831361172UL, 1723616626UL, 3675867172UL, 496773835UL, 3974041178UL, 387033391UL, 1528180036UL, 1561421035UL, 2763161987UL, 2014321457UL, 13543969UL, 3987997725UL, 4273177532UL, 2110570579UL, 2259553303UL, 459441276UL, 4225054447UL, 2248193798UL, 53021618UL, 3889361594UL, 1844457031UL, 1364117386UL, 1575430424UL, +1105247032UL, 3302182736UL, 1572038262UL, 930278208UL, 223382535UL, 2159964170UL, 4173186621UL, 4025056228UL, 2132019243UL, 468054579UL, 1397544344UL, 2396654717UL, 304940359UL, 4023859457UL, 892124224UL, 2800429255UL, 2903529759UL, 2006939659UL, 2558709596UL, 2057191226UL, 296054924UL, 715931354UL, 3026555841UL, 3171850455UL, 3733161247UL, 863280930UL, 3342675578UL, 2068299929UL, 1024625539UL, 3982786483UL, 949122664UL, 1157097180UL, +2512419366UL, 3014482913UL, 2928857967UL, 2585465463UL, 2192872017UL, 259065762UL, 57069608UL, 1554852195UL, 3650462338UL, 4165039782UL, 2261401631UL, 3945168588UL, 18495216UL, 524715648UL, 2453072030UL, 3049748661UL, 1492565146UL, 706052879UL, 123143857UL, 2233423433UL, 910808481UL, 2491601298UL, 850297175UL, 3272095697UL, 1154483111UL, 3877736250UL, 1364512871UL, 1193063601UL, 2394240337UL, 690173400UL, 3029512053UL, 2712499116UL, +1172861307UL, 598335483UL, 2683130322UL, 2398462790UL, 2785733262UL, 3548277076UL, 678275336UL, 4075824857UL, 3497485227UL, 2468534978UL, 602097973UL, 1861912463UL, 2711665545UL, 4271191874UL, 1581263823UL, 809076686UL, 3324887617UL, 3558962856UL, 3046259144UL, 706023882UL, 3236709493UL, 1776103512UL, 274706518UL, 591682100UL, 2492604085UL, 207296828UL, 1739697610UL, 1532885415UL, 3885379584UL, 835276604UL, 3005485731UL, 2931144546UL, +4143205928UL, 2784795951UL, 2679058432UL, 1061627241UL, 1487949699UL, 2539503297UL, 2864266022UL, 1297953898UL, 4282928317UL, 4101955339UL, 3333189589UL, 3374260620UL, 916308118UL, 4160016206UL, 376029432UL, 1771535488UL, 3025355241UL, 1963633184UL, 3595798857UL, 2826786027UL, 1735171204UL, 4115795122UL, 2267127964UL, 2201115693UL, 2572535497UL, 4220503034UL, 2905712346UL, 3039440017UL, 1122674005UL, 2482828099UL, 868453017UL, 2881663141UL, +633872502UL, 821930665UL, 2579406681UL, 1928586970UL, 2816533968UL, 1530517912UL, 1140212033UL, 2547368381UL, 1082127627UL, 1894667948UL, 2831361172UL, 1723616626UL, 1903980411UL, 496773835UL, 3974041178UL, 387033391UL, 1528180036UL, 2681142643UL, 2763161987UL, 2014321457UL, 13543969UL, 3987997725UL, 2583502227UL, 2110570579UL, 2259553303UL, 459441276UL, 4225054447UL, 177868402UL, 53021618UL, 3889361594UL, 1844457031UL, 1364117386UL, +2369166739UL, 240269378UL, 689700242UL, 297384154UL, 1052178701UL, 2154172820UL, 614713903UL, 3000863907UL, 3916962502UL, 94341217UL, 2609111975UL, 1621831476UL, 4260159710UL, 694869580UL, 1708268072UL, 2751452128UL, 3843916827UL, 3400387883UL, 2394104046UL, 2348934617UL, 3263438569UL, 3818556032UL, 1695621950UL, 410888855UL, 347231182UL, 612084657UL, 1858306225UL, 3024940417UL, 2482215564UL, 2728249904UL, 2825132299UL, 329106327UL, +3333110741UL, 2742025573UL, 2947035922UL, 3758718780UL, 2191527983UL, 864130510UL, 2586839659UL, 662702978UL, 817620197UL, 2888275812UL, 3372817000UL, 2982240654UL, 2211025418UL, 2043458594UL, 498221898UL, 1559803796UL, 209509183UL, 3004637012UL, 2204871924UL, 2445352606UL, 4026842262UL, 3211433366UL, 3533095828UL, 4172447076UL, 865408944UL, 2797639687UL, 3201749441UL, 1286664278UL, 1158271235UL, 2641361834UL, 4261559289UL, 3643706696UL, +2017210420UL, 2067296744UL, 3548126272UL, 3846378526UL, 3885857009UL, 3013926193UL, 368948443UL, 3839554625UL, 2032663713UL, 4185819024UL, 4279332940UL, 137321733UL, 3515190288UL, 4281845500UL, 2738024944UL, 3350239126UL, 1456676856UL, 1246688651UL, 2478709188UL, 12570320UL, 989306366UL, 2347610707UL, 2849134988UL, 2351681449UL, 4063448910UL, 1193872626UL, 3645565330UL, 1863134777UL, 1345198234UL, 2504863006UL, 3815974850UL, 3075495578UL, +2400383333UL, 2727346254UL, 985812393UL, 1432182882UL, 3668977714UL, 231840487UL, 647229148UL, 274547428UL, 2856186783UL, 1273158535UL, 900081267UL, 1566366419UL, 562584841UL, 2247144789UL, 3522587233UL, 1686032132UL, 586483076UL, 1207387616UL, 3040778905UL, 2532774045UL, 3681992451UL, 1034866888UL, 4029685195UL, 3307070989UL, 2412903766UL, 3156200186UL, 2625083166UL, 4148004113UL, 1756566287UL, 2319065855UL, 2924909429UL, 3050022486UL, +2464491722UL, 1137782196UL, 2749457821UL, 790410752UL, 3511746957UL, 2277733721UL, 2871407058UL, 3858561909UL, 2176119631UL, 952943025UL, 2987154266UL, 120799539UL, 2862346597UL, 3689389598UL, 3329995989UL, 715438735UL, 1035277216UL, 3079684809UL, 677298106UL, 2364292665UL, 4110165256UL, 4096954153UL, 356732100UL, 2361282903UL, 4050817284UL, 2010946835UL, 1824397679UL, 4087204231UL, 4178036725UL, 4197370951UL, 503070461UL, 1879838906UL, +}, +{ +4117851084UL, 2941903397UL, 1156439261UL, 1922510465UL, 2925632294UL, 2272105738UL, 641404242UL, 3414739418UL, 2602896978UL, 672876430UL, 1998875331UL, 1325970749UL, 1633717408UL, 3567722815UL, 2088144733UL, 95705225UL, 580635702UL, 3543633503UL, 1469889369UL, 239816045UL, 2254984383UL, 1632695776UL, 2033839470UL, 4117902893UL, 509938588UL, 1291002316UL, 3600816069UL, 2962644092UL, 4269959520UL, 3161890066UL, 1908855486UL, 1177948589UL, +473118979UL, 3205649854UL, 2027137481UL, 227656706UL, 1485922673UL, 3380103860UL, 2080286336UL, 2588604114UL, 1727893393UL, 3602757903UL, 3126385963UL, 2101893784UL, 3058515017UL, 833779022UL, 719369683UL, 3768029740UL, 1123855192UL, 2580550821UL, 3694463505UL, 1137588651UL, 1724433728UL, 3847324234UL, 2368689516UL, 1226895255UL, 1126753016UL, 2557024841UL, 3187601018UL, 3790080711UL, 2423256074UL, 2463913828UL, 1753321774UL, 1621519784UL, +3456900204UL, 3550875802UL, 3783120790UL, 2740104077UL, 2010858632UL, 1569277627UL, 1492853575UL, 2182681191UL, 3866043645UL, 2566155095UL, 770150438UL, 2482504045UL, 3916834400UL, 222960658UL, 342285296UL, 3354506276UL, 1371039946UL, 3717269950UL, 3632913684UL, 2557531969UL, 3934379214UL, 1732115898UL, 1598596195UL, 1180866173UL, 3526785234UL, 2740387380UL, 3540138766UL, 338607286UL, 3262593182UL, 2413619772UL, 2248013920UL, 3557851982UL, +2470276596UL, 1549877186UL, 447909575UL, 4010548064UL, 282941857UL, 3418249797UL, 3300699992UL, 1957423733UL, 2615274674UL, 370155667UL, 1109991145UL, 933065597UL, 3947818943UL, 3221736239UL, 402503017UL, 4016454981UL, 3640556350UL, 243947268UL, 1175418215UL, 2752078014UL, 371928981UL, 3354635500UL, 3471578165UL, 2735623932UL, 445067764UL, 2732367763UL, 3225606514UL, 1214718589UL, 2197756425UL, 2134958042UL, 680726116UL, 3098695319UL, +2103463364UL, 4058022972UL, 2428195541UL, 2433504485UL, 4042288512UL, 2383438250UL, 3821638336UL, 2375226348UL, 806148488UL, 197247918UL, 768984129UL, 412771011UL, 4020619856UL, 3030619444UL, 3242554868UL, 282156707UL, 3718880754UL, 2938924979UL, 4189583150UL, 1604586306UL, 1245779881UL, 4006389745UL, 2437150739UL, 1749517801UL, 2903749036UL, 1247308303UL, 2580023735UL, 2457849017UL, 342934950UL, 216040419UL, 3176519601UL, 4151509434UL, +2404801649UL, 4117851084UL, 2941903397UL, 1156439261UL, 1922510465UL, 14864453UL, 2272105738UL, 641404242UL, 3414739418UL, 2602896978UL, 2179417586UL, 1998875331UL, 1325970749UL, 1633717408UL, 3567722815UL, 428880410UL, 95705225UL, 580635702UL, 3543633503UL, 1469889369UL, 3132946201UL, 2254984383UL, 1632695776UL, 2033839470UL, 4117902893UL, 3029657560UL, 1291002316UL, 3600816069UL, 2962644092UL, 4269959520UL, 397442545UL, 1908855486UL, +1177948589UL, 473118979UL, 3205649854UL, 990384909UL, 227656706UL, 1485922673UL, 3380103860UL, 2080286336UL, 3295033100UL, 1727893393UL, 3602757903UL, 3126385963UL, 2101893784UL, 1132286601UL, 833779022UL, 719369683UL, 3768029740UL, 1123855192UL, 283414013UL, 3694463505UL, 1137588651UL, 1724433728UL, 3847324234UL, 1735742473UL, 1226895255UL, 1126753016UL, 2557024841UL, 3187601018UL, 2090644528UL, 2423256074UL, 2463913828UL, 1753321774UL, +1621519784UL, 1037552449UL, 3550875802UL, 3783120790UL, 2740104077UL, 2010858632UL, 3730461081UL, 1492853575UL, 2182681191UL, 3866043645UL, 2566155095UL, 2782805925UL, 2482504045UL, 3916834400UL, 222960658UL, 342285296UL, 2406892654UL, 1371039946UL, 3717269950UL, 3632913684UL, 2557531969UL, 4071148456UL, 1732115898UL, 1598596195UL, 1180866173UL, 3526785234UL, 1110366522UL, 3540138766UL, 338607286UL, 3262593182UL, 2413619772UL, 995824548UL, +3557851982UL, 2470276596UL, 1549877186UL, 447909575UL, 2962194596UL, 282941857UL, 3418249797UL, 3300699992UL, 1957423733UL, 1859612288UL, 370155667UL, 1109991145UL, 933065597UL, 3947818943UL, 3005912276UL, 402503017UL, 4016454981UL, 3640556350UL, 243947268UL, 2884057401UL, 2752078014UL, 371928981UL, 3354635500UL, 3471578165UL, 908942821UL, 445067764UL, 2732367763UL, 3225606514UL, 1214718589UL, 4104754911UL, 2134958042UL, 680726116UL, +3098695319UL, 2103463364UL, 2946640978UL, 2428195541UL, 2433504485UL, 4042288512UL, 2383438250UL, 1252490765UL, 2375226348UL, 806148488UL, 197247918UL, 768984129UL, 2578888115UL, 4020619856UL, 3030619444UL, 3242554868UL, 282156707UL, 3433259466UL, 2938924979UL, 4189583150UL, 1604586306UL, 1245779881UL, 616758943UL, 2437150739UL, 1749517801UL, 2903749036UL, 1247308303UL, 2722580830UL, 2457849017UL, 342934950UL, 216040419UL, 3176519601UL, +545097903UL, 2404801649UL, 4117851084UL, 2941903397UL, 1156439261UL, 1253296096UL, 14864453UL, 2272105738UL, 641404242UL, 3414739418UL, 2989955985UL, 2179417586UL, 1998875331UL, 1325970749UL, 1633717408UL, 1896726594UL, 428880410UL, 95705225UL, 580635702UL, 3543633503UL, 3294258049UL, 3132946201UL, 2254984383UL, 1632695776UL, 2033839470UL, 829668922UL, 3029657560UL, 1291002316UL, 3600816069UL, 2962644092UL, 715635401UL, 397442545UL, +1908855486UL, 1177948589UL, 473118979UL, 443010703UL, 990384909UL, 227656706UL, 1485922673UL, 3380103860UL, 727464961UL, 3295033100UL, 1727893393UL, 3602757903UL, 3126385963UL, 3020775130UL, 1132286601UL, 833779022UL, 719369683UL, 3768029740UL, 2215591597UL, 283414013UL, 3694463505UL, 1137588651UL, 1724433728UL, 2124955521UL, 1735742473UL, 1226895255UL, 1126753016UL, 2557024841UL, 1719121879UL, 2090644528UL, 2423256074UL, 2463913828UL, +1753321774UL, 1283364713UL, 1037552449UL, 3550875802UL, 3783120790UL, 2740104077UL, 3326764615UL, 3730461081UL, 1492853575UL, 2182681191UL, 3866043645UL, 1353658829UL, 2782805925UL, 2482504045UL, 3916834400UL, 222960658UL, 2681616579UL, 2406892654UL, 1371039946UL, 3717269950UL, 3632913684UL, 2373372484UL, 4071148456UL, 1732115898UL, 1598596195UL, 1180866173UL, 3787873944UL, 1110366522UL, 3540138766UL, 338607286UL, 3262593182UL, 1714619779UL, +995824548UL, 3557851982UL, 2470276596UL, 1549877186UL, 2342751414UL, 2962194596UL, 282941857UL, 3418249797UL, 3300699992UL, 2080590834UL, 1859612288UL, 370155667UL, 1109991145UL, 933065597UL, 4126279826UL, 3005912276UL, 402503017UL, 4016454981UL, 3640556350UL, 618040940UL, 2884057401UL, 2752078014UL, 371928981UL, 3354635500UL, 2952377979UL, 908942821UL, 445067764UL, 2732367763UL, 3225606514UL, 935181950UL, 4104754911UL, 2134958042UL, +680726116UL, 3098695319UL, 652514936UL, 2946640978UL, 2428195541UL, 2433504485UL, 4042288512UL, 1834165243UL, 1252490765UL, 2375226348UL, 806148488UL, 197247918UL, 1459523569UL, 2578888115UL, 4020619856UL, 3030619444UL, 3242554868UL, 2222750155UL, 3433259466UL, 2938924979UL, 4189583150UL, 1604586306UL, 400149547UL, 616758943UL, 2437150739UL, 1749517801UL, 2903749036UL, 571531698UL, 2722580830UL, 2457849017UL, 342934950UL, 216040419UL, +3302138698UL, 545097903UL, 2404801649UL, 4117851084UL, 2941903397UL, 2926001994UL, 1253296096UL, 14864453UL, 2272105738UL, 641404242UL, 2446601571UL, 2989955985UL, 2179417586UL, 1998875331UL, 1325970749UL, 2470418771UL, 1896726594UL, 428880410UL, 95705225UL, 580635702UL, 95529058UL, 3294258049UL, 3132946201UL, 2254984383UL, 1632695776UL, 3381575123UL, 829668922UL, 3029657560UL, 1291002316UL, 3600816069UL, 332821128UL, 715635401UL, +397442545UL, 1908855486UL, 1177948589UL, 3324147260UL, 443010703UL, 990384909UL, 227656706UL, 1485922673UL, 3468390490UL, 727464961UL, 3295033100UL, 1727893393UL, 3602757903UL, 3849734062UL, 3020775130UL, 1132286601UL, 833779022UL, 719369683UL, 3336941985UL, 2215591597UL, 283414013UL, 3694463505UL, 1137588651UL, 1245145305UL, 2124955521UL, 1735742473UL, 1226895255UL, 1126753016UL, 1536376839UL, 1719121879UL, 2090644528UL, 2423256074UL, +2463913828UL, 4035794571UL, 1283364713UL, 1037552449UL, 3550875802UL, 3783120790UL, 4233012781UL, 3326764615UL, 3730461081UL, 1492853575UL, 2182681191UL, 654850701UL, 1353658829UL, 2782805925UL, 2482504045UL, 3916834400UL, 1556782509UL, 2681616579UL, 2406892654UL, 1371039946UL, 3717269950UL, 1227526114UL, 2373372484UL, 4071148456UL, 1732115898UL, 1598596195UL, 1777009717UL, 3787873944UL, 1110366522UL, 3540138766UL, 338607286UL, 1161080599UL, +1714619779UL, 995824548UL, 3557851982UL, 2470276596UL, 3162659171UL, 2342751414UL, 2962194596UL, 282941857UL, 3418249797UL, 1032034511UL, 2080590834UL, 1859612288UL, 370155667UL, 1109991145UL, 2568097099UL, 4126279826UL, 3005912276UL, 402503017UL, 4016454981UL, 3196575353UL, 618040940UL, 2884057401UL, 2752078014UL, 371928981UL, 4223799564UL, 2952377979UL, 908942821UL, 445067764UL, 2732367763UL, 174723563UL, 935181950UL, 4104754911UL, +2134958042UL, 680726116UL, 649687363UL, 652514936UL, 2946640978UL, 2428195541UL, 2433504485UL, 3735735592UL, 1834165243UL, 1252490765UL, 2375226348UL, 806148488UL, 3720638976UL, 1459523569UL, 2578888115UL, 4020619856UL, 3030619444UL, 283333114UL, 2222750155UL, 3433259466UL, 2938924979UL, 4189583150UL, 870522428UL, 400149547UL, 616758943UL, 2437150739UL, 1749517801UL, 999295363UL, 571531698UL, 2722580830UL, 2457849017UL, 342934950UL, +3151292467UL, 2839665217UL, 2452261456UL, 208520727UL, 2269948412UL, 344787478UL, 3987474076UL, 3770524881UL, 2718719281UL, 2537804795UL, 850790212UL, 639946566UL, 2073602691UL, 2316769983UL, 3577216077UL, 3538374748UL, 61447995UL, 3718817085UL, 1476398788UL, 3239144530UL, 3595014456UL, 454482110UL, 286330934UL, 2119173159UL, 1693518756UL, 1464218560UL, 1201825197UL, 1112746405UL, 2988579776UL, 1626663767UL, 2236015969UL, 4018896468UL, +1885926862UL, 671386673UL, 1583086162UL, 1114723892UL, 2936863300UL, 2620955107UL, 2628074015UL, 426673611UL, 3370181092UL, 3462245129UL, 3590185736UL, 2630441788UL, 171626554UL, 3647663038UL, 880996914UL, 1155913149UL, 2653278555UL, 508978149UL, 2031872445UL, 3041145171UL, 1339819022UL, 127509725UL, 1336955078UL, 727702092UL, 693349672UL, 999665905UL, 2287631318UL, 961427722UL, 3355851447UL, 821851136UL, 2370998072UL, 4027450519UL, +2054803464UL, 144596514UL, 3295312213UL, 2579322479UL, 2982266864UL, 4275468400UL, 179988815UL, 2123828208UL, 1486957870UL, 2484928010UL, 288096701UL, 1211834301UL, 1819157080UL, 3569000238UL, 4164201803UL, 3042117433UL, 2741571248UL, 3688451311UL, 29376415UL, 437788821UL, 994675658UL, 1014591996UL, 296335443UL, 363551454UL, 2628890394UL, 332401256UL, 2288239762UL, 3766239385UL, 317162173UL, 3721125104UL, 2296650899UL, 56428392UL, +3900411067UL, 2303724992UL, 3735005983UL, 1377320198UL, 612032498UL, 1171213235UL, 2494454628UL, 1894368149UL, 4124860986UL, 1694123597UL, 2306091209UL, 2075278956UL, 3898366152UL, 937522278UL, 32800830UL, 324902076UL, 2365753207UL, 2251160429UL, 1692543836UL, 2920424644UL, 119047416UL, 1821685115UL, 1486296407UL, 3055580738UL, 3711421730UL, 1522703457UL, 1422399573UL, 2515073038UL, 3788816887UL, 3490575947UL, 2395299159UL, 4248373284UL, +3383561277UL, 3128107243UL, 2344292809UL, 1806504793UL, 3087395022UL, 4113720664UL, 2749262038UL, 395148869UL, 1331347439UL, 2682558741UL, 1253966763UL, 4204248490UL, 2083995727UL, 2717069903UL, 4144872894UL, 1857751053UL, 2166276701UL, 1419950839UL, 1145170701UL, 3225260742UL, 211743500UL, 2746391743UL, 3333387219UL, 4115426799UL, 3801457092UL, 3327614811UL, 1460971336UL, 2256342146UL, 3186427137UL, 2684216499UL, 1035644397UL, 2948948308UL, +}, +{ +216975964UL, 4145824263UL, 2147471723UL, 4154469597UL, 161744273UL, 1299764439UL, 3468614543UL, 4190517158UL, 4124232403UL, 754999274UL, 208153182UL, 1442063188UL, 2940825403UL, 729331312UL, 2124186505UL, 1136411459UL, 1083787490UL, 442264548UL, 442338468UL, 464589685UL, 3509461223UL, 4241734851UL, 370778328UL, 4003105058UL, 3163637982UL, 3747133182UL, 1433548371UL, 1876378240UL, 536564977UL, 1171222160UL, 3268902719UL, 2725776746UL, +1547771137UL, 2818791461UL, 4129042013UL, 2677094853UL, 1594765197UL, 1556725424UL, 569252594UL, 2640731848UL, 2947042710UL, 2633188904UL, 1640957370UL, 1806863786UL, 2803403654UL, 2632220187UL, 2740076538UL, 383549855UL, 3211856699UL, 3933793958UL, 1988232112UL, 404006876UL, 1369488120UL, 1963339964UL, 609604643UL, 2488118016UL, 3936354252UL, 1980115609UL, 189069630UL, 860670414UL, 85775513UL, 2447581620UL, 886385122UL, 3047212472UL, +2470718978UL, 4044569663UL, 430717074UL, 1598133481UL, 1905362808UL, 2981511487UL, 1842297666UL, 2992320857UL, 1682119455UL, 1753461544UL, 700013801UL, 3025873251UL, 3413358770UL, 1673092091UL, 113651375UL, 2618875026UL, 1479752146UL, 81598739UL, 1530418117UL, 962911586UL, 778994423UL, 3944331100UL, 4116504755UL, 480712357UL, 1078821437UL, 1091665476UL, 3696871260UL, 2074607518UL, 3226459752UL, 3767432525UL, 768289441UL, 3142741843UL, +2969151790UL, 1814889320UL, 2122849610UL, 451935137UL, 2784993892UL, 1836517944UL, 1565951586UL, 1663606442UL, 1578543925UL, 33407321UL, 1445768530UL, 2156093253UL, 3164165477UL, 3093293932UL, 298945371UL, 2558835427UL, 1386275152UL, 2649603495UL, 893605644UL, 1147537351UL, 1889670166UL, 3203610476UL, 2598985714UL, 966335150UL, 3384227644UL, 2584671737UL, 552770393UL, 2430097209UL, 3085150053UL, 3633667948UL, 1319147485UL, 1999467843UL, +3676133150UL, 2314789604UL, 1443760911UL, 1552954684UL, 2411684219UL, 3708965016UL, 2607719926UL, 484007519UL, 491681421UL, 2498192461UL, 6342020UL, 4226570819UL, 2329860147UL, 1097040622UL, 1270325434UL, 2572535504UL, 918592905UL, 193599782UL, 4223250613UL, 1640082589UL, 1817957216UL, 2937344769UL, 3768793871UL, 2982566292UL, 1607453458UL, 4096207317UL, 696907828UL, 2431936270UL, 627206620UL, 3267100287UL, 1161821973UL, 2322099303UL, +1700245615UL, 216975964UL, 4145824263UL, 2147471723UL, 4154469597UL, 2836499116UL, 1299764439UL, 3468614543UL, 4190517158UL, 4124232403UL, 2176257299UL, 208153182UL, 1442063188UL, 2940825403UL, 729331312UL, 2954254860UL, 1136411459UL, 1083787490UL, 442264548UL, 442338468UL, 3098695824UL, 3509461223UL, 4241734851UL, 370778328UL, 4003105058UL, 2963948505UL, 3747133182UL, 1433548371UL, 1876378240UL, 536564977UL, 1565224991UL, 3268902719UL, +2725776746UL, 1547771137UL, 2818791461UL, 2118790546UL, 2677094853UL, 1594765197UL, 1556725424UL, 569252594UL, 610771792UL, 2947042710UL, 2633188904UL, 1640957370UL, 1806863786UL, 2121022793UL, 2632220187UL, 2740076538UL, 383549855UL, 3211856699UL, 14274926UL, 1988232112UL, 404006876UL, 1369488120UL, 1963339964UL, 1661081792UL, 2488118016UL, 3936354252UL, 1980115609UL, 189069630UL, 595192504UL, 85775513UL, 2447581620UL, 886385122UL, +3047212472UL, 1596069326UL, 4044569663UL, 430717074UL, 1598133481UL, 1905362808UL, 2670961612UL, 1842297666UL, 2992320857UL, 1682119455UL, 1753461544UL, 1121764918UL, 3025873251UL, 3413358770UL, 1673092091UL, 113651375UL, 1721474883UL, 1479752146UL, 81598739UL, 1530418117UL, 962911586UL, 3478535046UL, 3944331100UL, 4116504755UL, 480712357UL, 1078821437UL, 1456786415UL, 3696871260UL, 2074607518UL, 3226459752UL, 3767432525UL, 2947648865UL, +3142741843UL, 2969151790UL, 1814889320UL, 2122849610UL, 3367879697UL, 2784993892UL, 1836517944UL, 1565951586UL, 1663606442UL, 2621366329UL, 33407321UL, 1445768530UL, 2156093253UL, 3164165477UL, 619266142UL, 298945371UL, 2558835427UL, 1386275152UL, 2649603495UL, 97967685UL, 1147537351UL, 1889670166UL, 3203610476UL, 2598985714UL, 504495866UL, 3384227644UL, 2584671737UL, 552770393UL, 2430097209UL, 2168477293UL, 3633667948UL, 1319147485UL, +1999467843UL, 3676133150UL, 2755203144UL, 1443760911UL, 1552954684UL, 2411684219UL, 3708965016UL, 2301846628UL, 484007519UL, 491681421UL, 2498192461UL, 6342020UL, 318325395UL, 2329860147UL, 1097040622UL, 1270325434UL, 2572535504UL, 3458698828UL, 193599782UL, 4223250613UL, 1640082589UL, 1817957216UL, 1861636211UL, 3768793871UL, 2982566292UL, 1607453458UL, 4096207317UL, 1871072589UL, 2431936270UL, 627206620UL, 3267100287UL, 1161821973UL, +3904037207UL, 1700245615UL, 216975964UL, 4145824263UL, 2147471723UL, 2789343849UL, 2836499116UL, 1299764439UL, 3468614543UL, 4190517158UL, 639361502UL, 2176257299UL, 208153182UL, 1442063188UL, 2940825403UL, 2962998954UL, 2954254860UL, 1136411459UL, 1083787490UL, 442264548UL, 1812626669UL, 3098695824UL, 3509461223UL, 4241734851UL, 370778328UL, 1673951193UL, 2963948505UL, 3747133182UL, 1433548371UL, 1876378240UL, 3651623536UL, 1565224991UL, +3268902719UL, 2725776746UL, 1547771137UL, 1938402968UL, 2118790546UL, 2677094853UL, 1594765197UL, 1556725424UL, 3267956202UL, 610771792UL, 2947042710UL, 2633188904UL, 1640957370UL, 1448040688UL, 2121022793UL, 2632220187UL, 2740076538UL, 383549855UL, 300148175UL, 14274926UL, 1988232112UL, 404006876UL, 1369488120UL, 3313508750UL, 1661081792UL, 2488118016UL, 3936354252UL, 1980115609UL, 2631341293UL, 595192504UL, 85775513UL, 2447581620UL, +886385122UL, 2465820467UL, 1596069326UL, 4044569663UL, 430717074UL, 1598133481UL, 4191772516UL, 2670961612UL, 1842297666UL, 2992320857UL, 1682119455UL, 997741285UL, 1121764918UL, 3025873251UL, 3413358770UL, 1673092091UL, 1493832846UL, 1721474883UL, 1479752146UL, 81598739UL, 1530418117UL, 2762019274UL, 3478535046UL, 3944331100UL, 4116504755UL, 480712357UL, 448437372UL, 1456786415UL, 3696871260UL, 2074607518UL, 3226459752UL, 2507199309UL, +2947648865UL, 3142741843UL, 2969151790UL, 1814889320UL, 2268952501UL, 3367879697UL, 2784993892UL, 1836517944UL, 1565951586UL, 377207573UL, 2621366329UL, 33407321UL, 1445768530UL, 2156093253UL, 1325490318UL, 619266142UL, 298945371UL, 2558835427UL, 1386275152UL, 2662699426UL, 97967685UL, 1147537351UL, 1889670166UL, 3203610476UL, 1999783658UL, 504495866UL, 3384227644UL, 2584671737UL, 552770393UL, 1562106652UL, 2168477293UL, 3633667948UL, +1319147485UL, 1999467843UL, 2037219988UL, 2755203144UL, 1443760911UL, 1552954684UL, 2411684219UL, 1579607443UL, 2301846628UL, 484007519UL, 491681421UL, 2498192461UL, 745333677UL, 318325395UL, 2329860147UL, 1097040622UL, 1270325434UL, 208017379UL, 3458698828UL, 193599782UL, 4223250613UL, 1640082589UL, 4049245262UL, 1861636211UL, 3768793871UL, 2982566292UL, 1607453458UL, 2058912455UL, 1871072589UL, 2431936270UL, 627206620UL, 3267100287UL, +1186015034UL, 3904037207UL, 1700245615UL, 216975964UL, 4145824263UL, 2422827462UL, 2789343849UL, 2836499116UL, 1299764439UL, 3468614543UL, 2084839633UL, 639361502UL, 2176257299UL, 208153182UL, 1442063188UL, 4065931048UL, 2962998954UL, 2954254860UL, 1136411459UL, 1083787490UL, 465529524UL, 1812626669UL, 3098695824UL, 3509461223UL, 4241734851UL, 3818602366UL, 1673951193UL, 2963948505UL, 3747133182UL, 1433548371UL, 2475307467UL, 3651623536UL, +1565224991UL, 3268902719UL, 2725776746UL, 2374226870UL, 1938402968UL, 2118790546UL, 2677094853UL, 1594765197UL, 348828658UL, 3267956202UL, 610771792UL, 2947042710UL, 2633188904UL, 1713124265UL, 1448040688UL, 2121022793UL, 2632220187UL, 2740076538UL, 1400362266UL, 300148175UL, 14274926UL, 1988232112UL, 404006876UL, 3662575932UL, 3313508750UL, 1661081792UL, 2488118016UL, 3936354252UL, 3100635752UL, 2631341293UL, 595192504UL, 85775513UL, +2447581620UL, 2417839883UL, 2465820467UL, 1596069326UL, 4044569663UL, 430717074UL, 1093503127UL, 4191772516UL, 2670961612UL, 1842297666UL, 2992320857UL, 3292586028UL, 997741285UL, 1121764918UL, 3025873251UL, 3413358770UL, 222522839UL, 1493832846UL, 1721474883UL, 1479752146UL, 81598739UL, 3132900738UL, 2762019274UL, 3478535046UL, 3944331100UL, 4116504755UL, 3429405501UL, 448437372UL, 1456786415UL, 3696871260UL, 2074607518UL, 1492852861UL, +2507199309UL, 2947648865UL, 3142741843UL, 2969151790UL, 2186889362UL, 2268952501UL, 3367879697UL, 2784993892UL, 1836517944UL, 3169157745UL, 377207573UL, 2621366329UL, 33407321UL, 1445768530UL, 4266168148UL, 1325490318UL, 619266142UL, 298945371UL, 2558835427UL, 1447045944UL, 2662699426UL, 97967685UL, 1147537351UL, 1889670166UL, 3354555370UL, 1999783658UL, 504495866UL, 3384227644UL, 2584671737UL, 2489662408UL, 1562106652UL, 2168477293UL, +3633667948UL, 1319147485UL, 3353555249UL, 2037219988UL, 2755203144UL, 1443760911UL, 1552954684UL, 4137514176UL, 1579607443UL, 2301846628UL, 484007519UL, 491681421UL, 164627749UL, 745333677UL, 318325395UL, 2329860147UL, 1097040622UL, 3587444362UL, 208017379UL, 3458698828UL, 193599782UL, 4223250613UL, 1102471426UL, 4049245262UL, 1861636211UL, 3768793871UL, 2982566292UL, 1941698603UL, 2058912455UL, 1871072589UL, 2431936270UL, 627206620UL, +2511999766UL, 1406946444UL, 1571284360UL, 1416792763UL, 1774410400UL, 1655066897UL, 740531687UL, 2852637013UL, 1574342442UL, 3931672444UL, 2887289502UL, 3588598337UL, 1607795590UL, 1893126336UL, 4113959952UL, 250670029UL, 89330705UL, 2198706475UL, 133060312UL, 4033807246UL, 2161604768UL, 3871950931UL, 1820516188UL, 828316231UL, 3126087794UL, 3740050736UL, 543577819UL, 1589693651UL, 4210480257UL, 3844498352UL, 96010254UL, 2888517657UL, +2931088981UL, 2307454606UL, 2411141663UL, 4193964276UL, 918899600UL, 888509951UL, 3023902229UL, 1371276096UL, 2107726407UL, 3863079906UL, 3849297291UL, 1512401618UL, 3098628219UL, 487705749UL, 492891601UL, 345791371UL, 3230138831UL, 1022138839UL, 974682588UL, 3677932604UL, 2054641860UL, 3303576494UL, 1416653965UL, 1119635666UL, 1907978487UL, 4269977208UL, 2047880336UL, 205698774UL, 2401894999UL, 3253173123UL, 2603439113UL, 1295808319UL, +2965198050UL, 1718424301UL, 1605627562UL, 2860017421UL, 1619060227UL, 1130717786UL, 2992070906UL, 2964091191UL, 3192265220UL, 3860528275UL, 45139953UL, 3914023193UL, 1253834497UL, 3885013544UL, 3793695046UL, 3632364934UL, 4127361980UL, 3323804519UL, 4117285262UL, 4171102020UL, 1863837906UL, 2848174924UL, 1731389076UL, 2514130112UL, 3539384422UL, 2950752200UL, 1138137434UL, 4147328087UL, 3345958235UL, 2305097760UL, 974161669UL, 1739611700UL, +2522036172UL, 1196649816UL, 2395301283UL, 911135539UL, 1029496076UL, 1786766951UL, 1802412425UL, 3485017668UL, 2837835718UL, 1951207514UL, 1447650206UL, 2289702688UL, 2517625074UL, 2408021138UL, 2022522416UL, 719777136UL, 417238676UL, 1865171065UL, 801820378UL, 2836941189UL, 1148226009UL, 1713866138UL, 64608707UL, 1458585813UL, 3581572089UL, 2251042907UL, 1818903516UL, 3278072806UL, 2838874249UL, 2665607605UL, 3360214955UL, 2185961451UL, +410342713UL, 364484774UL, 2887998484UL, 2100888426UL, 1394314931UL, 1362560504UL, 3487221127UL, 3140021092UL, 3168968161UL, 1613267484UL, 290430673UL, 2588210538UL, 2493788232UL, 2641638765UL, 2971195072UL, 2749469779UL, 692014176UL, 3268150742UL, 387451740UL, 461249727UL, 3579417331UL, 3738405845UL, 385445455UL, 1464799053UL, 2786433795UL, 3370371952UL, 675344511UL, 4049011269UL, 2196568686UL, 4166285481UL, 2547135972UL, 119952106UL, +}, +{ +2307933966UL, 145940188UL, 4247815717UL, 2995341855UL, 3245382498UL, 1213200792UL, 232910392UL, 2718014238UL, 918321585UL, 3583102265UL, 3176078796UL, 937696513UL, 266558688UL, 1520650260UL, 3655025189UL, 1653323191UL, 538426778UL, 491545855UL, 4064663509UL, 2788350755UL, 3941259490UL, 3471552693UL, 1851151228UL, 3279627338UL, 845228710UL, 29883500UL, 1503432309UL, 593880175UL, 2488716480UL, 828058076UL, 3287933183UL, 3510981973UL, +3970051135UL, 3803049980UL, 898259836UL, 2890959433UL, 234437380UL, 201835406UL, 1523016285UL, 2419577439UL, 2943482079UL, 4219300984UL, 1490698759UL, 533411805UL, 1644926459UL, 4097374623UL, 265292490UL, 2694560848UL, 285667083UL, 1563945375UL, 3128365011UL, 95277844UL, 2938824634UL, 2717708621UL, 3374928056UL, 3672802273UL, 3445399260UL, 2422205637UL, 1106030557UL, 1269805720UL, 1781057614UL, 3491203689UL, 2454028630UL, 2158698380UL, +2578431870UL, 3540412661UL, 2206372988UL, 3138025266UL, 474100503UL, 3310048546UL, 126856999UL, 3144057206UL, 917199551UL, 3549528813UL, 343855771UL, 391118877UL, 1900257963UL, 1616289477UL, 3663959751UL, 1887891784UL, 697303016UL, 1346369879UL, 3634838543UL, 909311683UL, 3534738830UL, 2676838865UL, 3020679234UL, 1248902118UL, 1517698896UL, 414632197UL, 199589058UL, 2922557451UL, 3915079510UL, 1309075563UL, 3836275459UL, 2549095941UL, +1643088840UL, 1153547003UL, 2254144060UL, 3585420425UL, 915059870UL, 2410951596UL, 1876156254UL, 2384812180UL, 3893647829UL, 4119002503UL, 1535078752UL, 3888310943UL, 1483731374UL, 3915992153UL, 3662664617UL, 1065246672UL, 2307959656UL, 1845927873UL, 2075990232UL, 1346396900UL, 4218283385UL, 3427468026UL, 1518645158UL, 3092538772UL, 3383570452UL, 1317710387UL, 3390054918UL, 4222595168UL, 2468387909UL, 3864538174UL, 2442851586UL, 1858344050UL, +1537617445UL, 1090881039UL, 2055021834UL, 4011332463UL, 2797336692UL, 280272261UL, 3350338577UL, 1682666744UL, 1256176165UL, 2017003515UL, 3666229067UL, 4288064377UL, 3407437449UL, 2957152445UL, 3557139753UL, 4106922773UL, 2612653316UL, 3491950269UL, 1107293753UL, 2926461368UL, 1433860998UL, 1975669351UL, 1680462513UL, 4283282673UL, 168788571UL, 57021447UL, 3888396304UL, 2218068386UL, 2170981202UL, 1587568797UL, 2097820654UL, 1308061343UL, +4096726326UL, 2307933966UL, 145940188UL, 4247815717UL, 2995341855UL, 2894586378UL, 1213200792UL, 232910392UL, 2718014238UL, 918321585UL, 520434726UL, 3176078796UL, 937696513UL, 266558688UL, 1520650260UL, 645408471UL, 1653323191UL, 538426778UL, 491545855UL, 4064663509UL, 2605358672UL, 3941259490UL, 3471552693UL, 1851151228UL, 3279627338UL, 1290188176UL, 29883500UL, 1503432309UL, 593880175UL, 2488716480UL, 1172244224UL, 3287933183UL, +3510981973UL, 3970051135UL, 3803049980UL, 3836242189UL, 2890959433UL, 234437380UL, 201835406UL, 1523016285UL, 1720566850UL, 2943482079UL, 4219300984UL, 1490698759UL, 533411805UL, 982587365UL, 4097374623UL, 265292490UL, 2694560848UL, 285667083UL, 3905392425UL, 3128365011UL, 95277844UL, 2938824634UL, 2717708621UL, 262111126UL, 3672802273UL, 3445399260UL, 2422205637UL, 1106030557UL, 233401560UL, 1781057614UL, 3491203689UL, 2454028630UL, +2158698380UL, 3314008662UL, 3540412661UL, 2206372988UL, 3138025266UL, 474100503UL, 1150191741UL, 126856999UL, 3144057206UL, 917199551UL, 3549528813UL, 84516590UL, 391118877UL, 1900257963UL, 1616289477UL, 3663959751UL, 2831036790UL, 697303016UL, 1346369879UL, 3634838543UL, 909311683UL, 2206291004UL, 2676838865UL, 3020679234UL, 1248902118UL, 1517698896UL, 882506847UL, 199589058UL, 2922557451UL, 3915079510UL, 1309075563UL, 3675129276UL, +2549095941UL, 1643088840UL, 1153547003UL, 2254144060UL, 1702669516UL, 915059870UL, 2410951596UL, 1876156254UL, 2384812180UL, 393602062UL, 4119002503UL, 1535078752UL, 3888310943UL, 1483731374UL, 1135074988UL, 3662664617UL, 1065246672UL, 2307959656UL, 1845927873UL, 883002610UL, 1346396900UL, 4218283385UL, 3427468026UL, 1518645158UL, 1478839081UL, 3383570452UL, 1317710387UL, 3390054918UL, 4222595168UL, 3009846855UL, 3864538174UL, 2442851586UL, +1858344050UL, 1537617445UL, 2419526192UL, 2055021834UL, 4011332463UL, 2797336692UL, 280272261UL, 2937342669UL, 1682666744UL, 1256176165UL, 2017003515UL, 3666229067UL, 3563024742UL, 3407437449UL, 2957152445UL, 3557139753UL, 4106922773UL, 610182860UL, 3491950269UL, 1107293753UL, 2926461368UL, 1433860998UL, 2493047579UL, 1680462513UL, 4283282673UL, 168788571UL, 57021447UL, 2151356582UL, 2218068386UL, 2170981202UL, 1587568797UL, 2097820654UL, +2738927570UL, 4096726326UL, 2307933966UL, 145940188UL, 4247815717UL, 1887236689UL, 2894586378UL, 1213200792UL, 232910392UL, 2718014238UL, 2028538736UL, 520434726UL, 3176078796UL, 937696513UL, 266558688UL, 305624632UL, 645408471UL, 1653323191UL, 538426778UL, 491545855UL, 4188864445UL, 2605358672UL, 3941259490UL, 3471552693UL, 1851151228UL, 1720039364UL, 1290188176UL, 29883500UL, 1503432309UL, 593880175UL, 2595662526UL, 1172244224UL, +3287933183UL, 3510981973UL, 3970051135UL, 2763703998UL, 3836242189UL, 2890959433UL, 234437380UL, 201835406UL, 2652280530UL, 1720566850UL, 2943482079UL, 4219300984UL, 1490698759UL, 1968049758UL, 982587365UL, 4097374623UL, 265292490UL, 2694560848UL, 1165326939UL, 3905392425UL, 3128365011UL, 95277844UL, 2938824634UL, 2521869983UL, 262111126UL, 3672802273UL, 3445399260UL, 2422205637UL, 395183943UL, 233401560UL, 1781057614UL, 3491203689UL, +2454028630UL, 249721174UL, 3314008662UL, 3540412661UL, 2206372988UL, 3138025266UL, 1644439373UL, 1150191741UL, 126856999UL, 3144057206UL, 917199551UL, 1997133400UL, 84516590UL, 391118877UL, 1900257963UL, 1616289477UL, 3843764922UL, 2831036790UL, 697303016UL, 1346369879UL, 3634838543UL, 1901125181UL, 2206291004UL, 2676838865UL, 3020679234UL, 1248902118UL, 344347894UL, 882506847UL, 199589058UL, 2922557451UL, 3915079510UL, 2919277604UL, +3675129276UL, 2549095941UL, 1643088840UL, 1153547003UL, 3305575634UL, 1702669516UL, 915059870UL, 2410951596UL, 1876156254UL, 1416053196UL, 393602062UL, 4119002503UL, 1535078752UL, 3888310943UL, 3993632377UL, 1135074988UL, 3662664617UL, 1065246672UL, 2307959656UL, 1044670394UL, 883002610UL, 1346396900UL, 4218283385UL, 3427468026UL, 1792832168UL, 1478839081UL, 3383570452UL, 1317710387UL, 3390054918UL, 1596709924UL, 3009846855UL, 3864538174UL, +2442851586UL, 1858344050UL, 2428482265UL, 2419526192UL, 2055021834UL, 4011332463UL, 2797336692UL, 424213503UL, 2937342669UL, 1682666744UL, 1256176165UL, 2017003515UL, 717473071UL, 3563024742UL, 3407437449UL, 2957152445UL, 3557139753UL, 3319575432UL, 610182860UL, 3491950269UL, 1107293753UL, 2926461368UL, 3052637648UL, 2493047579UL, 1680462513UL, 4283282673UL, 168788571UL, 1401253163UL, 2151356582UL, 2218068386UL, 2170981202UL, 1587568797UL, +3994937670UL, 2738927570UL, 4096726326UL, 2307933966UL, 145940188UL, 3928146647UL, 1887236689UL, 2894586378UL, 1213200792UL, 232910392UL, 833120806UL, 2028538736UL, 520434726UL, 3176078796UL, 937696513UL, 3704968451UL, 305624632UL, 645408471UL, 1653323191UL, 538426778UL, 939335571UL, 4188864445UL, 2605358672UL, 3941259490UL, 3471552693UL, 2168499975UL, 1720039364UL, 1290188176UL, 29883500UL, 1503432309UL, 524387655UL, 2595662526UL, +1172244224UL, 3287933183UL, 3510981973UL, 2444664749UL, 2763703998UL, 3836242189UL, 2890959433UL, 234437380UL, 3272987579UL, 2652280530UL, 1720566850UL, 2943482079UL, 4219300984UL, 1045589319UL, 1968049758UL, 982587365UL, 4097374623UL, 265292490UL, 1077412791UL, 1165326939UL, 3905392425UL, 3128365011UL, 95277844UL, 2896038035UL, 2521869983UL, 262111126UL, 3672802273UL, 3445399260UL, 4273256145UL, 395183943UL, 233401560UL, 1781057614UL, +3491203689UL, 8343453UL, 249721174UL, 3314008662UL, 3540412661UL, 2206372988UL, 3738630867UL, 1644439373UL, 1150191741UL, 126856999UL, 3144057206UL, 65169501UL, 1997133400UL, 84516590UL, 391118877UL, 1900257963UL, 2914085557UL, 3843764922UL, 2831036790UL, 697303016UL, 1346369879UL, 2007568079UL, 1901125181UL, 2206291004UL, 2676838865UL, 3020679234UL, 2097032931UL, 344347894UL, 882506847UL, 199589058UL, 2922557451UL, 3740400148UL, +2919277604UL, 3675129276UL, 2549095941UL, 1643088840UL, 199560818UL, 3305575634UL, 1702669516UL, 915059870UL, 2410951596UL, 117939268UL, 1416053196UL, 393602062UL, 4119002503UL, 1535078752UL, 4281599711UL, 3993632377UL, 1135074988UL, 3662664617UL, 1065246672UL, 2854253374UL, 1044670394UL, 883002610UL, 1346396900UL, 4218283385UL, 803910659UL, 1792832168UL, 1478839081UL, 3383570452UL, 1317710387UL, 1311168874UL, 1596709924UL, 3009846855UL, +3864538174UL, 2442851586UL, 1967982878UL, 2428482265UL, 2419526192UL, 2055021834UL, 4011332463UL, 2725198749UL, 424213503UL, 2937342669UL, 1682666744UL, 1256176165UL, 713350501UL, 717473071UL, 3563024742UL, 3407437449UL, 2957152445UL, 2363682828UL, 3319575432UL, 610182860UL, 3491950269UL, 1107293753UL, 3429638328UL, 3052637648UL, 2493047579UL, 1680462513UL, 4283282673UL, 2672311163UL, 1401253163UL, 2151356582UL, 2218068386UL, 2170981202UL, +431601500UL, 4193143261UL, 2985267149UL, 1556712183UL, 4135181832UL, 285960576UL, 81711096UL, 57066962UL, 2646151573UL, 3692824605UL, 485132216UL, 2799654118UL, 903527523UL, 1210637484UL, 3195346614UL, 599540837UL, 1410108963UL, 3723542120UL, 1350764011UL, 1717225239UL, 239736775UL, 3946934722UL, 420024332UL, 589304817UL, 1331122625UL, 4294403247UL, 2009397371UL, 844641869UL, 166387728UL, 4093361096UL, 2342369656UL, 3958170613UL, +1660376297UL, 1259528150UL, 4240809115UL, 2875563845UL, 2613790323UL, 2869665108UL, 1414690635UL, 944649070UL, 3539368342UL, 199532147UL, 2707660205UL, 2258475730UL, 771169023UL, 158544851UL, 588872178UL, 2002019277UL, 4225148852UL, 641266809UL, 2133909450UL, 330112418UL, 1815776319UL, 1949213618UL, 3868452239UL, 2702722715UL, 2491030937UL, 468812562UL, 3226259052UL, 199165016UL, 436679774UL, 881956108UL, 1098105661UL, 68909298UL, +248572829UL, 339224422UL, 553849953UL, 3054752668UL, 701934162UL, 1898925107UL, 749060575UL, 987950022UL, 4040401060UL, 684345838UL, 3449205676UL, 2583450513UL, 433795092UL, 3559011048UL, 293161429UL, 3947766299UL, 3491895171UL, 1651265910UL, 1216468759UL, 1625512737UL, 412235874UL, 893680794UL, 2582820523UL, 1514322840UL, 2348781204UL, 2720801933UL, 3364999370UL, 2822073391UL, 2627166519UL, 3805500773UL, 177760590UL, 2210728920UL, +3136345252UL, 3226658259UL, 3982978003UL, 86264452UL, 536816704UL, 3489051867UL, 2161950016UL, 1375640747UL, 4116957650UL, 3676292350UL, 3001078542UL, 1379688752UL, 3059678152UL, 3740664918UL, 475697670UL, 539253230UL, 1256048653UL, 3819847913UL, 141216227UL, 3888391528UL, 3567424851UL, 4131097532UL, 2142453586UL, 3606575354UL, 3689715433UL, 2318212425UL, 3026095399UL, 2451038695UL, 4052322172UL, 1861782452UL, 3032216562UL, 4078403318UL, +2636775961UL, 2188864067UL, 3276459319UL, 2230349722UL, 3939784264UL, 831216291UL, 2483460713UL, 2571551493UL, 484276565UL, 3173595164UL, 4177831244UL, 4132249231UL, 2116763555UL, 1420812998UL, 2121017321UL, 2855491215UL, 1630144518UL, 2489688364UL, 411521312UL, 3713786536UL, 4177871972UL, 690465497UL, 855092147UL, 4271606539UL, 1265108699UL, 3757106624UL, 3151574897UL, 670335437UL, 3099376310UL, 3946436509UL, 1795346235UL, 4013409945UL, +}, +{ +650684252UL, 2220445579UL, 537394374UL, 571322423UL, 2781663439UL, 899394682UL, 364129622UL, 328438826UL, 1219862153UL, 830435885UL, 3278649457UL, 3072225531UL, 2838645991UL, 3150905380UL, 1251952499UL, 1751415553UL, 2034088483UL, 1437197870UL, 1907624878UL, 1786974150UL, 4207811086UL, 768131803UL, 2713210999UL, 4004509777UL, 3510764535UL, 2740991637UL, 3000313526UL, 1355959320UL, 938244439UL, 4093313692UL, 2476002145UL, 835527260UL, +2084758949UL, 4223775017UL, 91645393UL, 2251723899UL, 3159477758UL, 2008655575UL, 912220875UL, 1525327655UL, 2067948386UL, 2006141522UL, 450235614UL, 3945671083UL, 2852189452UL, 3804118704UL, 3302604345UL, 1712745267UL, 349281154UL, 19331179UL, 3423301791UL, 416995358UL, 2049170698UL, 684574142UL, 3271042138UL, 3438668017UL, 1645378852UL, 1995123150UL, 1835887948UL, 2347182898UL, 3828432892UL, 3710259931UL, 713144773UL, 3246285450UL, +2196135622UL, 1611287338UL, 2845388948UL, 3690657633UL, 2403178686UL, 2946296994UL, 2180908599UL, 3072014497UL, 3436535724UL, 2948908116UL, 3080353236UL, 1669938872UL, 3572731079UL, 1100892983UL, 308060688UL, 3092946261UL, 2725115972UL, 887278263UL, 991869336UL, 3597899723UL, 3454505181UL, 1108269267UL, 851855066UL, 1940998002UL, 3539084542UL, 3102161424UL, 965450940UL, 1942363226UL, 1430246588UL, 1368971075UL, 4251556311UL, 642683738UL, +3035789355UL, 1829444044UL, 4234626091UL, 671403403UL, 2809844786UL, 2251172733UL, 970188857UL, 3910072565UL, 1131847479UL, 3397535176UL, 3290884849UL, 861868157UL, 2811422184UL, 3280310458UL, 3502085520UL, 1499698865UL, 2446269873UL, 236680785UL, 1896103604UL, 1179896471UL, 83960622UL, 3303129336UL, 1191373247UL, 177898275UL, 3077388457UL, 1022975703UL, 2535144448UL, 8680269UL, 3602435630UL, 1810825915UL, 2293529378UL, 2307085218UL, +483894148UL, 2872435038UL, 2043868156UL, 3038491874UL, 3786518530UL, 3606440668UL, 3336713377UL, 120183042UL, 86901386UL, 2233164457UL, 2881782972UL, 3135264768UL, 2294460421UL, 2996668315UL, 658184098UL, 3558825846UL, 2386173040UL, 1950463910UL, 551627788UL, 2464303444UL, 893474565UL, 3277869222UL, 2852725906UL, 1191310725UL, 2398932683UL, 4164956002UL, 1689291769UL, 2619288187UL, 3429362702UL, 3205668166UL, 1668126623UL, 955771270UL, +2106753333UL, 650684252UL, 2220445579UL, 537394374UL, 571322423UL, 2369694095UL, 899394682UL, 364129622UL, 328438826UL, 1219862153UL, 4195985755UL, 3278649457UL, 3072225531UL, 2838645991UL, 3150905380UL, 2389919UL, 1751415553UL, 2034088483UL, 1437197870UL, 1907624878UL, 1516966376UL, 4207811086UL, 768131803UL, 2713210999UL, 4004509777UL, 1955929377UL, 2740991637UL, 3000313526UL, 1355959320UL, 938244439UL, 4263287583UL, 2476002145UL, +835527260UL, 2084758949UL, 4223775017UL, 110659216UL, 2251723899UL, 3159477758UL, 2008655575UL, 912220875UL, 2378803214UL, 2067948386UL, 2006141522UL, 450235614UL, 3945671083UL, 4112321452UL, 3804118704UL, 3302604345UL, 1712745267UL, 349281154UL, 3834044005UL, 3423301791UL, 416995358UL, 2049170698UL, 684574142UL, 3651360887UL, 3438668017UL, 1645378852UL, 1995123150UL, 1835887948UL, 1022257616UL, 3828432892UL, 3710259931UL, 713144773UL, +3246285450UL, 2485142597UL, 1611287338UL, 2845388948UL, 3690657633UL, 2403178686UL, 2201888000UL, 2180908599UL, 3072014497UL, 3436535724UL, 2948908116UL, 1647734358UL, 1669938872UL, 3572731079UL, 1100892983UL, 308060688UL, 592016509UL, 2725115972UL, 887278263UL, 991869336UL, 3597899723UL, 819708104UL, 1108269267UL, 851855066UL, 1940998002UL, 3539084542UL, 3156419045UL, 965450940UL, 1942363226UL, 1430246588UL, 1368971075UL, 224112021UL, +642683738UL, 3035789355UL, 1829444044UL, 4234626091UL, 314715303UL, 2809844786UL, 2251172733UL, 970188857UL, 3910072565UL, 155628632UL, 3397535176UL, 3290884849UL, 861868157UL, 2811422184UL, 1847583676UL, 3502085520UL, 1499698865UL, 2446269873UL, 236680785UL, 3698448762UL, 1179896471UL, 83960622UL, 3303129336UL, 1191373247UL, 1567908030UL, 3077388457UL, 1022975703UL, 2535144448UL, 8680269UL, 3979982957UL, 1810825915UL, 2293529378UL, +2307085218UL, 483894148UL, 4003402870UL, 2043868156UL, 3038491874UL, 3786518530UL, 3606440668UL, 3062185402UL, 120183042UL, 86901386UL, 2233164457UL, 2881782972UL, 3345668738UL, 2294460421UL, 2996668315UL, 658184098UL, 3558825846UL, 2121278529UL, 1950463910UL, 551627788UL, 2464303444UL, 893474565UL, 183176481UL, 2852725906UL, 1191310725UL, 2398932683UL, 4164956002UL, 788617081UL, 2619288187UL, 3429362702UL, 3205668166UL, 1668126623UL, +29124108UL, 2106753333UL, 650684252UL, 2220445579UL, 537394374UL, 725338795UL, 2369694095UL, 899394682UL, 364129622UL, 328438826UL, 1727397396UL, 4195985755UL, 3278649457UL, 3072225531UL, 2838645991UL, 583924693UL, 2389919UL, 1751415553UL, 2034088483UL, 1437197870UL, 1017611325UL, 1516966376UL, 4207811086UL, 768131803UL, 2713210999UL, 761144580UL, 1955929377UL, 2740991637UL, 3000313526UL, 1355959320UL, 840696976UL, 4263287583UL, +2476002145UL, 835527260UL, 2084758949UL, 3729075247UL, 110659216UL, 2251723899UL, 3159477758UL, 2008655575UL, 4127907945UL, 2378803214UL, 2067948386UL, 2006141522UL, 450235614UL, 3240776806UL, 4112321452UL, 3804118704UL, 3302604345UL, 1712745267UL, 1079549936UL, 3834044005UL, 3423301791UL, 416995358UL, 2049170698UL, 3913510119UL, 3651360887UL, 3438668017UL, 1645378852UL, 1995123150UL, 841590980UL, 1022257616UL, 3828432892UL, 3710259931UL, +713144773UL, 1272133892UL, 2485142597UL, 1611287338UL, 2845388948UL, 3690657633UL, 3083851146UL, 2201888000UL, 2180908599UL, 3072014497UL, 3436535724UL, 4162521870UL, 1647734358UL, 1669938872UL, 3572731079UL, 1100892983UL, 986584939UL, 592016509UL, 2725115972UL, 887278263UL, 991869336UL, 2711883653UL, 819708104UL, 1108269267UL, 851855066UL, 1940998002UL, 4050477073UL, 3156419045UL, 965450940UL, 1942363226UL, 1430246588UL, 4285490865UL, +224112021UL, 642683738UL, 3035789355UL, 1829444044UL, 4197159994UL, 314715303UL, 2809844786UL, 2251172733UL, 970188857UL, 3018833494UL, 155628632UL, 3397535176UL, 3290884849UL, 861868157UL, 2883971818UL, 1847583676UL, 3502085520UL, 1499698865UL, 2446269873UL, 2621709156UL, 3698448762UL, 1179896471UL, 83960622UL, 3303129336UL, 2192966710UL, 1567908030UL, 3077388457UL, 1022975703UL, 2535144448UL, 95661399UL, 3979982957UL, 1810825915UL, +2293529378UL, 2307085218UL, 485952375UL, 4003402870UL, 2043868156UL, 3038491874UL, 3786518530UL, 575288835UL, 3062185402UL, 120183042UL, 86901386UL, 2233164457UL, 2864966512UL, 3345668738UL, 2294460421UL, 2996668315UL, 658184098UL, 2892259673UL, 2121278529UL, 1950463910UL, 551627788UL, 2464303444UL, 2699734841UL, 183176481UL, 2852725906UL, 1191310725UL, 2398932683UL, 3505505465UL, 788617081UL, 2619288187UL, 3429362702UL, 3205668166UL, +2157859363UL, 29124108UL, 2106753333UL, 650684252UL, 2220445579UL, 978263237UL, 725338795UL, 2369694095UL, 899394682UL, 364129622UL, 3795063930UL, 1727397396UL, 4195985755UL, 3278649457UL, 3072225531UL, 1996768476UL, 583924693UL, 2389919UL, 1751415553UL, 2034088483UL, 1069211024UL, 1017611325UL, 1516966376UL, 4207811086UL, 768131803UL, 1365857736UL, 761144580UL, 1955929377UL, 2740991637UL, 3000313526UL, 1057560595UL, 840696976UL, +4263287583UL, 2476002145UL, 835527260UL, 76517292UL, 3729075247UL, 110659216UL, 2251723899UL, 3159477758UL, 3272987770UL, 4127907945UL, 2378803214UL, 2067948386UL, 2006141522UL, 1223694226UL, 3240776806UL, 4112321452UL, 3804118704UL, 3302604345UL, 2218568154UL, 1079549936UL, 3834044005UL, 3423301791UL, 416995358UL, 3661322119UL, 3913510119UL, 3651360887UL, 3438668017UL, 1645378852UL, 3606917602UL, 841590980UL, 1022257616UL, 3828432892UL, +3710259931UL, 1270853142UL, 1272133892UL, 2485142597UL, 1611287338UL, 2845388948UL, 131877212UL, 3083851146UL, 2201888000UL, 2180908599UL, 3072014497UL, 2459348479UL, 4162521870UL, 1647734358UL, 1669938872UL, 3572731079UL, 4285199726UL, 986584939UL, 592016509UL, 2725115972UL, 887278263UL, 3824306591UL, 2711883653UL, 819708104UL, 1108269267UL, 851855066UL, 190839383UL, 4050477073UL, 3156419045UL, 965450940UL, 1942363226UL, 1750931697UL, +4285490865UL, 224112021UL, 642683738UL, 3035789355UL, 1544088048UL, 4197159994UL, 314715303UL, 2809844786UL, 2251172733UL, 3155072709UL, 3018833494UL, 155628632UL, 3397535176UL, 3290884849UL, 4153861738UL, 2883971818UL, 1847583676UL, 3502085520UL, 1499698865UL, 1780983485UL, 2621709156UL, 3698448762UL, 1179896471UL, 83960622UL, 3849402190UL, 2192966710UL, 1567908030UL, 3077388457UL, 1022975703UL, 1639944917UL, 95661399UL, 3979982957UL, +1810825915UL, 2293529378UL, 3477014442UL, 485952375UL, 4003402870UL, 2043868156UL, 3038491874UL, 1482314580UL, 575288835UL, 3062185402UL, 120183042UL, 86901386UL, 3129494022UL, 2864966512UL, 3345668738UL, 2294460421UL, 2996668315UL, 1986664970UL, 2892259673UL, 2121278529UL, 1950463910UL, 551627788UL, 3105369079UL, 2699734841UL, 183176481UL, 2852725906UL, 1191310725UL, 3154591925UL, 3505505465UL, 788617081UL, 2619288187UL, 3429362702UL, +4204415531UL, 1321048315UL, 4247243973UL, 3085535935UL, 114618345UL, 2126710176UL, 1857709117UL, 3744103666UL, 304437872UL, 2388303947UL, 1802971382UL, 2099900439UL, 2543837819UL, 593111133UL, 3788847386UL, 1479546758UL, 4095492150UL, 240996968UL, 3423191009UL, 2666077260UL, 884572403UL, 2988847666UL, 928827215UL, 2549465610UL, 2773670136UL, 708214104UL, 2594951780UL, 1076989709UL, 2850313793UL, 1401578686UL, 4100639899UL, 2353261688UL, +1323066237UL, 31664438UL, 951240198UL, 3676836716UL, 3633113483UL, 3262159382UL, 981784748UL, 1172850762UL, 3106238289UL, 3118297408UL, 4207023277UL, 3362324732UL, 844983306UL, 3790928628UL, 4156848237UL, 2638267501UL, 1494090858UL, 3955182404UL, 1193294064UL, 4035152789UL, 2971914580UL, 2865046609UL, 3782329083UL, 120288587UL, 3300482994UL, 4268540970UL, 4183426205UL, 3572724103UL, 3287140971UL, 3038086532UL, 3210919007UL, 2171998100UL, +3958495101UL, 1589679371UL, 2880366694UL, 827575211UL, 1343189406UL, 364332706UL, 866065087UL, 33080625UL, 4284492640UL, 2277479989UL, 4110331130UL, 430538110UL, 3549886335UL, 3734345920UL, 3780943339UL, 638033279UL, 2684714509UL, 945721631UL, 49994267UL, 2394351381UL, 1996532760UL, 3201422203UL, 3509459657UL, 4118609520UL, 632454166UL, 696027759UL, 901486290UL, 1230453723UL, 4225865813UL, 4072619256UL, 3111686961UL, 1487480830UL, +4112016561UL, 1577020285UL, 2765241900UL, 2496609620UL, 1731271292UL, 6970479UL, 2936359283UL, 1541124937UL, 3705956773UL, 2349695021UL, 2247551804UL, 3759489710UL, 1321217706UL, 379586757UL, 2008242014UL, 1138475935UL, 3044902216UL, 1917596533UL, 2905651936UL, 3320601534UL, 1468557693UL, 4101437636UL, 374575138UL, 730079080UL, 995340259UL, 1430552870UL, 3860649629UL, 541396702UL, 3413070856UL, 3052797396UL, 3591116740UL, 2811484252UL, +2464310183UL, 1597327051UL, 3288232619UL, 1564716093UL, 2838386049UL, 264313861UL, 881377066UL, 4165178494UL, 1069189853UL, 1045737884UL, 2072266205UL, 2700673629UL, 2338724235UL, 837702541UL, 2603464957UL, 1548182143UL, 3565539962UL, 38172869UL, 1949065935UL, 3628598166UL, 2788698071UL, 3531182193UL, 1367529788UL, 3902468811UL, 1215323634UL, 1117475027UL, 3901912129UL, 2678279671UL, 597953858UL, 4082485755UL, 3696533122UL, 1078703353UL, +}, +{ +590004384UL, 3025338414UL, 1764374188UL, 20686172UL, 932343559UL, 1798441768UL, 1013577341UL, 4275903797UL, 853441141UL, 1065980978UL, 3665193407UL, 1555165047UL, 2962781443UL, 1822487181UL, 3329200135UL, 1527094489UL, 3805115799UL, 2252376033UL, 2137546519UL, 3632426270UL, 2439842864UL, 2525211849UL, 602876448UL, 1488163727UL, 3169015136UL, 832084039UL, 81097112UL, 994974428UL, 1945411347UL, 1020609213UL, 2863240894UL, 1639194881UL, +3078842449UL, 1885382385UL, 2595105518UL, 3857547190UL, 3654577058UL, 3853111480UL, 2237941224UL, 625422255UL, 3292783340UL, 750206381UL, 1002246874UL, 900879607UL, 820635221UL, 3318328110UL, 3980484559UL, 3924790669UL, 4260574943UL, 3658381114UL, 3673068643UL, 1319175627UL, 3620071157UL, 3914274380UL, 3310864044UL, 1529070914UL, 1760958838UL, 818806045UL, 3056976418UL, 2337737150UL, 2061530784UL, 1036243443UL, 2058675708UL, 1932546035UL, +1604709219UL, 1317296740UL, 2505350414UL, 624826181UL, 2710208816UL, 2208469912UL, 1930700024UL, 3769953790UL, 2092911082UL, 520309780UL, 3787727278UL, 684095804UL, 3697683979UL, 111440289UL, 4043494885UL, 1571375993UL, 1828801775UL, 3589061974UL, 3016563679UL, 2026002784UL, 3810490061UL, 2634997537UL, 2715287551UL, 1973545003UL, 3407971274UL, 3239387641UL, 2479429785UL, 324785401UL, 2622755198UL, 1525605325UL, 3280412074UL, 2453630352UL, +726090704UL, 4170024046UL, 248003549UL, 3319518538UL, 1331224401UL, 1203416669UL, 3497395173UL, 2465693133UL, 15303334UL, 267163358UL, 627307819UL, 294350450UL, 3691559013UL, 2491765952UL, 839609873UL, 1598505629UL, 3905396753UL, 583168080UL, 281403302UL, 1658629464UL, 1498139453UL, 2860737994UL, 148007837UL, 1439496901UL, 3226624586UL, 1708925351UL, 195473107UL, 1150552649UL, 2856922985UL, 1853471286UL, 1286593394UL, 2025932254UL, +1300583198UL, 3169702837UL, 1255226060UL, 3482666699UL, 1515557266UL, 1964035766UL, 1604627993UL, 641427670UL, 450188959UL, 1095230428UL, 293179001UL, 1293554079UL, 3022335608UL, 610535626UL, 1329467104UL, 3717935497UL, 1252385485UL, 441595535UL, 2937045243UL, 2846877561UL, 668719121UL, 3604154741UL, 1150714166UL, 1689640190UL, 2219487087UL, 2445975095UL, 3492083575UL, 377195836UL, 2727989292UL, 2460040634UL, 2910322481UL, 399050881UL, +3601292788UL, 590004384UL, 3025338414UL, 1764374188UL, 20686172UL, 3576058865UL, 1798441768UL, 1013577341UL, 4275903797UL, 853441141UL, 3862104007UL, 3665193407UL, 1555165047UL, 2962781443UL, 1822487181UL, 1058917817UL, 1527094489UL, 3805115799UL, 2252376033UL, 2137546519UL, 780594798UL, 2439842864UL, 2525211849UL, 602876448UL, 1488163727UL, 642430472UL, 832084039UL, 81097112UL, 994974428UL, 1945411347UL, 2231598766UL, 2863240894UL, +1639194881UL, 3078842449UL, 1885382385UL, 2387524763UL, 3857547190UL, 3654577058UL, 3853111480UL, 2237941224UL, 991026264UL, 3292783340UL, 750206381UL, 1002246874UL, 900879607UL, 1178067772UL, 3318328110UL, 3980484559UL, 3924790669UL, 4260574943UL, 1964983082UL, 3673068643UL, 1319175627UL, 3620071157UL, 3914274380UL, 992141498UL, 1529070914UL, 1760958838UL, 818806045UL, 3056976418UL, 3295305429UL, 2061530784UL, 1036243443UL, 2058675708UL, +1932546035UL, 3724542133UL, 1317296740UL, 2505350414UL, 624826181UL, 2710208816UL, 3359715256UL, 1930700024UL, 3769953790UL, 2092911082UL, 520309780UL, 1979908015UL, 684095804UL, 3697683979UL, 111440289UL, 4043494885UL, 3256907235UL, 1828801775UL, 3589061974UL, 3016563679UL, 2026002784UL, 1967781780UL, 2634997537UL, 2715287551UL, 1973545003UL, 3407971274UL, 391604110UL, 2479429785UL, 324785401UL, 2622755198UL, 1525605325UL, 462777294UL, +2453630352UL, 726090704UL, 4170024046UL, 248003549UL, 3125444318UL, 1331224401UL, 1203416669UL, 3497395173UL, 2465693133UL, 1610778556UL, 267163358UL, 627307819UL, 294350450UL, 3691559013UL, 3302305047UL, 839609873UL, 1598505629UL, 3905396753UL, 583168080UL, 1502262581UL, 1658629464UL, 1498139453UL, 2860737994UL, 148007837UL, 2973368511UL, 3226624586UL, 1708925351UL, 195473107UL, 1150552649UL, 522423348UL, 1853471286UL, 1286593394UL, +2025932254UL, 1300583198UL, 555770116UL, 1255226060UL, 3482666699UL, 1515557266UL, 1964035766UL, 877073175UL, 641427670UL, 450188959UL, 1095230428UL, 293179001UL, 4216364784UL, 3022335608UL, 610535626UL, 1329467104UL, 3717935497UL, 1665384485UL, 441595535UL, 2937045243UL, 2846877561UL, 668719121UL, 978801343UL, 1150714166UL, 1689640190UL, 2219487087UL, 2445975095UL, 3819595050UL, 377195836UL, 2727989292UL, 2460040634UL, 2910322481UL, +1200428010UL, 3601292788UL, 590004384UL, 3025338414UL, 1764374188UL, 3586255253UL, 3576058865UL, 1798441768UL, 1013577341UL, 4275903797UL, 1511067357UL, 3862104007UL, 3665193407UL, 1555165047UL, 2962781443UL, 2749766525UL, 1058917817UL, 1527094489UL, 3805115799UL, 2252376033UL, 817362043UL, 780594798UL, 2439842864UL, 2525211849UL, 602876448UL, 2309049006UL, 642430472UL, 832084039UL, 81097112UL, 994974428UL, 3148197354UL, 2231598766UL, +2863240894UL, 1639194881UL, 3078842449UL, 311769962UL, 2387524763UL, 3857547190UL, 3654577058UL, 3853111480UL, 1888597091UL, 991026264UL, 3292783340UL, 750206381UL, 1002246874UL, 2904195378UL, 1178067772UL, 3318328110UL, 3980484559UL, 3924790669UL, 4265386540UL, 1964983082UL, 3673068643UL, 1319175627UL, 3620071157UL, 1635921454UL, 992141498UL, 1529070914UL, 1760958838UL, 818806045UL, 3002614702UL, 3295305429UL, 2061530784UL, 1036243443UL, +2058675708UL, 2534375036UL, 3724542133UL, 1317296740UL, 2505350414UL, 624826181UL, 3042995618UL, 3359715256UL, 1930700024UL, 3769953790UL, 2092911082UL, 1870611696UL, 1979908015UL, 684095804UL, 3697683979UL, 111440289UL, 1111193348UL, 3256907235UL, 1828801775UL, 3589061974UL, 3016563679UL, 2203918092UL, 1967781780UL, 2634997537UL, 2715287551UL, 1973545003UL, 17967467UL, 391604110UL, 2479429785UL, 324785401UL, 2622755198UL, 3993572289UL, +462777294UL, 2453630352UL, 726090704UL, 4170024046UL, 813760479UL, 3125444318UL, 1331224401UL, 1203416669UL, 3497395173UL, 2528908686UL, 1610778556UL, 267163358UL, 627307819UL, 294350450UL, 4252461657UL, 3302305047UL, 839609873UL, 1598505629UL, 3905396753UL, 3407593947UL, 1502262581UL, 1658629464UL, 1498139453UL, 2860737994UL, 1137070983UL, 2973368511UL, 3226624586UL, 1708925351UL, 195473107UL, 1973834367UL, 522423348UL, 1853471286UL, +1286593394UL, 2025932254UL, 1636839834UL, 555770116UL, 1255226060UL, 3482666699UL, 1515557266UL, 4244619305UL, 877073175UL, 641427670UL, 450188959UL, 1095230428UL, 710341587UL, 4216364784UL, 3022335608UL, 610535626UL, 1329467104UL, 262034293UL, 1665384485UL, 441595535UL, 2937045243UL, 2846877561UL, 1059914271UL, 978801343UL, 1150714166UL, 1689640190UL, 2219487087UL, 258315233UL, 3819595050UL, 377195836UL, 2727989292UL, 2460040634UL, +1828274968UL, 1200428010UL, 3601292788UL, 590004384UL, 3025338414UL, 3487643146UL, 3586255253UL, 3576058865UL, 1798441768UL, 1013577341UL, 3609472816UL, 1511067357UL, 3862104007UL, 3665193407UL, 1555165047UL, 4188135767UL, 2749766525UL, 1058917817UL, 1527094489UL, 3805115799UL, 1547526585UL, 817362043UL, 780594798UL, 2439842864UL, 2525211849UL, 3949139098UL, 2309049006UL, 642430472UL, 832084039UL, 81097112UL, 2619711743UL, 3148197354UL, +2231598766UL, 2863240894UL, 1639194881UL, 3018692935UL, 311769962UL, 2387524763UL, 3857547190UL, 3654577058UL, 2418052942UL, 1888597091UL, 991026264UL, 3292783340UL, 750206381UL, 2501986418UL, 2904195378UL, 1178067772UL, 3318328110UL, 3980484559UL, 655757623UL, 4265386540UL, 1964983082UL, 3673068643UL, 1319175627UL, 1539823819UL, 1635921454UL, 992141498UL, 1529070914UL, 1760958838UL, 1840073710UL, 3002614702UL, 3295305429UL, 2061530784UL, +1036243443UL, 2212957003UL, 2534375036UL, 3724542133UL, 1317296740UL, 2505350414UL, 2754670042UL, 3042995618UL, 3359715256UL, 1930700024UL, 3769953790UL, 3307920786UL, 1870611696UL, 1979908015UL, 684095804UL, 3697683979UL, 326641529UL, 1111193348UL, 3256907235UL, 1828801775UL, 3589061974UL, 1408835557UL, 2203918092UL, 1967781780UL, 2634997537UL, 2715287551UL, 1958610929UL, 17967467UL, 391604110UL, 2479429785UL, 324785401UL, 3833051255UL, +3993572289UL, 462777294UL, 2453630352UL, 726090704UL, 1236380896UL, 813760479UL, 3125444318UL, 1331224401UL, 1203416669UL, 728276857UL, 2528908686UL, 1610778556UL, 267163358UL, 627307819UL, 4276734917UL, 4252461657UL, 3302305047UL, 839609873UL, 1598505629UL, 3827653659UL, 3407593947UL, 1502262581UL, 1658629464UL, 1498139453UL, 3636064463UL, 1137070983UL, 2973368511UL, 3226624586UL, 1708925351UL, 2288771247UL, 1973834367UL, 522423348UL, +1853471286UL, 1286593394UL, 798364204UL, 1636839834UL, 555770116UL, 1255226060UL, 3482666699UL, 2385578475UL, 4244619305UL, 877073175UL, 641427670UL, 450188959UL, 3502743047UL, 710341587UL, 4216364784UL, 3022335608UL, 610535626UL, 2388448039UL, 262034293UL, 1665384485UL, 441595535UL, 2937045243UL, 3028160550UL, 1059914271UL, 978801343UL, 1150714166UL, 1689640190UL, 169488023UL, 258315233UL, 3819595050UL, 377195836UL, 2727989292UL, +837094660UL, 3531987448UL, 1901453576UL, 3312447598UL, 1036467641UL, 2243300650UL, 3148869460UL, 1886274644UL, 4076707689UL, 257110870UL, 3118463831UL, 1165161057UL, 1118846497UL, 3446934363UL, 1514176098UL, 1362957326UL, 2629874126UL, 791374320UL, 1015673947UL, 4252955786UL, 2409207780UL, 3831311130UL, 1654475922UL, 3682733431UL, 780405105UL, 4059616372UL, 503333525UL, 1471514828UL, 2526848791UL, 607539645UL, 730408454UL, 1574159005UL, +1777808061UL, 1296178310UL, 1078855633UL, 878462103UL, 269337411UL, 750735378UL, 2599590920UL, 4206153248UL, 939121991UL, 3061289971UL, 2543431563UL, 1684736054UL, 2319658494UL, 77300347UL, 3222569207UL, 3882064339UL, 2201120493UL, 289098227UL, 3934209124UL, 2407620042UL, 2713079957UL, 2812644841UL, 115993752UL, 2545688211UL, 774350907UL, 939749505UL, 2242588062UL, 960853876UL, 296665594UL, 1367312411UL, 3370351589UL, 711706404UL, +3331136631UL, 1370376958UL, 2322438166UL, 577115138UL, 1472236592UL, 4029835216UL, 1122502809UL, 3490426739UL, 1930206806UL, 2074277138UL, 1360950220UL, 3797708387UL, 2007430804UL, 2257239461UL, 3889012648UL, 710165871UL, 763101711UL, 728019024UL, 652403220UL, 2517020147UL, 1801290767UL, 1478810019UL, 1057288808UL, 2879821959UL, 3916870020UL, 1480362189UL, 919816752UL, 375872647UL, 3236906236UL, 1504223782UL, 128306943UL, 1355826533UL, +2656243649UL, 390454690UL, 3848250363UL, 377480950UL, 358651174UL, 1337795904UL, 1925462532UL, 2421843219UL, 173144626UL, 886649902UL, 402617827UL, 932830871UL, 742712936UL, 4033430386UL, 1409945926UL, 3617206544UL, 2383446356UL, 3452204096UL, 615486157UL, 720696019UL, 1730134434UL, 3918468503UL, 1629431965UL, 2174079220UL, 325852294UL, 234479771UL, 1490297289UL, 3579002992UL, 3538738636UL, 139386548UL, 3067789050UL, 2078261059UL, +3552654276UL, 1774602596UL, 2105142163UL, 2768099869UL, 2265044995UL, 3680536732UL, 3601322356UL, 2848878442UL, 1166743022UL, 3508176959UL, 2186695985UL, 550278868UL, 3324775634UL, 384537301UL, 1019044102UL, 3354263542UL, 1942540686UL, 922714337UL, 3097711558UL, 3074228403UL, 3565076630UL, 3459053081UL, 4128383906UL, 1114387332UL, 2101424539UL, 1192649508UL, 58778130UL, 1651798895UL, 1752063480UL, 1728826905UL, 2225187635UL, 2463770127UL, +}, +{ +1978406995UL, 576106282UL, 2238958298UL, 2073551095UL, 624788087UL, 4231569260UL, 1853272808UL, 238274694UL, 2389334758UL, 410188028UL, 2293786099UL, 4243662908UL, 2317700970UL, 4050493361UL, 2348206908UL, 485250660UL, 1212732903UL, 169414736UL, 292623762UL, 1602229231UL, 2466348869UL, 3063669700UL, 1872890881UL, 1887188929UL, 3447638989UL, 162521682UL, 1470651713UL, 4036975255UL, 3423782623UL, 4043724693UL, 1686690883UL, 2610958712UL, +35940353UL, 78593759UL, 1565950713UL, 1304303952UL, 2004267248UL, 1417268036UL, 3328228522UL, 789915977UL, 2567452041UL, 3564175714UL, 1838409932UL, 1455795236UL, 22377452UL, 455201131UL, 3340286965UL, 184599544UL, 4102076073UL, 4007870762UL, 1470247063UL, 1579231003UL, 3544385556UL, 3408973464UL, 3759098465UL, 3243598964UL, 532452279UL, 1172265732UL, 3520978258UL, 2880513876UL, 41188252UL, 1663974668UL, 3444236420UL, 338981290UL, +2140558860UL, 3310465688UL, 552673362UL, 3277110106UL, 948036400UL, 1346056406UL, 3257468427UL, 4008294878UL, 3788890535UL, 2414511414UL, 3539325895UL, 3025695322UL, 3727849930UL, 3922840362UL, 535899902UL, 665898223UL, 1456499692UL, 354208792UL, 247894771UL, 2093316680UL, 2945209002UL, 1029298544UL, 976007759UL, 394966955UL, 1843302845UL, 3689202777UL, 1999949614UL, 1070472810UL, 4233404701UL, 667526747UL, 2313963966UL, 3519400667UL, +1548274317UL, 3272402139UL, 2570038689UL, 892260481UL, 3547254358UL, 1540409404UL, 3687395534UL, 3751445920UL, 546406228UL, 2167638865UL, 4234783150UL, 806401261UL, 1351195286UL, 1085913868UL, 3109267901UL, 1882610112UL, 1568734773UL, 239430641UL, 3971361190UL, 383932711UL, 149541490UL, 196701535UL, 108079452UL, 888590964UL, 1708559652UL, 3196290573UL, 2115587458UL, 3198525248UL, 3580113911UL, 3098818120UL, 4271558926UL, 3208851696UL, +3354604918UL, 3536923694UL, 1087345822UL, 2292802521UL, 3500230819UL, 411564772UL, 2408049547UL, 1215342690UL, 1707182109UL, 774540619UL, 1613606757UL, 836141085UL, 1061962136UL, 348765795UL, 2852610966UL, 3526215991UL, 2708801073UL, 3467537935UL, 472234793UL, 3944263763UL, 1782219410UL, 502724699UL, 3525703395UL, 1756411033UL, 1358811278UL, 3938603279UL, 3701976555UL, 3259537961UL, 628617330UL, 1553932236UL, 1974037630UL, 2090519666UL, +2185028543UL, 1978406995UL, 576106282UL, 2238958298UL, 2073551095UL, 638634424UL, 4231569260UL, 1853272808UL, 238274694UL, 2389334758UL, 3808551433UL, 2293786099UL, 4243662908UL, 2317700970UL, 4050493361UL, 957981276UL, 485250660UL, 1212732903UL, 169414736UL, 292623762UL, 1956197178UL, 2466348869UL, 3063669700UL, 1872890881UL, 1887188929UL, 1162224455UL, 162521682UL, 1470651713UL, 4036975255UL, 3423782623UL, 3243414978UL, 1686690883UL, +2610958712UL, 35940353UL, 78593759UL, 1648686849UL, 1304303952UL, 2004267248UL, 1417268036UL, 3328228522UL, 3740797237UL, 2567452041UL, 3564175714UL, 1838409932UL, 1455795236UL, 1045087636UL, 455201131UL, 3340286965UL, 184599544UL, 4102076073UL, 2685677331UL, 1470247063UL, 1579231003UL, 3544385556UL, 3408973464UL, 3832799869UL, 3243598964UL, 532452279UL, 1172265732UL, 3520978258UL, 531684354UL, 41188252UL, 1663974668UL, 3444236420UL, +338981290UL, 1286622338UL, 3310465688UL, 552673362UL, 3277110106UL, 948036400UL, 2987864230UL, 3257468427UL, 4008294878UL, 3788890535UL, 2414511414UL, 2613137548UL, 3025695322UL, 3727849930UL, 3922840362UL, 535899902UL, 3288883992UL, 1456499692UL, 354208792UL, 247894771UL, 2093316680UL, 3775770224UL, 1029298544UL, 976007759UL, 394966955UL, 1843302845UL, 1484214934UL, 1999949614UL, 1070472810UL, 4233404701UL, 667526747UL, 3708951530UL, +3519400667UL, 1548274317UL, 3272402139UL, 2570038689UL, 3457725296UL, 3547254358UL, 1540409404UL, 3687395534UL, 3751445920UL, 181641144UL, 2167638865UL, 4234783150UL, 806401261UL, 1351195286UL, 3457819598UL, 3109267901UL, 1882610112UL, 1568734773UL, 239430641UL, 4037392309UL, 383932711UL, 149541490UL, 196701535UL, 108079452UL, 1724276622UL, 1708559652UL, 3196290573UL, 2115587458UL, 3198525248UL, 3784683125UL, 3098818120UL, 4271558926UL, +3208851696UL, 3354604918UL, 149872004UL, 1087345822UL, 2292802521UL, 3500230819UL, 411564772UL, 4068437023UL, 1215342690UL, 1707182109UL, 774540619UL, 1613606757UL, 1062624488UL, 1061962136UL, 348765795UL, 2852610966UL, 3526215991UL, 1518538195UL, 3467537935UL, 472234793UL, 3944263763UL, 1782219410UL, 1835413488UL, 3525703395UL, 1756411033UL, 1358811278UL, 3938603279UL, 1054245423UL, 3259537961UL, 628617330UL, 1553932236UL, 1974037630UL, +2030751433UL, 2185028543UL, 1978406995UL, 576106282UL, 2238958298UL, 3877268821UL, 638634424UL, 4231569260UL, 1853272808UL, 238274694UL, 2482404724UL, 3808551433UL, 2293786099UL, 4243662908UL, 2317700970UL, 1955227186UL, 957981276UL, 485250660UL, 1212732903UL, 169414736UL, 1333246101UL, 1956197178UL, 2466348869UL, 3063669700UL, 1872890881UL, 3662049503UL, 1162224455UL, 162521682UL, 1470651713UL, 4036975255UL, 3593925064UL, 3243414978UL, +1686690883UL, 2610958712UL, 35940353UL, 2530174792UL, 1648686849UL, 1304303952UL, 2004267248UL, 1417268036UL, 1299827381UL, 3740797237UL, 2567452041UL, 3564175714UL, 1838409932UL, 4221368409UL, 1045087636UL, 455201131UL, 3340286965UL, 184599544UL, 486448047UL, 2685677331UL, 1470247063UL, 1579231003UL, 3544385556UL, 1404931688UL, 3832799869UL, 3243598964UL, 532452279UL, 1172265732UL, 3373048034UL, 531684354UL, 41188252UL, 1663974668UL, +3444236420UL, 1375188728UL, 1286622338UL, 3310465688UL, 552673362UL, 3277110106UL, 655980467UL, 2987864230UL, 3257468427UL, 4008294878UL, 3788890535UL, 763995173UL, 2613137548UL, 3025695322UL, 3727849930UL, 3922840362UL, 1850434657UL, 3288883992UL, 1456499692UL, 354208792UL, 247894771UL, 3440471938UL, 3775770224UL, 1029298544UL, 976007759UL, 394966955UL, 3298245949UL, 1484214934UL, 1999949614UL, 1070472810UL, 4233404701UL, 3788558253UL, +3708951530UL, 3519400667UL, 1548274317UL, 3272402139UL, 3117201719UL, 3457725296UL, 3547254358UL, 1540409404UL, 3687395534UL, 3871454027UL, 181641144UL, 2167638865UL, 4234783150UL, 806401261UL, 1627904858UL, 3457819598UL, 3109267901UL, 1882610112UL, 1568734773UL, 3178105921UL, 4037392309UL, 383932711UL, 149541490UL, 196701535UL, 424324376UL, 1724276622UL, 1708559652UL, 3196290573UL, 2115587458UL, 2946026327UL, 3784683125UL, 3098818120UL, +4271558926UL, 3208851696UL, 2551504859UL, 149872004UL, 1087345822UL, 2292802521UL, 3500230819UL, 3055410013UL, 4068437023UL, 1215342690UL, 1707182109UL, 774540619UL, 2466902579UL, 1062624488UL, 1061962136UL, 348765795UL, 2852610966UL, 355211123UL, 1518538195UL, 3467537935UL, 472234793UL, 3944263763UL, 3159176627UL, 1835413488UL, 3525703395UL, 1756411033UL, 1358811278UL, 2153206130UL, 1054245423UL, 3259537961UL, 628617330UL, 1553932236UL, +1741202495UL, 2030751433UL, 2185028543UL, 1978406995UL, 576106282UL, 2832311581UL, 3877268821UL, 638634424UL, 4231569260UL, 1853272808UL, 3103974717UL, 2482404724UL, 3808551433UL, 2293786099UL, 4243662908UL, 2607780401UL, 1955227186UL, 957981276UL, 485250660UL, 1212732903UL, 3214649174UL, 1333246101UL, 1956197178UL, 2466348869UL, 3063669700UL, 2428387069UL, 3662049503UL, 1162224455UL, 162521682UL, 1470651713UL, 3563435961UL, 3593925064UL, +3243414978UL, 1686690883UL, 2610958712UL, 1021669488UL, 2530174792UL, 1648686849UL, 1304303952UL, 2004267248UL, 1150095671UL, 1299827381UL, 3740797237UL, 2567452041UL, 3564175714UL, 1992360540UL, 4221368409UL, 1045087636UL, 455201131UL, 3340286965UL, 3795860292UL, 486448047UL, 2685677331UL, 1470247063UL, 1579231003UL, 3012017918UL, 1404931688UL, 3832799869UL, 3243598964UL, 532452279UL, 2740401823UL, 3373048034UL, 531684354UL, 41188252UL, +1663974668UL, 1239982773UL, 1375188728UL, 1286622338UL, 3310465688UL, 552673362UL, 2159084435UL, 655980467UL, 2987864230UL, 3257468427UL, 4008294878UL, 1526518186UL, 763995173UL, 2613137548UL, 3025695322UL, 3727849930UL, 4161669345UL, 1850434657UL, 3288883992UL, 1456499692UL, 354208792UL, 1648970767UL, 3440471938UL, 3775770224UL, 1029298544UL, 976007759UL, 292829454UL, 3298245949UL, 1484214934UL, 1999949614UL, 1070472810UL, 949984087UL, +3788558253UL, 3708951530UL, 3519400667UL, 1548274317UL, 3691975282UL, 3117201719UL, 3457725296UL, 3547254358UL, 1540409404UL, 3414085332UL, 3871454027UL, 181641144UL, 2167638865UL, 4234783150UL, 487427004UL, 1627904858UL, 3457819598UL, 3109267901UL, 1882610112UL, 2942538550UL, 3178105921UL, 4037392309UL, 383932711UL, 149541490UL, 528605550UL, 424324376UL, 1724276622UL, 1708559652UL, 3196290573UL, 2042399752UL, 2946026327UL, 3784683125UL, +3098818120UL, 4271558926UL, 2493686919UL, 2551504859UL, 149872004UL, 1087345822UL, 2292802521UL, 3257357826UL, 3055410013UL, 4068437023UL, 1215342690UL, 1707182109UL, 1101368233UL, 2466902579UL, 1062624488UL, 1061962136UL, 348765795UL, 377675640UL, 355211123UL, 1518538195UL, 3467537935UL, 472234793UL, 1918362523UL, 3159176627UL, 1835413488UL, 3525703395UL, 1756411033UL, 490591069UL, 2153206130UL, 1054245423UL, 3259537961UL, 628617330UL, +2464143505UL, 3547421156UL, 4181103091UL, 1646291356UL, 2711273600UL, 2961799099UL, 1443009342UL, 2191618308UL, 1193143275UL, 1858488142UL, 3741304147UL, 1479629752UL, 214641634UL, 1601114903UL, 3032545707UL, 5784133UL, 1466424840UL, 2251379876UL, 4054080092UL, 2965144328UL, 644228426UL, 1397556958UL, 422190032UL, 3059134799UL, 3779253493UL, 1314537880UL, 867798895UL, 3819721559UL, 3588436937UL, 670021879UL, 1070365654UL, 3339455790UL, +2963659516UL, 1662488399UL, 2336157317UL, 3427798652UL, 2782719134UL, 1317842084UL, 1576308528UL, 1129452059UL, 3400565954UL, 84977051UL, 3689257381UL, 3289717503UL, 3535165628UL, 3982356490UL, 173255911UL, 1929987033UL, 4221790572UL, 3473317939UL, 749060417UL, 2711561754UL, 316719217UL, 2359410057UL, 2014271053UL, 1432982162UL, 2107582322UL, 1899811989UL, 1394115707UL, 1134266213UL, 2334994542UL, 2475488907UL, 3238562415UL, 2410379210UL, +4147209396UL, 2446286513UL, 2194020199UL, 3068194593UL, 797186100UL, 1299000541UL, 1870322719UL, 2944499140UL, 1045779179UL, 2735528787UL, 3057750264UL, 2607876894UL, 1595833743UL, 3327636115UL, 3520489322UL, 3864068029UL, 3153522810UL, 2609437702UL, 1360208295UL, 2062444770UL, 3927110355UL, 1524755299UL, 1708215998UL, 3587488663UL, 2813888113UL, 686192293UL, 1078633032UL, 3066910876UL, 793688350UL, 3613674912UL, 387713910UL, 2660476731UL, +3032509241UL, 2353038709UL, 2212424333UL, 2110412913UL, 3631228061UL, 2765134272UL, 4025821789UL, 3324834269UL, 187577732UL, 1568270802UL, 2098502315UL, 2472645526UL, 2986813860UL, 1621191378UL, 3891512282UL, 1561648319UL, 2690491944UL, 3075246584UL, 3202791012UL, 315381589UL, 3645907425UL, 3532420114UL, 802256935UL, 1270128258UL, 2695868207UL, 4075358890UL, 3888212208UL, 510396943UL, 3683116722UL, 3943939501UL, 146061942UL, 733291914UL, +1402325031UL, 672641124UL, 2817168601UL, 2622398925UL, 3641379870UL, 2969146913UL, 4232866548UL, 1694492034UL, 3065141682UL, 234404736UL, 1921499010UL, 2300706258UL, 1304904939UL, 207802178UL, 2674605425UL, 2688377241UL, 2674991105UL, 2585496531UL, 2358858923UL, 2578793432UL, 3275116043UL, 228073476UL, 2936443283UL, 3713102344UL, 1629243323UL, 209348683UL, 3730808488UL, 275442226UL, 223820143UL, 2365614109UL, 3017206322UL, 1906208795UL, +}, +{ +1545504510UL, 1985586093UL, 2005504076UL, 2487099791UL, 2348737867UL, 2254755902UL, 3789154730UL, 3268946922UL, 99552511UL, 1369361877UL, 1888041043UL, 3105269579UL, 4044127396UL, 2380045264UL, 2970234287UL, 293292961UL, 1811276320UL, 1083136897UL, 3016497500UL, 950611584UL, 2165628367UL, 4140133899UL, 2402926185UL, 990501164UL, 2185997143UL, 1769871204UL, 721625457UL, 567446962UL, 1695515231UL, 1848699963UL, 4163520111UL, 2316975723UL, +4268269680UL, 1021066723UL, 517434635UL, 3827063239UL, 3483118065UL, 760366769UL, 3072996795UL, 3548263896UL, 2131401627UL, 4167855065UL, 410255606UL, 1992500865UL, 1322267629UL, 1599293552UL, 2389387938UL, 3721625360UL, 216375429UL, 2002236178UL, 1834631738UL, 1585275126UL, 3879559071UL, 2517667239UL, 1397456303UL, 4095227658UL, 589002062UL, 137665950UL, 3933018338UL, 1519132173UL, 3566494128UL, 3914066872UL, 3233332246UL, 855336825UL, +1882502420UL, 1081015168UL, 4148374722UL, 1683880703UL, 1161266344UL, 99374978UL, 733926790UL, 3520260556UL, 3643143173UL, 927318029UL, 398003191UL, 3472026294UL, 3518018860UL, 2319507998UL, 2650129369UL, 3781620600UL, 1294634949UL, 3977318486UL, 3068540117UL, 3732334866UL, 740308004UL, 1988900647UL, 2936479173UL, 2348744493UL, 1357856242UL, 3842428732UL, 3746094733UL, 214260739UL, 3493892012UL, 2358001919UL, 1775614809UL, 952871363UL, +1216985499UL, 2706067772UL, 1008517818UL, 4189424856UL, 1260334069UL, 2420035836UL, 311831945UL, 3409272605UL, 4266242510UL, 3590716427UL, 537257045UL, 3153762469UL, 1620749663UL, 3338743851UL, 3644831936UL, 3243426619UL, 783551642UL, 1305153827UL, 2026979662UL, 3164955857UL, 4082645339UL, 1633544228UL, 3389303153UL, 440623817UL, 204979344UL, 1674764841UL, 633231391UL, 4180702701UL, 1953210184UL, 2534954734UL, 4252100558UL, 2993632630UL, +4050264705UL, 678445398UL, 1502035091UL, 302442688UL, 493504779UL, 2321459487UL, 1141171231UL, 1507727159UL, 672678623UL, 4046722895UL, 65675127UL, 2936731189UL, 441159654UL, 832039862UL, 2252252769UL, 3090962795UL, 2839688755UL, 645344032UL, 2921087914UL, 2264738834UL, 2341060101UL, 778789539UL, 737962654UL, 2859693559UL, 2784310535UL, 493247978UL, 185832691UL, 3321631011UL, 641506549UL, 2652806878UL, 480335604UL, 2908694258UL, +984807024UL, 1545504510UL, 1985586093UL, 2005504076UL, 2487099791UL, 127488455UL, 2254755902UL, 3789154730UL, 3268946922UL, 99552511UL, 2160330513UL, 1888041043UL, 3105269579UL, 4044127396UL, 2380045264UL, 3185912634UL, 293292961UL, 1811276320UL, 1083136897UL, 3016497500UL, 116883339UL, 2165628367UL, 4140133899UL, 2402926185UL, 990501164UL, 4099344218UL, 1769871204UL, 721625457UL, 567446962UL, 1695515231UL, 1218419978UL, 4163520111UL, +2316975723UL, 4268269680UL, 1021066723UL, 237254804UL, 3827063239UL, 3483118065UL, 760366769UL, 3072996795UL, 1020639813UL, 2131401627UL, 4167855065UL, 410255606UL, 1992500865UL, 1887858126UL, 1599293552UL, 2389387938UL, 3721625360UL, 216375429UL, 2096265248UL, 1834631738UL, 1585275126UL, 3879559071UL, 2517667239UL, 3267338158UL, 4095227658UL, 589002062UL, 137665950UL, 3933018338UL, 3823062902UL, 3566494128UL, 3914066872UL, 3233332246UL, +855336825UL, 3240858503UL, 1081015168UL, 4148374722UL, 1683880703UL, 1161266344UL, 4034899335UL, 733926790UL, 3520260556UL, 3643143173UL, 927318029UL, 2130442867UL, 3472026294UL, 3518018860UL, 2319507998UL, 2650129369UL, 253769320UL, 1294634949UL, 3977318486UL, 3068540117UL, 3732334866UL, 3100107703UL, 1988900647UL, 2936479173UL, 2348744493UL, 1357856242UL, 477065277UL, 3746094733UL, 214260739UL, 3493892012UL, 2358001919UL, 52055911UL, +952871363UL, 1216985499UL, 2706067772UL, 1008517818UL, 2820619262UL, 1260334069UL, 2420035836UL, 311831945UL, 3409272605UL, 2066128794UL, 3590716427UL, 537257045UL, 3153762469UL, 1620749663UL, 2261931254UL, 3644831936UL, 3243426619UL, 783551642UL, 1305153827UL, 3937339872UL, 3164955857UL, 4082645339UL, 1633544228UL, 3389303153UL, 3304461891UL, 204979344UL, 1674764841UL, 633231391UL, 4180702701UL, 2649553051UL, 2534954734UL, 4252100558UL, +2993632630UL, 4050264705UL, 3777379050UL, 1502035091UL, 302442688UL, 493504779UL, 2321459487UL, 1795212504UL, 1507727159UL, 672678623UL, 4046722895UL, 65675127UL, 2810951967UL, 441159654UL, 832039862UL, 2252252769UL, 3090962795UL, 3317253399UL, 645344032UL, 2921087914UL, 2264738834UL, 2341060101UL, 1431934790UL, 737962654UL, 2859693559UL, 2784310535UL, 493247978UL, 555655767UL, 3321631011UL, 641506549UL, 2652806878UL, 480335604UL, +1837415425UL, 984807024UL, 1545504510UL, 1985586093UL, 2005504076UL, 2274320195UL, 127488455UL, 2254755902UL, 3789154730UL, 3268946922UL, 3812459919UL, 2160330513UL, 1888041043UL, 3105269579UL, 4044127396UL, 2341347785UL, 3185912634UL, 293292961UL, 1811276320UL, 1083136897UL, 825098089UL, 116883339UL, 2165628367UL, 4140133899UL, 2402926185UL, 4124720284UL, 4099344218UL, 1769871204UL, 721625457UL, 567446962UL, 3598160577UL, 1218419978UL, +4163520111UL, 2316975723UL, 4268269680UL, 923374392UL, 237254804UL, 3827063239UL, 3483118065UL, 760366769UL, 2263405553UL, 1020639813UL, 2131401627UL, 4167855065UL, 410255606UL, 3382265961UL, 1887858126UL, 1599293552UL, 2389387938UL, 3721625360UL, 3440586186UL, 2096265248UL, 1834631738UL, 1585275126UL, 3879559071UL, 711626863UL, 3267338158UL, 4095227658UL, 589002062UL, 137665950UL, 1190761134UL, 3823062902UL, 3566494128UL, 3914066872UL, +3233332246UL, 3844456625UL, 3240858503UL, 1081015168UL, 4148374722UL, 1683880703UL, 589447946UL, 4034899335UL, 733926790UL, 3520260556UL, 3643143173UL, 3202263729UL, 2130442867UL, 3472026294UL, 3518018860UL, 2319507998UL, 3458685425UL, 253769320UL, 1294634949UL, 3977318486UL, 3068540117UL, 702365700UL, 3100107703UL, 1988900647UL, 2936479173UL, 2348744493UL, 969926974UL, 477065277UL, 3746094733UL, 214260739UL, 3493892012UL, 2890740482UL, +52055911UL, 952871363UL, 1216985499UL, 2706067772UL, 1079370138UL, 2820619262UL, 1260334069UL, 2420035836UL, 311831945UL, 701108525UL, 2066128794UL, 3590716427UL, 537257045UL, 3153762469UL, 2900214585UL, 2261931254UL, 3644831936UL, 3243426619UL, 783551642UL, 3143067452UL, 3937339872UL, 3164955857UL, 4082645339UL, 1633544228UL, 1680728882UL, 3304461891UL, 204979344UL, 1674764841UL, 633231391UL, 689425572UL, 2649553051UL, 2534954734UL, +4252100558UL, 2993632630UL, 865432399UL, 3777379050UL, 1502035091UL, 302442688UL, 493504779UL, 1282312650UL, 1795212504UL, 1507727159UL, 672678623UL, 4046722895UL, 976003271UL, 2810951967UL, 441159654UL, 832039862UL, 2252252769UL, 726554843UL, 3317253399UL, 645344032UL, 2921087914UL, 2264738834UL, 1325395107UL, 1431934790UL, 737962654UL, 2859693559UL, 2784310535UL, 3876486226UL, 555655767UL, 3321631011UL, 641506549UL, 2652806878UL, +3848380198UL, 1837415425UL, 984807024UL, 1545504510UL, 1985586093UL, 3711682090UL, 2274320195UL, 127488455UL, 2254755902UL, 3789154730UL, 1595223697UL, 3812459919UL, 2160330513UL, 1888041043UL, 3105269579UL, 2773455385UL, 2341347785UL, 3185912634UL, 293292961UL, 1811276320UL, 3280464626UL, 825098089UL, 116883339UL, 2165628367UL, 4140133899UL, 3092114881UL, 4124720284UL, 4099344218UL, 1769871204UL, 721625457UL, 1514083147UL, 3598160577UL, +1218419978UL, 4163520111UL, 2316975723UL, 200993429UL, 923374392UL, 237254804UL, 3827063239UL, 3483118065UL, 677187089UL, 2263405553UL, 1020639813UL, 2131401627UL, 4167855065UL, 1892382552UL, 3382265961UL, 1887858126UL, 1599293552UL, 2389387938UL, 4153928364UL, 3440586186UL, 2096265248UL, 1834631738UL, 1585275126UL, 3348317504UL, 711626863UL, 3267338158UL, 4095227658UL, 589002062UL, 3125839176UL, 1190761134UL, 3823062902UL, 3566494128UL, +3914066872UL, 1320578396UL, 3844456625UL, 3240858503UL, 1081015168UL, 4148374722UL, 258762412UL, 589447946UL, 4034899335UL, 733926790UL, 3520260556UL, 4290301810UL, 3202263729UL, 2130442867UL, 3472026294UL, 3518018860UL, 2904238635UL, 3458685425UL, 253769320UL, 1294634949UL, 3977318486UL, 2517006218UL, 702365700UL, 3100107703UL, 1988900647UL, 2936479173UL, 3227096174UL, 969926974UL, 477065277UL, 3746094733UL, 214260739UL, 3868449115UL, +2890740482UL, 52055911UL, 952871363UL, 1216985499UL, 2857823043UL, 1079370138UL, 2820619262UL, 1260334069UL, 2420035836UL, 1843837226UL, 701108525UL, 2066128794UL, 3590716427UL, 537257045UL, 1202524172UL, 2900214585UL, 2261931254UL, 3644831936UL, 3243426619UL, 2113758468UL, 3143067452UL, 3937339872UL, 3164955857UL, 4082645339UL, 3987431298UL, 1680728882UL, 3304461891UL, 204979344UL, 1674764841UL, 2684386058UL, 689425572UL, 2649553051UL, +2534954734UL, 4252100558UL, 3511996574UL, 865432399UL, 3777379050UL, 1502035091UL, 302442688UL, 970989610UL, 1282312650UL, 1795212504UL, 1507727159UL, 672678623UL, 3080995547UL, 976003271UL, 2810951967UL, 441159654UL, 832039862UL, 2670291295UL, 726554843UL, 3317253399UL, 645344032UL, 2921087914UL, 3039207936UL, 1325395107UL, 1431934790UL, 737962654UL, 2859693559UL, 2452474228UL, 3876486226UL, 555655767UL, 3321631011UL, 641506549UL, +712394572UL, 931322445UL, 3691485988UL, 77755644UL, 3585967569UL, 1546642657UL, 1074481665UL, 1211742891UL, 2405208503UL, 1015438825UL, 3187019083UL, 2194891243UL, 1305917012UL, 3737279586UL, 2633137983UL, 1924729261UL, 72781059UL, 1412697099UL, 3828782214UL, 1637665425UL, 4170514983UL, 2248277352UL, 3793164712UL, 2365683667UL, 1287488796UL, 3240061130UL, 2411573225UL, 3237771995UL, 901649504UL, 4107276625UL, 1613775409UL, 741888560UL, +332459303UL, 850991886UL, 3249391248UL, 3550484151UL, 3689717953UL, 233288631UL, 2496730550UL, 3221264250UL, 3172144573UL, 1429937065UL, 1776357872UL, 1084763904UL, 1993209913UL, 4142869218UL, 3130780078UL, 18180577UL, 2819625557UL, 1978393449UL, 372704074UL, 3919523286UL, 1777756963UL, 188652529UL, 411213996UL, 62282979UL, 3775037518UL, 2534579861UL, 2966280971UL, 3863833471UL, 3228893189UL, 3123894696UL, 362579125UL, 1232030882UL, +575379775UL, 1019196436UL, 1914161190UL, 3649246842UL, 2192095564UL, 2368224476UL, 138396720UL, 1299868479UL, 507152626UL, 2129033575UL, 3801624222UL, 623352301UL, 1551535796UL, 3848329776UL, 2727905150UL, 1109499603UL, 3222756581UL, 3914846131UL, 3207366497UL, 3216028717UL, 3712661572UL, 1970542UL, 1320230637UL, 2583706801UL, 1341029904UL, 1903168049UL, 1244252579UL, 1885511879UL, 2426625042UL, 3082846847UL, 3858784104UL, 2263210027UL, +130350645UL, 956540733UL, 776729371UL, 2266749094UL, 2220603773UL, 2556170531UL, 263980324UL, 802194348UL, 697108594UL, 3634984969UL, 4251738712UL, 1831444758UL, 1209156358UL, 3089957258UL, 4195548426UL, 3641578987UL, 990686800UL, 2391278490UL, 2233755358UL, 1739784005UL, 2458544650UL, 340925249UL, 2442887806UL, 3503407512UL, 3058778909UL, 3619026333UL, 2289286518UL, 1296212011UL, 3879317178UL, 1210295163UL, 3113210467UL, 1578990986UL, +641384071UL, 2437977832UL, 1689385197UL, 1323268226UL, 861337916UL, 3532905860UL, 3735971843UL, 2294673483UL, 1032787575UL, 1868992735UL, 4260308791UL, 2091311463UL, 2354047234UL, 1005300697UL, 29821726UL, 2790044161UL, 3154591207UL, 1370229266UL, 3464848205UL, 3855301526UL, 544374401UL, 101012897UL, 4214903025UL, 1310520049UL, 14884434UL, 1438288148UL, 2118574986UL, 2360002070UL, 512167778UL, 4186534704UL, 3633828199UL, 493600836UL, +}, +{ +2932801042UL, 4101748508UL, 3363559072UL, 1213475638UL, 2400369070UL, 1726749444UL, 3175844814UL, 2600020277UL, 3779799804UL, 1886667522UL, 1228105891UL, 589138388UL, 3960459504UL, 450669757UL, 3773736740UL, 2107201112UL, 1437834675UL, 3618095315UL, 3662453347UL, 968349971UL, 1891706458UL, 2333451375UL, 4242907074UL, 3265111057UL, 3648168902UL, 4137035018UL, 105573058UL, 2075999861UL, 1053920954UL, 3768713177UL, 1836088599UL, 2015103258UL, +2649187541UL, 2717894301UL, 534937136UL, 3492326400UL, 2406499346UL, 617315838UL, 1384748442UL, 519804615UL, 524657043UL, 832148261UL, 156272480UL, 394759604UL, 2428809631UL, 3401589884UL, 2588359262UL, 3826333418UL, 2427993050UL, 3254067543UL, 2570694144UL, 2876613091UL, 2883884893UL, 613070434UL, 1599903665UL, 3476967713UL, 1729385632UL, 207879231UL, 1256308247UL, 2538975486UL, 2550001448UL, 1820975095UL, 915640692UL, 1633749116UL, +1294669585UL, 3257901643UL, 3193347552UL, 3369630539UL, 285165240UL, 2337727802UL, 1854640523UL, 1034379307UL, 1206304638UL, 889104297UL, 3084078942UL, 3485609519UL, 3903898589UL, 4274630316UL, 3290195566UL, 2071163950UL, 775170461UL, 551343738UL, 164916146UL, 1678786363UL, 123960948UL, 2721608023UL, 3463122611UL, 1525791510UL, 1531697627UL, 1457848578UL, 665433501UL, 1784274031UL, 3436850186UL, 3976095421UL, 383031580UL, 2146948399UL, +3137780800UL, 410458873UL, 381977170UL, 4264728702UL, 1515223147UL, 3358033956UL, 139804933UL, 438534588UL, 901342240UL, 1536972976UL, 184570377UL, 681864510UL, 844333847UL, 2515362910UL, 917461167UL, 2538721219UL, 4268394152UL, 680292330UL, 3420438710UL, 3784725677UL, 1983802086UL, 4165891809UL, 2369490764UL, 3808530114UL, 3391499460UL, 2509287180UL, 970129219UL, 2492785859UL, 3611863290UL, 1303524794UL, 2991964551UL, 1828774928UL, +3950385781UL, 3251583775UL, 14901408UL, 1890180396UL, 1306701779UL, 3161784071UL, 637842485UL, 2830070006UL, 3867491336UL, 1594948357UL, 2579795132UL, 479188700UL, 806498245UL, 3905876458UL, 3499065005UL, 3168076042UL, 769094339UL, 3769363696UL, 1241457026UL, 1073618847UL, 251335726UL, 2574341631UL, 2534047421UL, 3151952274UL, 534046859UL, 3264754113UL, 1325368288UL, 2131927230UL, 3229420672UL, 336348290UL, 3768781638UL, 2593952436UL, +849969290UL, 2932801042UL, 4101748508UL, 3363559072UL, 1213475638UL, 1710895496UL, 1726749444UL, 3175844814UL, 2600020277UL, 3779799804UL, 4044580435UL, 1228105891UL, 589138388UL, 3960459504UL, 450669757UL, 4253882965UL, 2107201112UL, 1437834675UL, 3618095315UL, 3662453347UL, 3625360228UL, 1891706458UL, 2333451375UL, 4242907074UL, 3265111057UL, 3638586625UL, 4137035018UL, 105573058UL, 2075999861UL, 1053920954UL, 3014895241UL, 1836088599UL, +2015103258UL, 2649187541UL, 2717894301UL, 701652515UL, 3492326400UL, 2406499346UL, 617315838UL, 1384748442UL, 1142040801UL, 524657043UL, 832148261UL, 156272480UL, 394759604UL, 944890908UL, 3401589884UL, 2588359262UL, 3826333418UL, 2427993050UL, 337891051UL, 2570694144UL, 2876613091UL, 2883884893UL, 613070434UL, 659063916UL, 3476967713UL, 1729385632UL, 207879231UL, 1256308247UL, 311608860UL, 2550001448UL, 1820975095UL, 915640692UL, +1633749116UL, 1772334285UL, 3257901643UL, 3193347552UL, 3369630539UL, 285165240UL, 2627441892UL, 1854640523UL, 1034379307UL, 1206304638UL, 889104297UL, 2289660031UL, 3485609519UL, 3903898589UL, 4274630316UL, 3290195566UL, 3572160580UL, 775170461UL, 551343738UL, 164916146UL, 1678786363UL, 3109616684UL, 2721608023UL, 3463122611UL, 1525791510UL, 1531697627UL, 3660976089UL, 665433501UL, 1784274031UL, 3436850186UL, 3976095421UL, 1696775162UL, +2146948399UL, 3137780800UL, 410458873UL, 381977170UL, 1669455215UL, 1515223147UL, 3358033956UL, 139804933UL, 438534588UL, 1738237971UL, 1536972976UL, 184570377UL, 681864510UL, 844333847UL, 770765754UL, 917461167UL, 2538721219UL, 4268394152UL, 680292330UL, 1993152157UL, 3784725677UL, 1983802086UL, 4165891809UL, 2369490764UL, 3411542022UL, 3391499460UL, 2509287180UL, 970129219UL, 2492785859UL, 1869391890UL, 1303524794UL, 2991964551UL, +1828774928UL, 3950385781UL, 4139486157UL, 14901408UL, 1890180396UL, 1306701779UL, 3161784071UL, 174545194UL, 2830070006UL, 3867491336UL, 1594948357UL, 2579795132UL, 4132973523UL, 806498245UL, 3905876458UL, 3499065005UL, 3168076042UL, 538076966UL, 3769363696UL, 1241457026UL, 1073618847UL, 251335726UL, 2085586137UL, 2534047421UL, 3151952274UL, 534046859UL, 3264754113UL, 643987981UL, 2131927230UL, 3229420672UL, 336348290UL, 3768781638UL, +3468816701UL, 849969290UL, 2932801042UL, 4101748508UL, 3363559072UL, 2524943673UL, 1710895496UL, 1726749444UL, 3175844814UL, 2600020277UL, 3677241699UL, 4044580435UL, 1228105891UL, 589138388UL, 3960459504UL, 3903077887UL, 4253882965UL, 2107201112UL, 1437834675UL, 3618095315UL, 2362822379UL, 3625360228UL, 1891706458UL, 2333451375UL, 4242907074UL, 2289503940UL, 3638586625UL, 4137035018UL, 105573058UL, 2075999861UL, 1299938293UL, 3014895241UL, +1836088599UL, 2015103258UL, 2649187541UL, 3727003343UL, 701652515UL, 3492326400UL, 2406499346UL, 617315838UL, 1627975589UL, 1142040801UL, 524657043UL, 832148261UL, 156272480UL, 3658645823UL, 944890908UL, 3401589884UL, 2588359262UL, 3826333418UL, 3645806126UL, 337891051UL, 2570694144UL, 2876613091UL, 2883884893UL, 2866570997UL, 659063916UL, 3476967713UL, 1729385632UL, 207879231UL, 298556768UL, 311608860UL, 2550001448UL, 1820975095UL, +915640692UL, 1014996737UL, 1772334285UL, 3257901643UL, 3193347552UL, 3369630539UL, 96395889UL, 2627441892UL, 1854640523UL, 1034379307UL, 1206304638UL, 2546521293UL, 2289660031UL, 3485609519UL, 3903898589UL, 4274630316UL, 2360048518UL, 3572160580UL, 775170461UL, 551343738UL, 164916146UL, 2068601014UL, 3109616684UL, 2721608023UL, 3463122611UL, 1525791510UL, 1228011534UL, 3660976089UL, 665433501UL, 1784274031UL, 3436850186UL, 1620580129UL, +1696775162UL, 2146948399UL, 3137780800UL, 410458873UL, 2753059283UL, 1669455215UL, 1515223147UL, 3358033956UL, 139804933UL, 2786429190UL, 1738237971UL, 1536972976UL, 184570377UL, 681864510UL, 358796749UL, 770765754UL, 917461167UL, 2538721219UL, 4268394152UL, 2355846025UL, 1993152157UL, 3784725677UL, 1983802086UL, 4165891809UL, 360259050UL, 3411542022UL, 3391499460UL, 2509287180UL, 970129219UL, 4055494275UL, 1869391890UL, 1303524794UL, +2991964551UL, 1828774928UL, 3508750618UL, 4139486157UL, 14901408UL, 1890180396UL, 1306701779UL, 3684762156UL, 174545194UL, 2830070006UL, 3867491336UL, 1594948357UL, 702781070UL, 4132973523UL, 806498245UL, 3905876458UL, 3499065005UL, 1372989388UL, 538076966UL, 3769363696UL, 1241457026UL, 1073618847UL, 3579114424UL, 2085586137UL, 2534047421UL, 3151952274UL, 534046859UL, 1882037168UL, 643987981UL, 2131927230UL, 3229420672UL, 336348290UL, +555833786UL, 3468816701UL, 849969290UL, 2932801042UL, 4101748508UL, 1095934625UL, 2524943673UL, 1710895496UL, 1726749444UL, 3175844814UL, 2287140069UL, 3677241699UL, 4044580435UL, 1228105891UL, 589138388UL, 1596938176UL, 3903077887UL, 4253882965UL, 2107201112UL, 1437834675UL, 2605388022UL, 2362822379UL, 3625360228UL, 1891706458UL, 2333451375UL, 174003035UL, 2289503940UL, 3638586625UL, 4137035018UL, 105573058UL, 697023108UL, 1299938293UL, +3014895241UL, 1836088599UL, 2015103258UL, 4128339205UL, 3727003343UL, 701652515UL, 3492326400UL, 2406499346UL, 426422678UL, 1627975589UL, 1142040801UL, 524657043UL, 832148261UL, 2461054373UL, 3658645823UL, 944890908UL, 3401589884UL, 2588359262UL, 3184255074UL, 3645806126UL, 337891051UL, 2570694144UL, 2876613091UL, 187151044UL, 2866570997UL, 659063916UL, 3476967713UL, 1729385632UL, 2811989057UL, 298556768UL, 311608860UL, 2550001448UL, +1820975095UL, 1806779934UL, 1014996737UL, 1772334285UL, 3257901643UL, 3193347552UL, 2145947779UL, 96395889UL, 2627441892UL, 1854640523UL, 1034379307UL, 2748996070UL, 2546521293UL, 2289660031UL, 3485609519UL, 3903898589UL, 452746826UL, 2360048518UL, 3572160580UL, 775170461UL, 551343738UL, 669098691UL, 2068601014UL, 3109616684UL, 2721608023UL, 3463122611UL, 22889155UL, 1228011534UL, 3660976089UL, 665433501UL, 1784274031UL, 227705324UL, +1620580129UL, 1696775162UL, 2146948399UL, 3137780800UL, 4267814323UL, 2753059283UL, 1669455215UL, 1515223147UL, 3358033956UL, 2806778033UL, 2786429190UL, 1738237971UL, 1536972976UL, 184570377UL, 3310279262UL, 358796749UL, 770765754UL, 917461167UL, 2538721219UL, 2247224091UL, 2355846025UL, 1993152157UL, 3784725677UL, 1983802086UL, 2399541755UL, 360259050UL, 3411542022UL, 3391499460UL, 2509287180UL, 2335541531UL, 4055494275UL, 1869391890UL, +1303524794UL, 2991964551UL, 392724462UL, 3508750618UL, 4139486157UL, 14901408UL, 1890180396UL, 2513331299UL, 3684762156UL, 174545194UL, 2830070006UL, 3867491336UL, 1887131931UL, 702781070UL, 4132973523UL, 806498245UL, 3905876458UL, 2263606492UL, 1372989388UL, 538076966UL, 3769363696UL, 1241457026UL, 170472774UL, 3579114424UL, 2085586137UL, 2534047421UL, 3151952274UL, 1488165272UL, 1882037168UL, 643987981UL, 2131927230UL, 3229420672UL, +1158405862UL, 1469009373UL, 4117356830UL, 4063868500UL, 2006417445UL, 2976934394UL, 2683607933UL, 3174943272UL, 2099974138UL, 2250858961UL, 205251124UL, 84783688UL, 1551294676UL, 224349432UL, 1893741756UL, 3680361724UL, 561624088UL, 251553631UL, 1654870642UL, 2195380145UL, 866503297UL, 1814519294UL, 905566144UL, 727763043UL, 1910034093UL, 1876316198UL, 3031876716UL, 2783769690UL, 2649650479UL, 2024342098UL, 2170858649UL, 2186613759UL, +2688207487UL, 881594599UL, 1010953695UL, 2768977700UL, 3341020856UL, 2446339960UL, 2648757147UL, 1317083878UL, 3301541769UL, 3574285525UL, 3331294407UL, 712581268UL, 3612116700UL, 3510601489UL, 2569879282UL, 3772968052UL, 332485239UL, 280920979UL, 716834274UL, 1863623285UL, 654670865UL, 1706917935UL, 1598315563UL, 2486805657UL, 2295746319UL, 635609792UL, 55141757UL, 4089183045UL, 145257162UL, 1921789879UL, 2833550514UL, 3798992859UL, +1532875864UL, 3668053062UL, 2749191097UL, 3412220447UL, 3383752088UL, 3191842833UL, 4167387125UL, 2438940746UL, 1453011669UL, 2747298308UL, 1057877757UL, 399006034UL, 132680506UL, 31671249UL, 1070386969UL, 2415113777UL, 3720335676UL, 3416473189UL, 1476808053UL, 785398955UL, 3335661823UL, 315496929UL, 1421907623UL, 1802371914UL, 3049258946UL, 1773374729UL, 382902076UL, 3262814446UL, 1774244917UL, 4064677234UL, 2281551331UL, 3019541390UL, +2445483046UL, 3059154103UL, 2147309319UL, 566587847UL, 216051987UL, 521013398UL, 2721884570UL, 3325443529UL, 1921922591UL, 1643064709UL, 1155714395UL, 1737031844UL, 2117338012UL, 1876262536UL, 3589621009UL, 3800806613UL, 1102108318UL, 1376914700UL, 539544394UL, 799741508UL, 1192097712UL, 2894663754UL, 567276527UL, 106814343UL, 3985577014UL, 422246623UL, 126568764UL, 4008211389UL, 4037889581UL, 2185357423UL, 2239644921UL, 2116447019UL, +1249715620UL, 2095747493UL, 4063243162UL, 3059330950UL, 1045571624UL, 1150656233UL, 3024439196UL, 3981904623UL, 1743764595UL, 4220253496UL, 3322182853UL, 2132911849UL, 2074342674UL, 198749193UL, 574306951UL, 3563262292UL, 3832626833UL, 2349475213UL, 182567249UL, 1530390173UL, 2066055611UL, 2609802571UL, 1392638962UL, 1495846580UL, 2356952332UL, 4029921749UL, 1731839848UL, 527880959UL, 1204112231UL, 938004695UL, 294300378UL, 1855457892UL, +}, +{ +1438083560UL, 1727969469UL, 703174449UL, 1296281193UL, 1386452240UL, 3304170302UL, 3048300096UL, 277697908UL, 2675939661UL, 3382564518UL, 1639425457UL, 2210719281UL, 3173605115UL, 1685375802UL, 1317820682UL, 1960916541UL, 4230888182UL, 1924357010UL, 3322827982UL, 1663716994UL, 976583570UL, 4146230815UL, 525755678UL, 3608894680UL, 1715438458UL, 1519478303UL, 2845291872UL, 1115405802UL, 2468673244UL, 2289739992UL, 46988928UL, 2559411080UL, +2466723374UL, 2995303634UL, 3871022237UL, 1794652692UL, 2424766096UL, 2849910020UL, 978542234UL, 1667051478UL, 3393290740UL, 1508376445UL, 4090541488UL, 1314139749UL, 1271060027UL, 3272019878UL, 4032394060UL, 757805987UL, 619143288UL, 1165760536UL, 225099797UL, 871754591UL, 2065691940UL, 2016593817UL, 1705071529UL, 2559080067UL, 2048856253UL, 3217759224UL, 2691334730UL, 1576829868UL, 3356759591UL, 1570481357UL, 1097065360UL, 852561431UL, +3559721965UL, 1403648739UL, 1772347635UL, 1196457607UL, 462142253UL, 761176322UL, 2209893444UL, 217724244UL, 3356132814UL, 2838131962UL, 3571552868UL, 1197135963UL, 3239010986UL, 2612283238UL, 2606429155UL, 2194090162UL, 4256137634UL, 935551404UL, 3057660021UL, 866672836UL, 1119670384UL, 1757615349UL, 649402076UL, 2814108193UL, 3312658713UL, 2627947214UL, 2982267121UL, 486762785UL, 2746076238UL, 2134737126UL, 4106010468UL, 3151832629UL, +2419694200UL, 2803791741UL, 2100250718UL, 3171079849UL, 1874606681UL, 1884940331UL, 926257211UL, 1940082331UL, 1024435222UL, 609478334UL, 2501896844UL, 518643063UL, 4285619138UL, 1054300997UL, 4024681853UL, 2287236199UL, 2891891855UL, 1519666047UL, 1919500932UL, 3880316442UL, 1994336737UL, 1025147784UL, 3433493260UL, 1647319600UL, 3298872174UL, 3744513628UL, 2918990402UL, 2649193481UL, 234630674UL, 1963357481UL, 1118148435UL, 2658522312UL, +2563194501UL, 2238556876UL, 1210050812UL, 748709882UL, 3894824022UL, 2575692519UL, 436044710UL, 3465014792UL, 3686094502UL, 2963529475UL, 3251316066UL, 2834750227UL, 789471563UL, 853201732UL, 4119014483UL, 1312738151UL, 2018934495UL, 542908921UL, 732294449UL, 2519981401UL, 1663929229UL, 4041419972UL, 3038382188UL, 3182489020UL, 353453260UL, 4074472601UL, 1187952022UL, 2118553383UL, 1068338764UL, 3699144039UL, 3129056770UL, 1419222328UL, +2666827910UL, 1438083560UL, 1727969469UL, 703174449UL, 1296281193UL, 2134413940UL, 3304170302UL, 3048300096UL, 277697908UL, 2675939661UL, 3817858752UL, 1639425457UL, 2210719281UL, 3173605115UL, 1685375802UL, 2587083472UL, 1960916541UL, 4230888182UL, 1924357010UL, 3322827982UL, 2582901426UL, 976583570UL, 4146230815UL, 525755678UL, 3608894680UL, 524232549UL, 1519478303UL, 2845291872UL, 1115405802UL, 2468673244UL, 591800699UL, 46988928UL, +2559411080UL, 2466723374UL, 2995303634UL, 2307625850UL, 1794652692UL, 2424766096UL, 2849910020UL, 978542234UL, 1284927074UL, 3393290740UL, 1508376445UL, 4090541488UL, 1314139749UL, 3508281898UL, 3272019878UL, 4032394060UL, 757805987UL, 619143288UL, 1846615167UL, 225099797UL, 871754591UL, 2065691940UL, 2016593817UL, 1193455869UL, 2559080067UL, 2048856253UL, 3217759224UL, 2691334730UL, 2665708717UL, 3356759591UL, 1570481357UL, 1097065360UL, +852561431UL, 1652864273UL, 1403648739UL, 1772347635UL, 1196457607UL, 462142253UL, 1222855287UL, 2209893444UL, 217724244UL, 3356132814UL, 2838131962UL, 3060983219UL, 1197135963UL, 3239010986UL, 2612283238UL, 2606429155UL, 4171729370UL, 4256137634UL, 935551404UL, 3057660021UL, 866672836UL, 75618353UL, 1757615349UL, 649402076UL, 2814108193UL, 3312658713UL, 3975515213UL, 2982267121UL, 486762785UL, 2746076238UL, 2134737126UL, 3251020123UL, +3151832629UL, 2419694200UL, 2803791741UL, 2100250718UL, 624531676UL, 1874606681UL, 1884940331UL, 926257211UL, 1940082331UL, 3678479182UL, 609478334UL, 2501896844UL, 518643063UL, 4285619138UL, 1725899979UL, 4024681853UL, 2287236199UL, 2891891855UL, 1519666047UL, 702508101UL, 3880316442UL, 1994336737UL, 1025147784UL, 3433493260UL, 4212959134UL, 3298872174UL, 3744513628UL, 2918990402UL, 2649193481UL, 1782150764UL, 1963357481UL, 1118148435UL, +2658522312UL, 2563194501UL, 3330122355UL, 1210050812UL, 748709882UL, 3894824022UL, 2575692519UL, 637240921UL, 3465014792UL, 3686094502UL, 2963529475UL, 3251316066UL, 1510158901UL, 789471563UL, 853201732UL, 4119014483UL, 1312738151UL, 3018953017UL, 542908921UL, 732294449UL, 2519981401UL, 1663929229UL, 2696317636UL, 3038382188UL, 3182489020UL, 353453260UL, 4074472601UL, 4249950407UL, 2118553383UL, 1068338764UL, 3699144039UL, 3129056770UL, +2334590922UL, 2666827910UL, 1438083560UL, 1727969469UL, 703174449UL, 1679528518UL, 2134413940UL, 3304170302UL, 3048300096UL, 277697908UL, 3417107827UL, 3817858752UL, 1639425457UL, 2210719281UL, 3173605115UL, 1858788112UL, 2587083472UL, 1960916541UL, 4230888182UL, 1924357010UL, 3692988029UL, 2582901426UL, 976583570UL, 4146230815UL, 525755678UL, 1122319464UL, 524232549UL, 1519478303UL, 2845291872UL, 1115405802UL, 205855120UL, 591800699UL, +46988928UL, 2559411080UL, 2466723374UL, 3358512221UL, 2307625850UL, 1794652692UL, 2424766096UL, 2849910020UL, 2865273283UL, 1284927074UL, 3393290740UL, 1508376445UL, 4090541488UL, 2453941323UL, 3508281898UL, 3272019878UL, 4032394060UL, 757805987UL, 3191753865UL, 1846615167UL, 225099797UL, 871754591UL, 2065691940UL, 1301630578UL, 1193455869UL, 2559080067UL, 2048856253UL, 3217759224UL, 3858428004UL, 2665708717UL, 3356759591UL, 1570481357UL, +1097065360UL, 3550687085UL, 1652864273UL, 1403648739UL, 1772347635UL, 1196457607UL, 2158802672UL, 1222855287UL, 2209893444UL, 217724244UL, 3356132814UL, 1954043011UL, 3060983219UL, 1197135963UL, 3239010986UL, 2612283238UL, 2156334822UL, 4171729370UL, 4256137634UL, 935551404UL, 3057660021UL, 3331206175UL, 75618353UL, 1757615349UL, 649402076UL, 2814108193UL, 1313890357UL, 3975515213UL, 2982267121UL, 486762785UL, 2746076238UL, 2023213803UL, +3251020123UL, 3151832629UL, 2419694200UL, 2803791741UL, 392313450UL, 624531676UL, 1874606681UL, 1884940331UL, 926257211UL, 3369012310UL, 3678479182UL, 609478334UL, 2501896844UL, 518643063UL, 3638013610UL, 1725899979UL, 4024681853UL, 2287236199UL, 2891891855UL, 429282096UL, 702508101UL, 3880316442UL, 1994336737UL, 1025147784UL, 1217486411UL, 4212959134UL, 3298872174UL, 3744513628UL, 2918990402UL, 1279832521UL, 1782150764UL, 1963357481UL, +1118148435UL, 2658522312UL, 2379123622UL, 3330122355UL, 1210050812UL, 748709882UL, 3894824022UL, 3987054169UL, 637240921UL, 3465014792UL, 3686094502UL, 2963529475UL, 2167876400UL, 1510158901UL, 789471563UL, 853201732UL, 4119014483UL, 1746447311UL, 3018953017UL, 542908921UL, 732294449UL, 2519981401UL, 1908715414UL, 2696317636UL, 3038382188UL, 3182489020UL, 353453260UL, 2132930364UL, 4249950407UL, 2118553383UL, 1068338764UL, 3699144039UL, +433893434UL, 2334590922UL, 2666827910UL, 1438083560UL, 1727969469UL, 1154725669UL, 1679528518UL, 2134413940UL, 3304170302UL, 3048300096UL, 31944135UL, 3417107827UL, 3817858752UL, 1639425457UL, 2210719281UL, 4203237786UL, 1858788112UL, 2587083472UL, 1960916541UL, 4230888182UL, 2712081548UL, 3692988029UL, 2582901426UL, 976583570UL, 4146230815UL, 3948659885UL, 1122319464UL, 524232549UL, 1519478303UL, 2845291872UL, 2881616509UL, 205855120UL, +591800699UL, 46988928UL, 2559411080UL, 3645011109UL, 3358512221UL, 2307625850UL, 1794652692UL, 2424766096UL, 3667888476UL, 2865273283UL, 1284927074UL, 3393290740UL, 1508376445UL, 1605429636UL, 2453941323UL, 3508281898UL, 3272019878UL, 4032394060UL, 3904681057UL, 3191753865UL, 1846615167UL, 225099797UL, 871754591UL, 696516502UL, 1301630578UL, 1193455869UL, 2559080067UL, 2048856253UL, 2589248412UL, 3858428004UL, 2665708717UL, 3356759591UL, +1570481357UL, 1884333722UL, 3550687085UL, 1652864273UL, 1403648739UL, 1772347635UL, 3418430008UL, 2158802672UL, 1222855287UL, 2209893444UL, 217724244UL, 4164333189UL, 1954043011UL, 3060983219UL, 1197135963UL, 3239010986UL, 2300947859UL, 2156334822UL, 4171729370UL, 4256137634UL, 935551404UL, 1258856668UL, 3331206175UL, 75618353UL, 1757615349UL, 649402076UL, 772455867UL, 1313890357UL, 3975515213UL, 2982267121UL, 486762785UL, 3671941628UL, +2023213803UL, 3251020123UL, 3151832629UL, 2419694200UL, 4264015999UL, 392313450UL, 624531676UL, 1874606681UL, 1884940331UL, 2460787316UL, 3369012310UL, 3678479182UL, 609478334UL, 2501896844UL, 2131090271UL, 3638013610UL, 1725899979UL, 4024681853UL, 2287236199UL, 455349830UL, 429282096UL, 702508101UL, 3880316442UL, 1994336737UL, 1727894434UL, 1217486411UL, 4212959134UL, 3298872174UL, 3744513628UL, 1120563681UL, 1279832521UL, 1782150764UL, +1963357481UL, 1118148435UL, 3362151087UL, 2379123622UL, 3330122355UL, 1210050812UL, 748709882UL, 2506587900UL, 3987054169UL, 637240921UL, 3465014792UL, 3686094502UL, 1265652315UL, 2167876400UL, 1510158901UL, 789471563UL, 853201732UL, 3472479264UL, 1746447311UL, 3018953017UL, 542908921UL, 732294449UL, 659090240UL, 1908715414UL, 2696317636UL, 3038382188UL, 3182489020UL, 174113867UL, 2132930364UL, 4249950407UL, 2118553383UL, 1068338764UL, +4115132848UL, 1714842877UL, 1153237667UL, 1015943026UL, 2014412384UL, 2478393613UL, 1340079052UL, 167685322UL, 1848482402UL, 3252973254UL, 638064461UL, 1599254200UL, 2525050247UL, 2813349060UL, 2415037971UL, 3274852801UL, 3415369586UL, 3216396500UL, 3147792606UL, 438338168UL, 2326605175UL, 2846648724UL, 3871841623UL, 287840506UL, 3218295001UL, 2562000356UL, 574276928UL, 418096348UL, 1798854554UL, 1913561074UL, 2025706546UL, 41907788UL, +3535708035UL, 1240819558UL, 208810147UL, 4062740265UL, 451865782UL, 2652508890UL, 3579720859UL, 1243967909UL, 2191937647UL, 2473947838UL, 1847359263UL, 2496539569UL, 4061942257UL, 1372849161UL, 2016697844UL, 1827460131UL, 1135062647UL, 1255573479UL, 3506657283UL, 3699699807UL, 3087913374UL, 1196140869UL, 4095306490UL, 830793530UL, 1289366065UL, 3268392251UL, 4119035690UL, 1631012325UL, 3410799501UL, 1470209122UL, 3057922764UL, 2895379380UL, +2654121201UL, 1984999545UL, 2258412956UL, 4267137150UL, 3396740662UL, 2480013857UL, 3845856317UL, 3669454152UL, 2438423716UL, 3191341994UL, 1571280634UL, 1423782557UL, 3279999352UL, 1886288620UL, 205278284UL, 793062897UL, 112852083UL, 69164746UL, 2218046933UL, 4206182754UL, 3021072495UL, 2157753215UL, 2875773583UL, 1453706073UL, 168681204UL, 3905840714UL, 4098714445UL, 3410804508UL, 1737239929UL, 1613207828UL, 2987997090UL, 1869303136UL, +3348561687UL, 3391148819UL, 1680062950UL, 4150476788UL, 2340622122UL, 11331065UL, 2250669421UL, 3003852975UL, 2145739501UL, 1627177260UL, 994260425UL, 1479134620UL, 2315299915UL, 1268765340UL, 285960682UL, 3801150032UL, 3948820512UL, 1677682247UL, 1735541155UL, 1914753931UL, 1965156079UL, 1875233710UL, 681418791UL, 2077804400UL, 1963479724UL, 2447942398UL, 269798686UL, 2740088859UL, 1974178779UL, 3373487761UL, 2879779843UL, 157827737UL, +3855390825UL, 2779173093UL, 2359181541UL, 3508102362UL, 4001266348UL, 3949912729UL, 3232414439UL, 472195874UL, 57835121UL, 1854343116UL, 3020785997UL, 2024437594UL, 2182964208UL, 3379376555UL, 1213864603UL, 307833006UL, 1029130725UL, 545051507UL, 4001695571UL, 2258480284UL, 896286117UL, 355474524UL, 2514583184UL, 2997458384UL, 3278715462UL, 1675341954UL, 3603020014UL, 2318410671UL, 2152785892UL, 4285597912UL, 35655711UL, 2087100216UL, +}, +{ +1671155UL, 472949658UL, 148656515UL, 1640075411UL, 930771231UL, 1601854390UL, 471598090UL, 2013359012UL, 3708325970UL, 1688441844UL, 736452516UL, 100585026UL, 1154373750UL, 4029833741UL, 3409420465UL, 192349301UL, 3804215437UL, 909027311UL, 2896874106UL, 3567276364UL, 1319305666UL, 3858990362UL, 3155018279UL, 3756192170UL, 3567813642UL, 228734829UL, 577956164UL, 2078807284UL, 1005987081UL, 1464380935UL, 112604551UL, 3865074232UL, +3776350052UL, 1112767766UL, 2947509331UL, 910887552UL, 4127297396UL, 851240323UL, 3136588838UL, 1639013085UL, 1154068086UL, 639126620UL, 2501600773UL, 3174842042UL, 3456593672UL, 80596481UL, 126970446UL, 2184239961UL, 1448001095UL, 689252599UL, 1087028487UL, 2905348107UL, 2502009404UL, 2156595397UL, 2149975474UL, 2201723284UL, 3908202640UL, 754508313UL, 2321393187UL, 787043244UL, 2575809693UL, 4172462501UL, 2322897687UL, 1899992264UL, +1854136781UL, 3575249683UL, 2939319477UL, 901605762UL, 676398674UL, 2849283587UL, 2992300101UL, 1513271778UL, 2797164148UL, 1914019034UL, 1889341710UL, 2739211008UL, 1954453463UL, 3279391005UL, 2899313529UL, 1412533980UL, 1291505093UL, 2884603001UL, 564097935UL, 3552741248UL, 2809901827UL, 1263126330UL, 860214490UL, 2168366043UL, 2681035029UL, 3226888214UL, 2902522885UL, 554804421UL, 1571065517UL, 3322453053UL, 4144256215UL, 126415290UL, +980853251UL, 1531963815UL, 3237470129UL, 1465444883UL, 2031491001UL, 2205009469UL, 1046577915UL, 828927962UL, 2170245718UL, 1090142292UL, 1667375106UL, 2522840205UL, 4047872402UL, 3862734726UL, 91588630UL, 3122782857UL, 929883614UL, 694999008UL, 1472139068UL, 1246663706UL, 3500613893UL, 4200173807UL, 186199942UL, 3890621040UL, 229752655UL, 1011692880UL, 2791828564UL, 2677625011UL, 791005643UL, 1754509337UL, 2321492983UL, 3512328605UL, +1294405891UL, 2845189858UL, 434175992UL, 3155484007UL, 2306406482UL, 3197931140UL, 22971924UL, 1521633702UL, 2366802562UL, 399245037UL, 2833224222UL, 2507478835UL, 3231711673UL, 3784114896UL, 1927919696UL, 783802899UL, 3408133710UL, 2278711709UL, 3001078924UL, 1223320630UL, 3246830042UL, 943189685UL, 4062534962UL, 1039971013UL, 2342241593UL, 3551623946UL, 322017346UL, 3585779636UL, 81127429UL, 3549929990UL, 2886997195UL, 1746081951UL, +4169018554UL, 1671155UL, 472949658UL, 148656515UL, 1640075411UL, 3772042754UL, 1601854390UL, 471598090UL, 2013359012UL, 3708325970UL, 321630853UL, 736452516UL, 100585026UL, 1154373750UL, 4029833741UL, 1926754199UL, 192349301UL, 3804215437UL, 909027311UL, 2896874106UL, 1138131968UL, 1319305666UL, 3858990362UL, 3155018279UL, 3756192170UL, 2489094664UL, 228734829UL, 577956164UL, 2078807284UL, 1005987081UL, 2678967510UL, 112604551UL, +3865074232UL, 3776350052UL, 1112767766UL, 626049886UL, 910887552UL, 4127297396UL, 851240323UL, 3136588838UL, 2142891352UL, 1154068086UL, 639126620UL, 2501600773UL, 3174842042UL, 3342870442UL, 80596481UL, 126970446UL, 2184239961UL, 1448001095UL, 3399719246UL, 1087028487UL, 2905348107UL, 2502009404UL, 2156595397UL, 14860817UL, 2201723284UL, 3908202640UL, 754508313UL, 2321393187UL, 90540547UL, 2575809693UL, 4172462501UL, 2322897687UL, +1899992264UL, 56239065UL, 3575249683UL, 2939319477UL, 901605762UL, 676398674UL, 412461711UL, 2992300101UL, 1513271778UL, 2797164148UL, 1914019034UL, 3660190396UL, 2739211008UL, 1954453463UL, 3279391005UL, 2899313529UL, 4193503742UL, 1291505093UL, 2884603001UL, 564097935UL, 3552741248UL, 2124229268UL, 1263126330UL, 860214490UL, 2168366043UL, 2681035029UL, 4086980935UL, 2902522885UL, 554804421UL, 1571065517UL, 3322453053UL, 1821678887UL, +126415290UL, 980853251UL, 1531963815UL, 3237470129UL, 2099629264UL, 2031491001UL, 2205009469UL, 1046577915UL, 828927962UL, 3447807375UL, 1090142292UL, 1667375106UL, 2522840205UL, 4047872402UL, 2255362927UL, 91588630UL, 3122782857UL, 929883614UL, 694999008UL, 4135967848UL, 1246663706UL, 3500613893UL, 4200173807UL, 186199942UL, 4182379872UL, 229752655UL, 1011692880UL, 2791828564UL, 2677625011UL, 397062412UL, 1754509337UL, 2321492983UL, +3512328605UL, 1294405891UL, 1028843071UL, 434175992UL, 3155484007UL, 2306406482UL, 3197931140UL, 3217107401UL, 1521633702UL, 2366802562UL, 399245037UL, 2833224222UL, 76017436UL, 3231711673UL, 3784114896UL, 1927919696UL, 783802899UL, 2157090897UL, 2278711709UL, 3001078924UL, 1223320630UL, 3246830042UL, 1197195551UL, 4062534962UL, 1039971013UL, 2342241593UL, 3551623946UL, 63853850UL, 3585779636UL, 81127429UL, 3549929990UL, 2886997195UL, +1335910186UL, 4169018554UL, 1671155UL, 472949658UL, 148656515UL, 3600963048UL, 3772042754UL, 1601854390UL, 471598090UL, 2013359012UL, 1181513377UL, 321630853UL, 736452516UL, 100585026UL, 1154373750UL, 2323956092UL, 1926754199UL, 192349301UL, 3804215437UL, 909027311UL, 2993842723UL, 1138131968UL, 1319305666UL, 3858990362UL, 3155018279UL, 2288945270UL, 2489094664UL, 228734829UL, 577956164UL, 2078807284UL, 1924581773UL, 2678967510UL, +112604551UL, 3865074232UL, 3776350052UL, 2127459222UL, 626049886UL, 910887552UL, 4127297396UL, 851240323UL, 547797457UL, 2142891352UL, 1154068086UL, 639126620UL, 2501600773UL, 2391654498UL, 3342870442UL, 80596481UL, 126970446UL, 2184239961UL, 824575673UL, 3399719246UL, 1087028487UL, 2905348107UL, 2502009404UL, 740197255UL, 14860817UL, 2201723284UL, 3908202640UL, 754508313UL, 4133980283UL, 90540547UL, 2575809693UL, 4172462501UL, +2322897687UL, 831222037UL, 56239065UL, 3575249683UL, 2939319477UL, 901605762UL, 1998632674UL, 412461711UL, 2992300101UL, 1513271778UL, 2797164148UL, 969149327UL, 3660190396UL, 2739211008UL, 1954453463UL, 3279391005UL, 1267183547UL, 4193503742UL, 1291505093UL, 2884603001UL, 564097935UL, 3378471970UL, 2124229268UL, 1263126330UL, 860214490UL, 2168366043UL, 867190357UL, 4086980935UL, 2902522885UL, 554804421UL, 1571065517UL, 497580674UL, +1821678887UL, 126415290UL, 980853251UL, 1531963815UL, 2259090956UL, 2099629264UL, 2031491001UL, 2205009469UL, 1046577915UL, 30458798UL, 3447807375UL, 1090142292UL, 1667375106UL, 2522840205UL, 748518306UL, 2255362927UL, 91588630UL, 3122782857UL, 929883614UL, 1016302700UL, 4135967848UL, 1246663706UL, 3500613893UL, 4200173807UL, 4149573092UL, 4182379872UL, 229752655UL, 1011692880UL, 2791828564UL, 2890696349UL, 397062412UL, 1754509337UL, +2321492983UL, 3512328605UL, 3005148093UL, 1028843071UL, 434175992UL, 3155484007UL, 2306406482UL, 1417194283UL, 3217107401UL, 1521633702UL, 2366802562UL, 399245037UL, 665389310UL, 76017436UL, 3231711673UL, 3784114896UL, 1927919696UL, 37004463UL, 2157090897UL, 2278711709UL, 3001078924UL, 1223320630UL, 1281902891UL, 1197195551UL, 4062534962UL, 1039971013UL, 2342241593UL, 836721481UL, 63853850UL, 3585779636UL, 81127429UL, 3549929990UL, +2541553478UL, 1335910186UL, 4169018554UL, 1671155UL, 472949658UL, 2086411677UL, 3600963048UL, 3772042754UL, 1601854390UL, 471598090UL, 3297781744UL, 1181513377UL, 321630853UL, 736452516UL, 100585026UL, 2296508711UL, 2323956092UL, 1926754199UL, 192349301UL, 3804215437UL, 314399580UL, 2993842723UL, 1138131968UL, 1319305666UL, 3858990362UL, 584746730UL, 2288945270UL, 2489094664UL, 228734829UL, 577956164UL, 3868048239UL, 1924581773UL, +2678967510UL, 112604551UL, 3865074232UL, 2091950990UL, 2127459222UL, 626049886UL, 910887552UL, 4127297396UL, 2494071916UL, 547797457UL, 2142891352UL, 1154068086UL, 639126620UL, 1159991153UL, 2391654498UL, 3342870442UL, 80596481UL, 126970446UL, 2276453681UL, 824575673UL, 3399719246UL, 1087028487UL, 2905348107UL, 874278393UL, 740197255UL, 14860817UL, 2201723284UL, 3908202640UL, 1189317351UL, 4133980283UL, 90540547UL, 2575809693UL, +4172462501UL, 746169572UL, 831222037UL, 56239065UL, 3575249683UL, 2939319477UL, 4148988439UL, 1998632674UL, 412461711UL, 2992300101UL, 1513271778UL, 1078781767UL, 969149327UL, 3660190396UL, 2739211008UL, 1954453463UL, 369522045UL, 1267183547UL, 4193503742UL, 1291505093UL, 2884603001UL, 2820350438UL, 3378471970UL, 2124229268UL, 1263126330UL, 860214490UL, 793306335UL, 867190357UL, 4086980935UL, 2902522885UL, 554804421UL, 1472297125UL, +497580674UL, 1821678887UL, 126415290UL, 980853251UL, 1628231485UL, 2259090956UL, 2099629264UL, 2031491001UL, 2205009469UL, 2562996945UL, 30458798UL, 3447807375UL, 1090142292UL, 1667375106UL, 3513508401UL, 748518306UL, 2255362927UL, 91588630UL, 3122782857UL, 435869165UL, 1016302700UL, 4135967848UL, 1246663706UL, 3500613893UL, 4156110437UL, 4149573092UL, 4182379872UL, 229752655UL, 1011692880UL, 1150278253UL, 2890696349UL, 397062412UL, +1754509337UL, 2321492983UL, 1126835971UL, 3005148093UL, 1028843071UL, 434175992UL, 3155484007UL, 4169948411UL, 1417194283UL, 3217107401UL, 1521633702UL, 2366802562UL, 1629830655UL, 665389310UL, 76017436UL, 3231711673UL, 3784114896UL, 2523153991UL, 37004463UL, 2157090897UL, 2278711709UL, 3001078924UL, 3770048208UL, 1281902891UL, 1197195551UL, 4062534962UL, 1039971013UL, 2710590100UL, 836721481UL, 63853850UL, 3585779636UL, 81127429UL, +3850118466UL, 1883009417UL, 1027645619UL, 2766570701UL, 529436174UL, 4182542040UL, 2027954186UL, 1551970336UL, 2476537298UL, 1601343216UL, 3847258834UL, 14764974UL, 2173280370UL, 4148127270UL, 2818930089UL, 4238274314UL, 1291010651UL, 276452076UL, 192067464UL, 4086351393UL, 37573517UL, 48008720UL, 1641547972UL, 3144774960UL, 2159884108UL, 4260412239UL, 4072883650UL, 801704944UL, 2475958420UL, 2719220408UL, 555871884UL, 3338968445UL, +1704817873UL, 1960791083UL, 3785650808UL, 948722806UL, 3591229899UL, 1776225011UL, 4086658524UL, 2675451845UL, 308053697UL, 3514232055UL, 2575301108UL, 1970226110UL, 3926325352UL, 770275431UL, 1432667716UL, 671201644UL, 1008866625UL, 1151827040UL, 11061406UL, 3492749345UL, 2398090284UL, 2479688660UL, 2275263177UL, 2452696627UL, 3239880878UL, 3206200433UL, 1520851097UL, 1517432473UL, 1468198490UL, 1756343506UL, 2477348626UL, 3684701600UL, +3173720911UL, 1034531154UL, 4092116810UL, 3546516359UL, 2085136160UL, 643024588UL, 1462240654UL, 1877398196UL, 3615581878UL, 1419408410UL, 3581360976UL, 1731324772UL, 1377343320UL, 3848152825UL, 2213533588UL, 2484549569UL, 2043594863UL, 224490427UL, 1298974897UL, 4279011954UL, 3970331393UL, 3795364604UL, 285230552UL, 2893090686UL, 2399312639UL, 2638905215UL, 3481427245UL, 3477537504UL, 2609821731UL, 867675919UL, 3395750357UL, 1969593211UL, +2390932014UL, 3164333009UL, 3032345429UL, 3054196992UL, 1655295657UL, 193598641UL, 1267960637UL, 1599091894UL, 3377410805UL, 1529073346UL, 1949183620UL, 1575927573UL, 1493246650UL, 2285478895UL, 797817618UL, 1736047766UL, 1537439339UL, 1422940895UL, 2210817855UL, 2888194544UL, 800138109UL, 1689425315UL, 87966703UL, 3800446188UL, 137301285UL, 3334431104UL, 1776710491UL, 4010349050UL, 2577018472UL, 3083459223UL, 672158271UL, 3379478560UL, +2445459713UL, 918903140UL, 2577376693UL, 273150303UL, 2300393435UL, 3529750006UL, 3941920515UL, 2590879584UL, 2005940914UL, 2533952036UL, 2918638361UL, 1907638097UL, 959011520UL, 1477207871UL, 2141548481UL, 2065858781UL, 3145892196UL, 3679867589UL, 1295127682UL, 1325838381UL, 3482593404UL, 1212565985UL, 3404887017UL, 709111097UL, 1714185234UL, 561489165UL, 3545430079UL, 359778601UL, 3034684349UL, 2235482356UL, 2263913966UL, 1397371482UL, +}, +{ +170295791UL, 2753410803UL, 2200994594UL, 14686027UL, 3460333923UL, 1523230564UL, 393272614UL, 1632665034UL, 2139771608UL, 2436912103UL, 375335282UL, 667585308UL, 3651645415UL, 1403132103UL, 4146144245UL, 786890392UL, 1349234364UL, 1278024517UL, 84921263UL, 3758850381UL, 4213552796UL, 2355655048UL, 1636349912UL, 172797504UL, 2490691729UL, 1233059003UL, 2593048824UL, 942056581UL, 953415060UL, 4250104075UL, 787552244UL, 1995239637UL, +2482815609UL, 767530774UL, 773778243UL, 841396894UL, 2718419035UL, 3363828032UL, 737774143UL, 4128182656UL, 2335090807UL, 1421795969UL, 2322011430UL, 2808330380UL, 2207840656UL, 1646731611UL, 492284258UL, 2339383764UL, 3439685708UL, 2316859204UL, 4055048437UL, 1700143892UL, 2980557654UL, 1353917552UL, 548777318UL, 1077538998UL, 2650679367UL, 2853583947UL, 2721899692UL, 4253535213UL, 3375043688UL, 3489699354UL, 2401362855UL, 3391605246UL, +914273272UL, 3060460082UL, 1409014396UL, 3313834796UL, 461914731UL, 82334736UL, 3200344474UL, 2743316601UL, 842885927UL, 613943741UL, 96056919UL, 3116963503UL, 305659983UL, 132158360UL, 239064402UL, 849530381UL, 543215927UL, 4250983939UL, 2719881954UL, 1950301886UL, 2760008207UL, 853237881UL, 3875675156UL, 1753566841UL, 1446648300UL, 1663885236UL, 2155720472UL, 1902508987UL, 4246118829UL, 383661834UL, 2420221467UL, 156828838UL, +2919782856UL, 499968148UL, 2538550321UL, 65231340UL, 1589837081UL, 3654438263UL, 467304037UL, 1000159563UL, 622643461UL, 1410713407UL, 491953742UL, 1003597552UL, 1972701846UL, 1534343952UL, 1934888620UL, 4214562113UL, 4154375443UL, 3612899079UL, 2132948514UL, 2599819225UL, 2676649952UL, 3147375990UL, 533258319UL, 3323553423UL, 4203909276UL, 668602384UL, 3979162921UL, 2360530772UL, 162121513UL, 8968884UL, 3647746035UL, 2830313226UL, +1736955603UL, 78142012UL, 1643270604UL, 1571637938UL, 4065571991UL, 2071640825UL, 2715113082UL, 3826814783UL, 1067370024UL, 1810581550UL, 2354204343UL, 3798962263UL, 1664654967UL, 3740539785UL, 3746164996UL, 4280983219UL, 3313400832UL, 3305556349UL, 4226011346UL, 839676594UL, 1785445494UL, 1248107478UL, 904240268UL, 3484988721UL, 2290931247UL, 2109493967UL, 3895901626UL, 1494555863UL, 3251796061UL, 40877237UL, 2914051470UL, 2810210896UL, +1428826975UL, 170295791UL, 2753410803UL, 2200994594UL, 14686027UL, 3263438011UL, 1523230564UL, 393272614UL, 1632665034UL, 2139771608UL, 1847095655UL, 375335282UL, 667585308UL, 3651645415UL, 1403132103UL, 1888152231UL, 786890392UL, 1349234364UL, 1278024517UL, 84921263UL, 317409190UL, 4213552796UL, 2355655048UL, 1636349912UL, 172797504UL, 891435579UL, 1233059003UL, 2593048824UL, 942056581UL, 953415060UL, 1606837225UL, 787552244UL, +1995239637UL, 2482815609UL, 767530774UL, 723338833UL, 841396894UL, 2718419035UL, 3363828032UL, 737774143UL, 1043554448UL, 2335090807UL, 1421795969UL, 2322011430UL, 2808330380UL, 2754923978UL, 1646731611UL, 492284258UL, 2339383764UL, 3439685708UL, 3985616488UL, 4055048437UL, 1700143892UL, 2980557654UL, 1353917552UL, 588678041UL, 1077538998UL, 2650679367UL, 2853583947UL, 2721899692UL, 992549416UL, 3375043688UL, 3489699354UL, 2401362855UL, +3391605246UL, 2111206241UL, 3060460082UL, 1409014396UL, 3313834796UL, 461914731UL, 749987143UL, 3200344474UL, 2743316601UL, 842885927UL, 613943741UL, 1572013294UL, 3116963503UL, 305659983UL, 132158360UL, 239064402UL, 2802105766UL, 543215927UL, 4250983939UL, 2719881954UL, 1950301886UL, 1025784309UL, 853237881UL, 3875675156UL, 1753566841UL, 1446648300UL, 2265992307UL, 2155720472UL, 1902508987UL, 4246118829UL, 383661834UL, 1291267638UL, +156828838UL, 2919782856UL, 499968148UL, 2538550321UL, 2108151330UL, 1589837081UL, 3654438263UL, 467304037UL, 1000159563UL, 611554173UL, 1410713407UL, 491953742UL, 1003597552UL, 1972701846UL, 1548061756UL, 1934888620UL, 4214562113UL, 4154375443UL, 3612899079UL, 3599839935UL, 2599819225UL, 2676649952UL, 3147375990UL, 533258319UL, 4213499273UL, 4203909276UL, 668602384UL, 3979162921UL, 2360530772UL, 197252548UL, 8968884UL, 3647746035UL, +2830313226UL, 1736955603UL, 791687787UL, 1643270604UL, 1571637938UL, 4065571991UL, 2071640825UL, 2026290282UL, 3826814783UL, 1067370024UL, 1810581550UL, 2354204343UL, 2679791787UL, 1664654967UL, 3740539785UL, 3746164996UL, 4280983219UL, 1690075221UL, 3305556349UL, 4226011346UL, 839676594UL, 1785445494UL, 935893161UL, 904240268UL, 3484988721UL, 2290931247UL, 2109493967UL, 1497667362UL, 1494555863UL, 3251796061UL, 40877237UL, 2914051470UL, +1936503212UL, 1428826975UL, 170295791UL, 2753410803UL, 2200994594UL, 3416506072UL, 3263438011UL, 1523230564UL, 393272614UL, 1632665034UL, 3223475136UL, 1847095655UL, 375335282UL, 667585308UL, 3651645415UL, 1628711405UL, 1888152231UL, 786890392UL, 1349234364UL, 1278024517UL, 3955811679UL, 317409190UL, 4213552796UL, 2355655048UL, 1636349912UL, 2875036620UL, 891435579UL, 1233059003UL, 2593048824UL, 942056581UL, 2852399035UL, 1606837225UL, +787552244UL, 1995239637UL, 2482815609UL, 3849697041UL, 723338833UL, 841396894UL, 2718419035UL, 3363828032UL, 2914796626UL, 1043554448UL, 2335090807UL, 1421795969UL, 2322011430UL, 1088985845UL, 2754923978UL, 1646731611UL, 492284258UL, 2339383764UL, 2345741058UL, 3985616488UL, 4055048437UL, 1700143892UL, 2980557654UL, 3047950756UL, 588678041UL, 1077538998UL, 2650679367UL, 2853583947UL, 1902113580UL, 992549416UL, 3375043688UL, 3489699354UL, +2401362855UL, 2822431025UL, 2111206241UL, 3060460082UL, 1409014396UL, 3313834796UL, 3661696135UL, 749987143UL, 3200344474UL, 2743316601UL, 842885927UL, 3902266797UL, 1572013294UL, 3116963503UL, 305659983UL, 132158360UL, 2399116869UL, 2802105766UL, 543215927UL, 4250983939UL, 2719881954UL, 1909593430UL, 1025784309UL, 853237881UL, 3875675156UL, 1753566841UL, 315928539UL, 2265992307UL, 2155720472UL, 1902508987UL, 4246118829UL, 4054781820UL, +1291267638UL, 156828838UL, 2919782856UL, 499968148UL, 2746436642UL, 2108151330UL, 1589837081UL, 3654438263UL, 467304037UL, 2376244866UL, 611554173UL, 1410713407UL, 491953742UL, 1003597552UL, 961109680UL, 1548061756UL, 1934888620UL, 4214562113UL, 4154375443UL, 3318608531UL, 3599839935UL, 2599819225UL, 2676649952UL, 3147375990UL, 3197943734UL, 4213499273UL, 4203909276UL, 668602384UL, 3979162921UL, 4241359084UL, 197252548UL, 8968884UL, +3647746035UL, 2830313226UL, 2057817762UL, 791687787UL, 1643270604UL, 1571637938UL, 4065571991UL, 961587641UL, 2026290282UL, 3826814783UL, 1067370024UL, 1810581550UL, 1525669339UL, 2679791787UL, 1664654967UL, 3740539785UL, 3746164996UL, 3971185743UL, 1690075221UL, 3305556349UL, 4226011346UL, 839676594UL, 4017546432UL, 935893161UL, 904240268UL, 3484988721UL, 2290931247UL, 2887434676UL, 1497667362UL, 1494555863UL, 3251796061UL, 40877237UL, +675451622UL, 1936503212UL, 1428826975UL, 170295791UL, 2753410803UL, 13691728UL, 3416506072UL, 3263438011UL, 1523230564UL, 393272614UL, 2875584734UL, 3223475136UL, 1847095655UL, 375335282UL, 667585308UL, 192306502UL, 1628711405UL, 1888152231UL, 786890392UL, 1349234364UL, 511851370UL, 3955811679UL, 317409190UL, 4213552796UL, 2355655048UL, 131052067UL, 2875036620UL, 891435579UL, 1233059003UL, 2593048824UL, 2915307792UL, 2852399035UL, +1606837225UL, 787552244UL, 1995239637UL, 886016481UL, 3849697041UL, 723338833UL, 841396894UL, 2718419035UL, 1765948302UL, 2914796626UL, 1043554448UL, 2335090807UL, 1421795969UL, 4270899906UL, 1088985845UL, 2754923978UL, 1646731611UL, 492284258UL, 1723935335UL, 2345741058UL, 3985616488UL, 4055048437UL, 1700143892UL, 2254566160UL, 3047950756UL, 588678041UL, 1077538998UL, 2650679367UL, 1004539894UL, 1902113580UL, 992549416UL, 3375043688UL, +3489699354UL, 2030140735UL, 2822431025UL, 2111206241UL, 3060460082UL, 1409014396UL, 3053214877UL, 3661696135UL, 749987143UL, 3200344474UL, 2743316601UL, 398855857UL, 3902266797UL, 1572013294UL, 3116963503UL, 305659983UL, 1626072332UL, 2399116869UL, 2802105766UL, 543215927UL, 4250983939UL, 1149058742UL, 1909593430UL, 1025784309UL, 853237881UL, 3875675156UL, 2709854504UL, 315928539UL, 2265992307UL, 2155720472UL, 1902508987UL, 4065691077UL, +4054781820UL, 1291267638UL, 156828838UL, 2919782856UL, 1004764391UL, 2746436642UL, 2108151330UL, 1589837081UL, 3654438263UL, 2380382984UL, 2376244866UL, 611554173UL, 1410713407UL, 491953742UL, 3149407591UL, 961109680UL, 1548061756UL, 1934888620UL, 4214562113UL, 1555853416UL, 3318608531UL, 3599839935UL, 2599819225UL, 2676649952UL, 1902647993UL, 3197943734UL, 4213499273UL, 4203909276UL, 668602384UL, 2188341510UL, 4241359084UL, 197252548UL, +8968884UL, 3647746035UL, 629654524UL, 2057817762UL, 791687787UL, 1643270604UL, 1571637938UL, 3066487639UL, 961587641UL, 2026290282UL, 3826814783UL, 1067370024UL, 2223613942UL, 1525669339UL, 2679791787UL, 1664654967UL, 3740539785UL, 3902060288UL, 3971185743UL, 1690075221UL, 3305556349UL, 4226011346UL, 3135081672UL, 4017546432UL, 935893161UL, 904240268UL, 3484988721UL, 2448752416UL, 2887434676UL, 1497667362UL, 1494555863UL, 3251796061UL, +1037186927UL, 1608759110UL, 3873834254UL, 59242551UL, 487334743UL, 2580513180UL, 3704829028UL, 3859157573UL, 3452402004UL, 783668920UL, 2394905786UL, 3179497902UL, 2576105629UL, 1552362163UL, 2138613992UL, 224944469UL, 3876873579UL, 3402518289UL, 1709606949UL, 4255868112UL, 1249055439UL, 3395879908UL, 2957760102UL, 346905231UL, 590629983UL, 1171021480UL, 4051081465UL, 3913643946UL, 3115845768UL, 1021908139UL, 2556028362UL, 3828177651UL, +2870156105UL, 899722025UL, 661756192UL, 3775551864UL, 1288569751UL, 3751947667UL, 3064664685UL, 2559273148UL, 2660772417UL, 2448044253UL, 3054357327UL, 3434913868UL, 1444728572UL, 3010819186UL, 3010362527UL, 1709131033UL, 3425689752UL, 2849921358UL, 3518017065UL, 3845809665UL, 3245724553UL, 1008739837UL, 3274032925UL, 2567688974UL, 1981389077UL, 1108638127UL, 470206543UL, 1097339633UL, 1714430226UL, 2321268672UL, 1149373331UL, 294569671UL, +4264586290UL, 4270574127UL, 2522456947UL, 230975563UL, 131504269UL, 541738544UL, 1380704847UL, 2946408074UL, 282744860UL, 246858261UL, 2037373985UL, 1769191691UL, 2174871838UL, 2097427065UL, 492251656UL, 1252290304UL, 3616248100UL, 3213248383UL, 1847973756UL, 647347869UL, 3015847616UL, 299045987UL, 866593289UL, 2009367463UL, 2448831631UL, 337965200UL, 1210654808UL, 1694878225UL, 853507918UL, 3373825966UL, 4262812941UL, 4279525028UL, +338822858UL, 1038097567UL, 3996799911UL, 755960212UL, 149304151UL, 1599868486UL, 4021605447UL, 3040297322UL, 3891899828UL, 1711866076UL, 900840696UL, 3675688669UL, 3070862438UL, 2611308185UL, 2359948129UL, 1158552196UL, 2094484627UL, 3077606843UL, 2119537593UL, 427023787UL, 3632076073UL, 2670551310UL, 3396099733UL, 1066081183UL, 1817788918UL, 324769315UL, 656687887UL, 202117575UL, 3106428593UL, 3730407212UL, 1661316263UL, 1215084998UL, +2025391552UL, 664352483UL, 1914686594UL, 9439399UL, 2548190484UL, 3127972014UL, 4008228378UL, 2645735658UL, 2191361716UL, 2211450148UL, 1863406291UL, 1179298131UL, 241880428UL, 2330159770UL, 3490494273UL, 1337382890UL, 747522461UL, 1060348557UL, 3618051469UL, 991193538UL, 1604905367UL, 2595102954UL, 1460144089UL, 3990194961UL, 44265425UL, 896268152UL, 9333748UL, 2850675977UL, 941433385UL, 2483544989UL, 3443750079UL, 2488690792UL, +}, +{ +824297644UL, 239464654UL, 4133652405UL, 1611614045UL, 102133367UL, 1780659362UL, 114934718UL, 3793050817UL, 3286619856UL, 1323742990UL, 3487325492UL, 468742651UL, 271433491UL, 3474195023UL, 479173886UL, 3282693508UL, 978269731UL, 1826990521UL, 3664994445UL, 1943608646UL, 2356793330UL, 2228748670UL, 4238523810UL, 2467714013UL, 1732683390UL, 2345218001UL, 3371637369UL, 1073602848UL, 844797255UL, 3881048480UL, 509186599UL, 1399427071UL, +3815270778UL, 1505666412UL, 2616384981UL, 2990167853UL, 3716581225UL, 3063486812UL, 1568307898UL, 3262882991UL, 1455926070UL, 3011806226UL, 3803364927UL, 849372289UL, 2382885729UL, 3071102985UL, 3838244574UL, 3219174218UL, 847830757UL, 1414310383UL, 3679389549UL, 1558413907UL, 2211822428UL, 339810803UL, 1051648907UL, 76928699UL, 3174194320UL, 3920525151UL, 2010088097UL, 4111092791UL, 3537133983UL, 1701410561UL, 3036563175UL, 4010986440UL, +1749862952UL, 159833659UL, 3406940095UL, 1041601178UL, 4005001553UL, 1663515026UL, 1728511107UL, 1496728329UL, 2359970426UL, 530862749UL, 3797637507UL, 2550923758UL, 1450321218UL, 21682904UL, 936804838UL, 3832989199UL, 3063256293UL, 3991708711UL, 986539283UL, 3775232150UL, 2867283706UL, 747477232UL, 946349345UL, 1010022077UL, 188204104UL, 2526787171UL, 2816843760UL, 1776005940UL, 2819738500UL, 1155856699UL, 2191793692UL, 3802193350UL, +1163036922UL, 645032560UL, 3122679267UL, 3311719932UL, 3757073707UL, 2464258247UL, 1360425558UL, 387981241UL, 1714916540UL, 411019237UL, 2248466094UL, 2878213113UL, 2742600760UL, 2763650927UL, 2526526309UL, 1093836264UL, 3819986000UL, 3754388150UL, 1731831799UL, 1441137152UL, 1625850961UL, 1182084155UL, 1596226376UL, 2389499892UL, 3923360808UL, 2439159233UL, 1623373213UL, 2513747479UL, 3651587995UL, 1040867254UL, 4208484711UL, 3489019765UL, +2141904813UL, 3666280633UL, 970464748UL, 2970978888UL, 1376163015UL, 1218588624UL, 2721249823UL, 707915046UL, 4262557484UL, 3237019195UL, 744279211UL, 364567144UL, 1997174860UL, 3215512870UL, 2758022574UL, 2677818352UL, 4198422061UL, 3016017869UL, 2243997977UL, 1029293722UL, 1820056287UL, 1090825999UL, 4135403724UL, 299239527UL, 874620372UL, 2995368704UL, 3219627293UL, 2431393692UL, 3470601754UL, 1809177571UL, 37446335UL, 1619184385UL, +675901368UL, 824297644UL, 239464654UL, 4133652405UL, 1611614045UL, 1918718045UL, 1780659362UL, 114934718UL, 3793050817UL, 3286619856UL, 3566342809UL, 3487325492UL, 468742651UL, 271433491UL, 3474195023UL, 77797025UL, 3282693508UL, 978269731UL, 1826990521UL, 3664994445UL, 1455182612UL, 2356793330UL, 2228748670UL, 4238523810UL, 2467714013UL, 1081984526UL, 2345218001UL, 3371637369UL, 1073602848UL, 844797255UL, 4125413817UL, 509186599UL, +1399427071UL, 3815270778UL, 1505666412UL, 891823593UL, 2990167853UL, 3716581225UL, 3063486812UL, 1568307898UL, 1753181930UL, 1455926070UL, 3011806226UL, 3803364927UL, 849372289UL, 4211525266UL, 3071102985UL, 3838244574UL, 3219174218UL, 847830757UL, 774013898UL, 3679389549UL, 1558413907UL, 2211822428UL, 339810803UL, 2282783575UL, 76928699UL, 3174194320UL, 3920525151UL, 2010088097UL, 3894905215UL, 3537133983UL, 1701410561UL, 3036563175UL, +4010986440UL, 676262036UL, 159833659UL, 3406940095UL, 1041601178UL, 4005001553UL, 3470687799UL, 1728511107UL, 1496728329UL, 2359970426UL, 530862749UL, 3081565689UL, 2550923758UL, 1450321218UL, 21682904UL, 936804838UL, 951873872UL, 3063256293UL, 3991708711UL, 986539283UL, 3775232150UL, 487381835UL, 747477232UL, 946349345UL, 1010022077UL, 188204104UL, 2898848241UL, 2816843760UL, 1776005940UL, 2819738500UL, 1155856699UL, 2432683643UL, +3802193350UL, 1163036922UL, 645032560UL, 3122679267UL, 22749078UL, 3757073707UL, 2464258247UL, 1360425558UL, 387981241UL, 3652130062UL, 411019237UL, 2248466094UL, 2878213113UL, 2742600760UL, 811608089UL, 2526526309UL, 1093836264UL, 3819986000UL, 3754388150UL, 415809552UL, 1441137152UL, 1625850961UL, 1182084155UL, 1596226376UL, 202609936UL, 3923360808UL, 2439159233UL, 1623373213UL, 2513747479UL, 4149563237UL, 1040867254UL, 4208484711UL, +3489019765UL, 2141904813UL, 718806958UL, 970464748UL, 2970978888UL, 1376163015UL, 1218588624UL, 2307367700UL, 707915046UL, 4262557484UL, 3237019195UL, 744279211UL, 1876395939UL, 1997174860UL, 3215512870UL, 2758022574UL, 2677818352UL, 2276158677UL, 3016017869UL, 2243997977UL, 1029293722UL, 1820056287UL, 3605618012UL, 4135403724UL, 299239527UL, 874620372UL, 2995368704UL, 872126519UL, 2431393692UL, 3470601754UL, 1809177571UL, 37446335UL, +2365355125UL, 675901368UL, 824297644UL, 239464654UL, 4133652405UL, 8139161UL, 1918718045UL, 1780659362UL, 114934718UL, 3793050817UL, 2424418256UL, 3566342809UL, 3487325492UL, 468742651UL, 271433491UL, 542129690UL, 77797025UL, 3282693508UL, 978269731UL, 1826990521UL, 2963435579UL, 1455182612UL, 2356793330UL, 2228748670UL, 4238523810UL, 2373300657UL, 1081984526UL, 2345218001UL, 3371637369UL, 1073602848UL, 2948610237UL, 4125413817UL, +509186599UL, 1399427071UL, 3815270778UL, 2870251133UL, 891823593UL, 2990167853UL, 3716581225UL, 3063486812UL, 2347504584UL, 1753181930UL, 1455926070UL, 3011806226UL, 3803364927UL, 3956554065UL, 4211525266UL, 3071102985UL, 3838244574UL, 3219174218UL, 2018597841UL, 774013898UL, 3679389549UL, 1558413907UL, 2211822428UL, 56072605UL, 2282783575UL, 76928699UL, 3174194320UL, 3920525151UL, 268031035UL, 3894905215UL, 3537133983UL, 1701410561UL, +3036563175UL, 366935627UL, 676262036UL, 159833659UL, 3406940095UL, 1041601178UL, 4125224603UL, 3470687799UL, 1728511107UL, 1496728329UL, 2359970426UL, 3570997128UL, 3081565689UL, 2550923758UL, 1450321218UL, 21682904UL, 604517910UL, 951873872UL, 3063256293UL, 3991708711UL, 986539283UL, 2414780630UL, 487381835UL, 747477232UL, 946349345UL, 1010022077UL, 3820353604UL, 2898848241UL, 2816843760UL, 1776005940UL, 2819738500UL, 1192624235UL, +2432683643UL, 3802193350UL, 1163036922UL, 645032560UL, 4050277201UL, 22749078UL, 3757073707UL, 2464258247UL, 1360425558UL, 1933406988UL, 3652130062UL, 411019237UL, 2248466094UL, 2878213113UL, 37869698UL, 811608089UL, 2526526309UL, 1093836264UL, 3819986000UL, 3999750910UL, 415809552UL, 1441137152UL, 1625850961UL, 1182084155UL, 1186617400UL, 202609936UL, 3923360808UL, 2439159233UL, 1623373213UL, 4226729056UL, 4149563237UL, 1040867254UL, +4208484711UL, 3489019765UL, 3728140516UL, 718806958UL, 970464748UL, 2970978888UL, 1376163015UL, 1307011711UL, 2307367700UL, 707915046UL, 4262557484UL, 3237019195UL, 4014387080UL, 1876395939UL, 1997174860UL, 3215512870UL, 2758022574UL, 1696763772UL, 2276158677UL, 3016017869UL, 2243997977UL, 1029293722UL, 1444214949UL, 3605618012UL, 4135403724UL, 299239527UL, 874620372UL, 1524158085UL, 872126519UL, 2431393692UL, 3470601754UL, 1809177571UL, +163166369UL, 2365355125UL, 675901368UL, 824297644UL, 239464654UL, 1626558353UL, 8139161UL, 1918718045UL, 1780659362UL, 114934718UL, 1885224714UL, 2424418256UL, 3566342809UL, 3487325492UL, 468742651UL, 1101039917UL, 542129690UL, 77797025UL, 3282693508UL, 978269731UL, 3659653445UL, 2963435579UL, 1455182612UL, 2356793330UL, 2228748670UL, 539062188UL, 2373300657UL, 1081984526UL, 2345218001UL, 3371637369UL, 2825652803UL, 2948610237UL, +4125413817UL, 509186599UL, 1399427071UL, 3197034620UL, 2870251133UL, 891823593UL, 2990167853UL, 3716581225UL, 3773712182UL, 2347504584UL, 1753181930UL, 1455926070UL, 3011806226UL, 3260276773UL, 3956554065UL, 4211525266UL, 3071102985UL, 3838244574UL, 201639236UL, 2018597841UL, 774013898UL, 3679389549UL, 1558413907UL, 2830702673UL, 56072605UL, 2282783575UL, 76928699UL, 3174194320UL, 1677734845UL, 268031035UL, 3894905215UL, 3537133983UL, +1701410561UL, 4240866153UL, 366935627UL, 676262036UL, 159833659UL, 3406940095UL, 4245889153UL, 4125224603UL, 3470687799UL, 1728511107UL, 1496728329UL, 3650277906UL, 3570997128UL, 3081565689UL, 2550923758UL, 1450321218UL, 3392011930UL, 604517910UL, 951873872UL, 3063256293UL, 3991708711UL, 2876003834UL, 2414780630UL, 487381835UL, 747477232UL, 946349345UL, 982266944UL, 3820353604UL, 2898848241UL, 2816843760UL, 1776005940UL, 3677715064UL, +1192624235UL, 2432683643UL, 3802193350UL, 1163036922UL, 1226669337UL, 4050277201UL, 22749078UL, 3757073707UL, 2464258247UL, 4197532785UL, 1933406988UL, 3652130062UL, 411019237UL, 2248466094UL, 3209426720UL, 37869698UL, 811608089UL, 2526526309UL, 1093836264UL, 535856568UL, 3999750910UL, 415809552UL, 1441137152UL, 1625850961UL, 2181491119UL, 1186617400UL, 202609936UL, 3923360808UL, 2439159233UL, 1823827533UL, 4226729056UL, 4149563237UL, +1040867254UL, 4208484711UL, 1101917521UL, 3728140516UL, 718806958UL, 970464748UL, 2970978888UL, 1574663259UL, 1307011711UL, 2307367700UL, 707915046UL, 4262557484UL, 2164217930UL, 4014387080UL, 1876395939UL, 1997174860UL, 3215512870UL, 1335157953UL, 1696763772UL, 2276158677UL, 3016017869UL, 2243997977UL, 324788481UL, 1444214949UL, 3605618012UL, 4135403724UL, 299239527UL, 4190629945UL, 1524158085UL, 872126519UL, 2431393692UL, 3470601754UL, +3701018280UL, 671547257UL, 4029965023UL, 1026428282UL, 1584875796UL, 3537698406UL, 3731126476UL, 2419795330UL, 993551117UL, 2126319514UL, 3557113304UL, 1014047757UL, 1407120210UL, 1977537539UL, 1338958570UL, 3249585389UL, 3661503659UL, 4240815680UL, 1866933898UL, 3205442033UL, 4247144816UL, 1422846419UL, 3847421981UL, 1383632066UL, 3589322376UL, 1816906043UL, 1310944471UL, 3646822098UL, 799529013UL, 3350558751UL, 2552899295UL, 4281235599UL, +4069668296UL, 4123814877UL, 3289565353UL, 1512974699UL, 111908081UL, 2535556715UL, 333570815UL, 3638041929UL, 1942569446UL, 20945397UL, 3784826827UL, 200406456UL, 2640512138UL, 38390336UL, 436784052UL, 3062106345UL, 1675333627UL, 709613078UL, 3479720979UL, 2726065658UL, 4072312748UL, 797389139UL, 3492082903UL, 3792395750UL, 983473383UL, 2984788349UL, 2030282907UL, 2246686378UL, 2451087141UL, 1799640566UL, 2182694041UL, 3226819076UL, +3573153299UL, 3658670545UL, 1197013516UL, 777601408UL, 4271704548UL, 1192713934UL, 1628497069UL, 681025927UL, 4078910773UL, 619496169UL, 1534725146UL, 1881987408UL, 2283881479UL, 1090218673UL, 4169123978UL, 2352195985UL, 2640116078UL, 3869558100UL, 2859177954UL, 3329803656UL, 4048903941UL, 1636589748UL, 2095007175UL, 4169840880UL, 2953611537UL, 2413740464UL, 3029624235UL, 778662441UL, 422412779UL, 412103280UL, 1701569571UL, 564088645UL, +469973310UL, 254302146UL, 3963642101UL, 555781470UL, 2983576224UL, 1757897888UL, 1420763962UL, 2176323176UL, 916790568UL, 3057610889UL, 196828641UL, 1435167402UL, 325046353UL, 1337309066UL, 2691769282UL, 3572566918UL, 2910149226UL, 3659418019UL, 2511762503UL, 3869838339UL, 1413312151UL, 1939339596UL, 801124461UL, 760477862UL, 2416958233UL, 3439465675UL, 3561763524UL, 1760392811UL, 1582406751UL, 1203071257UL, 755811399UL, 2675585013UL, +1150664766UL, 3515765747UL, 3419135844UL, 2076543342UL, 1191918544UL, 3644819073UL, 2195875022UL, 2909071148UL, 3385707813UL, 1151273265UL, 1467337419UL, 3570589492UL, 3742049917UL, 1609858615UL, 2964509119UL, 3747960348UL, 2825858640UL, 101501715UL, 1234710482UL, 750428334UL, 2870070395UL, 416615350UL, 4054039387UL, 3807926874UL, 3035407103UL, 1644560291UL, 2490941295UL, 963796562UL, 3233132139UL, 2590859502UL, 2845243609UL, 964355909UL, +}, +{ +2882980002UL, 2211288683UL, 872766101UL, 3713771728UL, 1429983118UL, 2069599564UL, 827699420UL, 1288565883UL, 2985727214UL, 3873174741UL, 2138389854UL, 3915615927UL, 2759028650UL, 3120611541UL, 385953581UL, 189931252UL, 2044235060UL, 4214733958UL, 1899137741UL, 1973215178UL, 494148492UL, 1550568689UL, 3646957712UL, 3764784141UL, 1114556979UL, 1411407684UL, 1194906295UL, 1718808623UL, 1809627046UL, 1413570172UL, 180837718UL, 2588730975UL, +1481586714UL, 2836300053UL, 1967135375UL, 4010897189UL, 3392273121UL, 3466021198UL, 1182364160UL, 1364130321UL, 1795412556UL, 330320182UL, 1165093128UL, 2125767818UL, 904192995UL, 51833064UL, 232302906UL, 1834422179UL, 476731510UL, 3484170517UL, 2373156680UL, 2610500049UL, 1688364249UL, 463611489UL, 3759685710UL, 62038708UL, 2357334250UL, 1230002441UL, 520303451UL, 3009758047UL, 1882263827UL, 2524779298UL, 1736323157UL, 3883037541UL, +1103650182UL, 1137565179UL, 3112310886UL, 3524287283UL, 3064002681UL, 4106308847UL, 3180534967UL, 2463036338UL, 1859639515UL, 1319061987UL, 354419222UL, 4108171950UL, 601260554UL, 705389180UL, 4081137445UL, 3461353436UL, 399768111UL, 3963945521UL, 2094962544UL, 630762046UL, 369047181UL, 3495709267UL, 3525452874UL, 314919391UL, 2152657907UL, 881476500UL, 3565507827UL, 2594931381UL, 579458905UL, 1767988684UL, 2678728511UL, 3416503939UL, +4150612567UL, 1015748208UL, 2059142720UL, 2725183490UL, 2998421769UL, 1644667445UL, 4221112143UL, 456578131UL, 3881530201UL, 190710543UL, 1721255927UL, 2274887963UL, 187713135UL, 2209254952UL, 2185750138UL, 2992229399UL, 482133467UL, 2758198810UL, 15147949UL, 536333711UL, 2296185346UL, 1103433779UL, 1573407789UL, 1357843567UL, 2927153963UL, 4157295398UL, 533935893UL, 3567030810UL, 1900900411UL, 509578395UL, 3810017456UL, 2134110040UL, +3347323570UL, 3497032747UL, 201278263UL, 3933249682UL, 3849960474UL, 2509123202UL, 3445521167UL, 1355284593UL, 2444811561UL, 2751112324UL, 1116246614UL, 511213077UL, 3412599909UL, 1712118363UL, 54054007UL, 442729047UL, 3077267414UL, 1532701769UL, 181534938UL, 1278069867UL, 3847149992UL, 2305860479UL, 4146252420UL, 2047690303UL, 361856758UL, 452490341UL, 636885000UL, 1733216839UL, 3788548638UL, 1094285639UL, 1349356222UL, 2760444511UL, +976767752UL, 2882980002UL, 2211288683UL, 872766101UL, 3713771728UL, 895830110UL, 2069599564UL, 827699420UL, 1288565883UL, 2985727214UL, 3377496544UL, 2138389854UL, 3915615927UL, 2759028650UL, 3120611541UL, 3254971483UL, 189931252UL, 2044235060UL, 4214733958UL, 1899137741UL, 2095055586UL, 494148492UL, 1550568689UL, 3646957712UL, 3764784141UL, 2869825005UL, 1411407684UL, 1194906295UL, 1718808623UL, 1809627046UL, 907760376UL, 180837718UL, +2588730975UL, 1481586714UL, 2836300053UL, 639229964UL, 4010897189UL, 3392273121UL, 3466021198UL, 1182364160UL, 3006792787UL, 1795412556UL, 330320182UL, 1165093128UL, 2125767818UL, 253264555UL, 51833064UL, 232302906UL, 1834422179UL, 476731510UL, 4284481518UL, 2373156680UL, 2610500049UL, 1688364249UL, 463611489UL, 4133115610UL, 62038708UL, 2357334250UL, 1230002441UL, 520303451UL, 1497001150UL, 1882263827UL, 2524779298UL, 1736323157UL, +3883037541UL, 3541909847UL, 1137565179UL, 3112310886UL, 3524287283UL, 3064002681UL, 3193060438UL, 3180534967UL, 2463036338UL, 1859639515UL, 1319061987UL, 111871878UL, 4108171950UL, 601260554UL, 705389180UL, 4081137445UL, 742999102UL, 399768111UL, 3963945521UL, 2094962544UL, 630762046UL, 3219207950UL, 3495709267UL, 3525452874UL, 314919391UL, 2152657907UL, 720863934UL, 3565507827UL, 2594931381UL, 579458905UL, 1767988684UL, 3958525287UL, +3416503939UL, 4150612567UL, 1015748208UL, 2059142720UL, 4227838648UL, 2998421769UL, 1644667445UL, 4221112143UL, 456578131UL, 302729329UL, 190710543UL, 1721255927UL, 2274887963UL, 187713135UL, 1293706587UL, 2185750138UL, 2992229399UL, 482133467UL, 2758198810UL, 2514965671UL, 536333711UL, 2296185346UL, 1103433779UL, 1573407789UL, 2237639577UL, 2927153963UL, 4157295398UL, 533935893UL, 3567030810UL, 3793156627UL, 509578395UL, 3810017456UL, +2134110040UL, 3347323570UL, 1358364UL, 201278263UL, 3933249682UL, 3849960474UL, 2509123202UL, 628476542UL, 1355284593UL, 2444811561UL, 2751112324UL, 1116246614UL, 3421170828UL, 3412599909UL, 1712118363UL, 54054007UL, 442729047UL, 325825294UL, 1532701769UL, 181534938UL, 1278069867UL, 3847149992UL, 2785457372UL, 4146252420UL, 2047690303UL, 361856758UL, 452490341UL, 1099532083UL, 1733216839UL, 3788548638UL, 1094285639UL, 1349356222UL, +3047068265UL, 976767752UL, 2882980002UL, 2211288683UL, 872766101UL, 366378371UL, 895830110UL, 2069599564UL, 827699420UL, 1288565883UL, 962962884UL, 3377496544UL, 2138389854UL, 3915615927UL, 2759028650UL, 3742489931UL, 3254971483UL, 189931252UL, 2044235060UL, 4214733958UL, 3073407497UL, 2095055586UL, 494148492UL, 1550568689UL, 3646957712UL, 758370067UL, 2869825005UL, 1411407684UL, 1194906295UL, 1718808623UL, 636166267UL, 907760376UL, +180837718UL, 2588730975UL, 1481586714UL, 705382583UL, 639229964UL, 4010897189UL, 3392273121UL, 3466021198UL, 3815622040UL, 3006792787UL, 1795412556UL, 330320182UL, 1165093128UL, 2956382339UL, 253264555UL, 51833064UL, 232302906UL, 1834422179UL, 3665645898UL, 4284481518UL, 2373156680UL, 2610500049UL, 1688364249UL, 2565987890UL, 4133115610UL, 62038708UL, 2357334250UL, 1230002441UL, 2397198293UL, 1497001150UL, 1882263827UL, 2524779298UL, +1736323157UL, 817630445UL, 3541909847UL, 1137565179UL, 3112310886UL, 3524287283UL, 1356492703UL, 3193060438UL, 3180534967UL, 2463036338UL, 1859639515UL, 3963974342UL, 111871878UL, 4108171950UL, 601260554UL, 705389180UL, 1776439965UL, 742999102UL, 399768111UL, 3963945521UL, 2094962544UL, 2007137733UL, 3219207950UL, 3495709267UL, 3525452874UL, 314919391UL, 3877039785UL, 720863934UL, 3565507827UL, 2594931381UL, 579458905UL, 2919403199UL, +3958525287UL, 3416503939UL, 4150612567UL, 1015748208UL, 960765392UL, 4227838648UL, 2998421769UL, 1644667445UL, 4221112143UL, 2402062799UL, 302729329UL, 190710543UL, 1721255927UL, 2274887963UL, 3958481548UL, 1293706587UL, 2185750138UL, 2992229399UL, 482133467UL, 3838280UL, 2514965671UL, 536333711UL, 2296185346UL, 1103433779UL, 3675282065UL, 2237639577UL, 2927153963UL, 4157295398UL, 533935893UL, 4172021805UL, 3793156627UL, 509578395UL, +3810017456UL, 2134110040UL, 3608998517UL, 1358364UL, 201278263UL, 3933249682UL, 3849960474UL, 2445690023UL, 628476542UL, 1355284593UL, 2444811561UL, 2751112324UL, 507378026UL, 3421170828UL, 3412599909UL, 1712118363UL, 54054007UL, 770634305UL, 325825294UL, 1532701769UL, 181534938UL, 1278069867UL, 4055596097UL, 2785457372UL, 4146252420UL, 2047690303UL, 361856758UL, 3439427065UL, 1099532083UL, 1733216839UL, 3788548638UL, 1094285639UL, +1633234274UL, 3047068265UL, 976767752UL, 2882980002UL, 2211288683UL, 3763615153UL, 366378371UL, 895830110UL, 2069599564UL, 827699420UL, 2457443913UL, 962962884UL, 3377496544UL, 2138389854UL, 3915615927UL, 3290989016UL, 3742489931UL, 3254971483UL, 189931252UL, 2044235060UL, 4275822963UL, 3073407497UL, 2095055586UL, 494148492UL, 1550568689UL, 1043420085UL, 758370067UL, 2869825005UL, 1411407684UL, 1194906295UL, 676378812UL, 636166267UL, +907760376UL, 180837718UL, 2588730975UL, 2971715054UL, 705382583UL, 639229964UL, 4010897189UL, 3392273121UL, 795184546UL, 3815622040UL, 3006792787UL, 1795412556UL, 330320182UL, 1990804460UL, 2956382339UL, 253264555UL, 51833064UL, 232302906UL, 836875615UL, 3665645898UL, 4284481518UL, 2373156680UL, 2610500049UL, 98106795UL, 2565987890UL, 4133115610UL, 62038708UL, 2357334250UL, 2761212145UL, 2397198293UL, 1497001150UL, 1882263827UL, +2524779298UL, 2381031747UL, 817630445UL, 3541909847UL, 1137565179UL, 3112310886UL, 2501374726UL, 1356492703UL, 3193060438UL, 3180534967UL, 2463036338UL, 3671733096UL, 3963974342UL, 111871878UL, 4108171950UL, 601260554UL, 1017043724UL, 1776439965UL, 742999102UL, 399768111UL, 3963945521UL, 2177838102UL, 2007137733UL, 3219207950UL, 3495709267UL, 3525452874UL, 3254054416UL, 3877039785UL, 720863934UL, 3565507827UL, 2594931381UL, 1994293489UL, +2919403199UL, 3958525287UL, 3416503939UL, 4150612567UL, 1976960210UL, 960765392UL, 4227838648UL, 2998421769UL, 1644667445UL, 2896792687UL, 2402062799UL, 302729329UL, 190710543UL, 1721255927UL, 2914584080UL, 3958481548UL, 1293706587UL, 2185750138UL, 2992229399UL, 810756083UL, 3838280UL, 2514965671UL, 536333711UL, 2296185346UL, 1776509588UL, 3675282065UL, 2237639577UL, 2927153963UL, 4157295398UL, 2048779551UL, 4172021805UL, 3793156627UL, +509578395UL, 3810017456UL, 3042185034UL, 3608998517UL, 1358364UL, 201278263UL, 3933249682UL, 3551449718UL, 2445690023UL, 628476542UL, 1355284593UL, 2444811561UL, 3480611728UL, 507378026UL, 3421170828UL, 3412599909UL, 1712118363UL, 1268921331UL, 770634305UL, 325825294UL, 1532701769UL, 181534938UL, 2645357587UL, 4055596097UL, 2785457372UL, 4146252420UL, 2047690303UL, 1994855609UL, 3439427065UL, 1099532083UL, 1733216839UL, 3788548638UL, +3516588243UL, 4058132193UL, 3940172101UL, 4043964688UL, 3377150021UL, 1381463736UL, 3320280180UL, 931260821UL, 2754727582UL, 1286176949UL, 1661126244UL, 2301263887UL, 2255977851UL, 1122646603UL, 1767549201UL, 162324152UL, 425506096UL, 3777762686UL, 13687528UL, 710105607UL, 1092739920UL, 2930179533UL, 568855389UL, 2476208631UL, 964360978UL, 2011445117UL, 3887128674UL, 2799005525UL, 2479086439UL, 814368438UL, 2018629666UL, 909662384UL, +231589584UL, 1422241284UL, 4035938208UL, 3570985552UL, 660700421UL, 603857869UL, 567385627UL, 3232044670UL, 291307502UL, 947817625UL, 3466590280UL, 3080261993UL, 947835229UL, 2925888682UL, 1817591844UL, 2652420575UL, 4150903445UL, 4055627313UL, 1715025966UL, 505331227UL, 1863531052UL, 2928506098UL, 947547681UL, 1117344443UL, 781457023UL, 607542746UL, 241559360UL, 3797150797UL, 105381589UL, 361541961UL, 3393121650UL, 3840152184UL, +2873171161UL, 3030026082UL, 1115171192UL, 1718221281UL, 96787532UL, 2556617898UL, 1237726058UL, 2876298621UL, 1052881200UL, 461661595UL, 2632346030UL, 1775614319UL, 2454951319UL, 3691637824UL, 4018448825UL, 1610472965UL, 3076493165UL, 1364200430UL, 2011206580UL, 1066672050UL, 706141458UL, 2064189273UL, 346938484UL, 2964350202UL, 3731612957UL, 2506635528UL, 2007045393UL, 3312126930UL, 2602035453UL, 988876930UL, 2960173442UL, 559685520UL, +2719943441UL, 891699839UL, 1151651090UL, 1223301894UL, 3666960271UL, 1330825927UL, 1681770552UL, 38877327UL, 3803211467UL, 4000053051UL, 3552560459UL, 3510286057UL, 2606732870UL, 721190747UL, 1933504723UL, 3110735238UL, 2333178561UL, 1577381363UL, 595257962UL, 4120745072UL, 960219089UL, 2591080970UL, 3354222743UL, 47827627UL, 3759509914UL, 304815919UL, 2643673615UL, 1381570381UL, 2103367217UL, 2440936991UL, 2376721005UL, 1483630814UL, +3137202706UL, 3075255640UL, 1743649605UL, 3649754571UL, 2550788713UL, 4281983459UL, 904183710UL, 4243944530UL, 2742129811UL, 3363501626UL, 3670239155UL, 4233018118UL, 2615012385UL, 1420298161UL, 1251344091UL, 2172588631UL, 1243035186UL, 1724496237UL, 762022558UL, 8747231UL, 334416849UL, 1219880856UL, 187900356UL, 2527057367UL, 1730455958UL, 3240238410UL, 906024910UL, 2351575735UL, 4207748622UL, 936139767UL, 1984289988UL, 285939331UL, +}, +{ +4246897171UL, 2217508286UL, 4117450683UL, 4110626546UL, 3753823387UL, 3977667932UL, 623718443UL, 2276396692UL, 3772091798UL, 2272323453UL, 710314822UL, 3733316262UL, 1497955597UL, 700242668UL, 3582720207UL, 1247731879UL, 336477088UL, 532374143UL, 1123157198UL, 123828173UL, 272472192UL, 2142741093UL, 2557920990UL, 4209595119UL, 2807266578UL, 1516814248UL, 4250883502UL, 1967663703UL, 215335417UL, 1252724071UL, 4267389372UL, 94668579UL, +1980152960UL, 968677393UL, 1237744359UL, 63833646UL, 2488747616UL, 700459471UL, 744977323UL, 40829823UL, 955400639UL, 37187948UL, 53133706UL, 2014551043UL, 1664982537UL, 3342787122UL, 1549278321UL, 1245110464UL, 3424539081UL, 2180485253UL, 2757636973UL, 3590044052UL, 2712703548UL, 1366894959UL, 1777449151UL, 1538653374UL, 168718075UL, 2435805251UL, 588815465UL, 3166271130UL, 3164200096UL, 417809976UL, 623036767UL, 340121872UL, +1792214783UL, 56330125UL, 3268029211UL, 1117100306UL, 345899179UL, 1547071836UL, 3657965225UL, 4109701299UL, 664937685UL, 2627187961UL, 149301108UL, 1764003230UL, 3177910586UL, 3081492846UL, 2295419724UL, 2553420882UL, 1506534805UL, 971284719UL, 3224921758UL, 3336906843UL, 1507395478UL, 1224379418UL, 4117299702UL, 1973783225UL, 3609783242UL, 4186900040UL, 3715175536UL, 3904547465UL, 459692505UL, 3546328518UL, 3071448159UL, 1300375875UL, +1805392236UL, 3072717072UL, 99113127UL, 4281059076UL, 1658649136UL, 1974081931UL, 3940966682UL, 2092428023UL, 4014384840UL, 1546542514UL, 1130620125UL, 4117533767UL, 3372991735UL, 3537429957UL, 2704347564UL, 2300583688UL, 915286167UL, 1553874575UL, 3466388216UL, 701000054UL, 349103195UL, 1554395274UL, 3140941933UL, 2874072684UL, 2630572105UL, 2794301280UL, 321399291UL, 1158058020UL, 3570908149UL, 122802750UL, 3012686842UL, 2588402967UL, +3420589812UL, 581016671UL, 193235885UL, 1558092297UL, 1233353728UL, 1080743465UL, 3292663441UL, 2188057155UL, 2715412992UL, 4274317234UL, 1657504087UL, 2554269340UL, 1079741964UL, 922252155UL, 569761460UL, 3215661310UL, 2450710288UL, 2491078689UL, 632504591UL, 2169581755UL, 2552457727UL, 2554414735UL, 3347573916UL, 681756629UL, 801451286UL, 3504956478UL, 1308297539UL, 3602650700UL, 3530372129UL, 4117441036UL, 1827438812UL, 2852602217UL, +570161747UL, 4246897171UL, 2217508286UL, 4117450683UL, 4110626546UL, 756072139UL, 3977667932UL, 623718443UL, 2276396692UL, 3772091798UL, 3829898369UL, 710314822UL, 3733316262UL, 1497955597UL, 700242668UL, 757539371UL, 1247731879UL, 336477088UL, 532374143UL, 1123157198UL, 2374238409UL, 272472192UL, 2142741093UL, 2557920990UL, 4209595119UL, 1632439709UL, 1516814248UL, 4250883502UL, 1967663703UL, 215335417UL, 1267642920UL, 4267389372UL, +94668579UL, 1980152960UL, 968677393UL, 2252616933UL, 63833646UL, 2488747616UL, 700459471UL, 744977323UL, 2711054317UL, 955400639UL, 37187948UL, 53133706UL, 2014551043UL, 1664498234UL, 3342787122UL, 1549278321UL, 1245110464UL, 3424539081UL, 496150741UL, 2757636973UL, 3590044052UL, 2712703548UL, 1366894959UL, 2066534443UL, 1538653374UL, 168718075UL, 2435805251UL, 588815465UL, 318307195UL, 3164200096UL, 417809976UL, 623036767UL, +340121872UL, 3426055217UL, 56330125UL, 3268029211UL, 1117100306UL, 345899179UL, 979486044UL, 3657965225UL, 4109701299UL, 664937685UL, 2627187961UL, 2747102301UL, 1764003230UL, 3177910586UL, 3081492846UL, 2295419724UL, 1088606857UL, 1506534805UL, 971284719UL, 3224921758UL, 3336906843UL, 984983218UL, 1224379418UL, 4117299702UL, 1973783225UL, 3609783242UL, 1044785427UL, 3715175536UL, 3904547465UL, 459692505UL, 3546328518UL, 2096978494UL, +1300375875UL, 1805392236UL, 3072717072UL, 99113127UL, 972796497UL, 1658649136UL, 1974081931UL, 3940966682UL, 2092428023UL, 2914458983UL, 1546542514UL, 1130620125UL, 4117533767UL, 3372991735UL, 947968718UL, 2704347564UL, 2300583688UL, 915286167UL, 1553874575UL, 2124709798UL, 701000054UL, 349103195UL, 1554395274UL, 3140941933UL, 2569019225UL, 2630572105UL, 2794301280UL, 321399291UL, 1158058020UL, 4051601694UL, 122802750UL, 3012686842UL, +2588402967UL, 3420589812UL, 1738150581UL, 193235885UL, 1558092297UL, 1233353728UL, 1080743465UL, 1527068788UL, 2188057155UL, 2715412992UL, 4274317234UL, 1657504087UL, 1543089352UL, 1079741964UL, 922252155UL, 569761460UL, 3215661310UL, 2869922986UL, 2491078689UL, 632504591UL, 2169581755UL, 2552457727UL, 2807462748UL, 3347573916UL, 681756629UL, 801451286UL, 3504956478UL, 3400676931UL, 3602650700UL, 3530372129UL, 4117441036UL, 1827438812UL, +4056234054UL, 570161747UL, 4246897171UL, 2217508286UL, 4117450683UL, 3321376103UL, 756072139UL, 3977667932UL, 623718443UL, 2276396692UL, 1340008665UL, 3829898369UL, 710314822UL, 3733316262UL, 1497955597UL, 2098292377UL, 757539371UL, 1247731879UL, 336477088UL, 532374143UL, 2210327641UL, 2374238409UL, 272472192UL, 2142741093UL, 2557920990UL, 3502520226UL, 1632439709UL, 1516814248UL, 4250883502UL, 1967663703UL, 499168780UL, 1267642920UL, +4267389372UL, 94668579UL, 1980152960UL, 2695928666UL, 2252616933UL, 63833646UL, 2488747616UL, 700459471UL, 4181471443UL, 2711054317UL, 955400639UL, 37187948UL, 53133706UL, 441944403UL, 1664498234UL, 3342787122UL, 1549278321UL, 1245110464UL, 2271611585UL, 496150741UL, 2757636973UL, 3590044052UL, 2712703548UL, 3009817799UL, 2066534443UL, 1538653374UL, 168718075UL, 2435805251UL, 734763537UL, 318307195UL, 3164200096UL, 417809976UL, +623036767UL, 4002728646UL, 3426055217UL, 56330125UL, 3268029211UL, 1117100306UL, 1435987728UL, 979486044UL, 3657965225UL, 4109701299UL, 664937685UL, 815527474UL, 2747102301UL, 1764003230UL, 3177910586UL, 3081492846UL, 63383766UL, 1088606857UL, 1506534805UL, 971284719UL, 3224921758UL, 2331024939UL, 984983218UL, 1224379418UL, 4117299702UL, 1973783225UL, 3998070267UL, 1044785427UL, 3715175536UL, 3904547465UL, 459692505UL, 2582830990UL, +2096978494UL, 1300375875UL, 1805392236UL, 3072717072UL, 321154403UL, 972796497UL, 1658649136UL, 1974081931UL, 3940966682UL, 3789726976UL, 2914458983UL, 1546542514UL, 1130620125UL, 4117533767UL, 3440681546UL, 947968718UL, 2704347564UL, 2300583688UL, 915286167UL, 474021937UL, 2124709798UL, 701000054UL, 349103195UL, 1554395274UL, 702752814UL, 2569019225UL, 2630572105UL, 2794301280UL, 321399291UL, 2406346046UL, 4051601694UL, 122802750UL, +3012686842UL, 2588402967UL, 1782259321UL, 1738150581UL, 193235885UL, 1558092297UL, 1233353728UL, 3935919190UL, 1527068788UL, 2188057155UL, 2715412992UL, 4274317234UL, 1722541048UL, 1543089352UL, 1079741964UL, 922252155UL, 569761460UL, 3384000986UL, 2869922986UL, 2491078689UL, 632504591UL, 2169581755UL, 3451609034UL, 2807462748UL, 3347573916UL, 681756629UL, 801451286UL, 2643408064UL, 3400676931UL, 3602650700UL, 3530372129UL, 4117441036UL, +3635077251UL, 4056234054UL, 570161747UL, 4246897171UL, 2217508286UL, 2364796923UL, 3321376103UL, 756072139UL, 3977667932UL, 623718443UL, 3792539489UL, 1340008665UL, 3829898369UL, 710314822UL, 3733316262UL, 876419217UL, 2098292377UL, 757539371UL, 1247731879UL, 336477088UL, 3307300788UL, 2210327641UL, 2374238409UL, 272472192UL, 2142741093UL, 4142392723UL, 3502520226UL, 1632439709UL, 1516814248UL, 4250883502UL, 3551852862UL, 499168780UL, +1267642920UL, 4267389372UL, 94668579UL, 1177286958UL, 2695928666UL, 2252616933UL, 63833646UL, 2488747616UL, 3571573975UL, 4181471443UL, 2711054317UL, 955400639UL, 37187948UL, 1485050393UL, 441944403UL, 1664498234UL, 3342787122UL, 1549278321UL, 518707274UL, 2271611585UL, 496150741UL, 2757636973UL, 3590044052UL, 305206687UL, 3009817799UL, 2066534443UL, 1538653374UL, 168718075UL, 1914032206UL, 734763537UL, 318307195UL, 3164200096UL, +417809976UL, 2062496275UL, 4002728646UL, 3426055217UL, 56330125UL, 3268029211UL, 1878869053UL, 1435987728UL, 979486044UL, 3657965225UL, 4109701299UL, 1558853775UL, 815527474UL, 2747102301UL, 1764003230UL, 3177910586UL, 681877401UL, 63383766UL, 1088606857UL, 1506534805UL, 971284719UL, 2546285777UL, 2331024939UL, 984983218UL, 1224379418UL, 4117299702UL, 539292757UL, 3998070267UL, 1044785427UL, 3715175536UL, 3904547465UL, 3854154565UL, +2582830990UL, 2096978494UL, 1300375875UL, 1805392236UL, 2586804198UL, 321154403UL, 972796497UL, 1658649136UL, 1974081931UL, 1718873863UL, 3789726976UL, 2914458983UL, 1546542514UL, 1130620125UL, 477866180UL, 3440681546UL, 947968718UL, 2704347564UL, 2300583688UL, 56071603UL, 474021937UL, 2124709798UL, 701000054UL, 349103195UL, 2431577249UL, 702752814UL, 2569019225UL, 2630572105UL, 2794301280UL, 211758134UL, 2406346046UL, 4051601694UL, +122802750UL, 3012686842UL, 2470642374UL, 1782259321UL, 1738150581UL, 193235885UL, 1558092297UL, 852353933UL, 3935919190UL, 1527068788UL, 2188057155UL, 2715412992UL, 543290606UL, 1722541048UL, 1543089352UL, 1079741964UL, 922252155UL, 1146820965UL, 3384000986UL, 2869922986UL, 2491078689UL, 632504591UL, 2936494996UL, 3451609034UL, 2807462748UL, 3347573916UL, 681756629UL, 3428474076UL, 2643408064UL, 3400676931UL, 3602650700UL, 3530372129UL, +3558016488UL, 304167301UL, 3073812276UL, 1253385329UL, 801639697UL, 1346336854UL, 3880416830UL, 1110804934UL, 2500585706UL, 1294233475UL, 1964132477UL, 1625651370UL, 2732590160UL, 310054807UL, 3350133555UL, 800839525UL, 3435579932UL, 2120216654UL, 407780291UL, 1228117799UL, 513334510UL, 1423091447UL, 3698882838UL, 2556406643UL, 1536483608UL, 998695315UL, 1619514015UL, 4197375975UL, 892985909UL, 993665758UL, 4160405430UL, 2379977763UL, +1423742790UL, 4286808034UL, 479280944UL, 3611297256UL, 3481820363UL, 1261889958UL, 455298115UL, 3955764756UL, 2406161837UL, 185873336UL, 3382956716UL, 3556168427UL, 3988426650UL, 2917586591UL, 1248672474UL, 2925146191UL, 1416331075UL, 290755159UL, 2845168299UL, 3301422441UL, 3771816588UL, 491352430UL, 2461746382UL, 1591975949UL, 604909111UL, 3595669760UL, 4079314041UL, 258321046UL, 1352583874UL, 999018951UL, 3150079914UL, 113122510UL, +743303046UL, 3205496412UL, 4267738054UL, 2567402806UL, 2181107494UL, 3266354249UL, 1941487496UL, 2742084900UL, 3758785335UL, 732694221UL, 2052988791UL, 1759288229UL, 1094292464UL, 1582835026UL, 2817864273UL, 666443657UL, 419482443UL, 2877435004UL, 2944696351UL, 2523539432UL, 301119182UL, 998264713UL, 2314419254UL, 3610447393UL, 1139414242UL, 1486351830UL, 3207929489UL, 384633091UL, 4056367270UL, 2348418835UL, 3773781885UL, 1963929818UL, +804929680UL, 1511023454UL, 3915948102UL, 1371942526UL, 2586212526UL, 130122933UL, 2030859646UL, 3730011315UL, 118408868UL, 632704878UL, 3559959612UL, 2926361713UL, 1401386286UL, 599210027UL, 2315051975UL, 157809758UL, 1148939942UL, 3060024350UL, 1464284678UL, 3209480975UL, 3961060416UL, 3481639206UL, 4113344379UL, 3475766200UL, 130581501UL, 1844026536UL, 2661594012UL, 3145812007UL, 3233175620UL, 2549419093UL, 2612966733UL, 1348260920UL, +740167863UL, 226231218UL, 2631972701UL, 2148020402UL, 3399479414UL, 1074946996UL, 30872114UL, 1342415612UL, 1071408471UL, 1141719547UL, 332346805UL, 1473336719UL, 4207932404UL, 3668838170UL, 3154502882UL, 3892070442UL, 2812790310UL, 13931822UL, 1150258251UL, 2369539473UL, 640926011UL, 2991135002UL, 2410382633UL, 548200125UL, 3977740663UL, 1245837867UL, 2378569399UL, 1561469990UL, 2437445882UL, 214387770UL, 3329587833UL, 281635893UL, +}, +{ +1720103319UL, 2201367526UL, 1415072072UL, 2446588589UL, 2195586017UL, 3817930623UL, 653121934UL, 2766514657UL, 765921436UL, 630082485UL, 2990883045UL, 3304472999UL, 471385134UL, 4097977544UL, 3749829028UL, 3587534772UL, 1064359851UL, 800061060UL, 2844220510UL, 389838005UL, 3681318140UL, 1515923235UL, 1885079324UL, 713031018UL, 1962734763UL, 2288160004UL, 1983331336UL, 1247350521UL, 4208372034UL, 1444837930UL, 3549494305UL, 4169715512UL, +701313302UL, 1118275019UL, 3118975645UL, 4153969630UL, 3516491181UL, 3601057044UL, 2509222288UL, 223064937UL, 899123842UL, 2574531231UL, 1386928111UL, 3790651401UL, 1300768348UL, 2038833061UL, 3736517792UL, 3850203561UL, 1679542285UL, 3391273474UL, 3862995487UL, 3118056386UL, 47128429UL, 2977525950UL, 3236389548UL, 1937040839UL, 4223233198UL, 2105119262UL, 721111284UL, 331726226UL, 68419013UL, 2575393464UL, 3648293304UL, 1448878851UL, +4186783614UL, 3696899986UL, 1270877069UL, 3351263117UL, 3918639273UL, 1472902162UL, 2767482392UL, 3549853842UL, 2353191576UL, 3353325530UL, 3072485271UL, 2689121900UL, 2335686695UL, 246689858UL, 2946177636UL, 1677728066UL, 1455723263UL, 3447540996UL, 2143976172UL, 1779511280UL, 3667361203UL, 1575502035UL, 849872082UL, 3527265600UL, 1443266215UL, 1320668722UL, 458373857UL, 3862342513UL, 699597603UL, 685707268UL, 948502001UL, 2501058653UL, +2254562046UL, 2210683894UL, 29088679UL, 1456231200UL, 2764392560UL, 4138068372UL, 3094591474UL, 1093749152UL, 1668875176UL, 3133003149UL, 4128702884UL, 652852832UL, 2211671337UL, 2231125160UL, 131729558UL, 3845605816UL, 3769660625UL, 1696592453UL, 728353643UL, 2751201502UL, 3496971733UL, 3349166522UL, 1005919830UL, 3411089601UL, 3754493523UL, 1994945529UL, 1604309774UL, 2083609686UL, 833983349UL, 2600153513UL, 1677348112UL, 207321473UL, +1051990507UL, 2135039620UL, 4239461390UL, 1574144998UL, 1070761856UL, 1990807569UL, 112704720UL, 2506523299UL, 2827487353UL, 4130754901UL, 1943274185UL, 3913701053UL, 1014850621UL, 3662772872UL, 4115124063UL, 1760146762UL, 3254829227UL, 800302547UL, 3602066837UL, 975658158UL, 2880018391UL, 714134831UL, 2696483406UL, 2351365577UL, 2811011071UL, 3505407160UL, 54109504UL, 424967367UL, 3759525737UL, 1726627246UL, 1110539071UL, 2339755764UL, +3356877114UL, 1720103319UL, 2201367526UL, 1415072072UL, 2446588589UL, 2499136377UL, 3817930623UL, 653121934UL, 2766514657UL, 765921436UL, 3794433488UL, 2990883045UL, 3304472999UL, 471385134UL, 4097977544UL, 3618516788UL, 3587534772UL, 1064359851UL, 800061060UL, 2844220510UL, 2319780070UL, 3681318140UL, 1515923235UL, 1885079324UL, 713031018UL, 11705290UL, 2288160004UL, 1983331336UL, 1247350521UL, 4208372034UL, 2508892029UL, 3549494305UL, +4169715512UL, 701313302UL, 1118275019UL, 1430522809UL, 4153969630UL, 3516491181UL, 3601057044UL, 2509222288UL, 1917025539UL, 899123842UL, 2574531231UL, 1386928111UL, 3790651401UL, 1219040401UL, 2038833061UL, 3736517792UL, 3850203561UL, 1679542285UL, 671522957UL, 3862995487UL, 3118056386UL, 47128429UL, 2977525950UL, 2762831063UL, 1937040839UL, 4223233198UL, 2105119262UL, 721111284UL, 1386688457UL, 68419013UL, 2575393464UL, 3648293304UL, +1448878851UL, 466405406UL, 3696899986UL, 1270877069UL, 3351263117UL, 3918639273UL, 94103836UL, 2767482392UL, 3549853842UL, 2353191576UL, 3353325530UL, 349361794UL, 2689121900UL, 2335686695UL, 246689858UL, 2946177636UL, 3232050945UL, 1455723263UL, 3447540996UL, 2143976172UL, 1779511280UL, 542837628UL, 1575502035UL, 849872082UL, 3527265600UL, 1443266215UL, 1867394883UL, 458373857UL, 3862342513UL, 699597603UL, 685707268UL, 4210562190UL, +2501058653UL, 2254562046UL, 2210683894UL, 29088679UL, 3647972960UL, 2764392560UL, 4138068372UL, 3094591474UL, 1093749152UL, 312511475UL, 3133003149UL, 4128702884UL, 652852832UL, 2211671337UL, 145492343UL, 131729558UL, 3845605816UL, 3769660625UL, 1696592453UL, 4223421915UL, 2751201502UL, 3496971733UL, 3349166522UL, 1005919830UL, 1656802049UL, 3754493523UL, 1994945529UL, 1604309774UL, 2083609686UL, 3032348100UL, 2600153513UL, 1677348112UL, +207321473UL, 1051990507UL, 3349078950UL, 4239461390UL, 1574144998UL, 1070761856UL, 1990807569UL, 2970449178UL, 2506523299UL, 2827487353UL, 4130754901UL, 1943274185UL, 445467699UL, 1014850621UL, 3662772872UL, 4115124063UL, 1760146762UL, 3738518624UL, 800302547UL, 3602066837UL, 975658158UL, 2880018391UL, 1553758240UL, 2696483406UL, 2351365577UL, 2811011071UL, 3505407160UL, 1259180427UL, 424967367UL, 3759525737UL, 1726627246UL, 1110539071UL, +2863575420UL, 3356877114UL, 1720103319UL, 2201367526UL, 1415072072UL, 1463388387UL, 2499136377UL, 3817930623UL, 653121934UL, 2766514657UL, 526940162UL, 3794433488UL, 2990883045UL, 3304472999UL, 471385134UL, 594057325UL, 3618516788UL, 3587534772UL, 1064359851UL, 800061060UL, 1001523010UL, 2319780070UL, 3681318140UL, 1515923235UL, 1885079324UL, 255576756UL, 11705290UL, 2288160004UL, 1983331336UL, 1247350521UL, 1108575113UL, 2508892029UL, +3549494305UL, 4169715512UL, 701313302UL, 524281295UL, 1430522809UL, 4153969630UL, 3516491181UL, 3601057044UL, 1816283752UL, 1917025539UL, 899123842UL, 2574531231UL, 1386928111UL, 1530966640UL, 1219040401UL, 2038833061UL, 3736517792UL, 3850203561UL, 1855689726UL, 671522957UL, 3862995487UL, 3118056386UL, 47128429UL, 1718476461UL, 2762831063UL, 1937040839UL, 4223233198UL, 2105119262UL, 176166283UL, 1386688457UL, 68419013UL, 2575393464UL, +3648293304UL, 4069820559UL, 466405406UL, 3696899986UL, 1270877069UL, 3351263117UL, 1645545933UL, 94103836UL, 2767482392UL, 3549853842UL, 2353191576UL, 4163887784UL, 349361794UL, 2689121900UL, 2335686695UL, 246689858UL, 1246040634UL, 3232050945UL, 1455723263UL, 3447540996UL, 2143976172UL, 2111249329UL, 542837628UL, 1575502035UL, 849872082UL, 3527265600UL, 1836050084UL, 1867394883UL, 458373857UL, 3862342513UL, 699597603UL, 3139537113UL, +4210562190UL, 2501058653UL, 2254562046UL, 2210683894UL, 3997617191UL, 3647972960UL, 2764392560UL, 4138068372UL, 3094591474UL, 2664795910UL, 312511475UL, 3133003149UL, 4128702884UL, 652852832UL, 1658020144UL, 145492343UL, 131729558UL, 3845605816UL, 3769660625UL, 2822578949UL, 4223421915UL, 2751201502UL, 3496971733UL, 3349166522UL, 1582873482UL, 1656802049UL, 3754493523UL, 1994945529UL, 1604309774UL, 1113569720UL, 3032348100UL, 2600153513UL, +1677348112UL, 207321473UL, 3169983987UL, 3349078950UL, 4239461390UL, 1574144998UL, 1070761856UL, 1308776367UL, 2970449178UL, 2506523299UL, 2827487353UL, 4130754901UL, 1403493846UL, 445467699UL, 1014850621UL, 3662772872UL, 4115124063UL, 340210579UL, 3738518624UL, 800302547UL, 3602066837UL, 975658158UL, 3367770843UL, 1553758240UL, 2696483406UL, 2351365577UL, 2811011071UL, 4162875353UL, 1259180427UL, 424967367UL, 3759525737UL, 1726627246UL, +1341806135UL, 2863575420UL, 3356877114UL, 1720103319UL, 2201367526UL, 2232383995UL, 1463388387UL, 2499136377UL, 3817930623UL, 653121934UL, 1756183481UL, 526940162UL, 3794433488UL, 2990883045UL, 3304472999UL, 2185125572UL, 594057325UL, 3618516788UL, 3587534772UL, 1064359851UL, 2933544964UL, 1001523010UL, 2319780070UL, 3681318140UL, 1515923235UL, 4147783641UL, 255576756UL, 11705290UL, 2288160004UL, 1983331336UL, 956739400UL, 1108575113UL, +2508892029UL, 3549494305UL, 4169715512UL, 142273913UL, 524281295UL, 1430522809UL, 4153969630UL, 3516491181UL, 986032639UL, 1816283752UL, 1917025539UL, 899123842UL, 2574531231UL, 1508271110UL, 1530966640UL, 1219040401UL, 2038833061UL, 3736517792UL, 458417668UL, 1855689726UL, 671522957UL, 3862995487UL, 3118056386UL, 284266432UL, 1718476461UL, 2762831063UL, 1937040839UL, 4223233198UL, 1605514069UL, 176166283UL, 1386688457UL, 68419013UL, +2575393464UL, 3650747541UL, 4069820559UL, 466405406UL, 3696899986UL, 1270877069UL, 678590674UL, 1645545933UL, 94103836UL, 2767482392UL, 3549853842UL, 398179945UL, 4163887784UL, 349361794UL, 2689121900UL, 2335686695UL, 3853658293UL, 1246040634UL, 3232050945UL, 1455723263UL, 3447540996UL, 2657693810UL, 2111249329UL, 542837628UL, 1575502035UL, 849872082UL, 2061659800UL, 1836050084UL, 1867394883UL, 458373857UL, 3862342513UL, 730568629UL, +3139537113UL, 4210562190UL, 2501058653UL, 2254562046UL, 449510786UL, 3997617191UL, 3647972960UL, 2764392560UL, 4138068372UL, 1939679536UL, 2664795910UL, 312511475UL, 3133003149UL, 4128702884UL, 4057510355UL, 1658020144UL, 145492343UL, 131729558UL, 3845605816UL, 3235632110UL, 2822578949UL, 4223421915UL, 2751201502UL, 3496971733UL, 4258920219UL, 1582873482UL, 1656802049UL, 3754493523UL, 1994945529UL, 1073499993UL, 1113569720UL, 3032348100UL, +2600153513UL, 1677348112UL, 3152835240UL, 3169983987UL, 3349078950UL, 4239461390UL, 1574144998UL, 2548972357UL, 1308776367UL, 2970449178UL, 2506523299UL, 2827487353UL, 2908066033UL, 1403493846UL, 445467699UL, 1014850621UL, 3662772872UL, 1685925089UL, 340210579UL, 3738518624UL, 800302547UL, 3602066837UL, 2264692610UL, 3367770843UL, 1553758240UL, 2696483406UL, 2351365577UL, 1686022564UL, 4162875353UL, 1259180427UL, 424967367UL, 3759525737UL, +70326173UL, 3028074555UL, 2568586198UL, 2513473964UL, 2923109510UL, 2265392251UL, 3760490867UL, 147487099UL, 386755149UL, 2152759137UL, 2716532213UL, 1153507474UL, 627929575UL, 847454712UL, 2426916452UL, 3861548980UL, 209825268UL, 1090299778UL, 1876886461UL, 976019203UL, 4290216337UL, 2278290065UL, 3302814528UL, 1567440061UL, 1874857224UL, 3794588915UL, 3218569451UL, 2335365199UL, 1959651923UL, 3366000689UL, 2374428382UL, 2126784887UL, +4123272655UL, 274837369UL, 1413111935UL, 1754627204UL, 1863684635UL, 4170025739UL, 2150019850UL, 4250751856UL, 3601214212UL, 2024081043UL, 334808859UL, 3921757513UL, 3870643644UL, 2864810945UL, 1004431888UL, 4283279830UL, 873365350UL, 2479791433UL, 3393478881UL, 3373502257UL, 1882140107UL, 2546676519UL, 1208428915UL, 268043238UL, 2292710623UL, 770651064UL, 2330160036UL, 2476488258UL, 2496037992UL, 118721504UL, 2289499985UL, 987994743UL, +3610346256UL, 3371795927UL, 2681434550UL, 2213200417UL, 3729194378UL, 1657623395UL, 402983380UL, 3618058500UL, 3487743585UL, 965523531UL, 819256729UL, 2544660729UL, 3273986506UL, 60894411UL, 1779152929UL, 3598159279UL, 3429317853UL, 2246402362UL, 3761392367UL, 3921798306UL, 947928110UL, 2394097908UL, 4004330264UL, 1180759989UL, 1624349051UL, 1750929499UL, 3889184770UL, 2052097704UL, 4092981046UL, 2913733578UL, 4241980897UL, 1127407450UL, +950788009UL, 2105033320UL, 473205730UL, 981905310UL, 2888856914UL, 798112239UL, 3377889612UL, 2273659507UL, 1157471194UL, 4269212574UL, 3575306012UL, 116024754UL, 1432668659UL, 1079598649UL, 3882002482UL, 3838480186UL, 823643071UL, 1244220618UL, 1227720039UL, 1343395654UL, 4277277976UL, 2612321540UL, 3013674017UL, 3658064522UL, 2573775167UL, 142767236UL, 2545708383UL, 1740478937UL, 809036862UL, 1492188594UL, 1294286248UL, 1093543858UL, +2944418375UL, 2981996479UL, 4067464923UL, 3071157685UL, 1938984450UL, 81707323UL, 337713546UL, 1849381296UL, 3447450393UL, 3551106302UL, 3394545269UL, 3167744716UL, 1815294624UL, 3244728913UL, 2462138247UL, 2286711732UL, 3023116169UL, 707366723UL, 1314169762UL, 1511231537UL, 2227622993UL, 2876600706UL, 4271030726UL, 2020521540UL, 2966596767UL, 3964589247UL, 1291306737UL, 883851756UL, 1355819080UL, 2834319249UL, 3825063450UL, 4205423325UL, +}, +{ +525214560UL, 1972466543UL, 1542775297UL, 3030388145UL, 2623763324UL, 1445252054UL, 2315649878UL, 2940376435UL, 1322155857UL, 2007925719UL, 899111545UL, 3946601974UL, 720416639UL, 566341007UL, 3830971140UL, 2379218430UL, 946001131UL, 324551023UL, 3792134824UL, 2419222364UL, 2507004728UL, 4050415702UL, 2934667964UL, 3435655480UL, 3738151878UL, 340092998UL, 429296098UL, 3804978739UL, 1547120540UL, 976306993UL, 1134820236UL, 288696971UL, +292350374UL, 423348923UL, 4250561112UL, 1380146522UL, 646098313UL, 3081299572UL, 3633231429UL, 2348008746UL, 3250735726UL, 3495239618UL, 1083361876UL, 2660545988UL, 97607299UL, 741626628UL, 2451882102UL, 607936604UL, 1566190301UL, 3752644837UL, 1626575269UL, 2569947980UL, 120166892UL, 1936167922UL, 2964570009UL, 2601765059UL, 2550590348UL, 1491574373UL, 1916644920UL, 2955888714UL, 3900360190UL, 396836243UL, 2417234534UL, 4219822777UL, +3017031315UL, 3848370775UL, 4113753945UL, 1038708316UL, 1227041843UL, 1287656330UL, 594136009UL, 1679465955UL, 1127853612UL, 445673212UL, 2491164616UL, 4234959779UL, 3670094401UL, 2810998507UL, 2091885715UL, 4213376041UL, 3724691332UL, 1428205363UL, 2351471476UL, 1863345709UL, 3172242044UL, 1435176883UL, 925973933UL, 3166951436UL, 2056462416UL, 489417029UL, 4029854347UL, 3002516723UL, 1597712463UL, 1200457469UL, 3909654542UL, 1352519428UL, +13398705UL, 3919269221UL, 371331154UL, 332347636UL, 3726033518UL, 2407091731UL, 2926199215UL, 3054175446UL, 3208807730UL, 584793525UL, 2706493003UL, 561190823UL, 2412132195UL, 2488492462UL, 3149885896UL, 3512276852UL, 2843032269UL, 2485506176UL, 4025325347UL, 4152622551UL, 4022346903UL, 331746013UL, 197533993UL, 3658414685UL, 2670729696UL, 3290854172UL, 2251426444UL, 3569225076UL, 2466203243UL, 658184940UL, 518096293UL, 52156682UL, +2398958685UL, 745491615UL, 3723004242UL, 2847276077UL, 1857504125UL, 633035220UL, 4057593658UL, 2783467746UL, 3122875931UL, 446601186UL, 2786851490UL, 261950076UL, 2843506874UL, 745391893UL, 1404094021UL, 2234513997UL, 315083019UL, 645865358UL, 2862243948UL, 1204315994UL, 3701151065UL, 663411328UL, 1924727700UL, 1905843757UL, 1483930049UL, 449616818UL, 3793968150UL, 1840668755UL, 1671024110UL, 4079375869UL, 4171670660UL, 2585904968UL, +3886777251UL, 525214560UL, 1972466543UL, 1542775297UL, 3030388145UL, 2530126952UL, 1445252054UL, 2315649878UL, 2940376435UL, 1322155857UL, 1599103627UL, 899111545UL, 3946601974UL, 720416639UL, 566341007UL, 4070101360UL, 2379218430UL, 946001131UL, 324551023UL, 3792134824UL, 2445126690UL, 2507004728UL, 4050415702UL, 2934667964UL, 3435655480UL, 2968121571UL, 340092998UL, 429296098UL, 3804978739UL, 1547120540UL, 3901803457UL, 1134820236UL, +288696971UL, 292350374UL, 423348923UL, 1589814289UL, 1380146522UL, 646098313UL, 3081299572UL, 3633231429UL, 670777956UL, 3250735726UL, 3495239618UL, 1083361876UL, 2660545988UL, 4050232394UL, 741626628UL, 2451882102UL, 607936604UL, 1566190301UL, 1132827700UL, 1626575269UL, 2569947980UL, 120166892UL, 1936167922UL, 1280520333UL, 2601765059UL, 2550590348UL, 1491574373UL, 1916644920UL, 1073889810UL, 3900360190UL, 396836243UL, 2417234534UL, +4219822777UL, 1754651820UL, 3848370775UL, 4113753945UL, 1038708316UL, 1227041843UL, 464826842UL, 594136009UL, 1679465955UL, 1127853612UL, 445673212UL, 4198686893UL, 4234959779UL, 3670094401UL, 2810998507UL, 2091885715UL, 416103731UL, 3724691332UL, 1428205363UL, 2351471476UL, 1863345709UL, 2637470915UL, 1435176883UL, 925973933UL, 3166951436UL, 2056462416UL, 2546319147UL, 4029854347UL, 3002516723UL, 1597712463UL, 1200457469UL, 681365672UL, +1352519428UL, 13398705UL, 3919269221UL, 371331154UL, 742849231UL, 3726033518UL, 2407091731UL, 2926199215UL, 3054175446UL, 1323833820UL, 584793525UL, 2706493003UL, 561190823UL, 2412132195UL, 3747238187UL, 3149885896UL, 3512276852UL, 2843032269UL, 2485506176UL, 3817319503UL, 4152622551UL, 4022346903UL, 331746013UL, 197533993UL, 99009902UL, 2670729696UL, 3290854172UL, 2251426444UL, 3569225076UL, 4199909720UL, 658184940UL, 518096293UL, +52156682UL, 2398958685UL, 1648201186UL, 3723004242UL, 2847276077UL, 1857504125UL, 633035220UL, 1394668680UL, 2783467746UL, 3122875931UL, 446601186UL, 2786851490UL, 2590549096UL, 2843506874UL, 745391893UL, 1404094021UL, 2234513997UL, 347299411UL, 645865358UL, 2862243948UL, 1204315994UL, 3701151065UL, 4028305509UL, 1924727700UL, 1905843757UL, 1483930049UL, 449616818UL, 2251238906UL, 1840668755UL, 1671024110UL, 4079375869UL, 4171670660UL, +4080554282UL, 3886777251UL, 525214560UL, 1972466543UL, 1542775297UL, 3280177496UL, 2530126952UL, 1445252054UL, 2315649878UL, 2940376435UL, 2094983509UL, 1599103627UL, 899111545UL, 3946601974UL, 720416639UL, 1446566513UL, 4070101360UL, 2379218430UL, 946001131UL, 324551023UL, 2945613775UL, 2445126690UL, 2507004728UL, 4050415702UL, 2934667964UL, 2815036731UL, 2968121571UL, 340092998UL, 429296098UL, 3804978739UL, 3298867574UL, 3901803457UL, +1134820236UL, 288696971UL, 292350374UL, 3280367987UL, 1589814289UL, 1380146522UL, 646098313UL, 3081299572UL, 2536311658UL, 670777956UL, 3250735726UL, 3495239618UL, 1083361876UL, 3726225049UL, 4050232394UL, 741626628UL, 2451882102UL, 607936604UL, 3460165725UL, 1132827700UL, 1626575269UL, 2569947980UL, 120166892UL, 2961109404UL, 1280520333UL, 2601765059UL, 2550590348UL, 1491574373UL, 755823086UL, 1073889810UL, 3900360190UL, 396836243UL, +2417234534UL, 3036027780UL, 1754651820UL, 3848370775UL, 4113753945UL, 1038708316UL, 3784147349UL, 464826842UL, 594136009UL, 1679465955UL, 1127853612UL, 2128970592UL, 4198686893UL, 4234959779UL, 3670094401UL, 2810998507UL, 421961324UL, 416103731UL, 3724691332UL, 1428205363UL, 2351471476UL, 3407618159UL, 2637470915UL, 1435176883UL, 925973933UL, 3166951436UL, 1274860184UL, 2546319147UL, 4029854347UL, 3002516723UL, 1597712463UL, 671480036UL, +681365672UL, 1352519428UL, 13398705UL, 3919269221UL, 1150967289UL, 742849231UL, 3726033518UL, 2407091731UL, 2926199215UL, 3106945136UL, 1323833820UL, 584793525UL, 2706493003UL, 561190823UL, 2013357219UL, 3747238187UL, 3149885896UL, 3512276852UL, 2843032269UL, 3595347994UL, 3817319503UL, 4152622551UL, 4022346903UL, 331746013UL, 367216863UL, 99009902UL, 2670729696UL, 3290854172UL, 2251426444UL, 3130148315UL, 4199909720UL, 658184940UL, +518096293UL, 52156682UL, 3004378899UL, 1648201186UL, 3723004242UL, 2847276077UL, 1857504125UL, 253542783UL, 1394668680UL, 2783467746UL, 3122875931UL, 446601186UL, 1228837642UL, 2590549096UL, 2843506874UL, 745391893UL, 1404094021UL, 1324404436UL, 347299411UL, 645865358UL, 2862243948UL, 1204315994UL, 1455458347UL, 4028305509UL, 1924727700UL, 1905843757UL, 1483930049UL, 330348422UL, 2251238906UL, 1840668755UL, 1671024110UL, 4079375869UL, +606568968UL, 4080554282UL, 3886777251UL, 525214560UL, 1972466543UL, 1703103913UL, 3280177496UL, 2530126952UL, 1445252054UL, 2315649878UL, 3946153427UL, 2094983509UL, 1599103627UL, 899111545UL, 3946601974UL, 2053673584UL, 1446566513UL, 4070101360UL, 2379218430UL, 946001131UL, 4184236551UL, 2945613775UL, 2445126690UL, 2507004728UL, 4050415702UL, 3890831500UL, 2815036731UL, 2968121571UL, 340092998UL, 429296098UL, 228493148UL, 3298867574UL, +3901803457UL, 1134820236UL, 288696971UL, 2321943990UL, 3280367987UL, 1589814289UL, 1380146522UL, 646098313UL, 1765624343UL, 2536311658UL, 670777956UL, 3250735726UL, 3495239618UL, 1772431608UL, 3726225049UL, 4050232394UL, 741626628UL, 2451882102UL, 3386124330UL, 3460165725UL, 1132827700UL, 1626575269UL, 2569947980UL, 860947846UL, 2961109404UL, 1280520333UL, 2601765059UL, 2550590348UL, 2298495740UL, 755823086UL, 1073889810UL, 3900360190UL, +396836243UL, 2702634902UL, 3036027780UL, 1754651820UL, 3848370775UL, 4113753945UL, 3836550212UL, 3784147349UL, 464826842UL, 594136009UL, 1679465955UL, 1500399122UL, 2128970592UL, 4198686893UL, 4234959779UL, 3670094401UL, 1632934875UL, 421961324UL, 416103731UL, 3724691332UL, 1428205363UL, 2330377177UL, 3407618159UL, 2637470915UL, 1435176883UL, 925973933UL, 2558479866UL, 1274860184UL, 2546319147UL, 4029854347UL, 3002516723UL, 1331271216UL, +671480036UL, 681365672UL, 1352519428UL, 13398705UL, 1532459856UL, 1150967289UL, 742849231UL, 3726033518UL, 2407091731UL, 1766120506UL, 3106945136UL, 1323833820UL, 584793525UL, 2706493003UL, 3817434387UL, 2013357219UL, 3747238187UL, 3149885896UL, 3512276852UL, 203757UL, 3595347994UL, 3817319503UL, 4152622551UL, 4022346903UL, 3438004885UL, 367216863UL, 99009902UL, 2670729696UL, 3290854172UL, 1092092654UL, 3130148315UL, 4199909720UL, +658184940UL, 518096293UL, 982576981UL, 3004378899UL, 1648201186UL, 3723004242UL, 2847276077UL, 33113683UL, 253542783UL, 1394668680UL, 2783467746UL, 3122875931UL, 3109404671UL, 1228837642UL, 2590549096UL, 2843506874UL, 745391893UL, 809710525UL, 1324404436UL, 347299411UL, 645865358UL, 2862243948UL, 3652256751UL, 1455458347UL, 4028305509UL, 1924727700UL, 1905843757UL, 2035132481UL, 330348422UL, 2251238906UL, 1840668755UL, 1671024110UL, +3593348393UL, 4151905045UL, 3398483770UL, 611142788UL, 1798029112UL, 2747225670UL, 2894981396UL, 2117120651UL, 3087941624UL, 416876364UL, 700011792UL, 63929447UL, 822005210UL, 3483417647UL, 3513365134UL, 3071572873UL, 1925919001UL, 2778688996UL, 3079943255UL, 1252316311UL, 91270196UL, 3469862149UL, 156659741UL, 1342755036UL, 3821302858UL, 1790046971UL, 289329863UL, 1357914395UL, 4143182690UL, 2590503919UL, 3242437796UL, 1341085928UL, +2685277054UL, 727602392UL, 2581493226UL, 3216496864UL, 2171373196UL, 3767765187UL, 1895767358UL, 1029452326UL, 851913526UL, 1746266839UL, 3370323171UL, 648118190UL, 3244211645UL, 2623946928UL, 3859087079UL, 384443034UL, 2026989771UL, 802104797UL, 2201121552UL, 725742304UL, 1673563239UL, 4045658814UL, 2682764476UL, 3032306650UL, 2725871420UL, 3467522540UL, 534803010UL, 1135606913UL, 871336950UL, 937160030UL, 3384357161UL, 641566845UL, +2267407903UL, 331847343UL, 787968740UL, 2673012251UL, 2066357778UL, 2740382722UL, 1638377946UL, 2260504282UL, 3513172717UL, 238548903UL, 2203496688UL, 630532448UL, 3702112076UL, 2635952931UL, 3344713216UL, 139406056UL, 2369004628UL, 3547213209UL, 2944858950UL, 1231203228UL, 616949630UL, 2619739101UL, 89360251UL, 2364353701UL, 1025345607UL, 4177965685UL, 62274372UL, 3059207586UL, 3303376016UL, 2919795870UL, 3676526103UL, 2689781822UL, +1062293263UL, 2684605838UL, 863975243UL, 723728777UL, 1057919510UL, 1708017843UL, 4264127977UL, 3013938022UL, 3958746896UL, 328415103UL, 1117948849UL, 751056929UL, 2442147201UL, 1781170563UL, 765377308UL, 961452970UL, 4247303973UL, 2233034754UL, 86997820UL, 3495561473UL, 3075957349UL, 3152032365UL, 1220657606UL, 708134514UL, 26714613UL, 3749542051UL, 1640668224UL, 2252760600UL, 1635050662UL, 947216628UL, 3612773344UL, 4089189500UL, +3647048119UL, 979491227UL, 4149824933UL, 3160885292UL, 2808843788UL, 998859510UL, 3903167193UL, 1728999561UL, 3673946130UL, 279338980UL, 2507635299UL, 1614929524UL, 302060483UL, 2874453052UL, 3798613814UL, 2013436766UL, 3514754020UL, 2923162106UL, 2658720327UL, 3498579091UL, 3292220096UL, 3796129102UL, 1907288796UL, 2820663603UL, 4276052248UL, 247755133UL, 2088596201UL, 3154955976UL, 3309397641UL, 3606171919UL, 1356791029UL, 1030266022UL, +}, +{ +3868946146UL, 1938156793UL, 1877502872UL, 1408917625UL, 1549117911UL, 2465501566UL, 4218547770UL, 2942249332UL, 2731789075UL, 2366036899UL, 1312641799UL, 2243363271UL, 2238839307UL, 384814263UL, 1552361757UL, 3521369641UL, 431721717UL, 3089625732UL, 1023760034UL, 53847139UL, 2240881978UL, 3178046414UL, 145135653UL, 1580878781UL, 3500228040UL, 3360910006UL, 3285542950UL, 3330062556UL, 2870158227UL, 1481496810UL, 4222704363UL, 2973046526UL, +435155769UL, 3234730070UL, 3306545960UL, 2539776908UL, 3991420334UL, 125389349UL, 2397544348UL, 2504790975UL, 886432257UL, 1804136430UL, 1506551086UL, 219847214UL, 890282686UL, 1489840806UL, 2536942497UL, 87527661UL, 1822718904UL, 3984956867UL, 2334419518UL, 4065487054UL, 992104547UL, 1566792845UL, 1068226712UL, 2622731799UL, 921431708UL, 2833392639UL, 640267449UL, 324907409UL, 3911698049UL, 2108189994UL, 1623761598UL, 52771719UL, +467926435UL, 2811768106UL, 3760723083UL, 906402727UL, 3438479463UL, 2064004404UL, 988123982UL, 563076447UL, 2979641383UL, 1366086397UL, 2078608605UL, 3868491514UL, 1077957067UL, 615363273UL, 1388831706UL, 1586480552UL, 4216838311UL, 3587550780UL, 2057048927UL, 2814838921UL, 2454041809UL, 180612020UL, 930406098UL, 4286819113UL, 2756562967UL, 3404265234UL, 3844482428UL, 467484533UL, 4122644954UL, 3517116598UL, 1887163240UL, 4217569180UL, +4191149652UL, 2756931330UL, 3702787956UL, 152166773UL, 146763911UL, 536678737UL, 481385008UL, 3681433244UL, 1194909733UL, 3713568496UL, 3927837202UL, 846842608UL, 687314083UL, 1144793694UL, 1062075916UL, 3017627145UL, 1296695243UL, 981862419UL, 2363304726UL, 3242788356UL, 3359957762UL, 4249190787UL, 1697910336UL, 3286799886UL, 1063822293UL, 3246091430UL, 743808559UL, 2137668568UL, 2812072749UL, 2303791182UL, 3161789548UL, 2911126624UL, +4087873192UL, 1813622227UL, 1272618849UL, 1882292328UL, 3861455677UL, 2921641470UL, 3079812494UL, 2814569163UL, 1975646942UL, 2826176621UL, 1896904368UL, 831552834UL, 2935863403UL, 449217054UL, 3688067832UL, 1048877596UL, 1613227043UL, 553867520UL, 3682575786UL, 3058863948UL, 4200858129UL, 4131625UL, 2434123776UL, 2235627905UL, 2905358693UL, 3429312266UL, 3363231514UL, 1182242507UL, 2792234422UL, 1843330053UL, 4192875151UL, 1088813348UL, +357805687UL, 3868946146UL, 1938156793UL, 1877502872UL, 1408917625UL, 30638250UL, 2465501566UL, 4218547770UL, 2942249332UL, 2731789075UL, 448998968UL, 1312641799UL, 2243363271UL, 2238839307UL, 384814263UL, 2229663001UL, 3521369641UL, 431721717UL, 3089625732UL, 1023760034UL, 790771414UL, 2240881978UL, 3178046414UL, 145135653UL, 1580878781UL, 847577516UL, 3360910006UL, 3285542950UL, 3330062556UL, 2870158227UL, 112738978UL, 4222704363UL, +2973046526UL, 435155769UL, 3234730070UL, 1135073835UL, 2539776908UL, 3991420334UL, 125389349UL, 2397544348UL, 1243128255UL, 886432257UL, 1804136430UL, 1506551086UL, 219847214UL, 875051553UL, 1489840806UL, 2536942497UL, 87527661UL, 1822718904UL, 1883615145UL, 2334419518UL, 4065487054UL, 992104547UL, 1566792845UL, 1037132511UL, 2622731799UL, 921431708UL, 2833392639UL, 640267449UL, 504304037UL, 3911698049UL, 2108189994UL, 1623761598UL, +52771719UL, 3969520254UL, 2811768106UL, 3760723083UL, 906402727UL, 3438479463UL, 3707538496UL, 988123982UL, 563076447UL, 2979641383UL, 1366086397UL, 3577913613UL, 3868491514UL, 1077957067UL, 615363273UL, 1388831706UL, 903353909UL, 4216838311UL, 3587550780UL, 2057048927UL, 2814838921UL, 3532304828UL, 180612020UL, 930406098UL, 4286819113UL, 2756562967UL, 1950528802UL, 3844482428UL, 467484533UL, 4122644954UL, 3517116598UL, 139409766UL, +4217569180UL, 4191149652UL, 2756931330UL, 3702787956UL, 504815033UL, 146763911UL, 536678737UL, 481385008UL, 3681433244UL, 2166865052UL, 3713568496UL, 3927837202UL, 846842608UL, 687314083UL, 135403542UL, 1062075916UL, 3017627145UL, 1296695243UL, 981862419UL, 2405232584UL, 3242788356UL, 3359957762UL, 4249190787UL, 1697910336UL, 3517294012UL, 1063822293UL, 3246091430UL, 743808559UL, 2137668568UL, 2962825355UL, 2303791182UL, 3161789548UL, +2911126624UL, 4087873192UL, 2344237973UL, 1272618849UL, 1882292328UL, 3861455677UL, 2921641470UL, 1062672856UL, 2814569163UL, 1975646942UL, 2826176621UL, 1896904368UL, 3172875195UL, 2935863403UL, 449217054UL, 3688067832UL, 1048877596UL, 983648949UL, 553867520UL, 3682575786UL, 3058863948UL, 4200858129UL, 2552994282UL, 2434123776UL, 2235627905UL, 2905358693UL, 3429312266UL, 461707508UL, 1182242507UL, 2792234422UL, 1843330053UL, 4192875151UL, +2557078297UL, 357805687UL, 3868946146UL, 1938156793UL, 1877502872UL, 1178921294UL, 30638250UL, 2465501566UL, 4218547770UL, 2942249332UL, 2597087237UL, 448998968UL, 1312641799UL, 2243363271UL, 2238839307UL, 3465588695UL, 2229663001UL, 3521369641UL, 431721717UL, 3089625732UL, 2420359327UL, 790771414UL, 2240881978UL, 3178046414UL, 145135653UL, 3411014139UL, 847577516UL, 3360910006UL, 3285542950UL, 3330062556UL, 4257518865UL, 112738978UL, +4222704363UL, 2973046526UL, 435155769UL, 1154160505UL, 1135073835UL, 2539776908UL, 3991420334UL, 125389349UL, 1396475349UL, 1243128255UL, 886432257UL, 1804136430UL, 1506551086UL, 3727497731UL, 875051553UL, 1489840806UL, 2536942497UL, 87527661UL, 2521823325UL, 1883615145UL, 2334419518UL, 4065487054UL, 992104547UL, 3431387970UL, 1037132511UL, 2622731799UL, 921431708UL, 2833392639UL, 780276883UL, 504304037UL, 3911698049UL, 2108189994UL, +1623761598UL, 1832564202UL, 3969520254UL, 2811768106UL, 3760723083UL, 906402727UL, 2319993554UL, 3707538496UL, 988123982UL, 563076447UL, 2979641383UL, 3703509163UL, 3577913613UL, 3868491514UL, 1077957067UL, 615363273UL, 3925135746UL, 903353909UL, 4216838311UL, 3587550780UL, 2057048927UL, 2129250845UL, 3532304828UL, 180612020UL, 930406098UL, 4286819113UL, 571849466UL, 1950528802UL, 3844482428UL, 467484533UL, 4122644954UL, 3696836546UL, +139409766UL, 4217569180UL, 4191149652UL, 2756931330UL, 84389584UL, 504815033UL, 146763911UL, 536678737UL, 481385008UL, 281139563UL, 2166865052UL, 3713568496UL, 3927837202UL, 846842608UL, 2123715146UL, 135403542UL, 1062075916UL, 3017627145UL, 1296695243UL, 4206227732UL, 2405232584UL, 3242788356UL, 3359957762UL, 4249190787UL, 2766470555UL, 3517294012UL, 1063822293UL, 3246091430UL, 743808559UL, 2821229002UL, 2962825355UL, 2303791182UL, +3161789548UL, 2911126624UL, 503886017UL, 2344237973UL, 1272618849UL, 1882292328UL, 3861455677UL, 4158985014UL, 1062672856UL, 2814569163UL, 1975646942UL, 2826176621UL, 4118784229UL, 3172875195UL, 2935863403UL, 449217054UL, 3688067832UL, 3556237148UL, 983648949UL, 553867520UL, 3682575786UL, 3058863948UL, 3200838331UL, 2552994282UL, 2434123776UL, 2235627905UL, 2905358693UL, 4178312045UL, 461707508UL, 1182242507UL, 2792234422UL, 1843330053UL, +3597816691UL, 2557078297UL, 357805687UL, 3868946146UL, 1938156793UL, 2168462050UL, 1178921294UL, 30638250UL, 2465501566UL, 4218547770UL, 4101101381UL, 2597087237UL, 448998968UL, 1312641799UL, 2243363271UL, 313553894UL, 3465588695UL, 2229663001UL, 3521369641UL, 431721717UL, 737541534UL, 2420359327UL, 790771414UL, 2240881978UL, 3178046414UL, 326569272UL, 3411014139UL, 847577516UL, 3360910006UL, 3285542950UL, 3098408987UL, 4257518865UL, +112738978UL, 4222704363UL, 2973046526UL, 3668411828UL, 1154160505UL, 1135073835UL, 2539776908UL, 3991420334UL, 2902976896UL, 1396475349UL, 1243128255UL, 886432257UL, 1804136430UL, 2162242501UL, 3727497731UL, 875051553UL, 1489840806UL, 2536942497UL, 2238214198UL, 2521823325UL, 1883615145UL, 2334419518UL, 4065487054UL, 1081167745UL, 3431387970UL, 1037132511UL, 2622731799UL, 921431708UL, 2612105434UL, 780276883UL, 504304037UL, 3911698049UL, +2108189994UL, 2518535877UL, 1832564202UL, 3969520254UL, 2811768106UL, 3760723083UL, 2894544992UL, 2319993554UL, 3707538496UL, 988123982UL, 563076447UL, 719340658UL, 3703509163UL, 3577913613UL, 3868491514UL, 1077957067UL, 2371417985UL, 3925135746UL, 903353909UL, 4216838311UL, 3587550780UL, 3146473377UL, 2129250845UL, 3532304828UL, 180612020UL, 930406098UL, 1054512059UL, 571849466UL, 1950528802UL, 3844482428UL, 467484533UL, 1437844285UL, +3696836546UL, 139409766UL, 4217569180UL, 4191149652UL, 1161452915UL, 84389584UL, 504815033UL, 146763911UL, 536678737UL, 3965987378UL, 281139563UL, 2166865052UL, 3713568496UL, 3927837202UL, 2566873330UL, 2123715146UL, 135403542UL, 1062075916UL, 3017627145UL, 3204726297UL, 4206227732UL, 2405232584UL, 3242788356UL, 3359957762UL, 2338319494UL, 2766470555UL, 3517294012UL, 1063822293UL, 3246091430UL, 1531757306UL, 2821229002UL, 2962825355UL, +2303791182UL, 3161789548UL, 2778326467UL, 503886017UL, 2344237973UL, 1272618849UL, 1882292328UL, 1725075819UL, 4158985014UL, 1062672856UL, 2814569163UL, 1975646942UL, 3822868823UL, 4118784229UL, 3172875195UL, 2935863403UL, 449217054UL, 2465297154UL, 3556237148UL, 983648949UL, 553867520UL, 3682575786UL, 4023654874UL, 3200838331UL, 2552994282UL, 2434123776UL, 2235627905UL, 3063253867UL, 4178312045UL, 461707508UL, 1182242507UL, 2792234422UL, +3673318927UL, 1249828417UL, 2772427670UL, 1052324962UL, 3106530204UL, 2843183862UL, 630633945UL, 4140139503UL, 1659674037UL, 1096812757UL, 1376150732UL, 2328468653UL, 1410746620UL, 4025107990UL, 3335632421UL, 2754906610UL, 1615859006UL, 285467698UL, 4013475548UL, 1287384555UL, 1191111485UL, 1999165134UL, 2396354947UL, 1628158236UL, 3586708909UL, 228664781UL, 2501369720UL, 2516229872UL, 2977432606UL, 1745869751UL, 750661412UL, 1142144084UL, +2705268946UL, 1728488244UL, 589587862UL, 3604281130UL, 3217245915UL, 2061424631UL, 1918958878UL, 1162850007UL, 438550637UL, 1774088146UL, 3237803593UL, 827476363UL, 404982536UL, 2344744845UL, 3416436851UL, 369597250UL, 287618335UL, 1349740180UL, 3489688427UL, 417859991UL, 3229729092UL, 3214122057UL, 3955335849UL, 3014669381UL, 2178319957UL, 1259991234UL, 2689513541UL, 2628816894UL, 3734652479UL, 4202568782UL, 3149274749UL, 497295490UL, +3427602420UL, 3229774907UL, 59257138UL, 856364156UL, 429586733UL, 1800559699UL, 1300239050UL, 1311125646UL, 257421988UL, 3749074142UL, 1648939149UL, 1914174865UL, 105489877UL, 3599116888UL, 2695725484UL, 1543985792UL, 3210070699UL, 1867126432UL, 3088920410UL, 953084407UL, 2185095866UL, 1427606476UL, 1572442276UL, 3322674991UL, 3578824788UL, 1156246244UL, 2938200612UL, 3409545464UL, 215820858UL, 2279282461UL, 3861049095UL, 1589517366UL, +208707366UL, 2741570297UL, 440313302UL, 864288468UL, 1564945290UL, 1050929272UL, 3037450392UL, 1101323242UL, 1200278943UL, 3005564105UL, 3847988630UL, 3251750599UL, 2608433412UL, 3106720723UL, 1522694503UL, 3857782840UL, 4282681349UL, 2229263718UL, 4106780914UL, 125648941UL, 1933617693UL, 2971178569UL, 3537872030UL, 448962137UL, 652123777UL, 2393871920UL, 3938047691UL, 244410098UL, 3110791961UL, 3122318189UL, 877378106UL, 3683644255UL, +4279094311UL, 3638987055UL, 667681197UL, 1679868535UL, 1938378101UL, 1331340184UL, 734163051UL, 3409564713UL, 955108672UL, 3969637663UL, 156515523UL, 1871394552UL, 590275639UL, 3237133664UL, 898438533UL, 2291347006UL, 644781653UL, 3575493549UL, 1206698159UL, 2484805619UL, 2931447110UL, 2411269190UL, 3866437145UL, 161562563UL, 3077166456UL, 792874130UL, 3193406610UL, 2500233218UL, 596837225UL, 3667458052UL, 3239960816UL, 2271901243UL, +}, +{ +3975736867UL, 2402230281UL, 4092718962UL, 3100052505UL, 3277909563UL, 2827154828UL, 1067483357UL, 3495429909UL, 426635932UL, 2702495453UL, 725679489UL, 3705541400UL, 1308182381UL, 27549785UL, 3000675918UL, 2982141597UL, 1090931027UL, 755020243UL, 3986354189UL, 2529541113UL, 452574019UL, 2384876926UL, 2147764179UL, 1360907484UL, 2072364695UL, 3034185952UL, 2765119653UL, 3279755577UL, 3828140333UL, 582568392UL, 4228353628UL, 701214306UL, +2460043371UL, 3943376509UL, 2443090800UL, 2481277520UL, 859309333UL, 2928621220UL, 1933644685UL, 3803162893UL, 3310629548UL, 2361261213UL, 790233558UL, 2517540072UL, 2823327610UL, 2952921690UL, 3295251862UL, 1089451775UL, 2637751681UL, 1648031370UL, 1343061717UL, 2355026672UL, 67684812UL, 4019593497UL, 2636283634UL, 1051433451UL, 51111285UL, 15338687UL, 3779021741UL, 3987886044UL, 70037785UL, 2009147353UL, 4236701871UL, 928261128UL, +2185183571UL, 2793993680UL, 2975111058UL, 3730415022UL, 3316612678UL, 823585671UL, 4153354125UL, 509071385UL, 2056228251UL, 4034784810UL, 96820040UL, 169863045UL, 932848332UL, 2282651407UL, 747279843UL, 1387211022UL, 2410099142UL, 3394315084UL, 3191572807UL, 4073182500UL, 3768455462UL, 3712420663UL, 3000991259UL, 249137656UL, 2477445202UL, 3952155443UL, 392730170UL, 4208559971UL, 24751401UL, 661761054UL, 1574175475UL, 2715927647UL, +985309803UL, 2570053358UL, 619269634UL, 3890591314UL, 1129119636UL, 3133886450UL, 328788870UL, 3449809720UL, 1380118080UL, 2719792059UL, 691527418UL, 3487733607UL, 3819095050UL, 3367871088UL, 709089170UL, 1057897966UL, 1938975941UL, 4082466714UL, 251564920UL, 3083496965UL, 1040123365UL, 295024253UL, 2788334176UL, 3430095934UL, 3641758945UL, 2029993123UL, 3231254260UL, 150555625UL, 2270671577UL, 2032382533UL, 2088497043UL, 1392075576UL, +644811077UL, 2122632989UL, 3224165725UL, 1571908345UL, 2558692460UL, 1493305706UL, 4064652450UL, 448105905UL, 699188129UL, 2017324335UL, 4286307548UL, 2415725473UL, 3976741021UL, 3526784185UL, 2882973520UL, 3420335125UL, 2034028744UL, 1425242390UL, 982315917UL, 2614735561UL, 2439972944UL, 2518992720UL, 3792239985UL, 3260669732UL, 2586472751UL, 3432756715UL, 1318634102UL, 3722487277UL, 3037304631UL, 433233786UL, 3750002877UL, 2504731459UL, +1111327015UL, 3975736867UL, 2402230281UL, 4092718962UL, 3100052505UL, 3521430425UL, 2827154828UL, 1067483357UL, 3495429909UL, 426635932UL, 2034644068UL, 725679489UL, 3705541400UL, 1308182381UL, 27549785UL, 3001720496UL, 2982141597UL, 1090931027UL, 755020243UL, 3986354189UL, 307638580UL, 452574019UL, 2384876926UL, 2147764179UL, 1360907484UL, 1701580099UL, 3034185952UL, 2765119653UL, 3279755577UL, 3828140333UL, 2659043235UL, 4228353628UL, +701214306UL, 2460043371UL, 3943376509UL, 2084857792UL, 2481277520UL, 859309333UL, 2928621220UL, 1933644685UL, 4152646669UL, 3310629548UL, 2361261213UL, 790233558UL, 2517540072UL, 481283060UL, 2952921690UL, 3295251862UL, 1089451775UL, 2637751681UL, 2915212660UL, 1343061717UL, 2355026672UL, 67684812UL, 4019593497UL, 3290479436UL, 1051433451UL, 51111285UL, 15338687UL, 3779021741UL, 1430944862UL, 70037785UL, 2009147353UL, 4236701871UL, +928261128UL, 2063919641UL, 2793993680UL, 2975111058UL, 3730415022UL, 3316612678UL, 2373806232UL, 4153354125UL, 509071385UL, 2056228251UL, 4034784810UL, 1912268707UL, 169863045UL, 932848332UL, 2282651407UL, 747279843UL, 3712980941UL, 2410099142UL, 3394315084UL, 3191572807UL, 4073182500UL, 4262344652UL, 3712420663UL, 3000991259UL, 249137656UL, 2477445202UL, 3374467273UL, 392730170UL, 4208559971UL, 24751401UL, 661761054UL, 1670592959UL, +2715927647UL, 985309803UL, 2570053358UL, 619269634UL, 830547082UL, 1129119636UL, 3133886450UL, 328788870UL, 3449809720UL, 202644333UL, 2719792059UL, 691527418UL, 3487733607UL, 3819095050UL, 1400269159UL, 709089170UL, 1057897966UL, 1938975941UL, 4082466714UL, 3393893128UL, 3083496965UL, 1040123365UL, 295024253UL, 2788334176UL, 1219456UL, 3641758945UL, 2029993123UL, 3231254260UL, 150555625UL, 3713963210UL, 2032382533UL, 2088497043UL, +1392075576UL, 644811077UL, 3733090890UL, 3224165725UL, 1571908345UL, 2558692460UL, 1493305706UL, 1678929187UL, 448105905UL, 699188129UL, 2017324335UL, 4286307548UL, 3368868963UL, 3976741021UL, 3526784185UL, 2882973520UL, 3420335125UL, 3233347584UL, 1425242390UL, 982315917UL, 2614735561UL, 2439972944UL, 4172908214UL, 3792239985UL, 3260669732UL, 2586472751UL, 3432756715UL, 1926157640UL, 3722487277UL, 3037304631UL, 433233786UL, 3750002877UL, +625648993UL, 1111327015UL, 3975736867UL, 2402230281UL, 4092718962UL, 1349560774UL, 3521430425UL, 2827154828UL, 1067483357UL, 3495429909UL, 2808148912UL, 2034644068UL, 725679489UL, 3705541400UL, 1308182381UL, 212242504UL, 3001720496UL, 2982141597UL, 1090931027UL, 755020243UL, 2510536004UL, 307638580UL, 452574019UL, 2384876926UL, 2147764179UL, 3227931749UL, 1701580099UL, 3034185952UL, 2765119653UL, 3279755577UL, 1054678914UL, 2659043235UL, +4228353628UL, 701214306UL, 2460043371UL, 381309305UL, 2084857792UL, 2481277520UL, 859309333UL, 2928621220UL, 891630344UL, 4152646669UL, 3310629548UL, 2361261213UL, 790233558UL, 1490030690UL, 481283060UL, 2952921690UL, 3295251862UL, 1089451775UL, 2025962691UL, 2915212660UL, 1343061717UL, 2355026672UL, 67684812UL, 2217081575UL, 3290479436UL, 1051433451UL, 51111285UL, 15338687UL, 3455020635UL, 1430944862UL, 70037785UL, 2009147353UL, +4236701871UL, 1155691935UL, 2063919641UL, 2793993680UL, 2975111058UL, 3730415022UL, 403147571UL, 2373806232UL, 4153354125UL, 509071385UL, 2056228251UL, 444685935UL, 1912268707UL, 169863045UL, 932848332UL, 2282651407UL, 2077207745UL, 3712980941UL, 2410099142UL, 3394315084UL, 3191572807UL, 640536184UL, 4262344652UL, 3712420663UL, 3000991259UL, 249137656UL, 368243227UL, 3374467273UL, 392730170UL, 4208559971UL, 24751401UL, 495648080UL, +1670592959UL, 2715927647UL, 985309803UL, 2570053358UL, 2181488546UL, 830547082UL, 1129119636UL, 3133886450UL, 328788870UL, 2497762979UL, 202644333UL, 2719792059UL, 691527418UL, 3487733607UL, 1976943620UL, 1400269159UL, 709089170UL, 1057897966UL, 1938975941UL, 2071351862UL, 3393893128UL, 3083496965UL, 1040123365UL, 295024253UL, 1440317859UL, 1219456UL, 3641758945UL, 2029993123UL, 3231254260UL, 952956380UL, 3713963210UL, 2032382533UL, +2088497043UL, 1392075576UL, 4180475645UL, 3733090890UL, 3224165725UL, 1571908345UL, 2558692460UL, 3482549931UL, 1678929187UL, 448105905UL, 699188129UL, 2017324335UL, 2431113987UL, 3368868963UL, 3976741021UL, 3526784185UL, 2882973520UL, 1900625235UL, 3233347584UL, 1425242390UL, 982315917UL, 2614735561UL, 1128074864UL, 4172908214UL, 3792239985UL, 3260669732UL, 2586472751UL, 4095880420UL, 1926157640UL, 3722487277UL, 3037304631UL, 433233786UL, +2927295412UL, 625648993UL, 1111327015UL, 3975736867UL, 2402230281UL, 259216032UL, 1349560774UL, 3521430425UL, 2827154828UL, 1067483357UL, 989690947UL, 2808148912UL, 2034644068UL, 725679489UL, 3705541400UL, 588787520UL, 212242504UL, 3001720496UL, 2982141597UL, 1090931027UL, 1235811382UL, 2510536004UL, 307638580UL, 452574019UL, 2384876926UL, 3536994565UL, 3227931749UL, 1701580099UL, 3034185952UL, 2765119653UL, 463890041UL, 1054678914UL, +2659043235UL, 4228353628UL, 701214306UL, 3085494195UL, 381309305UL, 2084857792UL, 2481277520UL, 859309333UL, 3760199179UL, 891630344UL, 4152646669UL, 3310629548UL, 2361261213UL, 2550680915UL, 1490030690UL, 481283060UL, 2952921690UL, 3295251862UL, 4195487760UL, 2025962691UL, 2915212660UL, 1343061717UL, 2355026672UL, 339445869UL, 2217081575UL, 3290479436UL, 1051433451UL, 51111285UL, 1113202216UL, 3455020635UL, 1430944862UL, 70037785UL, +2009147353UL, 3982848623UL, 1155691935UL, 2063919641UL, 2793993680UL, 2975111058UL, 1725337613UL, 403147571UL, 2373806232UL, 4153354125UL, 509071385UL, 1474832043UL, 444685935UL, 1912268707UL, 169863045UL, 932848332UL, 1500855137UL, 2077207745UL, 3712980941UL, 2410099142UL, 3394315084UL, 2800379966UL, 640536184UL, 4262344652UL, 3712420663UL, 3000991259UL, 1028021485UL, 368243227UL, 3374467273UL, 392730170UL, 4208559971UL, 108468246UL, +495648080UL, 1670592959UL, 2715927647UL, 985309803UL, 61959589UL, 2181488546UL, 830547082UL, 1129119636UL, 3133886450UL, 3912020361UL, 2497762979UL, 202644333UL, 2719792059UL, 691527418UL, 1984193076UL, 1976943620UL, 1400269159UL, 709089170UL, 1057897966UL, 2381612490UL, 2071351862UL, 3393893128UL, 3083496965UL, 1040123365UL, 391784014UL, 1440317859UL, 1219456UL, 3641758945UL, 2029993123UL, 2260373342UL, 952956380UL, 3713963210UL, +2032382533UL, 2088497043UL, 135943164UL, 4180475645UL, 3733090890UL, 3224165725UL, 1571908345UL, 2660287325UL, 3482549931UL, 1678929187UL, 448105905UL, 699188129UL, 4104693318UL, 2431113987UL, 3368868963UL, 3976741021UL, 3526784185UL, 113762138UL, 1900625235UL, 3233347584UL, 1425242390UL, 982315917UL, 599246177UL, 1128074864UL, 4172908214UL, 3792239985UL, 3260669732UL, 2309689974UL, 4095880420UL, 1926157640UL, 3722487277UL, 3037304631UL, +3765223460UL, 866296319UL, 1169380319UL, 2919436659UL, 3370646420UL, 1866719277UL, 3226685069UL, 4252262342UL, 1835269960UL, 1170376930UL, 1357078768UL, 269175192UL, 3826888026UL, 3430363541UL, 1920758494UL, 51532769UL, 2919489927UL, 1568325914UL, 3184357856UL, 43519013UL, 2108988015UL, 1398495041UL, 2844640139UL, 2317092036UL, 1774750014UL, 2690907136UL, 1834465421UL, 1106469655UL, 2149810726UL, 4265420439UL, 2048218411UL, 1399986034UL, +1361619115UL, 2504769226UL, 913700780UL, 2382994726UL, 4292849877UL, 1381838410UL, 250258264UL, 1828569640UL, 1732718872UL, 1869949326UL, 835188347UL, 4180489913UL, 3049522050UL, 535168392UL, 3972173823UL, 2763844722UL, 3401884753UL, 3750694101UL, 851518496UL, 1015521371UL, 1511969218UL, 1597622074UL, 3810841601UL, 3326003776UL, 3141062630UL, 552856274UL, 4059179808UL, 175647012UL, 3893497501UL, 1805118717UL, 1064213711UL, 2310866839UL, +1397146463UL, 1798096676UL, 279868399UL, 1926726615UL, 2773068510UL, 347721208UL, 4099183723UL, 509136218UL, 2833615756UL, 3960499694UL, 4236258712UL, 1765641675UL, 535748563UL, 354515646UL, 3307314159UL, 3160079941UL, 3252681800UL, 2568363625UL, 3818514182UL, 3738662353UL, 899056999UL, 2531772068UL, 647726503UL, 2895823632UL, 393777910UL, 1759531813UL, 2363148604UL, 2931477989UL, 3381169914UL, 3877595131UL, 2375539210UL, 557544627UL, +273611522UL, 2717517554UL, 1935966767UL, 1738732887UL, 29153600UL, 20993454UL, 3758163226UL, 1692844400UL, 2176938194UL, 378940221UL, 2888599759UL, 1173120554UL, 2732575460UL, 3912766812UL, 522606644UL, 1925230852UL, 3887440328UL, 2111843275UL, 3549473366UL, 922916775UL, 2889744544UL, 2970467682UL, 3039277863UL, 990580154UL, 55435595UL, 1665634070UL, 3043418336UL, 2792050230UL, 2762503138UL, 1402344059UL, 2099263558UL, 3945248675UL, +3925566467UL, 2413979948UL, 463637252UL, 3768636616UL, 3374572388UL, 2217956879UL, 791988933UL, 382210765UL, 1715859444UL, 3462446413UL, 971427992UL, 3255404695UL, 2001750035UL, 2214129237UL, 320812374UL, 3688098101UL, 920365480UL, 2819401059UL, 2932570681UL, 3749857130UL, 523943786UL, 1271514748UL, 4078439472UL, 3501181265UL, 2475869985UL, 1797996951UL, 2300820710UL, 3994893924UL, 1739992082UL, 2475950326UL, 3780826558UL, 1018851411UL, +}, + +}; +#endif +CURAND_XORWOW_PRECALCULATED_DEVICE_QUALIFIERS unsigned int precalc_xorwow_offset_matrix[32][800] = { +{ +0UL, 0UL, 0UL, 0UL, 3UL, 0UL, 0UL, 0UL, 0UL, 6UL, 0UL, 0UL, 0UL, 0UL, 15UL, 0UL, 0UL, 0UL, 0UL, 30UL, 0UL, 0UL, 0UL, 0UL, 60UL, 0UL, 0UL, 0UL, 0UL, 120UL, 0UL, 0UL, +0UL, 0UL, 240UL, 0UL, 0UL, 0UL, 0UL, 480UL, 0UL, 0UL, 0UL, 0UL, 960UL, 0UL, 0UL, 0UL, 0UL, 1920UL, 0UL, 0UL, 0UL, 0UL, 3840UL, 0UL, 0UL, 0UL, 0UL, 7680UL, 0UL, 0UL, 0UL, 0UL, +15360UL, 0UL, 0UL, 0UL, 0UL, 30720UL, 0UL, 0UL, 0UL, 0UL, 61440UL, 0UL, 0UL, 0UL, 0UL, 122880UL, 0UL, 0UL, 0UL, 0UL, 245760UL, 0UL, 0UL, 0UL, 0UL, 491520UL, 0UL, 0UL, 0UL, 0UL, 983040UL, 0UL, +0UL, 0UL, 0UL, 1966080UL, 0UL, 0UL, 0UL, 0UL, 3932160UL, 0UL, 0UL, 0UL, 0UL, 7864320UL, 0UL, 0UL, 0UL, 0UL, 15728640UL, 0UL, 0UL, 0UL, 0UL, 31457280UL, 0UL, 0UL, 0UL, 0UL, 62914560UL, 0UL, 0UL, 0UL, +0UL, 125829120UL, 0UL, 0UL, 0UL, 0UL, 251658240UL, 0UL, 0UL, 0UL, 0UL, 503316480UL, 0UL, 0UL, 0UL, 0UL, 1006632960UL, 0UL, 0UL, 0UL, 0UL, 2013265920UL, 0UL, 0UL, 0UL, 0UL, 4026531840UL, 0UL, 0UL, 0UL, 0UL, 3758096384UL, +1UL, 0UL, 0UL, 0UL, 0UL, 2UL, 0UL, 0UL, 0UL, 0UL, 4UL, 0UL, 0UL, 0UL, 0UL, 8UL, 0UL, 0UL, 0UL, 0UL, 16UL, 0UL, 0UL, 0UL, 0UL, 32UL, 0UL, 0UL, 0UL, 0UL, 64UL, 0UL, +0UL, 0UL, 0UL, 128UL, 0UL, 0UL, 0UL, 0UL, 256UL, 0UL, 0UL, 0UL, 0UL, 512UL, 0UL, 0UL, 0UL, 0UL, 1024UL, 0UL, 0UL, 0UL, 0UL, 2048UL, 0UL, 0UL, 0UL, 0UL, 4096UL, 0UL, 0UL, 0UL, +0UL, 8192UL, 0UL, 0UL, 0UL, 0UL, 16384UL, 0UL, 0UL, 0UL, 0UL, 32768UL, 0UL, 0UL, 0UL, 0UL, 65536UL, 0UL, 0UL, 0UL, 0UL, 131072UL, 0UL, 0UL, 0UL, 0UL, 262144UL, 0UL, 0UL, 0UL, 0UL, 524288UL, +0UL, 0UL, 0UL, 0UL, 1048576UL, 0UL, 0UL, 0UL, 0UL, 2097152UL, 0UL, 0UL, 0UL, 0UL, 4194304UL, 0UL, 0UL, 0UL, 0UL, 8388608UL, 0UL, 0UL, 0UL, 0UL, 16777216UL, 0UL, 0UL, 0UL, 0UL, 33554432UL, 0UL, 0UL, +0UL, 0UL, 67108864UL, 0UL, 0UL, 0UL, 0UL, 134217728UL, 0UL, 0UL, 0UL, 0UL, 268435456UL, 0UL, 0UL, 0UL, 0UL, 536870912UL, 0UL, 0UL, 0UL, 0UL, 1073741824UL, 0UL, 0UL, 0UL, 0UL, 2147483648UL, 0UL, 0UL, 0UL, 0UL, +0UL, 1UL, 0UL, 0UL, 0UL, 0UL, 2UL, 0UL, 0UL, 0UL, 0UL, 4UL, 0UL, 0UL, 0UL, 0UL, 8UL, 0UL, 0UL, 0UL, 0UL, 16UL, 0UL, 0UL, 0UL, 0UL, 32UL, 0UL, 0UL, 0UL, 0UL, 64UL, +0UL, 0UL, 0UL, 0UL, 128UL, 0UL, 0UL, 0UL, 0UL, 256UL, 0UL, 0UL, 0UL, 0UL, 512UL, 0UL, 0UL, 0UL, 0UL, 1024UL, 0UL, 0UL, 0UL, 0UL, 2048UL, 0UL, 0UL, 0UL, 0UL, 4096UL, 0UL, 0UL, +0UL, 0UL, 8192UL, 0UL, 0UL, 0UL, 0UL, 16384UL, 0UL, 0UL, 0UL, 0UL, 32768UL, 0UL, 0UL, 0UL, 0UL, 65536UL, 0UL, 0UL, 0UL, 0UL, 131072UL, 0UL, 0UL, 0UL, 0UL, 262144UL, 0UL, 0UL, 0UL, 0UL, +524288UL, 0UL, 0UL, 0UL, 0UL, 1048576UL, 0UL, 0UL, 0UL, 0UL, 2097152UL, 0UL, 0UL, 0UL, 0UL, 4194304UL, 0UL, 0UL, 0UL, 0UL, 8388608UL, 0UL, 0UL, 0UL, 0UL, 16777216UL, 0UL, 0UL, 0UL, 0UL, 33554432UL, 0UL, +0UL, 0UL, 0UL, 67108864UL, 0UL, 0UL, 0UL, 0UL, 134217728UL, 0UL, 0UL, 0UL, 0UL, 268435456UL, 0UL, 0UL, 0UL, 0UL, 536870912UL, 0UL, 0UL, 0UL, 0UL, 1073741824UL, 0UL, 0UL, 0UL, 0UL, 2147483648UL, 0UL, 0UL, 0UL, +0UL, 0UL, 1UL, 0UL, 0UL, 0UL, 0UL, 2UL, 0UL, 0UL, 0UL, 0UL, 4UL, 0UL, 0UL, 0UL, 0UL, 8UL, 0UL, 0UL, 0UL, 0UL, 16UL, 0UL, 0UL, 0UL, 0UL, 32UL, 0UL, 0UL, 0UL, 0UL, +64UL, 0UL, 0UL, 0UL, 0UL, 128UL, 0UL, 0UL, 0UL, 0UL, 256UL, 0UL, 0UL, 0UL, 0UL, 512UL, 0UL, 0UL, 0UL, 0UL, 1024UL, 0UL, 0UL, 0UL, 0UL, 2048UL, 0UL, 0UL, 0UL, 0UL, 4096UL, 0UL, +0UL, 0UL, 0UL, 8192UL, 0UL, 0UL, 0UL, 0UL, 16384UL, 0UL, 0UL, 0UL, 0UL, 32768UL, 0UL, 0UL, 0UL, 0UL, 65536UL, 0UL, 0UL, 0UL, 0UL, 131072UL, 0UL, 0UL, 0UL, 0UL, 262144UL, 0UL, 0UL, 0UL, +0UL, 524288UL, 0UL, 0UL, 0UL, 0UL, 1048576UL, 0UL, 0UL, 0UL, 0UL, 2097152UL, 0UL, 0UL, 0UL, 0UL, 4194304UL, 0UL, 0UL, 0UL, 0UL, 8388608UL, 0UL, 0UL, 0UL, 0UL, 16777216UL, 0UL, 0UL, 0UL, 0UL, 33554432UL, +0UL, 0UL, 0UL, 0UL, 67108864UL, 0UL, 0UL, 0UL, 0UL, 134217728UL, 0UL, 0UL, 0UL, 0UL, 268435456UL, 0UL, 0UL, 0UL, 0UL, 536870912UL, 0UL, 0UL, 0UL, 0UL, 1073741824UL, 0UL, 0UL, 0UL, 0UL, 2147483648UL, 0UL, 0UL, +0UL, 0UL, 0UL, 1UL, 17UL, 0UL, 0UL, 0UL, 2UL, 34UL, 0UL, 0UL, 0UL, 4UL, 68UL, 0UL, 0UL, 0UL, 8UL, 136UL, 0UL, 0UL, 0UL, 16UL, 272UL, 0UL, 0UL, 0UL, 32UL, 544UL, 0UL, 0UL, +0UL, 64UL, 1088UL, 0UL, 0UL, 0UL, 128UL, 2176UL, 0UL, 0UL, 0UL, 256UL, 4352UL, 0UL, 0UL, 0UL, 512UL, 8704UL, 0UL, 0UL, 0UL, 1024UL, 17408UL, 0UL, 0UL, 0UL, 2048UL, 34816UL, 0UL, 0UL, 0UL, 4096UL, +69632UL, 0UL, 0UL, 0UL, 8192UL, 139264UL, 0UL, 0UL, 0UL, 16384UL, 278528UL, 0UL, 0UL, 0UL, 32768UL, 557056UL, 0UL, 0UL, 0UL, 65536UL, 1114112UL, 0UL, 0UL, 0UL, 131072UL, 2228224UL, 0UL, 0UL, 0UL, 262144UL, 4456448UL, 0UL, +0UL, 0UL, 524288UL, 8912896UL, 0UL, 0UL, 0UL, 1048576UL, 17825792UL, 0UL, 0UL, 0UL, 2097152UL, 35651584UL, 0UL, 0UL, 0UL, 4194304UL, 71303168UL, 0UL, 0UL, 0UL, 8388608UL, 142606336UL, 0UL, 0UL, 0UL, 16777216UL, 285212672UL, 0UL, 0UL, 0UL, +33554432UL, 570425344UL, 0UL, 0UL, 0UL, 67108864UL, 1140850688UL, 0UL, 0UL, 0UL, 134217728UL, 2281701376UL, 0UL, 0UL, 0UL, 268435456UL, 268435456UL, 0UL, 0UL, 0UL, 536870912UL, 536870912UL, 0UL, 0UL, 0UL, 1073741824UL, 1073741824UL, 0UL, 0UL, 0UL, 2147483648UL, 2147483648UL, +}, +{ +0UL, 3UL, 51UL, 771UL, 13107UL, 0UL, 6UL, 102UL, 1542UL, 26214UL, 0UL, 15UL, 255UL, 3855UL, 65535UL, 0UL, 30UL, 510UL, 7710UL, 131070UL, 0UL, 60UL, 1020UL, 15420UL, 262140UL, 0UL, 120UL, 2040UL, 30840UL, 524280UL, 0UL, 240UL, +4080UL, 61680UL, 1048560UL, 0UL, 480UL, 8160UL, 123360UL, 2097120UL, 0UL, 960UL, 16320UL, 246720UL, 4194240UL, 0UL, 1920UL, 32640UL, 493440UL, 8388480UL, 0UL, 3840UL, 65280UL, 986880UL, 16776960UL, 0UL, 7680UL, 130560UL, 1973760UL, 33553920UL, 0UL, 15360UL, 261120UL, 3947520UL, +67107840UL, 0UL, 30720UL, 522240UL, 7895040UL, 134215680UL, 0UL, 61440UL, 1044480UL, 15790080UL, 268431360UL, 0UL, 122880UL, 2088960UL, 31580160UL, 536862720UL, 0UL, 245760UL, 4177920UL, 63160320UL, 1073725440UL, 0UL, 491520UL, 8355840UL, 126320640UL, 2147450880UL, 0UL, 983040UL, 16711680UL, 252641280UL, 4294901760UL, 0UL, +1966080UL, 33423360UL, 505282560UL, 4294836224UL, 0UL, 3932160UL, 66846720UL, 1010565120UL, 4294705152UL, 0UL, 7864320UL, 133693440UL, 2021130240UL, 4294443008UL, 0UL, 15728640UL, 267386880UL, 4042260480UL, 4293918720UL, 0UL, 31457280UL, 534773760UL, 3789553664UL, 4292870144UL, 0UL, 62914560UL, 1069547520UL, 3284140032UL, 4290772992UL, 0UL, 125829120UL, 2139095040UL, +2273312768UL, 4286578688UL, 0UL, 251658240UL, 4278190080UL, 251658240UL, 4278190080UL, 0UL, 503316480UL, 4261412864UL, 503316480UL, 4261412864UL, 0UL, 1006632960UL, 4227858432UL, 1006632960UL, 4227858432UL, 0UL, 2013265920UL, 4160749568UL, 2013265920UL, 4160749568UL, 0UL, 4026531840UL, 4026531840UL, 4026531840UL, 4026531840UL, 0UL, 3758096384UL, 3758096384UL, 3758096384UL, 3758096384UL, +0UL, 0UL, 3UL, 51UL, 771UL, 0UL, 0UL, 6UL, 102UL, 1542UL, 0UL, 0UL, 15UL, 255UL, 3855UL, 0UL, 0UL, 30UL, 510UL, 7710UL, 0UL, 0UL, 60UL, 1020UL, 15420UL, 0UL, 0UL, 120UL, 2040UL, 30840UL, 0UL, 0UL, +240UL, 4080UL, 61680UL, 0UL, 0UL, 480UL, 8160UL, 123360UL, 0UL, 0UL, 960UL, 16320UL, 246720UL, 0UL, 0UL, 1920UL, 32640UL, 493440UL, 0UL, 0UL, 3840UL, 65280UL, 986880UL, 0UL, 0UL, 7680UL, 130560UL, 1973760UL, 0UL, 0UL, 15360UL, 261120UL, +3947520UL, 0UL, 0UL, 30720UL, 522240UL, 7895040UL, 0UL, 0UL, 61440UL, 1044480UL, 15790080UL, 0UL, 0UL, 122880UL, 2088960UL, 31580160UL, 0UL, 0UL, 245760UL, 4177920UL, 63160320UL, 0UL, 0UL, 491520UL, 8355840UL, 126320640UL, 0UL, 0UL, 983040UL, 16711680UL, 252641280UL, 0UL, +0UL, 1966080UL, 33423360UL, 505282560UL, 0UL, 0UL, 3932160UL, 66846720UL, 1010565120UL, 0UL, 0UL, 7864320UL, 133693440UL, 2021130240UL, 0UL, 0UL, 15728640UL, 267386880UL, 4042260480UL, 0UL, 0UL, 31457280UL, 534773760UL, 3789553664UL, 0UL, 0UL, 62914560UL, 1069547520UL, 3284140032UL, 0UL, 0UL, 125829120UL, +2139095040UL, 2273312768UL, 0UL, 0UL, 251658240UL, 4278190080UL, 251658240UL, 0UL, 0UL, 503316480UL, 4261412864UL, 503316480UL, 0UL, 0UL, 1006632960UL, 4227858432UL, 1006632960UL, 0UL, 0UL, 2013265920UL, 4160749568UL, 2013265920UL, 0UL, 0UL, 4026531840UL, 4026531840UL, 4026531840UL, 0UL, 0UL, 3758096384UL, 3758096384UL, 3758096384UL, +0UL, 0UL, 0UL, 3UL, 51UL, 0UL, 0UL, 0UL, 6UL, 102UL, 0UL, 0UL, 0UL, 15UL, 255UL, 0UL, 0UL, 0UL, 30UL, 510UL, 0UL, 0UL, 0UL, 60UL, 1020UL, 0UL, 0UL, 0UL, 120UL, 2040UL, 0UL, 0UL, +0UL, 240UL, 4080UL, 0UL, 0UL, 0UL, 480UL, 8160UL, 0UL, 0UL, 0UL, 960UL, 16320UL, 0UL, 0UL, 0UL, 1920UL, 32640UL, 0UL, 0UL, 0UL, 3840UL, 65280UL, 0UL, 0UL, 0UL, 7680UL, 130560UL, 0UL, 0UL, 0UL, 15360UL, +261120UL, 0UL, 0UL, 0UL, 30720UL, 522240UL, 0UL, 0UL, 0UL, 61440UL, 1044480UL, 0UL, 0UL, 0UL, 122880UL, 2088960UL, 0UL, 0UL, 0UL, 245760UL, 4177920UL, 0UL, 0UL, 0UL, 491520UL, 8355840UL, 0UL, 0UL, 0UL, 983040UL, 16711680UL, 0UL, +0UL, 0UL, 1966080UL, 33423360UL, 0UL, 0UL, 0UL, 3932160UL, 66846720UL, 0UL, 0UL, 0UL, 7864320UL, 133693440UL, 0UL, 0UL, 0UL, 15728640UL, 267386880UL, 0UL, 0UL, 0UL, 31457280UL, 534773760UL, 0UL, 0UL, 0UL, 62914560UL, 1069547520UL, 0UL, 0UL, 0UL, +125829120UL, 2139095040UL, 0UL, 0UL, 0UL, 251658240UL, 4278190080UL, 0UL, 0UL, 0UL, 503316480UL, 4261412864UL, 0UL, 0UL, 0UL, 1006632960UL, 4227858432UL, 0UL, 0UL, 0UL, 2013265920UL, 4160749568UL, 0UL, 0UL, 0UL, 4026531840UL, 4026531840UL, 0UL, 0UL, 0UL, 3758096384UL, 3758096384UL, +0UL, 0UL, 0UL, 0UL, 3UL, 0UL, 0UL, 0UL, 0UL, 6UL, 0UL, 0UL, 0UL, 0UL, 15UL, 0UL, 0UL, 0UL, 0UL, 30UL, 0UL, 0UL, 0UL, 0UL, 60UL, 0UL, 0UL, 0UL, 0UL, 120UL, 0UL, 0UL, +0UL, 0UL, 240UL, 0UL, 0UL, 0UL, 0UL, 480UL, 0UL, 0UL, 0UL, 0UL, 960UL, 0UL, 0UL, 0UL, 0UL, 1920UL, 0UL, 0UL, 0UL, 0UL, 3840UL, 0UL, 0UL, 0UL, 0UL, 7680UL, 0UL, 0UL, 0UL, 0UL, +15360UL, 0UL, 0UL, 0UL, 0UL, 30720UL, 0UL, 0UL, 0UL, 0UL, 61440UL, 0UL, 0UL, 0UL, 0UL, 122880UL, 0UL, 0UL, 0UL, 0UL, 245760UL, 0UL, 0UL, 0UL, 0UL, 491520UL, 0UL, 0UL, 0UL, 0UL, 983040UL, 0UL, +0UL, 0UL, 0UL, 1966080UL, 0UL, 0UL, 0UL, 0UL, 3932160UL, 0UL, 0UL, 0UL, 0UL, 7864320UL, 0UL, 0UL, 0UL, 0UL, 15728640UL, 0UL, 0UL, 0UL, 0UL, 31457280UL, 0UL, 0UL, 0UL, 0UL, 62914560UL, 0UL, 0UL, 0UL, +0UL, 125829120UL, 0UL, 0UL, 0UL, 0UL, 251658240UL, 0UL, 0UL, 0UL, 0UL, 503316480UL, 0UL, 0UL, 0UL, 0UL, 1006632960UL, 0UL, 0UL, 0UL, 0UL, 2013265920UL, 0UL, 0UL, 0UL, 0UL, 4026531840UL, 0UL, 0UL, 0UL, 0UL, 3758096384UL, +1UL, 17UL, 257UL, 4369UL, 65537UL, 2UL, 34UL, 514UL, 8738UL, 131074UL, 4UL, 68UL, 1028UL, 17476UL, 262148UL, 8UL, 136UL, 2056UL, 34952UL, 524296UL, 16UL, 272UL, 4112UL, 69904UL, 1048592UL, 32UL, 544UL, 8224UL, 139808UL, 2097184UL, 64UL, 1088UL, +16448UL, 279616UL, 4194368UL, 128UL, 2176UL, 32896UL, 559232UL, 8388736UL, 256UL, 4352UL, 65792UL, 1118464UL, 16777472UL, 512UL, 8704UL, 131584UL, 2236928UL, 33554944UL, 1024UL, 17408UL, 263168UL, 4473856UL, 67109888UL, 2048UL, 34816UL, 526336UL, 8947712UL, 134219776UL, 4096UL, 69632UL, 1052672UL, 17895424UL, +268439552UL, 8192UL, 139264UL, 2105344UL, 35790848UL, 536879104UL, 16384UL, 278528UL, 4210688UL, 71581696UL, 1073758208UL, 32768UL, 557056UL, 8421376UL, 143163392UL, 2147516416UL, 65536UL, 1114112UL, 16842752UL, 286326784UL, 65536UL, 131072UL, 2228224UL, 33685504UL, 572653568UL, 131072UL, 262144UL, 4456448UL, 67371008UL, 1145307136UL, 262144UL, 524288UL, +8912896UL, 134742016UL, 2290614272UL, 524288UL, 1048576UL, 17825792UL, 269484032UL, 286261248UL, 1048576UL, 2097152UL, 35651584UL, 538968064UL, 572522496UL, 2097152UL, 4194304UL, 71303168UL, 1077936128UL, 1145044992UL, 4194304UL, 8388608UL, 142606336UL, 2155872256UL, 2290089984UL, 8388608UL, 16777216UL, 285212672UL, 16777216UL, 285212672UL, 16777216UL, 33554432UL, 570425344UL, 33554432UL, +570425344UL, 33554432UL, 67108864UL, 1140850688UL, 67108864UL, 1140850688UL, 67108864UL, 134217728UL, 2281701376UL, 134217728UL, 2281701376UL, 134217728UL, 268435456UL, 268435456UL, 268435456UL, 268435456UL, 268435456UL, 536870912UL, 536870912UL, 536870912UL, 536870912UL, 536870912UL, 1073741824UL, 1073741824UL, 1073741824UL, 1073741824UL, 1073741824UL, 2147483648UL, 2147483648UL, 2147483648UL, 2147483648UL, 2147483648UL, +}, +{ +85009117UL, 335741939UL, 1412632518UL, 386859243UL, 1741437244UL, 152139416UL, 403047142UL, 2556825231UL, 505087203UL, 4287193174UL, 335609039UL, 336528191UL, 1425998811UL, 456920088UL, 2832198590UL, 724748988UL, 3625845630UL, 1509824181UL, 3330088197UL, 2710488401UL, 1431742057UL, 1077674236UL, 1140592489UL, 2096905276UL, 3007294393UL, 2863484114UL, 1081606648UL, 1207443154UL, 972585080UL, 2793363314UL, 1432000919UL, 1089470704UL, +1341132452UL, 3019109363UL, 2362285522UL, 1790260014UL, 2178941408UL, 2682264904UL, 1743251430UL, 429603751UL, 359294556UL, 62915520UL, 1069562512UL, 3486502860UL, 859207501UL, 3939814584UL, 125831040UL, 2139125024UL, 2678038424UL, 1718415002UL, 363436400UL, 251662080UL, 4278250048UL, 1061109552UL, 3436830004UL, 3948098272UL, 503324160UL, 4261532800UL, 2122219104UL, 2310257256UL, 380003776UL, 1006648320UL, 4228098304UL, 4244438208UL, +3278337232UL, 3981233024UL, 2013296640UL, 4161229312UL, 4193909120UL, 2530142624UL, 446273280UL, 4026593280UL, 4027491328UL, 871625472UL, 4254978880UL, 4113772032UL, 3758219264UL, 3760015360UL, 2011686400UL, 3946555008UL, 711351296UL, 3221471232UL, 3225063424UL, 4291808256UL, 108481792UL, 2496444416UL, 2147975168UL, 2155159552UL, 4020213760UL, 485399040UL, 3919147008UL, 983040UL, 15351808UL, 255799296UL, 3923588096UL, 322101248UL, +1966080UL, 299139072UL, 511598592UL, 3283773440UL, 3865427968UL, 3932160UL, 4087939072UL, 1023197184UL, 1467273216UL, 214663168UL, 7864320UL, 4149346304UL, 2046394368UL, 3202981888UL, 3650551808UL, 3236954112UL, 1050935296UL, 871563264UL, 2916302848UL, 1932394496UL, 2447376384UL, 1833435136UL, 2011561984UL, 2342944768UL, 643563520UL, 868220928UL, 177209344UL, 4291559424UL, 122486784UL, 2360868864UL, 2004877312UL, 85983232UL, +4019716096UL, 3734634496UL, 3647995904UL, 1056964608UL, 3661627392UL, 254803968UL, 2905866240UL, 1658847232UL, 2113929216UL, 3028287488UL, 3730833408UL, 2322071552UL, 3586129920UL, 4227858432UL, 1761607680UL, 2092957696UL, 80740352UL, 2071986176UL, 4160749568UL, 3523215360UL, 964689920UL, 429916160UL, 3875536896UL, 4026531840UL, 2751463424UL, 1929379840UL, 4081057792UL, 503316480UL, 3758096384UL, 2281701376UL, 4127195136UL, 3397386240UL, +1316635UL, 85009117UL, 335741939UL, 1412632518UL, 386859243UL, 1580547UL, 152139416UL, 403047142UL, 2556825231UL, 505087203UL, 1317672UL, 335609039UL, 336528191UL, 1425998811UL, 456920088UL, 1574501UL, 724748988UL, 3625845630UL, 1509824181UL, 3330088197UL, 15612UL, 1431742057UL, 1077674236UL, 1140592489UL, 2096905276UL, 31224UL, 2863484114UL, 1081606648UL, 1207443154UL, 972585080UL, 62451UL, 1432000919UL, +1089470704UL, 1341132452UL, 3019109363UL, 124902UL, 1790260014UL, 2178941408UL, 2682264904UL, 1743251430UL, 249804UL, 359294556UL, 62915520UL, 1069562512UL, 3486502860UL, 499608UL, 3939814584UL, 125831040UL, 2139125024UL, 2678038424UL, 999216UL, 363436400UL, 251662080UL, 4278250048UL, 1061109552UL, 3223223904UL, 3948098272UL, 503324160UL, 4261532800UL, 2122219104UL, 1077738688UL, 380003776UL, 1006648320UL, 4228098304UL, +4244438208UL, 1081735552UL, 3981233024UL, 2013296640UL, 4161229312UL, 4193909120UL, 1089729280UL, 446273280UL, 4026593280UL, 4027491328UL, 871625472UL, 2179458560UL, 4113772032UL, 3758219264UL, 3760015360UL, 2011686400UL, 63949824UL, 711351296UL, 3221471232UL, 3225063424UL, 4291808256UL, 127899648UL, 2496444416UL, 2147975168UL, 2155159552UL, 4020213760UL, 255799296UL, 3919147008UL, 983040UL, 15351808UL, 255799296UL, 3732824064UL, +322101248UL, 1966080UL, 299139072UL, 511598592UL, 2096939008UL, 3865427968UL, 3932160UL, 4087939072UL, 1023197184UL, 972652544UL, 214663168UL, 7864320UL, 4149346304UL, 2046394368UL, 3019046912UL, 3650551808UL, 3236954112UL, 1050935296UL, 871563264UL, 1743126528UL, 1932394496UL, 2447376384UL, 1833435136UL, 2011561984UL, 3486253056UL, 643563520UL, 868220928UL, 177209344UL, 4291559424UL, 2677538816UL, 2360868864UL, 2004877312UL, +85983232UL, 4019716096UL, 1060110336UL, 3647995904UL, 1056964608UL, 3661627392UL, 254803968UL, 3193962496UL, 1658847232UL, 2113929216UL, 3028287488UL, 3730833408UL, 3166699520UL, 3586129920UL, 4227858432UL, 1761607680UL, 2092957696UL, 3112173568UL, 2071986176UL, 4160749568UL, 3523215360UL, 964689920UL, 1929379840UL, 3875536896UL, 4026531840UL, 2751463424UL, 1929379840UL, 4127195136UL, 503316480UL, 3758096384UL, 2281701376UL, 4127195136UL, +332854UL, 1316635UL, 85009117UL, 335741939UL, 1412632518UL, 596079UL, 1580547UL, 152139416UL, 403047142UL, 2556825231UL, 1316075UL, 1317672UL, 335609039UL, 336528191UL, 1425998811UL, 2824661UL, 1574501UL, 724748988UL, 3625845630UL, 1509824181UL, 5571497UL, 15612UL, 1431742057UL, 1077674236UL, 1140592489UL, 11142994UL, 31224UL, 2863484114UL, 1081606648UL, 1207443154UL, 22285988UL, 62451UL, +1432000919UL, 1089470704UL, 1341132452UL, 44571976UL, 124902UL, 1790260014UL, 2178941408UL, 2682264904UL, 89143952UL, 249804UL, 359294556UL, 62915520UL, 1069562512UL, 178287904UL, 499608UL, 3939814584UL, 125831040UL, 2139125024UL, 356575808UL, 999216UL, 363436400UL, 251662080UL, 4278250048UL, 713151616UL, 3223223904UL, 3948098272UL, 503324160UL, 4261532800UL, 1426303232UL, 1077738688UL, 380003776UL, 1006648320UL, +4228098304UL, 2852606464UL, 1081735552UL, 3981233024UL, 2013296640UL, 4161229312UL, 1410245632UL, 1089729280UL, 446273280UL, 4026593280UL, 4027491328UL, 1746749440UL, 2179458560UL, 4113772032UL, 3758219264UL, 3760015360UL, 272273408UL, 63949824UL, 711351296UL, 3221471232UL, 3225063424UL, 3765772288UL, 127899648UL, 2496444416UL, 2147975168UL, 2155159552UL, 15351808UL, 255799296UL, 3919147008UL, 983040UL, 15351808UL, 3251929088UL, +3732824064UL, 322101248UL, 1966080UL, 299139072UL, 1135149056UL, 2096939008UL, 3865427968UL, 3932160UL, 4087939072UL, 1196556288UL, 972652544UL, 214663168UL, 7864320UL, 4149346304UL, 1319370752UL, 3019046912UL, 3650551808UL, 3236954112UL, 1050935296UL, 2638741504UL, 1743126528UL, 1932394496UL, 2447376384UL, 1833435136UL, 982515712UL, 3486253056UL, 643563520UL, 868220928UL, 177209344UL, 1965031424UL, 2677538816UL, 2360868864UL, +2004877312UL, 85983232UL, 3930062848UL, 1060110336UL, 3647995904UL, 1056964608UL, 3661627392UL, 3565158400UL, 3193962496UL, 1658847232UL, 2113929216UL, 3028287488UL, 2835349504UL, 3166699520UL, 3586129920UL, 4227858432UL, 1761607680UL, 1375731712UL, 3112173568UL, 2071986176UL, 4160749568UL, 3523215360UL, 2751463424UL, 1929379840UL, 3875536896UL, 4026531840UL, 2751463424UL, 2281701376UL, 4127195136UL, 503316480UL, 3758096384UL, 2281701376UL, +5123UL, 332854UL, 1316635UL, 85009117UL, 335741939UL, 6150UL, 596079UL, 1580547UL, 152139416UL, 403047142UL, 5135UL, 1316075UL, 1317672UL, 335609039UL, 336528191UL, 6174UL, 2824661UL, 1574501UL, 724748988UL, 3625845630UL, 60UL, 5571497UL, 15612UL, 1431742057UL, 1077674236UL, 120UL, 11142994UL, 31224UL, 2863484114UL, 1081606648UL, 240UL, 22285988UL, +62451UL, 1432000919UL, 1089470704UL, 480UL, 44571976UL, 124902UL, 1790260014UL, 2178941408UL, 960UL, 89143952UL, 249804UL, 359294556UL, 62915520UL, 1920UL, 178287904UL, 499608UL, 3939814584UL, 125831040UL, 3840UL, 356575808UL, 999216UL, 363436400UL, 251662080UL, 7680UL, 713151616UL, 3223223904UL, 3948098272UL, 503324160UL, 15360UL, 1426303232UL, 1077738688UL, 380003776UL, +1006648320UL, 30720UL, 2852606464UL, 1081735552UL, 3981233024UL, 2013296640UL, 61440UL, 1410245632UL, 1089729280UL, 446273280UL, 4026593280UL, 122880UL, 1746749440UL, 2179458560UL, 4113772032UL, 3758219264UL, 245760UL, 272273408UL, 63949824UL, 711351296UL, 3221471232UL, 491520UL, 3765772288UL, 127899648UL, 2496444416UL, 2147975168UL, 983040UL, 15351808UL, 255799296UL, 3919147008UL, 983040UL, 3223191552UL, +3251929088UL, 3732824064UL, 322101248UL, 1966080UL, 1077673984UL, 1135149056UL, 2096939008UL, 3865427968UL, 3932160UL, 1081606144UL, 1196556288UL, 972652544UL, 214663168UL, 7864320UL, 1089470464UL, 1319370752UL, 3019046912UL, 3650551808UL, 3236954112UL, 2178940928UL, 2638741504UL, 1743126528UL, 1932394496UL, 2447376384UL, 62914560UL, 982515712UL, 3486253056UL, 643563520UL, 868220928UL, 125829120UL, 1965031424UL, 2677538816UL, +2360868864UL, 2004877312UL, 251658240UL, 3930062848UL, 1060110336UL, 3647995904UL, 1056964608UL, 503316480UL, 3565158400UL, 3193962496UL, 1658847232UL, 2113929216UL, 1006632960UL, 2835349504UL, 3166699520UL, 3586129920UL, 4227858432UL, 2013265920UL, 1375731712UL, 3112173568UL, 2071986176UL, 4160749568UL, 4026531840UL, 2751463424UL, 1929379840UL, 3875536896UL, 4026531840UL, 3758096384UL, 2281701376UL, 4127195136UL, 503316480UL, 3758096384UL, +201392209UL, 3423671362UL, 218366296UL, 3713336838UL, 206572594UL, 402785186UL, 2552372100UL, 436928947UL, 3130605370UL, 463476848UL, 262468UL, 4461835UL, 68158800UL, 1158700908UL, 20971524UL, 524680UL, 8919318UL, 136513955UL, 2316537326UL, 25165852UL, 3222274064UL, 3239051564UL, 3494187077UL, 3558090985UL, 3221225500UL, 2149580832UL, 2183135832UL, 2693406858UL, 2821214674UL, 2147483704UL, 4194368UL, 71304368UL, +1091846420UL, 1347462055UL, 64UL, 8388736UL, 142608736UL, 2183692840UL, 2694924110UL, 3221225600UL, 16777472UL, 285217472UL, 72418384UL, 1094880924UL, 1342177536UL, 33554944UL, 570434944UL, 144836768UL, 2189761848UL, 2684355072UL, 67109888UL, 1140869888UL, 289673536UL, 84556400UL, 1073742848UL, 134219776UL, 2281739776UL, 579347072UL, 169112800UL, 2147485696UL, 268439552UL, 268512256UL, 1158694144UL, 69790144UL, +4096UL, 536879104UL, 537024512UL, 2317388288UL, 3360805760UL, 8192UL, 1073758208UL, 1074049024UL, 339809280UL, 1352902400UL, 16384UL, 2147516416UL, 2148098048UL, 3900844032UL, 1632062976UL, 32768UL, 65536UL, 1228800UL, 17059840UL, 311335936UL, 65536UL, 131072UL, 2457600UL, 34119680UL, 622671872UL, 131072UL, 262144UL, 4915200UL, 68239360UL, 1245343744UL, 262144UL, 524288UL, +9830400UL, 136478720UL, 2490687488UL, 524288UL, 1048576UL, 288096256UL, 272957440UL, 954843136UL, 3222274048UL, 2097152UL, 3797417984UL, 545914880UL, 2983428096UL, 2149580800UL, 4194304UL, 78643200UL, 1091829760UL, 2745630720UL, 4194304UL, 3229614080UL, 3378511872UL, 1109917696UL, 2270035968UL, 8388608UL, 1358954496UL, 1119879168UL, 1414529024UL, 513540096UL, 16777216UL, 2717908992UL, 2239758336UL, 2829058048UL, +1027080192UL, 33554432UL, 1140850688UL, 184549376UL, 1363148800UL, 2054160384UL, 3288334336UL, 2281701376UL, 369098752UL, 2726297600UL, 4108320768UL, 2281701376UL, 268435456UL, 738197504UL, 2231369728UL, 968884224UL, 3959422976UL, 536870912UL, 1476395008UL, 167772160UL, 3011510272UL, 3355443200UL, 1073741824UL, 2952790016UL, 335544320UL, 1728053248UL, 2147483648UL, 2147483648UL, 1610612736UL, 3892314112UL, 503316480UL, 0UL, +}, +{ +1939838472UL, 1412147404UL, 166205219UL, 1757484276UL, 2905930693UL, 2345662040UL, 2845657161UL, 253454719UL, 2661974169UL, 303781080UL, 4075331504UL, 31014156UL, 244538930UL, 3752264221UL, 992575155UL, 219309525UL, 246620060UL, 215640989UL, 4125020723UL, 2016731730UL, 3236558869UL, 297169276UL, 3293566751UL, 1867504216UL, 210423272UL, 2531663658UL, 499723753UL, 1730625896UL, 189236880UL, 3388575408UL, 2433358422UL, 1368961148UL, +3134096848UL, 2827836415UL, 3888822753UL, 4172043647UL, 3379360748UL, 2651760955UL, 1345081091UL, 627692776UL, 189423917UL, 1927379456UL, 4004336944UL, 2995932065UL, 1882016234UL, 2551113616UL, 1576396048UL, 1299792730UL, 2151240795UL, 2154814108UL, 4292139924UL, 3555849728UL, 943986992UL, 3169912733UL, 2631635779UL, 3478094562UL, 1285558544UL, 3716074330UL, 2780749859UL, 3911106510UL, 4175656994UL, 1731832828UL, 1275401375UL, 937322456UL, +3802094750UL, 1145506936UL, 1008905193UL, 1718801768UL, 645739137UL, 1356219146UL, 827886816UL, 1722154800UL, 2242776733UL, 754630810UL, 772070504UL, 249481170UL, 2608123425UL, 2087201889UL, 3200968096UL, 3292110026UL, 841433255UL, 477543427UL, 1878882709UL, 705347364UL, 4003860146UL, 3194913138UL, 2616490007UL, 357561212UL, 2446098297UL, 2955680594UL, 2512991743UL, 637464579UL, 1209132455UL, 1341312804UL, 612108672UL, 2455017713UL, +1749147666UL, 4020226825UL, 2873924220UL, 499405095UL, 1837614076UL, 1227604028UL, 714577577UL, 165950208UL, 442290261UL, 489077752UL, 216760440UL, 42151250UL, 426862080UL, 2810242474UL, 4112075489UL, 3514761468UL, 4101921371UL, 982512636UL, 500792667UL, 4286077681UL, 198050301UL, 1858712743UL, 2913642493UL, 3547545255UL, 3981929169UL, 2944140287UL, 2286578015UL, 3422343167UL, 1239123295UL, 2026367394UL, 3269986302UL, 3028402878UL, +2709637886UL, 1096011710UL, 294584132UL, 3086749695UL, 3324400975UL, 1164394495UL, 4290155855UL, 543687304UL, 4008517630UL, 836370334UL, 1876426750UL, 2362048414UL, 3578325264UL, 3221487612UL, 2671154748UL, 3395518460UL, 2018383420UL, 2131029536UL, 2165829624UL, 697661816UL, 1336049656UL, 3309365624UL, 4259639360UL, 3423548400UL, 2416417776UL, 1633698800UL, 1630071792UL, 41950336UL, 3423478496UL, 2885608160UL, 3943744224UL, 677380832UL, +4179285363UL, 1939838472UL, 1412147404UL, 166205219UL, 1757484276UL, 3838244595UL, 2345662040UL, 2845657161UL, 253454719UL, 2661974169UL, 138737288UL, 4075331504UL, 31014156UL, 244538930UL, 3752264221UL, 1503392345UL, 219309525UL, 246620060UL, 215640989UL, 4125020723UL, 1759481152UL, 3236558869UL, 297169276UL, 3293566751UL, 1867504216UL, 3898070400UL, 2531663658UL, 499723753UL, 1730625896UL, 189236880UL, 2610231010UL, 2433358422UL, +1368961148UL, 3134096848UL, 2827836415UL, 3903474593UL, 4172043647UL, 3379360748UL, 2651760955UL, 1345081091UL, 1267864331UL, 189423917UL, 1927379456UL, 4004336944UL, 2995932065UL, 3452816347UL, 2551113616UL, 1576396048UL, 1299792730UL, 2151240795UL, 1222520631UL, 4292139924UL, 3555849728UL, 943986992UL, 3169912733UL, 3260130211UL, 3478094562UL, 1285558544UL, 3716074330UL, 2780749859UL, 3039362306UL, 4175656994UL, 1731832828UL, 1275401375UL, +937322456UL, 3236754932UL, 1145506936UL, 1008905193UL, 1718801768UL, 645739137UL, 1358079399UL, 827886816UL, 1722154800UL, 2242776733UL, 754630810UL, 1748663943UL, 249481170UL, 2608123425UL, 2087201889UL, 3200968096UL, 698076610UL, 841433255UL, 477543427UL, 1878882709UL, 705347364UL, 3692794996UL, 3194913138UL, 2616490007UL, 357561212UL, 2446098297UL, 2771068186UL, 2512991743UL, 637464579UL, 1209132455UL, 1341312804UL, 27937268UL, +2455017713UL, 1749147666UL, 4020226825UL, 2873924220UL, 1673040956UL, 1837614076UL, 1227604028UL, 714577577UL, 165950208UL, 528340088UL, 489077752UL, 216760440UL, 42151250UL, 426862080UL, 1646215396UL, 4112075489UL, 3514761468UL, 4101921371UL, 982512636UL, 2095821304UL, 4286077681UL, 198050301UL, 1858712743UL, 2913642493UL, 277300160UL, 3981929169UL, 2944140287UL, 2286578015UL, 3422343167UL, 1178044288UL, 2026367394UL, 3269986302UL, +3028402878UL, 2709637886UL, 2234191616UL, 294584132UL, 3086749695UL, 3324400975UL, 1164394495UL, 136978944UL, 543687304UL, 4008517630UL, 836370334UL, 1876426750UL, 3275253760UL, 3578325264UL, 3221487612UL, 2671154748UL, 3395518460UL, 3942394880UL, 2131029536UL, 2165829624UL, 697661816UL, 1336049656UL, 3265045504UL, 4259639360UL, 3423548400UL, 2416417776UL, 1633698800UL, 3943712768UL, 41950336UL, 3423478496UL, 2885608160UL, 3943744224UL, +2293593009UL, 4179285363UL, 1939838472UL, 1412147404UL, 166205219UL, 715714152UL, 3838244595UL, 2345662040UL, 2845657161UL, 253454719UL, 3758048260UL, 138737288UL, 4075331504UL, 31014156UL, 244538930UL, 370671650UL, 1503392345UL, 219309525UL, 246620060UL, 215640989UL, 2219162331UL, 1759481152UL, 3236558869UL, 297169276UL, 3293566751UL, 135243402UL, 3898070400UL, 2531663658UL, 499723753UL, 1730625896UL, 3142293713UL, 2610231010UL, +2433358422UL, 1368961148UL, 3134096848UL, 486949791UL, 3903474593UL, 4172043647UL, 3379360748UL, 2651760955UL, 3172880550UL, 1267864331UL, 189423917UL, 1927379456UL, 4004336944UL, 191463910UL, 3452816347UL, 2551113616UL, 1576396048UL, 1299792730UL, 4411574UL, 1222520631UL, 4292139924UL, 3555849728UL, 943986992UL, 3073348038UL, 3260130211UL, 3478094562UL, 1285558544UL, 3716074330UL, 3098363790UL, 3039362306UL, 4175656994UL, 1731832828UL, +1275401375UL, 468159532UL, 3236754932UL, 1145506936UL, 1008905193UL, 1718801768UL, 1092964081UL, 1358079399UL, 827886816UL, 1722154800UL, 2242776733UL, 53128947UL, 1748663943UL, 249481170UL, 2608123425UL, 2087201889UL, 1960144614UL, 698076610UL, 841433255UL, 477543427UL, 1878882709UL, 1505419004UL, 3692794996UL, 3194913138UL, 2616490007UL, 357561212UL, 2823143358UL, 2771068186UL, 2512991743UL, 637464579UL, 1209132455UL, 1991737212UL, +27937268UL, 2455017713UL, 1749147666UL, 4020226825UL, 2907896812UL, 1673040956UL, 1837614076UL, 1227604028UL, 714577577UL, 3633969112UL, 528340088UL, 489077752UL, 216760440UL, 42151250UL, 2886728356UL, 1646215396UL, 4112075489UL, 3514761468UL, 4101921371UL, 3507686008UL, 2095821304UL, 4286077681UL, 198050301UL, 1858712743UL, 1463806912UL, 277300160UL, 3981929169UL, 2944140287UL, 2286578015UL, 4137888640UL, 1178044288UL, 2026367394UL, +3269986302UL, 3028402878UL, 1276820224UL, 2234191616UL, 294584132UL, 3086749695UL, 3324400975UL, 4274031104UL, 136978944UL, 543687304UL, 4008517630UL, 836370334UL, 2978609152UL, 3275253760UL, 3578325264UL, 3221487612UL, 2671154748UL, 2296777728UL, 3942394880UL, 2131029536UL, 2165829624UL, 697661816UL, 1086645248UL, 3265045504UL, 4259639360UL, 3423548400UL, 2416417776UL, 2295121920UL, 3943712768UL, 41950336UL, 3423478496UL, 2885608160UL, +3290486993UL, 2293593009UL, 4179285363UL, 1939838472UL, 1412147404UL, 3718742914UL, 715714152UL, 3838244595UL, 2345662040UL, 2845657161UL, 3251034248UL, 3758048260UL, 138737288UL, 4075331504UL, 31014156UL, 2257801369UL, 370671650UL, 1503392345UL, 219309525UL, 246620060UL, 1375177854UL, 2219162331UL, 1759481152UL, 3236558869UL, 297169276UL, 2981812236UL, 135243402UL, 3898070400UL, 2531663658UL, 499723753UL, 1103465850UL, 3142293713UL, +2610231010UL, 2433358422UL, 1368961148UL, 2570001060UL, 486949791UL, 3903474593UL, 4172043647UL, 3379360748UL, 1922171925UL, 3172880550UL, 1267864331UL, 189423917UL, 1927379456UL, 1359812359UL, 191463910UL, 3452816347UL, 2551113616UL, 1576396048UL, 2518549525UL, 4411574UL, 1222520631UL, 4292139924UL, 3555849728UL, 949028615UL, 3073348038UL, 3260130211UL, 3478094562UL, 1285558544UL, 4113039486UL, 3098363790UL, 3039362306UL, 4175656994UL, +1731832828UL, 1827471372UL, 468159532UL, 3236754932UL, 1145506936UL, 1008905193UL, 1626341859UL, 1092964081UL, 1358079399UL, 827886816UL, 1722154800UL, 1069547583UL, 53128947UL, 1748663943UL, 249481170UL, 2608123425UL, 3162506114UL, 1960144614UL, 698076610UL, 841433255UL, 477543427UL, 3641706484UL, 1505419004UL, 3692794996UL, 3194913138UL, 2616490007UL, 3623882586UL, 2823143358UL, 2771068186UL, 2512991743UL, 637464579UL, 16785012UL, +1991737212UL, 27937268UL, 2455017713UL, 1749147666UL, 2348825660UL, 2907896812UL, 1673040956UL, 1837614076UL, 1227604028UL, 2579527800UL, 3633969112UL, 528340088UL, 489077752UL, 216760440UL, 3628134628UL, 2886728356UL, 1646215396UL, 4112075489UL, 3514761468UL, 1602085368UL, 3507686008UL, 2095821304UL, 4286077681UL, 198050301UL, 2501362624UL, 1463806912UL, 277300160UL, 3981929169UL, 2944140287UL, 4112467840UL, 4137888640UL, 1178044288UL, +2026367394UL, 3269986302UL, 3356184320UL, 1276820224UL, 2234191616UL, 294584132UL, 3086749695UL, 366387712UL, 4274031104UL, 136978944UL, 543687304UL, 4008517630UL, 1006135296UL, 2978609152UL, 3275253760UL, 3578325264UL, 3221487612UL, 3104844800UL, 2296777728UL, 3942394880UL, 2131029536UL, 2165829624UL, 1874371584UL, 1086645248UL, 3265045504UL, 4259639360UL, 3423548400UL, 2975352832UL, 2295121920UL, 3943712768UL, 41950336UL, 3423478496UL, +989898496UL, 3410688577UL, 2331788830UL, 3546482013UL, 813828841UL, 1865093068UL, 3265457506UL, 3795669738UL, 2119696024UL, 4285651426UL, 3333834629UL, 3451487261UL, 2090324595UL, 1816963648UL, 932961512UL, 2470761029UL, 3401764108UL, 3421619354UL, 4199624502UL, 589386372UL, 879396240UL, 3372470254UL, 2693109296UL, 2424215996UL, 38442268UL, 1882087724UL, 171397600UL, 2024561281UL, 183095586UL, 3282207272UL, 3402177296UL, 1859195498UL, +413109947UL, 2839537944UL, 1632143648UL, 3742715856UL, 388696500UL, 1748703733UL, 3563198567UL, 3826785440UL, 2896086528UL, 3989037829UL, 1478787788UL, 1390277813UL, 2123320736UL, 3416516800UL, 2056564203UL, 2584895011UL, 1605192736UL, 2475623616UL, 3856499712UL, 3439657984UL, 708088129UL, 1501395566UL, 1302184960UL, 1360092352UL, 1645630430UL, 1425230387UL, 3369488824UL, 2979863936UL, 869212432UL, 150548847UL, 1097557362UL, 655939640UL, +316553344UL, 3761918508UL, 3958338094UL, 141744600UL, 1412214640UL, 1859689984UL, 3200680981UL, 3883058679UL, 999801880UL, 3946079738UL, 1876072704UL, 194381849UL, 2177533995UL, 1584707624UL, 3053768410UL, 2593051904UL, 3458076673UL, 4047442835UL, 3545972808UL, 3441793178UL, 194975744UL, 1731731470UL, 4168755162UL, 2628944732UL, 2125675784UL, 3119906816UL, 960774145UL, 2646626078UL, 2152793157UL, 3049156634UL, 672464896UL, 3046932493UL, +3700727536UL, 2152335477UL, 575986696UL, 671940608UL, 2208366608UL, 1454456125UL, 937760016UL, 4103979069UL, 2737668096UL, 1179779104UL, 1030912634UL, 1041902112UL, 2032909434UL, 2274230272UL, 2089025605UL, 3050632421UL, 2428784965UL, 140658149UL, 4254138368UL, 1745354889UL, 711584249UL, 2746523017UL, 2551006457UL, 1100808192UL, 1494221073UL, 3422999489UL, 2696954129UL, 976716737UL, 2653421568UL, 3806331426UL, 3690047362UL, 1481392674UL, +3817015170UL, 2353004544UL, 286262340UL, 2300534532UL, 4206449732UL, 15339268UL, 2894069760UL, 488376456UL, 1489927688UL, 1196583048UL, 652746248UL, 2214592512UL, 69904UL, 1006205200UL, 2322628880UL, 1229515024UL, 2617245696UL, 3423527456UL, 1964953120UL, 4260938272UL, 386199072UL, 1744830464UL, 1342444608UL, 1069330496UL, 2138592320UL, 3185897536UL, 1073741824UL, 1342493824UL, 3780942976UL, 1771066496UL, 2189433984UL, 2147483648UL, +}, +{ +1804684571UL, 2106089606UL, 1533056158UL, 2870216110UL, 3618155659UL, 3789871366UL, 4246691682UL, 3667072763UL, 1212241769UL, 3152390668UL, 2973497449UL, 2958641966UL, 2088805328UL, 717518631UL, 2401090860UL, 3606967204UL, 952637656UL, 59827581UL, 1291486682UL, 1499453515UL, 2053994857UL, 563998083UL, 4094000396UL, 1163546899UL, 1003843565UL, 654565639UL, 1070907026UL, 4217851863UL, 426034251UL, 1721352737UL, 278404469UL, 3899800390UL, +1063362170UL, 1162348262UL, 3153545093UL, 3249996223UL, 186674553UL, 2616406148UL, 3137968354UL, 1282784965UL, 1495068058UL, 3033760361UL, 2278144523UL, 3192245769UL, 719586342UL, 2602548287UL, 3386583150UL, 355354345UL, 3252815848UL, 2178056037UL, 2283016801UL, 3005955037UL, 3340254490UL, 802791670UL, 251122316UL, 3705188626UL, 1252262272UL, 3989036796UL, 3527490452UL, 2047131255UL, 1447170583UL, 3373930285UL, 2895037457UL, 209341805UL, +1820357643UL, 3712392731UL, 685796521UL, 1322920440UL, 814388470UL, 1357857147UL, 434430265UL, 2650681935UL, 1371566728UL, 58783716UL, 2273435933UL, 3498513198UL, 792571900UL, 1447808772UL, 3513385860UL, 99175889UL, 1105434360UL, 1484146625UL, 3327194068UL, 242672513UL, 3552105593UL, 1425844616UL, 2871928454UL, 1124633561UL, 607610433UL, 2130018608UL, 1610235673UL, 2844230432UL, 2748082340UL, 994392866UL, 450823250UL, 2912535126UL, +2574390988UL, 3974009252UL, 78696582UL, 649682891UL, 3980917176UL, 3221419689UL, 960695436UL, 729221508UL, 358358845UL, 3392407691UL, 472711005UL, 295914899UL, 3005191796UL, 3078521977UL, 3370011868UL, 509135340UL, 1965939519UL, 2086465877UL, 2457949822UL, 1324152522UL, 762289386UL, 3618693997UL, 233730715UL, 2873984650UL, 31168606UL, 3367142977UL, 2851851305UL, 3251660053UL, 4209768406UL, 3298190175UL, 901235185UL, 1564391510UL, +2352686527UL, 1008150482UL, 578573310UL, 3462447127UL, 2482873876UL, 1790221257UL, 2255375608UL, 2335345651UL, 1381450613UL, 2866805101UL, 1495073163UL, 519905259UL, 3184556473UL, 1076378339UL, 2692926127UL, 970097715UL, 4013407916UL, 4014350363UL, 2476927059UL, 1989070516UL, 2640060069UL, 1987784589UL, 1880989003UL, 3861138803UL, 451743296UL, 1987067871UL, 1975657871UL, 3397816882UL, 2309900530UL, 4108425851UL, 4063867233UL, 3319482186UL, +2621772886UL, 1804684571UL, 2106089606UL, 1533056158UL, 2870216110UL, 611557097UL, 3789871366UL, 4246691682UL, 3667072763UL, 1212241769UL, 3389551988UL, 2973497449UL, 2958641966UL, 2088805328UL, 717518631UL, 2460955430UL, 3606967204UL, 952637656UL, 59827581UL, 1291486682UL, 3531087304UL, 2053994857UL, 563998083UL, 4094000396UL, 1163546899UL, 1242934125UL, 654565639UL, 1070907026UL, 4217851863UL, 426034251UL, 3034416129UL, 278404469UL, +3899800390UL, 1063362170UL, 1162348262UL, 4258714417UL, 3249996223UL, 186674553UL, 2616406148UL, 3137968354UL, 639885806UL, 1495068058UL, 3033760361UL, 2278144523UL, 3192245769UL, 4159910300UL, 2602548287UL, 3386583150UL, 355354345UL, 3252815848UL, 1555885880UL, 2283016801UL, 3005955037UL, 3340254490UL, 802791670UL, 2948774612UL, 3705188626UL, 1252262272UL, 3989036796UL, 3527490452UL, 2107826711UL, 1447170583UL, 3373930285UL, 2895037457UL, +209341805UL, 3763367196UL, 3712392731UL, 685796521UL, 1322920440UL, 814388470UL, 1986168339UL, 434430265UL, 2650681935UL, 1371566728UL, 58783716UL, 1423189187UL, 3498513198UL, 792571900UL, 1447808772UL, 3513385860UL, 315969823UL, 1105434360UL, 1484146625UL, 3327194068UL, 242672513UL, 3336228275UL, 1425844616UL, 2871928454UL, 1124633561UL, 607610433UL, 1762052458UL, 1610235673UL, 2844230432UL, 2748082340UL, 994392866UL, 3771702243UL, +2912535126UL, 2574390988UL, 3974009252UL, 78696582UL, 1626628844UL, 3980917176UL, 3221419689UL, 960695436UL, 729221508UL, 382092233UL, 3392407691UL, 472711005UL, 295914899UL, 3005191796UL, 514297204UL, 3370011868UL, 509135340UL, 1965939519UL, 2086465877UL, 3975975091UL, 1324152522UL, 762289386UL, 3618693997UL, 233730715UL, 455322516UL, 31168606UL, 3367142977UL, 2851851305UL, 3251660053UL, 3952189603UL, 3298190175UL, 901235185UL, +1564391510UL, 2352686527UL, 826181452UL, 578573310UL, 3462447127UL, 2482873876UL, 1790221257UL, 1529242773UL, 2335345651UL, 1381450613UL, 2866805101UL, 1495073163UL, 877718651UL, 3184556473UL, 1076378339UL, 2692926127UL, 970097715UL, 299344245UL, 4014350363UL, 2476927059UL, 1989070516UL, 2640060069UL, 3844531327UL, 1880989003UL, 3861138803UL, 451743296UL, 1987067871UL, 3272848161UL, 3397816882UL, 2309900530UL, 4108425851UL, 4063867233UL, +834288064UL, 2621772886UL, 1804684571UL, 2106089606UL, 1533056158UL, 304865970UL, 611557097UL, 3789871366UL, 4246691682UL, 3667072763UL, 2728206193UL, 3389551988UL, 2973497449UL, 2958641966UL, 2088805328UL, 3895037582UL, 2460955430UL, 3606967204UL, 952637656UL, 59827581UL, 2349212526UL, 3531087304UL, 2053994857UL, 563998083UL, 4094000396UL, 4028900485UL, 1242934125UL, 654565639UL, 1070907026UL, 4217851863UL, 1663452176UL, 3034416129UL, +278404469UL, 3899800390UL, 1063362170UL, 2721441405UL, 4258714417UL, 3249996223UL, 186674553UL, 2616406148UL, 4228837490UL, 639885806UL, 1495068058UL, 3033760361UL, 2278144523UL, 2820661772UL, 4159910300UL, 2602548287UL, 3386583150UL, 355354345UL, 1815256314UL, 1555885880UL, 2283016801UL, 3005955037UL, 3340254490UL, 2166514144UL, 2948774612UL, 3705188626UL, 1252262272UL, 3989036796UL, 751187322UL, 2107826711UL, 1447170583UL, 3373930285UL, +2895037457UL, 2809311944UL, 3763367196UL, 3712392731UL, 685796521UL, 1322920440UL, 936300677UL, 1986168339UL, 434430265UL, 2650681935UL, 1371566728UL, 1308015359UL, 1423189187UL, 3498513198UL, 792571900UL, 1447808772UL, 3065349526UL, 315969823UL, 1105434360UL, 1484146625UL, 3327194068UL, 1038676789UL, 3336228275UL, 1425844616UL, 2871928454UL, 1124633561UL, 2956422231UL, 1762052458UL, 1610235673UL, 2844230432UL, 2748082340UL, 3603862093UL, +3771702243UL, 2912535126UL, 2574390988UL, 3974009252UL, 1691332448UL, 1626628844UL, 3980917176UL, 3221419689UL, 960695436UL, 3120142427UL, 382092233UL, 3392407691UL, 472711005UL, 295914899UL, 4101686983UL, 514297204UL, 3370011868UL, 509135340UL, 1965939519UL, 3015736706UL, 3975975091UL, 1324152522UL, 762289386UL, 3618693997UL, 2395097989UL, 455322516UL, 31168606UL, 3367142977UL, 2851851305UL, 30511955UL, 3952189603UL, 3298190175UL, +901235185UL, 1564391510UL, 2606298633UL, 826181452UL, 578573310UL, 3462447127UL, 2482873876UL, 4159642946UL, 1529242773UL, 2335345651UL, 1381450613UL, 2866805101UL, 1782913669UL, 877718651UL, 3184556473UL, 1076378339UL, 2692926127UL, 1730328819UL, 299344245UL, 4014350363UL, 2476927059UL, 1989070516UL, 1425685614UL, 3844531327UL, 1880989003UL, 3861138803UL, 451743296UL, 889237383UL, 3272848161UL, 3397816882UL, 2309900530UL, 4108425851UL, +1155723231UL, 834288064UL, 2621772886UL, 1804684571UL, 2106089606UL, 2387009004UL, 304865970UL, 611557097UL, 3789871366UL, 4246691682UL, 1405709661UL, 2728206193UL, 3389551988UL, 2973497449UL, 2958641966UL, 3183906006UL, 3895037582UL, 2460955430UL, 3606967204UL, 952637656UL, 1345432763UL, 2349212526UL, 3531087304UL, 2053994857UL, 563998083UL, 3749011414UL, 4028900485UL, 1242934125UL, 654565639UL, 1070907026UL, 1072342672UL, 1663452176UL, +3034416129UL, 278404469UL, 3899800390UL, 3566652188UL, 2721441405UL, 4258714417UL, 3249996223UL, 186674553UL, 4001263143UL, 4228837490UL, 639885806UL, 1495068058UL, 3033760361UL, 4278332644UL, 2820661772UL, 4159910300UL, 2602548287UL, 3386583150UL, 838831089UL, 1815256314UL, 1555885880UL, 2283016801UL, 3005955037UL, 3377397178UL, 2166514144UL, 2948774612UL, 3705188626UL, 1252262272UL, 2414422575UL, 751187322UL, 2107826711UL, 1447170583UL, +3373930285UL, 1253755033UL, 2809311944UL, 3763367196UL, 3712392731UL, 685796521UL, 3238624475UL, 936300677UL, 1986168339UL, 434430265UL, 2650681935UL, 1642290570UL, 1308015359UL, 1423189187UL, 3498513198UL, 792571900UL, 173318140UL, 3065349526UL, 315969823UL, 1105434360UL, 1484146625UL, 4103797777UL, 1038676789UL, 3336228275UL, 1425844616UL, 2871928454UL, 1797745765UL, 2956422231UL, 1762052458UL, 1610235673UL, 2844230432UL, 2180656608UL, +3603862093UL, 3771702243UL, 2912535126UL, 2574390988UL, 1183098390UL, 1691332448UL, 1626628844UL, 3980917176UL, 3221419689UL, 2645203959UL, 3120142427UL, 382092233UL, 3392407691UL, 472711005UL, 1659659070UL, 4101686983UL, 514297204UL, 3370011868UL, 509135340UL, 483888155UL, 3015736706UL, 3975975091UL, 1324152522UL, 762289386UL, 1259948064UL, 2395097989UL, 455322516UL, 31168606UL, 3367142977UL, 339990414UL, 30511955UL, 3952189603UL, +3298190175UL, 901235185UL, 3097920065UL, 2606298633UL, 826181452UL, 578573310UL, 3462447127UL, 1548039839UL, 4159642946UL, 1529242773UL, 2335345651UL, 1381450613UL, 2173079994UL, 1782913669UL, 877718651UL, 3184556473UL, 1076378339UL, 1570275057UL, 1730328819UL, 299344245UL, 4014350363UL, 2476927059UL, 1845882881UL, 1425685614UL, 3844531327UL, 1880989003UL, 3861138803UL, 1322409081UL, 889237383UL, 3272848161UL, 3397816882UL, 2309900530UL, +3505447982UL, 3430136873UL, 1319796589UL, 4202423979UL, 3184732284UL, 2910356648UL, 2534615223UL, 3854465731UL, 768821792UL, 2205052576UL, 1348983754UL, 1300250188UL, 2919181738UL, 2520178732UL, 3967243685UL, 2646012002UL, 1784678658UL, 741302051UL, 3464753547UL, 194213376UL, 1482799064UL, 3009673860UL, 680824208UL, 741966796UL, 2381283369UL, 3022877171UL, 1619439814UL, 3961433610UL, 1331297670UL, 1100110820UL, 1311672539UL, 1122110615UL, +4056004850UL, 3413790176UL, 3148768822UL, 1242592694UL, 2925975727UL, 1879285134UL, 334328879UL, 1318235222UL, 3140739559UL, 401691770UL, 3604288404UL, 3686496908UL, 770670945UL, 199139043UL, 2092710473UL, 3914528993UL, 700991333UL, 2375775811UL, 858137308UL, 3490050165UL, 2389078291UL, 1615607459UL, 3027969809UL, 820012549UL, 2085659484UL, 2654485136UL, 2630408646UL, 196481396UL, 1119673274UL, 1026209692UL, 726501622UL, 2940737143UL, +3559571163UL, 2288027726UL, 1039212708UL, 929664536UL, 1061981465UL, 186058675UL, 3537656152UL, 844176796UL, 2996217992UL, 1545798611UL, 3031020656UL, 2248030435UL, 1665857580UL, 2905758082UL, 1269201312UL, 3031275084UL, 4034872841UL, 983632400UL, 4188503190UL, 757119675UL, 2105920865UL, 4281032819UL, 2917801076UL, 3900010013UL, 3910997169UL, 1729751422UL, 562313247UL, 3070846353UL, 2564238664UL, 4050540186UL, 4258833501UL, 2270666053UL, +2207128401UL, 2990540001UL, 797768898UL, 2288390225UL, 3230323685UL, 1974727440UL, 3327301426UL, 289857826UL, 3565889868UL, 2791014422UL, 2021097820UL, 3350378271UL, 3673707591UL, 2610067927UL, 4255789547UL, 2682856590UL, 12563128UL, 1397542366UL, 237149400UL, 2233707508UL, 3875573245UL, 2097374144UL, 175320773UL, 4103445984UL, 4089284323UL, 3610168130UL, 3084915964UL, 680145366UL, 2571684685UL, 1132894909UL, 104640024UL, 193765521UL, +2338202907UL, 895271448UL, 11499099UL, 1798066417UL, 1297412626UL, 2511347162UL, 3140535007UL, 2129963538UL, 700683199UL, 2609700278UL, 2953463279UL, 2290844145UL, 1871316353UL, 3993801787UL, 2219413182UL, 2954453701UL, 231283580UL, 1375331115UL, 207723994UL, 1799562537UL, 2056553564UL, 2513609799UL, 3542459627UL, 3173012714UL, 3923404932UL, 217877755UL, 2095124912UL, 192024370UL, 1168134987UL, 1889598668UL, 3014873069UL, 2033573343UL, +}, +{ +3465348660UL, 3623545008UL, 3505902593UL, 838034830UL, 1338018789UL, 2595329276UL, 3367746385UL, 3197935201UL, 1439351946UL, 3585085571UL, 4165798087UL, 3634792639UL, 2359485974UL, 2772582925UL, 1110186203UL, 3771562484UL, 1508694157UL, 1564641206UL, 2801985736UL, 2446107936UL, 3849126897UL, 1842973671UL, 944408104UL, 2624631280UL, 2729080685UL, 3737368614UL, 858809173UL, 2289802345UL, 2428186575UL, 3114742765UL, 716011303UL, 3443810690UL, +814132610UL, 517432787UL, 614445393UL, 2930433345UL, 291178098UL, 2117644502UL, 2749446703UL, 311745701UL, 365684723UL, 1705418876UL, 2213749318UL, 4011417220UL, 1842575651UL, 988348831UL, 94258998UL, 2771150272UL, 498058526UL, 1344827813UL, 2961955291UL, 262703473UL, 1404034822UL, 1566595865UL, 2522381203UL, 1706522206UL, 1203054806UL, 1273801539UL, 2070583465UL, 3913449936UL, 3231505231UL, 619636751UL, 3746997351UL, 4103027837UL, +1205468203UL, 3355878253UL, 3433356888UL, 107785753UL, 2779092609UL, 1869691566UL, 2555219983UL, 903319808UL, 3273374169UL, 2538926990UL, 979533870UL, 1356500860UL, 1661983738UL, 1380761625UL, 2919458459UL, 1041142798UL, 1430817627UL, 517007606UL, 1421570516UL, 2371447300UL, 2985632691UL, 3684889351UL, 3873926653UL, 788770697UL, 1854750277UL, 209332297UL, 1137299679UL, 848527832UL, 3850486924UL, 4179307312UL, 2764470693UL, 1353191605UL, +4166891919UL, 2074703841UL, 3373997532UL, 2013528640UL, 701389744UL, 841917592UL, 2065742268UL, 2721848192UL, 2566956680UL, 3122896007UL, 1090761479UL, 921859028UL, 4086736376UL, 1837462309UL, 2579826431UL, 2436217134UL, 839037727UL, 1072086642UL, 614518622UL, 3764758228UL, 1501128342UL, 3669108708UL, 1601407381UL, 2899014005UL, 3268308948UL, 3337564231UL, 1986911578UL, 3379194930UL, 1950365753UL, 2098537451UL, 51515980UL, 1176526086UL, +3213391582UL, 1059745735UL, 2273586703UL, 376085505UL, 1493749800UL, 3970342143UL, 1620925244UL, 2165301314UL, 2332030190UL, 1864098798UL, 276747442UL, 2776569227UL, 2992780663UL, 3027279789UL, 1074555384UL, 3481518659UL, 2499703783UL, 661805703UL, 3782305562UL, 9186074UL, 2357407210UL, 2355922343UL, 2024733363UL, 485434612UL, 862379913UL, 1029706268UL, 1512726310UL, 3834948354UL, 1435892840UL, 3297980694UL, 2831553800UL, 2111416471UL, +711321697UL, 3465348660UL, 3623545008UL, 3505902593UL, 838034830UL, 1553436793UL, 2595329276UL, 3367746385UL, 3197935201UL, 1439351946UL, 3198044157UL, 4165798087UL, 3634792639UL, 2359485974UL, 2772582925UL, 836042976UL, 3771562484UL, 1508694157UL, 1564641206UL, 2801985736UL, 1190371491UL, 3849126897UL, 1842973671UL, 944408104UL, 2624631280UL, 410746791UL, 3737368614UL, 858809173UL, 2289802345UL, 2428186575UL, 1542325976UL, 716011303UL, +3443810690UL, 814132610UL, 517432787UL, 1649301063UL, 2930433345UL, 291178098UL, 2117644502UL, 2749446703UL, 3955511579UL, 365684723UL, 1705418876UL, 2213749318UL, 4011417220UL, 2753632862UL, 988348831UL, 94258998UL, 2771150272UL, 498058526UL, 3314106168UL, 2961955291UL, 262703473UL, 1404034822UL, 1566595865UL, 3590367097UL, 1706522206UL, 1203054806UL, 1273801539UL, 2070583465UL, 2340683261UL, 3231505231UL, 619636751UL, 3746997351UL, +4103027837UL, 2785398766UL, 3355878253UL, 3433356888UL, 107785753UL, 2779092609UL, 1608451840UL, 2555219983UL, 903319808UL, 3273374169UL, 2538926990UL, 645164419UL, 1356500860UL, 1661983738UL, 1380761625UL, 2919458459UL, 2260224548UL, 1430817627UL, 517007606UL, 1421570516UL, 2371447300UL, 1636004496UL, 3684889351UL, 3873926653UL, 788770697UL, 1854750277UL, 1345251011UL, 1137299679UL, 848527832UL, 3850486924UL, 4179307312UL, 3576574608UL, +1353191605UL, 4166891919UL, 2074703841UL, 3373997532UL, 183447754UL, 701389744UL, 841917592UL, 2065742268UL, 2721848192UL, 2109289891UL, 3122896007UL, 1090761479UL, 921859028UL, 4086736376UL, 2212730874UL, 2579826431UL, 2436217134UL, 839037727UL, 1072086642UL, 55934784UL, 3764758228UL, 1501128342UL, 3669108708UL, 1601407381UL, 516550987UL, 3268308948UL, 3337564231UL, 1986911578UL, 3379194930UL, 3973484473UL, 2098537451UL, 51515980UL, +1176526086UL, 3213391582UL, 4251661633UL, 2273586703UL, 376085505UL, 1493749800UL, 3970342143UL, 3190791788UL, 2165301314UL, 2332030190UL, 1864098798UL, 276747442UL, 2991976613UL, 2992780663UL, 3027279789UL, 1074555384UL, 3481518659UL, 1399789494UL, 661805703UL, 3782305562UL, 9186074UL, 2357407210UL, 1942736967UL, 2024733363UL, 485434612UL, 862379913UL, 1029706268UL, 4122704494UL, 3834948354UL, 1435892840UL, 3297980694UL, 2831553800UL, +1210092654UL, 711321697UL, 3465348660UL, 3623545008UL, 3505902593UL, 3443231198UL, 1553436793UL, 2595329276UL, 3367746385UL, 3197935201UL, 1304974987UL, 3198044157UL, 4165798087UL, 3634792639UL, 2359485974UL, 3518323362UL, 836042976UL, 3771562484UL, 1508694157UL, 1564641206UL, 3577633375UL, 1190371491UL, 3849126897UL, 1842973671UL, 944408104UL, 1854555112UL, 410746791UL, 3737368614UL, 858809173UL, 2289802345UL, 3622671731UL, 1542325976UL, +716011303UL, 3443810690UL, 814132610UL, 296197011UL, 1649301063UL, 2930433345UL, 291178098UL, 2117644502UL, 1056271538UL, 3955511579UL, 365684723UL, 1705418876UL, 2213749318UL, 1258535671UL, 2753632862UL, 988348831UL, 94258998UL, 2771150272UL, 3669902097UL, 3314106168UL, 2961955291UL, 262703473UL, 1404034822UL, 1654433938UL, 3590367097UL, 1706522206UL, 1203054806UL, 1273801539UL, 2448138887UL, 2340683261UL, 3231505231UL, 619636751UL, +3746997351UL, 1454088394UL, 2785398766UL, 3355878253UL, 3433356888UL, 107785753UL, 689323470UL, 1608451840UL, 2555219983UL, 903319808UL, 3273374169UL, 1603842392UL, 645164419UL, 1356500860UL, 1661983738UL, 1380761625UL, 2814639423UL, 2260224548UL, 1430817627UL, 517007606UL, 1421570516UL, 1938805701UL, 1636004496UL, 3684889351UL, 3873926653UL, 788770697UL, 4238900666UL, 1345251011UL, 1137299679UL, 848527832UL, 3850486924UL, 108793827UL, +3576574608UL, 1353191605UL, 4166891919UL, 2074703841UL, 3780897861UL, 183447754UL, 701389744UL, 841917592UL, 2065742268UL, 3036602746UL, 2109289891UL, 3122896007UL, 1090761479UL, 921859028UL, 3499985398UL, 2212730874UL, 2579826431UL, 2436217134UL, 839037727UL, 3520354700UL, 55934784UL, 3764758228UL, 1501128342UL, 3669108708UL, 1601010847UL, 516550987UL, 3268308948UL, 3337564231UL, 1986911578UL, 2704241781UL, 3973484473UL, 2098537451UL, +51515980UL, 1176526086UL, 3602010532UL, 4251661633UL, 2273586703UL, 376085505UL, 1493749800UL, 2922957328UL, 3190791788UL, 2165301314UL, 2332030190UL, 1864098798UL, 1649666443UL, 2991976613UL, 2992780663UL, 3027279789UL, 1074555384UL, 2848531519UL, 1399789494UL, 661805703UL, 3782305562UL, 9186074UL, 320781315UL, 1942736967UL, 2024733363UL, 485434612UL, 862379913UL, 3598892066UL, 4122704494UL, 3834948354UL, 1435892840UL, 3297980694UL, +545184652UL, 1210092654UL, 711321697UL, 3465348660UL, 3623545008UL, 1173753045UL, 3443231198UL, 1553436793UL, 2595329276UL, 3367746385UL, 2444634476UL, 1304974987UL, 3198044157UL, 4165798087UL, 3634792639UL, 1837035806UL, 3518323362UL, 836042976UL, 3771562484UL, 1508694157UL, 2899021294UL, 3577633375UL, 1190371491UL, 3849126897UL, 1842973671UL, 1614215215UL, 1854555112UL, 410746791UL, 3737368614UL, 858809173UL, 525745365UL, 3622671731UL, +1542325976UL, 716011303UL, 3443810690UL, 566299749UL, 296197011UL, 1649301063UL, 2930433345UL, 291178098UL, 1987532525UL, 1056271538UL, 3955511579UL, 365684723UL, 1705418876UL, 2321222760UL, 1258535671UL, 2753632862UL, 988348831UL, 94258998UL, 2986060366UL, 3669902097UL, 3314106168UL, 2961955291UL, 262703473UL, 604452796UL, 1654433938UL, 3590367097UL, 1706522206UL, 1203054806UL, 1894894069UL, 2448138887UL, 2340683261UL, 3231505231UL, +619636751UL, 6680729UL, 1454088394UL, 2785398766UL, 3355878253UL, 3433356888UL, 2025591660UL, 689323470UL, 1608451840UL, 2555219983UL, 903319808UL, 3430384385UL, 1603842392UL, 645164419UL, 1356500860UL, 1661983738UL, 2108736152UL, 2814639423UL, 2260224548UL, 1430817627UL, 517007606UL, 2973658959UL, 1938805701UL, 1636004496UL, 3684889351UL, 3873926653UL, 2283691941UL, 4238900666UL, 1345251011UL, 1137299679UL, 848527832UL, 45551112UL, +108793827UL, 3576574608UL, 1353191605UL, 4166891919UL, 3776615962UL, 3780897861UL, 183447754UL, 701389744UL, 841917592UL, 3830639316UL, 3036602746UL, 2109289891UL, 3122896007UL, 1090761479UL, 1931255897UL, 3499985398UL, 2212730874UL, 2579826431UL, 2436217134UL, 3272166055UL, 3520354700UL, 55934784UL, 3764758228UL, 1501128342UL, 1567864246UL, 1601010847UL, 516550987UL, 3268308948UL, 3337564231UL, 3918802424UL, 2704241781UL, 3973484473UL, +2098537451UL, 51515980UL, 3551394489UL, 3602010532UL, 4251661633UL, 2273586703UL, 376085505UL, 885459498UL, 2922957328UL, 3190791788UL, 2165301314UL, 2332030190UL, 3197056515UL, 1649666443UL, 2991976613UL, 2992780663UL, 3027279789UL, 2385348906UL, 2848531519UL, 1399789494UL, 661805703UL, 3782305562UL, 2163075465UL, 320781315UL, 1942736967UL, 2024733363UL, 485434612UL, 2680597981UL, 3598892066UL, 4122704494UL, 3834948354UL, 1435892840UL, +2499644163UL, 2704575422UL, 2579557838UL, 673530532UL, 493730767UL, 1124557747UL, 1908629439UL, 2821949504UL, 1743112513UL, 2849457841UL, 2344409314UL, 3479159262UL, 4260973770UL, 2991970754UL, 3812641863UL, 2229319917UL, 2466968521UL, 1766353737UL, 3216591612UL, 2113272648UL, 364370737UL, 1893001758UL, 2608875275UL, 4224057183UL, 3546705413UL, 1999778009UL, 348872225UL, 2470564216UL, 1417878284UL, 2709790112UL, 3579129936UL, 2137971615UL, +4046639861UL, 2841156930UL, 391544737UL, 2056567354UL, 737657378UL, 3877904725UL, 578930752UL, 1759172471UL, 3383278785UL, 1047197514UL, 649468151UL, 3452867243UL, 1792089520UL, 63936215UL, 3909143729UL, 3753489875UL, 734314122UL, 2490530916UL, 3043874586UL, 1504812057UL, 59001199UL, 2493748676UL, 2552438622UL, 1889694845UL, 3715397860UL, 2817245010UL, 3841049206UL, 816106718UL, 2176130406UL, 640254735UL, 12376903UL, 3000264936UL, +3304116079UL, 1620334094UL, 2109391765UL, 1348210951UL, 2237645681UL, 1207768272UL, 1562894669UL, 2156631655UL, 1387193235UL, 3154858817UL, 633510901UL, 2312190757UL, 402878244UL, 2501565021UL, 2984409334UL, 4167491216UL, 3614267292UL, 3078552271UL, 971722322UL, 3065543880UL, 2307584190UL, 491480322UL, 2068673112UL, 1929780632UL, 178549964UL, 983979983UL, 2769314886UL, 4214442042UL, 2977609682UL, 25450683UL, 3075212658UL, 1571149568UL, +3531670561UL, 42782504UL, 425601306UL, 428715214UL, 497250251UL, 693520802UL, 166426814UL, 1786382125UL, 2712003995UL, 3610802197UL, 2076490757UL, 404822980UL, 3953184772UL, 1655231947UL, 3594351577UL, 3068232274UL, 3771730346UL, 4110519574UL, 3534704897UL, 2375277865UL, 3597780202UL, 3472676002UL, 1350276449UL, 3218248239UL, 3589255283UL, 3253132633UL, 1769885529UL, 3792812294UL, 120332643UL, 1219374788UL, 3608889019UL, 2386099811UL, +858495304UL, 1284785543UL, 331370962UL, 2259419662UL, 2519864134UL, 3194739432UL, 2669074511UL, 2565559140UL, 3378072004UL, 2647801475UL, 265068954UL, 1464416963UL, 1232787612UL, 4160089759UL, 2510685972UL, 670300081UL, 2509357766UL, 1981891975UL, 4161588397UL, 1371924626UL, 44760868UL, 634955171UL, 1187096933UL, 3324788972UL, 3576888559UL, 2801347752UL, 3730298395UL, 1702170762UL, 4206083415UL, 741409141UL, 3649731355UL, 1025429529UL, +}, +{ +91444490UL, 628576944UL, 4069219862UL, 2253058925UL, 492354082UL, 1191182242UL, 1565180119UL, 2257613723UL, 456055162UL, 605712223UL, 953365104UL, 3104638527UL, 1133984729UL, 2662828416UL, 2134948274UL, 1921384447UL, 843719355UL, 588432962UL, 1734575434UL, 2924140067UL, 483396548UL, 3848838894UL, 3155476556UL, 1760928304UL, 4168059840UL, 3279827269UL, 2644461735UL, 4168565656UL, 3951563569UL, 1276805504UL, 1708974143UL, 1878547888UL, +3465220024UL, 3062086782UL, 2801401651UL, 1510428126UL, 716404149UL, 1646021208UL, 3534932385UL, 1186585561UL, 651997355UL, 282914223UL, 352224857UL, 3764407517UL, 1059868753UL, 1971798134UL, 978904005UL, 976413661UL, 4039544152UL, 498989693UL, 2565125471UL, 2782642813UL, 3537961025UL, 1194967362UL, 169217024UL, 3491609UL, 1319592872UL, 1630206561UL, 2497130840UL, 1685008996UL, 2828944016UL, 3301346775UL, 2893072371UL, 2606559798UL, +4026138031UL, 2664450619UL, 691091062UL, 1079640113UL, 1417637732UL, 4081852209UL, 2197910648UL, 2310382370UL, 1000957047UL, 959936499UL, 2844551811UL, 2272766890UL, 31122394UL, 2742925483UL, 1121884686UL, 57929089UL, 2468361281UL, 2982007782UL, 2371576893UL, 177782593UL, 3603584577UL, 672057044UL, 2108452841UL, 1671338057UL, 3386908223UL, 1243029765UL, 805157552UL, 1271858417UL, 1621249501UL, 1804851492UL, 1321010403UL, 751773221UL, +1517221627UL, 822709871UL, 104533154UL, 3578182264UL, 640541709UL, 421086624UL, 4233576392UL, 3729339369UL, 197460644UL, 773140636UL, 2158026018UL, 1756785611UL, 4011575991UL, 3569445500UL, 736117181UL, 2456162322UL, 1168189787UL, 3651312675UL, 1070291988UL, 268231205UL, 541474497UL, 3316168972UL, 3546990856UL, 830417208UL, 725960194UL, 2044207227UL, 3188997938UL, 2383298579UL, 3350316374UL, 3575011225UL, 1553111865UL, 1285013027UL, +749371711UL, 766611716UL, 598195098UL, 2139882719UL, 2062405428UL, 3634702446UL, 3015263295UL, 223311969UL, 2622859522UL, 3888492701UL, 2955257225UL, 582625650UL, 3563756446UL, 2886083960UL, 1907546514UL, 454650902UL, 3287277541UL, 625828138UL, 2991888140UL, 1935326370UL, 4031152256UL, 702881509UL, 1427632724UL, 1345475301UL, 2577560804UL, 2858595147UL, 2533191188UL, 185662179UL, 536505093UL, 3747894147UL, 111551030UL, 370373207UL, +2293908590UL, 91444490UL, 628576944UL, 4069219862UL, 2253058925UL, 1671484924UL, 1191182242UL, 1565180119UL, 2257613723UL, 456055162UL, 3411094744UL, 953365104UL, 3104638527UL, 1133984729UL, 2662828416UL, 2000630022UL, 1921384447UL, 843719355UL, 588432962UL, 1734575434UL, 3293926122UL, 483396548UL, 3848838894UL, 3155476556UL, 1760928304UL, 146876953UL, 3279827269UL, 2644461735UL, 4168565656UL, 3951563569UL, 3976156700UL, 1708974143UL, +1878547888UL, 3465220024UL, 3062086782UL, 1999154400UL, 1510428126UL, 716404149UL, 1646021208UL, 3534932385UL, 2479551429UL, 651997355UL, 282914223UL, 352224857UL, 3764407517UL, 1275979651UL, 1971798134UL, 978904005UL, 976413661UL, 4039544152UL, 300654823UL, 2565125471UL, 2782642813UL, 3537961025UL, 1194967362UL, 3123973648UL, 3491609UL, 1319592872UL, 1630206561UL, 2497130840UL, 1437913158UL, 2828944016UL, 3301346775UL, 2893072371UL, +2606559798UL, 2153172585UL, 2664450619UL, 691091062UL, 1079640113UL, 1417637732UL, 17137237UL, 2197910648UL, 2310382370UL, 1000957047UL, 959936499UL, 802137134UL, 2272766890UL, 31122394UL, 2742925483UL, 1121884686UL, 3909775167UL, 2468361281UL, 2982007782UL, 2371576893UL, 177782593UL, 3319492525UL, 672057044UL, 2108452841UL, 1671338057UL, 3386908223UL, 1878151473UL, 805157552UL, 1271858417UL, 1621249501UL, 1804851492UL, 3215921223UL, +751773221UL, 1517221627UL, 822709871UL, 104533154UL, 361845001UL, 640541709UL, 421086624UL, 4233576392UL, 3729339369UL, 2655936801UL, 773140636UL, 2158026018UL, 1756785611UL, 4011575991UL, 587202971UL, 736117181UL, 2456162322UL, 1168189787UL, 3651312675UL, 2517883370UL, 268231205UL, 541474497UL, 3316168972UL, 3546990856UL, 2037251305UL, 725960194UL, 2044207227UL, 3188997938UL, 2383298579UL, 2665008587UL, 3575011225UL, 1553111865UL, +1285013027UL, 749371711UL, 2163964019UL, 598195098UL, 2139882719UL, 2062405428UL, 3634702446UL, 2788202059UL, 223311969UL, 2622859522UL, 3888492701UL, 2955257225UL, 740986174UL, 3563756446UL, 2886083960UL, 1907546514UL, 454650902UL, 2426323587UL, 625828138UL, 2991888140UL, 1935326370UL, 4031152256UL, 1831149435UL, 1427632724UL, 1345475301UL, 2577560804UL, 2858595147UL, 3977153945UL, 185662179UL, 536505093UL, 3747894147UL, 111551030UL, +4131587422UL, 2293908590UL, 91444490UL, 628576944UL, 4069219862UL, 2408189350UL, 1671484924UL, 1191182242UL, 1565180119UL, 2257613723UL, 1338069254UL, 3411094744UL, 953365104UL, 3104638527UL, 1133984729UL, 631497759UL, 2000630022UL, 1921384447UL, 843719355UL, 588432962UL, 3280318959UL, 3293926122UL, 483396548UL, 3848838894UL, 3155476556UL, 1777918163UL, 146876953UL, 3279827269UL, 2644461735UL, 4168565656UL, 2786264663UL, 3976156700UL, +1708974143UL, 1878547888UL, 3465220024UL, 2793923820UL, 1999154400UL, 1510428126UL, 716404149UL, 1646021208UL, 3102243824UL, 2479551429UL, 651997355UL, 282914223UL, 352224857UL, 3767702588UL, 1275979651UL, 1971798134UL, 978904005UL, 976413661UL, 1951622548UL, 300654823UL, 2565125471UL, 2782642813UL, 3537961025UL, 2186817324UL, 3123973648UL, 3491609UL, 1319592872UL, 1630206561UL, 1075424534UL, 1437913158UL, 2828944016UL, 3301346775UL, +2893072371UL, 207992406UL, 2153172585UL, 2664450619UL, 691091062UL, 1079640113UL, 3114255216UL, 17137237UL, 2197910648UL, 2310382370UL, 1000957047UL, 2548008553UL, 802137134UL, 2272766890UL, 31122394UL, 2742925483UL, 4069482373UL, 3909775167UL, 2468361281UL, 2982007782UL, 2371576893UL, 2807823912UL, 3319492525UL, 672057044UL, 2108452841UL, 1671338057UL, 12831353UL, 1878151473UL, 805157552UL, 1271858417UL, 1621249501UL, 461887094UL, +3215921223UL, 751773221UL, 1517221627UL, 822709871UL, 1317394918UL, 361845001UL, 640541709UL, 421086624UL, 4233576392UL, 3385587450UL, 2655936801UL, 773140636UL, 2158026018UL, 1756785611UL, 1475601973UL, 587202971UL, 736117181UL, 2456162322UL, 1168189787UL, 911455077UL, 2517883370UL, 268231205UL, 541474497UL, 3316168972UL, 1500275507UL, 2037251305UL, 725960194UL, 2044207227UL, 3188997938UL, 2036633808UL, 2665008587UL, 3575011225UL, +1553111865UL, 1285013027UL, 87868216UL, 2163964019UL, 598195098UL, 2139882719UL, 2062405428UL, 517907301UL, 2788202059UL, 223311969UL, 2622859522UL, 3888492701UL, 3926046234UL, 740986174UL, 3563756446UL, 2886083960UL, 1907546514UL, 1911066215UL, 2426323587UL, 625828138UL, 2991888140UL, 1935326370UL, 2031853435UL, 1831149435UL, 1427632724UL, 1345475301UL, 2577560804UL, 3509674153UL, 3977153945UL, 185662179UL, 536505093UL, 3747894147UL, +1711714600UL, 4131587422UL, 2293908590UL, 91444490UL, 628576944UL, 3370678255UL, 2408189350UL, 1671484924UL, 1191182242UL, 1565180119UL, 3786239592UL, 1338069254UL, 3411094744UL, 953365104UL, 3104638527UL, 3659647225UL, 631497759UL, 2000630022UL, 1921384447UL, 843719355UL, 3364831282UL, 3280318959UL, 3293926122UL, 483396548UL, 3848838894UL, 3131266478UL, 1777918163UL, 146876953UL, 3279827269UL, 2644461735UL, 4156372383UL, 2786264663UL, +3976156700UL, 1708974143UL, 1878547888UL, 2168041590UL, 2793923820UL, 1999154400UL, 1510428126UL, 716404149UL, 3392113666UL, 3102243824UL, 2479551429UL, 651997355UL, 282914223UL, 2085613514UL, 3767702588UL, 1275979651UL, 1971798134UL, 978904005UL, 503506384UL, 1951622548UL, 300654823UL, 2565125471UL, 2782642813UL, 1458431750UL, 2186817324UL, 3123973648UL, 3491609UL, 1319592872UL, 452433679UL, 1075424534UL, 1437913158UL, 2828944016UL, +3301346775UL, 2333281307UL, 207992406UL, 2153172585UL, 2664450619UL, 691091062UL, 3553502652UL, 3114255216UL, 17137237UL, 2197910648UL, 2310382370UL, 3153689868UL, 2548008553UL, 802137134UL, 2272766890UL, 31122394UL, 468580641UL, 4069482373UL, 3909775167UL, 2468361281UL, 2982007782UL, 1445286890UL, 2807823912UL, 3319492525UL, 672057044UL, 2108452841UL, 1755577669UL, 12831353UL, 1878151473UL, 805157552UL, 1271858417UL, 2623540912UL, +461887094UL, 3215921223UL, 751773221UL, 1517221627UL, 3922191946UL, 1317394918UL, 361845001UL, 640541709UL, 421086624UL, 2173849516UL, 3385587450UL, 2655936801UL, 773140636UL, 2158026018UL, 1085377158UL, 1475601973UL, 587202971UL, 736117181UL, 2456162322UL, 2158960374UL, 911455077UL, 2517883370UL, 268231205UL, 541474497UL, 943191315UL, 1500275507UL, 2037251305UL, 725960194UL, 2044207227UL, 2481150802UL, 2036633808UL, 2665008587UL, +3575011225UL, 1553111865UL, 2301231777UL, 87868216UL, 2163964019UL, 598195098UL, 2139882719UL, 2007840238UL, 517907301UL, 2788202059UL, 223311969UL, 2622859522UL, 151920263UL, 3926046234UL, 740986174UL, 3563756446UL, 2886083960UL, 1338937928UL, 1911066215UL, 2426323587UL, 625828138UL, 2991888140UL, 2652286195UL, 2031853435UL, 1831149435UL, 1427632724UL, 1345475301UL, 289801789UL, 3509674153UL, 3977153945UL, 185662179UL, 536505093UL, +2727322952UL, 3980498348UL, 2529622213UL, 1903052964UL, 3564714651UL, 2281240568UL, 533384122UL, 277613480UL, 1815540358UL, 282763841UL, 3669112623UL, 2572859425UL, 195220178UL, 1210883545UL, 2359703600UL, 1187537824UL, 675732974UL, 325036095UL, 708091465UL, 2556854604UL, 701006284UL, 2378459191UL, 1863513103UL, 2690918197UL, 4237307694UL, 1356483501UL, 2160905652UL, 521809106UL, 974368613UL, 3136010957UL, 2722488678UL, 3711515637UL, +2296341459UL, 4233729945UL, 1196247571UL, 3031398071UL, 515543502UL, 1314129776UL, 3235373306UL, 1303165859UL, 1820568009UL, 559099351UL, 186876368UL, 1076102111UL, 1218809551UL, 1790301111UL, 4130210229UL, 768125358UL, 1132864749UL, 4262563773UL, 2294411020UL, 4092943985UL, 2558108246UL, 3737664949UL, 2219923393UL, 724326159UL, 4134105682UL, 4188752746UL, 3615233671UL, 1526018731UL, 2281637916UL, 2459490295UL, 3637342666UL, 777862587UL, +39962002UL, 3772005832UL, 997473319UL, 574843584UL, 3356551974UL, 1265234427UL, 1698059437UL, 534747571UL, 1465532164UL, 3263029035UL, 534512444UL, 2343092827UL, 2375685652UL, 2497926141UL, 2377933621UL, 2212335180UL, 261114084UL, 172755755UL, 2737085495UL, 2225257145UL, 148605658UL, 1353911796UL, 357753009UL, 1778732943UL, 497635558UL, 4136467976UL, 2837964962UL, 4045039047UL, 2485296762UL, 1587587183UL, 4042904168UL, 3184240963UL, +2393293696UL, 915444966UL, 2299938515UL, 3351580749UL, 506575598UL, 1541916825UL, 3465300401UL, 525927458UL, 681152801UL, 331660975UL, 3624685846UL, 2994172100UL, 3274369082UL, 3638287602UL, 815689760UL, 1710961092UL, 2775607076UL, 2175058103UL, 3252688367UL, 2936890483UL, 2746319120UL, 2736754UL, 1646031035UL, 2448701214UL, 2886833213UL, 3689830606UL, 3292798106UL, 300773646UL, 3125160783UL, 1247453205UL, 2746275624UL, 4011063775UL, +904135764UL, 876847374UL, 366267234UL, 2541269205UL, 131376648UL, 1805948133UL, 3383589530UL, 2350119829UL, 2513170439UL, 4096158499UL, 4229211520UL, 2992048272UL, 1338522080UL, 1187391335UL, 2898563453UL, 2163088451UL, 1417971677UL, 2047421551UL, 902282791UL, 1143943232UL, 3568431811UL, 4059861993UL, 193362198UL, 2509297125UL, 3968551582UL, 2175686117UL, 3568936881UL, 1853177468UL, 2134063169UL, 2919389416UL, 1124914545UL, 1209806738UL, +}, +{ +1199972651UL, 1035834631UL, 3177798370UL, 860834162UL, 3741677748UL, 3780327829UL, 1693730265UL, 1643429511UL, 559568669UL, 2758650294UL, 647308222UL, 3901603996UL, 1778653821UL, 3618523672UL, 2154201067UL, 4261179460UL, 3285764480UL, 3334002738UL, 3215795953UL, 91368462UL, 1883994950UL, 1506873376UL, 1527780962UL, 4046354597UL, 4081676034UL, 2389066602UL, 1574939945UL, 427845396UL, 2714836263UL, 1259019491UL, 2493238133UL, 2584034689UL, +3151382431UL, 2171033919UL, 176883719UL, 2031844862UL, 1272380790UL, 1298975901UL, 4087222847UL, 1524000054UL, 311436877UL, 3627785554UL, 1889491722UL, 2938069193UL, 2771940687UL, 2756955968UL, 4289348777UL, 263514583UL, 887207028UL, 3522902525UL, 2273246349UL, 835377715UL, 2897243319UL, 204645450UL, 1775911983UL, 639470242UL, 2856296318UL, 3032942383UL, 2845501282UL, 1979082575UL, 202834023UL, 1876303820UL, 1434703409UL, 4240524132UL, +848853780UL, 4188621628UL, 928095314UL, 876412914UL, 3446576392UL, 3235688990UL, 4021419931UL, 2483628986UL, 3155781890UL, 399997246UL, 1642535200UL, 3872575068UL, 1577956550UL, 3606228634UL, 609914462UL, 653194726UL, 4048067248UL, 2500767965UL, 1125167825UL, 3707628088UL, 1819135158UL, 1875618971UL, 3865851141UL, 328215079UL, 1695889194UL, 2040280471UL, 3384684457UL, 2540504961UL, 293050253UL, 525570078UL, 2655676443UL, 1392199429UL, +3370444585UL, 1937915855UL, 2229636250UL, 247937142UL, 2534538765UL, 365841057UL, 2449431033UL, 2456532429UL, 101910696UL, 1247069485UL, 1523958293UL, 2473285670UL, 473709728UL, 3026667113UL, 2071968844UL, 324025193UL, 423064436UL, 3870800061UL, 3977393138UL, 3632553233UL, 352757977UL, 1584833348UL, 3173248650UL, 1159857686UL, 1501841977UL, 1751860798UL, 617281070UL, 1958012761UL, 4031667102UL, 3232142321UL, 3087428595UL, 2380824676UL, +1194087757UL, 1542961747UL, 4163350364UL, 1721646249UL, 1672791861UL, 2900511710UL, 24973500UL, 1705444176UL, 713642505UL, 3017719513UL, 2090715200UL, 3521434070UL, 37117223UL, 1948295454UL, 3055840561UL, 3476120789UL, 3994249388UL, 527899063UL, 4285770666UL, 1075524023UL, 2594223535UL, 392943522UL, 171012646UL, 3515750082UL, 3414659054UL, 3501852926UL, 1493283737UL, 2662104279UL, 2033464928UL, 90134967UL, 363058647UL, 3289266998UL, +2470752727UL, 1199972651UL, 1035834631UL, 3177798370UL, 860834162UL, 1791097822UL, 3780327829UL, 1693730265UL, 1643429511UL, 559568669UL, 3503319486UL, 647308222UL, 3901603996UL, 1778653821UL, 3618523672UL, 4294594427UL, 4261179460UL, 3285764480UL, 3334002738UL, 3215795953UL, 212518363UL, 1883994950UL, 1506873376UL, 1527780962UL, 4046354597UL, 2398655600UL, 2389066602UL, 1574939945UL, 427845396UL, 2714836263UL, 2744363872UL, 2493238133UL, +2584034689UL, 3151382431UL, 2171033919UL, 2787053497UL, 2031844862UL, 1272380790UL, 1298975901UL, 4087222847UL, 2342953154UL, 311436877UL, 3627785554UL, 1889491722UL, 2938069193UL, 2026656505UL, 2756955968UL, 4289348777UL, 263514583UL, 887207028UL, 2097276163UL, 2273246349UL, 835377715UL, 2897243319UL, 204645450UL, 4233399907UL, 639470242UL, 2856296318UL, 3032942383UL, 2845501282UL, 28260330UL, 202834023UL, 1876303820UL, 1434703409UL, +4240524132UL, 2455670466UL, 4188621628UL, 928095314UL, 876412914UL, 3446576392UL, 117581687UL, 4021419931UL, 2483628986UL, 3155781890UL, 399997246UL, 4254101087UL, 3872575068UL, 1577956550UL, 3606228634UL, 609914462UL, 4003279048UL, 4048067248UL, 2500767965UL, 1125167825UL, 3707628088UL, 922020515UL, 1875618971UL, 3865851141UL, 328215079UL, 1695889194UL, 625773097UL, 3384684457UL, 2540504961UL, 293050253UL, 525570078UL, 2592805114UL, +1392199429UL, 3370444585UL, 1937915855UL, 2229636250UL, 3190958614UL, 2534538765UL, 365841057UL, 2449431033UL, 2456532429UL, 3778669305UL, 1247069485UL, 1523958293UL, 2473285670UL, 473709728UL, 720895889UL, 2071968844UL, 324025193UL, 423064436UL, 3870800061UL, 3535536111UL, 3632553233UL, 352757977UL, 1584833348UL, 3173248650UL, 2649344603UL, 1501841977UL, 1751860798UL, 617281070UL, 1958012761UL, 778965559UL, 3232142321UL, 3087428595UL, +2380824676UL, 1194087757UL, 3880222002UL, 4163350364UL, 1721646249UL, 1672791861UL, 2900511710UL, 702936770UL, 1705444176UL, 713642505UL, 3017719513UL, 2090715200UL, 1477858694UL, 37117223UL, 1948295454UL, 3055840561UL, 3476120789UL, 464173532UL, 527899063UL, 4285770666UL, 1075524023UL, 2594223535UL, 2872629966UL, 171012646UL, 3515750082UL, 3414659054UL, 3501852926UL, 1631555059UL, 2662104279UL, 2033464928UL, 90134967UL, 363058647UL, +4112991722UL, 2470752727UL, 1199972651UL, 1035834631UL, 3177798370UL, 4152098951UL, 1791097822UL, 3780327829UL, 1693730265UL, 1643429511UL, 153020604UL, 3503319486UL, 647308222UL, 3901603996UL, 1778653821UL, 221887019UL, 4294594427UL, 4261179460UL, 3285764480UL, 3334002738UL, 3340918862UL, 212518363UL, 1883994950UL, 1506873376UL, 1527780962UL, 430180116UL, 2398655600UL, 2389066602UL, 1574939945UL, 427845396UL, 1683639957UL, 2744363872UL, +2493238133UL, 2584034689UL, 3151382431UL, 752704472UL, 2787053497UL, 2031844862UL, 1272380790UL, 1298975901UL, 1528220628UL, 2342953154UL, 311436877UL, 3627785554UL, 1889491722UL, 2576495467UL, 2026656505UL, 2756955968UL, 4289348777UL, 263514583UL, 3778019638UL, 2097276163UL, 2273246349UL, 835377715UL, 2897243319UL, 1060067446UL, 4233399907UL, 639470242UL, 2856296318UL, 3032942383UL, 2351047932UL, 28260330UL, 202834023UL, 1876303820UL, +1434703409UL, 3094305336UL, 2455670466UL, 4188621628UL, 928095314UL, 876412914UL, 3785385583UL, 117581687UL, 4021419931UL, 2483628986UL, 3155781890UL, 1867816730UL, 4254101087UL, 3872575068UL, 1577956550UL, 3606228634UL, 3081878598UL, 4003279048UL, 4048067248UL, 2500767965UL, 1125167825UL, 928465955UL, 922020515UL, 1875618971UL, 3865851141UL, 328215079UL, 173810260UL, 625773097UL, 3384684457UL, 2540504961UL, 293050253UL, 2645143254UL, +2592805114UL, 1392199429UL, 3370444585UL, 1937915855UL, 162781360UL, 3190958614UL, 2534538765UL, 365841057UL, 2449431033UL, 3105377832UL, 3778669305UL, 1247069485UL, 1523958293UL, 2473285670UL, 800971948UL, 720895889UL, 2071968844UL, 324025193UL, 423064436UL, 52577992UL, 3535536111UL, 3632553233UL, 352757977UL, 1584833348UL, 3305908059UL, 2649344603UL, 1501841977UL, 1751860798UL, 617281070UL, 264880505UL, 778965559UL, 3232142321UL, +3087428595UL, 2380824676UL, 1127761012UL, 3880222002UL, 4163350364UL, 1721646249UL, 1672791861UL, 2368512339UL, 702936770UL, 1705444176UL, 713642505UL, 3017719513UL, 197200752UL, 1477858694UL, 37117223UL, 1948295454UL, 3055840561UL, 1588372042UL, 464173532UL, 527899063UL, 4285770666UL, 1075524023UL, 2124039914UL, 2872629966UL, 171012646UL, 3515750082UL, 3414659054UL, 818571456UL, 1631555059UL, 2662104279UL, 2033464928UL, 90134967UL, +952712086UL, 4112991722UL, 2470752727UL, 1199972651UL, 1035834631UL, 888975816UL, 4152098951UL, 1791097822UL, 3780327829UL, 1693730265UL, 3406785510UL, 153020604UL, 3503319486UL, 647308222UL, 3901603996UL, 3753248472UL, 221887019UL, 4294594427UL, 4261179460UL, 3285764480UL, 1861431346UL, 3340918862UL, 212518363UL, 1883994950UL, 1506873376UL, 2695939612UL, 430180116UL, 2398655600UL, 2389066602UL, 1574939945UL, 2852159074UL, 1683639957UL, +2744363872UL, 2493238133UL, 2584034689UL, 1952065633UL, 752704472UL, 2787053497UL, 2031844862UL, 1272380790UL, 3530505866UL, 1528220628UL, 2342953154UL, 311436877UL, 3627785554UL, 3410473245UL, 2576495467UL, 2026656505UL, 2756955968UL, 4289348777UL, 2856163034UL, 3778019638UL, 2097276163UL, 2273246349UL, 835377715UL, 3127280755UL, 1060067446UL, 4233399907UL, 639470242UL, 2856296318UL, 2615775011UL, 2351047932UL, 28260330UL, 202834023UL, +1876303820UL, 619308202UL, 3094305336UL, 2455670466UL, 4188621628UL, 928095314UL, 3764894047UL, 3785385583UL, 117581687UL, 4021419931UL, 2483628986UL, 3759839215UL, 1867816730UL, 4254101087UL, 3872575068UL, 1577956550UL, 1687107439UL, 3081878598UL, 4003279048UL, 4048067248UL, 2500767965UL, 2804044146UL, 928465955UL, 922020515UL, 1875618971UL, 3865851141UL, 2359176389UL, 173810260UL, 625773097UL, 3384684457UL, 2540504961UL, 3665420733UL, +2645143254UL, 2592805114UL, 1392199429UL, 3370444585UL, 1604709429UL, 162781360UL, 3190958614UL, 2534538765UL, 365841057UL, 3843585067UL, 3105377832UL, 3778669305UL, 1247069485UL, 1523958293UL, 293374051UL, 800971948UL, 720895889UL, 2071968844UL, 324025193UL, 3342361801UL, 52577992UL, 3535536111UL, 3632553233UL, 352757977UL, 1386594581UL, 3305908059UL, 2649344603UL, 1501841977UL, 1751860798UL, 3160423601UL, 264880505UL, 778965559UL, +3232142321UL, 3087428595UL, 3814775120UL, 1127761012UL, 3880222002UL, 4163350364UL, 1721646249UL, 3640773034UL, 2368512339UL, 702936770UL, 1705444176UL, 713642505UL, 1717761787UL, 197200752UL, 1477858694UL, 37117223UL, 1948295454UL, 896215772UL, 1588372042UL, 464173532UL, 527899063UL, 4285770666UL, 3441409029UL, 2124039914UL, 2872629966UL, 171012646UL, 3515750082UL, 2216687886UL, 818571456UL, 1631555059UL, 2662104279UL, 2033464928UL, +369438400UL, 329003658UL, 1503365029UL, 4215790910UL, 3264377550UL, 733526983UL, 2935318632UL, 1792331479UL, 608347530UL, 392723097UL, 1330445854UL, 3473004271UL, 1267636682UL, 2150566972UL, 2664910943UL, 2591861637UL, 409769584UL, 2943326880UL, 3746302819UL, 3162268832UL, 1028663260UL, 3206607045UL, 832105292UL, 2119405275UL, 538318455UL, 2981192295UL, 861775416UL, 609718403UL, 3531204230UL, 1904759571UL, 1262633751UL, 2375133081UL, +460454984UL, 946700253UL, 3763898311UL, 1571175213UL, 3124410107UL, 2413420216UL, 2664177543UL, 3241803820UL, 3968067371UL, 1234860999UL, 1130471500UL, 772727786UL, 247203117UL, 576455235UL, 246297007UL, 2027348597UL, 764933887UL, 3812479771UL, 1825807084UL, 4072281412UL, 2156865781UL, 1286484847UL, 1966749063UL, 2479269303UL, 423506843UL, 3070938758UL, 653091413UL, 2267423132UL, 2004263526UL, 1374490719UL, 3871990628UL, 841138314UL, +1260317857UL, 3887432433UL, 4025147569UL, 764233331UL, 1794763428UL, 3005903468UL, 877926770UL, 2466593927UL, 2971729561UL, 3203070565UL, 4198500026UL, 815665759UL, 2434508139UL, 1840456368UL, 2279000427UL, 17077200UL, 3178380570UL, 990304199UL, 3578008580UL, 1965763660UL, 1640352477UL, 750159594UL, 2047409402UL, 3576308245UL, 544920564UL, 1730124869UL, 1194761386UL, 3280315505UL, 147334027UL, 2870674244UL, 2076860776UL, 1100947675UL, +2482772161UL, 401966468UL, 1610650855UL, 193868446UL, 3808157106UL, 1509130117UL, 1324484736UL, 3852893217UL, 1059179497UL, 4053543778UL, 2557844172UL, 3282312002UL, 682550058UL, 4281899173UL, 137171998UL, 3239159214UL, 2258610918UL, 426724741UL, 3502660993UL, 135977383UL, 429929363UL, 3984458137UL, 964026748UL, 2182019070UL, 3836562946UL, 515026869UL, 359030455UL, 1301694917UL, 2300414803UL, 2364654981UL, 3804876710UL, 171119249UL, +2646785698UL, 4283509387UL, 3628087763UL, 1748227044UL, 3037141234UL, 3000413256UL, 23007314UL, 3598880509UL, 4160517314UL, 112205578UL, 1677675411UL, 734881643UL, 2830770338UL, 3470317145UL, 3306806569UL, 2635040943UL, 2671367560UL, 3528996498UL, 3878886478UL, 3114253828UL, 2721384408UL, 3175226991UL, 1393767271UL, 2651623266UL, 3767978376UL, 1269699398UL, 1100964192UL, 4169085845UL, 2086718107UL, 1286251099UL, 764751784UL, 3006878591UL, +}, +{ +2565473087UL, 1149521056UL, 3529037691UL, 630435548UL, 73598765UL, 1467331930UL, 3988027050UL, 2771962200UL, 91261543UL, 980989218UL, 2227515435UL, 236831608UL, 2872772569UL, 2330469327UL, 1654035853UL, 2883791516UL, 4170143763UL, 126418114UL, 127789935UL, 2114249438UL, 2933346767UL, 639483386UL, 1532399845UL, 2182422151UL, 741069317UL, 2376371063UL, 3398508789UL, 3828295651UL, 3963199356UL, 4156483769UL, 4206759111UL, 1266176088UL, +3210273687UL, 432131993UL, 667709537UL, 874477513UL, 2304714957UL, 629309008UL, 116453438UL, 3051811727UL, 3490241985UL, 3355968243UL, 2304043871UL, 2724990029UL, 1095724699UL, 2408437363UL, 1433161037UL, 3245468546UL, 2494529842UL, 4204170637UL, 1966342448UL, 3092333073UL, 1861880941UL, 3990012367UL, 3710334908UL, 2526395471UL, 1884691351UL, 2145882162UL, 2561288457UL, 2253122309UL, 1154858044UL, 1643256991UL, 3172857504UL, 1096492713UL, +2848827103UL, 799826424UL, 3094672168UL, 3535834360UL, 4213256737UL, 1131757994UL, 520495112UL, 575315345UL, 3823364867UL, 2424349582UL, 3604795017UL, 310789314UL, 4207205257UL, 553462404UL, 2918228443UL, 2568360580UL, 3863565851UL, 874197736UL, 3329267685UL, 1186352580UL, 3928193054UL, 1780200631UL, 4088289456UL, 3323217870UL, 2758854947UL, 3111637417UL, 990374143UL, 2080149357UL, 4047813631UL, 2019887940UL, 578660736UL, 2145680301UL, +2328411541UL, 1572704242UL, 405739686UL, 1869350271UL, 2046317220UL, 4021497634UL, 1385163990UL, 1935250885UL, 1132987169UL, 581690993UL, 3172043012UL, 628071512UL, 2851125739UL, 2735324847UL, 2847267504UL, 3408334906UL, 3352976111UL, 706277272UL, 2971786942UL, 2811957324UL, 3578703606UL, 1126685543UL, 2671169997UL, 31952251UL, 2802110464UL, 2391618856UL, 3031260674UL, 1165714541UL, 2411388800UL, 2825634835UL, 101928462UL, 477629709UL, +4257022506UL, 3281706767UL, 2576087732UL, 736533968UL, 2543083137UL, 3430523686UL, 3272172013UL, 3056925798UL, 341993500UL, 406782950UL, 1770032304UL, 125786076UL, 1321359723UL, 2901696227UL, 1890958265UL, 3610842776UL, 1772227311UL, 1564088598UL, 914173231UL, 3734092059UL, 1652333721UL, 2386645282UL, 329706426UL, 1022239203UL, 1832393502UL, 4064995802UL, 3497852986UL, 1046436763UL, 366391010UL, 2237068647UL, 2887356463UL, 304718827UL, +3969799795UL, 2565473087UL, 1149521056UL, 3529037691UL, 630435548UL, 3758124054UL, 1467331930UL, 3988027050UL, 2771962200UL, 91261543UL, 836545831UL, 2227515435UL, 236831608UL, 2872772569UL, 2330469327UL, 3439193753UL, 2883791516UL, 4170143763UL, 126418114UL, 127789935UL, 1648940583UL, 2933346767UL, 639483386UL, 1532399845UL, 2182422151UL, 2470139222UL, 2376371063UL, 3398508789UL, 3828295651UL, 3963199356UL, 2997263135UL, 4206759111UL, +1266176088UL, 3210273687UL, 432131993UL, 2416600665UL, 874477513UL, 2304714957UL, 629309008UL, 116453438UL, 2586542760UL, 3490241985UL, 3355968243UL, 2304043871UL, 2724990029UL, 452934545UL, 2408437363UL, 1433161037UL, 3245468546UL, 2494529842UL, 2244403710UL, 1966342448UL, 3092333073UL, 1861880941UL, 3990012367UL, 2774994234UL, 2526395471UL, 1884691351UL, 2145882162UL, 2561288457UL, 2303702146UL, 1154858044UL, 1643256991UL, 3172857504UL, +1096492713UL, 130979316UL, 799826424UL, 3094672168UL, 3535834360UL, 4213256737UL, 935499492UL, 520495112UL, 575315345UL, 3823364867UL, 2424349582UL, 2272973265UL, 310789314UL, 4207205257UL, 553462404UL, 2918228443UL, 2613016888UL, 3863565851UL, 874197736UL, 3329267685UL, 1186352580UL, 4106984978UL, 1780200631UL, 4088289456UL, 3323217870UL, 2758854947UL, 1559861146UL, 990374143UL, 2080149357UL, 4047813631UL, 2019887940UL, 1133329900UL, +2145680301UL, 2328411541UL, 1572704242UL, 405739686UL, 63633520UL, 2046317220UL, 4021497634UL, 1385163990UL, 1935250885UL, 1762959503UL, 581690993UL, 3172043012UL, 628071512UL, 2851125739UL, 3726073981UL, 2847267504UL, 3408334906UL, 3352976111UL, 706277272UL, 3817450114UL, 2811957324UL, 3578703606UL, 1126685543UL, 2671169997UL, 2749086326UL, 2802110464UL, 2391618856UL, 3031260674UL, 1165714541UL, 2210258428UL, 2825634835UL, 101928462UL, +477629709UL, 4257022506UL, 2679409844UL, 2576087732UL, 736533968UL, 2543083137UL, 3430523686UL, 1122549807UL, 3056925798UL, 341993500UL, 406782950UL, 1770032304UL, 2617760292UL, 1321359723UL, 2901696227UL, 1890958265UL, 3610842776UL, 2666109620UL, 1564088598UL, 914173231UL, 3734092059UL, 1652333721UL, 3456779008UL, 329706426UL, 1022239203UL, 1832393502UL, 4064995802UL, 4006865520UL, 1046436763UL, 366391010UL, 2237068647UL, 2887356463UL, +1479646555UL, 3969799795UL, 2565473087UL, 1149521056UL, 3529037691UL, 2379195579UL, 3758124054UL, 1467331930UL, 3988027050UL, 2771962200UL, 1796797949UL, 836545831UL, 2227515435UL, 236831608UL, 2872772569UL, 544017308UL, 3439193753UL, 2883791516UL, 4170143763UL, 126418114UL, 3811390247UL, 1648940583UL, 2933346767UL, 639483386UL, 1532399845UL, 4165970043UL, 2470139222UL, 2376371063UL, 3398508789UL, 3828295651UL, 4066952157UL, 2997263135UL, +4206759111UL, 1266176088UL, 3210273687UL, 560560354UL, 2416600665UL, 874477513UL, 2304714957UL, 629309008UL, 2010844440UL, 2586542760UL, 3490241985UL, 3355968243UL, 2304043871UL, 855615381UL, 452934545UL, 2408437363UL, 1433161037UL, 3245468546UL, 3813880871UL, 2244403710UL, 1966342448UL, 3092333073UL, 1861880941UL, 3334256651UL, 2774994234UL, 2526395471UL, 1884691351UL, 2145882162UL, 3500193798UL, 2303702146UL, 1154858044UL, 1643256991UL, +3172857504UL, 3480843206UL, 130979316UL, 799826424UL, 3094672168UL, 3535834360UL, 915442396UL, 935499492UL, 520495112UL, 575315345UL, 3823364867UL, 2876158574UL, 2272973265UL, 310789314UL, 4207205257UL, 553462404UL, 2184663001UL, 2613016888UL, 3863565851UL, 874197736UL, 3329267685UL, 3447734684UL, 4106984978UL, 1780200631UL, 4088289456UL, 3323217870UL, 2748493470UL, 1559861146UL, 990374143UL, 2080149357UL, 4047813631UL, 2728282767UL, +1133329900UL, 2145680301UL, 2328411541UL, 1572704242UL, 3396987326UL, 63633520UL, 2046317220UL, 4021497634UL, 1385163990UL, 1582181054UL, 1762959503UL, 581690993UL, 3172043012UL, 628071512UL, 2790170929UL, 3726073981UL, 2847267504UL, 3408334906UL, 3352976111UL, 1211075015UL, 3817450114UL, 2811957324UL, 3578703606UL, 1126685543UL, 1946225412UL, 2749086326UL, 2802110464UL, 2391618856UL, 3031260674UL, 453222948UL, 2210258428UL, 2825634835UL, +101928462UL, 477629709UL, 410621659UL, 2679409844UL, 2576087732UL, 736533968UL, 2543083137UL, 1101977922UL, 1122549807UL, 3056925798UL, 341993500UL, 406782950UL, 3057489804UL, 2617760292UL, 1321359723UL, 2901696227UL, 1890958265UL, 4035843698UL, 2666109620UL, 1564088598UL, 914173231UL, 3734092059UL, 908525903UL, 3456779008UL, 329706426UL, 1022239203UL, 1832393502UL, 4024857205UL, 4006865520UL, 1046436763UL, 366391010UL, 2237068647UL, +1564059380UL, 1479646555UL, 3969799795UL, 2565473087UL, 1149521056UL, 2808155917UL, 2379195579UL, 3758124054UL, 1467331930UL, 3988027050UL, 810008243UL, 1796797949UL, 836545831UL, 2227515435UL, 236831608UL, 608273331UL, 544017308UL, 3439193753UL, 2883791516UL, 4170143763UL, 3309288977UL, 3811390247UL, 1648940583UL, 2933346767UL, 639483386UL, 1685761277UL, 4165970043UL, 2470139222UL, 2376371063UL, 3398508789UL, 4275493636UL, 4066952157UL, +2997263135UL, 4206759111UL, 1266176088UL, 333592630UL, 560560354UL, 2416600665UL, 874477513UL, 2304714957UL, 1438974661UL, 2010844440UL, 2586542760UL, 3490241985UL, 3355968243UL, 2556368068UL, 855615381UL, 452934545UL, 2408437363UL, 1433161037UL, 4061232080UL, 3813880871UL, 2244403710UL, 1966342448UL, 3092333073UL, 3412770364UL, 3334256651UL, 2774994234UL, 2526395471UL, 1884691351UL, 1414627588UL, 3500193798UL, 2303702146UL, 1154858044UL, +1643256991UL, 2245958719UL, 3480843206UL, 130979316UL, 799826424UL, 3094672168UL, 2214560871UL, 915442396UL, 935499492UL, 520495112UL, 575315345UL, 3894763683UL, 2876158574UL, 2272973265UL, 310789314UL, 4207205257UL, 3203740771UL, 2184663001UL, 2613016888UL, 3863565851UL, 874197736UL, 3371653768UL, 3447734684UL, 4106984978UL, 1780200631UL, 4088289456UL, 378312754UL, 2748493470UL, 1559861146UL, 990374143UL, 2080149357UL, 554816113UL, +2728282767UL, 1133329900UL, 2145680301UL, 2328411541UL, 4249979994UL, 3396987326UL, 63633520UL, 2046317220UL, 4021497634UL, 4185731269UL, 1582181054UL, 1762959503UL, 581690993UL, 3172043012UL, 3142596028UL, 2790170929UL, 3726073981UL, 2847267504UL, 3408334906UL, 2556911142UL, 1211075015UL, 3817450114UL, 2811957324UL, 3578703606UL, 1480672978UL, 1946225412UL, 2749086326UL, 2802110464UL, 2391618856UL, 3986823297UL, 453222948UL, 2210258428UL, +2825634835UL, 101928462UL, 26373721UL, 410621659UL, 2679409844UL, 2576087732UL, 736533968UL, 888001208UL, 1101977922UL, 1122549807UL, 3056925798UL, 341993500UL, 3243663736UL, 3057489804UL, 2617760292UL, 1321359723UL, 2901696227UL, 1652018736UL, 4035843698UL, 2666109620UL, 1564088598UL, 914173231UL, 1857869366UL, 908525903UL, 3456779008UL, 329706426UL, 1022239203UL, 2622178179UL, 4024857205UL, 4006865520UL, 1046436763UL, 366391010UL, +3722250905UL, 2880126367UL, 4102186560UL, 1642831571UL, 2222486636UL, 2572764729UL, 2046028516UL, 3507603612UL, 1703451134UL, 89818497UL, 1961701523UL, 3704300476UL, 3563143931UL, 1609575644UL, 1599081111UL, 1047838539UL, 2779312926UL, 2065354728UL, 956677756UL, 2073145924UL, 726634994UL, 119064196UL, 2046275296UL, 2105141632UL, 1023267361UL, 1204528080UL, 623740611UL, 1419328884UL, 933734693UL, 2030900835UL, 2556538268UL, 1672647866UL, +3125658368UL, 2221217376UL, 1097330641UL, 3214790630UL, 4276041578UL, 2397216525UL, 3916900004UL, 330223096UL, 3915966823UL, 2646760259UL, 1724289351UL, 4015221358UL, 2338587000UL, 110922222UL, 2314933196UL, 4026908935UL, 3272487985UL, 2685115305UL, 84271650UL, 731354215UL, 2358136447UL, 1069348214UL, 2676811333UL, 1386266810UL, 1364512901UL, 4154449904UL, 3469122709UL, 54276972UL, 560967905UL, 2363475740UL, 331250049UL, 3024074455UL, +186605617UL, 389582566UL, 1258386782UL, 703909543UL, 3968367083UL, 1553533794UL, 3699576213UL, 1145761343UL, 921983735UL, 3573813763UL, 1280477631UL, 3365842435UL, 1618458494UL, 2621328991UL, 1534006198UL, 2307669227UL, 4192335609UL, 1338050203UL, 785284052UL, 4227164890UL, 2874735332UL, 3655821191UL, 2911684671UL, 3266454200UL, 2679968625UL, 1191162601UL, 456550349UL, 1143881236UL, 3560103440UL, 2253437876UL, 3683014001UL, 1087142366UL, +1462192975UL, 1076595768UL, 3227872159UL, 1842092988UL, 148227073UL, 3812110998UL, 1317300278UL, 3068446245UL, 3376284001UL, 3164402992UL, 2730404635UL, 2848239579UL, 3008959791UL, 2901849226UL, 1234485739UL, 869158554UL, 245101118UL, 1724974650UL, 3851803199UL, 922411232UL, 3046280696UL, 3284392523UL, 3528264590UL, 2802364078UL, 381450957UL, 1741009694UL, 4222244451UL, 102929888UL, 1668474417UL, 3881791214UL, 1429483134UL, 1938365051UL, +1023690708UL, 3333855520UL, 3238705869UL, 2602245525UL, 3059586169UL, 720438965UL, 2120786297UL, 453980990UL, 1048501876UL, 4060576583UL, 3537810796UL, 3892882814UL, 691572481UL, 3899584121UL, 1582529013UL, 3260326865UL, 2358704826UL, 1607030801UL, 1035900449UL, 3442507859UL, 1406737127UL, 249758705UL, 1535363329UL, 893329207UL, 51912312UL, 3440532856UL, 3736385218UL, 295452658UL, 2379709553UL, 1647382020UL, 2363679860UL, 2998779887UL, +}, +{ +4209102573UL, 2387104994UL, 1221484586UL, 1726143957UL, 3263877318UL, 3362559187UL, 282442925UL, 2418524976UL, 3196072648UL, 3174695999UL, 2072047145UL, 2985823503UL, 2132951745UL, 2298545297UL, 2495977670UL, 1397656146UL, 2086257884UL, 3834366725UL, 3862532368UL, 3583329522UL, 1543996818UL, 2192688115UL, 3081427696UL, 2656520743UL, 8772004UL, 2476324234UL, 3600148050UL, 1168683794UL, 3219143568UL, 108768238UL, 1339513738UL, 447593731UL, +2742877256UL, 2488536667UL, 4189834432UL, 808657962UL, 2422880287UL, 390864786UL, 3381554683UL, 760628048UL, 353395922UL, 3577556262UL, 2482413928UL, 507756643UL, 839344953UL, 3505184848UL, 3945044582UL, 2414915836UL, 2313624497UL, 1832728088UL, 2036999647UL, 1369090013UL, 3264575895UL, 1096327239UL, 3483440128UL, 3999302048UL, 2761563885UL, 2882627112UL, 3126073009UL, 1749658776UL, 3152482044UL, 3040022505UL, 3249451214UL, 2933713956UL, +2861715096UL, 1314806730UL, 932941454UL, 4276317539UL, 343449784UL, 1913556027UL, 1493892363UL, 2539517630UL, 2046391233UL, 3046108187UL, 28742917UL, 4009448584UL, 530945117UL, 3165875131UL, 1018448712UL, 110256395UL, 3550192264UL, 1279873435UL, 2276349621UL, 517650895UL, 1957973772UL, 619869608UL, 4260458157UL, 2281748739UL, 2489253174UL, 2220997989UL, 3787481606UL, 508630251UL, 3761850170UL, 3992979014UL, 2298047038UL, 3506428315UL, +1279341556UL, 3293496518UL, 1313470495UL, 1021100687UL, 3113171268UL, 798494760UL, 2981622008UL, 4152623583UL, 576409629UL, 2312811213UL, 992326282UL, 261645450UL, 1818084365UL, 3357150904UL, 144093UL, 1937589359UL, 2016990596UL, 4273422066UL, 588267732UL, 3592151118UL, 3846596932UL, 1198111464UL, 944363907UL, 1288613766UL, 1707163456UL, 4020906747UL, 1161127694UL, 2303844076UL, 2632591611UL, 3877442490UL, 2453788473UL, 1725876694UL, +1193989740UL, 2650581453UL, 1937459187UL, 361099994UL, 3566745727UL, 3658112707UL, 3612317412UL, 2684702277UL, 2880928862UL, 2044313931UL, 1866044828UL, 3528429465UL, 130421713UL, 2658878825UL, 1566180833UL, 1572228417UL, 531947625UL, 3774861000UL, 1894712110UL, 1319199233UL, 865634052UL, 2602102379UL, 3389730171UL, 3878969250UL, 107983959UL, 1601930856UL, 2511728925UL, 2146946013UL, 497511195UL, 720616881UL, 699892123UL, 2404505137UL, +2656498433UL, 4209102573UL, 2387104994UL, 1221484586UL, 1726143957UL, 1267363185UL, 3362559187UL, 282442925UL, 2418524976UL, 3196072648UL, 2942944206UL, 2072047145UL, 2985823503UL, 2132951745UL, 2298545297UL, 4079341490UL, 1397656146UL, 2086257884UL, 3834366725UL, 3862532368UL, 3991197972UL, 1543996818UL, 2192688115UL, 3081427696UL, 2656520743UL, 825853576UL, 2476324234UL, 3600148050UL, 1168683794UL, 3219143568UL, 528751585UL, 1339513738UL, +447593731UL, 2742877256UL, 2488536667UL, 4025362081UL, 808657962UL, 2422880287UL, 390864786UL, 3381554683UL, 2682225618UL, 353395922UL, 3577556262UL, 2482413928UL, 507756643UL, 3979211244UL, 3505184848UL, 3945044582UL, 2414915836UL, 2313624497UL, 1841224078UL, 2036999647UL, 1369090013UL, 3264575895UL, 1096327239UL, 607843308UL, 3999302048UL, 2761563885UL, 2882627112UL, 3126073009UL, 1241524975UL, 3152482044UL, 3040022505UL, 3249451214UL, +2933713956UL, 420486142UL, 1314806730UL, 932941454UL, 4276317539UL, 343449784UL, 2231505736UL, 1493892363UL, 2539517630UL, 2046391233UL, 3046108187UL, 2351652097UL, 4009448584UL, 530945117UL, 3165875131UL, 1018448712UL, 1683392491UL, 3550192264UL, 1279873435UL, 2276349621UL, 517650895UL, 4036312766UL, 619869608UL, 4260458157UL, 2281748739UL, 2489253174UL, 1686790154UL, 3787481606UL, 508630251UL, 3761850170UL, 3992979014UL, 1745325013UL, +3506428315UL, 1279341556UL, 3293496518UL, 1313470495UL, 3066312306UL, 3113171268UL, 798494760UL, 2981622008UL, 4152623583UL, 3871822467UL, 2312811213UL, 992326282UL, 261645450UL, 1818084365UL, 3681154045UL, 144093UL, 1937589359UL, 2016990596UL, 4273422066UL, 2361898985UL, 3592151118UL, 3846596932UL, 1198111464UL, 944363907UL, 2866279694UL, 1707163456UL, 4020906747UL, 1161127694UL, 2303844076UL, 3044280908UL, 3877442490UL, 2453788473UL, +1725876694UL, 1193989740UL, 2049617934UL, 1937459187UL, 361099994UL, 3566745727UL, 3658112707UL, 934740227UL, 2684702277UL, 2880928862UL, 2044313931UL, 1866044828UL, 1814569183UL, 130421713UL, 2658878825UL, 1566180833UL, 1572228417UL, 1784679035UL, 3774861000UL, 1894712110UL, 1319199233UL, 865634052UL, 283642947UL, 3389730171UL, 3878969250UL, 107983959UL, 1601930856UL, 3698217362UL, 2146946013UL, 497511195UL, 720616881UL, 699892123UL, +2117385156UL, 2656498433UL, 4209102573UL, 2387104994UL, 1221484586UL, 3495886368UL, 1267363185UL, 3362559187UL, 282442925UL, 2418524976UL, 3489510655UL, 2942944206UL, 2072047145UL, 2985823503UL, 2132951745UL, 885541635UL, 4079341490UL, 1397656146UL, 2086257884UL, 3834366725UL, 1049969755UL, 3991197972UL, 1543996818UL, 2192688115UL, 3081427696UL, 2141948440UL, 825853576UL, 2476324234UL, 3600148050UL, 1168683794UL, 5160254UL, 528751585UL, +1339513738UL, 447593731UL, 2742877256UL, 3033397497UL, 4025362081UL, 808657962UL, 2422880287UL, 390864786UL, 3191593886UL, 2682225618UL, 353395922UL, 3577556262UL, 2482413928UL, 1185107868UL, 3979211244UL, 3505184848UL, 3945044582UL, 2414915836UL, 3030493909UL, 1841224078UL, 2036999647UL, 1369090013UL, 3264575895UL, 3054343366UL, 607843308UL, 3999302048UL, 2761563885UL, 2882627112UL, 3912854189UL, 1241524975UL, 3152482044UL, 3040022505UL, +3249451214UL, 55140065UL, 420486142UL, 1314806730UL, 932941454UL, 4276317539UL, 1055315026UL, 2231505736UL, 1493892363UL, 2539517630UL, 2046391233UL, 4174985470UL, 2351652097UL, 4009448584UL, 530945117UL, 3165875131UL, 2168411768UL, 1683392491UL, 3550192264UL, 1279873435UL, 2276349621UL, 1875092822UL, 4036312766UL, 619869608UL, 4260458157UL, 2281748739UL, 98823023UL, 1686790154UL, 3787481606UL, 508630251UL, 3761850170UL, 2636025017UL, +1745325013UL, 3506428315UL, 1279341556UL, 3293496518UL, 978338993UL, 3066312306UL, 3113171268UL, 798494760UL, 2981622008UL, 2712384846UL, 3871822467UL, 2312811213UL, 992326282UL, 261645450UL, 66982935UL, 3681154045UL, 144093UL, 1937589359UL, 2016990596UL, 3390191329UL, 2361898985UL, 3592151118UL, 3846596932UL, 1198111464UL, 1857959320UL, 2866279694UL, 1707163456UL, 4020906747UL, 1161127694UL, 913091437UL, 3044280908UL, 3877442490UL, +2453788473UL, 1725876694UL, 4254455215UL, 2049617934UL, 1937459187UL, 361099994UL, 3566745727UL, 2914687409UL, 934740227UL, 2684702277UL, 2880928862UL, 2044313931UL, 1515195925UL, 1814569183UL, 130421713UL, 2658878825UL, 1566180833UL, 2753417020UL, 1784679035UL, 3774861000UL, 1894712110UL, 1319199233UL, 287161774UL, 283642947UL, 3389730171UL, 3878969250UL, 107983959UL, 3057929912UL, 3698217362UL, 2146946013UL, 497511195UL, 720616881UL, +3570251850UL, 2117385156UL, 2656498433UL, 4209102573UL, 2387104994UL, 2940868252UL, 3495886368UL, 1267363185UL, 3362559187UL, 282442925UL, 2510419746UL, 3489510655UL, 2942944206UL, 2072047145UL, 2985823503UL, 978430777UL, 885541635UL, 4079341490UL, 1397656146UL, 2086257884UL, 134380865UL, 1049969755UL, 3991197972UL, 1543996818UL, 2192688115UL, 1205081471UL, 2141948440UL, 825853576UL, 2476324234UL, 3600148050UL, 228461601UL, 5160254UL, +528751585UL, 1339513738UL, 447593731UL, 2852356745UL, 3033397497UL, 4025362081UL, 808657962UL, 2422880287UL, 3287655095UL, 3191593886UL, 2682225618UL, 353395922UL, 3577556262UL, 2542841784UL, 1185107868UL, 3979211244UL, 3505184848UL, 3945044582UL, 2905156498UL, 3030493909UL, 1841224078UL, 2036999647UL, 1369090013UL, 4246605417UL, 3054343366UL, 607843308UL, 3999302048UL, 2761563885UL, 3611911899UL, 3912854189UL, 1241524975UL, 3152482044UL, +3040022505UL, 3215633820UL, 55140065UL, 420486142UL, 1314806730UL, 932941454UL, 2708752494UL, 1055315026UL, 2231505736UL, 1493892363UL, 2539517630UL, 962728637UL, 4174985470UL, 2351652097UL, 4009448584UL, 530945117UL, 3370859357UL, 2168411768UL, 1683392491UL, 3550192264UL, 1279873435UL, 3028448904UL, 1875092822UL, 4036312766UL, 619869608UL, 4260458157UL, 199178828UL, 98823023UL, 1686790154UL, 3787481606UL, 508630251UL, 4205010983UL, +2636025017UL, 1745325013UL, 3506428315UL, 1279341556UL, 683127445UL, 978338993UL, 3066312306UL, 3113171268UL, 798494760UL, 2823693013UL, 2712384846UL, 3871822467UL, 2312811213UL, 992326282UL, 3701928286UL, 66982935UL, 3681154045UL, 144093UL, 1937589359UL, 1117717039UL, 3390191329UL, 2361898985UL, 3592151118UL, 3846596932UL, 1072660054UL, 1857959320UL, 2866279694UL, 1707163456UL, 4020906747UL, 2503116219UL, 913091437UL, 3044280908UL, +3877442490UL, 2453788473UL, 1815274499UL, 4254455215UL, 2049617934UL, 1937459187UL, 361099994UL, 3771108073UL, 2914687409UL, 934740227UL, 2684702277UL, 2880928862UL, 3591322975UL, 1515195925UL, 1814569183UL, 130421713UL, 2658878825UL, 354587729UL, 2753417020UL, 1784679035UL, 3774861000UL, 1894712110UL, 1799044969UL, 287161774UL, 283642947UL, 3389730171UL, 3878969250UL, 1229815186UL, 3057929912UL, 3698217362UL, 2146946013UL, 497511195UL, +3121882901UL, 426537369UL, 3852284416UL, 4050544256UL, 3148944089UL, 878474231UL, 1369575859UL, 2206199765UL, 870626886UL, 494668165UL, 613011290UL, 3246772867UL, 1040178461UL, 2396959353UL, 2105449571UL, 456758967UL, 4134137960UL, 3525051481UL, 3633445497UL, 2895048060UL, 2008411846UL, 2194012253UL, 2326112129UL, 2956901044UL, 2297039362UL, 3400824024UL, 42139718UL, 4212208866UL, 3874761488UL, 2361955811UL, 1890446075UL, 864533345UL, +474524842UL, 2283847731UL, 283971243UL, 3607219686UL, 280870706UL, 4188549522UL, 659660119UL, 2460943922UL, 4252134362UL, 922033031UL, 3615474721UL, 1691563300UL, 3002653770UL, 2414043617UL, 2251931324UL, 752654714UL, 4188343161UL, 305594960UL, 1320443323UL, 797027061UL, 2347530104UL, 3608843538UL, 2717312892UL, 1841295453UL, 1574467161UL, 823626340UL, 2244853583UL, 2648217758UL, 141742826UL, 1605436472UL, 745763543UL, 3275460028UL, +3166960370UL, 2655678693UL, 3964037210UL, 945054703UL, 998173049UL, 1014527437UL, 3424443612UL, 281835352UL, 826817508UL, 260462513UL, 2849967970UL, 3447294061UL, 3670173947UL, 2430650055UL, 4134905457UL, 3798172627UL, 2156572681UL, 2600148034UL, 2773013892UL, 3290397106UL, 1740507705UL, 3450254627UL, 3613087060UL, 440045928UL, 1230555006UL, 980805434UL, 2107958250UL, 526555374UL, 3150741277UL, 4283672024UL, 193019043UL, 786035243UL, +3002832578UL, 3938336183UL, 4209865002UL, 1005950967UL, 3533346582UL, 3196886974UL, 83962845UL, 1882902787UL, 3595687446UL, 2927597311UL, 2728550762UL, 2750900392UL, 1474254316UL, 1509832112UL, 1763262792UL, 2706181276UL, 538294991UL, 353565565UL, 18133995UL, 1719731406UL, 3311085516UL, 2018821960UL, 300367686UL, 2628312935UL, 1151449661UL, 2178805970UL, 3288321196UL, 535051857UL, 1623270973UL, 2761151808UL, 2701048972UL, 317681607UL, +2281427601UL, 719748170UL, 351452298UL, 2191958596UL, 4000232015UL, 335837771UL, 4158081521UL, 3779404077UL, 1998444133UL, 3849605095UL, 1532231791UL, 2930266419UL, 4203951289UL, 748423654UL, 1993082867UL, 451159852UL, 488781053UL, 2438982775UL, 2222815270UL, 543209242UL, 1241562465UL, 2868868009UL, 4201052877UL, 2438841764UL, 2151708682UL, 2426958921UL, 1520654642UL, 1990098337UL, 1070792755UL, 2308394635UL, 1442389785UL, 705615044UL, +}, +{ +973368008UL, 1221885324UL, 2086331970UL, 2323744198UL, 280145759UL, 1795442656UL, 2984366093UL, 3532172763UL, 323888669UL, 851950179UL, 4198638255UL, 899943985UL, 4087912561UL, 2935341503UL, 1443752852UL, 3991058999UL, 3547259355UL, 35779889UL, 1076308344UL, 4075444807UL, 186174448UL, 3542284780UL, 660388677UL, 2777400132UL, 1092226205UL, 2418702276UL, 1307933032UL, 1940510003UL, 1932005362UL, 4016036211UL, 387339882UL, 2969593895UL, +3453134349UL, 1382709098UL, 1795814140UL, 1588159469UL, 1216733801UL, 2227378121UL, 2063027627UL, 582454582UL, 3364657275UL, 3466973302UL, 484564303UL, 1489261596UL, 2270291560UL, 2008178784UL, 2284268924UL, 2229317366UL, 644797709UL, 1213921542UL, 99331403UL, 3027640949UL, 1137722852UL, 2991506109UL, 1432805987UL, 931795812UL, 1075567424UL, 28963219UL, 1462245461UL, 3781444706UL, 521233400UL, 1891915904UL, 3774338085UL, 1635359313UL, +2356111795UL, 4121073768UL, 1045110727UL, 2822507066UL, 1087914587UL, 3744509525UL, 911370656UL, 181884066UL, 1944539735UL, 290356444UL, 3598887471UL, 4236934380UL, 3224468239UL, 457546246UL, 4119337570UL, 37700432UL, 655783844UL, 1423101410UL, 1693002969UL, 3287768267UL, 928748421UL, 4074128009UL, 3081088543UL, 2882833790UL, 3180154875UL, 1094657682UL, 2388253717UL, 4173455215UL, 794709427UL, 3363292346UL, 67786868UL, 3786597763UL, +380587236UL, 2345941620UL, 560232318UL, 2137123833UL, 619747082UL, 1050293267UL, 2537845069UL, 1407302835UL, 433399526UL, 1083185007UL, 1893842085UL, 3711748584UL, 4225838280UL, 3863317129UL, 2043467942UL, 2799650657UL, 3590486611UL, 1231938950UL, 215905995UL, 155811669UL, 806806587UL, 2732631168UL, 1621659281UL, 632403616UL, 401165422UL, 2661074778UL, 4156963191UL, 3691812937UL, 3767271627UL, 2834948318UL, 2877210497UL, 2420260153UL, +733172233UL, 1771708940UL, 3102718549UL, 2468707423UL, 1857088312UL, 3176535032UL, 1908570295UL, 3966666208UL, 605079895UL, 2982506620UL, 3721694730UL, 1640691570UL, 3764975545UL, 3257514114UL, 1826578604UL, 1358557411UL, 4049610348UL, 615820785UL, 3355718142UL, 1734641780UL, 2958744617UL, 274522187UL, 3198436002UL, 4077346785UL, 2890101344UL, 4012464346UL, 1288365365UL, 96583076UL, 2656389382UL, 1858181040UL, 2717010340UL, 2032153178UL, +349324012UL, 973368008UL, 1221885324UL, 2086331970UL, 2323744198UL, 253685576UL, 1795442656UL, 2984366093UL, 3532172763UL, 323888669UL, 248935329UL, 4198638255UL, 899943985UL, 4087912561UL, 2935341503UL, 3213394756UL, 3991058999UL, 3547259355UL, 35779889UL, 1076308344UL, 1987715385UL, 186174448UL, 3542284780UL, 660388677UL, 2777400132UL, 2071022105UL, 2418702276UL, 1307933032UL, 1940510003UL, 1932005362UL, 144370664UL, 387339882UL, +2969593895UL, 3453134349UL, 1382709098UL, 2394736611UL, 1588159469UL, 1216733801UL, 2227378121UL, 2063027627UL, 4064263898UL, 3364657275UL, 3466973302UL, 484564303UL, 1489261596UL, 3405101812UL, 2008178784UL, 2284268924UL, 2229317366UL, 644797709UL, 2560273821UL, 99331403UL, 3027640949UL, 1137722852UL, 2991506109UL, 1446442417UL, 931795812UL, 1075567424UL, 28963219UL, 1462245461UL, 1201513613UL, 521233400UL, 1891915904UL, 3774338085UL, +1635359313UL, 2815447944UL, 4121073768UL, 1045110727UL, 2822507066UL, 1087914587UL, 2485035329UL, 911370656UL, 181884066UL, 1944539735UL, 290356444UL, 2078819341UL, 4236934380UL, 3224468239UL, 457546246UL, 4119337570UL, 2666895496UL, 655783844UL, 1423101410UL, 1693002969UL, 3287768267UL, 3595439673UL, 4074128009UL, 3081088543UL, 2882833790UL, 3180154875UL, 872453917UL, 2388253717UL, 4173455215UL, 794709427UL, 3363292346UL, 4188764388UL, +3786597763UL, 380587236UL, 2345941620UL, 560232318UL, 625538006UL, 619747082UL, 1050293267UL, 2537845069UL, 1407302835UL, 2128289331UL, 1083185007UL, 1893842085UL, 3711748584UL, 4225838280UL, 2486133065UL, 2043467942UL, 2799650657UL, 3590486611UL, 1231938950UL, 928582681UL, 155811669UL, 806806587UL, 2732631168UL, 1621659281UL, 1163969880UL, 401165422UL, 2661074778UL, 4156963191UL, 3691812937UL, 2322579561UL, 2834948318UL, 2877210497UL, +2420260153UL, 733172233UL, 170239236UL, 3102718549UL, 2468707423UL, 1857088312UL, 3176535032UL, 3868693408UL, 3966666208UL, 605079895UL, 2982506620UL, 3721694730UL, 2066859537UL, 3764975545UL, 3257514114UL, 1826578604UL, 1358557411UL, 2964604045UL, 615820785UL, 3355718142UL, 1734641780UL, 2958744617UL, 4091225681UL, 3198436002UL, 4077346785UL, 2890101344UL, 4012464346UL, 2612861218UL, 96583076UL, 2656389382UL, 1858181040UL, 2717010340UL, +3639170895UL, 349324012UL, 973368008UL, 1221885324UL, 2086331970UL, 2258432445UL, 253685576UL, 1795442656UL, 2984366093UL, 3532172763UL, 3831166882UL, 248935329UL, 4198638255UL, 899943985UL, 4087912561UL, 715173523UL, 3213394756UL, 3991058999UL, 3547259355UL, 35779889UL, 2393072396UL, 1987715385UL, 186174448UL, 3542284780UL, 660388677UL, 3731857267UL, 2071022105UL, 2418702276UL, 1307933032UL, 1940510003UL, 4262274779UL, 144370664UL, +387339882UL, 2969593895UL, 3453134349UL, 1923698215UL, 2394736611UL, 1588159469UL, 1216733801UL, 2227378121UL, 2907069566UL, 4064263898UL, 3364657275UL, 3466973302UL, 484564303UL, 2234542580UL, 3405101812UL, 2008178784UL, 2284268924UL, 2229317366UL, 1349323372UL, 2560273821UL, 99331403UL, 3027640949UL, 1137722852UL, 4200786664UL, 1446442417UL, 931795812UL, 1075567424UL, 28963219UL, 1659632304UL, 1201513613UL, 521233400UL, 1891915904UL, +3774338085UL, 763590809UL, 2815447944UL, 4121073768UL, 1045110727UL, 2822507066UL, 4131040734UL, 2485035329UL, 911370656UL, 181884066UL, 1944539735UL, 4104473807UL, 2078819341UL, 4236934380UL, 3224468239UL, 457546246UL, 1241850776UL, 2666895496UL, 655783844UL, 1423101410UL, 1693002969UL, 2025898966UL, 3595439673UL, 4074128009UL, 3081088543UL, 2882833790UL, 218474476UL, 872453917UL, 2388253717UL, 4173455215UL, 794709427UL, 250328312UL, +4188764388UL, 3786597763UL, 380587236UL, 2345941620UL, 1937652040UL, 625538006UL, 619747082UL, 1050293267UL, 2537845069UL, 1140055765UL, 2128289331UL, 1083185007UL, 1893842085UL, 3711748584UL, 2298055548UL, 2486133065UL, 2043467942UL, 2799650657UL, 3590486611UL, 1235949580UL, 928582681UL, 155811669UL, 806806587UL, 2732631168UL, 4046198728UL, 1163969880UL, 401165422UL, 2661074778UL, 4156963191UL, 2003518762UL, 2322579561UL, 2834948318UL, +2877210497UL, 2420260153UL, 326741418UL, 170239236UL, 3102718549UL, 2468707423UL, 1857088312UL, 3936056808UL, 3868693408UL, 3966666208UL, 605079895UL, 2982506620UL, 2354705582UL, 2066859537UL, 3764975545UL, 3257514114UL, 1826578604UL, 3017501686UL, 2964604045UL, 615820785UL, 3355718142UL, 1734641780UL, 1681548103UL, 4091225681UL, 3198436002UL, 4077346785UL, 2890101344UL, 416470693UL, 2612861218UL, 96583076UL, 2656389382UL, 1858181040UL, +3104217288UL, 3639170895UL, 349324012UL, 973368008UL, 1221885324UL, 601524567UL, 2258432445UL, 253685576UL, 1795442656UL, 2984366093UL, 1875491903UL, 3831166882UL, 248935329UL, 4198638255UL, 899943985UL, 2182697927UL, 715173523UL, 3213394756UL, 3991058999UL, 3547259355UL, 1472237612UL, 2393072396UL, 1987715385UL, 186174448UL, 3542284780UL, 2160848139UL, 3731857267UL, 2071022105UL, 2418702276UL, 1307933032UL, 3815354311UL, 4262274779UL, +144370664UL, 387339882UL, 2969593895UL, 4240850623UL, 1923698215UL, 2394736611UL, 1588159469UL, 1216733801UL, 322523795UL, 2907069566UL, 4064263898UL, 3364657275UL, 3466973302UL, 2920715858UL, 2234542580UL, 3405101812UL, 2008178784UL, 2284268924UL, 1936025139UL, 1349323372UL, 2560273821UL, 99331403UL, 3027640949UL, 859541953UL, 4200786664UL, 1446442417UL, 931795812UL, 1075567424UL, 1876635772UL, 1659632304UL, 1201513613UL, 521233400UL, +1891915904UL, 3949233865UL, 763590809UL, 2815447944UL, 4121073768UL, 1045110727UL, 2522258582UL, 4131040734UL, 2485035329UL, 911370656UL, 181884066UL, 2467886009UL, 4104473807UL, 2078819341UL, 4236934380UL, 3224468239UL, 603014155UL, 1241850776UL, 2666895496UL, 655783844UL, 1423101410UL, 673119756UL, 2025898966UL, 3595439673UL, 4074128009UL, 3081088543UL, 4100445818UL, 218474476UL, 872453917UL, 2388253717UL, 4173455215UL, 2395519424UL, +250328312UL, 4188764388UL, 3786597763UL, 380587236UL, 4292608797UL, 1937652040UL, 625538006UL, 619747082UL, 1050293267UL, 2989616803UL, 1140055765UL, 2128289331UL, 1083185007UL, 1893842085UL, 3313934002UL, 2298055548UL, 2486133065UL, 2043467942UL, 2799650657UL, 1804808801UL, 1235949580UL, 928582681UL, 155811669UL, 806806587UL, 2864892828UL, 4046198728UL, 1163969880UL, 401165422UL, 2661074778UL, 2946769376UL, 2003518762UL, 2322579561UL, +2834948318UL, 2877210497UL, 2647485275UL, 326741418UL, 170239236UL, 3102718549UL, 2468707423UL, 2520336801UL, 3936056808UL, 3868693408UL, 3966666208UL, 605079895UL, 2949706551UL, 2354705582UL, 2066859537UL, 3764975545UL, 3257514114UL, 495003693UL, 3017501686UL, 2964604045UL, 615820785UL, 3355718142UL, 3799230297UL, 1681548103UL, 4091225681UL, 3198436002UL, 4077346785UL, 258363842UL, 416470693UL, 2612861218UL, 96583076UL, 2656389382UL, +2198085634UL, 1607235362UL, 694172175UL, 4194347563UL, 2665732891UL, 3419430286UL, 597070176UL, 2749480905UL, 3937535348UL, 3639873850UL, 2050067843UL, 4045290683UL, 2964298196UL, 3631595287UL, 1409808193UL, 121765438UL, 2129412744UL, 2497437101UL, 2664102876UL, 1773441464UL, 1708052456UL, 2923764322UL, 3350385352UL, 1592204280UL, 1118221370UL, 3416016313UL, 116121364UL, 1179473397UL, 1497519022UL, 902569114UL, 3840281863UL, 2783662797UL, +1712084322UL, 1982884601UL, 3625797892UL, 4222938993UL, 3231134134UL, 3046745397UL, 446484563UL, 1133869192UL, 2622178726UL, 3881085862UL, 4012894217UL, 391734322UL, 2089696890UL, 1304197030UL, 2663978386UL, 1685998658UL, 4238620912UL, 448351665UL, 2724524045UL, 1038754164UL, 413586547UL, 3107681687UL, 1454664365UL, 3353731192UL, 128440996UL, 565817989UL, 127978294UL, 1043863326UL, 1747369107UL, 2772246481UL, 172569313UL, 2740699699UL, +3417082503UL, 2103702630UL, 2139566116UL, 1378864710UL, 2444170529UL, 3234220221UL, 3974870858UL, 1965162347UL, 956763257UL, 3932467825UL, 1077337271UL, 4084837149UL, 3699147465UL, 1882164226UL, 236113740UL, 3116302858UL, 2730529598UL, 3449804672UL, 4002370655UL, 2011573068UL, 1551746089UL, 3917496971UL, 2852603UL, 1682999535UL, 2764817908UL, 2489487254UL, 261936311UL, 3122421452UL, 1199382345UL, 2617247590UL, 1909026938UL, 3156073069UL, +1492533764UL, 97847107UL, 1260892586UL, 187242945UL, 1286471861UL, 1763024967UL, 127723419UL, 210606273UL, 228546401UL, 3249879676UL, 482069954UL, 383075106UL, 3263105259UL, 2242748676UL, 1105681409UL, 4033144425UL, 4017983282UL, 1670425353UL, 4040882785UL, 1780687273UL, 1405678015UL, 3076115981UL, 2713472488UL, 286336494UL, 3664225263UL, 502759060UL, 777620620UL, 635590826UL, 132236203UL, 1866406173UL, 1235046453UL, 2859554298UL, +121814656UL, 944976320UL, 1946494170UL, 2548097575UL, 415384946UL, 3934685646UL, 1507032178UL, 1383654007UL, 2906269630UL, 566005756UL, 3118733139UL, 2969075870UL, 1834096359UL, 3263358416UL, 1322979710UL, 904583023UL, 3582075094UL, 2298898632UL, 2491891941UL, 660351763UL, 2548592542UL, 3009200751UL, 2116595110UL, 2623212287UL, 4167133624UL, 196759529UL, 3038645579UL, 1769704552UL, 1713233322UL, 2127497999UL, 3849458221UL, 3769872265UL, +}, +{ +51082211UL, 3347503176UL, 3221768777UL, 2986163981UL, 3937460013UL, 1716372908UL, 4132024211UL, 3035957293UL, 1791036224UL, 4214815056UL, 1645540011UL, 2629793790UL, 3185505897UL, 1855718954UL, 495459467UL, 1728339314UL, 2318396341UL, 3396602050UL, 3273624616UL, 2625973148UL, 1762905939UL, 1706358553UL, 1088424264UL, 2764318930UL, 1026127380UL, 1128004134UL, 2724553694UL, 41981087UL, 2304966004UL, 1342745986UL, 3425554050UL, 3537673465UL, +752263676UL, 280905885UL, 929399589UL, 4090689526UL, 2141254732UL, 1469491656UL, 2593100469UL, 1096008340UL, 3316809312UL, 1698245188UL, 1656427920UL, 3081873338UL, 1750515301UL, 3850483440UL, 4081834419UL, 1225164947UL, 1244139942UL, 1972663124UL, 116832506UL, 3097397897UL, 961156503UL, 1899056660UL, 1659173175UL, 1890464921UL, 1891872926UL, 191259956UL, 1735304734UL, 4246751855UL, 4285601625UL, 1495519933UL, 3398829761UL, 997567482UL, +2277782972UL, 1286922996UL, 3120709698UL, 15569196UL, 191501283UL, 3916619528UL, 1552075789UL, 4259725643UL, 2837166910UL, 2231584792UL, 1912204495UL, 2597304083UL, 4147585653UL, 1021482843UL, 2003417305UL, 186794491UL, 3608172979UL, 1991038123UL, 97515853UL, 34341352UL, 4163491231UL, 1046079304UL, 4105813389UL, 3589099183UL, 3970004064UL, 3899560802UL, 4148331147UL, 2267137817UL, 85024486UL, 3019925981UL, 3069231953UL, 1563669137UL, +314080592UL, 2943111861UL, 2838243982UL, 726216848UL, 2621853102UL, 2355885175UL, 3359668856UL, 1111296541UL, 2330283124UL, 3626558972UL, 4290084148UL, 1632078UL, 1047440803UL, 1350377197UL, 2490578842UL, 2366345698UL, 1628128899UL, 860259543UL, 1937956234UL, 2833820527UL, 329818923UL, 648489148UL, 1791961202UL, 1652322723UL, 1513419073UL, 149629345UL, 2468961221UL, 3711837973UL, 2377333831UL, 1434755773UL, 3808719305UL, 2513270108UL, +2701064683UL, 3097011724UL, 303393137UL, 1346302239UL, 1852307302UL, 850106025UL, 2473124483UL, 2853497268UL, 3786573704UL, 2604101162UL, 1446573486UL, 506925220UL, 3138967488UL, 2973528682UL, 2752811123UL, 2890321579UL, 1037196362UL, 1335670403UL, 1560253777UL, 1437495434UL, 2700525242UL, 4259933972UL, 3870707795UL, 4141538580UL, 3375331039UL, 3081538601UL, 3129978494UL, 3689191993UL, 1933431212UL, 2196145886UL, 87814045UL, 878611347UL, +812542698UL, 51082211UL, 3347503176UL, 3221768777UL, 2986163981UL, 277257023UL, 1716372908UL, 4132024211UL, 3035957293UL, 1791036224UL, 2713916211UL, 1645540011UL, 2629793790UL, 3185505897UL, 1855718954UL, 3800150234UL, 1728339314UL, 2318396341UL, 3396602050UL, 3273624616UL, 2530282967UL, 1762905939UL, 1706358553UL, 1088424264UL, 2764318930UL, 4224669506UL, 1128004134UL, 2724553694UL, 41981087UL, 2304966004UL, 484289311UL, 3425554050UL, +3537673465UL, 752263676UL, 280905885UL, 657028134UL, 4090689526UL, 2141254732UL, 1469491656UL, 2593100469UL, 2089385540UL, 3316809312UL, 1698245188UL, 1656427920UL, 3081873338UL, 2750354264UL, 3850483440UL, 4081834419UL, 1225164947UL, 1244139942UL, 3432605739UL, 116832506UL, 3097397897UL, 961156503UL, 1899056660UL, 2234120716UL, 1890464921UL, 1891872926UL, 191259956UL, 1735304734UL, 125359575UL, 4285601625UL, 1495519933UL, 3398829761UL, +997567482UL, 4034254942UL, 1286922996UL, 3120709698UL, 15569196UL, 191501283UL, 2090684174UL, 1552075789UL, 4259725643UL, 2837166910UL, 2231584792UL, 3412758413UL, 2597304083UL, 4147585653UL, 1021482843UL, 2003417305UL, 2464533361UL, 3608172979UL, 1991038123UL, 97515853UL, 34341352UL, 2634732952UL, 1046079304UL, 4105813389UL, 3589099183UL, 3970004064UL, 4263828421UL, 4148331147UL, 2267137817UL, 85024486UL, 3019925981UL, 3229477751UL, +1563669137UL, 314080592UL, 2943111861UL, 2838243982UL, 1274664774UL, 2621853102UL, 2355885175UL, 3359668856UL, 1111296541UL, 1615234696UL, 3626558972UL, 4290084148UL, 1632078UL, 1047440803UL, 623898652UL, 2490578842UL, 2366345698UL, 1628128899UL, 860259543UL, 2097114662UL, 2833820527UL, 329818923UL, 648489148UL, 1791961202UL, 1730000077UL, 1513419073UL, 149629345UL, 2468961221UL, 3711837973UL, 3255238414UL, 1434755773UL, 3808719305UL, +2513270108UL, 2701064683UL, 1635042488UL, 303393137UL, 1346302239UL, 1852307302UL, 850106025UL, 3523245944UL, 2853497268UL, 3786573704UL, 2604101162UL, 1446573486UL, 1011238489UL, 3138967488UL, 2973528682UL, 2752811123UL, 2890321579UL, 1044586909UL, 1335670403UL, 1560253777UL, 1437495434UL, 2700525242UL, 608940900UL, 3870707795UL, 4141538580UL, 3375331039UL, 3081538601UL, 728626935UL, 3689191993UL, 1933431212UL, 2196145886UL, 87814045UL, +646732047UL, 812542698UL, 51082211UL, 3347503176UL, 3221768777UL, 1783601443UL, 277257023UL, 1716372908UL, 4132024211UL, 3035957293UL, 3363442238UL, 2713916211UL, 1645540011UL, 2629793790UL, 3185505897UL, 2066587565UL, 3800150234UL, 1728339314UL, 2318396341UL, 3396602050UL, 2279941522UL, 2530282967UL, 1762905939UL, 1706358553UL, 1088424264UL, 2989326347UL, 4224669506UL, 1128004134UL, 2724553694UL, 41981087UL, 2348931916UL, 484289311UL, +3425554050UL, 3537673465UL, 752263676UL, 3169550883UL, 657028134UL, 4090689526UL, 2141254732UL, 1469491656UL, 1152943917UL, 2089385540UL, 3316809312UL, 1698245188UL, 1656427920UL, 1808689833UL, 2750354264UL, 3850483440UL, 4081834419UL, 1225164947UL, 2422106046UL, 3432605739UL, 116832506UL, 3097397897UL, 961156503UL, 1581804167UL, 2234120716UL, 1890464921UL, 1891872926UL, 191259956UL, 4113708001UL, 125359575UL, 4285601625UL, 1495519933UL, +3398829761UL, 3473435310UL, 4034254942UL, 1286922996UL, 3120709698UL, 15569196UL, 3122200488UL, 2090684174UL, 1552075789UL, 4259725643UL, 2837166910UL, 2838170407UL, 3412758413UL, 2597304083UL, 4147585653UL, 1021482843UL, 954000150UL, 2464533361UL, 3608172979UL, 1991038123UL, 97515853UL, 3832321348UL, 2634732952UL, 1046079304UL, 4105813389UL, 3589099183UL, 1288675572UL, 4263828421UL, 4148331147UL, 2267137817UL, 85024486UL, 1080403742UL, +3229477751UL, 1563669137UL, 314080592UL, 2943111861UL, 3357655593UL, 1274664774UL, 2621853102UL, 2355885175UL, 3359668856UL, 3722440291UL, 1615234696UL, 3626558972UL, 4290084148UL, 1632078UL, 4263556325UL, 623898652UL, 2490578842UL, 2366345698UL, 1628128899UL, 3623136669UL, 2097114662UL, 2833820527UL, 329818923UL, 648489148UL, 592747007UL, 1730000077UL, 1513419073UL, 149629345UL, 2468961221UL, 3766709284UL, 3255238414UL, 1434755773UL, +3808719305UL, 2513270108UL, 1958651003UL, 1635042488UL, 303393137UL, 1346302239UL, 1852307302UL, 579487408UL, 3523245944UL, 2853497268UL, 3786573704UL, 2604101162UL, 4183724981UL, 1011238489UL, 3138967488UL, 2973528682UL, 2752811123UL, 3074709397UL, 1044586909UL, 1335670403UL, 1560253777UL, 1437495434UL, 1237099522UL, 608940900UL, 3870707795UL, 4141538580UL, 3375331039UL, 2032507604UL, 728626935UL, 3689191993UL, 1933431212UL, 2196145886UL, +4008131891UL, 646732047UL, 812542698UL, 51082211UL, 3347503176UL, 3622107037UL, 1783601443UL, 277257023UL, 1716372908UL, 4132024211UL, 1264285659UL, 3363442238UL, 2713916211UL, 1645540011UL, 2629793790UL, 2179309595UL, 2066587565UL, 3800150234UL, 1728339314UL, 2318396341UL, 580990822UL, 2279941522UL, 2530282967UL, 1762905939UL, 1706358553UL, 2826056883UL, 2989326347UL, 4224669506UL, 1128004134UL, 2724553694UL, 1486392636UL, 2348931916UL, +484289311UL, 3425554050UL, 3537673465UL, 2497657189UL, 3169550883UL, 657028134UL, 4090689526UL, 2141254732UL, 1019244016UL, 1152943917UL, 2089385540UL, 3316809312UL, 1698245188UL, 2921739456UL, 1808689833UL, 2750354264UL, 3850483440UL, 4081834419UL, 108425527UL, 2422106046UL, 3432605739UL, 116832506UL, 3097397897UL, 3902994002UL, 1581804167UL, 2234120716UL, 1890464921UL, 1891872926UL, 3428861050UL, 4113708001UL, 125359575UL, 4285601625UL, +1495519933UL, 3350053832UL, 3473435310UL, 4034254942UL, 1286922996UL, 3120709698UL, 2906201347UL, 3122200488UL, 2090684174UL, 1552075789UL, 4259725643UL, 1965598685UL, 2838170407UL, 3412758413UL, 2597304083UL, 4147585653UL, 3335631208UL, 954000150UL, 2464533361UL, 3608172979UL, 1991038123UL, 3788034599UL, 3832321348UL, 2634732952UL, 1046079304UL, 4105813389UL, 2362460804UL, 1288675572UL, 4263828421UL, 4148331147UL, 2267137817UL, 2767331798UL, +1080403742UL, 3229477751UL, 1563669137UL, 314080592UL, 1737897403UL, 3357655593UL, 1274664774UL, 2621853102UL, 2355885175UL, 57997639UL, 3722440291UL, 1615234696UL, 3626558972UL, 4290084148UL, 3703113369UL, 4263556325UL, 623898652UL, 2490578842UL, 2366345698UL, 73788443UL, 3623136669UL, 2097114662UL, 2833820527UL, 329818923UL, 253042650UL, 592747007UL, 1730000077UL, 1513419073UL, 149629345UL, 4248302934UL, 3766709284UL, 3255238414UL, +1434755773UL, 3808719305UL, 3698431827UL, 1958651003UL, 1635042488UL, 303393137UL, 1346302239UL, 3872433842UL, 579487408UL, 3523245944UL, 2853497268UL, 3786573704UL, 3459185849UL, 4183724981UL, 1011238489UL, 3138967488UL, 2973528682UL, 2605373899UL, 3074709397UL, 1044586909UL, 1335670403UL, 1560253777UL, 4069724875UL, 1237099522UL, 608940900UL, 3870707795UL, 4141538580UL, 2550307954UL, 2032507604UL, 728626935UL, 3689191993UL, 1933431212UL, +1177640824UL, 4168589688UL, 1361487780UL, 2649612520UL, 2181448948UL, 2176288560UL, 947907377UL, 3772487849UL, 2002599877UL, 3353450532UL, 2013145251UL, 2357912348UL, 2316997609UL, 2355480213UL, 255142205UL, 751273749UL, 4049362748UL, 1434168014UL, 2069693747UL, 6910933UL, 1352778547UL, 2413649875UL, 4238683558UL, 484497407UL, 522555106UL, 1848417180UL, 3001805499UL, 2264939603UL, 3606143565UL, 1782482647UL, 2955918436UL, 3471474379UL, +2814133839UL, 3779337475UL, 3522102195UL, 1551792178UL, 3742001759UL, 3433504551UL, 472918932UL, 3835854229UL, 4259163014UL, 4103952359UL, 1989474190UL, 1792448078UL, 1517735224UL, 1958036884UL, 2277922531UL, 2856192348UL, 4294188732UL, 2674247971UL, 643649427UL, 3847742408UL, 1512435795UL, 4236693554UL, 1749045838UL, 397093640UL, 2940663643UL, 4156440725UL, 188785143UL, 3894740830UL, 897618321UL, 3333498692UL, 1623924612UL, 4111607062UL, +2242558573UL, 1565861815UL, 1177957654UL, 4129621176UL, 2232443247UL, 3216995984UL, 3313294700UL, 791442469UL, 1782204490UL, 2452634246UL, 1288014576UL, 1347365377UL, 112254281UL, 2044140398UL, 2479591984UL, 3293701920UL, 1062335151UL, 1397230369UL, 2460086085UL, 2412349474UL, 1252633202UL, 3704541545UL, 2132499200UL, 2202058121UL, 1981543691UL, 2683673516UL, 1198109770UL, 4279157703UL, 2224504258UL, 2188868731UL, 769314834UL, 601313429UL, +3595357440UL, 561383123UL, 3444949507UL, 2127327734UL, 2865252582UL, 4181002098UL, 2408426518UL, 309361635UL, 2377703815UL, 1109219406UL, 406287309UL, 1750179098UL, 3619129839UL, 937928728UL, 884423945UL, 928407281UL, 4173634172UL, 1492070114UL, 2706943441UL, 1365883971UL, 3076484301UL, 744370087UL, 4004118884UL, 2199449568UL, 879458863UL, 3197725005UL, 3590586547UL, 59693002UL, 3614114662UL, 1499386564UL, 2914582708UL, 3751842429UL, +947438603UL, 1986129491UL, 3747112289UL, 833777768UL, 2231649410UL, 1841607849UL, 3526253103UL, 3797105813UL, 1291185911UL, 3188408549UL, 3311027691UL, 3983681758UL, 2246511800UL, 1271525377UL, 2996265908UL, 2396071405UL, 902427181UL, 164636454UL, 2459631341UL, 635349368UL, 463309029UL, 1409367654UL, 849052250UL, 3221786769UL, 2310288531UL, 2919204855UL, 1263130532UL, 1215722704UL, 3497322658UL, 2840687222UL, 2185004161UL, 1507335864UL, +}, +{ +2052557448UL, 2879065999UL, 22933757UL, 2160014758UL, 3736092460UL, 3556641619UL, 1350613766UL, 2107757927UL, 309323868UL, 3452852627UL, 3424626316UL, 545651740UL, 1935764720UL, 2349926457UL, 3546577033UL, 862046434UL, 167198649UL, 338290297UL, 1145807303UL, 1571276102UL, 883549156UL, 907871968UL, 638566313UL, 678764227UL, 3795356864UL, 3306095271UL, 1452688488UL, 621126888UL, 1838613968UL, 2054107827UL, 1785040579UL, 454879400UL, +1952849106UL, 1907701866UL, 1639495252UL, 1623968604UL, 2997422000UL, 2633878652UL, 1036670775UL, 2191465943UL, 3053533585UL, 1654709920UL, 1950620393UL, 4177745509UL, 1742007818UL, 2888573892UL, 2825965566UL, 1399790365UL, 1307674482UL, 310692416UL, 384880529UL, 3497622676UL, 1024664651UL, 1541456182UL, 1904670217UL, 1008618602UL, 2816673160UL, 684112698UL, 3332034744UL, 3646613828UL, 962627614UL, 3072103948UL, 3713153075UL, 476323310UL, +3243124597UL, 126319837UL, 2155412848UL, 228580793UL, 2142696490UL, 3442722759UL, 2689599232UL, 426191419UL, 3157759186UL, 100239709UL, 494534049UL, 1259677734UL, 2889209278UL, 1754641396UL, 1057778427UL, 2133253617UL, 1298500018UL, 3340348062UL, 3967049659UL, 2927469144UL, 1503854147UL, 2271956463UL, 3004309866UL, 260248338UL, 2570702480UL, 2067671015UL, 3168497089UL, 361311552UL, 2123195373UL, 2825457193UL, 2599488181UL, 507483626UL, +1201669979UL, 910763802UL, 4158584821UL, 3116016424UL, 3375736126UL, 2857697336UL, 3112473104UL, 2683465481UL, 1495348009UL, 681020485UL, 4044713962UL, 2443109893UL, 129994063UL, 1710251126UL, 820410567UL, 601527649UL, 1007603132UL, 2096580480UL, 1942768885UL, 1984297765UL, 1888157243UL, 960265104UL, 527990410UL, 1572910026UL, 1106822080UL, 1472807331UL, 2465011897UL, 3139401215UL, 3705452371UL, 393081842UL, 3826516196UL, 2576499701UL, +4130037087UL, 4155028170UL, 2188282304UL, 2949056849UL, 1138928618UL, 858751984UL, 3735375571UL, 496972334UL, 830265621UL, 1355757111UL, 909444416UL, 1337622259UL, 2616327935UL, 2337227347UL, 2139876075UL, 4269663356UL, 796316592UL, 1893005585UL, 3958551664UL, 1746456069UL, 2430709714UL, 4025417573UL, 3333292799UL, 1833607331UL, 3864559081UL, 3415700826UL, 3291421244UL, 1987321873UL, 1792851165UL, 505718946UL, 3755903648UL, 3351468604UL, +4035552813UL, 2052557448UL, 2879065999UL, 22933757UL, 2160014758UL, 2321387515UL, 3556641619UL, 1350613766UL, 2107757927UL, 309323868UL, 1850700415UL, 3424626316UL, 545651740UL, 1935764720UL, 2349926457UL, 979047283UL, 862046434UL, 167198649UL, 338290297UL, 1145807303UL, 4201635137UL, 883549156UL, 907871968UL, 638566313UL, 678764227UL, 2637527083UL, 3306095271UL, 1452688488UL, 621126888UL, 1838613968UL, 117966344UL, 1785040579UL, +454879400UL, 1952849106UL, 1907701866UL, 733998186UL, 1623968604UL, 2997422000UL, 2633878652UL, 1036670775UL, 3360491537UL, 3053533585UL, 1654709920UL, 1950620393UL, 4177745509UL, 1716078578UL, 2888573892UL, 2825965566UL, 1399790365UL, 1307674482UL, 2776111761UL, 384880529UL, 3497622676UL, 1024664651UL, 1541456182UL, 618916624UL, 1008618602UL, 2816673160UL, 684112698UL, 3332034744UL, 3340690804UL, 962627614UL, 3072103948UL, 3713153075UL, +476323310UL, 902990902UL, 126319837UL, 2155412848UL, 228580793UL, 2142696490UL, 4254301999UL, 2689599232UL, 426191419UL, 3157759186UL, 100239709UL, 3216403640UL, 1259677734UL, 2889209278UL, 1754641396UL, 1057778427UL, 3221479262UL, 1298500018UL, 3340348062UL, 3967049659UL, 2927469144UL, 3926654939UL, 2271956463UL, 3004309866UL, 260248338UL, 2570702480UL, 1879451653UL, 3168497089UL, 361311552UL, 2123195373UL, 2825457193UL, 341920668UL, +507483626UL, 1201669979UL, 910763802UL, 4158584821UL, 3748705813UL, 3375736126UL, 2857697336UL, 3112473104UL, 2683465481UL, 3336305747UL, 681020485UL, 4044713962UL, 2443109893UL, 129994063UL, 2578353596UL, 820410567UL, 601527649UL, 1007603132UL, 2096580480UL, 3155251071UL, 1984297765UL, 1888157243UL, 960265104UL, 527990410UL, 2548692624UL, 1106822080UL, 1472807331UL, 2465011897UL, 3139401215UL, 736629379UL, 393081842UL, 3826516196UL, +2576499701UL, 4130037087UL, 2440227627UL, 2188282304UL, 2949056849UL, 1138928618UL, 858751984UL, 191805249UL, 496972334UL, 830265621UL, 1355757111UL, 909444416UL, 396738554UL, 2616327935UL, 2337227347UL, 2139876075UL, 4269663356UL, 3932761947UL, 1893005585UL, 3958551664UL, 1746456069UL, 2430709714UL, 3171160829UL, 3333292799UL, 1833607331UL, 3864559081UL, 3415700826UL, 1332800826UL, 1987321873UL, 1792851165UL, 505718946UL, 3755903648UL, +1770588062UL, 4035552813UL, 2052557448UL, 2879065999UL, 22933757UL, 3159941473UL, 2321387515UL, 3556641619UL, 1350613766UL, 2107757927UL, 2669366188UL, 1850700415UL, 3424626316UL, 545651740UL, 1935764720UL, 3252475208UL, 979047283UL, 862046434UL, 167198649UL, 338290297UL, 771814471UL, 4201635137UL, 883549156UL, 907871968UL, 638566313UL, 184144160UL, 2637527083UL, 3306095271UL, 1452688488UL, 621126888UL, 4275587594UL, 117966344UL, +1785040579UL, 454879400UL, 1952849106UL, 3806424990UL, 733998186UL, 1623968604UL, 2997422000UL, 2633878652UL, 2670843077UL, 3360491537UL, 3053533585UL, 1654709920UL, 1950620393UL, 3541927406UL, 1716078578UL, 2888573892UL, 2825965566UL, 1399790365UL, 3184295779UL, 2776111761UL, 384880529UL, 3497622676UL, 1024664651UL, 723804135UL, 618916624UL, 1008618602UL, 2816673160UL, 684112698UL, 3275521308UL, 3340690804UL, 962627614UL, 3072103948UL, +3713153075UL, 2023106558UL, 902990902UL, 126319837UL, 2155412848UL, 228580793UL, 3978575748UL, 4254301999UL, 2689599232UL, 426191419UL, 3157759186UL, 2446138116UL, 3216403640UL, 1259677734UL, 2889209278UL, 1754641396UL, 1706032491UL, 3221479262UL, 1298500018UL, 3340348062UL, 3967049659UL, 3805001240UL, 3926654939UL, 2271956463UL, 3004309866UL, 260248338UL, 294480880UL, 1879451653UL, 3168497089UL, 361311552UL, 2123195373UL, 2080604411UL, +341920668UL, 507483626UL, 1201669979UL, 910763802UL, 2012149356UL, 3748705813UL, 3375736126UL, 2857697336UL, 3112473104UL, 2935748807UL, 3336305747UL, 681020485UL, 4044713962UL, 2443109893UL, 2862982895UL, 2578353596UL, 820410567UL, 601527649UL, 1007603132UL, 1890290066UL, 3155251071UL, 1984297765UL, 1888157243UL, 960265104UL, 41870487UL, 2548692624UL, 1106822080UL, 1472807331UL, 2465011897UL, 2382974023UL, 736629379UL, 393081842UL, +3826516196UL, 2576499701UL, 4219335149UL, 2440227627UL, 2188282304UL, 2949056849UL, 1138928618UL, 3785297102UL, 191805249UL, 496972334UL, 830265621UL, 1355757111UL, 3962907313UL, 396738554UL, 2616327935UL, 2337227347UL, 2139876075UL, 552154011UL, 3932761947UL, 1893005585UL, 3958551664UL, 1746456069UL, 895507243UL, 3171160829UL, 3333292799UL, 1833607331UL, 3864559081UL, 3564325554UL, 1332800826UL, 1987321873UL, 1792851165UL, 505718946UL, +3245448088UL, 1770588062UL, 4035552813UL, 2052557448UL, 2879065999UL, 3602157977UL, 3159941473UL, 2321387515UL, 3556641619UL, 1350613766UL, 4101259055UL, 2669366188UL, 1850700415UL, 3424626316UL, 545651740UL, 2873707882UL, 3252475208UL, 979047283UL, 862046434UL, 167198649UL, 654196140UL, 771814471UL, 4201635137UL, 883549156UL, 907871968UL, 191965184UL, 184144160UL, 2637527083UL, 3306095271UL, 1452688488UL, 1562736568UL, 4275587594UL, +117966344UL, 1785040579UL, 454879400UL, 3484019450UL, 3806424990UL, 733998186UL, 1623968604UL, 2997422000UL, 273316614UL, 2670843077UL, 3360491537UL, 3053533585UL, 1654709920UL, 591311873UL, 3541927406UL, 1716078578UL, 2888573892UL, 2825965566UL, 2277117038UL, 3184295779UL, 2776111761UL, 384880529UL, 3497622676UL, 1086566797UL, 723804135UL, 618916624UL, 1008618602UL, 2816673160UL, 3344392942UL, 3275521308UL, 3340690804UL, 962627614UL, +3072103948UL, 2910444460UL, 2023106558UL, 902990902UL, 126319837UL, 2155412848UL, 337119596UL, 3978575748UL, 4254301999UL, 2689599232UL, 426191419UL, 3471778695UL, 2446138116UL, 3216403640UL, 1259677734UL, 2889209278UL, 4102983766UL, 1706032491UL, 3221479262UL, 1298500018UL, 3340348062UL, 2940293024UL, 3805001240UL, 3926654939UL, 2271956463UL, 3004309866UL, 3634668003UL, 294480880UL, 1879451653UL, 3168497089UL, 361311552UL, 3417679321UL, +2080604411UL, 341920668UL, 507483626UL, 1201669979UL, 3174274528UL, 2012149356UL, 3748705813UL, 3375736126UL, 2857697336UL, 3929686609UL, 2935748807UL, 3336305747UL, 681020485UL, 4044713962UL, 405011299UL, 2862982895UL, 2578353596UL, 820410567UL, 601527649UL, 4281957726UL, 1890290066UL, 3155251071UL, 1984297765UL, 1888157243UL, 1978308818UL, 41870487UL, 2548692624UL, 1106822080UL, 1472807331UL, 3701147046UL, 2382974023UL, 736629379UL, +393081842UL, 3826516196UL, 3225163595UL, 4219335149UL, 2440227627UL, 2188282304UL, 2949056849UL, 3894577191UL, 3785297102UL, 191805249UL, 496972334UL, 830265621UL, 4293577013UL, 3962907313UL, 396738554UL, 2616327935UL, 2337227347UL, 3701032380UL, 552154011UL, 3932761947UL, 1893005585UL, 3958551664UL, 4148575672UL, 895507243UL, 3171160829UL, 3333292799UL, 1833607331UL, 1596419195UL, 3564325554UL, 1332800826UL, 1987321873UL, 1792851165UL, +3663406943UL, 3892533309UL, 247565591UL, 953356243UL, 4103354183UL, 1908418768UL, 3915294912UL, 2390669489UL, 3865260287UL, 1818313429UL, 557880278UL, 2499771815UL, 2618380525UL, 732785004UL, 1414011135UL, 2858311749UL, 3871596970UL, 2428464498UL, 645476041UL, 683035653UL, 4079609082UL, 2404111028UL, 3332056297UL, 3054547484UL, 3616426087UL, 1311379849UL, 3682136336UL, 3795847093UL, 1509718393UL, 541389178UL, 1103876446UL, 2549442278UL, +3656600574UL, 3019560735UL, 523610761UL, 3889482885UL, 3080739216UL, 2359120072UL, 1034857006UL, 63567637UL, 1520176098UL, 1741685274UL, 2330217396UL, 1429674399UL, 517809884UL, 2653145241UL, 868296581UL, 646514407UL, 3166145188UL, 3023629813UL, 2333851648UL, 2967365394UL, 1828821737UL, 3333092181UL, 445460259UL, 2682093551UL, 3655100102UL, 2592872076UL, 1588368999UL, 3964958220UL, 755397374UL, 1912970603UL, 396253754UL, 4260038354UL, +1530898510UL, 2396805917UL, 3327501452UL, 4235709361UL, 2762163349UL, 553869167UL, 3162483580UL, 1611891352UL, 248738605UL, 3403092967UL, 2194464420UL, 113420452UL, 1752444845UL, 3770903547UL, 2397481985UL, 2866414964UL, 2555678075UL, 2796010061UL, 762034588UL, 2679383682UL, 1848516655UL, 3857720381UL, 1119111363UL, 1829110546UL, 2183620391UL, 1743838702UL, 3363053704UL, 2212810289UL, 966205413UL, 3897281091UL, 2148139678UL, 2690229390UL, +427450194UL, 3516115778UL, 1864991059UL, 134448489UL, 3397232480UL, 3999530682UL, 1927036992UL, 3170864927UL, 3879295489UL, 134554462UL, 3447324105UL, 86678510UL, 1656551206UL, 2844494044UL, 2469678938UL, 2885597732UL, 2715483555UL, 3566904604UL, 462585182UL, 1922457093UL, 3035264235UL, 2866504077UL, 2031456720UL, 1598555964UL, 2569915450UL, 3947972758UL, 290683210UL, 2465427488UL, 3504862176UL, 793156806UL, 1722326752UL, 2706215067UL, +3818976191UL, 2007064241UL, 552144413UL, 2692866408UL, 3975075075UL, 4293828741UL, 1123460373UL, 960845744UL, 1855626484UL, 1876934434UL, 1343778249UL, 912185207UL, 127278206UL, 4168930635UL, 340393978UL, 65814528UL, 2552086271UL, 2507474816UL, 1240220220UL, 1761964455UL, 2204917500UL, 4088965101UL, 1079310398UL, 3071460742UL, 2188549805UL, 1064733776UL, 4191719087UL, 3221046115UL, 3772395288UL, 883516842UL, 2077853840UL, 229484673UL, +}, +{ +448889887UL, 3508620909UL, 4164289950UL, 155254859UL, 298319697UL, 980080883UL, 3500794888UL, 3974907245UL, 682778656UL, 382798811UL, 1500342771UL, 3942535492UL, 1039809505UL, 2126581011UL, 561192171UL, 4046277638UL, 840733718UL, 1694555864UL, 241216466UL, 4182349979UL, 2525929010UL, 386794637UL, 349755829UL, 2959959729UL, 686974318UL, 3243688353UL, 3911051908UL, 3917458620UL, 441833800UL, 3164548257UL, 584185450UL, 450132281UL, +3528356519UL, 4275666503UL, 1317069624UL, 817077137UL, 2945430988UL, 1532878265UL, 2542155552UL, 3348614029UL, 1419611574UL, 1245233100UL, 1981161828UL, 1161647342UL, 2781439556UL, 3896025436UL, 2349200248UL, 1213899699UL, 860301545UL, 1590934964UL, 3371591516UL, 2850926464UL, 2774569126UL, 907316453UL, 3541736952UL, 3572719697UL, 278602945UL, 4257620354UL, 3396349537UL, 3144949411UL, 191271983UL, 2974056951UL, 2743594803UL, 1119054633UL, +815666748UL, 920991498UL, 187861899UL, 2008325469UL, 1548504646UL, 3749744762UL, 993523345UL, 1171349070UL, 4105576982UL, 1559471848UL, 2656434170UL, 2795453957UL, 3357293755UL, 4260164297UL, 2211998873UL, 1783238785UL, 2831224398UL, 1704939914UL, 2626903427UL, 1148581053UL, 849777796UL, 4219173763UL, 694869701UL, 1297370017UL, 3573985711UL, 1739242781UL, 3680794431UL, 400850360UL, 909653264UL, 1496585542UL, 460982606UL, 828640603UL, +3993062500UL, 2145047281UL, 1587836828UL, 912583500UL, 1234319994UL, 4276951314UL, 485282908UL, 1903750880UL, 1667769214UL, 3950976882UL, 3711912938UL, 3626058764UL, 627857875UL, 436470402UL, 1753727232UL, 50241405UL, 206782941UL, 612110492UL, 954016857UL, 2567547031UL, 3360482779UL, 820704062UL, 412722485UL, 2044763466UL, 1915626743UL, 2703000434UL, 2755090057UL, 53587450UL, 2457122208UL, 1397065983UL, 2822294224UL, 3024827428UL, +2201149820UL, 699377793UL, 157099022UL, 2792298089UL, 3927835437UL, 1095494739UL, 1230723791UL, 2740420278UL, 2518077381UL, 3674832547UL, 2375246835UL, 923451748UL, 3665432731UL, 1577970518UL, 2643388181UL, 4050379756UL, 1145072065UL, 1632232822UL, 2365350332UL, 1126185680UL, 930842061UL, 3816331201UL, 1624573114UL, 3809118349UL, 1187817320UL, 945407897UL, 63630679UL, 1852369563UL, 971772965UL, 2229069035UL, 2320405193UL, 3474864049UL, +1666937976UL, 448889887UL, 3508620909UL, 4164289950UL, 155254859UL, 3157319819UL, 980080883UL, 3500794888UL, 3974907245UL, 682778656UL, 3201604042UL, 1500342771UL, 3942535492UL, 1039809505UL, 2126581011UL, 3235144326UL, 4046277638UL, 840733718UL, 1694555864UL, 241216466UL, 2728337326UL, 2525929010UL, 386794637UL, 349755829UL, 2959959729UL, 20820947UL, 3243688353UL, 3911051908UL, 3917458620UL, 441833800UL, 4143649787UL, 584185450UL, +450132281UL, 3528356519UL, 4275666503UL, 3541347868UL, 817077137UL, 2945430988UL, 1532878265UL, 2542155552UL, 3199458552UL, 1419611574UL, 1245233100UL, 1981161828UL, 1161647342UL, 958085276UL, 3896025436UL, 2349200248UL, 1213899699UL, 860301545UL, 1701089635UL, 3371591516UL, 2850926464UL, 2774569126UL, 907316453UL, 1529987826UL, 3572719697UL, 278602945UL, 4257620354UL, 3396349537UL, 4120000342UL, 191271983UL, 2974056951UL, 2743594803UL, +1119054633UL, 4255116655UL, 920991498UL, 187861899UL, 2008325469UL, 1548504646UL, 100038488UL, 993523345UL, 1171349070UL, 4105576982UL, 1559471848UL, 2523523381UL, 2795453957UL, 3357293755UL, 4260164297UL, 2211998873UL, 3644225670UL, 2831224398UL, 1704939914UL, 2626903427UL, 1148581053UL, 1292003378UL, 4219173763UL, 694869701UL, 1297370017UL, 3573985711UL, 2510138592UL, 3680794431UL, 400850360UL, 909653264UL, 1496585542UL, 1738256576UL, +828640603UL, 3993062500UL, 2145047281UL, 1587836828UL, 3478998519UL, 1234319994UL, 4276951314UL, 485282908UL, 1903750880UL, 746205619UL, 3950976882UL, 3711912938UL, 3626058764UL, 627857875UL, 954627753UL, 1753727232UL, 50241405UL, 206782941UL, 612110492UL, 2251018875UL, 2567547031UL, 3360482779UL, 820704062UL, 412722485UL, 2120077037UL, 1915626743UL, 2703000434UL, 2755090057UL, 53587450UL, 2696843657UL, 1397065983UL, 2822294224UL, +3024827428UL, 2201149820UL, 3308142895UL, 157099022UL, 2792298089UL, 3927835437UL, 1095494739UL, 730099534UL, 2740420278UL, 2518077381UL, 3674832547UL, 2375246835UL, 2126745526UL, 3665432731UL, 1577970518UL, 2643388181UL, 4050379756UL, 2987545029UL, 1632232822UL, 2365350332UL, 1126185680UL, 930842061UL, 3140947362UL, 1624573114UL, 3809118349UL, 1187817320UL, 945407897UL, 1282799903UL, 1852369563UL, 971772965UL, 2229069035UL, 2320405193UL, +670134249UL, 1666937976UL, 448889887UL, 3508620909UL, 4164289950UL, 127045110UL, 3157319819UL, 980080883UL, 3500794888UL, 3974907245UL, 2740953010UL, 3201604042UL, 1500342771UL, 3942535492UL, 1039809505UL, 306788856UL, 3235144326UL, 4046277638UL, 840733718UL, 1694555864UL, 2260304655UL, 2728337326UL, 2525929010UL, 386794637UL, 349755829UL, 3842816805UL, 20820947UL, 3243688353UL, 3911051908UL, 3917458620UL, 3398227861UL, 4143649787UL, +584185450UL, 450132281UL, 3528356519UL, 550401017UL, 3541347868UL, 817077137UL, 2945430988UL, 1532878265UL, 1045681234UL, 3199458552UL, 1419611574UL, 1245233100UL, 1981161828UL, 1153297031UL, 958085276UL, 3896025436UL, 2349200248UL, 1213899699UL, 1451842347UL, 1701089635UL, 3371591516UL, 2850926464UL, 2774569126UL, 1269128107UL, 1529987826UL, 3572719697UL, 278602945UL, 4257620354UL, 2479560493UL, 4120000342UL, 191271983UL, 2974056951UL, +2743594803UL, 4081110580UL, 4255116655UL, 920991498UL, 187861899UL, 2008325469UL, 1300371976UL, 100038488UL, 993523345UL, 1171349070UL, 4105576982UL, 3010753279UL, 2523523381UL, 2795453957UL, 3357293755UL, 4260164297UL, 207153762UL, 3644225670UL, 2831224398UL, 1704939914UL, 2626903427UL, 916783095UL, 1292003378UL, 4219173763UL, 694869701UL, 1297370017UL, 3388725608UL, 2510138592UL, 3680794431UL, 400850360UL, 909653264UL, 2421730678UL, +1738256576UL, 828640603UL, 3993062500UL, 2145047281UL, 2123619770UL, 3478998519UL, 1234319994UL, 4276951314UL, 485282908UL, 4002661777UL, 746205619UL, 3950976882UL, 3711912938UL, 3626058764UL, 1230937254UL, 954627753UL, 1753727232UL, 50241405UL, 206782941UL, 460314337UL, 2251018875UL, 2567547031UL, 3360482779UL, 820704062UL, 1339598718UL, 2120077037UL, 1915626743UL, 2703000434UL, 2755090057UL, 660730207UL, 2696843657UL, 1397065983UL, +2822294224UL, 3024827428UL, 126840648UL, 3308142895UL, 157099022UL, 2792298089UL, 3927835437UL, 2192535935UL, 730099534UL, 2740420278UL, 2518077381UL, 3674832547UL, 1879512787UL, 2126745526UL, 3665432731UL, 1577970518UL, 2643388181UL, 832572764UL, 2987545029UL, 1632232822UL, 2365350332UL, 1126185680UL, 3248646182UL, 3140947362UL, 1624573114UL, 3809118349UL, 1187817320UL, 4270855000UL, 1282799903UL, 1852369563UL, 971772965UL, 2229069035UL, +3735782785UL, 670134249UL, 1666937976UL, 448889887UL, 3508620909UL, 3681408470UL, 127045110UL, 3157319819UL, 980080883UL, 3500794888UL, 3967872553UL, 2740953010UL, 3201604042UL, 1500342771UL, 3942535492UL, 613854690UL, 306788856UL, 3235144326UL, 4046277638UL, 840733718UL, 3957877023UL, 2260304655UL, 2728337326UL, 2525929010UL, 386794637UL, 1779451936UL, 3842816805UL, 20820947UL, 3243688353UL, 3911051908UL, 688470429UL, 3398227861UL, +4143649787UL, 584185450UL, 450132281UL, 3381050556UL, 550401017UL, 3541347868UL, 817077137UL, 2945430988UL, 1859551669UL, 1045681234UL, 3199458552UL, 1419611574UL, 1245233100UL, 53681099UL, 1153297031UL, 958085276UL, 3896025436UL, 2349200248UL, 1796144514UL, 1451842347UL, 1701089635UL, 3371591516UL, 2850926464UL, 1337394836UL, 1269128107UL, 1529987826UL, 3572719697UL, 278602945UL, 46913829UL, 2479560493UL, 4120000342UL, 191271983UL, +2974056951UL, 1361976701UL, 4081110580UL, 4255116655UL, 920991498UL, 187861899UL, 1237191391UL, 1300371976UL, 100038488UL, 993523345UL, 1171349070UL, 3168325479UL, 3010753279UL, 2523523381UL, 2795453957UL, 3357293755UL, 2142853843UL, 207153762UL, 3644225670UL, 2831224398UL, 1704939914UL, 2369686128UL, 916783095UL, 1292003378UL, 4219173763UL, 694869701UL, 4150182218UL, 3388725608UL, 2510138592UL, 3680794431UL, 400850360UL, 654034492UL, +2421730678UL, 1738256576UL, 828640603UL, 3993062500UL, 84735560UL, 2123619770UL, 3478998519UL, 1234319994UL, 4276951314UL, 2545204994UL, 4002661777UL, 746205619UL, 3950976882UL, 3711912938UL, 426068544UL, 1230937254UL, 954627753UL, 1753727232UL, 50241405UL, 589286339UL, 460314337UL, 2251018875UL, 2567547031UL, 3360482779UL, 3279873953UL, 1339598718UL, 2120077037UL, 1915626743UL, 2703000434UL, 2720159887UL, 660730207UL, 2696843657UL, +1397065983UL, 2822294224UL, 3536645029UL, 126840648UL, 3308142895UL, 157099022UL, 2792298089UL, 485214530UL, 2192535935UL, 730099534UL, 2740420278UL, 2518077381UL, 418832171UL, 1879512787UL, 2126745526UL, 3665432731UL, 1577970518UL, 721018UL, 832572764UL, 2987545029UL, 1632232822UL, 2365350332UL, 1769688764UL, 3248646182UL, 3140947362UL, 1624573114UL, 3809118349UL, 3561012744UL, 4270855000UL, 1282799903UL, 1852369563UL, 971772965UL, +2160782957UL, 105464019UL, 2131462864UL, 335205049UL, 3271229551UL, 1374396416UL, 4269753677UL, 1984596635UL, 37563880UL, 3956352262UL, 2168603656UL, 311623712UL, 1593371323UL, 351020595UL, 3439337532UL, 3130874657UL, 3613343327UL, 695789539UL, 609797513UL, 53642143UL, 1479027519UL, 1588831722UL, 262810641UL, 3418379977UL, 530167431UL, 1962487963UL, 2410103328UL, 3360114680UL, 3548827677UL, 2735238248UL, 2136058369UL, 4013192489UL, +4106245442UL, 2155966460UL, 3653971354UL, 1230293148UL, 3966689348UL, 3455336684UL, 3594979856UL, 3178937309UL, 3983796170UL, 3617590004UL, 1727358326UL, 1121418876UL, 1022562029UL, 2437823131UL, 2733424381UL, 452731958UL, 2983755220UL, 1674750403UL, 3110921909UL, 3514365950UL, 2193238341UL, 2073801740UL, 669573402UL, 1824298084UL, 22336337UL, 3366446304UL, 1536043612UL, 2502297553UL, 1409641611UL, 2399583184UL, 2593245170UL, 716832039UL, +4286149460UL, 814849965UL, 4239224908UL, 2453627262UL, 976385355UL, 1846129423UL, 52096201UL, 88835472UL, 2621770794UL, 2491757130UL, 1849417480UL, 576668065UL, 2186701850UL, 3357019214UL, 442191324UL, 3662645846UL, 3653766782UL, 2254203663UL, 1169821059UL, 3735427676UL, 2246044748UL, 2635264668UL, 2647842566UL, 1435695450UL, 1658777934UL, 2927080369UL, 1341088646UL, 3565982642UL, 221661496UL, 3246988243UL, 2718455491UL, 483517148UL, +4181332651UL, 1143646375UL, 1720449423UL, 331164544UL, 539836322UL, 3485371630UL, 1110077273UL, 4088985694UL, 145720169UL, 2382276586UL, 4276410795UL, 2051956774UL, 936524156UL, 15415192UL, 1815949694UL, 272696290UL, 1495465483UL, 3102030383UL, 3546078241UL, 3272619595UL, 759699322UL, 1161486824UL, 1146281812UL, 4194130649UL, 3936306436UL, 4077338125UL, 2127551216UL, 2995077453UL, 209698652UL, 3836657987UL, 1782152220UL, 1642490089UL, +3695579542UL, 537862234UL, 1696168156UL, 4022607UL, 3642864269UL, 54404878UL, 2925910542UL, 3444042482UL, 1931288691UL, 2269375687UL, 614870298UL, 1139082272UL, 3672546472UL, 3255845763UL, 2987873616UL, 3436501734UL, 380553853UL, 750118352UL, 750708138UL, 488564982UL, 2936846643UL, 3460652101UL, 3085496886UL, 3734224010UL, 523359404UL, 2751912206UL, 3302219188UL, 2729509827UL, 1995554251UL, 2288103059UL, 3289667468UL, 2860301591UL, +}, +{ +3481653941UL, 2111903071UL, 3569014882UL, 1149634763UL, 4206972571UL, 2948781360UL, 2576820949UL, 2587099571UL, 3987042644UL, 4255777336UL, 2829594348UL, 3832744490UL, 3554499754UL, 787920018UL, 695635693UL, 2746034685UL, 2078139227UL, 1144320548UL, 4020978225UL, 449503505UL, 3004993826UL, 2045843139UL, 1604631401UL, 148449881UL, 457819243UL, 4089112489UL, 1713441237UL, 1790909556UL, 3334464951UL, 3070008305UL, 811825474UL, 4089105370UL, +708239097UL, 1494832299UL, 2074902973UL, 468898217UL, 1722559700UL, 2499754488UL, 2267939270UL, 650114709UL, 549502184UL, 4040463514UL, 4228169080UL, 4094284819UL, 1599334548UL, 2992525399UL, 2107053637UL, 197348940UL, 1669884894UL, 3982326753UL, 4259099320UL, 1862793542UL, 1751219817UL, 2701271514UL, 2507353222UL, 1488339939UL, 4246544316UL, 3978321870UL, 132720476UL, 3020305599UL, 154822619UL, 2595474066UL, 1654579304UL, 1997335204UL, +891320674UL, 3153502700UL, 601607977UL, 2695457160UL, 4137981809UL, 37584248UL, 1674050253UL, 1805619463UL, 676369068UL, 2294902904UL, 658143166UL, 141452045UL, 2383327493UL, 1222336195UL, 2628962123UL, 2378299402UL, 2724274090UL, 1783957650UL, 453206569UL, 3190116972UL, 1480368955UL, 1145768764UL, 3628222572UL, 3108689607UL, 182547022UL, 360165920UL, 3378423016UL, 1443723222UL, 2843274258UL, 1597581683UL, 664283285UL, 258077235UL, +3071875976UL, 240688930UL, 988895736UL, 2965351284UL, 91332032UL, 941306162UL, 2464278288UL, 3493666272UL, 2437043750UL, 2356658919UL, 24726067UL, 3025656863UL, 1343636659UL, 2408295270UL, 3097408183UL, 461428710UL, 2449005423UL, 3220070834UL, 1418517867UL, 907095008UL, 428073188UL, 1938061314UL, 2094361729UL, 2570445990UL, 346999411UL, 990247709UL, 1630488660UL, 2574142591UL, 1466590284UL, 1906935236UL, 1592544037UL, 4168163186UL, +2773942807UL, 939392801UL, 1610069434UL, 1935303983UL, 2962954128UL, 2490925509UL, 4103025390UL, 3614258069UL, 174125899UL, 4113855120UL, 2449365101UL, 3384244363UL, 4115219971UL, 3187664453UL, 4021992190UL, 2959372973UL, 2946571025UL, 2144945539UL, 388172915UL, 1125615727UL, 881693338UL, 3313110562UL, 859388069UL, 177786360UL, 4134747901UL, 616417204UL, 2104495620UL, 783302897UL, 512784708UL, 1295821322UL, 3810209448UL, 2966899912UL, +2390608767UL, 3481653941UL, 2111903071UL, 3569014882UL, 1149634763UL, 1385372463UL, 2948781360UL, 2576820949UL, 2587099571UL, 3987042644UL, 2251144849UL, 2829594348UL, 3832744490UL, 3554499754UL, 787920018UL, 73007125UL, 2746034685UL, 2078139227UL, 1144320548UL, 4020978225UL, 2729117517UL, 3004993826UL, 2045843139UL, 1604631401UL, 148449881UL, 3343221736UL, 4089112489UL, 1713441237UL, 1790909556UL, 3334464951UL, 1920962856UL, 811825474UL, +4089105370UL, 708239097UL, 1494832299UL, 2485576001UL, 468898217UL, 1722559700UL, 2499754488UL, 2267939270UL, 2271486862UL, 549502184UL, 4040463514UL, 4228169080UL, 4094284819UL, 3177940420UL, 2992525399UL, 2107053637UL, 197348940UL, 1669884894UL, 3596140613UL, 4259099320UL, 1862793542UL, 1751219817UL, 2701271514UL, 1357847339UL, 1488339939UL, 4246544316UL, 3978321870UL, 132720476UL, 344033794UL, 154822619UL, 2595474066UL, 1654579304UL, +1997335204UL, 1849659590UL, 3153502700UL, 601607977UL, 2695457160UL, 4137981809UL, 3559496104UL, 1674050253UL, 1805619463UL, 676369068UL, 2294902904UL, 1583197657UL, 141452045UL, 2383327493UL, 1222336195UL, 2628962123UL, 3486106126UL, 2724274090UL, 1783957650UL, 453206569UL, 3190116972UL, 1939413704UL, 1145768764UL, 3628222572UL, 3108689607UL, 182547022UL, 2911760834UL, 3378423016UL, 1443723222UL, 2843274258UL, 1597581683UL, 3599911248UL, +258077235UL, 3071875976UL, 240688930UL, 988895736UL, 4263328855UL, 91332032UL, 941306162UL, 2464278288UL, 3493666272UL, 1561559932UL, 2356658919UL, 24726067UL, 3025656863UL, 1343636659UL, 257301433UL, 3097408183UL, 461428710UL, 2449005423UL, 3220070834UL, 3544357262UL, 907095008UL, 428073188UL, 1938061314UL, 2094361729UL, 4112109825UL, 346999411UL, 990247709UL, 1630488660UL, 2574142591UL, 1466763688UL, 1906935236UL, 1592544037UL, +4168163186UL, 2773942807UL, 3608227467UL, 1610069434UL, 1935303983UL, 2962954128UL, 2490925509UL, 825197245UL, 3614258069UL, 174125899UL, 4113855120UL, 2449365101UL, 167881680UL, 4115219971UL, 3187664453UL, 4021992190UL, 2959372973UL, 1971633162UL, 2144945539UL, 388172915UL, 1125615727UL, 881693338UL, 223946687UL, 859388069UL, 177786360UL, 4134747901UL, 616417204UL, 722598357UL, 783302897UL, 512784708UL, 1295821322UL, 3810209448UL, +1589703161UL, 2390608767UL, 3481653941UL, 2111903071UL, 3569014882UL, 2520719089UL, 1385372463UL, 2948781360UL, 2576820949UL, 2587099571UL, 1427210741UL, 2251144849UL, 2829594348UL, 3832744490UL, 3554499754UL, 1257461820UL, 73007125UL, 2746034685UL, 2078139227UL, 1144320548UL, 3065859797UL, 2729117517UL, 3004993826UL, 2045843139UL, 1604631401UL, 36092756UL, 3343221736UL, 4089112489UL, 1713441237UL, 1790909556UL, 1504385586UL, 1920962856UL, +811825474UL, 4089105370UL, 708239097UL, 4135459720UL, 2485576001UL, 468898217UL, 1722559700UL, 2499754488UL, 1392696606UL, 2271486862UL, 549502184UL, 4040463514UL, 4228169080UL, 2521060775UL, 3177940420UL, 2992525399UL, 2107053637UL, 197348940UL, 4225425195UL, 3596140613UL, 4259099320UL, 1862793542UL, 1751219817UL, 3752827533UL, 1357847339UL, 1488339939UL, 4246544316UL, 3978321870UL, 270743120UL, 344033794UL, 154822619UL, 2595474066UL, +1654579304UL, 986127123UL, 1849659590UL, 3153502700UL, 601607977UL, 2695457160UL, 437034992UL, 3559496104UL, 1674050253UL, 1805619463UL, 676369068UL, 956939381UL, 1583197657UL, 141452045UL, 2383327493UL, 1222336195UL, 3287498300UL, 3486106126UL, 2724274090UL, 1783957650UL, 453206569UL, 3610364652UL, 1939413704UL, 1145768764UL, 3628222572UL, 3108689607UL, 708259891UL, 2911760834UL, 3378423016UL, 1443723222UL, 2843274258UL, 1498209005UL, +3599911248UL, 258077235UL, 3071875976UL, 240688930UL, 3815218922UL, 4263328855UL, 91332032UL, 941306162UL, 2464278288UL, 3018835600UL, 1561559932UL, 2356658919UL, 24726067UL, 3025656863UL, 368313673UL, 257301433UL, 3097408183UL, 461428710UL, 2449005423UL, 3690066046UL, 3544357262UL, 907095008UL, 428073188UL, 1938061314UL, 2274317748UL, 4112109825UL, 346999411UL, 990247709UL, 1630488660UL, 1584471638UL, 1466763688UL, 1906935236UL, +1592544037UL, 4168163186UL, 473837206UL, 3608227467UL, 1610069434UL, 1935303983UL, 2962954128UL, 391171548UL, 825197245UL, 3614258069UL, 174125899UL, 4113855120UL, 2095676907UL, 167881680UL, 4115219971UL, 3187664453UL, 4021992190UL, 4246237180UL, 1971633162UL, 2144945539UL, 388172915UL, 1125615727UL, 3158677395UL, 223946687UL, 859388069UL, 177786360UL, 4134747901UL, 4017781965UL, 722598357UL, 783302897UL, 512784708UL, 1295821322UL, +3908594844UL, 1589703161UL, 2390608767UL, 3481653941UL, 2111903071UL, 2713757719UL, 2520719089UL, 1385372463UL, 2948781360UL, 2576820949UL, 638075690UL, 1427210741UL, 2251144849UL, 2829594348UL, 3832744490UL, 2871270139UL, 1257461820UL, 73007125UL, 2746034685UL, 2078139227UL, 1974062189UL, 3065859797UL, 2729117517UL, 3004993826UL, 2045843139UL, 772058252UL, 36092756UL, 3343221736UL, 4089112489UL, 1713441237UL, 2172680702UL, 1504385586UL, +1920962856UL, 811825474UL, 4089105370UL, 1822881146UL, 4135459720UL, 2485576001UL, 468898217UL, 1722559700UL, 3429640856UL, 1392696606UL, 2271486862UL, 549502184UL, 4040463514UL, 3072935276UL, 2521060775UL, 3177940420UL, 2992525399UL, 2107053637UL, 1114377646UL, 4225425195UL, 3596140613UL, 4259099320UL, 1862793542UL, 1439724658UL, 3752827533UL, 1357847339UL, 1488339939UL, 4246544316UL, 1051119047UL, 270743120UL, 344033794UL, 154822619UL, +2595474066UL, 3143800435UL, 986127123UL, 1849659590UL, 3153502700UL, 601607977UL, 2334441739UL, 437034992UL, 3559496104UL, 1674050253UL, 1805619463UL, 455274178UL, 956939381UL, 1583197657UL, 141452045UL, 2383327493UL, 1520979444UL, 3287498300UL, 3486106126UL, 2724274090UL, 1783957650UL, 2212706740UL, 3610364652UL, 1939413704UL, 1145768764UL, 3628222572UL, 2719501850UL, 708259891UL, 2911760834UL, 3378423016UL, 1443723222UL, 2678486648UL, +1498209005UL, 3599911248UL, 258077235UL, 3071875976UL, 513762712UL, 3815218922UL, 4263328855UL, 91332032UL, 941306162UL, 3000922309UL, 3018835600UL, 1561559932UL, 2356658919UL, 24726067UL, 3626352172UL, 368313673UL, 257301433UL, 3097408183UL, 461428710UL, 2370224855UL, 3690066046UL, 3544357262UL, 907095008UL, 428073188UL, 2279237523UL, 2274317748UL, 4112109825UL, 346999411UL, 990247709UL, 896290404UL, 1584471638UL, 1466763688UL, +1906935236UL, 1592544037UL, 2387522308UL, 473837206UL, 3608227467UL, 1610069434UL, 1935303983UL, 4120978868UL, 391171548UL, 825197245UL, 3614258069UL, 174125899UL, 2940674123UL, 2095676907UL, 167881680UL, 4115219971UL, 3187664453UL, 456143482UL, 4246237180UL, 1971633162UL, 2144945539UL, 388172915UL, 4041481385UL, 3158677395UL, 223946687UL, 859388069UL, 177786360UL, 3094936989UL, 4017781965UL, 722598357UL, 783302897UL, 512784708UL, +4078350595UL, 2002159085UL, 3374931831UL, 1327513052UL, 4231642441UL, 2398594140UL, 2750176655UL, 2377078716UL, 3051451207UL, 2923556938UL, 392203913UL, 970480700UL, 1611278056UL, 1212903807UL, 85815670UL, 2398261756UL, 1052760308UL, 175807153UL, 2617028873UL, 1862087601UL, 1824020594UL, 3770624867UL, 141863380UL, 2090619424UL, 3994019338UL, 2363183556UL, 3095139522UL, 1792884692UL, 3026343485UL, 2320955816UL, 145789343UL, 214170401UL, +2926373126UL, 3858640613UL, 2188241463UL, 459887603UL, 2117474937UL, 2514234285UL, 1454156613UL, 1675396814UL, 4188979068UL, 1584843874UL, 3594779833UL, 563029256UL, 28681425UL, 446949770UL, 3498545218UL, 435874305UL, 3448653884UL, 863509898UL, 2247299904UL, 4211345429UL, 971855563UL, 1475394960UL, 3401692834UL, 167361776UL, 496249436UL, 1465278889UL, 780336162UL, 2108770597UL, 1806981510UL, 3677875653UL, 1890122303UL, 16399665UL, +2747394159UL, 2098019492UL, 1597583332UL, 1763649529UL, 1286079969UL, 1846278877UL, 1016796923UL, 959676917UL, 3091540766UL, 1626192266UL, 780987350UL, 1102963422UL, 2507002232UL, 691766944UL, 193328868UL, 981596600UL, 2384820612UL, 3149668778UL, 1691569420UL, 2852237957UL, 893819979UL, 2572584243UL, 216077070UL, 1267249886UL, 2572508880UL, 1706489454UL, 2391561733UL, 2608477467UL, 209783612UL, 765896849UL, 3617020328UL, 3488800100UL, +2237655981UL, 2095308189UL, 963275857UL, 3563488318UL, 1865487834UL, 480006810UL, 18562439UL, 1025913188UL, 3368592397UL, 374648713UL, 2421713724UL, 2705651398UL, 3098059650UL, 1109934605UL, 3085839620UL, 3184266772UL, 2359972463UL, 862934481UL, 3624479194UL, 3574284465UL, 2700143837UL, 2468083868UL, 3798800988UL, 4116964911UL, 1832002264UL, 4276154871UL, 3256889524UL, 4036954281UL, 697729046UL, 886223984UL, 2196986730UL, 1157617208UL, +1995907944UL, 398452318UL, 3523714364UL, 613570866UL, 2962430983UL, 1408814780UL, 892117129UL, 4173164219UL, 3894076479UL, 2721348430UL, 555734931UL, 1869034419UL, 336114876UL, 3142554871UL, 3349604636UL, 3450290892UL, 955122895UL, 2202902910UL, 2558366468UL, 1701182712UL, 283197682UL, 1865942385UL, 2027648778UL, 2285857699UL, 880475184UL, 958651279UL, 169534250UL, 3842420528UL, 1568559789UL, 2986618464UL, 2568345525UL, 3081082692UL, +}, +{ +575494427UL, 2773243709UL, 4009191487UL, 3877909663UL, 2252044261UL, 1328043370UL, 1407136778UL, 3204434425UL, 3881653592UL, 1481049819UL, 2939203697UL, 889352935UL, 628666312UL, 165199023UL, 2949092155UL, 1116804589UL, 998930334UL, 4144153491UL, 4191022348UL, 9022505UL, 4033326555UL, 2329569601UL, 824756145UL, 3501916851UL, 1481410328UL, 1970954319UL, 4022176157UL, 2356841052UL, 3783173734UL, 3649102345UL, 3205430658UL, 1460938436UL, +280282398UL, 3262135457UL, 4055383786UL, 28522973UL, 1100901182UL, 4048609665UL, 994490185UL, 2888527367UL, 3591919750UL, 65093467UL, 399797207UL, 3377740861UL, 3103183487UL, 3696509979UL, 866353724UL, 3847992271UL, 2821933890UL, 1491144079UL, 1702442928UL, 1271285504UL, 636444475UL, 2465430290UL, 2440306765UL, 2651443172UL, 2895101023UL, 43843628UL, 518479547UL, 3708355608UL, 2313400729UL, 3786408564UL, 2823763904UL, 3267560272UL, +524168411UL, 2580824843UL, 2687886610UL, 785942949UL, 2624395631UL, 3713348903UL, 4104123478UL, 2234056629UL, 2683158959UL, 1805382347UL, 1645702909UL, 382688861UL, 2843792951UL, 39122499UL, 2765954033UL, 3033237617UL, 784228054UL, 1680611136UL, 2306036746UL, 892707919UL, 3825738103UL, 1289362844UL, 3462989616UL, 484526950UL, 178560970UL, 1863413515UL, 71290794UL, 1716785670UL, 3881310302UL, 2826977504UL, 2312744076UL, 1000001815UL, +1580868938UL, 3808984884UL, 2521899773UL, 738699928UL, 2244576791UL, 1833964269UL, 1361345793UL, 2934763305UL, 2944705940UL, 2334116476UL, 674208214UL, 587191877UL, 271361277UL, 1639419136UL, 2742744205UL, 2556530506UL, 3764115510UL, 861410771UL, 3473658359UL, 2879790483UL, 1497452846UL, 1101855458UL, 2268199923UL, 1766359872UL, 480532790UL, 2926891626UL, 1366888524UL, 2262816900UL, 620045088UL, 2279182738UL, 2479688463UL, 427385986UL, +271096497UL, 1999040724UL, 1980388138UL, 3104550456UL, 2496325717UL, 2941450111UL, 1784373495UL, 4020221165UL, 2567325850UL, 2636190539UL, 2764516078UL, 2285887821UL, 2395930109UL, 1867061176UL, 665795763UL, 3869868300UL, 4033135159UL, 2589983679UL, 682593183UL, 1254600537UL, 1701095863UL, 3738080583UL, 369734429UL, 2231641462UL, 1866531599UL, 1317004965UL, 466053171UL, 2320346625UL, 485850108UL, 1279183025UL, 423884362UL, 1878291714UL, +228799661UL, 575494427UL, 2773243709UL, 4009191487UL, 3877909663UL, 1392246100UL, 1328043370UL, 1407136778UL, 3204434425UL, 3881653592UL, 303018213UL, 2939203697UL, 889352935UL, 628666312UL, 165199023UL, 691563049UL, 1116804589UL, 998930334UL, 4144153491UL, 4191022348UL, 2882458100UL, 4033326555UL, 2329569601UL, 824756145UL, 3501916851UL, 3512382126UL, 1970954319UL, 4022176157UL, 2356841052UL, 3783173734UL, 3277915742UL, 3205430658UL, +1460938436UL, 280282398UL, 3262135457UL, 416160861UL, 28522973UL, 1100901182UL, 4048609665UL, 994490185UL, 2206150488UL, 3591919750UL, 65093467UL, 399797207UL, 3377740861UL, 3954301001UL, 3696509979UL, 866353724UL, 3847992271UL, 2821933890UL, 482325742UL, 1702442928UL, 1271285504UL, 636444475UL, 2465430290UL, 476965483UL, 2651443172UL, 2895101023UL, 43843628UL, 518479547UL, 2354104222UL, 2313400729UL, 3786408564UL, 2823763904UL, +3267560272UL, 1682576095UL, 2580824843UL, 2687886610UL, 785942949UL, 2624395631UL, 3219885224UL, 4104123478UL, 2234056629UL, 2683158959UL, 1805382347UL, 4143809855UL, 382688861UL, 2843792951UL, 39122499UL, 2765954033UL, 2870716981UL, 784228054UL, 1680611136UL, 2306036746UL, 892707919UL, 2648492467UL, 1289362844UL, 3462989616UL, 484526950UL, 178560970UL, 3047404165UL, 71290794UL, 1716785670UL, 3881310302UL, 2826977504UL, 2439325884UL, +1000001815UL, 1580868938UL, 3808984884UL, 2521899773UL, 2222792732UL, 2244576791UL, 1833964269UL, 1361345793UL, 2934763305UL, 655108124UL, 2334116476UL, 674208214UL, 587191877UL, 271361277UL, 1403491312UL, 2742744205UL, 2556530506UL, 3764115510UL, 861410771UL, 2748819627UL, 2879790483UL, 1497452846UL, 1101855458UL, 2268199923UL, 2646753562UL, 480532790UL, 2926891626UL, 1366888524UL, 2262816900UL, 691077353UL, 2279182738UL, 2479688463UL, +427385986UL, 271096497UL, 357444234UL, 1980388138UL, 3104550456UL, 2496325717UL, 2941450111UL, 717953620UL, 4020221165UL, 2567325850UL, 2636190539UL, 2764516078UL, 588189150UL, 2395930109UL, 1867061176UL, 665795763UL, 3869868300UL, 2245339306UL, 2589983679UL, 682593183UL, 1254600537UL, 1701095863UL, 3193417815UL, 369734429UL, 2231641462UL, 1866531599UL, 1317004965UL, 1295326133UL, 2320346625UL, 485850108UL, 1279183025UL, 423884362UL, +1310342080UL, 228799661UL, 575494427UL, 2773243709UL, 4009191487UL, 3178129190UL, 1392246100UL, 1328043370UL, 1407136778UL, 3204434425UL, 558594993UL, 303018213UL, 2939203697UL, 889352935UL, 628666312UL, 3995857198UL, 691563049UL, 1116804589UL, 998930334UL, 4144153491UL, 2375099047UL, 2882458100UL, 4033326555UL, 2329569601UL, 824756145UL, 3031828205UL, 3512382126UL, 1970954319UL, 4022176157UL, 2356841052UL, 1599294097UL, 3277915742UL, +3205430658UL, 1460938436UL, 280282398UL, 2438973535UL, 416160861UL, 28522973UL, 1100901182UL, 4048609665UL, 2989609671UL, 2206150488UL, 3591919750UL, 65093467UL, 399797207UL, 183644195UL, 3954301001UL, 3696509979UL, 866353724UL, 3847992271UL, 1244421011UL, 482325742UL, 1702442928UL, 1271285504UL, 636444475UL, 3659422961UL, 476965483UL, 2651443172UL, 2895101023UL, 43843628UL, 2230230933UL, 2354104222UL, 2313400729UL, 3786408564UL, +2823763904UL, 4146329709UL, 1682576095UL, 2580824843UL, 2687886610UL, 785942949UL, 126345381UL, 3219885224UL, 4104123478UL, 2234056629UL, 2683158959UL, 1734650983UL, 4143809855UL, 382688861UL, 2843792951UL, 39122499UL, 3527484969UL, 2870716981UL, 784228054UL, 1680611136UL, 2306036746UL, 1606477743UL, 2648492467UL, 1289362844UL, 3462989616UL, 484526950UL, 3730796296UL, 3047404165UL, 71290794UL, 1716785670UL, 3881310302UL, 4233965062UL, +2439325884UL, 1000001815UL, 1580868938UL, 3808984884UL, 1228341642UL, 2222792732UL, 2244576791UL, 1833964269UL, 1361345793UL, 3313812192UL, 655108124UL, 2334116476UL, 674208214UL, 587191877UL, 1531247446UL, 1403491312UL, 2742744205UL, 2556530506UL, 3764115510UL, 2419989900UL, 2748819627UL, 2879790483UL, 1497452846UL, 1101855458UL, 1430402656UL, 2646753562UL, 480532790UL, 2926891626UL, 1366888524UL, 1848714433UL, 691077353UL, 2279182738UL, +2479688463UL, 427385986UL, 3906690631UL, 357444234UL, 1980388138UL, 3104550456UL, 2496325717UL, 2272350403UL, 717953620UL, 4020221165UL, 2567325850UL, 2636190539UL, 1950604113UL, 588189150UL, 2395930109UL, 1867061176UL, 665795763UL, 1735147895UL, 2245339306UL, 2589983679UL, 682593183UL, 1254600537UL, 1518037357UL, 3193417815UL, 369734429UL, 2231641462UL, 1866531599UL, 1751783137UL, 1295326133UL, 2320346625UL, 485850108UL, 1279183025UL, +149835864UL, 1310342080UL, 228799661UL, 575494427UL, 2773243709UL, 1505829825UL, 3178129190UL, 1392246100UL, 1328043370UL, 1407136778UL, 856233019UL, 558594993UL, 303018213UL, 2939203697UL, 889352935UL, 625515593UL, 3995857198UL, 691563049UL, 1116804589UL, 998930334UL, 3264640128UL, 2375099047UL, 2882458100UL, 4033326555UL, 2329569601UL, 1824812377UL, 3031828205UL, 3512382126UL, 1970954319UL, 4022176157UL, 3682468973UL, 1599294097UL, +3277915742UL, 3205430658UL, 1460938436UL, 2034940270UL, 2438973535UL, 416160861UL, 28522973UL, 1100901182UL, 3534874298UL, 2989609671UL, 2206150488UL, 3591919750UL, 65093467UL, 2231373121UL, 183644195UL, 3954301001UL, 3696509979UL, 866353724UL, 1479968372UL, 1244421011UL, 482325742UL, 1702442928UL, 1271285504UL, 3834022401UL, 3659422961UL, 476965483UL, 2651443172UL, 2895101023UL, 1042443120UL, 2230230933UL, 2354104222UL, 2313400729UL, +3786408564UL, 2940290545UL, 4146329709UL, 1682576095UL, 2580824843UL, 2687886610UL, 895602439UL, 126345381UL, 3219885224UL, 4104123478UL, 2234056629UL, 3633565082UL, 1734650983UL, 4143809855UL, 382688861UL, 2843792951UL, 3076342354UL, 3527484969UL, 2870716981UL, 784228054UL, 1680611136UL, 3667923304UL, 1606477743UL, 2648492467UL, 1289362844UL, 3462989616UL, 1338592032UL, 3730796296UL, 3047404165UL, 71290794UL, 1716785670UL, 995728648UL, +4233965062UL, 2439325884UL, 1000001815UL, 1580868938UL, 1245957136UL, 1228341642UL, 2222792732UL, 2244576791UL, 1833964269UL, 2899552190UL, 3313812192UL, 655108124UL, 2334116476UL, 674208214UL, 1154789946UL, 1531247446UL, 1403491312UL, 2742744205UL, 2556530506UL, 1668620496UL, 2419989900UL, 2748819627UL, 2879790483UL, 1497452846UL, 177853954UL, 1430402656UL, 2646753562UL, 480532790UL, 2926891626UL, 3179057526UL, 1848714433UL, 691077353UL, +2279182738UL, 2479688463UL, 1988854710UL, 3906690631UL, 357444234UL, 1980388138UL, 3104550456UL, 1772857305UL, 2272350403UL, 717953620UL, 4020221165UL, 2567325850UL, 3129906484UL, 1950604113UL, 588189150UL, 2395930109UL, 1867061176UL, 2248975336UL, 1735147895UL, 2245339306UL, 2589983679UL, 682593183UL, 3087155398UL, 1518037357UL, 3193417815UL, 369734429UL, 2231641462UL, 1858424931UL, 1751783137UL, 1295326133UL, 2320346625UL, 485850108UL, +2471611230UL, 107369761UL, 2623559579UL, 4256589070UL, 2365810185UL, 907910243UL, 3901832478UL, 2068079364UL, 2072842987UL, 401440347UL, 1707255913UL, 1450112231UL, 2618898012UL, 600446000UL, 788321632UL, 4119629235UL, 2648781584UL, 1927659116UL, 171372782UL, 1789511950UL, 2648296999UL, 3558619514UL, 1819608632UL, 1392007708UL, 2918513974UL, 2270003900UL, 784021820UL, 1379044539UL, 591935962UL, 1638390839UL, 10832053UL, 3946625290UL, +2916913801UL, 2718331169UL, 1595482738UL, 1294279402UL, 19889234UL, 1374364843UL, 571354125UL, 3357938719UL, 2337506269UL, 905453029UL, 2504232400UL, 258673393UL, 2590342355UL, 3308443353UL, 3359617898UL, 2686453711UL, 932545954UL, 509832408UL, 820508114UL, 431186194UL, 3434866166UL, 1108455121UL, 2802986572UL, 893446102UL, 3248197798UL, 1797985531UL, 3952804303UL, 558601278UL, 1813674114UL, 311050994UL, 425175161UL, 1125527204UL, +1597986581UL, 2282580210UL, 1659733126UL, 2080660004UL, 4121079137UL, 3373787661UL, 1902252724UL, 2669993847UL, 2450915273UL, 2155525933UL, 2139535914UL, 274595185UL, 1890506924UL, 2631794527UL, 1423530517UL, 4027031002UL, 1085427968UL, 2402514206UL, 3591455043UL, 2513094696UL, 2338347202UL, 1168222597UL, 3922339535UL, 3991725466UL, 2774598759UL, 3478721168UL, 3676766916UL, 179748891UL, 2911159372UL, 191101265UL, 3389843262UL, 3093358663UL, +2333576084UL, 1056514165UL, 2987497874UL, 2502331872UL, 2027710028UL, 2338525812UL, 3904906078UL, 806669884UL, 596300960UL, 1993055778UL, 1541809402UL, 3578865742UL, 652348267UL, 3332532764UL, 2656602623UL, 2037214047UL, 323260312UL, 3310408133UL, 4037617529UL, 137297627UL, 1236501991UL, 495817051UL, 481150309UL, 3067841968UL, 3120347176UL, 714354848UL, 1554632062UL, 2522324107UL, 4274051212UL, 2180914534UL, 1261686356UL, 3569290041UL, +1801431819UL, 4286755560UL, 2749452442UL, 829235089UL, 2243153325UL, 2525168177UL, 1486881882UL, 585653228UL, 3288336688UL, 2734161045UL, 30430534UL, 714492313UL, 2582732426UL, 595577790UL, 1463554287UL, 1949506865UL, 4210942156UL, 2008105540UL, 4055753132UL, 2530320603UL, 319064177UL, 2305067982UL, 3825716413UL, 1543867515UL, 108979478UL, 3089716545UL, 2921391708UL, 2403595525UL, 3783697766UL, 2313991047UL, 3302598706UL, 1318323763UL, +}, +{ +1470380360UL, 3057428612UL, 2756676297UL, 1633786556UL, 4246459918UL, 2557524017UL, 1857180133UL, 618903690UL, 2475611092UL, 2621430634UL, 2084292404UL, 1698607774UL, 1788956972UL, 3375072220UL, 1499167056UL, 1218814632UL, 3699503479UL, 588281768UL, 3603925285UL, 1187721841UL, 1307962320UL, 2562217840UL, 3882506958UL, 2387033730UL, 2097027049UL, 1593669125UL, 1899433035UL, 4039983902UL, 1546854551UL, 1073191673UL, 3368453769UL, 3074694838UL, +534637095UL, 1860006723UL, 3416402670UL, 802354899UL, 3998709605UL, 3944315555UL, 3454226397UL, 1648185195UL, 488532673UL, 3063734121UL, 1318974867UL, 187087202UL, 200160693UL, 4170479404UL, 782764886UL, 4007973657UL, 1651636372UL, 3084151528UL, 2085263921UL, 2424937940UL, 230704223UL, 3342587983UL, 1093085714UL, 683877298UL, 3635026316UL, 3839461209UL, 2977567556UL, 3947448199UL, 3767172681UL, 1350679624UL, 3541409523UL, 3975162472UL, +2459379316UL, 3287828387UL, 1565768431UL, 3149625429UL, 1328627497UL, 2156355750UL, 112739894UL, 4052025045UL, 1396839113UL, 212349044UL, 110706825UL, 2185320852UL, 2540909191UL, 2129623107UL, 3515174750UL, 2669147508UL, 1243549180UL, 3996575850UL, 149304348UL, 2755670869UL, 930137412UL, 350687475UL, 1512442864UL, 3764389325UL, 3489308665UL, 276147411UL, 2268414314UL, 30674096UL, 3202650841UL, 3446821592UL, 3341145621UL, 3749209259UL, +674361204UL, 1384681012UL, 2716655878UL, 454169262UL, 289282175UL, 966029495UL, 3052791893UL, 3111969089UL, 1151599976UL, 3620936019UL, 1877909034UL, 1953262994UL, 4240669039UL, 1857402256UL, 3337397349UL, 2392730459UL, 1158928694UL, 1757447952UL, 2682284750UL, 2796982914UL, 1203210173UL, 797579212UL, 1645601877UL, 3579805998UL, 797556690UL, 4106236617UL, 1379943929UL, 129105346UL, 3950170317UL, 723231430UL, 88997404UL, 2591283275UL, +359831168UL, 306903531UL, 1987846974UL, 2654779951UL, 3724360049UL, 1693615498UL, 1095306415UL, 3586751806UL, 2045807380UL, 2779363615UL, 2912940562UL, 1557518560UL, 3620536996UL, 1723152132UL, 4087191232UL, 1042907094UL, 3210303305UL, 1536493323UL, 4094765090UL, 575328723UL, 359319532UL, 2458971265UL, 3159207510UL, 387883436UL, 2521400838UL, 2359639886UL, 261289463UL, 2094643916UL, 2269112547UL, 2387198764UL, 3619233779UL, 3019052785UL, +2910774311UL, 1470380360UL, 3057428612UL, 2756676297UL, 1633786556UL, 386502519UL, 2557524017UL, 1857180133UL, 618903690UL, 2475611092UL, 30080431UL, 2084292404UL, 1698607774UL, 1788956972UL, 3375072220UL, 1158684464UL, 1218814632UL, 3699503479UL, 588281768UL, 3603925285UL, 238328161UL, 1307962320UL, 2562217840UL, 3882506958UL, 2387033730UL, 3010587639UL, 1593669125UL, 1899433035UL, 4039983902UL, 1546854551UL, 4192218972UL, 3368453769UL, +3074694838UL, 534637095UL, 1860006723UL, 652336168UL, 802354899UL, 3998709605UL, 3944315555UL, 3454226397UL, 1926499185UL, 488532673UL, 3063734121UL, 1318974867UL, 187087202UL, 1106075322UL, 4170479404UL, 782764886UL, 4007973657UL, 1651636372UL, 2404132022UL, 2085263921UL, 2424937940UL, 230704223UL, 3342587983UL, 918664020UL, 683877298UL, 3635026316UL, 3839461209UL, 2977567556UL, 1943458501UL, 3767172681UL, 1350679624UL, 3541409523UL, +3975162472UL, 276593262UL, 3287828387UL, 1565768431UL, 3149625429UL, 1328627497UL, 1428675465UL, 112739894UL, 4052025045UL, 1396839113UL, 212349044UL, 4056830215UL, 2185320852UL, 2540909191UL, 2129623107UL, 3515174750UL, 1542171596UL, 1243549180UL, 3996575850UL, 149304348UL, 2755670869UL, 3578672658UL, 350687475UL, 1512442864UL, 3764389325UL, 3489308665UL, 1546094236UL, 2268414314UL, 30674096UL, 3202650841UL, 3446821592UL, 2954172575UL, +3749209259UL, 674361204UL, 1384681012UL, 2716655878UL, 3784818668UL, 289282175UL, 966029495UL, 3052791893UL, 3111969089UL, 4157356036UL, 3620936019UL, 1877909034UL, 1953262994UL, 4240669039UL, 558548232UL, 3337397349UL, 2392730459UL, 1158928694UL, 1757447952UL, 2764253876UL, 2796982914UL, 1203210173UL, 797579212UL, 1645601877UL, 1754284241UL, 797556690UL, 4106236617UL, 1379943929UL, 129105346UL, 1072954804UL, 723231430UL, 88997404UL, +2591283275UL, 359831168UL, 3790749526UL, 1987846974UL, 2654779951UL, 3724360049UL, 1693615498UL, 529478744UL, 3586751806UL, 2045807380UL, 2779363615UL, 2912940562UL, 3883779003UL, 3620536996UL, 1723152132UL, 4087191232UL, 1042907094UL, 2510614710UL, 1536493323UL, 4094765090UL, 575328723UL, 359319532UL, 4185709932UL, 3159207510UL, 387883436UL, 2521400838UL, 2359639886UL, 143795416UL, 2094643916UL, 2269112547UL, 2387198764UL, 3619233779UL, +2856133500UL, 2910774311UL, 1470380360UL, 3057428612UL, 2756676297UL, 1184346658UL, 386502519UL, 2557524017UL, 1857180133UL, 618903690UL, 113530176UL, 30080431UL, 2084292404UL, 1698607774UL, 1788956972UL, 1446640841UL, 1158684464UL, 1218814632UL, 3699503479UL, 588281768UL, 145530757UL, 238328161UL, 1307962320UL, 2562217840UL, 3882506958UL, 2145494995UL, 3010587639UL, 1593669125UL, 1899433035UL, 4039983902UL, 1668183055UL, 4192218972UL, +3368453769UL, 3074694838UL, 534637095UL, 1759744354UL, 652336168UL, 802354899UL, 3998709605UL, 3944315555UL, 3058692249UL, 1926499185UL, 488532673UL, 3063734121UL, 1318974867UL, 728549366UL, 1106075322UL, 4170479404UL, 782764886UL, 4007973657UL, 3270440405UL, 2404132022UL, 2085263921UL, 2424937940UL, 230704223UL, 3329510499UL, 918664020UL, 683877298UL, 3635026316UL, 3839461209UL, 79335966UL, 1943458501UL, 3767172681UL, 1350679624UL, +3541409523UL, 925084463UL, 276593262UL, 3287828387UL, 1565768431UL, 3149625429UL, 3775346659UL, 1428675465UL, 112739894UL, 4052025045UL, 1396839113UL, 865124022UL, 4056830215UL, 2185320852UL, 2540909191UL, 2129623107UL, 408329043UL, 1542171596UL, 1243549180UL, 3996575850UL, 149304348UL, 3549625626UL, 3578672658UL, 350687475UL, 1512442864UL, 3764389325UL, 2745315161UL, 1546094236UL, 2268414314UL, 30674096UL, 3202650841UL, 1591955495UL, +2954172575UL, 3749209259UL, 674361204UL, 1384681012UL, 4064148122UL, 3784818668UL, 289282175UL, 966029495UL, 3052791893UL, 1370867977UL, 4157356036UL, 3620936019UL, 1877909034UL, 1953262994UL, 4021792514UL, 558548232UL, 3337397349UL, 2392730459UL, 1158928694UL, 3155295174UL, 2764253876UL, 2796982914UL, 1203210173UL, 797579212UL, 3928348491UL, 1754284241UL, 797556690UL, 4106236617UL, 1379943929UL, 535801204UL, 1072954804UL, 723231430UL, +88997404UL, 2591283275UL, 3834650337UL, 3790749526UL, 1987846974UL, 2654779951UL, 3724360049UL, 1042046499UL, 529478744UL, 3586751806UL, 2045807380UL, 2779363615UL, 1125934487UL, 3883779003UL, 3620536996UL, 1723152132UL, 4087191232UL, 234512721UL, 2510614710UL, 1536493323UL, 4094765090UL, 575328723UL, 3997395999UL, 4185709932UL, 3159207510UL, 387883436UL, 2521400838UL, 3125399953UL, 143795416UL, 2094643916UL, 2269112547UL, 2387198764UL, +652167990UL, 2856133500UL, 2910774311UL, 1470380360UL, 3057428612UL, 2132157457UL, 1184346658UL, 386502519UL, 2557524017UL, 1857180133UL, 4131611047UL, 113530176UL, 30080431UL, 2084292404UL, 1698607774UL, 391246724UL, 1446640841UL, 1158684464UL, 1218814632UL, 3699503479UL, 2411874184UL, 145530757UL, 238328161UL, 1307962320UL, 2562217840UL, 2812151676UL, 2145494995UL, 3010587639UL, 1593669125UL, 1899433035UL, 2422208371UL, 1668183055UL, +4192218972UL, 3368453769UL, 3074694838UL, 2148785858UL, 1759744354UL, 652336168UL, 802354899UL, 3998709605UL, 1781938823UL, 3058692249UL, 1926499185UL, 488532673UL, 3063734121UL, 3539633540UL, 728549366UL, 1106075322UL, 4170479404UL, 782764886UL, 2780824417UL, 3270440405UL, 2404132022UL, 2085263921UL, 2424937940UL, 1908513596UL, 3329510499UL, 918664020UL, 683877298UL, 3635026316UL, 2918953355UL, 79335966UL, 1943458501UL, 3767172681UL, +1350679624UL, 341369607UL, 925084463UL, 276593262UL, 3287828387UL, 1565768431UL, 1957429498UL, 3775346659UL, 1428675465UL, 112739894UL, 4052025045UL, 1847440090UL, 865124022UL, 4056830215UL, 2185320852UL, 2540909191UL, 3477402775UL, 408329043UL, 1542171596UL, 1243549180UL, 3996575850UL, 179432054UL, 3549625626UL, 3578672658UL, 350687475UL, 1512442864UL, 2118138924UL, 2745315161UL, 1546094236UL, 2268414314UL, 30674096UL, 2317064191UL, +1591955495UL, 2954172575UL, 3749209259UL, 674361204UL, 3286542168UL, 4064148122UL, 3784818668UL, 289282175UL, 966029495UL, 1327408800UL, 1370867977UL, 4157356036UL, 3620936019UL, 1877909034UL, 405707683UL, 4021792514UL, 558548232UL, 3337397349UL, 2392730459UL, 3244675609UL, 3155295174UL, 2764253876UL, 2796982914UL, 1203210173UL, 2274948223UL, 3928348491UL, 1754284241UL, 797556690UL, 4106236617UL, 2665938417UL, 535801204UL, 1072954804UL, +723231430UL, 88997404UL, 3006584290UL, 3834650337UL, 3790749526UL, 1987846974UL, 2654779951UL, 4271242910UL, 1042046499UL, 529478744UL, 3586751806UL, 2045807380UL, 2283867237UL, 1125934487UL, 3883779003UL, 3620536996UL, 1723152132UL, 1761178713UL, 234512721UL, 2510614710UL, 1536493323UL, 4094765090UL, 2361030279UL, 3997395999UL, 4185709932UL, 3159207510UL, 387883436UL, 3979684113UL, 3125399953UL, 143795416UL, 2094643916UL, 2269112547UL, +1499026790UL, 2673871071UL, 3817604600UL, 2996498142UL, 1211396713UL, 4016438754UL, 992969238UL, 2196610884UL, 1333868752UL, 2722471337UL, 2178395143UL, 533478044UL, 291720336UL, 3552502714UL, 1060260388UL, 1389737501UL, 3508724089UL, 3106493936UL, 2013154532UL, 3169850047UL, 3773175439UL, 3604033115UL, 4234678017UL, 2903156223UL, 3832188501UL, 2874956773UL, 4283805552UL, 3664062691UL, 1974738248UL, 925764827UL, 1750660924UL, 141239116UL, +3273085573UL, 2427940522UL, 1962727892UL, 2493949152UL, 1043482688UL, 2345076260UL, 2209086707UL, 3642865193UL, 3119873884UL, 571850463UL, 1599484831UL, 76923002UL, 3077572436UL, 4086821865UL, 1523654720UL, 480304732UL, 476538774UL, 2169116383UL, 4033618691UL, 2819753414UL, 2856326003UL, 747450871UL, 1851448547UL, 713503330UL, 3709263622UL, 781002495UL, 1968749577UL, 2933719965UL, 4057398020UL, 3406593497UL, 689436820UL, 2935729647UL, +2030357428UL, 2075940397UL, 1830631914UL, 1093330800UL, 1706624613UL, 1805612947UL, 4257097124UL, 3233604448UL, 159450674UL, 1050507045UL, 566046625UL, 2253420120UL, 904902042UL, 1830037922UL, 4081490982UL, 1427186514UL, 2535536470UL, 3869316947UL, 4097476542UL, 930420754UL, 2519255367UL, 49908928UL, 454325685UL, 888118139UL, 3453892181UL, 1263601461UL, 1236190782UL, 674943665UL, 1648077470UL, 429399730UL, 2904879506UL, 3718410520UL, +1802183310UL, 1872553091UL, 605480672UL, 774749173UL, 3200570514UL, 181210046UL, 2560898144UL, 3947027625UL, 1535243167UL, 324801283UL, 4234744788UL, 746560316UL, 2456297875UL, 3925756080UL, 533997731UL, 3919796086UL, 662975152UL, 864661066UL, 1070894403UL, 1020445801UL, 1511298602UL, 4221508348UL, 3577952702UL, 4122306502UL, 2012051572UL, 1616168260UL, 2456901413UL, 2717726537UL, 840264605UL, 2687215223UL, 2174960097UL, 1239122603UL, +2890231920UL, 3365350767UL, 3998868598UL, 563137220UL, 893868530UL, 3400632172UL, 1538627830UL, 2812510298UL, 496662288UL, 2317289974UL, 2252393722UL, 1221289032UL, 2418100559UL, 402670890UL, 1528570045UL, 3160531718UL, 1806492066UL, 3211663975UL, 3617025598UL, 3664580463UL, 1338638297UL, 341637330UL, 2097019728UL, 4031221207UL, 503636424UL, 3883416740UL, 1530237682UL, 1152125396UL, 2845384901UL, 332460372UL, 457364876UL, 1738239808UL, +}, +{ +1118787884UL, 1884590246UL, 1007052798UL, 3717680750UL, 1609263052UL, 2486654530UL, 2761168910UL, 163554565UL, 3928803020UL, 2632714628UL, 1386788970UL, 2621928183UL, 2855206157UL, 2989018213UL, 1836814260UL, 4197635108UL, 1030118238UL, 2789863793UL, 2063944689UL, 1647608366UL, 255485979UL, 3657534664UL, 1317185871UL, 2410074449UL, 3971156607UL, 907575923UL, 4132859581UL, 416269582UL, 877554291UL, 633895348UL, 2236014545UL, 992386759UL, +3971362318UL, 2173597771UL, 1673339632UL, 1371742490UL, 2033574313UL, 3809530180UL, 319182848UL, 1562235776UL, 463522324UL, 1482338913UL, 1816432405UL, 3278626272UL, 1335179249UL, 171265751UL, 2249118654UL, 1153849045UL, 3013179633UL, 1450352108UL, 1267908572UL, 1138658121UL, 623675874UL, 3608469129UL, 978093004UL, 1283228910UL, 1810859539UL, 1179125634UL, 2939039286UL, 3862213960UL, 1168357273UL, 376788629UL, 314507445UL, 219039712UL, +463080619UL, 2994990779UL, 1035692306UL, 2228303916UL, 1280244913UL, 1965417315UL, 1815095408UL, 939691799UL, 3080056566UL, 3741305118UL, 1495905100UL, 65327713UL, 3884301346UL, 2536445014UL, 1503280354UL, 3398924419UL, 3678532805UL, 2616964783UL, 3168581019UL, 3553322118UL, 3023259169UL, 480342712UL, 451634742UL, 3562778450UL, 1943708078UL, 660077747UL, 434714388UL, 2369278293UL, 2894425895UL, 1919542250UL, 2469130567UL, 551196237UL, +4193980239UL, 2952382875UL, 3311173667UL, 2856797012UL, 2845888917UL, 1669184098UL, 3928626091UL, 2491577076UL, 3719464032UL, 2151963814UL, 3474431449UL, 3971510537UL, 3695841119UL, 2215238146UL, 3668152847UL, 1974578319UL, 2328185090UL, 2096356935UL, 3973692455UL, 3954842437UL, 422675402UL, 477894725UL, 3398641827UL, 1366451030UL, 1354642198UL, 3029840461UL, 35700837UL, 2937170986UL, 1336296570UL, 3508313874UL, 587724229UL, 2051237478UL, +3539754304UL, 1946154432UL, 2463932452UL, 144772179UL, 353408424UL, 3493806256UL, 3782958493UL, 1957797444UL, 228084488UL, 192277278UL, 3612092522UL, 2235069734UL, 467407503UL, 3391861572UL, 847810786UL, 1838763654UL, 2272109211UL, 3018265496UL, 4249218445UL, 1722760791UL, 3484353162UL, 3906437663UL, 4208966227UL, 2352549740UL, 714311566UL, 1346246305UL, 2865157059UL, 2989587005UL, 3946819548UL, 3109244860UL, 3885124598UL, 3314346978UL, +952826829UL, 1118787884UL, 1884590246UL, 1007052798UL, 3717680750UL, 1521451317UL, 2486654530UL, 2761168910UL, 163554565UL, 3928803020UL, 2299046195UL, 1386788970UL, 2621928183UL, 2855206157UL, 2989018213UL, 3048269905UL, 4197635108UL, 1030118238UL, 2789863793UL, 2063944689UL, 1814057352UL, 255485979UL, 3657534664UL, 1317185871UL, 2410074449UL, 4041610788UL, 907575923UL, 4132859581UL, 416269582UL, 877554291UL, 2338964683UL, 2236014545UL, +992386759UL, 3971362318UL, 2173597771UL, 579340117UL, 1371742490UL, 2033574313UL, 3809530180UL, 319182848UL, 3090313228UL, 463522324UL, 1482338913UL, 1816432405UL, 3278626272UL, 2418220643UL, 171265751UL, 2249118654UL, 1153849045UL, 3013179633UL, 2738647190UL, 1267908572UL, 1138658121UL, 623675874UL, 3608469129UL, 3096087202UL, 1283228910UL, 1810859539UL, 1179125634UL, 2939039286UL, 2601862091UL, 1168357273UL, 376788629UL, 314507445UL, +219039712UL, 1174181426UL, 2994990779UL, 1035692306UL, 2228303916UL, 1280244913UL, 752017703UL, 1815095408UL, 939691799UL, 3080056566UL, 3741305118UL, 126135654UL, 65327713UL, 3884301346UL, 2536445014UL, 1503280354UL, 955981361UL, 3678532805UL, 2616964783UL, 3168581019UL, 3553322118UL, 3772187171UL, 480342712UL, 451634742UL, 3562778450UL, 1943708078UL, 1466950454UL, 434714388UL, 2369278293UL, 2894425895UL, 1919542250UL, 317862862UL, +551196237UL, 4193980239UL, 2952382875UL, 3311173667UL, 12728591UL, 2845888917UL, 1669184098UL, 3928626091UL, 2491577076UL, 2742989641UL, 2151963814UL, 3474431449UL, 3971510537UL, 3695841119UL, 1005662613UL, 3668152847UL, 1974578319UL, 2328185090UL, 2096356935UL, 3629684995UL, 3954842437UL, 422675402UL, 477894725UL, 3398641827UL, 209352768UL, 1354642198UL, 3029840461UL, 35700837UL, 2937170986UL, 1660777984UL, 3508313874UL, 587724229UL, +2051237478UL, 3539754304UL, 3631430985UL, 2463932452UL, 144772179UL, 353408424UL, 3493806256UL, 3616422021UL, 1957797444UL, 228084488UL, 192277278UL, 3612092522UL, 3638977910UL, 467407503UL, 3391861572UL, 847810786UL, 1838763654UL, 2427237699UL, 3018265496UL, 4249218445UL, 1722760791UL, 3484353162UL, 2322365400UL, 4208966227UL, 2352549740UL, 714311566UL, 1346246305UL, 954101391UL, 2989587005UL, 3946819548UL, 3109244860UL, 3885124598UL, +420941376UL, 952826829UL, 1118787884UL, 1884590246UL, 1007052798UL, 539759724UL, 1521451317UL, 2486654530UL, 2761168910UL, 163554565UL, 1954997983UL, 2299046195UL, 1386788970UL, 2621928183UL, 2855206157UL, 3104695189UL, 3048269905UL, 4197635108UL, 1030118238UL, 2789863793UL, 3556473570UL, 1814057352UL, 255485979UL, 3657534664UL, 1317185871UL, 3004205219UL, 4041610788UL, 907575923UL, 4132859581UL, 416269582UL, 2980178044UL, 2338964683UL, +2236014545UL, 992386759UL, 3971362318UL, 2573125018UL, 579340117UL, 1371742490UL, 2033574313UL, 3809530180UL, 766585731UL, 3090313228UL, 463522324UL, 1482338913UL, 1816432405UL, 3101578277UL, 2418220643UL, 171265751UL, 2249118654UL, 1153849045UL, 2143267892UL, 2738647190UL, 1267908572UL, 1138658121UL, 623675874UL, 2944231951UL, 3096087202UL, 1283228910UL, 1810859539UL, 1179125634UL, 374714364UL, 2601862091UL, 1168357273UL, 376788629UL, +314507445UL, 1710922505UL, 1174181426UL, 2994990779UL, 1035692306UL, 2228303916UL, 3222680885UL, 752017703UL, 1815095408UL, 939691799UL, 3080056566UL, 1985366287UL, 126135654UL, 65327713UL, 3884301346UL, 2536445014UL, 3002467868UL, 955981361UL, 3678532805UL, 2616964783UL, 3168581019UL, 2173417616UL, 3772187171UL, 480342712UL, 451634742UL, 3562778450UL, 236095606UL, 1466950454UL, 434714388UL, 2369278293UL, 2894425895UL, 1766257461UL, +317862862UL, 551196237UL, 4193980239UL, 2952382875UL, 2416349742UL, 12728591UL, 2845888917UL, 1669184098UL, 3928626091UL, 2346338391UL, 2742989641UL, 2151963814UL, 3474431449UL, 3971510537UL, 942354812UL, 1005662613UL, 3668152847UL, 1974578319UL, 2328185090UL, 3234982376UL, 3629684995UL, 3954842437UL, 422675402UL, 477894725UL, 2931444539UL, 209352768UL, 1354642198UL, 3029840461UL, 35700837UL, 3388567298UL, 1660777984UL, 3508313874UL, +587724229UL, 2051237478UL, 1770178720UL, 3631430985UL, 2463932452UL, 144772179UL, 353408424UL, 3783114255UL, 3616422021UL, 1957797444UL, 228084488UL, 192277278UL, 611095909UL, 3638977910UL, 467407503UL, 3391861572UL, 847810786UL, 1413548572UL, 2427237699UL, 3018265496UL, 4249218445UL, 1722760791UL, 1487262638UL, 2322365400UL, 4208966227UL, 2352549740UL, 714311566UL, 1378213368UL, 954101391UL, 2989587005UL, 3946819548UL, 3109244860UL, +4183748384UL, 420941376UL, 952826829UL, 1118787884UL, 1884590246UL, 2199811809UL, 539759724UL, 1521451317UL, 2486654530UL, 2761168910UL, 1100080647UL, 1954997983UL, 2299046195UL, 1386788970UL, 2621928183UL, 916352763UL, 3104695189UL, 3048269905UL, 4197635108UL, 1030118238UL, 369866139UL, 3556473570UL, 1814057352UL, 255485979UL, 3657534664UL, 2916985473UL, 3004205219UL, 4041610788UL, 907575923UL, 4132859581UL, 3856599532UL, 2980178044UL, +2338964683UL, 2236014545UL, 992386759UL, 3393662326UL, 2573125018UL, 579340117UL, 1371742490UL, 2033574313UL, 1938766053UL, 766585731UL, 3090313228UL, 463522324UL, 1482338913UL, 2122086302UL, 3101578277UL, 2418220643UL, 171265751UL, 2249118654UL, 952602228UL, 2143267892UL, 2738647190UL, 1267908572UL, 1138658121UL, 1808026803UL, 2944231951UL, 3096087202UL, 1283228910UL, 1810859539UL, 3881666794UL, 374714364UL, 2601862091UL, 1168357273UL, +376788629UL, 728738466UL, 1710922505UL, 1174181426UL, 2994990779UL, 1035692306UL, 74930675UL, 3222680885UL, 752017703UL, 1815095408UL, 939691799UL, 3404352271UL, 1985366287UL, 126135654UL, 65327713UL, 3884301346UL, 1822629733UL, 3002467868UL, 955981361UL, 3678532805UL, 2616964783UL, 3865359567UL, 2173417616UL, 3772187171UL, 480342712UL, 451634742UL, 1099609112UL, 236095606UL, 1466950454UL, 434714388UL, 2369278293UL, 2671873359UL, +1766257461UL, 317862862UL, 551196237UL, 4193980239UL, 2006763654UL, 2416349742UL, 12728591UL, 2845888917UL, 1669184098UL, 2492983893UL, 2346338391UL, 2742989641UL, 2151963814UL, 3474431449UL, 2095232649UL, 942354812UL, 1005662613UL, 3668152847UL, 1974578319UL, 1748794756UL, 3234982376UL, 3629684995UL, 3954842437UL, 422675402UL, 2291986911UL, 2931444539UL, 209352768UL, 1354642198UL, 3029840461UL, 3772709822UL, 3388567298UL, 1660777984UL, +3508313874UL, 587724229UL, 2759789003UL, 1770178720UL, 3631430985UL, 2463932452UL, 144772179UL, 1572181309UL, 3783114255UL, 3616422021UL, 1957797444UL, 228084488UL, 4106643586UL, 611095909UL, 3638977910UL, 467407503UL, 3391861572UL, 927151111UL, 1413548572UL, 2427237699UL, 3018265496UL, 4249218445UL, 692575565UL, 1487262638UL, 2322365400UL, 4208966227UL, 2352549740UL, 1281886506UL, 1378213368UL, 954101391UL, 2989587005UL, 3946819548UL, +1861811740UL, 1484768905UL, 359662140UL, 4058479705UL, 1306547382UL, 514617018UL, 1685692791UL, 3370601554UL, 2920029077UL, 447798803UL, 3124262580UL, 1841693810UL, 583764638UL, 853545489UL, 2614348705UL, 1445696741UL, 4226719361UL, 1299450005UL, 7404137UL, 3158806368UL, 3487160245UL, 1410910965UL, 3697116584UL, 4272452035UL, 832215403UL, 4190877996UL, 2360539465UL, 1011144434UL, 546018244UL, 613443074UL, 2523894977UL, 998991923UL, +2569220540UL, 4221264346UL, 2627827148UL, 2606458015UL, 261584257UL, 4172552877UL, 1174774061UL, 1040006970UL, 2378868955UL, 1539192255UL, 1322624483UL, 3221782707UL, 3352886416UL, 3634686692UL, 65447704UL, 3962131218UL, 839088053UL, 4154193716UL, 1211888926UL, 319402483UL, 3922826413UL, 3799829447UL, 623726612UL, 1586183272UL, 1853729462UL, 2621029589UL, 708558605UL, 1618007233UL, 2784732545UL, 953859039UL, 921654620UL, 477148727UL, +3592256598UL, 2772318818UL, 1460772911UL, 1309227716UL, 3484274262UL, 3425161241UL, 1677052569UL, 2238155114UL, 2828087292UL, 2361598991UL, 4283732706UL, 1530059373UL, 1564048492UL, 243829114UL, 104328994UL, 3080249237UL, 2054985396UL, 408961407UL, 2978652320UL, 2412674552UL, 3794618070UL, 3644862703UL, 2095186402UL, 3294126752UL, 2970218740UL, 1800713612UL, 3806665216UL, 3990918051UL, 142666452UL, 531078813UL, 1079142774UL, 3437358350UL, +635943961UL, 255576894UL, 2991317718UL, 1208676456UL, 247449774UL, 454879171UL, 113230697UL, 3064123371UL, 336269028UL, 1137083842UL, 959568850UL, 2508623991UL, 3338418112UL, 2660268938UL, 1318010299UL, 3950178561UL, 1078499199UL, 1176289535UL, 3875152821UL, 1984420952UL, 1134199826UL, 2944539174UL, 3667625203UL, 2034152216UL, 1648355307UL, 2376447620UL, 2967418253UL, 185143450UL, 889002925UL, 3999315013UL, 661455858UL, 4026799358UL, +3626504428UL, 3544795311UL, 3642718771UL, 2467387138UL, 1034249749UL, 2051371333UL, 4251353248UL, 1575036366UL, 751400924UL, 2906720214UL, 1210002606UL, 916508568UL, 1728487600UL, 2478884914UL, 3081526615UL, 1867135009UL, 1955998382UL, 701713417UL, 512784398UL, 1255240210UL, 3665676113UL, 1771754697UL, 4000392442UL, 3342268855UL, 2677221913UL, 369054145UL, 4011912082UL, 748537647UL, 1626721797UL, 852497405UL, 168721778UL, 3091138383UL, +}, +{ +3781228998UL, 1787582256UL, 838267218UL, 2710632450UL, 690892139UL, 2484870604UL, 4151302318UL, 1844787776UL, 727768263UL, 1075391038UL, 1842903369UL, 2927332301UL, 3246688068UL, 1234715005UL, 2906526190UL, 3369636401UL, 3091858538UL, 3320767682UL, 920496809UL, 1406803705UL, 3163880457UL, 1540551653UL, 2733620168UL, 2588558057UL, 147277542UL, 803170440UL, 821275940UL, 3897549272UL, 151390608UL, 951639139UL, 904639695UL, 1106545578UL, +1514893712UL, 998760135UL, 2557458623UL, 4109877399UL, 578824730UL, 2174064027UL, 3352513900UL, 3206168298UL, 911932439UL, 2030004973UL, 3283902592UL, 3755877921UL, 250434692UL, 352122318UL, 977153640UL, 642640734UL, 2555395772UL, 2307695537UL, 2593565626UL, 3738143618UL, 734614254UL, 3276420511UL, 2636087597UL, 4157371578UL, 1082026387UL, 429736987UL, 3755125580UL, 1935957937UL, 3300547146UL, 3089498232UL, 4167244256UL, 1619189426UL, +1094447351UL, 1061842570UL, 3666470174UL, 810916769UL, 2263633079UL, 3863543843UL, 1804937521UL, 2774236887UL, 2858593613UL, 961498236UL, 1515309045UL, 1564424234UL, 2276602447UL, 2540994858UL, 78621171UL, 3575132456UL, 2958793283UL, 387554009UL, 688827573UL, 3833764146UL, 2611524056UL, 2296780370UL, 2411775612UL, 3790615886UL, 3399757437UL, 1385198595UL, 1005364336UL, 2093159919UL, 2091827252UL, 1461775197UL, 4225171212UL, 1185831033UL, +12264437UL, 1313835999UL, 556653278UL, 917105970UL, 1471530347UL, 2010243509UL, 3097827138UL, 1399987735UL, 273352191UL, 2505795417UL, 1336824946UL, 3358720963UL, 2874295267UL, 2282349617UL, 3478581038UL, 4027859424UL, 713597958UL, 4059691816UL, 2812811116UL, 2291324146UL, 932688463UL, 3001334051UL, 2028368589UL, 830582457UL, 3964293916UL, 4276849132UL, 1828058403UL, 1351688755UL, 2113265048UL, 42517349UL, 3100438883UL, 1137792178UL, +1479076106UL, 463377892UL, 3964913740UL, 2422362185UL, 436113863UL, 2044139049UL, 4197323265UL, 3275185975UL, 2655265571UL, 1674107588UL, 1496360114UL, 3642050139UL, 1739051417UL, 2393774399UL, 250035802UL, 10186306UL, 263338568UL, 3899157617UL, 3679157076UL, 2258085991UL, 1407319575UL, 899008067UL, 3679828833UL, 711086272UL, 2952963707UL, 3373894808UL, 445540851UL, 3405637490UL, 1343291195UL, 730888681UL, 507768703UL, 3473963321UL, +1779803564UL, 3781228998UL, 1787582256UL, 838267218UL, 2710632450UL, 2431224659UL, 2484870604UL, 4151302318UL, 1844787776UL, 727768263UL, 4012573268UL, 1842903369UL, 2927332301UL, 3246688068UL, 1234715005UL, 3405161215UL, 3369636401UL, 3091858538UL, 3320767682UL, 920496809UL, 400609988UL, 3163880457UL, 1540551653UL, 2733620168UL, 2588558057UL, 2137935937UL, 803170440UL, 821275940UL, 3897549272UL, 151390608UL, 194431797UL, 904639695UL, +1106545578UL, 1514893712UL, 998760135UL, 62528087UL, 4109877399UL, 578824730UL, 2174064027UL, 3352513900UL, 3495516649UL, 911932439UL, 2030004973UL, 3283902592UL, 3755877921UL, 1774462108UL, 352122318UL, 977153640UL, 642640734UL, 2555395772UL, 756528792UL, 2593565626UL, 3738143618UL, 734614254UL, 3276420511UL, 4086313763UL, 4157371578UL, 1082026387UL, 429736987UL, 3755125580UL, 526056489UL, 3300547146UL, 3089498232UL, 4167244256UL, +1619189426UL, 82235109UL, 1061842570UL, 3666470174UL, 810916769UL, 2263633079UL, 1110270726UL, 1804937521UL, 2774236887UL, 2858593613UL, 961498236UL, 1840197918UL, 1564424234UL, 2276602447UL, 2540994858UL, 78621171UL, 3690913528UL, 2958793283UL, 387554009UL, 688827573UL, 3833764146UL, 3626285597UL, 2296780370UL, 2411775612UL, 3790615886UL, 3399757437UL, 1561545830UL, 1005364336UL, 2093159919UL, 2091827252UL, 1461775197UL, 63358970UL, +1185831033UL, 12264437UL, 1313835999UL, 556653278UL, 3918754976UL, 1471530347UL, 2010243509UL, 3097827138UL, 1399987735UL, 2767111911UL, 2505795417UL, 1336824946UL, 3358720963UL, 2874295267UL, 902314853UL, 3478581038UL, 4027859424UL, 713597958UL, 4059691816UL, 1462989647UL, 2291324146UL, 932688463UL, 3001334051UL, 2028368589UL, 3594712587UL, 3964293916UL, 4276849132UL, 1828058403UL, 1351688755UL, 2571513800UL, 42517349UL, 3100438883UL, +1137792178UL, 1479076106UL, 140519541UL, 3964913740UL, 2422362185UL, 436113863UL, 2044139049UL, 226785542UL, 3275185975UL, 2655265571UL, 1674107588UL, 1496360114UL, 46428973UL, 1739051417UL, 2393774399UL, 250035802UL, 10186306UL, 4118320101UL, 3899157617UL, 3679157076UL, 2258085991UL, 1407319575UL, 4267866849UL, 3679828833UL, 711086272UL, 2952963707UL, 3373894808UL, 3662249794UL, 3405637490UL, 1343291195UL, 730888681UL, 507768703UL, +2930510271UL, 1779803564UL, 3781228998UL, 1787582256UL, 838267218UL, 1817693489UL, 2431224659UL, 2484870604UL, 4151302318UL, 1844787776UL, 1788220652UL, 4012573268UL, 1842903369UL, 2927332301UL, 3246688068UL, 2050648011UL, 3405161215UL, 3369636401UL, 3091858538UL, 3320767682UL, 241001958UL, 400609988UL, 3163880457UL, 1540551653UL, 2733620168UL, 3857223520UL, 2137935937UL, 803170440UL, 821275940UL, 3897549272UL, 1451986523UL, 194431797UL, +904639695UL, 1106545578UL, 1514893712UL, 4147878244UL, 62528087UL, 4109877399UL, 578824730UL, 2174064027UL, 461571251UL, 3495516649UL, 911932439UL, 2030004973UL, 3283902592UL, 1580354765UL, 1774462108UL, 352122318UL, 977153640UL, 642640734UL, 1019387737UL, 756528792UL, 2593565626UL, 3738143618UL, 734614254UL, 999431451UL, 4086313763UL, 4157371578UL, 1082026387UL, 429736987UL, 140091634UL, 526056489UL, 3300547146UL, 3089498232UL, +4167244256UL, 3202763095UL, 82235109UL, 1061842570UL, 3666470174UL, 810916769UL, 3663992550UL, 1110270726UL, 1804937521UL, 2774236887UL, 2858593613UL, 2203639366UL, 1840197918UL, 1564424234UL, 2276602447UL, 2540994858UL, 978199281UL, 3690913528UL, 2958793283UL, 387554009UL, 688827573UL, 375113876UL, 3626285597UL, 2296780370UL, 2411775612UL, 3790615886UL, 1277897939UL, 1561545830UL, 1005364336UL, 2093159919UL, 2091827252UL, 1631078873UL, +63358970UL, 1185831033UL, 12264437UL, 1313835999UL, 3872277948UL, 3918754976UL, 1471530347UL, 2010243509UL, 3097827138UL, 1291836608UL, 2767111911UL, 2505795417UL, 1336824946UL, 3358720963UL, 3954754615UL, 902314853UL, 3478581038UL, 4027859424UL, 713597958UL, 2198246306UL, 1462989647UL, 2291324146UL, 932688463UL, 3001334051UL, 2374736511UL, 3594712587UL, 3964293916UL, 4276849132UL, 1828058403UL, 3619038368UL, 2571513800UL, 42517349UL, +3100438883UL, 1137792178UL, 1146435746UL, 140519541UL, 3964913740UL, 2422362185UL, 436113863UL, 3460540392UL, 226785542UL, 3275185975UL, 2655265571UL, 1674107588UL, 1288223861UL, 46428973UL, 1739051417UL, 2393774399UL, 250035802UL, 1986226858UL, 4118320101UL, 3899157617UL, 3679157076UL, 2258085991UL, 551117761UL, 4267866849UL, 3679828833UL, 711086272UL, 2952963707UL, 1667866621UL, 3662249794UL, 3405637490UL, 1343291195UL, 730888681UL, +2381246695UL, 2930510271UL, 1779803564UL, 3781228998UL, 1787582256UL, 1236367773UL, 1817693489UL, 2431224659UL, 2484870604UL, 4151302318UL, 2902321811UL, 1788220652UL, 4012573268UL, 1842903369UL, 2927332301UL, 1185539274UL, 2050648011UL, 3405161215UL, 3369636401UL, 3091858538UL, 4240555382UL, 241001958UL, 400609988UL, 3163880457UL, 1540551653UL, 2539098607UL, 3857223520UL, 2137935937UL, 803170440UL, 821275940UL, 3485313735UL, 1451986523UL, +194431797UL, 904639695UL, 1106545578UL, 1633417190UL, 4147878244UL, 62528087UL, 4109877399UL, 578824730UL, 3671726812UL, 461571251UL, 3495516649UL, 911932439UL, 2030004973UL, 2002341352UL, 1580354765UL, 1774462108UL, 352122318UL, 977153640UL, 170033402UL, 1019387737UL, 756528792UL, 2593565626UL, 3738143618UL, 4160516213UL, 999431451UL, 4086313763UL, 4157371578UL, 1082026387UL, 1423352480UL, 140091634UL, 526056489UL, 3300547146UL, +3089498232UL, 4266971502UL, 3202763095UL, 82235109UL, 1061842570UL, 3666470174UL, 945994616UL, 3663992550UL, 1110270726UL, 1804937521UL, 2774236887UL, 3776581315UL, 2203639366UL, 1840197918UL, 1564424234UL, 2276602447UL, 928117829UL, 978199281UL, 3690913528UL, 2958793283UL, 387554009UL, 2817496615UL, 375113876UL, 3626285597UL, 2296780370UL, 2411775612UL, 1346030561UL, 1277897939UL, 1561545830UL, 1005364336UL, 2093159919UL, 821902776UL, +1631078873UL, 63358970UL, 1185831033UL, 12264437UL, 3192617499UL, 3872277948UL, 3918754976UL, 1471530347UL, 2010243509UL, 4011062105UL, 1291836608UL, 2767111911UL, 2505795417UL, 1336824946UL, 1593119272UL, 3954754615UL, 902314853UL, 3478581038UL, 4027859424UL, 1163079365UL, 2198246306UL, 1462989647UL, 2291324146UL, 932688463UL, 4018333691UL, 2374736511UL, 3594712587UL, 3964293916UL, 4276849132UL, 3902062310UL, 3619038368UL, 2571513800UL, +42517349UL, 3100438883UL, 1645455709UL, 1146435746UL, 140519541UL, 3964913740UL, 2422362185UL, 3338363150UL, 3460540392UL, 226785542UL, 3275185975UL, 2655265571UL, 3789582441UL, 1288223861UL, 46428973UL, 1739051417UL, 2393774399UL, 2257001236UL, 1986226858UL, 4118320101UL, 3899157617UL, 3679157076UL, 3707520907UL, 551117761UL, 4267866849UL, 3679828833UL, 711086272UL, 570153549UL, 1667866621UL, 3662249794UL, 3405637490UL, 1343291195UL, +112368058UL, 2615115584UL, 2865130041UL, 357584504UL, 528807633UL, 1816055434UL, 2854850066UL, 190222907UL, 1014915859UL, 3472967123UL, 2605782564UL, 3353130066UL, 540430076UL, 2087143725UL, 1571283916UL, 1604766425UL, 934199876UL, 3359569795UL, 4168578472UL, 1745876717UL, 277026333UL, 2679446726UL, 3582165485UL, 3954458991UL, 2615245404UL, 2410035461UL, 3442004248UL, 2814474875UL, 1734556428UL, 2653422310UL, 4033890533UL, 2373774914UL, +3011118469UL, 1276695464UL, 2995405818UL, 782363735UL, 2242531852UL, 4206829780UL, 1486885236UL, 3764707851UL, 1945614253UL, 1147926733UL, 701960774UL, 3435251514UL, 3626050187UL, 3587799538UL, 2399216643UL, 3217822006UL, 3600044386UL, 648239752UL, 2997947488UL, 1754097052UL, 4109638936UL, 3413714077UL, 1038375790UL, 3394259389UL, 2284776380UL, 2711956471UL, 1278424040UL, 1272230764UL, 3980809660UL, 1983901240UL, 894405781UL, 582621606UL, +1274260631UL, 763432985UL, 1862236664UL, 10249416UL, 3838574116UL, 1912270458UL, 3491686662UL, 2696669149UL, 312119069UL, 1812714569UL, 2729307370UL, 3045249652UL, 303684944UL, 503720764UL, 4029412414UL, 4101616421UL, 3484358948UL, 1261027935UL, 145713434UL, 2918444923UL, 2099546237UL, 3173693583UL, 3498398823UL, 3769717769UL, 2860220116UL, 2919562911UL, 1221047715UL, 1749384742UL, 1018968146UL, 2771587474UL, 2746107326UL, 1182859751UL, +2403805226UL, 2206395932UL, 1500348209UL, 1762634532UL, 3017223998UL, 2043185588UL, 2124568729UL, 1619852613UL, 3248258238UL, 3393223375UL, 644860154UL, 2465108160UL, 2358875673UL, 3643741304UL, 1891106916UL, 416443047UL, 3298583974UL, 1030877276UL, 2839390034UL, 4181398645UL, 1845333999UL, 3643365079UL, 1993116780UL, 1763857175UL, 1951718545UL, 3785659537UL, 4156412284UL, 4138026128UL, 3480291142UL, 54280556UL, 4169041146UL, 3130638398UL, +3236816184UL, 3559898998UL, 916420843UL, 938920758UL, 3425021599UL, 1528477728UL, 3597939783UL, 3516249439UL, 936528538UL, 4174817780UL, 2541489033UL, 3962368135UL, 2054336507UL, 2610093970UL, 3613025255UL, 3583905994UL, 2990129491UL, 332823408UL, 2505138276UL, 3811707598UL, 373987627UL, 4263703898UL, 1668946560UL, 3213253899UL, 2673819338UL, 1631405099UL, 3127443274UL, 549232331UL, 21447814UL, 1647238011UL, 3093799993UL, 1922712395UL, +}, +{ +4224788259UL, 3569487556UL, 1080137041UL, 2788623569UL, 856160888UL, 2195536417UL, 3030463035UL, 2906439247UL, 896055051UL, 1967105456UL, 2093562169UL, 2919742950UL, 546374698UL, 1372591815UL, 3773616637UL, 349073007UL, 1331102855UL, 3035367896UL, 1222622311UL, 2266618592UL, 74466398UL, 1140488004UL, 855606859UL, 3803728487UL, 3589743162UL, 2748402856UL, 1044387368UL, 1494850922UL, 2242660891UL, 3111566003UL, 2013737074UL, 163276737UL, +1526772858UL, 3047139947UL, 3150695453UL, 2583795468UL, 3628272447UL, 305282258UL, 2151108134UL, 2905708853UL, 1052800761UL, 3354632338UL, 1017036861UL, 2453680791UL, 2673902555UL, 1622154585UL, 2893733051UL, 3888482522UL, 306284440UL, 3245137245UL, 3480776670UL, 2865396581UL, 3571456526UL, 3284891766UL, 1393584874UL, 1057867320UL, 2888126310UL, 3302325443UL, 4135187530UL, 1770789166UL, 1615533805UL, 1438727397UL, 2921922012UL, 3156703516UL, +435047591UL, 2999350446UL, 575044884UL, 1001339111UL, 625824120UL, 2489346227UL, 2104489492UL, 2494528446UL, 1141458836UL, 4048430074UL, 2599022749UL, 2438694106UL, 1443850072UL, 3321658999UL, 87870515UL, 958195816UL, 380666771UL, 3062272732UL, 4178548642UL, 4274603044UL, 888566831UL, 3386636024UL, 1636806704UL, 2400069397UL, 3003029365UL, 1953620944UL, 3278772216UL, 1562778171UL, 2767090642UL, 14436957UL, 913966574UL, 1724553886UL, +2015261135UL, 4191296122UL, 1688939147UL, 110865735UL, 2913800286UL, 4131469475UL, 315962755UL, 1531174227UL, 1226678476UL, 3446400266UL, 3896297836UL, 539834883UL, 2871306264UL, 3333932675UL, 2229436010UL, 1928458456UL, 464682640UL, 1786180352UL, 162599143UL, 817038005UL, 3146256537UL, 1676400403UL, 2484731087UL, 702610427UL, 4005124049UL, 1691076958UL, 1268494739UL, 4093608833UL, 3757213737UL, 2627839929UL, 2884764386UL, 1548110665UL, +3361745333UL, 3955318088UL, 3264527857UL, 3969225726UL, 968269281UL, 2630991382UL, 2716444139UL, 1071781623UL, 3704437685UL, 1511193802UL, 843840414UL, 1277966236UL, 4141095880UL, 715016637UL, 1255888181UL, 1321941951UL, 1180174408UL, 1021629824UL, 3395369301UL, 3912221525UL, 2611782663UL, 4038117717UL, 2253029302UL, 974431991UL, 347200257UL, 886823557UL, 2275848777UL, 3732452739UL, 3708953729UL, 2688020866UL, 4185175489UL, 99605353UL, +2387945286UL, 4224788259UL, 3569487556UL, 1080137041UL, 2788623569UL, 238715294UL, 2195536417UL, 3030463035UL, 2906439247UL, 896055051UL, 3061240402UL, 2093562169UL, 2919742950UL, 546374698UL, 1372591815UL, 851057115UL, 349073007UL, 1331102855UL, 3035367896UL, 1222622311UL, 3305595574UL, 74466398UL, 1140488004UL, 855606859UL, 3803728487UL, 3838112757UL, 2748402856UL, 1044387368UL, 1494850922UL, 2242660891UL, 1038286760UL, 2013737074UL, +163276737UL, 1526772858UL, 3047139947UL, 3518918891UL, 2583795468UL, 3628272447UL, 305282258UL, 2151108134UL, 3555155951UL, 1052800761UL, 3354632338UL, 1017036861UL, 2453680791UL, 2394691836UL, 1622154585UL, 2893733051UL, 3888482522UL, 306284440UL, 2055552069UL, 3480776670UL, 2865396581UL, 3571456526UL, 3284891766UL, 1179339312UL, 1057867320UL, 2888126310UL, 3302325443UL, 4135187530UL, 683364318UL, 1615533805UL, 1438727397UL, 2921922012UL, +3156703516UL, 1333086260UL, 2999350446UL, 575044884UL, 1001339111UL, 625824120UL, 576119652UL, 2104489492UL, 2494528446UL, 1141458836UL, 4048430074UL, 786660788UL, 2438694106UL, 1443850072UL, 3321658999UL, 87870515UL, 457955380UL, 380666771UL, 3062272732UL, 4178548642UL, 4274603044UL, 2256710588UL, 3386636024UL, 1636806704UL, 2400069397UL, 3003029365UL, 3733049985UL, 3278772216UL, 1562778171UL, 2767090642UL, 14436957UL, 530062778UL, +1724553886UL, 2015261135UL, 4191296122UL, 1688939147UL, 2981240708UL, 2913800286UL, 4131469475UL, 315962755UL, 1531174227UL, 2433363617UL, 3446400266UL, 3896297836UL, 539834883UL, 2871306264UL, 2597546929UL, 2229436010UL, 1928458456UL, 464682640UL, 1786180352UL, 1165821797UL, 817038005UL, 3146256537UL, 1676400403UL, 2484731087UL, 3239493343UL, 4005124049UL, 1691076958UL, 1268494739UL, 4093608833UL, 2088690204UL, 2627839929UL, 2884764386UL, +1548110665UL, 3361745333UL, 1075350364UL, 3264527857UL, 3969225726UL, 968269281UL, 2630991382UL, 4103280359UL, 1071781623UL, 3704437685UL, 1511193802UL, 843840414UL, 1340474980UL, 4141095880UL, 715016637UL, 1255888181UL, 1321941951UL, 2512565938UL, 1021629824UL, 3395369301UL, 3912221525UL, 2611782663UL, 2287272047UL, 2253029302UL, 974431991UL, 347200257UL, 886823557UL, 3775715445UL, 3732452739UL, 3708953729UL, 2688020866UL, 4185175489UL, +2151114047UL, 2387945286UL, 4224788259UL, 3569487556UL, 1080137041UL, 879682447UL, 238715294UL, 2195536417UL, 3030463035UL, 2906439247UL, 3975397430UL, 3061240402UL, 2093562169UL, 2919742950UL, 546374698UL, 1928060945UL, 851057115UL, 349073007UL, 1331102855UL, 3035367896UL, 1148668613UL, 3305595574UL, 74466398UL, 1140488004UL, 855606859UL, 917923571UL, 3838112757UL, 2748402856UL, 1044387368UL, 1494850922UL, 995791756UL, 1038286760UL, +2013737074UL, 163276737UL, 1526772858UL, 1944370085UL, 3518918891UL, 2583795468UL, 3628272447UL, 305282258UL, 685261037UL, 3555155951UL, 1052800761UL, 3354632338UL, 1017036861UL, 1620076466UL, 2394691836UL, 1622154585UL, 2893733051UL, 3888482522UL, 4119309151UL, 2055552069UL, 3480776670UL, 2865396581UL, 3571456526UL, 4008552940UL, 1179339312UL, 1057867320UL, 2888126310UL, 3302325443UL, 2359989247UL, 683364318UL, 1615533805UL, 1438727397UL, +2921922012UL, 2092991022UL, 1333086260UL, 2999350446UL, 575044884UL, 1001339111UL, 2406217399UL, 576119652UL, 2104489492UL, 2494528446UL, 1141458836UL, 1856565466UL, 786660788UL, 2438694106UL, 1443850072UL, 3321658999UL, 2752588925UL, 457955380UL, 380666771UL, 3062272732UL, 4178548642UL, 1354877973UL, 2256710588UL, 3386636024UL, 1636806704UL, 2400069397UL, 2275777233UL, 3733049985UL, 3278772216UL, 1562778171UL, 2767090642UL, 3438624166UL, +530062778UL, 1724553886UL, 2015261135UL, 4191296122UL, 3842215040UL, 2981240708UL, 2913800286UL, 4131469475UL, 315962755UL, 2891870900UL, 2433363617UL, 3446400266UL, 3896297836UL, 539834883UL, 1390877376UL, 2597546929UL, 2229436010UL, 1928458456UL, 464682640UL, 1405678725UL, 1165821797UL, 817038005UL, 3146256537UL, 1676400403UL, 9522151UL, 3239493343UL, 4005124049UL, 1691076958UL, 1268494739UL, 4076978821UL, 2088690204UL, 2627839929UL, +2884764386UL, 1548110665UL, 3713129550UL, 1075350364UL, 3264527857UL, 3969225726UL, 968269281UL, 2669129178UL, 4103280359UL, 1071781623UL, 3704437685UL, 1511193802UL, 2032747975UL, 1340474980UL, 4141095880UL, 715016637UL, 1255888181UL, 1290704077UL, 2512565938UL, 1021629824UL, 3395369301UL, 3912221525UL, 767420943UL, 2287272047UL, 2253029302UL, 974431991UL, 347200257UL, 940587649UL, 3775715445UL, 3732452739UL, 3708953729UL, 2688020866UL, +1603856534UL, 2151114047UL, 2387945286UL, 4224788259UL, 3569487556UL, 4060395365UL, 879682447UL, 238715294UL, 2195536417UL, 3030463035UL, 774839173UL, 3975397430UL, 3061240402UL, 2093562169UL, 2919742950UL, 77503099UL, 1928060945UL, 851057115UL, 349073007UL, 1331102855UL, 4216140027UL, 1148668613UL, 3305595574UL, 74466398UL, 1140488004UL, 1728766104UL, 917923571UL, 3838112757UL, 2748402856UL, 1044387368UL, 1408900577UL, 995791756UL, +1038286760UL, 2013737074UL, 163276737UL, 936142172UL, 1944370085UL, 3518918891UL, 2583795468UL, 3628272447UL, 1701372078UL, 685261037UL, 3555155951UL, 1052800761UL, 3354632338UL, 2951922777UL, 1620076466UL, 2394691836UL, 1622154585UL, 2893733051UL, 2494523614UL, 4119309151UL, 2055552069UL, 3480776670UL, 2865396581UL, 3031455484UL, 4008552940UL, 1179339312UL, 1057867320UL, 2888126310UL, 2970791558UL, 2359989247UL, 683364318UL, 1615533805UL, +1438727397UL, 3697460033UL, 2092991022UL, 1333086260UL, 2999350446UL, 575044884UL, 2712063736UL, 2406217399UL, 576119652UL, 2104489492UL, 2494528446UL, 1096189230UL, 1856565466UL, 786660788UL, 2438694106UL, 1443850072UL, 3615481975UL, 2752588925UL, 457955380UL, 380666771UL, 3062272732UL, 2387056252UL, 1354877973UL, 2256710588UL, 3386636024UL, 1636806704UL, 517188972UL, 2275777233UL, 3733049985UL, 3278772216UL, 1562778171UL, 3436331606UL, +3438624166UL, 530062778UL, 1724553886UL, 2015261135UL, 1711407722UL, 3842215040UL, 2981240708UL, 2913800286UL, 4131469475UL, 878455086UL, 2891870900UL, 2433363617UL, 3446400266UL, 3896297836UL, 4251949215UL, 1390877376UL, 2597546929UL, 2229436010UL, 1928458456UL, 719826541UL, 1405678725UL, 1165821797UL, 817038005UL, 3146256537UL, 3883590627UL, 9522151UL, 3239493343UL, 4005124049UL, 1691076958UL, 893183073UL, 4076978821UL, 2088690204UL, +2627839929UL, 2884764386UL, 3312769297UL, 3713129550UL, 1075350364UL, 3264527857UL, 3969225726UL, 4161107579UL, 2669129178UL, 4103280359UL, 1071781623UL, 3704437685UL, 1400940789UL, 2032747975UL, 1340474980UL, 4141095880UL, 715016637UL, 1705234794UL, 1290704077UL, 2512565938UL, 1021629824UL, 3395369301UL, 2934074199UL, 767420943UL, 2287272047UL, 2253029302UL, 974431991UL, 3060035390UL, 940587649UL, 3775715445UL, 3732452739UL, 3708953729UL, +3489160434UL, 3200799223UL, 340420813UL, 2539294182UL, 2619616318UL, 456806966UL, 4272538790UL, 2994564124UL, 2757588894UL, 3493053179UL, 2946195469UL, 1402305257UL, 2266356503UL, 3512914478UL, 273195440UL, 3579761455UL, 862317458UL, 1894959361UL, 42596779UL, 376641729UL, 782820755UL, 716528645UL, 222675565UL, 4038035195UL, 311038326UL, 395780597UL, 2025474869UL, 404396572UL, 4138962756UL, 2441107014UL, 3525378401UL, 947085768UL, +3758218091UL, 3185789607UL, 638283508UL, 3802505926UL, 830259842UL, 1086400881UL, 3444485UL, 142418107UL, 4283468141UL, 1669846189UL, 955065888UL, 3864384467UL, 73139517UL, 136809048UL, 1444329434UL, 174974637UL, 3303183786UL, 282216656UL, 3114827080UL, 3811060015UL, 1610640996UL, 3824096289UL, 1123437514UL, 3826582808UL, 39407702UL, 2437666463UL, 2454206642UL, 830758422UL, 4190092654UL, 1941090912UL, 224373276UL, 3704201239UL, +3284012568UL, 4056152539UL, 1022047941UL, 1077111803UL, 3028336675UL, 3207391465UL, 3459202233UL, 1991240724UL, 4184491520UL, 1851863093UL, 1038639595UL, 1392247730UL, 2113875749UL, 1162388509UL, 2629935260UL, 3545260772UL, 991928712UL, 4064775043UL, 4180493781UL, 2134685922UL, 642853690UL, 290065503UL, 1629968UL, 3150373868UL, 3110755428UL, 2254306163UL, 421928533UL, 11426979UL, 3042809169UL, 786868170UL, 1287942583UL, 1851107769UL, +1444903906UL, 4150950197UL, 3737798306UL, 2848738554UL, 505924220UL, 2944131627UL, 2639930627UL, 1339887691UL, 2382166850UL, 2668971315UL, 3944739049UL, 2217612340UL, 4142682607UL, 997824216UL, 123465626UL, 844518179UL, 1161486362UL, 2706162053UL, 2966530827UL, 4103639053UL, 1837121393UL, 909648429UL, 298619078UL, 2057042454UL, 3613272637UL, 3609349032UL, 1664428748UL, 1871510359UL, 58508710UL, 1079418100UL, 3278870121UL, 3821562746UL, +16654909UL, 2530580589UL, 3361874982UL, 629910009UL, 2124761646UL, 2508133604UL, 1954315500UL, 3019833617UL, 141617625UL, 1653192078UL, 1541695589UL, 1223978475UL, 3875963510UL, 3028691587UL, 3450826564UL, 2185849120UL, 1956475624UL, 3053842172UL, 3550887830UL, 2672339803UL, 176823785UL, 913229929UL, 681399502UL, 2256486297UL, 2881672598UL, 597153273UL, 2782767695UL, 1133158067UL, 4126077325UL, 3456027404UL, 754062201UL, 4069172986UL, +}, +{ +2441935114UL, 3465447683UL, 2897229686UL, 3845380309UL, 1199633364UL, 495424232UL, 2490548037UL, 581670528UL, 2467171733UL, 2200094863UL, 2163927790UL, 3895792830UL, 2097210789UL, 1606544633UL, 1305562517UL, 4072525389UL, 3256142090UL, 349440478UL, 3920932491UL, 2462464051UL, 1075951496UL, 2835763703UL, 1593198055UL, 2380945625UL, 543531323UL, 3182766507UL, 2927484354UL, 2877470578UL, 4153923603UL, 2443156156UL, 1168544900UL, 888955615UL, +3605412824UL, 1336677864UL, 3256116974UL, 2884036014UL, 4070749843UL, 2989661773UL, 1095584023UL, 1370834065UL, 3534389580UL, 312378113UL, 3190819203UL, 1247574926UL, 2046019470UL, 3536918510UL, 1479030180UL, 847820646UL, 3992973956UL, 3827223401UL, 4113429617UL, 3504933502UL, 295000614UL, 2238923504UL, 3485717254UL, 290246351UL, 1064210816UL, 2848539559UL, 2617134888UL, 422213010UL, 2796674561UL, 3568250500UL, 2736237915UL, 3950756060UL, +1527249993UL, 3603540278UL, 4115393386UL, 2851621193UL, 4230341156UL, 905168850UL, 3916344126UL, 1496013046UL, 206343742UL, 2894205125UL, 1082918859UL, 2746480417UL, 3077328661UL, 1209440053UL, 3258293856UL, 1032236533UL, 3043332566UL, 446879604UL, 587022214UL, 1614371566UL, 3040899994UL, 3686422145UL, 937325128UL, 1968833679UL, 169086151UL, 4075432555UL, 1196046411UL, 3101745581UL, 4228079966UL, 2942213563UL, 1195005323UL, 1673491641UL, +1762746534UL, 3641827252UL, 694590905UL, 1828365460UL, 513716230UL, 3106485486UL, 2441593994UL, 4044462965UL, 3628121101UL, 3957990629UL, 179764922UL, 579361186UL, 3474393871UL, 2474241006UL, 4031850878UL, 3120409532UL, 4011587898UL, 3682942579UL, 3257272830UL, 3097029759UL, 2652540191UL, 1128762588UL, 1040256382UL, 2743736716UL, 334893087UL, 1892049031UL, 2603159239UL, 3712772023UL, 2126593224UL, 3465793906UL, 3180780589UL, 725740783UL, +3728108967UL, 573931936UL, 137996587UL, 110756053UL, 3984787930UL, 3773232816UL, 3406981985UL, 1783088630UL, 2080089781UL, 195827466UL, 1409073281UL, 867635355UL, 3049533211UL, 486687054UL, 2570137956UL, 527522011UL, 1084454084UL, 1019222771UL, 1415565066UL, 650794786UL, 629618803UL, 1237709131UL, 1241899078UL, 2751644247UL, 2792313337UL, 649402117UL, 275078659UL, 752459111UL, 2173220853UL, 3207031798UL, 821073585UL, 3005400729UL, +1085152012UL, 2441935114UL, 3465447683UL, 2897229686UL, 3845380309UL, 3573898488UL, 495424232UL, 2490548037UL, 581670528UL, 2467171733UL, 1208279791UL, 2163927790UL, 3895792830UL, 2097210789UL, 1606544633UL, 2148733343UL, 4072525389UL, 3256142090UL, 349440478UL, 3920932491UL, 657289255UL, 1075951496UL, 2835763703UL, 1593198055UL, 2380945625UL, 149487931UL, 3182766507UL, 2927484354UL, 2877470578UL, 4153923603UL, 606130344UL, 1168544900UL, +888955615UL, 3605412824UL, 1336677864UL, 53448770UL, 2884036014UL, 4070749843UL, 2989661773UL, 1095584023UL, 2766144383UL, 3534389580UL, 312378113UL, 3190819203UL, 1247574926UL, 1530609481UL, 3536918510UL, 1479030180UL, 847820646UL, 3992973956UL, 154171325UL, 4113429617UL, 3504933502UL, 295000614UL, 2238923504UL, 282708664UL, 290246351UL, 1064210816UL, 2848539559UL, 2617134888UL, 36906646UL, 2796674561UL, 3568250500UL, 2736237915UL, +3950756060UL, 3416260072UL, 3603540278UL, 4115393386UL, 2851621193UL, 4230341156UL, 448215287UL, 3916344126UL, 1496013046UL, 206343742UL, 2894205125UL, 2420861244UL, 2746480417UL, 3077328661UL, 1209440053UL, 3258293856UL, 2545287695UL, 3043332566UL, 446879604UL, 587022214UL, 1614371566UL, 958587333UL, 3686422145UL, 937325128UL, 1968833679UL, 169086151UL, 154576725UL, 1196046411UL, 3101745581UL, 4228079966UL, 2942213563UL, 2487464668UL, +1673491641UL, 1762746534UL, 3641827252UL, 694590905UL, 3754606623UL, 513716230UL, 3106485486UL, 2441593994UL, 4044462965UL, 3064108377UL, 3957990629UL, 179764922UL, 579361186UL, 3474393871UL, 2138270428UL, 4031850878UL, 3120409532UL, 4011587898UL, 3682942579UL, 4015980199UL, 3097029759UL, 2652540191UL, 1128762588UL, 1040256382UL, 3908621649UL, 334893087UL, 1892049031UL, 2603159239UL, 3712772023UL, 3291038350UL, 3465793906UL, 3180780589UL, +725740783UL, 3728108967UL, 436976908UL, 137996587UL, 110756053UL, 3984787930UL, 3773232816UL, 1000054791UL, 1783088630UL, 2080089781UL, 195827466UL, 1409073281UL, 3036813614UL, 3049533211UL, 486687054UL, 2570137956UL, 527522011UL, 3669951690UL, 1019222771UL, 1415565066UL, 650794786UL, 629618803UL, 4140569538UL, 1241899078UL, 2751644247UL, 2792313337UL, 649402117UL, 2946582304UL, 752459111UL, 2173220853UL, 3207031798UL, 821073585UL, +1738142977UL, 1085152012UL, 2441935114UL, 3465447683UL, 2897229686UL, 2707197334UL, 3573898488UL, 495424232UL, 2490548037UL, 581670528UL, 2365865647UL, 1208279791UL, 2163927790UL, 3895792830UL, 2097210789UL, 3219551420UL, 2148733343UL, 4072525389UL, 3256142090UL, 349440478UL, 3706519197UL, 657289255UL, 1075951496UL, 2835763703UL, 1593198055UL, 2200084531UL, 149487931UL, 3182766507UL, 2927484354UL, 2877470578UL, 2394288661UL, 606130344UL, +1168544900UL, 888955615UL, 3605412824UL, 1503975597UL, 53448770UL, 2884036014UL, 4070749843UL, 2989661773UL, 243605110UL, 2766144383UL, 3534389580UL, 312378113UL, 3190819203UL, 2398088088UL, 1530609481UL, 3536918510UL, 1479030180UL, 847820646UL, 2940281320UL, 154171325UL, 4113429617UL, 3504933502UL, 295000614UL, 3078701806UL, 282708664UL, 290246351UL, 1064210816UL, 2848539559UL, 3960345380UL, 36906646UL, 2796674561UL, 3568250500UL, +2736237915UL, 2657034787UL, 3416260072UL, 3603540278UL, 4115393386UL, 2851621193UL, 3847740427UL, 448215287UL, 3916344126UL, 1496013046UL, 206343742UL, 3419083433UL, 2420861244UL, 2746480417UL, 3077328661UL, 1209440053UL, 3824237152UL, 2545287695UL, 3043332566UL, 446879604UL, 587022214UL, 506352928UL, 958587333UL, 3686422145UL, 937325128UL, 1968833679UL, 1808935939UL, 154576725UL, 1196046411UL, 3101745581UL, 4228079966UL, 709576348UL, +2487464668UL, 1673491641UL, 1762746534UL, 3641827252UL, 3968332142UL, 3754606623UL, 513716230UL, 3106485486UL, 2441593994UL, 1453443785UL, 3064108377UL, 3957990629UL, 179764922UL, 579361186UL, 1454621561UL, 2138270428UL, 4031850878UL, 3120409532UL, 4011587898UL, 898119245UL, 4015980199UL, 3097029759UL, 2652540191UL, 1128762588UL, 1131456853UL, 3908621649UL, 334893087UL, 1892049031UL, 2603159239UL, 4280222837UL, 3291038350UL, 3465793906UL, +3180780589UL, 725740783UL, 1515867399UL, 436976908UL, 137996587UL, 110756053UL, 3984787930UL, 1295994548UL, 1000054791UL, 1783088630UL, 2080089781UL, 195827466UL, 252558267UL, 3036813614UL, 3049533211UL, 486687054UL, 2570137956UL, 786434419UL, 3669951690UL, 1019222771UL, 1415565066UL, 650794786UL, 1316734597UL, 4140569538UL, 1241899078UL, 2751644247UL, 2792313337UL, 4014748337UL, 2946582304UL, 752459111UL, 2173220853UL, 3207031798UL, +2903407363UL, 1738142977UL, 1085152012UL, 2441935114UL, 3465447683UL, 1082984764UL, 2707197334UL, 3573898488UL, 495424232UL, 2490548037UL, 240094068UL, 2365865647UL, 1208279791UL, 2163927790UL, 3895792830UL, 1107651215UL, 3219551420UL, 2148733343UL, 4072525389UL, 3256142090UL, 681942656UL, 3706519197UL, 657289255UL, 1075951496UL, 2835763703UL, 2172774506UL, 2200084531UL, 149487931UL, 3182766507UL, 2927484354UL, 3069592433UL, 2394288661UL, +606130344UL, 1168544900UL, 888955615UL, 757163746UL, 1503975597UL, 53448770UL, 2884036014UL, 4070749843UL, 1705538727UL, 243605110UL, 2766144383UL, 3534389580UL, 312378113UL, 2256467250UL, 2398088088UL, 1530609481UL, 3536918510UL, 1479030180UL, 1360826079UL, 2940281320UL, 154171325UL, 4113429617UL, 3504933502UL, 714934244UL, 3078701806UL, 282708664UL, 290246351UL, 1064210816UL, 3694453051UL, 3960345380UL, 36906646UL, 2796674561UL, +3568250500UL, 3400481963UL, 2657034787UL, 3416260072UL, 3603540278UL, 4115393386UL, 1466632735UL, 3847740427UL, 448215287UL, 3916344126UL, 1496013046UL, 2893537514UL, 3419083433UL, 2420861244UL, 2746480417UL, 3077328661UL, 2815979224UL, 3824237152UL, 2545287695UL, 3043332566UL, 446879604UL, 3719452721UL, 506352928UL, 958587333UL, 3686422145UL, 937325128UL, 2653904510UL, 1808935939UL, 154576725UL, 1196046411UL, 3101745581UL, 425411544UL, +709576348UL, 2487464668UL, 1673491641UL, 1762746534UL, 1960605594UL, 3968332142UL, 3754606623UL, 513716230UL, 3106485486UL, 2881551071UL, 1453443785UL, 3064108377UL, 3957990629UL, 179764922UL, 1408218536UL, 1454621561UL, 2138270428UL, 4031850878UL, 3120409532UL, 3700386494UL, 898119245UL, 4015980199UL, 3097029759UL, 2652540191UL, 2181464767UL, 1131456853UL, 3908621649UL, 334893087UL, 1892049031UL, 4220220071UL, 4280222837UL, 3291038350UL, +3465793906UL, 3180780589UL, 1737123182UL, 1515867399UL, 436976908UL, 137996587UL, 110756053UL, 1360813614UL, 1295994548UL, 1000054791UL, 1783088630UL, 2080089781UL, 1019367341UL, 252558267UL, 3036813614UL, 3049533211UL, 486687054UL, 387915679UL, 786434419UL, 3669951690UL, 1019222771UL, 1415565066UL, 4267042909UL, 1316734597UL, 4140569538UL, 1241899078UL, 2751644247UL, 3622120385UL, 4014748337UL, 2946582304UL, 752459111UL, 2173220853UL, +1128460687UL, 2268047031UL, 239933818UL, 4141570430UL, 1318816940UL, 2378987660UL, 731877825UL, 3950952879UL, 2975574698UL, 2938375136UL, 431933385UL, 154404673UL, 2020658234UL, 846815781UL, 822137193UL, 1057315444UL, 3632584082UL, 3263363094UL, 942201956UL, 2704683551UL, 1768107067UL, 4009446092UL, 3090701064UL, 701246680UL, 3548419575UL, 3873366129UL, 1639833080UL, 2401253373UL, 66597794UL, 2515774132UL, 516246524UL, 4232115668UL, +34426096UL, 2206423458UL, 3628832867UL, 2776950121UL, 2782943544UL, 2058958317UL, 1805852726UL, 2151415233UL, 2940074103UL, 2318397273UL, 3067676663UL, 3127709351UL, 71509976UL, 115529187UL, 1841252918UL, 2217805156UL, 733917373UL, 2432474677UL, 1416887641UL, 1895320369UL, 2779694586UL, 510547269UL, 2614743018UL, 759552691UL, 2264773752UL, 305497497UL, 1082013785UL, 1681067734UL, 1085957001UL, 846460632UL, 2824079919UL, 1820633139UL, +3686495295UL, 3978521319UL, 1734452426UL, 4105472656UL, 1771256166UL, 1578071897UL, 1972844727UL, 2048372515UL, 3002132226UL, 1889169118UL, 2932142799UL, 2166712623UL, 592016143UL, 1116895096UL, 889321536UL, 375621825UL, 2935845994UL, 1982459859UL, 3336799370UL, 294519309UL, 2661638345UL, 1089335942UL, 227150969UL, 1454919198UL, 3780503305UL, 1862290968UL, 1491836299UL, 766546986UL, 3638407467UL, 925906735UL, 208891816UL, 236714698UL, +2853181150UL, 3889751556UL, 2161215392UL, 853579433UL, 2131555681UL, 1396396345UL, 1088128136UL, 978252562UL, 2134024308UL, 2429920974UL, 1159468871UL, 2395949266UL, 1441791888UL, 916521377UL, 3950270431UL, 2663319810UL, 3873120593UL, 2080989388UL, 2896532502UL, 3176181708UL, 1736685126UL, 4081767288UL, 3515770288UL, 1371473598UL, 1491850178UL, 4284949727UL, 2774513541UL, 1541596000UL, 3948112869UL, 2114538326UL, 2641532252UL, 1837244955UL, +2292505300UL, 3179787565UL, 639953781UL, 785902378UL, 3852544833UL, 553508260UL, 23014564UL, 106722100UL, 2705412979UL, 3449440367UL, 950636401UL, 870804158UL, 629831074UL, 424163855UL, 373653940UL, 2739378330UL, 377730945UL, 418426029UL, 267367218UL, 554678849UL, 4222664331UL, 3346048120UL, 1870226737UL, 2435616108UL, 3747040233UL, 698046507UL, 1671346285UL, 4127293033UL, 568612264UL, 3467142937UL, 1627988025UL, 1305525598UL, +}, +{ +2246605826UL, 215030128UL, 871645668UL, 3402612852UL, 423273439UL, 316965236UL, 47416561UL, 1470716454UL, 2288582385UL, 2021890755UL, 2148091363UL, 167227868UL, 3085506034UL, 3365950545UL, 1170282137UL, 1345986409UL, 197195155UL, 2644113318UL, 2491271090UL, 2597072003UL, 170335901UL, 2540851884UL, 2584420407UL, 3609142920UL, 3052130502UL, 4018095157UL, 2850805299UL, 2777821400UL, 110647395UL, 3262987676UL, 1447103309UL, 3632575579UL, +3243210595UL, 1892770504UL, 4214485953UL, 38676169UL, 2431628817UL, 2836918800UL, 272023527UL, 2825888902UL, 2794421955UL, 2354379386UL, 452404203UL, 584718212UL, 1915053836UL, 1455821656UL, 4264066935UL, 1150980581UL, 3792433350UL, 3104909316UL, 441521402UL, 3807587668UL, 275969953UL, 3970844623UL, 3323695518UL, 3909107329UL, 290225599UL, 957520066UL, 4048181850UL, 2623778463UL, 1957371891UL, 540091753UL, 3072448879UL, 2386916346UL, +392549194UL, 1261391184UL, 4137605148UL, 314807135UL, 2916930821UL, 3168561018UL, 2332027308UL, 1967082817UL, 1849256214UL, 1141134412UL, 1206824012UL, 2088102210UL, 4170914605UL, 3399892824UL, 59190648UL, 1657183299UL, 1314626253UL, 500606287UL, 413229420UL, 1245395908UL, 664681UL, 2726979120UL, 3408998445UL, 2318397638UL, 1882820077UL, 2073055266UL, 4262833629UL, 1348801932UL, 229857331UL, 3086071450UL, 1327801028UL, 812015573UL, +2214355282UL, 2232635690UL, 3162540418UL, 2049877621UL, 470752564UL, 2527480795UL, 1285499716UL, 220173566UL, 4239277569UL, 788168494UL, 3748855859UL, 1360707769UL, 449512212UL, 1238219398UL, 2880205975UL, 2755133627UL, 372409230UL, 411800575UL, 2455333195UL, 4080817864UL, 3556684908UL, 2857940866UL, 1969081563UL, 2526852668UL, 1026062474UL, 1849785784UL, 3552290093UL, 4214448UL, 460332681UL, 30890894UL, 1108618048UL, 272438799UL, +3339891045UL, 1512685591UL, 1310038443UL, 2431938882UL, 1478442144UL, 2804640700UL, 3426381347UL, 861206186UL, 290322827UL, 2736623609UL, 327318125UL, 1922859957UL, 1939922519UL, 3539608908UL, 3442377433UL, 3868710131UL, 2244493875UL, 47774461UL, 3858864626UL, 3294523981UL, 1798515481UL, 565017248UL, 2633378137UL, 811307482UL, 1743357106UL, 419676111UL, 1688841846UL, 1799884674UL, 1720546272UL, 3900863156UL, 3506303345UL, 1719438472UL, +576775454UL, 2246605826UL, 215030128UL, 871645668UL, 3402612852UL, 619000856UL, 316965236UL, 47416561UL, 1470716454UL, 2288582385UL, 3464704266UL, 2148091363UL, 167227868UL, 3085506034UL, 3365950545UL, 901169164UL, 1345986409UL, 197195155UL, 2644113318UL, 2491271090UL, 3243741640UL, 170335901UL, 2540851884UL, 2584420407UL, 3609142920UL, 2051834116UL, 4018095157UL, 2850805299UL, 2777821400UL, 110647395UL, 2822981113UL, 1447103309UL, +3632575579UL, 3243210595UL, 1892770504UL, 1947501555UL, 38676169UL, 2431628817UL, 2836918800UL, 272023527UL, 4010280501UL, 2794421955UL, 2354379386UL, 452404203UL, 584718212UL, 3991257933UL, 1455821656UL, 4264066935UL, 1150980581UL, 3792433350UL, 2151631692UL, 441521402UL, 3807587668UL, 275969953UL, 3970844623UL, 3965914153UL, 3909107329UL, 290225599UL, 957520066UL, 4048181850UL, 4011285909UL, 1957371891UL, 540091753UL, 3072448879UL, +2386916346UL, 1347453316UL, 1261391184UL, 4137605148UL, 314807135UL, 2916930821UL, 840822698UL, 2332027308UL, 1967082817UL, 1849256214UL, 1141134412UL, 960593185UL, 2088102210UL, 4170914605UL, 3399892824UL, 59190648UL, 2261593014UL, 1314626253UL, 500606287UL, 413229420UL, 1245395908UL, 3401527918UL, 2726979120UL, 3408998445UL, 2318397638UL, 1882820077UL, 1683077666UL, 4262833629UL, 1348801932UL, 229857331UL, 3086071450UL, 3363644507UL, +812015573UL, 2214355282UL, 2232635690UL, 3162540418UL, 3579858747UL, 470752564UL, 2527480795UL, 1285499716UL, 220173566UL, 2294101261UL, 788168494UL, 3748855859UL, 1360707769UL, 449512212UL, 28595866UL, 2880205975UL, 2755133627UL, 372409230UL, 411800575UL, 1905311140UL, 4080817864UL, 3556684908UL, 2857940866UL, 1969081563UL, 148561593UL, 1026062474UL, 1849785784UL, 3552290093UL, 4214448UL, 2237247821UL, 30890894UL, 1108618048UL, +272438799UL, 3339891045UL, 169576507UL, 1310038443UL, 2431938882UL, 1478442144UL, 2804640700UL, 4119485855UL, 861206186UL, 290322827UL, 2736623609UL, 327318125UL, 3408620608UL, 1939922519UL, 3539608908UL, 3442377433UL, 3868710131UL, 1188056275UL, 47774461UL, 3858864626UL, 3294523981UL, 1798515481UL, 1228896851UL, 2633378137UL, 811307482UL, 1743357106UL, 419676111UL, 3111013241UL, 1799884674UL, 1720546272UL, 3900863156UL, 3506303345UL, +1474164586UL, 576775454UL, 2246605826UL, 215030128UL, 871645668UL, 2968519387UL, 619000856UL, 316965236UL, 47416561UL, 1470716454UL, 9648980UL, 3464704266UL, 2148091363UL, 167227868UL, 3085506034UL, 1505294373UL, 901169164UL, 1345986409UL, 197195155UL, 2644113318UL, 1227359150UL, 3243741640UL, 170335901UL, 2540851884UL, 2584420407UL, 1205921163UL, 2051834116UL, 4018095157UL, 2850805299UL, 2777821400UL, 2967529310UL, 2822981113UL, +1447103309UL, 3632575579UL, 3243210595UL, 532996977UL, 1947501555UL, 38676169UL, 2431628817UL, 2836918800UL, 1761031313UL, 4010280501UL, 2794421955UL, 2354379386UL, 452404203UL, 1222630846UL, 3991257933UL, 1455821656UL, 4264066935UL, 1150980581UL, 2344548386UL, 2151631692UL, 441521402UL, 3807587668UL, 275969953UL, 963889269UL, 3965914153UL, 3909107329UL, 290225599UL, 957520066UL, 4176220201UL, 4011285909UL, 1957371891UL, 540091753UL, +3072448879UL, 1810164615UL, 1347453316UL, 1261391184UL, 4137605148UL, 314807135UL, 2672526663UL, 840822698UL, 2332027308UL, 1967082817UL, 1849256214UL, 734862208UL, 960593185UL, 2088102210UL, 4170914605UL, 3399892824UL, 2471507530UL, 2261593014UL, 1314626253UL, 500606287UL, 413229420UL, 970185057UL, 3401527918UL, 2726979120UL, 3408998445UL, 2318397638UL, 708987193UL, 1683077666UL, 4262833629UL, 1348801932UL, 229857331UL, 749849397UL, +3363644507UL, 812015573UL, 2214355282UL, 2232635690UL, 2901095495UL, 3579858747UL, 470752564UL, 2527480795UL, 1285499716UL, 941862108UL, 2294101261UL, 788168494UL, 3748855859UL, 1360707769UL, 3818227212UL, 28595866UL, 2880205975UL, 2755133627UL, 372409230UL, 570110534UL, 1905311140UL, 4080817864UL, 3556684908UL, 2857940866UL, 2253777974UL, 148561593UL, 1026062474UL, 1849785784UL, 3552290093UL, 1525559608UL, 2237247821UL, 30890894UL, +1108618048UL, 272438799UL, 3996203631UL, 169576507UL, 1310038443UL, 2431938882UL, 1478442144UL, 2857841871UL, 4119485855UL, 861206186UL, 290322827UL, 2736623609UL, 1184217272UL, 3408620608UL, 1939922519UL, 3539608908UL, 3442377433UL, 1263700272UL, 1188056275UL, 47774461UL, 3858864626UL, 3294523981UL, 2611619UL, 1228896851UL, 2633378137UL, 811307482UL, 1743357106UL, 1930089302UL, 3111013241UL, 1799884674UL, 1720546272UL, 3900863156UL, +2370003471UL, 1474164586UL, 576775454UL, 2246605826UL, 215030128UL, 540197019UL, 2968519387UL, 619000856UL, 316965236UL, 47416561UL, 3585128733UL, 9648980UL, 3464704266UL, 2148091363UL, 167227868UL, 509283324UL, 1505294373UL, 901169164UL, 1345986409UL, 197195155UL, 3983525470UL, 1227359150UL, 3243741640UL, 170335901UL, 2540851884UL, 2812935262UL, 1205921163UL, 2051834116UL, 4018095157UL, 2850805299UL, 2798430304UL, 2967529310UL, +2822981113UL, 1447103309UL, 3632575579UL, 389184524UL, 532996977UL, 1947501555UL, 38676169UL, 2431628817UL, 1055068556UL, 1761031313UL, 4010280501UL, 2794421955UL, 2354379386UL, 965687576UL, 1222630846UL, 3991257933UL, 1455821656UL, 4264066935UL, 1551000086UL, 2344548386UL, 2151631692UL, 441521402UL, 3807587668UL, 3701529910UL, 963889269UL, 3965914153UL, 3909107329UL, 290225599UL, 1771599976UL, 4176220201UL, 4011285909UL, 1957371891UL, +540091753UL, 1670159873UL, 1810164615UL, 1347453316UL, 1261391184UL, 4137605148UL, 4191698993UL, 2672526663UL, 840822698UL, 2332027308UL, 1967082817UL, 3098515331UL, 734862208UL, 960593185UL, 2088102210UL, 4170914605UL, 2470055060UL, 2471507530UL, 2261593014UL, 1314626253UL, 500606287UL, 1100764382UL, 970185057UL, 3401527918UL, 2726979120UL, 3408998445UL, 4100198161UL, 708987193UL, 1683077666UL, 4262833629UL, 1348801932UL, 3744209503UL, +749849397UL, 3363644507UL, 812015573UL, 2214355282UL, 3217409412UL, 2901095495UL, 3579858747UL, 470752564UL, 2527480795UL, 552979949UL, 941862108UL, 2294101261UL, 788168494UL, 3748855859UL, 2355231228UL, 3818227212UL, 28595866UL, 2880205975UL, 2755133627UL, 833553378UL, 570110534UL, 1905311140UL, 4080817864UL, 3556684908UL, 4124102038UL, 2253777974UL, 148561593UL, 1026062474UL, 1849785784UL, 656329297UL, 1525559608UL, 2237247821UL, +30890894UL, 1108618048UL, 1464443032UL, 3996203631UL, 169576507UL, 1310038443UL, 2431938882UL, 2100788071UL, 2857841871UL, 4119485855UL, 861206186UL, 290322827UL, 3653047356UL, 1184217272UL, 3408620608UL, 1939922519UL, 3539608908UL, 4267170500UL, 1263700272UL, 1188056275UL, 47774461UL, 3858864626UL, 1046565728UL, 2611619UL, 1228896851UL, 2633378137UL, 811307482UL, 1312393456UL, 1930089302UL, 3111013241UL, 1799884674UL, 1720546272UL, +1199041144UL, 2406753856UL, 2108495166UL, 2126345981UL, 1524975128UL, 1269232392UL, 3162531748UL, 3076707658UL, 1736955170UL, 1036221745UL, 1232435193UL, 3945348482UL, 1057631163UL, 520376289UL, 4154435769UL, 1280565077UL, 1865705876UL, 1030078366UL, 1140849319UL, 1769263412UL, 1161866807UL, 2768552980UL, 561022685UL, 2712685799UL, 1501252058UL, 3608433719UL, 3138564149UL, 4093654128UL, 1218455911UL, 892700607UL, 2012017510UL, 3568315757UL, +4002239824UL, 1754440379UL, 2641708101UL, 1027390781UL, 199831087UL, 1261208885UL, 2058433786UL, 2101649235UL, 220966013UL, 3445375335UL, 1100438514UL, 4075559840UL, 4244062658UL, 3417249884UL, 150102478UL, 3337395219UL, 2464869101UL, 3720375949UL, 93353579UL, 2329780067UL, 777826834UL, 2745626035UL, 2984812746UL, 568848158UL, 1593919595UL, 1166619196UL, 96177504UL, 305329591UL, 4271176854UL, 3829149188UL, 1551058535UL, 2828280993UL, +1367551996UL, 4208083082UL, 2260803683UL, 3118708147UL, 434935608UL, 702805370UL, 3544156958UL, 792712531UL, 231019757UL, 136272259UL, 4049968615UL, 2722527811UL, 603697698UL, 2891035509UL, 4270409302UL, 1220615076UL, 1932569338UL, 1084454986UL, 468729683UL, 2377913518UL, 2068946556UL, 530579176UL, 1422294615UL, 4032799503UL, 2065706770UL, 604700228UL, 98049660UL, 3182511353UL, 935830212UL, 1938107848UL, 1266035034UL, 957505506UL, +2758220503UL, 1805223938UL, 3393041584UL, 3958541336UL, 2695487012UL, 3355668819UL, 276889675UL, 3098939423UL, 415941187UL, 180737121UL, 2638873657UL, 1103150707UL, 4255168358UL, 2736183195UL, 1275942292UL, 2687807236UL, 538129710UL, 3337005391UL, 3941968393UL, 1113153386UL, 3813628384UL, 1775835369UL, 296314749UL, 1697642748UL, 3614403315UL, 1953056095UL, 2102878063UL, 3161706344UL, 2207159580UL, 3078233525UL, 3836286614UL, 886914072UL, +1884037075UL, 4135819784UL, 1616380780UL, 1672616998UL, 3879848699UL, 2277472209UL, 3933249848UL, 2428044648UL, 2876076879UL, 165724720UL, 2277165385UL, 1984963196UL, 1456923194UL, 2406217222UL, 3388886718UL, 47522558UL, 1903557801UL, 1959641458UL, 2325355446UL, 3251147398UL, 2266553941UL, 2243962024UL, 1420017618UL, 1791159474UL, 1793406225UL, 601509698UL, 3207357979UL, 1189285184UL, 148538800UL, 2077251302UL, 3267239327UL, 2851475997UL, +}, +{ +2628162153UL, 3861478870UL, 2769884494UL, 3423483820UL, 1118276924UL, 536776894UL, 3742490940UL, 550084334UL, 2441329856UL, 2604618499UL, 2308745810UL, 1178166365UL, 1345165241UL, 4039508109UL, 1246601384UL, 3843182157UL, 2200144237UL, 91750284UL, 4290064840UL, 3363597477UL, 3243492274UL, 4271100308UL, 4186328336UL, 2291901989UL, 1834723222UL, 372220743UL, 2190417067UL, 2624886324UL, 3567647862UL, 1591175369UL, 2278087682UL, 2461678432UL, +232820452UL, 2714694382UL, 3070258434UL, 2412655444UL, 2667664607UL, 249083056UL, 4166379751UL, 1360927521UL, 2247816079UL, 3253689753UL, 1563674427UL, 1914999382UL, 2101454952UL, 1067816947UL, 1098201917UL, 4054175236UL, 1805828534UL, 1815913104UL, 738357340UL, 2597170030UL, 1689737432UL, 2004663483UL, 1160995461UL, 1008175050UL, 2004702919UL, 4258654415UL, 938972594UL, 2121583885UL, 2208729114UL, 276726877UL, 3973538591UL, 2991069145UL, +2345655326UL, 2980162173UL, 1915611444UL, 2332104940UL, 2382102873UL, 2324437093UL, 2640563452UL, 2680619359UL, 3413490949UL, 2140843463UL, 2424016743UL, 3735508133UL, 3421831326UL, 4037977349UL, 3721506282UL, 510431975UL, 1014707294UL, 1378686477UL, 1939678832UL, 2223101760UL, 2067687989UL, 309274614UL, 276596103UL, 3757624719UL, 1212251468UL, 2649271847UL, 4140361758UL, 2634738350UL, 2029358730UL, 3205861896UL, 3090549771UL, 3775019657UL, +2018542036UL, 3675805680UL, 3946144023UL, 331655838UL, 326568491UL, 1867863527UL, 1550945400UL, 3087000670UL, 2342003578UL, 3949479453UL, 586483056UL, 147951307UL, 503062740UL, 3823927166UL, 2789767841UL, 3121654578UL, 634238762UL, 4084629478UL, 3878778788UL, 435990088UL, 1724770389UL, 1403031256UL, 1334135626UL, 1096780503UL, 3288769545UL, 2793293893UL, 80675548UL, 1637232257UL, 1856565474UL, 2675485635UL, 1961165681UL, 1647512786UL, +4190102851UL, 4081320784UL, 2853183400UL, 3812341867UL, 278236392UL, 1700614299UL, 2765246084UL, 3846866009UL, 1220806787UL, 3655684157UL, 1133921183UL, 2779125219UL, 523552281UL, 703813725UL, 3110126767UL, 823843890UL, 290243102UL, 821297176UL, 364959993UL, 3381862130UL, 2305271841UL, 356059263UL, 2558018765UL, 3235968999UL, 1070598970UL, 2444411636UL, 3636221117UL, 4275517214UL, 4035198865UL, 3339014315UL, 2911872812UL, 4049586122UL, +4211583637UL, 2628162153UL, 3861478870UL, 2769884494UL, 3423483820UL, 3254616321UL, 536776894UL, 3742490940UL, 550084334UL, 2441329856UL, 1909596092UL, 2308745810UL, 1178166365UL, 1345165241UL, 4039508109UL, 1349347043UL, 3843182157UL, 2200144237UL, 91750284UL, 4290064840UL, 803098068UL, 3243492274UL, 4271100308UL, 4186328336UL, 2291901989UL, 2575673198UL, 372220743UL, 2190417067UL, 2624886324UL, 3567647862UL, 132569424UL, 2278087682UL, +2461678432UL, 232820452UL, 2714694382UL, 3490648253UL, 2412655444UL, 2667664607UL, 249083056UL, 4166379751UL, 3503294711UL, 2247816079UL, 3253689753UL, 1563674427UL, 1914999382UL, 3121933565UL, 1067816947UL, 1098201917UL, 4054175236UL, 1805828534UL, 816420552UL, 738357340UL, 2597170030UL, 1689737432UL, 2004663483UL, 397934907UL, 1008175050UL, 2004702919UL, 4258654415UL, 938972594UL, 156733019UL, 2208729114UL, 276726877UL, 3973538591UL, +2991069145UL, 2470446383UL, 2980162173UL, 1915611444UL, 2332104940UL, 2382102873UL, 3265195583UL, 2640563452UL, 2680619359UL, 3413490949UL, 2140843463UL, 142464483UL, 3735508133UL, 3421831326UL, 4037977349UL, 3721506282UL, 1898668265UL, 1014707294UL, 1378686477UL, 1939678832UL, 2223101760UL, 4085776926UL, 309274614UL, 276596103UL, 3757624719UL, 1212251468UL, 1116423339UL, 4140361758UL, 2634738350UL, 2029358730UL, 3205861896UL, 880658361UL, +3775019657UL, 2018542036UL, 3675805680UL, 3946144023UL, 839516623UL, 326568491UL, 1867863527UL, 1550945400UL, 3087000670UL, 420309880UL, 3949479453UL, 586483056UL, 147951307UL, 503062740UL, 416618471UL, 2789767841UL, 3121654578UL, 634238762UL, 4084629478UL, 1120413065UL, 435990088UL, 1724770389UL, 1403031256UL, 1334135626UL, 240966420UL, 3288769545UL, 2793293893UL, 80675548UL, 1637232257UL, 1785064235UL, 2675485635UL, 1961165681UL, +1647512786UL, 4190102851UL, 2775407492UL, 2853183400UL, 3812341867UL, 278236392UL, 1700614299UL, 2439624528UL, 3846866009UL, 1220806787UL, 3655684157UL, 1133921183UL, 366933679UL, 523552281UL, 703813725UL, 3110126767UL, 823843890UL, 132468066UL, 821297176UL, 364959993UL, 3381862130UL, 2305271841UL, 1048450041UL, 2558018765UL, 3235968999UL, 1070598970UL, 2444411636UL, 1699430013UL, 4275517214UL, 4035198865UL, 3339014315UL, 2911872812UL, +324524850UL, 4211583637UL, 2628162153UL, 3861478870UL, 2769884494UL, 1995585079UL, 3254616321UL, 536776894UL, 3742490940UL, 550084334UL, 2121458511UL, 1909596092UL, 2308745810UL, 1178166365UL, 1345165241UL, 3067877274UL, 1349347043UL, 3843182157UL, 2200144237UL, 91750284UL, 1246148630UL, 803098068UL, 3243492274UL, 4271100308UL, 4186328336UL, 2932236493UL, 2575673198UL, 372220743UL, 2190417067UL, 2624886324UL, 3945294599UL, 132569424UL, +2278087682UL, 2461678432UL, 232820452UL, 3341915918UL, 3490648253UL, 2412655444UL, 2667664607UL, 249083056UL, 2307336284UL, 3503294711UL, 2247816079UL, 3253689753UL, 1563674427UL, 1717494311UL, 3121933565UL, 1067816947UL, 1098201917UL, 4054175236UL, 971917867UL, 816420552UL, 738357340UL, 2597170030UL, 1689737432UL, 243915062UL, 397934907UL, 1008175050UL, 2004702919UL, 4258654415UL, 1807067458UL, 156733019UL, 2208729114UL, 276726877UL, +3973538591UL, 1909483753UL, 2470446383UL, 2980162173UL, 1915611444UL, 2332104940UL, 3454651559UL, 3265195583UL, 2640563452UL, 2680619359UL, 3413490949UL, 462852932UL, 142464483UL, 3735508133UL, 3421831326UL, 4037977349UL, 1372088341UL, 1898668265UL, 1014707294UL, 1378686477UL, 1939678832UL, 752503486UL, 4085776926UL, 309274614UL, 276596103UL, 3757624719UL, 4193030119UL, 1116423339UL, 4140361758UL, 2634738350UL, 2029358730UL, 1725105892UL, +880658361UL, 3775019657UL, 2018542036UL, 3675805680UL, 3496508290UL, 839516623UL, 326568491UL, 1867863527UL, 1550945400UL, 2685835387UL, 420309880UL, 3949479453UL, 586483056UL, 147951307UL, 1639139280UL, 416618471UL, 2789767841UL, 3121654578UL, 634238762UL, 3622035469UL, 1120413065UL, 435990088UL, 1724770389UL, 1403031256UL, 3548817929UL, 240966420UL, 3288769545UL, 2793293893UL, 80675548UL, 3119506726UL, 1785064235UL, 2675485635UL, +1961165681UL, 1647512786UL, 4019542081UL, 2775407492UL, 2853183400UL, 3812341867UL, 278236392UL, 3487875111UL, 2439624528UL, 3846866009UL, 1220806787UL, 3655684157UL, 3303554633UL, 366933679UL, 523552281UL, 703813725UL, 3110126767UL, 2477354049UL, 132468066UL, 821297176UL, 364959993UL, 3381862130UL, 4065162466UL, 1048450041UL, 2558018765UL, 3235968999UL, 1070598970UL, 191819556UL, 1699430013UL, 4275517214UL, 4035198865UL, 3339014315UL, +3588518026UL, 324524850UL, 4211583637UL, 2628162153UL, 3861478870UL, 3361198093UL, 1995585079UL, 3254616321UL, 536776894UL, 3742490940UL, 3912424229UL, 2121458511UL, 1909596092UL, 2308745810UL, 1178166365UL, 1882174246UL, 3067877274UL, 1349347043UL, 3843182157UL, 2200144237UL, 1210030640UL, 1246148630UL, 803098068UL, 3243492274UL, 4271100308UL, 402141998UL, 2932236493UL, 2575673198UL, 372220743UL, 2190417067UL, 1883679642UL, 3945294599UL, +132569424UL, 2278087682UL, 2461678432UL, 708189294UL, 3341915918UL, 3490648253UL, 2412655444UL, 2667664607UL, 2871800434UL, 2307336284UL, 3503294711UL, 2247816079UL, 3253689753UL, 2113837945UL, 1717494311UL, 3121933565UL, 1067816947UL, 1098201917UL, 1041869160UL, 971917867UL, 816420552UL, 738357340UL, 2597170030UL, 2306273930UL, 243915062UL, 397934907UL, 1008175050UL, 2004702919UL, 2345434637UL, 1807067458UL, 156733019UL, 2208729114UL, +276726877UL, 2452083872UL, 1909483753UL, 2470446383UL, 2980162173UL, 1915611444UL, 2043489400UL, 3454651559UL, 3265195583UL, 2640563452UL, 2680619359UL, 2845757473UL, 462852932UL, 142464483UL, 3735508133UL, 3421831326UL, 25103542UL, 1372088341UL, 1898668265UL, 1014707294UL, 1378686477UL, 2680788341UL, 752503486UL, 4085776926UL, 309274614UL, 276596103UL, 3663266970UL, 4193030119UL, 1116423339UL, 4140361758UL, 2634738350UL, 453005903UL, +1725105892UL, 880658361UL, 3775019657UL, 2018542036UL, 2601909713UL, 3496508290UL, 839516623UL, 326568491UL, 1867863527UL, 3474340574UL, 2685835387UL, 420309880UL, 3949479453UL, 586483056UL, 297934218UL, 1639139280UL, 416618471UL, 2789767841UL, 3121654578UL, 958889718UL, 3622035469UL, 1120413065UL, 435990088UL, 1724770389UL, 2589603756UL, 3548817929UL, 240966420UL, 3288769545UL, 2793293893UL, 972899860UL, 3119506726UL, 1785064235UL, +2675485635UL, 1961165681UL, 2576799764UL, 4019542081UL, 2775407492UL, 2853183400UL, 3812341867UL, 159345352UL, 3487875111UL, 2439624528UL, 3846866009UL, 1220806787UL, 3367080935UL, 3303554633UL, 366933679UL, 523552281UL, 703813725UL, 1717395617UL, 2477354049UL, 132468066UL, 821297176UL, 364959993UL, 1088290332UL, 4065162466UL, 1048450041UL, 2558018765UL, 3235968999UL, 285340039UL, 191819556UL, 1699430013UL, 4275517214UL, 4035198865UL, +3544133220UL, 285121978UL, 1175302919UL, 4101282768UL, 513236580UL, 890655666UL, 3051849972UL, 2315486379UL, 3067287276UL, 3134806925UL, 3926373006UL, 2502825498UL, 461387883UL, 770459119UL, 3121636621UL, 1243065093UL, 1612354797UL, 659033930UL, 621176955UL, 214256518UL, 371573588UL, 1168438671UL, 1233027650UL, 1984255965UL, 659404177UL, 1218841419UL, 1226193512UL, 4247589702UL, 334814687UL, 980422670UL, 2518384561UL, 4041002302UL, +1203659320UL, 509643440UL, 2528499450UL, 1512213710UL, 4052651069UL, 1378025938UL, 3436277168UL, 2797728577UL, 463383787UL, 1184681947UL, 283482187UL, 2421891582UL, 3200080903UL, 373817869UL, 452807139UL, 2002545143UL, 1068199574UL, 3390998240UL, 377559317UL, 1548403713UL, 1580741080UL, 253591624UL, 759280679UL, 2174360733UL, 1687952097UL, 1325235423UL, 3856575909UL, 652218568UL, 4130230594UL, 3757998028UL, 1349431618UL, 2870775414UL, +229741978UL, 1900794007UL, 201310771UL, 4075023260UL, 3390078853UL, 3572716207UL, 1959949436UL, 1000128498UL, 1636575064UL, 241058867UL, 2075461870UL, 1819342070UL, 619233032UL, 3164328001UL, 4280892071UL, 4219074185UL, 2719764611UL, 3827656652UL, 4062556527UL, 621515766UL, 2542375627UL, 3901998596UL, 2295087430UL, 2880672054UL, 2940372823UL, 2318642706UL, 914614262UL, 2549699597UL, 2907475284UL, 3901259809UL, 2663167002UL, 3775306719UL, +2212887565UL, 1271873285UL, 3673659531UL, 3856609875UL, 1195785209UL, 1204338358UL, 2785362544UL, 2398696803UL, 3038377816UL, 4288025143UL, 262511310UL, 4151907455UL, 924716723UL, 3298769960UL, 2065938273UL, 3277412030UL, 122636766UL, 2164055077UL, 1000638739UL, 2044933533UL, 2935604716UL, 2772787255UL, 3727331409UL, 1315627932UL, 2610657438UL, 832931652UL, 452359900UL, 681035792UL, 3312648046UL, 1059435047UL, 1489639114UL, 3647631796UL, +417952902UL, 731020350UL, 2847472725UL, 2779076784UL, 2674295324UL, 487600023UL, 2925909449UL, 3997011591UL, 3697231318UL, 967300591UL, 2310856069UL, 684710043UL, 811911286UL, 4174732177UL, 1010656728UL, 702780279UL, 920081774UL, 1578296057UL, 944734808UL, 2884038169UL, 2885919611UL, 2633474915UL, 2508946673UL, 3579216621UL, 656143887UL, 426108406UL, 2166202683UL, 991797657UL, 706498590UL, 561168186UL, 1144619335UL, 3136206425UL, +}, +{ +3600072515UL, 651444872UL, 2348224675UL, 1684848433UL, 1913333701UL, 3413467790UL, 1567802204UL, 2125206188UL, 2463158656UL, 2251055204UL, 4132590383UL, 3192977084UL, 3718261822UL, 3431519430UL, 3506690867UL, 1313208797UL, 637811069UL, 12802085UL, 3456408080UL, 166617386UL, 1764224523UL, 4016338923UL, 2225367442UL, 2461647273UL, 3137989854UL, 373730087UL, 3013524828UL, 242949418UL, 3443491410UL, 3671816408UL, 2391000148UL, 3964107377UL, +716535366UL, 1884597979UL, 3917515811UL, 3441985401UL, 2472173593UL, 4034695117UL, 2486526143UL, 1658764329UL, 1873516415UL, 884116165UL, 814992460UL, 1069506245UL, 3797556389UL, 838088473UL, 2279863068UL, 1002637017UL, 4174541774UL, 644478743UL, 4138151954UL, 4030442072UL, 297710349UL, 3507828614UL, 1403493362UL, 3132267322UL, 227377796UL, 388148240UL, 2760904473UL, 352998924UL, 1603734504UL, 1528807885UL, 2283620218UL, 737730350UL, +2761342715UL, 809367801UL, 1667936422UL, 1510238771UL, 3762862328UL, 1171532060UL, 647580587UL, 1460988169UL, 3944640945UL, 2331043627UL, 1965076564UL, 2913596196UL, 2960957119UL, 1316491503UL, 3086954934UL, 3471945989UL, 2485431762UL, 692294537UL, 3148362914UL, 3371415765UL, 2990795967UL, 706771848UL, 3734467362UL, 2768750385UL, 2061275631UL, 3935582473UL, 1449841372UL, 1239527551UL, 592595530UL, 1685341001UL, 3352323357UL, 4147988039UL, +4003871917UL, 4035869533UL, 3022833195UL, 1266052547UL, 1429645393UL, 565106475UL, 327014810UL, 348739711UL, 3262918351UL, 915509292UL, 397356303UL, 3248246752UL, 1122821778UL, 2373765260UL, 1795464380UL, 3485315196UL, 1731529670UL, 86888382UL, 2789587372UL, 850847993UL, 1794523220UL, 577288126UL, 1996569530UL, 909222664UL, 2601642298UL, 1469035973UL, 2727135938UL, 3467853736UL, 633292505UL, 756260381UL, 41782389UL, 226724724UL, +3633968708UL, 1695315503UL, 1846857904UL, 3185630605UL, 823108172UL, 3609336496UL, 3422558797UL, 2865413534UL, 564221408UL, 591845835UL, 2498463433UL, 3573926554UL, 1336639597UL, 4180084026UL, 3195588503UL, 2822864841UL, 1916459886UL, 2073158796UL, 56968669UL, 1234765864UL, 2456093821UL, 3500058416UL, 3146725645UL, 3295822468UL, 4135196531UL, 628000231UL, 745509757UL, 4143543278UL, 1941480444UL, 3607603517UL, 2288239329UL, 1991437813UL, +4081693775UL, 3600072515UL, 651444872UL, 2348224675UL, 1684848433UL, 3748890341UL, 3413467790UL, 1567802204UL, 2125206188UL, 2463158656UL, 1516568259UL, 4132590383UL, 3192977084UL, 3718261822UL, 3431519430UL, 461466951UL, 1313208797UL, 637811069UL, 12802085UL, 3456408080UL, 3444149988UL, 1764224523UL, 4016338923UL, 2225367442UL, 2461647273UL, 2594402002UL, 373730087UL, 3013524828UL, 242949418UL, 3443491410UL, 2740782133UL, 2391000148UL, +3964107377UL, 716535366UL, 1884597979UL, 3161911677UL, 3441985401UL, 2472173593UL, 4034695117UL, 2486526143UL, 3623045141UL, 1873516415UL, 884116165UL, 814992460UL, 1069506245UL, 1053106195UL, 838088473UL, 2279863068UL, 1002637017UL, 4174541774UL, 1806935386UL, 4138151954UL, 4030442072UL, 297710349UL, 3507828614UL, 2328331779UL, 3132267322UL, 227377796UL, 388148240UL, 2760904473UL, 3654577129UL, 1603734504UL, 1528807885UL, 2283620218UL, +737730350UL, 2134741424UL, 809367801UL, 1667936422UL, 1510238771UL, 3762862328UL, 4084104273UL, 647580587UL, 1460988169UL, 3944640945UL, 2331043627UL, 3458437694UL, 2913596196UL, 2960957119UL, 1316491503UL, 3086954934UL, 2404530503UL, 2485431762UL, 692294537UL, 3148362914UL, 3371415765UL, 3697728317UL, 706771848UL, 3734467362UL, 2768750385UL, 2061275631UL, 1337146928UL, 1449841372UL, 1239527551UL, 592595530UL, 1685341001UL, 3121493408UL, +4147988039UL, 4003871917UL, 4035869533UL, 3022833195UL, 2709537023UL, 1429645393UL, 565106475UL, 327014810UL, 348739711UL, 1278935671UL, 915509292UL, 397356303UL, 3248246752UL, 1122821778UL, 1086107506UL, 1795464380UL, 3485315196UL, 1731529670UL, 86888382UL, 3645735256UL, 850847993UL, 1794523220UL, 577288126UL, 1996569530UL, 1126950UL, 2601642298UL, 1469035973UL, 2727135938UL, 3467853736UL, 3668777652UL, 756260381UL, 41782389UL, +226724724UL, 3633968708UL, 738274780UL, 1846857904UL, 3185630605UL, 823108172UL, 3609336496UL, 3371270228UL, 2865413534UL, 564221408UL, 591845835UL, 2498463433UL, 4157618574UL, 1336639597UL, 4180084026UL, 3195588503UL, 2822864841UL, 3844986377UL, 2073158796UL, 56968669UL, 1234765864UL, 2456093821UL, 1001761927UL, 3146725645UL, 3295822468UL, 4135196531UL, 628000231UL, 541676954UL, 4143543278UL, 1941480444UL, 3607603517UL, 2288239329UL, +1068806322UL, 4081693775UL, 3600072515UL, 651444872UL, 2348224675UL, 47991343UL, 3748890341UL, 3413467790UL, 1567802204UL, 2125206188UL, 2662653600UL, 1516568259UL, 4132590383UL, 3192977084UL, 3718261822UL, 2554440323UL, 461466951UL, 1313208797UL, 637811069UL, 12802085UL, 982676468UL, 3444149988UL, 1764224523UL, 4016338923UL, 2225367442UL, 451503008UL, 2594402002UL, 373730087UL, 3013524828UL, 242949418UL, 1086137206UL, 2740782133UL, +2391000148UL, 3964107377UL, 716535366UL, 731470002UL, 3161911677UL, 3441985401UL, 2472173593UL, 4034695117UL, 44456710UL, 3623045141UL, 1873516415UL, 884116165UL, 814992460UL, 4004771121UL, 1053106195UL, 838088473UL, 2279863068UL, 1002637017UL, 1587145121UL, 1806935386UL, 4138151954UL, 4030442072UL, 297710349UL, 2570695340UL, 2328331779UL, 3132267322UL, 227377796UL, 388148240UL, 3570998746UL, 3654577129UL, 1603734504UL, 1528807885UL, +2283620218UL, 188017185UL, 2134741424UL, 809367801UL, 1667936422UL, 1510238771UL, 1503613101UL, 4084104273UL, 647580587UL, 1460988169UL, 3944640945UL, 3301866374UL, 3458437694UL, 2913596196UL, 2960957119UL, 1316491503UL, 2674694926UL, 2404530503UL, 2485431762UL, 692294537UL, 3148362914UL, 1645995464UL, 3697728317UL, 706771848UL, 3734467362UL, 2768750385UL, 670964862UL, 1337146928UL, 1449841372UL, 1239527551UL, 592595530UL, 4204421245UL, +3121493408UL, 4147988039UL, 4003871917UL, 4035869533UL, 3652555523UL, 2709537023UL, 1429645393UL, 565106475UL, 327014810UL, 2716443687UL, 1278935671UL, 915509292UL, 397356303UL, 3248246752UL, 204830047UL, 1086107506UL, 1795464380UL, 3485315196UL, 1731529670UL, 662578255UL, 3645735256UL, 850847993UL, 1794523220UL, 577288126UL, 4237140216UL, 1126950UL, 2601642298UL, 1469035973UL, 2727135938UL, 92392213UL, 3668777652UL, 756260381UL, +41782389UL, 226724724UL, 1123105466UL, 738274780UL, 1846857904UL, 3185630605UL, 823108172UL, 2880110296UL, 3371270228UL, 2865413534UL, 564221408UL, 591845835UL, 2356214088UL, 4157618574UL, 1336639597UL, 4180084026UL, 3195588503UL, 4266261353UL, 3844986377UL, 2073158796UL, 56968669UL, 1234765864UL, 3166457679UL, 1001761927UL, 3146725645UL, 3295822468UL, 4135196531UL, 496099322UL, 541676954UL, 4143543278UL, 1941480444UL, 3607603517UL, +2578543796UL, 1068806322UL, 4081693775UL, 3600072515UL, 651444872UL, 1131603264UL, 47991343UL, 3748890341UL, 3413467790UL, 1567802204UL, 2823058381UL, 2662653600UL, 1516568259UL, 4132590383UL, 3192977084UL, 4247798474UL, 2554440323UL, 461466951UL, 1313208797UL, 637811069UL, 2744898822UL, 982676468UL, 3444149988UL, 1764224523UL, 4016338923UL, 2845667517UL, 451503008UL, 2594402002UL, 373730087UL, 3013524828UL, 3442521115UL, 1086137206UL, +2740782133UL, 2391000148UL, 3964107377UL, 4060067791UL, 731470002UL, 3161911677UL, 3441985401UL, 2472173593UL, 4227407417UL, 44456710UL, 3623045141UL, 1873516415UL, 884116165UL, 2550700713UL, 4004771121UL, 1053106195UL, 838088473UL, 2279863068UL, 1296332348UL, 1587145121UL, 1806935386UL, 4138151954UL, 4030442072UL, 2552496880UL, 2570695340UL, 2328331779UL, 3132267322UL, 227377796UL, 3887816270UL, 3570998746UL, 3654577129UL, 1603734504UL, +1528807885UL, 3365552060UL, 188017185UL, 2134741424UL, 809367801UL, 1667936422UL, 1358744245UL, 1503613101UL, 4084104273UL, 647580587UL, 1460988169UL, 2318828416UL, 3301866374UL, 3458437694UL, 2913596196UL, 2960957119UL, 49464436UL, 2674694926UL, 2404530503UL, 2485431762UL, 692294537UL, 1803418945UL, 1645995464UL, 3697728317UL, 706771848UL, 3734467362UL, 2407932841UL, 670964862UL, 1337146928UL, 1449841372UL, 1239527551UL, 1124552917UL, +4204421245UL, 3121493408UL, 4147988039UL, 4003871917UL, 3542256025UL, 3652555523UL, 2709537023UL, 1429645393UL, 565106475UL, 2063548817UL, 2716443687UL, 1278935671UL, 915509292UL, 397356303UL, 1049916999UL, 204830047UL, 1086107506UL, 1795464380UL, 3485315196UL, 2183256184UL, 662578255UL, 3645735256UL, 850847993UL, 1794523220UL, 2943700388UL, 4237140216UL, 1126950UL, 2601642298UL, 1469035973UL, 535075238UL, 92392213UL, 3668777652UL, +756260381UL, 41782389UL, 1043025574UL, 1123105466UL, 738274780UL, 1846857904UL, 3185630605UL, 3324487649UL, 2880110296UL, 3371270228UL, 2865413534UL, 564221408UL, 2528599862UL, 2356214088UL, 4157618574UL, 1336639597UL, 4180084026UL, 592094844UL, 4266261353UL, 3844986377UL, 2073158796UL, 56968669UL, 629503707UL, 3166457679UL, 1001761927UL, 3146725645UL, 3295822468UL, 2725304934UL, 496099322UL, 541676954UL, 4143543278UL, 1941480444UL, +3557859116UL, 31832949UL, 3805791401UL, 4056283801UL, 242812250UL, 4072988068UL, 2316479446UL, 2260433816UL, 2211372380UL, 2039672698UL, 2947948280UL, 4106140026UL, 342600216UL, 98745656UL, 2541799209UL, 926067404UL, 2733213159UL, 3163537903UL, 2800370126UL, 2099121446UL, 1279545581UL, 3699822446UL, 3764095615UL, 690503808UL, 3799637505UL, 1000641330UL, 242588257UL, 3657834529UL, 824791208UL, 2529299371UL, 4081898575UL, 2120338882UL, +1273883107UL, 1680877886UL, 1253060582UL, 1760259553UL, 2250763915UL, 31780198UL, 2511451445UL, 3102141340UL, 861489797UL, 105854693UL, 70927387UL, 2725671050UL, 688282241UL, 2622257646UL, 3466254816UL, 1905008219UL, 2980966436UL, 2154356718UL, 1075686806UL, 1966147415UL, 2357249256UL, 2684600972UL, 400926709UL, 523449509UL, 2891602783UL, 673425710UL, 3766475216UL, 2319843954UL, 3471794777UL, 13838840UL, 1908374660UL, 3839606132UL, +3829795513UL, 3403561639UL, 1369780874UL, 4276407916UL, 3217619UL, 1284482371UL, 2020138237UL, 2804427294UL, 1194369854UL, 1094800747UL, 2119081501UL, 726494474UL, 490750173UL, 1117517565UL, 3498786968UL, 2163060528UL, 696718831UL, 2780121254UL, 1286646297UL, 1594539045UL, 411215116UL, 1407268753UL, 2759136967UL, 2179483407UL, 2088977769UL, 2737453188UL, 2411478102UL, 3112688013UL, 4112484868UL, 429293789UL, 426390687UL, 3158027863UL, +2601897382UL, 1546855515UL, 4258208908UL, 3691263847UL, 2394986813UL, 1986623921UL, 2632462203UL, 3551311099UL, 3309482741UL, 2632571927UL, 1200010240UL, 554555739UL, 4119397989UL, 622818813UL, 3116222066UL, 1801867255UL, 2738500841UL, 1452697246UL, 733457482UL, 1680421668UL, 1035766144UL, 468847991UL, 3606474156UL, 2612692123UL, 730556693UL, 859096521UL, 4005878655UL, 1138273887UL, 2182363629UL, 2710579590UL, 3345140092UL, 2562710857UL, +3859276724UL, 2318176233UL, 3964665794UL, 3295219265UL, 3037789445UL, 371545704UL, 3434130670UL, 3686032092UL, 19964088UL, 340386179UL, 2147090894UL, 1446742483UL, 3083526520UL, 561888846UL, 2903328518UL, 1524465288UL, 360120037UL, 2031515996UL, 1516035872UL, 2752848969UL, 1094251072UL, 984159948UL, 369999653UL, 864602622UL, 2402584241UL, 3028363830UL, 252580667UL, 480470405UL, 3201548259UL, 2739036185UL, 2198549891UL, 1978812013UL, +}, +{ +2546657140UL, 2771792972UL, 3371698159UL, 1137313111UL, 2399264952UL, 1204642544UL, 2090179262UL, 2948712987UL, 2908027331UL, 498636511UL, 2292804841UL, 1480836858UL, 2826016727UL, 196495965UL, 2168559184UL, 3910150715UL, 320076735UL, 3144753899UL, 3199094529UL, 1165806050UL, 728308199UL, 2322528104UL, 2891334400UL, 561853019UL, 4161870615UL, 1348321971UL, 2461357166UL, 1216229488UL, 1392766290UL, 3060494848UL, 3282469664UL, 1866493654UL, +2351421557UL, 4195620347UL, 1512242723UL, 478174598UL, 1087303780UL, 471631659UL, 2599553643UL, 791527994UL, 563537164UL, 1238109907UL, 3218421602UL, 133222502UL, 4182363220UL, 305688802UL, 2666439314UL, 2408520958UL, 787389550UL, 4226450542UL, 4107143646UL, 4103547035UL, 1840887424UL, 2686247491UL, 334267386UL, 3772035402UL, 3436827662UL, 1411515743UL, 2193739735UL, 1892746640UL, 4163192062UL, 2921191805UL, 1011310614UL, 2178118214UL, +33647321UL, 1121452997UL, 507942677UL, 2542792587UL, 351339975UL, 1586639416UL, 1918003826UL, 2513357034UL, 2747854573UL, 606238275UL, 1132105249UL, 574593993UL, 2655425816UL, 1680556547UL, 1831942411UL, 2587194016UL, 90710116UL, 4291431098UL, 1899367028UL, 3251152898UL, 3297078396UL, 2712235924UL, 1546135008UL, 897753268UL, 1619454780UL, 938130143UL, 1828916640UL, 3620488958UL, 1822437033UL, 172584228UL, 1853048226UL, 3659288522UL, +3623450763UL, 1893292786UL, 851522142UL, 3411705687UL, 4106341088UL, 4109830348UL, 1193339049UL, 878885723UL, 2964062476UL, 2320209608UL, 1777678953UL, 2886897705UL, 3856938396UL, 252913914UL, 3648685154UL, 544382669UL, 2631141468UL, 1524405364UL, 1848509666UL, 580646927UL, 2451560151UL, 181916967UL, 1426301928UL, 1652422182UL, 2625099169UL, 176664750UL, 1582626255UL, 1675120608UL, 2571617898UL, 2096572277UL, 2471745846UL, 419906507UL, +886861124UL, 1974832558UL, 3157060904UL, 216000225UL, 746978071UL, 1424984058UL, 1457979883UL, 809822177UL, 3833178010UL, 3926414726UL, 1423462846UL, 3024443248UL, 4067020014UL, 2881559869UL, 1376840097UL, 548130303UL, 1118013762UL, 1309103114UL, 2227304261UL, 4205319357UL, 228947246UL, 2167410411UL, 620496852UL, 2724112116UL, 705259153UL, 3499686911UL, 3085999115UL, 2447267299UL, 4190122199UL, 1091465954UL, 1233728238UL, 39711865UL, +1076751044UL, 2546657140UL, 2771792972UL, 3371698159UL, 1137313111UL, 3857150586UL, 1204642544UL, 2090179262UL, 2948712987UL, 2908027331UL, 368199414UL, 2292804841UL, 1480836858UL, 2826016727UL, 196495965UL, 3235583934UL, 3910150715UL, 320076735UL, 3144753899UL, 3199094529UL, 1374597050UL, 728308199UL, 2322528104UL, 2891334400UL, 561853019UL, 1515915224UL, 1348321971UL, 2461357166UL, 1216229488UL, 1392766290UL, 15252704UL, 3282469664UL, +1866493654UL, 2351421557UL, 4195620347UL, 192355609UL, 478174598UL, 1087303780UL, 471631659UL, 2599553643UL, 1725604263UL, 563537164UL, 1238109907UL, 3218421602UL, 133222502UL, 305098282UL, 305688802UL, 2666439314UL, 2408520958UL, 787389550UL, 3195522899UL, 4107143646UL, 4103547035UL, 1840887424UL, 2686247491UL, 1565529892UL, 3772035402UL, 3436827662UL, 1411515743UL, 2193739735UL, 1848198417UL, 4163192062UL, 2921191805UL, 1011310614UL, +2178118214UL, 3474206203UL, 1121452997UL, 507942677UL, 2542792587UL, 351339975UL, 3599278861UL, 1918003826UL, 2513357034UL, 2747854573UL, 606238275UL, 446979745UL, 574593993UL, 2655425816UL, 1680556547UL, 1831942411UL, 3338512802UL, 90710116UL, 4291431098UL, 1899367028UL, 3251152898UL, 1006512939UL, 2712235924UL, 1546135008UL, 897753268UL, 1619454780UL, 1429190743UL, 1828916640UL, 3620488958UL, 1822437033UL, 172584228UL, 2529855020UL, +3659288522UL, 3623450763UL, 1893292786UL, 851522142UL, 1417935793UL, 4106341088UL, 4109830348UL, 1193339049UL, 878885723UL, 1886400637UL, 2320209608UL, 1777678953UL, 2886897705UL, 3856938396UL, 1813134786UL, 3648685154UL, 544382669UL, 2631141468UL, 1524405364UL, 687661410UL, 580646927UL, 2451560151UL, 181916967UL, 1426301928UL, 1463347373UL, 2625099169UL, 176664750UL, 1582626255UL, 1675120608UL, 3387060344UL, 2096572277UL, 2471745846UL, +419906507UL, 886861124UL, 4209699955UL, 3157060904UL, 216000225UL, 746978071UL, 1424984058UL, 3063941448UL, 809822177UL, 3833178010UL, 3926414726UL, 1423462846UL, 750559587UL, 4067020014UL, 2881559869UL, 1376840097UL, 548130303UL, 4056763004UL, 1309103114UL, 2227304261UL, 4205319357UL, 228947246UL, 774411056UL, 620496852UL, 2724112116UL, 705259153UL, 3499686911UL, 2486247387UL, 2447267299UL, 4190122199UL, 1091465954UL, 1233728238UL, +54639263UL, 1076751044UL, 2546657140UL, 2771792972UL, 3371698159UL, 1152150303UL, 3857150586UL, 1204642544UL, 2090179262UL, 2948712987UL, 452427847UL, 368199414UL, 2292804841UL, 1480836858UL, 2826016727UL, 1929008184UL, 3235583934UL, 3910150715UL, 320076735UL, 3144753899UL, 895636897UL, 1374597050UL, 728308199UL, 2322528104UL, 2891334400UL, 1871824871UL, 1515915224UL, 1348321971UL, 2461357166UL, 1216229488UL, 3170568098UL, 15252704UL, +3282469664UL, 1866493654UL, 2351421557UL, 4253216490UL, 192355609UL, 478174598UL, 1087303780UL, 471631659UL, 4230260400UL, 1725604263UL, 563537164UL, 1238109907UL, 3218421602UL, 960481514UL, 305098282UL, 305688802UL, 2666439314UL, 2408520958UL, 242741163UL, 3195522899UL, 4107143646UL, 4103547035UL, 1840887424UL, 2768321503UL, 1565529892UL, 3772035402UL, 3436827662UL, 1411515743UL, 545362965UL, 1848198417UL, 4163192062UL, 2921191805UL, +1011310614UL, 1196775493UL, 3474206203UL, 1121452997UL, 507942677UL, 2542792587UL, 1948892535UL, 3599278861UL, 1918003826UL, 2513357034UL, 2747854573UL, 4172793632UL, 446979745UL, 574593993UL, 2655425816UL, 1680556547UL, 2986869736UL, 3338512802UL, 90710116UL, 4291431098UL, 1899367028UL, 3376952160UL, 1006512939UL, 2712235924UL, 1546135008UL, 897753268UL, 2061577225UL, 1429190743UL, 1828916640UL, 3620488958UL, 1822437033UL, 4221327184UL, +2529855020UL, 3659288522UL, 3623450763UL, 1893292786UL, 16446898UL, 1417935793UL, 4106341088UL, 4109830348UL, 1193339049UL, 2895194326UL, 1886400637UL, 2320209608UL, 1777678953UL, 2886897705UL, 117861450UL, 1813134786UL, 3648685154UL, 544382669UL, 2631141468UL, 1105253905UL, 687661410UL, 580646927UL, 2451560151UL, 181916967UL, 1605087684UL, 1463347373UL, 2625099169UL, 176664750UL, 1582626255UL, 1993431057UL, 3387060344UL, 2096572277UL, +2471745846UL, 419906507UL, 3219719670UL, 4209699955UL, 3157060904UL, 216000225UL, 746978071UL, 3304126047UL, 3063941448UL, 809822177UL, 3833178010UL, 3926414726UL, 4061584738UL, 750559587UL, 4067020014UL, 2881559869UL, 1376840097UL, 973425409UL, 4056763004UL, 1309103114UL, 2227304261UL, 4205319357UL, 939664759UL, 774411056UL, 620496852UL, 2724112116UL, 705259153UL, 176172666UL, 2486247387UL, 2447267299UL, 4190122199UL, 1091465954UL, +300145620UL, 54639263UL, 1076751044UL, 2546657140UL, 2771792972UL, 188149161UL, 1152150303UL, 3857150586UL, 1204642544UL, 2090179262UL, 626100323UL, 452427847UL, 368199414UL, 2292804841UL, 1480836858UL, 2700509669UL, 1929008184UL, 3235583934UL, 3910150715UL, 320076735UL, 1715326239UL, 895636897UL, 1374597050UL, 728308199UL, 2322528104UL, 2356051490UL, 1871824871UL, 1515915224UL, 1348321971UL, 2461357166UL, 243332180UL, 3170568098UL, +15252704UL, 3282469664UL, 1866493654UL, 4079212881UL, 4253216490UL, 192355609UL, 478174598UL, 1087303780UL, 3787911270UL, 4230260400UL, 1725604263UL, 563537164UL, 1238109907UL, 1147223471UL, 960481514UL, 305098282UL, 305688802UL, 2666439314UL, 1503870433UL, 242741163UL, 3195522899UL, 4107143646UL, 4103547035UL, 4041516761UL, 2768321503UL, 1565529892UL, 3772035402UL, 3436827662UL, 3952861918UL, 545362965UL, 1848198417UL, 4163192062UL, +2921191805UL, 793561655UL, 1196775493UL, 3474206203UL, 1121452997UL, 507942677UL, 3788690254UL, 1948892535UL, 3599278861UL, 1918003826UL, 2513357034UL, 3301940062UL, 4172793632UL, 446979745UL, 574593993UL, 2655425816UL, 667233719UL, 2986869736UL, 3338512802UL, 90710116UL, 4291431098UL, 2027122085UL, 3376952160UL, 1006512939UL, 2712235924UL, 1546135008UL, 2609276017UL, 2061577225UL, 1429190743UL, 1828916640UL, 3620488958UL, 1603195641UL, +4221327184UL, 2529855020UL, 3659288522UL, 3623450763UL, 2313432963UL, 16446898UL, 1417935793UL, 4106341088UL, 4109830348UL, 4106013120UL, 2895194326UL, 1886400637UL, 2320209608UL, 1777678953UL, 1952597964UL, 117861450UL, 1813134786UL, 3648685154UL, 544382669UL, 3108229631UL, 1105253905UL, 687661410UL, 580646927UL, 2451560151UL, 1160575897UL, 1605087684UL, 1463347373UL, 2625099169UL, 176664750UL, 1998534134UL, 1993431057UL, 3387060344UL, +2096572277UL, 2471745846UL, 2246406696UL, 3219719670UL, 4209699955UL, 3157060904UL, 216000225UL, 902956869UL, 3304126047UL, 3063941448UL, 809822177UL, 3833178010UL, 815366736UL, 4061584738UL, 750559587UL, 4067020014UL, 2881559869UL, 350775477UL, 973425409UL, 4056763004UL, 1309103114UL, 2227304261UL, 2047915817UL, 939664759UL, 774411056UL, 620496852UL, 2724112116UL, 3593903529UL, 176172666UL, 2486247387UL, 2447267299UL, 4190122199UL, +1450746791UL, 1521739409UL, 272699299UL, 4113952664UL, 1408743622UL, 4082014187UL, 2454446462UL, 1401621236UL, 2050232096UL, 4204834821UL, 2413497685UL, 1032465253UL, 4276089655UL, 1737267711UL, 3335718398UL, 1924071395UL, 1560525661UL, 3064183869UL, 1775038231UL, 89761304UL, 489201378UL, 1236489133UL, 2774076159UL, 822652970UL, 1583752702UL, 1781766972UL, 2238480533UL, 3428349870UL, 3344555477UL, 2251934941UL, 2533404243UL, 3651295253UL, +2359372862UL, 704049384UL, 3238382362UL, 2405156187UL, 2572833624UL, 531907732UL, 2240111412UL, 4102445586UL, 849739856UL, 3649572083UL, 3317634415UL, 1141345331UL, 1118528358UL, 1664181643UL, 648360156UL, 1364897187UL, 289264571UL, 1625825195UL, 1075970578UL, 3925373833UL, 2780782646UL, 727038162UL, 2824687935UL, 3844230994UL, 2070739238UL, 2437298873UL, 1837327520UL, 4248571219UL, 183041221UL, 3759390508UL, 3881974011UL, 658115161UL, +560642175UL, 32860408UL, 1321227669UL, 1380454450UL, 1676524786UL, 476585241UL, 4034481274UL, 1110506516UL, 815601591UL, 2009522227UL, 2168306897UL, 1856639149UL, 1328281664UL, 2710915389UL, 1886116025UL, 2074502324UL, 23109943UL, 670045122UL, 2926671795UL, 4269143768UL, 2688621201UL, 1618605914UL, 1541217762UL, 4273045819UL, 1029546542UL, 3663663567UL, 1402692384UL, 109336276UL, 2446546057UL, 2225682064UL, 3535545430UL, 3847123891UL, +369718877UL, 3411726117UL, 703735748UL, 3139527634UL, 22388546UL, 998860697UL, 2532911305UL, 1532808237UL, 4170332196UL, 1131906845UL, 1814343609UL, 4161931326UL, 1185668213UL, 1903273604UL, 3466154373UL, 3988139604UL, 1079368270UL, 991305574UL, 898158502UL, 2898908951UL, 651161128UL, 1952607949UL, 1221528540UL, 29979722UL, 3006846808UL, 2911550178UL, 2569412437UL, 1460616937UL, 2127921978UL, 3689931108UL, 950505297UL, 3469337654UL, +3180457017UL, 2316433735UL, 1464678429UL, 2867173456UL, 391248106UL, 3622065314UL, 2143251073UL, 860219584UL, 323835636UL, 340886643UL, 1805485977UL, 109344001UL, 1537119779UL, 1795626099UL, 2568079633UL, 3048040562UL, 1204069532UL, 2488753091UL, 2160014198UL, 3132782711UL, 1266102795UL, 91252225UL, 2018366053UL, 39675212UL, 979320891UL, 343397131UL, 814470367UL, 366655857UL, 3287033048UL, 3379301026UL, 1566381433UL, 3431153818UL, +}, +{ +2234324389UL, 1682296894UL, 3526681456UL, 3988544681UL, 1315506584UL, 1754723911UL, 3607564438UL, 3764062195UL, 3408328234UL, 2385116969UL, 3827569659UL, 4104590721UL, 2612634189UL, 1762747544UL, 1676800931UL, 1814546108UL, 2684685172UL, 1659194343UL, 3381624140UL, 2286640580UL, 688245437UL, 2593335056UL, 1657668516UL, 1161309746UL, 3390664973UL, 2460564382UL, 2811435329UL, 2169200311UL, 2768093584UL, 4288309691UL, 1341061221UL, 1361417084UL, +3060155336UL, 2526021346UL, 1037055386UL, 890124736UL, 2185462193UL, 765141735UL, 1841745804UL, 3562499272UL, 1437907207UL, 2127475991UL, 2845453063UL, 4007976206UL, 4160093314UL, 2717704308UL, 4193767498UL, 1667876711UL, 3477753188UL, 3150367681UL, 3224086539UL, 231347764UL, 2737121599UL, 1230656103UL, 4168131490UL, 1463860373UL, 2760968409UL, 2579133178UL, 2309591728UL, 2958907244UL, 1041094855UL, 685134804UL, 3861095208UL, 1088109135UL, +815655228UL, 2618003265UL, 3454840568UL, 1668276240UL, 1668403077UL, 663034899UL, 4020374281UL, 1896863688UL, 677285319UL, 4047674693UL, 4098535894UL, 2038783953UL, 236635760UL, 3641273565UL, 3568356824UL, 3405704765UL, 186484522UL, 3626346451UL, 3653227559UL, 281949942UL, 1847600066UL, 4168753288UL, 1723123703UL, 3600798445UL, 4267802363UL, 2947454105UL, 468768748UL, 2745777741UL, 26635454UL, 837186232UL, 206931043UL, 2601865569UL, +2021732453UL, 3171165636UL, 786833002UL, 116631308UL, 1604778670UL, 437644814UL, 2437761489UL, 3573139998UL, 2637030522UL, 972076738UL, 4075927397UL, 1427554739UL, 597414077UL, 559325169UL, 1774857312UL, 224593737UL, 3697511293UL, 3905126277UL, 2446278950UL, 1847061846UL, 333176687UL, 2988562696UL, 3623938567UL, 2389910304UL, 4273100167UL, 1673622334UL, 2163644598UL, 3666601063UL, 3971760462UL, 4176957983UL, 565952761UL, 566996714UL, +103136762UL, 3648349163UL, 115456167UL, 3265051494UL, 2826313040UL, 1898888678UL, 3921049266UL, 1276809956UL, 4051866478UL, 959265349UL, 851980436UL, 3105565302UL, 2905096898UL, 342438530UL, 3428101638UL, 912389587UL, 2306839396UL, 3613297213UL, 200159550UL, 3406974927UL, 832121231UL, 2998593393UL, 1242069873UL, 1464281204UL, 1828082526UL, 2620095350UL, 3727900009UL, 986958825UL, 3332332947UL, 1610600284UL, 3193282615UL, 1873987353UL, +537698841UL, 2234324389UL, 1682296894UL, 3526681456UL, 3988544681UL, 1112334635UL, 1754723911UL, 3607564438UL, 3764062195UL, 3408328234UL, 2702680798UL, 3827569659UL, 4104590721UL, 2612634189UL, 1762747544UL, 1596420149UL, 1814546108UL, 2684685172UL, 1659194343UL, 3381624140UL, 2424233156UL, 688245437UL, 2593335056UL, 1657668516UL, 1161309746UL, 260803614UL, 2460564382UL, 2811435329UL, 2169200311UL, 2768093584UL, 1426048416UL, 1341061221UL, +1361417084UL, 3060155336UL, 2526021346UL, 688976997UL, 890124736UL, 2185462193UL, 765141735UL, 1841745804UL, 1113361455UL, 1437907207UL, 2127475991UL, 2845453063UL, 4007976206UL, 1719248425UL, 2717704308UL, 4193767498UL, 1667876711UL, 3477753188UL, 449353539UL, 3224086539UL, 231347764UL, 2737121599UL, 1230656103UL, 2122699205UL, 1463860373UL, 2760968409UL, 2579133178UL, 2309591728UL, 4017154219UL, 1041094855UL, 685134804UL, 3861095208UL, +1088109135UL, 3954527144UL, 2618003265UL, 3454840568UL, 1668276240UL, 1668403077UL, 3235241899UL, 4020374281UL, 1896863688UL, 677285319UL, 4047674693UL, 4043186819UL, 2038783953UL, 236635760UL, 3641273565UL, 3568356824UL, 3946220303UL, 186484522UL, 3626346451UL, 3653227559UL, 281949942UL, 1896524045UL, 4168753288UL, 1723123703UL, 3600798445UL, 4267802363UL, 412498526UL, 468768748UL, 2745777741UL, 26635454UL, 837186232UL, 1473941762UL, +2601865569UL, 2021732453UL, 3171165636UL, 786833002UL, 3461566768UL, 1604778670UL, 437644814UL, 2437761489UL, 3573139998UL, 306196591UL, 972076738UL, 4075927397UL, 1427554739UL, 597414077UL, 2401305323UL, 1774857312UL, 224593737UL, 3697511293UL, 3905126277UL, 1527832817UL, 1847061846UL, 333176687UL, 2988562696UL, 3623938567UL, 2731158470UL, 4273100167UL, 1673622334UL, 2163644598UL, 3666601063UL, 1991088422UL, 4176957983UL, 565952761UL, +566996714UL, 103136762UL, 1639884175UL, 115456167UL, 3265051494UL, 2826313040UL, 1898888678UL, 2976556877UL, 1276809956UL, 4051866478UL, 959265349UL, 851980436UL, 2482970929UL, 2905096898UL, 342438530UL, 3428101638UL, 912389587UL, 2716490551UL, 3613297213UL, 200159550UL, 3406974927UL, 832121231UL, 2865829307UL, 1242069873UL, 1464281204UL, 1828082526UL, 2620095350UL, 3671861666UL, 986958825UL, 3332332947UL, 1610600284UL, 3193282615UL, +164496953UL, 537698841UL, 2234324389UL, 1682296894UL, 3526681456UL, 486931321UL, 1112334635UL, 1754723911UL, 3607564438UL, 3764062195UL, 898439171UL, 2702680798UL, 3827569659UL, 4104590721UL, 2612634189UL, 1703436382UL, 1596420149UL, 1814546108UL, 2684685172UL, 1659194343UL, 3421607784UL, 2424233156UL, 688245437UL, 2593335056UL, 1657668516UL, 362342820UL, 260803614UL, 2460564382UL, 2811435329UL, 2169200311UL, 4248717010UL, 1426048416UL, +1341061221UL, 1361417084UL, 3060155336UL, 2693026827UL, 688976997UL, 890124736UL, 2185462193UL, 765141735UL, 2445632748UL, 1113361455UL, 1437907207UL, 2127475991UL, 2845453063UL, 1830953748UL, 1719248425UL, 2717704308UL, 4193767498UL, 1667876711UL, 2469362144UL, 449353539UL, 3224086539UL, 231347764UL, 2737121599UL, 2917779591UL, 2122699205UL, 1463860373UL, 2760968409UL, 2579133178UL, 2600345316UL, 4017154219UL, 1041094855UL, 685134804UL, +3861095208UL, 3682591427UL, 3954527144UL, 2618003265UL, 3454840568UL, 1668276240UL, 988400088UL, 3235241899UL, 4020374281UL, 1896863688UL, 677285319UL, 2749516227UL, 4043186819UL, 2038783953UL, 236635760UL, 3641273565UL, 4073317913UL, 3946220303UL, 186484522UL, 3626346451UL, 3653227559UL, 872336642UL, 1896524045UL, 4168753288UL, 1723123703UL, 3600798445UL, 524095357UL, 412498526UL, 468768748UL, 2745777741UL, 26635454UL, 840544541UL, +1473941762UL, 2601865569UL, 2021732453UL, 3171165636UL, 1058640324UL, 3461566768UL, 1604778670UL, 437644814UL, 2437761489UL, 3615438045UL, 306196591UL, 972076738UL, 4075927397UL, 1427554739UL, 2369367008UL, 2401305323UL, 1774857312UL, 224593737UL, 3697511293UL, 4186564433UL, 1527832817UL, 1847061846UL, 333176687UL, 2988562696UL, 4039340326UL, 2731158470UL, 4273100167UL, 1673622334UL, 2163644598UL, 307949376UL, 1991088422UL, 4176957983UL, +565952761UL, 566996714UL, 4159448552UL, 1639884175UL, 115456167UL, 3265051494UL, 2826313040UL, 2698725478UL, 2976556877UL, 1276809956UL, 4051866478UL, 959265349UL, 293029699UL, 2482970929UL, 2905096898UL, 342438530UL, 3428101638UL, 4172766741UL, 2716490551UL, 3613297213UL, 200159550UL, 3406974927UL, 3723281866UL, 2865829307UL, 1242069873UL, 1464281204UL, 1828082526UL, 3304191156UL, 3671861666UL, 986958825UL, 3332332947UL, 1610600284UL, +2370407607UL, 164496953UL, 537698841UL, 2234324389UL, 1682296894UL, 826891606UL, 486931321UL, 1112334635UL, 1754723911UL, 3607564438UL, 3598993552UL, 898439171UL, 2702680798UL, 3827569659UL, 4104590721UL, 1421852097UL, 1703436382UL, 1596420149UL, 1814546108UL, 2684685172UL, 4090587429UL, 3421607784UL, 2424233156UL, 688245437UL, 2593335056UL, 4151905751UL, 362342820UL, 260803614UL, 2460564382UL, 2811435329UL, 2402832015UL, 4248717010UL, +1426048416UL, 1341061221UL, 1361417084UL, 1629089021UL, 2693026827UL, 688976997UL, 890124736UL, 2185462193UL, 303105066UL, 2445632748UL, 1113361455UL, 1437907207UL, 2127475991UL, 62024604UL, 1830953748UL, 1719248425UL, 2717704308UL, 4193767498UL, 667433630UL, 2469362144UL, 449353539UL, 3224086539UL, 231347764UL, 3918249451UL, 2917779591UL, 2122699205UL, 1463860373UL, 2760968409UL, 4274016442UL, 2600345316UL, 4017154219UL, 1041094855UL, +685134804UL, 643006688UL, 3682591427UL, 3954527144UL, 2618003265UL, 3454840568UL, 4180665518UL, 988400088UL, 3235241899UL, 4020374281UL, 1896863688UL, 3678687414UL, 2749516227UL, 4043186819UL, 2038783953UL, 236635760UL, 2880089648UL, 4073317913UL, 3946220303UL, 186484522UL, 3626346451UL, 2454620114UL, 872336642UL, 1896524045UL, 4168753288UL, 1723123703UL, 2692406059UL, 524095357UL, 412498526UL, 468768748UL, 2745777741UL, 918726515UL, +840544541UL, 1473941762UL, 2601865569UL, 2021732453UL, 3534238020UL, 1058640324UL, 3461566768UL, 1604778670UL, 437644814UL, 2894699005UL, 3615438045UL, 306196591UL, 972076738UL, 4075927397UL, 3468671461UL, 2369367008UL, 2401305323UL, 1774857312UL, 224593737UL, 2734827022UL, 4186564433UL, 1527832817UL, 1847061846UL, 333176687UL, 2437714719UL, 4039340326UL, 2731158470UL, 4273100167UL, 1673622334UL, 196072958UL, 307949376UL, 1991088422UL, +4176957983UL, 565952761UL, 847200194UL, 4159448552UL, 1639884175UL, 115456167UL, 3265051494UL, 2503079777UL, 2698725478UL, 2976556877UL, 1276809956UL, 4051866478UL, 2731665893UL, 293029699UL, 2482970929UL, 2905096898UL, 342438530UL, 581060953UL, 4172766741UL, 2716490551UL, 3613297213UL, 200159550UL, 4222335623UL, 3723281866UL, 2865829307UL, 1242069873UL, 1464281204UL, 1080647953UL, 3304191156UL, 3671861666UL, 986958825UL, 3332332947UL, +920422540UL, 3656094274UL, 4036161427UL, 2157099981UL, 1855437762UL, 1385781426UL, 199192882UL, 489599802UL, 3472601685UL, 717544078UL, 2241742884UL, 3951326913UL, 3590866192UL, 1087524220UL, 3517385549UL, 360484251UL, 2718513148UL, 1386577185UL, 1833613127UL, 2926418589UL, 1652463225UL, 548895720UL, 1343026759UL, 1797789098UL, 3229783023UL, 1745843414UL, 200554865UL, 2442780740UL, 2359926428UL, 2970332116UL, 3097392757UL, 134294482UL, +936225458UL, 1968264650UL, 64868134UL, 3821668262UL, 2502175363UL, 1623767635UL, 2936073062UL, 1991791011UL, 2971174068UL, 3142195911UL, 2874818345UL, 2192526584UL, 496586185UL, 2491564144UL, 2415210641UL, 314307270UL, 2936737494UL, 557604388UL, 1067914024UL, 3270690738UL, 375601880UL, 962749065UL, 3610467620UL, 402112984UL, 1432929499UL, 3872957776UL, 3971384069UL, 2223968592UL, 407083609UL, 2178236674UL, 1806303230UL, 3397564470UL, +12158764UL, 415570813UL, 4033667395UL, 3687406137UL, 801878150UL, 953500350UL, 3667783172UL, 1203668106UL, 902418194UL, 779786150UL, 774683730UL, 2870261992UL, 509192460UL, 1961621392UL, 1064906432UL, 3665710891UL, 1733725153UL, 1887608856UL, 1314631523UL, 4097239005UL, 29074501UL, 3472521950UL, 4040841657UL, 532128023UL, 2333441401UL, 1671717886UL, 1678544416UL, 1218347584UL, 3680929567UL, 4025753853UL, 2810948711UL, 1846100306UL, +3377469279UL, 3144481747UL, 2625781306UL, 730632118UL, 3162408393UL, 3423660386UL, 1364968369UL, 4270900402UL, 1075484840UL, 2892932277UL, 3700635052UL, 3853022563UL, 281755151UL, 1530909868UL, 2364069707UL, 2361723426UL, 738500028UL, 1401903990UL, 1543704261UL, 2442916222UL, 1076190609UL, 1882477803UL, 740024557UL, 1591015439UL, 2730909167UL, 2723330839UL, 1637373491UL, 3777799860UL, 2921269571UL, 3698591972UL, 3997463570UL, 3877862147UL, +1912888417UL, 3365137165UL, 3465700492UL, 771243134UL, 4037723169UL, 1715894739UL, 1025821874UL, 1924958945UL, 3382242859UL, 121591031UL, 483980724UL, 546523388UL, 2446882279UL, 856267778UL, 578739009UL, 2978085488UL, 480884914UL, 966764808UL, 457039953UL, 3817520708UL, 1113646451UL, 2503896910UL, 3507840816UL, 717151671UL, 4149352573UL, 1568869830UL, 395015863UL, 773165995UL, 1853682362UL, 2861368846UL, 1884368812UL, 1250092101UL, +}, +{ +916910638UL, 961623451UL, 1193013401UL, 1016438484UL, 4091279871UL, 287282633UL, 8590725UL, 3575333670UL, 324340905UL, 3133751747UL, 2840894649UL, 2980503178UL, 1111215768UL, 2783846375UL, 72516413UL, 4158424384UL, 2184094569UL, 2305724254UL, 4057093054UL, 1407652993UL, 3105191537UL, 768505376UL, 298782270UL, 993926164UL, 2694730042UL, 1479658113UL, 2376490281UL, 2767906402UL, 1619969256UL, 3256472015UL, 2563843533UL, 2974784738UL, +2529307107UL, 4289918826UL, 3105587575UL, 3748950898UL, 2182744253UL, 431888679UL, 3780324902UL, 2525978209UL, 54545903UL, 1688749940UL, 2394884334UL, 3477656171UL, 263834270UL, 1562965459UL, 804704330UL, 4185729868UL, 138898835UL, 2113063150UL, 327612841UL, 1252226275UL, 935318076UL, 2956823075UL, 4095101181UL, 1510586062UL, 156282440UL, 3386839706UL, 2294393752UL, 1306167091UL, 4005033667UL, 651716500UL, 4115192738UL, 123027719UL, +3873547487UL, 2910637335UL, 2571924586UL, 3489608656UL, 956791985UL, 2467423726UL, 3214531645UL, 2054232851UL, 49634692UL, 377192215UL, 1865068750UL, 2479252980UL, 3481787748UL, 3243507737UL, 605491073UL, 4062466752UL, 988602517UL, 1539348794UL, 1555068617UL, 2657884010UL, 460334294UL, 4240766479UL, 3639800790UL, 253377117UL, 3969136265UL, 488705329UL, 1722560286UL, 2289159295UL, 1025876008UL, 2927117896UL, 767521707UL, 2047999999UL, +4260853571UL, 2079302241UL, 2409677301UL, 1087552976UL, 2363907365UL, 2574464321UL, 2606273241UL, 3716086457UL, 26053603UL, 3162779415UL, 14843078UL, 2614076143UL, 1157531920UL, 2773275636UL, 2338825066UL, 435472225UL, 1399711137UL, 1224374788UL, 2154533280UL, 560135209UL, 935800607UL, 1940258814UL, 3826959530UL, 3423217355UL, 3704934971UL, 3815248829UL, 3878175339UL, 1395508015UL, 3295101527UL, 177901558UL, 4167531389UL, 1375148189UL, +3125377631UL, 557218961UL, 4088880299UL, 3478859071UL, 3687276754UL, 2845114223UL, 1713171361UL, 1756507633UL, 3160807894UL, 2375334470UL, 843542578UL, 1907952570UL, 1544844563UL, 2294372007UL, 3336681376UL, 734347193UL, 102566945UL, 2311037104UL, 4294750194UL, 3572240326UL, 732958152UL, 263733314UL, 2087890678UL, 331542297UL, 3549110380UL, 2073894939UL, 2104101380UL, 3670791368UL, 3122901693UL, 3799823891UL, 3783548253UL, 1102633864UL, +44327348UL, 916910638UL, 961623451UL, 1193013401UL, 1016438484UL, 1873779640UL, 287282633UL, 8590725UL, 3575333670UL, 324340905UL, 1144671533UL, 2840894649UL, 2980503178UL, 1111215768UL, 2783846375UL, 2000673937UL, 4158424384UL, 2184094569UL, 2305724254UL, 4057093054UL, 533488413UL, 3105191537UL, 768505376UL, 298782270UL, 993926164UL, 2015456740UL, 1479658113UL, 2376490281UL, 2767906402UL, 1619969256UL, 3120736988UL, 2563843533UL, +2974784738UL, 2529307107UL, 4289918826UL, 729503771UL, 3748950898UL, 2182744253UL, 431888679UL, 3780324902UL, 373638396UL, 54545903UL, 1688749940UL, 2394884334UL, 3477656171UL, 1083764681UL, 1562965459UL, 804704330UL, 4185729868UL, 138898835UL, 823405282UL, 327612841UL, 1252226275UL, 935318076UL, 2956823075UL, 899234846UL, 1510586062UL, 156282440UL, 3386839706UL, 2294393752UL, 2769934879UL, 4005033667UL, 651716500UL, 4115192738UL, +123027719UL, 3729538641UL, 2910637335UL, 2571924586UL, 3489608656UL, 956791985UL, 139360134UL, 3214531645UL, 2054232851UL, 49634692UL, 377192215UL, 2754746969UL, 2479252980UL, 3481787748UL, 3243507737UL, 605491073UL, 732155706UL, 988602517UL, 1539348794UL, 1555068617UL, 2657884010UL, 3753733088UL, 4240766479UL, 3639800790UL, 253377117UL, 3969136265UL, 3848735787UL, 1722560286UL, 2289159295UL, 1025876008UL, 2927117896UL, 3661948694UL, +2047999999UL, 4260853571UL, 2079302241UL, 2409677301UL, 3421911122UL, 2363907365UL, 2574464321UL, 2606273241UL, 3716086457UL, 2064343322UL, 3162779415UL, 14843078UL, 2614076143UL, 1157531920UL, 826449637UL, 2338825066UL, 435472225UL, 1399711137UL, 1224374788UL, 3770340198UL, 560135209UL, 935800607UL, 1940258814UL, 3826959530UL, 2963586762UL, 3704934971UL, 3815248829UL, 3878175339UL, 1395508015UL, 3721612680UL, 177901558UL, 4167531389UL, +1375148189UL, 3125377631UL, 1023552290UL, 4088880299UL, 3478859071UL, 3687276754UL, 2845114223UL, 3831557301UL, 1756507633UL, 3160807894UL, 2375334470UL, 843542578UL, 2798365898UL, 1544844563UL, 2294372007UL, 3336681376UL, 734347193UL, 1856808621UL, 2311037104UL, 4294750194UL, 3572240326UL, 732958152UL, 1999195012UL, 2087890678UL, 331542297UL, 3549110380UL, 2073894939UL, 3115936764UL, 3670791368UL, 3122901693UL, 3799823891UL, 3783548253UL, +132796150UL, 44327348UL, 916910638UL, 961623451UL, 1193013401UL, 1753944196UL, 1873779640UL, 287282633UL, 8590725UL, 3575333670UL, 1447720209UL, 1144671533UL, 2840894649UL, 2980503178UL, 1111215768UL, 1211945983UL, 2000673937UL, 4158424384UL, 2184094569UL, 2305724254UL, 402617261UL, 533488413UL, 3105191537UL, 768505376UL, 298782270UL, 2915553159UL, 2015456740UL, 1479658113UL, 2376490281UL, 2767906402UL, 3473761811UL, 3120736988UL, +2563843533UL, 2974784738UL, 2529307107UL, 737859212UL, 729503771UL, 3748950898UL, 2182744253UL, 431888679UL, 2013420163UL, 373638396UL, 54545903UL, 1688749940UL, 2394884334UL, 675998523UL, 1083764681UL, 1562965459UL, 804704330UL, 4185729868UL, 1165431355UL, 823405282UL, 327612841UL, 1252226275UL, 935318076UL, 2420680216UL, 899234846UL, 1510586062UL, 156282440UL, 3386839706UL, 2101339651UL, 2769934879UL, 4005033667UL, 651716500UL, +4115192738UL, 112049740UL, 3729538641UL, 2910637335UL, 2571924586UL, 3489608656UL, 305695595UL, 139360134UL, 3214531645UL, 2054232851UL, 49634692UL, 1073828255UL, 2754746969UL, 2479252980UL, 3481787748UL, 3243507737UL, 3392719169UL, 732155706UL, 988602517UL, 1539348794UL, 1555068617UL, 3246776527UL, 3753733088UL, 4240766479UL, 3639800790UL, 253377117UL, 872273450UL, 3848735787UL, 1722560286UL, 2289159295UL, 1025876008UL, 4168154213UL, +3661948694UL, 2047999999UL, 4260853571UL, 2079302241UL, 2380420842UL, 3421911122UL, 2363907365UL, 2574464321UL, 2606273241UL, 3881916078UL, 2064343322UL, 3162779415UL, 14843078UL, 2614076143UL, 473288515UL, 826449637UL, 2338825066UL, 435472225UL, 1399711137UL, 3068538992UL, 3770340198UL, 560135209UL, 935800607UL, 1940258814UL, 1469655183UL, 2963586762UL, 3704934971UL, 3815248829UL, 3878175339UL, 2410602840UL, 3721612680UL, 177901558UL, +4167531389UL, 1375148189UL, 1367577763UL, 1023552290UL, 4088880299UL, 3478859071UL, 3687276754UL, 678224549UL, 3831557301UL, 1756507633UL, 3160807894UL, 2375334470UL, 2884561721UL, 2798365898UL, 1544844563UL, 2294372007UL, 3336681376UL, 1938834658UL, 1856808621UL, 2311037104UL, 4294750194UL, 3572240326UL, 2786764913UL, 1999195012UL, 2087890678UL, 331542297UL, 3549110380UL, 3597797341UL, 3115936764UL, 3670791368UL, 3122901693UL, 3799823891UL, +1271317799UL, 132796150UL, 44327348UL, 916910638UL, 961623451UL, 2427821332UL, 1753944196UL, 1873779640UL, 287282633UL, 8590725UL, 1244012658UL, 1447720209UL, 1144671533UL, 2840894649UL, 2980503178UL, 3548902577UL, 1211945983UL, 2000673937UL, 4158424384UL, 2184094569UL, 2152623453UL, 402617261UL, 533488413UL, 3105191537UL, 768505376UL, 1095141108UL, 2915553159UL, 2015456740UL, 1479658113UL, 2376490281UL, 337998873UL, 3473761811UL, +3120736988UL, 2563843533UL, 2974784738UL, 3087228498UL, 737859212UL, 729503771UL, 3748950898UL, 2182744253UL, 2140410733UL, 2013420163UL, 373638396UL, 54545903UL, 1688749940UL, 528290088UL, 675998523UL, 1083764681UL, 1562965459UL, 804704330UL, 2536362875UL, 1165431355UL, 823405282UL, 327612841UL, 1252226275UL, 4037635314UL, 2420680216UL, 899234846UL, 1510586062UL, 156282440UL, 2012335895UL, 2101339651UL, 2769934879UL, 4005033667UL, +651716500UL, 2552583570UL, 112049740UL, 3729538641UL, 2910637335UL, 2571924586UL, 2436645403UL, 305695595UL, 139360134UL, 3214531645UL, 2054232851UL, 2384286326UL, 1073828255UL, 2754746969UL, 2479252980UL, 3481787748UL, 1948315585UL, 3392719169UL, 732155706UL, 988602517UL, 1539348794UL, 4110558494UL, 3246776527UL, 3753733088UL, 4240766479UL, 3639800790UL, 3627363812UL, 872273450UL, 3848735787UL, 1722560286UL, 2289159295UL, 4122430477UL, +4168154213UL, 3661948694UL, 2047999999UL, 4260853571UL, 1767882442UL, 2380420842UL, 3421911122UL, 2363907365UL, 2574464321UL, 2778622726UL, 3881916078UL, 2064343322UL, 3162779415UL, 14843078UL, 1513897109UL, 473288515UL, 826449637UL, 2338825066UL, 435472225UL, 322954918UL, 3068538992UL, 3770340198UL, 560135209UL, 935800607UL, 345602050UL, 1469655183UL, 2963586762UL, 3704934971UL, 3815248829UL, 3508249920UL, 2410602840UL, 3721612680UL, +177901558UL, 4167531389UL, 2161244150UL, 1367577763UL, 1023552290UL, 4088880299UL, 3478859071UL, 1108183104UL, 678224549UL, 3831557301UL, 1756507633UL, 3160807894UL, 2551630811UL, 2884561721UL, 2798365898UL, 1544844563UL, 2294372007UL, 2520267760UL, 1938834658UL, 1856808621UL, 2311037104UL, 4294750194UL, 2310096003UL, 2786764913UL, 1999195012UL, 2087890678UL, 331542297UL, 1205238749UL, 3597797341UL, 3115936764UL, 3670791368UL, 3122901693UL, +2008141679UL, 2018425028UL, 3435073328UL, 1452813805UL, 1628661138UL, 1323367156UL, 1062553693UL, 4029321700UL, 2772685842UL, 3798388850UL, 1315172209UL, 3930983291UL, 3816791373UL, 529176017UL, 3419610188UL, 3331589216UL, 4016977274UL, 2047089790UL, 3892571923UL, 2363414008UL, 1144631948UL, 3004954882UL, 2558739305UL, 19774033UL, 2525079911UL, 3774885821UL, 2817837373UL, 986111566UL, 1446678953UL, 3238485630UL, 3993748600UL, 1601954599UL, +3100591537UL, 2098009380UL, 3935971261UL, 4202546603UL, 3713465083UL, 3845664764UL, 2466365355UL, 1452340065UL, 2003576531UL, 1013434822UL, 2254608933UL, 783902023UL, 3129770529UL, 129130612UL, 821418228UL, 350036483UL, 3473671510UL, 4128495167UL, 2773832518UL, 683262085UL, 2143353417UL, 256251732UL, 1719056536UL, 2670223618UL, 328467339UL, 1564657740UL, 451231672UL, 2788353006UL, 882900088UL, 3255241056UL, 3198073758UL, 2541070985UL, +1941509325UL, 674933160UL, 207753676UL, 2605303964UL, 1681335994UL, 1143520001UL, 448872632UL, 302917879UL, 1100138495UL, 2058770021UL, 3116955098UL, 2081754747UL, 3734924767UL, 1916718058UL, 3873335960UL, 2740460398UL, 2171157007UL, 27677949UL, 2364721928UL, 175851655UL, 1468083950UL, 3162369526UL, 2441504540UL, 556978295UL, 2372096172UL, 3181101116UL, 2582850132UL, 1101292643UL, 862643740UL, 2095546242UL, 3261953801UL, 748040658UL, +3970037674UL, 819116843UL, 3594523650UL, 1597423019UL, 4109336883UL, 1198282420UL, 2905230517UL, 1729529596UL, 3230132814UL, 3640242164UL, 1899059108UL, 1944906555UL, 3426510495UL, 3035188107UL, 6448083UL, 1093882965UL, 2867500469UL, 3626379157UL, 1849073068UL, 897616501UL, 604221668UL, 1020676159UL, 4083635798UL, 1716022041UL, 3671877965UL, 1738820843UL, 30077467UL, 729231767UL, 3413193248UL, 207000406UL, 3854363185UL, 3302747326UL, +3293643267UL, 2101250157UL, 460131091UL, 4159442595UL, 1133391045UL, 1031215443UL, 4195487944UL, 45931575UL, 2922629291UL, 789302543UL, 3024994662UL, 442525623UL, 2850119076UL, 838309503UL, 2585361734UL, 1020449164UL, 1623631007UL, 955374631UL, 2932467671UL, 3713639221UL, 3019179416UL, 977970472UL, 1817244230UL, 3856774853UL, 1140530868UL, 886199600UL, 1218509766UL, 4001537244UL, 2840913665UL, 2133254364UL, 3332344608UL, 475291624UL, +}, +{ +1854921599UL, 2655519695UL, 3124573588UL, 319882484UL, 603545603UL, 4175512633UL, 141286453UL, 1183670252UL, 1789500145UL, 37351733UL, 3190829323UL, 2782782009UL, 493805446UL, 1228958246UL, 2672482554UL, 2274981421UL, 2935438833UL, 3625733677UL, 3679506394UL, 687805550UL, 134516308UL, 3576789728UL, 965007022UL, 1056542222UL, 2319405423UL, 3944221200UL, 950102624UL, 3848192810UL, 3205299696UL, 82033760UL, 1241913280UL, 1360146137UL, +1675732327UL, 2164452797UL, 3920498715UL, 2226452641UL, 3172047212UL, 1569171738UL, 2631589480UL, 2889660225UL, 2030783667UL, 2237381973UL, 2706217212UL, 3143638386UL, 1733174225UL, 1166820137UL, 3818389960UL, 193959252UL, 2793509934UL, 316291605UL, 2502743884UL, 1963136977UL, 3739017448UL, 25754513UL, 1590156485UL, 1856291967UL, 4143674472UL, 2538785911UL, 2159135699UL, 1908446793UL, 3303325234UL, 2589568800UL, 1193586059UL, 77481069UL, +789413194UL, 2556570543UL, 162987300UL, 1960844609UL, 2973799047UL, 4253906178UL, 315868734UL, 2542622968UL, 3949539136UL, 1479106582UL, 4225431384UL, 1235059630UL, 1533374854UL, 847792023UL, 4031286530UL, 4194276632UL, 164541100UL, 1010135841UL, 143302319UL, 1335585015UL, 1237311692UL, 20896020UL, 344974153UL, 2576803233UL, 3430251730UL, 984163376UL, 2680612471UL, 1276425436UL, 2400671554UL, 1628640140UL, 2161048926UL, 2109177634UL, +998215324UL, 3127793500UL, 1759998050UL, 3105138908UL, 2583746384UL, 2126302368UL, 3258602104UL, 1262742375UL, 3565617377UL, 3726060195UL, 157069329UL, 390662438UL, 3800994052UL, 2007694482UL, 377281730UL, 3251789121UL, 236703173UL, 122782596UL, 775407411UL, 3394010206UL, 4232159202UL, 468321553UL, 2704615220UL, 1332411375UL, 2978494251UL, 989230484UL, 3122841814UL, 2348872707UL, 731335994UL, 541354422UL, 223117443UL, 2225009071UL, +4230058949UL, 1875162926UL, 3897048544UL, 3550177883UL, 2461273592UL, 1046820583UL, 1333727817UL, 1378024753UL, 3686775275UL, 4230752590UL, 64834458UL, 1281467967UL, 729116355UL, 3886390916UL, 65029451UL, 3478506446UL, 1387684482UL, 1172004841UL, 2525409243UL, 1677678908UL, 1704646757UL, 930937262UL, 1088384271UL, 689357059UL, 1754542213UL, 702963842UL, 2864311668UL, 1960202673UL, 1009675673UL, 3742350158UL, 3751269215UL, 3166659283UL, +9090161UL, 1854921599UL, 2655519695UL, 3124573588UL, 319882484UL, 1422536794UL, 4175512633UL, 141286453UL, 1183670252UL, 1789500145UL, 850391877UL, 3190829323UL, 2782782009UL, 493805446UL, 1228958246UL, 837232655UL, 2274981421UL, 2935438833UL, 3625733677UL, 3679506394UL, 955772620UL, 134516308UL, 3576789728UL, 965007022UL, 1056542222UL, 874117013UL, 3944221200UL, 950102624UL, 3848192810UL, 3205299696UL, 543679720UL, 1241913280UL, +1360146137UL, 1675732327UL, 2164452797UL, 1169030022UL, 2226452641UL, 3172047212UL, 1569171738UL, 2631589480UL, 3783543297UL, 2030783667UL, 2237381973UL, 2706217212UL, 3143638386UL, 1560162209UL, 1166820137UL, 3818389960UL, 193959252UL, 2793509934UL, 4258046618UL, 2502743884UL, 1963136977UL, 3739017448UL, 25754513UL, 1204846712UL, 1856291967UL, 4143674472UL, 2538785911UL, 2159135699UL, 3889946075UL, 3303325234UL, 2589568800UL, 1193586059UL, +77481069UL, 969912041UL, 2556570543UL, 162987300UL, 1960844609UL, 2973799047UL, 427583517UL, 315868734UL, 2542622968UL, 3949539136UL, 1479106582UL, 92839917UL, 1235059630UL, 1533374854UL, 847792023UL, 4031286530UL, 1147875681UL, 164541100UL, 1010135841UL, 143302319UL, 1335585015UL, 368616909UL, 20896020UL, 344974153UL, 2576803233UL, 3430251730UL, 1078575783UL, 2680612471UL, 1276425436UL, 2400671554UL, 1628640140UL, 4149623645UL, +2109177634UL, 998215324UL, 3127793500UL, 1759998050UL, 3525419965UL, 2583746384UL, 2126302368UL, 3258602104UL, 1262742375UL, 1996113346UL, 3726060195UL, 157069329UL, 390662438UL, 3800994052UL, 982000497UL, 377281730UL, 3251789121UL, 236703173UL, 122782596UL, 2303768414UL, 3394010206UL, 4232159202UL, 468321553UL, 2704615220UL, 681592492UL, 2978494251UL, 989230484UL, 3122841814UL, 2348872707UL, 4089094260UL, 541354422UL, 223117443UL, +2225009071UL, 4230058949UL, 2754981128UL, 3897048544UL, 3550177883UL, 2461273592UL, 1046820583UL, 668143612UL, 1378024753UL, 3686775275UL, 4230752590UL, 64834458UL, 3765910650UL, 729116355UL, 3886390916UL, 65029451UL, 3478506446UL, 3419111947UL, 1172004841UL, 2525409243UL, 1677678908UL, 1704646757UL, 155635560UL, 1088384271UL, 689357059UL, 1754542213UL, 702963842UL, 2712009967UL, 1960202673UL, 1009675673UL, 3742350158UL, 3751269215UL, +129749802UL, 9090161UL, 1854921599UL, 2655519695UL, 3124573588UL, 809557750UL, 1422536794UL, 4175512633UL, 141286453UL, 1183670252UL, 1739311360UL, 850391877UL, 3190829323UL, 2782782009UL, 493805446UL, 1738527771UL, 837232655UL, 2274981421UL, 2935438833UL, 3625733677UL, 1858071296UL, 955772620UL, 134516308UL, 3576789728UL, 965007022UL, 3367712327UL, 874117013UL, 3944221200UL, 950102624UL, 3848192810UL, 2420548306UL, 543679720UL, +1241913280UL, 1360146137UL, 1675732327UL, 176019367UL, 1169030022UL, 2226452641UL, 3172047212UL, 1569171738UL, 76544055UL, 3783543297UL, 2030783667UL, 2237381973UL, 2706217212UL, 3283985735UL, 1560162209UL, 1166820137UL, 3818389960UL, 193959252UL, 346134252UL, 4258046618UL, 2502743884UL, 1963136977UL, 3739017448UL, 3887005605UL, 1204846712UL, 1856291967UL, 4143674472UL, 2538785911UL, 366578749UL, 3889946075UL, 3303325234UL, 2589568800UL, +1193586059UL, 2917569085UL, 969912041UL, 2556570543UL, 162987300UL, 1960844609UL, 61311938UL, 427583517UL, 315868734UL, 2542622968UL, 3949539136UL, 2278526422UL, 92839917UL, 1235059630UL, 1533374854UL, 847792023UL, 1361054176UL, 1147875681UL, 164541100UL, 1010135841UL, 143302319UL, 1348709332UL, 368616909UL, 20896020UL, 344974153UL, 2576803233UL, 3290873783UL, 1078575783UL, 2680612471UL, 1276425436UL, 2400671554UL, 628790408UL, +4149623645UL, 2109177634UL, 998215324UL, 3127793500UL, 2019336900UL, 3525419965UL, 2583746384UL, 2126302368UL, 3258602104UL, 2858154034UL, 1996113346UL, 3726060195UL, 157069329UL, 390662438UL, 2250549235UL, 982000497UL, 377281730UL, 3251789121UL, 236703173UL, 3487415996UL, 2303768414UL, 3394010206UL, 4232159202UL, 468321553UL, 2773608982UL, 681592492UL, 2978494251UL, 989230484UL, 3122841814UL, 3647638215UL, 4089094260UL, 541354422UL, +223117443UL, 2225009071UL, 2829509947UL, 2754981128UL, 3897048544UL, 3550177883UL, 2461273592UL, 282627696UL, 668143612UL, 1378024753UL, 3686775275UL, 4230752590UL, 1105868822UL, 3765910650UL, 729116355UL, 3886390916UL, 65029451UL, 328554604UL, 3419111947UL, 1172004841UL, 2525409243UL, 1677678908UL, 1395036942UL, 155635560UL, 1088384271UL, 689357059UL, 1754542213UL, 1076601715UL, 2712009967UL, 1960202673UL, 1009675673UL, 3742350158UL, +2581225953UL, 129749802UL, 9090161UL, 1854921599UL, 2655519695UL, 1393282220UL, 809557750UL, 1422536794UL, 4175512633UL, 141286453UL, 2211497169UL, 1739311360UL, 850391877UL, 3190829323UL, 2782782009UL, 2694871802UL, 1738527771UL, 837232655UL, 2274981421UL, 2935438833UL, 3145832503UL, 1858071296UL, 955772620UL, 134516308UL, 3576789728UL, 4045354759UL, 3367712327UL, 874117013UL, 3944221200UL, 950102624UL, 3562634568UL, 2420548306UL, +543679720UL, 1241913280UL, 1360146137UL, 3644280343UL, 176019367UL, 1169030022UL, 2226452641UL, 3172047212UL, 3927720006UL, 76544055UL, 3783543297UL, 2030783667UL, 2237381973UL, 1497233808UL, 3283985735UL, 1560162209UL, 1166820137UL, 3818389960UL, 2344066681UL, 346134252UL, 4258046618UL, 2502743884UL, 1963136977UL, 79988846UL, 3887005605UL, 1204846712UL, 1856291967UL, 4143674472UL, 3967952414UL, 366578749UL, 3889946075UL, 3303325234UL, +2589568800UL, 2193179011UL, 2917569085UL, 969912041UL, 2556570543UL, 162987300UL, 52882655UL, 61311938UL, 427583517UL, 315868734UL, 2542622968UL, 1575831590UL, 2278526422UL, 92839917UL, 1235059630UL, 1533374854UL, 2397068791UL, 1361054176UL, 1147875681UL, 164541100UL, 1010135841UL, 2586368032UL, 1348709332UL, 368616909UL, 20896020UL, 344974153UL, 3445652232UL, 3290873783UL, 1078575783UL, 2680612471UL, 1276425436UL, 3682156544UL, +628790408UL, 4149623645UL, 2109177634UL, 998215324UL, 4049708298UL, 2019336900UL, 3525419965UL, 2583746384UL, 2126302368UL, 1627944270UL, 2858154034UL, 1996113346UL, 3726060195UL, 157069329UL, 1481222640UL, 2250549235UL, 982000497UL, 377281730UL, 3251789121UL, 3564274539UL, 3487415996UL, 2303768414UL, 3394010206UL, 4232159202UL, 3509025997UL, 2773608982UL, 681592492UL, 2978494251UL, 989230484UL, 980252048UL, 3647638215UL, 4089094260UL, +541354422UL, 223117443UL, 543970497UL, 2829509947UL, 2754981128UL, 3897048544UL, 3550177883UL, 2736782140UL, 282627696UL, 668143612UL, 1378024753UL, 3686775275UL, 2728601425UL, 1105868822UL, 3765910650UL, 729116355UL, 3886390916UL, 1866378660UL, 328554604UL, 3419111947UL, 1172004841UL, 2525409243UL, 1506924008UL, 1395036942UL, 155635560UL, 1088384271UL, 689357059UL, 3587092123UL, 1076601715UL, 2712009967UL, 1960202673UL, 1009675673UL, +4292715891UL, 2465250857UL, 3267969665UL, 2459570573UL, 3644463083UL, 1637197500UL, 684559293UL, 3520611957UL, 2976084366UL, 1512112440UL, 1778285193UL, 1849742417UL, 3144801412UL, 3009052859UL, 820829188UL, 1382783871UL, 3373481539UL, 3777016406UL, 266942530UL, 1792334422UL, 4109859515UL, 1468149634UL, 1356457853UL, 623893785UL, 1301686542UL, 441704877UL, 3377795902UL, 879822753UL, 329462927UL, 543858304UL, 2221828617UL, 2996486613UL, +981774202UL, 1032220084UL, 1066536452UL, 1004068806UL, 1336694798UL, 3744375323UL, 3802436665UL, 3366526577UL, 418696462UL, 1776559103UL, 1291965608UL, 1623030339UL, 1443628607UL, 572114324UL, 899621592UL, 332121275UL, 3637616671UL, 457287722UL, 3803043476UL, 408472701UL, 660940326UL, 1209169008UL, 1202511620UL, 2906900959UL, 2600414642UL, 2015874468UL, 2931389161UL, 1760773669UL, 2601299639UL, 543821664UL, 3426280682UL, 1337602255UL, +3334593650UL, 1320885980UL, 3857269540UL, 2548321029UL, 2250001180UL, 673341051UL, 1900184720UL, 731675831UL, 2461790412UL, 2593291320UL, 1640301250UL, 863529987UL, 91627443UL, 2437824309UL, 2834231475UL, 4093270720UL, 1474594761UL, 4186662839UL, 1683556862UL, 1302286991UL, 806676270UL, 703274107UL, 3756759580UL, 674737904UL, 912015048UL, 1823306025UL, 1509430520UL, 3128952761UL, 290841833UL, 3917789380UL, 1022040580UL, 1810054038UL, +334998864UL, 1009274987UL, 310979037UL, 606749827UL, 546291081UL, 3438438313UL, 1840081424UL, 1950680845UL, 4217236364UL, 1814584903UL, 2814353208UL, 194196981UL, 1540331253UL, 3135937654UL, 773351497UL, 1878220007UL, 3097009802UL, 1252607159UL, 1378821846UL, 2741884614UL, 178612659UL, 3656860395UL, 1259606652UL, 3942111545UL, 488406826UL, 3640897405UL, 3419000480UL, 353909713UL, 2996208477UL, 2862593073UL, 108483327UL, 648472258UL, +1060249632UL, 1049865483UL, 430087518UL, 1364157854UL, 3367631180UL, 251313827UL, 2374149836UL, 2109357086UL, 479172068UL, 464775113UL, 1806677787UL, 3488082411UL, 356035738UL, 3080424395UL, 4134646749UL, 369528743UL, 1031004516UL, 2525336414UL, 4189798138UL, 3928909462UL, 568714397UL, 1681832820UL, 1753328641UL, 827357673UL, 1651960551UL, 1798317455UL, 737101952UL, 3257553606UL, 400882781UL, 1473208110UL, 4134183873UL, 2193420912UL, +}, +{ +2483976489UL, 2790651795UL, 3298324523UL, 3508205426UL, 2236819708UL, 917494217UL, 769620837UL, 3411018785UL, 2391335000UL, 1627061280UL, 3356773416UL, 1288706527UL, 4178910717UL, 3636299534UL, 4221874052UL, 3674654381UL, 537787012UL, 4271656840UL, 185820273UL, 1160533598UL, 1862365049UL, 2550353307UL, 1392072847UL, 1870891365UL, 1517453821UL, 524666025UL, 3645751565UL, 2415020247UL, 3691419894UL, 2580450642UL, 2130267479UL, 3636103610UL, +562446539UL, 750696587UL, 97137475UL, 3894066051UL, 2239638596UL, 3256181120UL, 3981041836UL, 774947039UL, 451287677UL, 3618957054UL, 4236303539UL, 1027744929UL, 1497195372UL, 498574915UL, 2164122779UL, 582902291UL, 3040883311UL, 1626221455UL, 1853378UL, 2125490000UL, 3185055972UL, 1607660025UL, 432884530UL, 779476209UL, 124284956UL, 2488937128UL, 2521389012UL, 107485781UL, 2873055013UL, 1171872946UL, 3130489952UL, 4273333914UL, +646240524UL, 3970896645UL, 942009076UL, 4069926418UL, 3129385884UL, 3470469370UL, 388702536UL, 450999415UL, 2995728716UL, 1687173264UL, 3049352827UL, 2648078738UL, 190663705UL, 486809970UL, 424002670UL, 2421764946UL, 2941043524UL, 3841512738UL, 119077561UL, 1801381572UL, 2208680167UL, 2502730219UL, 9899015UL, 2455199230UL, 3755314209UL, 3958460021UL, 3846398898UL, 1405136244UL, 2870563334UL, 821846618UL, 2790899812UL, 863647562UL, +629585032UL, 958925512UL, 1190540209UL, 57251233UL, 2109551995UL, 2294881622UL, 2603370255UL, 3839518646UL, 123838650UL, 3436270690UL, 1637121394UL, 3761101432UL, 954001192UL, 759760236UL, 3268295908UL, 2313083096UL, 630164216UL, 2367213191UL, 3992059381UL, 3292952769UL, 2040774258UL, 1420209005UL, 527547730UL, 1222399440UL, 1515078401UL, 2005580991UL, 645585788UL, 2256370254UL, 3057235502UL, 2870727428UL, 2785498804UL, 333440916UL, +1873686678UL, 2489794553UL, 3726728164UL, 3405629071UL, 3869328595UL, 3081963448UL, 2122133003UL, 1428788181UL, 4141962679UL, 41030733UL, 183716455UL, 36316501UL, 1430796327UL, 1884066707UL, 1216957106UL, 3455082673UL, 1092665987UL, 535070834UL, 3873372533UL, 175757671UL, 3414803303UL, 791028991UL, 3436610906UL, 2950895946UL, 977680845UL, 4224715886UL, 2809442211UL, 4044727083UL, 3035532020UL, 4253187882UL, 969203959UL, 2539482914UL, +813880136UL, 2483976489UL, 2790651795UL, 3298324523UL, 3508205426UL, 49280479UL, 917494217UL, 769620837UL, 3411018785UL, 2391335000UL, 3036738936UL, 3356773416UL, 1288706527UL, 4178910717UL, 3636299534UL, 2294957038UL, 3674654381UL, 537787012UL, 4271656840UL, 185820273UL, 2622722506UL, 1862365049UL, 2550353307UL, 1392072847UL, 1870891365UL, 2838104933UL, 524666025UL, 3645751565UL, 2415020247UL, 3691419894UL, 1295777418UL, 2130267479UL, +3636103610UL, 562446539UL, 750696587UL, 249830932UL, 3894066051UL, 2239638596UL, 3256181120UL, 3981041836UL, 3217398876UL, 451287677UL, 3618957054UL, 4236303539UL, 1027744929UL, 1724964245UL, 498574915UL, 2164122779UL, 582902291UL, 3040883311UL, 3101287841UL, 1853378UL, 2125490000UL, 3185055972UL, 1607660025UL, 1128474163UL, 779476209UL, 124284956UL, 2488937128UL, 2521389012UL, 338597864UL, 2873055013UL, 1171872946UL, 3130489952UL, +4273333914UL, 1557892392UL, 3970896645UL, 942009076UL, 4069926418UL, 3129385884UL, 2688433076UL, 388702536UL, 450999415UL, 2995728716UL, 1687173264UL, 157685189UL, 2648078738UL, 190663705UL, 486809970UL, 424002670UL, 979986388UL, 2941043524UL, 3841512738UL, 119077561UL, 1801381572UL, 2668625968UL, 2502730219UL, 9899015UL, 2455199230UL, 3755314209UL, 2699515741UL, 3846398898UL, 1405136244UL, 2870563334UL, 821846618UL, 505633792UL, +863647562UL, 629585032UL, 958925512UL, 1190540209UL, 2067402799UL, 2109551995UL, 2294881622UL, 2603370255UL, 3839518646UL, 2688067120UL, 3436270690UL, 1637121394UL, 3761101432UL, 954001192UL, 3206166733UL, 3268295908UL, 2313083096UL, 630164216UL, 2367213191UL, 3007494680UL, 3292952769UL, 2040774258UL, 1420209005UL, 527547730UL, 4047406592UL, 1515078401UL, 2005580991UL, 645585788UL, 2256370254UL, 13805572UL, 2870727428UL, 2785498804UL, +333440916UL, 1873686678UL, 1928222740UL, 3726728164UL, 3405629071UL, 3869328595UL, 3081963448UL, 2971423693UL, 1428788181UL, 4141962679UL, 41030733UL, 183716455UL, 4064095256UL, 1430796327UL, 1884066707UL, 1216957106UL, 3455082673UL, 985592757UL, 535070834UL, 3873372533UL, 175757671UL, 3414803303UL, 2159028553UL, 3436610906UL, 2950895946UL, 977680845UL, 4224715886UL, 345462057UL, 4044727083UL, 3035532020UL, 4253187882UL, 969203959UL, +984166534UL, 813880136UL, 2483976489UL, 2790651795UL, 3298324523UL, 1080001158UL, 49280479UL, 917494217UL, 769620837UL, 3411018785UL, 3216598401UL, 3036738936UL, 3356773416UL, 1288706527UL, 4178910717UL, 3311472057UL, 2294957038UL, 3674654381UL, 537787012UL, 4271656840UL, 220045511UL, 2622722506UL, 1862365049UL, 2550353307UL, 1392072847UL, 3057632678UL, 2838104933UL, 524666025UL, 3645751565UL, 2415020247UL, 252304106UL, 1295777418UL, +2130267479UL, 3636103610UL, 562446539UL, 80437039UL, 249830932UL, 3894066051UL, 2239638596UL, 3256181120UL, 117173223UL, 3217398876UL, 451287677UL, 3618957054UL, 4236303539UL, 1986849360UL, 1724964245UL, 498574915UL, 2164122779UL, 582902291UL, 288631030UL, 3101287841UL, 1853378UL, 2125490000UL, 3185055972UL, 824635664UL, 1128474163UL, 779476209UL, 124284956UL, 2488937128UL, 1231646648UL, 338597864UL, 2873055013UL, 1171872946UL, +3130489952UL, 708957725UL, 1557892392UL, 3970896645UL, 942009076UL, 4069926418UL, 2286522565UL, 2688433076UL, 388702536UL, 450999415UL, 2995728716UL, 2523361978UL, 157685189UL, 2648078738UL, 190663705UL, 486809970UL, 151444406UL, 979986388UL, 2941043524UL, 3841512738UL, 119077561UL, 3762447035UL, 2668625968UL, 2502730219UL, 9899015UL, 2455199230UL, 3532439568UL, 2699515741UL, 3846398898UL, 1405136244UL, 2870563334UL, 2242036665UL, +505633792UL, 863647562UL, 629585032UL, 958925512UL, 2618618630UL, 2067402799UL, 2109551995UL, 2294881622UL, 2603370255UL, 2461404010UL, 2688067120UL, 3436270690UL, 1637121394UL, 3761101432UL, 1076814097UL, 3206166733UL, 3268295908UL, 2313083096UL, 630164216UL, 12196305UL, 3007494680UL, 3292952769UL, 2040774258UL, 1420209005UL, 2609377752UL, 4047406592UL, 1515078401UL, 2005580991UL, 645585788UL, 865985176UL, 13805572UL, 2870727428UL, +2785498804UL, 333440916UL, 3735553268UL, 1928222740UL, 3726728164UL, 3405629071UL, 3869328595UL, 501640466UL, 2971423693UL, 1428788181UL, 4141962679UL, 41030733UL, 97561214UL, 4064095256UL, 1430796327UL, 1884066707UL, 1216957106UL, 3840122090UL, 985592757UL, 535070834UL, 3873372533UL, 175757671UL, 3856277268UL, 2159028553UL, 3436610906UL, 2950895946UL, 977680845UL, 3313441827UL, 345462057UL, 4044727083UL, 3035532020UL, 4253187882UL, +3468811573UL, 984166534UL, 813880136UL, 2483976489UL, 2790651795UL, 3733649754UL, 1080001158UL, 49280479UL, 917494217UL, 769620837UL, 3969566450UL, 3216598401UL, 3036738936UL, 3356773416UL, 1288706527UL, 2444128005UL, 3311472057UL, 2294957038UL, 3674654381UL, 537787012UL, 4166109669UL, 220045511UL, 2622722506UL, 1862365049UL, 2550353307UL, 2552992760UL, 3057632678UL, 2838104933UL, 524666025UL, 3645751565UL, 664164441UL, 252304106UL, +1295777418UL, 2130267479UL, 3636103610UL, 3227561061UL, 80437039UL, 249830932UL, 3894066051UL, 2239638596UL, 1071536668UL, 117173223UL, 3217398876UL, 451287677UL, 3618957054UL, 3066415327UL, 1986849360UL, 1724964245UL, 498574915UL, 2164122779UL, 3541914330UL, 288631030UL, 3101287841UL, 1853378UL, 2125490000UL, 2207189978UL, 824635664UL, 1128474163UL, 779476209UL, 124284956UL, 2117633906UL, 1231646648UL, 338597864UL, 2873055013UL, +1171872946UL, 891038594UL, 708957725UL, 1557892392UL, 3970896645UL, 942009076UL, 42952651UL, 2286522565UL, 2688433076UL, 388702536UL, 450999415UL, 2986730356UL, 2523361978UL, 157685189UL, 2648078738UL, 190663705UL, 3058267870UL, 151444406UL, 979986388UL, 2941043524UL, 3841512738UL, 1844101292UL, 3762447035UL, 2668625968UL, 2502730219UL, 9899015UL, 2599582093UL, 3532439568UL, 2699515741UL, 3846398898UL, 1405136244UL, 811001941UL, +2242036665UL, 505633792UL, 863647562UL, 629585032UL, 2722320710UL, 2618618630UL, 2067402799UL, 2109551995UL, 2294881622UL, 1820862072UL, 2461404010UL, 2688067120UL, 3436270690UL, 1637121394UL, 3642978005UL, 1076814097UL, 3206166733UL, 3268295908UL, 2313083096UL, 1900318020UL, 12196305UL, 3007494680UL, 3292952769UL, 2040774258UL, 520848705UL, 2609377752UL, 4047406592UL, 1515078401UL, 2005580991UL, 2530251392UL, 865985176UL, 13805572UL, +2870727428UL, 2785498804UL, 2878984912UL, 3735553268UL, 1928222740UL, 3726728164UL, 3405629071UL, 2717736455UL, 501640466UL, 2971423693UL, 1428788181UL, 4141962679UL, 3704214873UL, 97561214UL, 4064095256UL, 1430796327UL, 1884066707UL, 1721732760UL, 3840122090UL, 985592757UL, 535070834UL, 3873372533UL, 770732059UL, 3856277268UL, 2159028553UL, 3436610906UL, 2950895946UL, 33753949UL, 3313441827UL, 345462057UL, 4044727083UL, 3035532020UL, +4166506071UL, 2719759982UL, 1025532659UL, 3811323959UL, 713457907UL, 1577198020UL, 1719946821UL, 3963262337UL, 1719605451UL, 703663722UL, 1943886497UL, 2916371044UL, 1655862745UL, 109438187UL, 195575943UL, 2572727533UL, 2421761970UL, 1796539813UL, 2020762515UL, 1191344316UL, 2492085516UL, 2778033179UL, 4002316684UL, 1571080685UL, 1157340389UL, 3859584731UL, 3403766082UL, 2292873365UL, 2032258920UL, 1749575450UL, 848549431UL, 1893685820UL, +3510068298UL, 3308906564UL, 1193936308UL, 2561670234UL, 1043148718UL, 2611815896UL, 3832995202UL, 2436487998UL, 3377369330UL, 1174818128UL, 796514731UL, 1985886833UL, 88296218UL, 3032898657UL, 4101301361UL, 1486994584UL, 237792475UL, 1029399834UL, 1708840018UL, 2934039708UL, 1496674948UL, 4243234983UL, 3896751668UL, 1726119825UL, 2706068825UL, 1900013134UL, 2639641919UL, 1433377392UL, 2962655166UL, 1870954268UL, 3873603462UL, 1778084630UL, +2393311756UL, 4135022799UL, 3669603001UL, 811404758UL, 784379778UL, 4283689136UL, 405168660UL, 3873488622UL, 486946690UL, 347427153UL, 2139072474UL, 1143349522UL, 3780264455UL, 2938731842UL, 3864001470UL, 3497981827UL, 2703917008UL, 3222236962UL, 2604106616UL, 1281570367UL, 175937153UL, 433252852UL, 3232065906UL, 1111895932UL, 1027363895UL, 2435093744UL, 4232690481UL, 1940855209UL, 2844613991UL, 2095175619UL, 3479946852UL, 393314401UL, +3625733631UL, 1073779513UL, 2884072879UL, 4089630675UL, 3614205484UL, 1379809260UL, 3980251795UL, 3914556410UL, 3633356126UL, 3030204458UL, 1654727861UL, 3765074811UL, 959734060UL, 842315676UL, 353688341UL, 145655006UL, 1972100601UL, 1456042517UL, 3767579955UL, 4282066379UL, 498998655UL, 4123310742UL, 1801424182UL, 777808179UL, 655425670UL, 588715641UL, 2136252742UL, 1283378143UL, 639191135UL, 3132375783UL, 276649124UL, 2036776039UL, +3352396498UL, 3893441746UL, 3298373918UL, 1024178230UL, 2623051553UL, 1956117442UL, 2955394456UL, 2478945776UL, 3904945720UL, 769232312UL, 2168822980UL, 3715831945UL, 453874622UL, 3351529191UL, 3256151193UL, 808042625UL, 1700919462UL, 1008305347UL, 1518733915UL, 3194328753UL, 2228970756UL, 2604658038UL, 1376476152UL, 2147167203UL, 2585867511UL, 445717950UL, 3595016420UL, 3673970127UL, 3640614546UL, 494944945UL, 152508312UL, 4160926899UL, +}, +{ +3225674336UL, 827428943UL, 2858523441UL, 2447266124UL, 1539223637UL, 2299756421UL, 776912458UL, 279091824UL, 1152725492UL, 3903457284UL, 3987010398UL, 3996115574UL, 839506039UL, 3052513014UL, 28550291UL, 2597814974UL, 2328446377UL, 1961600298UL, 3695276714UL, 1334932648UL, 1141381380UL, 3025370440UL, 997698792UL, 931473445UL, 3091440507UL, 820119215UL, 3586778616UL, 1993126242UL, 4252838072UL, 3033829531UL, 2120026924UL, 65722921UL, +746724958UL, 461423533UL, 1582298542UL, 1564918930UL, 3710935369UL, 419349792UL, 3914061713UL, 2279209938UL, 770031171UL, 2062767935UL, 3373230309UL, 3582372364UL, 2025682996UL, 3352859025UL, 1262632952UL, 3140021482UL, 501370035UL, 2554730117UL, 352450195UL, 1002557127UL, 2813224858UL, 2808406559UL, 290476252UL, 4216846311UL, 1187381982UL, 3131323304UL, 1094330039UL, 2646234280UL, 655242013UL, 1152156402UL, 3658526705UL, 3565043535UL, +693375321UL, 2120064836UL, 3726555752UL, 97387177UL, 546586686UL, 1013492636UL, 3874404446UL, 440995849UL, 1929251266UL, 95137166UL, 564969023UL, 3559119399UL, 3855477390UL, 2439885481UL, 2492213232UL, 2611214170UL, 2054191666UL, 2778642234UL, 2267416277UL, 2194315209UL, 1360165075UL, 1018128176UL, 2841084399UL, 3028189871UL, 3631770575UL, 541021087UL, 1091467742UL, 2743780329UL, 3566538467UL, 1277066122UL, 279582475UL, 2712119598UL, +3296319359UL, 4187226385UL, 1468994750UL, 2946664285UL, 2284913307UL, 740953233UL, 3351500634UL, 1791054313UL, 3355533193UL, 610062694UL, 3089981426UL, 3469441840UL, 3225672476UL, 2223653903UL, 2593994385UL, 548784340UL, 549871569UL, 865468702UL, 1593939385UL, 645229999UL, 1412095765UL, 2814231763UL, 3619658094UL, 877462820UL, 2198765077UL, 1845119421UL, 4144145546UL, 1356681209UL, 848707034UL, 4144513299UL, 3231318896UL, 3382035479UL, +693621410UL, 2821661683UL, 4236142563UL, 680649431UL, 3290999942UL, 200856634UL, 617766412UL, 3194332974UL, 4102392657UL, 2776797278UL, 2932808060UL, 793967937UL, 2149374605UL, 3736514467UL, 3547689148UL, 3744888920UL, 98278184UL, 1497045279UL, 2945126332UL, 4285864315UL, 2791068812UL, 1939995011UL, 56752862UL, 864909862UL, 625377571UL, 2266362085UL, 1050287398UL, 925722519UL, 1008109592UL, 2819528345UL, 3573068613UL, 1915083884UL, +1536828870UL, 3225674336UL, 827428943UL, 2858523441UL, 2447266124UL, 2186287936UL, 2299756421UL, 776912458UL, 279091824UL, 1152725492UL, 1271286102UL, 3987010398UL, 3996115574UL, 839506039UL, 3052513014UL, 1036957208UL, 2597814974UL, 2328446377UL, 1961600298UL, 3695276714UL, 2395157917UL, 1141381380UL, 3025370440UL, 997698792UL, 931473445UL, 2727078785UL, 820119215UL, 3586778616UL, 1993126242UL, 4252838072UL, 1171102868UL, 2120026924UL, +65722921UL, 746724958UL, 461423533UL, 2335086228UL, 1564918930UL, 3710935369UL, 419349792UL, 3914061713UL, 1136716661UL, 770031171UL, 2062767935UL, 3373230309UL, 3582372364UL, 4100328450UL, 3352859025UL, 1262632952UL, 3140021482UL, 501370035UL, 2579000299UL, 352450195UL, 1002557127UL, 2813224858UL, 2808406559UL, 2642514897UL, 4216846311UL, 1187381982UL, 3131323304UL, 1094330039UL, 3092488663UL, 655242013UL, 1152156402UL, 3658526705UL, +3565043535UL, 3280658482UL, 2120064836UL, 3726555752UL, 97387177UL, 546586686UL, 584864345UL, 3874404446UL, 440995849UL, 1929251266UL, 95137166UL, 823950215UL, 3559119399UL, 3855477390UL, 2439885481UL, 2492213232UL, 2297040376UL, 2054191666UL, 2778642234UL, 2267416277UL, 2194315209UL, 573807317UL, 1018128176UL, 2841084399UL, 3028189871UL, 3631770575UL, 2747338726UL, 1091467742UL, 2743780329UL, 3566538467UL, 1277066122UL, 1715139924UL, +2712119598UL, 3296319359UL, 4187226385UL, 1468994750UL, 3361368810UL, 2284913307UL, 740953233UL, 3351500634UL, 1791054313UL, 4290564545UL, 610062694UL, 3089981426UL, 3469441840UL, 3225672476UL, 1010959310UL, 2593994385UL, 548784340UL, 549871569UL, 865468702UL, 1825306744UL, 645229999UL, 1412095765UL, 2814231763UL, 3619658094UL, 3792219969UL, 2198765077UL, 1845119421UL, 4144145546UL, 1356681209UL, 268197516UL, 4144513299UL, 3231318896UL, +3382035479UL, 693621410UL, 2786831464UL, 4236142563UL, 680649431UL, 3290999942UL, 200856634UL, 3822069622UL, 3194332974UL, 4102392657UL, 2776797278UL, 2932808060UL, 525501162UL, 2149374605UL, 3736514467UL, 3547689148UL, 3744888920UL, 3219948462UL, 1497045279UL, 2945126332UL, 4285864315UL, 2791068812UL, 2678467476UL, 56752862UL, 864909862UL, 625377571UL, 2266362085UL, 2258093843UL, 925722519UL, 1008109592UL, 2819528345UL, 3573068613UL, +2743241289UL, 1536828870UL, 3225674336UL, 827428943UL, 2858523441UL, 992128922UL, 2186287936UL, 2299756421UL, 776912458UL, 279091824UL, 2108721702UL, 1271286102UL, 3987010398UL, 3996115574UL, 839506039UL, 1315622698UL, 1036957208UL, 2597814974UL, 2328446377UL, 1961600298UL, 3098343478UL, 2395157917UL, 1141381380UL, 3025370440UL, 997698792UL, 1317753106UL, 2727078785UL, 820119215UL, 3586778616UL, 1993126242UL, 2295599934UL, 1171102868UL, +2120026924UL, 65722921UL, 746724958UL, 3999203443UL, 2335086228UL, 1564918930UL, 3710935369UL, 419349792UL, 1662083910UL, 1136716661UL, 770031171UL, 2062767935UL, 3373230309UL, 3271761171UL, 4100328450UL, 3352859025UL, 1262632952UL, 3140021482UL, 3981040854UL, 2579000299UL, 352450195UL, 1002557127UL, 2813224858UL, 1064251076UL, 2642514897UL, 4216846311UL, 1187381982UL, 3131323304UL, 2077640887UL, 3092488663UL, 655242013UL, 1152156402UL, +3658526705UL, 548941006UL, 3280658482UL, 2120064836UL, 3726555752UL, 97387177UL, 4112878213UL, 584864345UL, 3874404446UL, 440995849UL, 1929251266UL, 227230803UL, 823950215UL, 3559119399UL, 3855477390UL, 2439885481UL, 610498128UL, 2297040376UL, 2054191666UL, 2778642234UL, 2267416277UL, 518192832UL, 573807317UL, 1018128176UL, 2841084399UL, 3028189871UL, 2512871059UL, 2747338726UL, 1091467742UL, 2743780329UL, 3566538467UL, 386661563UL, +1715139924UL, 2712119598UL, 3296319359UL, 4187226385UL, 2508754324UL, 3361368810UL, 2284913307UL, 740953233UL, 3351500634UL, 1296305541UL, 4290564545UL, 610062694UL, 3089981426UL, 3469441840UL, 148510865UL, 1010959310UL, 2593994385UL, 548784340UL, 549871569UL, 124676809UL, 1825306744UL, 645229999UL, 1412095765UL, 2814231763UL, 2540745278UL, 3792219969UL, 2198765077UL, 1845119421UL, 4144145546UL, 3966655401UL, 268197516UL, 4144513299UL, +3231318896UL, 3382035479UL, 1674022032UL, 2786831464UL, 4236142563UL, 680649431UL, 3290999942UL, 4065303704UL, 3822069622UL, 3194332974UL, 4102392657UL, 2776797278UL, 3735376922UL, 525501162UL, 2149374605UL, 3736514467UL, 3547689148UL, 2064870756UL, 3219948462UL, 1497045279UL, 2945126332UL, 4285864315UL, 2389978045UL, 2678467476UL, 56752862UL, 864909862UL, 625377571UL, 2308006661UL, 2258093843UL, 925722519UL, 1008109592UL, 2819528345UL, +2927186231UL, 2743241289UL, 1536828870UL, 3225674336UL, 827428943UL, 1583633720UL, 992128922UL, 2186287936UL, 2299756421UL, 776912458UL, 298217241UL, 2108721702UL, 1271286102UL, 3987010398UL, 3996115574UL, 1041730366UL, 1315622698UL, 1036957208UL, 2597814974UL, 2328446377UL, 1386688725UL, 3098343478UL, 2395157917UL, 1141381380UL, 3025370440UL, 2292273773UL, 1317753106UL, 2727078785UL, 820119215UL, 3586778616UL, 206996196UL, 2295599934UL, +1171102868UL, 2120026924UL, 65722921UL, 3271158508UL, 3999203443UL, 2335086228UL, 1564918930UL, 3710935369UL, 3305544914UL, 1662083910UL, 1136716661UL, 770031171UL, 2062767935UL, 4244195826UL, 3271761171UL, 4100328450UL, 3352859025UL, 1262632952UL, 3581040310UL, 3981040854UL, 2579000299UL, 352450195UL, 1002557127UL, 1789606594UL, 1064251076UL, 2642514897UL, 4216846311UL, 1187381982UL, 1519386238UL, 2077640887UL, 3092488663UL, 655242013UL, +1152156402UL, 3732146227UL, 548941006UL, 3280658482UL, 2120064836UL, 3726555752UL, 2631398817UL, 4112878213UL, 584864345UL, 3874404446UL, 440995849UL, 3541162446UL, 227230803UL, 823950215UL, 3559119399UL, 3855477390UL, 560704260UL, 610498128UL, 2297040376UL, 2054191666UL, 2778642234UL, 1614756373UL, 518192832UL, 573807317UL, 1018128176UL, 2841084399UL, 927011949UL, 2512871059UL, 2747338726UL, 1091467742UL, 2743780329UL, 566198434UL, +386661563UL, 1715139924UL, 2712119598UL, 3296319359UL, 520529825UL, 2508754324UL, 3361368810UL, 2284913307UL, 740953233UL, 2414584088UL, 1296305541UL, 4290564545UL, 610062694UL, 3089981426UL, 120496553UL, 148510865UL, 1010959310UL, 2593994385UL, 548784340UL, 3206664898UL, 124676809UL, 1825306744UL, 645229999UL, 1412095765UL, 821445348UL, 2540745278UL, 3792219969UL, 2198765077UL, 1845119421UL, 3434574619UL, 3966655401UL, 268197516UL, +4144513299UL, 3231318896UL, 3856935910UL, 1674022032UL, 2786831464UL, 4236142563UL, 680649431UL, 3331403374UL, 4065303704UL, 3822069622UL, 3194332974UL, 4102392657UL, 2194924932UL, 3735376922UL, 525501162UL, 2149374605UL, 3736514467UL, 2041458481UL, 2064870756UL, 3219948462UL, 1497045279UL, 2945126332UL, 3515890044UL, 2389978045UL, 2678467476UL, 56752862UL, 864909862UL, 1009125580UL, 2308006661UL, 2258093843UL, 925722519UL, 1008109592UL, +4166824654UL, 3399481064UL, 3848337172UL, 841675162UL, 2388734555UL, 3373081217UL, 1627287001UL, 1958651480UL, 1771323855UL, 2126620758UL, 3879967947UL, 1885140905UL, 806066092UL, 2168342987UL, 3778265278UL, 943582962UL, 3895768303UL, 337928214UL, 3677576461UL, 1884088203UL, 2629440785UL, 2357038005UL, 2362450760UL, 2080907681UL, 2644383608UL, 4153875040UL, 794977307UL, 2675637463UL, 2655426076UL, 3481699657UL, 2262369403UL, 1038608931UL, +4210267953UL, 2376694315UL, 2661705117UL, 3994997027UL, 2994346963UL, 4074343171UL, 833108024UL, 3562046155UL, 1113632369UL, 3087093963UL, 2115712884UL, 2778607581UL, 2702162487UL, 1347693590UL, 4271098334UL, 2746712394UL, 1629623802UL, 1932973152UL, 3077074108UL, 1338011180UL, 848785806UL, 1834095770UL, 4017238UL, 2661097500UL, 2935787683UL, 1214195119UL, 3099491937UL, 3868451396UL, 1063740008UL, 2768962809UL, 2554721244UL, 695479209UL, +2634119800UL, 1379839034UL, 2653377927UL, 921934002UL, 3586936843UL, 3035369677UL, 769283110UL, 2417935220UL, 3330084607UL, 2020519519UL, 2546176786UL, 1523223165UL, 3654065096UL, 1835059231UL, 2776263618UL, 3837173427UL, 3236141295UL, 1184415634UL, 157448610UL, 2474336972UL, 3313035876UL, 309195150UL, 2288837115UL, 548743307UL, 528342914UL, 1527562212UL, 554918643UL, 2739291918UL, 2630873849UL, 155419923UL, 226845272UL, 1343735931UL, +3106346884UL, 4177975386UL, 2515480406UL, 2049734808UL, 2802879609UL, 1805234272UL, 317920918UL, 745796250UL, 3816657414UL, 4198378080UL, 3057334192UL, 503016924UL, 2027816790UL, 579332504UL, 3037999504UL, 2857298788UL, 911046668UL, 1170775701UL, 2369720UL, 3364839261UL, 1462383461UL, 181600856UL, 1315241696UL, 2861043792UL, 3549404088UL, 3974245218UL, 4141518566UL, 1195336199UL, 2291064152UL, 3287203016UL, 3867432937UL, 2593766219UL, +2114273192UL, 3716228986UL, 410286941UL, 2497285113UL, 1338500439UL, 3748757692UL, 2315519304UL, 545570554UL, 1519868916UL, 679216320UL, 3264840479UL, 4083041163UL, 261878334UL, 2370312122UL, 1408058272UL, 1287635274UL, 3433241543UL, 3923613754UL, 2423502603UL, 3948993135UL, 1418484161UL, 230113502UL, 1766447938UL, 3101286974UL, 917358979UL, 2836128279UL, 2859079881UL, 3162688352UL, 2158281644UL, 154509481UL, 2409785274UL, 3096379437UL, +}, +{ +2456954827UL, 2895978734UL, 1621803157UL, 230462381UL, 4046364119UL, 716597790UL, 2031510641UL, 2208319977UL, 1107910846UL, 3379950723UL, 3628284249UL, 1393263274UL, 3842378742UL, 768116962UL, 1782906996UL, 3022943801UL, 510040722UL, 2180373447UL, 1294989632UL, 1659724107UL, 953774117UL, 500296619UL, 2269873184UL, 3215368465UL, 3933601613UL, 2401810535UL, 3568992417UL, 617528376UL, 2437412983UL, 2921242388UL, 2311040363UL, 3695847323UL, +1609309841UL, 3222455492UL, 1108155620UL, 397599239UL, 3344183623UL, 1159383441UL, 81554651UL, 4223302962UL, 2812031899UL, 2613176831UL, 2967803832UL, 3560382993UL, 670173062UL, 2361031672UL, 1745444335UL, 2067906079UL, 3019908371UL, 2662226130UL, 2962440272UL, 3053411095UL, 92212044UL, 1041941495UL, 4116546365UL, 2094375399UL, 3992554702UL, 216246182UL, 2271736480UL, 1006434362UL, 4104644208UL, 2543874803UL, 1310440964UL, 1956002873UL, +1485192936UL, 3027546418UL, 448786402UL, 749040342UL, 406538664UL, 2522826782UL, 3681979470UL, 3941253886UL, 672615054UL, 3655479714UL, 392178376UL, 1619518340UL, 1639889010UL, 666186812UL, 4094569743UL, 2947917117UL, 3308938954UL, 1572886498UL, 1065510431UL, 2158389109UL, 1583642689UL, 1763046973UL, 3578310229UL, 4106948216UL, 58659757UL, 691952777UL, 3394715763UL, 3333944006UL, 3020203798UL, 3598064251UL, 3151881711UL, 2071056894UL, +1263790655UL, 4188233031UL, 4230429856UL, 3088041549UL, 3031631424UL, 3912597408UL, 1768734847UL, 1975027092UL, 3976493733UL, 2376551740UL, 1137628506UL, 535767974UL, 3105256806UL, 15427398UL, 2472341690UL, 685997424UL, 1374644561UL, 2446214061UL, 2844847931UL, 1058649390UL, 1581230869UL, 1725846082UL, 3062699842UL, 1116400547UL, 1095426642UL, 2940190462UL, 4276038488UL, 2091764667UL, 4074059985UL, 98163536UL, 4157153745UL, 32476821UL, +2354284775UL, 752663757UL, 2987293678UL, 1119786914UL, 3019442904UL, 111185876UL, 3569592548UL, 3991775183UL, 3161418733UL, 3973354577UL, 1650454973UL, 426129509UL, 3659038742UL, 1387393667UL, 543731583UL, 781586523UL, 917315276UL, 832142534UL, 3911092159UL, 325250500UL, 2735441676UL, 163564958UL, 1002098855UL, 337936437UL, 1869530240UL, 2233969733UL, 4108076124UL, 3255026725UL, 4072134049UL, 2083771067UL, 1559589006UL, 1845121907UL, +466036013UL, 2456954827UL, 2895978734UL, 1621803157UL, 230462381UL, 2022150409UL, 716597790UL, 2031510641UL, 2208319977UL, 1107910846UL, 1838834877UL, 3628284249UL, 1393263274UL, 3842378742UL, 768116962UL, 2303040715UL, 3022943801UL, 510040722UL, 2180373447UL, 1294989632UL, 3074858415UL, 953774117UL, 500296619UL, 2269873184UL, 3215368465UL, 3531413908UL, 2401810535UL, 3568992417UL, 617528376UL, 2437412983UL, 1730632320UL, 2311040363UL, +3695847323UL, 1609309841UL, 3222455492UL, 3189359980UL, 397599239UL, 3344183623UL, 1159383441UL, 81554651UL, 1933731121UL, 2812031899UL, 2613176831UL, 2967803832UL, 3560382993UL, 758113139UL, 2361031672UL, 1745444335UL, 2067906079UL, 3019908371UL, 3537991495UL, 2962440272UL, 3053411095UL, 92212044UL, 1041941495UL, 2653519981UL, 2094375399UL, 3992554702UL, 216246182UL, 2271736480UL, 695350220UL, 4104644208UL, 2543874803UL, 1310440964UL, +1956002873UL, 3373048130UL, 3027546418UL, 448786402UL, 749040342UL, 406538664UL, 4081844472UL, 3681979470UL, 3941253886UL, 672615054UL, 3655479714UL, 197563239UL, 1619518340UL, 1639889010UL, 666186812UL, 4094569743UL, 2518320719UL, 3308938954UL, 1572886498UL, 1065510431UL, 2158389109UL, 3320483696UL, 1763046973UL, 3578310229UL, 4106948216UL, 58659757UL, 3412172826UL, 3394715763UL, 3333944006UL, 3020203798UL, 3598064251UL, 1693717788UL, +2071056894UL, 1263790655UL, 4188233031UL, 4230429856UL, 2564478937UL, 3031631424UL, 3912597408UL, 1768734847UL, 1975027092UL, 3546175061UL, 2376551740UL, 1137628506UL, 535767974UL, 3105256806UL, 450760279UL, 2472341690UL, 685997424UL, 1374644561UL, 2446214061UL, 1873063065UL, 1058649390UL, 1581230869UL, 1725846082UL, 3062699842UL, 813496775UL, 1095426642UL, 2940190462UL, 4276038488UL, 2091764667UL, 3857233976UL, 98163536UL, 4157153745UL, +32476821UL, 2354284775UL, 3115605568UL, 2987293678UL, 1119786914UL, 3019442904UL, 111185876UL, 996447434UL, 3991775183UL, 3161418733UL, 3973354577UL, 1650454973UL, 1089784804UL, 3659038742UL, 1387393667UL, 543731583UL, 781586523UL, 2711412312UL, 832142534UL, 3911092159UL, 325250500UL, 2735441676UL, 3563501139UL, 1002098855UL, 337936437UL, 1869530240UL, 2233969733UL, 1156926454UL, 3255026725UL, 4072134049UL, 2083771067UL, 1559589006UL, +3832870112UL, 466036013UL, 2456954827UL, 2895978734UL, 1621803157UL, 2340808859UL, 2022150409UL, 716597790UL, 2031510641UL, 2208319977UL, 1823993818UL, 1838834877UL, 3628284249UL, 1393263274UL, 3842378742UL, 2489609764UL, 2303040715UL, 3022943801UL, 510040722UL, 2180373447UL, 4204167795UL, 3074858415UL, 953774117UL, 500296619UL, 2269873184UL, 2320314628UL, 3531413908UL, 2401810535UL, 3568992417UL, 617528376UL, 712451843UL, 1730632320UL, +2311040363UL, 3695847323UL, 1609309841UL, 3224192365UL, 3189359980UL, 397599239UL, 3344183623UL, 1159383441UL, 758272390UL, 1933731121UL, 2812031899UL, 2613176831UL, 2967803832UL, 3986798661UL, 758113139UL, 2361031672UL, 1745444335UL, 2067906079UL, 3814344052UL, 3537991495UL, 2962440272UL, 3053411095UL, 92212044UL, 817573506UL, 2653519981UL, 2094375399UL, 3992554702UL, 216246182UL, 2456924809UL, 695350220UL, 4104644208UL, 2543874803UL, +1310440964UL, 1151286621UL, 3373048130UL, 3027546418UL, 448786402UL, 749040342UL, 637572176UL, 4081844472UL, 3681979470UL, 3941253886UL, 672615054UL, 3038758846UL, 197563239UL, 1619518340UL, 1639889010UL, 666186812UL, 4254608071UL, 2518320719UL, 3308938954UL, 1572886498UL, 1065510431UL, 3100620860UL, 3320483696UL, 1763046973UL, 3578310229UL, 4106948216UL, 403923766UL, 3412172826UL, 3394715763UL, 3333944006UL, 3020203798UL, 1859724785UL, +1693717788UL, 2071056894UL, 1263790655UL, 4188233031UL, 2908736862UL, 2564478937UL, 3031631424UL, 3912597408UL, 1768734847UL, 966714666UL, 3546175061UL, 2376551740UL, 1137628506UL, 535767974UL, 1561255376UL, 450760279UL, 2472341690UL, 685997424UL, 1374644561UL, 3122124160UL, 1873063065UL, 1058649390UL, 1581230869UL, 1725846082UL, 3791666219UL, 813496775UL, 1095426642UL, 2940190462UL, 4276038488UL, 2802023399UL, 3857233976UL, 98163536UL, +4157153745UL, 32476821UL, 1640659450UL, 3115605568UL, 2987293678UL, 1119786914UL, 3019442904UL, 4278091706UL, 996447434UL, 3991775183UL, 3161418733UL, 3973354577UL, 3398421232UL, 1089784804UL, 3659038742UL, 1387393667UL, 543731583UL, 1694361696UL, 2711412312UL, 832142534UL, 3911092159UL, 325250500UL, 166035542UL, 3563501139UL, 1002098855UL, 337936437UL, 1869530240UL, 1306446339UL, 1156926454UL, 3255026725UL, 4072134049UL, 2083771067UL, +61899937UL, 3832870112UL, 466036013UL, 2456954827UL, 2895978734UL, 767569205UL, 2340808859UL, 2022150409UL, 716597790UL, 2031510641UL, 1690074863UL, 1823993818UL, 1838834877UL, 3628284249UL, 1393263274UL, 546011580UL, 2489609764UL, 2303040715UL, 3022943801UL, 510040722UL, 825252468UL, 4204167795UL, 3074858415UL, 953774117UL, 500296619UL, 1952242515UL, 2320314628UL, 3531413908UL, 2401810535UL, 3568992417UL, 4254767597UL, 712451843UL, +1730632320UL, 2311040363UL, 3695847323UL, 2393864919UL, 3224192365UL, 3189359980UL, 397599239UL, 3344183623UL, 1759399025UL, 758272390UL, 1933731121UL, 2812031899UL, 2613176831UL, 2809078783UL, 3986798661UL, 758113139UL, 2361031672UL, 1745444335UL, 1223235915UL, 3814344052UL, 3537991495UL, 2962440272UL, 3053411095UL, 3711100000UL, 817573506UL, 2653519981UL, 2094375399UL, 3992554702UL, 2987412942UL, 2456924809UL, 695350220UL, 4104644208UL, +2543874803UL, 2746231792UL, 1151286621UL, 3373048130UL, 3027546418UL, 448786402UL, 801157439UL, 637572176UL, 4081844472UL, 3681979470UL, 3941253886UL, 975875511UL, 3038758846UL, 197563239UL, 1619518340UL, 1639889010UL, 3137491209UL, 4254608071UL, 2518320719UL, 3308938954UL, 1572886498UL, 631178204UL, 3100620860UL, 3320483696UL, 1763046973UL, 3578310229UL, 3338308117UL, 403923766UL, 3412172826UL, 3394715763UL, 3333944006UL, 37220448UL, +1859724785UL, 1693717788UL, 2071056894UL, 1263790655UL, 228419012UL, 2908736862UL, 2564478937UL, 3031631424UL, 3912597408UL, 3862306448UL, 966714666UL, 3546175061UL, 2376551740UL, 1137628506UL, 1114919961UL, 1561255376UL, 450760279UL, 2472341690UL, 685997424UL, 2456661198UL, 3122124160UL, 1873063065UL, 1058649390UL, 1581230869UL, 2996925693UL, 3791666219UL, 813496775UL, 1095426642UL, 2940190462UL, 1642720015UL, 2802023399UL, 3857233976UL, +98163536UL, 4157153745UL, 1578965959UL, 1640659450UL, 3115605568UL, 2987293678UL, 1119786914UL, 1748408698UL, 4278091706UL, 996447434UL, 3991775183UL, 3161418733UL, 4123935663UL, 3398421232UL, 1089784804UL, 3659038742UL, 1387393667UL, 770706529UL, 1694361696UL, 2711412312UL, 832142534UL, 3911092159UL, 335435644UL, 166035542UL, 3563501139UL, 1002098855UL, 337936437UL, 2961857543UL, 1306446339UL, 1156926454UL, 3255026725UL, 4072134049UL, +1717290230UL, 1323146393UL, 2156340433UL, 2065716367UL, 2597996276UL, 3402032152UL, 779574284UL, 2369501052UL, 2316224856UL, 2720986136UL, 3016786025UL, 2916554213UL, 3476215746UL, 1132150235UL, 2619889920UL, 1279664685UL, 679206534UL, 4014394509UL, 3624968312UL, 1480455625UL, 725015758UL, 707677352UL, 3764409715UL, 1938306480UL, 2171474419UL, 3379664161UL, 684262379UL, 2142433069UL, 43407198UL, 1398850259UL, 2059135843UL, 240266749UL, +3788738212UL, 118513026UL, 820245055UL, 1152812311UL, 1398373423UL, 3188977726UL, 872620936UL, 2084649448UL, 807979538UL, 819501992UL, 615447916UL, 3393148006UL, 1765623964UL, 2514767257UL, 3711360450UL, 2941886951UL, 3739102698UL, 4022385962UL, 2306039667UL, 3321267290UL, 2179238310UL, 3192652502UL, 2118792870UL, 2571142127UL, 761776508UL, 873010906UL, 1609627751UL, 4260021041UL, 1747852747UL, 960771906UL, 2647903291UL, 77475681UL, +1282566533UL, 4022186916UL, 2681128032UL, 1554542462UL, 3181701944UL, 1168469070UL, 74236514UL, 2806532232UL, 3981048887UL, 1888842784UL, 2888607878UL, 1763028723UL, 701886756UL, 4124077776UL, 3738147505UL, 4066663138UL, 3816449863UL, 921061872UL, 2956972182UL, 3159072916UL, 3337110888UL, 3552795700UL, 2281281091UL, 671098116UL, 1282750020UL, 1008618197UL, 2363767765UL, 1812013295UL, 1854965999UL, 131027176UL, 666394000UL, 2062217824UL, +1763334218UL, 551118598UL, 1277961175UL, 3523893635UL, 1855881150UL, 2067903393UL, 2590963277UL, 3214508854UL, 1604911832UL, 1906690475UL, 389417851UL, 2711591984UL, 427723436UL, 1039703630UL, 639602991UL, 444779318UL, 2722002973UL, 3927985419UL, 1297446054UL, 298277450UL, 656022205UL, 134304205UL, 3847728042UL, 3339100423UL, 407022043UL, 1282443442UL, 3173884578UL, 1417906094UL, 2364502739UL, 2158353472UL, 2402775649UL, 1807696073UL, +2837535198UL, 705887737UL, 2129202688UL, 3853676283UL, 1388329793UL, 875153687UL, 2367465660UL, 2763058233UL, 2500632304UL, 2196920062UL, 491306883UL, 277753357UL, 3868415380UL, 324867643UL, 3654474955UL, 2569410351UL, 1128175417UL, 1853572398UL, 1133201743UL, 662085935UL, 2263514999UL, 3077768113UL, 3309730620UL, 3602394176UL, 3747458070UL, 188422725UL, 813812450UL, 1502276531UL, 3909138356UL, 2766044599UL, 3760928321UL, 573108836UL, +}, +{ +1240264181UL, 1624064648UL, 3039823158UL, 2013985253UL, 1473300299UL, 2762062141UL, 3273470484UL, 1889745445UL, 2516996174UL, 3190376531UL, 996186898UL, 3893981177UL, 1268272590UL, 3226095713UL, 153038465UL, 2184871198UL, 3224094011UL, 2526518401UL, 1738960059UL, 1187560605UL, 4194384320UL, 2837011297UL, 3638232350UL, 367907454UL, 574009898UL, 1948901330UL, 60430044UL, 1569835584UL, 3160561697UL, 321792583UL, 3179087993UL, 1936928378UL, +412346905UL, 4020812489UL, 2603392174UL, 3499496781UL, 1499441233UL, 1062415256UL, 1347130973UL, 1823246794UL, 3411391800UL, 4253618056UL, 1507733072UL, 1605629518UL, 1503312494UL, 8035741UL, 4038904206UL, 2408545792UL, 969543501UL, 954847087UL, 956553276UL, 3096241999UL, 2566194741UL, 84678421UL, 3882676079UL, 2483934330UL, 3673546814UL, 2461422466UL, 620385599UL, 898325340UL, 2145883445UL, 3653728520UL, 3744850294UL, 2441124935UL, +904854507UL, 3216304963UL, 2373268568UL, 2354362010UL, 1245572787UL, 2894748714UL, 2889136188UL, 3716879184UL, 1766013949UL, 1305712667UL, 1227530310UL, 4051221847UL, 925440190UL, 1508686692UL, 1104647879UL, 1496666754UL, 3300504219UL, 127787091UL, 1528394637UL, 1739640835UL, 2475711496UL, 3792639955UL, 1450796299UL, 1634217367UL, 3289785095UL, 2149949989UL, 811612039UL, 1750779366UL, 1157474938UL, 514004414UL, 2264909096UL, 3730411668UL, +3308882513UL, 1834571716UL, 378288317UL, 3800023701UL, 763396788UL, 1597708317UL, 983953861UL, 94566098UL, 1548157668UL, 3755427117UL, 1646496505UL, 3748241449UL, 3439805936UL, 2321644449UL, 3805706235UL, 4220083901UL, 1069923823UL, 2984004391UL, 3824885361UL, 1967477766UL, 218978249UL, 348955028UL, 3188651823UL, 1008338679UL, 2331688720UL, 1562995454UL, 1837179689UL, 3033872688UL, 3007293665UL, 1759522678UL, 319754369UL, 2763991927UL, +1983149629UL, 1353197132UL, 1489552694UL, 2990539062UL, 3244609108UL, 669775440UL, 886127995UL, 1636688014UL, 1251222487UL, 2351883247UL, 3261502906UL, 3139614137UL, 3203790139UL, 2777648095UL, 3693390579UL, 3540514982UL, 3200191735UL, 750726325UL, 1014534145UL, 2091792357UL, 3931704474UL, 1383925867UL, 2038878506UL, 2247134268UL, 2840132188UL, 61137652UL, 1162051299UL, 399657268UL, 1682018695UL, 2640231287UL, 1733438115UL, 3611823506UL, +2077891037UL, 1240264181UL, 1624064648UL, 3039823158UL, 2013985253UL, 4188888201UL, 2762062141UL, 3273470484UL, 1889745445UL, 2516996174UL, 2621448256UL, 996186898UL, 3893981177UL, 1268272590UL, 3226095713UL, 952803645UL, 2184871198UL, 3224094011UL, 2526518401UL, 1738960059UL, 738368399UL, 4194384320UL, 2837011297UL, 3638232350UL, 367907454UL, 3772812520UL, 1948901330UL, 60430044UL, 1569835584UL, 3160561697UL, 1655622513UL, 3179087993UL, +1936928378UL, 412346905UL, 4020812489UL, 3754224996UL, 3499496781UL, 1499441233UL, 1062415256UL, 1347130973UL, 1167581269UL, 3411391800UL, 4253618056UL, 1507733072UL, 1605629518UL, 1867781671UL, 8035741UL, 4038904206UL, 2408545792UL, 969543501UL, 3189323143UL, 956553276UL, 3096241999UL, 2566194741UL, 84678421UL, 996778900UL, 2483934330UL, 3673546814UL, 2461422466UL, 620385599UL, 3129088144UL, 2145883445UL, 3653728520UL, 3744850294UL, +2441124935UL, 4230756652UL, 3216304963UL, 2373268568UL, 2354362010UL, 1245572787UL, 1600525238UL, 2889136188UL, 3716879184UL, 1766013949UL, 1305712667UL, 59908073UL, 4051221847UL, 925440190UL, 1508686692UL, 1104647879UL, 2931214731UL, 3300504219UL, 127787091UL, 1528394637UL, 1739640835UL, 62963469UL, 3792639955UL, 1450796299UL, 1634217367UL, 3289785095UL, 667987389UL, 811612039UL, 1750779366UL, 1157474938UL, 514004414UL, 2737193098UL, +3730411668UL, 3308882513UL, 1834571716UL, 378288317UL, 3452657469UL, 763396788UL, 1597708317UL, 983953861UL, 94566098UL, 2752347916UL, 3755427117UL, 1646496505UL, 3748241449UL, 3439805936UL, 4222757079UL, 3805706235UL, 4220083901UL, 1069923823UL, 2984004391UL, 3887639520UL, 1967477766UL, 218978249UL, 348955028UL, 3188651823UL, 4168456281UL, 2331688720UL, 1562995454UL, 1837179689UL, 3033872688UL, 814903833UL, 1759522678UL, 319754369UL, +2763991927UL, 1983149629UL, 3818528075UL, 1489552694UL, 2990539062UL, 3244609108UL, 669775440UL, 1004789460UL, 1636688014UL, 1251222487UL, 2351883247UL, 3261502906UL, 4143823654UL, 3203790139UL, 2777648095UL, 3693390579UL, 3540514982UL, 153421222UL, 750726325UL, 1014534145UL, 2091792357UL, 3931704474UL, 4018591985UL, 2038878506UL, 2247134268UL, 2840132188UL, 61137652UL, 1455028838UL, 399657268UL, 1682018695UL, 2640231287UL, 1733438115UL, +1853142849UL, 2077891037UL, 1240264181UL, 1624064648UL, 3039823158UL, 2235369076UL, 4188888201UL, 2762062141UL, 3273470484UL, 1889745445UL, 3627876603UL, 2621448256UL, 996186898UL, 3893981177UL, 1268272590UL, 2687846008UL, 952803645UL, 2184871198UL, 3224094011UL, 2526518401UL, 861379413UL, 738368399UL, 4194384320UL, 2837011297UL, 3638232350UL, 3753321702UL, 3772812520UL, 1948901330UL, 60430044UL, 1569835584UL, 581506474UL, 1655622513UL, +3179087993UL, 1936928378UL, 412346905UL, 2710043900UL, 3754224996UL, 3499496781UL, 1499441233UL, 1062415256UL, 2704745463UL, 1167581269UL, 3411391800UL, 4253618056UL, 1507733072UL, 4215403465UL, 1867781671UL, 8035741UL, 4038904206UL, 2408545792UL, 3252742933UL, 3189323143UL, 956553276UL, 3096241999UL, 2566194741UL, 1865159158UL, 996778900UL, 2483934330UL, 3673546814UL, 2461422466UL, 3123557619UL, 3129088144UL, 2145883445UL, 3653728520UL, +3744850294UL, 21840044UL, 4230756652UL, 3216304963UL, 2373268568UL, 2354362010UL, 1934462999UL, 1600525238UL, 2889136188UL, 3716879184UL, 1766013949UL, 2822794708UL, 59908073UL, 4051221847UL, 925440190UL, 1508686692UL, 2938291976UL, 2931214731UL, 3300504219UL, 127787091UL, 1528394637UL, 1914923136UL, 62963469UL, 3792639955UL, 1450796299UL, 1634217367UL, 257322213UL, 667987389UL, 811612039UL, 1750779366UL, 1157474938UL, 3083649350UL, +2737193098UL, 3730411668UL, 3308882513UL, 1834571716UL, 2778729422UL, 3452657469UL, 763396788UL, 1597708317UL, 983953861UL, 1337754195UL, 2752347916UL, 3755427117UL, 1646496505UL, 3748241449UL, 3942745717UL, 4222757079UL, 3805706235UL, 4220083901UL, 1069923823UL, 1314928500UL, 3887639520UL, 1967477766UL, 218978249UL, 348955028UL, 3425797638UL, 4168456281UL, 2331688720UL, 1562995454UL, 1837179689UL, 1814071277UL, 814903833UL, 1759522678UL, +319754369UL, 2763991927UL, 1079270448UL, 3818528075UL, 1489552694UL, 2990539062UL, 3244609108UL, 2944573315UL, 1004789460UL, 1636688014UL, 1251222487UL, 2351883247UL, 1356892540UL, 4143823654UL, 3203790139UL, 2777648095UL, 3693390579UL, 983917956UL, 153421222UL, 750726325UL, 1014534145UL, 2091792357UL, 296882400UL, 4018591985UL, 2038878506UL, 2247134268UL, 2840132188UL, 3508266160UL, 1455028838UL, 399657268UL, 1682018695UL, 2640231287UL, +2480988791UL, 1853142849UL, 2077891037UL, 1240264181UL, 1624064648UL, 1741738969UL, 2235369076UL, 4188888201UL, 2762062141UL, 3273470484UL, 3569498651UL, 3627876603UL, 2621448256UL, 996186898UL, 3893981177UL, 4026533880UL, 2687846008UL, 952803645UL, 2184871198UL, 3224094011UL, 1290870737UL, 861379413UL, 738368399UL, 4194384320UL, 2837011297UL, 3833099205UL, 3753321702UL, 3772812520UL, 1948901330UL, 60430044UL, 4131290878UL, 581506474UL, +1655622513UL, 3179087993UL, 1936928378UL, 2379952582UL, 2710043900UL, 3754224996UL, 3499496781UL, 1499441233UL, 593780490UL, 2704745463UL, 1167581269UL, 3411391800UL, 4253618056UL, 621889762UL, 4215403465UL, 1867781671UL, 8035741UL, 4038904206UL, 2045289976UL, 3252742933UL, 3189323143UL, 956553276UL, 3096241999UL, 2188329018UL, 1865159158UL, 996778900UL, 2483934330UL, 3673546814UL, 2717648418UL, 3123557619UL, 3129088144UL, 2145883445UL, +3653728520UL, 1528077261UL, 21840044UL, 4230756652UL, 3216304963UL, 2373268568UL, 803158556UL, 1934462999UL, 1600525238UL, 2889136188UL, 3716879184UL, 161827512UL, 2822794708UL, 59908073UL, 4051221847UL, 925440190UL, 3599942370UL, 2938291976UL, 2931214731UL, 3300504219UL, 127787091UL, 4082579845UL, 1914923136UL, 62963469UL, 3792639955UL, 1450796299UL, 2035446714UL, 257322213UL, 667987389UL, 811612039UL, 1750779366UL, 2344204796UL, +3083649350UL, 2737193098UL, 3730411668UL, 3308882513UL, 2765191583UL, 2778729422UL, 3452657469UL, 763396788UL, 1597708317UL, 1854746879UL, 1337754195UL, 2752347916UL, 3755427117UL, 1646496505UL, 4020292301UL, 3942745717UL, 4222757079UL, 3805706235UL, 4220083901UL, 1408262601UL, 1314928500UL, 3887639520UL, 1967477766UL, 218978249UL, 2173193841UL, 3425797638UL, 4168456281UL, 2331688720UL, 1562995454UL, 2835294077UL, 1814071277UL, 814903833UL, +1759522678UL, 319754369UL, 4048528178UL, 1079270448UL, 3818528075UL, 1489552694UL, 2990539062UL, 787253600UL, 2944573315UL, 1004789460UL, 1636688014UL, 1251222487UL, 3584515216UL, 1356892540UL, 4143823654UL, 3203790139UL, 2777648095UL, 1681621541UL, 983917956UL, 153421222UL, 750726325UL, 1014534145UL, 3951869055UL, 296882400UL, 4018591985UL, 2038878506UL, 2247134268UL, 1990726826UL, 3508266160UL, 1455028838UL, 399657268UL, 1682018695UL, +3360119279UL, 3151120565UL, 3011208718UL, 3694535943UL, 104562665UL, 2827623271UL, 249712003UL, 3413221355UL, 2347164236UL, 3227498378UL, 1805068659UL, 2118219686UL, 1568133029UL, 902801951UL, 175637375UL, 3812819970UL, 2162769758UL, 3845613089UL, 1795179477UL, 171494391UL, 3765826349UL, 1725798906UL, 345463508UL, 2481043227UL, 226569380UL, 3250095421UL, 1085199388UL, 3107594542UL, 4011388155UL, 1092611190UL, 3239339214UL, 4211849464UL, +4109911546UL, 81212018UL, 3691937144UL, 2477407396UL, 3320520455UL, 3070067913UL, 3808621884UL, 252917069UL, 3394860294UL, 1092442235UL, 2876536384UL, 1684120191UL, 431096075UL, 1701716708UL, 639881684UL, 3066183997UL, 3660504927UL, 2047274UL, 3424756424UL, 760932520UL, 2457976057UL, 1705265011UL, 2691137533UL, 3684307557UL, 3532744498UL, 2319162513UL, 1015534908UL, 1907173398UL, 2820698743UL, 1264455116UL, 2323788906UL, 3062240844UL, +1878550513UL, 1717353426UL, 1805673248UL, 62425157UL, 3662381032UL, 1964107209UL, 2559831960UL, 2117844804UL, 1228721677UL, 4240498866UL, 3212920337UL, 2338600301UL, 931588693UL, 2379606585UL, 3643222352UL, 4154645082UL, 1115847065UL, 2079427925UL, 2256943798UL, 2795103368UL, 2688136486UL, 1458062143UL, 1767222217UL, 635424385UL, 284062050UL, 1547163554UL, 3380046528UL, 1145758046UL, 3935976713UL, 4017430175UL, 3863367362UL, 3041367424UL, +303263160UL, 1465965696UL, 3757919837UL, 3083072836UL, 4024514094UL, 1381331179UL, 2393446325UL, 3256476469UL, 4066482738UL, 3437941107UL, 1051266504UL, 921764078UL, 2933305619UL, 1358097211UL, 4100978724UL, 2709958834UL, 574590507UL, 961767386UL, 21100886UL, 753746372UL, 4072632446UL, 733729367UL, 3060214669UL, 289165105UL, 426065754UL, 2036100240UL, 2172365757UL, 502856627UL, 84490194UL, 2630806596UL, 1206161269UL, 1009438449UL, +569581317UL, 1836947000UL, 3125379675UL, 1756936428UL, 3772694822UL, 3670337911UL, 3020603818UL, 2376224883UL, 2539951453UL, 2053395002UL, 3525193914UL, 1991480838UL, 3786481083UL, 873873707UL, 1693894743UL, 2450223985UL, 754878026UL, 1943356492UL, 401524329UL, 759931885UL, 611231307UL, 147950334UL, 599693701UL, 3358729722UL, 3649058074UL, 906423787UL, 1333804225UL, 875187278UL, 1115838692UL, 2476325972UL, 3307226674UL, 3539078918UL, +}, + +}; +#ifndef __CUDACC_RTC__ +CURAND_XORWOW_PRECALCULATED_HOST_QUALIFIERS unsigned int precalc_xorwow_offset_matrix_host[32][800] = { +{ +0UL, 0UL, 0UL, 0UL, 3UL, 0UL, 0UL, 0UL, 0UL, 6UL, 0UL, 0UL, 0UL, 0UL, 15UL, 0UL, 0UL, 0UL, 0UL, 30UL, 0UL, 0UL, 0UL, 0UL, 60UL, 0UL, 0UL, 0UL, 0UL, 120UL, 0UL, 0UL, +0UL, 0UL, 240UL, 0UL, 0UL, 0UL, 0UL, 480UL, 0UL, 0UL, 0UL, 0UL, 960UL, 0UL, 0UL, 0UL, 0UL, 1920UL, 0UL, 0UL, 0UL, 0UL, 3840UL, 0UL, 0UL, 0UL, 0UL, 7680UL, 0UL, 0UL, 0UL, 0UL, +15360UL, 0UL, 0UL, 0UL, 0UL, 30720UL, 0UL, 0UL, 0UL, 0UL, 61440UL, 0UL, 0UL, 0UL, 0UL, 122880UL, 0UL, 0UL, 0UL, 0UL, 245760UL, 0UL, 0UL, 0UL, 0UL, 491520UL, 0UL, 0UL, 0UL, 0UL, 983040UL, 0UL, +0UL, 0UL, 0UL, 1966080UL, 0UL, 0UL, 0UL, 0UL, 3932160UL, 0UL, 0UL, 0UL, 0UL, 7864320UL, 0UL, 0UL, 0UL, 0UL, 15728640UL, 0UL, 0UL, 0UL, 0UL, 31457280UL, 0UL, 0UL, 0UL, 0UL, 62914560UL, 0UL, 0UL, 0UL, +0UL, 125829120UL, 0UL, 0UL, 0UL, 0UL, 251658240UL, 0UL, 0UL, 0UL, 0UL, 503316480UL, 0UL, 0UL, 0UL, 0UL, 1006632960UL, 0UL, 0UL, 0UL, 0UL, 2013265920UL, 0UL, 0UL, 0UL, 0UL, 4026531840UL, 0UL, 0UL, 0UL, 0UL, 3758096384UL, +1UL, 0UL, 0UL, 0UL, 0UL, 2UL, 0UL, 0UL, 0UL, 0UL, 4UL, 0UL, 0UL, 0UL, 0UL, 8UL, 0UL, 0UL, 0UL, 0UL, 16UL, 0UL, 0UL, 0UL, 0UL, 32UL, 0UL, 0UL, 0UL, 0UL, 64UL, 0UL, +0UL, 0UL, 0UL, 128UL, 0UL, 0UL, 0UL, 0UL, 256UL, 0UL, 0UL, 0UL, 0UL, 512UL, 0UL, 0UL, 0UL, 0UL, 1024UL, 0UL, 0UL, 0UL, 0UL, 2048UL, 0UL, 0UL, 0UL, 0UL, 4096UL, 0UL, 0UL, 0UL, +0UL, 8192UL, 0UL, 0UL, 0UL, 0UL, 16384UL, 0UL, 0UL, 0UL, 0UL, 32768UL, 0UL, 0UL, 0UL, 0UL, 65536UL, 0UL, 0UL, 0UL, 0UL, 131072UL, 0UL, 0UL, 0UL, 0UL, 262144UL, 0UL, 0UL, 0UL, 0UL, 524288UL, +0UL, 0UL, 0UL, 0UL, 1048576UL, 0UL, 0UL, 0UL, 0UL, 2097152UL, 0UL, 0UL, 0UL, 0UL, 4194304UL, 0UL, 0UL, 0UL, 0UL, 8388608UL, 0UL, 0UL, 0UL, 0UL, 16777216UL, 0UL, 0UL, 0UL, 0UL, 33554432UL, 0UL, 0UL, +0UL, 0UL, 67108864UL, 0UL, 0UL, 0UL, 0UL, 134217728UL, 0UL, 0UL, 0UL, 0UL, 268435456UL, 0UL, 0UL, 0UL, 0UL, 536870912UL, 0UL, 0UL, 0UL, 0UL, 1073741824UL, 0UL, 0UL, 0UL, 0UL, 2147483648UL, 0UL, 0UL, 0UL, 0UL, +0UL, 1UL, 0UL, 0UL, 0UL, 0UL, 2UL, 0UL, 0UL, 0UL, 0UL, 4UL, 0UL, 0UL, 0UL, 0UL, 8UL, 0UL, 0UL, 0UL, 0UL, 16UL, 0UL, 0UL, 0UL, 0UL, 32UL, 0UL, 0UL, 0UL, 0UL, 64UL, +0UL, 0UL, 0UL, 0UL, 128UL, 0UL, 0UL, 0UL, 0UL, 256UL, 0UL, 0UL, 0UL, 0UL, 512UL, 0UL, 0UL, 0UL, 0UL, 1024UL, 0UL, 0UL, 0UL, 0UL, 2048UL, 0UL, 0UL, 0UL, 0UL, 4096UL, 0UL, 0UL, +0UL, 0UL, 8192UL, 0UL, 0UL, 0UL, 0UL, 16384UL, 0UL, 0UL, 0UL, 0UL, 32768UL, 0UL, 0UL, 0UL, 0UL, 65536UL, 0UL, 0UL, 0UL, 0UL, 131072UL, 0UL, 0UL, 0UL, 0UL, 262144UL, 0UL, 0UL, 0UL, 0UL, +524288UL, 0UL, 0UL, 0UL, 0UL, 1048576UL, 0UL, 0UL, 0UL, 0UL, 2097152UL, 0UL, 0UL, 0UL, 0UL, 4194304UL, 0UL, 0UL, 0UL, 0UL, 8388608UL, 0UL, 0UL, 0UL, 0UL, 16777216UL, 0UL, 0UL, 0UL, 0UL, 33554432UL, 0UL, +0UL, 0UL, 0UL, 67108864UL, 0UL, 0UL, 0UL, 0UL, 134217728UL, 0UL, 0UL, 0UL, 0UL, 268435456UL, 0UL, 0UL, 0UL, 0UL, 536870912UL, 0UL, 0UL, 0UL, 0UL, 1073741824UL, 0UL, 0UL, 0UL, 0UL, 2147483648UL, 0UL, 0UL, 0UL, +0UL, 0UL, 1UL, 0UL, 0UL, 0UL, 0UL, 2UL, 0UL, 0UL, 0UL, 0UL, 4UL, 0UL, 0UL, 0UL, 0UL, 8UL, 0UL, 0UL, 0UL, 0UL, 16UL, 0UL, 0UL, 0UL, 0UL, 32UL, 0UL, 0UL, 0UL, 0UL, +64UL, 0UL, 0UL, 0UL, 0UL, 128UL, 0UL, 0UL, 0UL, 0UL, 256UL, 0UL, 0UL, 0UL, 0UL, 512UL, 0UL, 0UL, 0UL, 0UL, 1024UL, 0UL, 0UL, 0UL, 0UL, 2048UL, 0UL, 0UL, 0UL, 0UL, 4096UL, 0UL, +0UL, 0UL, 0UL, 8192UL, 0UL, 0UL, 0UL, 0UL, 16384UL, 0UL, 0UL, 0UL, 0UL, 32768UL, 0UL, 0UL, 0UL, 0UL, 65536UL, 0UL, 0UL, 0UL, 0UL, 131072UL, 0UL, 0UL, 0UL, 0UL, 262144UL, 0UL, 0UL, 0UL, +0UL, 524288UL, 0UL, 0UL, 0UL, 0UL, 1048576UL, 0UL, 0UL, 0UL, 0UL, 2097152UL, 0UL, 0UL, 0UL, 0UL, 4194304UL, 0UL, 0UL, 0UL, 0UL, 8388608UL, 0UL, 0UL, 0UL, 0UL, 16777216UL, 0UL, 0UL, 0UL, 0UL, 33554432UL, +0UL, 0UL, 0UL, 0UL, 67108864UL, 0UL, 0UL, 0UL, 0UL, 134217728UL, 0UL, 0UL, 0UL, 0UL, 268435456UL, 0UL, 0UL, 0UL, 0UL, 536870912UL, 0UL, 0UL, 0UL, 0UL, 1073741824UL, 0UL, 0UL, 0UL, 0UL, 2147483648UL, 0UL, 0UL, +0UL, 0UL, 0UL, 1UL, 17UL, 0UL, 0UL, 0UL, 2UL, 34UL, 0UL, 0UL, 0UL, 4UL, 68UL, 0UL, 0UL, 0UL, 8UL, 136UL, 0UL, 0UL, 0UL, 16UL, 272UL, 0UL, 0UL, 0UL, 32UL, 544UL, 0UL, 0UL, +0UL, 64UL, 1088UL, 0UL, 0UL, 0UL, 128UL, 2176UL, 0UL, 0UL, 0UL, 256UL, 4352UL, 0UL, 0UL, 0UL, 512UL, 8704UL, 0UL, 0UL, 0UL, 1024UL, 17408UL, 0UL, 0UL, 0UL, 2048UL, 34816UL, 0UL, 0UL, 0UL, 4096UL, +69632UL, 0UL, 0UL, 0UL, 8192UL, 139264UL, 0UL, 0UL, 0UL, 16384UL, 278528UL, 0UL, 0UL, 0UL, 32768UL, 557056UL, 0UL, 0UL, 0UL, 65536UL, 1114112UL, 0UL, 0UL, 0UL, 131072UL, 2228224UL, 0UL, 0UL, 0UL, 262144UL, 4456448UL, 0UL, +0UL, 0UL, 524288UL, 8912896UL, 0UL, 0UL, 0UL, 1048576UL, 17825792UL, 0UL, 0UL, 0UL, 2097152UL, 35651584UL, 0UL, 0UL, 0UL, 4194304UL, 71303168UL, 0UL, 0UL, 0UL, 8388608UL, 142606336UL, 0UL, 0UL, 0UL, 16777216UL, 285212672UL, 0UL, 0UL, 0UL, +33554432UL, 570425344UL, 0UL, 0UL, 0UL, 67108864UL, 1140850688UL, 0UL, 0UL, 0UL, 134217728UL, 2281701376UL, 0UL, 0UL, 0UL, 268435456UL, 268435456UL, 0UL, 0UL, 0UL, 536870912UL, 536870912UL, 0UL, 0UL, 0UL, 1073741824UL, 1073741824UL, 0UL, 0UL, 0UL, 2147483648UL, 2147483648UL, +}, +{ +0UL, 3UL, 51UL, 771UL, 13107UL, 0UL, 6UL, 102UL, 1542UL, 26214UL, 0UL, 15UL, 255UL, 3855UL, 65535UL, 0UL, 30UL, 510UL, 7710UL, 131070UL, 0UL, 60UL, 1020UL, 15420UL, 262140UL, 0UL, 120UL, 2040UL, 30840UL, 524280UL, 0UL, 240UL, +4080UL, 61680UL, 1048560UL, 0UL, 480UL, 8160UL, 123360UL, 2097120UL, 0UL, 960UL, 16320UL, 246720UL, 4194240UL, 0UL, 1920UL, 32640UL, 493440UL, 8388480UL, 0UL, 3840UL, 65280UL, 986880UL, 16776960UL, 0UL, 7680UL, 130560UL, 1973760UL, 33553920UL, 0UL, 15360UL, 261120UL, 3947520UL, +67107840UL, 0UL, 30720UL, 522240UL, 7895040UL, 134215680UL, 0UL, 61440UL, 1044480UL, 15790080UL, 268431360UL, 0UL, 122880UL, 2088960UL, 31580160UL, 536862720UL, 0UL, 245760UL, 4177920UL, 63160320UL, 1073725440UL, 0UL, 491520UL, 8355840UL, 126320640UL, 2147450880UL, 0UL, 983040UL, 16711680UL, 252641280UL, 4294901760UL, 0UL, +1966080UL, 33423360UL, 505282560UL, 4294836224UL, 0UL, 3932160UL, 66846720UL, 1010565120UL, 4294705152UL, 0UL, 7864320UL, 133693440UL, 2021130240UL, 4294443008UL, 0UL, 15728640UL, 267386880UL, 4042260480UL, 4293918720UL, 0UL, 31457280UL, 534773760UL, 3789553664UL, 4292870144UL, 0UL, 62914560UL, 1069547520UL, 3284140032UL, 4290772992UL, 0UL, 125829120UL, 2139095040UL, +2273312768UL, 4286578688UL, 0UL, 251658240UL, 4278190080UL, 251658240UL, 4278190080UL, 0UL, 503316480UL, 4261412864UL, 503316480UL, 4261412864UL, 0UL, 1006632960UL, 4227858432UL, 1006632960UL, 4227858432UL, 0UL, 2013265920UL, 4160749568UL, 2013265920UL, 4160749568UL, 0UL, 4026531840UL, 4026531840UL, 4026531840UL, 4026531840UL, 0UL, 3758096384UL, 3758096384UL, 3758096384UL, 3758096384UL, +0UL, 0UL, 3UL, 51UL, 771UL, 0UL, 0UL, 6UL, 102UL, 1542UL, 0UL, 0UL, 15UL, 255UL, 3855UL, 0UL, 0UL, 30UL, 510UL, 7710UL, 0UL, 0UL, 60UL, 1020UL, 15420UL, 0UL, 0UL, 120UL, 2040UL, 30840UL, 0UL, 0UL, +240UL, 4080UL, 61680UL, 0UL, 0UL, 480UL, 8160UL, 123360UL, 0UL, 0UL, 960UL, 16320UL, 246720UL, 0UL, 0UL, 1920UL, 32640UL, 493440UL, 0UL, 0UL, 3840UL, 65280UL, 986880UL, 0UL, 0UL, 7680UL, 130560UL, 1973760UL, 0UL, 0UL, 15360UL, 261120UL, +3947520UL, 0UL, 0UL, 30720UL, 522240UL, 7895040UL, 0UL, 0UL, 61440UL, 1044480UL, 15790080UL, 0UL, 0UL, 122880UL, 2088960UL, 31580160UL, 0UL, 0UL, 245760UL, 4177920UL, 63160320UL, 0UL, 0UL, 491520UL, 8355840UL, 126320640UL, 0UL, 0UL, 983040UL, 16711680UL, 252641280UL, 0UL, +0UL, 1966080UL, 33423360UL, 505282560UL, 0UL, 0UL, 3932160UL, 66846720UL, 1010565120UL, 0UL, 0UL, 7864320UL, 133693440UL, 2021130240UL, 0UL, 0UL, 15728640UL, 267386880UL, 4042260480UL, 0UL, 0UL, 31457280UL, 534773760UL, 3789553664UL, 0UL, 0UL, 62914560UL, 1069547520UL, 3284140032UL, 0UL, 0UL, 125829120UL, +2139095040UL, 2273312768UL, 0UL, 0UL, 251658240UL, 4278190080UL, 251658240UL, 0UL, 0UL, 503316480UL, 4261412864UL, 503316480UL, 0UL, 0UL, 1006632960UL, 4227858432UL, 1006632960UL, 0UL, 0UL, 2013265920UL, 4160749568UL, 2013265920UL, 0UL, 0UL, 4026531840UL, 4026531840UL, 4026531840UL, 0UL, 0UL, 3758096384UL, 3758096384UL, 3758096384UL, +0UL, 0UL, 0UL, 3UL, 51UL, 0UL, 0UL, 0UL, 6UL, 102UL, 0UL, 0UL, 0UL, 15UL, 255UL, 0UL, 0UL, 0UL, 30UL, 510UL, 0UL, 0UL, 0UL, 60UL, 1020UL, 0UL, 0UL, 0UL, 120UL, 2040UL, 0UL, 0UL, +0UL, 240UL, 4080UL, 0UL, 0UL, 0UL, 480UL, 8160UL, 0UL, 0UL, 0UL, 960UL, 16320UL, 0UL, 0UL, 0UL, 1920UL, 32640UL, 0UL, 0UL, 0UL, 3840UL, 65280UL, 0UL, 0UL, 0UL, 7680UL, 130560UL, 0UL, 0UL, 0UL, 15360UL, +261120UL, 0UL, 0UL, 0UL, 30720UL, 522240UL, 0UL, 0UL, 0UL, 61440UL, 1044480UL, 0UL, 0UL, 0UL, 122880UL, 2088960UL, 0UL, 0UL, 0UL, 245760UL, 4177920UL, 0UL, 0UL, 0UL, 491520UL, 8355840UL, 0UL, 0UL, 0UL, 983040UL, 16711680UL, 0UL, +0UL, 0UL, 1966080UL, 33423360UL, 0UL, 0UL, 0UL, 3932160UL, 66846720UL, 0UL, 0UL, 0UL, 7864320UL, 133693440UL, 0UL, 0UL, 0UL, 15728640UL, 267386880UL, 0UL, 0UL, 0UL, 31457280UL, 534773760UL, 0UL, 0UL, 0UL, 62914560UL, 1069547520UL, 0UL, 0UL, 0UL, +125829120UL, 2139095040UL, 0UL, 0UL, 0UL, 251658240UL, 4278190080UL, 0UL, 0UL, 0UL, 503316480UL, 4261412864UL, 0UL, 0UL, 0UL, 1006632960UL, 4227858432UL, 0UL, 0UL, 0UL, 2013265920UL, 4160749568UL, 0UL, 0UL, 0UL, 4026531840UL, 4026531840UL, 0UL, 0UL, 0UL, 3758096384UL, 3758096384UL, +0UL, 0UL, 0UL, 0UL, 3UL, 0UL, 0UL, 0UL, 0UL, 6UL, 0UL, 0UL, 0UL, 0UL, 15UL, 0UL, 0UL, 0UL, 0UL, 30UL, 0UL, 0UL, 0UL, 0UL, 60UL, 0UL, 0UL, 0UL, 0UL, 120UL, 0UL, 0UL, +0UL, 0UL, 240UL, 0UL, 0UL, 0UL, 0UL, 480UL, 0UL, 0UL, 0UL, 0UL, 960UL, 0UL, 0UL, 0UL, 0UL, 1920UL, 0UL, 0UL, 0UL, 0UL, 3840UL, 0UL, 0UL, 0UL, 0UL, 7680UL, 0UL, 0UL, 0UL, 0UL, +15360UL, 0UL, 0UL, 0UL, 0UL, 30720UL, 0UL, 0UL, 0UL, 0UL, 61440UL, 0UL, 0UL, 0UL, 0UL, 122880UL, 0UL, 0UL, 0UL, 0UL, 245760UL, 0UL, 0UL, 0UL, 0UL, 491520UL, 0UL, 0UL, 0UL, 0UL, 983040UL, 0UL, +0UL, 0UL, 0UL, 1966080UL, 0UL, 0UL, 0UL, 0UL, 3932160UL, 0UL, 0UL, 0UL, 0UL, 7864320UL, 0UL, 0UL, 0UL, 0UL, 15728640UL, 0UL, 0UL, 0UL, 0UL, 31457280UL, 0UL, 0UL, 0UL, 0UL, 62914560UL, 0UL, 0UL, 0UL, +0UL, 125829120UL, 0UL, 0UL, 0UL, 0UL, 251658240UL, 0UL, 0UL, 0UL, 0UL, 503316480UL, 0UL, 0UL, 0UL, 0UL, 1006632960UL, 0UL, 0UL, 0UL, 0UL, 2013265920UL, 0UL, 0UL, 0UL, 0UL, 4026531840UL, 0UL, 0UL, 0UL, 0UL, 3758096384UL, +1UL, 17UL, 257UL, 4369UL, 65537UL, 2UL, 34UL, 514UL, 8738UL, 131074UL, 4UL, 68UL, 1028UL, 17476UL, 262148UL, 8UL, 136UL, 2056UL, 34952UL, 524296UL, 16UL, 272UL, 4112UL, 69904UL, 1048592UL, 32UL, 544UL, 8224UL, 139808UL, 2097184UL, 64UL, 1088UL, +16448UL, 279616UL, 4194368UL, 128UL, 2176UL, 32896UL, 559232UL, 8388736UL, 256UL, 4352UL, 65792UL, 1118464UL, 16777472UL, 512UL, 8704UL, 131584UL, 2236928UL, 33554944UL, 1024UL, 17408UL, 263168UL, 4473856UL, 67109888UL, 2048UL, 34816UL, 526336UL, 8947712UL, 134219776UL, 4096UL, 69632UL, 1052672UL, 17895424UL, +268439552UL, 8192UL, 139264UL, 2105344UL, 35790848UL, 536879104UL, 16384UL, 278528UL, 4210688UL, 71581696UL, 1073758208UL, 32768UL, 557056UL, 8421376UL, 143163392UL, 2147516416UL, 65536UL, 1114112UL, 16842752UL, 286326784UL, 65536UL, 131072UL, 2228224UL, 33685504UL, 572653568UL, 131072UL, 262144UL, 4456448UL, 67371008UL, 1145307136UL, 262144UL, 524288UL, +8912896UL, 134742016UL, 2290614272UL, 524288UL, 1048576UL, 17825792UL, 269484032UL, 286261248UL, 1048576UL, 2097152UL, 35651584UL, 538968064UL, 572522496UL, 2097152UL, 4194304UL, 71303168UL, 1077936128UL, 1145044992UL, 4194304UL, 8388608UL, 142606336UL, 2155872256UL, 2290089984UL, 8388608UL, 16777216UL, 285212672UL, 16777216UL, 285212672UL, 16777216UL, 33554432UL, 570425344UL, 33554432UL, +570425344UL, 33554432UL, 67108864UL, 1140850688UL, 67108864UL, 1140850688UL, 67108864UL, 134217728UL, 2281701376UL, 134217728UL, 2281701376UL, 134217728UL, 268435456UL, 268435456UL, 268435456UL, 268435456UL, 268435456UL, 536870912UL, 536870912UL, 536870912UL, 536870912UL, 536870912UL, 1073741824UL, 1073741824UL, 1073741824UL, 1073741824UL, 1073741824UL, 2147483648UL, 2147483648UL, 2147483648UL, 2147483648UL, 2147483648UL, +}, +{ +85009117UL, 335741939UL, 1412632518UL, 386859243UL, 1741437244UL, 152139416UL, 403047142UL, 2556825231UL, 505087203UL, 4287193174UL, 335609039UL, 336528191UL, 1425998811UL, 456920088UL, 2832198590UL, 724748988UL, 3625845630UL, 1509824181UL, 3330088197UL, 2710488401UL, 1431742057UL, 1077674236UL, 1140592489UL, 2096905276UL, 3007294393UL, 2863484114UL, 1081606648UL, 1207443154UL, 972585080UL, 2793363314UL, 1432000919UL, 1089470704UL, +1341132452UL, 3019109363UL, 2362285522UL, 1790260014UL, 2178941408UL, 2682264904UL, 1743251430UL, 429603751UL, 359294556UL, 62915520UL, 1069562512UL, 3486502860UL, 859207501UL, 3939814584UL, 125831040UL, 2139125024UL, 2678038424UL, 1718415002UL, 363436400UL, 251662080UL, 4278250048UL, 1061109552UL, 3436830004UL, 3948098272UL, 503324160UL, 4261532800UL, 2122219104UL, 2310257256UL, 380003776UL, 1006648320UL, 4228098304UL, 4244438208UL, +3278337232UL, 3981233024UL, 2013296640UL, 4161229312UL, 4193909120UL, 2530142624UL, 446273280UL, 4026593280UL, 4027491328UL, 871625472UL, 4254978880UL, 4113772032UL, 3758219264UL, 3760015360UL, 2011686400UL, 3946555008UL, 711351296UL, 3221471232UL, 3225063424UL, 4291808256UL, 108481792UL, 2496444416UL, 2147975168UL, 2155159552UL, 4020213760UL, 485399040UL, 3919147008UL, 983040UL, 15351808UL, 255799296UL, 3923588096UL, 322101248UL, +1966080UL, 299139072UL, 511598592UL, 3283773440UL, 3865427968UL, 3932160UL, 4087939072UL, 1023197184UL, 1467273216UL, 214663168UL, 7864320UL, 4149346304UL, 2046394368UL, 3202981888UL, 3650551808UL, 3236954112UL, 1050935296UL, 871563264UL, 2916302848UL, 1932394496UL, 2447376384UL, 1833435136UL, 2011561984UL, 2342944768UL, 643563520UL, 868220928UL, 177209344UL, 4291559424UL, 122486784UL, 2360868864UL, 2004877312UL, 85983232UL, +4019716096UL, 3734634496UL, 3647995904UL, 1056964608UL, 3661627392UL, 254803968UL, 2905866240UL, 1658847232UL, 2113929216UL, 3028287488UL, 3730833408UL, 2322071552UL, 3586129920UL, 4227858432UL, 1761607680UL, 2092957696UL, 80740352UL, 2071986176UL, 4160749568UL, 3523215360UL, 964689920UL, 429916160UL, 3875536896UL, 4026531840UL, 2751463424UL, 1929379840UL, 4081057792UL, 503316480UL, 3758096384UL, 2281701376UL, 4127195136UL, 3397386240UL, +1316635UL, 85009117UL, 335741939UL, 1412632518UL, 386859243UL, 1580547UL, 152139416UL, 403047142UL, 2556825231UL, 505087203UL, 1317672UL, 335609039UL, 336528191UL, 1425998811UL, 456920088UL, 1574501UL, 724748988UL, 3625845630UL, 1509824181UL, 3330088197UL, 15612UL, 1431742057UL, 1077674236UL, 1140592489UL, 2096905276UL, 31224UL, 2863484114UL, 1081606648UL, 1207443154UL, 972585080UL, 62451UL, 1432000919UL, +1089470704UL, 1341132452UL, 3019109363UL, 124902UL, 1790260014UL, 2178941408UL, 2682264904UL, 1743251430UL, 249804UL, 359294556UL, 62915520UL, 1069562512UL, 3486502860UL, 499608UL, 3939814584UL, 125831040UL, 2139125024UL, 2678038424UL, 999216UL, 363436400UL, 251662080UL, 4278250048UL, 1061109552UL, 3223223904UL, 3948098272UL, 503324160UL, 4261532800UL, 2122219104UL, 1077738688UL, 380003776UL, 1006648320UL, 4228098304UL, +4244438208UL, 1081735552UL, 3981233024UL, 2013296640UL, 4161229312UL, 4193909120UL, 1089729280UL, 446273280UL, 4026593280UL, 4027491328UL, 871625472UL, 2179458560UL, 4113772032UL, 3758219264UL, 3760015360UL, 2011686400UL, 63949824UL, 711351296UL, 3221471232UL, 3225063424UL, 4291808256UL, 127899648UL, 2496444416UL, 2147975168UL, 2155159552UL, 4020213760UL, 255799296UL, 3919147008UL, 983040UL, 15351808UL, 255799296UL, 3732824064UL, +322101248UL, 1966080UL, 299139072UL, 511598592UL, 2096939008UL, 3865427968UL, 3932160UL, 4087939072UL, 1023197184UL, 972652544UL, 214663168UL, 7864320UL, 4149346304UL, 2046394368UL, 3019046912UL, 3650551808UL, 3236954112UL, 1050935296UL, 871563264UL, 1743126528UL, 1932394496UL, 2447376384UL, 1833435136UL, 2011561984UL, 3486253056UL, 643563520UL, 868220928UL, 177209344UL, 4291559424UL, 2677538816UL, 2360868864UL, 2004877312UL, +85983232UL, 4019716096UL, 1060110336UL, 3647995904UL, 1056964608UL, 3661627392UL, 254803968UL, 3193962496UL, 1658847232UL, 2113929216UL, 3028287488UL, 3730833408UL, 3166699520UL, 3586129920UL, 4227858432UL, 1761607680UL, 2092957696UL, 3112173568UL, 2071986176UL, 4160749568UL, 3523215360UL, 964689920UL, 1929379840UL, 3875536896UL, 4026531840UL, 2751463424UL, 1929379840UL, 4127195136UL, 503316480UL, 3758096384UL, 2281701376UL, 4127195136UL, +332854UL, 1316635UL, 85009117UL, 335741939UL, 1412632518UL, 596079UL, 1580547UL, 152139416UL, 403047142UL, 2556825231UL, 1316075UL, 1317672UL, 335609039UL, 336528191UL, 1425998811UL, 2824661UL, 1574501UL, 724748988UL, 3625845630UL, 1509824181UL, 5571497UL, 15612UL, 1431742057UL, 1077674236UL, 1140592489UL, 11142994UL, 31224UL, 2863484114UL, 1081606648UL, 1207443154UL, 22285988UL, 62451UL, +1432000919UL, 1089470704UL, 1341132452UL, 44571976UL, 124902UL, 1790260014UL, 2178941408UL, 2682264904UL, 89143952UL, 249804UL, 359294556UL, 62915520UL, 1069562512UL, 178287904UL, 499608UL, 3939814584UL, 125831040UL, 2139125024UL, 356575808UL, 999216UL, 363436400UL, 251662080UL, 4278250048UL, 713151616UL, 3223223904UL, 3948098272UL, 503324160UL, 4261532800UL, 1426303232UL, 1077738688UL, 380003776UL, 1006648320UL, +4228098304UL, 2852606464UL, 1081735552UL, 3981233024UL, 2013296640UL, 4161229312UL, 1410245632UL, 1089729280UL, 446273280UL, 4026593280UL, 4027491328UL, 1746749440UL, 2179458560UL, 4113772032UL, 3758219264UL, 3760015360UL, 272273408UL, 63949824UL, 711351296UL, 3221471232UL, 3225063424UL, 3765772288UL, 127899648UL, 2496444416UL, 2147975168UL, 2155159552UL, 15351808UL, 255799296UL, 3919147008UL, 983040UL, 15351808UL, 3251929088UL, +3732824064UL, 322101248UL, 1966080UL, 299139072UL, 1135149056UL, 2096939008UL, 3865427968UL, 3932160UL, 4087939072UL, 1196556288UL, 972652544UL, 214663168UL, 7864320UL, 4149346304UL, 1319370752UL, 3019046912UL, 3650551808UL, 3236954112UL, 1050935296UL, 2638741504UL, 1743126528UL, 1932394496UL, 2447376384UL, 1833435136UL, 982515712UL, 3486253056UL, 643563520UL, 868220928UL, 177209344UL, 1965031424UL, 2677538816UL, 2360868864UL, +2004877312UL, 85983232UL, 3930062848UL, 1060110336UL, 3647995904UL, 1056964608UL, 3661627392UL, 3565158400UL, 3193962496UL, 1658847232UL, 2113929216UL, 3028287488UL, 2835349504UL, 3166699520UL, 3586129920UL, 4227858432UL, 1761607680UL, 1375731712UL, 3112173568UL, 2071986176UL, 4160749568UL, 3523215360UL, 2751463424UL, 1929379840UL, 3875536896UL, 4026531840UL, 2751463424UL, 2281701376UL, 4127195136UL, 503316480UL, 3758096384UL, 2281701376UL, +5123UL, 332854UL, 1316635UL, 85009117UL, 335741939UL, 6150UL, 596079UL, 1580547UL, 152139416UL, 403047142UL, 5135UL, 1316075UL, 1317672UL, 335609039UL, 336528191UL, 6174UL, 2824661UL, 1574501UL, 724748988UL, 3625845630UL, 60UL, 5571497UL, 15612UL, 1431742057UL, 1077674236UL, 120UL, 11142994UL, 31224UL, 2863484114UL, 1081606648UL, 240UL, 22285988UL, +62451UL, 1432000919UL, 1089470704UL, 480UL, 44571976UL, 124902UL, 1790260014UL, 2178941408UL, 960UL, 89143952UL, 249804UL, 359294556UL, 62915520UL, 1920UL, 178287904UL, 499608UL, 3939814584UL, 125831040UL, 3840UL, 356575808UL, 999216UL, 363436400UL, 251662080UL, 7680UL, 713151616UL, 3223223904UL, 3948098272UL, 503324160UL, 15360UL, 1426303232UL, 1077738688UL, 380003776UL, +1006648320UL, 30720UL, 2852606464UL, 1081735552UL, 3981233024UL, 2013296640UL, 61440UL, 1410245632UL, 1089729280UL, 446273280UL, 4026593280UL, 122880UL, 1746749440UL, 2179458560UL, 4113772032UL, 3758219264UL, 245760UL, 272273408UL, 63949824UL, 711351296UL, 3221471232UL, 491520UL, 3765772288UL, 127899648UL, 2496444416UL, 2147975168UL, 983040UL, 15351808UL, 255799296UL, 3919147008UL, 983040UL, 3223191552UL, +3251929088UL, 3732824064UL, 322101248UL, 1966080UL, 1077673984UL, 1135149056UL, 2096939008UL, 3865427968UL, 3932160UL, 1081606144UL, 1196556288UL, 972652544UL, 214663168UL, 7864320UL, 1089470464UL, 1319370752UL, 3019046912UL, 3650551808UL, 3236954112UL, 2178940928UL, 2638741504UL, 1743126528UL, 1932394496UL, 2447376384UL, 62914560UL, 982515712UL, 3486253056UL, 643563520UL, 868220928UL, 125829120UL, 1965031424UL, 2677538816UL, +2360868864UL, 2004877312UL, 251658240UL, 3930062848UL, 1060110336UL, 3647995904UL, 1056964608UL, 503316480UL, 3565158400UL, 3193962496UL, 1658847232UL, 2113929216UL, 1006632960UL, 2835349504UL, 3166699520UL, 3586129920UL, 4227858432UL, 2013265920UL, 1375731712UL, 3112173568UL, 2071986176UL, 4160749568UL, 4026531840UL, 2751463424UL, 1929379840UL, 3875536896UL, 4026531840UL, 3758096384UL, 2281701376UL, 4127195136UL, 503316480UL, 3758096384UL, +201392209UL, 3423671362UL, 218366296UL, 3713336838UL, 206572594UL, 402785186UL, 2552372100UL, 436928947UL, 3130605370UL, 463476848UL, 262468UL, 4461835UL, 68158800UL, 1158700908UL, 20971524UL, 524680UL, 8919318UL, 136513955UL, 2316537326UL, 25165852UL, 3222274064UL, 3239051564UL, 3494187077UL, 3558090985UL, 3221225500UL, 2149580832UL, 2183135832UL, 2693406858UL, 2821214674UL, 2147483704UL, 4194368UL, 71304368UL, +1091846420UL, 1347462055UL, 64UL, 8388736UL, 142608736UL, 2183692840UL, 2694924110UL, 3221225600UL, 16777472UL, 285217472UL, 72418384UL, 1094880924UL, 1342177536UL, 33554944UL, 570434944UL, 144836768UL, 2189761848UL, 2684355072UL, 67109888UL, 1140869888UL, 289673536UL, 84556400UL, 1073742848UL, 134219776UL, 2281739776UL, 579347072UL, 169112800UL, 2147485696UL, 268439552UL, 268512256UL, 1158694144UL, 69790144UL, +4096UL, 536879104UL, 537024512UL, 2317388288UL, 3360805760UL, 8192UL, 1073758208UL, 1074049024UL, 339809280UL, 1352902400UL, 16384UL, 2147516416UL, 2148098048UL, 3900844032UL, 1632062976UL, 32768UL, 65536UL, 1228800UL, 17059840UL, 311335936UL, 65536UL, 131072UL, 2457600UL, 34119680UL, 622671872UL, 131072UL, 262144UL, 4915200UL, 68239360UL, 1245343744UL, 262144UL, 524288UL, +9830400UL, 136478720UL, 2490687488UL, 524288UL, 1048576UL, 288096256UL, 272957440UL, 954843136UL, 3222274048UL, 2097152UL, 3797417984UL, 545914880UL, 2983428096UL, 2149580800UL, 4194304UL, 78643200UL, 1091829760UL, 2745630720UL, 4194304UL, 3229614080UL, 3378511872UL, 1109917696UL, 2270035968UL, 8388608UL, 1358954496UL, 1119879168UL, 1414529024UL, 513540096UL, 16777216UL, 2717908992UL, 2239758336UL, 2829058048UL, +1027080192UL, 33554432UL, 1140850688UL, 184549376UL, 1363148800UL, 2054160384UL, 3288334336UL, 2281701376UL, 369098752UL, 2726297600UL, 4108320768UL, 2281701376UL, 268435456UL, 738197504UL, 2231369728UL, 968884224UL, 3959422976UL, 536870912UL, 1476395008UL, 167772160UL, 3011510272UL, 3355443200UL, 1073741824UL, 2952790016UL, 335544320UL, 1728053248UL, 2147483648UL, 2147483648UL, 1610612736UL, 3892314112UL, 503316480UL, 0UL, +}, +{ +1939838472UL, 1412147404UL, 166205219UL, 1757484276UL, 2905930693UL, 2345662040UL, 2845657161UL, 253454719UL, 2661974169UL, 303781080UL, 4075331504UL, 31014156UL, 244538930UL, 3752264221UL, 992575155UL, 219309525UL, 246620060UL, 215640989UL, 4125020723UL, 2016731730UL, 3236558869UL, 297169276UL, 3293566751UL, 1867504216UL, 210423272UL, 2531663658UL, 499723753UL, 1730625896UL, 189236880UL, 3388575408UL, 2433358422UL, 1368961148UL, +3134096848UL, 2827836415UL, 3888822753UL, 4172043647UL, 3379360748UL, 2651760955UL, 1345081091UL, 627692776UL, 189423917UL, 1927379456UL, 4004336944UL, 2995932065UL, 1882016234UL, 2551113616UL, 1576396048UL, 1299792730UL, 2151240795UL, 2154814108UL, 4292139924UL, 3555849728UL, 943986992UL, 3169912733UL, 2631635779UL, 3478094562UL, 1285558544UL, 3716074330UL, 2780749859UL, 3911106510UL, 4175656994UL, 1731832828UL, 1275401375UL, 937322456UL, +3802094750UL, 1145506936UL, 1008905193UL, 1718801768UL, 645739137UL, 1356219146UL, 827886816UL, 1722154800UL, 2242776733UL, 754630810UL, 772070504UL, 249481170UL, 2608123425UL, 2087201889UL, 3200968096UL, 3292110026UL, 841433255UL, 477543427UL, 1878882709UL, 705347364UL, 4003860146UL, 3194913138UL, 2616490007UL, 357561212UL, 2446098297UL, 2955680594UL, 2512991743UL, 637464579UL, 1209132455UL, 1341312804UL, 612108672UL, 2455017713UL, +1749147666UL, 4020226825UL, 2873924220UL, 499405095UL, 1837614076UL, 1227604028UL, 714577577UL, 165950208UL, 442290261UL, 489077752UL, 216760440UL, 42151250UL, 426862080UL, 2810242474UL, 4112075489UL, 3514761468UL, 4101921371UL, 982512636UL, 500792667UL, 4286077681UL, 198050301UL, 1858712743UL, 2913642493UL, 3547545255UL, 3981929169UL, 2944140287UL, 2286578015UL, 3422343167UL, 1239123295UL, 2026367394UL, 3269986302UL, 3028402878UL, +2709637886UL, 1096011710UL, 294584132UL, 3086749695UL, 3324400975UL, 1164394495UL, 4290155855UL, 543687304UL, 4008517630UL, 836370334UL, 1876426750UL, 2362048414UL, 3578325264UL, 3221487612UL, 2671154748UL, 3395518460UL, 2018383420UL, 2131029536UL, 2165829624UL, 697661816UL, 1336049656UL, 3309365624UL, 4259639360UL, 3423548400UL, 2416417776UL, 1633698800UL, 1630071792UL, 41950336UL, 3423478496UL, 2885608160UL, 3943744224UL, 677380832UL, +4179285363UL, 1939838472UL, 1412147404UL, 166205219UL, 1757484276UL, 3838244595UL, 2345662040UL, 2845657161UL, 253454719UL, 2661974169UL, 138737288UL, 4075331504UL, 31014156UL, 244538930UL, 3752264221UL, 1503392345UL, 219309525UL, 246620060UL, 215640989UL, 4125020723UL, 1759481152UL, 3236558869UL, 297169276UL, 3293566751UL, 1867504216UL, 3898070400UL, 2531663658UL, 499723753UL, 1730625896UL, 189236880UL, 2610231010UL, 2433358422UL, +1368961148UL, 3134096848UL, 2827836415UL, 3903474593UL, 4172043647UL, 3379360748UL, 2651760955UL, 1345081091UL, 1267864331UL, 189423917UL, 1927379456UL, 4004336944UL, 2995932065UL, 3452816347UL, 2551113616UL, 1576396048UL, 1299792730UL, 2151240795UL, 1222520631UL, 4292139924UL, 3555849728UL, 943986992UL, 3169912733UL, 3260130211UL, 3478094562UL, 1285558544UL, 3716074330UL, 2780749859UL, 3039362306UL, 4175656994UL, 1731832828UL, 1275401375UL, +937322456UL, 3236754932UL, 1145506936UL, 1008905193UL, 1718801768UL, 645739137UL, 1358079399UL, 827886816UL, 1722154800UL, 2242776733UL, 754630810UL, 1748663943UL, 249481170UL, 2608123425UL, 2087201889UL, 3200968096UL, 698076610UL, 841433255UL, 477543427UL, 1878882709UL, 705347364UL, 3692794996UL, 3194913138UL, 2616490007UL, 357561212UL, 2446098297UL, 2771068186UL, 2512991743UL, 637464579UL, 1209132455UL, 1341312804UL, 27937268UL, +2455017713UL, 1749147666UL, 4020226825UL, 2873924220UL, 1673040956UL, 1837614076UL, 1227604028UL, 714577577UL, 165950208UL, 528340088UL, 489077752UL, 216760440UL, 42151250UL, 426862080UL, 1646215396UL, 4112075489UL, 3514761468UL, 4101921371UL, 982512636UL, 2095821304UL, 4286077681UL, 198050301UL, 1858712743UL, 2913642493UL, 277300160UL, 3981929169UL, 2944140287UL, 2286578015UL, 3422343167UL, 1178044288UL, 2026367394UL, 3269986302UL, +3028402878UL, 2709637886UL, 2234191616UL, 294584132UL, 3086749695UL, 3324400975UL, 1164394495UL, 136978944UL, 543687304UL, 4008517630UL, 836370334UL, 1876426750UL, 3275253760UL, 3578325264UL, 3221487612UL, 2671154748UL, 3395518460UL, 3942394880UL, 2131029536UL, 2165829624UL, 697661816UL, 1336049656UL, 3265045504UL, 4259639360UL, 3423548400UL, 2416417776UL, 1633698800UL, 3943712768UL, 41950336UL, 3423478496UL, 2885608160UL, 3943744224UL, +2293593009UL, 4179285363UL, 1939838472UL, 1412147404UL, 166205219UL, 715714152UL, 3838244595UL, 2345662040UL, 2845657161UL, 253454719UL, 3758048260UL, 138737288UL, 4075331504UL, 31014156UL, 244538930UL, 370671650UL, 1503392345UL, 219309525UL, 246620060UL, 215640989UL, 2219162331UL, 1759481152UL, 3236558869UL, 297169276UL, 3293566751UL, 135243402UL, 3898070400UL, 2531663658UL, 499723753UL, 1730625896UL, 3142293713UL, 2610231010UL, +2433358422UL, 1368961148UL, 3134096848UL, 486949791UL, 3903474593UL, 4172043647UL, 3379360748UL, 2651760955UL, 3172880550UL, 1267864331UL, 189423917UL, 1927379456UL, 4004336944UL, 191463910UL, 3452816347UL, 2551113616UL, 1576396048UL, 1299792730UL, 4411574UL, 1222520631UL, 4292139924UL, 3555849728UL, 943986992UL, 3073348038UL, 3260130211UL, 3478094562UL, 1285558544UL, 3716074330UL, 3098363790UL, 3039362306UL, 4175656994UL, 1731832828UL, +1275401375UL, 468159532UL, 3236754932UL, 1145506936UL, 1008905193UL, 1718801768UL, 1092964081UL, 1358079399UL, 827886816UL, 1722154800UL, 2242776733UL, 53128947UL, 1748663943UL, 249481170UL, 2608123425UL, 2087201889UL, 1960144614UL, 698076610UL, 841433255UL, 477543427UL, 1878882709UL, 1505419004UL, 3692794996UL, 3194913138UL, 2616490007UL, 357561212UL, 2823143358UL, 2771068186UL, 2512991743UL, 637464579UL, 1209132455UL, 1991737212UL, +27937268UL, 2455017713UL, 1749147666UL, 4020226825UL, 2907896812UL, 1673040956UL, 1837614076UL, 1227604028UL, 714577577UL, 3633969112UL, 528340088UL, 489077752UL, 216760440UL, 42151250UL, 2886728356UL, 1646215396UL, 4112075489UL, 3514761468UL, 4101921371UL, 3507686008UL, 2095821304UL, 4286077681UL, 198050301UL, 1858712743UL, 1463806912UL, 277300160UL, 3981929169UL, 2944140287UL, 2286578015UL, 4137888640UL, 1178044288UL, 2026367394UL, +3269986302UL, 3028402878UL, 1276820224UL, 2234191616UL, 294584132UL, 3086749695UL, 3324400975UL, 4274031104UL, 136978944UL, 543687304UL, 4008517630UL, 836370334UL, 2978609152UL, 3275253760UL, 3578325264UL, 3221487612UL, 2671154748UL, 2296777728UL, 3942394880UL, 2131029536UL, 2165829624UL, 697661816UL, 1086645248UL, 3265045504UL, 4259639360UL, 3423548400UL, 2416417776UL, 2295121920UL, 3943712768UL, 41950336UL, 3423478496UL, 2885608160UL, +3290486993UL, 2293593009UL, 4179285363UL, 1939838472UL, 1412147404UL, 3718742914UL, 715714152UL, 3838244595UL, 2345662040UL, 2845657161UL, 3251034248UL, 3758048260UL, 138737288UL, 4075331504UL, 31014156UL, 2257801369UL, 370671650UL, 1503392345UL, 219309525UL, 246620060UL, 1375177854UL, 2219162331UL, 1759481152UL, 3236558869UL, 297169276UL, 2981812236UL, 135243402UL, 3898070400UL, 2531663658UL, 499723753UL, 1103465850UL, 3142293713UL, +2610231010UL, 2433358422UL, 1368961148UL, 2570001060UL, 486949791UL, 3903474593UL, 4172043647UL, 3379360748UL, 1922171925UL, 3172880550UL, 1267864331UL, 189423917UL, 1927379456UL, 1359812359UL, 191463910UL, 3452816347UL, 2551113616UL, 1576396048UL, 2518549525UL, 4411574UL, 1222520631UL, 4292139924UL, 3555849728UL, 949028615UL, 3073348038UL, 3260130211UL, 3478094562UL, 1285558544UL, 4113039486UL, 3098363790UL, 3039362306UL, 4175656994UL, +1731832828UL, 1827471372UL, 468159532UL, 3236754932UL, 1145506936UL, 1008905193UL, 1626341859UL, 1092964081UL, 1358079399UL, 827886816UL, 1722154800UL, 1069547583UL, 53128947UL, 1748663943UL, 249481170UL, 2608123425UL, 3162506114UL, 1960144614UL, 698076610UL, 841433255UL, 477543427UL, 3641706484UL, 1505419004UL, 3692794996UL, 3194913138UL, 2616490007UL, 3623882586UL, 2823143358UL, 2771068186UL, 2512991743UL, 637464579UL, 16785012UL, +1991737212UL, 27937268UL, 2455017713UL, 1749147666UL, 2348825660UL, 2907896812UL, 1673040956UL, 1837614076UL, 1227604028UL, 2579527800UL, 3633969112UL, 528340088UL, 489077752UL, 216760440UL, 3628134628UL, 2886728356UL, 1646215396UL, 4112075489UL, 3514761468UL, 1602085368UL, 3507686008UL, 2095821304UL, 4286077681UL, 198050301UL, 2501362624UL, 1463806912UL, 277300160UL, 3981929169UL, 2944140287UL, 4112467840UL, 4137888640UL, 1178044288UL, +2026367394UL, 3269986302UL, 3356184320UL, 1276820224UL, 2234191616UL, 294584132UL, 3086749695UL, 366387712UL, 4274031104UL, 136978944UL, 543687304UL, 4008517630UL, 1006135296UL, 2978609152UL, 3275253760UL, 3578325264UL, 3221487612UL, 3104844800UL, 2296777728UL, 3942394880UL, 2131029536UL, 2165829624UL, 1874371584UL, 1086645248UL, 3265045504UL, 4259639360UL, 3423548400UL, 2975352832UL, 2295121920UL, 3943712768UL, 41950336UL, 3423478496UL, +989898496UL, 3410688577UL, 2331788830UL, 3546482013UL, 813828841UL, 1865093068UL, 3265457506UL, 3795669738UL, 2119696024UL, 4285651426UL, 3333834629UL, 3451487261UL, 2090324595UL, 1816963648UL, 932961512UL, 2470761029UL, 3401764108UL, 3421619354UL, 4199624502UL, 589386372UL, 879396240UL, 3372470254UL, 2693109296UL, 2424215996UL, 38442268UL, 1882087724UL, 171397600UL, 2024561281UL, 183095586UL, 3282207272UL, 3402177296UL, 1859195498UL, +413109947UL, 2839537944UL, 1632143648UL, 3742715856UL, 388696500UL, 1748703733UL, 3563198567UL, 3826785440UL, 2896086528UL, 3989037829UL, 1478787788UL, 1390277813UL, 2123320736UL, 3416516800UL, 2056564203UL, 2584895011UL, 1605192736UL, 2475623616UL, 3856499712UL, 3439657984UL, 708088129UL, 1501395566UL, 1302184960UL, 1360092352UL, 1645630430UL, 1425230387UL, 3369488824UL, 2979863936UL, 869212432UL, 150548847UL, 1097557362UL, 655939640UL, +316553344UL, 3761918508UL, 3958338094UL, 141744600UL, 1412214640UL, 1859689984UL, 3200680981UL, 3883058679UL, 999801880UL, 3946079738UL, 1876072704UL, 194381849UL, 2177533995UL, 1584707624UL, 3053768410UL, 2593051904UL, 3458076673UL, 4047442835UL, 3545972808UL, 3441793178UL, 194975744UL, 1731731470UL, 4168755162UL, 2628944732UL, 2125675784UL, 3119906816UL, 960774145UL, 2646626078UL, 2152793157UL, 3049156634UL, 672464896UL, 3046932493UL, +3700727536UL, 2152335477UL, 575986696UL, 671940608UL, 2208366608UL, 1454456125UL, 937760016UL, 4103979069UL, 2737668096UL, 1179779104UL, 1030912634UL, 1041902112UL, 2032909434UL, 2274230272UL, 2089025605UL, 3050632421UL, 2428784965UL, 140658149UL, 4254138368UL, 1745354889UL, 711584249UL, 2746523017UL, 2551006457UL, 1100808192UL, 1494221073UL, 3422999489UL, 2696954129UL, 976716737UL, 2653421568UL, 3806331426UL, 3690047362UL, 1481392674UL, +3817015170UL, 2353004544UL, 286262340UL, 2300534532UL, 4206449732UL, 15339268UL, 2894069760UL, 488376456UL, 1489927688UL, 1196583048UL, 652746248UL, 2214592512UL, 69904UL, 1006205200UL, 2322628880UL, 1229515024UL, 2617245696UL, 3423527456UL, 1964953120UL, 4260938272UL, 386199072UL, 1744830464UL, 1342444608UL, 1069330496UL, 2138592320UL, 3185897536UL, 1073741824UL, 1342493824UL, 3780942976UL, 1771066496UL, 2189433984UL, 2147483648UL, +}, +{ +1804684571UL, 2106089606UL, 1533056158UL, 2870216110UL, 3618155659UL, 3789871366UL, 4246691682UL, 3667072763UL, 1212241769UL, 3152390668UL, 2973497449UL, 2958641966UL, 2088805328UL, 717518631UL, 2401090860UL, 3606967204UL, 952637656UL, 59827581UL, 1291486682UL, 1499453515UL, 2053994857UL, 563998083UL, 4094000396UL, 1163546899UL, 1003843565UL, 654565639UL, 1070907026UL, 4217851863UL, 426034251UL, 1721352737UL, 278404469UL, 3899800390UL, +1063362170UL, 1162348262UL, 3153545093UL, 3249996223UL, 186674553UL, 2616406148UL, 3137968354UL, 1282784965UL, 1495068058UL, 3033760361UL, 2278144523UL, 3192245769UL, 719586342UL, 2602548287UL, 3386583150UL, 355354345UL, 3252815848UL, 2178056037UL, 2283016801UL, 3005955037UL, 3340254490UL, 802791670UL, 251122316UL, 3705188626UL, 1252262272UL, 3989036796UL, 3527490452UL, 2047131255UL, 1447170583UL, 3373930285UL, 2895037457UL, 209341805UL, +1820357643UL, 3712392731UL, 685796521UL, 1322920440UL, 814388470UL, 1357857147UL, 434430265UL, 2650681935UL, 1371566728UL, 58783716UL, 2273435933UL, 3498513198UL, 792571900UL, 1447808772UL, 3513385860UL, 99175889UL, 1105434360UL, 1484146625UL, 3327194068UL, 242672513UL, 3552105593UL, 1425844616UL, 2871928454UL, 1124633561UL, 607610433UL, 2130018608UL, 1610235673UL, 2844230432UL, 2748082340UL, 994392866UL, 450823250UL, 2912535126UL, +2574390988UL, 3974009252UL, 78696582UL, 649682891UL, 3980917176UL, 3221419689UL, 960695436UL, 729221508UL, 358358845UL, 3392407691UL, 472711005UL, 295914899UL, 3005191796UL, 3078521977UL, 3370011868UL, 509135340UL, 1965939519UL, 2086465877UL, 2457949822UL, 1324152522UL, 762289386UL, 3618693997UL, 233730715UL, 2873984650UL, 31168606UL, 3367142977UL, 2851851305UL, 3251660053UL, 4209768406UL, 3298190175UL, 901235185UL, 1564391510UL, +2352686527UL, 1008150482UL, 578573310UL, 3462447127UL, 2482873876UL, 1790221257UL, 2255375608UL, 2335345651UL, 1381450613UL, 2866805101UL, 1495073163UL, 519905259UL, 3184556473UL, 1076378339UL, 2692926127UL, 970097715UL, 4013407916UL, 4014350363UL, 2476927059UL, 1989070516UL, 2640060069UL, 1987784589UL, 1880989003UL, 3861138803UL, 451743296UL, 1987067871UL, 1975657871UL, 3397816882UL, 2309900530UL, 4108425851UL, 4063867233UL, 3319482186UL, +2621772886UL, 1804684571UL, 2106089606UL, 1533056158UL, 2870216110UL, 611557097UL, 3789871366UL, 4246691682UL, 3667072763UL, 1212241769UL, 3389551988UL, 2973497449UL, 2958641966UL, 2088805328UL, 717518631UL, 2460955430UL, 3606967204UL, 952637656UL, 59827581UL, 1291486682UL, 3531087304UL, 2053994857UL, 563998083UL, 4094000396UL, 1163546899UL, 1242934125UL, 654565639UL, 1070907026UL, 4217851863UL, 426034251UL, 3034416129UL, 278404469UL, +3899800390UL, 1063362170UL, 1162348262UL, 4258714417UL, 3249996223UL, 186674553UL, 2616406148UL, 3137968354UL, 639885806UL, 1495068058UL, 3033760361UL, 2278144523UL, 3192245769UL, 4159910300UL, 2602548287UL, 3386583150UL, 355354345UL, 3252815848UL, 1555885880UL, 2283016801UL, 3005955037UL, 3340254490UL, 802791670UL, 2948774612UL, 3705188626UL, 1252262272UL, 3989036796UL, 3527490452UL, 2107826711UL, 1447170583UL, 3373930285UL, 2895037457UL, +209341805UL, 3763367196UL, 3712392731UL, 685796521UL, 1322920440UL, 814388470UL, 1986168339UL, 434430265UL, 2650681935UL, 1371566728UL, 58783716UL, 1423189187UL, 3498513198UL, 792571900UL, 1447808772UL, 3513385860UL, 315969823UL, 1105434360UL, 1484146625UL, 3327194068UL, 242672513UL, 3336228275UL, 1425844616UL, 2871928454UL, 1124633561UL, 607610433UL, 1762052458UL, 1610235673UL, 2844230432UL, 2748082340UL, 994392866UL, 3771702243UL, +2912535126UL, 2574390988UL, 3974009252UL, 78696582UL, 1626628844UL, 3980917176UL, 3221419689UL, 960695436UL, 729221508UL, 382092233UL, 3392407691UL, 472711005UL, 295914899UL, 3005191796UL, 514297204UL, 3370011868UL, 509135340UL, 1965939519UL, 2086465877UL, 3975975091UL, 1324152522UL, 762289386UL, 3618693997UL, 233730715UL, 455322516UL, 31168606UL, 3367142977UL, 2851851305UL, 3251660053UL, 3952189603UL, 3298190175UL, 901235185UL, +1564391510UL, 2352686527UL, 826181452UL, 578573310UL, 3462447127UL, 2482873876UL, 1790221257UL, 1529242773UL, 2335345651UL, 1381450613UL, 2866805101UL, 1495073163UL, 877718651UL, 3184556473UL, 1076378339UL, 2692926127UL, 970097715UL, 299344245UL, 4014350363UL, 2476927059UL, 1989070516UL, 2640060069UL, 3844531327UL, 1880989003UL, 3861138803UL, 451743296UL, 1987067871UL, 3272848161UL, 3397816882UL, 2309900530UL, 4108425851UL, 4063867233UL, +834288064UL, 2621772886UL, 1804684571UL, 2106089606UL, 1533056158UL, 304865970UL, 611557097UL, 3789871366UL, 4246691682UL, 3667072763UL, 2728206193UL, 3389551988UL, 2973497449UL, 2958641966UL, 2088805328UL, 3895037582UL, 2460955430UL, 3606967204UL, 952637656UL, 59827581UL, 2349212526UL, 3531087304UL, 2053994857UL, 563998083UL, 4094000396UL, 4028900485UL, 1242934125UL, 654565639UL, 1070907026UL, 4217851863UL, 1663452176UL, 3034416129UL, +278404469UL, 3899800390UL, 1063362170UL, 2721441405UL, 4258714417UL, 3249996223UL, 186674553UL, 2616406148UL, 4228837490UL, 639885806UL, 1495068058UL, 3033760361UL, 2278144523UL, 2820661772UL, 4159910300UL, 2602548287UL, 3386583150UL, 355354345UL, 1815256314UL, 1555885880UL, 2283016801UL, 3005955037UL, 3340254490UL, 2166514144UL, 2948774612UL, 3705188626UL, 1252262272UL, 3989036796UL, 751187322UL, 2107826711UL, 1447170583UL, 3373930285UL, +2895037457UL, 2809311944UL, 3763367196UL, 3712392731UL, 685796521UL, 1322920440UL, 936300677UL, 1986168339UL, 434430265UL, 2650681935UL, 1371566728UL, 1308015359UL, 1423189187UL, 3498513198UL, 792571900UL, 1447808772UL, 3065349526UL, 315969823UL, 1105434360UL, 1484146625UL, 3327194068UL, 1038676789UL, 3336228275UL, 1425844616UL, 2871928454UL, 1124633561UL, 2956422231UL, 1762052458UL, 1610235673UL, 2844230432UL, 2748082340UL, 3603862093UL, +3771702243UL, 2912535126UL, 2574390988UL, 3974009252UL, 1691332448UL, 1626628844UL, 3980917176UL, 3221419689UL, 960695436UL, 3120142427UL, 382092233UL, 3392407691UL, 472711005UL, 295914899UL, 4101686983UL, 514297204UL, 3370011868UL, 509135340UL, 1965939519UL, 3015736706UL, 3975975091UL, 1324152522UL, 762289386UL, 3618693997UL, 2395097989UL, 455322516UL, 31168606UL, 3367142977UL, 2851851305UL, 30511955UL, 3952189603UL, 3298190175UL, +901235185UL, 1564391510UL, 2606298633UL, 826181452UL, 578573310UL, 3462447127UL, 2482873876UL, 4159642946UL, 1529242773UL, 2335345651UL, 1381450613UL, 2866805101UL, 1782913669UL, 877718651UL, 3184556473UL, 1076378339UL, 2692926127UL, 1730328819UL, 299344245UL, 4014350363UL, 2476927059UL, 1989070516UL, 1425685614UL, 3844531327UL, 1880989003UL, 3861138803UL, 451743296UL, 889237383UL, 3272848161UL, 3397816882UL, 2309900530UL, 4108425851UL, +1155723231UL, 834288064UL, 2621772886UL, 1804684571UL, 2106089606UL, 2387009004UL, 304865970UL, 611557097UL, 3789871366UL, 4246691682UL, 1405709661UL, 2728206193UL, 3389551988UL, 2973497449UL, 2958641966UL, 3183906006UL, 3895037582UL, 2460955430UL, 3606967204UL, 952637656UL, 1345432763UL, 2349212526UL, 3531087304UL, 2053994857UL, 563998083UL, 3749011414UL, 4028900485UL, 1242934125UL, 654565639UL, 1070907026UL, 1072342672UL, 1663452176UL, +3034416129UL, 278404469UL, 3899800390UL, 3566652188UL, 2721441405UL, 4258714417UL, 3249996223UL, 186674553UL, 4001263143UL, 4228837490UL, 639885806UL, 1495068058UL, 3033760361UL, 4278332644UL, 2820661772UL, 4159910300UL, 2602548287UL, 3386583150UL, 838831089UL, 1815256314UL, 1555885880UL, 2283016801UL, 3005955037UL, 3377397178UL, 2166514144UL, 2948774612UL, 3705188626UL, 1252262272UL, 2414422575UL, 751187322UL, 2107826711UL, 1447170583UL, +3373930285UL, 1253755033UL, 2809311944UL, 3763367196UL, 3712392731UL, 685796521UL, 3238624475UL, 936300677UL, 1986168339UL, 434430265UL, 2650681935UL, 1642290570UL, 1308015359UL, 1423189187UL, 3498513198UL, 792571900UL, 173318140UL, 3065349526UL, 315969823UL, 1105434360UL, 1484146625UL, 4103797777UL, 1038676789UL, 3336228275UL, 1425844616UL, 2871928454UL, 1797745765UL, 2956422231UL, 1762052458UL, 1610235673UL, 2844230432UL, 2180656608UL, +3603862093UL, 3771702243UL, 2912535126UL, 2574390988UL, 1183098390UL, 1691332448UL, 1626628844UL, 3980917176UL, 3221419689UL, 2645203959UL, 3120142427UL, 382092233UL, 3392407691UL, 472711005UL, 1659659070UL, 4101686983UL, 514297204UL, 3370011868UL, 509135340UL, 483888155UL, 3015736706UL, 3975975091UL, 1324152522UL, 762289386UL, 1259948064UL, 2395097989UL, 455322516UL, 31168606UL, 3367142977UL, 339990414UL, 30511955UL, 3952189603UL, +3298190175UL, 901235185UL, 3097920065UL, 2606298633UL, 826181452UL, 578573310UL, 3462447127UL, 1548039839UL, 4159642946UL, 1529242773UL, 2335345651UL, 1381450613UL, 2173079994UL, 1782913669UL, 877718651UL, 3184556473UL, 1076378339UL, 1570275057UL, 1730328819UL, 299344245UL, 4014350363UL, 2476927059UL, 1845882881UL, 1425685614UL, 3844531327UL, 1880989003UL, 3861138803UL, 1322409081UL, 889237383UL, 3272848161UL, 3397816882UL, 2309900530UL, +3505447982UL, 3430136873UL, 1319796589UL, 4202423979UL, 3184732284UL, 2910356648UL, 2534615223UL, 3854465731UL, 768821792UL, 2205052576UL, 1348983754UL, 1300250188UL, 2919181738UL, 2520178732UL, 3967243685UL, 2646012002UL, 1784678658UL, 741302051UL, 3464753547UL, 194213376UL, 1482799064UL, 3009673860UL, 680824208UL, 741966796UL, 2381283369UL, 3022877171UL, 1619439814UL, 3961433610UL, 1331297670UL, 1100110820UL, 1311672539UL, 1122110615UL, +4056004850UL, 3413790176UL, 3148768822UL, 1242592694UL, 2925975727UL, 1879285134UL, 334328879UL, 1318235222UL, 3140739559UL, 401691770UL, 3604288404UL, 3686496908UL, 770670945UL, 199139043UL, 2092710473UL, 3914528993UL, 700991333UL, 2375775811UL, 858137308UL, 3490050165UL, 2389078291UL, 1615607459UL, 3027969809UL, 820012549UL, 2085659484UL, 2654485136UL, 2630408646UL, 196481396UL, 1119673274UL, 1026209692UL, 726501622UL, 2940737143UL, +3559571163UL, 2288027726UL, 1039212708UL, 929664536UL, 1061981465UL, 186058675UL, 3537656152UL, 844176796UL, 2996217992UL, 1545798611UL, 3031020656UL, 2248030435UL, 1665857580UL, 2905758082UL, 1269201312UL, 3031275084UL, 4034872841UL, 983632400UL, 4188503190UL, 757119675UL, 2105920865UL, 4281032819UL, 2917801076UL, 3900010013UL, 3910997169UL, 1729751422UL, 562313247UL, 3070846353UL, 2564238664UL, 4050540186UL, 4258833501UL, 2270666053UL, +2207128401UL, 2990540001UL, 797768898UL, 2288390225UL, 3230323685UL, 1974727440UL, 3327301426UL, 289857826UL, 3565889868UL, 2791014422UL, 2021097820UL, 3350378271UL, 3673707591UL, 2610067927UL, 4255789547UL, 2682856590UL, 12563128UL, 1397542366UL, 237149400UL, 2233707508UL, 3875573245UL, 2097374144UL, 175320773UL, 4103445984UL, 4089284323UL, 3610168130UL, 3084915964UL, 680145366UL, 2571684685UL, 1132894909UL, 104640024UL, 193765521UL, +2338202907UL, 895271448UL, 11499099UL, 1798066417UL, 1297412626UL, 2511347162UL, 3140535007UL, 2129963538UL, 700683199UL, 2609700278UL, 2953463279UL, 2290844145UL, 1871316353UL, 3993801787UL, 2219413182UL, 2954453701UL, 231283580UL, 1375331115UL, 207723994UL, 1799562537UL, 2056553564UL, 2513609799UL, 3542459627UL, 3173012714UL, 3923404932UL, 217877755UL, 2095124912UL, 192024370UL, 1168134987UL, 1889598668UL, 3014873069UL, 2033573343UL, +}, +{ +3465348660UL, 3623545008UL, 3505902593UL, 838034830UL, 1338018789UL, 2595329276UL, 3367746385UL, 3197935201UL, 1439351946UL, 3585085571UL, 4165798087UL, 3634792639UL, 2359485974UL, 2772582925UL, 1110186203UL, 3771562484UL, 1508694157UL, 1564641206UL, 2801985736UL, 2446107936UL, 3849126897UL, 1842973671UL, 944408104UL, 2624631280UL, 2729080685UL, 3737368614UL, 858809173UL, 2289802345UL, 2428186575UL, 3114742765UL, 716011303UL, 3443810690UL, +814132610UL, 517432787UL, 614445393UL, 2930433345UL, 291178098UL, 2117644502UL, 2749446703UL, 311745701UL, 365684723UL, 1705418876UL, 2213749318UL, 4011417220UL, 1842575651UL, 988348831UL, 94258998UL, 2771150272UL, 498058526UL, 1344827813UL, 2961955291UL, 262703473UL, 1404034822UL, 1566595865UL, 2522381203UL, 1706522206UL, 1203054806UL, 1273801539UL, 2070583465UL, 3913449936UL, 3231505231UL, 619636751UL, 3746997351UL, 4103027837UL, +1205468203UL, 3355878253UL, 3433356888UL, 107785753UL, 2779092609UL, 1869691566UL, 2555219983UL, 903319808UL, 3273374169UL, 2538926990UL, 979533870UL, 1356500860UL, 1661983738UL, 1380761625UL, 2919458459UL, 1041142798UL, 1430817627UL, 517007606UL, 1421570516UL, 2371447300UL, 2985632691UL, 3684889351UL, 3873926653UL, 788770697UL, 1854750277UL, 209332297UL, 1137299679UL, 848527832UL, 3850486924UL, 4179307312UL, 2764470693UL, 1353191605UL, +4166891919UL, 2074703841UL, 3373997532UL, 2013528640UL, 701389744UL, 841917592UL, 2065742268UL, 2721848192UL, 2566956680UL, 3122896007UL, 1090761479UL, 921859028UL, 4086736376UL, 1837462309UL, 2579826431UL, 2436217134UL, 839037727UL, 1072086642UL, 614518622UL, 3764758228UL, 1501128342UL, 3669108708UL, 1601407381UL, 2899014005UL, 3268308948UL, 3337564231UL, 1986911578UL, 3379194930UL, 1950365753UL, 2098537451UL, 51515980UL, 1176526086UL, +3213391582UL, 1059745735UL, 2273586703UL, 376085505UL, 1493749800UL, 3970342143UL, 1620925244UL, 2165301314UL, 2332030190UL, 1864098798UL, 276747442UL, 2776569227UL, 2992780663UL, 3027279789UL, 1074555384UL, 3481518659UL, 2499703783UL, 661805703UL, 3782305562UL, 9186074UL, 2357407210UL, 2355922343UL, 2024733363UL, 485434612UL, 862379913UL, 1029706268UL, 1512726310UL, 3834948354UL, 1435892840UL, 3297980694UL, 2831553800UL, 2111416471UL, +711321697UL, 3465348660UL, 3623545008UL, 3505902593UL, 838034830UL, 1553436793UL, 2595329276UL, 3367746385UL, 3197935201UL, 1439351946UL, 3198044157UL, 4165798087UL, 3634792639UL, 2359485974UL, 2772582925UL, 836042976UL, 3771562484UL, 1508694157UL, 1564641206UL, 2801985736UL, 1190371491UL, 3849126897UL, 1842973671UL, 944408104UL, 2624631280UL, 410746791UL, 3737368614UL, 858809173UL, 2289802345UL, 2428186575UL, 1542325976UL, 716011303UL, +3443810690UL, 814132610UL, 517432787UL, 1649301063UL, 2930433345UL, 291178098UL, 2117644502UL, 2749446703UL, 3955511579UL, 365684723UL, 1705418876UL, 2213749318UL, 4011417220UL, 2753632862UL, 988348831UL, 94258998UL, 2771150272UL, 498058526UL, 3314106168UL, 2961955291UL, 262703473UL, 1404034822UL, 1566595865UL, 3590367097UL, 1706522206UL, 1203054806UL, 1273801539UL, 2070583465UL, 2340683261UL, 3231505231UL, 619636751UL, 3746997351UL, +4103027837UL, 2785398766UL, 3355878253UL, 3433356888UL, 107785753UL, 2779092609UL, 1608451840UL, 2555219983UL, 903319808UL, 3273374169UL, 2538926990UL, 645164419UL, 1356500860UL, 1661983738UL, 1380761625UL, 2919458459UL, 2260224548UL, 1430817627UL, 517007606UL, 1421570516UL, 2371447300UL, 1636004496UL, 3684889351UL, 3873926653UL, 788770697UL, 1854750277UL, 1345251011UL, 1137299679UL, 848527832UL, 3850486924UL, 4179307312UL, 3576574608UL, +1353191605UL, 4166891919UL, 2074703841UL, 3373997532UL, 183447754UL, 701389744UL, 841917592UL, 2065742268UL, 2721848192UL, 2109289891UL, 3122896007UL, 1090761479UL, 921859028UL, 4086736376UL, 2212730874UL, 2579826431UL, 2436217134UL, 839037727UL, 1072086642UL, 55934784UL, 3764758228UL, 1501128342UL, 3669108708UL, 1601407381UL, 516550987UL, 3268308948UL, 3337564231UL, 1986911578UL, 3379194930UL, 3973484473UL, 2098537451UL, 51515980UL, +1176526086UL, 3213391582UL, 4251661633UL, 2273586703UL, 376085505UL, 1493749800UL, 3970342143UL, 3190791788UL, 2165301314UL, 2332030190UL, 1864098798UL, 276747442UL, 2991976613UL, 2992780663UL, 3027279789UL, 1074555384UL, 3481518659UL, 1399789494UL, 661805703UL, 3782305562UL, 9186074UL, 2357407210UL, 1942736967UL, 2024733363UL, 485434612UL, 862379913UL, 1029706268UL, 4122704494UL, 3834948354UL, 1435892840UL, 3297980694UL, 2831553800UL, +1210092654UL, 711321697UL, 3465348660UL, 3623545008UL, 3505902593UL, 3443231198UL, 1553436793UL, 2595329276UL, 3367746385UL, 3197935201UL, 1304974987UL, 3198044157UL, 4165798087UL, 3634792639UL, 2359485974UL, 3518323362UL, 836042976UL, 3771562484UL, 1508694157UL, 1564641206UL, 3577633375UL, 1190371491UL, 3849126897UL, 1842973671UL, 944408104UL, 1854555112UL, 410746791UL, 3737368614UL, 858809173UL, 2289802345UL, 3622671731UL, 1542325976UL, +716011303UL, 3443810690UL, 814132610UL, 296197011UL, 1649301063UL, 2930433345UL, 291178098UL, 2117644502UL, 1056271538UL, 3955511579UL, 365684723UL, 1705418876UL, 2213749318UL, 1258535671UL, 2753632862UL, 988348831UL, 94258998UL, 2771150272UL, 3669902097UL, 3314106168UL, 2961955291UL, 262703473UL, 1404034822UL, 1654433938UL, 3590367097UL, 1706522206UL, 1203054806UL, 1273801539UL, 2448138887UL, 2340683261UL, 3231505231UL, 619636751UL, +3746997351UL, 1454088394UL, 2785398766UL, 3355878253UL, 3433356888UL, 107785753UL, 689323470UL, 1608451840UL, 2555219983UL, 903319808UL, 3273374169UL, 1603842392UL, 645164419UL, 1356500860UL, 1661983738UL, 1380761625UL, 2814639423UL, 2260224548UL, 1430817627UL, 517007606UL, 1421570516UL, 1938805701UL, 1636004496UL, 3684889351UL, 3873926653UL, 788770697UL, 4238900666UL, 1345251011UL, 1137299679UL, 848527832UL, 3850486924UL, 108793827UL, +3576574608UL, 1353191605UL, 4166891919UL, 2074703841UL, 3780897861UL, 183447754UL, 701389744UL, 841917592UL, 2065742268UL, 3036602746UL, 2109289891UL, 3122896007UL, 1090761479UL, 921859028UL, 3499985398UL, 2212730874UL, 2579826431UL, 2436217134UL, 839037727UL, 3520354700UL, 55934784UL, 3764758228UL, 1501128342UL, 3669108708UL, 1601010847UL, 516550987UL, 3268308948UL, 3337564231UL, 1986911578UL, 2704241781UL, 3973484473UL, 2098537451UL, +51515980UL, 1176526086UL, 3602010532UL, 4251661633UL, 2273586703UL, 376085505UL, 1493749800UL, 2922957328UL, 3190791788UL, 2165301314UL, 2332030190UL, 1864098798UL, 1649666443UL, 2991976613UL, 2992780663UL, 3027279789UL, 1074555384UL, 2848531519UL, 1399789494UL, 661805703UL, 3782305562UL, 9186074UL, 320781315UL, 1942736967UL, 2024733363UL, 485434612UL, 862379913UL, 3598892066UL, 4122704494UL, 3834948354UL, 1435892840UL, 3297980694UL, +545184652UL, 1210092654UL, 711321697UL, 3465348660UL, 3623545008UL, 1173753045UL, 3443231198UL, 1553436793UL, 2595329276UL, 3367746385UL, 2444634476UL, 1304974987UL, 3198044157UL, 4165798087UL, 3634792639UL, 1837035806UL, 3518323362UL, 836042976UL, 3771562484UL, 1508694157UL, 2899021294UL, 3577633375UL, 1190371491UL, 3849126897UL, 1842973671UL, 1614215215UL, 1854555112UL, 410746791UL, 3737368614UL, 858809173UL, 525745365UL, 3622671731UL, +1542325976UL, 716011303UL, 3443810690UL, 566299749UL, 296197011UL, 1649301063UL, 2930433345UL, 291178098UL, 1987532525UL, 1056271538UL, 3955511579UL, 365684723UL, 1705418876UL, 2321222760UL, 1258535671UL, 2753632862UL, 988348831UL, 94258998UL, 2986060366UL, 3669902097UL, 3314106168UL, 2961955291UL, 262703473UL, 604452796UL, 1654433938UL, 3590367097UL, 1706522206UL, 1203054806UL, 1894894069UL, 2448138887UL, 2340683261UL, 3231505231UL, +619636751UL, 6680729UL, 1454088394UL, 2785398766UL, 3355878253UL, 3433356888UL, 2025591660UL, 689323470UL, 1608451840UL, 2555219983UL, 903319808UL, 3430384385UL, 1603842392UL, 645164419UL, 1356500860UL, 1661983738UL, 2108736152UL, 2814639423UL, 2260224548UL, 1430817627UL, 517007606UL, 2973658959UL, 1938805701UL, 1636004496UL, 3684889351UL, 3873926653UL, 2283691941UL, 4238900666UL, 1345251011UL, 1137299679UL, 848527832UL, 45551112UL, +108793827UL, 3576574608UL, 1353191605UL, 4166891919UL, 3776615962UL, 3780897861UL, 183447754UL, 701389744UL, 841917592UL, 3830639316UL, 3036602746UL, 2109289891UL, 3122896007UL, 1090761479UL, 1931255897UL, 3499985398UL, 2212730874UL, 2579826431UL, 2436217134UL, 3272166055UL, 3520354700UL, 55934784UL, 3764758228UL, 1501128342UL, 1567864246UL, 1601010847UL, 516550987UL, 3268308948UL, 3337564231UL, 3918802424UL, 2704241781UL, 3973484473UL, +2098537451UL, 51515980UL, 3551394489UL, 3602010532UL, 4251661633UL, 2273586703UL, 376085505UL, 885459498UL, 2922957328UL, 3190791788UL, 2165301314UL, 2332030190UL, 3197056515UL, 1649666443UL, 2991976613UL, 2992780663UL, 3027279789UL, 2385348906UL, 2848531519UL, 1399789494UL, 661805703UL, 3782305562UL, 2163075465UL, 320781315UL, 1942736967UL, 2024733363UL, 485434612UL, 2680597981UL, 3598892066UL, 4122704494UL, 3834948354UL, 1435892840UL, +2499644163UL, 2704575422UL, 2579557838UL, 673530532UL, 493730767UL, 1124557747UL, 1908629439UL, 2821949504UL, 1743112513UL, 2849457841UL, 2344409314UL, 3479159262UL, 4260973770UL, 2991970754UL, 3812641863UL, 2229319917UL, 2466968521UL, 1766353737UL, 3216591612UL, 2113272648UL, 364370737UL, 1893001758UL, 2608875275UL, 4224057183UL, 3546705413UL, 1999778009UL, 348872225UL, 2470564216UL, 1417878284UL, 2709790112UL, 3579129936UL, 2137971615UL, +4046639861UL, 2841156930UL, 391544737UL, 2056567354UL, 737657378UL, 3877904725UL, 578930752UL, 1759172471UL, 3383278785UL, 1047197514UL, 649468151UL, 3452867243UL, 1792089520UL, 63936215UL, 3909143729UL, 3753489875UL, 734314122UL, 2490530916UL, 3043874586UL, 1504812057UL, 59001199UL, 2493748676UL, 2552438622UL, 1889694845UL, 3715397860UL, 2817245010UL, 3841049206UL, 816106718UL, 2176130406UL, 640254735UL, 12376903UL, 3000264936UL, +3304116079UL, 1620334094UL, 2109391765UL, 1348210951UL, 2237645681UL, 1207768272UL, 1562894669UL, 2156631655UL, 1387193235UL, 3154858817UL, 633510901UL, 2312190757UL, 402878244UL, 2501565021UL, 2984409334UL, 4167491216UL, 3614267292UL, 3078552271UL, 971722322UL, 3065543880UL, 2307584190UL, 491480322UL, 2068673112UL, 1929780632UL, 178549964UL, 983979983UL, 2769314886UL, 4214442042UL, 2977609682UL, 25450683UL, 3075212658UL, 1571149568UL, +3531670561UL, 42782504UL, 425601306UL, 428715214UL, 497250251UL, 693520802UL, 166426814UL, 1786382125UL, 2712003995UL, 3610802197UL, 2076490757UL, 404822980UL, 3953184772UL, 1655231947UL, 3594351577UL, 3068232274UL, 3771730346UL, 4110519574UL, 3534704897UL, 2375277865UL, 3597780202UL, 3472676002UL, 1350276449UL, 3218248239UL, 3589255283UL, 3253132633UL, 1769885529UL, 3792812294UL, 120332643UL, 1219374788UL, 3608889019UL, 2386099811UL, +858495304UL, 1284785543UL, 331370962UL, 2259419662UL, 2519864134UL, 3194739432UL, 2669074511UL, 2565559140UL, 3378072004UL, 2647801475UL, 265068954UL, 1464416963UL, 1232787612UL, 4160089759UL, 2510685972UL, 670300081UL, 2509357766UL, 1981891975UL, 4161588397UL, 1371924626UL, 44760868UL, 634955171UL, 1187096933UL, 3324788972UL, 3576888559UL, 2801347752UL, 3730298395UL, 1702170762UL, 4206083415UL, 741409141UL, 3649731355UL, 1025429529UL, +}, +{ +91444490UL, 628576944UL, 4069219862UL, 2253058925UL, 492354082UL, 1191182242UL, 1565180119UL, 2257613723UL, 456055162UL, 605712223UL, 953365104UL, 3104638527UL, 1133984729UL, 2662828416UL, 2134948274UL, 1921384447UL, 843719355UL, 588432962UL, 1734575434UL, 2924140067UL, 483396548UL, 3848838894UL, 3155476556UL, 1760928304UL, 4168059840UL, 3279827269UL, 2644461735UL, 4168565656UL, 3951563569UL, 1276805504UL, 1708974143UL, 1878547888UL, +3465220024UL, 3062086782UL, 2801401651UL, 1510428126UL, 716404149UL, 1646021208UL, 3534932385UL, 1186585561UL, 651997355UL, 282914223UL, 352224857UL, 3764407517UL, 1059868753UL, 1971798134UL, 978904005UL, 976413661UL, 4039544152UL, 498989693UL, 2565125471UL, 2782642813UL, 3537961025UL, 1194967362UL, 169217024UL, 3491609UL, 1319592872UL, 1630206561UL, 2497130840UL, 1685008996UL, 2828944016UL, 3301346775UL, 2893072371UL, 2606559798UL, +4026138031UL, 2664450619UL, 691091062UL, 1079640113UL, 1417637732UL, 4081852209UL, 2197910648UL, 2310382370UL, 1000957047UL, 959936499UL, 2844551811UL, 2272766890UL, 31122394UL, 2742925483UL, 1121884686UL, 57929089UL, 2468361281UL, 2982007782UL, 2371576893UL, 177782593UL, 3603584577UL, 672057044UL, 2108452841UL, 1671338057UL, 3386908223UL, 1243029765UL, 805157552UL, 1271858417UL, 1621249501UL, 1804851492UL, 1321010403UL, 751773221UL, +1517221627UL, 822709871UL, 104533154UL, 3578182264UL, 640541709UL, 421086624UL, 4233576392UL, 3729339369UL, 197460644UL, 773140636UL, 2158026018UL, 1756785611UL, 4011575991UL, 3569445500UL, 736117181UL, 2456162322UL, 1168189787UL, 3651312675UL, 1070291988UL, 268231205UL, 541474497UL, 3316168972UL, 3546990856UL, 830417208UL, 725960194UL, 2044207227UL, 3188997938UL, 2383298579UL, 3350316374UL, 3575011225UL, 1553111865UL, 1285013027UL, +749371711UL, 766611716UL, 598195098UL, 2139882719UL, 2062405428UL, 3634702446UL, 3015263295UL, 223311969UL, 2622859522UL, 3888492701UL, 2955257225UL, 582625650UL, 3563756446UL, 2886083960UL, 1907546514UL, 454650902UL, 3287277541UL, 625828138UL, 2991888140UL, 1935326370UL, 4031152256UL, 702881509UL, 1427632724UL, 1345475301UL, 2577560804UL, 2858595147UL, 2533191188UL, 185662179UL, 536505093UL, 3747894147UL, 111551030UL, 370373207UL, +2293908590UL, 91444490UL, 628576944UL, 4069219862UL, 2253058925UL, 1671484924UL, 1191182242UL, 1565180119UL, 2257613723UL, 456055162UL, 3411094744UL, 953365104UL, 3104638527UL, 1133984729UL, 2662828416UL, 2000630022UL, 1921384447UL, 843719355UL, 588432962UL, 1734575434UL, 3293926122UL, 483396548UL, 3848838894UL, 3155476556UL, 1760928304UL, 146876953UL, 3279827269UL, 2644461735UL, 4168565656UL, 3951563569UL, 3976156700UL, 1708974143UL, +1878547888UL, 3465220024UL, 3062086782UL, 1999154400UL, 1510428126UL, 716404149UL, 1646021208UL, 3534932385UL, 2479551429UL, 651997355UL, 282914223UL, 352224857UL, 3764407517UL, 1275979651UL, 1971798134UL, 978904005UL, 976413661UL, 4039544152UL, 300654823UL, 2565125471UL, 2782642813UL, 3537961025UL, 1194967362UL, 3123973648UL, 3491609UL, 1319592872UL, 1630206561UL, 2497130840UL, 1437913158UL, 2828944016UL, 3301346775UL, 2893072371UL, +2606559798UL, 2153172585UL, 2664450619UL, 691091062UL, 1079640113UL, 1417637732UL, 17137237UL, 2197910648UL, 2310382370UL, 1000957047UL, 959936499UL, 802137134UL, 2272766890UL, 31122394UL, 2742925483UL, 1121884686UL, 3909775167UL, 2468361281UL, 2982007782UL, 2371576893UL, 177782593UL, 3319492525UL, 672057044UL, 2108452841UL, 1671338057UL, 3386908223UL, 1878151473UL, 805157552UL, 1271858417UL, 1621249501UL, 1804851492UL, 3215921223UL, +751773221UL, 1517221627UL, 822709871UL, 104533154UL, 361845001UL, 640541709UL, 421086624UL, 4233576392UL, 3729339369UL, 2655936801UL, 773140636UL, 2158026018UL, 1756785611UL, 4011575991UL, 587202971UL, 736117181UL, 2456162322UL, 1168189787UL, 3651312675UL, 2517883370UL, 268231205UL, 541474497UL, 3316168972UL, 3546990856UL, 2037251305UL, 725960194UL, 2044207227UL, 3188997938UL, 2383298579UL, 2665008587UL, 3575011225UL, 1553111865UL, +1285013027UL, 749371711UL, 2163964019UL, 598195098UL, 2139882719UL, 2062405428UL, 3634702446UL, 2788202059UL, 223311969UL, 2622859522UL, 3888492701UL, 2955257225UL, 740986174UL, 3563756446UL, 2886083960UL, 1907546514UL, 454650902UL, 2426323587UL, 625828138UL, 2991888140UL, 1935326370UL, 4031152256UL, 1831149435UL, 1427632724UL, 1345475301UL, 2577560804UL, 2858595147UL, 3977153945UL, 185662179UL, 536505093UL, 3747894147UL, 111551030UL, +4131587422UL, 2293908590UL, 91444490UL, 628576944UL, 4069219862UL, 2408189350UL, 1671484924UL, 1191182242UL, 1565180119UL, 2257613723UL, 1338069254UL, 3411094744UL, 953365104UL, 3104638527UL, 1133984729UL, 631497759UL, 2000630022UL, 1921384447UL, 843719355UL, 588432962UL, 3280318959UL, 3293926122UL, 483396548UL, 3848838894UL, 3155476556UL, 1777918163UL, 146876953UL, 3279827269UL, 2644461735UL, 4168565656UL, 2786264663UL, 3976156700UL, +1708974143UL, 1878547888UL, 3465220024UL, 2793923820UL, 1999154400UL, 1510428126UL, 716404149UL, 1646021208UL, 3102243824UL, 2479551429UL, 651997355UL, 282914223UL, 352224857UL, 3767702588UL, 1275979651UL, 1971798134UL, 978904005UL, 976413661UL, 1951622548UL, 300654823UL, 2565125471UL, 2782642813UL, 3537961025UL, 2186817324UL, 3123973648UL, 3491609UL, 1319592872UL, 1630206561UL, 1075424534UL, 1437913158UL, 2828944016UL, 3301346775UL, +2893072371UL, 207992406UL, 2153172585UL, 2664450619UL, 691091062UL, 1079640113UL, 3114255216UL, 17137237UL, 2197910648UL, 2310382370UL, 1000957047UL, 2548008553UL, 802137134UL, 2272766890UL, 31122394UL, 2742925483UL, 4069482373UL, 3909775167UL, 2468361281UL, 2982007782UL, 2371576893UL, 2807823912UL, 3319492525UL, 672057044UL, 2108452841UL, 1671338057UL, 12831353UL, 1878151473UL, 805157552UL, 1271858417UL, 1621249501UL, 461887094UL, +3215921223UL, 751773221UL, 1517221627UL, 822709871UL, 1317394918UL, 361845001UL, 640541709UL, 421086624UL, 4233576392UL, 3385587450UL, 2655936801UL, 773140636UL, 2158026018UL, 1756785611UL, 1475601973UL, 587202971UL, 736117181UL, 2456162322UL, 1168189787UL, 911455077UL, 2517883370UL, 268231205UL, 541474497UL, 3316168972UL, 1500275507UL, 2037251305UL, 725960194UL, 2044207227UL, 3188997938UL, 2036633808UL, 2665008587UL, 3575011225UL, +1553111865UL, 1285013027UL, 87868216UL, 2163964019UL, 598195098UL, 2139882719UL, 2062405428UL, 517907301UL, 2788202059UL, 223311969UL, 2622859522UL, 3888492701UL, 3926046234UL, 740986174UL, 3563756446UL, 2886083960UL, 1907546514UL, 1911066215UL, 2426323587UL, 625828138UL, 2991888140UL, 1935326370UL, 2031853435UL, 1831149435UL, 1427632724UL, 1345475301UL, 2577560804UL, 3509674153UL, 3977153945UL, 185662179UL, 536505093UL, 3747894147UL, +1711714600UL, 4131587422UL, 2293908590UL, 91444490UL, 628576944UL, 3370678255UL, 2408189350UL, 1671484924UL, 1191182242UL, 1565180119UL, 3786239592UL, 1338069254UL, 3411094744UL, 953365104UL, 3104638527UL, 3659647225UL, 631497759UL, 2000630022UL, 1921384447UL, 843719355UL, 3364831282UL, 3280318959UL, 3293926122UL, 483396548UL, 3848838894UL, 3131266478UL, 1777918163UL, 146876953UL, 3279827269UL, 2644461735UL, 4156372383UL, 2786264663UL, +3976156700UL, 1708974143UL, 1878547888UL, 2168041590UL, 2793923820UL, 1999154400UL, 1510428126UL, 716404149UL, 3392113666UL, 3102243824UL, 2479551429UL, 651997355UL, 282914223UL, 2085613514UL, 3767702588UL, 1275979651UL, 1971798134UL, 978904005UL, 503506384UL, 1951622548UL, 300654823UL, 2565125471UL, 2782642813UL, 1458431750UL, 2186817324UL, 3123973648UL, 3491609UL, 1319592872UL, 452433679UL, 1075424534UL, 1437913158UL, 2828944016UL, +3301346775UL, 2333281307UL, 207992406UL, 2153172585UL, 2664450619UL, 691091062UL, 3553502652UL, 3114255216UL, 17137237UL, 2197910648UL, 2310382370UL, 3153689868UL, 2548008553UL, 802137134UL, 2272766890UL, 31122394UL, 468580641UL, 4069482373UL, 3909775167UL, 2468361281UL, 2982007782UL, 1445286890UL, 2807823912UL, 3319492525UL, 672057044UL, 2108452841UL, 1755577669UL, 12831353UL, 1878151473UL, 805157552UL, 1271858417UL, 2623540912UL, +461887094UL, 3215921223UL, 751773221UL, 1517221627UL, 3922191946UL, 1317394918UL, 361845001UL, 640541709UL, 421086624UL, 2173849516UL, 3385587450UL, 2655936801UL, 773140636UL, 2158026018UL, 1085377158UL, 1475601973UL, 587202971UL, 736117181UL, 2456162322UL, 2158960374UL, 911455077UL, 2517883370UL, 268231205UL, 541474497UL, 943191315UL, 1500275507UL, 2037251305UL, 725960194UL, 2044207227UL, 2481150802UL, 2036633808UL, 2665008587UL, +3575011225UL, 1553111865UL, 2301231777UL, 87868216UL, 2163964019UL, 598195098UL, 2139882719UL, 2007840238UL, 517907301UL, 2788202059UL, 223311969UL, 2622859522UL, 151920263UL, 3926046234UL, 740986174UL, 3563756446UL, 2886083960UL, 1338937928UL, 1911066215UL, 2426323587UL, 625828138UL, 2991888140UL, 2652286195UL, 2031853435UL, 1831149435UL, 1427632724UL, 1345475301UL, 289801789UL, 3509674153UL, 3977153945UL, 185662179UL, 536505093UL, +2727322952UL, 3980498348UL, 2529622213UL, 1903052964UL, 3564714651UL, 2281240568UL, 533384122UL, 277613480UL, 1815540358UL, 282763841UL, 3669112623UL, 2572859425UL, 195220178UL, 1210883545UL, 2359703600UL, 1187537824UL, 675732974UL, 325036095UL, 708091465UL, 2556854604UL, 701006284UL, 2378459191UL, 1863513103UL, 2690918197UL, 4237307694UL, 1356483501UL, 2160905652UL, 521809106UL, 974368613UL, 3136010957UL, 2722488678UL, 3711515637UL, +2296341459UL, 4233729945UL, 1196247571UL, 3031398071UL, 515543502UL, 1314129776UL, 3235373306UL, 1303165859UL, 1820568009UL, 559099351UL, 186876368UL, 1076102111UL, 1218809551UL, 1790301111UL, 4130210229UL, 768125358UL, 1132864749UL, 4262563773UL, 2294411020UL, 4092943985UL, 2558108246UL, 3737664949UL, 2219923393UL, 724326159UL, 4134105682UL, 4188752746UL, 3615233671UL, 1526018731UL, 2281637916UL, 2459490295UL, 3637342666UL, 777862587UL, +39962002UL, 3772005832UL, 997473319UL, 574843584UL, 3356551974UL, 1265234427UL, 1698059437UL, 534747571UL, 1465532164UL, 3263029035UL, 534512444UL, 2343092827UL, 2375685652UL, 2497926141UL, 2377933621UL, 2212335180UL, 261114084UL, 172755755UL, 2737085495UL, 2225257145UL, 148605658UL, 1353911796UL, 357753009UL, 1778732943UL, 497635558UL, 4136467976UL, 2837964962UL, 4045039047UL, 2485296762UL, 1587587183UL, 4042904168UL, 3184240963UL, +2393293696UL, 915444966UL, 2299938515UL, 3351580749UL, 506575598UL, 1541916825UL, 3465300401UL, 525927458UL, 681152801UL, 331660975UL, 3624685846UL, 2994172100UL, 3274369082UL, 3638287602UL, 815689760UL, 1710961092UL, 2775607076UL, 2175058103UL, 3252688367UL, 2936890483UL, 2746319120UL, 2736754UL, 1646031035UL, 2448701214UL, 2886833213UL, 3689830606UL, 3292798106UL, 300773646UL, 3125160783UL, 1247453205UL, 2746275624UL, 4011063775UL, +904135764UL, 876847374UL, 366267234UL, 2541269205UL, 131376648UL, 1805948133UL, 3383589530UL, 2350119829UL, 2513170439UL, 4096158499UL, 4229211520UL, 2992048272UL, 1338522080UL, 1187391335UL, 2898563453UL, 2163088451UL, 1417971677UL, 2047421551UL, 902282791UL, 1143943232UL, 3568431811UL, 4059861993UL, 193362198UL, 2509297125UL, 3968551582UL, 2175686117UL, 3568936881UL, 1853177468UL, 2134063169UL, 2919389416UL, 1124914545UL, 1209806738UL, +}, +{ +1199972651UL, 1035834631UL, 3177798370UL, 860834162UL, 3741677748UL, 3780327829UL, 1693730265UL, 1643429511UL, 559568669UL, 2758650294UL, 647308222UL, 3901603996UL, 1778653821UL, 3618523672UL, 2154201067UL, 4261179460UL, 3285764480UL, 3334002738UL, 3215795953UL, 91368462UL, 1883994950UL, 1506873376UL, 1527780962UL, 4046354597UL, 4081676034UL, 2389066602UL, 1574939945UL, 427845396UL, 2714836263UL, 1259019491UL, 2493238133UL, 2584034689UL, +3151382431UL, 2171033919UL, 176883719UL, 2031844862UL, 1272380790UL, 1298975901UL, 4087222847UL, 1524000054UL, 311436877UL, 3627785554UL, 1889491722UL, 2938069193UL, 2771940687UL, 2756955968UL, 4289348777UL, 263514583UL, 887207028UL, 3522902525UL, 2273246349UL, 835377715UL, 2897243319UL, 204645450UL, 1775911983UL, 639470242UL, 2856296318UL, 3032942383UL, 2845501282UL, 1979082575UL, 202834023UL, 1876303820UL, 1434703409UL, 4240524132UL, +848853780UL, 4188621628UL, 928095314UL, 876412914UL, 3446576392UL, 3235688990UL, 4021419931UL, 2483628986UL, 3155781890UL, 399997246UL, 1642535200UL, 3872575068UL, 1577956550UL, 3606228634UL, 609914462UL, 653194726UL, 4048067248UL, 2500767965UL, 1125167825UL, 3707628088UL, 1819135158UL, 1875618971UL, 3865851141UL, 328215079UL, 1695889194UL, 2040280471UL, 3384684457UL, 2540504961UL, 293050253UL, 525570078UL, 2655676443UL, 1392199429UL, +3370444585UL, 1937915855UL, 2229636250UL, 247937142UL, 2534538765UL, 365841057UL, 2449431033UL, 2456532429UL, 101910696UL, 1247069485UL, 1523958293UL, 2473285670UL, 473709728UL, 3026667113UL, 2071968844UL, 324025193UL, 423064436UL, 3870800061UL, 3977393138UL, 3632553233UL, 352757977UL, 1584833348UL, 3173248650UL, 1159857686UL, 1501841977UL, 1751860798UL, 617281070UL, 1958012761UL, 4031667102UL, 3232142321UL, 3087428595UL, 2380824676UL, +1194087757UL, 1542961747UL, 4163350364UL, 1721646249UL, 1672791861UL, 2900511710UL, 24973500UL, 1705444176UL, 713642505UL, 3017719513UL, 2090715200UL, 3521434070UL, 37117223UL, 1948295454UL, 3055840561UL, 3476120789UL, 3994249388UL, 527899063UL, 4285770666UL, 1075524023UL, 2594223535UL, 392943522UL, 171012646UL, 3515750082UL, 3414659054UL, 3501852926UL, 1493283737UL, 2662104279UL, 2033464928UL, 90134967UL, 363058647UL, 3289266998UL, +2470752727UL, 1199972651UL, 1035834631UL, 3177798370UL, 860834162UL, 1791097822UL, 3780327829UL, 1693730265UL, 1643429511UL, 559568669UL, 3503319486UL, 647308222UL, 3901603996UL, 1778653821UL, 3618523672UL, 4294594427UL, 4261179460UL, 3285764480UL, 3334002738UL, 3215795953UL, 212518363UL, 1883994950UL, 1506873376UL, 1527780962UL, 4046354597UL, 2398655600UL, 2389066602UL, 1574939945UL, 427845396UL, 2714836263UL, 2744363872UL, 2493238133UL, +2584034689UL, 3151382431UL, 2171033919UL, 2787053497UL, 2031844862UL, 1272380790UL, 1298975901UL, 4087222847UL, 2342953154UL, 311436877UL, 3627785554UL, 1889491722UL, 2938069193UL, 2026656505UL, 2756955968UL, 4289348777UL, 263514583UL, 887207028UL, 2097276163UL, 2273246349UL, 835377715UL, 2897243319UL, 204645450UL, 4233399907UL, 639470242UL, 2856296318UL, 3032942383UL, 2845501282UL, 28260330UL, 202834023UL, 1876303820UL, 1434703409UL, +4240524132UL, 2455670466UL, 4188621628UL, 928095314UL, 876412914UL, 3446576392UL, 117581687UL, 4021419931UL, 2483628986UL, 3155781890UL, 399997246UL, 4254101087UL, 3872575068UL, 1577956550UL, 3606228634UL, 609914462UL, 4003279048UL, 4048067248UL, 2500767965UL, 1125167825UL, 3707628088UL, 922020515UL, 1875618971UL, 3865851141UL, 328215079UL, 1695889194UL, 625773097UL, 3384684457UL, 2540504961UL, 293050253UL, 525570078UL, 2592805114UL, +1392199429UL, 3370444585UL, 1937915855UL, 2229636250UL, 3190958614UL, 2534538765UL, 365841057UL, 2449431033UL, 2456532429UL, 3778669305UL, 1247069485UL, 1523958293UL, 2473285670UL, 473709728UL, 720895889UL, 2071968844UL, 324025193UL, 423064436UL, 3870800061UL, 3535536111UL, 3632553233UL, 352757977UL, 1584833348UL, 3173248650UL, 2649344603UL, 1501841977UL, 1751860798UL, 617281070UL, 1958012761UL, 778965559UL, 3232142321UL, 3087428595UL, +2380824676UL, 1194087757UL, 3880222002UL, 4163350364UL, 1721646249UL, 1672791861UL, 2900511710UL, 702936770UL, 1705444176UL, 713642505UL, 3017719513UL, 2090715200UL, 1477858694UL, 37117223UL, 1948295454UL, 3055840561UL, 3476120789UL, 464173532UL, 527899063UL, 4285770666UL, 1075524023UL, 2594223535UL, 2872629966UL, 171012646UL, 3515750082UL, 3414659054UL, 3501852926UL, 1631555059UL, 2662104279UL, 2033464928UL, 90134967UL, 363058647UL, +4112991722UL, 2470752727UL, 1199972651UL, 1035834631UL, 3177798370UL, 4152098951UL, 1791097822UL, 3780327829UL, 1693730265UL, 1643429511UL, 153020604UL, 3503319486UL, 647308222UL, 3901603996UL, 1778653821UL, 221887019UL, 4294594427UL, 4261179460UL, 3285764480UL, 3334002738UL, 3340918862UL, 212518363UL, 1883994950UL, 1506873376UL, 1527780962UL, 430180116UL, 2398655600UL, 2389066602UL, 1574939945UL, 427845396UL, 1683639957UL, 2744363872UL, +2493238133UL, 2584034689UL, 3151382431UL, 752704472UL, 2787053497UL, 2031844862UL, 1272380790UL, 1298975901UL, 1528220628UL, 2342953154UL, 311436877UL, 3627785554UL, 1889491722UL, 2576495467UL, 2026656505UL, 2756955968UL, 4289348777UL, 263514583UL, 3778019638UL, 2097276163UL, 2273246349UL, 835377715UL, 2897243319UL, 1060067446UL, 4233399907UL, 639470242UL, 2856296318UL, 3032942383UL, 2351047932UL, 28260330UL, 202834023UL, 1876303820UL, +1434703409UL, 3094305336UL, 2455670466UL, 4188621628UL, 928095314UL, 876412914UL, 3785385583UL, 117581687UL, 4021419931UL, 2483628986UL, 3155781890UL, 1867816730UL, 4254101087UL, 3872575068UL, 1577956550UL, 3606228634UL, 3081878598UL, 4003279048UL, 4048067248UL, 2500767965UL, 1125167825UL, 928465955UL, 922020515UL, 1875618971UL, 3865851141UL, 328215079UL, 173810260UL, 625773097UL, 3384684457UL, 2540504961UL, 293050253UL, 2645143254UL, +2592805114UL, 1392199429UL, 3370444585UL, 1937915855UL, 162781360UL, 3190958614UL, 2534538765UL, 365841057UL, 2449431033UL, 3105377832UL, 3778669305UL, 1247069485UL, 1523958293UL, 2473285670UL, 800971948UL, 720895889UL, 2071968844UL, 324025193UL, 423064436UL, 52577992UL, 3535536111UL, 3632553233UL, 352757977UL, 1584833348UL, 3305908059UL, 2649344603UL, 1501841977UL, 1751860798UL, 617281070UL, 264880505UL, 778965559UL, 3232142321UL, +3087428595UL, 2380824676UL, 1127761012UL, 3880222002UL, 4163350364UL, 1721646249UL, 1672791861UL, 2368512339UL, 702936770UL, 1705444176UL, 713642505UL, 3017719513UL, 197200752UL, 1477858694UL, 37117223UL, 1948295454UL, 3055840561UL, 1588372042UL, 464173532UL, 527899063UL, 4285770666UL, 1075524023UL, 2124039914UL, 2872629966UL, 171012646UL, 3515750082UL, 3414659054UL, 818571456UL, 1631555059UL, 2662104279UL, 2033464928UL, 90134967UL, +952712086UL, 4112991722UL, 2470752727UL, 1199972651UL, 1035834631UL, 888975816UL, 4152098951UL, 1791097822UL, 3780327829UL, 1693730265UL, 3406785510UL, 153020604UL, 3503319486UL, 647308222UL, 3901603996UL, 3753248472UL, 221887019UL, 4294594427UL, 4261179460UL, 3285764480UL, 1861431346UL, 3340918862UL, 212518363UL, 1883994950UL, 1506873376UL, 2695939612UL, 430180116UL, 2398655600UL, 2389066602UL, 1574939945UL, 2852159074UL, 1683639957UL, +2744363872UL, 2493238133UL, 2584034689UL, 1952065633UL, 752704472UL, 2787053497UL, 2031844862UL, 1272380790UL, 3530505866UL, 1528220628UL, 2342953154UL, 311436877UL, 3627785554UL, 3410473245UL, 2576495467UL, 2026656505UL, 2756955968UL, 4289348777UL, 2856163034UL, 3778019638UL, 2097276163UL, 2273246349UL, 835377715UL, 3127280755UL, 1060067446UL, 4233399907UL, 639470242UL, 2856296318UL, 2615775011UL, 2351047932UL, 28260330UL, 202834023UL, +1876303820UL, 619308202UL, 3094305336UL, 2455670466UL, 4188621628UL, 928095314UL, 3764894047UL, 3785385583UL, 117581687UL, 4021419931UL, 2483628986UL, 3759839215UL, 1867816730UL, 4254101087UL, 3872575068UL, 1577956550UL, 1687107439UL, 3081878598UL, 4003279048UL, 4048067248UL, 2500767965UL, 2804044146UL, 928465955UL, 922020515UL, 1875618971UL, 3865851141UL, 2359176389UL, 173810260UL, 625773097UL, 3384684457UL, 2540504961UL, 3665420733UL, +2645143254UL, 2592805114UL, 1392199429UL, 3370444585UL, 1604709429UL, 162781360UL, 3190958614UL, 2534538765UL, 365841057UL, 3843585067UL, 3105377832UL, 3778669305UL, 1247069485UL, 1523958293UL, 293374051UL, 800971948UL, 720895889UL, 2071968844UL, 324025193UL, 3342361801UL, 52577992UL, 3535536111UL, 3632553233UL, 352757977UL, 1386594581UL, 3305908059UL, 2649344603UL, 1501841977UL, 1751860798UL, 3160423601UL, 264880505UL, 778965559UL, +3232142321UL, 3087428595UL, 3814775120UL, 1127761012UL, 3880222002UL, 4163350364UL, 1721646249UL, 3640773034UL, 2368512339UL, 702936770UL, 1705444176UL, 713642505UL, 1717761787UL, 197200752UL, 1477858694UL, 37117223UL, 1948295454UL, 896215772UL, 1588372042UL, 464173532UL, 527899063UL, 4285770666UL, 3441409029UL, 2124039914UL, 2872629966UL, 171012646UL, 3515750082UL, 2216687886UL, 818571456UL, 1631555059UL, 2662104279UL, 2033464928UL, +369438400UL, 329003658UL, 1503365029UL, 4215790910UL, 3264377550UL, 733526983UL, 2935318632UL, 1792331479UL, 608347530UL, 392723097UL, 1330445854UL, 3473004271UL, 1267636682UL, 2150566972UL, 2664910943UL, 2591861637UL, 409769584UL, 2943326880UL, 3746302819UL, 3162268832UL, 1028663260UL, 3206607045UL, 832105292UL, 2119405275UL, 538318455UL, 2981192295UL, 861775416UL, 609718403UL, 3531204230UL, 1904759571UL, 1262633751UL, 2375133081UL, +460454984UL, 946700253UL, 3763898311UL, 1571175213UL, 3124410107UL, 2413420216UL, 2664177543UL, 3241803820UL, 3968067371UL, 1234860999UL, 1130471500UL, 772727786UL, 247203117UL, 576455235UL, 246297007UL, 2027348597UL, 764933887UL, 3812479771UL, 1825807084UL, 4072281412UL, 2156865781UL, 1286484847UL, 1966749063UL, 2479269303UL, 423506843UL, 3070938758UL, 653091413UL, 2267423132UL, 2004263526UL, 1374490719UL, 3871990628UL, 841138314UL, +1260317857UL, 3887432433UL, 4025147569UL, 764233331UL, 1794763428UL, 3005903468UL, 877926770UL, 2466593927UL, 2971729561UL, 3203070565UL, 4198500026UL, 815665759UL, 2434508139UL, 1840456368UL, 2279000427UL, 17077200UL, 3178380570UL, 990304199UL, 3578008580UL, 1965763660UL, 1640352477UL, 750159594UL, 2047409402UL, 3576308245UL, 544920564UL, 1730124869UL, 1194761386UL, 3280315505UL, 147334027UL, 2870674244UL, 2076860776UL, 1100947675UL, +2482772161UL, 401966468UL, 1610650855UL, 193868446UL, 3808157106UL, 1509130117UL, 1324484736UL, 3852893217UL, 1059179497UL, 4053543778UL, 2557844172UL, 3282312002UL, 682550058UL, 4281899173UL, 137171998UL, 3239159214UL, 2258610918UL, 426724741UL, 3502660993UL, 135977383UL, 429929363UL, 3984458137UL, 964026748UL, 2182019070UL, 3836562946UL, 515026869UL, 359030455UL, 1301694917UL, 2300414803UL, 2364654981UL, 3804876710UL, 171119249UL, +2646785698UL, 4283509387UL, 3628087763UL, 1748227044UL, 3037141234UL, 3000413256UL, 23007314UL, 3598880509UL, 4160517314UL, 112205578UL, 1677675411UL, 734881643UL, 2830770338UL, 3470317145UL, 3306806569UL, 2635040943UL, 2671367560UL, 3528996498UL, 3878886478UL, 3114253828UL, 2721384408UL, 3175226991UL, 1393767271UL, 2651623266UL, 3767978376UL, 1269699398UL, 1100964192UL, 4169085845UL, 2086718107UL, 1286251099UL, 764751784UL, 3006878591UL, +}, +{ +2565473087UL, 1149521056UL, 3529037691UL, 630435548UL, 73598765UL, 1467331930UL, 3988027050UL, 2771962200UL, 91261543UL, 980989218UL, 2227515435UL, 236831608UL, 2872772569UL, 2330469327UL, 1654035853UL, 2883791516UL, 4170143763UL, 126418114UL, 127789935UL, 2114249438UL, 2933346767UL, 639483386UL, 1532399845UL, 2182422151UL, 741069317UL, 2376371063UL, 3398508789UL, 3828295651UL, 3963199356UL, 4156483769UL, 4206759111UL, 1266176088UL, +3210273687UL, 432131993UL, 667709537UL, 874477513UL, 2304714957UL, 629309008UL, 116453438UL, 3051811727UL, 3490241985UL, 3355968243UL, 2304043871UL, 2724990029UL, 1095724699UL, 2408437363UL, 1433161037UL, 3245468546UL, 2494529842UL, 4204170637UL, 1966342448UL, 3092333073UL, 1861880941UL, 3990012367UL, 3710334908UL, 2526395471UL, 1884691351UL, 2145882162UL, 2561288457UL, 2253122309UL, 1154858044UL, 1643256991UL, 3172857504UL, 1096492713UL, +2848827103UL, 799826424UL, 3094672168UL, 3535834360UL, 4213256737UL, 1131757994UL, 520495112UL, 575315345UL, 3823364867UL, 2424349582UL, 3604795017UL, 310789314UL, 4207205257UL, 553462404UL, 2918228443UL, 2568360580UL, 3863565851UL, 874197736UL, 3329267685UL, 1186352580UL, 3928193054UL, 1780200631UL, 4088289456UL, 3323217870UL, 2758854947UL, 3111637417UL, 990374143UL, 2080149357UL, 4047813631UL, 2019887940UL, 578660736UL, 2145680301UL, +2328411541UL, 1572704242UL, 405739686UL, 1869350271UL, 2046317220UL, 4021497634UL, 1385163990UL, 1935250885UL, 1132987169UL, 581690993UL, 3172043012UL, 628071512UL, 2851125739UL, 2735324847UL, 2847267504UL, 3408334906UL, 3352976111UL, 706277272UL, 2971786942UL, 2811957324UL, 3578703606UL, 1126685543UL, 2671169997UL, 31952251UL, 2802110464UL, 2391618856UL, 3031260674UL, 1165714541UL, 2411388800UL, 2825634835UL, 101928462UL, 477629709UL, +4257022506UL, 3281706767UL, 2576087732UL, 736533968UL, 2543083137UL, 3430523686UL, 3272172013UL, 3056925798UL, 341993500UL, 406782950UL, 1770032304UL, 125786076UL, 1321359723UL, 2901696227UL, 1890958265UL, 3610842776UL, 1772227311UL, 1564088598UL, 914173231UL, 3734092059UL, 1652333721UL, 2386645282UL, 329706426UL, 1022239203UL, 1832393502UL, 4064995802UL, 3497852986UL, 1046436763UL, 366391010UL, 2237068647UL, 2887356463UL, 304718827UL, +3969799795UL, 2565473087UL, 1149521056UL, 3529037691UL, 630435548UL, 3758124054UL, 1467331930UL, 3988027050UL, 2771962200UL, 91261543UL, 836545831UL, 2227515435UL, 236831608UL, 2872772569UL, 2330469327UL, 3439193753UL, 2883791516UL, 4170143763UL, 126418114UL, 127789935UL, 1648940583UL, 2933346767UL, 639483386UL, 1532399845UL, 2182422151UL, 2470139222UL, 2376371063UL, 3398508789UL, 3828295651UL, 3963199356UL, 2997263135UL, 4206759111UL, +1266176088UL, 3210273687UL, 432131993UL, 2416600665UL, 874477513UL, 2304714957UL, 629309008UL, 116453438UL, 2586542760UL, 3490241985UL, 3355968243UL, 2304043871UL, 2724990029UL, 452934545UL, 2408437363UL, 1433161037UL, 3245468546UL, 2494529842UL, 2244403710UL, 1966342448UL, 3092333073UL, 1861880941UL, 3990012367UL, 2774994234UL, 2526395471UL, 1884691351UL, 2145882162UL, 2561288457UL, 2303702146UL, 1154858044UL, 1643256991UL, 3172857504UL, +1096492713UL, 130979316UL, 799826424UL, 3094672168UL, 3535834360UL, 4213256737UL, 935499492UL, 520495112UL, 575315345UL, 3823364867UL, 2424349582UL, 2272973265UL, 310789314UL, 4207205257UL, 553462404UL, 2918228443UL, 2613016888UL, 3863565851UL, 874197736UL, 3329267685UL, 1186352580UL, 4106984978UL, 1780200631UL, 4088289456UL, 3323217870UL, 2758854947UL, 1559861146UL, 990374143UL, 2080149357UL, 4047813631UL, 2019887940UL, 1133329900UL, +2145680301UL, 2328411541UL, 1572704242UL, 405739686UL, 63633520UL, 2046317220UL, 4021497634UL, 1385163990UL, 1935250885UL, 1762959503UL, 581690993UL, 3172043012UL, 628071512UL, 2851125739UL, 3726073981UL, 2847267504UL, 3408334906UL, 3352976111UL, 706277272UL, 3817450114UL, 2811957324UL, 3578703606UL, 1126685543UL, 2671169997UL, 2749086326UL, 2802110464UL, 2391618856UL, 3031260674UL, 1165714541UL, 2210258428UL, 2825634835UL, 101928462UL, +477629709UL, 4257022506UL, 2679409844UL, 2576087732UL, 736533968UL, 2543083137UL, 3430523686UL, 1122549807UL, 3056925798UL, 341993500UL, 406782950UL, 1770032304UL, 2617760292UL, 1321359723UL, 2901696227UL, 1890958265UL, 3610842776UL, 2666109620UL, 1564088598UL, 914173231UL, 3734092059UL, 1652333721UL, 3456779008UL, 329706426UL, 1022239203UL, 1832393502UL, 4064995802UL, 4006865520UL, 1046436763UL, 366391010UL, 2237068647UL, 2887356463UL, +1479646555UL, 3969799795UL, 2565473087UL, 1149521056UL, 3529037691UL, 2379195579UL, 3758124054UL, 1467331930UL, 3988027050UL, 2771962200UL, 1796797949UL, 836545831UL, 2227515435UL, 236831608UL, 2872772569UL, 544017308UL, 3439193753UL, 2883791516UL, 4170143763UL, 126418114UL, 3811390247UL, 1648940583UL, 2933346767UL, 639483386UL, 1532399845UL, 4165970043UL, 2470139222UL, 2376371063UL, 3398508789UL, 3828295651UL, 4066952157UL, 2997263135UL, +4206759111UL, 1266176088UL, 3210273687UL, 560560354UL, 2416600665UL, 874477513UL, 2304714957UL, 629309008UL, 2010844440UL, 2586542760UL, 3490241985UL, 3355968243UL, 2304043871UL, 855615381UL, 452934545UL, 2408437363UL, 1433161037UL, 3245468546UL, 3813880871UL, 2244403710UL, 1966342448UL, 3092333073UL, 1861880941UL, 3334256651UL, 2774994234UL, 2526395471UL, 1884691351UL, 2145882162UL, 3500193798UL, 2303702146UL, 1154858044UL, 1643256991UL, +3172857504UL, 3480843206UL, 130979316UL, 799826424UL, 3094672168UL, 3535834360UL, 915442396UL, 935499492UL, 520495112UL, 575315345UL, 3823364867UL, 2876158574UL, 2272973265UL, 310789314UL, 4207205257UL, 553462404UL, 2184663001UL, 2613016888UL, 3863565851UL, 874197736UL, 3329267685UL, 3447734684UL, 4106984978UL, 1780200631UL, 4088289456UL, 3323217870UL, 2748493470UL, 1559861146UL, 990374143UL, 2080149357UL, 4047813631UL, 2728282767UL, +1133329900UL, 2145680301UL, 2328411541UL, 1572704242UL, 3396987326UL, 63633520UL, 2046317220UL, 4021497634UL, 1385163990UL, 1582181054UL, 1762959503UL, 581690993UL, 3172043012UL, 628071512UL, 2790170929UL, 3726073981UL, 2847267504UL, 3408334906UL, 3352976111UL, 1211075015UL, 3817450114UL, 2811957324UL, 3578703606UL, 1126685543UL, 1946225412UL, 2749086326UL, 2802110464UL, 2391618856UL, 3031260674UL, 453222948UL, 2210258428UL, 2825634835UL, +101928462UL, 477629709UL, 410621659UL, 2679409844UL, 2576087732UL, 736533968UL, 2543083137UL, 1101977922UL, 1122549807UL, 3056925798UL, 341993500UL, 406782950UL, 3057489804UL, 2617760292UL, 1321359723UL, 2901696227UL, 1890958265UL, 4035843698UL, 2666109620UL, 1564088598UL, 914173231UL, 3734092059UL, 908525903UL, 3456779008UL, 329706426UL, 1022239203UL, 1832393502UL, 4024857205UL, 4006865520UL, 1046436763UL, 366391010UL, 2237068647UL, +1564059380UL, 1479646555UL, 3969799795UL, 2565473087UL, 1149521056UL, 2808155917UL, 2379195579UL, 3758124054UL, 1467331930UL, 3988027050UL, 810008243UL, 1796797949UL, 836545831UL, 2227515435UL, 236831608UL, 608273331UL, 544017308UL, 3439193753UL, 2883791516UL, 4170143763UL, 3309288977UL, 3811390247UL, 1648940583UL, 2933346767UL, 639483386UL, 1685761277UL, 4165970043UL, 2470139222UL, 2376371063UL, 3398508789UL, 4275493636UL, 4066952157UL, +2997263135UL, 4206759111UL, 1266176088UL, 333592630UL, 560560354UL, 2416600665UL, 874477513UL, 2304714957UL, 1438974661UL, 2010844440UL, 2586542760UL, 3490241985UL, 3355968243UL, 2556368068UL, 855615381UL, 452934545UL, 2408437363UL, 1433161037UL, 4061232080UL, 3813880871UL, 2244403710UL, 1966342448UL, 3092333073UL, 3412770364UL, 3334256651UL, 2774994234UL, 2526395471UL, 1884691351UL, 1414627588UL, 3500193798UL, 2303702146UL, 1154858044UL, +1643256991UL, 2245958719UL, 3480843206UL, 130979316UL, 799826424UL, 3094672168UL, 2214560871UL, 915442396UL, 935499492UL, 520495112UL, 575315345UL, 3894763683UL, 2876158574UL, 2272973265UL, 310789314UL, 4207205257UL, 3203740771UL, 2184663001UL, 2613016888UL, 3863565851UL, 874197736UL, 3371653768UL, 3447734684UL, 4106984978UL, 1780200631UL, 4088289456UL, 378312754UL, 2748493470UL, 1559861146UL, 990374143UL, 2080149357UL, 554816113UL, +2728282767UL, 1133329900UL, 2145680301UL, 2328411541UL, 4249979994UL, 3396987326UL, 63633520UL, 2046317220UL, 4021497634UL, 4185731269UL, 1582181054UL, 1762959503UL, 581690993UL, 3172043012UL, 3142596028UL, 2790170929UL, 3726073981UL, 2847267504UL, 3408334906UL, 2556911142UL, 1211075015UL, 3817450114UL, 2811957324UL, 3578703606UL, 1480672978UL, 1946225412UL, 2749086326UL, 2802110464UL, 2391618856UL, 3986823297UL, 453222948UL, 2210258428UL, +2825634835UL, 101928462UL, 26373721UL, 410621659UL, 2679409844UL, 2576087732UL, 736533968UL, 888001208UL, 1101977922UL, 1122549807UL, 3056925798UL, 341993500UL, 3243663736UL, 3057489804UL, 2617760292UL, 1321359723UL, 2901696227UL, 1652018736UL, 4035843698UL, 2666109620UL, 1564088598UL, 914173231UL, 1857869366UL, 908525903UL, 3456779008UL, 329706426UL, 1022239203UL, 2622178179UL, 4024857205UL, 4006865520UL, 1046436763UL, 366391010UL, +3722250905UL, 2880126367UL, 4102186560UL, 1642831571UL, 2222486636UL, 2572764729UL, 2046028516UL, 3507603612UL, 1703451134UL, 89818497UL, 1961701523UL, 3704300476UL, 3563143931UL, 1609575644UL, 1599081111UL, 1047838539UL, 2779312926UL, 2065354728UL, 956677756UL, 2073145924UL, 726634994UL, 119064196UL, 2046275296UL, 2105141632UL, 1023267361UL, 1204528080UL, 623740611UL, 1419328884UL, 933734693UL, 2030900835UL, 2556538268UL, 1672647866UL, +3125658368UL, 2221217376UL, 1097330641UL, 3214790630UL, 4276041578UL, 2397216525UL, 3916900004UL, 330223096UL, 3915966823UL, 2646760259UL, 1724289351UL, 4015221358UL, 2338587000UL, 110922222UL, 2314933196UL, 4026908935UL, 3272487985UL, 2685115305UL, 84271650UL, 731354215UL, 2358136447UL, 1069348214UL, 2676811333UL, 1386266810UL, 1364512901UL, 4154449904UL, 3469122709UL, 54276972UL, 560967905UL, 2363475740UL, 331250049UL, 3024074455UL, +186605617UL, 389582566UL, 1258386782UL, 703909543UL, 3968367083UL, 1553533794UL, 3699576213UL, 1145761343UL, 921983735UL, 3573813763UL, 1280477631UL, 3365842435UL, 1618458494UL, 2621328991UL, 1534006198UL, 2307669227UL, 4192335609UL, 1338050203UL, 785284052UL, 4227164890UL, 2874735332UL, 3655821191UL, 2911684671UL, 3266454200UL, 2679968625UL, 1191162601UL, 456550349UL, 1143881236UL, 3560103440UL, 2253437876UL, 3683014001UL, 1087142366UL, +1462192975UL, 1076595768UL, 3227872159UL, 1842092988UL, 148227073UL, 3812110998UL, 1317300278UL, 3068446245UL, 3376284001UL, 3164402992UL, 2730404635UL, 2848239579UL, 3008959791UL, 2901849226UL, 1234485739UL, 869158554UL, 245101118UL, 1724974650UL, 3851803199UL, 922411232UL, 3046280696UL, 3284392523UL, 3528264590UL, 2802364078UL, 381450957UL, 1741009694UL, 4222244451UL, 102929888UL, 1668474417UL, 3881791214UL, 1429483134UL, 1938365051UL, +1023690708UL, 3333855520UL, 3238705869UL, 2602245525UL, 3059586169UL, 720438965UL, 2120786297UL, 453980990UL, 1048501876UL, 4060576583UL, 3537810796UL, 3892882814UL, 691572481UL, 3899584121UL, 1582529013UL, 3260326865UL, 2358704826UL, 1607030801UL, 1035900449UL, 3442507859UL, 1406737127UL, 249758705UL, 1535363329UL, 893329207UL, 51912312UL, 3440532856UL, 3736385218UL, 295452658UL, 2379709553UL, 1647382020UL, 2363679860UL, 2998779887UL, +}, +{ +4209102573UL, 2387104994UL, 1221484586UL, 1726143957UL, 3263877318UL, 3362559187UL, 282442925UL, 2418524976UL, 3196072648UL, 3174695999UL, 2072047145UL, 2985823503UL, 2132951745UL, 2298545297UL, 2495977670UL, 1397656146UL, 2086257884UL, 3834366725UL, 3862532368UL, 3583329522UL, 1543996818UL, 2192688115UL, 3081427696UL, 2656520743UL, 8772004UL, 2476324234UL, 3600148050UL, 1168683794UL, 3219143568UL, 108768238UL, 1339513738UL, 447593731UL, +2742877256UL, 2488536667UL, 4189834432UL, 808657962UL, 2422880287UL, 390864786UL, 3381554683UL, 760628048UL, 353395922UL, 3577556262UL, 2482413928UL, 507756643UL, 839344953UL, 3505184848UL, 3945044582UL, 2414915836UL, 2313624497UL, 1832728088UL, 2036999647UL, 1369090013UL, 3264575895UL, 1096327239UL, 3483440128UL, 3999302048UL, 2761563885UL, 2882627112UL, 3126073009UL, 1749658776UL, 3152482044UL, 3040022505UL, 3249451214UL, 2933713956UL, +2861715096UL, 1314806730UL, 932941454UL, 4276317539UL, 343449784UL, 1913556027UL, 1493892363UL, 2539517630UL, 2046391233UL, 3046108187UL, 28742917UL, 4009448584UL, 530945117UL, 3165875131UL, 1018448712UL, 110256395UL, 3550192264UL, 1279873435UL, 2276349621UL, 517650895UL, 1957973772UL, 619869608UL, 4260458157UL, 2281748739UL, 2489253174UL, 2220997989UL, 3787481606UL, 508630251UL, 3761850170UL, 3992979014UL, 2298047038UL, 3506428315UL, +1279341556UL, 3293496518UL, 1313470495UL, 1021100687UL, 3113171268UL, 798494760UL, 2981622008UL, 4152623583UL, 576409629UL, 2312811213UL, 992326282UL, 261645450UL, 1818084365UL, 3357150904UL, 144093UL, 1937589359UL, 2016990596UL, 4273422066UL, 588267732UL, 3592151118UL, 3846596932UL, 1198111464UL, 944363907UL, 1288613766UL, 1707163456UL, 4020906747UL, 1161127694UL, 2303844076UL, 2632591611UL, 3877442490UL, 2453788473UL, 1725876694UL, +1193989740UL, 2650581453UL, 1937459187UL, 361099994UL, 3566745727UL, 3658112707UL, 3612317412UL, 2684702277UL, 2880928862UL, 2044313931UL, 1866044828UL, 3528429465UL, 130421713UL, 2658878825UL, 1566180833UL, 1572228417UL, 531947625UL, 3774861000UL, 1894712110UL, 1319199233UL, 865634052UL, 2602102379UL, 3389730171UL, 3878969250UL, 107983959UL, 1601930856UL, 2511728925UL, 2146946013UL, 497511195UL, 720616881UL, 699892123UL, 2404505137UL, +2656498433UL, 4209102573UL, 2387104994UL, 1221484586UL, 1726143957UL, 1267363185UL, 3362559187UL, 282442925UL, 2418524976UL, 3196072648UL, 2942944206UL, 2072047145UL, 2985823503UL, 2132951745UL, 2298545297UL, 4079341490UL, 1397656146UL, 2086257884UL, 3834366725UL, 3862532368UL, 3991197972UL, 1543996818UL, 2192688115UL, 3081427696UL, 2656520743UL, 825853576UL, 2476324234UL, 3600148050UL, 1168683794UL, 3219143568UL, 528751585UL, 1339513738UL, +447593731UL, 2742877256UL, 2488536667UL, 4025362081UL, 808657962UL, 2422880287UL, 390864786UL, 3381554683UL, 2682225618UL, 353395922UL, 3577556262UL, 2482413928UL, 507756643UL, 3979211244UL, 3505184848UL, 3945044582UL, 2414915836UL, 2313624497UL, 1841224078UL, 2036999647UL, 1369090013UL, 3264575895UL, 1096327239UL, 607843308UL, 3999302048UL, 2761563885UL, 2882627112UL, 3126073009UL, 1241524975UL, 3152482044UL, 3040022505UL, 3249451214UL, +2933713956UL, 420486142UL, 1314806730UL, 932941454UL, 4276317539UL, 343449784UL, 2231505736UL, 1493892363UL, 2539517630UL, 2046391233UL, 3046108187UL, 2351652097UL, 4009448584UL, 530945117UL, 3165875131UL, 1018448712UL, 1683392491UL, 3550192264UL, 1279873435UL, 2276349621UL, 517650895UL, 4036312766UL, 619869608UL, 4260458157UL, 2281748739UL, 2489253174UL, 1686790154UL, 3787481606UL, 508630251UL, 3761850170UL, 3992979014UL, 1745325013UL, +3506428315UL, 1279341556UL, 3293496518UL, 1313470495UL, 3066312306UL, 3113171268UL, 798494760UL, 2981622008UL, 4152623583UL, 3871822467UL, 2312811213UL, 992326282UL, 261645450UL, 1818084365UL, 3681154045UL, 144093UL, 1937589359UL, 2016990596UL, 4273422066UL, 2361898985UL, 3592151118UL, 3846596932UL, 1198111464UL, 944363907UL, 2866279694UL, 1707163456UL, 4020906747UL, 1161127694UL, 2303844076UL, 3044280908UL, 3877442490UL, 2453788473UL, +1725876694UL, 1193989740UL, 2049617934UL, 1937459187UL, 361099994UL, 3566745727UL, 3658112707UL, 934740227UL, 2684702277UL, 2880928862UL, 2044313931UL, 1866044828UL, 1814569183UL, 130421713UL, 2658878825UL, 1566180833UL, 1572228417UL, 1784679035UL, 3774861000UL, 1894712110UL, 1319199233UL, 865634052UL, 283642947UL, 3389730171UL, 3878969250UL, 107983959UL, 1601930856UL, 3698217362UL, 2146946013UL, 497511195UL, 720616881UL, 699892123UL, +2117385156UL, 2656498433UL, 4209102573UL, 2387104994UL, 1221484586UL, 3495886368UL, 1267363185UL, 3362559187UL, 282442925UL, 2418524976UL, 3489510655UL, 2942944206UL, 2072047145UL, 2985823503UL, 2132951745UL, 885541635UL, 4079341490UL, 1397656146UL, 2086257884UL, 3834366725UL, 1049969755UL, 3991197972UL, 1543996818UL, 2192688115UL, 3081427696UL, 2141948440UL, 825853576UL, 2476324234UL, 3600148050UL, 1168683794UL, 5160254UL, 528751585UL, +1339513738UL, 447593731UL, 2742877256UL, 3033397497UL, 4025362081UL, 808657962UL, 2422880287UL, 390864786UL, 3191593886UL, 2682225618UL, 353395922UL, 3577556262UL, 2482413928UL, 1185107868UL, 3979211244UL, 3505184848UL, 3945044582UL, 2414915836UL, 3030493909UL, 1841224078UL, 2036999647UL, 1369090013UL, 3264575895UL, 3054343366UL, 607843308UL, 3999302048UL, 2761563885UL, 2882627112UL, 3912854189UL, 1241524975UL, 3152482044UL, 3040022505UL, +3249451214UL, 55140065UL, 420486142UL, 1314806730UL, 932941454UL, 4276317539UL, 1055315026UL, 2231505736UL, 1493892363UL, 2539517630UL, 2046391233UL, 4174985470UL, 2351652097UL, 4009448584UL, 530945117UL, 3165875131UL, 2168411768UL, 1683392491UL, 3550192264UL, 1279873435UL, 2276349621UL, 1875092822UL, 4036312766UL, 619869608UL, 4260458157UL, 2281748739UL, 98823023UL, 1686790154UL, 3787481606UL, 508630251UL, 3761850170UL, 2636025017UL, +1745325013UL, 3506428315UL, 1279341556UL, 3293496518UL, 978338993UL, 3066312306UL, 3113171268UL, 798494760UL, 2981622008UL, 2712384846UL, 3871822467UL, 2312811213UL, 992326282UL, 261645450UL, 66982935UL, 3681154045UL, 144093UL, 1937589359UL, 2016990596UL, 3390191329UL, 2361898985UL, 3592151118UL, 3846596932UL, 1198111464UL, 1857959320UL, 2866279694UL, 1707163456UL, 4020906747UL, 1161127694UL, 913091437UL, 3044280908UL, 3877442490UL, +2453788473UL, 1725876694UL, 4254455215UL, 2049617934UL, 1937459187UL, 361099994UL, 3566745727UL, 2914687409UL, 934740227UL, 2684702277UL, 2880928862UL, 2044313931UL, 1515195925UL, 1814569183UL, 130421713UL, 2658878825UL, 1566180833UL, 2753417020UL, 1784679035UL, 3774861000UL, 1894712110UL, 1319199233UL, 287161774UL, 283642947UL, 3389730171UL, 3878969250UL, 107983959UL, 3057929912UL, 3698217362UL, 2146946013UL, 497511195UL, 720616881UL, +3570251850UL, 2117385156UL, 2656498433UL, 4209102573UL, 2387104994UL, 2940868252UL, 3495886368UL, 1267363185UL, 3362559187UL, 282442925UL, 2510419746UL, 3489510655UL, 2942944206UL, 2072047145UL, 2985823503UL, 978430777UL, 885541635UL, 4079341490UL, 1397656146UL, 2086257884UL, 134380865UL, 1049969755UL, 3991197972UL, 1543996818UL, 2192688115UL, 1205081471UL, 2141948440UL, 825853576UL, 2476324234UL, 3600148050UL, 228461601UL, 5160254UL, +528751585UL, 1339513738UL, 447593731UL, 2852356745UL, 3033397497UL, 4025362081UL, 808657962UL, 2422880287UL, 3287655095UL, 3191593886UL, 2682225618UL, 353395922UL, 3577556262UL, 2542841784UL, 1185107868UL, 3979211244UL, 3505184848UL, 3945044582UL, 2905156498UL, 3030493909UL, 1841224078UL, 2036999647UL, 1369090013UL, 4246605417UL, 3054343366UL, 607843308UL, 3999302048UL, 2761563885UL, 3611911899UL, 3912854189UL, 1241524975UL, 3152482044UL, +3040022505UL, 3215633820UL, 55140065UL, 420486142UL, 1314806730UL, 932941454UL, 2708752494UL, 1055315026UL, 2231505736UL, 1493892363UL, 2539517630UL, 962728637UL, 4174985470UL, 2351652097UL, 4009448584UL, 530945117UL, 3370859357UL, 2168411768UL, 1683392491UL, 3550192264UL, 1279873435UL, 3028448904UL, 1875092822UL, 4036312766UL, 619869608UL, 4260458157UL, 199178828UL, 98823023UL, 1686790154UL, 3787481606UL, 508630251UL, 4205010983UL, +2636025017UL, 1745325013UL, 3506428315UL, 1279341556UL, 683127445UL, 978338993UL, 3066312306UL, 3113171268UL, 798494760UL, 2823693013UL, 2712384846UL, 3871822467UL, 2312811213UL, 992326282UL, 3701928286UL, 66982935UL, 3681154045UL, 144093UL, 1937589359UL, 1117717039UL, 3390191329UL, 2361898985UL, 3592151118UL, 3846596932UL, 1072660054UL, 1857959320UL, 2866279694UL, 1707163456UL, 4020906747UL, 2503116219UL, 913091437UL, 3044280908UL, +3877442490UL, 2453788473UL, 1815274499UL, 4254455215UL, 2049617934UL, 1937459187UL, 361099994UL, 3771108073UL, 2914687409UL, 934740227UL, 2684702277UL, 2880928862UL, 3591322975UL, 1515195925UL, 1814569183UL, 130421713UL, 2658878825UL, 354587729UL, 2753417020UL, 1784679035UL, 3774861000UL, 1894712110UL, 1799044969UL, 287161774UL, 283642947UL, 3389730171UL, 3878969250UL, 1229815186UL, 3057929912UL, 3698217362UL, 2146946013UL, 497511195UL, +3121882901UL, 426537369UL, 3852284416UL, 4050544256UL, 3148944089UL, 878474231UL, 1369575859UL, 2206199765UL, 870626886UL, 494668165UL, 613011290UL, 3246772867UL, 1040178461UL, 2396959353UL, 2105449571UL, 456758967UL, 4134137960UL, 3525051481UL, 3633445497UL, 2895048060UL, 2008411846UL, 2194012253UL, 2326112129UL, 2956901044UL, 2297039362UL, 3400824024UL, 42139718UL, 4212208866UL, 3874761488UL, 2361955811UL, 1890446075UL, 864533345UL, +474524842UL, 2283847731UL, 283971243UL, 3607219686UL, 280870706UL, 4188549522UL, 659660119UL, 2460943922UL, 4252134362UL, 922033031UL, 3615474721UL, 1691563300UL, 3002653770UL, 2414043617UL, 2251931324UL, 752654714UL, 4188343161UL, 305594960UL, 1320443323UL, 797027061UL, 2347530104UL, 3608843538UL, 2717312892UL, 1841295453UL, 1574467161UL, 823626340UL, 2244853583UL, 2648217758UL, 141742826UL, 1605436472UL, 745763543UL, 3275460028UL, +3166960370UL, 2655678693UL, 3964037210UL, 945054703UL, 998173049UL, 1014527437UL, 3424443612UL, 281835352UL, 826817508UL, 260462513UL, 2849967970UL, 3447294061UL, 3670173947UL, 2430650055UL, 4134905457UL, 3798172627UL, 2156572681UL, 2600148034UL, 2773013892UL, 3290397106UL, 1740507705UL, 3450254627UL, 3613087060UL, 440045928UL, 1230555006UL, 980805434UL, 2107958250UL, 526555374UL, 3150741277UL, 4283672024UL, 193019043UL, 786035243UL, +3002832578UL, 3938336183UL, 4209865002UL, 1005950967UL, 3533346582UL, 3196886974UL, 83962845UL, 1882902787UL, 3595687446UL, 2927597311UL, 2728550762UL, 2750900392UL, 1474254316UL, 1509832112UL, 1763262792UL, 2706181276UL, 538294991UL, 353565565UL, 18133995UL, 1719731406UL, 3311085516UL, 2018821960UL, 300367686UL, 2628312935UL, 1151449661UL, 2178805970UL, 3288321196UL, 535051857UL, 1623270973UL, 2761151808UL, 2701048972UL, 317681607UL, +2281427601UL, 719748170UL, 351452298UL, 2191958596UL, 4000232015UL, 335837771UL, 4158081521UL, 3779404077UL, 1998444133UL, 3849605095UL, 1532231791UL, 2930266419UL, 4203951289UL, 748423654UL, 1993082867UL, 451159852UL, 488781053UL, 2438982775UL, 2222815270UL, 543209242UL, 1241562465UL, 2868868009UL, 4201052877UL, 2438841764UL, 2151708682UL, 2426958921UL, 1520654642UL, 1990098337UL, 1070792755UL, 2308394635UL, 1442389785UL, 705615044UL, +}, +{ +973368008UL, 1221885324UL, 2086331970UL, 2323744198UL, 280145759UL, 1795442656UL, 2984366093UL, 3532172763UL, 323888669UL, 851950179UL, 4198638255UL, 899943985UL, 4087912561UL, 2935341503UL, 1443752852UL, 3991058999UL, 3547259355UL, 35779889UL, 1076308344UL, 4075444807UL, 186174448UL, 3542284780UL, 660388677UL, 2777400132UL, 1092226205UL, 2418702276UL, 1307933032UL, 1940510003UL, 1932005362UL, 4016036211UL, 387339882UL, 2969593895UL, +3453134349UL, 1382709098UL, 1795814140UL, 1588159469UL, 1216733801UL, 2227378121UL, 2063027627UL, 582454582UL, 3364657275UL, 3466973302UL, 484564303UL, 1489261596UL, 2270291560UL, 2008178784UL, 2284268924UL, 2229317366UL, 644797709UL, 1213921542UL, 99331403UL, 3027640949UL, 1137722852UL, 2991506109UL, 1432805987UL, 931795812UL, 1075567424UL, 28963219UL, 1462245461UL, 3781444706UL, 521233400UL, 1891915904UL, 3774338085UL, 1635359313UL, +2356111795UL, 4121073768UL, 1045110727UL, 2822507066UL, 1087914587UL, 3744509525UL, 911370656UL, 181884066UL, 1944539735UL, 290356444UL, 3598887471UL, 4236934380UL, 3224468239UL, 457546246UL, 4119337570UL, 37700432UL, 655783844UL, 1423101410UL, 1693002969UL, 3287768267UL, 928748421UL, 4074128009UL, 3081088543UL, 2882833790UL, 3180154875UL, 1094657682UL, 2388253717UL, 4173455215UL, 794709427UL, 3363292346UL, 67786868UL, 3786597763UL, +380587236UL, 2345941620UL, 560232318UL, 2137123833UL, 619747082UL, 1050293267UL, 2537845069UL, 1407302835UL, 433399526UL, 1083185007UL, 1893842085UL, 3711748584UL, 4225838280UL, 3863317129UL, 2043467942UL, 2799650657UL, 3590486611UL, 1231938950UL, 215905995UL, 155811669UL, 806806587UL, 2732631168UL, 1621659281UL, 632403616UL, 401165422UL, 2661074778UL, 4156963191UL, 3691812937UL, 3767271627UL, 2834948318UL, 2877210497UL, 2420260153UL, +733172233UL, 1771708940UL, 3102718549UL, 2468707423UL, 1857088312UL, 3176535032UL, 1908570295UL, 3966666208UL, 605079895UL, 2982506620UL, 3721694730UL, 1640691570UL, 3764975545UL, 3257514114UL, 1826578604UL, 1358557411UL, 4049610348UL, 615820785UL, 3355718142UL, 1734641780UL, 2958744617UL, 274522187UL, 3198436002UL, 4077346785UL, 2890101344UL, 4012464346UL, 1288365365UL, 96583076UL, 2656389382UL, 1858181040UL, 2717010340UL, 2032153178UL, +349324012UL, 973368008UL, 1221885324UL, 2086331970UL, 2323744198UL, 253685576UL, 1795442656UL, 2984366093UL, 3532172763UL, 323888669UL, 248935329UL, 4198638255UL, 899943985UL, 4087912561UL, 2935341503UL, 3213394756UL, 3991058999UL, 3547259355UL, 35779889UL, 1076308344UL, 1987715385UL, 186174448UL, 3542284780UL, 660388677UL, 2777400132UL, 2071022105UL, 2418702276UL, 1307933032UL, 1940510003UL, 1932005362UL, 144370664UL, 387339882UL, +2969593895UL, 3453134349UL, 1382709098UL, 2394736611UL, 1588159469UL, 1216733801UL, 2227378121UL, 2063027627UL, 4064263898UL, 3364657275UL, 3466973302UL, 484564303UL, 1489261596UL, 3405101812UL, 2008178784UL, 2284268924UL, 2229317366UL, 644797709UL, 2560273821UL, 99331403UL, 3027640949UL, 1137722852UL, 2991506109UL, 1446442417UL, 931795812UL, 1075567424UL, 28963219UL, 1462245461UL, 1201513613UL, 521233400UL, 1891915904UL, 3774338085UL, +1635359313UL, 2815447944UL, 4121073768UL, 1045110727UL, 2822507066UL, 1087914587UL, 2485035329UL, 911370656UL, 181884066UL, 1944539735UL, 290356444UL, 2078819341UL, 4236934380UL, 3224468239UL, 457546246UL, 4119337570UL, 2666895496UL, 655783844UL, 1423101410UL, 1693002969UL, 3287768267UL, 3595439673UL, 4074128009UL, 3081088543UL, 2882833790UL, 3180154875UL, 872453917UL, 2388253717UL, 4173455215UL, 794709427UL, 3363292346UL, 4188764388UL, +3786597763UL, 380587236UL, 2345941620UL, 560232318UL, 625538006UL, 619747082UL, 1050293267UL, 2537845069UL, 1407302835UL, 2128289331UL, 1083185007UL, 1893842085UL, 3711748584UL, 4225838280UL, 2486133065UL, 2043467942UL, 2799650657UL, 3590486611UL, 1231938950UL, 928582681UL, 155811669UL, 806806587UL, 2732631168UL, 1621659281UL, 1163969880UL, 401165422UL, 2661074778UL, 4156963191UL, 3691812937UL, 2322579561UL, 2834948318UL, 2877210497UL, +2420260153UL, 733172233UL, 170239236UL, 3102718549UL, 2468707423UL, 1857088312UL, 3176535032UL, 3868693408UL, 3966666208UL, 605079895UL, 2982506620UL, 3721694730UL, 2066859537UL, 3764975545UL, 3257514114UL, 1826578604UL, 1358557411UL, 2964604045UL, 615820785UL, 3355718142UL, 1734641780UL, 2958744617UL, 4091225681UL, 3198436002UL, 4077346785UL, 2890101344UL, 4012464346UL, 2612861218UL, 96583076UL, 2656389382UL, 1858181040UL, 2717010340UL, +3639170895UL, 349324012UL, 973368008UL, 1221885324UL, 2086331970UL, 2258432445UL, 253685576UL, 1795442656UL, 2984366093UL, 3532172763UL, 3831166882UL, 248935329UL, 4198638255UL, 899943985UL, 4087912561UL, 715173523UL, 3213394756UL, 3991058999UL, 3547259355UL, 35779889UL, 2393072396UL, 1987715385UL, 186174448UL, 3542284780UL, 660388677UL, 3731857267UL, 2071022105UL, 2418702276UL, 1307933032UL, 1940510003UL, 4262274779UL, 144370664UL, +387339882UL, 2969593895UL, 3453134349UL, 1923698215UL, 2394736611UL, 1588159469UL, 1216733801UL, 2227378121UL, 2907069566UL, 4064263898UL, 3364657275UL, 3466973302UL, 484564303UL, 2234542580UL, 3405101812UL, 2008178784UL, 2284268924UL, 2229317366UL, 1349323372UL, 2560273821UL, 99331403UL, 3027640949UL, 1137722852UL, 4200786664UL, 1446442417UL, 931795812UL, 1075567424UL, 28963219UL, 1659632304UL, 1201513613UL, 521233400UL, 1891915904UL, +3774338085UL, 763590809UL, 2815447944UL, 4121073768UL, 1045110727UL, 2822507066UL, 4131040734UL, 2485035329UL, 911370656UL, 181884066UL, 1944539735UL, 4104473807UL, 2078819341UL, 4236934380UL, 3224468239UL, 457546246UL, 1241850776UL, 2666895496UL, 655783844UL, 1423101410UL, 1693002969UL, 2025898966UL, 3595439673UL, 4074128009UL, 3081088543UL, 2882833790UL, 218474476UL, 872453917UL, 2388253717UL, 4173455215UL, 794709427UL, 250328312UL, +4188764388UL, 3786597763UL, 380587236UL, 2345941620UL, 1937652040UL, 625538006UL, 619747082UL, 1050293267UL, 2537845069UL, 1140055765UL, 2128289331UL, 1083185007UL, 1893842085UL, 3711748584UL, 2298055548UL, 2486133065UL, 2043467942UL, 2799650657UL, 3590486611UL, 1235949580UL, 928582681UL, 155811669UL, 806806587UL, 2732631168UL, 4046198728UL, 1163969880UL, 401165422UL, 2661074778UL, 4156963191UL, 2003518762UL, 2322579561UL, 2834948318UL, +2877210497UL, 2420260153UL, 326741418UL, 170239236UL, 3102718549UL, 2468707423UL, 1857088312UL, 3936056808UL, 3868693408UL, 3966666208UL, 605079895UL, 2982506620UL, 2354705582UL, 2066859537UL, 3764975545UL, 3257514114UL, 1826578604UL, 3017501686UL, 2964604045UL, 615820785UL, 3355718142UL, 1734641780UL, 1681548103UL, 4091225681UL, 3198436002UL, 4077346785UL, 2890101344UL, 416470693UL, 2612861218UL, 96583076UL, 2656389382UL, 1858181040UL, +3104217288UL, 3639170895UL, 349324012UL, 973368008UL, 1221885324UL, 601524567UL, 2258432445UL, 253685576UL, 1795442656UL, 2984366093UL, 1875491903UL, 3831166882UL, 248935329UL, 4198638255UL, 899943985UL, 2182697927UL, 715173523UL, 3213394756UL, 3991058999UL, 3547259355UL, 1472237612UL, 2393072396UL, 1987715385UL, 186174448UL, 3542284780UL, 2160848139UL, 3731857267UL, 2071022105UL, 2418702276UL, 1307933032UL, 3815354311UL, 4262274779UL, +144370664UL, 387339882UL, 2969593895UL, 4240850623UL, 1923698215UL, 2394736611UL, 1588159469UL, 1216733801UL, 322523795UL, 2907069566UL, 4064263898UL, 3364657275UL, 3466973302UL, 2920715858UL, 2234542580UL, 3405101812UL, 2008178784UL, 2284268924UL, 1936025139UL, 1349323372UL, 2560273821UL, 99331403UL, 3027640949UL, 859541953UL, 4200786664UL, 1446442417UL, 931795812UL, 1075567424UL, 1876635772UL, 1659632304UL, 1201513613UL, 521233400UL, +1891915904UL, 3949233865UL, 763590809UL, 2815447944UL, 4121073768UL, 1045110727UL, 2522258582UL, 4131040734UL, 2485035329UL, 911370656UL, 181884066UL, 2467886009UL, 4104473807UL, 2078819341UL, 4236934380UL, 3224468239UL, 603014155UL, 1241850776UL, 2666895496UL, 655783844UL, 1423101410UL, 673119756UL, 2025898966UL, 3595439673UL, 4074128009UL, 3081088543UL, 4100445818UL, 218474476UL, 872453917UL, 2388253717UL, 4173455215UL, 2395519424UL, +250328312UL, 4188764388UL, 3786597763UL, 380587236UL, 4292608797UL, 1937652040UL, 625538006UL, 619747082UL, 1050293267UL, 2989616803UL, 1140055765UL, 2128289331UL, 1083185007UL, 1893842085UL, 3313934002UL, 2298055548UL, 2486133065UL, 2043467942UL, 2799650657UL, 1804808801UL, 1235949580UL, 928582681UL, 155811669UL, 806806587UL, 2864892828UL, 4046198728UL, 1163969880UL, 401165422UL, 2661074778UL, 2946769376UL, 2003518762UL, 2322579561UL, +2834948318UL, 2877210497UL, 2647485275UL, 326741418UL, 170239236UL, 3102718549UL, 2468707423UL, 2520336801UL, 3936056808UL, 3868693408UL, 3966666208UL, 605079895UL, 2949706551UL, 2354705582UL, 2066859537UL, 3764975545UL, 3257514114UL, 495003693UL, 3017501686UL, 2964604045UL, 615820785UL, 3355718142UL, 3799230297UL, 1681548103UL, 4091225681UL, 3198436002UL, 4077346785UL, 258363842UL, 416470693UL, 2612861218UL, 96583076UL, 2656389382UL, +2198085634UL, 1607235362UL, 694172175UL, 4194347563UL, 2665732891UL, 3419430286UL, 597070176UL, 2749480905UL, 3937535348UL, 3639873850UL, 2050067843UL, 4045290683UL, 2964298196UL, 3631595287UL, 1409808193UL, 121765438UL, 2129412744UL, 2497437101UL, 2664102876UL, 1773441464UL, 1708052456UL, 2923764322UL, 3350385352UL, 1592204280UL, 1118221370UL, 3416016313UL, 116121364UL, 1179473397UL, 1497519022UL, 902569114UL, 3840281863UL, 2783662797UL, +1712084322UL, 1982884601UL, 3625797892UL, 4222938993UL, 3231134134UL, 3046745397UL, 446484563UL, 1133869192UL, 2622178726UL, 3881085862UL, 4012894217UL, 391734322UL, 2089696890UL, 1304197030UL, 2663978386UL, 1685998658UL, 4238620912UL, 448351665UL, 2724524045UL, 1038754164UL, 413586547UL, 3107681687UL, 1454664365UL, 3353731192UL, 128440996UL, 565817989UL, 127978294UL, 1043863326UL, 1747369107UL, 2772246481UL, 172569313UL, 2740699699UL, +3417082503UL, 2103702630UL, 2139566116UL, 1378864710UL, 2444170529UL, 3234220221UL, 3974870858UL, 1965162347UL, 956763257UL, 3932467825UL, 1077337271UL, 4084837149UL, 3699147465UL, 1882164226UL, 236113740UL, 3116302858UL, 2730529598UL, 3449804672UL, 4002370655UL, 2011573068UL, 1551746089UL, 3917496971UL, 2852603UL, 1682999535UL, 2764817908UL, 2489487254UL, 261936311UL, 3122421452UL, 1199382345UL, 2617247590UL, 1909026938UL, 3156073069UL, +1492533764UL, 97847107UL, 1260892586UL, 187242945UL, 1286471861UL, 1763024967UL, 127723419UL, 210606273UL, 228546401UL, 3249879676UL, 482069954UL, 383075106UL, 3263105259UL, 2242748676UL, 1105681409UL, 4033144425UL, 4017983282UL, 1670425353UL, 4040882785UL, 1780687273UL, 1405678015UL, 3076115981UL, 2713472488UL, 286336494UL, 3664225263UL, 502759060UL, 777620620UL, 635590826UL, 132236203UL, 1866406173UL, 1235046453UL, 2859554298UL, +121814656UL, 944976320UL, 1946494170UL, 2548097575UL, 415384946UL, 3934685646UL, 1507032178UL, 1383654007UL, 2906269630UL, 566005756UL, 3118733139UL, 2969075870UL, 1834096359UL, 3263358416UL, 1322979710UL, 904583023UL, 3582075094UL, 2298898632UL, 2491891941UL, 660351763UL, 2548592542UL, 3009200751UL, 2116595110UL, 2623212287UL, 4167133624UL, 196759529UL, 3038645579UL, 1769704552UL, 1713233322UL, 2127497999UL, 3849458221UL, 3769872265UL, +}, +{ +51082211UL, 3347503176UL, 3221768777UL, 2986163981UL, 3937460013UL, 1716372908UL, 4132024211UL, 3035957293UL, 1791036224UL, 4214815056UL, 1645540011UL, 2629793790UL, 3185505897UL, 1855718954UL, 495459467UL, 1728339314UL, 2318396341UL, 3396602050UL, 3273624616UL, 2625973148UL, 1762905939UL, 1706358553UL, 1088424264UL, 2764318930UL, 1026127380UL, 1128004134UL, 2724553694UL, 41981087UL, 2304966004UL, 1342745986UL, 3425554050UL, 3537673465UL, +752263676UL, 280905885UL, 929399589UL, 4090689526UL, 2141254732UL, 1469491656UL, 2593100469UL, 1096008340UL, 3316809312UL, 1698245188UL, 1656427920UL, 3081873338UL, 1750515301UL, 3850483440UL, 4081834419UL, 1225164947UL, 1244139942UL, 1972663124UL, 116832506UL, 3097397897UL, 961156503UL, 1899056660UL, 1659173175UL, 1890464921UL, 1891872926UL, 191259956UL, 1735304734UL, 4246751855UL, 4285601625UL, 1495519933UL, 3398829761UL, 997567482UL, +2277782972UL, 1286922996UL, 3120709698UL, 15569196UL, 191501283UL, 3916619528UL, 1552075789UL, 4259725643UL, 2837166910UL, 2231584792UL, 1912204495UL, 2597304083UL, 4147585653UL, 1021482843UL, 2003417305UL, 186794491UL, 3608172979UL, 1991038123UL, 97515853UL, 34341352UL, 4163491231UL, 1046079304UL, 4105813389UL, 3589099183UL, 3970004064UL, 3899560802UL, 4148331147UL, 2267137817UL, 85024486UL, 3019925981UL, 3069231953UL, 1563669137UL, +314080592UL, 2943111861UL, 2838243982UL, 726216848UL, 2621853102UL, 2355885175UL, 3359668856UL, 1111296541UL, 2330283124UL, 3626558972UL, 4290084148UL, 1632078UL, 1047440803UL, 1350377197UL, 2490578842UL, 2366345698UL, 1628128899UL, 860259543UL, 1937956234UL, 2833820527UL, 329818923UL, 648489148UL, 1791961202UL, 1652322723UL, 1513419073UL, 149629345UL, 2468961221UL, 3711837973UL, 2377333831UL, 1434755773UL, 3808719305UL, 2513270108UL, +2701064683UL, 3097011724UL, 303393137UL, 1346302239UL, 1852307302UL, 850106025UL, 2473124483UL, 2853497268UL, 3786573704UL, 2604101162UL, 1446573486UL, 506925220UL, 3138967488UL, 2973528682UL, 2752811123UL, 2890321579UL, 1037196362UL, 1335670403UL, 1560253777UL, 1437495434UL, 2700525242UL, 4259933972UL, 3870707795UL, 4141538580UL, 3375331039UL, 3081538601UL, 3129978494UL, 3689191993UL, 1933431212UL, 2196145886UL, 87814045UL, 878611347UL, +812542698UL, 51082211UL, 3347503176UL, 3221768777UL, 2986163981UL, 277257023UL, 1716372908UL, 4132024211UL, 3035957293UL, 1791036224UL, 2713916211UL, 1645540011UL, 2629793790UL, 3185505897UL, 1855718954UL, 3800150234UL, 1728339314UL, 2318396341UL, 3396602050UL, 3273624616UL, 2530282967UL, 1762905939UL, 1706358553UL, 1088424264UL, 2764318930UL, 4224669506UL, 1128004134UL, 2724553694UL, 41981087UL, 2304966004UL, 484289311UL, 3425554050UL, +3537673465UL, 752263676UL, 280905885UL, 657028134UL, 4090689526UL, 2141254732UL, 1469491656UL, 2593100469UL, 2089385540UL, 3316809312UL, 1698245188UL, 1656427920UL, 3081873338UL, 2750354264UL, 3850483440UL, 4081834419UL, 1225164947UL, 1244139942UL, 3432605739UL, 116832506UL, 3097397897UL, 961156503UL, 1899056660UL, 2234120716UL, 1890464921UL, 1891872926UL, 191259956UL, 1735304734UL, 125359575UL, 4285601625UL, 1495519933UL, 3398829761UL, +997567482UL, 4034254942UL, 1286922996UL, 3120709698UL, 15569196UL, 191501283UL, 2090684174UL, 1552075789UL, 4259725643UL, 2837166910UL, 2231584792UL, 3412758413UL, 2597304083UL, 4147585653UL, 1021482843UL, 2003417305UL, 2464533361UL, 3608172979UL, 1991038123UL, 97515853UL, 34341352UL, 2634732952UL, 1046079304UL, 4105813389UL, 3589099183UL, 3970004064UL, 4263828421UL, 4148331147UL, 2267137817UL, 85024486UL, 3019925981UL, 3229477751UL, +1563669137UL, 314080592UL, 2943111861UL, 2838243982UL, 1274664774UL, 2621853102UL, 2355885175UL, 3359668856UL, 1111296541UL, 1615234696UL, 3626558972UL, 4290084148UL, 1632078UL, 1047440803UL, 623898652UL, 2490578842UL, 2366345698UL, 1628128899UL, 860259543UL, 2097114662UL, 2833820527UL, 329818923UL, 648489148UL, 1791961202UL, 1730000077UL, 1513419073UL, 149629345UL, 2468961221UL, 3711837973UL, 3255238414UL, 1434755773UL, 3808719305UL, +2513270108UL, 2701064683UL, 1635042488UL, 303393137UL, 1346302239UL, 1852307302UL, 850106025UL, 3523245944UL, 2853497268UL, 3786573704UL, 2604101162UL, 1446573486UL, 1011238489UL, 3138967488UL, 2973528682UL, 2752811123UL, 2890321579UL, 1044586909UL, 1335670403UL, 1560253777UL, 1437495434UL, 2700525242UL, 608940900UL, 3870707795UL, 4141538580UL, 3375331039UL, 3081538601UL, 728626935UL, 3689191993UL, 1933431212UL, 2196145886UL, 87814045UL, +646732047UL, 812542698UL, 51082211UL, 3347503176UL, 3221768777UL, 1783601443UL, 277257023UL, 1716372908UL, 4132024211UL, 3035957293UL, 3363442238UL, 2713916211UL, 1645540011UL, 2629793790UL, 3185505897UL, 2066587565UL, 3800150234UL, 1728339314UL, 2318396341UL, 3396602050UL, 2279941522UL, 2530282967UL, 1762905939UL, 1706358553UL, 1088424264UL, 2989326347UL, 4224669506UL, 1128004134UL, 2724553694UL, 41981087UL, 2348931916UL, 484289311UL, +3425554050UL, 3537673465UL, 752263676UL, 3169550883UL, 657028134UL, 4090689526UL, 2141254732UL, 1469491656UL, 1152943917UL, 2089385540UL, 3316809312UL, 1698245188UL, 1656427920UL, 1808689833UL, 2750354264UL, 3850483440UL, 4081834419UL, 1225164947UL, 2422106046UL, 3432605739UL, 116832506UL, 3097397897UL, 961156503UL, 1581804167UL, 2234120716UL, 1890464921UL, 1891872926UL, 191259956UL, 4113708001UL, 125359575UL, 4285601625UL, 1495519933UL, +3398829761UL, 3473435310UL, 4034254942UL, 1286922996UL, 3120709698UL, 15569196UL, 3122200488UL, 2090684174UL, 1552075789UL, 4259725643UL, 2837166910UL, 2838170407UL, 3412758413UL, 2597304083UL, 4147585653UL, 1021482843UL, 954000150UL, 2464533361UL, 3608172979UL, 1991038123UL, 97515853UL, 3832321348UL, 2634732952UL, 1046079304UL, 4105813389UL, 3589099183UL, 1288675572UL, 4263828421UL, 4148331147UL, 2267137817UL, 85024486UL, 1080403742UL, +3229477751UL, 1563669137UL, 314080592UL, 2943111861UL, 3357655593UL, 1274664774UL, 2621853102UL, 2355885175UL, 3359668856UL, 3722440291UL, 1615234696UL, 3626558972UL, 4290084148UL, 1632078UL, 4263556325UL, 623898652UL, 2490578842UL, 2366345698UL, 1628128899UL, 3623136669UL, 2097114662UL, 2833820527UL, 329818923UL, 648489148UL, 592747007UL, 1730000077UL, 1513419073UL, 149629345UL, 2468961221UL, 3766709284UL, 3255238414UL, 1434755773UL, +3808719305UL, 2513270108UL, 1958651003UL, 1635042488UL, 303393137UL, 1346302239UL, 1852307302UL, 579487408UL, 3523245944UL, 2853497268UL, 3786573704UL, 2604101162UL, 4183724981UL, 1011238489UL, 3138967488UL, 2973528682UL, 2752811123UL, 3074709397UL, 1044586909UL, 1335670403UL, 1560253777UL, 1437495434UL, 1237099522UL, 608940900UL, 3870707795UL, 4141538580UL, 3375331039UL, 2032507604UL, 728626935UL, 3689191993UL, 1933431212UL, 2196145886UL, +4008131891UL, 646732047UL, 812542698UL, 51082211UL, 3347503176UL, 3622107037UL, 1783601443UL, 277257023UL, 1716372908UL, 4132024211UL, 1264285659UL, 3363442238UL, 2713916211UL, 1645540011UL, 2629793790UL, 2179309595UL, 2066587565UL, 3800150234UL, 1728339314UL, 2318396341UL, 580990822UL, 2279941522UL, 2530282967UL, 1762905939UL, 1706358553UL, 2826056883UL, 2989326347UL, 4224669506UL, 1128004134UL, 2724553694UL, 1486392636UL, 2348931916UL, +484289311UL, 3425554050UL, 3537673465UL, 2497657189UL, 3169550883UL, 657028134UL, 4090689526UL, 2141254732UL, 1019244016UL, 1152943917UL, 2089385540UL, 3316809312UL, 1698245188UL, 2921739456UL, 1808689833UL, 2750354264UL, 3850483440UL, 4081834419UL, 108425527UL, 2422106046UL, 3432605739UL, 116832506UL, 3097397897UL, 3902994002UL, 1581804167UL, 2234120716UL, 1890464921UL, 1891872926UL, 3428861050UL, 4113708001UL, 125359575UL, 4285601625UL, +1495519933UL, 3350053832UL, 3473435310UL, 4034254942UL, 1286922996UL, 3120709698UL, 2906201347UL, 3122200488UL, 2090684174UL, 1552075789UL, 4259725643UL, 1965598685UL, 2838170407UL, 3412758413UL, 2597304083UL, 4147585653UL, 3335631208UL, 954000150UL, 2464533361UL, 3608172979UL, 1991038123UL, 3788034599UL, 3832321348UL, 2634732952UL, 1046079304UL, 4105813389UL, 2362460804UL, 1288675572UL, 4263828421UL, 4148331147UL, 2267137817UL, 2767331798UL, +1080403742UL, 3229477751UL, 1563669137UL, 314080592UL, 1737897403UL, 3357655593UL, 1274664774UL, 2621853102UL, 2355885175UL, 57997639UL, 3722440291UL, 1615234696UL, 3626558972UL, 4290084148UL, 3703113369UL, 4263556325UL, 623898652UL, 2490578842UL, 2366345698UL, 73788443UL, 3623136669UL, 2097114662UL, 2833820527UL, 329818923UL, 253042650UL, 592747007UL, 1730000077UL, 1513419073UL, 149629345UL, 4248302934UL, 3766709284UL, 3255238414UL, +1434755773UL, 3808719305UL, 3698431827UL, 1958651003UL, 1635042488UL, 303393137UL, 1346302239UL, 3872433842UL, 579487408UL, 3523245944UL, 2853497268UL, 3786573704UL, 3459185849UL, 4183724981UL, 1011238489UL, 3138967488UL, 2973528682UL, 2605373899UL, 3074709397UL, 1044586909UL, 1335670403UL, 1560253777UL, 4069724875UL, 1237099522UL, 608940900UL, 3870707795UL, 4141538580UL, 2550307954UL, 2032507604UL, 728626935UL, 3689191993UL, 1933431212UL, +1177640824UL, 4168589688UL, 1361487780UL, 2649612520UL, 2181448948UL, 2176288560UL, 947907377UL, 3772487849UL, 2002599877UL, 3353450532UL, 2013145251UL, 2357912348UL, 2316997609UL, 2355480213UL, 255142205UL, 751273749UL, 4049362748UL, 1434168014UL, 2069693747UL, 6910933UL, 1352778547UL, 2413649875UL, 4238683558UL, 484497407UL, 522555106UL, 1848417180UL, 3001805499UL, 2264939603UL, 3606143565UL, 1782482647UL, 2955918436UL, 3471474379UL, +2814133839UL, 3779337475UL, 3522102195UL, 1551792178UL, 3742001759UL, 3433504551UL, 472918932UL, 3835854229UL, 4259163014UL, 4103952359UL, 1989474190UL, 1792448078UL, 1517735224UL, 1958036884UL, 2277922531UL, 2856192348UL, 4294188732UL, 2674247971UL, 643649427UL, 3847742408UL, 1512435795UL, 4236693554UL, 1749045838UL, 397093640UL, 2940663643UL, 4156440725UL, 188785143UL, 3894740830UL, 897618321UL, 3333498692UL, 1623924612UL, 4111607062UL, +2242558573UL, 1565861815UL, 1177957654UL, 4129621176UL, 2232443247UL, 3216995984UL, 3313294700UL, 791442469UL, 1782204490UL, 2452634246UL, 1288014576UL, 1347365377UL, 112254281UL, 2044140398UL, 2479591984UL, 3293701920UL, 1062335151UL, 1397230369UL, 2460086085UL, 2412349474UL, 1252633202UL, 3704541545UL, 2132499200UL, 2202058121UL, 1981543691UL, 2683673516UL, 1198109770UL, 4279157703UL, 2224504258UL, 2188868731UL, 769314834UL, 601313429UL, +3595357440UL, 561383123UL, 3444949507UL, 2127327734UL, 2865252582UL, 4181002098UL, 2408426518UL, 309361635UL, 2377703815UL, 1109219406UL, 406287309UL, 1750179098UL, 3619129839UL, 937928728UL, 884423945UL, 928407281UL, 4173634172UL, 1492070114UL, 2706943441UL, 1365883971UL, 3076484301UL, 744370087UL, 4004118884UL, 2199449568UL, 879458863UL, 3197725005UL, 3590586547UL, 59693002UL, 3614114662UL, 1499386564UL, 2914582708UL, 3751842429UL, +947438603UL, 1986129491UL, 3747112289UL, 833777768UL, 2231649410UL, 1841607849UL, 3526253103UL, 3797105813UL, 1291185911UL, 3188408549UL, 3311027691UL, 3983681758UL, 2246511800UL, 1271525377UL, 2996265908UL, 2396071405UL, 902427181UL, 164636454UL, 2459631341UL, 635349368UL, 463309029UL, 1409367654UL, 849052250UL, 3221786769UL, 2310288531UL, 2919204855UL, 1263130532UL, 1215722704UL, 3497322658UL, 2840687222UL, 2185004161UL, 1507335864UL, +}, +{ +2052557448UL, 2879065999UL, 22933757UL, 2160014758UL, 3736092460UL, 3556641619UL, 1350613766UL, 2107757927UL, 309323868UL, 3452852627UL, 3424626316UL, 545651740UL, 1935764720UL, 2349926457UL, 3546577033UL, 862046434UL, 167198649UL, 338290297UL, 1145807303UL, 1571276102UL, 883549156UL, 907871968UL, 638566313UL, 678764227UL, 3795356864UL, 3306095271UL, 1452688488UL, 621126888UL, 1838613968UL, 2054107827UL, 1785040579UL, 454879400UL, +1952849106UL, 1907701866UL, 1639495252UL, 1623968604UL, 2997422000UL, 2633878652UL, 1036670775UL, 2191465943UL, 3053533585UL, 1654709920UL, 1950620393UL, 4177745509UL, 1742007818UL, 2888573892UL, 2825965566UL, 1399790365UL, 1307674482UL, 310692416UL, 384880529UL, 3497622676UL, 1024664651UL, 1541456182UL, 1904670217UL, 1008618602UL, 2816673160UL, 684112698UL, 3332034744UL, 3646613828UL, 962627614UL, 3072103948UL, 3713153075UL, 476323310UL, +3243124597UL, 126319837UL, 2155412848UL, 228580793UL, 2142696490UL, 3442722759UL, 2689599232UL, 426191419UL, 3157759186UL, 100239709UL, 494534049UL, 1259677734UL, 2889209278UL, 1754641396UL, 1057778427UL, 2133253617UL, 1298500018UL, 3340348062UL, 3967049659UL, 2927469144UL, 1503854147UL, 2271956463UL, 3004309866UL, 260248338UL, 2570702480UL, 2067671015UL, 3168497089UL, 361311552UL, 2123195373UL, 2825457193UL, 2599488181UL, 507483626UL, +1201669979UL, 910763802UL, 4158584821UL, 3116016424UL, 3375736126UL, 2857697336UL, 3112473104UL, 2683465481UL, 1495348009UL, 681020485UL, 4044713962UL, 2443109893UL, 129994063UL, 1710251126UL, 820410567UL, 601527649UL, 1007603132UL, 2096580480UL, 1942768885UL, 1984297765UL, 1888157243UL, 960265104UL, 527990410UL, 1572910026UL, 1106822080UL, 1472807331UL, 2465011897UL, 3139401215UL, 3705452371UL, 393081842UL, 3826516196UL, 2576499701UL, +4130037087UL, 4155028170UL, 2188282304UL, 2949056849UL, 1138928618UL, 858751984UL, 3735375571UL, 496972334UL, 830265621UL, 1355757111UL, 909444416UL, 1337622259UL, 2616327935UL, 2337227347UL, 2139876075UL, 4269663356UL, 796316592UL, 1893005585UL, 3958551664UL, 1746456069UL, 2430709714UL, 4025417573UL, 3333292799UL, 1833607331UL, 3864559081UL, 3415700826UL, 3291421244UL, 1987321873UL, 1792851165UL, 505718946UL, 3755903648UL, 3351468604UL, +4035552813UL, 2052557448UL, 2879065999UL, 22933757UL, 2160014758UL, 2321387515UL, 3556641619UL, 1350613766UL, 2107757927UL, 309323868UL, 1850700415UL, 3424626316UL, 545651740UL, 1935764720UL, 2349926457UL, 979047283UL, 862046434UL, 167198649UL, 338290297UL, 1145807303UL, 4201635137UL, 883549156UL, 907871968UL, 638566313UL, 678764227UL, 2637527083UL, 3306095271UL, 1452688488UL, 621126888UL, 1838613968UL, 117966344UL, 1785040579UL, +454879400UL, 1952849106UL, 1907701866UL, 733998186UL, 1623968604UL, 2997422000UL, 2633878652UL, 1036670775UL, 3360491537UL, 3053533585UL, 1654709920UL, 1950620393UL, 4177745509UL, 1716078578UL, 2888573892UL, 2825965566UL, 1399790365UL, 1307674482UL, 2776111761UL, 384880529UL, 3497622676UL, 1024664651UL, 1541456182UL, 618916624UL, 1008618602UL, 2816673160UL, 684112698UL, 3332034744UL, 3340690804UL, 962627614UL, 3072103948UL, 3713153075UL, +476323310UL, 902990902UL, 126319837UL, 2155412848UL, 228580793UL, 2142696490UL, 4254301999UL, 2689599232UL, 426191419UL, 3157759186UL, 100239709UL, 3216403640UL, 1259677734UL, 2889209278UL, 1754641396UL, 1057778427UL, 3221479262UL, 1298500018UL, 3340348062UL, 3967049659UL, 2927469144UL, 3926654939UL, 2271956463UL, 3004309866UL, 260248338UL, 2570702480UL, 1879451653UL, 3168497089UL, 361311552UL, 2123195373UL, 2825457193UL, 341920668UL, +507483626UL, 1201669979UL, 910763802UL, 4158584821UL, 3748705813UL, 3375736126UL, 2857697336UL, 3112473104UL, 2683465481UL, 3336305747UL, 681020485UL, 4044713962UL, 2443109893UL, 129994063UL, 2578353596UL, 820410567UL, 601527649UL, 1007603132UL, 2096580480UL, 3155251071UL, 1984297765UL, 1888157243UL, 960265104UL, 527990410UL, 2548692624UL, 1106822080UL, 1472807331UL, 2465011897UL, 3139401215UL, 736629379UL, 393081842UL, 3826516196UL, +2576499701UL, 4130037087UL, 2440227627UL, 2188282304UL, 2949056849UL, 1138928618UL, 858751984UL, 191805249UL, 496972334UL, 830265621UL, 1355757111UL, 909444416UL, 396738554UL, 2616327935UL, 2337227347UL, 2139876075UL, 4269663356UL, 3932761947UL, 1893005585UL, 3958551664UL, 1746456069UL, 2430709714UL, 3171160829UL, 3333292799UL, 1833607331UL, 3864559081UL, 3415700826UL, 1332800826UL, 1987321873UL, 1792851165UL, 505718946UL, 3755903648UL, +1770588062UL, 4035552813UL, 2052557448UL, 2879065999UL, 22933757UL, 3159941473UL, 2321387515UL, 3556641619UL, 1350613766UL, 2107757927UL, 2669366188UL, 1850700415UL, 3424626316UL, 545651740UL, 1935764720UL, 3252475208UL, 979047283UL, 862046434UL, 167198649UL, 338290297UL, 771814471UL, 4201635137UL, 883549156UL, 907871968UL, 638566313UL, 184144160UL, 2637527083UL, 3306095271UL, 1452688488UL, 621126888UL, 4275587594UL, 117966344UL, +1785040579UL, 454879400UL, 1952849106UL, 3806424990UL, 733998186UL, 1623968604UL, 2997422000UL, 2633878652UL, 2670843077UL, 3360491537UL, 3053533585UL, 1654709920UL, 1950620393UL, 3541927406UL, 1716078578UL, 2888573892UL, 2825965566UL, 1399790365UL, 3184295779UL, 2776111761UL, 384880529UL, 3497622676UL, 1024664651UL, 723804135UL, 618916624UL, 1008618602UL, 2816673160UL, 684112698UL, 3275521308UL, 3340690804UL, 962627614UL, 3072103948UL, +3713153075UL, 2023106558UL, 902990902UL, 126319837UL, 2155412848UL, 228580793UL, 3978575748UL, 4254301999UL, 2689599232UL, 426191419UL, 3157759186UL, 2446138116UL, 3216403640UL, 1259677734UL, 2889209278UL, 1754641396UL, 1706032491UL, 3221479262UL, 1298500018UL, 3340348062UL, 3967049659UL, 3805001240UL, 3926654939UL, 2271956463UL, 3004309866UL, 260248338UL, 294480880UL, 1879451653UL, 3168497089UL, 361311552UL, 2123195373UL, 2080604411UL, +341920668UL, 507483626UL, 1201669979UL, 910763802UL, 2012149356UL, 3748705813UL, 3375736126UL, 2857697336UL, 3112473104UL, 2935748807UL, 3336305747UL, 681020485UL, 4044713962UL, 2443109893UL, 2862982895UL, 2578353596UL, 820410567UL, 601527649UL, 1007603132UL, 1890290066UL, 3155251071UL, 1984297765UL, 1888157243UL, 960265104UL, 41870487UL, 2548692624UL, 1106822080UL, 1472807331UL, 2465011897UL, 2382974023UL, 736629379UL, 393081842UL, +3826516196UL, 2576499701UL, 4219335149UL, 2440227627UL, 2188282304UL, 2949056849UL, 1138928618UL, 3785297102UL, 191805249UL, 496972334UL, 830265621UL, 1355757111UL, 3962907313UL, 396738554UL, 2616327935UL, 2337227347UL, 2139876075UL, 552154011UL, 3932761947UL, 1893005585UL, 3958551664UL, 1746456069UL, 895507243UL, 3171160829UL, 3333292799UL, 1833607331UL, 3864559081UL, 3564325554UL, 1332800826UL, 1987321873UL, 1792851165UL, 505718946UL, +3245448088UL, 1770588062UL, 4035552813UL, 2052557448UL, 2879065999UL, 3602157977UL, 3159941473UL, 2321387515UL, 3556641619UL, 1350613766UL, 4101259055UL, 2669366188UL, 1850700415UL, 3424626316UL, 545651740UL, 2873707882UL, 3252475208UL, 979047283UL, 862046434UL, 167198649UL, 654196140UL, 771814471UL, 4201635137UL, 883549156UL, 907871968UL, 191965184UL, 184144160UL, 2637527083UL, 3306095271UL, 1452688488UL, 1562736568UL, 4275587594UL, +117966344UL, 1785040579UL, 454879400UL, 3484019450UL, 3806424990UL, 733998186UL, 1623968604UL, 2997422000UL, 273316614UL, 2670843077UL, 3360491537UL, 3053533585UL, 1654709920UL, 591311873UL, 3541927406UL, 1716078578UL, 2888573892UL, 2825965566UL, 2277117038UL, 3184295779UL, 2776111761UL, 384880529UL, 3497622676UL, 1086566797UL, 723804135UL, 618916624UL, 1008618602UL, 2816673160UL, 3344392942UL, 3275521308UL, 3340690804UL, 962627614UL, +3072103948UL, 2910444460UL, 2023106558UL, 902990902UL, 126319837UL, 2155412848UL, 337119596UL, 3978575748UL, 4254301999UL, 2689599232UL, 426191419UL, 3471778695UL, 2446138116UL, 3216403640UL, 1259677734UL, 2889209278UL, 4102983766UL, 1706032491UL, 3221479262UL, 1298500018UL, 3340348062UL, 2940293024UL, 3805001240UL, 3926654939UL, 2271956463UL, 3004309866UL, 3634668003UL, 294480880UL, 1879451653UL, 3168497089UL, 361311552UL, 3417679321UL, +2080604411UL, 341920668UL, 507483626UL, 1201669979UL, 3174274528UL, 2012149356UL, 3748705813UL, 3375736126UL, 2857697336UL, 3929686609UL, 2935748807UL, 3336305747UL, 681020485UL, 4044713962UL, 405011299UL, 2862982895UL, 2578353596UL, 820410567UL, 601527649UL, 4281957726UL, 1890290066UL, 3155251071UL, 1984297765UL, 1888157243UL, 1978308818UL, 41870487UL, 2548692624UL, 1106822080UL, 1472807331UL, 3701147046UL, 2382974023UL, 736629379UL, +393081842UL, 3826516196UL, 3225163595UL, 4219335149UL, 2440227627UL, 2188282304UL, 2949056849UL, 3894577191UL, 3785297102UL, 191805249UL, 496972334UL, 830265621UL, 4293577013UL, 3962907313UL, 396738554UL, 2616327935UL, 2337227347UL, 3701032380UL, 552154011UL, 3932761947UL, 1893005585UL, 3958551664UL, 4148575672UL, 895507243UL, 3171160829UL, 3333292799UL, 1833607331UL, 1596419195UL, 3564325554UL, 1332800826UL, 1987321873UL, 1792851165UL, +3663406943UL, 3892533309UL, 247565591UL, 953356243UL, 4103354183UL, 1908418768UL, 3915294912UL, 2390669489UL, 3865260287UL, 1818313429UL, 557880278UL, 2499771815UL, 2618380525UL, 732785004UL, 1414011135UL, 2858311749UL, 3871596970UL, 2428464498UL, 645476041UL, 683035653UL, 4079609082UL, 2404111028UL, 3332056297UL, 3054547484UL, 3616426087UL, 1311379849UL, 3682136336UL, 3795847093UL, 1509718393UL, 541389178UL, 1103876446UL, 2549442278UL, +3656600574UL, 3019560735UL, 523610761UL, 3889482885UL, 3080739216UL, 2359120072UL, 1034857006UL, 63567637UL, 1520176098UL, 1741685274UL, 2330217396UL, 1429674399UL, 517809884UL, 2653145241UL, 868296581UL, 646514407UL, 3166145188UL, 3023629813UL, 2333851648UL, 2967365394UL, 1828821737UL, 3333092181UL, 445460259UL, 2682093551UL, 3655100102UL, 2592872076UL, 1588368999UL, 3964958220UL, 755397374UL, 1912970603UL, 396253754UL, 4260038354UL, +1530898510UL, 2396805917UL, 3327501452UL, 4235709361UL, 2762163349UL, 553869167UL, 3162483580UL, 1611891352UL, 248738605UL, 3403092967UL, 2194464420UL, 113420452UL, 1752444845UL, 3770903547UL, 2397481985UL, 2866414964UL, 2555678075UL, 2796010061UL, 762034588UL, 2679383682UL, 1848516655UL, 3857720381UL, 1119111363UL, 1829110546UL, 2183620391UL, 1743838702UL, 3363053704UL, 2212810289UL, 966205413UL, 3897281091UL, 2148139678UL, 2690229390UL, +427450194UL, 3516115778UL, 1864991059UL, 134448489UL, 3397232480UL, 3999530682UL, 1927036992UL, 3170864927UL, 3879295489UL, 134554462UL, 3447324105UL, 86678510UL, 1656551206UL, 2844494044UL, 2469678938UL, 2885597732UL, 2715483555UL, 3566904604UL, 462585182UL, 1922457093UL, 3035264235UL, 2866504077UL, 2031456720UL, 1598555964UL, 2569915450UL, 3947972758UL, 290683210UL, 2465427488UL, 3504862176UL, 793156806UL, 1722326752UL, 2706215067UL, +3818976191UL, 2007064241UL, 552144413UL, 2692866408UL, 3975075075UL, 4293828741UL, 1123460373UL, 960845744UL, 1855626484UL, 1876934434UL, 1343778249UL, 912185207UL, 127278206UL, 4168930635UL, 340393978UL, 65814528UL, 2552086271UL, 2507474816UL, 1240220220UL, 1761964455UL, 2204917500UL, 4088965101UL, 1079310398UL, 3071460742UL, 2188549805UL, 1064733776UL, 4191719087UL, 3221046115UL, 3772395288UL, 883516842UL, 2077853840UL, 229484673UL, +}, +{ +448889887UL, 3508620909UL, 4164289950UL, 155254859UL, 298319697UL, 980080883UL, 3500794888UL, 3974907245UL, 682778656UL, 382798811UL, 1500342771UL, 3942535492UL, 1039809505UL, 2126581011UL, 561192171UL, 4046277638UL, 840733718UL, 1694555864UL, 241216466UL, 4182349979UL, 2525929010UL, 386794637UL, 349755829UL, 2959959729UL, 686974318UL, 3243688353UL, 3911051908UL, 3917458620UL, 441833800UL, 3164548257UL, 584185450UL, 450132281UL, +3528356519UL, 4275666503UL, 1317069624UL, 817077137UL, 2945430988UL, 1532878265UL, 2542155552UL, 3348614029UL, 1419611574UL, 1245233100UL, 1981161828UL, 1161647342UL, 2781439556UL, 3896025436UL, 2349200248UL, 1213899699UL, 860301545UL, 1590934964UL, 3371591516UL, 2850926464UL, 2774569126UL, 907316453UL, 3541736952UL, 3572719697UL, 278602945UL, 4257620354UL, 3396349537UL, 3144949411UL, 191271983UL, 2974056951UL, 2743594803UL, 1119054633UL, +815666748UL, 920991498UL, 187861899UL, 2008325469UL, 1548504646UL, 3749744762UL, 993523345UL, 1171349070UL, 4105576982UL, 1559471848UL, 2656434170UL, 2795453957UL, 3357293755UL, 4260164297UL, 2211998873UL, 1783238785UL, 2831224398UL, 1704939914UL, 2626903427UL, 1148581053UL, 849777796UL, 4219173763UL, 694869701UL, 1297370017UL, 3573985711UL, 1739242781UL, 3680794431UL, 400850360UL, 909653264UL, 1496585542UL, 460982606UL, 828640603UL, +3993062500UL, 2145047281UL, 1587836828UL, 912583500UL, 1234319994UL, 4276951314UL, 485282908UL, 1903750880UL, 1667769214UL, 3950976882UL, 3711912938UL, 3626058764UL, 627857875UL, 436470402UL, 1753727232UL, 50241405UL, 206782941UL, 612110492UL, 954016857UL, 2567547031UL, 3360482779UL, 820704062UL, 412722485UL, 2044763466UL, 1915626743UL, 2703000434UL, 2755090057UL, 53587450UL, 2457122208UL, 1397065983UL, 2822294224UL, 3024827428UL, +2201149820UL, 699377793UL, 157099022UL, 2792298089UL, 3927835437UL, 1095494739UL, 1230723791UL, 2740420278UL, 2518077381UL, 3674832547UL, 2375246835UL, 923451748UL, 3665432731UL, 1577970518UL, 2643388181UL, 4050379756UL, 1145072065UL, 1632232822UL, 2365350332UL, 1126185680UL, 930842061UL, 3816331201UL, 1624573114UL, 3809118349UL, 1187817320UL, 945407897UL, 63630679UL, 1852369563UL, 971772965UL, 2229069035UL, 2320405193UL, 3474864049UL, +1666937976UL, 448889887UL, 3508620909UL, 4164289950UL, 155254859UL, 3157319819UL, 980080883UL, 3500794888UL, 3974907245UL, 682778656UL, 3201604042UL, 1500342771UL, 3942535492UL, 1039809505UL, 2126581011UL, 3235144326UL, 4046277638UL, 840733718UL, 1694555864UL, 241216466UL, 2728337326UL, 2525929010UL, 386794637UL, 349755829UL, 2959959729UL, 20820947UL, 3243688353UL, 3911051908UL, 3917458620UL, 441833800UL, 4143649787UL, 584185450UL, +450132281UL, 3528356519UL, 4275666503UL, 3541347868UL, 817077137UL, 2945430988UL, 1532878265UL, 2542155552UL, 3199458552UL, 1419611574UL, 1245233100UL, 1981161828UL, 1161647342UL, 958085276UL, 3896025436UL, 2349200248UL, 1213899699UL, 860301545UL, 1701089635UL, 3371591516UL, 2850926464UL, 2774569126UL, 907316453UL, 1529987826UL, 3572719697UL, 278602945UL, 4257620354UL, 3396349537UL, 4120000342UL, 191271983UL, 2974056951UL, 2743594803UL, +1119054633UL, 4255116655UL, 920991498UL, 187861899UL, 2008325469UL, 1548504646UL, 100038488UL, 993523345UL, 1171349070UL, 4105576982UL, 1559471848UL, 2523523381UL, 2795453957UL, 3357293755UL, 4260164297UL, 2211998873UL, 3644225670UL, 2831224398UL, 1704939914UL, 2626903427UL, 1148581053UL, 1292003378UL, 4219173763UL, 694869701UL, 1297370017UL, 3573985711UL, 2510138592UL, 3680794431UL, 400850360UL, 909653264UL, 1496585542UL, 1738256576UL, +828640603UL, 3993062500UL, 2145047281UL, 1587836828UL, 3478998519UL, 1234319994UL, 4276951314UL, 485282908UL, 1903750880UL, 746205619UL, 3950976882UL, 3711912938UL, 3626058764UL, 627857875UL, 954627753UL, 1753727232UL, 50241405UL, 206782941UL, 612110492UL, 2251018875UL, 2567547031UL, 3360482779UL, 820704062UL, 412722485UL, 2120077037UL, 1915626743UL, 2703000434UL, 2755090057UL, 53587450UL, 2696843657UL, 1397065983UL, 2822294224UL, +3024827428UL, 2201149820UL, 3308142895UL, 157099022UL, 2792298089UL, 3927835437UL, 1095494739UL, 730099534UL, 2740420278UL, 2518077381UL, 3674832547UL, 2375246835UL, 2126745526UL, 3665432731UL, 1577970518UL, 2643388181UL, 4050379756UL, 2987545029UL, 1632232822UL, 2365350332UL, 1126185680UL, 930842061UL, 3140947362UL, 1624573114UL, 3809118349UL, 1187817320UL, 945407897UL, 1282799903UL, 1852369563UL, 971772965UL, 2229069035UL, 2320405193UL, +670134249UL, 1666937976UL, 448889887UL, 3508620909UL, 4164289950UL, 127045110UL, 3157319819UL, 980080883UL, 3500794888UL, 3974907245UL, 2740953010UL, 3201604042UL, 1500342771UL, 3942535492UL, 1039809505UL, 306788856UL, 3235144326UL, 4046277638UL, 840733718UL, 1694555864UL, 2260304655UL, 2728337326UL, 2525929010UL, 386794637UL, 349755829UL, 3842816805UL, 20820947UL, 3243688353UL, 3911051908UL, 3917458620UL, 3398227861UL, 4143649787UL, +584185450UL, 450132281UL, 3528356519UL, 550401017UL, 3541347868UL, 817077137UL, 2945430988UL, 1532878265UL, 1045681234UL, 3199458552UL, 1419611574UL, 1245233100UL, 1981161828UL, 1153297031UL, 958085276UL, 3896025436UL, 2349200248UL, 1213899699UL, 1451842347UL, 1701089635UL, 3371591516UL, 2850926464UL, 2774569126UL, 1269128107UL, 1529987826UL, 3572719697UL, 278602945UL, 4257620354UL, 2479560493UL, 4120000342UL, 191271983UL, 2974056951UL, +2743594803UL, 4081110580UL, 4255116655UL, 920991498UL, 187861899UL, 2008325469UL, 1300371976UL, 100038488UL, 993523345UL, 1171349070UL, 4105576982UL, 3010753279UL, 2523523381UL, 2795453957UL, 3357293755UL, 4260164297UL, 207153762UL, 3644225670UL, 2831224398UL, 1704939914UL, 2626903427UL, 916783095UL, 1292003378UL, 4219173763UL, 694869701UL, 1297370017UL, 3388725608UL, 2510138592UL, 3680794431UL, 400850360UL, 909653264UL, 2421730678UL, +1738256576UL, 828640603UL, 3993062500UL, 2145047281UL, 2123619770UL, 3478998519UL, 1234319994UL, 4276951314UL, 485282908UL, 4002661777UL, 746205619UL, 3950976882UL, 3711912938UL, 3626058764UL, 1230937254UL, 954627753UL, 1753727232UL, 50241405UL, 206782941UL, 460314337UL, 2251018875UL, 2567547031UL, 3360482779UL, 820704062UL, 1339598718UL, 2120077037UL, 1915626743UL, 2703000434UL, 2755090057UL, 660730207UL, 2696843657UL, 1397065983UL, +2822294224UL, 3024827428UL, 126840648UL, 3308142895UL, 157099022UL, 2792298089UL, 3927835437UL, 2192535935UL, 730099534UL, 2740420278UL, 2518077381UL, 3674832547UL, 1879512787UL, 2126745526UL, 3665432731UL, 1577970518UL, 2643388181UL, 832572764UL, 2987545029UL, 1632232822UL, 2365350332UL, 1126185680UL, 3248646182UL, 3140947362UL, 1624573114UL, 3809118349UL, 1187817320UL, 4270855000UL, 1282799903UL, 1852369563UL, 971772965UL, 2229069035UL, +3735782785UL, 670134249UL, 1666937976UL, 448889887UL, 3508620909UL, 3681408470UL, 127045110UL, 3157319819UL, 980080883UL, 3500794888UL, 3967872553UL, 2740953010UL, 3201604042UL, 1500342771UL, 3942535492UL, 613854690UL, 306788856UL, 3235144326UL, 4046277638UL, 840733718UL, 3957877023UL, 2260304655UL, 2728337326UL, 2525929010UL, 386794637UL, 1779451936UL, 3842816805UL, 20820947UL, 3243688353UL, 3911051908UL, 688470429UL, 3398227861UL, +4143649787UL, 584185450UL, 450132281UL, 3381050556UL, 550401017UL, 3541347868UL, 817077137UL, 2945430988UL, 1859551669UL, 1045681234UL, 3199458552UL, 1419611574UL, 1245233100UL, 53681099UL, 1153297031UL, 958085276UL, 3896025436UL, 2349200248UL, 1796144514UL, 1451842347UL, 1701089635UL, 3371591516UL, 2850926464UL, 1337394836UL, 1269128107UL, 1529987826UL, 3572719697UL, 278602945UL, 46913829UL, 2479560493UL, 4120000342UL, 191271983UL, +2974056951UL, 1361976701UL, 4081110580UL, 4255116655UL, 920991498UL, 187861899UL, 1237191391UL, 1300371976UL, 100038488UL, 993523345UL, 1171349070UL, 3168325479UL, 3010753279UL, 2523523381UL, 2795453957UL, 3357293755UL, 2142853843UL, 207153762UL, 3644225670UL, 2831224398UL, 1704939914UL, 2369686128UL, 916783095UL, 1292003378UL, 4219173763UL, 694869701UL, 4150182218UL, 3388725608UL, 2510138592UL, 3680794431UL, 400850360UL, 654034492UL, +2421730678UL, 1738256576UL, 828640603UL, 3993062500UL, 84735560UL, 2123619770UL, 3478998519UL, 1234319994UL, 4276951314UL, 2545204994UL, 4002661777UL, 746205619UL, 3950976882UL, 3711912938UL, 426068544UL, 1230937254UL, 954627753UL, 1753727232UL, 50241405UL, 589286339UL, 460314337UL, 2251018875UL, 2567547031UL, 3360482779UL, 3279873953UL, 1339598718UL, 2120077037UL, 1915626743UL, 2703000434UL, 2720159887UL, 660730207UL, 2696843657UL, +1397065983UL, 2822294224UL, 3536645029UL, 126840648UL, 3308142895UL, 157099022UL, 2792298089UL, 485214530UL, 2192535935UL, 730099534UL, 2740420278UL, 2518077381UL, 418832171UL, 1879512787UL, 2126745526UL, 3665432731UL, 1577970518UL, 721018UL, 832572764UL, 2987545029UL, 1632232822UL, 2365350332UL, 1769688764UL, 3248646182UL, 3140947362UL, 1624573114UL, 3809118349UL, 3561012744UL, 4270855000UL, 1282799903UL, 1852369563UL, 971772965UL, +2160782957UL, 105464019UL, 2131462864UL, 335205049UL, 3271229551UL, 1374396416UL, 4269753677UL, 1984596635UL, 37563880UL, 3956352262UL, 2168603656UL, 311623712UL, 1593371323UL, 351020595UL, 3439337532UL, 3130874657UL, 3613343327UL, 695789539UL, 609797513UL, 53642143UL, 1479027519UL, 1588831722UL, 262810641UL, 3418379977UL, 530167431UL, 1962487963UL, 2410103328UL, 3360114680UL, 3548827677UL, 2735238248UL, 2136058369UL, 4013192489UL, +4106245442UL, 2155966460UL, 3653971354UL, 1230293148UL, 3966689348UL, 3455336684UL, 3594979856UL, 3178937309UL, 3983796170UL, 3617590004UL, 1727358326UL, 1121418876UL, 1022562029UL, 2437823131UL, 2733424381UL, 452731958UL, 2983755220UL, 1674750403UL, 3110921909UL, 3514365950UL, 2193238341UL, 2073801740UL, 669573402UL, 1824298084UL, 22336337UL, 3366446304UL, 1536043612UL, 2502297553UL, 1409641611UL, 2399583184UL, 2593245170UL, 716832039UL, +4286149460UL, 814849965UL, 4239224908UL, 2453627262UL, 976385355UL, 1846129423UL, 52096201UL, 88835472UL, 2621770794UL, 2491757130UL, 1849417480UL, 576668065UL, 2186701850UL, 3357019214UL, 442191324UL, 3662645846UL, 3653766782UL, 2254203663UL, 1169821059UL, 3735427676UL, 2246044748UL, 2635264668UL, 2647842566UL, 1435695450UL, 1658777934UL, 2927080369UL, 1341088646UL, 3565982642UL, 221661496UL, 3246988243UL, 2718455491UL, 483517148UL, +4181332651UL, 1143646375UL, 1720449423UL, 331164544UL, 539836322UL, 3485371630UL, 1110077273UL, 4088985694UL, 145720169UL, 2382276586UL, 4276410795UL, 2051956774UL, 936524156UL, 15415192UL, 1815949694UL, 272696290UL, 1495465483UL, 3102030383UL, 3546078241UL, 3272619595UL, 759699322UL, 1161486824UL, 1146281812UL, 4194130649UL, 3936306436UL, 4077338125UL, 2127551216UL, 2995077453UL, 209698652UL, 3836657987UL, 1782152220UL, 1642490089UL, +3695579542UL, 537862234UL, 1696168156UL, 4022607UL, 3642864269UL, 54404878UL, 2925910542UL, 3444042482UL, 1931288691UL, 2269375687UL, 614870298UL, 1139082272UL, 3672546472UL, 3255845763UL, 2987873616UL, 3436501734UL, 380553853UL, 750118352UL, 750708138UL, 488564982UL, 2936846643UL, 3460652101UL, 3085496886UL, 3734224010UL, 523359404UL, 2751912206UL, 3302219188UL, 2729509827UL, 1995554251UL, 2288103059UL, 3289667468UL, 2860301591UL, +}, +{ +3481653941UL, 2111903071UL, 3569014882UL, 1149634763UL, 4206972571UL, 2948781360UL, 2576820949UL, 2587099571UL, 3987042644UL, 4255777336UL, 2829594348UL, 3832744490UL, 3554499754UL, 787920018UL, 695635693UL, 2746034685UL, 2078139227UL, 1144320548UL, 4020978225UL, 449503505UL, 3004993826UL, 2045843139UL, 1604631401UL, 148449881UL, 457819243UL, 4089112489UL, 1713441237UL, 1790909556UL, 3334464951UL, 3070008305UL, 811825474UL, 4089105370UL, +708239097UL, 1494832299UL, 2074902973UL, 468898217UL, 1722559700UL, 2499754488UL, 2267939270UL, 650114709UL, 549502184UL, 4040463514UL, 4228169080UL, 4094284819UL, 1599334548UL, 2992525399UL, 2107053637UL, 197348940UL, 1669884894UL, 3982326753UL, 4259099320UL, 1862793542UL, 1751219817UL, 2701271514UL, 2507353222UL, 1488339939UL, 4246544316UL, 3978321870UL, 132720476UL, 3020305599UL, 154822619UL, 2595474066UL, 1654579304UL, 1997335204UL, +891320674UL, 3153502700UL, 601607977UL, 2695457160UL, 4137981809UL, 37584248UL, 1674050253UL, 1805619463UL, 676369068UL, 2294902904UL, 658143166UL, 141452045UL, 2383327493UL, 1222336195UL, 2628962123UL, 2378299402UL, 2724274090UL, 1783957650UL, 453206569UL, 3190116972UL, 1480368955UL, 1145768764UL, 3628222572UL, 3108689607UL, 182547022UL, 360165920UL, 3378423016UL, 1443723222UL, 2843274258UL, 1597581683UL, 664283285UL, 258077235UL, +3071875976UL, 240688930UL, 988895736UL, 2965351284UL, 91332032UL, 941306162UL, 2464278288UL, 3493666272UL, 2437043750UL, 2356658919UL, 24726067UL, 3025656863UL, 1343636659UL, 2408295270UL, 3097408183UL, 461428710UL, 2449005423UL, 3220070834UL, 1418517867UL, 907095008UL, 428073188UL, 1938061314UL, 2094361729UL, 2570445990UL, 346999411UL, 990247709UL, 1630488660UL, 2574142591UL, 1466590284UL, 1906935236UL, 1592544037UL, 4168163186UL, +2773942807UL, 939392801UL, 1610069434UL, 1935303983UL, 2962954128UL, 2490925509UL, 4103025390UL, 3614258069UL, 174125899UL, 4113855120UL, 2449365101UL, 3384244363UL, 4115219971UL, 3187664453UL, 4021992190UL, 2959372973UL, 2946571025UL, 2144945539UL, 388172915UL, 1125615727UL, 881693338UL, 3313110562UL, 859388069UL, 177786360UL, 4134747901UL, 616417204UL, 2104495620UL, 783302897UL, 512784708UL, 1295821322UL, 3810209448UL, 2966899912UL, +2390608767UL, 3481653941UL, 2111903071UL, 3569014882UL, 1149634763UL, 1385372463UL, 2948781360UL, 2576820949UL, 2587099571UL, 3987042644UL, 2251144849UL, 2829594348UL, 3832744490UL, 3554499754UL, 787920018UL, 73007125UL, 2746034685UL, 2078139227UL, 1144320548UL, 4020978225UL, 2729117517UL, 3004993826UL, 2045843139UL, 1604631401UL, 148449881UL, 3343221736UL, 4089112489UL, 1713441237UL, 1790909556UL, 3334464951UL, 1920962856UL, 811825474UL, +4089105370UL, 708239097UL, 1494832299UL, 2485576001UL, 468898217UL, 1722559700UL, 2499754488UL, 2267939270UL, 2271486862UL, 549502184UL, 4040463514UL, 4228169080UL, 4094284819UL, 3177940420UL, 2992525399UL, 2107053637UL, 197348940UL, 1669884894UL, 3596140613UL, 4259099320UL, 1862793542UL, 1751219817UL, 2701271514UL, 1357847339UL, 1488339939UL, 4246544316UL, 3978321870UL, 132720476UL, 344033794UL, 154822619UL, 2595474066UL, 1654579304UL, +1997335204UL, 1849659590UL, 3153502700UL, 601607977UL, 2695457160UL, 4137981809UL, 3559496104UL, 1674050253UL, 1805619463UL, 676369068UL, 2294902904UL, 1583197657UL, 141452045UL, 2383327493UL, 1222336195UL, 2628962123UL, 3486106126UL, 2724274090UL, 1783957650UL, 453206569UL, 3190116972UL, 1939413704UL, 1145768764UL, 3628222572UL, 3108689607UL, 182547022UL, 2911760834UL, 3378423016UL, 1443723222UL, 2843274258UL, 1597581683UL, 3599911248UL, +258077235UL, 3071875976UL, 240688930UL, 988895736UL, 4263328855UL, 91332032UL, 941306162UL, 2464278288UL, 3493666272UL, 1561559932UL, 2356658919UL, 24726067UL, 3025656863UL, 1343636659UL, 257301433UL, 3097408183UL, 461428710UL, 2449005423UL, 3220070834UL, 3544357262UL, 907095008UL, 428073188UL, 1938061314UL, 2094361729UL, 4112109825UL, 346999411UL, 990247709UL, 1630488660UL, 2574142591UL, 1466763688UL, 1906935236UL, 1592544037UL, +4168163186UL, 2773942807UL, 3608227467UL, 1610069434UL, 1935303983UL, 2962954128UL, 2490925509UL, 825197245UL, 3614258069UL, 174125899UL, 4113855120UL, 2449365101UL, 167881680UL, 4115219971UL, 3187664453UL, 4021992190UL, 2959372973UL, 1971633162UL, 2144945539UL, 388172915UL, 1125615727UL, 881693338UL, 223946687UL, 859388069UL, 177786360UL, 4134747901UL, 616417204UL, 722598357UL, 783302897UL, 512784708UL, 1295821322UL, 3810209448UL, +1589703161UL, 2390608767UL, 3481653941UL, 2111903071UL, 3569014882UL, 2520719089UL, 1385372463UL, 2948781360UL, 2576820949UL, 2587099571UL, 1427210741UL, 2251144849UL, 2829594348UL, 3832744490UL, 3554499754UL, 1257461820UL, 73007125UL, 2746034685UL, 2078139227UL, 1144320548UL, 3065859797UL, 2729117517UL, 3004993826UL, 2045843139UL, 1604631401UL, 36092756UL, 3343221736UL, 4089112489UL, 1713441237UL, 1790909556UL, 1504385586UL, 1920962856UL, +811825474UL, 4089105370UL, 708239097UL, 4135459720UL, 2485576001UL, 468898217UL, 1722559700UL, 2499754488UL, 1392696606UL, 2271486862UL, 549502184UL, 4040463514UL, 4228169080UL, 2521060775UL, 3177940420UL, 2992525399UL, 2107053637UL, 197348940UL, 4225425195UL, 3596140613UL, 4259099320UL, 1862793542UL, 1751219817UL, 3752827533UL, 1357847339UL, 1488339939UL, 4246544316UL, 3978321870UL, 270743120UL, 344033794UL, 154822619UL, 2595474066UL, +1654579304UL, 986127123UL, 1849659590UL, 3153502700UL, 601607977UL, 2695457160UL, 437034992UL, 3559496104UL, 1674050253UL, 1805619463UL, 676369068UL, 956939381UL, 1583197657UL, 141452045UL, 2383327493UL, 1222336195UL, 3287498300UL, 3486106126UL, 2724274090UL, 1783957650UL, 453206569UL, 3610364652UL, 1939413704UL, 1145768764UL, 3628222572UL, 3108689607UL, 708259891UL, 2911760834UL, 3378423016UL, 1443723222UL, 2843274258UL, 1498209005UL, +3599911248UL, 258077235UL, 3071875976UL, 240688930UL, 3815218922UL, 4263328855UL, 91332032UL, 941306162UL, 2464278288UL, 3018835600UL, 1561559932UL, 2356658919UL, 24726067UL, 3025656863UL, 368313673UL, 257301433UL, 3097408183UL, 461428710UL, 2449005423UL, 3690066046UL, 3544357262UL, 907095008UL, 428073188UL, 1938061314UL, 2274317748UL, 4112109825UL, 346999411UL, 990247709UL, 1630488660UL, 1584471638UL, 1466763688UL, 1906935236UL, +1592544037UL, 4168163186UL, 473837206UL, 3608227467UL, 1610069434UL, 1935303983UL, 2962954128UL, 391171548UL, 825197245UL, 3614258069UL, 174125899UL, 4113855120UL, 2095676907UL, 167881680UL, 4115219971UL, 3187664453UL, 4021992190UL, 4246237180UL, 1971633162UL, 2144945539UL, 388172915UL, 1125615727UL, 3158677395UL, 223946687UL, 859388069UL, 177786360UL, 4134747901UL, 4017781965UL, 722598357UL, 783302897UL, 512784708UL, 1295821322UL, +3908594844UL, 1589703161UL, 2390608767UL, 3481653941UL, 2111903071UL, 2713757719UL, 2520719089UL, 1385372463UL, 2948781360UL, 2576820949UL, 638075690UL, 1427210741UL, 2251144849UL, 2829594348UL, 3832744490UL, 2871270139UL, 1257461820UL, 73007125UL, 2746034685UL, 2078139227UL, 1974062189UL, 3065859797UL, 2729117517UL, 3004993826UL, 2045843139UL, 772058252UL, 36092756UL, 3343221736UL, 4089112489UL, 1713441237UL, 2172680702UL, 1504385586UL, +1920962856UL, 811825474UL, 4089105370UL, 1822881146UL, 4135459720UL, 2485576001UL, 468898217UL, 1722559700UL, 3429640856UL, 1392696606UL, 2271486862UL, 549502184UL, 4040463514UL, 3072935276UL, 2521060775UL, 3177940420UL, 2992525399UL, 2107053637UL, 1114377646UL, 4225425195UL, 3596140613UL, 4259099320UL, 1862793542UL, 1439724658UL, 3752827533UL, 1357847339UL, 1488339939UL, 4246544316UL, 1051119047UL, 270743120UL, 344033794UL, 154822619UL, +2595474066UL, 3143800435UL, 986127123UL, 1849659590UL, 3153502700UL, 601607977UL, 2334441739UL, 437034992UL, 3559496104UL, 1674050253UL, 1805619463UL, 455274178UL, 956939381UL, 1583197657UL, 141452045UL, 2383327493UL, 1520979444UL, 3287498300UL, 3486106126UL, 2724274090UL, 1783957650UL, 2212706740UL, 3610364652UL, 1939413704UL, 1145768764UL, 3628222572UL, 2719501850UL, 708259891UL, 2911760834UL, 3378423016UL, 1443723222UL, 2678486648UL, +1498209005UL, 3599911248UL, 258077235UL, 3071875976UL, 513762712UL, 3815218922UL, 4263328855UL, 91332032UL, 941306162UL, 3000922309UL, 3018835600UL, 1561559932UL, 2356658919UL, 24726067UL, 3626352172UL, 368313673UL, 257301433UL, 3097408183UL, 461428710UL, 2370224855UL, 3690066046UL, 3544357262UL, 907095008UL, 428073188UL, 2279237523UL, 2274317748UL, 4112109825UL, 346999411UL, 990247709UL, 896290404UL, 1584471638UL, 1466763688UL, +1906935236UL, 1592544037UL, 2387522308UL, 473837206UL, 3608227467UL, 1610069434UL, 1935303983UL, 4120978868UL, 391171548UL, 825197245UL, 3614258069UL, 174125899UL, 2940674123UL, 2095676907UL, 167881680UL, 4115219971UL, 3187664453UL, 456143482UL, 4246237180UL, 1971633162UL, 2144945539UL, 388172915UL, 4041481385UL, 3158677395UL, 223946687UL, 859388069UL, 177786360UL, 3094936989UL, 4017781965UL, 722598357UL, 783302897UL, 512784708UL, +4078350595UL, 2002159085UL, 3374931831UL, 1327513052UL, 4231642441UL, 2398594140UL, 2750176655UL, 2377078716UL, 3051451207UL, 2923556938UL, 392203913UL, 970480700UL, 1611278056UL, 1212903807UL, 85815670UL, 2398261756UL, 1052760308UL, 175807153UL, 2617028873UL, 1862087601UL, 1824020594UL, 3770624867UL, 141863380UL, 2090619424UL, 3994019338UL, 2363183556UL, 3095139522UL, 1792884692UL, 3026343485UL, 2320955816UL, 145789343UL, 214170401UL, +2926373126UL, 3858640613UL, 2188241463UL, 459887603UL, 2117474937UL, 2514234285UL, 1454156613UL, 1675396814UL, 4188979068UL, 1584843874UL, 3594779833UL, 563029256UL, 28681425UL, 446949770UL, 3498545218UL, 435874305UL, 3448653884UL, 863509898UL, 2247299904UL, 4211345429UL, 971855563UL, 1475394960UL, 3401692834UL, 167361776UL, 496249436UL, 1465278889UL, 780336162UL, 2108770597UL, 1806981510UL, 3677875653UL, 1890122303UL, 16399665UL, +2747394159UL, 2098019492UL, 1597583332UL, 1763649529UL, 1286079969UL, 1846278877UL, 1016796923UL, 959676917UL, 3091540766UL, 1626192266UL, 780987350UL, 1102963422UL, 2507002232UL, 691766944UL, 193328868UL, 981596600UL, 2384820612UL, 3149668778UL, 1691569420UL, 2852237957UL, 893819979UL, 2572584243UL, 216077070UL, 1267249886UL, 2572508880UL, 1706489454UL, 2391561733UL, 2608477467UL, 209783612UL, 765896849UL, 3617020328UL, 3488800100UL, +2237655981UL, 2095308189UL, 963275857UL, 3563488318UL, 1865487834UL, 480006810UL, 18562439UL, 1025913188UL, 3368592397UL, 374648713UL, 2421713724UL, 2705651398UL, 3098059650UL, 1109934605UL, 3085839620UL, 3184266772UL, 2359972463UL, 862934481UL, 3624479194UL, 3574284465UL, 2700143837UL, 2468083868UL, 3798800988UL, 4116964911UL, 1832002264UL, 4276154871UL, 3256889524UL, 4036954281UL, 697729046UL, 886223984UL, 2196986730UL, 1157617208UL, +1995907944UL, 398452318UL, 3523714364UL, 613570866UL, 2962430983UL, 1408814780UL, 892117129UL, 4173164219UL, 3894076479UL, 2721348430UL, 555734931UL, 1869034419UL, 336114876UL, 3142554871UL, 3349604636UL, 3450290892UL, 955122895UL, 2202902910UL, 2558366468UL, 1701182712UL, 283197682UL, 1865942385UL, 2027648778UL, 2285857699UL, 880475184UL, 958651279UL, 169534250UL, 3842420528UL, 1568559789UL, 2986618464UL, 2568345525UL, 3081082692UL, +}, +{ +575494427UL, 2773243709UL, 4009191487UL, 3877909663UL, 2252044261UL, 1328043370UL, 1407136778UL, 3204434425UL, 3881653592UL, 1481049819UL, 2939203697UL, 889352935UL, 628666312UL, 165199023UL, 2949092155UL, 1116804589UL, 998930334UL, 4144153491UL, 4191022348UL, 9022505UL, 4033326555UL, 2329569601UL, 824756145UL, 3501916851UL, 1481410328UL, 1970954319UL, 4022176157UL, 2356841052UL, 3783173734UL, 3649102345UL, 3205430658UL, 1460938436UL, +280282398UL, 3262135457UL, 4055383786UL, 28522973UL, 1100901182UL, 4048609665UL, 994490185UL, 2888527367UL, 3591919750UL, 65093467UL, 399797207UL, 3377740861UL, 3103183487UL, 3696509979UL, 866353724UL, 3847992271UL, 2821933890UL, 1491144079UL, 1702442928UL, 1271285504UL, 636444475UL, 2465430290UL, 2440306765UL, 2651443172UL, 2895101023UL, 43843628UL, 518479547UL, 3708355608UL, 2313400729UL, 3786408564UL, 2823763904UL, 3267560272UL, +524168411UL, 2580824843UL, 2687886610UL, 785942949UL, 2624395631UL, 3713348903UL, 4104123478UL, 2234056629UL, 2683158959UL, 1805382347UL, 1645702909UL, 382688861UL, 2843792951UL, 39122499UL, 2765954033UL, 3033237617UL, 784228054UL, 1680611136UL, 2306036746UL, 892707919UL, 3825738103UL, 1289362844UL, 3462989616UL, 484526950UL, 178560970UL, 1863413515UL, 71290794UL, 1716785670UL, 3881310302UL, 2826977504UL, 2312744076UL, 1000001815UL, +1580868938UL, 3808984884UL, 2521899773UL, 738699928UL, 2244576791UL, 1833964269UL, 1361345793UL, 2934763305UL, 2944705940UL, 2334116476UL, 674208214UL, 587191877UL, 271361277UL, 1639419136UL, 2742744205UL, 2556530506UL, 3764115510UL, 861410771UL, 3473658359UL, 2879790483UL, 1497452846UL, 1101855458UL, 2268199923UL, 1766359872UL, 480532790UL, 2926891626UL, 1366888524UL, 2262816900UL, 620045088UL, 2279182738UL, 2479688463UL, 427385986UL, +271096497UL, 1999040724UL, 1980388138UL, 3104550456UL, 2496325717UL, 2941450111UL, 1784373495UL, 4020221165UL, 2567325850UL, 2636190539UL, 2764516078UL, 2285887821UL, 2395930109UL, 1867061176UL, 665795763UL, 3869868300UL, 4033135159UL, 2589983679UL, 682593183UL, 1254600537UL, 1701095863UL, 3738080583UL, 369734429UL, 2231641462UL, 1866531599UL, 1317004965UL, 466053171UL, 2320346625UL, 485850108UL, 1279183025UL, 423884362UL, 1878291714UL, +228799661UL, 575494427UL, 2773243709UL, 4009191487UL, 3877909663UL, 1392246100UL, 1328043370UL, 1407136778UL, 3204434425UL, 3881653592UL, 303018213UL, 2939203697UL, 889352935UL, 628666312UL, 165199023UL, 691563049UL, 1116804589UL, 998930334UL, 4144153491UL, 4191022348UL, 2882458100UL, 4033326555UL, 2329569601UL, 824756145UL, 3501916851UL, 3512382126UL, 1970954319UL, 4022176157UL, 2356841052UL, 3783173734UL, 3277915742UL, 3205430658UL, +1460938436UL, 280282398UL, 3262135457UL, 416160861UL, 28522973UL, 1100901182UL, 4048609665UL, 994490185UL, 2206150488UL, 3591919750UL, 65093467UL, 399797207UL, 3377740861UL, 3954301001UL, 3696509979UL, 866353724UL, 3847992271UL, 2821933890UL, 482325742UL, 1702442928UL, 1271285504UL, 636444475UL, 2465430290UL, 476965483UL, 2651443172UL, 2895101023UL, 43843628UL, 518479547UL, 2354104222UL, 2313400729UL, 3786408564UL, 2823763904UL, +3267560272UL, 1682576095UL, 2580824843UL, 2687886610UL, 785942949UL, 2624395631UL, 3219885224UL, 4104123478UL, 2234056629UL, 2683158959UL, 1805382347UL, 4143809855UL, 382688861UL, 2843792951UL, 39122499UL, 2765954033UL, 2870716981UL, 784228054UL, 1680611136UL, 2306036746UL, 892707919UL, 2648492467UL, 1289362844UL, 3462989616UL, 484526950UL, 178560970UL, 3047404165UL, 71290794UL, 1716785670UL, 3881310302UL, 2826977504UL, 2439325884UL, +1000001815UL, 1580868938UL, 3808984884UL, 2521899773UL, 2222792732UL, 2244576791UL, 1833964269UL, 1361345793UL, 2934763305UL, 655108124UL, 2334116476UL, 674208214UL, 587191877UL, 271361277UL, 1403491312UL, 2742744205UL, 2556530506UL, 3764115510UL, 861410771UL, 2748819627UL, 2879790483UL, 1497452846UL, 1101855458UL, 2268199923UL, 2646753562UL, 480532790UL, 2926891626UL, 1366888524UL, 2262816900UL, 691077353UL, 2279182738UL, 2479688463UL, +427385986UL, 271096497UL, 357444234UL, 1980388138UL, 3104550456UL, 2496325717UL, 2941450111UL, 717953620UL, 4020221165UL, 2567325850UL, 2636190539UL, 2764516078UL, 588189150UL, 2395930109UL, 1867061176UL, 665795763UL, 3869868300UL, 2245339306UL, 2589983679UL, 682593183UL, 1254600537UL, 1701095863UL, 3193417815UL, 369734429UL, 2231641462UL, 1866531599UL, 1317004965UL, 1295326133UL, 2320346625UL, 485850108UL, 1279183025UL, 423884362UL, +1310342080UL, 228799661UL, 575494427UL, 2773243709UL, 4009191487UL, 3178129190UL, 1392246100UL, 1328043370UL, 1407136778UL, 3204434425UL, 558594993UL, 303018213UL, 2939203697UL, 889352935UL, 628666312UL, 3995857198UL, 691563049UL, 1116804589UL, 998930334UL, 4144153491UL, 2375099047UL, 2882458100UL, 4033326555UL, 2329569601UL, 824756145UL, 3031828205UL, 3512382126UL, 1970954319UL, 4022176157UL, 2356841052UL, 1599294097UL, 3277915742UL, +3205430658UL, 1460938436UL, 280282398UL, 2438973535UL, 416160861UL, 28522973UL, 1100901182UL, 4048609665UL, 2989609671UL, 2206150488UL, 3591919750UL, 65093467UL, 399797207UL, 183644195UL, 3954301001UL, 3696509979UL, 866353724UL, 3847992271UL, 1244421011UL, 482325742UL, 1702442928UL, 1271285504UL, 636444475UL, 3659422961UL, 476965483UL, 2651443172UL, 2895101023UL, 43843628UL, 2230230933UL, 2354104222UL, 2313400729UL, 3786408564UL, +2823763904UL, 4146329709UL, 1682576095UL, 2580824843UL, 2687886610UL, 785942949UL, 126345381UL, 3219885224UL, 4104123478UL, 2234056629UL, 2683158959UL, 1734650983UL, 4143809855UL, 382688861UL, 2843792951UL, 39122499UL, 3527484969UL, 2870716981UL, 784228054UL, 1680611136UL, 2306036746UL, 1606477743UL, 2648492467UL, 1289362844UL, 3462989616UL, 484526950UL, 3730796296UL, 3047404165UL, 71290794UL, 1716785670UL, 3881310302UL, 4233965062UL, +2439325884UL, 1000001815UL, 1580868938UL, 3808984884UL, 1228341642UL, 2222792732UL, 2244576791UL, 1833964269UL, 1361345793UL, 3313812192UL, 655108124UL, 2334116476UL, 674208214UL, 587191877UL, 1531247446UL, 1403491312UL, 2742744205UL, 2556530506UL, 3764115510UL, 2419989900UL, 2748819627UL, 2879790483UL, 1497452846UL, 1101855458UL, 1430402656UL, 2646753562UL, 480532790UL, 2926891626UL, 1366888524UL, 1848714433UL, 691077353UL, 2279182738UL, +2479688463UL, 427385986UL, 3906690631UL, 357444234UL, 1980388138UL, 3104550456UL, 2496325717UL, 2272350403UL, 717953620UL, 4020221165UL, 2567325850UL, 2636190539UL, 1950604113UL, 588189150UL, 2395930109UL, 1867061176UL, 665795763UL, 1735147895UL, 2245339306UL, 2589983679UL, 682593183UL, 1254600537UL, 1518037357UL, 3193417815UL, 369734429UL, 2231641462UL, 1866531599UL, 1751783137UL, 1295326133UL, 2320346625UL, 485850108UL, 1279183025UL, +149835864UL, 1310342080UL, 228799661UL, 575494427UL, 2773243709UL, 1505829825UL, 3178129190UL, 1392246100UL, 1328043370UL, 1407136778UL, 856233019UL, 558594993UL, 303018213UL, 2939203697UL, 889352935UL, 625515593UL, 3995857198UL, 691563049UL, 1116804589UL, 998930334UL, 3264640128UL, 2375099047UL, 2882458100UL, 4033326555UL, 2329569601UL, 1824812377UL, 3031828205UL, 3512382126UL, 1970954319UL, 4022176157UL, 3682468973UL, 1599294097UL, +3277915742UL, 3205430658UL, 1460938436UL, 2034940270UL, 2438973535UL, 416160861UL, 28522973UL, 1100901182UL, 3534874298UL, 2989609671UL, 2206150488UL, 3591919750UL, 65093467UL, 2231373121UL, 183644195UL, 3954301001UL, 3696509979UL, 866353724UL, 1479968372UL, 1244421011UL, 482325742UL, 1702442928UL, 1271285504UL, 3834022401UL, 3659422961UL, 476965483UL, 2651443172UL, 2895101023UL, 1042443120UL, 2230230933UL, 2354104222UL, 2313400729UL, +3786408564UL, 2940290545UL, 4146329709UL, 1682576095UL, 2580824843UL, 2687886610UL, 895602439UL, 126345381UL, 3219885224UL, 4104123478UL, 2234056629UL, 3633565082UL, 1734650983UL, 4143809855UL, 382688861UL, 2843792951UL, 3076342354UL, 3527484969UL, 2870716981UL, 784228054UL, 1680611136UL, 3667923304UL, 1606477743UL, 2648492467UL, 1289362844UL, 3462989616UL, 1338592032UL, 3730796296UL, 3047404165UL, 71290794UL, 1716785670UL, 995728648UL, +4233965062UL, 2439325884UL, 1000001815UL, 1580868938UL, 1245957136UL, 1228341642UL, 2222792732UL, 2244576791UL, 1833964269UL, 2899552190UL, 3313812192UL, 655108124UL, 2334116476UL, 674208214UL, 1154789946UL, 1531247446UL, 1403491312UL, 2742744205UL, 2556530506UL, 1668620496UL, 2419989900UL, 2748819627UL, 2879790483UL, 1497452846UL, 177853954UL, 1430402656UL, 2646753562UL, 480532790UL, 2926891626UL, 3179057526UL, 1848714433UL, 691077353UL, +2279182738UL, 2479688463UL, 1988854710UL, 3906690631UL, 357444234UL, 1980388138UL, 3104550456UL, 1772857305UL, 2272350403UL, 717953620UL, 4020221165UL, 2567325850UL, 3129906484UL, 1950604113UL, 588189150UL, 2395930109UL, 1867061176UL, 2248975336UL, 1735147895UL, 2245339306UL, 2589983679UL, 682593183UL, 3087155398UL, 1518037357UL, 3193417815UL, 369734429UL, 2231641462UL, 1858424931UL, 1751783137UL, 1295326133UL, 2320346625UL, 485850108UL, +2471611230UL, 107369761UL, 2623559579UL, 4256589070UL, 2365810185UL, 907910243UL, 3901832478UL, 2068079364UL, 2072842987UL, 401440347UL, 1707255913UL, 1450112231UL, 2618898012UL, 600446000UL, 788321632UL, 4119629235UL, 2648781584UL, 1927659116UL, 171372782UL, 1789511950UL, 2648296999UL, 3558619514UL, 1819608632UL, 1392007708UL, 2918513974UL, 2270003900UL, 784021820UL, 1379044539UL, 591935962UL, 1638390839UL, 10832053UL, 3946625290UL, +2916913801UL, 2718331169UL, 1595482738UL, 1294279402UL, 19889234UL, 1374364843UL, 571354125UL, 3357938719UL, 2337506269UL, 905453029UL, 2504232400UL, 258673393UL, 2590342355UL, 3308443353UL, 3359617898UL, 2686453711UL, 932545954UL, 509832408UL, 820508114UL, 431186194UL, 3434866166UL, 1108455121UL, 2802986572UL, 893446102UL, 3248197798UL, 1797985531UL, 3952804303UL, 558601278UL, 1813674114UL, 311050994UL, 425175161UL, 1125527204UL, +1597986581UL, 2282580210UL, 1659733126UL, 2080660004UL, 4121079137UL, 3373787661UL, 1902252724UL, 2669993847UL, 2450915273UL, 2155525933UL, 2139535914UL, 274595185UL, 1890506924UL, 2631794527UL, 1423530517UL, 4027031002UL, 1085427968UL, 2402514206UL, 3591455043UL, 2513094696UL, 2338347202UL, 1168222597UL, 3922339535UL, 3991725466UL, 2774598759UL, 3478721168UL, 3676766916UL, 179748891UL, 2911159372UL, 191101265UL, 3389843262UL, 3093358663UL, +2333576084UL, 1056514165UL, 2987497874UL, 2502331872UL, 2027710028UL, 2338525812UL, 3904906078UL, 806669884UL, 596300960UL, 1993055778UL, 1541809402UL, 3578865742UL, 652348267UL, 3332532764UL, 2656602623UL, 2037214047UL, 323260312UL, 3310408133UL, 4037617529UL, 137297627UL, 1236501991UL, 495817051UL, 481150309UL, 3067841968UL, 3120347176UL, 714354848UL, 1554632062UL, 2522324107UL, 4274051212UL, 2180914534UL, 1261686356UL, 3569290041UL, +1801431819UL, 4286755560UL, 2749452442UL, 829235089UL, 2243153325UL, 2525168177UL, 1486881882UL, 585653228UL, 3288336688UL, 2734161045UL, 30430534UL, 714492313UL, 2582732426UL, 595577790UL, 1463554287UL, 1949506865UL, 4210942156UL, 2008105540UL, 4055753132UL, 2530320603UL, 319064177UL, 2305067982UL, 3825716413UL, 1543867515UL, 108979478UL, 3089716545UL, 2921391708UL, 2403595525UL, 3783697766UL, 2313991047UL, 3302598706UL, 1318323763UL, +}, +{ +1470380360UL, 3057428612UL, 2756676297UL, 1633786556UL, 4246459918UL, 2557524017UL, 1857180133UL, 618903690UL, 2475611092UL, 2621430634UL, 2084292404UL, 1698607774UL, 1788956972UL, 3375072220UL, 1499167056UL, 1218814632UL, 3699503479UL, 588281768UL, 3603925285UL, 1187721841UL, 1307962320UL, 2562217840UL, 3882506958UL, 2387033730UL, 2097027049UL, 1593669125UL, 1899433035UL, 4039983902UL, 1546854551UL, 1073191673UL, 3368453769UL, 3074694838UL, +534637095UL, 1860006723UL, 3416402670UL, 802354899UL, 3998709605UL, 3944315555UL, 3454226397UL, 1648185195UL, 488532673UL, 3063734121UL, 1318974867UL, 187087202UL, 200160693UL, 4170479404UL, 782764886UL, 4007973657UL, 1651636372UL, 3084151528UL, 2085263921UL, 2424937940UL, 230704223UL, 3342587983UL, 1093085714UL, 683877298UL, 3635026316UL, 3839461209UL, 2977567556UL, 3947448199UL, 3767172681UL, 1350679624UL, 3541409523UL, 3975162472UL, +2459379316UL, 3287828387UL, 1565768431UL, 3149625429UL, 1328627497UL, 2156355750UL, 112739894UL, 4052025045UL, 1396839113UL, 212349044UL, 110706825UL, 2185320852UL, 2540909191UL, 2129623107UL, 3515174750UL, 2669147508UL, 1243549180UL, 3996575850UL, 149304348UL, 2755670869UL, 930137412UL, 350687475UL, 1512442864UL, 3764389325UL, 3489308665UL, 276147411UL, 2268414314UL, 30674096UL, 3202650841UL, 3446821592UL, 3341145621UL, 3749209259UL, +674361204UL, 1384681012UL, 2716655878UL, 454169262UL, 289282175UL, 966029495UL, 3052791893UL, 3111969089UL, 1151599976UL, 3620936019UL, 1877909034UL, 1953262994UL, 4240669039UL, 1857402256UL, 3337397349UL, 2392730459UL, 1158928694UL, 1757447952UL, 2682284750UL, 2796982914UL, 1203210173UL, 797579212UL, 1645601877UL, 3579805998UL, 797556690UL, 4106236617UL, 1379943929UL, 129105346UL, 3950170317UL, 723231430UL, 88997404UL, 2591283275UL, +359831168UL, 306903531UL, 1987846974UL, 2654779951UL, 3724360049UL, 1693615498UL, 1095306415UL, 3586751806UL, 2045807380UL, 2779363615UL, 2912940562UL, 1557518560UL, 3620536996UL, 1723152132UL, 4087191232UL, 1042907094UL, 3210303305UL, 1536493323UL, 4094765090UL, 575328723UL, 359319532UL, 2458971265UL, 3159207510UL, 387883436UL, 2521400838UL, 2359639886UL, 261289463UL, 2094643916UL, 2269112547UL, 2387198764UL, 3619233779UL, 3019052785UL, +2910774311UL, 1470380360UL, 3057428612UL, 2756676297UL, 1633786556UL, 386502519UL, 2557524017UL, 1857180133UL, 618903690UL, 2475611092UL, 30080431UL, 2084292404UL, 1698607774UL, 1788956972UL, 3375072220UL, 1158684464UL, 1218814632UL, 3699503479UL, 588281768UL, 3603925285UL, 238328161UL, 1307962320UL, 2562217840UL, 3882506958UL, 2387033730UL, 3010587639UL, 1593669125UL, 1899433035UL, 4039983902UL, 1546854551UL, 4192218972UL, 3368453769UL, +3074694838UL, 534637095UL, 1860006723UL, 652336168UL, 802354899UL, 3998709605UL, 3944315555UL, 3454226397UL, 1926499185UL, 488532673UL, 3063734121UL, 1318974867UL, 187087202UL, 1106075322UL, 4170479404UL, 782764886UL, 4007973657UL, 1651636372UL, 2404132022UL, 2085263921UL, 2424937940UL, 230704223UL, 3342587983UL, 918664020UL, 683877298UL, 3635026316UL, 3839461209UL, 2977567556UL, 1943458501UL, 3767172681UL, 1350679624UL, 3541409523UL, +3975162472UL, 276593262UL, 3287828387UL, 1565768431UL, 3149625429UL, 1328627497UL, 1428675465UL, 112739894UL, 4052025045UL, 1396839113UL, 212349044UL, 4056830215UL, 2185320852UL, 2540909191UL, 2129623107UL, 3515174750UL, 1542171596UL, 1243549180UL, 3996575850UL, 149304348UL, 2755670869UL, 3578672658UL, 350687475UL, 1512442864UL, 3764389325UL, 3489308665UL, 1546094236UL, 2268414314UL, 30674096UL, 3202650841UL, 3446821592UL, 2954172575UL, +3749209259UL, 674361204UL, 1384681012UL, 2716655878UL, 3784818668UL, 289282175UL, 966029495UL, 3052791893UL, 3111969089UL, 4157356036UL, 3620936019UL, 1877909034UL, 1953262994UL, 4240669039UL, 558548232UL, 3337397349UL, 2392730459UL, 1158928694UL, 1757447952UL, 2764253876UL, 2796982914UL, 1203210173UL, 797579212UL, 1645601877UL, 1754284241UL, 797556690UL, 4106236617UL, 1379943929UL, 129105346UL, 1072954804UL, 723231430UL, 88997404UL, +2591283275UL, 359831168UL, 3790749526UL, 1987846974UL, 2654779951UL, 3724360049UL, 1693615498UL, 529478744UL, 3586751806UL, 2045807380UL, 2779363615UL, 2912940562UL, 3883779003UL, 3620536996UL, 1723152132UL, 4087191232UL, 1042907094UL, 2510614710UL, 1536493323UL, 4094765090UL, 575328723UL, 359319532UL, 4185709932UL, 3159207510UL, 387883436UL, 2521400838UL, 2359639886UL, 143795416UL, 2094643916UL, 2269112547UL, 2387198764UL, 3619233779UL, +2856133500UL, 2910774311UL, 1470380360UL, 3057428612UL, 2756676297UL, 1184346658UL, 386502519UL, 2557524017UL, 1857180133UL, 618903690UL, 113530176UL, 30080431UL, 2084292404UL, 1698607774UL, 1788956972UL, 1446640841UL, 1158684464UL, 1218814632UL, 3699503479UL, 588281768UL, 145530757UL, 238328161UL, 1307962320UL, 2562217840UL, 3882506958UL, 2145494995UL, 3010587639UL, 1593669125UL, 1899433035UL, 4039983902UL, 1668183055UL, 4192218972UL, +3368453769UL, 3074694838UL, 534637095UL, 1759744354UL, 652336168UL, 802354899UL, 3998709605UL, 3944315555UL, 3058692249UL, 1926499185UL, 488532673UL, 3063734121UL, 1318974867UL, 728549366UL, 1106075322UL, 4170479404UL, 782764886UL, 4007973657UL, 3270440405UL, 2404132022UL, 2085263921UL, 2424937940UL, 230704223UL, 3329510499UL, 918664020UL, 683877298UL, 3635026316UL, 3839461209UL, 79335966UL, 1943458501UL, 3767172681UL, 1350679624UL, +3541409523UL, 925084463UL, 276593262UL, 3287828387UL, 1565768431UL, 3149625429UL, 3775346659UL, 1428675465UL, 112739894UL, 4052025045UL, 1396839113UL, 865124022UL, 4056830215UL, 2185320852UL, 2540909191UL, 2129623107UL, 408329043UL, 1542171596UL, 1243549180UL, 3996575850UL, 149304348UL, 3549625626UL, 3578672658UL, 350687475UL, 1512442864UL, 3764389325UL, 2745315161UL, 1546094236UL, 2268414314UL, 30674096UL, 3202650841UL, 1591955495UL, +2954172575UL, 3749209259UL, 674361204UL, 1384681012UL, 4064148122UL, 3784818668UL, 289282175UL, 966029495UL, 3052791893UL, 1370867977UL, 4157356036UL, 3620936019UL, 1877909034UL, 1953262994UL, 4021792514UL, 558548232UL, 3337397349UL, 2392730459UL, 1158928694UL, 3155295174UL, 2764253876UL, 2796982914UL, 1203210173UL, 797579212UL, 3928348491UL, 1754284241UL, 797556690UL, 4106236617UL, 1379943929UL, 535801204UL, 1072954804UL, 723231430UL, +88997404UL, 2591283275UL, 3834650337UL, 3790749526UL, 1987846974UL, 2654779951UL, 3724360049UL, 1042046499UL, 529478744UL, 3586751806UL, 2045807380UL, 2779363615UL, 1125934487UL, 3883779003UL, 3620536996UL, 1723152132UL, 4087191232UL, 234512721UL, 2510614710UL, 1536493323UL, 4094765090UL, 575328723UL, 3997395999UL, 4185709932UL, 3159207510UL, 387883436UL, 2521400838UL, 3125399953UL, 143795416UL, 2094643916UL, 2269112547UL, 2387198764UL, +652167990UL, 2856133500UL, 2910774311UL, 1470380360UL, 3057428612UL, 2132157457UL, 1184346658UL, 386502519UL, 2557524017UL, 1857180133UL, 4131611047UL, 113530176UL, 30080431UL, 2084292404UL, 1698607774UL, 391246724UL, 1446640841UL, 1158684464UL, 1218814632UL, 3699503479UL, 2411874184UL, 145530757UL, 238328161UL, 1307962320UL, 2562217840UL, 2812151676UL, 2145494995UL, 3010587639UL, 1593669125UL, 1899433035UL, 2422208371UL, 1668183055UL, +4192218972UL, 3368453769UL, 3074694838UL, 2148785858UL, 1759744354UL, 652336168UL, 802354899UL, 3998709605UL, 1781938823UL, 3058692249UL, 1926499185UL, 488532673UL, 3063734121UL, 3539633540UL, 728549366UL, 1106075322UL, 4170479404UL, 782764886UL, 2780824417UL, 3270440405UL, 2404132022UL, 2085263921UL, 2424937940UL, 1908513596UL, 3329510499UL, 918664020UL, 683877298UL, 3635026316UL, 2918953355UL, 79335966UL, 1943458501UL, 3767172681UL, +1350679624UL, 341369607UL, 925084463UL, 276593262UL, 3287828387UL, 1565768431UL, 1957429498UL, 3775346659UL, 1428675465UL, 112739894UL, 4052025045UL, 1847440090UL, 865124022UL, 4056830215UL, 2185320852UL, 2540909191UL, 3477402775UL, 408329043UL, 1542171596UL, 1243549180UL, 3996575850UL, 179432054UL, 3549625626UL, 3578672658UL, 350687475UL, 1512442864UL, 2118138924UL, 2745315161UL, 1546094236UL, 2268414314UL, 30674096UL, 2317064191UL, +1591955495UL, 2954172575UL, 3749209259UL, 674361204UL, 3286542168UL, 4064148122UL, 3784818668UL, 289282175UL, 966029495UL, 1327408800UL, 1370867977UL, 4157356036UL, 3620936019UL, 1877909034UL, 405707683UL, 4021792514UL, 558548232UL, 3337397349UL, 2392730459UL, 3244675609UL, 3155295174UL, 2764253876UL, 2796982914UL, 1203210173UL, 2274948223UL, 3928348491UL, 1754284241UL, 797556690UL, 4106236617UL, 2665938417UL, 535801204UL, 1072954804UL, +723231430UL, 88997404UL, 3006584290UL, 3834650337UL, 3790749526UL, 1987846974UL, 2654779951UL, 4271242910UL, 1042046499UL, 529478744UL, 3586751806UL, 2045807380UL, 2283867237UL, 1125934487UL, 3883779003UL, 3620536996UL, 1723152132UL, 1761178713UL, 234512721UL, 2510614710UL, 1536493323UL, 4094765090UL, 2361030279UL, 3997395999UL, 4185709932UL, 3159207510UL, 387883436UL, 3979684113UL, 3125399953UL, 143795416UL, 2094643916UL, 2269112547UL, +1499026790UL, 2673871071UL, 3817604600UL, 2996498142UL, 1211396713UL, 4016438754UL, 992969238UL, 2196610884UL, 1333868752UL, 2722471337UL, 2178395143UL, 533478044UL, 291720336UL, 3552502714UL, 1060260388UL, 1389737501UL, 3508724089UL, 3106493936UL, 2013154532UL, 3169850047UL, 3773175439UL, 3604033115UL, 4234678017UL, 2903156223UL, 3832188501UL, 2874956773UL, 4283805552UL, 3664062691UL, 1974738248UL, 925764827UL, 1750660924UL, 141239116UL, +3273085573UL, 2427940522UL, 1962727892UL, 2493949152UL, 1043482688UL, 2345076260UL, 2209086707UL, 3642865193UL, 3119873884UL, 571850463UL, 1599484831UL, 76923002UL, 3077572436UL, 4086821865UL, 1523654720UL, 480304732UL, 476538774UL, 2169116383UL, 4033618691UL, 2819753414UL, 2856326003UL, 747450871UL, 1851448547UL, 713503330UL, 3709263622UL, 781002495UL, 1968749577UL, 2933719965UL, 4057398020UL, 3406593497UL, 689436820UL, 2935729647UL, +2030357428UL, 2075940397UL, 1830631914UL, 1093330800UL, 1706624613UL, 1805612947UL, 4257097124UL, 3233604448UL, 159450674UL, 1050507045UL, 566046625UL, 2253420120UL, 904902042UL, 1830037922UL, 4081490982UL, 1427186514UL, 2535536470UL, 3869316947UL, 4097476542UL, 930420754UL, 2519255367UL, 49908928UL, 454325685UL, 888118139UL, 3453892181UL, 1263601461UL, 1236190782UL, 674943665UL, 1648077470UL, 429399730UL, 2904879506UL, 3718410520UL, +1802183310UL, 1872553091UL, 605480672UL, 774749173UL, 3200570514UL, 181210046UL, 2560898144UL, 3947027625UL, 1535243167UL, 324801283UL, 4234744788UL, 746560316UL, 2456297875UL, 3925756080UL, 533997731UL, 3919796086UL, 662975152UL, 864661066UL, 1070894403UL, 1020445801UL, 1511298602UL, 4221508348UL, 3577952702UL, 4122306502UL, 2012051572UL, 1616168260UL, 2456901413UL, 2717726537UL, 840264605UL, 2687215223UL, 2174960097UL, 1239122603UL, +2890231920UL, 3365350767UL, 3998868598UL, 563137220UL, 893868530UL, 3400632172UL, 1538627830UL, 2812510298UL, 496662288UL, 2317289974UL, 2252393722UL, 1221289032UL, 2418100559UL, 402670890UL, 1528570045UL, 3160531718UL, 1806492066UL, 3211663975UL, 3617025598UL, 3664580463UL, 1338638297UL, 341637330UL, 2097019728UL, 4031221207UL, 503636424UL, 3883416740UL, 1530237682UL, 1152125396UL, 2845384901UL, 332460372UL, 457364876UL, 1738239808UL, +}, +{ +1118787884UL, 1884590246UL, 1007052798UL, 3717680750UL, 1609263052UL, 2486654530UL, 2761168910UL, 163554565UL, 3928803020UL, 2632714628UL, 1386788970UL, 2621928183UL, 2855206157UL, 2989018213UL, 1836814260UL, 4197635108UL, 1030118238UL, 2789863793UL, 2063944689UL, 1647608366UL, 255485979UL, 3657534664UL, 1317185871UL, 2410074449UL, 3971156607UL, 907575923UL, 4132859581UL, 416269582UL, 877554291UL, 633895348UL, 2236014545UL, 992386759UL, +3971362318UL, 2173597771UL, 1673339632UL, 1371742490UL, 2033574313UL, 3809530180UL, 319182848UL, 1562235776UL, 463522324UL, 1482338913UL, 1816432405UL, 3278626272UL, 1335179249UL, 171265751UL, 2249118654UL, 1153849045UL, 3013179633UL, 1450352108UL, 1267908572UL, 1138658121UL, 623675874UL, 3608469129UL, 978093004UL, 1283228910UL, 1810859539UL, 1179125634UL, 2939039286UL, 3862213960UL, 1168357273UL, 376788629UL, 314507445UL, 219039712UL, +463080619UL, 2994990779UL, 1035692306UL, 2228303916UL, 1280244913UL, 1965417315UL, 1815095408UL, 939691799UL, 3080056566UL, 3741305118UL, 1495905100UL, 65327713UL, 3884301346UL, 2536445014UL, 1503280354UL, 3398924419UL, 3678532805UL, 2616964783UL, 3168581019UL, 3553322118UL, 3023259169UL, 480342712UL, 451634742UL, 3562778450UL, 1943708078UL, 660077747UL, 434714388UL, 2369278293UL, 2894425895UL, 1919542250UL, 2469130567UL, 551196237UL, +4193980239UL, 2952382875UL, 3311173667UL, 2856797012UL, 2845888917UL, 1669184098UL, 3928626091UL, 2491577076UL, 3719464032UL, 2151963814UL, 3474431449UL, 3971510537UL, 3695841119UL, 2215238146UL, 3668152847UL, 1974578319UL, 2328185090UL, 2096356935UL, 3973692455UL, 3954842437UL, 422675402UL, 477894725UL, 3398641827UL, 1366451030UL, 1354642198UL, 3029840461UL, 35700837UL, 2937170986UL, 1336296570UL, 3508313874UL, 587724229UL, 2051237478UL, +3539754304UL, 1946154432UL, 2463932452UL, 144772179UL, 353408424UL, 3493806256UL, 3782958493UL, 1957797444UL, 228084488UL, 192277278UL, 3612092522UL, 2235069734UL, 467407503UL, 3391861572UL, 847810786UL, 1838763654UL, 2272109211UL, 3018265496UL, 4249218445UL, 1722760791UL, 3484353162UL, 3906437663UL, 4208966227UL, 2352549740UL, 714311566UL, 1346246305UL, 2865157059UL, 2989587005UL, 3946819548UL, 3109244860UL, 3885124598UL, 3314346978UL, +952826829UL, 1118787884UL, 1884590246UL, 1007052798UL, 3717680750UL, 1521451317UL, 2486654530UL, 2761168910UL, 163554565UL, 3928803020UL, 2299046195UL, 1386788970UL, 2621928183UL, 2855206157UL, 2989018213UL, 3048269905UL, 4197635108UL, 1030118238UL, 2789863793UL, 2063944689UL, 1814057352UL, 255485979UL, 3657534664UL, 1317185871UL, 2410074449UL, 4041610788UL, 907575923UL, 4132859581UL, 416269582UL, 877554291UL, 2338964683UL, 2236014545UL, +992386759UL, 3971362318UL, 2173597771UL, 579340117UL, 1371742490UL, 2033574313UL, 3809530180UL, 319182848UL, 3090313228UL, 463522324UL, 1482338913UL, 1816432405UL, 3278626272UL, 2418220643UL, 171265751UL, 2249118654UL, 1153849045UL, 3013179633UL, 2738647190UL, 1267908572UL, 1138658121UL, 623675874UL, 3608469129UL, 3096087202UL, 1283228910UL, 1810859539UL, 1179125634UL, 2939039286UL, 2601862091UL, 1168357273UL, 376788629UL, 314507445UL, +219039712UL, 1174181426UL, 2994990779UL, 1035692306UL, 2228303916UL, 1280244913UL, 752017703UL, 1815095408UL, 939691799UL, 3080056566UL, 3741305118UL, 126135654UL, 65327713UL, 3884301346UL, 2536445014UL, 1503280354UL, 955981361UL, 3678532805UL, 2616964783UL, 3168581019UL, 3553322118UL, 3772187171UL, 480342712UL, 451634742UL, 3562778450UL, 1943708078UL, 1466950454UL, 434714388UL, 2369278293UL, 2894425895UL, 1919542250UL, 317862862UL, +551196237UL, 4193980239UL, 2952382875UL, 3311173667UL, 12728591UL, 2845888917UL, 1669184098UL, 3928626091UL, 2491577076UL, 2742989641UL, 2151963814UL, 3474431449UL, 3971510537UL, 3695841119UL, 1005662613UL, 3668152847UL, 1974578319UL, 2328185090UL, 2096356935UL, 3629684995UL, 3954842437UL, 422675402UL, 477894725UL, 3398641827UL, 209352768UL, 1354642198UL, 3029840461UL, 35700837UL, 2937170986UL, 1660777984UL, 3508313874UL, 587724229UL, +2051237478UL, 3539754304UL, 3631430985UL, 2463932452UL, 144772179UL, 353408424UL, 3493806256UL, 3616422021UL, 1957797444UL, 228084488UL, 192277278UL, 3612092522UL, 3638977910UL, 467407503UL, 3391861572UL, 847810786UL, 1838763654UL, 2427237699UL, 3018265496UL, 4249218445UL, 1722760791UL, 3484353162UL, 2322365400UL, 4208966227UL, 2352549740UL, 714311566UL, 1346246305UL, 954101391UL, 2989587005UL, 3946819548UL, 3109244860UL, 3885124598UL, +420941376UL, 952826829UL, 1118787884UL, 1884590246UL, 1007052798UL, 539759724UL, 1521451317UL, 2486654530UL, 2761168910UL, 163554565UL, 1954997983UL, 2299046195UL, 1386788970UL, 2621928183UL, 2855206157UL, 3104695189UL, 3048269905UL, 4197635108UL, 1030118238UL, 2789863793UL, 3556473570UL, 1814057352UL, 255485979UL, 3657534664UL, 1317185871UL, 3004205219UL, 4041610788UL, 907575923UL, 4132859581UL, 416269582UL, 2980178044UL, 2338964683UL, +2236014545UL, 992386759UL, 3971362318UL, 2573125018UL, 579340117UL, 1371742490UL, 2033574313UL, 3809530180UL, 766585731UL, 3090313228UL, 463522324UL, 1482338913UL, 1816432405UL, 3101578277UL, 2418220643UL, 171265751UL, 2249118654UL, 1153849045UL, 2143267892UL, 2738647190UL, 1267908572UL, 1138658121UL, 623675874UL, 2944231951UL, 3096087202UL, 1283228910UL, 1810859539UL, 1179125634UL, 374714364UL, 2601862091UL, 1168357273UL, 376788629UL, +314507445UL, 1710922505UL, 1174181426UL, 2994990779UL, 1035692306UL, 2228303916UL, 3222680885UL, 752017703UL, 1815095408UL, 939691799UL, 3080056566UL, 1985366287UL, 126135654UL, 65327713UL, 3884301346UL, 2536445014UL, 3002467868UL, 955981361UL, 3678532805UL, 2616964783UL, 3168581019UL, 2173417616UL, 3772187171UL, 480342712UL, 451634742UL, 3562778450UL, 236095606UL, 1466950454UL, 434714388UL, 2369278293UL, 2894425895UL, 1766257461UL, +317862862UL, 551196237UL, 4193980239UL, 2952382875UL, 2416349742UL, 12728591UL, 2845888917UL, 1669184098UL, 3928626091UL, 2346338391UL, 2742989641UL, 2151963814UL, 3474431449UL, 3971510537UL, 942354812UL, 1005662613UL, 3668152847UL, 1974578319UL, 2328185090UL, 3234982376UL, 3629684995UL, 3954842437UL, 422675402UL, 477894725UL, 2931444539UL, 209352768UL, 1354642198UL, 3029840461UL, 35700837UL, 3388567298UL, 1660777984UL, 3508313874UL, +587724229UL, 2051237478UL, 1770178720UL, 3631430985UL, 2463932452UL, 144772179UL, 353408424UL, 3783114255UL, 3616422021UL, 1957797444UL, 228084488UL, 192277278UL, 611095909UL, 3638977910UL, 467407503UL, 3391861572UL, 847810786UL, 1413548572UL, 2427237699UL, 3018265496UL, 4249218445UL, 1722760791UL, 1487262638UL, 2322365400UL, 4208966227UL, 2352549740UL, 714311566UL, 1378213368UL, 954101391UL, 2989587005UL, 3946819548UL, 3109244860UL, +4183748384UL, 420941376UL, 952826829UL, 1118787884UL, 1884590246UL, 2199811809UL, 539759724UL, 1521451317UL, 2486654530UL, 2761168910UL, 1100080647UL, 1954997983UL, 2299046195UL, 1386788970UL, 2621928183UL, 916352763UL, 3104695189UL, 3048269905UL, 4197635108UL, 1030118238UL, 369866139UL, 3556473570UL, 1814057352UL, 255485979UL, 3657534664UL, 2916985473UL, 3004205219UL, 4041610788UL, 907575923UL, 4132859581UL, 3856599532UL, 2980178044UL, +2338964683UL, 2236014545UL, 992386759UL, 3393662326UL, 2573125018UL, 579340117UL, 1371742490UL, 2033574313UL, 1938766053UL, 766585731UL, 3090313228UL, 463522324UL, 1482338913UL, 2122086302UL, 3101578277UL, 2418220643UL, 171265751UL, 2249118654UL, 952602228UL, 2143267892UL, 2738647190UL, 1267908572UL, 1138658121UL, 1808026803UL, 2944231951UL, 3096087202UL, 1283228910UL, 1810859539UL, 3881666794UL, 374714364UL, 2601862091UL, 1168357273UL, +376788629UL, 728738466UL, 1710922505UL, 1174181426UL, 2994990779UL, 1035692306UL, 74930675UL, 3222680885UL, 752017703UL, 1815095408UL, 939691799UL, 3404352271UL, 1985366287UL, 126135654UL, 65327713UL, 3884301346UL, 1822629733UL, 3002467868UL, 955981361UL, 3678532805UL, 2616964783UL, 3865359567UL, 2173417616UL, 3772187171UL, 480342712UL, 451634742UL, 1099609112UL, 236095606UL, 1466950454UL, 434714388UL, 2369278293UL, 2671873359UL, +1766257461UL, 317862862UL, 551196237UL, 4193980239UL, 2006763654UL, 2416349742UL, 12728591UL, 2845888917UL, 1669184098UL, 2492983893UL, 2346338391UL, 2742989641UL, 2151963814UL, 3474431449UL, 2095232649UL, 942354812UL, 1005662613UL, 3668152847UL, 1974578319UL, 1748794756UL, 3234982376UL, 3629684995UL, 3954842437UL, 422675402UL, 2291986911UL, 2931444539UL, 209352768UL, 1354642198UL, 3029840461UL, 3772709822UL, 3388567298UL, 1660777984UL, +3508313874UL, 587724229UL, 2759789003UL, 1770178720UL, 3631430985UL, 2463932452UL, 144772179UL, 1572181309UL, 3783114255UL, 3616422021UL, 1957797444UL, 228084488UL, 4106643586UL, 611095909UL, 3638977910UL, 467407503UL, 3391861572UL, 927151111UL, 1413548572UL, 2427237699UL, 3018265496UL, 4249218445UL, 692575565UL, 1487262638UL, 2322365400UL, 4208966227UL, 2352549740UL, 1281886506UL, 1378213368UL, 954101391UL, 2989587005UL, 3946819548UL, +1861811740UL, 1484768905UL, 359662140UL, 4058479705UL, 1306547382UL, 514617018UL, 1685692791UL, 3370601554UL, 2920029077UL, 447798803UL, 3124262580UL, 1841693810UL, 583764638UL, 853545489UL, 2614348705UL, 1445696741UL, 4226719361UL, 1299450005UL, 7404137UL, 3158806368UL, 3487160245UL, 1410910965UL, 3697116584UL, 4272452035UL, 832215403UL, 4190877996UL, 2360539465UL, 1011144434UL, 546018244UL, 613443074UL, 2523894977UL, 998991923UL, +2569220540UL, 4221264346UL, 2627827148UL, 2606458015UL, 261584257UL, 4172552877UL, 1174774061UL, 1040006970UL, 2378868955UL, 1539192255UL, 1322624483UL, 3221782707UL, 3352886416UL, 3634686692UL, 65447704UL, 3962131218UL, 839088053UL, 4154193716UL, 1211888926UL, 319402483UL, 3922826413UL, 3799829447UL, 623726612UL, 1586183272UL, 1853729462UL, 2621029589UL, 708558605UL, 1618007233UL, 2784732545UL, 953859039UL, 921654620UL, 477148727UL, +3592256598UL, 2772318818UL, 1460772911UL, 1309227716UL, 3484274262UL, 3425161241UL, 1677052569UL, 2238155114UL, 2828087292UL, 2361598991UL, 4283732706UL, 1530059373UL, 1564048492UL, 243829114UL, 104328994UL, 3080249237UL, 2054985396UL, 408961407UL, 2978652320UL, 2412674552UL, 3794618070UL, 3644862703UL, 2095186402UL, 3294126752UL, 2970218740UL, 1800713612UL, 3806665216UL, 3990918051UL, 142666452UL, 531078813UL, 1079142774UL, 3437358350UL, +635943961UL, 255576894UL, 2991317718UL, 1208676456UL, 247449774UL, 454879171UL, 113230697UL, 3064123371UL, 336269028UL, 1137083842UL, 959568850UL, 2508623991UL, 3338418112UL, 2660268938UL, 1318010299UL, 3950178561UL, 1078499199UL, 1176289535UL, 3875152821UL, 1984420952UL, 1134199826UL, 2944539174UL, 3667625203UL, 2034152216UL, 1648355307UL, 2376447620UL, 2967418253UL, 185143450UL, 889002925UL, 3999315013UL, 661455858UL, 4026799358UL, +3626504428UL, 3544795311UL, 3642718771UL, 2467387138UL, 1034249749UL, 2051371333UL, 4251353248UL, 1575036366UL, 751400924UL, 2906720214UL, 1210002606UL, 916508568UL, 1728487600UL, 2478884914UL, 3081526615UL, 1867135009UL, 1955998382UL, 701713417UL, 512784398UL, 1255240210UL, 3665676113UL, 1771754697UL, 4000392442UL, 3342268855UL, 2677221913UL, 369054145UL, 4011912082UL, 748537647UL, 1626721797UL, 852497405UL, 168721778UL, 3091138383UL, +}, +{ +3781228998UL, 1787582256UL, 838267218UL, 2710632450UL, 690892139UL, 2484870604UL, 4151302318UL, 1844787776UL, 727768263UL, 1075391038UL, 1842903369UL, 2927332301UL, 3246688068UL, 1234715005UL, 2906526190UL, 3369636401UL, 3091858538UL, 3320767682UL, 920496809UL, 1406803705UL, 3163880457UL, 1540551653UL, 2733620168UL, 2588558057UL, 147277542UL, 803170440UL, 821275940UL, 3897549272UL, 151390608UL, 951639139UL, 904639695UL, 1106545578UL, +1514893712UL, 998760135UL, 2557458623UL, 4109877399UL, 578824730UL, 2174064027UL, 3352513900UL, 3206168298UL, 911932439UL, 2030004973UL, 3283902592UL, 3755877921UL, 250434692UL, 352122318UL, 977153640UL, 642640734UL, 2555395772UL, 2307695537UL, 2593565626UL, 3738143618UL, 734614254UL, 3276420511UL, 2636087597UL, 4157371578UL, 1082026387UL, 429736987UL, 3755125580UL, 1935957937UL, 3300547146UL, 3089498232UL, 4167244256UL, 1619189426UL, +1094447351UL, 1061842570UL, 3666470174UL, 810916769UL, 2263633079UL, 3863543843UL, 1804937521UL, 2774236887UL, 2858593613UL, 961498236UL, 1515309045UL, 1564424234UL, 2276602447UL, 2540994858UL, 78621171UL, 3575132456UL, 2958793283UL, 387554009UL, 688827573UL, 3833764146UL, 2611524056UL, 2296780370UL, 2411775612UL, 3790615886UL, 3399757437UL, 1385198595UL, 1005364336UL, 2093159919UL, 2091827252UL, 1461775197UL, 4225171212UL, 1185831033UL, +12264437UL, 1313835999UL, 556653278UL, 917105970UL, 1471530347UL, 2010243509UL, 3097827138UL, 1399987735UL, 273352191UL, 2505795417UL, 1336824946UL, 3358720963UL, 2874295267UL, 2282349617UL, 3478581038UL, 4027859424UL, 713597958UL, 4059691816UL, 2812811116UL, 2291324146UL, 932688463UL, 3001334051UL, 2028368589UL, 830582457UL, 3964293916UL, 4276849132UL, 1828058403UL, 1351688755UL, 2113265048UL, 42517349UL, 3100438883UL, 1137792178UL, +1479076106UL, 463377892UL, 3964913740UL, 2422362185UL, 436113863UL, 2044139049UL, 4197323265UL, 3275185975UL, 2655265571UL, 1674107588UL, 1496360114UL, 3642050139UL, 1739051417UL, 2393774399UL, 250035802UL, 10186306UL, 263338568UL, 3899157617UL, 3679157076UL, 2258085991UL, 1407319575UL, 899008067UL, 3679828833UL, 711086272UL, 2952963707UL, 3373894808UL, 445540851UL, 3405637490UL, 1343291195UL, 730888681UL, 507768703UL, 3473963321UL, +1779803564UL, 3781228998UL, 1787582256UL, 838267218UL, 2710632450UL, 2431224659UL, 2484870604UL, 4151302318UL, 1844787776UL, 727768263UL, 4012573268UL, 1842903369UL, 2927332301UL, 3246688068UL, 1234715005UL, 3405161215UL, 3369636401UL, 3091858538UL, 3320767682UL, 920496809UL, 400609988UL, 3163880457UL, 1540551653UL, 2733620168UL, 2588558057UL, 2137935937UL, 803170440UL, 821275940UL, 3897549272UL, 151390608UL, 194431797UL, 904639695UL, +1106545578UL, 1514893712UL, 998760135UL, 62528087UL, 4109877399UL, 578824730UL, 2174064027UL, 3352513900UL, 3495516649UL, 911932439UL, 2030004973UL, 3283902592UL, 3755877921UL, 1774462108UL, 352122318UL, 977153640UL, 642640734UL, 2555395772UL, 756528792UL, 2593565626UL, 3738143618UL, 734614254UL, 3276420511UL, 4086313763UL, 4157371578UL, 1082026387UL, 429736987UL, 3755125580UL, 526056489UL, 3300547146UL, 3089498232UL, 4167244256UL, +1619189426UL, 82235109UL, 1061842570UL, 3666470174UL, 810916769UL, 2263633079UL, 1110270726UL, 1804937521UL, 2774236887UL, 2858593613UL, 961498236UL, 1840197918UL, 1564424234UL, 2276602447UL, 2540994858UL, 78621171UL, 3690913528UL, 2958793283UL, 387554009UL, 688827573UL, 3833764146UL, 3626285597UL, 2296780370UL, 2411775612UL, 3790615886UL, 3399757437UL, 1561545830UL, 1005364336UL, 2093159919UL, 2091827252UL, 1461775197UL, 63358970UL, +1185831033UL, 12264437UL, 1313835999UL, 556653278UL, 3918754976UL, 1471530347UL, 2010243509UL, 3097827138UL, 1399987735UL, 2767111911UL, 2505795417UL, 1336824946UL, 3358720963UL, 2874295267UL, 902314853UL, 3478581038UL, 4027859424UL, 713597958UL, 4059691816UL, 1462989647UL, 2291324146UL, 932688463UL, 3001334051UL, 2028368589UL, 3594712587UL, 3964293916UL, 4276849132UL, 1828058403UL, 1351688755UL, 2571513800UL, 42517349UL, 3100438883UL, +1137792178UL, 1479076106UL, 140519541UL, 3964913740UL, 2422362185UL, 436113863UL, 2044139049UL, 226785542UL, 3275185975UL, 2655265571UL, 1674107588UL, 1496360114UL, 46428973UL, 1739051417UL, 2393774399UL, 250035802UL, 10186306UL, 4118320101UL, 3899157617UL, 3679157076UL, 2258085991UL, 1407319575UL, 4267866849UL, 3679828833UL, 711086272UL, 2952963707UL, 3373894808UL, 3662249794UL, 3405637490UL, 1343291195UL, 730888681UL, 507768703UL, +2930510271UL, 1779803564UL, 3781228998UL, 1787582256UL, 838267218UL, 1817693489UL, 2431224659UL, 2484870604UL, 4151302318UL, 1844787776UL, 1788220652UL, 4012573268UL, 1842903369UL, 2927332301UL, 3246688068UL, 2050648011UL, 3405161215UL, 3369636401UL, 3091858538UL, 3320767682UL, 241001958UL, 400609988UL, 3163880457UL, 1540551653UL, 2733620168UL, 3857223520UL, 2137935937UL, 803170440UL, 821275940UL, 3897549272UL, 1451986523UL, 194431797UL, +904639695UL, 1106545578UL, 1514893712UL, 4147878244UL, 62528087UL, 4109877399UL, 578824730UL, 2174064027UL, 461571251UL, 3495516649UL, 911932439UL, 2030004973UL, 3283902592UL, 1580354765UL, 1774462108UL, 352122318UL, 977153640UL, 642640734UL, 1019387737UL, 756528792UL, 2593565626UL, 3738143618UL, 734614254UL, 999431451UL, 4086313763UL, 4157371578UL, 1082026387UL, 429736987UL, 140091634UL, 526056489UL, 3300547146UL, 3089498232UL, +4167244256UL, 3202763095UL, 82235109UL, 1061842570UL, 3666470174UL, 810916769UL, 3663992550UL, 1110270726UL, 1804937521UL, 2774236887UL, 2858593613UL, 2203639366UL, 1840197918UL, 1564424234UL, 2276602447UL, 2540994858UL, 978199281UL, 3690913528UL, 2958793283UL, 387554009UL, 688827573UL, 375113876UL, 3626285597UL, 2296780370UL, 2411775612UL, 3790615886UL, 1277897939UL, 1561545830UL, 1005364336UL, 2093159919UL, 2091827252UL, 1631078873UL, +63358970UL, 1185831033UL, 12264437UL, 1313835999UL, 3872277948UL, 3918754976UL, 1471530347UL, 2010243509UL, 3097827138UL, 1291836608UL, 2767111911UL, 2505795417UL, 1336824946UL, 3358720963UL, 3954754615UL, 902314853UL, 3478581038UL, 4027859424UL, 713597958UL, 2198246306UL, 1462989647UL, 2291324146UL, 932688463UL, 3001334051UL, 2374736511UL, 3594712587UL, 3964293916UL, 4276849132UL, 1828058403UL, 3619038368UL, 2571513800UL, 42517349UL, +3100438883UL, 1137792178UL, 1146435746UL, 140519541UL, 3964913740UL, 2422362185UL, 436113863UL, 3460540392UL, 226785542UL, 3275185975UL, 2655265571UL, 1674107588UL, 1288223861UL, 46428973UL, 1739051417UL, 2393774399UL, 250035802UL, 1986226858UL, 4118320101UL, 3899157617UL, 3679157076UL, 2258085991UL, 551117761UL, 4267866849UL, 3679828833UL, 711086272UL, 2952963707UL, 1667866621UL, 3662249794UL, 3405637490UL, 1343291195UL, 730888681UL, +2381246695UL, 2930510271UL, 1779803564UL, 3781228998UL, 1787582256UL, 1236367773UL, 1817693489UL, 2431224659UL, 2484870604UL, 4151302318UL, 2902321811UL, 1788220652UL, 4012573268UL, 1842903369UL, 2927332301UL, 1185539274UL, 2050648011UL, 3405161215UL, 3369636401UL, 3091858538UL, 4240555382UL, 241001958UL, 400609988UL, 3163880457UL, 1540551653UL, 2539098607UL, 3857223520UL, 2137935937UL, 803170440UL, 821275940UL, 3485313735UL, 1451986523UL, +194431797UL, 904639695UL, 1106545578UL, 1633417190UL, 4147878244UL, 62528087UL, 4109877399UL, 578824730UL, 3671726812UL, 461571251UL, 3495516649UL, 911932439UL, 2030004973UL, 2002341352UL, 1580354765UL, 1774462108UL, 352122318UL, 977153640UL, 170033402UL, 1019387737UL, 756528792UL, 2593565626UL, 3738143618UL, 4160516213UL, 999431451UL, 4086313763UL, 4157371578UL, 1082026387UL, 1423352480UL, 140091634UL, 526056489UL, 3300547146UL, +3089498232UL, 4266971502UL, 3202763095UL, 82235109UL, 1061842570UL, 3666470174UL, 945994616UL, 3663992550UL, 1110270726UL, 1804937521UL, 2774236887UL, 3776581315UL, 2203639366UL, 1840197918UL, 1564424234UL, 2276602447UL, 928117829UL, 978199281UL, 3690913528UL, 2958793283UL, 387554009UL, 2817496615UL, 375113876UL, 3626285597UL, 2296780370UL, 2411775612UL, 1346030561UL, 1277897939UL, 1561545830UL, 1005364336UL, 2093159919UL, 821902776UL, +1631078873UL, 63358970UL, 1185831033UL, 12264437UL, 3192617499UL, 3872277948UL, 3918754976UL, 1471530347UL, 2010243509UL, 4011062105UL, 1291836608UL, 2767111911UL, 2505795417UL, 1336824946UL, 1593119272UL, 3954754615UL, 902314853UL, 3478581038UL, 4027859424UL, 1163079365UL, 2198246306UL, 1462989647UL, 2291324146UL, 932688463UL, 4018333691UL, 2374736511UL, 3594712587UL, 3964293916UL, 4276849132UL, 3902062310UL, 3619038368UL, 2571513800UL, +42517349UL, 3100438883UL, 1645455709UL, 1146435746UL, 140519541UL, 3964913740UL, 2422362185UL, 3338363150UL, 3460540392UL, 226785542UL, 3275185975UL, 2655265571UL, 3789582441UL, 1288223861UL, 46428973UL, 1739051417UL, 2393774399UL, 2257001236UL, 1986226858UL, 4118320101UL, 3899157617UL, 3679157076UL, 3707520907UL, 551117761UL, 4267866849UL, 3679828833UL, 711086272UL, 570153549UL, 1667866621UL, 3662249794UL, 3405637490UL, 1343291195UL, +112368058UL, 2615115584UL, 2865130041UL, 357584504UL, 528807633UL, 1816055434UL, 2854850066UL, 190222907UL, 1014915859UL, 3472967123UL, 2605782564UL, 3353130066UL, 540430076UL, 2087143725UL, 1571283916UL, 1604766425UL, 934199876UL, 3359569795UL, 4168578472UL, 1745876717UL, 277026333UL, 2679446726UL, 3582165485UL, 3954458991UL, 2615245404UL, 2410035461UL, 3442004248UL, 2814474875UL, 1734556428UL, 2653422310UL, 4033890533UL, 2373774914UL, +3011118469UL, 1276695464UL, 2995405818UL, 782363735UL, 2242531852UL, 4206829780UL, 1486885236UL, 3764707851UL, 1945614253UL, 1147926733UL, 701960774UL, 3435251514UL, 3626050187UL, 3587799538UL, 2399216643UL, 3217822006UL, 3600044386UL, 648239752UL, 2997947488UL, 1754097052UL, 4109638936UL, 3413714077UL, 1038375790UL, 3394259389UL, 2284776380UL, 2711956471UL, 1278424040UL, 1272230764UL, 3980809660UL, 1983901240UL, 894405781UL, 582621606UL, +1274260631UL, 763432985UL, 1862236664UL, 10249416UL, 3838574116UL, 1912270458UL, 3491686662UL, 2696669149UL, 312119069UL, 1812714569UL, 2729307370UL, 3045249652UL, 303684944UL, 503720764UL, 4029412414UL, 4101616421UL, 3484358948UL, 1261027935UL, 145713434UL, 2918444923UL, 2099546237UL, 3173693583UL, 3498398823UL, 3769717769UL, 2860220116UL, 2919562911UL, 1221047715UL, 1749384742UL, 1018968146UL, 2771587474UL, 2746107326UL, 1182859751UL, +2403805226UL, 2206395932UL, 1500348209UL, 1762634532UL, 3017223998UL, 2043185588UL, 2124568729UL, 1619852613UL, 3248258238UL, 3393223375UL, 644860154UL, 2465108160UL, 2358875673UL, 3643741304UL, 1891106916UL, 416443047UL, 3298583974UL, 1030877276UL, 2839390034UL, 4181398645UL, 1845333999UL, 3643365079UL, 1993116780UL, 1763857175UL, 1951718545UL, 3785659537UL, 4156412284UL, 4138026128UL, 3480291142UL, 54280556UL, 4169041146UL, 3130638398UL, +3236816184UL, 3559898998UL, 916420843UL, 938920758UL, 3425021599UL, 1528477728UL, 3597939783UL, 3516249439UL, 936528538UL, 4174817780UL, 2541489033UL, 3962368135UL, 2054336507UL, 2610093970UL, 3613025255UL, 3583905994UL, 2990129491UL, 332823408UL, 2505138276UL, 3811707598UL, 373987627UL, 4263703898UL, 1668946560UL, 3213253899UL, 2673819338UL, 1631405099UL, 3127443274UL, 549232331UL, 21447814UL, 1647238011UL, 3093799993UL, 1922712395UL, +}, +{ +4224788259UL, 3569487556UL, 1080137041UL, 2788623569UL, 856160888UL, 2195536417UL, 3030463035UL, 2906439247UL, 896055051UL, 1967105456UL, 2093562169UL, 2919742950UL, 546374698UL, 1372591815UL, 3773616637UL, 349073007UL, 1331102855UL, 3035367896UL, 1222622311UL, 2266618592UL, 74466398UL, 1140488004UL, 855606859UL, 3803728487UL, 3589743162UL, 2748402856UL, 1044387368UL, 1494850922UL, 2242660891UL, 3111566003UL, 2013737074UL, 163276737UL, +1526772858UL, 3047139947UL, 3150695453UL, 2583795468UL, 3628272447UL, 305282258UL, 2151108134UL, 2905708853UL, 1052800761UL, 3354632338UL, 1017036861UL, 2453680791UL, 2673902555UL, 1622154585UL, 2893733051UL, 3888482522UL, 306284440UL, 3245137245UL, 3480776670UL, 2865396581UL, 3571456526UL, 3284891766UL, 1393584874UL, 1057867320UL, 2888126310UL, 3302325443UL, 4135187530UL, 1770789166UL, 1615533805UL, 1438727397UL, 2921922012UL, 3156703516UL, +435047591UL, 2999350446UL, 575044884UL, 1001339111UL, 625824120UL, 2489346227UL, 2104489492UL, 2494528446UL, 1141458836UL, 4048430074UL, 2599022749UL, 2438694106UL, 1443850072UL, 3321658999UL, 87870515UL, 958195816UL, 380666771UL, 3062272732UL, 4178548642UL, 4274603044UL, 888566831UL, 3386636024UL, 1636806704UL, 2400069397UL, 3003029365UL, 1953620944UL, 3278772216UL, 1562778171UL, 2767090642UL, 14436957UL, 913966574UL, 1724553886UL, +2015261135UL, 4191296122UL, 1688939147UL, 110865735UL, 2913800286UL, 4131469475UL, 315962755UL, 1531174227UL, 1226678476UL, 3446400266UL, 3896297836UL, 539834883UL, 2871306264UL, 3333932675UL, 2229436010UL, 1928458456UL, 464682640UL, 1786180352UL, 162599143UL, 817038005UL, 3146256537UL, 1676400403UL, 2484731087UL, 702610427UL, 4005124049UL, 1691076958UL, 1268494739UL, 4093608833UL, 3757213737UL, 2627839929UL, 2884764386UL, 1548110665UL, +3361745333UL, 3955318088UL, 3264527857UL, 3969225726UL, 968269281UL, 2630991382UL, 2716444139UL, 1071781623UL, 3704437685UL, 1511193802UL, 843840414UL, 1277966236UL, 4141095880UL, 715016637UL, 1255888181UL, 1321941951UL, 1180174408UL, 1021629824UL, 3395369301UL, 3912221525UL, 2611782663UL, 4038117717UL, 2253029302UL, 974431991UL, 347200257UL, 886823557UL, 2275848777UL, 3732452739UL, 3708953729UL, 2688020866UL, 4185175489UL, 99605353UL, +2387945286UL, 4224788259UL, 3569487556UL, 1080137041UL, 2788623569UL, 238715294UL, 2195536417UL, 3030463035UL, 2906439247UL, 896055051UL, 3061240402UL, 2093562169UL, 2919742950UL, 546374698UL, 1372591815UL, 851057115UL, 349073007UL, 1331102855UL, 3035367896UL, 1222622311UL, 3305595574UL, 74466398UL, 1140488004UL, 855606859UL, 3803728487UL, 3838112757UL, 2748402856UL, 1044387368UL, 1494850922UL, 2242660891UL, 1038286760UL, 2013737074UL, +163276737UL, 1526772858UL, 3047139947UL, 3518918891UL, 2583795468UL, 3628272447UL, 305282258UL, 2151108134UL, 3555155951UL, 1052800761UL, 3354632338UL, 1017036861UL, 2453680791UL, 2394691836UL, 1622154585UL, 2893733051UL, 3888482522UL, 306284440UL, 2055552069UL, 3480776670UL, 2865396581UL, 3571456526UL, 3284891766UL, 1179339312UL, 1057867320UL, 2888126310UL, 3302325443UL, 4135187530UL, 683364318UL, 1615533805UL, 1438727397UL, 2921922012UL, +3156703516UL, 1333086260UL, 2999350446UL, 575044884UL, 1001339111UL, 625824120UL, 576119652UL, 2104489492UL, 2494528446UL, 1141458836UL, 4048430074UL, 786660788UL, 2438694106UL, 1443850072UL, 3321658999UL, 87870515UL, 457955380UL, 380666771UL, 3062272732UL, 4178548642UL, 4274603044UL, 2256710588UL, 3386636024UL, 1636806704UL, 2400069397UL, 3003029365UL, 3733049985UL, 3278772216UL, 1562778171UL, 2767090642UL, 14436957UL, 530062778UL, +1724553886UL, 2015261135UL, 4191296122UL, 1688939147UL, 2981240708UL, 2913800286UL, 4131469475UL, 315962755UL, 1531174227UL, 2433363617UL, 3446400266UL, 3896297836UL, 539834883UL, 2871306264UL, 2597546929UL, 2229436010UL, 1928458456UL, 464682640UL, 1786180352UL, 1165821797UL, 817038005UL, 3146256537UL, 1676400403UL, 2484731087UL, 3239493343UL, 4005124049UL, 1691076958UL, 1268494739UL, 4093608833UL, 2088690204UL, 2627839929UL, 2884764386UL, +1548110665UL, 3361745333UL, 1075350364UL, 3264527857UL, 3969225726UL, 968269281UL, 2630991382UL, 4103280359UL, 1071781623UL, 3704437685UL, 1511193802UL, 843840414UL, 1340474980UL, 4141095880UL, 715016637UL, 1255888181UL, 1321941951UL, 2512565938UL, 1021629824UL, 3395369301UL, 3912221525UL, 2611782663UL, 2287272047UL, 2253029302UL, 974431991UL, 347200257UL, 886823557UL, 3775715445UL, 3732452739UL, 3708953729UL, 2688020866UL, 4185175489UL, +2151114047UL, 2387945286UL, 4224788259UL, 3569487556UL, 1080137041UL, 879682447UL, 238715294UL, 2195536417UL, 3030463035UL, 2906439247UL, 3975397430UL, 3061240402UL, 2093562169UL, 2919742950UL, 546374698UL, 1928060945UL, 851057115UL, 349073007UL, 1331102855UL, 3035367896UL, 1148668613UL, 3305595574UL, 74466398UL, 1140488004UL, 855606859UL, 917923571UL, 3838112757UL, 2748402856UL, 1044387368UL, 1494850922UL, 995791756UL, 1038286760UL, +2013737074UL, 163276737UL, 1526772858UL, 1944370085UL, 3518918891UL, 2583795468UL, 3628272447UL, 305282258UL, 685261037UL, 3555155951UL, 1052800761UL, 3354632338UL, 1017036861UL, 1620076466UL, 2394691836UL, 1622154585UL, 2893733051UL, 3888482522UL, 4119309151UL, 2055552069UL, 3480776670UL, 2865396581UL, 3571456526UL, 4008552940UL, 1179339312UL, 1057867320UL, 2888126310UL, 3302325443UL, 2359989247UL, 683364318UL, 1615533805UL, 1438727397UL, +2921922012UL, 2092991022UL, 1333086260UL, 2999350446UL, 575044884UL, 1001339111UL, 2406217399UL, 576119652UL, 2104489492UL, 2494528446UL, 1141458836UL, 1856565466UL, 786660788UL, 2438694106UL, 1443850072UL, 3321658999UL, 2752588925UL, 457955380UL, 380666771UL, 3062272732UL, 4178548642UL, 1354877973UL, 2256710588UL, 3386636024UL, 1636806704UL, 2400069397UL, 2275777233UL, 3733049985UL, 3278772216UL, 1562778171UL, 2767090642UL, 3438624166UL, +530062778UL, 1724553886UL, 2015261135UL, 4191296122UL, 3842215040UL, 2981240708UL, 2913800286UL, 4131469475UL, 315962755UL, 2891870900UL, 2433363617UL, 3446400266UL, 3896297836UL, 539834883UL, 1390877376UL, 2597546929UL, 2229436010UL, 1928458456UL, 464682640UL, 1405678725UL, 1165821797UL, 817038005UL, 3146256537UL, 1676400403UL, 9522151UL, 3239493343UL, 4005124049UL, 1691076958UL, 1268494739UL, 4076978821UL, 2088690204UL, 2627839929UL, +2884764386UL, 1548110665UL, 3713129550UL, 1075350364UL, 3264527857UL, 3969225726UL, 968269281UL, 2669129178UL, 4103280359UL, 1071781623UL, 3704437685UL, 1511193802UL, 2032747975UL, 1340474980UL, 4141095880UL, 715016637UL, 1255888181UL, 1290704077UL, 2512565938UL, 1021629824UL, 3395369301UL, 3912221525UL, 767420943UL, 2287272047UL, 2253029302UL, 974431991UL, 347200257UL, 940587649UL, 3775715445UL, 3732452739UL, 3708953729UL, 2688020866UL, +1603856534UL, 2151114047UL, 2387945286UL, 4224788259UL, 3569487556UL, 4060395365UL, 879682447UL, 238715294UL, 2195536417UL, 3030463035UL, 774839173UL, 3975397430UL, 3061240402UL, 2093562169UL, 2919742950UL, 77503099UL, 1928060945UL, 851057115UL, 349073007UL, 1331102855UL, 4216140027UL, 1148668613UL, 3305595574UL, 74466398UL, 1140488004UL, 1728766104UL, 917923571UL, 3838112757UL, 2748402856UL, 1044387368UL, 1408900577UL, 995791756UL, +1038286760UL, 2013737074UL, 163276737UL, 936142172UL, 1944370085UL, 3518918891UL, 2583795468UL, 3628272447UL, 1701372078UL, 685261037UL, 3555155951UL, 1052800761UL, 3354632338UL, 2951922777UL, 1620076466UL, 2394691836UL, 1622154585UL, 2893733051UL, 2494523614UL, 4119309151UL, 2055552069UL, 3480776670UL, 2865396581UL, 3031455484UL, 4008552940UL, 1179339312UL, 1057867320UL, 2888126310UL, 2970791558UL, 2359989247UL, 683364318UL, 1615533805UL, +1438727397UL, 3697460033UL, 2092991022UL, 1333086260UL, 2999350446UL, 575044884UL, 2712063736UL, 2406217399UL, 576119652UL, 2104489492UL, 2494528446UL, 1096189230UL, 1856565466UL, 786660788UL, 2438694106UL, 1443850072UL, 3615481975UL, 2752588925UL, 457955380UL, 380666771UL, 3062272732UL, 2387056252UL, 1354877973UL, 2256710588UL, 3386636024UL, 1636806704UL, 517188972UL, 2275777233UL, 3733049985UL, 3278772216UL, 1562778171UL, 3436331606UL, +3438624166UL, 530062778UL, 1724553886UL, 2015261135UL, 1711407722UL, 3842215040UL, 2981240708UL, 2913800286UL, 4131469475UL, 878455086UL, 2891870900UL, 2433363617UL, 3446400266UL, 3896297836UL, 4251949215UL, 1390877376UL, 2597546929UL, 2229436010UL, 1928458456UL, 719826541UL, 1405678725UL, 1165821797UL, 817038005UL, 3146256537UL, 3883590627UL, 9522151UL, 3239493343UL, 4005124049UL, 1691076958UL, 893183073UL, 4076978821UL, 2088690204UL, +2627839929UL, 2884764386UL, 3312769297UL, 3713129550UL, 1075350364UL, 3264527857UL, 3969225726UL, 4161107579UL, 2669129178UL, 4103280359UL, 1071781623UL, 3704437685UL, 1400940789UL, 2032747975UL, 1340474980UL, 4141095880UL, 715016637UL, 1705234794UL, 1290704077UL, 2512565938UL, 1021629824UL, 3395369301UL, 2934074199UL, 767420943UL, 2287272047UL, 2253029302UL, 974431991UL, 3060035390UL, 940587649UL, 3775715445UL, 3732452739UL, 3708953729UL, +3489160434UL, 3200799223UL, 340420813UL, 2539294182UL, 2619616318UL, 456806966UL, 4272538790UL, 2994564124UL, 2757588894UL, 3493053179UL, 2946195469UL, 1402305257UL, 2266356503UL, 3512914478UL, 273195440UL, 3579761455UL, 862317458UL, 1894959361UL, 42596779UL, 376641729UL, 782820755UL, 716528645UL, 222675565UL, 4038035195UL, 311038326UL, 395780597UL, 2025474869UL, 404396572UL, 4138962756UL, 2441107014UL, 3525378401UL, 947085768UL, +3758218091UL, 3185789607UL, 638283508UL, 3802505926UL, 830259842UL, 1086400881UL, 3444485UL, 142418107UL, 4283468141UL, 1669846189UL, 955065888UL, 3864384467UL, 73139517UL, 136809048UL, 1444329434UL, 174974637UL, 3303183786UL, 282216656UL, 3114827080UL, 3811060015UL, 1610640996UL, 3824096289UL, 1123437514UL, 3826582808UL, 39407702UL, 2437666463UL, 2454206642UL, 830758422UL, 4190092654UL, 1941090912UL, 224373276UL, 3704201239UL, +3284012568UL, 4056152539UL, 1022047941UL, 1077111803UL, 3028336675UL, 3207391465UL, 3459202233UL, 1991240724UL, 4184491520UL, 1851863093UL, 1038639595UL, 1392247730UL, 2113875749UL, 1162388509UL, 2629935260UL, 3545260772UL, 991928712UL, 4064775043UL, 4180493781UL, 2134685922UL, 642853690UL, 290065503UL, 1629968UL, 3150373868UL, 3110755428UL, 2254306163UL, 421928533UL, 11426979UL, 3042809169UL, 786868170UL, 1287942583UL, 1851107769UL, +1444903906UL, 4150950197UL, 3737798306UL, 2848738554UL, 505924220UL, 2944131627UL, 2639930627UL, 1339887691UL, 2382166850UL, 2668971315UL, 3944739049UL, 2217612340UL, 4142682607UL, 997824216UL, 123465626UL, 844518179UL, 1161486362UL, 2706162053UL, 2966530827UL, 4103639053UL, 1837121393UL, 909648429UL, 298619078UL, 2057042454UL, 3613272637UL, 3609349032UL, 1664428748UL, 1871510359UL, 58508710UL, 1079418100UL, 3278870121UL, 3821562746UL, +16654909UL, 2530580589UL, 3361874982UL, 629910009UL, 2124761646UL, 2508133604UL, 1954315500UL, 3019833617UL, 141617625UL, 1653192078UL, 1541695589UL, 1223978475UL, 3875963510UL, 3028691587UL, 3450826564UL, 2185849120UL, 1956475624UL, 3053842172UL, 3550887830UL, 2672339803UL, 176823785UL, 913229929UL, 681399502UL, 2256486297UL, 2881672598UL, 597153273UL, 2782767695UL, 1133158067UL, 4126077325UL, 3456027404UL, 754062201UL, 4069172986UL, +}, +{ +2441935114UL, 3465447683UL, 2897229686UL, 3845380309UL, 1199633364UL, 495424232UL, 2490548037UL, 581670528UL, 2467171733UL, 2200094863UL, 2163927790UL, 3895792830UL, 2097210789UL, 1606544633UL, 1305562517UL, 4072525389UL, 3256142090UL, 349440478UL, 3920932491UL, 2462464051UL, 1075951496UL, 2835763703UL, 1593198055UL, 2380945625UL, 543531323UL, 3182766507UL, 2927484354UL, 2877470578UL, 4153923603UL, 2443156156UL, 1168544900UL, 888955615UL, +3605412824UL, 1336677864UL, 3256116974UL, 2884036014UL, 4070749843UL, 2989661773UL, 1095584023UL, 1370834065UL, 3534389580UL, 312378113UL, 3190819203UL, 1247574926UL, 2046019470UL, 3536918510UL, 1479030180UL, 847820646UL, 3992973956UL, 3827223401UL, 4113429617UL, 3504933502UL, 295000614UL, 2238923504UL, 3485717254UL, 290246351UL, 1064210816UL, 2848539559UL, 2617134888UL, 422213010UL, 2796674561UL, 3568250500UL, 2736237915UL, 3950756060UL, +1527249993UL, 3603540278UL, 4115393386UL, 2851621193UL, 4230341156UL, 905168850UL, 3916344126UL, 1496013046UL, 206343742UL, 2894205125UL, 1082918859UL, 2746480417UL, 3077328661UL, 1209440053UL, 3258293856UL, 1032236533UL, 3043332566UL, 446879604UL, 587022214UL, 1614371566UL, 3040899994UL, 3686422145UL, 937325128UL, 1968833679UL, 169086151UL, 4075432555UL, 1196046411UL, 3101745581UL, 4228079966UL, 2942213563UL, 1195005323UL, 1673491641UL, +1762746534UL, 3641827252UL, 694590905UL, 1828365460UL, 513716230UL, 3106485486UL, 2441593994UL, 4044462965UL, 3628121101UL, 3957990629UL, 179764922UL, 579361186UL, 3474393871UL, 2474241006UL, 4031850878UL, 3120409532UL, 4011587898UL, 3682942579UL, 3257272830UL, 3097029759UL, 2652540191UL, 1128762588UL, 1040256382UL, 2743736716UL, 334893087UL, 1892049031UL, 2603159239UL, 3712772023UL, 2126593224UL, 3465793906UL, 3180780589UL, 725740783UL, +3728108967UL, 573931936UL, 137996587UL, 110756053UL, 3984787930UL, 3773232816UL, 3406981985UL, 1783088630UL, 2080089781UL, 195827466UL, 1409073281UL, 867635355UL, 3049533211UL, 486687054UL, 2570137956UL, 527522011UL, 1084454084UL, 1019222771UL, 1415565066UL, 650794786UL, 629618803UL, 1237709131UL, 1241899078UL, 2751644247UL, 2792313337UL, 649402117UL, 275078659UL, 752459111UL, 2173220853UL, 3207031798UL, 821073585UL, 3005400729UL, +1085152012UL, 2441935114UL, 3465447683UL, 2897229686UL, 3845380309UL, 3573898488UL, 495424232UL, 2490548037UL, 581670528UL, 2467171733UL, 1208279791UL, 2163927790UL, 3895792830UL, 2097210789UL, 1606544633UL, 2148733343UL, 4072525389UL, 3256142090UL, 349440478UL, 3920932491UL, 657289255UL, 1075951496UL, 2835763703UL, 1593198055UL, 2380945625UL, 149487931UL, 3182766507UL, 2927484354UL, 2877470578UL, 4153923603UL, 606130344UL, 1168544900UL, +888955615UL, 3605412824UL, 1336677864UL, 53448770UL, 2884036014UL, 4070749843UL, 2989661773UL, 1095584023UL, 2766144383UL, 3534389580UL, 312378113UL, 3190819203UL, 1247574926UL, 1530609481UL, 3536918510UL, 1479030180UL, 847820646UL, 3992973956UL, 154171325UL, 4113429617UL, 3504933502UL, 295000614UL, 2238923504UL, 282708664UL, 290246351UL, 1064210816UL, 2848539559UL, 2617134888UL, 36906646UL, 2796674561UL, 3568250500UL, 2736237915UL, +3950756060UL, 3416260072UL, 3603540278UL, 4115393386UL, 2851621193UL, 4230341156UL, 448215287UL, 3916344126UL, 1496013046UL, 206343742UL, 2894205125UL, 2420861244UL, 2746480417UL, 3077328661UL, 1209440053UL, 3258293856UL, 2545287695UL, 3043332566UL, 446879604UL, 587022214UL, 1614371566UL, 958587333UL, 3686422145UL, 937325128UL, 1968833679UL, 169086151UL, 154576725UL, 1196046411UL, 3101745581UL, 4228079966UL, 2942213563UL, 2487464668UL, +1673491641UL, 1762746534UL, 3641827252UL, 694590905UL, 3754606623UL, 513716230UL, 3106485486UL, 2441593994UL, 4044462965UL, 3064108377UL, 3957990629UL, 179764922UL, 579361186UL, 3474393871UL, 2138270428UL, 4031850878UL, 3120409532UL, 4011587898UL, 3682942579UL, 4015980199UL, 3097029759UL, 2652540191UL, 1128762588UL, 1040256382UL, 3908621649UL, 334893087UL, 1892049031UL, 2603159239UL, 3712772023UL, 3291038350UL, 3465793906UL, 3180780589UL, +725740783UL, 3728108967UL, 436976908UL, 137996587UL, 110756053UL, 3984787930UL, 3773232816UL, 1000054791UL, 1783088630UL, 2080089781UL, 195827466UL, 1409073281UL, 3036813614UL, 3049533211UL, 486687054UL, 2570137956UL, 527522011UL, 3669951690UL, 1019222771UL, 1415565066UL, 650794786UL, 629618803UL, 4140569538UL, 1241899078UL, 2751644247UL, 2792313337UL, 649402117UL, 2946582304UL, 752459111UL, 2173220853UL, 3207031798UL, 821073585UL, +1738142977UL, 1085152012UL, 2441935114UL, 3465447683UL, 2897229686UL, 2707197334UL, 3573898488UL, 495424232UL, 2490548037UL, 581670528UL, 2365865647UL, 1208279791UL, 2163927790UL, 3895792830UL, 2097210789UL, 3219551420UL, 2148733343UL, 4072525389UL, 3256142090UL, 349440478UL, 3706519197UL, 657289255UL, 1075951496UL, 2835763703UL, 1593198055UL, 2200084531UL, 149487931UL, 3182766507UL, 2927484354UL, 2877470578UL, 2394288661UL, 606130344UL, +1168544900UL, 888955615UL, 3605412824UL, 1503975597UL, 53448770UL, 2884036014UL, 4070749843UL, 2989661773UL, 243605110UL, 2766144383UL, 3534389580UL, 312378113UL, 3190819203UL, 2398088088UL, 1530609481UL, 3536918510UL, 1479030180UL, 847820646UL, 2940281320UL, 154171325UL, 4113429617UL, 3504933502UL, 295000614UL, 3078701806UL, 282708664UL, 290246351UL, 1064210816UL, 2848539559UL, 3960345380UL, 36906646UL, 2796674561UL, 3568250500UL, +2736237915UL, 2657034787UL, 3416260072UL, 3603540278UL, 4115393386UL, 2851621193UL, 3847740427UL, 448215287UL, 3916344126UL, 1496013046UL, 206343742UL, 3419083433UL, 2420861244UL, 2746480417UL, 3077328661UL, 1209440053UL, 3824237152UL, 2545287695UL, 3043332566UL, 446879604UL, 587022214UL, 506352928UL, 958587333UL, 3686422145UL, 937325128UL, 1968833679UL, 1808935939UL, 154576725UL, 1196046411UL, 3101745581UL, 4228079966UL, 709576348UL, +2487464668UL, 1673491641UL, 1762746534UL, 3641827252UL, 3968332142UL, 3754606623UL, 513716230UL, 3106485486UL, 2441593994UL, 1453443785UL, 3064108377UL, 3957990629UL, 179764922UL, 579361186UL, 1454621561UL, 2138270428UL, 4031850878UL, 3120409532UL, 4011587898UL, 898119245UL, 4015980199UL, 3097029759UL, 2652540191UL, 1128762588UL, 1131456853UL, 3908621649UL, 334893087UL, 1892049031UL, 2603159239UL, 4280222837UL, 3291038350UL, 3465793906UL, +3180780589UL, 725740783UL, 1515867399UL, 436976908UL, 137996587UL, 110756053UL, 3984787930UL, 1295994548UL, 1000054791UL, 1783088630UL, 2080089781UL, 195827466UL, 252558267UL, 3036813614UL, 3049533211UL, 486687054UL, 2570137956UL, 786434419UL, 3669951690UL, 1019222771UL, 1415565066UL, 650794786UL, 1316734597UL, 4140569538UL, 1241899078UL, 2751644247UL, 2792313337UL, 4014748337UL, 2946582304UL, 752459111UL, 2173220853UL, 3207031798UL, +2903407363UL, 1738142977UL, 1085152012UL, 2441935114UL, 3465447683UL, 1082984764UL, 2707197334UL, 3573898488UL, 495424232UL, 2490548037UL, 240094068UL, 2365865647UL, 1208279791UL, 2163927790UL, 3895792830UL, 1107651215UL, 3219551420UL, 2148733343UL, 4072525389UL, 3256142090UL, 681942656UL, 3706519197UL, 657289255UL, 1075951496UL, 2835763703UL, 2172774506UL, 2200084531UL, 149487931UL, 3182766507UL, 2927484354UL, 3069592433UL, 2394288661UL, +606130344UL, 1168544900UL, 888955615UL, 757163746UL, 1503975597UL, 53448770UL, 2884036014UL, 4070749843UL, 1705538727UL, 243605110UL, 2766144383UL, 3534389580UL, 312378113UL, 2256467250UL, 2398088088UL, 1530609481UL, 3536918510UL, 1479030180UL, 1360826079UL, 2940281320UL, 154171325UL, 4113429617UL, 3504933502UL, 714934244UL, 3078701806UL, 282708664UL, 290246351UL, 1064210816UL, 3694453051UL, 3960345380UL, 36906646UL, 2796674561UL, +3568250500UL, 3400481963UL, 2657034787UL, 3416260072UL, 3603540278UL, 4115393386UL, 1466632735UL, 3847740427UL, 448215287UL, 3916344126UL, 1496013046UL, 2893537514UL, 3419083433UL, 2420861244UL, 2746480417UL, 3077328661UL, 2815979224UL, 3824237152UL, 2545287695UL, 3043332566UL, 446879604UL, 3719452721UL, 506352928UL, 958587333UL, 3686422145UL, 937325128UL, 2653904510UL, 1808935939UL, 154576725UL, 1196046411UL, 3101745581UL, 425411544UL, +709576348UL, 2487464668UL, 1673491641UL, 1762746534UL, 1960605594UL, 3968332142UL, 3754606623UL, 513716230UL, 3106485486UL, 2881551071UL, 1453443785UL, 3064108377UL, 3957990629UL, 179764922UL, 1408218536UL, 1454621561UL, 2138270428UL, 4031850878UL, 3120409532UL, 3700386494UL, 898119245UL, 4015980199UL, 3097029759UL, 2652540191UL, 2181464767UL, 1131456853UL, 3908621649UL, 334893087UL, 1892049031UL, 4220220071UL, 4280222837UL, 3291038350UL, +3465793906UL, 3180780589UL, 1737123182UL, 1515867399UL, 436976908UL, 137996587UL, 110756053UL, 1360813614UL, 1295994548UL, 1000054791UL, 1783088630UL, 2080089781UL, 1019367341UL, 252558267UL, 3036813614UL, 3049533211UL, 486687054UL, 387915679UL, 786434419UL, 3669951690UL, 1019222771UL, 1415565066UL, 4267042909UL, 1316734597UL, 4140569538UL, 1241899078UL, 2751644247UL, 3622120385UL, 4014748337UL, 2946582304UL, 752459111UL, 2173220853UL, +1128460687UL, 2268047031UL, 239933818UL, 4141570430UL, 1318816940UL, 2378987660UL, 731877825UL, 3950952879UL, 2975574698UL, 2938375136UL, 431933385UL, 154404673UL, 2020658234UL, 846815781UL, 822137193UL, 1057315444UL, 3632584082UL, 3263363094UL, 942201956UL, 2704683551UL, 1768107067UL, 4009446092UL, 3090701064UL, 701246680UL, 3548419575UL, 3873366129UL, 1639833080UL, 2401253373UL, 66597794UL, 2515774132UL, 516246524UL, 4232115668UL, +34426096UL, 2206423458UL, 3628832867UL, 2776950121UL, 2782943544UL, 2058958317UL, 1805852726UL, 2151415233UL, 2940074103UL, 2318397273UL, 3067676663UL, 3127709351UL, 71509976UL, 115529187UL, 1841252918UL, 2217805156UL, 733917373UL, 2432474677UL, 1416887641UL, 1895320369UL, 2779694586UL, 510547269UL, 2614743018UL, 759552691UL, 2264773752UL, 305497497UL, 1082013785UL, 1681067734UL, 1085957001UL, 846460632UL, 2824079919UL, 1820633139UL, +3686495295UL, 3978521319UL, 1734452426UL, 4105472656UL, 1771256166UL, 1578071897UL, 1972844727UL, 2048372515UL, 3002132226UL, 1889169118UL, 2932142799UL, 2166712623UL, 592016143UL, 1116895096UL, 889321536UL, 375621825UL, 2935845994UL, 1982459859UL, 3336799370UL, 294519309UL, 2661638345UL, 1089335942UL, 227150969UL, 1454919198UL, 3780503305UL, 1862290968UL, 1491836299UL, 766546986UL, 3638407467UL, 925906735UL, 208891816UL, 236714698UL, +2853181150UL, 3889751556UL, 2161215392UL, 853579433UL, 2131555681UL, 1396396345UL, 1088128136UL, 978252562UL, 2134024308UL, 2429920974UL, 1159468871UL, 2395949266UL, 1441791888UL, 916521377UL, 3950270431UL, 2663319810UL, 3873120593UL, 2080989388UL, 2896532502UL, 3176181708UL, 1736685126UL, 4081767288UL, 3515770288UL, 1371473598UL, 1491850178UL, 4284949727UL, 2774513541UL, 1541596000UL, 3948112869UL, 2114538326UL, 2641532252UL, 1837244955UL, +2292505300UL, 3179787565UL, 639953781UL, 785902378UL, 3852544833UL, 553508260UL, 23014564UL, 106722100UL, 2705412979UL, 3449440367UL, 950636401UL, 870804158UL, 629831074UL, 424163855UL, 373653940UL, 2739378330UL, 377730945UL, 418426029UL, 267367218UL, 554678849UL, 4222664331UL, 3346048120UL, 1870226737UL, 2435616108UL, 3747040233UL, 698046507UL, 1671346285UL, 4127293033UL, 568612264UL, 3467142937UL, 1627988025UL, 1305525598UL, +}, +{ +2246605826UL, 215030128UL, 871645668UL, 3402612852UL, 423273439UL, 316965236UL, 47416561UL, 1470716454UL, 2288582385UL, 2021890755UL, 2148091363UL, 167227868UL, 3085506034UL, 3365950545UL, 1170282137UL, 1345986409UL, 197195155UL, 2644113318UL, 2491271090UL, 2597072003UL, 170335901UL, 2540851884UL, 2584420407UL, 3609142920UL, 3052130502UL, 4018095157UL, 2850805299UL, 2777821400UL, 110647395UL, 3262987676UL, 1447103309UL, 3632575579UL, +3243210595UL, 1892770504UL, 4214485953UL, 38676169UL, 2431628817UL, 2836918800UL, 272023527UL, 2825888902UL, 2794421955UL, 2354379386UL, 452404203UL, 584718212UL, 1915053836UL, 1455821656UL, 4264066935UL, 1150980581UL, 3792433350UL, 3104909316UL, 441521402UL, 3807587668UL, 275969953UL, 3970844623UL, 3323695518UL, 3909107329UL, 290225599UL, 957520066UL, 4048181850UL, 2623778463UL, 1957371891UL, 540091753UL, 3072448879UL, 2386916346UL, +392549194UL, 1261391184UL, 4137605148UL, 314807135UL, 2916930821UL, 3168561018UL, 2332027308UL, 1967082817UL, 1849256214UL, 1141134412UL, 1206824012UL, 2088102210UL, 4170914605UL, 3399892824UL, 59190648UL, 1657183299UL, 1314626253UL, 500606287UL, 413229420UL, 1245395908UL, 664681UL, 2726979120UL, 3408998445UL, 2318397638UL, 1882820077UL, 2073055266UL, 4262833629UL, 1348801932UL, 229857331UL, 3086071450UL, 1327801028UL, 812015573UL, +2214355282UL, 2232635690UL, 3162540418UL, 2049877621UL, 470752564UL, 2527480795UL, 1285499716UL, 220173566UL, 4239277569UL, 788168494UL, 3748855859UL, 1360707769UL, 449512212UL, 1238219398UL, 2880205975UL, 2755133627UL, 372409230UL, 411800575UL, 2455333195UL, 4080817864UL, 3556684908UL, 2857940866UL, 1969081563UL, 2526852668UL, 1026062474UL, 1849785784UL, 3552290093UL, 4214448UL, 460332681UL, 30890894UL, 1108618048UL, 272438799UL, +3339891045UL, 1512685591UL, 1310038443UL, 2431938882UL, 1478442144UL, 2804640700UL, 3426381347UL, 861206186UL, 290322827UL, 2736623609UL, 327318125UL, 1922859957UL, 1939922519UL, 3539608908UL, 3442377433UL, 3868710131UL, 2244493875UL, 47774461UL, 3858864626UL, 3294523981UL, 1798515481UL, 565017248UL, 2633378137UL, 811307482UL, 1743357106UL, 419676111UL, 1688841846UL, 1799884674UL, 1720546272UL, 3900863156UL, 3506303345UL, 1719438472UL, +576775454UL, 2246605826UL, 215030128UL, 871645668UL, 3402612852UL, 619000856UL, 316965236UL, 47416561UL, 1470716454UL, 2288582385UL, 3464704266UL, 2148091363UL, 167227868UL, 3085506034UL, 3365950545UL, 901169164UL, 1345986409UL, 197195155UL, 2644113318UL, 2491271090UL, 3243741640UL, 170335901UL, 2540851884UL, 2584420407UL, 3609142920UL, 2051834116UL, 4018095157UL, 2850805299UL, 2777821400UL, 110647395UL, 2822981113UL, 1447103309UL, +3632575579UL, 3243210595UL, 1892770504UL, 1947501555UL, 38676169UL, 2431628817UL, 2836918800UL, 272023527UL, 4010280501UL, 2794421955UL, 2354379386UL, 452404203UL, 584718212UL, 3991257933UL, 1455821656UL, 4264066935UL, 1150980581UL, 3792433350UL, 2151631692UL, 441521402UL, 3807587668UL, 275969953UL, 3970844623UL, 3965914153UL, 3909107329UL, 290225599UL, 957520066UL, 4048181850UL, 4011285909UL, 1957371891UL, 540091753UL, 3072448879UL, +2386916346UL, 1347453316UL, 1261391184UL, 4137605148UL, 314807135UL, 2916930821UL, 840822698UL, 2332027308UL, 1967082817UL, 1849256214UL, 1141134412UL, 960593185UL, 2088102210UL, 4170914605UL, 3399892824UL, 59190648UL, 2261593014UL, 1314626253UL, 500606287UL, 413229420UL, 1245395908UL, 3401527918UL, 2726979120UL, 3408998445UL, 2318397638UL, 1882820077UL, 1683077666UL, 4262833629UL, 1348801932UL, 229857331UL, 3086071450UL, 3363644507UL, +812015573UL, 2214355282UL, 2232635690UL, 3162540418UL, 3579858747UL, 470752564UL, 2527480795UL, 1285499716UL, 220173566UL, 2294101261UL, 788168494UL, 3748855859UL, 1360707769UL, 449512212UL, 28595866UL, 2880205975UL, 2755133627UL, 372409230UL, 411800575UL, 1905311140UL, 4080817864UL, 3556684908UL, 2857940866UL, 1969081563UL, 148561593UL, 1026062474UL, 1849785784UL, 3552290093UL, 4214448UL, 2237247821UL, 30890894UL, 1108618048UL, +272438799UL, 3339891045UL, 169576507UL, 1310038443UL, 2431938882UL, 1478442144UL, 2804640700UL, 4119485855UL, 861206186UL, 290322827UL, 2736623609UL, 327318125UL, 3408620608UL, 1939922519UL, 3539608908UL, 3442377433UL, 3868710131UL, 1188056275UL, 47774461UL, 3858864626UL, 3294523981UL, 1798515481UL, 1228896851UL, 2633378137UL, 811307482UL, 1743357106UL, 419676111UL, 3111013241UL, 1799884674UL, 1720546272UL, 3900863156UL, 3506303345UL, +1474164586UL, 576775454UL, 2246605826UL, 215030128UL, 871645668UL, 2968519387UL, 619000856UL, 316965236UL, 47416561UL, 1470716454UL, 9648980UL, 3464704266UL, 2148091363UL, 167227868UL, 3085506034UL, 1505294373UL, 901169164UL, 1345986409UL, 197195155UL, 2644113318UL, 1227359150UL, 3243741640UL, 170335901UL, 2540851884UL, 2584420407UL, 1205921163UL, 2051834116UL, 4018095157UL, 2850805299UL, 2777821400UL, 2967529310UL, 2822981113UL, +1447103309UL, 3632575579UL, 3243210595UL, 532996977UL, 1947501555UL, 38676169UL, 2431628817UL, 2836918800UL, 1761031313UL, 4010280501UL, 2794421955UL, 2354379386UL, 452404203UL, 1222630846UL, 3991257933UL, 1455821656UL, 4264066935UL, 1150980581UL, 2344548386UL, 2151631692UL, 441521402UL, 3807587668UL, 275969953UL, 963889269UL, 3965914153UL, 3909107329UL, 290225599UL, 957520066UL, 4176220201UL, 4011285909UL, 1957371891UL, 540091753UL, +3072448879UL, 1810164615UL, 1347453316UL, 1261391184UL, 4137605148UL, 314807135UL, 2672526663UL, 840822698UL, 2332027308UL, 1967082817UL, 1849256214UL, 734862208UL, 960593185UL, 2088102210UL, 4170914605UL, 3399892824UL, 2471507530UL, 2261593014UL, 1314626253UL, 500606287UL, 413229420UL, 970185057UL, 3401527918UL, 2726979120UL, 3408998445UL, 2318397638UL, 708987193UL, 1683077666UL, 4262833629UL, 1348801932UL, 229857331UL, 749849397UL, +3363644507UL, 812015573UL, 2214355282UL, 2232635690UL, 2901095495UL, 3579858747UL, 470752564UL, 2527480795UL, 1285499716UL, 941862108UL, 2294101261UL, 788168494UL, 3748855859UL, 1360707769UL, 3818227212UL, 28595866UL, 2880205975UL, 2755133627UL, 372409230UL, 570110534UL, 1905311140UL, 4080817864UL, 3556684908UL, 2857940866UL, 2253777974UL, 148561593UL, 1026062474UL, 1849785784UL, 3552290093UL, 1525559608UL, 2237247821UL, 30890894UL, +1108618048UL, 272438799UL, 3996203631UL, 169576507UL, 1310038443UL, 2431938882UL, 1478442144UL, 2857841871UL, 4119485855UL, 861206186UL, 290322827UL, 2736623609UL, 1184217272UL, 3408620608UL, 1939922519UL, 3539608908UL, 3442377433UL, 1263700272UL, 1188056275UL, 47774461UL, 3858864626UL, 3294523981UL, 2611619UL, 1228896851UL, 2633378137UL, 811307482UL, 1743357106UL, 1930089302UL, 3111013241UL, 1799884674UL, 1720546272UL, 3900863156UL, +2370003471UL, 1474164586UL, 576775454UL, 2246605826UL, 215030128UL, 540197019UL, 2968519387UL, 619000856UL, 316965236UL, 47416561UL, 3585128733UL, 9648980UL, 3464704266UL, 2148091363UL, 167227868UL, 509283324UL, 1505294373UL, 901169164UL, 1345986409UL, 197195155UL, 3983525470UL, 1227359150UL, 3243741640UL, 170335901UL, 2540851884UL, 2812935262UL, 1205921163UL, 2051834116UL, 4018095157UL, 2850805299UL, 2798430304UL, 2967529310UL, +2822981113UL, 1447103309UL, 3632575579UL, 389184524UL, 532996977UL, 1947501555UL, 38676169UL, 2431628817UL, 1055068556UL, 1761031313UL, 4010280501UL, 2794421955UL, 2354379386UL, 965687576UL, 1222630846UL, 3991257933UL, 1455821656UL, 4264066935UL, 1551000086UL, 2344548386UL, 2151631692UL, 441521402UL, 3807587668UL, 3701529910UL, 963889269UL, 3965914153UL, 3909107329UL, 290225599UL, 1771599976UL, 4176220201UL, 4011285909UL, 1957371891UL, +540091753UL, 1670159873UL, 1810164615UL, 1347453316UL, 1261391184UL, 4137605148UL, 4191698993UL, 2672526663UL, 840822698UL, 2332027308UL, 1967082817UL, 3098515331UL, 734862208UL, 960593185UL, 2088102210UL, 4170914605UL, 2470055060UL, 2471507530UL, 2261593014UL, 1314626253UL, 500606287UL, 1100764382UL, 970185057UL, 3401527918UL, 2726979120UL, 3408998445UL, 4100198161UL, 708987193UL, 1683077666UL, 4262833629UL, 1348801932UL, 3744209503UL, +749849397UL, 3363644507UL, 812015573UL, 2214355282UL, 3217409412UL, 2901095495UL, 3579858747UL, 470752564UL, 2527480795UL, 552979949UL, 941862108UL, 2294101261UL, 788168494UL, 3748855859UL, 2355231228UL, 3818227212UL, 28595866UL, 2880205975UL, 2755133627UL, 833553378UL, 570110534UL, 1905311140UL, 4080817864UL, 3556684908UL, 4124102038UL, 2253777974UL, 148561593UL, 1026062474UL, 1849785784UL, 656329297UL, 1525559608UL, 2237247821UL, +30890894UL, 1108618048UL, 1464443032UL, 3996203631UL, 169576507UL, 1310038443UL, 2431938882UL, 2100788071UL, 2857841871UL, 4119485855UL, 861206186UL, 290322827UL, 3653047356UL, 1184217272UL, 3408620608UL, 1939922519UL, 3539608908UL, 4267170500UL, 1263700272UL, 1188056275UL, 47774461UL, 3858864626UL, 1046565728UL, 2611619UL, 1228896851UL, 2633378137UL, 811307482UL, 1312393456UL, 1930089302UL, 3111013241UL, 1799884674UL, 1720546272UL, +1199041144UL, 2406753856UL, 2108495166UL, 2126345981UL, 1524975128UL, 1269232392UL, 3162531748UL, 3076707658UL, 1736955170UL, 1036221745UL, 1232435193UL, 3945348482UL, 1057631163UL, 520376289UL, 4154435769UL, 1280565077UL, 1865705876UL, 1030078366UL, 1140849319UL, 1769263412UL, 1161866807UL, 2768552980UL, 561022685UL, 2712685799UL, 1501252058UL, 3608433719UL, 3138564149UL, 4093654128UL, 1218455911UL, 892700607UL, 2012017510UL, 3568315757UL, +4002239824UL, 1754440379UL, 2641708101UL, 1027390781UL, 199831087UL, 1261208885UL, 2058433786UL, 2101649235UL, 220966013UL, 3445375335UL, 1100438514UL, 4075559840UL, 4244062658UL, 3417249884UL, 150102478UL, 3337395219UL, 2464869101UL, 3720375949UL, 93353579UL, 2329780067UL, 777826834UL, 2745626035UL, 2984812746UL, 568848158UL, 1593919595UL, 1166619196UL, 96177504UL, 305329591UL, 4271176854UL, 3829149188UL, 1551058535UL, 2828280993UL, +1367551996UL, 4208083082UL, 2260803683UL, 3118708147UL, 434935608UL, 702805370UL, 3544156958UL, 792712531UL, 231019757UL, 136272259UL, 4049968615UL, 2722527811UL, 603697698UL, 2891035509UL, 4270409302UL, 1220615076UL, 1932569338UL, 1084454986UL, 468729683UL, 2377913518UL, 2068946556UL, 530579176UL, 1422294615UL, 4032799503UL, 2065706770UL, 604700228UL, 98049660UL, 3182511353UL, 935830212UL, 1938107848UL, 1266035034UL, 957505506UL, +2758220503UL, 1805223938UL, 3393041584UL, 3958541336UL, 2695487012UL, 3355668819UL, 276889675UL, 3098939423UL, 415941187UL, 180737121UL, 2638873657UL, 1103150707UL, 4255168358UL, 2736183195UL, 1275942292UL, 2687807236UL, 538129710UL, 3337005391UL, 3941968393UL, 1113153386UL, 3813628384UL, 1775835369UL, 296314749UL, 1697642748UL, 3614403315UL, 1953056095UL, 2102878063UL, 3161706344UL, 2207159580UL, 3078233525UL, 3836286614UL, 886914072UL, +1884037075UL, 4135819784UL, 1616380780UL, 1672616998UL, 3879848699UL, 2277472209UL, 3933249848UL, 2428044648UL, 2876076879UL, 165724720UL, 2277165385UL, 1984963196UL, 1456923194UL, 2406217222UL, 3388886718UL, 47522558UL, 1903557801UL, 1959641458UL, 2325355446UL, 3251147398UL, 2266553941UL, 2243962024UL, 1420017618UL, 1791159474UL, 1793406225UL, 601509698UL, 3207357979UL, 1189285184UL, 148538800UL, 2077251302UL, 3267239327UL, 2851475997UL, +}, +{ +2628162153UL, 3861478870UL, 2769884494UL, 3423483820UL, 1118276924UL, 536776894UL, 3742490940UL, 550084334UL, 2441329856UL, 2604618499UL, 2308745810UL, 1178166365UL, 1345165241UL, 4039508109UL, 1246601384UL, 3843182157UL, 2200144237UL, 91750284UL, 4290064840UL, 3363597477UL, 3243492274UL, 4271100308UL, 4186328336UL, 2291901989UL, 1834723222UL, 372220743UL, 2190417067UL, 2624886324UL, 3567647862UL, 1591175369UL, 2278087682UL, 2461678432UL, +232820452UL, 2714694382UL, 3070258434UL, 2412655444UL, 2667664607UL, 249083056UL, 4166379751UL, 1360927521UL, 2247816079UL, 3253689753UL, 1563674427UL, 1914999382UL, 2101454952UL, 1067816947UL, 1098201917UL, 4054175236UL, 1805828534UL, 1815913104UL, 738357340UL, 2597170030UL, 1689737432UL, 2004663483UL, 1160995461UL, 1008175050UL, 2004702919UL, 4258654415UL, 938972594UL, 2121583885UL, 2208729114UL, 276726877UL, 3973538591UL, 2991069145UL, +2345655326UL, 2980162173UL, 1915611444UL, 2332104940UL, 2382102873UL, 2324437093UL, 2640563452UL, 2680619359UL, 3413490949UL, 2140843463UL, 2424016743UL, 3735508133UL, 3421831326UL, 4037977349UL, 3721506282UL, 510431975UL, 1014707294UL, 1378686477UL, 1939678832UL, 2223101760UL, 2067687989UL, 309274614UL, 276596103UL, 3757624719UL, 1212251468UL, 2649271847UL, 4140361758UL, 2634738350UL, 2029358730UL, 3205861896UL, 3090549771UL, 3775019657UL, +2018542036UL, 3675805680UL, 3946144023UL, 331655838UL, 326568491UL, 1867863527UL, 1550945400UL, 3087000670UL, 2342003578UL, 3949479453UL, 586483056UL, 147951307UL, 503062740UL, 3823927166UL, 2789767841UL, 3121654578UL, 634238762UL, 4084629478UL, 3878778788UL, 435990088UL, 1724770389UL, 1403031256UL, 1334135626UL, 1096780503UL, 3288769545UL, 2793293893UL, 80675548UL, 1637232257UL, 1856565474UL, 2675485635UL, 1961165681UL, 1647512786UL, +4190102851UL, 4081320784UL, 2853183400UL, 3812341867UL, 278236392UL, 1700614299UL, 2765246084UL, 3846866009UL, 1220806787UL, 3655684157UL, 1133921183UL, 2779125219UL, 523552281UL, 703813725UL, 3110126767UL, 823843890UL, 290243102UL, 821297176UL, 364959993UL, 3381862130UL, 2305271841UL, 356059263UL, 2558018765UL, 3235968999UL, 1070598970UL, 2444411636UL, 3636221117UL, 4275517214UL, 4035198865UL, 3339014315UL, 2911872812UL, 4049586122UL, +4211583637UL, 2628162153UL, 3861478870UL, 2769884494UL, 3423483820UL, 3254616321UL, 536776894UL, 3742490940UL, 550084334UL, 2441329856UL, 1909596092UL, 2308745810UL, 1178166365UL, 1345165241UL, 4039508109UL, 1349347043UL, 3843182157UL, 2200144237UL, 91750284UL, 4290064840UL, 803098068UL, 3243492274UL, 4271100308UL, 4186328336UL, 2291901989UL, 2575673198UL, 372220743UL, 2190417067UL, 2624886324UL, 3567647862UL, 132569424UL, 2278087682UL, +2461678432UL, 232820452UL, 2714694382UL, 3490648253UL, 2412655444UL, 2667664607UL, 249083056UL, 4166379751UL, 3503294711UL, 2247816079UL, 3253689753UL, 1563674427UL, 1914999382UL, 3121933565UL, 1067816947UL, 1098201917UL, 4054175236UL, 1805828534UL, 816420552UL, 738357340UL, 2597170030UL, 1689737432UL, 2004663483UL, 397934907UL, 1008175050UL, 2004702919UL, 4258654415UL, 938972594UL, 156733019UL, 2208729114UL, 276726877UL, 3973538591UL, +2991069145UL, 2470446383UL, 2980162173UL, 1915611444UL, 2332104940UL, 2382102873UL, 3265195583UL, 2640563452UL, 2680619359UL, 3413490949UL, 2140843463UL, 142464483UL, 3735508133UL, 3421831326UL, 4037977349UL, 3721506282UL, 1898668265UL, 1014707294UL, 1378686477UL, 1939678832UL, 2223101760UL, 4085776926UL, 309274614UL, 276596103UL, 3757624719UL, 1212251468UL, 1116423339UL, 4140361758UL, 2634738350UL, 2029358730UL, 3205861896UL, 880658361UL, +3775019657UL, 2018542036UL, 3675805680UL, 3946144023UL, 839516623UL, 326568491UL, 1867863527UL, 1550945400UL, 3087000670UL, 420309880UL, 3949479453UL, 586483056UL, 147951307UL, 503062740UL, 416618471UL, 2789767841UL, 3121654578UL, 634238762UL, 4084629478UL, 1120413065UL, 435990088UL, 1724770389UL, 1403031256UL, 1334135626UL, 240966420UL, 3288769545UL, 2793293893UL, 80675548UL, 1637232257UL, 1785064235UL, 2675485635UL, 1961165681UL, +1647512786UL, 4190102851UL, 2775407492UL, 2853183400UL, 3812341867UL, 278236392UL, 1700614299UL, 2439624528UL, 3846866009UL, 1220806787UL, 3655684157UL, 1133921183UL, 366933679UL, 523552281UL, 703813725UL, 3110126767UL, 823843890UL, 132468066UL, 821297176UL, 364959993UL, 3381862130UL, 2305271841UL, 1048450041UL, 2558018765UL, 3235968999UL, 1070598970UL, 2444411636UL, 1699430013UL, 4275517214UL, 4035198865UL, 3339014315UL, 2911872812UL, +324524850UL, 4211583637UL, 2628162153UL, 3861478870UL, 2769884494UL, 1995585079UL, 3254616321UL, 536776894UL, 3742490940UL, 550084334UL, 2121458511UL, 1909596092UL, 2308745810UL, 1178166365UL, 1345165241UL, 3067877274UL, 1349347043UL, 3843182157UL, 2200144237UL, 91750284UL, 1246148630UL, 803098068UL, 3243492274UL, 4271100308UL, 4186328336UL, 2932236493UL, 2575673198UL, 372220743UL, 2190417067UL, 2624886324UL, 3945294599UL, 132569424UL, +2278087682UL, 2461678432UL, 232820452UL, 3341915918UL, 3490648253UL, 2412655444UL, 2667664607UL, 249083056UL, 2307336284UL, 3503294711UL, 2247816079UL, 3253689753UL, 1563674427UL, 1717494311UL, 3121933565UL, 1067816947UL, 1098201917UL, 4054175236UL, 971917867UL, 816420552UL, 738357340UL, 2597170030UL, 1689737432UL, 243915062UL, 397934907UL, 1008175050UL, 2004702919UL, 4258654415UL, 1807067458UL, 156733019UL, 2208729114UL, 276726877UL, +3973538591UL, 1909483753UL, 2470446383UL, 2980162173UL, 1915611444UL, 2332104940UL, 3454651559UL, 3265195583UL, 2640563452UL, 2680619359UL, 3413490949UL, 462852932UL, 142464483UL, 3735508133UL, 3421831326UL, 4037977349UL, 1372088341UL, 1898668265UL, 1014707294UL, 1378686477UL, 1939678832UL, 752503486UL, 4085776926UL, 309274614UL, 276596103UL, 3757624719UL, 4193030119UL, 1116423339UL, 4140361758UL, 2634738350UL, 2029358730UL, 1725105892UL, +880658361UL, 3775019657UL, 2018542036UL, 3675805680UL, 3496508290UL, 839516623UL, 326568491UL, 1867863527UL, 1550945400UL, 2685835387UL, 420309880UL, 3949479453UL, 586483056UL, 147951307UL, 1639139280UL, 416618471UL, 2789767841UL, 3121654578UL, 634238762UL, 3622035469UL, 1120413065UL, 435990088UL, 1724770389UL, 1403031256UL, 3548817929UL, 240966420UL, 3288769545UL, 2793293893UL, 80675548UL, 3119506726UL, 1785064235UL, 2675485635UL, +1961165681UL, 1647512786UL, 4019542081UL, 2775407492UL, 2853183400UL, 3812341867UL, 278236392UL, 3487875111UL, 2439624528UL, 3846866009UL, 1220806787UL, 3655684157UL, 3303554633UL, 366933679UL, 523552281UL, 703813725UL, 3110126767UL, 2477354049UL, 132468066UL, 821297176UL, 364959993UL, 3381862130UL, 4065162466UL, 1048450041UL, 2558018765UL, 3235968999UL, 1070598970UL, 191819556UL, 1699430013UL, 4275517214UL, 4035198865UL, 3339014315UL, +3588518026UL, 324524850UL, 4211583637UL, 2628162153UL, 3861478870UL, 3361198093UL, 1995585079UL, 3254616321UL, 536776894UL, 3742490940UL, 3912424229UL, 2121458511UL, 1909596092UL, 2308745810UL, 1178166365UL, 1882174246UL, 3067877274UL, 1349347043UL, 3843182157UL, 2200144237UL, 1210030640UL, 1246148630UL, 803098068UL, 3243492274UL, 4271100308UL, 402141998UL, 2932236493UL, 2575673198UL, 372220743UL, 2190417067UL, 1883679642UL, 3945294599UL, +132569424UL, 2278087682UL, 2461678432UL, 708189294UL, 3341915918UL, 3490648253UL, 2412655444UL, 2667664607UL, 2871800434UL, 2307336284UL, 3503294711UL, 2247816079UL, 3253689753UL, 2113837945UL, 1717494311UL, 3121933565UL, 1067816947UL, 1098201917UL, 1041869160UL, 971917867UL, 816420552UL, 738357340UL, 2597170030UL, 2306273930UL, 243915062UL, 397934907UL, 1008175050UL, 2004702919UL, 2345434637UL, 1807067458UL, 156733019UL, 2208729114UL, +276726877UL, 2452083872UL, 1909483753UL, 2470446383UL, 2980162173UL, 1915611444UL, 2043489400UL, 3454651559UL, 3265195583UL, 2640563452UL, 2680619359UL, 2845757473UL, 462852932UL, 142464483UL, 3735508133UL, 3421831326UL, 25103542UL, 1372088341UL, 1898668265UL, 1014707294UL, 1378686477UL, 2680788341UL, 752503486UL, 4085776926UL, 309274614UL, 276596103UL, 3663266970UL, 4193030119UL, 1116423339UL, 4140361758UL, 2634738350UL, 453005903UL, +1725105892UL, 880658361UL, 3775019657UL, 2018542036UL, 2601909713UL, 3496508290UL, 839516623UL, 326568491UL, 1867863527UL, 3474340574UL, 2685835387UL, 420309880UL, 3949479453UL, 586483056UL, 297934218UL, 1639139280UL, 416618471UL, 2789767841UL, 3121654578UL, 958889718UL, 3622035469UL, 1120413065UL, 435990088UL, 1724770389UL, 2589603756UL, 3548817929UL, 240966420UL, 3288769545UL, 2793293893UL, 972899860UL, 3119506726UL, 1785064235UL, +2675485635UL, 1961165681UL, 2576799764UL, 4019542081UL, 2775407492UL, 2853183400UL, 3812341867UL, 159345352UL, 3487875111UL, 2439624528UL, 3846866009UL, 1220806787UL, 3367080935UL, 3303554633UL, 366933679UL, 523552281UL, 703813725UL, 1717395617UL, 2477354049UL, 132468066UL, 821297176UL, 364959993UL, 1088290332UL, 4065162466UL, 1048450041UL, 2558018765UL, 3235968999UL, 285340039UL, 191819556UL, 1699430013UL, 4275517214UL, 4035198865UL, +3544133220UL, 285121978UL, 1175302919UL, 4101282768UL, 513236580UL, 890655666UL, 3051849972UL, 2315486379UL, 3067287276UL, 3134806925UL, 3926373006UL, 2502825498UL, 461387883UL, 770459119UL, 3121636621UL, 1243065093UL, 1612354797UL, 659033930UL, 621176955UL, 214256518UL, 371573588UL, 1168438671UL, 1233027650UL, 1984255965UL, 659404177UL, 1218841419UL, 1226193512UL, 4247589702UL, 334814687UL, 980422670UL, 2518384561UL, 4041002302UL, +1203659320UL, 509643440UL, 2528499450UL, 1512213710UL, 4052651069UL, 1378025938UL, 3436277168UL, 2797728577UL, 463383787UL, 1184681947UL, 283482187UL, 2421891582UL, 3200080903UL, 373817869UL, 452807139UL, 2002545143UL, 1068199574UL, 3390998240UL, 377559317UL, 1548403713UL, 1580741080UL, 253591624UL, 759280679UL, 2174360733UL, 1687952097UL, 1325235423UL, 3856575909UL, 652218568UL, 4130230594UL, 3757998028UL, 1349431618UL, 2870775414UL, +229741978UL, 1900794007UL, 201310771UL, 4075023260UL, 3390078853UL, 3572716207UL, 1959949436UL, 1000128498UL, 1636575064UL, 241058867UL, 2075461870UL, 1819342070UL, 619233032UL, 3164328001UL, 4280892071UL, 4219074185UL, 2719764611UL, 3827656652UL, 4062556527UL, 621515766UL, 2542375627UL, 3901998596UL, 2295087430UL, 2880672054UL, 2940372823UL, 2318642706UL, 914614262UL, 2549699597UL, 2907475284UL, 3901259809UL, 2663167002UL, 3775306719UL, +2212887565UL, 1271873285UL, 3673659531UL, 3856609875UL, 1195785209UL, 1204338358UL, 2785362544UL, 2398696803UL, 3038377816UL, 4288025143UL, 262511310UL, 4151907455UL, 924716723UL, 3298769960UL, 2065938273UL, 3277412030UL, 122636766UL, 2164055077UL, 1000638739UL, 2044933533UL, 2935604716UL, 2772787255UL, 3727331409UL, 1315627932UL, 2610657438UL, 832931652UL, 452359900UL, 681035792UL, 3312648046UL, 1059435047UL, 1489639114UL, 3647631796UL, +417952902UL, 731020350UL, 2847472725UL, 2779076784UL, 2674295324UL, 487600023UL, 2925909449UL, 3997011591UL, 3697231318UL, 967300591UL, 2310856069UL, 684710043UL, 811911286UL, 4174732177UL, 1010656728UL, 702780279UL, 920081774UL, 1578296057UL, 944734808UL, 2884038169UL, 2885919611UL, 2633474915UL, 2508946673UL, 3579216621UL, 656143887UL, 426108406UL, 2166202683UL, 991797657UL, 706498590UL, 561168186UL, 1144619335UL, 3136206425UL, +}, +{ +3600072515UL, 651444872UL, 2348224675UL, 1684848433UL, 1913333701UL, 3413467790UL, 1567802204UL, 2125206188UL, 2463158656UL, 2251055204UL, 4132590383UL, 3192977084UL, 3718261822UL, 3431519430UL, 3506690867UL, 1313208797UL, 637811069UL, 12802085UL, 3456408080UL, 166617386UL, 1764224523UL, 4016338923UL, 2225367442UL, 2461647273UL, 3137989854UL, 373730087UL, 3013524828UL, 242949418UL, 3443491410UL, 3671816408UL, 2391000148UL, 3964107377UL, +716535366UL, 1884597979UL, 3917515811UL, 3441985401UL, 2472173593UL, 4034695117UL, 2486526143UL, 1658764329UL, 1873516415UL, 884116165UL, 814992460UL, 1069506245UL, 3797556389UL, 838088473UL, 2279863068UL, 1002637017UL, 4174541774UL, 644478743UL, 4138151954UL, 4030442072UL, 297710349UL, 3507828614UL, 1403493362UL, 3132267322UL, 227377796UL, 388148240UL, 2760904473UL, 352998924UL, 1603734504UL, 1528807885UL, 2283620218UL, 737730350UL, +2761342715UL, 809367801UL, 1667936422UL, 1510238771UL, 3762862328UL, 1171532060UL, 647580587UL, 1460988169UL, 3944640945UL, 2331043627UL, 1965076564UL, 2913596196UL, 2960957119UL, 1316491503UL, 3086954934UL, 3471945989UL, 2485431762UL, 692294537UL, 3148362914UL, 3371415765UL, 2990795967UL, 706771848UL, 3734467362UL, 2768750385UL, 2061275631UL, 3935582473UL, 1449841372UL, 1239527551UL, 592595530UL, 1685341001UL, 3352323357UL, 4147988039UL, +4003871917UL, 4035869533UL, 3022833195UL, 1266052547UL, 1429645393UL, 565106475UL, 327014810UL, 348739711UL, 3262918351UL, 915509292UL, 397356303UL, 3248246752UL, 1122821778UL, 2373765260UL, 1795464380UL, 3485315196UL, 1731529670UL, 86888382UL, 2789587372UL, 850847993UL, 1794523220UL, 577288126UL, 1996569530UL, 909222664UL, 2601642298UL, 1469035973UL, 2727135938UL, 3467853736UL, 633292505UL, 756260381UL, 41782389UL, 226724724UL, +3633968708UL, 1695315503UL, 1846857904UL, 3185630605UL, 823108172UL, 3609336496UL, 3422558797UL, 2865413534UL, 564221408UL, 591845835UL, 2498463433UL, 3573926554UL, 1336639597UL, 4180084026UL, 3195588503UL, 2822864841UL, 1916459886UL, 2073158796UL, 56968669UL, 1234765864UL, 2456093821UL, 3500058416UL, 3146725645UL, 3295822468UL, 4135196531UL, 628000231UL, 745509757UL, 4143543278UL, 1941480444UL, 3607603517UL, 2288239329UL, 1991437813UL, +4081693775UL, 3600072515UL, 651444872UL, 2348224675UL, 1684848433UL, 3748890341UL, 3413467790UL, 1567802204UL, 2125206188UL, 2463158656UL, 1516568259UL, 4132590383UL, 3192977084UL, 3718261822UL, 3431519430UL, 461466951UL, 1313208797UL, 637811069UL, 12802085UL, 3456408080UL, 3444149988UL, 1764224523UL, 4016338923UL, 2225367442UL, 2461647273UL, 2594402002UL, 373730087UL, 3013524828UL, 242949418UL, 3443491410UL, 2740782133UL, 2391000148UL, +3964107377UL, 716535366UL, 1884597979UL, 3161911677UL, 3441985401UL, 2472173593UL, 4034695117UL, 2486526143UL, 3623045141UL, 1873516415UL, 884116165UL, 814992460UL, 1069506245UL, 1053106195UL, 838088473UL, 2279863068UL, 1002637017UL, 4174541774UL, 1806935386UL, 4138151954UL, 4030442072UL, 297710349UL, 3507828614UL, 2328331779UL, 3132267322UL, 227377796UL, 388148240UL, 2760904473UL, 3654577129UL, 1603734504UL, 1528807885UL, 2283620218UL, +737730350UL, 2134741424UL, 809367801UL, 1667936422UL, 1510238771UL, 3762862328UL, 4084104273UL, 647580587UL, 1460988169UL, 3944640945UL, 2331043627UL, 3458437694UL, 2913596196UL, 2960957119UL, 1316491503UL, 3086954934UL, 2404530503UL, 2485431762UL, 692294537UL, 3148362914UL, 3371415765UL, 3697728317UL, 706771848UL, 3734467362UL, 2768750385UL, 2061275631UL, 1337146928UL, 1449841372UL, 1239527551UL, 592595530UL, 1685341001UL, 3121493408UL, +4147988039UL, 4003871917UL, 4035869533UL, 3022833195UL, 2709537023UL, 1429645393UL, 565106475UL, 327014810UL, 348739711UL, 1278935671UL, 915509292UL, 397356303UL, 3248246752UL, 1122821778UL, 1086107506UL, 1795464380UL, 3485315196UL, 1731529670UL, 86888382UL, 3645735256UL, 850847993UL, 1794523220UL, 577288126UL, 1996569530UL, 1126950UL, 2601642298UL, 1469035973UL, 2727135938UL, 3467853736UL, 3668777652UL, 756260381UL, 41782389UL, +226724724UL, 3633968708UL, 738274780UL, 1846857904UL, 3185630605UL, 823108172UL, 3609336496UL, 3371270228UL, 2865413534UL, 564221408UL, 591845835UL, 2498463433UL, 4157618574UL, 1336639597UL, 4180084026UL, 3195588503UL, 2822864841UL, 3844986377UL, 2073158796UL, 56968669UL, 1234765864UL, 2456093821UL, 1001761927UL, 3146725645UL, 3295822468UL, 4135196531UL, 628000231UL, 541676954UL, 4143543278UL, 1941480444UL, 3607603517UL, 2288239329UL, +1068806322UL, 4081693775UL, 3600072515UL, 651444872UL, 2348224675UL, 47991343UL, 3748890341UL, 3413467790UL, 1567802204UL, 2125206188UL, 2662653600UL, 1516568259UL, 4132590383UL, 3192977084UL, 3718261822UL, 2554440323UL, 461466951UL, 1313208797UL, 637811069UL, 12802085UL, 982676468UL, 3444149988UL, 1764224523UL, 4016338923UL, 2225367442UL, 451503008UL, 2594402002UL, 373730087UL, 3013524828UL, 242949418UL, 1086137206UL, 2740782133UL, +2391000148UL, 3964107377UL, 716535366UL, 731470002UL, 3161911677UL, 3441985401UL, 2472173593UL, 4034695117UL, 44456710UL, 3623045141UL, 1873516415UL, 884116165UL, 814992460UL, 4004771121UL, 1053106195UL, 838088473UL, 2279863068UL, 1002637017UL, 1587145121UL, 1806935386UL, 4138151954UL, 4030442072UL, 297710349UL, 2570695340UL, 2328331779UL, 3132267322UL, 227377796UL, 388148240UL, 3570998746UL, 3654577129UL, 1603734504UL, 1528807885UL, +2283620218UL, 188017185UL, 2134741424UL, 809367801UL, 1667936422UL, 1510238771UL, 1503613101UL, 4084104273UL, 647580587UL, 1460988169UL, 3944640945UL, 3301866374UL, 3458437694UL, 2913596196UL, 2960957119UL, 1316491503UL, 2674694926UL, 2404530503UL, 2485431762UL, 692294537UL, 3148362914UL, 1645995464UL, 3697728317UL, 706771848UL, 3734467362UL, 2768750385UL, 670964862UL, 1337146928UL, 1449841372UL, 1239527551UL, 592595530UL, 4204421245UL, +3121493408UL, 4147988039UL, 4003871917UL, 4035869533UL, 3652555523UL, 2709537023UL, 1429645393UL, 565106475UL, 327014810UL, 2716443687UL, 1278935671UL, 915509292UL, 397356303UL, 3248246752UL, 204830047UL, 1086107506UL, 1795464380UL, 3485315196UL, 1731529670UL, 662578255UL, 3645735256UL, 850847993UL, 1794523220UL, 577288126UL, 4237140216UL, 1126950UL, 2601642298UL, 1469035973UL, 2727135938UL, 92392213UL, 3668777652UL, 756260381UL, +41782389UL, 226724724UL, 1123105466UL, 738274780UL, 1846857904UL, 3185630605UL, 823108172UL, 2880110296UL, 3371270228UL, 2865413534UL, 564221408UL, 591845835UL, 2356214088UL, 4157618574UL, 1336639597UL, 4180084026UL, 3195588503UL, 4266261353UL, 3844986377UL, 2073158796UL, 56968669UL, 1234765864UL, 3166457679UL, 1001761927UL, 3146725645UL, 3295822468UL, 4135196531UL, 496099322UL, 541676954UL, 4143543278UL, 1941480444UL, 3607603517UL, +2578543796UL, 1068806322UL, 4081693775UL, 3600072515UL, 651444872UL, 1131603264UL, 47991343UL, 3748890341UL, 3413467790UL, 1567802204UL, 2823058381UL, 2662653600UL, 1516568259UL, 4132590383UL, 3192977084UL, 4247798474UL, 2554440323UL, 461466951UL, 1313208797UL, 637811069UL, 2744898822UL, 982676468UL, 3444149988UL, 1764224523UL, 4016338923UL, 2845667517UL, 451503008UL, 2594402002UL, 373730087UL, 3013524828UL, 3442521115UL, 1086137206UL, +2740782133UL, 2391000148UL, 3964107377UL, 4060067791UL, 731470002UL, 3161911677UL, 3441985401UL, 2472173593UL, 4227407417UL, 44456710UL, 3623045141UL, 1873516415UL, 884116165UL, 2550700713UL, 4004771121UL, 1053106195UL, 838088473UL, 2279863068UL, 1296332348UL, 1587145121UL, 1806935386UL, 4138151954UL, 4030442072UL, 2552496880UL, 2570695340UL, 2328331779UL, 3132267322UL, 227377796UL, 3887816270UL, 3570998746UL, 3654577129UL, 1603734504UL, +1528807885UL, 3365552060UL, 188017185UL, 2134741424UL, 809367801UL, 1667936422UL, 1358744245UL, 1503613101UL, 4084104273UL, 647580587UL, 1460988169UL, 2318828416UL, 3301866374UL, 3458437694UL, 2913596196UL, 2960957119UL, 49464436UL, 2674694926UL, 2404530503UL, 2485431762UL, 692294537UL, 1803418945UL, 1645995464UL, 3697728317UL, 706771848UL, 3734467362UL, 2407932841UL, 670964862UL, 1337146928UL, 1449841372UL, 1239527551UL, 1124552917UL, +4204421245UL, 3121493408UL, 4147988039UL, 4003871917UL, 3542256025UL, 3652555523UL, 2709537023UL, 1429645393UL, 565106475UL, 2063548817UL, 2716443687UL, 1278935671UL, 915509292UL, 397356303UL, 1049916999UL, 204830047UL, 1086107506UL, 1795464380UL, 3485315196UL, 2183256184UL, 662578255UL, 3645735256UL, 850847993UL, 1794523220UL, 2943700388UL, 4237140216UL, 1126950UL, 2601642298UL, 1469035973UL, 535075238UL, 92392213UL, 3668777652UL, +756260381UL, 41782389UL, 1043025574UL, 1123105466UL, 738274780UL, 1846857904UL, 3185630605UL, 3324487649UL, 2880110296UL, 3371270228UL, 2865413534UL, 564221408UL, 2528599862UL, 2356214088UL, 4157618574UL, 1336639597UL, 4180084026UL, 592094844UL, 4266261353UL, 3844986377UL, 2073158796UL, 56968669UL, 629503707UL, 3166457679UL, 1001761927UL, 3146725645UL, 3295822468UL, 2725304934UL, 496099322UL, 541676954UL, 4143543278UL, 1941480444UL, +3557859116UL, 31832949UL, 3805791401UL, 4056283801UL, 242812250UL, 4072988068UL, 2316479446UL, 2260433816UL, 2211372380UL, 2039672698UL, 2947948280UL, 4106140026UL, 342600216UL, 98745656UL, 2541799209UL, 926067404UL, 2733213159UL, 3163537903UL, 2800370126UL, 2099121446UL, 1279545581UL, 3699822446UL, 3764095615UL, 690503808UL, 3799637505UL, 1000641330UL, 242588257UL, 3657834529UL, 824791208UL, 2529299371UL, 4081898575UL, 2120338882UL, +1273883107UL, 1680877886UL, 1253060582UL, 1760259553UL, 2250763915UL, 31780198UL, 2511451445UL, 3102141340UL, 861489797UL, 105854693UL, 70927387UL, 2725671050UL, 688282241UL, 2622257646UL, 3466254816UL, 1905008219UL, 2980966436UL, 2154356718UL, 1075686806UL, 1966147415UL, 2357249256UL, 2684600972UL, 400926709UL, 523449509UL, 2891602783UL, 673425710UL, 3766475216UL, 2319843954UL, 3471794777UL, 13838840UL, 1908374660UL, 3839606132UL, +3829795513UL, 3403561639UL, 1369780874UL, 4276407916UL, 3217619UL, 1284482371UL, 2020138237UL, 2804427294UL, 1194369854UL, 1094800747UL, 2119081501UL, 726494474UL, 490750173UL, 1117517565UL, 3498786968UL, 2163060528UL, 696718831UL, 2780121254UL, 1286646297UL, 1594539045UL, 411215116UL, 1407268753UL, 2759136967UL, 2179483407UL, 2088977769UL, 2737453188UL, 2411478102UL, 3112688013UL, 4112484868UL, 429293789UL, 426390687UL, 3158027863UL, +2601897382UL, 1546855515UL, 4258208908UL, 3691263847UL, 2394986813UL, 1986623921UL, 2632462203UL, 3551311099UL, 3309482741UL, 2632571927UL, 1200010240UL, 554555739UL, 4119397989UL, 622818813UL, 3116222066UL, 1801867255UL, 2738500841UL, 1452697246UL, 733457482UL, 1680421668UL, 1035766144UL, 468847991UL, 3606474156UL, 2612692123UL, 730556693UL, 859096521UL, 4005878655UL, 1138273887UL, 2182363629UL, 2710579590UL, 3345140092UL, 2562710857UL, +3859276724UL, 2318176233UL, 3964665794UL, 3295219265UL, 3037789445UL, 371545704UL, 3434130670UL, 3686032092UL, 19964088UL, 340386179UL, 2147090894UL, 1446742483UL, 3083526520UL, 561888846UL, 2903328518UL, 1524465288UL, 360120037UL, 2031515996UL, 1516035872UL, 2752848969UL, 1094251072UL, 984159948UL, 369999653UL, 864602622UL, 2402584241UL, 3028363830UL, 252580667UL, 480470405UL, 3201548259UL, 2739036185UL, 2198549891UL, 1978812013UL, +}, +{ +2546657140UL, 2771792972UL, 3371698159UL, 1137313111UL, 2399264952UL, 1204642544UL, 2090179262UL, 2948712987UL, 2908027331UL, 498636511UL, 2292804841UL, 1480836858UL, 2826016727UL, 196495965UL, 2168559184UL, 3910150715UL, 320076735UL, 3144753899UL, 3199094529UL, 1165806050UL, 728308199UL, 2322528104UL, 2891334400UL, 561853019UL, 4161870615UL, 1348321971UL, 2461357166UL, 1216229488UL, 1392766290UL, 3060494848UL, 3282469664UL, 1866493654UL, +2351421557UL, 4195620347UL, 1512242723UL, 478174598UL, 1087303780UL, 471631659UL, 2599553643UL, 791527994UL, 563537164UL, 1238109907UL, 3218421602UL, 133222502UL, 4182363220UL, 305688802UL, 2666439314UL, 2408520958UL, 787389550UL, 4226450542UL, 4107143646UL, 4103547035UL, 1840887424UL, 2686247491UL, 334267386UL, 3772035402UL, 3436827662UL, 1411515743UL, 2193739735UL, 1892746640UL, 4163192062UL, 2921191805UL, 1011310614UL, 2178118214UL, +33647321UL, 1121452997UL, 507942677UL, 2542792587UL, 351339975UL, 1586639416UL, 1918003826UL, 2513357034UL, 2747854573UL, 606238275UL, 1132105249UL, 574593993UL, 2655425816UL, 1680556547UL, 1831942411UL, 2587194016UL, 90710116UL, 4291431098UL, 1899367028UL, 3251152898UL, 3297078396UL, 2712235924UL, 1546135008UL, 897753268UL, 1619454780UL, 938130143UL, 1828916640UL, 3620488958UL, 1822437033UL, 172584228UL, 1853048226UL, 3659288522UL, +3623450763UL, 1893292786UL, 851522142UL, 3411705687UL, 4106341088UL, 4109830348UL, 1193339049UL, 878885723UL, 2964062476UL, 2320209608UL, 1777678953UL, 2886897705UL, 3856938396UL, 252913914UL, 3648685154UL, 544382669UL, 2631141468UL, 1524405364UL, 1848509666UL, 580646927UL, 2451560151UL, 181916967UL, 1426301928UL, 1652422182UL, 2625099169UL, 176664750UL, 1582626255UL, 1675120608UL, 2571617898UL, 2096572277UL, 2471745846UL, 419906507UL, +886861124UL, 1974832558UL, 3157060904UL, 216000225UL, 746978071UL, 1424984058UL, 1457979883UL, 809822177UL, 3833178010UL, 3926414726UL, 1423462846UL, 3024443248UL, 4067020014UL, 2881559869UL, 1376840097UL, 548130303UL, 1118013762UL, 1309103114UL, 2227304261UL, 4205319357UL, 228947246UL, 2167410411UL, 620496852UL, 2724112116UL, 705259153UL, 3499686911UL, 3085999115UL, 2447267299UL, 4190122199UL, 1091465954UL, 1233728238UL, 39711865UL, +1076751044UL, 2546657140UL, 2771792972UL, 3371698159UL, 1137313111UL, 3857150586UL, 1204642544UL, 2090179262UL, 2948712987UL, 2908027331UL, 368199414UL, 2292804841UL, 1480836858UL, 2826016727UL, 196495965UL, 3235583934UL, 3910150715UL, 320076735UL, 3144753899UL, 3199094529UL, 1374597050UL, 728308199UL, 2322528104UL, 2891334400UL, 561853019UL, 1515915224UL, 1348321971UL, 2461357166UL, 1216229488UL, 1392766290UL, 15252704UL, 3282469664UL, +1866493654UL, 2351421557UL, 4195620347UL, 192355609UL, 478174598UL, 1087303780UL, 471631659UL, 2599553643UL, 1725604263UL, 563537164UL, 1238109907UL, 3218421602UL, 133222502UL, 305098282UL, 305688802UL, 2666439314UL, 2408520958UL, 787389550UL, 3195522899UL, 4107143646UL, 4103547035UL, 1840887424UL, 2686247491UL, 1565529892UL, 3772035402UL, 3436827662UL, 1411515743UL, 2193739735UL, 1848198417UL, 4163192062UL, 2921191805UL, 1011310614UL, +2178118214UL, 3474206203UL, 1121452997UL, 507942677UL, 2542792587UL, 351339975UL, 3599278861UL, 1918003826UL, 2513357034UL, 2747854573UL, 606238275UL, 446979745UL, 574593993UL, 2655425816UL, 1680556547UL, 1831942411UL, 3338512802UL, 90710116UL, 4291431098UL, 1899367028UL, 3251152898UL, 1006512939UL, 2712235924UL, 1546135008UL, 897753268UL, 1619454780UL, 1429190743UL, 1828916640UL, 3620488958UL, 1822437033UL, 172584228UL, 2529855020UL, +3659288522UL, 3623450763UL, 1893292786UL, 851522142UL, 1417935793UL, 4106341088UL, 4109830348UL, 1193339049UL, 878885723UL, 1886400637UL, 2320209608UL, 1777678953UL, 2886897705UL, 3856938396UL, 1813134786UL, 3648685154UL, 544382669UL, 2631141468UL, 1524405364UL, 687661410UL, 580646927UL, 2451560151UL, 181916967UL, 1426301928UL, 1463347373UL, 2625099169UL, 176664750UL, 1582626255UL, 1675120608UL, 3387060344UL, 2096572277UL, 2471745846UL, +419906507UL, 886861124UL, 4209699955UL, 3157060904UL, 216000225UL, 746978071UL, 1424984058UL, 3063941448UL, 809822177UL, 3833178010UL, 3926414726UL, 1423462846UL, 750559587UL, 4067020014UL, 2881559869UL, 1376840097UL, 548130303UL, 4056763004UL, 1309103114UL, 2227304261UL, 4205319357UL, 228947246UL, 774411056UL, 620496852UL, 2724112116UL, 705259153UL, 3499686911UL, 2486247387UL, 2447267299UL, 4190122199UL, 1091465954UL, 1233728238UL, +54639263UL, 1076751044UL, 2546657140UL, 2771792972UL, 3371698159UL, 1152150303UL, 3857150586UL, 1204642544UL, 2090179262UL, 2948712987UL, 452427847UL, 368199414UL, 2292804841UL, 1480836858UL, 2826016727UL, 1929008184UL, 3235583934UL, 3910150715UL, 320076735UL, 3144753899UL, 895636897UL, 1374597050UL, 728308199UL, 2322528104UL, 2891334400UL, 1871824871UL, 1515915224UL, 1348321971UL, 2461357166UL, 1216229488UL, 3170568098UL, 15252704UL, +3282469664UL, 1866493654UL, 2351421557UL, 4253216490UL, 192355609UL, 478174598UL, 1087303780UL, 471631659UL, 4230260400UL, 1725604263UL, 563537164UL, 1238109907UL, 3218421602UL, 960481514UL, 305098282UL, 305688802UL, 2666439314UL, 2408520958UL, 242741163UL, 3195522899UL, 4107143646UL, 4103547035UL, 1840887424UL, 2768321503UL, 1565529892UL, 3772035402UL, 3436827662UL, 1411515743UL, 545362965UL, 1848198417UL, 4163192062UL, 2921191805UL, +1011310614UL, 1196775493UL, 3474206203UL, 1121452997UL, 507942677UL, 2542792587UL, 1948892535UL, 3599278861UL, 1918003826UL, 2513357034UL, 2747854573UL, 4172793632UL, 446979745UL, 574593993UL, 2655425816UL, 1680556547UL, 2986869736UL, 3338512802UL, 90710116UL, 4291431098UL, 1899367028UL, 3376952160UL, 1006512939UL, 2712235924UL, 1546135008UL, 897753268UL, 2061577225UL, 1429190743UL, 1828916640UL, 3620488958UL, 1822437033UL, 4221327184UL, +2529855020UL, 3659288522UL, 3623450763UL, 1893292786UL, 16446898UL, 1417935793UL, 4106341088UL, 4109830348UL, 1193339049UL, 2895194326UL, 1886400637UL, 2320209608UL, 1777678953UL, 2886897705UL, 117861450UL, 1813134786UL, 3648685154UL, 544382669UL, 2631141468UL, 1105253905UL, 687661410UL, 580646927UL, 2451560151UL, 181916967UL, 1605087684UL, 1463347373UL, 2625099169UL, 176664750UL, 1582626255UL, 1993431057UL, 3387060344UL, 2096572277UL, +2471745846UL, 419906507UL, 3219719670UL, 4209699955UL, 3157060904UL, 216000225UL, 746978071UL, 3304126047UL, 3063941448UL, 809822177UL, 3833178010UL, 3926414726UL, 4061584738UL, 750559587UL, 4067020014UL, 2881559869UL, 1376840097UL, 973425409UL, 4056763004UL, 1309103114UL, 2227304261UL, 4205319357UL, 939664759UL, 774411056UL, 620496852UL, 2724112116UL, 705259153UL, 176172666UL, 2486247387UL, 2447267299UL, 4190122199UL, 1091465954UL, +300145620UL, 54639263UL, 1076751044UL, 2546657140UL, 2771792972UL, 188149161UL, 1152150303UL, 3857150586UL, 1204642544UL, 2090179262UL, 626100323UL, 452427847UL, 368199414UL, 2292804841UL, 1480836858UL, 2700509669UL, 1929008184UL, 3235583934UL, 3910150715UL, 320076735UL, 1715326239UL, 895636897UL, 1374597050UL, 728308199UL, 2322528104UL, 2356051490UL, 1871824871UL, 1515915224UL, 1348321971UL, 2461357166UL, 243332180UL, 3170568098UL, +15252704UL, 3282469664UL, 1866493654UL, 4079212881UL, 4253216490UL, 192355609UL, 478174598UL, 1087303780UL, 3787911270UL, 4230260400UL, 1725604263UL, 563537164UL, 1238109907UL, 1147223471UL, 960481514UL, 305098282UL, 305688802UL, 2666439314UL, 1503870433UL, 242741163UL, 3195522899UL, 4107143646UL, 4103547035UL, 4041516761UL, 2768321503UL, 1565529892UL, 3772035402UL, 3436827662UL, 3952861918UL, 545362965UL, 1848198417UL, 4163192062UL, +2921191805UL, 793561655UL, 1196775493UL, 3474206203UL, 1121452997UL, 507942677UL, 3788690254UL, 1948892535UL, 3599278861UL, 1918003826UL, 2513357034UL, 3301940062UL, 4172793632UL, 446979745UL, 574593993UL, 2655425816UL, 667233719UL, 2986869736UL, 3338512802UL, 90710116UL, 4291431098UL, 2027122085UL, 3376952160UL, 1006512939UL, 2712235924UL, 1546135008UL, 2609276017UL, 2061577225UL, 1429190743UL, 1828916640UL, 3620488958UL, 1603195641UL, +4221327184UL, 2529855020UL, 3659288522UL, 3623450763UL, 2313432963UL, 16446898UL, 1417935793UL, 4106341088UL, 4109830348UL, 4106013120UL, 2895194326UL, 1886400637UL, 2320209608UL, 1777678953UL, 1952597964UL, 117861450UL, 1813134786UL, 3648685154UL, 544382669UL, 3108229631UL, 1105253905UL, 687661410UL, 580646927UL, 2451560151UL, 1160575897UL, 1605087684UL, 1463347373UL, 2625099169UL, 176664750UL, 1998534134UL, 1993431057UL, 3387060344UL, +2096572277UL, 2471745846UL, 2246406696UL, 3219719670UL, 4209699955UL, 3157060904UL, 216000225UL, 902956869UL, 3304126047UL, 3063941448UL, 809822177UL, 3833178010UL, 815366736UL, 4061584738UL, 750559587UL, 4067020014UL, 2881559869UL, 350775477UL, 973425409UL, 4056763004UL, 1309103114UL, 2227304261UL, 2047915817UL, 939664759UL, 774411056UL, 620496852UL, 2724112116UL, 3593903529UL, 176172666UL, 2486247387UL, 2447267299UL, 4190122199UL, +1450746791UL, 1521739409UL, 272699299UL, 4113952664UL, 1408743622UL, 4082014187UL, 2454446462UL, 1401621236UL, 2050232096UL, 4204834821UL, 2413497685UL, 1032465253UL, 4276089655UL, 1737267711UL, 3335718398UL, 1924071395UL, 1560525661UL, 3064183869UL, 1775038231UL, 89761304UL, 489201378UL, 1236489133UL, 2774076159UL, 822652970UL, 1583752702UL, 1781766972UL, 2238480533UL, 3428349870UL, 3344555477UL, 2251934941UL, 2533404243UL, 3651295253UL, +2359372862UL, 704049384UL, 3238382362UL, 2405156187UL, 2572833624UL, 531907732UL, 2240111412UL, 4102445586UL, 849739856UL, 3649572083UL, 3317634415UL, 1141345331UL, 1118528358UL, 1664181643UL, 648360156UL, 1364897187UL, 289264571UL, 1625825195UL, 1075970578UL, 3925373833UL, 2780782646UL, 727038162UL, 2824687935UL, 3844230994UL, 2070739238UL, 2437298873UL, 1837327520UL, 4248571219UL, 183041221UL, 3759390508UL, 3881974011UL, 658115161UL, +560642175UL, 32860408UL, 1321227669UL, 1380454450UL, 1676524786UL, 476585241UL, 4034481274UL, 1110506516UL, 815601591UL, 2009522227UL, 2168306897UL, 1856639149UL, 1328281664UL, 2710915389UL, 1886116025UL, 2074502324UL, 23109943UL, 670045122UL, 2926671795UL, 4269143768UL, 2688621201UL, 1618605914UL, 1541217762UL, 4273045819UL, 1029546542UL, 3663663567UL, 1402692384UL, 109336276UL, 2446546057UL, 2225682064UL, 3535545430UL, 3847123891UL, +369718877UL, 3411726117UL, 703735748UL, 3139527634UL, 22388546UL, 998860697UL, 2532911305UL, 1532808237UL, 4170332196UL, 1131906845UL, 1814343609UL, 4161931326UL, 1185668213UL, 1903273604UL, 3466154373UL, 3988139604UL, 1079368270UL, 991305574UL, 898158502UL, 2898908951UL, 651161128UL, 1952607949UL, 1221528540UL, 29979722UL, 3006846808UL, 2911550178UL, 2569412437UL, 1460616937UL, 2127921978UL, 3689931108UL, 950505297UL, 3469337654UL, +3180457017UL, 2316433735UL, 1464678429UL, 2867173456UL, 391248106UL, 3622065314UL, 2143251073UL, 860219584UL, 323835636UL, 340886643UL, 1805485977UL, 109344001UL, 1537119779UL, 1795626099UL, 2568079633UL, 3048040562UL, 1204069532UL, 2488753091UL, 2160014198UL, 3132782711UL, 1266102795UL, 91252225UL, 2018366053UL, 39675212UL, 979320891UL, 343397131UL, 814470367UL, 366655857UL, 3287033048UL, 3379301026UL, 1566381433UL, 3431153818UL, +}, +{ +2234324389UL, 1682296894UL, 3526681456UL, 3988544681UL, 1315506584UL, 1754723911UL, 3607564438UL, 3764062195UL, 3408328234UL, 2385116969UL, 3827569659UL, 4104590721UL, 2612634189UL, 1762747544UL, 1676800931UL, 1814546108UL, 2684685172UL, 1659194343UL, 3381624140UL, 2286640580UL, 688245437UL, 2593335056UL, 1657668516UL, 1161309746UL, 3390664973UL, 2460564382UL, 2811435329UL, 2169200311UL, 2768093584UL, 4288309691UL, 1341061221UL, 1361417084UL, +3060155336UL, 2526021346UL, 1037055386UL, 890124736UL, 2185462193UL, 765141735UL, 1841745804UL, 3562499272UL, 1437907207UL, 2127475991UL, 2845453063UL, 4007976206UL, 4160093314UL, 2717704308UL, 4193767498UL, 1667876711UL, 3477753188UL, 3150367681UL, 3224086539UL, 231347764UL, 2737121599UL, 1230656103UL, 4168131490UL, 1463860373UL, 2760968409UL, 2579133178UL, 2309591728UL, 2958907244UL, 1041094855UL, 685134804UL, 3861095208UL, 1088109135UL, +815655228UL, 2618003265UL, 3454840568UL, 1668276240UL, 1668403077UL, 663034899UL, 4020374281UL, 1896863688UL, 677285319UL, 4047674693UL, 4098535894UL, 2038783953UL, 236635760UL, 3641273565UL, 3568356824UL, 3405704765UL, 186484522UL, 3626346451UL, 3653227559UL, 281949942UL, 1847600066UL, 4168753288UL, 1723123703UL, 3600798445UL, 4267802363UL, 2947454105UL, 468768748UL, 2745777741UL, 26635454UL, 837186232UL, 206931043UL, 2601865569UL, +2021732453UL, 3171165636UL, 786833002UL, 116631308UL, 1604778670UL, 437644814UL, 2437761489UL, 3573139998UL, 2637030522UL, 972076738UL, 4075927397UL, 1427554739UL, 597414077UL, 559325169UL, 1774857312UL, 224593737UL, 3697511293UL, 3905126277UL, 2446278950UL, 1847061846UL, 333176687UL, 2988562696UL, 3623938567UL, 2389910304UL, 4273100167UL, 1673622334UL, 2163644598UL, 3666601063UL, 3971760462UL, 4176957983UL, 565952761UL, 566996714UL, +103136762UL, 3648349163UL, 115456167UL, 3265051494UL, 2826313040UL, 1898888678UL, 3921049266UL, 1276809956UL, 4051866478UL, 959265349UL, 851980436UL, 3105565302UL, 2905096898UL, 342438530UL, 3428101638UL, 912389587UL, 2306839396UL, 3613297213UL, 200159550UL, 3406974927UL, 832121231UL, 2998593393UL, 1242069873UL, 1464281204UL, 1828082526UL, 2620095350UL, 3727900009UL, 986958825UL, 3332332947UL, 1610600284UL, 3193282615UL, 1873987353UL, +537698841UL, 2234324389UL, 1682296894UL, 3526681456UL, 3988544681UL, 1112334635UL, 1754723911UL, 3607564438UL, 3764062195UL, 3408328234UL, 2702680798UL, 3827569659UL, 4104590721UL, 2612634189UL, 1762747544UL, 1596420149UL, 1814546108UL, 2684685172UL, 1659194343UL, 3381624140UL, 2424233156UL, 688245437UL, 2593335056UL, 1657668516UL, 1161309746UL, 260803614UL, 2460564382UL, 2811435329UL, 2169200311UL, 2768093584UL, 1426048416UL, 1341061221UL, +1361417084UL, 3060155336UL, 2526021346UL, 688976997UL, 890124736UL, 2185462193UL, 765141735UL, 1841745804UL, 1113361455UL, 1437907207UL, 2127475991UL, 2845453063UL, 4007976206UL, 1719248425UL, 2717704308UL, 4193767498UL, 1667876711UL, 3477753188UL, 449353539UL, 3224086539UL, 231347764UL, 2737121599UL, 1230656103UL, 2122699205UL, 1463860373UL, 2760968409UL, 2579133178UL, 2309591728UL, 4017154219UL, 1041094855UL, 685134804UL, 3861095208UL, +1088109135UL, 3954527144UL, 2618003265UL, 3454840568UL, 1668276240UL, 1668403077UL, 3235241899UL, 4020374281UL, 1896863688UL, 677285319UL, 4047674693UL, 4043186819UL, 2038783953UL, 236635760UL, 3641273565UL, 3568356824UL, 3946220303UL, 186484522UL, 3626346451UL, 3653227559UL, 281949942UL, 1896524045UL, 4168753288UL, 1723123703UL, 3600798445UL, 4267802363UL, 412498526UL, 468768748UL, 2745777741UL, 26635454UL, 837186232UL, 1473941762UL, +2601865569UL, 2021732453UL, 3171165636UL, 786833002UL, 3461566768UL, 1604778670UL, 437644814UL, 2437761489UL, 3573139998UL, 306196591UL, 972076738UL, 4075927397UL, 1427554739UL, 597414077UL, 2401305323UL, 1774857312UL, 224593737UL, 3697511293UL, 3905126277UL, 1527832817UL, 1847061846UL, 333176687UL, 2988562696UL, 3623938567UL, 2731158470UL, 4273100167UL, 1673622334UL, 2163644598UL, 3666601063UL, 1991088422UL, 4176957983UL, 565952761UL, +566996714UL, 103136762UL, 1639884175UL, 115456167UL, 3265051494UL, 2826313040UL, 1898888678UL, 2976556877UL, 1276809956UL, 4051866478UL, 959265349UL, 851980436UL, 2482970929UL, 2905096898UL, 342438530UL, 3428101638UL, 912389587UL, 2716490551UL, 3613297213UL, 200159550UL, 3406974927UL, 832121231UL, 2865829307UL, 1242069873UL, 1464281204UL, 1828082526UL, 2620095350UL, 3671861666UL, 986958825UL, 3332332947UL, 1610600284UL, 3193282615UL, +164496953UL, 537698841UL, 2234324389UL, 1682296894UL, 3526681456UL, 486931321UL, 1112334635UL, 1754723911UL, 3607564438UL, 3764062195UL, 898439171UL, 2702680798UL, 3827569659UL, 4104590721UL, 2612634189UL, 1703436382UL, 1596420149UL, 1814546108UL, 2684685172UL, 1659194343UL, 3421607784UL, 2424233156UL, 688245437UL, 2593335056UL, 1657668516UL, 362342820UL, 260803614UL, 2460564382UL, 2811435329UL, 2169200311UL, 4248717010UL, 1426048416UL, +1341061221UL, 1361417084UL, 3060155336UL, 2693026827UL, 688976997UL, 890124736UL, 2185462193UL, 765141735UL, 2445632748UL, 1113361455UL, 1437907207UL, 2127475991UL, 2845453063UL, 1830953748UL, 1719248425UL, 2717704308UL, 4193767498UL, 1667876711UL, 2469362144UL, 449353539UL, 3224086539UL, 231347764UL, 2737121599UL, 2917779591UL, 2122699205UL, 1463860373UL, 2760968409UL, 2579133178UL, 2600345316UL, 4017154219UL, 1041094855UL, 685134804UL, +3861095208UL, 3682591427UL, 3954527144UL, 2618003265UL, 3454840568UL, 1668276240UL, 988400088UL, 3235241899UL, 4020374281UL, 1896863688UL, 677285319UL, 2749516227UL, 4043186819UL, 2038783953UL, 236635760UL, 3641273565UL, 4073317913UL, 3946220303UL, 186484522UL, 3626346451UL, 3653227559UL, 872336642UL, 1896524045UL, 4168753288UL, 1723123703UL, 3600798445UL, 524095357UL, 412498526UL, 468768748UL, 2745777741UL, 26635454UL, 840544541UL, +1473941762UL, 2601865569UL, 2021732453UL, 3171165636UL, 1058640324UL, 3461566768UL, 1604778670UL, 437644814UL, 2437761489UL, 3615438045UL, 306196591UL, 972076738UL, 4075927397UL, 1427554739UL, 2369367008UL, 2401305323UL, 1774857312UL, 224593737UL, 3697511293UL, 4186564433UL, 1527832817UL, 1847061846UL, 333176687UL, 2988562696UL, 4039340326UL, 2731158470UL, 4273100167UL, 1673622334UL, 2163644598UL, 307949376UL, 1991088422UL, 4176957983UL, +565952761UL, 566996714UL, 4159448552UL, 1639884175UL, 115456167UL, 3265051494UL, 2826313040UL, 2698725478UL, 2976556877UL, 1276809956UL, 4051866478UL, 959265349UL, 293029699UL, 2482970929UL, 2905096898UL, 342438530UL, 3428101638UL, 4172766741UL, 2716490551UL, 3613297213UL, 200159550UL, 3406974927UL, 3723281866UL, 2865829307UL, 1242069873UL, 1464281204UL, 1828082526UL, 3304191156UL, 3671861666UL, 986958825UL, 3332332947UL, 1610600284UL, +2370407607UL, 164496953UL, 537698841UL, 2234324389UL, 1682296894UL, 826891606UL, 486931321UL, 1112334635UL, 1754723911UL, 3607564438UL, 3598993552UL, 898439171UL, 2702680798UL, 3827569659UL, 4104590721UL, 1421852097UL, 1703436382UL, 1596420149UL, 1814546108UL, 2684685172UL, 4090587429UL, 3421607784UL, 2424233156UL, 688245437UL, 2593335056UL, 4151905751UL, 362342820UL, 260803614UL, 2460564382UL, 2811435329UL, 2402832015UL, 4248717010UL, +1426048416UL, 1341061221UL, 1361417084UL, 1629089021UL, 2693026827UL, 688976997UL, 890124736UL, 2185462193UL, 303105066UL, 2445632748UL, 1113361455UL, 1437907207UL, 2127475991UL, 62024604UL, 1830953748UL, 1719248425UL, 2717704308UL, 4193767498UL, 667433630UL, 2469362144UL, 449353539UL, 3224086539UL, 231347764UL, 3918249451UL, 2917779591UL, 2122699205UL, 1463860373UL, 2760968409UL, 4274016442UL, 2600345316UL, 4017154219UL, 1041094855UL, +685134804UL, 643006688UL, 3682591427UL, 3954527144UL, 2618003265UL, 3454840568UL, 4180665518UL, 988400088UL, 3235241899UL, 4020374281UL, 1896863688UL, 3678687414UL, 2749516227UL, 4043186819UL, 2038783953UL, 236635760UL, 2880089648UL, 4073317913UL, 3946220303UL, 186484522UL, 3626346451UL, 2454620114UL, 872336642UL, 1896524045UL, 4168753288UL, 1723123703UL, 2692406059UL, 524095357UL, 412498526UL, 468768748UL, 2745777741UL, 918726515UL, +840544541UL, 1473941762UL, 2601865569UL, 2021732453UL, 3534238020UL, 1058640324UL, 3461566768UL, 1604778670UL, 437644814UL, 2894699005UL, 3615438045UL, 306196591UL, 972076738UL, 4075927397UL, 3468671461UL, 2369367008UL, 2401305323UL, 1774857312UL, 224593737UL, 2734827022UL, 4186564433UL, 1527832817UL, 1847061846UL, 333176687UL, 2437714719UL, 4039340326UL, 2731158470UL, 4273100167UL, 1673622334UL, 196072958UL, 307949376UL, 1991088422UL, +4176957983UL, 565952761UL, 847200194UL, 4159448552UL, 1639884175UL, 115456167UL, 3265051494UL, 2503079777UL, 2698725478UL, 2976556877UL, 1276809956UL, 4051866478UL, 2731665893UL, 293029699UL, 2482970929UL, 2905096898UL, 342438530UL, 581060953UL, 4172766741UL, 2716490551UL, 3613297213UL, 200159550UL, 4222335623UL, 3723281866UL, 2865829307UL, 1242069873UL, 1464281204UL, 1080647953UL, 3304191156UL, 3671861666UL, 986958825UL, 3332332947UL, +920422540UL, 3656094274UL, 4036161427UL, 2157099981UL, 1855437762UL, 1385781426UL, 199192882UL, 489599802UL, 3472601685UL, 717544078UL, 2241742884UL, 3951326913UL, 3590866192UL, 1087524220UL, 3517385549UL, 360484251UL, 2718513148UL, 1386577185UL, 1833613127UL, 2926418589UL, 1652463225UL, 548895720UL, 1343026759UL, 1797789098UL, 3229783023UL, 1745843414UL, 200554865UL, 2442780740UL, 2359926428UL, 2970332116UL, 3097392757UL, 134294482UL, +936225458UL, 1968264650UL, 64868134UL, 3821668262UL, 2502175363UL, 1623767635UL, 2936073062UL, 1991791011UL, 2971174068UL, 3142195911UL, 2874818345UL, 2192526584UL, 496586185UL, 2491564144UL, 2415210641UL, 314307270UL, 2936737494UL, 557604388UL, 1067914024UL, 3270690738UL, 375601880UL, 962749065UL, 3610467620UL, 402112984UL, 1432929499UL, 3872957776UL, 3971384069UL, 2223968592UL, 407083609UL, 2178236674UL, 1806303230UL, 3397564470UL, +12158764UL, 415570813UL, 4033667395UL, 3687406137UL, 801878150UL, 953500350UL, 3667783172UL, 1203668106UL, 902418194UL, 779786150UL, 774683730UL, 2870261992UL, 509192460UL, 1961621392UL, 1064906432UL, 3665710891UL, 1733725153UL, 1887608856UL, 1314631523UL, 4097239005UL, 29074501UL, 3472521950UL, 4040841657UL, 532128023UL, 2333441401UL, 1671717886UL, 1678544416UL, 1218347584UL, 3680929567UL, 4025753853UL, 2810948711UL, 1846100306UL, +3377469279UL, 3144481747UL, 2625781306UL, 730632118UL, 3162408393UL, 3423660386UL, 1364968369UL, 4270900402UL, 1075484840UL, 2892932277UL, 3700635052UL, 3853022563UL, 281755151UL, 1530909868UL, 2364069707UL, 2361723426UL, 738500028UL, 1401903990UL, 1543704261UL, 2442916222UL, 1076190609UL, 1882477803UL, 740024557UL, 1591015439UL, 2730909167UL, 2723330839UL, 1637373491UL, 3777799860UL, 2921269571UL, 3698591972UL, 3997463570UL, 3877862147UL, +1912888417UL, 3365137165UL, 3465700492UL, 771243134UL, 4037723169UL, 1715894739UL, 1025821874UL, 1924958945UL, 3382242859UL, 121591031UL, 483980724UL, 546523388UL, 2446882279UL, 856267778UL, 578739009UL, 2978085488UL, 480884914UL, 966764808UL, 457039953UL, 3817520708UL, 1113646451UL, 2503896910UL, 3507840816UL, 717151671UL, 4149352573UL, 1568869830UL, 395015863UL, 773165995UL, 1853682362UL, 2861368846UL, 1884368812UL, 1250092101UL, +}, +{ +916910638UL, 961623451UL, 1193013401UL, 1016438484UL, 4091279871UL, 287282633UL, 8590725UL, 3575333670UL, 324340905UL, 3133751747UL, 2840894649UL, 2980503178UL, 1111215768UL, 2783846375UL, 72516413UL, 4158424384UL, 2184094569UL, 2305724254UL, 4057093054UL, 1407652993UL, 3105191537UL, 768505376UL, 298782270UL, 993926164UL, 2694730042UL, 1479658113UL, 2376490281UL, 2767906402UL, 1619969256UL, 3256472015UL, 2563843533UL, 2974784738UL, +2529307107UL, 4289918826UL, 3105587575UL, 3748950898UL, 2182744253UL, 431888679UL, 3780324902UL, 2525978209UL, 54545903UL, 1688749940UL, 2394884334UL, 3477656171UL, 263834270UL, 1562965459UL, 804704330UL, 4185729868UL, 138898835UL, 2113063150UL, 327612841UL, 1252226275UL, 935318076UL, 2956823075UL, 4095101181UL, 1510586062UL, 156282440UL, 3386839706UL, 2294393752UL, 1306167091UL, 4005033667UL, 651716500UL, 4115192738UL, 123027719UL, +3873547487UL, 2910637335UL, 2571924586UL, 3489608656UL, 956791985UL, 2467423726UL, 3214531645UL, 2054232851UL, 49634692UL, 377192215UL, 1865068750UL, 2479252980UL, 3481787748UL, 3243507737UL, 605491073UL, 4062466752UL, 988602517UL, 1539348794UL, 1555068617UL, 2657884010UL, 460334294UL, 4240766479UL, 3639800790UL, 253377117UL, 3969136265UL, 488705329UL, 1722560286UL, 2289159295UL, 1025876008UL, 2927117896UL, 767521707UL, 2047999999UL, +4260853571UL, 2079302241UL, 2409677301UL, 1087552976UL, 2363907365UL, 2574464321UL, 2606273241UL, 3716086457UL, 26053603UL, 3162779415UL, 14843078UL, 2614076143UL, 1157531920UL, 2773275636UL, 2338825066UL, 435472225UL, 1399711137UL, 1224374788UL, 2154533280UL, 560135209UL, 935800607UL, 1940258814UL, 3826959530UL, 3423217355UL, 3704934971UL, 3815248829UL, 3878175339UL, 1395508015UL, 3295101527UL, 177901558UL, 4167531389UL, 1375148189UL, +3125377631UL, 557218961UL, 4088880299UL, 3478859071UL, 3687276754UL, 2845114223UL, 1713171361UL, 1756507633UL, 3160807894UL, 2375334470UL, 843542578UL, 1907952570UL, 1544844563UL, 2294372007UL, 3336681376UL, 734347193UL, 102566945UL, 2311037104UL, 4294750194UL, 3572240326UL, 732958152UL, 263733314UL, 2087890678UL, 331542297UL, 3549110380UL, 2073894939UL, 2104101380UL, 3670791368UL, 3122901693UL, 3799823891UL, 3783548253UL, 1102633864UL, +44327348UL, 916910638UL, 961623451UL, 1193013401UL, 1016438484UL, 1873779640UL, 287282633UL, 8590725UL, 3575333670UL, 324340905UL, 1144671533UL, 2840894649UL, 2980503178UL, 1111215768UL, 2783846375UL, 2000673937UL, 4158424384UL, 2184094569UL, 2305724254UL, 4057093054UL, 533488413UL, 3105191537UL, 768505376UL, 298782270UL, 993926164UL, 2015456740UL, 1479658113UL, 2376490281UL, 2767906402UL, 1619969256UL, 3120736988UL, 2563843533UL, +2974784738UL, 2529307107UL, 4289918826UL, 729503771UL, 3748950898UL, 2182744253UL, 431888679UL, 3780324902UL, 373638396UL, 54545903UL, 1688749940UL, 2394884334UL, 3477656171UL, 1083764681UL, 1562965459UL, 804704330UL, 4185729868UL, 138898835UL, 823405282UL, 327612841UL, 1252226275UL, 935318076UL, 2956823075UL, 899234846UL, 1510586062UL, 156282440UL, 3386839706UL, 2294393752UL, 2769934879UL, 4005033667UL, 651716500UL, 4115192738UL, +123027719UL, 3729538641UL, 2910637335UL, 2571924586UL, 3489608656UL, 956791985UL, 139360134UL, 3214531645UL, 2054232851UL, 49634692UL, 377192215UL, 2754746969UL, 2479252980UL, 3481787748UL, 3243507737UL, 605491073UL, 732155706UL, 988602517UL, 1539348794UL, 1555068617UL, 2657884010UL, 3753733088UL, 4240766479UL, 3639800790UL, 253377117UL, 3969136265UL, 3848735787UL, 1722560286UL, 2289159295UL, 1025876008UL, 2927117896UL, 3661948694UL, +2047999999UL, 4260853571UL, 2079302241UL, 2409677301UL, 3421911122UL, 2363907365UL, 2574464321UL, 2606273241UL, 3716086457UL, 2064343322UL, 3162779415UL, 14843078UL, 2614076143UL, 1157531920UL, 826449637UL, 2338825066UL, 435472225UL, 1399711137UL, 1224374788UL, 3770340198UL, 560135209UL, 935800607UL, 1940258814UL, 3826959530UL, 2963586762UL, 3704934971UL, 3815248829UL, 3878175339UL, 1395508015UL, 3721612680UL, 177901558UL, 4167531389UL, +1375148189UL, 3125377631UL, 1023552290UL, 4088880299UL, 3478859071UL, 3687276754UL, 2845114223UL, 3831557301UL, 1756507633UL, 3160807894UL, 2375334470UL, 843542578UL, 2798365898UL, 1544844563UL, 2294372007UL, 3336681376UL, 734347193UL, 1856808621UL, 2311037104UL, 4294750194UL, 3572240326UL, 732958152UL, 1999195012UL, 2087890678UL, 331542297UL, 3549110380UL, 2073894939UL, 3115936764UL, 3670791368UL, 3122901693UL, 3799823891UL, 3783548253UL, +132796150UL, 44327348UL, 916910638UL, 961623451UL, 1193013401UL, 1753944196UL, 1873779640UL, 287282633UL, 8590725UL, 3575333670UL, 1447720209UL, 1144671533UL, 2840894649UL, 2980503178UL, 1111215768UL, 1211945983UL, 2000673937UL, 4158424384UL, 2184094569UL, 2305724254UL, 402617261UL, 533488413UL, 3105191537UL, 768505376UL, 298782270UL, 2915553159UL, 2015456740UL, 1479658113UL, 2376490281UL, 2767906402UL, 3473761811UL, 3120736988UL, +2563843533UL, 2974784738UL, 2529307107UL, 737859212UL, 729503771UL, 3748950898UL, 2182744253UL, 431888679UL, 2013420163UL, 373638396UL, 54545903UL, 1688749940UL, 2394884334UL, 675998523UL, 1083764681UL, 1562965459UL, 804704330UL, 4185729868UL, 1165431355UL, 823405282UL, 327612841UL, 1252226275UL, 935318076UL, 2420680216UL, 899234846UL, 1510586062UL, 156282440UL, 3386839706UL, 2101339651UL, 2769934879UL, 4005033667UL, 651716500UL, +4115192738UL, 112049740UL, 3729538641UL, 2910637335UL, 2571924586UL, 3489608656UL, 305695595UL, 139360134UL, 3214531645UL, 2054232851UL, 49634692UL, 1073828255UL, 2754746969UL, 2479252980UL, 3481787748UL, 3243507737UL, 3392719169UL, 732155706UL, 988602517UL, 1539348794UL, 1555068617UL, 3246776527UL, 3753733088UL, 4240766479UL, 3639800790UL, 253377117UL, 872273450UL, 3848735787UL, 1722560286UL, 2289159295UL, 1025876008UL, 4168154213UL, +3661948694UL, 2047999999UL, 4260853571UL, 2079302241UL, 2380420842UL, 3421911122UL, 2363907365UL, 2574464321UL, 2606273241UL, 3881916078UL, 2064343322UL, 3162779415UL, 14843078UL, 2614076143UL, 473288515UL, 826449637UL, 2338825066UL, 435472225UL, 1399711137UL, 3068538992UL, 3770340198UL, 560135209UL, 935800607UL, 1940258814UL, 1469655183UL, 2963586762UL, 3704934971UL, 3815248829UL, 3878175339UL, 2410602840UL, 3721612680UL, 177901558UL, +4167531389UL, 1375148189UL, 1367577763UL, 1023552290UL, 4088880299UL, 3478859071UL, 3687276754UL, 678224549UL, 3831557301UL, 1756507633UL, 3160807894UL, 2375334470UL, 2884561721UL, 2798365898UL, 1544844563UL, 2294372007UL, 3336681376UL, 1938834658UL, 1856808621UL, 2311037104UL, 4294750194UL, 3572240326UL, 2786764913UL, 1999195012UL, 2087890678UL, 331542297UL, 3549110380UL, 3597797341UL, 3115936764UL, 3670791368UL, 3122901693UL, 3799823891UL, +1271317799UL, 132796150UL, 44327348UL, 916910638UL, 961623451UL, 2427821332UL, 1753944196UL, 1873779640UL, 287282633UL, 8590725UL, 1244012658UL, 1447720209UL, 1144671533UL, 2840894649UL, 2980503178UL, 3548902577UL, 1211945983UL, 2000673937UL, 4158424384UL, 2184094569UL, 2152623453UL, 402617261UL, 533488413UL, 3105191537UL, 768505376UL, 1095141108UL, 2915553159UL, 2015456740UL, 1479658113UL, 2376490281UL, 337998873UL, 3473761811UL, +3120736988UL, 2563843533UL, 2974784738UL, 3087228498UL, 737859212UL, 729503771UL, 3748950898UL, 2182744253UL, 2140410733UL, 2013420163UL, 373638396UL, 54545903UL, 1688749940UL, 528290088UL, 675998523UL, 1083764681UL, 1562965459UL, 804704330UL, 2536362875UL, 1165431355UL, 823405282UL, 327612841UL, 1252226275UL, 4037635314UL, 2420680216UL, 899234846UL, 1510586062UL, 156282440UL, 2012335895UL, 2101339651UL, 2769934879UL, 4005033667UL, +651716500UL, 2552583570UL, 112049740UL, 3729538641UL, 2910637335UL, 2571924586UL, 2436645403UL, 305695595UL, 139360134UL, 3214531645UL, 2054232851UL, 2384286326UL, 1073828255UL, 2754746969UL, 2479252980UL, 3481787748UL, 1948315585UL, 3392719169UL, 732155706UL, 988602517UL, 1539348794UL, 4110558494UL, 3246776527UL, 3753733088UL, 4240766479UL, 3639800790UL, 3627363812UL, 872273450UL, 3848735787UL, 1722560286UL, 2289159295UL, 4122430477UL, +4168154213UL, 3661948694UL, 2047999999UL, 4260853571UL, 1767882442UL, 2380420842UL, 3421911122UL, 2363907365UL, 2574464321UL, 2778622726UL, 3881916078UL, 2064343322UL, 3162779415UL, 14843078UL, 1513897109UL, 473288515UL, 826449637UL, 2338825066UL, 435472225UL, 322954918UL, 3068538992UL, 3770340198UL, 560135209UL, 935800607UL, 345602050UL, 1469655183UL, 2963586762UL, 3704934971UL, 3815248829UL, 3508249920UL, 2410602840UL, 3721612680UL, +177901558UL, 4167531389UL, 2161244150UL, 1367577763UL, 1023552290UL, 4088880299UL, 3478859071UL, 1108183104UL, 678224549UL, 3831557301UL, 1756507633UL, 3160807894UL, 2551630811UL, 2884561721UL, 2798365898UL, 1544844563UL, 2294372007UL, 2520267760UL, 1938834658UL, 1856808621UL, 2311037104UL, 4294750194UL, 2310096003UL, 2786764913UL, 1999195012UL, 2087890678UL, 331542297UL, 1205238749UL, 3597797341UL, 3115936764UL, 3670791368UL, 3122901693UL, +2008141679UL, 2018425028UL, 3435073328UL, 1452813805UL, 1628661138UL, 1323367156UL, 1062553693UL, 4029321700UL, 2772685842UL, 3798388850UL, 1315172209UL, 3930983291UL, 3816791373UL, 529176017UL, 3419610188UL, 3331589216UL, 4016977274UL, 2047089790UL, 3892571923UL, 2363414008UL, 1144631948UL, 3004954882UL, 2558739305UL, 19774033UL, 2525079911UL, 3774885821UL, 2817837373UL, 986111566UL, 1446678953UL, 3238485630UL, 3993748600UL, 1601954599UL, +3100591537UL, 2098009380UL, 3935971261UL, 4202546603UL, 3713465083UL, 3845664764UL, 2466365355UL, 1452340065UL, 2003576531UL, 1013434822UL, 2254608933UL, 783902023UL, 3129770529UL, 129130612UL, 821418228UL, 350036483UL, 3473671510UL, 4128495167UL, 2773832518UL, 683262085UL, 2143353417UL, 256251732UL, 1719056536UL, 2670223618UL, 328467339UL, 1564657740UL, 451231672UL, 2788353006UL, 882900088UL, 3255241056UL, 3198073758UL, 2541070985UL, +1941509325UL, 674933160UL, 207753676UL, 2605303964UL, 1681335994UL, 1143520001UL, 448872632UL, 302917879UL, 1100138495UL, 2058770021UL, 3116955098UL, 2081754747UL, 3734924767UL, 1916718058UL, 3873335960UL, 2740460398UL, 2171157007UL, 27677949UL, 2364721928UL, 175851655UL, 1468083950UL, 3162369526UL, 2441504540UL, 556978295UL, 2372096172UL, 3181101116UL, 2582850132UL, 1101292643UL, 862643740UL, 2095546242UL, 3261953801UL, 748040658UL, +3970037674UL, 819116843UL, 3594523650UL, 1597423019UL, 4109336883UL, 1198282420UL, 2905230517UL, 1729529596UL, 3230132814UL, 3640242164UL, 1899059108UL, 1944906555UL, 3426510495UL, 3035188107UL, 6448083UL, 1093882965UL, 2867500469UL, 3626379157UL, 1849073068UL, 897616501UL, 604221668UL, 1020676159UL, 4083635798UL, 1716022041UL, 3671877965UL, 1738820843UL, 30077467UL, 729231767UL, 3413193248UL, 207000406UL, 3854363185UL, 3302747326UL, +3293643267UL, 2101250157UL, 460131091UL, 4159442595UL, 1133391045UL, 1031215443UL, 4195487944UL, 45931575UL, 2922629291UL, 789302543UL, 3024994662UL, 442525623UL, 2850119076UL, 838309503UL, 2585361734UL, 1020449164UL, 1623631007UL, 955374631UL, 2932467671UL, 3713639221UL, 3019179416UL, 977970472UL, 1817244230UL, 3856774853UL, 1140530868UL, 886199600UL, 1218509766UL, 4001537244UL, 2840913665UL, 2133254364UL, 3332344608UL, 475291624UL, +}, +{ +1854921599UL, 2655519695UL, 3124573588UL, 319882484UL, 603545603UL, 4175512633UL, 141286453UL, 1183670252UL, 1789500145UL, 37351733UL, 3190829323UL, 2782782009UL, 493805446UL, 1228958246UL, 2672482554UL, 2274981421UL, 2935438833UL, 3625733677UL, 3679506394UL, 687805550UL, 134516308UL, 3576789728UL, 965007022UL, 1056542222UL, 2319405423UL, 3944221200UL, 950102624UL, 3848192810UL, 3205299696UL, 82033760UL, 1241913280UL, 1360146137UL, +1675732327UL, 2164452797UL, 3920498715UL, 2226452641UL, 3172047212UL, 1569171738UL, 2631589480UL, 2889660225UL, 2030783667UL, 2237381973UL, 2706217212UL, 3143638386UL, 1733174225UL, 1166820137UL, 3818389960UL, 193959252UL, 2793509934UL, 316291605UL, 2502743884UL, 1963136977UL, 3739017448UL, 25754513UL, 1590156485UL, 1856291967UL, 4143674472UL, 2538785911UL, 2159135699UL, 1908446793UL, 3303325234UL, 2589568800UL, 1193586059UL, 77481069UL, +789413194UL, 2556570543UL, 162987300UL, 1960844609UL, 2973799047UL, 4253906178UL, 315868734UL, 2542622968UL, 3949539136UL, 1479106582UL, 4225431384UL, 1235059630UL, 1533374854UL, 847792023UL, 4031286530UL, 4194276632UL, 164541100UL, 1010135841UL, 143302319UL, 1335585015UL, 1237311692UL, 20896020UL, 344974153UL, 2576803233UL, 3430251730UL, 984163376UL, 2680612471UL, 1276425436UL, 2400671554UL, 1628640140UL, 2161048926UL, 2109177634UL, +998215324UL, 3127793500UL, 1759998050UL, 3105138908UL, 2583746384UL, 2126302368UL, 3258602104UL, 1262742375UL, 3565617377UL, 3726060195UL, 157069329UL, 390662438UL, 3800994052UL, 2007694482UL, 377281730UL, 3251789121UL, 236703173UL, 122782596UL, 775407411UL, 3394010206UL, 4232159202UL, 468321553UL, 2704615220UL, 1332411375UL, 2978494251UL, 989230484UL, 3122841814UL, 2348872707UL, 731335994UL, 541354422UL, 223117443UL, 2225009071UL, +4230058949UL, 1875162926UL, 3897048544UL, 3550177883UL, 2461273592UL, 1046820583UL, 1333727817UL, 1378024753UL, 3686775275UL, 4230752590UL, 64834458UL, 1281467967UL, 729116355UL, 3886390916UL, 65029451UL, 3478506446UL, 1387684482UL, 1172004841UL, 2525409243UL, 1677678908UL, 1704646757UL, 930937262UL, 1088384271UL, 689357059UL, 1754542213UL, 702963842UL, 2864311668UL, 1960202673UL, 1009675673UL, 3742350158UL, 3751269215UL, 3166659283UL, +9090161UL, 1854921599UL, 2655519695UL, 3124573588UL, 319882484UL, 1422536794UL, 4175512633UL, 141286453UL, 1183670252UL, 1789500145UL, 850391877UL, 3190829323UL, 2782782009UL, 493805446UL, 1228958246UL, 837232655UL, 2274981421UL, 2935438833UL, 3625733677UL, 3679506394UL, 955772620UL, 134516308UL, 3576789728UL, 965007022UL, 1056542222UL, 874117013UL, 3944221200UL, 950102624UL, 3848192810UL, 3205299696UL, 543679720UL, 1241913280UL, +1360146137UL, 1675732327UL, 2164452797UL, 1169030022UL, 2226452641UL, 3172047212UL, 1569171738UL, 2631589480UL, 3783543297UL, 2030783667UL, 2237381973UL, 2706217212UL, 3143638386UL, 1560162209UL, 1166820137UL, 3818389960UL, 193959252UL, 2793509934UL, 4258046618UL, 2502743884UL, 1963136977UL, 3739017448UL, 25754513UL, 1204846712UL, 1856291967UL, 4143674472UL, 2538785911UL, 2159135699UL, 3889946075UL, 3303325234UL, 2589568800UL, 1193586059UL, +77481069UL, 969912041UL, 2556570543UL, 162987300UL, 1960844609UL, 2973799047UL, 427583517UL, 315868734UL, 2542622968UL, 3949539136UL, 1479106582UL, 92839917UL, 1235059630UL, 1533374854UL, 847792023UL, 4031286530UL, 1147875681UL, 164541100UL, 1010135841UL, 143302319UL, 1335585015UL, 368616909UL, 20896020UL, 344974153UL, 2576803233UL, 3430251730UL, 1078575783UL, 2680612471UL, 1276425436UL, 2400671554UL, 1628640140UL, 4149623645UL, +2109177634UL, 998215324UL, 3127793500UL, 1759998050UL, 3525419965UL, 2583746384UL, 2126302368UL, 3258602104UL, 1262742375UL, 1996113346UL, 3726060195UL, 157069329UL, 390662438UL, 3800994052UL, 982000497UL, 377281730UL, 3251789121UL, 236703173UL, 122782596UL, 2303768414UL, 3394010206UL, 4232159202UL, 468321553UL, 2704615220UL, 681592492UL, 2978494251UL, 989230484UL, 3122841814UL, 2348872707UL, 4089094260UL, 541354422UL, 223117443UL, +2225009071UL, 4230058949UL, 2754981128UL, 3897048544UL, 3550177883UL, 2461273592UL, 1046820583UL, 668143612UL, 1378024753UL, 3686775275UL, 4230752590UL, 64834458UL, 3765910650UL, 729116355UL, 3886390916UL, 65029451UL, 3478506446UL, 3419111947UL, 1172004841UL, 2525409243UL, 1677678908UL, 1704646757UL, 155635560UL, 1088384271UL, 689357059UL, 1754542213UL, 702963842UL, 2712009967UL, 1960202673UL, 1009675673UL, 3742350158UL, 3751269215UL, +129749802UL, 9090161UL, 1854921599UL, 2655519695UL, 3124573588UL, 809557750UL, 1422536794UL, 4175512633UL, 141286453UL, 1183670252UL, 1739311360UL, 850391877UL, 3190829323UL, 2782782009UL, 493805446UL, 1738527771UL, 837232655UL, 2274981421UL, 2935438833UL, 3625733677UL, 1858071296UL, 955772620UL, 134516308UL, 3576789728UL, 965007022UL, 3367712327UL, 874117013UL, 3944221200UL, 950102624UL, 3848192810UL, 2420548306UL, 543679720UL, +1241913280UL, 1360146137UL, 1675732327UL, 176019367UL, 1169030022UL, 2226452641UL, 3172047212UL, 1569171738UL, 76544055UL, 3783543297UL, 2030783667UL, 2237381973UL, 2706217212UL, 3283985735UL, 1560162209UL, 1166820137UL, 3818389960UL, 193959252UL, 346134252UL, 4258046618UL, 2502743884UL, 1963136977UL, 3739017448UL, 3887005605UL, 1204846712UL, 1856291967UL, 4143674472UL, 2538785911UL, 366578749UL, 3889946075UL, 3303325234UL, 2589568800UL, +1193586059UL, 2917569085UL, 969912041UL, 2556570543UL, 162987300UL, 1960844609UL, 61311938UL, 427583517UL, 315868734UL, 2542622968UL, 3949539136UL, 2278526422UL, 92839917UL, 1235059630UL, 1533374854UL, 847792023UL, 1361054176UL, 1147875681UL, 164541100UL, 1010135841UL, 143302319UL, 1348709332UL, 368616909UL, 20896020UL, 344974153UL, 2576803233UL, 3290873783UL, 1078575783UL, 2680612471UL, 1276425436UL, 2400671554UL, 628790408UL, +4149623645UL, 2109177634UL, 998215324UL, 3127793500UL, 2019336900UL, 3525419965UL, 2583746384UL, 2126302368UL, 3258602104UL, 2858154034UL, 1996113346UL, 3726060195UL, 157069329UL, 390662438UL, 2250549235UL, 982000497UL, 377281730UL, 3251789121UL, 236703173UL, 3487415996UL, 2303768414UL, 3394010206UL, 4232159202UL, 468321553UL, 2773608982UL, 681592492UL, 2978494251UL, 989230484UL, 3122841814UL, 3647638215UL, 4089094260UL, 541354422UL, +223117443UL, 2225009071UL, 2829509947UL, 2754981128UL, 3897048544UL, 3550177883UL, 2461273592UL, 282627696UL, 668143612UL, 1378024753UL, 3686775275UL, 4230752590UL, 1105868822UL, 3765910650UL, 729116355UL, 3886390916UL, 65029451UL, 328554604UL, 3419111947UL, 1172004841UL, 2525409243UL, 1677678908UL, 1395036942UL, 155635560UL, 1088384271UL, 689357059UL, 1754542213UL, 1076601715UL, 2712009967UL, 1960202673UL, 1009675673UL, 3742350158UL, +2581225953UL, 129749802UL, 9090161UL, 1854921599UL, 2655519695UL, 1393282220UL, 809557750UL, 1422536794UL, 4175512633UL, 141286453UL, 2211497169UL, 1739311360UL, 850391877UL, 3190829323UL, 2782782009UL, 2694871802UL, 1738527771UL, 837232655UL, 2274981421UL, 2935438833UL, 3145832503UL, 1858071296UL, 955772620UL, 134516308UL, 3576789728UL, 4045354759UL, 3367712327UL, 874117013UL, 3944221200UL, 950102624UL, 3562634568UL, 2420548306UL, +543679720UL, 1241913280UL, 1360146137UL, 3644280343UL, 176019367UL, 1169030022UL, 2226452641UL, 3172047212UL, 3927720006UL, 76544055UL, 3783543297UL, 2030783667UL, 2237381973UL, 1497233808UL, 3283985735UL, 1560162209UL, 1166820137UL, 3818389960UL, 2344066681UL, 346134252UL, 4258046618UL, 2502743884UL, 1963136977UL, 79988846UL, 3887005605UL, 1204846712UL, 1856291967UL, 4143674472UL, 3967952414UL, 366578749UL, 3889946075UL, 3303325234UL, +2589568800UL, 2193179011UL, 2917569085UL, 969912041UL, 2556570543UL, 162987300UL, 52882655UL, 61311938UL, 427583517UL, 315868734UL, 2542622968UL, 1575831590UL, 2278526422UL, 92839917UL, 1235059630UL, 1533374854UL, 2397068791UL, 1361054176UL, 1147875681UL, 164541100UL, 1010135841UL, 2586368032UL, 1348709332UL, 368616909UL, 20896020UL, 344974153UL, 3445652232UL, 3290873783UL, 1078575783UL, 2680612471UL, 1276425436UL, 3682156544UL, +628790408UL, 4149623645UL, 2109177634UL, 998215324UL, 4049708298UL, 2019336900UL, 3525419965UL, 2583746384UL, 2126302368UL, 1627944270UL, 2858154034UL, 1996113346UL, 3726060195UL, 157069329UL, 1481222640UL, 2250549235UL, 982000497UL, 377281730UL, 3251789121UL, 3564274539UL, 3487415996UL, 2303768414UL, 3394010206UL, 4232159202UL, 3509025997UL, 2773608982UL, 681592492UL, 2978494251UL, 989230484UL, 980252048UL, 3647638215UL, 4089094260UL, +541354422UL, 223117443UL, 543970497UL, 2829509947UL, 2754981128UL, 3897048544UL, 3550177883UL, 2736782140UL, 282627696UL, 668143612UL, 1378024753UL, 3686775275UL, 2728601425UL, 1105868822UL, 3765910650UL, 729116355UL, 3886390916UL, 1866378660UL, 328554604UL, 3419111947UL, 1172004841UL, 2525409243UL, 1506924008UL, 1395036942UL, 155635560UL, 1088384271UL, 689357059UL, 3587092123UL, 1076601715UL, 2712009967UL, 1960202673UL, 1009675673UL, +4292715891UL, 2465250857UL, 3267969665UL, 2459570573UL, 3644463083UL, 1637197500UL, 684559293UL, 3520611957UL, 2976084366UL, 1512112440UL, 1778285193UL, 1849742417UL, 3144801412UL, 3009052859UL, 820829188UL, 1382783871UL, 3373481539UL, 3777016406UL, 266942530UL, 1792334422UL, 4109859515UL, 1468149634UL, 1356457853UL, 623893785UL, 1301686542UL, 441704877UL, 3377795902UL, 879822753UL, 329462927UL, 543858304UL, 2221828617UL, 2996486613UL, +981774202UL, 1032220084UL, 1066536452UL, 1004068806UL, 1336694798UL, 3744375323UL, 3802436665UL, 3366526577UL, 418696462UL, 1776559103UL, 1291965608UL, 1623030339UL, 1443628607UL, 572114324UL, 899621592UL, 332121275UL, 3637616671UL, 457287722UL, 3803043476UL, 408472701UL, 660940326UL, 1209169008UL, 1202511620UL, 2906900959UL, 2600414642UL, 2015874468UL, 2931389161UL, 1760773669UL, 2601299639UL, 543821664UL, 3426280682UL, 1337602255UL, +3334593650UL, 1320885980UL, 3857269540UL, 2548321029UL, 2250001180UL, 673341051UL, 1900184720UL, 731675831UL, 2461790412UL, 2593291320UL, 1640301250UL, 863529987UL, 91627443UL, 2437824309UL, 2834231475UL, 4093270720UL, 1474594761UL, 4186662839UL, 1683556862UL, 1302286991UL, 806676270UL, 703274107UL, 3756759580UL, 674737904UL, 912015048UL, 1823306025UL, 1509430520UL, 3128952761UL, 290841833UL, 3917789380UL, 1022040580UL, 1810054038UL, +334998864UL, 1009274987UL, 310979037UL, 606749827UL, 546291081UL, 3438438313UL, 1840081424UL, 1950680845UL, 4217236364UL, 1814584903UL, 2814353208UL, 194196981UL, 1540331253UL, 3135937654UL, 773351497UL, 1878220007UL, 3097009802UL, 1252607159UL, 1378821846UL, 2741884614UL, 178612659UL, 3656860395UL, 1259606652UL, 3942111545UL, 488406826UL, 3640897405UL, 3419000480UL, 353909713UL, 2996208477UL, 2862593073UL, 108483327UL, 648472258UL, +1060249632UL, 1049865483UL, 430087518UL, 1364157854UL, 3367631180UL, 251313827UL, 2374149836UL, 2109357086UL, 479172068UL, 464775113UL, 1806677787UL, 3488082411UL, 356035738UL, 3080424395UL, 4134646749UL, 369528743UL, 1031004516UL, 2525336414UL, 4189798138UL, 3928909462UL, 568714397UL, 1681832820UL, 1753328641UL, 827357673UL, 1651960551UL, 1798317455UL, 737101952UL, 3257553606UL, 400882781UL, 1473208110UL, 4134183873UL, 2193420912UL, +}, +{ +2483976489UL, 2790651795UL, 3298324523UL, 3508205426UL, 2236819708UL, 917494217UL, 769620837UL, 3411018785UL, 2391335000UL, 1627061280UL, 3356773416UL, 1288706527UL, 4178910717UL, 3636299534UL, 4221874052UL, 3674654381UL, 537787012UL, 4271656840UL, 185820273UL, 1160533598UL, 1862365049UL, 2550353307UL, 1392072847UL, 1870891365UL, 1517453821UL, 524666025UL, 3645751565UL, 2415020247UL, 3691419894UL, 2580450642UL, 2130267479UL, 3636103610UL, +562446539UL, 750696587UL, 97137475UL, 3894066051UL, 2239638596UL, 3256181120UL, 3981041836UL, 774947039UL, 451287677UL, 3618957054UL, 4236303539UL, 1027744929UL, 1497195372UL, 498574915UL, 2164122779UL, 582902291UL, 3040883311UL, 1626221455UL, 1853378UL, 2125490000UL, 3185055972UL, 1607660025UL, 432884530UL, 779476209UL, 124284956UL, 2488937128UL, 2521389012UL, 107485781UL, 2873055013UL, 1171872946UL, 3130489952UL, 4273333914UL, +646240524UL, 3970896645UL, 942009076UL, 4069926418UL, 3129385884UL, 3470469370UL, 388702536UL, 450999415UL, 2995728716UL, 1687173264UL, 3049352827UL, 2648078738UL, 190663705UL, 486809970UL, 424002670UL, 2421764946UL, 2941043524UL, 3841512738UL, 119077561UL, 1801381572UL, 2208680167UL, 2502730219UL, 9899015UL, 2455199230UL, 3755314209UL, 3958460021UL, 3846398898UL, 1405136244UL, 2870563334UL, 821846618UL, 2790899812UL, 863647562UL, +629585032UL, 958925512UL, 1190540209UL, 57251233UL, 2109551995UL, 2294881622UL, 2603370255UL, 3839518646UL, 123838650UL, 3436270690UL, 1637121394UL, 3761101432UL, 954001192UL, 759760236UL, 3268295908UL, 2313083096UL, 630164216UL, 2367213191UL, 3992059381UL, 3292952769UL, 2040774258UL, 1420209005UL, 527547730UL, 1222399440UL, 1515078401UL, 2005580991UL, 645585788UL, 2256370254UL, 3057235502UL, 2870727428UL, 2785498804UL, 333440916UL, +1873686678UL, 2489794553UL, 3726728164UL, 3405629071UL, 3869328595UL, 3081963448UL, 2122133003UL, 1428788181UL, 4141962679UL, 41030733UL, 183716455UL, 36316501UL, 1430796327UL, 1884066707UL, 1216957106UL, 3455082673UL, 1092665987UL, 535070834UL, 3873372533UL, 175757671UL, 3414803303UL, 791028991UL, 3436610906UL, 2950895946UL, 977680845UL, 4224715886UL, 2809442211UL, 4044727083UL, 3035532020UL, 4253187882UL, 969203959UL, 2539482914UL, +813880136UL, 2483976489UL, 2790651795UL, 3298324523UL, 3508205426UL, 49280479UL, 917494217UL, 769620837UL, 3411018785UL, 2391335000UL, 3036738936UL, 3356773416UL, 1288706527UL, 4178910717UL, 3636299534UL, 2294957038UL, 3674654381UL, 537787012UL, 4271656840UL, 185820273UL, 2622722506UL, 1862365049UL, 2550353307UL, 1392072847UL, 1870891365UL, 2838104933UL, 524666025UL, 3645751565UL, 2415020247UL, 3691419894UL, 1295777418UL, 2130267479UL, +3636103610UL, 562446539UL, 750696587UL, 249830932UL, 3894066051UL, 2239638596UL, 3256181120UL, 3981041836UL, 3217398876UL, 451287677UL, 3618957054UL, 4236303539UL, 1027744929UL, 1724964245UL, 498574915UL, 2164122779UL, 582902291UL, 3040883311UL, 3101287841UL, 1853378UL, 2125490000UL, 3185055972UL, 1607660025UL, 1128474163UL, 779476209UL, 124284956UL, 2488937128UL, 2521389012UL, 338597864UL, 2873055013UL, 1171872946UL, 3130489952UL, +4273333914UL, 1557892392UL, 3970896645UL, 942009076UL, 4069926418UL, 3129385884UL, 2688433076UL, 388702536UL, 450999415UL, 2995728716UL, 1687173264UL, 157685189UL, 2648078738UL, 190663705UL, 486809970UL, 424002670UL, 979986388UL, 2941043524UL, 3841512738UL, 119077561UL, 1801381572UL, 2668625968UL, 2502730219UL, 9899015UL, 2455199230UL, 3755314209UL, 2699515741UL, 3846398898UL, 1405136244UL, 2870563334UL, 821846618UL, 505633792UL, +863647562UL, 629585032UL, 958925512UL, 1190540209UL, 2067402799UL, 2109551995UL, 2294881622UL, 2603370255UL, 3839518646UL, 2688067120UL, 3436270690UL, 1637121394UL, 3761101432UL, 954001192UL, 3206166733UL, 3268295908UL, 2313083096UL, 630164216UL, 2367213191UL, 3007494680UL, 3292952769UL, 2040774258UL, 1420209005UL, 527547730UL, 4047406592UL, 1515078401UL, 2005580991UL, 645585788UL, 2256370254UL, 13805572UL, 2870727428UL, 2785498804UL, +333440916UL, 1873686678UL, 1928222740UL, 3726728164UL, 3405629071UL, 3869328595UL, 3081963448UL, 2971423693UL, 1428788181UL, 4141962679UL, 41030733UL, 183716455UL, 4064095256UL, 1430796327UL, 1884066707UL, 1216957106UL, 3455082673UL, 985592757UL, 535070834UL, 3873372533UL, 175757671UL, 3414803303UL, 2159028553UL, 3436610906UL, 2950895946UL, 977680845UL, 4224715886UL, 345462057UL, 4044727083UL, 3035532020UL, 4253187882UL, 969203959UL, +984166534UL, 813880136UL, 2483976489UL, 2790651795UL, 3298324523UL, 1080001158UL, 49280479UL, 917494217UL, 769620837UL, 3411018785UL, 3216598401UL, 3036738936UL, 3356773416UL, 1288706527UL, 4178910717UL, 3311472057UL, 2294957038UL, 3674654381UL, 537787012UL, 4271656840UL, 220045511UL, 2622722506UL, 1862365049UL, 2550353307UL, 1392072847UL, 3057632678UL, 2838104933UL, 524666025UL, 3645751565UL, 2415020247UL, 252304106UL, 1295777418UL, +2130267479UL, 3636103610UL, 562446539UL, 80437039UL, 249830932UL, 3894066051UL, 2239638596UL, 3256181120UL, 117173223UL, 3217398876UL, 451287677UL, 3618957054UL, 4236303539UL, 1986849360UL, 1724964245UL, 498574915UL, 2164122779UL, 582902291UL, 288631030UL, 3101287841UL, 1853378UL, 2125490000UL, 3185055972UL, 824635664UL, 1128474163UL, 779476209UL, 124284956UL, 2488937128UL, 1231646648UL, 338597864UL, 2873055013UL, 1171872946UL, +3130489952UL, 708957725UL, 1557892392UL, 3970896645UL, 942009076UL, 4069926418UL, 2286522565UL, 2688433076UL, 388702536UL, 450999415UL, 2995728716UL, 2523361978UL, 157685189UL, 2648078738UL, 190663705UL, 486809970UL, 151444406UL, 979986388UL, 2941043524UL, 3841512738UL, 119077561UL, 3762447035UL, 2668625968UL, 2502730219UL, 9899015UL, 2455199230UL, 3532439568UL, 2699515741UL, 3846398898UL, 1405136244UL, 2870563334UL, 2242036665UL, +505633792UL, 863647562UL, 629585032UL, 958925512UL, 2618618630UL, 2067402799UL, 2109551995UL, 2294881622UL, 2603370255UL, 2461404010UL, 2688067120UL, 3436270690UL, 1637121394UL, 3761101432UL, 1076814097UL, 3206166733UL, 3268295908UL, 2313083096UL, 630164216UL, 12196305UL, 3007494680UL, 3292952769UL, 2040774258UL, 1420209005UL, 2609377752UL, 4047406592UL, 1515078401UL, 2005580991UL, 645585788UL, 865985176UL, 13805572UL, 2870727428UL, +2785498804UL, 333440916UL, 3735553268UL, 1928222740UL, 3726728164UL, 3405629071UL, 3869328595UL, 501640466UL, 2971423693UL, 1428788181UL, 4141962679UL, 41030733UL, 97561214UL, 4064095256UL, 1430796327UL, 1884066707UL, 1216957106UL, 3840122090UL, 985592757UL, 535070834UL, 3873372533UL, 175757671UL, 3856277268UL, 2159028553UL, 3436610906UL, 2950895946UL, 977680845UL, 3313441827UL, 345462057UL, 4044727083UL, 3035532020UL, 4253187882UL, +3468811573UL, 984166534UL, 813880136UL, 2483976489UL, 2790651795UL, 3733649754UL, 1080001158UL, 49280479UL, 917494217UL, 769620837UL, 3969566450UL, 3216598401UL, 3036738936UL, 3356773416UL, 1288706527UL, 2444128005UL, 3311472057UL, 2294957038UL, 3674654381UL, 537787012UL, 4166109669UL, 220045511UL, 2622722506UL, 1862365049UL, 2550353307UL, 2552992760UL, 3057632678UL, 2838104933UL, 524666025UL, 3645751565UL, 664164441UL, 252304106UL, +1295777418UL, 2130267479UL, 3636103610UL, 3227561061UL, 80437039UL, 249830932UL, 3894066051UL, 2239638596UL, 1071536668UL, 117173223UL, 3217398876UL, 451287677UL, 3618957054UL, 3066415327UL, 1986849360UL, 1724964245UL, 498574915UL, 2164122779UL, 3541914330UL, 288631030UL, 3101287841UL, 1853378UL, 2125490000UL, 2207189978UL, 824635664UL, 1128474163UL, 779476209UL, 124284956UL, 2117633906UL, 1231646648UL, 338597864UL, 2873055013UL, +1171872946UL, 891038594UL, 708957725UL, 1557892392UL, 3970896645UL, 942009076UL, 42952651UL, 2286522565UL, 2688433076UL, 388702536UL, 450999415UL, 2986730356UL, 2523361978UL, 157685189UL, 2648078738UL, 190663705UL, 3058267870UL, 151444406UL, 979986388UL, 2941043524UL, 3841512738UL, 1844101292UL, 3762447035UL, 2668625968UL, 2502730219UL, 9899015UL, 2599582093UL, 3532439568UL, 2699515741UL, 3846398898UL, 1405136244UL, 811001941UL, +2242036665UL, 505633792UL, 863647562UL, 629585032UL, 2722320710UL, 2618618630UL, 2067402799UL, 2109551995UL, 2294881622UL, 1820862072UL, 2461404010UL, 2688067120UL, 3436270690UL, 1637121394UL, 3642978005UL, 1076814097UL, 3206166733UL, 3268295908UL, 2313083096UL, 1900318020UL, 12196305UL, 3007494680UL, 3292952769UL, 2040774258UL, 520848705UL, 2609377752UL, 4047406592UL, 1515078401UL, 2005580991UL, 2530251392UL, 865985176UL, 13805572UL, +2870727428UL, 2785498804UL, 2878984912UL, 3735553268UL, 1928222740UL, 3726728164UL, 3405629071UL, 2717736455UL, 501640466UL, 2971423693UL, 1428788181UL, 4141962679UL, 3704214873UL, 97561214UL, 4064095256UL, 1430796327UL, 1884066707UL, 1721732760UL, 3840122090UL, 985592757UL, 535070834UL, 3873372533UL, 770732059UL, 3856277268UL, 2159028553UL, 3436610906UL, 2950895946UL, 33753949UL, 3313441827UL, 345462057UL, 4044727083UL, 3035532020UL, +4166506071UL, 2719759982UL, 1025532659UL, 3811323959UL, 713457907UL, 1577198020UL, 1719946821UL, 3963262337UL, 1719605451UL, 703663722UL, 1943886497UL, 2916371044UL, 1655862745UL, 109438187UL, 195575943UL, 2572727533UL, 2421761970UL, 1796539813UL, 2020762515UL, 1191344316UL, 2492085516UL, 2778033179UL, 4002316684UL, 1571080685UL, 1157340389UL, 3859584731UL, 3403766082UL, 2292873365UL, 2032258920UL, 1749575450UL, 848549431UL, 1893685820UL, +3510068298UL, 3308906564UL, 1193936308UL, 2561670234UL, 1043148718UL, 2611815896UL, 3832995202UL, 2436487998UL, 3377369330UL, 1174818128UL, 796514731UL, 1985886833UL, 88296218UL, 3032898657UL, 4101301361UL, 1486994584UL, 237792475UL, 1029399834UL, 1708840018UL, 2934039708UL, 1496674948UL, 4243234983UL, 3896751668UL, 1726119825UL, 2706068825UL, 1900013134UL, 2639641919UL, 1433377392UL, 2962655166UL, 1870954268UL, 3873603462UL, 1778084630UL, +2393311756UL, 4135022799UL, 3669603001UL, 811404758UL, 784379778UL, 4283689136UL, 405168660UL, 3873488622UL, 486946690UL, 347427153UL, 2139072474UL, 1143349522UL, 3780264455UL, 2938731842UL, 3864001470UL, 3497981827UL, 2703917008UL, 3222236962UL, 2604106616UL, 1281570367UL, 175937153UL, 433252852UL, 3232065906UL, 1111895932UL, 1027363895UL, 2435093744UL, 4232690481UL, 1940855209UL, 2844613991UL, 2095175619UL, 3479946852UL, 393314401UL, +3625733631UL, 1073779513UL, 2884072879UL, 4089630675UL, 3614205484UL, 1379809260UL, 3980251795UL, 3914556410UL, 3633356126UL, 3030204458UL, 1654727861UL, 3765074811UL, 959734060UL, 842315676UL, 353688341UL, 145655006UL, 1972100601UL, 1456042517UL, 3767579955UL, 4282066379UL, 498998655UL, 4123310742UL, 1801424182UL, 777808179UL, 655425670UL, 588715641UL, 2136252742UL, 1283378143UL, 639191135UL, 3132375783UL, 276649124UL, 2036776039UL, +3352396498UL, 3893441746UL, 3298373918UL, 1024178230UL, 2623051553UL, 1956117442UL, 2955394456UL, 2478945776UL, 3904945720UL, 769232312UL, 2168822980UL, 3715831945UL, 453874622UL, 3351529191UL, 3256151193UL, 808042625UL, 1700919462UL, 1008305347UL, 1518733915UL, 3194328753UL, 2228970756UL, 2604658038UL, 1376476152UL, 2147167203UL, 2585867511UL, 445717950UL, 3595016420UL, 3673970127UL, 3640614546UL, 494944945UL, 152508312UL, 4160926899UL, +}, +{ +3225674336UL, 827428943UL, 2858523441UL, 2447266124UL, 1539223637UL, 2299756421UL, 776912458UL, 279091824UL, 1152725492UL, 3903457284UL, 3987010398UL, 3996115574UL, 839506039UL, 3052513014UL, 28550291UL, 2597814974UL, 2328446377UL, 1961600298UL, 3695276714UL, 1334932648UL, 1141381380UL, 3025370440UL, 997698792UL, 931473445UL, 3091440507UL, 820119215UL, 3586778616UL, 1993126242UL, 4252838072UL, 3033829531UL, 2120026924UL, 65722921UL, +746724958UL, 461423533UL, 1582298542UL, 1564918930UL, 3710935369UL, 419349792UL, 3914061713UL, 2279209938UL, 770031171UL, 2062767935UL, 3373230309UL, 3582372364UL, 2025682996UL, 3352859025UL, 1262632952UL, 3140021482UL, 501370035UL, 2554730117UL, 352450195UL, 1002557127UL, 2813224858UL, 2808406559UL, 290476252UL, 4216846311UL, 1187381982UL, 3131323304UL, 1094330039UL, 2646234280UL, 655242013UL, 1152156402UL, 3658526705UL, 3565043535UL, +693375321UL, 2120064836UL, 3726555752UL, 97387177UL, 546586686UL, 1013492636UL, 3874404446UL, 440995849UL, 1929251266UL, 95137166UL, 564969023UL, 3559119399UL, 3855477390UL, 2439885481UL, 2492213232UL, 2611214170UL, 2054191666UL, 2778642234UL, 2267416277UL, 2194315209UL, 1360165075UL, 1018128176UL, 2841084399UL, 3028189871UL, 3631770575UL, 541021087UL, 1091467742UL, 2743780329UL, 3566538467UL, 1277066122UL, 279582475UL, 2712119598UL, +3296319359UL, 4187226385UL, 1468994750UL, 2946664285UL, 2284913307UL, 740953233UL, 3351500634UL, 1791054313UL, 3355533193UL, 610062694UL, 3089981426UL, 3469441840UL, 3225672476UL, 2223653903UL, 2593994385UL, 548784340UL, 549871569UL, 865468702UL, 1593939385UL, 645229999UL, 1412095765UL, 2814231763UL, 3619658094UL, 877462820UL, 2198765077UL, 1845119421UL, 4144145546UL, 1356681209UL, 848707034UL, 4144513299UL, 3231318896UL, 3382035479UL, +693621410UL, 2821661683UL, 4236142563UL, 680649431UL, 3290999942UL, 200856634UL, 617766412UL, 3194332974UL, 4102392657UL, 2776797278UL, 2932808060UL, 793967937UL, 2149374605UL, 3736514467UL, 3547689148UL, 3744888920UL, 98278184UL, 1497045279UL, 2945126332UL, 4285864315UL, 2791068812UL, 1939995011UL, 56752862UL, 864909862UL, 625377571UL, 2266362085UL, 1050287398UL, 925722519UL, 1008109592UL, 2819528345UL, 3573068613UL, 1915083884UL, +1536828870UL, 3225674336UL, 827428943UL, 2858523441UL, 2447266124UL, 2186287936UL, 2299756421UL, 776912458UL, 279091824UL, 1152725492UL, 1271286102UL, 3987010398UL, 3996115574UL, 839506039UL, 3052513014UL, 1036957208UL, 2597814974UL, 2328446377UL, 1961600298UL, 3695276714UL, 2395157917UL, 1141381380UL, 3025370440UL, 997698792UL, 931473445UL, 2727078785UL, 820119215UL, 3586778616UL, 1993126242UL, 4252838072UL, 1171102868UL, 2120026924UL, +65722921UL, 746724958UL, 461423533UL, 2335086228UL, 1564918930UL, 3710935369UL, 419349792UL, 3914061713UL, 1136716661UL, 770031171UL, 2062767935UL, 3373230309UL, 3582372364UL, 4100328450UL, 3352859025UL, 1262632952UL, 3140021482UL, 501370035UL, 2579000299UL, 352450195UL, 1002557127UL, 2813224858UL, 2808406559UL, 2642514897UL, 4216846311UL, 1187381982UL, 3131323304UL, 1094330039UL, 3092488663UL, 655242013UL, 1152156402UL, 3658526705UL, +3565043535UL, 3280658482UL, 2120064836UL, 3726555752UL, 97387177UL, 546586686UL, 584864345UL, 3874404446UL, 440995849UL, 1929251266UL, 95137166UL, 823950215UL, 3559119399UL, 3855477390UL, 2439885481UL, 2492213232UL, 2297040376UL, 2054191666UL, 2778642234UL, 2267416277UL, 2194315209UL, 573807317UL, 1018128176UL, 2841084399UL, 3028189871UL, 3631770575UL, 2747338726UL, 1091467742UL, 2743780329UL, 3566538467UL, 1277066122UL, 1715139924UL, +2712119598UL, 3296319359UL, 4187226385UL, 1468994750UL, 3361368810UL, 2284913307UL, 740953233UL, 3351500634UL, 1791054313UL, 4290564545UL, 610062694UL, 3089981426UL, 3469441840UL, 3225672476UL, 1010959310UL, 2593994385UL, 548784340UL, 549871569UL, 865468702UL, 1825306744UL, 645229999UL, 1412095765UL, 2814231763UL, 3619658094UL, 3792219969UL, 2198765077UL, 1845119421UL, 4144145546UL, 1356681209UL, 268197516UL, 4144513299UL, 3231318896UL, +3382035479UL, 693621410UL, 2786831464UL, 4236142563UL, 680649431UL, 3290999942UL, 200856634UL, 3822069622UL, 3194332974UL, 4102392657UL, 2776797278UL, 2932808060UL, 525501162UL, 2149374605UL, 3736514467UL, 3547689148UL, 3744888920UL, 3219948462UL, 1497045279UL, 2945126332UL, 4285864315UL, 2791068812UL, 2678467476UL, 56752862UL, 864909862UL, 625377571UL, 2266362085UL, 2258093843UL, 925722519UL, 1008109592UL, 2819528345UL, 3573068613UL, +2743241289UL, 1536828870UL, 3225674336UL, 827428943UL, 2858523441UL, 992128922UL, 2186287936UL, 2299756421UL, 776912458UL, 279091824UL, 2108721702UL, 1271286102UL, 3987010398UL, 3996115574UL, 839506039UL, 1315622698UL, 1036957208UL, 2597814974UL, 2328446377UL, 1961600298UL, 3098343478UL, 2395157917UL, 1141381380UL, 3025370440UL, 997698792UL, 1317753106UL, 2727078785UL, 820119215UL, 3586778616UL, 1993126242UL, 2295599934UL, 1171102868UL, +2120026924UL, 65722921UL, 746724958UL, 3999203443UL, 2335086228UL, 1564918930UL, 3710935369UL, 419349792UL, 1662083910UL, 1136716661UL, 770031171UL, 2062767935UL, 3373230309UL, 3271761171UL, 4100328450UL, 3352859025UL, 1262632952UL, 3140021482UL, 3981040854UL, 2579000299UL, 352450195UL, 1002557127UL, 2813224858UL, 1064251076UL, 2642514897UL, 4216846311UL, 1187381982UL, 3131323304UL, 2077640887UL, 3092488663UL, 655242013UL, 1152156402UL, +3658526705UL, 548941006UL, 3280658482UL, 2120064836UL, 3726555752UL, 97387177UL, 4112878213UL, 584864345UL, 3874404446UL, 440995849UL, 1929251266UL, 227230803UL, 823950215UL, 3559119399UL, 3855477390UL, 2439885481UL, 610498128UL, 2297040376UL, 2054191666UL, 2778642234UL, 2267416277UL, 518192832UL, 573807317UL, 1018128176UL, 2841084399UL, 3028189871UL, 2512871059UL, 2747338726UL, 1091467742UL, 2743780329UL, 3566538467UL, 386661563UL, +1715139924UL, 2712119598UL, 3296319359UL, 4187226385UL, 2508754324UL, 3361368810UL, 2284913307UL, 740953233UL, 3351500634UL, 1296305541UL, 4290564545UL, 610062694UL, 3089981426UL, 3469441840UL, 148510865UL, 1010959310UL, 2593994385UL, 548784340UL, 549871569UL, 124676809UL, 1825306744UL, 645229999UL, 1412095765UL, 2814231763UL, 2540745278UL, 3792219969UL, 2198765077UL, 1845119421UL, 4144145546UL, 3966655401UL, 268197516UL, 4144513299UL, +3231318896UL, 3382035479UL, 1674022032UL, 2786831464UL, 4236142563UL, 680649431UL, 3290999942UL, 4065303704UL, 3822069622UL, 3194332974UL, 4102392657UL, 2776797278UL, 3735376922UL, 525501162UL, 2149374605UL, 3736514467UL, 3547689148UL, 2064870756UL, 3219948462UL, 1497045279UL, 2945126332UL, 4285864315UL, 2389978045UL, 2678467476UL, 56752862UL, 864909862UL, 625377571UL, 2308006661UL, 2258093843UL, 925722519UL, 1008109592UL, 2819528345UL, +2927186231UL, 2743241289UL, 1536828870UL, 3225674336UL, 827428943UL, 1583633720UL, 992128922UL, 2186287936UL, 2299756421UL, 776912458UL, 298217241UL, 2108721702UL, 1271286102UL, 3987010398UL, 3996115574UL, 1041730366UL, 1315622698UL, 1036957208UL, 2597814974UL, 2328446377UL, 1386688725UL, 3098343478UL, 2395157917UL, 1141381380UL, 3025370440UL, 2292273773UL, 1317753106UL, 2727078785UL, 820119215UL, 3586778616UL, 206996196UL, 2295599934UL, +1171102868UL, 2120026924UL, 65722921UL, 3271158508UL, 3999203443UL, 2335086228UL, 1564918930UL, 3710935369UL, 3305544914UL, 1662083910UL, 1136716661UL, 770031171UL, 2062767935UL, 4244195826UL, 3271761171UL, 4100328450UL, 3352859025UL, 1262632952UL, 3581040310UL, 3981040854UL, 2579000299UL, 352450195UL, 1002557127UL, 1789606594UL, 1064251076UL, 2642514897UL, 4216846311UL, 1187381982UL, 1519386238UL, 2077640887UL, 3092488663UL, 655242013UL, +1152156402UL, 3732146227UL, 548941006UL, 3280658482UL, 2120064836UL, 3726555752UL, 2631398817UL, 4112878213UL, 584864345UL, 3874404446UL, 440995849UL, 3541162446UL, 227230803UL, 823950215UL, 3559119399UL, 3855477390UL, 560704260UL, 610498128UL, 2297040376UL, 2054191666UL, 2778642234UL, 1614756373UL, 518192832UL, 573807317UL, 1018128176UL, 2841084399UL, 927011949UL, 2512871059UL, 2747338726UL, 1091467742UL, 2743780329UL, 566198434UL, +386661563UL, 1715139924UL, 2712119598UL, 3296319359UL, 520529825UL, 2508754324UL, 3361368810UL, 2284913307UL, 740953233UL, 2414584088UL, 1296305541UL, 4290564545UL, 610062694UL, 3089981426UL, 120496553UL, 148510865UL, 1010959310UL, 2593994385UL, 548784340UL, 3206664898UL, 124676809UL, 1825306744UL, 645229999UL, 1412095765UL, 821445348UL, 2540745278UL, 3792219969UL, 2198765077UL, 1845119421UL, 3434574619UL, 3966655401UL, 268197516UL, +4144513299UL, 3231318896UL, 3856935910UL, 1674022032UL, 2786831464UL, 4236142563UL, 680649431UL, 3331403374UL, 4065303704UL, 3822069622UL, 3194332974UL, 4102392657UL, 2194924932UL, 3735376922UL, 525501162UL, 2149374605UL, 3736514467UL, 2041458481UL, 2064870756UL, 3219948462UL, 1497045279UL, 2945126332UL, 3515890044UL, 2389978045UL, 2678467476UL, 56752862UL, 864909862UL, 1009125580UL, 2308006661UL, 2258093843UL, 925722519UL, 1008109592UL, +4166824654UL, 3399481064UL, 3848337172UL, 841675162UL, 2388734555UL, 3373081217UL, 1627287001UL, 1958651480UL, 1771323855UL, 2126620758UL, 3879967947UL, 1885140905UL, 806066092UL, 2168342987UL, 3778265278UL, 943582962UL, 3895768303UL, 337928214UL, 3677576461UL, 1884088203UL, 2629440785UL, 2357038005UL, 2362450760UL, 2080907681UL, 2644383608UL, 4153875040UL, 794977307UL, 2675637463UL, 2655426076UL, 3481699657UL, 2262369403UL, 1038608931UL, +4210267953UL, 2376694315UL, 2661705117UL, 3994997027UL, 2994346963UL, 4074343171UL, 833108024UL, 3562046155UL, 1113632369UL, 3087093963UL, 2115712884UL, 2778607581UL, 2702162487UL, 1347693590UL, 4271098334UL, 2746712394UL, 1629623802UL, 1932973152UL, 3077074108UL, 1338011180UL, 848785806UL, 1834095770UL, 4017238UL, 2661097500UL, 2935787683UL, 1214195119UL, 3099491937UL, 3868451396UL, 1063740008UL, 2768962809UL, 2554721244UL, 695479209UL, +2634119800UL, 1379839034UL, 2653377927UL, 921934002UL, 3586936843UL, 3035369677UL, 769283110UL, 2417935220UL, 3330084607UL, 2020519519UL, 2546176786UL, 1523223165UL, 3654065096UL, 1835059231UL, 2776263618UL, 3837173427UL, 3236141295UL, 1184415634UL, 157448610UL, 2474336972UL, 3313035876UL, 309195150UL, 2288837115UL, 548743307UL, 528342914UL, 1527562212UL, 554918643UL, 2739291918UL, 2630873849UL, 155419923UL, 226845272UL, 1343735931UL, +3106346884UL, 4177975386UL, 2515480406UL, 2049734808UL, 2802879609UL, 1805234272UL, 317920918UL, 745796250UL, 3816657414UL, 4198378080UL, 3057334192UL, 503016924UL, 2027816790UL, 579332504UL, 3037999504UL, 2857298788UL, 911046668UL, 1170775701UL, 2369720UL, 3364839261UL, 1462383461UL, 181600856UL, 1315241696UL, 2861043792UL, 3549404088UL, 3974245218UL, 4141518566UL, 1195336199UL, 2291064152UL, 3287203016UL, 3867432937UL, 2593766219UL, +2114273192UL, 3716228986UL, 410286941UL, 2497285113UL, 1338500439UL, 3748757692UL, 2315519304UL, 545570554UL, 1519868916UL, 679216320UL, 3264840479UL, 4083041163UL, 261878334UL, 2370312122UL, 1408058272UL, 1287635274UL, 3433241543UL, 3923613754UL, 2423502603UL, 3948993135UL, 1418484161UL, 230113502UL, 1766447938UL, 3101286974UL, 917358979UL, 2836128279UL, 2859079881UL, 3162688352UL, 2158281644UL, 154509481UL, 2409785274UL, 3096379437UL, +}, +{ +2456954827UL, 2895978734UL, 1621803157UL, 230462381UL, 4046364119UL, 716597790UL, 2031510641UL, 2208319977UL, 1107910846UL, 3379950723UL, 3628284249UL, 1393263274UL, 3842378742UL, 768116962UL, 1782906996UL, 3022943801UL, 510040722UL, 2180373447UL, 1294989632UL, 1659724107UL, 953774117UL, 500296619UL, 2269873184UL, 3215368465UL, 3933601613UL, 2401810535UL, 3568992417UL, 617528376UL, 2437412983UL, 2921242388UL, 2311040363UL, 3695847323UL, +1609309841UL, 3222455492UL, 1108155620UL, 397599239UL, 3344183623UL, 1159383441UL, 81554651UL, 4223302962UL, 2812031899UL, 2613176831UL, 2967803832UL, 3560382993UL, 670173062UL, 2361031672UL, 1745444335UL, 2067906079UL, 3019908371UL, 2662226130UL, 2962440272UL, 3053411095UL, 92212044UL, 1041941495UL, 4116546365UL, 2094375399UL, 3992554702UL, 216246182UL, 2271736480UL, 1006434362UL, 4104644208UL, 2543874803UL, 1310440964UL, 1956002873UL, +1485192936UL, 3027546418UL, 448786402UL, 749040342UL, 406538664UL, 2522826782UL, 3681979470UL, 3941253886UL, 672615054UL, 3655479714UL, 392178376UL, 1619518340UL, 1639889010UL, 666186812UL, 4094569743UL, 2947917117UL, 3308938954UL, 1572886498UL, 1065510431UL, 2158389109UL, 1583642689UL, 1763046973UL, 3578310229UL, 4106948216UL, 58659757UL, 691952777UL, 3394715763UL, 3333944006UL, 3020203798UL, 3598064251UL, 3151881711UL, 2071056894UL, +1263790655UL, 4188233031UL, 4230429856UL, 3088041549UL, 3031631424UL, 3912597408UL, 1768734847UL, 1975027092UL, 3976493733UL, 2376551740UL, 1137628506UL, 535767974UL, 3105256806UL, 15427398UL, 2472341690UL, 685997424UL, 1374644561UL, 2446214061UL, 2844847931UL, 1058649390UL, 1581230869UL, 1725846082UL, 3062699842UL, 1116400547UL, 1095426642UL, 2940190462UL, 4276038488UL, 2091764667UL, 4074059985UL, 98163536UL, 4157153745UL, 32476821UL, +2354284775UL, 752663757UL, 2987293678UL, 1119786914UL, 3019442904UL, 111185876UL, 3569592548UL, 3991775183UL, 3161418733UL, 3973354577UL, 1650454973UL, 426129509UL, 3659038742UL, 1387393667UL, 543731583UL, 781586523UL, 917315276UL, 832142534UL, 3911092159UL, 325250500UL, 2735441676UL, 163564958UL, 1002098855UL, 337936437UL, 1869530240UL, 2233969733UL, 4108076124UL, 3255026725UL, 4072134049UL, 2083771067UL, 1559589006UL, 1845121907UL, +466036013UL, 2456954827UL, 2895978734UL, 1621803157UL, 230462381UL, 2022150409UL, 716597790UL, 2031510641UL, 2208319977UL, 1107910846UL, 1838834877UL, 3628284249UL, 1393263274UL, 3842378742UL, 768116962UL, 2303040715UL, 3022943801UL, 510040722UL, 2180373447UL, 1294989632UL, 3074858415UL, 953774117UL, 500296619UL, 2269873184UL, 3215368465UL, 3531413908UL, 2401810535UL, 3568992417UL, 617528376UL, 2437412983UL, 1730632320UL, 2311040363UL, +3695847323UL, 1609309841UL, 3222455492UL, 3189359980UL, 397599239UL, 3344183623UL, 1159383441UL, 81554651UL, 1933731121UL, 2812031899UL, 2613176831UL, 2967803832UL, 3560382993UL, 758113139UL, 2361031672UL, 1745444335UL, 2067906079UL, 3019908371UL, 3537991495UL, 2962440272UL, 3053411095UL, 92212044UL, 1041941495UL, 2653519981UL, 2094375399UL, 3992554702UL, 216246182UL, 2271736480UL, 695350220UL, 4104644208UL, 2543874803UL, 1310440964UL, +1956002873UL, 3373048130UL, 3027546418UL, 448786402UL, 749040342UL, 406538664UL, 4081844472UL, 3681979470UL, 3941253886UL, 672615054UL, 3655479714UL, 197563239UL, 1619518340UL, 1639889010UL, 666186812UL, 4094569743UL, 2518320719UL, 3308938954UL, 1572886498UL, 1065510431UL, 2158389109UL, 3320483696UL, 1763046973UL, 3578310229UL, 4106948216UL, 58659757UL, 3412172826UL, 3394715763UL, 3333944006UL, 3020203798UL, 3598064251UL, 1693717788UL, +2071056894UL, 1263790655UL, 4188233031UL, 4230429856UL, 2564478937UL, 3031631424UL, 3912597408UL, 1768734847UL, 1975027092UL, 3546175061UL, 2376551740UL, 1137628506UL, 535767974UL, 3105256806UL, 450760279UL, 2472341690UL, 685997424UL, 1374644561UL, 2446214061UL, 1873063065UL, 1058649390UL, 1581230869UL, 1725846082UL, 3062699842UL, 813496775UL, 1095426642UL, 2940190462UL, 4276038488UL, 2091764667UL, 3857233976UL, 98163536UL, 4157153745UL, +32476821UL, 2354284775UL, 3115605568UL, 2987293678UL, 1119786914UL, 3019442904UL, 111185876UL, 996447434UL, 3991775183UL, 3161418733UL, 3973354577UL, 1650454973UL, 1089784804UL, 3659038742UL, 1387393667UL, 543731583UL, 781586523UL, 2711412312UL, 832142534UL, 3911092159UL, 325250500UL, 2735441676UL, 3563501139UL, 1002098855UL, 337936437UL, 1869530240UL, 2233969733UL, 1156926454UL, 3255026725UL, 4072134049UL, 2083771067UL, 1559589006UL, +3832870112UL, 466036013UL, 2456954827UL, 2895978734UL, 1621803157UL, 2340808859UL, 2022150409UL, 716597790UL, 2031510641UL, 2208319977UL, 1823993818UL, 1838834877UL, 3628284249UL, 1393263274UL, 3842378742UL, 2489609764UL, 2303040715UL, 3022943801UL, 510040722UL, 2180373447UL, 4204167795UL, 3074858415UL, 953774117UL, 500296619UL, 2269873184UL, 2320314628UL, 3531413908UL, 2401810535UL, 3568992417UL, 617528376UL, 712451843UL, 1730632320UL, +2311040363UL, 3695847323UL, 1609309841UL, 3224192365UL, 3189359980UL, 397599239UL, 3344183623UL, 1159383441UL, 758272390UL, 1933731121UL, 2812031899UL, 2613176831UL, 2967803832UL, 3986798661UL, 758113139UL, 2361031672UL, 1745444335UL, 2067906079UL, 3814344052UL, 3537991495UL, 2962440272UL, 3053411095UL, 92212044UL, 817573506UL, 2653519981UL, 2094375399UL, 3992554702UL, 216246182UL, 2456924809UL, 695350220UL, 4104644208UL, 2543874803UL, +1310440964UL, 1151286621UL, 3373048130UL, 3027546418UL, 448786402UL, 749040342UL, 637572176UL, 4081844472UL, 3681979470UL, 3941253886UL, 672615054UL, 3038758846UL, 197563239UL, 1619518340UL, 1639889010UL, 666186812UL, 4254608071UL, 2518320719UL, 3308938954UL, 1572886498UL, 1065510431UL, 3100620860UL, 3320483696UL, 1763046973UL, 3578310229UL, 4106948216UL, 403923766UL, 3412172826UL, 3394715763UL, 3333944006UL, 3020203798UL, 1859724785UL, +1693717788UL, 2071056894UL, 1263790655UL, 4188233031UL, 2908736862UL, 2564478937UL, 3031631424UL, 3912597408UL, 1768734847UL, 966714666UL, 3546175061UL, 2376551740UL, 1137628506UL, 535767974UL, 1561255376UL, 450760279UL, 2472341690UL, 685997424UL, 1374644561UL, 3122124160UL, 1873063065UL, 1058649390UL, 1581230869UL, 1725846082UL, 3791666219UL, 813496775UL, 1095426642UL, 2940190462UL, 4276038488UL, 2802023399UL, 3857233976UL, 98163536UL, +4157153745UL, 32476821UL, 1640659450UL, 3115605568UL, 2987293678UL, 1119786914UL, 3019442904UL, 4278091706UL, 996447434UL, 3991775183UL, 3161418733UL, 3973354577UL, 3398421232UL, 1089784804UL, 3659038742UL, 1387393667UL, 543731583UL, 1694361696UL, 2711412312UL, 832142534UL, 3911092159UL, 325250500UL, 166035542UL, 3563501139UL, 1002098855UL, 337936437UL, 1869530240UL, 1306446339UL, 1156926454UL, 3255026725UL, 4072134049UL, 2083771067UL, +61899937UL, 3832870112UL, 466036013UL, 2456954827UL, 2895978734UL, 767569205UL, 2340808859UL, 2022150409UL, 716597790UL, 2031510641UL, 1690074863UL, 1823993818UL, 1838834877UL, 3628284249UL, 1393263274UL, 546011580UL, 2489609764UL, 2303040715UL, 3022943801UL, 510040722UL, 825252468UL, 4204167795UL, 3074858415UL, 953774117UL, 500296619UL, 1952242515UL, 2320314628UL, 3531413908UL, 2401810535UL, 3568992417UL, 4254767597UL, 712451843UL, +1730632320UL, 2311040363UL, 3695847323UL, 2393864919UL, 3224192365UL, 3189359980UL, 397599239UL, 3344183623UL, 1759399025UL, 758272390UL, 1933731121UL, 2812031899UL, 2613176831UL, 2809078783UL, 3986798661UL, 758113139UL, 2361031672UL, 1745444335UL, 1223235915UL, 3814344052UL, 3537991495UL, 2962440272UL, 3053411095UL, 3711100000UL, 817573506UL, 2653519981UL, 2094375399UL, 3992554702UL, 2987412942UL, 2456924809UL, 695350220UL, 4104644208UL, +2543874803UL, 2746231792UL, 1151286621UL, 3373048130UL, 3027546418UL, 448786402UL, 801157439UL, 637572176UL, 4081844472UL, 3681979470UL, 3941253886UL, 975875511UL, 3038758846UL, 197563239UL, 1619518340UL, 1639889010UL, 3137491209UL, 4254608071UL, 2518320719UL, 3308938954UL, 1572886498UL, 631178204UL, 3100620860UL, 3320483696UL, 1763046973UL, 3578310229UL, 3338308117UL, 403923766UL, 3412172826UL, 3394715763UL, 3333944006UL, 37220448UL, +1859724785UL, 1693717788UL, 2071056894UL, 1263790655UL, 228419012UL, 2908736862UL, 2564478937UL, 3031631424UL, 3912597408UL, 3862306448UL, 966714666UL, 3546175061UL, 2376551740UL, 1137628506UL, 1114919961UL, 1561255376UL, 450760279UL, 2472341690UL, 685997424UL, 2456661198UL, 3122124160UL, 1873063065UL, 1058649390UL, 1581230869UL, 2996925693UL, 3791666219UL, 813496775UL, 1095426642UL, 2940190462UL, 1642720015UL, 2802023399UL, 3857233976UL, +98163536UL, 4157153745UL, 1578965959UL, 1640659450UL, 3115605568UL, 2987293678UL, 1119786914UL, 1748408698UL, 4278091706UL, 996447434UL, 3991775183UL, 3161418733UL, 4123935663UL, 3398421232UL, 1089784804UL, 3659038742UL, 1387393667UL, 770706529UL, 1694361696UL, 2711412312UL, 832142534UL, 3911092159UL, 335435644UL, 166035542UL, 3563501139UL, 1002098855UL, 337936437UL, 2961857543UL, 1306446339UL, 1156926454UL, 3255026725UL, 4072134049UL, +1717290230UL, 1323146393UL, 2156340433UL, 2065716367UL, 2597996276UL, 3402032152UL, 779574284UL, 2369501052UL, 2316224856UL, 2720986136UL, 3016786025UL, 2916554213UL, 3476215746UL, 1132150235UL, 2619889920UL, 1279664685UL, 679206534UL, 4014394509UL, 3624968312UL, 1480455625UL, 725015758UL, 707677352UL, 3764409715UL, 1938306480UL, 2171474419UL, 3379664161UL, 684262379UL, 2142433069UL, 43407198UL, 1398850259UL, 2059135843UL, 240266749UL, +3788738212UL, 118513026UL, 820245055UL, 1152812311UL, 1398373423UL, 3188977726UL, 872620936UL, 2084649448UL, 807979538UL, 819501992UL, 615447916UL, 3393148006UL, 1765623964UL, 2514767257UL, 3711360450UL, 2941886951UL, 3739102698UL, 4022385962UL, 2306039667UL, 3321267290UL, 2179238310UL, 3192652502UL, 2118792870UL, 2571142127UL, 761776508UL, 873010906UL, 1609627751UL, 4260021041UL, 1747852747UL, 960771906UL, 2647903291UL, 77475681UL, +1282566533UL, 4022186916UL, 2681128032UL, 1554542462UL, 3181701944UL, 1168469070UL, 74236514UL, 2806532232UL, 3981048887UL, 1888842784UL, 2888607878UL, 1763028723UL, 701886756UL, 4124077776UL, 3738147505UL, 4066663138UL, 3816449863UL, 921061872UL, 2956972182UL, 3159072916UL, 3337110888UL, 3552795700UL, 2281281091UL, 671098116UL, 1282750020UL, 1008618197UL, 2363767765UL, 1812013295UL, 1854965999UL, 131027176UL, 666394000UL, 2062217824UL, +1763334218UL, 551118598UL, 1277961175UL, 3523893635UL, 1855881150UL, 2067903393UL, 2590963277UL, 3214508854UL, 1604911832UL, 1906690475UL, 389417851UL, 2711591984UL, 427723436UL, 1039703630UL, 639602991UL, 444779318UL, 2722002973UL, 3927985419UL, 1297446054UL, 298277450UL, 656022205UL, 134304205UL, 3847728042UL, 3339100423UL, 407022043UL, 1282443442UL, 3173884578UL, 1417906094UL, 2364502739UL, 2158353472UL, 2402775649UL, 1807696073UL, +2837535198UL, 705887737UL, 2129202688UL, 3853676283UL, 1388329793UL, 875153687UL, 2367465660UL, 2763058233UL, 2500632304UL, 2196920062UL, 491306883UL, 277753357UL, 3868415380UL, 324867643UL, 3654474955UL, 2569410351UL, 1128175417UL, 1853572398UL, 1133201743UL, 662085935UL, 2263514999UL, 3077768113UL, 3309730620UL, 3602394176UL, 3747458070UL, 188422725UL, 813812450UL, 1502276531UL, 3909138356UL, 2766044599UL, 3760928321UL, 573108836UL, +}, +{ +1240264181UL, 1624064648UL, 3039823158UL, 2013985253UL, 1473300299UL, 2762062141UL, 3273470484UL, 1889745445UL, 2516996174UL, 3190376531UL, 996186898UL, 3893981177UL, 1268272590UL, 3226095713UL, 153038465UL, 2184871198UL, 3224094011UL, 2526518401UL, 1738960059UL, 1187560605UL, 4194384320UL, 2837011297UL, 3638232350UL, 367907454UL, 574009898UL, 1948901330UL, 60430044UL, 1569835584UL, 3160561697UL, 321792583UL, 3179087993UL, 1936928378UL, +412346905UL, 4020812489UL, 2603392174UL, 3499496781UL, 1499441233UL, 1062415256UL, 1347130973UL, 1823246794UL, 3411391800UL, 4253618056UL, 1507733072UL, 1605629518UL, 1503312494UL, 8035741UL, 4038904206UL, 2408545792UL, 969543501UL, 954847087UL, 956553276UL, 3096241999UL, 2566194741UL, 84678421UL, 3882676079UL, 2483934330UL, 3673546814UL, 2461422466UL, 620385599UL, 898325340UL, 2145883445UL, 3653728520UL, 3744850294UL, 2441124935UL, +904854507UL, 3216304963UL, 2373268568UL, 2354362010UL, 1245572787UL, 2894748714UL, 2889136188UL, 3716879184UL, 1766013949UL, 1305712667UL, 1227530310UL, 4051221847UL, 925440190UL, 1508686692UL, 1104647879UL, 1496666754UL, 3300504219UL, 127787091UL, 1528394637UL, 1739640835UL, 2475711496UL, 3792639955UL, 1450796299UL, 1634217367UL, 3289785095UL, 2149949989UL, 811612039UL, 1750779366UL, 1157474938UL, 514004414UL, 2264909096UL, 3730411668UL, +3308882513UL, 1834571716UL, 378288317UL, 3800023701UL, 763396788UL, 1597708317UL, 983953861UL, 94566098UL, 1548157668UL, 3755427117UL, 1646496505UL, 3748241449UL, 3439805936UL, 2321644449UL, 3805706235UL, 4220083901UL, 1069923823UL, 2984004391UL, 3824885361UL, 1967477766UL, 218978249UL, 348955028UL, 3188651823UL, 1008338679UL, 2331688720UL, 1562995454UL, 1837179689UL, 3033872688UL, 3007293665UL, 1759522678UL, 319754369UL, 2763991927UL, +1983149629UL, 1353197132UL, 1489552694UL, 2990539062UL, 3244609108UL, 669775440UL, 886127995UL, 1636688014UL, 1251222487UL, 2351883247UL, 3261502906UL, 3139614137UL, 3203790139UL, 2777648095UL, 3693390579UL, 3540514982UL, 3200191735UL, 750726325UL, 1014534145UL, 2091792357UL, 3931704474UL, 1383925867UL, 2038878506UL, 2247134268UL, 2840132188UL, 61137652UL, 1162051299UL, 399657268UL, 1682018695UL, 2640231287UL, 1733438115UL, 3611823506UL, +2077891037UL, 1240264181UL, 1624064648UL, 3039823158UL, 2013985253UL, 4188888201UL, 2762062141UL, 3273470484UL, 1889745445UL, 2516996174UL, 2621448256UL, 996186898UL, 3893981177UL, 1268272590UL, 3226095713UL, 952803645UL, 2184871198UL, 3224094011UL, 2526518401UL, 1738960059UL, 738368399UL, 4194384320UL, 2837011297UL, 3638232350UL, 367907454UL, 3772812520UL, 1948901330UL, 60430044UL, 1569835584UL, 3160561697UL, 1655622513UL, 3179087993UL, +1936928378UL, 412346905UL, 4020812489UL, 3754224996UL, 3499496781UL, 1499441233UL, 1062415256UL, 1347130973UL, 1167581269UL, 3411391800UL, 4253618056UL, 1507733072UL, 1605629518UL, 1867781671UL, 8035741UL, 4038904206UL, 2408545792UL, 969543501UL, 3189323143UL, 956553276UL, 3096241999UL, 2566194741UL, 84678421UL, 996778900UL, 2483934330UL, 3673546814UL, 2461422466UL, 620385599UL, 3129088144UL, 2145883445UL, 3653728520UL, 3744850294UL, +2441124935UL, 4230756652UL, 3216304963UL, 2373268568UL, 2354362010UL, 1245572787UL, 1600525238UL, 2889136188UL, 3716879184UL, 1766013949UL, 1305712667UL, 59908073UL, 4051221847UL, 925440190UL, 1508686692UL, 1104647879UL, 2931214731UL, 3300504219UL, 127787091UL, 1528394637UL, 1739640835UL, 62963469UL, 3792639955UL, 1450796299UL, 1634217367UL, 3289785095UL, 667987389UL, 811612039UL, 1750779366UL, 1157474938UL, 514004414UL, 2737193098UL, +3730411668UL, 3308882513UL, 1834571716UL, 378288317UL, 3452657469UL, 763396788UL, 1597708317UL, 983953861UL, 94566098UL, 2752347916UL, 3755427117UL, 1646496505UL, 3748241449UL, 3439805936UL, 4222757079UL, 3805706235UL, 4220083901UL, 1069923823UL, 2984004391UL, 3887639520UL, 1967477766UL, 218978249UL, 348955028UL, 3188651823UL, 4168456281UL, 2331688720UL, 1562995454UL, 1837179689UL, 3033872688UL, 814903833UL, 1759522678UL, 319754369UL, +2763991927UL, 1983149629UL, 3818528075UL, 1489552694UL, 2990539062UL, 3244609108UL, 669775440UL, 1004789460UL, 1636688014UL, 1251222487UL, 2351883247UL, 3261502906UL, 4143823654UL, 3203790139UL, 2777648095UL, 3693390579UL, 3540514982UL, 153421222UL, 750726325UL, 1014534145UL, 2091792357UL, 3931704474UL, 4018591985UL, 2038878506UL, 2247134268UL, 2840132188UL, 61137652UL, 1455028838UL, 399657268UL, 1682018695UL, 2640231287UL, 1733438115UL, +1853142849UL, 2077891037UL, 1240264181UL, 1624064648UL, 3039823158UL, 2235369076UL, 4188888201UL, 2762062141UL, 3273470484UL, 1889745445UL, 3627876603UL, 2621448256UL, 996186898UL, 3893981177UL, 1268272590UL, 2687846008UL, 952803645UL, 2184871198UL, 3224094011UL, 2526518401UL, 861379413UL, 738368399UL, 4194384320UL, 2837011297UL, 3638232350UL, 3753321702UL, 3772812520UL, 1948901330UL, 60430044UL, 1569835584UL, 581506474UL, 1655622513UL, +3179087993UL, 1936928378UL, 412346905UL, 2710043900UL, 3754224996UL, 3499496781UL, 1499441233UL, 1062415256UL, 2704745463UL, 1167581269UL, 3411391800UL, 4253618056UL, 1507733072UL, 4215403465UL, 1867781671UL, 8035741UL, 4038904206UL, 2408545792UL, 3252742933UL, 3189323143UL, 956553276UL, 3096241999UL, 2566194741UL, 1865159158UL, 996778900UL, 2483934330UL, 3673546814UL, 2461422466UL, 3123557619UL, 3129088144UL, 2145883445UL, 3653728520UL, +3744850294UL, 21840044UL, 4230756652UL, 3216304963UL, 2373268568UL, 2354362010UL, 1934462999UL, 1600525238UL, 2889136188UL, 3716879184UL, 1766013949UL, 2822794708UL, 59908073UL, 4051221847UL, 925440190UL, 1508686692UL, 2938291976UL, 2931214731UL, 3300504219UL, 127787091UL, 1528394637UL, 1914923136UL, 62963469UL, 3792639955UL, 1450796299UL, 1634217367UL, 257322213UL, 667987389UL, 811612039UL, 1750779366UL, 1157474938UL, 3083649350UL, +2737193098UL, 3730411668UL, 3308882513UL, 1834571716UL, 2778729422UL, 3452657469UL, 763396788UL, 1597708317UL, 983953861UL, 1337754195UL, 2752347916UL, 3755427117UL, 1646496505UL, 3748241449UL, 3942745717UL, 4222757079UL, 3805706235UL, 4220083901UL, 1069923823UL, 1314928500UL, 3887639520UL, 1967477766UL, 218978249UL, 348955028UL, 3425797638UL, 4168456281UL, 2331688720UL, 1562995454UL, 1837179689UL, 1814071277UL, 814903833UL, 1759522678UL, +319754369UL, 2763991927UL, 1079270448UL, 3818528075UL, 1489552694UL, 2990539062UL, 3244609108UL, 2944573315UL, 1004789460UL, 1636688014UL, 1251222487UL, 2351883247UL, 1356892540UL, 4143823654UL, 3203790139UL, 2777648095UL, 3693390579UL, 983917956UL, 153421222UL, 750726325UL, 1014534145UL, 2091792357UL, 296882400UL, 4018591985UL, 2038878506UL, 2247134268UL, 2840132188UL, 3508266160UL, 1455028838UL, 399657268UL, 1682018695UL, 2640231287UL, +2480988791UL, 1853142849UL, 2077891037UL, 1240264181UL, 1624064648UL, 1741738969UL, 2235369076UL, 4188888201UL, 2762062141UL, 3273470484UL, 3569498651UL, 3627876603UL, 2621448256UL, 996186898UL, 3893981177UL, 4026533880UL, 2687846008UL, 952803645UL, 2184871198UL, 3224094011UL, 1290870737UL, 861379413UL, 738368399UL, 4194384320UL, 2837011297UL, 3833099205UL, 3753321702UL, 3772812520UL, 1948901330UL, 60430044UL, 4131290878UL, 581506474UL, +1655622513UL, 3179087993UL, 1936928378UL, 2379952582UL, 2710043900UL, 3754224996UL, 3499496781UL, 1499441233UL, 593780490UL, 2704745463UL, 1167581269UL, 3411391800UL, 4253618056UL, 621889762UL, 4215403465UL, 1867781671UL, 8035741UL, 4038904206UL, 2045289976UL, 3252742933UL, 3189323143UL, 956553276UL, 3096241999UL, 2188329018UL, 1865159158UL, 996778900UL, 2483934330UL, 3673546814UL, 2717648418UL, 3123557619UL, 3129088144UL, 2145883445UL, +3653728520UL, 1528077261UL, 21840044UL, 4230756652UL, 3216304963UL, 2373268568UL, 803158556UL, 1934462999UL, 1600525238UL, 2889136188UL, 3716879184UL, 161827512UL, 2822794708UL, 59908073UL, 4051221847UL, 925440190UL, 3599942370UL, 2938291976UL, 2931214731UL, 3300504219UL, 127787091UL, 4082579845UL, 1914923136UL, 62963469UL, 3792639955UL, 1450796299UL, 2035446714UL, 257322213UL, 667987389UL, 811612039UL, 1750779366UL, 2344204796UL, +3083649350UL, 2737193098UL, 3730411668UL, 3308882513UL, 2765191583UL, 2778729422UL, 3452657469UL, 763396788UL, 1597708317UL, 1854746879UL, 1337754195UL, 2752347916UL, 3755427117UL, 1646496505UL, 4020292301UL, 3942745717UL, 4222757079UL, 3805706235UL, 4220083901UL, 1408262601UL, 1314928500UL, 3887639520UL, 1967477766UL, 218978249UL, 2173193841UL, 3425797638UL, 4168456281UL, 2331688720UL, 1562995454UL, 2835294077UL, 1814071277UL, 814903833UL, +1759522678UL, 319754369UL, 4048528178UL, 1079270448UL, 3818528075UL, 1489552694UL, 2990539062UL, 787253600UL, 2944573315UL, 1004789460UL, 1636688014UL, 1251222487UL, 3584515216UL, 1356892540UL, 4143823654UL, 3203790139UL, 2777648095UL, 1681621541UL, 983917956UL, 153421222UL, 750726325UL, 1014534145UL, 3951869055UL, 296882400UL, 4018591985UL, 2038878506UL, 2247134268UL, 1990726826UL, 3508266160UL, 1455028838UL, 399657268UL, 1682018695UL, +3360119279UL, 3151120565UL, 3011208718UL, 3694535943UL, 104562665UL, 2827623271UL, 249712003UL, 3413221355UL, 2347164236UL, 3227498378UL, 1805068659UL, 2118219686UL, 1568133029UL, 902801951UL, 175637375UL, 3812819970UL, 2162769758UL, 3845613089UL, 1795179477UL, 171494391UL, 3765826349UL, 1725798906UL, 345463508UL, 2481043227UL, 226569380UL, 3250095421UL, 1085199388UL, 3107594542UL, 4011388155UL, 1092611190UL, 3239339214UL, 4211849464UL, +4109911546UL, 81212018UL, 3691937144UL, 2477407396UL, 3320520455UL, 3070067913UL, 3808621884UL, 252917069UL, 3394860294UL, 1092442235UL, 2876536384UL, 1684120191UL, 431096075UL, 1701716708UL, 639881684UL, 3066183997UL, 3660504927UL, 2047274UL, 3424756424UL, 760932520UL, 2457976057UL, 1705265011UL, 2691137533UL, 3684307557UL, 3532744498UL, 2319162513UL, 1015534908UL, 1907173398UL, 2820698743UL, 1264455116UL, 2323788906UL, 3062240844UL, +1878550513UL, 1717353426UL, 1805673248UL, 62425157UL, 3662381032UL, 1964107209UL, 2559831960UL, 2117844804UL, 1228721677UL, 4240498866UL, 3212920337UL, 2338600301UL, 931588693UL, 2379606585UL, 3643222352UL, 4154645082UL, 1115847065UL, 2079427925UL, 2256943798UL, 2795103368UL, 2688136486UL, 1458062143UL, 1767222217UL, 635424385UL, 284062050UL, 1547163554UL, 3380046528UL, 1145758046UL, 3935976713UL, 4017430175UL, 3863367362UL, 3041367424UL, +303263160UL, 1465965696UL, 3757919837UL, 3083072836UL, 4024514094UL, 1381331179UL, 2393446325UL, 3256476469UL, 4066482738UL, 3437941107UL, 1051266504UL, 921764078UL, 2933305619UL, 1358097211UL, 4100978724UL, 2709958834UL, 574590507UL, 961767386UL, 21100886UL, 753746372UL, 4072632446UL, 733729367UL, 3060214669UL, 289165105UL, 426065754UL, 2036100240UL, 2172365757UL, 502856627UL, 84490194UL, 2630806596UL, 1206161269UL, 1009438449UL, +569581317UL, 1836947000UL, 3125379675UL, 1756936428UL, 3772694822UL, 3670337911UL, 3020603818UL, 2376224883UL, 2539951453UL, 2053395002UL, 3525193914UL, 1991480838UL, 3786481083UL, 873873707UL, 1693894743UL, 2450223985UL, 754878026UL, 1943356492UL, 401524329UL, 759931885UL, 611231307UL, 147950334UL, 599693701UL, 3358729722UL, 3649058074UL, 906423787UL, 1333804225UL, 875187278UL, 1115838692UL, 2476325972UL, 3307226674UL, 3539078918UL, +}, + +}; +#endif + +#ifdef CURAND_XORWOW_PRECALCULATED_DEVICE_QUALIFIERS +#undef CURAND_XORWOW_PRECALCULATED_DEVICE_QUALIFIERS +#endif + +#ifdef CURAND_XORWOW_PRECALCULATED_HOST_QUALIFIERS +#undef CURAND_XORWOW_PRECALCULATED_HOST_QUALIFIERS +#endif + +#endif // CURAND_XORWOW_PRECALCULATED_H_ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_uniform.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_uniform.h new file mode 100644 index 0000000000000000000000000000000000000000..7a4af8afa328c186d9ea33a8c8226e19aba4793e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/include/curand_uniform.h @@ -0,0 +1,498 @@ + + /* Copyright 2010-2018 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO LICENSEE: + * + * The source code and/or documentation ("Licensed Deliverables") are + * subject to NVIDIA intellectual property rights under U.S. and + * international Copyright laws. + * + * The Licensed Deliverables contained herein are PROPRIETARY and + * CONFIDENTIAL to NVIDIA and are being provided under the terms and + * conditions of a form of NVIDIA software license agreement by and + * between NVIDIA and Licensee ("License Agreement") or electronically + * accepted by Licensee. Notwithstanding any terms or conditions to + * the contrary in the License Agreement, reproduction or disclosure + * of the Licensed Deliverables to any third party without the express + * written consent of NVIDIA is prohibited. + * + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE + * SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. THEY ARE + * PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + * NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED + * DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, + * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE + * LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY + * SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THESE LICENSED DELIVERABLES. + * + * U.S. Government End Users. These Licensed Deliverables are a + * "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT + * 1995), consisting of "commercial computer software" and "commercial + * computer software documentation" as such terms are used in 48 + * C.F.R. 12.212 (SEPT 1995) and are provided to the U.S. Government + * only as a commercial end item. Consistent with 48 C.F.R.12.212 and + * 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all + * U.S. Government End Users acquire the Licensed Deliverables with + * only those rights set forth herein. + * + * Any use of the Licensed Deliverables in individual and commercial + * software must include, in the user documentation and internal + * comments to the code, the above Disclaimer and U.S. Government End + * Users Notice. + */ + + +#if !defined(CURAND_UNIFORM_H_) +#define CURAND_UNIFORM_H_ + +/** + * \defgroup DEVICE Device API + * + * @{ + */ + +#ifndef __CUDACC_RTC__ +#include +#endif // __CUDACC_RTC__ + +#include "curand_mrg32k3a.h" +#include "curand_mtgp32_kernel.h" +#include "curand_philox4x32_x.h" + + +QUALIFIERS float _curand_uniform(unsigned int x) +{ + return x * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); +} + +QUALIFIERS float4 _curand_uniform4(uint4 x) +{ + float4 y; + y.x = x.x * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); + y.y = x.y * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); + y.z = x.z * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); + y.w = x.w * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); + return y; +} + +QUALIFIERS float _curand_uniform(unsigned long long x) +{ + unsigned int t; + t = (unsigned int)(x >> 32); + return t * CURAND_2POW32_INV + (CURAND_2POW32_INV/2.0f); +} + +QUALIFIERS double _curand_uniform_double(unsigned int x) +{ + return x * CURAND_2POW32_INV_DOUBLE + CURAND_2POW32_INV_DOUBLE; +} + +QUALIFIERS double _curand_uniform_double(unsigned long long x) +{ + return (x >> 11) * CURAND_2POW53_INV_DOUBLE + (CURAND_2POW53_INV_DOUBLE/2.0); +} + +QUALIFIERS double _curand_uniform_double_hq(unsigned int x, unsigned int y) +{ + unsigned long long z = (unsigned long long)x ^ + ((unsigned long long)y << (53 - 32)); + return z * CURAND_2POW53_INV_DOUBLE + (CURAND_2POW53_INV_DOUBLE/2.0); +} + +QUALIFIERS float curand_uniform(curandStateTest_t *state) +{ + return _curand_uniform(curand(state)); +} + +QUALIFIERS double curand_uniform_double(curandStateTest_t *state) +{ + return _curand_uniform_double(curand(state)); +} + +/** + * \brief Return a uniformly distributed float from an XORWOW generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the XORWOW generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * The implementation may use any number of calls to \p curand() to + * get enough random bits to create the return value. The current + * implementation uses one call. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_uniform(curandStateXORWOW_t *state) +{ + return _curand_uniform(curand(state)); +} + +/** + * \brief Return a uniformly distributed double from an XORWOW generator. + * + * Return a uniformly distributed double between \p 0.0 and \p 1.0 + * from the XORWOW generator in \p state, increment position of generator. + * Output range excludes \p 0.0 but includes \p 1.0. Denormalized floating + * point outputs are never returned. + * + * The implementation may use any number of calls to \p curand() to + * get enough random bits to create the return value. The current + * implementation uses exactly two calls. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed double between \p 0.0 and \p 1.0 + */ +QUALIFIERS double curand_uniform_double(curandStateXORWOW_t *state) +{ + unsigned int x, y; + x = curand(state); + y = curand(state); + return _curand_uniform_double_hq(x, y); +} +/** + * \brief Return a uniformly distributed float from an MRG32k3a generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the MRG32k3a generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * The implementation returns up to 23 bits of mantissa, with the minimum + * return value \f$ 2^{-32} \f$ + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_uniform(curandStateMRG32k3a_t *state) +{ + return ((float)(curand_MRG32k3a(state)*MRG32K3A_NORM)); +} + +/** + * \brief Return a uniformly distributed double from an MRG32k3a generator. + * + * Return a uniformly distributed double between \p 0.0 and \p 1.0 + * from the MRG32k3a generator in \p state, increment position of generator. + * Output range excludes \p 0.0 but includes \p 1.0. Denormalized floating + * point outputs are never returned. + * + * Note the implementation returns at most 32 random bits of mantissa as + * outlined in the seminal paper by L'Ecuyer. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed double between \p 0.0 and \p 1.0 + */ +QUALIFIERS double curand_uniform_double(curandStateMRG32k3a_t *state) +{ + return curand_MRG32k3a(state)*MRG32K3A_NORM; +} + + + +/** + * \brief Return a uniformly distributed tuple of 2 doubles from an Philox4_32_10 generator. + * + * Return a uniformly distributed 2 doubles (double4) between \p 0.0 and \p 1.0 + * from the Philox4_32_10 generator in \p state, increment position of generator by 4. + * Output range excludes \p 0.0 but includes \p 1.0. Denormalized floating + * point outputs are never returned. + * + * \param state - Pointer to state to update + * + * \return 2 uniformly distributed doubles between \p 0.0 and \p 1.0 + */ + +QUALIFIERS double2 curand_uniform2_double(curandStatePhilox4_32_10_t *state) +{ + uint4 _x; + double2 result; + _x = curand4(state); + result.x = _curand_uniform_double_hq(_x.x,_x.y); + result.y = _curand_uniform_double_hq(_x.z,_x.w); + return result; +} + + +// not a part of API +QUALIFIERS double4 curand_uniform4_double(curandStatePhilox4_32_10_t *state) +{ + uint4 _x, _y; + double4 result; + _x = curand4(state); + _y = curand4(state); + result.x = _curand_uniform_double_hq(_x.x,_x.y); + result.y = _curand_uniform_double_hq(_x.z,_x.w); + result.z = _curand_uniform_double_hq(_y.x,_y.y); + result.w = _curand_uniform_double_hq(_y.z,_y.w); + return result; +} + +/** + * \brief Return a uniformly distributed float from a Philox4_32_10 generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the Philox4_32_10 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0 and \p 1.0 + * + */ +QUALIFIERS float curand_uniform(curandStatePhilox4_32_10_t *state) +{ + return _curand_uniform(curand(state)); +} + +/** + * \brief Return a uniformly distributed tuple of 4 floats from a Philox4_32_10 generator. + * + * Return a uniformly distributed 4 floats between \p 0.0f and \p 1.0f + * from the Philox4_32_10 generator in \p state, increment position of generator by 4. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0 and \p 1.0 + * + */ +QUALIFIERS float4 curand_uniform4(curandStatePhilox4_32_10_t *state) +{ + return _curand_uniform4(curand4(state)); +} + +/** + * \brief Return a uniformly distributed float from a MTGP32 generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the MTGP32 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_uniform(curandStateMtgp32_t *state) +{ + return _curand_uniform(curand(state)); +} +/** + * \brief Return a uniformly distributed double from a MTGP32 generator. + * + * Return a uniformly distributed double between \p 0.0f and \p 1.0f + * from the MTGP32 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * Note that the implementation uses only 32 random bits to generate a single double + * precision value. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed double between \p 0.0f and \p 1.0f + */ +QUALIFIERS double curand_uniform_double(curandStateMtgp32_t *state) +{ + return _curand_uniform_double(curand(state)); +} + +/** + * \brief Return a uniformly distributed double from a Philox4_32_10 generator. + * + * Return a uniformly distributed double between \p 0.0f and \p 1.0f + * from the Philox4_32_10 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * Note that the implementation uses only 32 random bits to generate a single double + * precision value. + * + * \p curand_uniform2_double() is recommended for higher quality uniformly distributed + * double precision values. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed double between \p 0.0f and \p 1.0f + */ + +QUALIFIERS double curand_uniform_double(curandStatePhilox4_32_10_t *state) +{ + return _curand_uniform_double(curand(state)); +} + + +/** + * \brief Return a uniformly distributed float from a Sobol32 generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the Sobol32 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * The implementation is guaranteed to use a single call to \p curand(). + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_uniform(curandStateSobol32_t *state) +{ + return _curand_uniform(curand(state)); +} + +/** + * \brief Return a uniformly distributed double from a Sobol32 generator. + * + * Return a uniformly distributed double between \p 0.0 and \p 1.0 + * from the Sobol32 generator in \p state, increment position of generator. + * Output range excludes \p 0.0 but includes \p 1.0. Denormalized floating + * point outputs are never returned. + * + * The implementation is guaranteed to use a single call to \p curand() + * to preserve the quasirandom properties of the sequence. + * + * Note that the implementation uses only 32 random bits to generate a single double + * precision value. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed double between \p 0.0 and \p 1.0 + */ +QUALIFIERS double curand_uniform_double(curandStateSobol32_t *state) +{ + return _curand_uniform_double(curand(state)); +} +/** + * \brief Return a uniformly distributed float from a scrambled Sobol32 generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the scrambled Sobol32 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * The implementation is guaranteed to use a single call to \p curand(). + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_uniform(curandStateScrambledSobol32_t *state) +{ + return _curand_uniform(curand(state)); +} + +/** + * \brief Return a uniformly distributed double from a scrambled Sobol32 generator. + * + * Return a uniformly distributed double between \p 0.0 and \p 1.0 + * from the scrambled Sobol32 generator in \p state, increment position of generator. + * Output range excludes \p 0.0 but includes \p 1.0. Denormalized floating + * point outputs are never returned. + * + * The implementation is guaranteed to use a single call to \p curand() + * to preserve the quasirandom properties of the sequence. + * + * Note that the implementation uses only 32 random bits to generate a single double + * precision value. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed double between \p 0.0 and \p 1.0 + */ +QUALIFIERS double curand_uniform_double(curandStateScrambledSobol32_t *state) +{ + return _curand_uniform_double(curand(state)); +} +/** + * \brief Return a uniformly distributed float from a Sobol64 generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the Sobol64 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * The implementation is guaranteed to use a single call to \p curand(). + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_uniform(curandStateSobol64_t *state) +{ + return _curand_uniform(curand(state)); +} + +/** + * \brief Return a uniformly distributed double from a Sobol64 generator. + * + * Return a uniformly distributed double between \p 0.0 and \p 1.0 + * from the Sobol64 generator in \p state, increment position of generator. + * Output range excludes \p 0.0 but includes \p 1.0. Denormalized floating + * point outputs are never returned. + * + * The implementation is guaranteed to use a single call to \p curand() + * to preserve the quasirandom properties of the sequence. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed double between \p 0.0 and \p 1.0 + */ +QUALIFIERS double curand_uniform_double(curandStateSobol64_t *state) +{ + return _curand_uniform_double(curand(state)); +} +/** + * \brief Return a uniformly distributed float from a scrambled Sobol64 generator. + * + * Return a uniformly distributed float between \p 0.0f and \p 1.0f + * from the scrambled Sobol64 generator in \p state, increment position of generator. + * Output range excludes \p 0.0f but includes \p 1.0f. Denormalized floating + * point outputs are never returned. + * + * The implementation is guaranteed to use a single call to \p curand(). + * + * \param state - Pointer to state to update + * + * \return uniformly distributed float between \p 0.0f and \p 1.0f + */ +QUALIFIERS float curand_uniform(curandStateScrambledSobol64_t *state) +{ + return _curand_uniform(curand(state)); +} + +/** + * \brief Return a uniformly distributed double from a scrambled Sobol64 generator. + * + * Return a uniformly distributed double between \p 0.0 and \p 1.0 + * from the scrambled Sobol64 generator in \p state, increment position of generator. + * Output range excludes \p 0.0 but includes \p 1.0. Denormalized floating + * point outputs are never returned. + * + * The implementation is guaranteed to use a single call to \p curand() + * to preserve the quasirandom properties of the sequence. + * + * \param state - Pointer to state to update + * + * \return uniformly distributed double between \p 0.0 and \p 1.0 + */ +QUALIFIERS double curand_uniform_double(curandStateScrambledSobol64_t *state) +{ + return _curand_uniform_double(curand(state)); +} + +#endif // !defined(CURAND_UNIFORM_H_) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/lib/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/lib/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/lib/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/lib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fab9ea752c80f33ce9bf7f93ce6d6b875d4ef59e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/curand/lib/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f1956f56188f5bb6c2475dbc7081c566041ac7e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/include/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/include/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43c82112785f61502475d6a1f728a78796b2060b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/include/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d1ea8b6d8d0b4cd51fc8b191e686249cb3112f5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/nccl/include/nccl.h b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/nccl/include/nccl.h new file mode 100644 index 0000000000000000000000000000000000000000..01c58461e532c13344571dcc9ca8621e5eb701fa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia/nccl/include/nccl.h @@ -0,0 +1,518 @@ +/************************************************************************* + * Copyright (c) 2015-2021, NVIDIA CORPORATION. All rights reserved. + * + * See LICENSE.txt for license information + ************************************************************************/ + +#ifndef NCCL_H_ +#define NCCL_H_ + +#include +#include +#if CUDART_VERSION >= 11000 +#include +#endif +#if CUDART_VERSION >= 11080 +#include +#endif + +#define NCCL_MAJOR 2 +#define NCCL_MINOR 27 +#define NCCL_PATCH 5 +#define NCCL_SUFFIX "" + +#define NCCL_VERSION_CODE 22705 +#define NCCL_VERSION(X,Y,Z) (((X) <= 2 && (Y) <= 8) ? (X) * 1000 + (Y) * 100 + (Z) : (X) * 10000 + (Y) * 100 + (Z)) + +#ifdef __cplusplus +extern "C" { +#endif + +#include +/* Opaque handle to communicator */ +typedef struct ncclComm* ncclComm_t; +typedef struct ncclWindow* ncclWindow_t; +#define NCCL_COMM_NULL NULL + +#define NCCL_UNIQUE_ID_BYTES 128 +typedef struct { char internal[NCCL_UNIQUE_ID_BYTES]; } ncclUniqueId; + +/* Error type */ +typedef enum { ncclSuccess = 0, + ncclUnhandledCudaError = 1, + ncclSystemError = 2, + ncclInternalError = 3, + ncclInvalidArgument = 4, + ncclInvalidUsage = 5, + ncclRemoteError = 6, + ncclInProgress = 7, + ncclNumResults = 8 } ncclResult_t; + +#define NCCL_CONFIG_UNDEF_INT INT_MIN +#define NCCL_CONFIG_UNDEF_PTR NULL +#define NCCL_SPLIT_NOCOLOR -1 +#define NCCL_UNDEF_FLOAT -1.0f + +/* Window Registration flags */ +#define NCCL_WIN_DEFAULT 0x00 +#define NCCL_WIN_COLL_SYMMETRIC 0x01 + +/* NCCL performance policy */ +#define NCCL_CTA_POLICY_DEFAULT 0x00 +#define NCCL_CTA_POLICY_EFFICIENCY 0x01 + +/* ncclCommShrink flags*/ +#define NCCL_SHRINK_DEFAULT 0x00 /* shrink the parent communicator */ +#define NCCL_SHRINK_ABORT 0x01 /* First, terminate ongoing parent operations, and then shrink the parent communicator */ + +/* Communicator configuration. Users can assign value to attributes to specify the + * behavior of a communicator. */ +typedef struct ncclConfig_v22700 { + /* attributes that users should never touch. */ + size_t size; + unsigned int magic; + unsigned int version; + /* attributes that users are able to customize. */ + int blocking; + int cgaClusterSize; + int minCTAs; + int maxCTAs; + const char *netName; + int splitShare; + int trafficClass; + const char *commName; + int collnetEnable; + int CTAPolicy; + int shrinkShare; + int nvlsCTAs; +} ncclConfig_t; + +/* Config initializer must be assigned to initialize config structure when it is created. + * Not initialized config will result in NCCL error. */ +#define NCCL_CONFIG_INITIALIZER { \ + sizeof(ncclConfig_t), /* size */ \ + 0xcafebeef, /* magic */ \ + NCCL_VERSION(NCCL_MAJOR, NCCL_MINOR, NCCL_PATCH), /* version */ \ + NCCL_CONFIG_UNDEF_INT, /* blocking */ \ + NCCL_CONFIG_UNDEF_INT, /* cgaClusterSize */ \ + NCCL_CONFIG_UNDEF_INT, /* minCTAs */ \ + NCCL_CONFIG_UNDEF_INT, /* maxCTAs */ \ + NCCL_CONFIG_UNDEF_PTR, /* netName */ \ + NCCL_CONFIG_UNDEF_INT, /* splitShare */ \ + NCCL_CONFIG_UNDEF_INT, /* trafficClass */ \ + NCCL_CONFIG_UNDEF_PTR, /* commName */ \ + NCCL_CONFIG_UNDEF_INT, /* collnetEnable */ \ + NCCL_CONFIG_UNDEF_INT, /* CTAPolicy */ \ + NCCL_CONFIG_UNDEF_INT, /* shrinkShare */ \ + NCCL_CONFIG_UNDEF_INT, /* nvlsCTAs */ \ +} + +/* This struct will be used by ncclGroupSimulateEnd() API to query information about simulation. */ +typedef struct ncclSimInfo_v22200 { + size_t size; + unsigned int magic; + unsigned int version; + float estimatedTime; +} ncclSimInfo_t; + +/* NCCL_SIM_INFO_INITIALIZER must be assigned to initialize simInfo structure when it is created. + * Not initialized simInfo will result in NCCL error. */ +#define NCCL_SIM_INFO_INITIALIZER { \ + sizeof(ncclSimInfo_t), /* size */ \ + 0x74685283, /* magic */ \ + NCCL_VERSION(NCCL_MAJOR, NCCL_MINOR, NCCL_PATCH), /* version */ \ + NCCL_UNDEF_FLOAT /* estimated time */ \ +} + +/* NCCL malloc and free function for all types of NCCL optimizations + * (e.g. user buffer registration). The actual allocated size might + * be larger than requested due to granularity requirement. */ +ncclResult_t ncclMemAlloc(void** ptr, size_t size); +ncclResult_t pncclMemAlloc(void** ptr, size_t size); + +ncclResult_t ncclMemFree(void *ptr); +ncclResult_t pncclMemFree(void *ptr); + +/* Return the NCCL_VERSION_CODE of the NCCL library in the supplied integer. + * This integer is coded with the MAJOR, MINOR and PATCH level of the + * NCCL library + */ +ncclResult_t ncclGetVersion(int *version); +ncclResult_t pncclGetVersion(int *version); + +/* Generates an Id to be used in ncclCommInitRank. ncclGetUniqueId should be + * called once and the Id should be distributed to all ranks in the + * communicator before calling ncclCommInitRank. */ +ncclResult_t ncclGetUniqueId(ncclUniqueId* uniqueId); +ncclResult_t pncclGetUniqueId(ncclUniqueId* uniqueId); + +/* Create a new communicator (multi thread/process version) with a configuration + * set by users. */ +ncclResult_t ncclCommInitRankConfig(ncclComm_t* comm, int nranks, ncclUniqueId commId, int rank, ncclConfig_t* config); +ncclResult_t pncclCommInitRankConfig(ncclComm_t* comm, int nranks, ncclUniqueId commId, int rank, ncclConfig_t* config); + +/* Creates a new communicator (multi thread/process version). + * rank must be between 0 and nranks-1 and unique within a communicator clique. + * Each rank is associated to a CUDA device, which has to be set before calling + * ncclCommInitRank. + * ncclCommInitRank implicitly syncronizes with other ranks, so it must be + * called by different threads/processes or use ncclGroupStart/ncclGroupEnd. */ +ncclResult_t ncclCommInitRank(ncclComm_t* comm, int nranks, ncclUniqueId commId, int rank); +ncclResult_t pncclCommInitRank(ncclComm_t* comm, int nranks, ncclUniqueId commId, int rank); + +/* Creates a clique of communicators (single process version). + * This is a convenience function to create a single-process communicator clique. + * Returns an array of ndev newly initialized communicators in comm. + * comm should be pre-allocated with size at least ndev*sizeof(ncclComm_t). + * If devlist is NULL, the first ndev CUDA devices are used. + * Order of devlist defines user-order of processors within the communicator. */ +ncclResult_t ncclCommInitAll(ncclComm_t* comm, int ndev, const int* devlist); +ncclResult_t pncclCommInitAll(ncclComm_t* comm, int ndev, const int* devlist); + +/* Finalize a communicator. ncclCommFinalize flushes all issued communications, + * and marks communicator state as ncclInProgress. The state will change to ncclSuccess + * when the communicator is globally quiescent and related resources are freed; then, + * calling ncclCommDestroy can locally free the rest of the resources (e.g. communicator + * itself) without blocking. */ +ncclResult_t ncclCommFinalize(ncclComm_t comm); +ncclResult_t pncclCommFinalize(ncclComm_t comm); + +/* Frees local resources associated with communicator object. */ +ncclResult_t ncclCommDestroy(ncclComm_t comm); +ncclResult_t pncclCommDestroy(ncclComm_t comm); + +/* Frees resources associated with communicator object and aborts any operations + * that might still be running on the device. */ +ncclResult_t ncclCommAbort(ncclComm_t comm); +ncclResult_t pncclCommAbort(ncclComm_t comm); + +/* Creates one or more communicators from an existing one. + * Ranks with the same color will end up in the same communicator. + * Within the new communicator, key will be used to order ranks. + * NCCL_SPLIT_NOCOLOR as color will indicate the rank will not be part of any group + * and will therefore return a NULL communicator. + * If config is NULL, the new communicator will inherit the original communicator's + * configuration*/ +ncclResult_t ncclCommSplit(ncclComm_t comm, int color, int key, ncclComm_t *newcomm, ncclConfig_t* config); +ncclResult_t pncclCommSplit(ncclComm_t comm, int color, int key, ncclComm_t *newcomm, ncclConfig_t* config); + +/* Shrink existing communicator. + * Ranks in excludeRanksList will be removed form the existing communicator. + * Within the new communicator, ranks will be re-ordered to fill the gap of removed ones. + * If config is NULL, the new communicator will inherit the original communicator's configuration + * The flag enables NCCL to adapt to various states of the parent communicator, see NCCL_SHRINK flags.*/ +ncclResult_t ncclCommShrink(ncclComm_t comm, int* excludeRanksList, int excludeRanksCount, ncclComm_t* newcomm, ncclConfig_t* config, int shrinkFlags); +ncclResult_t pncclCommShrink(ncclComm_t comm, int* excludeRanksList, int excludeRanksCount, ncclComm_t* newcomm, ncclConfig_t* config, int shrinkFlags); + +/* Creates a new communicator (multi thread/process version), similar to ncclCommInitRankConfig. + * Allows to use more than one ncclUniqueId (up to one per rank), indicated by nId, to accelerate the init operation. + * The number of ncclUniqueIds and their order must be the same for every rank. + */ +ncclResult_t ncclCommInitRankScalable(ncclComm_t* newcomm, int nranks, int myrank, int nId, ncclUniqueId* commIds, ncclConfig_t* config); +ncclResult_t pncclCommInitRankScalable(ncclComm_t* newcomm, int nranks, int myrank, int nId, ncclUniqueId* commIds, ncclConfig_t* config); + +/* Returns a string for each error code. */ +const char* ncclGetErrorString(ncclResult_t result); +const char* pncclGetErrorString(ncclResult_t result); + +/* Returns a human-readable message of the last error that occurred. */ +const char* ncclGetLastError(ncclComm_t comm); +const char* pncclGetLastError(ncclComm_t comm); + +/* Reload environment variables that determine logging. */ +void ncclResetDebugInit(); +void pncclResetDebugInit(); + +/* Checks whether the comm has encountered any asynchronous errors */ +ncclResult_t ncclCommGetAsyncError(ncclComm_t comm, ncclResult_t *asyncError); +ncclResult_t pncclCommGetAsyncError(ncclComm_t comm, ncclResult_t *asyncError); + +/* Gets the number of ranks in the communicator clique. */ +ncclResult_t ncclCommCount(const ncclComm_t comm, int* count); +ncclResult_t pncclCommCount(const ncclComm_t comm, int* count); + +/* Returns the cuda device number associated with the communicator. */ +ncclResult_t ncclCommCuDevice(const ncclComm_t comm, int* device); +ncclResult_t pncclCommCuDevice(const ncclComm_t comm, int* device); + +/* Returns the user-ordered "rank" associated with the communicator. */ +ncclResult_t ncclCommUserRank(const ncclComm_t comm, int* rank); +ncclResult_t pncclCommUserRank(const ncclComm_t comm, int* rank); + +/* Register CUDA buffer for zero-copy operation */ +ncclResult_t ncclCommRegister(const ncclComm_t comm, void* buff, size_t size, void** handle); +ncclResult_t pncclCommRegister(const ncclComm_t comm, void* buff, size_t size, void** handle); + +/* Deregister CUDA buffer */ +ncclResult_t ncclCommDeregister(const ncclComm_t comm, void* handle); +ncclResult_t pncclCommDeregister(const ncclComm_t comm, void* handle); + +/* Register memory window */ +ncclResult_t ncclCommWindowRegister(ncclComm_t comm, void* buff, size_t size, ncclWindow_t* win, int winFlags); +ncclResult_t pncclCommWindowRegister(ncclComm_t comm, void* buff, size_t size, ncclWindow_t* win, int winFlags); + +/* Deregister symmetric memory */ +ncclResult_t ncclCommWindowDeregister(ncclComm_t comm, ncclWindow_t win); +ncclResult_t pncclCommWindowDeregister(ncclComm_t comm, ncclWindow_t win); + +/* Reduction operation selector */ +typedef enum { ncclNumOps_dummy = 5 } ncclRedOp_dummy_t; +typedef enum { ncclSum = 0, + ncclProd = 1, + ncclMax = 2, + ncclMin = 3, + ncclAvg = 4, + /* ncclNumOps: The number of built-in ncclRedOp_t values. Also + * serves as the least possible value for dynamic ncclRedOp_t's + * as constructed by ncclRedOpCreate*** functions. */ + ncclNumOps = 5, + /* ncclMaxRedOp: The largest valid value for ncclRedOp_t. + * It is defined to be the largest signed value (since compilers + * are permitted to use signed enums) that won't grow + * sizeof(ncclRedOp_t) when compared to previous NCCL versions to + * maintain ABI compatibility. */ + ncclMaxRedOp = 0x7fffffff>>(32-8*sizeof(ncclRedOp_dummy_t)) + } ncclRedOp_t; + +/* Data types */ +typedef enum { ncclInt8 = 0, ncclChar = 0, + ncclUint8 = 1, + ncclInt32 = 2, ncclInt = 2, + ncclUint32 = 3, + ncclInt64 = 4, + ncclUint64 = 5, + ncclFloat16 = 6, ncclHalf = 6, + ncclFloat32 = 7, ncclFloat = 7, + ncclFloat64 = 8, ncclDouble = 8, + ncclBfloat16 = 9, + ncclFloat8e4m3 = 10, + ncclFloat8e5m2 = 11, + ncclNumTypes = 12 +} ncclDataType_t; + +/* ncclScalarResidence_t: Location and dereferencing logic for scalar arguments. */ +typedef enum { + /* ncclScalarDevice: The scalar is in device-visible memory and will be + * dereferenced while the collective is running. */ + ncclScalarDevice = 0, + + /* ncclScalarHostImmediate: The scalar is in host-visible memory and will be + * dereferenced before the ncclRedOpCreate***() function returns. */ + ncclScalarHostImmediate = 1 +} ncclScalarResidence_t; + +/* + * ncclRedOpCreatePreMulSum + * + * Creates a new reduction operator which pre-multiplies input values by a given + * scalar locally before reducing them with peer values via summation. For use + * only with collectives launched against *comm* and *datatype*. The + * *residence* argument indicates how/when the memory pointed to by *scalar* + * will be dereferenced. Upon return, the newly created operator's handle + * is stored in *op*. + */ +ncclResult_t ncclRedOpCreatePreMulSum(ncclRedOp_t *op, void *scalar, ncclDataType_t datatype, ncclScalarResidence_t residence, ncclComm_t comm); +ncclResult_t pncclRedOpCreatePreMulSum(ncclRedOp_t *op, void *scalar, ncclDataType_t datatype, ncclScalarResidence_t residence, ncclComm_t comm); + +/* + * ncclRedOpDestroy + * + * Destroys the reduction operator *op*. The operator must have been created by + * ncclRedOpCreatePreMul with the matching communicator *comm*. An operator may be + * destroyed as soon as the last NCCL function which is given that operator returns. + */ +ncclResult_t ncclRedOpDestroy(ncclRedOp_t op, ncclComm_t comm); +ncclResult_t pncclRedOpDestroy(ncclRedOp_t op, ncclComm_t comm); + +/* + * Collective communication operations + * + * Collective communication operations must be called separately for each + * communicator in a communicator clique. + * + * They return when operations have been enqueued on the CUDA stream. + * + * Since they may perform inter-CPU synchronization, each call has to be done + * from a different thread or process, or need to use Group Semantics (see + * below). + */ + +/* + * Reduce + * + * Reduces data arrays of length count in sendbuff into recvbuff using op + * operation. + * recvbuff may be NULL on all calls except for root device. + * root is the rank (not the CUDA device) where data will reside after the + * operation is complete. + * + * In-place operation will happen if sendbuff == recvbuff. + */ +ncclResult_t ncclReduce(const void* sendbuff, void* recvbuff, size_t count, ncclDataType_t datatype, + ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream); +ncclResult_t pncclReduce(const void* sendbuff, void* recvbuff, size_t count, ncclDataType_t datatype, + ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream); + +/* + * (deprecated) Broadcast (in-place) + * + * Copies count values from root to all other devices. + * root is the rank (not the CUDA device) where data resides before the + * operation is started. + * + * This operation is implicitely in place. + */ +ncclResult_t ncclBcast(void* buff, size_t count, ncclDataType_t datatype, int root, + ncclComm_t comm, cudaStream_t stream); +ncclResult_t pncclBcast(void* buff, size_t count, ncclDataType_t datatype, int root, + ncclComm_t comm, cudaStream_t stream); + +/* + * Broadcast + * + * Copies count values from root to all other devices. + * root is the rank (not the CUDA device) where data resides before the + * operation is started. + * + * In-place operation will happen if sendbuff == recvbuff. + */ +ncclResult_t ncclBroadcast(const void* sendbuff, void* recvbuff, size_t count, ncclDataType_t datatype, int root, + ncclComm_t comm, cudaStream_t stream); +ncclResult_t pncclBroadcast(const void* sendbuff, void* recvbuff, size_t count, ncclDataType_t datatype, int root, + ncclComm_t comm, cudaStream_t stream); + +/* + * All-Reduce + * + * Reduces data arrays of length count in sendbuff using op operation, and + * leaves identical copies of result on each recvbuff. + * + * In-place operation will happen if sendbuff == recvbuff. + */ +ncclResult_t ncclAllReduce(const void* sendbuff, void* recvbuff, size_t count, + ncclDataType_t datatype, ncclRedOp_t op, ncclComm_t comm, cudaStream_t stream); +ncclResult_t pncclAllReduce(const void* sendbuff, void* recvbuff, size_t count, + ncclDataType_t datatype, ncclRedOp_t op, ncclComm_t comm, cudaStream_t stream); + +/* + * Reduce-Scatter + * + * Reduces data in sendbuff using op operation and leaves reduced result + * scattered over the devices so that recvbuff on rank i will contain the i-th + * block of the result. + * Assumes sendcount is equal to nranks*recvcount, which means that sendbuff + * should have a size of at least nranks*recvcount elements. + * + * In-place operations will happen if recvbuff == sendbuff + rank * recvcount. + */ +ncclResult_t ncclReduceScatter(const void* sendbuff, void* recvbuff, + size_t recvcount, ncclDataType_t datatype, ncclRedOp_t op, ncclComm_t comm, + cudaStream_t stream); +ncclResult_t pncclReduceScatter(const void* sendbuff, void* recvbuff, + size_t recvcount, ncclDataType_t datatype, ncclRedOp_t op, ncclComm_t comm, + cudaStream_t stream); + +/* + * All-Gather + * + * Each device gathers sendcount values from other GPUs into recvbuff, + * receiving data from rank i at offset i*sendcount. + * Assumes recvcount is equal to nranks*sendcount, which means that recvbuff + * should have a size of at least nranks*sendcount elements. + * + * In-place operations will happen if sendbuff == recvbuff + rank * sendcount. + */ +ncclResult_t ncclAllGather(const void* sendbuff, void* recvbuff, size_t sendcount, + ncclDataType_t datatype, ncclComm_t comm, cudaStream_t stream); +ncclResult_t pncclAllGather(const void* sendbuff, void* recvbuff, size_t sendcount, + ncclDataType_t datatype, ncclComm_t comm, cudaStream_t stream); + +/* + * Send + * + * Send data from sendbuff to rank peer. + * + * Rank peer needs to call ncclRecv with the same datatype and the same count from this + * rank. + * + * This operation is blocking for the GPU. If multiple ncclSend and ncclRecv operations + * need to progress concurrently to complete, they must be fused within a ncclGroupStart/ + * ncclGroupEnd section. + */ +ncclResult_t ncclSend(const void* sendbuff, size_t count, ncclDataType_t datatype, int peer, + ncclComm_t comm, cudaStream_t stream); +ncclResult_t pncclSend(const void* sendbuff, size_t count, ncclDataType_t datatype, int peer, + ncclComm_t comm, cudaStream_t stream); + +/* + * Receive + * + * Receive data from rank peer into recvbuff. + * + * Rank peer needs to call ncclSend with the same datatype and the same count to this + * rank. + * + * This operation is blocking for the GPU. If multiple ncclSend and ncclRecv operations + * need to progress concurrently to complete, they must be fused within a ncclGroupStart/ + * ncclGroupEnd section. + */ +ncclResult_t pncclRecv(void* recvbuff, size_t count, ncclDataType_t datatype, int peer, + ncclComm_t comm, cudaStream_t stream); +ncclResult_t ncclRecv(void* recvbuff, size_t count, ncclDataType_t datatype, int peer, + ncclComm_t comm, cudaStream_t stream); + +/* + * Group semantics + * + * When managing multiple GPUs from a single thread, and since NCCL collective + * calls may perform inter-CPU synchronization, we need to "group" calls for + * different ranks/devices into a single call. + * + * Grouping NCCL calls as being part of the same collective operation is done + * using ncclGroupStart and ncclGroupEnd. ncclGroupStart will enqueue all + * collective calls until the ncclGroupEnd call, which will wait for all calls + * to be complete. Note that for collective communication, ncclGroupEnd only + * guarantees that the operations are enqueued on the streams, not that + * the operation is effectively done. + * + * Both collective communication and ncclCommInitRank can be used in conjunction + * of ncclGroupStart/ncclGroupEnd, but not together. + * + * Group semantics also allow to fuse multiple operations on the same device + * to improve performance (for aggregated collective calls), or to permit + * concurrent progress of multiple send/receive operations. + */ + +/* + * Group Start + * + * Start a group call. All calls to NCCL until ncclGroupEnd will be fused into + * a single NCCL operation. Nothing will be started on the CUDA stream until + * ncclGroupEnd. + */ +ncclResult_t ncclGroupStart(); +ncclResult_t pncclGroupStart(); + +/* + * Group End + * + * End a group call. Start a fused NCCL operation consisting of all calls since + * ncclGroupStart. Operations on the CUDA stream depending on the NCCL operations + * need to be called after ncclGroupEnd. + */ +ncclResult_t ncclGroupEnd(); +ncclResult_t pncclGroupEnd(); + +/* + * Group Simulate End + * + * Simulate a ncclGroupEnd() call and return NCCL's simulation info in a struct. + */ +ncclResult_t ncclGroupSimulateEnd(ncclSimInfo_t* simInfo); +ncclResult_t pncclGroupSimulateEnd(ncclSimInfo_t* simInfo); + +#ifdef __cplusplus +} // end extern "C" +#endif + +#endif // end include guard diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pathvalidate-3.3.1.dist-info/licenses/LICENSE b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pathvalidate-3.3.1.dist-info/licenses/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..3e3c2f9d5e2bc9c160cda612c58f5fb61df672d0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pathvalidate-3.3.1.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016-2025 Tsuyoshi Hombashi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9108737444f4d122f02a50d9cd804cee3b26dddc Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/abc.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/abc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6217db1e5988796fe675969a7abae74848bbc282 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/abc.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/conftest.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/conftest.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7783273cdbb20a7c5ae591154b0089c187b32d25 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/conftest.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/galgebra.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/galgebra.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9d78ee53016dcb41afff7ec7ce616248e911b8c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/galgebra.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/release.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/release.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e04b6b66a2b50abcfacffd425141db396427ea2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/release.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/this.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/this.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e846c730d192f28ceb6b452a47e2a85ca821664 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/__pycache__/this.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/algebras/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/algebras/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..58013d2e0377a016d1a21fbf21c344ee76765189 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/algebras/__init__.py @@ -0,0 +1,3 @@ +from .quaternion import Quaternion + +__all__ = ["Quaternion",] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/algebras/quaternion.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/algebras/quaternion.py new file mode 100644 index 0000000000000000000000000000000000000000..1bf4b363545128e50294e825461106ef9b41990d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/algebras/quaternion.py @@ -0,0 +1,1666 @@ +from sympy.core.numbers import Rational +from sympy.core.singleton import S +from sympy.core.relational import is_eq +from sympy.functions.elementary.complexes import (conjugate, im, re, sign) +from sympy.functions.elementary.exponential import (exp, log as ln) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (acos, asin, atan2) +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.simplify.trigsimp import trigsimp +from sympy.integrals.integrals import integrate +from sympy.matrices.dense import MutableDenseMatrix as Matrix +from sympy.core.sympify import sympify, _sympify +from sympy.core.expr import Expr +from sympy.core.logic import fuzzy_not, fuzzy_or +from sympy.utilities.misc import as_int + +from mpmath.libmp.libmpf import prec_to_dps + + +def _check_norm(elements, norm): + """validate if input norm is consistent""" + if norm is not None and norm.is_number: + if norm.is_positive is False: + raise ValueError("Input norm must be positive.") + + numerical = all(i.is_number and i.is_real is True for i in elements) + if numerical and is_eq(norm**2, sum(i**2 for i in elements)) is False: + raise ValueError("Incompatible value for norm.") + + +def _is_extrinsic(seq): + """validate seq and return True if seq is lowercase and False if uppercase""" + if type(seq) != str: + raise ValueError('Expected seq to be a string.') + if len(seq) != 3: + raise ValueError("Expected 3 axes, got `{}`.".format(seq)) + + intrinsic = seq.isupper() + extrinsic = seq.islower() + if not (intrinsic or extrinsic): + raise ValueError("seq must either be fully uppercase (for extrinsic " + "rotations), or fully lowercase, for intrinsic " + "rotations).") + + i, j, k = seq.lower() + if (i == j) or (j == k): + raise ValueError("Consecutive axes must be different") + + bad = set(seq) - set('xyzXYZ') + if bad: + raise ValueError("Expected axes from `seq` to be from " + "['x', 'y', 'z'] or ['X', 'Y', 'Z'], " + "got {}".format(''.join(bad))) + + return extrinsic + + +class Quaternion(Expr): + """Provides basic quaternion operations. + Quaternion objects can be instantiated as ``Quaternion(a, b, c, d)`` + as in $q = a + bi + cj + dk$. + + Parameters + ========== + + norm : None or number + Pre-defined quaternion norm. If a value is given, Quaternion.norm + returns this pre-defined value instead of calculating the norm + + Examples + ======== + + >>> from sympy import Quaternion + >>> q = Quaternion(1, 2, 3, 4) + >>> q + 1 + 2*i + 3*j + 4*k + + Quaternions over complex fields can be defined as: + + >>> from sympy import Quaternion + >>> from sympy import symbols, I + >>> x = symbols('x') + >>> q1 = Quaternion(x, x**3, x, x**2, real_field = False) + >>> q2 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) + >>> q1 + x + x**3*i + x*j + x**2*k + >>> q2 + (3 + 4*I) + (2 + 5*I)*i + 0*j + (7 + 8*I)*k + + Defining symbolic unit quaternions: + + >>> from sympy import Quaternion + >>> from sympy.abc import w, x, y, z + >>> q = Quaternion(w, x, y, z, norm=1) + >>> q + w + x*i + y*j + z*k + >>> q.norm() + 1 + + References + ========== + + .. [1] https://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/ + .. [2] https://en.wikipedia.org/wiki/Quaternion + + """ + _op_priority = 11.0 + + is_commutative = False + + def __new__(cls, a=0, b=0, c=0, d=0, real_field=True, norm=None): + a, b, c, d = map(sympify, (a, b, c, d)) + + if any(i.is_commutative is False for i in [a, b, c, d]): + raise ValueError("arguments have to be commutative") + obj = super().__new__(cls, a, b, c, d) + obj._real_field = real_field + obj.set_norm(norm) + return obj + + def set_norm(self, norm): + """Sets norm of an already instantiated quaternion. + + Parameters + ========== + + norm : None or number + Pre-defined quaternion norm. If a value is given, Quaternion.norm + returns this pre-defined value instead of calculating the norm + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy.abc import a, b, c, d + >>> q = Quaternion(a, b, c, d) + >>> q.norm() + sqrt(a**2 + b**2 + c**2 + d**2) + + Setting the norm: + + >>> q.set_norm(1) + >>> q.norm() + 1 + + Removing set norm: + + >>> q.set_norm(None) + >>> q.norm() + sqrt(a**2 + b**2 + c**2 + d**2) + + """ + norm = sympify(norm) + _check_norm(self.args, norm) + self._norm = norm + + @property + def a(self): + return self.args[0] + + @property + def b(self): + return self.args[1] + + @property + def c(self): + return self.args[2] + + @property + def d(self): + return self.args[3] + + @property + def real_field(self): + return self._real_field + + @property + def product_matrix_left(self): + r"""Returns 4 x 4 Matrix equivalent to a Hamilton product from the + left. This can be useful when treating quaternion elements as column + vectors. Given a quaternion $q = a + bi + cj + dk$ where a, b, c and d + are real numbers, the product matrix from the left is: + + .. math:: + + M = \begin{bmatrix} a &-b &-c &-d \\ + b & a &-d & c \\ + c & d & a &-b \\ + d &-c & b & a \end{bmatrix} + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy.abc import a, b, c, d + >>> q1 = Quaternion(1, 0, 0, 1) + >>> q2 = Quaternion(a, b, c, d) + >>> q1.product_matrix_left + Matrix([ + [1, 0, 0, -1], + [0, 1, -1, 0], + [0, 1, 1, 0], + [1, 0, 0, 1]]) + + >>> q1.product_matrix_left * q2.to_Matrix() + Matrix([ + [a - d], + [b - c], + [b + c], + [a + d]]) + + This is equivalent to: + + >>> (q1 * q2).to_Matrix() + Matrix([ + [a - d], + [b - c], + [b + c], + [a + d]]) + """ + return Matrix([ + [self.a, -self.b, -self.c, -self.d], + [self.b, self.a, -self.d, self.c], + [self.c, self.d, self.a, -self.b], + [self.d, -self.c, self.b, self.a]]) + + @property + def product_matrix_right(self): + r"""Returns 4 x 4 Matrix equivalent to a Hamilton product from the + right. This can be useful when treating quaternion elements as column + vectors. Given a quaternion $q = a + bi + cj + dk$ where a, b, c and d + are real numbers, the product matrix from the left is: + + .. math:: + + M = \begin{bmatrix} a &-b &-c &-d \\ + b & a & d &-c \\ + c &-d & a & b \\ + d & c &-b & a \end{bmatrix} + + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy.abc import a, b, c, d + >>> q1 = Quaternion(a, b, c, d) + >>> q2 = Quaternion(1, 0, 0, 1) + >>> q2.product_matrix_right + Matrix([ + [1, 0, 0, -1], + [0, 1, 1, 0], + [0, -1, 1, 0], + [1, 0, 0, 1]]) + + Note the switched arguments: the matrix represents the quaternion on + the right, but is still considered as a matrix multiplication from the + left. + + >>> q2.product_matrix_right * q1.to_Matrix() + Matrix([ + [ a - d], + [ b + c], + [-b + c], + [ a + d]]) + + This is equivalent to: + + >>> (q1 * q2).to_Matrix() + Matrix([ + [ a - d], + [ b + c], + [-b + c], + [ a + d]]) + """ + return Matrix([ + [self.a, -self.b, -self.c, -self.d], + [self.b, self.a, self.d, -self.c], + [self.c, -self.d, self.a, self.b], + [self.d, self.c, -self.b, self.a]]) + + def to_Matrix(self, vector_only=False): + """Returns elements of quaternion as a column vector. + By default, a ``Matrix`` of length 4 is returned, with the real part as the + first element. + If ``vector_only`` is ``True``, returns only imaginary part as a Matrix of + length 3. + + Parameters + ========== + + vector_only : bool + If True, only imaginary part is returned. + Default value: False + + Returns + ======= + + Matrix + A column vector constructed by the elements of the quaternion. + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy.abc import a, b, c, d + >>> q = Quaternion(a, b, c, d) + >>> q + a + b*i + c*j + d*k + + >>> q.to_Matrix() + Matrix([ + [a], + [b], + [c], + [d]]) + + + >>> q.to_Matrix(vector_only=True) + Matrix([ + [b], + [c], + [d]]) + + """ + if vector_only: + return Matrix(self.args[1:]) + else: + return Matrix(self.args) + + @classmethod + def from_Matrix(cls, elements): + """Returns quaternion from elements of a column vector`. + If vector_only is True, returns only imaginary part as a Matrix of + length 3. + + Parameters + ========== + + elements : Matrix, list or tuple of length 3 or 4. If length is 3, + assume real part is zero. + Default value: False + + Returns + ======= + + Quaternion + A quaternion created from the input elements. + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy.abc import a, b, c, d + >>> q = Quaternion.from_Matrix([a, b, c, d]) + >>> q + a + b*i + c*j + d*k + + >>> q = Quaternion.from_Matrix([b, c, d]) + >>> q + 0 + b*i + c*j + d*k + + """ + length = len(elements) + if length != 3 and length != 4: + raise ValueError("Input elements must have length 3 or 4, got {} " + "elements".format(length)) + + if length == 3: + return Quaternion(0, *elements) + else: + return Quaternion(*elements) + + @classmethod + def from_euler(cls, angles, seq): + """Returns quaternion equivalent to rotation represented by the Euler + angles, in the sequence defined by ``seq``. + + Parameters + ========== + + angles : list, tuple or Matrix of 3 numbers + The Euler angles (in radians). + seq : string of length 3 + Represents the sequence of rotations. + For extrinsic rotations, seq must be all lowercase and its elements + must be from the set ``{'x', 'y', 'z'}`` + For intrinsic rotations, seq must be all uppercase and its elements + must be from the set ``{'X', 'Y', 'Z'}`` + + Returns + ======= + + Quaternion + The normalized rotation quaternion calculated from the Euler angles + in the given sequence. + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import pi + >>> q = Quaternion.from_euler([pi/2, 0, 0], 'xyz') + >>> q + sqrt(2)/2 + sqrt(2)/2*i + 0*j + 0*k + + >>> q = Quaternion.from_euler([0, pi/2, pi] , 'zyz') + >>> q + 0 + (-sqrt(2)/2)*i + 0*j + sqrt(2)/2*k + + >>> q = Quaternion.from_euler([0, pi/2, pi] , 'ZYZ') + >>> q + 0 + sqrt(2)/2*i + 0*j + sqrt(2)/2*k + + """ + + if len(angles) != 3: + raise ValueError("3 angles must be given.") + + extrinsic = _is_extrinsic(seq) + i, j, k = seq.lower() + + # get elementary basis vectors + ei = [1 if n == i else 0 for n in 'xyz'] + ej = [1 if n == j else 0 for n in 'xyz'] + ek = [1 if n == k else 0 for n in 'xyz'] + + # calculate distinct quaternions + qi = cls.from_axis_angle(ei, angles[0]) + qj = cls.from_axis_angle(ej, angles[1]) + qk = cls.from_axis_angle(ek, angles[2]) + + if extrinsic: + return trigsimp(qk * qj * qi) + else: + return trigsimp(qi * qj * qk) + + def to_euler(self, seq, angle_addition=True, avoid_square_root=False): + r"""Returns Euler angles representing same rotation as the quaternion, + in the sequence given by ``seq``. This implements the method described + in [1]_. + + For degenerate cases (gymbal lock cases), the third angle is + set to zero. + + Parameters + ========== + + seq : string of length 3 + Represents the sequence of rotations. + For extrinsic rotations, seq must be all lowercase and its elements + must be from the set ``{'x', 'y', 'z'}`` + For intrinsic rotations, seq must be all uppercase and its elements + must be from the set ``{'X', 'Y', 'Z'}`` + + angle_addition : bool + When True, first and third angles are given as an addition and + subtraction of two simpler ``atan2`` expressions. When False, the + first and third angles are each given by a single more complicated + ``atan2`` expression. This equivalent expression is given by: + + .. math:: + + \operatorname{atan_2} (b,a) \pm \operatorname{atan_2} (d,c) = + \operatorname{atan_2} (bc\pm ad, ac\mp bd) + + Default value: True + + avoid_square_root : bool + When True, the second angle is calculated with an expression based + on ``acos``, which is slightly more complicated but avoids a square + root. When False, second angle is calculated with ``atan2``, which + is simpler and can be better for numerical reasons (some + numerical implementations of ``acos`` have problems near zero). + Default value: False + + + Returns + ======= + + Tuple + The Euler angles calculated from the quaternion + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy.abc import a, b, c, d + >>> euler = Quaternion(a, b, c, d).to_euler('zyz') + >>> euler + (-atan2(-b, c) + atan2(d, a), + 2*atan2(sqrt(b**2 + c**2), sqrt(a**2 + d**2)), + atan2(-b, c) + atan2(d, a)) + + + References + ========== + + .. [1] https://doi.org/10.1371/journal.pone.0276302 + + """ + if self.is_zero_quaternion(): + raise ValueError('Cannot convert a quaternion with norm 0.') + + angles = [0, 0, 0] + + extrinsic = _is_extrinsic(seq) + i, j, k = seq.lower() + + # get index corresponding to elementary basis vectors + i = 'xyz'.index(i) + 1 + j = 'xyz'.index(j) + 1 + k = 'xyz'.index(k) + 1 + + if not extrinsic: + i, k = k, i + + # check if sequence is symmetric + symmetric = i == k + if symmetric: + k = 6 - i - j + + # parity of the permutation + sign = (i - j) * (j - k) * (k - i) // 2 + + # permutate elements + elements = [self.a, self.b, self.c, self.d] + a = elements[0] + b = elements[i] + c = elements[j] + d = elements[k] * sign + + if not symmetric: + a, b, c, d = a - c, b + d, c + a, d - b + + if avoid_square_root: + if symmetric: + n2 = self.norm()**2 + angles[1] = acos((a * a + b * b - c * c - d * d) / n2) + else: + n2 = 2 * self.norm()**2 + angles[1] = asin((c * c + d * d - a * a - b * b) / n2) + else: + angles[1] = 2 * atan2(sqrt(c * c + d * d), sqrt(a * a + b * b)) + if not symmetric: + angles[1] -= S.Pi / 2 + + # Check for singularities in numerical cases + case = 0 + if is_eq(c, S.Zero) and is_eq(d, S.Zero): + case = 1 + if is_eq(a, S.Zero) and is_eq(b, S.Zero): + case = 2 + + if case == 0: + if angle_addition: + angles[0] = atan2(b, a) + atan2(d, c) + angles[2] = atan2(b, a) - atan2(d, c) + else: + angles[0] = atan2(b*c + a*d, a*c - b*d) + angles[2] = atan2(b*c - a*d, a*c + b*d) + + else: # any degenerate case + angles[2 * (not extrinsic)] = S.Zero + if case == 1: + angles[2 * extrinsic] = 2 * atan2(b, a) + else: + angles[2 * extrinsic] = 2 * atan2(d, c) + angles[2 * extrinsic] *= (-1 if extrinsic else 1) + + # for Tait-Bryan angles + if not symmetric: + angles[0] *= sign + + if extrinsic: + return tuple(angles[::-1]) + else: + return tuple(angles) + + @classmethod + def from_axis_angle(cls, vector, angle): + """Returns a rotation quaternion given the axis and the angle of rotation. + + Parameters + ========== + + vector : tuple of three numbers + The vector representation of the given axis. + angle : number + The angle by which axis is rotated (in radians). + + Returns + ======= + + Quaternion + The normalized rotation quaternion calculated from the given axis and the angle of rotation. + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import pi, sqrt + >>> q = Quaternion.from_axis_angle((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), 2*pi/3) + >>> q + 1/2 + 1/2*i + 1/2*j + 1/2*k + + """ + (x, y, z) = vector + norm = sqrt(x**2 + y**2 + z**2) + (x, y, z) = (x / norm, y / norm, z / norm) + s = sin(angle * S.Half) + a = cos(angle * S.Half) + b = x * s + c = y * s + d = z * s + + # note that this quaternion is already normalized by construction: + # c^2 + (s*x)^2 + (s*y)^2 + (s*z)^2 = c^2 + s^2*(x^2 + y^2 + z^2) = c^2 + s^2 * 1 = c^2 + s^2 = 1 + # so, what we return is a normalized quaternion + + return cls(a, b, c, d) + + @classmethod + def from_rotation_matrix(cls, M): + """Returns the equivalent quaternion of a matrix. The quaternion will be normalized + only if the matrix is special orthogonal (orthogonal and det(M) = 1). + + Parameters + ========== + + M : Matrix + Input matrix to be converted to equivalent quaternion. M must be special + orthogonal (orthogonal and det(M) = 1) for the quaternion to be normalized. + + Returns + ======= + + Quaternion + The quaternion equivalent to given matrix. + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import Matrix, symbols, cos, sin, trigsimp + >>> x = symbols('x') + >>> M = Matrix([[cos(x), -sin(x), 0], [sin(x), cos(x), 0], [0, 0, 1]]) + >>> q = trigsimp(Quaternion.from_rotation_matrix(M)) + >>> q + sqrt(2)*sqrt(cos(x) + 1)/2 + 0*i + 0*j + sqrt(2 - 2*cos(x))*sign(sin(x))/2*k + + """ + + absQ = M.det()**Rational(1, 3) + + a = sqrt(absQ + M[0, 0] + M[1, 1] + M[2, 2]) / 2 + b = sqrt(absQ + M[0, 0] - M[1, 1] - M[2, 2]) / 2 + c = sqrt(absQ - M[0, 0] + M[1, 1] - M[2, 2]) / 2 + d = sqrt(absQ - M[0, 0] - M[1, 1] + M[2, 2]) / 2 + + b = b * sign(M[2, 1] - M[1, 2]) + c = c * sign(M[0, 2] - M[2, 0]) + d = d * sign(M[1, 0] - M[0, 1]) + + return Quaternion(a, b, c, d) + + def __add__(self, other): + return self.add(other) + + def __radd__(self, other): + return self.add(other) + + def __sub__(self, other): + return self.add(other*-1) + + def __mul__(self, other): + return self._generic_mul(self, _sympify(other)) + + def __rmul__(self, other): + return self._generic_mul(_sympify(other), self) + + def __pow__(self, p): + return self.pow(p) + + def __neg__(self): + return Quaternion(-self.a, -self.b, -self.c, -self.d) + + def __truediv__(self, other): + return self * sympify(other)**-1 + + def __rtruediv__(self, other): + return sympify(other) * self**-1 + + def _eval_Integral(self, *args): + return self.integrate(*args) + + def diff(self, *symbols, **kwargs): + kwargs.setdefault('evaluate', True) + return self.func(*[a.diff(*symbols, **kwargs) for a in self.args]) + + def add(self, other): + """Adds quaternions. + + Parameters + ========== + + other : Quaternion + The quaternion to add to current (self) quaternion. + + Returns + ======= + + Quaternion + The resultant quaternion after adding self to other + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import symbols + >>> q1 = Quaternion(1, 2, 3, 4) + >>> q2 = Quaternion(5, 6, 7, 8) + >>> q1.add(q2) + 6 + 8*i + 10*j + 12*k + >>> q1 + 5 + 6 + 2*i + 3*j + 4*k + >>> x = symbols('x', real = True) + >>> q1.add(x) + (x + 1) + 2*i + 3*j + 4*k + + Quaternions over complex fields : + + >>> from sympy import Quaternion + >>> from sympy import I + >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) + >>> q3.add(2 + 3*I) + (5 + 7*I) + (2 + 5*I)*i + 0*j + (7 + 8*I)*k + + """ + q1 = self + q2 = sympify(other) + + # If q2 is a number or a SymPy expression instead of a quaternion + if not isinstance(q2, Quaternion): + if q1.real_field and q2.is_complex: + return Quaternion(re(q2) + q1.a, im(q2) + q1.b, q1.c, q1.d) + elif q2.is_commutative: + return Quaternion(q1.a + q2, q1.b, q1.c, q1.d) + else: + raise ValueError("Only commutative expressions can be added with a Quaternion.") + + return Quaternion(q1.a + q2.a, q1.b + q2.b, q1.c + q2.c, q1.d + + q2.d) + + def mul(self, other): + """Multiplies quaternions. + + Parameters + ========== + + other : Quaternion or symbol + The quaternion to multiply to current (self) quaternion. + + Returns + ======= + + Quaternion + The resultant quaternion after multiplying self with other + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import symbols + >>> q1 = Quaternion(1, 2, 3, 4) + >>> q2 = Quaternion(5, 6, 7, 8) + >>> q1.mul(q2) + (-60) + 12*i + 30*j + 24*k + >>> q1.mul(2) + 2 + 4*i + 6*j + 8*k + >>> x = symbols('x', real = True) + >>> q1.mul(x) + x + 2*x*i + 3*x*j + 4*x*k + + Quaternions over complex fields : + + >>> from sympy import Quaternion + >>> from sympy import I + >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) + >>> q3.mul(2 + 3*I) + (2 + 3*I)*(3 + 4*I) + (2 + 3*I)*(2 + 5*I)*i + 0*j + (2 + 3*I)*(7 + 8*I)*k + + """ + return self._generic_mul(self, _sympify(other)) + + @staticmethod + def _generic_mul(q1, q2): + """Generic multiplication. + + Parameters + ========== + + q1 : Quaternion or symbol + q2 : Quaternion or symbol + + It is important to note that if neither q1 nor q2 is a Quaternion, + this function simply returns q1 * q2. + + Returns + ======= + + Quaternion + The resultant quaternion after multiplying q1 and q2 + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import Symbol, S + >>> q1 = Quaternion(1, 2, 3, 4) + >>> q2 = Quaternion(5, 6, 7, 8) + >>> Quaternion._generic_mul(q1, q2) + (-60) + 12*i + 30*j + 24*k + >>> Quaternion._generic_mul(q1, S(2)) + 2 + 4*i + 6*j + 8*k + >>> x = Symbol('x', real = True) + >>> Quaternion._generic_mul(q1, x) + x + 2*x*i + 3*x*j + 4*x*k + + Quaternions over complex fields : + + >>> from sympy import I + >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) + >>> Quaternion._generic_mul(q3, 2 + 3*I) + (2 + 3*I)*(3 + 4*I) + (2 + 3*I)*(2 + 5*I)*i + 0*j + (2 + 3*I)*(7 + 8*I)*k + + """ + # None is a Quaternion: + if not isinstance(q1, Quaternion) and not isinstance(q2, Quaternion): + return q1 * q2 + + # If q1 is a number or a SymPy expression instead of a quaternion + if not isinstance(q1, Quaternion): + if q2.real_field and q1.is_complex: + return Quaternion(re(q1), im(q1), 0, 0) * q2 + elif q1.is_commutative: + return Quaternion(q1 * q2.a, q1 * q2.b, q1 * q2.c, q1 * q2.d) + else: + raise ValueError("Only commutative expressions can be multiplied with a Quaternion.") + + # If q2 is a number or a SymPy expression instead of a quaternion + if not isinstance(q2, Quaternion): + if q1.real_field and q2.is_complex: + return q1 * Quaternion(re(q2), im(q2), 0, 0) + elif q2.is_commutative: + return Quaternion(q2 * q1.a, q2 * q1.b, q2 * q1.c, q2 * q1.d) + else: + raise ValueError("Only commutative expressions can be multiplied with a Quaternion.") + + # If any of the quaternions has a fixed norm, pre-compute norm + if q1._norm is None and q2._norm is None: + norm = None + else: + norm = q1.norm() * q2.norm() + + return Quaternion(-q1.b*q2.b - q1.c*q2.c - q1.d*q2.d + q1.a*q2.a, + q1.b*q2.a + q1.c*q2.d - q1.d*q2.c + q1.a*q2.b, + -q1.b*q2.d + q1.c*q2.a + q1.d*q2.b + q1.a*q2.c, + q1.b*q2.c - q1.c*q2.b + q1.d*q2.a + q1.a * q2.d, + norm=norm) + + def _eval_conjugate(self): + """Returns the conjugate of the quaternion.""" + q = self + return Quaternion(q.a, -q.b, -q.c, -q.d, norm=q._norm) + + def norm(self): + """Returns the norm of the quaternion.""" + if self._norm is None: # check if norm is pre-defined + q = self + # trigsimp is used to simplify sin(x)^2 + cos(x)^2 (these terms + # arise when from_axis_angle is used). + return sqrt(trigsimp(q.a**2 + q.b**2 + q.c**2 + q.d**2)) + + return self._norm + + def normalize(self): + """Returns the normalized form of the quaternion.""" + q = self + return q * (1/q.norm()) + + def inverse(self): + """Returns the inverse of the quaternion.""" + q = self + if not q.norm(): + raise ValueError("Cannot compute inverse for a quaternion with zero norm") + return conjugate(q) * (1/q.norm()**2) + + def pow(self, p): + """Finds the pth power of the quaternion. + + Parameters + ========== + + p : int + Power to be applied on quaternion. + + Returns + ======= + + Quaternion + Returns the p-th power of the current quaternion. + Returns the inverse if p = -1. + + Examples + ======== + + >>> from sympy import Quaternion + >>> q = Quaternion(1, 2, 3, 4) + >>> q.pow(4) + 668 + (-224)*i + (-336)*j + (-448)*k + + """ + try: + q, p = self, as_int(p) + except ValueError: + return NotImplemented + + if p < 0: + q, p = q.inverse(), -p + + if p == 1: + return q + + res = Quaternion(1, 0, 0, 0) + while p > 0: + if p & 1: + res *= q + q *= q + p >>= 1 + + return res + + def exp(self): + """Returns the exponential of $q$, given by $e^q$. + + Returns + ======= + + Quaternion + The exponential of the quaternion. + + Examples + ======== + + >>> from sympy import Quaternion + >>> q = Quaternion(1, 2, 3, 4) + >>> q.exp() + E*cos(sqrt(29)) + + 2*sqrt(29)*E*sin(sqrt(29))/29*i + + 3*sqrt(29)*E*sin(sqrt(29))/29*j + + 4*sqrt(29)*E*sin(sqrt(29))/29*k + + """ + # exp(q) = e^a(cos||v|| + v/||v||*sin||v||) + q = self + vector_norm = sqrt(q.b**2 + q.c**2 + q.d**2) + a = exp(q.a) * cos(vector_norm) + b = exp(q.a) * sin(vector_norm) * q.b / vector_norm + c = exp(q.a) * sin(vector_norm) * q.c / vector_norm + d = exp(q.a) * sin(vector_norm) * q.d / vector_norm + + return Quaternion(a, b, c, d) + + def log(self): + r"""Returns the logarithm of the quaternion, given by $\log q$. + + Examples + ======== + + >>> from sympy import Quaternion + >>> q = Quaternion(1, 2, 3, 4) + >>> q.log() + log(sqrt(30)) + + 2*sqrt(29)*acos(sqrt(30)/30)/29*i + + 3*sqrt(29)*acos(sqrt(30)/30)/29*j + + 4*sqrt(29)*acos(sqrt(30)/30)/29*k + + """ + # log(q) = log||q|| + v/||v||*arccos(a/||q||) + q = self + vector_norm = sqrt(q.b**2 + q.c**2 + q.d**2) + q_norm = q.norm() + a = ln(q_norm) + b = q.b * acos(q.a / q_norm) / vector_norm + c = q.c * acos(q.a / q_norm) / vector_norm + d = q.d * acos(q.a / q_norm) / vector_norm + + return Quaternion(a, b, c, d) + + def _eval_subs(self, *args): + elements = [i.subs(*args) for i in self.args] + norm = self._norm + if norm is not None: + norm = norm.subs(*args) + _check_norm(elements, norm) + return Quaternion(*elements, norm=norm) + + def _eval_evalf(self, prec): + """Returns the floating point approximations (decimal numbers) of the quaternion. + + Returns + ======= + + Quaternion + Floating point approximations of quaternion(self) + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import sqrt + >>> q = Quaternion(1/sqrt(1), 1/sqrt(2), 1/sqrt(3), 1/sqrt(4)) + >>> q.evalf() + 1.00000000000000 + + 0.707106781186547*i + + 0.577350269189626*j + + 0.500000000000000*k + + """ + nprec = prec_to_dps(prec) + return Quaternion(*[arg.evalf(n=nprec) for arg in self.args]) + + def pow_cos_sin(self, p): + """Computes the pth power in the cos-sin form. + + Parameters + ========== + + p : int + Power to be applied on quaternion. + + Returns + ======= + + Quaternion + The p-th power in the cos-sin form. + + Examples + ======== + + >>> from sympy import Quaternion + >>> q = Quaternion(1, 2, 3, 4) + >>> q.pow_cos_sin(4) + 900*cos(4*acos(sqrt(30)/30)) + + 1800*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*i + + 2700*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*j + + 3600*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*k + + """ + # q = ||q||*(cos(a) + u*sin(a)) + # q^p = ||q||^p * (cos(p*a) + u*sin(p*a)) + + q = self + (v, angle) = q.to_axis_angle() + q2 = Quaternion.from_axis_angle(v, p * angle) + return q2 * (q.norm()**p) + + def integrate(self, *args): + """Computes integration of quaternion. + + Returns + ======= + + Quaternion + Integration of the quaternion(self) with the given variable. + + Examples + ======== + + Indefinite Integral of quaternion : + + >>> from sympy import Quaternion + >>> from sympy.abc import x + >>> q = Quaternion(1, 2, 3, 4) + >>> q.integrate(x) + x + 2*x*i + 3*x*j + 4*x*k + + Definite integral of quaternion : + + >>> from sympy import Quaternion + >>> from sympy.abc import x + >>> q = Quaternion(1, 2, 3, 4) + >>> q.integrate((x, 1, 5)) + 4 + 8*i + 12*j + 16*k + + """ + return Quaternion(integrate(self.a, *args), integrate(self.b, *args), + integrate(self.c, *args), integrate(self.d, *args)) + + @staticmethod + def rotate_point(pin, r): + """Returns the coordinates of the point pin (a 3 tuple) after rotation. + + Parameters + ========== + + pin : tuple + A 3-element tuple of coordinates of a point which needs to be + rotated. + r : Quaternion or tuple + Axis and angle of rotation. + + It's important to note that when r is a tuple, it must be of the form + (axis, angle) + + Returns + ======= + + tuple + The coordinates of the point after rotation. + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import symbols, trigsimp, cos, sin + >>> x = symbols('x') + >>> q = Quaternion(cos(x/2), 0, 0, sin(x/2)) + >>> trigsimp(Quaternion.rotate_point((1, 1, 1), q)) + (sqrt(2)*cos(x + pi/4), sqrt(2)*sin(x + pi/4), 1) + >>> (axis, angle) = q.to_axis_angle() + >>> trigsimp(Quaternion.rotate_point((1, 1, 1), (axis, angle))) + (sqrt(2)*cos(x + pi/4), sqrt(2)*sin(x + pi/4), 1) + + """ + if isinstance(r, tuple): + # if r is of the form (vector, angle) + q = Quaternion.from_axis_angle(r[0], r[1]) + else: + # if r is a quaternion + q = r.normalize() + pout = q * Quaternion(0, pin[0], pin[1], pin[2]) * conjugate(q) + return (pout.b, pout.c, pout.d) + + def to_axis_angle(self): + """Returns the axis and angle of rotation of a quaternion. + + Returns + ======= + + tuple + Tuple of (axis, angle) + + Examples + ======== + + >>> from sympy import Quaternion + >>> q = Quaternion(1, 1, 1, 1) + >>> (axis, angle) = q.to_axis_angle() + >>> axis + (sqrt(3)/3, sqrt(3)/3, sqrt(3)/3) + >>> angle + 2*pi/3 + + """ + q = self + if q.a.is_negative: + q = q * -1 + + q = q.normalize() + angle = trigsimp(2 * acos(q.a)) + + # Since quaternion is normalised, q.a is less than 1. + s = sqrt(1 - q.a*q.a) + + x = trigsimp(q.b / s) + y = trigsimp(q.c / s) + z = trigsimp(q.d / s) + + v = (x, y, z) + t = (v, angle) + + return t + + def to_rotation_matrix(self, v=None, homogeneous=True): + """Returns the equivalent rotation transformation matrix of the quaternion + which represents rotation about the origin if ``v`` is not passed. + + Parameters + ========== + + v : tuple or None + Default value: None + homogeneous : bool + When True, gives an expression that may be more efficient for + symbolic calculations but less so for direct evaluation. Both + formulas are mathematically equivalent. + Default value: True + + Returns + ======= + + tuple + Returns the equivalent rotation transformation matrix of the quaternion + which represents rotation about the origin if v is not passed. + + Examples + ======== + + >>> from sympy import Quaternion + >>> from sympy import symbols, trigsimp, cos, sin + >>> x = symbols('x') + >>> q = Quaternion(cos(x/2), 0, 0, sin(x/2)) + >>> trigsimp(q.to_rotation_matrix()) + Matrix([ + [cos(x), -sin(x), 0], + [sin(x), cos(x), 0], + [ 0, 0, 1]]) + + Generates a 4x4 transformation matrix (used for rotation about a point + other than the origin) if the point(v) is passed as an argument. + """ + + q = self + s = q.norm()**-2 + + # diagonal elements are different according to parameter normal + if homogeneous: + m00 = s*(q.a**2 + q.b**2 - q.c**2 - q.d**2) + m11 = s*(q.a**2 - q.b**2 + q.c**2 - q.d**2) + m22 = s*(q.a**2 - q.b**2 - q.c**2 + q.d**2) + else: + m00 = 1 - 2*s*(q.c**2 + q.d**2) + m11 = 1 - 2*s*(q.b**2 + q.d**2) + m22 = 1 - 2*s*(q.b**2 + q.c**2) + + m01 = 2*s*(q.b*q.c - q.d*q.a) + m02 = 2*s*(q.b*q.d + q.c*q.a) + + m10 = 2*s*(q.b*q.c + q.d*q.a) + m12 = 2*s*(q.c*q.d - q.b*q.a) + + m20 = 2*s*(q.b*q.d - q.c*q.a) + m21 = 2*s*(q.c*q.d + q.b*q.a) + + if not v: + return Matrix([[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]]) + + else: + (x, y, z) = v + + m03 = x - x*m00 - y*m01 - z*m02 + m13 = y - x*m10 - y*m11 - z*m12 + m23 = z - x*m20 - y*m21 - z*m22 + m30 = m31 = m32 = 0 + m33 = 1 + + return Matrix([[m00, m01, m02, m03], [m10, m11, m12, m13], + [m20, m21, m22, m23], [m30, m31, m32, m33]]) + + def scalar_part(self): + r"""Returns scalar part($\mathbf{S}(q)$) of the quaternion q. + + Explanation + =========== + + Given a quaternion $q = a + bi + cj + dk$, returns $\mathbf{S}(q) = a$. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(4, 8, 13, 12) + >>> q.scalar_part() + 4 + + """ + + return self.a + + def vector_part(self): + r""" + Returns $\mathbf{V}(q)$, the vector part of the quaternion $q$. + + Explanation + =========== + + Given a quaternion $q = a + bi + cj + dk$, returns $\mathbf{V}(q) = bi + cj + dk$. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(1, 1, 1, 1) + >>> q.vector_part() + 0 + 1*i + 1*j + 1*k + + >>> q = Quaternion(4, 8, 13, 12) + >>> q.vector_part() + 0 + 8*i + 13*j + 12*k + + """ + + return Quaternion(0, self.b, self.c, self.d) + + def axis(self): + r""" + Returns $\mathbf{Ax}(q)$, the axis of the quaternion $q$. + + Explanation + =========== + + Given a quaternion $q = a + bi + cj + dk$, returns $\mathbf{Ax}(q)$ i.e., the versor of the vector part of that quaternion + equal to $\mathbf{U}[\mathbf{V}(q)]$. + The axis is always an imaginary unit with square equal to $-1 + 0i + 0j + 0k$. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(1, 1, 1, 1) + >>> q.axis() + 0 + sqrt(3)/3*i + sqrt(3)/3*j + sqrt(3)/3*k + + See Also + ======== + + vector_part + + """ + axis = self.vector_part().normalize() + + return Quaternion(0, axis.b, axis.c, axis.d) + + def is_pure(self): + """ + Returns true if the quaternion is pure, false if the quaternion is not pure + or returns none if it is unknown. + + Explanation + =========== + + A pure quaternion (also a vector quaternion) is a quaternion with scalar + part equal to 0. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(0, 8, 13, 12) + >>> q.is_pure() + True + + See Also + ======== + scalar_part + + """ + + return self.a.is_zero + + def is_zero_quaternion(self): + """ + Returns true if the quaternion is a zero quaternion or false if it is not a zero quaternion + and None if the value is unknown. + + Explanation + =========== + + A zero quaternion is a quaternion with both scalar part and + vector part equal to 0. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(1, 0, 0, 0) + >>> q.is_zero_quaternion() + False + + >>> q = Quaternion(0, 0, 0, 0) + >>> q.is_zero_quaternion() + True + + See Also + ======== + scalar_part + vector_part + + """ + + return self.norm().is_zero + + def angle(self): + r""" + Returns the angle of the quaternion measured in the real-axis plane. + + Explanation + =========== + + Given a quaternion $q = a + bi + cj + dk$ where $a$, $b$, $c$ and $d$ + are real numbers, returns the angle of the quaternion given by + + .. math:: + \theta := 2 \operatorname{atan_2}\left(\sqrt{b^2 + c^2 + d^2}, {a}\right) + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(1, 4, 4, 4) + >>> q.angle() + 2*atan(4*sqrt(3)) + + """ + + return 2 * atan2(self.vector_part().norm(), self.scalar_part()) + + + def arc_coplanar(self, other): + """ + Returns True if the transformation arcs represented by the input quaternions happen in the same plane. + + Explanation + =========== + + Two quaternions are said to be coplanar (in this arc sense) when their axes are parallel. + The plane of a quaternion is the one normal to its axis. + + Parameters + ========== + + other : a Quaternion + + Returns + ======= + + True : if the planes of the two quaternions are the same, apart from its orientation/sign. + False : if the planes of the two quaternions are not the same, apart from its orientation/sign. + None : if plane of either of the quaternion is unknown. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q1 = Quaternion(1, 4, 4, 4) + >>> q2 = Quaternion(3, 8, 8, 8) + >>> Quaternion.arc_coplanar(q1, q2) + True + + >>> q1 = Quaternion(2, 8, 13, 12) + >>> Quaternion.arc_coplanar(q1, q2) + False + + See Also + ======== + + vector_coplanar + is_pure + + """ + if (self.is_zero_quaternion()) or (other.is_zero_quaternion()): + raise ValueError('Neither of the given quaternions can be 0') + + return fuzzy_or([(self.axis() - other.axis()).is_zero_quaternion(), (self.axis() + other.axis()).is_zero_quaternion()]) + + @classmethod + def vector_coplanar(cls, q1, q2, q3): + r""" + Returns True if the axis of the pure quaternions seen as 3D vectors + ``q1``, ``q2``, and ``q3`` are coplanar. + + Explanation + =========== + + Three pure quaternions are vector coplanar if the quaternions seen as 3D vectors are coplanar. + + Parameters + ========== + + q1 + A pure Quaternion. + q2 + A pure Quaternion. + q3 + A pure Quaternion. + + Returns + ======= + + True : if the axis of the pure quaternions seen as 3D vectors + q1, q2, and q3 are coplanar. + False : if the axis of the pure quaternions seen as 3D vectors + q1, q2, and q3 are not coplanar. + None : if the axis of the pure quaternions seen as 3D vectors + q1, q2, and q3 are coplanar is unknown. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q1 = Quaternion(0, 4, 4, 4) + >>> q2 = Quaternion(0, 8, 8, 8) + >>> q3 = Quaternion(0, 24, 24, 24) + >>> Quaternion.vector_coplanar(q1, q2, q3) + True + + >>> q1 = Quaternion(0, 8, 16, 8) + >>> q2 = Quaternion(0, 8, 3, 12) + >>> Quaternion.vector_coplanar(q1, q2, q3) + False + + See Also + ======== + + axis + is_pure + + """ + + if fuzzy_not(q1.is_pure()) or fuzzy_not(q2.is_pure()) or fuzzy_not(q3.is_pure()): + raise ValueError('The given quaternions must be pure') + + M = Matrix([[q1.b, q1.c, q1.d], [q2.b, q2.c, q2.d], [q3.b, q3.c, q3.d]]).det() + return M.is_zero + + def parallel(self, other): + """ + Returns True if the two pure quaternions seen as 3D vectors are parallel. + + Explanation + =========== + + Two pure quaternions are called parallel when their vector product is commutative which + implies that the quaternions seen as 3D vectors have same direction. + + Parameters + ========== + + other : a Quaternion + + Returns + ======= + + True : if the two pure quaternions seen as 3D vectors are parallel. + False : if the two pure quaternions seen as 3D vectors are not parallel. + None : if the two pure quaternions seen as 3D vectors are parallel is unknown. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(0, 4, 4, 4) + >>> q1 = Quaternion(0, 8, 8, 8) + >>> q.parallel(q1) + True + + >>> q1 = Quaternion(0, 8, 13, 12) + >>> q.parallel(q1) + False + + """ + + if fuzzy_not(self.is_pure()) or fuzzy_not(other.is_pure()): + raise ValueError('The provided quaternions must be pure') + + return (self*other - other*self).is_zero_quaternion() + + def orthogonal(self, other): + """ + Returns the orthogonality of two quaternions. + + Explanation + =========== + + Two pure quaternions are called orthogonal when their product is anti-commutative. + + Parameters + ========== + + other : a Quaternion + + Returns + ======= + + True : if the two pure quaternions seen as 3D vectors are orthogonal. + False : if the two pure quaternions seen as 3D vectors are not orthogonal. + None : if the two pure quaternions seen as 3D vectors are orthogonal is unknown. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(0, 4, 4, 4) + >>> q1 = Quaternion(0, 8, 8, 8) + >>> q.orthogonal(q1) + False + + >>> q1 = Quaternion(0, 2, 2, 0) + >>> q = Quaternion(0, 2, -2, 0) + >>> q.orthogonal(q1) + True + + """ + + if fuzzy_not(self.is_pure()) or fuzzy_not(other.is_pure()): + raise ValueError('The given quaternions must be pure') + + return (self*other + other*self).is_zero_quaternion() + + def index_vector(self): + r""" + Returns the index vector of the quaternion. + + Explanation + =========== + + The index vector is given by $\mathbf{T}(q)$, the norm (or magnitude) of + the quaternion $q$, multiplied by $\mathbf{Ax}(q)$, the axis of $q$. + + Returns + ======= + + Quaternion: representing index vector of the provided quaternion. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(2, 4, 2, 4) + >>> q.index_vector() + 0 + 4*sqrt(10)/3*i + 2*sqrt(10)/3*j + 4*sqrt(10)/3*k + + See Also + ======== + + axis + norm + + """ + + return self.norm() * self.axis() + + def mensor(self): + """ + Returns the natural logarithm of the norm(magnitude) of the quaternion. + + Examples + ======== + + >>> from sympy.algebras.quaternion import Quaternion + >>> q = Quaternion(2, 4, 2, 4) + >>> q.mensor() + log(2*sqrt(10)) + >>> q.norm() + 2*sqrt(10) + + See Also + ======== + + norm + + """ + + return ln(self.norm()) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..af862653f3ce0eeb67f7764e16c32f3466e87024 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/__init__.py @@ -0,0 +1,18 @@ +""" +A module to implement logical predicates and assumption system. +""" + +from .assume import ( + AppliedPredicate, Predicate, AssumptionsContext, assuming, + global_assumptions +) +from .ask import Q, ask, register_handler, remove_handler +from .refine import refine +from .relation import BinaryRelation, AppliedBinaryRelation + +__all__ = [ + 'AppliedPredicate', 'Predicate', 'AssumptionsContext', 'assuming', + 'global_assumptions', 'Q', 'ask', 'register_handler', 'remove_handler', + 'refine', + 'BinaryRelation', 'AppliedBinaryRelation' +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/ask.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/ask.py new file mode 100644 index 0000000000000000000000000000000000000000..ec81ec8ecce245c2a798cf9e71af1e9373292bc1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/ask.py @@ -0,0 +1,651 @@ +"""Module for querying SymPy objects about assumptions.""" + +from sympy.assumptions.assume import (global_assumptions, Predicate, + AppliedPredicate) +from sympy.assumptions.cnf import CNF, EncodedCNF, Literal +from sympy.core import sympify +from sympy.core.kind import BooleanKind +from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le +from sympy.logic.inference import satisfiable +from sympy.utilities.decorator import memoize_property +from sympy.utilities.exceptions import (sympy_deprecation_warning, + SymPyDeprecationWarning, + ignore_warnings) + + +# Memoization is necessary for the properties of AssumptionKeys to +# ensure that only one object of Predicate objects are created. +# This is because assumption handlers are registered on those objects. + + +class AssumptionKeys: + """ + This class contains all the supported keys by ``ask``. + It should be accessed via the instance ``sympy.Q``. + + """ + + # DO NOT add methods or properties other than predicate keys. + # SAT solver checks the properties of Q and use them to compute the + # fact system. Non-predicate attributes will break this. + + @memoize_property + def hermitian(self): + from .handlers.sets import HermitianPredicate + return HermitianPredicate() + + @memoize_property + def antihermitian(self): + from .handlers.sets import AntihermitianPredicate + return AntihermitianPredicate() + + @memoize_property + def real(self): + from .handlers.sets import RealPredicate + return RealPredicate() + + @memoize_property + def extended_real(self): + from .handlers.sets import ExtendedRealPredicate + return ExtendedRealPredicate() + + @memoize_property + def imaginary(self): + from .handlers.sets import ImaginaryPredicate + return ImaginaryPredicate() + + @memoize_property + def complex(self): + from .handlers.sets import ComplexPredicate + return ComplexPredicate() + + @memoize_property + def algebraic(self): + from .handlers.sets import AlgebraicPredicate + return AlgebraicPredicate() + + @memoize_property + def transcendental(self): + from .predicates.sets import TranscendentalPredicate + return TranscendentalPredicate() + + @memoize_property + def integer(self): + from .handlers.sets import IntegerPredicate + return IntegerPredicate() + + @memoize_property + def noninteger(self): + from .predicates.sets import NonIntegerPredicate + return NonIntegerPredicate() + + @memoize_property + def rational(self): + from .handlers.sets import RationalPredicate + return RationalPredicate() + + @memoize_property + def irrational(self): + from .handlers.sets import IrrationalPredicate + return IrrationalPredicate() + + @memoize_property + def finite(self): + from .handlers.calculus import FinitePredicate + return FinitePredicate() + + @memoize_property + def infinite(self): + from .handlers.calculus import InfinitePredicate + return InfinitePredicate() + + @memoize_property + def positive_infinite(self): + from .handlers.calculus import PositiveInfinitePredicate + return PositiveInfinitePredicate() + + @memoize_property + def negative_infinite(self): + from .handlers.calculus import NegativeInfinitePredicate + return NegativeInfinitePredicate() + + @memoize_property + def positive(self): + from .handlers.order import PositivePredicate + return PositivePredicate() + + @memoize_property + def negative(self): + from .handlers.order import NegativePredicate + return NegativePredicate() + + @memoize_property + def zero(self): + from .handlers.order import ZeroPredicate + return ZeroPredicate() + + @memoize_property + def extended_positive(self): + from .handlers.order import ExtendedPositivePredicate + return ExtendedPositivePredicate() + + @memoize_property + def extended_negative(self): + from .handlers.order import ExtendedNegativePredicate + return ExtendedNegativePredicate() + + @memoize_property + def nonzero(self): + from .handlers.order import NonZeroPredicate + return NonZeroPredicate() + + @memoize_property + def nonpositive(self): + from .handlers.order import NonPositivePredicate + return NonPositivePredicate() + + @memoize_property + def nonnegative(self): + from .handlers.order import NonNegativePredicate + return NonNegativePredicate() + + @memoize_property + def extended_nonzero(self): + from .handlers.order import ExtendedNonZeroPredicate + return ExtendedNonZeroPredicate() + + @memoize_property + def extended_nonpositive(self): + from .handlers.order import ExtendedNonPositivePredicate + return ExtendedNonPositivePredicate() + + @memoize_property + def extended_nonnegative(self): + from .handlers.order import ExtendedNonNegativePredicate + return ExtendedNonNegativePredicate() + + @memoize_property + def even(self): + from .handlers.ntheory import EvenPredicate + return EvenPredicate() + + @memoize_property + def odd(self): + from .handlers.ntheory import OddPredicate + return OddPredicate() + + @memoize_property + def prime(self): + from .handlers.ntheory import PrimePredicate + return PrimePredicate() + + @memoize_property + def composite(self): + from .handlers.ntheory import CompositePredicate + return CompositePredicate() + + @memoize_property + def commutative(self): + from .handlers.common import CommutativePredicate + return CommutativePredicate() + + @memoize_property + def is_true(self): + from .handlers.common import IsTruePredicate + return IsTruePredicate() + + @memoize_property + def symmetric(self): + from .handlers.matrices import SymmetricPredicate + return SymmetricPredicate() + + @memoize_property + def invertible(self): + from .handlers.matrices import InvertiblePredicate + return InvertiblePredicate() + + @memoize_property + def orthogonal(self): + from .handlers.matrices import OrthogonalPredicate + return OrthogonalPredicate() + + @memoize_property + def unitary(self): + from .handlers.matrices import UnitaryPredicate + return UnitaryPredicate() + + @memoize_property + def positive_definite(self): + from .handlers.matrices import PositiveDefinitePredicate + return PositiveDefinitePredicate() + + @memoize_property + def upper_triangular(self): + from .handlers.matrices import UpperTriangularPredicate + return UpperTriangularPredicate() + + @memoize_property + def lower_triangular(self): + from .handlers.matrices import LowerTriangularPredicate + return LowerTriangularPredicate() + + @memoize_property + def diagonal(self): + from .handlers.matrices import DiagonalPredicate + return DiagonalPredicate() + + @memoize_property + def fullrank(self): + from .handlers.matrices import FullRankPredicate + return FullRankPredicate() + + @memoize_property + def square(self): + from .handlers.matrices import SquarePredicate + return SquarePredicate() + + @memoize_property + def integer_elements(self): + from .handlers.matrices import IntegerElementsPredicate + return IntegerElementsPredicate() + + @memoize_property + def real_elements(self): + from .handlers.matrices import RealElementsPredicate + return RealElementsPredicate() + + @memoize_property + def complex_elements(self): + from .handlers.matrices import ComplexElementsPredicate + return ComplexElementsPredicate() + + @memoize_property + def singular(self): + from .predicates.matrices import SingularPredicate + return SingularPredicate() + + @memoize_property + def normal(self): + from .predicates.matrices import NormalPredicate + return NormalPredicate() + + @memoize_property + def triangular(self): + from .predicates.matrices import TriangularPredicate + return TriangularPredicate() + + @memoize_property + def unit_triangular(self): + from .predicates.matrices import UnitTriangularPredicate + return UnitTriangularPredicate() + + @memoize_property + def eq(self): + from .relation.equality import EqualityPredicate + return EqualityPredicate() + + @memoize_property + def ne(self): + from .relation.equality import UnequalityPredicate + return UnequalityPredicate() + + @memoize_property + def gt(self): + from .relation.equality import StrictGreaterThanPredicate + return StrictGreaterThanPredicate() + + @memoize_property + def ge(self): + from .relation.equality import GreaterThanPredicate + return GreaterThanPredicate() + + @memoize_property + def lt(self): + from .relation.equality import StrictLessThanPredicate + return StrictLessThanPredicate() + + @memoize_property + def le(self): + from .relation.equality import LessThanPredicate + return LessThanPredicate() + + +Q = AssumptionKeys() + +def _extract_all_facts(assump, exprs): + """ + Extract all relevant assumptions from *assump* with respect to given *exprs*. + + Parameters + ========== + + assump : sympy.assumptions.cnf.CNF + + exprs : tuple of expressions + + Returns + ======= + + sympy.assumptions.cnf.CNF + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.assumptions.ask import _extract_all_facts + >>> from sympy.abc import x, y + >>> assump = CNF.from_prop(Q.positive(x) & Q.integer(y)) + >>> exprs = (x,) + >>> cnf = _extract_all_facts(assump, exprs) + >>> cnf.clauses + {frozenset({Literal(Q.positive, False)})} + + """ + facts = set() + + for clause in assump.clauses: + args = [] + for literal in clause: + if isinstance(literal.lit, AppliedPredicate) and len(literal.lit.arguments) == 1: + if literal.lit.arg in exprs: + # Add literal if it has matching in it + args.append(Literal(literal.lit.function, literal.is_Not)) + else: + # If any of the literals doesn't have matching expr don't add the whole clause. + break + else: + # If any of the literals aren't unary predicate don't add the whole clause. + break + + else: + if args: + facts.add(frozenset(args)) + return CNF(facts) + + +def ask(proposition, assumptions=True, context=global_assumptions): + """ + Function to evaluate the proposition with assumptions. + + Explanation + =========== + + This function evaluates the proposition to ``True`` or ``False`` if + the truth value can be determined. If not, it returns ``None``. + + It should be discerned from :func:`~.refine` which, when applied to a + proposition, simplifies the argument to symbolic ``Boolean`` instead of + Python built-in ``True``, ``False`` or ``None``. + + **Syntax** + + * ask(proposition) + Evaluate the *proposition* in global assumption context. + + * ask(proposition, assumptions) + Evaluate the *proposition* with respect to *assumptions* in + global assumption context. + + Parameters + ========== + + proposition : Boolean + Proposition which will be evaluated to boolean value. If this is + not ``AppliedPredicate``, it will be wrapped by ``Q.is_true``. + + assumptions : Boolean, optional + Local assumptions to evaluate the *proposition*. + + context : AssumptionsContext, optional + Default assumptions to evaluate the *proposition*. By default, + this is ``sympy.assumptions.global_assumptions`` variable. + + Returns + ======= + + ``True``, ``False``, or ``None`` + + Raises + ====== + + TypeError : *proposition* or *assumptions* is not valid logical expression. + + ValueError : assumptions are inconsistent. + + Examples + ======== + + >>> from sympy import ask, Q, pi + >>> from sympy.abc import x, y + >>> ask(Q.rational(pi)) + False + >>> ask(Q.even(x*y), Q.even(x) & Q.integer(y)) + True + >>> ask(Q.prime(4*x), Q.integer(x)) + False + + If the truth value cannot be determined, ``None`` will be returned. + + >>> print(ask(Q.odd(3*x))) # cannot determine unless we know x + None + + ``ValueError`` is raised if assumptions are inconsistent. + + >>> ask(Q.integer(x), Q.even(x) & Q.odd(x)) + Traceback (most recent call last): + ... + ValueError: inconsistent assumptions Q.even(x) & Q.odd(x) + + Notes + ===== + + Relations in assumptions are not implemented (yet), so the following + will not give a meaningful result. + + >>> ask(Q.positive(x), x > 0) + + It is however a work in progress. + + See Also + ======== + + sympy.assumptions.refine.refine : Simplification using assumptions. + Proposition is not reduced to ``None`` if the truth value cannot + be determined. + """ + from sympy.assumptions.satask import satask + from sympy.assumptions.lra_satask import lra_satask + from sympy.logic.algorithms.lra_theory import UnhandledInput + + proposition = sympify(proposition) + assumptions = sympify(assumptions) + + if isinstance(proposition, Predicate) or proposition.kind is not BooleanKind: + raise TypeError("proposition must be a valid logical expression") + + if isinstance(assumptions, Predicate) or assumptions.kind is not BooleanKind: + raise TypeError("assumptions must be a valid logical expression") + + binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le} + if isinstance(proposition, AppliedPredicate): + key, args = proposition.function, proposition.arguments + elif proposition.func in binrelpreds: + key, args = binrelpreds[type(proposition)], proposition.args + else: + key, args = Q.is_true, (proposition,) + + # convert local and global assumptions to CNF + assump_cnf = CNF.from_prop(assumptions) + assump_cnf.extend(context) + + # extract the relevant facts from assumptions with respect to args + local_facts = _extract_all_facts(assump_cnf, args) + + # convert default facts and assumed facts to encoded CNF + known_facts_cnf = get_all_known_facts() + enc_cnf = EncodedCNF() + enc_cnf.from_cnf(CNF(known_facts_cnf)) + enc_cnf.add_from_cnf(local_facts) + + # check the satisfiability of given assumptions + if local_facts.clauses and satisfiable(enc_cnf) is False: + raise ValueError("inconsistent assumptions %s" % assumptions) + + # quick computation for single fact + res = _ask_single_fact(key, local_facts) + if res is not None: + return res + + # direct resolution method, no logic + res = key(*args)._eval_ask(assumptions) + if res is not None: + return bool(res) + + # using satask (still costly) + res = satask(proposition, assumptions=assumptions, context=context) + if res is not None: + return res + + try: + res = lra_satask(proposition, assumptions=assumptions, context=context) + except UnhandledInput: + return None + + return res + + +def _ask_single_fact(key, local_facts): + """ + Compute the truth value of single predicate using assumptions. + + Parameters + ========== + + key : sympy.assumptions.assume.Predicate + Proposition predicate. + + local_facts : sympy.assumptions.cnf.CNF + Local assumption in CNF form. + + Returns + ======= + + ``True``, ``False`` or ``None`` + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.assumptions.ask import _ask_single_fact + + If prerequisite of proposition is rejected by the assumption, + return ``False``. + + >>> key, assump = Q.zero, ~Q.zero + >>> local_facts = CNF.from_prop(assump) + >>> _ask_single_fact(key, local_facts) + False + >>> key, assump = Q.zero, ~Q.even + >>> local_facts = CNF.from_prop(assump) + >>> _ask_single_fact(key, local_facts) + False + + If assumption implies the proposition, return ``True``. + + >>> key, assump = Q.even, Q.zero + >>> local_facts = CNF.from_prop(assump) + >>> _ask_single_fact(key, local_facts) + True + + If proposition rejects the assumption, return ``False``. + + >>> key, assump = Q.even, Q.odd + >>> local_facts = CNF.from_prop(assump) + >>> _ask_single_fact(key, local_facts) + False + """ + if local_facts.clauses: + + known_facts_dict = get_known_facts_dict() + + if len(local_facts.clauses) == 1: + cl, = local_facts.clauses + if len(cl) == 1: + f, = cl + prop_facts = known_facts_dict.get(key, None) + prop_req = prop_facts[0] if prop_facts is not None else set() + if f.is_Not and f.arg in prop_req: + # the prerequisite of proposition is rejected + return False + + for clause in local_facts.clauses: + if len(clause) == 1: + f, = clause + prop_facts = known_facts_dict.get(f.arg, None) if not f.is_Not else None + if prop_facts is None: + continue + + prop_req, prop_rej = prop_facts + if key in prop_req: + # assumption implies the proposition + return True + elif key in prop_rej: + # proposition rejects the assumption + return False + + return None + + +def register_handler(key, handler): + """ + Register a handler in the ask system. key must be a string and handler a + class inheriting from AskHandler. + + .. deprecated:: 1.8. + Use multipledispatch handler instead. See :obj:`~.Predicate`. + + """ + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. The register_handler() function + should be replaced with the multipledispatch handler of Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + ) + if isinstance(key, Predicate): + key = key.name.name + Qkey = getattr(Q, key, None) + if Qkey is not None: + Qkey.add_handler(handler) + else: + setattr(Q, key, Predicate(key, handlers=[handler])) + + +def remove_handler(key, handler): + """ + Removes a handler from the ask system. + + .. deprecated:: 1.8. + Use multipledispatch handler instead. See :obj:`~.Predicate`. + + """ + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. The remove_handler() function + should be replaced with the multipledispatch handler of Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + ) + if isinstance(key, Predicate): + key = key.name.name + # Don't show the same warning again recursively + with ignore_warnings(SymPyDeprecationWarning): + getattr(Q, key).remove_handler(handler) + + +from sympy.assumptions.ask_generated import (get_all_known_facts, + get_known_facts_dict) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/ask_generated.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/ask_generated.py new file mode 100644 index 0000000000000000000000000000000000000000..d90cdffc1e127d78e18f70cda13d8d5e0530d41b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/ask_generated.py @@ -0,0 +1,352 @@ +""" +Do NOT manually edit this file. +Instead, run ./bin/ask_update.py. +""" + +from sympy.assumptions.ask import Q +from sympy.assumptions.cnf import Literal +from sympy.core.cache import cacheit + +@cacheit +def get_all_known_facts(): + """ + Known facts between unary predicates as CNF clauses. + """ + return { + frozenset((Literal(Q.algebraic, False), Literal(Q.imaginary, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.negative, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.positive, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.rational, True))), + frozenset((Literal(Q.algebraic, False), Literal(Q.transcendental, False), Literal(Q.zero, True))), + frozenset((Literal(Q.algebraic, True), Literal(Q.finite, False))), + frozenset((Literal(Q.algebraic, True), Literal(Q.transcendental, True))), + frozenset((Literal(Q.antihermitian, False), Literal(Q.hermitian, False), Literal(Q.zero, True))), + frozenset((Literal(Q.antihermitian, False), Literal(Q.imaginary, True))), + frozenset((Literal(Q.commutative, False), Literal(Q.finite, True))), + frozenset((Literal(Q.commutative, False), Literal(Q.infinite, True))), + frozenset((Literal(Q.complex_elements, False), Literal(Q.real_elements, True))), + frozenset((Literal(Q.composite, False), Literal(Q.even, True), Literal(Q.positive, True), Literal(Q.prime, False))), + frozenset((Literal(Q.composite, True), Literal(Q.even, False), Literal(Q.odd, False))), + frozenset((Literal(Q.composite, True), Literal(Q.positive, False))), + frozenset((Literal(Q.composite, True), Literal(Q.prime, True))), + frozenset((Literal(Q.diagonal, False), Literal(Q.lower_triangular, True), Literal(Q.upper_triangular, True))), + frozenset((Literal(Q.diagonal, True), Literal(Q.lower_triangular, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.normal, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.symmetric, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.upper_triangular, False))), + frozenset((Literal(Q.even, False), Literal(Q.odd, False), Literal(Q.prime, True))), + frozenset((Literal(Q.even, False), Literal(Q.zero, True))), + frozenset((Literal(Q.even, True), Literal(Q.odd, True))), + frozenset((Literal(Q.even, True), Literal(Q.rational, False))), + frozenset((Literal(Q.finite, False), Literal(Q.transcendental, True))), + frozenset((Literal(Q.finite, True), Literal(Q.infinite, True))), + frozenset((Literal(Q.fullrank, False), Literal(Q.invertible, True))), + frozenset((Literal(Q.fullrank, True), Literal(Q.invertible, False), Literal(Q.square, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.negative, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.positive, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.zero, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.negative, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.positive, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.zero, True))), + frozenset((Literal(Q.infinite, False), Literal(Q.negative_infinite, True))), + frozenset((Literal(Q.infinite, False), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.integer_elements, True), Literal(Q.real_elements, False))), + frozenset((Literal(Q.invertible, False), Literal(Q.positive_definite, True))), + frozenset((Literal(Q.invertible, False), Literal(Q.singular, False))), + frozenset((Literal(Q.invertible, False), Literal(Q.unitary, True))), + frozenset((Literal(Q.invertible, True), Literal(Q.singular, True))), + frozenset((Literal(Q.invertible, True), Literal(Q.square, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.negative, True), Literal(Q.rational, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.positive, True), Literal(Q.rational, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.rational, False), Literal(Q.zero, True))), + frozenset((Literal(Q.irrational, True), Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.zero, False))), + frozenset((Literal(Q.irrational, True), Literal(Q.rational, True))), + frozenset((Literal(Q.lower_triangular, False), Literal(Q.triangular, True), Literal(Q.upper_triangular, False))), + frozenset((Literal(Q.lower_triangular, True), Literal(Q.triangular, False))), + frozenset((Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.rational, True), Literal(Q.zero, False))), + frozenset((Literal(Q.negative, True), Literal(Q.negative_infinite, True))), + frozenset((Literal(Q.negative, True), Literal(Q.positive, True))), + frozenset((Literal(Q.negative, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.negative, True), Literal(Q.zero, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.zero, True))), + frozenset((Literal(Q.normal, False), Literal(Q.unitary, True))), + frozenset((Literal(Q.normal, True), Literal(Q.square, False))), + frozenset((Literal(Q.odd, True), Literal(Q.rational, False))), + frozenset((Literal(Q.orthogonal, False), Literal(Q.real_elements, True), Literal(Q.unitary, True))), + frozenset((Literal(Q.orthogonal, True), Literal(Q.positive_definite, False))), + frozenset((Literal(Q.orthogonal, True), Literal(Q.unitary, False))), + frozenset((Literal(Q.positive, False), Literal(Q.prime, True))), + frozenset((Literal(Q.positive, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.positive, True), Literal(Q.zero, True))), + frozenset((Literal(Q.positive_infinite, True), Literal(Q.zero, True))), + frozenset((Literal(Q.square, False), Literal(Q.symmetric, True))), + frozenset((Literal(Q.triangular, False), Literal(Q.unit_triangular, True))), + frozenset((Literal(Q.triangular, False), Literal(Q.upper_triangular, True))) + } + +@cacheit +def get_all_known_matrix_facts(): + """ + Known facts between unary predicates for matrices as CNF clauses. + """ + return { + frozenset((Literal(Q.complex_elements, False), Literal(Q.real_elements, True))), + frozenset((Literal(Q.diagonal, False), Literal(Q.lower_triangular, True), Literal(Q.upper_triangular, True))), + frozenset((Literal(Q.diagonal, True), Literal(Q.lower_triangular, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.normal, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.symmetric, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.upper_triangular, False))), + frozenset((Literal(Q.fullrank, False), Literal(Q.invertible, True))), + frozenset((Literal(Q.fullrank, True), Literal(Q.invertible, False), Literal(Q.square, True))), + frozenset((Literal(Q.integer_elements, True), Literal(Q.real_elements, False))), + frozenset((Literal(Q.invertible, False), Literal(Q.positive_definite, True))), + frozenset((Literal(Q.invertible, False), Literal(Q.singular, False))), + frozenset((Literal(Q.invertible, False), Literal(Q.unitary, True))), + frozenset((Literal(Q.invertible, True), Literal(Q.singular, True))), + frozenset((Literal(Q.invertible, True), Literal(Q.square, False))), + frozenset((Literal(Q.lower_triangular, False), Literal(Q.triangular, True), Literal(Q.upper_triangular, False))), + frozenset((Literal(Q.lower_triangular, True), Literal(Q.triangular, False))), + frozenset((Literal(Q.normal, False), Literal(Q.unitary, True))), + frozenset((Literal(Q.normal, True), Literal(Q.square, False))), + frozenset((Literal(Q.orthogonal, False), Literal(Q.real_elements, True), Literal(Q.unitary, True))), + frozenset((Literal(Q.orthogonal, True), Literal(Q.positive_definite, False))), + frozenset((Literal(Q.orthogonal, True), Literal(Q.unitary, False))), + frozenset((Literal(Q.square, False), Literal(Q.symmetric, True))), + frozenset((Literal(Q.triangular, False), Literal(Q.unit_triangular, True))), + frozenset((Literal(Q.triangular, False), Literal(Q.upper_triangular, True))) + } + +@cacheit +def get_all_known_number_facts(): + """ + Known facts between unary predicates for numbers as CNF clauses. + """ + return { + frozenset((Literal(Q.algebraic, False), Literal(Q.imaginary, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.negative, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.positive, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.rational, True))), + frozenset((Literal(Q.algebraic, False), Literal(Q.transcendental, False), Literal(Q.zero, True))), + frozenset((Literal(Q.algebraic, True), Literal(Q.finite, False))), + frozenset((Literal(Q.algebraic, True), Literal(Q.transcendental, True))), + frozenset((Literal(Q.antihermitian, False), Literal(Q.hermitian, False), Literal(Q.zero, True))), + frozenset((Literal(Q.antihermitian, False), Literal(Q.imaginary, True))), + frozenset((Literal(Q.commutative, False), Literal(Q.finite, True))), + frozenset((Literal(Q.commutative, False), Literal(Q.infinite, True))), + frozenset((Literal(Q.composite, False), Literal(Q.even, True), Literal(Q.positive, True), Literal(Q.prime, False))), + frozenset((Literal(Q.composite, True), Literal(Q.even, False), Literal(Q.odd, False))), + frozenset((Literal(Q.composite, True), Literal(Q.positive, False))), + frozenset((Literal(Q.composite, True), Literal(Q.prime, True))), + frozenset((Literal(Q.even, False), Literal(Q.odd, False), Literal(Q.prime, True))), + frozenset((Literal(Q.even, False), Literal(Q.zero, True))), + frozenset((Literal(Q.even, True), Literal(Q.odd, True))), + frozenset((Literal(Q.even, True), Literal(Q.rational, False))), + frozenset((Literal(Q.finite, False), Literal(Q.transcendental, True))), + frozenset((Literal(Q.finite, True), Literal(Q.infinite, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.negative, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.positive, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.zero, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.negative, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.positive, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.zero, True))), + frozenset((Literal(Q.infinite, False), Literal(Q.negative_infinite, True))), + frozenset((Literal(Q.infinite, False), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.irrational, False), Literal(Q.negative, True), Literal(Q.rational, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.positive, True), Literal(Q.rational, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.rational, False), Literal(Q.zero, True))), + frozenset((Literal(Q.irrational, True), Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.zero, False))), + frozenset((Literal(Q.irrational, True), Literal(Q.rational, True))), + frozenset((Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.rational, True), Literal(Q.zero, False))), + frozenset((Literal(Q.negative, True), Literal(Q.negative_infinite, True))), + frozenset((Literal(Q.negative, True), Literal(Q.positive, True))), + frozenset((Literal(Q.negative, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.negative, True), Literal(Q.zero, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.zero, True))), + frozenset((Literal(Q.odd, True), Literal(Q.rational, False))), + frozenset((Literal(Q.positive, False), Literal(Q.prime, True))), + frozenset((Literal(Q.positive, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.positive, True), Literal(Q.zero, True))), + frozenset((Literal(Q.positive_infinite, True), Literal(Q.zero, True))) + } + +@cacheit +def get_known_facts_dict(): + """ + Logical relations between unary predicates as dictionary. + + Each key is a predicate, and item is two groups of predicates. + First group contains the predicates which are implied by the key, and + second group contains the predicates which are rejected by the key. + + """ + return { + Q.algebraic: (set([Q.algebraic, Q.commutative, Q.complex, Q.finite]), + set([Q.infinite, Q.negative_infinite, Q.positive_infinite, + Q.transcendental])), + Q.antihermitian: (set([Q.antihermitian]), set([])), + Q.commutative: (set([Q.commutative]), set([])), + Q.complex: (set([Q.commutative, Q.complex, Q.finite]), + set([Q.infinite, Q.negative_infinite, Q.positive_infinite])), + Q.complex_elements: (set([Q.complex_elements]), set([])), + Q.composite: (set([Q.algebraic, Q.commutative, Q.complex, Q.composite, + Q.extended_nonnegative, Q.extended_nonzero, + Q.extended_positive, Q.extended_real, Q.finite, Q.hermitian, + Q.integer, Q.nonnegative, Q.nonzero, Q.positive, Q.rational, + Q.real]), set([Q.extended_negative, Q.extended_nonpositive, + Q.imaginary, Q.infinite, Q.irrational, Q.negative, + Q.negative_infinite, Q.nonpositive, Q.positive_infinite, + Q.prime, Q.transcendental, Q.zero])), + Q.diagonal: (set([Q.diagonal, Q.lower_triangular, Q.normal, Q.square, + Q.symmetric, Q.triangular, Q.upper_triangular]), set([])), + Q.even: (set([Q.algebraic, Q.commutative, Q.complex, Q.even, + Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.rational, + Q.real]), set([Q.imaginary, Q.infinite, Q.irrational, + Q.negative_infinite, Q.odd, Q.positive_infinite, + Q.transcendental])), + Q.extended_negative: (set([Q.commutative, Q.extended_negative, + Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real]), + set([Q.composite, Q.extended_nonnegative, Q.extended_positive, + Q.imaginary, Q.nonnegative, Q.positive, Q.positive_infinite, + Q.prime, Q.zero])), + Q.extended_nonnegative: (set([Q.commutative, Q.extended_nonnegative, + Q.extended_real]), set([Q.extended_negative, Q.imaginary, + Q.negative, Q.negative_infinite])), + Q.extended_nonpositive: (set([Q.commutative, Q.extended_nonpositive, + Q.extended_real]), set([Q.composite, Q.extended_positive, + Q.imaginary, Q.positive, Q.positive_infinite, Q.prime])), + Q.extended_nonzero: (set([Q.commutative, Q.extended_nonzero, + Q.extended_real]), set([Q.imaginary, Q.zero])), + Q.extended_positive: (set([Q.commutative, Q.extended_nonnegative, + Q.extended_nonzero, Q.extended_positive, Q.extended_real]), + set([Q.extended_negative, Q.extended_nonpositive, Q.imaginary, + Q.negative, Q.negative_infinite, Q.nonpositive, Q.zero])), + Q.extended_real: (set([Q.commutative, Q.extended_real]), + set([Q.imaginary])), + Q.finite: (set([Q.commutative, Q.finite]), set([Q.infinite, + Q.negative_infinite, Q.positive_infinite])), + Q.fullrank: (set([Q.fullrank]), set([])), + Q.hermitian: (set([Q.hermitian]), set([])), + Q.imaginary: (set([Q.antihermitian, Q.commutative, Q.complex, + Q.finite, Q.imaginary]), set([Q.composite, Q.even, + Q.extended_negative, Q.extended_nonnegative, + Q.extended_nonpositive, Q.extended_nonzero, + Q.extended_positive, Q.extended_real, Q.infinite, Q.integer, + Q.irrational, Q.negative, Q.negative_infinite, Q.nonnegative, + Q.nonpositive, Q.nonzero, Q.odd, Q.positive, + Q.positive_infinite, Q.prime, Q.rational, Q.real, Q.zero])), + Q.infinite: (set([Q.commutative, Q.infinite]), set([Q.algebraic, + Q.complex, Q.composite, Q.even, Q.finite, Q.imaginary, + Q.integer, Q.irrational, Q.negative, Q.nonnegative, + Q.nonpositive, Q.nonzero, Q.odd, Q.positive, Q.prime, + Q.rational, Q.real, Q.transcendental, Q.zero])), + Q.integer: (set([Q.algebraic, Q.commutative, Q.complex, + Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.rational, + Q.real]), set([Q.imaginary, Q.infinite, Q.irrational, + Q.negative_infinite, Q.positive_infinite, Q.transcendental])), + Q.integer_elements: (set([Q.complex_elements, Q.integer_elements, + Q.real_elements]), set([])), + Q.invertible: (set([Q.fullrank, Q.invertible, Q.square]), + set([Q.singular])), + Q.irrational: (set([Q.commutative, Q.complex, Q.extended_nonzero, + Q.extended_real, Q.finite, Q.hermitian, Q.irrational, + Q.nonzero, Q.real]), set([Q.composite, Q.even, Q.imaginary, + Q.infinite, Q.integer, Q.negative_infinite, Q.odd, + Q.positive_infinite, Q.prime, Q.rational, Q.zero])), + Q.is_true: (set([Q.is_true]), set([])), + Q.lower_triangular: (set([Q.lower_triangular, Q.triangular]), set([])), + Q.negative: (set([Q.commutative, Q.complex, Q.extended_negative, + Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real, + Q.finite, Q.hermitian, Q.negative, Q.nonpositive, Q.nonzero, + Q.real]), set([Q.composite, Q.extended_nonnegative, + Q.extended_positive, Q.imaginary, Q.infinite, + Q.negative_infinite, Q.nonnegative, Q.positive, + Q.positive_infinite, Q.prime, Q.zero])), + Q.negative_infinite: (set([Q.commutative, Q.extended_negative, + Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real, + Q.infinite, Q.negative_infinite]), set([Q.algebraic, + Q.complex, Q.composite, Q.even, Q.extended_nonnegative, + Q.extended_positive, Q.finite, Q.imaginary, Q.integer, + Q.irrational, Q.negative, Q.nonnegative, Q.nonpositive, + Q.nonzero, Q.odd, Q.positive, Q.positive_infinite, Q.prime, + Q.rational, Q.real, Q.transcendental, Q.zero])), + Q.noninteger: (set([Q.noninteger]), set([])), + Q.nonnegative: (set([Q.commutative, Q.complex, Q.extended_nonnegative, + Q.extended_real, Q.finite, Q.hermitian, Q.nonnegative, + Q.real]), set([Q.extended_negative, Q.imaginary, Q.infinite, + Q.negative, Q.negative_infinite, Q.positive_infinite])), + Q.nonpositive: (set([Q.commutative, Q.complex, Q.extended_nonpositive, + Q.extended_real, Q.finite, Q.hermitian, Q.nonpositive, + Q.real]), set([Q.composite, Q.extended_positive, Q.imaginary, + Q.infinite, Q.negative_infinite, Q.positive, + Q.positive_infinite, Q.prime])), + Q.nonzero: (set([Q.commutative, Q.complex, Q.extended_nonzero, + Q.extended_real, Q.finite, Q.hermitian, Q.nonzero, Q.real]), + set([Q.imaginary, Q.infinite, Q.negative_infinite, + Q.positive_infinite, Q.zero])), + Q.normal: (set([Q.normal, Q.square]), set([])), + Q.odd: (set([Q.algebraic, Q.commutative, Q.complex, + Q.extended_nonzero, Q.extended_real, Q.finite, Q.hermitian, + Q.integer, Q.nonzero, Q.odd, Q.rational, Q.real]), + set([Q.even, Q.imaginary, Q.infinite, Q.irrational, + Q.negative_infinite, Q.positive_infinite, Q.transcendental, + Q.zero])), + Q.orthogonal: (set([Q.fullrank, Q.invertible, Q.normal, Q.orthogonal, + Q.positive_definite, Q.square, Q.unitary]), set([Q.singular])), + Q.positive: (set([Q.commutative, Q.complex, Q.extended_nonnegative, + Q.extended_nonzero, Q.extended_positive, Q.extended_real, + Q.finite, Q.hermitian, Q.nonnegative, Q.nonzero, Q.positive, + Q.real]), set([Q.extended_negative, Q.extended_nonpositive, + Q.imaginary, Q.infinite, Q.negative, Q.negative_infinite, + Q.nonpositive, Q.positive_infinite, Q.zero])), + Q.positive_definite: (set([Q.fullrank, Q.invertible, + Q.positive_definite, Q.square]), set([Q.singular])), + Q.positive_infinite: (set([Q.commutative, Q.extended_nonnegative, + Q.extended_nonzero, Q.extended_positive, Q.extended_real, + Q.infinite, Q.positive_infinite]), set([Q.algebraic, + Q.complex, Q.composite, Q.even, Q.extended_negative, + Q.extended_nonpositive, Q.finite, Q.imaginary, Q.integer, + Q.irrational, Q.negative, Q.negative_infinite, Q.nonnegative, + Q.nonpositive, Q.nonzero, Q.odd, Q.positive, Q.prime, + Q.rational, Q.real, Q.transcendental, Q.zero])), + Q.prime: (set([Q.algebraic, Q.commutative, Q.complex, + Q.extended_nonnegative, Q.extended_nonzero, + Q.extended_positive, Q.extended_real, Q.finite, Q.hermitian, + Q.integer, Q.nonnegative, Q.nonzero, Q.positive, Q.prime, + Q.rational, Q.real]), set([Q.composite, Q.extended_negative, + Q.extended_nonpositive, Q.imaginary, Q.infinite, Q.irrational, + Q.negative, Q.negative_infinite, Q.nonpositive, + Q.positive_infinite, Q.transcendental, Q.zero])), + Q.rational: (set([Q.algebraic, Q.commutative, Q.complex, + Q.extended_real, Q.finite, Q.hermitian, Q.rational, Q.real]), + set([Q.imaginary, Q.infinite, Q.irrational, + Q.negative_infinite, Q.positive_infinite, Q.transcendental])), + Q.real: (set([Q.commutative, Q.complex, Q.extended_real, Q.finite, + Q.hermitian, Q.real]), set([Q.imaginary, Q.infinite, + Q.negative_infinite, Q.positive_infinite])), + Q.real_elements: (set([Q.complex_elements, Q.real_elements]), set([])), + Q.singular: (set([Q.singular]), set([Q.invertible, Q.orthogonal, + Q.positive_definite, Q.unitary])), + Q.square: (set([Q.square]), set([])), + Q.symmetric: (set([Q.square, Q.symmetric]), set([])), + Q.transcendental: (set([Q.commutative, Q.complex, Q.finite, + Q.transcendental]), set([Q.algebraic, Q.composite, Q.even, + Q.infinite, Q.integer, Q.negative_infinite, Q.odd, + Q.positive_infinite, Q.prime, Q.rational, Q.zero])), + Q.triangular: (set([Q.triangular]), set([])), + Q.unit_triangular: (set([Q.triangular, Q.unit_triangular]), set([])), + Q.unitary: (set([Q.fullrank, Q.invertible, Q.normal, Q.square, + Q.unitary]), set([Q.singular])), + Q.upper_triangular: (set([Q.triangular, Q.upper_triangular]), set([])), + Q.zero: (set([Q.algebraic, Q.commutative, Q.complex, Q.even, + Q.extended_nonnegative, Q.extended_nonpositive, + Q.extended_real, Q.finite, Q.hermitian, Q.integer, + Q.nonnegative, Q.nonpositive, Q.rational, Q.real, Q.zero]), + set([Q.composite, Q.extended_negative, Q.extended_nonzero, + Q.extended_positive, Q.imaginary, Q.infinite, Q.irrational, + Q.negative, Q.negative_infinite, Q.nonzero, Q.odd, Q.positive, + Q.positive_infinite, Q.prime, Q.transcendental])), + } diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/assume.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/assume.py new file mode 100644 index 0000000000000000000000000000000000000000..743195a865a1d39389d471b95728ca79834ed019 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/assume.py @@ -0,0 +1,485 @@ +"""A module which implements predicates and assumption context.""" + +from contextlib import contextmanager +import inspect +from sympy.core.symbol import Str +from sympy.core.sympify import _sympify +from sympy.logic.boolalg import Boolean, false, true +from sympy.multipledispatch.dispatcher import Dispatcher, str_signature +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import is_sequence +from sympy.utilities.source import get_class + + +class AssumptionsContext(set): + """ + Set containing default assumptions which are applied to the ``ask()`` + function. + + Explanation + =========== + + This is used to represent global assumptions, but you can also use this + class to create your own local assumptions contexts. It is basically a thin + wrapper to Python's set, so see its documentation for advanced usage. + + Examples + ======== + + The default assumption context is ``global_assumptions``, which is initially empty: + + >>> from sympy import ask, Q + >>> from sympy.assumptions import global_assumptions + >>> global_assumptions + AssumptionsContext() + + You can add default assumptions: + + >>> from sympy.abc import x + >>> global_assumptions.add(Q.real(x)) + >>> global_assumptions + AssumptionsContext({Q.real(x)}) + >>> ask(Q.real(x)) + True + + And remove them: + + >>> global_assumptions.remove(Q.real(x)) + >>> print(ask(Q.real(x))) + None + + The ``clear()`` method removes every assumption: + + >>> global_assumptions.add(Q.positive(x)) + >>> global_assumptions + AssumptionsContext({Q.positive(x)}) + >>> global_assumptions.clear() + >>> global_assumptions + AssumptionsContext() + + See Also + ======== + + assuming + + """ + + def add(self, *assumptions): + """Add assumptions.""" + for a in assumptions: + super().add(a) + + def _sympystr(self, printer): + if not self: + return "%s()" % self.__class__.__name__ + return "{}({})".format(self.__class__.__name__, printer._print_set(self)) + +global_assumptions = AssumptionsContext() + + +class AppliedPredicate(Boolean): + """ + The class of expressions resulting from applying ``Predicate`` to + the arguments. ``AppliedPredicate`` merely wraps its argument and + remain unevaluated. To evaluate it, use the ``ask()`` function. + + Examples + ======== + + >>> from sympy import Q, ask + >>> Q.integer(1) + Q.integer(1) + + The ``function`` attribute returns the predicate, and the ``arguments`` + attribute returns the tuple of arguments. + + >>> type(Q.integer(1)) + + >>> Q.integer(1).function + Q.integer + >>> Q.integer(1).arguments + (1,) + + Applied predicates can be evaluated to a boolean value with ``ask``: + + >>> ask(Q.integer(1)) + True + + """ + __slots__ = () + + def __new__(cls, predicate, *args): + if not isinstance(predicate, Predicate): + raise TypeError("%s is not a Predicate." % predicate) + args = map(_sympify, args) + return super().__new__(cls, predicate, *args) + + @property + def arg(self): + """ + Return the expression used by this assumption. + + Examples + ======== + + >>> from sympy import Q, Symbol + >>> x = Symbol('x') + >>> a = Q.integer(x + 1) + >>> a.arg + x + 1 + + """ + # Will be deprecated + args = self._args + if len(args) == 2: + # backwards compatibility + return args[1] + raise TypeError("'arg' property is allowed only for unary predicates.") + + @property + def function(self): + """ + Return the predicate. + """ + # Will be changed to self.args[0] after args overriding is removed + return self._args[0] + + @property + def arguments(self): + """ + Return the arguments which are applied to the predicate. + """ + # Will be changed to self.args[1:] after args overriding is removed + return self._args[1:] + + def _eval_ask(self, assumptions): + return self.function.eval(self.arguments, assumptions) + + @property + def binary_symbols(self): + from .ask import Q + if self.function == Q.is_true: + i = self.arguments[0] + if i.is_Boolean or i.is_Symbol: + return i.binary_symbols + if self.function in (Q.eq, Q.ne): + if true in self.arguments or false in self.arguments: + if self.arguments[0].is_Symbol: + return {self.arguments[0]} + elif self.arguments[1].is_Symbol: + return {self.arguments[1]} + return set() + + +class PredicateMeta(type): + def __new__(cls, clsname, bases, dct): + # If handler is not defined, assign empty dispatcher. + if "handler" not in dct: + name = f"Ask{clsname.capitalize()}Handler" + handler = Dispatcher(name, doc="Handler for key %s" % name) + dct["handler"] = handler + + dct["_orig_doc"] = dct.get("__doc__", "") + + return super().__new__(cls, clsname, bases, dct) + + @property + def __doc__(cls): + handler = cls.handler + doc = cls._orig_doc + if cls is not Predicate and handler is not None: + doc += "Handler\n" + doc += " =======\n\n" + + # Append the handler's doc without breaking sphinx documentation. + docs = [" Multiply dispatched method: %s" % handler.name] + if handler.doc: + for line in handler.doc.splitlines(): + if not line: + continue + docs.append(" %s" % line) + other = [] + for sig in handler.ordering[::-1]: + func = handler.funcs[sig] + if func.__doc__: + s = ' Inputs: <%s>' % str_signature(sig) + lines = [] + for line in func.__doc__.splitlines(): + lines.append(" %s" % line) + s += "\n".join(lines) + docs.append(s) + else: + other.append(str_signature(sig)) + if other: + othersig = " Other signatures:" + for line in other: + othersig += "\n * %s" % line + docs.append(othersig) + + doc += '\n\n'.join(docs) + + return doc + + +class Predicate(Boolean, metaclass=PredicateMeta): + """ + Base class for mathematical predicates. It also serves as a + constructor for undefined predicate objects. + + Explanation + =========== + + Predicate is a function that returns a boolean value [1]. + + Predicate function is object, and it is instance of predicate class. + When a predicate is applied to arguments, ``AppliedPredicate`` + instance is returned. This merely wraps the argument and remain + unevaluated. To obtain the truth value of applied predicate, use the + function ``ask``. + + Evaluation of predicate is done by multiple dispatching. You can + register new handler to the predicate to support new types. + + Every predicate in SymPy can be accessed via the property of ``Q``. + For example, ``Q.even`` returns the predicate which checks if the + argument is even number. + + To define a predicate which can be evaluated, you must subclass this + class, make an instance of it, and register it to ``Q``. After then, + dispatch the handler by argument types. + + If you directly construct predicate using this class, you will get + ``UndefinedPredicate`` which cannot be dispatched. This is useful + when you are building boolean expressions which do not need to be + evaluated. + + Examples + ======== + + Applying and evaluating to boolean value: + + >>> from sympy import Q, ask + >>> ask(Q.prime(7)) + True + + You can define a new predicate by subclassing and dispatching. Here, + we define a predicate for sexy primes [2] as an example. + + >>> from sympy import Predicate, Integer + >>> class SexyPrimePredicate(Predicate): + ... name = "sexyprime" + >>> Q.sexyprime = SexyPrimePredicate() + >>> @Q.sexyprime.register(Integer, Integer) + ... def _(int1, int2, assumptions): + ... args = sorted([int1, int2]) + ... if not all(ask(Q.prime(a), assumptions) for a in args): + ... return False + ... return args[1] - args[0] == 6 + >>> ask(Q.sexyprime(5, 11)) + True + + Direct constructing returns ``UndefinedPredicate``, which can be + applied but cannot be dispatched. + + >>> from sympy import Predicate, Integer + >>> Q.P = Predicate("P") + >>> type(Q.P) + + >>> Q.P(1) + Q.P(1) + >>> Q.P.register(Integer)(lambda expr, assump: True) + Traceback (most recent call last): + ... + TypeError: cannot be dispatched. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Predicate_%28mathematical_logic%29 + .. [2] https://en.wikipedia.org/wiki/Sexy_prime + + """ + + is_Atom = True + + def __new__(cls, *args, **kwargs): + if cls is Predicate: + return UndefinedPredicate(*args, **kwargs) + obj = super().__new__(cls, *args) + return obj + + @property + def name(self): + # May be overridden + return type(self).__name__ + + @classmethod + def register(cls, *types, **kwargs): + """ + Register the signature to the handler. + """ + if cls.handler is None: + raise TypeError("%s cannot be dispatched." % type(cls)) + return cls.handler.register(*types, **kwargs) + + @classmethod + def register_many(cls, *types, **kwargs): + """ + Register multiple signatures to same handler. + """ + def _(func): + for t in types: + if not is_sequence(t): + t = (t,) # for convenience, allow passing `type` to mean `(type,)` + cls.register(*t, **kwargs)(func) + return _ + + def __call__(self, *args): + return AppliedPredicate(self, *args) + + def eval(self, args, assumptions=True): + """ + Evaluate ``self(*args)`` under the given assumptions. + + This uses only direct resolution methods, not logical inference. + """ + result = None + try: + result = self.handler(*args, assumptions=assumptions) + except NotImplementedError: + pass + return result + + def _eval_refine(self, assumptions): + # When Predicate is no longer Boolean, delete this method + return self + + +class UndefinedPredicate(Predicate): + """ + Predicate without handler. + + Explanation + =========== + + This predicate is generated by using ``Predicate`` directly for + construction. It does not have a handler, and evaluating this with + arguments is done by SAT solver. + + Examples + ======== + + >>> from sympy import Predicate, Q + >>> Q.P = Predicate('P') + >>> Q.P.func + + >>> Q.P.name + Str('P') + + """ + + handler = None + + def __new__(cls, name, handlers=None): + # "handlers" parameter supports old design + if not isinstance(name, Str): + name = Str(name) + obj = super(Boolean, cls).__new__(cls, name) + obj.handlers = handlers or [] + return obj + + @property + def name(self): + return self.args[0] + + def _hashable_content(self): + return (self.name,) + + def __getnewargs__(self): + return (self.name,) + + def __call__(self, expr): + return AppliedPredicate(self, expr) + + def add_handler(self, handler): + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. Predicate.add_handler() + should be replaced with the multipledispatch handler of Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + ) + self.handlers.append(handler) + + def remove_handler(self, handler): + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. Predicate.remove_handler() + should be replaced with the multipledispatch handler of Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + ) + self.handlers.remove(handler) + + def eval(self, args, assumptions=True): + # Support for deprecated design + # When old design is removed, this will always return None + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. Evaluating UndefinedPredicate + objects should be replaced with the multipledispatch handler of + Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + stacklevel=5, + ) + expr, = args + res, _res = None, None + mro = inspect.getmro(type(expr)) + for handler in self.handlers: + cls = get_class(handler) + for subclass in mro: + eval_ = getattr(cls, subclass.__name__, None) + if eval_ is None: + continue + res = eval_(expr, assumptions) + # Do not stop if value returned is None + # Try to check for higher classes + if res is None: + continue + if _res is None: + _res = res + else: + # only check consistency if both resolutors have concluded + if _res != res: + raise ValueError('incompatible resolutors') + break + return res + + +@contextmanager +def assuming(*assumptions): + """ + Context manager for assumptions. + + Examples + ======== + + >>> from sympy import assuming, Q, ask + >>> from sympy.abc import x, y + >>> print(ask(Q.integer(x + y))) + None + >>> with assuming(Q.integer(x), Q.integer(y)): + ... print(ask(Q.integer(x + y))) + True + """ + old_global_assumptions = global_assumptions.copy() + global_assumptions.update(assumptions) + try: + yield + finally: + global_assumptions.clear() + global_assumptions.update(old_global_assumptions) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/cnf.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/cnf.py new file mode 100644 index 0000000000000000000000000000000000000000..a95d27bed6eeb64c42f4edd9d49bd8e5753069e5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/cnf.py @@ -0,0 +1,445 @@ +""" +The classes used here are for the internal use of assumptions system +only and should not be used anywhere else as these do not possess the +signatures common to SymPy objects. For general use of logic constructs +please refer to sympy.logic classes And, Or, Not, etc. +""" +from itertools import combinations, product, zip_longest +from sympy.assumptions.assume import AppliedPredicate, Predicate +from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le +from sympy.core.singleton import S +from sympy.logic.boolalg import Or, And, Not, Xnor +from sympy.logic.boolalg import (Equivalent, ITE, Implies, Nand, Nor, Xor) + + +class Literal: + """ + The smallest element of a CNF object. + + Parameters + ========== + + lit : Boolean expression + + is_Not : bool + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import Literal + >>> from sympy.abc import x + >>> Literal(Q.even(x)) + Literal(Q.even(x), False) + >>> Literal(~Q.even(x)) + Literal(Q.even(x), True) + """ + + def __new__(cls, lit, is_Not=False): + if isinstance(lit, Not): + lit = lit.args[0] + is_Not = True + elif isinstance(lit, (AND, OR, Literal)): + return ~lit if is_Not else lit + obj = super().__new__(cls) + obj.lit = lit + obj.is_Not = is_Not + return obj + + @property + def arg(self): + return self.lit + + def rcall(self, expr): + if callable(self.lit): + lit = self.lit(expr) + else: + lit = self.lit.apply(expr) + return type(self)(lit, self.is_Not) + + def __invert__(self): + is_Not = not self.is_Not + return Literal(self.lit, is_Not) + + def __str__(self): + return '{}({}, {})'.format(type(self).__name__, self.lit, self.is_Not) + + __repr__ = __str__ + + def __eq__(self, other): + return self.arg == other.arg and self.is_Not == other.is_Not + + def __hash__(self): + h = hash((type(self).__name__, self.arg, self.is_Not)) + return h + + +class OR: + """ + A low-level implementation for Or + """ + def __init__(self, *args): + self._args = args + + @property + def args(self): + return sorted(self._args, key=str) + + def rcall(self, expr): + return type(self)(*[arg.rcall(expr) + for arg in self._args + ]) + + def __invert__(self): + return AND(*[~arg for arg in self._args]) + + def __hash__(self): + return hash((type(self).__name__,) + tuple(self.args)) + + def __eq__(self, other): + return self.args == other.args + + def __str__(self): + s = '(' + ' | '.join([str(arg) for arg in self.args]) + ')' + return s + + __repr__ = __str__ + + +class AND: + """ + A low-level implementation for And + """ + def __init__(self, *args): + self._args = args + + def __invert__(self): + return OR(*[~arg for arg in self._args]) + + @property + def args(self): + return sorted(self._args, key=str) + + def rcall(self, expr): + return type(self)(*[arg.rcall(expr) + for arg in self._args + ]) + + def __hash__(self): + return hash((type(self).__name__,) + tuple(self.args)) + + def __eq__(self, other): + return self.args == other.args + + def __str__(self): + s = '('+' & '.join([str(arg) for arg in self.args])+')' + return s + + __repr__ = __str__ + + +def to_NNF(expr, composite_map=None): + """ + Generates the Negation Normal Form of any boolean expression in terms + of AND, OR, and Literal objects. + + Examples + ======== + + >>> from sympy import Q, Eq + >>> from sympy.assumptions.cnf import to_NNF + >>> from sympy.abc import x, y + >>> expr = Q.even(x) & ~Q.positive(x) + >>> to_NNF(expr) + (Literal(Q.even(x), False) & Literal(Q.positive(x), True)) + + Supported boolean objects are converted to corresponding predicates. + + >>> to_NNF(Eq(x, y)) + Literal(Q.eq(x, y), False) + + If ``composite_map`` argument is given, ``to_NNF`` decomposes the + specified predicate into a combination of primitive predicates. + + >>> cmap = {Q.nonpositive: Q.negative | Q.zero} + >>> to_NNF(Q.nonpositive, cmap) + (Literal(Q.negative, False) | Literal(Q.zero, False)) + >>> to_NNF(Q.nonpositive(x), cmap) + (Literal(Q.negative(x), False) | Literal(Q.zero(x), False)) + """ + from sympy.assumptions.ask import Q + + if composite_map is None: + composite_map = {} + + + binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le} + if type(expr) in binrelpreds: + pred = binrelpreds[type(expr)] + expr = pred(*expr.args) + + if isinstance(expr, Not): + arg = expr.args[0] + tmp = to_NNF(arg, composite_map) # Strategy: negate the NNF of expr + return ~tmp + + if isinstance(expr, Or): + return OR(*[to_NNF(x, composite_map) for x in Or.make_args(expr)]) + + if isinstance(expr, And): + return AND(*[to_NNF(x, composite_map) for x in And.make_args(expr)]) + + if isinstance(expr, Nand): + tmp = AND(*[to_NNF(x, composite_map) for x in expr.args]) + return ~tmp + + if isinstance(expr, Nor): + tmp = OR(*[to_NNF(x, composite_map) for x in expr.args]) + return ~tmp + + if isinstance(expr, Xor): + cnfs = [] + for i in range(0, len(expr.args) + 1, 2): + for neg in combinations(expr.args, i): + clause = [~to_NNF(s, composite_map) if s in neg else to_NNF(s, composite_map) + for s in expr.args] + cnfs.append(OR(*clause)) + return AND(*cnfs) + + if isinstance(expr, Xnor): + cnfs = [] + for i in range(0, len(expr.args) + 1, 2): + for neg in combinations(expr.args, i): + clause = [~to_NNF(s, composite_map) if s in neg else to_NNF(s, composite_map) + for s in expr.args] + cnfs.append(OR(*clause)) + return ~AND(*cnfs) + + if isinstance(expr, Implies): + L, R = to_NNF(expr.args[0], composite_map), to_NNF(expr.args[1], composite_map) + return OR(~L, R) + + if isinstance(expr, Equivalent): + cnfs = [] + for a, b in zip_longest(expr.args, expr.args[1:], fillvalue=expr.args[0]): + a = to_NNF(a, composite_map) + b = to_NNF(b, composite_map) + cnfs.append(OR(~a, b)) + return AND(*cnfs) + + if isinstance(expr, ITE): + L = to_NNF(expr.args[0], composite_map) + M = to_NNF(expr.args[1], composite_map) + R = to_NNF(expr.args[2], composite_map) + return AND(OR(~L, M), OR(L, R)) + + if isinstance(expr, AppliedPredicate): + pred, args = expr.function, expr.arguments + newpred = composite_map.get(pred, None) + if newpred is not None: + return to_NNF(newpred.rcall(*args), composite_map) + + if isinstance(expr, Predicate): + newpred = composite_map.get(expr, None) + if newpred is not None: + return to_NNF(newpred, composite_map) + + return Literal(expr) + + +def distribute_AND_over_OR(expr): + """ + Distributes AND over OR in the NNF expression. + Returns the result( Conjunctive Normal Form of expression) + as a CNF object. + """ + if not isinstance(expr, (AND, OR)): + tmp = set() + tmp.add(frozenset((expr,))) + return CNF(tmp) + + if isinstance(expr, OR): + return CNF.all_or(*[distribute_AND_over_OR(arg) + for arg in expr._args]) + + if isinstance(expr, AND): + return CNF.all_and(*[distribute_AND_over_OR(arg) + for arg in expr._args]) + + +class CNF: + """ + Class to represent CNF of a Boolean expression. + Consists of set of clauses, which themselves are stored as + frozenset of Literal objects. + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.abc import x + >>> cnf = CNF.from_prop(Q.real(x) & ~Q.zero(x)) + >>> cnf.clauses + {frozenset({Literal(Q.zero(x), True)}), + frozenset({Literal(Q.negative(x), False), + Literal(Q.positive(x), False), Literal(Q.zero(x), False)})} + """ + def __init__(self, clauses=None): + if not clauses: + clauses = set() + self.clauses = clauses + + def add(self, prop): + clauses = CNF.to_CNF(prop).clauses + self.add_clauses(clauses) + + def __str__(self): + s = ' & '.join( + ['(' + ' | '.join([str(lit) for lit in clause]) +')' + for clause in self.clauses] + ) + return s + + def extend(self, props): + for p in props: + self.add(p) + return self + + def copy(self): + return CNF(set(self.clauses)) + + def add_clauses(self, clauses): + self.clauses |= clauses + + @classmethod + def from_prop(cls, prop): + res = cls() + res.add(prop) + return res + + def __iand__(self, other): + self.add_clauses(other.clauses) + return self + + def all_predicates(self): + predicates = set() + for c in self.clauses: + predicates |= {arg.lit for arg in c} + return predicates + + def _or(self, cnf): + clauses = set() + for a, b in product(self.clauses, cnf.clauses): + tmp = set(a) + tmp.update(b) + clauses.add(frozenset(tmp)) + return CNF(clauses) + + def _and(self, cnf): + clauses = self.clauses.union(cnf.clauses) + return CNF(clauses) + + def _not(self): + clss = list(self.clauses) + ll = {frozenset((~x,)) for x in clss[-1]} + ll = CNF(ll) + + for rest in clss[:-1]: + p = {frozenset((~x,)) for x in rest} + ll = ll._or(CNF(p)) + return ll + + def rcall(self, expr): + clause_list = [] + for clause in self.clauses: + lits = [arg.rcall(expr) for arg in clause] + clause_list.append(OR(*lits)) + expr = AND(*clause_list) + return distribute_AND_over_OR(expr) + + @classmethod + def all_or(cls, *cnfs): + b = cnfs[0].copy() + for rest in cnfs[1:]: + b = b._or(rest) + return b + + @classmethod + def all_and(cls, *cnfs): + b = cnfs[0].copy() + for rest in cnfs[1:]: + b = b._and(rest) + return b + + @classmethod + def to_CNF(cls, expr): + from sympy.assumptions.facts import get_composite_predicates + expr = to_NNF(expr, get_composite_predicates()) + expr = distribute_AND_over_OR(expr) + return expr + + @classmethod + def CNF_to_cnf(cls, cnf): + """ + Converts CNF object to SymPy's boolean expression + retaining the form of expression. + """ + def remove_literal(arg): + return Not(arg.lit) if arg.is_Not else arg.lit + + return And(*(Or(*(remove_literal(arg) for arg in clause)) for clause in cnf.clauses)) + + +class EncodedCNF: + """ + Class for encoding the CNF expression. + """ + def __init__(self, data=None, encoding=None): + if not data and not encoding: + data = [] + encoding = {} + self.data = data + self.encoding = encoding + self._symbols = list(encoding.keys()) + + def from_cnf(self, cnf): + self._symbols = list(cnf.all_predicates()) + n = len(self._symbols) + self.encoding = dict(zip(self._symbols, range(1, n + 1))) + self.data = [self.encode(clause) for clause in cnf.clauses] + + @property + def symbols(self): + return self._symbols + + @property + def variables(self): + return range(1, len(self._symbols) + 1) + + def copy(self): + new_data = [set(clause) for clause in self.data] + return EncodedCNF(new_data, dict(self.encoding)) + + def add_prop(self, prop): + cnf = CNF.from_prop(prop) + self.add_from_cnf(cnf) + + def add_from_cnf(self, cnf): + clauses = [self.encode(clause) for clause in cnf.clauses] + self.data += clauses + + def encode_arg(self, arg): + literal = arg.lit + value = self.encoding.get(literal, None) + if value is None: + n = len(self._symbols) + self._symbols.append(literal) + value = self.encoding[literal] = n + 1 + if arg.is_Not: + return -value + else: + return value + + def encode(self, clause): + return {self.encode_arg(arg) if not arg.lit == S.false else 0 for arg in clause} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/facts.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/facts.py new file mode 100644 index 0000000000000000000000000000000000000000..2ff268677cf74e252ac6c3bc3eecbea08b9414d0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/facts.py @@ -0,0 +1,270 @@ +""" +Known facts in assumptions module. + +This module defines the facts between unary predicates in ``get_known_facts()``, +and supports functions to generate the contents in +``sympy.assumptions.ask_generated`` file. +""" + +from sympy.assumptions.ask import Q +from sympy.assumptions.assume import AppliedPredicate +from sympy.core.cache import cacheit +from sympy.core.symbol import Symbol +from sympy.logic.boolalg import (to_cnf, And, Not, Implies, Equivalent, + Exclusive,) +from sympy.logic.inference import satisfiable + + +@cacheit +def get_composite_predicates(): + # To reduce the complexity of sat solver, these predicates are + # transformed into the combination of primitive predicates. + return { + Q.real : Q.negative | Q.zero | Q.positive, + Q.integer : Q.even | Q.odd, + Q.nonpositive : Q.negative | Q.zero, + Q.nonzero : Q.negative | Q.positive, + Q.nonnegative : Q.zero | Q.positive, + Q.extended_real : Q.negative_infinite | Q.negative | Q.zero | Q.positive | Q.positive_infinite, + Q.extended_positive: Q.positive | Q.positive_infinite, + Q.extended_negative: Q.negative | Q.negative_infinite, + Q.extended_nonzero: Q.negative_infinite | Q.negative | Q.positive | Q.positive_infinite, + Q.extended_nonpositive: Q.negative_infinite | Q.negative | Q.zero, + Q.extended_nonnegative: Q.zero | Q.positive | Q.positive_infinite, + Q.complex : Q.algebraic | Q.transcendental + } + + +@cacheit +def get_known_facts(x=None): + """ + Facts between unary predicates. + + Parameters + ========== + + x : Symbol, optional + Placeholder symbol for unary facts. Default is ``Symbol('x')``. + + Returns + ======= + + fact : Known facts in conjugated normal form. + + """ + if x is None: + x = Symbol('x') + + fact = And( + get_number_facts(x), + get_matrix_facts(x) + ) + return fact + + +@cacheit +def get_number_facts(x = None): + """ + Facts between unary number predicates. + + Parameters + ========== + + x : Symbol, optional + Placeholder symbol for unary facts. Default is ``Symbol('x')``. + + Returns + ======= + + fact : Known facts in conjugated normal form. + + """ + if x is None: + x = Symbol('x') + + fact = And( + # primitive predicates for extended real exclude each other. + Exclusive(Q.negative_infinite(x), Q.negative(x), Q.zero(x), + Q.positive(x), Q.positive_infinite(x)), + + # build complex plane + Exclusive(Q.real(x), Q.imaginary(x)), + Implies(Q.real(x) | Q.imaginary(x), Q.complex(x)), + + # other subsets of complex + Exclusive(Q.transcendental(x), Q.algebraic(x)), + Equivalent(Q.real(x), Q.rational(x) | Q.irrational(x)), + Exclusive(Q.irrational(x), Q.rational(x)), + Implies(Q.rational(x), Q.algebraic(x)), + + # integers + Exclusive(Q.even(x), Q.odd(x)), + Implies(Q.integer(x), Q.rational(x)), + Implies(Q.zero(x), Q.even(x)), + Exclusive(Q.composite(x), Q.prime(x)), + Implies(Q.composite(x) | Q.prime(x), Q.integer(x) & Q.positive(x)), + Implies(Q.even(x) & Q.positive(x) & ~Q.prime(x), Q.composite(x)), + + # hermitian and antihermitian + Implies(Q.real(x), Q.hermitian(x)), + Implies(Q.imaginary(x), Q.antihermitian(x)), + Implies(Q.zero(x), Q.hermitian(x) | Q.antihermitian(x)), + + # define finity and infinity, and build extended real line + Exclusive(Q.infinite(x), Q.finite(x)), + Implies(Q.complex(x), Q.finite(x)), + Implies(Q.negative_infinite(x) | Q.positive_infinite(x), Q.infinite(x)), + + # commutativity + Implies(Q.finite(x) | Q.infinite(x), Q.commutative(x)), + ) + return fact + + +@cacheit +def get_matrix_facts(x = None): + """ + Facts between unary matrix predicates. + + Parameters + ========== + + x : Symbol, optional + Placeholder symbol for unary facts. Default is ``Symbol('x')``. + + Returns + ======= + + fact : Known facts in conjugated normal form. + + """ + if x is None: + x = Symbol('x') + + fact = And( + # matrices + Implies(Q.orthogonal(x), Q.positive_definite(x)), + Implies(Q.orthogonal(x), Q.unitary(x)), + Implies(Q.unitary(x) & Q.real_elements(x), Q.orthogonal(x)), + Implies(Q.unitary(x), Q.normal(x)), + Implies(Q.unitary(x), Q.invertible(x)), + Implies(Q.normal(x), Q.square(x)), + Implies(Q.diagonal(x), Q.normal(x)), + Implies(Q.positive_definite(x), Q.invertible(x)), + Implies(Q.diagonal(x), Q.upper_triangular(x)), + Implies(Q.diagonal(x), Q.lower_triangular(x)), + Implies(Q.lower_triangular(x), Q.triangular(x)), + Implies(Q.upper_triangular(x), Q.triangular(x)), + Implies(Q.triangular(x), Q.upper_triangular(x) | Q.lower_triangular(x)), + Implies(Q.upper_triangular(x) & Q.lower_triangular(x), Q.diagonal(x)), + Implies(Q.diagonal(x), Q.symmetric(x)), + Implies(Q.unit_triangular(x), Q.triangular(x)), + Implies(Q.invertible(x), Q.fullrank(x)), + Implies(Q.invertible(x), Q.square(x)), + Implies(Q.symmetric(x), Q.square(x)), + Implies(Q.fullrank(x) & Q.square(x), Q.invertible(x)), + Equivalent(Q.invertible(x), ~Q.singular(x)), + Implies(Q.integer_elements(x), Q.real_elements(x)), + Implies(Q.real_elements(x), Q.complex_elements(x)), + ) + return fact + + + +def generate_known_facts_dict(keys, fact): + """ + Computes and returns a dictionary which contains the relations between + unary predicates. + + Each key is a predicate, and item is two groups of predicates. + First group contains the predicates which are implied by the key, and + second group contains the predicates which are rejected by the key. + + All predicates in *keys* and *fact* must be unary and have same placeholder + symbol. + + Parameters + ========== + + keys : list of AppliedPredicate instances. + + fact : Fact between predicates in conjugated normal form. + + Examples + ======== + + >>> from sympy import Q, And, Implies + >>> from sympy.assumptions.facts import generate_known_facts_dict + >>> from sympy.abc import x + >>> keys = [Q.even(x), Q.odd(x), Q.zero(x)] + >>> fact = And(Implies(Q.even(x), ~Q.odd(x)), + ... Implies(Q.zero(x), Q.even(x))) + >>> generate_known_facts_dict(keys, fact) + {Q.even: ({Q.even}, {Q.odd}), + Q.odd: ({Q.odd}, {Q.even, Q.zero}), + Q.zero: ({Q.even, Q.zero}, {Q.odd})} + """ + fact_cnf = to_cnf(fact) + mapping = single_fact_lookup(keys, fact_cnf) + + ret = {} + for key, value in mapping.items(): + implied = set() + rejected = set() + for expr in value: + if isinstance(expr, AppliedPredicate): + implied.add(expr.function) + elif isinstance(expr, Not): + pred = expr.args[0] + rejected.add(pred.function) + ret[key.function] = (implied, rejected) + return ret + + +@cacheit +def get_known_facts_keys(): + """ + Return every unary predicates registered to ``Q``. + + This function is used to generate the keys for + ``generate_known_facts_dict``. + + """ + # exclude polyadic predicates + exclude = {Q.eq, Q.ne, Q.gt, Q.lt, Q.ge, Q.le} + + result = [] + for attr in Q.__class__.__dict__: + if attr.startswith('__'): + continue + pred = getattr(Q, attr) + if pred in exclude: + continue + result.append(pred) + return result + + +def single_fact_lookup(known_facts_keys, known_facts_cnf): + # Return the dictionary for quick lookup of single fact + mapping = {} + for key in known_facts_keys: + mapping[key] = {key} + for other_key in known_facts_keys: + if other_key != key: + if ask_full_inference(other_key, key, known_facts_cnf): + mapping[key].add(other_key) + if ask_full_inference(~other_key, key, known_facts_cnf): + mapping[key].add(~other_key) + return mapping + + +def ask_full_inference(proposition, assumptions, known_facts_cnf): + """ + Method for inferring properties about objects. + + """ + if not satisfiable(And(known_facts_cnf, assumptions, proposition)): + return False + if not satisfiable(And(known_facts_cnf, assumptions, Not(proposition))): + return True + return None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/lra_satask.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/lra_satask.py new file mode 100644 index 0000000000000000000000000000000000000000..53afe3e5abe99109ec01a47f19f1a8a4c99c5628 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/lra_satask.py @@ -0,0 +1,286 @@ +from sympy.assumptions.assume import global_assumptions +from sympy.assumptions.cnf import CNF, EncodedCNF +from sympy.assumptions.ask import Q +from sympy.logic.inference import satisfiable +from sympy.logic.algorithms.lra_theory import UnhandledInput, ALLOWED_PRED +from sympy.matrices.kind import MatrixKind +from sympy.core.kind import NumberKind +from sympy.assumptions.assume import AppliedPredicate +from sympy.core.mul import Mul +from sympy.core.singleton import S + + +def lra_satask(proposition, assumptions=True, context=global_assumptions): + """ + Function to evaluate the proposition with assumptions using SAT algorithm + in conjunction with an Linear Real Arithmetic theory solver. + + Used to handle inequalities. Should eventually be depreciated and combined + into satask, but infinity handling and other things need to be implemented + before that can happen. + """ + props = CNF.from_prop(proposition) + _props = CNF.from_prop(~proposition) + + cnf = CNF.from_prop(assumptions) + assumptions = EncodedCNF() + assumptions.from_cnf(cnf) + + context_cnf = CNF() + if context: + context_cnf = context_cnf.extend(context) + + assumptions.add_from_cnf(context_cnf) + + return check_satisfiability(props, _props, assumptions) + +# Some predicates such as Q.prime can't be handled by lra_satask. +# For example, (x > 0) & (x < 1) & Q.prime(x) is unsat but lra_satask would think it was sat. +# WHITE_LIST is a list of predicates that can always be handled. +WHITE_LIST = ALLOWED_PRED | {Q.positive, Q.negative, Q.zero, Q.nonzero, Q.nonpositive, Q.nonnegative, + Q.extended_positive, Q.extended_negative, Q.extended_nonpositive, + Q.extended_negative, Q.extended_nonzero, Q.negative_infinite, + Q.positive_infinite} + + +def check_satisfiability(prop, _prop, factbase): + sat_true = factbase.copy() + sat_false = factbase.copy() + sat_true.add_from_cnf(prop) + sat_false.add_from_cnf(_prop) + + all_pred, all_exprs = get_all_pred_and_expr_from_enc_cnf(sat_true) + + for pred in all_pred: + if pred.function not in WHITE_LIST and pred.function != Q.ne: + raise UnhandledInput(f"LRASolver: {pred} is an unhandled predicate") + for expr in all_exprs: + if expr.kind == MatrixKind(NumberKind): + raise UnhandledInput(f"LRASolver: {expr} is of MatrixKind") + if expr == S.NaN: + raise UnhandledInput("LRASolver: nan") + + # convert old assumptions into predicates and add them to sat_true and sat_false + # also check for unhandled predicates + for assm in extract_pred_from_old_assum(all_exprs): + n = len(sat_true.encoding) + if assm not in sat_true.encoding: + sat_true.encoding[assm] = n+1 + sat_true.data.append([sat_true.encoding[assm]]) + + n = len(sat_false.encoding) + if assm not in sat_false.encoding: + sat_false.encoding[assm] = n+1 + sat_false.data.append([sat_false.encoding[assm]]) + + + sat_true = _preprocess(sat_true) + sat_false = _preprocess(sat_false) + + can_be_true = satisfiable(sat_true, use_lra_theory=True) is not False + can_be_false = satisfiable(sat_false, use_lra_theory=True) is not False + + if can_be_true and can_be_false: + return None + + if can_be_true and not can_be_false: + return True + + if not can_be_true and can_be_false: + return False + + if not can_be_true and not can_be_false: + raise ValueError("Inconsistent assumptions") + + +def _preprocess(enc_cnf): + """ + Returns an encoded cnf with only Q.eq, Q.gt, Q.lt, + Q.ge, and Q.le predicate. + + Converts every unequality into a disjunction of strict + inequalities. For example, x != 3 would become + x < 3 OR x > 3. + + Also converts all negated Q.ne predicates into + equalities. + """ + + # loops through each literal in each clause + # to construct a new, preprocessed encodedCNF + + enc_cnf = enc_cnf.copy() + cur_enc = 1 + rev_encoding = {value: key for key, value in enc_cnf.encoding.items()} + + new_encoding = {} + new_data = [] + for clause in enc_cnf.data: + new_clause = [] + for lit in clause: + if lit == 0: + new_clause.append(lit) + new_encoding[lit] = False + continue + prop = rev_encoding[abs(lit)] + negated = lit < 0 + sign = (lit > 0) - (lit < 0) + + prop = _pred_to_binrel(prop) + + if not isinstance(prop, AppliedPredicate): + if prop not in new_encoding: + new_encoding[prop] = cur_enc + cur_enc += 1 + lit = new_encoding[prop] + new_clause.append(sign*lit) + continue + + + if negated and prop.function == Q.eq: + negated = False + prop = Q.ne(*prop.arguments) + + if prop.function == Q.ne: + arg1, arg2 = prop.arguments + if negated: + new_prop = Q.eq(arg1, arg2) + if new_prop not in new_encoding: + new_encoding[new_prop] = cur_enc + cur_enc += 1 + + new_enc = new_encoding[new_prop] + new_clause.append(new_enc) + continue + else: + new_props = (Q.gt(arg1, arg2), Q.lt(arg1, arg2)) + for new_prop in new_props: + if new_prop not in new_encoding: + new_encoding[new_prop] = cur_enc + cur_enc += 1 + + new_enc = new_encoding[new_prop] + new_clause.append(new_enc) + continue + + if prop.function == Q.eq and negated: + assert False + + if prop not in new_encoding: + new_encoding[prop] = cur_enc + cur_enc += 1 + new_clause.append(new_encoding[prop]*sign) + new_data.append(new_clause) + + assert len(new_encoding) >= cur_enc - 1 + + enc_cnf = EncodedCNF(new_data, new_encoding) + return enc_cnf + + +def _pred_to_binrel(pred): + if not isinstance(pred, AppliedPredicate): + return pred + + if pred.function in pred_to_pos_neg_zero: + f = pred_to_pos_neg_zero[pred.function] + if f is False: + return False + pred = f(pred.arguments[0]) + + if pred.function == Q.positive: + pred = Q.gt(pred.arguments[0], 0) + elif pred.function == Q.negative: + pred = Q.lt(pred.arguments[0], 0) + elif pred.function == Q.zero: + pred = Q.eq(pred.arguments[0], 0) + elif pred.function == Q.nonpositive: + pred = Q.le(pred.arguments[0], 0) + elif pred.function == Q.nonnegative: + pred = Q.ge(pred.arguments[0], 0) + elif pred.function == Q.nonzero: + pred = Q.ne(pred.arguments[0], 0) + + return pred + +pred_to_pos_neg_zero = { + Q.extended_positive: Q.positive, + Q.extended_negative: Q.negative, + Q.extended_nonpositive: Q.nonpositive, + Q.extended_negative: Q.negative, + Q.extended_nonzero: Q.nonzero, + Q.negative_infinite: False, + Q.positive_infinite: False +} + +def get_all_pred_and_expr_from_enc_cnf(enc_cnf): + all_exprs = set() + all_pred = set() + for pred in enc_cnf.encoding.keys(): + if isinstance(pred, AppliedPredicate): + all_pred.add(pred) + all_exprs.update(pred.arguments) + + return all_pred, all_exprs + +def extract_pred_from_old_assum(all_exprs): + """ + Returns a list of relevant new assumption predicate + based on any old assumptions. + + Raises an UnhandledInput exception if any of the assumptions are + unhandled. + + Ignored predicate: + - commutative + - complex + - algebraic + - transcendental + - extended_real + - real + - all matrix predicate + - rational + - irrational + + Example + ======= + >>> from sympy.assumptions.lra_satask import extract_pred_from_old_assum + >>> from sympy import symbols + >>> x, y = symbols("x y", positive=True) + >>> extract_pred_from_old_assum([x, y, 2]) + [Q.positive(x), Q.positive(y)] + """ + ret = [] + for expr in all_exprs: + if not hasattr(expr, "free_symbols"): + continue + if len(expr.free_symbols) == 0: + continue + + if expr.is_real is not True: + raise UnhandledInput(f"LRASolver: {expr} must be real") + # test for I times imaginary variable; such expressions are considered real + if isinstance(expr, Mul) and any(arg.is_real is not True for arg in expr.args): + raise UnhandledInput(f"LRASolver: {expr} must be real") + + if expr.is_integer == True and expr.is_zero != True: + raise UnhandledInput(f"LRASolver: {expr} is an integer") + if expr.is_integer == False: + raise UnhandledInput(f"LRASolver: {expr} can't be an integer") + if expr.is_rational == False: + raise UnhandledInput(f"LRASolver: {expr} is irational") + + if expr.is_zero: + ret.append(Q.zero(expr)) + elif expr.is_positive: + ret.append(Q.positive(expr)) + elif expr.is_negative: + ret.append(Q.negative(expr)) + elif expr.is_nonzero: + ret.append(Q.nonzero(expr)) + elif expr.is_nonpositive: + ret.append(Q.nonpositive(expr)) + elif expr.is_nonnegative: + ret.append(Q.nonnegative(expr)) + + return ret diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/refine.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/refine.py new file mode 100644 index 0000000000000000000000000000000000000000..c36a4e1cdb40f1b59a96f60a3b36182b587920fa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/refine.py @@ -0,0 +1,405 @@ +from __future__ import annotations +from typing import Callable + +from sympy.core import S, Add, Expr, Basic, Mul, Pow, Rational +from sympy.core.logic import fuzzy_not +from sympy.logic.boolalg import Boolean + +from sympy.assumptions import ask, Q # type: ignore + + +def refine(expr, assumptions=True): + """ + Simplify an expression using assumptions. + + Explanation + =========== + + Unlike :func:`~.simplify` which performs structural simplification + without any assumption, this function transforms the expression into + the form which is only valid under certain assumptions. Note that + ``simplify()`` is generally not done in refining process. + + Refining boolean expression involves reducing it to ``S.true`` or + ``S.false``. Unlike :func:`~.ask`, the expression will not be reduced + if the truth value cannot be determined. + + Examples + ======== + + >>> from sympy import refine, sqrt, Q + >>> from sympy.abc import x + >>> refine(sqrt(x**2), Q.real(x)) + Abs(x) + >>> refine(sqrt(x**2), Q.positive(x)) + x + + >>> refine(Q.real(x), Q.positive(x)) + True + >>> refine(Q.positive(x), Q.real(x)) + Q.positive(x) + + See Also + ======== + + sympy.simplify.simplify.simplify : Structural simplification without assumptions. + sympy.assumptions.ask.ask : Query for boolean expressions using assumptions. + """ + if not isinstance(expr, Basic): + return expr + + if not expr.is_Atom: + args = [refine(arg, assumptions) for arg in expr.args] + # TODO: this will probably not work with Integral or Polynomial + expr = expr.func(*args) + if hasattr(expr, '_eval_refine'): + ref_expr = expr._eval_refine(assumptions) + if ref_expr is not None: + return ref_expr + name = expr.__class__.__name__ + handler = handlers_dict.get(name, None) + if handler is None: + return expr + new_expr = handler(expr, assumptions) + if (new_expr is None) or (expr == new_expr): + return expr + if not isinstance(new_expr, Expr): + return new_expr + return refine(new_expr, assumptions) + + +def refine_abs(expr, assumptions): + """ + Handler for the absolute value. + + Examples + ======== + + >>> from sympy import Q, Abs + >>> from sympy.assumptions.refine import refine_abs + >>> from sympy.abc import x + >>> refine_abs(Abs(x), Q.real(x)) + >>> refine_abs(Abs(x), Q.positive(x)) + x + >>> refine_abs(Abs(x), Q.negative(x)) + -x + + """ + from sympy.functions.elementary.complexes import Abs + arg = expr.args[0] + if ask(Q.real(arg), assumptions) and \ + fuzzy_not(ask(Q.negative(arg), assumptions)): + # if it's nonnegative + return arg + if ask(Q.negative(arg), assumptions): + return -arg + # arg is Mul + if isinstance(arg, Mul): + r = [refine(abs(a), assumptions) for a in arg.args] + non_abs = [] + in_abs = [] + for i in r: + if isinstance(i, Abs): + in_abs.append(i.args[0]) + else: + non_abs.append(i) + return Mul(*non_abs) * Abs(Mul(*in_abs)) + + +def refine_Pow(expr, assumptions): + """ + Handler for instances of Pow. + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.refine import refine_Pow + >>> from sympy.abc import x,y,z + >>> refine_Pow((-1)**x, Q.real(x)) + >>> refine_Pow((-1)**x, Q.even(x)) + 1 + >>> refine_Pow((-1)**x, Q.odd(x)) + -1 + + For powers of -1, even parts of the exponent can be simplified: + + >>> refine_Pow((-1)**(x+y), Q.even(x)) + (-1)**y + >>> refine_Pow((-1)**(x+y+z), Q.odd(x) & Q.odd(z)) + (-1)**y + >>> refine_Pow((-1)**(x+y+2), Q.odd(x)) + (-1)**(y + 1) + >>> refine_Pow((-1)**(x+3), True) + (-1)**(x + 1) + + """ + from sympy.functions.elementary.complexes import Abs + from sympy.functions import sign + if isinstance(expr.base, Abs): + if ask(Q.real(expr.base.args[0]), assumptions) and \ + ask(Q.even(expr.exp), assumptions): + return expr.base.args[0] ** expr.exp + if ask(Q.real(expr.base), assumptions): + if expr.base.is_number: + if ask(Q.even(expr.exp), assumptions): + return abs(expr.base) ** expr.exp + if ask(Q.odd(expr.exp), assumptions): + return sign(expr.base) * abs(expr.base) ** expr.exp + if isinstance(expr.exp, Rational): + if isinstance(expr.base, Pow): + return abs(expr.base.base) ** (expr.base.exp * expr.exp) + + if expr.base is S.NegativeOne: + if expr.exp.is_Add: + + old = expr + + # For powers of (-1) we can remove + # - even terms + # - pairs of odd terms + # - a single odd term + 1 + # - A numerical constant N can be replaced with mod(N,2) + + coeff, terms = expr.exp.as_coeff_add() + terms = set(terms) + even_terms = set() + odd_terms = set() + initial_number_of_terms = len(terms) + + for t in terms: + if ask(Q.even(t), assumptions): + even_terms.add(t) + elif ask(Q.odd(t), assumptions): + odd_terms.add(t) + + terms -= even_terms + if len(odd_terms) % 2: + terms -= odd_terms + new_coeff = (coeff + S.One) % 2 + else: + terms -= odd_terms + new_coeff = coeff % 2 + + if new_coeff != coeff or len(terms) < initial_number_of_terms: + terms.add(new_coeff) + expr = expr.base**(Add(*terms)) + + # Handle (-1)**((-1)**n/2 + m/2) + e2 = 2*expr.exp + if ask(Q.even(e2), assumptions): + if e2.could_extract_minus_sign(): + e2 *= expr.base + if e2.is_Add: + i, p = e2.as_two_terms() + if p.is_Pow and p.base is S.NegativeOne: + if ask(Q.integer(p.exp), assumptions): + i = (i + 1)/2 + if ask(Q.even(i), assumptions): + return expr.base**p.exp + elif ask(Q.odd(i), assumptions): + return expr.base**(p.exp + 1) + else: + return expr.base**(p.exp + i) + + if old != expr: + return expr + + +def refine_atan2(expr, assumptions): + """ + Handler for the atan2 function. + + Examples + ======== + + >>> from sympy import Q, atan2 + >>> from sympy.assumptions.refine import refine_atan2 + >>> from sympy.abc import x, y + >>> refine_atan2(atan2(y,x), Q.real(y) & Q.positive(x)) + atan(y/x) + >>> refine_atan2(atan2(y,x), Q.negative(y) & Q.negative(x)) + atan(y/x) - pi + >>> refine_atan2(atan2(y,x), Q.positive(y) & Q.negative(x)) + atan(y/x) + pi + >>> refine_atan2(atan2(y,x), Q.zero(y) & Q.negative(x)) + pi + >>> refine_atan2(atan2(y,x), Q.positive(y) & Q.zero(x)) + pi/2 + >>> refine_atan2(atan2(y,x), Q.negative(y) & Q.zero(x)) + -pi/2 + >>> refine_atan2(atan2(y,x), Q.zero(y) & Q.zero(x)) + nan + """ + from sympy.functions.elementary.trigonometric import atan + y, x = expr.args + if ask(Q.real(y) & Q.positive(x), assumptions): + return atan(y / x) + elif ask(Q.negative(y) & Q.negative(x), assumptions): + return atan(y / x) - S.Pi + elif ask(Q.positive(y) & Q.negative(x), assumptions): + return atan(y / x) + S.Pi + elif ask(Q.zero(y) & Q.negative(x), assumptions): + return S.Pi + elif ask(Q.positive(y) & Q.zero(x), assumptions): + return S.Pi/2 + elif ask(Q.negative(y) & Q.zero(x), assumptions): + return -S.Pi/2 + elif ask(Q.zero(y) & Q.zero(x), assumptions): + return S.NaN + else: + return expr + + +def refine_re(expr, assumptions): + """ + Handler for real part. + + Examples + ======== + + >>> from sympy.assumptions.refine import refine_re + >>> from sympy import Q, re + >>> from sympy.abc import x + >>> refine_re(re(x), Q.real(x)) + x + >>> refine_re(re(x), Q.imaginary(x)) + 0 + """ + arg = expr.args[0] + if ask(Q.real(arg), assumptions): + return arg + if ask(Q.imaginary(arg), assumptions): + return S.Zero + return _refine_reim(expr, assumptions) + + +def refine_im(expr, assumptions): + """ + Handler for imaginary part. + + Explanation + =========== + + >>> from sympy.assumptions.refine import refine_im + >>> from sympy import Q, im + >>> from sympy.abc import x + >>> refine_im(im(x), Q.real(x)) + 0 + >>> refine_im(im(x), Q.imaginary(x)) + -I*x + """ + arg = expr.args[0] + if ask(Q.real(arg), assumptions): + return S.Zero + if ask(Q.imaginary(arg), assumptions): + return - S.ImaginaryUnit * arg + return _refine_reim(expr, assumptions) + +def refine_arg(expr, assumptions): + """ + Handler for complex argument + + Explanation + =========== + + >>> from sympy.assumptions.refine import refine_arg + >>> from sympy import Q, arg + >>> from sympy.abc import x + >>> refine_arg(arg(x), Q.positive(x)) + 0 + >>> refine_arg(arg(x), Q.negative(x)) + pi + """ + rg = expr.args[0] + if ask(Q.positive(rg), assumptions): + return S.Zero + if ask(Q.negative(rg), assumptions): + return S.Pi + return None + + +def _refine_reim(expr, assumptions): + # Helper function for refine_re & refine_im + expanded = expr.expand(complex = True) + if expanded != expr: + refined = refine(expanded, assumptions) + if refined != expanded: + return refined + # Best to leave the expression as is + return None + + +def refine_sign(expr, assumptions): + """ + Handler for sign. + + Examples + ======== + + >>> from sympy.assumptions.refine import refine_sign + >>> from sympy import Symbol, Q, sign, im + >>> x = Symbol('x', real = True) + >>> expr = sign(x) + >>> refine_sign(expr, Q.positive(x) & Q.nonzero(x)) + 1 + >>> refine_sign(expr, Q.negative(x) & Q.nonzero(x)) + -1 + >>> refine_sign(expr, Q.zero(x)) + 0 + >>> y = Symbol('y', imaginary = True) + >>> expr = sign(y) + >>> refine_sign(expr, Q.positive(im(y))) + I + >>> refine_sign(expr, Q.negative(im(y))) + -I + """ + arg = expr.args[0] + if ask(Q.zero(arg), assumptions): + return S.Zero + if ask(Q.real(arg)): + if ask(Q.positive(arg), assumptions): + return S.One + if ask(Q.negative(arg), assumptions): + return S.NegativeOne + if ask(Q.imaginary(arg)): + arg_re, arg_im = arg.as_real_imag() + if ask(Q.positive(arg_im), assumptions): + return S.ImaginaryUnit + if ask(Q.negative(arg_im), assumptions): + return -S.ImaginaryUnit + return expr + + +def refine_matrixelement(expr, assumptions): + """ + Handler for symmetric part. + + Examples + ======== + + >>> from sympy.assumptions.refine import refine_matrixelement + >>> from sympy import MatrixSymbol, Q + >>> X = MatrixSymbol('X', 3, 3) + >>> refine_matrixelement(X[0, 1], Q.symmetric(X)) + X[0, 1] + >>> refine_matrixelement(X[1, 0], Q.symmetric(X)) + X[0, 1] + """ + from sympy.matrices.expressions.matexpr import MatrixElement + matrix, i, j = expr.args + if ask(Q.symmetric(matrix), assumptions): + if (i - j).could_extract_minus_sign(): + return expr + return MatrixElement(matrix, j, i) + +handlers_dict: dict[str, Callable[[Expr, Boolean], Expr]] = { + 'Abs': refine_abs, + 'Pow': refine_Pow, + 'atan2': refine_atan2, + 're': refine_re, + 'im': refine_im, + 'arg': refine_arg, + 'sign': refine_sign, + 'MatrixElement': refine_matrixelement +} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/satask.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/satask.py new file mode 100644 index 0000000000000000000000000000000000000000..ffc13f6d3bc3fb7f573c8d5d0564b780440c1a8c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/satask.py @@ -0,0 +1,369 @@ +""" +Module to evaluate the proposition with assumptions using SAT algorithm. +""" + +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.kind import NumberKind, UndefinedKind +from sympy.assumptions.ask_generated import get_all_known_matrix_facts, get_all_known_number_facts +from sympy.assumptions.assume import global_assumptions, AppliedPredicate +from sympy.assumptions.sathandlers import class_fact_registry +from sympy.core import oo +from sympy.logic.inference import satisfiable +from sympy.assumptions.cnf import CNF, EncodedCNF +from sympy.matrices.kind import MatrixKind + + +def satask(proposition, assumptions=True, context=global_assumptions, + use_known_facts=True, iterations=oo): + """ + Function to evaluate the proposition with assumptions using SAT algorithm. + + This function extracts every fact relevant to the expressions composing + proposition and assumptions. For example, if a predicate containing + ``Abs(x)`` is proposed, then ``Q.zero(Abs(x)) | Q.positive(Abs(x))`` + will be found and passed to SAT solver because ``Q.nonnegative`` is + registered as a fact for ``Abs``. + + Proposition is evaluated to ``True`` or ``False`` if the truth value can be + determined. If not, ``None`` is returned. + + Parameters + ========== + + proposition : Any boolean expression. + Proposition which will be evaluated to boolean value. + + assumptions : Any boolean expression, optional. + Local assumptions to evaluate the *proposition*. + + context : AssumptionsContext, optional. + Default assumptions to evaluate the *proposition*. By default, + this is ``sympy.assumptions.global_assumptions`` variable. + + use_known_facts : bool, optional. + If ``True``, facts from ``sympy.assumptions.ask_generated`` + module are passed to SAT solver as well. + + iterations : int, optional. + Number of times that relevant facts are recursively extracted. + Default is infinite times until no new fact is found. + + Returns + ======= + + ``True``, ``False``, or ``None`` + + Examples + ======== + + >>> from sympy import Abs, Q + >>> from sympy.assumptions.satask import satask + >>> from sympy.abc import x + >>> satask(Q.zero(Abs(x)), Q.zero(x)) + True + + """ + props = CNF.from_prop(proposition) + _props = CNF.from_prop(~proposition) + + assumptions = CNF.from_prop(assumptions) + + context_cnf = CNF() + if context: + context_cnf = context_cnf.extend(context) + + sat = get_all_relevant_facts(props, assumptions, context_cnf, + use_known_facts=use_known_facts, iterations=iterations) + sat.add_from_cnf(assumptions) + if context: + sat.add_from_cnf(context_cnf) + + return check_satisfiability(props, _props, sat) + + +def check_satisfiability(prop, _prop, factbase): + sat_true = factbase.copy() + sat_false = factbase.copy() + sat_true.add_from_cnf(prop) + sat_false.add_from_cnf(_prop) + can_be_true = satisfiable(sat_true) + can_be_false = satisfiable(sat_false) + + if can_be_true and can_be_false: + return None + + if can_be_true and not can_be_false: + return True + + if not can_be_true and can_be_false: + return False + + if not can_be_true and not can_be_false: + # TODO: Run additional checks to see which combination of the + # assumptions, global_assumptions, and relevant_facts are + # inconsistent. + raise ValueError("Inconsistent assumptions") + + +def extract_predargs(proposition, assumptions=None, context=None): + """ + Extract every expression in the argument of predicates from *proposition*, + *assumptions* and *context*. + + Parameters + ========== + + proposition : sympy.assumptions.cnf.CNF + + assumptions : sympy.assumptions.cnf.CNF, optional. + + context : sympy.assumptions.cnf.CNF, optional. + CNF generated from assumptions context. + + Examples + ======== + + >>> from sympy import Q, Abs + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.assumptions.satask import extract_predargs + >>> from sympy.abc import x, y + >>> props = CNF.from_prop(Q.zero(Abs(x*y))) + >>> assump = CNF.from_prop(Q.zero(x) & Q.zero(y)) + >>> extract_predargs(props, assump) + {x, y, Abs(x*y)} + + """ + req_keys = find_symbols(proposition) + keys = proposition.all_predicates() + # XXX: We need this since True/False are not Basic + lkeys = set() + if assumptions: + lkeys |= assumptions.all_predicates() + if context: + lkeys |= context.all_predicates() + + lkeys = lkeys - {S.true, S.false} + tmp_keys = None + while tmp_keys != set(): + tmp = set() + for l in lkeys: + syms = find_symbols(l) + if (syms & req_keys) != set(): + tmp |= syms + tmp_keys = tmp - req_keys + req_keys |= tmp_keys + keys |= {l for l in lkeys if find_symbols(l) & req_keys != set()} + + exprs = set() + for key in keys: + if isinstance(key, AppliedPredicate): + exprs |= set(key.arguments) + else: + exprs.add(key) + return exprs + +def find_symbols(pred): + """ + Find every :obj:`~.Symbol` in *pred*. + + Parameters + ========== + + pred : sympy.assumptions.cnf.CNF, or any Expr. + + """ + if isinstance(pred, CNF): + symbols = set() + for a in pred.all_predicates(): + symbols |= find_symbols(a) + return symbols + return pred.atoms(Symbol) + + +def get_relevant_clsfacts(exprs, relevant_facts=None): + """ + Extract relevant facts from the items in *exprs*. Facts are defined in + ``assumptions.sathandlers`` module. + + This function is recursively called by ``get_all_relevant_facts()``. + + Parameters + ========== + + exprs : set + Expressions whose relevant facts are searched. + + relevant_facts : sympy.assumptions.cnf.CNF, optional. + Pre-discovered relevant facts. + + Returns + ======= + + exprs : set + Candidates for next relevant fact searching. + + relevant_facts : sympy.assumptions.cnf.CNF + Updated relevant facts. + + Examples + ======== + + Here, we will see how facts relevant to ``Abs(x*y)`` are recursively + extracted. On the first run, set containing the expression is passed + without pre-discovered relevant facts. The result is a set containing + candidates for next run, and ``CNF()`` instance containing facts + which are relevant to ``Abs`` and its argument. + + >>> from sympy import Abs + >>> from sympy.assumptions.satask import get_relevant_clsfacts + >>> from sympy.abc import x, y + >>> exprs = {Abs(x*y)} + >>> exprs, facts = get_relevant_clsfacts(exprs) + >>> exprs + {x*y} + >>> facts.clauses #doctest: +SKIP + {frozenset({Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}), + frozenset({Literal(Q.zero(Abs(x*y)), False), Literal(Q.zero(x*y), True)}), + frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True)}), + frozenset({Literal(Q.zero(Abs(x*y)), True), Literal(Q.zero(x*y), False)}), + frozenset({Literal(Q.even(Abs(x*y)), False), + Literal(Q.odd(Abs(x*y)), False), + Literal(Q.odd(x*y), True)}), + frozenset({Literal(Q.even(Abs(x*y)), False), + Literal(Q.even(x*y), True), + Literal(Q.odd(Abs(x*y)), False)}), + frozenset({Literal(Q.positive(Abs(x*y)), False), + Literal(Q.zero(Abs(x*y)), False)})} + + We pass the first run's results to the second run, and get the expressions + for next run and updated facts. + + >>> exprs, facts = get_relevant_clsfacts(exprs, relevant_facts=facts) + >>> exprs + {x, y} + + On final run, no more candidate is returned thus we know that all + relevant facts are successfully retrieved. + + >>> exprs, facts = get_relevant_clsfacts(exprs, relevant_facts=facts) + >>> exprs + set() + + """ + if not relevant_facts: + relevant_facts = CNF() + + newexprs = set() + for expr in exprs: + for fact in class_fact_registry(expr): + newfact = CNF.to_CNF(fact) + relevant_facts = relevant_facts._and(newfact) + for key in newfact.all_predicates(): + if isinstance(key, AppliedPredicate): + newexprs |= set(key.arguments) + + return newexprs - exprs, relevant_facts + + +def get_all_relevant_facts(proposition, assumptions, context, + use_known_facts=True, iterations=oo): + """ + Extract all relevant facts from *proposition* and *assumptions*. + + This function extracts the facts by recursively calling + ``get_relevant_clsfacts()``. Extracted facts are converted to + ``EncodedCNF`` and returned. + + Parameters + ========== + + proposition : sympy.assumptions.cnf.CNF + CNF generated from proposition expression. + + assumptions : sympy.assumptions.cnf.CNF + CNF generated from assumption expression. + + context : sympy.assumptions.cnf.CNF + CNF generated from assumptions context. + + use_known_facts : bool, optional. + If ``True``, facts from ``sympy.assumptions.ask_generated`` + module are encoded as well. + + iterations : int, optional. + Number of times that relevant facts are recursively extracted. + Default is infinite times until no new fact is found. + + Returns + ======= + + sympy.assumptions.cnf.EncodedCNF + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.assumptions.satask import get_all_relevant_facts + >>> from sympy.abc import x, y + >>> props = CNF.from_prop(Q.nonzero(x*y)) + >>> assump = CNF.from_prop(Q.nonzero(x)) + >>> context = CNF.from_prop(Q.nonzero(y)) + >>> get_all_relevant_facts(props, assump, context) #doctest: +SKIP + + + """ + # The relevant facts might introduce new keys, e.g., Q.zero(x*y) will + # introduce the keys Q.zero(x) and Q.zero(y), so we need to run it until + # we stop getting new things. Hopefully this strategy won't lead to an + # infinite loop in the future. + i = 0 + relevant_facts = CNF() + all_exprs = set() + while True: + if i == 0: + exprs = extract_predargs(proposition, assumptions, context) + all_exprs |= exprs + exprs, relevant_facts = get_relevant_clsfacts(exprs, relevant_facts) + i += 1 + if i >= iterations: + break + if not exprs: + break + + if use_known_facts: + known_facts_CNF = CNF() + + if any(expr.kind == MatrixKind(NumberKind) for expr in all_exprs): + known_facts_CNF.add_clauses(get_all_known_matrix_facts()) + # check for undefinedKind since kind system isn't fully implemented + if any(((expr.kind == NumberKind) or (expr.kind == UndefinedKind)) for expr in all_exprs): + known_facts_CNF.add_clauses(get_all_known_number_facts()) + + kf_encoded = EncodedCNF() + kf_encoded.from_cnf(known_facts_CNF) + + def translate_literal(lit, delta): + if lit > 0: + return lit + delta + else: + return lit - delta + + def translate_data(data, delta): + return [{translate_literal(i, delta) for i in clause} for clause in data] + data = [] + symbols = [] + n_lit = len(kf_encoded.symbols) + for i, expr in enumerate(all_exprs): + symbols += [pred(expr) for pred in kf_encoded.symbols] + data += translate_data(kf_encoded.data, i * n_lit) + + encoding = dict(list(zip(symbols, range(1, len(symbols)+1)))) + ctx = EncodedCNF(data, encoding) + else: + ctx = EncodedCNF() + + ctx.add_from_cnf(relevant_facts) + + return ctx diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/sathandlers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/sathandlers.py new file mode 100644 index 0000000000000000000000000000000000000000..a11199eb0e547187ab280c18196c0259c178e004 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/sathandlers.py @@ -0,0 +1,322 @@ +from collections import defaultdict + +from sympy.assumptions.ask import Q +from sympy.core import (Add, Mul, Pow, Number, NumberSymbol, Symbol) +from sympy.core.numbers import ImaginaryUnit +from sympy.functions.elementary.complexes import Abs +from sympy.logic.boolalg import (Equivalent, And, Or, Implies) +from sympy.matrices.expressions import MatMul + +# APIs here may be subject to change + + +### Helper functions ### + +def allargs(symbol, fact, expr): + """ + Apply all arguments of the expression to the fact structure. + + Parameters + ========== + + symbol : Symbol + A placeholder symbol. + + fact : Boolean + Resulting ``Boolean`` expression. + + expr : Expr + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.sathandlers import allargs + >>> from sympy.abc import x, y + >>> allargs(x, Q.negative(x) | Q.positive(x), x*y) + (Q.negative(x) | Q.positive(x)) & (Q.negative(y) | Q.positive(y)) + + """ + return And(*[fact.subs(symbol, arg) for arg in expr.args]) + + +def anyarg(symbol, fact, expr): + """ + Apply any argument of the expression to the fact structure. + + Parameters + ========== + + symbol : Symbol + A placeholder symbol. + + fact : Boolean + Resulting ``Boolean`` expression. + + expr : Expr + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.sathandlers import anyarg + >>> from sympy.abc import x, y + >>> anyarg(x, Q.negative(x) & Q.positive(x), x*y) + (Q.negative(x) & Q.positive(x)) | (Q.negative(y) & Q.positive(y)) + + """ + return Or(*[fact.subs(symbol, arg) for arg in expr.args]) + + +def exactlyonearg(symbol, fact, expr): + """ + Apply exactly one argument of the expression to the fact structure. + + Parameters + ========== + + symbol : Symbol + A placeholder symbol. + + fact : Boolean + Resulting ``Boolean`` expression. + + expr : Expr + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.sathandlers import exactlyonearg + >>> from sympy.abc import x, y + >>> exactlyonearg(x, Q.positive(x), x*y) + (Q.positive(x) & ~Q.positive(y)) | (Q.positive(y) & ~Q.positive(x)) + + """ + pred_args = [fact.subs(symbol, arg) for arg in expr.args] + res = Or(*[And(pred_args[i], *[~lit for lit in pred_args[:i] + + pred_args[i+1:]]) for i in range(len(pred_args))]) + return res + + +### Fact registry ### + +class ClassFactRegistry: + """ + Register handlers against classes. + + Explanation + =========== + + ``register`` method registers the handler function for a class. Here, + handler function should return a single fact. ``multiregister`` method + registers the handler function for multiple classes. Here, handler function + should return a container of multiple facts. + + ``registry(expr)`` returns a set of facts for *expr*. + + Examples + ======== + + Here, we register the facts for ``Abs``. + + >>> from sympy import Abs, Equivalent, Q + >>> from sympy.assumptions.sathandlers import ClassFactRegistry + >>> reg = ClassFactRegistry() + >>> @reg.register(Abs) + ... def f1(expr): + ... return Q.nonnegative(expr) + >>> @reg.register(Abs) + ... def f2(expr): + ... arg = expr.args[0] + ... return Equivalent(~Q.zero(arg), ~Q.zero(expr)) + + Calling the registry with expression returns the defined facts for the + expression. + + >>> from sympy.abc import x + >>> reg(Abs(x)) + {Q.nonnegative(Abs(x)), Equivalent(~Q.zero(x), ~Q.zero(Abs(x)))} + + Multiple facts can be registered at once by ``multiregister`` method. + + >>> reg2 = ClassFactRegistry() + >>> @reg2.multiregister(Abs) + ... def _(expr): + ... arg = expr.args[0] + ... return [Q.even(arg) >> Q.even(expr), Q.odd(arg) >> Q.odd(expr)] + >>> reg2(Abs(x)) + {Implies(Q.even(x), Q.even(Abs(x))), Implies(Q.odd(x), Q.odd(Abs(x)))} + + """ + def __init__(self): + self.singlefacts = defaultdict(frozenset) + self.multifacts = defaultdict(frozenset) + + def register(self, cls): + def _(func): + self.singlefacts[cls] |= {func} + return func + return _ + + def multiregister(self, *classes): + def _(func): + for cls in classes: + self.multifacts[cls] |= {func} + return func + return _ + + def __getitem__(self, key): + ret1 = self.singlefacts[key] + for k in self.singlefacts: + if issubclass(key, k): + ret1 |= self.singlefacts[k] + + ret2 = self.multifacts[key] + for k in self.multifacts: + if issubclass(key, k): + ret2 |= self.multifacts[k] + + return ret1, ret2 + + def __call__(self, expr): + ret = set() + + handlers1, handlers2 = self[type(expr)] + + ret.update(h(expr) for h in handlers1) + for h in handlers2: + ret.update(h(expr)) + return ret + +class_fact_registry = ClassFactRegistry() + + + +### Class fact registration ### + +x = Symbol('x') + +## Abs ## + +@class_fact_registry.multiregister(Abs) +def _(expr): + arg = expr.args[0] + return [Q.nonnegative(expr), + Equivalent(~Q.zero(arg), ~Q.zero(expr)), + Q.even(arg) >> Q.even(expr), + Q.odd(arg) >> Q.odd(expr), + Q.integer(arg) >> Q.integer(expr), + ] + + +### Add ## + +@class_fact_registry.multiregister(Add) +def _(expr): + return [allargs(x, Q.positive(x), expr) >> Q.positive(expr), + allargs(x, Q.negative(x), expr) >> Q.negative(expr), + allargs(x, Q.real(x), expr) >> Q.real(expr), + allargs(x, Q.rational(x), expr) >> Q.rational(expr), + allargs(x, Q.integer(x), expr) >> Q.integer(expr), + exactlyonearg(x, ~Q.integer(x), expr) >> ~Q.integer(expr), + ] + +@class_fact_registry.register(Add) +def _(expr): + allargs_real = allargs(x, Q.real(x), expr) + onearg_irrational = exactlyonearg(x, Q.irrational(x), expr) + return Implies(allargs_real, Implies(onearg_irrational, Q.irrational(expr))) + + +### Mul ### + +@class_fact_registry.multiregister(Mul) +def _(expr): + return [Equivalent(Q.zero(expr), anyarg(x, Q.zero(x), expr)), + allargs(x, Q.positive(x), expr) >> Q.positive(expr), + allargs(x, Q.real(x), expr) >> Q.real(expr), + allargs(x, Q.rational(x), expr) >> Q.rational(expr), + allargs(x, Q.integer(x), expr) >> Q.integer(expr), + exactlyonearg(x, ~Q.rational(x), expr) >> ~Q.integer(expr), + allargs(x, Q.commutative(x), expr) >> Q.commutative(expr), + ] + +@class_fact_registry.register(Mul) +def _(expr): + # Implicitly assumes Mul has more than one arg + # Would be allargs(x, Q.prime(x) | Q.composite(x)) except 1 is composite + # More advanced prime assumptions will require inequalities, as 1 provides + # a corner case. + allargs_prime = allargs(x, Q.prime(x), expr) + return Implies(allargs_prime, ~Q.prime(expr)) + +@class_fact_registry.register(Mul) +def _(expr): + # General Case: Odd number of imaginary args implies mul is imaginary(To be implemented) + allargs_imag_or_real = allargs(x, Q.imaginary(x) | Q.real(x), expr) + onearg_imaginary = exactlyonearg(x, Q.imaginary(x), expr) + return Implies(allargs_imag_or_real, Implies(onearg_imaginary, Q.imaginary(expr))) + +@class_fact_registry.register(Mul) +def _(expr): + allargs_real = allargs(x, Q.real(x), expr) + onearg_irrational = exactlyonearg(x, Q.irrational(x), expr) + return Implies(allargs_real, Implies(onearg_irrational, Q.irrational(expr))) + +@class_fact_registry.register(Mul) +def _(expr): + # Including the integer qualification means we don't need to add any facts + # for odd, since the assumptions already know that every integer is + # exactly one of even or odd. + allargs_integer = allargs(x, Q.integer(x), expr) + anyarg_even = anyarg(x, Q.even(x), expr) + return Implies(allargs_integer, Equivalent(anyarg_even, Q.even(expr))) + + +### MatMul ### + +@class_fact_registry.register(MatMul) +def _(expr): + allargs_square = allargs(x, Q.square(x), expr) + allargs_invertible = allargs(x, Q.invertible(x), expr) + return Implies(allargs_square, Equivalent(Q.invertible(expr), allargs_invertible)) + + +### Pow ### + +@class_fact_registry.multiregister(Pow) +def _(expr): + base, exp = expr.base, expr.exp + return [ + (Q.real(base) & Q.even(exp) & Q.nonnegative(exp)) >> Q.nonnegative(expr), + (Q.nonnegative(base) & Q.odd(exp) & Q.nonnegative(exp)) >> Q.nonnegative(expr), + (Q.nonpositive(base) & Q.odd(exp) & Q.nonnegative(exp)) >> Q.nonpositive(expr), + Equivalent(Q.zero(expr), Q.zero(base) & Q.positive(exp)) + ] + + +### Numbers ### + +_old_assump_getters = { + Q.positive: lambda o: o.is_positive, + Q.zero: lambda o: o.is_zero, + Q.negative: lambda o: o.is_negative, + Q.rational: lambda o: o.is_rational, + Q.irrational: lambda o: o.is_irrational, + Q.even: lambda o: o.is_even, + Q.odd: lambda o: o.is_odd, + Q.imaginary: lambda o: o.is_imaginary, + Q.prime: lambda o: o.is_prime, + Q.composite: lambda o: o.is_composite, +} + +@class_fact_registry.multiregister(Number, NumberSymbol, ImaginaryUnit) +def _(expr): + ret = [] + for p, getter in _old_assump_getters.items(): + pred = p(expr) + prop = getter(expr) + if prop is not None: + ret.append(Equivalent(pred, prop)) + return ret diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/wrapper.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/wrapper.py new file mode 100644 index 0000000000000000000000000000000000000000..cb06e9de770ed41a2b3d6fe63381ad1cb59acacc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/assumptions/wrapper.py @@ -0,0 +1,164 @@ +""" +Functions and wrapper object to call assumption property and predicate +query with same syntax. + +In SymPy, there are two assumption systems. Old assumption system is +defined in sympy/core/assumptions, and it can be accessed by attribute +such as ``x.is_even``. New assumption system is defined in +sympy/assumptions, and it can be accessed by predicates such as +``Q.even(x)``. + +Old assumption is fast, while new assumptions can freely take local facts. +In general, old assumption is used in evaluation method and new assumption +is used in refinement method. + +In most cases, both evaluation and refinement follow the same process, and +the only difference is which assumption system is used. This module provides +``is_[...]()`` functions and ``AssumptionsWrapper()`` class which allows +using two systems with same syntax so that parallel code implementation can be +avoided. + +Examples +======== + +For multiple use, use ``AssumptionsWrapper()``. + +>>> from sympy import Q, Symbol +>>> from sympy.assumptions.wrapper import AssumptionsWrapper +>>> x = Symbol('x') +>>> _x = AssumptionsWrapper(x, Q.even(x)) +>>> _x.is_integer +True +>>> _x.is_odd +False + +For single use, use ``is_[...]()`` functions. + +>>> from sympy.assumptions.wrapper import is_infinite +>>> a = Symbol('a') +>>> print(is_infinite(a)) +None +>>> is_infinite(a, Q.finite(a)) +False + +""" + +from sympy.assumptions import ask, Q +from sympy.core.basic import Basic +from sympy.core.sympify import _sympify + + +def make_eval_method(fact): + def getit(self): + pred = getattr(Q, fact) + ret = ask(pred(self.expr), self.assumptions) + return ret + return getit + + +# we subclass Basic to use the fact deduction and caching +class AssumptionsWrapper(Basic): + """ + Wrapper over ``Basic`` instances to call predicate query by + ``.is_[...]`` property + + Parameters + ========== + + expr : Basic + + assumptions : Boolean, optional + + Examples + ======== + + >>> from sympy import Q, Symbol + >>> from sympy.assumptions.wrapper import AssumptionsWrapper + >>> x = Symbol('x', even=True) + >>> AssumptionsWrapper(x).is_integer + True + >>> y = Symbol('y') + >>> AssumptionsWrapper(y, Q.even(y)).is_integer + True + + With ``AssumptionsWrapper``, both evaluation and refinement can be supported + by single implementation. + + >>> from sympy import Function + >>> class MyAbs(Function): + ... @classmethod + ... def eval(cls, x, assumptions=True): + ... _x = AssumptionsWrapper(x, assumptions) + ... if _x.is_nonnegative: + ... return x + ... if _x.is_negative: + ... return -x + ... def _eval_refine(self, assumptions): + ... return MyAbs.eval(self.args[0], assumptions) + >>> MyAbs(x) + MyAbs(x) + >>> MyAbs(x).refine(Q.positive(x)) + x + >>> MyAbs(Symbol('y', negative=True)) + -y + + """ + def __new__(cls, expr, assumptions=None): + if assumptions is None: + return expr + obj = super().__new__(cls, expr, _sympify(assumptions)) + obj.expr = expr + obj.assumptions = assumptions + return obj + + _eval_is_algebraic = make_eval_method("algebraic") + _eval_is_antihermitian = make_eval_method("antihermitian") + _eval_is_commutative = make_eval_method("commutative") + _eval_is_complex = make_eval_method("complex") + _eval_is_composite = make_eval_method("composite") + _eval_is_even = make_eval_method("even") + _eval_is_extended_negative = make_eval_method("extended_negative") + _eval_is_extended_nonnegative = make_eval_method("extended_nonnegative") + _eval_is_extended_nonpositive = make_eval_method("extended_nonpositive") + _eval_is_extended_nonzero = make_eval_method("extended_nonzero") + _eval_is_extended_positive = make_eval_method("extended_positive") + _eval_is_extended_real = make_eval_method("extended_real") + _eval_is_finite = make_eval_method("finite") + _eval_is_hermitian = make_eval_method("hermitian") + _eval_is_imaginary = make_eval_method("imaginary") + _eval_is_infinite = make_eval_method("infinite") + _eval_is_integer = make_eval_method("integer") + _eval_is_irrational = make_eval_method("irrational") + _eval_is_negative = make_eval_method("negative") + _eval_is_noninteger = make_eval_method("noninteger") + _eval_is_nonnegative = make_eval_method("nonnegative") + _eval_is_nonpositive = make_eval_method("nonpositive") + _eval_is_nonzero = make_eval_method("nonzero") + _eval_is_odd = make_eval_method("odd") + _eval_is_polar = make_eval_method("polar") + _eval_is_positive = make_eval_method("positive") + _eval_is_prime = make_eval_method("prime") + _eval_is_rational = make_eval_method("rational") + _eval_is_real = make_eval_method("real") + _eval_is_transcendental = make_eval_method("transcendental") + _eval_is_zero = make_eval_method("zero") + + +# one shot functions which are faster than AssumptionsWrapper + +def is_infinite(obj, assumptions=None): + if assumptions is None: + return obj.is_infinite + return ask(Q.infinite(obj), assumptions) + + +def is_extended_real(obj, assumptions=None): + if assumptions is None: + return obj.is_extended_real + return ask(Q.extended_real(obj), assumptions) + + +def is_extended_nonnegative(obj, assumptions=None): + if assumptions is None: + return obj.is_extended_nonnegative + return ask(Q.extended_nonnegative(obj), assumptions) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_discrete_log.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_discrete_log.py new file mode 100644 index 0000000000000000000000000000000000000000..76b273909e415318a7d3bace00ffff2a0bc53762 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_discrete_log.py @@ -0,0 +1,83 @@ +import sys +from time import time +from sympy.ntheory.residue_ntheory import (discrete_log, + _discrete_log_trial_mul, _discrete_log_shanks_steps, + _discrete_log_pollard_rho, _discrete_log_pohlig_hellman) + + +# Cyclic group (Z/pZ)* with p prime, order p - 1 and generator g +data_set_1 = [ + # p, p - 1, g + [191, 190, 19], + [46639, 46638, 6], + [14789363, 14789362, 2], + [4254225211, 4254225210, 2], + [432751500361, 432751500360, 7], + [158505390797053, 158505390797052, 2], + [6575202655312007, 6575202655312006, 5], + [8430573471995353769, 8430573471995353768, 3], + [3938471339744997827267, 3938471339744997827266, 2], + [875260951364705563393093, 875260951364705563393092, 5], + ] + + +# Cyclic sub-groups of (Z/nZ)* with prime order p and generator g +# (n, p are primes and n = 2 * p + 1) +data_set_2 = [ + # n, p, g + [227, 113, 3], + [2447, 1223, 2], + [24527, 12263, 2], + [245639, 122819, 2], + [2456747, 1228373, 3], + [24567899, 12283949, 3], + [245679023, 122839511, 2], + [2456791307, 1228395653, 3], + [24567913439, 12283956719, 2], + [245679135407, 122839567703, 2], + [2456791354763, 1228395677381, 3], + [24567913550903, 12283956775451, 2], + [245679135509519, 122839567754759, 2], + ] + + +# Cyclic sub-groups of (Z/nZ)* with smooth order o and generator g +data_set_3 = [ + # n, o, g + [2**118, 2**116, 3], + ] + + +def bench_discrete_log(data_set, algo=None): + if algo is None: + f = discrete_log + elif algo == 'trial': + f = _discrete_log_trial_mul + elif algo == 'shanks': + f = _discrete_log_shanks_steps + elif algo == 'rho': + f = _discrete_log_pollard_rho + elif algo == 'ph': + f = _discrete_log_pohlig_hellman + else: + raise ValueError("Argument 'algo' should be one" + " of ('trial', 'shanks', 'rho' or 'ph')") + + for i, data in enumerate(data_set): + for j, (n, p, g) in enumerate(data): + t = time() + l = f(n, pow(g, p - 1, n), g, p) + t = time() - t + print('[%02d-%03d] %15.10f' % (i, j, t)) + assert l == p - 1 + + +if __name__ == '__main__': + algo = sys.argv[1] \ + if len(sys.argv) > 1 else None + data_set = [ + data_set_1, + data_set_2, + data_set_3, + ] + bench_discrete_log(data_set, algo) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_meijerint.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_meijerint.py new file mode 100644 index 0000000000000000000000000000000000000000..d648c3e02463d5a7ee1dcbe3b22af5cc22fef43d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_meijerint.py @@ -0,0 +1,261 @@ +# conceal the implicit import from the code quality tester +from sympy.core.numbers import (oo, pi) +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.bessel import besseli +from sympy.functions.special.gamma_functions import gamma +from sympy.integrals.integrals import integrate +from sympy.integrals.transforms import (mellin_transform, + inverse_fourier_transform, inverse_mellin_transform, + laplace_transform, inverse_laplace_transform, fourier_transform) + +LT = laplace_transform +FT = fourier_transform +MT = mellin_transform +IFT = inverse_fourier_transform +ILT = inverse_laplace_transform +IMT = inverse_mellin_transform + +from sympy.abc import x, y +nu, beta, rho = symbols('nu beta rho') + +apos, bpos, cpos, dpos, posk, p = symbols('a b c d k p', positive=True) +k = Symbol('k', real=True) +negk = Symbol('k', negative=True) + +mu1, mu2 = symbols('mu1 mu2', real=True, nonzero=True, finite=True) +sigma1, sigma2 = symbols('sigma1 sigma2', real=True, nonzero=True, + finite=True, positive=True) +rate = Symbol('lambda', positive=True) + + +def normal(x, mu, sigma): + return 1/sqrt(2*pi*sigma**2)*exp(-(x - mu)**2/2/sigma**2) + + +def exponential(x, rate): + return rate*exp(-rate*x) +alpha, beta = symbols('alpha beta', positive=True) +betadist = x**(alpha - 1)*(1 + x)**(-alpha - beta)*gamma(alpha + beta) \ + /gamma(alpha)/gamma(beta) +kint = Symbol('k', integer=True, positive=True) +chi = 2**(1 - kint/2)*x**(kint - 1)*exp(-x**2/2)/gamma(kint/2) +chisquared = 2**(-k/2)/gamma(k/2)*x**(k/2 - 1)*exp(-x/2) +dagum = apos*p/x*(x/bpos)**(apos*p)/(1 + x**apos/bpos**apos)**(p + 1) +d1, d2 = symbols('d1 d2', positive=True) +f = sqrt(((d1*x)**d1 * d2**d2)/(d1*x + d2)**(d1 + d2))/x \ + /gamma(d1/2)/gamma(d2/2)*gamma((d1 + d2)/2) +nupos, sigmapos = symbols('nu sigma', positive=True) +rice = x/sigmapos**2*exp(-(x**2 + nupos**2)/2/sigmapos**2)*besseli(0, x* + nupos/sigmapos**2) +mu = Symbol('mu', real=True) +laplace = exp(-abs(x - mu)/bpos)/2/bpos + +u = Symbol('u', polar=True) +tpos = Symbol('t', positive=True) + + +def E(expr): + integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1), + (x, 0, oo), (y, -oo, oo), meijerg=True) + integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1), + (y, -oo, oo), (x, 0, oo), meijerg=True) + +bench = [ + 'MT(x**nu*Heaviside(x - 1), x, s)', + 'MT(x**nu*Heaviside(1 - x), x, s)', + 'MT((1-x)**(beta - 1)*Heaviside(1-x), x, s)', + 'MT((x-1)**(beta - 1)*Heaviside(x-1), x, s)', + 'MT((1+x)**(-rho), x, s)', + 'MT(abs(1-x)**(-rho), x, s)', + 'MT((1-x)**(beta-1)*Heaviside(1-x) + a*(x-1)**(beta-1)*Heaviside(x-1), x, s)', + 'MT((x**a-b**a)/(x-b), x, s)', + 'MT((x**a-bpos**a)/(x-bpos), x, s)', + 'MT(exp(-x), x, s)', + 'MT(exp(-1/x), x, s)', + 'MT(log(x)**4*Heaviside(1-x), x, s)', + 'MT(log(x)**3*Heaviside(x-1), x, s)', + 'MT(log(x + 1), x, s)', + 'MT(log(1/x + 1), x, s)', + 'MT(log(abs(1 - x)), x, s)', + 'MT(log(abs(1 - 1/x)), x, s)', + 'MT(log(x)/(x+1), x, s)', + 'MT(log(x)**2/(x+1), x, s)', + 'MT(log(x)/(x+1)**2, x, s)', + 'MT(erf(sqrt(x)), x, s)', + + 'MT(besselj(a, 2*sqrt(x)), x, s)', + 'MT(sin(sqrt(x))*besselj(a, sqrt(x)), x, s)', + 'MT(cos(sqrt(x))*besselj(a, sqrt(x)), x, s)', + 'MT(besselj(a, sqrt(x))**2, x, s)', + 'MT(besselj(a, sqrt(x))*besselj(-a, sqrt(x)), x, s)', + 'MT(besselj(a - 1, sqrt(x))*besselj(a, sqrt(x)), x, s)', + 'MT(besselj(a, sqrt(x))*besselj(b, sqrt(x)), x, s)', + 'MT(besselj(a, sqrt(x))**2 + besselj(-a, sqrt(x))**2, x, s)', + 'MT(bessely(a, 2*sqrt(x)), x, s)', + 'MT(sin(sqrt(x))*bessely(a, sqrt(x)), x, s)', + 'MT(cos(sqrt(x))*bessely(a, sqrt(x)), x, s)', + 'MT(besselj(a, sqrt(x))*bessely(a, sqrt(x)), x, s)', + 'MT(besselj(a, sqrt(x))*bessely(b, sqrt(x)), x, s)', + 'MT(bessely(a, sqrt(x))**2, x, s)', + + 'MT(besselk(a, 2*sqrt(x)), x, s)', + 'MT(besselj(a, 2*sqrt(2*sqrt(x)))*besselk(a, 2*sqrt(2*sqrt(x))), x, s)', + 'MT(besseli(a, sqrt(x))*besselk(a, sqrt(x)), x, s)', + 'MT(besseli(b, sqrt(x))*besselk(a, sqrt(x)), x, s)', + 'MT(exp(-x/2)*besselk(a, x/2), x, s)', + + # later: ILT, IMT + + 'LT((t-apos)**bpos*exp(-cpos*(t-apos))*Heaviside(t-apos), t, s)', + 'LT(t**apos, t, s)', + 'LT(Heaviside(t), t, s)', + 'LT(Heaviside(t - apos), t, s)', + 'LT(1 - exp(-apos*t), t, s)', + 'LT((exp(2*t)-1)*exp(-bpos - t)*Heaviside(t)/2, t, s, noconds=True)', + 'LT(exp(t), t, s)', + 'LT(exp(2*t), t, s)', + 'LT(exp(apos*t), t, s)', + 'LT(log(t/apos), t, s)', + 'LT(erf(t), t, s)', + 'LT(sin(apos*t), t, s)', + 'LT(cos(apos*t), t, s)', + 'LT(exp(-apos*t)*sin(bpos*t), t, s)', + 'LT(exp(-apos*t)*cos(bpos*t), t, s)', + 'LT(besselj(0, t), t, s, noconds=True)', + 'LT(besselj(1, t), t, s, noconds=True)', + + 'FT(Heaviside(1 - abs(2*apos*x)), x, k)', + 'FT(Heaviside(1-abs(apos*x))*(1-abs(apos*x)), x, k)', + 'FT(exp(-apos*x)*Heaviside(x), x, k)', + 'IFT(1/(apos + 2*pi*I*x), x, posk, noconds=False)', + 'IFT(1/(apos + 2*pi*I*x), x, -posk, noconds=False)', + 'IFT(1/(apos + 2*pi*I*x), x, negk)', + 'FT(x*exp(-apos*x)*Heaviside(x), x, k)', + 'FT(exp(-apos*x)*sin(bpos*x)*Heaviside(x), x, k)', + 'FT(exp(-apos*x**2), x, k)', + 'IFT(sqrt(pi/apos)*exp(-(pi*k)**2/apos), k, x)', + 'FT(exp(-apos*abs(x)), x, k)', + + 'integrate(normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True)', + 'integrate(x*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True)', + 'integrate(x**2*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True)', + 'integrate(x**3*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True)', + 'integrate(normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' + ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', + 'integrate(x*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' + ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', + 'integrate(y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' + ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', + 'integrate(x*y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' + ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', + 'integrate((x+y+1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' + ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', + 'integrate((x+y-1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' + ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', + 'integrate(x**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' + ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', + 'integrate(y**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' + ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', + 'integrate(exponential(x, rate), (x, 0, oo), meijerg=True)', + 'integrate(x*exponential(x, rate), (x, 0, oo), meijerg=True)', + 'integrate(x**2*exponential(x, rate), (x, 0, oo), meijerg=True)', + 'E(1)', + 'E(x*y)', + 'E(x*y**2)', + 'E((x+y+1)**2)', + 'E(x+y+1)', + 'E((x+y-1)**2)', + 'integrate(betadist, (x, 0, oo), meijerg=True)', + 'integrate(x*betadist, (x, 0, oo), meijerg=True)', + 'integrate(x**2*betadist, (x, 0, oo), meijerg=True)', + 'integrate(chi, (x, 0, oo), meijerg=True)', + 'integrate(x*chi, (x, 0, oo), meijerg=True)', + 'integrate(x**2*chi, (x, 0, oo), meijerg=True)', + 'integrate(chisquared, (x, 0, oo), meijerg=True)', + 'integrate(x*chisquared, (x, 0, oo), meijerg=True)', + 'integrate(x**2*chisquared, (x, 0, oo), meijerg=True)', + 'integrate(((x-k)/sqrt(2*k))**3*chisquared, (x, 0, oo), meijerg=True)', + 'integrate(dagum, (x, 0, oo), meijerg=True)', + 'integrate(x*dagum, (x, 0, oo), meijerg=True)', + 'integrate(x**2*dagum, (x, 0, oo), meijerg=True)', + 'integrate(f, (x, 0, oo), meijerg=True)', + 'integrate(x*f, (x, 0, oo), meijerg=True)', + 'integrate(x**2*f, (x, 0, oo), meijerg=True)', + 'integrate(rice, (x, 0, oo), meijerg=True)', + 'integrate(laplace, (x, -oo, oo), meijerg=True)', + 'integrate(x*laplace, (x, -oo, oo), meijerg=True)', + 'integrate(x**2*laplace, (x, -oo, oo), meijerg=True)', + 'integrate(log(x) * x**(k-1) * exp(-x) / gamma(k), (x, 0, oo))', + + 'integrate(sin(z*x)*(x**2-1)**(-(y+S(1)/2)), (x, 1, oo), meijerg=True)', + 'integrate(besselj(0,x)*besselj(1,x)*exp(-x**2), (x, 0, oo), meijerg=True)', + 'integrate(besselj(0,x)*besselj(1,x)*besselk(0,x), (x, 0, oo), meijerg=True)', + 'integrate(besselj(0,x)*besselj(1,x)*exp(-x**2), (x, 0, oo), meijerg=True)', + 'integrate(besselj(a,x)*besselj(b,x)/x, (x,0,oo), meijerg=True)', + + 'hyperexpand(meijerg((-s - a/2 + 1, -s + a/2 + 1), (-a/2 - S(1)/2, -s + a/2 + S(3)/2), (a/2, -a/2), (-a/2 - S(1)/2, -s + a/2 + S(3)/2), 1))', + "gammasimp(S('2**(2*s)*(-pi*gamma(-a + 1)*gamma(a + 1)*gamma(-a - s + 1)*gamma(-a + s - 1/2)*gamma(a - s + 3/2)*gamma(a + s + 1)/(a*(a + s)) - gamma(-a - 1/2)*gamma(-a + 1)*gamma(a + 1)*gamma(a + 3/2)*gamma(-s + 3/2)*gamma(s - 1/2)*gamma(-a + s + 1)*gamma(a - s + 1)/(a*(-a + s)))*gamma(-2*s + 1)*gamma(s + 1)/(pi*s*gamma(-a - 1/2)*gamma(a + 3/2)*gamma(-s + 1)*gamma(-s + 3/2)*gamma(s - 1/2)*gamma(-a - s + 1)*gamma(-a + s - 1/2)*gamma(a - s + 1)*gamma(a - s + 3/2))'))", + + 'mellin_transform(E1(x), x, s)', + 'inverse_mellin_transform(gamma(s)/s, s, x, (0, oo))', + 'mellin_transform(expint(a, x), x, s)', + 'mellin_transform(Si(x), x, s)', + 'inverse_mellin_transform(-2**s*sqrt(pi)*gamma((s + 1)/2)/(2*s*gamma(-s/2 + 1)), s, x, (-1, 0))', + 'mellin_transform(Ci(sqrt(x)), x, s)', + 'inverse_mellin_transform(-4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S(1)/2)),s, u, (0, 1))', + 'laplace_transform(Ci(x), x, s)', + 'laplace_transform(expint(a, x), x, s)', + 'laplace_transform(expint(1, x), x, s)', + 'laplace_transform(expint(2, x), x, s)', + 'inverse_laplace_transform(-log(1 + s**2)/2/s, s, u)', + 'inverse_laplace_transform(log(s + 1)/s, s, x)', + 'inverse_laplace_transform((s - log(s + 1))/s**2, s, x)', + 'laplace_transform(Chi(x), x, s)', + 'laplace_transform(Shi(x), x, s)', + + 'integrate(exp(-z*x)/x, (x, 1, oo), meijerg=True, conds="none")', + 'integrate(exp(-z*x)/x**2, (x, 1, oo), meijerg=True, conds="none")', + 'integrate(exp(-z*x)/x**3, (x, 1, oo), meijerg=True,conds="none")', + 'integrate(-cos(x)/x, (x, tpos, oo), meijerg=True)', + 'integrate(-sin(x)/x, (x, tpos, oo), meijerg=True)', + 'integrate(sin(x)/x, (x, 0, z), meijerg=True)', + 'integrate(sinh(x)/x, (x, 0, z), meijerg=True)', + 'integrate(exp(-x)/x, x, meijerg=True)', + 'integrate(exp(-x)/x**2, x, meijerg=True)', + 'integrate(cos(u)/u, u, meijerg=True)', + 'integrate(cosh(u)/u, u, meijerg=True)', + 'integrate(expint(1, x), x, meijerg=True)', + 'integrate(expint(2, x), x, meijerg=True)', + 'integrate(Si(x), x, meijerg=True)', + 'integrate(Ci(u), u, meijerg=True)', + 'integrate(Shi(x), x, meijerg=True)', + 'integrate(Chi(u), u, meijerg=True)', + 'integrate(Si(x)*exp(-x), (x, 0, oo), meijerg=True)', + 'integrate(expint(1, x)*sin(x), (x, 0, oo), meijerg=True)' +] + +from time import time +from sympy.core.cache import clear_cache +import sys + +timings = [] + +if __name__ == '__main__': + for n, string in enumerate(bench): + clear_cache() + _t = time() + exec(string) + _t = time() - _t + timings += [(_t, string)] + sys.stdout.write('.') + sys.stdout.flush() + if n % (len(bench) // 10) == 0: + sys.stdout.write('%s' % (10*n // len(bench))) + print() + + timings.sort(key=lambda x: -x[0]) + + for ti, string in timings: + print('%.2fs %s' % (ti, string)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_symbench.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_symbench.py new file mode 100644 index 0000000000000000000000000000000000000000..8ea700b44b677107f5345196a8895e8ed5a9d56d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/benchmarks/bench_symbench.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python +from sympy.core.random import random +from sympy.core.numbers import (I, Integer, pi) +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.polys.polytools import factor +from sympy.simplify.simplify import simplify +from sympy.abc import x, y, z +from timeit import default_timer as clock + + +def bench_R1(): + "real(f(f(f(f(f(f(f(f(f(f(i/2)))))))))))" + def f(z): + return sqrt(Integer(1)/3)*z**2 + I/3 + f(f(f(f(f(f(f(f(f(f(I/2)))))))))).as_real_imag()[0] + + +def bench_R2(): + "Hermite polynomial hermite(15, y)" + def hermite(n, y): + if n == 1: + return 2*y + if n == 0: + return 1 + return (2*y*hermite(n - 1, y) - 2*(n - 1)*hermite(n - 2, y)).expand() + + hermite(15, y) + + +def bench_R3(): + "a = [bool(f==f) for _ in range(10)]" + f = x + y + z + [bool(f == f) for _ in range(10)] + + +def bench_R4(): + # we don't have Tuples + pass + + +def bench_R5(): + "blowup(L, 8); L=uniq(L)" + def blowup(L, n): + for i in range(n): + L.append( (L[i] + L[i + 1]) * L[i + 2] ) + + def uniq(x): + v = set(x) + return v + L = [x, y, z] + blowup(L, 8) + L = uniq(L) + + +def bench_R6(): + "sum(simplify((x+sin(i))/x+(x-sin(i))/x) for i in range(100))" + sum(simplify((x + sin(i))/x + (x - sin(i))/x) for i in range(100)) + + +def bench_R7(): + "[f.subs(x, random()) for _ in range(10**4)]" + f = x**24 + 34*x**12 + 45*x**3 + 9*x**18 + 34*x**10 + 32*x**21 + [f.subs(x, random()) for _ in range(10**4)] + + +def bench_R8(): + "right(x^2,0,5,10^4)" + def right(f, a, b, n): + a = sympify(a) + b = sympify(b) + n = sympify(n) + x = f.atoms(Symbol).pop() + Deltax = (b - a)/n + c = a + est = 0 + for i in range(n): + c += Deltax + est += f.subs(x, c) + return est*Deltax + + right(x**2, 0, 5, 10**4) + + +def _bench_R9(): + "factor(x^20 - pi^5*y^20)" + factor(x**20 - pi**5*y**20) + + +def bench_R10(): + "v = [-pi,-pi+1/10..,pi]" + def srange(min, max, step): + v = [min] + while (max - v[-1]).evalf() > 0: + v.append(v[-1] + step) + return v[:-1] + srange(-pi, pi, sympify(1)/10) + + +def bench_R11(): + "a = [random() + random()*I for w in [0..1000]]" + [random() + random()*I for w in range(1000)] + + +def bench_S1(): + "e=(x+y+z+1)**7;f=e*(e+1);f.expand()" + e = (x + y + z + 1)**7 + f = e*(e + 1) + f.expand() + + +if __name__ == '__main__': + benchmarks = [ + bench_R1, + bench_R2, + bench_R3, + bench_R5, + bench_R6, + bench_R7, + bench_R8, + #_bench_R9, + bench_R10, + bench_R11, + #bench_S1, + ] + + report = [] + for b in benchmarks: + t = clock() + b() + t = clock() - t + print("%s%65s: %f" % (b.__name__, b.__doc__, t)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..865c0556769e35ca7e8a09a4c208a1cfbd17369c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/__init__.py @@ -0,0 +1,25 @@ +"""Calculus-related methods.""" + +from .euler import euler_equations +from .singularities import (singularities, is_increasing, + is_strictly_increasing, is_decreasing, + is_strictly_decreasing, is_monotonic) +from .finite_diff import finite_diff_weights, apply_finite_diff, differentiate_finite +from .util import (periodicity, not_empty_in, is_convex, + stationary_points, minimum, maximum) +from .accumulationbounds import AccumBounds + +__all__ = [ +'euler_equations', + +'singularities', 'is_increasing', +'is_strictly_increasing', 'is_decreasing', +'is_strictly_decreasing', 'is_monotonic', + +'finite_diff_weights', 'apply_finite_diff', 'differentiate_finite', + +'periodicity', 'not_empty_in', 'is_convex', 'stationary_points', +'minimum', 'maximum', + +'AccumBounds' +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/accumulationbounds.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/accumulationbounds.py new file mode 100644 index 0000000000000000000000000000000000000000..8a2b0e634da1028c25399c8b03884865d981a56e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/accumulationbounds.py @@ -0,0 +1,804 @@ +from sympy.core import Add, Mul, Pow, S +from sympy.core.basic import Basic +from sympy.core.expr import Expr +from sympy.core.numbers import _sympifyit, oo, zoo +from sympy.core.relational import is_le, is_lt, is_ge, is_gt +from sympy.core.sympify import _sympify +from sympy.functions.elementary.miscellaneous import Min, Max +from sympy.logic.boolalg import And +from sympy.multipledispatch import dispatch +from sympy.series.order import Order +from sympy.sets.sets import FiniteSet + + +class AccumulationBounds(Expr): + r"""An accumulation bounds. + + # Note AccumulationBounds has an alias: AccumBounds + + AccumulationBounds represent an interval `[a, b]`, which is always closed + at the ends. Here `a` and `b` can be any value from extended real numbers. + + The intended meaning of AccummulationBounds is to give an approximate + location of the accumulation points of a real function at a limit point. + + Let `a` and `b` be reals such that `a \le b`. + + `\left\langle a, b\right\rangle = \{x \in \mathbb{R} \mid a \le x \le b\}` + + `\left\langle -\infty, b\right\rangle = \{x \in \mathbb{R} \mid x \le b\} \cup \{-\infty, \infty\}` + + `\left\langle a, \infty \right\rangle = \{x \in \mathbb{R} \mid a \le x\} \cup \{-\infty, \infty\}` + + `\left\langle -\infty, \infty \right\rangle = \mathbb{R} \cup \{-\infty, \infty\}` + + ``oo`` and ``-oo`` are added to the second and third definition respectively, + since if either ``-oo`` or ``oo`` is an argument, then the other one should + be included (though not as an end point). This is forced, since we have, + for example, ``1/AccumBounds(0, 1) = AccumBounds(1, oo)``, and the limit at + `0` is not one-sided. As `x` tends to `0-`, then `1/x \rightarrow -\infty`, so `-\infty` + should be interpreted as belonging to ``AccumBounds(1, oo)`` though it need + not appear explicitly. + + In many cases it suffices to know that the limit set is bounded. + However, in some other cases more exact information could be useful. + For example, all accumulation values of `\cos(x) + 1` are non-negative. + (``AccumBounds(-1, 1) + 1 = AccumBounds(0, 2)``) + + A AccumulationBounds object is defined to be real AccumulationBounds, + if its end points are finite reals. + + Let `X`, `Y` be real AccumulationBounds, then their sum, difference, + product are defined to be the following sets: + + `X + Y = \{ x+y \mid x \in X \cap y \in Y\}` + + `X - Y = \{ x-y \mid x \in X \cap y \in Y\}` + + `X \times Y = \{ x \times y \mid x \in X \cap y \in Y\}` + + When an AccumBounds is raised to a negative power, if 0 is contained + between the bounds then an infinite range is returned, otherwise if an + endpoint is 0 then a semi-infinite range with consistent sign will be returned. + + AccumBounds in expressions behave a lot like Intervals but the + semantics are not necessarily the same. Division (or exponentiation + to a negative integer power) could be handled with *intervals* by + returning a union of the results obtained after splitting the + bounds between negatives and positives, but that is not done with + AccumBounds. In addition, bounds are assumed to be independent of + each other; if the same bound is used in more than one place in an + expression, the result may not be the supremum or infimum of the + expression (see below). Finally, when a boundary is ``1``, + exponentiation to the power of ``oo`` yields ``oo``, neither + ``1`` nor ``nan``. + + Examples + ======== + + >>> from sympy import AccumBounds, sin, exp, log, pi, E, S, oo + >>> from sympy.abc import x + + >>> AccumBounds(0, 1) + AccumBounds(1, 2) + AccumBounds(1, 3) + + >>> AccumBounds(0, 1) - AccumBounds(0, 2) + AccumBounds(-2, 1) + + >>> AccumBounds(-2, 3)*AccumBounds(-1, 1) + AccumBounds(-3, 3) + + >>> AccumBounds(1, 2)*AccumBounds(3, 5) + AccumBounds(3, 10) + + The exponentiation of AccumulationBounds is defined + as follows: + + If 0 does not belong to `X` or `n > 0` then + + `X^n = \{ x^n \mid x \in X\}` + + >>> AccumBounds(1, 4)**(S(1)/2) + AccumBounds(1, 2) + + otherwise, an infinite or semi-infinite result is obtained: + + >>> 1/AccumBounds(-1, 1) + AccumBounds(-oo, oo) + >>> 1/AccumBounds(0, 2) + AccumBounds(1/2, oo) + >>> 1/AccumBounds(-oo, 0) + AccumBounds(-oo, 0) + + A boundary of 1 will always generate all nonnegatives: + + >>> AccumBounds(1, 2)**oo + AccumBounds(0, oo) + >>> AccumBounds(0, 1)**oo + AccumBounds(0, oo) + + If the exponent is itself an AccumulationBounds or is not an + integer then unevaluated results will be returned unless the base + values are positive: + + >>> AccumBounds(2, 3)**AccumBounds(-1, 2) + AccumBounds(1/3, 9) + >>> AccumBounds(-2, 3)**AccumBounds(-1, 2) + AccumBounds(-2, 3)**AccumBounds(-1, 2) + + >>> AccumBounds(-2, -1)**(S(1)/2) + sqrt(AccumBounds(-2, -1)) + + Note: `\left\langle a, b\right\rangle^2` is not same as `\left\langle a, b\right\rangle \times \left\langle a, b\right\rangle` + + >>> AccumBounds(-1, 1)**2 + AccumBounds(0, 1) + + >>> AccumBounds(1, 3) < 4 + True + + >>> AccumBounds(1, 3) < -1 + False + + Some elementary functions can also take AccumulationBounds as input. + A function `f` evaluated for some real AccumulationBounds `\left\langle a, b \right\rangle` + is defined as `f(\left\langle a, b\right\rangle) = \{ f(x) \mid a \le x \le b \}` + + >>> sin(AccumBounds(pi/6, pi/3)) + AccumBounds(1/2, sqrt(3)/2) + + >>> exp(AccumBounds(0, 1)) + AccumBounds(1, E) + + >>> log(AccumBounds(1, E)) + AccumBounds(0, 1) + + Some symbol in an expression can be substituted for a AccumulationBounds + object. But it does not necessarily evaluate the AccumulationBounds for + that expression. + + The same expression can be evaluated to different values depending upon + the form it is used for substitution since each instance of an + AccumulationBounds is considered independent. For example: + + >>> (x**2 + 2*x + 1).subs(x, AccumBounds(-1, 1)) + AccumBounds(-1, 4) + + >>> ((x + 1)**2).subs(x, AccumBounds(-1, 1)) + AccumBounds(0, 4) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Interval_arithmetic + + .. [2] https://fab.cba.mit.edu/classes/S62.12/docs/Hickey_interval.pdf + + Notes + ===== + + Do not use ``AccumulationBounds`` for floating point interval arithmetic + calculations, use ``mpmath.iv`` instead. + """ + + is_extended_real = True + is_number = False + + def __new__(cls, min, max) -> Expr: # type: ignore + + min = _sympify(min) + max = _sympify(max) + + # Only allow real intervals (use symbols with 'is_extended_real=True'). + if not min.is_extended_real or not max.is_extended_real: + raise ValueError("Only real AccumulationBounds are supported") + + if max == min: + return max + + # Make sure that the created AccumBounds object will be valid. + if max.is_number and min.is_number: + bad = max.is_comparable and min.is_comparable and max < min + else: + bad = (max - min).is_extended_negative + if bad: + raise ValueError( + "Lower limit should be smaller than upper limit") + + return Basic.__new__(cls, min, max) + + # setting the operation priority + _op_priority = 11.0 + + def _eval_is_real(self): + if self.min.is_real and self.max.is_real: + return True + + @property + def min(self): + """ + Returns the minimum possible value attained by AccumulationBounds + object. + + Examples + ======== + + >>> from sympy import AccumBounds + >>> AccumBounds(1, 3).min + 1 + + """ + return self.args[0] + + @property + def max(self): + """ + Returns the maximum possible value attained by AccumulationBounds + object. + + Examples + ======== + + >>> from sympy import AccumBounds + >>> AccumBounds(1, 3).max + 3 + + """ + return self.args[1] + + @property + def delta(self): + """ + Returns the difference of maximum possible value attained by + AccumulationBounds object and minimum possible value attained + by AccumulationBounds object. + + Examples + ======== + + >>> from sympy import AccumBounds + >>> AccumBounds(1, 3).delta + 2 + + """ + return self.max - self.min + + @property + def mid(self): + """ + Returns the mean of maximum possible value attained by + AccumulationBounds object and minimum possible value + attained by AccumulationBounds object. + + Examples + ======== + + >>> from sympy import AccumBounds + >>> AccumBounds(1, 3).mid + 2 + + """ + return (self.min + self.max) / 2 + + @_sympifyit('other', NotImplemented) + def _eval_power(self, other): + return self.__pow__(other) + + @_sympifyit('other', NotImplemented) + def __add__(self, other): + if isinstance(other, Expr): + if isinstance(other, AccumBounds): + return AccumBounds( + Add(self.min, other.min), + Add(self.max, other.max)) + if other is S.Infinity and self.min is S.NegativeInfinity or \ + other is S.NegativeInfinity and self.max is S.Infinity: + return AccumBounds(-oo, oo) + elif other.is_extended_real: + if self.min is S.NegativeInfinity and self.max is S.Infinity: + return AccumBounds(-oo, oo) + elif self.min is S.NegativeInfinity: + return AccumBounds(-oo, self.max + other) + elif self.max is S.Infinity: + return AccumBounds(self.min + other, oo) + else: + return AccumBounds(Add(self.min, other), Add(self.max, other)) + return Add(self, other, evaluate=False) + return NotImplemented + + __radd__ = __add__ + + def __neg__(self): + return AccumBounds(-self.max, -self.min) + + @_sympifyit('other', NotImplemented) + def __sub__(self, other): + if isinstance(other, Expr): + if isinstance(other, AccumBounds): + return AccumBounds( + Add(self.min, -other.max), + Add(self.max, -other.min)) + if other is S.NegativeInfinity and self.min is S.NegativeInfinity or \ + other is S.Infinity and self.max is S.Infinity: + return AccumBounds(-oo, oo) + elif other.is_extended_real: + if self.min is S.NegativeInfinity and self.max is S.Infinity: + return AccumBounds(-oo, oo) + elif self.min is S.NegativeInfinity: + return AccumBounds(-oo, self.max - other) + elif self.max is S.Infinity: + return AccumBounds(self.min - other, oo) + else: + return AccumBounds( + Add(self.min, -other), + Add(self.max, -other)) + return Add(self, -other, evaluate=False) + return NotImplemented + + @_sympifyit('other', NotImplemented) + def __rsub__(self, other): + return self.__neg__() + other + + @_sympifyit('other', NotImplemented) + def __mul__(self, other): + if self.args == (-oo, oo): + return self + if isinstance(other, Expr): + if isinstance(other, AccumBounds): + if other.args == (-oo, oo): + return other + v = set() + for a in self.args: + vi = other*a + v.update(vi.args or (vi,)) + return AccumBounds(Min(*v), Max(*v)) + if other is S.Infinity: + if self.min.is_zero: + return AccumBounds(0, oo) + if self.max.is_zero: + return AccumBounds(-oo, 0) + if other is S.NegativeInfinity: + if self.min.is_zero: + return AccumBounds(-oo, 0) + if self.max.is_zero: + return AccumBounds(0, oo) + if other.is_extended_real: + if other.is_zero: + if self.max is S.Infinity: + return AccumBounds(0, oo) + if self.min is S.NegativeInfinity: + return AccumBounds(-oo, 0) + return S.Zero + if other.is_extended_positive: + return AccumBounds( + Mul(self.min, other), + Mul(self.max, other)) + elif other.is_extended_negative: + return AccumBounds( + Mul(self.max, other), + Mul(self.min, other)) + if isinstance(other, Order): + return other + return Mul(self, other, evaluate=False) + return NotImplemented + + __rmul__ = __mul__ + + @_sympifyit('other', NotImplemented) + def __truediv__(self, other): + if isinstance(other, Expr): + if isinstance(other, AccumBounds): + if other.min.is_positive or other.max.is_negative: + return self * AccumBounds(1/other.max, 1/other.min) + + if (self.min.is_extended_nonpositive and self.max.is_extended_nonnegative and + other.min.is_extended_nonpositive and other.max.is_extended_nonnegative): + if self.min.is_zero and other.min.is_zero: + return AccumBounds(0, oo) + if self.max.is_zero and other.min.is_zero: + return AccumBounds(-oo, 0) + return AccumBounds(-oo, oo) + + if self.max.is_extended_negative: + if other.min.is_extended_negative: + if other.max.is_zero: + return AccumBounds(self.max / other.min, oo) + if other.max.is_extended_positive: + # if we were dealing with intervals we would return + # Union(Interval(-oo, self.max/other.max), + # Interval(self.max/other.min, oo)) + return AccumBounds(-oo, oo) + + if other.min.is_zero and other.max.is_extended_positive: + return AccumBounds(-oo, self.max / other.max) + + if self.min.is_extended_positive: + if other.min.is_extended_negative: + if other.max.is_zero: + return AccumBounds(-oo, self.min / other.min) + if other.max.is_extended_positive: + # if we were dealing with intervals we would return + # Union(Interval(-oo, self.min/other.min), + # Interval(self.min/other.max, oo)) + return AccumBounds(-oo, oo) + + if other.min.is_zero and other.max.is_extended_positive: + return AccumBounds(self.min / other.max, oo) + + elif other.is_extended_real: + if other in (S.Infinity, S.NegativeInfinity): + if self == AccumBounds(-oo, oo): + return AccumBounds(-oo, oo) + if self.max is S.Infinity: + return AccumBounds(Min(0, other), Max(0, other)) + if self.min is S.NegativeInfinity: + return AccumBounds(Min(0, -other), Max(0, -other)) + if other.is_extended_positive: + return AccumBounds(self.min / other, self.max / other) + elif other.is_extended_negative: + return AccumBounds(self.max / other, self.min / other) + if (1 / other) is S.ComplexInfinity: + return Mul(self, 1 / other, evaluate=False) + else: + return Mul(self, 1 / other) + + return NotImplemented + + @_sympifyit('other', NotImplemented) + def __rtruediv__(self, other): + if isinstance(other, Expr): + if other.is_extended_real: + if other.is_zero: + return S.Zero + if (self.min.is_extended_nonpositive and self.max.is_extended_nonnegative): + if self.min.is_zero: + if other.is_extended_positive: + return AccumBounds(Mul(other, 1 / self.max), oo) + if other.is_extended_negative: + return AccumBounds(-oo, Mul(other, 1 / self.max)) + if self.max.is_zero: + if other.is_extended_positive: + return AccumBounds(-oo, Mul(other, 1 / self.min)) + if other.is_extended_negative: + return AccumBounds(Mul(other, 1 / self.min), oo) + return AccumBounds(-oo, oo) + else: + return AccumBounds(Min(other / self.min, other / self.max), + Max(other / self.min, other / self.max)) + return Mul(other, 1 / self, evaluate=False) + else: + return NotImplemented + + @_sympifyit('other', NotImplemented) + def __pow__(self, other): + if isinstance(other, Expr): + if other is S.Infinity: + if self.min.is_extended_nonnegative: + if self.max < 1: + return S.Zero + if self.min > 1: + return S.Infinity + return AccumBounds(0, oo) + elif self.max.is_extended_negative: + if self.min > -1: + return S.Zero + if self.max < -1: + return zoo + return S.NaN + else: + if self.min > -1: + if self.max < 1: + return S.Zero + return AccumBounds(0, oo) + return AccumBounds(-oo, oo) + + if other is S.NegativeInfinity: + return (1/self)**oo + + # generically true + if (self.max - self.min).is_nonnegative: + # well defined + if self.min.is_nonnegative: + # no 0 to worry about + if other.is_nonnegative: + # no infinity to worry about + return self.func(self.min**other, self.max**other) + + if other.is_zero: + return S.One # x**0 = 1 + + if other.is_Integer or other.is_integer: + if self.min.is_extended_positive: + return AccumBounds( + Min(self.min**other, self.max**other), + Max(self.min**other, self.max**other)) + elif self.max.is_extended_negative: + return AccumBounds( + Min(self.max**other, self.min**other), + Max(self.max**other, self.min**other)) + + if other % 2 == 0: + if other.is_extended_negative: + if self.min.is_zero: + return AccumBounds(self.max**other, oo) + if self.max.is_zero: + return AccumBounds(self.min**other, oo) + return (1/self)**(-other) + return AccumBounds( + S.Zero, Max(self.min**other, self.max**other)) + elif other % 2 == 1: + if other.is_extended_negative: + if self.min.is_zero: + return AccumBounds(self.max**other, oo) + if self.max.is_zero: + return AccumBounds(-oo, self.min**other) + return (1/self)**(-other) + return AccumBounds(self.min**other, self.max**other) + + # non-integer exponent + # 0**neg or neg**frac yields complex + if (other.is_number or other.is_rational) and ( + self.min.is_extended_nonnegative or ( + other.is_extended_nonnegative and + self.min.is_extended_nonnegative)): + num, den = other.as_numer_denom() + if num is S.One: + return AccumBounds(*[i**(1/den) for i in self.args]) + + elif den is not S.One: # e.g. if other is not Float + return (self**num)**(1/den) # ok for non-negative base + + if isinstance(other, AccumBounds): + if (self.min.is_extended_positive or + self.min.is_extended_nonnegative and + other.min.is_extended_nonnegative): + p = [self**i for i in other.args] + if not any(i.is_Pow for i in p): + a = [j for i in p for j in i.args or (i,)] + try: + return self.func(min(a), max(a)) + except TypeError: # can't sort + pass + + return Pow(self, other, evaluate=False) + + return NotImplemented + + @_sympifyit('other', NotImplemented) + def __rpow__(self, other): + if other.is_real and other.is_extended_nonnegative and ( + self.max - self.min).is_extended_positive: + if other is S.One: + return S.One + if other.is_extended_positive: + a, b = [other**i for i in self.args] + if min(a, b) != a: + a, b = b, a + return self.func(a, b) + if other.is_zero: + if self.min.is_zero: + return self.func(0, 1) + if self.min.is_extended_positive: + return S.Zero + + return Pow(other, self, evaluate=False) + + def __abs__(self): + if self.max.is_extended_negative: + return self.__neg__() + elif self.min.is_extended_negative: + return AccumBounds(S.Zero, Max(abs(self.min), self.max)) + else: + return self + + + def __contains__(self, other): + """ + Returns ``True`` if other is contained in self, where other + belongs to extended real numbers, ``False`` if not contained, + otherwise TypeError is raised. + + Examples + ======== + + >>> from sympy import AccumBounds, oo + >>> 1 in AccumBounds(-1, 3) + True + + -oo and oo go together as limits (in AccumulationBounds). + + >>> -oo in AccumBounds(1, oo) + True + + >>> oo in AccumBounds(-oo, 0) + True + + """ + other = _sympify(other) + + if other in (S.Infinity, S.NegativeInfinity): + if self.min is S.NegativeInfinity or self.max is S.Infinity: + return True + return False + + rv = And(self.min <= other, self.max >= other) + if rv not in (True, False): + raise TypeError("input failed to evaluate") + return rv + + def intersection(self, other): + """ + Returns the intersection of 'self' and 'other'. + Here other can be an instance of :py:class:`~.FiniteSet` or AccumulationBounds. + + Parameters + ========== + + other : AccumulationBounds + Another AccumulationBounds object with which the intersection + has to be computed. + + Returns + ======= + + AccumulationBounds + Intersection of ``self`` and ``other``. + + Examples + ======== + + >>> from sympy import AccumBounds, FiniteSet + >>> AccumBounds(1, 3).intersection(AccumBounds(2, 4)) + AccumBounds(2, 3) + + >>> AccumBounds(1, 3).intersection(AccumBounds(4, 6)) + EmptySet + + >>> AccumBounds(1, 4).intersection(FiniteSet(1, 2, 5)) + {1, 2} + + """ + if not isinstance(other, (AccumBounds, FiniteSet)): + raise TypeError( + "Input must be AccumulationBounds or FiniteSet object") + + if isinstance(other, FiniteSet): + fin_set = S.EmptySet + for i in other: + if i in self: + fin_set = fin_set + FiniteSet(i) + return fin_set + + if self.max < other.min or self.min > other.max: + return S.EmptySet + + if self.min <= other.min: + if self.max <= other.max: + return AccumBounds(other.min, self.max) + if self.max > other.max: + return other + + if other.min <= self.min: + if other.max < self.max: + return AccumBounds(self.min, other.max) + if other.max > self.max: + return self + + def union(self, other): + # TODO : Devise a better method for Union of AccumBounds + # this method is not actually correct and + # can be made better + if not isinstance(other, AccumBounds): + raise TypeError( + "Input must be AccumulationBounds or FiniteSet object") + + if self.min <= other.min and self.max >= other.min: + return AccumBounds(self.min, Max(self.max, other.max)) + + if other.min <= self.min and other.max >= self.min: + return AccumBounds(other.min, Max(self.max, other.max)) + + +@dispatch(AccumulationBounds, AccumulationBounds) # type: ignore # noqa:F811 +def _eval_is_le(lhs, rhs): # noqa:F811 + if is_le(lhs.max, rhs.min): + return True + if is_gt(lhs.min, rhs.max): + return False + + +@dispatch(AccumulationBounds, Basic) # type: ignore # noqa:F811 +def _eval_is_le(lhs, rhs): # noqa: F811 + + """ + Returns ``True `` if range of values attained by ``lhs`` AccumulationBounds + object is greater than the range of values attained by ``rhs``, + where ``rhs`` may be any value of type AccumulationBounds object or + extended real number value, ``False`` if ``rhs`` satisfies + the same property, else an unevaluated :py:class:`~.Relational`. + + Examples + ======== + + >>> from sympy import AccumBounds, oo + >>> AccumBounds(1, 3) > AccumBounds(4, oo) + False + >>> AccumBounds(1, 4) > AccumBounds(3, 4) + AccumBounds(1, 4) > AccumBounds(3, 4) + >>> AccumBounds(1, oo) > -1 + True + + """ + if not rhs.is_extended_real: + raise TypeError( + "Invalid comparison of %s %s" % + (type(rhs), rhs)) + elif rhs.is_comparable: + if is_le(lhs.max, rhs): + return True + if is_gt(lhs.min, rhs): + return False + + +@dispatch(AccumulationBounds, AccumulationBounds) +def _eval_is_ge(lhs, rhs): # noqa:F811 + if is_ge(lhs.min, rhs.max): + return True + if is_lt(lhs.max, rhs.min): + return False + + +@dispatch(AccumulationBounds, Expr) # type:ignore +def _eval_is_ge(lhs, rhs): # noqa: F811 + """ + Returns ``True`` if range of values attained by ``lhs`` AccumulationBounds + object is less that the range of values attained by ``rhs``, where + other may be any value of type AccumulationBounds object or extended + real number value, ``False`` if ``rhs`` satisfies the same + property, else an unevaluated :py:class:`~.Relational`. + + Examples + ======== + + >>> from sympy import AccumBounds, oo + >>> AccumBounds(1, 3) >= AccumBounds(4, oo) + False + >>> AccumBounds(1, 4) >= AccumBounds(3, 4) + AccumBounds(1, 4) >= AccumBounds(3, 4) + >>> AccumBounds(1, oo) >= 1 + True + """ + + if not rhs.is_extended_real: + raise TypeError( + "Invalid comparison of %s %s" % + (type(rhs), rhs)) + elif rhs.is_comparable: + if is_ge(lhs.min, rhs): + return True + if is_lt(lhs.max, rhs): + return False + + +@dispatch(Expr, AccumulationBounds) # type:ignore +def _eval_is_ge(lhs, rhs): # noqa:F811 + if not lhs.is_extended_real: + raise TypeError( + "Invalid comparison of %s %s" % + (type(lhs), lhs)) + elif lhs.is_comparable: + if is_le(rhs.max, lhs): + return True + if is_gt(rhs.min, lhs): + return False + + +@dispatch(AccumulationBounds, AccumulationBounds) # type:ignore +def _eval_is_ge(lhs, rhs): # noqa:F811 + if is_ge(lhs.min, rhs.max): + return True + if is_lt(lhs.max, rhs.min): + return False + +# setting an alias for AccumulationBounds +AccumBounds = AccumulationBounds diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/euler.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/euler.py new file mode 100644 index 0000000000000000000000000000000000000000..817acf76091dfba2dba40487ca7735e307c0fc15 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/euler.py @@ -0,0 +1,108 @@ +""" +This module implements a method to find +Euler-Lagrange Equations for given Lagrangian. +""" +from itertools import combinations_with_replacement +from sympy.core.function import (Derivative, Function, diff) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.utilities.iterables import iterable + + +def euler_equations(L, funcs=(), vars=()): + r""" + Find the Euler-Lagrange equations [1]_ for a given Lagrangian. + + Parameters + ========== + + L : Expr + The Lagrangian that should be a function of the functions listed + in the second argument and their derivatives. + + For example, in the case of two functions $f(x,y)$, $g(x,y)$ and + two independent variables $x$, $y$ the Lagrangian has the form: + + .. math:: L\left(f(x,y),g(x,y),\frac{\partial f(x,y)}{\partial x}, + \frac{\partial f(x,y)}{\partial y}, + \frac{\partial g(x,y)}{\partial x}, + \frac{\partial g(x,y)}{\partial y},x,y\right) + + In many cases it is not necessary to provide anything, except the + Lagrangian, it will be auto-detected (and an error raised if this + cannot be done). + + funcs : Function or an iterable of Functions + The functions that the Lagrangian depends on. The Euler equations + are differential equations for each of these functions. + + vars : Symbol or an iterable of Symbols + The Symbols that are the independent variables of the functions. + + Returns + ======= + + eqns : list of Eq + The list of differential equations, one for each function. + + Examples + ======== + + >>> from sympy import euler_equations, Symbol, Function + >>> x = Function('x') + >>> t = Symbol('t') + >>> L = (x(t).diff(t))**2/2 - x(t)**2/2 + >>> euler_equations(L, x(t), t) + [Eq(-x(t) - Derivative(x(t), (t, 2)), 0)] + >>> u = Function('u') + >>> x = Symbol('x') + >>> L = (u(t, x).diff(t))**2/2 - (u(t, x).diff(x))**2/2 + >>> euler_equations(L, u(t, x), [t, x]) + [Eq(-Derivative(u(t, x), (t, 2)) + Derivative(u(t, x), (x, 2)), 0)] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Euler%E2%80%93Lagrange_equation + + """ + + funcs = tuple(funcs) if iterable(funcs) else (funcs,) + + if not funcs: + funcs = tuple(L.atoms(Function)) + else: + for f in funcs: + if not isinstance(f, Function): + raise TypeError('Function expected, got: %s' % f) + + vars = tuple(vars) if iterable(vars) else (vars,) + + if not vars: + vars = funcs[0].args + else: + vars = tuple(sympify(var) for var in vars) + + if not all(isinstance(v, Symbol) for v in vars): + raise TypeError('Variables are not symbols, got %s' % vars) + + for f in funcs: + if not vars == f.args: + raise ValueError("Variables %s do not match args: %s" % (vars, f)) + + order = max([len(d.variables) for d in L.atoms(Derivative) + if d.expr in funcs] + [0]) + + eqns = [] + for f in funcs: + eq = diff(L, f) + for i in range(1, order + 1): + for p in combinations_with_replacement(vars, i): + eq = eq + S.NegativeOne**i*diff(L, diff(f, *p), *p) + new_eq = Eq(eq, 0) + if isinstance(new_eq, Eq): + eqns.append(new_eq) + + return eqns diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/finite_diff.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/finite_diff.py new file mode 100644 index 0000000000000000000000000000000000000000..17eece149aadad236cefeb350e1ef4a383c84f01 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/finite_diff.py @@ -0,0 +1,476 @@ +""" +Finite difference weights +========================= + +This module implements an algorithm for efficient generation of finite +difference weights for ordinary differentials of functions for +derivatives from 0 (interpolation) up to arbitrary order. + +The core algorithm is provided in the finite difference weight generating +function (``finite_diff_weights``), and two convenience functions are provided +for: + +- estimating a derivative (or interpolate) directly from a series of points + is also provided (``apply_finite_diff``). +- differentiating by using finite difference approximations + (``differentiate_finite``). + +""" + +from sympy.core.function import Derivative +from sympy.core.singleton import S +from sympy.core.function import Subs +from sympy.core.traversal import preorder_traversal +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import iterable + + + +def finite_diff_weights(order, x_list, x0=S.One): + """ + Calculates the finite difference weights for an arbitrarily spaced + one-dimensional grid (``x_list``) for derivatives at ``x0`` of order + 0, 1, ..., up to ``order`` using a recursive formula. Order of accuracy + is at least ``len(x_list) - order``, if ``x_list`` is defined correctly. + + Parameters + ========== + + order: int + Up to what derivative order weights should be calculated. + 0 corresponds to interpolation. + x_list: sequence + Sequence of (unique) values for the independent variable. + It is useful (but not necessary) to order ``x_list`` from + nearest to furthest from ``x0``; see examples below. + x0: Number or Symbol + Root or value of the independent variable for which the finite + difference weights should be generated. Default is ``S.One``. + + Returns + ======= + + list + A list of sublists, each corresponding to coefficients for + increasing derivative order, and each containing lists of + coefficients for increasing subsets of x_list. + + Examples + ======== + + >>> from sympy import finite_diff_weights, S + >>> res = finite_diff_weights(1, [-S(1)/2, S(1)/2, S(3)/2, S(5)/2], 0) + >>> res + [[[1, 0, 0, 0], + [1/2, 1/2, 0, 0], + [3/8, 3/4, -1/8, 0], + [5/16, 15/16, -5/16, 1/16]], + [[0, 0, 0, 0], + [-1, 1, 0, 0], + [-1, 1, 0, 0], + [-23/24, 7/8, 1/8, -1/24]]] + >>> res[0][-1] # FD weights for 0th derivative, using full x_list + [5/16, 15/16, -5/16, 1/16] + >>> res[1][-1] # FD weights for 1st derivative + [-23/24, 7/8, 1/8, -1/24] + >>> res[1][-2] # FD weights for 1st derivative, using x_list[:-1] + [-1, 1, 0, 0] + >>> res[1][-1][0] # FD weight for 1st deriv. for x_list[0] + -23/24 + >>> res[1][-1][1] # FD weight for 1st deriv. for x_list[1], etc. + 7/8 + + Each sublist contains the most accurate formula at the end. + Note, that in the above example ``res[1][1]`` is the same as ``res[1][2]``. + Since res[1][2] has an order of accuracy of + ``len(x_list[:3]) - order = 3 - 1 = 2``, the same is true for ``res[1][1]``! + + >>> res = finite_diff_weights(1, [S(0), S(1), -S(1), S(2), -S(2)], 0)[1] + >>> res + [[0, 0, 0, 0, 0], + [-1, 1, 0, 0, 0], + [0, 1/2, -1/2, 0, 0], + [-1/2, 1, -1/3, -1/6, 0], + [0, 2/3, -2/3, -1/12, 1/12]] + >>> res[0] # no approximation possible, using x_list[0] only + [0, 0, 0, 0, 0] + >>> res[1] # classic forward step approximation + [-1, 1, 0, 0, 0] + >>> res[2] # classic centered approximation + [0, 1/2, -1/2, 0, 0] + >>> res[3:] # higher order approximations + [[-1/2, 1, -1/3, -1/6, 0], [0, 2/3, -2/3, -1/12, 1/12]] + + Let us compare this to a differently defined ``x_list``. Pay attention to + ``foo[i][k]`` corresponding to the gridpoint defined by ``x_list[k]``. + + >>> foo = finite_diff_weights(1, [-S(2), -S(1), S(0), S(1), S(2)], 0)[1] + >>> foo + [[0, 0, 0, 0, 0], + [-1, 1, 0, 0, 0], + [1/2, -2, 3/2, 0, 0], + [1/6, -1, 1/2, 1/3, 0], + [1/12, -2/3, 0, 2/3, -1/12]] + >>> foo[1] # not the same and of lower accuracy as res[1]! + [-1, 1, 0, 0, 0] + >>> foo[2] # classic double backward step approximation + [1/2, -2, 3/2, 0, 0] + >>> foo[4] # the same as res[4] + [1/12, -2/3, 0, 2/3, -1/12] + + Note that, unless you plan on using approximations based on subsets of + ``x_list``, the order of gridpoints does not matter. + + The capability to generate weights at arbitrary points can be + used e.g. to minimize Runge's phenomenon by using Chebyshev nodes: + + >>> from sympy import cos, symbols, pi, simplify + >>> N, (h, x) = 4, symbols('h x') + >>> x_list = [x+h*cos(i*pi/(N)) for i in range(N,-1,-1)] # chebyshev nodes + >>> print(x_list) + [-h + x, -sqrt(2)*h/2 + x, x, sqrt(2)*h/2 + x, h + x] + >>> mycoeffs = finite_diff_weights(1, x_list, 0)[1][4] + >>> [simplify(c) for c in mycoeffs] #doctest: +NORMALIZE_WHITESPACE + [(h**3/2 + h**2*x - 3*h*x**2 - 4*x**3)/h**4, + (-sqrt(2)*h**3 - 4*h**2*x + 3*sqrt(2)*h*x**2 + 8*x**3)/h**4, + (6*h**2*x - 8*x**3)/h**4, + (sqrt(2)*h**3 - 4*h**2*x - 3*sqrt(2)*h*x**2 + 8*x**3)/h**4, + (-h**3/2 + h**2*x + 3*h*x**2 - 4*x**3)/h**4] + + Notes + ===== + + If weights for a finite difference approximation of 3rd order + derivative is wanted, weights for 0th, 1st and 2nd order are + calculated "for free", so are formulae using subsets of ``x_list``. + This is something one can take advantage of to save computational cost. + Be aware that one should define ``x_list`` from nearest to furthest from + ``x0``. If not, subsets of ``x_list`` will yield poorer approximations, + which might not grand an order of accuracy of ``len(x_list) - order``. + + See also + ======== + + sympy.calculus.finite_diff.apply_finite_diff + + References + ========== + + .. [1] Generation of Finite Difference Formulas on Arbitrarily Spaced + Grids, Bengt Fornberg; Mathematics of computation; 51; 184; + (1988); 699-706; doi:10.1090/S0025-5718-1988-0935077-0 + + """ + # The notation below closely corresponds to the one used in the paper. + order = S(order) + if not order.is_number: + raise ValueError("Cannot handle symbolic order.") + if order < 0: + raise ValueError("Negative derivative order illegal.") + if int(order) != order: + raise ValueError("Non-integer order illegal") + M = order + N = len(x_list) - 1 + delta = [[[0 for nu in range(N+1)] for n in range(N+1)] for + m in range(M+1)] + delta[0][0][0] = S.One + c1 = S.One + for n in range(1, N+1): + c2 = S.One + for nu in range(n): + c3 = x_list[n] - x_list[nu] + c2 = c2 * c3 + if n <= M: + delta[n][n-1][nu] = 0 + for m in range(min(n, M)+1): + delta[m][n][nu] = (x_list[n]-x0)*delta[m][n-1][nu] -\ + m*delta[m-1][n-1][nu] + delta[m][n][nu] /= c3 + for m in range(min(n, M)+1): + delta[m][n][n] = c1/c2*(m*delta[m-1][n-1][n-1] - + (x_list[n-1]-x0)*delta[m][n-1][n-1]) + c1 = c2 + return delta + + +def apply_finite_diff(order, x_list, y_list, x0=S.Zero): + """ + Calculates the finite difference approximation of + the derivative of requested order at ``x0`` from points + provided in ``x_list`` and ``y_list``. + + Parameters + ========== + + order: int + order of derivative to approximate. 0 corresponds to interpolation. + x_list: sequence + Sequence of (unique) values for the independent variable. + y_list: sequence + The function value at corresponding values for the independent + variable in x_list. + x0: Number or Symbol + At what value of the independent variable the derivative should be + evaluated. Defaults to 0. + + Returns + ======= + + sympy.core.add.Add or sympy.core.numbers.Number + The finite difference expression approximating the requested + derivative order at ``x0``. + + Examples + ======== + + >>> from sympy import apply_finite_diff + >>> cube = lambda arg: (1.0*arg)**3 + >>> xlist = range(-3,3+1) + >>> apply_finite_diff(2, xlist, map(cube, xlist), 2) - 12 # doctest: +SKIP + -3.55271367880050e-15 + + we see that the example above only contain rounding errors. + apply_finite_diff can also be used on more abstract objects: + + >>> from sympy import IndexedBase, Idx + >>> x, y = map(IndexedBase, 'xy') + >>> i = Idx('i') + >>> x_list, y_list = zip(*[(x[i+j], y[i+j]) for j in range(-1,2)]) + >>> apply_finite_diff(1, x_list, y_list, x[i]) + ((x[i + 1] - x[i])/(-x[i - 1] + x[i]) - 1)*y[i]/(x[i + 1] - x[i]) - + (x[i + 1] - x[i])*y[i - 1]/((x[i + 1] - x[i - 1])*(-x[i - 1] + x[i])) + + (-x[i - 1] + x[i])*y[i + 1]/((x[i + 1] - x[i - 1])*(x[i + 1] - x[i])) + + Notes + ===== + + Order = 0 corresponds to interpolation. + Only supply so many points you think makes sense + to around x0 when extracting the derivative (the function + need to be well behaved within that region). Also beware + of Runge's phenomenon. + + See also + ======== + + sympy.calculus.finite_diff.finite_diff_weights + + References + ========== + + Fortran 90 implementation with Python interface for numerics: finitediff_ + + .. _finitediff: https://github.com/bjodah/finitediff + + """ + + # In the original paper the following holds for the notation: + # M = order + # N = len(x_list) - 1 + + N = len(x_list) - 1 + if len(x_list) != len(y_list): + raise ValueError("x_list and y_list not equal in length.") + + delta = finite_diff_weights(order, x_list, x0) + + derivative = 0 + for nu in range(len(x_list)): + derivative += delta[order][N][nu]*y_list[nu] + return derivative + + +def _as_finite_diff(derivative, points=1, x0=None, wrt=None): + """ + Returns an approximation of a derivative of a function in + the form of a finite difference formula. The expression is a + weighted sum of the function at a number of discrete values of + (one of) the independent variable(s). + + Parameters + ========== + + derivative: a Derivative instance + + points: sequence or coefficient, optional + If sequence: discrete values (length >= order+1) of the + independent variable used for generating the finite + difference weights. + If it is a coefficient, it will be used as the step-size + for generating an equidistant sequence of length order+1 + centered around ``x0``. default: 1 (step-size 1) + + x0: number or Symbol, optional + the value of the independent variable (``wrt``) at which the + derivative is to be approximated. Default: same as ``wrt``. + + wrt: Symbol, optional + "with respect to" the variable for which the (partial) + derivative is to be approximated for. If not provided it + is required that the Derivative is ordinary. Default: ``None``. + + Examples + ======== + + >>> from sympy import symbols, Function, exp, sqrt, Symbol + >>> from sympy.calculus.finite_diff import _as_finite_diff + >>> x, h = symbols('x h') + >>> f = Function('f') + >>> _as_finite_diff(f(x).diff(x)) + -f(x - 1/2) + f(x + 1/2) + + The default step size and number of points are 1 and ``order + 1`` + respectively. We can change the step size by passing a symbol + as a parameter: + + >>> _as_finite_diff(f(x).diff(x), h) + -f(-h/2 + x)/h + f(h/2 + x)/h + + We can also specify the discretized values to be used in a sequence: + + >>> _as_finite_diff(f(x).diff(x), [x, x+h, x+2*h]) + -3*f(x)/(2*h) + 2*f(h + x)/h - f(2*h + x)/(2*h) + + The algorithm is not restricted to use equidistant spacing, nor + do we need to make the approximation around ``x0``, but we can get + an expression estimating the derivative at an offset: + + >>> e, sq2 = exp(1), sqrt(2) + >>> xl = [x-h, x+h, x+e*h] + >>> _as_finite_diff(f(x).diff(x, 1), xl, x+h*sq2) + 2*h*((h + sqrt(2)*h)/(2*h) - (-sqrt(2)*h + h)/(2*h))*f(E*h + x)/((-h + E*h)*(h + E*h)) + + (-(-sqrt(2)*h + h)/(2*h) - (-sqrt(2)*h + E*h)/(2*h))*f(-h + x)/(h + E*h) + + (-(h + sqrt(2)*h)/(2*h) + (-sqrt(2)*h + E*h)/(2*h))*f(h + x)/(-h + E*h) + + Partial derivatives are also supported: + + >>> y = Symbol('y') + >>> d2fdxdy=f(x,y).diff(x,y) + >>> _as_finite_diff(d2fdxdy, wrt=x) + -Derivative(f(x - 1/2, y), y) + Derivative(f(x + 1/2, y), y) + + See also + ======== + + sympy.calculus.finite_diff.apply_finite_diff + sympy.calculus.finite_diff.finite_diff_weights + + """ + if derivative.is_Derivative: + pass + elif derivative.is_Atom: + return derivative + else: + return derivative.fromiter( + [_as_finite_diff(ar, points, x0, wrt) for ar + in derivative.args], **derivative.assumptions0) + + if wrt is None: + old = None + for v in derivative.variables: + if old is v: + continue + derivative = _as_finite_diff(derivative, points, x0, v) + old = v + return derivative + + order = derivative.variables.count(wrt) + + if x0 is None: + x0 = wrt + + if not iterable(points): + if getattr(points, 'is_Function', False) and wrt in points.args: + points = points.subs(wrt, x0) + # points is simply the step-size, let's make it a + # equidistant sequence centered around x0 + if order % 2 == 0: + # even order => odd number of points, grid point included + points = [x0 + points*i for i + in range(-order//2, order//2 + 1)] + else: + # odd order => even number of points, half-way wrt grid point + points = [x0 + points*S(i)/2 for i + in range(-order, order + 1, 2)] + others = [wrt, 0] + for v in set(derivative.variables): + if v == wrt: + continue + others += [v, derivative.variables.count(v)] + if len(points) < order+1: + raise ValueError("Too few points for order %d" % order) + return apply_finite_diff(order, points, [ + Derivative(derivative.expr.subs({wrt: x}), *others) for + x in points], x0) + + +def differentiate_finite(expr, *symbols, + points=1, x0=None, wrt=None, evaluate=False): + r""" Differentiate expr and replace Derivatives with finite differences. + + Parameters + ========== + + expr : expression + \*symbols : differentiate with respect to symbols + points: sequence, coefficient or undefined function, optional + see ``Derivative.as_finite_difference`` + x0: number or Symbol, optional + see ``Derivative.as_finite_difference`` + wrt: Symbol, optional + see ``Derivative.as_finite_difference`` + + Examples + ======== + + >>> from sympy import sin, Function, differentiate_finite + >>> from sympy.abc import x, y, h + >>> f, g = Function('f'), Function('g') + >>> differentiate_finite(f(x)*g(x), x, points=[x-h, x+h]) + -f(-h + x)*g(-h + x)/(2*h) + f(h + x)*g(h + x)/(2*h) + + ``differentiate_finite`` works on any expression, including the expressions + with embedded derivatives: + + >>> differentiate_finite(f(x) + sin(x), x, 2) + -2*f(x) + f(x - 1) + f(x + 1) - 2*sin(x) + sin(x - 1) + sin(x + 1) + >>> differentiate_finite(f(x, y), x, y) + f(x - 1/2, y - 1/2) - f(x - 1/2, y + 1/2) - f(x + 1/2, y - 1/2) + f(x + 1/2, y + 1/2) + >>> differentiate_finite(f(x)*g(x).diff(x), x) + (-g(x) + g(x + 1))*f(x + 1/2) - (g(x) - g(x - 1))*f(x - 1/2) + + To make finite difference with non-constant discretization step use + undefined functions: + + >>> dx = Function('dx') + >>> differentiate_finite(f(x)*g(x).diff(x), points=dx(x)) + -(-g(x - dx(x)/2 - dx(x - dx(x)/2)/2)/dx(x - dx(x)/2) + + g(x - dx(x)/2 + dx(x - dx(x)/2)/2)/dx(x - dx(x)/2))*f(x - dx(x)/2)/dx(x) + + (-g(x + dx(x)/2 - dx(x + dx(x)/2)/2)/dx(x + dx(x)/2) + + g(x + dx(x)/2 + dx(x + dx(x)/2)/2)/dx(x + dx(x)/2))*f(x + dx(x)/2)/dx(x) + + """ + if any(term.is_Derivative for term in list(preorder_traversal(expr))): + evaluate = False + + Dexpr = expr.diff(*symbols, evaluate=evaluate) + if evaluate: + sympy_deprecation_warning(""" + The evaluate flag to differentiate_finite() is deprecated. + + evaluate=True expands the intermediate derivatives before computing + differences, but this usually not what you want, as it does not + satisfy the product rule. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-differentiate_finite-evaluate", + ) + return Dexpr.replace( + lambda arg: arg.is_Derivative, + lambda arg: arg.as_finite_difference(points=points, x0=x0, wrt=wrt)) + else: + DFexpr = Dexpr.as_finite_difference(points=points, x0=x0, wrt=wrt) + return DFexpr.replace( + lambda arg: isinstance(arg, Subs), + lambda arg: arg.expr.as_finite_difference( + points=points, x0=arg.point[0], wrt=arg.variables[0])) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/singularities.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/singularities.py new file mode 100644 index 0000000000000000000000000000000000000000..5adafc59efaf0bff44707f6b5e3f074be6bc1f32 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/singularities.py @@ -0,0 +1,406 @@ +""" +Singularities +============= + +This module implements algorithms for finding singularities for a function +and identifying types of functions. + +The differential calculus methods in this module include methods to identify +the following function types in the given ``Interval``: +- Increasing +- Strictly Increasing +- Decreasing +- Strictly Decreasing +- Monotonic + +""" + +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.trigonometric import sec, csc, cot, tan, cos +from sympy.functions.elementary.hyperbolic import ( + sech, csch, coth, tanh, cosh, asech, acsch, atanh, acoth) +from sympy.utilities.misc import filldedent + + +def singularities(expression, symbol, domain=None): + """ + Find singularities of a given function. + + Parameters + ========== + + expression : Expr + The target function in which singularities need to be found. + symbol : Symbol + The symbol over the values of which the singularity in + expression in being searched for. + + Returns + ======= + + Set + A set of values for ``symbol`` for which ``expression`` has a + singularity. An ``EmptySet`` is returned if ``expression`` has no + singularities for any given value of ``Symbol``. + + Raises + ====== + + NotImplementedError + Methods for determining the singularities of this function have + not been developed. + + Notes + ===== + + This function does not find non-isolated singularities + nor does it find branch points of the expression. + + Currently supported functions are: + - univariate continuous (real or complex) functions + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Mathematical_singularity + + Examples + ======== + + >>> from sympy import singularities, Symbol, log + >>> x = Symbol('x', real=True) + >>> y = Symbol('y', real=False) + >>> singularities(x**2 + x + 1, x) + EmptySet + >>> singularities(1/(x + 1), x) + {-1} + >>> singularities(1/(y**2 + 1), y) + {-I, I} + >>> singularities(1/(y**3 + 1), y) + {-1, 1/2 - sqrt(3)*I/2, 1/2 + sqrt(3)*I/2} + >>> singularities(log(x), x) + {0} + + """ + from sympy.solvers.solveset import solveset + + if domain is None: + domain = S.Reals if symbol.is_real else S.Complexes + try: + sings = S.EmptySet + e = expression.rewrite([sec, csc, cot, tan], cos) + e = e.rewrite([sech, csch, coth, tanh], cosh) + for i in e.atoms(Pow): + if i.exp.is_infinite: + raise NotImplementedError + if i.exp.is_negative: + # XXX: exponent of varying sign not handled + sings += solveset(i.base, symbol, domain) + for i in expression.atoms(log, asech, acsch): + sings += solveset(i.args[0], symbol, domain) + for i in expression.atoms(atanh, acoth): + sings += solveset(i.args[0] - 1, symbol, domain) + sings += solveset(i.args[0] + 1, symbol, domain) + return sings + except NotImplementedError: + raise NotImplementedError(filldedent(''' + Methods for determining the singularities + of this function have not been developed.''')) + + +########################################################################### +# DIFFERENTIAL CALCULUS METHODS # +########################################################################### + + +def monotonicity_helper(expression, predicate, interval=S.Reals, symbol=None): + """ + Helper function for functions checking function monotonicity. + + Parameters + ========== + + expression : Expr + The target function which is being checked + predicate : function + The property being tested for. The function takes in an integer + and returns a boolean. The integer input is the derivative and + the boolean result should be true if the property is being held, + and false otherwise. + interval : Set, optional + The range of values in which we are testing, defaults to all reals. + symbol : Symbol, optional + The symbol present in expression which gets varied over the given range. + + It returns a boolean indicating whether the interval in which + the function's derivative satisfies given predicate is a superset + of the given interval. + + Returns + ======= + + Boolean + True if ``predicate`` is true for all the derivatives when ``symbol`` + is varied in ``range``, False otherwise. + + """ + from sympy.solvers.solveset import solveset + + expression = sympify(expression) + free = expression.free_symbols + + if symbol is None: + if len(free) > 1: + raise NotImplementedError( + 'The function has not yet been implemented' + ' for all multivariate expressions.' + ) + + variable = symbol or (free.pop() if free else Symbol('x')) + derivative = expression.diff(variable) + predicate_interval = solveset(predicate(derivative), variable, S.Reals) + return interval.is_subset(predicate_interval) + + +def is_increasing(expression, interval=S.Reals, symbol=None): + """ + Return whether the function is increasing in the given interval. + + Parameters + ========== + + expression : Expr + The target function which is being checked. + interval : Set, optional + The range of values in which we are testing (defaults to set of + all real numbers). + symbol : Symbol, optional + The symbol present in expression which gets varied over the given range. + + Returns + ======= + + Boolean + True if ``expression`` is increasing (either strictly increasing or + constant) in the given ``interval``, False otherwise. + + Examples + ======== + + >>> from sympy import is_increasing + >>> from sympy.abc import x, y + >>> from sympy import S, Interval, oo + >>> is_increasing(x**3 - 3*x**2 + 4*x, S.Reals) + True + >>> is_increasing(-x**2, Interval(-oo, 0)) + True + >>> is_increasing(-x**2, Interval(0, oo)) + False + >>> is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) + False + >>> is_increasing(x**2 + y, Interval(1, 2), x) + True + + """ + return monotonicity_helper(expression, lambda x: x >= 0, interval, symbol) + + +def is_strictly_increasing(expression, interval=S.Reals, symbol=None): + """ + Return whether the function is strictly increasing in the given interval. + + Parameters + ========== + + expression : Expr + The target function which is being checked. + interval : Set, optional + The range of values in which we are testing (defaults to set of + all real numbers). + symbol : Symbol, optional + The symbol present in expression which gets varied over the given range. + + Returns + ======= + + Boolean + True if ``expression`` is strictly increasing in the given ``interval``, + False otherwise. + + Examples + ======== + + >>> from sympy import is_strictly_increasing + >>> from sympy.abc import x, y + >>> from sympy import Interval, oo + >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Ropen(-oo, -2)) + True + >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Lopen(3, oo)) + True + >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.open(-2, 3)) + False + >>> is_strictly_increasing(-x**2, Interval(0, oo)) + False + >>> is_strictly_increasing(-x**2 + y, Interval(-oo, 0), x) + False + + """ + return monotonicity_helper(expression, lambda x: x > 0, interval, symbol) + + +def is_decreasing(expression, interval=S.Reals, symbol=None): + """ + Return whether the function is decreasing in the given interval. + + Parameters + ========== + + expression : Expr + The target function which is being checked. + interval : Set, optional + The range of values in which we are testing (defaults to set of + all real numbers). + symbol : Symbol, optional + The symbol present in expression which gets varied over the given range. + + Returns + ======= + + Boolean + True if ``expression`` is decreasing (either strictly decreasing or + constant) in the given ``interval``, False otherwise. + + Examples + ======== + + >>> from sympy import is_decreasing + >>> from sympy.abc import x, y + >>> from sympy import S, Interval, oo + >>> is_decreasing(1/(x**2 - 3*x), Interval.open(S(3)/2, 3)) + True + >>> is_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3)) + True + >>> is_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo)) + True + >>> is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2)) + False + >>> is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, 1.5)) + False + >>> is_decreasing(-x**2, Interval(-oo, 0)) + False + >>> is_decreasing(-x**2 + y, Interval(-oo, 0), x) + False + + """ + return monotonicity_helper(expression, lambda x: x <= 0, interval, symbol) + + +def is_strictly_decreasing(expression, interval=S.Reals, symbol=None): + """ + Return whether the function is strictly decreasing in the given interval. + + Parameters + ========== + + expression : Expr + The target function which is being checked. + interval : Set, optional + The range of values in which we are testing (defaults to set of + all real numbers). + symbol : Symbol, optional + The symbol present in expression which gets varied over the given range. + + Returns + ======= + + Boolean + True if ``expression`` is strictly decreasing in the given ``interval``, + False otherwise. + + Examples + ======== + + >>> from sympy import is_strictly_decreasing + >>> from sympy.abc import x, y + >>> from sympy import S, Interval, oo + >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo)) + True + >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2)) + False + >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, 1.5)) + False + >>> is_strictly_decreasing(-x**2, Interval(-oo, 0)) + False + >>> is_strictly_decreasing(-x**2 + y, Interval(-oo, 0), x) + False + + """ + return monotonicity_helper(expression, lambda x: x < 0, interval, symbol) + + +def is_monotonic(expression, interval=S.Reals, symbol=None): + """ + Return whether the function is monotonic in the given interval. + + Parameters + ========== + + expression : Expr + The target function which is being checked. + interval : Set, optional + The range of values in which we are testing (defaults to set of + all real numbers). + symbol : Symbol, optional + The symbol present in expression which gets varied over the given range. + + Returns + ======= + + Boolean + True if ``expression`` is monotonic in the given ``interval``, + False otherwise. + + Raises + ====== + + NotImplementedError + Monotonicity check has not been implemented for the queried function. + + Examples + ======== + + >>> from sympy import is_monotonic + >>> from sympy.abc import x, y + >>> from sympy import S, Interval, oo + >>> is_monotonic(1/(x**2 - 3*x), Interval.open(S(3)/2, 3)) + True + >>> is_monotonic(1/(x**2 - 3*x), Interval.open(1.5, 3)) + True + >>> is_monotonic(1/(x**2 - 3*x), Interval.Lopen(3, oo)) + True + >>> is_monotonic(x**3 - 3*x**2 + 4*x, S.Reals) + True + >>> is_monotonic(-x**2, S.Reals) + False + >>> is_monotonic(x**2 + y + 1, Interval(1, 2), x) + True + + """ + from sympy.solvers.solveset import solveset + + expression = sympify(expression) + + free = expression.free_symbols + if symbol is None and len(free) > 1: + raise NotImplementedError( + 'is_monotonic has not yet been implemented' + ' for all multivariate expressions.' + ) + + variable = symbol or (free.pop() if free else Symbol('x')) + turning_points = solveset(expression.diff(variable), variable, interval) + return interval.intersection(turning_points) is S.EmptySet diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/util.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/util.py new file mode 100644 index 0000000000000000000000000000000000000000..dac316358873de2418dd8ab56445823f07a37b1b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/calculus/util.py @@ -0,0 +1,895 @@ +from .accumulationbounds import AccumBounds, AccumulationBounds # noqa: F401 +from .singularities import singularities +from sympy.core import Pow, S +from sympy.core.function import diff, expand_mul, Function +from sympy.core.kind import NumberKind +from sympy.core.mod import Mod +from sympy.core.numbers import equal_valued +from sympy.core.relational import Relational +from sympy.core.symbol import Symbol, Dummy +from sympy.core.sympify import _sympify +from sympy.functions.elementary.complexes import Abs, im, re +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.integers import frac +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import ( + TrigonometricFunction, sin, cos, tan, cot, csc, sec, + asin, acos, acot, atan, asec, acsc) +from sympy.functions.elementary.hyperbolic import (sinh, cosh, tanh, coth, + sech, csch, asinh, acosh, atanh, acoth, asech, acsch) +from sympy.polys.polytools import degree, lcm_list +from sympy.sets.sets import (Interval, Intersection, FiniteSet, Union, + Complement) +from sympy.sets.fancysets import ImageSet +from sympy.sets.conditionset import ConditionSet +from sympy.utilities import filldedent +from sympy.utilities.iterables import iterable +from sympy.matrices.dense import hessian + + +def continuous_domain(f, symbol, domain): + """ + Returns the domain on which the function expression f is continuous. + + This function is limited by the ability to determine the various + singularities and discontinuities of the given function. + The result is either given as a union of intervals or constructed using + other set operations. + + Parameters + ========== + + f : :py:class:`~.Expr` + The concerned function. + symbol : :py:class:`~.Symbol` + The variable for which the intervals are to be determined. + domain : :py:class:`~.Interval` + The domain over which the continuity of the symbol has to be checked. + + Examples + ======== + + >>> from sympy import Interval, Symbol, S, tan, log, pi, sqrt + >>> from sympy.calculus.util import continuous_domain + >>> x = Symbol('x') + >>> continuous_domain(1/x, x, S.Reals) + Union(Interval.open(-oo, 0), Interval.open(0, oo)) + >>> continuous_domain(tan(x), x, Interval(0, pi)) + Union(Interval.Ropen(0, pi/2), Interval.Lopen(pi/2, pi)) + >>> continuous_domain(sqrt(x - 2), x, Interval(-5, 5)) + Interval(2, 5) + >>> continuous_domain(log(2*x - 1), x, S.Reals) + Interval.open(1/2, oo) + + Returns + ======= + + :py:class:`~.Interval` + Union of all intervals where the function is continuous. + + Raises + ====== + + NotImplementedError + If the method to determine continuity of such a function + has not yet been developed. + + """ + from sympy.solvers.inequalities import solve_univariate_inequality + + if not domain.is_subset(S.Reals): + raise NotImplementedError(filldedent(''' + Domain must be a subset of S.Reals. + ''')) + implemented = [Pow, exp, log, Abs, frac, + sin, cos, tan, cot, sec, csc, + asin, acos, atan, acot, asec, acsc, + sinh, cosh, tanh, coth, sech, csch, + asinh, acosh, atanh, acoth, asech, acsch] + used = [fct.func for fct in f.atoms(Function) if fct.has(symbol)] + if any(func not in implemented for func in used): + raise NotImplementedError(filldedent(''' + Unable to determine the domain of the given function. + ''')) + + x = Symbol('x') + constraints = { + log: (x > 0,), + asin: (x >= -1, x <= 1), + acos: (x >= -1, x <= 1), + acosh: (x >= 1,), + atanh: (x > -1, x < 1), + asech: (x > 0, x <= 1) + } + constraints_union = { + asec: (x <= -1, x >= 1), + acsc: (x <= -1, x >= 1), + acoth: (x < -1, x > 1) + } + + cont_domain = domain + for atom in f.atoms(Pow): + den = atom.exp.as_numer_denom()[1] + if atom.exp.is_rational and den.is_odd: + pass # 0**negative handled by singularities() + else: + constraint = solve_univariate_inequality(atom.base >= 0, + symbol).as_set() + cont_domain = Intersection(constraint, cont_domain) + + for atom in f.atoms(Function): + if atom.func in constraints: + for c in constraints[atom.func]: + constraint_relational = c.subs(x, atom.args[0]) + constraint_set = solve_univariate_inequality( + constraint_relational, symbol).as_set() + cont_domain = Intersection(constraint_set, cont_domain) + elif atom.func in constraints_union: + constraint_set = S.EmptySet + for c in constraints_union[atom.func]: + constraint_relational = c.subs(x, atom.args[0]) + constraint_set += solve_univariate_inequality( + constraint_relational, symbol).as_set() + cont_domain = Intersection(constraint_set, cont_domain) + # XXX: the discontinuities below could be factored out in + # a new "discontinuities()". + elif atom.func == acot: + from sympy.solvers.solveset import solveset_real + # Sympy's acot() has a step discontinuity at 0. Since it's + # neither an essential singularity nor a pole, singularities() + # will not report it. But it's still relevant for determining + # the continuity of the function f. + cont_domain -= solveset_real(atom.args[0], symbol) + # Note that the above may introduce spurious discontinuities, e.g. + # for abs(acot(x)) at 0. + elif atom.func == frac: + from sympy.solvers.solveset import solveset_real + r = function_range(atom.args[0], symbol, domain) + r = Intersection(r, S.Integers) + if r.is_finite_set: + discont = S.EmptySet + for n in r: + discont += solveset_real(atom.args[0]-n, symbol) + else: + discont = ConditionSet( + symbol, S.Integers.contains(atom.args[0]), cont_domain) + cont_domain -= discont + + return cont_domain - singularities(f, symbol, domain) + + +def function_range(f, symbol, domain): + """ + Finds the range of a function in a given domain. + This method is limited by the ability to determine the singularities and + determine limits. + + Parameters + ========== + + f : :py:class:`~.Expr` + The concerned function. + symbol : :py:class:`~.Symbol` + The variable for which the range of function is to be determined. + domain : :py:class:`~.Interval` + The domain under which the range of the function has to be found. + + Examples + ======== + + >>> from sympy import Interval, Symbol, S, exp, log, pi, sqrt, sin, tan + >>> from sympy.calculus.util import function_range + >>> x = Symbol('x') + >>> function_range(sin(x), x, Interval(0, 2*pi)) + Interval(-1, 1) + >>> function_range(tan(x), x, Interval(-pi/2, pi/2)) + Interval(-oo, oo) + >>> function_range(1/x, x, S.Reals) + Union(Interval.open(-oo, 0), Interval.open(0, oo)) + >>> function_range(exp(x), x, S.Reals) + Interval.open(0, oo) + >>> function_range(log(x), x, S.Reals) + Interval(-oo, oo) + >>> function_range(sqrt(x), x, Interval(-5, 9)) + Interval(0, 3) + + Returns + ======= + + :py:class:`~.Interval` + Union of all ranges for all intervals under domain where function is + continuous. + + Raises + ====== + + NotImplementedError + If any of the intervals, in the given domain, for which function + is continuous are not finite or real, + OR if the critical points of the function on the domain cannot be found. + """ + + if domain is S.EmptySet: + return S.EmptySet + + period = periodicity(f, symbol) + if period == S.Zero: + # the expression is constant wrt symbol + return FiniteSet(f.expand()) + + from sympy.series.limits import limit + from sympy.solvers.solveset import solveset + + if period is not None: + if isinstance(domain, Interval): + if (domain.inf - domain.sup).is_infinite: + domain = Interval(0, period) + elif isinstance(domain, Union): + for sub_dom in domain.args: + if isinstance(sub_dom, Interval) and \ + ((sub_dom.inf - sub_dom.sup).is_infinite): + domain = Interval(0, period) + + intervals = continuous_domain(f, symbol, domain) + range_int = S.EmptySet + if isinstance(intervals,(Interval, FiniteSet)): + interval_iter = (intervals,) + elif isinstance(intervals, Union): + interval_iter = intervals.args + else: + raise NotImplementedError("Unable to find range for the given domain.") + + for interval in interval_iter: + if isinstance(interval, FiniteSet): + for singleton in interval: + if singleton in domain: + range_int += FiniteSet(f.subs(symbol, singleton)) + elif isinstance(interval, Interval): + vals = S.EmptySet + critical_values = S.EmptySet + bounds = ((interval.left_open, interval.inf, '+'), + (interval.right_open, interval.sup, '-')) + + for is_open, limit_point, direction in bounds: + if is_open: + critical_values += FiniteSet(limit(f, symbol, limit_point, direction)) + vals += critical_values + else: + vals += FiniteSet(f.subs(symbol, limit_point)) + + critical_points = solveset(f.diff(symbol), symbol, interval) + + if not iterable(critical_points): + raise NotImplementedError( + 'Unable to find critical points for {}'.format(f)) + if isinstance(critical_points, ImageSet): + raise NotImplementedError( + 'Infinite number of critical points for {}'.format(f)) + + for critical_point in critical_points: + vals += FiniteSet(f.subs(symbol, critical_point)) + + left_open, right_open = False, False + + if critical_values is not S.EmptySet: + if critical_values.inf == vals.inf: + left_open = True + + if critical_values.sup == vals.sup: + right_open = True + + range_int += Interval(vals.inf, vals.sup, left_open, right_open) + else: + raise NotImplementedError("Unable to find range for the given domain.") + + return range_int + + +def not_empty_in(finset_intersection, *syms): + """ + Finds the domain of the functions in ``finset_intersection`` in which the + ``finite_set`` is not-empty. + + Parameters + ========== + + finset_intersection : Intersection of FiniteSet + The unevaluated intersection of FiniteSet containing + real-valued functions with Union of Sets + syms : Tuple of symbols + Symbol for which domain is to be found + + Raises + ====== + + NotImplementedError + The algorithms to find the non-emptiness of the given FiniteSet are + not yet implemented. + ValueError + The input is not valid. + RuntimeError + It is a bug, please report it to the github issue tracker + (https://github.com/sympy/sympy/issues). + + Examples + ======== + + >>> from sympy import FiniteSet, Interval, not_empty_in, oo + >>> from sympy.abc import x + >>> not_empty_in(FiniteSet(x/2).intersect(Interval(0, 1)), x) + Interval(0, 2) + >>> not_empty_in(FiniteSet(x, x**2).intersect(Interval(1, 2)), x) + Union(Interval(1, 2), Interval(-sqrt(2), -1)) + >>> not_empty_in(FiniteSet(x**2/(x + 2)).intersect(Interval(1, oo)), x) + Union(Interval.Lopen(-2, -1), Interval(2, oo)) + """ + + # TODO: handle piecewise defined functions + # TODO: handle transcendental functions + # TODO: handle multivariate functions + if len(syms) == 0: + raise ValueError("One or more symbols must be given in syms.") + + if finset_intersection is S.EmptySet: + return S.EmptySet + + if isinstance(finset_intersection, Union): + elm_in_sets = finset_intersection.args[0] + return Union(not_empty_in(finset_intersection.args[1], *syms), + elm_in_sets) + + if isinstance(finset_intersection, FiniteSet): + finite_set = finset_intersection + _sets = S.Reals + else: + finite_set = finset_intersection.args[1] + _sets = finset_intersection.args[0] + + if not isinstance(finite_set, FiniteSet): + raise ValueError('A FiniteSet must be given, not %s: %s' % + (type(finite_set), finite_set)) + + if len(syms) == 1: + symb = syms[0] + else: + raise NotImplementedError('more than one variables %s not handled' % + (syms,)) + + def elm_domain(expr, intrvl): + """ Finds the domain of an expression in any given interval """ + from sympy.solvers.solveset import solveset + + _start = intrvl.start + _end = intrvl.end + _singularities = solveset(expr.as_numer_denom()[1], symb, + domain=S.Reals) + + if intrvl.right_open: + if _end is S.Infinity: + _domain1 = S.Reals + else: + _domain1 = solveset(expr < _end, symb, domain=S.Reals) + else: + _domain1 = solveset(expr <= _end, symb, domain=S.Reals) + + if intrvl.left_open: + if _start is S.NegativeInfinity: + _domain2 = S.Reals + else: + _domain2 = solveset(expr > _start, symb, domain=S.Reals) + else: + _domain2 = solveset(expr >= _start, symb, domain=S.Reals) + + # domain in the interval + expr_with_sing = Intersection(_domain1, _domain2) + expr_domain = Complement(expr_with_sing, _singularities) + return expr_domain + + if isinstance(_sets, Interval): + return Union(*[elm_domain(element, _sets) for element in finite_set]) + + if isinstance(_sets, Union): + _domain = S.EmptySet + for intrvl in _sets.args: + _domain_element = Union(*[elm_domain(element, intrvl) + for element in finite_set]) + _domain = Union(_domain, _domain_element) + return _domain + + +def periodicity(f, symbol, check=False): + """ + Tests the given function for periodicity in the given symbol. + + Parameters + ========== + + f : :py:class:`~.Expr` + The concerned function. + symbol : :py:class:`~.Symbol` + The variable for which the period is to be determined. + check : bool, optional + The flag to verify whether the value being returned is a period or not. + + Returns + ======= + + period + The period of the function is returned. + ``None`` is returned when the function is aperiodic or has a complex period. + The value of $0$ is returned as the period of a constant function. + + Raises + ====== + + NotImplementedError + The value of the period computed cannot be verified. + + + Notes + ===== + + Currently, we do not support functions with a complex period. + The period of functions having complex periodic values such + as ``exp``, ``sinh`` is evaluated to ``None``. + + The value returned might not be the "fundamental" period of the given + function i.e. it may not be the smallest periodic value of the function. + + The verification of the period through the ``check`` flag is not reliable + due to internal simplification of the given expression. Hence, it is set + to ``False`` by default. + + Examples + ======== + >>> from sympy import periodicity, Symbol, sin, cos, tan, exp + >>> x = Symbol('x') + >>> f = sin(x) + sin(2*x) + sin(3*x) + >>> periodicity(f, x) + 2*pi + >>> periodicity(sin(x)*cos(x), x) + pi + >>> periodicity(exp(tan(2*x) - 1), x) + pi/2 + >>> periodicity(sin(4*x)**cos(2*x), x) + pi + >>> periodicity(exp(x), x) + """ + if symbol.kind is not NumberKind: + raise NotImplementedError("Cannot use symbol of kind %s" % symbol.kind) + temp = Dummy('x', real=True) + f = f.subs(symbol, temp) + symbol = temp + + def _check(orig_f, period): + '''Return the checked period or raise an error.''' + new_f = orig_f.subs(symbol, symbol + period) + if new_f.equals(orig_f): + return period + else: + raise NotImplementedError(filldedent(''' + The period of the given function cannot be verified. + When `%s` was replaced with `%s + %s` in `%s`, the result + was `%s` which was not recognized as being the same as + the original function. + So either the period was wrong or the two forms were + not recognized as being equal. + Set check=False to obtain the value.''' % + (symbol, symbol, period, orig_f, new_f))) + + orig_f = f + period = None + + if isinstance(f, Relational): + f = f.lhs - f.rhs + + f = f.simplify() + + if symbol not in f.free_symbols: + return S.Zero + + if isinstance(f, TrigonometricFunction): + try: + period = f.period(symbol) + except NotImplementedError: + pass + + if isinstance(f, Abs): + arg = f.args[0] + if isinstance(arg, (sec, csc, cos)): + # all but tan and cot might have a + # a period that is half as large + # so recast as sin + arg = sin(arg.args[0]) + period = periodicity(arg, symbol) + if period is not None and isinstance(arg, sin): + # the argument of Abs was a trigonometric other than + # cot or tan; test to see if the half-period + # is valid. Abs(arg) has behaviour equivalent to + # orig_f, so use that for test: + orig_f = Abs(arg) + try: + return _check(orig_f, period/2) + except NotImplementedError as err: + if check: + raise NotImplementedError(err) + # else let new orig_f and period be + # checked below + + if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1): + f = Pow(S.Exp1, expand_mul(f.exp)) + if im(f) != 0: + period_real = periodicity(re(f), symbol) + period_imag = periodicity(im(f), symbol) + if period_real is not None and period_imag is not None: + period = lcim([period_real, period_imag]) + + if f.is_Pow and f.base != S.Exp1: + base, expo = f.args + base_has_sym = base.has(symbol) + expo_has_sym = expo.has(symbol) + + if base_has_sym and not expo_has_sym: + period = periodicity(base, symbol) + + elif expo_has_sym and not base_has_sym: + period = periodicity(expo, symbol) + + else: + period = _periodicity(f.args, symbol) + + elif f.is_Mul: + coeff, g = f.as_independent(symbol, as_Add=False) + if isinstance(g, TrigonometricFunction) or not equal_valued(coeff, 1): + period = periodicity(g, symbol) + else: + period = _periodicity(g.args, symbol) + + elif f.is_Add: + k, g = f.as_independent(symbol) + if k is not S.Zero: + return periodicity(g, symbol) + + period = _periodicity(g.args, symbol) + + elif isinstance(f, Mod): + a, n = f.args + + if a == symbol: + period = n + elif isinstance(a, TrigonometricFunction): + period = periodicity(a, symbol) + #check if 'f' is linear in 'symbol' + elif (a.is_polynomial(symbol) and degree(a, symbol) == 1 and + symbol not in n.free_symbols): + period = Abs(n / a.diff(symbol)) + + elif isinstance(f, Piecewise): + pass # not handling Piecewise yet as the return type is not favorable + + elif period is None: + from sympy.solvers.decompogen import compogen, decompogen + g_s = decompogen(f, symbol) + num_of_gs = len(g_s) + if num_of_gs > 1: + for index, g in enumerate(reversed(g_s)): + start_index = num_of_gs - 1 - index + g = compogen(g_s[start_index:], symbol) + if g not in (orig_f, f): # Fix for issue 12620 + period = periodicity(g, symbol) + if period is not None: + break + + if period is not None: + if check: + return _check(orig_f, period) + return period + + return None + + +def _periodicity(args, symbol): + """ + Helper for `periodicity` to find the period of a list of simpler + functions. + It uses the `lcim` method to find the least common period of + all the functions. + + Parameters + ========== + + args : Tuple of :py:class:`~.Symbol` + All the symbols present in a function. + + symbol : :py:class:`~.Symbol` + The symbol over which the function is to be evaluated. + + Returns + ======= + + period + The least common period of the function for all the symbols + of the function. + ``None`` if for at least one of the symbols the function is aperiodic. + + """ + periods = [] + for f in args: + period = periodicity(f, symbol) + if period is None: + return None + + if period is not S.Zero: + periods.append(period) + + if len(periods) > 1: + return lcim(periods) + + if periods: + return periods[0] + + +def lcim(numbers): + """Returns the least common integral multiple of a list of numbers. + + The numbers can be rational or irrational or a mixture of both. + `None` is returned for incommensurable numbers. + + Parameters + ========== + + numbers : list + Numbers (rational and/or irrational) for which lcim is to be found. + + Returns + ======= + + number + lcim if it exists, otherwise ``None`` for incommensurable numbers. + + Examples + ======== + + >>> from sympy.calculus.util import lcim + >>> from sympy import S, pi + >>> lcim([S(1)/2, S(3)/4, S(5)/6]) + 15/2 + >>> lcim([2*pi, 3*pi, pi, pi/2]) + 6*pi + >>> lcim([S(1), 2*pi]) + """ + result = None + if all(num.is_irrational for num in numbers): + factorized_nums = [num.factor() for num in numbers] + factors_num = [num.as_coeff_Mul() for num in factorized_nums] + term = factors_num[0][1] + if all(factor == term for coeff, factor in factors_num): + common_term = term + coeffs = [coeff for coeff, factor in factors_num] + result = lcm_list(coeffs) * common_term + + elif all(num.is_rational for num in numbers): + result = lcm_list(numbers) + + else: + pass + + return result + +def is_convex(f, *syms, domain=S.Reals): + r"""Determines the convexity of the function passed in the argument. + + Parameters + ========== + + f : :py:class:`~.Expr` + The concerned function. + syms : Tuple of :py:class:`~.Symbol` + The variables with respect to which the convexity is to be determined. + domain : :py:class:`~.Interval`, optional + The domain over which the convexity of the function has to be checked. + If unspecified, S.Reals will be the default domain. + + Returns + ======= + + bool + The method returns ``True`` if the function is convex otherwise it + returns ``False``. + + Raises + ====== + + NotImplementedError + The check for the convexity of multivariate functions is not implemented yet. + + Notes + ===== + + To determine concavity of a function pass `-f` as the concerned function. + To determine logarithmic convexity of a function pass `\log(f)` as + concerned function. + To determine logarithmic concavity of a function pass `-\log(f)` as + concerned function. + + Currently, convexity check of multivariate functions is not handled. + + Examples + ======== + + >>> from sympy import is_convex, symbols, exp, oo, Interval + >>> x = symbols('x') + >>> is_convex(exp(x), x) + True + >>> is_convex(x**3, x, domain = Interval(-1, oo)) + False + >>> is_convex(1/x**2, x, domain=Interval.open(0, oo)) + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Convex_function + .. [2] http://www.ifp.illinois.edu/~angelia/L3_convfunc.pdf + .. [3] https://en.wikipedia.org/wiki/Logarithmically_convex_function + .. [4] https://en.wikipedia.org/wiki/Logarithmically_concave_function + .. [5] https://en.wikipedia.org/wiki/Concave_function + + """ + if len(syms) > 1 : + return hessian(f, syms).is_positive_semidefinite + from sympy.solvers.inequalities import solve_univariate_inequality + f = _sympify(f) + var = syms[0] + if any(s in domain for s in singularities(f, var)): + return False + condition = f.diff(var, 2) < 0 + if solve_univariate_inequality(condition, var, False, domain): + return False + return True + + +def stationary_points(f, symbol, domain=S.Reals): + """ + Returns the stationary points of a function (where derivative of the + function is 0) in the given domain. + + Parameters + ========== + + f : :py:class:`~.Expr` + The concerned function. + symbol : :py:class:`~.Symbol` + The variable for which the stationary points are to be determined. + domain : :py:class:`~.Interval` + The domain over which the stationary points have to be checked. + If unspecified, ``S.Reals`` will be the default domain. + + Returns + ======= + + Set + A set of stationary points for the function. If there are no + stationary point, an :py:class:`~.EmptySet` is returned. + + Examples + ======== + + >>> from sympy import Interval, Symbol, S, sin, pi, pprint, stationary_points + >>> x = Symbol('x') + + >>> stationary_points(1/x, x, S.Reals) + EmptySet + + >>> pprint(stationary_points(sin(x), x), use_unicode=False) + pi 3*pi + {2*n*pi + -- | n in Integers} U {2*n*pi + ---- | n in Integers} + 2 2 + + >>> stationary_points(sin(x),x, Interval(0, 4*pi)) + {pi/2, 3*pi/2, 5*pi/2, 7*pi/2} + + """ + from sympy.solvers.solveset import solveset + + if domain is S.EmptySet: + return S.EmptySet + + domain = continuous_domain(f, symbol, domain) + set = solveset(diff(f, symbol), symbol, domain) + + return set + + +def maximum(f, symbol, domain=S.Reals): + """ + Returns the maximum value of a function in the given domain. + + Parameters + ========== + + f : :py:class:`~.Expr` + The concerned function. + symbol : :py:class:`~.Symbol` + The variable for maximum value needs to be determined. + domain : :py:class:`~.Interval` + The domain over which the maximum have to be checked. + If unspecified, then the global maximum is returned. + + Returns + ======= + + number + Maximum value of the function in given domain. + + Examples + ======== + + >>> from sympy import Interval, Symbol, S, sin, cos, pi, maximum + >>> x = Symbol('x') + + >>> f = -x**2 + 2*x + 5 + >>> maximum(f, x, S.Reals) + 6 + + >>> maximum(sin(x), x, Interval(-pi, pi/4)) + sqrt(2)/2 + + >>> maximum(sin(x)*cos(x), x) + 1/2 + + """ + if isinstance(symbol, Symbol): + if domain is S.EmptySet: + raise ValueError("Maximum value not defined for empty domain.") + + return function_range(f, symbol, domain).sup + else: + raise ValueError("%s is not a valid symbol." % symbol) + + +def minimum(f, symbol, domain=S.Reals): + """ + Returns the minimum value of a function in the given domain. + + Parameters + ========== + + f : :py:class:`~.Expr` + The concerned function. + symbol : :py:class:`~.Symbol` + The variable for minimum value needs to be determined. + domain : :py:class:`~.Interval` + The domain over which the minimum have to be checked. + If unspecified, then the global minimum is returned. + + Returns + ======= + + number + Minimum value of the function in the given domain. + + Examples + ======== + + >>> from sympy import Interval, Symbol, S, sin, cos, minimum + >>> x = Symbol('x') + + >>> f = x**2 + 2*x + 5 + >>> minimum(f, x, S.Reals) + 4 + + >>> minimum(sin(x), x, Interval(2, 3)) + sin(3) + + >>> minimum(sin(x)*cos(x), x) + -1/2 + + """ + if isinstance(symbol, Symbol): + if domain is S.EmptySet: + raise ValueError("Minimum value not defined for empty domain.") + + return function_range(f, symbol, domain).inf + else: + raise ValueError("%s is not a valid symbol." % symbol) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4c5007308a1b232e57f9ed164276862df0c5f265 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/__init__.py @@ -0,0 +1,33 @@ +""" +Category Theory module. + +Provides some of the fundamental category-theory-related classes, +including categories, morphisms, diagrams. Functors are not +implemented yet. + +The general reference work this module tries to follow is + + [JoyOfCats] J. Adamek, H. Herrlich. G. E. Strecker: Abstract and + Concrete Categories. The Joy of Cats. + +The latest version of this book should be available for free download +from + + katmat.math.uni-bremen.de/acc/acc.pdf + +""" + +from .baseclasses import (Object, Morphism, IdentityMorphism, + NamedMorphism, CompositeMorphism, Category, + Diagram) + +from .diagram_drawing import (DiagramGrid, XypicDiagramDrawer, + xypic_draw_diagram, preview_diagram) + +__all__ = [ + 'Object', 'Morphism', 'IdentityMorphism', 'NamedMorphism', + 'CompositeMorphism', 'Category', 'Diagram', + + 'DiagramGrid', 'XypicDiagramDrawer', 'xypic_draw_diagram', + 'preview_diagram', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/baseclasses.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/baseclasses.py new file mode 100644 index 0000000000000000000000000000000000000000..e6ab5153ae4e95f193030864c8f32a52254f2458 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/baseclasses.py @@ -0,0 +1,978 @@ +from sympy.core import S, Basic, Dict, Symbol, Tuple, sympify +from sympy.core.symbol import Str +from sympy.sets import Set, FiniteSet, EmptySet +from sympy.utilities.iterables import iterable + + +class Class(Set): + r""" + The base class for any kind of class in the set-theoretic sense. + + Explanation + =========== + + In axiomatic set theories, everything is a class. A class which + can be a member of another class is a set. A class which is not a + member of another class is a proper class. The class `\{1, 2\}` + is a set; the class of all sets is a proper class. + + This class is essentially a synonym for :class:`sympy.core.Set`. + The goal of this class is to assure easier migration to the + eventual proper implementation of set theory. + """ + is_proper = False + + +class Object(Symbol): + """ + The base class for any kind of object in an abstract category. + + Explanation + =========== + + While technically any instance of :class:`~.Basic` will do, this + class is the recommended way to create abstract objects in + abstract categories. + """ + + +class Morphism(Basic): + """ + The base class for any morphism in an abstract category. + + Explanation + =========== + + In abstract categories, a morphism is an arrow between two + category objects. The object where the arrow starts is called the + domain, while the object where the arrow ends is called the + codomain. + + Two morphisms between the same pair of objects are considered to + be the same morphisms. To distinguish between morphisms between + the same objects use :class:`NamedMorphism`. + + It is prohibited to instantiate this class. Use one of the + derived classes instead. + + See Also + ======== + + IdentityMorphism, NamedMorphism, CompositeMorphism + """ + def __new__(cls, domain, codomain): + raise(NotImplementedError( + "Cannot instantiate Morphism. Use derived classes instead.")) + + @property + def domain(self): + """ + Returns the domain of the morphism. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> f = NamedMorphism(A, B, "f") + >>> f.domain + Object("A") + + """ + return self.args[0] + + @property + def codomain(self): + """ + Returns the codomain of the morphism. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> f = NamedMorphism(A, B, "f") + >>> f.codomain + Object("B") + + """ + return self.args[1] + + def compose(self, other): + r""" + Composes self with the supplied morphism. + + The order of elements in the composition is the usual order, + i.e., to construct `g\circ f` use ``g.compose(f)``. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> g * f + CompositeMorphism((NamedMorphism(Object("A"), Object("B"), "f"), + NamedMorphism(Object("B"), Object("C"), "g"))) + >>> (g * f).domain + Object("A") + >>> (g * f).codomain + Object("C") + + """ + return CompositeMorphism(other, self) + + def __mul__(self, other): + r""" + Composes self with the supplied morphism. + + The semantics of this operation is given by the following + equation: ``g * f == g.compose(f)`` for composable morphisms + ``g`` and ``f``. + + See Also + ======== + + compose + """ + return self.compose(other) + + +class IdentityMorphism(Morphism): + """ + Represents an identity morphism. + + Explanation + =========== + + An identity morphism is a morphism with equal domain and codomain, + which acts as an identity with respect to composition. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, IdentityMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> f = NamedMorphism(A, B, "f") + >>> id_A = IdentityMorphism(A) + >>> id_B = IdentityMorphism(B) + >>> f * id_A == f + True + >>> id_B * f == f + True + + See Also + ======== + + Morphism + """ + def __new__(cls, domain): + return Basic.__new__(cls, domain) + + @property + def codomain(self): + return self.domain + + +class NamedMorphism(Morphism): + """ + Represents a morphism which has a name. + + Explanation + =========== + + Names are used to distinguish between morphisms which have the + same domain and codomain: two named morphisms are equal if they + have the same domains, codomains, and names. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> f = NamedMorphism(A, B, "f") + >>> f + NamedMorphism(Object("A"), Object("B"), "f") + >>> f.name + 'f' + + See Also + ======== + + Morphism + """ + def __new__(cls, domain, codomain, name): + if not name: + raise ValueError("Empty morphism names not allowed.") + + if not isinstance(name, Str): + name = Str(name) + + return Basic.__new__(cls, domain, codomain, name) + + @property + def name(self): + """ + Returns the name of the morphism. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> f = NamedMorphism(A, B, "f") + >>> f.name + 'f' + + """ + return self.args[2].name + + +class CompositeMorphism(Morphism): + r""" + Represents a morphism which is a composition of other morphisms. + + Explanation + =========== + + Two composite morphisms are equal if the morphisms they were + obtained from (components) are the same and were listed in the + same order. + + The arguments to the constructor for this class should be listed + in diagram order: to obtain the composition `g\circ f` from the + instances of :class:`Morphism` ``g`` and ``f`` use + ``CompositeMorphism(f, g)``. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, CompositeMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> g * f + CompositeMorphism((NamedMorphism(Object("A"), Object("B"), "f"), + NamedMorphism(Object("B"), Object("C"), "g"))) + >>> CompositeMorphism(f, g) == g * f + True + + """ + @staticmethod + def _add_morphism(t, morphism): + """ + Intelligently adds ``morphism`` to tuple ``t``. + + Explanation + =========== + + If ``morphism`` is a composite morphism, its components are + added to the tuple. If ``morphism`` is an identity, nothing + is added to the tuple. + + No composability checks are performed. + """ + if isinstance(morphism, CompositeMorphism): + # ``morphism`` is a composite morphism; we have to + # denest its components. + return t + morphism.components + elif isinstance(morphism, IdentityMorphism): + # ``morphism`` is an identity. Nothing happens. + return t + else: + return t + Tuple(morphism) + + def __new__(cls, *components): + if components and not isinstance(components[0], Morphism): + # Maybe the user has explicitly supplied a list of + # morphisms. + return CompositeMorphism.__new__(cls, *components[0]) + + normalised_components = Tuple() + + for current, following in zip(components, components[1:]): + if not isinstance(current, Morphism) or \ + not isinstance(following, Morphism): + raise TypeError("All components must be morphisms.") + + if current.codomain != following.domain: + raise ValueError("Uncomposable morphisms.") + + normalised_components = CompositeMorphism._add_morphism( + normalised_components, current) + + # We haven't added the last morphism to the list of normalised + # components. Add it now. + normalised_components = CompositeMorphism._add_morphism( + normalised_components, components[-1]) + + if not normalised_components: + # If ``normalised_components`` is empty, only identities + # were supplied. Since they all were composable, they are + # all the same identities. + return components[0] + elif len(normalised_components) == 1: + # No sense to construct a whole CompositeMorphism. + return normalised_components[0] + + return Basic.__new__(cls, normalised_components) + + @property + def components(self): + """ + Returns the components of this composite morphism. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> (g * f).components + (NamedMorphism(Object("A"), Object("B"), "f"), + NamedMorphism(Object("B"), Object("C"), "g")) + + """ + return self.args[0] + + @property + def domain(self): + """ + Returns the domain of this composite morphism. + + The domain of the composite morphism is the domain of its + first component. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> (g * f).domain + Object("A") + + """ + return self.components[0].domain + + @property + def codomain(self): + """ + Returns the codomain of this composite morphism. + + The codomain of the composite morphism is the codomain of its + last component. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> (g * f).codomain + Object("C") + + """ + return self.components[-1].codomain + + def flatten(self, new_name): + """ + Forgets the composite structure of this morphism. + + Explanation + =========== + + If ``new_name`` is not empty, returns a :class:`NamedMorphism` + with the supplied name, otherwise returns a :class:`Morphism`. + In both cases the domain of the new morphism is the domain of + this composite morphism and the codomain of the new morphism + is the codomain of this composite morphism. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> (g * f).flatten("h") + NamedMorphism(Object("A"), Object("C"), "h") + + """ + return NamedMorphism(self.domain, self.codomain, new_name) + + +class Category(Basic): + r""" + An (abstract) category. + + Explanation + =========== + + A category [JoyOfCats] is a quadruple `\mbox{K} = (O, \hom, id, + \circ)` consisting of + + * a (set-theoretical) class `O`, whose members are called + `K`-objects, + + * for each pair `(A, B)` of `K`-objects, a set `\hom(A, B)` whose + members are called `K`-morphisms from `A` to `B`, + + * for a each `K`-object `A`, a morphism `id:A\rightarrow A`, + called the `K`-identity of `A`, + + * a composition law `\circ` associating with every `K`-morphisms + `f:A\rightarrow B` and `g:B\rightarrow C` a `K`-morphism `g\circ + f:A\rightarrow C`, called the composite of `f` and `g`. + + Composition is associative, `K`-identities are identities with + respect to composition, and the sets `\hom(A, B)` are pairwise + disjoint. + + This class knows nothing about its objects and morphisms. + Concrete cases of (abstract) categories should be implemented as + classes derived from this one. + + Certain instances of :class:`Diagram` can be asserted to be + commutative in a :class:`Category` by supplying the argument + ``commutative_diagrams`` in the constructor. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram, Category + >>> from sympy import FiniteSet + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g]) + >>> K = Category("K", commutative_diagrams=[d]) + >>> K.commutative_diagrams == FiniteSet(d) + True + + See Also + ======== + + Diagram + """ + def __new__(cls, name, objects=EmptySet, commutative_diagrams=EmptySet): + if not name: + raise ValueError("A Category cannot have an empty name.") + + if not isinstance(name, Str): + name = Str(name) + + if not isinstance(objects, Class): + objects = Class(objects) + + new_category = Basic.__new__(cls, name, objects, + FiniteSet(*commutative_diagrams)) + return new_category + + @property + def name(self): + """ + Returns the name of this category. + + Examples + ======== + + >>> from sympy.categories import Category + >>> K = Category("K") + >>> K.name + 'K' + + """ + return self.args[0].name + + @property + def objects(self): + """ + Returns the class of objects of this category. + + Examples + ======== + + >>> from sympy.categories import Object, Category + >>> from sympy import FiniteSet + >>> A = Object("A") + >>> B = Object("B") + >>> K = Category("K", FiniteSet(A, B)) + >>> K.objects + Class({Object("A"), Object("B")}) + + """ + return self.args[1] + + @property + def commutative_diagrams(self): + """ + Returns the :class:`~.FiniteSet` of diagrams which are known to + be commutative in this category. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram, Category + >>> from sympy import FiniteSet + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g]) + >>> K = Category("K", commutative_diagrams=[d]) + >>> K.commutative_diagrams == FiniteSet(d) + True + + """ + return self.args[2] + + def hom(self, A, B): + raise NotImplementedError( + "hom-sets are not implemented in Category.") + + def all_morphisms(self): + raise NotImplementedError( + "Obtaining the class of morphisms is not implemented in Category.") + + +class Diagram(Basic): + r""" + Represents a diagram in a certain category. + + Explanation + =========== + + Informally, a diagram is a collection of objects of a category and + certain morphisms between them. A diagram is still a monoid with + respect to morphism composition; i.e., identity morphisms, as well + as all composites of morphisms included in the diagram belong to + the diagram. For a more formal approach to this notion see + [Pare1970]. + + The components of composite morphisms are also added to the + diagram. No properties are assigned to such morphisms by default. + + A commutative diagram is often accompanied by a statement of the + following kind: "if such morphisms with such properties exist, + then such morphisms which such properties exist and the diagram is + commutative". To represent this, an instance of :class:`Diagram` + includes a collection of morphisms which are the premises and + another collection of conclusions. ``premises`` and + ``conclusions`` associate morphisms belonging to the corresponding + categories with the :class:`~.FiniteSet`'s of their properties. + + The set of properties of a composite morphism is the intersection + of the sets of properties of its components. The domain and + codomain of a conclusion morphism should be among the domains and + codomains of the morphisms listed as the premises of a diagram. + + No checks are carried out of whether the supplied object and + morphisms do belong to one and the same category. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy import pprint, default_sort_key + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g]) + >>> premises_keys = sorted(d.premises.keys(), key=default_sort_key) + >>> pprint(premises_keys, use_unicode=False) + [g*f:A-->C, id:A-->A, id:B-->B, id:C-->C, f:A-->B, g:B-->C] + >>> pprint(d.premises, use_unicode=False) + {g*f:A-->C: EmptySet, id:A-->A: EmptySet, id:B-->B: EmptySet, + id:C-->C: EmptySet, f:A-->B: EmptySet, g:B-->C: EmptySet} + >>> d = Diagram([f, g], {g * f: "unique"}) + >>> pprint(d.conclusions,use_unicode=False) + {g*f:A-->C: {unique}} + + References + ========== + + [Pare1970] B. Pareigis: Categories and functors. Academic Press, 1970. + + """ + @staticmethod + def _set_dict_union(dictionary, key, value): + """ + If ``key`` is in ``dictionary``, set the new value of ``key`` + to be the union between the old value and ``value``. + Otherwise, set the value of ``key`` to ``value. + + Returns ``True`` if the key already was in the dictionary and + ``False`` otherwise. + """ + if key in dictionary: + dictionary[key] = dictionary[key] | value + return True + else: + dictionary[key] = value + return False + + @staticmethod + def _add_morphism_closure(morphisms, morphism, props, add_identities=True, + recurse_composites=True): + """ + Adds a morphism and its attributes to the supplied dictionary + ``morphisms``. If ``add_identities`` is True, also adds the + identity morphisms for the domain and the codomain of + ``morphism``. + """ + if not Diagram._set_dict_union(morphisms, morphism, props): + # We have just added a new morphism. + + if isinstance(morphism, IdentityMorphism): + if props: + # Properties for identity morphisms don't really + # make sense, because very much is known about + # identity morphisms already, so much that they + # are trivial. Having properties for identity + # morphisms would only be confusing. + raise ValueError( + "Instances of IdentityMorphism cannot have properties.") + return + + if add_identities: + empty = EmptySet + + id_dom = IdentityMorphism(morphism.domain) + id_cod = IdentityMorphism(morphism.codomain) + + Diagram._set_dict_union(morphisms, id_dom, empty) + Diagram._set_dict_union(morphisms, id_cod, empty) + + for existing_morphism, existing_props in list(morphisms.items()): + new_props = existing_props & props + if morphism.domain == existing_morphism.codomain: + left = morphism * existing_morphism + Diagram._set_dict_union(morphisms, left, new_props) + if morphism.codomain == existing_morphism.domain: + right = existing_morphism * morphism + Diagram._set_dict_union(morphisms, right, new_props) + + if isinstance(morphism, CompositeMorphism) and recurse_composites: + # This is a composite morphism, add its components as + # well. + empty = EmptySet + for component in morphism.components: + Diagram._add_morphism_closure(morphisms, component, empty, + add_identities) + + def __new__(cls, *args): + """ + Construct a new instance of Diagram. + + Explanation + =========== + + If no arguments are supplied, an empty diagram is created. + + If at least an argument is supplied, ``args[0]`` is + interpreted as the premises of the diagram. If ``args[0]`` is + a list, it is interpreted as a list of :class:`Morphism`'s, in + which each :class:`Morphism` has an empty set of properties. + If ``args[0]`` is a Python dictionary or a :class:`Dict`, it + is interpreted as a dictionary associating to some + :class:`Morphism`'s some properties. + + If at least two arguments are supplied ``args[1]`` is + interpreted as the conclusions of the diagram. The type of + ``args[1]`` is interpreted in exactly the same way as the type + of ``args[0]``. If only one argument is supplied, the diagram + has no conclusions. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import IdentityMorphism, Diagram + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g]) + >>> IdentityMorphism(A) in d.premises.keys() + True + >>> g * f in d.premises.keys() + True + >>> d = Diagram([f, g], {g * f: "unique"}) + >>> d.conclusions[g * f] + {unique} + + """ + premises = {} + conclusions = {} + + # Here we will keep track of the objects which appear in the + # premises. + objects = EmptySet + + if len(args) >= 1: + # We've got some premises in the arguments. + premises_arg = args[0] + + if isinstance(premises_arg, list): + # The user has supplied a list of morphisms, none of + # which have any attributes. + empty = EmptySet + + for morphism in premises_arg: + objects |= FiniteSet(morphism.domain, morphism.codomain) + Diagram._add_morphism_closure(premises, morphism, empty) + elif isinstance(premises_arg, (dict, Dict)): + # The user has supplied a dictionary of morphisms and + # their properties. + for morphism, props in premises_arg.items(): + objects |= FiniteSet(morphism.domain, morphism.codomain) + Diagram._add_morphism_closure( + premises, morphism, FiniteSet(*props) if iterable(props) else FiniteSet(props)) + + if len(args) >= 2: + # We also have some conclusions. + conclusions_arg = args[1] + + if isinstance(conclusions_arg, list): + # The user has supplied a list of morphisms, none of + # which have any attributes. + empty = EmptySet + + for morphism in conclusions_arg: + # Check that no new objects appear in conclusions. + if ((sympify(objects.contains(morphism.domain)) is S.true) and + (sympify(objects.contains(morphism.codomain)) is S.true)): + # No need to add identities and recurse + # composites this time. + Diagram._add_morphism_closure( + conclusions, morphism, empty, add_identities=False, + recurse_composites=False) + elif isinstance(conclusions_arg, (dict, Dict)): + # The user has supplied a dictionary of morphisms and + # their properties. + for morphism, props in conclusions_arg.items(): + # Check that no new objects appear in conclusions. + if (morphism.domain in objects) and \ + (morphism.codomain in objects): + # No need to add identities and recurse + # composites this time. + Diagram._add_morphism_closure( + conclusions, morphism, FiniteSet(*props) if iterable(props) else FiniteSet(props), + add_identities=False, recurse_composites=False) + + return Basic.__new__(cls, Dict(premises), Dict(conclusions), objects) + + @property + def premises(self): + """ + Returns the premises of this diagram. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import IdentityMorphism, Diagram + >>> from sympy import pretty + >>> A = Object("A") + >>> B = Object("B") + >>> f = NamedMorphism(A, B, "f") + >>> id_A = IdentityMorphism(A) + >>> id_B = IdentityMorphism(B) + >>> d = Diagram([f]) + >>> print(pretty(d.premises, use_unicode=False)) + {id:A-->A: EmptySet, id:B-->B: EmptySet, f:A-->B: EmptySet} + + """ + return self.args[0] + + @property + def conclusions(self): + """ + Returns the conclusions of this diagram. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import IdentityMorphism, Diagram + >>> from sympy import FiniteSet + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g]) + >>> IdentityMorphism(A) in d.premises.keys() + True + >>> g * f in d.premises.keys() + True + >>> d = Diagram([f, g], {g * f: "unique"}) + >>> d.conclusions[g * f] == FiniteSet("unique") + True + + """ + return self.args[1] + + @property + def objects(self): + """ + Returns the :class:`~.FiniteSet` of objects that appear in this + diagram. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g]) + >>> d.objects + {Object("A"), Object("B"), Object("C")} + + """ + return self.args[2] + + def hom(self, A, B): + """ + Returns a 2-tuple of sets of morphisms between objects ``A`` and + ``B``: one set of morphisms listed as premises, and the other set + of morphisms listed as conclusions. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy import pretty + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g], {g * f: "unique"}) + >>> print(pretty(d.hom(A, C), use_unicode=False)) + ({g*f:A-->C}, {g*f:A-->C}) + + See Also + ======== + Object, Morphism + """ + premises = EmptySet + conclusions = EmptySet + + for morphism in self.premises.keys(): + if (morphism.domain == A) and (morphism.codomain == B): + premises |= FiniteSet(morphism) + for morphism in self.conclusions.keys(): + if (morphism.domain == A) and (morphism.codomain == B): + conclusions |= FiniteSet(morphism) + + return (premises, conclusions) + + def is_subdiagram(self, diagram): + """ + Checks whether ``diagram`` is a subdiagram of ``self``. + Diagram `D'` is a subdiagram of `D` if all premises + (conclusions) of `D'` are contained in the premises + (conclusions) of `D`. The morphisms contained + both in `D'` and `D` should have the same properties for `D'` + to be a subdiagram of `D`. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g], {g * f: "unique"}) + >>> d1 = Diagram([f]) + >>> d.is_subdiagram(d1) + True + >>> d1.is_subdiagram(d) + False + """ + premises = all((m in self.premises) and + (diagram.premises[m] == self.premises[m]) + for m in diagram.premises) + if not premises: + return False + + conclusions = all((m in self.conclusions) and + (diagram.conclusions[m] == self.conclusions[m]) + for m in diagram.conclusions) + + # Premises is surely ``True`` here. + return conclusions + + def subdiagram_from_objects(self, objects): + """ + If ``objects`` is a subset of the objects of ``self``, returns + a diagram which has as premises all those premises of ``self`` + which have a domains and codomains in ``objects``, likewise + for conclusions. Properties are preserved. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy import FiniteSet + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g], {f: "unique", g*f: "veryunique"}) + >>> d1 = d.subdiagram_from_objects(FiniteSet(A, B)) + >>> d1 == Diagram([f], {f: "unique"}) + True + """ + if not objects.is_subset(self.objects): + raise ValueError( + "Supplied objects should all belong to the diagram.") + + new_premises = {} + for morphism, props in self.premises.items(): + if ((sympify(objects.contains(morphism.domain)) is S.true) and + (sympify(objects.contains(morphism.codomain)) is S.true)): + new_premises[morphism] = props + + new_conclusions = {} + for morphism, props in self.conclusions.items(): + if ((sympify(objects.contains(morphism.domain)) is S.true) and + (sympify(objects.contains(morphism.codomain)) is S.true)): + new_conclusions[morphism] = props + + return Diagram(new_premises, new_conclusions) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/diagram_drawing.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/diagram_drawing.py new file mode 100644 index 0000000000000000000000000000000000000000..2a9b507cd86cf0e633b5abf7a0c9a353740af334 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/categories/diagram_drawing.py @@ -0,0 +1,2580 @@ +r""" +This module contains the functionality to arrange the nodes of a +diagram on an abstract grid, and then to produce a graphical +representation of the grid. + +The currently supported back-ends are Xy-pic [Xypic]. + +Layout Algorithm +================ + +This section provides an overview of the algorithms implemented in +:class:`DiagramGrid` to lay out diagrams. + +The first step of the algorithm is the removal composite and identity +morphisms which do not have properties in the supplied diagram. The +premises and conclusions of the diagram are then merged. + +The generic layout algorithm begins with the construction of the +"skeleton" of the diagram. The skeleton is an undirected graph which +has the objects of the diagram as vertices and has an (undirected) +edge between each pair of objects between which there exist morphisms. +The direction of the morphisms does not matter at this stage. The +skeleton also includes an edge between each pair of vertices `A` and +`C` such that there exists an object `B` which is connected via +a morphism to `A`, and via a morphism to `C`. + +The skeleton constructed in this way has the property that every +object is a vertex of a triangle formed by three edges of the +skeleton. This property lies at the base of the generic layout +algorithm. + +After the skeleton has been constructed, the algorithm lists all +triangles which can be formed. Note that some triangles will not have +all edges corresponding to morphisms which will actually be drawn. +Triangles which have only one edge or less which will actually be +drawn are immediately discarded. + +The list of triangles is sorted according to the number of edges which +correspond to morphisms, then the triangle with the least number of such +edges is selected. One of such edges is picked and the corresponding +objects are placed horizontally, on a grid. This edge is recorded to +be in the fringe. The algorithm then finds a "welding" of a triangle +to the fringe. A welding is an edge in the fringe where a triangle +could be attached. If the algorithm succeeds in finding such a +welding, it adds to the grid that vertex of the triangle which was not +yet included in any edge in the fringe and records the two new edges in +the fringe. This process continues iteratively until all objects of +the diagram has been placed or until no more weldings can be found. + +An edge is only removed from the fringe when a welding to this edge +has been found, and there is no room around this edge to place +another vertex. + +When no more weldings can be found, but there are still triangles +left, the algorithm searches for a possibility of attaching one of the +remaining triangles to the existing structure by a vertex. If such a +possibility is found, the corresponding edge of the found triangle is +placed in the found space and the iterative process of welding +triangles restarts. + +When logical groups are supplied, each of these groups is laid out +independently. Then a diagram is constructed in which groups are +objects and any two logical groups between which there exist morphisms +are connected via a morphism. This diagram is laid out. Finally, +the grid which includes all objects of the initial diagram is +constructed by replacing the cells which contain logical groups with +the corresponding laid out grids, and by correspondingly expanding the +rows and columns. + +The sequential layout algorithm begins by constructing the +underlying undirected graph defined by the morphisms obtained after +simplifying premises and conclusions and merging them (see above). +The vertex with the minimal degree is then picked up and depth-first +search is started from it. All objects which are located at distance +`n` from the root in the depth-first search tree, are positioned in +the `n`-th column of the resulting grid. The sequential layout will +therefore attempt to lay the objects out along a line. + +References +========== + +.. [Xypic] https://xy-pic.sourceforge.net/ + +""" +from sympy.categories import (CompositeMorphism, IdentityMorphism, + NamedMorphism, Diagram) +from sympy.core import Dict, Symbol, default_sort_key +from sympy.printing.latex import latex +from sympy.sets import FiniteSet +from sympy.utilities.iterables import iterable +from sympy.utilities.decorator import doctest_depends_on + +from itertools import chain + + +__doctest_requires__ = {('preview_diagram',): 'pyglet'} + + +class _GrowableGrid: + """ + Holds a growable grid of objects. + + Explanation + =========== + + It is possible to append or prepend a row or a column to the grid + using the corresponding methods. Prepending rows or columns has + the effect of changing the coordinates of the already existing + elements. + + This class currently represents a naive implementation of the + functionality with little attempt at optimisation. + """ + def __init__(self, width, height): + self._width = width + self._height = height + + self._array = [[None for j in range(width)] for i in range(height)] + + @property + def width(self): + return self._width + + @property + def height(self): + return self._height + + def __getitem__(self, i_j): + """ + Returns the element located at in the i-th line and j-th + column. + """ + i, j = i_j + return self._array[i][j] + + def __setitem__(self, i_j, newvalue): + """ + Sets the element located at in the i-th line and j-th + column. + """ + i, j = i_j + self._array[i][j] = newvalue + + def append_row(self): + """ + Appends an empty row to the grid. + """ + self._height += 1 + self._array.append([None for j in range(self._width)]) + + def append_column(self): + """ + Appends an empty column to the grid. + """ + self._width += 1 + for i in range(self._height): + self._array[i].append(None) + + def prepend_row(self): + """ + Prepends the grid with an empty row. + """ + self._height += 1 + self._array.insert(0, [None for j in range(self._width)]) + + def prepend_column(self): + """ + Prepends the grid with an empty column. + """ + self._width += 1 + for i in range(self._height): + self._array[i].insert(0, None) + + +class DiagramGrid: + r""" + Constructs and holds the fitting of the diagram into a grid. + + Explanation + =========== + + The mission of this class is to analyse the structure of the + supplied diagram and to place its objects on a grid such that, + when the objects and the morphisms are actually drawn, the diagram + would be "readable", in the sense that there will not be many + intersections of moprhisms. This class does not perform any + actual drawing. It does strive nevertheless to offer sufficient + metadata to draw a diagram. + + Consider the following simple diagram. + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import Diagram, DiagramGrid + >>> from sympy import pprint + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g]) + + The simplest way to have a diagram laid out is the following: + + >>> grid = DiagramGrid(diagram) + >>> (grid.width, grid.height) + (2, 2) + >>> pprint(grid) + A B + + C + + Sometimes one sees the diagram as consisting of logical groups. + One can advise ``DiagramGrid`` as to such groups by employing the + ``groups`` keyword argument. + + Consider the following diagram: + + >>> D = Object("D") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> h = NamedMorphism(D, A, "h") + >>> k = NamedMorphism(D, B, "k") + >>> diagram = Diagram([f, g, h, k]) + + Lay it out with generic layout: + + >>> grid = DiagramGrid(diagram) + >>> pprint(grid) + A B D + + C + + Now, we can group the objects `A` and `D` to have them near one + another: + + >>> grid = DiagramGrid(diagram, groups=[[A, D], B, C]) + >>> pprint(grid) + B C + + A D + + Note how the positioning of the other objects changes. + + Further indications can be supplied to the constructor of + :class:`DiagramGrid` using keyword arguments. The currently + supported hints are explained in the following paragraphs. + + :class:`DiagramGrid` does not automatically guess which layout + would suit the supplied diagram better. Consider, for example, + the following linear diagram: + + >>> E = Object("E") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> h = NamedMorphism(C, D, "h") + >>> i = NamedMorphism(D, E, "i") + >>> diagram = Diagram([f, g, h, i]) + + When laid out with the generic layout, it does not get to look + linear: + + >>> grid = DiagramGrid(diagram) + >>> pprint(grid) + A B + + C D + + E + + To get it laid out in a line, use ``layout="sequential"``: + + >>> grid = DiagramGrid(diagram, layout="sequential") + >>> pprint(grid) + A B C D E + + One may sometimes need to transpose the resulting layout. While + this can always be done by hand, :class:`DiagramGrid` provides a + hint for that purpose: + + >>> grid = DiagramGrid(diagram, layout="sequential", transpose=True) + >>> pprint(grid) + A + + B + + C + + D + + E + + Separate hints can also be provided for each group. For an + example, refer to ``tests/test_drawing.py``, and see the different + ways in which the five lemma [FiveLemma] can be laid out. + + See Also + ======== + + Diagram + + References + ========== + + .. [FiveLemma] https://en.wikipedia.org/wiki/Five_lemma + """ + @staticmethod + def _simplify_morphisms(morphisms): + """ + Given a dictionary mapping morphisms to their properties, + returns a new dictionary in which there are no morphisms which + do not have properties, and which are compositions of other + morphisms included in the dictionary. Identities are dropped + as well. + """ + newmorphisms = {} + for morphism, props in morphisms.items(): + if isinstance(morphism, CompositeMorphism) and not props: + continue + elif isinstance(morphism, IdentityMorphism): + continue + else: + newmorphisms[morphism] = props + return newmorphisms + + @staticmethod + def _merge_premises_conclusions(premises, conclusions): + """ + Given two dictionaries of morphisms and their properties, + produces a single dictionary which includes elements from both + dictionaries. If a morphism has some properties in premises + and also in conclusions, the properties in conclusions take + priority. + """ + return dict(chain(premises.items(), conclusions.items())) + + @staticmethod + def _juxtapose_edges(edge1, edge2): + """ + If ``edge1`` and ``edge2`` have precisely one common endpoint, + returns an edge which would form a triangle with ``edge1`` and + ``edge2``. + + If ``edge1`` and ``edge2`` do not have a common endpoint, + returns ``None``. + + If ``edge1`` and ``edge`` are the same edge, returns ``None``. + """ + intersection = edge1 & edge2 + if len(intersection) != 1: + # The edges either have no common points or are equal. + return None + + # The edges have a common endpoint. Extract the different + # endpoints and set up the new edge. + return (edge1 - intersection) | (edge2 - intersection) + + @staticmethod + def _add_edge_append(dictionary, edge, elem): + """ + If ``edge`` is not in ``dictionary``, adds ``edge`` to the + dictionary and sets its value to ``[elem]``. Otherwise + appends ``elem`` to the value of existing entry. + + Note that edges are undirected, thus `(A, B) = (B, A)`. + """ + if edge in dictionary: + dictionary[edge].append(elem) + else: + dictionary[edge] = [elem] + + @staticmethod + def _build_skeleton(morphisms): + """ + Creates a dictionary which maps edges to corresponding + morphisms. Thus for a morphism `f:A\rightarrow B`, the edge + `(A, B)` will be associated with `f`. This function also adds + to the list those edges which are formed by juxtaposition of + two edges already in the list. These new edges are not + associated with any morphism and are only added to assure that + the diagram can be decomposed into triangles. + """ + edges = {} + # Create edges for morphisms. + for morphism in morphisms: + DiagramGrid._add_edge_append( + edges, frozenset([morphism.domain, morphism.codomain]), morphism) + + # Create new edges by juxtaposing existing edges. + edges1 = dict(edges) + for w in edges1: + for v in edges1: + wv = DiagramGrid._juxtapose_edges(w, v) + if wv and wv not in edges: + edges[wv] = [] + + return edges + + @staticmethod + def _list_triangles(edges): + """ + Builds the set of triangles formed by the supplied edges. The + triangles are arbitrary and need not be commutative. A + triangle is a set that contains all three of its sides. + """ + triangles = set() + + for w in edges: + for v in edges: + wv = DiagramGrid._juxtapose_edges(w, v) + if wv and wv in edges: + triangles.add(frozenset([w, v, wv])) + + return triangles + + @staticmethod + def _drop_redundant_triangles(triangles, skeleton): + """ + Returns a list which contains only those triangles who have + morphisms associated with at least two edges. + """ + return [tri for tri in triangles + if len([e for e in tri if skeleton[e]]) >= 2] + + @staticmethod + def _morphism_length(morphism): + """ + Returns the length of a morphism. The length of a morphism is + the number of components it consists of. A non-composite + morphism is of length 1. + """ + if isinstance(morphism, CompositeMorphism): + return len(morphism.components) + else: + return 1 + + @staticmethod + def _compute_triangle_min_sizes(triangles, edges): + r""" + Returns a dictionary mapping triangles to their minimal sizes. + The minimal size of a triangle is the sum of maximal lengths + of morphisms associated to the sides of the triangle. The + length of a morphism is the number of components it consists + of. A non-composite morphism is of length 1. + + Sorting triangles by this metric attempts to address two + aspects of layout. For triangles with only simple morphisms + in the edge, this assures that triangles with all three edges + visible will get typeset after triangles with less visible + edges, which sometimes minimizes the necessity in diagonal + arrows. For triangles with composite morphisms in the edges, + this assures that objects connected with shorter morphisms + will be laid out first, resulting the visual proximity of + those objects which are connected by shorter morphisms. + """ + triangle_sizes = {} + for triangle in triangles: + size = 0 + for e in triangle: + morphisms = edges[e] + if morphisms: + size += max(DiagramGrid._morphism_length(m) + for m in morphisms) + triangle_sizes[triangle] = size + return triangle_sizes + + @staticmethod + def _triangle_objects(triangle): + """ + Given a triangle, returns the objects included in it. + """ + # A triangle is a frozenset of three two-element frozensets + # (the edges). This chains the three edges together and + # creates a frozenset from the iterator, thus producing a + # frozenset of objects of the triangle. + return frozenset(chain(*tuple(triangle))) + + @staticmethod + def _other_vertex(triangle, edge): + """ + Given a triangle and an edge of it, returns the vertex which + opposes the edge. + """ + # This gets the set of objects of the triangle and then + # subtracts the set of objects employed in ``edge`` to get the + # vertex opposite to ``edge``. + return list(DiagramGrid._triangle_objects(triangle) - set(edge))[0] + + @staticmethod + def _empty_point(pt, grid): + """ + Checks if the cell at coordinates ``pt`` is either empty or + out of the bounds of the grid. + """ + if (pt[0] < 0) or (pt[1] < 0) or \ + (pt[0] >= grid.height) or (pt[1] >= grid.width): + return True + return grid[pt] is None + + @staticmethod + def _put_object(coords, obj, grid, fringe): + """ + Places an object at the coordinate ``cords`` in ``grid``, + growing the grid and updating ``fringe``, if necessary. + Returns (0, 0) if no row or column has been prepended, (1, 0) + if a row was prepended, (0, 1) if a column was prepended and + (1, 1) if both a column and a row were prepended. + """ + (i, j) = coords + offset = (0, 0) + if i == -1: + grid.prepend_row() + i = 0 + offset = (1, 0) + for k in range(len(fringe)): + ((i1, j1), (i2, j2)) = fringe[k] + fringe[k] = ((i1 + 1, j1), (i2 + 1, j2)) + elif i == grid.height: + grid.append_row() + + if j == -1: + j = 0 + offset = (offset[0], 1) + grid.prepend_column() + for k in range(len(fringe)): + ((i1, j1), (i2, j2)) = fringe[k] + fringe[k] = ((i1, j1 + 1), (i2, j2 + 1)) + elif j == grid.width: + grid.append_column() + + grid[i, j] = obj + return offset + + @staticmethod + def _choose_target_cell(pt1, pt2, edge, obj, skeleton, grid): + """ + Given two points, ``pt1`` and ``pt2``, and the welding edge + ``edge``, chooses one of the two points to place the opposing + vertex ``obj`` of the triangle. If neither of this points + fits, returns ``None``. + """ + pt1_empty = DiagramGrid._empty_point(pt1, grid) + pt2_empty = DiagramGrid._empty_point(pt2, grid) + + if pt1_empty and pt2_empty: + # Both cells are empty. Of these two, choose that cell + # which will assure that a visible edge of the triangle + # will be drawn perpendicularly to the current welding + # edge. + + A = grid[edge[0]] + + if skeleton.get(frozenset([A, obj])): + return pt1 + else: + return pt2 + if pt1_empty: + return pt1 + elif pt2_empty: + return pt2 + else: + return None + + @staticmethod + def _find_triangle_to_weld(triangles, fringe, grid): + """ + Finds, if possible, a triangle and an edge in the ``fringe`` to + which the triangle could be attached. Returns the tuple + containing the triangle and the index of the corresponding + edge in the ``fringe``. + + This function relies on the fact that objects are unique in + the diagram. + """ + for triangle in triangles: + for (a, b) in fringe: + if frozenset([grid[a], grid[b]]) in triangle: + return (triangle, (a, b)) + return None + + @staticmethod + def _weld_triangle(tri, welding_edge, fringe, grid, skeleton): + """ + If possible, welds the triangle ``tri`` to ``fringe`` and + returns ``False``. If this method encounters a degenerate + situation in the fringe and corrects it such that a restart of + the search is required, it returns ``True`` (which means that + a restart in finding triangle weldings is required). + + A degenerate situation is a situation when an edge listed in + the fringe does not belong to the visual boundary of the + diagram. + """ + a, b = welding_edge + target_cell = None + + obj = DiagramGrid._other_vertex(tri, (grid[a], grid[b])) + + # We now have a triangle and an edge where it can be welded to + # the fringe. Decide where to place the other vertex of the + # triangle and check for degenerate situations en route. + + if (abs(a[0] - b[0]) == 1) and (abs(a[1] - b[1]) == 1): + # A diagonal edge. + target_cell = (a[0], b[1]) + if grid[target_cell]: + # That cell is already occupied. + target_cell = (b[0], a[1]) + + if grid[target_cell]: + # Degenerate situation, this edge is not + # on the actual fringe. Correct the + # fringe and go on. + fringe.remove((a, b)) + return True + elif a[0] == b[0]: + # A horizontal edge. We first attempt to build the + # triangle in the downward direction. + + down_left = a[0] + 1, a[1] + down_right = a[0] + 1, b[1] + + target_cell = DiagramGrid._choose_target_cell( + down_left, down_right, (a, b), obj, skeleton, grid) + + if not target_cell: + # No room below this edge. Check above. + up_left = a[0] - 1, a[1] + up_right = a[0] - 1, b[1] + + target_cell = DiagramGrid._choose_target_cell( + up_left, up_right, (a, b), obj, skeleton, grid) + + if not target_cell: + # This edge is not in the fringe, remove it + # and restart. + fringe.remove((a, b)) + return True + elif a[1] == b[1]: + # A vertical edge. We will attempt to place the other + # vertex of the triangle to the right of this edge. + right_up = a[0], a[1] + 1 + right_down = b[0], a[1] + 1 + + target_cell = DiagramGrid._choose_target_cell( + right_up, right_down, (a, b), obj, skeleton, grid) + + if not target_cell: + # No room to the left. See what's to the right. + left_up = a[0], a[1] - 1 + left_down = b[0], a[1] - 1 + + target_cell = DiagramGrid._choose_target_cell( + left_up, left_down, (a, b), obj, skeleton, grid) + + if not target_cell: + # This edge is not in the fringe, remove it + # and restart. + fringe.remove((a, b)) + return True + + # We now know where to place the other vertex of the + # triangle. + offset = DiagramGrid._put_object(target_cell, obj, grid, fringe) + + # Take care of the displacement of coordinates if a row or + # a column was prepended. + target_cell = (target_cell[0] + offset[0], + target_cell[1] + offset[1]) + a = (a[0] + offset[0], a[1] + offset[1]) + b = (b[0] + offset[0], b[1] + offset[1]) + + fringe.extend([(a, target_cell), (b, target_cell)]) + + # No restart is required. + return False + + @staticmethod + def _triangle_key(tri, triangle_sizes): + """ + Returns a key for the supplied triangle. It should be the + same independently of the hash randomisation. + """ + objects = sorted( + DiagramGrid._triangle_objects(tri), key=default_sort_key) + return (triangle_sizes[tri], default_sort_key(objects)) + + @staticmethod + def _pick_root_edge(tri, skeleton): + """ + For a given triangle always picks the same root edge. The + root edge is the edge that will be placed first on the grid. + """ + candidates = [sorted(e, key=default_sort_key) + for e in tri if skeleton[e]] + sorted_candidates = sorted(candidates, key=default_sort_key) + # Don't forget to assure the proper ordering of the vertices + # in this edge. + return tuple(sorted(sorted_candidates[0], key=default_sort_key)) + + @staticmethod + def _drop_irrelevant_triangles(triangles, placed_objects): + """ + Returns only those triangles whose set of objects is not + completely included in ``placed_objects``. + """ + return [tri for tri in triangles if not placed_objects.issuperset( + DiagramGrid._triangle_objects(tri))] + + @staticmethod + def _grow_pseudopod(triangles, fringe, grid, skeleton, placed_objects): + """ + Starting from an object in the existing structure on the ``grid``, + adds an edge to which a triangle from ``triangles`` could be + welded. If this method has found a way to do so, it returns + the object it has just added. + + This method should be applied when ``_weld_triangle`` cannot + find weldings any more. + """ + for i in range(grid.height): + for j in range(grid.width): + obj = grid[i, j] + if not obj: + continue + + # Here we need to choose a triangle which has only + # ``obj`` in common with the existing structure. The + # situations when this is not possible should be + # handled elsewhere. + + def good_triangle(tri): + objs = DiagramGrid._triangle_objects(tri) + return obj in objs and \ + placed_objects & (objs - {obj}) == set() + + tris = [tri for tri in triangles if good_triangle(tri)] + if not tris: + # This object is not interesting. + continue + + # Pick the "simplest" of the triangles which could be + # attached. Remember that the list of triangles is + # sorted according to their "simplicity" (see + # _compute_triangle_min_sizes for the metric). + # + # Note that ``tris`` are sequentially built from + # ``triangles``, so we don't have to worry about hash + # randomisation. + tri = tris[0] + + # We have found a triangle which could be attached to + # the existing structure by a vertex. + + candidates = sorted([e for e in tri if skeleton[e]], + key=lambda e: FiniteSet(*e).sort_key()) + edges = [e for e in candidates if obj in e] + + # Note that a meaningful edge (i.e., and edge that is + # associated with a morphism) containing ``obj`` + # always exists. That's because all triangles are + # guaranteed to have at least two meaningful edges. + # See _drop_redundant_triangles. + + # Get the object at the other end of the edge. + edge = edges[0] + other_obj = tuple(edge - frozenset([obj]))[0] + + # Now check for free directions. When checking for + # free directions, prefer the horizontal and vertical + # directions. + neighbours = [(i - 1, j), (i, j + 1), (i + 1, j), (i, j - 1), + (i - 1, j - 1), (i - 1, j + 1), (i + 1, j - 1), (i + 1, j + 1)] + + for pt in neighbours: + if DiagramGrid._empty_point(pt, grid): + # We have a found a place to grow the + # pseudopod into. + offset = DiagramGrid._put_object( + pt, other_obj, grid, fringe) + + i += offset[0] + j += offset[1] + pt = (pt[0] + offset[0], pt[1] + offset[1]) + fringe.append(((i, j), pt)) + + return other_obj + + # This diagram is actually cooler that I can handle. Fail cowardly. + return None + + @staticmethod + def _handle_groups(diagram, groups, merged_morphisms, hints): + """ + Given the slightly preprocessed morphisms of the diagram, + produces a grid laid out according to ``groups``. + + If a group has hints, it is laid out with those hints only, + without any influence from ``hints``. Otherwise, it is laid + out with ``hints``. + """ + def lay_out_group(group, local_hints): + """ + If ``group`` is a set of objects, uses a ``DiagramGrid`` + to lay it out and returns the grid. Otherwise returns the + object (i.e., ``group``). If ``local_hints`` is not + empty, it is supplied to ``DiagramGrid`` as the dictionary + of hints. Otherwise, the ``hints`` argument of + ``_handle_groups`` is used. + """ + if isinstance(group, FiniteSet): + # Set up the corresponding object-to-group + # mappings. + for obj in group: + obj_groups[obj] = group + + # Lay out the current group. + if local_hints: + groups_grids[group] = DiagramGrid( + diagram.subdiagram_from_objects(group), **local_hints) + else: + groups_grids[group] = DiagramGrid( + diagram.subdiagram_from_objects(group), **hints) + else: + obj_groups[group] = group + + def group_to_finiteset(group): + """ + Converts ``group`` to a :class:``FiniteSet`` if it is an + iterable. + """ + if iterable(group): + return FiniteSet(*group) + else: + return group + + obj_groups = {} + groups_grids = {} + + # We would like to support various containers to represent + # groups. To achieve that, before laying each group out, it + # should be converted to a FiniteSet, because that is what the + # following code expects. + + if isinstance(groups, (dict, Dict)): + finiteset_groups = {} + for group, local_hints in groups.items(): + finiteset_group = group_to_finiteset(group) + finiteset_groups[finiteset_group] = local_hints + lay_out_group(group, local_hints) + groups = finiteset_groups + else: + finiteset_groups = [] + for group in groups: + finiteset_group = group_to_finiteset(group) + finiteset_groups.append(finiteset_group) + lay_out_group(finiteset_group, None) + groups = finiteset_groups + + new_morphisms = [] + for morphism in merged_morphisms: + dom = obj_groups[morphism.domain] + cod = obj_groups[morphism.codomain] + # Note that we are not really interested in morphisms + # which do not employ two different groups, because + # these do not influence the layout. + if dom != cod: + # These are essentially unnamed morphisms; they are + # not going to mess in the final layout. By giving + # them the same names, we avoid unnecessary + # duplicates. + new_morphisms.append(NamedMorphism(dom, cod, "dummy")) + + # Lay out the new diagram. Since these are dummy morphisms, + # properties and conclusions are irrelevant. + top_grid = DiagramGrid(Diagram(new_morphisms)) + + # We now have to substitute the groups with the corresponding + # grids, laid out at the beginning of this function. Compute + # the size of each row and column in the grid, so that all + # nested grids fit. + + def group_size(group): + """ + For the supplied group (or object, eventually), returns + the size of the cell that will hold this group (object). + """ + if group in groups_grids: + grid = groups_grids[group] + return (grid.height, grid.width) + else: + return (1, 1) + + row_heights = [max(group_size(top_grid[i, j])[0] + for j in range(top_grid.width)) + for i in range(top_grid.height)] + + column_widths = [max(group_size(top_grid[i, j])[1] + for i in range(top_grid.height)) + for j in range(top_grid.width)] + + grid = _GrowableGrid(sum(column_widths), sum(row_heights)) + + real_row = 0 + real_column = 0 + for logical_row in range(top_grid.height): + for logical_column in range(top_grid.width): + obj = top_grid[logical_row, logical_column] + + if obj in groups_grids: + # This is a group. Copy the corresponding grid in + # place. + local_grid = groups_grids[obj] + for i in range(local_grid.height): + for j in range(local_grid.width): + grid[real_row + i, + real_column + j] = local_grid[i, j] + else: + # This is an object. Just put it there. + grid[real_row, real_column] = obj + + real_column += column_widths[logical_column] + real_column = 0 + real_row += row_heights[logical_row] + + return grid + + @staticmethod + def _generic_layout(diagram, merged_morphisms): + """ + Produces the generic layout for the supplied diagram. + """ + all_objects = set(diagram.objects) + if len(all_objects) == 1: + # There only one object in the diagram, just put in on 1x1 + # grid. + grid = _GrowableGrid(1, 1) + grid[0, 0] = tuple(all_objects)[0] + return grid + + skeleton = DiagramGrid._build_skeleton(merged_morphisms) + + grid = _GrowableGrid(2, 1) + + if len(skeleton) == 1: + # This diagram contains only one morphism. Draw it + # horizontally. + objects = sorted(all_objects, key=default_sort_key) + grid[0, 0] = objects[0] + grid[0, 1] = objects[1] + + return grid + + triangles = DiagramGrid._list_triangles(skeleton) + triangles = DiagramGrid._drop_redundant_triangles(triangles, skeleton) + triangle_sizes = DiagramGrid._compute_triangle_min_sizes( + triangles, skeleton) + + triangles = sorted(triangles, key=lambda tri: + DiagramGrid._triangle_key(tri, triangle_sizes)) + + # Place the first edge on the grid. + root_edge = DiagramGrid._pick_root_edge(triangles[0], skeleton) + grid[0, 0], grid[0, 1] = root_edge + fringe = [((0, 0), (0, 1))] + + # Record which objects we now have on the grid. + placed_objects = set(root_edge) + + while placed_objects != all_objects: + welding = DiagramGrid._find_triangle_to_weld( + triangles, fringe, grid) + + if welding: + (triangle, welding_edge) = welding + + restart_required = DiagramGrid._weld_triangle( + triangle, welding_edge, fringe, grid, skeleton) + if restart_required: + continue + + placed_objects.update( + DiagramGrid._triangle_objects(triangle)) + else: + # No more weldings found. Try to attach triangles by + # vertices. + new_obj = DiagramGrid._grow_pseudopod( + triangles, fringe, grid, skeleton, placed_objects) + + if not new_obj: + # No more triangles can be attached, not even by + # the edge. We will set up a new diagram out of + # what has been left, laid it out independently, + # and then attach it to this one. + + remaining_objects = all_objects - placed_objects + + remaining_diagram = diagram.subdiagram_from_objects( + FiniteSet(*remaining_objects)) + remaining_grid = DiagramGrid(remaining_diagram) + + # Now, let's glue ``remaining_grid`` to ``grid``. + final_width = grid.width + remaining_grid.width + final_height = max(grid.height, remaining_grid.height) + final_grid = _GrowableGrid(final_width, final_height) + + for i in range(grid.width): + for j in range(grid.height): + final_grid[i, j] = grid[i, j] + + start_j = grid.width + for i in range(remaining_grid.height): + for j in range(remaining_grid.width): + final_grid[i, start_j + j] = remaining_grid[i, j] + + return final_grid + + placed_objects.add(new_obj) + + triangles = DiagramGrid._drop_irrelevant_triangles( + triangles, placed_objects) + + return grid + + @staticmethod + def _get_undirected_graph(objects, merged_morphisms): + """ + Given the objects and the relevant morphisms of a diagram, + returns the adjacency lists of the underlying undirected + graph. + """ + adjlists = {obj: [] for obj in objects} + + for morphism in merged_morphisms: + adjlists[morphism.domain].append(morphism.codomain) + adjlists[morphism.codomain].append(morphism.domain) + + # Assure that the objects in the adjacency list are always in + # the same order. + for obj in adjlists.keys(): + adjlists[obj].sort(key=default_sort_key) + + return adjlists + + @staticmethod + def _sequential_layout(diagram, merged_morphisms): + r""" + Lays out the diagram in "sequential" layout. This method + will attempt to produce a result as close to a line as + possible. For linear diagrams, the result will actually be a + line. + """ + objects = diagram.objects + sorted_objects = sorted(objects, key=default_sort_key) + + # Set up the adjacency lists of the underlying undirected + # graph of ``merged_morphisms``. + adjlists = DiagramGrid._get_undirected_graph(objects, merged_morphisms) + + root = min(sorted_objects, key=lambda x: len(adjlists[x])) + grid = _GrowableGrid(1, 1) + grid[0, 0] = root + + placed_objects = {root} + + def place_objects(pt, placed_objects): + """ + Does depth-first search in the underlying graph of the + diagram and places the objects en route. + """ + # We will start placing new objects from here. + new_pt = (pt[0], pt[1] + 1) + + for adjacent_obj in adjlists[grid[pt]]: + if adjacent_obj in placed_objects: + # This object has already been placed. + continue + + DiagramGrid._put_object(new_pt, adjacent_obj, grid, []) + placed_objects.add(adjacent_obj) + placed_objects.update(place_objects(new_pt, placed_objects)) + + new_pt = (new_pt[0] + 1, new_pt[1]) + + return placed_objects + + place_objects((0, 0), placed_objects) + + return grid + + @staticmethod + def _drop_inessential_morphisms(merged_morphisms): + r""" + Removes those morphisms which should appear in the diagram, + but which have no relevance to object layout. + + Currently this removes "loop" morphisms: the non-identity + morphisms with the same domains and codomains. + """ + morphisms = [m for m in merged_morphisms if m.domain != m.codomain] + return morphisms + + @staticmethod + def _get_connected_components(objects, merged_morphisms): + """ + Given a container of morphisms, returns a list of connected + components formed by these morphisms. A connected component + is represented by a diagram consisting of the corresponding + morphisms. + """ + component_index = {} + for o in objects: + component_index[o] = None + + # Get the underlying undirected graph of the diagram. + adjlist = DiagramGrid._get_undirected_graph(objects, merged_morphisms) + + def traverse_component(object, current_index): + """ + Does a depth-first search traversal of the component + containing ``object``. + """ + component_index[object] = current_index + for o in adjlist[object]: + if component_index[o] is None: + traverse_component(o, current_index) + + # Traverse all components. + current_index = 0 + for o in adjlist: + if component_index[o] is None: + traverse_component(o, current_index) + current_index += 1 + + # List the objects of the components. + component_objects = [[] for i in range(current_index)] + for o, idx in component_index.items(): + component_objects[idx].append(o) + + # Finally, list the morphisms belonging to each component. + # + # Note: If some objects are isolated, they will not get any + # morphisms at this stage, and since the layout algorithm + # relies, we are essentially going to lose this object. + # Therefore, check if there are isolated objects and, for each + # of them, provide the trivial identity morphism. It will get + # discarded later, but the object will be there. + + component_morphisms = [] + for component in component_objects: + current_morphisms = {} + for m in merged_morphisms: + if (m.domain in component) and (m.codomain in component): + current_morphisms[m] = merged_morphisms[m] + + if len(component) == 1: + # Let's add an identity morphism, for the sake of + # surely having morphisms in this component. + current_morphisms[IdentityMorphism(component[0])] = FiniteSet() + + component_morphisms.append(Diagram(current_morphisms)) + + return component_morphisms + + def __init__(self, diagram, groups=None, **hints): + premises = DiagramGrid._simplify_morphisms(diagram.premises) + conclusions = DiagramGrid._simplify_morphisms(diagram.conclusions) + all_merged_morphisms = DiagramGrid._merge_premises_conclusions( + premises, conclusions) + merged_morphisms = DiagramGrid._drop_inessential_morphisms( + all_merged_morphisms) + + # Store the merged morphisms for later use. + self._morphisms = all_merged_morphisms + + components = DiagramGrid._get_connected_components( + diagram.objects, all_merged_morphisms) + + if groups and (groups != diagram.objects): + # Lay out the diagram according to the groups. + self._grid = DiagramGrid._handle_groups( + diagram, groups, merged_morphisms, hints) + elif len(components) > 1: + # Note that we check for connectedness _before_ checking + # the layout hints because the layout strategies don't + # know how to deal with disconnected diagrams. + + # The diagram is disconnected. Lay out the components + # independently. + grids = [] + + # Sort the components to eventually get the grids arranged + # in a fixed, hash-independent order. + components = sorted(components, key=default_sort_key) + + for component in components: + grid = DiagramGrid(component, **hints) + grids.append(grid) + + # Throw the grids together, in a line. + total_width = sum(g.width for g in grids) + total_height = max(g.height for g in grids) + + grid = _GrowableGrid(total_width, total_height) + start_j = 0 + for g in grids: + for i in range(g.height): + for j in range(g.width): + grid[i, start_j + j] = g[i, j] + + start_j += g.width + + self._grid = grid + elif "layout" in hints: + if hints["layout"] == "sequential": + self._grid = DiagramGrid._sequential_layout( + diagram, merged_morphisms) + else: + self._grid = DiagramGrid._generic_layout(diagram, merged_morphisms) + + if hints.get("transpose"): + # Transpose the resulting grid. + grid = _GrowableGrid(self._grid.height, self._grid.width) + for i in range(self._grid.height): + for j in range(self._grid.width): + grid[j, i] = self._grid[i, j] + self._grid = grid + + @property + def width(self): + """ + Returns the number of columns in this diagram layout. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import Diagram, DiagramGrid + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g]) + >>> grid = DiagramGrid(diagram) + >>> grid.width + 2 + + """ + return self._grid.width + + @property + def height(self): + """ + Returns the number of rows in this diagram layout. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import Diagram, DiagramGrid + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g]) + >>> grid = DiagramGrid(diagram) + >>> grid.height + 2 + + """ + return self._grid.height + + def __getitem__(self, i_j): + """ + Returns the object placed in the row ``i`` and column ``j``. + The indices are 0-based. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import Diagram, DiagramGrid + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g]) + >>> grid = DiagramGrid(diagram) + >>> (grid[0, 0], grid[0, 1]) + (Object("A"), Object("B")) + >>> (grid[1, 0], grid[1, 1]) + (None, Object("C")) + + """ + i, j = i_j + return self._grid[i, j] + + @property + def morphisms(self): + """ + Returns those morphisms (and their properties) which are + sufficiently meaningful to be drawn. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import Diagram, DiagramGrid + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g]) + >>> grid = DiagramGrid(diagram) + >>> grid.morphisms + {NamedMorphism(Object("A"), Object("B"), "f"): EmptySet, + NamedMorphism(Object("B"), Object("C"), "g"): EmptySet} + + """ + return self._morphisms + + def __str__(self): + """ + Produces a string representation of this class. + + This method returns a string representation of the underlying + list of lists of objects. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism + >>> from sympy.categories import Diagram, DiagramGrid + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g]) + >>> grid = DiagramGrid(diagram) + >>> print(grid) + [[Object("A"), Object("B")], + [None, Object("C")]] + + """ + return repr(self._grid._array) + + +class ArrowStringDescription: + r""" + Stores the information necessary for producing an Xy-pic + description of an arrow. + + The principal goal of this class is to abstract away the string + representation of an arrow and to also provide the functionality + to produce the actual Xy-pic string. + + ``unit`` sets the unit which will be used to specify the amount of + curving and other distances. ``horizontal_direction`` should be a + string of ``"r"`` or ``"l"`` specifying the horizontal offset of the + target cell of the arrow relatively to the current one. + ``vertical_direction`` should specify the vertical offset using a + series of either ``"d"`` or ``"u"``. ``label_position`` should be + either ``"^"``, ``"_"``, or ``"|"`` to specify that the label should + be positioned above the arrow, below the arrow or just over the arrow, + in a break. Note that the notions "above" and "below" are relative + to arrow direction. ``label`` stores the morphism label. + + This works as follows (disregard the yet unexplained arguments): + + >>> from sympy.categories.diagram_drawing import ArrowStringDescription + >>> astr = ArrowStringDescription( + ... unit="mm", curving=None, curving_amount=None, + ... looping_start=None, looping_end=None, horizontal_direction="d", + ... vertical_direction="r", label_position="_", label="f") + >>> print(str(astr)) + \ar[dr]_{f} + + ``curving`` should be one of ``"^"``, ``"_"`` to specify in which + direction the arrow is going to curve. ``curving_amount`` is a number + describing how many ``unit``'s the morphism is going to curve: + + >>> astr = ArrowStringDescription( + ... unit="mm", curving="^", curving_amount=12, + ... looping_start=None, looping_end=None, horizontal_direction="d", + ... vertical_direction="r", label_position="_", label="f") + >>> print(str(astr)) + \ar@/^12mm/[dr]_{f} + + ``looping_start`` and ``looping_end`` are currently only used for + loop morphisms, those which have the same domain and codomain. + These two attributes should store a valid Xy-pic direction and + specify, correspondingly, the direction the arrow gets out into + and the direction the arrow gets back from: + + >>> astr = ArrowStringDescription( + ... unit="mm", curving=None, curving_amount=None, + ... looping_start="u", looping_end="l", horizontal_direction="", + ... vertical_direction="", label_position="_", label="f") + >>> print(str(astr)) + \ar@(u,l)[]_{f} + + ``label_displacement`` controls how far the arrow label is from + the ends of the arrow. For example, to position the arrow label + near the arrow head, use ">": + + >>> astr = ArrowStringDescription( + ... unit="mm", curving="^", curving_amount=12, + ... looping_start=None, looping_end=None, horizontal_direction="d", + ... vertical_direction="r", label_position="_", label="f") + >>> astr.label_displacement = ">" + >>> print(str(astr)) + \ar@/^12mm/[dr]_>{f} + + Finally, ``arrow_style`` is used to specify the arrow style. To + get a dashed arrow, for example, use "{-->}" as arrow style: + + >>> astr = ArrowStringDescription( + ... unit="mm", curving="^", curving_amount=12, + ... looping_start=None, looping_end=None, horizontal_direction="d", + ... vertical_direction="r", label_position="_", label="f") + >>> astr.arrow_style = "{-->}" + >>> print(str(astr)) + \ar@/^12mm/@{-->}[dr]_{f} + + Notes + ===== + + Instances of :class:`ArrowStringDescription` will be constructed + by :class:`XypicDiagramDrawer` and provided for further use in + formatters. The user is not expected to construct instances of + :class:`ArrowStringDescription` themselves. + + To be able to properly utilise this class, the reader is encouraged + to checkout the Xy-pic user guide, available at [Xypic]. + + See Also + ======== + + XypicDiagramDrawer + + References + ========== + + .. [Xypic] https://xy-pic.sourceforge.net/ + """ + def __init__(self, unit, curving, curving_amount, looping_start, + looping_end, horizontal_direction, vertical_direction, + label_position, label): + self.unit = unit + self.curving = curving + self.curving_amount = curving_amount + self.looping_start = looping_start + self.looping_end = looping_end + self.horizontal_direction = horizontal_direction + self.vertical_direction = vertical_direction + self.label_position = label_position + self.label = label + + self.label_displacement = "" + self.arrow_style = "" + + # This flag shows that the position of the label of this + # morphism was set while typesetting a curved morphism and + # should not be modified later. + self.forced_label_position = False + + def __str__(self): + if self.curving: + curving_str = "@/%s%d%s/" % (self.curving, self.curving_amount, + self.unit) + else: + curving_str = "" + + if self.looping_start and self.looping_end: + looping_str = "@(%s,%s)" % (self.looping_start, self.looping_end) + else: + looping_str = "" + + if self.arrow_style: + + style_str = "@" + self.arrow_style + else: + style_str = "" + + return "\\ar%s%s%s[%s%s]%s%s{%s}" % \ + (curving_str, looping_str, style_str, self.horizontal_direction, + self.vertical_direction, self.label_position, + self.label_displacement, self.label) + + +class XypicDiagramDrawer: + r""" + Given a :class:`~.Diagram` and the corresponding + :class:`DiagramGrid`, produces the Xy-pic representation of the + diagram. + + The most important method in this class is ``draw``. Consider the + following triangle diagram: + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy.categories import DiagramGrid, XypicDiagramDrawer + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g], {g * f: "unique"}) + + To draw this diagram, its objects need to be laid out with a + :class:`DiagramGrid`:: + + >>> grid = DiagramGrid(diagram) + + Finally, the drawing: + + >>> drawer = XypicDiagramDrawer() + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + For further details see the docstring of this method. + + To control the appearance of the arrows, formatters are used. The + dictionary ``arrow_formatters`` maps morphisms to formatter + functions. A formatter is accepts an + :class:`ArrowStringDescription` and is allowed to modify any of + the arrow properties exposed thereby. For example, to have all + morphisms with the property ``unique`` appear as dashed arrows, + and to have their names prepended with `\exists !`, the following + should be done: + + >>> def formatter(astr): + ... astr.label = r"\exists !" + astr.label + ... astr.arrow_style = "{-->}" + >>> drawer.arrow_formatters["unique"] = formatter + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar@{-->}[d]_{\exists !g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + To modify the appearance of all arrows in the diagram, set + ``default_arrow_formatter``. For example, to place all morphism + labels a little bit farther from the arrow head so that they look + more centred, do as follows: + + >>> def default_formatter(astr): + ... astr.label_displacement = "(0.45)" + >>> drawer.default_arrow_formatter = default_formatter + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar@{-->}[d]_(0.45){\exists !g\circ f} \ar[r]^(0.45){f} & B \ar[ld]^(0.45){g} \\ + C & + } + + In some diagrams some morphisms are drawn as curved arrows. + Consider the following diagram: + + >>> D = Object("D") + >>> E = Object("E") + >>> h = NamedMorphism(D, A, "h") + >>> k = NamedMorphism(D, B, "k") + >>> diagram = Diagram([f, g, h, k]) + >>> grid = DiagramGrid(diagram) + >>> drawer = XypicDiagramDrawer() + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_3mm/[ll]_{h} \\ + & C & + } + + To control how far the morphisms are curved by default, one can + use the ``unit`` and ``default_curving_amount`` attributes: + + >>> drawer.unit = "cm" + >>> drawer.default_curving_amount = 1 + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_1cm/[ll]_{h} \\ + & C & + } + + In some diagrams, there are multiple curved morphisms between the + same two objects. To control by how much the curving changes + between two such successive morphisms, use + ``default_curving_step``: + + >>> drawer.default_curving_step = 1 + >>> h1 = NamedMorphism(A, D, "h1") + >>> diagram = Diagram([f, g, h, k, h1]) + >>> grid = DiagramGrid(diagram) + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[r]_{f} \ar@/^1cm/[rr]^{h_{1}} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_2cm/[ll]_{h} \\ + & C & + } + + The default value of ``default_curving_step`` is 4 units. + + See Also + ======== + + draw, ArrowStringDescription + """ + def __init__(self): + self.unit = "mm" + self.default_curving_amount = 3 + self.default_curving_step = 4 + + # This dictionary maps properties to the corresponding arrow + # formatters. + self.arrow_formatters = {} + + # This is the default arrow formatter which will be applied to + # each arrow independently of its properties. + self.default_arrow_formatter = None + + @staticmethod + def _process_loop_morphism(i, j, grid, morphisms_str_info, object_coords): + """ + Produces the information required for constructing the string + representation of a loop morphism. This function is invoked + from ``_process_morphism``. + + See Also + ======== + + _process_morphism + """ + curving = "" + label_pos = "^" + looping_start = "" + looping_end = "" + + # This is a loop morphism. Count how many morphisms stick + # in each of the four quadrants. Note that straight + # vertical and horizontal morphisms count in two quadrants + # at the same time (i.e., a morphism going up counts both + # in the first and the second quadrants). + + # The usual numbering (counterclockwise) of quadrants + # applies. + quadrant = [0, 0, 0, 0] + + obj = grid[i, j] + + for m, m_str_info in morphisms_str_info.items(): + if (m.domain == obj) and (m.codomain == obj): + # That's another loop morphism. Check how it + # loops and mark the corresponding quadrants as + # busy. + (l_s, l_e) = (m_str_info.looping_start, m_str_info.looping_end) + + if (l_s, l_e) == ("r", "u"): + quadrant[0] += 1 + elif (l_s, l_e) == ("u", "l"): + quadrant[1] += 1 + elif (l_s, l_e) == ("l", "d"): + quadrant[2] += 1 + elif (l_s, l_e) == ("d", "r"): + quadrant[3] += 1 + + continue + if m.domain == obj: + (end_i, end_j) = object_coords[m.codomain] + goes_out = True + elif m.codomain == obj: + (end_i, end_j) = object_coords[m.domain] + goes_out = False + else: + continue + + d_i = end_i - i + d_j = end_j - j + m_curving = m_str_info.curving + + if (d_i != 0) and (d_j != 0): + # This is really a diagonal morphism. Detect the + # quadrant. + if (d_i > 0) and (d_j > 0): + quadrant[0] += 1 + elif (d_i > 0) and (d_j < 0): + quadrant[1] += 1 + elif (d_i < 0) and (d_j < 0): + quadrant[2] += 1 + elif (d_i < 0) and (d_j > 0): + quadrant[3] += 1 + elif d_i == 0: + # Knowing where the other end of the morphism is + # and which way it goes, we now have to decide + # which quadrant is now the upper one and which is + # the lower one. + if d_j > 0: + if goes_out: + upper_quadrant = 0 + lower_quadrant = 3 + else: + upper_quadrant = 3 + lower_quadrant = 0 + else: + if goes_out: + upper_quadrant = 2 + lower_quadrant = 1 + else: + upper_quadrant = 1 + lower_quadrant = 2 + + if m_curving: + if m_curving == "^": + quadrant[upper_quadrant] += 1 + elif m_curving == "_": + quadrant[lower_quadrant] += 1 + else: + # This morphism counts in both upper and lower + # quadrants. + quadrant[upper_quadrant] += 1 + quadrant[lower_quadrant] += 1 + elif d_j == 0: + # Knowing where the other end of the morphism is + # and which way it goes, we now have to decide + # which quadrant is now the left one and which is + # the right one. + if d_i < 0: + if goes_out: + left_quadrant = 1 + right_quadrant = 0 + else: + left_quadrant = 0 + right_quadrant = 1 + else: + if goes_out: + left_quadrant = 3 + right_quadrant = 2 + else: + left_quadrant = 2 + right_quadrant = 3 + + if m_curving: + if m_curving == "^": + quadrant[left_quadrant] += 1 + elif m_curving == "_": + quadrant[right_quadrant] += 1 + else: + # This morphism counts in both upper and lower + # quadrants. + quadrant[left_quadrant] += 1 + quadrant[right_quadrant] += 1 + + # Pick the freest quadrant to curve our morphism into. + freest_quadrant = 0 + for i in range(4): + if quadrant[i] < quadrant[freest_quadrant]: + freest_quadrant = i + + # Now set up proper looping. + (looping_start, looping_end) = [("r", "u"), ("u", "l"), ("l", "d"), + ("d", "r")][freest_quadrant] + + return (curving, label_pos, looping_start, looping_end) + + @staticmethod + def _process_horizontal_morphism(i, j, target_j, grid, morphisms_str_info, + object_coords): + """ + Produces the information required for constructing the string + representation of a horizontal morphism. This function is + invoked from ``_process_morphism``. + + See Also + ======== + + _process_morphism + """ + # The arrow is horizontal. Check if it goes from left to + # right (``backwards == False``) or from right to left + # (``backwards == True``). + backwards = False + start = j + end = target_j + if end < start: + (start, end) = (end, start) + backwards = True + + # Let's see which objects are there between ``start`` and + # ``end``, and then count how many morphisms stick out + # upwards, and how many stick out downwards. + # + # For example, consider the situation: + # + # B1 C1 + # | | + # A--B--C--D + # | + # B2 + # + # Between the objects `A` and `D` there are two objects: + # `B` and `C`. Further, there are two morphisms which + # stick out upward (the ones between `B1` and `B` and + # between `C` and `C1`) and one morphism which sticks out + # downward (the one between `B and `B2`). + # + # We need this information to decide how to curve the + # arrow between `A` and `D`. First of all, since there + # are two objects between `A` and `D``, we must curve the + # arrow. Then, we will have it curve downward, because + # there is more space (less morphisms stick out downward + # than upward). + up = [] + down = [] + straight_horizontal = [] + for k in range(start + 1, end): + obj = grid[i, k] + if not obj: + continue + + for m in morphisms_str_info: + if m.domain == obj: + (end_i, end_j) = object_coords[m.codomain] + elif m.codomain == obj: + (end_i, end_j) = object_coords[m.domain] + else: + continue + + if end_i > i: + down.append(m) + elif end_i < i: + up.append(m) + elif not morphisms_str_info[m].curving: + # This is a straight horizontal morphism, + # because it has no curving. + straight_horizontal.append(m) + + if len(up) < len(down): + # More morphisms stick out downward than upward, let's + # curve the morphism up. + if backwards: + curving = "_" + label_pos = "_" + else: + curving = "^" + label_pos = "^" + + # Assure that the straight horizontal morphisms have + # their labels on the lower side of the arrow. + for m in straight_horizontal: + (i1, j1) = object_coords[m.domain] + (i2, j2) = object_coords[m.codomain] + + m_str_info = morphisms_str_info[m] + if j1 < j2: + m_str_info.label_position = "_" + else: + m_str_info.label_position = "^" + + # Don't allow any further modifications of the + # position of this label. + m_str_info.forced_label_position = True + else: + # More morphisms stick out downward than upward, let's + # curve the morphism up. + if backwards: + curving = "^" + label_pos = "^" + else: + curving = "_" + label_pos = "_" + + # Assure that the straight horizontal morphisms have + # their labels on the upper side of the arrow. + for m in straight_horizontal: + (i1, j1) = object_coords[m.domain] + (i2, j2) = object_coords[m.codomain] + + m_str_info = morphisms_str_info[m] + if j1 < j2: + m_str_info.label_position = "^" + else: + m_str_info.label_position = "_" + + # Don't allow any further modifications of the + # position of this label. + m_str_info.forced_label_position = True + + return (curving, label_pos) + + @staticmethod + def _process_vertical_morphism(i, j, target_i, grid, morphisms_str_info, + object_coords): + """ + Produces the information required for constructing the string + representation of a vertical morphism. This function is + invoked from ``_process_morphism``. + + See Also + ======== + + _process_morphism + """ + # This arrow is vertical. Check if it goes from top to + # bottom (``backwards == False``) or from bottom to top + # (``backwards == True``). + backwards = False + start = i + end = target_i + if end < start: + (start, end) = (end, start) + backwards = True + + # Let's see which objects are there between ``start`` and + # ``end``, and then count how many morphisms stick out to + # the left, and how many stick out to the right. + # + # See the corresponding comment in the previous branch of + # this if-statement for more details. + left = [] + right = [] + straight_vertical = [] + for k in range(start + 1, end): + obj = grid[k, j] + if not obj: + continue + + for m in morphisms_str_info: + if m.domain == obj: + (end_i, end_j) = object_coords[m.codomain] + elif m.codomain == obj: + (end_i, end_j) = object_coords[m.domain] + else: + continue + + if end_j > j: + right.append(m) + elif end_j < j: + left.append(m) + elif not morphisms_str_info[m].curving: + # This is a straight vertical morphism, + # because it has no curving. + straight_vertical.append(m) + + if len(left) < len(right): + # More morphisms stick out to the left than to the + # right, let's curve the morphism to the right. + if backwards: + curving = "^" + label_pos = "^" + else: + curving = "_" + label_pos = "_" + + # Assure that the straight vertical morphisms have + # their labels on the left side of the arrow. + for m in straight_vertical: + (i1, j1) = object_coords[m.domain] + (i2, j2) = object_coords[m.codomain] + + m_str_info = morphisms_str_info[m] + if i1 < i2: + m_str_info.label_position = "^" + else: + m_str_info.label_position = "_" + + # Don't allow any further modifications of the + # position of this label. + m_str_info.forced_label_position = True + else: + # More morphisms stick out to the right than to the + # left, let's curve the morphism to the left. + if backwards: + curving = "_" + label_pos = "_" + else: + curving = "^" + label_pos = "^" + + # Assure that the straight vertical morphisms have + # their labels on the right side of the arrow. + for m in straight_vertical: + (i1, j1) = object_coords[m.domain] + (i2, j2) = object_coords[m.codomain] + + m_str_info = morphisms_str_info[m] + if i1 < i2: + m_str_info.label_position = "_" + else: + m_str_info.label_position = "^" + + # Don't allow any further modifications of the + # position of this label. + m_str_info.forced_label_position = True + + return (curving, label_pos) + + def _process_morphism(self, diagram, grid, morphism, object_coords, + morphisms, morphisms_str_info): + """ + Given the required information, produces the string + representation of ``morphism``. + """ + def repeat_string_cond(times, str_gt, str_lt): + """ + If ``times > 0``, repeats ``str_gt`` ``times`` times. + Otherwise, repeats ``str_lt`` ``-times`` times. + """ + if times > 0: + return str_gt * times + else: + return str_lt * (-times) + + def count_morphisms_undirected(A, B): + """ + Counts how many processed morphisms there are between the + two supplied objects. + """ + return len([m for m in morphisms_str_info + if {m.domain, m.codomain} == {A, B}]) + + def count_morphisms_filtered(dom, cod, curving): + """ + Counts the processed morphisms which go out of ``dom`` + into ``cod`` with curving ``curving``. + """ + return len([m for m, m_str_info in morphisms_str_info.items() + if (m.domain, m.codomain) == (dom, cod) and + (m_str_info.curving == curving)]) + + (i, j) = object_coords[morphism.domain] + (target_i, target_j) = object_coords[morphism.codomain] + + # We now need to determine the direction of + # the arrow. + delta_i = target_i - i + delta_j = target_j - j + vertical_direction = repeat_string_cond(delta_i, + "d", "u") + horizontal_direction = repeat_string_cond(delta_j, + "r", "l") + + curving = "" + label_pos = "^" + looping_start = "" + looping_end = "" + + if (delta_i == 0) and (delta_j == 0): + # This is a loop morphism. + (curving, label_pos, looping_start, + looping_end) = XypicDiagramDrawer._process_loop_morphism( + i, j, grid, morphisms_str_info, object_coords) + elif (delta_i == 0) and (abs(j - target_j) > 1): + # This is a horizontal morphism. + (curving, label_pos) = XypicDiagramDrawer._process_horizontal_morphism( + i, j, target_j, grid, morphisms_str_info, object_coords) + elif (delta_j == 0) and (abs(i - target_i) > 1): + # This is a vertical morphism. + (curving, label_pos) = XypicDiagramDrawer._process_vertical_morphism( + i, j, target_i, grid, morphisms_str_info, object_coords) + + count = count_morphisms_undirected(morphism.domain, morphism.codomain) + curving_amount = "" + if curving: + # This morphisms should be curved anyway. + curving_amount = self.default_curving_amount + count * \ + self.default_curving_step + elif count: + # There are no objects between the domain and codomain of + # the current morphism, but this is not there already are + # some morphisms with the same domain and codomain, so we + # have to curve this one. + curving = "^" + filtered_morphisms = count_morphisms_filtered( + morphism.domain, morphism.codomain, curving) + curving_amount = self.default_curving_amount + \ + filtered_morphisms * \ + self.default_curving_step + + # Let's now get the name of the morphism. + morphism_name = "" + if isinstance(morphism, IdentityMorphism): + morphism_name = "id_{%s}" + latex(grid[i, j]) + elif isinstance(morphism, CompositeMorphism): + component_names = [latex(Symbol(component.name)) for + component in morphism.components] + component_names.reverse() + morphism_name = "\\circ ".join(component_names) + elif isinstance(morphism, NamedMorphism): + morphism_name = latex(Symbol(morphism.name)) + + return ArrowStringDescription( + self.unit, curving, curving_amount, looping_start, + looping_end, horizontal_direction, vertical_direction, + label_pos, morphism_name) + + @staticmethod + def _check_free_space_horizontal(dom_i, dom_j, cod_j, grid): + """ + For a horizontal morphism, checks whether there is free space + (i.e., space not occupied by any objects) above the morphism + or below it. + """ + if dom_j < cod_j: + (start, end) = (dom_j, cod_j) + backwards = False + else: + (start, end) = (cod_j, dom_j) + backwards = True + + # Check for free space above. + if dom_i == 0: + free_up = True + else: + free_up = all(grid[dom_i - 1, j] for j in + range(start, end + 1)) + + # Check for free space below. + if dom_i == grid.height - 1: + free_down = True + else: + free_down = not any(grid[dom_i + 1, j] for j in + range(start, end + 1)) + + return (free_up, free_down, backwards) + + @staticmethod + def _check_free_space_vertical(dom_i, cod_i, dom_j, grid): + """ + For a vertical morphism, checks whether there is free space + (i.e., space not occupied by any objects) to the left of the + morphism or to the right of it. + """ + if dom_i < cod_i: + (start, end) = (dom_i, cod_i) + backwards = False + else: + (start, end) = (cod_i, dom_i) + backwards = True + + # Check if there's space to the left. + if dom_j == 0: + free_left = True + else: + free_left = not any(grid[i, dom_j - 1] for i in + range(start, end + 1)) + + if dom_j == grid.width - 1: + free_right = True + else: + free_right = not any(grid[i, dom_j + 1] for i in + range(start, end + 1)) + + return (free_left, free_right, backwards) + + @staticmethod + def _check_free_space_diagonal(dom_i, cod_i, dom_j, cod_j, grid): + """ + For a diagonal morphism, checks whether there is free space + (i.e., space not occupied by any objects) above the morphism + or below it. + """ + def abs_xrange(start, end): + if start < end: + return range(start, end + 1) + else: + return range(end, start + 1) + + if dom_i < cod_i and dom_j < cod_j: + # This morphism goes from top-left to + # bottom-right. + (start_i, start_j) = (dom_i, dom_j) + (end_i, end_j) = (cod_i, cod_j) + backwards = False + elif dom_i > cod_i and dom_j > cod_j: + # This morphism goes from bottom-right to + # top-left. + (start_i, start_j) = (cod_i, cod_j) + (end_i, end_j) = (dom_i, dom_j) + backwards = True + if dom_i < cod_i and dom_j > cod_j: + # This morphism goes from top-right to + # bottom-left. + (start_i, start_j) = (dom_i, dom_j) + (end_i, end_j) = (cod_i, cod_j) + backwards = True + elif dom_i > cod_i and dom_j < cod_j: + # This morphism goes from bottom-left to + # top-right. + (start_i, start_j) = (cod_i, cod_j) + (end_i, end_j) = (dom_i, dom_j) + backwards = False + + # This is an attempt at a fast and furious strategy to + # decide where there is free space on the two sides of + # a diagonal morphism. For a diagonal morphism + # starting at ``(start_i, start_j)`` and ending at + # ``(end_i, end_j)`` the rectangle defined by these + # two points is considered. The slope of the diagonal + # ``alpha`` is then computed. Then, for every cell + # ``(i, j)`` within the rectangle, the slope + # ``alpha1`` of the line through ``(start_i, + # start_j)`` and ``(i, j)`` is considered. If + # ``alpha1`` is between 0 and ``alpha``, the point + # ``(i, j)`` is above the diagonal, if ``alpha1`` is + # between ``alpha`` and infinity, the point is below + # the diagonal. Also note that, with some beforehand + # precautions, this trick works for both the main and + # the secondary diagonals of the rectangle. + + # I have considered the possibility to only follow the + # shorter diagonals immediately above and below the + # main (or secondary) diagonal. This, however, + # wouldn't have resulted in much performance gain or + # better detection of outer edges, because of + # relatively small sizes of diagram grids, while the + # code would have become harder to understand. + + alpha = float(end_i - start_i)/(end_j - start_j) + free_up = True + free_down = True + for i in abs_xrange(start_i, end_i): + if not free_up and not free_down: + break + + for j in abs_xrange(start_j, end_j): + if not free_up and not free_down: + break + + if (i, j) == (start_i, start_j): + continue + + if j == start_j: + alpha1 = "inf" + else: + alpha1 = float(i - start_i)/(j - start_j) + + if grid[i, j]: + if (alpha1 == "inf") or (abs(alpha1) > abs(alpha)): + free_down = False + elif abs(alpha1) < abs(alpha): + free_up = False + + return (free_up, free_down, backwards) + + def _push_labels_out(self, morphisms_str_info, grid, object_coords): + """ + For all straight morphisms which form the visual boundary of + the laid out diagram, puts their labels on their outer sides. + """ + def set_label_position(free1, free2, pos1, pos2, backwards, m_str_info): + """ + Given the information about room available to one side and + to the other side of a morphism (``free1`` and ``free2``), + sets the position of the morphism label in such a way that + it is on the freer side. This latter operations involves + choice between ``pos1`` and ``pos2``, taking ``backwards`` + in consideration. + + Thus this function will do nothing if either both ``free1 + == True`` and ``free2 == True`` or both ``free1 == False`` + and ``free2 == False``. In either case, choosing one side + over the other presents no advantage. + """ + if backwards: + (pos1, pos2) = (pos2, pos1) + + if free1 and not free2: + m_str_info.label_position = pos1 + elif free2 and not free1: + m_str_info.label_position = pos2 + + for m, m_str_info in morphisms_str_info.items(): + if m_str_info.curving or m_str_info.forced_label_position: + # This is either a curved morphism, and curved + # morphisms have other magic, or the position of this + # label has already been fixed. + continue + + if m.domain == m.codomain: + # This is a loop morphism, their labels, again have a + # different magic. + continue + + (dom_i, dom_j) = object_coords[m.domain] + (cod_i, cod_j) = object_coords[m.codomain] + + if dom_i == cod_i: + # Horizontal morphism. + (free_up, free_down, + backwards) = XypicDiagramDrawer._check_free_space_horizontal( + dom_i, dom_j, cod_j, grid) + + set_label_position(free_up, free_down, "^", "_", + backwards, m_str_info) + elif dom_j == cod_j: + # Vertical morphism. + (free_left, free_right, + backwards) = XypicDiagramDrawer._check_free_space_vertical( + dom_i, cod_i, dom_j, grid) + + set_label_position(free_left, free_right, "_", "^", + backwards, m_str_info) + else: + # A diagonal morphism. + (free_up, free_down, + backwards) = XypicDiagramDrawer._check_free_space_diagonal( + dom_i, cod_i, dom_j, cod_j, grid) + + set_label_position(free_up, free_down, "^", "_", + backwards, m_str_info) + + @staticmethod + def _morphism_sort_key(morphism, object_coords): + """ + Provides a morphism sorting key such that horizontal or + vertical morphisms between neighbouring objects come + first, then horizontal or vertical morphisms between more + far away objects, and finally, all other morphisms. + """ + (i, j) = object_coords[morphism.domain] + (target_i, target_j) = object_coords[morphism.codomain] + + if morphism.domain == morphism.codomain: + # Loop morphisms should get after diagonal morphisms + # so that the proper direction in which to curve the + # loop can be determined. + return (3, 0, default_sort_key(morphism)) + + if target_i == i: + return (1, abs(target_j - j), default_sort_key(morphism)) + + if target_j == j: + return (1, abs(target_i - i), default_sort_key(morphism)) + + # Diagonal morphism. + return (2, 0, default_sort_key(morphism)) + + @staticmethod + def _build_xypic_string(diagram, grid, morphisms, + morphisms_str_info, diagram_format): + """ + Given a collection of :class:`ArrowStringDescription` + describing the morphisms of a diagram and the object layout + information of a diagram, produces the final Xy-pic picture. + """ + # Build the mapping between objects and morphisms which have + # them as domains. + object_morphisms = {} + for obj in diagram.objects: + object_morphisms[obj] = [] + for morphism in morphisms: + object_morphisms[morphism.domain].append(morphism) + + result = "\\xymatrix%s{\n" % diagram_format + + for i in range(grid.height): + for j in range(grid.width): + obj = grid[i, j] + if obj: + result += latex(obj) + " " + + morphisms_to_draw = object_morphisms[obj] + for morphism in morphisms_to_draw: + result += str(morphisms_str_info[morphism]) + " " + + # Don't put the & after the last column. + if j < grid.width - 1: + result += "& " + + # Don't put the line break after the last row. + if i < grid.height - 1: + result += "\\\\" + result += "\n" + + result += "}\n" + + return result + + def draw(self, diagram, grid, masked=None, diagram_format=""): + r""" + Returns the Xy-pic representation of ``diagram`` laid out in + ``grid``. + + Consider the following simple triangle diagram. + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy.categories import DiagramGrid, XypicDiagramDrawer + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g], {g * f: "unique"}) + + To draw this diagram, its objects need to be laid out with a + :class:`DiagramGrid`:: + + >>> grid = DiagramGrid(diagram) + + Finally, the drawing: + + >>> drawer = XypicDiagramDrawer() + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + The argument ``masked`` can be used to skip morphisms in the + presentation of the diagram: + + >>> print(drawer.draw(diagram, grid, masked=[g * f])) + \xymatrix{ + A \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + Finally, the ``diagram_format`` argument can be used to + specify the format string of the diagram. For example, to + increase the spacing by 1 cm, proceeding as follows: + + >>> print(drawer.draw(diagram, grid, diagram_format="@+1cm")) + \xymatrix@+1cm{ + A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + """ + # This method works in several steps. It starts by removing + # the masked morphisms, if necessary, and then maps objects to + # their positions in the grid (coordinate tuples). Remember + # that objects are unique in ``Diagram`` and in the layout + # produced by ``DiagramGrid``, so every object is mapped to a + # single coordinate pair. + # + # The next step is the central step and is concerned with + # analysing the morphisms of the diagram and deciding how to + # draw them. For example, how to curve the arrows is decided + # at this step. The bulk of the analysis is implemented in + # ``_process_morphism``, to the result of which the + # appropriate formatters are applied. + # + # The result of the previous step is a list of + # ``ArrowStringDescription``. After the analysis and + # application of formatters, some extra logic tries to assure + # better positioning of morphism labels (for example, an + # attempt is made to avoid the situations when arrows cross + # labels). This functionality constitutes the next step and + # is implemented in ``_push_labels_out``. Note that label + # positions which have been set via a formatter are not + # affected in this step. + # + # Finally, at the closing step, the array of + # ``ArrowStringDescription`` and the layout information + # incorporated in ``DiagramGrid`` are combined to produce the + # resulting Xy-pic picture. This part of code lies in + # ``_build_xypic_string``. + + if not masked: + morphisms_props = grid.morphisms + else: + morphisms_props = {} + for m, props in grid.morphisms.items(): + if m in masked: + continue + morphisms_props[m] = props + + # Build the mapping between objects and their position in the + # grid. + object_coords = {} + for i in range(grid.height): + for j in range(grid.width): + if grid[i, j]: + object_coords[grid[i, j]] = (i, j) + + morphisms = sorted(morphisms_props, + key=lambda m: XypicDiagramDrawer._morphism_sort_key( + m, object_coords)) + + # Build the tuples defining the string representations of + # morphisms. + morphisms_str_info = {} + for morphism in morphisms: + string_description = self._process_morphism( + diagram, grid, morphism, object_coords, morphisms, + morphisms_str_info) + + if self.default_arrow_formatter: + self.default_arrow_formatter(string_description) + + for prop in morphisms_props[morphism]: + # prop is a Symbol. TODO: Find out why. + if prop.name in self.arrow_formatters: + formatter = self.arrow_formatters[prop.name] + formatter(string_description) + + morphisms_str_info[morphism] = string_description + + # Reposition the labels a bit. + self._push_labels_out(morphisms_str_info, grid, object_coords) + + return XypicDiagramDrawer._build_xypic_string( + diagram, grid, morphisms, morphisms_str_info, diagram_format) + + +def xypic_draw_diagram(diagram, masked=None, diagram_format="", + groups=None, **hints): + r""" + Provides a shortcut combining :class:`DiagramGrid` and + :class:`XypicDiagramDrawer`. Returns an Xy-pic presentation of + ``diagram``. The argument ``masked`` is a list of morphisms which + will be not be drawn. The argument ``diagram_format`` is the + format string inserted after "\xymatrix". ``groups`` should be a + set of logical groups. The ``hints`` will be passed directly to + the constructor of :class:`DiagramGrid`. + + For more information about the arguments, see the docstrings of + :class:`DiagramGrid` and ``XypicDiagramDrawer.draw``. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy.categories import xypic_draw_diagram + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g], {g * f: "unique"}) + >>> print(xypic_draw_diagram(diagram)) + \xymatrix{ + A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + See Also + ======== + + XypicDiagramDrawer, DiagramGrid + """ + grid = DiagramGrid(diagram, groups, **hints) + drawer = XypicDiagramDrawer() + return drawer.draw(diagram, grid, masked, diagram_format) + + +@doctest_depends_on(exe=('latex', 'dvipng'), modules=('pyglet',)) +def preview_diagram(diagram, masked=None, diagram_format="", groups=None, + output='png', viewer=None, euler=True, **hints): + """ + Combines the functionality of ``xypic_draw_diagram`` and + ``sympy.printing.preview``. The arguments ``masked``, + ``diagram_format``, ``groups``, and ``hints`` are passed to + ``xypic_draw_diagram``, while ``output``, ``viewer, and ``euler`` + are passed to ``preview``. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy.categories import preview_diagram + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g], {g * f: "unique"}) + >>> preview_diagram(d) + + See Also + ======== + + XypicDiagramDrawer + """ + from sympy.printing import preview + latex_output = xypic_draw_diagram(diagram, masked, diagram_format, + groups, **hints) + preview(latex_output, output, viewer, euler, ("xypic",)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..62b195633bae28371bdf9e79317050d7fa7125ae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__init__.py @@ -0,0 +1,24 @@ +""" The ``sympy.codegen`` module contains classes and functions for building +abstract syntax trees of algorithms. These trees may then be printed by the +code-printers in ``sympy.printing``. + +There are several submodules available: +- ``sympy.codegen.ast``: AST nodes useful across multiple languages. +- ``sympy.codegen.cnodes``: AST nodes useful for the C family of languages. +- ``sympy.codegen.fnodes``: AST nodes useful for Fortran. +- ``sympy.codegen.cfunctions``: functions specific to C (C99 math functions) +- ``sympy.codegen.ffunctions``: functions specific to Fortran (e.g. ``kind``). + + + +""" +from .ast import ( + Assignment, aug_assign, CodeBlock, For, Attribute, Variable, Declaration, + While, Scope, Print, FunctionPrototype, FunctionDefinition, FunctionCall +) + +__all__ = [ + 'Assignment', 'aug_assign', 'CodeBlock', 'For', 'Attribute', 'Variable', + 'Declaration', 'While', 'Scope', 'Print', 'FunctionPrototype', + 'FunctionDefinition', 'FunctionCall', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/abstract_nodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/abstract_nodes.py new file mode 100644 index 0000000000000000000000000000000000000000..ae0a8b3e996a7112edf2568c00138e11c3f3327d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/abstract_nodes.py @@ -0,0 +1,18 @@ +"""This module provides containers for python objects that are valid +printing targets but are not a subclass of SymPy's Printable. +""" + + +from sympy.core.containers import Tuple + + +class List(Tuple): + """Represents a (frozen) (Python) list (for code printing purposes).""" + def __eq__(self, other): + if isinstance(other, list): + return self == List(*other) + else: + return self.args == other + + def __hash__(self): + return super().__hash__() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/algorithms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/algorithms.py new file mode 100644 index 0000000000000000000000000000000000000000..f4890eb8c25e565095600e2713c0de270aa0cf97 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/algorithms.py @@ -0,0 +1,180 @@ +from sympy.core.containers import Tuple +from sympy.core.numbers import oo +from sympy.core.relational import (Gt, Lt) +from sympy.core.symbol import (Dummy, Symbol) +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.miscellaneous import Min, Max +from sympy.logic.boolalg import And +from sympy.codegen.ast import ( + Assignment, AddAugmentedAssignment, break_, CodeBlock, Declaration, FunctionDefinition, + Print, Return, Scope, While, Variable, Pointer, real +) +from sympy.codegen.cfunctions import isnan + +""" This module collects functions for constructing ASTs representing algorithms. """ + +def newtons_method(expr, wrt, atol=1e-12, delta=None, *, rtol=4e-16, debug=False, + itermax=None, counter=None, delta_fn=lambda e, x: -e/e.diff(x), + cse=False, handle_nan=None, + bounds=None): + """ Generates an AST for Newton-Raphson method (a root-finding algorithm). + + Explanation + =========== + + Returns an abstract syntax tree (AST) based on ``sympy.codegen.ast`` for Netwon's + method of root-finding. + + Parameters + ========== + + expr : expression + wrt : Symbol + With respect to, i.e. what is the variable. + atol : number or expression + Absolute tolerance (stopping criterion) + rtol : number or expression + Relative tolerance (stopping criterion) + delta : Symbol + Will be a ``Dummy`` if ``None``. + debug : bool + Whether to print convergence information during iterations + itermax : number or expr + Maximum number of iterations. + counter : Symbol + Will be a ``Dummy`` if ``None``. + delta_fn: Callable[[Expr, Symbol], Expr] + computes the step, default is newtons method. For e.g. Halley's method + use delta_fn=lambda e, x: -2*e*e.diff(x)/(2*e.diff(x)**2 - e*e.diff(x, 2)) + cse: bool + Perform common sub-expression elimination on delta expression + handle_nan: Token + How to handle occurrence of not-a-number (NaN). + bounds: Optional[tuple[Expr, Expr]] + Perform optimization within bounds + + Examples + ======== + + >>> from sympy import symbols, cos + >>> from sympy.codegen.ast import Assignment + >>> from sympy.codegen.algorithms import newtons_method + >>> x, dx, atol = symbols('x dx atol') + >>> expr = cos(x) - x**3 + >>> algo = newtons_method(expr, x, atol=atol, delta=dx) + >>> algo.has(Assignment(dx, -expr/expr.diff(x))) + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Newton%27s_method + + """ + + if delta is None: + delta = Dummy() + Wrapper = Scope + name_d = 'delta' + else: + Wrapper = lambda x: x + name_d = delta.name + + delta_expr = delta_fn(expr, wrt) + if cse: + from sympy.simplify.cse_main import cse + cses, (red,) = cse([delta_expr.factor()]) + whl_bdy = [Assignment(dum, sub_e) for dum, sub_e in cses] + whl_bdy += [Assignment(delta, red)] + else: + whl_bdy = [Assignment(delta, delta_expr)] + if handle_nan is not None: + whl_bdy += [While(isnan(delta), CodeBlock(handle_nan, break_))] + whl_bdy += [AddAugmentedAssignment(wrt, delta)] + if bounds is not None: + whl_bdy += [Assignment(wrt, Min(Max(wrt, bounds[0]), bounds[1]))] + if debug: + prnt = Print([wrt, delta], r"{}=%12.5g {}=%12.5g\n".format(wrt.name, name_d)) + whl_bdy += [prnt] + req = Gt(Abs(delta), atol + rtol*Abs(wrt)) + declars = [Declaration(Variable(delta, type=real, value=oo))] + if itermax is not None: + counter = counter or Dummy(integer=True) + v_counter = Variable.deduced(counter, 0) + declars.append(Declaration(v_counter)) + whl_bdy.append(AddAugmentedAssignment(counter, 1)) + req = And(req, Lt(counter, itermax)) + whl = While(req, CodeBlock(*whl_bdy)) + blck = declars + if debug: + blck.append(Print([wrt], r"{}=%12.5g\n".format(wrt.name))) + blck += [whl] + return Wrapper(CodeBlock(*blck)) + + +def _symbol_of(arg): + if isinstance(arg, Declaration): + arg = arg.variable.symbol + elif isinstance(arg, Variable): + arg = arg.symbol + return arg + + +def newtons_method_function(expr, wrt, params=None, func_name="newton", attrs=Tuple(), *, delta=None, **kwargs): + """ Generates an AST for a function implementing the Newton-Raphson method. + + Parameters + ========== + + expr : expression + wrt : Symbol + With respect to, i.e. what is the variable + params : iterable of symbols + Symbols appearing in expr that are taken as constants during the iterations + (these will be accepted as parameters to the generated function). + func_name : str + Name of the generated function. + attrs : Tuple + Attribute instances passed as ``attrs`` to ``FunctionDefinition``. + \\*\\*kwargs : + Keyword arguments passed to :func:`sympy.codegen.algorithms.newtons_method`. + + Examples + ======== + + >>> from sympy import symbols, cos + >>> from sympy.codegen.algorithms import newtons_method_function + >>> from sympy.codegen.pyutils import render_as_module + >>> x = symbols('x') + >>> expr = cos(x) - x**3 + >>> func = newtons_method_function(expr, x) + >>> py_mod = render_as_module(func) # source code as string + >>> namespace = {} + >>> exec(py_mod, namespace, namespace) + >>> res = eval('newton(0.5)', namespace) + >>> abs(res - 0.865474033102) < 1e-12 + True + + See Also + ======== + + sympy.codegen.algorithms.newtons_method + + """ + if params is None: + params = (wrt,) + pointer_subs = {p.symbol: Symbol('(*%s)' % p.symbol.name) + for p in params if isinstance(p, Pointer)} + if delta is None: + delta = Symbol('d_' + wrt.name) + if expr.has(delta): + delta = None # will use Dummy + algo = newtons_method(expr, wrt, delta=delta, **kwargs).xreplace(pointer_subs) + if isinstance(algo, Scope): + algo = algo.body + not_in_params = expr.free_symbols.difference({_symbol_of(p) for p in params}) + if not_in_params: + raise ValueError("Missing symbols in params: %s" % ', '.join(map(str, not_in_params))) + declars = tuple(Variable(p, real) for p in params) + body = CodeBlock(algo, Return(wrt)) + return FunctionDefinition(real, func_name, declars, body, attrs=attrs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/approximations.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/approximations.py new file mode 100644 index 0000000000000000000000000000000000000000..c6486926938224c5052dc5adfac29807e82eb4d8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/approximations.py @@ -0,0 +1,187 @@ +import math +from sympy.sets.sets import Interval +from sympy.calculus.singularities import is_increasing, is_decreasing +from sympy.codegen.rewriting import Optimization +from sympy.core.function import UndefinedFunction + +""" +This module collects classes useful for approximate rewriting of expressions. +This can be beneficial when generating numeric code for which performance is +of greater importance than precision (e.g. for preconditioners used in iterative +methods). +""" + +class SumApprox(Optimization): + """ + Approximates sum by neglecting small terms. + + Explanation + =========== + + If terms are expressions which can be determined to be monotonic, then + bounds for those expressions are added. + + Parameters + ========== + + bounds : dict + Mapping expressions to length 2 tuple of bounds (low, high). + reltol : number + Threshold for when to ignore a term. Taken relative to the largest + lower bound among bounds. + + Examples + ======== + + >>> from sympy import exp + >>> from sympy.abc import x, y, z + >>> from sympy.codegen.rewriting import optimize + >>> from sympy.codegen.approximations import SumApprox + >>> bounds = {x: (-1, 1), y: (1000, 2000), z: (-10, 3)} + >>> sum_approx3 = SumApprox(bounds, reltol=1e-3) + >>> sum_approx2 = SumApprox(bounds, reltol=1e-2) + >>> sum_approx1 = SumApprox(bounds, reltol=1e-1) + >>> expr = 3*(x + y + exp(z)) + >>> optimize(expr, [sum_approx3]) + 3*(x + y + exp(z)) + >>> optimize(expr, [sum_approx2]) + 3*y + 3*exp(z) + >>> optimize(expr, [sum_approx1]) + 3*y + + """ + + def __init__(self, bounds, reltol, **kwargs): + super().__init__(**kwargs) + self.bounds = bounds + self.reltol = reltol + + def __call__(self, expr): + return expr.factor().replace(self.query, lambda arg: self.value(arg)) + + def query(self, expr): + return expr.is_Add + + def value(self, add): + for term in add.args: + if term.is_number or term in self.bounds or len(term.free_symbols) != 1: + continue + fs, = term.free_symbols + if fs not in self.bounds: + continue + intrvl = Interval(*self.bounds[fs]) + if is_increasing(term, intrvl, fs): + self.bounds[term] = ( + term.subs({fs: self.bounds[fs][0]}), + term.subs({fs: self.bounds[fs][1]}) + ) + elif is_decreasing(term, intrvl, fs): + self.bounds[term] = ( + term.subs({fs: self.bounds[fs][1]}), + term.subs({fs: self.bounds[fs][0]}) + ) + else: + return add + + if all(term.is_number or term in self.bounds for term in add.args): + bounds = [(term, term) if term.is_number else self.bounds[term] for term in add.args] + largest_abs_guarantee = 0 + for lo, hi in bounds: + if lo <= 0 <= hi: + continue + largest_abs_guarantee = max(largest_abs_guarantee, + min(abs(lo), abs(hi))) + new_terms = [] + for term, (lo, hi) in zip(add.args, bounds): + if max(abs(lo), abs(hi)) >= largest_abs_guarantee*self.reltol: + new_terms.append(term) + return add.func(*new_terms) + else: + return add + + +class SeriesApprox(Optimization): + """ Approximates functions by expanding them as a series. + + Parameters + ========== + + bounds : dict + Mapping expressions to length 2 tuple of bounds (low, high). + reltol : number + Threshold for when to ignore a term. Taken relative to the largest + lower bound among bounds. + max_order : int + Largest order to include in series expansion + n_point_checks : int (even) + The validity of an expansion (with respect to reltol) is checked at + discrete points (linearly spaced over the bounds of the variable). The + number of points used in this numerical check is given by this number. + + Examples + ======== + + >>> from sympy import sin, pi + >>> from sympy.abc import x, y + >>> from sympy.codegen.rewriting import optimize + >>> from sympy.codegen.approximations import SeriesApprox + >>> bounds = {x: (-.1, .1), y: (pi-1, pi+1)} + >>> series_approx2 = SeriesApprox(bounds, reltol=1e-2) + >>> series_approx3 = SeriesApprox(bounds, reltol=1e-3) + >>> series_approx8 = SeriesApprox(bounds, reltol=1e-8) + >>> expr = sin(x)*sin(y) + >>> optimize(expr, [series_approx2]) + x*(-y + (y - pi)**3/6 + pi) + >>> optimize(expr, [series_approx3]) + (-x**3/6 + x)*sin(y) + >>> optimize(expr, [series_approx8]) + sin(x)*sin(y) + + """ + def __init__(self, bounds, reltol, max_order=4, n_point_checks=4, **kwargs): + super().__init__(**kwargs) + self.bounds = bounds + self.reltol = reltol + self.max_order = max_order + if n_point_checks % 2 == 1: + raise ValueError("Checking the solution at expansion point is not helpful") + self.n_point_checks = n_point_checks + self._prec = math.ceil(-math.log10(self.reltol)) + + def __call__(self, expr): + return expr.factor().replace(self.query, lambda arg: self.value(arg)) + + def query(self, expr): + return (expr.is_Function and not isinstance(expr, UndefinedFunction) + and len(expr.args) == 1) + + def value(self, fexpr): + free_symbols = fexpr.free_symbols + if len(free_symbols) != 1: + return fexpr + symb, = free_symbols + if symb not in self.bounds: + return fexpr + lo, hi = self.bounds[symb] + x0 = (lo + hi)/2 + cheapest = None + for n in range(self.max_order+1, 0, -1): + fseri = fexpr.series(symb, x0=x0, n=n).removeO() + n_ok = True + for idx in range(self.n_point_checks): + x = lo + idx*(hi - lo)/(self.n_point_checks - 1) + val = fseri.xreplace({symb: x}) + ref = fexpr.xreplace({symb: x}) + if abs((1 - val/ref).evalf(self._prec)) > self.reltol: + n_ok = False + break + + if n_ok: + cheapest = fseri + else: + break + + if cheapest is None: + return fexpr + else: + return cheapest diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/ast.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/ast.py new file mode 100644 index 0000000000000000000000000000000000000000..dd774ca87c5c9d4b55c8ea7a3b68837035b0d06d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/ast.py @@ -0,0 +1,1906 @@ +""" +Types used to represent a full function/module as an Abstract Syntax Tree. + +Most types are small, and are merely used as tokens in the AST. A tree diagram +has been included below to illustrate the relationships between the AST types. + + +AST Type Tree +------------- +:: + + *Basic* + | + | + CodegenAST + | + |--->AssignmentBase + | |--->Assignment + | |--->AugmentedAssignment + | |--->AddAugmentedAssignment + | |--->SubAugmentedAssignment + | |--->MulAugmentedAssignment + | |--->DivAugmentedAssignment + | |--->ModAugmentedAssignment + | + |--->CodeBlock + | + | + |--->Token + |--->Attribute + |--->For + |--->String + | |--->QuotedString + | |--->Comment + |--->Type + | |--->IntBaseType + | | |--->_SizedIntType + | | |--->SignedIntType + | | |--->UnsignedIntType + | |--->FloatBaseType + | |--->FloatType + | |--->ComplexBaseType + | |--->ComplexType + |--->Node + | |--->Variable + | | |---> Pointer + | |--->FunctionPrototype + | |--->FunctionDefinition + |--->Element + |--->Declaration + |--->While + |--->Scope + |--->Stream + |--->Print + |--->FunctionCall + |--->BreakToken + |--->ContinueToken + |--->NoneToken + |--->Return + + +Predefined types +---------------- + +A number of ``Type`` instances are provided in the ``sympy.codegen.ast`` module +for convenience. Perhaps the two most common ones for code-generation (of numeric +codes) are ``float32`` and ``float64`` (known as single and double precision respectively). +There are also precision generic versions of Types (for which the codeprinters selects the +underlying data type at time of printing): ``real``, ``integer``, ``complex_``, ``bool_``. + +The other ``Type`` instances defined are: + +- ``intc``: Integer type used by C's "int". +- ``intp``: Integer type used by C's "unsigned". +- ``int8``, ``int16``, ``int32``, ``int64``: n-bit integers. +- ``uint8``, ``uint16``, ``uint32``, ``uint64``: n-bit unsigned integers. +- ``float80``: known as "extended precision" on modern x86/amd64 hardware. +- ``complex64``: Complex number represented by two ``float32`` numbers +- ``complex128``: Complex number represented by two ``float64`` numbers + +Using the nodes +--------------- + +It is possible to construct simple algorithms using the AST nodes. Let's construct a loop applying +Newton's method:: + + >>> from sympy import symbols, cos + >>> from sympy.codegen.ast import While, Assignment, aug_assign, Print, QuotedString + >>> t, dx, x = symbols('tol delta val') + >>> expr = cos(x) - x**3 + >>> whl = While(abs(dx) > t, [ + ... Assignment(dx, -expr/expr.diff(x)), + ... aug_assign(x, '+', dx), + ... Print([x]) + ... ]) + >>> from sympy import pycode + >>> py_str = pycode(whl) + >>> print(py_str) + while (abs(delta) > tol): + delta = (val**3 - math.cos(val))/(-3*val**2 - math.sin(val)) + val += delta + print(val) + >>> import math + >>> tol, val, delta = 1e-5, 0.5, float('inf') + >>> exec(py_str) + 1.1121416371 + 0.909672693737 + 0.867263818209 + 0.865477135298 + 0.865474033111 + >>> print('%3.1g' % (math.cos(val) - val**3)) + -3e-11 + +If we want to generate Fortran code for the same while loop we simple call ``fcode``:: + + >>> from sympy import fcode + >>> print(fcode(whl, standard=2003, source_format='free')) + do while (abs(delta) > tol) + delta = (val**3 - cos(val))/(-3*val**2 - sin(val)) + val = val + delta + print *, val + end do + +There is a function constructing a loop (or a complete function) like this in +:mod:`sympy.codegen.algorithms`. + +""" + +from __future__ import annotations +from typing import Any + +from collections import defaultdict + +from sympy.core.relational import (Ge, Gt, Le, Lt) +from sympy.core import Symbol, Tuple, Dummy +from sympy.core.basic import Basic +from sympy.core.expr import Expr, Atom +from sympy.core.numbers import Float, Integer, oo +from sympy.core.sympify import _sympify, sympify, SympifyError +from sympy.utilities.iterables import (iterable, topological_sort, + numbered_symbols, filter_symbols) + + +def _mk_Tuple(args): + """ + Create a SymPy Tuple object from an iterable, converting Python strings to + AST strings. + + Parameters + ========== + + args: iterable + Arguments to :class:`sympy.Tuple`. + + Returns + ======= + + sympy.Tuple + """ + args = [String(arg) if isinstance(arg, str) else arg for arg in args] + return Tuple(*args) + + +class CodegenAST(Basic): + __slots__ = () + + +class Token(CodegenAST): + """ Base class for the AST types. + + Explanation + =========== + + Defining fields are set in ``_fields``. Attributes (defined in _fields) + are only allowed to contain instances of Basic (unless atomic, see + ``String``). The arguments to ``__new__()`` correspond to the attributes in + the order defined in ``_fields`. The ``defaults`` class attribute is a + dictionary mapping attribute names to their default values. + + Subclasses should not need to override the ``__new__()`` method. They may + define a class or static method named ``_construct_`` for each + attribute to process the value passed to ``__new__()``. Attributes listed + in the class attribute ``not_in_args`` are not passed to :class:`~.Basic`. + """ + + __slots__: tuple[str, ...] = () + _fields = __slots__ + defaults: dict[str, Any] = {} + not_in_args: list[str] = [] + indented_args = ['body'] + + @property + def is_Atom(self): + return len(self._fields) == 0 + + @classmethod + def _get_constructor(cls, attr): + """ Get the constructor function for an attribute by name. """ + return getattr(cls, '_construct_%s' % attr, lambda x: x) + + @classmethod + def _construct(cls, attr, arg): + """ Construct an attribute value from argument passed to ``__new__()``. """ + # arg may be ``NoneToken()``, so comparison is done using == instead of ``is`` operator + if arg == None: + return cls.defaults.get(attr, none) + else: + if isinstance(arg, Dummy): # SymPy's replace uses Dummy instances + return arg + else: + return cls._get_constructor(attr)(arg) + + def __new__(cls, *args, **kwargs): + # Pass through existing instances when given as sole argument + if len(args) == 1 and not kwargs and isinstance(args[0], cls): + return args[0] + + if len(args) > len(cls._fields): + raise ValueError("Too many arguments (%d), expected at most %d" % (len(args), len(cls._fields))) + + attrvals = [] + + # Process positional arguments + for attrname, argval in zip(cls._fields, args): + if attrname in kwargs: + raise TypeError('Got multiple values for attribute %r' % attrname) + + attrvals.append(cls._construct(attrname, argval)) + + # Process keyword arguments + for attrname in cls._fields[len(args):]: + if attrname in kwargs: + argval = kwargs.pop(attrname) + + elif attrname in cls.defaults: + argval = cls.defaults[attrname] + + else: + raise TypeError('No value for %r given and attribute has no default' % attrname) + + attrvals.append(cls._construct(attrname, argval)) + + if kwargs: + raise ValueError("Unknown keyword arguments: %s" % ' '.join(kwargs)) + + # Parent constructor + basic_args = [ + val for attr, val in zip(cls._fields, attrvals) + if attr not in cls.not_in_args + ] + obj = CodegenAST.__new__(cls, *basic_args) + + # Set attributes + for attr, arg in zip(cls._fields, attrvals): + setattr(obj, attr, arg) + + return obj + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + for attr in self._fields: + if getattr(self, attr) != getattr(other, attr): + return False + return True + + def _hashable_content(self): + return tuple([getattr(self, attr) for attr in self._fields]) + + def __hash__(self): + return super().__hash__() + + def _joiner(self, k, indent_level): + return (',\n' + ' '*indent_level) if k in self.indented_args else ', ' + + def _indented(self, printer, k, v, *args, **kwargs): + il = printer._context['indent_level'] + def _print(arg): + if isinstance(arg, Token): + return printer._print(arg, *args, joiner=self._joiner(k, il), **kwargs) + else: + return printer._print(arg, *args, **kwargs) + + if isinstance(v, Tuple): + joined = self._joiner(k, il).join([_print(arg) for arg in v.args]) + if k in self.indented_args: + return '(\n' + ' '*il + joined + ',\n' + ' '*(il - 4) + ')' + else: + return ('({0},)' if len(v.args) == 1 else '({0})').format(joined) + else: + return _print(v) + + def _sympyrepr(self, printer, *args, joiner=', ', **kwargs): + from sympy.printing.printer import printer_context + exclude = kwargs.get('exclude', ()) + values = [getattr(self, k) for k in self._fields] + indent_level = printer._context.get('indent_level', 0) + + arg_reprs = [] + + for i, (attr, value) in enumerate(zip(self._fields, values)): + if attr in exclude: + continue + + # Skip attributes which have the default value + if attr in self.defaults and value == self.defaults[attr]: + continue + + ilvl = indent_level + 4 if attr in self.indented_args else 0 + with printer_context(printer, indent_level=ilvl): + indented = self._indented(printer, attr, value, *args, **kwargs) + arg_reprs.append(('{1}' if i == 0 else '{0}={1}').format(attr, indented.lstrip())) + + return "{}({})".format(self.__class__.__name__, joiner.join(arg_reprs)) + + _sympystr = _sympyrepr + + def __repr__(self): # sympy.core.Basic.__repr__ uses sstr + from sympy.printing import srepr + return srepr(self) + + def kwargs(self, exclude=(), apply=None): + """ Get instance's attributes as dict of keyword arguments. + + Parameters + ========== + + exclude : collection of str + Collection of keywords to exclude. + + apply : callable, optional + Function to apply to all values. + """ + kwargs = {k: getattr(self, k) for k in self._fields if k not in exclude} + if apply is not None: + return {k: apply(v) for k, v in kwargs.items()} + else: + return kwargs + +class BreakToken(Token): + """ Represents 'break' in C/Python ('exit' in Fortran). + + Use the premade instance ``break_`` or instantiate manually. + + Examples + ======== + + >>> from sympy import ccode, fcode + >>> from sympy.codegen.ast import break_ + >>> ccode(break_) + 'break' + >>> fcode(break_, source_format='free') + 'exit' + """ + +break_ = BreakToken() + + +class ContinueToken(Token): + """ Represents 'continue' in C/Python ('cycle' in Fortran) + + Use the premade instance ``continue_`` or instantiate manually. + + Examples + ======== + + >>> from sympy import ccode, fcode + >>> from sympy.codegen.ast import continue_ + >>> ccode(continue_) + 'continue' + >>> fcode(continue_, source_format='free') + 'cycle' + """ + +continue_ = ContinueToken() + +class NoneToken(Token): + """ The AST equivalence of Python's NoneType + + The corresponding instance of Python's ``None`` is ``none``. + + Examples + ======== + + >>> from sympy.codegen.ast import none, Variable + >>> from sympy import pycode + >>> print(pycode(Variable('x').as_Declaration(value=none))) + x = None + + """ + def __eq__(self, other): + return other is None or isinstance(other, NoneToken) + + def _hashable_content(self): + return () + + def __hash__(self): + return super().__hash__() + + +none = NoneToken() + + +class AssignmentBase(CodegenAST): + """ Abstract base class for Assignment and AugmentedAssignment. + + Attributes: + =========== + + op : str + Symbol for assignment operator, e.g. "=", "+=", etc. + """ + + def __new__(cls, lhs, rhs): + lhs = _sympify(lhs) + rhs = _sympify(rhs) + + cls._check_args(lhs, rhs) + + return super().__new__(cls, lhs, rhs) + + @property + def lhs(self): + return self.args[0] + + @property + def rhs(self): + return self.args[1] + + @classmethod + def _check_args(cls, lhs, rhs): + """ Check arguments to __new__ and raise exception if any problems found. + + Derived classes may wish to override this. + """ + from sympy.matrices.expressions.matexpr import ( + MatrixElement, MatrixSymbol) + from sympy.tensor.indexed import Indexed + from sympy.tensor.array.expressions import ArrayElement + + # Tuple of things that can be on the lhs of an assignment + assignable = (Symbol, MatrixSymbol, MatrixElement, Indexed, Element, Variable, + ArrayElement) + if not isinstance(lhs, assignable): + raise TypeError("Cannot assign to lhs of type %s." % type(lhs)) + + # Indexed types implement shape, but don't define it until later. This + # causes issues in assignment validation. For now, matrices are defined + # as anything with a shape that is not an Indexed + lhs_is_mat = hasattr(lhs, 'shape') and not isinstance(lhs, Indexed) + rhs_is_mat = hasattr(rhs, 'shape') and not isinstance(rhs, Indexed) + + # If lhs and rhs have same structure, then this assignment is ok + if lhs_is_mat: + if not rhs_is_mat: + raise ValueError("Cannot assign a scalar to a matrix.") + elif lhs.shape != rhs.shape: + raise ValueError("Dimensions of lhs and rhs do not align.") + elif rhs_is_mat and not lhs_is_mat: + raise ValueError("Cannot assign a matrix to a scalar.") + + +class Assignment(AssignmentBase): + """ + Represents variable assignment for code generation. + + Parameters + ========== + + lhs : Expr + SymPy object representing the lhs of the expression. These should be + singular objects, such as one would use in writing code. Notable types + include Symbol, MatrixSymbol, MatrixElement, and Indexed. Types that + subclass these types are also supported. + + rhs : Expr + SymPy object representing the rhs of the expression. This can be any + type, provided its shape corresponds to that of the lhs. For example, + a Matrix type can be assigned to MatrixSymbol, but not to Symbol, as + the dimensions will not align. + + Examples + ======== + + >>> from sympy import symbols, MatrixSymbol, Matrix + >>> from sympy.codegen.ast import Assignment + >>> x, y, z = symbols('x, y, z') + >>> Assignment(x, y) + Assignment(x, y) + >>> Assignment(x, 0) + Assignment(x, 0) + >>> A = MatrixSymbol('A', 1, 3) + >>> mat = Matrix([x, y, z]).T + >>> Assignment(A, mat) + Assignment(A, Matrix([[x, y, z]])) + >>> Assignment(A[0, 1], x) + Assignment(A[0, 1], x) + """ + + op = ':=' + + +class AugmentedAssignment(AssignmentBase): + """ + Base class for augmented assignments. + + Attributes: + =========== + + binop : str + Symbol for binary operation being applied in the assignment, such as "+", + "*", etc. + """ + binop: str | None + + @property + def op(self): + return self.binop + '=' + + +class AddAugmentedAssignment(AugmentedAssignment): + binop = '+' + + +class SubAugmentedAssignment(AugmentedAssignment): + binop = '-' + + +class MulAugmentedAssignment(AugmentedAssignment): + binop = '*' + + +class DivAugmentedAssignment(AugmentedAssignment): + binop = '/' + + +class ModAugmentedAssignment(AugmentedAssignment): + binop = '%' + + +# Mapping from binary op strings to AugmentedAssignment subclasses +augassign_classes = { + cls.binop: cls for cls in [ + AddAugmentedAssignment, SubAugmentedAssignment, MulAugmentedAssignment, + DivAugmentedAssignment, ModAugmentedAssignment + ] +} + + +def aug_assign(lhs, op, rhs): + """ + Create 'lhs op= rhs'. + + Explanation + =========== + + Represents augmented variable assignment for code generation. This is a + convenience function. You can also use the AugmentedAssignment classes + directly, like AddAugmentedAssignment(x, y). + + Parameters + ========== + + lhs : Expr + SymPy object representing the lhs of the expression. These should be + singular objects, such as one would use in writing code. Notable types + include Symbol, MatrixSymbol, MatrixElement, and Indexed. Types that + subclass these types are also supported. + + op : str + Operator (+, -, /, \\*, %). + + rhs : Expr + SymPy object representing the rhs of the expression. This can be any + type, provided its shape corresponds to that of the lhs. For example, + a Matrix type can be assigned to MatrixSymbol, but not to Symbol, as + the dimensions will not align. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.codegen.ast import aug_assign + >>> x, y = symbols('x, y') + >>> aug_assign(x, '+', y) + AddAugmentedAssignment(x, y) + """ + if op not in augassign_classes: + raise ValueError("Unrecognized operator %s" % op) + return augassign_classes[op](lhs, rhs) + + +class CodeBlock(CodegenAST): + """ + Represents a block of code. + + Explanation + =========== + + For now only assignments are supported. This restriction will be lifted in + the future. + + Useful attributes on this object are: + + ``left_hand_sides``: + Tuple of left-hand sides of assignments, in order. + ``left_hand_sides``: + Tuple of right-hand sides of assignments, in order. + ``free_symbols``: Free symbols of the expressions in the right-hand sides + which do not appear in the left-hand side of an assignment. + + Useful methods on this object are: + + ``topological_sort``: + Class method. Return a CodeBlock with assignments + sorted so that variables are assigned before they + are used. + ``cse``: + Return a new CodeBlock with common subexpressions eliminated and + pulled out as assignments. + + Examples + ======== + + >>> from sympy import symbols, ccode + >>> from sympy.codegen.ast import CodeBlock, Assignment + >>> x, y = symbols('x y') + >>> c = CodeBlock(Assignment(x, 1), Assignment(y, x + 1)) + >>> print(ccode(c)) + x = 1; + y = x + 1; + + """ + def __new__(cls, *args): + left_hand_sides = [] + right_hand_sides = [] + for i in args: + if isinstance(i, Assignment): + lhs, rhs = i.args + left_hand_sides.append(lhs) + right_hand_sides.append(rhs) + + obj = CodegenAST.__new__(cls, *args) + + obj.left_hand_sides = Tuple(*left_hand_sides) + obj.right_hand_sides = Tuple(*right_hand_sides) + return obj + + def __iter__(self): + return iter(self.args) + + def _sympyrepr(self, printer, *args, **kwargs): + il = printer._context.get('indent_level', 0) + joiner = ',\n' + ' '*il + joined = joiner.join(map(printer._print, self.args)) + return ('{}(\n'.format(' '*(il-4) + self.__class__.__name__,) + + ' '*il + joined + '\n' + ' '*(il - 4) + ')') + + _sympystr = _sympyrepr + + @property + def free_symbols(self): + return super().free_symbols - set(self.left_hand_sides) + + @classmethod + def topological_sort(cls, assignments): + """ + Return a CodeBlock with topologically sorted assignments so that + variables are assigned before they are used. + + Examples + ======== + + The existing order of assignments is preserved as much as possible. + + This function assumes that variables are assigned to only once. + + This is a class constructor so that the default constructor for + CodeBlock can error when variables are used before they are assigned. + + >>> from sympy import symbols + >>> from sympy.codegen.ast import CodeBlock, Assignment + >>> x, y, z = symbols('x y z') + + >>> assignments = [ + ... Assignment(x, y + z), + ... Assignment(y, z + 1), + ... Assignment(z, 2), + ... ] + >>> CodeBlock.topological_sort(assignments) + CodeBlock( + Assignment(z, 2), + Assignment(y, z + 1), + Assignment(x, y + z) + ) + + """ + + if not all(isinstance(i, Assignment) for i in assignments): + # Will support more things later + raise NotImplementedError("CodeBlock.topological_sort only supports Assignments") + + if any(isinstance(i, AugmentedAssignment) for i in assignments): + raise NotImplementedError("CodeBlock.topological_sort does not yet work with AugmentedAssignments") + + # Create a graph where the nodes are assignments and there is a directed edge + # between nodes that use a variable and nodes that assign that + # variable, like + + # [(x := 1, y := x + 1), (x := 1, z := y + z), (y := x + 1, z := y + z)] + + # If we then topologically sort these nodes, they will be in + # assignment order, like + + # x := 1 + # y := x + 1 + # z := y + z + + # A = The nodes + # + # enumerate keeps nodes in the same order they are already in if + # possible. It will also allow us to handle duplicate assignments to + # the same variable when those are implemented. + A = list(enumerate(assignments)) + + # var_map = {variable: [nodes for which this variable is assigned to]} + # like {x: [(1, x := y + z), (4, x := 2 * w)], ...} + var_map = defaultdict(list) + for node in A: + i, a = node + var_map[a.lhs].append(node) + + # E = Edges in the graph + E = [] + for dst_node in A: + i, a = dst_node + for s in a.rhs.free_symbols: + for src_node in var_map[s]: + E.append((src_node, dst_node)) + + ordered_assignments = topological_sort([A, E]) + + # De-enumerate the result + return cls(*[a for i, a in ordered_assignments]) + + def cse(self, symbols=None, optimizations=None, postprocess=None, + order='canonical'): + """ + Return a new code block with common subexpressions eliminated. + + Explanation + =========== + + See the docstring of :func:`sympy.simplify.cse_main.cse` for more + information. + + Examples + ======== + + >>> from sympy import symbols, sin + >>> from sympy.codegen.ast import CodeBlock, Assignment + >>> x, y, z = symbols('x y z') + + >>> c = CodeBlock( + ... Assignment(x, 1), + ... Assignment(y, sin(x) + 1), + ... Assignment(z, sin(x) - 1), + ... ) + ... + >>> c.cse() + CodeBlock( + Assignment(x, 1), + Assignment(x0, sin(x)), + Assignment(y, x0 + 1), + Assignment(z, x0 - 1) + ) + + """ + from sympy.simplify.cse_main import cse + + # Check that the CodeBlock only contains assignments to unique variables + if not all(isinstance(i, Assignment) for i in self.args): + # Will support more things later + raise NotImplementedError("CodeBlock.cse only supports Assignments") + + if any(isinstance(i, AugmentedAssignment) for i in self.args): + raise NotImplementedError("CodeBlock.cse does not yet work with AugmentedAssignments") + + for i, lhs in enumerate(self.left_hand_sides): + if lhs in self.left_hand_sides[:i]: + raise NotImplementedError("Duplicate assignments to the same " + "variable are not yet supported (%s)" % lhs) + + # Ensure new symbols for subexpressions do not conflict with existing + existing_symbols = self.atoms(Symbol) + if symbols is None: + symbols = numbered_symbols() + symbols = filter_symbols(symbols, existing_symbols) + + replacements, reduced_exprs = cse(list(self.right_hand_sides), + symbols=symbols, optimizations=optimizations, postprocess=postprocess, + order=order) + + new_block = [Assignment(var, expr) for var, expr in + zip(self.left_hand_sides, reduced_exprs)] + new_assignments = [Assignment(var, expr) for var, expr in replacements] + return self.topological_sort(new_assignments + new_block) + + +class For(Token): + """Represents a 'for-loop' in the code. + + Expressions are of the form: + "for target in iter: + body..." + + Parameters + ========== + + target : symbol + iter : iterable + body : CodeBlock or iterable +! When passed an iterable it is used to instantiate a CodeBlock. + + Examples + ======== + + >>> from sympy import symbols, Range + >>> from sympy.codegen.ast import aug_assign, For + >>> x, i, j, k = symbols('x i j k') + >>> for_i = For(i, Range(10), [aug_assign(x, '+', i*j*k)]) + >>> for_i # doctest: -NORMALIZE_WHITESPACE + For(i, iterable=Range(0, 10, 1), body=CodeBlock( + AddAugmentedAssignment(x, i*j*k) + )) + >>> for_ji = For(j, Range(7), [for_i]) + >>> for_ji # doctest: -NORMALIZE_WHITESPACE + For(j, iterable=Range(0, 7, 1), body=CodeBlock( + For(i, iterable=Range(0, 10, 1), body=CodeBlock( + AddAugmentedAssignment(x, i*j*k) + )) + )) + >>> for_kji =For(k, Range(5), [for_ji]) + >>> for_kji # doctest: -NORMALIZE_WHITESPACE + For(k, iterable=Range(0, 5, 1), body=CodeBlock( + For(j, iterable=Range(0, 7, 1), body=CodeBlock( + For(i, iterable=Range(0, 10, 1), body=CodeBlock( + AddAugmentedAssignment(x, i*j*k) + )) + )) + )) + """ + __slots__ = _fields = ('target', 'iterable', 'body') + _construct_target = staticmethod(_sympify) + + @classmethod + def _construct_body(cls, itr): + if isinstance(itr, CodeBlock): + return itr + else: + return CodeBlock(*itr) + + @classmethod + def _construct_iterable(cls, itr): + if not iterable(itr): + raise TypeError("iterable must be an iterable") + if isinstance(itr, list): # _sympify errors on lists because they are mutable + itr = tuple(itr) + return _sympify(itr) + + +class String(Atom, Token): + """ SymPy object representing a string. + + Atomic object which is not an expression (as opposed to Symbol). + + Parameters + ========== + + text : str + + Examples + ======== + + >>> from sympy.codegen.ast import String + >>> f = String('foo') + >>> f + foo + >>> str(f) + 'foo' + >>> f.text + 'foo' + >>> print(repr(f)) + String('foo') + + """ + __slots__ = _fields = ('text',) + not_in_args = ['text'] + is_Atom = True + + @classmethod + def _construct_text(cls, text): + if not isinstance(text, str): + raise TypeError("Argument text is not a string type.") + return text + + def _sympystr(self, printer, *args, **kwargs): + return self.text + + def kwargs(self, exclude = (), apply = None): + return {} + + #to be removed when Atom is given a suitable func + @property + def func(self): + return lambda: self + + def _latex(self, printer): + from sympy.printing.latex import latex_escape + return r'\texttt{{"{}"}}'.format(latex_escape(self.text)) + +class QuotedString(String): + """ Represents a string which should be printed with quotes. """ + +class Comment(String): + """ Represents a comment. """ + +class Node(Token): + """ Subclass of Token, carrying the attribute 'attrs' (Tuple) + + Examples + ======== + + >>> from sympy.codegen.ast import Node, value_const, pointer_const + >>> n1 = Node([value_const]) + >>> n1.attr_params('value_const') # get the parameters of attribute (by name) + () + >>> from sympy.codegen.fnodes import dimension + >>> n2 = Node([value_const, dimension(5, 3)]) + >>> n2.attr_params(value_const) # get the parameters of attribute (by Attribute instance) + () + >>> n2.attr_params('dimension') # get the parameters of attribute (by name) + (5, 3) + >>> n2.attr_params(pointer_const) is None + True + + """ + + __slots__: tuple[str, ...] = ('attrs',) + _fields = __slots__ + + defaults: dict[str, Any] = {'attrs': Tuple()} + + _construct_attrs = staticmethod(_mk_Tuple) + + def attr_params(self, looking_for): + """ Returns the parameters of the Attribute with name ``looking_for`` in self.attrs """ + for attr in self.attrs: + if str(attr.name) == str(looking_for): + return attr.parameters + + +class Type(Token): + """ Represents a type. + + Explanation + =========== + + The naming is a super-set of NumPy naming. Type has a classmethod + ``from_expr`` which offer type deduction. It also has a method + ``cast_check`` which casts the argument to its type, possibly raising an + exception if rounding error is not within tolerances, or if the value is not + representable by the underlying data type (e.g. unsigned integers). + + Parameters + ========== + + name : str + Name of the type, e.g. ``object``, ``int16``, ``float16`` (where the latter two + would use the ``Type`` sub-classes ``IntType`` and ``FloatType`` respectively). + If a ``Type`` instance is given, the said instance is returned. + + Examples + ======== + + >>> from sympy.codegen.ast import Type + >>> t = Type.from_expr(42) + >>> t + integer + >>> print(repr(t)) + IntBaseType(String('integer')) + >>> from sympy.codegen.ast import uint8 + >>> uint8.cast_check(-1) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Minimum value for data type bigger than new value. + >>> from sympy.codegen.ast import float32 + >>> v6 = 0.123456 + >>> float32.cast_check(v6) + 0.123456 + >>> v10 = 12345.67894 + >>> float32.cast_check(v10) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Casting gives a significantly different value. + >>> boost_mp50 = Type('boost::multiprecision::cpp_dec_float_50') + >>> from sympy import cxxcode + >>> from sympy.codegen.ast import Declaration, Variable + >>> cxxcode(Declaration(Variable('x', type=boost_mp50))) + 'boost::multiprecision::cpp_dec_float_50 x' + + References + ========== + + .. [1] https://numpy.org/doc/stable/user/basics.types.html + + """ + __slots__: tuple[str, ...] = ('name',) + _fields = __slots__ + + _construct_name = String + + def _sympystr(self, printer, *args, **kwargs): + return str(self.name) + + @classmethod + def from_expr(cls, expr): + """ Deduces type from an expression or a ``Symbol``. + + Parameters + ========== + + expr : number or SymPy object + The type will be deduced from type or properties. + + Examples + ======== + + >>> from sympy.codegen.ast import Type, integer, complex_ + >>> Type.from_expr(2) == integer + True + >>> from sympy import Symbol + >>> Type.from_expr(Symbol('z', complex=True)) == complex_ + True + >>> Type.from_expr(sum) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Could not deduce type from expr. + + Raises + ====== + + ValueError when type deduction fails. + + """ + if isinstance(expr, (float, Float)): + return real + if isinstance(expr, (int, Integer)) or getattr(expr, 'is_integer', False): + return integer + if getattr(expr, 'is_real', False): + return real + if isinstance(expr, complex) or getattr(expr, 'is_complex', False): + return complex_ + if isinstance(expr, bool) or getattr(expr, 'is_Relational', False): + return bool_ + else: + raise ValueError("Could not deduce type from expr.") + + def _check(self, value): + pass + + def cast_check(self, value, rtol=None, atol=0, precision_targets=None): + """ Casts a value to the data type of the instance. + + Parameters + ========== + + value : number + rtol : floating point number + Relative tolerance. (will be deduced if not given). + atol : floating point number + Absolute tolerance (in addition to ``rtol``). + type_aliases : dict + Maps substitutions for Type, e.g. {integer: int64, real: float32} + + Examples + ======== + + >>> from sympy.codegen.ast import integer, float32, int8 + >>> integer.cast_check(3.0) == 3 + True + >>> float32.cast_check(1e-40) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Minimum value for data type bigger than new value. + >>> int8.cast_check(256) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Maximum value for data type smaller than new value. + >>> v10 = 12345.67894 + >>> float32.cast_check(v10) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Casting gives a significantly different value. + >>> from sympy.codegen.ast import float64 + >>> float64.cast_check(v10) + 12345.67894 + >>> from sympy import Float + >>> v18 = Float('0.123456789012345646') + >>> float64.cast_check(v18) + Traceback (most recent call last): + ... + ValueError: Casting gives a significantly different value. + >>> from sympy.codegen.ast import float80 + >>> float80.cast_check(v18) + 0.123456789012345649 + + """ + val = sympify(value) + + ten = Integer(10) + exp10 = getattr(self, 'decimal_dig', None) + + if rtol is None: + rtol = 1e-15 if exp10 is None else 2.0*ten**(-exp10) + + def tol(num): + return atol + rtol*abs(num) + + new_val = self.cast_nocheck(value) + self._check(new_val) + + delta = new_val - val + if abs(delta) > tol(val): # rounding, e.g. int(3.5) != 3.5 + raise ValueError("Casting gives a significantly different value.") + + return new_val + + def _latex(self, printer): + from sympy.printing.latex import latex_escape + type_name = latex_escape(self.__class__.__name__) + name = latex_escape(self.name.text) + return r"\text{{{}}}\left(\texttt{{{}}}\right)".format(type_name, name) + + +class IntBaseType(Type): + """ Integer base type, contains no size information. """ + __slots__ = () + cast_nocheck = lambda self, i: Integer(int(i)) + + +class _SizedIntType(IntBaseType): + __slots__ = ('nbits',) + _fields = Type._fields + __slots__ + + _construct_nbits = Integer + + def _check(self, value): + if value < self.min: + raise ValueError("Value is too small: %d < %d" % (value, self.min)) + if value > self.max: + raise ValueError("Value is too big: %d > %d" % (value, self.max)) + + +class SignedIntType(_SizedIntType): + """ Represents a signed integer type. """ + __slots__ = () + @property + def min(self): + return -2**(self.nbits-1) + + @property + def max(self): + return 2**(self.nbits-1) - 1 + + +class UnsignedIntType(_SizedIntType): + """ Represents an unsigned integer type. """ + __slots__ = () + @property + def min(self): + return 0 + + @property + def max(self): + return 2**self.nbits - 1 + +two = Integer(2) + +class FloatBaseType(Type): + """ Represents a floating point number type. """ + __slots__ = () + cast_nocheck = Float + +class FloatType(FloatBaseType): + """ Represents a floating point type with fixed bit width. + + Base 2 & one sign bit is assumed. + + Parameters + ========== + + name : str + Name of the type. + nbits : integer + Number of bits used (storage). + nmant : integer + Number of bits used to represent the mantissa. + nexp : integer + Number of bits used to represent the mantissa. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.codegen.ast import FloatType + >>> half_precision = FloatType('f16', nbits=16, nmant=10, nexp=5) + >>> half_precision.max + 65504 + >>> half_precision.tiny == S(2)**-14 + True + >>> half_precision.eps == S(2)**-10 + True + >>> half_precision.dig == 3 + True + >>> half_precision.decimal_dig == 5 + True + >>> half_precision.cast_check(1.0) + 1.0 + >>> half_precision.cast_check(1e5) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Maximum value for data type smaller than new value. + """ + + __slots__ = ('nbits', 'nmant', 'nexp',) + _fields = Type._fields + __slots__ + + _construct_nbits = _construct_nmant = _construct_nexp = Integer + + + @property + def max_exponent(self): + """ The largest positive number n, such that 2**(n - 1) is a representable finite value. """ + # cf. C++'s ``std::numeric_limits::max_exponent`` + return two**(self.nexp - 1) + + @property + def min_exponent(self): + """ The lowest negative number n, such that 2**(n - 1) is a valid normalized number. """ + # cf. C++'s ``std::numeric_limits::min_exponent`` + return 3 - self.max_exponent + + @property + def max(self): + """ Maximum value representable. """ + return (1 - two**-(self.nmant+1))*two**self.max_exponent + + @property + def tiny(self): + """ The minimum positive normalized value. """ + # See C macros: FLT_MIN, DBL_MIN, LDBL_MIN + # or C++'s ``std::numeric_limits::min`` + # or numpy.finfo(dtype).tiny + return two**(self.min_exponent - 1) + + + @property + def eps(self): + """ Difference between 1.0 and the next representable value. """ + return two**(-self.nmant) + + @property + def dig(self): + """ Number of decimal digits that are guaranteed to be preserved in text. + + When converting text -> float -> text, you are guaranteed that at least ``dig`` + number of digits are preserved with respect to rounding or overflow. + """ + from sympy.functions import floor, log + return floor(self.nmant * log(2)/log(10)) + + @property + def decimal_dig(self): + """ Number of digits needed to store & load without loss. + + Explanation + =========== + + Number of decimal digits needed to guarantee that two consecutive conversions + (float -> text -> float) to be idempotent. This is useful when one do not want + to loose precision due to rounding errors when storing a floating point value + as text. + """ + from sympy.functions import ceiling, log + return ceiling((self.nmant + 1) * log(2)/log(10) + 1) + + def cast_nocheck(self, value): + """ Casts without checking if out of bounds or subnormal. """ + if value == oo: # float(oo) or oo + return float(oo) + elif value == -oo: # float(-oo) or -oo + return float(-oo) + return Float(str(sympify(value).evalf(self.decimal_dig)), self.decimal_dig) + + def _check(self, value): + if value < -self.max: + raise ValueError("Value is too small: %d < %d" % (value, -self.max)) + if value > self.max: + raise ValueError("Value is too big: %d > %d" % (value, self.max)) + if abs(value) < self.tiny: + raise ValueError("Smallest (absolute) value for data type bigger than new value.") + +class ComplexBaseType(FloatBaseType): + + __slots__ = () + + def cast_nocheck(self, value): + """ Casts without checking if out of bounds or subnormal. """ + from sympy.functions import re, im + return ( + super().cast_nocheck(re(value)) + + super().cast_nocheck(im(value))*1j + ) + + def _check(self, value): + from sympy.functions import re, im + super()._check(re(value)) + super()._check(im(value)) + + +class ComplexType(ComplexBaseType, FloatType): + """ Represents a complex floating point number. """ + __slots__ = () + + +# NumPy types: +intc = IntBaseType('intc') +intp = IntBaseType('intp') +int8 = SignedIntType('int8', 8) +int16 = SignedIntType('int16', 16) +int32 = SignedIntType('int32', 32) +int64 = SignedIntType('int64', 64) +uint8 = UnsignedIntType('uint8', 8) +uint16 = UnsignedIntType('uint16', 16) +uint32 = UnsignedIntType('uint32', 32) +uint64 = UnsignedIntType('uint64', 64) +float16 = FloatType('float16', 16, nexp=5, nmant=10) # IEEE 754 binary16, Half precision +float32 = FloatType('float32', 32, nexp=8, nmant=23) # IEEE 754 binary32, Single precision +float64 = FloatType('float64', 64, nexp=11, nmant=52) # IEEE 754 binary64, Double precision +float80 = FloatType('float80', 80, nexp=15, nmant=63) # x86 extended precision (1 integer part bit), "long double" +float128 = FloatType('float128', 128, nexp=15, nmant=112) # IEEE 754 binary128, Quadruple precision +float256 = FloatType('float256', 256, nexp=19, nmant=236) # IEEE 754 binary256, Octuple precision + +complex64 = ComplexType('complex64', nbits=64, **float32.kwargs(exclude=('name', 'nbits'))) +complex128 = ComplexType('complex128', nbits=128, **float64.kwargs(exclude=('name', 'nbits'))) + +# Generic types (precision may be chosen by code printers): +untyped = Type('untyped') +real = FloatBaseType('real') +integer = IntBaseType('integer') +complex_ = ComplexBaseType('complex') +bool_ = Type('bool') + + +class Attribute(Token): + """ Attribute (possibly parametrized) + + For use with :class:`sympy.codegen.ast.Node` (which takes instances of + ``Attribute`` as ``attrs``). + + Parameters + ========== + + name : str + parameters : Tuple + + Examples + ======== + + >>> from sympy.codegen.ast import Attribute + >>> volatile = Attribute('volatile') + >>> volatile + volatile + >>> print(repr(volatile)) + Attribute(String('volatile')) + >>> a = Attribute('foo', [1, 2, 3]) + >>> a + foo(1, 2, 3) + >>> a.parameters == (1, 2, 3) + True + """ + __slots__ = _fields = ('name', 'parameters') + defaults = {'parameters': Tuple()} + + _construct_name = String + _construct_parameters = staticmethod(_mk_Tuple) + + def _sympystr(self, printer, *args, **kwargs): + result = str(self.name) + if self.parameters: + result += '(%s)' % ', '.join((printer._print( + arg, *args, **kwargs) for arg in self.parameters)) + return result + +value_const = Attribute('value_const') +pointer_const = Attribute('pointer_const') + + +class Variable(Node): + """ Represents a variable. + + Parameters + ========== + + symbol : Symbol + type : Type (optional) + Type of the variable. + attrs : iterable of Attribute instances + Will be stored as a Tuple. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.codegen.ast import Variable, float32, integer + >>> x = Symbol('x') + >>> v = Variable(x, type=float32) + >>> v.attrs + () + >>> v == Variable('x') + False + >>> v == Variable('x', type=float32) + True + >>> v + Variable(x, type=float32) + + One may also construct a ``Variable`` instance with the type deduced from + assumptions about the symbol using the ``deduced`` classmethod: + + >>> i = Symbol('i', integer=True) + >>> v = Variable.deduced(i) + >>> v.type == integer + True + >>> v == Variable('i') + False + >>> from sympy.codegen.ast import value_const + >>> value_const in v.attrs + False + >>> w = Variable('w', attrs=[value_const]) + >>> w + Variable(w, attrs=(value_const,)) + >>> value_const in w.attrs + True + >>> w.as_Declaration(value=42) + Declaration(Variable(w, value=42, attrs=(value_const,))) + + """ + + __slots__ = ('symbol', 'type', 'value') + _fields = __slots__ + Node._fields + + defaults = Node.defaults.copy() + defaults.update({'type': untyped, 'value': none}) + + _construct_symbol = staticmethod(sympify) + _construct_value = staticmethod(sympify) + + @classmethod + def deduced(cls, symbol, value=None, attrs=Tuple(), cast_check=True): + """ Alt. constructor with type deduction from ``Type.from_expr``. + + Deduces type primarily from ``symbol``, secondarily from ``value``. + + Parameters + ========== + + symbol : Symbol + value : expr + (optional) value of the variable. + attrs : iterable of Attribute instances + cast_check : bool + Whether to apply ``Type.cast_check`` on ``value``. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.codegen.ast import Variable, complex_ + >>> n = Symbol('n', integer=True) + >>> str(Variable.deduced(n).type) + 'integer' + >>> x = Symbol('x', real=True) + >>> v = Variable.deduced(x) + >>> v.type + real + >>> z = Symbol('z', complex=True) + >>> Variable.deduced(z).type == complex_ + True + + """ + if isinstance(symbol, Variable): + return symbol + + try: + type_ = Type.from_expr(symbol) + except ValueError: + type_ = Type.from_expr(value) + + if value is not None and cast_check: + value = type_.cast_check(value) + return cls(symbol, type=type_, value=value, attrs=attrs) + + def as_Declaration(self, **kwargs): + """ Convenience method for creating a Declaration instance. + + Explanation + =========== + + If the variable of the Declaration need to wrap a modified + variable keyword arguments may be passed (overriding e.g. + the ``value`` of the Variable instance). + + Examples + ======== + + >>> from sympy.codegen.ast import Variable, NoneToken + >>> x = Variable('x') + >>> decl1 = x.as_Declaration() + >>> # value is special NoneToken() which must be tested with == operator + >>> decl1.variable.value is None # won't work + False + >>> decl1.variable.value == None # not PEP-8 compliant + True + >>> decl1.variable.value == NoneToken() # OK + True + >>> decl2 = x.as_Declaration(value=42.0) + >>> decl2.variable.value == 42.0 + True + + """ + kw = self.kwargs() + kw.update(kwargs) + return Declaration(self.func(**kw)) + + def _relation(self, rhs, op): + try: + rhs = _sympify(rhs) + except SympifyError: + raise TypeError("Invalid comparison %s < %s" % (self, rhs)) + return op(self, rhs, evaluate=False) + + __lt__ = lambda self, other: self._relation(other, Lt) + __le__ = lambda self, other: self._relation(other, Le) + __ge__ = lambda self, other: self._relation(other, Ge) + __gt__ = lambda self, other: self._relation(other, Gt) + +class Pointer(Variable): + """ Represents a pointer. See ``Variable``. + + Examples + ======== + + Can create instances of ``Element``: + + >>> from sympy import Symbol + >>> from sympy.codegen.ast import Pointer + >>> i = Symbol('i', integer=True) + >>> p = Pointer('x') + >>> p[i+1] + Element(x, indices=(i + 1,)) + + """ + __slots__ = () + + def __getitem__(self, key): + try: + return Element(self.symbol, key) + except TypeError: + return Element(self.symbol, (key,)) + + +class Element(Token): + """ Element in (a possibly N-dimensional) array. + + Examples + ======== + + >>> from sympy.codegen.ast import Element + >>> elem = Element('x', 'ijk') + >>> elem.symbol.name == 'x' + True + >>> elem.indices + (i, j, k) + >>> from sympy import ccode + >>> ccode(elem) + 'x[i][j][k]' + >>> ccode(Element('x', 'ijk', strides='lmn', offset='o')) + 'x[i*l + j*m + k*n + o]' + + """ + __slots__ = _fields = ('symbol', 'indices', 'strides', 'offset') + defaults = {'strides': none, 'offset': none} + _construct_symbol = staticmethod(sympify) + _construct_indices = staticmethod(lambda arg: Tuple(*arg)) + _construct_strides = staticmethod(lambda arg: Tuple(*arg)) + _construct_offset = staticmethod(sympify) + + +class Declaration(Token): + """ Represents a variable declaration + + Parameters + ========== + + variable : Variable + + Examples + ======== + + >>> from sympy.codegen.ast import Declaration, NoneToken, untyped + >>> z = Declaration('z') + >>> z.variable.type == untyped + True + >>> # value is special NoneToken() which must be tested with == operator + >>> z.variable.value is None # won't work + False + >>> z.variable.value == None # not PEP-8 compliant + True + >>> z.variable.value == NoneToken() # OK + True + """ + __slots__ = _fields = ('variable',) + _construct_variable = Variable + + +class While(Token): + """ Represents a 'for-loop' in the code. + + Expressions are of the form: + "while condition: + body..." + + Parameters + ========== + + condition : expression convertible to Boolean + body : CodeBlock or iterable + When passed an iterable it is used to instantiate a CodeBlock. + + Examples + ======== + + >>> from sympy import symbols, Gt, Abs + >>> from sympy.codegen import aug_assign, Assignment, While + >>> x, dx = symbols('x dx') + >>> expr = 1 - x**2 + >>> whl = While(Gt(Abs(dx), 1e-9), [ + ... Assignment(dx, -expr/expr.diff(x)), + ... aug_assign(x, '+', dx) + ... ]) + + """ + __slots__ = _fields = ('condition', 'body') + _construct_condition = staticmethod(lambda cond: _sympify(cond)) + + @classmethod + def _construct_body(cls, itr): + if isinstance(itr, CodeBlock): + return itr + else: + return CodeBlock(*itr) + + +class Scope(Token): + """ Represents a scope in the code. + + Parameters + ========== + + body : CodeBlock or iterable + When passed an iterable it is used to instantiate a CodeBlock. + + """ + __slots__ = _fields = ('body',) + + @classmethod + def _construct_body(cls, itr): + if isinstance(itr, CodeBlock): + return itr + else: + return CodeBlock(*itr) + + +class Stream(Token): + """ Represents a stream. + + There are two predefined Stream instances ``stdout`` & ``stderr``. + + Parameters + ========== + + name : str + + Examples + ======== + + >>> from sympy import pycode, Symbol + >>> from sympy.codegen.ast import Print, stderr, QuotedString + >>> print(pycode(Print(['x'], file=stderr))) + print(x, file=sys.stderr) + >>> x = Symbol('x') + >>> print(pycode(Print([QuotedString('x')], file=stderr))) # print literally "x" + print("x", file=sys.stderr) + + """ + __slots__ = _fields = ('name',) + _construct_name = String + +stdout = Stream('stdout') +stderr = Stream('stderr') + + +class Print(Token): + r""" Represents print command in the code. + + Parameters + ========== + + formatstring : str + *args : Basic instances (or convertible to such through sympify) + + Examples + ======== + + >>> from sympy.codegen.ast import Print + >>> from sympy import pycode + >>> print(pycode(Print('x y'.split(), "coordinate: %12.5g %12.5g\\n"))) + print("coordinate: %12.5g %12.5g\n" % (x, y), end="") + + """ + + __slots__ = _fields = ('print_args', 'format_string', 'file') + defaults = {'format_string': none, 'file': none} + + _construct_print_args = staticmethod(_mk_Tuple) + _construct_format_string = QuotedString + _construct_file = Stream + + +class FunctionPrototype(Node): + """ Represents a function prototype + + Allows the user to generate forward declaration in e.g. C/C++. + + Parameters + ========== + + return_type : Type + name : str + parameters: iterable of Variable instances + attrs : iterable of Attribute instances + + Examples + ======== + + >>> from sympy import ccode, symbols + >>> from sympy.codegen.ast import real, FunctionPrototype + >>> x, y = symbols('x y', real=True) + >>> fp = FunctionPrototype(real, 'foo', [x, y]) + >>> ccode(fp) + 'double foo(double x, double y)' + + """ + + __slots__ = ('return_type', 'name', 'parameters') + _fields: tuple[str, ...] = __slots__ + Node._fields + + _construct_return_type = Type + _construct_name = String + + @staticmethod + def _construct_parameters(args): + def _var(arg): + if isinstance(arg, Declaration): + return arg.variable + elif isinstance(arg, Variable): + return arg + else: + return Variable.deduced(arg) + return Tuple(*map(_var, args)) + + @classmethod + def from_FunctionDefinition(cls, func_def): + if not isinstance(func_def, FunctionDefinition): + raise TypeError("func_def is not an instance of FunctionDefinition") + return cls(**func_def.kwargs(exclude=('body',))) + + +class FunctionDefinition(FunctionPrototype): + """ Represents a function definition in the code. + + Parameters + ========== + + return_type : Type + name : str + parameters: iterable of Variable instances + body : CodeBlock or iterable + attrs : iterable of Attribute instances + + Examples + ======== + + >>> from sympy import ccode, symbols + >>> from sympy.codegen.ast import real, FunctionPrototype + >>> x, y = symbols('x y', real=True) + >>> fp = FunctionPrototype(real, 'foo', [x, y]) + >>> ccode(fp) + 'double foo(double x, double y)' + >>> from sympy.codegen.ast import FunctionDefinition, Return + >>> body = [Return(x*y)] + >>> fd = FunctionDefinition.from_FunctionPrototype(fp, body) + >>> print(ccode(fd)) + double foo(double x, double y){ + return x*y; + } + """ + + __slots__ = ('body', ) + _fields = FunctionPrototype._fields[:-1] + __slots__ + Node._fields + + @classmethod + def _construct_body(cls, itr): + if isinstance(itr, CodeBlock): + return itr + else: + return CodeBlock(*itr) + + @classmethod + def from_FunctionPrototype(cls, func_proto, body): + if not isinstance(func_proto, FunctionPrototype): + raise TypeError("func_proto is not an instance of FunctionPrototype") + return cls(body=body, **func_proto.kwargs()) + + +class Return(Token): + """ Represents a return command in the code. + + Parameters + ========== + + return : Basic + + Examples + ======== + + >>> from sympy.codegen.ast import Return + >>> from sympy.printing.pycode import pycode + >>> from sympy import Symbol + >>> x = Symbol('x') + >>> print(pycode(Return(x))) + return x + + """ + __slots__ = _fields = ('return',) + _construct_return=staticmethod(_sympify) + + +class FunctionCall(Token, Expr): + """ Represents a call to a function in the code. + + Parameters + ========== + + name : str + function_args : Tuple + + Examples + ======== + + >>> from sympy.codegen.ast import FunctionCall + >>> from sympy import pycode + >>> fcall = FunctionCall('foo', 'bar baz'.split()) + >>> print(pycode(fcall)) + foo(bar, baz) + + """ + __slots__ = _fields = ('name', 'function_args') + + _construct_name = String + _construct_function_args = staticmethod(lambda args: Tuple(*args)) + + +class Raise(Token): + """ Prints as 'raise ...' in Python, 'throw ...' in C++""" + __slots__ = _fields = ('exception',) + + +class RuntimeError_(Token): + """ Represents 'std::runtime_error' in C++ and 'RuntimeError' in Python. + + Note that the latter is uncommon, and you might want to use e.g. ValueError. + """ + __slots__ = _fields = ('message',) + _construct_message = String diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cfunctions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cfunctions.py new file mode 100644 index 0000000000000000000000000000000000000000..7b79291f128aef1cb83b327782840508e59a9cc8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cfunctions.py @@ -0,0 +1,558 @@ +""" +This module contains SymPy functions mathcin corresponding to special math functions in the +C standard library (since C99, also available in C++11). + +The functions defined in this module allows the user to express functions such as ``expm1`` +as a SymPy function for symbolic manipulation. + +""" +from sympy.core.function import ArgumentIndexError, Function +from sympy.core.numbers import Rational +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.logic.boolalg import BooleanFunction, true, false + +def _expm1(x): + return exp(x) - S.One + + +class expm1(Function): + """ + Represents the exponential function minus one. + + Explanation + =========== + + The benefit of using ``expm1(x)`` over ``exp(x) - 1`` + is that the latter is prone to cancellation under finite precision + arithmetic when x is close to zero. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cfunctions import expm1 + >>> '%.0e' % expm1(1e-99).evalf() + '1e-99' + >>> from math import exp + >>> exp(1e-99) - 1 + 0.0 + >>> expm1(x).diff(x) + exp(x) + + See Also + ======== + + log1p + """ + nargs = 1 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return exp(*self.args) + else: + raise ArgumentIndexError(self, argindex) + + def _eval_expand_func(self, **hints): + return _expm1(*self.args) + + def _eval_rewrite_as_exp(self, arg, **kwargs): + return exp(arg) - S.One + + _eval_rewrite_as_tractable = _eval_rewrite_as_exp + + @classmethod + def eval(cls, arg): + exp_arg = exp.eval(arg) + if exp_arg is not None: + return exp_arg - S.One + + def _eval_is_real(self): + return self.args[0].is_real + + def _eval_is_finite(self): + return self.args[0].is_finite + + +def _log1p(x): + return log(x + S.One) + + +class log1p(Function): + """ + Represents the natural logarithm of a number plus one. + + Explanation + =========== + + The benefit of using ``log1p(x)`` over ``log(x + 1)`` + is that the latter is prone to cancellation under finite precision + arithmetic when x is close to zero. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cfunctions import log1p + >>> from sympy import expand_log + >>> '%.0e' % expand_log(log1p(1e-99)).evalf() + '1e-99' + >>> from math import log + >>> log(1 + 1e-99) + 0.0 + >>> log1p(x).diff(x) + 1/(x + 1) + + See Also + ======== + + expm1 + """ + nargs = 1 + + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return S.One/(self.args[0] + S.One) + else: + raise ArgumentIndexError(self, argindex) + + + def _eval_expand_func(self, **hints): + return _log1p(*self.args) + + def _eval_rewrite_as_log(self, arg, **kwargs): + return _log1p(arg) + + _eval_rewrite_as_tractable = _eval_rewrite_as_log + + @classmethod + def eval(cls, arg): + if arg.is_Rational: + return log(arg + S.One) + elif not arg.is_Float: # not safe to add 1 to Float + return log.eval(arg + S.One) + elif arg.is_number: + return log(Rational(arg) + S.One) + + def _eval_is_real(self): + return (self.args[0] + S.One).is_nonnegative + + def _eval_is_finite(self): + if (self.args[0] + S.One).is_zero: + return False + return self.args[0].is_finite + + def _eval_is_positive(self): + return self.args[0].is_positive + + def _eval_is_zero(self): + return self.args[0].is_zero + + def _eval_is_nonnegative(self): + return self.args[0].is_nonnegative + +_Two = S(2) + +def _exp2(x): + return Pow(_Two, x) + +class exp2(Function): + """ + Represents the exponential function with base two. + + Explanation + =========== + + The benefit of using ``exp2(x)`` over ``2**x`` + is that the latter is not as efficient under finite precision + arithmetic. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cfunctions import exp2 + >>> exp2(2).evalf() == 4.0 + True + >>> exp2(x).diff(x) + log(2)*exp2(x) + + See Also + ======== + + log2 + """ + nargs = 1 + + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return self*log(_Two) + else: + raise ArgumentIndexError(self, argindex) + + def _eval_rewrite_as_Pow(self, arg, **kwargs): + return _exp2(arg) + + _eval_rewrite_as_tractable = _eval_rewrite_as_Pow + + def _eval_expand_func(self, **hints): + return _exp2(*self.args) + + @classmethod + def eval(cls, arg): + if arg.is_number: + return _exp2(arg) + + +def _log2(x): + return log(x)/log(_Two) + + +class log2(Function): + """ + Represents the logarithm function with base two. + + Explanation + =========== + + The benefit of using ``log2(x)`` over ``log(x)/log(2)`` + is that the latter is not as efficient under finite precision + arithmetic. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cfunctions import log2 + >>> log2(4).evalf() == 2.0 + True + >>> log2(x).diff(x) + 1/(x*log(2)) + + See Also + ======== + + exp2 + log10 + """ + nargs = 1 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return S.One/(log(_Two)*self.args[0]) + else: + raise ArgumentIndexError(self, argindex) + + + @classmethod + def eval(cls, arg): + if arg.is_number: + result = log.eval(arg, base=_Two) + if result.is_Atom: + return result + elif arg.is_Pow and arg.base == _Two: + return arg.exp + + def _eval_evalf(self, *args, **kwargs): + return self.rewrite(log).evalf(*args, **kwargs) + + def _eval_expand_func(self, **hints): + return _log2(*self.args) + + def _eval_rewrite_as_log(self, arg, **kwargs): + return _log2(arg) + + _eval_rewrite_as_tractable = _eval_rewrite_as_log + + +def _fma(x, y, z): + return x*y + z + + +class fma(Function): + """ + Represents "fused multiply add". + + Explanation + =========== + + The benefit of using ``fma(x, y, z)`` over ``x*y + z`` + is that, under finite precision arithmetic, the former is + supported by special instructions on some CPUs. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.codegen.cfunctions import fma + >>> fma(x, y, z).diff(x) + y + + """ + nargs = 3 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex in (1, 2): + return self.args[2 - argindex] + elif argindex == 3: + return S.One + else: + raise ArgumentIndexError(self, argindex) + + + def _eval_expand_func(self, **hints): + return _fma(*self.args) + + def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): + return _fma(arg) + + +_Ten = S(10) + + +def _log10(x): + return log(x)/log(_Ten) + + +class log10(Function): + """ + Represents the logarithm function with base ten. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cfunctions import log10 + >>> log10(100).evalf() == 2.0 + True + >>> log10(x).diff(x) + 1/(x*log(10)) + + See Also + ======== + + log2 + """ + nargs = 1 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return S.One/(log(_Ten)*self.args[0]) + else: + raise ArgumentIndexError(self, argindex) + + + @classmethod + def eval(cls, arg): + if arg.is_number: + result = log.eval(arg, base=_Ten) + if result.is_Atom: + return result + elif arg.is_Pow and arg.base == _Ten: + return arg.exp + + def _eval_expand_func(self, **hints): + return _log10(*self.args) + + def _eval_rewrite_as_log(self, arg, **kwargs): + return _log10(arg) + + _eval_rewrite_as_tractable = _eval_rewrite_as_log + + +def _Sqrt(x): + return Pow(x, S.Half) + + +class Sqrt(Function): # 'sqrt' already defined in sympy.functions.elementary.miscellaneous + """ + Represents the square root function. + + Explanation + =========== + + The reason why one would use ``Sqrt(x)`` over ``sqrt(x)`` + is that the latter is internally represented as ``Pow(x, S.Half)`` which + may not be what one wants when doing code-generation. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cfunctions import Sqrt + >>> Sqrt(x) + Sqrt(x) + >>> Sqrt(x).diff(x) + 1/(2*sqrt(x)) + + See Also + ======== + + Cbrt + """ + nargs = 1 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return Pow(self.args[0], Rational(-1, 2))/_Two + else: + raise ArgumentIndexError(self, argindex) + + def _eval_expand_func(self, **hints): + return _Sqrt(*self.args) + + def _eval_rewrite_as_Pow(self, arg, **kwargs): + return _Sqrt(arg) + + _eval_rewrite_as_tractable = _eval_rewrite_as_Pow + + +def _Cbrt(x): + return Pow(x, Rational(1, 3)) + + +class Cbrt(Function): # 'cbrt' already defined in sympy.functions.elementary.miscellaneous + """ + Represents the cube root function. + + Explanation + =========== + + The reason why one would use ``Cbrt(x)`` over ``cbrt(x)`` + is that the latter is internally represented as ``Pow(x, Rational(1, 3))`` which + may not be what one wants when doing code-generation. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cfunctions import Cbrt + >>> Cbrt(x) + Cbrt(x) + >>> Cbrt(x).diff(x) + 1/(3*x**(2/3)) + + See Also + ======== + + Sqrt + """ + nargs = 1 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return Pow(self.args[0], Rational(-_Two/3))/3 + else: + raise ArgumentIndexError(self, argindex) + + + def _eval_expand_func(self, **hints): + return _Cbrt(*self.args) + + def _eval_rewrite_as_Pow(self, arg, **kwargs): + return _Cbrt(arg) + + _eval_rewrite_as_tractable = _eval_rewrite_as_Pow + + +def _hypot(x, y): + return sqrt(Pow(x, 2) + Pow(y, 2)) + + +class hypot(Function): + """ + Represents the hypotenuse function. + + Explanation + =========== + + The hypotenuse function is provided by e.g. the math library + in the C99 standard, hence one may want to represent the function + symbolically when doing code-generation. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.codegen.cfunctions import hypot + >>> hypot(3, 4).evalf() == 5.0 + True + >>> hypot(x, y) + hypot(x, y) + >>> hypot(x, y).diff(x) + x/hypot(x, y) + + """ + nargs = 2 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex in (1, 2): + return 2*self.args[argindex-1]/(_Two*self.func(*self.args)) + else: + raise ArgumentIndexError(self, argindex) + + + def _eval_expand_func(self, **hints): + return _hypot(*self.args) + + def _eval_rewrite_as_Pow(self, arg, **kwargs): + return _hypot(arg) + + _eval_rewrite_as_tractable = _eval_rewrite_as_Pow + + +class isnan(BooleanFunction): + nargs = 1 + + @classmethod + def eval(cls, arg): + if arg is S.NaN: + return true + elif arg.is_number: + return false + else: + return None + + +class isinf(BooleanFunction): + nargs = 1 + + @classmethod + def eval(cls, arg): + if arg.is_infinite: + return true + elif arg.is_finite: + return false + else: + return None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cnodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cnodes.py new file mode 100644 index 0000000000000000000000000000000000000000..dd2a324ee49cabcd42e99ca5d8e5379cc9262c4e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cnodes.py @@ -0,0 +1,156 @@ +""" +AST nodes specific to the C family of languages +""" + +from sympy.codegen.ast import ( + Attribute, Declaration, Node, String, Token, Type, none, + FunctionCall, CodeBlock + ) +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.sympify import sympify + +void = Type('void') + +restrict = Attribute('restrict') # guarantees no pointer aliasing +volatile = Attribute('volatile') +static = Attribute('static') + + +def alignof(arg): + """ Generate of FunctionCall instance for calling 'alignof' """ + return FunctionCall('alignof', [String(arg) if isinstance(arg, str) else arg]) + + +def sizeof(arg): + """ Generate of FunctionCall instance for calling 'sizeof' + + Examples + ======== + + >>> from sympy.codegen.ast import real + >>> from sympy.codegen.cnodes import sizeof + >>> from sympy import ccode + >>> ccode(sizeof(real)) + 'sizeof(double)' + """ + return FunctionCall('sizeof', [String(arg) if isinstance(arg, str) else arg]) + + +class CommaOperator(Basic): + """ Represents the comma operator in C """ + def __new__(cls, *args): + return Basic.__new__(cls, *[sympify(arg) for arg in args]) + + +class Label(Node): + """ Label for use with e.g. goto statement. + + Examples + ======== + + >>> from sympy import ccode, Symbol + >>> from sympy.codegen.cnodes import Label, PreIncrement + >>> print(ccode(Label('foo'))) + foo: + >>> print(ccode(Label('bar', [PreIncrement(Symbol('a'))]))) + bar: + ++(a); + + """ + __slots__ = _fields = ('name', 'body') + defaults = {'body': none} + _construct_name = String + + @classmethod + def _construct_body(cls, itr): + if isinstance(itr, CodeBlock): + return itr + else: + return CodeBlock(*itr) + + +class goto(Token): + """ Represents goto in C """ + __slots__ = _fields = ('label',) + _construct_label = Label + + +class PreDecrement(Basic): + """ Represents the pre-decrement operator + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cnodes import PreDecrement + >>> from sympy import ccode + >>> ccode(PreDecrement(x)) + '--(x)' + + """ + nargs = 1 + + +class PostDecrement(Basic): + """ Represents the post-decrement operator + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cnodes import PostDecrement + >>> from sympy import ccode + >>> ccode(PostDecrement(x)) + '(x)--' + + """ + nargs = 1 + + +class PreIncrement(Basic): + """ Represents the pre-increment operator + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cnodes import PreIncrement + >>> from sympy import ccode + >>> ccode(PreIncrement(x)) + '++(x)' + + """ + nargs = 1 + + +class PostIncrement(Basic): + """ Represents the post-increment operator + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.codegen.cnodes import PostIncrement + >>> from sympy import ccode + >>> ccode(PostIncrement(x)) + '(x)++' + + """ + nargs = 1 + + +class struct(Node): + """ Represents a struct in C """ + __slots__ = _fields = ('name', 'declarations') + defaults = {'name': none} + _construct_name = String + + @classmethod + def _construct_declarations(cls, args): + return Tuple(*[Declaration(arg) for arg in args]) + + +class union(struct): + """ Represents a union in C """ + __slots__ = () diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cutils.py new file mode 100644 index 0000000000000000000000000000000000000000..2182ac1f3455da490a0bb57f8d6731fe8a29a232 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cutils.py @@ -0,0 +1,8 @@ +from sympy.printing.c import C99CodePrinter + +def render_as_source_file(content, Printer=C99CodePrinter, settings=None): + """ Renders a C source file (with required #include statements) """ + printer = Printer(settings or {}) + code_str = printer.doprint(content) + includes = '\n'.join(['#include <%s>' % h for h in printer.headers]) + return includes + '\n\n' + code_str diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cxxnodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cxxnodes.py new file mode 100644 index 0000000000000000000000000000000000000000..7f7aafd01ab2de99ad0f668275889863fc73f5aa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/cxxnodes.py @@ -0,0 +1,14 @@ +""" +AST nodes specific to C++. +""" + +from sympy.codegen.ast import Attribute, String, Token, Type, none + +class using(Token): + """ Represents a 'using' statement in C++ """ + __slots__ = _fields = ('type', 'alias') + defaults = {'alias': none} + _construct_type = Type + _construct_alias = String + +constexpr = Attribute('constexpr') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/fnodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/fnodes.py new file mode 100644 index 0000000000000000000000000000000000000000..8b972fcfe4d4de4cfe74d75705f42c5e112a9b43 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/fnodes.py @@ -0,0 +1,658 @@ +""" +AST nodes specific to Fortran. + +The functions defined in this module allows the user to express functions such as ``dsign`` +as a SymPy function for symbolic manipulation. +""" + +from __future__ import annotations +from sympy.codegen.ast import ( + Attribute, CodeBlock, FunctionCall, Node, none, String, + Token, _mk_Tuple, Variable +) +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import Function +from sympy.core.numbers import Float, Integer +from sympy.core.symbol import Str +from sympy.core.sympify import sympify +from sympy.logic import true, false +from sympy.utilities.iterables import iterable + + + +pure = Attribute('pure') +elemental = Attribute('elemental') # (all elemental procedures are also pure) + +intent_in = Attribute('intent_in') +intent_out = Attribute('intent_out') +intent_inout = Attribute('intent_inout') + +allocatable = Attribute('allocatable') + +class Program(Token): + """ Represents a 'program' block in Fortran. + + Examples + ======== + + >>> from sympy.codegen.ast import Print + >>> from sympy.codegen.fnodes import Program + >>> prog = Program('myprogram', [Print([42])]) + >>> from sympy import fcode + >>> print(fcode(prog, source_format='free')) + program myprogram + print *, 42 + end program + + """ + __slots__ = _fields = ('name', 'body') + _construct_name = String + _construct_body = staticmethod(lambda body: CodeBlock(*body)) + + +class use_rename(Token): + """ Represents a renaming in a use statement in Fortran. + + Examples + ======== + + >>> from sympy.codegen.fnodes import use_rename, use + >>> from sympy import fcode + >>> ren = use_rename("thingy", "convolution2d") + >>> print(fcode(ren, source_format='free')) + thingy => convolution2d + >>> full = use('signallib', only=['snr', ren]) + >>> print(fcode(full, source_format='free')) + use signallib, only: snr, thingy => convolution2d + + """ + __slots__ = _fields = ('local', 'original') + _construct_local = String + _construct_original = String + +def _name(arg): + if hasattr(arg, 'name'): + return arg.name + else: + return String(arg) + +class use(Token): + """ Represents a use statement in Fortran. + + Examples + ======== + + >>> from sympy.codegen.fnodes import use + >>> from sympy import fcode + >>> fcode(use('signallib'), source_format='free') + 'use signallib' + >>> fcode(use('signallib', [('metric', 'snr')]), source_format='free') + 'use signallib, metric => snr' + >>> fcode(use('signallib', only=['snr', 'convolution2d']), source_format='free') + 'use signallib, only: snr, convolution2d' + + """ + __slots__ = _fields = ('namespace', 'rename', 'only') + defaults = {'rename': none, 'only': none} + _construct_namespace = staticmethod(_name) + _construct_rename = staticmethod(lambda args: Tuple(*[arg if isinstance(arg, use_rename) else use_rename(*arg) for arg in args])) + _construct_only = staticmethod(lambda args: Tuple(*[arg if isinstance(arg, use_rename) else _name(arg) for arg in args])) + + +class Module(Token): + """ Represents a module in Fortran. + + Examples + ======== + + >>> from sympy.codegen.fnodes import Module + >>> from sympy import fcode + >>> print(fcode(Module('signallib', ['implicit none'], []), source_format='free')) + module signallib + implicit none + + contains + + + end module + + """ + __slots__ = _fields = ('name', 'declarations', 'definitions') + defaults = {'declarations': Tuple()} + _construct_name = String + + @classmethod + def _construct_declarations(cls, args): + args = [Str(arg) if isinstance(arg, str) else arg for arg in args] + return CodeBlock(*args) + + _construct_definitions = staticmethod(lambda arg: CodeBlock(*arg)) + + +class Subroutine(Node): + """ Represents a subroutine in Fortran. + + Examples + ======== + + >>> from sympy import fcode, symbols + >>> from sympy.codegen.ast import Print + >>> from sympy.codegen.fnodes import Subroutine + >>> x, y = symbols('x y', real=True) + >>> sub = Subroutine('mysub', [x, y], [Print([x**2 + y**2, x*y])]) + >>> print(fcode(sub, source_format='free', standard=2003)) + subroutine mysub(x, y) + real*8 :: x + real*8 :: y + print *, x**2 + y**2, x*y + end subroutine + + """ + __slots__ = ('name', 'parameters', 'body') + _fields = __slots__ + Node._fields + _construct_name = String + _construct_parameters = staticmethod(lambda params: Tuple(*map(Variable.deduced, params))) + + @classmethod + def _construct_body(cls, itr): + if isinstance(itr, CodeBlock): + return itr + else: + return CodeBlock(*itr) + +class SubroutineCall(Token): + """ Represents a call to a subroutine in Fortran. + + Examples + ======== + + >>> from sympy.codegen.fnodes import SubroutineCall + >>> from sympy import fcode + >>> fcode(SubroutineCall('mysub', 'x y'.split())) + ' call mysub(x, y)' + + """ + __slots__ = _fields = ('name', 'subroutine_args') + _construct_name = staticmethod(_name) + _construct_subroutine_args = staticmethod(_mk_Tuple) + + +class Do(Token): + """ Represents a Do loop in in Fortran. + + Examples + ======== + + >>> from sympy import fcode, symbols + >>> from sympy.codegen.ast import aug_assign, Print + >>> from sympy.codegen.fnodes import Do + >>> i, n = symbols('i n', integer=True) + >>> r = symbols('r', real=True) + >>> body = [aug_assign(r, '+', 1/i), Print([i, r])] + >>> do1 = Do(body, i, 1, n) + >>> print(fcode(do1, source_format='free')) + do i = 1, n + r = r + 1d0/i + print *, i, r + end do + >>> do2 = Do(body, i, 1, n, 2) + >>> print(fcode(do2, source_format='free')) + do i = 1, n, 2 + r = r + 1d0/i + print *, i, r + end do + + """ + + __slots__ = _fields = ('body', 'counter', 'first', 'last', 'step', 'concurrent') + defaults = {'step': Integer(1), 'concurrent': false} + _construct_body = staticmethod(lambda body: CodeBlock(*body)) + _construct_counter = staticmethod(sympify) + _construct_first = staticmethod(sympify) + _construct_last = staticmethod(sympify) + _construct_step = staticmethod(sympify) + _construct_concurrent = staticmethod(lambda arg: true if arg else false) + + +class ArrayConstructor(Token): + """ Represents an array constructor. + + Examples + ======== + + >>> from sympy import fcode + >>> from sympy.codegen.fnodes import ArrayConstructor + >>> ac = ArrayConstructor([1, 2, 3]) + >>> fcode(ac, standard=95, source_format='free') + '(/1, 2, 3/)' + >>> fcode(ac, standard=2003, source_format='free') + '[1, 2, 3]' + + """ + __slots__ = _fields = ('elements',) + _construct_elements = staticmethod(_mk_Tuple) + + +class ImpliedDoLoop(Token): + """ Represents an implied do loop in Fortran. + + Examples + ======== + + >>> from sympy import Symbol, fcode + >>> from sympy.codegen.fnodes import ImpliedDoLoop, ArrayConstructor + >>> i = Symbol('i', integer=True) + >>> idl = ImpliedDoLoop(i**3, i, -3, 3, 2) # -27, -1, 1, 27 + >>> ac = ArrayConstructor([-28, idl, 28]) # -28, -27, -1, 1, 27, 28 + >>> fcode(ac, standard=2003, source_format='free') + '[-28, (i**3, i = -3, 3, 2), 28]' + + """ + __slots__ = _fields = ('expr', 'counter', 'first', 'last', 'step') + defaults = {'step': Integer(1)} + _construct_expr = staticmethod(sympify) + _construct_counter = staticmethod(sympify) + _construct_first = staticmethod(sympify) + _construct_last = staticmethod(sympify) + _construct_step = staticmethod(sympify) + + +class Extent(Basic): + """ Represents a dimension extent. + + Examples + ======== + + >>> from sympy.codegen.fnodes import Extent + >>> e = Extent(-3, 3) # -3, -2, -1, 0, 1, 2, 3 + >>> from sympy import fcode + >>> fcode(e, source_format='free') + '-3:3' + >>> from sympy.codegen.ast import Variable, real + >>> from sympy.codegen.fnodes import dimension, intent_out + >>> dim = dimension(e, e) + >>> arr = Variable('x', real, attrs=[dim, intent_out]) + >>> fcode(arr.as_Declaration(), source_format='free', standard=2003) + 'real*8, dimension(-3:3, -3:3), intent(out) :: x' + + """ + def __new__(cls, *args): + if len(args) == 2: + low, high = args + return Basic.__new__(cls, sympify(low), sympify(high)) + elif len(args) == 0 or (len(args) == 1 and args[0] in (':', None)): + return Basic.__new__(cls) # assumed shape + else: + raise ValueError("Expected 0 or 2 args (or one argument == None or ':')") + + def _sympystr(self, printer): + if len(self.args) == 0: + return ':' + return ":".join(str(arg) for arg in self.args) + +assumed_extent = Extent() # or Extent(':'), Extent(None) + + +def dimension(*args): + """ Creates a 'dimension' Attribute with (up to 7) extents. + + Examples + ======== + + >>> from sympy import fcode + >>> from sympy.codegen.fnodes import dimension, intent_in + >>> dim = dimension('2', ':') # 2 rows, runtime determined number of columns + >>> from sympy.codegen.ast import Variable, integer + >>> arr = Variable('a', integer, attrs=[dim, intent_in]) + >>> fcode(arr.as_Declaration(), source_format='free', standard=2003) + 'integer*4, dimension(2, :), intent(in) :: a' + + """ + if len(args) > 7: + raise ValueError("Fortran only supports up to 7 dimensional arrays") + parameters = [] + for arg in args: + if isinstance(arg, Extent): + parameters.append(arg) + elif isinstance(arg, str): + if arg == ':': + parameters.append(Extent()) + else: + parameters.append(String(arg)) + elif iterable(arg): + parameters.append(Extent(*arg)) + else: + parameters.append(sympify(arg)) + if len(args) == 0: + raise ValueError("Need at least one dimension") + return Attribute('dimension', parameters) + + +assumed_size = dimension('*') + +def array(symbol, dim, intent=None, *, attrs=(), value=None, type=None): + """ Convenience function for creating a Variable instance for a Fortran array. + + Parameters + ========== + + symbol : symbol + dim : Attribute or iterable + If dim is an ``Attribute`` it need to have the name 'dimension'. If it is + not an ``Attribute``, then it is passed to :func:`dimension` as ``*dim`` + intent : str + One of: 'in', 'out', 'inout' or None + \\*\\*kwargs: + Keyword arguments for ``Variable`` ('type' & 'value') + + Examples + ======== + + >>> from sympy import fcode + >>> from sympy.codegen.ast import integer, real + >>> from sympy.codegen.fnodes import array + >>> arr = array('a', '*', 'in', type=integer) + >>> print(fcode(arr.as_Declaration(), source_format='free', standard=2003)) + integer*4, dimension(*), intent(in) :: a + >>> x = array('x', [3, ':', ':'], intent='out', type=real) + >>> print(fcode(x.as_Declaration(value=1), source_format='free', standard=2003)) + real*8, dimension(3, :, :), intent(out) :: x = 1 + + """ + if isinstance(dim, Attribute): + if str(dim.name) != 'dimension': + raise ValueError("Got an unexpected Attribute argument as dim: %s" % str(dim)) + else: + dim = dimension(*dim) + + attrs = list(attrs) + [dim] + if intent is not None: + if intent not in (intent_in, intent_out, intent_inout): + intent = {'in': intent_in, 'out': intent_out, 'inout': intent_inout}[intent] + attrs.append(intent) + if type is None: + return Variable.deduced(symbol, value=value, attrs=attrs) + else: + return Variable(symbol, type, value=value, attrs=attrs) + +def _printable(arg): + return String(arg) if isinstance(arg, str) else sympify(arg) + + +def allocated(array): + """ Creates an AST node for a function call to Fortran's "allocated(...)" + + Examples + ======== + + >>> from sympy import fcode + >>> from sympy.codegen.fnodes import allocated + >>> alloc = allocated('x') + >>> fcode(alloc, source_format='free') + 'allocated(x)' + + """ + return FunctionCall('allocated', [_printable(array)]) + + +def lbound(array, dim=None, kind=None): + """ Creates an AST node for a function call to Fortran's "lbound(...)" + + Parameters + ========== + + array : Symbol or String + dim : expr + kind : expr + + Examples + ======== + + >>> from sympy import fcode + >>> from sympy.codegen.fnodes import lbound + >>> lb = lbound('arr', dim=2) + >>> fcode(lb, source_format='free') + 'lbound(arr, 2)' + + """ + return FunctionCall( + 'lbound', + [_printable(array)] + + ([_printable(dim)] if dim else []) + + ([_printable(kind)] if kind else []) + ) + + +def ubound(array, dim=None, kind=None): + return FunctionCall( + 'ubound', + [_printable(array)] + + ([_printable(dim)] if dim else []) + + ([_printable(kind)] if kind else []) + ) + + +def shape(source, kind=None): + """ Creates an AST node for a function call to Fortran's "shape(...)" + + Parameters + ========== + + source : Symbol or String + kind : expr + + Examples + ======== + + >>> from sympy import fcode + >>> from sympy.codegen.fnodes import shape + >>> shp = shape('x') + >>> fcode(shp, source_format='free') + 'shape(x)' + + """ + return FunctionCall( + 'shape', + [_printable(source)] + + ([_printable(kind)] if kind else []) + ) + + +def size(array, dim=None, kind=None): + """ Creates an AST node for a function call to Fortran's "size(...)" + + Examples + ======== + + >>> from sympy import fcode, Symbol + >>> from sympy.codegen.ast import FunctionDefinition, real, Return + >>> from sympy.codegen.fnodes import array, sum_, size + >>> a = Symbol('a', real=True) + >>> body = [Return((sum_(a**2)/size(a))**.5)] + >>> arr = array(a, dim=[':'], intent='in') + >>> fd = FunctionDefinition(real, 'rms', [arr], body) + >>> print(fcode(fd, source_format='free', standard=2003)) + real*8 function rms(a) + real*8, dimension(:), intent(in) :: a + rms = sqrt(sum(a**2)*1d0/size(a)) + end function + + """ + return FunctionCall( + 'size', + [_printable(array)] + + ([_printable(dim)] if dim else []) + + ([_printable(kind)] if kind else []) + ) + + +def reshape(source, shape, pad=None, order=None): + """ Creates an AST node for a function call to Fortran's "reshape(...)" + + Parameters + ========== + + source : Symbol or String + shape : ArrayExpr + + """ + return FunctionCall( + 'reshape', + [_printable(source), _printable(shape)] + + ([_printable(pad)] if pad else []) + + ([_printable(order)] if pad else []) + ) + + +def bind_C(name=None): + """ Creates an Attribute ``bind_C`` with a name. + + Parameters + ========== + + name : str + + Examples + ======== + + >>> from sympy import fcode, Symbol + >>> from sympy.codegen.ast import FunctionDefinition, real, Return + >>> from sympy.codegen.fnodes import array, sum_, bind_C + >>> a = Symbol('a', real=True) + >>> s = Symbol('s', integer=True) + >>> arr = array(a, dim=[s], intent='in') + >>> body = [Return((sum_(a**2)/s)**.5)] + >>> fd = FunctionDefinition(real, 'rms', [arr, s], body, attrs=[bind_C('rms')]) + >>> print(fcode(fd, source_format='free', standard=2003)) + real*8 function rms(a, s) bind(C, name="rms") + real*8, dimension(s), intent(in) :: a + integer*4 :: s + rms = sqrt(sum(a**2)/s) + end function + + """ + return Attribute('bind_C', [String(name)] if name else []) + +class GoTo(Token): + """ Represents a goto statement in Fortran + + Examples + ======== + + >>> from sympy.codegen.fnodes import GoTo + >>> go = GoTo([10, 20, 30], 'i') + >>> from sympy import fcode + >>> fcode(go, source_format='free') + 'go to (10, 20, 30), i' + + """ + __slots__ = _fields = ('labels', 'expr') + defaults = {'expr': none} + _construct_labels = staticmethod(_mk_Tuple) + _construct_expr = staticmethod(sympify) + + +class FortranReturn(Token): + """ AST node explicitly mapped to a fortran "return". + + Explanation + =========== + + Because a return statement in fortran is different from C, and + in order to aid reuse of our codegen ASTs the ordinary + ``.codegen.ast.Return`` is interpreted as assignment to + the result variable of the function. If one for some reason needs + to generate a fortran RETURN statement, this node should be used. + + Examples + ======== + + >>> from sympy.codegen.fnodes import FortranReturn + >>> from sympy import fcode + >>> fcode(FortranReturn('x')) + ' return x' + + """ + __slots__ = _fields = ('return_value',) + defaults = {'return_value': none} + _construct_return_value = staticmethod(sympify) + + +class FFunction(Function): + _required_standard = 77 + + def _fcode(self, printer): + name = self.__class__.__name__ + if printer._settings['standard'] < self._required_standard: + raise NotImplementedError("%s requires Fortran %d or newer" % + (name, self._required_standard)) + return '{}({})'.format(name, ', '.join(map(printer._print, self.args))) + + +class F95Function(FFunction): + _required_standard = 95 + + +class isign(FFunction): + """ Fortran sign intrinsic for integer arguments. """ + nargs = 2 + + +class dsign(FFunction): + """ Fortran sign intrinsic for double precision arguments. """ + nargs = 2 + + +class cmplx(FFunction): + """ Fortran complex conversion function. """ + nargs = 2 # may be extended to (2, 3) at a later point + + +class kind(FFunction): + """ Fortran kind function. """ + nargs = 1 + + +class merge(F95Function): + """ Fortran merge function """ + nargs = 3 + + +class _literal(Float): + _token: str + _decimals: int + + def _fcode(self, printer, *args, **kwargs): + mantissa, sgnd_ex = ('%.{}e'.format(self._decimals) % self).split('e') + mantissa = mantissa.strip('0').rstrip('.') + ex_sgn, ex_num = sgnd_ex[0], sgnd_ex[1:].lstrip('0') + ex_sgn = '' if ex_sgn == '+' else ex_sgn + return (mantissa or '0') + self._token + ex_sgn + (ex_num or '0') + + +class literal_sp(_literal): + """ Fortran single precision real literal """ + _token = 'e' + _decimals = 9 + + +class literal_dp(_literal): + """ Fortran double precision real literal """ + _token = 'd' + _decimals = 17 + + +class sum_(Token, Expr): + __slots__ = _fields = ('array', 'dim', 'mask') + defaults = {'dim': none, 'mask': none} + _construct_array = staticmethod(sympify) + _construct_dim = staticmethod(sympify) + + +class product_(Token, Expr): + __slots__ = _fields = ('array', 'dim', 'mask') + defaults = {'dim': none, 'mask': none} + _construct_array = staticmethod(sympify) + _construct_dim = staticmethod(sympify) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/futils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/futils.py new file mode 100644 index 0000000000000000000000000000000000000000..4a1f5751fbd4d6b44d99c69a74ad89a8496f8648 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/futils.py @@ -0,0 +1,40 @@ +from itertools import chain +from sympy.codegen.fnodes import Module +from sympy.core.symbol import Dummy +from sympy.printing.fortran import FCodePrinter + +""" This module collects utilities for rendering Fortran code. """ + + +def render_as_module(definitions, name, declarations=(), printer_settings=None): + """ Creates a ``Module`` instance and renders it as a string. + + This generates Fortran source code for a module with the correct ``use`` statements. + + Parameters + ========== + + definitions : iterable + Passed to :class:`sympy.codegen.fnodes.Module`. + name : str + Passed to :class:`sympy.codegen.fnodes.Module`. + declarations : iterable + Passed to :class:`sympy.codegen.fnodes.Module`. It will be extended with + use statements, 'implicit none' and public list generated from ``definitions``. + printer_settings : dict + Passed to ``FCodePrinter`` (default: ``{'standard': 2003, 'source_format': 'free'}``). + + """ + printer_settings = printer_settings or {'standard': 2003, 'source_format': 'free'} + printer = FCodePrinter(printer_settings) + dummy = Dummy() + if isinstance(definitions, Module): + raise ValueError("This function expects to construct a module on its own.") + mod = Module(name, chain(declarations, [dummy]), definitions) + fstr = printer.doprint(mod) + module_use_str = ' %s\n' % ' \n'.join(['use %s, only: %s' % (k, ', '.join(v)) for + k, v in printer.module_uses.items()]) + module_use_str += ' implicit none\n' + module_use_str += ' private\n' + module_use_str += ' public %s\n' % ', '.join([str(node.name) for node in definitions if getattr(node, 'name', None)]) + return fstr.replace(printer.doprint(dummy), module_use_str) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/matrix_nodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/matrix_nodes.py new file mode 100644 index 0000000000000000000000000000000000000000..cf0a13a81c963e2c9e2b885dabd0ff3e2d2b3eb9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/matrix_nodes.py @@ -0,0 +1,71 @@ +""" +Additional AST nodes for operations on matrices. The nodes in this module +are meant to represent optimization of matrix expressions within codegen's +target languages that cannot be represented by SymPy expressions. + +As an example, we can use :meth:`sympy.codegen.rewriting.optimize` and the +``matin_opt`` optimization provided in :mod:`sympy.codegen.rewriting` to +transform matrix multiplication under certain assumptions: + + >>> from sympy import symbols, MatrixSymbol + >>> n = symbols('n', integer=True) + >>> A = MatrixSymbol('A', n, n) + >>> x = MatrixSymbol('x', n, 1) + >>> expr = A**(-1) * x + >>> from sympy import assuming, Q + >>> from sympy.codegen.rewriting import matinv_opt, optimize + >>> with assuming(Q.fullrank(A)): + ... optimize(expr, [matinv_opt]) + MatrixSolve(A, vector=x) +""" + +from .ast import Token +from sympy.matrices import MatrixExpr +from sympy.core.sympify import sympify + + +class MatrixSolve(Token, MatrixExpr): + """Represents an operation to solve a linear matrix equation. + + Parameters + ========== + + matrix : MatrixSymbol + + Matrix representing the coefficients of variables in the linear + equation. This matrix must be square and full-rank (i.e. all columns must + be linearly independent) for the solving operation to be valid. + + vector : MatrixSymbol + + One-column matrix representing the solutions to the equations + represented in ``matrix``. + + Examples + ======== + + >>> from sympy import symbols, MatrixSymbol + >>> from sympy.codegen.matrix_nodes import MatrixSolve + >>> n = symbols('n', integer=True) + >>> A = MatrixSymbol('A', n, n) + >>> x = MatrixSymbol('x', n, 1) + >>> from sympy.printing.numpy import NumPyPrinter + >>> NumPyPrinter().doprint(MatrixSolve(A, x)) + 'numpy.linalg.solve(A, x)' + >>> from sympy import octave_code + >>> octave_code(MatrixSolve(A, x)) + 'A \\\\ x' + + """ + __slots__ = _fields = ('matrix', 'vector') + + _construct_matrix = staticmethod(sympify) + _construct_vector = staticmethod(sympify) + + @property + def shape(self): + return self.vector.shape + + def _eval_derivative(self, x): + A, b = self.matrix, self.vector + return MatrixSolve(A, b.diff(x) - A.diff(x) * MatrixSolve(A, b)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/numpy_nodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/numpy_nodes.py new file mode 100644 index 0000000000000000000000000000000000000000..c47c87f0e1df74cd314bb70674ebff732fe500aa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/numpy_nodes.py @@ -0,0 +1,177 @@ +from sympy.core.function import Add, ArgumentIndexError, Function +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import sympify +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.miscellaneous import Max, Min +from .ast import Token, none + + +def _logaddexp(x1, x2, *, evaluate=True): + return log(Add(exp(x1, evaluate=evaluate), exp(x2, evaluate=evaluate), evaluate=evaluate)) + + +_two = S.One*2 +_ln2 = log(_two) + + +def _lb(x, *, evaluate=True): + return log(x, evaluate=evaluate)/_ln2 + + +def _exp2(x, *, evaluate=True): + return Pow(_two, x, evaluate=evaluate) + + +def _logaddexp2(x1, x2, *, evaluate=True): + return _lb(Add(_exp2(x1, evaluate=evaluate), + _exp2(x2, evaluate=evaluate), evaluate=evaluate)) + + +class logaddexp(Function): + """ Logarithm of the sum of exponentiations of the inputs. + + Helper class for use with e.g. numpy.logaddexp + + See Also + ======== + + https://numpy.org/doc/stable/reference/generated/numpy.logaddexp.html + """ + nargs = 2 + + def __new__(cls, *args): + return Function.__new__(cls, *sorted(args, key=default_sort_key)) + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + wrt, other = self.args + elif argindex == 2: + other, wrt = self.args + else: + raise ArgumentIndexError(self, argindex) + return S.One/(S.One + exp(other-wrt)) + + def _eval_rewrite_as_log(self, x1, x2, **kwargs): + return _logaddexp(x1, x2) + + def _eval_evalf(self, *args, **kwargs): + return self.rewrite(log).evalf(*args, **kwargs) + + def _eval_simplify(self, *args, **kwargs): + a, b = (x.simplify(**kwargs) for x in self.args) + candidate = _logaddexp(a, b) + if candidate != _logaddexp(a, b, evaluate=False): + return candidate + else: + return logaddexp(a, b) + + +class logaddexp2(Function): + """ Logarithm of the sum of exponentiations of the inputs in base-2. + + Helper class for use with e.g. numpy.logaddexp2 + + See Also + ======== + + https://numpy.org/doc/stable/reference/generated/numpy.logaddexp2.html + """ + nargs = 2 + + def __new__(cls, *args): + return Function.__new__(cls, *sorted(args, key=default_sort_key)) + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + wrt, other = self.args + elif argindex == 2: + other, wrt = self.args + else: + raise ArgumentIndexError(self, argindex) + return S.One/(S.One + _exp2(other-wrt)) + + def _eval_rewrite_as_log(self, x1, x2, **kwargs): + return _logaddexp2(x1, x2) + + def _eval_evalf(self, *args, **kwargs): + return self.rewrite(log).evalf(*args, **kwargs) + + def _eval_simplify(self, *args, **kwargs): + a, b = (x.simplify(**kwargs).factor() for x in self.args) + candidate = _logaddexp2(a, b) + if candidate != _logaddexp2(a, b, evaluate=False): + return candidate + else: + return logaddexp2(a, b) + + +class amin(Token): + """ Minimum value along an axis. + + Helper class for use with e.g. numpy.amin + + + See Also + ======== + + https://numpy.org/doc/stable/reference/generated/numpy.amin.html + """ + __slots__ = _fields = ('array', 'axis') + defaults = {'axis': none} + _construct_axis = staticmethod(sympify) + + +class amax(Token): + """ Maximum value along an axis. + + Helper class for use with e.g. numpy.amax + + + See Also + ======== + + https://numpy.org/doc/stable/reference/generated/numpy.amax.html + """ + __slots__ = _fields = ('array', 'axis') + defaults = {'axis': none} + _construct_axis = staticmethod(sympify) + + +class maximum(Function): + """ Element-wise maximum of array elements. + + Helper class for use with e.g. numpy.maximum + + + See Also + ======== + + https://numpy.org/doc/stable/reference/generated/numpy.maximum.html + """ + + def _eval_rewrite_as_Max(self, *args): + return Max(*self.args) + + +class minimum(Function): + """ Element-wise minimum of array elements. + + Helper class for use with e.g. numpy.minimum + + + See Also + ======== + + https://numpy.org/doc/stable/reference/generated/numpy.minimum.html + """ + + def _eval_rewrite_as_Min(self, *args): + return Min(*self.args) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/pynodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/pynodes.py new file mode 100644 index 0000000000000000000000000000000000000000..f0a08b4a79d32f63d345947d6be310b44504dbf5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/pynodes.py @@ -0,0 +1,11 @@ +from .abstract_nodes import List as AbstractList +from .ast import Token + + +class List(AbstractList): + pass + + +class NumExprEvaluate(Token): + """represents a call to :class:`numexpr`s :func:`evaluate`""" + __slots__ = _fields = ('expr',) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/pyutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/pyutils.py new file mode 100644 index 0000000000000000000000000000000000000000..e14eabe92ce50105a4055b71a49767aae04610b9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/pyutils.py @@ -0,0 +1,24 @@ +from sympy.printing.pycode import PythonCodePrinter + +""" This module collects utilities for rendering Python code. """ + + +def render_as_module(content, standard='python3'): + """Renders Python code as a module (with the required imports). + + Parameters + ========== + + standard : + See the parameter ``standard`` in + :meth:`sympy.printing.pycode.pycode` + """ + + printer = PythonCodePrinter({'standard':standard}) + pystr = printer.doprint(content) + if printer._settings['fully_qualified_modules']: + module_imports_str = '\n'.join('import %s' % k for k in printer.module_imports) + else: + module_imports_str = '\n'.join(['from %s import %s' % (k, ', '.join(v)) for + k, v in printer.module_imports.items()]) + return module_imports_str + '\n\n' + pystr diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/rewriting.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/rewriting.py new file mode 100644 index 0000000000000000000000000000000000000000..274b7770b46ded6711468ab2a01db3a53d6fde87 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/rewriting.py @@ -0,0 +1,357 @@ +""" +Classes and functions useful for rewriting expressions for optimized code +generation. Some languages (or standards thereof), e.g. C99, offer specialized +math functions for better performance and/or precision. + +Using the ``optimize`` function in this module, together with a collection of +rules (represented as instances of ``Optimization``), one can rewrite the +expressions for this purpose:: + + >>> from sympy import Symbol, exp, log + >>> from sympy.codegen.rewriting import optimize, optims_c99 + >>> x = Symbol('x') + >>> optimize(3*exp(2*x) - 3, optims_c99) + 3*expm1(2*x) + >>> optimize(exp(2*x) - 1 - exp(-33), optims_c99) + expm1(2*x) - exp(-33) + >>> optimize(log(3*x + 3), optims_c99) + log1p(x) + log(3) + >>> optimize(log(2*x + 3), optims_c99) + log(2*x + 3) + +The ``optims_c99`` imported above is tuple containing the following instances +(which may be imported from ``sympy.codegen.rewriting``): + +- ``expm1_opt`` +- ``log1p_opt`` +- ``exp2_opt`` +- ``log2_opt`` +- ``log2const_opt`` + + +""" +from sympy.core.function import expand_log +from sympy.core.singleton import S +from sympy.core.symbol import Wild +from sympy.functions.elementary.complexes import sign +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import (Max, Min) +from sympy.functions.elementary.trigonometric import (cos, sin, sinc) +from sympy.assumptions import Q, ask +from sympy.codegen.cfunctions import log1p, log2, exp2, expm1 +from sympy.codegen.matrix_nodes import MatrixSolve +from sympy.core.expr import UnevaluatedExpr +from sympy.core.power import Pow +from sympy.codegen.numpy_nodes import logaddexp, logaddexp2 +from sympy.codegen.scipy_nodes import cosm1, powm1 +from sympy.core.mul import Mul +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.utilities.iterables import sift + + +class Optimization: + """ Abstract base class for rewriting optimization. + + Subclasses should implement ``__call__`` taking an expression + as argument. + + Parameters + ========== + cost_function : callable returning number + priority : number + + """ + def __init__(self, cost_function=None, priority=1): + self.cost_function = cost_function + self.priority=priority + + def cheapest(self, *args): + return min(args, key=self.cost_function) + + +class ReplaceOptim(Optimization): + """ Rewriting optimization calling replace on expressions. + + Explanation + =========== + + The instance can be used as a function on expressions for which + it will apply the ``replace`` method (see + :meth:`sympy.core.basic.Basic.replace`). + + Parameters + ========== + + query : + First argument passed to replace. + value : + Second argument passed to replace. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.codegen.rewriting import ReplaceOptim + >>> from sympy.codegen.cfunctions import exp2 + >>> x = Symbol('x') + >>> exp2_opt = ReplaceOptim(lambda p: p.is_Pow and p.base == 2, + ... lambda p: exp2(p.exp)) + >>> exp2_opt(2**x) + exp2(x) + + """ + + def __init__(self, query, value, **kwargs): + super().__init__(**kwargs) + self.query = query + self.value = value + + def __call__(self, expr): + return expr.replace(self.query, self.value) + + +def optimize(expr, optimizations): + """ Apply optimizations to an expression. + + Parameters + ========== + + expr : expression + optimizations : iterable of ``Optimization`` instances + The optimizations will be sorted with respect to ``priority`` (highest first). + + Examples + ======== + + >>> from sympy import log, Symbol + >>> from sympy.codegen.rewriting import optims_c99, optimize + >>> x = Symbol('x') + >>> optimize(log(x+3)/log(2) + log(x**2 + 1), optims_c99) + log1p(x**2) + log2(x + 3) + + """ + + for optim in sorted(optimizations, key=lambda opt: opt.priority, reverse=True): + new_expr = optim(expr) + if optim.cost_function is None: + expr = new_expr + else: + expr = optim.cheapest(expr, new_expr) + return expr + + +exp2_opt = ReplaceOptim( + lambda p: p.is_Pow and p.base == 2, + lambda p: exp2(p.exp) +) + + +_d = Wild('d', properties=[lambda x: x.is_Dummy]) +_u = Wild('u', properties=[lambda x: not x.is_number and not x.is_Add]) +_v = Wild('v') +_w = Wild('w') +_n = Wild('n', properties=[lambda x: x.is_number]) + +sinc_opt1 = ReplaceOptim( + sin(_w)/_w, sinc(_w) +) +sinc_opt2 = ReplaceOptim( + sin(_n*_w)/_w, _n*sinc(_n*_w) +) +sinc_opts = (sinc_opt1, sinc_opt2) + +log2_opt = ReplaceOptim(_v*log(_w)/log(2), _v*log2(_w), cost_function=lambda expr: expr.count( + lambda e: ( # division & eval of transcendentals are expensive floating point operations... + e.is_Pow and e.exp.is_negative # division + or (isinstance(e, (log, log2)) and not e.args[0].is_number)) # transcendental + ) +) + +log2const_opt = ReplaceOptim(log(2)*log2(_w), log(_w)) + +logsumexp_2terms_opt = ReplaceOptim( + lambda l: (isinstance(l, log) + and l.args[0].is_Add + and len(l.args[0].args) == 2 + and all(isinstance(t, exp) for t in l.args[0].args)), + lambda l: ( + Max(*[e.args[0] for e in l.args[0].args]) + + log1p(exp(Min(*[e.args[0] for e in l.args[0].args]))) + ) +) + + +class FuncMinusOneOptim(ReplaceOptim): + """Specialization of ReplaceOptim for functions evaluating "f(x) - 1". + + Explanation + =========== + + Numerical functions which go toward one as x go toward zero is often best + implemented by a dedicated function in order to avoid catastrophic + cancellation. One such example is ``expm1(x)`` in the C standard library + which evaluates ``exp(x) - 1``. Such functions preserves many more + significant digits when its argument is much smaller than one, compared + to subtracting one afterwards. + + Parameters + ========== + + func : + The function which is subtracted by one. + func_m_1 : + The specialized function evaluating ``func(x) - 1``. + opportunistic : bool + When ``True``, apply the transformation as long as the magnitude of the + remaining number terms decreases. When ``False``, only apply the + transformation if it completely eliminates the number term. + + Examples + ======== + + >>> from sympy import symbols, exp + >>> from sympy.codegen.rewriting import FuncMinusOneOptim + >>> from sympy.codegen.cfunctions import expm1 + >>> x, y = symbols('x y') + >>> expm1_opt = FuncMinusOneOptim(exp, expm1) + >>> expm1_opt(exp(x) + 2*exp(5*y) - 3) + expm1(x) + 2*expm1(5*y) + + + """ + + def __init__(self, func, func_m_1, opportunistic=True): + weight = 10 # <-- this is an arbitrary number (heuristic) + super().__init__(lambda e: e.is_Add, self.replace_in_Add, + cost_function=lambda expr: expr.count_ops() - weight*expr.count(func_m_1)) + self.func = func + self.func_m_1 = func_m_1 + self.opportunistic = opportunistic + + def _group_Add_terms(self, add): + numbers, non_num = sift(add.args, lambda arg: arg.is_number, binary=True) + numsum = sum(numbers) + terms_with_func, other = sift(non_num, lambda arg: arg.has(self.func), binary=True) + return numsum, terms_with_func, other + + def replace_in_Add(self, e): + """ passed as second argument to Basic.replace(...) """ + numsum, terms_with_func, other_non_num_terms = self._group_Add_terms(e) + if numsum == 0: + return e + substituted, untouched = [], [] + for with_func in terms_with_func: + if with_func.is_Mul: + func, coeff = sift(with_func.args, lambda arg: arg.func == self.func, binary=True) + if len(func) == 1 and len(coeff) == 1: + func, coeff = func[0], coeff[0] + else: + coeff = None + elif with_func.func == self.func: + func, coeff = with_func, S.One + else: + coeff = None + + if coeff is not None and coeff.is_number and sign(coeff) == -sign(numsum): + if self.opportunistic: + do_substitute = abs(coeff+numsum) < abs(numsum) + else: + do_substitute = coeff+numsum == 0 + + if do_substitute: # advantageous substitution + numsum += coeff + substituted.append(coeff*self.func_m_1(*func.args)) + continue + untouched.append(with_func) + + return e.func(numsum, *substituted, *untouched, *other_non_num_terms) + + def __call__(self, expr): + alt1 = super().__call__(expr) + alt2 = super().__call__(expr.factor()) + return self.cheapest(alt1, alt2) + + +expm1_opt = FuncMinusOneOptim(exp, expm1) +cosm1_opt = FuncMinusOneOptim(cos, cosm1) +powm1_opt = FuncMinusOneOptim(Pow, powm1) + +log1p_opt = ReplaceOptim( + lambda e: isinstance(e, log), + lambda l: expand_log(l.replace( + log, lambda arg: log(arg.factor()) + )).replace(log(_u+1), log1p(_u)) +) + +def create_expand_pow_optimization(limit, *, base_req=lambda b: b.is_symbol): + """ Creates an instance of :class:`ReplaceOptim` for expanding ``Pow``. + + Explanation + =========== + + The requirements for expansions are that the base needs to be a symbol + and the exponent needs to be an Integer (and be less than or equal to + ``limit``). + + Parameters + ========== + + limit : int + The highest power which is expanded into multiplication. + base_req : function returning bool + Requirement on base for expansion to happen, default is to return + the ``is_symbol`` attribute of the base. + + Examples + ======== + + >>> from sympy import Symbol, sin + >>> from sympy.codegen.rewriting import create_expand_pow_optimization + >>> x = Symbol('x') + >>> expand_opt = create_expand_pow_optimization(3) + >>> expand_opt(x**5 + x**3) + x**5 + x*x*x + >>> expand_opt(x**5 + x**3 + sin(x)**3) + x**5 + sin(x)**3 + x*x*x + >>> opt2 = create_expand_pow_optimization(3, base_req=lambda b: not b.is_Function) + >>> opt2((x+1)**2 + sin(x)**2) + sin(x)**2 + (x + 1)*(x + 1) + + """ + return ReplaceOptim( + lambda e: e.is_Pow and base_req(e.base) and e.exp.is_Integer and abs(e.exp) <= limit, + lambda p: ( + UnevaluatedExpr(Mul(*([p.base]*+p.exp), evaluate=False)) if p.exp > 0 else + 1/UnevaluatedExpr(Mul(*([p.base]*-p.exp), evaluate=False)) + )) + +# Optimization procedures for turning A**(-1) * x into MatrixSolve(A, x) +def _matinv_predicate(expr): + # TODO: We should be able to support more than 2 elements + if expr.is_MatMul and len(expr.args) == 2: + left, right = expr.args + if left.is_Inverse and right.shape[1] == 1: + inv_arg = left.arg + if isinstance(inv_arg, MatrixSymbol): + return bool(ask(Q.fullrank(left.arg))) + + return False + +def _matinv_transform(expr): + left, right = expr.args + inv_arg = left.arg + return MatrixSolve(inv_arg, right) + + +matinv_opt = ReplaceOptim(_matinv_predicate, _matinv_transform) + + +logaddexp_opt = ReplaceOptim(log(exp(_v)+exp(_w)), logaddexp(_v, _w)) +logaddexp2_opt = ReplaceOptim(log(Pow(2, _v)+Pow(2, _w)), logaddexp2(_v, _w)*log(2)) + +# Collections of optimizations: +optims_c99 = (expm1_opt, log1p_opt, exp2_opt, log2_opt, log2const_opt) + +optims_numpy = optims_c99 + (logaddexp_opt, logaddexp2_opt,) + sinc_opts + +optims_scipy = (cosm1_opt, powm1_opt) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/scipy_nodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/scipy_nodes.py new file mode 100644 index 0000000000000000000000000000000000000000..059a853fc8cac6e0b9a1a3c7395dd3a15384dcba --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/scipy_nodes.py @@ -0,0 +1,79 @@ +from sympy.core.function import Add, ArgumentIndexError, Function +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.trigonometric import cos, sin + + +def _cosm1(x, *, evaluate=True): + return Add(cos(x, evaluate=evaluate), -S.One, evaluate=evaluate) + + +class cosm1(Function): + """ Minus one plus cosine of x, i.e. cos(x) - 1. For use when x is close to zero. + + Helper class for use with e.g. scipy.special.cosm1 + See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.cosm1.html + """ + nargs = 1 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return -sin(*self.args) + else: + raise ArgumentIndexError(self, argindex) + + def _eval_rewrite_as_cos(self, x, **kwargs): + return _cosm1(x) + + def _eval_evalf(self, *args, **kwargs): + return self.rewrite(cos).evalf(*args, **kwargs) + + def _eval_simplify(self, **kwargs): + x, = self.args + candidate = _cosm1(x.simplify(**kwargs)) + if candidate != _cosm1(x, evaluate=False): + return candidate + else: + return cosm1(x) + + +def _powm1(x, y, *, evaluate=True): + return Add(Pow(x, y, evaluate=evaluate), -S.One, evaluate=evaluate) + + +class powm1(Function): + """ Minus one plus x to the power of y, i.e. x**y - 1. For use when x is close to one or y is close to zero. + + Helper class for use with e.g. scipy.special.powm1 + See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.powm1.html + """ + nargs = 2 + + def fdiff(self, argindex=1): + """ + Returns the first derivative of this function. + """ + if argindex == 1: + return Pow(self.args[0], self.args[1])*self.args[1]/self.args[0] + elif argindex == 2: + return log(self.args[0])*Pow(*self.args) + else: + raise ArgumentIndexError(self, argindex) + + def _eval_rewrite_as_Pow(self, x, y, **kwargs): + return _powm1(x, y) + + def _eval_evalf(self, *args, **kwargs): + return self.rewrite(Pow).evalf(*args, **kwargs) + + def _eval_simplify(self, **kwargs): + x, y = self.args + candidate = _powm1(x.simplify(**kwargs), y.simplify(**kwargs)) + if candidate != _powm1(x, y, evaluate=False): + return candidate + else: + return powm1(x, y) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..220c27a42975555f8fe7770fcef0dd18475c89e1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/__init__.py @@ -0,0 +1,43 @@ +from sympy.combinatorics.permutations import Permutation, Cycle +from sympy.combinatorics.prufer import Prufer +from sympy.combinatorics.generators import cyclic, alternating, symmetric, dihedral +from sympy.combinatorics.subsets import Subset +from sympy.combinatorics.partitions import (Partition, IntegerPartition, + RGS_rank, RGS_unrank, RGS_enum) +from sympy.combinatorics.polyhedron import (Polyhedron, tetrahedron, cube, + octahedron, dodecahedron, icosahedron) +from sympy.combinatorics.perm_groups import PermutationGroup, Coset, SymmetricPermutationGroup +from sympy.combinatorics.group_constructs import DirectProduct +from sympy.combinatorics.graycode import GrayCode +from sympy.combinatorics.named_groups import (SymmetricGroup, DihedralGroup, + CyclicGroup, AlternatingGroup, AbelianGroup, RubikGroup) +from sympy.combinatorics.pc_groups import PolycyclicGroup, Collector +from sympy.combinatorics.free_groups import free_group + +__all__ = [ + 'Permutation', 'Cycle', + + 'Prufer', + + 'cyclic', 'alternating', 'symmetric', 'dihedral', + + 'Subset', + + 'Partition', 'IntegerPartition', 'RGS_rank', 'RGS_unrank', 'RGS_enum', + + 'Polyhedron', 'tetrahedron', 'cube', 'octahedron', 'dodecahedron', + 'icosahedron', + + 'PermutationGroup', 'Coset', 'SymmetricPermutationGroup', + + 'DirectProduct', + + 'GrayCode', + + 'SymmetricGroup', 'DihedralGroup', 'CyclicGroup', 'AlternatingGroup', + 'AbelianGroup', 'RubikGroup', + + 'PolycyclicGroup', 'Collector', + + 'free_group', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/coset_table.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/coset_table.py new file mode 100644 index 0000000000000000000000000000000000000000..0687aa34ec70e9062f65ff6413213848cf03e51b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/coset_table.py @@ -0,0 +1,1259 @@ +from sympy.combinatorics.free_groups import free_group +from sympy.printing.defaults import DefaultPrinting + +from itertools import chain, product +from bisect import bisect_left + + +############################################################################### +# COSET TABLE # +############################################################################### + +class CosetTable(DefaultPrinting): + # coset_table: Mathematically a coset table + # represented using a list of lists + # alpha: Mathematically a coset (precisely, a live coset) + # represented by an integer between i with 1 <= i <= n + # alpha in c + # x: Mathematically an element of "A" (set of generators and + # their inverses), represented using "FpGroupElement" + # fp_grp: Finitely Presented Group with < X|R > as presentation. + # H: subgroup of fp_grp. + # NOTE: We start with H as being only a list of words in generators + # of "fp_grp". Since `.subgroup` method has not been implemented. + + r""" + + Properties + ========== + + [1] `0 \in \Omega` and `\tau(1) = \epsilon` + [2] `\alpha^x = \beta \Leftrightarrow \beta^{x^{-1}} = \alpha` + [3] If `\alpha^x = \beta`, then `H \tau(\alpha)x = H \tau(\beta)` + [4] `\forall \alpha \in \Omega, 1^{\tau(\alpha)} = \alpha` + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of Computational Group Theory" + + .. [2] John J. Cannon; Lucien A. Dimino; George Havas; Jane M. Watson + Mathematics of Computation, Vol. 27, No. 123. (Jul., 1973), pp. 463-490. + "Implementation and Analysis of the Todd-Coxeter Algorithm" + + """ + # default limit for the number of cosets allowed in a + # coset enumeration. + coset_table_max_limit = 4096000 + # limit for the current instance + coset_table_limit = None + # maximum size of deduction stack above or equal to + # which it is emptied + max_stack_size = 100 + + def __init__(self, fp_grp, subgroup, max_cosets=None): + if not max_cosets: + max_cosets = CosetTable.coset_table_max_limit + self.fp_group = fp_grp + self.subgroup = subgroup + self.coset_table_limit = max_cosets + # "p" is setup independent of Omega and n + self.p = [0] + # a list of the form `[gen_1, gen_1^{-1}, ... , gen_k, gen_k^{-1}]` + self.A = list(chain.from_iterable((gen, gen**-1) \ + for gen in self.fp_group.generators)) + #P[alpha, x] Only defined when alpha^x is defined. + self.P = [[None]*len(self.A)] + # the mathematical coset table which is a list of lists + self.table = [[None]*len(self.A)] + self.A_dict = {x: self.A.index(x) for x in self.A} + self.A_dict_inv = {} + for x, index in self.A_dict.items(): + if index % 2 == 0: + self.A_dict_inv[x] = self.A_dict[x] + 1 + else: + self.A_dict_inv[x] = self.A_dict[x] - 1 + # used in the coset-table based method of coset enumeration. Each of + # the element is called a "deduction" which is the form (alpha, x) whenever + # a value is assigned to alpha^x during a definition or "deduction process" + self.deduction_stack = [] + # Attributes for modified methods. + H = self.subgroup + self._grp = free_group(', ' .join(["a_%d" % i for i in range(len(H))]))[0] + self.P = [[None]*len(self.A)] + self.p_p = {} + + @property + def omega(self): + """Set of live cosets. """ + return [coset for coset in range(len(self.p)) if self.p[coset] == coset] + + def copy(self): + """ + Return a shallow copy of Coset Table instance ``self``. + + """ + self_copy = self.__class__(self.fp_group, self.subgroup) + self_copy.table = [list(perm_rep) for perm_rep in self.table] + self_copy.p = list(self.p) + self_copy.deduction_stack = list(self.deduction_stack) + return self_copy + + def __str__(self): + return "Coset Table on %s with %s as subgroup generators" \ + % (self.fp_group, self.subgroup) + + __repr__ = __str__ + + @property + def n(self): + """The number `n` represents the length of the sublist containing the + live cosets. + + """ + if not self.table: + return 0 + return max(self.omega) + 1 + + # Pg. 152 [1] + def is_complete(self): + r""" + The coset table is called complete if it has no undefined entries + on the live cosets; that is, `\alpha^x` is defined for all + `\alpha \in \Omega` and `x \in A`. + + """ + return not any(None in self.table[coset] for coset in self.omega) + + # Pg. 153 [1] + def define(self, alpha, x, modified=False): + r""" + This routine is used in the relator-based strategy of Todd-Coxeter + algorithm if some `\alpha^x` is undefined. We check whether there is + space available for defining a new coset. If there is enough space + then we remedy this by adjoining a new coset `\beta` to `\Omega` + (i.e to set of live cosets) and put that equal to `\alpha^x`, then + make an assignment satisfying Property[1]. If there is not enough space + then we halt the Coset Table creation. The maximum amount of space that + can be used by Coset Table can be manipulated using the class variable + ``CosetTable.coset_table_max_limit``. + + See Also + ======== + + define_c + + """ + A = self.A + table = self.table + len_table = len(table) + if len_table >= self.coset_table_limit: + # abort the further generation of cosets + raise ValueError("the coset enumeration has defined more than " + "%s cosets. Try with a greater value max number of cosets " + % self.coset_table_limit) + table.append([None]*len(A)) + self.P.append([None]*len(self.A)) + # beta is the new coset generated + beta = len_table + self.p.append(beta) + table[alpha][self.A_dict[x]] = beta + table[beta][self.A_dict_inv[x]] = alpha + # P[alpha][x] = epsilon, P[beta][x**-1] = epsilon + if modified: + self.P[alpha][self.A_dict[x]] = self._grp.identity + self.P[beta][self.A_dict_inv[x]] = self._grp.identity + self.p_p[beta] = self._grp.identity + + def define_c(self, alpha, x): + r""" + A variation of ``define`` routine, described on Pg. 165 [1], used in + the coset table-based strategy of Todd-Coxeter algorithm. It differs + from ``define`` routine in that for each definition it also adds the + tuple `(\alpha, x)` to the deduction stack. + + See Also + ======== + + define + + """ + A = self.A + table = self.table + len_table = len(table) + if len_table >= self.coset_table_limit: + # abort the further generation of cosets + raise ValueError("the coset enumeration has defined more than " + "%s cosets. Try with a greater value max number of cosets " + % self.coset_table_limit) + table.append([None]*len(A)) + # beta is the new coset generated + beta = len_table + self.p.append(beta) + table[alpha][self.A_dict[x]] = beta + table[beta][self.A_dict_inv[x]] = alpha + # append to deduction stack + self.deduction_stack.append((alpha, x)) + + def scan_c(self, alpha, word): + """ + A variation of ``scan`` routine, described on pg. 165 of [1], which + puts at tuple, whenever a deduction occurs, to deduction stack. + + See Also + ======== + + scan, scan_check, scan_and_fill, scan_and_fill_c + + """ + # alpha is an integer representing a "coset" + # since scanning can be in two cases + # 1. for alpha=0 and w in Y (i.e generating set of H) + # 2. alpha in Omega (set of live cosets), w in R (relators) + A_dict = self.A_dict + A_dict_inv = self.A_dict_inv + table = self.table + f = alpha + i = 0 + r = len(word) + b = alpha + j = r - 1 + # list of union of generators and their inverses + while i <= j and table[f][A_dict[word[i]]] is not None: + f = table[f][A_dict[word[i]]] + i += 1 + if i > j: + if f != b: + self.coincidence_c(f, b) + return + while j >= i and table[b][A_dict_inv[word[j]]] is not None: + b = table[b][A_dict_inv[word[j]]] + j -= 1 + if j < i: + # we have an incorrect completed scan with coincidence f ~ b + # run the "coincidence" routine + self.coincidence_c(f, b) + elif j == i: + # deduction process + table[f][A_dict[word[i]]] = b + table[b][A_dict_inv[word[i]]] = f + self.deduction_stack.append((f, word[i])) + # otherwise scan is incomplete and yields no information + + # alpha, beta coincide, i.e. alpha, beta represent the pair of cosets where + # coincidence occurs + def coincidence_c(self, alpha, beta): + """ + A variation of ``coincidence`` routine used in the coset-table based + method of coset enumeration. The only difference being on addition of + a new coset in coset table(i.e new coset introduction), then it is + appended to ``deduction_stack``. + + See Also + ======== + + coincidence + + """ + A_dict = self.A_dict + A_dict_inv = self.A_dict_inv + table = self.table + # behaves as a queue + q = [] + self.merge(alpha, beta, q) + while len(q) > 0: + gamma = q.pop(0) + for x in A_dict: + delta = table[gamma][A_dict[x]] + if delta is not None: + table[delta][A_dict_inv[x]] = None + # only line of difference from ``coincidence`` routine + self.deduction_stack.append((delta, x**-1)) + mu = self.rep(gamma) + nu = self.rep(delta) + if table[mu][A_dict[x]] is not None: + self.merge(nu, table[mu][A_dict[x]], q) + elif table[nu][A_dict_inv[x]] is not None: + self.merge(mu, table[nu][A_dict_inv[x]], q) + else: + table[mu][A_dict[x]] = nu + table[nu][A_dict_inv[x]] = mu + + def scan(self, alpha, word, y=None, fill=False, modified=False): + r""" + ``scan`` performs a scanning process on the input ``word``. + It first locates the largest prefix ``s`` of ``word`` for which + `\alpha^s` is defined (i.e is not ``None``), ``s`` may be empty. Let + ``word=sv``, let ``t`` be the longest suffix of ``v`` for which + `\alpha^{t^{-1}}` is defined, and let ``v=ut``. Then three + possibilities are there: + + 1. If ``t=v``, then we say that the scan completes, and if, in addition + `\alpha^s = \alpha^{t^{-1}}`, then we say that the scan completes + correctly. + + 2. It can also happen that scan does not complete, but `|u|=1`; that + is, the word ``u`` consists of a single generator `x \in A`. In that + case, if `\alpha^s = \beta` and `\alpha^{t^{-1}} = \gamma`, then we can + set `\beta^x = \gamma` and `\gamma^{x^{-1}} = \beta`. These assignments + are known as deductions and enable the scan to complete correctly. + + 3. See ``coicidence`` routine for explanation of third condition. + + Notes + ===== + + The code for the procedure of scanning `\alpha \in \Omega` + under `w \in A*` is defined on pg. 155 [1] + + See Also + ======== + + scan_c, scan_check, scan_and_fill, scan_and_fill_c + + Scan and Fill + ============= + + Performed when the default argument fill=True. + + Modified Scan + ============= + + Performed when the default argument modified=True + + """ + # alpha is an integer representing a "coset" + # since scanning can be in two cases + # 1. for alpha=0 and w in Y (i.e generating set of H) + # 2. alpha in Omega (set of live cosets), w in R (relators) + A_dict = self.A_dict + A_dict_inv = self.A_dict_inv + table = self.table + f = alpha + i = 0 + r = len(word) + b = alpha + j = r - 1 + b_p = y + if modified: + f_p = self._grp.identity + flag = 0 + while fill or flag == 0: + flag = 1 + while i <= j and table[f][A_dict[word[i]]] is not None: + if modified: + f_p = f_p*self.P[f][A_dict[word[i]]] + f = table[f][A_dict[word[i]]] + i += 1 + if i > j: + if f != b: + if modified: + self.modified_coincidence(f, b, f_p**-1*y) + else: + self.coincidence(f, b) + return + while j >= i and table[b][A_dict_inv[word[j]]] is not None: + if modified: + b_p = b_p*self.P[b][self.A_dict_inv[word[j]]] + b = table[b][A_dict_inv[word[j]]] + j -= 1 + if j < i: + # we have an incorrect completed scan with coincidence f ~ b + # run the "coincidence" routine + if modified: + self.modified_coincidence(f, b, f_p**-1*b_p) + else: + self.coincidence(f, b) + elif j == i: + # deduction process + table[f][A_dict[word[i]]] = b + table[b][A_dict_inv[word[i]]] = f + if modified: + self.P[f][self.A_dict[word[i]]] = f_p**-1*b_p + self.P[b][self.A_dict_inv[word[i]]] = b_p**-1*f_p + return + elif fill: + self.define(f, word[i], modified=modified) + # otherwise scan is incomplete and yields no information + + # used in the low-index subgroups algorithm + def scan_check(self, alpha, word): + r""" + Another version of ``scan`` routine, described on, it checks whether + `\alpha` scans correctly under `word`, it is a straightforward + modification of ``scan``. ``scan_check`` returns ``False`` (rather than + calling ``coincidence``) if the scan completes incorrectly; otherwise + it returns ``True``. + + See Also + ======== + + scan, scan_c, scan_and_fill, scan_and_fill_c + + """ + # alpha is an integer representing a "coset" + # since scanning can be in two cases + # 1. for alpha=0 and w in Y (i.e generating set of H) + # 2. alpha in Omega (set of live cosets), w in R (relators) + A_dict = self.A_dict + A_dict_inv = self.A_dict_inv + table = self.table + f = alpha + i = 0 + r = len(word) + b = alpha + j = r - 1 + while i <= j and table[f][A_dict[word[i]]] is not None: + f = table[f][A_dict[word[i]]] + i += 1 + if i > j: + return f == b + while j >= i and table[b][A_dict_inv[word[j]]] is not None: + b = table[b][A_dict_inv[word[j]]] + j -= 1 + if j < i: + # we have an incorrect completed scan with coincidence f ~ b + # return False, instead of calling coincidence routine + return False + elif j == i: + # deduction process + table[f][A_dict[word[i]]] = b + table[b][A_dict_inv[word[i]]] = f + return True + + def merge(self, k, lamda, q, w=None, modified=False): + """ + Merge two classes with representatives ``k`` and ``lamda``, described + on Pg. 157 [1] (for pseudocode), start by putting ``p[k] = lamda``. + It is more efficient to choose the new representative from the larger + of the two classes being merged, i.e larger among ``k`` and ``lamda``. + procedure ``merge`` performs the merging operation, adds the deleted + class representative to the queue ``q``. + + Parameters + ========== + + 'k', 'lamda' being the two class representatives to be merged. + + Notes + ===== + + Pg. 86-87 [1] contains a description of this method. + + See Also + ======== + + coincidence, rep + + """ + p = self.p + rep = self.rep + phi = rep(k, modified=modified) + psi = rep(lamda, modified=modified) + if phi != psi: + mu = min(phi, psi) + v = max(phi, psi) + p[v] = mu + if modified: + if v == phi: + self.p_p[phi] = self.p_p[k]**-1*w*self.p_p[lamda] + else: + self.p_p[psi] = self.p_p[lamda]**-1*w**-1*self.p_p[k] + q.append(v) + + def rep(self, k, modified=False): + r""" + Parameters + ========== + + `k \in [0 \ldots n-1]`, as for ``self`` only array ``p`` is used + + Returns + ======= + + Representative of the class containing ``k``. + + Returns the representative of `\sim` class containing ``k``, it also + makes some modification to array ``p`` of ``self`` to ease further + computations, described on Pg. 157 [1]. + + The information on classes under `\sim` is stored in array `p` of + ``self`` argument, which will always satisfy the property: + + `p[\alpha] \sim \alpha` and `p[\alpha]=\alpha \iff \alpha=rep(\alpha)` + `\forall \in [0 \ldots n-1]`. + + So, for `\alpha \in [0 \ldots n-1]`, we find `rep(self, \alpha)` by + continually replacing `\alpha` by `p[\alpha]` until it becomes + constant (i.e satisfies `p[\alpha] = \alpha`):w + + To increase the efficiency of later ``rep`` calculations, whenever we + find `rep(self, \alpha)=\beta`, we set + `p[\gamma] = \beta \forall \gamma \in p-chain` from `\alpha` to `\beta` + + Notes + ===== + + ``rep`` routine is also described on Pg. 85-87 [1] in Atkinson's + algorithm, this results from the fact that ``coincidence`` routine + introduces functionality similar to that introduced by the + ``minimal_block`` routine on Pg. 85-87 [1]. + + See Also + ======== + + coincidence, merge + + """ + p = self.p + lamda = k + rho = p[lamda] + if modified: + s = p[:] + while rho != lamda: + if modified: + s[rho] = lamda + lamda = rho + rho = p[lamda] + if modified: + rho = s[lamda] + while rho != k: + mu = rho + rho = s[mu] + p[rho] = lamda + self.p_p[rho] = self.p_p[rho]*self.p_p[mu] + else: + mu = k + rho = p[mu] + while rho != lamda: + p[mu] = lamda + mu = rho + rho = p[mu] + return lamda + + # alpha, beta coincide, i.e. alpha, beta represent the pair of cosets + # where coincidence occurs + def coincidence(self, alpha, beta, w=None, modified=False): + r""" + The third situation described in ``scan`` routine is handled by this + routine, described on Pg. 156-161 [1]. + + The unfortunate situation when the scan completes but not correctly, + then ``coincidence`` routine is run. i.e when for some `i` with + `1 \le i \le r+1`, we have `w=st` with `s = x_1 x_2 \dots x_{i-1}`, + `t = x_i x_{i+1} \dots x_r`, and `\beta = \alpha^s` and + `\gamma = \alpha^{t-1}` are defined but unequal. This means that + `\beta` and `\gamma` represent the same coset of `H` in `G`. Described + on Pg. 156 [1]. ``rep`` + + See Also + ======== + + scan + + """ + A_dict = self.A_dict + A_dict_inv = self.A_dict_inv + table = self.table + # behaves as a queue + q = [] + if modified: + self.modified_merge(alpha, beta, w, q) + else: + self.merge(alpha, beta, q) + while len(q) > 0: + gamma = q.pop(0) + for x in A_dict: + delta = table[gamma][A_dict[x]] + if delta is not None: + table[delta][A_dict_inv[x]] = None + mu = self.rep(gamma, modified=modified) + nu = self.rep(delta, modified=modified) + if table[mu][A_dict[x]] is not None: + if modified: + v = self.p_p[delta]**-1*self.P[gamma][self.A_dict[x]]**-1 + v = v*self.p_p[gamma]*self.P[mu][self.A_dict[x]] + self.modified_merge(nu, table[mu][self.A_dict[x]], v, q) + else: + self.merge(nu, table[mu][A_dict[x]], q) + elif table[nu][A_dict_inv[x]] is not None: + if modified: + v = self.p_p[gamma]**-1*self.P[gamma][self.A_dict[x]] + v = v*self.p_p[delta]*self.P[mu][self.A_dict_inv[x]] + self.modified_merge(mu, table[nu][self.A_dict_inv[x]], v, q) + else: + self.merge(mu, table[nu][A_dict_inv[x]], q) + else: + table[mu][A_dict[x]] = nu + table[nu][A_dict_inv[x]] = mu + if modified: + v = self.p_p[gamma]**-1*self.P[gamma][self.A_dict[x]]*self.p_p[delta] + self.P[mu][self.A_dict[x]] = v + self.P[nu][self.A_dict_inv[x]] = v**-1 + + # method used in the HLT strategy + def scan_and_fill(self, alpha, word): + """ + A modified version of ``scan`` routine used in the relator-based + method of coset enumeration, described on pg. 162-163 [1], which + follows the idea that whenever the procedure is called and the scan + is incomplete then it makes new definitions to enable the scan to + complete; i.e it fills in the gaps in the scan of the relator or + subgroup generator. + + """ + self.scan(alpha, word, fill=True) + + def scan_and_fill_c(self, alpha, word): + """ + A modified version of ``scan`` routine, described on Pg. 165 second + para. [1], with modification similar to that of ``scan_anf_fill`` the + only difference being it calls the coincidence procedure used in the + coset-table based method i.e. the routine ``coincidence_c`` is used. + + See Also + ======== + + scan, scan_and_fill + + """ + A_dict = self.A_dict + A_dict_inv = self.A_dict_inv + table = self.table + r = len(word) + f = alpha + i = 0 + b = alpha + j = r - 1 + # loop until it has filled the alpha row in the table. + while True: + # do the forward scanning + while i <= j and table[f][A_dict[word[i]]] is not None: + f = table[f][A_dict[word[i]]] + i += 1 + if i > j: + if f != b: + self.coincidence_c(f, b) + return + # forward scan was incomplete, scan backwards + while j >= i and table[b][A_dict_inv[word[j]]] is not None: + b = table[b][A_dict_inv[word[j]]] + j -= 1 + if j < i: + self.coincidence_c(f, b) + elif j == i: + table[f][A_dict[word[i]]] = b + table[b][A_dict_inv[word[i]]] = f + self.deduction_stack.append((f, word[i])) + else: + self.define_c(f, word[i]) + + # method used in the HLT strategy + def look_ahead(self): + """ + When combined with the HLT method this is known as HLT+Lookahead + method of coset enumeration, described on pg. 164 [1]. Whenever + ``define`` aborts due to lack of space available this procedure is + executed. This routine helps in recovering space resulting from + "coincidence" of cosets. + + """ + R = self.fp_group.relators + p = self.p + # complete scan all relators under all cosets(obviously live) + # without making new definitions + for beta in self.omega: + for w in R: + self.scan(beta, w) + if p[beta] < beta: + break + + # Pg. 166 + def process_deductions(self, R_c_x, R_c_x_inv): + """ + Processes the deductions that have been pushed onto ``deduction_stack``, + described on Pg. 166 [1] and is used in coset-table based enumeration. + + See Also + ======== + + deduction_stack + + """ + p = self.p + table = self.table + while len(self.deduction_stack) > 0: + if len(self.deduction_stack) >= CosetTable.max_stack_size: + self.look_ahead() + del self.deduction_stack[:] + continue + else: + alpha, x = self.deduction_stack.pop() + if p[alpha] == alpha: + for w in R_c_x: + self.scan_c(alpha, w) + if p[alpha] < alpha: + break + beta = table[alpha][self.A_dict[x]] + if beta is not None and p[beta] == beta: + for w in R_c_x_inv: + self.scan_c(beta, w) + if p[beta] < beta: + break + + def process_deductions_check(self, R_c_x, R_c_x_inv): + """ + A variation of ``process_deductions``, this calls ``scan_check`` + wherever ``process_deductions`` calls ``scan``, described on Pg. [1]. + + See Also + ======== + + process_deductions + + """ + table = self.table + while len(self.deduction_stack) > 0: + alpha, x = self.deduction_stack.pop() + if not all(self.scan_check(alpha, w) for w in R_c_x): + return False + beta = table[alpha][self.A_dict[x]] + if beta is not None: + if not all(self.scan_check(beta, w) for w in R_c_x_inv): + return False + return True + + def switch(self, beta, gamma): + r"""Switch the elements `\beta, \gamma \in \Omega` of ``self``, used + by the ``standardize`` procedure, described on Pg. 167 [1]. + + See Also + ======== + + standardize + + """ + A = self.A + A_dict = self.A_dict + table = self.table + for x in A: + z = table[gamma][A_dict[x]] + table[gamma][A_dict[x]] = table[beta][A_dict[x]] + table[beta][A_dict[x]] = z + for alpha in range(len(self.p)): + if self.p[alpha] == alpha: + if table[alpha][A_dict[x]] == beta: + table[alpha][A_dict[x]] = gamma + elif table[alpha][A_dict[x]] == gamma: + table[alpha][A_dict[x]] = beta + + def standardize(self): + r""" + A coset table is standardized if when running through the cosets and + within each coset through the generator images (ignoring generator + inverses), the cosets appear in order of the integers + `0, 1, \dots, n`. "Standardize" reorders the elements of `\Omega` + such that, if we scan the coset table first by elements of `\Omega` + and then by elements of A, then the cosets occur in ascending order. + ``standardize()`` is used at the end of an enumeration to permute the + cosets so that they occur in some sort of standard order. + + Notes + ===== + + procedure is described on pg. 167-168 [1], it also makes use of the + ``switch`` routine to replace by smaller integer value. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_r + >>> F, x, y = free_group("x, y") + + # Example 5.3 from [1] + >>> f = FpGroup(F, [x**2*y**2, x**3*y**5]) + >>> C = coset_enumeration_r(f, []) + >>> C.compress() + >>> C.table + [[1, 3, 1, 3], [2, 0, 2, 0], [3, 1, 3, 1], [0, 2, 0, 2]] + >>> C.standardize() + >>> C.table + [[1, 2, 1, 2], [3, 0, 3, 0], [0, 3, 0, 3], [2, 1, 2, 1]] + + """ + A = self.A + A_dict = self.A_dict + gamma = 1 + for alpha, x in product(range(self.n), A): + beta = self.table[alpha][A_dict[x]] + if beta >= gamma: + if beta > gamma: + self.switch(gamma, beta) + gamma += 1 + if gamma == self.n: + return + + # Compression of a Coset Table + def compress(self): + """Removes the non-live cosets from the coset table, described on + pg. 167 [1]. + + """ + gamma = -1 + A = self.A + A_dict = self.A_dict + A_dict_inv = self.A_dict_inv + table = self.table + chi = tuple([i for i in range(len(self.p)) if self.p[i] != i]) + for alpha in self.omega: + gamma += 1 + if gamma != alpha: + # replace alpha by gamma in coset table + for x in A: + beta = table[alpha][A_dict[x]] + table[gamma][A_dict[x]] = beta + # XXX: The line below uses == rather than = which means + # that it has no effect. It is not clear though if it is + # correct simply to delete the line or to change it to + # use =. Changing it causes some tests to fail. + # + # https://github.com/sympy/sympy/issues/27633 + table[beta][A_dict_inv[x]] == gamma # noqa: B015 + # all the cosets in the table are live cosets + self.p = list(range(gamma + 1)) + # delete the useless columns + del table[len(self.p):] + # re-define values + for row in table: + for j in range(len(self.A)): + row[j] -= bisect_left(chi, row[j]) + + def conjugates(self, R): + R_c = list(chain.from_iterable((rel.cyclic_conjugates(), \ + (rel**-1).cyclic_conjugates()) for rel in R)) + R_set = set() + for conjugate in R_c: + R_set = R_set.union(conjugate) + R_c_list = [] + for x in self.A: + r = {word for word in R_set if word[0] == x} + R_c_list.append(r) + R_set.difference_update(r) + return R_c_list + + def coset_representative(self, coset): + ''' + Compute the coset representative of a given coset. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_r + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) + >>> C = coset_enumeration_r(f, [x]) + >>> C.compress() + >>> C.table + [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1]] + >>> C.coset_representative(0) + + >>> C.coset_representative(1) + y + >>> C.coset_representative(2) + y**-1 + + ''' + for x in self.A: + gamma = self.table[coset][self.A_dict[x]] + if coset == 0: + return self.fp_group.identity + if gamma < coset: + return self.coset_representative(gamma)*x**-1 + + ############################## + # Modified Methods # + ############################## + + def modified_define(self, alpha, x): + r""" + Define a function p_p from from [1..n] to A* as + an additional component of the modified coset table. + + Parameters + ========== + + \alpha \in \Omega + x \in A* + + See Also + ======== + + define + + """ + self.define(alpha, x, modified=True) + + def modified_scan(self, alpha, w, y, fill=False): + r""" + Parameters + ========== + \alpha \in \Omega + w \in A* + y \in (YUY^-1) + fill -- `modified_scan_and_fill` when set to True. + + See Also + ======== + + scan + """ + self.scan(alpha, w, y=y, fill=fill, modified=True) + + def modified_scan_and_fill(self, alpha, w, y): + self.modified_scan(alpha, w, y, fill=True) + + def modified_merge(self, k, lamda, w, q): + r""" + Parameters + ========== + + 'k', 'lamda' -- the two class representatives to be merged. + q -- queue of length l of elements to be deleted from `\Omega` *. + w -- Word in (YUY^-1) + + See Also + ======== + + merge + """ + self.merge(k, lamda, q, w=w, modified=True) + + def modified_rep(self, k): + r""" + Parameters + ========== + + `k \in [0 \ldots n-1]` + + See Also + ======== + + rep + """ + self.rep(k, modified=True) + + def modified_coincidence(self, alpha, beta, w): + r""" + Parameters + ========== + + A coincident pair `\alpha, \beta \in \Omega, w \in Y \cup Y^{-1}` + + See Also + ======== + + coincidence + + """ + self.coincidence(alpha, beta, w=w, modified=True) + +############################################################################### +# COSET ENUMERATION # +############################################################################### + +# relator-based method +def coset_enumeration_r(fp_grp, Y, max_cosets=None, draft=None, + incomplete=False, modified=False): + """ + This is easier of the two implemented methods of coset enumeration. + and is often called the HLT method, after Hazelgrove, Leech, Trotter + The idea is that we make use of ``scan_and_fill`` makes new definitions + whenever the scan is incomplete to enable the scan to complete; this way + we fill in the gaps in the scan of the relator or subgroup generator, + that's why the name relator-based method. + + An instance of `CosetTable` for `fp_grp` can be passed as the keyword + argument `draft` in which case the coset enumeration will start with + that instance and attempt to complete it. + + When `incomplete` is `True` and the function is unable to complete for + some reason, the partially complete table will be returned. + + # TODO: complete the docstring + + See Also + ======== + + scan_and_fill, + + Examples + ======== + + >>> from sympy.combinatorics.free_groups import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_r + >>> F, x, y = free_group("x, y") + + # Example 5.1 from [1] + >>> f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) + >>> C = coset_enumeration_r(f, [x]) + >>> for i in range(len(C.p)): + ... if C.p[i] == i: + ... print(C.table[i]) + [0, 0, 1, 2] + [1, 1, 2, 0] + [2, 2, 0, 1] + >>> C.p + [0, 1, 2, 1, 1] + + # Example from exercises Q2 [1] + >>> f = FpGroup(F, [x**2*y**2, y**-1*x*y*x**-3]) + >>> C = coset_enumeration_r(f, []) + >>> C.compress(); C.standardize() + >>> C.table + [[1, 2, 3, 4], + [5, 0, 6, 7], + [0, 5, 7, 6], + [7, 6, 5, 0], + [6, 7, 0, 5], + [2, 1, 4, 3], + [3, 4, 2, 1], + [4, 3, 1, 2]] + + # Example 5.2 + >>> f = FpGroup(F, [x**2, y**3, (x*y)**3]) + >>> Y = [x*y] + >>> C = coset_enumeration_r(f, Y) + >>> for i in range(len(C.p)): + ... if C.p[i] == i: + ... print(C.table[i]) + [1, 1, 2, 1] + [0, 0, 0, 2] + [3, 3, 1, 0] + [2, 2, 3, 3] + + # Example 5.3 + >>> f = FpGroup(F, [x**2*y**2, x**3*y**5]) + >>> Y = [] + >>> C = coset_enumeration_r(f, Y) + >>> for i in range(len(C.p)): + ... if C.p[i] == i: + ... print(C.table[i]) + [1, 3, 1, 3] + [2, 0, 2, 0] + [3, 1, 3, 1] + [0, 2, 0, 2] + + # Example 5.4 + >>> F, a, b, c, d, e = free_group("a, b, c, d, e") + >>> f = FpGroup(F, [a*b*c**-1, b*c*d**-1, c*d*e**-1, d*e*a**-1, e*a*b**-1]) + >>> Y = [a] + >>> C = coset_enumeration_r(f, Y) + >>> for i in range(len(C.p)): + ... if C.p[i] == i: + ... print(C.table[i]) + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + + # example of "compress" method + >>> C.compress() + >>> C.table + [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] + + # Exercises Pg. 161, Q2. + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**2*y**2, y**-1*x*y*x**-3]) + >>> Y = [] + >>> C = coset_enumeration_r(f, Y) + >>> C.compress() + >>> C.standardize() + >>> C.table + [[1, 2, 3, 4], + [5, 0, 6, 7], + [0, 5, 7, 6], + [7, 6, 5, 0], + [6, 7, 0, 5], + [2, 1, 4, 3], + [3, 4, 2, 1], + [4, 3, 1, 2]] + + # John J. Cannon; Lucien A. Dimino; George Havas; Jane M. Watson + # Mathematics of Computation, Vol. 27, No. 123. (Jul., 1973), pp. 463-490 + # from 1973chwd.pdf + # Table 1. Ex. 1 + >>> F, r, s, t = free_group("r, s, t") + >>> E1 = FpGroup(F, [t**-1*r*t*r**-2, r**-1*s*r*s**-2, s**-1*t*s*t**-2]) + >>> C = coset_enumeration_r(E1, [r]) + >>> for i in range(len(C.p)): + ... if C.p[i] == i: + ... print(C.table[i]) + [0, 0, 0, 0, 0, 0] + + Ex. 2 + >>> F, a, b = free_group("a, b") + >>> Cox = FpGroup(F, [a**6, b**6, (a*b)**2, (a**2*b**2)**2, (a**3*b**3)**5]) + >>> C = coset_enumeration_r(Cox, [a]) + >>> index = 0 + >>> for i in range(len(C.p)): + ... if C.p[i] == i: + ... index += 1 + >>> index + 500 + + # Ex. 3 + >>> F, a, b = free_group("a, b") + >>> B_2_4 = FpGroup(F, [a**4, b**4, (a*b)**4, (a**-1*b)**4, (a**2*b)**4, \ + (a*b**2)**4, (a**2*b**2)**4, (a**-1*b*a*b)**4, (a*b**-1*a*b)**4]) + >>> C = coset_enumeration_r(B_2_4, [a]) + >>> index = 0 + >>> for i in range(len(C.p)): + ... if C.p[i] == i: + ... index += 1 + >>> index + 1024 + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of computational group theory" + + """ + # 1. Initialize a coset table C for < X|R > + C = CosetTable(fp_grp, Y, max_cosets=max_cosets) + # Define coset table methods. + if modified: + _scan_and_fill = C.modified_scan_and_fill + _define = C.modified_define + else: + _scan_and_fill = C.scan_and_fill + _define = C.define + if draft: + C.table = draft.table[:] + C.p = draft.p[:] + R = fp_grp.relators + A_dict = C.A_dict + p = C.p + for i in range(len(Y)): + if modified: + _scan_and_fill(0, Y[i], C._grp.generators[i]) + else: + _scan_and_fill(0, Y[i]) + alpha = 0 + while alpha < C.n: + if p[alpha] == alpha: + try: + for w in R: + if modified: + _scan_and_fill(alpha, w, C._grp.identity) + else: + _scan_and_fill(alpha, w) + # if alpha was eliminated during the scan then break + if p[alpha] < alpha: + break + if p[alpha] == alpha: + for x in A_dict: + if C.table[alpha][A_dict[x]] is None: + _define(alpha, x) + except ValueError as e: + if incomplete: + return C + raise e + alpha += 1 + return C + +def modified_coset_enumeration_r(fp_grp, Y, max_cosets=None, draft=None, + incomplete=False): + r""" + Introduce a new set of symbols y \in Y that correspond to the + generators of the subgroup. Store the elements of Y as a + word P[\alpha, x] and compute the coset table similar to that of + the regular coset enumeration methods. + + Examples + ======== + + >>> from sympy.combinatorics.free_groups import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup + >>> from sympy.combinatorics.coset_table import modified_coset_enumeration_r + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) + >>> C = modified_coset_enumeration_r(f, [x]) + >>> C.table + [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1], [None, 1, None, None], [1, 3, None, None]] + + See Also + ======== + + coset_enumertation_r + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E., + "Handbook of Computational Group Theory", + Section 5.3.2 + """ + return coset_enumeration_r(fp_grp, Y, max_cosets=max_cosets, draft=draft, + incomplete=incomplete, modified=True) + +# Pg. 166 +# coset-table based method +def coset_enumeration_c(fp_grp, Y, max_cosets=None, draft=None, + incomplete=False): + """ + >>> from sympy.combinatorics.free_groups import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_c + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) + >>> C = coset_enumeration_c(f, [x]) + >>> C.table + [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1]] + + """ + # Initialize a coset table C for < X|R > + X = fp_grp.generators + R = fp_grp.relators + C = CosetTable(fp_grp, Y, max_cosets=max_cosets) + if draft: + C.table = draft.table[:] + C.p = draft.p[:] + C.deduction_stack = draft.deduction_stack + for alpha, x in product(range(len(C.table)), X): + if C.table[alpha][C.A_dict[x]] is not None: + C.deduction_stack.append((alpha, x)) + A = C.A + # replace all the elements by cyclic reductions + R_cyc_red = [rel.identity_cyclic_reduction() for rel in R] + R_c = list(chain.from_iterable((rel.cyclic_conjugates(), (rel**-1).cyclic_conjugates()) \ + for rel in R_cyc_red)) + R_set = set() + for conjugate in R_c: + R_set = R_set.union(conjugate) + # a list of subsets of R_c whose words start with "x". + R_c_list = [] + for x in C.A: + r = {word for word in R_set if word[0] == x} + R_c_list.append(r) + R_set.difference_update(r) + for w in Y: + C.scan_and_fill_c(0, w) + for x in A: + C.process_deductions(R_c_list[C.A_dict[x]], R_c_list[C.A_dict_inv[x]]) + alpha = 0 + while alpha < len(C.table): + if C.p[alpha] == alpha: + try: + for x in C.A: + if C.p[alpha] != alpha: + break + if C.table[alpha][C.A_dict[x]] is None: + C.define_c(alpha, x) + C.process_deductions(R_c_list[C.A_dict[x]], R_c_list[C.A_dict_inv[x]]) + except ValueError as e: + if incomplete: + return C + raise e + alpha += 1 + return C diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/fp_groups.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/fp_groups.py new file mode 100644 index 0000000000000000000000000000000000000000..95530ccd44f025eca5f029c6ba60d3727cbcb29d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/fp_groups.py @@ -0,0 +1,1352 @@ +"""Finitely Presented Groups and its algorithms. """ + +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.combinatorics.free_groups import (FreeGroup, FreeGroupElement, + free_group) +from sympy.combinatorics.rewritingsystem import RewritingSystem +from sympy.combinatorics.coset_table import (CosetTable, + coset_enumeration_r, + coset_enumeration_c) +from sympy.combinatorics import PermutationGroup +from sympy.matrices.normalforms import invariant_factors +from sympy.matrices import Matrix +from sympy.polys.polytools import gcd +from sympy.printing.defaults import DefaultPrinting +from sympy.utilities import public +from sympy.utilities.magic import pollute + +from itertools import product + + +@public +def fp_group(fr_grp, relators=()): + _fp_group = FpGroup(fr_grp, relators) + return (_fp_group,) + tuple(_fp_group._generators) + +@public +def xfp_group(fr_grp, relators=()): + _fp_group = FpGroup(fr_grp, relators) + return (_fp_group, _fp_group._generators) + +# Does not work. Both symbols and pollute are undefined. Never tested. +@public +def vfp_group(fr_grpm, relators): + _fp_group = FpGroup(symbols, relators) + pollute([sym.name for sym in _fp_group.symbols], _fp_group.generators) + return _fp_group + + +def _parse_relators(rels): + """Parse the passed relators.""" + return rels + + +############################################################################### +# FINITELY PRESENTED GROUPS # +############################################################################### + + +class FpGroup(DefaultPrinting): + """ + The FpGroup would take a FreeGroup and a list/tuple of relators, the + relators would be specified in such a way that each of them be equal to the + identity of the provided free group. + + """ + is_group = True + is_FpGroup = True + is_PermutationGroup = False + + def __init__(self, fr_grp, relators): + relators = _parse_relators(relators) + self.free_group = fr_grp + self.relators = relators + self.generators = self._generators() + self.dtype = type("FpGroupElement", (FpGroupElement,), {"group": self}) + + # CosetTable instance on identity subgroup + self._coset_table = None + # returns whether coset table on identity subgroup + # has been standardized + self._is_standardized = False + + self._order = None + self._center = None + + self._rewriting_system = RewritingSystem(self) + self._perm_isomorphism = None + return + + def _generators(self): + return self.free_group.generators + + def make_confluent(self): + ''' + Try to make the group's rewriting system confluent + + ''' + self._rewriting_system.make_confluent() + return + + def reduce(self, word): + ''' + Return the reduced form of `word` in `self` according to the group's + rewriting system. If it's confluent, the reduced form is the unique normal + form of the word in the group. + + ''' + return self._rewriting_system.reduce(word) + + def equals(self, word1, word2): + ''' + Compare `word1` and `word2` for equality in the group + using the group's rewriting system. If the system is + confluent, the returned answer is necessarily correct. + (If it is not, `False` could be returned in some cases + where in fact `word1 == word2`) + + ''' + if self.reduce(word1*word2**-1) == self.identity: + return True + elif self._rewriting_system.is_confluent: + return False + return None + + @property + def identity(self): + return self.free_group.identity + + def __contains__(self, g): + return g in self.free_group + + def subgroup(self, gens, C=None, homomorphism=False): + ''' + Return the subgroup generated by `gens` using the + Reidemeister-Schreier algorithm + homomorphism -- When set to True, return a dictionary containing the images + of the presentation generators in the original group. + + Examples + ======== + + >>> from sympy.combinatorics.fp_groups import FpGroup + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**3, y**5, (x*y)**2]) + >>> H = [x*y, x**-1*y**-1*x*y*x] + >>> K, T = f.subgroup(H, homomorphism=True) + >>> T(K.generators) + [x*y, x**-1*y**2*x**-1] + + ''' + + if not all(isinstance(g, FreeGroupElement) for g in gens): + raise ValueError("Generators must be `FreeGroupElement`s") + if not all(g.group == self.free_group for g in gens): + raise ValueError("Given generators are not members of the group") + if homomorphism: + g, rels, _gens = reidemeister_presentation(self, gens, C=C, homomorphism=True) + else: + g, rels = reidemeister_presentation(self, gens, C=C) + if g: + g = FpGroup(g[0].group, rels) + else: + g = FpGroup(free_group('')[0], []) + if homomorphism: + from sympy.combinatorics.homomorphisms import homomorphism + return g, homomorphism(g, self, g.generators, _gens, check=False) + return g + + def coset_enumeration(self, H, strategy="relator_based", max_cosets=None, + draft=None, incomplete=False): + """ + Return an instance of ``coset table``, when Todd-Coxeter algorithm is + run over the ``self`` with ``H`` as subgroup, using ``strategy`` + argument as strategy. The returned coset table is compressed but not + standardized. + + An instance of `CosetTable` for `fp_grp` can be passed as the keyword + argument `draft` in which case the coset enumeration will start with + that instance and attempt to complete it. + + When `incomplete` is `True` and the function is unable to complete for + some reason, the partially complete table will be returned. + + """ + if not max_cosets: + max_cosets = CosetTable.coset_table_max_limit + if strategy == 'relator_based': + C = coset_enumeration_r(self, H, max_cosets=max_cosets, + draft=draft, incomplete=incomplete) + else: + C = coset_enumeration_c(self, H, max_cosets=max_cosets, + draft=draft, incomplete=incomplete) + if C.is_complete(): + C.compress() + return C + + def standardize_coset_table(self): + """ + Standardized the coset table ``self`` and makes the internal variable + ``_is_standardized`` equal to ``True``. + + """ + self._coset_table.standardize() + self._is_standardized = True + + def coset_table(self, H, strategy="relator_based", max_cosets=None, + draft=None, incomplete=False): + """ + Return the mathematical coset table of ``self`` in ``H``. + + """ + if not H: + if self._coset_table is not None: + if not self._is_standardized: + self.standardize_coset_table() + else: + C = self.coset_enumeration([], strategy, max_cosets=max_cosets, + draft=draft, incomplete=incomplete) + self._coset_table = C + self.standardize_coset_table() + return self._coset_table.table + else: + C = self.coset_enumeration(H, strategy, max_cosets=max_cosets, + draft=draft, incomplete=incomplete) + C.standardize() + return C.table + + def order(self, strategy="relator_based"): + """ + Returns the order of the finitely presented group ``self``. It uses + the coset enumeration with identity group as subgroup, i.e ``H=[]``. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x, y**2]) + >>> f.order(strategy="coset_table_based") + 2 + + """ + if self._order is not None: + return self._order + if self._coset_table is not None: + self._order = len(self._coset_table.table) + elif len(self.relators) == 0: + self._order = self.free_group.order() + elif len(self.generators) == 1: + self._order = abs(gcd([r.array_form[0][1] for r in self.relators])) + elif self._is_infinite(): + self._order = S.Infinity + else: + gens, C = self._finite_index_subgroup() + if C: + ind = len(C.table) + self._order = ind*self.subgroup(gens, C=C).order() + else: + self._order = self.index([]) + return self._order + + def _is_infinite(self): + ''' + Test if the group is infinite. Return `True` if the test succeeds + and `None` otherwise + + ''' + used_gens = set() + for r in self.relators: + used_gens.update(r.contains_generators()) + if not set(self.generators) <= used_gens: + return True + # Abelianisation test: check is the abelianisation is infinite + abelian_rels = [] + for rel in self.relators: + abelian_rels.append([rel.exponent_sum(g) for g in self.generators]) + m = Matrix(Matrix(abelian_rels)) + if 0 in invariant_factors(m): + return True + else: + return None + + + def _finite_index_subgroup(self, s=None): + ''' + Find the elements of `self` that generate a finite index subgroup + and, if found, return the list of elements and the coset table of `self` by + the subgroup, otherwise return `(None, None)` + + ''' + gen = self.most_frequent_generator() + rels = list(self.generators) + rels.extend(self.relators) + if not s: + if len(self.generators) == 2: + s = [gen] + [g for g in self.generators if g != gen] + else: + rand = self.free_group.identity + i = 0 + while ((rand in rels or rand**-1 in rels or rand.is_identity) + and i<10): + rand = self.random() + i += 1 + s = [gen, rand] + [g for g in self.generators if g != gen] + mid = (len(s)+1)//2 + half1 = s[:mid] + half2 = s[mid:] + draft1 = None + draft2 = None + m = 200 + C = None + while not C and (m/2 < CosetTable.coset_table_max_limit): + m = min(m, CosetTable.coset_table_max_limit) + draft1 = self.coset_enumeration(half1, max_cosets=m, + draft=draft1, incomplete=True) + if draft1.is_complete(): + C = draft1 + half = half1 + else: + draft2 = self.coset_enumeration(half2, max_cosets=m, + draft=draft2, incomplete=True) + if draft2.is_complete(): + C = draft2 + half = half2 + if not C: + m *= 2 + if not C: + return None, None + C.compress() + return half, C + + def most_frequent_generator(self): + gens = self.generators + rels = self.relators + freqs = [sum(r.generator_count(g) for r in rels) for g in gens] + return gens[freqs.index(max(freqs))] + + def random(self): + import random + r = self.free_group.identity + for i in range(random.randint(2,3)): + r = r*random.choice(self.generators)**random.choice([1,-1]) + return r + + def index(self, H, strategy="relator_based"): + """ + Return the index of subgroup ``H`` in group ``self``. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**5, y**4, y*x*y**3*x**3]) + >>> f.index([x]) + 4 + + """ + # TODO: use |G:H| = |G|/|H| (currently H can't be made into a group) + # when we know |G| and |H| + + if H == []: + return self.order() + else: + C = self.coset_enumeration(H, strategy) + return len(C.table) + + def __str__(self): + if self.free_group.rank > 30: + str_form = "" % self.free_group.rank + else: + str_form = "" % str(self.generators) + return str_form + + __repr__ = __str__ + +#============================================================================== +# PERMUTATION GROUP METHODS +#============================================================================== + + def _to_perm_group(self): + ''' + Return an isomorphic permutation group and the isomorphism. + The implementation is dependent on coset enumeration so + will only terminate for finite groups. + + ''' + from sympy.combinatorics import Permutation + from sympy.combinatorics.homomorphisms import homomorphism + if self.order() is S.Infinity: + raise NotImplementedError("Permutation presentation of infinite " + "groups is not implemented") + if self._perm_isomorphism: + T = self._perm_isomorphism + P = T.image() + else: + C = self.coset_table([]) + gens = self.generators + images = [[C[i][2*gens.index(g)] for i in range(len(C))] for g in gens] + images = [Permutation(i) for i in images] + P = PermutationGroup(images) + T = homomorphism(self, P, gens, images, check=False) + self._perm_isomorphism = T + return P, T + + def _perm_group_list(self, method_name, *args): + ''' + Given the name of a `PermutationGroup` method (returning a subgroup + or a list of subgroups) and (optionally) additional arguments it takes, + return a list or a list of lists containing the generators of this (or + these) subgroups in terms of the generators of `self`. + + ''' + P, T = self._to_perm_group() + perm_result = getattr(P, method_name)(*args) + single = False + if isinstance(perm_result, PermutationGroup): + perm_result, single = [perm_result], True + result = [] + for group in perm_result: + gens = group.generators + result.append(T.invert(gens)) + return result[0] if single else result + + def derived_series(self): + ''' + Return the list of lists containing the generators + of the subgroups in the derived series of `self`. + + ''' + return self._perm_group_list('derived_series') + + def lower_central_series(self): + ''' + Return the list of lists containing the generators + of the subgroups in the lower central series of `self`. + + ''' + return self._perm_group_list('lower_central_series') + + def center(self): + ''' + Return the list of generators of the center of `self`. + + ''' + return self._perm_group_list('center') + + + def derived_subgroup(self): + ''' + Return the list of generators of the derived subgroup of `self`. + + ''' + return self._perm_group_list('derived_subgroup') + + + def centralizer(self, other): + ''' + Return the list of generators of the centralizer of `other` + (a list of elements of `self`) in `self`. + + ''' + T = self._to_perm_group()[1] + other = T(other) + return self._perm_group_list('centralizer', other) + + def normal_closure(self, other): + ''' + Return the list of generators of the normal closure of `other` + (a list of elements of `self`) in `self`. + + ''' + T = self._to_perm_group()[1] + other = T(other) + return self._perm_group_list('normal_closure', other) + + def _perm_property(self, attr): + ''' + Given an attribute of a `PermutationGroup`, return + its value for a permutation group isomorphic to `self`. + + ''' + P = self._to_perm_group()[0] + return getattr(P, attr) + + @property + def is_abelian(self): + ''' + Check if `self` is abelian. + + ''' + return self._perm_property("is_abelian") + + @property + def is_nilpotent(self): + ''' + Check if `self` is nilpotent. + + ''' + return self._perm_property("is_nilpotent") + + @property + def is_solvable(self): + ''' + Check if `self` is solvable. + + ''' + return self._perm_property("is_solvable") + + @property + def elements(self): + ''' + List the elements of `self`. + + ''' + P, T = self._to_perm_group() + return T.invert(P.elements) + + @property + def is_cyclic(self): + """ + Return ``True`` if group is Cyclic. + + """ + if len(self.generators) <= 1: + return True + try: + P, T = self._to_perm_group() + except NotImplementedError: + raise NotImplementedError("Check for infinite Cyclic group " + "is not implemented") + return P.is_cyclic + + def abelian_invariants(self): + """ + Return Abelian Invariants of a group. + """ + try: + P, T = self._to_perm_group() + except NotImplementedError: + raise NotImplementedError("abelian invariants is not implemented" + "for infinite group") + return P.abelian_invariants() + + def composition_series(self): + """ + Return subnormal series of maximum length for a group. + """ + try: + P, T = self._to_perm_group() + except NotImplementedError: + raise NotImplementedError("composition series is not implemented" + "for infinite group") + return P.composition_series() + + +class FpSubgroup(DefaultPrinting): + ''' + The class implementing a subgroup of an FpGroup or a FreeGroup + (only finite index subgroups are supported at this point). This + is to be used if one wishes to check if an element of the original + group belongs to the subgroup + + ''' + def __init__(self, G, gens, normal=False): + super().__init__() + self.parent = G + self.generators = list({g for g in gens if g != G.identity}) + self._min_words = None #for use in __contains__ + self.C = None + self.normal = normal + + def __contains__(self, g): + + if isinstance(self.parent, FreeGroup): + if self._min_words is None: + # make _min_words - a list of subwords such that + # g is in the subgroup if and only if it can be + # partitioned into these subwords. Infinite families of + # subwords are presented by tuples, e.g. (r, w) + # stands for the family of subwords r*w**n*r**-1 + + def _process(w): + # this is to be used before adding new words + # into _min_words; if the word w is not cyclically + # reduced, it will generate an infinite family of + # subwords so should be written as a tuple; + # if it is, w**-1 should be added to the list + # as well + p, r = w.cyclic_reduction(removed=True) + if not r.is_identity: + return [(r, p)] + else: + return [w, w**-1] + + # make the initial list + gens = [] + for w in self.generators: + if self.normal: + w = w.cyclic_reduction() + gens.extend(_process(w)) + + for w1 in gens: + for w2 in gens: + # if w1 and w2 are equal or are inverses, continue + if w1 == w2 or (not isinstance(w1, tuple) + and w1**-1 == w2): + continue + + # if the start of one word is the inverse of the + # end of the other, their multiple should be added + # to _min_words because of cancellation + if isinstance(w1, tuple): + # start, end + s1, s2 = w1[0][0], w1[0][0]**-1 + else: + s1, s2 = w1[0], w1[len(w1)-1] + + if isinstance(w2, tuple): + # start, end + r1, r2 = w2[0][0], w2[0][0]**-1 + else: + r1, r2 = w2[0], w2[len(w1)-1] + + # p1 and p2 are w1 and w2 or, in case when + # w1 or w2 is an infinite family, a representative + p1, p2 = w1, w2 + if isinstance(w1, tuple): + p1 = w1[0]*w1[1]*w1[0]**-1 + if isinstance(w2, tuple): + p2 = w2[0]*w2[1]*w2[0]**-1 + + # add the product of the words to the list is necessary + if r1**-1 == s2 and not (p1*p2).is_identity: + new = _process(p1*p2) + if new not in gens: + gens.extend(new) + + if r2**-1 == s1 and not (p2*p1).is_identity: + new = _process(p2*p1) + if new not in gens: + gens.extend(new) + + self._min_words = gens + + min_words = self._min_words + + def _is_subword(w): + # check if w is a word in _min_words or one of + # the infinite families in it + w, r = w.cyclic_reduction(removed=True) + if r.is_identity or self.normal: + return w in min_words + else: + t = [s[1] for s in min_words if isinstance(s, tuple) + and s[0] == r] + return [s for s in t if w.power_of(s)] != [] + + # store the solution of words for which the result of + # _word_break (below) is known + known = {} + + def _word_break(w): + # check if w can be written as a product of words + # in min_words + if len(w) == 0: + return True + i = 0 + while i < len(w): + i += 1 + prefix = w.subword(0, i) + if not _is_subword(prefix): + continue + rest = w.subword(i, len(w)) + if rest not in known: + known[rest] = _word_break(rest) + if known[rest]: + return True + return False + + if self.normal: + g = g.cyclic_reduction() + return _word_break(g) + else: + if self.C is None: + C = self.parent.coset_enumeration(self.generators) + self.C = C + i = 0 + C = self.C + for j in range(len(g)): + i = C.table[i][C.A_dict[g[j]]] + return i == 0 + + def order(self): + if not self.generators: + return S.One + if isinstance(self.parent, FreeGroup): + return S.Infinity + if self.C is None: + C = self.parent.coset_enumeration(self.generators) + self.C = C + # This is valid because `len(self.C.table)` (the index of the subgroup) + # will always be finite - otherwise coset enumeration doesn't terminate + return self.parent.order()/len(self.C.table) + + def to_FpGroup(self): + if isinstance(self.parent, FreeGroup): + gen_syms = [('x_%d'%i) for i in range(len(self.generators))] + return free_group(', '.join(gen_syms))[0] + return self.parent.subgroup(C=self.C) + + def __str__(self): + if len(self.generators) > 30: + str_form = "" % len(self.generators) + else: + str_form = "" % str(self.generators) + return str_form + + __repr__ = __str__ + + +############################################################################### +# LOW INDEX SUBGROUPS # +############################################################################### + +def low_index_subgroups(G, N, Y=()): + """ + Implements the Low Index Subgroups algorithm, i.e find all subgroups of + ``G`` upto a given index ``N``. This implements the method described in + [Sim94]. This procedure involves a backtrack search over incomplete Coset + Tables, rather than over forced coincidences. + + Parameters + ========== + + G: An FpGroup < X|R > + N: positive integer, representing the maximum index value for subgroups + Y: (an optional argument) specifying a list of subgroup generators, such + that each of the resulting subgroup contains the subgroup generated by Y. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup, low_index_subgroups + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**2, y**3, (x*y)**4]) + >>> L = low_index_subgroups(f, 4) + >>> for coset_table in L: + ... print(coset_table.table) + [[0, 0, 0, 0]] + [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 3, 3]] + [[0, 0, 1, 2], [2, 2, 2, 0], [1, 1, 0, 1]] + [[1, 1, 0, 0], [0, 0, 1, 1]] + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of Computational Group Theory" + Section 5.4 + + .. [2] Marston Conder and Peter Dobcsanyi + "Applications and Adaptions of the Low Index Subgroups Procedure" + + """ + C = CosetTable(G, []) + R = G.relators + # length chosen for the length of the short relators + len_short_rel = 5 + # elements of R2 only checked at the last step for complete + # coset tables + R2 = {rel for rel in R if len(rel) > len_short_rel} + # elements of R1 are used in inner parts of the process to prune + # branches of the search tree, + R1 = {rel.identity_cyclic_reduction() for rel in set(R) - R2} + R1_c_list = C.conjugates(R1) + S = [] + descendant_subgroups(S, C, R1_c_list, C.A[0], R2, N, Y) + return S + + +def descendant_subgroups(S, C, R1_c_list, x, R2, N, Y): + A_dict = C.A_dict + A_dict_inv = C.A_dict_inv + if C.is_complete(): + # if C is complete then it only needs to test + # whether the relators in R2 are satisfied + for w, alpha in product(R2, C.omega): + if not C.scan_check(alpha, w): + return + # relators in R2 are satisfied, append the table to list + S.append(C) + else: + # find the first undefined entry in Coset Table + for alpha, x in product(range(len(C.table)), C.A): + if C.table[alpha][A_dict[x]] is None: + # this is "x" in pseudo-code (using "y" makes it clear) + undefined_coset, undefined_gen = alpha, x + break + # for filling up the undefine entry we try all possible values + # of beta in Omega or beta = n where beta^(undefined_gen^-1) is undefined + reach = C.omega + [C.n] + for beta in reach: + if beta < N: + if beta == C.n or C.table[beta][A_dict_inv[undefined_gen]] is None: + try_descendant(S, C, R1_c_list, R2, N, undefined_coset, \ + undefined_gen, beta, Y) + + +def try_descendant(S, C, R1_c_list, R2, N, alpha, x, beta, Y): + r""" + Solves the problem of trying out each individual possibility + for `\alpha^x. + + """ + D = C.copy() + if beta == D.n and beta < N: + D.table.append([None]*len(D.A)) + D.p.append(beta) + D.table[alpha][D.A_dict[x]] = beta + D.table[beta][D.A_dict_inv[x]] = alpha + D.deduction_stack.append((alpha, x)) + if not D.process_deductions_check(R1_c_list[D.A_dict[x]], \ + R1_c_list[D.A_dict_inv[x]]): + return + for w in Y: + if not D.scan_check(0, w): + return + if first_in_class(D, Y): + descendant_subgroups(S, D, R1_c_list, x, R2, N, Y) + + +def first_in_class(C, Y=()): + """ + Checks whether the subgroup ``H=G1`` corresponding to the Coset Table + could possibly be the canonical representative of its conjugacy class. + + Parameters + ========== + + C: CosetTable + + Returns + ======= + + bool: True/False + + If this returns False, then no descendant of C can have that property, and + so we can abandon C. If it returns True, then we need to process further + the node of the search tree corresponding to C, and so we call + ``descendant_subgroups`` recursively on C. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup, CosetTable, first_in_class + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**2, y**3, (x*y)**4]) + >>> C = CosetTable(f, []) + >>> C.table = [[0, 0, None, None]] + >>> first_in_class(C) + True + >>> C.table = [[1, 1, 1, None], [0, 0, None, 1]]; C.p = [0, 1] + >>> first_in_class(C) + True + >>> C.table = [[1, 1, 2, 1], [0, 0, 0, None], [None, None, None, 0]] + >>> C.p = [0, 1, 2] + >>> first_in_class(C) + False + >>> C.table = [[1, 1, 1, 2], [0, 0, 2, 0], [2, None, 0, 1]] + >>> first_in_class(C) + False + + # TODO:: Sims points out in [Sim94] that performance can be improved by + # remembering some of the information computed by ``first_in_class``. If + # the ``continue alpha`` statement is executed at line 14, then the same thing + # will happen for that value of alpha in any descendant of the table C, and so + # the values the values of alpha for which this occurs could profitably be + # stored and passed through to the descendants of C. Of course this would + # make the code more complicated. + + # The code below is taken directly from the function on page 208 of [Sim94] + # nu[alpha] + + """ + n = C.n + # lamda is the largest numbered point in Omega_c_alpha which is currently defined + lamda = -1 + # for alpha in Omega_c, nu[alpha] is the point in Omega_c_alpha corresponding to alpha + nu = [None]*n + # for alpha in Omega_c_alpha, mu[alpha] is the point in Omega_c corresponding to alpha + mu = [None]*n + # mutually nu and mu are the mutually-inverse equivalence maps between + # Omega_c_alpha and Omega_c + next_alpha = False + # For each 0!=alpha in [0 .. nc-1], we start by constructing the equivalent + # standardized coset table C_alpha corresponding to H_alpha + for alpha in range(1, n): + # reset nu to "None" after previous value of alpha + for beta in range(lamda+1): + nu[mu[beta]] = None + # we only want to reject our current table in favour of a preceding + # table in the ordering in which 1 is replaced by alpha, if the subgroup + # G_alpha corresponding to this preceding table definitely contains the + # given subgroup + for w in Y: + # TODO: this should support input of a list of general words + # not just the words which are in "A" (i.e gen and gen^-1) + if C.table[alpha][C.A_dict[w]] != alpha: + # continue with alpha + next_alpha = True + break + if next_alpha: + next_alpha = False + continue + # try alpha as the new point 0 in Omega_C_alpha + mu[0] = alpha + nu[alpha] = 0 + # compare corresponding entries in C and C_alpha + lamda = 0 + for beta in range(n): + for x in C.A: + gamma = C.table[beta][C.A_dict[x]] + delta = C.table[mu[beta]][C.A_dict[x]] + # if either of the entries is undefined, + # we move with next alpha + if gamma is None or delta is None: + # continue with alpha + next_alpha = True + break + if nu[delta] is None: + # delta becomes the next point in Omega_C_alpha + lamda += 1 + nu[delta] = lamda + mu[lamda] = delta + if nu[delta] < gamma: + return False + if nu[delta] > gamma: + # continue with alpha + next_alpha = True + break + if next_alpha: + next_alpha = False + break + return True + +#======================================================================== +# Simplifying Presentation +#======================================================================== + +def simplify_presentation(*args, change_gens=False): + ''' + For an instance of `FpGroup`, return a simplified isomorphic copy of + the group (e.g. remove redundant generators or relators). Alternatively, + a list of generators and relators can be passed in which case the + simplified lists will be returned. + + By default, the generators of the group are unchanged. If you would + like to remove redundant generators, set the keyword argument + `change_gens = True`. + + ''' + if len(args) == 1: + if not isinstance(args[0], FpGroup): + raise TypeError("The argument must be an instance of FpGroup") + G = args[0] + gens, rels = simplify_presentation(G.generators, G.relators, + change_gens=change_gens) + if gens: + return FpGroup(gens[0].group, rels) + return FpGroup(FreeGroup([]), []) + elif len(args) == 2: + gens, rels = args[0][:], args[1][:] + if not gens: + return gens, rels + identity = gens[0].group.identity + else: + if len(args) == 0: + m = "Not enough arguments" + else: + m = "Too many arguments" + raise RuntimeError(m) + + prev_gens = [] + prev_rels = [] + while not set(prev_rels) == set(rels): + prev_rels = rels + while change_gens and not set(prev_gens) == set(gens): + prev_gens = gens + gens, rels = elimination_technique_1(gens, rels, identity) + rels = _simplify_relators(rels) + + if change_gens: + syms = [g.array_form[0][0] for g in gens] + F = free_group(syms)[0] + identity = F.identity + gens = F.generators + subs = dict(zip(syms, gens)) + for j, r in enumerate(rels): + a = r.array_form + rel = identity + for sym, p in a: + rel = rel*subs[sym]**p + rels[j] = rel + return gens, rels + +def _simplify_relators(rels): + """ + Simplifies a set of relators. All relators are checked to see if they are + of the form `gen^n`. If any such relators are found then all other relators + are processed for strings in the `gen` known order. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import _simplify_relators + >>> F, x, y = free_group("x, y") + >>> w1 = [x**2*y**4, x**3] + >>> _simplify_relators(w1) + [x**3, x**-1*y**4] + + >>> w2 = [x**2*y**-4*x**5, x**3, x**2*y**8, y**5] + >>> _simplify_relators(w2) + [x**-1*y**-2, x**-1*y*x**-1, x**3, y**5] + + >>> w3 = [x**6*y**4, x**4] + >>> _simplify_relators(w3) + [x**4, x**2*y**4] + + >>> w4 = [x**2, x**5, y**3] + >>> _simplify_relators(w4) + [x, y**3] + + """ + rels = rels[:] + + if not rels: + return [] + + identity = rels[0].group.identity + + # build dictionary with "gen: n" where gen^n is one of the relators + exps = {} + for i in range(len(rels)): + rel = rels[i] + if rel.number_syllables() == 1: + g = rel[0] + exp = abs(rel.array_form[0][1]) + if rel.array_form[0][1] < 0: + rels[i] = rels[i]**-1 + g = g**-1 + if g in exps: + exp = gcd(exp, exps[g].array_form[0][1]) + exps[g] = g**exp + + one_syllables_words = list(exps.values()) + # decrease some of the exponents in relators, making use of the single + # syllable relators + for i, rel in enumerate(rels): + if rel in one_syllables_words: + continue + rel = rel.eliminate_words(one_syllables_words, _all = True) + # if rels[i] contains g**n where abs(n) is greater than half of the power p + # of g in exps, g**n can be replaced by g**(n-p) (or g**(p-n) if n<0) + for g in rel.contains_generators(): + if g in exps: + exp = exps[g].array_form[0][1] + max_exp = (exp + 1)//2 + rel = rel.eliminate_word(g**(max_exp), g**(max_exp-exp), _all = True) + rel = rel.eliminate_word(g**(-max_exp), g**(-(max_exp-exp)), _all = True) + rels[i] = rel + + rels = [r.identity_cyclic_reduction() for r in rels] + + rels += one_syllables_words # include one_syllable_words in the list of relators + rels = list(set(rels)) # get unique values in rels + rels.sort() + + # remove entries in rels + try: + rels.remove(identity) + except ValueError: + pass + return rels + +# Pg 350, section 2.5.1 from [2] +def elimination_technique_1(gens, rels, identity): + rels = rels[:] + # the shorter relators are examined first so that generators selected for + # elimination will have shorter strings as equivalent + rels.sort() + gens = gens[:] + redundant_gens = {} + redundant_rels = [] + used_gens = set() + # examine each relator in relator list for any generator occurring exactly + # once + for rel in rels: + # don't look for a redundant generator in a relator which + # depends on previously found ones + contained_gens = rel.contains_generators() + if any(g in contained_gens for g in redundant_gens): + continue + contained_gens = list(contained_gens) + contained_gens.sort(reverse = True) + for gen in contained_gens: + if rel.generator_count(gen) == 1 and gen not in used_gens: + k = rel.exponent_sum(gen) + gen_index = rel.index(gen**k) + bk = rel.subword(gen_index + 1, len(rel)) + fw = rel.subword(0, gen_index) + chi = bk*fw + redundant_gens[gen] = chi**(-1*k) + used_gens.update(chi.contains_generators()) + redundant_rels.append(rel) + break + rels = [r for r in rels if r not in redundant_rels] + # eliminate the redundant generators from remaining relators + rels = [r.eliminate_words(redundant_gens, _all = True).identity_cyclic_reduction() for r in rels] + rels = list(set(rels)) + try: + rels.remove(identity) + except ValueError: + pass + gens = [g for g in gens if g not in redundant_gens] + return gens, rels + +############################################################################### +# SUBGROUP PRESENTATIONS # +############################################################################### + +# Pg 175 [1] +def define_schreier_generators(C, homomorphism=False): + ''' + Parameters + ========== + + C -- Coset table. + homomorphism -- When set to True, return a dictionary containing the images + of the presentation generators in the original group. + ''' + y = [] + gamma = 1 + f = C.fp_group + X = f.generators + if homomorphism: + # `_gens` stores the elements of the parent group to + # to which the schreier generators correspond to. + _gens = {} + # compute the schreier Traversal + tau = {} + tau[0] = f.identity + C.P = [[None]*len(C.A) for i in range(C.n)] + for alpha, x in product(C.omega, C.A): + beta = C.table[alpha][C.A_dict[x]] + if beta == gamma: + C.P[alpha][C.A_dict[x]] = "" + C.P[beta][C.A_dict_inv[x]] = "" + gamma += 1 + if homomorphism: + tau[beta] = tau[alpha]*x + elif x in X and C.P[alpha][C.A_dict[x]] is None: + y_alpha_x = '%s_%s' % (x, alpha) + y.append(y_alpha_x) + C.P[alpha][C.A_dict[x]] = y_alpha_x + if homomorphism: + _gens[y_alpha_x] = tau[alpha]*x*tau[beta]**-1 + grp_gens = list(free_group(', '.join(y))) + C._schreier_free_group = grp_gens.pop(0) + C._schreier_generators = grp_gens + if homomorphism: + C._schreier_gen_elem = _gens + # replace all elements of P by, free group elements + for i, j in product(range(len(C.P)), range(len(C.A))): + # if equals "", replace by identity element + if C.P[i][j] == "": + C.P[i][j] = C._schreier_free_group.identity + elif isinstance(C.P[i][j], str): + r = C._schreier_generators[y.index(C.P[i][j])] + C.P[i][j] = r + beta = C.table[i][j] + C.P[beta][j + 1] = r**-1 + +def reidemeister_relators(C): + R = C.fp_group.relators + rels = [rewrite(C, coset, word) for word in R for coset in range(C.n)] + order_1_gens = {i for i in rels if len(i) == 1} + + # remove all the order 1 generators from relators + rels = list(filter(lambda rel: rel not in order_1_gens, rels)) + + # replace order 1 generators by identity element in reidemeister relators + for i in range(len(rels)): + w = rels[i] + w = w.eliminate_words(order_1_gens, _all=True) + rels[i] = w + + C._schreier_generators = [i for i in C._schreier_generators + if not (i in order_1_gens or i**-1 in order_1_gens)] + + # Tietze transformation 1 i.e TT_1 + # remove cyclic conjugate elements from relators + i = 0 + while i < len(rels): + w = rels[i] + j = i + 1 + while j < len(rels): + if w.is_cyclic_conjugate(rels[j]): + del rels[j] + else: + j += 1 + i += 1 + + C._reidemeister_relators = rels + + +def rewrite(C, alpha, w): + """ + Parameters + ========== + + C: CosetTable + alpha: A live coset + w: A word in `A*` + + Returns + ======= + + rho(tau(alpha), w) + + Examples + ======== + + >>> from sympy.combinatorics.fp_groups import FpGroup, CosetTable, define_schreier_generators, rewrite + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**2, y**3, (x*y)**6]) + >>> C = CosetTable(f, []) + >>> C.table = [[1, 1, 2, 3], [0, 0, 4, 5], [4, 4, 3, 0], [5, 5, 0, 2], [2, 2, 5, 1], [3, 3, 1, 4]] + >>> C.p = [0, 1, 2, 3, 4, 5] + >>> define_schreier_generators(C) + >>> rewrite(C, 0, (x*y)**6) + x_4*y_2*x_3*x_1*x_2*y_4*x_5 + + """ + v = C._schreier_free_group.identity + for i in range(len(w)): + x_i = w[i] + v = v*C.P[alpha][C.A_dict[x_i]] + alpha = C.table[alpha][C.A_dict[x_i]] + return v + +# Pg 350, section 2.5.2 from [2] +def elimination_technique_2(C): + """ + This technique eliminates one generator at a time. Heuristically this + seems superior in that we may select for elimination the generator with + shortest equivalent string at each stage. + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_r, \ + reidemeister_relators, define_schreier_generators, elimination_technique_2 + >>> F, x, y = free_group("x, y") + >>> f = FpGroup(F, [x**3, y**5, (x*y)**2]); H = [x*y, x**-1*y**-1*x*y*x] + >>> C = coset_enumeration_r(f, H) + >>> C.compress(); C.standardize() + >>> define_schreier_generators(C) + >>> reidemeister_relators(C) + >>> elimination_technique_2(C) + ([y_1, y_2], [y_2**-3, y_2*y_1*y_2*y_1*y_2*y_1, y_1**2]) + + """ + rels = C._reidemeister_relators + rels.sort(reverse=True) + gens = C._schreier_generators + for i in range(len(gens) - 1, -1, -1): + rel = rels[i] + for j in range(len(gens) - 1, -1, -1): + gen = gens[j] + if rel.generator_count(gen) == 1: + k = rel.exponent_sum(gen) + gen_index = rel.index(gen**k) + bk = rel.subword(gen_index + 1, len(rel)) + fw = rel.subword(0, gen_index) + rep_by = (bk*fw)**(-1*k) + del rels[i] + del gens[j] + rels = [rel.eliminate_word(gen, rep_by) for rel in rels] + break + C._reidemeister_relators = rels + C._schreier_generators = gens + return C._schreier_generators, C._reidemeister_relators + +def reidemeister_presentation(fp_grp, H, C=None, homomorphism=False): + """ + Parameters + ========== + + fp_group: A finitely presented group, an instance of FpGroup + H: A subgroup whose presentation is to be found, given as a list + of words in generators of `fp_grp` + homomorphism: When set to True, return a homomorphism from the subgroup + to the parent group + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> from sympy.combinatorics.fp_groups import FpGroup, reidemeister_presentation + >>> F, x, y = free_group("x, y") + + Example 5.6 Pg. 177 from [1] + >>> f = FpGroup(F, [x**3, y**5, (x*y)**2]) + >>> H = [x*y, x**-1*y**-1*x*y*x] + >>> reidemeister_presentation(f, H) + ((y_1, y_2), (y_1**2, y_2**3, y_2*y_1*y_2*y_1*y_2*y_1)) + + Example 5.8 Pg. 183 from [1] + >>> f = FpGroup(F, [x**3, y**3, (x*y)**3]) + >>> H = [x*y, x*y**-1] + >>> reidemeister_presentation(f, H) + ((x_0, y_0), (x_0**3, y_0**3, x_0*y_0*x_0*y_0*x_0*y_0)) + + Exercises Q2. Pg 187 from [1] + >>> f = FpGroup(F, [x**2*y**2, y**-1*x*y*x**-3]) + >>> H = [x] + >>> reidemeister_presentation(f, H) + ((x_0,), (x_0**4,)) + + Example 5.9 Pg. 183 from [1] + >>> f = FpGroup(F, [x**3*y**-3, (x*y)**3, (x*y**-1)**2]) + >>> H = [x] + >>> reidemeister_presentation(f, H) + ((x_0,), (x_0**6,)) + + """ + if not C: + C = coset_enumeration_r(fp_grp, H) + C.compress(); C.standardize() + define_schreier_generators(C, homomorphism=homomorphism) + reidemeister_relators(C) + gens, rels = C._schreier_generators, C._reidemeister_relators + gens, rels = simplify_presentation(gens, rels, change_gens=True) + + C.schreier_generators = tuple(gens) + C.reidemeister_relators = tuple(rels) + + if homomorphism: + _gens = [C._schreier_gen_elem[str(gen)] for gen in gens] + return C.schreier_generators, C.reidemeister_relators, _gens + + return C.schreier_generators, C.reidemeister_relators + + +FpGroupElement = FreeGroupElement diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/free_groups.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/free_groups.py new file mode 100644 index 0000000000000000000000000000000000000000..2ec85f4fac73fba95d4644a37ecb27140e45a4c5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/free_groups.py @@ -0,0 +1,1360 @@ +from __future__ import annotations + +from sympy.core import S +from sympy.core.expr import Expr +from sympy.core.symbol import Symbol, symbols as _symbols +from sympy.core.sympify import CantSympify +from sympy.printing.defaults import DefaultPrinting +from sympy.utilities import public +from sympy.utilities.iterables import flatten, is_sequence +from sympy.utilities.magic import pollute +from sympy.utilities.misc import as_int + + +@public +def free_group(symbols): + """Construct a free group returning ``(FreeGroup, (f_0, f_1, ..., f_(n-1))``. + + Parameters + ========== + + symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty) + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y, z = free_group("x, y, z") + >>> F + + >>> x**2*y**-1 + x**2*y**-1 + >>> type(_) + + + """ + _free_group = FreeGroup(symbols) + return (_free_group,) + tuple(_free_group.generators) + +@public +def xfree_group(symbols): + """Construct a free group returning ``(FreeGroup, (f_0, f_1, ..., f_(n-1)))``. + + Parameters + ========== + + symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty) + + Examples + ======== + + >>> from sympy.combinatorics.free_groups import xfree_group + >>> F, (x, y, z) = xfree_group("x, y, z") + >>> F + + >>> y**2*x**-2*z**-1 + y**2*x**-2*z**-1 + >>> type(_) + + + """ + _free_group = FreeGroup(symbols) + return (_free_group, _free_group.generators) + +@public +def vfree_group(symbols): + """Construct a free group and inject ``f_0, f_1, ..., f_(n-1)`` as symbols + into the global namespace. + + Parameters + ========== + + symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty) + + Examples + ======== + + >>> from sympy.combinatorics.free_groups import vfree_group + >>> vfree_group("x, y, z") + + >>> x**2*y**-2*z # noqa: F821 + x**2*y**-2*z + >>> type(_) + + + """ + _free_group = FreeGroup(symbols) + pollute([sym.name for sym in _free_group.symbols], _free_group.generators) + return _free_group + + +def _parse_symbols(symbols): + if not symbols: + return () + if isinstance(symbols, str): + return _symbols(symbols, seq=True) + elif isinstance(symbols, (Expr, FreeGroupElement)): + return (symbols,) + elif is_sequence(symbols): + if all(isinstance(s, str) for s in symbols): + return _symbols(symbols) + elif all(isinstance(s, Expr) for s in symbols): + return symbols + raise ValueError("The type of `symbols` must be one of the following: " + "a str, Symbol/Expr or a sequence of " + "one of these types") + + +############################################################################## +# FREE GROUP # +############################################################################## + +_free_group_cache: dict[int, FreeGroup] = {} + +class FreeGroup(DefaultPrinting): + """ + Free group with finite or infinite number of generators. Its input API + is that of a str, Symbol/Expr or a sequence of one of + these types (which may be empty) + + See Also + ======== + + sympy.polys.rings.PolyRing + + References + ========== + + .. [1] https://www.gap-system.org/Manuals/doc/ref/chap37.html + + .. [2] https://en.wikipedia.org/wiki/Free_group + + """ + is_associative = True + is_group = True + is_FreeGroup = True + is_PermutationGroup = False + relators: list[Expr] = [] + + def __new__(cls, symbols): + symbols = tuple(_parse_symbols(symbols)) + rank = len(symbols) + _hash = hash((cls.__name__, symbols, rank)) + obj = _free_group_cache.get(_hash) + + if obj is None: + obj = object.__new__(cls) + obj._hash = _hash + obj._rank = rank + # dtype method is used to create new instances of FreeGroupElement + obj.dtype = type("FreeGroupElement", (FreeGroupElement,), {"group": obj}) + obj.symbols = symbols + obj.generators = obj._generators() + obj._gens_set = set(obj.generators) + for symbol, generator in zip(obj.symbols, obj.generators): + if isinstance(symbol, Symbol): + name = symbol.name + if hasattr(obj, name): + setattr(obj, name, generator) + + _free_group_cache[_hash] = obj + + return obj + + def __getnewargs__(self): + """Return a tuple of arguments that must be passed to __new__ in order to support pickling this object.""" + return (self.symbols,) + + def __getstate__(self): + # Don't pickle any fields because they are regenerated within __new__ + return None + + def _generators(group): + """Returns the generators of the FreeGroup. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y, z = free_group("x, y, z") + >>> F.generators + (x, y, z) + + """ + gens = [] + for sym in group.symbols: + elm = ((sym, 1),) + gens.append(group.dtype(elm)) + return tuple(gens) + + def clone(self, symbols=None): + return self.__class__(symbols or self.symbols) + + def __contains__(self, i): + """Return True if ``i`` is contained in FreeGroup.""" + if not isinstance(i, FreeGroupElement): + return False + group = i.group + return self == group + + def __hash__(self): + return self._hash + + def __len__(self): + return self.rank + + def __str__(self): + if self.rank > 30: + str_form = "" % self.rank + else: + str_form = "" + return str_form + + __repr__ = __str__ + + def __getitem__(self, index): + symbols = self.symbols[index] + return self.clone(symbols=symbols) + + def __eq__(self, other): + """No ``FreeGroup`` is equal to any "other" ``FreeGroup``. + """ + return self is other + + def index(self, gen): + """Return the index of the generator `gen` from ``(f_0, ..., f_(n-1))``. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> F.index(y) + 1 + >>> F.index(x) + 0 + + """ + if isinstance(gen, self.dtype): + return self.generators.index(gen) + else: + raise ValueError("expected a generator of Free Group %s, got %s" % (self, gen)) + + def order(self): + """Return the order of the free group. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> F.order() + oo + + >>> free_group("")[0].order() + 1 + + """ + if self.rank == 0: + return S.One + else: + return S.Infinity + + @property + def elements(self): + """ + Return the elements of the free group. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> (z,) = free_group("") + >>> z.elements + {} + + """ + if self.rank == 0: + # A set containing Identity element of `FreeGroup` self is returned + return {self.identity} + else: + raise ValueError("Group contains infinitely many elements" + ", hence cannot be represented") + + @property + def rank(self): + r""" + In group theory, the `rank` of a group `G`, denoted `G.rank`, + can refer to the smallest cardinality of a generating set + for G, that is + + \operatorname{rank}(G)=\min\{ |X|: X\subseteq G, \left\langle X\right\rangle =G\}. + + """ + return self._rank + + @property + def is_abelian(self): + """Returns if the group is Abelian. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, x, y, z = free_group("x y z") + >>> f.is_abelian + False + + """ + return self.rank in (0, 1) + + @property + def identity(self): + """Returns the identity element of free group.""" + return self.dtype() + + def contains(self, g): + """Tests if Free Group element ``g`` belong to self, ``G``. + + In mathematical terms any linear combination of generators + of a Free Group is contained in it. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, x, y, z = free_group("x y z") + >>> f.contains(x**3*y**2) + True + + """ + if not isinstance(g, FreeGroupElement): + return False + elif self != g.group: + return False + else: + return True + + def center(self): + """Returns the center of the free group `self`.""" + return {self.identity} + + +############################################################################ +# FreeGroupElement # +############################################################################ + + +class FreeGroupElement(CantSympify, DefaultPrinting, tuple): + """Used to create elements of FreeGroup. It cannot be used directly to + create a free group element. It is called by the `dtype` method of the + `FreeGroup` class. + + """ + __slots__ = () + is_assoc_word = True + + def new(self, init): + return self.__class__(init) + + _hash = None + + def __hash__(self): + _hash = self._hash + if _hash is None: + self._hash = _hash = hash((self.group, frozenset(tuple(self)))) + return _hash + + def copy(self): + return self.new(self) + + @property + def is_identity(self): + return not self.array_form + + @property + def array_form(self): + """ + SymPy provides two different internal kinds of representation + of associative words. The first one is called the `array_form` + which is a tuple containing `tuples` as its elements, where the + size of each tuple is two. At the first position the tuple + contains the `symbol-generator`, while at the second position + of tuple contains the exponent of that generator at the position. + Since elements (i.e. words) do not commute, the indexing of tuple + makes that property to stay. + + The structure in ``array_form`` of ``FreeGroupElement`` is of form: + + ``( ( symbol_of_gen, exponent ), ( , ), ... ( , ) )`` + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, x, y, z = free_group("x y z") + >>> (x*z).array_form + ((x, 1), (z, 1)) + >>> (x**2*z*y*x**2).array_form + ((x, 2), (z, 1), (y, 1), (x, 2)) + + See Also + ======== + + letter_repr + + """ + return tuple(self) + + @property + def letter_form(self): + """ + The letter representation of a ``FreeGroupElement`` is a tuple + of generator symbols, with each entry corresponding to a group + generator. Inverses of the generators are represented by + negative generator symbols. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, a, b, c, d = free_group("a b c d") + >>> (a**3).letter_form + (a, a, a) + >>> (a**2*d**-2*a*b**-4).letter_form + (a, a, -d, -d, a, -b, -b, -b, -b) + >>> (a**-2*b**3*d).letter_form + (-a, -a, b, b, b, d) + + See Also + ======== + + array_form + + """ + return tuple(flatten([(i,)*j if j > 0 else (-i,)*(-j) + for i, j in self.array_form])) + + def __getitem__(self, i): + group = self.group + r = self.letter_form[i] + if r.is_Symbol: + return group.dtype(((r, 1),)) + else: + return group.dtype(((-r, -1),)) + + def index(self, gen): + if len(gen) != 1: + raise ValueError() + return (self.letter_form).index(gen.letter_form[0]) + + @property + def letter_form_elm(self): + """ + """ + group = self.group + r = self.letter_form + return [group.dtype(((elm,1),)) if elm.is_Symbol \ + else group.dtype(((-elm,-1),)) for elm in r] + + @property + def ext_rep(self): + """This is called the External Representation of ``FreeGroupElement`` + """ + return tuple(flatten(self.array_form)) + + def __contains__(self, gen): + return gen.array_form[0][0] in tuple([r[0] for r in self.array_form]) + + def __str__(self): + if self.is_identity: + return "" + + str_form = "" + array_form = self.array_form + for i in range(len(array_form)): + if i == len(array_form) - 1: + if array_form[i][1] == 1: + str_form += str(array_form[i][0]) + else: + str_form += str(array_form[i][0]) + \ + "**" + str(array_form[i][1]) + else: + if array_form[i][1] == 1: + str_form += str(array_form[i][0]) + "*" + else: + str_form += str(array_form[i][0]) + \ + "**" + str(array_form[i][1]) + "*" + return str_form + + __repr__ = __str__ + + def __pow__(self, n): + n = as_int(n) + result = self.group.identity + if n == 0: + return result + if n < 0: + n = -n + x = self.inverse() + else: + x = self + while True: + if n % 2: + result *= x + n >>= 1 + if not n: + break + x *= x + return result + + def __mul__(self, other): + """Returns the product of elements belonging to the same ``FreeGroup``. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, x, y, z = free_group("x y z") + >>> x*y**2*y**-4 + x*y**-2 + >>> z*y**-2 + z*y**-2 + >>> x**2*y*y**-1*x**-2 + + + """ + group = self.group + if not isinstance(other, group.dtype): + raise TypeError("only FreeGroup elements of same FreeGroup can " + "be multiplied") + if self.is_identity: + return other + if other.is_identity: + return self + r = list(self.array_form + other.array_form) + zero_mul_simp(r, len(self.array_form) - 1) + return group.dtype(tuple(r)) + + def __truediv__(self, other): + group = self.group + if not isinstance(other, group.dtype): + raise TypeError("only FreeGroup elements of same FreeGroup can " + "be multiplied") + return self*(other.inverse()) + + def __rtruediv__(self, other): + group = self.group + if not isinstance(other, group.dtype): + raise TypeError("only FreeGroup elements of same FreeGroup can " + "be multiplied") + return other*(self.inverse()) + + def __add__(self, other): + return NotImplemented + + def inverse(self): + """ + Returns the inverse of a ``FreeGroupElement`` element + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, x, y, z = free_group("x y z") + >>> x.inverse() + x**-1 + >>> (x*y).inverse() + y**-1*x**-1 + + """ + group = self.group + r = tuple([(i, -j) for i, j in self.array_form[::-1]]) + return group.dtype(r) + + def order(self): + """Find the order of a ``FreeGroupElement``. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, x, y = free_group("x y") + >>> (x**2*y*y**-1*x**-2).order() + 1 + + """ + if self.is_identity: + return S.One + else: + return S.Infinity + + def commutator(self, other): + """ + Return the commutator of `self` and `x`: ``~x*~self*x*self`` + + """ + group = self.group + if not isinstance(other, group.dtype): + raise ValueError("commutator of only FreeGroupElement of the same " + "FreeGroup exists") + else: + return self.inverse()*other.inverse()*self*other + + def eliminate_words(self, words, _all=False, inverse=True): + ''' + Replace each subword from the dictionary `words` by words[subword]. + If words is a list, replace the words by the identity. + + ''' + again = True + new = self + if isinstance(words, dict): + while again: + again = False + for sub in words: + prev = new + new = new.eliminate_word(sub, words[sub], _all=_all, inverse=inverse) + if new != prev: + again = True + else: + while again: + again = False + for sub in words: + prev = new + new = new.eliminate_word(sub, _all=_all, inverse=inverse) + if new != prev: + again = True + return new + + def eliminate_word(self, gen, by=None, _all=False, inverse=True): + """ + For an associative word `self`, a subword `gen`, and an associative + word `by` (identity by default), return the associative word obtained by + replacing each occurrence of `gen` in `self` by `by`. If `_all = True`, + the occurrences of `gen` that may appear after the first substitution will + also be replaced and so on until no occurrences are found. This might not + always terminate (e.g. `(x).eliminate_word(x, x**2, _all=True)`). + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, x, y = free_group("x y") + >>> w = x**5*y*x**2*y**-4*x + >>> w.eliminate_word( x, x**2 ) + x**10*y*x**4*y**-4*x**2 + >>> w.eliminate_word( x, y**-1 ) + y**-11 + >>> w.eliminate_word(x**5) + y*x**2*y**-4*x + >>> w.eliminate_word(x*y, y) + x**4*y*x**2*y**-4*x + + See Also + ======== + substituted_word + + """ + if by is None: + by = self.group.identity + if self.is_independent(gen) or gen == by: + return self + if gen == self: + return by + if gen**-1 == by: + _all = False + word = self + l = len(gen) + + try: + i = word.subword_index(gen) + k = 1 + except ValueError: + if not inverse: + return word + try: + i = word.subword_index(gen**-1) + k = -1 + except ValueError: + return word + + word = word.subword(0, i)*by**k*word.subword(i+l, len(word)).eliminate_word(gen, by) + + if _all: + return word.eliminate_word(gen, by, _all=True, inverse=inverse) + else: + return word + + def __len__(self): + """ + For an associative word `self`, returns the number of letters in it. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, a, b = free_group("a b") + >>> w = a**5*b*a**2*b**-4*a + >>> len(w) + 13 + >>> len(a**17) + 17 + >>> len(w**0) + 0 + + """ + return sum(abs(j) for (i, j) in self) + + def __eq__(self, other): + """ + Two associative words are equal if they are words over the + same alphabet and if they are sequences of the same letters. + This is equivalent to saying that the external representations + of the words are equal. + There is no "universal" empty word, every alphabet has its own + empty word. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, swapnil0, swapnil1 = free_group("swapnil0 swapnil1") + >>> f + + >>> g, swap0, swap1 = free_group("swap0 swap1") + >>> g + + + >>> swapnil0 == swapnil1 + False + >>> swapnil0*swapnil1 == swapnil1/swapnil1*swapnil0*swapnil1 + True + >>> swapnil0*swapnil1 == swapnil1*swapnil0 + False + >>> swapnil1**0 == swap0**0 + False + + """ + group = self.group + if not isinstance(other, group.dtype): + return False + return tuple.__eq__(self, other) + + def __lt__(self, other): + """ + The ordering of associative words is defined by length and + lexicography (this ordering is called short-lex ordering), that + is, shorter words are smaller than longer words, and words of the + same length are compared w.r.t. the lexicographical ordering induced + by the ordering of generators. Generators are sorted according + to the order in which they were created. If the generators are + invertible then each generator `g` is larger than its inverse `g^{-1}`, + and `g^{-1}` is larger than every generator that is smaller than `g`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, a, b = free_group("a b") + >>> b < a + False + >>> a < a.inverse() + False + + """ + group = self.group + if not isinstance(other, group.dtype): + raise TypeError("only FreeGroup elements of same FreeGroup can " + "be compared") + l = len(self) + m = len(other) + # implement lenlex order + if l < m: + return True + elif l > m: + return False + for i in range(l): + a = self[i].array_form[0] + b = other[i].array_form[0] + p = group.symbols.index(a[0]) + q = group.symbols.index(b[0]) + if p < q: + return True + elif p > q: + return False + elif a[1] < b[1]: + return True + elif a[1] > b[1]: + return False + return False + + def __le__(self, other): + return (self == other or self < other) + + def __gt__(self, other): + """ + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, x, y, z = free_group("x y z") + >>> y**2 > x**2 + True + >>> y*z > z*y + False + >>> x > x.inverse() + True + + """ + group = self.group + if not isinstance(other, group.dtype): + raise TypeError("only FreeGroup elements of same FreeGroup can " + "be compared") + return not self <= other + + def __ge__(self, other): + return not self < other + + def exponent_sum(self, gen): + """ + For an associative word `self` and a generator or inverse of generator + `gen`, ``exponent_sum`` returns the number of times `gen` appears in + `self` minus the number of times its inverse appears in `self`. If + neither `gen` nor its inverse occur in `self` then 0 is returned. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> w = x**2*y**3 + >>> w.exponent_sum(x) + 2 + >>> w.exponent_sum(x**-1) + -2 + >>> w = x**2*y**4*x**-3 + >>> w.exponent_sum(x) + -1 + + See Also + ======== + + generator_count + + """ + if len(gen) != 1: + raise ValueError("gen must be a generator or inverse of a generator") + s = gen.array_form[0] + return s[1]*sum(i[1] for i in self.array_form if i[0] == s[0]) + + def generator_count(self, gen): + """ + For an associative word `self` and a generator `gen`, + ``generator_count`` returns the multiplicity of generator + `gen` in `self`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> w = x**2*y**3 + >>> w.generator_count(x) + 2 + >>> w = x**2*y**4*x**-3 + >>> w.generator_count(x) + 5 + + See Also + ======== + + exponent_sum + + """ + if len(gen) != 1 or gen.array_form[0][1] < 0: + raise ValueError("gen must be a generator") + s = gen.array_form[0] + return s[1]*sum(abs(i[1]) for i in self.array_form if i[0] == s[0]) + + def subword(self, from_i, to_j, strict=True): + """ + For an associative word `self` and two positive integers `from_i` and + `to_j`, `subword` returns the subword of `self` that begins at position + `from_i` and ends at `to_j - 1`, indexing is done with origin 0. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, a, b = free_group("a b") + >>> w = a**5*b*a**2*b**-4*a + >>> w.subword(2, 6) + a**3*b + + """ + group = self.group + if not strict: + from_i = max(from_i, 0) + to_j = min(len(self), to_j) + if from_i < 0 or to_j > len(self): + raise ValueError("`from_i`, `to_j` must be positive and no greater than " + "the length of associative word") + if to_j <= from_i: + return group.identity + else: + letter_form = self.letter_form[from_i: to_j] + array_form = letter_form_to_array_form(letter_form, group) + return group.dtype(array_form) + + def subword_index(self, word, start = 0): + ''' + Find the index of `word` in `self`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, a, b = free_group("a b") + >>> w = a**2*b*a*b**3 + >>> w.subword_index(a*b*a*b) + 1 + + ''' + l = len(word) + self_lf = self.letter_form + word_lf = word.letter_form + index = None + for i in range(start,len(self_lf)-l+1): + if self_lf[i:i+l] == word_lf: + index = i + break + if index is not None: + return index + else: + raise ValueError("The given word is not a subword of self") + + def is_dependent(self, word): + """ + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> (x**4*y**-3).is_dependent(x**4*y**-2) + True + >>> (x**2*y**-1).is_dependent(x*y) + False + >>> (x*y**2*x*y**2).is_dependent(x*y**2) + True + >>> (x**12).is_dependent(x**-4) + True + + See Also + ======== + + is_independent + + """ + try: + return self.subword_index(word) is not None + except ValueError: + pass + try: + return self.subword_index(word**-1) is not None + except ValueError: + return False + + def is_independent(self, word): + """ + + See Also + ======== + + is_dependent + + """ + return not self.is_dependent(word) + + def contains_generators(self): + """ + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y, z = free_group("x, y, z") + >>> (x**2*y**-1).contains_generators() + {x, y} + >>> (x**3*z).contains_generators() + {x, z} + + """ + group = self.group + gens = {group.dtype(((syllable[0], 1),)) for syllable in self.array_form} + return gens + + def cyclic_subword(self, from_i, to_j): + group = self.group + l = len(self) + letter_form = self.letter_form + period1 = int(from_i/l) + if from_i >= l: + from_i -= l*period1 + to_j -= l*period1 + diff = to_j - from_i + word = letter_form[from_i: to_j] + period2 = int(to_j/l) - 1 + word += letter_form*period2 + letter_form[:diff-l+from_i-l*period2] + word = letter_form_to_array_form(word, group) + return group.dtype(word) + + def cyclic_conjugates(self): + """Returns a words which are cyclic to the word `self`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> w = x*y*x*y*x + >>> w.cyclic_conjugates() + {x*y*x**2*y, x**2*y*x*y, y*x*y*x**2, y*x**2*y*x, x*y*x*y*x} + >>> s = x*y*x**2*y*x + >>> s.cyclic_conjugates() + {x**2*y*x**2*y, y*x**2*y*x**2, x*y*x**2*y*x} + + References + ========== + + .. [1] https://planetmath.org/cyclicpermutation + + """ + return {self.cyclic_subword(i, i+len(self)) for i in range(len(self))} + + def is_cyclic_conjugate(self, w): + """ + Checks whether words ``self``, ``w`` are cyclic conjugates. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> w1 = x**2*y**5 + >>> w2 = x*y**5*x + >>> w1.is_cyclic_conjugate(w2) + True + >>> w3 = x**-1*y**5*x**-1 + >>> w3.is_cyclic_conjugate(w2) + False + + """ + l1 = len(self) + l2 = len(w) + if l1 != l2: + return False + w1 = self.identity_cyclic_reduction() + w2 = w.identity_cyclic_reduction() + letter1 = w1.letter_form + letter2 = w2.letter_form + str1 = ' '.join(map(str, letter1)) + str2 = ' '.join(map(str, letter2)) + if len(str1) != len(str2): + return False + + return str1 in str2 + ' ' + str2 + + def number_syllables(self): + """Returns the number of syllables of the associative word `self`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, swapnil0, swapnil1 = free_group("swapnil0 swapnil1") + >>> (swapnil1**3*swapnil0*swapnil1**-1).number_syllables() + 3 + + """ + return len(self.array_form) + + def exponent_syllable(self, i): + """ + Returns the exponent of the `i`-th syllable of the associative word + `self`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, a, b = free_group("a b") + >>> w = a**5*b*a**2*b**-4*a + >>> w.exponent_syllable( 2 ) + 2 + + """ + return self.array_form[i][1] + + def generator_syllable(self, i): + """ + Returns the symbol of the generator that is involved in the + i-th syllable of the associative word `self`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, a, b = free_group("a b") + >>> w = a**5*b*a**2*b**-4*a + >>> w.generator_syllable( 3 ) + b + + """ + return self.array_form[i][0] + + def sub_syllables(self, from_i, to_j): + """ + `sub_syllables` returns the subword of the associative word `self` that + consists of syllables from positions `from_to` to `to_j`, where + `from_to` and `to_j` must be positive integers and indexing is done + with origin 0. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> f, a, b = free_group("a, b") + >>> w = a**5*b*a**2*b**-4*a + >>> w.sub_syllables(1, 2) + b + >>> w.sub_syllables(3, 3) + + + """ + if not isinstance(from_i, int) or not isinstance(to_j, int): + raise ValueError("both arguments should be integers") + group = self.group + if to_j <= from_i: + return group.identity + else: + r = tuple(self.array_form[from_i: to_j]) + return group.dtype(r) + + def substituted_word(self, from_i, to_j, by): + """ + Returns the associative word obtained by replacing the subword of + `self` that begins at position `from_i` and ends at position `to_j - 1` + by the associative word `by`. `from_i` and `to_j` must be positive + integers, indexing is done with origin 0. In other words, + `w.substituted_word(w, from_i, to_j, by)` is the product of the three + words: `w.subword(0, from_i)`, `by`, and + `w.subword(to_j len(w))`. + + See Also + ======== + + eliminate_word + + """ + lw = len(self) + if from_i >= to_j or from_i > lw or to_j > lw: + raise ValueError("values should be within bounds") + + # otherwise there are four possibilities + + # first if from=1 and to=lw then + if from_i == 0 and to_j == lw: + return by + elif from_i == 0: # second if from_i=1 (and to_j < lw) then + return by*self.subword(to_j, lw) + elif to_j == lw: # third if to_j=1 (and from_i > 1) then + return self.subword(0, from_i)*by + else: # finally + return self.subword(0, from_i)*by*self.subword(to_j, lw) + + def is_cyclically_reduced(self): + r"""Returns whether the word is cyclically reduced or not. + A word is cyclically reduced if by forming the cycle of the + word, the word is not reduced, i.e a word w = `a_1 ... a_n` + is called cyclically reduced if `a_1 \ne a_n^{-1}`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> (x**2*y**-1*x**-1).is_cyclically_reduced() + False + >>> (y*x**2*y**2).is_cyclically_reduced() + True + + """ + if not self: + return True + return self[0] != self[-1]**-1 + + def identity_cyclic_reduction(self): + """Return a unique cyclically reduced version of the word. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> (x**2*y**2*x**-1).identity_cyclic_reduction() + x*y**2 + >>> (x**-3*y**-1*x**5).identity_cyclic_reduction() + x**2*y**-1 + + References + ========== + + .. [1] https://planetmath.org/cyclicallyreduced + + """ + word = self.copy() + group = self.group + while not word.is_cyclically_reduced(): + exp1 = word.exponent_syllable(0) + exp2 = word.exponent_syllable(-1) + r = exp1 + exp2 + if r == 0: + rep = word.array_form[1: word.number_syllables() - 1] + else: + rep = ((word.generator_syllable(0), exp1 + exp2),) + \ + word.array_form[1: word.number_syllables() - 1] + word = group.dtype(rep) + return word + + def cyclic_reduction(self, removed=False): + """Return a cyclically reduced version of the word. Unlike + `identity_cyclic_reduction`, this will not cyclically permute + the reduced word - just remove the "unreduced" bits on either + side of it. Compare the examples with those of + `identity_cyclic_reduction`. + + When `removed` is `True`, return a tuple `(word, r)` where + self `r` is such that before the reduction the word was either + `r*word*r**-1`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> (x**2*y**2*x**-1).cyclic_reduction() + x*y**2 + >>> (x**-3*y**-1*x**5).cyclic_reduction() + y**-1*x**2 + >>> (x**-3*y**-1*x**5).cyclic_reduction(removed=True) + (y**-1*x**2, x**-3) + + """ + word = self.copy() + g = self.group.identity + while not word.is_cyclically_reduced(): + exp1 = abs(word.exponent_syllable(0)) + exp2 = abs(word.exponent_syllable(-1)) + exp = min(exp1, exp2) + start = word[0]**abs(exp) + end = word[-1]**abs(exp) + word = start**-1*word*end**-1 + g = g*start + if removed: + return word, g + return word + + def power_of(self, other): + ''' + Check if `self == other**n` for some integer n. + + Examples + ======== + + >>> from sympy.combinatorics import free_group + >>> F, x, y = free_group("x, y") + >>> ((x*y)**2).power_of(x*y) + True + >>> (x**-3*y**-2*x**3).power_of(x**-3*y*x**3) + True + + ''' + if self.is_identity: + return True + + l = len(other) + if l == 1: + # self has to be a power of one generator + gens = self.contains_generators() + s = other in gens or other**-1 in gens + return len(gens) == 1 and s + + # if self is not cyclically reduced and it is a power of other, + # other isn't cyclically reduced and the parts removed during + # their reduction must be equal + reduced, r1 = self.cyclic_reduction(removed=True) + if not r1.is_identity: + other, r2 = other.cyclic_reduction(removed=True) + if r1 == r2: + return reduced.power_of(other) + return False + + if len(self) < l or len(self) % l: + return False + + prefix = self.subword(0, l) + if prefix == other or prefix**-1 == other: + rest = self.subword(l, len(self)) + return rest.power_of(other) + return False + + +def letter_form_to_array_form(array_form, group): + """ + This method converts a list given with possible repetitions of elements in + it. It returns a new list such that repetitions of consecutive elements is + removed and replace with a tuple element of size two such that the first + index contains `value` and the second index contains the number of + consecutive repetitions of `value`. + + """ + a = list(array_form[:]) + new_array = [] + n = 1 + symbols = group.symbols + for i in range(len(a)): + if i == len(a) - 1: + if a[i] == a[i - 1]: + if (-a[i]) in symbols: + new_array.append((-a[i], -n)) + else: + new_array.append((a[i], n)) + else: + if (-a[i]) in symbols: + new_array.append((-a[i], -1)) + else: + new_array.append((a[i], 1)) + return new_array + elif a[i] == a[i + 1]: + n += 1 + else: + if (-a[i]) in symbols: + new_array.append((-a[i], -n)) + else: + new_array.append((a[i], n)) + n = 1 + + +def zero_mul_simp(l, index): + """Used to combine two reduced words.""" + while index >=0 and index < len(l) - 1 and l[index][0] == l[index + 1][0]: + exp = l[index][1] + l[index + 1][1] + base = l[index][0] + l[index] = (base, exp) + del l[index + 1] + if l[index][1] == 0: + del l[index] + index -= 1 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/galois.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/galois.py new file mode 100644 index 0000000000000000000000000000000000000000..f8ff89886283903e116bf40e1be6f6131386e802 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/galois.py @@ -0,0 +1,611 @@ +r""" +Construct transitive subgroups of symmetric groups, useful in Galois theory. + +Besides constructing instances of the :py:class:`~.PermutationGroup` class to +represent the transitive subgroups of $S_n$ for small $n$, this module provides +*names* for these groups. + +In some applications, it may be preferable to know the name of a group, +rather than receive an instance of the :py:class:`~.PermutationGroup` +class, and then have to do extra work to determine which group it is, by +checking various properties. + +Names are instances of ``Enum`` classes defined in this module. With a name in +hand, the name's ``get_perm_group`` method can then be used to retrieve a +:py:class:`~.PermutationGroup`. + +The names used for groups in this module are taken from [1]. + +References +========== + +.. [1] Cohen, H. *A Course in Computational Algebraic Number Theory*. + +""" + +from collections import defaultdict +from enum import Enum +import itertools + +from sympy.combinatorics.named_groups import ( + SymmetricGroup, AlternatingGroup, CyclicGroup, DihedralGroup, + set_symmetric_group_properties, set_alternating_group_properties, +) +from sympy.combinatorics.perm_groups import PermutationGroup +from sympy.combinatorics.permutations import Permutation + + +class S1TransitiveSubgroups(Enum): + """ + Names for the transitive subgroups of S1. + """ + S1 = "S1" + + def get_perm_group(self): + return SymmetricGroup(1) + + +class S2TransitiveSubgroups(Enum): + """ + Names for the transitive subgroups of S2. + """ + S2 = "S2" + + def get_perm_group(self): + return SymmetricGroup(2) + + +class S3TransitiveSubgroups(Enum): + """ + Names for the transitive subgroups of S3. + """ + A3 = "A3" + S3 = "S3" + + def get_perm_group(self): + if self == S3TransitiveSubgroups.A3: + return AlternatingGroup(3) + elif self == S3TransitiveSubgroups.S3: + return SymmetricGroup(3) + + +class S4TransitiveSubgroups(Enum): + """ + Names for the transitive subgroups of S4. + """ + C4 = "C4" + V = "V" + D4 = "D4" + A4 = "A4" + S4 = "S4" + + def get_perm_group(self): + if self == S4TransitiveSubgroups.C4: + return CyclicGroup(4) + elif self == S4TransitiveSubgroups.V: + return four_group() + elif self == S4TransitiveSubgroups.D4: + return DihedralGroup(4) + elif self == S4TransitiveSubgroups.A4: + return AlternatingGroup(4) + elif self == S4TransitiveSubgroups.S4: + return SymmetricGroup(4) + + +class S5TransitiveSubgroups(Enum): + """ + Names for the transitive subgroups of S5. + """ + C5 = "C5" + D5 = "D5" + M20 = "M20" + A5 = "A5" + S5 = "S5" + + def get_perm_group(self): + if self == S5TransitiveSubgroups.C5: + return CyclicGroup(5) + elif self == S5TransitiveSubgroups.D5: + return DihedralGroup(5) + elif self == S5TransitiveSubgroups.M20: + return M20() + elif self == S5TransitiveSubgroups.A5: + return AlternatingGroup(5) + elif self == S5TransitiveSubgroups.S5: + return SymmetricGroup(5) + + +class S6TransitiveSubgroups(Enum): + """ + Names for the transitive subgroups of S6. + """ + C6 = "C6" + S3 = "S3" + D6 = "D6" + A4 = "A4" + G18 = "G18" + A4xC2 = "A4 x C2" + S4m = "S4-" + S4p = "S4+" + G36m = "G36-" + G36p = "G36+" + S4xC2 = "S4 x C2" + PSL2F5 = "PSL2(F5)" + G72 = "G72" + PGL2F5 = "PGL2(F5)" + A6 = "A6" + S6 = "S6" + + def get_perm_group(self): + if self == S6TransitiveSubgroups.C6: + return CyclicGroup(6) + elif self == S6TransitiveSubgroups.S3: + return S3_in_S6() + elif self == S6TransitiveSubgroups.D6: + return DihedralGroup(6) + elif self == S6TransitiveSubgroups.A4: + return A4_in_S6() + elif self == S6TransitiveSubgroups.G18: + return G18() + elif self == S6TransitiveSubgroups.A4xC2: + return A4xC2() + elif self == S6TransitiveSubgroups.S4m: + return S4m() + elif self == S6TransitiveSubgroups.S4p: + return S4p() + elif self == S6TransitiveSubgroups.G36m: + return G36m() + elif self == S6TransitiveSubgroups.G36p: + return G36p() + elif self == S6TransitiveSubgroups.S4xC2: + return S4xC2() + elif self == S6TransitiveSubgroups.PSL2F5: + return PSL2F5() + elif self == S6TransitiveSubgroups.G72: + return G72() + elif self == S6TransitiveSubgroups.PGL2F5: + return PGL2F5() + elif self == S6TransitiveSubgroups.A6: + return AlternatingGroup(6) + elif self == S6TransitiveSubgroups.S6: + return SymmetricGroup(6) + + +def four_group(): + """ + Return a representation of the Klein four-group as a transitive subgroup + of S4. + """ + return PermutationGroup( + Permutation(0, 1)(2, 3), + Permutation(0, 2)(1, 3) + ) + + +def M20(): + """ + Return a representation of the metacyclic group M20, a transitive subgroup + of S5 that is one of the possible Galois groups for polys of degree 5. + + Notes + ===== + + See [1], Page 323. + + """ + G = PermutationGroup(Permutation(0, 1, 2, 3, 4), Permutation(1, 2, 4, 3)) + G._degree = 5 + G._order = 20 + G._is_transitive = True + G._is_sym = False + G._is_alt = False + G._is_cyclic = False + G._is_dihedral = False + return G + + +def S3_in_S6(): + """ + Return a representation of S3 as a transitive subgroup of S6. + + Notes + ===== + + The representation is found by viewing the group as the symmetries of a + triangular prism. + + """ + G = PermutationGroup(Permutation(0, 1, 2)(3, 4, 5), Permutation(0, 3)(2, 4)(1, 5)) + set_symmetric_group_properties(G, 3, 6) + return G + + +def A4_in_S6(): + """ + Return a representation of A4 as a transitive subgroup of S6. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + G = PermutationGroup(Permutation(0, 4, 5)(1, 3, 2), Permutation(0, 1, 2)(3, 5, 4)) + set_alternating_group_properties(G, 4, 6) + return G + + +def S4m(): + """ + Return a representation of the S4- transitive subgroup of S6. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + G = PermutationGroup(Permutation(1, 4, 5, 3), Permutation(0, 4)(1, 5)(2, 3)) + set_symmetric_group_properties(G, 4, 6) + return G + + +def S4p(): + """ + Return a representation of the S4+ transitive subgroup of S6. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + G = PermutationGroup(Permutation(0, 2, 4, 1)(3, 5), Permutation(0, 3)(4, 5)) + set_symmetric_group_properties(G, 4, 6) + return G + + +def A4xC2(): + """ + Return a representation of the (A4 x C2) transitive subgroup of S6. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + return PermutationGroup( + Permutation(0, 4, 5)(1, 3, 2), Permutation(0, 1, 2)(3, 5, 4), + Permutation(5)(2, 4)) + + +def S4xC2(): + """ + Return a representation of the (S4 x C2) transitive subgroup of S6. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + return PermutationGroup( + Permutation(1, 4, 5, 3), Permutation(0, 4)(1, 5)(2, 3), + Permutation(1, 4)(3, 5)) + + +def G18(): + """ + Return a representation of the group G18, a transitive subgroup of S6 + isomorphic to the semidirect product of C3^2 with C2. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + return PermutationGroup( + Permutation(5)(0, 1, 2), Permutation(3, 4, 5), + Permutation(0, 4)(1, 5)(2, 3)) + + +def G36m(): + """ + Return a representation of the group G36-, a transitive subgroup of S6 + isomorphic to the semidirect product of C3^2 with C2^2. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + return PermutationGroup( + Permutation(5)(0, 1, 2), Permutation(3, 4, 5), + Permutation(1, 2)(3, 5), Permutation(0, 4)(1, 5)(2, 3)) + + +def G36p(): + """ + Return a representation of the group G36+, a transitive subgroup of S6 + isomorphic to the semidirect product of C3^2 with C4. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + return PermutationGroup( + Permutation(5)(0, 1, 2), Permutation(3, 4, 5), + Permutation(0, 5, 2, 3)(1, 4)) + + +def G72(): + """ + Return a representation of the group G72, a transitive subgroup of S6 + isomorphic to the semidirect product of C3^2 with D4. + + Notes + ===== + + See [1], Page 325. + + """ + return PermutationGroup( + Permutation(5)(0, 1, 2), + Permutation(0, 4, 1, 3)(2, 5), Permutation(0, 3)(1, 4)(2, 5)) + + +def PSL2F5(): + r""" + Return a representation of the group $PSL_2(\mathbb{F}_5)$, as a transitive + subgroup of S6, isomorphic to $A_5$. + + Notes + ===== + + This was computed using :py:func:`~.find_transitive_subgroups_of_S6`. + + """ + G = PermutationGroup( + Permutation(0, 4, 5)(1, 3, 2), Permutation(0, 4, 3, 1, 5)) + set_alternating_group_properties(G, 5, 6) + return G + + +def PGL2F5(): + r""" + Return a representation of the group $PGL_2(\mathbb{F}_5)$, as a transitive + subgroup of S6, isomorphic to $S_5$. + + Notes + ===== + + See [1], Page 325. + + """ + G = PermutationGroup( + Permutation(0, 1, 2, 3, 4), Permutation(0, 5)(1, 2)(3, 4)) + set_symmetric_group_properties(G, 5, 6) + return G + + +def find_transitive_subgroups_of_S6(*targets, print_report=False): + r""" + Search for certain transitive subgroups of $S_6$. + + The symmetric group $S_6$ has 16 different transitive subgroups, up to + conjugacy. Some are more easily constructed than others. For example, the + dihedral group $D_6$ is immediately found, but it is not at all obvious how + to realize $S_4$ or $S_5$ *transitively* within $S_6$. + + In some cases there are well-known constructions that can be used. For + example, $S_5$ is isomorphic to $PGL_2(\mathbb{F}_5)$, which acts in a + natural way on the projective line $P^1(\mathbb{F}_5)$, a set of order 6. + + In absence of such special constructions however, we can simply search for + generators. For example, transitive instances of $A_4$ and $S_4$ can be + found within $S_6$ in this way. + + Once we are engaged in such searches, it may then be easier (if less + elegant) to find even those groups like $S_5$ that do have special + constructions, by mere search. + + This function locates generators for transitive instances in $S_6$ of the + following subgroups: + + * $A_4$ + * $S_4^-$ ($S_4$ not contained within $A_6$) + * $S_4^+$ ($S_4$ contained within $A_6$) + * $A_4 \times C_2$ + * $S_4 \times C_2$ + * $G_{18} = C_3^2 \rtimes C_2$ + * $G_{36}^- = C_3^2 \rtimes C_2^2$ + * $G_{36}^+ = C_3^2 \rtimes C_4$ + * $G_{72} = C_3^2 \rtimes D_4$ + * $A_5$ + * $S_5$ + + Note: Each of these groups also has a dedicated function in this module + that returns the group immediately, using generators that were found by + this search procedure. + + The search procedure serves as a record of how these generators were + found. Also, due to randomness in the generation of the elements of + permutation groups, it can be called again, in order to (probably) get + different generators for the same groups. + + Parameters + ========== + + targets : list of :py:class:`~.S6TransitiveSubgroups` values + The groups you want to find. + + print_report : bool (default False) + If True, print to stdout the generators found for each group. + + Returns + ======= + + dict + mapping each name in *targets* to the :py:class:`~.PermutationGroup` + that was found + + References + ========== + + .. [2] https://en.wikipedia.org/wiki/Projective_linear_group#Exceptional_isomorphisms + .. [3] https://en.wikipedia.org/wiki/Automorphisms_of_the_symmetric_and_alternating_groups#PGL%282,5%29 + + """ + def elts_by_order(G): + """Sort the elements of a group by their order. """ + elts = defaultdict(list) + for g in G.elements: + elts[g.order()].append(g) + return elts + + def order_profile(G, name=None): + """Determine how many elements a group has, of each order. """ + elts = elts_by_order(G) + profile = {o:len(e) for o, e in elts.items()} + if name: + print(f'{name}: ' + ' '.join(f'{len(profile[r])}@{r}' for r in sorted(profile.keys()))) + return profile + + S6 = SymmetricGroup(6) + A6 = AlternatingGroup(6) + S6_by_order = elts_by_order(S6) + + def search(existing_gens, needed_gen_orders, order, alt=None, profile=None, anti_profile=None): + """ + Find a transitive subgroup of S6. + + Parameters + ========== + + existing_gens : list of Permutation + Optionally empty list of generators that must be in the group. + + needed_gen_orders : list of positive int + Nonempty list of the orders of the additional generators that are + to be found. + + order: int + The order of the group being sought. + + alt: bool, None + If True, require the group to be contained in A6. + If False, require the group not to be contained in A6. + + profile : dict + If given, the group's order profile must equal this. + + anti_profile : dict + If given, the group's order profile must *not* equal this. + + """ + for gens in itertools.product(*[S6_by_order[n] for n in needed_gen_orders]): + if len(set(gens)) < len(gens): + continue + G = PermutationGroup(existing_gens + list(gens)) + if G.order() == order and G.is_transitive(): + if alt is not None and G.is_subgroup(A6) != alt: + continue + if profile and order_profile(G) != profile: + continue + if anti_profile and order_profile(G) == anti_profile: + continue + return G + + def match_known_group(G, alt=None): + needed = [g.order() for g in G.generators] + return search([], needed, G.order(), alt=alt, profile=order_profile(G)) + + found = {} + + def finish_up(name, G): + found[name] = G + if print_report: + print("=" * 40) + print(f"{name}:") + print(G.generators) + + if S6TransitiveSubgroups.A4 in targets or S6TransitiveSubgroups.A4xC2 in targets: + A4_in_S6 = match_known_group(AlternatingGroup(4)) + finish_up(S6TransitiveSubgroups.A4, A4_in_S6) + + if S6TransitiveSubgroups.S4m in targets or S6TransitiveSubgroups.S4xC2 in targets: + S4m_in_S6 = match_known_group(SymmetricGroup(4), alt=False) + finish_up(S6TransitiveSubgroups.S4m, S4m_in_S6) + + if S6TransitiveSubgroups.S4p in targets: + S4p_in_S6 = match_known_group(SymmetricGroup(4), alt=True) + finish_up(S6TransitiveSubgroups.S4p, S4p_in_S6) + + if S6TransitiveSubgroups.A4xC2 in targets: + A4xC2_in_S6 = search(A4_in_S6.generators, [2], 24, anti_profile=order_profile(SymmetricGroup(4))) + finish_up(S6TransitiveSubgroups.A4xC2, A4xC2_in_S6) + + if S6TransitiveSubgroups.S4xC2 in targets: + S4xC2_in_S6 = search(S4m_in_S6.generators, [2], 48) + finish_up(S6TransitiveSubgroups.S4xC2, S4xC2_in_S6) + + # For the normal factor N = C3^2 in any of the G_n subgroups, we take one + # obvious instance of C3^2 in S6: + N_gens = [Permutation(5)(0, 1, 2), Permutation(5)(3, 4, 5)] + + if S6TransitiveSubgroups.G18 in targets: + G18_in_S6 = search(N_gens, [2], 18) + finish_up(S6TransitiveSubgroups.G18, G18_in_S6) + + if S6TransitiveSubgroups.G36m in targets: + G36m_in_S6 = search(N_gens, [2, 2], 36, alt=False) + finish_up(S6TransitiveSubgroups.G36m, G36m_in_S6) + + if S6TransitiveSubgroups.G36p in targets: + G36p_in_S6 = search(N_gens, [4], 36, alt=True) + finish_up(S6TransitiveSubgroups.G36p, G36p_in_S6) + + if S6TransitiveSubgroups.G72 in targets: + G72_in_S6 = search(N_gens, [4, 2], 72) + finish_up(S6TransitiveSubgroups.G72, G72_in_S6) + + # The PSL2(F5) and PGL2(F5) subgroups are isomorphic to A5 and S5, resp. + + if S6TransitiveSubgroups.PSL2F5 in targets: + PSL2F5_in_S6 = match_known_group(AlternatingGroup(5)) + finish_up(S6TransitiveSubgroups.PSL2F5, PSL2F5_in_S6) + + if S6TransitiveSubgroups.PGL2F5 in targets: + PGL2F5_in_S6 = match_known_group(SymmetricGroup(5)) + finish_up(S6TransitiveSubgroups.PGL2F5, PGL2F5_in_S6) + + # There is little need to "search" for any of the groups C6, S3, D6, A6, + # or S6, since they all have obvious realizations within S6. However, we + # support them here just in case a random representation is desired. + + if S6TransitiveSubgroups.C6 in targets: + C6 = match_known_group(CyclicGroup(6)) + finish_up(S6TransitiveSubgroups.C6, C6) + + if S6TransitiveSubgroups.S3 in targets: + S3 = match_known_group(SymmetricGroup(3)) + finish_up(S6TransitiveSubgroups.S3, S3) + + if S6TransitiveSubgroups.D6 in targets: + D6 = match_known_group(DihedralGroup(6)) + finish_up(S6TransitiveSubgroups.D6, D6) + + if S6TransitiveSubgroups.A6 in targets: + A6 = match_known_group(A6) + finish_up(S6TransitiveSubgroups.A6, A6) + + if S6TransitiveSubgroups.S6 in targets: + S6 = match_known_group(S6) + finish_up(S6TransitiveSubgroups.S6, S6) + + return found diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/generators.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/generators.py new file mode 100644 index 0000000000000000000000000000000000000000..19e274a4c5b4bf0781855db6bc6bf499349fff31 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/generators.py @@ -0,0 +1,301 @@ +from sympy.combinatorics.permutations import Permutation +from sympy.core.symbol import symbols +from sympy.matrices import Matrix +from sympy.utilities.iterables import variations, rotate_left + + +def symmetric(n): + """ + Generates the symmetric group of order n, Sn. + + Examples + ======== + + >>> from sympy.combinatorics.generators import symmetric + >>> list(symmetric(3)) + [(2), (1 2), (2)(0 1), (0 1 2), (0 2 1), (0 2)] + """ + yield from (Permutation(perm) for perm in variations(range(n), n)) + + +def cyclic(n): + """ + Generates the cyclic group of order n, Cn. + + Examples + ======== + + >>> from sympy.combinatorics.generators import cyclic + >>> list(cyclic(5)) + [(4), (0 1 2 3 4), (0 2 4 1 3), + (0 3 1 4 2), (0 4 3 2 1)] + + See Also + ======== + + dihedral + """ + gen = list(range(n)) + for i in range(n): + yield Permutation(gen) + gen = rotate_left(gen, 1) + + +def alternating(n): + """ + Generates the alternating group of order n, An. + + Examples + ======== + + >>> from sympy.combinatorics.generators import alternating + >>> list(alternating(3)) + [(2), (0 1 2), (0 2 1)] + """ + for perm in variations(range(n), n): + p = Permutation(perm) + if p.is_even: + yield p + + +def dihedral(n): + """ + Generates the dihedral group of order 2n, Dn. + + The result is given as a subgroup of Sn, except for the special cases n=1 + (the group S2) and n=2 (the Klein 4-group) where that's not possible + and embeddings in S2 and S4 respectively are given. + + Examples + ======== + + >>> from sympy.combinatorics.generators import dihedral + >>> list(dihedral(3)) + [(2), (0 2), (0 1 2), (1 2), (0 2 1), (2)(0 1)] + + See Also + ======== + + cyclic + """ + if n == 1: + yield Permutation([0, 1]) + yield Permutation([1, 0]) + elif n == 2: + yield Permutation([0, 1, 2, 3]) + yield Permutation([1, 0, 3, 2]) + yield Permutation([2, 3, 0, 1]) + yield Permutation([3, 2, 1, 0]) + else: + gen = list(range(n)) + for i in range(n): + yield Permutation(gen) + yield Permutation(gen[::-1]) + gen = rotate_left(gen, 1) + + +def rubik_cube_generators(): + """Return the permutations of the 3x3 Rubik's cube, see + https://www.gap-system.org/Doc/Examples/rubik.html + """ + a = [ + [(1, 3, 8, 6), (2, 5, 7, 4), (9, 33, 25, 17), (10, 34, 26, 18), + (11, 35, 27, 19)], + [(9, 11, 16, 14), (10, 13, 15, 12), (1, 17, 41, 40), (4, 20, 44, 37), + (6, 22, 46, 35)], + [(17, 19, 24, 22), (18, 21, 23, 20), (6, 25, 43, 16), (7, 28, 42, 13), + (8, 30, 41, 11)], + [(25, 27, 32, 30), (26, 29, 31, 28), (3, 38, 43, 19), (5, 36, 45, 21), + (8, 33, 48, 24)], + [(33, 35, 40, 38), (34, 37, 39, 36), (3, 9, 46, 32), (2, 12, 47, 29), + (1, 14, 48, 27)], + [(41, 43, 48, 46), (42, 45, 47, 44), (14, 22, 30, 38), + (15, 23, 31, 39), (16, 24, 32, 40)] + ] + return [Permutation([[i - 1 for i in xi] for xi in x], size=48) for x in a] + + +def rubik(n): + """Return permutations for an nxn Rubik's cube. + + Permutations returned are for rotation of each of the slice + from the face up to the last face for each of the 3 sides (in this order): + front, right and bottom. Hence, the first n - 1 permutations are for the + slices from the front. + """ + + if n < 2: + raise ValueError('dimension of cube must be > 1') + + # 1-based reference to rows and columns in Matrix + def getr(f, i): + return faces[f].col(n - i) + + def getl(f, i): + return faces[f].col(i - 1) + + def getu(f, i): + return faces[f].row(i - 1) + + def getd(f, i): + return faces[f].row(n - i) + + def setr(f, i, s): + faces[f][:, n - i] = Matrix(n, 1, s) + + def setl(f, i, s): + faces[f][:, i - 1] = Matrix(n, 1, s) + + def setu(f, i, s): + faces[f][i - 1, :] = Matrix(1, n, s) + + def setd(f, i, s): + faces[f][n - i, :] = Matrix(1, n, s) + + # motion of a single face + def cw(F, r=1): + for _ in range(r): + face = faces[F] + rv = [] + for c in range(n): + for r in range(n - 1, -1, -1): + rv.append(face[r, c]) + faces[F] = Matrix(n, n, rv) + + def ccw(F): + cw(F, 3) + + # motion of plane i from the F side; + # fcw(0) moves the F face, fcw(1) moves the plane + # just behind the front face, etc... + def fcw(i, r=1): + for _ in range(r): + if i == 0: + cw(F) + i += 1 + temp = getr(L, i) + setr(L, i, list(getu(D, i))) + setu(D, i, list(reversed(getl(R, i)))) + setl(R, i, list(getd(U, i))) + setd(U, i, list(reversed(temp))) + i -= 1 + + def fccw(i): + fcw(i, 3) + + # motion of the entire cube from the F side + def FCW(r=1): + for _ in range(r): + cw(F) + ccw(B) + cw(U) + t = faces[U] + cw(L) + faces[U] = faces[L] + cw(D) + faces[L] = faces[D] + cw(R) + faces[D] = faces[R] + faces[R] = t + + def FCCW(): + FCW(3) + + # motion of the entire cube from the U side + def UCW(r=1): + for _ in range(r): + cw(U) + ccw(D) + t = faces[F] + faces[F] = faces[R] + faces[R] = faces[B] + faces[B] = faces[L] + faces[L] = t + + def UCCW(): + UCW(3) + + # defining the permutations for the cube + + U, F, R, B, L, D = names = symbols('U, F, R, B, L, D') + + # the faces are represented by nxn matrices + faces = {} + count = 0 + for fi in range(6): + f = [] + for a in range(n**2): + f.append(count) + count += 1 + faces[names[fi]] = Matrix(n, n, f) + + # this will either return the value of the current permutation + # (show != 1) or else append the permutation to the group, g + def perm(show=0): + # add perm to the list of perms + p = [] + for f in names: + p.extend(faces[f]) + if show: + return p + g.append(Permutation(p)) + + g = [] # container for the group's permutations + I = list(range(6*n**2)) # the identity permutation used for checking + + # define permutations corresponding to cw rotations of the planes + # up TO the last plane from that direction; by not including the + # last plane, the orientation of the cube is maintained. + + # F slices + for i in range(n - 1): + fcw(i) + perm() + fccw(i) # restore + assert perm(1) == I + + # R slices + # bring R to front + UCW() + for i in range(n - 1): + fcw(i) + # put it back in place + UCCW() + # record + perm() + # restore + # bring face to front + UCW() + fccw(i) + # restore + UCCW() + assert perm(1) == I + + # D slices + # bring up bottom + FCW() + UCCW() + FCCW() + for i in range(n - 1): + # turn strip + fcw(i) + # put bottom back on the bottom + FCW() + UCW() + FCCW() + # record + perm() + # restore + # bring up bottom + FCW() + UCCW() + FCCW() + # turn strip + fccw(i) + # put bottom back on the bottom + FCW() + UCW() + FCCW() + assert perm(1) == I + + return g diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/graycode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/graycode.py new file mode 100644 index 0000000000000000000000000000000000000000..930fd337862a70e920a985947d74375b27741293 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/graycode.py @@ -0,0 +1,430 @@ +from sympy.core import Basic, Integer + +import random + + +class GrayCode(Basic): + """ + A Gray code is essentially a Hamiltonian walk on + a n-dimensional cube with edge length of one. + The vertices of the cube are represented by vectors + whose values are binary. The Hamilton walk visits + each vertex exactly once. The Gray code for a 3d + cube is ['000','100','110','010','011','111','101', + '001']. + + A Gray code solves the problem of sequentially + generating all possible subsets of n objects in such + a way that each subset is obtained from the previous + one by either deleting or adding a single object. + In the above example, 1 indicates that the object is + present, and 0 indicates that its absent. + + Gray codes have applications in statistics as well when + we want to compute various statistics related to subsets + in an efficient manner. + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> a = GrayCode(3) + >>> list(a.generate_gray()) + ['000', '001', '011', '010', '110', '111', '101', '100'] + >>> a = GrayCode(4) + >>> list(a.generate_gray()) + ['0000', '0001', '0011', '0010', '0110', '0111', '0101', '0100', \ + '1100', '1101', '1111', '1110', '1010', '1011', '1001', '1000'] + + References + ========== + + .. [1] Nijenhuis,A. and Wilf,H.S.(1978). + Combinatorial Algorithms. Academic Press. + .. [2] Knuth, D. (2011). The Art of Computer Programming, Vol 4 + Addison Wesley + + + """ + + _skip = False + _current = 0 + _rank = None + + def __new__(cls, n, *args, **kw_args): + """ + Default constructor. + + It takes a single argument ``n`` which gives the dimension of the Gray + code. The starting Gray code string (``start``) or the starting ``rank`` + may also be given; the default is to start at rank = 0 ('0...0'). + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> a = GrayCode(3) + >>> a + GrayCode(3) + >>> a.n + 3 + + >>> a = GrayCode(3, start='100') + >>> a.current + '100' + + >>> a = GrayCode(4, rank=4) + >>> a.current + '0110' + >>> a.rank + 4 + + """ + if n < 1 or int(n) != n: + raise ValueError( + 'Gray code dimension must be a positive integer, not %i' % n) + n = Integer(n) + args = (n,) + args + obj = Basic.__new__(cls, *args) + if 'start' in kw_args: + obj._current = kw_args["start"] + if len(obj._current) > n: + raise ValueError('Gray code start has length %i but ' + 'should not be greater than %i' % (len(obj._current), n)) + elif 'rank' in kw_args: + if int(kw_args["rank"]) != kw_args["rank"]: + raise ValueError('Gray code rank must be a positive integer, ' + 'not %i' % kw_args["rank"]) + obj._rank = int(kw_args["rank"]) % obj.selections + obj._current = obj.unrank(n, obj._rank) + return obj + + def next(self, delta=1): + """ + Returns the Gray code a distance ``delta`` (default = 1) from the + current value in canonical order. + + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> a = GrayCode(3, start='110') + >>> a.next().current + '111' + >>> a.next(-1).current + '010' + """ + return GrayCode(self.n, rank=(self.rank + delta) % self.selections) + + @property + def selections(self): + """ + Returns the number of bit vectors in the Gray code. + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> a = GrayCode(3) + >>> a.selections + 8 + """ + return 2**self.n + + @property + def n(self): + """ + Returns the dimension of the Gray code. + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> a = GrayCode(5) + >>> a.n + 5 + """ + return self.args[0] + + def generate_gray(self, **hints): + """ + Generates the sequence of bit vectors of a Gray Code. + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> a = GrayCode(3) + >>> list(a.generate_gray()) + ['000', '001', '011', '010', '110', '111', '101', '100'] + >>> list(a.generate_gray(start='011')) + ['011', '010', '110', '111', '101', '100'] + >>> list(a.generate_gray(rank=4)) + ['110', '111', '101', '100'] + + See Also + ======== + + skip + + References + ========== + + .. [1] Knuth, D. (2011). The Art of Computer Programming, + Vol 4, Addison Wesley + + """ + bits = self.n + start = None + if "start" in hints: + start = hints["start"] + elif "rank" in hints: + start = GrayCode.unrank(self.n, hints["rank"]) + if start is not None: + self._current = start + current = self.current + graycode_bin = gray_to_bin(current) + if len(graycode_bin) > self.n: + raise ValueError('Gray code start has length %i but should ' + 'not be greater than %i' % (len(graycode_bin), bits)) + self._current = int(current, 2) + graycode_int = int(''.join(graycode_bin), 2) + for i in range(graycode_int, 1 << bits): + if self._skip: + self._skip = False + else: + yield self.current + bbtc = (i ^ (i + 1)) + gbtc = (bbtc ^ (bbtc >> 1)) + self._current = (self._current ^ gbtc) + self._current = 0 + + def skip(self): + """ + Skips the bit generation. + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> a = GrayCode(3) + >>> for i in a.generate_gray(): + ... if i == '010': + ... a.skip() + ... print(i) + ... + 000 + 001 + 011 + 010 + 111 + 101 + 100 + + See Also + ======== + + generate_gray + """ + self._skip = True + + @property + def rank(self): + """ + Ranks the Gray code. + + A ranking algorithm determines the position (or rank) + of a combinatorial object among all the objects w.r.t. + a given order. For example, the 4 bit binary reflected + Gray code (BRGC) '0101' has a rank of 6 as it appears in + the 6th position in the canonical ordering of the family + of 4 bit Gray codes. + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> a = GrayCode(3) + >>> list(a.generate_gray()) + ['000', '001', '011', '010', '110', '111', '101', '100'] + >>> GrayCode(3, start='100').rank + 7 + >>> GrayCode(3, rank=7).current + '100' + + See Also + ======== + + unrank + + References + ========== + + .. [1] https://web.archive.org/web/20200224064753/http://statweb.stanford.edu/~susan/courses/s208/node12.html + + """ + if self._rank is None: + self._rank = int(gray_to_bin(self.current), 2) + return self._rank + + @property + def current(self): + """ + Returns the currently referenced Gray code as a bit string. + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> GrayCode(3, start='100').current + '100' + """ + rv = self._current or '0' + if not isinstance(rv, str): + rv = bin(rv)[2:] + return rv.rjust(self.n, '0') + + @classmethod + def unrank(self, n, rank): + """ + Unranks an n-bit sized Gray code of rank k. This method exists + so that a derivative GrayCode class can define its own code of + a given rank. + + The string here is generated in reverse order to allow for tail-call + optimization. + + Examples + ======== + + >>> from sympy.combinatorics import GrayCode + >>> GrayCode(5, rank=3).current + '00010' + >>> GrayCode.unrank(5, 3) + '00010' + + See Also + ======== + + rank + """ + def _unrank(k, n): + if n == 1: + return str(k % 2) + m = 2**(n - 1) + if k < m: + return '0' + _unrank(k, n - 1) + return '1' + _unrank(m - (k % m) - 1, n - 1) + return _unrank(rank, n) + + +def random_bitstring(n): + """ + Generates a random bitlist of length n. + + Examples + ======== + + >>> from sympy.combinatorics.graycode import random_bitstring + >>> random_bitstring(3) # doctest: +SKIP + 100 + """ + return ''.join([random.choice('01') for i in range(n)]) + + +def gray_to_bin(bin_list): + """ + Convert from Gray coding to binary coding. + + We assume big endian encoding. + + Examples + ======== + + >>> from sympy.combinatorics.graycode import gray_to_bin + >>> gray_to_bin('100') + '111' + + See Also + ======== + + bin_to_gray + """ + b = [bin_list[0]] + for i in range(1, len(bin_list)): + b += str(int(b[i - 1] != bin_list[i])) + return ''.join(b) + + +def bin_to_gray(bin_list): + """ + Convert from binary coding to gray coding. + + We assume big endian encoding. + + Examples + ======== + + >>> from sympy.combinatorics.graycode import bin_to_gray + >>> bin_to_gray('111') + '100' + + See Also + ======== + + gray_to_bin + """ + b = [bin_list[0]] + for i in range(1, len(bin_list)): + b += str(int(bin_list[i]) ^ int(bin_list[i - 1])) + return ''.join(b) + + +def get_subset_from_bitstring(super_set, bitstring): + """ + Gets the subset defined by the bitstring. + + Examples + ======== + + >>> from sympy.combinatorics.graycode import get_subset_from_bitstring + >>> get_subset_from_bitstring(['a', 'b', 'c', 'd'], '0011') + ['c', 'd'] + >>> get_subset_from_bitstring(['c', 'a', 'c', 'c'], '1100') + ['c', 'a'] + + See Also + ======== + + graycode_subsets + """ + if len(super_set) != len(bitstring): + raise ValueError("The sizes of the lists are not equal") + return [super_set[i] for i, j in enumerate(bitstring) + if bitstring[i] == '1'] + + +def graycode_subsets(gray_code_set): + """ + Generates the subsets as enumerated by a Gray code. + + Examples + ======== + + >>> from sympy.combinatorics.graycode import graycode_subsets + >>> list(graycode_subsets(['a', 'b', 'c'])) + [[], ['c'], ['b', 'c'], ['b'], ['a', 'b'], ['a', 'b', 'c'], \ + ['a', 'c'], ['a']] + >>> list(graycode_subsets(['a', 'b', 'c', 'c'])) + [[], ['c'], ['c', 'c'], ['c'], ['b', 'c'], ['b', 'c', 'c'], \ + ['b', 'c'], ['b'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'c'], \ + ['a', 'b', 'c'], ['a', 'c'], ['a', 'c', 'c'], ['a', 'c'], ['a']] + + See Also + ======== + + get_subset_from_bitstring + """ + for bitstring in list(GrayCode(len(gray_code_set)).generate_gray()): + yield get_subset_from_bitstring(gray_code_set, bitstring) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/group_constructs.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/group_constructs.py new file mode 100644 index 0000000000000000000000000000000000000000..a5c16ec254191646b26eee869763e2926e187da5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/group_constructs.py @@ -0,0 +1,61 @@ +from sympy.combinatorics.perm_groups import PermutationGroup +from sympy.combinatorics.permutations import Permutation +from sympy.utilities.iterables import uniq + +_af_new = Permutation._af_new + + +def DirectProduct(*groups): + """ + Returns the direct product of several groups as a permutation group. + + Explanation + =========== + + This is implemented much like the __mul__ procedure for taking the direct + product of two permutation groups, but the idea of shifting the + generators is realized in the case of an arbitrary number of groups. + A call to DirectProduct(G1, G2, ..., Gn) is generally expected to be faster + than a call to G1*G2*...*Gn (and thus the need for this algorithm). + + Examples + ======== + + >>> from sympy.combinatorics.group_constructs import DirectProduct + >>> from sympy.combinatorics.named_groups import CyclicGroup + >>> C = CyclicGroup(4) + >>> G = DirectProduct(C, C, C) + >>> G.order() + 64 + + See Also + ======== + + sympy.combinatorics.perm_groups.PermutationGroup.__mul__ + + """ + degrees = [] + gens_count = [] + total_degree = 0 + total_gens = 0 + for group in groups: + current_deg = group.degree + current_num_gens = len(group.generators) + degrees.append(current_deg) + total_degree += current_deg + gens_count.append(current_num_gens) + total_gens += current_num_gens + array_gens = [] + for i in range(total_gens): + array_gens.append(list(range(total_degree))) + current_gen = 0 + current_deg = 0 + for i in range(len(gens_count)): + for j in range(current_gen, current_gen + gens_count[i]): + gen = ((groups[i].generators)[j - current_gen]).array_form + array_gens[j][current_deg:current_deg + degrees[i]] = \ + [x + current_deg for x in gen] + current_gen += gens_count[i] + current_deg += degrees[i] + perm_gens = list(uniq([_af_new(list(a)) for a in array_gens])) + return PermutationGroup(perm_gens, dups=False) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/group_numbers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/group_numbers.py new file mode 100644 index 0000000000000000000000000000000000000000..8099dfc2ed8a6943aa1261f9374ed84f0ad3c522 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/group_numbers.py @@ -0,0 +1,294 @@ +from itertools import chain, combinations + +from sympy.external.gmpy import gcd +from sympy.ntheory.factor_ import factorint +from sympy.utilities.misc import as_int + + +def _is_nilpotent_number(factors: dict) -> bool: + """ Check whether `n` is a nilpotent number. + Note that ``factors`` is a prime factorization of `n`. + + This is a low-level helper for ``is_nilpotent_number``, for internal use. + """ + for p in factors.keys(): + for q, e in factors.items(): + # We want to calculate + # any(pow(q, k, p) == 1 for k in range(1, e + 1)) + m = 1 + for _ in range(e): + m = m*q % p + if m == 1: + return False + return True + + +def is_nilpotent_number(n) -> bool: + """ + Check whether `n` is a nilpotent number. A number `n` is said to be + nilpotent if and only if every finite group of order `n` is nilpotent. + For more information see [1]_. + + Examples + ======== + + >>> from sympy.combinatorics.group_numbers import is_nilpotent_number + >>> from sympy import randprime + >>> is_nilpotent_number(21) + False + >>> is_nilpotent_number(randprime(1, 30)**12) + True + + References + ========== + + .. [1] Pakianathan, J., Shankar, K., Nilpotent Numbers, + The American Mathematical Monthly, 107(7), 631-634. + .. [2] https://oeis.org/A056867 + + """ + n = as_int(n) + if n <= 0: + raise ValueError("n must be a positive integer, not %i" % n) + return _is_nilpotent_number(factorint(n)) + + +def is_abelian_number(n) -> bool: + """ + Check whether `n` is an abelian number. A number `n` is said to be abelian + if and only if every finite group of order `n` is abelian. For more + information see [1]_. + + Examples + ======== + + >>> from sympy.combinatorics.group_numbers import is_abelian_number + >>> from sympy import randprime + >>> is_abelian_number(4) + True + >>> is_abelian_number(randprime(1, 2000)**2) + True + >>> is_abelian_number(60) + False + + References + ========== + + .. [1] Pakianathan, J., Shankar, K., Nilpotent Numbers, + The American Mathematical Monthly, 107(7), 631-634. + .. [2] https://oeis.org/A051532 + + """ + n = as_int(n) + if n <= 0: + raise ValueError("n must be a positive integer, not %i" % n) + factors = factorint(n) + return all(e < 3 for e in factors.values()) and _is_nilpotent_number(factors) + + +def is_cyclic_number(n) -> bool: + """ + Check whether `n` is a cyclic number. A number `n` is said to be cyclic + if and only if every finite group of order `n` is cyclic. For more + information see [1]_. + + Examples + ======== + + >>> from sympy.combinatorics.group_numbers import is_cyclic_number + >>> from sympy import randprime + >>> is_cyclic_number(15) + True + >>> is_cyclic_number(randprime(1, 2000)**2) + False + >>> is_cyclic_number(4) + False + + References + ========== + + .. [1] Pakianathan, J., Shankar, K., Nilpotent Numbers, + The American Mathematical Monthly, 107(7), 631-634. + .. [2] https://oeis.org/A003277 + + """ + n = as_int(n) + if n <= 0: + raise ValueError("n must be a positive integer, not %i" % n) + factors = factorint(n) + return all(e == 1 for e in factors.values()) and _is_nilpotent_number(factors) + + +def _holder_formula(prime_factors): + r""" Number of groups of order `n`. + where `n` is squarefree and its prime factors are ``prime_factors``. + i.e., ``n == math.prod(prime_factors)`` + + Explanation + =========== + + When `n` is squarefree, the number of groups of order `n` is expressed by + + .. math :: + \sum_{d \mid n} \prod_p \frac{p^{c(p, d)} - 1}{p - 1} + + where `n=de`, `p` is the prime factor of `e`, + and `c(p, d)` is the number of prime factors `q` of `d` such that `q \equiv 1 \pmod{p}` [2]_. + + The formula is elegant, but can be improved when implemented as an algorithm. + Since `n` is assumed to be squarefree, the divisor `d` of `n` can be identified with the power set of prime factors. + We let `N` be the set of prime factors of `n`. + `F = \{p \in N : \forall q \in N, q \not\equiv 1 \pmod{p} \}, M = N \setminus F`, we have the following. + + .. math :: + \sum_{d \in 2^{M}} \prod_{p \in M \setminus d} \frac{p^{c(p, F \cup d)} - 1}{p - 1} + + Practically, many prime factors are expected to be members of `F`, thus reducing computation time. + + Parameters + ========== + + prime_factors : set + The set of prime factors of ``n``. where `n` is squarefree. + + Returns + ======= + + int : Number of groups of order ``n`` + + Examples + ======== + + >>> from sympy.combinatorics.group_numbers import _holder_formula + >>> _holder_formula({2}) # n = 2 + 1 + >>> _holder_formula({2, 3}) # n = 2*3 = 6 + 2 + + See Also + ======== + + groups_count + + References + ========== + + .. [1] Otto Holder, Die Gruppen der Ordnungen p^3, pq^2, pqr, p^4, + Math. Ann. 43 pp. 301-412 (1893). + http://dx.doi.org/10.1007/BF01443651 + .. [2] John H. Conway, Heiko Dietrich and E.A. O'Brien, + Counting groups: gnus, moas and other exotica + The Mathematical Intelligencer 30, 6-15 (2008) + https://doi.org/10.1007/BF02985731 + + """ + F = {p for p in prime_factors if all(q % p != 1 for q in prime_factors)} + M = prime_factors - F + + s = 0 + powerset = chain.from_iterable(combinations(M, r) for r in range(len(M)+1)) + for ps in powerset: + ps = set(ps) + prod = 1 + for p in M - ps: + c = len([q for q in F | ps if q % p == 1]) + prod *= (p**c - 1) // (p - 1) + if not prod: + break + s += prod + return s + + +def groups_count(n): + r""" Number of groups of order `n`. + In [1]_, ``gnu(n)`` is given, so we follow this notation here as well. + + Parameters + ========== + + n : Integer + ``n`` is a positive integer + + Returns + ======= + + int : ``gnu(n)`` + + Raises + ====== + + ValueError + Number of groups of order ``n`` is unknown or not implemented. + For example, gnu(`2^{11}`) is not yet known. + On the other hand, gnu(99) is known to be 2, + but this has not yet been implemented in this function. + + Examples + ======== + + >>> from sympy.combinatorics.group_numbers import groups_count + >>> groups_count(3) # There is only one cyclic group of order 3 + 1 + >>> # There are two groups of order 10: the cyclic group and the dihedral group + >>> groups_count(10) + 2 + + See Also + ======== + + is_cyclic_number + `n` is cyclic iff gnu(n) = 1 + + References + ========== + + .. [1] John H. Conway, Heiko Dietrich and E.A. O'Brien, + Counting groups: gnus, moas and other exotica + The Mathematical Intelligencer 30, 6-15 (2008) + https://doi.org/10.1007/BF02985731 + .. [2] https://oeis.org/A000001 + + """ + n = as_int(n) + if n <= 0: + raise ValueError("n must be a positive integer, not %i" % n) + factors = factorint(n) + if len(factors) == 1: + (p, e) = list(factors.items())[0] + if p == 2: + A000679 = [1, 1, 2, 5, 14, 51, 267, 2328, 56092, 10494213, 49487367289] + if e < len(A000679): + return A000679[e] + if p == 3: + A090091 = [1, 1, 2, 5, 15, 67, 504, 9310, 1396077, 5937876645] + if e < len(A090091): + return A090091[e] + if e <= 2: # gnu(p) = 1, gnu(p**2) = 2 + return e + if e == 3: # gnu(p**3) = 5 + return 5 + if e == 4: # if p is an odd prime, gnu(p**4) = 15 + return 15 + if e == 5: # if p >= 5, gnu(p**5) is expressed by the following equation + return 61 + 2*p + 2*gcd(p-1, 3) + gcd(p-1, 4) + if e == 6: # if p >= 6, gnu(p**6) is expressed by the following equation + return 3*p**2 + 39*p + 344 +\ + 24*gcd(p-1, 3) + 11*gcd(p-1, 4) + 2*gcd(p-1, 5) + if e == 7: # if p >= 7, gnu(p**7) is expressed by the following equation + if p == 5: + return 34297 + return 3*p**5 + 12*p**4 + 44*p**3 + 170*p**2 + 707*p + 2455 +\ + (4*p**2 + 44*p + 291)*gcd(p-1, 3) + (p**2 + 19*p + 135)*gcd(p-1, 4) + \ + (3*p + 31)*gcd(p-1, 5) + 4*gcd(p-1, 7) + 5*gcd(p-1, 8) + gcd(p-1, 9) + if any(e > 1 for e in factors.values()): # n is not squarefree + # some known values for small n that have more than 1 factor and are not square free (https://oeis.org/A000001) + small = {12: 5, 18: 5, 20: 5, 24: 15, 28: 4, 36: 14, 40: 14, 44: 4, 45: 2, 48: 52, + 50: 5, 52: 5, 54: 15, 56: 13, 60: 13, 63: 4, 68: 5, 72: 50, 75: 3, 76: 4, + 80: 52, 84: 15, 88: 12, 90: 10, 92: 4} + if n in small: + return small[n] + raise ValueError("Number of groups of order n is unknown or not implemented") + if len(factors) == 2: # n is squarefree semiprime + p, q = sorted(factors.keys()) + return 2 if q % p == 1 else 1 + return _holder_formula(set(factors.keys())) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/homomorphisms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/homomorphisms.py new file mode 100644 index 0000000000000000000000000000000000000000..256f56b3aa7c5404d332f42e37d4f1117ea81db7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/homomorphisms.py @@ -0,0 +1,549 @@ +import itertools +from sympy.combinatorics.fp_groups import FpGroup, FpSubgroup, simplify_presentation +from sympy.combinatorics.free_groups import FreeGroup +from sympy.combinatorics.perm_groups import PermutationGroup +from sympy.core.intfunc import igcd +from sympy.functions.combinatorial.numbers import totient +from sympy.core.singleton import S + +class GroupHomomorphism: + ''' + A class representing group homomorphisms. Instantiate using `homomorphism()`. + + References + ========== + + .. [1] Holt, D., Eick, B. and O'Brien, E. (2005). Handbook of computational group theory. + + ''' + + def __init__(self, domain, codomain, images): + self.domain = domain + self.codomain = codomain + self.images = images + self._inverses = None + self._kernel = None + self._image = None + + def _invs(self): + ''' + Return a dictionary with `{gen: inverse}` where `gen` is a rewriting + generator of `codomain` (e.g. strong generator for permutation groups) + and `inverse` is an element of its preimage + + ''' + image = self.image() + inverses = {} + for k in list(self.images.keys()): + v = self.images[k] + if not (v in inverses + or v.is_identity): + inverses[v] = k + if isinstance(self.codomain, PermutationGroup): + gens = image.strong_gens + else: + gens = image.generators + for g in gens: + if g in inverses or g.is_identity: + continue + w = self.domain.identity + if isinstance(self.codomain, PermutationGroup): + parts = image._strong_gens_slp[g][::-1] + else: + parts = g + for s in parts: + if s in inverses: + w = w*inverses[s] + else: + w = w*inverses[s**-1]**-1 + inverses[g] = w + + return inverses + + def invert(self, g): + ''' + Return an element of the preimage of ``g`` or of each element + of ``g`` if ``g`` is a list. + + Explanation + =========== + + If the codomain is an FpGroup, the inverse for equal + elements might not always be the same unless the FpGroup's + rewriting system is confluent. However, making a system + confluent can be time-consuming. If it's important, try + `self.codomain.make_confluent()` first. + + ''' + from sympy.combinatorics import Permutation + from sympy.combinatorics.free_groups import FreeGroupElement + if isinstance(g, (Permutation, FreeGroupElement)): + if isinstance(self.codomain, FpGroup): + g = self.codomain.reduce(g) + if self._inverses is None: + self._inverses = self._invs() + image = self.image() + w = self.domain.identity + if isinstance(self.codomain, PermutationGroup): + gens = image.generator_product(g)[::-1] + else: + gens = g + # the following can't be "for s in gens:" + # because that would be equivalent to + # "for s in gens.array_form:" when g is + # a FreeGroupElement. On the other hand, + # when you call gens by index, the generator + # (or inverse) at position i is returned. + for i in range(len(gens)): + s = gens[i] + if s.is_identity: + continue + if s in self._inverses: + w = w*self._inverses[s] + else: + w = w*self._inverses[s**-1]**-1 + return w + elif isinstance(g, list): + return [self.invert(e) for e in g] + + def kernel(self): + ''' + Compute the kernel of `self`. + + ''' + if self._kernel is None: + self._kernel = self._compute_kernel() + return self._kernel + + def _compute_kernel(self): + G = self.domain + G_order = G.order() + if G_order is S.Infinity: + raise NotImplementedError( + "Kernel computation is not implemented for infinite groups") + gens = [] + if isinstance(G, PermutationGroup): + K = PermutationGroup(G.identity) + else: + K = FpSubgroup(G, gens, normal=True) + i = self.image().order() + while K.order()*i != G_order: + r = G.random() + k = r*self.invert(self(r))**-1 + if k not in K: + gens.append(k) + if isinstance(G, PermutationGroup): + K = PermutationGroup(gens) + else: + K = FpSubgroup(G, gens, normal=True) + return K + + def image(self): + ''' + Compute the image of `self`. + + ''' + if self._image is None: + values = list(set(self.images.values())) + if isinstance(self.codomain, PermutationGroup): + self._image = self.codomain.subgroup(values) + else: + self._image = FpSubgroup(self.codomain, values) + return self._image + + def _apply(self, elem): + ''' + Apply `self` to `elem`. + + ''' + if elem not in self.domain: + if isinstance(elem, (list, tuple)): + return [self._apply(e) for e in elem] + raise ValueError("The supplied element does not belong to the domain") + if elem.is_identity: + return self.codomain.identity + else: + images = self.images + value = self.codomain.identity + if isinstance(self.domain, PermutationGroup): + gens = self.domain.generator_product(elem, original=True) + for g in gens: + if g in self.images: + value = images[g]*value + else: + value = images[g**-1]**-1*value + else: + i = 0 + for _, p in elem.array_form: + if p < 0: + g = elem[i]**-1 + else: + g = elem[i] + value = value*images[g]**p + i += abs(p) + return value + + def __call__(self, elem): + return self._apply(elem) + + def is_injective(self): + ''' + Check if the homomorphism is injective + + ''' + return self.kernel().order() == 1 + + def is_surjective(self): + ''' + Check if the homomorphism is surjective + + ''' + im = self.image().order() + oth = self.codomain.order() + if im is S.Infinity and oth is S.Infinity: + return None + else: + return im == oth + + def is_isomorphism(self): + ''' + Check if `self` is an isomorphism. + + ''' + return self.is_injective() and self.is_surjective() + + def is_trivial(self): + ''' + Check is `self` is a trivial homomorphism, i.e. all elements + are mapped to the identity. + + ''' + return self.image().order() == 1 + + def compose(self, other): + ''' + Return the composition of `self` and `other`, i.e. + the homomorphism phi such that for all g in the domain + of `other`, phi(g) = self(other(g)) + + ''' + if not other.image().is_subgroup(self.domain): + raise ValueError("The image of `other` must be a subgroup of " + "the domain of `self`") + images = {g: self(other(g)) for g in other.images} + return GroupHomomorphism(other.domain, self.codomain, images) + + def restrict_to(self, H): + ''' + Return the restriction of the homomorphism to the subgroup `H` + of the domain. + + ''' + if not isinstance(H, PermutationGroup) or not H.is_subgroup(self.domain): + raise ValueError("Given H is not a subgroup of the domain") + domain = H + images = {g: self(g) for g in H.generators} + return GroupHomomorphism(domain, self.codomain, images) + + def invert_subgroup(self, H): + ''' + Return the subgroup of the domain that is the inverse image + of the subgroup ``H`` of the homomorphism image + + ''' + if not H.is_subgroup(self.image()): + raise ValueError("Given H is not a subgroup of the image") + gens = [] + P = PermutationGroup(self.image().identity) + for h in H.generators: + h_i = self.invert(h) + if h_i not in P: + gens.append(h_i) + P = PermutationGroup(gens) + for k in self.kernel().generators: + if k*h_i not in P: + gens.append(k*h_i) + P = PermutationGroup(gens) + return P + +def homomorphism(domain, codomain, gens, images=(), check=True): + ''' + Create (if possible) a group homomorphism from the group ``domain`` + to the group ``codomain`` defined by the images of the domain's + generators ``gens``. ``gens`` and ``images`` can be either lists or tuples + of equal sizes. If ``gens`` is a proper subset of the group's generators, + the unspecified generators will be mapped to the identity. If the + images are not specified, a trivial homomorphism will be created. + + If the given images of the generators do not define a homomorphism, + an exception is raised. + + If ``check`` is ``False``, do not check whether the given images actually + define a homomorphism. + + ''' + if not isinstance(domain, (PermutationGroup, FpGroup, FreeGroup)): + raise TypeError("The domain must be a group") + if not isinstance(codomain, (PermutationGroup, FpGroup, FreeGroup)): + raise TypeError("The codomain must be a group") + + generators = domain.generators + if not all(g in generators for g in gens): + raise ValueError("The supplied generators must be a subset of the domain's generators") + if not all(g in codomain for g in images): + raise ValueError("The images must be elements of the codomain") + + if images and len(images) != len(gens): + raise ValueError("The number of images must be equal to the number of generators") + + gens = list(gens) + images = list(images) + + images.extend([codomain.identity]*(len(generators)-len(images))) + gens.extend([g for g in generators if g not in gens]) + images = dict(zip(gens,images)) + + if check and not _check_homomorphism(domain, codomain, images): + raise ValueError("The given images do not define a homomorphism") + return GroupHomomorphism(domain, codomain, images) + +def _check_homomorphism(domain, codomain, images): + """ + Check that a given mapping of generators to images defines a homomorphism. + + Parameters + ========== + domain : PermutationGroup, FpGroup, FreeGroup + codomain : PermutationGroup, FpGroup, FreeGroup + images : dict + The set of keys must be equal to domain.generators. + The values must be elements of the codomain. + + """ + pres = domain if hasattr(domain, 'relators') else domain.presentation() + rels = pres.relators + gens = pres.generators + symbols = [g.ext_rep[0] for g in gens] + symbols_to_domain_generators = dict(zip(symbols, domain.generators)) + identity = codomain.identity + + def _image(r): + w = identity + for symbol, power in r.array_form: + g = symbols_to_domain_generators[symbol] + w *= images[g]**power + return w + + for r in rels: + if isinstance(codomain, FpGroup): + s = codomain.equals(_image(r), identity) + if s is None: + # only try to make the rewriting system + # confluent when it can't determine the + # truth of equality otherwise + success = codomain.make_confluent() + s = codomain.equals(_image(r), identity) + if s is None and not success: + raise RuntimeError("Can't determine if the images " + "define a homomorphism. Try increasing " + "the maximum number of rewriting rules " + "(group._rewriting_system.set_max(new_value); " + "the current value is stored in group._rewriting" + "_system.maxeqns)") + else: + s = _image(r).is_identity + if not s: + return False + return True + +def orbit_homomorphism(group, omega): + ''' + Return the homomorphism induced by the action of the permutation + group ``group`` on the set ``omega`` that is closed under the action. + + ''' + from sympy.combinatorics import Permutation + from sympy.combinatorics.named_groups import SymmetricGroup + codomain = SymmetricGroup(len(omega)) + identity = codomain.identity + omega = list(omega) + images = {g: identity*Permutation([omega.index(o^g) for o in omega]) for g in group.generators} + group._schreier_sims(base=omega) + H = GroupHomomorphism(group, codomain, images) + if len(group.basic_stabilizers) > len(omega): + H._kernel = group.basic_stabilizers[len(omega)] + else: + H._kernel = PermutationGroup([group.identity]) + return H + +def block_homomorphism(group, blocks): + ''' + Return the homomorphism induced by the action of the permutation + group ``group`` on the block system ``blocks``. The latter should be + of the same form as returned by the ``minimal_block`` method for + permutation groups, namely a list of length ``group.degree`` where + the i-th entry is a representative of the block i belongs to. + + ''' + from sympy.combinatorics import Permutation + from sympy.combinatorics.named_groups import SymmetricGroup + + n = len(blocks) + + # number the blocks; m is the total number, + # b is such that b[i] is the number of the block i belongs to, + # p is the list of length m such that p[i] is the representative + # of the i-th block + m = 0 + p = [] + b = [None]*n + for i in range(n): + if blocks[i] == i: + p.append(i) + b[i] = m + m += 1 + for i in range(n): + b[i] = b[blocks[i]] + + codomain = SymmetricGroup(m) + # the list corresponding to the identity permutation in codomain + identity = range(m) + images = {g: Permutation([b[p[i]^g] for i in identity]) for g in group.generators} + H = GroupHomomorphism(group, codomain, images) + return H + +def group_isomorphism(G, H, isomorphism=True): + ''' + Compute an isomorphism between 2 given groups. + + Parameters + ========== + + G : A finite ``FpGroup`` or a ``PermutationGroup``. + First group. + + H : A finite ``FpGroup`` or a ``PermutationGroup`` + Second group. + + isomorphism : bool + This is used to avoid the computation of homomorphism + when the user only wants to check if there exists + an isomorphism between the groups. + + Returns + ======= + + If isomorphism = False -- Returns a boolean. + If isomorphism = True -- Returns a boolean and an isomorphism between `G` and `H`. + + Examples + ======== + + >>> from sympy.combinatorics import free_group, Permutation + >>> from sympy.combinatorics.perm_groups import PermutationGroup + >>> from sympy.combinatorics.fp_groups import FpGroup + >>> from sympy.combinatorics.homomorphisms import group_isomorphism + >>> from sympy.combinatorics.named_groups import DihedralGroup, AlternatingGroup + + >>> D = DihedralGroup(8) + >>> p = Permutation(0, 1, 2, 3, 4, 5, 6, 7) + >>> P = PermutationGroup(p) + >>> group_isomorphism(D, P) + (False, None) + + >>> F, a, b = free_group("a, b") + >>> G = FpGroup(F, [a**3, b**3, (a*b)**2]) + >>> H = AlternatingGroup(4) + >>> (check, T) = group_isomorphism(G, H) + >>> check + True + >>> T(b*a*b**-1*a**-1*b**-1) + (0 2 3) + + Notes + ===== + + Uses the approach suggested by Robert Tarjan to compute the isomorphism between two groups. + First, the generators of ``G`` are mapped to the elements of ``H`` and + we check if the mapping induces an isomorphism. + + ''' + if not isinstance(G, (PermutationGroup, FpGroup)): + raise TypeError("The group must be a PermutationGroup or an FpGroup") + if not isinstance(H, (PermutationGroup, FpGroup)): + raise TypeError("The group must be a PermutationGroup or an FpGroup") + + if isinstance(G, FpGroup) and isinstance(H, FpGroup): + G = simplify_presentation(G) + H = simplify_presentation(H) + # Two infinite FpGroups with the same generators are isomorphic + # when the relators are same but are ordered differently. + if G.generators == H.generators and (G.relators).sort() == (H.relators).sort(): + if not isomorphism: + return True + return (True, homomorphism(G, H, G.generators, H.generators)) + + # `_H` is the permutation group isomorphic to `H`. + _H = H + g_order = G.order() + h_order = H.order() + + if g_order is S.Infinity: + raise NotImplementedError("Isomorphism methods are not implemented for infinite groups.") + + if isinstance(H, FpGroup): + if h_order is S.Infinity: + raise NotImplementedError("Isomorphism methods are not implemented for infinite groups.") + _H, h_isomorphism = H._to_perm_group() + + if (g_order != h_order) or (G.is_abelian != H.is_abelian): + if not isomorphism: + return False + return (False, None) + + if not isomorphism: + # Two groups of the same cyclic numbered order + # are isomorphic to each other. + n = g_order + if (igcd(n, totient(n))) == 1: + return True + + # Match the generators of `G` with subsets of `_H` + gens = list(G.generators) + for subset in itertools.permutations(_H, len(gens)): + images = list(subset) + images.extend([_H.identity]*(len(G.generators)-len(images))) + _images = dict(zip(gens,images)) + if _check_homomorphism(G, _H, _images): + if isinstance(H, FpGroup): + images = h_isomorphism.invert(images) + T = homomorphism(G, H, G.generators, images, check=False) + if T.is_isomorphism(): + # It is a valid isomorphism + if not isomorphism: + return True + return (True, T) + + if not isomorphism: + return False + return (False, None) + +def is_isomorphic(G, H): + ''' + Check if the groups are isomorphic to each other + + Parameters + ========== + + G : A finite ``FpGroup`` or a ``PermutationGroup`` + First group. + + H : A finite ``FpGroup`` or a ``PermutationGroup`` + Second group. + + Returns + ======= + + boolean + ''' + return group_isomorphism(G, H, isomorphism=False) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/named_groups.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/named_groups.py new file mode 100644 index 0000000000000000000000000000000000000000..59f10c40ef716e3b644e00f936323e9f6936eb88 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/named_groups.py @@ -0,0 +1,332 @@ +from sympy.combinatorics.group_constructs import DirectProduct +from sympy.combinatorics.perm_groups import PermutationGroup +from sympy.combinatorics.permutations import Permutation + +_af_new = Permutation._af_new + + +def AbelianGroup(*cyclic_orders): + """ + Returns the direct product of cyclic groups with the given orders. + + Explanation + =========== + + According to the structure theorem for finite abelian groups ([1]), + every finite abelian group can be written as the direct product of + finitely many cyclic groups. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import AbelianGroup + >>> AbelianGroup(3, 4) + PermutationGroup([ + (6)(0 1 2), + (3 4 5 6)]) + >>> _.is_group + True + + See Also + ======== + + DirectProduct + + References + ========== + + .. [1] https://groupprops.subwiki.org/wiki/Structure_theorem_for_finitely_generated_abelian_groups + + """ + groups = [] + degree = 0 + order = 1 + for size in cyclic_orders: + degree += size + order *= size + groups.append(CyclicGroup(size)) + G = DirectProduct(*groups) + G._is_abelian = True + G._degree = degree + G._order = order + + return G + + +def AlternatingGroup(n): + """ + Generates the alternating group on ``n`` elements as a permutation group. + + Explanation + =========== + + For ``n > 2``, the generators taken are ``(0 1 2), (0 1 2 ... n-1)`` for + ``n`` odd + and ``(0 1 2), (1 2 ... n-1)`` for ``n`` even (See [1], p.31, ex.6.9.). + After the group is generated, some of its basic properties are set. + The cases ``n = 1, 2`` are handled separately. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import AlternatingGroup + >>> G = AlternatingGroup(4) + >>> G.is_group + True + >>> a = list(G.generate_dimino()) + >>> len(a) + 12 + >>> all(perm.is_even for perm in a) + True + + See Also + ======== + + SymmetricGroup, CyclicGroup, DihedralGroup + + References + ========== + + .. [1] Armstrong, M. "Groups and Symmetry" + + """ + # small cases are special + if n in (1, 2): + return PermutationGroup([Permutation([0])]) + + a = list(range(n)) + a[0], a[1], a[2] = a[1], a[2], a[0] + gen1 = a + if n % 2: + a = list(range(1, n)) + a.append(0) + gen2 = a + else: + a = list(range(2, n)) + a.append(1) + a.insert(0, 0) + gen2 = a + gens = [gen1, gen2] + if gen1 == gen2: + gens = gens[:1] + G = PermutationGroup([_af_new(a) for a in gens], dups=False) + + set_alternating_group_properties(G, n, n) + G._is_alt = True + return G + + +def set_alternating_group_properties(G, n, degree): + """Set known properties of an alternating group. """ + if n < 4: + G._is_abelian = True + G._is_nilpotent = True + else: + G._is_abelian = False + G._is_nilpotent = False + if n < 5: + G._is_solvable = True + else: + G._is_solvable = False + G._degree = degree + G._is_transitive = True + G._is_dihedral = False + + +def CyclicGroup(n): + """ + Generates the cyclic group of order ``n`` as a permutation group. + + Explanation + =========== + + The generator taken is the ``n``-cycle ``(0 1 2 ... n-1)`` + (in cycle notation). After the group is generated, some of its basic + properties are set. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import CyclicGroup + >>> G = CyclicGroup(6) + >>> G.is_group + True + >>> G.order() + 6 + >>> list(G.generate_schreier_sims(af=True)) + [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 0], [2, 3, 4, 5, 0, 1], + [3, 4, 5, 0, 1, 2], [4, 5, 0, 1, 2, 3], [5, 0, 1, 2, 3, 4]] + + See Also + ======== + + SymmetricGroup, DihedralGroup, AlternatingGroup + + """ + a = list(range(1, n)) + a.append(0) + gen = _af_new(a) + G = PermutationGroup([gen]) + + G._is_abelian = True + G._is_nilpotent = True + G._is_solvable = True + G._degree = n + G._is_transitive = True + G._order = n + G._is_dihedral = (n == 2) + return G + + +def DihedralGroup(n): + r""" + Generates the dihedral group `D_n` as a permutation group. + + Explanation + =========== + + The dihedral group `D_n` is the group of symmetries of the regular + ``n``-gon. The generators taken are the ``n``-cycle ``a = (0 1 2 ... n-1)`` + (a rotation of the ``n``-gon) and ``b = (0 n-1)(1 n-2)...`` + (a reflection of the ``n``-gon) in cycle rotation. It is easy to see that + these satisfy ``a**n = b**2 = 1`` and ``bab = ~a`` so they indeed generate + `D_n` (See [1]). After the group is generated, some of its basic properties + are set. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> G = DihedralGroup(5) + >>> G.is_group + True + >>> a = list(G.generate_dimino()) + >>> [perm.cyclic_form for perm in a] + [[], [[0, 1, 2, 3, 4]], [[0, 2, 4, 1, 3]], + [[0, 3, 1, 4, 2]], [[0, 4, 3, 2, 1]], [[0, 4], [1, 3]], + [[1, 4], [2, 3]], [[0, 1], [2, 4]], [[0, 2], [3, 4]], + [[0, 3], [1, 2]]] + + See Also + ======== + + SymmetricGroup, CyclicGroup, AlternatingGroup + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Dihedral_group + + """ + # small cases are special + if n == 1: + return PermutationGroup([Permutation([1, 0])]) + if n == 2: + return PermutationGroup([Permutation([1, 0, 3, 2]), + Permutation([2, 3, 0, 1]), Permutation([3, 2, 1, 0])]) + + a = list(range(1, n)) + a.append(0) + gen1 = _af_new(a) + a = list(range(n)) + a.reverse() + gen2 = _af_new(a) + G = PermutationGroup([gen1, gen2]) + # if n is a power of 2, group is nilpotent + if n & (n-1) == 0: + G._is_nilpotent = True + else: + G._is_nilpotent = False + G._is_dihedral = True + G._is_abelian = False + G._is_solvable = True + G._degree = n + G._is_transitive = True + G._order = 2*n + return G + + +def SymmetricGroup(n): + """ + Generates the symmetric group on ``n`` elements as a permutation group. + + Explanation + =========== + + The generators taken are the ``n``-cycle + ``(0 1 2 ... n-1)`` and the transposition ``(0 1)`` (in cycle notation). + (See [1]). After the group is generated, some of its basic properties + are set. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> G = SymmetricGroup(4) + >>> G.is_group + True + >>> G.order() + 24 + >>> list(G.generate_schreier_sims(af=True)) + [[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 1, 2, 0], [0, 2, 3, 1], + [1, 3, 0, 2], [2, 0, 1, 3], [3, 2, 0, 1], [0, 3, 1, 2], [1, 0, 2, 3], + [2, 1, 3, 0], [3, 0, 1, 2], [0, 1, 3, 2], [1, 2, 0, 3], [2, 3, 1, 0], + [3, 1, 0, 2], [0, 2, 1, 3], [1, 3, 2, 0], [2, 0, 3, 1], [3, 2, 1, 0], + [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3], [3, 0, 2, 1]] + + See Also + ======== + + CyclicGroup, DihedralGroup, AlternatingGroup + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Symmetric_group#Generators_and_relations + + """ + if n == 1: + G = PermutationGroup([Permutation([0])]) + elif n == 2: + G = PermutationGroup([Permutation([1, 0])]) + else: + a = list(range(1, n)) + a.append(0) + gen1 = _af_new(a) + a = list(range(n)) + a[0], a[1] = a[1], a[0] + gen2 = _af_new(a) + G = PermutationGroup([gen1, gen2]) + set_symmetric_group_properties(G, n, n) + G._is_sym = True + return G + + +def set_symmetric_group_properties(G, n, degree): + """Set known properties of a symmetric group. """ + if n < 3: + G._is_abelian = True + G._is_nilpotent = True + else: + G._is_abelian = False + G._is_nilpotent = False + if n < 5: + G._is_solvable = True + else: + G._is_solvable = False + G._degree = degree + G._is_transitive = True + G._is_dihedral = (n in [2, 3]) # cf Landau's func and Stirling's approx + + +def RubikGroup(n): + """Return a group of Rubik's cube generators + + >>> from sympy.combinatorics.named_groups import RubikGroup + >>> RubikGroup(2).is_group + True + """ + from sympy.combinatorics.generators import rubik + if n <= 1: + raise ValueError("Invalid cube. n has to be greater than 1") + return PermutationGroup(rubik(n)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/partitions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/partitions.py new file mode 100644 index 0000000000000000000000000000000000000000..dfe646baabbb5bf2350cba859a265ac32bbfaf53 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/partitions.py @@ -0,0 +1,745 @@ +from sympy.core import Basic, Dict, sympify, Tuple +from sympy.core.numbers import Integer +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import _sympify +from sympy.functions.combinatorial.numbers import bell +from sympy.matrices import zeros +from sympy.sets.sets import FiniteSet, Union +from sympy.utilities.iterables import flatten, group +from sympy.utilities.misc import as_int + + +from collections import defaultdict + + +class Partition(FiniteSet): + """ + This class represents an abstract partition. + + A partition is a set of disjoint sets whose union equals a given set. + + See Also + ======== + + sympy.utilities.iterables.partitions, + sympy.utilities.iterables.multiset_partitions + """ + + _rank = None + _partition = None + + def __new__(cls, *partition): + """ + Generates a new partition object. + + This method also verifies if the arguments passed are + valid and raises a ValueError if they are not. + + Examples + ======== + + Creating Partition from Python lists: + + >>> from sympy.combinatorics import Partition + >>> a = Partition([1, 2], [3]) + >>> a + Partition({3}, {1, 2}) + >>> a.partition + [[1, 2], [3]] + >>> len(a) + 2 + >>> a.members + (1, 2, 3) + + Creating Partition from Python sets: + + >>> Partition({1, 2, 3}, {4, 5}) + Partition({4, 5}, {1, 2, 3}) + + Creating Partition from SymPy finite sets: + + >>> from sympy import FiniteSet + >>> a = FiniteSet(1, 2, 3) + >>> b = FiniteSet(4, 5) + >>> Partition(a, b) + Partition({4, 5}, {1, 2, 3}) + """ + args = [] + dups = False + for arg in partition: + if isinstance(arg, list): + as_set = set(arg) + if len(as_set) < len(arg): + dups = True + break # error below + arg = as_set + args.append(_sympify(arg)) + + if not all(isinstance(part, FiniteSet) for part in args): + raise ValueError( + "Each argument to Partition should be " \ + "a list, set, or a FiniteSet") + + # sort so we have a canonical reference for RGS + U = Union(*args) + if dups or len(U) < sum(len(arg) for arg in args): + raise ValueError("Partition contained duplicate elements.") + + obj = FiniteSet.__new__(cls, *args) + obj.members = tuple(U) + obj.size = len(U) + return obj + + def sort_key(self, order=None): + """Return a canonical key that can be used for sorting. + + Ordering is based on the size and sorted elements of the partition + and ties are broken with the rank. + + Examples + ======== + + >>> from sympy import default_sort_key + >>> from sympy.combinatorics import Partition + >>> from sympy.abc import x + >>> a = Partition([1, 2]) + >>> b = Partition([3, 4]) + >>> c = Partition([1, x]) + >>> d = Partition(list(range(4))) + >>> l = [d, b, a + 1, a, c] + >>> l.sort(key=default_sort_key); l + [Partition({1, 2}), Partition({1}, {2}), Partition({1, x}), Partition({3, 4}), Partition({0, 1, 2, 3})] + """ + if order is None: + members = self.members + else: + members = tuple(sorted(self.members, + key=lambda w: default_sort_key(w, order))) + return tuple(map(default_sort_key, (self.size, members, self.rank))) + + @property + def partition(self): + """Return partition as a sorted list of lists. + + Examples + ======== + + >>> from sympy.combinatorics import Partition + >>> Partition([1], [2, 3]).partition + [[1], [2, 3]] + """ + if self._partition is None: + self._partition = sorted([sorted(p, key=default_sort_key) + for p in self.args]) + return self._partition + + def __add__(self, other): + """ + Return permutation whose rank is ``other`` greater than current rank, + (mod the maximum rank for the set). + + Examples + ======== + + >>> from sympy.combinatorics import Partition + >>> a = Partition([1, 2], [3]) + >>> a.rank + 1 + >>> (a + 1).rank + 2 + >>> (a + 100).rank + 1 + """ + other = as_int(other) + offset = self.rank + other + result = RGS_unrank((offset) % + RGS_enum(self.size), + self.size) + return Partition.from_rgs(result, self.members) + + def __sub__(self, other): + """ + Return permutation whose rank is ``other`` less than current rank, + (mod the maximum rank for the set). + + Examples + ======== + + >>> from sympy.combinatorics import Partition + >>> a = Partition([1, 2], [3]) + >>> a.rank + 1 + >>> (a - 1).rank + 0 + >>> (a - 100).rank + 1 + """ + return self.__add__(-other) + + def __le__(self, other): + """ + Checks if a partition is less than or equal to + the other based on rank. + + Examples + ======== + + >>> from sympy.combinatorics import Partition + >>> a = Partition([1, 2], [3, 4, 5]) + >>> b = Partition([1], [2, 3], [4], [5]) + >>> a.rank, b.rank + (9, 34) + >>> a <= a + True + >>> a <= b + True + """ + return self.sort_key() <= sympify(other).sort_key() + + def __lt__(self, other): + """ + Checks if a partition is less than the other. + + Examples + ======== + + >>> from sympy.combinatorics import Partition + >>> a = Partition([1, 2], [3, 4, 5]) + >>> b = Partition([1], [2, 3], [4], [5]) + >>> a.rank, b.rank + (9, 34) + >>> a < b + True + """ + return self.sort_key() < sympify(other).sort_key() + + @property + def rank(self): + """ + Gets the rank of a partition. + + Examples + ======== + + >>> from sympy.combinatorics import Partition + >>> a = Partition([1, 2], [3], [4, 5]) + >>> a.rank + 13 + """ + if self._rank is not None: + return self._rank + self._rank = RGS_rank(self.RGS) + return self._rank + + @property + def RGS(self): + """ + Returns the "restricted growth string" of the partition. + + Explanation + =========== + + The RGS is returned as a list of indices, L, where L[i] indicates + the block in which element i appears. For example, in a partition + of 3 elements (a, b, c) into 2 blocks ([c], [a, b]) the RGS is + [1, 1, 0]: "a" is in block 1, "b" is in block 1 and "c" is in block 0. + + Examples + ======== + + >>> from sympy.combinatorics import Partition + >>> a = Partition([1, 2], [3], [4, 5]) + >>> a.members + (1, 2, 3, 4, 5) + >>> a.RGS + (0, 0, 1, 2, 2) + >>> a + 1 + Partition({3}, {4}, {5}, {1, 2}) + >>> _.RGS + (0, 0, 1, 2, 3) + """ + rgs = {} + partition = self.partition + for i, part in enumerate(partition): + for j in part: + rgs[j] = i + return tuple([rgs[i] for i in sorted( + [i for p in partition for i in p], key=default_sort_key)]) + + @classmethod + def from_rgs(self, rgs, elements): + """ + Creates a set partition from a restricted growth string. + + Explanation + =========== + + The indices given in rgs are assumed to be the index + of the element as given in elements *as provided* (the + elements are not sorted by this routine). Block numbering + starts from 0. If any block was not referenced in ``rgs`` + an error will be raised. + + Examples + ======== + + >>> from sympy.combinatorics import Partition + >>> Partition.from_rgs([0, 1, 2, 0, 1], list('abcde')) + Partition({c}, {a, d}, {b, e}) + >>> Partition.from_rgs([0, 1, 2, 0, 1], list('cbead')) + Partition({e}, {a, c}, {b, d}) + >>> a = Partition([1, 4], [2], [3, 5]) + >>> Partition.from_rgs(a.RGS, a.members) + Partition({2}, {1, 4}, {3, 5}) + """ + if len(rgs) != len(elements): + raise ValueError('mismatch in rgs and element lengths') + max_elem = max(rgs) + 1 + partition = [[] for i in range(max_elem)] + j = 0 + for i in rgs: + partition[i].append(elements[j]) + j += 1 + if not all(p for p in partition): + raise ValueError('some blocks of the partition were empty.') + return Partition(*partition) + + +class IntegerPartition(Basic): + """ + This class represents an integer partition. + + Explanation + =========== + + In number theory and combinatorics, a partition of a positive integer, + ``n``, also called an integer partition, is a way of writing ``n`` as a + list of positive integers that sum to n. Two partitions that differ only + in the order of summands are considered to be the same partition; if order + matters then the partitions are referred to as compositions. For example, + 4 has five partitions: [4], [3, 1], [2, 2], [2, 1, 1], and [1, 1, 1, 1]; + the compositions [1, 2, 1] and [1, 1, 2] are the same as partition + [2, 1, 1]. + + See Also + ======== + + sympy.utilities.iterables.partitions, + sympy.utilities.iterables.multiset_partitions + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Partition_%28number_theory%29 + """ + + _dict = None + _keys = None + + def __new__(cls, partition, integer=None): + """ + Generates a new IntegerPartition object from a list or dictionary. + + Explanation + =========== + + The partition can be given as a list of positive integers or a + dictionary of (integer, multiplicity) items. If the partition is + preceded by an integer an error will be raised if the partition + does not sum to that given integer. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import IntegerPartition + >>> a = IntegerPartition([5, 4, 3, 1, 1]) + >>> a + IntegerPartition(14, (5, 4, 3, 1, 1)) + >>> print(a) + [5, 4, 3, 1, 1] + >>> IntegerPartition({1:3, 2:1}) + IntegerPartition(5, (2, 1, 1, 1)) + + If the value that the partition should sum to is given first, a check + will be made to see n error will be raised if there is a discrepancy: + + >>> IntegerPartition(10, [5, 4, 3, 1]) + Traceback (most recent call last): + ... + ValueError: The partition is not valid + + """ + if integer is not None: + integer, partition = partition, integer + if isinstance(partition, (dict, Dict)): + _ = [] + for k, v in sorted(partition.items(), reverse=True): + if not v: + continue + k, v = as_int(k), as_int(v) + _.extend([k]*v) + partition = tuple(_) + else: + partition = tuple(sorted(map(as_int, partition), reverse=True)) + sum_ok = False + if integer is None: + integer = sum(partition) + sum_ok = True + else: + integer = as_int(integer) + + if not sum_ok and sum(partition) != integer: + raise ValueError("Partition did not add to %s" % integer) + if any(i < 1 for i in partition): + raise ValueError("All integer summands must be greater than one") + + obj = Basic.__new__(cls, Integer(integer), Tuple(*partition)) + obj.partition = list(partition) + obj.integer = integer + return obj + + def prev_lex(self): + """Return the previous partition of the integer, n, in lexical order, + wrapping around to [1, ..., 1] if the partition is [n]. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import IntegerPartition + >>> p = IntegerPartition([4]) + >>> print(p.prev_lex()) + [3, 1] + >>> p.partition > p.prev_lex().partition + True + """ + d = defaultdict(int) + d.update(self.as_dict()) + keys = self._keys + if keys == [1]: + return IntegerPartition({self.integer: 1}) + if keys[-1] != 1: + d[keys[-1]] -= 1 + if keys[-1] == 2: + d[1] = 2 + else: + d[keys[-1] - 1] = d[1] = 1 + else: + d[keys[-2]] -= 1 + left = d[1] + keys[-2] + new = keys[-2] + d[1] = 0 + while left: + new -= 1 + if left - new >= 0: + d[new] += left//new + left -= d[new]*new + return IntegerPartition(self.integer, d) + + def next_lex(self): + """Return the next partition of the integer, n, in lexical order, + wrapping around to [n] if the partition is [1, ..., 1]. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import IntegerPartition + >>> p = IntegerPartition([3, 1]) + >>> print(p.next_lex()) + [4] + >>> p.partition < p.next_lex().partition + True + """ + d = defaultdict(int) + d.update(self.as_dict()) + key = self._keys + a = key[-1] + if a == self.integer: + d.clear() + d[1] = self.integer + elif a == 1: + if d[a] > 1: + d[a + 1] += 1 + d[a] -= 2 + else: + b = key[-2] + d[b + 1] += 1 + d[1] = (d[b] - 1)*b + d[b] = 0 + else: + if d[a] > 1: + if len(key) == 1: + d.clear() + d[a + 1] = 1 + d[1] = self.integer - a - 1 + else: + a1 = a + 1 + d[a1] += 1 + d[1] = d[a]*a - a1 + d[a] = 0 + else: + b = key[-2] + b1 = b + 1 + d[b1] += 1 + need = d[b]*b + d[a]*a - b1 + d[a] = d[b] = 0 + d[1] = need + return IntegerPartition(self.integer, d) + + def as_dict(self): + """Return the partition as a dictionary whose keys are the + partition integers and the values are the multiplicity of that + integer. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import IntegerPartition + >>> IntegerPartition([1]*3 + [2] + [3]*4).as_dict() + {1: 3, 2: 1, 3: 4} + """ + if self._dict is None: + groups = group(self.partition, multiple=False) + self._keys = [g[0] for g in groups] + self._dict = dict(groups) + return self._dict + + @property + def conjugate(self): + """ + Computes the conjugate partition of itself. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import IntegerPartition + >>> a = IntegerPartition([6, 3, 3, 2, 1]) + >>> a.conjugate + [5, 4, 3, 1, 1, 1] + """ + j = 1 + temp_arr = list(self.partition) + [0] + k = temp_arr[0] + b = [0]*k + while k > 0: + while k > temp_arr[j]: + b[k - 1] = j + k -= 1 + j += 1 + return b + + def __lt__(self, other): + """Return True if self is less than other when the partition + is listed from smallest to biggest. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import IntegerPartition + >>> a = IntegerPartition([3, 1]) + >>> a < a + False + >>> b = a.next_lex() + >>> a < b + True + >>> a == b + False + """ + return list(reversed(self.partition)) < list(reversed(other.partition)) + + def __le__(self, other): + """Return True if self is less than other when the partition + is listed from smallest to biggest. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import IntegerPartition + >>> a = IntegerPartition([4]) + >>> a <= a + True + """ + return list(reversed(self.partition)) <= list(reversed(other.partition)) + + def as_ferrers(self, char='#'): + """ + Prints the ferrer diagram of a partition. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import IntegerPartition + >>> print(IntegerPartition([1, 1, 5]).as_ferrers()) + ##### + # + # + """ + return "\n".join([char*i for i in self.partition]) + + def __str__(self): + return str(list(self.partition)) + + +def random_integer_partition(n, seed=None): + """ + Generates a random integer partition summing to ``n`` as a list + of reverse-sorted integers. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import random_integer_partition + + For the following, a seed is given so a known value can be shown; in + practice, the seed would not be given. + + >>> random_integer_partition(100, seed=[1, 1, 12, 1, 2, 1, 85, 1]) + [85, 12, 2, 1] + >>> random_integer_partition(10, seed=[1, 2, 3, 1, 5, 1]) + [5, 3, 1, 1] + >>> random_integer_partition(1) + [1] + """ + from sympy.core.random import _randint + + n = as_int(n) + if n < 1: + raise ValueError('n must be a positive integer') + + randint = _randint(seed) + + partition = [] + while (n > 0): + k = randint(1, n) + mult = randint(1, n//k) + partition.append((k, mult)) + n -= k*mult + partition.sort(reverse=True) + partition = flatten([[k]*m for k, m in partition]) + return partition + + +def RGS_generalized(m): + """ + Computes the m + 1 generalized unrestricted growth strings + and returns them as rows in matrix. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import RGS_generalized + >>> RGS_generalized(6) + Matrix([ + [ 1, 1, 1, 1, 1, 1, 1], + [ 1, 2, 3, 4, 5, 6, 0], + [ 2, 5, 10, 17, 26, 0, 0], + [ 5, 15, 37, 77, 0, 0, 0], + [ 15, 52, 151, 0, 0, 0, 0], + [ 52, 203, 0, 0, 0, 0, 0], + [203, 0, 0, 0, 0, 0, 0]]) + """ + d = zeros(m + 1) + for i in range(m + 1): + d[0, i] = 1 + + for i in range(1, m + 1): + for j in range(m): + if j <= m - i: + d[i, j] = j * d[i - 1, j] + d[i - 1, j + 1] + else: + d[i, j] = 0 + return d + + +def RGS_enum(m): + """ + RGS_enum computes the total number of restricted growth strings + possible for a superset of size m. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import RGS_enum + >>> from sympy.combinatorics import Partition + >>> RGS_enum(4) + 15 + >>> RGS_enum(5) + 52 + >>> RGS_enum(6) + 203 + + We can check that the enumeration is correct by actually generating + the partitions. Here, the 15 partitions of 4 items are generated: + + >>> a = Partition(list(range(4))) + >>> s = set() + >>> for i in range(20): + ... s.add(a) + ... a += 1 + ... + >>> assert len(s) == 15 + + """ + if (m < 1): + return 0 + elif (m == 1): + return 1 + else: + return bell(m) + + +def RGS_unrank(rank, m): + """ + Gives the unranked restricted growth string for a given + superset size. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import RGS_unrank + >>> RGS_unrank(14, 4) + [0, 1, 2, 3] + >>> RGS_unrank(0, 4) + [0, 0, 0, 0] + """ + if m < 1: + raise ValueError("The superset size must be >= 1") + if rank < 0 or RGS_enum(m) <= rank: + raise ValueError("Invalid arguments") + + L = [1] * (m + 1) + j = 1 + D = RGS_generalized(m) + for i in range(2, m + 1): + v = D[m - i, j] + cr = j*v + if cr <= rank: + L[i] = j + 1 + rank -= cr + j += 1 + else: + L[i] = int(rank / v + 1) + rank %= v + return [x - 1 for x in L[1:]] + + +def RGS_rank(rgs): + """ + Computes the rank of a restricted growth string. + + Examples + ======== + + >>> from sympy.combinatorics.partitions import RGS_rank, RGS_unrank + >>> RGS_rank([0, 1, 2, 1, 3]) + 42 + >>> RGS_rank(RGS_unrank(4, 7)) + 4 + """ + rgs_size = len(rgs) + rank = 0 + D = RGS_generalized(rgs_size) + for i in range(1, rgs_size): + n = len(rgs[(i + 1):]) + m = max(rgs[0:i]) + rank += D[n, m + 1] * rgs[i] + return rank diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/pc_groups.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/pc_groups.py new file mode 100644 index 0000000000000000000000000000000000000000..abf7b82258d8bb61ba350509fcbb3110a035fc88 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/pc_groups.py @@ -0,0 +1,710 @@ +from sympy.ntheory.primetest import isprime +from sympy.combinatorics.perm_groups import PermutationGroup +from sympy.printing.defaults import DefaultPrinting +from sympy.combinatorics.free_groups import free_group + + +class PolycyclicGroup(DefaultPrinting): + + is_group = True + is_solvable = True + + def __init__(self, pc_sequence, pc_series, relative_order, collector=None): + """ + + Parameters + ========== + + pc_sequence : list + A sequence of elements whose classes generate the cyclic factor + groups of pc_series. + pc_series : list + A subnormal sequence of subgroups where each factor group is cyclic. + relative_order : list + The orders of factor groups of pc_series. + collector : Collector + By default, it is None. Collector class provides the + polycyclic presentation with various other functionalities. + + """ + self.pcgs = pc_sequence + self.pc_series = pc_series + self.relative_order = relative_order + self.collector = Collector(self.pcgs, pc_series, relative_order) if not collector else collector + + def is_prime_order(self): + return all(isprime(order) for order in self.relative_order) + + def length(self): + return len(self.pcgs) + + +class Collector(DefaultPrinting): + + """ + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of Computational Group Theory" + Section 8.1.3 + """ + + def __init__(self, pcgs, pc_series, relative_order, free_group_=None, pc_presentation=None): + """ + + Most of the parameters for the Collector class are the same as for PolycyclicGroup. + Others are described below. + + Parameters + ========== + + free_group_ : tuple + free_group_ provides the mapping of polycyclic generating + sequence with the free group elements. + pc_presentation : dict + Provides the presentation of polycyclic groups with the + help of power and conjugate relators. + + See Also + ======== + + PolycyclicGroup + + """ + self.pcgs = pcgs + self.pc_series = pc_series + self.relative_order = relative_order + self.free_group = free_group('x:{}'.format(len(pcgs)))[0] if not free_group_ else free_group_ + self.index = {s: i for i, s in enumerate(self.free_group.symbols)} + self.pc_presentation = self.pc_relators() + + def minimal_uncollected_subword(self, word): + r""" + Returns the minimal uncollected subwords. + + Explanation + =========== + + A word ``v`` defined on generators in ``X`` is a minimal + uncollected subword of the word ``w`` if ``v`` is a subword + of ``w`` and it has one of the following form + + * `v = {x_{i+1}}^{a_j}x_i` + + * `v = {x_{i+1}}^{a_j}{x_i}^{-1}` + + * `v = {x_i}^{a_j}` + + for `a_j` not in `\{1, \ldots, s-1\}`. Where, ``s`` is the power + exponent of the corresponding generator. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics import free_group + >>> G = SymmetricGroup(4) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> F, x1, x2 = free_group("x1, x2") + >>> word = x2**2*x1**7 + >>> collector.minimal_uncollected_subword(word) + ((x2, 2),) + + """ + # To handle the case word = + if not word: + return None + + array = word.array_form + re = self.relative_order + index = self.index + + for i in range(len(array)): + s1, e1 = array[i] + + if re[index[s1]] and (e1 < 0 or e1 > re[index[s1]]-1): + return ((s1, e1), ) + + for i in range(len(array)-1): + s1, e1 = array[i] + s2, e2 = array[i+1] + + if index[s1] > index[s2]: + e = 1 if e2 > 0 else -1 + return ((s1, e1), (s2, e)) + + return None + + def relations(self): + """ + Separates the given relators of pc presentation in power and + conjugate relations. + + Returns + ======= + + (power_rel, conj_rel) + Separates pc presentation into power and conjugate relations. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> G = SymmetricGroup(3) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> power_rel, conj_rel = collector.relations() + >>> power_rel + {x0**2: (), x1**3: ()} + >>> conj_rel + {x0**-1*x1*x0: x1**2} + + See Also + ======== + + pc_relators + + """ + power_relators = {} + conjugate_relators = {} + for key, value in self.pc_presentation.items(): + if len(key.array_form) == 1: + power_relators[key] = value + else: + conjugate_relators[key] = value + return power_relators, conjugate_relators + + def subword_index(self, word, w): + """ + Returns the start and ending index of a given + subword in a word. + + Parameters + ========== + + word : FreeGroupElement + word defined on free group elements for a + polycyclic group. + w : FreeGroupElement + subword of a given word, whose starting and + ending index to be computed. + + Returns + ======= + + (i, j) + A tuple containing starting and ending index of ``w`` + in the given word. If not exists, (-1,-1) is returned. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics import free_group + >>> G = SymmetricGroup(4) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> F, x1, x2 = free_group("x1, x2") + >>> word = x2**2*x1**7 + >>> w = x2**2*x1 + >>> collector.subword_index(word, w) + (0, 3) + >>> w = x1**7 + >>> collector.subword_index(word, w) + (2, 9) + >>> w = x1**8 + >>> collector.subword_index(word, w) + (-1, -1) + + """ + low = -1 + high = -1 + for i in range(len(word)-len(w)+1): + if word.subword(i, i+len(w)) == w: + low = i + high = i+len(w) + break + return low, high + + def map_relation(self, w): + """ + Return a conjugate relation. + + Explanation + =========== + + Given a word formed by two free group elements, the + corresponding conjugate relation with those free + group elements is formed and mapped with the collected + word in the polycyclic presentation. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics import free_group + >>> G = SymmetricGroup(3) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> F, x0, x1 = free_group("x0, x1") + >>> w = x1*x0 + >>> collector.map_relation(w) + x1**2 + + See Also + ======== + + pc_presentation + + """ + array = w.array_form + s1 = array[0][0] + s2 = array[1][0] + key = ((s2, -1), (s1, 1), (s2, 1)) + key = self.free_group.dtype(key) + return self.pc_presentation[key] + + + def collected_word(self, word): + r""" + Return the collected form of a word. + + Explanation + =========== + + A word ``w`` is called collected, if `w = {x_{i_1}}^{a_1} * \ldots * + {x_{i_r}}^{a_r}` with `i_1 < i_2< \ldots < i_r` and `a_j` is in + `\{1, \ldots, {s_j}-1\}`. + + Otherwise w is uncollected. + + Parameters + ========== + + word : FreeGroupElement + An uncollected word. + + Returns + ======= + + word + A collected word of form `w = {x_{i_1}}^{a_1}, \ldots, + {x_{i_r}}^{a_r}` with `i_1, i_2, \ldots, i_r` and `a_j \in + \{1, \ldots, {s_j}-1\}`. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics.perm_groups import PermutationGroup + >>> from sympy.combinatorics import free_group + >>> G = SymmetricGroup(4) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> F, x0, x1, x2, x3 = free_group("x0, x1, x2, x3") + >>> word = x3*x2*x1*x0 + >>> collected_word = collector.collected_word(word) + >>> free_to_perm = {} + >>> free_group = collector.free_group + >>> for sym, gen in zip(free_group.symbols, collector.pcgs): + ... free_to_perm[sym] = gen + >>> G1 = PermutationGroup() + >>> for w in word: + ... sym = w[0] + ... perm = free_to_perm[sym] + ... G1 = PermutationGroup([perm] + G1.generators) + >>> G2 = PermutationGroup() + >>> for w in collected_word: + ... sym = w[0] + ... perm = free_to_perm[sym] + ... G2 = PermutationGroup([perm] + G2.generators) + + The two are not identical, but they are equivalent: + + >>> G1.equals(G2), G1 == G2 + (True, False) + + See Also + ======== + + minimal_uncollected_subword + + """ + free_group = self.free_group + while True: + w = self.minimal_uncollected_subword(word) + if not w: + break + + low, high = self.subword_index(word, free_group.dtype(w)) + if low == -1: + continue + + s1, e1 = w[0] + if len(w) == 1: + re = self.relative_order[self.index[s1]] + q = e1 // re + r = e1-q*re + + key = ((w[0][0], re), ) + key = free_group.dtype(key) + if self.pc_presentation[key]: + presentation = self.pc_presentation[key].array_form + sym, exp = presentation[0] + word_ = ((w[0][0], r), (sym, q*exp)) + word_ = free_group.dtype(word_) + else: + if r != 0: + word_ = ((w[0][0], r), ) + word_ = free_group.dtype(word_) + else: + word_ = None + word = word.eliminate_word(free_group.dtype(w), word_) + + if len(w) == 2 and w[1][1] > 0: + s2, e2 = w[1] + s2 = ((s2, 1), ) + s2 = free_group.dtype(s2) + word_ = self.map_relation(free_group.dtype(w)) + word_ = s2*word_**e1 + word_ = free_group.dtype(word_) + word = word.substituted_word(low, high, word_) + + elif len(w) == 2 and w[1][1] < 0: + s2, e2 = w[1] + s2 = ((s2, 1), ) + s2 = free_group.dtype(s2) + word_ = self.map_relation(free_group.dtype(w)) + word_ = s2**-1*word_**e1 + word_ = free_group.dtype(word_) + word = word.substituted_word(low, high, word_) + + return word + + + def pc_relators(self): + r""" + Return the polycyclic presentation. + + Explanation + =========== + + There are two types of relations used in polycyclic + presentation. + + * Power relations : Power relators are of the form `x_i^{re_i}`, + where `i \in \{0, \ldots, \mathrm{len(pcgs)}\}`, ``x`` represents polycyclic + generator and ``re`` is the corresponding relative order. + + * Conjugate relations : Conjugate relators are of the form `x_j^-1x_ix_j`, + where `j < i \in \{0, \ldots, \mathrm{len(pcgs)}\}`. + + Returns + ======= + + A dictionary with power and conjugate relations as key and + their collected form as corresponding values. + + Notes + ===== + + Identity Permutation is mapped with empty ``()``. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics.permutations import Permutation + >>> S = SymmetricGroup(49).sylow_subgroup(7) + >>> der = S.derived_series() + >>> G = der[len(der)-2] + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> pcgs = PcGroup.pcgs + >>> len(pcgs) + 6 + >>> free_group = collector.free_group + >>> pc_resentation = collector.pc_presentation + >>> free_to_perm = {} + >>> for s, g in zip(free_group.symbols, pcgs): + ... free_to_perm[s] = g + + >>> for k, v in pc_resentation.items(): + ... k_array = k.array_form + ... if v != (): + ... v_array = v.array_form + ... lhs = Permutation() + ... for gen in k_array: + ... s = gen[0] + ... e = gen[1] + ... lhs = lhs*free_to_perm[s]**e + ... if v == (): + ... assert lhs.is_identity + ... continue + ... rhs = Permutation() + ... for gen in v_array: + ... s = gen[0] + ... e = gen[1] + ... rhs = rhs*free_to_perm[s]**e + ... assert lhs == rhs + + """ + free_group = self.free_group + rel_order = self.relative_order + pc_relators = {} + perm_to_free = {} + pcgs = self.pcgs + + for gen, s in zip(pcgs, free_group.generators): + perm_to_free[gen**-1] = s**-1 + perm_to_free[gen] = s + + pcgs = pcgs[::-1] + series = self.pc_series[::-1] + rel_order = rel_order[::-1] + collected_gens = [] + + for i, gen in enumerate(pcgs): + re = rel_order[i] + relation = perm_to_free[gen]**re + G = series[i] + + l = G.generator_product(gen**re, original = True) + l.reverse() + + word = free_group.identity + for g in l: + word = word*perm_to_free[g] + + word = self.collected_word(word) + pc_relators[relation] = word if word else () + self.pc_presentation = pc_relators + + collected_gens.append(gen) + if len(collected_gens) > 1: + conj = collected_gens[len(collected_gens)-1] + conjugator = perm_to_free[conj] + + for j in range(len(collected_gens)-1): + conjugated = perm_to_free[collected_gens[j]] + + relation = conjugator**-1*conjugated*conjugator + gens = conj**-1*collected_gens[j]*conj + + l = G.generator_product(gens, original = True) + l.reverse() + word = free_group.identity + for g in l: + word = word*perm_to_free[g] + + word = self.collected_word(word) + pc_relators[relation] = word if word else () + self.pc_presentation = pc_relators + + return pc_relators + + def exponent_vector(self, element): + r""" + Return the exponent vector of length equal to the + length of polycyclic generating sequence. + + Explanation + =========== + + For a given generator/element ``g`` of the polycyclic group, + it can be represented as `g = {x_1}^{e_1}, \ldots, {x_n}^{e_n}`, + where `x_i` represents polycyclic generators and ``n`` is + the number of generators in the free_group equal to the length + of pcgs. + + Parameters + ========== + + element : Permutation + Generator of a polycyclic group. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics.permutations import Permutation + >>> G = SymmetricGroup(4) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> pcgs = PcGroup.pcgs + >>> collector.exponent_vector(G[0]) + [1, 0, 0, 0] + >>> exp = collector.exponent_vector(G[1]) + >>> g = Permutation() + >>> for i in range(len(exp)): + ... g = g*pcgs[i]**exp[i] if exp[i] else g + >>> assert g == G[1] + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of Computational Group Theory" + Section 8.1.1, Definition 8.4 + + """ + free_group = self.free_group + G = PermutationGroup() + for g in self.pcgs: + G = PermutationGroup([g] + G.generators) + gens = G.generator_product(element, original = True) + gens.reverse() + + perm_to_free = {} + for sym, g in zip(free_group.generators, self.pcgs): + perm_to_free[g**-1] = sym**-1 + perm_to_free[g] = sym + w = free_group.identity + for g in gens: + w = w*perm_to_free[g] + + word = self.collected_word(w) + + index = self.index + exp_vector = [0]*len(free_group) + word = word.array_form + for t in word: + exp_vector[index[t[0]]] = t[1] + return exp_vector + + def depth(self, element): + r""" + Return the depth of a given element. + + Explanation + =========== + + The depth of a given element ``g`` is defined by + `\mathrm{dep}[g] = i` if `e_1 = e_2 = \ldots = e_{i-1} = 0` + and `e_i != 0`, where ``e`` represents the exponent-vector. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> G = SymmetricGroup(3) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> collector.depth(G[0]) + 2 + >>> collector.depth(G[1]) + 1 + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of Computational Group Theory" + Section 8.1.1, Definition 8.5 + + """ + exp_vector = self.exponent_vector(element) + return next((i+1 for i, x in enumerate(exp_vector) if x), len(self.pcgs)+1) + + def leading_exponent(self, element): + r""" + Return the leading non-zero exponent. + + Explanation + =========== + + The leading exponent for a given element `g` is defined + by `\mathrm{leading\_exponent}[g]` `= e_i`, if `\mathrm{depth}[g] = i`. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> G = SymmetricGroup(3) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> collector.leading_exponent(G[1]) + 1 + + """ + exp_vector = self.exponent_vector(element) + depth = self.depth(element) + if depth != len(self.pcgs)+1: + return exp_vector[depth-1] + return None + + def _sift(self, z, g): + h = g + d = self.depth(h) + while d < len(self.pcgs) and z[d-1] != 1: + k = z[d-1] + e = self.leading_exponent(h)*(self.leading_exponent(k))**-1 + e = e % self.relative_order[d-1] + h = k**-e*h + d = self.depth(h) + return h + + def induced_pcgs(self, gens): + """ + + Parameters + ========== + + gens : list + A list of generators on which polycyclic subgroup + is to be defined. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> S = SymmetricGroup(8) + >>> G = S.sylow_subgroup(2) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> gens = [G[0], G[1]] + >>> ipcgs = collector.induced_pcgs(gens) + >>> [gen.order() for gen in ipcgs] + [2, 2, 2] + >>> G = S.sylow_subgroup(3) + >>> PcGroup = G.polycyclic_group() + >>> collector = PcGroup.collector + >>> gens = [G[0], G[1]] + >>> ipcgs = collector.induced_pcgs(gens) + >>> [gen.order() for gen in ipcgs] + [3] + + """ + z = [1]*len(self.pcgs) + G = gens + while G: + g = G.pop(0) + h = self._sift(z, g) + d = self.depth(h) + if d < len(self.pcgs): + for gen in z: + if gen != 1: + G.append(h**-1*gen**-1*h*gen) + z[d-1] = h + z = [gen for gen in z if gen != 1] + return z + + def constructive_membership_test(self, ipcgs, g): + """ + Return the exponent vector for induced pcgs. + """ + e = [0]*len(ipcgs) + h = g + d = self.depth(h) + for i, gen in enumerate(ipcgs): + while self.depth(gen) == d: + f = self.leading_exponent(h)*self.leading_exponent(gen) + f = f % self.relative_order[d-1] + h = gen**(-f)*h + e[i] = f + d = self.depth(h) + if h == 1: + return e + return False diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/perm_groups.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/perm_groups.py new file mode 100644 index 0000000000000000000000000000000000000000..24359cb546246d63470de92b2fb2ab0804fc9886 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/perm_groups.py @@ -0,0 +1,5459 @@ +from math import factorial as _factorial, log, prod +from itertools import chain, product + + +from sympy.combinatorics import Permutation +from sympy.combinatorics.permutations import (_af_commutes_with, _af_invert, + _af_rmul, _af_rmuln, _af_pow, Cycle) +from sympy.combinatorics.util import (_check_cycles_alt_sym, + _distribute_gens_by_base, _orbits_transversals_from_bsgs, + _handle_precomputed_bsgs, _base_ordering, _strong_gens_from_distr, + _strip, _strip_af) +from sympy.core import Basic +from sympy.core.random import _randrange, randrange, choice +from sympy.core.symbol import Symbol +from sympy.core.sympify import _sympify +from sympy.functions.combinatorial.factorials import factorial +from sympy.ntheory import primefactors, sieve +from sympy.ntheory.factor_ import (factorint, multiplicity) +from sympy.ntheory.primetest import isprime +from sympy.utilities.iterables import has_variety, is_sequence, uniq + +rmul = Permutation.rmul_with_af +_af_new = Permutation._af_new + + +class PermutationGroup(Basic): + r"""The class defining a Permutation group. + + Explanation + =========== + + ``PermutationGroup([p1, p2, ..., pn])`` returns the permutation group + generated by the list of permutations. This group can be supplied + to Polyhedron if one desires to decorate the elements to which the + indices of the permutation refer. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> from sympy.combinatorics import Polyhedron + + The permutations corresponding to motion of the front, right and + bottom face of a $2 \times 2$ Rubik's cube are defined: + + >>> F = Permutation(2, 19, 21, 8)(3, 17, 20, 10)(4, 6, 7, 5) + >>> R = Permutation(1, 5, 21, 14)(3, 7, 23, 12)(8, 10, 11, 9) + >>> D = Permutation(6, 18, 14, 10)(7, 19, 15, 11)(20, 22, 23, 21) + + These are passed as permutations to PermutationGroup: + + >>> G = PermutationGroup(F, R, D) + >>> G.order() + 3674160 + + The group can be supplied to a Polyhedron in order to track the + objects being moved. An example involving the $2 \times 2$ Rubik's cube is + given there, but here is a simple demonstration: + + >>> a = Permutation(2, 1) + >>> b = Permutation(1, 0) + >>> G = PermutationGroup(a, b) + >>> P = Polyhedron(list('ABC'), pgroup=G) + >>> P.corners + (A, B, C) + >>> P.rotate(0) # apply permutation 0 + >>> P.corners + (A, C, B) + >>> P.reset() + >>> P.corners + (A, B, C) + + Or one can make a permutation as a product of selected permutations + and apply them to an iterable directly: + + >>> P10 = G.make_perm([0, 1]) + >>> P10('ABC') + ['C', 'A', 'B'] + + See Also + ======== + + sympy.combinatorics.polyhedron.Polyhedron, + sympy.combinatorics.permutations.Permutation + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of Computational Group Theory" + + .. [2] Seress, A. + "Permutation Group Algorithms" + + .. [3] https://en.wikipedia.org/wiki/Schreier_vector + + .. [4] https://en.wikipedia.org/wiki/Nielsen_transformation#Product_replacement_algorithm + + .. [5] Frank Celler, Charles R.Leedham-Green, Scott H.Murray, + Alice C.Niemeyer, and E.A.O'Brien. "Generating Random + Elements of a Finite Group" + + .. [6] https://en.wikipedia.org/wiki/Block_%28permutation_group_theory%29 + + .. [7] https://algorithmist.com/wiki/Union_find + + .. [8] https://en.wikipedia.org/wiki/Multiply_transitive_group#Multiply_transitive_groups + + .. [9] https://en.wikipedia.org/wiki/Center_%28group_theory%29 + + .. [10] https://en.wikipedia.org/wiki/Centralizer_and_normalizer + + .. [11] https://groupprops.subwiki.org/wiki/Derived_subgroup + + .. [12] https://en.wikipedia.org/wiki/Nilpotent_group + + .. [13] https://www.math.colostate.edu/~hulpke/CGT/cgtnotes.pdf + + .. [14] https://docs.gap-system.org/doc/ref/manual.pdf + + """ + is_group = True + + def __new__(cls, *args, dups=True, **kwargs): + """The default constructor. Accepts Cycle and Permutation forms. + Removes duplicates unless ``dups`` keyword is ``False``. + """ + if not args: + args = [Permutation()] + else: + args = list(args[0] if is_sequence(args[0]) else args) + if not args: + args = [Permutation()] + if any(isinstance(a, Cycle) for a in args): + args = [Permutation(a) for a in args] + if has_variety(a.size for a in args): + degree = kwargs.pop('degree', None) + if degree is None: + degree = max(a.size for a in args) + for i in range(len(args)): + if args[i].size != degree: + args[i] = Permutation(args[i], size=degree) + if dups: + args = list(uniq([_af_new(list(a)) for a in args])) + if len(args) > 1: + args = [g for g in args if not g.is_identity] + return Basic.__new__(cls, *args, **kwargs) + + def __init__(self, *args, **kwargs): + self._generators = list(self.args) + self._order = None + self._elements = [] + self._center = None + self._is_abelian = None + self._is_transitive = None + self._is_sym = None + self._is_alt = None + self._is_primitive = None + self._is_nilpotent = None + self._is_solvable = None + self._is_trivial = None + self._transitivity_degree = None + self._max_div = None + self._is_perfect = None + self._is_cyclic = None + self._is_dihedral = None + self._r = len(self._generators) + self._degree = self._generators[0].size + + # these attributes are assigned after running schreier_sims + self._base = [] + self._strong_gens = [] + self._strong_gens_slp = [] + self._basic_orbits = [] + self._transversals = [] + self._transversal_slp = [] + + # these attributes are assigned after running _random_pr_init + self._random_gens = [] + + # finite presentation of the group as an instance of `FpGroup` + self._fp_presentation = None + + def __getitem__(self, i): + return self._generators[i] + + def __contains__(self, i): + """Return ``True`` if *i* is contained in PermutationGroup. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> p = Permutation(1, 2, 3) + >>> Permutation(3) in PermutationGroup(p) + True + + """ + if not isinstance(i, Permutation): + raise TypeError("A PermutationGroup contains only Permutations as " + "elements, not elements of type %s" % type(i)) + return self.contains(i) + + def __len__(self): + return len(self._generators) + + def equals(self, other): + """Return ``True`` if PermutationGroup generated by elements in the + group are same i.e they represent the same PermutationGroup. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> p = Permutation(0, 1, 2, 3, 4, 5) + >>> G = PermutationGroup([p, p**2]) + >>> H = PermutationGroup([p**2, p]) + >>> G.generators == H.generators + False + >>> G.equals(H) + True + + """ + if not isinstance(other, PermutationGroup): + return False + + set_self_gens = set(self.generators) + set_other_gens = set(other.generators) + + # before reaching the general case there are also certain + # optimisation and obvious cases requiring less or no actual + # computation. + if set_self_gens == set_other_gens: + return True + + # in the most general case it will check that each generator of + # one group belongs to the other PermutationGroup and vice-versa + for gen1 in set_self_gens: + if not other.contains(gen1): + return False + for gen2 in set_other_gens: + if not self.contains(gen2): + return False + return True + + def __mul__(self, other): + """ + Return the direct product of two permutation groups as a permutation + group. + + Explanation + =========== + + This implementation realizes the direct product by shifting the index + set for the generators of the second group: so if we have ``G`` acting + on ``n1`` points and ``H`` acting on ``n2`` points, ``G*H`` acts on + ``n1 + n2`` points. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import CyclicGroup + >>> G = CyclicGroup(5) + >>> H = G*G + >>> H + PermutationGroup([ + (9)(0 1 2 3 4), + (5 6 7 8 9)]) + >>> H.order() + 25 + + """ + if isinstance(other, Permutation): + return Coset(other, self, dir='+') + gens1 = [perm._array_form for perm in self.generators] + gens2 = [perm._array_form for perm in other.generators] + n1 = self._degree + n2 = other._degree + start = list(range(n1)) + end = list(range(n1, n1 + n2)) + for i in range(len(gens2)): + gens2[i] = [x + n1 for x in gens2[i]] + gens2 = [start + gen for gen in gens2] + gens1 = [gen + end for gen in gens1] + together = gens1 + gens2 + gens = [_af_new(x) for x in together] + return PermutationGroup(gens) + + def _random_pr_init(self, r, n, _random_prec_n=None): + r"""Initialize random generators for the product replacement algorithm. + + Explanation + =========== + + The implementation uses a modification of the original product + replacement algorithm due to Leedham-Green, as described in [1], + pp. 69-71; also, see [2], pp. 27-29 for a detailed theoretical + analysis of the original product replacement algorithm, and [4]. + + The product replacement algorithm is used for producing random, + uniformly distributed elements of a group `G` with a set of generators + `S`. For the initialization ``_random_pr_init``, a list ``R`` of + `\max\{r, |S|\}` group generators is created as the attribute + ``G._random_gens``, repeating elements of `S` if necessary, and the + identity element of `G` is appended to ``R`` - we shall refer to this + last element as the accumulator. Then the function ``random_pr()`` + is called ``n`` times, randomizing the list ``R`` while preserving + the generation of `G` by ``R``. The function ``random_pr()`` itself + takes two random elements ``g, h`` among all elements of ``R`` but + the accumulator and replaces ``g`` with a randomly chosen element + from `\{gh, g(~h), hg, (~h)g\}`. Then the accumulator is multiplied + by whatever ``g`` was replaced by. The new value of the accumulator is + then returned by ``random_pr()``. + + The elements returned will eventually (for ``n`` large enough) become + uniformly distributed across `G` ([5]). For practical purposes however, + the values ``n = 50, r = 11`` are suggested in [1]. + + Notes + ===== + + THIS FUNCTION HAS SIDE EFFECTS: it changes the attribute + self._random_gens + + See Also + ======== + + random_pr + + """ + deg = self.degree + random_gens = [x._array_form for x in self.generators] + k = len(random_gens) + if k < r: + for i in range(k, r): + random_gens.append(random_gens[i - k]) + acc = list(range(deg)) + random_gens.append(acc) + self._random_gens = random_gens + + # handle randomized input for testing purposes + if _random_prec_n is None: + for i in range(n): + self.random_pr() + else: + for i in range(n): + self.random_pr(_random_prec=_random_prec_n[i]) + + def _union_find_merge(self, first, second, ranks, parents, not_rep): + """Merges two classes in a union-find data structure. + + Explanation + =========== + + Used in the implementation of Atkinson's algorithm as suggested in [1], + pp. 83-87. The class merging process uses union by rank as an + optimization. ([7]) + + Notes + ===== + + THIS FUNCTION HAS SIDE EFFECTS: the list of class representatives, + ``parents``, the list of class sizes, ``ranks``, and the list of + elements that are not representatives, ``not_rep``, are changed due to + class merging. + + See Also + ======== + + minimal_block, _union_find_rep + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of computational group theory" + + .. [7] https://algorithmist.com/wiki/Union_find + + """ + rep_first = self._union_find_rep(first, parents) + rep_second = self._union_find_rep(second, parents) + if rep_first != rep_second: + # union by rank + if ranks[rep_first] >= ranks[rep_second]: + new_1, new_2 = rep_first, rep_second + else: + new_1, new_2 = rep_second, rep_first + total_rank = ranks[new_1] + ranks[new_2] + if total_rank > self.max_div: + return -1 + parents[new_2] = new_1 + ranks[new_1] = total_rank + not_rep.append(new_2) + return 1 + return 0 + + def _union_find_rep(self, num, parents): + """Find representative of a class in a union-find data structure. + + Explanation + =========== + + Used in the implementation of Atkinson's algorithm as suggested in [1], + pp. 83-87. After the representative of the class to which ``num`` + belongs is found, path compression is performed as an optimization + ([7]). + + Notes + ===== + + THIS FUNCTION HAS SIDE EFFECTS: the list of class representatives, + ``parents``, is altered due to path compression. + + See Also + ======== + + minimal_block, _union_find_merge + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of computational group theory" + + .. [7] https://algorithmist.com/wiki/Union_find + + """ + rep, parent = num, parents[num] + while parent != rep: + rep = parent + parent = parents[rep] + # path compression + temp, parent = num, parents[num] + while parent != rep: + parents[temp] = rep + temp = parent + parent = parents[temp] + return rep + + @property + def base(self): + r"""Return a base from the Schreier-Sims algorithm. + + Explanation + =========== + + For a permutation group `G`, a base is a sequence of points + `B = (b_1, b_2, \dots, b_k)` such that no element of `G` apart + from the identity fixes all the points in `B`. The concepts of + a base and strong generating set and their applications are + discussed in depth in [1], pp. 87-89 and [2], pp. 55-57. + + An alternative way to think of `B` is that it gives the + indices of the stabilizer cosets that contain more than the + identity permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> G = PermutationGroup([Permutation(0, 1, 3)(2, 4)]) + >>> G.base + [0, 2] + + See Also + ======== + + strong_gens, basic_transversals, basic_orbits, basic_stabilizers + + """ + if self._base == []: + self.schreier_sims() + return self._base + + def baseswap(self, base, strong_gens, pos, randomized=False, + transversals=None, basic_orbits=None, strong_gens_distr=None): + r"""Swap two consecutive base points in base and strong generating set. + + Explanation + =========== + + If a base for a group `G` is given by `(b_1, b_2, \dots, b_k)`, this + function returns a base `(b_1, b_2, \dots, b_{i+1}, b_i, \dots, b_k)`, + where `i` is given by ``pos``, and a strong generating set relative + to that base. The original base and strong generating set are not + modified. + + The randomized version (default) is of Las Vegas type. + + Parameters + ========== + + base, strong_gens + The base and strong generating set. + pos + The position at which swapping is performed. + randomized + A switch between randomized and deterministic version. + transversals + The transversals for the basic orbits, if known. + basic_orbits + The basic orbits, if known. + strong_gens_distr + The strong generators distributed by basic stabilizers, if known. + + Returns + ======= + + (base, strong_gens) + ``base`` is the new base, and ``strong_gens`` is a generating set + relative to it. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics.testutil import _verify_bsgs + >>> from sympy.combinatorics.perm_groups import PermutationGroup + >>> S = SymmetricGroup(4) + >>> S.schreier_sims() + >>> S.base + [0, 1, 2] + >>> base, gens = S.baseswap(S.base, S.strong_gens, 1, randomized=False) + >>> base, gens + ([0, 2, 1], + [(0 1 2 3), (3)(0 1), (1 3 2), + (2 3), (1 3)]) + + check that base, gens is a BSGS + + >>> S1 = PermutationGroup(gens) + >>> _verify_bsgs(S1, base, gens) + True + + See Also + ======== + + schreier_sims + + Notes + ===== + + The deterministic version of the algorithm is discussed in + [1], pp. 102-103; the randomized version is discussed in [1], p.103, and + [2], p.98. It is of Las Vegas type. + Notice that [1] contains a mistake in the pseudocode and + discussion of BASESWAP: on line 3 of the pseudocode, + `|\beta_{i+1}^{\left\langle T\right\rangle}|` should be replaced by + `|\beta_{i}^{\left\langle T\right\rangle}|`, and the same for the + discussion of the algorithm. + + """ + # construct the basic orbits, generators for the stabilizer chain + # and transversal elements from whatever was provided + transversals, basic_orbits, strong_gens_distr = \ + _handle_precomputed_bsgs(base, strong_gens, transversals, + basic_orbits, strong_gens_distr) + base_len = len(base) + degree = self.degree + # size of orbit of base[pos] under the stabilizer we seek to insert + # in the stabilizer chain at position pos + 1 + size = len(basic_orbits[pos])*len(basic_orbits[pos + 1]) \ + //len(_orbit(degree, strong_gens_distr[pos], base[pos + 1])) + # initialize the wanted stabilizer by a subgroup + if pos + 2 > base_len - 1: + T = [] + else: + T = strong_gens_distr[pos + 2][:] + # randomized version + if randomized is True: + stab_pos = PermutationGroup(strong_gens_distr[pos]) + schreier_vector = stab_pos.schreier_vector(base[pos + 1]) + # add random elements of the stabilizer until they generate it + while len(_orbit(degree, T, base[pos])) != size: + new = stab_pos.random_stab(base[pos + 1], + schreier_vector=schreier_vector) + T.append(new) + # deterministic version + else: + Gamma = set(basic_orbits[pos]) + Gamma.remove(base[pos]) + if base[pos + 1] in Gamma: + Gamma.remove(base[pos + 1]) + # add elements of the stabilizer until they generate it by + # ruling out member of the basic orbit of base[pos] along the way + while len(_orbit(degree, T, base[pos])) != size: + gamma = next(iter(Gamma)) + x = transversals[pos][gamma] + temp = x._array_form.index(base[pos + 1]) # (~x)(base[pos + 1]) + if temp not in basic_orbits[pos + 1]: + Gamma = Gamma - _orbit(degree, T, gamma) + else: + y = transversals[pos + 1][temp] + el = rmul(x, y) + if el(base[pos]) not in _orbit(degree, T, base[pos]): + T.append(el) + Gamma = Gamma - _orbit(degree, T, base[pos]) + # build the new base and strong generating set + strong_gens_new_distr = strong_gens_distr[:] + strong_gens_new_distr[pos + 1] = T + base_new = base[:] + base_new[pos], base_new[pos + 1] = base_new[pos + 1], base_new[pos] + strong_gens_new = _strong_gens_from_distr(strong_gens_new_distr) + for gen in T: + if gen not in strong_gens_new: + strong_gens_new.append(gen) + return base_new, strong_gens_new + + @property + def basic_orbits(self): + r""" + Return the basic orbits relative to a base and strong generating set. + + Explanation + =========== + + If `(b_1, b_2, \dots, b_k)` is a base for a group `G`, and + `G^{(i)} = G_{b_1, b_2, \dots, b_{i-1}}` is the ``i``-th basic stabilizer + (so that `G^{(1)} = G`), the ``i``-th basic orbit relative to this base + is the orbit of `b_i` under `G^{(i)}`. See [1], pp. 87-89 for more + information. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> S = SymmetricGroup(4) + >>> S.basic_orbits + [[0, 1, 2, 3], [1, 2, 3], [2, 3]] + + See Also + ======== + + base, strong_gens, basic_transversals, basic_stabilizers + + """ + if self._basic_orbits == []: + self.schreier_sims() + return self._basic_orbits + + @property + def basic_stabilizers(self): + r""" + Return a chain of stabilizers relative to a base and strong generating + set. + + Explanation + =========== + + The ``i``-th basic stabilizer `G^{(i)}` relative to a base + `(b_1, b_2, \dots, b_k)` is `G_{b_1, b_2, \dots, b_{i-1}}`. For more + information, see [1], pp. 87-89. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import AlternatingGroup + >>> A = AlternatingGroup(4) + >>> A.schreier_sims() + >>> A.base + [0, 1] + >>> for g in A.basic_stabilizers: + ... print(g) + ... + PermutationGroup([ + (3)(0 1 2), + (1 2 3)]) + PermutationGroup([ + (1 2 3)]) + + See Also + ======== + + base, strong_gens, basic_orbits, basic_transversals + + """ + + if self._transversals == []: + self.schreier_sims() + strong_gens = self._strong_gens + base = self._base + if not base: # e.g. if self is trivial + return [] + strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + basic_stabilizers = [] + for gens in strong_gens_distr: + basic_stabilizers.append(PermutationGroup(gens)) + return basic_stabilizers + + @property + def basic_transversals(self): + """ + Return basic transversals relative to a base and strong generating set. + + Explanation + =========== + + The basic transversals are transversals of the basic orbits. They + are provided as a list of dictionaries, each dictionary having + keys - the elements of one of the basic orbits, and values - the + corresponding transversal elements. See [1], pp. 87-89 for more + information. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import AlternatingGroup + >>> A = AlternatingGroup(4) + >>> A.basic_transversals + [{0: (3), 1: (3)(0 1 2), 2: (3)(0 2 1), 3: (0 3 1)}, {1: (3), 2: (1 2 3), 3: (1 3 2)}] + + See Also + ======== + + strong_gens, base, basic_orbits, basic_stabilizers + + """ + + if self._transversals == []: + self.schreier_sims() + return self._transversals + + def composition_series(self): + r""" + Return the composition series for a group as a list + of permutation groups. + + Explanation + =========== + + The composition series for a group `G` is defined as a + subnormal series `G = H_0 > H_1 > H_2 \ldots` A composition + series is a subnormal series such that each factor group + `H(i+1) / H(i)` is simple. + A subnormal series is a composition series only if it is of + maximum length. + + The algorithm works as follows: + Starting with the derived series the idea is to fill + the gap between `G = der[i]` and `H = der[i+1]` for each + `i` independently. Since, all subgroups of the abelian group + `G/H` are normal so, first step is to take the generators + `g` of `G` and add them to generators of `H` one by one. + + The factor groups formed are not simple in general. Each + group is obtained from the previous one by adding one + generator `g`, if the previous group is denoted by `H` + then the next group `K` is generated by `g` and `H`. + The factor group `K/H` is cyclic and it's order is + `K.order()//G.order()`. The series is then extended between + `K` and `H` by groups generated by powers of `g` and `H`. + The series formed is then prepended to the already existing + series. + + Examples + ======== + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics.named_groups import CyclicGroup + >>> S = SymmetricGroup(12) + >>> G = S.sylow_subgroup(2) + >>> C = G.composition_series() + >>> [H.order() for H in C] + [1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1] + >>> G = S.sylow_subgroup(3) + >>> C = G.composition_series() + >>> [H.order() for H in C] + [243, 81, 27, 9, 3, 1] + >>> G = CyclicGroup(12) + >>> C = G.composition_series() + >>> [H.order() for H in C] + [12, 6, 3, 1] + + """ + der = self.derived_series() + if not all(g.is_identity for g in der[-1].generators): + raise NotImplementedError('Group should be solvable') + series = [] + + for i in range(len(der)-1): + H = der[i+1] + up_seg = [] + for g in der[i].generators: + K = PermutationGroup([g] + H.generators) + order = K.order() // H.order() + down_seg = [] + for p, e in factorint(order).items(): + for _ in range(e): + down_seg.append(PermutationGroup([g] + H.generators)) + g = g**p + up_seg = down_seg + up_seg + H = K + up_seg[0] = der[i] + series.extend(up_seg) + series.append(der[-1]) + return series + + def coset_transversal(self, H): + """Return a transversal of the right cosets of self by its subgroup H + using the second method described in [1], Subsection 4.6.7 + + """ + + if not H.is_subgroup(self): + raise ValueError("The argument must be a subgroup") + + if H.order() == 1: + return self.elements + + self._schreier_sims(base=H.base) # make G.base an extension of H.base + + base = self.base + base_ordering = _base_ordering(base, self.degree) + identity = Permutation(self.degree - 1) + + transversals = self.basic_transversals[:] + # transversals is a list of dictionaries. Get rid of the keys + # so that it is a list of lists and sort each list in + # the increasing order of base[l]^x + for l, t in enumerate(transversals): + transversals[l] = sorted(t.values(), + key = lambda x: base_ordering[base[l]^x]) + + orbits = H.basic_orbits + h_stabs = H.basic_stabilizers + g_stabs = self.basic_stabilizers + + indices = [x.order()//y.order() for x, y in zip(g_stabs, h_stabs)] + + # T^(l) should be a right transversal of H^(l) in G^(l) for + # 1<=l<=len(base). While H^(l) is the trivial group, T^(l) + # contains all the elements of G^(l) so we might just as well + # start with l = len(h_stabs)-1 + if len(g_stabs) > len(h_stabs): + T = g_stabs[len(h_stabs)].elements + else: + T = [identity] + l = len(h_stabs)-1 + t_len = len(T) + while l > -1: + T_next = [] + for u in transversals[l]: + if u == identity: + continue + b = base_ordering[base[l]^u] + for t in T: + p = t*u + if all(base_ordering[h^p] >= b for h in orbits[l]): + T_next.append(p) + if t_len + len(T_next) == indices[l]: + break + if t_len + len(T_next) == indices[l]: + break + T += T_next + t_len += len(T_next) + l -= 1 + T.remove(identity) + T = [identity] + T + return T + + def _coset_representative(self, g, H): + """Return the representative of Hg from the transversal that + would be computed by ``self.coset_transversal(H)``. + + """ + if H.order() == 1: + return g + # The base of self must be an extension of H.base. + if not(self.base[:len(H.base)] == H.base): + self._schreier_sims(base=H.base) + orbits = H.basic_orbits[:] + h_transversals = [list(_.values()) for _ in H.basic_transversals] + transversals = [list(_.values()) for _ in self.basic_transversals] + base = self.base + base_ordering = _base_ordering(base, self.degree) + def step(l, x): + gamma = min(orbits[l], key = lambda y: base_ordering[y^x]) + i = [base[l]^h for h in h_transversals[l]].index(gamma) + x = h_transversals[l][i]*x + if l < len(orbits)-1: + for u in transversals[l]: + if base[l]^u == base[l]^x: + break + x = step(l+1, x*u**-1)*u + return x + return step(0, g) + + def coset_table(self, H): + """Return the standardised (right) coset table of self in H as + a list of lists. + """ + # Maybe this should be made to return an instance of CosetTable + # from fp_groups.py but the class would need to be changed first + # to be compatible with PermutationGroups + + if not H.is_subgroup(self): + raise ValueError("The argument must be a subgroup") + T = self.coset_transversal(H) + n = len(T) + + A = list(chain.from_iterable((gen, gen**-1) + for gen in self.generators)) + + table = [] + for i in range(n): + row = [self._coset_representative(T[i]*x, H) for x in A] + row = [T.index(r) for r in row] + table.append(row) + + # standardize (this is the same as the algorithm used in coset_table) + # If CosetTable is made compatible with PermutationGroups, this + # should be replaced by table.standardize() + A = range(len(A)) + gamma = 1 + for alpha, a in product(range(n), A): + beta = table[alpha][a] + if beta >= gamma: + if beta > gamma: + for x in A: + z = table[gamma][x] + table[gamma][x] = table[beta][x] + table[beta][x] = z + for i in range(n): + if table[i][x] == beta: + table[i][x] = gamma + elif table[i][x] == gamma: + table[i][x] = beta + gamma += 1 + if gamma >= n-1: + return table + + def center(self): + r""" + Return the center of a permutation group. + + Explanation + =========== + + The center for a group `G` is defined as + `Z(G) = \{z\in G | \forall g\in G, zg = gz \}`, + the set of elements of `G` that commute with all elements of `G`. + It is equal to the centralizer of `G` inside `G`, and is naturally a + subgroup of `G` ([9]). + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> D = DihedralGroup(4) + >>> G = D.center() + >>> G.order() + 2 + + See Also + ======== + + centralizer + + Notes + ===== + + This is a naive implementation that is a straightforward application + of ``.centralizer()`` + + """ + if not self._center: + self._center = self.centralizer(self) + return self._center + + def centralizer(self, other): + r""" + Return the centralizer of a group/set/element. + + Explanation + =========== + + The centralizer of a set of permutations ``S`` inside + a group ``G`` is the set of elements of ``G`` that commute with all + elements of ``S``:: + + `C_G(S) = \{ g \in G | gs = sg \forall s \in S\}` ([10]) + + Usually, ``S`` is a subset of ``G``, but if ``G`` is a proper subgroup of + the full symmetric group, we allow for ``S`` to have elements outside + ``G``. + + It is naturally a subgroup of ``G``; the centralizer of a permutation + group is equal to the centralizer of any set of generators for that + group, since any element commuting with the generators commutes with + any product of the generators. + + Parameters + ========== + + other + a permutation group/list of permutations/single permutation + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, + ... CyclicGroup) + >>> S = SymmetricGroup(6) + >>> C = CyclicGroup(6) + >>> H = S.centralizer(C) + >>> H.is_subgroup(C) + True + + See Also + ======== + + subgroup_search + + Notes + ===== + + The implementation is an application of ``.subgroup_search()`` with + tests using a specific base for the group ``G``. + + """ + if hasattr(other, 'generators'): + if other.is_trivial or self.is_trivial: + return self + degree = self.degree + identity = _af_new(list(range(degree))) + orbits = other.orbits() + num_orbits = len(orbits) + orbits.sort(key=lambda x: -len(x)) + long_base = [] + orbit_reps = [None]*num_orbits + orbit_reps_indices = [None]*num_orbits + orbit_descr = [None]*degree + for i in range(num_orbits): + orbit = list(orbits[i]) + orbit_reps[i] = orbit[0] + orbit_reps_indices[i] = len(long_base) + for point in orbit: + orbit_descr[point] = i + long_base = long_base + orbit + base, strong_gens = self.schreier_sims_incremental(base=long_base) + strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + i = 0 + for i in range(len(base)): + if strong_gens_distr[i] == [identity]: + break + base = base[:i] + base_len = i + for j in range(num_orbits): + if base[base_len - 1] in orbits[j]: + break + rel_orbits = orbits[: j + 1] + num_rel_orbits = len(rel_orbits) + transversals = [None]*num_rel_orbits + for j in range(num_rel_orbits): + rep = orbit_reps[j] + transversals[j] = dict( + other.orbit_transversal(rep, pairs=True)) + trivial_test = lambda x: True + tests = [None]*base_len + for l in range(base_len): + if base[l] in orbit_reps: + tests[l] = trivial_test + else: + def test(computed_words, l=l): + g = computed_words[l] + rep_orb_index = orbit_descr[base[l]] + rep = orbit_reps[rep_orb_index] + im = g._array_form[base[l]] + im_rep = g._array_form[rep] + tr_el = transversals[rep_orb_index][base[l]] + # using the definition of transversal, + # base[l]^g = rep^(tr_el*g); + # if g belongs to the centralizer, then + # base[l]^g = (rep^g)^tr_el + return im == tr_el._array_form[im_rep] + tests[l] = test + + def prop(g): + return [rmul(g, gen) for gen in other.generators] == \ + [rmul(gen, g) for gen in other.generators] + return self.subgroup_search(prop, base=base, + strong_gens=strong_gens, tests=tests) + elif hasattr(other, '__getitem__'): + gens = list(other) + return self.centralizer(PermutationGroup(gens)) + elif hasattr(other, 'array_form'): + return self.centralizer(PermutationGroup([other])) + + def commutator(self, G, H): + """ + Return the commutator of two subgroups. + + Explanation + =========== + + For a permutation group ``K`` and subgroups ``G``, ``H``, the + commutator of ``G`` and ``H`` is defined as the group generated + by all the commutators `[g, h] = hgh^{-1}g^{-1}` for ``g`` in ``G`` and + ``h`` in ``H``. It is naturally a subgroup of ``K`` ([1], p.27). + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, + ... AlternatingGroup) + >>> S = SymmetricGroup(5) + >>> A = AlternatingGroup(5) + >>> G = S.commutator(S, A) + >>> G.is_subgroup(A) + True + + See Also + ======== + + derived_subgroup + + Notes + ===== + + The commutator of two subgroups `H, G` is equal to the normal closure + of the commutators of all the generators, i.e. `hgh^{-1}g^{-1}` for `h` + a generator of `H` and `g` a generator of `G` ([1], p.28) + + """ + ggens = G.generators + hgens = H.generators + commutators = [] + for ggen in ggens: + for hgen in hgens: + commutator = rmul(hgen, ggen, ~hgen, ~ggen) + if commutator not in commutators: + commutators.append(commutator) + res = self.normal_closure(commutators) + return res + + def coset_factor(self, g, factor_index=False): + """Return ``G``'s (self's) coset factorization of ``g`` + + Explanation + =========== + + If ``g`` is an element of ``G`` then it can be written as the product + of permutations drawn from the Schreier-Sims coset decomposition, + + The permutations returned in ``f`` are those for which + the product gives ``g``: ``g = f[n]*...f[1]*f[0]`` where ``n = len(B)`` + and ``B = G.base``. f[i] is one of the permutations in + ``self._basic_orbits[i]``. + + If factor_index==True, + returns a tuple ``[b[0],..,b[n]]``, where ``b[i]`` + belongs to ``self._basic_orbits[i]`` + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation(0, 1, 3, 7, 6, 4)(2, 5) + >>> b = Permutation(0, 1, 3, 2)(4, 5, 7, 6) + >>> G = PermutationGroup([a, b]) + + Define g: + + >>> g = Permutation(7)(1, 2, 4)(3, 6, 5) + + Confirm that it is an element of G: + + >>> G.contains(g) + True + + Thus, it can be written as a product of factors (up to + 3) drawn from u. See below that a factor from u1 and u2 + and the Identity permutation have been used: + + >>> f = G.coset_factor(g) + >>> f[2]*f[1]*f[0] == g + True + >>> f1 = G.coset_factor(g, True); f1 + [0, 4, 4] + >>> tr = G.basic_transversals + >>> f[0] == tr[0][f1[0]] + True + + If g is not an element of G then [] is returned: + + >>> c = Permutation(5, 6, 7) + >>> G.coset_factor(c) + [] + + See Also + ======== + + sympy.combinatorics.util._strip + + """ + if isinstance(g, (Cycle, Permutation)): + g = g.list() + if len(g) != self._degree: + # this could either adjust the size or return [] immediately + # but we don't choose between the two and just signal a possible + # error + raise ValueError('g should be the same size as permutations of G') + I = list(range(self._degree)) + basic_orbits = self.basic_orbits + transversals = self._transversals + factors = [] + base = self.base + h = g + for i in range(len(base)): + beta = h[base[i]] + if beta == base[i]: + factors.append(beta) + continue + if beta not in basic_orbits[i]: + return [] + u = transversals[i][beta]._array_form + h = _af_rmul(_af_invert(u), h) + factors.append(beta) + if h != I: + return [] + if factor_index: + return factors + tr = self.basic_transversals + factors = [tr[i][factors[i]] for i in range(len(base))] + return factors + + def generator_product(self, g, original=False): + r''' + Return a list of strong generators `[s1, \dots, sn]` + s.t `g = sn \times \dots \times s1`. If ``original=True``, make the + list contain only the original group generators + + ''' + product = [] + if g.is_identity: + return [] + if g in self.strong_gens: + if not original or g in self.generators: + return [g] + else: + slp = self._strong_gens_slp[g] + for s in slp: + product.extend(self.generator_product(s, original=True)) + return product + elif g**-1 in self.strong_gens: + g = g**-1 + if not original or g in self.generators: + return [g**-1] + else: + slp = self._strong_gens_slp[g] + for s in slp: + product.extend(self.generator_product(s, original=True)) + l = len(product) + product = [product[l-i-1]**-1 for i in range(l)] + return product + + f = self.coset_factor(g, True) + for i, j in enumerate(f): + slp = self._transversal_slp[i][j] + for s in slp: + if not original: + product.append(self.strong_gens[s]) + else: + s = self.strong_gens[s] + product.extend(self.generator_product(s, original=True)) + return product + + def coset_rank(self, g): + """rank using Schreier-Sims representation. + + Explanation + =========== + + The coset rank of ``g`` is the ordering number in which + it appears in the lexicographic listing according to the + coset decomposition + + The ordering is the same as in G.generate(method='coset'). + If ``g`` does not belong to the group it returns None. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation(0, 1, 3, 7, 6, 4)(2, 5) + >>> b = Permutation(0, 1, 3, 2)(4, 5, 7, 6) + >>> G = PermutationGroup([a, b]) + >>> c = Permutation(7)(2, 4)(3, 5) + >>> G.coset_rank(c) + 16 + >>> G.coset_unrank(16) + (7)(2 4)(3 5) + + See Also + ======== + + coset_factor + + """ + factors = self.coset_factor(g, True) + if not factors: + return None + rank = 0 + b = 1 + transversals = self._transversals + base = self._base + basic_orbits = self._basic_orbits + for i in range(len(base)): + k = factors[i] + j = basic_orbits[i].index(k) + rank += b*j + b = b*len(transversals[i]) + return rank + + def coset_unrank(self, rank, af=False): + """unrank using Schreier-Sims representation + + coset_unrank is the inverse operation of coset_rank + if 0 <= rank < order; otherwise it returns None. + + """ + if rank < 0 or rank >= self.order(): + return None + base = self.base + transversals = self.basic_transversals + basic_orbits = self.basic_orbits + m = len(base) + v = [0]*m + for i in range(m): + rank, c = divmod(rank, len(transversals[i])) + v[i] = basic_orbits[i][c] + a = [transversals[i][v[i]]._array_form for i in range(m)] + h = _af_rmuln(*a) + if af: + return h + else: + return _af_new(h) + + @property + def degree(self): + """Returns the size of the permutations in the group. + + Explanation + =========== + + The number of permutations comprising the group is given by + ``len(group)``; the number of permutations that can be generated + by the group is given by ``group.order()``. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a]) + >>> G.degree + 3 + >>> len(G) + 1 + >>> G.order() + 2 + >>> list(G.generate()) + [(2), (2)(0 1)] + + See Also + ======== + + order + """ + return self._degree + + @property + def identity(self): + ''' + Return the identity element of the permutation group. + + ''' + return _af_new(list(range(self.degree))) + + @property + def elements(self): + """Returns all the elements of the permutation group as a list + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> p = PermutationGroup(Permutation(1, 3), Permutation(1, 2)) + >>> p.elements + [(3), (3)(1 2), (1 3), (2 3), (1 2 3), (1 3 2)] + + """ + if not self._elements: + self._elements = list(self.generate()) + + return self._elements + + def derived_series(self): + r"""Return the derived series for the group. + + Explanation + =========== + + The derived series for a group `G` is defined as + `G = G_0 > G_1 > G_2 > \ldots` where `G_i = [G_{i-1}, G_{i-1}]`, + i.e. `G_i` is the derived subgroup of `G_{i-1}`, for + `i\in\mathbb{N}`. When we have `G_k = G_{k-1}` for some + `k\in\mathbb{N}`, the series terminates. + + Returns + ======= + + A list of permutation groups containing the members of the derived + series in the order `G = G_0, G_1, G_2, \ldots`. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, + ... AlternatingGroup, DihedralGroup) + >>> A = AlternatingGroup(5) + >>> len(A.derived_series()) + 1 + >>> S = SymmetricGroup(4) + >>> len(S.derived_series()) + 4 + >>> S.derived_series()[1].is_subgroup(AlternatingGroup(4)) + True + >>> S.derived_series()[2].is_subgroup(DihedralGroup(2)) + True + + See Also + ======== + + derived_subgroup + + """ + res = [self] + current = self + nxt = self.derived_subgroup() + while not current.is_subgroup(nxt): + res.append(nxt) + current = nxt + nxt = nxt.derived_subgroup() + return res + + def derived_subgroup(self): + r"""Compute the derived subgroup. + + Explanation + =========== + + The derived subgroup, or commutator subgroup is the subgroup generated + by all commutators `[g, h] = hgh^{-1}g^{-1}` for `g, h\in G` ; it is + equal to the normal closure of the set of commutators of the generators + ([1], p.28, [11]). + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([1, 0, 2, 4, 3]) + >>> b = Permutation([0, 1, 3, 2, 4]) + >>> G = PermutationGroup([a, b]) + >>> C = G.derived_subgroup() + >>> list(C.generate(af=True)) + [[0, 1, 2, 3, 4], [0, 1, 3, 4, 2], [0, 1, 4, 2, 3]] + + See Also + ======== + + derived_series + + """ + r = self._r + gens = [p._array_form for p in self.generators] + set_commutators = set() + degree = self._degree + rng = list(range(degree)) + for i in range(r): + for j in range(r): + p1 = gens[i] + p2 = gens[j] + c = list(range(degree)) + for k in rng: + c[p2[p1[k]]] = p1[p2[k]] + ct = tuple(c) + if ct not in set_commutators: + set_commutators.add(ct) + cms = [_af_new(p) for p in set_commutators] + G2 = self.normal_closure(cms) + return G2 + + def generate(self, method="coset", af=False): + """Return iterator to generate the elements of the group. + + Explanation + =========== + + Iteration is done with one of these methods:: + + method='coset' using the Schreier-Sims coset representation + method='dimino' using the Dimino method + + If ``af = True`` it yields the array form of the permutations + + Examples + ======== + + >>> from sympy.combinatorics import PermutationGroup + >>> from sympy.combinatorics.polyhedron import tetrahedron + + The permutation group given in the tetrahedron object is also + true groups: + + >>> G = tetrahedron.pgroup + >>> G.is_group + True + + Also the group generated by the permutations in the tetrahedron + pgroup -- even the first two -- is a proper group: + + >>> H = PermutationGroup(G[0], G[1]) + >>> J = PermutationGroup(list(H.generate())); J + PermutationGroup([ + (0 1)(2 3), + (1 2 3), + (1 3 2), + (0 3 1), + (0 2 3), + (0 3)(1 2), + (0 1 3), + (3)(0 2 1), + (0 3 2), + (3)(0 1 2), + (0 2)(1 3)]) + >>> _.is_group + True + """ + if method == "coset": + return self.generate_schreier_sims(af) + elif method == "dimino": + return self.generate_dimino(af) + else: + raise NotImplementedError('No generation defined for %s' % method) + + def generate_dimino(self, af=False): + """Yield group elements using Dimino's algorithm. + + If ``af == True`` it yields the array form of the permutations. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1, 3]) + >>> b = Permutation([0, 2, 3, 1]) + >>> g = PermutationGroup([a, b]) + >>> list(g.generate_dimino(af=True)) + [[0, 1, 2, 3], [0, 2, 1, 3], [0, 2, 3, 1], + [0, 1, 3, 2], [0, 3, 2, 1], [0, 3, 1, 2]] + + References + ========== + + .. [1] The Implementation of Various Algorithms for Permutation Groups in + the Computer Algebra System: AXIOM, N.J. Doye, M.Sc. Thesis + + """ + idn = list(range(self.degree)) + order = 0 + element_list = [idn] + set_element_list = {tuple(idn)} + if af: + yield idn + else: + yield _af_new(idn) + gens = [p._array_form for p in self.generators] + + for i in range(len(gens)): + # D elements of the subgroup G_i generated by gens[:i] + D = element_list.copy() + N = [idn] + while N: + A = N + N = [] + for a in A: + for g in gens[:i + 1]: + ag = _af_rmul(a, g) + if tuple(ag) not in set_element_list: + # produce G_i*g + for d in D: + order += 1 + ap = _af_rmul(d, ag) + if af: + yield ap + else: + p = _af_new(ap) + yield p + element_list.append(ap) + set_element_list.add(tuple(ap)) + N.append(ap) + self._order = len(element_list) + + def generate_schreier_sims(self, af=False): + """Yield group elements using the Schreier-Sims representation + in coset_rank order + + If ``af = True`` it yields the array form of the permutations + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1, 3]) + >>> b = Permutation([0, 2, 3, 1]) + >>> g = PermutationGroup([a, b]) + >>> list(g.generate_schreier_sims(af=True)) + [[0, 1, 2, 3], [0, 2, 1, 3], [0, 3, 2, 1], + [0, 1, 3, 2], [0, 2, 3, 1], [0, 3, 1, 2]] + """ + + n = self._degree + u = self.basic_transversals + basic_orbits = self._basic_orbits + if len(u) == 0: + for x in self.generators: + if af: + yield x._array_form + else: + yield x + return + if len(u) == 1: + for i in basic_orbits[0]: + if af: + yield u[0][i]._array_form + else: + yield u[0][i] + return + + u = list(reversed(u)) + basic_orbits = basic_orbits[::-1] + # stg stack of group elements + stg = [list(range(n))] + posmax = [len(x) for x in u] + n1 = len(posmax) - 1 + pos = [0]*n1 + h = 0 + while 1: + # backtrack when finished iterating over coset + if pos[h] >= posmax[h]: + if h == 0: + return + pos[h] = 0 + h -= 1 + stg.pop() + continue + p = _af_rmul(u[h][basic_orbits[h][pos[h]]]._array_form, stg[-1]) + pos[h] += 1 + stg.append(p) + h += 1 + if h == n1: + if af: + for i in basic_orbits[-1]: + p = _af_rmul(u[-1][i]._array_form, stg[-1]) + yield p + else: + for i in basic_orbits[-1]: + p = _af_rmul(u[-1][i]._array_form, stg[-1]) + p1 = _af_new(p) + yield p1 + stg.pop() + h -= 1 + + @property + def generators(self): + """Returns the generators of the group. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1]) + >>> b = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a, b]) + >>> G.generators + [(1 2), (2)(0 1)] + + """ + return self._generators + + def contains(self, g, strict=True): + """Test if permutation ``g`` belong to self, ``G``. + + Explanation + =========== + + If ``g`` is an element of ``G`` it can be written as a product + of factors drawn from the cosets of ``G``'s stabilizers. To see + if ``g`` is one of the actual generators defining the group use + ``G.has(g)``. + + If ``strict`` is not ``True``, ``g`` will be resized, if necessary, + to match the size of permutations in ``self``. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + + >>> a = Permutation(1, 2) + >>> b = Permutation(2, 3, 1) + >>> G = PermutationGroup(a, b, degree=5) + >>> G.contains(G[0]) # trivial check + True + >>> elem = Permutation([[2, 3]], size=5) + >>> G.contains(elem) + True + >>> G.contains(Permutation(4)(0, 1, 2, 3)) + False + + If strict is False, a permutation will be resized, if + necessary: + + >>> H = PermutationGroup(Permutation(5)) + >>> H.contains(Permutation(3)) + False + >>> H.contains(Permutation(3), strict=False) + True + + To test if a given permutation is present in the group: + + >>> elem in G.generators + False + >>> G.has(elem) + False + + See Also + ======== + + coset_factor, sympy.core.basic.Basic.has, __contains__ + + """ + if not isinstance(g, Permutation): + return False + if g.size != self.degree: + if strict: + return False + g = Permutation(g, size=self.degree) + if g in self.generators: + return True + return bool(self.coset_factor(g.array_form, True)) + + @property + def is_perfect(self): + """Return ``True`` if the group is perfect. + A group is perfect if it equals to its derived subgroup. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation(1,2,3)(4,5) + >>> b = Permutation(1,2,3,4,5) + >>> G = PermutationGroup([a, b]) + >>> G.is_perfect + False + + """ + if self._is_perfect is None: + self._is_perfect = self.equals(self.derived_subgroup()) + return self._is_perfect + + @property + def is_abelian(self): + """Test if the group is Abelian. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1]) + >>> b = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a, b]) + >>> G.is_abelian + False + >>> a = Permutation([0, 2, 1]) + >>> G = PermutationGroup([a]) + >>> G.is_abelian + True + + """ + if self._is_abelian is not None: + return self._is_abelian + + self._is_abelian = True + gens = [p._array_form for p in self.generators] + for x in gens: + for y in gens: + if y <= x: + continue + if not _af_commutes_with(x, y): + self._is_abelian = False + return False + return True + + def abelian_invariants(self): + """ + Returns the abelian invariants for the given group. + Let ``G`` be a nontrivial finite abelian group. Then G is isomorphic to + the direct product of finitely many nontrivial cyclic groups of + prime-power order. + + Explanation + =========== + + The prime-powers that occur as the orders of the factors are uniquely + determined by G. More precisely, the primes that occur in the orders of the + factors in any such decomposition of ``G`` are exactly the primes that divide + ``|G|`` and for any such prime ``p``, if the orders of the factors that are + p-groups in one such decomposition of ``G`` are ``p^{t_1} >= p^{t_2} >= ... p^{t_r}``, + then the orders of the factors that are p-groups in any such decomposition of ``G`` + are ``p^{t_1} >= p^{t_2} >= ... p^{t_r}``. + + The uniquely determined integers ``p^{t_1} >= p^{t_2} >= ... p^{t_r}``, taken + for all primes that divide ``|G|`` are called the invariants of the nontrivial + group ``G`` as suggested in ([14], p. 542). + + Notes + ===== + + We adopt the convention that the invariants of a trivial group are []. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1]) + >>> b = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a, b]) + >>> G.abelian_invariants() + [2] + >>> from sympy.combinatorics import CyclicGroup + >>> G = CyclicGroup(7) + >>> G.abelian_invariants() + [7] + + """ + if self.is_trivial: + return [] + gns = self.generators + inv = [] + G = self + H = G.derived_subgroup() + Hgens = H.generators + for p in primefactors(G.order()): + ranks = [] + while True: + pows = [] + for g in gns: + elm = g**p + if not H.contains(elm): + pows.append(elm) + K = PermutationGroup(Hgens + pows) if pows else H + r = G.order()//K.order() + G = K + gns = pows + if r == 1: + break + ranks.append(multiplicity(p, r)) + + if ranks: + pows = [1]*ranks[0] + for i in ranks: + for j in range(i): + pows[j] = pows[j]*p + inv.extend(pows) + inv.sort() + return inv + + def is_elementary(self, p): + """Return ``True`` if the group is elementary abelian. An elementary + abelian group is a finite abelian group, where every nontrivial + element has order `p`, where `p` is a prime. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1]) + >>> G = PermutationGroup([a]) + >>> G.is_elementary(2) + True + >>> a = Permutation([0, 2, 1, 3]) + >>> b = Permutation([3, 1, 2, 0]) + >>> G = PermutationGroup([a, b]) + >>> G.is_elementary(2) + True + >>> G.is_elementary(3) + False + + """ + return self.is_abelian and all(g.order() == p for g in self.generators) + + def _eval_is_alt_sym_naive(self, only_sym=False, only_alt=False): + """A naive test using the group order.""" + if only_sym and only_alt: + raise ValueError( + "Both {} and {} cannot be set to True" + .format(only_sym, only_alt)) + + n = self.degree + sym_order = _factorial(n) + order = self.order() + + if order == sym_order: + self._is_sym = True + self._is_alt = False + return not only_alt + + if 2*order == sym_order: + self._is_sym = False + self._is_alt = True + return not only_sym + + return False + + def _eval_is_alt_sym_monte_carlo(self, eps=0.05, perms=None): + """A test using monte-carlo algorithm. + + Parameters + ========== + + eps : float, optional + The criterion for the incorrect ``False`` return. + + perms : list[Permutation], optional + If explicitly given, it tests over the given candidates + for testing. + + If ``None``, it randomly computes ``N_eps`` and chooses + ``N_eps`` sample of the permutation from the group. + + See Also + ======== + + _check_cycles_alt_sym + """ + if perms is None: + n = self.degree + if n < 17: + c_n = 0.34 + else: + c_n = 0.57 + d_n = (c_n*log(2))/log(n) + N_eps = int(-log(eps)/d_n) + + perms = (self.random_pr() for i in range(N_eps)) + return self._eval_is_alt_sym_monte_carlo(perms=perms) + + for perm in perms: + if _check_cycles_alt_sym(perm): + return True + return False + + def is_alt_sym(self, eps=0.05, _random_prec=None): + r"""Monte Carlo test for the symmetric/alternating group for degrees + >= 8. + + Explanation + =========== + + More specifically, it is one-sided Monte Carlo with the + answer True (i.e., G is symmetric/alternating) guaranteed to be + correct, and the answer False being incorrect with probability eps. + + For degree < 8, the order of the group is checked so the test + is deterministic. + + Notes + ===== + + The algorithm itself uses some nontrivial results from group theory and + number theory: + 1) If a transitive group ``G`` of degree ``n`` contains an element + with a cycle of length ``n/2 < p < n-2`` for ``p`` a prime, ``G`` is the + symmetric or alternating group ([1], pp. 81-82) + 2) The proportion of elements in the symmetric/alternating group having + the property described in 1) is approximately `\log(2)/\log(n)` + ([1], p.82; [2], pp. 226-227). + The helper function ``_check_cycles_alt_sym`` is used to + go over the cycles in a permutation and look for ones satisfying 1). + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> D = DihedralGroup(10) + >>> D.is_alt_sym() + False + + See Also + ======== + + _check_cycles_alt_sym + + """ + if _random_prec is not None: + N_eps = _random_prec['N_eps'] + perms= (_random_prec[i] for i in range(N_eps)) + return self._eval_is_alt_sym_monte_carlo(perms=perms) + + if self._is_sym or self._is_alt: + return True + if self._is_sym is False and self._is_alt is False: + return False + + n = self.degree + if n < 8: + return self._eval_is_alt_sym_naive() + elif self.is_transitive(): + return self._eval_is_alt_sym_monte_carlo(eps=eps) + + self._is_sym, self._is_alt = False, False + return False + + @property + def is_nilpotent(self): + """Test if the group is nilpotent. + + Explanation + =========== + + A group `G` is nilpotent if it has a central series of finite length. + Alternatively, `G` is nilpotent if its lower central series terminates + with the trivial group. Every nilpotent group is also solvable + ([1], p.29, [12]). + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, + ... CyclicGroup) + >>> C = CyclicGroup(6) + >>> C.is_nilpotent + True + >>> S = SymmetricGroup(5) + >>> S.is_nilpotent + False + + See Also + ======== + + lower_central_series, is_solvable + + """ + if self._is_nilpotent is None: + lcs = self.lower_central_series() + terminator = lcs[len(lcs) - 1] + gens = terminator.generators + degree = self.degree + identity = _af_new(list(range(degree))) + if all(g == identity for g in gens): + self._is_solvable = True + self._is_nilpotent = True + return True + else: + self._is_nilpotent = False + return False + else: + return self._is_nilpotent + + def is_normal(self, gr, strict=True): + """Test if ``G=self`` is a normal subgroup of ``gr``. + + Explanation + =========== + + G is normal in gr if + for each g2 in G, g1 in gr, ``g = g1*g2*g1**-1`` belongs to G + It is sufficient to check this for each g1 in gr.generators and + g2 in G.generators. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([1, 2, 0]) + >>> b = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a, b]) + >>> G1 = PermutationGroup([a, Permutation([2, 0, 1])]) + >>> G1.is_normal(G) + True + + """ + if not self.is_subgroup(gr, strict=strict): + return False + d_self = self.degree + d_gr = gr.degree + if self.is_trivial and (d_self == d_gr or not strict): + return True + if self._is_abelian: + return True + new_self = self.copy() + if not strict and d_self != d_gr: + if d_self < d_gr: + new_self = PermGroup(new_self.generators + [Permutation(d_gr - 1)]) + else: + gr = PermGroup(gr.generators + [Permutation(d_self - 1)]) + gens2 = [p._array_form for p in new_self.generators] + gens1 = [p._array_form for p in gr.generators] + for g1 in gens1: + for g2 in gens2: + p = _af_rmuln(g1, g2, _af_invert(g1)) + if not new_self.coset_factor(p, True): + return False + return True + + def is_primitive(self, randomized=True): + r"""Test if a group is primitive. + + Explanation + =========== + + A permutation group ``G`` acting on a set ``S`` is called primitive if + ``S`` contains no nontrivial block under the action of ``G`` + (a block is nontrivial if its cardinality is more than ``1``). + + Notes + ===== + + The algorithm is described in [1], p.83, and uses the function + minimal_block to search for blocks of the form `\{0, k\}` for ``k`` + ranging over representatives for the orbits of `G_0`, the stabilizer of + ``0``. This algorithm has complexity `O(n^2)` where ``n`` is the degree + of the group, and will perform badly if `G_0` is small. + + There are two implementations offered: one finds `G_0` + deterministically using the function ``stabilizer``, and the other + (default) produces random elements of `G_0` using ``random_stab``, + hoping that they generate a subgroup of `G_0` with not too many more + orbits than `G_0` (this is suggested in [1], p.83). Behavior is changed + by the ``randomized`` flag. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> D = DihedralGroup(10) + >>> D.is_primitive() + False + + See Also + ======== + + minimal_block, random_stab + + """ + if self._is_primitive is not None: + return self._is_primitive + + if self.is_transitive() is False: + return False + + if randomized: + random_stab_gens = [] + v = self.schreier_vector(0) + for _ in range(len(self)): + random_stab_gens.append(self.random_stab(0, v)) + stab = PermutationGroup(random_stab_gens) + else: + stab = self.stabilizer(0) + orbits = stab.orbits() + for orb in orbits: + x = orb.pop() + if x != 0 and any(e != 0 for e in self.minimal_block([0, x])): + self._is_primitive = False + return False + self._is_primitive = True + return True + + def minimal_blocks(self, randomized=True): + ''' + For a transitive group, return the list of all minimal + block systems. If a group is intransitive, return `False`. + + Examples + ======== + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> DihedralGroup(6).minimal_blocks() + [[0, 1, 0, 1, 0, 1], [0, 1, 2, 0, 1, 2]] + >>> G = PermutationGroup(Permutation(1,2,5)) + >>> G.minimal_blocks() + False + + See Also + ======== + + minimal_block, is_transitive, is_primitive + + ''' + def _number_blocks(blocks): + # number the blocks of a block system + # in order and return the number of + # blocks and the tuple with the + # reordering + n = len(blocks) + appeared = {} + m = 0 + b = [None]*n + for i in range(n): + if blocks[i] not in appeared: + appeared[blocks[i]] = m + b[i] = m + m += 1 + else: + b[i] = appeared[blocks[i]] + return tuple(b), m + + if not self.is_transitive(): + return False + blocks = [] + num_blocks = [] + rep_blocks = [] + if randomized: + random_stab_gens = [] + v = self.schreier_vector(0) + for i in range(len(self)): + random_stab_gens.append(self.random_stab(0, v)) + stab = PermutationGroup(random_stab_gens) + else: + stab = self.stabilizer(0) + orbits = stab.orbits() + for orb in orbits: + x = orb.pop() + if x != 0: + block = self.minimal_block([0, x]) + num_block, _ = _number_blocks(block) + # a representative block (containing 0) + rep = {j for j in range(self.degree) if num_block[j] == 0} + # check if the system is minimal with + # respect to the already discovere ones + minimal = True + blocks_remove_mask = [False] * len(blocks) + for i, r in enumerate(rep_blocks): + if len(r) > len(rep) and rep.issubset(r): + # i-th block system is not minimal + blocks_remove_mask[i] = True + elif len(r) < len(rep) and r.issubset(rep): + # the system being checked is not minimal + minimal = False + break + # remove non-minimal representative blocks + blocks = [b for i, b in enumerate(blocks) if not blocks_remove_mask[i]] + num_blocks = [n for i, n in enumerate(num_blocks) if not blocks_remove_mask[i]] + rep_blocks = [r for i, r in enumerate(rep_blocks) if not blocks_remove_mask[i]] + + if minimal and num_block not in num_blocks: + blocks.append(block) + num_blocks.append(num_block) + rep_blocks.append(rep) + return blocks + + @property + def is_solvable(self): + """Test if the group is solvable. + + ``G`` is solvable if its derived series terminates with the trivial + group ([1], p.29). + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> S = SymmetricGroup(3) + >>> S.is_solvable + True + + See Also + ======== + + is_nilpotent, derived_series + + """ + if self._is_solvable is None: + if self.order() % 2 != 0: + return True + ds = self.derived_series() + terminator = ds[len(ds) - 1] + gens = terminator.generators + degree = self.degree + identity = _af_new(list(range(degree))) + if all(g == identity for g in gens): + self._is_solvable = True + return True + else: + self._is_solvable = False + return False + else: + return self._is_solvable + + def is_subgroup(self, G, strict=True): + """Return ``True`` if all elements of ``self`` belong to ``G``. + + If ``strict`` is ``False`` then if ``self``'s degree is smaller + than ``G``'s, the elements will be resized to have the same degree. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> from sympy.combinatorics import SymmetricGroup, CyclicGroup + + Testing is strict by default: the degree of each group must be the + same: + + >>> p = Permutation(0, 1, 2, 3, 4, 5) + >>> G1 = PermutationGroup([Permutation(0, 1, 2), Permutation(0, 1)]) + >>> G2 = PermutationGroup([Permutation(0, 2), Permutation(0, 1, 2)]) + >>> G3 = PermutationGroup([p, p**2]) + >>> assert G1.order() == G2.order() == G3.order() == 6 + >>> G1.is_subgroup(G2) + True + >>> G1.is_subgroup(G3) + False + >>> G3.is_subgroup(PermutationGroup(G3[1])) + False + >>> G3.is_subgroup(PermutationGroup(G3[0])) + True + + To ignore the size, set ``strict`` to ``False``: + + >>> S3 = SymmetricGroup(3) + >>> S5 = SymmetricGroup(5) + >>> S3.is_subgroup(S5, strict=False) + True + >>> C7 = CyclicGroup(7) + >>> G = S5*C7 + >>> S5.is_subgroup(G, False) + True + >>> C7.is_subgroup(G, 0) + False + + """ + if isinstance(G, SymmetricPermutationGroup): + if self.degree != G.degree: + return False + return True + if not isinstance(G, PermutationGroup): + return False + if self == G or self.generators[0]==Permutation(): + return True + if G.order() % self.order() != 0: + return False + if self.degree == G.degree or \ + (self.degree < G.degree and not strict): + gens = self.generators + else: + return False + return all(G.contains(g, strict=strict) for g in gens) + + @property + def is_polycyclic(self): + """Return ``True`` if a group is polycyclic. A group is polycyclic if + it has a subnormal series with cyclic factors. For finite groups, + this is the same as if the group is solvable. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1, 3]) + >>> b = Permutation([2, 0, 1, 3]) + >>> G = PermutationGroup([a, b]) + >>> G.is_polycyclic + True + + """ + return self.is_solvable + + def is_transitive(self, strict=True): + """Test if the group is transitive. + + Explanation + =========== + + A group is transitive if it has a single orbit. + + If ``strict`` is ``False`` the group is transitive if it has + a single orbit of length different from 1. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1, 3]) + >>> b = Permutation([2, 0, 1, 3]) + >>> G1 = PermutationGroup([a, b]) + >>> G1.is_transitive() + False + >>> G1.is_transitive(strict=False) + True + >>> c = Permutation([2, 3, 0, 1]) + >>> G2 = PermutationGroup([a, c]) + >>> G2.is_transitive() + True + >>> d = Permutation([1, 0, 2, 3]) + >>> e = Permutation([0, 1, 3, 2]) + >>> G3 = PermutationGroup([d, e]) + >>> G3.is_transitive() or G3.is_transitive(strict=False) + False + + """ + if self._is_transitive: # strict or not, if True then True + return self._is_transitive + if strict: + if self._is_transitive is not None: # we only store strict=True + return self._is_transitive + + ans = len(self.orbit(0)) == self.degree + self._is_transitive = ans + return ans + + got_orb = False + for x in self.orbits(): + if len(x) > 1: + if got_orb: + return False + got_orb = True + return got_orb + + @property + def is_trivial(self): + """Test if the group is the trivial group. + + This is true if the group contains only the identity permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> G = PermutationGroup([Permutation([0, 1, 2])]) + >>> G.is_trivial + True + + """ + if self._is_trivial is None: + self._is_trivial = len(self) == 1 and self[0].is_Identity + return self._is_trivial + + def lower_central_series(self): + r"""Return the lower central series for the group. + + The lower central series for a group `G` is the series + `G = G_0 > G_1 > G_2 > \ldots` where + `G_k = [G, G_{k-1}]`, i.e. every term after the first is equal to the + commutator of `G` and the previous term in `G1` ([1], p.29). + + Returns + ======= + + A list of permutation groups in the order `G = G_0, G_1, G_2, \ldots` + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (AlternatingGroup, + ... DihedralGroup) + >>> A = AlternatingGroup(4) + >>> len(A.lower_central_series()) + 2 + >>> A.lower_central_series()[1].is_subgroup(DihedralGroup(2)) + True + + See Also + ======== + + commutator, derived_series + + """ + res = [self] + current = self + nxt = self.commutator(self, current) + while not current.is_subgroup(nxt): + res.append(nxt) + current = nxt + nxt = self.commutator(self, current) + return res + + @property + def max_div(self): + """Maximum proper divisor of the degree of a permutation group. + + Explanation + =========== + + Obviously, this is the degree divided by its minimal proper divisor + (larger than ``1``, if one exists). As it is guaranteed to be prime, + the ``sieve`` from ``sympy.ntheory`` is used. + This function is also used as an optimization tool for the functions + ``minimal_block`` and ``_union_find_merge``. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> G = PermutationGroup([Permutation([0, 2, 1, 3])]) + >>> G.max_div + 2 + + See Also + ======== + + minimal_block, _union_find_merge + + """ + if self._max_div is not None: + return self._max_div + n = self.degree + if n == 1: + return 1 + for x in sieve: + if n % x == 0: + d = n//x + self._max_div = d + return d + + def minimal_block(self, points): + r"""For a transitive group, finds the block system generated by + ``points``. + + Explanation + =========== + + If a group ``G`` acts on a set ``S``, a nonempty subset ``B`` of ``S`` + is called a block under the action of ``G`` if for all ``g`` in ``G`` + we have ``gB = B`` (``g`` fixes ``B``) or ``gB`` and ``B`` have no + common points (``g`` moves ``B`` entirely). ([1], p.23; [6]). + + The distinct translates ``gB`` of a block ``B`` for ``g`` in ``G`` + partition the set ``S`` and this set of translates is known as a block + system. Moreover, we obviously have that all blocks in the partition + have the same size, hence the block size divides ``|S|`` ([1], p.23). + A ``G``-congruence is an equivalence relation ``~`` on the set ``S`` + such that ``a ~ b`` implies ``g(a) ~ g(b)`` for all ``g`` in ``G``. + For a transitive group, the equivalence classes of a ``G``-congruence + and the blocks of a block system are the same thing ([1], p.23). + + The algorithm below checks the group for transitivity, and then finds + the ``G``-congruence generated by the pairs ``(p_0, p_1), (p_0, p_2), + ..., (p_0,p_{k-1})`` which is the same as finding the maximal block + system (i.e., the one with minimum block size) such that + ``p_0, ..., p_{k-1}`` are in the same block ([1], p.83). + + It is an implementation of Atkinson's algorithm, as suggested in [1], + and manipulates an equivalence relation on the set ``S`` using a + union-find data structure. The running time is just above + `O(|points||S|)`. ([1], pp. 83-87; [7]). + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> D = DihedralGroup(10) + >>> D.minimal_block([0, 5]) + [0, 1, 2, 3, 4, 0, 1, 2, 3, 4] + >>> D.minimal_block([0, 1]) + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + + See Also + ======== + + _union_find_rep, _union_find_merge, is_transitive, is_primitive + + """ + if not self.is_transitive(): + return False + n = self.degree + gens = self.generators + # initialize the list of equivalence class representatives + parents = list(range(n)) + ranks = [1]*n + not_rep = [] + k = len(points) + # the block size must divide the degree of the group + if k > self.max_div: + return [0]*n + for i in range(k - 1): + parents[points[i + 1]] = points[0] + not_rep.append(points[i + 1]) + ranks[points[0]] = k + i = 0 + len_not_rep = k - 1 + while i < len_not_rep: + gamma = not_rep[i] + i += 1 + for gen in gens: + # find has side effects: performs path compression on the list + # of representatives + delta = self._union_find_rep(gamma, parents) + # union has side effects: performs union by rank on the list + # of representatives + temp = self._union_find_merge(gen(gamma), gen(delta), ranks, + parents, not_rep) + if temp == -1: + return [0]*n + len_not_rep += temp + for i in range(n): + # force path compression to get the final state of the equivalence + # relation + self._union_find_rep(i, parents) + + # rewrite result so that block representatives are minimal + new_reps = {} + return [new_reps.setdefault(r, i) for i, r in enumerate(parents)] + + def conjugacy_class(self, x): + r"""Return the conjugacy class of an element in the group. + + Explanation + =========== + + The conjugacy class of an element ``g`` in a group ``G`` is the set of + elements ``x`` in ``G`` that are conjugate with ``g``, i.e. for which + + ``g = xax^{-1}`` + + for some ``a`` in ``G``. + + Note that conjugacy is an equivalence relation, and therefore that + conjugacy classes are partitions of ``G``. For a list of all the + conjugacy classes of the group, use the conjugacy_classes() method. + + In a permutation group, each conjugacy class corresponds to a particular + `cycle structure': for example, in ``S_3``, the conjugacy classes are: + + * the identity class, ``{()}`` + * all transpositions, ``{(1 2), (1 3), (2 3)}`` + * all 3-cycles, ``{(1 2 3), (1 3 2)}`` + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, SymmetricGroup + >>> S3 = SymmetricGroup(3) + >>> S3.conjugacy_class(Permutation(0, 1, 2)) + {(0 1 2), (0 2 1)} + + Notes + ===== + + This procedure computes the conjugacy class directly by finding the + orbit of the element under conjugation in G. This algorithm is only + feasible for permutation groups of relatively small order, but is like + the orbit() function itself in that respect. + """ + # Ref: "Computing the conjugacy classes of finite groups"; Butler, G. + # Groups '93 Galway/St Andrews; edited by Campbell, C. M. + new_class = {x} + last_iteration = new_class + + while len(last_iteration) > 0: + this_iteration = set() + + for y in last_iteration: + for s in self.generators: + conjugated = s * y * (~s) + if conjugated not in new_class: + this_iteration.add(conjugated) + + new_class.update(last_iteration) + last_iteration = this_iteration + + return new_class + + + def conjugacy_classes(self): + r"""Return the conjugacy classes of the group. + + Explanation + =========== + + As described in the documentation for the .conjugacy_class() function, + conjugacy is an equivalence relation on a group G which partitions the + set of elements. This method returns a list of all these conjugacy + classes of G. + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricGroup + >>> SymmetricGroup(3).conjugacy_classes() + [{(2)}, {(0 1 2), (0 2 1)}, {(0 2), (1 2), (2)(0 1)}] + + """ + identity = _af_new(list(range(self.degree))) + known_elements = {identity} + classes = [known_elements.copy()] + + for x in self.generate(): + if x not in known_elements: + new_class = self.conjugacy_class(x) + classes.append(new_class) + known_elements.update(new_class) + + return classes + + def normal_closure(self, other, k=10): + r"""Return the normal closure of a subgroup/set of permutations. + + Explanation + =========== + + If ``S`` is a subset of a group ``G``, the normal closure of ``A`` in ``G`` + is defined as the intersection of all normal subgroups of ``G`` that + contain ``A`` ([1], p.14). Alternatively, it is the group generated by + the conjugates ``x^{-1}yx`` for ``x`` a generator of ``G`` and ``y`` a + generator of the subgroup ``\left\langle S\right\rangle`` generated by + ``S`` (for some chosen generating set for ``\left\langle S\right\rangle``) + ([1], p.73). + + Parameters + ========== + + other + a subgroup/list of permutations/single permutation + k + an implementation-specific parameter that determines the number + of conjugates that are adjoined to ``other`` at once + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, + ... CyclicGroup, AlternatingGroup) + >>> S = SymmetricGroup(5) + >>> C = CyclicGroup(5) + >>> G = S.normal_closure(C) + >>> G.order() + 60 + >>> G.is_subgroup(AlternatingGroup(5)) + True + + See Also + ======== + + commutator, derived_subgroup, random_pr + + Notes + ===== + + The algorithm is described in [1], pp. 73-74; it makes use of the + generation of random elements for permutation groups by the product + replacement algorithm. + + """ + if hasattr(other, 'generators'): + degree = self.degree + identity = _af_new(list(range(degree))) + + if all(g == identity for g in other.generators): + return other + Z = PermutationGroup(other.generators[:]) + base, strong_gens = Z.schreier_sims_incremental() + strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + basic_orbits, basic_transversals = \ + _orbits_transversals_from_bsgs(base, strong_gens_distr) + + self._random_pr_init(r=10, n=20) + + _loop = True + while _loop: + Z._random_pr_init(r=10, n=10) + for _ in range(k): + g = self.random_pr() + h = Z.random_pr() + conj = h^g + res = _strip(conj, base, basic_orbits, basic_transversals) + if res[0] != identity or res[1] != len(base) + 1: + gens = Z.generators + gens.append(conj) + Z = PermutationGroup(gens) + strong_gens.append(conj) + temp_base, temp_strong_gens = \ + Z.schreier_sims_incremental(base, strong_gens) + base, strong_gens = temp_base, temp_strong_gens + strong_gens_distr = \ + _distribute_gens_by_base(base, strong_gens) + basic_orbits, basic_transversals = \ + _orbits_transversals_from_bsgs(base, + strong_gens_distr) + _loop = False + for g in self.generators: + for h in Z.generators: + conj = h^g + res = _strip(conj, base, basic_orbits, + basic_transversals) + if res[0] != identity or res[1] != len(base) + 1: + _loop = True + break + if _loop: + break + return Z + elif hasattr(other, '__getitem__'): + return self.normal_closure(PermutationGroup(other)) + elif hasattr(other, 'array_form'): + return self.normal_closure(PermutationGroup([other])) + + def orbit(self, alpha, action='tuples'): + r"""Compute the orbit of alpha `\{g(\alpha) | g \in G\}` as a set. + + Explanation + =========== + + The time complexity of the algorithm used here is `O(|Orb|*r)` where + `|Orb|` is the size of the orbit and ``r`` is the number of generators of + the group. For a more detailed analysis, see [1], p.78, [2], pp. 19-21. + Here alpha can be a single point, or a list of points. + + If alpha is a single point, the ordinary orbit is computed. + if alpha is a list of points, there are three available options: + + 'union' - computes the union of the orbits of the points in the list + 'tuples' - computes the orbit of the list interpreted as an ordered + tuple under the group action ( i.e., g((1,2,3)) = (g(1), g(2), g(3)) ) + 'sets' - computes the orbit of the list interpreted as a sets + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([1, 2, 0, 4, 5, 6, 3]) + >>> G = PermutationGroup([a]) + >>> G.orbit(0) + {0, 1, 2} + >>> G.orbit([0, 4], 'union') + {0, 1, 2, 3, 4, 5, 6} + + See Also + ======== + + orbit_transversal + + """ + return _orbit(self.degree, self.generators, alpha, action) + + def orbit_rep(self, alpha, beta, schreier_vector=None): + """Return a group element which sends ``alpha`` to ``beta``. + + Explanation + =========== + + If ``beta`` is not in the orbit of ``alpha``, the function returns + ``False``. This implementation makes use of the schreier vector. + For a proof of correctness, see [1], p.80 + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import AlternatingGroup + >>> G = AlternatingGroup(5) + >>> G.orbit_rep(0, 4) + (0 4 1 2 3) + + See Also + ======== + + schreier_vector + + """ + if schreier_vector is None: + schreier_vector = self.schreier_vector(alpha) + if schreier_vector[beta] is None: + return False + k = schreier_vector[beta] + gens = [x._array_form for x in self.generators] + a = [] + while k != -1: + a.append(gens[k]) + beta = gens[k].index(beta) # beta = (~gens[k])(beta) + k = schreier_vector[beta] + if a: + return _af_new(_af_rmuln(*a)) + else: + return _af_new(list(range(self._degree))) + + def orbit_transversal(self, alpha, pairs=False): + r"""Computes a transversal for the orbit of ``alpha`` as a set. + + Explanation + =========== + + For a permutation group `G`, a transversal for the orbit + `Orb = \{g(\alpha) | g \in G\}` is a set + `\{g_\beta | g_\beta(\alpha) = \beta\}` for `\beta \in Orb`. + Note that there may be more than one possible transversal. + If ``pairs`` is set to ``True``, it returns the list of pairs + `(\beta, g_\beta)`. For a proof of correctness, see [1], p.79 + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> G = DihedralGroup(6) + >>> G.orbit_transversal(0) + [(5), (0 1 2 3 4 5), (0 5)(1 4)(2 3), (0 2 4)(1 3 5), (5)(0 4)(1 3), (0 3)(1 4)(2 5)] + + See Also + ======== + + orbit + + """ + return _orbit_transversal(self._degree, self.generators, alpha, pairs) + + def orbits(self, rep=False): + """Return the orbits of ``self``, ordered according to lowest element + in each orbit. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation(1, 5)(2, 3)(4, 0, 6) + >>> b = Permutation(1, 5)(3, 4)(2, 6, 0) + >>> G = PermutationGroup([a, b]) + >>> G.orbits() + [{0, 2, 3, 4, 6}, {1, 5}] + """ + return _orbits(self._degree, self._generators) + + def order(self): + """Return the order of the group: the number of permutations that + can be generated from elements of the group. + + The number of permutations comprising the group is given by + ``len(group)``; the length of each permutation in the group is + given by ``group.size``. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + + >>> a = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a]) + >>> G.degree + 3 + >>> len(G) + 1 + >>> G.order() + 2 + >>> list(G.generate()) + [(2), (2)(0 1)] + + >>> a = Permutation([0, 2, 1]) + >>> b = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a, b]) + >>> G.order() + 6 + + See Also + ======== + + degree + + """ + if self._order is not None: + return self._order + if self._is_sym: + n = self._degree + self._order = factorial(n) + return self._order + if self._is_alt: + n = self._degree + self._order = factorial(n)/2 + return self._order + + m = prod([len(x) for x in self.basic_transversals]) + self._order = m + return m + + def index(self, H): + """ + Returns the index of a permutation group. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation(1,2,3) + >>> b =Permutation(3) + >>> G = PermutationGroup([a]) + >>> H = PermutationGroup([b]) + >>> G.index(H) + 3 + + """ + if H.is_subgroup(self): + return self.order()//H.order() + + @property + def is_symmetric(self): + """Return ``True`` if the group is symmetric. + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricGroup + >>> g = SymmetricGroup(5) + >>> g.is_symmetric + True + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> g = PermutationGroup( + ... Permutation(0, 1, 2, 3, 4), + ... Permutation(2, 3)) + >>> g.is_symmetric + True + + Notes + ===== + + This uses a naive test involving the computation of the full + group order. + If you need more quicker taxonomy for large groups, you can use + :meth:`PermutationGroup.is_alt_sym`. + However, :meth:`PermutationGroup.is_alt_sym` may not be accurate + and is not able to distinguish between an alternating group and + a symmetric group. + + See Also + ======== + + is_alt_sym + """ + _is_sym = self._is_sym + if _is_sym is not None: + return _is_sym + + n = self.degree + if n >= 8: + if self.is_transitive(): + _is_alt_sym = self._eval_is_alt_sym_monte_carlo() + if _is_alt_sym: + if any(g.is_odd for g in self.generators): + self._is_sym, self._is_alt = True, False + return True + + self._is_sym, self._is_alt = False, True + return False + + return self._eval_is_alt_sym_naive(only_sym=True) + + self._is_sym, self._is_alt = False, False + return False + + return self._eval_is_alt_sym_naive(only_sym=True) + + + @property + def is_alternating(self): + """Return ``True`` if the group is alternating. + + Examples + ======== + + >>> from sympy.combinatorics import AlternatingGroup + >>> g = AlternatingGroup(5) + >>> g.is_alternating + True + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> g = PermutationGroup( + ... Permutation(0, 1, 2, 3, 4), + ... Permutation(2, 3, 4)) + >>> g.is_alternating + True + + Notes + ===== + + This uses a naive test involving the computation of the full + group order. + If you need more quicker taxonomy for large groups, you can use + :meth:`PermutationGroup.is_alt_sym`. + However, :meth:`PermutationGroup.is_alt_sym` may not be accurate + and is not able to distinguish between an alternating group and + a symmetric group. + + See Also + ======== + + is_alt_sym + """ + _is_alt = self._is_alt + if _is_alt is not None: + return _is_alt + + n = self.degree + if n >= 8: + if self.is_transitive(): + _is_alt_sym = self._eval_is_alt_sym_monte_carlo() + if _is_alt_sym: + if all(g.is_even for g in self.generators): + self._is_sym, self._is_alt = False, True + return True + + self._is_sym, self._is_alt = True, False + return False + + return self._eval_is_alt_sym_naive(only_alt=True) + + self._is_sym, self._is_alt = False, False + return False + + return self._eval_is_alt_sym_naive(only_alt=True) + + @classmethod + def _distinct_primes_lemma(cls, primes): + """Subroutine to test if there is only one cyclic group for the + order.""" + primes = sorted(primes) + l = len(primes) + for i in range(l): + for j in range(i+1, l): + if primes[j] % primes[i] == 1: + return None + return True + + @property + def is_cyclic(self): + r""" + Return ``True`` if the group is Cyclic. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import AbelianGroup + >>> G = AbelianGroup(3, 4) + >>> G.is_cyclic + True + >>> G = AbelianGroup(4, 4) + >>> G.is_cyclic + False + + Notes + ===== + + If the order of a group $n$ can be factored into the distinct + primes $p_1, p_2, \dots , p_s$ and if + + .. math:: + \forall i, j \in \{1, 2, \dots, s \}: + p_i \not \equiv 1 \pmod {p_j} + + holds true, there is only one group of the order $n$ which + is a cyclic group [1]_. This is a generalization of the lemma + that the group of order $15, 35, \dots$ are cyclic. + + And also, these additional lemmas can be used to test if a + group is cyclic if the order of the group is already found. + + - If the group is abelian and the order of the group is + square-free, the group is cyclic. + - If the order of the group is less than $6$ and is not $4$, the + group is cyclic. + - If the order of the group is prime, the group is cyclic. + + References + ========== + + .. [1] 1978: John S. Rose: A Course on Group Theory, + Introduction to Finite Group Theory: 1.4 + """ + if self._is_cyclic is not None: + return self._is_cyclic + + if len(self.generators) == 1: + self._is_cyclic = True + self._is_abelian = True + return True + + if self._is_abelian is False: + self._is_cyclic = False + return False + + order = self.order() + + if order < 6: + self._is_abelian = True + if order != 4: + self._is_cyclic = True + return True + + factors = factorint(order) + if all(v == 1 for v in factors.values()): + if self._is_abelian: + self._is_cyclic = True + return True + + primes = list(factors.keys()) + if PermutationGroup._distinct_primes_lemma(primes) is True: + self._is_cyclic = True + self._is_abelian = True + return True + + if not self.is_abelian: + self._is_cyclic = False + return False + + self._is_cyclic = all( + any(g**(order//p) != self.identity for g in self.generators) + for p, e in factors.items() if e > 1 + ) + return self._is_cyclic + + @property + def is_dihedral(self): + r""" + Return ``True`` if the group is dihedral. + + Examples + ======== + + >>> from sympy.combinatorics.perm_groups import PermutationGroup + >>> from sympy.combinatorics.permutations import Permutation + >>> from sympy.combinatorics.named_groups import SymmetricGroup, CyclicGroup + >>> G = PermutationGroup(Permutation(1, 6)(2, 5)(3, 4), Permutation(0, 1, 2, 3, 4, 5, 6)) + >>> G.is_dihedral + True + >>> G = SymmetricGroup(3) + >>> G.is_dihedral + True + >>> G = CyclicGroup(6) + >>> G.is_dihedral + False + + References + ========== + + .. [Di1] https://math.stackexchange.com/questions/827230/given-a-cayley-table-is-there-an-algorithm-to-determine-if-it-is-a-dihedral-gro/827273#827273 + .. [Di2] https://kconrad.math.uconn.edu/blurbs/grouptheory/dihedral.pdf + .. [Di3] https://kconrad.math.uconn.edu/blurbs/grouptheory/dihedral2.pdf + .. [Di4] https://en.wikipedia.org/wiki/Dihedral_group + """ + if self._is_dihedral is not None: + return self._is_dihedral + + order = self.order() + + if order % 2 == 1: + self._is_dihedral = False + return False + if order == 2: + self._is_dihedral = True + return True + if order == 4: + # The dihedral group of order 4 is the Klein 4-group. + self._is_dihedral = not self.is_cyclic + return self._is_dihedral + if self.is_abelian: + # The only abelian dihedral groups are the ones of orders 2 and 4. + self._is_dihedral = False + return False + + # Now we know the group is of even order >= 6, and nonabelian. + n = order // 2 + + # Handle special cases where there are exactly two generators. + gens = self.generators + if len(gens) == 2: + x, y = gens + a, b = x.order(), y.order() + # Make a >= b + if a < b: + x, y, a, b = y, x, b, a + # Using Theorem 2.1 of [Di3]: + if a == 2 == b: + self._is_dihedral = True + return True + # Using Theorem 1.1 of [Di3]: + if a == n and b == 2 and y*x*y == ~x: + self._is_dihedral = True + return True + + # Proceed with algorithm of [Di1] + # Find elements of orders 2 and n + order_2, order_n = [], [] + for p in self.elements: + k = p.order() + if k == 2: + order_2.append(p) + elif k == n: + order_n.append(p) + + if len(order_2) != n + 1 - (n % 2): + self._is_dihedral = False + return False + + if not order_n: + self._is_dihedral = False + return False + + x = order_n[0] + # Want an element y of order 2 that is not a power of x + # (i.e. that is not the 180-deg rotation, when n is even). + y = order_2[0] + if n % 2 == 0 and y == x**(n//2): + y = order_2[1] + + self._is_dihedral = (y*x*y == ~x) + return self._is_dihedral + + def pointwise_stabilizer(self, points, incremental=True): + r"""Return the pointwise stabilizer for a set of points. + + Explanation + =========== + + For a permutation group `G` and a set of points + `\{p_1, p_2,\ldots, p_k\}`, the pointwise stabilizer of + `p_1, p_2, \ldots, p_k` is defined as + `G_{p_1,\ldots, p_k} = + \{g\in G | g(p_i) = p_i \forall i\in\{1, 2,\ldots,k\}\}` ([1],p20). + It is a subgroup of `G`. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> S = SymmetricGroup(7) + >>> Stab = S.pointwise_stabilizer([2, 3, 5]) + >>> Stab.is_subgroup(S.stabilizer(2).stabilizer(3).stabilizer(5)) + True + + See Also + ======== + + stabilizer, schreier_sims_incremental + + Notes + ===== + + When incremental == True, + rather than the obvious implementation using successive calls to + ``.stabilizer()``, this uses the incremental Schreier-Sims algorithm + to obtain a base with starting segment - the given points. + + """ + if incremental: + base, strong_gens = self.schreier_sims_incremental(base=points) + stab_gens = [] + degree = self.degree + for gen in strong_gens: + if [gen(point) for point in points] == points: + stab_gens.append(gen) + if not stab_gens: + stab_gens = _af_new(list(range(degree))) + return PermutationGroup(stab_gens) + else: + gens = self._generators + degree = self.degree + for x in points: + gens = _stabilizer(degree, gens, x) + return PermutationGroup(gens) + + def make_perm(self, n, seed=None): + """ + Multiply ``n`` randomly selected permutations from + pgroup together, starting with the identity + permutation. If ``n`` is a list of integers, those + integers will be used to select the permutations and they + will be applied in L to R order: make_perm((A, B, C)) will + give CBA(I) where I is the identity permutation. + + ``seed`` is used to set the seed for the random selection + of permutations from pgroup. If this is a list of integers, + the corresponding permutations from pgroup will be selected + in the order give. This is mainly used for testing purposes. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a, b = [Permutation([1, 0, 3, 2]), Permutation([1, 3, 0, 2])] + >>> G = PermutationGroup([a, b]) + >>> G.make_perm(1, [0]) + (0 1)(2 3) + >>> G.make_perm(3, [0, 1, 0]) + (0 2 3 1) + >>> G.make_perm([0, 1, 0]) + (0 2 3 1) + + See Also + ======== + + random + """ + if is_sequence(n): + if seed is not None: + raise ValueError('If n is a sequence, seed should be None') + n, seed = len(n), n + else: + try: + n = int(n) + except TypeError: + raise ValueError('n must be an integer or a sequence.') + randomrange = _randrange(seed) + + # start with the identity permutation + result = Permutation(list(range(self.degree))) + m = len(self) + for _ in range(n): + p = self[randomrange(m)] + result = rmul(result, p) + return result + + def random(self, af=False): + """Return a random group element + """ + rank = randrange(self.order()) + return self.coset_unrank(rank, af) + + def random_pr(self, gen_count=11, iterations=50, _random_prec=None): + """Return a random group element using product replacement. + + Explanation + =========== + + For the details of the product replacement algorithm, see + ``_random_pr_init`` In ``random_pr`` the actual 'product replacement' + is performed. Notice that if the attribute ``_random_gens`` + is empty, it needs to be initialized by ``_random_pr_init``. + + See Also + ======== + + _random_pr_init + + """ + if self._random_gens == []: + self._random_pr_init(gen_count, iterations) + random_gens = self._random_gens + r = len(random_gens) - 1 + + # handle randomized input for testing purposes + if _random_prec is None: + s = randrange(r) + t = randrange(r - 1) + if t == s: + t = r - 1 + x = choice([1, 2]) + e = choice([-1, 1]) + else: + s = _random_prec['s'] + t = _random_prec['t'] + if t == s: + t = r - 1 + x = _random_prec['x'] + e = _random_prec['e'] + + if x == 1: + random_gens[s] = _af_rmul(random_gens[s], _af_pow(random_gens[t], e)) + random_gens[r] = _af_rmul(random_gens[r], random_gens[s]) + else: + random_gens[s] = _af_rmul(_af_pow(random_gens[t], e), random_gens[s]) + random_gens[r] = _af_rmul(random_gens[s], random_gens[r]) + return _af_new(random_gens[r]) + + def random_stab(self, alpha, schreier_vector=None, _random_prec=None): + """Random element from the stabilizer of ``alpha``. + + The schreier vector for ``alpha`` is an optional argument used + for speeding up repeated calls. The algorithm is described in [1], p.81 + + See Also + ======== + + random_pr, orbit_rep + + """ + if schreier_vector is None: + schreier_vector = self.schreier_vector(alpha) + if _random_prec is None: + rand = self.random_pr() + else: + rand = _random_prec['rand'] + beta = rand(alpha) + h = self.orbit_rep(alpha, beta, schreier_vector) + return rmul(~h, rand) + + def schreier_sims(self): + """Schreier-Sims algorithm. + + Explanation + =========== + + It computes the generators of the chain of stabilizers + `G > G_{b_1} > .. > G_{b1,..,b_r} > 1` + in which `G_{b_1,..,b_i}` stabilizes `b_1,..,b_i`, + and the corresponding ``s`` cosets. + An element of the group can be written as the product + `h_1*..*h_s`. + + We use the incremental Schreier-Sims algorithm. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([0, 2, 1]) + >>> b = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a, b]) + >>> G.schreier_sims() + >>> G.basic_transversals + [{0: (2)(0 1), 1: (2), 2: (1 2)}, + {0: (2), 2: (0 2)}] + """ + if self._transversals: + return + self._schreier_sims() + return + + def _schreier_sims(self, base=None): + schreier = self.schreier_sims_incremental(base=base, slp_dict=True) + base, strong_gens = schreier[:2] + self._base = base + self._strong_gens = strong_gens + self._strong_gens_slp = schreier[2] + if not base: + self._transversals = [] + self._basic_orbits = [] + return + + strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + basic_orbits, transversals, slps = _orbits_transversals_from_bsgs(base,\ + strong_gens_distr, slp=True) + + # rewrite the indices stored in slps in terms of strong_gens + for i, slp in enumerate(slps): + gens = strong_gens_distr[i] + for k in slp: + slp[k] = [strong_gens.index(gens[s]) for s in slp[k]] + + self._transversals = transversals + self._basic_orbits = [sorted(x) for x in basic_orbits] + self._transversal_slp = slps + + def schreier_sims_incremental(self, base=None, gens=None, slp_dict=False): + """Extend a sequence of points and generating set to a base and strong + generating set. + + Parameters + ========== + + base + The sequence of points to be extended to a base. Optional + parameter with default value ``[]``. + gens + The generating set to be extended to a strong generating set + relative to the base obtained. Optional parameter with default + value ``self.generators``. + + slp_dict + If `True`, return a dictionary `{g: gens}` for each strong + generator `g` where `gens` is a list of strong generators + coming before `g` in `strong_gens`, such that the product + of the elements of `gens` is equal to `g`. + + Returns + ======= + + (base, strong_gens) + ``base`` is the base obtained, and ``strong_gens`` is the strong + generating set relative to it. The original parameters ``base``, + ``gens`` remain unchanged. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import AlternatingGroup + >>> from sympy.combinatorics.testutil import _verify_bsgs + >>> A = AlternatingGroup(7) + >>> base = [2, 3] + >>> seq = [2, 3] + >>> base, strong_gens = A.schreier_sims_incremental(base=seq) + >>> _verify_bsgs(A, base, strong_gens) + True + >>> base[:2] + [2, 3] + + Notes + ===== + + This version of the Schreier-Sims algorithm runs in polynomial time. + There are certain assumptions in the implementation - if the trivial + group is provided, ``base`` and ``gens`` are returned immediately, + as any sequence of points is a base for the trivial group. If the + identity is present in the generators ``gens``, it is removed as + it is a redundant generator. + The implementation is described in [1], pp. 90-93. + + See Also + ======== + + schreier_sims, schreier_sims_random + + """ + if base is None: + base = [] + if gens is None: + gens = self.generators[:] + degree = self.degree + id_af = list(range(degree)) + # handle the trivial group + if len(gens) == 1 and gens[0].is_Identity: + if slp_dict: + return base, gens, {gens[0]: [gens[0]]} + return base, gens + # prevent side effects + _base, _gens = base[:], gens[:] + # remove the identity as a generator + _gens = [x for x in _gens if not x.is_Identity] + # make sure no generator fixes all base points + for gen in _gens: + if all(x == gen._array_form[x] for x in _base): + for new in id_af: + if gen._array_form[new] != new: + break + else: + assert None # can this ever happen? + _base.append(new) + # distribute generators according to basic stabilizers + strong_gens_distr = _distribute_gens_by_base(_base, _gens) + strong_gens_slp = [] + # initialize the basic stabilizers, basic orbits and basic transversals + orbs = {} + transversals = {} + slps = {} + base_len = len(_base) + for i in range(base_len): + transversals[i], slps[i] = _orbit_transversal(degree, strong_gens_distr[i], + _base[i], pairs=True, af=True, slp=True) + transversals[i] = dict(transversals[i]) + orbs[i] = list(transversals[i].keys()) + # main loop: amend the stabilizer chain until we have generators + # for all stabilizers + i = base_len - 1 + while i >= 0: + # this flag is used to continue with the main loop from inside + # a nested loop + continue_i = False + # test the generators for being a strong generating set + db = {} + for beta, u_beta in list(transversals[i].items()): + for j, gen in enumerate(strong_gens_distr[i]): + gb = gen._array_form[beta] + u1 = transversals[i][gb] + g1 = _af_rmul(gen._array_form, u_beta) + slp = [(i, g) for g in slps[i][beta]] + slp = [(i, j)] + slp + if g1 != u1: + # test if the schreier generator is in the i+1-th + # would-be basic stabilizer + y = True + try: + u1_inv = db[gb] + except KeyError: + u1_inv = db[gb] = _af_invert(u1) + schreier_gen = _af_rmul(u1_inv, g1) + u1_inv_slp = slps[i][gb][:] + u1_inv_slp.reverse() + u1_inv_slp = [(i, (g,)) for g in u1_inv_slp] + slp = u1_inv_slp + slp + h, j, slp = _strip_af(schreier_gen, _base, orbs, transversals, i, slp=slp, slps=slps) + if j <= base_len: + # new strong generator h at level j + y = False + elif h: + # h fixes all base points + y = False + moved = 0 + while h[moved] == moved: + moved += 1 + _base.append(moved) + base_len += 1 + strong_gens_distr.append([]) + if y is False: + # if a new strong generator is found, update the + # data structures and start over + h = _af_new(h) + strong_gens_slp.append((h, slp)) + for l in range(i + 1, j): + strong_gens_distr[l].append(h) + transversals[l], slps[l] =\ + _orbit_transversal(degree, strong_gens_distr[l], + _base[l], pairs=True, af=True, slp=True) + transversals[l] = dict(transversals[l]) + orbs[l] = list(transversals[l].keys()) + i = j - 1 + # continue main loop using the flag + continue_i = True + if continue_i is True: + break + if continue_i is True: + break + if continue_i is True: + continue + i -= 1 + + strong_gens = _gens[:] + + if slp_dict: + # create the list of the strong generators strong_gens and + # rewrite the indices of strong_gens_slp in terms of the + # elements of strong_gens + for k, slp in strong_gens_slp: + strong_gens.append(k) + for i in range(len(slp)): + s = slp[i] + if isinstance(s[1], tuple): + slp[i] = strong_gens_distr[s[0]][s[1][0]]**-1 + else: + slp[i] = strong_gens_distr[s[0]][s[1]] + strong_gens_slp = dict(strong_gens_slp) + # add the original generators + for g in _gens: + strong_gens_slp[g] = [g] + return (_base, strong_gens, strong_gens_slp) + + strong_gens.extend([k for k, _ in strong_gens_slp]) + return _base, strong_gens + + def schreier_sims_random(self, base=None, gens=None, consec_succ=10, + _random_prec=None): + r"""Randomized Schreier-Sims algorithm. + + Explanation + =========== + + The randomized Schreier-Sims algorithm takes the sequence ``base`` + and the generating set ``gens``, and extends ``base`` to a base, and + ``gens`` to a strong generating set relative to that base with + probability of a wrong answer at most `2^{-consec\_succ}`, + provided the random generators are sufficiently random. + + Parameters + ========== + + base + The sequence to be extended to a base. + gens + The generating set to be extended to a strong generating set. + consec_succ + The parameter defining the probability of a wrong answer. + _random_prec + An internal parameter used for testing purposes. + + Returns + ======= + + (base, strong_gens) + ``base`` is the base and ``strong_gens`` is the strong generating + set relative to it. + + Examples + ======== + + >>> from sympy.combinatorics.testutil import _verify_bsgs + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> S = SymmetricGroup(5) + >>> base, strong_gens = S.schreier_sims_random(consec_succ=5) + >>> _verify_bsgs(S, base, strong_gens) #doctest: +SKIP + True + + Notes + ===== + + The algorithm is described in detail in [1], pp. 97-98. It extends + the orbits ``orbs`` and the permutation groups ``stabs`` to + basic orbits and basic stabilizers for the base and strong generating + set produced in the end. + The idea of the extension process + is to "sift" random group elements through the stabilizer chain + and amend the stabilizers/orbits along the way when a sift + is not successful. + The helper function ``_strip`` is used to attempt + to decompose a random group element according to the current + state of the stabilizer chain and report whether the element was + fully decomposed (successful sift) or not (unsuccessful sift). In + the latter case, the level at which the sift failed is reported and + used to amend ``stabs``, ``base``, ``gens`` and ``orbs`` accordingly. + The halting condition is for ``consec_succ`` consecutive successful + sifts to pass. This makes sure that the current ``base`` and ``gens`` + form a BSGS with probability at least `1 - 1/\text{consec\_succ}`. + + See Also + ======== + + schreier_sims + + """ + if base is None: + base = [] + if gens is None: + gens = self.generators + base_len = len(base) + n = self.degree + # make sure no generator fixes all base points + for gen in gens: + if all(gen(x) == x for x in base): + new = 0 + while gen._array_form[new] == new: + new += 1 + base.append(new) + base_len += 1 + # distribute generators according to basic stabilizers + strong_gens_distr = _distribute_gens_by_base(base, gens) + # initialize the basic stabilizers, basic transversals and basic orbits + transversals = {} + orbs = {} + for i in range(base_len): + transversals[i] = dict(_orbit_transversal(n, strong_gens_distr[i], + base[i], pairs=True)) + orbs[i] = list(transversals[i].keys()) + # initialize the number of consecutive elements sifted + c = 0 + # start sifting random elements while the number of consecutive sifts + # is less than consec_succ + while c < consec_succ: + if _random_prec is None: + g = self.random_pr() + else: + g = _random_prec['g'].pop() + h, j = _strip(g, base, orbs, transversals) + y = True + # determine whether a new base point is needed + if j <= base_len: + y = False + elif not h.is_Identity: + y = False + moved = 0 + while h(moved) == moved: + moved += 1 + base.append(moved) + base_len += 1 + strong_gens_distr.append([]) + # if the element doesn't sift, amend the strong generators and + # associated stabilizers and orbits + if y is False: + for l in range(1, j): + strong_gens_distr[l].append(h) + transversals[l] = dict(_orbit_transversal(n, + strong_gens_distr[l], base[l], pairs=True)) + orbs[l] = list(transversals[l].keys()) + c = 0 + else: + c += 1 + # build the strong generating set + strong_gens = strong_gens_distr[0][:] + for gen in strong_gens_distr[1]: + if gen not in strong_gens: + strong_gens.append(gen) + return base, strong_gens + + def schreier_vector(self, alpha): + """Computes the schreier vector for ``alpha``. + + Explanation + =========== + + The Schreier vector efficiently stores information + about the orbit of ``alpha``. It can later be used to quickly obtain + elements of the group that send ``alpha`` to a particular element + in the orbit. Notice that the Schreier vector depends on the order + in which the group generators are listed. For a definition, see [3]. + Since list indices start from zero, we adopt the convention to use + "None" instead of 0 to signify that an element does not belong + to the orbit. + For the algorithm and its correctness, see [2], pp.78-80. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([2, 4, 6, 3, 1, 5, 0]) + >>> b = Permutation([0, 1, 3, 5, 4, 6, 2]) + >>> G = PermutationGroup([a, b]) + >>> G.schreier_vector(0) + [-1, None, 0, 1, None, 1, 0] + + See Also + ======== + + orbit + + """ + n = self.degree + v = [None]*n + v[alpha] = -1 + orb = [alpha] + used = [False]*n + used[alpha] = True + gens = self.generators + r = len(gens) + for b in orb: + for i in range(r): + temp = gens[i]._array_form[b] + if used[temp] is False: + orb.append(temp) + used[temp] = True + v[temp] = i + return v + + def stabilizer(self, alpha): + r"""Return the stabilizer subgroup of ``alpha``. + + Explanation + =========== + + The stabilizer of `\alpha` is the group `G_\alpha = + \{g \in G | g(\alpha) = \alpha\}`. + For a proof of correctness, see [1], p.79. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> G = DihedralGroup(6) + >>> G.stabilizer(5) + PermutationGroup([ + (5)(0 4)(1 3)]) + + See Also + ======== + + orbit + + """ + return PermGroup(_stabilizer(self._degree, self._generators, alpha)) + + @property + def strong_gens(self): + r"""Return a strong generating set from the Schreier-Sims algorithm. + + Explanation + =========== + + A generating set `S = \{g_1, g_2, \dots, g_t\}` for a permutation group + `G` is a strong generating set relative to the sequence of points + (referred to as a "base") `(b_1, b_2, \dots, b_k)` if, for + `1 \leq i \leq k` we have that the intersection of the pointwise + stabilizer `G^{(i+1)} := G_{b_1, b_2, \dots, b_i}` with `S` generates + the pointwise stabilizer `G^{(i+1)}`. The concepts of a base and + strong generating set and their applications are discussed in depth + in [1], pp. 87-89 and [2], pp. 55-57. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> D = DihedralGroup(4) + >>> D.strong_gens + [(0 1 2 3), (0 3)(1 2), (1 3)] + >>> D.base + [0, 1] + + See Also + ======== + + base, basic_transversals, basic_orbits, basic_stabilizers + + """ + if self._strong_gens == []: + self.schreier_sims() + return self._strong_gens + + def subgroup(self, gens): + """ + Return the subgroup generated by `gens` which is a list of + elements of the group + """ + + if not all(g in self for g in gens): + raise ValueError("The group does not contain the supplied generators") + + G = PermutationGroup(gens) + return G + + def subgroup_search(self, prop, base=None, strong_gens=None, tests=None, + init_subgroup=None): + """Find the subgroup of all elements satisfying the property ``prop``. + + Explanation + =========== + + This is done by a depth-first search with respect to base images that + uses several tests to prune the search tree. + + Parameters + ========== + + prop + The property to be used. Has to be callable on group elements + and always return ``True`` or ``False``. It is assumed that + all group elements satisfying ``prop`` indeed form a subgroup. + base + A base for the supergroup. + strong_gens + A strong generating set for the supergroup. + tests + A list of callables of length equal to the length of ``base``. + These are used to rule out group elements by partial base images, + so that ``tests[l](g)`` returns False if the element ``g`` is known + not to satisfy prop base on where g sends the first ``l + 1`` base + points. + init_subgroup + if a subgroup of the sought group is + known in advance, it can be passed to the function as this + parameter. + + Returns + ======= + + res + The subgroup of all elements satisfying ``prop``. The generating + set for this group is guaranteed to be a strong generating set + relative to the base ``base``. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, + ... AlternatingGroup) + >>> from sympy.combinatorics.testutil import _verify_bsgs + >>> S = SymmetricGroup(7) + >>> prop_even = lambda x: x.is_even + >>> base, strong_gens = S.schreier_sims_incremental() + >>> G = S.subgroup_search(prop_even, base=base, strong_gens=strong_gens) + >>> G.is_subgroup(AlternatingGroup(7)) + True + >>> _verify_bsgs(G, base, G.generators) + True + + Notes + ===== + + This function is extremely lengthy and complicated and will require + some careful attention. The implementation is described in + [1], pp. 114-117, and the comments for the code here follow the lines + of the pseudocode in the book for clarity. + + The complexity is exponential in general, since the search process by + itself visits all members of the supergroup. However, there are a lot + of tests which are used to prune the search tree, and users can define + their own tests via the ``tests`` parameter, so in practice, and for + some computations, it's not terrible. + + A crucial part in the procedure is the frequent base change performed + (this is line 11 in the pseudocode) in order to obtain a new basic + stabilizer. The book mentiones that this can be done by using + ``.baseswap(...)``, however the current implementation uses a more + straightforward way to find the next basic stabilizer - calling the + function ``.stabilizer(...)`` on the previous basic stabilizer. + + """ + # initialize BSGS and basic group properties + def get_reps(orbits): + # get the minimal element in the base ordering + return [min(orbit, key = lambda x: base_ordering[x]) \ + for orbit in orbits] + + def update_nu(l): + temp_index = len(basic_orbits[l]) + 1 -\ + len(res_basic_orbits_init_base[l]) + # this corresponds to the element larger than all points + if temp_index >= len(sorted_orbits[l]): + nu[l] = base_ordering[degree] + else: + nu[l] = sorted_orbits[l][temp_index] + + if base is None: + base, strong_gens = self.schreier_sims_incremental() + base_len = len(base) + degree = self.degree + identity = _af_new(list(range(degree))) + base_ordering = _base_ordering(base, degree) + # add an element larger than all points + base_ordering.append(degree) + # add an element smaller than all points + base_ordering.append(-1) + # compute BSGS-related structures + strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + basic_orbits, transversals = _orbits_transversals_from_bsgs(base, + strong_gens_distr) + # handle subgroup initialization and tests + if init_subgroup is None: + init_subgroup = PermutationGroup([identity]) + if tests is None: + trivial_test = lambda x: True + tests = [] + for i in range(base_len): + tests.append(trivial_test) + # line 1: more initializations. + res = init_subgroup + f = base_len - 1 + l = base_len - 1 + # line 2: set the base for K to the base for G + res_base = base[:] + # line 3: compute BSGS and related structures for K + res_base, res_strong_gens = res.schreier_sims_incremental( + base=res_base) + res_strong_gens_distr = _distribute_gens_by_base(res_base, + res_strong_gens) + res_generators = res.generators + res_basic_orbits_init_base = \ + [_orbit(degree, res_strong_gens_distr[i], res_base[i])\ + for i in range(base_len)] + # initialize orbit representatives + orbit_reps = [None]*base_len + # line 4: orbit representatives for f-th basic stabilizer of K + orbits = _orbits(degree, res_strong_gens_distr[f]) + orbit_reps[f] = get_reps(orbits) + # line 5: remove the base point from the representatives to avoid + # getting the identity element as a generator for K + orbit_reps[f].remove(base[f]) + # line 6: more initializations + c = [0]*base_len + u = [identity]*base_len + sorted_orbits = [None]*base_len + for i in range(base_len): + sorted_orbits[i] = basic_orbits[i][:] + sorted_orbits[i].sort(key=lambda point: base_ordering[point]) + # line 7: initializations + mu = [None]*base_len + nu = [None]*base_len + # this corresponds to the element smaller than all points + mu[l] = degree + 1 + update_nu(l) + # initialize computed words + computed_words = [identity]*base_len + # line 8: main loop + while True: + # apply all the tests + while l < base_len - 1 and \ + computed_words[l](base[l]) in orbit_reps[l] and \ + base_ordering[mu[l]] < \ + base_ordering[computed_words[l](base[l])] < \ + base_ordering[nu[l]] and \ + tests[l](computed_words): + # line 11: change the (partial) base of K + new_point = computed_words[l](base[l]) + res_base[l] = new_point + new_stab_gens = _stabilizer(degree, res_strong_gens_distr[l], + new_point) + res_strong_gens_distr[l + 1] = new_stab_gens + # line 12: calculate minimal orbit representatives for the + # l+1-th basic stabilizer + orbits = _orbits(degree, new_stab_gens) + orbit_reps[l + 1] = get_reps(orbits) + # line 13: amend sorted orbits + l += 1 + temp_orbit = [computed_words[l - 1](point) for point + in basic_orbits[l]] + temp_orbit.sort(key=lambda point: base_ordering[point]) + sorted_orbits[l] = temp_orbit + # lines 14 and 15: update variables used minimality tests + new_mu = degree + 1 + for i in range(l): + if base[l] in res_basic_orbits_init_base[i]: + candidate = computed_words[i](base[i]) + if base_ordering[candidate] > base_ordering[new_mu]: + new_mu = candidate + mu[l] = new_mu + update_nu(l) + # line 16: determine the new transversal element + c[l] = 0 + temp_point = sorted_orbits[l][c[l]] + gamma = computed_words[l - 1]._array_form.index(temp_point) + u[l] = transversals[l][gamma] + # update computed words + computed_words[l] = rmul(computed_words[l - 1], u[l]) + # lines 17 & 18: apply the tests to the group element found + g = computed_words[l] + temp_point = g(base[l]) + if l == base_len - 1 and \ + base_ordering[mu[l]] < \ + base_ordering[temp_point] < base_ordering[nu[l]] and \ + temp_point in orbit_reps[l] and \ + tests[l](computed_words) and \ + prop(g): + # line 19: reset the base of K + res_generators.append(g) + res_base = base[:] + # line 20: recalculate basic orbits (and transversals) + res_strong_gens.append(g) + res_strong_gens_distr = _distribute_gens_by_base(res_base, + res_strong_gens) + res_basic_orbits_init_base = \ + [_orbit(degree, res_strong_gens_distr[i], res_base[i]) \ + for i in range(base_len)] + # line 21: recalculate orbit representatives + # line 22: reset the search depth + orbit_reps[f] = get_reps(orbits) + l = f + # line 23: go up the tree until in the first branch not fully + # searched + while l >= 0 and c[l] == len(basic_orbits[l]) - 1: + l = l - 1 + # line 24: if the entire tree is traversed, return K + if l == -1: + return PermutationGroup(res_generators) + # lines 25-27: update orbit representatives + if l < f: + # line 26 + f = l + c[l] = 0 + # line 27 + temp_orbits = _orbits(degree, res_strong_gens_distr[f]) + orbit_reps[f] = get_reps(temp_orbits) + # line 28: update variables used for minimality testing + mu[l] = degree + 1 + temp_index = len(basic_orbits[l]) + 1 - \ + len(res_basic_orbits_init_base[l]) + if temp_index >= len(sorted_orbits[l]): + nu[l] = base_ordering[degree] + else: + nu[l] = sorted_orbits[l][temp_index] + # line 29: set the next element from the current branch and update + # accordingly + c[l] += 1 + if l == 0: + gamma = sorted_orbits[l][c[l]] + else: + gamma = computed_words[l - 1]._array_form.index(sorted_orbits[l][c[l]]) + + u[l] = transversals[l][gamma] + if l == 0: + computed_words[l] = u[l] + else: + computed_words[l] = rmul(computed_words[l - 1], u[l]) + + @property + def transitivity_degree(self): + r"""Compute the degree of transitivity of the group. + + Explanation + =========== + + A permutation group `G` acting on `\Omega = \{0, 1, \dots, n-1\}` is + ``k``-fold transitive, if, for any `k` points + `(a_1, a_2, \dots, a_k) \in \Omega` and any `k` points + `(b_1, b_2, \dots, b_k) \in \Omega` there exists `g \in G` such that + `g(a_1) = b_1, g(a_2) = b_2, \dots, g(a_k) = b_k` + The degree of transitivity of `G` is the maximum ``k`` such that + `G` is ``k``-fold transitive. ([8]) + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> a = Permutation([1, 2, 0]) + >>> b = Permutation([1, 0, 2]) + >>> G = PermutationGroup([a, b]) + >>> G.transitivity_degree + 3 + + See Also + ======== + + is_transitive, orbit + + """ + if self._transitivity_degree is None: + n = self.degree + G = self + # if G is k-transitive, a tuple (a_0,..,a_k) + # can be brought to (b_0,...,b_(k-1), b_k) + # where b_0,...,b_(k-1) are fixed points; + # consider the group G_k which stabilizes b_0,...,b_(k-1) + # if G_k is transitive on the subset excluding b_0,...,b_(k-1) + # then G is (k+1)-transitive + for i in range(n): + orb = G.orbit(i) + if len(orb) != n - i: + self._transitivity_degree = i + return i + G = G.stabilizer(i) + self._transitivity_degree = n + return n + else: + return self._transitivity_degree + + def _p_elements_group(self, p): + ''' + For an abelian p-group, return the subgroup consisting of + all elements of order p (and the identity) + + ''' + gens = self.generators[:] + gens = sorted(gens, key=lambda x: x.order(), reverse=True) + gens_p = [g**(g.order()/p) for g in gens] + gens_r = [] + for i in range(len(gens)): + x = gens[i] + x_order = x.order() + # x_p has order p + x_p = x**(x_order/p) + if i > 0: + P = PermutationGroup(gens_p[:i]) + else: + P = PermutationGroup(self.identity) + if x**(x_order/p) not in P: + gens_r.append(x**(x_order/p)) + else: + # replace x by an element of order (x.order()/p) + # so that gens still generates G + g = P.generator_product(x_p, original=True) + for s in g: + x = x*s**-1 + x_order = x_order/p + # insert x to gens so that the sorting is preserved + del gens[i] + del gens_p[i] + j = i - 1 + while j < len(gens) and gens[j].order() >= x_order: + j += 1 + gens = gens[:j] + [x] + gens[j:] + gens_p = gens_p[:j] + [x] + gens_p[j:] + return PermutationGroup(gens_r) + + def _sylow_alt_sym(self, p): + ''' + Return a p-Sylow subgroup of a symmetric or an + alternating group. + + Explanation + =========== + + The algorithm for this is hinted at in [1], Chapter 4, + Exercise 4. + + For Sym(n) with n = p^i, the idea is as follows. Partition + the interval [0..n-1] into p equal parts, each of length p^(i-1): + [0..p^(i-1)-1], [p^(i-1)..2*p^(i-1)-1]...[(p-1)*p^(i-1)..p^i-1]. + Find a p-Sylow subgroup of Sym(p^(i-1)) (treated as a subgroup + of ``self``) acting on each of the parts. Call the subgroups + P_1, P_2...P_p. The generators for the subgroups P_2...P_p + can be obtained from those of P_1 by applying a "shifting" + permutation to them, that is, a permutation mapping [0..p^(i-1)-1] + to the second part (the other parts are obtained by using the shift + multiple times). The union of this permutation and the generators + of P_1 is a p-Sylow subgroup of ``self``. + + For n not equal to a power of p, partition + [0..n-1] in accordance with how n would be written in base p. + E.g. for p=2 and n=11, 11 = 2^3 + 2^2 + 1 so the partition + is [[0..7], [8..9], {10}]. To generate a p-Sylow subgroup, + take the union of the generators for each of the parts. + For the above example, {(0 1), (0 2)(1 3), (0 4), (1 5)(2 7)} + from the first part, {(8 9)} from the second part and + nothing from the third. This gives 4 generators in total, and + the subgroup they generate is p-Sylow. + + Alternating groups are treated the same except when p=2. In this + case, (0 1)(s s+1) should be added for an appropriate s (the start + of a part) for each part in the partitions. + + See Also + ======== + + sylow_subgroup, is_alt_sym + + ''' + n = self.degree + gens = [] + identity = Permutation(n-1) + # the case of 2-sylow subgroups of alternating groups + # needs special treatment + alt = p == 2 and all(g.is_even for g in self.generators) + + # find the presentation of n in base p + coeffs = [] + m = n + while m > 0: + coeffs.append(m % p) + m = m // p + + power = len(coeffs)-1 + # for a symmetric group, gens[:i] is the generating + # set for a p-Sylow subgroup on [0..p**(i-1)-1]. For + # alternating groups, the same is given by gens[:2*(i-1)] + for i in range(1, power+1): + if i == 1 and alt: + # (0 1) shouldn't be added for alternating groups + continue + gen = Permutation([(j + p**(i-1)) % p**i for j in range(p**i)]) + gens.append(identity*gen) + if alt: + gen = Permutation(0, 1)*gen*Permutation(0, 1)*gen + gens.append(gen) + + # the first point in the current part (see the algorithm + # description in the docstring) + start = 0 + + while power > 0: + a = coeffs[power] + + # make the permutation shifting the start of the first + # part ([0..p^i-1] for some i) to the current one + for _ in range(a): + shift = Permutation() + if start > 0: + for i in range(p**power): + shift = shift(i, start + i) + + if alt: + gen = Permutation(0, 1)*shift*Permutation(0, 1)*shift + gens.append(gen) + j = 2*(power - 1) + else: + j = power + + for i, gen in enumerate(gens[:j]): + if alt and i % 2 == 1: + continue + # shift the generator to the start of the + # partition part + gen = shift*gen*shift + gens.append(gen) + + start += p**power + power = power-1 + + return gens + + def sylow_subgroup(self, p): + ''' + Return a p-Sylow subgroup of the group. + + The algorithm is described in [1], Chapter 4, Section 7 + + Examples + ======== + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> from sympy.combinatorics.named_groups import SymmetricGroup + >>> from sympy.combinatorics.named_groups import AlternatingGroup + + >>> D = DihedralGroup(6) + >>> S = D.sylow_subgroup(2) + >>> S.order() + 4 + >>> G = SymmetricGroup(6) + >>> S = G.sylow_subgroup(5) + >>> S.order() + 5 + + >>> G1 = AlternatingGroup(3) + >>> G2 = AlternatingGroup(5) + >>> G3 = AlternatingGroup(9) + + >>> S1 = G1.sylow_subgroup(3) + >>> S2 = G2.sylow_subgroup(3) + >>> S3 = G3.sylow_subgroup(3) + + >>> len1 = len(S1.lower_central_series()) + >>> len2 = len(S2.lower_central_series()) + >>> len3 = len(S3.lower_central_series()) + + >>> len1 == len2 + True + >>> len1 < len3 + True + + ''' + from sympy.combinatorics.homomorphisms import ( + orbit_homomorphism, block_homomorphism) + + if not isprime(p): + raise ValueError("p must be a prime") + + def is_p_group(G): + # check if the order of G is a power of p + # and return the power + m = G.order() + n = 0 + while m % p == 0: + m = m/p + n += 1 + if m == 1: + return True, n + return False, n + + def _sylow_reduce(mu, nu): + # reduction based on two homomorphisms + # mu and nu with trivially intersecting + # kernels + Q = mu.image().sylow_subgroup(p) + Q = mu.invert_subgroup(Q) + nu = nu.restrict_to(Q) + R = nu.image().sylow_subgroup(p) + return nu.invert_subgroup(R) + + order = self.order() + if order % p != 0: + return PermutationGroup([self.identity]) + p_group, n = is_p_group(self) + if p_group: + return self + + if self.is_alt_sym(): + return PermutationGroup(self._sylow_alt_sym(p)) + + # if there is a non-trivial orbit with size not divisible + # by p, the sylow subgroup is contained in its stabilizer + # (by orbit-stabilizer theorem) + orbits = self.orbits() + non_p_orbits = [o for o in orbits if len(o) % p != 0 and len(o) != 1] + if non_p_orbits: + G = self.stabilizer(list(non_p_orbits[0]).pop()) + return G.sylow_subgroup(p) + + if not self.is_transitive(): + # apply _sylow_reduce to orbit actions + orbits = sorted(orbits, key=len) + omega1 = orbits.pop() + omega2 = orbits[0].union(*orbits) + mu = orbit_homomorphism(self, omega1) + nu = orbit_homomorphism(self, omega2) + return _sylow_reduce(mu, nu) + + blocks = self.minimal_blocks() + if len(blocks) > 1: + # apply _sylow_reduce to block system actions + mu = block_homomorphism(self, blocks[0]) + nu = block_homomorphism(self, blocks[1]) + return _sylow_reduce(mu, nu) + elif len(blocks) == 1: + block = list(blocks)[0] + if any(e != 0 for e in block): + # self is imprimitive + mu = block_homomorphism(self, block) + if not is_p_group(mu.image())[0]: + S = mu.image().sylow_subgroup(p) + return mu.invert_subgroup(S).sylow_subgroup(p) + + # find an element of order p + g = self.random() + g_order = g.order() + while g_order % p != 0 or g_order == 0: + g = self.random() + g_order = g.order() + g = g**(g_order // p) + if order % p**2 != 0: + return PermutationGroup(g) + + C = self.centralizer(g) + while C.order() % p**n != 0: + S = C.sylow_subgroup(p) + s_order = S.order() + Z = S.center() + P = Z._p_elements_group(p) + h = P.random() + C_h = self.centralizer(h) + while C_h.order() % p*s_order != 0: + h = P.random() + C_h = self.centralizer(h) + C = C_h + + return C.sylow_subgroup(p) + + def _block_verify(self, L, alpha): + delta = sorted(self.orbit(alpha)) + # p[i] will be the number of the block + # delta[i] belongs to + p = [-1]*len(delta) + blocks = [-1]*len(delta) + + B = [[]] # future list of blocks + u = [0]*len(delta) # u[i] in L s.t. alpha^u[i] = B[0][i] + + t = L.orbit_transversal(alpha, pairs=True) + for a, beta in t: + B[0].append(a) + i_a = delta.index(a) + p[i_a] = 0 + blocks[i_a] = alpha + u[i_a] = beta + + rho = 0 + m = 0 # number of blocks - 1 + + while rho <= m: + beta = B[rho][0] + for g in self.generators: + d = beta^g + i_d = delta.index(d) + sigma = p[i_d] + if sigma < 0: + # define a new block + m += 1 + sigma = m + u[i_d] = u[delta.index(beta)]*g + p[i_d] = sigma + rep = d + blocks[i_d] = rep + newb = [rep] + for gamma in B[rho][1:]: + i_gamma = delta.index(gamma) + d = gamma^g + i_d = delta.index(d) + if p[i_d] < 0: + u[i_d] = u[i_gamma]*g + p[i_d] = sigma + blocks[i_d] = rep + newb.append(d) + else: + # B[rho] is not a block + s = u[i_gamma]*g*u[i_d]**(-1) + return False, s + + B.append(newb) + else: + for h in B[rho][1:]: + if h^g not in B[sigma]: + # B[rho] is not a block + s = u[delta.index(beta)]*g*u[i_d]**(-1) + return False, s + rho += 1 + + return True, blocks + + def _verify(H, K, phi, z, alpha): + ''' + Return a list of relators ``rels`` in generators ``gens`_h` that + are mapped to ``H.generators`` by ``phi`` so that given a finite + presentation of ``K`` on a subset of ``gens_h`` + is a finite presentation of ``H``. + + Explanation + =========== + + ``H`` should be generated by the union of ``K.generators`` and ``z`` + (a single generator), and ``H.stabilizer(alpha) == K``; ``phi`` is a + canonical injection from a free group into a permutation group + containing ``H``. + + The algorithm is described in [1], Chapter 6. + + Examples + ======== + + >>> from sympy.combinatorics import free_group, Permutation, PermutationGroup + >>> from sympy.combinatorics.homomorphisms import homomorphism + >>> from sympy.combinatorics.fp_groups import FpGroup + + >>> H = PermutationGroup(Permutation(0, 2), Permutation (1, 5)) + >>> K = PermutationGroup(Permutation(5)(0, 2)) + >>> F = free_group("x_0 x_1")[0] + >>> gens = F.generators + >>> phi = homomorphism(F, H, F.generators, H.generators) + >>> rels_k = [gens[0]**2] # relators for presentation of K + >>> z= Permutation(1, 5) + >>> check, rels_h = H._verify(K, phi, z, 1) + >>> check + True + >>> rels = rels_k + rels_h + >>> G = FpGroup(F, rels) # presentation of H + >>> G.order() == H.order() + True + + See also + ======== + + strong_presentation, presentation, stabilizer + + ''' + + orbit = H.orbit(alpha) + beta = alpha^(z**-1) + + K_beta = K.stabilizer(beta) + + # orbit representatives of K_beta + gammas = [alpha, beta] + orbits = list({tuple(K_beta.orbit(o)) for o in orbit}) + orbit_reps = [orb[0] for orb in orbits] + for rep in orbit_reps: + if rep not in gammas: + gammas.append(rep) + + # orbit transversal of K + betas = [alpha, beta] + transversal = {alpha: phi.invert(H.identity), beta: phi.invert(z**-1)} + + for s, g in K.orbit_transversal(beta, pairs=True): + if s not in transversal: + transversal[s] = transversal[beta]*phi.invert(g) + + + union = K.orbit(alpha).union(K.orbit(beta)) + while (len(union) < len(orbit)): + for gamma in gammas: + if gamma in union: + r = gamma^z + if r not in union: + betas.append(r) + transversal[r] = transversal[gamma]*phi.invert(z) + for s, g in K.orbit_transversal(r, pairs=True): + if s not in transversal: + transversal[s] = transversal[r]*phi.invert(g) + union = union.union(K.orbit(r)) + break + + # compute relators + rels = [] + + for b in betas: + k_gens = K.stabilizer(b).generators + for y in k_gens: + new_rel = transversal[b] + gens = K.generator_product(y, original=True) + for g in gens[::-1]: + new_rel = new_rel*phi.invert(g) + new_rel = new_rel*transversal[b]**-1 + + perm = phi(new_rel) + try: + gens = K.generator_product(perm, original=True) + except ValueError: + return False, perm + for g in gens: + new_rel = new_rel*phi.invert(g)**-1 + if new_rel not in rels: + rels.append(new_rel) + + for gamma in gammas: + new_rel = transversal[gamma]*phi.invert(z)*transversal[gamma^z]**-1 + perm = phi(new_rel) + try: + gens = K.generator_product(perm, original=True) + except ValueError: + return False, perm + for g in gens: + new_rel = new_rel*phi.invert(g)**-1 + if new_rel not in rels: + rels.append(new_rel) + + return True, rels + + def strong_presentation(self): + ''' + Return a strong finite presentation of group. The generators + of the returned group are in the same order as the strong + generators of group. + + The algorithm is based on Sims' Verify algorithm described + in [1], Chapter 6. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> P = DihedralGroup(4) + >>> G = P.strong_presentation() + >>> P.order() == G.order() + True + + See Also + ======== + + presentation, _verify + + ''' + from sympy.combinatorics.fp_groups import (FpGroup, + simplify_presentation) + from sympy.combinatorics.free_groups import free_group + from sympy.combinatorics.homomorphisms import (block_homomorphism, + homomorphism, GroupHomomorphism) + + strong_gens = self.strong_gens[:] + stabs = self.basic_stabilizers[:] + base = self.base[:] + + # injection from a free group on len(strong_gens) + # generators into G + gen_syms = [('x_%d'%i) for i in range(len(strong_gens))] + F = free_group(', '.join(gen_syms))[0] + phi = homomorphism(F, self, F.generators, strong_gens) + + H = PermutationGroup(self.identity) + while stabs: + alpha = base.pop() + K = H + H = stabs.pop() + new_gens = [g for g in H.generators if g not in K] + + if K.order() == 1: + z = new_gens.pop() + rels = [F.generators[-1]**z.order()] + intermediate_gens = [z] + K = PermutationGroup(intermediate_gens) + + # add generators one at a time building up from K to H + while new_gens: + z = new_gens.pop() + intermediate_gens = [z] + intermediate_gens + K_s = PermutationGroup(intermediate_gens) + orbit = K_s.orbit(alpha) + orbit_k = K.orbit(alpha) + + # split into cases based on the orbit of K_s + if orbit_k == orbit: + if z in K: + rel = phi.invert(z) + perm = z + else: + t = K.orbit_rep(alpha, alpha^z) + rel = phi.invert(z)*phi.invert(t)**-1 + perm = z*t**-1 + for g in K.generator_product(perm, original=True): + rel = rel*phi.invert(g)**-1 + new_rels = [rel] + elif len(orbit_k) == 1: + # `success` is always true because `strong_gens` + # and `base` are already a verified BSGS. Later + # this could be changed to start with a randomly + # generated (potential) BSGS, and then new elements + # would have to be appended to it when `success` + # is false. + success, new_rels = K_s._verify(K, phi, z, alpha) + else: + # K.orbit(alpha) should be a block + # under the action of K_s on K_s.orbit(alpha) + check, block = K_s._block_verify(K, alpha) + if check: + # apply _verify to the action of K_s + # on the block system; for convenience, + # add the blocks as additional points + # that K_s should act on + t = block_homomorphism(K_s, block) + m = t.codomain.degree # number of blocks + d = K_s.degree + + # conjugating with p will shift + # permutations in t.image() to + # higher numbers, e.g. + # p*(0 1)*p = (m m+1) + p = Permutation() + for i in range(m): + p *= Permutation(i, i+d) + + t_img = t.images + # combine generators of K_s with their + # action on the block system + images = {g: g*p*t_img[g]*p for g in t_img} + for g in self.strong_gens[:-len(K_s.generators)]: + images[g] = g + K_s_act = PermutationGroup(list(images.values())) + f = GroupHomomorphism(self, K_s_act, images) + + K_act = PermutationGroup([f(g) for g in K.generators]) + success, new_rels = K_s_act._verify(K_act, f.compose(phi), f(z), d) + + for n in new_rels: + if n not in rels: + rels.append(n) + K = K_s + + group = FpGroup(F, rels) + return simplify_presentation(group) + + def presentation(self, eliminate_gens=True): + ''' + Return an `FpGroup` presentation of the group. + + The algorithm is described in [1], Chapter 6.1. + + ''' + from sympy.combinatorics.fp_groups import (FpGroup, + simplify_presentation) + from sympy.combinatorics.coset_table import CosetTable + from sympy.combinatorics.free_groups import free_group + from sympy.combinatorics.homomorphisms import homomorphism + + if self._fp_presentation: + return self._fp_presentation + + def _factor_group_by_rels(G, rels): + if isinstance(G, FpGroup): + rels.extend(G.relators) + return FpGroup(G.free_group, list(set(rels))) + return FpGroup(G, rels) + + gens = self.generators + len_g = len(gens) + + if len_g == 1: + order = gens[0].order() + # handle the trivial group + if order == 1: + return free_group([])[0] + F, x = free_group('x') + return FpGroup(F, [x**order]) + + if self.order() > 20: + half_gens = self.generators[0:(len_g+1)//2] + else: + half_gens = [] + H = PermutationGroup(half_gens) + H_p = H.presentation() + + len_h = len(H_p.generators) + + C = self.coset_table(H) + n = len(C) # subgroup index + + gen_syms = [('x_%d'%i) for i in range(len(gens))] + F = free_group(', '.join(gen_syms))[0] + + # mapping generators of H_p to those of F + images = [F.generators[i] for i in range(len_h)] + R = homomorphism(H_p, F, H_p.generators, images, check=False) + + # rewrite relators + rels = R(H_p.relators) + G_p = FpGroup(F, rels) + + # injective homomorphism from G_p into self + T = homomorphism(G_p, self, G_p.generators, gens) + + C_p = CosetTable(G_p, []) + + C_p.table = [[None]*(2*len_g) for i in range(n)] + + # initiate the coset transversal + transversal = [None]*n + transversal[0] = G_p.identity + + # fill in the coset table as much as possible + for i in range(2*len_h): + C_p.table[0][i] = 0 + + gamma = 1 + for alpha, x in product(range(n), range(2*len_g)): + beta = C[alpha][x] + if beta == gamma: + gen = G_p.generators[x//2]**((-1)**(x % 2)) + transversal[beta] = transversal[alpha]*gen + C_p.table[alpha][x] = beta + C_p.table[beta][x + (-1)**(x % 2)] = alpha + gamma += 1 + if gamma == n: + break + + C_p.p = list(range(n)) + beta = x = 0 + + while not C_p.is_complete(): + # find the first undefined entry + while C_p.table[beta][x] == C[beta][x]: + x = (x + 1) % (2*len_g) + if x == 0: + beta = (beta + 1) % n + + # define a new relator + gen = G_p.generators[x//2]**((-1)**(x % 2)) + new_rel = transversal[beta]*gen*transversal[C[beta][x]]**-1 + perm = T(new_rel) + nxt = G_p.identity + for s in H.generator_product(perm, original=True): + nxt = nxt*T.invert(s)**-1 + new_rel = new_rel*nxt + + # continue coset enumeration + G_p = _factor_group_by_rels(G_p, [new_rel]) + C_p.scan_and_fill(0, new_rel) + C_p = G_p.coset_enumeration([], strategy="coset_table", + draft=C_p, max_cosets=n, incomplete=True) + + self._fp_presentation = simplify_presentation(G_p) + return self._fp_presentation + + def polycyclic_group(self): + """ + Return the PolycyclicGroup instance with below parameters: + + Explanation + =========== + + * pc_sequence : Polycyclic sequence is formed by collecting all + the missing generators between the adjacent groups in the + derived series of given permutation group. + + * pc_series : Polycyclic series is formed by adding all the missing + generators of ``der[i+1]`` in ``der[i]``, where ``der`` represents + the derived series. + + * relative_order : A list, computed by the ratio of adjacent groups in + pc_series. + + """ + from sympy.combinatorics.pc_groups import PolycyclicGroup + if not self.is_polycyclic: + raise ValueError("The group must be solvable") + + der = self.derived_series() + pc_series = [] + pc_sequence = [] + relative_order = [] + pc_series.append(der[-1]) + der.reverse() + + for i in range(len(der)-1): + H = der[i] + for g in der[i+1].generators: + if g not in H: + H = PermutationGroup([g] + H.generators) + pc_series.insert(0, H) + pc_sequence.insert(0, g) + + G1 = pc_series[0].order() + G2 = pc_series[1].order() + relative_order.insert(0, G1 // G2) + + return PolycyclicGroup(pc_sequence, pc_series, relative_order, collector=None) + + +def _orbit(degree, generators, alpha, action='tuples'): + r"""Compute the orbit of alpha `\{g(\alpha) | g \in G\}` as a set. + + Explanation + =========== + + The time complexity of the algorithm used here is `O(|Orb|*r)` where + `|Orb|` is the size of the orbit and ``r`` is the number of generators of + the group. For a more detailed analysis, see [1], p.78, [2], pp. 19-21. + Here alpha can be a single point, or a list of points. + + If alpha is a single point, the ordinary orbit is computed. + if alpha is a list of points, there are three available options: + + 'union' - computes the union of the orbits of the points in the list + 'tuples' - computes the orbit of the list interpreted as an ordered + tuple under the group action ( i.e., g((1, 2, 3)) = (g(1), g(2), g(3)) ) + 'sets' - computes the orbit of the list interpreted as a sets + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> from sympy.combinatorics.perm_groups import _orbit + >>> a = Permutation([1, 2, 0, 4, 5, 6, 3]) + >>> G = PermutationGroup([a]) + >>> _orbit(G.degree, G.generators, 0) + {0, 1, 2} + >>> _orbit(G.degree, G.generators, [0, 4], 'union') + {0, 1, 2, 3, 4, 5, 6} + + See Also + ======== + + orbit, orbit_transversal + + """ + if not hasattr(alpha, '__getitem__'): + alpha = [alpha] + + gens = [x._array_form for x in generators] + if len(alpha) == 1 or action == 'union': + orb = alpha + used = [False]*degree + for el in alpha: + used[el] = True + for b in orb: + for gen in gens: + temp = gen[b] + if used[temp] == False: + orb.append(temp) + used[temp] = True + return set(orb) + elif action == 'tuples': + alpha = tuple(alpha) + orb = [alpha] + used = {alpha} + for b in orb: + for gen in gens: + temp = tuple([gen[x] for x in b]) + if temp not in used: + orb.append(temp) + used.add(temp) + return set(orb) + elif action == 'sets': + alpha = frozenset(alpha) + orb = [alpha] + used = {alpha} + for b in orb: + for gen in gens: + temp = frozenset([gen[x] for x in b]) + if temp not in used: + orb.append(temp) + used.add(temp) + return {tuple(x) for x in orb} + + +def _orbits(degree, generators): + """Compute the orbits of G. + + If ``rep=False`` it returns a list of sets else it returns a list of + representatives of the orbits + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.perm_groups import _orbits + >>> a = Permutation([0, 2, 1]) + >>> b = Permutation([1, 0, 2]) + >>> _orbits(a.size, [a, b]) + [{0, 1, 2}] + """ + + orbs = [] + sorted_I = list(range(degree)) + I = set(sorted_I) + while I: + i = sorted_I[0] + orb = _orbit(degree, generators, i) + orbs.append(orb) + # remove all indices that are in this orbit + I -= orb + sorted_I = [i for i in sorted_I if i not in orb] + return orbs + + +def _orbit_transversal(degree, generators, alpha, pairs, af=False, slp=False): + r"""Computes a transversal for the orbit of ``alpha`` as a set. + + Explanation + =========== + + generators generators of the group ``G`` + + For a permutation group ``G``, a transversal for the orbit + `Orb = \{g(\alpha) | g \in G\}` is a set + `\{g_\beta | g_\beta(\alpha) = \beta\}` for `\beta \in Orb`. + Note that there may be more than one possible transversal. + If ``pairs`` is set to ``True``, it returns the list of pairs + `(\beta, g_\beta)`. For a proof of correctness, see [1], p.79 + + if ``af`` is ``True``, the transversal elements are given in + array form. + + If `slp` is `True`, a dictionary `{beta: slp_beta}` is returned + for `\beta \in Orb` where `slp_beta` is a list of indices of the + generators in `generators` s.t. if `slp_beta = [i_1 \dots i_n]` + `g_\beta = generators[i_n] \times \dots \times generators[i_1]`. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> from sympy.combinatorics.perm_groups import _orbit_transversal + >>> G = DihedralGroup(6) + >>> _orbit_transversal(G.degree, G.generators, 0, False) + [(5), (0 1 2 3 4 5), (0 5)(1 4)(2 3), (0 2 4)(1 3 5), (5)(0 4)(1 3), (0 3)(1 4)(2 5)] + """ + + tr = [(alpha, list(range(degree)))] + slp_dict = {alpha: []} + used = [False]*degree + used[alpha] = True + gens = [x._array_form for x in generators] + for x, px in tr: + px_slp = slp_dict[x] + for gen in gens: + temp = gen[x] + if used[temp] == False: + slp_dict[temp] = [gens.index(gen)] + px_slp + tr.append((temp, _af_rmul(gen, px))) + used[temp] = True + if pairs: + if not af: + tr = [(x, _af_new(y)) for x, y in tr] + if not slp: + return tr + return tr, slp_dict + + if af: + tr = [y for _, y in tr] + if not slp: + return tr + return tr, slp_dict + + tr = [_af_new(y) for _, y in tr] + if not slp: + return tr + return tr, slp_dict + + +def _stabilizer(degree, generators, alpha): + r"""Return the stabilizer subgroup of ``alpha``. + + Explanation + =========== + + The stabilizer of `\alpha` is the group `G_\alpha = + \{g \in G | g(\alpha) = \alpha\}`. + For a proof of correctness, see [1], p.79. + + degree : degree of G + generators : generators of G + + Examples + ======== + + >>> from sympy.combinatorics.perm_groups import _stabilizer + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> G = DihedralGroup(6) + >>> _stabilizer(G.degree, G.generators, 5) + [(5)(0 4)(1 3), (5)] + + See Also + ======== + + orbit + + """ + orb = [alpha] + table = {alpha: list(range(degree))} + table_inv = {alpha: list(range(degree))} + used = [False]*degree + used[alpha] = True + gens = [x._array_form for x in generators] + stab_gens = [] + for b in orb: + for gen in gens: + temp = gen[b] + if used[temp] is False: + gen_temp = _af_rmul(gen, table[b]) + orb.append(temp) + table[temp] = gen_temp + table_inv[temp] = _af_invert(gen_temp) + used[temp] = True + else: + schreier_gen = _af_rmuln(table_inv[temp], gen, table[b]) + if schreier_gen not in stab_gens: + stab_gens.append(schreier_gen) + return [_af_new(x) for x in stab_gens] + + +PermGroup = PermutationGroup + + +class SymmetricPermutationGroup(Basic): + """ + The class defining the lazy form of SymmetricGroup. + + deg : int + + """ + def __new__(cls, deg): + deg = _sympify(deg) + obj = Basic.__new__(cls, deg) + return obj + + def __init__(self, *args, **kwargs): + self._deg = self.args[0] + self._order = None + + def __contains__(self, i): + """Return ``True`` if *i* is contained in SymmetricPermutationGroup. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, SymmetricPermutationGroup + >>> G = SymmetricPermutationGroup(4) + >>> Permutation(1, 2, 3) in G + True + + """ + if not isinstance(i, Permutation): + raise TypeError("A SymmetricPermutationGroup contains only Permutations as " + "elements, not elements of type %s" % type(i)) + return i.size == self.degree + + def order(self): + """ + Return the order of the SymmetricPermutationGroup. + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricPermutationGroup + >>> G = SymmetricPermutationGroup(4) + >>> G.order() + 24 + """ + if self._order is not None: + return self._order + n = self._deg + self._order = factorial(n) + return self._order + + @property + def degree(self): + """ + Return the degree of the SymmetricPermutationGroup. + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricPermutationGroup + >>> G = SymmetricPermutationGroup(4) + >>> G.degree + 4 + + """ + return self._deg + + @property + def identity(self): + ''' + Return the identity element of the SymmetricPermutationGroup. + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricPermutationGroup + >>> G = SymmetricPermutationGroup(4) + >>> G.identity() + (3) + + ''' + return _af_new(list(range(self._deg))) + + +class Coset(Basic): + """A left coset of a permutation group with respect to an element. + + Parameters + ========== + + g : Permutation + + H : PermutationGroup + + dir : "+" or "-", If not specified by default it will be "+" + here ``dir`` specified the type of coset "+" represent the + right coset and "-" represent the left coset. + + G : PermutationGroup, optional + The group which contains *H* as its subgroup and *g* as its + element. + + If not specified, it would automatically become a symmetric + group ``SymmetricPermutationGroup(g.size)`` and + ``SymmetricPermutationGroup(H.degree)`` if ``g.size`` and ``H.degree`` + are matching.``SymmetricPermutationGroup`` is a lazy form of SymmetricGroup + used for representation purpose. + + """ + + def __new__(cls, g, H, G=None, dir="+"): + g = _sympify(g) + if not isinstance(g, Permutation): + raise NotImplementedError + + H = _sympify(H) + if not isinstance(H, PermutationGroup): + raise NotImplementedError + + if G is not None: + G = _sympify(G) + if not isinstance(G, (PermutationGroup, SymmetricPermutationGroup)): + raise NotImplementedError + if not H.is_subgroup(G): + raise ValueError("{} must be a subgroup of {}.".format(H, G)) + if g not in G: + raise ValueError("{} must be an element of {}.".format(g, G)) + else: + g_size = g.size + h_degree = H.degree + if g_size != h_degree: + raise ValueError( + "The size of the permutation {} and the degree of " + "the permutation group {} should be matching " + .format(g, H)) + G = SymmetricPermutationGroup(g.size) + + if isinstance(dir, str): + dir = Symbol(dir) + elif not isinstance(dir, Symbol): + raise TypeError("dir must be of type basestring or " + "Symbol, not %s" % type(dir)) + if str(dir) not in ('+', '-'): + raise ValueError("dir must be one of '+' or '-' not %s" % dir) + obj = Basic.__new__(cls, g, H, G, dir) + return obj + + def __init__(self, *args, **kwargs): + self._dir = self.args[3] + + @property + def is_left_coset(self): + """ + Check if the coset is left coset that is ``gH``. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup, Coset + >>> a = Permutation(1, 2) + >>> b = Permutation(0, 1) + >>> G = PermutationGroup([a, b]) + >>> cst = Coset(a, G, dir="-") + >>> cst.is_left_coset + True + + """ + return str(self._dir) == '-' + + @property + def is_right_coset(self): + """ + Check if the coset is right coset that is ``Hg``. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, PermutationGroup, Coset + >>> a = Permutation(1, 2) + >>> b = Permutation(0, 1) + >>> G = PermutationGroup([a, b]) + >>> cst = Coset(a, G, dir="+") + >>> cst.is_right_coset + True + + """ + return str(self._dir) == '+' + + def as_list(self): + """ + Return all the elements of coset in the form of list. + """ + g = self.args[0] + H = self.args[1] + cst = [] + if str(self._dir) == '+': + for h in H.elements: + cst.append(h*g) + else: + for h in H.elements: + cst.append(g*h) + return cst diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/permutations.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/permutations.py new file mode 100644 index 0000000000000000000000000000000000000000..3718467b69cbab2b9b0dd73e8fa160cceb0324bf --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/permutations.py @@ -0,0 +1,3114 @@ +import random +from collections import defaultdict +from collections.abc import Iterable +from functools import reduce + +from sympy.core.parameters import global_parameters +from sympy.core.basic import Atom +from sympy.core.expr import Expr +from sympy.core.numbers import int_valued +from sympy.core.numbers import Integer +from sympy.core.sympify import _sympify +from sympy.matrices import zeros +from sympy.polys.polytools import lcm +from sympy.printing.repr import srepr +from sympy.utilities.iterables import (flatten, has_variety, minlex, + has_dups, runs, is_sequence) +from sympy.utilities.misc import as_int +from mpmath.libmp.libintmath import ifac +from sympy.multipledispatch import dispatch + +def _af_rmul(a, b): + """ + Return the product b*a; input and output are array forms. The ith value + is a[b[i]]. + + Examples + ======== + + >>> from sympy.combinatorics.permutations import _af_rmul, Permutation + + >>> a, b = [1, 0, 2], [0, 2, 1] + >>> _af_rmul(a, b) + [1, 2, 0] + >>> [a[b[i]] for i in range(3)] + [1, 2, 0] + + This handles the operands in reverse order compared to the ``*`` operator: + + >>> a = Permutation(a) + >>> b = Permutation(b) + >>> list(a*b) + [2, 0, 1] + >>> [b(a(i)) for i in range(3)] + [2, 0, 1] + + See Also + ======== + + rmul, _af_rmuln + """ + return [a[i] for i in b] + + +def _af_rmuln(*abc): + """ + Given [a, b, c, ...] return the product of ...*c*b*a using array forms. + The ith value is a[b[c[i]]]. + + Examples + ======== + + >>> from sympy.combinatorics.permutations import _af_rmul, Permutation + + >>> a, b = [1, 0, 2], [0, 2, 1] + >>> _af_rmul(a, b) + [1, 2, 0] + >>> [a[b[i]] for i in range(3)] + [1, 2, 0] + + This handles the operands in reverse order compared to the ``*`` operator: + + >>> a = Permutation(a); b = Permutation(b) + >>> list(a*b) + [2, 0, 1] + >>> [b(a(i)) for i in range(3)] + [2, 0, 1] + + See Also + ======== + + rmul, _af_rmul + """ + a = abc + m = len(a) + if m == 3: + p0, p1, p2 = a + return [p0[p1[i]] for i in p2] + if m == 4: + p0, p1, p2, p3 = a + return [p0[p1[p2[i]]] for i in p3] + if m == 5: + p0, p1, p2, p3, p4 = a + return [p0[p1[p2[p3[i]]]] for i in p4] + if m == 6: + p0, p1, p2, p3, p4, p5 = a + return [p0[p1[p2[p3[p4[i]]]]] for i in p5] + if m == 7: + p0, p1, p2, p3, p4, p5, p6 = a + return [p0[p1[p2[p3[p4[p5[i]]]]]] for i in p6] + if m == 8: + p0, p1, p2, p3, p4, p5, p6, p7 = a + return [p0[p1[p2[p3[p4[p5[p6[i]]]]]]] for i in p7] + if m == 1: + return a[0][:] + if m == 2: + a, b = a + return [a[i] for i in b] + if m == 0: + raise ValueError("String must not be empty") + p0 = _af_rmuln(*a[:m//2]) + p1 = _af_rmuln(*a[m//2:]) + return [p0[i] for i in p1] + + +def _af_parity(pi): + """ + Computes the parity of a permutation in array form. + + Explanation + =========== + + The parity of a permutation reflects the parity of the + number of inversions in the permutation, i.e., the + number of pairs of x and y such that x > y but p[x] < p[y]. + + Examples + ======== + + >>> from sympy.combinatorics.permutations import _af_parity + >>> _af_parity([0, 1, 2, 3]) + 0 + >>> _af_parity([3, 2, 0, 1]) + 1 + + See Also + ======== + + Permutation + """ + n = len(pi) + a = [0] * n + c = 0 + for j in range(n): + if a[j] == 0: + c += 1 + a[j] = 1 + i = j + while pi[i] != j: + i = pi[i] + a[i] = 1 + return (n - c) % 2 + + +def _af_invert(a): + """ + Finds the inverse, ~A, of a permutation, A, given in array form. + + Examples + ======== + + >>> from sympy.combinatorics.permutations import _af_invert, _af_rmul + >>> A = [1, 2, 0, 3] + >>> _af_invert(A) + [2, 0, 1, 3] + >>> _af_rmul(_, A) + [0, 1, 2, 3] + + See Also + ======== + + Permutation, __invert__ + """ + inv_form = [0] * len(a) + for i, ai in enumerate(a): + inv_form[ai] = i + return inv_form + + +def _af_pow(a, n): + """ + Routine for finding powers of a permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.permutations import _af_pow + >>> p = Permutation([2, 0, 3, 1]) + >>> p.order() + 4 + >>> _af_pow(p._array_form, 4) + [0, 1, 2, 3] + """ + if n == 0: + return list(range(len(a))) + if n < 0: + return _af_pow(_af_invert(a), -n) + if n == 1: + return a[:] + elif n == 2: + b = [a[i] for i in a] + elif n == 3: + b = [a[a[i]] for i in a] + elif n == 4: + b = [a[a[a[i]]] for i in a] + else: + # use binary multiplication + b = list(range(len(a))) + while 1: + if n & 1: + b = [b[i] for i in a] + n -= 1 + if not n: + break + if n % 4 == 0: + a = [a[a[a[i]]] for i in a] + n = n // 4 + elif n % 2 == 0: + a = [a[i] for i in a] + n = n // 2 + return b + + +def _af_commutes_with(a, b): + """ + Checks if the two permutations with array forms + given by ``a`` and ``b`` commute. + + Examples + ======== + + >>> from sympy.combinatorics.permutations import _af_commutes_with + >>> _af_commutes_with([1, 2, 0], [0, 2, 1]) + False + + See Also + ======== + + Permutation, commutes_with + """ + return not any(a[b[i]] != b[a[i]] for i in range(len(a) - 1)) + + +class Cycle(dict): + """ + Wrapper around dict which provides the functionality of a disjoint cycle. + + Explanation + =========== + + A cycle shows the rule to use to move subsets of elements to obtain + a permutation. The Cycle class is more flexible than Permutation in + that 1) all elements need not be present in order to investigate how + multiple cycles act in sequence and 2) it can contain singletons: + + >>> from sympy.combinatorics.permutations import Perm, Cycle + + A Cycle will automatically parse a cycle given as a tuple on the rhs: + + >>> Cycle(1, 2)(2, 3) + (1 3 2) + + The identity cycle, Cycle(), can be used to start a product: + + >>> Cycle()(1, 2)(2, 3) + (1 3 2) + + The array form of a Cycle can be obtained by calling the list + method (or passing it to the list function) and all elements from + 0 will be shown: + + >>> a = Cycle(1, 2) + >>> a.list() + [0, 2, 1] + >>> list(a) + [0, 2, 1] + + If a larger (or smaller) range is desired use the list method and + provide the desired size -- but the Cycle cannot be truncated to + a size smaller than the largest element that is out of place: + + >>> b = Cycle(2, 4)(1, 2)(3, 1, 4)(1, 3) + >>> b.list() + [0, 2, 1, 3, 4] + >>> b.list(b.size + 1) + [0, 2, 1, 3, 4, 5] + >>> b.list(-1) + [0, 2, 1] + + Singletons are not shown when printing with one exception: the largest + element is always shown -- as a singleton if necessary: + + >>> Cycle(1, 4, 10)(4, 5) + (1 5 4 10) + >>> Cycle(1, 2)(4)(5)(10) + (1 2)(10) + + The array form can be used to instantiate a Permutation so other + properties of the permutation can be investigated: + + >>> Perm(Cycle(1, 2)(3, 4).list()).transpositions() + [(1, 2), (3, 4)] + + Notes + ===== + + The underlying structure of the Cycle is a dictionary and although + the __iter__ method has been redefined to give the array form of the + cycle, the underlying dictionary items are still available with the + such methods as items(): + + >>> list(Cycle(1, 2).items()) + [(1, 2), (2, 1)] + + See Also + ======== + + Permutation + """ + def __missing__(self, arg): + """Enter arg into dictionary and return arg.""" + return as_int(arg) + + def __iter__(self): + yield from self.list() + + def __call__(self, *other): + """Return product of cycles processed from R to L. + + Examples + ======== + + >>> from sympy.combinatorics import Cycle + >>> Cycle(1, 2)(2, 3) + (1 3 2) + + An instance of a Cycle will automatically parse list-like + objects and Permutations that are on the right. It is more + flexible than the Permutation in that all elements need not + be present: + + >>> a = Cycle(1, 2) + >>> a(2, 3) + (1 3 2) + >>> a(2, 3)(4, 5) + (1 3 2)(4 5) + + """ + rv = Cycle(*other) + for k, v in zip(list(self.keys()), [rv[self[k]] for k in self.keys()]): + rv[k] = v + return rv + + def list(self, size=None): + """Return the cycles as an explicit list starting from 0 up + to the greater of the largest value in the cycles and size. + + Truncation of trailing unmoved items will occur when size + is less than the maximum element in the cycle; if this is + desired, setting ``size=-1`` will guarantee such trimming. + + Examples + ======== + + >>> from sympy.combinatorics import Cycle + >>> p = Cycle(2, 3)(4, 5) + >>> p.list() + [0, 1, 3, 2, 5, 4] + >>> p.list(10) + [0, 1, 3, 2, 5, 4, 6, 7, 8, 9] + + Passing a length too small will trim trailing, unchanged elements + in the permutation: + + >>> Cycle(2, 4)(1, 2, 4).list(-1) + [0, 2, 1] + """ + if not self and size is None: + raise ValueError('must give size for empty Cycle') + if size is not None: + big = max([i for i in self.keys() if self[i] != i] + [0]) + size = max(size, big + 1) + else: + size = self.size + return [self[i] for i in range(size)] + + def __repr__(self): + """We want it to print as a Cycle, not as a dict. + + Examples + ======== + + >>> from sympy.combinatorics import Cycle + >>> Cycle(1, 2) + (1 2) + >>> print(_) + (1 2) + >>> list(Cycle(1, 2).items()) + [(1, 2), (2, 1)] + """ + if not self: + return 'Cycle()' + cycles = Permutation(self).cyclic_form + s = ''.join(str(tuple(c)) for c in cycles) + big = self.size - 1 + if not any(i == big for c in cycles for i in c): + s += '(%s)' % big + return 'Cycle%s' % s + + def __str__(self): + """We want it to be printed in a Cycle notation with no + comma in-between. + + Examples + ======== + + >>> from sympy.combinatorics import Cycle + >>> Cycle(1, 2) + (1 2) + >>> Cycle(1, 2, 4)(5, 6) + (1 2 4)(5 6) + """ + if not self: + return '()' + cycles = Permutation(self).cyclic_form + s = ''.join(str(tuple(c)) for c in cycles) + big = self.size - 1 + if not any(i == big for c in cycles for i in c): + s += '(%s)' % big + s = s.replace(',', '') + return s + + def __init__(self, *args): + """Load up a Cycle instance with the values for the cycle. + + Examples + ======== + + >>> from sympy.combinatorics import Cycle + >>> Cycle(1, 2, 6) + (1 2 6) + """ + + if not args: + return + if len(args) == 1: + if isinstance(args[0], Permutation): + for c in args[0].cyclic_form: + self.update(self(*c)) + return + elif isinstance(args[0], Cycle): + for k, v in args[0].items(): + self[k] = v + return + args = [as_int(a) for a in args] + if any(i < 0 for i in args): + raise ValueError('negative integers are not allowed in a cycle.') + if has_dups(args): + raise ValueError('All elements must be unique in a cycle.') + for i in range(-len(args), 0): + self[args[i]] = args[i + 1] + + @property + def size(self): + if not self: + return 0 + return max(self.keys()) + 1 + + def copy(self): + return Cycle(self) + + +class Permutation(Atom): + r""" + A permutation, alternatively known as an 'arrangement number' or 'ordering' + is an arrangement of the elements of an ordered list into a one-to-one + mapping with itself. The permutation of a given arrangement is given by + indicating the positions of the elements after re-arrangement [2]_. For + example, if one started with elements ``[x, y, a, b]`` (in that order) and + they were reordered as ``[x, y, b, a]`` then the permutation would be + ``[0, 1, 3, 2]``. Notice that (in SymPy) the first element is always referred + to as 0 and the permutation uses the indices of the elements in the + original ordering, not the elements ``(a, b, ...)`` themselves. + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + + Permutations Notation + ===================== + + Permutations are commonly represented in disjoint cycle or array forms. + + Array Notation and 2-line Form + ------------------------------------ + + In the 2-line form, the elements and their final positions are shown + as a matrix with 2 rows: + + [0 1 2 ... n-1] + [p(0) p(1) p(2) ... p(n-1)] + + Since the first line is always ``range(n)``, where n is the size of p, + it is sufficient to represent the permutation by the second line, + referred to as the "array form" of the permutation. This is entered + in brackets as the argument to the Permutation class: + + >>> p = Permutation([0, 2, 1]); p + Permutation([0, 2, 1]) + + Given i in range(p.size), the permutation maps i to i^p + + >>> [i^p for i in range(p.size)] + [0, 2, 1] + + The composite of two permutations p*q means first apply p, then q, so + i^(p*q) = (i^p)^q which is i^p^q according to Python precedence rules: + + >>> q = Permutation([2, 1, 0]) + >>> [i^p^q for i in range(3)] + [2, 0, 1] + >>> [i^(p*q) for i in range(3)] + [2, 0, 1] + + One can use also the notation p(i) = i^p, but then the composition + rule is (p*q)(i) = q(p(i)), not p(q(i)): + + >>> [(p*q)(i) for i in range(p.size)] + [2, 0, 1] + >>> [q(p(i)) for i in range(p.size)] + [2, 0, 1] + >>> [p(q(i)) for i in range(p.size)] + [1, 2, 0] + + Disjoint Cycle Notation + ----------------------- + + In disjoint cycle notation, only the elements that have shifted are + indicated. + + For example, [1, 3, 2, 0] can be represented as (0, 1, 3)(2). + This can be understood from the 2 line format of the given permutation. + In the 2-line form, + [0 1 2 3] + [1 3 2 0] + + The element in the 0th position is 1, so 0 -> 1. The element in the 1st + position is three, so 1 -> 3. And the element in the third position is again + 0, so 3 -> 0. Thus, 0 -> 1 -> 3 -> 0, and 2 -> 2. Thus, this can be represented + as 2 cycles: (0, 1, 3)(2). + In common notation, singular cycles are not explicitly written as they can be + inferred implicitly. + + Only the relative ordering of elements in a cycle matter: + + >>> Permutation(1,2,3) == Permutation(2,3,1) == Permutation(3,1,2) + True + + The disjoint cycle notation is convenient when representing + permutations that have several cycles in them: + + >>> Permutation(1, 2)(3, 5) == Permutation([[1, 2], [3, 5]]) + True + + It also provides some economy in entry when computing products of + permutations that are written in disjoint cycle notation: + + >>> Permutation(1, 2)(1, 3)(2, 3) + Permutation([0, 3, 2, 1]) + >>> _ == Permutation([[1, 2]])*Permutation([[1, 3]])*Permutation([[2, 3]]) + True + + Caution: when the cycles have common elements between them then the order + in which the permutations are applied matters. This module applies + the permutations from *left to right*. + + >>> Permutation(1, 2)(2, 3) == Permutation([(1, 2), (2, 3)]) + True + >>> Permutation(1, 2)(2, 3).list() + [0, 3, 1, 2] + + In the above case, (1,2) is computed before (2,3). + As 0 -> 0, 0 -> 0, element in position 0 is 0. + As 1 -> 2, 2 -> 3, element in position 1 is 3. + As 2 -> 1, 1 -> 1, element in position 2 is 1. + As 3 -> 3, 3 -> 2, element in position 3 is 2. + + If the first and second elements had been + swapped first, followed by the swapping of the second + and third, the result would have been [0, 2, 3, 1]. + If, you want to apply the cycles in the conventional + right to left order, call the function with arguments in reverse order + as demonstrated below: + + >>> Permutation([(1, 2), (2, 3)][::-1]).list() + [0, 2, 3, 1] + + Entering a singleton in a permutation is a way to indicate the size of the + permutation. The ``size`` keyword can also be used. + + Array-form entry: + + >>> Permutation([[1, 2], [9]]) + Permutation([0, 2, 1], size=10) + >>> Permutation([[1, 2]], size=10) + Permutation([0, 2, 1], size=10) + + Cyclic-form entry: + + >>> Permutation(1, 2, size=10) + Permutation([0, 2, 1], size=10) + >>> Permutation(9)(1, 2) + Permutation([0, 2, 1], size=10) + + Caution: no singleton containing an element larger than the largest + in any previous cycle can be entered. This is an important difference + in how Permutation and Cycle handle the ``__call__`` syntax. A singleton + argument at the start of a Permutation performs instantiation of the + Permutation and is permitted: + + >>> Permutation(5) + Permutation([], size=6) + + A singleton entered after instantiation is a call to the permutation + -- a function call -- and if the argument is out of range it will + trigger an error. For this reason, it is better to start the cycle + with the singleton: + + The following fails because there is no element 3: + + >>> Permutation(1, 2)(3) + Traceback (most recent call last): + ... + IndexError: list index out of range + + This is ok: only the call to an out of range singleton is prohibited; + otherwise the permutation autosizes: + + >>> Permutation(3)(1, 2) + Permutation([0, 2, 1, 3]) + >>> Permutation(1, 2)(3, 4) == Permutation(3, 4)(1, 2) + True + + + Equality testing + ---------------- + + The array forms must be the same in order for permutations to be equal: + + >>> Permutation([1, 0, 2, 3]) == Permutation([1, 0]) + False + + + Identity Permutation + -------------------- + + The identity permutation is a permutation in which no element is out of + place. It can be entered in a variety of ways. All the following create + an identity permutation of size 4: + + >>> I = Permutation([0, 1, 2, 3]) + >>> all(p == I for p in [ + ... Permutation(3), + ... Permutation(range(4)), + ... Permutation([], size=4), + ... Permutation(size=4)]) + True + + Watch out for entering the range *inside* a set of brackets (which is + cycle notation): + + >>> I == Permutation([range(4)]) + False + + + Permutation Printing + ==================== + + There are a few things to note about how Permutations are printed. + + .. deprecated:: 1.6 + + Configuring Permutation printing by setting + ``Permutation.print_cyclic`` is deprecated. Users should use the + ``perm_cyclic`` flag to the printers, as described below. + + 1) If you prefer one form (array or cycle) over another, you can set + ``init_printing`` with the ``perm_cyclic`` flag. + + >>> from sympy import init_printing + >>> p = Permutation(1, 2)(4, 5)(3, 4) + >>> p + Permutation([0, 2, 1, 4, 5, 3]) + + >>> init_printing(perm_cyclic=True, pretty_print=False) + >>> p + (1 2)(3 4 5) + + 2) Regardless of the setting, a list of elements in the array for cyclic + form can be obtained and either of those can be copied and supplied as + the argument to Permutation: + + >>> p.array_form + [0, 2, 1, 4, 5, 3] + >>> p.cyclic_form + [[1, 2], [3, 4, 5]] + >>> Permutation(_) == p + True + + 3) Printing is economical in that as little as possible is printed while + retaining all information about the size of the permutation: + + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> Permutation([1, 0, 2, 3]) + Permutation([1, 0, 2, 3]) + >>> Permutation([1, 0, 2, 3], size=20) + Permutation([1, 0], size=20) + >>> Permutation([1, 0, 2, 4, 3, 5, 6], size=20) + Permutation([1, 0, 2, 4, 3], size=20) + + >>> p = Permutation([1, 0, 2, 3]) + >>> init_printing(perm_cyclic=True, pretty_print=False) + >>> p + (3)(0 1) + >>> init_printing(perm_cyclic=False, pretty_print=False) + + The 2 was not printed but it is still there as can be seen with the + array_form and size methods: + + >>> p.array_form + [1, 0, 2, 3] + >>> p.size + 4 + + Short introduction to other methods + =================================== + + The permutation can act as a bijective function, telling what element is + located at a given position + + >>> q = Permutation([5, 2, 3, 4, 1, 0]) + >>> q.array_form[1] # the hard way + 2 + >>> q(1) # the easy way + 2 + >>> {i: q(i) for i in range(q.size)} # showing the bijection + {0: 5, 1: 2, 2: 3, 3: 4, 4: 1, 5: 0} + + The full cyclic form (including singletons) can be obtained: + + >>> p.full_cyclic_form + [[0, 1], [2], [3]] + + Any permutation can be factored into transpositions of pairs of elements: + + >>> Permutation([[1, 2], [3, 4, 5]]).transpositions() + [(1, 2), (3, 5), (3, 4)] + >>> Permutation.rmul(*[Permutation([ti], size=6) for ti in _]).cyclic_form + [[1, 2], [3, 4, 5]] + + The number of permutations on a set of n elements is given by n! and is + called the cardinality. + + >>> p.size + 4 + >>> p.cardinality + 24 + + A given permutation has a rank among all the possible permutations of the + same elements, but what that rank is depends on how the permutations are + enumerated. (There are a number of different methods of doing so.) The + lexicographic rank is given by the rank method and this rank is used to + increment a permutation with addition/subtraction: + + >>> p.rank() + 6 + >>> p + 1 + Permutation([1, 0, 3, 2]) + >>> p.next_lex() + Permutation([1, 0, 3, 2]) + >>> _.rank() + 7 + >>> p.unrank_lex(p.size, rank=7) + Permutation([1, 0, 3, 2]) + + The product of two permutations p and q is defined as their composition as + functions, (p*q)(i) = q(p(i)) [6]_. + + >>> p = Permutation([1, 0, 2, 3]) + >>> q = Permutation([2, 3, 1, 0]) + >>> list(q*p) + [2, 3, 0, 1] + >>> list(p*q) + [3, 2, 1, 0] + >>> [q(p(i)) for i in range(p.size)] + [3, 2, 1, 0] + + The permutation can be 'applied' to any list-like object, not only + Permutations: + + >>> p(['zero', 'one', 'four', 'two']) + ['one', 'zero', 'four', 'two'] + >>> p('zo42') + ['o', 'z', '4', '2'] + + If you have a list of arbitrary elements, the corresponding permutation + can be found with the from_sequence method: + + >>> Permutation.from_sequence('SymPy') + Permutation([1, 3, 2, 0, 4]) + + Checking if a Permutation is contained in a Group + ================================================= + + Generally if you have a group of permutations G on n symbols, and + you're checking if a permutation on less than n symbols is part + of that group, the check will fail. + + Here is an example for n=5 and we check if the cycle + (1,2,3) is in G: + + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=True, pretty_print=False) + >>> from sympy.combinatorics import Cycle, Permutation + >>> from sympy.combinatorics.perm_groups import PermutationGroup + >>> G = PermutationGroup(Cycle(2, 3)(4, 5), Cycle(1, 2, 3, 4, 5)) + >>> p1 = Permutation(Cycle(2, 5, 3)) + >>> p2 = Permutation(Cycle(1, 2, 3)) + >>> a1 = Permutation(Cycle(1, 2, 3).list(6)) + >>> a2 = Permutation(Cycle(1, 2, 3)(5)) + >>> a3 = Permutation(Cycle(1, 2, 3),size=6) + >>> for p in [p1,p2,a1,a2,a3]: p, G.contains(p) + ((2 5 3), True) + ((1 2 3), False) + ((5)(1 2 3), True) + ((5)(1 2 3), True) + ((5)(1 2 3), True) + + The check for p2 above will fail. + + Checking if p1 is in G works because SymPy knows + G is a group on 5 symbols, and p1 is also on 5 symbols + (its largest element is 5). + + For ``a1``, the ``.list(6)`` call will extend the permutation to 5 + symbols, so the test will work as well. In the case of ``a2`` the + permutation is being extended to 5 symbols by using a singleton, + and in the case of ``a3`` it's extended through the constructor + argument ``size=6``. + + There is another way to do this, which is to tell the ``contains`` + method that the number of symbols the group is on does not need to + match perfectly the number of symbols for the permutation: + + >>> G.contains(p2,strict=False) + True + + This can be via the ``strict`` argument to the ``contains`` method, + and SymPy will try to extend the permutation on its own and then + perform the containment check. + + See Also + ======== + + Cycle + + References + ========== + + .. [1] Skiena, S. 'Permutations.' 1.1 in Implementing Discrete Mathematics + Combinatorics and Graph Theory with Mathematica. Reading, MA: + Addison-Wesley, pp. 3-16, 1990. + + .. [2] Knuth, D. E. The Art of Computer Programming, Vol. 4: Combinatorial + Algorithms, 1st ed. Reading, MA: Addison-Wesley, 2011. + + .. [3] Wendy Myrvold and Frank Ruskey. 2001. Ranking and unranking + permutations in linear time. Inf. Process. Lett. 79, 6 (September 2001), + 281-284. DOI=10.1016/S0020-0190(01)00141-7 + + .. [4] D. L. Kreher, D. R. Stinson 'Combinatorial Algorithms' + CRC Press, 1999 + + .. [5] Graham, R. L.; Knuth, D. E.; and Patashnik, O. + Concrete Mathematics: A Foundation for Computer Science, 2nd ed. + Reading, MA: Addison-Wesley, 1994. + + .. [6] https://en.wikipedia.org/w/index.php?oldid=499948155#Product_and_inverse + + .. [7] https://en.wikipedia.org/wiki/Lehmer_code + + """ + + is_Permutation = True + + _array_form = None + _cyclic_form = None + _cycle_structure = None + _size = None + _rank = None + + def __new__(cls, *args, size=None, **kwargs): + """ + Constructor for the Permutation object from a list or a + list of lists in which all elements of the permutation may + appear only once. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + + Permutations entered in array-form are left unaltered: + + >>> Permutation([0, 2, 1]) + Permutation([0, 2, 1]) + + Permutations entered in cyclic form are converted to array form; + singletons need not be entered, but can be entered to indicate the + largest element: + + >>> Permutation([[4, 5, 6], [0, 1]]) + Permutation([1, 0, 2, 3, 5, 6, 4]) + >>> Permutation([[4, 5, 6], [0, 1], [19]]) + Permutation([1, 0, 2, 3, 5, 6, 4], size=20) + + All manipulation of permutations assumes that the smallest element + is 0 (in keeping with 0-based indexing in Python) so if the 0 is + missing when entering a permutation in array form, an error will be + raised: + + >>> Permutation([2, 1]) + Traceback (most recent call last): + ... + ValueError: Integers 0 through 2 must be present. + + If a permutation is entered in cyclic form, it can be entered without + singletons and the ``size`` specified so those values can be filled + in, otherwise the array form will only extend to the maximum value + in the cycles: + + >>> Permutation([[1, 4], [3, 5, 2]], size=10) + Permutation([0, 4, 3, 5, 1, 2], size=10) + >>> _.array_form + [0, 4, 3, 5, 1, 2, 6, 7, 8, 9] + """ + if size is not None: + size = int(size) + + #a) () + #b) (1) = identity + #c) (1, 2) = cycle + #d) ([1, 2, 3]) = array form + #e) ([[1, 2]]) = cyclic form + #f) (Cycle) = conversion to permutation + #g) (Permutation) = adjust size or return copy + ok = True + if not args: # a + return cls._af_new(list(range(size or 0))) + elif len(args) > 1: # c + return cls._af_new(Cycle(*args).list(size)) + if len(args) == 1: + a = args[0] + if isinstance(a, cls): # g + if size is None or size == a.size: + return a + return cls(a.array_form, size=size) + if isinstance(a, Cycle): # f + return cls._af_new(a.list(size)) + if not is_sequence(a): # b + if size is not None and a + 1 > size: + raise ValueError('size is too small when max is %s' % a) + return cls._af_new(list(range(a + 1))) + if has_variety(is_sequence(ai) for ai in a): + ok = False + else: + ok = False + if not ok: + raise ValueError("Permutation argument must be a list of ints, " + "a list of lists, Permutation or Cycle.") + + # safe to assume args are valid; this also makes a copy + # of the args + args = list(args[0]) + + is_cycle = args and is_sequence(args[0]) + if is_cycle: # e + args = [[int(i) for i in c] for c in args] + else: # d + args = [int(i) for i in args] + + # if there are n elements present, 0, 1, ..., n-1 should be present + # unless a cycle notation has been provided. A 0 will be added + # for convenience in case one wants to enter permutations where + # counting starts from 1. + + temp = flatten(args) + if has_dups(temp) and not is_cycle: + raise ValueError('there were repeated elements.') + temp = set(temp) + + if not is_cycle: + if temp != set(range(len(temp))): + raise ValueError('Integers 0 through %s must be present.' % + max(temp)) + if size is not None and temp and max(temp) + 1 > size: + raise ValueError('max element should not exceed %s' % (size - 1)) + + if is_cycle: + # it's not necessarily canonical so we won't store + # it -- use the array form instead + c = Cycle() + for ci in args: + c = c(*ci) + aform = c.list() + else: + aform = list(args) + if size and size > len(aform): + # don't allow for truncation of permutation which + # might split a cycle and lead to an invalid aform + # but do allow the permutation size to be increased + aform.extend(list(range(len(aform), size))) + + return cls._af_new(aform) + + @classmethod + def _af_new(cls, perm): + """A method to produce a Permutation object from a list; + the list is bound to the _array_form attribute, so it must + not be modified; this method is meant for internal use only; + the list ``a`` is supposed to be generated as a temporary value + in a method, so p = Perm._af_new(a) is the only object + to hold a reference to ``a``:: + + Examples + ======== + + >>> from sympy.combinatorics.permutations import Perm + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> a = [2, 1, 3, 0] + >>> p = Perm._af_new(a) + >>> p + Permutation([2, 1, 3, 0]) + + """ + p = super().__new__(cls) + p._array_form = perm + p._size = len(perm) + return p + + def copy(self): + return self.__class__(self.array_form) + + def __getnewargs__(self): + return (self.array_form,) + + def _hashable_content(self): + # the array_form (a list) is the Permutation arg, so we need to + # return a tuple, instead + return tuple(self.array_form) + + @property + def array_form(self): + """ + Return a copy of the attribute _array_form + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([[2, 0], [3, 1]]) + >>> p.array_form + [2, 3, 0, 1] + >>> Permutation([[2, 0, 3, 1]]).array_form + [3, 2, 0, 1] + >>> Permutation([2, 0, 3, 1]).array_form + [2, 0, 3, 1] + >>> Permutation([[1, 2], [4, 5]]).array_form + [0, 2, 1, 3, 5, 4] + """ + return self._array_form[:] + + def list(self, size=None): + """Return the permutation as an explicit list, possibly + trimming unmoved elements if size is less than the maximum + element in the permutation; if this is desired, setting + ``size=-1`` will guarantee such trimming. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation(2, 3)(4, 5) + >>> p.list() + [0, 1, 3, 2, 5, 4] + >>> p.list(10) + [0, 1, 3, 2, 5, 4, 6, 7, 8, 9] + + Passing a length too small will trim trailing, unchanged elements + in the permutation: + + >>> Permutation(2, 4)(1, 2, 4).list(-1) + [0, 2, 1] + >>> Permutation(3).list(-1) + [] + """ + if not self and size is None: + raise ValueError('must give size for empty Cycle') + rv = self.array_form + if size is not None: + if size > self.size: + rv.extend(list(range(self.size, size))) + else: + # find first value from rhs where rv[i] != i + i = self.size - 1 + while rv: + if rv[-1] != i: + break + rv.pop() + i -= 1 + return rv + + @property + def cyclic_form(self): + """ + This is used to convert to the cyclic notation + from the canonical notation. Singletons are omitted. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 3, 1, 2]) + >>> p.cyclic_form + [[1, 3, 2]] + >>> Permutation([1, 0, 2, 4, 3, 5]).cyclic_form + [[0, 1], [3, 4]] + + See Also + ======== + + array_form, full_cyclic_form + """ + if self._cyclic_form is not None: + return list(self._cyclic_form) + array_form = self.array_form + unchecked = [True] * len(array_form) + cyclic_form = [] + for i in range(len(array_form)): + if unchecked[i]: + cycle = [] + cycle.append(i) + unchecked[i] = False + j = i + while unchecked[array_form[j]]: + j = array_form[j] + cycle.append(j) + unchecked[j] = False + if len(cycle) > 1: + cyclic_form.append(cycle) + assert cycle == list(minlex(cycle)) + cyclic_form.sort() + self._cyclic_form = cyclic_form.copy() + return cyclic_form + + @property + def full_cyclic_form(self): + """Return permutation in cyclic form including singletons. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation([0, 2, 1]).full_cyclic_form + [[0], [1, 2]] + """ + need = set(range(self.size)) - set(flatten(self.cyclic_form)) + rv = self.cyclic_form + [[i] for i in need] + rv.sort() + return rv + + @property + def size(self): + """ + Returns the number of elements in the permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation([[3, 2], [0, 1]]).size + 4 + + See Also + ======== + + cardinality, length, order, rank + """ + return self._size + + def support(self): + """Return the elements in permutation, P, for which P[i] != i. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([[3, 2], [0, 1], [4]]) + >>> p.array_form + [1, 0, 3, 2, 4] + >>> p.support() + [0, 1, 2, 3] + """ + a = self.array_form + return [i for i, e in enumerate(a) if e != i] + + def __add__(self, other): + """Return permutation that is other higher in rank than self. + + The rank is the lexicographical rank, with the identity permutation + having rank of 0. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> I = Permutation([0, 1, 2, 3]) + >>> a = Permutation([2, 1, 3, 0]) + >>> I + a.rank() == a + True + + See Also + ======== + + __sub__, inversion_vector + + """ + rank = (self.rank() + other) % self.cardinality + rv = self.unrank_lex(self.size, rank) + rv._rank = rank + return rv + + def __sub__(self, other): + """Return the permutation that is other lower in rank than self. + + See Also + ======== + + __add__ + """ + return self.__add__(-other) + + @staticmethod + def rmul(*args): + """ + Return product of Permutations [a, b, c, ...] as the Permutation whose + ith value is a(b(c(i))). + + a, b, c, ... can be Permutation objects or tuples. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + + >>> a, b = [1, 0, 2], [0, 2, 1] + >>> a = Permutation(a); b = Permutation(b) + >>> list(Permutation.rmul(a, b)) + [1, 2, 0] + >>> [a(b(i)) for i in range(3)] + [1, 2, 0] + + This handles the operands in reverse order compared to the ``*`` operator: + + >>> a = Permutation(a); b = Permutation(b) + >>> list(a*b) + [2, 0, 1] + >>> [b(a(i)) for i in range(3)] + [2, 0, 1] + + Notes + ===== + + All items in the sequence will be parsed by Permutation as + necessary as long as the first item is a Permutation: + + >>> Permutation.rmul(a, [0, 2, 1]) == Permutation.rmul(a, b) + True + + The reverse order of arguments will raise a TypeError. + + """ + rv = args[0] + for i in range(1, len(args)): + rv = args[i]*rv + return rv + + @classmethod + def rmul_with_af(cls, *args): + """ + same as rmul, but the elements of args are Permutation objects + which have _array_form + """ + a = [x._array_form for x in args] + rv = cls._af_new(_af_rmuln(*a)) + return rv + + def mul_inv(self, other): + """ + other*~self, self and other have _array_form + """ + a = _af_invert(self._array_form) + b = other._array_form + return self._af_new(_af_rmul(a, b)) + + def __rmul__(self, other): + """This is needed to coerce other to Permutation in rmul.""" + cls = type(self) + return cls(other)*self + + def __mul__(self, other): + """ + Return the product a*b as a Permutation; the ith value is b(a(i)). + + Examples + ======== + + >>> from sympy.combinatorics.permutations import _af_rmul, Permutation + + >>> a, b = [1, 0, 2], [0, 2, 1] + >>> a = Permutation(a); b = Permutation(b) + >>> list(a*b) + [2, 0, 1] + >>> [b(a(i)) for i in range(3)] + [2, 0, 1] + + This handles operands in reverse order compared to _af_rmul and rmul: + + >>> al = list(a); bl = list(b) + >>> _af_rmul(al, bl) + [1, 2, 0] + >>> [al[bl[i]] for i in range(3)] + [1, 2, 0] + + It is acceptable for the arrays to have different lengths; the shorter + one will be padded to match the longer one: + + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> b*Permutation([1, 0]) + Permutation([1, 2, 0]) + >>> Permutation([1, 0])*b + Permutation([2, 0, 1]) + + It is also acceptable to allow coercion to handle conversion of a + single list to the left of a Permutation: + + >>> [0, 1]*a # no change: 2-element identity + Permutation([1, 0, 2]) + >>> [[0, 1]]*a # exchange first two elements + Permutation([0, 1, 2]) + + You cannot use more than 1 cycle notation in a product of cycles + since coercion can only handle one argument to the left. To handle + multiple cycles it is convenient to use Cycle instead of Permutation: + + >>> [[1, 2]]*[[2, 3]]*Permutation([]) # doctest: +SKIP + >>> from sympy.combinatorics.permutations import Cycle + >>> Cycle(1, 2)(2, 3) + (1 3 2) + + """ + from sympy.combinatorics.perm_groups import PermutationGroup, Coset + if isinstance(other, PermutationGroup): + return Coset(self, other, dir='-') + a = self.array_form + # __rmul__ makes sure the other is a Permutation + b = other.array_form + if not b: + perm = a + else: + b.extend(list(range(len(b), len(a)))) + perm = [b[i] for i in a] + b[len(a):] + return self._af_new(perm) + + def commutes_with(self, other): + """ + Checks if the elements are commuting. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> a = Permutation([1, 4, 3, 0, 2, 5]) + >>> b = Permutation([0, 1, 2, 3, 4, 5]) + >>> a.commutes_with(b) + True + >>> b = Permutation([2, 3, 5, 4, 1, 0]) + >>> a.commutes_with(b) + False + """ + a = self.array_form + b = other.array_form + return _af_commutes_with(a, b) + + def __pow__(self, n): + """ + Routine for finding powers of a permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> p = Permutation([2, 0, 3, 1]) + >>> p.order() + 4 + >>> p**4 + Permutation([0, 1, 2, 3]) + """ + if isinstance(n, Permutation): + raise NotImplementedError( + 'p**p is not defined; do you mean p^p (conjugate)?') + n = int(n) + return self._af_new(_af_pow(self.array_form, n)) + + def __rxor__(self, i): + """Return self(i) when ``i`` is an int. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation(1, 2, 9) + >>> 2^p == p(2) == 9 + True + """ + if int_valued(i): + return self(i) + else: + raise NotImplementedError( + "i^p = p(i) when i is an integer, not %s." % i) + + def __xor__(self, h): + """Return the conjugate permutation ``~h*self*h` `. + + Explanation + =========== + + If ``a`` and ``b`` are conjugates, ``a = h*b*~h`` and + ``b = ~h*a*h`` and both have the same cycle structure. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation(1, 2, 9) + >>> q = Permutation(6, 9, 8) + >>> p*q != q*p + True + + Calculate and check properties of the conjugate: + + >>> c = p^q + >>> c == ~q*p*q and p == q*c*~q + True + + The expression q^p^r is equivalent to q^(p*r): + + >>> r = Permutation(9)(4, 6, 8) + >>> q^p^r == q^(p*r) + True + + If the term to the left of the conjugate operator, i, is an integer + then this is interpreted as selecting the ith element from the + permutation to the right: + + >>> all(i^p == p(i) for i in range(p.size)) + True + + Note that the * operator as higher precedence than the ^ operator: + + >>> q^r*p^r == q^(r*p)^r == Permutation(9)(1, 6, 4) + True + + Notes + ===== + + In Python the precedence rule is p^q^r = (p^q)^r which differs + in general from p^(q^r) + + >>> q^p^r + (9)(1 4 8) + >>> q^(p^r) + (9)(1 8 6) + + For a given r and p, both of the following are conjugates of p: + ~r*p*r and r*p*~r. But these are not necessarily the same: + + >>> ~r*p*r == r*p*~r + True + + >>> p = Permutation(1, 2, 9)(5, 6) + >>> ~r*p*r == r*p*~r + False + + The conjugate ~r*p*r was chosen so that ``p^q^r`` would be equivalent + to ``p^(q*r)`` rather than ``p^(r*q)``. To obtain r*p*~r, pass ~r to + this method: + + >>> p^~r == r*p*~r + True + """ + + if self.size != h.size: + raise ValueError("The permutations must be of equal size.") + a = [None]*self.size + h = h._array_form + p = self._array_form + for i in range(self.size): + a[h[i]] = h[p[i]] + return self._af_new(a) + + def transpositions(self): + """ + Return the permutation decomposed into a list of transpositions. + + Explanation + =========== + + It is always possible to express a permutation as the product of + transpositions, see [1] + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([[1, 2, 3], [0, 4, 5, 6, 7]]) + >>> t = p.transpositions() + >>> t + [(0, 7), (0, 6), (0, 5), (0, 4), (1, 3), (1, 2)] + >>> print(''.join(str(c) for c in t)) + (0, 7)(0, 6)(0, 5)(0, 4)(1, 3)(1, 2) + >>> Permutation.rmul(*[Permutation([ti], size=p.size) for ti in t]) == p + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Transposition_%28mathematics%29#Properties + + """ + a = self.cyclic_form + res = [] + for x in a: + nx = len(x) + if nx == 2: + res.append(tuple(x)) + elif nx > 2: + first = x[0] + res.extend((first, y) for y in x[nx - 1:0:-1]) + return res + + @classmethod + def from_sequence(self, i, key=None): + """Return the permutation needed to obtain ``i`` from the sorted + elements of ``i``. If custom sorting is desired, a key can be given. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + + >>> Permutation.from_sequence('SymPy') + (4)(0 1 3) + >>> _(sorted("SymPy")) + ['S', 'y', 'm', 'P', 'y'] + >>> Permutation.from_sequence('SymPy', key=lambda x: x.lower()) + (4)(0 2)(1 3) + """ + ic = list(zip(i, list(range(len(i))))) + if key: + ic.sort(key=lambda x: key(x[0])) + else: + ic.sort() + return ~Permutation([i[1] for i in ic]) + + def __invert__(self): + """ + Return the inverse of the permutation. + + A permutation multiplied by its inverse is the identity permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> p = Permutation([[2, 0], [3, 1]]) + >>> ~p + Permutation([2, 3, 0, 1]) + >>> _ == p**-1 + True + >>> p*~p == ~p*p == Permutation([0, 1, 2, 3]) + True + """ + return self._af_new(_af_invert(self._array_form)) + + def __iter__(self): + """Yield elements from array form. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> list(Permutation(range(3))) + [0, 1, 2] + """ + yield from self.array_form + + def __repr__(self): + return srepr(self) + + def __call__(self, *i): + """ + Allows applying a permutation instance as a bijective function. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([[2, 0], [3, 1]]) + >>> p.array_form + [2, 3, 0, 1] + >>> [p(i) for i in range(4)] + [2, 3, 0, 1] + + If an array is given then the permutation selects the items + from the array (i.e. the permutation is applied to the array): + + >>> from sympy.abc import x + >>> p([x, 1, 0, x**2]) + [0, x**2, x, 1] + """ + # list indices can be Integer or int; leave this + # as it is (don't test or convert it) because this + # gets called a lot and should be fast + if len(i) == 1: + i = i[0] + if not isinstance(i, Iterable): + i = as_int(i) + if i < 0 or i > self.size: + raise TypeError( + "{} should be an integer between 0 and {}" + .format(i, self.size-1)) + return self._array_form[i] + # P([a, b, c]) + if len(i) != self.size: + raise TypeError( + "{} should have the length {}.".format(i, self.size)) + return [i[j] for j in self._array_form] + # P(1, 2, 3) + return self*Permutation(Cycle(*i), size=self.size) + + def atoms(self): + """ + Returns all the elements of a permutation + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation([0, 1, 2, 3, 4, 5]).atoms() + {0, 1, 2, 3, 4, 5} + >>> Permutation([[0, 1], [2, 3], [4, 5]]).atoms() + {0, 1, 2, 3, 4, 5} + """ + return set(self.array_form) + + def apply(self, i): + r"""Apply the permutation to an expression. + + Parameters + ========== + + i : Expr + It should be an integer between $0$ and $n-1$ where $n$ + is the size of the permutation. + + If it is a symbol or a symbolic expression that can + have integer values, an ``AppliedPermutation`` object + will be returned which can represent an unevaluated + function. + + Notes + ===== + + Any permutation can be defined as a bijective function + $\sigma : \{ 0, 1, \dots, n-1 \} \rightarrow \{ 0, 1, \dots, n-1 \}$ + where $n$ denotes the size of the permutation. + + The definition may even be extended for any set with distinctive + elements, such that the permutation can even be applied for + real numbers or such, however, it is not implemented for now for + computational reasons and the integrity with the group theory + module. + + This function is similar to the ``__call__`` magic, however, + ``__call__`` magic already has some other applications like + permuting an array or attaching new cycles, which would + not always be mathematically consistent. + + This also guarantees that the return type is a SymPy integer, + which guarantees the safety to use assumptions. + """ + i = _sympify(i) + if i.is_integer is False: + raise NotImplementedError("{} should be an integer.".format(i)) + + n = self.size + if (i < 0) == True or (i >= n) == True: + raise NotImplementedError( + "{} should be an integer between 0 and {}".format(i, n-1)) + + if i.is_Integer: + return Integer(self._array_form[i]) + return AppliedPermutation(self, i) + + def next_lex(self): + """ + Returns the next permutation in lexicographical order. + If self is the last permutation in lexicographical order + it returns None. + See [4] section 2.4. + + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([2, 3, 1, 0]) + >>> p = Permutation([2, 3, 1, 0]); p.rank() + 17 + >>> p = p.next_lex(); p.rank() + 18 + + See Also + ======== + + rank, unrank_lex + """ + perm = self.array_form[:] + n = len(perm) + i = n - 2 + while perm[i + 1] < perm[i]: + i -= 1 + if i == -1: + return None + else: + j = n - 1 + while perm[j] < perm[i]: + j -= 1 + perm[j], perm[i] = perm[i], perm[j] + i += 1 + j = n - 1 + while i < j: + perm[j], perm[i] = perm[i], perm[j] + i += 1 + j -= 1 + return self._af_new(perm) + + @classmethod + def unrank_nonlex(self, n, r): + """ + This is a linear time unranking algorithm that does not + respect lexicographic order [3]. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> Permutation.unrank_nonlex(4, 5) + Permutation([2, 0, 3, 1]) + >>> Permutation.unrank_nonlex(4, -1) + Permutation([0, 1, 2, 3]) + + See Also + ======== + + next_nonlex, rank_nonlex + """ + def _unrank1(n, r, a): + if n > 0: + a[n - 1], a[r % n] = a[r % n], a[n - 1] + _unrank1(n - 1, r//n, a) + + id_perm = list(range(n)) + n = int(n) + r = r % ifac(n) + _unrank1(n, r, id_perm) + return self._af_new(id_perm) + + def rank_nonlex(self, inv_perm=None): + """ + This is a linear time ranking algorithm that does not + enforce lexicographic order [3]. + + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2, 3]) + >>> p.rank_nonlex() + 23 + + See Also + ======== + + next_nonlex, unrank_nonlex + """ + def _rank1(n, perm, inv_perm): + if n == 1: + return 0 + s = perm[n - 1] + t = inv_perm[n - 1] + perm[n - 1], perm[t] = perm[t], s + inv_perm[n - 1], inv_perm[s] = inv_perm[s], t + return s + n*_rank1(n - 1, perm, inv_perm) + + if inv_perm is None: + inv_perm = (~self).array_form + if not inv_perm: + return 0 + perm = self.array_form[:] + r = _rank1(len(perm), perm, inv_perm) + return r + + def next_nonlex(self): + """ + Returns the next permutation in nonlex order [3]. + If self is the last permutation in this order it returns None. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> p = Permutation([2, 0, 3, 1]); p.rank_nonlex() + 5 + >>> p = p.next_nonlex(); p + Permutation([3, 0, 1, 2]) + >>> p.rank_nonlex() + 6 + + See Also + ======== + + rank_nonlex, unrank_nonlex + """ + r = self.rank_nonlex() + if r == ifac(self.size) - 1: + return None + return self.unrank_nonlex(self.size, r + 1) + + def rank(self): + """ + Returns the lexicographic rank of the permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2, 3]) + >>> p.rank() + 0 + >>> p = Permutation([3, 2, 1, 0]) + >>> p.rank() + 23 + + See Also + ======== + + next_lex, unrank_lex, cardinality, length, order, size + """ + if self._rank is not None: + return self._rank + rank = 0 + rho = self.array_form[:] + n = self.size - 1 + size = n + 1 + psize = int(ifac(n)) + for j in range(size - 1): + rank += rho[j]*psize + for i in range(j + 1, size): + if rho[i] > rho[j]: + rho[i] -= 1 + psize //= n + n -= 1 + self._rank = rank + return rank + + @property + def cardinality(self): + """ + Returns the number of all possible permutations. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2, 3]) + >>> p.cardinality + 24 + + See Also + ======== + + length, order, rank, size + """ + return int(ifac(self.size)) + + def parity(self): + """ + Computes the parity of a permutation. + + Explanation + =========== + + The parity of a permutation reflects the parity of the + number of inversions in the permutation, i.e., the + number of pairs of x and y such that ``x > y`` but ``p[x] < p[y]``. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2, 3]) + >>> p.parity() + 0 + >>> p = Permutation([3, 2, 0, 1]) + >>> p.parity() + 1 + + See Also + ======== + + _af_parity + """ + if self._cyclic_form is not None: + return (self.size - self.cycles) % 2 + + return _af_parity(self.array_form) + + @property + def is_even(self): + """ + Checks if a permutation is even. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2, 3]) + >>> p.is_even + True + >>> p = Permutation([3, 2, 1, 0]) + >>> p.is_even + True + + See Also + ======== + + is_odd + """ + return not self.is_odd + + @property + def is_odd(self): + """ + Checks if a permutation is odd. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2, 3]) + >>> p.is_odd + False + >>> p = Permutation([3, 2, 0, 1]) + >>> p.is_odd + True + + See Also + ======== + + is_even + """ + return bool(self.parity() % 2) + + @property + def is_Singleton(self): + """ + Checks to see if the permutation contains only one number and is + thus the only possible permutation of this set of numbers + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation([0]).is_Singleton + True + >>> Permutation([0, 1]).is_Singleton + False + + See Also + ======== + + is_Empty + """ + return self.size == 1 + + @property + def is_Empty(self): + """ + Checks to see if the permutation is a set with zero elements + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation([]).is_Empty + True + >>> Permutation([0]).is_Empty + False + + See Also + ======== + + is_Singleton + """ + return self.size == 0 + + @property + def is_identity(self): + return self.is_Identity + + @property + def is_Identity(self): + """ + Returns True if the Permutation is an identity permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([]) + >>> p.is_Identity + True + >>> p = Permutation([[0], [1], [2]]) + >>> p.is_Identity + True + >>> p = Permutation([0, 1, 2]) + >>> p.is_Identity + True + >>> p = Permutation([0, 2, 1]) + >>> p.is_Identity + False + + See Also + ======== + + order + """ + af = self.array_form + return not af or all(i == af[i] for i in range(self.size)) + + def ascents(self): + """ + Returns the positions of ascents in a permutation, ie, the location + where p[i] < p[i+1] + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([4, 0, 1, 3, 2]) + >>> p.ascents() + [1, 2] + + See Also + ======== + + descents, inversions, min, max + """ + a = self.array_form + pos = [i for i in range(len(a) - 1) if a[i] < a[i + 1]] + return pos + + def descents(self): + """ + Returns the positions of descents in a permutation, ie, the location + where p[i] > p[i+1] + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([4, 0, 1, 3, 2]) + >>> p.descents() + [0, 3] + + See Also + ======== + + ascents, inversions, min, max + """ + a = self.array_form + pos = [i for i in range(len(a) - 1) if a[i] > a[i + 1]] + return pos + + def max(self) -> int: + """ + The maximum element moved by the permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([1, 0, 2, 3, 4]) + >>> p.max() + 1 + + See Also + ======== + + min, descents, ascents, inversions + """ + a = self.array_form + if not a: + return 0 + return max(_a for i, _a in enumerate(a) if _a != i) + + def min(self) -> int: + """ + The minimum element moved by the permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 4, 3, 2]) + >>> p.min() + 2 + + See Also + ======== + + max, descents, ascents, inversions + """ + a = self.array_form + if not a: + return 0 + return min(_a for i, _a in enumerate(a) if _a != i) + + def inversions(self): + """ + Computes the number of inversions of a permutation. + + Explanation + =========== + + An inversion is where i > j but p[i] < p[j]. + + For small length of p, it iterates over all i and j + values and calculates the number of inversions. + For large length of p, it uses a variation of merge + sort to calculate the number of inversions. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2, 3, 4, 5]) + >>> p.inversions() + 0 + >>> Permutation([3, 2, 1, 0]).inversions() + 6 + + See Also + ======== + + descents, ascents, min, max + + References + ========== + + .. [1] https://www.cp.eng.chula.ac.th/~prabhas//teaching/algo/algo2008/count-inv.htm + + """ + inversions = 0 + a = self.array_form + n = len(a) + if n < 130: + for i in range(n - 1): + b = a[i] + for c in a[i + 1:]: + if b > c: + inversions += 1 + else: + k = 1 + right = 0 + arr = a[:] + temp = a[:] + while k < n: + i = 0 + while i + k < n: + right = i + k * 2 - 1 + if right >= n: + right = n - 1 + inversions += _merge(arr, temp, i, i + k, right) + i = i + k * 2 + k = k * 2 + return inversions + + def commutator(self, x): + """Return the commutator of ``self`` and ``x``: ``~x*~self*x*self`` + + If f and g are part of a group, G, then the commutator of f and g + is the group identity iff f and g commute, i.e. fg == gf. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> p = Permutation([0, 2, 3, 1]) + >>> x = Permutation([2, 0, 3, 1]) + >>> c = p.commutator(x); c + Permutation([2, 1, 3, 0]) + >>> c == ~x*~p*x*p + True + + >>> I = Permutation(3) + >>> p = [I + i for i in range(6)] + >>> for i in range(len(p)): + ... for j in range(len(p)): + ... c = p[i].commutator(p[j]) + ... if p[i]*p[j] == p[j]*p[i]: + ... assert c == I + ... else: + ... assert c != I + ... + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Commutator + """ + + a = self.array_form + b = x.array_form + n = len(a) + if len(b) != n: + raise ValueError("The permutations must be of equal size.") + inva = [None]*n + for i in range(n): + inva[a[i]] = i + invb = [None]*n + for i in range(n): + invb[b[i]] = i + return self._af_new([a[b[inva[i]]] for i in invb]) + + def signature(self): + """ + Gives the signature of the permutation needed to place the + elements of the permutation in canonical order. + + The signature is calculated as (-1)^ + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2]) + >>> p.inversions() + 0 + >>> p.signature() + 1 + >>> q = Permutation([0,2,1]) + >>> q.inversions() + 1 + >>> q.signature() + -1 + + See Also + ======== + + inversions + """ + if self.is_even: + return 1 + return -1 + + def order(self): + """ + Computes the order of a permutation. + + When the permutation is raised to the power of its + order it equals the identity permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> p = Permutation([3, 1, 5, 2, 4, 0]) + >>> p.order() + 4 + >>> (p**(p.order())) + Permutation([], size=6) + + See Also + ======== + + identity, cardinality, length, rank, size + """ + + return reduce(lcm, [len(cycle) for cycle in self.cyclic_form], 1) + + def length(self): + """ + Returns the number of integers moved by a permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation([0, 3, 2, 1]).length() + 2 + >>> Permutation([[0, 1], [2, 3]]).length() + 4 + + See Also + ======== + + min, max, support, cardinality, order, rank, size + """ + + return len(self.support()) + + @property + def cycle_structure(self): + """Return the cycle structure of the permutation as a dictionary + indicating the multiplicity of each cycle length. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation(3).cycle_structure + {1: 4} + >>> Permutation(0, 4, 3)(1, 2)(5, 6).cycle_structure + {2: 2, 3: 1} + """ + if self._cycle_structure: + rv = self._cycle_structure + else: + rv = defaultdict(int) + singletons = self.size + for c in self.cyclic_form: + rv[len(c)] += 1 + singletons -= len(c) + if singletons: + rv[1] = singletons + self._cycle_structure = rv + return dict(rv) # make a copy + + @property + def cycles(self): + """ + Returns the number of cycles contained in the permutation + (including singletons). + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation([0, 1, 2]).cycles + 3 + >>> Permutation([0, 1, 2]).full_cyclic_form + [[0], [1], [2]] + >>> Permutation(0, 1)(2, 3).cycles + 2 + + See Also + ======== + sympy.functions.combinatorial.numbers.stirling + """ + return len(self.full_cyclic_form) + + def index(self): + """ + Returns the index of a permutation. + + The index of a permutation is the sum of all subscripts j such + that p[j] is greater than p[j+1]. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([3, 0, 2, 1, 4]) + >>> p.index() + 2 + """ + a = self.array_form + + return sum(j for j in range(len(a) - 1) if a[j] > a[j + 1]) + + def runs(self): + """ + Returns the runs of a permutation. + + An ascending sequence in a permutation is called a run [5]. + + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([2, 5, 7, 3, 6, 0, 1, 4, 8]) + >>> p.runs() + [[2, 5, 7], [3, 6], [0, 1, 4, 8]] + >>> q = Permutation([1,3,2,0]) + >>> q.runs() + [[1, 3], [2], [0]] + """ + return runs(self.array_form) + + def inversion_vector(self): + """Return the inversion vector of the permutation. + + The inversion vector consists of elements whose value + indicates the number of elements in the permutation + that are lesser than it and lie on its right hand side. + + The inversion vector is the same as the Lehmer encoding of a + permutation. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([4, 8, 0, 7, 1, 5, 3, 6, 2]) + >>> p.inversion_vector() + [4, 7, 0, 5, 0, 2, 1, 1] + >>> p = Permutation([3, 2, 1, 0]) + >>> p.inversion_vector() + [3, 2, 1] + + The inversion vector increases lexicographically with the rank + of the permutation, the -ith element cycling through 0..i. + + >>> p = Permutation(2) + >>> while p: + ... print('%s %s %s' % (p, p.inversion_vector(), p.rank())) + ... p = p.next_lex() + (2) [0, 0] 0 + (1 2) [0, 1] 1 + (2)(0 1) [1, 0] 2 + (0 1 2) [1, 1] 3 + (0 2 1) [2, 0] 4 + (0 2) [2, 1] 5 + + See Also + ======== + + from_inversion_vector + """ + self_array_form = self.array_form + n = len(self_array_form) + inversion_vector = [0] * (n - 1) + + for i in range(n - 1): + val = 0 + for j in range(i + 1, n): + if self_array_form[j] < self_array_form[i]: + val += 1 + inversion_vector[i] = val + return inversion_vector + + def rank_trotterjohnson(self): + """ + Returns the Trotter Johnson rank, which we get from the minimal + change algorithm. See [4] section 2.4. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 1, 2, 3]) + >>> p.rank_trotterjohnson() + 0 + >>> p = Permutation([0, 2, 1, 3]) + >>> p.rank_trotterjohnson() + 7 + + See Also + ======== + + unrank_trotterjohnson, next_trotterjohnson + """ + if self.array_form == [] or self.is_Identity: + return 0 + if self.array_form == [1, 0]: + return 1 + perm = self.array_form + n = self.size + rank = 0 + for j in range(1, n): + k = 1 + i = 0 + while perm[i] != j: + if perm[i] < j: + k += 1 + i += 1 + j1 = j + 1 + if rank % 2 == 0: + rank = j1*rank + j1 - k + else: + rank = j1*rank + k - 1 + return rank + + @classmethod + def unrank_trotterjohnson(cls, size, rank): + """ + Trotter Johnson permutation unranking. See [4] section 2.4. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> Permutation.unrank_trotterjohnson(5, 10) + Permutation([0, 3, 1, 2, 4]) + + See Also + ======== + + rank_trotterjohnson, next_trotterjohnson + """ + perm = [0]*size + r2 = 0 + n = ifac(size) + pj = 1 + for j in range(2, size + 1): + pj *= j + r1 = (rank * pj) // n + k = r1 - j*r2 + if r2 % 2 == 0: + for i in range(j - 1, j - k - 1, -1): + perm[i] = perm[i - 1] + perm[j - k - 1] = j - 1 + else: + for i in range(j - 1, k, -1): + perm[i] = perm[i - 1] + perm[k] = j - 1 + r2 = r1 + return cls._af_new(perm) + + def next_trotterjohnson(self): + """ + Returns the next permutation in Trotter-Johnson order. + If self is the last permutation it returns None. + See [4] section 2.4. If it is desired to generate all such + permutations, they can be generated in order more quickly + with the ``generate_bell`` function. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> p = Permutation([3, 0, 2, 1]) + >>> p.rank_trotterjohnson() + 4 + >>> p = p.next_trotterjohnson(); p + Permutation([0, 3, 2, 1]) + >>> p.rank_trotterjohnson() + 5 + + See Also + ======== + + rank_trotterjohnson, unrank_trotterjohnson, sympy.utilities.iterables.generate_bell + """ + pi = self.array_form[:] + n = len(pi) + st = 0 + rho = pi[:] + done = False + m = n-1 + while m > 0 and not done: + d = rho.index(m) + for i in range(d, m): + rho[i] = rho[i + 1] + par = _af_parity(rho[:m]) + if par == 1: + if d == m: + m -= 1 + else: + pi[st + d], pi[st + d + 1] = pi[st + d + 1], pi[st + d] + done = True + else: + if d == 0: + m -= 1 + st += 1 + else: + pi[st + d], pi[st + d - 1] = pi[st + d - 1], pi[st + d] + done = True + if m == 0: + return None + return self._af_new(pi) + + def get_precedence_matrix(self): + """ + Gets the precedence matrix. This is used for computing the + distance between two permutations. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> p = Permutation.josephus(3, 6, 1) + >>> p + Permutation([2, 5, 3, 1, 4, 0]) + >>> p.get_precedence_matrix() + Matrix([ + [0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 1, 0], + [1, 1, 0, 1, 1, 1], + [1, 1, 0, 0, 1, 0], + [1, 0, 0, 0, 0, 0], + [1, 1, 0, 1, 1, 0]]) + + See Also + ======== + + get_precedence_distance, get_adjacency_matrix, get_adjacency_distance + """ + m = zeros(self.size) + perm = self.array_form + for i in range(m.rows): + for j in range(i + 1, m.cols): + m[perm[i], perm[j]] = 1 + return m + + def get_precedence_distance(self, other): + """ + Computes the precedence distance between two permutations. + + Explanation + =========== + + Suppose p and p' represent n jobs. The precedence metric + counts the number of times a job j is preceded by job i + in both p and p'. This metric is commutative. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([2, 0, 4, 3, 1]) + >>> q = Permutation([3, 1, 2, 4, 0]) + >>> p.get_precedence_distance(q) + 7 + >>> q.get_precedence_distance(p) + 7 + + See Also + ======== + + get_precedence_matrix, get_adjacency_matrix, get_adjacency_distance + """ + if self.size != other.size: + raise ValueError("The permutations must be of equal size.") + self_prec_mat = self.get_precedence_matrix() + other_prec_mat = other.get_precedence_matrix() + n_prec = 0 + for i in range(self.size): + for j in range(self.size): + if i == j: + continue + if self_prec_mat[i, j] * other_prec_mat[i, j] == 1: + n_prec += 1 + d = self.size * (self.size - 1)//2 - n_prec + return d + + def get_adjacency_matrix(self): + """ + Computes the adjacency matrix of a permutation. + + Explanation + =========== + + If job i is adjacent to job j in a permutation p + then we set m[i, j] = 1 where m is the adjacency + matrix of p. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation.josephus(3, 6, 1) + >>> p.get_adjacency_matrix() + Matrix([ + [0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1], + [0, 1, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0]]) + >>> q = Permutation([0, 1, 2, 3]) + >>> q.get_adjacency_matrix() + Matrix([ + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1], + [0, 0, 0, 0]]) + + See Also + ======== + + get_precedence_matrix, get_precedence_distance, get_adjacency_distance + """ + m = zeros(self.size) + perm = self.array_form + for i in range(self.size - 1): + m[perm[i], perm[i + 1]] = 1 + return m + + def get_adjacency_distance(self, other): + """ + Computes the adjacency distance between two permutations. + + Explanation + =========== + + This metric counts the number of times a pair i,j of jobs is + adjacent in both p and p'. If n_adj is this quantity then + the adjacency distance is n - n_adj - 1 [1] + + [1] Reeves, Colin R. Landscapes, Operators and Heuristic search, Annals + of Operational Research, 86, pp 473-490. (1999) + + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 3, 1, 2, 4]) + >>> q = Permutation.josephus(4, 5, 2) + >>> p.get_adjacency_distance(q) + 3 + >>> r = Permutation([0, 2, 1, 4, 3]) + >>> p.get_adjacency_distance(r) + 4 + + See Also + ======== + + get_precedence_matrix, get_precedence_distance, get_adjacency_matrix + """ + if self.size != other.size: + raise ValueError("The permutations must be of the same size.") + self_adj_mat = self.get_adjacency_matrix() + other_adj_mat = other.get_adjacency_matrix() + n_adj = 0 + for i in range(self.size): + for j in range(self.size): + if i == j: + continue + if self_adj_mat[i, j] * other_adj_mat[i, j] == 1: + n_adj += 1 + d = self.size - n_adj - 1 + return d + + def get_positional_distance(self, other): + """ + Computes the positional distance between two permutations. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> p = Permutation([0, 3, 1, 2, 4]) + >>> q = Permutation.josephus(4, 5, 2) + >>> r = Permutation([3, 1, 4, 0, 2]) + >>> p.get_positional_distance(q) + 12 + >>> p.get_positional_distance(r) + 12 + + See Also + ======== + + get_precedence_distance, get_adjacency_distance + """ + a = self.array_form + b = other.array_form + if len(a) != len(b): + raise ValueError("The permutations must be of the same size.") + return sum(abs(a[i] - b[i]) for i in range(len(a))) + + @classmethod + def josephus(cls, m, n, s=1): + """Return as a permutation the shuffling of range(n) using the Josephus + scheme in which every m-th item is selected until all have been chosen. + The returned permutation has elements listed by the order in which they + were selected. + + The parameter ``s`` stops the selection process when there are ``s`` + items remaining and these are selected by continuing the selection, + counting by 1 rather than by ``m``. + + Consider selecting every 3rd item from 6 until only 2 remain:: + + choices chosen + ======== ====== + 012345 + 01 345 2 + 01 34 25 + 01 4 253 + 0 4 2531 + 0 25314 + 253140 + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation.josephus(3, 6, 2).array_form + [2, 5, 3, 1, 4, 0] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Flavius_Josephus + .. [2] https://en.wikipedia.org/wiki/Josephus_problem + .. [3] https://web.archive.org/web/20171008094331/http://www.wou.edu/~burtonl/josephus.html + + """ + from collections import deque + m -= 1 + Q = deque(list(range(n))) + perm = [] + while len(Q) > max(s, 1): + for dp in range(m): + Q.append(Q.popleft()) + perm.append(Q.popleft()) + perm.extend(list(Q)) + return cls(perm) + + @classmethod + def from_inversion_vector(cls, inversion): + """ + Calculates the permutation from the inversion vector. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> Permutation.from_inversion_vector([3, 2, 1, 0, 0]) + Permutation([3, 2, 1, 0, 4, 5]) + + """ + size = len(inversion) + N = list(range(size + 1)) + perm = [] + try: + for k in range(size): + val = N[inversion[k]] + perm.append(val) + N.remove(val) + except IndexError: + raise ValueError("The inversion vector is not valid.") + perm.extend(N) + return cls._af_new(perm) + + @classmethod + def random(cls, n): + """ + Generates a random permutation of length ``n``. + + Uses the underlying Python pseudo-random number generator. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation.random(2) in (Permutation([1, 0]), Permutation([0, 1])) + True + + """ + perm_array = list(range(n)) + random.shuffle(perm_array) + return cls._af_new(perm_array) + + @classmethod + def unrank_lex(cls, size, rank): + """ + Lexicographic permutation unranking. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy import init_printing + >>> init_printing(perm_cyclic=False, pretty_print=False) + >>> a = Permutation.unrank_lex(5, 10) + >>> a.rank() + 10 + >>> a + Permutation([0, 2, 4, 1, 3]) + + See Also + ======== + + rank, next_lex + """ + perm_array = [0] * size + psize = 1 + for i in range(size): + new_psize = psize*(i + 1) + d = (rank % new_psize) // psize + rank -= d*psize + perm_array[size - i - 1] = d + for j in range(size - i, size): + if perm_array[j] > d - 1: + perm_array[j] += 1 + psize = new_psize + return cls._af_new(perm_array) + + def resize(self, n): + """Resize the permutation to the new size ``n``. + + Parameters + ========== + + n : int + The new size of the permutation. + + Raises + ====== + + ValueError + If the permutation cannot be resized to the given size. + This may only happen when resized to a smaller size than + the original. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + + Increasing the size of a permutation: + + >>> p = Permutation(0, 1, 2) + >>> p = p.resize(5) + >>> p + (4)(0 1 2) + + Decreasing the size of the permutation: + + >>> p = p.resize(4) + >>> p + (3)(0 1 2) + + If resizing to the specific size breaks the cycles: + + >>> p.resize(2) + Traceback (most recent call last): + ... + ValueError: The permutation cannot be resized to 2 because the + cycle (0, 1, 2) may break. + """ + aform = self.array_form + l = len(aform) + if n > l: + aform += list(range(l, n)) + return Permutation._af_new(aform) + + elif n < l: + cyclic_form = self.full_cyclic_form + new_cyclic_form = [] + for cycle in cyclic_form: + cycle_min = min(cycle) + cycle_max = max(cycle) + if cycle_min <= n-1: + if cycle_max > n-1: + raise ValueError( + "The permutation cannot be resized to {} " + "because the cycle {} may break." + .format(n, tuple(cycle))) + + new_cyclic_form.append(cycle) + return Permutation(new_cyclic_form) + + return self + + # XXX Deprecated flag + print_cyclic = None + + +def _merge(arr, temp, left, mid, right): + """ + Merges two sorted arrays and calculates the inversion count. + + Helper function for calculating inversions. This method is + for internal use only. + """ + i = k = left + j = mid + inv_count = 0 + while i < mid and j <= right: + if arr[i] < arr[j]: + temp[k] = arr[i] + k += 1 + i += 1 + else: + temp[k] = arr[j] + k += 1 + j += 1 + inv_count += (mid -i) + while i < mid: + temp[k] = arr[i] + k += 1 + i += 1 + if j <= right: + k += right - j + 1 + j += right - j + 1 + arr[left:k + 1] = temp[left:k + 1] + else: + arr[left:right + 1] = temp[left:right + 1] + return inv_count + +Perm = Permutation +_af_new = Perm._af_new + + +class AppliedPermutation(Expr): + """A permutation applied to a symbolic variable. + + Parameters + ========== + + perm : Permutation + x : Expr + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.combinatorics import Permutation + + Creating a symbolic permutation function application: + + >>> x = Symbol('x') + >>> p = Permutation(0, 1, 2) + >>> p.apply(x) + AppliedPermutation((0 1 2), x) + >>> _.subs(x, 1) + 2 + """ + def __new__(cls, perm, x, evaluate=None): + if evaluate is None: + evaluate = global_parameters.evaluate + + perm = _sympify(perm) + x = _sympify(x) + + if not isinstance(perm, Permutation): + raise ValueError("{} must be a Permutation instance." + .format(perm)) + + if evaluate: + if x.is_Integer: + return perm.apply(x) + + obj = super().__new__(cls, perm, x) + return obj + + +@dispatch(Permutation, Permutation) +def _eval_is_eq(lhs, rhs): + if lhs._size != rhs._size: + return None + return lhs._array_form == rhs._array_form diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/polyhedron.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/polyhedron.py new file mode 100644 index 0000000000000000000000000000000000000000..2bc05d7d97c840649661f3290442499c841ca7c1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/polyhedron.py @@ -0,0 +1,1019 @@ +from sympy.combinatorics import Permutation as Perm +from sympy.combinatorics.perm_groups import PermutationGroup +from sympy.core import Basic, Tuple, default_sort_key +from sympy.sets import FiniteSet +from sympy.utilities.iterables import (minlex, unflatten, flatten) +from sympy.utilities.misc import as_int + +rmul = Perm.rmul + + +class Polyhedron(Basic): + """ + Represents the polyhedral symmetry group (PSG). + + Explanation + =========== + + The PSG is one of the symmetry groups of the Platonic solids. + There are three polyhedral groups: the tetrahedral group + of order 12, the octahedral group of order 24, and the + icosahedral group of order 60. + + All doctests have been given in the docstring of the + constructor of the object. + + References + ========== + + .. [1] https://mathworld.wolfram.com/PolyhedralGroup.html + + """ + _edges = None + + def __new__(cls, corners, faces=(), pgroup=()): + """ + The constructor of the Polyhedron group object. + + Explanation + =========== + + It takes up to three parameters: the corners, faces, and + allowed transformations. + + The corners/vertices are entered as a list of arbitrary + expressions that are used to identify each vertex. + + The faces are entered as a list of tuples of indices; a tuple + of indices identifies the vertices which define the face. They + should be entered in a cw or ccw order; they will be standardized + by reversal and rotation to be give the lowest lexical ordering. + If no faces are given then no edges will be computed. + + >>> from sympy.combinatorics.polyhedron import Polyhedron + >>> Polyhedron(list('abc'), [(1, 2, 0)]).faces + {(0, 1, 2)} + >>> Polyhedron(list('abc'), [(1, 0, 2)]).faces + {(0, 1, 2)} + + The allowed transformations are entered as allowable permutations + of the vertices for the polyhedron. Instance of Permutations + (as with faces) should refer to the supplied vertices by index. + These permutation are stored as a PermutationGroup. + + Examples + ======== + + >>> from sympy.combinatorics.permutations import Permutation + >>> from sympy import init_printing + >>> from sympy.abc import w, x, y, z + >>> init_printing(pretty_print=False, perm_cyclic=False) + + Here we construct the Polyhedron object for a tetrahedron. + + >>> corners = [w, x, y, z] + >>> faces = [(0, 1, 2), (0, 2, 3), (0, 3, 1), (1, 2, 3)] + + Next, allowed transformations of the polyhedron must be given. This + is given as permutations of vertices. + + Although the vertices of a tetrahedron can be numbered in 24 (4!) + different ways, there are only 12 different orientations for a + physical tetrahedron. The following permutations, applied once or + twice, will generate all 12 of the orientations. (The identity + permutation, Permutation(range(4)), is not included since it does + not change the orientation of the vertices.) + + >>> pgroup = [Permutation([[0, 1, 2], [3]]), \ + Permutation([[0, 1, 3], [2]]), \ + Permutation([[0, 2, 3], [1]]), \ + Permutation([[1, 2, 3], [0]]), \ + Permutation([[0, 1], [2, 3]]), \ + Permutation([[0, 2], [1, 3]]), \ + Permutation([[0, 3], [1, 2]])] + + The Polyhedron is now constructed and demonstrated: + + >>> tetra = Polyhedron(corners, faces, pgroup) + >>> tetra.size + 4 + >>> tetra.edges + {(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} + >>> tetra.corners + (w, x, y, z) + + It can be rotated with an arbitrary permutation of vertices, e.g. + the following permutation is not in the pgroup: + + >>> tetra.rotate(Permutation([0, 1, 3, 2])) + >>> tetra.corners + (w, x, z, y) + + An allowed permutation of the vertices can be constructed by + repeatedly applying permutations from the pgroup to the vertices. + Here is a demonstration that applying p and p**2 for every p in + pgroup generates all the orientations of a tetrahedron and no others: + + >>> all = ( (w, x, y, z), \ + (x, y, w, z), \ + (y, w, x, z), \ + (w, z, x, y), \ + (z, w, y, x), \ + (w, y, z, x), \ + (y, z, w, x), \ + (x, z, y, w), \ + (z, y, x, w), \ + (y, x, z, w), \ + (x, w, z, y), \ + (z, x, w, y) ) + + >>> got = [] + >>> for p in (pgroup + [p**2 for p in pgroup]): + ... h = Polyhedron(corners) + ... h.rotate(p) + ... got.append(h.corners) + ... + >>> set(got) == set(all) + True + + The make_perm method of a PermutationGroup will randomly pick + permutations, multiply them together, and return the permutation that + can be applied to the polyhedron to give the orientation produced + by those individual permutations. + + Here, 3 permutations are used: + + >>> tetra.pgroup.make_perm(3) # doctest: +SKIP + Permutation([0, 3, 1, 2]) + + To select the permutations that should be used, supply a list + of indices to the permutations in pgroup in the order they should + be applied: + + >>> use = [0, 0, 2] + >>> p002 = tetra.pgroup.make_perm(3, use) + >>> p002 + Permutation([1, 0, 3, 2]) + + + Apply them one at a time: + + >>> tetra.reset() + >>> for i in use: + ... tetra.rotate(pgroup[i]) + ... + >>> tetra.vertices + (x, w, z, y) + >>> sequentially = tetra.vertices + + Apply the composite permutation: + + >>> tetra.reset() + >>> tetra.rotate(p002) + >>> tetra.corners + (x, w, z, y) + >>> tetra.corners in all and tetra.corners == sequentially + True + + Notes + ===== + + Defining permutation groups + --------------------------- + + It is not necessary to enter any permutations, nor is necessary to + enter a complete set of transformations. In fact, for a polyhedron, + all configurations can be constructed from just two permutations. + For example, the orientations of a tetrahedron can be generated from + an axis passing through a vertex and face and another axis passing + through a different vertex or from an axis passing through the + midpoints of two edges opposite of each other. + + For simplicity of presentation, consider a square -- + not a cube -- with vertices 1, 2, 3, and 4: + + 1-----2 We could think of axes of rotation being: + | | 1) through the face + | | 2) from midpoint 1-2 to 3-4 or 1-3 to 2-4 + 3-----4 3) lines 1-4 or 2-3 + + + To determine how to write the permutations, imagine 4 cameras, + one at each corner, labeled A-D: + + A B A B + 1-----2 1-----3 vertex index: + | | | | 1 0 + | | | | 2 1 + 3-----4 2-----4 3 2 + C D C D 4 3 + + original after rotation + along 1-4 + + A diagonal and a face axis will be chosen for the "permutation group" + from which any orientation can be constructed. + + >>> pgroup = [] + + Imagine a clockwise rotation when viewing 1-4 from camera A. The new + orientation is (in camera-order): 1, 3, 2, 4 so the permutation is + given using the *indices* of the vertices as: + + >>> pgroup.append(Permutation((0, 2, 1, 3))) + + Now imagine rotating clockwise when looking down an axis entering the + center of the square as viewed. The new camera-order would be + 3, 1, 4, 2 so the permutation is (using indices): + + >>> pgroup.append(Permutation((2, 0, 3, 1))) + + The square can now be constructed: + ** use real-world labels for the vertices, entering them in + camera order + ** for the faces we use zero-based indices of the vertices + in *edge-order* as the face is traversed; neither the + direction nor the starting point matter -- the faces are + only used to define edges (if so desired). + + >>> square = Polyhedron((1, 2, 3, 4), [(0, 1, 3, 2)], pgroup) + + To rotate the square with a single permutation we can do: + + >>> square.rotate(square.pgroup[0]) + >>> square.corners + (1, 3, 2, 4) + + To use more than one permutation (or to use one permutation more + than once) it is more convenient to use the make_perm method: + + >>> p011 = square.pgroup.make_perm([0, 1, 1]) # diag flip + 2 rotations + >>> square.reset() # return to initial orientation + >>> square.rotate(p011) + >>> square.corners + (4, 2, 3, 1) + + Thinking outside the box + ------------------------ + + Although the Polyhedron object has a direct physical meaning, it + actually has broader application. In the most general sense it is + just a decorated PermutationGroup, allowing one to connect the + permutations to something physical. For example, a Rubik's cube is + not a proper polyhedron, but the Polyhedron class can be used to + represent it in a way that helps to visualize the Rubik's cube. + + >>> from sympy import flatten, unflatten, symbols + >>> from sympy.combinatorics import RubikGroup + >>> facelets = flatten([symbols(s+'1:5') for s in 'UFRBLD']) + >>> def show(): + ... pairs = unflatten(r2.corners, 2) + ... print(pairs[::2]) + ... print(pairs[1::2]) + ... + >>> r2 = Polyhedron(facelets, pgroup=RubikGroup(2)) + >>> show() + [(U1, U2), (F1, F2), (R1, R2), (B1, B2), (L1, L2), (D1, D2)] + [(U3, U4), (F3, F4), (R3, R4), (B3, B4), (L3, L4), (D3, D4)] + >>> r2.rotate(0) # cw rotation of F + >>> show() + [(U1, U2), (F3, F1), (U3, R2), (B1, B2), (L1, D1), (R3, R1)] + [(L4, L2), (F4, F2), (U4, R4), (B3, B4), (L3, D2), (D3, D4)] + + Predefined Polyhedra + ==================== + + For convenience, the vertices and faces are defined for the following + standard solids along with a permutation group for transformations. + When the polyhedron is oriented as indicated below, the vertices in + a given horizontal plane are numbered in ccw direction, starting from + the vertex that will give the lowest indices in a given face. (In the + net of the vertices, indices preceded by "-" indicate replication of + the lhs index in the net.) + + tetrahedron, tetrahedron_faces + ------------------------------ + + 4 vertices (vertex up) net: + + 0 0-0 + 1 2 3-1 + + 4 faces: + + (0, 1, 2) (0, 2, 3) (0, 3, 1) (1, 2, 3) + + cube, cube_faces + ---------------- + + 8 vertices (face up) net: + + 0 1 2 3-0 + 4 5 6 7-4 + + 6 faces: + + (0, 1, 2, 3) + (0, 1, 5, 4) (1, 2, 6, 5) (2, 3, 7, 6) (0, 3, 7, 4) + (4, 5, 6, 7) + + octahedron, octahedron_faces + ---------------------------- + + 6 vertices (vertex up) net: + + 0 0 0-0 + 1 2 3 4-1 + 5 5 5-5 + + 8 faces: + + (0, 1, 2) (0, 2, 3) (0, 3, 4) (0, 1, 4) + (1, 2, 5) (2, 3, 5) (3, 4, 5) (1, 4, 5) + + dodecahedron, dodecahedron_faces + -------------------------------- + + 20 vertices (vertex up) net: + + 0 1 2 3 4 -0 + 5 6 7 8 9 -5 + 14 10 11 12 13-14 + 15 16 17 18 19-15 + + 12 faces: + + (0, 1, 2, 3, 4) (0, 1, 6, 10, 5) (1, 2, 7, 11, 6) + (2, 3, 8, 12, 7) (3, 4, 9, 13, 8) (0, 4, 9, 14, 5) + (5, 10, 16, 15, 14) (6, 10, 16, 17, 11) (7, 11, 17, 18, 12) + (8, 12, 18, 19, 13) (9, 13, 19, 15, 14)(15, 16, 17, 18, 19) + + icosahedron, icosahedron_faces + ------------------------------ + + 12 vertices (face up) net: + + 0 0 0 0 -0 + 1 2 3 4 5 -1 + 6 7 8 9 10 -6 + 11 11 11 11 -11 + + 20 faces: + + (0, 1, 2) (0, 2, 3) (0, 3, 4) + (0, 4, 5) (0, 1, 5) (1, 2, 6) + (2, 3, 7) (3, 4, 8) (4, 5, 9) + (1, 5, 10) (2, 6, 7) (3, 7, 8) + (4, 8, 9) (5, 9, 10) (1, 6, 10) + (6, 7, 11) (7, 8, 11) (8, 9, 11) + (9, 10, 11) (6, 10, 11) + + >>> from sympy.combinatorics.polyhedron import cube + >>> cube.edges + {(0, 1), (0, 3), (0, 4), (1, 2), (1, 5), (2, 3), (2, 6), (3, 7), (4, 5), (4, 7), (5, 6), (6, 7)} + + If you want to use letters or other names for the corners you + can still use the pre-calculated faces: + + >>> corners = list('abcdefgh') + >>> Polyhedron(corners, cube.faces).corners + (a, b, c, d, e, f, g, h) + + References + ========== + + .. [1] www.ocf.berkeley.edu/~wwu/articles/platonicsolids.pdf + + """ + faces = [minlex(f, directed=False, key=default_sort_key) for f in faces] + corners, faces, pgroup = args = \ + [Tuple(*a) for a in (corners, faces, pgroup)] + obj = Basic.__new__(cls, *args) + obj._corners = tuple(corners) # in order given + obj._faces = FiniteSet(*faces) + if pgroup and pgroup[0].size != len(corners): + raise ValueError("Permutation size unequal to number of corners.") + # use the identity permutation if none are given + obj._pgroup = PermutationGroup( + pgroup or [Perm(range(len(corners)))] ) + return obj + + @property + def corners(self): + """ + Get the corners of the Polyhedron. + + The method ``vertices`` is an alias for ``corners``. + + Examples + ======== + + >>> from sympy.combinatorics import Polyhedron + >>> from sympy.abc import a, b, c, d + >>> p = Polyhedron(list('abcd')) + >>> p.corners == p.vertices == (a, b, c, d) + True + + See Also + ======== + + array_form, cyclic_form + """ + return self._corners + vertices = corners + + @property + def array_form(self): + """Return the indices of the corners. + + The indices are given relative to the original position of corners. + + Examples + ======== + + >>> from sympy.combinatorics.polyhedron import tetrahedron + >>> tetrahedron = tetrahedron.copy() + >>> tetrahedron.array_form + [0, 1, 2, 3] + + >>> tetrahedron.rotate(0) + >>> tetrahedron.array_form + [0, 2, 3, 1] + >>> tetrahedron.pgroup[0].array_form + [0, 2, 3, 1] + + See Also + ======== + + corners, cyclic_form + """ + corners = list(self.args[0]) + return [corners.index(c) for c in self.corners] + + @property + def cyclic_form(self): + """Return the indices of the corners in cyclic notation. + + The indices are given relative to the original position of corners. + + See Also + ======== + + corners, array_form + """ + return Perm._af_new(self.array_form).cyclic_form + + @property + def size(self): + """ + Get the number of corners of the Polyhedron. + """ + return len(self._corners) + + @property + def faces(self): + """ + Get the faces of the Polyhedron. + """ + return self._faces + + @property + def pgroup(self): + """ + Get the permutations of the Polyhedron. + """ + return self._pgroup + + @property + def edges(self): + """ + Given the faces of the polyhedra we can get the edges. + + Examples + ======== + + >>> from sympy.combinatorics import Polyhedron + >>> from sympy.abc import a, b, c + >>> corners = (a, b, c) + >>> faces = [(0, 1, 2)] + >>> Polyhedron(corners, faces).edges + {(0, 1), (0, 2), (1, 2)} + + """ + if self._edges is None: + output = set() + for face in self.faces: + for i in range(len(face)): + edge = tuple(sorted([face[i], face[i - 1]])) + output.add(edge) + self._edges = FiniteSet(*output) + return self._edges + + def rotate(self, perm): + """ + Apply a permutation to the polyhedron *in place*. The permutation + may be given as a Permutation instance or an integer indicating + which permutation from pgroup of the Polyhedron should be + applied. + + This is an operation that is analogous to rotation about + an axis by a fixed increment. + + Notes + ===== + + When a Permutation is applied, no check is done to see if that + is a valid permutation for the Polyhedron. For example, a cube + could be given a permutation which effectively swaps only 2 + vertices. A valid permutation (that rotates the object in a + physical way) will be obtained if one only uses + permutations from the ``pgroup`` of the Polyhedron. On the other + hand, allowing arbitrary rotations (applications of permutations) + gives a way to follow named elements rather than indices since + Polyhedron allows vertices to be named while Permutation works + only with indices. + + Examples + ======== + + >>> from sympy.combinatorics import Polyhedron, Permutation + >>> from sympy.combinatorics.polyhedron import cube + >>> cube = cube.copy() + >>> cube.corners + (0, 1, 2, 3, 4, 5, 6, 7) + >>> cube.rotate(0) + >>> cube.corners + (1, 2, 3, 0, 5, 6, 7, 4) + + A non-physical "rotation" that is not prohibited by this method: + + >>> cube.reset() + >>> cube.rotate(Permutation([[1, 2]], size=8)) + >>> cube.corners + (0, 2, 1, 3, 4, 5, 6, 7) + + Polyhedron can be used to follow elements of set that are + identified by letters instead of integers: + + >>> shadow = h5 = Polyhedron(list('abcde')) + >>> p = Permutation([3, 0, 1, 2, 4]) + >>> h5.rotate(p) + >>> h5.corners + (d, a, b, c, e) + >>> _ == shadow.corners + True + >>> copy = h5.copy() + >>> h5.rotate(p) + >>> h5.corners == copy.corners + False + """ + if not isinstance(perm, Perm): + perm = self.pgroup[perm] + # and we know it's valid + else: + if perm.size != self.size: + raise ValueError('Polyhedron and Permutation sizes differ.') + a = perm.array_form + corners = [self.corners[a[i]] for i in range(len(self.corners))] + self._corners = tuple(corners) + + def reset(self): + """Return corners to their original positions. + + Examples + ======== + + >>> from sympy.combinatorics.polyhedron import tetrahedron as T + >>> T = T.copy() + >>> T.corners + (0, 1, 2, 3) + >>> T.rotate(0) + >>> T.corners + (0, 2, 3, 1) + >>> T.reset() + >>> T.corners + (0, 1, 2, 3) + """ + self._corners = self.args[0] + + +def _pgroup_calcs(): + """Return the permutation groups for each of the polyhedra and the face + definitions: tetrahedron, cube, octahedron, dodecahedron, icosahedron, + tetrahedron_faces, cube_faces, octahedron_faces, dodecahedron_faces, + icosahedron_faces + + Explanation + =========== + + (This author did not find and did not know of a better way to do it though + there likely is such a way.) + + Although only 2 permutations are needed for a polyhedron in order to + generate all the possible orientations, a group of permutations is + provided instead. A set of permutations is called a "group" if:: + + a*b = c (for any pair of permutations in the group, a and b, their + product, c, is in the group) + + a*(b*c) = (a*b)*c (for any 3 permutations in the group associativity holds) + + there is an identity permutation, I, such that I*a = a*I for all elements + in the group + + a*b = I (the inverse of each permutation is also in the group) + + None of the polyhedron groups defined follow these definitions of a group. + Instead, they are selected to contain those permutations whose powers + alone will construct all orientations of the polyhedron, i.e. for + permutations ``a``, ``b``, etc... in the group, ``a, a**2, ..., a**o_a``, + ``b, b**2, ..., b**o_b``, etc... (where ``o_i`` is the order of + permutation ``i``) generate all permutations of the polyhedron instead of + mixed products like ``a*b``, ``a*b**2``, etc.... + + Note that for a polyhedron with n vertices, the valid permutations of the + vertices exclude those that do not maintain its faces. e.g. the + permutation BCDE of a square's four corners, ABCD, is a valid + permutation while CBDE is not (because this would twist the square). + + Examples + ======== + + The is_group checks for: closure, the presence of the Identity permutation, + and the presence of the inverse for each of the elements in the group. This + confirms that none of the polyhedra are true groups: + + >>> from sympy.combinatorics.polyhedron import ( + ... tetrahedron, cube, octahedron, dodecahedron, icosahedron) + ... + >>> polyhedra = (tetrahedron, cube, octahedron, dodecahedron, icosahedron) + >>> [h.pgroup.is_group for h in polyhedra] + ... + [True, True, True, True, True] + + Although tests in polyhedron's test suite check that powers of the + permutations in the groups generate all permutations of the vertices + of the polyhedron, here we also demonstrate the powers of the given + permutations create a complete group for the tetrahedron: + + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> for h in polyhedra[:1]: + ... G = h.pgroup + ... perms = set() + ... for g in G: + ... for e in range(g.order()): + ... p = tuple((g**e).array_form) + ... perms.add(p) + ... + ... perms = [Permutation(p) for p in perms] + ... assert PermutationGroup(perms).is_group + + In addition to doing the above, the tests in the suite confirm that the + faces are all present after the application of each permutation. + + References + ========== + + .. [1] https://dogschool.tripod.com/trianglegroup.html + + """ + def _pgroup_of_double(polyh, ordered_faces, pgroup): + n = len(ordered_faces[0]) + # the vertices of the double which sits inside a give polyhedron + # can be found by tracking the faces of the outer polyhedron. + # A map between face and the vertex of the double is made so that + # after rotation the position of the vertices can be located + fmap = dict(zip(ordered_faces, + range(len(ordered_faces)))) + flat_faces = flatten(ordered_faces) + new_pgroup = [] + for p in pgroup: + h = polyh.copy() + h.rotate(p) + c = h.corners + # reorder corners in the order they should appear when + # enumerating the faces + reorder = unflatten([c[j] for j in flat_faces], n) + # make them canonical + reorder = [tuple(map(as_int, + minlex(f, directed=False))) + for f in reorder] + # map face to vertex: the resulting list of vertices are the + # permutation that we seek for the double + new_pgroup.append(Perm([fmap[f] for f in reorder])) + return new_pgroup + + tetrahedron_faces = [ + (0, 1, 2), (0, 2, 3), (0, 3, 1), # upper 3 + (1, 2, 3), # bottom + ] + + # cw from top + # + _t_pgroup = [ + Perm([[1, 2, 3], [0]]), # cw from top + Perm([[0, 1, 2], [3]]), # cw from front face + Perm([[0, 3, 2], [1]]), # cw from back right face + Perm([[0, 3, 1], [2]]), # cw from back left face + Perm([[0, 1], [2, 3]]), # through front left edge + Perm([[0, 2], [1, 3]]), # through front right edge + Perm([[0, 3], [1, 2]]), # through back edge + ] + + tetrahedron = Polyhedron( + range(4), + tetrahedron_faces, + _t_pgroup) + + cube_faces = [ + (0, 1, 2, 3), # upper + (0, 1, 5, 4), (1, 2, 6, 5), (2, 3, 7, 6), (0, 3, 7, 4), # middle 4 + (4, 5, 6, 7), # lower + ] + + # U, D, F, B, L, R = up, down, front, back, left, right + _c_pgroup = [Perm(p) for p in + [ + [1, 2, 3, 0, 5, 6, 7, 4], # cw from top, U + [4, 0, 3, 7, 5, 1, 2, 6], # cw from F face + [4, 5, 1, 0, 7, 6, 2, 3], # cw from R face + + [1, 0, 4, 5, 2, 3, 7, 6], # cw through UF edge + [6, 2, 1, 5, 7, 3, 0, 4], # cw through UR edge + [6, 7, 3, 2, 5, 4, 0, 1], # cw through UB edge + [3, 7, 4, 0, 2, 6, 5, 1], # cw through UL edge + [4, 7, 6, 5, 0, 3, 2, 1], # cw through FL edge + [6, 5, 4, 7, 2, 1, 0, 3], # cw through FR edge + + [0, 3, 7, 4, 1, 2, 6, 5], # cw through UFL vertex + [5, 1, 0, 4, 6, 2, 3, 7], # cw through UFR vertex + [5, 6, 2, 1, 4, 7, 3, 0], # cw through UBR vertex + [7, 4, 0, 3, 6, 5, 1, 2], # cw through UBL + ]] + + cube = Polyhedron( + range(8), + cube_faces, + _c_pgroup) + + octahedron_faces = [ + (0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 1, 4), # top 4 + (1, 2, 5), (2, 3, 5), (3, 4, 5), (1, 4, 5), # bottom 4 + ] + + octahedron = Polyhedron( + range(6), + octahedron_faces, + _pgroup_of_double(cube, cube_faces, _c_pgroup)) + + dodecahedron_faces = [ + (0, 1, 2, 3, 4), # top + (0, 1, 6, 10, 5), (1, 2, 7, 11, 6), (2, 3, 8, 12, 7), # upper 5 + (3, 4, 9, 13, 8), (0, 4, 9, 14, 5), + (5, 10, 16, 15, 14), (6, 10, 16, 17, 11), (7, 11, 17, 18, + 12), # lower 5 + (8, 12, 18, 19, 13), (9, 13, 19, 15, 14), + (15, 16, 17, 18, 19) # bottom + ] + + def _string_to_perm(s): + rv = [Perm(range(20))] + p = None + for si in s: + if si not in '01': + count = int(si) - 1 + else: + count = 1 + if si == '0': + p = _f0 + elif si == '1': + p = _f1 + rv.extend([p]*count) + return Perm.rmul(*rv) + + # top face cw + _f0 = Perm([ + 1, 2, 3, 4, 0, 6, 7, 8, 9, 5, 11, + 12, 13, 14, 10, 16, 17, 18, 19, 15]) + # front face cw + _f1 = Perm([ + 5, 0, 4, 9, 14, 10, 1, 3, 13, 15, + 6, 2, 8, 19, 16, 17, 11, 7, 12, 18]) + # the strings below, like 0104 are shorthand for F0*F1*F0**4 and are + # the remaining 4 face rotations, 15 edge permutations, and the + # 10 vertex rotations. + _dodeca_pgroup = [_f0, _f1] + [_string_to_perm(s) for s in ''' + 0104 140 014 0410 + 010 1403 03104 04103 102 + 120 1304 01303 021302 03130 + 0412041 041204103 04120410 041204104 041204102 + 10 01 1402 0140 04102 0412 1204 1302 0130 03120'''.strip().split()] + + dodecahedron = Polyhedron( + range(20), + dodecahedron_faces, + _dodeca_pgroup) + + icosahedron_faces = [ + (0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 4, 5), (0, 1, 5), + (1, 6, 7), (1, 2, 7), (2, 7, 8), (2, 3, 8), (3, 8, 9), + (3, 4, 9), (4, 9, 10), (4, 5, 10), (5, 6, 10), (1, 5, 6), + (6, 7, 11), (7, 8, 11), (8, 9, 11), (9, 10, 11), (6, 10, 11)] + + icosahedron = Polyhedron( + range(12), + icosahedron_faces, + _pgroup_of_double( + dodecahedron, dodecahedron_faces, _dodeca_pgroup)) + + return (tetrahedron, cube, octahedron, dodecahedron, icosahedron, + tetrahedron_faces, cube_faces, octahedron_faces, + dodecahedron_faces, icosahedron_faces) + +# ----------------------------------------------------------------------- +# Standard Polyhedron groups +# +# These are generated using _pgroup_calcs() above. However to save +# import time we encode them explicitly here. +# ----------------------------------------------------------------------- + +tetrahedron = Polyhedron( + Tuple(0, 1, 2, 3), + Tuple( + Tuple(0, 1, 2), + Tuple(0, 2, 3), + Tuple(0, 1, 3), + Tuple(1, 2, 3)), + Tuple( + Perm(1, 2, 3), + Perm(3)(0, 1, 2), + Perm(0, 3, 2), + Perm(0, 3, 1), + Perm(0, 1)(2, 3), + Perm(0, 2)(1, 3), + Perm(0, 3)(1, 2) + )) + +cube = Polyhedron( + Tuple(0, 1, 2, 3, 4, 5, 6, 7), + Tuple( + Tuple(0, 1, 2, 3), + Tuple(0, 1, 5, 4), + Tuple(1, 2, 6, 5), + Tuple(2, 3, 7, 6), + Tuple(0, 3, 7, 4), + Tuple(4, 5, 6, 7)), + Tuple( + Perm(0, 1, 2, 3)(4, 5, 6, 7), + Perm(0, 4, 5, 1)(2, 3, 7, 6), + Perm(0, 4, 7, 3)(1, 5, 6, 2), + Perm(0, 1)(2, 4)(3, 5)(6, 7), + Perm(0, 6)(1, 2)(3, 5)(4, 7), + Perm(0, 6)(1, 7)(2, 3)(4, 5), + Perm(0, 3)(1, 7)(2, 4)(5, 6), + Perm(0, 4)(1, 7)(2, 6)(3, 5), + Perm(0, 6)(1, 5)(2, 4)(3, 7), + Perm(1, 3, 4)(2, 7, 5), + Perm(7)(0, 5, 2)(3, 4, 6), + Perm(0, 5, 7)(1, 6, 3), + Perm(0, 7, 2)(1, 4, 6))) + +octahedron = Polyhedron( + Tuple(0, 1, 2, 3, 4, 5), + Tuple( + Tuple(0, 1, 2), + Tuple(0, 2, 3), + Tuple(0, 3, 4), + Tuple(0, 1, 4), + Tuple(1, 2, 5), + Tuple(2, 3, 5), + Tuple(3, 4, 5), + Tuple(1, 4, 5)), + Tuple( + Perm(5)(1, 2, 3, 4), + Perm(0, 4, 5, 2), + Perm(0, 1, 5, 3), + Perm(0, 1)(2, 4)(3, 5), + Perm(0, 2)(1, 3)(4, 5), + Perm(0, 3)(1, 5)(2, 4), + Perm(0, 4)(1, 3)(2, 5), + Perm(0, 5)(1, 4)(2, 3), + Perm(0, 5)(1, 2)(3, 4), + Perm(0, 4, 1)(2, 3, 5), + Perm(0, 1, 2)(3, 4, 5), + Perm(0, 2, 3)(1, 5, 4), + Perm(0, 4, 3)(1, 5, 2))) + +dodecahedron = Polyhedron( + Tuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), + Tuple( + Tuple(0, 1, 2, 3, 4), + Tuple(0, 1, 6, 10, 5), + Tuple(1, 2, 7, 11, 6), + Tuple(2, 3, 8, 12, 7), + Tuple(3, 4, 9, 13, 8), + Tuple(0, 4, 9, 14, 5), + Tuple(5, 10, 16, 15, 14), + Tuple(6, 10, 16, 17, 11), + Tuple(7, 11, 17, 18, 12), + Tuple(8, 12, 18, 19, 13), + Tuple(9, 13, 19, 15, 14), + Tuple(15, 16, 17, 18, 19)), + Tuple( + Perm(0, 1, 2, 3, 4)(5, 6, 7, 8, 9)(10, 11, 12, 13, 14)(15, 16, 17, 18, 19), + Perm(0, 5, 10, 6, 1)(2, 4, 14, 16, 11)(3, 9, 15, 17, 7)(8, 13, 19, 18, 12), + Perm(0, 10, 17, 12, 3)(1, 6, 11, 7, 2)(4, 5, 16, 18, 8)(9, 14, 15, 19, 13), + Perm(0, 6, 17, 19, 9)(1, 11, 18, 13, 4)(2, 7, 12, 8, 3)(5, 10, 16, 15, 14), + Perm(0, 2, 12, 19, 14)(1, 7, 18, 15, 5)(3, 8, 13, 9, 4)(6, 11, 17, 16, 10), + Perm(0, 4, 9, 14, 5)(1, 3, 13, 15, 10)(2, 8, 19, 16, 6)(7, 12, 18, 17, 11), + Perm(0, 1)(2, 5)(3, 10)(4, 6)(7, 14)(8, 16)(9, 11)(12, 15)(13, 17)(18, 19), + Perm(0, 7)(1, 2)(3, 6)(4, 11)(5, 12)(8, 10)(9, 17)(13, 16)(14, 18)(15, 19), + Perm(0, 12)(1, 8)(2, 3)(4, 7)(5, 18)(6, 13)(9, 11)(10, 19)(14, 17)(15, 16), + Perm(0, 8)(1, 13)(2, 9)(3, 4)(5, 12)(6, 19)(7, 14)(10, 18)(11, 15)(16, 17), + Perm(0, 4)(1, 9)(2, 14)(3, 5)(6, 13)(7, 15)(8, 10)(11, 19)(12, 16)(17, 18), + Perm(0, 5)(1, 14)(2, 15)(3, 16)(4, 10)(6, 9)(7, 19)(8, 17)(11, 13)(12, 18), + Perm(0, 11)(1, 6)(2, 10)(3, 16)(4, 17)(5, 7)(8, 15)(9, 18)(12, 14)(13, 19), + Perm(0, 18)(1, 12)(2, 7)(3, 11)(4, 17)(5, 19)(6, 8)(9, 16)(10, 13)(14, 15), + Perm(0, 18)(1, 19)(2, 13)(3, 8)(4, 12)(5, 17)(6, 15)(7, 9)(10, 16)(11, 14), + Perm(0, 13)(1, 19)(2, 15)(3, 14)(4, 9)(5, 8)(6, 18)(7, 16)(10, 12)(11, 17), + Perm(0, 16)(1, 15)(2, 19)(3, 18)(4, 17)(5, 10)(6, 14)(7, 13)(8, 12)(9, 11), + Perm(0, 18)(1, 17)(2, 16)(3, 15)(4, 19)(5, 12)(6, 11)(7, 10)(8, 14)(9, 13), + Perm(0, 15)(1, 19)(2, 18)(3, 17)(4, 16)(5, 14)(6, 13)(7, 12)(8, 11)(9, 10), + Perm(0, 17)(1, 16)(2, 15)(3, 19)(4, 18)(5, 11)(6, 10)(7, 14)(8, 13)(9, 12), + Perm(0, 19)(1, 18)(2, 17)(3, 16)(4, 15)(5, 13)(6, 12)(7, 11)(8, 10)(9, 14), + Perm(1, 4, 5)(2, 9, 10)(3, 14, 6)(7, 13, 16)(8, 15, 11)(12, 19, 17), + Perm(19)(0, 6, 2)(3, 5, 11)(4, 10, 7)(8, 14, 17)(9, 16, 12)(13, 15, 18), + Perm(0, 11, 8)(1, 7, 3)(4, 6, 12)(5, 17, 13)(9, 10, 18)(14, 16, 19), + Perm(0, 7, 13)(1, 12, 9)(2, 8, 4)(5, 11, 19)(6, 18, 14)(10, 17, 15), + Perm(0, 3, 9)(1, 8, 14)(2, 13, 5)(6, 12, 15)(7, 19, 10)(11, 18, 16), + Perm(0, 14, 10)(1, 9, 16)(2, 13, 17)(3, 19, 11)(4, 15, 6)(7, 8, 18), + Perm(0, 16, 7)(1, 10, 11)(2, 5, 17)(3, 14, 18)(4, 15, 12)(8, 9, 19), + Perm(0, 16, 13)(1, 17, 8)(2, 11, 12)(3, 6, 18)(4, 10, 19)(5, 15, 9), + Perm(0, 11, 15)(1, 17, 14)(2, 18, 9)(3, 12, 13)(4, 7, 19)(5, 6, 16), + Perm(0, 8, 15)(1, 12, 16)(2, 18, 10)(3, 19, 5)(4, 13, 14)(6, 7, 17))) + +icosahedron = Polyhedron( + Tuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), + Tuple( + Tuple(0, 1, 2), + Tuple(0, 2, 3), + Tuple(0, 3, 4), + Tuple(0, 4, 5), + Tuple(0, 1, 5), + Tuple(1, 6, 7), + Tuple(1, 2, 7), + Tuple(2, 7, 8), + Tuple(2, 3, 8), + Tuple(3, 8, 9), + Tuple(3, 4, 9), + Tuple(4, 9, 10), + Tuple(4, 5, 10), + Tuple(5, 6, 10), + Tuple(1, 5, 6), + Tuple(6, 7, 11), + Tuple(7, 8, 11), + Tuple(8, 9, 11), + Tuple(9, 10, 11), + Tuple(6, 10, 11)), + Tuple( + Perm(11)(1, 2, 3, 4, 5)(6, 7, 8, 9, 10), + Perm(0, 5, 6, 7, 2)(3, 4, 10, 11, 8), + Perm(0, 1, 7, 8, 3)(4, 5, 6, 11, 9), + Perm(0, 2, 8, 9, 4)(1, 7, 11, 10, 5), + Perm(0, 3, 9, 10, 5)(1, 2, 8, 11, 6), + Perm(0, 4, 10, 6, 1)(2, 3, 9, 11, 7), + Perm(0, 1)(2, 5)(3, 6)(4, 7)(8, 10)(9, 11), + Perm(0, 2)(1, 3)(4, 7)(5, 8)(6, 9)(10, 11), + Perm(0, 3)(1, 9)(2, 4)(5, 8)(6, 11)(7, 10), + Perm(0, 4)(1, 9)(2, 10)(3, 5)(6, 8)(7, 11), + Perm(0, 5)(1, 4)(2, 10)(3, 6)(7, 9)(8, 11), + Perm(0, 6)(1, 5)(2, 10)(3, 11)(4, 7)(8, 9), + Perm(0, 7)(1, 2)(3, 6)(4, 11)(5, 8)(9, 10), + Perm(0, 8)(1, 9)(2, 3)(4, 7)(5, 11)(6, 10), + Perm(0, 9)(1, 11)(2, 10)(3, 4)(5, 8)(6, 7), + Perm(0, 10)(1, 9)(2, 11)(3, 6)(4, 5)(7, 8), + Perm(0, 11)(1, 6)(2, 10)(3, 9)(4, 8)(5, 7), + Perm(0, 11)(1, 8)(2, 7)(3, 6)(4, 10)(5, 9), + Perm(0, 11)(1, 10)(2, 9)(3, 8)(4, 7)(5, 6), + Perm(0, 11)(1, 7)(2, 6)(3, 10)(4, 9)(5, 8), + Perm(0, 11)(1, 9)(2, 8)(3, 7)(4, 6)(5, 10), + Perm(0, 5, 1)(2, 4, 6)(3, 10, 7)(8, 9, 11), + Perm(0, 1, 2)(3, 5, 7)(4, 6, 8)(9, 10, 11), + Perm(0, 2, 3)(1, 8, 4)(5, 7, 9)(6, 11, 10), + Perm(0, 3, 4)(1, 8, 10)(2, 9, 5)(6, 7, 11), + Perm(0, 4, 5)(1, 3, 10)(2, 9, 6)(7, 8, 11), + Perm(0, 10, 7)(1, 5, 6)(2, 4, 11)(3, 9, 8), + Perm(0, 6, 8)(1, 7, 2)(3, 5, 11)(4, 10, 9), + Perm(0, 7, 9)(1, 11, 4)(2, 8, 3)(5, 6, 10), + Perm(0, 8, 10)(1, 7, 6)(2, 11, 5)(3, 9, 4), + Perm(0, 9, 6)(1, 3, 11)(2, 8, 7)(4, 10, 5))) + +tetrahedron_faces = [tuple(arg) for arg in tetrahedron.faces] + +cube_faces = [tuple(arg) for arg in cube.faces] + +octahedron_faces = [tuple(arg) for arg in octahedron.faces] + +dodecahedron_faces = [tuple(arg) for arg in dodecahedron.faces] + +icosahedron_faces = [tuple(arg) for arg in icosahedron.faces] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/prufer.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/prufer.py new file mode 100644 index 0000000000000000000000000000000000000000..e389df87cddc0152b2376e18b9f3df2e94d3d2fb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/prufer.py @@ -0,0 +1,435 @@ +from sympy.core import Basic +from sympy.core.containers import Tuple +from sympy.tensor.array import Array +from sympy.core.sympify import _sympify +from sympy.utilities.iterables import flatten, iterable +from sympy.utilities.misc import as_int + +from collections import defaultdict + + +class Prufer(Basic): + """ + The Prufer correspondence is an algorithm that describes the + bijection between labeled trees and the Prufer code. A Prufer + code of a labeled tree is unique up to isomorphism and has + a length of n - 2. + + Prufer sequences were first used by Heinz Prufer to give a + proof of Cayley's formula. + + References + ========== + + .. [1] https://mathworld.wolfram.com/LabeledTree.html + + """ + _prufer_repr = None + _tree_repr = None + _nodes = None + _rank = None + + @property + def prufer_repr(self): + """Returns Prufer sequence for the Prufer object. + + This sequence is found by removing the highest numbered vertex, + recording the node it was attached to, and continuing until only + two vertices remain. The Prufer sequence is the list of recorded nodes. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).prufer_repr + [3, 3, 3, 4] + >>> Prufer([1, 0, 0]).prufer_repr + [1, 0, 0] + + See Also + ======== + + to_prufer + + """ + if self._prufer_repr is None: + self._prufer_repr = self.to_prufer(self._tree_repr[:], self.nodes) + return self._prufer_repr + + @property + def tree_repr(self): + """Returns the tree representation of the Prufer object. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).tree_repr + [[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]] + >>> Prufer([1, 0, 0]).tree_repr + [[1, 2], [0, 1], [0, 3], [0, 4]] + + See Also + ======== + + to_tree + + """ + if self._tree_repr is None: + self._tree_repr = self.to_tree(self._prufer_repr[:]) + return self._tree_repr + + @property + def nodes(self): + """Returns the number of nodes in the tree. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).nodes + 6 + >>> Prufer([1, 0, 0]).nodes + 5 + + """ + return self._nodes + + @property + def rank(self): + """Returns the rank of the Prufer sequence. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> p = Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]) + >>> p.rank + 778 + >>> p.next(1).rank + 779 + >>> p.prev().rank + 777 + + See Also + ======== + + prufer_rank, next, prev, size + + """ + if self._rank is None: + self._rank = self.prufer_rank() + return self._rank + + @property + def size(self): + """Return the number of possible trees of this Prufer object. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> Prufer([0]*4).size == Prufer([6]*4).size == 1296 + True + + See Also + ======== + + prufer_rank, rank, next, prev + + """ + return self.prev(self.rank).prev().rank + 1 + + @staticmethod + def to_prufer(tree, n): + """Return the Prufer sequence for a tree given as a list of edges where + ``n`` is the number of nodes in the tree. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> a = Prufer([[0, 1], [0, 2], [0, 3]]) + >>> a.prufer_repr + [0, 0] + >>> Prufer.to_prufer([[0, 1], [0, 2], [0, 3]], 4) + [0, 0] + + See Also + ======== + prufer_repr: returns Prufer sequence of a Prufer object. + + """ + d = defaultdict(int) + L = [] + for edge in tree: + # Increment the value of the corresponding + # node in the degree list as we encounter an + # edge involving it. + d[edge[0]] += 1 + d[edge[1]] += 1 + for i in range(n - 2): + # find the smallest leaf + for x in range(n): + if d[x] == 1: + break + # find the node it was connected to + y = None + for edge in tree: + if x == edge[0]: + y = edge[1] + elif x == edge[1]: + y = edge[0] + if y is not None: + break + # record and update + L.append(y) + for j in (x, y): + d[j] -= 1 + if not d[j]: + d.pop(j) + tree.remove(edge) + return L + + @staticmethod + def to_tree(prufer): + """Return the tree (as a list of edges) of the given Prufer sequence. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> a = Prufer([0, 2], 4) + >>> a.tree_repr + [[0, 1], [0, 2], [2, 3]] + >>> Prufer.to_tree([0, 2]) + [[0, 1], [0, 2], [2, 3]] + + References + ========== + + .. [1] https://hamberg.no/erlend/posts/2010-11-06-prufer-sequence-compact-tree-representation.html + + See Also + ======== + tree_repr: returns tree representation of a Prufer object. + + """ + tree = [] + last = [] + n = len(prufer) + 2 + d = defaultdict(lambda: 1) + for p in prufer: + d[p] += 1 + for i in prufer: + for j in range(n): + # find the smallest leaf (degree = 1) + if d[j] == 1: + break + # (i, j) is the new edge that we append to the tree + # and remove from the degree dictionary + d[i] -= 1 + d[j] -= 1 + tree.append(sorted([i, j])) + last = [i for i in range(n) if d[i] == 1] or [0, 1] + tree.append(last) + + return tree + + @staticmethod + def edges(*runs): + """Return a list of edges and the number of nodes from the given runs + that connect nodes in an integer-labelled tree. + + All node numbers will be shifted so that the minimum node is 0. It is + not a problem if edges are repeated in the runs; only unique edges are + returned. There is no assumption made about what the range of the node + labels should be, but all nodes from the smallest through the largest + must be present. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> Prufer.edges([1, 2, 3], [2, 4, 5]) # a T + ([[0, 1], [1, 2], [1, 3], [3, 4]], 5) + + Duplicate edges are removed: + + >>> Prufer.edges([0, 1, 2, 3], [1, 4, 5], [1, 4, 6]) # a K + ([[0, 1], [1, 2], [1, 4], [2, 3], [4, 5], [4, 6]], 7) + + """ + e = set() + nmin = runs[0][0] + for r in runs: + for i in range(len(r) - 1): + a, b = r[i: i + 2] + if b < a: + a, b = b, a + e.add((a, b)) + rv = [] + got = set() + nmin = nmax = None + for ei in e: + got.update(ei) + nmin = min(ei[0], nmin) if nmin is not None else ei[0] + nmax = max(ei[1], nmax) if nmax is not None else ei[1] + rv.append(list(ei)) + missing = set(range(nmin, nmax + 1)) - got + if missing: + missing = [i + nmin for i in missing] + if len(missing) == 1: + msg = 'Node %s is missing.' % missing.pop() + else: + msg = 'Nodes %s are missing.' % sorted(missing) + raise ValueError(msg) + if nmin != 0: + for i, ei in enumerate(rv): + rv[i] = [n - nmin for n in ei] + nmax -= nmin + return sorted(rv), nmax + 1 + + def prufer_rank(self): + """Computes the rank of a Prufer sequence. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> a = Prufer([[0, 1], [0, 2], [0, 3]]) + >>> a.prufer_rank() + 0 + + See Also + ======== + + rank, next, prev, size + + """ + r = 0 + p = 1 + for i in range(self.nodes - 3, -1, -1): + r += p*self.prufer_repr[i] + p *= self.nodes + return r + + @classmethod + def unrank(self, rank, n): + """Finds the unranked Prufer sequence. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> Prufer.unrank(0, 4) + Prufer([0, 0]) + + """ + n, rank = as_int(n), as_int(rank) + L = defaultdict(int) + for i in range(n - 3, -1, -1): + L[i] = rank % n + rank = (rank - L[i])//n + return Prufer([L[i] for i in range(len(L))]) + + def __new__(cls, *args, **kw_args): + """The constructor for the Prufer object. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + + A Prufer object can be constructed from a list of edges: + + >>> a = Prufer([[0, 1], [0, 2], [0, 3]]) + >>> a.prufer_repr + [0, 0] + + If the number of nodes is given, no checking of the nodes will + be performed; it will be assumed that nodes 0 through n - 1 are + present: + + >>> Prufer([[0, 1], [0, 2], [0, 3]], 4) + Prufer([[0, 1], [0, 2], [0, 3]], 4) + + A Prufer object can be constructed from a Prufer sequence: + + >>> b = Prufer([1, 3]) + >>> b.tree_repr + [[0, 1], [1, 3], [2, 3]] + + """ + arg0 = Array(args[0]) if args[0] else Tuple() + args = (arg0,) + tuple(_sympify(arg) for arg in args[1:]) + ret_obj = Basic.__new__(cls, *args, **kw_args) + args = [list(args[0])] + if args[0] and iterable(args[0][0]): + if not args[0][0]: + raise ValueError( + 'Prufer expects at least one edge in the tree.') + if len(args) > 1: + nnodes = args[1] + else: + nodes = set(flatten(args[0])) + nnodes = max(nodes) + 1 + if nnodes != len(nodes): + missing = set(range(nnodes)) - nodes + if len(missing) == 1: + msg = 'Node %s is missing.' % missing.pop() + else: + msg = 'Nodes %s are missing.' % sorted(missing) + raise ValueError(msg) + ret_obj._tree_repr = [list(i) for i in args[0]] + ret_obj._nodes = nnodes + else: + ret_obj._prufer_repr = args[0] + ret_obj._nodes = len(ret_obj._prufer_repr) + 2 + return ret_obj + + def next(self, delta=1): + """Generates the Prufer sequence that is delta beyond the current one. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> a = Prufer([[0, 1], [0, 2], [0, 3]]) + >>> b = a.next(1) # == a.next() + >>> b.tree_repr + [[0, 2], [0, 1], [1, 3]] + >>> b.rank + 1 + + See Also + ======== + + prufer_rank, rank, prev, size + + """ + return Prufer.unrank(self.rank + delta, self.nodes) + + def prev(self, delta=1): + """Generates the Prufer sequence that is -delta before the current one. + + Examples + ======== + + >>> from sympy.combinatorics.prufer import Prufer + >>> a = Prufer([[0, 1], [1, 2], [2, 3], [1, 4]]) + >>> a.rank + 36 + >>> b = a.prev() + >>> b + Prufer([1, 2, 0]) + >>> b.rank + 35 + + See Also + ======== + + prufer_rank, rank, next, size + + """ + return Prufer.unrank(self.rank -delta, self.nodes) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/rewritingsystem.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/rewritingsystem.py new file mode 100644 index 0000000000000000000000000000000000000000..b9e8dfe4c831db6490c987c85a57d0d1a939de61 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/rewritingsystem.py @@ -0,0 +1,453 @@ +from collections import deque +from sympy.combinatorics.rewritingsystem_fsm import StateMachine + +class RewritingSystem: + ''' + A class implementing rewriting systems for `FpGroup`s. + + References + ========== + .. [1] Epstein, D., Holt, D. and Rees, S. (1991). + The use of Knuth-Bendix methods to solve the word problem in automatic groups. + Journal of Symbolic Computation, 12(4-5), pp.397-414. + + .. [2] GAP's Manual on its KBMAG package + https://www.gap-system.org/Manuals/pkg/kbmag-1.5.3/doc/manual.pdf + + ''' + def __init__(self, group): + self.group = group + self.alphabet = group.generators + self._is_confluent = None + + # these values are taken from [2] + self.maxeqns = 32767 # max rules + self.tidyint = 100 # rules before tidying + + # _max_exceeded is True if maxeqns is exceeded + # at any point + self._max_exceeded = False + + # Reduction automaton + self.reduction_automaton = None + self._new_rules = {} + + # dictionary of reductions + self.rules = {} + self.rules_cache = deque([], 50) + self._init_rules() + + + # All the transition symbols in the automaton + generators = list(self.alphabet) + generators += [gen**-1 for gen in generators] + # Create a finite state machine as an instance of the StateMachine object + self.reduction_automaton = StateMachine('Reduction automaton for '+ repr(self.group), generators) + self.construct_automaton() + + def set_max(self, n): + ''' + Set the maximum number of rules that can be defined + + ''' + if n > self.maxeqns: + self._max_exceeded = False + self.maxeqns = n + return + + @property + def is_confluent(self): + ''' + Return `True` if the system is confluent + + ''' + if self._is_confluent is None: + self._is_confluent = self._check_confluence() + return self._is_confluent + + def _init_rules(self): + identity = self.group.free_group.identity + for r in self.group.relators: + self.add_rule(r, identity) + self._remove_redundancies() + return + + def _add_rule(self, r1, r2): + ''' + Add the rule r1 -> r2 with no checking or further + deductions + + ''' + if len(self.rules) + 1 > self.maxeqns: + self._is_confluent = self._check_confluence() + self._max_exceeded = True + raise RuntimeError("Too many rules were defined.") + self.rules[r1] = r2 + # Add the newly added rule to the `new_rules` dictionary. + if self.reduction_automaton: + self._new_rules[r1] = r2 + + def add_rule(self, w1, w2, check=False): + new_keys = set() + + if w1 == w2: + return new_keys + + if w1 < w2: + w1, w2 = w2, w1 + + if (w1, w2) in self.rules_cache: + return new_keys + self.rules_cache.append((w1, w2)) + + s1, s2 = w1, w2 + + # The following is the equivalent of checking + # s1 for overlaps with the implicit reductions + # {g*g**-1 -> } and {g**-1*g -> } + # for any generator g without installing the + # redundant rules that would result from processing + # the overlaps. See [1], Section 3 for details. + + if len(s1) - len(s2) < 3: + if s1 not in self.rules: + new_keys.add(s1) + if not check: + self._add_rule(s1, s2) + if s2**-1 > s1**-1 and s2**-1 not in self.rules: + new_keys.add(s2**-1) + if not check: + self._add_rule(s2**-1, s1**-1) + + # overlaps on the right + while len(s1) - len(s2) > -1: + g = s1[len(s1)-1] + s1 = s1.subword(0, len(s1)-1) + s2 = s2*g**-1 + if len(s1) - len(s2) < 0: + if s2 not in self.rules: + if not check: + self._add_rule(s2, s1) + new_keys.add(s2) + elif len(s1) - len(s2) < 3: + new = self.add_rule(s1, s2, check) + new_keys.update(new) + + # overlaps on the left + while len(w1) - len(w2) > -1: + g = w1[0] + w1 = w1.subword(1, len(w1)) + w2 = g**-1*w2 + if len(w1) - len(w2) < 0: + if w2 not in self.rules: + if not check: + self._add_rule(w2, w1) + new_keys.add(w2) + elif len(w1) - len(w2) < 3: + new = self.add_rule(w1, w2, check) + new_keys.update(new) + + return new_keys + + def _remove_redundancies(self, changes=False): + ''' + Reduce left- and right-hand sides of reduction rules + and remove redundant equations (i.e. those for which + lhs == rhs). If `changes` is `True`, return a set + containing the removed keys and a set containing the + added keys + + ''' + removed = set() + added = set() + rules = self.rules.copy() + for r in rules: + v = self.reduce(r, exclude=r) + w = self.reduce(rules[r]) + if v != r: + del self.rules[r] + removed.add(r) + if v > w: + added.add(v) + self.rules[v] = w + elif v < w: + added.add(w) + self.rules[w] = v + else: + self.rules[v] = w + if changes: + return removed, added + return + + def make_confluent(self, check=False): + ''' + Try to make the system confluent using the Knuth-Bendix + completion algorithm + + ''' + if self._max_exceeded: + return self._is_confluent + lhs = list(self.rules.keys()) + + def _overlaps(r1, r2): + len1 = len(r1) + len2 = len(r2) + result = [] + for j in range(1, len1 + len2): + if (r1.subword(len1 - j, len1 + len2 - j, strict=False) + == r2.subword(j - len1, j, strict=False)): + a = r1.subword(0, len1-j, strict=False) + a = a*r2.subword(0, j-len1, strict=False) + b = r2.subword(j-len1, j, strict=False) + c = r2.subword(j, len2, strict=False) + c = c*r1.subword(len1 + len2 - j, len1, strict=False) + result.append(a*b*c) + return result + + def _process_overlap(w, r1, r2, check): + s = w.eliminate_word(r1, self.rules[r1]) + s = self.reduce(s) + t = w.eliminate_word(r2, self.rules[r2]) + t = self.reduce(t) + if s != t: + if check: + # system not confluent + return [0] + try: + new_keys = self.add_rule(t, s, check) + return new_keys + except RuntimeError: + return False + return + + added = 0 + i = 0 + while i < len(lhs): + r1 = lhs[i] + i += 1 + # j could be i+1 to not + # check each pair twice but lhs + # is extended in the loop and the new + # elements have to be checked with the + # preceding ones. there is probably a better way + # to handle this + j = 0 + while j < len(lhs): + r2 = lhs[j] + j += 1 + if r1 == r2: + continue + overlaps = _overlaps(r1, r2) + overlaps.extend(_overlaps(r1**-1, r2)) + if not overlaps: + continue + for w in overlaps: + new_keys = _process_overlap(w, r1, r2, check) + if new_keys: + if check: + return False + lhs.extend(new_keys) + added += len(new_keys) + elif new_keys == False: + # too many rules were added so the process + # couldn't complete + return self._is_confluent + + if added > self.tidyint and not check: + # tidy up + r, a = self._remove_redundancies(changes=True) + added = 0 + if r: + # reset i since some elements were removed + i = min(lhs.index(s) for s in r) + lhs = [l for l in lhs if l not in r] + lhs.extend(a) + if r1 in r: + # r1 was removed as redundant + break + + self._is_confluent = True + if not check: + self._remove_redundancies() + return True + + def _check_confluence(self): + return self.make_confluent(check=True) + + def reduce(self, word, exclude=None): + ''' + Apply reduction rules to `word` excluding the reduction rule + for the lhs equal to `exclude` + + ''' + rules = {r: self.rules[r] for r in self.rules if r != exclude} + # the following is essentially `eliminate_words()` code from the + # `FreeGroupElement` class, the only difference being the first + # "if" statement + again = True + new = word + while again: + again = False + for r in rules: + prev = new + if rules[r]**-1 > r**-1: + new = new.eliminate_word(r, rules[r], _all=True, inverse=False) + else: + new = new.eliminate_word(r, rules[r], _all=True) + if new != prev: + again = True + return new + + def _compute_inverse_rules(self, rules): + ''' + Compute the inverse rules for a given set of rules. + The inverse rules are used in the automaton for word reduction. + + Arguments: + rules (dictionary): Rules for which the inverse rules are to computed. + + Returns: + Dictionary of inverse_rules. + + ''' + inverse_rules = {} + for r in rules: + rule_key_inverse = r**-1 + rule_value_inverse = (rules[r])**-1 + if (rule_value_inverse < rule_key_inverse): + inverse_rules[rule_key_inverse] = rule_value_inverse + else: + inverse_rules[rule_value_inverse] = rule_key_inverse + return inverse_rules + + def construct_automaton(self): + ''' + Construct the automaton based on the set of reduction rules of the system. + + Automata Design: + The accept states of the automaton are the proper prefixes of the left hand side of the rules. + The complete left hand side of the rules are the dead states of the automaton. + + ''' + self._add_to_automaton(self.rules) + + def _add_to_automaton(self, rules): + ''' + Add new states and transitions to the automaton. + + Summary: + States corresponding to the new rules added to the system are computed and added to the automaton. + Transitions in the previously added states are also modified if necessary. + + Arguments: + rules (dictionary) -- Dictionary of the newly added rules. + + ''' + # Automaton variables + automaton_alphabet = [] + proper_prefixes = {} + + # compute the inverses of all the new rules added + all_rules = rules + inverse_rules = self._compute_inverse_rules(all_rules) + all_rules.update(inverse_rules) + + # Keep track of the accept_states. + accept_states = [] + + for rule in all_rules: + # The symbols present in the new rules are the symbols to be verified at each state. + # computes the automaton_alphabet, as the transitions solely depend upon the new states. + automaton_alphabet += rule.letter_form_elm + # Compute the proper prefixes for every rule. + proper_prefixes[rule] = [] + letter_word_array = list(rule.letter_form_elm) + len_letter_word_array = len(letter_word_array) + for i in range (1, len_letter_word_array): + letter_word_array[i] = letter_word_array[i-1]*letter_word_array[i] + # Add accept states. + elem = letter_word_array[i-1] + if elem not in self.reduction_automaton.states: + self.reduction_automaton.add_state(elem, state_type='a') + accept_states.append(elem) + proper_prefixes[rule] = letter_word_array + # Check for overlaps between dead and accept states. + if rule in accept_states: + self.reduction_automaton.states[rule].state_type = 'd' + self.reduction_automaton.states[rule].rh_rule = all_rules[rule] + accept_states.remove(rule) + # Add dead states + if rule not in self.reduction_automaton.states: + self.reduction_automaton.add_state(rule, state_type='d', rh_rule=all_rules[rule]) + + automaton_alphabet = set(automaton_alphabet) + + # Add new transitions for every state. + for state in self.reduction_automaton.states: + current_state_name = state + current_state_type = self.reduction_automaton.states[state].state_type + # Transitions will be modified only when suffixes of the current_state + # belongs to the proper_prefixes of the new rules. + # The rest are ignored if they cannot lead to a dead state after a finite number of transisitons. + if current_state_type == 's': + for letter in automaton_alphabet: + if letter in self.reduction_automaton.states: + self.reduction_automaton.states[state].add_transition(letter, letter) + else: + self.reduction_automaton.states[state].add_transition(letter, current_state_name) + elif current_state_type == 'a': + # Check if the transition to any new state in possible. + for letter in automaton_alphabet: + _next = current_state_name*letter + while len(_next) and _next not in self.reduction_automaton.states: + _next = _next.subword(1, len(_next)) + if not len(_next): + _next = 'start' + self.reduction_automaton.states[state].add_transition(letter, _next) + + # Add transitions for new states. All symbols used in the automaton are considered here. + # Ignore this if `reduction_automaton.automaton_alphabet` = `automaton_alphabet`. + if len(self.reduction_automaton.automaton_alphabet) != len(automaton_alphabet): + for state in accept_states: + current_state_name = state + for letter in self.reduction_automaton.automaton_alphabet: + _next = current_state_name*letter + while len(_next) and _next not in self.reduction_automaton.states: + _next = _next.subword(1, len(_next)) + if not len(_next): + _next = 'start' + self.reduction_automaton.states[state].add_transition(letter, _next) + + def reduce_using_automaton(self, word): + ''' + Reduce a word using an automaton. + + Summary: + All the symbols of the word are stored in an array and are given as the input to the automaton. + If the automaton reaches a dead state that subword is replaced and the automaton is run from the beginning. + The complete word has to be replaced when the word is read and the automaton reaches a dead state. + So, this process is repeated until the word is read completely and the automaton reaches the accept state. + + Arguments: + word (instance of FreeGroupElement) -- Word that needs to be reduced. + + ''' + # Modify the automaton if new rules are found. + if self._new_rules: + self._add_to_automaton(self._new_rules) + self._new_rules = {} + + flag = 1 + while flag: + flag = 0 + current_state = self.reduction_automaton.states['start'] + for i, s in enumerate(word.letter_form_elm): + next_state_name = current_state.transitions[s] + next_state = self.reduction_automaton.states[next_state_name] + if next_state.state_type == 'd': + subst = next_state.rh_rule + word = word.substituted_word(i - len(next_state_name) + 1, i+1, subst) + flag = 1 + break + current_state = next_state + return word diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/rewritingsystem_fsm.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/rewritingsystem_fsm.py new file mode 100644 index 0000000000000000000000000000000000000000..21916530040ac321180692d1a0811da4ae36a056 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/rewritingsystem_fsm.py @@ -0,0 +1,60 @@ +class State: + ''' + A representation of a state managed by a ``StateMachine``. + + Attributes: + name (instance of FreeGroupElement or string) -- State name which is also assigned to the Machine. + transisitons (OrderedDict) -- Represents all the transitions of the state object. + state_type (string) -- Denotes the type (accept/start/dead) of the state. + rh_rule (instance of FreeGroupElement) -- right hand rule for dead state. + state_machine (instance of StateMachine object) -- The finite state machine that the state belongs to. + ''' + + def __init__(self, name, state_machine, state_type=None, rh_rule=None): + self.name = name + self.transitions = {} + self.state_machine = state_machine + self.state_type = state_type[0] + self.rh_rule = rh_rule + + def add_transition(self, letter, state): + ''' + Add a transition from the current state to a new state. + + Keyword Arguments: + letter -- The alphabet element the current state reads to make the state transition. + state -- This will be an instance of the State object which represents a new state after in the transition after the alphabet is read. + + ''' + self.transitions[letter] = state + +class StateMachine: + ''' + Representation of a finite state machine the manages the states and the transitions of the automaton. + + Attributes: + states (dictionary) -- Collection of all registered `State` objects. + name (str) -- Name of the state machine. + ''' + + def __init__(self, name, automaton_alphabet): + self.name = name + self.automaton_alphabet = automaton_alphabet + self.states = {} # Contains all the states in the machine. + self.add_state('start', state_type='s') + + def add_state(self, state_name, state_type=None, rh_rule=None): + ''' + Instantiate a state object and stores it in the 'states' dictionary. + + Arguments: + state_name (instance of FreeGroupElement or string) -- name of the new states. + state_type (string) -- Denotes the type (accept/start/dead) of the state added. + rh_rule (instance of FreeGroupElement) -- right hand rule for dead state. + + ''' + new_state = State(state_name, self, state_type, rh_rule) + self.states[state_name] = new_state + + def __repr__(self): + return "%s" % (self.name) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/schur_number.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/schur_number.py new file mode 100644 index 0000000000000000000000000000000000000000..83aac98e543d4b54d4e6af17adca6e4f4de1b9ac --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/schur_number.py @@ -0,0 +1,160 @@ +""" +The Schur number S(k) is the largest integer n for which the interval [1,n] +can be partitioned into k sum-free sets.(https://mathworld.wolfram.com/SchurNumber.html) +""" +import math +from sympy.core import S +from sympy.core.basic import Basic +from sympy.core.function import Function +from sympy.core.numbers import Integer + + +class SchurNumber(Function): + r""" + This function creates a SchurNumber object + which is evaluated for `k \le 5` otherwise only + the lower bound information can be retrieved. + + Examples + ======== + + >>> from sympy.combinatorics.schur_number import SchurNumber + + Since S(3) = 13, hence the output is a number + >>> SchurNumber(3) + 13 + + We do not know the Schur number for values greater than 5, hence + only the object is returned + >>> SchurNumber(6) + SchurNumber(6) + + Now, the lower bound information can be retrieved using lower_bound() + method + >>> SchurNumber(6).lower_bound() + 536 + + """ + + @classmethod + def eval(cls, k): + if k.is_Number: + if k is S.Infinity: + return S.Infinity + if k.is_zero: + return S.Zero + if not k.is_integer or k.is_negative: + raise ValueError("k should be a positive integer") + first_known_schur_numbers = {1: 1, 2: 4, 3: 13, 4: 44, 5: 160} + if k <= 5: + return Integer(first_known_schur_numbers[k]) + + def lower_bound(self): + f_ = self.args[0] + # Improved lower bounds known for S(6) and S(7) + if f_ == 6: + return Integer(536) + if f_ == 7: + return Integer(1680) + # For other cases, use general expression + if f_.is_Integer: + return 3*self.func(f_ - 1).lower_bound() - 1 + return (3**f_ - 1)/2 + + +def _schur_subsets_number(n): + + if n is S.Infinity: + raise ValueError("Input must be finite") + if n <= 0: + raise ValueError("n must be a non-zero positive integer.") + elif n <= 3: + min_k = 1 + else: + min_k = math.ceil(math.log(2*n + 1, 3)) + + return Integer(min_k) + + +def schur_partition(n): + """ + + This function returns the partition in the minimum number of sum-free subsets + according to the lower bound given by the Schur Number. + + Parameters + ========== + + n: a number + n is the upper limit of the range [1, n] for which we need to find and + return the minimum number of free subsets according to the lower bound + of schur number + + Returns + ======= + + List of lists + List of the minimum number of sum-free subsets + + Notes + ===== + + It is possible for some n to make the partition into less + subsets since the only known Schur numbers are: + S(1) = 1, S(2) = 4, S(3) = 13, S(4) = 44. + e.g for n = 44 the lower bound from the function above is 5 subsets but it has been proven + that can be done with 4 subsets. + + Examples + ======== + + For n = 1, 2, 3 the answer is the set itself + + >>> from sympy.combinatorics.schur_number import schur_partition + >>> schur_partition(2) + [[1, 2]] + + For n > 3, the answer is the minimum number of sum-free subsets: + + >>> schur_partition(5) + [[3, 2], [5], [1, 4]] + + >>> schur_partition(8) + [[3, 2], [6, 5, 8], [1, 4, 7]] + """ + + if isinstance(n, Basic) and not n.is_Number: + raise ValueError("Input value must be a number") + + number_of_subsets = _schur_subsets_number(n) + if n == 1: + sum_free_subsets = [[1]] + elif n == 2: + sum_free_subsets = [[1, 2]] + elif n == 3: + sum_free_subsets = [[1, 2, 3]] + else: + sum_free_subsets = [[1, 4], [2, 3]] + + while len(sum_free_subsets) < number_of_subsets: + sum_free_subsets = _generate_next_list(sum_free_subsets, n) + missed_elements = [3*k + 1 for k in range(len(sum_free_subsets), (n-1)//3 + 1)] + sum_free_subsets[-1] += missed_elements + + return sum_free_subsets + + +def _generate_next_list(current_list, n): + new_list = [] + + for item in current_list: + temp_1 = [number*3 for number in item if number*3 <= n] + temp_2 = [number*3 - 1 for number in item if number*3 - 1 <= n] + new_item = temp_1 + temp_2 + new_list.append(new_item) + + last_list = [3*k + 1 for k in range(len(current_list)+1) if 3*k + 1 <= n] + new_list.append(last_list) + current_list = new_list + + return current_list diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/subsets.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/subsets.py new file mode 100644 index 0000000000000000000000000000000000000000..e540cb2395cb27e04c9d513831cb834a05ec2abd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/subsets.py @@ -0,0 +1,619 @@ +from itertools import combinations + +from sympy.combinatorics.graycode import GrayCode + + +class Subset(): + """ + Represents a basic subset object. + + Explanation + =========== + + We generate subsets using essentially two techniques, + binary enumeration and lexicographic enumeration. + The Subset class takes two arguments, the first one + describes the initial subset to consider and the second + describes the superset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.next_binary().subset + ['b'] + >>> a.prev_binary().subset + ['c'] + """ + + _rank_binary = None + _rank_lex = None + _rank_graycode = None + _subset = None + _superset = None + + def __new__(cls, subset, superset): + """ + Default constructor. + + It takes the ``subset`` and its ``superset`` as its parameters. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.subset + ['c', 'd'] + >>> a.superset + ['a', 'b', 'c', 'd'] + >>> a.size + 2 + """ + if len(subset) > len(superset): + raise ValueError('Invalid arguments have been provided. The ' + 'superset must be larger than the subset.') + for elem in subset: + if elem not in superset: + raise ValueError('The superset provided is invalid as it does ' + 'not contain the element {}'.format(elem)) + obj = object.__new__(cls) + obj._subset = subset + obj._superset = superset + return obj + + def __eq__(self, other): + """Return a boolean indicating whether a == b on the basis of + whether both objects are of the class Subset and if the values + of the subset and superset attributes are the same. + """ + if not isinstance(other, Subset): + return NotImplemented + return self.subset == other.subset and self.superset == other.superset + + def iterate_binary(self, k): + """ + This is a helper function. It iterates over the + binary subsets by ``k`` steps. This variable can be + both positive or negative. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.iterate_binary(-2).subset + ['d'] + >>> a = Subset(['a', 'b', 'c'], ['a', 'b', 'c', 'd']) + >>> a.iterate_binary(2).subset + [] + + See Also + ======== + + next_binary, prev_binary + """ + bin_list = Subset.bitlist_from_subset(self.subset, self.superset) + n = (int(''.join(bin_list), 2) + k) % 2**self.superset_size + bits = bin(n)[2:].rjust(self.superset_size, '0') + return Subset.subset_from_bitlist(self.superset, bits) + + def next_binary(self): + """ + Generates the next binary ordered subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.next_binary().subset + ['b'] + >>> a = Subset(['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.next_binary().subset + [] + + See Also + ======== + + prev_binary, iterate_binary + """ + return self.iterate_binary(1) + + def prev_binary(self): + """ + Generates the previous binary ordered subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset([], ['a', 'b', 'c', 'd']) + >>> a.prev_binary().subset + ['a', 'b', 'c', 'd'] + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.prev_binary().subset + ['c'] + + See Also + ======== + + next_binary, iterate_binary + """ + return self.iterate_binary(-1) + + def next_lexicographic(self): + """ + Generates the next lexicographically ordered subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.next_lexicographic().subset + ['d'] + >>> a = Subset(['d'], ['a', 'b', 'c', 'd']) + >>> a.next_lexicographic().subset + [] + + See Also + ======== + + prev_lexicographic + """ + i = self.superset_size - 1 + indices = Subset.subset_indices(self.subset, self.superset) + + if i in indices: + if i - 1 in indices: + indices.remove(i - 1) + else: + indices.remove(i) + i = i - 1 + while i >= 0 and i not in indices: + i = i - 1 + if i >= 0: + indices.remove(i) + indices.append(i+1) + else: + while i not in indices and i >= 0: + i = i - 1 + indices.append(i + 1) + + ret_set = [] + super_set = self.superset + for i in indices: + ret_set.append(super_set[i]) + return Subset(ret_set, super_set) + + def prev_lexicographic(self): + """ + Generates the previous lexicographically ordered subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset([], ['a', 'b', 'c', 'd']) + >>> a.prev_lexicographic().subset + ['d'] + >>> a = Subset(['c','d'], ['a', 'b', 'c', 'd']) + >>> a.prev_lexicographic().subset + ['c'] + + See Also + ======== + + next_lexicographic + """ + i = self.superset_size - 1 + indices = Subset.subset_indices(self.subset, self.superset) + + while i >= 0 and i not in indices: + i = i - 1 + + if i == 0 or i - 1 in indices: + indices.remove(i) + else: + if i >= 0: + indices.remove(i) + indices.append(i - 1) + indices.append(self.superset_size - 1) + + ret_set = [] + super_set = self.superset + for i in indices: + ret_set.append(super_set[i]) + return Subset(ret_set, super_set) + + def iterate_graycode(self, k): + """ + Helper function used for prev_gray and next_gray. + It performs ``k`` step overs to get the respective Gray codes. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset([1, 2, 3], [1, 2, 3, 4]) + >>> a.iterate_graycode(3).subset + [1, 4] + >>> a.iterate_graycode(-2).subset + [1, 2, 4] + + See Also + ======== + + next_gray, prev_gray + """ + unranked_code = GrayCode.unrank(self.superset_size, + (self.rank_gray + k) % self.cardinality) + return Subset.subset_from_bitlist(self.superset, + unranked_code) + + def next_gray(self): + """ + Generates the next Gray code ordered subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset([1, 2, 3], [1, 2, 3, 4]) + >>> a.next_gray().subset + [1, 3] + + See Also + ======== + + iterate_graycode, prev_gray + """ + return self.iterate_graycode(1) + + def prev_gray(self): + """ + Generates the previous Gray code ordered subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset([2, 3, 4], [1, 2, 3, 4, 5]) + >>> a.prev_gray().subset + [2, 3, 4, 5] + + See Also + ======== + + iterate_graycode, next_gray + """ + return self.iterate_graycode(-1) + + @property + def rank_binary(self): + """ + Computes the binary ordered rank. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset([], ['a','b','c','d']) + >>> a.rank_binary + 0 + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.rank_binary + 3 + + See Also + ======== + + iterate_binary, unrank_binary + """ + if self._rank_binary is None: + self._rank_binary = int("".join( + Subset.bitlist_from_subset(self.subset, + self.superset)), 2) + return self._rank_binary + + @property + def rank_lexicographic(self): + """ + Computes the lexicographic ranking of the subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.rank_lexicographic + 14 + >>> a = Subset([2, 4, 5], [1, 2, 3, 4, 5, 6]) + >>> a.rank_lexicographic + 43 + """ + if self._rank_lex is None: + def _ranklex(self, subset_index, i, n): + if subset_index == [] or i > n: + return 0 + if i in subset_index: + subset_index.remove(i) + return 1 + _ranklex(self, subset_index, i + 1, n) + return 2**(n - i - 1) + _ranklex(self, subset_index, i + 1, n) + indices = Subset.subset_indices(self.subset, self.superset) + self._rank_lex = _ranklex(self, indices, 0, self.superset_size) + return self._rank_lex + + @property + def rank_gray(self): + """ + Computes the Gray code ranking of the subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c','d'], ['a','b','c','d']) + >>> a.rank_gray + 2 + >>> a = Subset([2, 4, 5], [1, 2, 3, 4, 5, 6]) + >>> a.rank_gray + 27 + + See Also + ======== + + iterate_graycode, unrank_gray + """ + if self._rank_graycode is None: + bits = Subset.bitlist_from_subset(self.subset, self.superset) + self._rank_graycode = GrayCode(len(bits), start=bits).rank + return self._rank_graycode + + @property + def subset(self): + """ + Gets the subset represented by the current instance. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.subset + ['c', 'd'] + + See Also + ======== + + superset, size, superset_size, cardinality + """ + return self._subset + + @property + def size(self): + """ + Gets the size of the subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.size + 2 + + See Also + ======== + + subset, superset, superset_size, cardinality + """ + return len(self.subset) + + @property + def superset(self): + """ + Gets the superset of the subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.superset + ['a', 'b', 'c', 'd'] + + See Also + ======== + + subset, size, superset_size, cardinality + """ + return self._superset + + @property + def superset_size(self): + """ + Returns the size of the superset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.superset_size + 4 + + See Also + ======== + + subset, superset, size, cardinality + """ + return len(self.superset) + + @property + def cardinality(self): + """ + Returns the number of all possible subsets. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + >>> a.cardinality + 16 + + See Also + ======== + + subset, superset, size, superset_size + """ + return 2**(self.superset_size) + + @classmethod + def subset_from_bitlist(self, super_set, bitlist): + """ + Gets the subset defined by the bitlist. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> Subset.subset_from_bitlist(['a', 'b', 'c', 'd'], '0011').subset + ['c', 'd'] + + See Also + ======== + + bitlist_from_subset + """ + if len(super_set) != len(bitlist): + raise ValueError("The sizes of the lists are not equal") + ret_set = [] + for i in range(len(bitlist)): + if bitlist[i] == '1': + ret_set.append(super_set[i]) + return Subset(ret_set, super_set) + + @classmethod + def bitlist_from_subset(self, subset, superset): + """ + Gets the bitlist corresponding to a subset. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> Subset.bitlist_from_subset(['c', 'd'], ['a', 'b', 'c', 'd']) + '0011' + + See Also + ======== + + subset_from_bitlist + """ + bitlist = ['0'] * len(superset) + if isinstance(subset, Subset): + subset = subset.subset + for i in Subset.subset_indices(subset, superset): + bitlist[i] = '1' + return ''.join(bitlist) + + @classmethod + def unrank_binary(self, rank, superset): + """ + Gets the binary ordered subset of the specified rank. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> Subset.unrank_binary(4, ['a', 'b', 'c', 'd']).subset + ['b'] + + See Also + ======== + + iterate_binary, rank_binary + """ + bits = bin(rank)[2:].rjust(len(superset), '0') + return Subset.subset_from_bitlist(superset, bits) + + @classmethod + def unrank_gray(self, rank, superset): + """ + Gets the Gray code ordered subset of the specified rank. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> Subset.unrank_gray(4, ['a', 'b', 'c']).subset + ['a', 'b'] + >>> Subset.unrank_gray(0, ['a', 'b', 'c']).subset + [] + + See Also + ======== + + iterate_graycode, rank_gray + """ + graycode_bitlist = GrayCode.unrank(len(superset), rank) + return Subset.subset_from_bitlist(superset, graycode_bitlist) + + @classmethod + def subset_indices(self, subset, superset): + """Return indices of subset in superset in a list; the list is empty + if all elements of ``subset`` are not in ``superset``. + + Examples + ======== + + >>> from sympy.combinatorics import Subset + >>> superset = [1, 3, 2, 5, 4] + >>> Subset.subset_indices([3, 2, 1], superset) + [1, 2, 0] + >>> Subset.subset_indices([1, 6], superset) + [] + >>> Subset.subset_indices([], superset) + [] + + """ + a, b = superset, subset + sb = set(b) + d = {} + for i, ai in enumerate(a): + if ai in sb: + d[ai] = i + sb.remove(ai) + if not sb: + break + else: + return [] + return [d[bi] for bi in b] + + +def ksubsets(superset, k): + """ + Finds the subsets of size ``k`` in lexicographic order. + + This uses the itertools generator. + + Examples + ======== + + >>> from sympy.combinatorics.subsets import ksubsets + >>> list(ksubsets([1, 2, 3], 2)) + [(1, 2), (1, 3), (2, 3)] + >>> list(ksubsets([1, 2, 3, 4, 5], 2)) + [(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), \ + (2, 5), (3, 4), (3, 5), (4, 5)] + + See Also + ======== + + Subset + """ + return combinations(superset, k) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/tensor_can.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/tensor_can.py new file mode 100644 index 0000000000000000000000000000000000000000..d43e96ed27a21f988aaaa8fd16827987541f7373 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/tensor_can.py @@ -0,0 +1,1189 @@ +from sympy.combinatorics.permutations import Permutation, _af_rmul, \ + _af_invert, _af_new +from sympy.combinatorics.perm_groups import PermutationGroup, _orbit, \ + _orbit_transversal +from sympy.combinatorics.util import _distribute_gens_by_base, \ + _orbits_transversals_from_bsgs + +""" + References for tensor canonicalization: + + [1] R. Portugal "Algorithmic simplification of tensor expressions", + J. Phys. A 32 (1999) 7779-7789 + + [2] R. Portugal, B.F. Svaiter "Group-theoretic Approach for Symbolic + Tensor Manipulation: I. Free Indices" + arXiv:math-ph/0107031v1 + + [3] L.R.U. Manssur, R. Portugal "Group-theoretic Approach for Symbolic + Tensor Manipulation: II. Dummy Indices" + arXiv:math-ph/0107032v1 + + [4] xperm.c part of XPerm written by J. M. Martin-Garcia + http://www.xact.es/index.html +""" + + +def dummy_sgs(dummies, sym, n): + """ + Return the strong generators for dummy indices. + + Parameters + ========== + + dummies : List of dummy indices. + `dummies[2k], dummies[2k+1]` are paired indices. + In base form, the dummy indices are always in + consecutive positions. + sym : symmetry under interchange of contracted dummies:: + * None no symmetry + * 0 commuting + * 1 anticommuting + + n : number of indices + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import dummy_sgs + >>> dummy_sgs(list(range(2, 8)), 0, 8) + [[0, 1, 3, 2, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 5, 4, 6, 7, 8, 9], + [0, 1, 2, 3, 4, 5, 7, 6, 8, 9], [0, 1, 4, 5, 2, 3, 6, 7, 8, 9], + [0, 1, 2, 3, 6, 7, 4, 5, 8, 9]] + """ + if len(dummies) > n: + raise ValueError("List too large") + res = [] + # exchange of contravariant and covariant indices + if sym is not None: + for j in dummies[::2]: + a = list(range(n + 2)) + if sym == 1: + a[n] = n + 1 + a[n + 1] = n + a[j], a[j + 1] = a[j + 1], a[j] + res.append(a) + # rename dummy indices + for j in dummies[:-3:2]: + a = list(range(n + 2)) + a[j:j + 4] = a[j + 2], a[j + 3], a[j], a[j + 1] + res.append(a) + return res + + +def _min_dummies(dummies, sym, indices): + """ + Return list of minima of the orbits of indices in group of dummies. + See ``double_coset_can_rep`` for the description of ``dummies`` and ``sym``. + ``indices`` is the initial list of dummy indices. + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import _min_dummies + >>> _min_dummies([list(range(2, 8))], [0], list(range(10))) + [0, 1, 2, 2, 2, 2, 2, 2, 8, 9] + """ + num_types = len(sym) + m = [min(dx) if dx else None for dx in dummies] + res = indices[:] + for i in range(num_types): + for c, i in enumerate(indices): + for j in range(num_types): + if i in dummies[j]: + res[c] = m[j] + break + return res + + +def _trace_S(s, j, b, S_cosets): + """ + Return the representative h satisfying s[h[b]] == j + + If there is not such a representative return None + """ + for h in S_cosets[b]: + if s[h[b]] == j: + return h + return None + + +def _trace_D(gj, p_i, Dxtrav): + """ + Return the representative h satisfying h[gj] == p_i + + If there is not such a representative return None + """ + for h in Dxtrav: + if h[gj] == p_i: + return h + return None + + +def _dumx_remove(dumx, dumx_flat, p0): + """ + remove p0 from dumx + """ + res = [] + for dx in dumx: + if p0 not in dx: + res.append(dx) + continue + k = dx.index(p0) + if k % 2 == 0: + p0_paired = dx[k + 1] + else: + p0_paired = dx[k - 1] + dx.remove(p0) + dx.remove(p0_paired) + dumx_flat.remove(p0) + dumx_flat.remove(p0_paired) + res.append(dx) + + +def transversal2coset(size, base, transversal): + a = [] + j = 0 + for i in range(size): + if i in base: + a.append(sorted(transversal[j].values())) + j += 1 + else: + a.append([list(range(size))]) + j = len(a) - 1 + while a[j] == [list(range(size))]: + j -= 1 + return a[:j + 1] + + +def double_coset_can_rep(dummies, sym, b_S, sgens, S_transversals, g): + r""" + Butler-Portugal algorithm for tensor canonicalization with dummy indices. + + Parameters + ========== + + dummies + list of lists of dummy indices, + one list for each type of index; + the dummy indices are put in order contravariant, covariant + [d0, -d0, d1, -d1, ...]. + + sym + list of the symmetries of the index metric for each type. + + possible symmetries of the metrics + * 0 symmetric + * 1 antisymmetric + * None no symmetry + + b_S + base of a minimal slot symmetry BSGS. + + sgens + generators of the slot symmetry BSGS. + + S_transversals + transversals for the slot BSGS. + + g + permutation representing the tensor. + + Returns + ======= + + Return 0 if the tensor is zero, else return the array form of + the permutation representing the canonical form of the tensor. + + Notes + ===== + + A tensor with dummy indices can be represented in a number + of equivalent ways which typically grows exponentially with + the number of indices. To be able to establish if two tensors + with many indices are equal becomes computationally very slow + in absence of an efficient algorithm. + + The Butler-Portugal algorithm [3] is an efficient algorithm to + put tensors in canonical form, solving the above problem. + + Portugal observed that a tensor can be represented by a permutation, + and that the class of tensors equivalent to it under slot and dummy + symmetries is equivalent to the double coset `D*g*S` + (Note: in this documentation we use the conventions for multiplication + of permutations p, q with (p*q)(i) = p[q[i]] which is opposite + to the one used in the Permutation class) + + Using the algorithm by Butler to find a representative of the + double coset one can find a canonical form for the tensor. + + To see this correspondence, + let `g` be a permutation in array form; a tensor with indices `ind` + (the indices including both the contravariant and the covariant ones) + can be written as + + `t = T(ind[g[0]], \dots, ind[g[n-1]])`, + + where `n = len(ind)`; + `g` has size `n + 2`, the last two indices for the sign of the tensor + (trick introduced in [4]). + + A slot symmetry transformation `s` is a permutation acting on the slots + `t \rightarrow T(ind[(g*s)[0]], \dots, ind[(g*s)[n-1]])` + + A dummy symmetry transformation acts on `ind` + `t \rightarrow T(ind[(d*g)[0]], \dots, ind[(d*g)[n-1]])` + + Being interested only in the transformations of the tensor under + these symmetries, one can represent the tensor by `g`, which transforms + as + + `g -> d*g*s`, so it belongs to the coset `D*g*S`, or in other words + to the set of all permutations allowed by the slot and dummy symmetries. + + Let us explain the conventions by an example. + + Given a tensor `T^{d3 d2 d1}{}_{d1 d2 d3}` with the slot symmetries + `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}` + + `T^{a0 a1 a2 a3 a4 a5} = -T^{a4 a1 a2 a3 a0 a5}` + + and symmetric metric, find the tensor equivalent to it which + is the lowest under the ordering of indices: + lexicographic ordering `d1, d2, d3` and then contravariant + before covariant index; that is the canonical form of the tensor. + + The canonical form is `-T^{d1 d2 d3}{}_{d1 d2 d3}` + obtained using `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}`. + + To convert this problem in the input for this function, + use the following ordering of the index names + (- for covariant for short) `d1, -d1, d2, -d2, d3, -d3` + + `T^{d3 d2 d1}{}_{d1 d2 d3}` corresponds to `g = [4, 2, 0, 1, 3, 5, 6, 7]` + where the last two indices are for the sign + + `sgens = [Permutation(0, 2)(6, 7), Permutation(0, 4)(6, 7)]` + + sgens[0] is the slot symmetry `-(0, 2)` + `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}` + + sgens[1] is the slot symmetry `-(0, 4)` + `T^{a0 a1 a2 a3 a4 a5} = -T^{a4 a1 a2 a3 a0 a5}` + + The dummy symmetry group D is generated by the strong base generators + `[(0, 1), (2, 3), (4, 5), (0, 2)(1, 3), (0, 4)(1, 5)]` + where the first three interchange covariant and contravariant + positions of the same index (d1 <-> -d1) and the last two interchange + the dummy indices themselves (d1 <-> d2). + + The dummy symmetry acts from the left + `d = [1, 0, 2, 3, 4, 5, 6, 7]` exchange `d1 \leftrightarrow -d1` + `T^{d3 d2 d1}{}_{d1 d2 d3} == T^{d3 d2}{}_{d1}{}^{d1}{}_{d2 d3}` + + `g=[4, 2, 0, 1, 3, 5, 6, 7] -> [4, 2, 1, 0, 3, 5, 6, 7] = _af_rmul(d, g)` + which differs from `_af_rmul(g, d)`. + + The slot symmetry acts from the right + `s = [2, 1, 0, 3, 4, 5, 7, 6]` exchanges slots 0 and 2 and changes sign + `T^{d3 d2 d1}{}_{d1 d2 d3} == -T^{d1 d2 d3}{}_{d1 d2 d3}` + + `g=[4,2,0,1,3,5,6,7] -> [0, 2, 4, 1, 3, 5, 7, 6] = _af_rmul(g, s)` + + Example in which the tensor is zero, same slot symmetries as above: + `T^{d2}{}_{d1 d3}{}^{d1 d3}{}_{d2}` + + `= -T^{d3}{}_{d1 d3}{}^{d1 d2}{}_{d2}` under slot symmetry `-(0,4)`; + + `= T_{d3 d1}{}^{d3}{}^{d1 d2}{}_{d2}` under slot symmetry `-(0,2)`; + + `= T^{d3}{}_{d1 d3}{}^{d1 d2}{}_{d2}` symmetric metric; + + `= 0` since two of these lines have tensors differ only for the sign. + + The double coset D*g*S consists of permutations `h = d*g*s` corresponding + to equivalent tensors; if there are two `h` which are the same apart + from the sign, return zero; otherwise + choose as representative the tensor with indices + ordered lexicographically according to `[d1, -d1, d2, -d2, d3, -d3]` + that is ``rep = min(D*g*S) = min([d*g*s for d in D for s in S])`` + + The indices are fixed one by one; first choose the lowest index + for slot 0, then the lowest remaining index for slot 1, etc. + Doing this one obtains a chain of stabilizers + + `S \rightarrow S_{b0} \rightarrow S_{b0,b1} \rightarrow \dots` and + `D \rightarrow D_{p0} \rightarrow D_{p0,p1} \rightarrow \dots` + + where ``[b0, b1, ...] = range(b)`` is a base of the symmetric group; + the strong base `b_S` of S is an ordered sublist of it; + therefore it is sufficient to compute once the + strong base generators of S using the Schreier-Sims algorithm; + the stabilizers of the strong base generators are the + strong base generators of the stabilizer subgroup. + + ``dbase = [p0, p1, ...]`` is not in general in lexicographic order, + so that one must recompute the strong base generators each time; + however this is trivial, there is no need to use the Schreier-Sims + algorithm for D. + + The algorithm keeps a TAB of elements `(s_i, d_i, h_i)` + where `h_i = d_i \times g \times s_i` satisfying `h_i[j] = p_j` for `0 \le j < i` + starting from `s_0 = id, d_0 = id, h_0 = g`. + + The equations `h_0[0] = p_0, h_1[1] = p_1, \dots` are solved in this order, + choosing each time the lowest possible value of p_i + + For `j < i` + `d_i*g*s_i*S_{b_0, \dots, b_{i-1}}*b_j = D_{p_0, \dots, p_{i-1}}*p_j` + so that for dx in `D_{p_0,\dots,p_{i-1}}` and sx in + `S_{base[0], \dots, base[i-1]}` one has `dx*d_i*g*s_i*sx*b_j = p_j` + + Search for dx, sx such that this equation holds for `j = i`; + it can be written as `s_i*sx*b_j = J, dx*d_i*g*J = p_j` + `sx*b_j = s_i**-1*J; sx = trace(s_i**-1, S_{b_0,...,b_{i-1}})` + `dx**-1*p_j = d_i*g*J; dx = trace(d_i*g*J, D_{p_0,...,p_{i-1}})` + + `s_{i+1} = s_i*trace(s_i**-1*J, S_{b_0,...,b_{i-1}})` + `d_{i+1} = trace(d_i*g*J, D_{p_0,...,p_{i-1}})**-1*d_i` + `h_{i+1}*b_i = d_{i+1}*g*s_{i+1}*b_i = p_i` + + `h_n*b_j = p_j` for all j, so that `h_n` is the solution. + + Add the found `(s, d, h)` to TAB1. + + At the end of the iteration sort TAB1 with respect to the `h`; + if there are two consecutive `h` in TAB1 which differ only for the + sign, the tensor is zero, so return 0; + if there are two consecutive `h` which are equal, keep only one. + + Then stabilize the slot generators under `i` and the dummy generators + under `p_i`. + + Assign `TAB = TAB1` at the end of the iteration step. + + At the end `TAB` contains a unique `(s, d, h)`, since all the slots + of the tensor `h` have been fixed to have the minimum value according + to the symmetries. The algorithm returns `h`. + + It is important that the slot BSGS has lexicographic minimal base, + otherwise there is an `i` which does not belong to the slot base + for which `p_i` is fixed by the dummy symmetry only, while `i` + is not invariant from the slot stabilizer, so `p_i` is not in + general the minimal value. + + This algorithm differs slightly from the original algorithm [3]: + the canonical form is minimal lexicographically, and + the BSGS has minimal base under lexicographic order. + Equal tensors `h` are eliminated from TAB. + + + Examples + ======== + + >>> from sympy.combinatorics.permutations import Permutation + >>> from sympy.combinatorics.tensor_can import double_coset_can_rep, get_transversals + >>> gens = [Permutation(x) for x in [[2, 1, 0, 3, 4, 5, 7, 6], [4, 1, 2, 3, 0, 5, 7, 6]]] + >>> base = [0, 2] + >>> g = Permutation([4, 2, 0, 1, 3, 5, 6, 7]) + >>> transversals = get_transversals(base, gens) + >>> double_coset_can_rep([list(range(6))], [0], base, gens, transversals, g) + [0, 1, 2, 3, 4, 5, 7, 6] + + >>> g = Permutation([4, 1, 3, 0, 5, 2, 6, 7]) + >>> double_coset_can_rep([list(range(6))], [0], base, gens, transversals, g) + 0 + """ + size = g.size + g = g.array_form + num_dummies = size - 2 + indices = list(range(num_dummies)) + all_metrics_with_sym = not any(_ is None for _ in sym) + num_types = len(sym) + dumx = dummies[:] + dumx_flat = [] + for dx in dumx: + dumx_flat.extend(dx) + b_S = b_S[:] + sgensx = [h._array_form for h in sgens] + if b_S: + S_transversals = transversal2coset(size, b_S, S_transversals) + # strong generating set for D + dsgsx = [] + for i in range(num_types): + dsgsx.extend(dummy_sgs(dumx[i], sym[i], num_dummies)) + idn = list(range(size)) + # TAB = list of entries (s, d, h) where h = _af_rmuln(d,g,s) + # for short, in the following d*g*s means _af_rmuln(d,g,s) + TAB = [(idn, idn, g)] + for i in range(size - 2): + b = i + testb = b in b_S and sgensx + if testb: + sgensx1 = [_af_new(_) for _ in sgensx] + deltab = _orbit(size, sgensx1, b) + else: + deltab = {b} + # p1 = min(IMAGES) = min(Union D_p*h*deltab for h in TAB) + if all_metrics_with_sym: + md = _min_dummies(dumx, sym, indices) + else: + md = [min(_orbit(size, [_af_new( + ddx) for ddx in dsgsx], ii)) for ii in range(size - 2)] + + p_i = min(min(md[h[x]] for x in deltab) for s, d, h in TAB) + dsgsx1 = [_af_new(_) for _ in dsgsx] + Dxtrav = _orbit_transversal(size, dsgsx1, p_i, False, af=True) \ + if dsgsx else None + if Dxtrav: + Dxtrav = [_af_invert(x) for x in Dxtrav] + # compute the orbit of p_i + for ii in range(num_types): + if p_i in dumx[ii]: + # the orbit is made by all the indices in dum[ii] + if sym[ii] is not None: + deltap = dumx[ii] + else: + # the orbit is made by all the even indices if p_i + # is even, by all the odd indices if p_i is odd + p_i_index = dumx[ii].index(p_i) % 2 + deltap = dumx[ii][p_i_index::2] + break + else: + deltap = [p_i] + TAB1 = [] + while TAB: + s, d, h = TAB.pop() + if min(md[h[x]] for x in deltab) != p_i: + continue + deltab1 = [x for x in deltab if md[h[x]] == p_i] + # NEXT = s*deltab1 intersection (d*g)**-1*deltap + dg = _af_rmul(d, g) + dginv = _af_invert(dg) + sdeltab = [s[x] for x in deltab1] + gdeltap = [dginv[x] for x in deltap] + NEXT = [x for x in sdeltab if x in gdeltap] + # d, s satisfy + # d*g*s*base[i-1] = p_{i-1}; using the stabilizers + # d*g*s*S_{base[0],...,base[i-1]}*base[i-1] = + # D_{p_0,...,p_{i-1}}*p_{i-1} + # so that to find d1, s1 satisfying d1*g*s1*b = p_i + # one can look for dx in D_{p_0,...,p_{i-1}} and + # sx in S_{base[0],...,base[i-1]} + # d1 = dx*d; s1 = s*sx + # d1*g*s1*b = dx*d*g*s*sx*b = p_i + for j in NEXT: + if testb: + # solve s1*b = j with s1 = s*sx for some element sx + # of the stabilizer of ..., base[i-1] + # sx*b = s**-1*j; sx = _trace_S(s, j,...) + # s1 = s*trace_S(s**-1*j,...) + s1 = _trace_S(s, j, b, S_transversals) + if not s1: + continue + else: + s1 = [s[ix] for ix in s1] + else: + s1 = s + # assert s1[b] == j # invariant + # solve d1*g*j = p_i with d1 = dx*d for some element dg + # of the stabilizer of ..., p_{i-1} + # dx**-1*p_i = d*g*j; dx**-1 = trace_D(d*g*j,...) + # d1 = trace_D(d*g*j,...)**-1*d + # to save an inversion in the inner loop; notice we did + # Dxtrav = [perm_af_invert(x) for x in Dxtrav] out of the loop + if Dxtrav: + d1 = _trace_D(dg[j], p_i, Dxtrav) + if not d1: + continue + else: + if p_i != dg[j]: + continue + d1 = idn + assert d1[dg[j]] == p_i # invariant + d1 = [d1[ix] for ix in d] + h1 = [d1[g[ix]] for ix in s1] + # assert h1[b] == p_i # invariant + TAB1.append((s1, d1, h1)) + + # if TAB contains equal permutations, keep only one of them; + # if TAB contains equal permutations up to the sign, return 0 + TAB1.sort(key=lambda x: x[-1]) + prev = [0] * size + while TAB1: + s, d, h = TAB1.pop() + if h[:-2] == prev[:-2]: + if h[-1] != prev[-1]: + return 0 + else: + TAB.append((s, d, h)) + prev = h + + # stabilize the SGS + sgensx = [h for h in sgensx if h[b] == b] + if b in b_S: + b_S.remove(b) + _dumx_remove(dumx, dumx_flat, p_i) + dsgsx = [] + for i in range(num_types): + dsgsx.extend(dummy_sgs(dumx[i], sym[i], num_dummies)) + return TAB[0][-1] + + +def canonical_free(base, gens, g, num_free): + """ + Canonicalization of a tensor with respect to free indices + choosing the minimum with respect to lexicographical ordering + in the free indices. + + Explanation + =========== + + ``base``, ``gens`` BSGS for slot permutation group + ``g`` permutation representing the tensor + ``num_free`` number of free indices + The indices must be ordered with first the free indices + + See explanation in double_coset_can_rep + The algorithm is a variation of the one given in [2]. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import canonical_free + >>> gens = [[1, 0, 2, 3, 5, 4], [2, 3, 0, 1, 4, 5],[0, 1, 3, 2, 5, 4]] + >>> gens = [Permutation(h) for h in gens] + >>> base = [0, 2] + >>> g = Permutation([2, 1, 0, 3, 4, 5]) + >>> canonical_free(base, gens, g, 4) + [0, 3, 1, 2, 5, 4] + + Consider the product of Riemann tensors + ``T = R^{a}_{d0}^{d1,d2}*R_{d2,d1}^{d0,b}`` + The order of the indices is ``[a, b, d0, -d0, d1, -d1, d2, -d2]`` + The permutation corresponding to the tensor is + ``g = [0, 3, 4, 6, 7, 5, 2, 1, 8, 9]`` + + In particular ``a`` is position ``0``, ``b`` is in position ``9``. + Use the slot symmetries to get `T` is a form which is the minimal + in lexicographic order in the free indices ``a`` and ``b``, e.g. + ``-R^{a}_{d0}^{d1,d2}*R^{b,d0}_{d2,d1}`` corresponding to + ``[0, 3, 4, 6, 1, 2, 7, 5, 9, 8]`` + + >>> from sympy.combinatorics.tensor_can import riemann_bsgs, tensor_gens + >>> base, gens = riemann_bsgs + >>> size, sbase, sgens = tensor_gens(base, gens, [[], []], 0) + >>> g = Permutation([0, 3, 4, 6, 7, 5, 2, 1, 8, 9]) + >>> canonical_free(sbase, [Permutation(h) for h in sgens], g, 2) + [0, 3, 4, 6, 1, 2, 7, 5, 9, 8] + """ + g = g.array_form + size = len(g) + if not base: + return g[:] + + transversals = get_transversals(base, gens) + for x in sorted(g[:-2]): + if x not in base: + base.append(x) + h = g + for transv in transversals: + h_i = [size]*num_free + # find the element s in transversals[i] such that + # _af_rmul(h, s) has its free elements with the lowest position in h + s = None + for sk in transv.values(): + h1 = _af_rmul(h, sk) + hi = [h1.index(ix) for ix in range(num_free)] + if hi < h_i: + h_i = hi + s = sk + if s: + h = _af_rmul(h, s) + return h + + +def _get_map_slots(size, fixed_slots): + res = list(range(size)) + pos = 0 + for i in range(size): + if i in fixed_slots: + continue + res[i] = pos + pos += 1 + return res + + +def _lift_sgens(size, fixed_slots, free, s): + a = [] + j = k = 0 + fd = [y for _, y in sorted(zip(fixed_slots, free))] + num_free = len(free) + for i in range(size): + if i in fixed_slots: + a.append(fd[k]) + k += 1 + else: + a.append(s[j] + num_free) + j += 1 + return a + + +def canonicalize(g, dummies, msym, *v): + """ + canonicalize tensor formed by tensors + + Parameters + ========== + + g : permutation representing the tensor + + dummies : list representing the dummy indices + it can be a list of dummy indices of the same type + or a list of lists of dummy indices, one list for each + type of index; + the dummy indices must come after the free indices, + and put in order contravariant, covariant + [d0, -d0, d1,-d1,...] + + msym : symmetry of the metric(s) + it can be an integer or a list; + in the first case it is the symmetry of the dummy index metric; + in the second case it is the list of the symmetries of the + index metric for each type + + v : list, (base_i, gens_i, n_i, sym_i) for tensors of type `i` + + base_i, gens_i : BSGS for tensors of this type. + The BSGS should have minimal base under lexicographic ordering; + if not, an attempt is made do get the minimal BSGS; + in case of failure, + canonicalize_naive is used, which is much slower. + + n_i : number of tensors of type `i`. + + sym_i : symmetry under exchange of component tensors of type `i`. + + Both for msym and sym_i the cases are + * None no symmetry + * 0 commuting + * 1 anticommuting + + Returns + ======= + + 0 if the tensor is zero, else return the array form of + the permutation representing the canonical form of the tensor. + + Algorithm + ========= + + First one uses canonical_free to get the minimum tensor under + lexicographic order, using only the slot symmetries. + If the component tensors have not minimal BSGS, it is attempted + to find it; if the attempt fails canonicalize_naive + is used instead. + + Compute the residual slot symmetry keeping fixed the free indices + using tensor_gens(base, gens, list_free_indices, sym). + + Reduce the problem eliminating the free indices. + + Then use double_coset_can_rep and lift back the result reintroducing + the free indices. + + Examples + ======== + + one type of index with commuting metric; + + `A_{a b}` and `B_{a b}` antisymmetric and commuting + + `T = A_{d0 d1} * B^{d0}{}_{d2} * B^{d2 d1}` + + `ord = [d0,-d0,d1,-d1,d2,-d2]` order of the indices + + g = [1, 3, 0, 5, 4, 2, 6, 7] + + `T_c = 0` + + >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize, bsgs_direct_product + >>> from sympy.combinatorics import Permutation + >>> base2a, gens2a = get_symmetric_group_sgs(2, 1) + >>> t0 = (base2a, gens2a, 1, 0) + >>> t1 = (base2a, gens2a, 2, 0) + >>> g = Permutation([1, 3, 0, 5, 4, 2, 6, 7]) + >>> canonicalize(g, range(6), 0, t0, t1) + 0 + + same as above, but with `B_{a b}` anticommuting + + `T_c = -A^{d0 d1} * B_{d0}{}^{d2} * B_{d1 d2}` + + can = [0,2,1,4,3,5,7,6] + + >>> t1 = (base2a, gens2a, 2, 1) + >>> canonicalize(g, range(6), 0, t0, t1) + [0, 2, 1, 4, 3, 5, 7, 6] + + two types of indices `[a,b,c,d,e,f]` and `[m,n]`, in this order, + both with commuting metric + + `f^{a b c}` antisymmetric, commuting + + `A_{m a}` no symmetry, commuting + + `T = f^c{}_{d a} * f^f{}_{e b} * A_m{}^d * A^{m b} * A_n{}^a * A^{n e}` + + ord = [c,f,a,-a,b,-b,d,-d,e,-e,m,-m,n,-n] + + g = [0,7,3, 1,9,5, 11,6, 10,4, 13,2, 12,8, 14,15] + + The canonical tensor is + `T_c = -f^{c a b} * f^{f d e} * A^m{}_a * A_{m d} * A^n{}_b * A_{n e}` + + can = [0,2,4, 1,6,8, 10,3, 11,7, 12,5, 13,9, 15,14] + + >>> base_f, gens_f = get_symmetric_group_sgs(3, 1) + >>> base1, gens1 = get_symmetric_group_sgs(1) + >>> base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) + >>> t0 = (base_f, gens_f, 2, 0) + >>> t1 = (base_A, gens_A, 4, 0) + >>> dummies = [range(2, 10), range(10, 14)] + >>> g = Permutation([0, 7, 3, 1, 9, 5, 11, 6, 10, 4, 13, 2, 12, 8, 14, 15]) + >>> canonicalize(g, dummies, [0, 0], t0, t1) + [0, 2, 4, 1, 6, 8, 10, 3, 11, 7, 12, 5, 13, 9, 15, 14] + """ + from sympy.combinatorics.testutil import canonicalize_naive + if not isinstance(msym, list): + if msym not in (0, 1, None): + raise ValueError('msym must be 0, 1 or None') + num_types = 1 + else: + num_types = len(msym) + if not all(msymx in (0, 1, None) for msymx in msym): + raise ValueError('msym entries must be 0, 1 or None') + if len(dummies) != num_types: + raise ValueError( + 'dummies and msym must have the same number of elements') + size = g.size + num_tensors = 0 + v1 = [] + for base_i, gens_i, n_i, sym_i in v: + # check that the BSGS is minimal; + # this property is used in double_coset_can_rep; + # if it is not minimal use canonicalize_naive + if not _is_minimal_bsgs(base_i, gens_i): + mbsgs = get_minimal_bsgs(base_i, gens_i) + if not mbsgs: + can = canonicalize_naive(g, dummies, msym, *v) + return can + base_i, gens_i = mbsgs + v1.append((base_i, gens_i, [[]] * n_i, sym_i)) + num_tensors += n_i + + if num_types == 1 and not isinstance(msym, list): + dummies = [dummies] + msym = [msym] + flat_dummies = [] + for dumx in dummies: + flat_dummies.extend(dumx) + + if flat_dummies and flat_dummies != list(range(flat_dummies[0], flat_dummies[-1] + 1)): + raise ValueError('dummies is not valid') + + # slot symmetry of the tensor + size1, sbase, sgens = gens_products(*v1) + if size != size1: + raise ValueError( + 'g has size %d, generators have size %d' % (size, size1)) + free = [i for i in range(size - 2) if i not in flat_dummies] + num_free = len(free) + + # g1 minimal tensor under slot symmetry + g1 = canonical_free(sbase, sgens, g, num_free) + if not flat_dummies: + return g1 + # save the sign of g1 + sign = 0 if g1[-1] == size - 1 else 1 + + # the free indices are kept fixed. + # Determine free_i, the list of slots of tensors which are fixed + # since they are occupied by free indices, which are fixed. + start = 0 + for i, (base_i, gens_i, n_i, sym_i) in enumerate(v): + free_i = [] + len_tens = gens_i[0].size - 2 + # for each component tensor get a list od fixed islots + for j in range(n_i): + # get the elements corresponding to the component tensor + h = g1[start:(start + len_tens)] + fr = [] + # get the positions of the fixed elements in h + for k in free: + if k in h: + fr.append(h.index(k)) + free_i.append(fr) + start += len_tens + v1[i] = (base_i, gens_i, free_i, sym_i) + # BSGS of the tensor with fixed free indices + # if tensor_gens fails in gens_product, use canonicalize_naive + size, sbase, sgens = gens_products(*v1) + + # reduce the permutations getting rid of the free indices + pos_free = [g1.index(x) for x in range(num_free)] + size_red = size - num_free + g1_red = [x - num_free for x in g1 if x in flat_dummies] + if sign: + g1_red.extend([size_red - 1, size_red - 2]) + else: + g1_red.extend([size_red - 2, size_red - 1]) + map_slots = _get_map_slots(size, pos_free) + sbase_red = [map_slots[i] for i in sbase if i not in pos_free] + sgens_red = [_af_new([map_slots[i] for i in y._array_form if i not in pos_free]) for y in sgens] + dummies_red = [[x - num_free for x in y] for y in dummies] + transv_red = get_transversals(sbase_red, sgens_red) + g1_red = _af_new(g1_red) + g2 = double_coset_can_rep( + dummies_red, msym, sbase_red, sgens_red, transv_red, g1_red) + if g2 == 0: + return 0 + # lift to the case with the free indices + g3 = _lift_sgens(size, pos_free, free, g2) + return g3 + + +def perm_af_direct_product(gens1, gens2, signed=True): + """ + Direct products of the generators gens1 and gens2. + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import perm_af_direct_product + >>> gens1 = [[1, 0, 2, 3], [0, 1, 3, 2]] + >>> gens2 = [[1, 0]] + >>> perm_af_direct_product(gens1, gens2, False) + [[1, 0, 2, 3, 4, 5], [0, 1, 3, 2, 4, 5], [0, 1, 2, 3, 5, 4]] + >>> gens1 = [[1, 0, 2, 3, 5, 4], [0, 1, 3, 2, 4, 5]] + >>> gens2 = [[1, 0, 2, 3]] + >>> perm_af_direct_product(gens1, gens2, True) + [[1, 0, 2, 3, 4, 5, 7, 6], [0, 1, 3, 2, 4, 5, 6, 7], [0, 1, 2, 3, 5, 4, 6, 7]] + """ + gens1 = [list(x) for x in gens1] + gens2 = [list(x) for x in gens2] + s = 2 if signed else 0 + n1 = len(gens1[0]) - s + n2 = len(gens2[0]) - s + start = list(range(n1)) + end = list(range(n1, n1 + n2)) + if signed: + gens1 = [gen[:-2] + end + [gen[-2] + n2, gen[-1] + n2] + for gen in gens1] + gens2 = [start + [x + n1 for x in gen] for gen in gens2] + else: + gens1 = [gen + end for gen in gens1] + gens2 = [start + [x + n1 for x in gen] for gen in gens2] + + res = gens1 + gens2 + + return res + + +def bsgs_direct_product(base1, gens1, base2, gens2, signed=True): + """ + Direct product of two BSGS. + + Parameters + ========== + + base1 : base of the first BSGS. + + gens1 : strong generating sequence of the first BSGS. + + base2, gens2 : similarly for the second BSGS. + + signed : flag for signed permutations. + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import (get_symmetric_group_sgs, bsgs_direct_product) + >>> base1, gens1 = get_symmetric_group_sgs(1) + >>> base2, gens2 = get_symmetric_group_sgs(2) + >>> bsgs_direct_product(base1, gens1, base2, gens2) + ([1], [(4)(1 2)]) + """ + s = 2 if signed else 0 + n1 = gens1[0].size - s + base = list(base1) + base += [x + n1 for x in base2] + gens1 = [h._array_form for h in gens1] + gens2 = [h._array_form for h in gens2] + gens = perm_af_direct_product(gens1, gens2, signed) + size = len(gens[0]) + id_af = list(range(size)) + gens = [h for h in gens if h != id_af] + if not gens: + gens = [id_af] + return base, [_af_new(h) for h in gens] + + +def get_symmetric_group_sgs(n, antisym=False): + """ + Return base, gens of the minimal BSGS for (anti)symmetric tensor + + Parameters + ========== + + n : rank of the tensor + antisym : bool + ``antisym = False`` symmetric tensor + ``antisym = True`` antisymmetric tensor + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs + >>> get_symmetric_group_sgs(3) + ([0, 1], [(4)(0 1), (4)(1 2)]) + """ + if n == 1: + return [], [_af_new(list(range(3)))] + gens = [Permutation(n - 1)(i, i + 1)._array_form for i in range(n - 1)] + if antisym == 0: + gens = [x + [n, n + 1] for x in gens] + else: + gens = [x + [n + 1, n] for x in gens] + base = list(range(n - 1)) + return base, [_af_new(h) for h in gens] + +riemann_bsgs = [0, 2], [Permutation(0, 1)(4, 5), Permutation(2, 3)(4, 5), + Permutation(5)(0, 2)(1, 3)] + + +def get_transversals(base, gens): + """ + Return transversals for the group with BSGS base, gens + """ + if not base: + return [] + stabs = _distribute_gens_by_base(base, gens) + orbits, transversals = _orbits_transversals_from_bsgs(base, stabs) + transversals = [{x: h._array_form for x, h in y.items()} for y in + transversals] + return transversals + + +def _is_minimal_bsgs(base, gens): + """ + Check if the BSGS has minimal base under lexigographic order. + + base, gens BSGS + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import riemann_bsgs, _is_minimal_bsgs + >>> _is_minimal_bsgs(*riemann_bsgs) + True + >>> riemann_bsgs1 = ([2, 0], ([Permutation(5)(0, 1)(4, 5), Permutation(5)(0, 2)(1, 3)])) + >>> _is_minimal_bsgs(*riemann_bsgs1) + False + """ + base1 = [] + sgs1 = gens[:] + size = gens[0].size + for i in range(size): + if not all(h._array_form[i] == i for h in sgs1): + base1.append(i) + sgs1 = [h for h in sgs1 if h._array_form[i] == i] + return base1 == base + + +def get_minimal_bsgs(base, gens): + """ + Compute a minimal GSGS + + base, gens BSGS + + If base, gens is a minimal BSGS return it; else return a minimal BSGS + if it fails in finding one, it returns None + + TODO: use baseswap in the case in which if it fails in finding a + minimal BSGS + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import get_minimal_bsgs + >>> riemann_bsgs1 = ([2, 0], ([Permutation(5)(0, 1)(4, 5), Permutation(5)(0, 2)(1, 3)])) + >>> get_minimal_bsgs(*riemann_bsgs1) + ([0, 2], [(0 1)(4 5), (5)(0 2)(1 3), (2 3)(4 5)]) + """ + G = PermutationGroup(gens) + base, gens = G.schreier_sims_incremental() + if not _is_minimal_bsgs(base, gens): + return None + return base, gens + + +def tensor_gens(base, gens, list_free_indices, sym=0): + """ + Returns size, res_base, res_gens BSGS for n tensors of the + same type. + + Explanation + =========== + + base, gens BSGS for tensors of this type + list_free_indices list of the slots occupied by fixed indices + for each of the tensors + + sym symmetry under commutation of two tensors + sym None no symmetry + sym 0 commuting + sym 1 anticommuting + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import tensor_gens, get_symmetric_group_sgs + + two symmetric tensors with 3 indices without free indices + + >>> base, gens = get_symmetric_group_sgs(3) + >>> tensor_gens(base, gens, [[], []]) + (8, [0, 1, 3, 4], [(7)(0 1), (7)(1 2), (7)(3 4), (7)(4 5), (7)(0 3)(1 4)(2 5)]) + + two symmetric tensors with 3 indices with free indices in slot 1 and 0 + + >>> tensor_gens(base, gens, [[1], [0]]) + (8, [0, 4], [(7)(0 2), (7)(4 5)]) + + four symmetric tensors with 3 indices, two of which with free indices + + """ + def _get_bsgs(G, base, gens, free_indices): + """ + return the BSGS for G.pointwise_stabilizer(free_indices) + """ + if not free_indices: + return base[:], gens[:] + else: + H = G.pointwise_stabilizer(free_indices) + base, sgs = H.schreier_sims_incremental() + return base, sgs + + # if not base there is no slot symmetry for the component tensors + # if list_free_indices.count([]) < 2 there is no commutation symmetry + # so there is no resulting slot symmetry + if not base and list_free_indices.count([]) < 2: + n = len(list_free_indices) + size = gens[0].size + size = n * (size - 2) + 2 + return size, [], [_af_new(list(range(size)))] + + # if any(list_free_indices) one needs to compute the pointwise + # stabilizer, so G is needed + if any(list_free_indices): + G = PermutationGroup(gens) + else: + G = None + + # no_free list of lists of indices for component tensors without fixed + # indices + no_free = [] + size = gens[0].size + id_af = list(range(size)) + num_indices = size - 2 + if not list_free_indices[0]: + no_free.append(list(range(num_indices))) + res_base, res_gens = _get_bsgs(G, base, gens, list_free_indices[0]) + for i in range(1, len(list_free_indices)): + base1, gens1 = _get_bsgs(G, base, gens, list_free_indices[i]) + res_base, res_gens = bsgs_direct_product(res_base, res_gens, + base1, gens1, 1) + if not list_free_indices[i]: + no_free.append(list(range(size - 2, size - 2 + num_indices))) + size += num_indices + nr = size - 2 + res_gens = [h for h in res_gens if h._array_form != id_af] + # if sym there are no commuting tensors stop here + if sym is None or not no_free: + if not res_gens: + res_gens = [_af_new(id_af)] + return size, res_base, res_gens + + # if the component tensors have moinimal BSGS, so is their direct + # product P; the slot symmetry group is S = P*C, where C is the group + # to (anti)commute the component tensors with no free indices + # a stabilizer has the property S_i = P_i*C_i; + # the BSGS of P*C has SGS_P + SGS_C and the base is + # the ordered union of the bases of P and C. + # If P has minimal BSGS, so has S with this base. + base_comm = [] + for i in range(len(no_free) - 1): + ind1 = no_free[i] + ind2 = no_free[i + 1] + a = list(range(ind1[0])) + a.extend(ind2) + a.extend(ind1) + base_comm.append(ind1[0]) + a.extend(list(range(ind2[-1] + 1, nr))) + if sym == 0: + a.extend([nr, nr + 1]) + else: + a.extend([nr + 1, nr]) + res_gens.append(_af_new(a)) + res_base = list(res_base) + # each base is ordered; order the union of the two bases + for i in base_comm: + if i not in res_base: + res_base.append(i) + res_base.sort() + if not res_gens: + res_gens = [_af_new(id_af)] + + return size, res_base, res_gens + + +def gens_products(*v): + """ + Returns size, res_base, res_gens BSGS for n tensors of different types. + + Explanation + =========== + + v is a sequence of (base_i, gens_i, free_i, sym_i) + where + base_i, gens_i BSGS of tensor of type `i` + free_i list of the fixed slots for each of the tensors + of type `i`; if there are `n_i` tensors of type `i` + and none of them have fixed slots, `free = [[]]*n_i` + sym 0 (1) if the tensors of type `i` (anti)commute among themselves + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, gens_products + >>> base, gens = get_symmetric_group_sgs(2) + >>> gens_products((base, gens, [[], []], 0)) + (6, [0, 2], [(5)(0 1), (5)(2 3), (5)(0 2)(1 3)]) + >>> gens_products((base, gens, [[1], []], 0)) + (6, [2], [(5)(2 3)]) + """ + res_size, res_base, res_gens = tensor_gens(*v[0]) + for i in range(1, len(v)): + size, base, gens = tensor_gens(*v[i]) + res_base, res_gens = bsgs_direct_product(res_base, res_gens, base, + gens, 1) + res_size = res_gens[0].size + id_af = list(range(res_size)) + res_gens = [h for h in res_gens if h != id_af] + if not res_gens: + res_gens = [id_af] + return res_size, res_base, res_gens diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/testutil.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/testutil.py new file mode 100644 index 0000000000000000000000000000000000000000..9fe664ce9e7437b97feec90f2052eb2987c57a4e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/testutil.py @@ -0,0 +1,357 @@ +from sympy.combinatorics import Permutation +from sympy.combinatorics.util import _distribute_gens_by_base + +rmul = Permutation.rmul + + +def _cmp_perm_lists(first, second): + """ + Compare two lists of permutations as sets. + + Explanation + =========== + + This is used for testing purposes. Since the array form of a + permutation is currently a list, Permutation is not hashable + and cannot be put into a set. + + Examples + ======== + + >>> from sympy.combinatorics.permutations import Permutation + >>> from sympy.combinatorics.testutil import _cmp_perm_lists + >>> a = Permutation([0, 2, 3, 4, 1]) + >>> b = Permutation([1, 2, 0, 4, 3]) + >>> c = Permutation([3, 4, 0, 1, 2]) + >>> ls1 = [a, b, c] + >>> ls2 = [b, c, a] + >>> _cmp_perm_lists(ls1, ls2) + True + + """ + return {tuple(a) for a in first} == \ + {tuple(a) for a in second} + + +def _naive_list_centralizer(self, other, af=False): + from sympy.combinatorics.perm_groups import PermutationGroup + """ + Return a list of elements for the centralizer of a subgroup/set/element. + + Explanation + =========== + + This is a brute force implementation that goes over all elements of the + group and checks for membership in the centralizer. It is used to + test ``.centralizer()`` from ``sympy.combinatorics.perm_groups``. + + Examples + ======== + + >>> from sympy.combinatorics.testutil import _naive_list_centralizer + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> D = DihedralGroup(4) + >>> _naive_list_centralizer(D, D) + [Permutation([0, 1, 2, 3]), Permutation([2, 3, 0, 1])] + + See Also + ======== + + sympy.combinatorics.perm_groups.centralizer + + """ + from sympy.combinatorics.permutations import _af_commutes_with + if hasattr(other, 'generators'): + elements = list(self.generate_dimino(af=True)) + gens = [x._array_form for x in other.generators] + commutes_with_gens = lambda x: all(_af_commutes_with(x, gen) for gen in gens) + centralizer_list = [] + if not af: + for element in elements: + if commutes_with_gens(element): + centralizer_list.append(Permutation._af_new(element)) + else: + for element in elements: + if commutes_with_gens(element): + centralizer_list.append(element) + return centralizer_list + elif hasattr(other, 'getitem'): + return _naive_list_centralizer(self, PermutationGroup(other), af) + elif hasattr(other, 'array_form'): + return _naive_list_centralizer(self, PermutationGroup([other]), af) + + +def _verify_bsgs(group, base, gens): + """ + Verify the correctness of a base and strong generating set. + + Explanation + =========== + + This is a naive implementation using the definition of a base and a strong + generating set relative to it. There are other procedures for + verifying a base and strong generating set, but this one will + serve for more robust testing. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import AlternatingGroup + >>> from sympy.combinatorics.testutil import _verify_bsgs + >>> A = AlternatingGroup(4) + >>> A.schreier_sims() + >>> _verify_bsgs(A, A.base, A.strong_gens) + True + + See Also + ======== + + sympy.combinatorics.perm_groups.PermutationGroup.schreier_sims + + """ + from sympy.combinatorics.perm_groups import PermutationGroup + strong_gens_distr = _distribute_gens_by_base(base, gens) + current_stabilizer = group + for i in range(len(base)): + candidate = PermutationGroup(strong_gens_distr[i]) + if current_stabilizer.order() != candidate.order(): + return False + current_stabilizer = current_stabilizer.stabilizer(base[i]) + if current_stabilizer.order() != 1: + return False + return True + + +def _verify_centralizer(group, arg, centr=None): + """ + Verify the centralizer of a group/set/element inside another group. + + This is used for testing ``.centralizer()`` from + ``sympy.combinatorics.perm_groups`` + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, + ... AlternatingGroup) + >>> from sympy.combinatorics.perm_groups import PermutationGroup + >>> from sympy.combinatorics.permutations import Permutation + >>> from sympy.combinatorics.testutil import _verify_centralizer + >>> S = SymmetricGroup(5) + >>> A = AlternatingGroup(5) + >>> centr = PermutationGroup([Permutation([0, 1, 2, 3, 4])]) + >>> _verify_centralizer(S, A, centr) + True + + See Also + ======== + + _naive_list_centralizer, + sympy.combinatorics.perm_groups.PermutationGroup.centralizer, + _cmp_perm_lists + + """ + if centr is None: + centr = group.centralizer(arg) + centr_list = list(centr.generate_dimino(af=True)) + centr_list_naive = _naive_list_centralizer(group, arg, af=True) + return _cmp_perm_lists(centr_list, centr_list_naive) + + +def _verify_normal_closure(group, arg, closure=None): + from sympy.combinatorics.perm_groups import PermutationGroup + """ + Verify the normal closure of a subgroup/subset/element in a group. + + This is used to test + sympy.combinatorics.perm_groups.PermutationGroup.normal_closure + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, + ... AlternatingGroup) + >>> from sympy.combinatorics.testutil import _verify_normal_closure + >>> S = SymmetricGroup(3) + >>> A = AlternatingGroup(3) + >>> _verify_normal_closure(S, A, closure=A) + True + + See Also + ======== + + sympy.combinatorics.perm_groups.PermutationGroup.normal_closure + + """ + if closure is None: + closure = group.normal_closure(arg) + conjugates = set() + if hasattr(arg, 'generators'): + subgr_gens = arg.generators + elif hasattr(arg, '__getitem__'): + subgr_gens = arg + elif hasattr(arg, 'array_form'): + subgr_gens = [arg] + for el in group.generate_dimino(): + conjugates.update(gen ^ el for gen in subgr_gens) + naive_closure = PermutationGroup(list(conjugates)) + return closure.is_subgroup(naive_closure) + + +def canonicalize_naive(g, dummies, sym, *v): + """ + Canonicalize tensor formed by tensors of the different types. + + Explanation + =========== + + sym_i symmetry under exchange of two component tensors of type `i` + None no symmetry + 0 commuting + 1 anticommuting + + Parameters + ========== + + g : Permutation representing the tensor. + dummies : List of dummy indices. + msym : Symmetry of the metric. + v : A list of (base_i, gens_i, n_i, sym_i) for tensors of type `i`. + base_i, gens_i BSGS for tensors of this type + n_i number of tensors of type `i` + + Returns + ======= + + Returns 0 if the tensor is zero, else returns the array form of + the permutation representing the canonical form of the tensor. + + Examples + ======== + + >>> from sympy.combinatorics.testutil import canonicalize_naive + >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs + >>> from sympy.combinatorics import Permutation + >>> g = Permutation([1, 3, 2, 0, 4, 5]) + >>> base2, gens2 = get_symmetric_group_sgs(2) + >>> canonicalize_naive(g, [2, 3], 0, (base2, gens2, 2, 0)) + [0, 2, 1, 3, 4, 5] + """ + from sympy.combinatorics.perm_groups import PermutationGroup + from sympy.combinatorics.tensor_can import gens_products, dummy_sgs + from sympy.combinatorics.permutations import _af_rmul + v1 = [] + for i in range(len(v)): + base_i, gens_i, n_i, sym_i = v[i] + v1.append((base_i, gens_i, [[]]*n_i, sym_i)) + size, sbase, sgens = gens_products(*v1) + dgens = dummy_sgs(dummies, sym, size-2) + if isinstance(sym, int): + num_types = 1 + dummies = [dummies] + sym = [sym] + else: + num_types = len(sym) + dgens = [] + for i in range(num_types): + dgens.extend(dummy_sgs(dummies[i], sym[i], size - 2)) + S = PermutationGroup(sgens) + D = PermutationGroup([Permutation(x) for x in dgens]) + dlist = list(D.generate(af=True)) + g = g.array_form + st = set() + for s in S.generate(af=True): + h = _af_rmul(g, s) + for d in dlist: + q = tuple(_af_rmul(d, h)) + st.add(q) + a = list(st) + a.sort() + prev = (0,)*size + for h in a: + if h[:-2] == prev[:-2]: + if h[-1] != prev[-1]: + return 0 + prev = h + return list(a[0]) + + +def graph_certificate(gr): + """ + Return a certificate for the graph + + Parameters + ========== + + gr : adjacency list + + Explanation + =========== + + The graph is assumed to be unoriented and without + external lines. + + Associate to each vertex of the graph a symmetric tensor with + number of indices equal to the degree of the vertex; indices + are contracted when they correspond to the same line of the graph. + The canonical form of the tensor gives a certificate for the graph. + + This is not an efficient algorithm to get the certificate of a graph. + + Examples + ======== + + >>> from sympy.combinatorics.testutil import graph_certificate + >>> gr1 = {0:[1, 2, 3, 5], 1:[0, 2, 4], 2:[0, 1, 3, 4], 3:[0, 2, 4], 4:[1, 2, 3, 5], 5:[0, 4]} + >>> gr2 = {0:[1, 5], 1:[0, 2, 3, 4], 2:[1, 3, 5], 3:[1, 2, 4, 5], 4:[1, 3, 5], 5:[0, 2, 3, 4]} + >>> c1 = graph_certificate(gr1) + >>> c2 = graph_certificate(gr2) + >>> c1 + [0, 2, 4, 6, 1, 8, 10, 12, 3, 14, 16, 18, 5, 9, 15, 7, 11, 17, 13, 19, 20, 21] + >>> c1 == c2 + True + """ + from sympy.combinatorics.permutations import _af_invert + from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize + items = list(gr.items()) + items.sort(key=lambda x: len(x[1]), reverse=True) + pvert = [x[0] for x in items] + pvert = _af_invert(pvert) + + # the indices of the tensor are twice the number of lines of the graph + num_indices = 0 + for v, neigh in items: + num_indices += len(neigh) + # associate to each vertex its indices; for each line + # between two vertices assign the + # even index to the vertex which comes first in items, + # the odd index to the other vertex + vertices = [[] for i in items] + i = 0 + for v, neigh in items: + for v2 in neigh: + if pvert[v] < pvert[v2]: + vertices[pvert[v]].append(i) + vertices[pvert[v2]].append(i+1) + i += 2 + g = [] + for v in vertices: + g.extend(v) + assert len(g) == num_indices + g += [num_indices, num_indices + 1] + size = num_indices + 2 + assert sorted(g) == list(range(size)) + g = Permutation(g) + vlen = [0]*(len(vertices[0])+1) + for neigh in vertices: + vlen[len(neigh)] += 1 + v = [] + for i in range(len(vlen)): + n = vlen[i] + if n: + base, gens = get_symmetric_group_sgs(i) + v.append((base, gens, n, 0)) + v.reverse() + dummies = list(range(num_indices)) + can = canonicalize(g, dummies, 0, *v) + return can diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/util.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/util.py new file mode 100644 index 0000000000000000000000000000000000000000..fc73b02f94f4aae6f1b98bb3f0c837fd5a1d1e6d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/combinatorics/util.py @@ -0,0 +1,532 @@ +from sympy.combinatorics.permutations import Permutation, _af_invert, _af_rmul +from sympy.ntheory import isprime + +rmul = Permutation.rmul +_af_new = Permutation._af_new + +############################################ +# +# Utilities for computational group theory +# +############################################ + + +def _base_ordering(base, degree): + r""" + Order `\{0, 1, \dots, n-1\}` so that base points come first and in order. + + Parameters + ========== + + base : the base + degree : the degree of the associated permutation group + + Returns + ======= + + A list ``base_ordering`` such that ``base_ordering[point]`` is the + number of ``point`` in the ordering. + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricGroup + >>> from sympy.combinatorics.util import _base_ordering + >>> S = SymmetricGroup(4) + >>> S.schreier_sims() + >>> _base_ordering(S.base, S.degree) + [0, 1, 2, 3] + + Notes + ===== + + This is used in backtrack searches, when we define a relation `\ll` on + the underlying set for a permutation group of degree `n`, + `\{0, 1, \dots, n-1\}`, so that if `(b_1, b_2, \dots, b_k)` is a base we + have `b_i \ll b_j` whenever `i>> from sympy.combinatorics.util import _check_cycles_alt_sym + >>> from sympy.combinatorics import Permutation + >>> a = Permutation([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12]]) + >>> _check_cycles_alt_sym(a) + False + >>> b = Permutation([[0, 1, 2, 3, 4, 5, 6], [7, 8, 9, 10]]) + >>> _check_cycles_alt_sym(b) + True + + See Also + ======== + + sympy.combinatorics.perm_groups.PermutationGroup.is_alt_sym + + """ + n = perm.size + af = perm.array_form + current_len = 0 + total_len = 0 + used = set() + for i in range(n//2): + if i not in used and i < n//2 - total_len: + current_len = 1 + used.add(i) + j = i + while af[j] != i: + current_len += 1 + j = af[j] + used.add(j) + total_len += current_len + if current_len > n//2 and current_len < n - 2 and isprime(current_len): + return True + return False + + +def _distribute_gens_by_base(base, gens): + r""" + Distribute the group elements ``gens`` by membership in basic stabilizers. + + Explanation + =========== + + Notice that for a base `(b_1, b_2, \dots, b_k)`, the basic stabilizers + are defined as `G^{(i)} = G_{b_1, \dots, b_{i-1}}` for + `i \in\{1, 2, \dots, k\}`. + + Parameters + ========== + + base : a sequence of points in `\{0, 1, \dots, n-1\}` + gens : a list of elements of a permutation group of degree `n`. + + Returns + ======= + list + List of length `k`, where `k` is the length of *base*. The `i`-th entry + contains those elements in *gens* which fix the first `i` elements of + *base* (so that the `0`-th entry is equal to *gens* itself). If no + element fixes the first `i` elements of *base*, the `i`-th element is + set to a list containing the identity element. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> from sympy.combinatorics.util import _distribute_gens_by_base + >>> D = DihedralGroup(3) + >>> D.schreier_sims() + >>> D.strong_gens + [(0 1 2), (0 2), (1 2)] + >>> D.base + [0, 1] + >>> _distribute_gens_by_base(D.base, D.strong_gens) + [[(0 1 2), (0 2), (1 2)], + [(1 2)]] + + See Also + ======== + + _strong_gens_from_distr, _orbits_transversals_from_bsgs, + _handle_precomputed_bsgs + + """ + base_len = len(base) + degree = gens[0].size + stabs = [[] for _ in range(base_len)] + max_stab_index = 0 + for gen in gens: + j = 0 + while j < base_len - 1 and gen._array_form[base[j]] == base[j]: + j += 1 + if j > max_stab_index: + max_stab_index = j + for k in range(j + 1): + stabs[k].append(gen) + for i in range(max_stab_index + 1, base_len): + stabs[i].append(_af_new(list(range(degree)))) + return stabs + + +def _handle_precomputed_bsgs(base, strong_gens, transversals=None, + basic_orbits=None, strong_gens_distr=None): + """ + Calculate BSGS-related structures from those present. + + Explanation + =========== + + The base and strong generating set must be provided; if any of the + transversals, basic orbits or distributed strong generators are not + provided, they will be calculated from the base and strong generating set. + + Parameters + ========== + + base : the base + strong_gens : the strong generators + transversals : basic transversals + basic_orbits : basic orbits + strong_gens_distr : strong generators distributed by membership in basic stabilizers + + Returns + ======= + + (transversals, basic_orbits, strong_gens_distr) + where *transversals* are the basic transversals, *basic_orbits* are the + basic orbits, and *strong_gens_distr* are the strong generators distributed + by membership in basic stabilizers. + + Examples + ======== + + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> from sympy.combinatorics.util import _handle_precomputed_bsgs + >>> D = DihedralGroup(3) + >>> D.schreier_sims() + >>> _handle_precomputed_bsgs(D.base, D.strong_gens, + ... basic_orbits=D.basic_orbits) + ([{0: (2), 1: (0 1 2), 2: (0 2)}, {1: (2), 2: (1 2)}], [[0, 1, 2], [1, 2]], [[(0 1 2), (0 2), (1 2)], [(1 2)]]) + + See Also + ======== + + _orbits_transversals_from_bsgs, _distribute_gens_by_base + + """ + if strong_gens_distr is None: + strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + if transversals is None: + if basic_orbits is None: + basic_orbits, transversals = \ + _orbits_transversals_from_bsgs(base, strong_gens_distr) + else: + transversals = \ + _orbits_transversals_from_bsgs(base, strong_gens_distr, + transversals_only=True) + else: + if basic_orbits is None: + base_len = len(base) + basic_orbits = [None]*base_len + for i in range(base_len): + basic_orbits[i] = list(transversals[i].keys()) + return transversals, basic_orbits, strong_gens_distr + + +def _orbits_transversals_from_bsgs(base, strong_gens_distr, + transversals_only=False, slp=False): + """ + Compute basic orbits and transversals from a base and strong generating set. + + Explanation + =========== + + The generators are provided as distributed across the basic stabilizers. + If the optional argument ``transversals_only`` is set to True, only the + transversals are returned. + + Parameters + ========== + + base : The base. + strong_gens_distr : Strong generators distributed by membership in basic stabilizers. + transversals_only : bool, default: False + A flag switching between returning only the + transversals and both orbits and transversals. + slp : bool, default: False + If ``True``, return a list of dictionaries containing the + generator presentations of the elements of the transversals, + i.e. the list of indices of generators from ``strong_gens_distr[i]`` + such that their product is the relevant transversal element. + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricGroup + >>> from sympy.combinatorics.util import _distribute_gens_by_base + >>> S = SymmetricGroup(3) + >>> S.schreier_sims() + >>> strong_gens_distr = _distribute_gens_by_base(S.base, S.strong_gens) + >>> (S.base, strong_gens_distr) + ([0, 1], [[(0 1 2), (2)(0 1), (1 2)], [(1 2)]]) + + See Also + ======== + + _distribute_gens_by_base, _handle_precomputed_bsgs + + """ + from sympy.combinatorics.perm_groups import _orbit_transversal + base_len = len(base) + degree = strong_gens_distr[0][0].size + transversals = [None]*base_len + slps = [None]*base_len + if transversals_only is False: + basic_orbits = [None]*base_len + for i in range(base_len): + transversals[i], slps[i] = _orbit_transversal(degree, strong_gens_distr[i], + base[i], pairs=True, slp=True) + transversals[i] = dict(transversals[i]) + if transversals_only is False: + basic_orbits[i] = list(transversals[i].keys()) + if transversals_only: + return transversals + else: + if not slp: + return basic_orbits, transversals + return basic_orbits, transversals, slps + + +def _remove_gens(base, strong_gens, basic_orbits=None, strong_gens_distr=None): + """ + Remove redundant generators from a strong generating set. + + Parameters + ========== + + base : a base + strong_gens : a strong generating set relative to *base* + basic_orbits : basic orbits + strong_gens_distr : strong generators distributed by membership in basic stabilizers + + Returns + ======= + + A strong generating set with respect to ``base`` which is a subset of + ``strong_gens``. + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricGroup + >>> from sympy.combinatorics.util import _remove_gens + >>> from sympy.combinatorics.testutil import _verify_bsgs + >>> S = SymmetricGroup(15) + >>> base, strong_gens = S.schreier_sims_incremental() + >>> new_gens = _remove_gens(base, strong_gens) + >>> len(new_gens) + 14 + >>> _verify_bsgs(S, base, new_gens) + True + + Notes + ===== + + This procedure is outlined in [1],p.95. + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E. + "Handbook of computational group theory" + + """ + from sympy.combinatorics.perm_groups import _orbit + base_len = len(base) + degree = strong_gens[0].size + if strong_gens_distr is None: + strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + if basic_orbits is None: + basic_orbits = [] + for i in range(base_len): + basic_orbit = _orbit(degree, strong_gens_distr[i], base[i]) + basic_orbits.append(basic_orbit) + strong_gens_distr.append([]) + res = strong_gens[:] + for i in range(base_len - 1, -1, -1): + gens_copy = strong_gens_distr[i][:] + for gen in strong_gens_distr[i]: + if gen not in strong_gens_distr[i + 1]: + temp_gens = gens_copy[:] + temp_gens.remove(gen) + if temp_gens == []: + continue + temp_orbit = _orbit(degree, temp_gens, base[i]) + if temp_orbit == basic_orbits[i]: + gens_copy.remove(gen) + res.remove(gen) + return res + + +def _strip(g, base, orbits, transversals): + """ + Attempt to decompose a permutation using a (possibly partial) BSGS + structure. + + Explanation + =========== + + This is done by treating the sequence ``base`` as an actual base, and + the orbits ``orbits`` and transversals ``transversals`` as basic orbits and + transversals relative to it. + + This process is called "sifting". A sift is unsuccessful when a certain + orbit element is not found or when after the sift the decomposition + does not end with the identity element. + + The argument ``transversals`` is a list of dictionaries that provides + transversal elements for the orbits ``orbits``. + + Parameters + ========== + + g : permutation to be decomposed + base : sequence of points + orbits : list + A list in which the ``i``-th entry is an orbit of ``base[i]`` + under some subgroup of the pointwise stabilizer of ` + `base[0], base[1], ..., base[i - 1]``. The groups themselves are implicit + in this function since the only information we need is encoded in the orbits + and transversals + transversals : list + A list of orbit transversals associated with the orbits *orbits*. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation, SymmetricGroup + >>> from sympy.combinatorics.util import _strip + >>> S = SymmetricGroup(5) + >>> S.schreier_sims() + >>> g = Permutation([0, 2, 3, 1, 4]) + >>> _strip(g, S.base, S.basic_orbits, S.basic_transversals) + ((4), 5) + + Notes + ===== + + The algorithm is described in [1],pp.89-90. The reason for returning + both the current state of the element being decomposed and the level + at which the sifting ends is that they provide important information for + the randomized version of the Schreier-Sims algorithm. + + References + ========== + + .. [1] Holt, D., Eick, B., O'Brien, E."Handbook of computational group theory" + + See Also + ======== + + sympy.combinatorics.perm_groups.PermutationGroup.schreier_sims + sympy.combinatorics.perm_groups.PermutationGroup.schreier_sims_random + + """ + h = g._array_form + base_len = len(base) + for i in range(base_len): + beta = h[base[i]] + if beta == base[i]: + continue + if beta not in orbits[i]: + return _af_new(h), i + 1 + u = transversals[i][beta]._array_form + h = _af_rmul(_af_invert(u), h) + return _af_new(h), base_len + 1 + + +def _strip_af(h, base, orbits, transversals, j, slp=[], slps={}): + """ + optimized _strip, with h, transversals and result in array form + if the stripped elements is the identity, it returns False, base_len + 1 + + j h[base[i]] == base[i] for i <= j + + """ + base_len = len(base) + for i in range(j+1, base_len): + beta = h[base[i]] + if beta == base[i]: + continue + if beta not in orbits[i]: + if not slp: + return h, i + 1 + return h, i + 1, slp + u = transversals[i][beta] + if h == u: + if not slp: + return False, base_len + 1 + return False, base_len + 1, slp + h = _af_rmul(_af_invert(u), h) + if slp: + u_slp = slps[i][beta][:] + u_slp.reverse() + u_slp = [(i, (g,)) for g in u_slp] + slp = u_slp + slp + if not slp: + return h, base_len + 1 + return h, base_len + 1, slp + + +def _strong_gens_from_distr(strong_gens_distr): + """ + Retrieve strong generating set from generators of basic stabilizers. + + This is just the union of the generators of the first and second basic + stabilizers. + + Parameters + ========== + + strong_gens_distr : strong generators distributed by membership in basic stabilizers + + Examples + ======== + + >>> from sympy.combinatorics import SymmetricGroup + >>> from sympy.combinatorics.util import (_strong_gens_from_distr, + ... _distribute_gens_by_base) + >>> S = SymmetricGroup(3) + >>> S.schreier_sims() + >>> S.strong_gens + [(0 1 2), (2)(0 1), (1 2)] + >>> strong_gens_distr = _distribute_gens_by_base(S.base, S.strong_gens) + >>> _strong_gens_from_distr(strong_gens_distr) + [(0 1 2), (2)(0 1), (1 2)] + + See Also + ======== + + _distribute_gens_by_base + + """ + if len(strong_gens_distr) == 1: + return strong_gens_distr[0][:] + else: + result = strong_gens_distr[0] + for gen in strong_gens_distr[1]: + if gen not in result: + result.append(gen) + return result diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7048bd548cca04780479539339dd8cc49a21990f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/__init__.py @@ -0,0 +1,8 @@ +from .products import product, Product +from .summations import summation, Sum + +__all__ = [ + 'product', 'Product', + + 'summation', 'Sum', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/delta.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/delta.py new file mode 100644 index 0000000000000000000000000000000000000000..0471d2b2891a66a1b97b7a3a37bbd31d7b173a81 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/delta.py @@ -0,0 +1,327 @@ +""" +This module implements sums and products containing the Kronecker Delta function. + +References +========== + +.. [1] https://mathworld.wolfram.com/KroneckerDelta.html + +""" +from .products import product +from .summations import Sum, summation +from sympy.core import Add, Mul, S, Dummy +from sympy.core.cache import cacheit +from sympy.core.sorting import default_sort_key +from sympy.functions import KroneckerDelta, Piecewise, piecewise_fold +from sympy.polys.polytools import factor +from sympy.sets.sets import Interval +from sympy.solvers.solvers import solve + + +@cacheit +def _expand_delta(expr, index): + """ + Expand the first Add containing a simple KroneckerDelta. + """ + if not expr.is_Mul: + return expr + delta = None + func = Add + terms = [S.One] + for h in expr.args: + if delta is None and h.is_Add and _has_simple_delta(h, index): + delta = True + func = h.func + terms = [terms[0]*t for t in h.args] + else: + terms = [t*h for t in terms] + return func(*terms) + + +@cacheit +def _extract_delta(expr, index): + """ + Extract a simple KroneckerDelta from the expression. + + Explanation + =========== + + Returns the tuple ``(delta, newexpr)`` where: + + - ``delta`` is a simple KroneckerDelta expression if one was found, + or ``None`` if no simple KroneckerDelta expression was found. + + - ``newexpr`` is a Mul containing the remaining terms; ``expr`` is + returned unchanged if no simple KroneckerDelta expression was found. + + Examples + ======== + + >>> from sympy import KroneckerDelta + >>> from sympy.concrete.delta import _extract_delta + >>> from sympy.abc import x, y, i, j, k + >>> _extract_delta(4*x*y*KroneckerDelta(i, j), i) + (KroneckerDelta(i, j), 4*x*y) + >>> _extract_delta(4*x*y*KroneckerDelta(i, j), k) + (None, 4*x*y*KroneckerDelta(i, j)) + + See Also + ======== + + sympy.functions.special.tensor_functions.KroneckerDelta + deltaproduct + deltasummation + """ + if not _has_simple_delta(expr, index): + return (None, expr) + if isinstance(expr, KroneckerDelta): + return (expr, S.One) + if not expr.is_Mul: + raise ValueError("Incorrect expr") + delta = None + terms = [] + + for arg in expr.args: + if delta is None and _is_simple_delta(arg, index): + delta = arg + else: + terms.append(arg) + return (delta, expr.func(*terms)) + + +@cacheit +def _has_simple_delta(expr, index): + """ + Returns True if ``expr`` is an expression that contains a KroneckerDelta + that is simple in the index ``index``, meaning that this KroneckerDelta + is nonzero for a single value of the index ``index``. + """ + if expr.has(KroneckerDelta): + if _is_simple_delta(expr, index): + return True + if expr.is_Add or expr.is_Mul: + return any(_has_simple_delta(arg, index) for arg in expr.args) + return False + + +@cacheit +def _is_simple_delta(delta, index): + """ + Returns True if ``delta`` is a KroneckerDelta and is nonzero for a single + value of the index ``index``. + """ + if isinstance(delta, KroneckerDelta) and delta.has(index): + p = (delta.args[0] - delta.args[1]).as_poly(index) + if p: + return p.degree() == 1 + return False + + +@cacheit +def _remove_multiple_delta(expr): + """ + Evaluate products of KroneckerDelta's. + """ + if expr.is_Add: + return expr.func(*list(map(_remove_multiple_delta, expr.args))) + if not expr.is_Mul: + return expr + eqs = [] + newargs = [] + for arg in expr.args: + if isinstance(arg, KroneckerDelta): + eqs.append(arg.args[0] - arg.args[1]) + else: + newargs.append(arg) + if not eqs: + return expr + solns = solve(eqs, dict=True) + if len(solns) == 0: + return S.Zero + elif len(solns) == 1: + newargs += [KroneckerDelta(k, v) for k, v in solns[0].items()] + expr2 = expr.func(*newargs) + if expr != expr2: + return _remove_multiple_delta(expr2) + return expr + + +@cacheit +def _simplify_delta(expr): + """ + Rewrite a KroneckerDelta's indices in its simplest form. + """ + if isinstance(expr, KroneckerDelta): + try: + slns = solve(expr.args[0] - expr.args[1], dict=True) + if slns and len(slns) == 1: + return Mul(*[KroneckerDelta(*(key, value)) + for key, value in slns[0].items()]) + except NotImplementedError: + pass + return expr + + +@cacheit +def deltaproduct(f, limit): + """ + Handle products containing a KroneckerDelta. + + See Also + ======== + + deltasummation + sympy.functions.special.tensor_functions.KroneckerDelta + sympy.concrete.products.product + """ + if ((limit[2] - limit[1]) < 0) == True: + return S.One + + if not f.has(KroneckerDelta): + return product(f, limit) + + if f.is_Add: + # Identify the term in the Add that has a simple KroneckerDelta + delta = None + terms = [] + for arg in sorted(f.args, key=default_sort_key): + if delta is None and _has_simple_delta(arg, limit[0]): + delta = arg + else: + terms.append(arg) + newexpr = f.func(*terms) + k = Dummy("kprime", integer=True) + if isinstance(limit[1], int) and isinstance(limit[2], int): + result = deltaproduct(newexpr, limit) + sum(deltaproduct(newexpr, (limit[0], limit[1], ik - 1)) * + delta.subs(limit[0], ik) * + deltaproduct(newexpr, (limit[0], ik + 1, limit[2])) for ik in range(int(limit[1]), int(limit[2] + 1)) + ) + else: + result = deltaproduct(newexpr, limit) + deltasummation( + deltaproduct(newexpr, (limit[0], limit[1], k - 1)) * + delta.subs(limit[0], k) * + deltaproduct(newexpr, (limit[0], k + 1, limit[2])), + (k, limit[1], limit[2]), + no_piecewise=_has_simple_delta(newexpr, limit[0]) + ) + return _remove_multiple_delta(result) + + delta, _ = _extract_delta(f, limit[0]) + + if not delta: + g = _expand_delta(f, limit[0]) + if f != g: + try: + return factor(deltaproduct(g, limit)) + except AssertionError: + return deltaproduct(g, limit) + return product(f, limit) + + return _remove_multiple_delta(f.subs(limit[0], limit[1])*KroneckerDelta(limit[2], limit[1])) + \ + S.One*_simplify_delta(KroneckerDelta(limit[2], limit[1] - 1)) + + +@cacheit +def deltasummation(f, limit, no_piecewise=False): + """ + Handle summations containing a KroneckerDelta. + + Explanation + =========== + + The idea for summation is the following: + + - If we are dealing with a KroneckerDelta expression, i.e. KroneckerDelta(g(x), j), + we try to simplify it. + + If we could simplify it, then we sum the resulting expression. + We already know we can sum a simplified expression, because only + simple KroneckerDelta expressions are involved. + + If we could not simplify it, there are two cases: + + 1) The expression is a simple expression: we return the summation, + taking care if we are dealing with a Derivative or with a proper + KroneckerDelta. + + 2) The expression is not simple (i.e. KroneckerDelta(cos(x))): we can do + nothing at all. + + - If the expr is a multiplication expr having a KroneckerDelta term: + + First we expand it. + + If the expansion did work, then we try to sum the expansion. + + If not, we try to extract a simple KroneckerDelta term, then we have two + cases: + + 1) We have a simple KroneckerDelta term, so we return the summation. + + 2) We did not have a simple term, but we do have an expression with + simplified KroneckerDelta terms, so we sum this expression. + + Examples + ======== + + >>> from sympy import oo, symbols + >>> from sympy.abc import k + >>> i, j = symbols('i, j', integer=True, finite=True) + >>> from sympy.concrete.delta import deltasummation + >>> from sympy import KroneckerDelta + >>> deltasummation(KroneckerDelta(i, k), (k, -oo, oo)) + 1 + >>> deltasummation(KroneckerDelta(i, k), (k, 0, oo)) + Piecewise((1, i >= 0), (0, True)) + >>> deltasummation(KroneckerDelta(i, k), (k, 1, 3)) + Piecewise((1, (i >= 1) & (i <= 3)), (0, True)) + >>> deltasummation(k*KroneckerDelta(i, j)*KroneckerDelta(j, k), (k, -oo, oo)) + j*KroneckerDelta(i, j) + >>> deltasummation(j*KroneckerDelta(i, j), (j, -oo, oo)) + i + >>> deltasummation(i*KroneckerDelta(i, j), (i, -oo, oo)) + j + + See Also + ======== + + deltaproduct + sympy.functions.special.tensor_functions.KroneckerDelta + sympy.concrete.sums.summation + """ + if ((limit[2] - limit[1]) < 0) == True: + return S.Zero + + if not f.has(KroneckerDelta): + return summation(f, limit) + + x = limit[0] + + g = _expand_delta(f, x) + if g.is_Add: + return piecewise_fold( + g.func(*[deltasummation(h, limit, no_piecewise) for h in g.args])) + + # try to extract a simple KroneckerDelta term + delta, expr = _extract_delta(g, x) + + if (delta is not None) and (delta.delta_range is not None): + dinf, dsup = delta.delta_range + if (limit[1] - dinf <= 0) == True and (limit[2] - dsup >= 0) == True: + no_piecewise = True + + if not delta: + return summation(f, limit) + + solns = solve(delta.args[0] - delta.args[1], x) + if len(solns) == 0: + return S.Zero + elif len(solns) != 1: + return Sum(f, limit) + value = solns[0] + if no_piecewise: + return expr.subs(x, value) + return Piecewise( + (expr.subs(x, value), Interval(*limit[1:3]).as_relational(value)), + (S.Zero, True) + ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/expr_with_intlimits.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/expr_with_intlimits.py new file mode 100644 index 0000000000000000000000000000000000000000..8e109913cdb2f3018096972b14651b990f4b985e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/expr_with_intlimits.py @@ -0,0 +1,354 @@ +from sympy.concrete.expr_with_limits import ExprWithLimits +from sympy.core.singleton import S +from sympy.core.relational import Eq + +class ReorderError(NotImplementedError): + """ + Exception raised when trying to reorder dependent limits. + """ + def __init__(self, expr, msg): + super().__init__( + "%s could not be reordered: %s." % (expr, msg)) + +class ExprWithIntLimits(ExprWithLimits): + """ + Superclass for Product and Sum. + + See Also + ======== + + sympy.concrete.expr_with_limits.ExprWithLimits + sympy.concrete.products.Product + sympy.concrete.summations.Sum + """ + __slots__ = () + + def change_index(self, var, trafo, newvar=None): + r""" + Change index of a Sum or Product. + + Perform a linear transformation `x \mapsto a x + b` on the index variable + `x`. For `a` the only values allowed are `\pm 1`. A new variable to be used + after the change of index can also be specified. + + Explanation + =========== + + ``change_index(expr, var, trafo, newvar=None)`` where ``var`` specifies the + index variable `x` to transform. The transformation ``trafo`` must be linear + and given in terms of ``var``. If the optional argument ``newvar`` is + provided then ``var`` gets replaced by ``newvar`` in the final expression. + + Examples + ======== + + >>> from sympy import Sum, Product, simplify + >>> from sympy.abc import x, y, a, b, c, d, u, v, i, j, k, l + + >>> S = Sum(x, (x, a, b)) + >>> S.doit() + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> Sn = S.change_index(x, x + 1, y) + >>> Sn + Sum(y - 1, (y, a + 1, b + 1)) + >>> Sn.doit() + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> Sn = S.change_index(x, -x, y) + >>> Sn + Sum(-y, (y, -b, -a)) + >>> Sn.doit() + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> Sn = S.change_index(x, x+u) + >>> Sn + Sum(-u + x, (x, a + u, b + u)) + >>> Sn.doit() + -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u + >>> simplify(Sn.doit()) + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> Sn = S.change_index(x, -x - u, y) + >>> Sn + Sum(-u - y, (y, -b - u, -a - u)) + >>> Sn.doit() + -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u + >>> simplify(Sn.doit()) + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> P = Product(i*j**2, (i, a, b), (j, c, d)) + >>> P + Product(i*j**2, (i, a, b), (j, c, d)) + >>> P2 = P.change_index(i, i+3, k) + >>> P2 + Product(j**2*(k - 3), (k, a + 3, b + 3), (j, c, d)) + >>> P3 = P2.change_index(j, -j, l) + >>> P3 + Product(l**2*(k - 3), (k, a + 3, b + 3), (l, -d, -c)) + + When dealing with symbols only, we can make a + general linear transformation: + + >>> Sn = S.change_index(x, u*x+v, y) + >>> Sn + Sum((-v + y)/u, (y, b*u + v, a*u + v)) + >>> Sn.doit() + -v*(a*u - b*u + 1)/u + (a**2*u**2/2 + a*u*v + a*u/2 - b**2*u**2/2 - b*u*v + b*u/2 + v)/u + >>> simplify(Sn.doit()) + a**2*u/2 + a/2 - b**2*u/2 + b/2 + + However, the last result can be inconsistent with usual + summation where the index increment is always 1. This is + obvious as we get back the original value only for ``u`` + equal +1 or -1. + + See Also + ======== + + sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index, + reorder_limit, + sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder, + sympy.concrete.summations.Sum.reverse_order, + sympy.concrete.products.Product.reverse_order + """ + if newvar is None: + newvar = var + + limits = [] + for limit in self.limits: + if limit[0] == var: + p = trafo.as_poly(var) + if p.degree() != 1: + raise ValueError("Index transformation is not linear") + alpha = p.coeff_monomial(var) + beta = p.coeff_monomial(S.One) + if alpha.is_number: + if alpha == S.One: + limits.append((newvar, alpha*limit[1] + beta, alpha*limit[2] + beta)) + elif alpha == S.NegativeOne: + limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta)) + else: + raise ValueError("Linear transformation results in non-linear summation stepsize") + else: + # Note that the case of alpha being symbolic can give issues if alpha < 0. + limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta)) + else: + limits.append(limit) + + function = self.function.subs(var, (var - beta)/alpha) + function = function.subs(var, newvar) + + return self.func(function, *limits) + + + def index(expr, x): + """ + Return the index of a dummy variable in the list of limits. + + Explanation + =========== + + ``index(expr, x)`` returns the index of the dummy variable ``x`` in the + limits of ``expr``. Note that we start counting with 0 at the inner-most + limits tuple. + + Examples + ======== + + >>> from sympy.abc import x, y, a, b, c, d + >>> from sympy import Sum, Product + >>> Sum(x*y, (x, a, b), (y, c, d)).index(x) + 0 + >>> Sum(x*y, (x, a, b), (y, c, d)).index(y) + 1 + >>> Product(x*y, (x, a, b), (y, c, d)).index(x) + 0 + >>> Product(x*y, (x, a, b), (y, c, d)).index(y) + 1 + + See Also + ======== + + reorder_limit, reorder, sympy.concrete.summations.Sum.reverse_order, + sympy.concrete.products.Product.reverse_order + """ + variables = [limit[0] for limit in expr.limits] + + if variables.count(x) != 1: + raise ValueError(expr, "Number of instances of variable not equal to one") + else: + return variables.index(x) + + def reorder(expr, *arg): + """ + Reorder limits in a expression containing a Sum or a Product. + + Explanation + =========== + + ``expr.reorder(*arg)`` reorders the limits in the expression ``expr`` + according to the list of tuples given by ``arg``. These tuples can + contain numerical indices or index variable names or involve both. + + Examples + ======== + + >>> from sympy import Sum, Product + >>> from sympy.abc import x, y, z, a, b, c, d, e, f + + >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((x, y)) + Sum(x*y, (y, c, d), (x, a, b)) + + >>> Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder((x, y), (x, z), (y, z)) + Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b)) + + >>> P = Product(x*y*z, (x, a, b), (y, c, d), (z, e, f)) + >>> P.reorder((x, y), (x, z), (y, z)) + Product(x*y*z, (z, e, f), (y, c, d), (x, a, b)) + + We can also select the index variables by counting them, starting + with the inner-most one: + + >>> Sum(x**2, (x, a, b), (x, c, d)).reorder((0, 1)) + Sum(x**2, (x, c, d), (x, a, b)) + + And of course we can mix both schemes: + + >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((y, x)) + Sum(x*y, (y, c, d), (x, a, b)) + >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((y, 0)) + Sum(x*y, (y, c, d), (x, a, b)) + + See Also + ======== + + reorder_limit, index, sympy.concrete.summations.Sum.reverse_order, + sympy.concrete.products.Product.reverse_order + """ + new_expr = expr + + for r in arg: + if len(r) != 2: + raise ValueError(r, "Invalid number of arguments") + + index1 = r[0] + index2 = r[1] + + if not isinstance(r[0], int): + index1 = expr.index(r[0]) + if not isinstance(r[1], int): + index2 = expr.index(r[1]) + + new_expr = new_expr.reorder_limit(index1, index2) + + return new_expr + + + def reorder_limit(expr, x, y): + """ + Interchange two limit tuples of a Sum or Product expression. + + Explanation + =========== + + ``expr.reorder_limit(x, y)`` interchanges two limit tuples. The + arguments ``x`` and ``y`` are integers corresponding to the index + variables of the two limits which are to be interchanged. The + expression ``expr`` has to be either a Sum or a Product. + + Examples + ======== + + >>> from sympy.abc import x, y, z, a, b, c, d, e, f + >>> from sympy import Sum, Product + + >>> Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder_limit(0, 2) + Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b)) + >>> Sum(x**2, (x, a, b), (x, c, d)).reorder_limit(1, 0) + Sum(x**2, (x, c, d), (x, a, b)) + + >>> Product(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder_limit(0, 2) + Product(x*y*z, (z, e, f), (y, c, d), (x, a, b)) + + See Also + ======== + + index, reorder, sympy.concrete.summations.Sum.reverse_order, + sympy.concrete.products.Product.reverse_order + """ + var = {limit[0] for limit in expr.limits} + limit_x = expr.limits[x] + limit_y = expr.limits[y] + + if (len(set(limit_x[1].free_symbols).intersection(var)) == 0 and + len(set(limit_x[2].free_symbols).intersection(var)) == 0 and + len(set(limit_y[1].free_symbols).intersection(var)) == 0 and + len(set(limit_y[2].free_symbols).intersection(var)) == 0): + + limits = [] + for i, limit in enumerate(expr.limits): + if i == x: + limits.append(limit_y) + elif i == y: + limits.append(limit_x) + else: + limits.append(limit) + + return type(expr)(expr.function, *limits) + else: + raise ReorderError(expr, "could not interchange the two limits specified") + + @property + def has_empty_sequence(self): + """ + Returns True if the Sum or Product is computed for an empty sequence. + + Examples + ======== + + >>> from sympy import Sum, Product, Symbol + >>> m = Symbol('m') + >>> Sum(m, (m, 1, 0)).has_empty_sequence + True + + >>> Sum(m, (m, 1, 1)).has_empty_sequence + False + + >>> M = Symbol('M', integer=True, positive=True) + >>> Product(m, (m, 1, M)).has_empty_sequence + False + + >>> Product(m, (m, 2, M)).has_empty_sequence + + >>> Product(m, (m, M + 1, M)).has_empty_sequence + True + + >>> N = Symbol('N', integer=True, positive=True) + >>> Sum(m, (m, N, M)).has_empty_sequence + + >>> N = Symbol('N', integer=True, negative=True) + >>> Sum(m, (m, N, M)).has_empty_sequence + False + + See Also + ======== + + has_reversed_limits + has_finite_limits + + """ + ret_None = False + for lim in self.limits: + dif = lim[1] - lim[2] + eq = Eq(dif, 1) + if eq == True: + return True + elif eq == False: + continue + else: + ret_None = True + + if ret_None: + return None + return False diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/expr_with_limits.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/expr_with_limits.py new file mode 100644 index 0000000000000000000000000000000000000000..034e6ab0a7663525632abe0224fbac973c505c08 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/expr_with_limits.py @@ -0,0 +1,603 @@ +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import AppliedUndef, UndefinedFunction +from sympy.core.mul import Mul +from sympy.core.relational import Equality, Relational +from sympy.core.singleton import S +from sympy.core.symbol import Symbol, Dummy +from sympy.core.sympify import sympify +from sympy.functions.elementary.piecewise import (piecewise_fold, + Piecewise) +from sympy.logic.boolalg import BooleanFunction +from sympy.matrices.matrixbase import MatrixBase +from sympy.sets.sets import Interval, Set +from sympy.sets.fancysets import Range +from sympy.tensor.indexed import Idx +from sympy.utilities import flatten +from sympy.utilities.iterables import sift, is_sequence +from sympy.utilities.exceptions import sympy_deprecation_warning + + +def _common_new(cls, function, *symbols, discrete, **assumptions): + """Return either a special return value or the tuple, + (function, limits, orientation). This code is common to + both ExprWithLimits and AddWithLimits.""" + function = sympify(function) + + if isinstance(function, Equality): + # This transforms e.g. Integral(Eq(x, y)) to Eq(Integral(x), Integral(y)) + # but that is only valid for definite integrals. + limits, orientation = _process_limits(*symbols, discrete=discrete) + if not (limits and all(len(limit) == 3 for limit in limits)): + sympy_deprecation_warning( + """ + Creating a indefinite integral with an Eq() argument is + deprecated. + + This is because indefinite integrals do not preserve equality + due to the arbitrary constants. If you want an equality of + indefinite integrals, use Eq(Integral(a, x), Integral(b, x)) + explicitly. + """, + deprecated_since_version="1.6", + active_deprecations_target="deprecated-indefinite-integral-eq", + stacklevel=5, + ) + + lhs = function.lhs + rhs = function.rhs + return Equality(cls(lhs, *symbols, **assumptions), \ + cls(rhs, *symbols, **assumptions)) + + if function is S.NaN: + return S.NaN + + if symbols: + limits, orientation = _process_limits(*symbols, discrete=discrete) + for i, li in enumerate(limits): + if len(li) == 4: + function = function.subs(li[0], li[-1]) + limits[i] = Tuple(*li[:-1]) + else: + # symbol not provided -- we can still try to compute a general form + free = function.free_symbols + if len(free) != 1: + raise ValueError( + "specify dummy variables for %s" % function) + limits, orientation = [Tuple(s) for s in free], 1 + + # denest any nested calls + while cls == type(function): + limits = list(function.limits) + limits + function = function.function + + # Any embedded piecewise functions need to be brought out to the + # top level. We only fold Piecewise that contain the integration + # variable. + reps = {} + symbols_of_integration = {i[0] for i in limits} + for p in function.atoms(Piecewise): + if not p.has(*symbols_of_integration): + reps[p] = Dummy() + # mask off those that don't + function = function.xreplace(reps) + # do the fold + function = piecewise_fold(function) + # remove the masking + function = function.xreplace({v: k for k, v in reps.items()}) + + return function, limits, orientation + + +def _process_limits(*symbols, discrete=None): + """Process the list of symbols and convert them to canonical limits, + storing them as Tuple(symbol, lower, upper). The orientation of + the function is also returned when the upper limit is missing + so (x, 1, None) becomes (x, None, 1) and the orientation is changed. + In the case that a limit is specified as (symbol, Range), a list of + length 4 may be returned if a change of variables is needed; the + expression that should replace the symbol in the expression is + the fourth element in the list. + """ + limits = [] + orientation = 1 + if discrete is None: + err_msg = 'discrete must be True or False' + elif discrete: + err_msg = 'use Range, not Interval or Relational' + else: + err_msg = 'use Interval or Relational, not Range' + for V in symbols: + if isinstance(V, (Relational, BooleanFunction)): + if discrete: + raise TypeError(err_msg) + variable = V.atoms(Symbol).pop() + V = (variable, V.as_set()) + elif isinstance(V, Symbol) or getattr(V, '_diff_wrt', False): + if isinstance(V, Idx): + if V.lower is None or V.upper is None: + limits.append(Tuple(V)) + else: + limits.append(Tuple(V, V.lower, V.upper)) + else: + limits.append(Tuple(V)) + continue + if is_sequence(V) and not isinstance(V, Set): + if len(V) == 2 and isinstance(V[1], Set): + V = list(V) + if isinstance(V[1], Interval): # includes Reals + if discrete: + raise TypeError(err_msg) + V[1:] = V[1].inf, V[1].sup + elif isinstance(V[1], Range): + if not discrete: + raise TypeError(err_msg) + lo = V[1].inf + hi = V[1].sup + dx = abs(V[1].step) # direction doesn't matter + if dx == 1: + V[1:] = [lo, hi] + else: + if lo is not S.NegativeInfinity: + V = [V[0]] + [0, (hi - lo)//dx, dx*V[0] + lo] + else: + V = [V[0]] + [0, S.Infinity, -dx*V[0] + hi] + else: + # more complicated sets would require splitting, e.g. + # Union(Interval(1, 3), interval(6,10)) + raise NotImplementedError( + 'expecting Range' if discrete else + 'Relational or single Interval' ) + V = sympify(flatten(V)) # list of sympified elements/None + if isinstance(V[0], (Symbol, Idx)) or getattr(V[0], '_diff_wrt', False): + newsymbol = V[0] + if len(V) == 3: + # general case + if V[2] is None and V[1] is not None: + orientation *= -1 + V = [newsymbol] + [i for i in V[1:] if i is not None] + + lenV = len(V) + if not isinstance(newsymbol, Idx) or lenV == 3: + if lenV == 4: + limits.append(Tuple(*V)) + continue + if lenV == 3: + if isinstance(newsymbol, Idx): + # Idx represents an integer which may have + # specified values it can take on; if it is + # given such a value, an error is raised here + # if the summation would try to give it a larger + # or smaller value than permitted. None and Symbolic + # values will not raise an error. + lo, hi = newsymbol.lower, newsymbol.upper + try: + if lo is not None and not bool(V[1] >= lo): + raise ValueError("Summation will set Idx value too low.") + except TypeError: + pass + try: + if hi is not None and not bool(V[2] <= hi): + raise ValueError("Summation will set Idx value too high.") + except TypeError: + pass + limits.append(Tuple(*V)) + continue + if lenV == 1 or (lenV == 2 and V[1] is None): + limits.append(Tuple(newsymbol)) + continue + elif lenV == 2: + limits.append(Tuple(newsymbol, V[1])) + continue + + raise ValueError('Invalid limits given: %s' % str(symbols)) + + return limits, orientation + + +class ExprWithLimits(Expr): + __slots__ = ('is_commutative',) + + def __new__(cls, function, *symbols, **assumptions): + from sympy.concrete.products import Product + pre = _common_new(cls, function, *symbols, + discrete=issubclass(cls, Product), **assumptions) + if isinstance(pre, tuple): + function, limits, _ = pre + else: + return pre + + # limits must have upper and lower bounds; the indefinite form + # is not supported. This restriction does not apply to AddWithLimits + if any(len(l) != 3 or None in l for l in limits): + raise ValueError('ExprWithLimits requires values for lower and upper bounds.') + + obj = Expr.__new__(cls, **assumptions) + arglist = [function] + arglist.extend(limits) + obj._args = tuple(arglist) + obj.is_commutative = function.is_commutative # limits already checked + + return obj + + @property + def function(self): + """Return the function applied across limits. + + Examples + ======== + + >>> from sympy import Integral + >>> from sympy.abc import x + >>> Integral(x**2, (x,)).function + x**2 + + See Also + ======== + + limits, variables, free_symbols + """ + return self._args[0] + + @property + def kind(self): + return self.function.kind + + @property + def limits(self): + """Return the limits of expression. + + Examples + ======== + + >>> from sympy import Integral + >>> from sympy.abc import x, i + >>> Integral(x**i, (i, 1, 3)).limits + ((i, 1, 3),) + + See Also + ======== + + function, variables, free_symbols + """ + return self._args[1:] + + @property + def variables(self): + """Return a list of the limit variables. + + >>> from sympy import Sum + >>> from sympy.abc import x, i + >>> Sum(x**i, (i, 1, 3)).variables + [i] + + See Also + ======== + + function, limits, free_symbols + as_dummy : Rename dummy variables + sympy.integrals.integrals.Integral.transform : Perform mapping on the dummy variable + """ + return [l[0] for l in self.limits] + + @property + def bound_symbols(self): + """Return only variables that are dummy variables. + + Examples + ======== + + >>> from sympy import Integral + >>> from sympy.abc import x, i, j, k + >>> Integral(x**i, (i, 1, 3), (j, 2), k).bound_symbols + [i, j] + + See Also + ======== + + function, limits, free_symbols + as_dummy : Rename dummy variables + sympy.integrals.integrals.Integral.transform : Perform mapping on the dummy variable + """ + return [l[0] for l in self.limits if len(l) != 1] + + @property + def free_symbols(self): + """ + This method returns the symbols in the object, excluding those + that take on a specific value (i.e. the dummy symbols). + + Examples + ======== + + >>> from sympy import Sum + >>> from sympy.abc import x, y + >>> Sum(x, (x, y, 1)).free_symbols + {y} + """ + # don't test for any special values -- nominal free symbols + # should be returned, e.g. don't return set() if the + # function is zero -- treat it like an unevaluated expression. + function, limits = self.function, self.limits + # mask off non-symbol integration variables that have + # more than themself as a free symbol + reps = {i[0]: i[0] if i[0].free_symbols == {i[0]} else Dummy() + for i in self.limits} + function = function.xreplace(reps) + isyms = function.free_symbols + for xab in limits: + v = reps[xab[0]] + if len(xab) == 1: + isyms.add(v) + continue + # take out the target symbol + if v in isyms: + isyms.remove(v) + # add in the new symbols + for i in xab[1:]: + isyms.update(i.free_symbols) + reps = {v: k for k, v in reps.items()} + return {reps.get(_, _) for _ in isyms} + + @property + def is_number(self): + """Return True if the Sum has no free symbols, else False.""" + return not self.free_symbols + + def _eval_interval(self, x, a, b): + limits = [(i if i[0] != x else (x, a, b)) for i in self.limits] + integrand = self.function + return self.func(integrand, *limits) + + def _eval_subs(self, old, new): + """ + Perform substitutions over non-dummy variables + of an expression with limits. Also, can be used + to specify point-evaluation of an abstract antiderivative. + + Examples + ======== + + >>> from sympy import Sum, oo + >>> from sympy.abc import s, n + >>> Sum(1/n**s, (n, 1, oo)).subs(s, 2) + Sum(n**(-2), (n, 1, oo)) + + >>> from sympy import Integral + >>> from sympy.abc import x, a + >>> Integral(a*x**2, x).subs(x, 4) + Integral(a*x**2, (x, 4)) + + See Also + ======== + + variables : Lists the integration variables + transform : Perform mapping on the dummy variable for integrals + change_index : Perform mapping on the sum and product dummy variables + + """ + func, limits = self.function, list(self.limits) + + # If one of the expressions we are replacing is used as a func index + # one of two things happens. + # - the old variable first appears as a free variable + # so we perform all free substitutions before it becomes + # a func index. + # - the old variable first appears as a func index, in + # which case we ignore. See change_index. + + # Reorder limits to match standard mathematical practice for scoping + limits.reverse() + + if not isinstance(old, Symbol) or \ + old.free_symbols.intersection(self.free_symbols): + sub_into_func = True + for i, xab in enumerate(limits): + if 1 == len(xab) and old == xab[0]: + if new._diff_wrt: + xab = (new,) + else: + xab = (old, old) + limits[i] = Tuple(xab[0], *[l._subs(old, new) for l in xab[1:]]) + if len(xab[0].free_symbols.intersection(old.free_symbols)) != 0: + sub_into_func = False + break + if isinstance(old, (AppliedUndef, UndefinedFunction)): + sy2 = set(self.variables).intersection(set(new.atoms(Symbol))) + sy1 = set(self.variables).intersection(set(old.args)) + if not sy2.issubset(sy1): + raise ValueError( + "substitution cannot create dummy dependencies") + sub_into_func = True + if sub_into_func: + func = func.subs(old, new) + else: + # old is a Symbol and a dummy variable of some limit + for i, xab in enumerate(limits): + if len(xab) == 3: + limits[i] = Tuple(xab[0], *[l._subs(old, new) for l in xab[1:]]) + if old == xab[0]: + break + # simplify redundant limits (x, x) to (x, ) + for i, xab in enumerate(limits): + if len(xab) == 2 and (xab[0] - xab[1]).is_zero: + limits[i] = Tuple(xab[0], ) + + # Reorder limits back to representation-form + limits.reverse() + + return self.func(func, *limits) + + @property + def has_finite_limits(self): + """ + Returns True if the limits are known to be finite, either by the + explicit bounds, assumptions on the bounds, or assumptions on the + variables. False if known to be infinite, based on the bounds. + None if not enough information is available to determine. + + Examples + ======== + + >>> from sympy import Sum, Integral, Product, oo, Symbol + >>> x = Symbol('x') + >>> Sum(x, (x, 1, 8)).has_finite_limits + True + + >>> Integral(x, (x, 1, oo)).has_finite_limits + False + + >>> M = Symbol('M') + >>> Sum(x, (x, 1, M)).has_finite_limits + + >>> N = Symbol('N', integer=True) + >>> Product(x, (x, 1, N)).has_finite_limits + True + + See Also + ======== + + has_reversed_limits + + """ + + ret_None = False + for lim in self.limits: + if len(lim) == 3: + if any(l.is_infinite for l in lim[1:]): + # Any of the bounds are +/-oo + return False + elif any(l.is_infinite is None for l in lim[1:]): + # Maybe there are assumptions on the variable? + if lim[0].is_infinite is None: + ret_None = True + else: + if lim[0].is_infinite is None: + ret_None = True + + if ret_None: + return None + return True + + @property + def has_reversed_limits(self): + """ + Returns True if the limits are known to be in reversed order, either + by the explicit bounds, assumptions on the bounds, or assumptions on the + variables. False if known to be in normal order, based on the bounds. + None if not enough information is available to determine. + + Examples + ======== + + >>> from sympy import Sum, Integral, Product, oo, Symbol + >>> x = Symbol('x') + >>> Sum(x, (x, 8, 1)).has_reversed_limits + True + + >>> Sum(x, (x, 1, oo)).has_reversed_limits + False + + >>> M = Symbol('M') + >>> Integral(x, (x, 1, M)).has_reversed_limits + + >>> N = Symbol('N', integer=True, positive=True) + >>> Sum(x, (x, 1, N)).has_reversed_limits + False + + >>> Product(x, (x, 2, N)).has_reversed_limits + + >>> Product(x, (x, 2, N)).subs(N, N + 2).has_reversed_limits + False + + See Also + ======== + + sympy.concrete.expr_with_intlimits.ExprWithIntLimits.has_empty_sequence + + """ + ret_None = False + for lim in self.limits: + if len(lim) == 3: + var, a, b = lim + dif = b - a + if dif.is_extended_negative: + return True + elif dif.is_extended_nonnegative: + continue + else: + ret_None = True + else: + return None + if ret_None: + return None + return False + + +class AddWithLimits(ExprWithLimits): + r"""Represents unevaluated oriented additions. + Parent class for Integral and Sum. + """ + + __slots__ = () + + def __new__(cls, function, *symbols, **assumptions): + from sympy.concrete.summations import Sum + pre = _common_new(cls, function, *symbols, + discrete=issubclass(cls, Sum), **assumptions) + if isinstance(pre, tuple): + function, limits, orientation = pre + else: + return pre + + obj = Expr.__new__(cls, **assumptions) + arglist = [orientation*function] # orientation not used in ExprWithLimits + arglist.extend(limits) + obj._args = tuple(arglist) + obj.is_commutative = function.is_commutative # limits already checked + + return obj + + def _eval_adjoint(self): + if all(x.is_real for x in flatten(self.limits)): + return self.func(self.function.adjoint(), *self.limits) + return None + + def _eval_conjugate(self): + if all(x.is_real for x in flatten(self.limits)): + return self.func(self.function.conjugate(), *self.limits) + return None + + def _eval_transpose(self): + if all(x.is_real for x in flatten(self.limits)): + return self.func(self.function.transpose(), *self.limits) + return None + + def _eval_factor(self, **hints): + if 1 == len(self.limits): + summand = self.function.factor(**hints) + if summand.is_Mul: + out = sift(summand.args, lambda w: w.is_commutative \ + and not set(self.variables) & w.free_symbols) + return Mul(*out[True])*self.func(Mul(*out[False]), \ + *self.limits) + else: + summand = self.func(self.function, *self.limits[0:-1]).factor() + if not summand.has(self.variables[-1]): + return self.func(1, [self.limits[-1]]).doit()*summand + elif isinstance(summand, Mul): + return self.func(summand, self.limits[-1]).factor() + return self + + def _eval_expand_basic(self, **hints): + summand = self.function.expand(**hints) + force = hints.get('force', False) + if (summand.is_Add and (force or summand.is_commutative and + self.has_finite_limits is not False)): + return Add(*[self.func(i, *self.limits) for i in summand.args]) + elif isinstance(summand, MatrixBase): + return summand.applyfunc(lambda x: self.func(x, *self.limits)) + elif summand != self.function: + return self.func(summand, *self.limits) + return self diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/gosper.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/gosper.py new file mode 100644 index 0000000000000000000000000000000000000000..76eb20ef4f94bc6bff6324a1dcc09f90e05274b3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/gosper.py @@ -0,0 +1,222 @@ +"""Gosper's algorithm for hypergeometric summation. """ + +from sympy.core import S, Dummy, symbols +from sympy.polys import Poly, parallel_poly_from_expr, factor +from sympy.utilities.iterables import is_sequence + + +def gosper_normal(f, g, n, polys=True): + r""" + Compute the Gosper's normal form of ``f`` and ``g``. + + Explanation + =========== + + Given relatively prime univariate polynomials ``f`` and ``g``, + rewrite their quotient to a normal form defined as follows: + + .. math:: + \frac{f(n)}{g(n)} = Z \cdot \frac{A(n) C(n+1)}{B(n) C(n)} + + where ``Z`` is an arbitrary constant and ``A``, ``B``, ``C`` are + monic polynomials in ``n`` with the following properties: + + 1. `\gcd(A(n), B(n+h)) = 1 \forall h \in \mathbb{N}` + 2. `\gcd(B(n), C(n+1)) = 1` + 3. `\gcd(A(n), C(n)) = 1` + + This normal form, or rational factorization in other words, is a + crucial step in Gosper's algorithm and in solving of difference + equations. It can be also used to decide if two hypergeometric + terms are similar or not. + + This procedure will return a tuple containing elements of this + factorization in the form ``(Z*A, B, C)``. + + Examples + ======== + + >>> from sympy.concrete.gosper import gosper_normal + >>> from sympy.abc import n + + >>> gosper_normal(4*n+5, 2*(4*n+1)*(2*n+3), n, polys=False) + (1/4, n + 3/2, n + 1/4) + + """ + (p, q), opt = parallel_poly_from_expr( + (f, g), n, field=True, extension=True) + + a, A = p.LC(), p.monic() + b, B = q.LC(), q.monic() + + C, Z = A.one, a/b + h = Dummy('h') + + D = Poly(n + h, n, h, domain=opt.domain) + + R = A.resultant(B.compose(D)) + roots = {r for r in R.ground_roots().keys() if r.is_Integer and r >= 0} + for i in sorted(roots): + d = A.gcd(B.shift(+i)) + + A = A.quo(d) + B = B.quo(d.shift(-i)) + + for j in range(1, i + 1): + C *= d.shift(-j) + + A = A.mul_ground(Z) + + if not polys: + A = A.as_expr() + B = B.as_expr() + C = C.as_expr() + + return A, B, C + + +def gosper_term(f, n): + r""" + Compute Gosper's hypergeometric term for ``f``. + + Explanation + =========== + + Suppose ``f`` is a hypergeometric term such that: + + .. math:: + s_n = \sum_{k=0}^{n-1} f_k + + and `f_k` does not depend on `n`. Returns a hypergeometric + term `g_n` such that `g_{n+1} - g_n = f_n`. + + Examples + ======== + + >>> from sympy.concrete.gosper import gosper_term + >>> from sympy import factorial + >>> from sympy.abc import n + + >>> gosper_term((4*n + 1)*factorial(n)/factorial(2*n + 1), n) + (-n - 1/2)/(n + 1/4) + + """ + from sympy.simplify import hypersimp + r = hypersimp(f, n) + + if r is None: + return None # 'f' is *not* a hypergeometric term + + p, q = r.as_numer_denom() + + A, B, C = gosper_normal(p, q, n) + B = B.shift(-1) + + N = S(A.degree()) + M = S(B.degree()) + K = S(C.degree()) + + if (N != M) or (A.LC() != B.LC()): + D = {K - max(N, M)} + elif not N: + D = {K - N + 1, S.Zero} + else: + D = {K - N + 1, (B.nth(N - 1) - A.nth(N - 1))/A.LC()} + + for d in set(D): + if not d.is_Integer or d < 0: + D.remove(d) + + if not D: + return None # 'f(n)' is *not* Gosper-summable + + d = max(D) + + coeffs = symbols('c:%s' % (d + 1), cls=Dummy) + domain = A.get_domain().inject(*coeffs) + + x = Poly(coeffs, n, domain=domain) + H = A*x.shift(1) - B*x - C + + from sympy.solvers.solvers import solve + solution = solve(H.coeffs(), coeffs) + + if solution is None: + return None # 'f(n)' is *not* Gosper-summable + + x = x.as_expr().subs(solution) + + for coeff in coeffs: + if coeff not in solution: + x = x.subs(coeff, 0) + + if x.is_zero: + return None # 'f(n)' is *not* Gosper-summable + else: + return B.as_expr()*x/C.as_expr() + + +def gosper_sum(f, k): + r""" + Gosper's hypergeometric summation algorithm. + + Explanation + =========== + + Given a hypergeometric term ``f`` such that: + + .. math :: + s_n = \sum_{k=0}^{n-1} f_k + + and `f(n)` does not depend on `n`, returns `g_{n} - g(0)` where + `g_{n+1} - g_n = f_n`, or ``None`` if `s_n` cannot be expressed + in closed form as a sum of hypergeometric terms. + + Examples + ======== + + >>> from sympy.concrete.gosper import gosper_sum + >>> from sympy import factorial + >>> from sympy.abc import n, k + + >>> f = (4*k + 1)*factorial(k)/factorial(2*k + 1) + >>> gosper_sum(f, (k, 0, n)) + (-factorial(n) + 2*factorial(2*n + 1))/factorial(2*n + 1) + >>> _.subs(n, 2) == sum(f.subs(k, i) for i in [0, 1, 2]) + True + >>> gosper_sum(f, (k, 3, n)) + (-60*factorial(n) + factorial(2*n + 1))/(60*factorial(2*n + 1)) + >>> _.subs(n, 5) == sum(f.subs(k, i) for i in [3, 4, 5]) + True + + References + ========== + + .. [1] Marko Petkovsek, Herbert S. Wilf, Doron Zeilberger, A = B, + AK Peters, Ltd., Wellesley, MA, USA, 1997, pp. 73--100 + + """ + indefinite = False + + if is_sequence(k): + k, a, b = k + else: + indefinite = True + + g = gosper_term(f, k) + + if g is None: + return None + + if indefinite: + result = f*g + else: + result = (f*(g + 1)).subs(k, b) - (f*g).subs(k, a) + + if result is S.NaN: + try: + result = (f*(g + 1)).limit(k, b) - (f*g).limit(k, a) + except NotImplementedError: + result = None + + return factor(result) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/guess.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/guess.py new file mode 100644 index 0000000000000000000000000000000000000000..90aac54b442ce67c90cbb262e10d525e5f2ba316 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/guess.py @@ -0,0 +1,473 @@ +"""Various algorithms for helping identifying numbers and sequences.""" + + +from sympy.concrete.products import (Product, product) +from sympy.core import Function, S +from sympy.core.add import Add +from sympy.core.numbers import Integer, Rational +from sympy.core.symbol import Symbol, symbols +from sympy.core.sympify import sympify +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.integers import floor +from sympy.integrals.integrals import integrate +from sympy.polys.polyfuncs import rational_interpolate as rinterp +from sympy.polys.polytools import lcm +from sympy.simplify.radsimp import denom +from sympy.utilities import public + + +@public +def find_simple_recurrence_vector(l): + """ + This function is used internally by other functions from the + sympy.concrete.guess module. While most users may want to rather use the + function find_simple_recurrence when looking for recurrence relations + among rational numbers, the current function may still be useful when + some post-processing has to be done. + + Explanation + =========== + + The function returns a vector of length n when a recurrence relation of + order n is detected in the sequence of rational numbers v. + + If the returned vector has a length 1, then the returned value is always + the list [0], which means that no relation has been found. + + While the functions is intended to be used with rational numbers, it should + work for other kinds of real numbers except for some cases involving + quadratic numbers; for that reason it should be used with some caution when + the argument is not a list of rational numbers. + + Examples + ======== + + >>> from sympy.concrete.guess import find_simple_recurrence_vector + >>> from sympy import fibonacci + >>> find_simple_recurrence_vector([fibonacci(k) for k in range(12)]) + [1, -1, -1] + + See Also + ======== + + See the function sympy.concrete.guess.find_simple_recurrence which is more + user-friendly. + + """ + q1 = [0] + q2 = [1] + b, z = 0, len(l) >> 1 + while len(q2) <= z: + while l[b]==0: + b += 1 + if b == len(l): + c = 1 + for x in q2: + c = lcm(c, denom(x)) + if q2[0]*c < 0: c = -c + for k in range(len(q2)): + q2[k] = int(q2[k]*c) + return q2 + a = S.One/l[b] + m = [a] + for k in range(b+1, len(l)): + m.append(-sum(l[j+1]*m[b-j-1] for j in range(b, k))*a) + l, m = m, [0] * max(len(q2), b+len(q1)) + for k, q in enumerate(q2): + m[k] = a*q + for k, q in enumerate(q1): + m[k+b] += q + while m[-1]==0: m.pop() # because trailing zeros can occur + q1, q2, b = q2, m, 1 + return [0] + +@public +def find_simple_recurrence(v, A=Function('a'), N=Symbol('n')): + """ + Detects and returns a recurrence relation from a sequence of several integer + (or rational) terms. The name of the function in the returned expression is + 'a' by default; the main variable is 'n' by default. The smallest index in + the returned expression is always n (and never n-1, n-2, etc.). + + Examples + ======== + + >>> from sympy.concrete.guess import find_simple_recurrence + >>> from sympy import fibonacci + >>> find_simple_recurrence([fibonacci(k) for k in range(12)]) + -a(n) - a(n + 1) + a(n + 2) + + >>> from sympy import Function, Symbol + >>> a = [1, 1, 1] + >>> for k in range(15): a.append(5*a[-1]-3*a[-2]+8*a[-3]) + >>> find_simple_recurrence(a, A=Function('f'), N=Symbol('i')) + -8*f(i) + 3*f(i + 1) - 5*f(i + 2) + f(i + 3) + + """ + p = find_simple_recurrence_vector(v) + n = len(p) + if n <= 1: return S.Zero + + return Add(*[A(N+n-1-k)*p[k] for k in range(n)]) + + +@public +def rationalize(x, maxcoeff=10000): + """ + Helps identifying a rational number from a float (or mpmath.mpf) value by + using a continued fraction. The algorithm stops as soon as a large partial + quotient is detected (greater than 10000 by default). + + Examples + ======== + + >>> from sympy.concrete.guess import rationalize + >>> from mpmath import cos, pi + >>> rationalize(cos(pi/3)) + 1/2 + + >>> from mpmath import mpf + >>> rationalize(mpf("0.333333333333333")) + 1/3 + + While the function is rather intended to help 'identifying' rational + values, it may be used in some cases for approximating real numbers. + (Though other functions may be more relevant in that case.) + + >>> rationalize(pi, maxcoeff = 250) + 355/113 + + See Also + ======== + + Several other methods can approximate a real number as a rational, like: + + * fractions.Fraction.from_decimal + * fractions.Fraction.from_float + * mpmath.identify + * mpmath.pslq by using the following syntax: mpmath.pslq([x, 1]) + * mpmath.findpoly by using the following syntax: mpmath.findpoly(x, 1) + * sympy.simplify.nsimplify (which is a more general function) + + The main difference between the current function and all these variants is + that control focuses on magnitude of partial quotients here rather than on + global precision of the approximation. If the real is "known to be" a + rational number, the current function should be able to detect it correctly + with the default settings even when denominator is great (unless its + expansion contains unusually big partial quotients) which may occur + when studying sequences of increasing numbers. If the user cares more + on getting simple fractions, other methods may be more convenient. + + """ + p0, p1 = 0, 1 + q0, q1 = 1, 0 + a = floor(x) + while a < maxcoeff or q1==0: + p = a*p1 + p0 + q = a*q1 + q0 + p0, p1 = p1, p + q0, q1 = q1, q + if x==a: break + x = 1/(x-a) + a = floor(x) + return sympify(p) / q + + +@public +def guess_generating_function_rational(v, X=Symbol('x')): + """ + Tries to "guess" a rational generating function for a sequence of rational + numbers v. + + Examples + ======== + + >>> from sympy.concrete.guess import guess_generating_function_rational + >>> from sympy import fibonacci + >>> l = [fibonacci(k) for k in range(5,15)] + >>> guess_generating_function_rational(l) + (3*x + 5)/(-x**2 - x + 1) + + See Also + ======== + + sympy.series.approximants + mpmath.pade + + """ + # a) compute the denominator as q + q = find_simple_recurrence_vector(v) + n = len(q) + if n <= 1: return None + # b) compute the numerator as p + p = [sum(v[i-k]*q[k] for k in range(min(i+1, n))) + for i in range(len(v)>>1)] + return (sum(p[k]*X**k for k in range(len(p))) + / sum(q[k]*X**k for k in range(n))) + + +@public +def guess_generating_function(v, X=Symbol('x'), types=['all'], maxsqrtn=2): + """ + Tries to "guess" a generating function for a sequence of rational numbers v. + Only a few patterns are implemented yet. + + Explanation + =========== + + The function returns a dictionary where keys are the name of a given type of + generating function. Six types are currently implemented: + + type | formal definition + -------+---------------------------------------------------------------- + ogf | f(x) = Sum( a_k * x^k , k: 0..infinity ) + egf | f(x) = Sum( a_k * x^k / k! , k: 0..infinity ) + lgf | f(x) = Sum( (-1)^(k+1) a_k * x^k / k , k: 1..infinity ) + | (with initial index being hold as 1 rather than 0) + hlgf | f(x) = Sum( a_k * x^k / k , k: 1..infinity ) + | (with initial index being hold as 1 rather than 0) + lgdogf | f(x) = derivate( log(Sum( a_k * x^k, k: 0..infinity )), x) + lgdegf | f(x) = derivate( log(Sum( a_k * x^k / k!, k: 0..infinity )), x) + + In order to spare time, the user can select only some types of generating + functions (default being ['all']). While forgetting to use a list in the + case of a single type may seem to work most of the time as in: types='ogf' + this (convenient) syntax may lead to unexpected extra results in some cases. + + Discarding a type when calling the function does not mean that the type will + not be present in the returned dictionary; it only means that no extra + computation will be performed for that type, but the function may still add + it in the result when it can be easily converted from another type. + + Two generating functions (lgdogf and lgdegf) are not even computed if the + initial term of the sequence is 0; it may be useful in that case to try + again after having removed the leading zeros. + + Examples + ======== + + >>> from sympy.concrete.guess import guess_generating_function as ggf + >>> ggf([k+1 for k in range(12)], types=['ogf', 'lgf', 'hlgf']) + {'hlgf': 1/(1 - x), 'lgf': 1/(x + 1), 'ogf': 1/(x**2 - 2*x + 1)} + + >>> from sympy import sympify + >>> l = sympify("[3/2, 11/2, 0, -121/2, -363/2, 121]") + >>> ggf(l) + {'ogf': (x + 3/2)/(11*x**2 - 3*x + 1)} + + >>> from sympy import fibonacci + >>> ggf([fibonacci(k) for k in range(5, 15)], types=['ogf']) + {'ogf': (3*x + 5)/(-x**2 - x + 1)} + + >>> from sympy import factorial + >>> ggf([factorial(k) for k in range(12)], types=['ogf', 'egf', 'lgf']) + {'egf': 1/(1 - x)} + + >>> ggf([k+1 for k in range(12)], types=['egf']) + {'egf': (x + 1)*exp(x), 'lgdegf': (x + 2)/(x + 1)} + + N-th root of a rational function can also be detected (below is an example + coming from the sequence A108626 from https://oeis.org). + The greatest n-th root to be tested is specified as maxsqrtn (default 2). + + >>> ggf([1, 2, 5, 14, 41, 124, 383, 1200, 3799, 12122, 38919])['ogf'] + sqrt(1/(x**4 + 2*x**2 - 4*x + 1)) + + References + ========== + + .. [1] "Concrete Mathematics", R.L. Graham, D.E. Knuth, O. Patashnik + .. [2] https://oeis.org/wiki/Generating_functions + + """ + # List of all types of all g.f. known by the algorithm + if 'all' in types: + types = ('ogf', 'egf', 'lgf', 'hlgf', 'lgdogf', 'lgdegf') + + result = {} + + # Ordinary Generating Function (ogf) + if 'ogf' in types: + # Perform some convolutions of the sequence with itself + t = [1] + [0]*(len(v) - 1) + for d in range(max(1, maxsqrtn)): + t = [sum(t[n-i]*v[i] for i in range(n+1)) for n in range(len(v))] + g = guess_generating_function_rational(t, X=X) + if g: + result['ogf'] = g**Rational(1, d+1) + break + + # Exponential Generating Function (egf) + if 'egf' in types: + # Transform sequence (division by factorial) + w, f = [], S.One + for i, k in enumerate(v): + f *= i if i else 1 + w.append(k/f) + # Perform some convolutions of the sequence with itself + t = [1] + [0]*(len(w) - 1) + for d in range(max(1, maxsqrtn)): + t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] + g = guess_generating_function_rational(t, X=X) + if g: + result['egf'] = g**Rational(1, d+1) + break + + # Logarithmic Generating Function (lgf) + if 'lgf' in types: + # Transform sequence (multiplication by (-1)^(n+1) / n) + w, f = [], S.NegativeOne + for i, k in enumerate(v): + f = -f + w.append(f*k/Integer(i+1)) + # Perform some convolutions of the sequence with itself + t = [1] + [0]*(len(w) - 1) + for d in range(max(1, maxsqrtn)): + t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] + g = guess_generating_function_rational(t, X=X) + if g: + result['lgf'] = g**Rational(1, d+1) + break + + # Hyperbolic logarithmic Generating Function (hlgf) + if 'hlgf' in types: + # Transform sequence (division by n+1) + w = [] + for i, k in enumerate(v): + w.append(k/Integer(i+1)) + # Perform some convolutions of the sequence with itself + t = [1] + [0]*(len(w) - 1) + for d in range(max(1, maxsqrtn)): + t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] + g = guess_generating_function_rational(t, X=X) + if g: + result['hlgf'] = g**Rational(1, d+1) + break + + # Logarithmic derivative of ordinary generating Function (lgdogf) + if v[0] != 0 and ('lgdogf' in types + or ('ogf' in types and 'ogf' not in result)): + # Transform sequence by computing f'(x)/f(x) + # because log(f(x)) = integrate( f'(x)/f(x) ) + a, w = sympify(v[0]), [] + for n in range(len(v)-1): + w.append( + (v[n+1]*(n+1) - sum(w[-i-1]*v[i+1] for i in range(n)))/a) + # Perform some convolutions of the sequence with itself + t = [1] + [0]*(len(w) - 1) + for d in range(max(1, maxsqrtn)): + t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] + g = guess_generating_function_rational(t, X=X) + if g: + result['lgdogf'] = g**Rational(1, d+1) + if 'ogf' not in result: + result['ogf'] = exp(integrate(result['lgdogf'], X)) + break + + # Logarithmic derivative of exponential generating Function (lgdegf) + if v[0] != 0 and ('lgdegf' in types + or ('egf' in types and 'egf' not in result)): + # Transform sequence / step 1 (division by factorial) + z, f = [], S.One + for i, k in enumerate(v): + f *= i if i else 1 + z.append(k/f) + # Transform sequence / step 2 by computing f'(x)/f(x) + # because log(f(x)) = integrate( f'(x)/f(x) ) + a, w = z[0], [] + for n in range(len(z)-1): + w.append( + (z[n+1]*(n+1) - sum(w[-i-1]*z[i+1] for i in range(n)))/a) + # Perform some convolutions of the sequence with itself + t = [1] + [0]*(len(w) - 1) + for d in range(max(1, maxsqrtn)): + t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] + g = guess_generating_function_rational(t, X=X) + if g: + result['lgdegf'] = g**Rational(1, d+1) + if 'egf' not in result: + result['egf'] = exp(integrate(result['lgdegf'], X)) + break + + return result + + +@public +def guess(l, all=False, evaluate=True, niter=2, variables=None): + """ + This function is adapted from the Rate.m package for Mathematica + written by Christian Krattenthaler. + It tries to guess a formula from a given sequence of rational numbers. + + Explanation + =========== + + In order to speed up the process, the 'all' variable is set to False by + default, stopping the computation as some results are returned during an + iteration; the variable can be set to True if more iterations are needed + (other formulas may be found; however they may be equivalent to the first + ones). + + Another option is the 'evaluate' variable (default is True); setting it + to False will leave the involved products unevaluated. + + By default, the number of iterations is set to 2 but a greater value (up + to len(l)-1) can be specified with the optional 'niter' variable. + More and more convoluted results are found when the order of the + iteration gets higher: + + * first iteration returns polynomial or rational functions; + * second iteration returns products of rising factorials and their + inverses; + * third iteration returns products of products of rising factorials + and their inverses; + * etc. + + The returned formulas contain symbols i0, i1, i2, ... where the main + variables is i0 (and auxiliary variables are i1, i2, ...). A list of + other symbols can be provided in the 'variables' option; the length of + the least should be the value of 'niter' (more is acceptable but only + the first symbols will be used); in this case, the main variable will be + the first symbol in the list. + + Examples + ======== + + >>> from sympy.concrete.guess import guess + >>> guess([1,2,6,24,120], evaluate=False) + [Product(i1 + 1, (i1, 1, i0 - 1))] + + >>> from sympy import symbols + >>> r = guess([1,2,7,42,429,7436,218348,10850216], niter=4) + >>> i0 = symbols("i0") + >>> [r[0].subs(i0,n).doit() for n in range(1,10)] + [1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460] + """ + if any(a==0 for a in l[:-1]): + return [] + N = len(l) + niter = min(N-1, niter) + myprod = product if evaluate else Product + g = [] + res = [] + if variables is None: + symb = symbols('i:'+str(niter)) + else: + symb = variables + for k, s in enumerate(symb): + g.append(l) + n, r = len(l), [] + for i in range(n-2-1, -1, -1): + ri = rinterp(enumerate(g[k][:-1], start=1), i, X=s) + if ((denom(ri).subs({s:n}) != 0) + and (ri.subs({s:n}) - g[k][-1] == 0) + and ri not in r): + r.append(ri) + if r: + for i in range(k-1, -1, -1): + r = [g[i][0] + * myprod(v, (symb[i+1], 1, symb[i]-1)) for v in r] + if not all: return r + res += r + l = [Rational(l[i+1], l[i]) for i in range(N-k-1)] + return res diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/products.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/products.py new file mode 100644 index 0000000000000000000000000000000000000000..dd035551683531f80b0e4467fe1cdfbb6ebbe9ad --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/products.py @@ -0,0 +1,605 @@ +from __future__ import annotations + +from .expr_with_intlimits import ExprWithIntLimits +from .summations import Sum, summation, _dummy_with_inherited_properties_concrete +from sympy.core.expr import Expr +from sympy.core.exprtools import factor_terms +from sympy.core.function import Derivative +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.core.symbol import Dummy, Symbol +from sympy.functions.combinatorial.factorials import RisingFactorial +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.polys import quo, roots + + +class Product(ExprWithIntLimits): + r""" + Represents unevaluated products. + + Explanation + =========== + + ``Product`` represents a finite or infinite product, with the first + argument being the general form of terms in the series, and the second + argument being ``(dummy_variable, start, end)``, with ``dummy_variable`` + taking all integer values from ``start`` through ``end``. In accordance + with long-standing mathematical convention, the end term is included in + the product. + + Finite products + =============== + + For finite products (and products with symbolic limits assumed to be finite) + we follow the analogue of the summation convention described by Karr [1], + especially definition 3 of section 1.4. The product: + + .. math:: + + \prod_{m \leq i < n} f(i) + + has *the obvious meaning* for `m < n`, namely: + + .. math:: + + \prod_{m \leq i < n} f(i) = f(m) f(m+1) \cdot \ldots \cdot f(n-2) f(n-1) + + with the upper limit value `f(n)` excluded. The product over an empty set is + one if and only if `m = n`: + + .. math:: + + \prod_{m \leq i < n} f(i) = 1 \quad \mathrm{for} \quad m = n + + Finally, for all other products over empty sets we assume the following + definition: + + .. math:: + + \prod_{m \leq i < n} f(i) = \frac{1}{\prod_{n \leq i < m} f(i)} \quad \mathrm{for} \quad m > n + + It is important to note that above we define all products with the upper + limit being exclusive. This is in contrast to the usual mathematical notation, + but does not affect the product convention. Indeed we have: + + .. math:: + + \prod_{m \leq i < n} f(i) = \prod_{i = m}^{n - 1} f(i) + + where the difference in notation is intentional to emphasize the meaning, + with limits typeset on the top being inclusive. + + Examples + ======== + + >>> from sympy.abc import a, b, i, k, m, n, x + >>> from sympy import Product, oo + >>> Product(k, (k, 1, m)) + Product(k, (k, 1, m)) + >>> Product(k, (k, 1, m)).doit() + factorial(m) + >>> Product(k**2,(k, 1, m)) + Product(k**2, (k, 1, m)) + >>> Product(k**2,(k, 1, m)).doit() + factorial(m)**2 + + Wallis' product for pi: + + >>> W = Product(2*i/(2*i-1) * 2*i/(2*i+1), (i, 1, oo)) + >>> W + Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, oo)) + + Direct computation currently fails: + + >>> W.doit() + Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, oo)) + + But we can approach the infinite product by a limit of finite products: + + >>> from sympy import limit + >>> W2 = Product(2*i/(2*i-1)*2*i/(2*i+1), (i, 1, n)) + >>> W2 + Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, n)) + >>> W2e = W2.doit() + >>> W2e + 4**n*factorial(n)**2/(2**(2*n)*RisingFactorial(1/2, n)*RisingFactorial(3/2, n)) + >>> limit(W2e, n, oo) + pi/2 + + By the same formula we can compute sin(pi/2): + + >>> from sympy import combsimp, pi, gamma, simplify + >>> P = pi * x * Product(1 - x**2/k**2, (k, 1, n)) + >>> P = P.subs(x, pi/2) + >>> P + pi**2*Product(1 - pi**2/(4*k**2), (k, 1, n))/2 + >>> Pe = P.doit() + >>> Pe + pi**2*RisingFactorial(1 - pi/2, n)*RisingFactorial(1 + pi/2, n)/(2*factorial(n)**2) + >>> limit(Pe, n, oo).gammasimp() + sin(pi**2/2) + >>> Pe.rewrite(gamma) + (-1)**n*pi**2*gamma(pi/2)*gamma(n + 1 + pi/2)/(2*gamma(1 + pi/2)*gamma(-n + pi/2)*gamma(n + 1)**2) + + Products with the lower limit being larger than the upper one: + + >>> Product(1/i, (i, 6, 1)).doit() + 120 + >>> Product(i, (i, 2, 5)).doit() + 120 + + The empty product: + + >>> Product(i, (i, n, n-1)).doit() + 1 + + An example showing that the symbolic result of a product is still + valid for seemingly nonsensical values of the limits. Then the Karr + convention allows us to give a perfectly valid interpretation to + those products by interchanging the limits according to the above rules: + + >>> P = Product(2, (i, 10, n)).doit() + >>> P + 2**(n - 9) + >>> P.subs(n, 5) + 1/16 + >>> Product(2, (i, 10, 5)).doit() + 1/16 + >>> 1/Product(2, (i, 6, 9)).doit() + 1/16 + + An explicit example of the Karr summation convention applied to products: + + >>> P1 = Product(x, (i, a, b)).doit() + >>> P1 + x**(-a + b + 1) + >>> P2 = Product(x, (i, b+1, a-1)).doit() + >>> P2 + x**(a - b - 1) + >>> simplify(P1 * P2) + 1 + + And another one: + + >>> P1 = Product(i, (i, b, a)).doit() + >>> P1 + RisingFactorial(b, a - b + 1) + >>> P2 = Product(i, (i, a+1, b-1)).doit() + >>> P2 + RisingFactorial(a + 1, -a + b - 1) + >>> P1 * P2 + RisingFactorial(b, a - b + 1)*RisingFactorial(a + 1, -a + b - 1) + >>> combsimp(P1 * P2) + 1 + + See Also + ======== + + Sum, summation + product + + References + ========== + + .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, + Volume 28 Issue 2, April 1981, Pages 305-350 + https://dl.acm.org/doi/10.1145/322248.322255 + .. [2] https://en.wikipedia.org/wiki/Multiplication#Capital_Pi_notation + .. [3] https://en.wikipedia.org/wiki/Empty_product + """ + + __slots__ = () + + limits: tuple[tuple[Symbol, Expr, Expr]] + + def __new__(cls, function, *symbols, **assumptions): + obj = ExprWithIntLimits.__new__(cls, function, *symbols, **assumptions) + return obj + + def _eval_rewrite_as_Sum(self, *args, **kwargs): + return exp(Sum(log(self.function), *self.limits)) + + @property + def term(self): + return self._args[0] + function = term + + def _eval_is_zero(self): + if self.has_empty_sequence: + return False + + z = self.term.is_zero + if z is True: + return True + if self.has_finite_limits: + # A Product is zero only if its term is zero assuming finite limits. + return z + + def _eval_is_extended_real(self): + if self.has_empty_sequence: + return True + + return self.function.is_extended_real + + def _eval_is_positive(self): + if self.has_empty_sequence: + return True + if self.function.is_positive and self.has_finite_limits: + return True + + def _eval_is_nonnegative(self): + if self.has_empty_sequence: + return True + if self.function.is_nonnegative and self.has_finite_limits: + return True + + def _eval_is_extended_nonnegative(self): + if self.has_empty_sequence: + return True + if self.function.is_extended_nonnegative: + return True + + def _eval_is_extended_nonpositive(self): + if self.has_empty_sequence: + return True + + def _eval_is_finite(self): + if self.has_finite_limits and self.function.is_finite: + return True + + def doit(self, **hints): + # first make sure any definite limits have product + # variables with matching assumptions + reps = {} + for xab in self.limits: + d = _dummy_with_inherited_properties_concrete(xab) + if d: + reps[xab[0]] = d + if reps: + undo = {v: k for k, v in reps.items()} + did = self.xreplace(reps).doit(**hints) + if isinstance(did, tuple): # when separate=True + did = tuple([i.xreplace(undo) for i in did]) + else: + did = did.xreplace(undo) + return did + + from sympy.simplify.powsimp import powsimp + f = self.function + for index, limit in enumerate(self.limits): + i, a, b = limit + dif = b - a + if dif.is_integer and dif.is_negative: + a, b = b + 1, a - 1 + f = 1 / f + + g = self._eval_product(f, (i, a, b)) + if g in (None, S.NaN): + return self.func(powsimp(f), *self.limits[index:]) + else: + f = g + + if hints.get('deep', True): + return f.doit(**hints) + else: + return powsimp(f) + + def _eval_conjugate(self): + return self.func(self.function.conjugate(), *self.limits) + + def _eval_product(self, term, limits): + + (k, a, n) = limits + + if k not in term.free_symbols: + if (term - 1).is_zero: + return S.One + return term**(n - a + 1) + + if a == n: + return term.subs(k, a) + + from .delta import deltaproduct, _has_simple_delta + if term.has(KroneckerDelta) and _has_simple_delta(term, limits[0]): + return deltaproduct(term, limits) + + dif = n - a + definite = dif.is_Integer + if definite and (dif < 100): + return self._eval_product_direct(term, limits) + + elif term.is_polynomial(k): + poly = term.as_poly(k) + + A = B = Q = S.One + + all_roots = roots(poly) + + M = 0 + for r, m in all_roots.items(): + M += m + A *= RisingFactorial(a - r, n - a + 1)**m + Q *= (n - r)**m + + if M < poly.degree(): + arg = quo(poly, Q.as_poly(k)) + B = self.func(arg, (k, a, n)).doit() + + return poly.LC()**(n - a + 1) * A * B + + elif term.is_Add: + factored = factor_terms(term, fraction=True) + if factored.is_Mul: + return self._eval_product(factored, (k, a, n)) + + elif term.is_Mul: + # Factor in part without the summation variable and part with + without_k, with_k = term.as_coeff_mul(k) + + if len(with_k) >= 2: + # More than one term including k, so still a multiplication + exclude, include = [], [] + for t in with_k: + p = self._eval_product(t, (k, a, n)) + + if p is not None: + exclude.append(p) + else: + include.append(t) + + if not exclude: + return None + else: + arg = term._new_rawargs(*include) + A = Mul(*exclude) + B = self.func(arg, (k, a, n)).doit() + return without_k**(n - a + 1)*A * B + else: + # Just a single term + p = self._eval_product(with_k[0], (k, a, n)) + if p is None: + p = self.func(with_k[0], (k, a, n)).doit() + return without_k**(n - a + 1)*p + + + elif term.is_Pow: + if not term.base.has(k): + s = summation(term.exp, (k, a, n)) + + return term.base**s + elif not term.exp.has(k): + p = self._eval_product(term.base, (k, a, n)) + + if p is not None: + return p**term.exp + + elif isinstance(term, Product): + evaluated = term.doit() + f = self._eval_product(evaluated, limits) + if f is None: + return self.func(evaluated, limits) + else: + return f + + if definite: + return self._eval_product_direct(term, limits) + + def _eval_simplify(self, **kwargs): + from sympy.simplify.simplify import product_simplify + rv = product_simplify(self, **kwargs) + return rv.doit() if kwargs['doit'] else rv + + def _eval_transpose(self): + if self.is_commutative: + return self.func(self.function.transpose(), *self.limits) + return None + + def _eval_product_direct(self, term, limits): + (k, a, n) = limits + return Mul(*[term.subs(k, a + i) for i in range(n - a + 1)]) + + def _eval_derivative(self, x): + if isinstance(x, Symbol) and x not in self.free_symbols: + return S.Zero + f, limits = self.function, list(self.limits) + limit = limits.pop(-1) + if limits: + f = self.func(f, *limits) + i, a, b = limit + if x in a.free_symbols or x in b.free_symbols: + return None + h = Dummy() + rv = Sum( Product(f, (i, a, h - 1)) * Product(f, (i, h + 1, b)) * Derivative(f, x, evaluate=True).subs(i, h), (h, a, b)) + return rv + + def is_convergent(self): + r""" + See docs of :obj:`.Sum.is_convergent()` for explanation of convergence + in SymPy. + + Explanation + =========== + + The infinite product: + + .. math:: + + \prod_{1 \leq i < \infty} f(i) + + is defined by the sequence of partial products: + + .. math:: + + \prod_{i=1}^{n} f(i) = f(1) f(2) \cdots f(n) + + as n increases without bound. The product converges to a non-zero + value if and only if the sum: + + .. math:: + + \sum_{1 \leq i < \infty} \log{f(n)} + + converges. + + Examples + ======== + + >>> from sympy import Product, Symbol, cos, pi, exp, oo + >>> n = Symbol('n', integer=True) + >>> Product(n/(n + 1), (n, 1, oo)).is_convergent() + False + >>> Product(1/n**2, (n, 1, oo)).is_convergent() + False + >>> Product(cos(pi/n), (n, 1, oo)).is_convergent() + True + >>> Product(exp(-n**2), (n, 1, oo)).is_convergent() + False + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Infinite_product + """ + sequence_term = self.function + log_sum = log(sequence_term) + lim = self.limits + try: + is_conv = Sum(log_sum, *lim).is_convergent() + except NotImplementedError: + if Sum(sequence_term - 1, *lim).is_absolutely_convergent() is S.true: + return S.true + raise NotImplementedError("The algorithm to find the product convergence of %s " + "is not yet implemented" % (sequence_term)) + return is_conv + + def reverse_order(expr, *indices): + """ + Reverse the order of a limit in a Product. + + Explanation + =========== + + ``reverse_order(expr, *indices)`` reverses some limits in the expression + ``expr`` which can be either a ``Sum`` or a ``Product``. The selectors in + the argument ``indices`` specify some indices whose limits get reversed. + These selectors are either variable names or numerical indices counted + starting from the inner-most limit tuple. + + Examples + ======== + + >>> from sympy import gamma, Product, simplify, Sum + >>> from sympy.abc import x, y, a, b, c, d + >>> P = Product(x, (x, a, b)) + >>> Pr = P.reverse_order(x) + >>> Pr + Product(1/x, (x, b + 1, a - 1)) + >>> Pr = Pr.doit() + >>> Pr + 1/RisingFactorial(b + 1, a - b - 1) + >>> simplify(Pr.rewrite(gamma)) + Piecewise((gamma(b + 1)/gamma(a), b > -1), ((-1)**(-a + b + 1)*gamma(1 - a)/gamma(-b), True)) + >>> P = P.doit() + >>> P + RisingFactorial(a, -a + b + 1) + >>> simplify(P.rewrite(gamma)) + Piecewise((gamma(b + 1)/gamma(a), a > 0), ((-1)**(-a + b + 1)*gamma(1 - a)/gamma(-b), True)) + + While one should prefer variable names when specifying which limits + to reverse, the index counting notation comes in handy in case there + are several symbols with the same name. + + >>> S = Sum(x*y, (x, a, b), (y, c, d)) + >>> S + Sum(x*y, (x, a, b), (y, c, d)) + >>> S0 = S.reverse_order(0) + >>> S0 + Sum(-x*y, (x, b + 1, a - 1), (y, c, d)) + >>> S1 = S0.reverse_order(1) + >>> S1 + Sum(x*y, (x, b + 1, a - 1), (y, d + 1, c - 1)) + + Of course we can mix both notations: + + >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(x, 1) + Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) + >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(y, x) + Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) + + See Also + ======== + + sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index, + reorder_limit, + sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder + + References + ========== + + .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, + Volume 28 Issue 2, April 1981, Pages 305-350 + https://dl.acm.org/doi/10.1145/322248.322255 + + """ + l_indices = list(indices) + + for i, indx in enumerate(l_indices): + if not isinstance(indx, int): + l_indices[i] = expr.index(indx) + + e = 1 + limits = [] + for i, limit in enumerate(expr.limits): + l = limit + if i in l_indices: + e = -e + l = (limit[0], limit[2] + 1, limit[1] - 1) + limits.append(l) + + return Product(expr.function ** e, *limits) + + +def product(*args, **kwargs): + r""" + Compute the product. + + Explanation + =========== + + The notation for symbols is similar to the notation used in Sum or + Integral. product(f, (i, a, b)) computes the product of f with + respect to i from a to b, i.e., + + :: + + b + _____ + product(f(n), (i, a, b)) = | | f(n) + | | + i = a + + If it cannot compute the product, it returns an unevaluated Product object. + Repeated products can be computed by introducing additional symbols tuples:: + + Examples + ======== + + >>> from sympy import product, symbols + >>> i, n, m, k = symbols('i n m k', integer=True) + + >>> product(i, (i, 1, k)) + factorial(k) + >>> product(m, (i, 1, k)) + m**k + >>> product(i, (i, 1, k), (k, 1, n)) + Product(factorial(k), (k, 1, n)) + + """ + + prod = Product(*args, **kwargs) + + if isinstance(prod, Product): + return prod.doit(deep=False) + else: + return prod diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/summations.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/summations.py new file mode 100644 index 0000000000000000000000000000000000000000..96bdbd69b7820798fade4bc5ec145172b95947ef --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/concrete/summations.py @@ -0,0 +1,1659 @@ +from __future__ import annotations + +from sympy.calculus.singularities import is_decreasing +from sympy.calculus.accumulationbounds import AccumulationBounds +from .expr_with_intlimits import ExprWithIntLimits +from .expr_with_limits import AddWithLimits +from .gosper import gosper_sum +from sympy.core.expr import Expr +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.function import Derivative, expand +from sympy.core.mul import Mul +from sympy.core.numbers import Float, _illegal +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy, Wild, Symbol, symbols +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.combinatorial.numbers import bernoulli, harmonic +from sympy.functions.elementary.complexes import re +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import cot, csc +from sympy.functions.special.hyper import hyper +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.functions.special.zeta_functions import zeta +from sympy.integrals.integrals import Integral +from sympy.logic.boolalg import And, Not +from sympy.polys.partfrac import apart +from sympy.polys.polyerrors import PolynomialError, PolificationFailed +from sympy.polys.polytools import parallel_poly_from_expr, Poly, factor +from sympy.polys.rationaltools import together +from sympy.series.limitseq import limit_seq +from sympy.series.order import O +from sympy.series.residues import residue +from sympy.sets.contains import Contains +from sympy.sets.sets import FiniteSet, Interval +from sympy.utilities.iterables import sift +import itertools + + +class Sum(AddWithLimits, ExprWithIntLimits): + r""" + Represents unevaluated summation. + + Explanation + =========== + + ``Sum`` represents a finite or infinite series, with the first argument + being the general form of terms in the series, and the second argument + being ``(dummy_variable, start, end)``, with ``dummy_variable`` taking + all integer values from ``start`` through ``end``. In accordance with + long-standing mathematical convention, the end term is included in the + summation. + + Finite sums + =========== + + For finite sums (and sums with symbolic limits assumed to be finite) we + follow the summation convention described by Karr [1], especially + definition 3 of section 1.4. The sum: + + .. math:: + + \sum_{m \leq i < n} f(i) + + has *the obvious meaning* for `m < n`, namely: + + .. math:: + + \sum_{m \leq i < n} f(i) = f(m) + f(m+1) + \ldots + f(n-2) + f(n-1) + + with the upper limit value `f(n)` excluded. The sum over an empty set is + zero if and only if `m = n`: + + .. math:: + + \sum_{m \leq i < n} f(i) = 0 \quad \mathrm{for} \quad m = n + + Finally, for all other sums over empty sets we assume the following + definition: + + .. math:: + + \sum_{m \leq i < n} f(i) = - \sum_{n \leq i < m} f(i) \quad \mathrm{for} \quad m > n + + It is important to note that Karr defines all sums with the upper + limit being exclusive. This is in contrast to the usual mathematical notation, + but does not affect the summation convention. Indeed we have: + + .. math:: + + \sum_{m \leq i < n} f(i) = \sum_{i = m}^{n - 1} f(i) + + where the difference in notation is intentional to emphasize the meaning, + with limits typeset on the top being inclusive. + + Examples + ======== + + >>> from sympy.abc import i, k, m, n, x + >>> from sympy import Sum, factorial, oo, IndexedBase, Function + >>> Sum(k, (k, 1, m)) + Sum(k, (k, 1, m)) + >>> Sum(k, (k, 1, m)).doit() + m**2/2 + m/2 + >>> Sum(k**2, (k, 1, m)) + Sum(k**2, (k, 1, m)) + >>> Sum(k**2, (k, 1, m)).doit() + m**3/3 + m**2/2 + m/6 + >>> Sum(x**k, (k, 0, oo)) + Sum(x**k, (k, 0, oo)) + >>> Sum(x**k, (k, 0, oo)).doit() + Piecewise((1/(1 - x), Abs(x) < 1), (Sum(x**k, (k, 0, oo)), True)) + >>> Sum(x**k/factorial(k), (k, 0, oo)).doit() + exp(x) + + Here are examples to do summation with symbolic indices. You + can use either Function of IndexedBase classes: + + >>> f = Function('f') + >>> Sum(f(n), (n, 0, 3)).doit() + f(0) + f(1) + f(2) + f(3) + >>> Sum(f(n), (n, 0, oo)).doit() + Sum(f(n), (n, 0, oo)) + >>> f = IndexedBase('f') + >>> Sum(f[n]**2, (n, 0, 3)).doit() + f[0]**2 + f[1]**2 + f[2]**2 + f[3]**2 + + An example showing that the symbolic result of a summation is still + valid for seemingly nonsensical values of the limits. Then the Karr + convention allows us to give a perfectly valid interpretation to + those sums by interchanging the limits according to the above rules: + + >>> S = Sum(i, (i, 1, n)).doit() + >>> S + n**2/2 + n/2 + >>> S.subs(n, -4) + 6 + >>> Sum(i, (i, 1, -4)).doit() + 6 + >>> Sum(-i, (i, -3, 0)).doit() + 6 + + An explicit example of the Karr summation convention: + + >>> S1 = Sum(i**2, (i, m, m+n-1)).doit() + >>> S1 + m**2*n + m*n**2 - m*n + n**3/3 - n**2/2 + n/6 + >>> S2 = Sum(i**2, (i, m+n, m-1)).doit() + >>> S2 + -m**2*n - m*n**2 + m*n - n**3/3 + n**2/2 - n/6 + >>> S1 + S2 + 0 + >>> S3 = Sum(i, (i, m, m-1)).doit() + >>> S3 + 0 + + See Also + ======== + + summation + Product, sympy.concrete.products.product + + References + ========== + + .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, + Volume 28 Issue 2, April 1981, Pages 305-350 + https://dl.acm.org/doi/10.1145/322248.322255 + .. [2] https://en.wikipedia.org/wiki/Summation#Capital-sigma_notation + .. [3] https://en.wikipedia.org/wiki/Empty_sum + """ + + __slots__ = () + + limits: tuple[tuple[Symbol, Expr, Expr]] + + def __new__(cls, function, *symbols, **assumptions): + obj = AddWithLimits.__new__(cls, function, *symbols, **assumptions) + if not hasattr(obj, 'limits'): + return obj + if any(len(l) != 3 or None in l for l in obj.limits): + raise ValueError('Sum requires values for lower and upper bounds.') + + return obj + + def _eval_is_zero(self): + # a Sum is only zero if its function is zero or if all terms + # cancel out. This only answers whether the summand is zero; if + # not then None is returned since we don't analyze whether all + # terms cancel out. + if self.function.is_zero or self.has_empty_sequence: + return True + + def _eval_is_extended_real(self): + if self.has_empty_sequence: + return True + return self.function.is_extended_real + + def _eval_is_positive(self): + if self.has_finite_limits and self.has_reversed_limits is False: + return self.function.is_positive + + def _eval_is_negative(self): + if self.has_finite_limits and self.has_reversed_limits is False: + return self.function.is_negative + + def _eval_is_finite(self): + if self.has_finite_limits and self.function.is_finite: + return True + + def doit(self, **hints): + if hints.get('deep', True): + f = self.function.doit(**hints) + else: + f = self.function + + # first make sure any definite limits have summation + # variables with matching assumptions + reps = {} + for xab in self.limits: + d = _dummy_with_inherited_properties_concrete(xab) + if d: + reps[xab[0]] = d + if reps: + undo = {v: k for k, v in reps.items()} + did = self.xreplace(reps).doit(**hints) + if isinstance(did, tuple): # when separate=True + did = tuple([i.xreplace(undo) for i in did]) + elif did is not None: + did = did.xreplace(undo) + else: + did = self + return did + + + if self.function.is_Matrix: + expanded = self.expand() + if self != expanded: + return expanded.doit() + return _eval_matrix_sum(self) + + for n, limit in enumerate(self.limits): + i, a, b = limit + dif = b - a + if dif == -1: + # Any summation over an empty set is zero + return S.Zero + if dif.is_integer and dif.is_negative: + a, b = b + 1, a - 1 + f = -f + + newf = eval_sum(f, (i, a, b)) + if newf is None: + if f == self.function: + zeta_function = self.eval_zeta_function(f, (i, a, b)) + if zeta_function is not None: + return zeta_function + return self + else: + return self.func(f, *self.limits[n:]) + f = newf + + if hints.get('deep', True): + # eval_sum could return partially unevaluated + # result with Piecewise. In this case we won't + # doit() recursively. + if not isinstance(f, Piecewise): + return f.doit(**hints) + + return f + + def eval_zeta_function(self, f, limits): + """ + Check whether the function matches with the zeta function. + + If it matches, then return a `Piecewise` expression because + zeta function does not converge unless `s > 1` and `q > 0` + """ + i, a, b = limits + if a.is_comparable and b.is_comparable and a > b: + return self.eval_zeta_function(f, (i, b + S.One, a - S.One)) + if b is not S.Infinity: + return + w, y, z = Wild('w', exclude=[i]), Wild('y', exclude=[i]), Wild('z', exclude=[i]) + if result := f.match((w * i + y) ** (-z)): + coeff = 1 / result[w] ** result[z] + s = result[z] + q = result[y] / result[w] + a + return Piecewise((coeff * zeta(s, q), + And(Not(Contains(-q, S.Naturals0)), re(s) > S.One)), + (self, True)) + + def _eval_derivative(self, x): + """ + Differentiate wrt x as long as x is not in the free symbols of any of + the upper or lower limits. + + Explanation + =========== + + Sum(a*b*x, (x, 1, a)) can be differentiated wrt x or b but not `a` + since the value of the sum is discontinuous in `a`. In a case + involving a limit variable, the unevaluated derivative is returned. + """ + + # diff already confirmed that x is in the free symbols of self, but we + # don't want to differentiate wrt any free symbol in the upper or lower + # limits + # XXX remove this test for free_symbols when the default _eval_derivative is in + if isinstance(x, Symbol) and x not in self.free_symbols: + return S.Zero + + # get limits and the function + f, limits = self.function, list(self.limits) + + limit = limits.pop(-1) + + if limits: # f is the argument to a Sum + f = self.func(f, *limits) + + _, a, b = limit + if x in a.free_symbols or x in b.free_symbols: + return None + df = Derivative(f, x, evaluate=True) + rv = self.func(df, limit) + return rv + + def _eval_difference_delta(self, n, step): + k, _, upper = self.args[-1] + new_upper = upper.subs(n, n + step) + + if len(self.args) == 2: + f = self.args[0] + else: + f = self.func(*self.args[:-1]) + + return Sum(f, (k, upper + 1, new_upper)).doit() + + def _eval_simplify(self, **kwargs): + + function = self.function + + if kwargs.get('deep', True): + function = function.simplify(**kwargs) + + # split the function into adds + terms = Add.make_args(expand(function)) + s_t = [] # Sum Terms + o_t = [] # Other Terms + + for term in terms: + if term.has(Sum): + # if there is an embedded sum here + # it is of the form x * (Sum(whatever)) + # hence we make a Mul out of it, and simplify all interior sum terms + subterms = Mul.make_args(expand(term)) + out_terms = [] + for subterm in subterms: + # go through each term + if isinstance(subterm, Sum): + # if it's a sum, simplify it + out_terms.append(subterm._eval_simplify(**kwargs)) + else: + # otherwise, add it as is + out_terms.append(subterm) + + # turn it back into a Mul + s_t.append(Mul(*out_terms)) + else: + o_t.append(term) + + # next try to combine any interior sums for further simplification + from sympy.simplify.simplify import factor_sum, sum_combine + result = Add(sum_combine(s_t), *o_t) + + return factor_sum(result, limits=self.limits) + + def is_convergent(self): + r""" + Checks for the convergence of a Sum. + + Explanation + =========== + + We divide the study of convergence of infinite sums and products in + two parts. + + First Part: + One part is the question whether all the terms are well defined, i.e., + they are finite in a sum and also non-zero in a product. Zero + is the analogy of (minus) infinity in products as + :math:`e^{-\infty} = 0`. + + Second Part: + The second part is the question of convergence after infinities, + and zeros in products, have been omitted assuming that their number + is finite. This means that we only consider the tail of the sum or + product, starting from some point after which all terms are well + defined. + + For example, in a sum of the form: + + .. math:: + + \sum_{1 \leq i < \infty} \frac{1}{n^2 + an + b} + + where a and b are numbers. The routine will return true, even if there + are infinities in the term sequence (at most two). An analogous + product would be: + + .. math:: + + \prod_{1 \leq i < \infty} e^{\frac{1}{n^2 + an + b}} + + This is how convergence is interpreted. It is concerned with what + happens at the limit. Finding the bad terms is another independent + matter. + + Note: It is responsibility of user to see that the sum or product + is well defined. + + There are various tests employed to check the convergence like + divergence test, root test, integral test, alternating series test, + comparison tests, Dirichlet tests. It returns true if Sum is convergent + and false if divergent and NotImplementedError if it cannot be checked. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Convergence_tests + + Examples + ======== + + >>> from sympy import factorial, S, Sum, Symbol, oo + >>> n = Symbol('n', integer=True) + >>> Sum(n/(n - 1), (n, 4, 7)).is_convergent() + True + >>> Sum(n/(2*n + 1), (n, 1, oo)).is_convergent() + False + >>> Sum(factorial(n)/5**n, (n, 1, oo)).is_convergent() + False + >>> Sum(1/n**(S(6)/5), (n, 1, oo)).is_convergent() + True + + See Also + ======== + + Sum.is_absolutely_convergent + sympy.concrete.products.Product.is_convergent + """ + p, q, r = symbols('p q r', cls=Wild) + + sym = self.limits[0][0] + lower_limit = self.limits[0][1] + upper_limit = self.limits[0][2] + sequence_term = self.function.simplify() + + if len(sequence_term.free_symbols) > 1: + raise NotImplementedError("convergence checking for more than one symbol " + "containing series is not handled") + + if lower_limit.is_finite and upper_limit.is_finite: + return S.true + + # transform sym -> -sym and swap the upper_limit = S.Infinity + # and lower_limit = - upper_limit + if lower_limit is S.NegativeInfinity: + if upper_limit is S.Infinity: + return Sum(sequence_term, (sym, 0, S.Infinity)).is_convergent() and \ + Sum(sequence_term, (sym, S.NegativeInfinity, 0)).is_convergent() + from sympy.simplify.simplify import simplify + sequence_term = simplify(sequence_term.xreplace({sym: -sym})) + lower_limit = -upper_limit + upper_limit = S.Infinity + + sym_ = Dummy(sym.name, integer=True, positive=True) + sequence_term = sequence_term.xreplace({sym: sym_}) + sym = sym_ + + interval = Interval(lower_limit, upper_limit) + + # Piecewise function handle + if sequence_term.is_Piecewise: + for func, cond in sequence_term.args: + # see if it represents something going to oo + if cond == True or cond.as_set().sup is S.Infinity: + s = Sum(func, (sym, lower_limit, upper_limit)) + return s.is_convergent() + return S.true + + ### -------- Divergence test ----------- ### + try: + lim_val = limit_seq(sequence_term, sym) + if lim_val is not None and lim_val.is_zero is False: + return S.false + except NotImplementedError: + pass + + try: + lim_val_abs = limit_seq(abs(sequence_term), sym) + if lim_val_abs is not None and lim_val_abs.is_zero is False: + return S.false + except NotImplementedError: + pass + + order = O(sequence_term, (sym, S.Infinity)) + + ### --------- p-series test (1/n**p) ---------- ### + p_series_test = order.expr.match(sym**p) + if p_series_test is not None: + if p_series_test[p] < -1: + return S.true + if p_series_test[p] >= -1: + return S.false + + ### ------------- comparison test ------------- ### + # 1/(n**p*log(n)**q*log(log(n))**r) comparison + n_log_test = (order.expr.match(1/(sym**p*log(1/sym)**q*log(-log(1/sym))**r)) or + order.expr.match(1/(sym**p*(-log(1/sym))**q*log(-log(1/sym))**r))) + if n_log_test is not None: + if (n_log_test[p] > 1 or + (n_log_test[p] == 1 and n_log_test[q] > 1) or + (n_log_test[p] == n_log_test[q] == 1 and n_log_test[r] > 1)): + return S.true + return S.false + + ### ------------- Limit comparison test -----------### + # (1/n) comparison + try: + lim_comp = limit_seq(sym*sequence_term, sym) + if lim_comp is not None and lim_comp.is_number and lim_comp > 0: + return S.false + except NotImplementedError: + pass + + ### ----------- ratio test ---------------- ### + next_sequence_term = sequence_term.xreplace({sym: sym + 1}) + from sympy.simplify.combsimp import combsimp + from sympy.simplify.powsimp import powsimp + ratio = combsimp(powsimp(next_sequence_term/sequence_term)) + try: + lim_ratio = limit_seq(ratio, sym) + if lim_ratio is not None and lim_ratio.is_number and lim_ratio is not S.NaN: + if abs(lim_ratio) > 1: + return S.false + if abs(lim_ratio) < 1: + return S.true + except NotImplementedError: + lim_ratio = None + + ### ---------- Raabe's test -------------- ### + if lim_ratio == 1: # ratio test inconclusive + test_val = sym*(sequence_term/ + sequence_term.subs(sym, sym + 1) - 1) + test_val = test_val.gammasimp() + try: + lim_val = limit_seq(test_val, sym) + if lim_val is not None and lim_val.is_number: + if lim_val > 1: + return S.true + if lim_val < 1: + return S.false + except NotImplementedError: + pass + + ### ----------- root test ---------------- ### + # lim = Limit(abs(sequence_term)**(1/sym), sym, S.Infinity) + try: + lim_evaluated = limit_seq(abs(sequence_term)**(1/sym), sym) + if lim_evaluated is not None and lim_evaluated.is_number: + if lim_evaluated < 1: + return S.true + if lim_evaluated > 1: + return S.false + except NotImplementedError: + pass + + ### ------------- alternating series test ----------- ### + dict_val = sequence_term.match(S.NegativeOne**(sym + p)*q) + if not dict_val[p].has(sym) and is_decreasing(dict_val[q], interval): + return S.true + + ### ------------- integral test -------------- ### + check_interval = None + from sympy.solvers.solveset import solveset + maxima = solveset(sequence_term.diff(sym), sym, interval) + if not maxima: + check_interval = interval + elif isinstance(maxima, FiniteSet) and maxima.sup.is_number: + check_interval = Interval(maxima.sup, interval.sup) + if (check_interval is not None and + (is_decreasing(sequence_term, check_interval) or + is_decreasing(-sequence_term, check_interval))): + integral_val = Integral( + sequence_term, (sym, lower_limit, upper_limit)) + try: + integral_val_evaluated = integral_val.doit() + if integral_val_evaluated.is_number: + return S(integral_val_evaluated.is_finite) + except NotImplementedError: + pass + + ### ----- Dirichlet and bounded times convergent tests ----- ### + # TODO + # + # Dirichlet_test + # https://en.wikipedia.org/wiki/Dirichlet%27s_test + # + # Bounded times convergent test + # It is based on comparison theorems for series. + # In particular, if the general term of a series can + # be written as a product of two terms a_n and b_n + # and if a_n is bounded and if Sum(b_n) is absolutely + # convergent, then the original series Sum(a_n * b_n) + # is absolutely convergent and so convergent. + # + # The following code can grows like 2**n where n is the + # number of args in order.expr + # Possibly combined with the potentially slow checks + # inside the loop, could make this test extremely slow + # for larger summation expressions. + + if order.expr.is_Mul: + args = order.expr.args + argset = set(args) + + ### -------------- Dirichlet tests -------------- ### + m = Dummy('m', integer=True) + def _dirichlet_test(g_n): + try: + ing_val = limit_seq(Sum(g_n, (sym, interval.inf, m)).doit(), m) + if ing_val is not None and ing_val.is_finite: + return S.true + except NotImplementedError: + pass + + ### -------- bounded times convergent test ---------### + def _bounded_convergent_test(g1_n, g2_n): + try: + lim_val = limit_seq(g1_n, sym) + if lim_val is not None and (lim_val.is_finite or ( + isinstance(lim_val, AccumulationBounds) + and (lim_val.max - lim_val.min).is_finite)): + if Sum(g2_n, (sym, lower_limit, upper_limit)).is_absolutely_convergent(): + return S.true + except NotImplementedError: + pass + + for n in range(1, len(argset)): + for a_tuple in itertools.combinations(args, n): + b_set = argset - set(a_tuple) + a_n = Mul(*a_tuple) + b_n = Mul(*b_set) + + if is_decreasing(a_n, interval): + dirich = _dirichlet_test(b_n) + if dirich is not None: + return dirich + + bc_test = _bounded_convergent_test(a_n, b_n) + if bc_test is not None: + return bc_test + + _sym = self.limits[0][0] + sequence_term = sequence_term.xreplace({sym: _sym}) + raise NotImplementedError("The algorithm to find the Sum convergence of %s " + "is not yet implemented" % (sequence_term)) + + def is_absolutely_convergent(self): + """ + Checks for the absolute convergence of an infinite series. + + Same as checking convergence of absolute value of sequence_term of + an infinite series. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Absolute_convergence + + Examples + ======== + + >>> from sympy import Sum, Symbol, oo + >>> n = Symbol('n', integer=True) + >>> Sum((-1)**n, (n, 1, oo)).is_absolutely_convergent() + False + >>> Sum((-1)**n/n**2, (n, 1, oo)).is_absolutely_convergent() + True + + See Also + ======== + + Sum.is_convergent + """ + return Sum(abs(self.function), self.limits).is_convergent() + + def euler_maclaurin(self, m=0, n=0, eps=0, eval_integral=True): + """ + Return an Euler-Maclaurin approximation of self, where m is the + number of leading terms to sum directly and n is the number of + terms in the tail. + + With m = n = 0, this is simply the corresponding integral + plus a first-order endpoint correction. + + Returns (s, e) where s is the Euler-Maclaurin approximation + and e is the estimated error (taken to be the magnitude of + the first omitted term in the tail): + + >>> from sympy.abc import k, a, b + >>> from sympy import Sum + >>> Sum(1/k, (k, 2, 5)).doit().evalf() + 1.28333333333333 + >>> s, e = Sum(1/k, (k, 2, 5)).euler_maclaurin() + >>> s + -log(2) + 7/20 + log(5) + >>> from sympy import sstr + >>> print(sstr((s.evalf(), e.evalf()), full_prec=True)) + (1.26629073187415, 0.0175000000000000) + + The endpoints may be symbolic: + + >>> s, e = Sum(1/k, (k, a, b)).euler_maclaurin() + >>> s + -log(a) + log(b) + 1/(2*b) + 1/(2*a) + >>> e + Abs(1/(12*b**2) - 1/(12*a**2)) + + If the function is a polynomial of degree at most 2n+1, the + Euler-Maclaurin formula becomes exact (and e = 0 is returned): + + >>> Sum(k, (k, 2, b)).euler_maclaurin() + (b**2/2 + b/2 - 1, 0) + >>> Sum(k, (k, 2, b)).doit() + b**2/2 + b/2 - 1 + + With a nonzero eps specified, the summation is ended + as soon as the remainder term is less than the epsilon. + """ + m = int(m) + n = int(n) + f = self.function + if len(self.limits) != 1: + raise ValueError("More than 1 limit") + i, a, b = self.limits[0] + if (a > b) == True: + if a - b == 1: + return S.Zero, S.Zero + a, b = b + 1, a - 1 + f = -f + s = S.Zero + if m: + if b.is_Integer and a.is_Integer: + m = min(m, b - a + 1) + if not eps or f.is_polynomial(i): + s = Add(*[f.subs(i, a + k) for k in range(m)]) + else: + term = f.subs(i, a) + if term: + test = abs(term.evalf(3)) < eps + if test == True: + return s, abs(term) + elif not (test == False): + # a symbolic Relational class, can't go further + return term, S.Zero + s = term + for k in range(1, m): + term = f.subs(i, a + k) + if abs(term.evalf(3)) < eps and term != 0: + return s, abs(term) + s += term + if b - a + 1 == m: + return s, S.Zero + a += m + x = Dummy('x') + I = Integral(f.subs(i, x), (x, a, b)) + if eval_integral: + I = I.doit() + s += I + + def fpoint(expr): + if b is S.Infinity: + return expr.subs(i, a), 0 + return expr.subs(i, a), expr.subs(i, b) + fa, fb = fpoint(f) + iterm = (fa + fb)/2 + g = f.diff(i) + for k in range(1, n + 2): + ga, gb = fpoint(g) + term = bernoulli(2*k)/factorial(2*k)*(gb - ga) + if k > n: + break + if eps and term: + term_evalf = term.evalf(3) + if term_evalf is S.NaN: + return S.NaN, S.NaN + if abs(term_evalf) < eps: + break + s += term + g = g.diff(i, 2, simplify=False) + return s + iterm, abs(term) + + + def reverse_order(self, *indices): + """ + Reverse the order of a limit in a Sum. + + Explanation + =========== + + ``reverse_order(self, *indices)`` reverses some limits in the expression + ``self`` which can be either a ``Sum`` or a ``Product``. The selectors in + the argument ``indices`` specify some indices whose limits get reversed. + These selectors are either variable names or numerical indices counted + starting from the inner-most limit tuple. + + Examples + ======== + + >>> from sympy import Sum + >>> from sympy.abc import x, y, a, b, c, d + + >>> Sum(x, (x, 0, 3)).reverse_order(x) + Sum(-x, (x, 4, -1)) + >>> Sum(x*y, (x, 1, 5), (y, 0, 6)).reverse_order(x, y) + Sum(x*y, (x, 6, 0), (y, 7, -1)) + >>> Sum(x, (x, a, b)).reverse_order(x) + Sum(-x, (x, b + 1, a - 1)) + >>> Sum(x, (x, a, b)).reverse_order(0) + Sum(-x, (x, b + 1, a - 1)) + + While one should prefer variable names when specifying which limits + to reverse, the index counting notation comes in handy in case there + are several symbols with the same name. + + >>> S = Sum(x**2, (x, a, b), (x, c, d)) + >>> S + Sum(x**2, (x, a, b), (x, c, d)) + >>> S0 = S.reverse_order(0) + >>> S0 + Sum(-x**2, (x, b + 1, a - 1), (x, c, d)) + >>> S1 = S0.reverse_order(1) + >>> S1 + Sum(x**2, (x, b + 1, a - 1), (x, d + 1, c - 1)) + + Of course we can mix both notations: + + >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(x, 1) + Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) + >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(y, x) + Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) + + See Also + ======== + + sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index, reorder_limit, + sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder + + References + ========== + + .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, + Volume 28 Issue 2, April 1981, Pages 305-350 + https://dl.acm.org/doi/10.1145/322248.322255 + """ + l_indices = list(indices) + + for i, indx in enumerate(l_indices): + if not isinstance(indx, int): + l_indices[i] = self.index(indx) + + e = 1 + limits = [] + for i, limit in enumerate(self.limits): + l = limit + if i in l_indices: + e = -e + l = (limit[0], limit[2] + 1, limit[1] - 1) + limits.append(l) + + return Sum(e * self.function, *limits) + + def _eval_rewrite_as_Product(self, *args, **kwargs): + from sympy.concrete.products import Product + if self.function.is_extended_real: + return log(Product(exp(self.function), *self.limits)) + + +def summation(f, *symbols, **kwargs): + r""" + Compute the summation of f with respect to symbols. + + Explanation + =========== + + The notation for symbols is similar to the notation used in Integral. + summation(f, (i, a, b)) computes the sum of f with respect to i from a to b, + i.e., + + :: + + b + ____ + \ ` + summation(f, (i, a, b)) = ) f + /___, + i = a + + If it cannot compute the sum, it returns an unevaluated Sum object. + Repeated sums can be computed by introducing additional symbols tuples:: + + Examples + ======== + + >>> from sympy import summation, oo, symbols, log + >>> i, n, m = symbols('i n m', integer=True) + + >>> summation(2*i - 1, (i, 1, n)) + n**2 + >>> summation(1/2**i, (i, 0, oo)) + 2 + >>> summation(1/log(n)**n, (n, 2, oo)) + Sum(log(n)**(-n), (n, 2, oo)) + >>> summation(i, (i, 0, n), (n, 0, m)) + m**3/6 + m**2/2 + m/3 + + >>> from sympy.abc import x + >>> from sympy import factorial + >>> summation(x**n/factorial(n), (n, 0, oo)) + exp(x) + + See Also + ======== + + Sum + Product, sympy.concrete.products.product + + """ + return Sum(f, *symbols, **kwargs).doit(deep=False) + + +def telescopic_direct(L, R, n, limits): + """ + Returns the direct summation of the terms of a telescopic sum + + Explanation + =========== + + L is the term with lower index + R is the term with higher index + n difference between the indexes of L and R + + Examples + ======== + + >>> from sympy.concrete.summations import telescopic_direct + >>> from sympy.abc import k, a, b + >>> telescopic_direct(1/k, -1/(k+2), 2, (k, a, b)) + -1/(b + 2) - 1/(b + 1) + 1/(a + 1) + 1/a + + """ + (i, a, b) = limits + return Add(*[L.subs(i, a + m) + R.subs(i, b - m) for m in range(n)]) + + +def telescopic(L, R, limits): + ''' + Tries to perform the summation using the telescopic property. + + Return None if not possible. + ''' + (i, a, b) = limits + if L.is_Add or R.is_Add: + return None + + # We want to solve(L.subs(i, i + m) + R, m) + # First we try a simple match since this does things that + # solve doesn't do, e.g. solve(cos(k+m)-cos(k), m) gives + # a more complicated solution than m == 0. + + k = Wild("k") + sol = (-R).match(L.subs(i, i + k)) + s = None + if sol and k in sol: + s = sol[k] + if not (s.is_Integer and L.subs(i, i + s) + R == 0): + # invalid match or match didn't work + s = None + + # But there are things that match doesn't do that solve + # can do, e.g. determine that 1/(x + m) = 1/(1 - x) when m = 1 + + if s is None: + m = Dummy('m') + try: + from sympy.solvers.solvers import solve + sol = solve(L.subs(i, i + m) + R, m) or [] + except NotImplementedError: + return None + sol = [si for si in sol if si.is_Integer and + (L.subs(i, i + si) + R).expand().is_zero] + if len(sol) != 1: + return None + s = sol[0] + + if s < 0: + return telescopic_direct(R, L, abs(s), (i, a, b)) + elif s > 0: + return telescopic_direct(L, R, s, (i, a, b)) + + +def eval_sum(f, limits): + (i, a, b) = limits + if f.is_zero: + return S.Zero + if i not in f.free_symbols: + return f*(b - a + 1) + if a == b: + return f.subs(i, a) + if a.is_comparable and b.is_comparable and a > b: + return eval_sum(f, (i, b + S.One, a - S.One)) + if isinstance(f, Piecewise): + if not any(i in arg.args[1].free_symbols for arg in f.args): + # Piecewise conditions do not depend on the dummy summation variable, + # therefore we can fold: Sum(Piecewise((e, c), ...), limits) + # --> Piecewise((Sum(e, limits), c), ...) + newargs = [] + for arg in f.args: + newexpr = eval_sum(arg.expr, limits) + if newexpr is None: + return None + newargs.append((newexpr, arg.cond)) + return f.func(*newargs) + + if f.has(KroneckerDelta): + from .delta import deltasummation, _has_simple_delta + f = f.replace( + lambda x: isinstance(x, Sum), + lambda x: x.factor() + ) + if _has_simple_delta(f, limits[0]): + return deltasummation(f, limits) + + dif = b - a + definite = dif.is_Integer + # Doing it directly may be faster if there are very few terms. + if definite and (dif < 100): + return eval_sum_direct(f, (i, a, b)) + if isinstance(f, Piecewise): + return None + # Try to do it symbolically. Even when the number of terms is + # known, this can save time when b-a is big. + value = eval_sum_symbolic(f.expand(), (i, a, b)) + if value is not None: + return value + # Do it directly + if definite: + return eval_sum_direct(f, (i, a, b)) + + +def eval_sum_direct(expr, limits): + """ + Evaluate expression directly, but perform some simple checks first + to possibly result in a smaller expression and faster execution. + """ + (i, a, b) = limits + + dif = b - a + # Linearity + if expr.is_Mul: + # Try factor out everything not including i + without_i, with_i = expr.as_independent(i) + if without_i != 1: + s = eval_sum_direct(with_i, (i, a, b)) + if s: + r = without_i*s + if r is not S.NaN: + return r + else: + # Try term by term + L, R = expr.as_two_terms() + + if not L.has(i): + sR = eval_sum_direct(R, (i, a, b)) + if sR: + return L*sR + + if not R.has(i): + sL = eval_sum_direct(L, (i, a, b)) + if sL: + return sL*R + + # do this whether its an Add or Mul + # e.g. apart(1/(25*i**2 + 45*i + 14)) and + # apart(1/((5*i + 2)*(5*i + 7))) -> + # -1/(5*(5*i + 7)) + 1/(5*(5*i + 2)) + try: + expr = apart(expr, i) # see if it becomes an Add + except PolynomialError: + pass + + if expr.is_Add: + # Try factor out everything not including i + without_i, with_i = expr.as_independent(i) + if without_i != 0: + s = eval_sum_direct(with_i, (i, a, b)) + if s: + r = without_i*(dif + 1) + s + if r is not S.NaN: + return r + else: + # Try term by term + L, R = expr.as_two_terms() + lsum = eval_sum_direct(L, (i, a, b)) + rsum = eval_sum_direct(R, (i, a, b)) + + if None not in (lsum, rsum): + r = lsum + rsum + if r is not S.NaN: + return r + + return Add(*[expr.subs(i, a + j) for j in range(dif + 1)]) + + +def eval_sum_symbolic(f, limits): + f_orig = f + (i, a, b) = limits + if not f.has(i): + return f*(b - a + 1) + + # Linearity + if f.is_Mul: + # Try factor out everything not including i + without_i, with_i = f.as_independent(i) + if without_i != 1: + s = eval_sum_symbolic(with_i, (i, a, b)) + if s: + r = without_i*s + if r is not S.NaN: + return r + else: + # Try term by term + L, R = f.as_two_terms() + + if not L.has(i): + sR = eval_sum_symbolic(R, (i, a, b)) + if sR: + return L*sR + + if not R.has(i): + sL = eval_sum_symbolic(L, (i, a, b)) + if sL: + return sL*R + + # do this whether its an Add or Mul + # e.g. apart(1/(25*i**2 + 45*i + 14)) and + # apart(1/((5*i + 2)*(5*i + 7))) -> + # -1/(5*(5*i + 7)) + 1/(5*(5*i + 2)) + try: + f = apart(f, i) + except PolynomialError: + pass + + if f.is_Add: + L, R = f.as_two_terms() + lrsum = telescopic(L, R, (i, a, b)) + + if lrsum: + return lrsum + + # Try factor out everything not including i + without_i, with_i = f.as_independent(i) + if without_i != 0: + s = eval_sum_symbolic(with_i, (i, a, b)) + if s: + r = without_i*(b - a + 1) + s + if r is not S.NaN: + return r + else: + # Try term by term + lsum = eval_sum_symbolic(L, (i, a, b)) + rsum = eval_sum_symbolic(R, (i, a, b)) + + if None not in (lsum, rsum): + r = lsum + rsum + if r is not S.NaN: + return r + + + # Polynomial terms with Faulhaber's formula + n = Wild('n') + result = f.match(i**n) + + if result is not None: + n = result[n] + + if n.is_Integer: + if n >= 0: + if (b is S.Infinity and a is not S.NegativeInfinity) or \ + (a is S.NegativeInfinity and b is not S.Infinity): + return S.Infinity + return ((bernoulli(n + 1, b + 1) - bernoulli(n + 1, a))/(n + 1)).expand() + elif a.is_Integer and a >= 1: + if n == -1: + return harmonic(b) - harmonic(a - 1) + else: + return harmonic(b, abs(n)) - harmonic(a - 1, abs(n)) + + if not (a.has(S.Infinity, S.NegativeInfinity) or + b.has(S.Infinity, S.NegativeInfinity)): + # Geometric terms + c1 = Wild('c1', exclude=[i]) + c2 = Wild('c2', exclude=[i]) + c3 = Wild('c3', exclude=[i]) + wexp = Wild('wexp') + + # Here we first attempt powsimp on f for easier matching with the + # exponential pattern, and attempt expansion on the exponent for easier + # matching with the linear pattern. + e = f.powsimp().match(c1 ** wexp) + if e is not None: + e_exp = e.pop(wexp).expand().match(c2*i + c3) + if e_exp is not None: + e.update(e_exp) + + p = (c1**c3).subs(e) + q = (c1**c2).subs(e) + r = p*(q**a - q**(b + 1))/(1 - q) + l = p*(b - a + 1) + return Piecewise((l, Eq(q, S.One)), (r, True)) + + r = gosper_sum(f, (i, a, b)) + + if isinstance(r, (Mul,Add)): + from sympy.simplify.radsimp import denom + from sympy.solvers.solvers import solve + non_limit = r.free_symbols - Tuple(*limits[1:]).free_symbols + den = denom(together(r)) + den_sym = non_limit & den.free_symbols + args = [] + for v in ordered(den_sym): + try: + s = solve(den, v) + m = Eq(v, s[0]) if s else S.false + if m != False: + args.append((Sum(f_orig.subs(*m.args), limits).doit(), m)) + break + except NotImplementedError: + continue + + args.append((r, True)) + return Piecewise(*args) + + if r not in (None, S.NaN): + return r + + h = eval_sum_hyper(f_orig, (i, a, b)) + if h is not None: + return h + + r = eval_sum_residue(f_orig, (i, a, b)) + if r is not None: + return r + + factored = f_orig.factor() + if factored != f_orig: + return eval_sum_symbolic(factored, (i, a, b)) + + +def _eval_sum_hyper(f, i, a): + """ Returns (res, cond). Sums from a to oo. """ + if a != 0: + return _eval_sum_hyper(f.subs(i, i + a), i, 0) + + if f.subs(i, 0) == 0: + from sympy.simplify.simplify import simplify + if simplify(f.subs(i, Dummy('i', integer=True, positive=True))) == 0: + return S.Zero, True + return _eval_sum_hyper(f.subs(i, i + 1), i, 0) + + from sympy.simplify.simplify import hypersimp + hs = hypersimp(f, i) + if hs is None: + return None + + if isinstance(hs, Float): + from sympy.simplify.simplify import nsimplify + hs = nsimplify(hs) + + from sympy.simplify.combsimp import combsimp + from sympy.simplify.hyperexpand import hyperexpand + from sympy.simplify.radsimp import fraction + numer, denom = fraction(factor(hs)) + top, topl = numer.as_coeff_mul(i) + bot, botl = denom.as_coeff_mul(i) + ab = [top, bot] + factors = [topl, botl] + params = [[], []] + for k in range(2): + for fac in factors[k]: + mul = 1 + if fac.is_Pow: + mul = fac.exp + fac = fac.base + if not mul.is_Integer: + return None + p = Poly(fac, i) + if p.degree() != 1: + return None + m, n = p.all_coeffs() + ab[k] *= m**mul + params[k] += [n/m]*mul + + # Add "1" to numerator parameters, to account for implicit n! in + # hypergeometric series. + ap = params[0] + [1] + bq = params[1] + x = ab[0]/ab[1] + h = hyper(ap, bq, x) + f = combsimp(f) + return f.subs(i, 0)*hyperexpand(h), h.convergence_statement + + +def eval_sum_hyper(f, i_a_b): + i, a, b = i_a_b + + if f.is_hypergeometric(i) is False: + return + + if (b - a).is_Integer: + # We are never going to do better than doing the sum in the obvious way + return None + + old_sum = Sum(f, (i, a, b)) + + if b != S.Infinity: + if a is S.NegativeInfinity: + res = _eval_sum_hyper(f.subs(i, -i), i, -b) + if res is not None: + return Piecewise(res, (old_sum, True)) + else: + n_illegal = lambda x: sum(x.count(_) for _ in _illegal) + had = n_illegal(f) + # check that no extra illegals are introduced + res1 = _eval_sum_hyper(f, i, a) + if res1 is None or n_illegal(res1) > had: + return + res2 = _eval_sum_hyper(f, i, b + 1) + if res2 is None or n_illegal(res2) > had: + return + (res1, cond1), (res2, cond2) = res1, res2 + cond = And(cond1, cond2) + if cond == False: + return None + return Piecewise((res1 - res2, cond), (old_sum, True)) + + if a is S.NegativeInfinity: + res1 = _eval_sum_hyper(f.subs(i, -i), i, 1) + res2 = _eval_sum_hyper(f, i, 0) + if res1 is None or res2 is None: + return None + res1, cond1 = res1 + res2, cond2 = res2 + cond = And(cond1, cond2) + if cond == False or cond.as_set() == S.EmptySet: + return None + return Piecewise((res1 + res2, cond), (old_sum, True)) + + # Now b == oo, a != -oo + res = _eval_sum_hyper(f, i, a) + if res is not None: + r, c = res + if c == False: + if r.is_number: + f = f.subs(i, Dummy('i', integer=True, positive=True) + a) + if f.is_positive or f.is_zero: + return S.Infinity + elif f.is_negative: + return S.NegativeInfinity + return None + return Piecewise(res, (old_sum, True)) + + +def eval_sum_residue(f, i_a_b): + r"""Compute the infinite summation with residues + + Notes + ===== + + If $f(n), g(n)$ are polynomials with $\deg(g(n)) - \deg(f(n)) \ge 2$, + some infinite summations can be computed by the following residue + evaluations. + + .. math:: + \sum_{n=-\infty, g(n) \ne 0}^{\infty} \frac{f(n)}{g(n)} = + -\pi \sum_{\alpha|g(\alpha)=0} + \text{Res}(\cot(\pi x) \frac{f(x)}{g(x)}, \alpha) + + .. math:: + \sum_{n=-\infty, g(n) \ne 0}^{\infty} (-1)^n \frac{f(n)}{g(n)} = + -\pi \sum_{\alpha|g(\alpha)=0} + \text{Res}(\csc(\pi x) \frac{f(x)}{g(x)}, \alpha) + + Examples + ======== + + >>> from sympy import Sum, oo, Symbol + >>> x = Symbol('x') + + Doubly infinite series of rational functions. + + >>> Sum(1 / (x**2 + 1), (x, -oo, oo)).doit() + pi/tanh(pi) + + Doubly infinite alternating series of rational functions. + + >>> Sum((-1)**x / (x**2 + 1), (x, -oo, oo)).doit() + pi/sinh(pi) + + Infinite series of even rational functions. + + >>> Sum(1 / (x**2 + 1), (x, 0, oo)).doit() + 1/2 + pi/(2*tanh(pi)) + + Infinite series of alternating even rational functions. + + >>> Sum((-1)**x / (x**2 + 1), (x, 0, oo)).doit() + pi/(2*sinh(pi)) + 1/2 + + This also have heuristics to transform arbitrarily shifted summand or + arbitrarily shifted summation range to the canonical problem the + formula can handle. + + >>> Sum(1 / (x**2 + 2*x + 2), (x, -1, oo)).doit() + 1/2 + pi/(2*tanh(pi)) + >>> Sum(1 / (x**2 + 4*x + 5), (x, -2, oo)).doit() + 1/2 + pi/(2*tanh(pi)) + >>> Sum(1 / (x**2 + 1), (x, 1, oo)).doit() + -1/2 + pi/(2*tanh(pi)) + >>> Sum(1 / (x**2 + 1), (x, 2, oo)).doit() + -1 + pi/(2*tanh(pi)) + + References + ========== + + .. [#] http://www.supermath.info/InfiniteSeriesandtheResidueTheorem.pdf + + .. [#] Asmar N.H., Grafakos L. (2018) Residue Theory. + In: Complex Analysis with Applications. + Undergraduate Texts in Mathematics. Springer, Cham. + https://doi.org/10.1007/978-3-319-94063-2_5 + """ + i, a, b = i_a_b + + # If lower limit > upper limit: Karr Summation Convention + if a.is_comparable and b.is_comparable and a > b: + return eval_sum_residue(f, (i, b + S.One, a - S.One)) + + def is_even_function(numer, denom): + """Test if the rational function is an even function""" + numer_even = all(i % 2 == 0 for (i,) in numer.monoms()) + denom_even = all(i % 2 == 0 for (i,) in denom.monoms()) + numer_odd = all(i % 2 == 1 for (i,) in numer.monoms()) + denom_odd = all(i % 2 == 1 for (i,) in denom.monoms()) + return (numer_even and denom_even) or (numer_odd and denom_odd) + + def match_rational(f, i): + numer, denom = f.as_numer_denom() + try: + (numer, denom), opt = parallel_poly_from_expr((numer, denom), i) + except (PolificationFailed, PolynomialError): + return None + return numer, denom + + def get_poles(denom): + roots = denom.sqf_part().all_roots() + roots = sift(roots, lambda x: x.is_integer) + if None in roots: + return None + int_roots, nonint_roots = roots[True], roots[False] + return int_roots, nonint_roots + + def get_shift(denom): + n = denom.degree(i) + a = denom.coeff_monomial(i**n) + b = denom.coeff_monomial(i**(n-1)) + shift = - b / a / n + return shift + + #Need a dummy symbol with no assumptions set for get_residue_factor + z = Dummy('z') + + def get_residue_factor(numer, denom, alternating): + residue_factor = (numer.as_expr() / denom.as_expr()).subs(i, z) + if not alternating: + residue_factor *= cot(S.Pi * z) + else: + residue_factor *= csc(S.Pi * z) + return residue_factor + + # We don't know how to deal with symbolic constants in summand + if f.free_symbols - {i}: + return None + + if not (a.is_Integer or a in (S.Infinity, S.NegativeInfinity)): + return None + if not (b.is_Integer or b in (S.Infinity, S.NegativeInfinity)): + return None + + # Quick exit heuristic for the sums which doesn't have infinite range + if a != S.NegativeInfinity and b != S.Infinity: + return None + + match = match_rational(f, i) + if match: + alternating = False + numer, denom = match + else: + match = match_rational(f / S.NegativeOne**i, i) + if match: + alternating = True + numer, denom = match + else: + return None + + if denom.degree(i) - numer.degree(i) < 2: + return None + + if (a, b) == (S.NegativeInfinity, S.Infinity): + poles = get_poles(denom) + if poles is None: + return None + int_roots, nonint_roots = poles + + if int_roots: + return None + + residue_factor = get_residue_factor(numer, denom, alternating) + residues = [residue(residue_factor, z, root) for root in nonint_roots] + return -S.Pi * sum(residues) + + if not (a.is_finite and b is S.Infinity): + return None + + if not is_even_function(numer, denom): + # Try shifting summation and check if the summand can be made + # and even function from the origin. + # Sum(f(n), (n, a, b)) => Sum(f(n + s), (n, a - s, b - s)) + shift = get_shift(denom) + + if not shift.is_Integer: + return None + if shift == 0: + return None + + numer = numer.shift(shift) + denom = denom.shift(shift) + + if not is_even_function(numer, denom): + return None + + if alternating: + f = S.NegativeOne**i * (S.NegativeOne**shift * numer.as_expr() / denom.as_expr()) + else: + f = numer.as_expr() / denom.as_expr() + return eval_sum_residue(f, (i, a-shift, b-shift)) + + poles = get_poles(denom) + if poles is None: + return None + int_roots, nonint_roots = poles + + if int_roots: + int_roots = [int(root) for root in int_roots] + int_roots_max = max(int_roots) + int_roots_min = min(int_roots) + # Integer valued poles must be next to each other + # and also symmetric from origin (Because the function is even) + if not len(int_roots) == int_roots_max - int_roots_min + 1: + return None + + # Check whether the summation indices contain poles + if a <= max(int_roots): + return None + + residue_factor = get_residue_factor(numer, denom, alternating) + residues = [residue(residue_factor, z, root) for root in int_roots + nonint_roots] + full_sum = -S.Pi * sum(residues) + + if not int_roots: + # Compute Sum(f, (i, 0, oo)) by adding a extraneous evaluation + # at the origin. + half_sum = (full_sum + f.xreplace({i: 0})) / 2 + + # Add and subtract extraneous evaluations + extraneous_neg = [f.xreplace({i: i0}) for i0 in range(int(a), 0)] + extraneous_pos = [f.xreplace({i: i0}) for i0 in range(0, int(a))] + result = half_sum + sum(extraneous_neg) - sum(extraneous_pos) + + return result + + # Compute Sum(f, (i, min(poles) + 1, oo)) + half_sum = full_sum / 2 + + # Subtract extraneous evaluations + extraneous = [f.xreplace({i: i0}) for i0 in range(max(int_roots) + 1, int(a))] + result = half_sum - sum(extraneous) + + return result + + +def _eval_matrix_sum(expression): + f = expression.function + for limit in expression.limits: + i, a, b = limit + dif = b - a + if dif.is_Integer: + if (dif < 0) == True: + a, b = b + 1, a - 1 + f = -f + + newf = eval_sum_direct(f, (i, a, b)) + if newf is not None: + return newf.doit() + + +def _dummy_with_inherited_properties_concrete(limits): + """ + Return a Dummy symbol that inherits as many assumptions as possible + from the provided symbol and limits. + + If the symbol already has all True assumption shared by the limits + then return None. + """ + x, a, b = limits + l = [a, b] + + assumptions_to_consider = ['extended_nonnegative', 'nonnegative', + 'extended_nonpositive', 'nonpositive', + 'extended_positive', 'positive', + 'extended_negative', 'negative', + 'integer', 'rational', 'finite', + 'zero', 'real', 'extended_real'] + + assumptions_to_keep = {} + assumptions_to_add = {} + for assum in assumptions_to_consider: + assum_true = x._assumptions.get(assum, None) + if assum_true: + assumptions_to_keep[assum] = True + elif all(getattr(i, 'is_' + assum) for i in l): + assumptions_to_add[assum] = True + if assumptions_to_add: + assumptions_to_keep.update(assumptions_to_add) + return Dummy('d', **assumptions_to_keep) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4c03c9fc11479bb6d93a3bff3dfd0992ef994a19 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__init__.py @@ -0,0 +1,103 @@ +"""Core module. Provides the basic operations needed in sympy. +""" + +from .sympify import sympify, SympifyError +from .cache import cacheit +from .assumptions import assumptions, check_assumptions, failing_assumptions, common_assumptions +from .basic import Basic, Atom +from .singleton import S +from .expr import Expr, AtomicExpr, UnevaluatedExpr +from .symbol import Symbol, Wild, Dummy, symbols, var +from .numbers import Number, Float, Rational, Integer, NumberSymbol, \ + RealNumber, igcd, ilcm, seterr, E, I, nan, oo, pi, zoo, \ + AlgebraicNumber, comp, mod_inverse +from .power import Pow +from .intfunc import integer_nthroot, integer_log, num_digits, trailing +from .mul import Mul, prod +from .add import Add +from .mod import Mod +from .relational import ( Rel, Eq, Ne, Lt, Le, Gt, Ge, + Equality, GreaterThan, LessThan, Unequality, StrictGreaterThan, + StrictLessThan ) +from .multidimensional import vectorize +from .function import Lambda, WildFunction, Derivative, diff, FunctionClass, \ + Function, Subs, expand, PoleError, count_ops, \ + expand_mul, expand_log, expand_func, \ + expand_trig, expand_complex, expand_multinomial, nfloat, \ + expand_power_base, expand_power_exp, arity +from .evalf import PrecisionExhausted, N +from .containers import Tuple, Dict +from .exprtools import gcd_terms, factor_terms, factor_nc +from .parameters import evaluate +from .kind import UndefinedKind, NumberKind, BooleanKind +from .traversal import preorder_traversal, bottom_up, use, postorder_traversal +from .sorting import default_sort_key, ordered + +# expose singletons +Catalan = S.Catalan +EulerGamma = S.EulerGamma +GoldenRatio = S.GoldenRatio +TribonacciConstant = S.TribonacciConstant + +__all__ = [ + 'sympify', 'SympifyError', + + 'cacheit', + + 'assumptions', 'check_assumptions', 'failing_assumptions', + 'common_assumptions', + + 'Basic', 'Atom', + + 'S', + + 'Expr', 'AtomicExpr', 'UnevaluatedExpr', + + 'Symbol', 'Wild', 'Dummy', 'symbols', 'var', + + 'Number', 'Float', 'Rational', 'Integer', 'NumberSymbol', 'RealNumber', + 'igcd', 'ilcm', 'seterr', 'E', 'I', 'nan', 'oo', 'pi', 'zoo', + 'AlgebraicNumber', 'comp', 'mod_inverse', + + 'Pow', + + 'integer_nthroot', 'integer_log', 'num_digits', 'trailing', + + 'Mul', 'prod', + + 'Add', + + 'Mod', + + 'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', 'Equality', 'GreaterThan', + 'LessThan', 'Unequality', 'StrictGreaterThan', 'StrictLessThan', + + 'vectorize', + + 'Lambda', 'WildFunction', 'Derivative', 'diff', 'FunctionClass', + 'Function', 'Subs', 'expand', 'PoleError', 'count_ops', 'expand_mul', + 'expand_log', 'expand_func', 'expand_trig', 'expand_complex', + 'expand_multinomial', 'nfloat', 'expand_power_base', 'expand_power_exp', + 'arity', + + 'PrecisionExhausted', 'N', + + 'evalf', # The module? + + 'Tuple', 'Dict', + + 'gcd_terms', 'factor_terms', 'factor_nc', + + 'evaluate', + + 'Catalan', + 'EulerGamma', + 'GoldenRatio', + 'TribonacciConstant', + + 'UndefinedKind', 'NumberKind', 'BooleanKind', + + 'preorder_traversal', 'bottom_up', 'use', 'postorder_traversal', + + 'default_sort_key', 'ordered', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/_print_helpers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/_print_helpers.py new file mode 100644 index 0000000000000000000000000000000000000000..d704ed220d444e2d8510b280dca85c8ae6149d4c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/_print_helpers.py @@ -0,0 +1,65 @@ +""" +Base class to provide str and repr hooks that `init_printing` can overwrite. + +This is exposed publicly in the `printing.defaults` module, +but cannot be defined there without causing circular imports. +""" + +class Printable: + """ + The default implementation of printing for SymPy classes. + + This implements a hack that allows us to print elements of built-in + Python containers in a readable way. Natively Python uses ``repr()`` + even if ``str()`` was explicitly requested. Mix in this trait into + a class to get proper default printing. + + This also adds support for LaTeX printing in jupyter notebooks. + """ + + # Since this class is used as a mixin we set empty slots. That means that + # instances of any subclasses that use slots will not need to have a + # __dict__. + __slots__ = () + + # Note, we always use the default ordering (lex) in __str__ and __repr__, + # regardless of the global setting. See issue 5487. + def __str__(self): + from sympy.printing.str import sstr + return sstr(self, order=None) + + __repr__ = __str__ + + def _repr_disabled(self): + """ + No-op repr function used to disable jupyter display hooks. + + When :func:`sympy.init_printing` is used to disable certain display + formats, this function is copied into the appropriate ``_repr_*_`` + attributes. + + While we could just set the attributes to `None``, doing it this way + allows derived classes to call `super()`. + """ + return None + + # We don't implement _repr_png_ here because it would add a large amount of + # data to any notebook containing SymPy expressions, without adding + # anything useful to the notebook. It can still enabled manually, e.g., + # for the qtconsole, with init_printing(). + _repr_png_ = _repr_disabled + + _repr_svg_ = _repr_disabled + + def _repr_latex_(self): + """ + IPython/Jupyter LaTeX printing + + To change the behavior of this (e.g., pass in some settings to LaTeX), + use init_printing(). init_printing() will also enable LaTeX printing + for built in numeric types like ints and container types that contain + SymPy objects, like lists and dictionaries of expressions. + """ + from sympy.printing.latex import latex + s = latex(self, mode='plain') + return "$\\displaystyle %s$" % s diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/add.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/add.py new file mode 100644 index 0000000000000000000000000000000000000000..2d280f3286c34cd0dea14bf61194ed03ee6bf6ae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/add.py @@ -0,0 +1,1280 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, ClassVar +from collections import defaultdict +from functools import reduce +from operator import attrgetter +from .basic import _args_sortkey +from .parameters import global_parameters +from .logic import _fuzzy_group, fuzzy_or, fuzzy_not +from .singleton import S +from .operations import AssocOp, AssocOpDispatcher +from .cache import cacheit +from .intfunc import ilcm, igcd +from .expr import Expr +from .kind import UndefinedKind +from sympy.utilities.iterables import is_sequence, sift + + +if TYPE_CHECKING: + from sympy.core.numbers import Number + from sympy.series.order import Order + + +def _could_extract_minus_sign(expr): + # assume expr is Add-like + # We choose the one with less arguments with minus signs + negative_args = sum(1 for i in expr.args + if i.could_extract_minus_sign()) + positive_args = len(expr.args) - negative_args + if positive_args > negative_args: + return False + elif positive_args < negative_args: + return True + # choose based on .sort_key() to prefer + # x - 1 instead of 1 - x and + # 3 - sqrt(2) instead of -3 + sqrt(2) + return bool(expr.sort_key() < (-expr).sort_key()) + + +def _addsort(args): + # in-place sorting of args + args.sort(key=_args_sortkey) + + +def _unevaluated_Add(*args): + """Return a well-formed unevaluated Add: Numbers are collected and + put in slot 0 and args are sorted. Use this when args have changed + but you still want to return an unevaluated Add. + + Examples + ======== + + >>> from sympy.core.add import _unevaluated_Add as uAdd + >>> from sympy import S, Add + >>> from sympy.abc import x, y + >>> a = uAdd(*[S(1.0), x, S(2)]) + >>> a.args[0] + 3.00000000000000 + >>> a.args[1] + x + + Beyond the Number being in slot 0, there is no other assurance of + order for the arguments since they are hash sorted. So, for testing + purposes, output produced by this in some other function can only + be tested against the output of this function or as one of several + options: + + >>> opts = (Add(x, y, evaluate=False), Add(y, x, evaluate=False)) + >>> a = uAdd(x, y) + >>> assert a in opts and a == uAdd(x, y) + >>> uAdd(x + 1, x + 2) + x + x + 3 + """ + args = list(args) + newargs = [] + co = S.Zero + while args: + a = args.pop() + if a.is_Add: + # this will keep nesting from building up + # so that x + (x + 1) -> x + x + 1 (3 args) + args.extend(a.args) + elif a.is_Number: + co += a + else: + newargs.append(a) + _addsort(newargs) + if co: + newargs.insert(0, co) + return Add._from_args(newargs) + + +class Add(Expr, AssocOp): + """ + Expression representing addition operation for algebraic group. + + .. deprecated:: 1.7 + + Using arguments that aren't subclasses of :class:`~.Expr` in core + operators (:class:`~.Mul`, :class:`~.Add`, and :class:`~.Pow`) is + deprecated. See :ref:`non-expr-args-deprecated` for details. + + Every argument of ``Add()`` must be ``Expr``. Infix operator ``+`` + on most scalar objects in SymPy calls this class. + + Another use of ``Add()`` is to represent the structure of abstract + addition so that its arguments can be substituted to return different + class. Refer to examples section for this. + + ``Add()`` evaluates the argument unless ``evaluate=False`` is passed. + The evaluation logic includes: + + 1. Flattening + ``Add(x, Add(y, z))`` -> ``Add(x, y, z)`` + + 2. Identity removing + ``Add(x, 0, y)`` -> ``Add(x, y)`` + + 3. Coefficient collecting by ``.as_coeff_Mul()`` + ``Add(x, 2*x)`` -> ``Mul(3, x)`` + + 4. Term sorting + ``Add(y, x, 2)`` -> ``Add(2, x, y)`` + + If no argument is passed, identity element 0 is returned. If single + element is passed, that element is returned. + + Note that ``Add(*args)`` is more efficient than ``sum(args)`` because + it flattens the arguments. ``sum(a, b, c, ...)`` recursively adds the + arguments as ``a + (b + (c + ...))``, which has quadratic complexity. + On the other hand, ``Add(a, b, c, d)`` does not assume nested + structure, making the complexity linear. + + Since addition is group operation, every argument should have the + same :obj:`sympy.core.kind.Kind()`. + + Examples + ======== + + >>> from sympy import Add, I + >>> from sympy.abc import x, y + >>> Add(x, 1) + x + 1 + >>> Add(x, x) + 2*x + >>> 2*x**2 + 3*x + I*y + 2*y + 2*x/5 + 1.0*y + 1 + 2*x**2 + 17*x/5 + 3.0*y + I*y + 1 + + If ``evaluate=False`` is passed, result is not evaluated. + + >>> Add(1, 2, evaluate=False) + 1 + 2 + >>> Add(x, x, evaluate=False) + x + x + + ``Add()`` also represents the general structure of addition operation. + + >>> from sympy import MatrixSymbol + >>> A,B = MatrixSymbol('A', 2,2), MatrixSymbol('B', 2,2) + >>> expr = Add(x,y).subs({x:A, y:B}) + >>> expr + A + B + >>> type(expr) + + + Note that the printers do not display in args order. + + >>> Add(x, 1) + x + 1 + >>> Add(x, 1).args + (1, x) + + See Also + ======== + + MatAdd + + """ + + __slots__ = () + + is_Add = True + + _args_type = Expr + + identity: ClassVar[Expr] + + if TYPE_CHECKING: + + def __new__(cls, *args: Expr | complex, evaluate: bool=True) -> Expr: # type: ignore + ... + + @property + def args(self) -> tuple[Expr, ...]: + ... + + @classmethod + def flatten(cls, seq: list[Expr]) -> tuple[list[Expr], list[Expr], None]: + """ + Takes the sequence "seq" of nested Adds and returns a flatten list. + + Returns: (commutative_part, noncommutative_part, order_symbols) + + Applies associativity, all terms are commutable with respect to + addition. + + NB: the removal of 0 is already handled by AssocOp.__new__ + + See Also + ======== + + sympy.core.mul.Mul.flatten + + """ + from sympy.calculus.accumulationbounds import AccumBounds + from sympy.matrices.expressions import MatrixExpr + from sympy.tensor.tensor import TensExpr, TensAdd + rv = None + if len(seq) == 2: + a, b = seq + if b.is_Rational: + a, b = b, a + if a.is_Rational: + if b.is_Mul: + rv = [a, b], [], None + if rv: + if all(s.is_commutative for s in rv[0]): + return rv + return [], rv[0], None + + # term -> coeff + # e.g. x**2 -> 5 for ... + 5*x**2 + ... + terms: dict[Expr, Number] = {} + + # coefficient (Number or zoo) to always be in slot 0 + # e.g. 3 + ... + coeff: Expr = S.Zero + + order_factors: list[Order] = [] + + extra: list[MatrixExpr] = [] + + for o in seq: + + # O(x) + if o.is_Order: + if o.expr.is_zero: # type: ignore + continue + if any(o1.contains(o) for o1 in order_factors): + continue + order_factors = [o1 for o1 in order_factors if not o.contains(o1)] # type: ignore + order_factors = [o] + order_factors # type: ignore + continue + + # 3 or NaN + elif o.is_Number: + if (o is S.NaN or coeff is S.ComplexInfinity and + o.is_finite is False) and not extra: + # we know for sure the result will be nan + return [S.NaN], [], None + if coeff.is_Number or isinstance(coeff, AccumBounds): + coeff += o + if coeff is S.NaN and not extra: + # we know for sure the result will be nan + return [S.NaN], [], None + continue + + elif isinstance(o, AccumBounds): + coeff = o.__add__(coeff) + continue + + elif isinstance(o, MatrixExpr): + # can't add 0 to Matrix so make sure coeff is not 0 + extra.append(o) + continue + + elif isinstance(o, TensExpr): + coeff = TensAdd(o, coeff).doit(deep=False) + continue + + elif o is S.ComplexInfinity: + if coeff.is_finite is False and not extra: + # we know for sure the result will be nan + return [S.NaN], [], None + coeff = S.ComplexInfinity + continue + + # Add([...]) + elif o.is_Add: + # NB: here we assume Add is always commutative + o_args: tuple[Expr, ...] = o.args # type: ignore + seq.extend(o_args) # TODO zerocopy? + continue + + # Mul([...]) + elif o.is_Mul: + c, s = o.as_coeff_Mul() + + # check for unevaluated Pow, e.g. 2**3 or 2**(-1/2) + elif o.is_Pow: + b, e = o.as_base_exp() + if b.is_Number and (e.is_Integer or + (e.is_Rational and e.is_negative)): + seq.append(b**e) + continue + c, s = S.One, o + + else: + # everything else + c = S.One + s = o + + # now we have: + # o = c*s, where + # + # c is a Number + # s is an expression with number factor extracted + # let's collect terms with the same s, so e.g. + # 2*x**2 + 3*x**2 -> 5*x**2 + if s in terms: + terms[s] += c + if terms[s] is S.NaN and not extra: + # we know for sure the result will be nan + return [S.NaN], [], None + else: + terms[s] = c + + # now let's construct new args: + # [2*x**2, x**3, 7*x**4, pi, ...] + newseq = [] + noncommutative = False + for s, c in terms.items(): + # 0*s + if c.is_zero: + continue + # 1*s + elif c is S.One: + newseq.append(s) + # c*s + else: + if s.is_Mul: + # Mul, already keeps its arguments in perfect order. + # so we can simply put c in slot0 and go the fast way. + # + # XXX: This breaks VectorMul unless it overrides + # _new_rawargs + cs = s._new_rawargs(*((c,) + s.args)) # type: ignore + newseq.append(cs) + elif s.is_Add: + # we just re-create the unevaluated Mul + newseq.append(Mul(c, s, evaluate=False)) + else: + # alternatively we have to call all Mul's machinery (slow) + newseq.append(Mul(c, s)) + + noncommutative = noncommutative or not s.is_commutative + + # oo, -oo + if coeff is S.Infinity: + newseq = [f for f in newseq if not (f.is_extended_nonnegative or f.is_real)] + + elif coeff is S.NegativeInfinity: + newseq = [f for f in newseq if not (f.is_extended_nonpositive or f.is_real)] + + if coeff is S.ComplexInfinity: + # zoo might be + # infinite_real + finite_im + # finite_real + infinite_im + # infinite_real + infinite_im + # addition of a finite real or imaginary number won't be able to + # change the zoo nature; adding an infinite qualtity would result + # in a NaN condition if it had sign opposite of the infinite + # portion of zoo, e.g., infinite_real - infinite_real. + newseq = [c for c in newseq if not (c.is_finite and + c.is_extended_real is not None)] + + # process O(x) + if order_factors: + newseq2 = [] + for t in newseq: + # x + O(x) -> O(x) + if not any(o.contains(t) for o in order_factors): + newseq2.append(t) + newseq = newseq2 + order_factors # type: ignore + # 1 + O(1) -> O(1) + for o in order_factors: + if o.contains(coeff): + coeff = S.Zero + break + + # order args canonically + _addsort(newseq) + + # current code expects coeff to be first + if coeff is not S.Zero: + newseq.insert(0, coeff) + + if extra: + newseq += extra + noncommutative = True + + # we are done + if noncommutative: + return [], newseq, None + else: + return newseq, [], None + + @classmethod + def class_key(cls): + return 3, 1, cls.__name__ + + @property + def kind(self): + k = attrgetter('kind') + kinds = map(k, self.args) + kinds = frozenset(kinds) + if len(kinds) != 1: + # Since addition is group operator, kind must be same. + # We know that this is unexpected signature, so return this. + result = UndefinedKind + else: + result, = kinds + return result + + def could_extract_minus_sign(self): + return _could_extract_minus_sign(self) + + @cacheit + def as_coeff_add(self, *deps): + """ + Returns a tuple (coeff, args) where self is treated as an Add and coeff + is the Number term and args is a tuple of all other terms. + + Examples + ======== + + >>> from sympy.abc import x + >>> (7 + 3*x).as_coeff_add() + (7, (3*x,)) + >>> (7*x).as_coeff_add() + (0, (7*x,)) + """ + if deps: + l1, l2 = sift(self.args, lambda x: x.has_free(*deps), binary=True) + return self._new_rawargs(*l2), tuple(l1) + coeff, notrat = self.args[0].as_coeff_add() + if coeff is not S.Zero: + return coeff, notrat + self.args[1:] + return S.Zero, self.args + + def as_coeff_Add(self, rational=False, deps=None) -> tuple[Number, Expr]: + """ + Efficiently extract the coefficient of a summation. + """ + coeff, args = self.args[0], self.args[1:] + + if coeff.is_Number and not rational or coeff.is_Rational: + return coeff, self._new_rawargs(*args) # type: ignore + return S.Zero, self + + # Note, we intentionally do not implement Add.as_coeff_mul(). Rather, we + # let Expr.as_coeff_mul() just always return (S.One, self) for an Add. See + # issue 5524. + + def _eval_power(self, expt): + from .evalf import pure_complex + from .relational import is_eq + if len(self.args) == 2 and any(_.is_infinite for _ in self.args): + if expt.is_zero is False and is_eq(expt, S.One) is False: + # looking for literal a + I*b + a, b = self.args + if a.coeff(S.ImaginaryUnit): + a, b = b, a + ico = b.coeff(S.ImaginaryUnit) + if ico and ico.is_extended_real and a.is_extended_real: + if expt.is_extended_negative: + return S.Zero + if expt.is_extended_positive: + return S.ComplexInfinity + return + if expt.is_Rational and self.is_number: + ri = pure_complex(self) + if ri: + r, i = ri + if expt.q == 2: + from sympy.functions.elementary.miscellaneous import sqrt + D = sqrt(r**2 + i**2) + if D.is_Rational: + from .exprtools import factor_terms + from sympy.functions.elementary.complexes import sign + from .function import expand_multinomial + # (r, i, D) is a Pythagorean triple + root = sqrt(factor_terms((D - r)/2))**expt.p + return root*expand_multinomial(( + # principle value + (D + r)/abs(i) + sign(i)*S.ImaginaryUnit)**expt.p) + elif expt == -1: + return _unevaluated_Mul( + r - i*S.ImaginaryUnit, + 1/(r**2 + i**2)) + + @cacheit + def _eval_derivative(self, s): + return self.func(*[a.diff(s) for a in self.args]) + + def _eval_nseries(self, x, n, logx, cdir=0): + terms = [t.nseries(x, n=n, logx=logx, cdir=cdir) for t in self.args] + return self.func(*terms) + + def _matches_simple(self, expr, repl_dict): + # handle (w+3).matches('x+5') -> {w: x+2} + coeff, terms = self.as_coeff_add() + if len(terms) == 1: + return terms[0].matches(expr - coeff, repl_dict) + return + + def matches(self, expr, repl_dict=None, old=False): + return self._matches_commutative(expr, repl_dict, old) + + @staticmethod + def _combine_inverse(lhs, rhs): + """ + Returns lhs - rhs, but treats oo like a symbol so oo - oo + returns 0, instead of a nan. + """ + from sympy.simplify.simplify import signsimp + inf = (S.Infinity, S.NegativeInfinity) + if lhs.has(*inf) or rhs.has(*inf): + from .symbol import Dummy + oo = Dummy('oo') + reps = { + S.Infinity: oo, + S.NegativeInfinity: -oo} + ireps = {v: k for k, v in reps.items()} + eq = lhs.xreplace(reps) - rhs.xreplace(reps) + if eq.has(oo): + eq = eq.replace( + lambda x: x.is_Pow and x.base is oo, + lambda x: x.base) + rv = eq.xreplace(ireps) + else: + rv = lhs - rhs + srv = signsimp(rv) + return srv if srv.is_Number else rv + + @cacheit + def as_two_terms(self): + """Return head and tail of self. + + This is the most efficient way to get the head and tail of an + expression. + + - if you want only the head, use self.args[0]; + - if you want to process the arguments of the tail then use + self.as_coef_add() which gives the head and a tuple containing + the arguments of the tail when treated as an Add. + - if you want the coefficient when self is treated as a Mul + then use self.as_coeff_mul()[0] + + >>> from sympy.abc import x, y + >>> (3*x - 2*y + 5).as_two_terms() + (5, 3*x - 2*y) + """ + return self.args[0], self._new_rawargs(*self.args[1:]) + + def as_numer_denom(self) -> tuple[Expr, Expr]: + """ + Decomposes an expression to its numerator part and its + denominator part. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> (x*y/z).as_numer_denom() + (x*y, z) + >>> (x*(y + 1)/y**7).as_numer_denom() + (x*(y + 1), y**7) + + See Also + ======== + + sympy.core.expr.Expr.as_numer_denom + """ + # clear rational denominator + content, expr = self.primitive() + if not isinstance(expr, Add): + return Mul(content, expr, evaluate=False).as_numer_denom() + ncon, dcon = content.as_numer_denom() + + # collect numerators and denominators of the terms + nd = defaultdict(list) + for f in expr.args: + ni, di = f.as_numer_denom() + nd[di].append(ni) + + # check for quick exit + if len(nd) == 1: + d, n = nd.popitem() + return self.func( + *[_keep_coeff(ncon, ni) for ni in n]), _keep_coeff(dcon, d) + + # sum up the terms having a common denominator + nd2 = {d: self.func(*n) if len(n) > 1 else n[0] for d, n in nd.items()} + + # assemble single numerator and denominator + denoms, numers = [list(i) for i in zip(*iter(nd2.items()))] + n, d = self.func(*[Mul(*(denoms[:i] + [numers[i]] + denoms[i + 1:])) + for i in range(len(numers))]), Mul(*denoms) + + return _keep_coeff(ncon, n), _keep_coeff(dcon, d) + + def _eval_is_polynomial(self, syms): + return all(term._eval_is_polynomial(syms) for term in self.args) + + def _eval_is_rational_function(self, syms): + return all(term._eval_is_rational_function(syms) for term in self.args) + + def _eval_is_meromorphic(self, x, a): + return _fuzzy_group((arg.is_meromorphic(x, a) for arg in self.args), + quick_exit=True) + + def _eval_is_algebraic_expr(self, syms): + return all(term._eval_is_algebraic_expr(syms) for term in self.args) + + # assumption methods + _eval_is_real = lambda self: _fuzzy_group( + (a.is_real for a in self.args), quick_exit=True) + _eval_is_extended_real = lambda self: _fuzzy_group( + (a.is_extended_real for a in self.args), quick_exit=True) + _eval_is_complex = lambda self: _fuzzy_group( + (a.is_complex for a in self.args), quick_exit=True) + _eval_is_antihermitian = lambda self: _fuzzy_group( + (a.is_antihermitian for a in self.args), quick_exit=True) + _eval_is_finite = lambda self: _fuzzy_group( + (a.is_finite for a in self.args), quick_exit=True) + _eval_is_hermitian = lambda self: _fuzzy_group( + (a.is_hermitian for a in self.args), quick_exit=True) + _eval_is_integer = lambda self: _fuzzy_group( + (a.is_integer for a in self.args), quick_exit=True) + _eval_is_rational = lambda self: _fuzzy_group( + (a.is_rational for a in self.args), quick_exit=True) + _eval_is_algebraic = lambda self: _fuzzy_group( + (a.is_algebraic for a in self.args), quick_exit=True) + _eval_is_commutative = lambda self: _fuzzy_group( + a.is_commutative for a in self.args) + + def _eval_is_infinite(self): + sawinf = False + for a in self.args: + ainf = a.is_infinite + if ainf is None: + return None + elif ainf is True: + # infinite+infinite might not be infinite + if sawinf is True: + return None + sawinf = True + return sawinf + + def _eval_is_imaginary(self): + nz = [] + im_I = [] + for a in self.args: + if a.is_extended_real: + if a.is_zero: + pass + elif a.is_zero is False: + nz.append(a) + else: + return + elif a.is_imaginary: + im_I.append(a*S.ImaginaryUnit) + elif a.is_Mul and S.ImaginaryUnit in a.args: + coeff, ai = a.as_coeff_mul(S.ImaginaryUnit) + if ai == (S.ImaginaryUnit,) and coeff.is_extended_real: + im_I.append(-coeff) + else: + return + else: + return + b = self.func(*nz) + if b != self: + if b.is_zero: + return fuzzy_not(self.func(*im_I).is_zero) + elif b.is_zero is False: + return False + + def _eval_is_zero(self): + if self.is_commutative is False: + # issue 10528: there is no way to know if a nc symbol + # is zero or not + return + nz = [] + z = 0 + im_or_z = False + im = 0 + for a in self.args: + if a.is_extended_real: + if a.is_zero: + z += 1 + elif a.is_zero is False: + nz.append(a) + else: + return + elif a.is_imaginary: + im += 1 + elif a.is_Mul and S.ImaginaryUnit in a.args: + coeff, ai = a.as_coeff_mul(S.ImaginaryUnit) + if ai == (S.ImaginaryUnit,) and coeff.is_extended_real: + im_or_z = True + else: + return + else: + return + if z == len(self.args): + return True + if len(nz) in [0, len(self.args)]: + return None + b = self.func(*nz) + if b.is_zero: + if not im_or_z: + if im == 0: + return True + elif im == 1: + return False + if b.is_zero is False: + return False + + def _eval_is_odd(self): + l = [f for f in self.args if not (f.is_even is True)] + if not l: + return False + if l[0].is_odd: + return self._new_rawargs(*l[1:]).is_even + + def _eval_is_irrational(self): + for t in self.args: + a = t.is_irrational + if a: + others = list(self.args) + others.remove(t) + if all(x.is_rational is True for x in others): + return True + return None + if a is None: + return + return False + + def _all_nonneg_or_nonppos(self): + nn = np = 0 + for a in self.args: + if a.is_nonnegative: + if np: + return False + nn = 1 + elif a.is_nonpositive: + if nn: + return False + np = 1 + else: + break + else: + return True + + def _eval_is_extended_positive(self): + if self.is_number: + return super()._eval_is_extended_positive() + c, a = self.as_coeff_Add() + if not c.is_zero: + from .exprtools import _monotonic_sign + v = _monotonic_sign(a) + if v is not None: + s = v + c + if s != self and s.is_extended_positive and a.is_extended_nonnegative: + return True + if len(self.free_symbols) == 1: + v = _monotonic_sign(self) + if v is not None and v != self and v.is_extended_positive: + return True + pos = nonneg = nonpos = unknown_sign = False + saw_INF = set() + args = [a for a in self.args if not a.is_zero] + if not args: + return False + for a in args: + ispos = a.is_extended_positive + infinite = a.is_infinite + if infinite: + saw_INF.add(fuzzy_or((ispos, a.is_extended_nonnegative))) + if True in saw_INF and False in saw_INF: + return + if ispos: + pos = True + continue + elif a.is_extended_nonnegative: + nonneg = True + continue + elif a.is_extended_nonpositive: + nonpos = True + continue + + if infinite is None: + return + unknown_sign = True + + if saw_INF: + if len(saw_INF) > 1: + return + return saw_INF.pop() + elif unknown_sign: + return + elif not nonpos and not nonneg and pos: + return True + elif not nonpos and pos: + return True + elif not pos and not nonneg: + return False + + def _eval_is_extended_nonnegative(self): + if not self.is_number: + c, a = self.as_coeff_Add() + if not c.is_zero and a.is_extended_nonnegative: + from .exprtools import _monotonic_sign + v = _monotonic_sign(a) + if v is not None: + s = v + c + if s != self and s.is_extended_nonnegative: + return True + if len(self.free_symbols) == 1: + v = _monotonic_sign(self) + if v is not None and v != self and v.is_extended_nonnegative: + return True + + def _eval_is_extended_nonpositive(self): + if not self.is_number: + c, a = self.as_coeff_Add() + if not c.is_zero and a.is_extended_nonpositive: + from .exprtools import _monotonic_sign + v = _monotonic_sign(a) + if v is not None: + s = v + c + if s != self and s.is_extended_nonpositive: + return True + if len(self.free_symbols) == 1: + v = _monotonic_sign(self) + if v is not None and v != self and v.is_extended_nonpositive: + return True + + def _eval_is_extended_negative(self): + if self.is_number: + return super()._eval_is_extended_negative() + c, a = self.as_coeff_Add() + if not c.is_zero: + from .exprtools import _monotonic_sign + v = _monotonic_sign(a) + if v is not None: + s = v + c + if s != self and s.is_extended_negative and a.is_extended_nonpositive: + return True + if len(self.free_symbols) == 1: + v = _monotonic_sign(self) + if v is not None and v != self and v.is_extended_negative: + return True + neg = nonpos = nonneg = unknown_sign = False + saw_INF = set() + args = [a for a in self.args if not a.is_zero] + if not args: + return False + for a in args: + isneg = a.is_extended_negative + infinite = a.is_infinite + if infinite: + saw_INF.add(fuzzy_or((isneg, a.is_extended_nonpositive))) + if True in saw_INF and False in saw_INF: + return + if isneg: + neg = True + continue + elif a.is_extended_nonpositive: + nonpos = True + continue + elif a.is_extended_nonnegative: + nonneg = True + continue + + if infinite is None: + return + unknown_sign = True + + if saw_INF: + if len(saw_INF) > 1: + return + return saw_INF.pop() + elif unknown_sign: + return + elif not nonneg and not nonpos and neg: + return True + elif not nonneg and neg: + return True + elif not neg and not nonpos: + return False + + def _eval_subs(self, old, new): + if not old.is_Add: + if old is S.Infinity and -old in self.args: + # foo - oo is foo + (-oo) internally + return self.xreplace({-old: -new}) + return None + + coeff_self, terms_self = self.as_coeff_Add() + coeff_old, terms_old = old.as_coeff_Add() + + if coeff_self.is_Rational and coeff_old.is_Rational: + if terms_self == terms_old: # (2 + a).subs( 3 + a, y) -> -1 + y + return self.func(new, coeff_self, -coeff_old) + if terms_self == -terms_old: # (2 + a).subs(-3 - a, y) -> -1 - y + return self.func(-new, coeff_self, coeff_old) + + if coeff_self.is_Rational and coeff_old.is_Rational \ + or coeff_self == coeff_old: + args_old, args_self = self.func.make_args( + terms_old), self.func.make_args(terms_self) + if len(args_old) < len(args_self): # (a+b+c).subs(b+c,x) -> a+x + self_set = set(args_self) + old_set = set(args_old) + + if old_set < self_set: + ret_set = self_set - old_set + return self.func(new, coeff_self, -coeff_old, + *[s._subs(old, new) for s in ret_set]) + + args_old = self.func.make_args( + -terms_old) # (a+b+c+d).subs(-b-c,x) -> a-x+d + old_set = set(args_old) + if old_set < self_set: + ret_set = self_set - old_set + return self.func(-new, coeff_self, coeff_old, + *[s._subs(old, new) for s in ret_set]) + + def removeO(self): + args = [a for a in self.args if not a.is_Order] + return self._new_rawargs(*args) + + def getO(self): + args = [a for a in self.args if a.is_Order] + if args: + return self._new_rawargs(*args) + + @cacheit + def extract_leading_order(self, symbols, point=None): + """ + Returns the leading term and its order. + + Examples + ======== + + >>> from sympy.abc import x + >>> (x + 1 + 1/x**5).extract_leading_order(x) + ((x**(-5), O(x**(-5))),) + >>> (1 + x).extract_leading_order(x) + ((1, O(1)),) + >>> (x + x**2).extract_leading_order(x) + ((x, O(x)),) + + """ + from sympy.series.order import Order + lst = [] + symbols = list(symbols if is_sequence(symbols) else [symbols]) + if not point: + point = [0]*len(symbols) + seq = [(f, Order(f, *zip(symbols, point))) for f in self.args] + for ef, of in seq: + for e, o in lst: + if o.contains(of) and o != of: + of = None + break + if of is None: + continue + new_lst = [(ef, of)] + for e, o in lst: + if of.contains(o) and o != of: + continue + new_lst.append((e, o)) + lst = new_lst + return tuple(lst) + + def as_real_imag(self, deep=True, **hints): + """ + Return a tuple representing a complex number. + + Examples + ======== + + >>> from sympy import I + >>> (7 + 9*I).as_real_imag() + (7, 9) + >>> ((1 + I)/(1 - I)).as_real_imag() + (0, 1) + >>> ((1 + 2*I)*(1 + 3*I)).as_real_imag() + (-5, 5) + """ + sargs = self.args + re_part, im_part = [], [] + for term in sargs: + re, im = term.as_real_imag(deep=deep) + re_part.append(re) + im_part.append(im) + return (self.func(*re_part), self.func(*im_part)) + + def _eval_as_leading_term(self, x, logx, cdir): + from sympy.core.symbol import Dummy, Symbol + from sympy.series.order import Order + from sympy.functions.elementary.exponential import log + from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold + from .function import expand_mul + + o = self.getO() + if o is None: + o = Order(0) + old = self.removeO() + + if old.has(Piecewise): + old = piecewise_fold(old) + + # This expansion is the last part of expand_log. expand_log also calls + # expand_mul with factor=True, which would be more expensive + if any(isinstance(a, log) for a in self.args): + logflags = {"deep": True, "log": True, "mul": False, "power_exp": False, + "power_base": False, "multinomial": False, "basic": False, "force": False, + "factor": False} + old = old.expand(**logflags) + expr = expand_mul(old) + + if not expr.is_Add: + return expr.as_leading_term(x, logx=logx, cdir=cdir) + + infinite = [t for t in expr.args if t.is_infinite] + + _logx = Dummy('logx') if logx is None else logx + leading_terms = [t.as_leading_term(x, logx=_logx, cdir=cdir) for t in expr.args] + + min, new_expr = Order(0), S.Zero + + try: + for term in leading_terms: + order = Order(term, x) + if not min or order not in min: + min = order + new_expr = term + elif min in order: + new_expr += term + + except TypeError: + return expr + + if logx is None: + new_expr = new_expr.subs(_logx, log(x)) + + is_zero = new_expr.is_zero + if is_zero is None: + new_expr = new_expr.trigsimp().cancel() + is_zero = new_expr.is_zero + if is_zero is True: + # simple leading term analysis gave us cancelled terms but we have to send + # back a term, so compute the leading term (via series) + try: + n0 = min.getn() + except NotImplementedError: + n0 = S.One + if n0.has(Symbol): + n0 = S.One + res = Order(1) + incr = S.One + while res.is_Order: + res = old._eval_nseries(x, n=n0+incr, logx=logx, cdir=cdir).cancel().powsimp().trigsimp() + incr *= 2 + return res.as_leading_term(x, logx=logx, cdir=cdir) + + elif new_expr is S.NaN: + return old.func._from_args(infinite) + o + + else: + return new_expr + + def _eval_adjoint(self): + return self.func(*[t.adjoint() for t in self.args]) + + def _eval_conjugate(self): + return self.func(*[t.conjugate() for t in self.args]) + + def _eval_transpose(self): + return self.func(*[t.transpose() for t in self.args]) + + def primitive(self): + """ + Return ``(R, self/R)`` where ``R``` is the Rational GCD of ``self```. + + ``R`` is collected only from the leading coefficient of each term. + + Examples + ======== + + >>> from sympy.abc import x, y + + >>> (2*x + 4*y).primitive() + (2, x + 2*y) + + >>> (2*x/3 + 4*y/9).primitive() + (2/9, 3*x + 2*y) + + >>> (2*x/3 + 4.2*y).primitive() + (1/3, 2*x + 12.6*y) + + No subprocessing of term factors is performed: + + >>> ((2 + 2*x)*x + 2).primitive() + (1, x*(2*x + 2) + 2) + + Recursive processing can be done with the ``as_content_primitive()`` + method: + + >>> ((2 + 2*x)*x + 2).as_content_primitive() + (2, x*(x + 1) + 1) + + See also: primitive() function in polytools.py + + """ + + terms = [] + inf = False + for a in self.args: + c, m = a.as_coeff_Mul() + if not c.is_Rational: + c = S.One + m = a + inf = inf or m is S.ComplexInfinity + terms.append((c.p, c.q, m)) + + if not inf: + ngcd = reduce(igcd, [t[0] for t in terms], 0) + dlcm = reduce(ilcm, [t[1] for t in terms], 1) + else: + ngcd = reduce(igcd, [t[0] for t in terms if t[1]], 0) + dlcm = reduce(ilcm, [t[1] for t in terms if t[1]], 1) + + if ngcd == dlcm == 1: + return S.One, self + if not inf: + for i, (p, q, term) in enumerate(terms): + terms[i] = _keep_coeff(Rational((p//ngcd)*(dlcm//q)), term) + else: + for i, (p, q, term) in enumerate(terms): + if q: + terms[i] = _keep_coeff(Rational((p//ngcd)*(dlcm//q)), term) + else: + terms[i] = _keep_coeff(Rational(p, q), term) + + # we don't need a complete re-flattening since no new terms will join + # so we just use the same sort as is used in Add.flatten. When the + # coefficient changes, the ordering of terms may change, e.g. + # (3*x, 6*y) -> (2*y, x) + # + # We do need to make sure that term[0] stays in position 0, however. + # + if terms[0].is_Number or terms[0] is S.ComplexInfinity: + c = terms.pop(0) + else: + c = None + _addsort(terms) + if c: + terms.insert(0, c) + return Rational(ngcd, dlcm), self._new_rawargs(*terms) + + def as_content_primitive(self, radical=False, clear=True): + """Return the tuple (R, self/R) where R is the positive Rational + extracted from self. If radical is True (default is False) then + common radicals will be removed and included as a factor of the + primitive expression. + + Examples + ======== + + >>> from sympy import sqrt + >>> (3 + 3*sqrt(2)).as_content_primitive() + (3, 1 + sqrt(2)) + + Radical content can also be factored out of the primitive: + + >>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True) + (2, sqrt(2)*(1 + 2*sqrt(5))) + + See docstring of Expr.as_content_primitive for more examples. + """ + con, prim = self.func(*[_keep_coeff(*a.as_content_primitive( + radical=radical, clear=clear)) for a in self.args]).primitive() + if not clear and not con.is_Integer and prim.is_Add: + con, d = con.as_numer_denom() + _p = prim/d + if any(a.as_coeff_Mul()[0].is_Integer for a in _p.args): + prim = _p + else: + con /= d + if radical and prim.is_Add: + # look for common radicals that can be removed + args = prim.args + rads = [] + common_q = None + for m in args: + term_rads = defaultdict(list) + for ai in Mul.make_args(m): + if ai.is_Pow: + b, e = ai.as_base_exp() + if e.is_Rational and b.is_Integer: + term_rads[e.q].append(abs(int(b))**e.p) + if not term_rads: + break + if common_q is None: + common_q = set(term_rads.keys()) + else: + common_q = common_q & set(term_rads.keys()) + if not common_q: + break + rads.append(term_rads) + else: + # process rads + # keep only those in common_q + for r in rads: + for q in list(r.keys()): + if q not in common_q: + r.pop(q) + for q in r: + r[q] = Mul(*r[q]) + # find the gcd of bases for each q + G = [] + for q in common_q: + g = reduce(igcd, [r[q] for r in rads], 0) + if g != 1: + G.append(g**Rational(1, q)) + if G: + G = Mul(*G) + args = [ai/G for ai in args] + prim = G*prim.func(*args) + + return con, prim + + @property + def _sorted_args(self): + from .sorting import default_sort_key + return tuple(sorted(self.args, key=default_sort_key)) + + def _eval_difference_delta(self, n, step): + from sympy.series.limitseq import difference_delta as dd + return self.func(*[dd(a, n, step) for a in self.args]) + + @property + def _mpc_(self): + """ + Convert self to an mpmath mpc if possible + """ + from .numbers import Float + re_part, rest = self.as_coeff_Add() + im_part, imag_unit = rest.as_coeff_Mul() + if not imag_unit == S.ImaginaryUnit: + # ValueError may seem more reasonable but since it's a @property, + # we need to use AttributeError to keep from confusing things like + # hasattr. + raise AttributeError("Cannot convert Add to mpc. Must be of the form Number + Number*I") + + return (Float(re_part)._mpf_, Float(im_part)._mpf_) + + def __neg__(self): + if not global_parameters.distribute: + return super().__neg__() + return Mul(S.NegativeOne, self) + +add = AssocOpDispatcher('add') + +from .mul import Mul, _keep_coeff, _unevaluated_Mul +from .numbers import Rational diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/alphabets.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/alphabets.py new file mode 100644 index 0000000000000000000000000000000000000000..1ea2ae1c410ccd30e7ec9551f4cd8b19a36cdba1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/alphabets.py @@ -0,0 +1,4 @@ +greeks = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', + 'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', + 'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', + 'phi', 'chi', 'psi', 'omega') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/assumptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/assumptions.py new file mode 100644 index 0000000000000000000000000000000000000000..677e86c5e39390b0b188a5158dd2fabfbac4c760 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/assumptions.py @@ -0,0 +1,692 @@ +""" +This module contains the machinery handling assumptions. +Do also consider the guide :ref:`assumptions-guide`. + +All symbolic objects have assumption attributes that can be accessed via +``.is_`` attribute. + +Assumptions determine certain properties of symbolic objects and can +have 3 possible values: ``True``, ``False``, ``None``. ``True`` is returned if the +object has the property and ``False`` is returned if it does not or cannot +(i.e. does not make sense): + + >>> from sympy import I + >>> I.is_algebraic + True + >>> I.is_real + False + >>> I.is_prime + False + +When the property cannot be determined (or when a method is not +implemented) ``None`` will be returned. For example, a generic symbol, ``x``, +may or may not be positive so a value of ``None`` is returned for ``x.is_positive``. + +By default, all symbolic values are in the largest set in the given context +without specifying the property. For example, a symbol that has a property +being integer, is also real, complex, etc. + +Here follows a list of possible assumption names: + +.. glossary:: + + commutative + object commutes with any other object with + respect to multiplication operation. See [12]_. + + complex + object can have only values from the set + of complex numbers. See [13]_. + + imaginary + object value is a number that can be written as a real + number multiplied by the imaginary unit ``I``. See + [3]_. Please note that ``0`` is not considered to be an + imaginary number, see + `issue #7649 `_. + + real + object can have only values from the set + of real numbers. + + extended_real + object can have only values from the set + of real numbers, ``oo`` and ``-oo``. + + integer + object can have only values from the set + of integers. + + odd + even + object can have only values from the set of + odd (even) integers [2]_. + + prime + object is a natural number greater than 1 that has + no positive divisors other than 1 and itself. See [6]_. + + composite + object is a positive integer that has at least one positive + divisor other than 1 or the number itself. See [4]_. + + zero + object has the value of 0. + + nonzero + object is a real number that is not zero. + + rational + object can have only values from the set + of rationals. + + algebraic + object can have only values from the set + of algebraic numbers [11]_. + + transcendental + object can have only values from the set + of transcendental numbers [10]_. + + irrational + object value cannot be represented exactly by :class:`~.Rational`, see [5]_. + + finite + infinite + object absolute value is bounded (arbitrarily large). + See [7]_, [8]_, [9]_. + + negative + nonnegative + object can have only negative (nonnegative) + values [1]_. + + positive + nonpositive + object can have only positive (nonpositive) values. + + extended_negative + extended_nonnegative + extended_positive + extended_nonpositive + extended_nonzero + as without the extended part, but also including infinity with + corresponding sign, e.g., extended_positive includes ``oo`` + + hermitian + antihermitian + object belongs to the field of Hermitian + (antihermitian) operators. + +Examples +======== + + >>> from sympy import Symbol + >>> x = Symbol('x', real=True); x + x + >>> x.is_real + True + >>> x.is_complex + True + +See Also +======== + +.. seealso:: + + :py:class:`sympy.core.numbers.ImaginaryUnit` + :py:class:`sympy.core.numbers.Zero` + :py:class:`sympy.core.numbers.One` + :py:class:`sympy.core.numbers.Infinity` + :py:class:`sympy.core.numbers.NegativeInfinity` + :py:class:`sympy.core.numbers.ComplexInfinity` + +Notes +===== + +The fully-resolved assumptions for any SymPy expression +can be obtained as follows: + + >>> from sympy.core.assumptions import assumptions + >>> x = Symbol('x',positive=True) + >>> assumptions(x + I) + {'commutative': True, 'complex': True, 'composite': False, 'even': + False, 'extended_negative': False, 'extended_nonnegative': False, + 'extended_nonpositive': False, 'extended_nonzero': False, + 'extended_positive': False, 'extended_real': False, 'finite': True, + 'imaginary': False, 'infinite': False, 'integer': False, 'irrational': + False, 'negative': False, 'noninteger': False, 'nonnegative': False, + 'nonpositive': False, 'nonzero': False, 'odd': False, 'positive': + False, 'prime': False, 'rational': False, 'real': False, 'zero': + False} + +Developers Notes +================ + +The current (and possibly incomplete) values are stored +in the ``obj._assumptions dictionary``; queries to getter methods +(with property decorators) or attributes of objects/classes +will return values and update the dictionary. + + >>> eq = x**2 + I + >>> eq._assumptions + {} + >>> eq.is_finite + True + >>> eq._assumptions + {'finite': True, 'infinite': False} + +For a :class:`~.Symbol`, there are two locations for assumptions that may +be of interest. The ``assumptions0`` attribute gives the full set of +assumptions derived from a given set of initial assumptions. The +latter assumptions are stored as ``Symbol._assumptions_orig`` + + >>> Symbol('x', prime=True, even=True)._assumptions_orig + {'even': True, 'prime': True} + +The ``_assumptions_orig`` are not necessarily canonical nor are they filtered +in any way: they records the assumptions used to instantiate a Symbol and (for +storage purposes) represent a more compact representation of the assumptions +needed to recreate the full set in ``Symbol.assumptions0``. + + +References +========== + +.. [1] https://en.wikipedia.org/wiki/Negative_number +.. [2] https://en.wikipedia.org/wiki/Parity_%28mathematics%29 +.. [3] https://en.wikipedia.org/wiki/Imaginary_number +.. [4] https://en.wikipedia.org/wiki/Composite_number +.. [5] https://en.wikipedia.org/wiki/Irrational_number +.. [6] https://en.wikipedia.org/wiki/Prime_number +.. [7] https://en.wikipedia.org/wiki/Finite +.. [8] https://docs.python.org/3/library/math.html#math.isfinite +.. [9] https://numpy.org/doc/stable/reference/generated/numpy.isfinite.html +.. [10] https://en.wikipedia.org/wiki/Transcendental_number +.. [11] https://en.wikipedia.org/wiki/Algebraic_number +.. [12] https://en.wikipedia.org/wiki/Commutative_property +.. [13] https://en.wikipedia.org/wiki/Complex_number + +""" + +from sympy.utilities.exceptions import sympy_deprecation_warning + +from .facts import FactRules, FactKB +from .sympify import sympify + +from sympy.core.random import _assumptions_shuffle as shuffle +from sympy.core.assumptions_generated import generated_assumptions as _assumptions + +def _load_pre_generated_assumption_rules() -> FactRules: + """ Load the assumption rules from pre-generated data + + To update the pre-generated data, see :method::`_generate_assumption_rules` + """ + _assume_rules=FactRules._from_python(_assumptions) + return _assume_rules + +def _generate_assumption_rules(): + """ Generate the default assumption rules + + This method should only be called to update the pre-generated + assumption rules. + + To update the pre-generated assumptions run: bin/ask_update.py + + """ + _assume_rules = FactRules([ + + 'integer -> rational', + 'rational -> real', + 'rational -> algebraic', + 'algebraic -> complex', + 'transcendental == complex & !algebraic', + 'real -> hermitian', + 'imaginary -> complex', + 'imaginary -> antihermitian', + 'extended_real -> commutative', + 'complex -> commutative', + 'complex -> finite', + + 'odd == integer & !even', + 'even == integer & !odd', + + 'real -> complex', + 'extended_real -> real | infinite', + 'real == extended_real & finite', + + 'extended_real == extended_negative | zero | extended_positive', + 'extended_negative == extended_nonpositive & extended_nonzero', + 'extended_positive == extended_nonnegative & extended_nonzero', + + 'extended_nonpositive == extended_real & !extended_positive', + 'extended_nonnegative == extended_real & !extended_negative', + + 'real == negative | zero | positive', + 'negative == nonpositive & nonzero', + 'positive == nonnegative & nonzero', + + 'nonpositive == real & !positive', + 'nonnegative == real & !negative', + + 'positive == extended_positive & finite', + 'negative == extended_negative & finite', + 'nonpositive == extended_nonpositive & finite', + 'nonnegative == extended_nonnegative & finite', + 'nonzero == extended_nonzero & finite', + + 'zero -> even & finite', + 'zero == extended_nonnegative & extended_nonpositive', + 'zero == nonnegative & nonpositive', + 'nonzero -> real', + + 'prime -> integer & positive', + 'composite -> integer & positive & !prime', + '!composite -> !positive | !even | prime', + + 'irrational == real & !rational', + + 'imaginary -> !extended_real', + + 'infinite == !finite', + 'noninteger == extended_real & !integer', + 'extended_nonzero == extended_real & !zero', + ]) + return _assume_rules + + +_assume_rules = _load_pre_generated_assumption_rules() +_assume_defined = _assume_rules.defined_facts.copy() +_assume_defined.add('polar') +_assume_defined = frozenset(_assume_defined) + + +def assumptions(expr, _check=None): + """return the T/F assumptions of ``expr``""" + n = sympify(expr) + if n.is_Symbol: + rv = n.assumptions0 # are any important ones missing? + if _check is not None: + rv = {k: rv[k] for k in set(rv) & set(_check)} + return rv + rv = {} + for k in _assume_defined if _check is None else _check: + v = getattr(n, 'is_{}'.format(k)) + if v is not None: + rv[k] = v + return rv + + +def common_assumptions(exprs, check=None): + """return those assumptions which have the same True or False + value for all the given expressions. + + Examples + ======== + + >>> from sympy.core import common_assumptions + >>> from sympy import oo, pi, sqrt + >>> common_assumptions([-4, 0, sqrt(2), 2, pi, oo]) + {'commutative': True, 'composite': False, + 'extended_real': True, 'imaginary': False, 'odd': False} + + By default, all assumptions are tested; pass an iterable of the + assumptions to limit those that are reported: + + >>> common_assumptions([0, 1, 2], ['positive', 'integer']) + {'integer': True} + """ + check = _assume_defined if check is None else set(check) + if not check or not exprs: + return {} + + # get all assumptions for each + assume = [assumptions(i, _check=check) for i in sympify(exprs)] + # focus on those of interest that are True + for i, e in enumerate(assume): + assume[i] = {k: e[k] for k in set(e) & check} + # what assumptions are in common? + common = set.intersection(*[set(i) for i in assume]) + # which ones hold the same value + a = assume[0] + return {k: a[k] for k in common if all(a[k] == b[k] + for b in assume)} + + +def failing_assumptions(expr, **assumptions): + """ + Return a dictionary containing assumptions with values not + matching those of the passed assumptions. + + Examples + ======== + + >>> from sympy import failing_assumptions, Symbol + + >>> x = Symbol('x', positive=True) + >>> y = Symbol('y') + >>> failing_assumptions(6*x + y, positive=True) + {'positive': None} + + >>> failing_assumptions(x**2 - 1, positive=True) + {'positive': None} + + If *expr* satisfies all of the assumptions, an empty dictionary is returned. + + >>> failing_assumptions(x**2, positive=True) + {} + + """ + expr = sympify(expr) + failed = {} + for k in assumptions: + test = getattr(expr, 'is_%s' % k, None) + if test is not assumptions[k]: + failed[k] = test + return failed # {} or {assumption: value != desired} + + +def check_assumptions(expr, against=None, **assume): + """ + Checks whether assumptions of ``expr`` match the T/F assumptions + given (or possessed by ``against``). True is returned if all + assumptions match; False is returned if there is a mismatch and + the assumption in ``expr`` is not None; else None is returned. + + Explanation + =========== + + *assume* is a dict of assumptions with True or False values + + Examples + ======== + + >>> from sympy import Symbol, pi, I, exp, check_assumptions + >>> check_assumptions(-5, integer=True) + True + >>> check_assumptions(pi, real=True, integer=False) + True + >>> check_assumptions(pi, negative=True) + False + >>> check_assumptions(exp(I*pi/7), real=False) + True + >>> x = Symbol('x', positive=True) + >>> check_assumptions(2*x + 1, positive=True) + True + >>> check_assumptions(-2*x - 5, positive=True) + False + + To check assumptions of *expr* against another variable or expression, + pass the expression or variable as ``against``. + + >>> check_assumptions(2*x + 1, x) + True + + To see if a number matches the assumptions of an expression, pass + the number as the first argument, else its specific assumptions + may not have a non-None value in the expression: + + >>> check_assumptions(x, 3) + >>> check_assumptions(3, x) + True + + ``None`` is returned if ``check_assumptions()`` could not conclude. + + >>> check_assumptions(2*x - 1, x) + + >>> z = Symbol('z') + >>> check_assumptions(z, real=True) + + See Also + ======== + + failing_assumptions + + """ + expr = sympify(expr) + if against is not None: + if assume: + raise ValueError( + 'Expecting `against` or `assume`, not both.') + assume = assumptions(against) + known = True + for k, v in assume.items(): + if v is None: + continue + e = getattr(expr, 'is_' + k, None) + if e is None: + known = None + elif v != e: + return False + return known + + +class StdFactKB(FactKB): + """A FactKB specialized for the built-in rules + + This is the only kind of FactKB that Basic objects should use. + """ + def __init__(self, facts=None): + super().__init__(_assume_rules) + # save a copy of the facts dict + if not facts: + self._generator = {} + elif not isinstance(facts, FactKB): + self._generator = facts.copy() + else: + self._generator = facts.generator + if facts: + self.deduce_all_facts(facts) + + def copy(self): + return self.__class__(self) + + @property + def generator(self): + return self._generator.copy() + + +def as_property(fact): + """Convert a fact name to the name of the corresponding property""" + return 'is_%s' % fact + + +def make_property(fact): + """Create the automagic property corresponding to a fact.""" + + def getit(self): + try: + return self._assumptions[fact] + except KeyError: + if self._assumptions is self.default_assumptions: + self._assumptions = self.default_assumptions.copy() + return _ask(fact, self) + + getit.func_name = as_property(fact) + return property(getit) + + +def _ask(fact, obj): + """ + Find the truth value for a property of an object. + + This function is called when a request is made to see what a fact + value is. + + For this we use several techniques: + + First, the fact-evaluation function is tried, if it exists (for + example _eval_is_integer). Then we try related facts. For example + + rational --> integer + + another example is joined rule: + + integer & !odd --> even + + so in the latter case if we are looking at what 'even' value is, + 'integer' and 'odd' facts will be asked. + + In all cases, when we settle on some fact value, its implications are + deduced, and the result is cached in ._assumptions. + """ + # FactKB which is dict-like and maps facts to their known values: + assumptions = obj._assumptions + + # A dict that maps facts to their handlers: + handler_map = obj._prop_handler + + # This is our queue of facts to check: + facts_to_check = [fact] + facts_queued = {fact} + + # Loop over the queue as it extends + for fact_i in facts_to_check: + + # If fact_i has already been determined then we don't need to rerun the + # handler. There is a potential race condition for multithreaded code + # though because it's possible that fact_i was checked in another + # thread. The main logic of the loop below would potentially skip + # checking assumptions[fact] in this case so we check it once after the + # loop to be sure. + if fact_i in assumptions: + continue + + # Now we call the associated handler for fact_i if it exists. + fact_i_value = None + handler_i = handler_map.get(fact_i) + if handler_i is not None: + fact_i_value = handler_i(obj) + + # If we get a new value for fact_i then we should update our knowledge + # of fact_i as well as any related facts that can be inferred using the + # inference rules connecting the fact_i and any other fact values that + # are already known. + if fact_i_value is not None: + assumptions.deduce_all_facts(((fact_i, fact_i_value),)) + + # Usually if assumptions[fact] is now not None then that is because of + # the call to deduce_all_facts above. The handler for fact_i returned + # True or False and knowing fact_i (which is equal to fact in the first + # iteration) implies knowing a value for fact. It is also possible + # though that independent code e.g. called indirectly by the handler or + # called in another thread in a multithreaded context might have + # resulted in assumptions[fact] being set. Either way we return it. + fact_value = assumptions.get(fact) + if fact_value is not None: + return fact_value + + # Extend the queue with other facts that might determine fact_i. Here + # we randomise the order of the facts that are checked. This should not + # lead to any non-determinism if all handlers are logically consistent + # with the inference rules for the facts. Non-deterministic assumptions + # queries can result from bugs in the handlers that are exposed by this + # call to shuffle. These are pushed to the back of the queue meaning + # that the inference graph is traversed in breadth-first order. + new_facts_to_check = list(_assume_rules.prereq[fact_i] - facts_queued) + shuffle(new_facts_to_check) + facts_to_check.extend(new_facts_to_check) + facts_queued.update(new_facts_to_check) + + # The above loop should be able to handle everything fine in a + # single-threaded context but in multithreaded code it is possible that + # this thread skipped computing a particular fact that was computed in + # another thread (due to the continue). In that case it is possible that + # fact was inferred and is now stored in the assumptions dict but it wasn't + # checked for in the body of the loop. This is an obscure case but to make + # sure we catch it we check once here at the end of the loop. + if fact in assumptions: + return assumptions[fact] + + # This query can not be answered. It's possible that e.g. another thread + # has already stored None for fact but assumptions._tell does not mind if + # we call _tell twice setting the same value. If this raises + # InconsistentAssumptions then it probably means that another thread + # attempted to compute this and got a value of True or False rather than + # None. In that case there must be a bug in at least one of the handlers. + # If the handlers are all deterministic and are consistent with the + # inference rules then the same value should be computed for fact in all + # threads. + assumptions._tell(fact, None) + return None + + +def _prepare_class_assumptions(cls): + """Precompute class level assumptions and generate handlers. + + This is called by Basic.__init_subclass__ each time a Basic subclass is + defined. + """ + + local_defs = {} + for k in _assume_defined: + attrname = as_property(k) + v = cls.__dict__.get(attrname, '') + if isinstance(v, (bool, int, type(None))): + if v is not None: + v = bool(v) + local_defs[k] = v + + defs = {} + for base in reversed(cls.__bases__): + assumptions = getattr(base, '_explicit_class_assumptions', None) + if assumptions is not None: + defs.update(assumptions) + defs.update(local_defs) + + cls._explicit_class_assumptions = defs + cls.default_assumptions = StdFactKB(defs) + + cls._prop_handler = {} + for k in _assume_defined: + eval_is_meth = getattr(cls, '_eval_is_%s' % k, None) + if eval_is_meth is not None: + cls._prop_handler[k] = eval_is_meth + + # Put definite results directly into the class dict, for speed + for k, v in cls.default_assumptions.items(): + setattr(cls, as_property(k), v) + + # protection e.g. for Integer.is_even=F <- (Rational.is_integer=F) + derived_from_bases = set() + for base in cls.__bases__: + default_assumptions = getattr(base, 'default_assumptions', None) + # is an assumption-aware class + if default_assumptions is not None: + derived_from_bases.update(default_assumptions) + + for fact in derived_from_bases - set(cls.default_assumptions): + pname = as_property(fact) + if pname not in cls.__dict__: + setattr(cls, pname, make_property(fact)) + + # Finally, add any missing automagic property (e.g. for Basic) + for fact in _assume_defined: + pname = as_property(fact) + if not hasattr(cls, pname): + setattr(cls, pname, make_property(fact)) + + +# XXX: ManagedProperties used to be the metaclass for Basic but now Basic does +# not use a metaclass. We leave this here for backwards compatibility for now +# in case someone has been using the ManagedProperties class in downstream +# code. The reason that it might have been used is that when subclassing a +# class and wanting to use a metaclass the metaclass must be a subclass of the +# metaclass for the class that is being subclassed. Anyone wanting to subclass +# Basic and use a metaclass in their subclass would have needed to subclass +# ManagedProperties. Here ManagedProperties is not the metaclass for Basic any +# more but it should still be usable as a metaclass for Basic subclasses since +# it is a subclass of type which is now the metaclass for Basic. +class ManagedProperties(type): + def __init__(cls, *args, **kwargs): + msg = ("The ManagedProperties metaclass. " + "Basic does not use metaclasses any more") + sympy_deprecation_warning(msg, + deprecated_since_version="1.12", + active_deprecations_target='managedproperties') + + # Here we still call this function in case someone is using + # ManagedProperties for something that is not a Basic subclass. For + # Basic subclasses this function is now called by __init_subclass__ and + # so this metaclass is not needed any more. + _prepare_class_assumptions(cls) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/assumptions_generated.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/assumptions_generated.py new file mode 100644 index 0000000000000000000000000000000000000000..b4b2597a72b500155370db385b58e61f0f951984 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/assumptions_generated.py @@ -0,0 +1,1615 @@ +""" +Do NOT manually edit this file. +Instead, run ./bin/ask_update.py. +""" + +defined_facts = [ + 'algebraic', + 'antihermitian', + 'commutative', + 'complex', + 'composite', + 'even', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'negative', + 'noninteger', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'transcendental', + 'zero', +] # defined_facts + + +full_implications = dict( [ + # Implications of algebraic = True: + (('algebraic', True), set( ( + ('commutative', True), + ('complex', True), + ('finite', True), + ('infinite', False), + ('transcendental', False), + ) ), + ), + # Implications of algebraic = False: + (('algebraic', False), set( ( + ('composite', False), + ('even', False), + ('integer', False), + ('odd', False), + ('prime', False), + ('rational', False), + ('zero', False), + ) ), + ), + # Implications of antihermitian = True: + (('antihermitian', True), set( ( + ) ), + ), + # Implications of antihermitian = False: + (('antihermitian', False), set( ( + ('imaginary', False), + ) ), + ), + # Implications of commutative = True: + (('commutative', True), set( ( + ) ), + ), + # Implications of commutative = False: + (('commutative', False), set( ( + ('algebraic', False), + ('complex', False), + ('composite', False), + ('even', False), + ('extended_negative', False), + ('extended_nonnegative', False), + ('extended_nonpositive', False), + ('extended_nonzero', False), + ('extended_positive', False), + ('extended_real', False), + ('imaginary', False), + ('integer', False), + ('irrational', False), + ('negative', False), + ('noninteger', False), + ('nonnegative', False), + ('nonpositive', False), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', False), + ('real', False), + ('transcendental', False), + ('zero', False), + ) ), + ), + # Implications of complex = True: + (('complex', True), set( ( + ('commutative', True), + ('finite', True), + ('infinite', False), + ) ), + ), + # Implications of complex = False: + (('complex', False), set( ( + ('algebraic', False), + ('composite', False), + ('even', False), + ('imaginary', False), + ('integer', False), + ('irrational', False), + ('negative', False), + ('nonnegative', False), + ('nonpositive', False), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', False), + ('real', False), + ('transcendental', False), + ('zero', False), + ) ), + ), + # Implications of composite = True: + (('composite', True), set( ( + ('algebraic', True), + ('commutative', True), + ('complex', True), + ('extended_negative', False), + ('extended_nonnegative', True), + ('extended_nonpositive', False), + ('extended_nonzero', True), + ('extended_positive', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('integer', True), + ('irrational', False), + ('negative', False), + ('noninteger', False), + ('nonnegative', True), + ('nonpositive', False), + ('nonzero', True), + ('positive', True), + ('prime', False), + ('rational', True), + ('real', True), + ('transcendental', False), + ('zero', False), + ) ), + ), + # Implications of composite = False: + (('composite', False), set( ( + ) ), + ), + # Implications of even = True: + (('even', True), set( ( + ('algebraic', True), + ('commutative', True), + ('complex', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('integer', True), + ('irrational', False), + ('noninteger', False), + ('odd', False), + ('rational', True), + ('real', True), + ('transcendental', False), + ) ), + ), + # Implications of even = False: + (('even', False), set( ( + ('zero', False), + ) ), + ), + # Implications of extended_negative = True: + (('extended_negative', True), set( ( + ('commutative', True), + ('composite', False), + ('extended_nonnegative', False), + ('extended_nonpositive', True), + ('extended_nonzero', True), + ('extended_positive', False), + ('extended_real', True), + ('imaginary', False), + ('nonnegative', False), + ('positive', False), + ('prime', False), + ('zero', False), + ) ), + ), + # Implications of extended_negative = False: + (('extended_negative', False), set( ( + ('negative', False), + ) ), + ), + # Implications of extended_nonnegative = True: + (('extended_nonnegative', True), set( ( + ('commutative', True), + ('extended_negative', False), + ('extended_real', True), + ('imaginary', False), + ('negative', False), + ) ), + ), + # Implications of extended_nonnegative = False: + (('extended_nonnegative', False), set( ( + ('composite', False), + ('extended_positive', False), + ('nonnegative', False), + ('positive', False), + ('prime', False), + ('zero', False), + ) ), + ), + # Implications of extended_nonpositive = True: + (('extended_nonpositive', True), set( ( + ('commutative', True), + ('composite', False), + ('extended_positive', False), + ('extended_real', True), + ('imaginary', False), + ('positive', False), + ('prime', False), + ) ), + ), + # Implications of extended_nonpositive = False: + (('extended_nonpositive', False), set( ( + ('extended_negative', False), + ('negative', False), + ('nonpositive', False), + ('zero', False), + ) ), + ), + # Implications of extended_nonzero = True: + (('extended_nonzero', True), set( ( + ('commutative', True), + ('extended_real', True), + ('imaginary', False), + ('zero', False), + ) ), + ), + # Implications of extended_nonzero = False: + (('extended_nonzero', False), set( ( + ('composite', False), + ('extended_negative', False), + ('extended_positive', False), + ('negative', False), + ('nonzero', False), + ('positive', False), + ('prime', False), + ) ), + ), + # Implications of extended_positive = True: + (('extended_positive', True), set( ( + ('commutative', True), + ('extended_negative', False), + ('extended_nonnegative', True), + ('extended_nonpositive', False), + ('extended_nonzero', True), + ('extended_real', True), + ('imaginary', False), + ('negative', False), + ('nonpositive', False), + ('zero', False), + ) ), + ), + # Implications of extended_positive = False: + (('extended_positive', False), set( ( + ('composite', False), + ('positive', False), + ('prime', False), + ) ), + ), + # Implications of extended_real = True: + (('extended_real', True), set( ( + ('commutative', True), + ('imaginary', False), + ) ), + ), + # Implications of extended_real = False: + (('extended_real', False), set( ( + ('composite', False), + ('even', False), + ('extended_negative', False), + ('extended_nonnegative', False), + ('extended_nonpositive', False), + ('extended_nonzero', False), + ('extended_positive', False), + ('integer', False), + ('irrational', False), + ('negative', False), + ('noninteger', False), + ('nonnegative', False), + ('nonpositive', False), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', False), + ('real', False), + ('zero', False), + ) ), + ), + # Implications of finite = True: + (('finite', True), set( ( + ('infinite', False), + ) ), + ), + # Implications of finite = False: + (('finite', False), set( ( + ('algebraic', False), + ('complex', False), + ('composite', False), + ('even', False), + ('imaginary', False), + ('infinite', True), + ('integer', False), + ('irrational', False), + ('negative', False), + ('nonnegative', False), + ('nonpositive', False), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', False), + ('real', False), + ('transcendental', False), + ('zero', False), + ) ), + ), + # Implications of hermitian = True: + (('hermitian', True), set( ( + ) ), + ), + # Implications of hermitian = False: + (('hermitian', False), set( ( + ('composite', False), + ('even', False), + ('integer', False), + ('irrational', False), + ('negative', False), + ('nonnegative', False), + ('nonpositive', False), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', False), + ('real', False), + ('zero', False), + ) ), + ), + # Implications of imaginary = True: + (('imaginary', True), set( ( + ('antihermitian', True), + ('commutative', True), + ('complex', True), + ('composite', False), + ('even', False), + ('extended_negative', False), + ('extended_nonnegative', False), + ('extended_nonpositive', False), + ('extended_nonzero', False), + ('extended_positive', False), + ('extended_real', False), + ('finite', True), + ('infinite', False), + ('integer', False), + ('irrational', False), + ('negative', False), + ('noninteger', False), + ('nonnegative', False), + ('nonpositive', False), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', False), + ('real', False), + ('zero', False), + ) ), + ), + # Implications of imaginary = False: + (('imaginary', False), set( ( + ) ), + ), + # Implications of infinite = True: + (('infinite', True), set( ( + ('algebraic', False), + ('complex', False), + ('composite', False), + ('even', False), + ('finite', False), + ('imaginary', False), + ('integer', False), + ('irrational', False), + ('negative', False), + ('nonnegative', False), + ('nonpositive', False), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', False), + ('real', False), + ('transcendental', False), + ('zero', False), + ) ), + ), + # Implications of infinite = False: + (('infinite', False), set( ( + ('finite', True), + ) ), + ), + # Implications of integer = True: + (('integer', True), set( ( + ('algebraic', True), + ('commutative', True), + ('complex', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('irrational', False), + ('noninteger', False), + ('rational', True), + ('real', True), + ('transcendental', False), + ) ), + ), + # Implications of integer = False: + (('integer', False), set( ( + ('composite', False), + ('even', False), + ('odd', False), + ('prime', False), + ('zero', False), + ) ), + ), + # Implications of irrational = True: + (('irrational', True), set( ( + ('commutative', True), + ('complex', True), + ('composite', False), + ('even', False), + ('extended_nonzero', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('integer', False), + ('noninteger', True), + ('nonzero', True), + ('odd', False), + ('prime', False), + ('rational', False), + ('real', True), + ('zero', False), + ) ), + ), + # Implications of irrational = False: + (('irrational', False), set( ( + ) ), + ), + # Implications of negative = True: + (('negative', True), set( ( + ('commutative', True), + ('complex', True), + ('composite', False), + ('extended_negative', True), + ('extended_nonnegative', False), + ('extended_nonpositive', True), + ('extended_nonzero', True), + ('extended_positive', False), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('nonnegative', False), + ('nonpositive', True), + ('nonzero', True), + ('positive', False), + ('prime', False), + ('real', True), + ('zero', False), + ) ), + ), + # Implications of negative = False: + (('negative', False), set( ( + ) ), + ), + # Implications of noninteger = True: + (('noninteger', True), set( ( + ('commutative', True), + ('composite', False), + ('even', False), + ('extended_nonzero', True), + ('extended_real', True), + ('imaginary', False), + ('integer', False), + ('odd', False), + ('prime', False), + ('zero', False), + ) ), + ), + # Implications of noninteger = False: + (('noninteger', False), set( ( + ) ), + ), + # Implications of nonnegative = True: + (('nonnegative', True), set( ( + ('commutative', True), + ('complex', True), + ('extended_negative', False), + ('extended_nonnegative', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('negative', False), + ('real', True), + ) ), + ), + # Implications of nonnegative = False: + (('nonnegative', False), set( ( + ('composite', False), + ('positive', False), + ('prime', False), + ('zero', False), + ) ), + ), + # Implications of nonpositive = True: + (('nonpositive', True), set( ( + ('commutative', True), + ('complex', True), + ('composite', False), + ('extended_nonpositive', True), + ('extended_positive', False), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('positive', False), + ('prime', False), + ('real', True), + ) ), + ), + # Implications of nonpositive = False: + (('nonpositive', False), set( ( + ('negative', False), + ('zero', False), + ) ), + ), + # Implications of nonzero = True: + (('nonzero', True), set( ( + ('commutative', True), + ('complex', True), + ('extended_nonzero', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('real', True), + ('zero', False), + ) ), + ), + # Implications of nonzero = False: + (('nonzero', False), set( ( + ('composite', False), + ('negative', False), + ('positive', False), + ('prime', False), + ) ), + ), + # Implications of odd = True: + (('odd', True), set( ( + ('algebraic', True), + ('commutative', True), + ('complex', True), + ('even', False), + ('extended_nonzero', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('integer', True), + ('irrational', False), + ('noninteger', False), + ('nonzero', True), + ('rational', True), + ('real', True), + ('transcendental', False), + ('zero', False), + ) ), + ), + # Implications of odd = False: + (('odd', False), set( ( + ) ), + ), + # Implications of positive = True: + (('positive', True), set( ( + ('commutative', True), + ('complex', True), + ('extended_negative', False), + ('extended_nonnegative', True), + ('extended_nonpositive', False), + ('extended_nonzero', True), + ('extended_positive', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('negative', False), + ('nonnegative', True), + ('nonpositive', False), + ('nonzero', True), + ('real', True), + ('zero', False), + ) ), + ), + # Implications of positive = False: + (('positive', False), set( ( + ('composite', False), + ('prime', False), + ) ), + ), + # Implications of prime = True: + (('prime', True), set( ( + ('algebraic', True), + ('commutative', True), + ('complex', True), + ('composite', False), + ('extended_negative', False), + ('extended_nonnegative', True), + ('extended_nonpositive', False), + ('extended_nonzero', True), + ('extended_positive', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('integer', True), + ('irrational', False), + ('negative', False), + ('noninteger', False), + ('nonnegative', True), + ('nonpositive', False), + ('nonzero', True), + ('positive', True), + ('rational', True), + ('real', True), + ('transcendental', False), + ('zero', False), + ) ), + ), + # Implications of prime = False: + (('prime', False), set( ( + ) ), + ), + # Implications of rational = True: + (('rational', True), set( ( + ('algebraic', True), + ('commutative', True), + ('complex', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('irrational', False), + ('real', True), + ('transcendental', False), + ) ), + ), + # Implications of rational = False: + (('rational', False), set( ( + ('composite', False), + ('even', False), + ('integer', False), + ('odd', False), + ('prime', False), + ('zero', False), + ) ), + ), + # Implications of real = True: + (('real', True), set( ( + ('commutative', True), + ('complex', True), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ) ), + ), + # Implications of real = False: + (('real', False), set( ( + ('composite', False), + ('even', False), + ('integer', False), + ('irrational', False), + ('negative', False), + ('nonnegative', False), + ('nonpositive', False), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', False), + ('zero', False), + ) ), + ), + # Implications of transcendental = True: + (('transcendental', True), set( ( + ('algebraic', False), + ('commutative', True), + ('complex', True), + ('composite', False), + ('even', False), + ('finite', True), + ('infinite', False), + ('integer', False), + ('odd', False), + ('prime', False), + ('rational', False), + ('zero', False), + ) ), + ), + # Implications of transcendental = False: + (('transcendental', False), set( ( + ) ), + ), + # Implications of zero = True: + (('zero', True), set( ( + ('algebraic', True), + ('commutative', True), + ('complex', True), + ('composite', False), + ('even', True), + ('extended_negative', False), + ('extended_nonnegative', True), + ('extended_nonpositive', True), + ('extended_nonzero', False), + ('extended_positive', False), + ('extended_real', True), + ('finite', True), + ('hermitian', True), + ('imaginary', False), + ('infinite', False), + ('integer', True), + ('irrational', False), + ('negative', False), + ('noninteger', False), + ('nonnegative', True), + ('nonpositive', True), + ('nonzero', False), + ('odd', False), + ('positive', False), + ('prime', False), + ('rational', True), + ('real', True), + ('transcendental', False), + ) ), + ), + # Implications of zero = False: + (('zero', False), set( ( + ) ), + ), + ] ) # full_implications + + +prereq = { + + # facts that could determine the value of algebraic + 'algebraic': { + 'commutative', + 'complex', + 'composite', + 'even', + 'finite', + 'infinite', + 'integer', + 'odd', + 'prime', + 'rational', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of antihermitian + 'antihermitian': { + 'imaginary', + }, + + # facts that could determine the value of commutative + 'commutative': { + 'algebraic', + 'complex', + 'composite', + 'even', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'imaginary', + 'integer', + 'irrational', + 'negative', + 'noninteger', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of complex + 'complex': { + 'algebraic', + 'commutative', + 'composite', + 'even', + 'finite', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'negative', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of composite + 'composite': { + 'algebraic', + 'commutative', + 'complex', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'negative', + 'noninteger', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'positive', + 'prime', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of even + 'even': { + 'algebraic', + 'commutative', + 'complex', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'noninteger', + 'odd', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of extended_negative + 'extended_negative': { + 'commutative', + 'composite', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'imaginary', + 'negative', + 'nonnegative', + 'positive', + 'prime', + 'zero', + }, + + # facts that could determine the value of extended_nonnegative + 'extended_nonnegative': { + 'commutative', + 'composite', + 'extended_negative', + 'extended_positive', + 'extended_real', + 'imaginary', + 'negative', + 'nonnegative', + 'positive', + 'prime', + 'zero', + }, + + # facts that could determine the value of extended_nonpositive + 'extended_nonpositive': { + 'commutative', + 'composite', + 'extended_negative', + 'extended_positive', + 'extended_real', + 'imaginary', + 'negative', + 'nonpositive', + 'positive', + 'prime', + 'zero', + }, + + # facts that could determine the value of extended_nonzero + 'extended_nonzero': { + 'commutative', + 'composite', + 'extended_negative', + 'extended_positive', + 'extended_real', + 'imaginary', + 'irrational', + 'negative', + 'noninteger', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'zero', + }, + + # facts that could determine the value of extended_positive + 'extended_positive': { + 'commutative', + 'composite', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_real', + 'imaginary', + 'negative', + 'nonpositive', + 'positive', + 'prime', + 'zero', + }, + + # facts that could determine the value of extended_real + 'extended_real': { + 'commutative', + 'composite', + 'even', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'imaginary', + 'integer', + 'irrational', + 'negative', + 'noninteger', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'zero', + }, + + # facts that could determine the value of finite + 'finite': { + 'algebraic', + 'complex', + 'composite', + 'even', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'negative', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of hermitian + 'hermitian': { + 'composite', + 'even', + 'integer', + 'irrational', + 'negative', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'zero', + }, + + # facts that could determine the value of imaginary + 'imaginary': { + 'antihermitian', + 'commutative', + 'complex', + 'composite', + 'even', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'finite', + 'infinite', + 'integer', + 'irrational', + 'negative', + 'noninteger', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'zero', + }, + + # facts that could determine the value of infinite + 'infinite': { + 'algebraic', + 'complex', + 'composite', + 'even', + 'finite', + 'imaginary', + 'integer', + 'irrational', + 'negative', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of integer + 'integer': { + 'algebraic', + 'commutative', + 'complex', + 'composite', + 'even', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'irrational', + 'noninteger', + 'odd', + 'prime', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of irrational + 'irrational': { + 'commutative', + 'complex', + 'composite', + 'even', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'odd', + 'prime', + 'rational', + 'real', + 'zero', + }, + + # facts that could determine the value of negative + 'negative': { + 'commutative', + 'complex', + 'composite', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'positive', + 'prime', + 'real', + 'zero', + }, + + # facts that could determine the value of noninteger + 'noninteger': { + 'commutative', + 'composite', + 'even', + 'extended_real', + 'imaginary', + 'integer', + 'irrational', + 'odd', + 'prime', + 'zero', + }, + + # facts that could determine the value of nonnegative + 'nonnegative': { + 'commutative', + 'complex', + 'composite', + 'extended_negative', + 'extended_nonnegative', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'negative', + 'positive', + 'prime', + 'real', + 'zero', + }, + + # facts that could determine the value of nonpositive + 'nonpositive': { + 'commutative', + 'complex', + 'composite', + 'extended_nonpositive', + 'extended_positive', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'negative', + 'positive', + 'prime', + 'real', + 'zero', + }, + + # facts that could determine the value of nonzero + 'nonzero': { + 'commutative', + 'complex', + 'composite', + 'extended_nonzero', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'irrational', + 'negative', + 'odd', + 'positive', + 'prime', + 'real', + 'zero', + }, + + # facts that could determine the value of odd + 'odd': { + 'algebraic', + 'commutative', + 'complex', + 'even', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'noninteger', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of positive + 'positive': { + 'commutative', + 'complex', + 'composite', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'negative', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'prime', + 'real', + 'zero', + }, + + # facts that could determine the value of prime + 'prime': { + 'algebraic', + 'commutative', + 'complex', + 'composite', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'negative', + 'noninteger', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'positive', + 'rational', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of rational + 'rational': { + 'algebraic', + 'commutative', + 'complex', + 'composite', + 'even', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'odd', + 'prime', + 'real', + 'transcendental', + 'zero', + }, + + # facts that could determine the value of real + 'real': { + 'commutative', + 'complex', + 'composite', + 'even', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'negative', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'zero', + }, + + # facts that could determine the value of transcendental + 'transcendental': { + 'algebraic', + 'commutative', + 'complex', + 'composite', + 'even', + 'finite', + 'infinite', + 'integer', + 'odd', + 'prime', + 'rational', + 'zero', + }, + + # facts that could determine the value of zero + 'zero': { + 'algebraic', + 'commutative', + 'complex', + 'composite', + 'even', + 'extended_negative', + 'extended_nonnegative', + 'extended_nonpositive', + 'extended_nonzero', + 'extended_positive', + 'extended_real', + 'finite', + 'hermitian', + 'imaginary', + 'infinite', + 'integer', + 'irrational', + 'negative', + 'noninteger', + 'nonnegative', + 'nonpositive', + 'nonzero', + 'odd', + 'positive', + 'prime', + 'rational', + 'real', + 'transcendental', + }, + +} # prereq + + +# Note: the order of the beta rules is used in the beta_triggers +beta_rules = [ + + # Rules implying composite = True + ({('even', True), ('positive', True), ('prime', False)}, + ('composite', True)), + + # Rules implying even = False + ({('composite', False), ('positive', True), ('prime', False)}, + ('even', False)), + + # Rules implying even = True + ({('integer', True), ('odd', False)}, + ('even', True)), + + # Rules implying extended_negative = True + ({('extended_positive', False), ('extended_real', True), ('zero', False)}, + ('extended_negative', True)), + ({('extended_nonpositive', True), ('extended_nonzero', True)}, + ('extended_negative', True)), + + # Rules implying extended_nonnegative = True + ({('extended_negative', False), ('extended_real', True)}, + ('extended_nonnegative', True)), + + # Rules implying extended_nonpositive = True + ({('extended_positive', False), ('extended_real', True)}, + ('extended_nonpositive', True)), + + # Rules implying extended_nonzero = True + ({('extended_real', True), ('zero', False)}, + ('extended_nonzero', True)), + + # Rules implying extended_positive = True + ({('extended_negative', False), ('extended_real', True), ('zero', False)}, + ('extended_positive', True)), + ({('extended_nonnegative', True), ('extended_nonzero', True)}, + ('extended_positive', True)), + + # Rules implying extended_real = False + ({('infinite', False), ('real', False)}, + ('extended_real', False)), + ({('extended_negative', False), ('extended_positive', False), ('zero', False)}, + ('extended_real', False)), + + # Rules implying infinite = True + ({('extended_real', True), ('real', False)}, + ('infinite', True)), + + # Rules implying irrational = True + ({('rational', False), ('real', True)}, + ('irrational', True)), + + # Rules implying negative = True + ({('positive', False), ('real', True), ('zero', False)}, + ('negative', True)), + ({('nonpositive', True), ('nonzero', True)}, + ('negative', True)), + ({('extended_negative', True), ('finite', True)}, + ('negative', True)), + + # Rules implying noninteger = True + ({('extended_real', True), ('integer', False)}, + ('noninteger', True)), + + # Rules implying nonnegative = True + ({('negative', False), ('real', True)}, + ('nonnegative', True)), + ({('extended_nonnegative', True), ('finite', True)}, + ('nonnegative', True)), + + # Rules implying nonpositive = True + ({('positive', False), ('real', True)}, + ('nonpositive', True)), + ({('extended_nonpositive', True), ('finite', True)}, + ('nonpositive', True)), + + # Rules implying nonzero = True + ({('extended_nonzero', True), ('finite', True)}, + ('nonzero', True)), + + # Rules implying odd = True + ({('even', False), ('integer', True)}, + ('odd', True)), + + # Rules implying positive = False + ({('composite', False), ('even', True), ('prime', False)}, + ('positive', False)), + + # Rules implying positive = True + ({('negative', False), ('real', True), ('zero', False)}, + ('positive', True)), + ({('nonnegative', True), ('nonzero', True)}, + ('positive', True)), + ({('extended_positive', True), ('finite', True)}, + ('positive', True)), + + # Rules implying prime = True + ({('composite', False), ('even', True), ('positive', True)}, + ('prime', True)), + + # Rules implying real = False + ({('negative', False), ('positive', False), ('zero', False)}, + ('real', False)), + + # Rules implying real = True + ({('extended_real', True), ('infinite', False)}, + ('real', True)), + ({('extended_real', True), ('finite', True)}, + ('real', True)), + + # Rules implying transcendental = True + ({('algebraic', False), ('complex', True)}, + ('transcendental', True)), + + # Rules implying zero = True + ({('extended_negative', False), ('extended_positive', False), ('extended_real', True)}, + ('zero', True)), + ({('negative', False), ('positive', False), ('real', True)}, + ('zero', True)), + ({('extended_nonnegative', True), ('extended_nonpositive', True)}, + ('zero', True)), + ({('nonnegative', True), ('nonpositive', True)}, + ('zero', True)), + +] # beta_rules +beta_triggers = { + ('algebraic', False): [32, 11, 3, 8, 29, 14, 25, 13, 17, 7], + ('algebraic', True): [10, 30, 31, 27, 16, 21, 19, 22], + ('antihermitian', False): [], + ('commutative', False): [], + ('complex', False): [10, 12, 11, 3, 8, 17, 7], + ('complex', True): [32, 10, 30, 31, 27, 16, 21, 19, 22], + ('composite', False): [1, 28, 24], + ('composite', True): [23, 2], + ('even', False): [23, 11, 3, 8, 29, 14, 25, 7], + ('even', True): [3, 33, 8, 6, 5, 14, 34, 25, 20, 18, 27, 16, 21, 19, 22, 0, 28, 24, 7], + ('extended_negative', False): [11, 33, 8, 5, 29, 34, 25, 18], + ('extended_negative', True): [30, 12, 31, 29, 14, 20, 16, 21, 22, 17], + ('extended_nonnegative', False): [11, 3, 6, 29, 14, 20, 7], + ('extended_nonnegative', True): [30, 12, 31, 33, 8, 9, 6, 29, 34, 25, 18, 19, 35, 17, 7], + ('extended_nonpositive', False): [11, 8, 5, 29, 25, 18, 7], + ('extended_nonpositive', True): [30, 12, 31, 3, 33, 4, 5, 29, 14, 34, 20, 21, 35, 17, 7], + ('extended_nonzero', False): [11, 33, 6, 5, 29, 34, 20, 18], + ('extended_nonzero', True): [30, 12, 31, 3, 8, 4, 9, 6, 5, 29, 14, 25, 22, 17], + ('extended_positive', False): [11, 3, 33, 6, 29, 14, 34, 20], + ('extended_positive', True): [30, 12, 31, 29, 25, 18, 27, 19, 22, 17], + ('extended_real', False): [], + ('extended_real', True): [30, 12, 31, 3, 33, 8, 6, 5, 17, 7], + ('finite', False): [11, 3, 8, 17, 7], + ('finite', True): [10, 30, 31, 27, 16, 21, 19, 22], + ('hermitian', False): [10, 12, 11, 3, 8, 17, 7], + ('imaginary', True): [32], + ('infinite', False): [10, 30, 31, 27, 16, 21, 19, 22], + ('infinite', True): [11, 3, 8, 17, 7], + ('integer', False): [11, 3, 8, 29, 14, 25, 17, 7], + ('integer', True): [23, 2, 3, 33, 8, 6, 5, 14, 34, 25, 20, 18, 27, 16, 21, 19, 22, 7], + ('irrational', True): [32, 3, 8, 4, 9, 6, 5, 14, 25, 15, 26, 20, 18, 27, 16, 21, 19], + ('negative', False): [29, 34, 25, 18], + ('negative', True): [32, 13, 17], + ('noninteger', True): [30, 12, 31, 3, 8, 4, 9, 6, 5, 29, 14, 25, 22], + ('nonnegative', False): [11, 3, 8, 29, 14, 20, 7], + ('nonnegative', True): [32, 33, 8, 9, 6, 34, 25, 26, 20, 27, 21, 22, 35, 36, 13, 17, 7], + ('nonpositive', False): [11, 3, 8, 29, 25, 18, 7], + ('nonpositive', True): [32, 3, 33, 4, 5, 14, 34, 15, 18, 16, 19, 22, 35, 36, 13, 17, 7], + ('nonzero', False): [29, 34, 20, 18], + ('nonzero', True): [32, 3, 8, 4, 9, 6, 5, 14, 25, 15, 26, 20, 18, 27, 16, 21, 19, 13, 17], + ('odd', False): [2], + ('odd', True): [3, 8, 4, 9, 6, 5, 14, 25, 15, 26, 20, 18, 27, 16, 21, 19], + ('positive', False): [29, 14, 34, 20], + ('positive', True): [32, 0, 1, 28, 13, 17], + ('prime', False): [0, 1, 24], + ('prime', True): [23, 2], + ('rational', False): [11, 3, 8, 29, 14, 25, 13, 17, 7], + ('rational', True): [3, 33, 8, 6, 5, 14, 34, 25, 20, 18, 27, 16, 21, 19, 22, 17, 7], + ('real', False): [10, 12, 11, 3, 8, 17, 7], + ('real', True): [32, 3, 33, 8, 6, 5, 14, 34, 25, 20, 18, 27, 16, 21, 19, 22, 13, 17, 7], + ('transcendental', True): [10, 30, 31, 11, 3, 8, 29, 14, 25, 27, 16, 21, 19, 22, 13, 17, 7], + ('zero', False): [11, 3, 8, 29, 14, 25, 7], + ('zero', True): [], +} # beta_triggers + + +generated_assumptions = {'defined_facts': defined_facts, 'full_implications': full_implications, + 'prereq': prereq, 'beta_rules': beta_rules, 'beta_triggers': beta_triggers} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/backend.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/backend.py new file mode 100644 index 0000000000000000000000000000000000000000..34a4e05a4a4ac50d0830960cb324871a20e9a12d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/backend.py @@ -0,0 +1,120 @@ +import os +USE_SYMENGINE = os.getenv('USE_SYMENGINE', '0') +USE_SYMENGINE = USE_SYMENGINE.lower() in ('1', 't', 'true') # type: ignore + +if USE_SYMENGINE: + from symengine import (Symbol, Integer, sympify as sympify_symengine, S, + SympifyError, exp, log, gamma, sqrt, I, E, pi, Matrix, + sin, cos, tan, cot, csc, sec, asin, acos, atan, acot, acsc, asec, + sinh, cosh, tanh, coth, asinh, acosh, atanh, acoth, + lambdify, symarray, diff, zeros, eye, diag, ones, + expand, Function, symbols, var, Add, Mul, Derivative, + ImmutableMatrix, MatrixBase, Rational, Basic) + from symengine.lib.symengine_wrapper import gcd as igcd + from symengine import AppliedUndef + + def sympify(a, *, strict=False): + """ + Notes + ===== + + SymEngine's ``sympify`` does not accept keyword arguments and is + therefore not compatible with SymPy's ``sympify`` with ``strict=True`` + (which ensures that only the types for which an explicit conversion has + been defined are converted). This wrapper adds an additional parameter + ``strict`` (with default ``False``) that will raise a ``SympifyError`` + if ``strict=True`` and the argument passed to the parameter ``a`` is a + string. + + See Also + ======== + + sympify: Converts an arbitrary expression to a type that can be used + inside SymPy. + + """ + # The parameter ``a`` is used for this function to keep compatibility + # with the SymEngine docstring. + if strict and isinstance(a, str): + raise SympifyError(a) + return sympify_symengine(a) + + # Keep the SymEngine docstring and append the additional "Notes" and "See + # Also" sections. Replacement of spaces is required to correctly format the + # indentation of the combined docstring. + sympify.__doc__ = ( + sympify_symengine.__doc__ + + sympify.__doc__.replace(' ', ' ') # type: ignore + ) +else: + from sympy.core.add import Add + from sympy.core.basic import Basic + from sympy.core.function import (diff, Function, AppliedUndef, + expand, Derivative) + from sympy.core.mul import Mul + from sympy.core.intfunc import igcd + from sympy.core.numbers import pi, I, Integer, Rational, E + from sympy.core.singleton import S + from sympy.core.symbol import Symbol, var, symbols + from sympy.core.sympify import SympifyError, sympify + from sympy.functions.elementary.exponential import log, exp + from sympy.functions.elementary.hyperbolic import (coth, sinh, + acosh, acoth, tanh, asinh, atanh, cosh) + from sympy.functions.elementary.miscellaneous import sqrt + from sympy.functions.elementary.trigonometric import (csc, + asec, cos, atan, sec, acot, asin, tan, sin, cot, acsc, acos) + from sympy.functions.special.gamma_functions import gamma + from sympy.matrices.dense import (eye, zeros, diag, Matrix, + ones, symarray) + from sympy.matrices.immutable import ImmutableMatrix + from sympy.matrices.matrixbase import MatrixBase + from sympy.utilities.lambdify import lambdify + + +# +# XXX: Handling of immutable and mutable matrices in SymEngine is inconsistent +# with SymPy's matrix classes in at least SymEngine version 0.7.0. Until that +# is fixed the function below is needed for consistent behaviour when +# attempting to simplify a matrix. +# +# Expected behaviour of a SymPy mutable/immutable matrix .simplify() method: +# +# Matrix.simplify() : works in place, returns None +# ImmutableMatrix.simplify() : returns a simplified copy +# +# In SymEngine both mutable and immutable matrices simplify in place and return +# None. This is inconsistent with the matrix being "immutable" and also the +# returned None leads to problems in the mechanics module. +# +# The simplify function should not be used because simplify(M) sympifies the +# matrix M and the SymEngine matrices all sympify to SymPy matrices. If we want +# to work with SymEngine matrices then we need to use their .simplify() method +# but that method does not work correctly with immutable matrices. +# +# The _simplify_matrix function can be removed when the SymEngine bug is fixed. +# Since this should be a temporary problem we do not make this function part of +# the public API. +# +# SymEngine issue: https://github.com/symengine/symengine.py/issues/363 +# + +def _simplify_matrix(M): + """Return a simplified copy of the matrix M""" + if not isinstance(M, (Matrix, ImmutableMatrix)): + raise TypeError("The matrix M must be an instance of Matrix or ImmutableMatrix") + Mnew = M.as_mutable() # makes a copy if mutable + Mnew.simplify() + if isinstance(M, ImmutableMatrix): + Mnew = Mnew.as_immutable() + return Mnew + + +__all__ = [ + 'Symbol', 'Integer', 'sympify', 'S', 'SympifyError', 'exp', 'log', + 'gamma', 'sqrt', 'I', 'E', 'pi', 'Matrix', 'sin', 'cos', 'tan', 'cot', + 'csc', 'sec', 'asin', 'acos', 'atan', 'acot', 'acsc', 'asec', 'sinh', + 'cosh', 'tanh', 'coth', 'asinh', 'acosh', 'atanh', 'acoth', 'lambdify', + 'symarray', 'diff', 'zeros', 'eye', 'diag', 'ones', 'expand', 'Function', + 'symbols', 'var', 'Add', 'Mul', 'Derivative', 'ImmutableMatrix', + 'MatrixBase', 'Rational', 'Basic', 'igcd', 'AppliedUndef', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/basic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/basic.py new file mode 100644 index 0000000000000000000000000000000000000000..92f6e710113ce0523ad15100abb0acd00f03f741 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/basic.py @@ -0,0 +1,2355 @@ +"""Base class for all the objects in SymPy""" +from __future__ import annotations + +from collections import Counter +from collections.abc import Mapping, Iterable +from itertools import zip_longest +from functools import cmp_to_key +from typing import TYPE_CHECKING, overload + +from .assumptions import _prepare_class_assumptions +from .cache import cacheit +from .sympify import _sympify, sympify, SympifyError, _external_converter +from .sorting import ordered +from .kind import Kind, UndefinedKind +from ._print_helpers import Printable + +from sympy.utilities.decorator import deprecated +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import iterable, numbered_symbols +from sympy.utilities.misc import filldedent, func_name + + +if TYPE_CHECKING: + from typing import ClassVar, TypeVar, Any + from typing_extensions import Self + from .assumptions import StdFactKB + from .symbol import Symbol + + Tbasic = TypeVar("Tbasic", bound='Basic') + + +def as_Basic(expr): + """Return expr as a Basic instance using strict sympify + or raise a TypeError; this is just a wrapper to _sympify, + raising a TypeError instead of a SympifyError.""" + try: + return _sympify(expr) + except SympifyError: + raise TypeError( + 'Argument must be a Basic object, not `%s`' % func_name( + expr)) + + +# Key for sorting commutative args in canonical order +# by name. This is used for canonical ordering of the +# args for Add and Mul *if* the names of both classes +# being compared appear here. Some things in this list +# are not spelled the same as their name so they do not, +# in effect, appear here. See Basic.compare. +ordering_of_classes = [ + # singleton numbers + 'Zero', 'One', 'Half', 'Infinity', 'NaN', 'NegativeOne', 'NegativeInfinity', + # numbers + 'Integer', 'Rational', 'Float', + # singleton symbols + 'Exp1', 'Pi', 'ImaginaryUnit', + # symbols + 'Symbol', 'Wild', + # arithmetic operations + 'Pow', 'Mul', 'Add', + # function values + 'Derivative', 'Integral', + # defined singleton functions + 'Abs', 'Sign', 'Sqrt', + 'Floor', 'Ceiling', + 'Re', 'Im', 'Arg', + 'Conjugate', + 'Exp', 'Log', + 'Sin', 'Cos', 'Tan', 'Cot', 'ASin', 'ACos', 'ATan', 'ACot', + 'Sinh', 'Cosh', 'Tanh', 'Coth', 'ASinh', 'ACosh', 'ATanh', 'ACoth', + 'RisingFactorial', 'FallingFactorial', + 'factorial', 'binomial', + 'Gamma', 'LowerGamma', 'UpperGamma', 'PolyGamma', + 'Erf', + # special polynomials + 'Chebyshev', 'Chebyshev2', + # undefined functions + 'Function', 'WildFunction', + # anonymous functions + 'Lambda', + # Landau O symbol + 'Order', + # relational operations + 'Equality', 'Unequality', 'StrictGreaterThan', 'StrictLessThan', + 'GreaterThan', 'LessThan', +] + +def _cmp_name(x: type, y: type) -> int: + """return -1, 0, 1 if the name of x is before that of y. + A string comparison is done if either name does not appear + in `ordering_of_classes`. This is the helper for + ``Basic.compare`` + + Examples + ======== + + >>> from sympy import cos, tan, sin + >>> from sympy.core import basic + >>> save = basic.ordering_of_classes + >>> basic.ordering_of_classes = () + >>> basic._cmp_name(cos, tan) + -1 + >>> basic.ordering_of_classes = ["tan", "sin", "cos"] + >>> basic._cmp_name(cos, tan) + 1 + >>> basic._cmp_name(sin, cos) + -1 + >>> basic.ordering_of_classes = save + + """ + n1 = x.__name__ + n2 = y.__name__ + if n1 == n2: + return 0 + + # If the other object is not a Basic subclass, then we are not equal to it. + if not issubclass(y, Basic): + return -1 + + UNKNOWN = len(ordering_of_classes) + 1 + try: + i1 = ordering_of_classes.index(n1) + except ValueError: + i1 = UNKNOWN + try: + i2 = ordering_of_classes.index(n2) + except ValueError: + i2 = UNKNOWN + if i1 == UNKNOWN and i2 == UNKNOWN: + return (n1 > n2) - (n1 < n2) + return (i1 > i2) - (i1 < i2) + + + +@cacheit +def _get_postprocessors(clsname, arg_type): + # Since only Add, Mul, Pow can be clsname, this cache + # is not quadratic. + postprocessors = set() + mappings = _get_postprocessors_for_type(arg_type) + for mapping in mappings: + f = mapping.get(clsname, None) + if f is not None: + postprocessors.update(f) + return postprocessors + +@cacheit +def _get_postprocessors_for_type(arg_type): + return tuple( + Basic._constructor_postprocessor_mapping[cls] + for cls in arg_type.mro() + if cls in Basic._constructor_postprocessor_mapping + ) + + +class Basic(Printable): + """ + Base class for all SymPy objects. + + Notes and conventions + ===================== + + 1) Always use ``.args``, when accessing parameters of some instance: + + >>> from sympy import cot + >>> from sympy.abc import x, y + + >>> cot(x).args + (x,) + + >>> cot(x).args[0] + x + + >>> (x*y).args + (x, y) + + >>> (x*y).args[1] + y + + + 2) Never use internal methods or variables (the ones prefixed with ``_``): + + >>> cot(x)._args # do not use this, use cot(x).args instead + (x,) + + + 3) By "SymPy object" we mean something that can be returned by + ``sympify``. But not all objects one encounters using SymPy are + subclasses of Basic. For example, mutable objects are not: + + >>> from sympy import Basic, Matrix, sympify + >>> A = Matrix([[1, 2], [3, 4]]).as_mutable() + >>> isinstance(A, Basic) + False + + >>> B = sympify(A) + >>> isinstance(B, Basic) + True + """ + __slots__ = ('_mhash', # hash value + '_args', # arguments + '_assumptions' + ) + + _args: tuple[Basic, ...] + _mhash: int | None + + @property + def __sympy__(self): + return True + + def __init_subclass__(cls): + # Initialize the default_assumptions FactKB and also any assumptions + # property methods. This method will only be called for subclasses of + # Basic but not for Basic itself so we call + # _prepare_class_assumptions(Basic) below the class definition. + super().__init_subclass__() + _prepare_class_assumptions(cls) + + # To be overridden with True in the appropriate subclasses + is_number = False + is_Atom = False + is_Symbol = False + is_symbol = False + is_Indexed = False + is_Dummy = False + is_Wild = False + is_Function = False + is_Add = False + is_Mul = False + is_Pow = False + is_Number = False + is_Float = False + is_Rational = False + is_Integer = False + is_NumberSymbol = False + is_Order = False + is_Derivative = False + is_Piecewise = False + is_Poly = False + is_AlgebraicNumber = False + is_Relational = False + is_Equality = False + is_Boolean = False + is_Not = False + is_Matrix = False + is_Vector = False + is_Point = False + is_MatAdd = False + is_MatMul = False + + default_assumptions: ClassVar[StdFactKB] + + is_composite: bool | None + is_noninteger: bool | None + is_extended_positive: bool | None + is_negative: bool | None + is_complex: bool | None + is_extended_nonpositive: bool | None + is_integer: bool | None + is_positive: bool | None + is_rational: bool | None + is_extended_nonnegative: bool | None + is_infinite: bool | None + is_antihermitian: bool | None + is_extended_negative: bool | None + is_extended_real: bool | None + is_finite: bool | None + is_polar: bool | None + is_imaginary: bool | None + is_transcendental: bool | None + is_extended_nonzero: bool | None + is_nonzero: bool | None + is_odd: bool | None + is_algebraic: bool | None + is_prime: bool | None + is_commutative: bool | None + is_nonnegative: bool | None + is_nonpositive: bool | None + is_hermitian: bool | None + is_irrational: bool | None + is_real: bool | None + is_zero: bool | None + is_even: bool | None + + kind: Kind = UndefinedKind + + def __new__(cls, *args): + obj = object.__new__(cls) + obj._assumptions = cls.default_assumptions + obj._mhash = None # will be set by __hash__ method. + + obj._args = args # all items in args must be Basic objects + return obj + + def copy(self): + return self.func(*self.args) + + def __getnewargs__(self): + return self.args + + def __getstate__(self): + return None + + def __setstate__(self, state): + for name, value in state.items(): + setattr(self, name, value) + + def __reduce_ex__(self, protocol): + if protocol < 2: + msg = "Only pickle protocol 2 or higher is supported by SymPy" + raise NotImplementedError(msg) + return super().__reduce_ex__(protocol) + + def __hash__(self) -> int: + # hash cannot be cached using cache_it because infinite recurrence + # occurs as hash is needed for setting cache dictionary keys + h = self._mhash + if h is None: + h = hash((type(self).__name__,) + self._hashable_content()) + self._mhash = h + return h + + def _hashable_content(self): + """Return a tuple of information about self that can be used to + compute the hash. If a class defines additional attributes, + like ``name`` in Symbol, then this method should be updated + accordingly to return such relevant attributes. + + Defining more than _hashable_content is necessary if __eq__ has + been defined by a class. See note about this in Basic.__eq__.""" + return self._args + + @property + def assumptions0(self): + """ + Return object `type` assumptions. + + For example: + + Symbol('x', real=True) + Symbol('x', integer=True) + + are different objects. In other words, besides Python type (Symbol in + this case), the initial assumptions are also forming their typeinfo. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.abc import x + >>> x.assumptions0 + {'commutative': True} + >>> x = Symbol("x", positive=True) + >>> x.assumptions0 + {'commutative': True, 'complex': True, 'extended_negative': False, + 'extended_nonnegative': True, 'extended_nonpositive': False, + 'extended_nonzero': True, 'extended_positive': True, 'extended_real': + True, 'finite': True, 'hermitian': True, 'imaginary': False, + 'infinite': False, 'negative': False, 'nonnegative': True, + 'nonpositive': False, 'nonzero': True, 'positive': True, 'real': + True, 'zero': False} + """ + return {} + + def compare(self, other): + """ + Return -1, 0, 1 if the object is less than, equal, + or greater than other in a canonical sense. + Non-Basic are always greater than Basic. + If both names of the classes being compared appear + in the `ordering_of_classes` then the ordering will + depend on the appearance of the names there. + If either does not appear in that list, then the + comparison is based on the class name. + If the names are the same then a comparison is made + on the length of the hashable content. + Items of the equal-lengthed contents are then + successively compared using the same rules. If there + is never a difference then 0 is returned. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> x.compare(y) + -1 + >>> x.compare(x) + 0 + >>> y.compare(x) + 1 + + """ + # all redefinitions of __cmp__ method should start with the + # following lines: + if self is other: + return 0 + n1 = self.__class__ + n2 = other.__class__ + c = _cmp_name(n1, n2) + if c: + return c + # + st = self._hashable_content() + ot = other._hashable_content() + len_st = len(st) + len_ot = len(ot) + c = (len_st > len_ot) - (len_st < len_ot) + if c: + return c + for l, r in zip(st, ot): + if isinstance(l, Basic): + c = l.compare(r) + elif isinstance(l, frozenset): + l = Basic(*l) if isinstance(l, frozenset) else l + r = Basic(*r) if isinstance(r, frozenset) else r + c = l.compare(r) + else: + c = (l > r) - (l < r) + if c: + return c + return 0 + + @classmethod + def fromiter(cls, args, **assumptions): + """ + Create a new object from an iterable. + + This is a convenience function that allows one to create objects from + any iterable, without having to convert to a list or tuple first. + + Examples + ======== + + >>> from sympy import Tuple + >>> Tuple.fromiter(i for i in range(5)) + (0, 1, 2, 3, 4) + + """ + return cls(*tuple(args), **assumptions) + + @classmethod + def class_key(cls) -> tuple[int, int, str]: + """Nice order of classes.""" + return 5, 0, cls.__name__ + + @cacheit + def sort_key(self, order=None): + """ + Return a sort key. + + Examples + ======== + + >>> from sympy import S, I + + >>> sorted([S(1)/2, I, -I], key=lambda x: x.sort_key()) + [1/2, -I, I] + + >>> S("[x, 1/x, 1/x**2, x**2, x**(1/2), x**(1/4), x**(3/2)]") + [x, 1/x, x**(-2), x**2, sqrt(x), x**(1/4), x**(3/2)] + >>> sorted(_, key=lambda x: x.sort_key()) + [x**(-2), 1/x, x**(1/4), sqrt(x), x, x**(3/2), x**2] + + """ + + # XXX: remove this when issue 5169 is fixed + def inner_key(arg): + if isinstance(arg, Basic): + return arg.sort_key(order) + else: + return arg + + args = self._sorted_args + args = len(args), tuple([inner_key(arg) for arg in args]) + return self.class_key(), args, S.One.sort_key(), S.One + + def _do_eq_sympify(self, other): + """Returns a boolean indicating whether a == b when either a + or b is not a Basic. This is only done for types that were either + added to `converter` by a 3rd party or when the object has `_sympy_` + defined. This essentially reuses the code in `_sympify` that is + specific for this use case. Non-user defined types that are meant + to work with SymPy should be handled directly in the __eq__ methods + of the `Basic` classes it could equate to and not be converted. Note + that after conversion, `==` is used again since it is not + necessarily clear whether `self` or `other`'s __eq__ method needs + to be used.""" + for superclass in type(other).__mro__: + conv = _external_converter.get(superclass) + if conv is not None: + return self == conv(other) + if hasattr(other, '_sympy_'): + return self == other._sympy_() + return NotImplemented + + def __eq__(self, other): + """Return a boolean indicating whether a == b on the basis of + their symbolic trees. + + This is the same as a.compare(b) == 0 but faster. + + Notes + ===== + + If a class that overrides __eq__() needs to retain the + implementation of __hash__() from a parent class, the + interpreter must be told this explicitly by setting + __hash__ : Callable[[object], int] = .__hash__. + Otherwise the inheritance of __hash__() will be blocked, + just as if __hash__ had been explicitly set to None. + + References + ========== + + from https://docs.python.org/dev/reference/datamodel.html#object.__hash__ + """ + if self is other: + return True + + if not isinstance(other, Basic): + return self._do_eq_sympify(other) + + # check for pure number expr + if not (self.is_Number and other.is_Number) and ( + type(self) != type(other)): + return False + a, b = self._hashable_content(), other._hashable_content() + if a != b: + return False + # check number *in* an expression + for a, b in zip(a, b): + if not isinstance(a, Basic): + continue + if a.is_Number and type(a) != type(b): + return False + return True + + def __ne__(self, other): + """``a != b`` -> Compare two symbolic trees and see whether they are different + + this is the same as: + + ``a.compare(b) != 0`` + + but faster + """ + return not self == other + + def dummy_eq(self, other, symbol=None): + """ + Compare two expressions and handle dummy symbols. + + Examples + ======== + + >>> from sympy import Dummy + >>> from sympy.abc import x, y + + >>> u = Dummy('u') + + >>> (u**2 + 1).dummy_eq(x**2 + 1) + True + >>> (u**2 + 1) == (x**2 + 1) + False + + >>> (u**2 + y).dummy_eq(x**2 + y, x) + True + >>> (u**2 + y).dummy_eq(x**2 + y, y) + False + + """ + s = self.as_dummy() + o = _sympify(other) + o = o.as_dummy() + + dummy_symbols = [i for i in s.free_symbols if i.is_Dummy] + + if len(dummy_symbols) == 1: + dummy = dummy_symbols.pop() + else: + return s == o + + if symbol is None: + symbols = o.free_symbols + + if len(symbols) == 1: + symbol = symbols.pop() + else: + return s == o + + tmp = dummy.__class__() + + return s.xreplace({dummy: tmp}) == o.xreplace({symbol: tmp}) + + @overload + def atoms(self) -> set[Basic]: ... + @overload + def atoms(self, *types: Tbasic | type[Tbasic]) -> set[Tbasic]: ... + + def atoms(self, *types: Tbasic | type[Tbasic]) -> set[Basic] | set[Tbasic]: + """Returns the atoms that form the current object. + + By default, only objects that are truly atomic and cannot + be divided into smaller pieces are returned: symbols, numbers, + and number symbols like I and pi. It is possible to request + atoms of any type, however, as demonstrated below. + + Examples + ======== + + >>> from sympy import I, pi, sin + >>> from sympy.abc import x, y + >>> (1 + x + 2*sin(y + I*pi)).atoms() + {1, 2, I, pi, x, y} + + If one or more types are given, the results will contain only + those types of atoms. + + >>> from sympy import Number, NumberSymbol, Symbol + >>> (1 + x + 2*sin(y + I*pi)).atoms(Symbol) + {x, y} + + >>> (1 + x + 2*sin(y + I*pi)).atoms(Number) + {1, 2} + + >>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol) + {1, 2, pi} + + >>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol, I) + {1, 2, I, pi} + + Note that I (imaginary unit) and zoo (complex infinity) are special + types of number symbols and are not part of the NumberSymbol class. + + The type can be given implicitly, too: + + >>> (1 + x + 2*sin(y + I*pi)).atoms(x) # x is a Symbol + {x, y} + + Be careful to check your assumptions when using the implicit option + since ``S(1).is_Integer = True`` but ``type(S(1))`` is ``One``, a special type + of SymPy atom, while ``type(S(2))`` is type ``Integer`` and will find all + integers in an expression: + + >>> from sympy import S + >>> (1 + x + 2*sin(y + I*pi)).atoms(S(1)) + {1} + + >>> (1 + x + 2*sin(y + I*pi)).atoms(S(2)) + {1, 2} + + Finally, arguments to atoms() can select more than atomic atoms: any + SymPy type (loaded in core/__init__.py) can be listed as an argument + and those types of "atoms" as found in scanning the arguments of the + expression recursively: + + >>> from sympy import Function, Mul + >>> from sympy.core.function import AppliedUndef + >>> f = Function('f') + >>> (1 + f(x) + 2*sin(y + I*pi)).atoms(Function) + {f(x), sin(y + I*pi)} + >>> (1 + f(x) + 2*sin(y + I*pi)).atoms(AppliedUndef) + {f(x)} + + >>> (1 + x + 2*sin(y + I*pi)).atoms(Mul) + {I*pi, 2*sin(y + I*pi)} + + """ + nodes = _preorder_traversal(self) + if types: + types2 = tuple([t if isinstance(t, type) else type(t) for t in types]) + return {node for node in nodes if isinstance(node, types2)} + else: + return {node for node in nodes if not node.args} + + @property + def free_symbols(self) -> set[Basic]: + """Return from the atoms of self those which are free symbols. + + Not all free symbols are ``Symbol`` (see examples) + + For most expressions, all symbols are free symbols. For some classes + this is not true. e.g. Integrals use Symbols for the dummy variables + which are bound variables, so Integral has a method to return all + symbols except those. Derivative keeps track of symbols with respect + to which it will perform a derivative; those are + bound variables, too, so it has its own free_symbols method. + + Any other method that uses bound variables should implement a + free_symbols method. + + Examples + ======== + + >>> from sympy import Derivative, Integral, IndexedBase + >>> from sympy.abc import x, y, n + >>> (x + 1).free_symbols + {x} + >>> Integral(x, y).free_symbols + {x, y} + + Not all free symbols are actually symbols: + + >>> IndexedBase('F')[0].free_symbols + {F, F[0]} + + The symbols of differentiation are not included unless they + appear in the expression being differentiated. + + >>> Derivative(x + y, y).free_symbols + {x, y} + >>> Derivative(x, y).free_symbols + {x} + >>> Derivative(x, (y, n)).free_symbols + {n, x} + + If you want to know if a symbol is in the variables of the + Derivative you can do so as follows: + + >>> Derivative(x, y).has_free(y) + True + """ + empty: set[Basic] = set() + return empty.union(*(a.free_symbols for a in self.args)) + + @property + def expr_free_symbols(self): + sympy_deprecation_warning(""" + The expr_free_symbols property is deprecated. Use free_symbols to get + the free symbols of an expression. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-expr-free-symbols") + return set() + + def as_dummy(self) -> "Self": + """Return the expression with any objects having structurally + bound symbols replaced with unique, canonical symbols within + the object in which they appear and having only the default + assumption for commutativity being True. When applied to a + symbol a new symbol having only the same commutativity will be + returned. + + Examples + ======== + + >>> from sympy import Integral, Symbol + >>> from sympy.abc import x + >>> r = Symbol('r', real=True) + >>> Integral(r, (r, x)).as_dummy() + Integral(_0, (_0, x)) + >>> _.variables[0].is_real is None + True + >>> r.as_dummy() + _r + + Notes + ===== + + Any object that has structurally bound variables should have + a property, ``bound_symbols`` that returns those symbols + appearing in the object. + """ + from .symbol import Dummy, Symbol + def can(x): + # mask free that shadow bound + free = x.free_symbols + bound = set(x.bound_symbols) + d = {i: Dummy() for i in bound & free} + x = x.subs(d) + # replace bound with canonical names + x = x.xreplace(x.canonical_variables) + # return after undoing masking + return x.xreplace({v: k for k, v in d.items()}) + if not self.has(Symbol): + return self + return self.replace( + lambda x: hasattr(x, 'bound_symbols'), + can, + simultaneous=False) # type:ignore + + @property + def canonical_variables(self) -> dict[Basic, Symbol]: + """Return a dictionary mapping any variable defined in + ``self.bound_symbols`` to Symbols that do not clash + with any free symbols in the expression. + + Examples + ======== + + >>> from sympy import Lambda + >>> from sympy.abc import x + >>> Lambda(x, 2*x).canonical_variables + {x: _0} + """ + bound: list[Basic] | None = getattr(self, 'bound_symbols', None) + if bound is None: + return {} + dums = numbered_symbols('_') + reps = {} + # watch out for free symbol that are not in bound symbols; + # those that are in bound symbols are about to get changed + + # XXX: free_symbols only returns particular kinds of expressions that + # generally have a .name attribute. There is not a proper class/type + # that represents this. + names = {i.name for i in self.free_symbols - set(bound)} # type: ignore + for b in bound: + d = next(dums) + if b.is_Symbol: + while d.name in names: + d = next(dums) + reps[b] = d + return reps + + def rcall(self, *args): + """Apply on the argument recursively through the expression tree. + + This method is used to simulate a common abuse of notation for + operators. For instance, in SymPy the following will not work: + + ``(x+Lambda(y, 2*y))(z) == x+2*z``, + + however, you can use: + + >>> from sympy import Lambda + >>> from sympy.abc import x, y, z + >>> (x + Lambda(y, 2*y)).rcall(z) + x + 2*z + """ + if callable(self): + return self(*args) + elif self.args: + newargs = [sub.rcall(*args) for sub in self.args] + return self.func(*newargs) + else: + return self + + def is_hypergeometric(self, k): + from sympy.simplify.simplify import hypersimp + from sympy.functions.elementary.piecewise import Piecewise + if self.has(Piecewise): + return None + return hypersimp(self, k) is not None + + @property + def is_comparable(self): + """Return True if self can be computed to a real number + (or already is a real number) with precision, else False. + + Examples + ======== + + >>> from sympy import exp_polar, pi, I + >>> (I*exp_polar(I*pi/2)).is_comparable + True + >>> (I*exp_polar(I*pi*2)).is_comparable + False + + A False result does not mean that `self` cannot be rewritten + into a form that would be comparable. For example, the + difference computed below is zero but without simplification + it does not evaluate to a zero with precision: + + >>> e = 2**pi*(1 + 2**pi) + >>> dif = e - e.expand() + >>> dif.is_comparable + False + >>> dif.n(2)._prec + 1 + + """ + return self._eval_is_comparable() + + def _eval_is_comparable(self) -> bool: + # Expr.is_comparable overrides this + return False + + @property + def func(self): + """ + The top-level function in an expression. + + The following should hold for all objects:: + + >> x == x.func(*x.args) + + Examples + ======== + + >>> from sympy.abc import x + >>> a = 2*x + >>> a.func + + >>> a.args + (2, x) + >>> a.func(*a.args) + 2*x + >>> a == a.func(*a.args) + True + + """ + return self.__class__ + + @property + def args(self) -> tuple[Basic, ...]: + """Returns a tuple of arguments of 'self'. + + Examples + ======== + + >>> from sympy import cot + >>> from sympy.abc import x, y + + >>> cot(x).args + (x,) + + >>> cot(x).args[0] + x + + >>> (x*y).args + (x, y) + + >>> (x*y).args[1] + y + + Notes + ===== + + Never use self._args, always use self.args. + Only use _args in __new__ when creating a new function. + Do not override .args() from Basic (so that it is easy to + change the interface in the future if needed). + """ + return self._args + + @property + def _sorted_args(self): + """ + The same as ``args``. Derived classes which do not fix an + order on their arguments should override this method to + produce the sorted representation. + """ + return self.args + + def as_content_primitive(self, radical=False, clear=True): + """A stub to allow Basic args (like Tuple) to be skipped when computing + the content and primitive components of an expression. + + See Also + ======== + + sympy.core.expr.Expr.as_content_primitive + """ + return S.One, self + + @overload + def subs(self, arg1: Mapping[Basic | complex, Basic | complex], arg2: None=None, **kwargs: Any) -> Basic: ... + @overload + def subs(self, arg1: Iterable[tuple[Basic | complex, Basic | complex]], arg2: None=None, **kwargs: Any) -> Basic: ... + @overload + def subs(self, arg1: Basic | complex, arg2: Basic | complex, **kwargs: Any) -> Basic: ... + + def subs(self, arg1: Mapping[Basic | complex, Basic | complex] + | Iterable[tuple[Basic | complex, Basic | complex]] | Basic | complex, + arg2: Basic | complex | None = None, **kwargs: Any) -> Basic: + """ + Substitutes old for new in an expression after sympifying args. + + `args` is either: + - two arguments, e.g. foo.subs(old, new) + - one iterable argument, e.g. foo.subs(iterable). The iterable may be + o an iterable container with (old, new) pairs. In this case the + replacements are processed in the order given with successive + patterns possibly affecting replacements already made. + o a dict or set whose key/value items correspond to old/new pairs. + In this case the old/new pairs will be sorted by op count and in + case of a tie, by number of args and the default_sort_key. The + resulting sorted list is then processed as an iterable container + (see previous). + + If the keyword ``simultaneous`` is True, the subexpressions will not be + evaluated until all the substitutions have been made. + + Examples + ======== + + >>> from sympy import pi, exp, limit, oo + >>> from sympy.abc import x, y + >>> (1 + x*y).subs(x, pi) + pi*y + 1 + >>> (1 + x*y).subs({x:pi, y:2}) + 1 + 2*pi + >>> (1 + x*y).subs([(x, pi), (y, 2)]) + 1 + 2*pi + >>> reps = [(y, x**2), (x, 2)] + >>> (x + y).subs(reps) + 6 + >>> (x + y).subs(reversed(reps)) + x**2 + 2 + + >>> (x**2 + x**4).subs(x**2, y) + y**2 + y + + To replace only the x**2 but not the x**4, use xreplace: + + >>> (x**2 + x**4).xreplace({x**2: y}) + x**4 + y + + To delay evaluation until all substitutions have been made, + set the keyword ``simultaneous`` to True: + + >>> (x/y).subs([(x, 0), (y, 0)]) + 0 + >>> (x/y).subs([(x, 0), (y, 0)], simultaneous=True) + nan + + This has the added feature of not allowing subsequent substitutions + to affect those already made: + + >>> ((x + y)/y).subs({x + y: y, y: x + y}) + 1 + >>> ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True) + y/(x + y) + + In order to obtain a canonical result, unordered iterables are + sorted by count_op length, number of arguments and by the + default_sort_key to break any ties. All other iterables are left + unsorted. + + >>> from sympy import sqrt, sin, cos + >>> from sympy.abc import a, b, c, d, e + + >>> A = (sqrt(sin(2*x)), a) + >>> B = (sin(2*x), b) + >>> C = (cos(2*x), c) + >>> D = (x, d) + >>> E = (exp(x), e) + + >>> expr = sqrt(sin(2*x))*sin(exp(x)*x)*cos(2*x) + sin(2*x) + + >>> expr.subs(dict([A, B, C, D, E])) + a*c*sin(d*e) + b + + The resulting expression represents a literal replacement of the + old arguments with the new arguments. This may not reflect the + limiting behavior of the expression: + + >>> (x**3 - 3*x).subs({x: oo}) + nan + + >>> limit(x**3 - 3*x, x, oo) + oo + + If the substitution will be followed by numerical + evaluation, it is better to pass the substitution to + evalf as + + >>> (1/x).evalf(subs={x: 3.0}, n=21) + 0.333333333333333333333 + + rather than + + >>> (1/x).subs({x: 3.0}).evalf(21) + 0.333333333333333314830 + + as the former will ensure that the desired level of precision is + obtained. + + See Also + ======== + replace: replacement capable of doing wildcard-like matching, + parsing of match, and conditional replacements + xreplace: exact node replacement in expr tree; also capable of + using matching rules + sympy.core.evalf.EvalfMixin.evalf: calculates the given formula to a desired level of precision + + """ + from .containers import Dict + from .symbol import Dummy, Symbol + from .numbers import _illegal + + items: Iterable[tuple[Basic | complex, Basic | complex]] + + unordered = False + if arg2 is None: + + if isinstance(arg1, set): + items = arg1 + unordered = True + elif isinstance(arg1, (Dict, Mapping)): + unordered = True + items = arg1.items() # type: ignore + elif not iterable(arg1): + raise ValueError(filldedent(""" + When a single argument is passed to subs + it should be a dictionary of old: new pairs or an iterable + of (old, new) tuples.""")) + else: + items = arg1 # type: ignore + else: + items = [(arg1, arg2)] # type: ignore + + def sympify_old(old) -> Basic: + if isinstance(old, str): + # Use Symbol rather than parse_expr for old + return Symbol(old) + elif isinstance(old, type): + # Allow a type e.g. Function('f') or sin + return sympify(old, strict=False) + else: + return sympify(old, strict=True) + + def sympify_new(new) -> Basic: + if isinstance(new, (str, type)): + # Allow a type or parse a string input + return sympify(new, strict=False) + else: + return sympify(new, strict=True) + + sequence = [(sympify_old(s1), sympify_new(s2)) for s1, s2 in items] + + # skip if there is no change + sequence = [(s1, s2) for s1, s2 in sequence if not _aresame(s1, s2)] + + simultaneous = kwargs.pop('simultaneous', False) + + if unordered: + from .sorting import _nodes, default_sort_key + sequence_dict = dict(sequence) + # order so more complex items are first and items + # of identical complexity are ordered so + # f(x) < f(y) < x < y + # \___ 2 __/ \_1_/ <- number of nodes + # + # For more complex ordering use an unordered sequence. + k = list(ordered(sequence_dict, default=False, keys=( + lambda x: -_nodes(x), + default_sort_key, + ))) + sequence = [(k, sequence_dict[k]) for k in k] + # do infinities first + if not simultaneous: + redo = [i for i, seq in enumerate(sequence) if seq[1] in _illegal] + for i in reversed(redo): + sequence.insert(0, sequence.pop(i)) + + if simultaneous: # XXX should this be the default for dict subs? + reps = {} + rv = self + kwargs['hack2'] = True + m = Dummy('subs_m') + for old, new in sequence: + com = new.is_commutative + if com is None: + com = True + d = Dummy('subs_d', commutative=com) + # using d*m so Subs will be used on dummy variables + # in things like Derivative(f(x, y), x) in which x + # is both free and bound + rv = rv._subs(old, d*m, **kwargs) + if not isinstance(rv, Basic): + break + reps[d] = new + reps[m] = S.One # get rid of m + return rv.xreplace(reps) + else: + rv = self + for old, new in sequence: + rv = rv._subs(old, new, **kwargs) + if not isinstance(rv, Basic): + break + return rv + + @cacheit + def _subs(self, old, new, **hints): + """Substitutes an expression old -> new. + + If self is not equal to old then _eval_subs is called. + If _eval_subs does not want to make any special replacement + then a None is received which indicates that the fallback + should be applied wherein a search for replacements is made + amongst the arguments of self. + + >>> from sympy import Add + >>> from sympy.abc import x, y, z + + Examples + ======== + + Add's _eval_subs knows how to target x + y in the following + so it makes the change: + + >>> (x + y + z).subs(x + y, 1) + z + 1 + + Add's _eval_subs does not need to know how to find x + y in + the following: + + >>> Add._eval_subs(z*(x + y) + 3, x + y, 1) is None + True + + The returned None will cause the fallback routine to traverse the args and + pass the z*(x + y) arg to Mul where the change will take place and the + substitution will succeed: + + >>> (z*(x + y) + 3).subs(x + y, 1) + z + 3 + + ** Developers Notes ** + + An _eval_subs routine for a class should be written if: + + 1) any arguments are not instances of Basic (e.g. bool, tuple); + + 2) some arguments should not be targeted (as in integration + variables); + + 3) if there is something other than a literal replacement + that should be attempted (as in Piecewise where the condition + may be updated without doing a replacement). + + If it is overridden, here are some special cases that might arise: + + 1) If it turns out that no special change was made and all + the original sub-arguments should be checked for + replacements then None should be returned. + + 2) If it is necessary to do substitutions on a portion of + the expression then _subs should be called. _subs will + handle the case of any sub-expression being equal to old + (which usually would not be the case) while its fallback + will handle the recursion into the sub-arguments. For + example, after Add's _eval_subs removes some matching terms + it must process the remaining terms so it calls _subs + on each of the un-matched terms and then adds them + onto the terms previously obtained. + + 3) If the initial expression should remain unchanged then + the original expression should be returned. (Whenever an + expression is returned, modified or not, no further + substitution of old -> new is attempted.) Sum's _eval_subs + routine uses this strategy when a substitution is attempted + on any of its summation variables. + """ + + def fallback(self, old, new): + """ + Try to replace old with new in any of self's arguments. + """ + hit = False + args = list(self.args) + for i, arg in enumerate(args): + if not hasattr(arg, '_eval_subs'): + continue + arg = arg._subs(old, new, **hints) + if not _aresame(arg, args[i]): + hit = True + args[i] = arg + if hit: + rv = self.func(*args) + hack2 = hints.get('hack2', False) + if hack2 and self.is_Mul and not rv.is_Mul: # 2-arg hack + coeff = S.One + nonnumber = [] + for i in args: + if i.is_Number: + coeff *= i + else: + nonnumber.append(i) + nonnumber = self.func(*nonnumber) + if coeff is S.One: + return nonnumber + else: + return self.func(coeff, nonnumber, evaluate=False) + return rv + return self + + if _aresame(self, old): + return new + + rv = self._eval_subs(old, new) + if rv is None: + rv = fallback(self, old, new) + return rv + + def _eval_subs(self, old, new) -> Basic | None: + """Override this stub if you want to do anything more than + attempt a replacement of old with new in the arguments of self. + + See also + ======== + + _subs + """ + return None + + def xreplace(self, rule): + """ + Replace occurrences of objects within the expression. + + Parameters + ========== + + rule : dict-like + Expresses a replacement rule + + Returns + ======= + + xreplace : the result of the replacement + + Examples + ======== + + >>> from sympy import symbols, pi, exp + >>> x, y, z = symbols('x y z') + >>> (1 + x*y).xreplace({x: pi}) + pi*y + 1 + >>> (1 + x*y).xreplace({x: pi, y: 2}) + 1 + 2*pi + + Replacements occur only if an entire node in the expression tree is + matched: + + >>> (x*y + z).xreplace({x*y: pi}) + z + pi + >>> (x*y*z).xreplace({x*y: pi}) + x*y*z + >>> (2*x).xreplace({2*x: y, x: z}) + y + >>> (2*2*x).xreplace({2*x: y, x: z}) + 4*z + >>> (x + y + 2).xreplace({x + y: 2}) + x + y + 2 + >>> (x + 2 + exp(x + 2)).xreplace({x + 2: y}) + x + exp(y) + 2 + + xreplace does not differentiate between free and bound symbols. In the + following, subs(x, y) would not change x since it is a bound symbol, + but xreplace does: + + >>> from sympy import Integral + >>> Integral(x, (x, 1, 2*x)).xreplace({x: y}) + Integral(y, (y, 1, 2*y)) + + Trying to replace x with an expression raises an error: + + >>> Integral(x, (x, 1, 2*x)).xreplace({x: 2*y}) # doctest: +SKIP + ValueError: Invalid limits given: ((2*y, 1, 4*y),) + + See Also + ======== + replace: replacement capable of doing wildcard-like matching, + parsing of match, and conditional replacements + subs: substitution of subexpressions as defined by the objects + themselves. + + """ + value, _ = self._xreplace(rule) + return value + + def _xreplace(self, rule): + """ + Helper for xreplace. Tracks whether a replacement actually occurred. + """ + if self in rule: + return rule[self], True + elif rule: + args = [] + changed = False + for a in self.args: + _xreplace = getattr(a, '_xreplace', None) + if _xreplace is not None: + a_xr = _xreplace(rule) + args.append(a_xr[0]) + changed |= a_xr[1] + else: + args.append(a) + args = tuple(args) + if changed: + return self.func(*args), True + return self, False + + @cacheit + def has(self, *patterns): + """ + Test whether any subexpression matches any of the patterns. + + Examples + ======== + + >>> from sympy import sin + >>> from sympy.abc import x, y, z + >>> (x**2 + sin(x*y)).has(z) + False + >>> (x**2 + sin(x*y)).has(x, y, z) + True + >>> x.has(x) + True + + Note ``has`` is a structural algorithm with no knowledge of + mathematics. Consider the following half-open interval: + + >>> from sympy import Interval + >>> i = Interval.Lopen(0, 5); i + Interval.Lopen(0, 5) + >>> i.args + (0, 5, True, False) + >>> i.has(4) # there is no "4" in the arguments + False + >>> i.has(0) # there *is* a "0" in the arguments + True + + Instead, use ``contains`` to determine whether a number is in the + interval or not: + + >>> i.contains(4) + True + >>> i.contains(0) + False + + + Note that ``expr.has(*patterns)`` is exactly equivalent to + ``any(expr.has(p) for p in patterns)``. In particular, ``False`` is + returned when the list of patterns is empty. + + >>> x.has() + False + + """ + return self._has(iterargs, *patterns) + + def has_xfree(self, s: set[Basic]): + """Return True if self has any of the patterns in s as a + free argument, else False. This is like `Basic.has_free` + but this will only report exact argument matches. + + Examples + ======== + + >>> from sympy import Function + >>> from sympy.abc import x, y + >>> f = Function('f') + >>> f(x).has_xfree({f}) + False + >>> f(x).has_xfree({f(x)}) + True + >>> f(x + 1).has_xfree({x}) + True + >>> f(x + 1).has_xfree({x + 1}) + True + >>> f(x + y + 1).has_xfree({x + 1}) + False + """ + # protect O(1) containment check by requiring: + if type(s) is not set: + raise TypeError('expecting set argument') + return any(a in s for a in iterfreeargs(self)) + + @cacheit + def has_free(self, *patterns): + """Return True if self has object(s) ``x`` as a free expression + else False. + + Examples + ======== + + >>> from sympy import Integral, Function + >>> from sympy.abc import x, y + >>> f = Function('f') + >>> g = Function('g') + >>> expr = Integral(f(x), (f(x), 1, g(y))) + >>> expr.free_symbols + {y} + >>> expr.has_free(g(y)) + True + >>> expr.has_free(*(x, f(x))) + False + + This works for subexpressions and types, too: + + >>> expr.has_free(g) + True + >>> (x + y + 1).has_free(y + 1) + True + """ + if not patterns: + return False + p0 = patterns[0] + if len(patterns) == 1 and iterable(p0) and not isinstance(p0, Basic): + # Basic can contain iterables (though not non-Basic, ideally) + # but don't encourage mixed passing patterns + raise TypeError(filldedent(''' + Expecting 1 or more Basic args, not a single + non-Basic iterable. Don't forget to unpack + iterables: `eq.has_free(*patterns)`''')) + # try quick test first + s = set(patterns) + rv = self.has_xfree(s) + if rv: + return rv + # now try matching through slower _has + return self._has(iterfreeargs, *patterns) + + def _has(self, iterargs, *patterns): + # separate out types and unhashable objects + type_set = set() # only types + p_set = set() # hashable non-types + for p in patterns: + if isinstance(p, type) and issubclass(p, Basic): + type_set.add(p) + continue + if not isinstance(p, Basic): + try: + p = _sympify(p) + except SympifyError: + continue # Basic won't have this in it + p_set.add(p) # fails if object defines __eq__ but + # doesn't define __hash__ + types = tuple(type_set) # + for i in iterargs(self): # + if i in p_set: # <--- here, too + return True + if isinstance(i, types): + return True + + # use matcher if defined, e.g. operations defines + # matcher that checks for exact subset containment, + # (x + y + 1).has(x + 1) -> True + for i in p_set - type_set: # types don't have matchers + if not hasattr(i, '_has_matcher'): + continue + match = i._has_matcher() + if any(match(arg) for arg in iterargs(self)): + return True + + # no success + return False + + def replace(self, query, value, map=False, simultaneous=True, exact=None) -> Basic: + """ + Replace matching subexpressions of ``self`` with ``value``. + + If ``map = True`` then also return the mapping {old: new} where ``old`` + was a sub-expression found with query and ``new`` is the replacement + value for it. If the expression itself does not match the query, then + the returned value will be ``self.xreplace(map)`` otherwise it should + be ``self.subs(ordered(map.items()))``. + + Traverses an expression tree and performs replacement of matching + subexpressions from the bottom to the top of the tree. The default + approach is to do the replacement in a simultaneous fashion so + changes made are targeted only once. If this is not desired or causes + problems, ``simultaneous`` can be set to False. + + In addition, if an expression containing more than one Wild symbol + is being used to match subexpressions and the ``exact`` flag is None + it will be set to True so the match will only succeed if all non-zero + values are received for each Wild that appears in the match pattern. + Setting this to False accepts a match of 0; while setting it True + accepts all matches that have a 0 in them. See example below for + cautions. + + The list of possible combinations of queries and replacement values + is listed below: + + Examples + ======== + + Initial setup + + >>> from sympy import log, sin, cos, tan, Wild, Mul, Add + >>> from sympy.abc import x, y + >>> f = log(sin(x)) + tan(sin(x**2)) + + 1.1. type -> type + obj.replace(type, newtype) + + When object of type ``type`` is found, replace it with the + result of passing its argument(s) to ``newtype``. + + >>> f.replace(sin, cos) + log(cos(x)) + tan(cos(x**2)) + >>> sin(x).replace(sin, cos, map=True) + (cos(x), {sin(x): cos(x)}) + >>> (x*y).replace(Mul, Add) + x + y + + 1.2. type -> func + obj.replace(type, func) + + When object of type ``type`` is found, apply ``func`` to its + argument(s). ``func`` must be written to handle the number + of arguments of ``type``. + + >>> f.replace(sin, lambda arg: sin(2*arg)) + log(sin(2*x)) + tan(sin(2*x**2)) + >>> (x*y).replace(Mul, lambda *args: sin(2*Mul(*args))) + sin(2*x*y) + + 2.1. pattern -> expr + obj.replace(pattern(wild), expr(wild)) + + Replace subexpressions matching ``pattern`` with the expression + written in terms of the Wild symbols in ``pattern``. + + >>> a, b = map(Wild, 'ab') + >>> f.replace(sin(a), tan(a)) + log(tan(x)) + tan(tan(x**2)) + >>> f.replace(sin(a), tan(a/2)) + log(tan(x/2)) + tan(tan(x**2/2)) + >>> f.replace(sin(a), a) + log(x) + tan(x**2) + >>> (x*y).replace(a*x, a) + y + + Matching is exact by default when more than one Wild symbol + is used: matching fails unless the match gives non-zero + values for all Wild symbols: + + >>> (2*x + y).replace(a*x + b, b - a) + y - 2 + >>> (2*x).replace(a*x + b, b - a) + 2*x + + When set to False, the results may be non-intuitive: + + >>> (2*x).replace(a*x + b, b - a, exact=False) + 2/x + + 2.2. pattern -> func + obj.replace(pattern(wild), lambda wild: expr(wild)) + + All behavior is the same as in 2.1 but now a function in terms of + pattern variables is used rather than an expression: + + >>> f.replace(sin(a), lambda a: sin(2*a)) + log(sin(2*x)) + tan(sin(2*x**2)) + + 3.1. func -> func + obj.replace(filter, func) + + Replace subexpression ``e`` with ``func(e)`` if ``filter(e)`` + is True. + + >>> g = 2*sin(x**3) + >>> g.replace(lambda expr: expr.is_Number, lambda expr: expr**2) + 4*sin(x**9) + + The expression itself is also targeted by the query but is done in + such a fashion that changes are not made twice. + + >>> e = x*(x*y + 1) + >>> e.replace(lambda x: x.is_Mul, lambda x: 2*x) + 2*x*(2*x*y + 1) + + When matching a single symbol, `exact` will default to True, but + this may or may not be the behavior that is desired: + + Here, we want `exact=False`: + + >>> from sympy import Function + >>> f = Function('f') + >>> e = f(1) + f(0) + >>> q = f(a), lambda a: f(a + 1) + >>> e.replace(*q, exact=False) + f(1) + f(2) + >>> e.replace(*q, exact=True) + f(0) + f(2) + + But here, the nature of matching makes selecting + the right setting tricky: + + >>> e = x**(1 + y) + >>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=False) + x + >>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=True) + x**(-x - y + 1) + >>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=False) + x + >>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=True) + x**(1 - y) + + It is probably better to use a different form of the query + that describes the target expression more precisely: + + >>> (1 + x**(1 + y)).replace( + ... lambda x: x.is_Pow and x.exp.is_Add and x.exp.args[0] == 1, + ... lambda x: x.base**(1 - (x.exp - 1))) + ... + x**(1 - y) + 1 + + See Also + ======== + + subs: substitution of subexpressions as defined by the objects + themselves. + xreplace: exact node replacement in expr tree; also capable of + using matching rules + + """ + + try: + query = _sympify(query) + except SympifyError: + pass + try: + value = _sympify(value) + except SympifyError: + pass + if isinstance(query, type): + _query = lambda expr: isinstance(expr, query) + + if isinstance(value, type): + _value = lambda expr, result: value(*expr.args) + elif callable(value): + _value = lambda expr, result: value(*expr.args) + else: + raise TypeError( + "given a type, replace() expects another " + "type or a callable") + elif isinstance(query, Basic): + _query = lambda expr: expr.match(query) + if exact is None: + from .symbol import Wild + exact = (len(query.atoms(Wild)) > 1) + + if isinstance(value, Basic): + if exact: + _value = lambda expr, result: (value.subs(result) + if all(result.values()) else expr) + else: + _value = lambda expr, result: value.subs(result) + elif callable(value): + # match dictionary keys get the trailing underscore stripped + # from them and are then passed as keywords to the callable; + # if ``exact`` is True, only accept match if there are no null + # values amongst those matched. + if exact: + _value = lambda expr, result: (value(** + {str(k)[:-1]: v for k, v in result.items()}) + if all(val for val in result.values()) else expr) + else: + _value = lambda expr, result: value(** + {str(k)[:-1]: v for k, v in result.items()}) + else: + raise TypeError( + "given an expression, replace() expects " + "another expression or a callable") + elif callable(query): + _query = query + + if callable(value): + _value = lambda expr, result: value(expr) + else: + raise TypeError( + "given a callable, replace() expects " + "another callable") + else: + raise TypeError( + "first argument to replace() must be a " + "type, an expression or a callable") + + def walk(rv, F): + """Apply ``F`` to args and then to result. + """ + args = getattr(rv, 'args', None) + if args is not None: + if args: + newargs = tuple([walk(a, F) for a in args]) + if args != newargs: + rv = rv.func(*newargs) + if simultaneous: + # if rv is something that was already + # matched (that was changed) then skip + # applying F again + for i, e in enumerate(args): + if rv == e and e != newargs[i]: + return rv + rv = F(rv) + return rv + + mapping = {} # changes that took place + + def rec_replace(expr): + result = _query(expr) + if result or result == {}: + v = _value(expr, result) + if v is not None and v != expr: + if map: + mapping[expr] = v + expr = v + return expr + + rv = walk(self, rec_replace) + return (rv, mapping) if map else rv # type: ignore + + def find(self, query, group=False): + """Find all subexpressions matching a query.""" + query = _make_find_query(query) + results = list(filter(query, _preorder_traversal(self))) + + if not group: + return set(results) + return dict(Counter(results)) + + def count(self, query): + """Count the number of matching subexpressions.""" + query = _make_find_query(query) + return sum(bool(query(sub)) for sub in _preorder_traversal(self)) + + def matches(self, expr, repl_dict=None, old=False): + """ + Helper method for match() that looks for a match between Wild symbols + in self and expressions in expr. + + Examples + ======== + + >>> from sympy import symbols, Wild, Basic + >>> a, b, c = symbols('a b c') + >>> x = Wild('x') + >>> Basic(a + x, x).matches(Basic(a + b, c)) is None + True + >>> Basic(a + x, x).matches(Basic(a + b + c, b + c)) + {x_: b + c} + """ + expr = sympify(expr) + if not isinstance(expr, self.__class__): + return None + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + if self == expr: + return repl_dict + + if len(self.args) != len(expr.args): + return None + + d = repl_dict # already a copy + for arg, other_arg in zip(self.args, expr.args): + if arg == other_arg: + continue + if arg.is_Relational: + try: + d = arg.xreplace(d).matches(other_arg, d, old=old) + except TypeError: # Should be InvalidComparisonError when introduced + d = None + else: + d = arg.xreplace(d).matches(other_arg, d, old=old) + if d is None: + return None + return d + + def match(self, pattern, old=False): + """ + Pattern matching. + + Wild symbols match all. + + Return ``None`` when expression (self) does not match with pattern. + Otherwise return a dictionary such that:: + + pattern.xreplace(self.match(pattern)) == self + + Examples + ======== + + >>> from sympy import Wild, Sum + >>> from sympy.abc import x, y + >>> p = Wild("p") + >>> q = Wild("q") + >>> r = Wild("r") + >>> e = (x+y)**(x+y) + >>> e.match(p**p) + {p_: x + y} + >>> e.match(p**q) + {p_: x + y, q_: x + y} + >>> e = (2*x)**2 + >>> e.match(p*q**r) + {p_: 4, q_: x, r_: 2} + >>> (p*q**r).xreplace(e.match(p*q**r)) + 4*x**2 + + Since match is purely structural expressions that are equivalent up to + bound symbols will not match: + + >>> print(Sum(x, (x, 1, 2)).match(Sum(y, (y, 1, p)))) + None + + An expression with bound symbols can be matched if the pattern uses + a distinct ``Wild`` for each bound symbol: + + >>> Sum(x, (x, 1, 2)).match(Sum(q, (q, 1, p))) + {p_: 2, q_: x} + + The ``old`` flag will give the old-style pattern matching where + expressions and patterns are essentially solved to give the match. Both + of the following give None unless ``old=True``: + + >>> (x - 2).match(p - x, old=True) + {p_: 2*x - 2} + >>> (2/x).match(p*x, old=True) + {p_: 2/x**2} + + See Also + ======== + + matches: pattern.matches(expr) is the same as expr.match(pattern) + xreplace: exact structural replacement + replace: structural replacement with pattern matching + Wild: symbolic placeholders for expressions in pattern matching + """ + pattern = sympify(pattern) + return pattern.matches(self, old=old) + + def count_ops(self, visual=False): + """Wrapper for count_ops that returns the operation count.""" + from .function import count_ops + return count_ops(self, visual) + + def doit(self, **hints): + """Evaluate objects that are not evaluated by default like limits, + integrals, sums and products. All objects of this kind will be + evaluated recursively, unless some species were excluded via 'hints' + or unless the 'deep' hint was set to 'False'. + + >>> from sympy import Integral + >>> from sympy.abc import x + + >>> 2*Integral(x, x) + 2*Integral(x, x) + + >>> (2*Integral(x, x)).doit() + x**2 + + >>> (2*Integral(x, x)).doit(deep=False) + 2*Integral(x, x) + + """ + if hints.get('deep', True): + terms = [term.doit(**hints) if isinstance(term, Basic) else term + for term in self.args] + return self.func(*terms) + else: + return self + + def simplify(self, **kwargs) -> Basic: + """See the simplify function in sympy.simplify""" + from sympy.simplify.simplify import simplify + return simplify(self, **kwargs) + + def refine(self, assumption=True): + """See the refine function in sympy.assumptions""" + from sympy.assumptions.refine import refine + return refine(self, assumption) + + def _eval_derivative_n_times(self, s, n): + # This is the default evaluator for derivatives (as called by `diff` + # and `Derivative`), it will attempt a loop to derive the expression + # `n` times by calling the corresponding `_eval_derivative` method, + # while leaving the derivative unevaluated if `n` is symbolic. This + # method should be overridden if the object has a closed form for its + # symbolic n-th derivative. + from .numbers import Integer + if isinstance(n, (int, Integer)): + obj = self + for i in range(n): + prev = obj + obj = obj._eval_derivative(s) + if obj is None: + return None + elif obj == prev: + break + return obj + else: + return None + + def rewrite(self, *args, deep=True, **hints): + """ + Rewrite *self* using a defined rule. + + Rewriting transforms an expression to another, which is mathematically + equivalent but structurally different. For example you can rewrite + trigonometric functions as complex exponentials or combinatorial + functions as gamma function. + + This method takes a *pattern* and a *rule* as positional arguments. + *pattern* is optional parameter which defines the types of expressions + that will be transformed. If it is not passed, all possible expressions + will be rewritten. *rule* defines how the expression will be rewritten. + + Parameters + ========== + + args : Expr + A *rule*, or *pattern* and *rule*. + - *pattern* is a type or an iterable of types. + - *rule* can be any object. + + deep : bool, optional + If ``True``, subexpressions are recursively transformed. Default is + ``True``. + + Examples + ======== + + If *pattern* is unspecified, all possible expressions are transformed. + + >>> from sympy import cos, sin, exp, I + >>> from sympy.abc import x + >>> expr = cos(x) + I*sin(x) + >>> expr.rewrite(exp) + exp(I*x) + + Pattern can be a type or an iterable of types. + + >>> expr.rewrite(sin, exp) + exp(I*x)/2 + cos(x) - exp(-I*x)/2 + >>> expr.rewrite([cos,], exp) + exp(I*x)/2 + I*sin(x) + exp(-I*x)/2 + >>> expr.rewrite([cos, sin], exp) + exp(I*x) + + Rewriting behavior can be implemented by defining ``_eval_rewrite()`` + method. + + >>> from sympy import Expr, sqrt, pi + >>> class MySin(Expr): + ... def _eval_rewrite(self, rule, args, **hints): + ... x, = args + ... if rule == cos: + ... return cos(pi/2 - x, evaluate=False) + ... if rule == sqrt: + ... return sqrt(1 - cos(x)**2) + >>> MySin(MySin(x)).rewrite(cos) + cos(-cos(-x + pi/2) + pi/2) + >>> MySin(x).rewrite(sqrt) + sqrt(1 - cos(x)**2) + + Defining ``_eval_rewrite_as_[...]()`` method is supported for backwards + compatibility reason. This may be removed in the future and using it is + discouraged. + + >>> class MySin(Expr): + ... def _eval_rewrite_as_cos(self, *args, **hints): + ... x, = args + ... return cos(pi/2 - x, evaluate=False) + >>> MySin(x).rewrite(cos) + cos(-x + pi/2) + + """ + if not args: + return self + + hints.update(deep=deep) + + pattern = args[:-1] + rule = args[-1] + + # Special case: map `abs` to `Abs` + if rule is abs: + from sympy.functions.elementary.complexes import Abs + rule = Abs + + # support old design by _eval_rewrite_as_[...] method + if isinstance(rule, str): + method = "_eval_rewrite_as_%s" % rule + elif hasattr(rule, "__name__"): + # rule is class or function + clsname = rule.__name__ + method = "_eval_rewrite_as_%s" % clsname + else: + # rule is instance + clsname = rule.__class__.__name__ + method = "_eval_rewrite_as_%s" % clsname + + if pattern: + if iterable(pattern[0]): + pattern = pattern[0] + pattern = tuple(p for p in pattern if self.has(p)) + if not pattern: + return self + # hereafter, empty pattern is interpreted as all pattern. + + return self._rewrite(pattern, rule, method, **hints) + + def _rewrite(self, pattern, rule, method, **hints): + deep = hints.pop('deep', True) + if deep: + args = [a._rewrite(pattern, rule, method, **hints) + for a in self.args] + else: + args = self.args + if not pattern or any(isinstance(self, p) for p in pattern): + meth = getattr(self, method, None) + if meth is not None: + rewritten = meth(*args, **hints) + else: + rewritten = self._eval_rewrite(rule, args, **hints) + if rewritten is not None: + return rewritten + if not args: + return self + return self.func(*args) + + def _eval_rewrite(self, rule, args, **hints): + return None + + _constructor_postprocessor_mapping = {} # type: ignore + + @classmethod + def _exec_constructor_postprocessors(cls, obj): + # WARNING: This API is experimental. + + # This is an experimental API that introduces constructor + # postprosessors for SymPy Core elements. If an argument of a SymPy + # expression has a `_constructor_postprocessor_mapping` attribute, it will + # be interpreted as a dictionary containing lists of postprocessing + # functions for matching expression node names. + + clsname = obj.__class__.__name__ + postprocessors = {f for i in obj.args + for f in _get_postprocessors(clsname, type(i))} + for f in postprocessors: + obj = f(obj) + + return obj + + def _sage_(self): + """ + Convert *self* to a symbolic expression of SageMath. + + This version of the method is merely a placeholder. + """ + old_method = self._sage_ + from sage.interfaces.sympy import sympy_init # type: ignore + sympy_init() # may monkey-patch _sage_ method into self's class or superclasses + if old_method == self._sage_: + raise NotImplementedError('conversion to SageMath is not implemented') + else: + # call the freshly monkey-patched method + return self._sage_() + + def could_extract_minus_sign(self) -> bool: + return False # see Expr.could_extract_minus_sign + + def is_same(a, b, approx=None): + """Return True if a and b are structurally the same, else False. + If `approx` is supplied, it will be used to test whether two + numbers are the same or not. By default, only numbers of the + same type will compare equal, so S.Half != Float(0.5). + + Examples + ======== + + In SymPy (unlike Python) two numbers do not compare the same if they are + not of the same type: + + >>> from sympy import S + >>> 2.0 == S(2) + False + >>> 0.5 == S.Half + False + + By supplying a function with which to compare two numbers, such + differences can be ignored. e.g. `equal_valued` will return True + for decimal numbers having a denominator that is a power of 2, + regardless of precision. + + >>> from sympy import Float + >>> from sympy.core.numbers import equal_valued + >>> (S.Half/4).is_same(Float(0.125, 1), equal_valued) + True + >>> Float(1, 2).is_same(Float(1, 10), equal_valued) + True + + But decimals without a power of 2 denominator will compare + as not being the same. + + >>> Float(0.1, 9).is_same(Float(0.1, 10), equal_valued) + False + + But arbitrary differences can be ignored by supplying a function + to test the equivalence of two numbers: + + >>> import math + >>> Float(0.1, 9).is_same(Float(0.1, 10), math.isclose) + True + + Other objects might compare the same even though types are not the + same. This routine will only return True if two expressions are + identical in terms of class types. + + >>> from sympy import eye, Basic + >>> eye(1) == S(eye(1)) # mutable vs immutable + True + >>> Basic.is_same(eye(1), S(eye(1))) + False + + """ + from .numbers import Number + from .traversal import postorder_traversal as pot + for t in zip_longest(pot(a), pot(b)): + if None in t: + return False + a, b = t + if isinstance(a, Number): + if not isinstance(b, Number): + return False + if approx: + return approx(a, b) + if not (a == b and a.__class__ == b.__class__): + return False + return True + +_aresame = Basic.is_same # for sake of others importing this + +# key used by Mul and Add to make canonical args +_args_sortkey = cmp_to_key(Basic.compare) + +# For all Basic subclasses _prepare_class_assumptions is called by +# Basic.__init_subclass__ but that method is not called for Basic itself so we +# call the function here instead. +_prepare_class_assumptions(Basic) + + +class Atom(Basic): + """ + A parent class for atomic things. An atom is an expression with no subexpressions. + + Examples + ======== + + Symbol, Number, Rational, Integer, ... + But not: Add, Mul, Pow, ... + """ + + is_Atom = True + + __slots__ = () + + def matches(self, expr, repl_dict=None, old=False): + if self == expr: + if repl_dict is None: + return {} + return repl_dict.copy() + + def xreplace(self, rule, hack2=False): + return rule.get(self, self) + + def doit(self, **hints): + return self + + @classmethod + def class_key(cls): + return 2, 0, cls.__name__ + + @cacheit + def sort_key(self, order=None): + return self.class_key(), (1, (str(self),)), S.One.sort_key(), S.One + + def _eval_simplify(self, **kwargs): + return self + + @property + def _sorted_args(self): + # this is here as a safeguard against accidentally using _sorted_args + # on Atoms -- they cannot be rebuilt as atom.func(*atom._sorted_args) + # since there are no args. So the calling routine should be checking + # to see that this property is not called for Atoms. + raise AttributeError('Atoms have no args. It might be necessary' + ' to make a check for Atoms in the calling code.') + + +def _atomic(e, recursive=False): + """Return atom-like quantities as far as substitution is + concerned: Derivatives, Functions and Symbols. Do not + return any 'atoms' that are inside such quantities unless + they also appear outside, too, unless `recursive` is True. + + Examples + ======== + + >>> from sympy import Derivative, Function, cos + >>> from sympy.abc import x, y + >>> from sympy.core.basic import _atomic + >>> f = Function('f') + >>> _atomic(x + y) + {x, y} + >>> _atomic(x + f(y)) + {x, f(y)} + >>> _atomic(Derivative(f(x), x) + cos(x) + y) + {y, cos(x), Derivative(f(x), x)} + + """ + pot = _preorder_traversal(e) + seen = set() + if isinstance(e, Basic): + free = getattr(e, "free_symbols", None) + if free is None: + return {e} + else: + return set() + from .symbol import Symbol + from .function import Derivative, Function + atoms = set() + for p in pot: + if p in seen: + pot.skip() + continue + seen.add(p) + if isinstance(p, Symbol) and p in free: + atoms.add(p) + elif isinstance(p, (Derivative, Function)): + if not recursive: + pot.skip() + atoms.add(p) + return atoms + + +def _make_find_query(query): + """Convert the argument of Basic.find() into a callable""" + try: + query = _sympify(query) + except SympifyError: + pass + if isinstance(query, type): + return lambda expr: isinstance(expr, query) + elif isinstance(query, Basic): + return lambda expr: expr.match(query) is not None + return query + +# Delayed to avoid cyclic import +from .singleton import S +from .traversal import (preorder_traversal as _preorder_traversal, + iterargs, iterfreeargs) + +preorder_traversal = deprecated( + """ + Using preorder_traversal from the sympy.core.basic submodule is + deprecated. + + Instead, use preorder_traversal from the top-level sympy namespace, like + + sympy.preorder_traversal + """, + deprecated_since_version="1.10", + active_deprecations_target="deprecated-traversal-functions-moved", +)(_preorder_traversal) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/cache.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/cache.py new file mode 100644 index 0000000000000000000000000000000000000000..ec11600a5e40ad446a6e5dde8820d46ea915b06a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/cache.py @@ -0,0 +1,210 @@ +""" Caching facility for SymPy """ +from importlib import import_module +from typing import Callable + +class _cache(list): + """ List of cached functions """ + + def print_cache(self): + """print cache info""" + + for item in self: + name = item.__name__ + myfunc = item + while hasattr(myfunc, '__wrapped__'): + if hasattr(myfunc, 'cache_info'): + info = myfunc.cache_info() + break + else: + myfunc = myfunc.__wrapped__ + else: + info = None + + print(name, info) + + def clear_cache(self): + """clear cache content""" + for item in self: + myfunc = item + while hasattr(myfunc, '__wrapped__'): + if hasattr(myfunc, 'cache_clear'): + myfunc.cache_clear() + break + else: + myfunc = myfunc.__wrapped__ + + +# global cache registry: +CACHE = _cache() +# make clear and print methods available +print_cache = CACHE.print_cache +clear_cache = CACHE.clear_cache + +from functools import lru_cache, wraps + +def __cacheit(maxsize): + """caching decorator. + + important: the result of cached function must be *immutable* + + + Examples + ======== + + >>> from sympy import cacheit + >>> @cacheit + ... def f(a, b): + ... return a+b + + >>> @cacheit + ... def f(a, b): # noqa: F811 + ... return [a, b] # <-- WRONG, returns mutable object + + to force cacheit to check returned results mutability and consistency, + set environment variable SYMPY_USE_CACHE to 'debug' + """ + def func_wrapper(func): + cfunc = lru_cache(maxsize, typed=True)(func) + + @wraps(func) + def wrapper(*args, **kwargs): + try: + retval = cfunc(*args, **kwargs) + except TypeError as e: + if not e.args or not e.args[0].startswith('unhashable type:'): + raise + retval = func(*args, **kwargs) + return retval + + wrapper.cache_info = cfunc.cache_info + wrapper.cache_clear = cfunc.cache_clear + + CACHE.append(wrapper) + return wrapper + + return func_wrapper +######################################## + + +def __cacheit_nocache(func): + return func + + +def __cacheit_debug(maxsize): + """cacheit + code to check cache consistency""" + def func_wrapper(func): + cfunc = __cacheit(maxsize)(func) + + @wraps(func) + def wrapper(*args, **kw_args): + # always call function itself and compare it with cached version + r1 = func(*args, **kw_args) + r2 = cfunc(*args, **kw_args) + + # try to see if the result is immutable + # + # this works because: + # + # hash([1,2,3]) -> raise TypeError + # hash({'a':1, 'b':2}) -> raise TypeError + # hash((1,[2,3])) -> raise TypeError + # + # hash((1,2,3)) -> just computes the hash + hash(r1), hash(r2) + + # also see if returned values are the same + if r1 != r2: + raise RuntimeError("Returned values are not the same") + return r1 + return wrapper + return func_wrapper + + +def _getenv(key, default=None): + from os import getenv + return getenv(key, default) + +# SYMPY_USE_CACHE=yes/no/debug +USE_CACHE = _getenv('SYMPY_USE_CACHE', 'yes').lower() +# SYMPY_CACHE_SIZE=some_integer/None +# special cases : +# SYMPY_CACHE_SIZE=0 -> No caching +# SYMPY_CACHE_SIZE=None -> Unbounded caching +scs = _getenv('SYMPY_CACHE_SIZE', '1000') +if scs.lower() == 'none': + SYMPY_CACHE_SIZE = None +else: + try: + SYMPY_CACHE_SIZE = int(scs) + except ValueError: + raise RuntimeError( + 'SYMPY_CACHE_SIZE must be a valid integer or None. ' + \ + 'Got: %s' % SYMPY_CACHE_SIZE) + +if USE_CACHE == 'no': + cacheit = __cacheit_nocache +elif USE_CACHE == 'yes': + cacheit = __cacheit(SYMPY_CACHE_SIZE) +elif USE_CACHE == 'debug': + cacheit = __cacheit_debug(SYMPY_CACHE_SIZE) # a lot slower +else: + raise RuntimeError( + 'unrecognized value for SYMPY_USE_CACHE: %s' % USE_CACHE) + + +def cached_property(func): + '''Decorator to cache property method''' + attrname = '__' + func.__name__ + _cached_property_sentinel = object() + def propfunc(self): + val = getattr(self, attrname, _cached_property_sentinel) + if val is _cached_property_sentinel: + val = func(self) + setattr(self, attrname, val) + return val + return property(propfunc) + + +def lazy_function(module : str, name : str) -> Callable: + """Create a lazy proxy for a function in a module. + + The module containing the function is not imported until the function is used. + + """ + func = None + + def _get_function(): + nonlocal func + if func is None: + func = getattr(import_module(module), name) + return func + + # The metaclass is needed so that help() shows the docstring + class LazyFunctionMeta(type): + @property + def __doc__(self): + docstring = _get_function().__doc__ + docstring += f"\n\nNote: this is a {self.__class__.__name__} wrapper of '{module}.{name}'" + return docstring + + class LazyFunction(metaclass=LazyFunctionMeta): + def __call__(self, *args, **kwargs): + # inline get of function for performance gh-23832 + nonlocal func + if func is None: + func = getattr(import_module(module), name) + return func(*args, **kwargs) + + @property + def __doc__(self): + docstring = _get_function().__doc__ + docstring += f"\n\nNote: this is a {self.__class__.__name__} wrapper of '{module}.{name}'" + return docstring + + def __str__(self): + return _get_function().__str__() + + def __repr__(self): + return f"<{__class__.__name__} object at 0x{id(self):x}>: wrapping '{module}.{name}'" + + return LazyFunction() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/compatibility.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/compatibility.py new file mode 100644 index 0000000000000000000000000000000000000000..637a2698dbb39a042d3d664404bb0a4cba7fd004 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/compatibility.py @@ -0,0 +1,35 @@ +""" +.. deprecated:: 1.10 + + ``sympy.core.compatibility`` is deprecated. See + :ref:`sympy-core-compatibility`. + +Reimplementations of constructs introduced in later versions of Python than +we support. Also some functions that are needed SymPy-wide and are located +here for easy import. + +""" + + +from sympy.utilities.exceptions import sympy_deprecation_warning + +sympy_deprecation_warning(""" +The sympy.core.compatibility submodule is deprecated. + +This module was only ever intended for internal use. Some of the functions +that were in this module are available from the top-level SymPy namespace, +i.e., + + from sympy import ordered, default_sort_key + +The remaining were only intended for internal SymPy use and should not be used +by user code. +""", + deprecated_since_version="1.10", + active_deprecations_target="deprecated-sympy-core-compatibility", + ) + + +from .sorting import ordered, _nodes, default_sort_key # noqa:F401 +from sympy.utilities.misc import as_int as _as_int # noqa:F401 +from sympy.utilities.iterables import iterable, is_sequence, NotIterable # noqa:F401 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/containers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/containers.py new file mode 100644 index 0000000000000000000000000000000000000000..35352009e87f3a7809a53031080cefdadb6528be --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/containers.py @@ -0,0 +1,415 @@ +"""Module for SymPy containers + + (SymPy objects that store other SymPy objects) + + The containers implemented in this module are subclassed to Basic. + They are supposed to work seamlessly within the SymPy framework. +""" + +from __future__ import annotations + +from collections import OrderedDict +from collections.abc import MutableSet +from typing import Any, Callable + +from .basic import Basic +from .sorting import default_sort_key, ordered +from .sympify import _sympify, sympify, _sympy_converter, SympifyError +from sympy.core.kind import Kind +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import as_int + + +class Tuple(Basic): + """ + Wrapper around the builtin tuple object. + + Explanation + =========== + + The Tuple is a subclass of Basic, so that it works well in the + SymPy framework. The wrapped tuple is available as self.args, but + you can also access elements or slices with [:] syntax. + + Parameters + ========== + + sympify : bool + If ``False``, ``sympify`` is not called on ``args``. This + can be used for speedups for very large tuples where the + elements are known to already be SymPy objects. + + Examples + ======== + + >>> from sympy import Tuple, symbols + >>> a, b, c, d = symbols('a b c d') + >>> Tuple(a, b, c)[1:] + (b, c) + >>> Tuple(a, b, c).subs(a, d) + (d, b, c) + + """ + + def __new__(cls, *args, **kwargs): + if kwargs.get('sympify', True): + args = (sympify(arg) for arg in args) + obj = Basic.__new__(cls, *args) + return obj + + def __getitem__(self, i): + if isinstance(i, slice): + indices = i.indices(len(self)) + return Tuple(*(self.args[j] for j in range(*indices))) + return self.args[i] + + def __len__(self): + return len(self.args) + + def __contains__(self, item): + return item in self.args + + def __iter__(self): + return iter(self.args) + + def __add__(self, other): + if isinstance(other, Tuple): + return Tuple(*(self.args + other.args)) + elif isinstance(other, tuple): + return Tuple(*(self.args + other)) + else: + return NotImplemented + + def __radd__(self, other): + if isinstance(other, Tuple): + return Tuple(*(other.args + self.args)) + elif isinstance(other, tuple): + return Tuple(*(other + self.args)) + else: + return NotImplemented + + def __mul__(self, other): + try: + n = as_int(other) + except ValueError: + raise TypeError("Can't multiply sequence by non-integer of type '%s'" % type(other)) + return self.func(*(self.args*n)) + + __rmul__ = __mul__ + + def __eq__(self, other): + if isinstance(other, Basic): + return super().__eq__(other) + return self.args == other + + def __ne__(self, other): + if isinstance(other, Basic): + return super().__ne__(other) + return self.args != other + + def __hash__(self): + return hash(self.args) + + def _to_mpmath(self, prec): + return tuple(a._to_mpmath(prec) for a in self.args) + + def __lt__(self, other): + return _sympify(self.args < other.args) + + def __le__(self, other): + return _sympify(self.args <= other.args) + + # XXX: Basic defines count() as something different, so we can't + # redefine it here. Originally this lead to cse() test failure. + def tuple_count(self, value) -> int: + """Return number of occurrences of value.""" + return self.args.count(value) + + def index(self, value, start=None, stop=None): + """Searches and returns the first index of the value.""" + # XXX: One would expect: + # + # return self.args.index(value, start, stop) + # + # here. Any trouble with that? Yes: + # + # >>> (1,).index(1, None, None) + # Traceback (most recent call last): + # File "", line 1, in + # TypeError: slice indices must be integers or None or have an __index__ method + # + # See: http://bugs.python.org/issue13340 + + if start is None and stop is None: + return self.args.index(value) + elif stop is None: + return self.args.index(value, start) + else: + return self.args.index(value, start, stop) + + @property + def kind(self): + """ + The kind of a Tuple instance. + + The kind of a Tuple is always of :class:`TupleKind` but + parametrised by the number of elements and the kind of each element. + + Examples + ======== + + >>> from sympy import Tuple, Matrix + >>> Tuple(1, 2).kind + TupleKind(NumberKind, NumberKind) + >>> Tuple(Matrix([1, 2]), 1).kind + TupleKind(MatrixKind(NumberKind), NumberKind) + >>> Tuple(1, 2).kind.element_kind + (NumberKind, NumberKind) + + See Also + ======== + + sympy.matrices.kind.MatrixKind + sympy.core.kind.NumberKind + """ + return TupleKind(*(i.kind for i in self.args)) + +_sympy_converter[tuple] = lambda tup: Tuple(*tup) + + + + + +def tuple_wrapper(method): + """ + Decorator that converts any tuple in the function arguments into a Tuple. + + Explanation + =========== + + The motivation for this is to provide simple user interfaces. The user can + call a function with regular tuples in the argument, and the wrapper will + convert them to Tuples before handing them to the function. + + Explanation + =========== + + >>> from sympy.core.containers import tuple_wrapper + >>> def f(*args): + ... return args + >>> g = tuple_wrapper(f) + + The decorated function g sees only the Tuple argument: + + >>> g(0, (1, 2), 3) + (0, (1, 2), 3) + + """ + def wrap_tuples(*args, **kw_args): + newargs = [] + for arg in args: + if isinstance(arg, tuple): + newargs.append(Tuple(*arg)) + else: + newargs.append(arg) + return method(*newargs, **kw_args) + return wrap_tuples + + +class Dict(Basic): + """ + Wrapper around the builtin dict object. + + Explanation + =========== + + The Dict is a subclass of Basic, so that it works well in the + SymPy framework. Because it is immutable, it may be included + in sets, but its values must all be given at instantiation and + cannot be changed afterwards. Otherwise it behaves identically + to the Python dict. + + Examples + ======== + + >>> from sympy import Dict, Symbol + + >>> D = Dict({1: 'one', 2: 'two'}) + >>> for key in D: + ... if key == 1: + ... print('%s %s' % (key, D[key])) + 1 one + + The args are sympified so the 1 and 2 are Integers and the values + are Symbols. Queries automatically sympify args so the following work: + + >>> 1 in D + True + >>> D.has(Symbol('one')) # searches keys and values + True + >>> 'one' in D # not in the keys + False + >>> D[1] + one + + """ + + elements: frozenset[Tuple] + _dict: dict[Basic, Basic] + + def __new__(cls, *args): + if len(args) == 1 and isinstance(args[0], (dict, Dict)): + items = [Tuple(k, v) for k, v in args[0].items()] + elif iterable(args) and all(len(arg) == 2 for arg in args): + items = [Tuple(k, v) for k, v in args] + else: + raise TypeError('Pass Dict args as Dict((k1, v1), ...) or Dict({k1: v1, ...})') + elements = frozenset(items) + obj = Basic.__new__(cls, *ordered(items)) + obj.elements = elements + obj._dict = dict(items) # In case Tuple decides it wants to sympify + return obj + + def __getitem__(self, key): + """x.__getitem__(y) <==> x[y]""" + try: + key = _sympify(key) + except SympifyError: + raise KeyError(key) + + return self._dict[key] + + def __setitem__(self, key, value): + raise NotImplementedError("SymPy Dicts are Immutable") + + def items(self): + '''Returns a set-like object providing a view on dict's items. + ''' + return self._dict.items() + + def keys(self): + '''Returns the list of the dict's keys.''' + return self._dict.keys() + + def values(self): + '''Returns the list of the dict's values.''' + return self._dict.values() + + def __iter__(self): + '''x.__iter__() <==> iter(x)''' + return iter(self._dict) + + def __len__(self): + '''x.__len__() <==> len(x)''' + return self._dict.__len__() + + def get(self, key, default=None): + '''Returns the value for key if the key is in the dictionary.''' + try: + key = _sympify(key) + except SympifyError: + return default + return self._dict.get(key, default) + + def __contains__(self, key): + '''D.__contains__(k) -> True if D has a key k, else False''' + try: + key = _sympify(key) + except SympifyError: + return False + return key in self._dict + + def __lt__(self, other): + return _sympify(self.args < other.args) + + @property + def _sorted_args(self): + return tuple(sorted(self.args, key=default_sort_key)) + + def __eq__(self, other): + if isinstance(other, dict): + return self == Dict(other) + return super().__eq__(other) + + __hash__ : Callable[[Basic], Any] = Basic.__hash__ + +# this handles dict, defaultdict, OrderedDict +_sympy_converter[dict] = lambda d: Dict(*d.items()) + +class OrderedSet(MutableSet): + def __init__(self, iterable=None): + if iterable: + self.map = OrderedDict((item, None) for item in iterable) + else: + self.map = OrderedDict() + + def __len__(self): + return len(self.map) + + def __contains__(self, key): + return key in self.map + + def add(self, key): + self.map[key] = None + + def discard(self, key): + self.map.pop(key) + + def pop(self, last=True): + return self.map.popitem(last=last)[0] + + def __iter__(self): + yield from self.map.keys() + + def __repr__(self): + if not self.map: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, list(self.map.keys())) + + def intersection(self, other): + return self.__class__([val for val in self if val in other]) + + def difference(self, other): + return self.__class__([val for val in self if val not in other]) + + def update(self, iterable): + for val in iterable: + self.add(val) + +class TupleKind(Kind): + """ + TupleKind is a subclass of Kind, which is used to define Kind of ``Tuple``. + + Parameters of TupleKind will be kinds of all the arguments in Tuples, for + example + + Parameters + ========== + + args : tuple(element_kind) + element_kind is kind of element. + args is tuple of kinds of element + + Examples + ======== + + >>> from sympy import Tuple + >>> Tuple(1, 2).kind + TupleKind(NumberKind, NumberKind) + >>> Tuple(1, 2).kind.element_kind + (NumberKind, NumberKind) + + See Also + ======== + + sympy.core.kind.NumberKind + MatrixKind + sympy.sets.sets.SetKind + """ + def __new__(cls, *args): + obj = super().__new__(cls, *args) + obj.element_kind = args + return obj + + def __repr__(self): + return "TupleKind{}".format(self.element_kind) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/core.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/core.py new file mode 100644 index 0000000000000000000000000000000000000000..8a45bb06919d7a8ef88e2c9958decac705c0b8ee --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/core.py @@ -0,0 +1,21 @@ +""" The core's core. """ +from __future__ import annotations + + +class Registry: + """ + Base class for registry objects. + + Registries map a name to an object using attribute notation. Registry + classes behave singletonically: all their instances share the same state, + which is stored in the class object. + + All subclasses should set `__slots__ = ()`. + """ + __slots__ = () + + def __setattr__(self, name, obj): + setattr(self.__class__, name, obj) + + def __delattr__(self, name): + delattr(self.__class__, name) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/coreerrors.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/coreerrors.py new file mode 100644 index 0000000000000000000000000000000000000000..d2dbdd5227d7b0495145072d31bd993f13f31f0d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/coreerrors.py @@ -0,0 +1,23 @@ +"""Definitions of common exceptions for :mod:`sympy.core` module. """ + +from typing import Callable + + +class BaseCoreError(Exception): + """Base class for core related exceptions. """ + + +class NonCommutativeExpression(BaseCoreError): + """Raised when expression didn't have commutative property. """ + + +class LazyExceptionMessage: + """Wrapper class that lets you specify an expensive to compute + error message that is only evaluated if the error is rendered.""" + callback: Callable[[], str] + + def __init__(self, callback: Callable[[], str]): + self.callback = callback + + def __str__(self): + return self.callback() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/decorators.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/decorators.py new file mode 100644 index 0000000000000000000000000000000000000000..afd6ae0c72dc32d260586c6411507e4859a9f8ff --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/decorators.py @@ -0,0 +1,250 @@ +""" +SymPy core decorators. + +The purpose of this module is to expose decorators without any other +dependencies, so that they can be easily imported anywhere in sympy/core. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from functools import wraps +from .sympify import SympifyError, sympify + + +if TYPE_CHECKING: + from typing import Callable, TypeVar, Union + T1 = TypeVar('T1') + T2 = TypeVar('T2') + T3 = TypeVar('T3') + + +def _sympifyit(arg, retval=None) -> Callable[[Callable[[T1, T2], T3]], Callable[[T1, T2], T3]]: + """ + decorator to smartly _sympify function arguments + + Explanation + =========== + + @_sympifyit('other', NotImplemented) + def add(self, other): + ... + + In add, other can be thought of as already being a SymPy object. + + If it is not, the code is likely to catch an exception, then other will + be explicitly _sympified, and the whole code restarted. + + if _sympify(arg) fails, NotImplemented will be returned + + See also + ======== + + __sympifyit + """ + def deco(func): + return __sympifyit(func, arg, retval) + + return deco + + +def __sympifyit(func, arg, retval=None): + """Decorator to _sympify `arg` argument for function `func`. + + Do not use directly -- use _sympifyit instead. + """ + + # we support f(a,b) only + if not func.__code__.co_argcount: + raise LookupError("func not found") + # only b is _sympified + assert func.__code__.co_varnames[1] == arg + if retval is None: + @wraps(func) + def __sympifyit_wrapper(a, b): + return func(a, sympify(b, strict=True)) + + else: + @wraps(func) + def __sympifyit_wrapper(a, b): + try: + # If an external class has _op_priority, it knows how to deal + # with SymPy objects. Otherwise, it must be converted. + if not hasattr(b, '_op_priority'): + b = sympify(b, strict=True) + return func(a, b) + except SympifyError: + return retval + + return __sympifyit_wrapper + + +def call_highest_priority(method_name: str + ) -> Callable[[Callable[[T1, T2], T3]], Callable[[T1, T2], T3]]: + """A decorator for binary special methods to handle _op_priority. + + Explanation + =========== + + Binary special methods in Expr and its subclasses use a special attribute + '_op_priority' to determine whose special method will be called to + handle the operation. In general, the object having the highest value of + '_op_priority' will handle the operation. Expr and subclasses that define + custom binary special methods (__mul__, etc.) should decorate those + methods with this decorator to add the priority logic. + + The ``method_name`` argument is the name of the method of the other class + that will be called. Use this decorator in the following manner:: + + # Call other.__rmul__ if other._op_priority > self._op_priority + @call_highest_priority('__rmul__') + def __mul__(self, other): + ... + + # Call other.__mul__ if other._op_priority > self._op_priority + @call_highest_priority('__mul__') + def __rmul__(self, other): + ... + """ + def priority_decorator(func: Callable[[T1, T2], T3]) -> Callable[[T1, T2], T3]: + @wraps(func) + def binary_op_wrapper(self: T1, other: T2) -> T3: + if hasattr(other, '_op_priority'): + if other._op_priority > self._op_priority: # type: ignore + f: Union[Callable[[T1], T3], None] = getattr(other, method_name, None) + if f is not None: + return f(self) + return func(self, other) + return binary_op_wrapper + return priority_decorator + + +def sympify_method_args(cls: type[T1]) -> type[T1]: + '''Decorator for a class with methods that sympify arguments. + + Explanation + =========== + + The sympify_method_args decorator is to be used with the sympify_return + decorator for automatic sympification of method arguments. This is + intended for the common idiom of writing a class like : + + Examples + ======== + + >>> from sympy import Basic, SympifyError, S + >>> from sympy.core.sympify import _sympify + + >>> class MyTuple(Basic): + ... def __add__(self, other): + ... try: + ... other = _sympify(other) + ... except SympifyError: + ... return NotImplemented + ... if not isinstance(other, MyTuple): + ... return NotImplemented + ... return MyTuple(*(self.args + other.args)) + + >>> MyTuple(S(1), S(2)) + MyTuple(S(3), S(4)) + MyTuple(1, 2, 3, 4) + + In the above it is important that we return NotImplemented when other is + not sympifiable and also when the sympified result is not of the expected + type. This allows the MyTuple class to be used cooperatively with other + classes that overload __add__ and want to do something else in combination + with instance of Tuple. + + Using this decorator the above can be written as + + >>> from sympy.core.decorators import sympify_method_args, sympify_return + + >>> @sympify_method_args + ... class MyTuple(Basic): + ... @sympify_return([('other', 'MyTuple')], NotImplemented) + ... def __add__(self, other): + ... return MyTuple(*(self.args + other.args)) + + >>> MyTuple(S(1), S(2)) + MyTuple(S(3), S(4)) + MyTuple(1, 2, 3, 4) + + The idea here is that the decorators take care of the boiler-plate code + for making this happen in each method that potentially needs to accept + unsympified arguments. Then the body of e.g. the __add__ method can be + written without needing to worry about calling _sympify or checking the + type of the resulting object. + + The parameters for sympify_return are a list of tuples of the form + (parameter_name, expected_type) and the value to return (e.g. + NotImplemented). The expected_type parameter can be a type e.g. Tuple or a + string 'Tuple'. Using a string is useful for specifying a Type within its + class body (as in the above example). + + Notes: Currently sympify_return only works for methods that take a single + argument (not including self). Specifying an expected_type as a string + only works for the class in which the method is defined. + ''' + # Extract the wrapped methods from each of the wrapper objects created by + # the sympify_return decorator. Doing this here allows us to provide the + # cls argument which is used for forward string referencing. + for attrname, obj in cls.__dict__.items(): + if isinstance(obj, _SympifyWrapper): + setattr(cls, attrname, obj.make_wrapped(cls)) + return cls + + +def sympify_return(*args): + '''Function/method decorator to sympify arguments automatically + + See the docstring of sympify_method_args for explanation. + ''' + # Store a wrapper object for the decorated method + def wrapper(func: Callable[[T1, T2], T3]) -> Callable[[T1, T2], T3]: + return _SympifyWrapper(func, args) # type: ignore + return wrapper + + +class _SympifyWrapper: + '''Internal class used by sympify_return and sympify_method_args''' + + def __init__(self, func, args): + self.func = func + self.args = args + + def make_wrapped(self, cls): + func = self.func + parameters, retval = self.args + + # XXX: Handle more than one parameter? + [(parameter, expectedcls)] = parameters + + # Handle forward references to the current class using strings + if expectedcls == cls.__name__: + expectedcls = cls + + # Raise RuntimeError since this is a failure at import time and should + # not be recoverable. + nargs = func.__code__.co_argcount + # we support f(a, b) only + if nargs != 2: + raise RuntimeError('sympify_return can only be used with 2 argument functions') + # only b is _sympified + if func.__code__.co_varnames[1] != parameter: + raise RuntimeError('parameter name mismatch "%s" in %s' % + (parameter, func.__name__)) + + @wraps(func) + def _func(self, other): + # XXX: The check for _op_priority here should be removed. It is + # needed to stop mutable matrices from being sympified to + # immutable matrices which breaks things in quantum... + if not hasattr(other, '_op_priority'): + try: + other = sympify(other, strict=True) + except SympifyError: + return retval + if not isinstance(other, expectedcls): + return retval + return func(self, other) + + return _func diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/evalf.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/evalf.py new file mode 100644 index 0000000000000000000000000000000000000000..55a981090360556b357ec1cade5576e226633be8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/evalf.py @@ -0,0 +1,1808 @@ +""" +Adaptive numerical evaluation of SymPy expressions, using mpmath +for mathematical functions. +""" +from __future__ import annotations +from typing import Callable, TYPE_CHECKING, Any, overload, Type + +import math + +import mpmath.libmp as libmp +from mpmath import ( + make_mpc, make_mpf, mp, mpc, mpf, nsum, quadts, quadosc, workprec) +from mpmath import inf as mpmath_inf +from mpmath.libmp import (from_int, from_man_exp, from_rational, fhalf, + fnan, finf, fninf, fnone, fone, fzero, mpf_abs, mpf_add, + mpf_atan, mpf_atan2, mpf_cmp, mpf_cos, mpf_e, mpf_exp, mpf_log, mpf_lt, + mpf_mul, mpf_neg, mpf_pi, mpf_pow, mpf_pow_int, mpf_shift, mpf_sin, + mpf_sqrt, normalize, round_nearest, to_int, to_str, mpf_tan) +from mpmath.libmp import bitcount as mpmath_bitcount +from mpmath.libmp.backend import MPZ +from mpmath.libmp.libmpc import _infs_nan +from mpmath.libmp.libmpf import dps_to_prec, prec_to_dps + +from .sympify import sympify +from .singleton import S +from sympy.external.gmpy import SYMPY_INTS +from sympy.utilities.iterables import is_sequence +from sympy.utilities.lambdify import lambdify +from sympy.utilities.misc import as_int + +if TYPE_CHECKING: + from sympy.core.expr import Expr + from sympy.core.add import Add + from sympy.core.mul import Mul + from sympy.core.power import Pow + from sympy.core.symbol import Symbol + from sympy.integrals.integrals import Integral + from sympy.concrete.summations import Sum + from sympy.concrete.products import Product + from sympy.functions.elementary.exponential import exp, log + from sympy.functions.elementary.complexes import Abs, re, im + from sympy.functions.elementary.integers import ceiling, floor + from sympy.functions.elementary.trigonometric import atan + from .numbers import Float, Rational, Integer, AlgebraicNumber, Number + +LG10 = math.log2(10) +rnd = round_nearest + + +def bitcount(n): + """Return smallest integer, b, such that |n|/2**b < 1. + """ + return mpmath_bitcount(abs(int(n))) + +# Used in a few places as placeholder values to denote exponents and +# precision levels, e.g. of exact numbers. Must be careful to avoid +# passing these to mpmath functions or returning them in final results. +INF = float(mpmath_inf) +MINUS_INF = float(-mpmath_inf) + +# ~= 100 digits. Real men set this to INF. +DEFAULT_MAXPREC = 333 + + +class PrecisionExhausted(ArithmeticError): + pass + +#----------------------------------------------------------------------------# +# # +# Helper functions for arithmetic and complex parts # +# # +#----------------------------------------------------------------------------# + +""" +An mpf value tuple is a tuple of integers (sign, man, exp, bc) +representing a floating-point number: [1, -1][sign]*man*2**exp where +sign is 0 or 1 and bc should correspond to the number of bits used to +represent the mantissa (man) in binary notation, e.g. +""" + +MPF_TUP = tuple[int, int, int, int] # mpf value tuple + +""" +Explanation +=========== + +>>> from sympy.core.evalf import bitcount +>>> sign, man, exp, bc = 0, 5, 1, 3 +>>> n = [1, -1][sign]*man*2**exp +>>> n, bitcount(man) +(10, 3) + +A temporary result is a tuple (re, im, re_acc, im_acc) where +re and im are nonzero mpf value tuples representing approximate +numbers, or None to denote exact zeros. + +re_acc, im_acc are integers denoting log2(e) where e is the estimated +relative accuracy of the respective complex part, but may be anything +if the corresponding complex part is None. + +""" +TMP_RES = Any # temporary result, should be some variant of +# tUnion[tTuple[Optional[MPF_TUP], Optional[MPF_TUP], +# Optional[int], Optional[int]], +# 'ComplexInfinity'] +# but mypy reports error because it doesn't know as we know +# 1. re and re_acc are either both None or both MPF_TUP +# 2. sometimes the result can't be zoo + +# type of the "options" parameter in internal evalf functions +OPT_DICT = dict[str, Any] + + +def fastlog(x: MPF_TUP | None) -> int | Any: + """Fast approximation of log2(x) for an mpf value tuple x. + + Explanation + =========== + + Calculated as exponent + width of mantissa. This is an + approximation for two reasons: 1) it gives the ceil(log2(abs(x))) + value and 2) it is too high by 1 in the case that x is an exact + power of 2. Although this is easy to remedy by testing to see if + the odd mpf mantissa is 1 (indicating that one was dealing with + an exact power of 2) that would decrease the speed and is not + necessary as this is only being used as an approximation for the + number of bits in x. The correct return value could be written as + "x[2] + (x[3] if x[1] != 1 else 0)". + Since mpf tuples always have an odd mantissa, no check is done + to see if the mantissa is a multiple of 2 (in which case the + result would be too large by 1). + + Examples + ======== + + >>> from sympy import log + >>> from sympy.core.evalf import fastlog, bitcount + >>> s, m, e = 0, 5, 1 + >>> bc = bitcount(m) + >>> n = [1, -1][s]*m*2**e + >>> n, (log(n)/log(2)).evalf(2), fastlog((s, m, e, bc)) + (10, 3.3, 4) + """ + + if not x or x == fzero: + return MINUS_INF + return x[2] + x[3] + + +def pure_complex(v: Expr, or_real=False) -> tuple[Number, Number] | None: + """Return a and b if v matches a + I*b where b is not zero and + a and b are Numbers, else None. If `or_real` is True then 0 will + be returned for `b` if `v` is a real number. + + Examples + ======== + + >>> from sympy.core.evalf import pure_complex + >>> from sympy import sqrt, I, S + >>> a, b, surd = S(2), S(3), sqrt(2) + >>> pure_complex(a) + >>> pure_complex(a, or_real=True) + (2, 0) + >>> pure_complex(surd) + >>> pure_complex(a + b*I) + (2, 3) + >>> pure_complex(I) + (0, 1) + """ + h, t = v.as_coeff_Add() + if t: + c, i = t.as_coeff_Mul() + if i is S.ImaginaryUnit: + return h, c + elif or_real: + return h, S.Zero + return None + + +# I don't know what this is, see function scaled_zero below +SCALED_ZERO_TUP = tuple[list[int], int, int, int] + + + +@overload +def scaled_zero(mag: SCALED_ZERO_TUP, sign=1) -> MPF_TUP: + ... +@overload +def scaled_zero(mag: int, sign=1) -> tuple[SCALED_ZERO_TUP, int]: + ... +def scaled_zero(mag: SCALED_ZERO_TUP | int, sign=1) -> \ + MPF_TUP | tuple[SCALED_ZERO_TUP, int]: + """Return an mpf representing a power of two with magnitude ``mag`` + and -1 for precision. Or, if ``mag`` is a scaled_zero tuple, then just + remove the sign from within the list that it was initially wrapped + in. + + Examples + ======== + + >>> from sympy.core.evalf import scaled_zero + >>> from sympy import Float + >>> z, p = scaled_zero(100) + >>> z, p + (([0], 1, 100, 1), -1) + >>> ok = scaled_zero(z) + >>> ok + (0, 1, 100, 1) + >>> Float(ok) + 1.26765060022823e+30 + >>> Float(ok, p) + 0.e+30 + >>> ok, p = scaled_zero(100, -1) + >>> Float(scaled_zero(ok), p) + -0.e+30 + """ + if isinstance(mag, tuple) and len(mag) == 4 and iszero(mag, scaled=True): + return (mag[0][0],) + mag[1:] + elif isinstance(mag, SYMPY_INTS): + if sign not in [-1, 1]: + raise ValueError('sign must be +/-1') + rv, p = mpf_shift(fone, mag), -1 + s = 0 if sign == 1 else 1 + rv = ([s],) + rv[1:] + return rv, p + else: + raise ValueError('scaled zero expects int or scaled_zero tuple.') + + +def iszero(mpf: MPF_TUP | SCALED_ZERO_TUP | None, scaled=False) -> bool | None: + if not scaled: + return not mpf or not mpf[1] and not mpf[-1] + return mpf and isinstance(mpf[0], list) and mpf[1] == mpf[-1] == 1 + + +def complex_accuracy(result: TMP_RES) -> int | Any: + """ + Returns relative accuracy of a complex number with given accuracies + for the real and imaginary parts. The relative accuracy is defined + in the complex norm sense as ||z|+|error|| / |z| where error + is equal to (real absolute error) + (imag absolute error)*i. + + The full expression for the (logarithmic) error can be approximated + easily by using the max norm to approximate the complex norm. + + In the worst case (re and im equal), this is wrong by a factor + sqrt(2), or by log2(sqrt(2)) = 0.5 bit. + """ + if result is S.ComplexInfinity: + return INF + re, im, re_acc, im_acc = result + if not im: + if not re: + return INF + return re_acc + if not re: + return im_acc + re_size = fastlog(re) + im_size = fastlog(im) + absolute_error = max(re_size - re_acc, im_size - im_acc) + relative_error = absolute_error - max(re_size, im_size) + return -relative_error + + +def get_abs(expr: Expr, prec: int, options: OPT_DICT) -> TMP_RES: + result = evalf(expr, prec + 2, options) + if result is S.ComplexInfinity: + return finf, None, prec, None + re, im, re_acc, im_acc = result + if not re: + re, re_acc, im, im_acc = im, im_acc, re, re_acc + if im: + if expr.is_number: + abs_expr, _, acc, _ = evalf(abs(N(expr, prec + 2)), + prec + 2, options) + return abs_expr, None, acc, None + else: + if 'subs' in options: + return libmp.mpc_abs((re, im), prec), None, re_acc, None + return abs(expr), None, prec, None + elif re: + return mpf_abs(re), None, re_acc, None + else: + return None, None, None, None + + +def get_complex_part(expr: Expr, no: int, prec: int, options: OPT_DICT) -> TMP_RES: + """no = 0 for real part, no = 1 for imaginary part""" + workprec = prec + i = 0 + while 1: + res = evalf(expr, workprec, options) + if res is S.ComplexInfinity: + return fnan, None, prec, None + value, accuracy = res[no::2] + # XXX is the last one correct? Consider re((1+I)**2).n() + if (not value) or accuracy >= prec or -value[2] > prec: + return value, None, accuracy, None + workprec += max(30, 2**i) + i += 1 + + +def evalf_abs(expr: 'Abs', prec: int, options: OPT_DICT) -> TMP_RES: + return get_abs(expr.args[0], prec, options) + + +def evalf_re(expr: 're', prec: int, options: OPT_DICT) -> TMP_RES: + return get_complex_part(expr.args[0], 0, prec, options) + + +def evalf_im(expr: 'im', prec: int, options: OPT_DICT) -> TMP_RES: + return get_complex_part(expr.args[0], 1, prec, options) + + +def finalize_complex(re: MPF_TUP, im: MPF_TUP, prec: int) -> TMP_RES: + if re == fzero and im == fzero: + raise ValueError("got complex zero with unknown accuracy") + elif re == fzero: + return None, im, None, prec + elif im == fzero: + return re, None, prec, None + + size_re = fastlog(re) + size_im = fastlog(im) + if size_re > size_im: + re_acc = prec + im_acc = prec + min(-(size_re - size_im), 0) + else: + im_acc = prec + re_acc = prec + min(-(size_im - size_re), 0) + return re, im, re_acc, im_acc + + +def chop_parts(value: TMP_RES, prec: int) -> TMP_RES: + """ + Chop off tiny real or complex parts. + """ + if value is S.ComplexInfinity: + return value + re, im, re_acc, im_acc = value + # Method 1: chop based on absolute value + if re and re not in _infs_nan and (fastlog(re) < -prec + 4): + re, re_acc = None, None + if im and im not in _infs_nan and (fastlog(im) < -prec + 4): + im, im_acc = None, None + # Method 2: chop if inaccurate and relatively small + if re and im: + delta = fastlog(re) - fastlog(im) + if re_acc < 2 and (delta - re_acc <= -prec + 4): + re, re_acc = None, None + if im_acc < 2 and (delta - im_acc >= prec - 4): + im, im_acc = None, None + return re, im, re_acc, im_acc + + +def check_target(expr: Expr, result: TMP_RES, prec: int): + a = complex_accuracy(result) + if a < prec: + raise PrecisionExhausted("Failed to distinguish the expression: \n\n%s\n\n" + "from zero. Try simplifying the input, using chop=True, or providing " + "a higher maxn for evalf" % (expr)) + + +def get_integer_part(expr: Expr, no: int, options: OPT_DICT, return_ints=False) -> \ + TMP_RES | tuple[int, int]: + """ + With no = 1, computes ceiling(expr) + With no = -1, computes floor(expr) + + Note: this function either gives the exact result or signals failure. + """ + from sympy.functions.elementary.complexes import re, im + # The expression is likely less than 2^30 or so + assumed_size = 30 + result = evalf(expr, assumed_size, options) + if result is S.ComplexInfinity: + raise ValueError("Cannot get integer part of Complex Infinity") + ire, iim, ire_acc, iim_acc = result + + # We now know the size, so we can calculate how much extra precision + # (if any) is needed to get within the nearest integer + if ire and iim: + gap = max(fastlog(ire) - ire_acc, fastlog(iim) - iim_acc) + elif ire: + gap = fastlog(ire) - ire_acc + elif iim: + gap = fastlog(iim) - iim_acc + else: + # ... or maybe the expression was exactly zero + if return_ints: + return 0, 0 + else: + return None, None, None, None + + margin = 10 + + if gap >= -margin: + prec = margin + assumed_size + gap + ire, iim, ire_acc, iim_acc = evalf( + expr, prec, options) + else: + prec = assumed_size + + # We can now easily find the nearest integer, but to find floor/ceil, we + # must also calculate whether the difference to the nearest integer is + # positive or negative (which may fail if very close). + def calc_part(re_im: Expr, nexpr: MPF_TUP): + from .add import Add + _, _, exponent, _ = nexpr + is_int = exponent == 0 + nint = int(to_int(nexpr, rnd)) + if is_int: + # make sure that we had enough precision to distinguish + # between nint and the re or im part (re_im) of expr that + # was passed to calc_part + ire, iim, ire_acc, iim_acc = evalf( + re_im - nint, 10, options) # don't need much precision + assert not iim + size = -fastlog(ire) + 2 # -ve b/c ire is less than 1 + if size > prec: + ire, iim, ire_acc, iim_acc = evalf( + re_im, size, options) + assert not iim + nexpr = ire + nint = int(to_int(nexpr, rnd)) + _, _, new_exp, _ = ire + is_int = new_exp == 0 + if not is_int: + # if there are subs and they all contain integer re/im parts + # then we can (hopefully) safely substitute them into the + # expression + s = options.get('subs', False) + if s: + # use strict=False with as_int because we take + # 2.0 == 2 + def is_int_reim(x): + """Check for integer or integer + I*integer.""" + try: + as_int(x, strict=False) + return True + except ValueError: + try: + [as_int(i, strict=False) for i in x.as_real_imag()] + return True + except ValueError: + return False + + if all(is_int_reim(v) for v in s.values()): + re_im = re_im.subs(s) + + re_im = Add(re_im, -nint, evaluate=False) + x, _, x_acc, _ = evalf(re_im, 10, options) + try: + check_target(re_im, (x, None, x_acc, None), 3) + except PrecisionExhausted: + if not re_im.equals(0): + raise PrecisionExhausted + x = fzero + nint += int(no*(mpf_cmp(x or fzero, fzero) == no)) + nint = from_int(nint) + return nint, INF + + re_, im_, re_acc, im_acc = None, None, None, None + + if ire is not None and ire != fzero: + re_, re_acc = calc_part(re(expr, evaluate=False), ire) + if iim is not None and iim != fzero: + im_, im_acc = calc_part(im(expr, evaluate=False), iim) + + if return_ints: + return int(to_int(re_ or fzero)), int(to_int(im_ or fzero)) + return re_, im_, re_acc, im_acc + + +def evalf_ceiling(expr: 'ceiling', prec: int, options: OPT_DICT) -> TMP_RES: + return get_integer_part(expr.args[0], 1, options) + + +def evalf_floor(expr: 'floor', prec: int, options: OPT_DICT) -> TMP_RES: + return get_integer_part(expr.args[0], -1, options) + + +def evalf_float(expr: 'Float', prec: int, options: OPT_DICT) -> TMP_RES: + return expr._mpf_, None, prec, None + + +def evalf_rational(expr: 'Rational', prec: int, options: OPT_DICT) -> TMP_RES: + return from_rational(expr.p, expr.q, prec), None, prec, None + + +def evalf_integer(expr: 'Integer', prec: int, options: OPT_DICT) -> TMP_RES: + return from_int(expr.p, prec), None, prec, None + +#----------------------------------------------------------------------------# +# # +# Arithmetic operations # +# # +#----------------------------------------------------------------------------# + + +def add_terms(terms: list, prec: int, target_prec: int) -> \ + tuple[MPF_TUP | SCALED_ZERO_TUP | None, int | None]: + """ + Helper for evalf_add. Adds a list of (mpfval, accuracy) terms. + + Returns + ======= + + - None, None if there are no non-zero terms; + - terms[0] if there is only 1 term; + - scaled_zero if the sum of the terms produces a zero by cancellation + e.g. mpfs representing 1 and -1 would produce a scaled zero which need + special handling since they are not actually zero and they are purposely + malformed to ensure that they cannot be used in anything but accuracy + calculations; + - a tuple that is scaled to target_prec that corresponds to the + sum of the terms. + + The returned mpf tuple will be normalized to target_prec; the input + prec is used to define the working precision. + + XXX explain why this is needed and why one cannot just loop using mpf_add + """ + + terms = [t for t in terms if not iszero(t[0])] + if not terms: + return None, None + elif len(terms) == 1: + return terms[0] + + # see if any argument is NaN or oo and thus warrants a special return + special = [] + from .numbers import Float + for t in terms: + arg = Float._new(t[0], 1) + if arg is S.NaN or arg.is_infinite: + special.append(arg) + if special: + from .add import Add + rv = evalf(Add(*special), prec + 4, {}) + return rv[0], rv[2] + + working_prec = 2*prec + sum_man, sum_exp = 0, 0 + absolute_err: list[int] = [] + + for x, accuracy in terms: + sign, man, exp, bc = x + if sign: + man = -man + absolute_err.append(bc + exp - accuracy) + delta = exp - sum_exp + if exp >= sum_exp: + # x much larger than existing sum? + # first: quick test + if ((delta > working_prec) and + ((not sum_man) or + delta - bitcount(abs(sum_man)) > working_prec)): + sum_man = man + sum_exp = exp + else: + sum_man += (man << delta) + else: + delta = -delta + # x much smaller than existing sum? + if delta - bc > working_prec: + if not sum_man: + sum_man, sum_exp = man, exp + else: + sum_man = (sum_man << delta) + man + sum_exp = exp + absolute_error = max(absolute_err) + if not sum_man: + return scaled_zero(absolute_error) + if sum_man < 0: + sum_sign = 1 + sum_man = -sum_man + else: + sum_sign = 0 + sum_bc = bitcount(sum_man) + sum_accuracy = sum_exp + sum_bc - absolute_error + r = normalize(sum_sign, sum_man, sum_exp, sum_bc, target_prec, + rnd), sum_accuracy + return r + + +def evalf_add(v: 'Add', prec: int, options: OPT_DICT) -> TMP_RES: + res = pure_complex(v) + if res: + h, c = res + re, _, re_acc, _ = evalf(h, prec, options) + im, _, im_acc, _ = evalf(c, prec, options) + return re, im, re_acc, im_acc + + oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) + + i = 0 + target_prec = prec + while 1: + options['maxprec'] = min(oldmaxprec, 2*prec) + + terms = [evalf(arg, prec + 10, options) for arg in v.args] + n = terms.count(S.ComplexInfinity) + if n >= 2: + return fnan, None, prec, None + re, re_acc = add_terms( + [a[0::2] for a in terms if isinstance(a, tuple) and a[0]], prec, target_prec) + im, im_acc = add_terms( + [a[1::2] for a in terms if isinstance(a, tuple) and a[1]], prec, target_prec) + if n == 1: + if re in (finf, fninf, fnan) or im in (finf, fninf, fnan): + return fnan, None, prec, None + return S.ComplexInfinity + acc = complex_accuracy((re, im, re_acc, im_acc)) + if acc >= target_prec: + if options.get('verbose'): + print("ADD: wanted", target_prec, "accurate bits, got", re_acc, im_acc) + break + else: + if (prec - target_prec) > options['maxprec']: + break + + prec = prec + max(10 + 2**i, target_prec - acc) + i += 1 + if options.get('verbose'): + print("ADD: restarting with prec", prec) + + options['maxprec'] = oldmaxprec + if iszero(re, scaled=True): + re = scaled_zero(re) + if iszero(im, scaled=True): + im = scaled_zero(im) + return re, im, re_acc, im_acc + + +def evalf_mul(v: 'Mul', prec: int, options: OPT_DICT) -> TMP_RES: + res = pure_complex(v) + if res: + # the only pure complex that is a mul is h*I + _, h = res + im, _, im_acc, _ = evalf(h, prec, options) + return None, im, None, im_acc + args = list(v.args) + + # see if any argument is NaN or oo and thus warrants a special return + has_zero = False + special = [] + from .numbers import Float + for arg in args: + result = evalf(arg, prec, options) + if result is S.ComplexInfinity: + special.append(result) + continue + if result[0] is None: + if result[1] is None: + has_zero = True + continue + num = Float._new(result[0], 1) + if num is S.NaN: + return fnan, None, prec, None + if num.is_infinite: + special.append(num) + if special: + if has_zero: + return fnan, None, prec, None + from .mul import Mul + return evalf(Mul(*special), prec + 4, {}) + if has_zero: + return None, None, None, None + + # With guard digits, multiplication in the real case does not destroy + # accuracy. This is also true in the complex case when considering the + # total accuracy; however accuracy for the real or imaginary parts + # separately may be lower. + acc = prec + + # XXX: big overestimate + working_prec = prec + len(args) + 5 + + # Empty product is 1 + start = man, exp, bc = MPZ(1), 0, 1 + + # First, we multiply all pure real or pure imaginary numbers. + # direction tells us that the result should be multiplied by + # I**direction; all other numbers get put into complex_factors + # to be multiplied out after the first phase. + last = len(args) + direction = 0 + args.append(S.One) + complex_factors = [] + + for i, arg in enumerate(args): + if i != last and pure_complex(arg): + args[-1] = (args[-1]*arg).expand() + continue + elif i == last and arg is S.One: + continue + re, im, re_acc, im_acc = evalf(arg, working_prec, options) + if re and im: + complex_factors.append((re, im, re_acc, im_acc)) + continue + elif re: + (s, m, e, b), w_acc = re, re_acc + elif im: + (s, m, e, b), w_acc = im, im_acc + direction += 1 + else: + return None, None, None, None + direction += 2*s + man *= m + exp += e + bc += b + while bc > 3*working_prec: + man >>= working_prec + exp += working_prec + bc -= working_prec + acc = min(acc, w_acc) + sign = (direction & 2) >> 1 + if not complex_factors: + v = normalize(sign, man, exp, bitcount(man), prec, rnd) + # multiply by i + if direction & 1: + return None, v, None, acc + else: + return v, None, acc, None + else: + # initialize with the first term + if (man, exp, bc) != start: + # there was a real part; give it an imaginary part + re, im = (sign, man, exp, bitcount(man)), (0, MPZ(0), 0, 0) + i0 = 0 + else: + # there is no real part to start (other than the starting 1) + wre, wim, wre_acc, wim_acc = complex_factors[0] + acc = min(acc, + complex_accuracy((wre, wim, wre_acc, wim_acc))) + re = wre + im = wim + i0 = 1 + + for wre, wim, wre_acc, wim_acc in complex_factors[i0:]: + # acc is the overall accuracy of the product; we aren't + # computing exact accuracies of the product. + acc = min(acc, + complex_accuracy((wre, wim, wre_acc, wim_acc))) + + use_prec = working_prec + A = mpf_mul(re, wre, use_prec) + B = mpf_mul(mpf_neg(im), wim, use_prec) + C = mpf_mul(re, wim, use_prec) + D = mpf_mul(im, wre, use_prec) + re = mpf_add(A, B, use_prec) + im = mpf_add(C, D, use_prec) + if options.get('verbose'): + print("MUL: wanted", prec, "accurate bits, got", acc) + # multiply by I + if direction & 1: + re, im = mpf_neg(im), re + return re, im, acc, acc + + +def evalf_pow(v: 'Pow', prec: int, options) -> TMP_RES: + + target_prec = prec + base, exp = v.args + + # We handle x**n separately. This has two purposes: 1) it is much + # faster, because we avoid calling evalf on the exponent, and 2) it + # allows better handling of real/imaginary parts that are exactly zero + if exp.is_Integer: + p: int = exp.p # type: ignore + # Exact + if not p: + return fone, None, prec, None + # Exponentiation by p magnifies relative error by |p|, so the + # base must be evaluated with increased precision if p is large + prec += int(math.log2(abs(p))) + result = evalf(base, prec + 5, options) + if result is S.ComplexInfinity: + if p < 0: + return None, None, None, None + return result + re, im, re_acc, im_acc = result + # Real to integer power + if re and not im: + return mpf_pow_int(re, p, target_prec), None, target_prec, None + # (x*I)**n = I**n * x**n + if im and not re: + z = mpf_pow_int(im, p, target_prec) + case = p % 4 + if case == 0: + return z, None, target_prec, None + if case == 1: + return None, z, None, target_prec + if case == 2: + return mpf_neg(z), None, target_prec, None + if case == 3: + return None, mpf_neg(z), None, target_prec + # Zero raised to an integer power + if not re: + if p < 0: + return S.ComplexInfinity + return None, None, None, None + # General complex number to arbitrary integer power + re, im = libmp.mpc_pow_int((re, im), p, prec) + # Assumes full accuracy in input + return finalize_complex(re, im, target_prec) + + result = evalf(base, prec + 5, options) + if result is S.ComplexInfinity: + if exp.is_Rational: + if exp < 0: + return None, None, None, None + return result + raise NotImplementedError + + # Pure square root + if exp is S.Half: + xre, xim, _, _ = result + # General complex square root + if xim: + re, im = libmp.mpc_sqrt((xre or fzero, xim), prec) + return finalize_complex(re, im, prec) + if not xre: + return None, None, None, None + # Square root of a negative real number + if mpf_lt(xre, fzero): + return None, mpf_sqrt(mpf_neg(xre), prec), None, prec + # Positive square root + return mpf_sqrt(xre, prec), None, prec, None + + # We first evaluate the exponent to find its magnitude + # This determines the working precision that must be used + prec += 10 + result = evalf(exp, prec, options) + if result is S.ComplexInfinity: + return fnan, None, prec, None + yre, yim, _, _ = result + # Special cases: x**0 + if not (yre or yim): + return fone, None, prec, None + + ysize = fastlog(yre) + # Restart if too big + # XXX: prec + ysize might exceed maxprec + if ysize > 5: + prec += ysize + yre, yim, _, _ = evalf(exp, prec, options) + + # Pure exponential function; no need to evalf the base + if base is S.Exp1: + if yim: + re, im = libmp.mpc_exp((yre or fzero, yim), prec) + return finalize_complex(re, im, target_prec) + return mpf_exp(yre, target_prec), None, target_prec, None + + xre, xim, _, _ = evalf(base, prec + 5, options) + # 0**y + if not (xre or xim): + if yim: + return fnan, None, prec, None + if yre[0] == 1: # y < 0 + return S.ComplexInfinity + return None, None, None, None + + # (real ** complex) or (complex ** complex) + if yim: + re, im = libmp.mpc_pow( + (xre or fzero, xim or fzero), (yre or fzero, yim), + target_prec) + return finalize_complex(re, im, target_prec) + # complex ** real + if xim: + re, im = libmp.mpc_pow_mpf((xre or fzero, xim), yre, target_prec) + return finalize_complex(re, im, target_prec) + # negative ** real + elif mpf_lt(xre, fzero): + re, im = libmp.mpc_pow_mpf((xre, fzero), yre, target_prec) + return finalize_complex(re, im, target_prec) + # positive ** real + else: + return mpf_pow(xre, yre, target_prec), None, target_prec, None + + +#----------------------------------------------------------------------------# +# # +# Special functions # +# # +#----------------------------------------------------------------------------# + + +def evalf_exp(expr: 'exp', prec: int, options: OPT_DICT) -> TMP_RES: + from .power import Pow + return evalf_pow(Pow(S.Exp1, expr.exp, evaluate=False), prec, options) + + +def evalf_trig(v: Expr, prec: int, options: OPT_DICT) -> TMP_RES: + """ + This function handles sin , cos and tan of complex arguments. + + """ + from sympy.functions.elementary.trigonometric import cos, sin, tan + if isinstance(v, cos): + func = mpf_cos + elif isinstance(v, sin): + func = mpf_sin + elif isinstance(v,tan): + func = mpf_tan + else: + raise NotImplementedError + arg = v.args[0] + # 20 extra bits is possibly overkill. It does make the need + # to restart very unlikely + xprec = prec + 20 + re, im, re_acc, im_acc = evalf(arg, xprec, options) + if im: + if 'subs' in options: + v = v.subs(options['subs']) + return evalf(v._eval_evalf(prec), prec, options) + if not re: + if isinstance(v, cos): + return fone, None, prec, None + elif isinstance(v, sin): + return None, None, None, None + elif isinstance(v,tan): + return None, None, None, None + else: + raise NotImplementedError + # For trigonometric functions, we are interested in the + # fixed-point (absolute) accuracy of the argument. + xsize = fastlog(re) + # Magnitude <= 1.0. OK to compute directly, because there is no + # danger of hitting the first root of cos (with sin, magnitude + # <= 2.0 would actually be ok) + if xsize < 1: + return func(re, prec, rnd), None, prec, None + # Very large + if xsize >= 10: + xprec = prec + xsize + re, im, re_acc, im_acc = evalf(arg, xprec, options) + # Need to repeat in case the argument is very close to a + # multiple of pi (or pi/2), hitting close to a root + while 1: + y = func(re, prec, rnd) + ysize = fastlog(y) + gap = -ysize + accuracy = (xprec - xsize) - gap + if accuracy < prec: + if options.get('verbose'): + print("SIN/COS/TAN", accuracy, "wanted", prec, "gap", gap) + print(to_str(y, 10)) + if xprec > options.get('maxprec', DEFAULT_MAXPREC): + return y, None, accuracy, None + xprec += gap + re, im, re_acc, im_acc = evalf(arg, xprec, options) + continue + else: + return y, None, prec, None + + +def evalf_log(expr: 'log', prec: int, options: OPT_DICT) -> TMP_RES: + if len(expr.args)>1: + expr = expr.doit() + return evalf(expr, prec, options) + arg = expr.args[0] + workprec = prec + 10 + result = evalf(arg, workprec, options) + if result is S.ComplexInfinity: + return result + xre, xim, xacc, _ = result + + # evalf can return NoneTypes if chop=True + # issue 18516, 19623 + if xre is xim is None: + # Dear reviewer, I do not know what -inf is; + # it looks to be (1, 0, -789, -3) + # but I'm not sure in general, + # so we just let mpmath figure + # it out by taking log of 0 directly. + # It would be better to return -inf instead. + xre = fzero + + if xim: + from sympy.functions.elementary.complexes import Abs + from sympy.functions.elementary.exponential import log + + # XXX: use get_abs etc instead + re = evalf_log( + log(Abs(arg, evaluate=False), evaluate=False), prec, options) + im = mpf_atan2(xim, xre or fzero, prec) + return re[0], im, re[2], prec + + imaginary_term = (mpf_cmp(xre, fzero) < 0) + + re = mpf_log(mpf_abs(xre), prec, rnd) + size = fastlog(re) + if prec - size > workprec and re != fzero: + from .add import Add + # We actually need to compute 1+x accurately, not x + add = Add(S.NegativeOne, arg, evaluate=False) + xre, xim, _, _ = evalf_add(add, prec, options) + prec2 = workprec - fastlog(xre) + # xre is now x - 1 so we add 1 back here to calculate x + re = mpf_log(mpf_abs(mpf_add(xre, fone, prec2)), prec, rnd) + + re_acc = prec + + if imaginary_term: + return re, mpf_pi(prec), re_acc, prec + else: + return re, None, re_acc, None + + +def evalf_atan(v: 'atan', prec: int, options: OPT_DICT) -> TMP_RES: + arg = v.args[0] + xre, xim, reacc, imacc = evalf(arg, prec + 5, options) + if xre is xim is None: + return (None,)*4 + if xim: + raise NotImplementedError + return mpf_atan(xre, prec, rnd), None, prec, None + + +def evalf_subs(prec: int, subs: dict) -> dict: + """ Change all Float entries in `subs` to have precision prec. """ + newsubs = {} + for a, b in subs.items(): + b = S(b) + if b.is_Float: + b = b._eval_evalf(prec) + newsubs[a] = b + return newsubs + + +def evalf_piecewise(expr: Expr, prec: int, options: OPT_DICT) -> TMP_RES: + from .numbers import Float, Integer + if 'subs' in options: + expr = expr.subs(evalf_subs(prec, options['subs'])) + newopts = options.copy() + del newopts['subs'] + if hasattr(expr, 'func'): + return evalf(expr, prec, newopts) + if isinstance(expr, float): + return evalf(Float(expr), prec, newopts) + if isinstance(expr, int): + return evalf(Integer(expr), prec, newopts) + + # We still have undefined symbols + raise NotImplementedError + + +def evalf_alg_num(a: 'AlgebraicNumber', prec: int, options: OPT_DICT) -> TMP_RES: + return evalf(a.to_root(), prec, options) + +#----------------------------------------------------------------------------# +# # +# High-level operations # +# # +#----------------------------------------------------------------------------# + + +def as_mpmath(x: Any, prec: int, options: OPT_DICT) -> mpc | mpf: + from .numbers import Infinity, NegativeInfinity, Zero + x = sympify(x) + if isinstance(x, Zero) or x == 0.0: + return mpf(0) + if isinstance(x, Infinity): + return mpf('inf') + if isinstance(x, NegativeInfinity): + return mpf('-inf') + # XXX + result = evalf(x, prec, options) + return quad_to_mpmath(result) + + +def do_integral(expr: 'Integral', prec: int, options: OPT_DICT) -> TMP_RES: + func = expr.args[0] + x, xlow, xhigh = expr.args[1] + if xlow == xhigh: + xlow = xhigh = 0 + elif x not in func.free_symbols: + # only the difference in limits matters in this case + # so if there is a symbol in common that will cancel + # out when taking the difference, then use that + # difference + if xhigh.free_symbols & xlow.free_symbols: + diff = xhigh - xlow + if diff.is_number: + xlow, xhigh = 0, diff + + oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) + options['maxprec'] = min(oldmaxprec, 2*prec) + + with workprec(prec + 5): + xlow = as_mpmath(xlow, prec + 15, options) + xhigh = as_mpmath(xhigh, prec + 15, options) + + # Integration is like summation, and we can phone home from + # the integrand function to update accuracy summation style + # Note that this accuracy is inaccurate, since it fails + # to account for the variable quadrature weights, + # but it is better than nothing + + from sympy.functions.elementary.trigonometric import cos, sin + from .symbol import Wild + + have_part = [False, False] + max_real_term: float | int = MINUS_INF + max_imag_term: float | int = MINUS_INF + + def f(t: Expr) -> mpc | mpf: + nonlocal max_real_term, max_imag_term + re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}}) + + have_part[0] = re or have_part[0] + have_part[1] = im or have_part[1] + + max_real_term = max(max_real_term, fastlog(re)) + max_imag_term = max(max_imag_term, fastlog(im)) + + if im: + return mpc(re or fzero, im) + return mpf(re or fzero) + + if options.get('quad') == 'osc': + A = Wild('A', exclude=[x]) + B = Wild('B', exclude=[x]) + D = Wild('D') + m = func.match(cos(A*x + B)*D) + if not m: + m = func.match(sin(A*x + B)*D) + if not m: + raise ValueError("An integrand of the form sin(A*x+B)*f(x) " + "or cos(A*x+B)*f(x) is required for oscillatory quadrature") + period = as_mpmath(2*S.Pi/m[A], prec + 15, options) + result = quadosc(f, [xlow, xhigh], period=period) + # XXX: quadosc does not do error detection yet + quadrature_error = MINUS_INF + else: + result, quadrature_err = quadts(f, [xlow, xhigh], error=1) + quadrature_error = fastlog(quadrature_err._mpf_) + + options['maxprec'] = oldmaxprec + + if have_part[0]: + re: MPF_TUP | None = result.real._mpf_ + re_acc: int | None + if re == fzero: + re_s, re_acc = scaled_zero(int(-max(prec, max_real_term, quadrature_error))) + re = scaled_zero(re_s) # handled ok in evalf_integral + else: + re_acc = int(-max(max_real_term - fastlog(re) - prec, quadrature_error)) + else: + re, re_acc = None, None + + if have_part[1]: + im: MPF_TUP | None = result.imag._mpf_ + im_acc: int | None + if im == fzero: + im_s, im_acc = scaled_zero(int(-max(prec, max_imag_term, quadrature_error))) + im = scaled_zero(im_s) # handled ok in evalf_integral + else: + im_acc = int(-max(max_imag_term - fastlog(im) - prec, quadrature_error)) + else: + im, im_acc = None, None + + result = re, im, re_acc, im_acc + return result + + +def evalf_integral(expr: 'Integral', prec: int, options: OPT_DICT) -> TMP_RES: + limits = expr.limits + if len(limits) != 1 or len(limits[0]) != 3: + raise NotImplementedError + workprec = prec + i = 0 + maxprec = options.get('maxprec', INF) + while 1: + result = do_integral(expr, workprec, options) + accuracy = complex_accuracy(result) + if accuracy >= prec: # achieved desired precision + break + if workprec >= maxprec: # can't increase accuracy any more + break + if accuracy == -1: + # maybe the answer really is zero and maybe we just haven't increased + # the precision enough. So increase by doubling to not take too long + # to get to maxprec. + workprec *= 2 + else: + workprec += max(prec, 2**i) + workprec = min(workprec, maxprec) + i += 1 + return result + + +def check_convergence(numer: Expr, denom: Expr, n: Symbol) -> tuple[int, Any, Any]: + """ + Returns + ======= + + (h, g, p) where + -- h is: + > 0 for convergence of rate 1/factorial(n)**h + < 0 for divergence of rate factorial(n)**(-h) + = 0 for geometric or polynomial convergence or divergence + + -- abs(g) is: + > 1 for geometric convergence of rate 1/h**n + < 1 for geometric divergence of rate h**n + = 1 for polynomial convergence or divergence + + (g < 0 indicates an alternating series) + + -- p is: + > 1 for polynomial convergence of rate 1/n**h + <= 1 for polynomial divergence of rate n**(-h) + + """ + from sympy.polys.polytools import Poly + npol = Poly(numer, n) + dpol = Poly(denom, n) + p = npol.degree() + q = dpol.degree() + rate = q - p + if rate: + return rate, None, None + constant = dpol.LC() / npol.LC() + from .numbers import equal_valued + if not equal_valued(abs(constant), 1): + return rate, constant, None + if npol.degree() == dpol.degree() == 0: + return rate, constant, 0 + pc = npol.all_coeffs()[1] + qc = dpol.all_coeffs()[1] + return rate, constant, (qc - pc)/dpol.LC() + + +def hypsum(expr: Expr, n: Symbol, start: int, prec: int) -> mpf: + """ + Sum a rapidly convergent infinite hypergeometric series with + given general term, e.g. e = hypsum(1/factorial(n), n). The + quotient between successive terms must be a quotient of integer + polynomials. + """ + from .numbers import Float, equal_valued + from sympy.simplify.simplify import hypersimp + + if prec == float('inf'): + raise NotImplementedError('does not support inf prec') + + if start: + expr = expr.subs(n, n + start) + hs = hypersimp(expr, n) + if hs is None: + raise NotImplementedError("a hypergeometric series is required") + num, den = hs.as_numer_denom() + + func1 = lambdify(n, num) + func2 = lambdify(n, den) + + h, g, p = check_convergence(num, den, n) + + if h < 0: + raise ValueError("Sum diverges like (n!)^%i" % (-h)) + + eterm = expr.subs(n, 0) + if not eterm.is_Rational: + raise NotImplementedError("Non rational term functionality is not implemented.") + + term: Rational = eterm # type: ignore + + # Direct summation if geometric or faster + if h > 0 or (h == 0 and abs(g) > 1): + term = (MPZ(term.p) << prec) // term.q + s = term + k = 1 + while abs(term) > 5: + term *= MPZ(func1(k - 1)) + term //= MPZ(func2(k - 1)) + s += term + k += 1 + return from_man_exp(s, -prec) + else: + alt = g < 0 + if abs(g) < 1: + raise ValueError("Sum diverges like (%i)^n" % abs(1/g)) + if p < 1 or (equal_valued(p, 1) and not alt): + raise ValueError("Sum diverges like n^%i" % (-p)) + # We have polynomial convergence: use Richardson extrapolation + vold = None + ndig = prec_to_dps(prec) + while True: + # Need to use at least quad precision because a lot of cancellation + # might occur in the extrapolation process; we check the answer to + # make sure that the desired precision has been reached, too. + prec2 = 4*prec + term0 = (MPZ(term.p) << prec2) // term.q + + def summand(k, _term=[term0]): + if k: + k = int(k) + _term[0] *= MPZ(func1(k - 1)) + _term[0] //= MPZ(func2(k - 1)) + return make_mpf(from_man_exp(_term[0], -prec2)) + + with workprec(prec): + v = nsum(summand, [0, mpmath_inf], method='richardson') + vf = Float(v, ndig) + if vold is not None and vold == vf: + break + prec += prec # double precision each time + vold = vf + + return v._mpf_ + + +def evalf_prod(expr: 'Product', prec: int, options: OPT_DICT) -> TMP_RES: + if all((l[1] - l[2]).is_Integer for l in expr.limits): + result = evalf(expr.doit(), prec=prec, options=options) + else: + from sympy.concrete.summations import Sum + result = evalf(expr.rewrite(Sum), prec=prec, options=options) + return result + + +def evalf_sum(expr: 'Sum', prec: int, options: OPT_DICT) -> TMP_RES: + from .numbers import Float + if 'subs' in options: + expr = expr.subs(options['subs']) # type: ignore + func = expr.function + limits = expr.limits + if len(limits) != 1 or len(limits[0]) != 3: + raise NotImplementedError + if func.is_zero: + return None, None, prec, None + prec2 = prec + 10 + try: + n, a, b = limits[0] + if b is not S.Infinity or a is S.NegativeInfinity or a != int(a): + raise NotImplementedError + # Use fast hypergeometric summation if possible + v = hypsum(func, n, int(a), prec2) + delta = prec - fastlog(v) + if fastlog(v) < -10: + v = hypsum(func, n, int(a), delta) + return v, None, min(prec, delta), None + except NotImplementedError: + # Euler-Maclaurin summation for general series + eps = Float(2.0)**(-prec) + for i in range(1, 5): + m = n = 2**i * prec + s, err = expr.euler_maclaurin(m=m, n=n, eps=eps, + eval_integral=False) + err = err.evalf() + if err is S.NaN: + raise NotImplementedError + if err <= eps: + break + err = fastlog(evalf(abs(err), 20, options)[0]) + re, im, re_acc, im_acc = evalf(s, prec2, options) + if re_acc is None: + re_acc = -err + if im_acc is None: + im_acc = -err + return re, im, re_acc, im_acc + + +#----------------------------------------------------------------------------# +# # +# Symbolic interface # +# # +#----------------------------------------------------------------------------# + +def evalf_symbol(x: Expr, prec: int, options: OPT_DICT) -> TMP_RES: + val = options['subs'][x] + if isinstance(val, mpf): + if not val: + return None, None, None, None + return val._mpf_, None, prec, None + else: + if '_cache' not in options: + options['_cache'] = {} + cache = options['_cache'] + cached, cached_prec = cache.get(x, (None, MINUS_INF)) + if cached_prec >= prec: + return cached + v = evalf(sympify(val), prec, options) + cache[x] = (v, prec) + return v + +evalf_table: dict[Type[Expr], Callable[[Expr, int, OPT_DICT], TMP_RES]] = {} + + +def _create_evalf_table(): + global evalf_table + from sympy.concrete.products import Product + from sympy.concrete.summations import Sum + from .add import Add + from .mul import Mul + from .numbers import Exp1, Float, Half, ImaginaryUnit, Integer, NaN, NegativeOne, One, Pi, Rational, \ + Zero, ComplexInfinity, AlgebraicNumber + from .power import Pow + from .symbol import Dummy, Symbol + from sympy.functions.elementary.complexes import Abs, im, re + from sympy.functions.elementary.exponential import exp, log + from sympy.functions.elementary.integers import ceiling, floor + from sympy.functions.elementary.piecewise import Piecewise + from sympy.functions.elementary.trigonometric import atan, cos, sin, tan + from sympy.integrals.integrals import Integral + evalf_table = { + Symbol: evalf_symbol, + Dummy: evalf_symbol, + Float: evalf_float, + Rational: evalf_rational, + Integer: evalf_integer, + Zero: lambda x, prec, options: (None, None, prec, None), + One: lambda x, prec, options: (fone, None, prec, None), + Half: lambda x, prec, options: (fhalf, None, prec, None), + Pi: lambda x, prec, options: (mpf_pi(prec), None, prec, None), + Exp1: lambda x, prec, options: (mpf_e(prec), None, prec, None), + ImaginaryUnit: lambda x, prec, options: (None, fone, None, prec), + NegativeOne: lambda x, prec, options: (fnone, None, prec, None), + ComplexInfinity: lambda x, prec, options: S.ComplexInfinity, + NaN: lambda x, prec, options: (fnan, None, prec, None), + + exp: evalf_exp, + + cos: evalf_trig, + sin: evalf_trig, + tan: evalf_trig, + + Add: evalf_add, + Mul: evalf_mul, + Pow: evalf_pow, + + log: evalf_log, + atan: evalf_atan, + Abs: evalf_abs, + + re: evalf_re, + im: evalf_im, + floor: evalf_floor, + ceiling: evalf_ceiling, + + Integral: evalf_integral, + Sum: evalf_sum, + Product: evalf_prod, + Piecewise: evalf_piecewise, + + AlgebraicNumber: evalf_alg_num, + } + + +def evalf(x: Expr, prec: int, options: OPT_DICT) -> TMP_RES: + """ + Evaluate the ``Expr`` instance, ``x`` + to a binary precision of ``prec``. This + function is supposed to be used internally. + + Parameters + ========== + + x : Expr + The formula to evaluate to a float. + prec : int + The binary precision that the output should have. + options : dict + A dictionary with the same entries as + ``EvalfMixin.evalf`` and in addition, + ``maxprec`` which is the maximum working precision. + + Returns + ======= + + An optional tuple, ``(re, im, re_acc, im_acc)`` + which are the real, imaginary, real accuracy + and imaginary accuracy respectively. ``re`` is + an mpf value tuple and so is ``im``. ``re_acc`` + and ``im_acc`` are ints. + + NB: all these return values can be ``None``. + If all values are ``None``, then that represents 0. + Note that 0 is also represented as ``fzero = (0, 0, 0, 0)``. + """ + from sympy.functions.elementary.complexes import re as re_, im as im_ + try: + rf = evalf_table[type(x)] + r = rf(x, prec, options) + except KeyError: + # Fall back to ordinary evalf if possible + if 'subs' in options: + x = x.subs(evalf_subs(prec, options['subs'])) + xe = x._eval_evalf(prec) + if xe is None: + raise NotImplementedError + as_real_imag = getattr(xe, "as_real_imag", None) + if as_real_imag is None: + raise NotImplementedError # e.g. FiniteSet(-1.0, 1.0).evalf() + re, im = as_real_imag() + if re.has(re_) or im.has(im_): + raise NotImplementedError + if not re: + re = None + reprec = None + elif re.is_number: + re = re._to_mpmath(prec, allow_ints=False)._mpf_ + reprec = prec + else: + raise NotImplementedError + if not im: + im = None + imprec = None + elif im.is_number: + im = im._to_mpmath(prec, allow_ints=False)._mpf_ + imprec = prec + else: + raise NotImplementedError + r = re, im, reprec, imprec + + if options.get("verbose"): + print("### input", x) + print("### output", to_str(r[0] or fzero, 50) if isinstance(r, tuple) else r) + print("### raw", r) # r[0], r[2] + print() + chop = options.get('chop', False) + if chop: + if chop is True: + chop_prec = prec + else: + # convert (approximately) from given tolerance; + # the formula here will will make 1e-i rounds to 0 for + # i in the range +/-27 while 2e-i will not be chopped + chop_prec = int(round(-3.321*math.log10(chop) + 2.5)) + if chop_prec == 3: + chop_prec -= 1 + r = chop_parts(r, chop_prec) + if options.get("strict"): + check_target(x, r, prec) + return r + + +def quad_to_mpmath(q, ctx=None): + """Turn the quad returned by ``evalf`` into an ``mpf`` or ``mpc``. """ + mpc = make_mpc if ctx is None else ctx.make_mpc + mpf = make_mpf if ctx is None else ctx.make_mpf + if q is S.ComplexInfinity: + raise NotImplementedError + re, im, _, _ = q + if im: + if not re: + re = fzero + return mpc((re, im)) + elif re: + return mpf(re) + else: + return mpf(fzero) + + +class EvalfMixin: + """Mixin class adding evalf capability.""" + + __slots__: tuple[str, ...] = () + + def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): + """ + Evaluate the given formula to an accuracy of *n* digits. + + Parameters + ========== + + subs : dict, optional + Substitute numerical values for symbols, e.g. + ``subs={x:3, y:1+pi}``. The substitutions must be given as a + dictionary. + + maxn : int, optional + Allow a maximum temporary working precision of maxn digits. + + chop : bool or number, optional + Specifies how to replace tiny real or imaginary parts in + subresults by exact zeros. + + When ``True`` the chop value defaults to standard precision. + + Otherwise the chop value is used to determine the + magnitude of "small" for purposes of chopping. + + >>> from sympy import N + >>> x = 1e-4 + >>> N(x, chop=True) + 0.000100000000000000 + >>> N(x, chop=1e-5) + 0.000100000000000000 + >>> N(x, chop=1e-4) + 0 + + strict : bool, optional + Raise ``PrecisionExhausted`` if any subresult fails to + evaluate to full accuracy, given the available maxprec. + + quad : str, optional + Choose algorithm for numerical quadrature. By default, + tanh-sinh quadrature is used. For oscillatory + integrals on an infinite interval, try ``quad='osc'``. + + verbose : bool, optional + Print debug information. + + Notes + ===== + + When Floats are naively substituted into an expression, + precision errors may adversely affect the result. For example, + adding 1e16 (a Float) to 1 will truncate to 1e16; if 1e16 is + then subtracted, the result will be 0. + That is exactly what happens in the following: + + >>> from sympy.abc import x, y, z + >>> values = {x: 1e16, y: 1, z: 1e16} + >>> (x + y - z).subs(values) + 0 + + Using the subs argument for evalf is the accurate way to + evaluate such an expression: + + >>> (x + y - z).evalf(subs=values) + 1.00000000000000 + """ + from .numbers import Float, Number + n = n if n is not None else 15 + + if subs and is_sequence(subs): + raise TypeError('subs must be given as a dictionary') + + # for sake of sage that doesn't like evalf(1) + if n == 1 and isinstance(self, Number): + from .expr import _mag + rv = self.evalf(2, subs, maxn, chop, strict, quad, verbose) + m = _mag(rv) + rv = rv.round(1 - m) + return rv + + if not evalf_table: + _create_evalf_table() + prec = dps_to_prec(n) + options = {'maxprec': max(prec, int(maxn*LG10)), 'chop': chop, + 'strict': strict, 'verbose': verbose} + if subs is not None: + options['subs'] = subs + if quad is not None: + options['quad'] = quad + try: + result = evalf(self, prec + 4, options) + except NotImplementedError: + # Fall back to the ordinary evalf + if hasattr(self, 'subs') and subs is not None: # issue 20291 + v = self.subs(subs)._eval_evalf(prec) + else: + v = self._eval_evalf(prec) + if v is None: + return self + elif not v.is_number: + return v + try: + # If the result is numerical, normalize it + result = evalf(v, prec, options) + except NotImplementedError: + # Probably contains symbols or unknown functions + return v + if result is S.ComplexInfinity: + return result + re, im, re_acc, im_acc = result + if re is S.NaN or im is S.NaN: + return S.NaN + if re: + p = max(min(prec, re_acc), 1) + re = Float._new(re, p) + else: + re = S.Zero + if im: + p = max(min(prec, im_acc), 1) + im = Float._new(im, p) + return re + im*S.ImaginaryUnit + else: + return re + + n = evalf + + def _evalf(self, prec: int) -> Expr: + """Helper for evalf. Does the same thing but takes binary precision""" + r = self._eval_evalf(prec) + if r is None: + r = self # type: ignore + return r # type: ignore + + def _eval_evalf(self, prec: int) -> Expr | None: + return None + + def _to_mpmath(self, prec, allow_ints=True): + # mpmath functions accept ints as input + errmsg = "cannot convert to mpmath number" + if allow_ints and self.is_Integer: + return self.p + if hasattr(self, '_as_mpf_val'): + return make_mpf(self._as_mpf_val(prec)) + try: + result = evalf(self, prec, {}) + return quad_to_mpmath(result) + except NotImplementedError: + v = self._eval_evalf(prec) + if v is None: + raise ValueError(errmsg) + if v.is_Float: + return make_mpf(v._mpf_) + # Number + Number*I is also fine + re, im = v.as_real_imag() + if allow_ints and re.is_Integer: + re = from_int(re.p) + elif re.is_Float: + re = re._mpf_ + else: + raise ValueError(errmsg) + if allow_ints and im.is_Integer: + im = from_int(im.p) + elif im.is_Float: + im = im._mpf_ + else: + raise ValueError(errmsg) + return make_mpc((re, im)) + + +def N(x, n=15, **options): + r""" + Calls x.evalf(n, \*\*options). + + Explanations + ============ + + Both .n() and N() are equivalent to .evalf(); use the one that you like better. + See also the docstring of .evalf() for information on the options. + + Examples + ======== + + >>> from sympy import Sum, oo, N + >>> from sympy.abc import k + >>> Sum(1/k**k, (k, 1, oo)) + Sum(k**(-k), (k, 1, oo)) + >>> N(_, 4) + 1.291 + + """ + # by using rational=True, any evaluation of a string + # will be done using exact values for the Floats + return sympify(x, rational=True).evalf(n, **options) + + +def _evalf_with_bounded_error(x: Expr, eps: Expr | None = None, + m: int = 0, + options: OPT_DICT | None = None) -> TMP_RES: + """ + Evaluate *x* to within a bounded absolute error. + + Parameters + ========== + + x : Expr + The quantity to be evaluated. + eps : Expr, None, optional (default=None) + Positive real upper bound on the acceptable error. + m : int, optional (default=0) + If *eps* is None, then use 2**(-m) as the upper bound on the error. + options: OPT_DICT + As in the ``evalf`` function. + + Returns + ======= + + A tuple ``(re, im, re_acc, im_acc)``, as returned by ``evalf``. + + See Also + ======== + + evalf + + """ + if eps is not None: + if not (eps.is_Rational or eps.is_Float) or not eps > 0: + raise ValueError("eps must be positive") + r, _, _, _ = evalf(1/eps, 1, {}) + m = fastlog(r) + + c, d, _, _ = evalf(x, 1, {}) + # Note: If x = a + b*I, then |a| <= 2|c| and |b| <= 2|d|, with equality + # only in the zero case. + # If a is non-zero, then |c| = 2**nc for some integer nc, and c has + # bitcount 1. Therefore 2**fastlog(c) = 2**(nc+1) = 2|c| is an upper bound + # on |a|. Likewise for b and d. + nr, ni = fastlog(c), fastlog(d) + n = max(nr, ni) + 1 + # If x is 0, then n is MINUS_INF, and p will be 1. Otherwise, + # n - 1 bits get us past the integer parts of a and b, and +1 accounts for + # the factor of <= sqrt(2) that is |x|/max(|a|, |b|). + p = max(1, m + n + 1) + + options = options or {} + return evalf(x, p, options) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/expr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/expr.py new file mode 100644 index 0000000000000000000000000000000000000000..e66ff239a679942f2cc95c3f66af1fc13f7229d9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/expr.py @@ -0,0 +1,4194 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, overload +from collections.abc import Iterable, Mapping +from functools import reduce +import re + +from .sympify import sympify, _sympify +from .basic import Basic, Atom +from .singleton import S +from .evalf import EvalfMixin, pure_complex, DEFAULT_MAXPREC +from .decorators import call_highest_priority, sympify_method_args, sympify_return +from .cache import cacheit +from .logic import fuzzy_or, fuzzy_not +from .intfunc import mod_inverse +from .sorting import default_sort_key +from .kind import NumberKind +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.misc import as_int, func_name, filldedent +from sympy.utilities.iterables import has_variety, sift +from mpmath.libmp import mpf_log, prec_to_dps +from mpmath.libmp.libintmath import giant_steps + + +if TYPE_CHECKING: + from typing import Any + from typing_extensions import Self + from .numbers import Number + +from collections import defaultdict + + +def _corem(eq, c): # helper for extract_additively + # return co, diff from co*c + diff + co = [] + non = [] + for i in Add.make_args(eq): + ci = i.coeff(c) + if not ci: + non.append(i) + else: + co.append(ci) + return Add(*co), Add(*non) + + +@sympify_method_args +class Expr(Basic, EvalfMixin): + """ + Base class for algebraic expressions. + + Explanation + =========== + + Everything that requires arithmetic operations to be defined + should subclass this class, instead of Basic (which should be + used only for argument storage and expression manipulation, i.e. + pattern matching, substitutions, etc). + + If you want to override the comparisons of expressions: + Should use _eval_is_ge for inequality, or _eval_is_eq, with multiple dispatch. + _eval_is_ge return true if x >= y, false if x < y, and None if the two types + are not comparable or the comparison is indeterminate + + See Also + ======== + + sympy.core.basic.Basic + """ + + __slots__: tuple[str, ...] = () + + if TYPE_CHECKING: + + def __new__(cls, *args: Basic) -> Self: + ... + + @overload # type: ignore + def subs(self, arg1: Mapping[Basic | complex, Expr | complex], arg2: None=None) -> Expr: ... + @overload + def subs(self, arg1: Iterable[tuple[Basic | complex, Expr | complex]], arg2: None=None, **kwargs: Any) -> Expr: ... + @overload + def subs(self, arg1: Expr | complex, arg2: Expr | complex) -> Expr: ... + @overload + def subs(self, arg1: Mapping[Basic | complex, Basic | complex], arg2: None=None, **kwargs: Any) -> Basic: ... + @overload + def subs(self, arg1: Iterable[tuple[Basic | complex, Basic | complex]], arg2: None=None, **kwargs: Any) -> Basic: ... + @overload + def subs(self, arg1: Basic | complex, arg2: Basic | complex, **kwargs: Any) -> Basic: ... + + def subs(self, arg1: Mapping[Basic | complex, Basic | complex] | Basic | complex, # type: ignore + arg2: Basic | complex | None = None, **kwargs: Any) -> Basic: + ... + + def simplify(self, **kwargs) -> Expr: + ... + + def evalf(self, n: int = 15, subs: dict[Basic, Basic | float] | None = None, + maxn: int = 100, chop: bool = False, strict: bool = False, + quad: str | None = None, verbose: bool = False) -> Expr: + ... + + n = evalf + + is_scalar = True # self derivative is 1 + + @property + def _diff_wrt(self): + """Return True if one can differentiate with respect to this + object, else False. + + Explanation + =========== + + Subclasses such as Symbol, Function and Derivative return True + to enable derivatives wrt them. The implementation in Derivative + separates the Symbol and non-Symbol (_diff_wrt=True) variables and + temporarily converts the non-Symbols into Symbols when performing + the differentiation. By default, any object deriving from Expr + will behave like a scalar with self.diff(self) == 1. If this is + not desired then the object must also set `is_scalar = False` or + else define an _eval_derivative routine. + + Note, see the docstring of Derivative for how this should work + mathematically. In particular, note that expr.subs(yourclass, Symbol) + should be well-defined on a structural level, or this will lead to + inconsistent results. + + Examples + ======== + + >>> from sympy import Expr + >>> e = Expr() + >>> e._diff_wrt + False + >>> class MyScalar(Expr): + ... _diff_wrt = True + ... + >>> MyScalar().diff(MyScalar()) + 1 + >>> class MySymbol(Expr): + ... _diff_wrt = True + ... is_scalar = False + ... + >>> MySymbol().diff(MySymbol()) + Derivative(MySymbol(), MySymbol()) + """ + return False + + @cacheit + def sort_key(self, order=None): + + coeff, expr = self.as_coeff_Mul() + + if expr.is_Pow: + base, exp = expr.as_base_exp() + if base is S.Exp1: + # If we remove this, many doctests will go crazy: + # (keeps E**x sorted like the exp(x) function, + # part of exp(x) to E**x transition) + base, exp = Function("exp")(exp), S.One + expr = base + else: + exp = S.One + + if expr.is_Dummy: + args = (expr.sort_key(),) + elif expr.is_Atom: + args = (str(expr),) + else: + if expr.is_Add: + args = expr.as_ordered_terms(order=order) + elif expr.is_Mul: + args = expr.as_ordered_factors(order=order) + else: + args = expr.args + + args = tuple( + [ default_sort_key(arg, order=order) for arg in args ]) + + args = (len(args), tuple(args)) + exp = exp.sort_key(order=order) + + return expr.class_key(), args, exp, coeff + + def _hashable_content(self): + """Return a tuple of information about self that can be used to + compute the hash. If a class defines additional attributes, + like ``name`` in Symbol, then this method should be updated + accordingly to return such relevant attributes. + Defining more than _hashable_content is necessary if __eq__ has + been defined by a class. See note about this in Basic.__eq__.""" + return self._args + + # *************** + # * Arithmetics * + # *************** + # Expr and its subclasses use _op_priority to determine which object + # passed to a binary special method (__mul__, etc.) will handle the + # operation. In general, the 'call_highest_priority' decorator will choose + # the object with the highest _op_priority to handle the call. + # Custom subclasses that want to define their own binary special methods + # should set an _op_priority value that is higher than the default. + # + # **NOTE**: + # This is a temporary fix, and will eventually be replaced with + # something better and more powerful. See issue 5510. + _op_priority = 10.0 + + @property + def _add_handler(self): + return Add + + @property + def _mul_handler(self): + return Mul + + def __pos__(self) -> Expr: + return self + + def __neg__(self) -> Expr: + # Mul has its own __neg__ routine, so we just + # create a 2-args Mul with the -1 in the canonical + # slot 0. + c = self.is_commutative + return Mul._from_args((S.NegativeOne, self), c) + + def __abs__(self) -> Expr: + from sympy.functions.elementary.complexes import Abs + return Abs(self) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__radd__') + def __add__(self, other) -> Expr: + return Add(self, other) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__add__') + def __radd__(self, other) -> Expr: + return Add(other, self) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__rsub__') + def __sub__(self, other) -> Expr: + return Add(self, -other) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__sub__') + def __rsub__(self, other) -> Expr: + return Add(other, -self) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__rmul__') + def __mul__(self, other) -> Expr: + return Mul(self, other) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__mul__') + def __rmul__(self, other) -> Expr: + return Mul(other, self) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__rpow__') + def _pow(self, other): + return Pow(self, other) + + def __pow__(self, other, mod=None) -> Expr: + if mod is None: + return self._pow(other) + try: + _self, other, mod = as_int(self), as_int(other), as_int(mod) + if other >= 0: + return _sympify(pow(_self, other, mod)) + else: + return _sympify(mod_inverse(pow(_self, -other, mod), mod)) + except ValueError: + power = self._pow(other) + try: + return power%mod + except TypeError: + return NotImplemented + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__pow__') + def __rpow__(self, other) -> Expr: + return Pow(other, self) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__rtruediv__') + def __truediv__(self, other) -> Expr: + denom = Pow(other, S.NegativeOne) + if self is S.One: + return denom + else: + return Mul(self, denom) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__truediv__') + def __rtruediv__(self, other) -> Expr: + denom = Pow(self, S.NegativeOne) + if other is S.One: + return denom + else: + return Mul(other, denom) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__rmod__') + def __mod__(self, other) -> Expr: + return Mod(self, other) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__mod__') + def __rmod__(self, other) -> Expr: + return Mod(other, self) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__rfloordiv__') + def __floordiv__(self, other) -> Expr: + from sympy.functions.elementary.integers import floor + return floor(self / other) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__floordiv__') + def __rfloordiv__(self, other) -> Expr: + from sympy.functions.elementary.integers import floor + return floor(other / self) + + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__rdivmod__') + def __divmod__(self, other) -> tuple[Expr, Expr]: + from sympy.functions.elementary.integers import floor + return floor(self / other), Mod(self, other) + + @sympify_return([('other', 'Expr')], NotImplemented) + @call_highest_priority('__divmod__') + def __rdivmod__(self, other) -> tuple[Expr, Expr]: + from sympy.functions.elementary.integers import floor + return floor(other / self), Mod(other, self) + + def __int__(self) -> int: + if not self.is_number: + raise TypeError("Cannot convert symbols to int") + r = self.round(2) + if not r.is_Number: + raise TypeError("Cannot convert complex to int") + if r in (S.NaN, S.Infinity, S.NegativeInfinity): + raise TypeError("Cannot convert %s to int" % r) + i = int(r) + if not i: + return i + if int_valued(r): + # non-integer self should pass one of these tests + if (self > i) is S.true: + return i + if (self < i) is S.true: + return i - 1 + ok = self.equals(i) + if ok is None: + raise TypeError('cannot compute int value accurately') + if ok: + return i + # off by one + return i - (1 if i > 0 else -1) + return i + + def __float__(self) -> float: + # Don't bother testing if it's a number; if it's not this is going + # to fail, and if it is we still need to check that it evalf'ed to + # a number. + result = self.evalf() + if result.is_Number: + return float(result) + if result.is_number and result.as_real_imag()[1]: + raise TypeError("Cannot convert complex to float") + raise TypeError("Cannot convert expression to float") + + def __complex__(self) -> complex: + result = self.evalf() + re, im = result.as_real_imag() + return complex(float(re), float(im)) + + @sympify_return([('other', 'Expr')], NotImplemented) + def __ge__(self, other): + from .relational import GreaterThan + return GreaterThan(self, other) + + @sympify_return([('other', 'Expr')], NotImplemented) + def __le__(self, other): + from .relational import LessThan + return LessThan(self, other) + + @sympify_return([('other', 'Expr')], NotImplemented) + def __gt__(self, other): + from .relational import StrictGreaterThan + return StrictGreaterThan(self, other) + + @sympify_return([('other', 'Expr')], NotImplemented) + def __lt__(self, other): + from .relational import StrictLessThan + return StrictLessThan(self, other) + + def __trunc__(self): + if not self.is_number: + raise TypeError("Cannot truncate symbols and expressions") + else: + return Integer(self) + + def __format__(self, format_spec: str): + if self.is_number: + mt = re.match(r'\+?\d*\.(\d+)f', format_spec) + if mt: + prec = int(mt.group(1)) + rounded = self.round(prec) + if rounded.is_Integer: + return format(int(rounded), format_spec) + if rounded.is_Float: + return format(rounded, format_spec) + return super().__format__(format_spec) + + @staticmethod + def _from_mpmath(x, prec): + if hasattr(x, "_mpf_"): + return Float._new(x._mpf_, prec) + elif hasattr(x, "_mpc_"): + re, im = x._mpc_ + re = Float._new(re, prec) + im = Float._new(im, prec)*S.ImaginaryUnit + return re + im + else: + raise TypeError("expected mpmath number (mpf or mpc)") + + @property + def is_number(self): + """Returns True if ``self`` has no free symbols and no + undefined functions (AppliedUndef, to be precise). It will be + faster than ``if not self.free_symbols``, however, since + ``is_number`` will fail as soon as it hits a free symbol + or undefined function. + + Examples + ======== + + >>> from sympy import Function, Integral, cos, sin, pi + >>> from sympy.abc import x + >>> f = Function('f') + + >>> x.is_number + False + >>> f(1).is_number + False + >>> (2*x).is_number + False + >>> (2 + Integral(2, x)).is_number + False + >>> (2 + Integral(2, (x, 1, 2))).is_number + True + + Not all numbers are Numbers in the SymPy sense: + + >>> pi.is_number, pi.is_Number + (True, False) + + If something is a number it should evaluate to a number with + real and imaginary parts that are Numbers; the result may not + be comparable, however, since the real and/or imaginary part + of the result may not have precision. + + >>> cos(1).is_number and cos(1).is_comparable + True + + >>> z = cos(1)**2 + sin(1)**2 - 1 + >>> z.is_number + True + >>> z.is_comparable + False + + See Also + ======== + + sympy.core.basic.Basic.is_comparable + """ + return all(obj.is_number for obj in self.args) + + def _eval_is_comparable(self): + # Basic._eval_is_comparable always returns False, so we override it + # here + is_extended_real = self.is_extended_real + if is_extended_real is False: + return False + if not self.is_number: + return False + + # XXX: as_real_imag() can be a very expensive operation. It should not + # be used here because is_comparable is used implicitly in many places. + # Probably this method should just return self.evalf(2).is_Number. + + n, i = self.as_real_imag() + + if not n.is_Number: + n = n.evalf(2) + if not n.is_Number: + return False + + if not i.is_Number: + i = i.evalf(2) + if not i.is_Number: + return False + + if i: + # if _prec = 1 we can't decide and if not, + # the answer is False because numbers with + # imaginary parts can't be compared + # so return False + return False + else: + return n._prec != 1 + + def _random(self, n=None, re_min=-1, im_min=-1, re_max=1, im_max=1): + """Return self evaluated, if possible, replacing free symbols with + random complex values, if necessary. + + Explanation + =========== + + The random complex value for each free symbol is generated + by the random_complex_number routine giving real and imaginary + parts in the range given by the re_min, re_max, im_min, and im_max + values. The returned value is evaluated to a precision of n + (if given) else the maximum of 15 and the precision needed + to get more than 1 digit of precision. If the expression + could not be evaluated to a number, or could not be evaluated + to more than 1 digit of precision, then None is returned. + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.abc import x, y + >>> x._random() # doctest: +SKIP + 0.0392918155679172 + 0.916050214307199*I + >>> x._random(2) # doctest: +SKIP + -0.77 - 0.87*I + >>> (x + y/2)._random(2) # doctest: +SKIP + -0.57 + 0.16*I + >>> sqrt(2)._random(2) + 1.4 + + See Also + ======== + + sympy.core.random.random_complex_number + """ + + free = self.free_symbols + prec = 1 + if free: + from sympy.core.random import random_complex_number + a, c, b, d = re_min, re_max, im_min, im_max + reps = dict(list(zip(free, [random_complex_number(a, b, c, d, rational=True) + for zi in free]))) + try: + nmag = abs(self.evalf(2, subs=reps)) + except (ValueError, TypeError): + # if an out of range value resulted in evalf problems + # then return None -- XXX is there a way to know how to + # select a good random number for a given expression? + # e.g. when calculating n! negative values for n should not + # be used + return None + else: + reps = {} + nmag = abs(self.evalf(2)) + + if not hasattr(nmag, '_prec'): + # e.g. exp_polar(2*I*pi) doesn't evaluate but is_number is True + return None + + if nmag._prec == 1: + # increase the precision up to the default maximum + # precision to see if we can get any significance + + # evaluate + for prec in giant_steps(2, DEFAULT_MAXPREC): + nmag = abs(self.evalf(prec, subs=reps)) + if nmag._prec != 1: + break + + if nmag._prec != 1: + if n is None: + n = max(prec, 15) + return self.evalf(n, subs=reps) + + # never got any significance + return None + + def is_constant(self, *wrt, **flags): + """Return True if self is constant, False if not, or None if + the constancy could not be determined conclusively. + + Explanation + =========== + + If an expression has no free symbols then it is a constant. If + there are free symbols it is possible that the expression is a + constant, perhaps (but not necessarily) zero. To test such + expressions, a few strategies are tried: + + 1) numerical evaluation at two random points. If two such evaluations + give two different values and the values have a precision greater than + 1 then self is not constant. If the evaluations agree or could not be + obtained with any precision, no decision is made. The numerical testing + is done only if ``wrt`` is different than the free symbols. + + 2) differentiation with respect to variables in 'wrt' (or all free + symbols if omitted) to see if the expression is constant or not. This + will not always lead to an expression that is zero even though an + expression is constant (see added test in test_expr.py). If + all derivatives are zero then self is constant with respect to the + given symbols. + + 3) finding out zeros of denominator expression with free_symbols. + It will not be constant if there are zeros. It gives more negative + answers for expression that are not constant. + + If neither evaluation nor differentiation can prove the expression is + constant, None is returned unless two numerical values happened to be + the same and the flag ``failing_number`` is True -- in that case the + numerical value will be returned. + + If flag simplify=False is passed, self will not be simplified; + the default is True since self should be simplified before testing. + + Examples + ======== + + >>> from sympy import cos, sin, Sum, S, pi + >>> from sympy.abc import a, n, x, y + >>> x.is_constant() + False + >>> S(2).is_constant() + True + >>> Sum(x, (x, 1, 10)).is_constant() + True + >>> Sum(x, (x, 1, n)).is_constant() + False + >>> Sum(x, (x, 1, n)).is_constant(y) + True + >>> Sum(x, (x, 1, n)).is_constant(n) + False + >>> Sum(x, (x, 1, n)).is_constant(x) + True + >>> eq = a*cos(x)**2 + a*sin(x)**2 - a + >>> eq.is_constant() + True + >>> eq.subs({x: pi, a: 2}) == eq.subs({x: pi, a: 3}) == 0 + True + + >>> (0**x).is_constant() + False + >>> x.is_constant() + False + >>> (x**x).is_constant() + False + >>> one = cos(x)**2 + sin(x)**2 + >>> one.is_constant() + True + >>> ((one - 1)**(x + 1)).is_constant() in (True, False) # could be 0 or 1 + True + """ + + simplify = flags.get('simplify', True) + + if self.is_number: + return True + free = self.free_symbols + if not free: + return True # assume f(1) is some constant + + # if we are only interested in some symbols and they are not in the + # free symbols then this expression is constant wrt those symbols + wrt = set(wrt) + if wrt and not wrt & free: + return True + wrt = wrt or free + + # simplify unless this has already been done + expr = self + if simplify: + expr = expr.simplify() + + # is_zero should be a quick assumptions check; it can be wrong for + # numbers (see test_is_not_constant test), giving False when it + # shouldn't, but hopefully it will never give True unless it is sure. + if expr.is_zero: + return True + + # Don't attempt substitution or differentiation with non-number symbols + wrt_number = {sym for sym in wrt if sym.kind is NumberKind} + + # try numerical evaluation to see if we get two different values + failing_number = None + if wrt_number == free: + # try 0 (for a) and 1 (for b) + try: + a = expr.subs(list(zip(free, [0]*len(free))), + simultaneous=True) + if a is S.NaN: + # evaluation may succeed when substitution fails + a = expr._random(None, 0, 0, 0, 0) + except ZeroDivisionError: + a = None + if a is not None and a is not S.NaN: + try: + b = expr.subs(list(zip(free, [1]*len(free))), + simultaneous=True) + if b is S.NaN: + # evaluation may succeed when substitution fails + b = expr._random(None, 1, 0, 1, 0) + except ZeroDivisionError: + b = None + if b is not None and b is not S.NaN and b.equals(a) is False: + return False + # try random real + b = expr._random(None, -1, 0, 1, 0) + if b is not None and b is not S.NaN and b.equals(a) is False: + return False + # try random complex + b = expr._random() + if b is not None and b is not S.NaN: + if b.equals(a) is False: + return False + failing_number = a if a.is_number else b + + # now we will test each wrt symbol (or all free symbols) to see if the + # expression depends on them or not using differentiation. This is + # not sufficient for all expressions, however, so we don't return + # False if we get a derivative other than 0 with free symbols. + for w in wrt_number: + deriv = expr.diff(w) + if simplify: + deriv = deriv.simplify() + if deriv != 0: + if not (pure_complex(deriv, or_real=True)): + if flags.get('failing_number', False): + return failing_number + return False + from sympy.solvers.solvers import denoms + return fuzzy_not(fuzzy_or(den.is_zero for den in denoms(self))) + + def equals(self, other, failing_expression=False): + """Return True if self == other, False if it does not, or None. If + failing_expression is True then the expression which did not simplify + to a 0 will be returned instead of None. + + Explanation + =========== + + If ``self`` is a Number (or complex number) that is not zero, then + the result is False. + + If ``self`` is a number and has not evaluated to zero, evalf will be + used to test whether the expression evaluates to zero. If it does so + and the result has significance (i.e. the precision is either -1, for + a Rational result, or is greater than 1) then the evalf value will be + used to return True or False. + + """ + from sympy.simplify.simplify import nsimplify, simplify + from sympy.solvers.solvers import solve + from sympy.polys.polyerrors import NotAlgebraic + from sympy.polys.numberfields import minimal_polynomial + + other = sympify(other) + + if not isinstance(other, Expr): + return False + + if self == other: + return True + + # they aren't the same so see if we can make the difference 0; + # don't worry about doing simplification steps one at a time + # because if the expression ever goes to 0 then the subsequent + # simplification steps that are done will be very fast. + diff = factor_terms(simplify(self - other), radical=True) + + if not diff: + return True + + if not diff.has(Add, Mod): + # if there is no expanding to be done after simplifying + # then this can't be a zero + return False + + factors = diff.as_coeff_mul()[1] + if len(factors) > 1: # avoid infinity recursion + fac_zero = [fac.equals(0) for fac in factors] + if None not in fac_zero: # every part can be decided + return any(fac_zero) + + constant = diff.is_constant(simplify=False, failing_number=True) + + if constant is False: + return False + + if not diff.is_number: + if constant is None: + # e.g. unless the right simplification is done, a symbolic + # zero is possible (see expression of issue 6829: without + # simplification constant will be None). + return + + if constant is True: + # this gives a number whether there are free symbols or not + ndiff = diff._random() + # is_comparable will work whether the result is real + # or complex; it could be None, however. + if ndiff and ndiff.is_comparable: + return False + + # sometimes we can use a simplified result to give a clue as to + # what the expression should be; if the expression is *not* zero + # then we should have been able to compute that and so now + # we can just consider the cases where the approximation appears + # to be zero -- we try to prove it via minimal_polynomial. + # + # removed + # ns = nsimplify(diff) + # if diff.is_number and (not ns or ns == diff): + # + # The thought was that if it nsimplifies to 0 that's a sure sign + # to try the following to prove it; or if it changed but wasn't + # zero that might be a sign that it's not going to be easy to + # prove. But tests seem to be working without that logic. + # + if diff.is_number: + # try to prove via self-consistency + surds = [s for s in diff.atoms(Pow) if s.args[0].is_Integer] + # it seems to work better to try big ones first + surds.sort(key=lambda x: -x.args[0]) + for s in surds: + try: + # simplify is False here -- this expression has already + # been identified as being hard to identify as zero; + # we will handle the checking ourselves using nsimplify + # to see if we are in the right ballpark or not and if so + # *then* the simplification will be attempted. + sol = solve(diff, s, simplify=False) + if sol: + if s in sol: + # the self-consistent result is present + return True + if all(si.is_Integer for si in sol): + # perfect powers are removed at instantiation + # so surd s cannot be an integer + return False + if all(i.is_algebraic is False for i in sol): + # a surd is algebraic + return False + if any(si in surds for si in sol): + # it wasn't equal to s but it is in surds + # and different surds are not equal + return False + if any(nsimplify(s - si) == 0 and + simplify(s - si) == 0 for si in sol): + return True + if s.is_real: + if any(nsimplify(si, [s]) == s and simplify(si) == s + for si in sol): + return True + except NotImplementedError: + pass + + # try to prove with minimal_polynomial but know when + # *not* to use this or else it can take a long time. e.g. issue 8354 + if True: # change True to condition that assures non-hang + try: + mp = minimal_polynomial(diff) + if mp.is_Symbol: + return True + return False + except (NotAlgebraic, NotImplementedError): + pass + + # diff has not simplified to zero; constant is either None, True + # or the number with significance (is_comparable) that was randomly + # calculated twice as the same value. + if constant not in (True, None) and constant != 0: + return False + + if failing_expression: + return diff + return None + + def _eval_is_extended_positive_negative(self, positive): + from sympy.polys.numberfields import minimal_polynomial + from sympy.polys.polyerrors import NotAlgebraic + if self.is_number: + # check to see that we can get a value + try: + n2 = self._eval_evalf(2) + # XXX: This shouldn't be caught here + # Catches ValueError: hypsum() failed to converge to the requested + # 34 bits of accuracy + except ValueError: + return None + if n2 is None: + return None + if getattr(n2, '_prec', 1) == 1: # no significance + return None + if n2 is S.NaN: + return None + + f = self.evalf(2) + if f.is_Float: + match = f, S.Zero + else: + match = pure_complex(f) + if match is None: + return False + r, i = match + if not (i.is_Number and r.is_Number): + return False + if r._prec != 1 and i._prec != 1: + return bool(not i and ((r > 0) if positive else (r < 0))) + elif r._prec == 1 and (not i or i._prec == 1) and \ + self._eval_is_algebraic() and not self.has(Function): + try: + if minimal_polynomial(self).is_Symbol: + return False + except (NotAlgebraic, NotImplementedError): + pass + + def _eval_is_extended_positive(self): + return self._eval_is_extended_positive_negative(positive=True) + + def _eval_is_extended_negative(self): + return self._eval_is_extended_positive_negative(positive=False) + + def _eval_interval(self, x, a, b): + """ + Returns evaluation over an interval. For most functions this is: + + self.subs(x, b) - self.subs(x, a), + + possibly using limit() if NaN is returned from subs, or if + singularities are found between a and b. + + If b or a is None, it only evaluates -self.subs(x, a) or self.subs(b, x), + respectively. + + """ + from sympy.calculus.accumulationbounds import AccumBounds + from sympy.functions.elementary.exponential import log + from sympy.series.limits import limit, Limit + from sympy.sets.sets import Interval + from sympy.solvers.solveset import solveset + + if (a is None and b is None): + raise ValueError('Both interval ends cannot be None.') + + def _eval_endpoint(left): + c = a if left else b + if c is None: + return S.Zero + else: + C = self.subs(x, c) + if C.has(S.NaN, S.Infinity, S.NegativeInfinity, + S.ComplexInfinity, AccumBounds): + if (a < b) != False: + C = limit(self, x, c, "+" if left else "-") + else: + C = limit(self, x, c, "-" if left else "+") + + if isinstance(C, Limit): + raise NotImplementedError("Could not compute limit") + return C + + if a == b: + return S.Zero + + A = _eval_endpoint(left=True) + if A is S.NaN: + return A + + B = _eval_endpoint(left=False) + + if (a and b) is None: + return B - A + + value = B - A + + if a.is_comparable and b.is_comparable: + if a < b: + domain = Interval(a, b) + else: + domain = Interval(b, a) + # check the singularities of self within the interval + # if singularities is a ConditionSet (not iterable), catch the exception and pass + singularities = solveset(self.cancel().as_numer_denom()[1], x, + domain=domain) + for logterm in self.atoms(log): + singularities = singularities | solveset(logterm.args[0], x, + domain=domain) + try: + for s in singularities: + if value is S.NaN: + # no need to keep adding, it will stay NaN + break + if not s.is_comparable: + continue + if (a < s) == (s < b) == True: + value += -limit(self, x, s, "+") + limit(self, x, s, "-") + elif (b < s) == (s < a) == True: + value += limit(self, x, s, "+") - limit(self, x, s, "-") + except TypeError: + pass + + return value + + def _eval_power(self, expt) -> Expr | None: + # subclass to compute self**other for cases when + # other is not NaN, 0, or 1 + return None + + def _eval_conjugate(self): + if self.is_extended_real: + return self + elif self.is_imaginary: + return -self + + def conjugate(self): + """Returns the complex conjugate of 'self'.""" + from sympy.functions.elementary.complexes import conjugate as c + return c(self) + + def dir(self, x, cdir): + if self.is_zero: + return S.Zero + from sympy.functions.elementary.exponential import log + minexp = S.Zero + arg = self + while arg: + minexp += S.One + arg = arg.diff(x) + coeff = arg.subs(x, 0) + if coeff is S.NaN: + coeff = arg.limit(x, 0) + if coeff is S.ComplexInfinity: + try: + coeff, _ = arg.leadterm(x) + if coeff.has(log(x)): + raise ValueError() + except ValueError: + coeff = arg.limit(x, 0) + if coeff != S.Zero: + break + return coeff*cdir**minexp + + def _eval_transpose(self): + from sympy.functions.elementary.complexes import conjugate + if self.is_commutative: + return self + elif self.is_hermitian: + return conjugate(self) + elif self.is_antihermitian: + return -conjugate(self) + + def transpose(self): + from sympy.functions.elementary.complexes import transpose + return transpose(self) + + def _eval_adjoint(self): + from sympy.functions.elementary.complexes import conjugate, transpose + if self.is_hermitian: + return self + elif self.is_antihermitian: + return -self + obj = self._eval_conjugate() + if obj is not None: + return transpose(obj) + obj = self._eval_transpose() + if obj is not None: + return conjugate(obj) + + def adjoint(self): + from sympy.functions.elementary.complexes import adjoint + return adjoint(self) + + @classmethod + def _parse_order(cls, order): + """Parse and configure the ordering of terms. """ + from sympy.polys.orderings import monomial_key + + startswith = getattr(order, "startswith", None) + if startswith is None: + reverse = False + else: + reverse = startswith('rev-') + if reverse: + order = order[4:] + + monom_key = monomial_key(order) + + def neg(monom): + return tuple([neg(m) if isinstance(m, tuple) else -m for m in monom]) + + def key(term): + _, ((re, im), monom, ncpart) = term + + monom = neg(monom_key(monom)) + ncpart = tuple([e.sort_key(order=order) for e in ncpart]) + coeff = ((bool(im), im), (re, im)) + + return monom, ncpart, coeff + + return key, reverse + + def as_ordered_factors(self, order=None): + """Return list of ordered factors (if Mul) else [self].""" + return [self] + + def as_poly(self, *gens, **args): + """Converts ``self`` to a polynomial or returns ``None``. + + Explanation + =========== + + >>> from sympy import sin + >>> from sympy.abc import x, y + + >>> print((x**2 + x*y).as_poly()) + Poly(x**2 + x*y, x, y, domain='ZZ') + + >>> print((x**2 + x*y).as_poly(x, y)) + Poly(x**2 + x*y, x, y, domain='ZZ') + + >>> print((x**2 + sin(y)).as_poly(x, y)) + None + + """ + from sympy.polys.polyerrors import PolynomialError, GeneratorsNeeded + from sympy.polys.polytools import Poly + + try: + poly = Poly(self, *gens, **args) + + if not poly.is_Poly: + return None + else: + return poly + except (PolynomialError, GeneratorsNeeded): + # PolynomialError is caught for e.g. exp(x).as_poly(x) + # GeneratorsNeeded is caught for e.g. S(2).as_poly() + return None + + def as_ordered_terms(self, order=None, data=False): + """ + Transform an expression to an ordered list of terms. + + Examples + ======== + + >>> from sympy import sin, cos + >>> from sympy.abc import x + + >>> (sin(x)**2*cos(x) + sin(x)**2 + 1).as_ordered_terms() + [sin(x)**2*cos(x), sin(x)**2, 1] + + """ + + from .numbers import Number, NumberSymbol + + if order is None and self.is_Add: + # Spot the special case of Add(Number, Mul(Number, expr)) with the + # first number positive and the second number negative + key = lambda x:not isinstance(x, (Number, NumberSymbol)) + add_args = sorted(Add.make_args(self), key=key) + if (len(add_args) == 2 + and isinstance(add_args[0], (Number, NumberSymbol)) + and isinstance(add_args[1], Mul)): + mul_args = sorted(Mul.make_args(add_args[1]), key=key) + if (len(mul_args) == 2 + and isinstance(mul_args[0], Number) + and add_args[0].is_positive + and mul_args[0].is_negative): + return add_args + + key, reverse = self._parse_order(order) + terms, gens = self.as_terms() + + if not any(term.is_Order for term, _ in terms): + ordered = sorted(terms, key=key, reverse=reverse) + else: + _terms, _order = [], [] + + for term, repr in terms: + if not term.is_Order: + _terms.append((term, repr)) + else: + _order.append((term, repr)) + + ordered = sorted(_terms, key=key, reverse=True) \ + + sorted(_order, key=key, reverse=True) + + if data: + return ordered, gens + else: + return [term for term, _ in ordered] + + def as_terms(self): + """Transform an expression to a list of terms. """ + from .exprtools import decompose_power + + gens, terms = set(), [] + + for term in Add.make_args(self): + coeff, _term = term.as_coeff_Mul() + + coeff = complex(coeff) + cpart, ncpart = {}, [] + + if _term is not S.One: + for factor in Mul.make_args(_term): + if factor.is_number: + try: + coeff *= complex(factor) + except (TypeError, ValueError): + pass + else: + continue + + if factor.is_commutative: + base, exp = decompose_power(factor) + + cpart[base] = exp + gens.add(base) + else: + ncpart.append(factor) + + coeff = coeff.real, coeff.imag + ncpart = tuple(ncpart) + + terms.append((term, (coeff, cpart, ncpart))) + + gens = sorted(gens, key=default_sort_key) + + k, indices = len(gens), {} + + for i, g in enumerate(gens): + indices[g] = i + + result = [] + + for term, (coeff, cpart, ncpart) in terms: + monom = [0]*k + + for base, exp in cpart.items(): + monom[indices[base]] = exp + + result.append((term, (coeff, tuple(monom), ncpart))) + + return result, gens + + def removeO(self) -> Expr: + """Removes the additive O(..) symbol if there is one""" + return self + + def getO(self) -> Expr | None: + """Returns the additive O(..) symbol if there is one, else None.""" + return None + + def getn(self): + """ + Returns the order of the expression. + + Explanation + =========== + + The order is determined either from the O(...) term. If there + is no O(...) term, it returns None. + + Examples + ======== + + >>> from sympy import O + >>> from sympy.abc import x + >>> (1 + x + O(x**2)).getn() + 2 + >>> (1 + x).getn() + + """ + o = self.getO() + if o is None: + return None + elif o.is_Order: + o = o.expr + if o is S.One: + return S.Zero + if o.is_Symbol: + return S.One + if o.is_Pow: + return o.args[1] + if o.is_Mul: # x**n*log(x)**n or x**n/log(x)**n + for oi in o.args: + if oi.is_Symbol: + return S.One + if oi.is_Pow: + from .symbol import Dummy, Symbol + syms = oi.atoms(Symbol) + if len(syms) == 1: + x = syms.pop() + oi = oi.subs(x, Dummy('x', positive=True)) + if oi.base.is_Symbol and oi.exp.is_Rational: + return abs(oi.exp) + + raise NotImplementedError('not sure of order of %s' % o) + + def count_ops(self, visual=False): + from .function import count_ops + return count_ops(self, visual) + + def args_cnc(self, cset=False, warn=True, split_1=True): + """Return [commutative factors, non-commutative factors] of self. + + Explanation + =========== + + self is treated as a Mul and the ordering of the factors is maintained. + If ``cset`` is True the commutative factors will be returned in a set. + If there were repeated factors (as may happen with an unevaluated Mul) + then an error will be raised unless it is explicitly suppressed by + setting ``warn`` to False. + + Note: -1 is always separated from a Number unless split_1 is False. + + Examples + ======== + + >>> from sympy import symbols, oo + >>> A, B = symbols('A B', commutative=0) + >>> x, y = symbols('x y') + >>> (-2*x*y).args_cnc() + [[-1, 2, x, y], []] + >>> (-2.5*x).args_cnc() + [[-1, 2.5, x], []] + >>> (-2*x*A*B*y).args_cnc() + [[-1, 2, x, y], [A, B]] + >>> (-2*x*A*B*y).args_cnc(split_1=False) + [[-2, x, y], [A, B]] + >>> (-2*x*y).args_cnc(cset=True) + [{-1, 2, x, y}, []] + + The arg is always treated as a Mul: + + >>> (-2 + x + A).args_cnc() + [[], [x - 2 + A]] + >>> (-oo).args_cnc() # -oo is a singleton + [[-1, oo], []] + """ + args = list(Mul.make_args(self)) + + for i, mi in enumerate(args): + if not mi.is_commutative: + c = args[:i] + nc = args[i:] + break + else: + c = args + nc = [] + + if c and split_1 and ( + c[0].is_Number and + c[0].is_extended_negative and + c[0] is not S.NegativeOne): + c[:1] = [S.NegativeOne, -c[0]] + + if cset: + clen = len(c) + c = set(c) + if clen and warn and len(c) != clen: + raise ValueError('repeated commutative arguments: %s' % + [ci for ci in c if list(self.args).count(ci) > 1]) + return [c, nc] + + def coeff(self, x: Expr, n=1, right=False, _first=True): + """ + Returns the coefficient from the term(s) containing ``x**n``. If ``n`` + is zero then all terms independent of ``x`` will be returned. + + Explanation + =========== + + When ``x`` is noncommutative, the coefficient to the left (default) or + right of ``x`` can be returned. The keyword 'right' is ignored when + ``x`` is commutative. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.abc import x, y, z + + You can select terms that have an explicit negative in front of them: + + >>> (-x + 2*y).coeff(-1) + x + >>> (x - 2*y).coeff(-1) + 2*y + + You can select terms with no Rational coefficient: + + >>> (x + 2*y).coeff(1) + x + >>> (3 + 2*x + 4*x**2).coeff(1) + 0 + + You can select terms independent of x by making n=0; in this case + expr.as_independent(x)[0] is returned (and 0 will be returned instead + of None): + + >>> (3 + 2*x + 4*x**2).coeff(x, 0) + 3 + >>> eq = ((x + 1)**3).expand() + 1 + >>> eq + x**3 + 3*x**2 + 3*x + 2 + >>> [eq.coeff(x, i) for i in reversed(range(4))] + [1, 3, 3, 2] + >>> eq -= 2 + >>> [eq.coeff(x, i) for i in reversed(range(4))] + [1, 3, 3, 0] + + You can select terms that have a numerical term in front of them: + + >>> (-x - 2*y).coeff(2) + -y + >>> from sympy import sqrt + >>> (x + sqrt(2)*x).coeff(sqrt(2)) + x + + The matching is exact: + + >>> (3 + 2*x + 4*x**2).coeff(x) + 2 + >>> (3 + 2*x + 4*x**2).coeff(x**2) + 4 + >>> (3 + 2*x + 4*x**2).coeff(x**3) + 0 + >>> (z*(x + y)**2).coeff((x + y)**2) + z + >>> (z*(x + y)**2).coeff(x + y) + 0 + + In addition, no factoring is done, so 1 + z*(1 + y) is not obtained + from the following: + + >>> (x + z*(x + x*y)).coeff(x) + 1 + + If such factoring is desired, factor_terms can be used first: + + >>> from sympy import factor_terms + >>> factor_terms(x + z*(x + x*y)).coeff(x) + z*(y + 1) + 1 + + >>> n, m, o = symbols('n m o', commutative=False) + >>> n.coeff(n) + 1 + >>> (3*n).coeff(n) + 3 + >>> (n*m + m*n*m).coeff(n) # = (1 + m)*n*m + 1 + m + >>> (n*m + m*n*m).coeff(n, right=True) # = (1 + m)*n*m + m + + If there is more than one possible coefficient 0 is returned: + + >>> (n*m + m*n).coeff(n) + 0 + + If there is only one possible coefficient, it is returned: + + >>> (n*m + x*m*n).coeff(m*n) + x + >>> (n*m + x*m*n).coeff(m*n, right=1) + 1 + + See Also + ======== + + as_coefficient: separate the expression into a coefficient and factor + as_coeff_Add: separate the additive constant from an expression + as_coeff_Mul: separate the multiplicative constant from an expression + as_independent: separate x-dependent terms/factors from others + sympy.polys.polytools.Poly.coeff_monomial: efficiently find the single coefficient of a monomial in Poly + sympy.polys.polytools.Poly.nth: like coeff_monomial but powers of monomial terms are used + """ + x = sympify(x) + if not isinstance(x, Basic): + return S.Zero + + n = as_int(n) + + if not x: + return S.Zero + + if x == self: + if n == 1: + return S.One + return S.Zero + + co2: list[Expr] + + if x is S.One: + co2 = [a for a in Add.make_args(self) if a.as_coeff_Mul()[0] is S.One] + if not co2: + return S.Zero + return Add(*co2) + + if n == 0: + if x.is_Add and self.is_Add: + c = self.coeff(x, right=right) + if not c: + return S.Zero + if not right: + return self - Add(*[a*x for a in Add.make_args(c)]) + return self - Add(*[x*a for a in Add.make_args(c)]) + return self.as_independent(x, as_Add=True)[0] + + # continue with the full method, looking for this power of x: + x = x**n + + def incommon(l1, l2): + if not l1 or not l2: + return [] + n = min(len(l1), len(l2)) + for i in range(n): + if l1[i] != l2[i]: + return l1[:i] + return l1[:] + + def find(l, sub, first=True): + """ Find where list sub appears in list l. When ``first`` is True + the first occurrence from the left is returned, else the last + occurrence is returned. Return None if sub is not in l. + + Examples + ======== + + >> l = range(5)*2 + >> find(l, [2, 3]) + 2 + >> find(l, [2, 3], first=0) + 7 + >> find(l, [2, 4]) + None + + """ + if not sub or not l or len(sub) > len(l): + return None + n = len(sub) + if not first: + l.reverse() + sub.reverse() + for i in range(len(l) - n + 1): + if all(l[i + j] == sub[j] for j in range(n)): + break + else: + i = None + if not first: + l.reverse() + sub.reverse() + if i is not None and not first: + i = len(l) - (i + n) + return i + + co2 = [] + co: list[tuple[set[Expr], list[Expr]]] = [] + args = Add.make_args(self) + self_c = self.is_commutative + x_c = x.is_commutative + if self_c and not x_c: + return S.Zero + if _first and self.is_Add and not self_c and not x_c: + # get the part that depends on x exactly + xargs = Mul.make_args(x) + d = Add(*[i for i in Add.make_args(self.as_independent(x)[1]) + if all(xi in Mul.make_args(i) for xi in xargs)]) + rv = d.coeff(x, right=right, _first=False) + if not rv.is_Add or not right: + return rv + c_part, nc_part = zip(*[i.args_cnc() for i in rv.args]) + if has_variety(c_part): + return rv + return Add(*[Mul._from_args(i) for i in nc_part]) + + one_c = self_c or x_c + xargs, nx = x.args_cnc(cset=True, warn=bool(not x_c)) + # find the parts that pass the commutative terms + for a in args: + margs, nc = a.args_cnc(cset=True, warn=bool(not self_c)) + if nc is None: + nc = [] + if len(xargs) > len(margs): + continue + resid = margs.difference(xargs) + if len(resid) + len(xargs) == len(margs): + if one_c: + co2.append(Mul(*(list(resid) + nc))) + else: + co.append((resid, nc)) + if one_c: + if co2 == []: + return S.Zero + elif co2: + return Add(*co2) + else: # both nc + # now check the non-comm parts + if not co: + return S.Zero + if all(n == co[0][1] for r, n in co): + ii = find(co[0][1], nx, right) + if ii is not None: + if not right: + return Mul(Add(*[Mul(*r) for r, c in co]), Mul(*co[0][1][:ii])) + else: + return Mul(*co[0][1][ii + len(nx):]) + beg = reduce(incommon, (n[1] for n in co)) + if beg: + ii = find(beg, nx, right) + if ii is not None: + if not right: + gcdc = co[0][0] + for i in range(1, len(co)): + gcdc = gcdc.intersection(co[i][0]) + if not gcdc: + break + return Mul(*(list(gcdc) + beg[:ii])) + else: + m = ii + len(nx) + return Add(*[Mul(*(list(r) + n[m:])) for r, n in co]) + end = list(reversed( + reduce(incommon, (list(reversed(n[1])) for n in co)))) + if end: + ii = find(end, nx, right) + if ii is not None: + if not right: + return Add(*[Mul(*(list(r) + n[:-len(end) + ii])) for r, n in co]) + else: + return Mul(*end[ii + len(nx):]) + # look for single match + hit = None + for i, (r, n) in enumerate(co): + ii = find(n, nx, right) + if ii is not None: + if not hit: + hit = ii, r, n + else: + break + else: + if hit: + ii, r, n = hit + if not right: + return Mul(*(list(r) + n[:ii])) + else: + return Mul(*n[ii + len(nx):]) + + return S.Zero + + def as_expr(self, *gens): + """ + Convert a polynomial to a SymPy expression. + + Examples + ======== + + >>> from sympy import sin + >>> from sympy.abc import x, y + + >>> f = (x**2 + x*y).as_poly(x, y) + >>> f.as_expr() + x**2 + x*y + + >>> sin(x).as_expr() + sin(x) + + """ + return self + + def as_coefficient(self, expr: Expr) -> Expr | None: + """ + Extracts symbolic coefficient at the given expression. In + other words, this functions separates 'self' into the product + of 'expr' and 'expr'-free coefficient. If such separation + is not possible it will return None. + + Examples + ======== + + >>> from sympy import E, pi, sin, I, Poly + >>> from sympy.abc import x + + >>> E.as_coefficient(E) + 1 + >>> (2*E).as_coefficient(E) + 2 + >>> (2*sin(E)*E).as_coefficient(E) + + Two terms have E in them so a sum is returned. (If one were + desiring the coefficient of the term exactly matching E then + the constant from the returned expression could be selected. + Or, for greater precision, a method of Poly can be used to + indicate the desired term from which the coefficient is + desired.) + + >>> (2*E + x*E).as_coefficient(E) + x + 2 + >>> _.args[0] # just want the exact match + 2 + >>> p = Poly(2*E + x*E); p + Poly(x*E + 2*E, x, E, domain='ZZ') + >>> p.coeff_monomial(E) + 2 + >>> p.nth(0, 1) + 2 + + Since the following cannot be written as a product containing + E as a factor, None is returned. (If the coefficient ``2*x`` is + desired then the ``coeff`` method should be used.) + + >>> (2*E*x + x).as_coefficient(E) + >>> (2*E*x + x).coeff(E) + 2*x + + >>> (E*(x + 1) + x).as_coefficient(E) + + >>> (2*pi*I).as_coefficient(pi*I) + 2 + >>> (2*I).as_coefficient(pi*I) + + See Also + ======== + + coeff: return sum of terms have a given factor + as_coeff_Add: separate the additive constant from an expression + as_coeff_Mul: separate the multiplicative constant from an expression + as_independent: separate x-dependent terms/factors from others + sympy.polys.polytools.Poly.coeff_monomial: efficiently find the single coefficient of a monomial in Poly + sympy.polys.polytools.Poly.nth: like coeff_monomial but powers of monomial terms are used + + + """ + + r = self.extract_multiplicatively(expr) + if r and not r.has(expr): + return r + else: + return None + + def as_independent(self, *deps, **hint) -> tuple[Expr, Expr]: + """ + A mostly naive separation of a Mul or Add into arguments that are not + are dependent on deps. To obtain as complete a separation of variables + as possible, use a separation method first, e.g.: + + * separatevars() to change Mul, Add and Pow (including exp) into Mul + * .expand(mul=True) to change Add or Mul into Add + * .expand(log=True) to change log expr into an Add + + The only non-naive thing that is done here is to respect noncommutative + ordering of variables and to always return (0, 0) for `self` of zero + regardless of hints. + + For nonzero `self`, the returned tuple (i, d) has the + following interpretation: + + * i will has no variable that appears in deps + * d will either have terms that contain variables that are in deps, or + be equal to 0 (when self is an Add) or 1 (when self is a Mul) + * if self is an Add then self = i + d + * if self is a Mul then self = i*d + * otherwise (self, S.One) or (S.One, self) is returned. + + To force the expression to be treated as an Add, use the hint as_Add=True + + Examples + ======== + + -- self is an Add + + >>> from sympy import sin, cos, exp + >>> from sympy.abc import x, y, z + + >>> (x + x*y).as_independent(x) + (0, x*y + x) + >>> (x + x*y).as_independent(y) + (x, x*y) + >>> (2*x*sin(x) + y + x + z).as_independent(x) + (y + z, 2*x*sin(x) + x) + >>> (2*x*sin(x) + y + x + z).as_independent(x, y) + (z, 2*x*sin(x) + x + y) + + -- self is a Mul + + >>> (x*sin(x)*cos(y)).as_independent(x) + (cos(y), x*sin(x)) + + non-commutative terms cannot always be separated out when self is a Mul + + >>> from sympy import symbols + >>> n1, n2, n3 = symbols('n1 n2 n3', commutative=False) + >>> (n1 + n1*n2).as_independent(n2) + (n1, n1*n2) + >>> (n2*n1 + n1*n2).as_independent(n2) + (0, n1*n2 + n2*n1) + >>> (n1*n2*n3).as_independent(n1) + (1, n1*n2*n3) + >>> (n1*n2*n3).as_independent(n2) + (n1, n2*n3) + >>> ((x-n1)*(x-y)).as_independent(x) + (1, (x - y)*(x - n1)) + + -- self is anything else: + + >>> (sin(x)).as_independent(x) + (1, sin(x)) + >>> (sin(x)).as_independent(y) + (sin(x), 1) + >>> exp(x+y).as_independent(x) + (1, exp(x + y)) + + -- force self to be treated as an Add: + + >>> (3*x).as_independent(x, as_Add=True) + (0, 3*x) + + -- force self to be treated as a Mul: + + >>> (3+x).as_independent(x, as_Add=False) + (1, x + 3) + >>> (-3+x).as_independent(x, as_Add=False) + (1, x - 3) + + Note how the below differs from the above in making the + constant on the dep term positive. + + >>> (y*(-3+x)).as_independent(x) + (y, x - 3) + + -- use .as_independent() for true independence testing instead + of .has(). The former considers only symbols in the free + symbols while the latter considers all symbols + + >>> from sympy import Integral + >>> I = Integral(x, (x, 1, 2)) + >>> I.has(x) + True + >>> x in I.free_symbols + False + >>> I.as_independent(x) == (I, 1) + True + >>> (I + x).as_independent(x) == (I, x) + True + + Note: when trying to get independent terms, a separation method + might need to be used first. In this case, it is important to keep + track of what you send to this routine so you know how to interpret + the returned values + + >>> from sympy import separatevars, log + >>> separatevars(exp(x+y)).as_independent(x) + (exp(y), exp(x)) + >>> (x + x*y).as_independent(y) + (x, x*y) + >>> separatevars(x + x*y).as_independent(y) + (x, y + 1) + >>> (x*(1 + y)).as_independent(y) + (x, y + 1) + >>> (x*(1 + y)).expand(mul=True).as_independent(y) + (x, x*y) + >>> a, b=symbols('a b', positive=True) + >>> (log(a*b).expand(log=True)).as_independent(b) + (log(a), log(b)) + + See Also + ======== + + separatevars + expand_log + sympy.core.add.Add.as_two_terms + sympy.core.mul.Mul.as_two_terms + as_coeff_mul + """ + from .symbol import Symbol + from .add import _unevaluated_Add + from .mul import _unevaluated_Mul + + if self is S.Zero: + return (self, self) + + func = self.func + want: type[Add] | type[Mul] + if hint.get('as_Add', isinstance(self, Add) ): + want = Add + else: + want = Mul + + # sift out deps into symbolic and other and ignore + # all symbols but those that are in the free symbols + sym = set() + other = [] + for d in deps: + if isinstance(d, Symbol): # Symbol.is_Symbol is True + sym.add(d) + else: + other.append(d) + + def has(e): + """return the standard has() if there are no literal symbols, else + check to see that symbol-deps are in the free symbols.""" + has_other = e.has(*other) + if not sym: + return has_other + return has_other or e.has(*(e.free_symbols & sym)) + + if (want is not func or + func is not Add and func is not Mul): + if has(self): + return (want.identity, self) + else: + return (self, want.identity) + else: + if func is Add: + args = list(self.args) + else: + args, nc = self.args_cnc() + + d = sift(args, has) + depend = d[True] + indep = d[False] + if func is Add: # all terms were treated as commutative + return (Add(*indep), _unevaluated_Add(*depend)) + else: # handle noncommutative by stopping at first dependent term + for i, n in enumerate(nc): + if has(n): + depend.extend(nc[i:]) + break + indep.append(n) + return Mul(*indep), _unevaluated_Mul(*depend) + + def as_real_imag(self, deep=True, **hints) -> tuple[Expr, Expr]: + """Performs complex expansion on 'self' and returns a tuple + containing collected both real and imaginary parts. This + method cannot be confused with re() and im() functions, + which does not perform complex expansion at evaluation. + + However it is possible to expand both re() and im() + functions and get exactly the same results as with + a single call to this function. + + >>> from sympy import symbols, I + + >>> x, y = symbols('x,y', real=True) + + >>> (x + y*I).as_real_imag() + (x, y) + + >>> from sympy.abc import z, w + + >>> (z + w*I).as_real_imag() + (re(z) - im(w), re(w) + im(z)) + + """ + if hints.get('ignore') == self: + return None # type: ignore + else: + from sympy.functions.elementary.complexes import im, re + return (re(self), im(self)) + + def as_powers_dict(self): + """Return self as a dictionary of factors with each factor being + treated as a power. The keys are the bases of the factors and the + values, the corresponding exponents. The resulting dictionary should + be used with caution if the expression is a Mul and contains non- + commutative factors since the order that they appeared will be lost in + the dictionary. + + See Also + ======== + as_ordered_factors: An alternative for noncommutative applications, + returning an ordered list of factors. + args_cnc: Similar to as_ordered_factors, but guarantees separation + of commutative and noncommutative factors. + """ + d = defaultdict(int) + d.update([self.as_base_exp()]) + return d + + def as_coefficients_dict(self, *syms): + """Return a dictionary mapping terms to their Rational coefficient. + Since the dictionary is a defaultdict, inquiries about terms which + were not present will return a coefficient of 0. + + If symbols ``syms`` are provided, any multiplicative terms + independent of them will be considered a coefficient and a + regular dictionary of syms-dependent generators as keys and + their corresponding coefficients as values will be returned. + + Examples + ======== + + >>> from sympy.abc import a, x, y + >>> (3*x + a*x + 4).as_coefficients_dict() + {1: 4, x: 3, a*x: 1} + >>> _[a] + 0 + >>> (3*a*x).as_coefficients_dict() + {a*x: 3} + >>> (3*a*x).as_coefficients_dict(x) + {x: 3*a} + >>> (3*a*x).as_coefficients_dict(y) + {1: 3*a*x} + + """ + d = defaultdict(list) + if not syms: + for ai in Add.make_args(self): + c, m = ai.as_coeff_Mul() + d[m].append(c) + for k, v in d.items(): + if len(v) == 1: + d[k] = v[0] + else: + d[k] = Add(*v) + else: + ind, dep = self.as_independent(*syms, as_Add=True) + for i in Add.make_args(dep): + if i.is_Mul: + c, x = i.as_coeff_mul(*syms) + if c is S.One: + d[i].append(c) + else: + d[i._new_rawargs(*x)].append(c) + elif i: + d[i].append(S.One) + d = {k: Add(*d[k]) for k in d} + if ind is not S.Zero: + d.update({S.One: ind}) + di = defaultdict(int) + di.update(d) + return di + + def as_base_exp(self) -> tuple[Expr, Expr]: + # a -> b ** e + return self, S.One + + def as_coeff_mul(self, *deps, **kwargs) -> tuple[Expr, tuple[Expr, ...]]: + """Return the tuple (c, args) where self is written as a Mul, ``m``. + + c should be a Rational multiplied by any factors of the Mul that are + independent of deps. + + args should be a tuple of all other factors of m; args is empty + if self is a Number or if self is independent of deps (when given). + + This should be used when you do not know if self is a Mul or not but + you want to treat self as a Mul or if you want to process the + individual arguments of the tail of self as a Mul. + + - if you know self is a Mul and want only the head, use self.args[0]; + - if you do not want to process the arguments of the tail but need the + tail then use self.as_two_terms() which gives the head and tail; + - if you want to split self into an independent and dependent parts + use ``self.as_independent(*deps)`` + + >>> from sympy import S + >>> from sympy.abc import x, y + >>> (S(3)).as_coeff_mul() + (3, ()) + >>> (3*x*y).as_coeff_mul() + (3, (x, y)) + >>> (3*x*y).as_coeff_mul(x) + (3*y, (x,)) + >>> (3*y).as_coeff_mul(x) + (3*y, ()) + """ + if deps: + if not self.has(*deps): + return self, () + return S.One, (self,) + + def as_coeff_add(self, *deps) -> tuple[Expr, tuple[Expr, ...]]: + """Return the tuple (c, args) where self is written as an Add, ``a``. + + c should be a Rational added to any terms of the Add that are + independent of deps. + + args should be a tuple of all other terms of ``a``; args is empty + if self is a Number or if self is independent of deps (when given). + + This should be used when you do not know if self is an Add or not but + you want to treat self as an Add or if you want to process the + individual arguments of the tail of self as an Add. + + - if you know self is an Add and want only the head, use self.args[0]; + - if you do not want to process the arguments of the tail but need the + tail then use self.as_two_terms() which gives the head and tail. + - if you want to split self into an independent and dependent parts + use ``self.as_independent(*deps)`` + + >>> from sympy import S + >>> from sympy.abc import x, y + >>> (S(3)).as_coeff_add() + (3, ()) + >>> (3 + x).as_coeff_add() + (3, (x,)) + >>> (3 + x + y).as_coeff_add(x) + (y + 3, (x,)) + >>> (3 + y).as_coeff_add(x) + (y + 3, ()) + + """ + if deps: + if not self.has_free(*deps): + return self, () + return S.Zero, (self,) + + def primitive(self) -> tuple[Number, Expr]: + """Return the positive Rational that can be extracted non-recursively + from every term of self (i.e., self is treated like an Add). This is + like the as_coeff_Mul() method but primitive always extracts a positive + Rational (never a negative or a Float). + + Examples + ======== + + >>> from sympy.abc import x + >>> (3*(x + 1)**2).primitive() + (3, (x + 1)**2) + >>> a = (6*x + 2); a.primitive() + (2, 3*x + 1) + >>> b = (x/2 + 3); b.primitive() + (1/2, x + 6) + >>> (a*b).primitive() == (1, a*b) + True + """ + if not self: + return S.One, S.Zero + c, r = self.as_coeff_Mul(rational=True) + if c.is_negative: + c, r = -c, -r + return c, r + + def as_content_primitive(self, radical=False, clear=True): + """This method should recursively remove a Rational from all arguments + and return that (content) and the new self (primitive). The content + should always be positive and ``Mul(*foo.as_content_primitive()) == foo``. + The primitive need not be in canonical form and should try to preserve + the underlying structure if possible (i.e. expand_mul should not be + applied to self). + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.abc import x, y, z + + >>> eq = 2 + 2*x + 2*y*(3 + 3*y) + + The as_content_primitive function is recursive and retains structure: + + >>> eq.as_content_primitive() + (2, x + 3*y*(y + 1) + 1) + + Integer powers will have Rationals extracted from the base: + + >>> ((2 + 6*x)**2).as_content_primitive() + (4, (3*x + 1)**2) + >>> ((2 + 6*x)**(2*y)).as_content_primitive() + (1, (2*(3*x + 1))**(2*y)) + + Terms may end up joining once their as_content_primitives are added: + + >>> ((5*(x*(1 + y)) + 2*x*(3 + 3*y))).as_content_primitive() + (11, x*(y + 1)) + >>> ((3*(x*(1 + y)) + 2*x*(3 + 3*y))).as_content_primitive() + (9, x*(y + 1)) + >>> ((3*(z*(1 + y)) + 2.0*x*(3 + 3*y))).as_content_primitive() + (1, 6.0*x*(y + 1) + 3*z*(y + 1)) + >>> ((5*(x*(1 + y)) + 2*x*(3 + 3*y))**2).as_content_primitive() + (121, x**2*(y + 1)**2) + >>> ((x*(1 + y) + 0.4*x*(3 + 3*y))**2).as_content_primitive() + (1, 4.84*x**2*(y + 1)**2) + + Radical content can also be factored out of the primitive: + + >>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True) + (2, sqrt(2)*(1 + 2*sqrt(5))) + + If clear=False (default is True) then content will not be removed + from an Add if it can be distributed to leave one or more + terms with integer coefficients. + + >>> (x/2 + y).as_content_primitive() + (1/2, x + 2*y) + >>> (x/2 + y).as_content_primitive(clear=False) + (1, x/2 + y) + """ + return S.One, self + + def as_numer_denom(self) -> tuple[Expr, Expr]: + """Return the numerator and the denominator of an expression. + + expression -> a/b -> a, b + + This is just a stub that should be defined by + an object's class methods to get anything else. + + See Also + ======== + + normal: return ``a/b`` instead of ``(a, b)`` + + """ + return self, S.One + + def normal(self): + """Return the expression as a fraction. + + expression -> a/b + + See Also + ======== + + as_numer_denom: return ``(a, b)`` instead of ``a/b`` + + """ + from .mul import _unevaluated_Mul + n, d = self.as_numer_denom() + if d is S.One: + return n + if d.is_Number: + return _unevaluated_Mul(n, 1/d) + else: + return n/d + + def extract_multiplicatively(self, c: Expr) -> Expr | None: + """Return None if it's not possible to make self in the form + c * something in a nice way, i.e. preserving the properties + of arguments of self. + + Examples + ======== + + >>> from sympy import symbols, Rational + + >>> x, y = symbols('x,y', real=True) + + >>> ((x*y)**3).extract_multiplicatively(x**2 * y) + x*y**2 + + >>> ((x*y)**3).extract_multiplicatively(x**4 * y) + + >>> (2*x).extract_multiplicatively(2) + x + + >>> (2*x).extract_multiplicatively(3) + + >>> (Rational(1, 2)*x).extract_multiplicatively(3) + x/6 + + """ + from sympy.functions.elementary.exponential import exp + from .add import _unevaluated_Add + c = sympify(c) + if self is S.NaN: + return None + if c is S.One: + return self + elif c == self: + return S.One + + if c.is_Add: + cc, pc = c.primitive() + if cc is not S.One: + c = Mul(cc, pc, evaluate=False) + + if c.is_Mul: + a, b = c.as_two_terms() # type: ignore + x = self.extract_multiplicatively(a) + if x is not None: + return x.extract_multiplicatively(b) + else: + return x + + quotient = self / c + if self.is_Number: + if self is S.Infinity: + if c.is_positive: + return S.Infinity + elif self is S.NegativeInfinity: + if c.is_negative: + return S.Infinity + elif c.is_positive: + return S.NegativeInfinity + elif self is S.ComplexInfinity: + if not c.is_zero: + return S.ComplexInfinity + elif self.is_Integer: + if not quotient.is_Integer: + return None + elif self.is_positive and quotient.is_negative: + return None + else: + return quotient + elif self.is_Rational: + if not quotient.is_Rational: + return None + elif self.is_positive and quotient.is_negative: + return None + else: + return quotient + elif self.is_Float: + if not quotient.is_Float: + return None + elif self.is_positive and quotient.is_negative: + return None + else: + return quotient + elif self.is_NumberSymbol or self.is_Symbol or self is S.ImaginaryUnit: + if quotient.is_Mul and len(quotient.args) == 2: + if quotient.args[0].is_Integer and quotient.args[0].is_positive and quotient.args[1] == self: + return quotient + elif quotient.is_Integer and c.is_Number: + return quotient + elif self.is_Add: + cs, ps = self.primitive() + # assert cs >= 1 + if c.is_Number and c is not S.NegativeOne: + # assert c != 1 (handled at top) + if cs is not S.One: + if c.is_negative: + xc = cs.extract_multiplicatively(-c) + if xc is not None: + xc = -xc + else: + xc = cs.extract_multiplicatively(c) + if xc is not None: + return xc*ps # rely on 2-arg Mul to restore Add + return None # |c| != 1 can only be extracted from cs + if c == ps: + return cs + # check args of ps + newargs = [] + arg: Expr + for arg in ps.args: # type: ignore + newarg = arg.extract_multiplicatively(c) + if newarg is None: + return None # all or nothing + newargs.append(newarg) + if cs is not S.One: + args = [cs*t for t in newargs] + # args may be in different order + return _unevaluated_Add(*args) + else: + return Add._from_args(newargs) + elif self.is_Mul: + args: list[Expr] = list(self.args) # type: ignore + for i, arg in enumerate(args): + newarg = arg.extract_multiplicatively(c) + if newarg is not None: + args[i] = newarg + return Mul(*args) + elif self.is_Pow or isinstance(self, exp): + sb, se = self.as_base_exp() + cb, ce = c.as_base_exp() + if cb == sb: + new_exp = se.extract_additively(ce) + if new_exp is not None: + return Pow(sb, new_exp) + elif c == sb: + new_exp = se.extract_additively(1) + if new_exp is not None: + return Pow(sb, new_exp) + + return None + + def extract_additively(self, c): + """Return self - c if it's possible to subtract c from self and + make all matching coefficients move towards zero, else return None. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> e = 2*x + 3 + >>> e.extract_additively(x + 1) + x + 2 + >>> e.extract_additively(3*x) + >>> e.extract_additively(4) + >>> (y*(x + 1)).extract_additively(x + 1) + >>> ((x + 1)*(x + 2*y + 1) + 3).extract_additively(x + 1) + (x + 1)*(x + 2*y) + 3 + + See Also + ======== + extract_multiplicatively + coeff + as_coefficient + + """ + + c = sympify(c) + if self is S.NaN: + return None + if c.is_zero: + return self + elif c == self: + return S.Zero + elif self == S.Zero: + return None + + if self.is_Number: + if not c.is_Number: + return None + co = self + diff = co - c + # XXX should we match types? i.e should 3 - .1 succeed? + if (co > 0 and diff >= 0 and diff < co or + co < 0 and diff <= 0 and diff > co): + return diff + return None + + if c.is_Number: + co, t = self.as_coeff_Add() + xa = co.extract_additively(c) + if xa is None: + return None + return xa + t + + # handle the args[0].is_Number case separately + # since we will have trouble looking for the coeff of + # a number. + if c.is_Add and c.args[0].is_Number: + # whole term as a term factor + co = self.coeff(c) + xa0 = (co.extract_additively(1) or 0)*c + if xa0: + diff = self - co*c + return (xa0 + (diff.extract_additively(c) or diff)) or None + # term-wise + h, t = c.as_coeff_Add() + sh, st = self.as_coeff_Add() + xa = sh.extract_additively(h) + if xa is None: + return None + xa2 = st.extract_additively(t) + if xa2 is None: + return None + return xa + xa2 + + # whole term as a term factor + co, diff = _corem(self, c) + xa0 = (co.extract_additively(1) or 0)*c + if xa0: + return (xa0 + (diff.extract_additively(c) or diff)) or None + # term-wise + coeffs = [] + for a in Add.make_args(c): + ac, at = a.as_coeff_Mul() + co = self.coeff(at) + if not co: + return None + coc, cot = co.as_coeff_Add() + xa = coc.extract_additively(ac) + if xa is None: + return None + self -= co*at + coeffs.append((cot + xa)*at) + coeffs.append(self) + return Add(*coeffs) + + @property + def expr_free_symbols(self): + """ + Like ``free_symbols``, but returns the free symbols only if + they are contained in an expression node. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> (x + y).expr_free_symbols # doctest: +SKIP + {x, y} + + If the expression is contained in a non-expression object, do not return + the free symbols. Compare: + + >>> from sympy import Tuple + >>> t = Tuple(x + y) + >>> t.expr_free_symbols # doctest: +SKIP + set() + >>> t.free_symbols + {x, y} + """ + sympy_deprecation_warning(""" + The expr_free_symbols property is deprecated. Use free_symbols to get + the free symbols of an expression. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-expr-free-symbols") + return {j for i in self.args for j in i.expr_free_symbols} + + def could_extract_minus_sign(self) -> bool: + """Return True if self has -1 as a leading factor or has + more literal negative signs than positive signs in a sum, + otherwise False. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> e = x - y + >>> {i.could_extract_minus_sign() for i in (e, -e)} + {False, True} + + Though the ``y - x`` is considered like ``-(x - y)``, since it + is in a product without a leading factor of -1, the result is + false below: + + >>> (x*(y - x)).could_extract_minus_sign() + False + + To put something in canonical form wrt to sign, use `signsimp`: + + >>> from sympy import signsimp + >>> signsimp(x*(y - x)) + -x*(x - y) + >>> _.could_extract_minus_sign() + True + """ + return False + + def extract_branch_factor(self, allow_half=False): + """ + Try to write self as ``exp_polar(2*pi*I*n)*z`` in a nice way. + Return (z, n). + + >>> from sympy import exp_polar, I, pi + >>> from sympy.abc import x, y + >>> exp_polar(I*pi).extract_branch_factor() + (exp_polar(I*pi), 0) + >>> exp_polar(2*I*pi).extract_branch_factor() + (1, 1) + >>> exp_polar(-pi*I).extract_branch_factor() + (exp_polar(I*pi), -1) + >>> exp_polar(3*pi*I + x).extract_branch_factor() + (exp_polar(x + I*pi), 1) + >>> (y*exp_polar(-5*pi*I)*exp_polar(3*pi*I + 2*pi*x)).extract_branch_factor() + (y*exp_polar(2*pi*x), -1) + >>> exp_polar(-I*pi/2).extract_branch_factor() + (exp_polar(-I*pi/2), 0) + + If allow_half is True, also extract exp_polar(I*pi): + + >>> exp_polar(I*pi).extract_branch_factor(allow_half=True) + (1, 1/2) + >>> exp_polar(2*I*pi).extract_branch_factor(allow_half=True) + (1, 1) + >>> exp_polar(3*I*pi).extract_branch_factor(allow_half=True) + (1, 3/2) + >>> exp_polar(-I*pi).extract_branch_factor(allow_half=True) + (1, -1/2) + """ + from sympy.functions.elementary.exponential import exp_polar + from sympy.functions.elementary.integers import ceiling + + n = S.Zero + res = S.One + args = Mul.make_args(self) + exps = [] + for arg in args: + if isinstance(arg, exp_polar): + exps += [arg.exp] + else: + res *= arg + piimult = S.Zero + extras = [] + + ipi = S.Pi*S.ImaginaryUnit + while exps: + exp = exps.pop() + if exp.is_Add: + exps += exp.args + continue + if exp.is_Mul: + coeff = exp.as_coefficient(ipi) + if coeff is not None: + piimult += coeff + continue + extras += [exp] + if piimult.is_number: + coeff = piimult + tail = () + else: + coeff, tail = piimult.as_coeff_add(*piimult.free_symbols) + # round down to nearest multiple of 2 + branchfact = ceiling(coeff/2 - S.Half)*2 + n += branchfact/2 + c = coeff - branchfact + if allow_half: + nc = c.extract_additively(1) + if nc is not None: + n += S.Half + c = nc + newexp = ipi*Add(*((c, ) + tail)) + Add(*extras) + if newexp != 0: + res *= exp_polar(newexp) + return res, n + + def is_polynomial(self, *syms): + r""" + Return True if self is a polynomial in syms and False otherwise. + + This checks if self is an exact polynomial in syms. This function + returns False for expressions that are "polynomials" with symbolic + exponents. Thus, you should be able to apply polynomial algorithms to + expressions for which this returns True, and Poly(expr, \*syms) should + work if and only if expr.is_polynomial(\*syms) returns True. The + polynomial does not have to be in expanded form. If no symbols are + given, all free symbols in the expression will be used. + + This is not part of the assumptions system. You cannot do + Symbol('z', polynomial=True). + + Examples + ======== + + >>> from sympy import Symbol, Function + >>> x = Symbol('x') + >>> ((x**2 + 1)**4).is_polynomial(x) + True + >>> ((x**2 + 1)**4).is_polynomial() + True + >>> (2**x + 1).is_polynomial(x) + False + >>> (2**x + 1).is_polynomial(2**x) + True + >>> f = Function('f') + >>> (f(x) + 1).is_polynomial(x) + False + >>> (f(x) + 1).is_polynomial(f(x)) + True + >>> (1/f(x) + 1).is_polynomial(f(x)) + False + + >>> n = Symbol('n', nonnegative=True, integer=True) + >>> (x**n + 1).is_polynomial(x) + False + + This function does not attempt any nontrivial simplifications that may + result in an expression that does not appear to be a polynomial to + become one. + + >>> from sympy import sqrt, factor, cancel + >>> y = Symbol('y', positive=True) + >>> a = sqrt(y**2 + 2*y + 1) + >>> a.is_polynomial(y) + False + >>> factor(a) + y + 1 + >>> factor(a).is_polynomial(y) + True + + >>> b = (y**2 + 2*y + 1)/(y + 1) + >>> b.is_polynomial(y) + False + >>> cancel(b) + y + 1 + >>> cancel(b).is_polynomial(y) + True + + See also .is_rational_function() + + """ + if syms: + syms = set(map(sympify, syms)) + else: + syms = self.free_symbols + if not syms: + return True + + return self._eval_is_polynomial(syms) + + def _eval_is_polynomial(self, syms) -> bool | None: + if self in syms: + return True + if not self.has_free(*syms): + # constant polynomial + return True + # subclasses should return True or False + return None + + def is_rational_function(self, *syms): + """ + Test whether function is a ratio of two polynomials in the given + symbols, syms. When syms is not given, all free symbols will be used. + The rational function does not have to be in expanded or in any kind of + canonical form. + + This function returns False for expressions that are "rational + functions" with symbolic exponents. Thus, you should be able to call + .as_numer_denom() and apply polynomial algorithms to the result for + expressions for which this returns True. + + This is not part of the assumptions system. You cannot do + Symbol('z', rational_function=True). + + Examples + ======== + + >>> from sympy import Symbol, sin + >>> from sympy.abc import x, y + + >>> (x/y).is_rational_function() + True + + >>> (x**2).is_rational_function() + True + + >>> (x/sin(y)).is_rational_function(y) + False + + >>> n = Symbol('n', integer=True) + >>> (x**n + 1).is_rational_function(x) + False + + This function does not attempt any nontrivial simplifications that may + result in an expression that does not appear to be a rational function + to become one. + + >>> from sympy import sqrt, factor + >>> y = Symbol('y', positive=True) + >>> a = sqrt(y**2 + 2*y + 1)/y + >>> a.is_rational_function(y) + False + >>> factor(a) + (y + 1)/y + >>> factor(a).is_rational_function(y) + True + + See also is_algebraic_expr(). + + """ + if syms: + syms = set(map(sympify, syms)) + else: + syms = self.free_symbols + if not syms: + return self not in _illegal + + return self._eval_is_rational_function(syms) + + def _eval_is_rational_function(self, syms) -> bool | None: + if self in syms: + return True + if not self.has_xfree(syms): + return True + # subclasses should return True or False + return None + + def is_meromorphic(self, x, a): + """ + This tests whether an expression is meromorphic as + a function of the given symbol ``x`` at the point ``a``. + + This method is intended as a quick test that will return + None if no decision can be made without simplification or + more detailed analysis. + + Examples + ======== + + >>> from sympy import zoo, log, sin, sqrt + >>> from sympy.abc import x + + >>> f = 1/x**2 + 1 - 2*x**3 + >>> f.is_meromorphic(x, 0) + True + >>> f.is_meromorphic(x, 1) + True + >>> f.is_meromorphic(x, zoo) + True + + >>> g = x**log(3) + >>> g.is_meromorphic(x, 0) + False + >>> g.is_meromorphic(x, 1) + True + >>> g.is_meromorphic(x, zoo) + False + + >>> h = sin(1/x)*x**2 + >>> h.is_meromorphic(x, 0) + False + >>> h.is_meromorphic(x, 1) + True + >>> h.is_meromorphic(x, zoo) + True + + Multivalued functions are considered meromorphic when their + branches are meromorphic. Thus most functions are meromorphic + everywhere except at essential singularities and branch points. + In particular, they will be meromorphic also on branch cuts + except at their endpoints. + + >>> log(x).is_meromorphic(x, -1) + True + >>> log(x).is_meromorphic(x, 0) + False + >>> sqrt(x).is_meromorphic(x, -1) + True + >>> sqrt(x).is_meromorphic(x, 0) + False + + """ + if not x.is_symbol: + raise TypeError("{} should be of symbol type".format(x)) + a = sympify(a) + + return self._eval_is_meromorphic(x, a) + + def _eval_is_meromorphic(self, x, a) -> bool | None: + if self == x: + return True + if not self.has_free(x): + return True + # subclasses should return True or False + return None + + def is_algebraic_expr(self, *syms): + """ + This tests whether a given expression is algebraic or not, in the + given symbols, syms. When syms is not given, all free symbols + will be used. The rational function does not have to be in expanded + or in any kind of canonical form. + + This function returns False for expressions that are "algebraic + expressions" with symbolic exponents. This is a simple extension to the + is_rational_function, including rational exponentiation. + + Examples + ======== + + >>> from sympy import Symbol, sqrt + >>> x = Symbol('x', real=True) + >>> sqrt(1 + x).is_rational_function() + False + >>> sqrt(1 + x).is_algebraic_expr() + True + + This function does not attempt any nontrivial simplifications that may + result in an expression that does not appear to be an algebraic + expression to become one. + + >>> from sympy import exp, factor + >>> a = sqrt(exp(x)**2 + 2*exp(x) + 1)/(exp(x) + 1) + >>> a.is_algebraic_expr(x) + False + >>> factor(a).is_algebraic_expr() + True + + See Also + ======== + + is_rational_function + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Algebraic_expression + + """ + if syms: + syms = set(map(sympify, syms)) + else: + syms = self.free_symbols + if not syms: + return True + + return self._eval_is_algebraic_expr(syms) + + def _eval_is_algebraic_expr(self, syms) -> bool | None: + if self in syms: + return True + if not self.has_free(*syms): + return True + # subclasses should return True or False + return None + + ################################################################################### + ##################### SERIES, LEADING TERM, LIMIT, ORDER METHODS ################## + ################################################################################### + + def series(self, x=None, x0=0, n=6, dir="+", logx=None, cdir=0): + """ + Series expansion of "self" around ``x = x0`` yielding either terms of + the series one by one (the lazy series given when n=None), else + all the terms at once when n != None. + + Returns the series expansion of "self" around the point ``x = x0`` + with respect to ``x`` up to ``O((x - x0)**n, x, x0)`` (default n is 6). + + If ``x=None`` and ``self`` is univariate, the univariate symbol will + be supplied, otherwise an error will be raised. + + Parameters + ========== + + expr : Expression + The expression whose series is to be expanded. + + x : Symbol + It is the variable of the expression to be calculated. + + x0 : Value + The value around which ``x`` is calculated. Can be any value + from ``-oo`` to ``oo``. + + n : Value + The value used to represent the order in terms of ``x**n``, + up to which the series is to be expanded. + + dir : String, optional + The series-expansion can be bi-directional. If ``dir="+"``, + then (x->x0+). If ``dir="-", then (x->x0-). For infinite + ``x0`` (``oo`` or ``-oo``), the ``dir`` argument is determined + from the direction of the infinity (i.e., ``dir="-"`` for + ``oo``). + + logx : optional + It is used to replace any log(x) in the returned series with a + symbolic value rather than evaluating the actual value. + + cdir : optional + It stands for complex direction, and indicates the direction + from which the expansion needs to be evaluated. + + Examples + ======== + + >>> from sympy import cos, exp, tan + >>> from sympy.abc import x, y + >>> cos(x).series() + 1 - x**2/2 + x**4/24 + O(x**6) + >>> cos(x).series(n=4) + 1 - x**2/2 + O(x**4) + >>> cos(x).series(x, x0=1, n=2) + cos(1) - (x - 1)*sin(1) + O((x - 1)**2, (x, 1)) + >>> e = cos(x + exp(y)) + >>> e.series(y, n=2) + cos(x + 1) - y*sin(x + 1) + O(y**2) + >>> e.series(x, n=2) + cos(exp(y)) - x*sin(exp(y)) + O(x**2) + + If ``n=None`` then a generator of the series terms will be returned. + + >>> term=cos(x).series(n=None) + >>> [next(term) for i in range(2)] + [1, -x**2/2] + + For ``dir=+`` (default) the series is calculated from the right and + for ``dir=-`` the series from the left. For smooth functions this + flag will not alter the results. + + >>> abs(x).series(dir="+") + x + >>> abs(x).series(dir="-") + -x + >>> f = tan(x) + >>> f.series(x, 2, 6, "+") + tan(2) + (1 + tan(2)**2)*(x - 2) + (x - 2)**2*(tan(2)**3 + tan(2)) + + (x - 2)**3*(1/3 + 4*tan(2)**2/3 + tan(2)**4) + (x - 2)**4*(tan(2)**5 + + 5*tan(2)**3/3 + 2*tan(2)/3) + (x - 2)**5*(2/15 + 17*tan(2)**2/15 + + 2*tan(2)**4 + tan(2)**6) + O((x - 2)**6, (x, 2)) + + >>> f.series(x, 2, 3, "-") + tan(2) + (2 - x)*(-tan(2)**2 - 1) + (2 - x)**2*(tan(2)**3 + tan(2)) + + O((x - 2)**3, (x, 2)) + + For rational expressions this method may return original expression without the Order term. + >>> (1/x).series(x, n=8) + 1/x + + Returns + ======= + + Expr : Expression + Series expansion of the expression about x0 + + Raises + ====== + + TypeError + If "n" and "x0" are infinity objects + + PoleError + If "x0" is an infinity object + + """ + if x is None: + syms = self.free_symbols + if not syms: + return self + elif len(syms) > 1: + raise ValueError('x must be given for multivariate functions.') + x = syms.pop() + + from .symbol import Dummy, Symbol + if isinstance(x, Symbol): + dep = x in self.free_symbols + else: + d = Dummy() + dep = d in self.xreplace({x: d}).free_symbols + if not dep: + if n is None: + return (s for s in [self]) + else: + return self + + if len(dir) != 1 or dir not in '+-': + raise ValueError("Dir must be '+' or '-'") + + if n is not None: + n = int(n) + if n < 0: + raise ValueError("Number of terms should be nonnegative") + + x0 = sympify(x0) + cdir = sympify(cdir) + from sympy.functions.elementary.complexes import im, sign + + if not cdir.is_zero: + if cdir.is_real: + dir = '+' if cdir.is_positive else '-' + else: + dir = '+' if im(cdir).is_positive else '-' + else: + if x0 and x0.is_infinite: + cdir = sign(x0).simplify() + elif str(dir) == "+": + cdir = S.One + elif str(dir) == "-": + cdir = S.NegativeOne + elif cdir == S.Zero: + cdir = S.One + + cdir = cdir/abs(cdir) + + if x0 and x0.is_infinite: + from .function import PoleError + try: + s = self.subs(x, cdir/x).series(x, n=n, dir='+', cdir=1) + if n is None: + return (si.subs(x, cdir/x) for si in s) + return s.subs(x, cdir/x) + except PoleError: + s = self.subs(x, cdir*x).aseries(x, n=n) + return s.subs(x, cdir*x) + + # use rep to shift origin to x0 and change sign (if dir is negative) + # and undo the process with rep2 + if x0 or cdir != 1: + s = self.subs({x: x0 + cdir*x}).series(x, x0=0, n=n, dir='+', logx=logx, cdir=1) + if n is None: # lseries... + return (si.subs({x: x/cdir - x0/cdir}) for si in s) + return s.subs({x: x/cdir - x0/cdir}) + + # from here on it's x0=0 and dir='+' handling + + if x.is_positive is x.is_negative is None or x.is_Symbol is not True: + # replace x with an x that has a positive assumption + xpos = Dummy('x', positive=True) + rv = self.subs(x, xpos).series(xpos, x0, n, dir, logx=logx, cdir=cdir) + if n is None: + return (s.subs(xpos, x) for s in rv) + else: + return rv.subs(xpos, x) + + from sympy.series.order import Order + if n is not None: # nseries handling + s1 = self._eval_nseries(x, n=n, logx=logx, cdir=cdir) + o = s1.getO() or S.Zero + if o: + # make sure the requested order is returned + ngot = o.getn() + if ngot > n: + # leave o in its current form (e.g. with x*log(x)) so + # it eats terms properly, then replace it below + if n != 0: + s1 += o.subs(x, x**Rational(n, ngot)) + else: + s1 += Order(1, x) + elif ngot < n: + # increase the requested number of terms to get the desired + # number keep increasing (up to 9) until the received order + # is different than the original order and then predict how + # many additional terms are needed + from sympy.functions.elementary.integers import ceiling + for more in range(1, 9): + s1 = self._eval_nseries(x, n=n + more, logx=logx, cdir=cdir) + newn = s1.getn() + if newn != ngot: + ndo = n + ceiling((n - ngot)*more/(newn - ngot)) + s1 = self._eval_nseries(x, n=ndo, logx=logx, cdir=cdir) + while s1.getn() < n: + s1 = self._eval_nseries(x, n=ndo, logx=logx, cdir=cdir) + ndo += 1 + break + else: + raise ValueError('Could not calculate %s terms for %s' + % (str(n), self)) + s1 += Order(x**n, x) + o = s1.getO() + s1 = s1.removeO() + elif s1.has(Order): + # asymptotic expansion + return s1 + else: + o = Order(x**n, x) + s1done = s1.doit() + try: + if (s1done + o).removeO() == s1done: + o = S.Zero + except NotImplementedError: + return s1 + + try: + from sympy.simplify.radsimp import collect + return collect(s1, x) + o + except NotImplementedError: + return s1 + o + + else: # lseries handling + def yield_lseries(s): + """Return terms of lseries one at a time.""" + for si in s: + if not si.is_Add: + yield si + continue + # yield terms 1 at a time if possible + # by increasing order until all the + # terms have been returned + yielded = 0 + o = Order(si, x)*x + ndid = 0 + ndo = len(si.args) + while 1: + do = (si - yielded + o).removeO() + o *= x + if not do or do.is_Order: + continue + if do.is_Add: + ndid += len(do.args) + else: + ndid += 1 + yield do + if ndid == ndo: + break + yielded += do + + return yield_lseries(self.removeO()._eval_lseries(x, logx=logx, cdir=cdir)) + + def aseries(self, x=None, n=6, bound=0, hir=False): + """Asymptotic Series expansion of self. + This is equivalent to ``self.series(x, oo, n)``. + + Parameters + ========== + + self : Expression + The expression whose series is to be expanded. + + x : Symbol + It is the variable of the expression to be calculated. + + n : Value + The value used to represent the order in terms of ``x**n``, + up to which the series is to be expanded. + + hir : Boolean + Set this parameter to be True to produce hierarchical series. + It stops the recursion at an early level and may provide nicer + and more useful results. + + bound : Value, Integer + Use the ``bound`` parameter to give limit on rewriting + coefficients in its normalised form. + + Examples + ======== + + >>> from sympy import sin, exp + >>> from sympy.abc import x + + >>> e = sin(1/x + exp(-x)) - sin(1/x) + + >>> e.aseries(x) + (1/(24*x**4) - 1/(2*x**2) + 1 + O(x**(-6), (x, oo)))*exp(-x) + + >>> e.aseries(x, n=3, hir=True) + -exp(-2*x)*sin(1/x)/2 + exp(-x)*cos(1/x) + O(exp(-3*x), (x, oo)) + + >>> e = exp(exp(x)/(1 - 1/x)) + + >>> e.aseries(x) + exp(exp(x)/(1 - 1/x)) + + >>> e.aseries(x, bound=3) # doctest: +SKIP + exp(exp(x)/x**2)*exp(exp(x)/x)*exp(-exp(x) + exp(x)/(1 - 1/x) - exp(x)/x - exp(x)/x**2)*exp(exp(x)) + + For rational expressions this method may return original expression without the Order term. + >>> (1/x).aseries(x, n=8) + 1/x + + Returns + ======= + + Expr + Asymptotic series expansion of the expression. + + Notes + ===== + + This algorithm is directly induced from the limit computational algorithm provided by Gruntz. + It majorly uses the mrv and rewrite sub-routines. The overall idea of this algorithm is first + to look for the most rapidly varying subexpression w of a given expression f and then expands f + in a series in w. Then same thing is recursively done on the leading coefficient + till we get constant coefficients. + + If the most rapidly varying subexpression of a given expression f is f itself, + the algorithm tries to find a normalised representation of the mrv set and rewrites f + using this normalised representation. + + If the expansion contains an order term, it will be either ``O(x ** (-n))`` or ``O(w ** (-n))`` + where ``w`` belongs to the most rapidly varying expression of ``self``. + + References + ========== + + .. [1] Gruntz, Dominik. A new algorithm for computing asymptotic series. + In: Proc. 1993 Int. Symp. Symbolic and Algebraic Computation. 1993. + pp. 239-244. + .. [2] Gruntz thesis - p90 + .. [3] https://en.wikipedia.org/wiki/Asymptotic_expansion + + See Also + ======== + + Expr.aseries: See the docstring of this function for complete details of this wrapper. + """ + + from .symbol import Dummy + + if x.is_positive is x.is_negative is None: + xpos = Dummy('x', positive=True) + return self.subs(x, xpos).aseries(xpos, n, bound, hir).subs(xpos, x) + + from .function import PoleError + from sympy.series.gruntz import mrv, rewrite + + try: + om, exps = mrv(self, x) + except PoleError: + return self + + # We move one level up by replacing `x` by `exp(x)`, and then + # computing the asymptotic series for f(exp(x)). Then asymptotic series + # can be obtained by moving one-step back, by replacing x by ln(x). + + from sympy.functions.elementary.exponential import exp, log + from sympy.series.order import Order + + if x in om: + s = self.subs(x, exp(x)).aseries(x, n, bound, hir).subs(x, log(x)) + if s.getO(): + return s + Order(1/x**n, (x, S.Infinity)) + return s + + k = Dummy('k', positive=True) + # f is rewritten in terms of omega + func, logw = rewrite(exps, om, x, k) + + if self in om: + if bound <= 0: + return self + s = (self.exp).aseries(x, n, bound=bound) + s = s.func(*[t.removeO() for t in s.args]) + try: + res = exp(s.subs(x, 1/x).as_leading_term(x).subs(x, 1/x)) + except PoleError: + res = self + + func = exp(self.args[0] - res.args[0]) / k + logw = log(1/res) + + s = func.series(k, 0, n) + from sympy.core.function import expand_mul + s = expand_mul(s) + # Hierarchical series + if hir: + return s.subs(k, exp(logw)) + + o = s.getO() + terms = sorted(Add.make_args(s.removeO()), key=lambda i: int(i.as_coeff_exponent(k)[1])) + s = S.Zero + has_ord = False + + # Then we recursively expand these coefficients one by one into + # their asymptotic series in terms of their most rapidly varying subexpressions. + for t in terms: + coeff, expo = t.as_coeff_exponent(k) + if coeff.has(x): + # Recursive step + snew = coeff.aseries(x, n, bound=bound-1) + if has_ord and snew.getO(): + break + elif snew.getO(): + has_ord = True + s += (snew * k**expo) + else: + s += t + + if not o or has_ord: + return s.subs(k, exp(logw)) + return (s + o).subs(k, exp(logw)) + + + def taylor_term(self, n, x, *previous_terms): + """General method for the taylor term. + + This method is slow, because it differentiates n-times. Subclasses can + redefine it to make it faster by using the "previous_terms". + """ + from .symbol import Dummy + from sympy.functions.combinatorial.factorials import factorial + + x = sympify(x) + _x = Dummy('x') + return self.subs(x, _x).diff(_x, n).subs(_x, x).subs(x, 0) * x**n / factorial(n) + + def lseries(self, x=None, x0=0, dir='+', logx=None, cdir=0): + """ + Wrapper for series yielding an iterator of the terms of the series. + + Note: an infinite series will yield an infinite iterator. The following, + for exaxmple, will never terminate. It will just keep printing terms + of the sin(x) series:: + + for term in sin(x).lseries(x): + print term + + The advantage of lseries() over nseries() is that many times you are + just interested in the next term in the series (i.e. the first term for + example), but you do not know how many you should ask for in nseries() + using the "n" parameter. + + See also nseries(). + """ + return self.series(x, x0, n=None, dir=dir, logx=logx, cdir=cdir) + + def _eval_lseries(self, x, logx=None, cdir=0): + # default implementation of lseries is using nseries(), and adaptively + # increasing the "n". As you can see, it is not very efficient, because + # we are calculating the series over and over again. Subclasses should + # override this method and implement much more efficient yielding of + # terms. + n = 0 + series = self._eval_nseries(x, n=n, logx=logx, cdir=cdir) + + while series.is_Order: + n += 1 + series = self._eval_nseries(x, n=n, logx=logx, cdir=cdir) + + e = series.removeO() + yield e + if e is S.Zero: + return + + while 1: + while 1: + n += 1 + series = self._eval_nseries(x, n=n, logx=logx, cdir=cdir).removeO() + if e != series: + break + if (series - self).cancel() is S.Zero: + return + yield series - e + e = series + + def nseries(self, x=None, x0=0, n=6, dir='+', logx=None, cdir=0): + """ + Wrapper to _eval_nseries if assumptions allow, else to series. + + If x is given, x0 is 0, dir='+', and self has x, then _eval_nseries is + called. This calculates "n" terms in the innermost expressions and + then builds up the final series just by "cross-multiplying" everything + out. + + The optional ``logx`` parameter can be used to replace any log(x) in the + returned series with a symbolic value to avoid evaluating log(x) at 0. A + symbol to use in place of log(x) should be provided. + + Advantage -- it's fast, because we do not have to determine how many + terms we need to calculate in advance. + + Disadvantage -- you may end up with less terms than you may have + expected, but the O(x**n) term appended will always be correct and + so the result, though perhaps shorter, will also be correct. + + If any of those assumptions is not met, this is treated like a + wrapper to series which will try harder to return the correct + number of terms. + + See also lseries(). + + Examples + ======== + + >>> from sympy import sin, log, Symbol + >>> from sympy.abc import x, y + >>> sin(x).nseries(x, 0, 6) + x - x**3/6 + x**5/120 + O(x**6) + >>> log(x+1).nseries(x, 0, 5) + x - x**2/2 + x**3/3 - x**4/4 + O(x**5) + + Handling of the ``logx`` parameter --- in the following example the + expansion fails since ``sin`` does not have an asymptotic expansion + at -oo (the limit of log(x) as x approaches 0): + + >>> e = sin(log(x)) + >>> e.nseries(x, 0, 6) + Traceback (most recent call last): + ... + PoleError: ... + ... + >>> logx = Symbol('logx') + >>> e.nseries(x, 0, 6, logx=logx) + sin(logx) + + In the following example, the expansion works but only returns self + unless the ``logx`` parameter is used: + + >>> e = x**y + >>> e.nseries(x, 0, 2) + x**y + >>> e.nseries(x, 0, 2, logx=logx) + exp(logx*y) + + """ + if x and x not in self.free_symbols: + return self + if x is None or x0 or dir != '+': # {see XPOS above} or (x.is_positive == x.is_negative == None): + return self.series(x, x0, n, dir, cdir=cdir) + else: + return self._eval_nseries(x, n=n, logx=logx, cdir=cdir) + + def _eval_nseries(self, x, n, logx, cdir): + """ + Return terms of series for self up to O(x**n) at x=0 + from the positive direction. + + This is a method that should be overridden in subclasses. Users should + never call this method directly (use .nseries() instead), so you do not + have to write docstrings for _eval_nseries(). + """ + raise NotImplementedError(filldedent(""" + The _eval_nseries method should be added to + %s to give terms up to O(x**n) at x=0 + from the positive direction so it is available when + nseries calls it.""" % self.func) + ) + + def limit(self, x, xlim, dir='+'): + """ Compute limit x->xlim. + """ + from sympy.series.limits import limit + return limit(self, x, xlim, dir) + + @cacheit + def as_leading_term(self, *symbols, logx=None, cdir=0): + """ + Returns the leading (nonzero) term of the series expansion of self. + + The _eval_as_leading_term routines are used to do this, and they must + always return a non-zero value. + + Examples + ======== + + >>> from sympy.abc import x + >>> (1 + x + x**2).as_leading_term(x) + 1 + >>> (1/x**2 + x + x**2).as_leading_term(x) + x**(-2) + + """ + if len(symbols) > 1: + c = self + for x in symbols: + c = c.as_leading_term(x, logx=logx, cdir=cdir) + return c + elif not symbols: + return self + x = sympify(symbols[0]) + cdir = sympify(cdir) + if not x.is_symbol: + raise ValueError('expecting a Symbol but got %s' % x) + if x not in self.free_symbols: + return self + obj = self._eval_as_leading_term(x, logx=logx, cdir=cdir) + if obj is not None: + from sympy.simplify.powsimp import powsimp + return powsimp(obj, deep=True, combine='exp') + raise NotImplementedError('as_leading_term(%s, %s)' % (self, x)) + + def _eval_as_leading_term(self, x, logx, cdir): + return self + + def as_coeff_exponent(self, x) -> tuple[Expr, Expr]: + """ ``c*x**e -> c,e`` where x can be any symbolic expression. + """ + from sympy.simplify.radsimp import collect + s = collect(self, x) + c, p = s.as_coeff_mul(x) + if len(p) == 1: + b, e = p[0].as_base_exp() + if b == x: + return c, e + return s, S.Zero + + def leadterm(self, x, logx=None, cdir=0): + """ + Returns the leading term a*x**b as a tuple (a, b). + + Examples + ======== + + >>> from sympy.abc import x + >>> (1+x+x**2).leadterm(x) + (1, 0) + >>> (1/x**2+x+x**2).leadterm(x) + (1, -2) + + """ + from .symbol import Dummy + from sympy.functions.elementary.exponential import log + l = self.as_leading_term(x, logx=logx, cdir=cdir) + d = Dummy('logx') + if l.has(log(x)): + l = l.subs(log(x), d) + c, e = l.as_coeff_exponent(x) + if x in c.free_symbols: + raise ValueError(filldedent(""" + cannot compute leadterm(%s, %s). The coefficient + should have been free of %s but got %s""" % (self, x, x, c))) + c = c.subs(d, log(x)) + return c, e + + def as_coeff_Mul(self, rational: bool = False) -> tuple['Number', Expr]: + """Efficiently extract the coefficient of a product.""" + return S.One, self + + def as_coeff_Add(self, rational=False) -> tuple['Number', Expr]: + """Efficiently extract the coefficient of a summation.""" + return S.Zero, self + + def fps(self, x=None, x0=0, dir=1, hyper=True, order=4, rational=True, + full=False): + """ + Compute formal power power series of self. + + See the docstring of the :func:`fps` function in sympy.series.formal for + more information. + """ + from sympy.series.formal import fps + + return fps(self, x, x0, dir, hyper, order, rational, full) + + def fourier_series(self, limits=None): + """Compute fourier sine/cosine series of self. + + See the docstring of the :func:`fourier_series` in sympy.series.fourier + for more information. + """ + from sympy.series.fourier import fourier_series + + return fourier_series(self, limits) + + ################################################################################### + ##################### DERIVATIVE, INTEGRAL, FUNCTIONAL METHODS #################### + ################################################################################### + + def diff(self, *symbols, **assumptions): + assumptions.setdefault("evaluate", True) + return _derivative_dispatch(self, *symbols, **assumptions) + + ########################################################################### + ###################### EXPRESSION EXPANSION METHODS ####################### + ########################################################################### + + # Relevant subclasses should override _eval_expand_hint() methods. See + # the docstring of expand() for more info. + + def _eval_expand_complex(self, **hints): + real, imag = self.as_real_imag(**hints) + return real + S.ImaginaryUnit*imag + + @staticmethod + def _expand_hint(expr, hint, deep=True, **hints): + """ + Helper for ``expand()``. Recursively calls ``expr._eval_expand_hint()``. + + Returns ``(expr, hit)``, where expr is the (possibly) expanded + ``expr`` and ``hit`` is ``True`` if ``expr`` was truly expanded and + ``False`` otherwise. + """ + hit = False + # XXX: Hack to support non-Basic args + # | + # V + if deep and getattr(expr, 'args', ()) and not expr.is_Atom: + sargs = [] + for arg in expr.args: + arg, arghit = Expr._expand_hint(arg, hint, **hints) + hit |= arghit + sargs.append(arg) + + if hit: + expr = expr.func(*sargs) + + if hasattr(expr, hint): + newexpr = getattr(expr, hint)(**hints) + if newexpr != expr: + return (newexpr, True) + + return (expr, hit) + + @cacheit + def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, + mul=True, log=True, multinomial=True, basic=True, **hints): + """ + Expand an expression using hints. + + See the docstring of the expand() function in sympy.core.function for + more information. + + """ + from sympy.simplify.radsimp import fraction + + hints.update(power_base=power_base, power_exp=power_exp, mul=mul, + log=log, multinomial=multinomial, basic=basic) + + expr = self + # default matches fraction's default + _fraction = lambda x: fraction(x, hints.get('exact', False)) + if hints.pop('frac', False): + n, d = [a.expand(deep=deep, modulus=modulus, **hints) + for a in _fraction(self)] + return n/d + elif hints.pop('denom', False): + n, d = _fraction(self) + return n/d.expand(deep=deep, modulus=modulus, **hints) + elif hints.pop('numer', False): + n, d = _fraction(self) + return n.expand(deep=deep, modulus=modulus, **hints)/d + + # Although the hints are sorted here, an earlier hint may get applied + # at a given node in the expression tree before another because of how + # the hints are applied. e.g. expand(log(x*(y + z))) -> log(x*y + + # x*z) because while applying log at the top level, log and mul are + # applied at the deeper level in the tree so that when the log at the + # upper level gets applied, the mul has already been applied at the + # lower level. + + # Additionally, because hints are only applied once, the expression + # may not be expanded all the way. For example, if mul is applied + # before multinomial, x*(x + 1)**2 won't be expanded all the way. For + # now, we just use a special case to make multinomial run before mul, + # so that at least polynomials will be expanded all the way. In the + # future, smarter heuristics should be applied. + # TODO: Smarter heuristics + + def _expand_hint_key(hint): + """Make multinomial come before mul""" + if hint == 'mul': + return 'mulz' + return hint + + for hint in sorted(hints.keys(), key=_expand_hint_key): + use_hint = hints[hint] + if use_hint: + hint = '_eval_expand_' + hint + expr, hit = Expr._expand_hint(expr, hint, deep=deep, **hints) + + while True: + was = expr + if hints.get('multinomial', False): + expr, _ = Expr._expand_hint( + expr, '_eval_expand_multinomial', deep=deep, **hints) + if hints.get('mul', False): + expr, _ = Expr._expand_hint( + expr, '_eval_expand_mul', deep=deep, **hints) + if hints.get('log', False): + expr, _ = Expr._expand_hint( + expr, '_eval_expand_log', deep=deep, **hints) + if expr == was: + break + + if modulus is not None: + modulus = sympify(modulus) + + if not modulus.is_Integer or modulus <= 0: + raise ValueError( + "modulus must be a positive integer, got %s" % modulus) + + terms = [] + + for term in Add.make_args(expr): + coeff, tail = term.as_coeff_Mul(rational=True) + + coeff %= modulus + + if coeff: + terms.append(coeff*tail) + + expr = Add(*terms) + + return expr + + ########################################################################### + ################### GLOBAL ACTION VERB WRAPPER METHODS #################### + ########################################################################### + + def integrate(self, *args, **kwargs): + """See the integrate function in sympy.integrals""" + from sympy.integrals.integrals import integrate + return integrate(self, *args, **kwargs) + + def nsimplify(self, constants=(), tolerance=None, full=False): + """See the nsimplify function in sympy.simplify""" + from sympy.simplify.simplify import nsimplify + return nsimplify(self, constants, tolerance, full) + + def separate(self, deep=False, force=False): + """See the separate function in sympy.simplify""" + from .function import expand_power_base + return expand_power_base(self, deep=deep, force=force) + + def collect(self, syms, func=None, evaluate=True, exact=False, distribute_order_term=True): + """See the collect function in sympy.simplify""" + from sympy.simplify.radsimp import collect + return collect(self, syms, func, evaluate, exact, distribute_order_term) + + def together(self, *args, **kwargs): + """See the together function in sympy.polys""" + from sympy.polys.rationaltools import together + return together(self, *args, **kwargs) + + def apart(self, x=None, **args): + """See the apart function in sympy.polys""" + from sympy.polys.partfrac import apart + return apart(self, x, **args) + + def ratsimp(self): + """See the ratsimp function in sympy.simplify""" + from sympy.simplify.ratsimp import ratsimp + return ratsimp(self) + + def trigsimp(self, **args): + """See the trigsimp function in sympy.simplify""" + from sympy.simplify.trigsimp import trigsimp + return trigsimp(self, **args) + + def radsimp(self, **kwargs): + """See the radsimp function in sympy.simplify""" + from sympy.simplify.radsimp import radsimp + return radsimp(self, **kwargs) + + def powsimp(self, *args, **kwargs): + """See the powsimp function in sympy.simplify""" + from sympy.simplify.powsimp import powsimp + return powsimp(self, *args, **kwargs) + + def combsimp(self): + """See the combsimp function in sympy.simplify""" + from sympy.simplify.combsimp import combsimp + return combsimp(self) + + def gammasimp(self): + """See the gammasimp function in sympy.simplify""" + from sympy.simplify.gammasimp import gammasimp + return gammasimp(self) + + def factor(self, *gens, **args): + """See the factor() function in sympy.polys.polytools""" + from sympy.polys.polytools import factor + return factor(self, *gens, **args) + + def cancel(self, *gens, **args): + """See the cancel function in sympy.polys""" + from sympy.polys.polytools import cancel + return cancel(self, *gens, **args) + + def invert(self, g, *gens, **args): + """Return the multiplicative inverse of ``self`` mod ``g`` + where ``self`` (and ``g``) may be symbolic expressions). + + See Also + ======== + sympy.core.intfunc.mod_inverse, sympy.polys.polytools.invert + """ + if self.is_number and getattr(g, 'is_number', True): + return mod_inverse(self, g) + from sympy.polys.polytools import invert + return invert(self, g, *gens, **args) + + def round(self, n=None): + """Return x rounded to the given decimal place. + + If a complex number would results, apply round to the real + and imaginary components of the number. + + Examples + ======== + + >>> from sympy import pi, E, I, S, Number + >>> pi.round() + 3 + >>> pi.round(2) + 3.14 + >>> (2*pi + E*I).round() + 6 + 3*I + + The round method has a chopping effect: + + >>> (2*pi + I/10).round() + 6 + >>> (pi/10 + 2*I).round() + 2*I + >>> (pi/10 + E*I).round(2) + 0.31 + 2.72*I + + Notes + ===== + + The Python ``round`` function uses the SymPy ``round`` method so it + will always return a SymPy number (not a Python float or int): + + >>> isinstance(round(S(123), -2), Number) + True + """ + x = self + + if not x.is_number: + raise TypeError("Cannot round symbolic expression") + if not x.is_Atom: + if not pure_complex(x.n(2), or_real=True): + raise TypeError( + 'Expected a number but got %s:' % func_name(x)) + elif x in _illegal: + return x + if not (xr := x.is_extended_real): + r, i = x.as_real_imag() + if xr is False: + return r.round(n) + S.ImaginaryUnit*i.round(n) + if i.equals(0): + return r.round(n) + if not x: + return S.Zero if n is None else x + + p = as_int(n or 0) + + if x.is_Integer: + return Integer(round(int(x), p)) + + digits_to_decimal = _mag(x) # _mag(12) = 2, _mag(.012) = -1 + allow = digits_to_decimal + p + precs = [f._prec for f in x.atoms(Float)] + dps = prec_to_dps(max(precs)) if precs else None + if dps is None: + # assume everything is exact so use the Python + # float default or whatever was requested + dps = max(15, allow) + else: + allow = min(allow, dps) + # this will shift all digits to right of decimal + # and give us dps to work with as an int + shift = -digits_to_decimal + dps + extra = 1 # how far we look past known digits + # NOTE + # mpmath will calculate the binary representation to + # an arbitrary number of digits but we must base our + # answer on a finite number of those digits, e.g. + # .575 2589569785738035/2**52 in binary. + # mpmath shows us that the first 18 digits are + # >>> Float(.575).n(18) + # 0.574999999999999956 + # The default precision is 15 digits and if we ask + # for 15 we get + # >>> Float(.575).n(15) + # 0.575000000000000 + # mpmath handles rounding at the 15th digit. But we + # need to be careful since the user might be asking + # for rounding at the last digit and our semantics + # are to round toward the even final digit when there + # is a tie. So the extra digit will be used to make + # that decision. In this case, the value is the same + # to 15 digits: + # >>> Float(.575).n(16) + # 0.5750000000000000 + # Now converting this to the 15 known digits gives + # 575000000000000.0 + # which rounds to integer + # 5750000000000000 + # And now we can round to the desired digt, e.g. at + # the second from the left and we get + # 5800000000000000 + # and rescaling that gives + # 0.58 + # as the final result. + # If the value is made slightly less than 0.575 we might + # still obtain the same value: + # >>> Float(.575-1e-16).n(16)*10**15 + # 574999999999999.8 + # What 15 digits best represents the known digits (which are + # to the left of the decimal? 5750000000000000, the same as + # before. The only way we will round down (in this case) is + # if we declared that we had more than 15 digits of precision. + # For example, if we use 16 digits of precision, the integer + # we deal with is + # >>> Float(.575-1e-16).n(17)*10**16 + # 5749999999999998.4 + # and this now rounds to 5749999999999998 and (if we round to + # the 2nd digit from the left) we get 5700000000000000. + # + xf = x.n(dps + extra)*Pow(10, shift) + if xf.is_Number and xf._prec == 1: # xf.is_Add will raise below + # is x == 0? + if x.equals(0): + return Float(0) + raise ValueError('not computing with precision') + xi = Integer(xf) + # use the last digit to select the value of xi + # nearest to x before rounding at the desired digit + sign = 1 if x > 0 else -1 + dif2 = sign*(xf - xi).n(extra) + if dif2 < 0: + raise NotImplementedError( + 'not expecting int(x) to round away from 0') + if dif2 > .5: + xi += sign # round away from 0 + elif dif2 == .5: + xi += sign if xi%2 else -sign # round toward even + # shift p to the new position + ip = p - shift + # let Python handle the int rounding then rescale + xr = round(xi.p, ip) + # restore scale + rv = Rational(xr, Pow(10, shift)) + # return Float or Integer + if rv.is_Integer: + if n is None: # the single-arg case + return rv + # use str or else it won't be a float + return Float(str(rv), dps) # keep same precision + else: + if not allow and rv > self: + allow += 1 + return Float(rv, allow) + + __round__ = round + + def _eval_derivative_matrix_lines(self, x): + from sympy.matrices.expressions.matexpr import _LeftRightArgs + return [_LeftRightArgs([S.One, S.One], higher=self._eval_derivative(x))] + + +class AtomicExpr(Atom, Expr): + """ + A parent class for object which are both atoms and Exprs. + + For example: Symbol, Number, Rational, Integer, ... + But not: Add, Mul, Pow, ... + """ + is_number = False + is_Atom = True + + __slots__ = () + + def _eval_derivative(self, s): + if self == s: + return S.One + return S.Zero + + def _eval_derivative_n_times(self, s, n): + from .containers import Tuple + from sympy.matrices.expressions.matexpr import MatrixExpr + from sympy.matrices.matrixbase import MatrixBase + if isinstance(s, (MatrixBase, Tuple, Iterable, MatrixExpr)): + return super()._eval_derivative_n_times(s, n) + from .relational import Eq + from sympy.functions.elementary.piecewise import Piecewise + if self == s: + return Piecewise((self, Eq(n, 0)), (1, Eq(n, 1)), (0, True)) + else: + return Piecewise((self, Eq(n, 0)), (0, True)) + + def _eval_is_polynomial(self, syms): + return True + + def _eval_is_rational_function(self, syms): + return self not in _illegal + + def _eval_is_meromorphic(self, x, a): + from sympy.calculus.accumulationbounds import AccumBounds + return (not self.is_Number or self.is_finite) and not isinstance(self, AccumBounds) + + def _eval_is_algebraic_expr(self, syms): + return True + + def _eval_nseries(self, x, n, logx, cdir=0): + return self + + @property + def expr_free_symbols(self): + sympy_deprecation_warning(""" + The expr_free_symbols property is deprecated. Use free_symbols to get + the free symbols of an expression. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-expr-free-symbols") + return {self} + + +def _mag(x): + r"""Return integer $i$ such that $0.1 \le x/10^i < 1$ + + Examples + ======== + + >>> from sympy.core.expr import _mag + >>> from sympy import Float + >>> _mag(Float(.1)) + 0 + >>> _mag(Float(.01)) + -1 + >>> _mag(Float(1234)) + 4 + """ + from math import log10, ceil, log + xpos = abs(x.n()) + if not xpos: + return S.Zero + try: + mag_first_dig = int(ceil(log10(xpos))) + except (ValueError, OverflowError): + mag_first_dig = int(ceil(Float(mpf_log(xpos._mpf_, 53))/log(10))) + # check that we aren't off by 1 + if (xpos/S(10)**mag_first_dig) >= 1: + assert 1 <= (xpos/S(10)**mag_first_dig) < 10 + mag_first_dig += 1 + return mag_first_dig + + +class UnevaluatedExpr(Expr): + """ + Expression that is not evaluated unless released. + + Examples + ======== + + >>> from sympy import UnevaluatedExpr + >>> from sympy.abc import x + >>> x*(1/x) + 1 + >>> x*UnevaluatedExpr(1/x) + x*1/x + + """ + + def __new__(cls, arg, **kwargs): + arg = _sympify(arg) + obj = Expr.__new__(cls, arg, **kwargs) + return obj + + def doit(self, **hints): + if hints.get("deep", True): + return self.args[0].doit(**hints) + else: + return self.args[0] + + + +def unchanged(func, *args): + """Return True if `func` applied to the `args` is unchanged. + Can be used instead of `assert foo == foo`. + + Examples + ======== + + >>> from sympy import Piecewise, cos, pi + >>> from sympy.core.expr import unchanged + >>> from sympy.abc import x + + >>> unchanged(cos, 1) # instead of assert cos(1) == cos(1) + True + + >>> unchanged(cos, pi) + False + + Comparison of args uses the builtin capabilities of the object's + arguments to test for equality so args can be defined loosely. Here, + the ExprCondPair arguments of Piecewise compare as equal to the + tuples that can be used to create the Piecewise: + + >>> unchanged(Piecewise, (x, x > 1), (0, True)) + True + """ + f = func(*args) + return f.func == func and f.args == args + + +class ExprBuilder: + def __init__(self, op, args=None, validator=None, check=True): + if not hasattr(op, "__call__"): + raise TypeError("op {} needs to be callable".format(op)) + self.op = op + if args is None: + self.args = [] + else: + self.args = args + self.validator = validator + if (validator is not None) and check: + self.validate() + + @staticmethod + def _build_args(args): + return [i.build() if isinstance(i, ExprBuilder) else i for i in args] + + def validate(self): + if self.validator is None: + return + args = self._build_args(self.args) + self.validator(*args) + + def build(self, check=True): + args = self._build_args(self.args) + if self.validator and check: + self.validator(*args) + return self.op(*args) + + def append_argument(self, arg, check=True): + self.args.append(arg) + if self.validator and check: + self.validate(*self.args) + + def __getitem__(self, item): + if item == 0: + return self.op + else: + return self.args[item-1] + + def __repr__(self): + return str(self.build()) + + def search_element(self, elem): + for i, arg in enumerate(self.args): + if isinstance(arg, ExprBuilder): + ret = arg.search_index(elem) + if ret is not None: + return (i,) + ret + elif id(arg) == id(elem): + return (i,) + return None + + +from .mul import Mul +from .add import Add +from .power import Pow +from .function import Function, _derivative_dispatch +from .mod import Mod +from .exprtools import factor_terms +from .numbers import Float, Integer, Rational, _illegal, int_valued diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/exprtools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/exprtools.py new file mode 100644 index 0000000000000000000000000000000000000000..4868e4416a72e91dc12c9113d90b9c31c5e26011 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/exprtools.py @@ -0,0 +1,1573 @@ +"""Tools for manipulating of large commutative expressions. """ + +from __future__ import annotations + +from .add import Add +from .mul import Mul, _keep_coeff +from .power import Pow +from .basic import Basic +from .expr import Expr +from .function import expand_power_exp +from .sympify import sympify +from .numbers import Rational, Integer, Number, I, equal_valued +from .singleton import S +from .sorting import default_sort_key, ordered +from .symbol import Dummy +from .traversal import preorder_traversal +from .coreerrors import NonCommutativeExpression +from .containers import Tuple, Dict +from sympy.external.gmpy import SYMPY_INTS +from sympy.utilities.iterables import (common_prefix, common_suffix, + variations, iterable, is_sequence) + +from collections import defaultdict + + +_eps = Dummy(positive=True) + + +def _isnumber(i): + return isinstance(i, (SYMPY_INTS, float)) or i.is_Number + + +def _monotonic_sign(self): + """Return the value closest to 0 that ``self`` may have if all symbols + are signed and the result is uniformly the same sign for all values of symbols. + If a symbol is only signed but not known to be an + integer or the result is 0 then a symbol representative of the sign of self + will be returned. Otherwise, None is returned if a) the sign could be positive + or negative or b) self is not in one of the following forms: + + - L(x, y, ...) + A: a function linear in all symbols x, y, ... with an + additive constant; if A is zero then the function can be a monomial whose + sign is monotonic over the range of the variables, e.g. (x + 1)**3 if x is + nonnegative. + - A/L(x, y, ...) + B: the inverse of a function linear in all symbols x, y, ... + that does not have a sign change from positive to negative for any set + of values for the variables. + - M(x, y, ...) + A: a monomial M whose factors are all signed and a constant, A. + - A/M(x, y, ...) + B: the inverse of a monomial and constants A and B. + - P(x): a univariate polynomial + + Examples + ======== + + >>> from sympy.core.exprtools import _monotonic_sign as F + >>> from sympy import Dummy + >>> nn = Dummy(integer=True, nonnegative=True) + >>> p = Dummy(integer=True, positive=True) + >>> p2 = Dummy(integer=True, positive=True) + >>> F(nn + 1) + 1 + >>> F(p - 1) + _nneg + >>> F(nn*p + 1) + 1 + >>> F(p2*p + 1) + 2 + >>> F(nn - 1) # could be negative, zero or positive + """ + if not self.is_extended_real: + return + + if (-self).is_Symbol: + rv = _monotonic_sign(-self) + return rv if rv is None else -rv + + if not self.is_Add and self.as_numer_denom()[1].is_number: + s = self + if s.is_prime: + if s.is_odd: + return Integer(3) + else: + return Integer(2) + elif s.is_composite: + if s.is_odd: + return Integer(9) + else: + return Integer(4) + elif s.is_positive: + if s.is_even: + if s.is_prime is False: + return Integer(4) + else: + return Integer(2) + elif s.is_integer: + return S.One + else: + return _eps + elif s.is_extended_negative: + if s.is_even: + return Integer(-2) + elif s.is_integer: + return S.NegativeOne + else: + return -_eps + if s.is_zero or s.is_extended_nonpositive or s.is_extended_nonnegative: + return S.Zero + return None + + # univariate polynomial + free = self.free_symbols + if len(free) == 1: + if self.is_polynomial(): + from sympy.polys.polytools import real_roots + from sympy.polys.polyroots import roots + from sympy.polys.polyerrors import PolynomialError + x = free.pop() + x0 = _monotonic_sign(x) + if x0 in (_eps, -_eps): + x0 = S.Zero + if x0 is not None: + d = self.diff(x) + if d.is_number: + currentroots = [] + else: + try: + currentroots = real_roots(d) + except (PolynomialError, NotImplementedError): + currentroots = [r for r in roots(d, x) if r.is_extended_real] + y = self.subs(x, x0) + if x.is_nonnegative and all( + (r - x0).is_nonpositive for r in currentroots): + if y.is_nonnegative and d.is_positive: + if y: + return y if y.is_positive else Dummy('pos', positive=True) + else: + return Dummy('nneg', nonnegative=True) + if y.is_nonpositive and d.is_negative: + if y: + return y if y.is_negative else Dummy('neg', negative=True) + else: + return Dummy('npos', nonpositive=True) + elif x.is_nonpositive and all( + (r - x0).is_nonnegative for r in currentroots): + if y.is_nonnegative and d.is_negative: + if y: + return Dummy('pos', positive=True) + else: + return Dummy('nneg', nonnegative=True) + if y.is_nonpositive and d.is_positive: + if y: + return Dummy('neg', negative=True) + else: + return Dummy('npos', nonpositive=True) + else: + n, d = self.as_numer_denom() + den = None + if n.is_number: + den = _monotonic_sign(d) + elif not d.is_number: + if _monotonic_sign(n) is not None: + den = _monotonic_sign(d) + if den is not None and (den.is_positive or den.is_negative): + v = n*den + if v.is_positive: + return Dummy('pos', positive=True) + elif v.is_nonnegative: + return Dummy('nneg', nonnegative=True) + elif v.is_negative: + return Dummy('neg', negative=True) + elif v.is_nonpositive: + return Dummy('npos', nonpositive=True) + return None + + # multivariate + c, a = self.as_coeff_Add() + v = None + if not a.is_polynomial(): + # F/A or A/F where A is a number and F is a signed, rational monomial + n, d = a.as_numer_denom() + if not (n.is_number or d.is_number): + return + if ( + a.is_Mul or a.is_Pow) and \ + a.is_rational and \ + all(p.exp.is_Integer for p in a.atoms(Pow) if p.is_Pow) and \ + (a.is_positive or a.is_negative): + v = S.One + for ai in Mul.make_args(a): + if ai.is_number: + v *= ai + continue + reps = {} + for x in ai.free_symbols: + reps[x] = _monotonic_sign(x) + if reps[x] is None: + return + v *= ai.subs(reps) + elif c: + # signed linear expression + if not any(p for p in a.atoms(Pow) if not p.is_number) and (a.is_nonpositive or a.is_nonnegative): + free = list(a.free_symbols) + p = {} + for i in free: + v = _monotonic_sign(i) + if v is None: + return + p[i] = v or (_eps if i.is_nonnegative else -_eps) + v = a.xreplace(p) + if v is not None: + rv = v + c + if v.is_nonnegative and rv.is_positive: + return rv.subs(_eps, 0) + if v.is_nonpositive and rv.is_negative: + return rv.subs(_eps, 0) + + +def decompose_power(expr: Expr) -> tuple[Expr, int]: + """ + Decompose power into symbolic base and integer exponent. + + Examples + ======== + + >>> from sympy.core.exprtools import decompose_power + >>> from sympy.abc import x, y + >>> from sympy import exp + + >>> decompose_power(x) + (x, 1) + >>> decompose_power(x**2) + (x, 2) + >>> decompose_power(exp(2*y/3)) + (exp(y/3), 2) + + """ + base, exp = expr.as_base_exp() + + if exp.is_Number: + if exp.is_Rational: + if not exp.is_Integer: + base = Pow(base, Rational(1, exp.q)) # type: ignore + e = exp.p # type: ignore + else: + base, e = expr, 1 + else: + exp, tail = exp.as_coeff_Mul(rational=True) + + if exp is S.NegativeOne: + base, e = Pow(base, tail), -1 + elif exp is not S.One: + # todo: after dropping python 3.7 support, use overload and Literal + # in as_coeff_Mul to make exp Rational, and remove these 2 ignores + tail = _keep_coeff(Rational(1, exp.q), tail) # type: ignore + base, e = Pow(base, tail), exp.p # type: ignore + else: + base, e = expr, 1 + + return base, e + + +def decompose_power_rat(expr: Expr) -> tuple[Expr, Rational]: + """ + Decompose power into symbolic base and rational exponent; + if the exponent is not a Rational, then separate only the + integer coefficient. + + Examples + ======== + + >>> from sympy.core.exprtools import decompose_power_rat + >>> from sympy.abc import x + >>> from sympy import sqrt, exp + + >>> decompose_power_rat(sqrt(x)) + (x, 1/2) + >>> decompose_power_rat(exp(-3*x/2)) + (exp(x/2), -3) + + """ + base, exp = expr.as_base_exp() + if not exp.is_Rational: + base, exp_i = decompose_power(expr) + exp = Integer(exp_i) + return base, exp # type: ignore + + +class Factors: + """Efficient representation of ``f_1*f_2*...*f_n``.""" + + __slots__ = ('factors', 'gens') + + def __init__(self, factors=None): # Factors + """Initialize Factors from dict or expr. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x + >>> from sympy import I + >>> e = 2*x**3 + >>> Factors(e) + Factors({2: 1, x: 3}) + >>> Factors(e.as_powers_dict()) + Factors({2: 1, x: 3}) + >>> f = _ + >>> f.factors # underlying dictionary + {2: 1, x: 3} + >>> f.gens # base of each factor + frozenset({2, x}) + >>> Factors(0) + Factors({0: 1}) + >>> Factors(I) + Factors({I: 1}) + + Notes + ===== + + Although a dictionary can be passed, only minimal checking is + performed: powers of -1 and I are made canonical. + + """ + if isinstance(factors, (SYMPY_INTS, float)): + factors = S(factors) + if isinstance(factors, Factors): + factors = factors.factors.copy() + elif factors in (None, S.One): + factors = {} + elif factors is S.Zero or factors == 0: + factors = {S.Zero: S.One} + elif isinstance(factors, Number): + n = factors + factors = {} + if n < 0: + factors[S.NegativeOne] = S.One + n = -n + if n is not S.One: + if n.is_Float or n.is_Integer or n is S.Infinity: + factors[n] = S.One + elif n.is_Rational: + # since we're processing Numbers, the denominator is + # stored with a negative exponent; all other factors + # are left . + if n.p != 1: + factors[Integer(n.p)] = S.One + factors[Integer(n.q)] = S.NegativeOne + else: + raise ValueError('Expected Float|Rational|Integer, not %s' % n) + elif isinstance(factors, Basic) and not factors.args: + factors = {factors: S.One} + elif isinstance(factors, Expr): + c, nc = factors.args_cnc() + i = c.count(I) + for _ in range(i): + c.remove(I) + factors = dict(Mul._from_args(c).as_powers_dict()) + # Handle all rational Coefficients + for f in list(factors.keys()): + if isinstance(f, Rational) and not isinstance(f, Integer): + p, q = Integer(f.p), Integer(f.q) + factors[p] = (factors[p] if p in factors else S.Zero) + factors[f] + factors[q] = (factors[q] if q in factors else S.Zero) - factors[f] + factors.pop(f) + if i: + factors[I] = factors.get(I, S.Zero) + i + if nc: + factors[Mul(*nc, evaluate=False)] = S.One + else: + factors = factors.copy() # /!\ should be dict-like + + # tidy up -/+1 and I exponents if Rational + + handle = [k for k in factors if k is I or k in (-1, 1)] + if handle: + i1 = S.One + for k in handle: + if not _isnumber(factors[k]): + continue + i1 *= k**factors.pop(k) + if i1 is not S.One: + for a in i1.args if i1.is_Mul else [i1]: # at worst, -1.0*I*(-1)**e + if a is S.NegativeOne: + factors[a] = S.One + elif a is I: + factors[I] = S.One + elif a.is_Pow: + factors[a.base] = factors.get(a.base, S.Zero) + a.exp + elif equal_valued(a, 1): + factors[a] = S.One + elif equal_valued(a, -1): + factors[-a] = S.One + factors[S.NegativeOne] = S.One + else: + raise ValueError('unexpected factor in i1: %s' % a) + + self.factors = factors + keys = getattr(factors, 'keys', None) + if keys is None: + raise TypeError('expecting Expr or dictionary') + self.gens = frozenset(keys()) + + def __hash__(self): # Factors + keys = tuple(ordered(self.factors.keys())) + values = [self.factors[k] for k in keys] + return hash((keys, values)) + + def __repr__(self): # Factors + return "Factors({%s})" % ', '.join( + ['%s: %s' % (k, v) for k, v in ordered(self.factors.items())]) + + @property + def is_zero(self): # Factors + """ + >>> from sympy.core.exprtools import Factors + >>> Factors(0).is_zero + True + """ + f = self.factors + return len(f) == 1 and S.Zero in f + + @property + def is_one(self): # Factors + """ + >>> from sympy.core.exprtools import Factors + >>> Factors(1).is_one + True + """ + return not self.factors + + def as_expr(self): # Factors + """Return the underlying expression. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y + >>> Factors((x*y**2).as_powers_dict()).as_expr() + x*y**2 + + """ + + args = [] + for factor, exp in self.factors.items(): + if exp != 1: + if isinstance(exp, Integer): + b, e = factor.as_base_exp() + e = _keep_coeff(exp, e) + args.append(b**e) + else: + args.append(factor**exp) + else: + args.append(factor) + return Mul(*args) + + def mul(self, other): # Factors + """Return Factors of ``self * other``. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.mul(b) + Factors({x: 2, y: 3, z: -1}) + >>> a*b + Factors({x: 2, y: 3, z: -1}) + """ + if not isinstance(other, Factors): + other = Factors(other) + if any(f.is_zero for f in (self, other)): + return Factors(S.Zero) + factors = dict(self.factors) + + for factor, exp in other.factors.items(): + if factor in factors: + exp = factors[factor] + exp + + if not exp: + del factors[factor] + continue + + factors[factor] = exp + + return Factors(factors) + + def normal(self, other): + """Return ``self`` and ``other`` with ``gcd`` removed from each. + The only differences between this and method ``div`` is that this + is 1) optimized for the case when there are few factors in common and + 2) this does not raise an error if ``other`` is zero. + + See Also + ======== + div + + """ + if not isinstance(other, Factors): + other = Factors(other) + if other.is_zero: + return (Factors(), Factors(S.Zero)) + if self.is_zero: + return (Factors(S.Zero), Factors()) + + self_factors = dict(self.factors) + other_factors = dict(other.factors) + + for factor, self_exp in self.factors.items(): + try: + other_exp = other.factors[factor] + except KeyError: + continue + + exp = self_exp - other_exp + + if not exp: + del self_factors[factor] + del other_factors[factor] + elif _isnumber(exp): + if exp > 0: + self_factors[factor] = exp + del other_factors[factor] + else: + del self_factors[factor] + other_factors[factor] = -exp + else: + r = self_exp.extract_additively(other_exp) + if r is not None: + if r: + self_factors[factor] = r + del other_factors[factor] + else: # should be handled already + del self_factors[factor] + del other_factors[factor] + else: + sc, sa = self_exp.as_coeff_Add() + if sc: + oc, oa = other_exp.as_coeff_Add() + diff = sc - oc + if diff > 0: + self_factors[factor] -= oc + other_exp = oa + elif diff < 0: + self_factors[factor] -= sc + other_factors[factor] -= sc + other_exp = oa - diff + else: + self_factors[factor] = sa + other_exp = oa + if other_exp: + other_factors[factor] = other_exp + else: + del other_factors[factor] + + return Factors(self_factors), Factors(other_factors) + + def div(self, other): # Factors + """Return ``self`` and ``other`` with ``gcd`` removed from each. + This is optimized for the case when there are many factors in common. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> from sympy import S + + >>> a = Factors((x*y**2).as_powers_dict()) + >>> a.div(a) + (Factors({}), Factors({})) + >>> a.div(x*z) + (Factors({y: 2}), Factors({z: 1})) + + The ``/`` operator only gives ``quo``: + + >>> a/x + Factors({y: 2}) + + Factors treats its factors as though they are all in the numerator, so + if you violate this assumption the results will be correct but will + not strictly correspond to the numerator and denominator of the ratio: + + >>> a.div(x/z) + (Factors({y: 2}), Factors({z: -1})) + + Factors is also naive about bases: it does not attempt any denesting + of Rational-base terms, for example the following does not become + 2**(2*x)/2. + + >>> Factors(2**(2*x + 2)).div(S(8)) + (Factors({2: 2*x + 2}), Factors({8: 1})) + + factor_terms can clean up such Rational-bases powers: + + >>> from sympy import factor_terms + >>> n, d = Factors(2**(2*x + 2)).div(S(8)) + >>> n.as_expr()/d.as_expr() + 2**(2*x + 2)/8 + >>> factor_terms(_) + 2**(2*x)/2 + + """ + quo, rem = dict(self.factors), {} + + if not isinstance(other, Factors): + other = Factors(other) + if other.is_zero: + raise ZeroDivisionError + if self.is_zero: + return (Factors(S.Zero), Factors()) + + for factor, exp in other.factors.items(): + if factor in quo: + d = quo[factor] - exp + if _isnumber(d): + if d <= 0: + del quo[factor] + + if d >= 0: + if d: + quo[factor] = d + + continue + + exp = -d + + else: + r = quo[factor].extract_additively(exp) + if r is not None: + if r: + quo[factor] = r + else: # should be handled already + del quo[factor] + else: + other_exp = exp + sc, sa = quo[factor].as_coeff_Add() + if sc: + oc, oa = other_exp.as_coeff_Add() + diff = sc - oc + if diff > 0: + quo[factor] -= oc + other_exp = oa + elif diff < 0: + quo[factor] -= sc + other_exp = oa - diff + else: + quo[factor] = sa + other_exp = oa + if other_exp: + rem[factor] = other_exp + else: + assert factor not in rem + continue + + rem[factor] = exp + + return Factors(quo), Factors(rem) + + def quo(self, other): # Factors + """Return numerator Factor of ``self / other``. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.quo(b) # same as a/b + Factors({y: 1}) + """ + return self.div(other)[0] + + def rem(self, other): # Factors + """Return denominator Factors of ``self / other``. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.rem(b) + Factors({z: -1}) + >>> a.rem(a) + Factors({}) + """ + return self.div(other)[1] + + def pow(self, other): # Factors + """Return self raised to a non-negative integer power. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y + >>> a = Factors((x*y**2).as_powers_dict()) + >>> a**2 + Factors({x: 2, y: 4}) + + """ + if isinstance(other, Factors): + other = other.as_expr() + if other.is_Integer: + other = int(other) + if isinstance(other, SYMPY_INTS) and other >= 0: + factors = {} + + if other: + for factor, exp in self.factors.items(): + factors[factor] = exp*other + + return Factors(factors) + else: + raise ValueError("expected non-negative integer, got %s" % other) + + def gcd(self, other): # Factors + """Return Factors of ``gcd(self, other)``. The keys are + the intersection of factors with the minimum exponent for + each factor. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.gcd(b) + Factors({x: 1, y: 1}) + """ + if not isinstance(other, Factors): + other = Factors(other) + if other.is_zero: + return Factors(self.factors) + + factors = {} + + for factor, exp in self.factors.items(): + factor, exp = sympify(factor), sympify(exp) + if factor in other.factors: + lt = (exp - other.factors[factor]).is_negative + if lt == True: + factors[factor] = exp + elif lt == False: + factors[factor] = other.factors[factor] + + return Factors(factors) + + def lcm(self, other): # Factors + """Return Factors of ``lcm(self, other)`` which are + the union of factors with the maximum exponent for + each factor. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.lcm(b) + Factors({x: 1, y: 2, z: -1}) + """ + if not isinstance(other, Factors): + other = Factors(other) + if any(f.is_zero for f in (self, other)): + return Factors(S.Zero) + + factors = dict(self.factors) + + for factor, exp in other.factors.items(): + if factor in factors: + exp = max(exp, factors[factor]) + + factors[factor] = exp + + return Factors(factors) + + def __mul__(self, other): # Factors + return self.mul(other) + + def __divmod__(self, other): # Factors + return self.div(other) + + def __truediv__(self, other): # Factors + return self.quo(other) + + def __mod__(self, other): # Factors + return self.rem(other) + + def __pow__(self, other): # Factors + return self.pow(other) + + def __eq__(self, other): # Factors + if not isinstance(other, Factors): + other = Factors(other) + return self.factors == other.factors + + def __ne__(self, other): # Factors + return not self == other + + +class Term: + """Efficient representation of ``coeff*(numer/denom)``. """ + + __slots__ = ('coeff', 'numer', 'denom') + + def __init__(self, term, numer=None, denom=None): # Term + if numer is None and denom is None: + if not term.is_commutative: + raise NonCommutativeExpression( + 'commutative expression expected') + + coeff, factors = term.as_coeff_mul() + numer, denom = defaultdict(int), defaultdict(int) + + for factor in factors: + base, exp = decompose_power(factor) + + if base.is_Add: + cont, base = base.primitive() + coeff *= cont**exp + + if exp > 0: + numer[base] += exp + else: + denom[base] += -exp + + numer = Factors(numer) + denom = Factors(denom) + else: + coeff = term + + if numer is None: + numer = Factors() + + if denom is None: + denom = Factors() + + self.coeff = coeff + self.numer = numer + self.denom = denom + + def __hash__(self): # Term + return hash((self.coeff, self.numer, self.denom)) + + def __repr__(self): # Term + return "Term(%s, %s, %s)" % (self.coeff, self.numer, self.denom) + + def as_expr(self): # Term + return self.coeff*(self.numer.as_expr()/self.denom.as_expr()) + + def mul(self, other): # Term + coeff = self.coeff*other.coeff + numer = self.numer.mul(other.numer) + denom = self.denom.mul(other.denom) + + numer, denom = numer.normal(denom) + + return Term(coeff, numer, denom) + + def inv(self): # Term + return Term(1/self.coeff, self.denom, self.numer) + + def quo(self, other): # Term + return self.mul(other.inv()) + + def pow(self, other): # Term + if other < 0: + return self.inv().pow(-other) + else: + return Term(self.coeff ** other, + self.numer.pow(other), + self.denom.pow(other)) + + def gcd(self, other): # Term + return Term(self.coeff.gcd(other.coeff), + self.numer.gcd(other.numer), + self.denom.gcd(other.denom)) + + def lcm(self, other): # Term + return Term(self.coeff.lcm(other.coeff), + self.numer.lcm(other.numer), + self.denom.lcm(other.denom)) + + def __mul__(self, other): # Term + if isinstance(other, Term): + return self.mul(other) + else: + return NotImplemented + + def __truediv__(self, other): # Term + if isinstance(other, Term): + return self.quo(other) + else: + return NotImplemented + + def __pow__(self, other): # Term + if isinstance(other, SYMPY_INTS): + return self.pow(other) + else: + return NotImplemented + + def __eq__(self, other): # Term + return (self.coeff == other.coeff and + self.numer == other.numer and + self.denom == other.denom) + + def __ne__(self, other): # Term + return not self == other + + +def _gcd_terms(terms, isprimitive=False, fraction=True): + """Helper function for :func:`gcd_terms`. + + Parameters + ========== + + isprimitive : boolean, optional + If ``isprimitive`` is True then the call to primitive + for an Add will be skipped. This is useful when the + content has already been extracted. + + fraction : boolean, optional + If ``fraction`` is True then the expression will appear over a common + denominator, the lcm of all term denominators. + """ + + if isinstance(terms, Basic) and not isinstance(terms, Tuple): + terms = Add.make_args(terms) + + terms = list(map(Term, [t for t in terms if t])) + + # there is some simplification that may happen if we leave this + # here rather than duplicate it before the mapping of Term onto + # the terms + if len(terms) == 0: + return S.Zero, S.Zero, S.One + + if len(terms) == 1: + cont = terms[0].coeff + numer = terms[0].numer.as_expr() + denom = terms[0].denom.as_expr() + + else: + cont = terms[0] + for term in terms[1:]: + cont = cont.gcd(term) + + for i, term in enumerate(terms): + terms[i] = term.quo(cont) + + if fraction: + denom = terms[0].denom + + for term in terms[1:]: + denom = denom.lcm(term.denom) + + numers = [] + for term in terms: + numer = term.numer.mul(denom.quo(term.denom)) + numers.append(term.coeff*numer.as_expr()) + else: + numers = [t.as_expr() for t in terms] + denom = Term(S.One).numer + + cont = cont.as_expr() + numer = Add(*numers) + denom = denom.as_expr() + + if not isprimitive and numer.is_Add: + _cont, numer = numer.primitive() + cont *= _cont + + return cont, numer, denom + + +def gcd_terms(terms, isprimitive=False, clear=True, fraction=True): + """Compute the GCD of ``terms`` and put them together. + + Parameters + ========== + + terms : Expr + Can be an expression or a non-Basic sequence of expressions + which will be handled as though they are terms from a sum. + + isprimitive : bool, optional + If ``isprimitive`` is True the _gcd_terms will not run the primitive + method on the terms. + + clear : bool, optional + It controls the removal of integers from the denominator of an Add + expression. When True (default), all numerical denominator will be cleared; + when False the denominators will be cleared only if all terms had numerical + denominators other than 1. + + fraction : bool, optional + When True (default), will put the expression over a common + denominator. + + Examples + ======== + + >>> from sympy import gcd_terms + >>> from sympy.abc import x, y + + >>> gcd_terms((x + 1)**2*y + (x + 1)*y**2) + y*(x + 1)*(x + y + 1) + >>> gcd_terms(x/2 + 1) + (x + 2)/2 + >>> gcd_terms(x/2 + 1, clear=False) + x/2 + 1 + >>> gcd_terms(x/2 + y/2, clear=False) + (x + y)/2 + >>> gcd_terms(x/2 + 1/x) + (x**2 + 2)/(2*x) + >>> gcd_terms(x/2 + 1/x, fraction=False) + (x + 2/x)/2 + >>> gcd_terms(x/2 + 1/x, fraction=False, clear=False) + x/2 + 1/x + + >>> gcd_terms(x/2/y + 1/x/y) + (x**2 + 2)/(2*x*y) + >>> gcd_terms(x/2/y + 1/x/y, clear=False) + (x**2/2 + 1)/(x*y) + >>> gcd_terms(x/2/y + 1/x/y, clear=False, fraction=False) + (x/2 + 1/x)/y + + The ``clear`` flag was ignored in this case because the returned + expression was a rational expression, not a simple sum. + + See Also + ======== + + factor_terms, sympy.polys.polytools.terms_gcd + + """ + def mask(terms): + """replace nc portions of each term with a unique Dummy symbols + and return the replacements to restore them""" + args = [(a, []) if a.is_commutative else a.args_cnc() for a in terms] + reps = [] + for i, (c, nc) in enumerate(args): + if nc: + nc = Mul(*nc) + d = Dummy() + reps.append((d, nc)) + c.append(d) + args[i] = Mul(*c) + else: + args[i] = c + return args, dict(reps) + + isadd = isinstance(terms, Add) + addlike = isadd or not isinstance(terms, Basic) and \ + is_sequence(terms, include=set) and \ + not isinstance(terms, Dict) + + if addlike: + if isadd: # i.e. an Add + terms = list(terms.args) + else: + terms = sympify(terms) + terms, reps = mask(terms) + cont, numer, denom = _gcd_terms(terms, isprimitive, fraction) + numer = numer.xreplace(reps) + coeff, factors = cont.as_coeff_Mul() + if not clear: + c, _coeff = coeff.as_coeff_Mul() + if not c.is_Integer and not clear and numer.is_Add: + n, d = c.as_numer_denom() + _numer = numer/d + if any(a.as_coeff_Mul()[0].is_Integer + for a in _numer.args): + numer = _numer + coeff = n*_coeff + return _keep_coeff(coeff, factors*numer/denom, clear=clear) + + if not isinstance(terms, Basic): + return terms + + if terms.is_Atom: + return terms + + if terms.is_Mul: + c, args = terms.as_coeff_mul() + return _keep_coeff(c, Mul(*[gcd_terms(i, isprimitive, clear, fraction) + for i in args]), clear=clear) + + def handle(a): + # don't treat internal args like terms of an Add + if not isinstance(a, Expr): + if isinstance(a, Basic): + if not a.args: + return a + return a.func(*[handle(i) for i in a.args]) + return type(a)([handle(i) for i in a]) + return gcd_terms(a, isprimitive, clear, fraction) + + if isinstance(terms, Dict): + return Dict(*[(k, handle(v)) for k, v in terms.args]) + return terms.func(*[handle(i) for i in terms.args]) + + +def _factor_sum_int(expr, **kwargs): + """Return Sum or Integral object with factors that are not + in the wrt variables removed. In cases where there are additive + terms in the function of the object that are independent, the + object will be separated into two objects. + + Examples + ======== + + >>> from sympy import Sum, factor_terms + >>> from sympy.abc import x, y + >>> factor_terms(Sum(x + y, (x, 1, 3))) + y*Sum(1, (x, 1, 3)) + Sum(x, (x, 1, 3)) + >>> factor_terms(Sum(x*y, (x, 1, 3))) + y*Sum(x, (x, 1, 3)) + + Notes + ===== + + If a function in the summand or integrand is replaced + with a symbol, then this simplification should not be + done or else an incorrect result will be obtained when + the symbol is replaced with an expression that depends + on the variables of summation/integration: + + >>> eq = Sum(y, (x, 1, 3)) + >>> factor_terms(eq).subs(y, x).doit() + 3*x + >>> eq.subs(y, x).doit() + 6 + """ + result = expr.function + if result == 0: + return S.Zero + limits = expr.limits + + # get the wrt variables + wrt = {i.args[0] for i in limits} + + # factor out any common terms that are independent of wrt + f = factor_terms(result, **kwargs) + i, d = f.as_independent(*wrt) + if isinstance(f, Add): + return i * expr.func(1, *limits) + expr.func(d, *limits) + else: + return i * expr.func(d, *limits) + + +def factor_terms(expr: Expr | complex, radical=False, clear=False, fraction=False, sign=True) -> Expr: + """Remove common factors from terms in all arguments without + changing the underlying structure of the expr. No expansion or + simplification (and no processing of non-commutatives) is performed. + + Parameters + ========== + + radical: bool, optional + If radical=True then a radical common to all terms will be factored + out of any Add sub-expressions of the expr. + + clear : bool, optional + If clear=False (default) then coefficients will not be separated + from a single Add if they can be distributed to leave one or more + terms with integer coefficients. + + fraction : bool, optional + If fraction=True (default is False) then a common denominator will be + constructed for the expression. + + sign : bool, optional + If sign=True (default) then even if the only factor in common is a -1, + it will be factored out of the expression. + + Examples + ======== + + >>> from sympy import factor_terms, Symbol + >>> from sympy.abc import x, y + >>> factor_terms(x + x*(2 + 4*y)**3) + x*(8*(2*y + 1)**3 + 1) + >>> A = Symbol('A', commutative=False) + >>> factor_terms(x*A + x*A + x*y*A) + x*(y*A + 2*A) + + When ``clear`` is False, a rational will only be factored out of an + Add expression if all terms of the Add have coefficients that are + fractions: + + >>> factor_terms(x/2 + 1, clear=False) + x/2 + 1 + >>> factor_terms(x/2 + 1, clear=True) + (x + 2)/2 + + If a -1 is all that can be factored out, to *not* factor it out, the + flag ``sign`` must be False: + + >>> factor_terms(-x - y) + -(x + y) + >>> factor_terms(-x - y, sign=False) + -x - y + >>> factor_terms(-2*x - 2*y, sign=False) + -2*(x + y) + + See Also + ======== + + gcd_terms, sympy.polys.polytools.terms_gcd + + """ + def do(expr): + from sympy.concrete.summations import Sum + from sympy.integrals.integrals import Integral + is_iterable = iterable(expr) + + if not isinstance(expr, Basic) or expr.is_Atom: + if is_iterable: + return type(expr)([do(i) for i in expr]) + return expr + + if expr.is_Pow or expr.is_Function or \ + is_iterable or not hasattr(expr, 'args_cnc'): + args = expr.args + newargs = tuple([do(i) for i in args]) + if newargs == args: + return expr + return expr.func(*newargs) + + if isinstance(expr, (Sum, Integral)): + return _factor_sum_int(expr, + radical=radical, clear=clear, + fraction=fraction, sign=sign) + + cont, p = expr.as_content_primitive(radical=radical, clear=clear) + if p.is_Add: + list_args = [do(a) for a in Add.make_args(p)] + # get a common negative (if there) which gcd_terms does not remove + if not any(a.as_coeff_Mul()[0].extract_multiplicatively(-1) is None + for a in list_args): + cont = -cont + list_args = [-a for a in list_args] + # watch out for exp(-(x+2)) which gcd_terms will change to exp(-x-2) + special = {} + for i, a in enumerate(list_args): + b, e = a.as_base_exp() + if e.is_Mul and e != Mul(*e.args): + list_args[i] = Dummy() + special[list_args[i]] = a + # rebuild p not worrying about the order which gcd_terms will fix + p = Add._from_args(list_args) + p = gcd_terms(p, + isprimitive=True, + clear=clear, + fraction=fraction).xreplace(special) + elif p.args: + p = p.func( + *[do(a) for a in p.args]) + rv = _keep_coeff(cont, p, clear=clear, sign=sign) + return rv + expr2 = sympify(expr) + return do(expr2) + + +def _mask_nc(eq, name=None): + """ + Return ``eq`` with non-commutative objects replaced with Dummy + symbols. A dictionary that can be used to restore the original + values is returned: if it is None, the expression is noncommutative + and cannot be made commutative. The third value returned is a list + of any non-commutative symbols that appear in the returned equation. + + Explanation + =========== + + All non-commutative objects other than Symbols are replaced with + a non-commutative Symbol. Identical objects will be identified + by identical symbols. + + If there is only 1 non-commutative object in an expression it will + be replaced with a commutative symbol. Otherwise, the non-commutative + entities are retained and the calling routine should handle + replacements in this case since some care must be taken to keep + track of the ordering of symbols when they occur within Muls. + + Parameters + ========== + + name : str + ``name``, if given, is the name that will be used with numbered Dummy + variables that will replace the non-commutative objects and is mainly + used for doctesting purposes. + + Examples + ======== + + >>> from sympy.physics.secondquant import Commutator, NO, F, Fd + >>> from sympy import symbols + >>> from sympy.core.exprtools import _mask_nc + >>> from sympy.abc import x, y + >>> A, B, C = symbols('A,B,C', commutative=False) + + One nc-symbol: + + >>> _mask_nc(A**2 - x**2, 'd') + (_d0**2 - x**2, {_d0: A}, []) + + Multiple nc-symbols: + + >>> _mask_nc(A**2 - B**2, 'd') + (A**2 - B**2, {}, [A, B]) + + An nc-object with nc-symbols but no others outside of it: + + >>> _mask_nc(1 + x*Commutator(A, B), 'd') + (_d0*x + 1, {_d0: Commutator(A, B)}, []) + >>> _mask_nc(NO(Fd(x)*F(y)), 'd') + (_d0, {_d0: NO(CreateFermion(x)*AnnihilateFermion(y))}, []) + + Multiple nc-objects: + + >>> eq = x*Commutator(A, B) + x*Commutator(A, C)*Commutator(A, B) + >>> _mask_nc(eq, 'd') + (x*_d0 + x*_d1*_d0, {_d0: Commutator(A, B), _d1: Commutator(A, C)}, [_d0, _d1]) + + Multiple nc-objects and nc-symbols: + + >>> eq = A*Commutator(A, B) + B*Commutator(A, C) + >>> _mask_nc(eq, 'd') + (A*_d0 + B*_d1, {_d0: Commutator(A, B), _d1: Commutator(A, C)}, [_d0, _d1, A, B]) + + """ + name = name or 'mask' + # Make Dummy() append sequential numbers to the name + + def numbered_names(): + i = 0 + while True: + yield name + str(i) + i += 1 + + names = numbered_names() + + def Dummy(*args, **kwargs): + from .symbol import Dummy + return Dummy(next(names), *args, **kwargs) + + expr = eq + if expr.is_commutative: + return eq, {}, [] + + # identify nc-objects; symbols and other + rep = [] + nc_obj = set() + nc_syms = set() + pot = preorder_traversal(expr, keys=default_sort_key) + for a in pot: + if any(a == r[0] for r in rep): + pot.skip() + elif not a.is_commutative: + if a.is_symbol: + nc_syms.add(a) + pot.skip() + elif not (a.is_Add or a.is_Mul or a.is_Pow): + nc_obj.add(a) + pot.skip() + + # If there is only one nc symbol or object, it can be factored regularly + # but polys is going to complain, so replace it with a Dummy. + if len(nc_obj) == 1 and not nc_syms: + rep.append((nc_obj.pop(), Dummy())) + elif len(nc_syms) == 1 and not nc_obj: + rep.append((nc_syms.pop(), Dummy())) + + # Any remaining nc-objects will be replaced with an nc-Dummy and + # identified as an nc-Symbol to watch out for + nc_obj = sorted(nc_obj, key=default_sort_key) + for n in nc_obj: + nc = Dummy(commutative=False) + rep.append((n, nc)) + nc_syms.add(nc) + expr = expr.subs(rep) + + nc_syms = list(nc_syms) + nc_syms.sort(key=default_sort_key) + return expr, {v: k for k, v in rep}, nc_syms + + +def factor_nc(expr): + """Return the factored form of ``expr`` while handling non-commutative + expressions. + + Examples + ======== + + >>> from sympy import factor_nc, Symbol + >>> from sympy.abc import x + >>> A = Symbol('A', commutative=False) + >>> B = Symbol('B', commutative=False) + >>> factor_nc((x**2 + 2*A*x + A**2).expand()) + (x + A)**2 + >>> factor_nc(((x + A)*(x + B)).expand()) + (x + A)*(x + B) + """ + expr = sympify(expr) + if not isinstance(expr, Expr) or not expr.args: + return expr + if not expr.is_Add: + return expr.func(*[factor_nc(a) for a in expr.args]) + expr = expr.func(*[expand_power_exp(i) for i in expr.args]) + + from sympy.polys.polytools import gcd, factor + expr, rep, nc_symbols = _mask_nc(expr) + + if rep: + return factor(expr).subs(rep) + else: + args = [a.args_cnc() for a in Add.make_args(expr)] + c = g = l = r = S.One + hit = False + # find any commutative gcd term + for i, a in enumerate(args): + if i == 0: + c = Mul._from_args(a[0]) + elif a[0]: + c = gcd(c, Mul._from_args(a[0])) + else: + c = S.One + if c is not S.One: + hit = True + c, g = c.as_coeff_Mul() + if g is not S.One: + for i, (cc, _) in enumerate(args): + cc = list(Mul.make_args(Mul._from_args(list(cc))/g)) + args[i][0] = cc + for i, (cc, _) in enumerate(args): + if cc: + cc[0] = cc[0]/c + else: + cc = [1/c] + args[i][0] = cc + # find any noncommutative common prefix + for i, a in enumerate(args): + if i == 0: + n = a[1][:] + else: + n = common_prefix(n, a[1]) + if not n: + # is there a power that can be extracted? + if not args[0][1]: + break + b, e = args[0][1][0].as_base_exp() + ok = False + if e.is_Integer: + for t in args: + if not t[1]: + break + bt, et = t[1][0].as_base_exp() + if et.is_Integer and bt == b: + e = min(e, et) + else: + break + else: + ok = hit = True + l = b**e + il = b**-e + for _ in args: + _[1][0] = il*_[1][0] + break + if not ok: + break + else: + hit = True + lenn = len(n) + l = Mul(*n) + for _ in args: + _[1] = _[1][lenn:] + # find any noncommutative common suffix + for i, a in enumerate(args): + if i == 0: + n = a[1][:] + else: + n = common_suffix(n, a[1]) + if not n: + # is there a power that can be extracted? + if not args[0][1]: + break + b, e = args[0][1][-1].as_base_exp() + ok = False + if e.is_Integer: + for t in args: + if not t[1]: + break + bt, et = t[1][-1].as_base_exp() + if et.is_Integer and bt == b: + e = min(e, et) + else: + break + else: + ok = hit = True + r = b**e + il = b**-e + for _ in args: + _[1][-1] = _[1][-1]*il + break + if not ok: + break + else: + hit = True + lenn = len(n) + r = Mul(*n) + for _ in args: + _[1] = _[1][:len(_[1]) - lenn] + if hit: + mid = Add(*[Mul(*cc)*Mul(*nc) for cc, nc in args]) + else: + mid = expr + + from sympy.simplify.powsimp import powsimp + + # sort the symbols so the Dummys would appear in the same + # order as the original symbols, otherwise you may introduce + # a factor of -1, e.g. A**2 - B**2) -- {A:y, B:x} --> y**2 - x**2 + # and the former factors into two terms, (A - B)*(A + B) while the + # latter factors into 3 terms, (-1)*(x - y)*(x + y) + rep1 = [(n, Dummy()) for n in sorted(nc_symbols, key=default_sort_key)] + unrep1 = [(v, k) for k, v in rep1] + unrep1.reverse() + new_mid, r2, _ = _mask_nc(mid.subs(rep1)) + new_mid = powsimp(factor(new_mid)) + + new_mid = new_mid.subs(r2).subs(unrep1) + + if new_mid.is_Pow: + return _keep_coeff(c, g*l*new_mid*r) + + if new_mid.is_Mul: + def _pemexpand(expr): + "Expand with the minimal set of hints necessary to check the result." + return expr.expand(deep=True, mul=True, power_exp=True, + power_base=False, basic=False, multinomial=True, log=False) + # XXX TODO there should be a way to inspect what order the terms + # must be in and just select the plausible ordering without + # checking permutations + cfac = [] + ncfac = [] + for f in new_mid.args: + if f.is_commutative: + cfac.append(f) + else: + b, e = f.as_base_exp() + if e.is_Integer: + ncfac.extend([b]*e) + else: + ncfac.append(f) + pre_mid = g*Mul(*cfac)*l + target = _pemexpand(expr/c) + for s in variations(ncfac, len(ncfac)): + ok = pre_mid*Mul(*s)*r + if _pemexpand(ok) == target: + return _keep_coeff(c, ok) + + # mid was an Add that didn't factor successfully + return _keep_coeff(c, g*l*mid*r) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/facts.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/facts.py new file mode 100644 index 0000000000000000000000000000000000000000..0b98d9b14bbac661d3c0fd1d1fd87977a792fb74 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/facts.py @@ -0,0 +1,634 @@ +r"""This is rule-based deduction system for SymPy + +The whole thing is split into two parts + + - rules compilation and preparation of tables + - runtime inference + +For rule-based inference engines, the classical work is RETE algorithm [1], +[2] Although we are not implementing it in full (or even significantly) +it's still worth a read to understand the underlying ideas. + +In short, every rule in a system of rules is one of two forms: + + - atom -> ... (alpha rule) + - And(atom1, atom2, ...) -> ... (beta rule) + + +The major complexity is in efficient beta-rules processing and usually for an +expert system a lot of effort goes into code that operates on beta-rules. + + +Here we take minimalistic approach to get something usable first. + + - (preparation) of alpha- and beta- networks, everything except + - (runtime) FactRules.deduce_all_facts + + _____________________________________ + ( Kirr: I've never thought that doing ) + ( logic stuff is that difficult... ) + ------------------------------------- + o ^__^ + o (oo)\_______ + (__)\ )\/\ + ||----w | + || || + + +Some references on the topic +---------------------------- + +[1] https://en.wikipedia.org/wiki/Rete_algorithm +[2] http://reports-archive.adm.cs.cmu.edu/anon/1995/CMU-CS-95-113.pdf + +https://en.wikipedia.org/wiki/Propositional_formula +https://en.wikipedia.org/wiki/Inference_rule +https://en.wikipedia.org/wiki/List_of_rules_of_inference +""" + +from collections import defaultdict +from typing import Iterator + +from .logic import Logic, And, Or, Not + + +def _base_fact(atom): + """Return the literal fact of an atom. + + Effectively, this merely strips the Not around a fact. + """ + if isinstance(atom, Not): + return atom.arg + else: + return atom + + +def _as_pair(atom): + if isinstance(atom, Not): + return (atom.arg, False) + else: + return (atom, True) + +# XXX this prepares forward-chaining rules for alpha-network + + +def transitive_closure(implications): + """ + Computes the transitive closure of a list of implications + + Uses Warshall's algorithm, as described at + http://www.cs.hope.edu/~cusack/Notes/Notes/DiscreteMath/Warshall.pdf. + """ + full_implications = set(implications) + literals = set().union(*map(set, full_implications)) + + for k in literals: + for i in literals: + if (i, k) in full_implications: + for j in literals: + if (k, j) in full_implications: + full_implications.add((i, j)) + + return full_implications + + +def deduce_alpha_implications(implications): + """deduce all implications + + Description by example + ---------------------- + + given set of logic rules: + + a -> b + b -> c + + we deduce all possible rules: + + a -> b, c + b -> c + + + implications: [] of (a,b) + return: {} of a -> set([b, c, ...]) + """ + implications = implications + [(Not(j), Not(i)) for (i, j) in implications] + res = defaultdict(set) + full_implications = transitive_closure(implications) + for a, b in full_implications: + if a == b: + continue # skip a->a cyclic input + + res[a].add(b) + + # Clean up tautologies and check consistency + for a, impl in res.items(): + impl.discard(a) + na = Not(a) + if na in impl: + raise ValueError( + 'implications are inconsistent: %s -> %s %s' % (a, na, impl)) + + return res + + +def apply_beta_to_alpha_route(alpha_implications, beta_rules): + """apply additional beta-rules (And conditions) to already-built + alpha implication tables + + TODO: write about + + - static extension of alpha-chains + - attaching refs to beta-nodes to alpha chains + + + e.g. + + alpha_implications: + + a -> [b, !c, d] + b -> [d] + ... + + + beta_rules: + + &(b,d) -> e + + + then we'll extend a's rule to the following + + a -> [b, !c, d, e] + """ + x_impl = {} + for x in alpha_implications.keys(): + x_impl[x] = (set(alpha_implications[x]), []) + for bcond, bimpl in beta_rules: + for bk in bcond.args: + if bk in x_impl: + continue + x_impl[bk] = (set(), []) + + # static extensions to alpha rules: + # A: x -> a,b B: &(a,b) -> c ==> A: x -> a,b,c + seen_static_extension = True + while seen_static_extension: + seen_static_extension = False + + for bcond, bimpl in beta_rules: + if not isinstance(bcond, And): + raise TypeError("Cond is not And") + bargs = set(bcond.args) + for x, (ximpls, bb) in x_impl.items(): + x_all = ximpls | {x} + # A: ... -> a B: &(...) -> a is non-informative + if bimpl not in x_all and bargs.issubset(x_all): + ximpls.add(bimpl) + + # we introduced new implication - now we have to restore + # completeness of the whole set. + bimpl_impl = x_impl.get(bimpl) + if bimpl_impl is not None: + ximpls |= bimpl_impl[0] + seen_static_extension = True + + # attach beta-nodes which can be possibly triggered by an alpha-chain + for bidx, (bcond, bimpl) in enumerate(beta_rules): + bargs = set(bcond.args) + for x, (ximpls, bb) in x_impl.items(): + x_all = ximpls | {x} + # A: ... -> a B: &(...) -> a (non-informative) + if bimpl in x_all: + continue + # A: x -> a... B: &(!a,...) -> ... (will never trigger) + # A: x -> a... B: &(...) -> !a (will never trigger) + if any(Not(xi) in bargs or Not(xi) == bimpl for xi in x_all): + continue + + if bargs & x_all: + bb.append(bidx) + + return x_impl + + +def rules_2prereq(rules): + """build prerequisites table from rules + + Description by example + ---------------------- + + given set of logic rules: + + a -> b, c + b -> c + + we build prerequisites (from what points something can be deduced): + + b <- a + c <- a, b + + rules: {} of a -> [b, c, ...] + return: {} of c <- [a, b, ...] + + Note however, that this prerequisites may be *not* enough to prove a + fact. An example is 'a -> b' rule, where prereq(a) is b, and prereq(b) + is a. That's because a=T -> b=T, and b=F -> a=F, but a=F -> b=? + """ + prereq = defaultdict(set) + for (a, _), impl in rules.items(): + if isinstance(a, Not): + a = a.args[0] + for (i, _) in impl: + if isinstance(i, Not): + i = i.args[0] + prereq[i].add(a) + return prereq + +################ +# RULES PROVER # +################ + + +class TautologyDetected(Exception): + """(internal) Prover uses it for reporting detected tautology""" + pass + + +class Prover: + """ai - prover of logic rules + + given a set of initial rules, Prover tries to prove all possible rules + which follow from given premises. + + As a result proved_rules are always either in one of two forms: alpha or + beta: + + Alpha rules + ----------- + + This are rules of the form:: + + a -> b & c & d & ... + + + Beta rules + ---------- + + This are rules of the form:: + + &(a,b,...) -> c & d & ... + + + i.e. beta rules are join conditions that say that something follows when + *several* facts are true at the same time. + """ + + def __init__(self): + self.proved_rules = [] + self._rules_seen = set() + + def split_alpha_beta(self): + """split proved rules into alpha and beta chains""" + rules_alpha = [] # a -> b + rules_beta = [] # &(...) -> b + for a, b in self.proved_rules: + if isinstance(a, And): + rules_beta.append((a, b)) + else: + rules_alpha.append((a, b)) + return rules_alpha, rules_beta + + @property + def rules_alpha(self): + return self.split_alpha_beta()[0] + + @property + def rules_beta(self): + return self.split_alpha_beta()[1] + + def process_rule(self, a, b): + """process a -> b rule""" # TODO write more? + if (not a) or isinstance(b, bool): + return + if isinstance(a, bool): + return + if (a, b) in self._rules_seen: + return + else: + self._rules_seen.add((a, b)) + + # this is the core of processing + try: + self._process_rule(a, b) + except TautologyDetected: + pass + + def _process_rule(self, a, b): + # right part first + + # a -> b & c --> a -> b ; a -> c + # (?) FIXME this is only correct when b & c != null ! + + if isinstance(b, And): + sorted_bargs = sorted(b.args, key=str) + for barg in sorted_bargs: + self.process_rule(a, barg) + + # a -> b | c --> !b & !c -> !a + # --> a & !b -> c + # --> a & !c -> b + elif isinstance(b, Or): + sorted_bargs = sorted(b.args, key=str) + # detect tautology first + if not isinstance(a, Logic): # Atom + # tautology: a -> a|c|... + if a in sorted_bargs: + raise TautologyDetected(a, b, 'a -> a|c|...') + self.process_rule(And(*[Not(barg) for barg in b.args]), Not(a)) + + for bidx in range(len(sorted_bargs)): + barg = sorted_bargs[bidx] + brest = sorted_bargs[:bidx] + sorted_bargs[bidx + 1:] + self.process_rule(And(a, Not(barg)), Or(*brest)) + + # left part + + # a & b -> c --> IRREDUCIBLE CASE -- WE STORE IT AS IS + # (this will be the basis of beta-network) + elif isinstance(a, And): + sorted_aargs = sorted(a.args, key=str) + if b in sorted_aargs: + raise TautologyDetected(a, b, 'a & b -> a') + self.proved_rules.append((a, b)) + # XXX NOTE at present we ignore !c -> !a | !b + + elif isinstance(a, Or): + sorted_aargs = sorted(a.args, key=str) + if b in sorted_aargs: + raise TautologyDetected(a, b, 'a | b -> a') + for aarg in sorted_aargs: + self.process_rule(aarg, b) + + else: + # both `a` and `b` are atoms + self.proved_rules.append((a, b)) # a -> b + self.proved_rules.append((Not(b), Not(a))) # !b -> !a + +######################################## + + +class FactRules: + """Rules that describe how to deduce facts in logic space + + When defined, these rules allow implications to quickly be determined + for a set of facts. For this precomputed deduction tables are used. + see `deduce_all_facts` (forward-chaining) + + Also it is possible to gather prerequisites for a fact, which is tried + to be proven. (backward-chaining) + + + Definition Syntax + ----------------- + + a -> b -- a=T -> b=T (and automatically b=F -> a=F) + a -> !b -- a=T -> b=F + a == b -- a -> b & b -> a + a -> b & c -- a=T -> b=T & c=T + # TODO b | c + + + Internals + --------- + + .full_implications[k, v]: all the implications of fact k=v + .beta_triggers[k, v]: beta rules that might be triggered when k=v + .prereq -- {} k <- [] of k's prerequisites + + .defined_facts -- set of defined fact names + """ + + def __init__(self, rules): + """Compile rules into internal lookup tables""" + + if isinstance(rules, str): + rules = rules.splitlines() + + # --- parse and process rules --- + P = Prover() + + for rule in rules: + # XXX `a` is hardcoded to be always atom + a, op, b = rule.split(None, 2) + + a = Logic.fromstring(a) + b = Logic.fromstring(b) + + if op == '->': + P.process_rule(a, b) + elif op == '==': + P.process_rule(a, b) + P.process_rule(b, a) + else: + raise ValueError('unknown op %r' % op) + + # --- build deduction networks --- + self.beta_rules = [] + for bcond, bimpl in P.rules_beta: + self.beta_rules.append( + ({_as_pair(a) for a in bcond.args}, _as_pair(bimpl))) + + # deduce alpha implications + impl_a = deduce_alpha_implications(P.rules_alpha) + + # now: + # - apply beta rules to alpha chains (static extension), and + # - further associate beta rules to alpha chain (for inference + # at runtime) + impl_ab = apply_beta_to_alpha_route(impl_a, P.rules_beta) + + # extract defined fact names + self.defined_facts = {_base_fact(k) for k in impl_ab.keys()} + + # build rels (forward chains) + full_implications = defaultdict(set) + beta_triggers = defaultdict(set) + for k, (impl, betaidxs) in impl_ab.items(): + full_implications[_as_pair(k)] = {_as_pair(i) for i in impl} + beta_triggers[_as_pair(k)] = betaidxs + + self.full_implications = full_implications + self.beta_triggers = beta_triggers + + # build prereq (backward chains) + prereq = defaultdict(set) + rel_prereq = rules_2prereq(full_implications) + for k, pitems in rel_prereq.items(): + prereq[k] |= pitems + self.prereq = prereq + + def _to_python(self) -> str: + """ Generate a string with plain python representation of the instance """ + return '\n'.join(self.print_rules()) + + @classmethod + def _from_python(cls, data : dict): + """ Generate an instance from the plain python representation """ + self = cls('') + for key in ['full_implications', 'beta_triggers', 'prereq']: + d=defaultdict(set) + d.update(data[key]) + setattr(self, key, d) + self.beta_rules = data['beta_rules'] + self.defined_facts = set(data['defined_facts']) + + return self + + def _defined_facts_lines(self): + yield 'defined_facts = [' + for fact in sorted(self.defined_facts): + yield f' {fact!r},' + yield '] # defined_facts' + + def _full_implications_lines(self): + yield 'full_implications = dict( [' + for fact in sorted(self.defined_facts): + for value in (True, False): + yield f' # Implications of {fact} = {value}:' + yield f' (({fact!r}, {value!r}), set( (' + implications = self.full_implications[(fact, value)] + for implied in sorted(implications): + yield f' {implied!r},' + yield ' ) ),' + yield ' ),' + yield ' ] ) # full_implications' + + def _prereq_lines(self): + yield 'prereq = {' + yield '' + for fact in sorted(self.prereq): + yield f' # facts that could determine the value of {fact}' + yield f' {fact!r}: {{' + for pfact in sorted(self.prereq[fact]): + yield f' {pfact!r},' + yield ' },' + yield '' + yield '} # prereq' + + def _beta_rules_lines(self): + reverse_implications = defaultdict(list) + for n, (pre, implied) in enumerate(self.beta_rules): + reverse_implications[implied].append((pre, n)) + + yield '# Note: the order of the beta rules is used in the beta_triggers' + yield 'beta_rules = [' + yield '' + m = 0 + indices = {} + for implied in sorted(reverse_implications): + fact, value = implied + yield f' # Rules implying {fact} = {value}' + for pre, n in reverse_implications[implied]: + indices[n] = m + m += 1 + setstr = ", ".join(map(str, sorted(pre))) + yield f' ({{{setstr}}},' + yield f' {implied!r}),' + yield '' + yield '] # beta_rules' + + yield 'beta_triggers = {' + for query in sorted(self.beta_triggers): + fact, value = query + triggers = [indices[n] for n in self.beta_triggers[query]] + yield f' {query!r}: {triggers!r},' + yield '} # beta_triggers' + + def print_rules(self) -> Iterator[str]: + """ Returns a generator with lines to represent the facts and rules """ + yield from self._defined_facts_lines() + yield '' + yield '' + yield from self._full_implications_lines() + yield '' + yield '' + yield from self._prereq_lines() + yield '' + yield '' + yield from self._beta_rules_lines() + yield '' + yield '' + yield "generated_assumptions = {'defined_facts': defined_facts, 'full_implications': full_implications," + yield " 'prereq': prereq, 'beta_rules': beta_rules, 'beta_triggers': beta_triggers}" + + +class InconsistentAssumptions(ValueError): + def __str__(self): + kb, fact, value = self.args + return "%s, %s=%s" % (kb, fact, value) + + +class FactKB(dict): + """ + A simple propositional knowledge base relying on compiled inference rules. + """ + def __str__(self): + return '{\n%s}' % ',\n'.join( + ["\t%s: %s" % i for i in sorted(self.items())]) + + def __init__(self, rules): + self.rules = rules + + def _tell(self, k, v): + """Add fact k=v to the knowledge base. + + Returns True if the KB has actually been updated, False otherwise. + """ + if k in self and self[k] is not None: + if self[k] == v: + return False + else: + raise InconsistentAssumptions(self, k, v) + else: + self[k] = v + return True + + # ********************************************* + # * This is the workhorse, so keep it *fast*. * + # ********************************************* + def deduce_all_facts(self, facts): + """ + Update the KB with all the implications of a list of facts. + + Facts can be specified as a dictionary or as a list of (key, value) + pairs. + """ + # keep frequently used attributes locally, so we'll avoid extra + # attribute access overhead + full_implications = self.rules.full_implications + beta_triggers = self.rules.beta_triggers + beta_rules = self.rules.beta_rules + + if isinstance(facts, dict): + facts = facts.items() + + while facts: + beta_maytrigger = set() + + # --- alpha chains --- + for k, v in facts: + if not self._tell(k, v) or v is None: + continue + + # lookup routing tables + for key, value in full_implications[k, v]: + self._tell(key, value) + + beta_maytrigger.update(beta_triggers[k, v]) + + # --- beta chains --- + facts = [] + for bidx in beta_maytrigger: + bcond, bimpl = beta_rules[bidx] + if all(self.get(k) is v for k, v in bcond): + facts.append(bimpl) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/function.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/function.py new file mode 100644 index 0000000000000000000000000000000000000000..ac850845e0bb2aaf9b535635567d6e2629527ad7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/function.py @@ -0,0 +1,3423 @@ +""" +There are three types of functions implemented in SymPy: + + 1) defined functions (in the sense that they can be evaluated) like + exp or sin; they have a name and a body: + f = exp + 2) undefined function which have a name but no body. Undefined + functions can be defined using a Function class as follows: + f = Function('f') + (the result will be a Function instance) + 3) anonymous function (or lambda function) which have a body (defined + with dummy variables) but have no name: + f = Lambda(x, exp(x)*x) + f = Lambda((x, y), exp(x)*y) + The fourth type of functions are composites, like (sin + cos)(x); these work in + SymPy core, but are not yet part of SymPy. + + Examples + ======== + + >>> import sympy + >>> f = sympy.Function("f") + >>> from sympy.abc import x + >>> f(x) + f(x) + >>> print(sympy.srepr(f(x).func)) + Function('f') + >>> f(x).args + (x,) + +""" + +from __future__ import annotations + +from typing import Any +from collections.abc import Iterable +import copyreg + +from .add import Add +from .basic import Basic, _atomic +from .cache import cacheit +from .containers import Tuple, Dict +from .decorators import _sympifyit +from .evalf import pure_complex +from .expr import Expr, AtomicExpr +from .logic import fuzzy_and, fuzzy_or, fuzzy_not, FuzzyBool +from .mul import Mul +from .numbers import Rational, Float, Integer +from .operations import LatticeOp +from .parameters import global_parameters +from .rules import Transform +from .singleton import S +from .sympify import sympify, _sympify + +from .sorting import default_sort_key, ordered +from sympy.utilities.exceptions import (sympy_deprecation_warning, + SymPyDeprecationWarning, ignore_warnings) +from sympy.utilities.iterables import (has_dups, sift, iterable, + is_sequence, uniq, topological_sort) +from sympy.utilities.lambdify import MPMATH_TRANSLATIONS +from sympy.utilities.misc import as_int, filldedent, func_name + +import mpmath +from mpmath.libmp.libmpf import prec_to_dps + +import inspect +from collections import Counter + +def _coeff_isneg(a): + """Return True if the leading Number is negative. + + Examples + ======== + + >>> from sympy.core.function import _coeff_isneg + >>> from sympy import S, Symbol, oo, pi + >>> _coeff_isneg(-3*pi) + True + >>> _coeff_isneg(S(3)) + False + >>> _coeff_isneg(-oo) + True + >>> _coeff_isneg(Symbol('n', negative=True)) # coeff is 1 + False + + For matrix expressions: + + >>> from sympy import MatrixSymbol, sqrt + >>> A = MatrixSymbol("A", 3, 3) + >>> _coeff_isneg(-sqrt(2)*A) + True + >>> _coeff_isneg(sqrt(2)*A) + False + """ + + if a.is_MatMul: + a = a.args[0] + if a.is_Mul: + a = a.args[0] + return a.is_Number and a.is_extended_negative + + +class PoleError(Exception): + pass + + +class ArgumentIndexError(ValueError): + def __str__(self): + return ("Invalid operation with argument number %s for Function %s" % + (self.args[1], self.args[0])) + + +class BadSignatureError(TypeError): + '''Raised when a Lambda is created with an invalid signature''' + pass + + +class BadArgumentsError(TypeError): + '''Raised when a Lambda is called with an incorrect number of arguments''' + pass + + +# Python 3 version that does not raise a Deprecation warning +def arity(cls): + """Return the arity of the function if it is known, else None. + + Explanation + =========== + + When default values are specified for some arguments, they are + optional and the arity is reported as a tuple of possible values. + + Examples + ======== + + >>> from sympy import arity, log + >>> arity(lambda x: x) + 1 + >>> arity(log) + (1, 2) + >>> arity(lambda *x: sum(x)) is None + True + """ + eval_ = getattr(cls, 'eval', cls) + + parameters = inspect.signature(eval_).parameters.items() + if [p for _, p in parameters if p.kind == p.VAR_POSITIONAL]: + return + p_or_k = [p for _, p in parameters if p.kind == p.POSITIONAL_OR_KEYWORD] + # how many have no default and how many have a default value + no, yes = map(len, sift(p_or_k, + lambda p:p.default == p.empty, binary=True)) + return no if not yes else tuple(range(no, no + yes + 1)) + +class FunctionClass(type): + """ + Base class for function classes. FunctionClass is a subclass of type. + + Use Function('' [ , signature ]) to create + undefined function classes. + """ + _new = type.__new__ + + def __init__(cls, *args, **kwargs): + # honor kwarg value or class-defined value before using + # the number of arguments in the eval function (if present) + nargs = kwargs.pop('nargs', cls.__dict__.get('nargs', arity(cls))) + if nargs is None and 'nargs' not in cls.__dict__: + for supcls in cls.__mro__: + if hasattr(supcls, '_nargs'): + nargs = supcls._nargs + break + else: + continue + + # Canonicalize nargs here; change to set in nargs. + if is_sequence(nargs): + if not nargs: + raise ValueError(filldedent(''' + Incorrectly specified nargs as %s: + if there are no arguments, it should be + `nargs = 0`; + if there are any number of arguments, + it should be + `nargs = None`''' % str(nargs))) + nargs = tuple(ordered(set(nargs))) + elif nargs is not None: + nargs = (as_int(nargs),) + cls._nargs = nargs + + # When __init__ is called from UndefinedFunction it is called with + # just one arg but when it is called from subclassing Function it is + # called with the usual (name, bases, namespace) type() signature. + if len(args) == 3: + namespace = args[2] + if 'eval' in namespace and not isinstance(namespace['eval'], classmethod): + raise TypeError("eval on Function subclasses should be a class method (defined with @classmethod)") + + @property + def __signature__(self): + """ + Allow Python 3's inspect.signature to give a useful signature for + Function subclasses. + """ + # Python 3 only, but backports (like the one in IPython) still might + # call this. + try: + from inspect import signature + except ImportError: + return None + + # TODO: Look at nargs + return signature(self.eval) + + @property + def free_symbols(self): + return set() + + @property + def xreplace(self): + # Function needs args so we define a property that returns + # a function that takes args...and then use that function + # to return the right value + return lambda rule, **_: rule.get(self, self) + + @property + def nargs(self): + """Return a set of the allowed number of arguments for the function. + + Examples + ======== + + >>> from sympy import Function + >>> f = Function('f') + + If the function can take any number of arguments, the set of whole + numbers is returned: + + >>> Function('f').nargs + Naturals0 + + If the function was initialized to accept one or more arguments, a + corresponding set will be returned: + + >>> Function('f', nargs=1).nargs + {1} + >>> Function('f', nargs=(2, 1)).nargs + {1, 2} + + The undefined function, after application, also has the nargs + attribute; the actual number of arguments is always available by + checking the ``args`` attribute: + + >>> f = Function('f') + >>> f(1).nargs + Naturals0 + >>> len(f(1).args) + 1 + """ + from sympy.sets.sets import FiniteSet + # XXX it would be nice to handle this in __init__ but there are import + # problems with trying to import FiniteSet there + return FiniteSet(*self._nargs) if self._nargs else S.Naturals0 + + def _valid_nargs(self, n : int) -> bool: + """ Return True if the specified integer is a valid number of arguments + + The number of arguments n is guaranteed to be an integer and positive + + """ + if self._nargs: + return n in self._nargs + + nargs = self.nargs + return nargs is S.Naturals0 or n in nargs + + def __repr__(cls): + return cls.__name__ + + +class Application(Basic, metaclass=FunctionClass): + """ + Base class for applied functions. + + Explanation + =========== + + Instances of Application represent the result of applying an application of + any type to any object. + """ + + is_Function = True + + @cacheit + def __new__(cls, *args, **options): + from sympy.sets.fancysets import Naturals0 + from sympy.sets.sets import FiniteSet + + args = list(map(sympify, args)) + evaluate = options.pop('evaluate', global_parameters.evaluate) + # WildFunction (and anything else like it) may have nargs defined + # and we throw that value away here + options.pop('nargs', None) + + if options: + raise ValueError("Unknown options: %s" % options) + + if evaluate: + evaluated = cls.eval(*args) + if evaluated is not None: + return evaluated + + obj = super().__new__(cls, *args, **options) + + # make nargs uniform here + sentinel = object() + objnargs = getattr(obj, "nargs", sentinel) + if objnargs is not sentinel: + # things passing through here: + # - functions subclassed from Function (e.g. myfunc(1).nargs) + # - functions like cos(1).nargs + # - AppliedUndef with given nargs like Function('f', nargs=1)(1).nargs + # Canonicalize nargs here + if is_sequence(objnargs): + nargs = tuple(ordered(set(objnargs))) + elif objnargs is not None: + nargs = (as_int(objnargs),) + else: + nargs = None + else: + # things passing through here: + # - WildFunction('f').nargs + # - AppliedUndef with no nargs like Function('f')(1).nargs + nargs = obj._nargs # note the underscore here + # convert to FiniteSet + obj.nargs = FiniteSet(*nargs) if nargs else Naturals0() + return obj + + @classmethod + def eval(cls, *args): + """ + Returns a canonical form of cls applied to arguments args. + + Explanation + =========== + + The ``eval()`` method is called when the class ``cls`` is about to be + instantiated and it should return either some simplified instance + (possible of some other class), or if the class ``cls`` should be + unmodified, return None. + + Examples of ``eval()`` for the function "sign" + + .. code-block:: python + + @classmethod + def eval(cls, arg): + if arg is S.NaN: + return S.NaN + if arg.is_zero: return S.Zero + if arg.is_positive: return S.One + if arg.is_negative: return S.NegativeOne + if isinstance(arg, Mul): + coeff, terms = arg.as_coeff_Mul(rational=True) + if coeff is not S.One: + return cls(coeff) * cls(terms) + + """ + return + + @property + def func(self): + return self.__class__ + + def _eval_subs(self, old, new): + if (old.is_Function and new.is_Function and + callable(old) and callable(new) and + old == self.func and len(self.args) in new.nargs): + return new(*[i._subs(old, new) for i in self.args]) + + +class Function(Application, Expr): + r""" + Base class for applied mathematical functions. + + It also serves as a constructor for undefined function classes. + + See the :ref:`custom-functions` guide for details on how to subclass + ``Function`` and what methods can be defined. + + Examples + ======== + + **Undefined Functions** + + To create an undefined function, pass a string of the function name to + ``Function``. + + >>> from sympy import Function, Symbol + >>> x = Symbol('x') + >>> f = Function('f') + >>> g = Function('g')(x) + >>> f + f + >>> f(x) + f(x) + >>> g + g(x) + >>> f(x).diff(x) + Derivative(f(x), x) + >>> g.diff(x) + Derivative(g(x), x) + + Assumptions can be passed to ``Function`` the same as with a + :class:`~.Symbol`. Alternatively, you can use a ``Symbol`` with + assumptions for the function name and the function will inherit the name + and assumptions associated with the ``Symbol``: + + >>> f_real = Function('f', real=True) + >>> f_real(x).is_real + True + >>> f_real_inherit = Function(Symbol('f', real=True)) + >>> f_real_inherit(x).is_real + True + + Note that assumptions on a function are unrelated to the assumptions on + the variables it is called on. If you want to add a relationship, subclass + ``Function`` and define custom assumptions handler methods. See the + :ref:`custom-functions-assumptions` section of the :ref:`custom-functions` + guide for more details. + + **Custom Function Subclasses** + + The :ref:`custom-functions` guide has several + :ref:`custom-functions-complete-examples` of how to subclass ``Function`` + to create a custom function. + + """ + + @property + def _diff_wrt(self): + return False + + @cacheit + def __new__(cls, *args, **options) -> type[AppliedUndef]: # type: ignore + # Handle calls like Function('f') + if cls is Function: + return UndefinedFunction(*args, **options) # type: ignore + else: + return cls._new_(*args, **options) # type: ignore + + @classmethod + def _new_(cls, *args, **options) -> Expr: + n = len(args) + + if not cls._valid_nargs(n): + # XXX: exception message must be in exactly this format to + # make it work with NumPy's functions like vectorize(). See, + # for example, https://github.com/numpy/numpy/issues/1697. + # The ideal solution would be just to attach metadata to + # the exception and change NumPy to take advantage of this. + temp = ('%(name)s takes %(qual)s %(args)s ' + 'argument%(plural)s (%(given)s given)') + raise TypeError(temp % { + 'name': cls, + 'qual': 'exactly' if len(cls.nargs) == 1 else 'at least', + 'args': min(cls.nargs), + 'plural': 's'*(min(cls.nargs) != 1), + 'given': n}) + + evaluate = options.get('evaluate', global_parameters.evaluate) + result = super().__new__(cls, *args, **options) + if evaluate and isinstance(result, cls) and result.args: + _should_evalf = [cls._should_evalf(a) for a in result.args] + pr2 = min(_should_evalf) + if pr2 > 0: + pr = max(_should_evalf) + result = result.evalf(prec_to_dps(pr)) + + return _sympify(result) + + @classmethod + def _should_evalf(cls, arg): + """ + Decide if the function should automatically evalf(). + + Explanation + =========== + + By default (in this implementation), this happens if (and only if) the + ARG is a floating point number (including complex numbers). + This function is used by __new__. + + Returns the precision to evalf to, or -1 if it should not evalf. + """ + if arg.is_Float: + return arg._prec + if not arg.is_Add: + return -1 + m = pure_complex(arg) + if m is None: + return -1 + # the elements of m are of type Number, so have a _prec + return max(m[0]._prec, m[1]._prec) + + @classmethod + def class_key(cls): + from sympy.sets.fancysets import Naturals0 + funcs = { + 'exp': 10, + 'log': 11, + 'sin': 20, + 'cos': 21, + 'tan': 22, + 'cot': 23, + 'sinh': 30, + 'cosh': 31, + 'tanh': 32, + 'coth': 33, + 'conjugate': 40, + 're': 41, + 'im': 42, + 'arg': 43, + } + name = cls.__name__ + + try: + i = funcs[name] + except KeyError: + i = 0 if isinstance(cls.nargs, Naturals0) else 10000 + + return 4, i, name + + def _eval_evalf(self, prec): + + def _get_mpmath_func(fname): + """Lookup mpmath function based on name""" + if isinstance(self, AppliedUndef): + # Shouldn't lookup in mpmath but might have ._imp_ + return None + + if not hasattr(mpmath, fname): + fname = MPMATH_TRANSLATIONS.get(fname, None) + if fname is None: + return None + return getattr(mpmath, fname) + + _eval_mpmath = getattr(self, '_eval_mpmath', None) + if _eval_mpmath is None: + func = _get_mpmath_func(self.func.__name__) + args = self.args + else: + func, args = _eval_mpmath() + + # Fall-back evaluation + if func is None: + imp = getattr(self, '_imp_', None) + if imp is None: + return None + try: + return Float(imp(*[i.evalf(prec) for i in self.args]), prec) + except (TypeError, ValueError): + return None + + # Convert all args to mpf or mpc + # Convert the arguments to *higher* precision than requested for the + # final result. + # XXX + 5 is a guess, it is similar to what is used in evalf.py. Should + # we be more intelligent about it? + try: + args = [arg._to_mpmath(prec + 5) for arg in args] + def bad(m): + from mpmath import mpf, mpc + # the precision of an mpf value is the last element + # if that is 1 (and m[1] is not 1 which would indicate a + # power of 2), then the eval failed; so check that none of + # the arguments failed to compute to a finite precision. + # Note: An mpc value has two parts, the re and imag tuple; + # check each of those parts, too. Anything else is allowed to + # pass + if isinstance(m, mpf): + m = m._mpf_ + return m[1] !=1 and m[-1] == 1 + elif isinstance(m, mpc): + m, n = m._mpc_ + return m[1] !=1 and m[-1] == 1 and \ + n[1] !=1 and n[-1] == 1 + else: + return False + if any(bad(a) for a in args): + raise ValueError # one or more args failed to compute with significance + except ValueError: + return + + with mpmath.workprec(prec): + v = func(*args) + + return Expr._from_mpmath(v, prec) + + def _eval_derivative(self, s): + # f(x).diff(s) -> x.diff(s) * f.fdiff(1)(s) + i = 0 + l = [] + for a in self.args: + i += 1 + da = a.diff(s) + if da.is_zero: + continue + try: + df = self.fdiff(i) + except ArgumentIndexError: + df = Function.fdiff(self, i) + l.append(df * da) + return Add(*l) + + def _eval_is_commutative(self): + return fuzzy_and(a.is_commutative for a in self.args) + + def _eval_is_meromorphic(self, x, a): + if not self.args: + return True + if any(arg.has(x) for arg in self.args[1:]): + return False + + arg = self.args[0] + if not arg._eval_is_meromorphic(x, a): + return None + + return fuzzy_not(type(self).is_singular(arg.subs(x, a))) + + _singularities: FuzzyBool | tuple[Expr, ...] = None + + @classmethod + def is_singular(cls, a): + """ + Tests whether the argument is an essential singularity + or a branch point, or the functions is non-holomorphic. + """ + ss = cls._singularities + if ss in (True, None, False): + return ss + + return fuzzy_or(a.is_infinite if s is S.ComplexInfinity + else (a - s).is_zero for s in ss) + + def _eval_aseries(self, n, args0, x, logx): + """ + Compute an asymptotic expansion around args0, in terms of self.args. + This function is only used internally by _eval_nseries and should not + be called directly; derived classes can overwrite this to implement + asymptotic expansions. + """ + raise PoleError(filldedent(''' + Asymptotic expansion of %s around %s is + not implemented.''' % (type(self), args0))) + + def _eval_nseries(self, x, n, logx, cdir=0): + """ + This function does compute series for multivariate functions, + but the expansion is always in terms of *one* variable. + + Examples + ======== + + >>> from sympy import atan2 + >>> from sympy.abc import x, y + >>> atan2(x, y).series(x, n=2) + atan2(0, y) + x/y + O(x**2) + >>> atan2(x, y).series(y, n=2) + -y/x + atan2(x, 0) + O(y**2) + + This function also computes asymptotic expansions, if necessary + and possible: + + >>> from sympy import loggamma + >>> loggamma(1/x)._eval_nseries(x,0,None) + -1/x - log(x)/x + log(x)/2 + O(1) + + """ + from .symbol import uniquely_named_symbol + from sympy.series.order import Order + from sympy.sets.sets import FiniteSet + args = self.args + args0 = [t.limit(x, 0) for t in args] + if any(t.is_finite is False for t in args0): + from .numbers import oo, zoo, nan + a = [t.as_leading_term(x, logx=logx) for t in args] + a0 = [t.limit(x, 0) for t in a] + if any(t.has(oo, -oo, zoo, nan) for t in a0): + return self._eval_aseries(n, args0, x, logx) + # Careful: the argument goes to oo, but only logarithmically so. We + # are supposed to do a power series expansion "around the + # logarithmic term". e.g. + # f(1+x+log(x)) + # -> f(1+logx) + x*f'(1+logx) + O(x**2) + # where 'logx' is given in the argument + a = [t._eval_nseries(x, n, logx) for t in args] + z = [r - r0 for (r, r0) in zip(a, a0)] + p = [Dummy() for _ in z] + q = [] + v = None + for ai, zi, pi in zip(a0, z, p): + if zi.has(x): + if v is not None: + raise NotImplementedError + q.append(ai + pi) + v = pi + else: + q.append(ai) + e1 = self.func(*q) + if v is None: + return e1 + s = e1._eval_nseries(v, n, logx) + o = s.getO() + s = s.removeO() + s = s.subs(v, zi).expand() + Order(o.expr.subs(v, zi), x) + return s + if (self.func.nargs is S.Naturals0 + or (self.func.nargs == FiniteSet(1) and args0[0]) + or any(c > 1 for c in self.func.nargs)): + e = self + e1 = e.expand() + if e == e1: + #for example when e = sin(x+1) or e = sin(cos(x)) + #let's try the general algorithm + if len(e.args) == 1: + # issue 14411 + e = e.func(e.args[0].cancel()) + term = e.subs(x, S.Zero) + if term.is_finite is False or term is S.NaN: + raise PoleError("Cannot expand %s around 0" % (self)) + series = term + fact = S.One + + _x = uniquely_named_symbol('xi', self) + e = e.subs(x, _x) + for i in range(1, n): + fact *= Rational(i) + e = e.diff(_x) + subs = e.subs(_x, S.Zero) + if subs is S.NaN: + # try to evaluate a limit if we have to + subs = e.limit(_x, S.Zero) + if subs.is_finite is False: + raise PoleError("Cannot expand %s around 0" % (self)) + term = subs*(x**i)/fact + term = term.expand() + series += term + return series + Order(x**n, x) + return e1.nseries(x, n=n, logx=logx) + arg = self.args[0] + l = [] + g = None + # try to predict a number of terms needed + nterms = n + 2 + cf = Order(arg.as_leading_term(x), x).getn() + if cf != 0: + nterms = (n/cf).ceiling() + for i in range(nterms): + g = self.taylor_term(i, arg, g) + g = g.nseries(x, n=n, logx=logx) + l.append(g) + return Add(*l) + Order(x**n, x) + + def fdiff(self, argindex=1): + """ + Returns the first derivative of the function. + """ + if not (1 <= argindex <= len(self.args)): + raise ArgumentIndexError(self, argindex) + ix = argindex - 1 + A = self.args[ix] + if A._diff_wrt: + if len(self.args) == 1 or not A.is_Symbol: + return _derivative_dispatch(self, A) + for i, v in enumerate(self.args): + if i != ix and A in v.free_symbols: + # it can't be in any other argument's free symbols + # issue 8510 + break + else: + return _derivative_dispatch(self, A) + + # See issue 4624 and issue 4719, 5600 and 8510 + D = Dummy('xi_%i' % argindex, dummy_index=hash(A)) + args = self.args[:ix] + (D,) + self.args[ix + 1:] + return Subs(Derivative(self.func(*args), D), D, A) + + def _eval_as_leading_term(self, x, logx, cdir): + """Stub that should be overridden by new Functions to return + the first non-zero term in a series if ever an x-dependent + argument whose leading term vanishes as x -> 0 might be encountered. + See, for example, cos._eval_as_leading_term. + """ + from sympy.series.order import Order + args = [a.as_leading_term(x, logx=logx) for a in self.args] + o = Order(1, x) + if any(x in a.free_symbols and o.contains(a) for a in args): + # Whereas x and any finite number are contained in O(1, x), + # expressions like 1/x are not. If any arg simplified to a + # vanishing expression as x -> 0 (like x or x**2, but not + # 3, 1/x, etc...) then the _eval_as_leading_term is needed + # to supply the first non-zero term of the series, + # + # e.g. expression leading term + # ---------- ------------ + # cos(1/x) cos(1/x) + # cos(cos(x)) cos(1) + # cos(x) 1 <- _eval_as_leading_term needed + # sin(x) x <- _eval_as_leading_term needed + # + raise NotImplementedError( + '%s has no _eval_as_leading_term routine' % self.func) + else: + return self + + +class DefinedFunction(Function): + """Base class for defined functions like ``sin``, ``cos``, ...""" + + @cacheit + def __new__(cls, *args, **options) -> Expr: # type: ignore + return cls._new_(*args, **options) + + +class AppliedUndef(Function): + """ + Base class for expressions resulting from the application of an undefined + function. + """ + + is_number = False + + name: str + + def __new__(cls, *args, **options) -> Expr: # type: ignore + args = tuple(map(sympify, args)) + u = [a.name for a in args if isinstance(a, UndefinedFunction)] + if u: + raise TypeError('Invalid argument: expecting an expression, not UndefinedFunction%s: %s' % ( + 's'*(len(u) > 1), ', '.join(u))) + obj: Expr = super().__new__(cls, *args, **options) # type: ignore + return obj + + def _eval_as_leading_term(self, x, logx, cdir): + return self + + @property + def _diff_wrt(self): + """ + Allow derivatives wrt to undefined functions. + + Examples + ======== + + >>> from sympy import Function, Symbol + >>> f = Function('f') + >>> x = Symbol('x') + >>> f(x)._diff_wrt + True + >>> f(x).diff(x) + Derivative(f(x), x) + """ + return True + + +class UndefSageHelper: + """ + Helper to facilitate Sage conversion. + """ + def __get__(self, ins, typ): + import sage.all as sage + if ins is None: + return lambda: sage.function(typ.__name__) + else: + args = [arg._sage_() for arg in ins.args] + return lambda : sage.function(ins.__class__.__name__)(*args) + +_undef_sage_helper = UndefSageHelper() + + +class UndefinedFunction(FunctionClass): + """ + The (meta)class of undefined functions. + """ + name: str + _sage_: UndefSageHelper + + def __new__(mcl, name, bases=(AppliedUndef,), __dict__=None, **kwargs) -> type[AppliedUndef]: + from .symbol import _filter_assumptions + # Allow Function('f', real=True) + # and/or Function(Symbol('f', real=True)) + assumptions, kwargs = _filter_assumptions(kwargs) + if isinstance(name, Symbol): + assumptions = name._merge(assumptions) + name = name.name + elif not isinstance(name, str): + raise TypeError('expecting string or Symbol for name') + else: + commutative = assumptions.get('commutative', None) + assumptions = Symbol(name, **assumptions).assumptions0 + if commutative is None: + assumptions.pop('commutative') + __dict__ = __dict__ or {} + # put the `is_*` for into __dict__ + __dict__.update({'is_%s' % k: v for k, v in assumptions.items()}) + # You can add other attributes, although they do have to be hashable + # (but seriously, if you want to add anything other than assumptions, + # just subclass Function) + __dict__.update(kwargs) + # add back the sanitized assumptions without the is_ prefix + kwargs.update(assumptions) + # Save these for __eq__ + __dict__.update({'_kwargs': kwargs}) + # do this for pickling + __dict__['__module__'] = None + obj = super().__new__(mcl, name, bases, __dict__) # type: ignore + obj.name = name + obj._sage_ = _undef_sage_helper + return obj # type: ignore + + def __instancecheck__(cls, instance): + return cls in type(instance).__mro__ + + _kwargs: dict[str, bool | None] = {} + + def __hash__(self): + return hash((self.class_key(), frozenset(self._kwargs.items()))) + + def __eq__(self, other): + return (isinstance(other, self.__class__) and + self.class_key() == other.class_key() and + self._kwargs == other._kwargs) + + def __ne__(self, other): + return not self == other + + @property + def _diff_wrt(self): + return False + + +# Using copyreg is the only way to make a dynamically generated instance of a +# metaclass picklable without using a custom pickler. It is not possible to +# define e.g. __reduce__ on the metaclass because obj.__reduce__ will retrieve +# the __reduce__ method for reducing instances of the type rather than for the +# type itself. +def _reduce_undef(f): + return (_rebuild_undef, (f.name, f._kwargs)) + +def _rebuild_undef(name, kwargs): + return Function(name, **kwargs) + +copyreg.pickle(UndefinedFunction, _reduce_undef) + + +# XXX: The type: ignore on WildFunction is because mypy complains: +# +# sympy/core/function.py:939: error: Cannot determine type of 'sort_key' in +# base class 'Expr' +# +# Somehow this is because of the @cacheit decorator but it is not clear how to +# fix it. + + +class WildFunction(Function, AtomicExpr): # type: ignore + """ + A WildFunction function matches any function (with its arguments). + + Examples + ======== + + >>> from sympy import WildFunction, Function, cos + >>> from sympy.abc import x, y + >>> F = WildFunction('F') + >>> f = Function('f') + >>> F.nargs + Naturals0 + >>> x.match(F) + >>> F.match(F) + {F_: F_} + >>> f(x).match(F) + {F_: f(x)} + >>> cos(x).match(F) + {F_: cos(x)} + >>> f(x, y).match(F) + {F_: f(x, y)} + + To match functions with a given number of arguments, set ``nargs`` to the + desired value at instantiation: + + >>> F = WildFunction('F', nargs=2) + >>> F.nargs + {2} + >>> f(x).match(F) + >>> f(x, y).match(F) + {F_: f(x, y)} + + To match functions with a range of arguments, set ``nargs`` to a tuple + containing the desired number of arguments, e.g. if ``nargs = (1, 2)`` + then functions with 1 or 2 arguments will be matched. + + >>> F = WildFunction('F', nargs=(1, 2)) + >>> F.nargs + {1, 2} + >>> f(x).match(F) + {F_: f(x)} + >>> f(x, y).match(F) + {F_: f(x, y)} + >>> f(x, y, 1).match(F) + + """ + + # XXX: What is this class attribute used for? + include: set[Any] = set() + + def __init__(cls, name, **assumptions): + from sympy.sets.sets import Set, FiniteSet + cls.name = name + nargs = assumptions.pop('nargs', S.Naturals0) + if not isinstance(nargs, Set): + # Canonicalize nargs here. See also FunctionClass. + if is_sequence(nargs): + nargs = tuple(ordered(set(nargs))) + elif nargs is not None: + nargs = (as_int(nargs),) + nargs = FiniteSet(*nargs) + cls.nargs = nargs + + def matches(self, expr, repl_dict=None, old=False): + if not isinstance(expr, (AppliedUndef, Function)): + return None + if len(expr.args) not in self.nargs: + return None + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + repl_dict[self] = expr + return repl_dict + + +class Derivative(Expr): + """ + Carries out differentiation of the given expression with respect to symbols. + + Examples + ======== + + >>> from sympy import Derivative, Function, symbols, Subs + >>> from sympy.abc import x, y + >>> f, g = symbols('f g', cls=Function) + + >>> Derivative(x**2, x, evaluate=True) + 2*x + + Denesting of derivatives retains the ordering of variables: + + >>> Derivative(Derivative(f(x, y), y), x) + Derivative(f(x, y), y, x) + + Contiguously identical symbols are merged into a tuple giving + the symbol and the count: + + >>> Derivative(f(x), x, x, y, x) + Derivative(f(x), (x, 2), y, x) + + If the derivative cannot be performed, and evaluate is True, the + order of the variables of differentiation will be made canonical: + + >>> Derivative(f(x, y), y, x, evaluate=True) + Derivative(f(x, y), x, y) + + Derivatives with respect to undefined functions can be calculated: + + >>> Derivative(f(x)**2, f(x), evaluate=True) + 2*f(x) + + Such derivatives will show up when the chain rule is used to + evaluate a derivative: + + >>> f(g(x)).diff(x) + Derivative(f(g(x)), g(x))*Derivative(g(x), x) + + Substitution is used to represent derivatives of functions with + arguments that are not symbols or functions: + + >>> f(2*x + 3).diff(x) == 2*Subs(f(y).diff(y), y, 2*x + 3) + True + + Notes + ===== + + Simplification of high-order derivatives: + + Because there can be a significant amount of simplification that can be + done when multiple differentiations are performed, results will be + automatically simplified in a fairly conservative fashion unless the + keyword ``simplify`` is set to False. + + >>> from sympy import sqrt, diff, Function, symbols + >>> from sympy.abc import x, y, z + >>> f, g = symbols('f,g', cls=Function) + + >>> e = sqrt((x + 1)**2 + x) + >>> diff(e, (x, 5), simplify=False).count_ops() + 136 + >>> diff(e, (x, 5)).count_ops() + 30 + + Ordering of variables: + + If evaluate is set to True and the expression cannot be evaluated, the + list of differentiation symbols will be sorted, that is, the expression is + assumed to have continuous derivatives up to the order asked. + + Derivative wrt non-Symbols: + + For the most part, one may not differentiate wrt non-symbols. + For example, we do not allow differentiation wrt `x*y` because + there are multiple ways of structurally defining where x*y appears + in an expression: a very strict definition would make + (x*y*z).diff(x*y) == 0. Derivatives wrt defined functions (like + cos(x)) are not allowed, either: + + >>> (x*y*z).diff(x*y) + Traceback (most recent call last): + ... + ValueError: Can't calculate derivative wrt x*y. + + To make it easier to work with variational calculus, however, + derivatives wrt AppliedUndef and Derivatives are allowed. + For example, in the Euler-Lagrange method one may write + F(t, u, v) where u = f(t) and v = f'(t). These variables can be + written explicitly as functions of time:: + + >>> from sympy.abc import t + >>> F = Function('F') + >>> U = f(t) + >>> V = U.diff(t) + + The derivative wrt f(t) can be obtained directly: + + >>> direct = F(t, U, V).diff(U) + + When differentiation wrt a non-Symbol is attempted, the non-Symbol + is temporarily converted to a Symbol while the differentiation + is performed and the same answer is obtained: + + >>> indirect = F(t, U, V).subs(U, x).diff(x).subs(x, U) + >>> assert direct == indirect + + The implication of this non-symbol replacement is that all + functions are treated as independent of other functions and the + symbols are independent of the functions that contain them:: + + >>> x.diff(f(x)) + 0 + >>> g(x).diff(f(x)) + 0 + + It also means that derivatives are assumed to depend only + on the variables of differentiation, not on anything contained + within the expression being differentiated:: + + >>> F = f(x) + >>> Fx = F.diff(x) + >>> Fx.diff(F) # derivative depends on x, not F + 0 + >>> Fxx = Fx.diff(x) + >>> Fxx.diff(Fx) # derivative depends on x, not Fx + 0 + + The last example can be made explicit by showing the replacement + of Fx in Fxx with y: + + >>> Fxx.subs(Fx, y) + Derivative(y, x) + + Since that in itself will evaluate to zero, differentiating + wrt Fx will also be zero: + + >>> _.doit() + 0 + + Replacing undefined functions with concrete expressions + + One must be careful to replace undefined functions with expressions + that contain variables consistent with the function definition and + the variables of differentiation or else insconsistent result will + be obtained. Consider the following example: + + >>> eq = f(x)*g(y) + >>> eq.subs(f(x), x*y).diff(x, y).doit() + y*Derivative(g(y), y) + g(y) + >>> eq.diff(x, y).subs(f(x), x*y).doit() + y*Derivative(g(y), y) + + The results differ because `f(x)` was replaced with an expression + that involved both variables of differentiation. In the abstract + case, differentiation of `f(x)` by `y` is 0; in the concrete case, + the presence of `y` made that derivative nonvanishing and produced + the extra `g(y)` term. + + Defining differentiation for an object + + An object must define ._eval_derivative(symbol) method that returns + the differentiation result. This function only needs to consider the + non-trivial case where expr contains symbol and it should call the diff() + method internally (not _eval_derivative); Derivative should be the only + one to call _eval_derivative. + + Any class can allow derivatives to be taken with respect to + itself (while indicating its scalar nature). See the + docstring of Expr._diff_wrt. + + See Also + ======== + _sort_variable_count + """ + + is_Derivative = True + + @property + def _diff_wrt(self): + """An expression may be differentiated wrt a Derivative if + it is in elementary form. + + Examples + ======== + + >>> from sympy import Function, Derivative, cos + >>> from sympy.abc import x + >>> f = Function('f') + + >>> Derivative(f(x), x)._diff_wrt + True + >>> Derivative(cos(x), x)._diff_wrt + False + >>> Derivative(x + 1, x)._diff_wrt + False + + A Derivative might be an unevaluated form of what will not be + a valid variable of differentiation if evaluated. For example, + + >>> Derivative(f(f(x)), x).doit() + Derivative(f(x), x)*Derivative(f(f(x)), f(x)) + + Such an expression will present the same ambiguities as arise + when dealing with any other product, like ``2*x``, so ``_diff_wrt`` + is False: + + >>> Derivative(f(f(x)), x)._diff_wrt + False + """ + return self.expr._diff_wrt and isinstance(self.doit(), Derivative) + + def __new__(cls, expr, *variables, **kwargs): + expr = sympify(expr) + if not isinstance(expr, Basic): + raise TypeError(f"Cannot represent derivative of {type(expr)}") + symbols_or_none = getattr(expr, "free_symbols", None) + has_symbol_set = isinstance(symbols_or_none, set) + + if not has_symbol_set: + raise ValueError(filldedent(''' + Since there are no variables in the expression %s, + it cannot be differentiated.''' % expr)) + + # determine value for variables if it wasn't given + if not variables: + variables = expr.free_symbols + if len(variables) != 1: + if expr.is_number: + return S.Zero + if len(variables) == 0: + raise ValueError(filldedent(''' + Since there are no variables in the expression, + the variable(s) of differentiation must be supplied + to differentiate %s''' % expr)) + else: + raise ValueError(filldedent(''' + Since there is more than one variable in the + expression, the variable(s) of differentiation + must be supplied to differentiate %s''' % expr)) + + # Split the list of variables into a list of the variables we are diff + # wrt, where each element of the list has the form (s, count) where + # s is the entity to diff wrt and count is the order of the + # derivative. + variable_count = [] + array_likes = (tuple, list, Tuple) + + from sympy.tensor.array import Array, NDimArray + + for i, v in enumerate(variables): + if isinstance(v, UndefinedFunction): + raise TypeError( + "cannot differentiate wrt " + "UndefinedFunction: %s" % v) + + if isinstance(v, array_likes): + if len(v) == 0: + # Ignore empty tuples: Derivative(expr, ... , (), ... ) + continue + if isinstance(v[0], array_likes): + # Derive by array: Derivative(expr, ... , [[x, y, z]], ... ) + if len(v) == 1: + v = Array(v[0]) + count = 1 + else: + v, count = v + v = Array(v) + else: + v, count = v + if count == 0: + continue + variable_count.append(Tuple(v, count)) + continue + + v = sympify(v) + if isinstance(v, Integer): + if i == 0: + raise ValueError("First variable cannot be a number: %i" % v) + count = v + prev, prevcount = variable_count[-1] + if prevcount != 1: + raise TypeError("tuple {} followed by number {}".format((prev, prevcount), v)) + if count == 0: + variable_count.pop() + else: + variable_count[-1] = Tuple(prev, count) + else: + count = 1 + variable_count.append(Tuple(v, count)) + + # light evaluation of contiguous, identical + # items: (x, 1), (x, 1) -> (x, 2) + merged = [] + for t in variable_count: + v, c = t + if c.is_negative: + raise ValueError( + 'order of differentiation must be nonnegative') + if merged and merged[-1][0] == v: + c += merged[-1][1] + if not c: + merged.pop() + else: + merged[-1] = Tuple(v, c) + else: + merged.append(t) + variable_count = merged + + # sanity check of variables of differentation; we waited + # until the counts were computed since some variables may + # have been removed because the count was 0 + for v, c in variable_count: + # v must have _diff_wrt True + if not v._diff_wrt: + __ = '' # filler to make error message neater + raise ValueError(filldedent(''' + Can't calculate derivative wrt %s.%s''' % (v, + __))) + + # We make a special case for 0th derivative, because there is no + # good way to unambiguously print this. + if len(variable_count) == 0: + return expr + + evaluate = kwargs.get('evaluate', False) + + if evaluate: + if isinstance(expr, Derivative): + expr = expr.canonical + variable_count = [ + (v.canonical if isinstance(v, Derivative) else v, c) + for v, c in variable_count] + + # Look for a quick exit if there are symbols that don't appear in + # expression at all. Note, this cannot check non-symbols like + # Derivatives as those can be created by intermediate + # derivatives. + zero = False + free = expr.free_symbols + from sympy.matrices.expressions.matexpr import MatrixExpr + + for v, c in variable_count: + vfree = v.free_symbols + if c.is_positive and vfree: + if isinstance(v, AppliedUndef): + # these match exactly since + # x.diff(f(x)) == g(x).diff(f(x)) == 0 + # and are not created by differentiation + D = Dummy() + if not expr.xreplace({v: D}).has(D): + zero = True + break + elif isinstance(v, MatrixExpr): + zero = False + break + elif isinstance(v, Symbol) and v not in free: + zero = True + break + else: + if not free & vfree: + # e.g. v is IndexedBase or Matrix + zero = True + break + if zero: + return cls._get_zero_with_shape_like(expr) + + # make the order of symbols canonical + #TODO: check if assumption of discontinuous derivatives exist + variable_count = cls._sort_variable_count(variable_count) + + # denest + if isinstance(expr, Derivative): + variable_count = list(expr.variable_count) + variable_count + expr = expr.expr + return _derivative_dispatch(expr, *variable_count, **kwargs) + + # we return here if evaluate is False or if there is no + # _eval_derivative method + if not evaluate or not hasattr(expr, '_eval_derivative'): + # return an unevaluated Derivative + if evaluate and variable_count == [(expr, 1)] and expr.is_scalar: + # special hack providing evaluation for classes + # that have defined is_scalar=True but have no + # _eval_derivative defined + return S.One + return Expr.__new__(cls, expr, *variable_count) + + # evaluate the derivative by calling _eval_derivative method + # of expr for each variable + # ------------------------------------------------------------- + nderivs = 0 # how many derivatives were performed + unhandled = [] + from sympy.matrices.matrixbase import MatrixBase + for i, (v, count) in enumerate(variable_count): + + old_expr = expr + old_v = None + + is_symbol = v.is_symbol or isinstance(v, + (Iterable, Tuple, MatrixBase, NDimArray)) + + if not is_symbol: + old_v = v + v = Dummy('xi') + expr = expr.xreplace({old_v: v}) + # Derivatives and UndefinedFunctions are independent + # of all others + clashing = not (isinstance(old_v, (Derivative, AppliedUndef))) + if v not in expr.free_symbols and not clashing: + return expr.diff(v) # expr's version of 0 + if not old_v.is_scalar and not hasattr( + old_v, '_eval_derivative'): + # special hack providing evaluation for classes + # that have defined is_scalar=True but have no + # _eval_derivative defined + expr *= old_v.diff(old_v) + + obj = cls._dispatch_eval_derivative_n_times(expr, v, count) + if obj is not None and obj.is_zero: + return obj + + nderivs += count + + if old_v is not None: + if obj is not None: + # remove the dummy that was used + obj = obj.subs(v, old_v) + # restore expr + expr = old_expr + + if obj is None: + # we've already checked for quick-exit conditions + # that give 0 so the remaining variables + # are contained in the expression but the expression + # did not compute a derivative so we stop taking + # derivatives + unhandled = variable_count[i:] + break + + expr = obj + + # what we have so far can be made canonical + expr = expr.replace( + lambda x: isinstance(x, Derivative), + lambda x: x.canonical) + + if unhandled: + if isinstance(expr, Derivative): + unhandled = list(expr.variable_count) + unhandled + expr = expr.expr + expr = Expr.__new__(cls, expr, *unhandled) + + if (nderivs > 1) == True and kwargs.get('simplify', True): + from .exprtools import factor_terms + from sympy.simplify.simplify import signsimp + expr = factor_terms(signsimp(expr)) + return expr + + @property + def canonical(cls): + return cls.func(cls.expr, + *Derivative._sort_variable_count(cls.variable_count)) + + @classmethod + def _sort_variable_count(cls, vc): + """ + Sort (variable, count) pairs into canonical order while + retaining order of variables that do not commute during + differentiation: + + * symbols and functions commute with each other + * derivatives commute with each other + * a derivative does not commute with anything it contains + * any other object is not allowed to commute if it has + free symbols in common with another object + + Examples + ======== + + >>> from sympy import Derivative, Function, symbols + >>> vsort = Derivative._sort_variable_count + >>> x, y, z = symbols('x y z') + >>> f, g, h = symbols('f g h', cls=Function) + + Contiguous items are collapsed into one pair: + + >>> vsort([(x, 1), (x, 1)]) + [(x, 2)] + >>> vsort([(y, 1), (f(x), 1), (y, 1), (f(x), 1)]) + [(y, 2), (f(x), 2)] + + Ordering is canonical. + + >>> def vsort0(*v): + ... # docstring helper to + ... # change vi -> (vi, 0), sort, and return vi vals + ... return [i[0] for i in vsort([(i, 0) for i in v])] + + >>> vsort0(y, x) + [x, y] + >>> vsort0(g(y), g(x), f(y)) + [f(y), g(x), g(y)] + + Symbols are sorted as far to the left as possible but never + move to the left of a derivative having the same symbol in + its variables; the same applies to AppliedUndef which are + always sorted after Symbols: + + >>> dfx = f(x).diff(x) + >>> assert vsort0(dfx, y) == [y, dfx] + >>> assert vsort0(dfx, x) == [dfx, x] + """ + if not vc: + return [] + vc = list(vc) + if len(vc) == 1: + return [Tuple(*vc[0])] + V = list(range(len(vc))) + E = [] + v = lambda i: vc[i][0] + D = Dummy() + def _block(d, v, wrt=False): + # return True if v should not come before d else False + if d == v: + return wrt + if d.is_Symbol: + return False + if isinstance(d, Derivative): + # a derivative blocks if any of it's variables contain + # v; the wrt flag will return True for an exact match + # and will cause an AppliedUndef to block if v is in + # the arguments + if any(_block(k, v, wrt=True) + for k in d._wrt_variables): + return True + return False + if not wrt and isinstance(d, AppliedUndef): + return False + if v.is_Symbol: + return v in d.free_symbols + if isinstance(v, AppliedUndef): + return _block(d.xreplace({v: D}), D) + return d.free_symbols & v.free_symbols + for i in range(len(vc)): + for j in range(i): + if _block(v(j), v(i)): + E.append((j,i)) + # this is the default ordering to use in case of ties + O = dict(zip(ordered(uniq([i for i, c in vc])), range(len(vc)))) + ix = topological_sort((V, E), key=lambda i: O[v(i)]) + # merge counts of contiguously identical items + merged = [] + for v, c in [vc[i] for i in ix]: + if merged and merged[-1][0] == v: + merged[-1][1] += c + else: + merged.append([v, c]) + return [Tuple(*i) for i in merged] + + def _eval_is_commutative(self): + return self.expr.is_commutative + + def _eval_derivative(self, v): + # If v (the variable of differentiation) is not in + # self.variables, we might be able to take the derivative. + if v not in self._wrt_variables: + dedv = self.expr.diff(v) + if isinstance(dedv, Derivative): + return dedv.func(dedv.expr, *(self.variable_count + dedv.variable_count)) + # dedv (d(self.expr)/dv) could have simplified things such that the + # derivative wrt things in self.variables can now be done. Thus, + # we set evaluate=True to see if there are any other derivatives + # that can be done. The most common case is when dedv is a simple + # number so that the derivative wrt anything else will vanish. + return self.func(dedv, *self.variables, evaluate=True) + # In this case v was in self.variables so the derivative wrt v has + # already been attempted and was not computed, either because it + # couldn't be or evaluate=False originally. + variable_count = list(self.variable_count) + variable_count.append((v, 1)) + return self.func(self.expr, *variable_count, evaluate=False) + + def doit(self, **hints): + expr = self.expr + if hints.get('deep', True): + expr = expr.doit(**hints) + hints['evaluate'] = True + rv = self.func(expr, *self.variable_count, **hints) + if rv!= self and rv.has(Derivative): + rv = rv.doit(**hints) + return rv + + @_sympifyit('z0', NotImplementedError) + def doit_numerically(self, z0): + """ + Evaluate the derivative at z numerically. + + When we can represent derivatives at a point, this should be folded + into the normal evalf. For now, we need a special method. + """ + if len(self.free_symbols) != 1 or len(self.variables) != 1: + raise NotImplementedError('partials and higher order derivatives') + z = list(self.free_symbols)[0] + + def eval(x): + f0 = self.expr.subs(z, Expr._from_mpmath(x, prec=mpmath.mp.prec)) + f0 = f0.evalf(prec_to_dps(mpmath.mp.prec)) + return f0._to_mpmath(mpmath.mp.prec) + return Expr._from_mpmath(mpmath.diff(eval, + z0._to_mpmath(mpmath.mp.prec)), + mpmath.mp.prec) + + @property + def expr(self): + return self._args[0] + + @property + def _wrt_variables(self): + # return the variables of differentiation without + # respect to the type of count (int or symbolic) + return [i[0] for i in self.variable_count] + + @property + def variables(self): + # TODO: deprecate? YES, make this 'enumerated_variables' and + # name _wrt_variables as variables + # TODO: support for `d^n`? + rv = [] + for v, count in self.variable_count: + if not count.is_Integer: + raise TypeError(filldedent(''' + Cannot give expansion for symbolic count. If you just + want a list of all variables of differentiation, use + _wrt_variables.''')) + rv.extend([v]*count) + return tuple(rv) + + @property + def variable_count(self): + return self._args[1:] + + @property + def derivative_count(self): + return sum([count for _, count in self.variable_count], 0) + + @property + def free_symbols(self): + ret = self.expr.free_symbols + # Add symbolic counts to free_symbols + for _, count in self.variable_count: + ret.update(count.free_symbols) + return ret + + @property + def kind(self): + return self.args[0].kind + + def _eval_subs(self, old, new): + # The substitution (old, new) cannot be done inside + # Derivative(expr, vars) for a variety of reasons + # as handled below. + if old in self._wrt_variables: + # first handle the counts + expr = self.func(self.expr, *[(v, c.subs(old, new)) + for v, c in self.variable_count]) + if expr != self: + return expr._eval_subs(old, new) + # quick exit case + if not getattr(new, '_diff_wrt', False): + # case (0): new is not a valid variable of + # differentiation + if isinstance(old, Symbol): + # don't introduce a new symbol if the old will do + return Subs(self, old, new) + else: + xi = Dummy('xi') + return Subs(self.xreplace({old: xi}), xi, new) + + # If both are Derivatives with the same expr, check if old is + # equivalent to self or if old is a subderivative of self. + if old.is_Derivative and old.expr == self.expr: + if self.canonical == old.canonical: + return new + + # collections.Counter doesn't have __le__ + def _subset(a, b): + return all((a[i] <= b[i]) == True for i in a) + + old_vars = Counter(dict(reversed(old.variable_count))) + self_vars = Counter(dict(reversed(self.variable_count))) + if _subset(old_vars, self_vars): + return _derivative_dispatch(new, *(self_vars - old_vars).items()).canonical + + args = list(self.args) + newargs = [x._subs(old, new) for x in args] + if args[0] == old: + # complete replacement of self.expr + # we already checked that the new is valid so we know + # it won't be a problem should it appear in variables + return _derivative_dispatch(*newargs) + + if newargs[0] != args[0]: + # case (1) can't change expr by introducing something that is in + # the _wrt_variables if it was already in the expr + # e.g. + # for Derivative(f(x, g(y)), y), x cannot be replaced with + # anything that has y in it; for f(g(x), g(y)).diff(g(y)) + # g(x) cannot be replaced with anything that has g(y) + syms = {vi: Dummy() for vi in self._wrt_variables + if not vi.is_Symbol} + wrt = {syms.get(vi, vi) for vi in self._wrt_variables} + forbidden = args[0].xreplace(syms).free_symbols & wrt + nfree = new.xreplace(syms).free_symbols + ofree = old.xreplace(syms).free_symbols + if (nfree - ofree) & forbidden: + return Subs(self, old, new) + + viter = ((i, j) for ((i, _), (j, _)) in zip(newargs[1:], args[1:])) + if any(i != j for i, j in viter): # a wrt-variable change + # case (2) can't change vars by introducing a variable + # that is contained in expr, e.g. + # for Derivative(f(z, g(h(x), y)), y), y cannot be changed to + # x, h(x), or g(h(x), y) + for a in _atomic(self.expr, recursive=True): + for i in range(1, len(newargs)): + vi, _ = newargs[i] + if a == vi and vi != args[i][0]: + return Subs(self, old, new) + # more arg-wise checks + vc = newargs[1:] + oldv = self._wrt_variables + newe = self.expr + subs = [] + for i, (vi, ci) in enumerate(vc): + if not vi._diff_wrt: + # case (3) invalid differentiation expression so + # create a replacement dummy + xi = Dummy('xi_%i' % i) + # replace the old valid variable with the dummy + # in the expression + newe = newe.xreplace({oldv[i]: xi}) + # and replace the bad variable with the dummy + vc[i] = (xi, ci) + # and record the dummy with the new (invalid) + # differentiation expression + subs.append((xi, vi)) + + if subs: + # handle any residual substitution in the expression + newe = newe._subs(old, new) + # return the Subs-wrapped derivative + return Subs(Derivative(newe, *vc), *zip(*subs)) + + # everything was ok + return _derivative_dispatch(*newargs) + + def _eval_lseries(self, x, logx, cdir=0): + dx = self.variables + for term in self.expr.lseries(x, logx=logx, cdir=cdir): + yield self.func(term, *dx) + + def _eval_nseries(self, x, n, logx, cdir=0): + arg = self.expr.nseries(x, n=n, logx=logx) + o = arg.getO() + dx = self.variables + rv = [self.func(a, *dx) for a in Add.make_args(arg.removeO())] + if o: + rv.append(o/x) + return Add(*rv) + + def _eval_as_leading_term(self, x, logx, cdir): + series_gen = self.expr.lseries(x) + d = S.Zero + for leading_term in series_gen: + d = diff(leading_term, *self.variables) + if d != 0: + break + return d + + def as_finite_difference(self, points=1, x0=None, wrt=None): + """ Expresses a Derivative instance as a finite difference. + + Parameters + ========== + + points : sequence or coefficient, optional + If sequence: discrete values (length >= order+1) of the + independent variable used for generating the finite + difference weights. + If it is a coefficient, it will be used as the step-size + for generating an equidistant sequence of length order+1 + centered around ``x0``. Default: 1 (step-size 1) + + x0 : number or Symbol, optional + the value of the independent variable (``wrt``) at which the + derivative is to be approximated. Default: same as ``wrt``. + + wrt : Symbol, optional + "with respect to" the variable for which the (partial) + derivative is to be approximated for. If not provided it + is required that the derivative is ordinary. Default: ``None``. + + + Examples + ======== + + >>> from sympy import symbols, Function, exp, sqrt, Symbol + >>> x, h = symbols('x h') + >>> f = Function('f') + >>> f(x).diff(x).as_finite_difference() + -f(x - 1/2) + f(x + 1/2) + + The default step size and number of points are 1 and + ``order + 1`` respectively. We can change the step size by + passing a symbol as a parameter: + + >>> f(x).diff(x).as_finite_difference(h) + -f(-h/2 + x)/h + f(h/2 + x)/h + + We can also specify the discretized values to be used in a + sequence: + + >>> f(x).diff(x).as_finite_difference([x, x+h, x+2*h]) + -3*f(x)/(2*h) + 2*f(h + x)/h - f(2*h + x)/(2*h) + + The algorithm is not restricted to use equidistant spacing, nor + do we need to make the approximation around ``x0``, but we can get + an expression estimating the derivative at an offset: + + >>> e, sq2 = exp(1), sqrt(2) + >>> xl = [x-h, x+h, x+e*h] + >>> f(x).diff(x, 1).as_finite_difference(xl, x+h*sq2) # doctest: +ELLIPSIS + 2*h*((h + sqrt(2)*h)/(2*h) - (-sqrt(2)*h + h)/(2*h))*f(E*h + x)/... + + To approximate ``Derivative`` around ``x0`` using a non-equidistant + spacing step, the algorithm supports assignment of undefined + functions to ``points``: + + >>> dx = Function('dx') + >>> f(x).diff(x).as_finite_difference(points=dx(x), x0=x-h) + -f(-h + x - dx(-h + x)/2)/dx(-h + x) + f(-h + x + dx(-h + x)/2)/dx(-h + x) + + Partial derivatives are also supported: + + >>> y = Symbol('y') + >>> d2fdxdy=f(x,y).diff(x,y) + >>> d2fdxdy.as_finite_difference(wrt=x) + -Derivative(f(x - 1/2, y), y) + Derivative(f(x + 1/2, y), y) + + We can apply ``as_finite_difference`` to ``Derivative`` instances in + compound expressions using ``replace``: + + >>> (1 + 42**f(x).diff(x)).replace(lambda arg: arg.is_Derivative, + ... lambda arg: arg.as_finite_difference()) + 42**(-f(x - 1/2) + f(x + 1/2)) + 1 + + + See also + ======== + + sympy.calculus.finite_diff.apply_finite_diff + sympy.calculus.finite_diff.differentiate_finite + sympy.calculus.finite_diff.finite_diff_weights + + """ + from sympy.calculus.finite_diff import _as_finite_diff + return _as_finite_diff(self, points, x0, wrt) + + @classmethod + def _get_zero_with_shape_like(cls, expr): + return S.Zero + + @classmethod + def _dispatch_eval_derivative_n_times(cls, expr, v, count): + # Evaluate the derivative `n` times. If + # `_eval_derivative_n_times` is not overridden by the current + # object, the default in `Basic` will call a loop over + # `_eval_derivative`: + return expr._eval_derivative_n_times(v, count) + + +def _derivative_dispatch(expr, *variables, **kwargs): + from sympy.matrices.matrixbase import MatrixBase + from sympy.matrices.expressions.matexpr import MatrixExpr + from sympy.tensor.array import NDimArray + array_types = (MatrixBase, MatrixExpr, NDimArray, list, tuple, Tuple) + if isinstance(expr, array_types) or any(isinstance(i[0], array_types) if isinstance(i, (tuple, list, Tuple)) else isinstance(i, array_types) for i in variables): + from sympy.tensor.array.array_derivatives import ArrayDerivative + return ArrayDerivative(expr, *variables, **kwargs) + return Derivative(expr, *variables, **kwargs) + + +class Lambda(Expr): + """ + Lambda(x, expr) represents a lambda function similar to Python's + 'lambda x: expr'. A function of several variables is written as + Lambda((x, y, ...), expr). + + Examples + ======== + + A simple example: + + >>> from sympy import Lambda + >>> from sympy.abc import x + >>> f = Lambda(x, x**2) + >>> f(4) + 16 + + For multivariate functions, use: + + >>> from sympy.abc import y, z, t + >>> f2 = Lambda((x, y, z, t), x + y**z + t**z) + >>> f2(1, 2, 3, 4) + 73 + + It is also possible to unpack tuple arguments: + + >>> f = Lambda(((x, y), z), x + y + z) + >>> f((1, 2), 3) + 6 + + A handy shortcut for lots of arguments: + + >>> p = x, y, z + >>> f = Lambda(p, x + y*z) + >>> f(*p) + x + y*z + + """ + is_Function = True + + def __new__(cls, signature, expr) -> Lambda: + if iterable(signature) and not isinstance(signature, (tuple, Tuple)): + sympy_deprecation_warning( + """ + Using a non-tuple iterable as the first argument to Lambda + is deprecated. Use Lambda(tuple(args), expr) instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-non-tuple-lambda", + ) + signature = tuple(signature) + _sig = signature if iterable(signature) else (signature,) + sig: Tuple = sympify(_sig) # type: ignore + cls._check_signature(sig) + + if len(sig) == 1 and sig[0] == expr: + return S.IdentityFunction + + return Expr.__new__(cls, sig, sympify(expr)) + + @classmethod + def _check_signature(cls, sig): + syms = set() + + def rcheck(args): + for a in args: + if a.is_symbol: + if a in syms: + raise BadSignatureError("Duplicate symbol %s" % a) + syms.add(a) + elif isinstance(a, Tuple): + rcheck(a) + else: + raise BadSignatureError("Lambda signature should be only tuples" + " and symbols, not %s" % a) + + if not isinstance(sig, Tuple): + raise BadSignatureError("Lambda signature should be a tuple not %s" % sig) + # Recurse through the signature: + rcheck(sig) + + @property + def signature(self): + """The expected form of the arguments to be unpacked into variables""" + return self._args[0] + + @property + def expr(self): + """The return value of the function""" + return self._args[1] + + @property + def variables(self): + """The variables used in the internal representation of the function""" + def _variables(args): + if isinstance(args, Tuple): + for arg in args: + yield from _variables(arg) + else: + yield args + return tuple(_variables(self.signature)) + + @property + def nargs(self): + from sympy.sets.sets import FiniteSet + return FiniteSet(len(self.signature)) + + bound_symbols = variables + + @property + def free_symbols(self): + return self.expr.free_symbols - set(self.variables) + + def __call__(self, *args): + n = len(args) + if n not in self.nargs: # Lambda only ever has 1 value in nargs + # XXX: exception message must be in exactly this format to + # make it work with NumPy's functions like vectorize(). See, + # for example, https://github.com/numpy/numpy/issues/1697. + # The ideal solution would be just to attach metadata to + # the exception and change NumPy to take advantage of this. + ## XXX does this apply to Lambda? If not, remove this comment. + temp = ('%(name)s takes exactly %(args)s ' + 'argument%(plural)s (%(given)s given)') + raise BadArgumentsError(temp % { + 'name': self, + 'args': list(self.nargs)[0], + 'plural': 's'*(list(self.nargs)[0] != 1), + 'given': n}) + + d = self._match_signature(self.signature, args) + + return self.expr.xreplace(d) + + def _match_signature(self, sig, args): + + symargmap = {} + + def rmatch(pars, args): + for par, arg in zip(pars, args): + if par.is_symbol: + symargmap[par] = arg + elif isinstance(par, Tuple): + if not isinstance(arg, (tuple, Tuple)) or len(args) != len(pars): + raise BadArgumentsError("Can't match %s and %s" % (args, pars)) + rmatch(par, arg) + + rmatch(sig, args) + + return symargmap + + @property + def is_identity(self): + """Return ``True`` if this ``Lambda`` is an identity function. """ + return self.signature == self.expr + + def _eval_evalf(self, prec): + return self.func(self.args[0], self.args[1].evalf(n=prec_to_dps(prec))) + + +class Subs(Expr): + """ + Represents unevaluated substitutions of an expression. + + ``Subs(expr, x, x0)`` represents the expression resulting + from substituting x with x0 in expr. + + Parameters + ========== + + expr : Expr + An expression. + + x : tuple, variable + A variable or list of distinct variables. + + x0 : tuple or list of tuples + A point or list of evaluation points + corresponding to those variables. + + Examples + ======== + + >>> from sympy import Subs, Function, sin, cos + >>> from sympy.abc import x, y, z + >>> f = Function('f') + + Subs are created when a particular substitution cannot be made. The + x in the derivative cannot be replaced with 0 because 0 is not a + valid variables of differentiation: + + >>> f(x).diff(x).subs(x, 0) + Subs(Derivative(f(x), x), x, 0) + + Once f is known, the derivative and evaluation at 0 can be done: + + >>> _.subs(f, sin).doit() == sin(x).diff(x).subs(x, 0) == cos(0) + True + + Subs can also be created directly with one or more variables: + + >>> Subs(f(x)*sin(y) + z, (x, y), (0, 1)) + Subs(z + f(x)*sin(y), (x, y), (0, 1)) + >>> _.doit() + z + f(0)*sin(1) + + Notes + ===== + + ``Subs`` objects are generally useful to represent unevaluated derivatives + calculated at a point. + + The variables may be expressions, but they are subjected to the limitations + of subs(), so it is usually a good practice to use only symbols for + variables, since in that case there can be no ambiguity. + + There's no automatic expansion - use the method .doit() to effect all + possible substitutions of the object and also of objects inside the + expression. + + When evaluating derivatives at a point that is not a symbol, a Subs object + is returned. One is also able to calculate derivatives of Subs objects - in + this case the expression is always expanded (for the unevaluated form, use + Derivative()). + + In order to allow expressions to combine before doit is done, a + representation of the Subs expression is used internally to make + expressions that are superficially different compare the same: + + >>> a, b = Subs(x, x, 0), Subs(y, y, 0) + >>> a + b + 2*Subs(x, x, 0) + + This can lead to unexpected consequences when using methods + like `has` that are cached: + + >>> s = Subs(x, x, 0) + >>> s.has(x), s.has(y) + (True, False) + >>> ss = s.subs(x, y) + >>> ss.has(x), ss.has(y) + (True, False) + >>> s, ss + (Subs(x, x, 0), Subs(y, y, 0)) + """ + def __new__(cls, expr, variables, point, **assumptions): + if not is_sequence(variables, Tuple): + variables = [variables] + variables = Tuple(*variables) + + if has_dups(variables): + repeated = [str(v) for v, i in Counter(variables).items() if i > 1] + __ = ', '.join(repeated) + raise ValueError(filldedent(''' + The following expressions appear more than once: %s + ''' % __)) + + point = Tuple(*(point if is_sequence(point, Tuple) else [point])) + + if len(point) != len(variables): + raise ValueError('Number of point values must be the same as ' + 'the number of variables.') + + if not point: + return sympify(expr) + + # denest + if isinstance(expr, Subs): + variables = expr.variables + variables + point = expr.point + point + expr = expr.expr + else: + expr = sympify(expr) + + # use symbols with names equal to the point value (with prepended _) + # to give a variable-independent expression + pre = "_" + pts = sorted(set(point), key=default_sort_key) + from sympy.printing.str import StrPrinter + class CustomStrPrinter(StrPrinter): + def _print_Dummy(self, expr): + return str(expr) + str(expr.dummy_index) + def mystr(expr, **settings): + p = CustomStrPrinter(settings) + return p.doprint(expr) + while 1: + s_pts = {p: Symbol(pre + mystr(p)) for p in pts} + reps = [(v, s_pts[p]) + for v, p in zip(variables, point)] + # if any underscore-prepended symbol is already a free symbol + # and is a variable with a different point value, then there + # is a clash, e.g. _0 clashes in Subs(_0 + _1, (_0, _1), (1, 0)) + # because the new symbol that would be created is _1 but _1 + # is already mapped to 0 so __0 and __1 are used for the new + # symbols + if any(r in expr.free_symbols and + r in variables and + Symbol(pre + mystr(point[variables.index(r)])) != r + for _, r in reps): + pre += "_" + continue + break + + obj = Expr.__new__(cls, expr, Tuple(*variables), point) + obj._expr = expr.xreplace(dict(reps)) + return obj + + def _eval_is_commutative(self): + return self.expr.is_commutative + + def doit(self, **hints): + e, v, p = self.args + + # remove self mappings + for i, (vi, pi) in enumerate(zip(v, p)): + if vi == pi: + v = v[:i] + v[i + 1:] + p = p[:i] + p[i + 1:] + if not v: + return self.expr + + if isinstance(e, Derivative): + # apply functions first, e.g. f -> cos + undone = [] + for i, vi in enumerate(v): + if isinstance(vi, FunctionClass): + e = e.subs(vi, p[i]) + else: + undone.append((vi, p[i])) + if not isinstance(e, Derivative): + e = e.doit() + if isinstance(e, Derivative): + # do Subs that aren't related to differentiation + undone2 = [] + D = Dummy() + arg = e.args[0] + for vi, pi in undone: + if D not in e.xreplace({vi: D}).free_symbols: + if arg.has(vi): + e = e.subs(vi, pi) + else: + undone2.append((vi, pi)) + undone = undone2 + # differentiate wrt variables that are present + wrt = [] + D = Dummy() + expr = e.expr + free = expr.free_symbols + for vi, ci in e.variable_count: + if isinstance(vi, Symbol) and vi in free: + expr = expr.diff((vi, ci)) + elif D in expr.subs(vi, D).free_symbols: + expr = expr.diff((vi, ci)) + else: + wrt.append((vi, ci)) + # inject remaining subs + rv = expr.subs(undone) + # do remaining differentiation *in order given* + for vc in wrt: + rv = rv.diff(vc) + else: + # inject remaining subs + rv = e.subs(undone) + else: + rv = e.doit(**hints).subs(list(zip(v, p))) + + if hints.get('deep', True) and rv != self: + rv = rv.doit(**hints) + return rv + + def evalf(self, prec=None, **options): + return self.doit().evalf(prec, **options) + + n = evalf # type:ignore + + @property + def variables(self): + """The variables to be evaluated""" + return self._args[1] + + bound_symbols = variables + + @property + def expr(self): + """The expression on which the substitution operates""" + return self._args[0] + + @property + def point(self): + """The values for which the variables are to be substituted""" + return self._args[2] + + @property + def free_symbols(self): + return (self.expr.free_symbols - set(self.variables) | + set(self.point.free_symbols)) + + @property + def expr_free_symbols(self): + sympy_deprecation_warning(""" + The expr_free_symbols property is deprecated. Use free_symbols to get + the free symbols of an expression. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-expr-free-symbols") + # Don't show the warning twice from the recursive call + with ignore_warnings(SymPyDeprecationWarning): + return (self.expr.expr_free_symbols - set(self.variables) | + set(self.point.expr_free_symbols)) + + def __eq__(self, other): + if not isinstance(other, Subs): + return False + return self._hashable_content() == other._hashable_content() + + def __ne__(self, other): + return not(self == other) + + def __hash__(self): + return super().__hash__() + + def _hashable_content(self): + return (self._expr.xreplace(self.canonical_variables), + ) + tuple(ordered([(v, p) for v, p in + zip(self.variables, self.point) if not self.expr.has(v)])) + + def _eval_subs(self, old, new): + # Subs doit will do the variables in order; the semantics + # of subs for Subs is have the following invariant for + # Subs object foo: + # foo.doit().subs(reps) == foo.subs(reps).doit() + pt = list(self.point) + if old in self.variables: + if _atomic(new) == {new} and not any( + i.has(new) for i in self.args): + # the substitution is neutral + return self.xreplace({old: new}) + # any occurrence of old before this point will get + # handled by replacements from here on + i = self.variables.index(old) + for j in range(i, len(self.variables)): + pt[j] = pt[j]._subs(old, new) + return self.func(self.expr, self.variables, pt) + v = [i._subs(old, new) for i in self.variables] + if v != list(self.variables): + return self.func(self.expr, self.variables + (old,), pt + [new]) + expr = self.expr._subs(old, new) + pt = [i._subs(old, new) for i in self.point] + return self.func(expr, v, pt) + + def _eval_derivative(self, s): + # Apply the chain rule of the derivative on the substitution variables: + f = self.expr + vp = V, P = self.variables, self.point + val = Add.fromiter(p.diff(s)*Subs(f.diff(v), *vp).doit() + for v, p in zip(V, P)) + + # these are all the free symbols in the expr + efree = f.free_symbols + # some symbols like IndexedBase include themselves and args + # as free symbols + compound = {i for i in efree if len(i.free_symbols) > 1} + # hide them and see what independent free symbols remain + dums = {Dummy() for i in compound} + masked = f.xreplace(dict(zip(compound, dums))) + ifree = masked.free_symbols - dums + # include the compound symbols + free = ifree | compound + # remove the variables already handled + free -= set(V) + # add back any free symbols of remaining compound symbols + free |= {i for j in free & compound for i in j.free_symbols} + # if symbols of s are in free then there is more to do + if free & s.free_symbols: + val += Subs(f.diff(s), self.variables, self.point).doit() + return val + + def _eval_nseries(self, x, n, logx, cdir=0): + if x in self.point: + # x is the variable being substituted into + apos = self.point.index(x) + other = self.variables[apos] + else: + other = x + arg = self.expr.nseries(other, n=n, logx=logx) + o = arg.getO() + terms = Add.make_args(arg.removeO()) + rv = Add(*[self.func(a, *self.args[1:]) for a in terms]) + if o: + rv += o.subs(other, x) + return rv + + def _eval_as_leading_term(self, x, logx, cdir): + if x in self.point: + ipos = self.point.index(x) + xvar = self.variables[ipos] + return self.expr.as_leading_term(xvar) + if x in self.variables: + # if `x` is a dummy variable, it means it won't exist after the + # substitution has been performed: + return self + # The variable is independent of the substitution: + return self.expr.as_leading_term(x) + + +def diff(f, *symbols, **kwargs): + """ + Differentiate f with respect to symbols. + + Explanation + =========== + + This is just a wrapper to unify .diff() and the Derivative class; its + interface is similar to that of integrate(). You can use the same + shortcuts for multiple variables as with Derivative. For example, + diff(f(x), x, x, x) and diff(f(x), x, 3) both return the third derivative + of f(x). + + You can pass evaluate=False to get an unevaluated Derivative class. Note + that if there are 0 symbols (such as diff(f(x), x, 0), then the result will + be the function (the zeroth derivative), even if evaluate=False. + + Examples + ======== + + >>> from sympy import sin, cos, Function, diff + >>> from sympy.abc import x, y + >>> f = Function('f') + + >>> diff(sin(x), x) + cos(x) + >>> diff(f(x), x, x, x) + Derivative(f(x), (x, 3)) + >>> diff(f(x), x, 3) + Derivative(f(x), (x, 3)) + >>> diff(sin(x)*cos(y), x, 2, y, 2) + sin(x)*cos(y) + + >>> type(diff(sin(x), x)) + cos + >>> type(diff(sin(x), x, evaluate=False)) + + >>> type(diff(sin(x), x, 0)) + sin + >>> type(diff(sin(x), x, 0, evaluate=False)) + sin + + >>> diff(sin(x)) + cos(x) + >>> diff(sin(x*y)) + Traceback (most recent call last): + ... + ValueError: specify differentiation variables to differentiate sin(x*y) + + Note that ``diff(sin(x))`` syntax is meant only for convenience + in interactive sessions and should be avoided in library code. + + References + ========== + + .. [1] https://reference.wolfram.com/legacy/v5_2/Built-inFunctions/AlgebraicComputation/Calculus/D.html + + See Also + ======== + + Derivative + idiff: computes the derivative implicitly + + """ + if hasattr(f, 'diff'): + return f.diff(*symbols, **kwargs) + kwargs.setdefault('evaluate', True) + return _derivative_dispatch(f, *symbols, **kwargs) + + +def expand(e, deep=True, modulus=None, power_base=True, power_exp=True, + mul=True, log=True, multinomial=True, basic=True, **hints): + r""" + Expand an expression using methods given as hints. + + Explanation + =========== + + Hints evaluated unless explicitly set to False are: ``basic``, ``log``, + ``multinomial``, ``mul``, ``power_base``, and ``power_exp`` The following + hints are supported but not applied unless set to True: ``complex``, + ``func``, and ``trig``. In addition, the following meta-hints are + supported by some or all of the other hints: ``frac``, ``numer``, + ``denom``, ``modulus``, and ``force``. ``deep`` is supported by all + hints. Additionally, subclasses of Expr may define their own hints or + meta-hints. + + The ``basic`` hint is used for any special rewriting of an object that + should be done automatically (along with the other hints like ``mul``) + when expand is called. This is a catch-all hint to handle any sort of + expansion that may not be described by the existing hint names. To use + this hint an object should override the ``_eval_expand_basic`` method. + Objects may also define their own expand methods, which are not run by + default. See the API section below. + + If ``deep`` is set to ``True`` (the default), things like arguments of + functions are recursively expanded. Use ``deep=False`` to only expand on + the top level. + + If the ``force`` hint is used, assumptions about variables will be ignored + in making the expansion. + + Hints + ===== + + These hints are run by default + + mul + --- + + Distributes multiplication over addition: + + >>> from sympy import cos, exp, sin + >>> from sympy.abc import x, y, z + >>> (y*(x + z)).expand(mul=True) + x*y + y*z + + multinomial + ----------- + + Expand (x + y + ...)**n where n is a positive integer. + + >>> ((x + y + z)**2).expand(multinomial=True) + x**2 + 2*x*y + 2*x*z + y**2 + 2*y*z + z**2 + + power_exp + --------- + + Expand addition in exponents into multiplied bases. + + >>> exp(x + y).expand(power_exp=True) + exp(x)*exp(y) + >>> (2**(x + y)).expand(power_exp=True) + 2**x*2**y + + power_base + ---------- + + Split powers of multiplied bases. + + This only happens by default if assumptions allow, or if the + ``force`` meta-hint is used: + + >>> ((x*y)**z).expand(power_base=True) + (x*y)**z + >>> ((x*y)**z).expand(power_base=True, force=True) + x**z*y**z + >>> ((2*y)**z).expand(power_base=True) + 2**z*y**z + + Note that in some cases where this expansion always holds, SymPy performs + it automatically: + + >>> (x*y)**2 + x**2*y**2 + + log + --- + + Pull out power of an argument as a coefficient and split logs products + into sums of logs. + + Note that these only work if the arguments of the log function have the + proper assumptions--the arguments must be positive and the exponents must + be real--or else the ``force`` hint must be True: + + >>> from sympy import log, symbols + >>> log(x**2*y).expand(log=True) + log(x**2*y) + >>> log(x**2*y).expand(log=True, force=True) + 2*log(x) + log(y) + >>> x, y = symbols('x,y', positive=True) + >>> log(x**2*y).expand(log=True) + 2*log(x) + log(y) + + basic + ----- + + This hint is intended primarily as a way for custom subclasses to enable + expansion by default. + + These hints are not run by default: + + complex + ------- + + Split an expression into real and imaginary parts. + + >>> x, y = symbols('x,y') + >>> (x + y).expand(complex=True) + re(x) + re(y) + I*im(x) + I*im(y) + >>> cos(x).expand(complex=True) + -I*sin(re(x))*sinh(im(x)) + cos(re(x))*cosh(im(x)) + + Note that this is just a wrapper around ``as_real_imag()``. Most objects + that wish to redefine ``_eval_expand_complex()`` should consider + redefining ``as_real_imag()`` instead. + + func + ---- + + Expand other functions. + + >>> from sympy import gamma + >>> gamma(x + 1).expand(func=True) + x*gamma(x) + + trig + ---- + + Do trigonometric expansions. + + >>> cos(x + y).expand(trig=True) + -sin(x)*sin(y) + cos(x)*cos(y) + >>> sin(2*x).expand(trig=True) + 2*sin(x)*cos(x) + + Note that the forms of ``sin(n*x)`` and ``cos(n*x)`` in terms of ``sin(x)`` + and ``cos(x)`` are not unique, due to the identity `\sin^2(x) + \cos^2(x) + = 1`. The current implementation uses the form obtained from Chebyshev + polynomials, but this may change. See `this MathWorld article + `_ for more + information. + + Notes + ===== + + - You can shut off unwanted methods:: + + >>> (exp(x + y)*(x + y)).expand() + x*exp(x)*exp(y) + y*exp(x)*exp(y) + >>> (exp(x + y)*(x + y)).expand(power_exp=False) + x*exp(x + y) + y*exp(x + y) + >>> (exp(x + y)*(x + y)).expand(mul=False) + (x + y)*exp(x)*exp(y) + + - Use deep=False to only expand on the top level:: + + >>> exp(x + exp(x + y)).expand() + exp(x)*exp(exp(x)*exp(y)) + >>> exp(x + exp(x + y)).expand(deep=False) + exp(x)*exp(exp(x + y)) + + - Hints are applied in an arbitrary, but consistent order (in the current + implementation, they are applied in alphabetical order, except + multinomial comes before mul, but this may change). Because of this, + some hints may prevent expansion by other hints if they are applied + first. For example, ``mul`` may distribute multiplications and prevent + ``log`` and ``power_base`` from expanding them. Also, if ``mul`` is + applied before ``multinomial`, the expression might not be fully + distributed. The solution is to use the various ``expand_hint`` helper + functions or to use ``hint=False`` to this function to finely control + which hints are applied. Here are some examples:: + + >>> from sympy import expand, expand_mul, expand_power_base + >>> x, y, z = symbols('x,y,z', positive=True) + + >>> expand(log(x*(y + z))) + log(x) + log(y + z) + + Here, we see that ``log`` was applied before ``mul``. To get the mul + expanded form, either of the following will work:: + + >>> expand_mul(log(x*(y + z))) + log(x*y + x*z) + >>> expand(log(x*(y + z)), log=False) + log(x*y + x*z) + + A similar thing can happen with the ``power_base`` hint:: + + >>> expand((x*(y + z))**x) + (x*y + x*z)**x + + To get the ``power_base`` expanded form, either of the following will + work:: + + >>> expand((x*(y + z))**x, mul=False) + x**x*(y + z)**x + >>> expand_power_base((x*(y + z))**x) + x**x*(y + z)**x + + >>> expand((x + y)*y/x) + y + y**2/x + + The parts of a rational expression can be targeted:: + + >>> expand((x + y)*y/x/(x + 1), frac=True) + (x*y + y**2)/(x**2 + x) + >>> expand((x + y)*y/x/(x + 1), numer=True) + (x*y + y**2)/(x*(x + 1)) + >>> expand((x + y)*y/x/(x + 1), denom=True) + y*(x + y)/(x**2 + x) + + - The ``modulus`` meta-hint can be used to reduce the coefficients of an + expression post-expansion:: + + >>> expand((3*x + 1)**2) + 9*x**2 + 6*x + 1 + >>> expand((3*x + 1)**2, modulus=5) + 4*x**2 + x + 1 + + - Either ``expand()`` the function or ``.expand()`` the method can be + used. Both are equivalent:: + + >>> expand((x + 1)**2) + x**2 + 2*x + 1 + >>> ((x + 1)**2).expand() + x**2 + 2*x + 1 + + API + === + + Objects can define their own expand hints by defining + ``_eval_expand_hint()``. The function should take the form:: + + def _eval_expand_hint(self, **hints): + # Only apply the method to the top-level expression + ... + + See also the example below. Objects should define ``_eval_expand_hint()`` + methods only if ``hint`` applies to that specific object. The generic + ``_eval_expand_hint()`` method defined in Expr will handle the no-op case. + + Each hint should be responsible for expanding that hint only. + Furthermore, the expansion should be applied to the top-level expression + only. ``expand()`` takes care of the recursion that happens when + ``deep=True``. + + You should only call ``_eval_expand_hint()`` methods directly if you are + 100% sure that the object has the method, as otherwise you are liable to + get unexpected ``AttributeError``s. Note, again, that you do not need to + recursively apply the hint to args of your object: this is handled + automatically by ``expand()``. ``_eval_expand_hint()`` should + generally not be used at all outside of an ``_eval_expand_hint()`` method. + If you want to apply a specific expansion from within another method, use + the public ``expand()`` function, method, or ``expand_hint()`` functions. + + In order for expand to work, objects must be rebuildable by their args, + i.e., ``obj.func(*obj.args) == obj`` must hold. + + Expand methods are passed ``**hints`` so that expand hints may use + 'metahints'--hints that control how different expand methods are applied. + For example, the ``force=True`` hint described above that causes + ``expand(log=True)`` to ignore assumptions is such a metahint. The + ``deep`` meta-hint is handled exclusively by ``expand()`` and is not + passed to ``_eval_expand_hint()`` methods. + + Note that expansion hints should generally be methods that perform some + kind of 'expansion'. For hints that simply rewrite an expression, use the + .rewrite() API. + + Examples + ======== + + >>> from sympy import Expr, sympify + >>> class MyClass(Expr): + ... def __new__(cls, *args): + ... args = sympify(args) + ... return Expr.__new__(cls, *args) + ... + ... def _eval_expand_double(self, *, force=False, **hints): + ... ''' + ... Doubles the args of MyClass. + ... + ... If there more than four args, doubling is not performed, + ... unless force=True is also used (False by default). + ... ''' + ... if not force and len(self.args) > 4: + ... return self + ... return self.func(*(self.args + self.args)) + ... + >>> a = MyClass(1, 2, MyClass(3, 4)) + >>> a + MyClass(1, 2, MyClass(3, 4)) + >>> a.expand(double=True) + MyClass(1, 2, MyClass(3, 4, 3, 4), 1, 2, MyClass(3, 4, 3, 4)) + >>> a.expand(double=True, deep=False) + MyClass(1, 2, MyClass(3, 4), 1, 2, MyClass(3, 4)) + + >>> b = MyClass(1, 2, 3, 4, 5) + >>> b.expand(double=True) + MyClass(1, 2, 3, 4, 5) + >>> b.expand(double=True, force=True) + MyClass(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) + + See Also + ======== + + expand_log, expand_mul, expand_multinomial, expand_complex, expand_trig, + expand_power_base, expand_power_exp, expand_func, sympy.simplify.hyperexpand.hyperexpand + + """ + # don't modify this; modify the Expr.expand method + hints['power_base'] = power_base + hints['power_exp'] = power_exp + hints['mul'] = mul + hints['log'] = log + hints['multinomial'] = multinomial + hints['basic'] = basic + return sympify(e).expand(deep=deep, modulus=modulus, **hints) + +# This is a special application of two hints + +def _mexpand(expr, recursive=False): + # expand multinomials and then expand products; this may not always + # be sufficient to give a fully expanded expression (see + # test_issue_8247_8354 in test_arit) + if expr is None: + return + was = None + while was != expr: + was, expr = expr, expand_mul(expand_multinomial(expr)) + if not recursive: + break + return expr + + +# These are simple wrappers around single hints. + + +def expand_mul(expr, deep=True): + """ + Wrapper around expand that only uses the mul hint. See the expand + docstring for more information. + + Examples + ======== + + >>> from sympy import symbols, expand_mul, exp, log + >>> x, y = symbols('x,y', positive=True) + >>> expand_mul(exp(x+y)*(x+y)*log(x*y**2)) + x*exp(x + y)*log(x*y**2) + y*exp(x + y)*log(x*y**2) + + """ + return sympify(expr).expand(deep=deep, mul=True, power_exp=False, + power_base=False, basic=False, multinomial=False, log=False) + + +def expand_multinomial(expr, deep=True): + """ + Wrapper around expand that only uses the multinomial hint. See the expand + docstring for more information. + + Examples + ======== + + >>> from sympy import symbols, expand_multinomial, exp + >>> x, y = symbols('x y', positive=True) + >>> expand_multinomial((x + exp(x + 1))**2) + x**2 + 2*x*exp(x + 1) + exp(2*x + 2) + + """ + return sympify(expr).expand(deep=deep, mul=False, power_exp=False, + power_base=False, basic=False, multinomial=True, log=False) + + +def expand_log(expr, deep=True, force=False, factor=False): + """ + Wrapper around expand that only uses the log hint. See the expand + docstring for more information. + + Examples + ======== + + >>> from sympy import symbols, expand_log, exp, log + >>> x, y = symbols('x,y', positive=True) + >>> expand_log(exp(x+y)*(x+y)*log(x*y**2)) + (x + y)*(log(x) + 2*log(y))*exp(x + y) + + """ + from sympy.functions.elementary.exponential import log + from sympy.simplify.radsimp import fraction + if factor is False: + def _handleMul(x): + # look for the simple case of expanded log(b**a)/log(b) -> a in args + n, d = fraction(x) + n = [i for i in n.atoms(log) if i.args[0].is_Integer] + d = [i for i in d.atoms(log) if i.args[0].is_Integer] + if len(n) == 1 and len(d) == 1: + n = n[0] + d = d[0] + from sympy import multiplicity + m = multiplicity(d.args[0], n.args[0]) + if m: + r = m + log(n.args[0]//d.args[0]**m)/d + x = x.subs(n, d*r) + x1 = expand_mul(expand_log(x, deep=deep, force=force, factor=True)) + if x1.count(log) <= x.count(log): + return x1 + return x + + expr = expr.replace( + lambda x: x.is_Mul and all(any(isinstance(i, log) and i.args[0].is_Rational + for i in Mul.make_args(j)) for j in x.as_numer_denom()), + _handleMul) + + return sympify(expr).expand(deep=deep, log=True, mul=False, + power_exp=False, power_base=False, multinomial=False, + basic=False, force=force, factor=factor) + + +def expand_func(expr, deep=True): + """ + Wrapper around expand that only uses the func hint. See the expand + docstring for more information. + + Examples + ======== + + >>> from sympy import expand_func, gamma + >>> from sympy.abc import x + >>> expand_func(gamma(x + 2)) + x*(x + 1)*gamma(x) + + """ + return sympify(expr).expand(deep=deep, func=True, basic=False, + log=False, mul=False, power_exp=False, power_base=False, multinomial=False) + + +def expand_trig(expr, deep=True): + """ + Wrapper around expand that only uses the trig hint. See the expand + docstring for more information. + + Examples + ======== + + >>> from sympy import expand_trig, sin + >>> from sympy.abc import x, y + >>> expand_trig(sin(x+y)*(x+y)) + (x + y)*(sin(x)*cos(y) + sin(y)*cos(x)) + + """ + return sympify(expr).expand(deep=deep, trig=True, basic=False, + log=False, mul=False, power_exp=False, power_base=False, multinomial=False) + + +def expand_complex(expr, deep=True): + """ + Wrapper around expand that only uses the complex hint. See the expand + docstring for more information. + + Examples + ======== + + >>> from sympy import expand_complex, exp, sqrt, I + >>> from sympy.abc import z + >>> expand_complex(exp(z)) + I*exp(re(z))*sin(im(z)) + exp(re(z))*cos(im(z)) + >>> expand_complex(sqrt(I)) + sqrt(2)/2 + sqrt(2)*I/2 + + See Also + ======== + + sympy.core.expr.Expr.as_real_imag + """ + return sympify(expr).expand(deep=deep, complex=True, basic=False, + log=False, mul=False, power_exp=False, power_base=False, multinomial=False) + + +def expand_power_base(expr, deep=True, force=False): + """ + Wrapper around expand that only uses the power_base hint. + + A wrapper to expand(power_base=True) which separates a power with a base + that is a Mul into a product of powers, without performing any other + expansions, provided that assumptions about the power's base and exponent + allow. + + deep=False (default is True) will only apply to the top-level expression. + + force=True (default is False) will cause the expansion to ignore + assumptions about the base and exponent. When False, the expansion will + only happen if the base is non-negative or the exponent is an integer. + + >>> from sympy.abc import x, y, z + >>> from sympy import expand_power_base, sin, cos, exp, Symbol + + >>> (x*y)**2 + x**2*y**2 + + >>> (2*x)**y + (2*x)**y + >>> expand_power_base(_) + 2**y*x**y + + >>> expand_power_base((x*y)**z) + (x*y)**z + >>> expand_power_base((x*y)**z, force=True) + x**z*y**z + >>> expand_power_base(sin((x*y)**z), deep=False) + sin((x*y)**z) + >>> expand_power_base(sin((x*y)**z), force=True) + sin(x**z*y**z) + + >>> expand_power_base((2*sin(x))**y + (2*cos(x))**y) + 2**y*sin(x)**y + 2**y*cos(x)**y + + >>> expand_power_base((2*exp(y))**x) + 2**x*exp(y)**x + + >>> expand_power_base((2*cos(x))**y) + 2**y*cos(x)**y + + Notice that sums are left untouched. If this is not the desired behavior, + apply full ``expand()`` to the expression: + + >>> expand_power_base(((x+y)*z)**2) + z**2*(x + y)**2 + >>> (((x+y)*z)**2).expand() + x**2*z**2 + 2*x*y*z**2 + y**2*z**2 + + >>> expand_power_base((2*y)**(1+z)) + 2**(z + 1)*y**(z + 1) + >>> ((2*y)**(1+z)).expand() + 2*2**z*y**(z + 1) + + The power that is unexpanded can be expanded safely when + ``y != 0``, otherwise different values might be obtained for the expression: + + >>> prev = _ + + If we indicate that ``y`` is positive but then replace it with + a value of 0 after expansion, the expression becomes 0: + + >>> p = Symbol('p', positive=True) + >>> prev.subs(y, p).expand().subs(p, 0) + 0 + + But if ``z = -1`` the expression would not be zero: + + >>> prev.subs(y, 0).subs(z, -1) + 1 + + See Also + ======== + + expand + + """ + return sympify(expr).expand(deep=deep, log=False, mul=False, + power_exp=False, power_base=True, multinomial=False, + basic=False, force=force) + + +def expand_power_exp(expr, deep=True): + """ + Wrapper around expand that only uses the power_exp hint. + + See the expand docstring for more information. + + Examples + ======== + + >>> from sympy import expand_power_exp, Symbol + >>> from sympy.abc import x, y + >>> expand_power_exp(3**(y + 2)) + 9*3**y + >>> expand_power_exp(x**(y + 2)) + x**(y + 2) + + If ``x = 0`` the value of the expression depends on the + value of ``y``; if the expression were expanded the result + would be 0. So expansion is only done if ``x != 0``: + + >>> expand_power_exp(Symbol('x', zero=False)**(y + 2)) + x**2*x**y + """ + return sympify(expr).expand(deep=deep, complex=False, basic=False, + log=False, mul=False, power_exp=True, power_base=False, multinomial=False) + + +def count_ops(expr, visual=False): + """ + Return a representation (integer or expression) of the operations in expr. + + Parameters + ========== + + expr : Expr + If expr is an iterable, the sum of the op counts of the + items will be returned. + + visual : bool, optional + If ``False`` (default) then the sum of the coefficients of the + visual expression will be returned. + If ``True`` then the number of each type of operation is shown + with the core class types (or their virtual equivalent) multiplied by the + number of times they occur. + + Examples + ======== + + >>> from sympy.abc import a, b, x, y + >>> from sympy import sin, count_ops + + Although there is not a SUB object, minus signs are interpreted as + either negations or subtractions: + + >>> (x - y).count_ops(visual=True) + SUB + >>> (-x).count_ops(visual=True) + NEG + + Here, there are two Adds and a Pow: + + >>> (1 + a + b**2).count_ops(visual=True) + 2*ADD + POW + + In the following, an Add, Mul, Pow and two functions: + + >>> (sin(x)*x + sin(x)**2).count_ops(visual=True) + ADD + MUL + POW + 2*SIN + + for a total of 5: + + >>> (sin(x)*x + sin(x)**2).count_ops(visual=False) + 5 + + Note that "what you type" is not always what you get. The expression + 1/x/y is translated by sympy into 1/(x*y) so it gives a DIV and MUL rather + than two DIVs: + + >>> (1/x/y).count_ops(visual=True) + DIV + MUL + + The visual option can be used to demonstrate the difference in + operations for expressions in different forms. Here, the Horner + representation is compared with the expanded form of a polynomial: + + >>> eq=x*(1 + x*(2 + x*(3 + x))) + >>> count_ops(eq.expand(), visual=True) - count_ops(eq, visual=True) + -MUL + 3*POW + + The count_ops function also handles iterables: + + >>> count_ops([x, sin(x), None, True, x + 2], visual=False) + 2 + >>> count_ops([x, sin(x), None, True, x + 2], visual=True) + ADD + SIN + >>> count_ops({x: sin(x), x + 2: y + 1}, visual=True) + 2*ADD + SIN + + """ + from .relational import Relational + from sympy.concrete.summations import Sum + from sympy.integrals.integrals import Integral + from sympy.logic.boolalg import BooleanFunction + from sympy.simplify.radsimp import fraction + + expr = sympify(expr) + if isinstance(expr, Expr) and not expr.is_Relational: + + ops = [] + args = [expr] + NEG = Symbol('NEG') + DIV = Symbol('DIV') + SUB = Symbol('SUB') + ADD = Symbol('ADD') + EXP = Symbol('EXP') + while args: + a = args.pop() + + # if the following fails because the object is + # not Basic type, then the object should be fixed + # since it is the intention that all args of Basic + # should themselves be Basic + if a.is_Rational: + #-1/3 = NEG + DIV + if a is not S.One: + if a.p < 0: + ops.append(NEG) + if a.q != 1: + ops.append(DIV) + continue + elif a.is_Mul or a.is_MatMul: + if _coeff_isneg(a): + ops.append(NEG) + if a.args[0] is S.NegativeOne: + a = a.as_two_terms()[1] + else: + a = -a + n, d = fraction(a) + if n.is_Integer: + ops.append(DIV) + if n < 0: + ops.append(NEG) + args.append(d) + continue # won't be -Mul but could be Add + elif d is not S.One: + if not d.is_Integer: + args.append(d) + ops.append(DIV) + args.append(n) + continue # could be -Mul + elif a.is_Add or a.is_MatAdd: + aargs = list(a.args) + negs = 0 + for i, ai in enumerate(aargs): + if _coeff_isneg(ai): + negs += 1 + args.append(-ai) + if i > 0: + ops.append(SUB) + else: + args.append(ai) + if i > 0: + ops.append(ADD) + if negs == len(aargs): # -x - y = NEG + SUB + ops.append(NEG) + elif _coeff_isneg(aargs[0]): # -x + y = SUB, but already recorded ADD + ops.append(SUB - ADD) + continue + if a.is_Pow and a.exp is S.NegativeOne: + ops.append(DIV) + args.append(a.base) # won't be -Mul but could be Add + continue + if a == S.Exp1: + ops.append(EXP) + continue + if a.is_Pow and a.base == S.Exp1: + ops.append(EXP) + args.append(a.exp) + continue + if a.is_Mul or isinstance(a, LatticeOp): + o = Symbol(a.func.__name__.upper()) + # count the args + ops.append(o*(len(a.args) - 1)) + elif a.args and ( + a.is_Pow or a.is_Function or isinstance(a, (Derivative, Integral, Sum))): + # if it's not in the list above we don't + # consider a.func something to count, e.g. + # Tuple, MatrixSymbol, etc... + if isinstance(a.func, UndefinedFunction): + o = Symbol("FUNC_" + a.func.__name__.upper()) + else: + o = Symbol(a.func.__name__.upper()) + ops.append(o) + + if not a.is_Symbol: + args.extend(a.args) + + elif isinstance(expr, Dict): + ops = [count_ops(k, visual=visual) + + count_ops(v, visual=visual) for k, v in expr.items()] + elif iterable(expr): + ops = [count_ops(i, visual=visual) for i in expr] + elif isinstance(expr, (Relational, BooleanFunction)): + ops = [] + for arg in expr.args: + ops.append(count_ops(arg, visual=True)) + o = Symbol(func_name(expr, short=True).upper()) + ops.append(o) + elif not isinstance(expr, Basic): + ops = [] + else: # it's Basic not isinstance(expr, Expr): + if not isinstance(expr, Basic): + raise TypeError("Invalid type of expr") + else: + ops = [] + args = [expr] + while args: + a = args.pop() + + if a.args: + o = Symbol(type(a).__name__.upper()) + if a.is_Boolean: + ops.append(o*(len(a.args)-1)) + else: + ops.append(o) + args.extend(a.args) + + if not ops: + if visual: + return S.Zero + return 0 + + ops = Add(*ops) + + if visual: + return ops + + if ops.is_Number: + return int(ops) + + return sum(int((a.args or [1])[0]) for a in Add.make_args(ops)) + + +def nfloat(expr, n=15, exponent=False, dkeys=False): + """Make all Rationals in expr Floats except those in exponents + (unless the exponents flag is set to True) and those in undefined + functions. When processing dictionaries, do not modify the keys + unless ``dkeys=True``. + + Examples + ======== + + >>> from sympy import nfloat, cos, pi, sqrt + >>> from sympy.abc import x, y + >>> nfloat(x**4 + x/2 + cos(pi/3) + 1 + sqrt(y)) + x**4 + 0.5*x + sqrt(y) + 1.5 + >>> nfloat(x**4 + sqrt(y), exponent=True) + x**4.0 + y**0.5 + + Container types are not modified: + + >>> type(nfloat((1, 2))) is tuple + True + """ + from sympy.matrices.matrixbase import MatrixBase + + kw = {"n": n, "exponent": exponent, "dkeys": dkeys} + + if isinstance(expr, MatrixBase): + return expr.applyfunc(lambda e: nfloat(e, **kw)) + + # handling of iterable containers + if iterable(expr, exclude=str): + if isinstance(expr, (dict, Dict)): + if dkeys: + args = [tuple((nfloat(i, **kw) for i in a)) + for a in expr.items()] + else: + args = [(k, nfloat(v, **kw)) for k, v in expr.items()] + if isinstance(expr, dict): + return type(expr)(args) + else: + return expr.func(*args) + elif isinstance(expr, Basic): + return expr.func(*[nfloat(a, **kw) for a in expr.args]) + return type(expr)([nfloat(a, **kw) for a in expr]) + + rv = sympify(expr) + + if rv.is_Number: + return Float(rv, n) + elif rv.is_number: + # evalf doesn't always set the precision + rv = rv.n(n) + if rv.is_Number: + rv = Float(rv.n(n), n) + else: + pass # pure_complex(rv) is likely True + return rv + elif rv.is_Atom: + return rv + elif rv.is_Relational: + args_nfloat = (nfloat(arg, **kw) for arg in rv.args) + return rv.func(*args_nfloat) + + + # watch out for RootOf instances that don't like to have + # their exponents replaced with Dummies and also sometimes have + # problems with evaluating at low precision (issue 6393) + from sympy.polys.rootoftools import RootOf + rv = rv.xreplace({ro: ro.n(n) for ro in rv.atoms(RootOf)}) + + from .power import Pow + if not exponent: + reps = [(p, Pow(p.base, Dummy())) for p in rv.atoms(Pow)] + rv = rv.xreplace(dict(reps)) + rv = rv.n(n) + if not exponent: + rv = rv.xreplace({d.exp: p.exp for p, d in reps}) + else: + # Pow._eval_evalf special cases Integer exponents so if + # exponent is suppose to be handled we have to do so here + rv = rv.xreplace(Transform( + lambda x: Pow(x.base, Float(x.exp, n)), + lambda x: x.is_Pow and x.exp.is_Integer)) + + return rv.xreplace(Transform( + lambda x: x.func(*nfloat(x.args, n, exponent)), + lambda x: isinstance(x, Function) and not isinstance(x, AppliedUndef))) + + +from .symbol import Dummy, Symbol diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/intfunc.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/intfunc.py new file mode 100644 index 0000000000000000000000000000000000000000..50cb625dafcc1e795933311780e26423ddc6015a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/intfunc.py @@ -0,0 +1,530 @@ +""" +The routines here were removed from numbers.py, power.py, +digits.py and factor_.py so they could be imported into core +without raising circular import errors. + +Although the name 'intfunc' was chosen to represent functions that +work with integers, it can also be thought of as containing +internal/core functions that are needed by the classes of the core. +""" + +import math +import sys +from functools import lru_cache + +from .sympify import sympify +from .singleton import S +from sympy.external.gmpy import (gcd as number_gcd, lcm as number_lcm, sqrt, + iroot, bit_scan1, gcdext) +from sympy.utilities.misc import as_int, filldedent + + +def num_digits(n, base=10): + """Return the number of digits needed to express n in give base. + + Examples + ======== + + >>> from sympy.core.intfunc import num_digits + >>> num_digits(10) + 2 + >>> num_digits(10, 2) # 1010 -> 4 digits + 4 + >>> num_digits(-100, 16) # -64 -> 2 digits + 2 + + + Parameters + ========== + + n: integer + The number whose digits are counted. + + b: integer + The base in which digits are computed. + + See Also + ======== + sympy.ntheory.digits.digits, sympy.ntheory.digits.count_digits + """ + if base < 0: + raise ValueError('base must be int greater than 1') + if not n: + return 1 + e, t = integer_log(abs(n), base) + return 1 + e + + +def integer_log(n, b): + r""" + Returns ``(e, bool)`` where e is the largest nonnegative integer + such that :math:`|n| \geq |b^e|` and ``bool`` is True if $n = b^e$. + + Examples + ======== + + >>> from sympy import integer_log + >>> integer_log(125, 5) + (3, True) + >>> integer_log(17, 9) + (1, False) + + If the base is positive and the number negative the + return value will always be the same except for 2: + + >>> integer_log(-4, 2) + (2, False) + >>> integer_log(-16, 4) + (0, False) + + When the base is negative, the returned value + will only be True if the parity of the exponent is + correct for the sign of the base: + + >>> integer_log(4, -2) + (2, True) + >>> integer_log(8, -2) + (3, False) + >>> integer_log(-8, -2) + (3, True) + >>> integer_log(-4, -2) + (2, False) + + See Also + ======== + integer_nthroot + sympy.ntheory.primetest.is_square + sympy.ntheory.factor_.multiplicity + sympy.ntheory.factor_.perfect_power + """ + n = as_int(n) + b = as_int(b) + + if b < 0: + e, t = integer_log(abs(n), -b) + # (-2)**3 == -8 + # (-2)**2 = 4 + t = t and e % 2 == (n < 0) + return e, t + if b <= 1: + raise ValueError('base must be 2 or more') + if n < 0: + if b != 2: + return 0, False + e, t = integer_log(-n, b) + return e, False + if n == 0: + raise ValueError('n cannot be 0') + + if n < b: + return 0, n == 1 + if b == 2: + e = n.bit_length() - 1 + return e, trailing(n) == e + t = trailing(b) + if 2**t == b: + e = int(n.bit_length() - 1)//t + n_ = 1 << (t*e) + return e, n_ == n + + d = math.floor(math.log10(n) / math.log10(b)) + n_ = b ** d + while n_ <= n: # this will iterate 0, 1 or 2 times + d += 1 + n_ *= b + return d - (n_ > n), (n_ == n or n_//b == n) + + +def trailing(n): + """Count the number of trailing zero digits in the binary + representation of n, i.e. determine the largest power of 2 + that divides n. + + Examples + ======== + + >>> from sympy import trailing + >>> trailing(128) + 7 + >>> trailing(63) + 0 + + See Also + ======== + sympy.ntheory.factor_.multiplicity + + """ + if not n: + return 0 + return bit_scan1(int(n)) + + +@lru_cache(1024) +def igcd(*args): + """Computes nonnegative integer greatest common divisor. + + Explanation + =========== + + The algorithm is based on the well known Euclid's algorithm [1]_. To + improve speed, ``igcd()`` has its own caching mechanism. + If you do not need the cache mechanism, using ``sympy.external.gmpy.gcd``. + + Examples + ======== + + >>> from sympy import igcd + >>> igcd(2, 4) + 2 + >>> igcd(5, 10, 15) + 5 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Euclidean_algorithm + + """ + if len(args) < 2: + raise TypeError("igcd() takes at least 2 arguments (%s given)" % len(args)) + return int(number_gcd(*map(as_int, args))) + + +igcd2 = math.gcd + + +def igcd_lehmer(a, b): + r"""Computes greatest common divisor of two integers. + + Explanation + =========== + + Euclid's algorithm for the computation of the greatest + common divisor ``gcd(a, b)`` of two (positive) integers + $a$ and $b$ is based on the division identity + $$ a = q \times b + r$$, + where the quotient $q$ and the remainder $r$ are integers + and $0 \le r < b$. Then each common divisor of $a$ and $b$ + divides $r$, and it follows that ``gcd(a, b) == gcd(b, r)``. + The algorithm works by constructing the sequence + r0, r1, r2, ..., where r0 = a, r1 = b, and each rn + is the remainder from the division of the two preceding + elements. + + In Python, ``q = a // b`` and ``r = a % b`` are obtained by the + floor division and the remainder operations, respectively. + These are the most expensive arithmetic operations, especially + for large a and b. + + Lehmer's algorithm [1]_ is based on the observation that the quotients + ``qn = r(n-1) // rn`` are in general small integers even + when a and b are very large. Hence the quotients can be + usually determined from a relatively small number of most + significant bits. + + The efficiency of the algorithm is further enhanced by not + computing each long remainder in Euclid's sequence. The remainders + are linear combinations of a and b with integer coefficients + derived from the quotients. The coefficients can be computed + as far as the quotients can be determined from the chosen + most significant parts of a and b. Only then a new pair of + consecutive remainders is computed and the algorithm starts + anew with this pair. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Lehmer%27s_GCD_algorithm + + """ + a, b = abs(as_int(a)), abs(as_int(b)) + if a < b: + a, b = b, a + + # The algorithm works by using one or two digit division + # whenever possible. The outer loop will replace the + # pair (a, b) with a pair of shorter consecutive elements + # of the Euclidean gcd sequence until a and b + # fit into two Python (long) int digits. + nbits = 2 * sys.int_info.bits_per_digit + + while a.bit_length() > nbits and b != 0: + # Quotients are mostly small integers that can + # be determined from most significant bits. + n = a.bit_length() - nbits + x, y = int(a >> n), int(b >> n) # most significant bits + + # Elements of the Euclidean gcd sequence are linear + # combinations of a and b with integer coefficients. + # Compute the coefficients of consecutive pairs + # a' = A*a + B*b, b' = C*a + D*b + # using small integer arithmetic as far as possible. + A, B, C, D = 1, 0, 0, 1 # initial values + + while True: + # The coefficients alternate in sign while looping. + # The inner loop combines two steps to keep track + # of the signs. + + # At this point we have + # A > 0, B <= 0, C <= 0, D > 0, + # x' = x + B <= x < x" = x + A, + # y' = y + C <= y < y" = y + D, + # and + # x'*N <= a' < x"*N, y'*N <= b' < y"*N, + # where N = 2**n. + + # Now, if y' > 0, and x"//y' and x'//y" agree, + # then their common value is equal to q = a'//b'. + # In addition, + # x'%y" = x' - q*y" < x" - q*y' = x"%y', + # and + # (x'%y")*N < a'%b' < (x"%y')*N. + + # On the other hand, we also have x//y == q, + # and therefore + # x'%y" = x + B - q*(y + D) = x%y + B', + # x"%y' = x + A - q*(y + C) = x%y + A', + # where + # B' = B - q*D < 0, A' = A - q*C > 0. + + if y + C <= 0: + break + q = (x + A) // (y + C) + + # Now x'//y" <= q, and equality holds if + # x' - q*y" = (x - q*y) + (B - q*D) >= 0. + # This is a minor optimization to avoid division. + x_qy, B_qD = x - q * y, B - q * D + if x_qy + B_qD < 0: + break + + # Next step in the Euclidean sequence. + x, y = y, x_qy + A, B, C, D = C, D, A - q * C, B_qD + + # At this point the signs of the coefficients + # change and their roles are interchanged. + # A <= 0, B > 0, C > 0, D < 0, + # x' = x + A <= x < x" = x + B, + # y' = y + D < y < y" = y + C. + + if y + D <= 0: + break + q = (x + B) // (y + D) + x_qy, A_qC = x - q * y, A - q * C + if x_qy + A_qC < 0: + break + + x, y = y, x_qy + A, B, C, D = C, D, A_qC, B - q * D + # Now the conditions on top of the loop + # are again satisfied. + # A > 0, B < 0, C < 0, D > 0. + + if B == 0: + # This can only happen when y == 0 in the beginning + # and the inner loop does nothing. + # Long division is forced. + a, b = b, a % b + continue + + # Compute new long arguments using the coefficients. + a, b = A * a + B * b, C * a + D * b + + # Small divisors. Finish with the standard algorithm. + while b: + a, b = b, a % b + + return a + + +def ilcm(*args): + """Computes integer least common multiple. + + Examples + ======== + + >>> from sympy import ilcm + >>> ilcm(5, 10) + 10 + >>> ilcm(7, 3) + 21 + >>> ilcm(5, 10, 15) + 30 + + """ + if len(args) < 2: + raise TypeError("ilcm() takes at least 2 arguments (%s given)" % len(args)) + return int(number_lcm(*map(as_int, args))) + + +def igcdex(a, b): + """Returns x, y, g such that g = x*a + y*b = gcd(a, b). + + Examples + ======== + + >>> from sympy.core.intfunc import igcdex + >>> igcdex(2, 3) + (-1, 1, 1) + >>> igcdex(10, 12) + (-1, 1, 2) + + >>> x, y, g = igcdex(100, 2004) + >>> x, y, g + (-20, 1, 4) + >>> x*100 + y*2004 + 4 + + """ + g, x, y = gcdext(int(a), int(b)) + return x, y, g + + +def mod_inverse(a, m): + r""" + Return the number $c$ such that, $a \times c = 1 \pmod{m}$ + where $c$ has the same sign as $m$. If no such value exists, + a ValueError is raised. + + Examples + ======== + + >>> from sympy import mod_inverse, S + + Suppose we wish to find multiplicative inverse $x$ of + 3 modulo 11. This is the same as finding $x$ such + that $3x = 1 \pmod{11}$. One value of x that satisfies + this congruence is 4. Because $3 \times 4 = 12$ and $12 = 1 \pmod{11}$. + This is the value returned by ``mod_inverse``: + + >>> mod_inverse(3, 11) + 4 + >>> mod_inverse(-3, 11) + 7 + + When there is a common factor between the numerators of + `a` and `m` the inverse does not exist: + + >>> mod_inverse(2, 4) + Traceback (most recent call last): + ... + ValueError: inverse of 2 mod 4 does not exist + + >>> mod_inverse(S(2)/7, S(5)/2) + 7/2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Modular_multiplicative_inverse + .. [2] https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm + """ + c = None + try: + a, m = as_int(a), as_int(m) + if m != 1 and m != -1: + x, _, g = igcdex(a, m) + if g == 1: + c = x % m + except ValueError: + a, m = sympify(a), sympify(m) + if not (a.is_number and m.is_number): + raise TypeError( + filldedent( + """ + Expected numbers for arguments; symbolic `mod_inverse` + is not implemented + but symbolic expressions can be handled with the + similar function, + sympy.polys.polytools.invert""" + ) + ) + big = m > 1 + if big not in (S.true, S.false): + raise ValueError("m > 1 did not evaluate; try to simplify %s" % m) + elif big: + c = 1 / a + if c is None: + raise ValueError("inverse of %s (mod %s) does not exist" % (a, m)) + return c + + +def isqrt(n): + r""" Return the largest integer less than or equal to `\sqrt{n}`. + + Parameters + ========== + + n : non-negative integer + + Returns + ======= + + int : `\left\lfloor\sqrt{n}\right\rfloor` + + Raises + ====== + + ValueError + If n is negative. + TypeError + If n is of a type that cannot be compared to ``int``. + Therefore, a TypeError is raised for ``str``, but not for ``float``. + + Examples + ======== + + >>> from sympy.core.intfunc import isqrt + >>> isqrt(0) + 0 + >>> isqrt(9) + 3 + >>> isqrt(10) + 3 + >>> isqrt("30") + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' + >>> from sympy.core.numbers import Rational + >>> isqrt(Rational(-1, 2)) + Traceback (most recent call last): + ... + ValueError: n must be nonnegative + + """ + if n < 0: + raise ValueError("n must be nonnegative") + return int(sqrt(int(n))) + + +def integer_nthroot(y, n): + """ + Return a tuple containing x = floor(y**(1/n)) + and a boolean indicating whether the result is exact (that is, + whether x**n == y). + + Examples + ======== + + >>> from sympy import integer_nthroot + >>> integer_nthroot(16, 2) + (4, True) + >>> integer_nthroot(26, 2) + (5, False) + + To simply determine if a number is a perfect square, the is_square + function should be used: + + >>> from sympy.ntheory.primetest import is_square + >>> is_square(26) + False + + See Also + ======== + sympy.ntheory.primetest.is_square + integer_log + """ + x, b = iroot(as_int(y), as_int(n)) + return int(x), b diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/kind.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/kind.py new file mode 100644 index 0000000000000000000000000000000000000000..83c5929eda14114659f2a5a72eb2d8b91a560f0e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/kind.py @@ -0,0 +1,388 @@ +""" +Module to efficiently partition SymPy objects. + +This system is introduced because class of SymPy object does not always +represent the mathematical classification of the entity. For example, +``Integral(1, x)`` and ``Integral(Matrix([1,2]), x)`` are both instance +of ``Integral`` class. However the former is number and the latter is +matrix. + +One way to resolve this is defining subclass for each mathematical type, +such as ``MatAdd`` for the addition between matrices. Basic algebraic +operation such as addition or multiplication take this approach, but +defining every class for every mathematical object is not scalable. + +Therefore, we define the "kind" of the object and let the expression +infer the kind of itself from its arguments. Function and class can +filter the arguments by their kind, and behave differently according to +the type of itself. + +This module defines basic kinds for core objects. Other kinds such as +``ArrayKind`` or ``MatrixKind`` can be found in corresponding modules. + +.. notes:: + This approach is experimental, and can be replaced or deleted in the future. + See https://github.com/sympy/sympy/pull/20549. +""" + +from collections import defaultdict + +from .cache import cacheit +from sympy.multipledispatch.dispatcher import (Dispatcher, + ambiguity_warn, ambiguity_register_error_ignore_dup, + str_signature, RaiseNotImplementedError) + + +class KindMeta(type): + """ + Metaclass for ``Kind``. + + Assigns empty ``dict`` as class attribute ``_inst`` for every class, + in order to endow singleton-like behavior. + """ + def __new__(cls, clsname, bases, dct): + dct['_inst'] = {} + return super().__new__(cls, clsname, bases, dct) + + +class Kind(object, metaclass=KindMeta): + """ + Base class for kinds. + + Kind of the object represents the mathematical classification that + the entity falls into. It is expected that functions and classes + recognize and filter the argument by its kind. + + Kind of every object must be carefully selected so that it shows the + intention of design. Expressions may have different kind according + to the kind of its arguments. For example, arguments of ``Add`` + must have common kind since addition is group operator, and the + resulting ``Add()`` has the same kind. + + For the performance, each kind is as broad as possible and is not + based on set theory. For example, ``NumberKind`` includes not only + complex number but expression containing ``S.Infinity`` or ``S.NaN`` + which are not strictly number. + + Kind may have arguments as parameter. For example, ``MatrixKind()`` + may be constructed with one element which represents the kind of its + elements. + + ``Kind`` behaves in singleton-like fashion. Same signature will + return the same object. + + """ + def __new__(cls, *args): + if args in cls._inst: + inst = cls._inst[args] + else: + inst = super().__new__(cls) + cls._inst[args] = inst + return inst + + +class _UndefinedKind(Kind): + """ + Default kind for all SymPy object. If the kind is not defined for + the object, or if the object cannot infer the kind from its + arguments, this will be returned. + + Examples + ======== + + >>> from sympy import Expr + >>> Expr().kind + UndefinedKind + """ + def __new__(cls): + return super().__new__(cls) + + def __repr__(self): + return "UndefinedKind" + +UndefinedKind = _UndefinedKind() + + +class _NumberKind(Kind): + """ + Kind for all numeric object. + + This kind represents every number, including complex numbers, + infinity and ``S.NaN``. Other objects such as quaternions do not + have this kind. + + Most ``Expr`` are initially designed to represent the number, so + this will be the most common kind in SymPy core. For example + ``Symbol()``, which represents a scalar, has this kind as long as it + is commutative. + + Numbers form a field. Any operation between number-kind objects will + result this kind as well. + + Examples + ======== + + >>> from sympy import S, oo, Symbol + >>> S.One.kind + NumberKind + >>> (-oo).kind + NumberKind + >>> S.NaN.kind + NumberKind + + Commutative symbol are treated as number. + + >>> x = Symbol('x') + >>> x.kind + NumberKind + >>> Symbol('y', commutative=False).kind + UndefinedKind + + Operation between numbers results number. + + >>> (x+1).kind + NumberKind + + See Also + ======== + + sympy.core.expr.Expr.is_Number : check if the object is strictly + subclass of ``Number`` class. + + sympy.core.expr.Expr.is_number : check if the object is number + without any free symbol. + + """ + def __new__(cls): + return super().__new__(cls) + + def __repr__(self): + return "NumberKind" + +NumberKind = _NumberKind() + + +class _BooleanKind(Kind): + """ + Kind for boolean objects. + + SymPy's ``S.true``, ``S.false``, and built-in ``True`` and ``False`` + have this kind. Boolean number ``1`` and ``0`` are not relevant. + + Examples + ======== + + >>> from sympy import S, Q + >>> S.true.kind + BooleanKind + >>> Q.even(3).kind + BooleanKind + """ + def __new__(cls): + return super().__new__(cls) + + def __repr__(self): + return "BooleanKind" + +BooleanKind = _BooleanKind() + + +class KindDispatcher: + """ + Dispatcher to select a kind from multiple kinds by binary dispatching. + + .. notes:: + This approach is experimental, and can be replaced or deleted in + the future. + + Explanation + =========== + + SymPy object's :obj:`sympy.core.kind.Kind()` vaguely represents the + algebraic structure where the object belongs to. Therefore, with + given operation, we can always find a dominating kind among the + different kinds. This class selects the kind by recursive binary + dispatching. If the result cannot be determined, ``UndefinedKind`` + is returned. + + Examples + ======== + + Multiplication between numbers return number. + + >>> from sympy import NumberKind, Mul + >>> Mul._kind_dispatcher(NumberKind, NumberKind) + NumberKind + + Multiplication between number and unknown-kind object returns unknown kind. + + >>> from sympy import UndefinedKind + >>> Mul._kind_dispatcher(NumberKind, UndefinedKind) + UndefinedKind + + Any number and order of kinds is allowed. + + >>> Mul._kind_dispatcher(UndefinedKind, NumberKind) + UndefinedKind + >>> Mul._kind_dispatcher(NumberKind, UndefinedKind, NumberKind) + UndefinedKind + + Since matrix forms a vector space over scalar field, multiplication + between matrix with numeric element and number returns matrix with + numeric element. + + >>> from sympy.matrices import MatrixKind + >>> Mul._kind_dispatcher(MatrixKind(NumberKind), NumberKind) + MatrixKind(NumberKind) + + If a matrix with number element and another matrix with unknown-kind + element are multiplied, we know that the result is matrix but the + kind of its elements is unknown. + + >>> Mul._kind_dispatcher(MatrixKind(NumberKind), MatrixKind(UndefinedKind)) + MatrixKind(UndefinedKind) + + Parameters + ========== + + name : str + + commutative : bool, optional + If True, binary dispatch will be automatically registered in + reversed order as well. + + doc : str, optional + + """ + def __init__(self, name, commutative=False, doc=None): + self.name = name + self.doc = doc + self.commutative = commutative + self._dispatcher = Dispatcher(name) + + def __repr__(self): + return "" % self.name + + def register(self, *types, **kwargs): + """ + Register the binary dispatcher for two kind classes. + + If *self.commutative* is ``True``, signature in reversed order is + automatically registered as well. + """ + on_ambiguity = kwargs.pop("on_ambiguity", None) + if not on_ambiguity: + if self.commutative: + on_ambiguity = ambiguity_register_error_ignore_dup + else: + on_ambiguity = ambiguity_warn + kwargs.update(on_ambiguity=on_ambiguity) + + if not len(types) == 2: + raise RuntimeError( + "Only binary dispatch is supported, but got %s types: <%s>." % ( + len(types), str_signature(types) + )) + + def _(func): + self._dispatcher.add(types, func, **kwargs) + if self.commutative: + self._dispatcher.add(tuple(reversed(types)), func, **kwargs) + return _ + + def __call__(self, *args, **kwargs): + if self.commutative: + kinds = frozenset(args) + else: + kinds = [] + prev = None + for a in args: + if prev is not a: + kinds.append(a) + prev = a + return self.dispatch_kinds(kinds, **kwargs) + + @cacheit + def dispatch_kinds(self, kinds, **kwargs): + # Quick exit for the case where all kinds are same + if len(kinds) == 1: + result, = kinds + if not isinstance(result, Kind): + raise RuntimeError("%s is not a kind." % result) + return result + + for i,kind in enumerate(kinds): + if not isinstance(kind, Kind): + raise RuntimeError("%s is not a kind." % kind) + + if i == 0: + result = kind + else: + prev_kind = result + + t1, t2 = type(prev_kind), type(kind) + k1, k2 = prev_kind, kind + func = self._dispatcher.dispatch(t1, t2) + if func is None and self.commutative: + # try reversed order + func = self._dispatcher.dispatch(t2, t1) + k1, k2 = k2, k1 + if func is None: + # unregistered kind relation + result = UndefinedKind + else: + result = func(k1, k2) + if not isinstance(result, Kind): + raise RuntimeError( + "Dispatcher for {!r} and {!r} must return a Kind, but got {!r}".format( + prev_kind, kind, result + )) + + return result + + @property + def __doc__(self): + docs = [ + "Kind dispatcher : %s" % self.name, + "Note that support for this is experimental. See the docs for :class:`KindDispatcher` for details" + ] + + if self.doc: + docs.append(self.doc) + + s = "Registered kind classes\n" + s += '=' * len(s) + docs.append(s) + + amb_sigs = [] + + typ_sigs = defaultdict(list) + for sigs in self._dispatcher.ordering[::-1]: + key = self._dispatcher.funcs[sigs] + typ_sigs[key].append(sigs) + + for func, sigs in typ_sigs.items(): + + sigs_str = ', '.join('<%s>' % str_signature(sig) for sig in sigs) + + if isinstance(func, RaiseNotImplementedError): + amb_sigs.append(sigs_str) + continue + + s = 'Inputs: %s\n' % sigs_str + s += '-' * len(s) + '\n' + if func.__doc__: + s += func.__doc__.strip() + else: + s += func.__name__ + docs.append(s) + + if amb_sigs: + s = "Ambiguous kind classes\n" + s += '=' * len(s) + docs.append(s) + + s = '\n'.join(amb_sigs) + docs.append(s) + + return '\n\n'.join(docs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/logic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/logic.py new file mode 100644 index 0000000000000000000000000000000000000000..1c318063049a4657952c8ca84e0f0fdeef62a207 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/logic.py @@ -0,0 +1,425 @@ +"""Logic expressions handling + +NOTE +---- + +at present this is mainly needed for facts.py, feel free however to improve +this stuff for general purpose. +""" + +from __future__ import annotations +from typing import Optional + +# Type of a fuzzy bool +FuzzyBool = Optional[bool] + + +def _torf(args): + """Return True if all args are True, False if they + are all False, else None. + + >>> from sympy.core.logic import _torf + >>> _torf((True, True)) + True + >>> _torf((False, False)) + False + >>> _torf((True, False)) + """ + sawT = sawF = False + for a in args: + if a is True: + if sawF: + return + sawT = True + elif a is False: + if sawT: + return + sawF = True + else: + return + return sawT + + +def _fuzzy_group(args, quick_exit=False): + """Return True if all args are True, None if there is any None else False + unless ``quick_exit`` is True (then return None as soon as a second False + is seen. + + ``_fuzzy_group`` is like ``fuzzy_and`` except that it is more + conservative in returning a False, waiting to make sure that all + arguments are True or False and returning None if any arguments are + None. It also has the capability of permiting only a single False and + returning None if more than one is seen. For example, the presence of a + single transcendental amongst rationals would indicate that the group is + no longer rational; but a second transcendental in the group would make the + determination impossible. + + + Examples + ======== + + >>> from sympy.core.logic import _fuzzy_group + + By default, multiple Falses mean the group is broken: + + >>> _fuzzy_group([False, False, True]) + False + + If multiple Falses mean the group status is unknown then set + `quick_exit` to True so None can be returned when the 2nd False is seen: + + >>> _fuzzy_group([False, False, True], quick_exit=True) + + But if only a single False is seen then the group is known to + be broken: + + >>> _fuzzy_group([False, True, True], quick_exit=True) + False + + """ + saw_other = False + for a in args: + if a is True: + continue + if a is None: + return + if quick_exit and saw_other: + return + saw_other = True + return not saw_other + + +def fuzzy_bool(x): + """Return True, False or None according to x. + + Whereas bool(x) returns True or False, fuzzy_bool allows + for the None value and non-false values (which become None), too. + + Examples + ======== + + >>> from sympy.core.logic import fuzzy_bool + >>> from sympy.abc import x + >>> fuzzy_bool(x), fuzzy_bool(None) + (None, None) + >>> bool(x), bool(None) + (True, False) + + """ + if x is None: + return None + if x in (True, False): + return bool(x) + + +def fuzzy_and(args): + """Return True (all True), False (any False) or None. + + Examples + ======== + + >>> from sympy.core.logic import fuzzy_and + >>> from sympy import Dummy + + If you had a list of objects to test the commutivity of + and you want the fuzzy_and logic applied, passing an + iterator will allow the commutativity to only be computed + as many times as necessary. With this list, False can be + returned after analyzing the first symbol: + + >>> syms = [Dummy(commutative=False), Dummy()] + >>> fuzzy_and(s.is_commutative for s in syms) + False + + That False would require less work than if a list of pre-computed + items was sent: + + >>> fuzzy_and([s.is_commutative for s in syms]) + False + """ + + rv = True + for ai in args: + ai = fuzzy_bool(ai) + if ai is False: + return False + if rv: # this will stop updating if a None is ever trapped + rv = ai + return rv + + +def fuzzy_not(v): + """ + Not in fuzzy logic + + Return None if `v` is None else `not v`. + + Examples + ======== + + >>> from sympy.core.logic import fuzzy_not + >>> fuzzy_not(True) + False + >>> fuzzy_not(None) + >>> fuzzy_not(False) + True + + """ + if v is None: + return v + else: + return not v + + +def fuzzy_or(args): + """ + Or in fuzzy logic. Returns True (any True), False (all False), or None + + See the docstrings of fuzzy_and and fuzzy_not for more info. fuzzy_or is + related to the two by the standard De Morgan's law. + + >>> from sympy.core.logic import fuzzy_or + >>> fuzzy_or([True, False]) + True + >>> fuzzy_or([True, None]) + True + >>> fuzzy_or([False, False]) + False + >>> print(fuzzy_or([False, None])) + None + + """ + rv = False + for ai in args: + ai = fuzzy_bool(ai) + if ai is True: + return True + if rv is False: # this will stop updating if a None is ever trapped + rv = ai + return rv + + +def fuzzy_xor(args): + """Return None if any element of args is not True or False, else + True (if there are an odd number of True elements), else False.""" + t = 0 + for a in args: + ai = fuzzy_bool(a) + if ai: + t += 1 + elif ai is None: + return + return t % 2 == 1 + + +def fuzzy_nand(args): + """Return False if all args are True, True if they are all False, + else None.""" + return fuzzy_not(fuzzy_and(args)) + + +class Logic: + """Logical expression""" + # {} 'op' -> LogicClass + op_2class: dict[str, type[Logic]] = {} + + def __new__(cls, *args): + obj = object.__new__(cls) + obj.args = args + return obj + + def __getnewargs__(self): + return self.args + + def __hash__(self): + return hash((type(self).__name__,) + tuple(self.args)) + + def __eq__(a, b): + if not isinstance(b, type(a)): + return False + else: + return a.args == b.args + + def __ne__(a, b): + if not isinstance(b, type(a)): + return True + else: + return a.args != b.args + + def __lt__(self, other): + if self.__cmp__(other) == -1: + return True + return False + + def __cmp__(self, other): + if type(self) is not type(other): + a = str(type(self)) + b = str(type(other)) + else: + a = self.args + b = other.args + return (a > b) - (a < b) + + def __str__(self): + return '%s(%s)' % (self.__class__.__name__, + ', '.join(str(a) for a in self.args)) + + __repr__ = __str__ + + @staticmethod + def fromstring(text): + """Logic from string with space around & and | but none after !. + + e.g. + + !a & b | c + """ + lexpr = None # current logical expression + schedop = None # scheduled operation + for term in text.split(): + # operation symbol + if term in '&|': + if schedop is not None: + raise ValueError( + 'double op forbidden: "%s %s"' % (term, schedop)) + if lexpr is None: + raise ValueError( + '%s cannot be in the beginning of expression' % term) + schedop = term + continue + if '&' in term or '|' in term: + raise ValueError('& and | must have space around them') + if term[0] == '!': + if len(term) == 1: + raise ValueError('do not include space after "!"') + term = Not(term[1:]) + + # already scheduled operation, e.g. '&' + if schedop: + lexpr = Logic.op_2class[schedop](lexpr, term) + schedop = None + continue + + # this should be atom + if lexpr is not None: + raise ValueError( + 'missing op between "%s" and "%s"' % (lexpr, term)) + + lexpr = term + + # let's check that we ended up in correct state + if schedop is not None: + raise ValueError('premature end-of-expression in "%s"' % text) + if lexpr is None: + raise ValueError('"%s" is empty' % text) + + # everything looks good now + return lexpr + + +class AndOr_Base(Logic): + + def __new__(cls, *args): + bargs = [] + for a in args: + if a == cls.op_x_notx: + return a + elif a == (not cls.op_x_notx): + continue # skip this argument + bargs.append(a) + + args = sorted(set(cls.flatten(bargs)), key=hash) + + for a in args: + if Not(a) in args: + return cls.op_x_notx + + if len(args) == 1: + return args.pop() + elif len(args) == 0: + return not cls.op_x_notx + + return Logic.__new__(cls, *args) + + @classmethod + def flatten(cls, args): + # quick-n-dirty flattening for And and Or + args_queue = list(args) + res = [] + + while True: + try: + arg = args_queue.pop(0) + except IndexError: + break + if isinstance(arg, Logic): + if isinstance(arg, cls): + args_queue.extend(arg.args) + continue + res.append(arg) + + args = tuple(res) + return args + + +class And(AndOr_Base): + op_x_notx = False + + def _eval_propagate_not(self): + # !(a&b&c ...) == !a | !b | !c ... + return Or(*[Not(a) for a in self.args]) + + # (a|b|...) & c == (a&c) | (b&c) | ... + def expand(self): + + # first locate Or + for i, arg in enumerate(self.args): + if isinstance(arg, Or): + arest = self.args[:i] + self.args[i + 1:] + + orterms = [And(*(arest + (a,))) for a in arg.args] + for j in range(len(orterms)): + if isinstance(orterms[j], Logic): + orterms[j] = orterms[j].expand() + + res = Or(*orterms) + return res + + return self + + +class Or(AndOr_Base): + op_x_notx = True + + def _eval_propagate_not(self): + # !(a|b|c ...) == !a & !b & !c ... + return And(*[Not(a) for a in self.args]) + + +class Not(Logic): + + def __new__(cls, arg): + if isinstance(arg, str): + return Logic.__new__(cls, arg) + + elif isinstance(arg, bool): + return not arg + elif isinstance(arg, Not): + return arg.args[0] + + elif isinstance(arg, Logic): + # XXX this is a hack to expand right from the beginning + arg = arg._eval_propagate_not() + return arg + + else: + raise ValueError('Not: unknown argument %r' % (arg,)) + + @property + def arg(self): + return self.args[0] + + +Logic.op_2class['&'] = And +Logic.op_2class['|'] = Or +Logic.op_2class['!'] = Not diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/mod.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/mod.py new file mode 100644 index 0000000000000000000000000000000000000000..8be0c56e497eb5ed0041801488044b50f907962c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/mod.py @@ -0,0 +1,260 @@ +from .add import Add +from .exprtools import gcd_terms +from .function import DefinedFunction +from .kind import NumberKind +from .logic import fuzzy_and, fuzzy_not +from .mul import Mul +from .numbers import equal_valued +from .relational import is_le, is_lt, is_ge, is_gt +from .singleton import S + + +class Mod(DefinedFunction): + """Represents a modulo operation on symbolic expressions. + + Parameters + ========== + + p : Expr + Dividend. + + q : Expr + Divisor. + + Notes + ===== + + The convention used is the same as Python's: the remainder always has the + same sign as the divisor. + + Many objects can be evaluated modulo ``n`` much faster than they can be + evaluated directly (or at all). For this, ``evaluate=False`` is + necessary to prevent eager evaluation: + + >>> from sympy import binomial, factorial, Mod, Pow + >>> Mod(Pow(2, 10**16, evaluate=False), 97) + 61 + >>> Mod(factorial(10**9, evaluate=False), 10**9 + 9) + 712524808 + >>> Mod(binomial(10**18, 10**12, evaluate=False), (10**5 + 3)**2) + 3744312326 + + Examples + ======== + + >>> from sympy.abc import x, y + >>> x**2 % y + Mod(x**2, y) + >>> _.subs({x: 5, y: 6}) + 1 + + """ + + kind = NumberKind + + @classmethod + def eval(cls, p, q): + def number_eval(p, q): + """Try to return p % q if both are numbers or +/-p is known + to be less than or equal q. + """ + + if q.is_zero: + raise ZeroDivisionError("Modulo by zero") + if p is S.NaN or q is S.NaN or p.is_finite is False or q.is_finite is False: + return S.NaN + if p is S.Zero or p in (q, -q) or (p.is_integer and q == 1): + return S.Zero + + if q.is_Number: + if p.is_Number: + return p%q + if q == 2: + if p.is_even: + return S.Zero + elif p.is_odd: + return S.One + + if hasattr(p, '_eval_Mod'): + rv = getattr(p, '_eval_Mod')(q) + if rv is not None: + return rv + + # by ratio + r = p/q + if r.is_integer: + return S.Zero + try: + d = int(r) + except TypeError: + pass + else: + if isinstance(d, int): + rv = p - d*q + if (rv*q < 0) == True: + rv += q + return rv + + # by difference + # -2|q| < p < 2|q| + if q.is_positive: + comp1, comp2 = is_le, is_lt + elif q.is_negative: + comp1, comp2 = is_ge, is_gt + else: + return + ls = -2*q + r = p - q + for _ in range(4): + if not comp1(ls, p): + return + if comp2(r, ls): + return p - ls + ls += q + + rv = number_eval(p, q) + if rv is not None: + return rv + + # denest + if isinstance(p, cls): + qinner = p.args[1] + if qinner % q == 0: + return cls(p.args[0], q) + elif (qinner*(q - qinner)).is_nonnegative: + # |qinner| < |q| and have same sign + return p + elif isinstance(-p, cls): + qinner = (-p).args[1] + if qinner % q == 0: + return cls(-(-p).args[0], q) + elif (qinner*(q + qinner)).is_nonpositive: + # |qinner| < |q| and have different sign + return p + elif isinstance(p, Add): + # separating into modulus and non modulus + both_l = non_mod_l, mod_l = [], [] + for arg in p.args: + both_l[isinstance(arg, cls)].append(arg) + # if q same for all + if mod_l and all(inner.args[1] == q for inner in mod_l): + net = Add(*non_mod_l) + Add(*[i.args[0] for i in mod_l]) + return cls(net, q) + + elif isinstance(p, Mul): + # separating into modulus and non modulus + both_l = non_mod_l, mod_l = [], [] + for arg in p.args: + both_l[isinstance(arg, cls)].append(arg) + + if mod_l and all(inner.args[1] == q for inner in mod_l) and all(t.is_integer for t in p.args) and q.is_integer: + # finding distributive term + non_mod_l = [cls(x, q) for x in non_mod_l] + mod = [] + non_mod = [] + for j in non_mod_l: + if isinstance(j, cls): + mod.append(j.args[0]) + else: + non_mod.append(j) + prod_mod = Mul(*mod) + prod_non_mod = Mul(*non_mod) + prod_mod1 = Mul(*[i.args[0] for i in mod_l]) + net = prod_mod1*prod_mod + return prod_non_mod*cls(net, q) + + if q.is_Integer and q is not S.One: + if all(t.is_integer for t in p.args): + non_mod_l = [i % q if i.is_Integer else i for i in p.args] + if any(iq is S.Zero for iq in non_mod_l): + return S.Zero + + p = Mul(*(non_mod_l + mod_l)) + + # XXX other possibilities? + + from sympy.polys.polyerrors import PolynomialError + from sympy.polys.polytools import gcd + + # extract gcd; any further simplification should be done by the user + try: + G = gcd(p, q) + if not equal_valued(G, 1): + p, q = [gcd_terms(i/G, clear=False, fraction=False) + for i in (p, q)] + except PolynomialError: # issue 21373 + G = S.One + pwas, qwas = p, q + + # simplify terms + # (x + y + 2) % x -> Mod(y + 2, x) + if p.is_Add: + args = [] + for i in p.args: + a = cls(i, q) + if a.count(cls) > i.count(cls): + args.append(i) + else: + args.append(a) + if args != list(p.args): + p = Add(*args) + + else: + # handle coefficients if they are not Rational + # since those are not handled by factor_terms + # e.g. Mod(.6*x, .3*y) -> 0.3*Mod(2*x, y) + cp, p = p.as_coeff_Mul() + cq, q = q.as_coeff_Mul() + ok = False + if not cp.is_Rational or not cq.is_Rational: + r = cp % cq + if equal_valued(r, 0): + G *= cq + p *= int(cp/cq) + ok = True + if not ok: + p = cp*p + q = cq*q + + # simple -1 extraction + if p.could_extract_minus_sign() and q.could_extract_minus_sign(): + G, p, q = [-i for i in (G, p, q)] + + # check again to see if p and q can now be handled as numbers + rv = number_eval(p, q) + if rv is not None: + return rv*G + + # put 1.0 from G on inside + if G.is_Float and equal_valued(G, 1): + p *= G + return cls(p, q, evaluate=False) + elif G.is_Mul and G.args[0].is_Float and equal_valued(G.args[0], 1): + p = G.args[0]*p + G = Mul._from_args(G.args[1:]) + return G*cls(p, q, evaluate=(p, q) != (pwas, qwas)) + + def _eval_is_integer(self): + p, q = self.args + if fuzzy_and([p.is_integer, q.is_integer, fuzzy_not(q.is_zero)]): + return True + + def _eval_is_nonnegative(self): + if self.args[1].is_positive: + return True + + def _eval_is_nonpositive(self): + if self.args[1].is_negative: + return True + + def _eval_rewrite_as_floor(self, a, b, **kwargs): + from sympy.functions.elementary.integers import floor + return a - b*floor(a/b) + + def _eval_as_leading_term(self, x, logx, cdir): + from sympy.functions.elementary.integers import floor + return self.rewrite(floor)._eval_as_leading_term(x, logx=logx, cdir=cdir) + + def _eval_nseries(self, x, n, logx, cdir=0): + from sympy.functions.elementary.integers import floor + return self.rewrite(floor)._eval_nseries(x, n, logx=logx, cdir=cdir) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/mul.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/mul.py new file mode 100644 index 0000000000000000000000000000000000000000..fd83c8610a76db4e7bc7a2a71b98e437bd00a28e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/mul.py @@ -0,0 +1,2214 @@ +from __future__ import annotations +from typing import TYPE_CHECKING, ClassVar + +from collections import defaultdict +from functools import reduce +from itertools import product +import operator + +from .sympify import sympify +from .basic import Basic, _args_sortkey +from .singleton import S +from .operations import AssocOp, AssocOpDispatcher +from .cache import cacheit +from .intfunc import integer_nthroot, trailing +from .logic import fuzzy_not, _fuzzy_group +from .expr import Expr +from .parameters import global_parameters +from .kind import KindDispatcher +from .traversal import bottom_up +from sympy.utilities.iterables import sift + + +# internal marker to indicate: +# "there are still non-commutative objects -- don't forget to process them" +class NC_Marker: + is_Order = False + is_Mul = False + is_Number = False + is_Poly = False + + is_commutative = False + + +def _mulsort(args): + # in-place sorting of args + args.sort(key=_args_sortkey) + + +def _unevaluated_Mul(*args): + """Return a well-formed unevaluated Mul: Numbers are collected and + put in slot 0, any arguments that are Muls will be flattened, and args + are sorted. Use this when args have changed but you still want to return + an unevaluated Mul. + + Examples + ======== + + >>> from sympy.core.mul import _unevaluated_Mul as uMul + >>> from sympy import S, sqrt, Mul + >>> from sympy.abc import x + >>> a = uMul(*[S(3.0), x, S(2)]) + >>> a.args[0] + 6.00000000000000 + >>> a.args[1] + x + + Two unevaluated Muls with the same arguments will + always compare as equal during testing: + + >>> m = uMul(sqrt(2), sqrt(3)) + >>> m == uMul(sqrt(3), sqrt(2)) + True + >>> u = Mul(sqrt(3), sqrt(2), evaluate=False) + >>> m == uMul(u) + True + >>> m == Mul(*m.args) + False + + """ + cargs = [] + ncargs = [] + args = list(args) + co = S.One + for a in args: + if a.is_Mul: + a_c, a_nc = a.args_cnc() + args.extend(a_c) # grow args + ncargs.extend(a_nc) + elif a.is_Number: + co *= a + elif a.is_commutative: + cargs.append(a) + else: + ncargs.append(a) + _mulsort(cargs) + if co is not S.One: + cargs.insert(0, co) + return Mul._from_args(cargs+ncargs) + + +class Mul(Expr, AssocOp): + """ + Expression representing multiplication operation for algebraic field. + + .. deprecated:: 1.7 + + Using arguments that aren't subclasses of :class:`~.Expr` in core + operators (:class:`~.Mul`, :class:`~.Add`, and :class:`~.Pow`) is + deprecated. See :ref:`non-expr-args-deprecated` for details. + + Every argument of ``Mul()`` must be ``Expr``. Infix operator ``*`` + on most scalar objects in SymPy calls this class. + + Another use of ``Mul()`` is to represent the structure of abstract + multiplication so that its arguments can be substituted to return + different class. Refer to examples section for this. + + ``Mul()`` evaluates the argument unless ``evaluate=False`` is passed. + The evaluation logic includes: + + 1. Flattening + ``Mul(x, Mul(y, z))`` -> ``Mul(x, y, z)`` + + 2. Identity removing + ``Mul(x, 1, y)`` -> ``Mul(x, y)`` + + 3. Exponent collecting by ``.as_base_exp()`` + ``Mul(x, x**2)`` -> ``Pow(x, 3)`` + + 4. Term sorting + ``Mul(y, x, 2)`` -> ``Mul(2, x, y)`` + + Since multiplication can be vector space operation, arguments may + have the different :obj:`sympy.core.kind.Kind()`. Kind of the + resulting object is automatically inferred. + + Examples + ======== + + >>> from sympy import Mul + >>> from sympy.abc import x, y + >>> Mul(x, 1) + x + >>> Mul(x, x) + x**2 + + If ``evaluate=False`` is passed, result is not evaluated. + + >>> Mul(1, 2, evaluate=False) + 1*2 + >>> Mul(x, x, evaluate=False) + x*x + + ``Mul()`` also represents the general structure of multiplication + operation. + + >>> from sympy import MatrixSymbol + >>> A = MatrixSymbol('A', 2,2) + >>> expr = Mul(x,y).subs({y:A}) + >>> expr + x*A + >>> type(expr) + + + See Also + ======== + + MatMul + + """ + __slots__ = () + + is_Mul = True + + _args_type = Expr + _kind_dispatcher = KindDispatcher("Mul_kind_dispatcher", commutative=True) + + identity: ClassVar[Expr] + + @property + def kind(self): + arg_kinds = (a.kind for a in self.args) + return self._kind_dispatcher(*arg_kinds) + + if TYPE_CHECKING: + + def __new__(cls, *args: Expr | complex, evaluate: bool=True) -> Expr: # type: ignore + ... + + @property + def args(self) -> tuple[Expr, ...]: + ... + + def could_extract_minus_sign(self): + if self == (-self): + return False # e.g. zoo*x == -zoo*x + c = self.args[0] + return c.is_Number and c.is_extended_negative + + def __neg__(self): + c, args = self.as_coeff_mul() + if args[0] is not S.ComplexInfinity: + c = -c + if c is not S.One: + if args[0].is_Number: + args = list(args) + if c is S.NegativeOne: + args[0] = -args[0] + else: + args[0] *= c + else: + args = (c,) + args + return self._from_args(args, self.is_commutative) + + @classmethod + def flatten(cls, seq): + """Return commutative, noncommutative and order arguments by + combining related terms. + + Notes + ===== + * In an expression like ``a*b*c``, Python process this through SymPy + as ``Mul(Mul(a, b), c)``. This can have undesirable consequences. + + - Sometimes terms are not combined as one would like: + {c.f. https://github.com/sympy/sympy/issues/4596} + + >>> from sympy import Mul, sqrt + >>> from sympy.abc import x, y, z + >>> 2*(x + 1) # this is the 2-arg Mul behavior + 2*x + 2 + >>> y*(x + 1)*2 + 2*y*(x + 1) + >>> 2*(x + 1)*y # 2-arg result will be obtained first + y*(2*x + 2) + >>> Mul(2, x + 1, y) # all 3 args simultaneously processed + 2*y*(x + 1) + >>> 2*((x + 1)*y) # parentheses can control this behavior + 2*y*(x + 1) + + Powers with compound bases may not find a single base to + combine with unless all arguments are processed at once. + Post-processing may be necessary in such cases. + {c.f. https://github.com/sympy/sympy/issues/5728} + + >>> a = sqrt(x*sqrt(y)) + >>> a**3 + (x*sqrt(y))**(3/2) + >>> Mul(a,a,a) + (x*sqrt(y))**(3/2) + >>> a*a*a + x*sqrt(y)*sqrt(x*sqrt(y)) + >>> _.subs(a.base, z).subs(z, a.base) + (x*sqrt(y))**(3/2) + + - If more than two terms are being multiplied then all the + previous terms will be re-processed for each new argument. + So if each of ``a``, ``b`` and ``c`` were :class:`Mul` + expression, then ``a*b*c`` (or building up the product + with ``*=``) will process all the arguments of ``a`` and + ``b`` twice: once when ``a*b`` is computed and again when + ``c`` is multiplied. + + Using ``Mul(a, b, c)`` will process all arguments once. + + * The results of Mul are cached according to arguments, so flatten + will only be called once for ``Mul(a, b, c)``. If you can + structure a calculation so the arguments are most likely to be + repeats then this can save time in computing the answer. For + example, say you had a Mul, M, that you wished to divide by ``d[i]`` + and multiply by ``n[i]`` and you suspect there are many repeats + in ``n``. It would be better to compute ``M*n[i]/d[i]`` rather + than ``M/d[i]*n[i]`` since every time n[i] is a repeat, the + product, ``M*n[i]`` will be returned without flattening -- the + cached value will be returned. If you divide by the ``d[i]`` + first (and those are more unique than the ``n[i]``) then that will + create a new Mul, ``M/d[i]`` the args of which will be traversed + again when it is multiplied by ``n[i]``. + + {c.f. https://github.com/sympy/sympy/issues/5706} + + This consideration is moot if the cache is turned off. + + NB + -- + The validity of the above notes depends on the implementation + details of Mul and flatten which may change at any time. Therefore, + you should only consider them when your code is highly performance + sensitive. + + Removal of 1 from the sequence is already handled by AssocOp.__new__. + """ + + from sympy.calculus.accumulationbounds import AccumBounds + from sympy.matrices.expressions import MatrixExpr + rv = None + if len(seq) == 2: + a, b = seq + if b.is_Rational: + a, b = b, a + seq = [a, b] + assert a is not S.One + if a.is_Rational and not a.is_zero: + r, b = b.as_coeff_Mul() + if b.is_Add: + if r is not S.One: # 2-arg hack + # leave the Mul as a Mul? + ar = a*r + if ar is S.One: + arb = b + else: + arb = cls(a*r, b, evaluate=False) + rv = [arb], [], None + elif global_parameters.distribute and b.is_commutative: + newb = Add(*[_keep_coeff(a, bi) for bi in b.args]) + rv = [newb], [], None + if rv: + return rv + + # apply associativity, separate commutative part of seq + c_part = [] # out: commutative factors + nc_part = [] # out: non-commutative factors + + nc_seq = [] + + coeff = S.One # standalone term + # e.g. 3 * ... + + c_powers = [] # (base,exp) n + # e.g. (x,n) for x + + num_exp = [] # (num-base, exp) y + # e.g. (3, y) for ... * 3 * ... + + neg1e = S.Zero # exponent on -1 extracted from Number-based Pow and I + + pnum_rat = {} # (num-base, Rat-exp) 1/2 + # e.g. (3, 1/2) for ... * 3 * ... + + order_symbols = None + + # --- PART 1 --- + # + # "collect powers and coeff": + # + # o coeff + # o c_powers + # o num_exp + # o neg1e + # o pnum_rat + # + # NOTE: this is optimized for all-objects-are-commutative case + for o in seq: + # O(x) + if o.is_Order: + o, order_symbols = o.as_expr_variables(order_symbols) + + # Mul([...]) + if o.is_Mul: + if o.is_commutative: + seq.extend(o.args) # XXX zerocopy? + + else: + # NCMul can have commutative parts as well + for q in o.args: + if q.is_commutative: + seq.append(q) + else: + nc_seq.append(q) + + # append non-commutative marker, so we don't forget to + # process scheduled non-commutative objects + seq.append(NC_Marker) + + continue + + # 3 + elif o.is_Number: + if o is S.NaN or coeff is S.ComplexInfinity and o.is_zero: + # we know for sure the result will be nan + return [S.NaN], [], None + elif coeff.is_Number or isinstance(coeff, AccumBounds): # it could be zoo + coeff *= o + if coeff is S.NaN: + # we know for sure the result will be nan + return [S.NaN], [], None + continue + + elif isinstance(o, AccumBounds): + coeff = o.__mul__(coeff) + continue + + elif o is S.ComplexInfinity: + if not coeff: + # 0 * zoo = NaN + return [S.NaN], [], None + coeff = S.ComplexInfinity + continue + + elif not coeff and isinstance(o, Add) and any( + _ in (S.NegativeInfinity, S.ComplexInfinity, S.Infinity) + for __ in o.args for _ in Mul.make_args(__)): + # e.g 0 * (x + oo) = NaN but not + # 0 * (1 + Integral(x, (x, 0, oo))) which is + # treated like 0 * x -> 0 + return [S.NaN], [], None + + elif o is S.ImaginaryUnit: + neg1e += S.Half + continue + + elif o.is_commutative: + # e + # o = b + b, e = o.as_base_exp() + + # y + # 3 + if o.is_Pow: + if b.is_Number: + + # get all the factors with numeric base so they can be + # combined below, but don't combine negatives unless + # the exponent is an integer + if e.is_Rational: + if e.is_Integer: + coeff *= Pow(b, e) # it is an unevaluated power + continue + elif e.is_negative: # also a sign of an unevaluated power + seq.append(Pow(b, e)) + continue + elif b.is_negative: + neg1e += e + b = -b + if b is not S.One: + pnum_rat.setdefault(b, []).append(e) + continue + elif b.is_positive or e.is_integer: + num_exp.append((b, e)) + continue + + c_powers.append((b, e)) + + # NON-COMMUTATIVE + # TODO: Make non-commutative exponents not combine automatically + else: + if o is not NC_Marker: + nc_seq.append(o) + + # process nc_seq (if any) + while nc_seq: + o = nc_seq.pop(0) + if not nc_part: + nc_part.append(o) + continue + + # b c b+c + # try to combine last terms: a * a -> a + o1 = nc_part.pop() + b1, e1 = o1.as_base_exp() + b2, e2 = o.as_base_exp() + new_exp = e1 + e2 + # Only allow powers to combine if the new exponent is + # not an Add. This allow things like a**2*b**3 == a**5 + # if a.is_commutative == False, but prohibits + # a**x*a**y and x**a*x**b from combining (x,y commute). + if b1 == b2 and (not new_exp.is_Add): + o12 = b1 ** new_exp + + # now o12 could be a commutative object + if o12.is_commutative: + seq.append(o12) + continue + else: + nc_seq.insert(0, o12) + + else: + nc_part.extend([o1, o]) + + # We do want a combined exponent if it would not be an Add, such as + # y 2y 3y + # x * x -> x + # We determine if two exponents have the same term by using + # as_coeff_Mul. + # + # Unfortunately, this isn't smart enough to consider combining into + # exponents that might already be adds, so things like: + # z - y y + # x * x will be left alone. This is because checking every possible + # combination can slow things down. + + # gather exponents of common bases... + def _gather(c_powers): + common_b = {} # b:e + for b, e in c_powers: + co = e.as_coeff_Mul() + common_b.setdefault(b, {}).setdefault( + co[1], []).append(co[0]) + for b, d in common_b.items(): + for di, li in d.items(): + d[di] = Add(*li) + new_c_powers = [] + for b, e in common_b.items(): + new_c_powers.extend([(b, c*t) for t, c in e.items()]) + return new_c_powers + + # in c_powers + c_powers = _gather(c_powers) + + # and in num_exp + num_exp = _gather(num_exp) + + # --- PART 2 --- + # + # o process collected powers (x**0 -> 1; x**1 -> x; otherwise Pow) + # o combine collected powers (2**x * 3**x -> 6**x) + # with numeric base + + # ................................ + # now we have: + # - coeff: + # - c_powers: (b, e) + # - num_exp: (2, e) + # - pnum_rat: {(1/3, [1/3, 2/3, 1/4])} + + # 0 1 + # x -> 1 x -> x + + # this should only need to run twice; if it fails because + # it needs to be run more times, perhaps this should be + # changed to a "while True" loop -- the only reason it + # isn't such now is to allow a less-than-perfect result to + # be obtained rather than raising an error or entering an + # infinite loop + for i in range(2): + new_c_powers = [] + changed = False + for b, e in c_powers: + if e.is_zero: + # canceling out infinities yields NaN + if (b.is_Add or b.is_Mul) and any(infty in b.args + for infty in (S.ComplexInfinity, S.Infinity, + S.NegativeInfinity)): + return [S.NaN], [], None + continue + if e is S.One: + if b.is_Number: + coeff *= b + continue + p = b + if e is not S.One: + p = Pow(b, e) + # check to make sure that the base doesn't change + # after exponentiation; to allow for unevaluated + # Pow, we only do so if b is not already a Pow + if p.is_Pow and not b.is_Pow: + bi = b + b, e = p.as_base_exp() + if b != bi: + changed = True + c_part.append(p) + new_c_powers.append((b, e)) + # there might have been a change, but unless the base + # matches some other base, there is nothing to do + if changed and len({ + b for b, e in new_c_powers}) != len(new_c_powers): + # start over again + c_part = [] + c_powers = _gather(new_c_powers) + else: + break + + # x x x + # 2 * 3 -> 6 + inv_exp_dict = {} # exp:Mul(num-bases) x x + # e.g. x:6 for ... * 2 * 3 * ... + for b, e in num_exp: + inv_exp_dict.setdefault(e, []).append(b) + for e, b in inv_exp_dict.items(): + inv_exp_dict[e] = cls(*b) + c_part.extend([Pow(b, e) for e, b in inv_exp_dict.items() if e]) + + # b, e -> e' = sum(e), b + # {(1/5, [1/3]), (1/2, [1/12, 1/4]} -> {(1/3, [1/5, 1/2])} + comb_e = {} + for b, e in pnum_rat.items(): + comb_e.setdefault(Add(*e), []).append(b) + del pnum_rat + # process them, reducing exponents to values less than 1 + # and updating coeff if necessary else adding them to + # num_rat for further processing + num_rat = [] + for e, b in comb_e.items(): + b = cls(*b) + if e.q == 1: + coeff *= Pow(b, e) + continue + if e.p > e.q: + e_i, ep = divmod(e.p, e.q) + coeff *= Pow(b, e_i) + e = Rational(ep, e.q) + num_rat.append((b, e)) + del comb_e + + # extract gcd of bases in num_rat + # 2**(1/3)*6**(1/4) -> 2**(1/3+1/4)*3**(1/4) + pnew = defaultdict(list) + i = 0 # steps through num_rat which may grow + while i < len(num_rat): + bi, ei = num_rat[i] + if bi == 1: + i += 1 + continue + grow = [] + for j in range(i + 1, len(num_rat)): + bj, ej = num_rat[j] + g = bi.gcd(bj) + if g is not S.One: + # 4**r1*6**r2 -> 2**(r1+r2) * 2**r1 * 3**r2 + # this might have a gcd with something else + e = ei + ej + if e.q == 1: + coeff *= Pow(g, e) + else: + if e.p > e.q: + e_i, ep = divmod(e.p, e.q) # change e in place + coeff *= Pow(g, e_i) + e = Rational(ep, e.q) + grow.append((g, e)) + # update the jth item + num_rat[j] = (bj/g, ej) + # update bi that we are checking with + bi = bi/g + if bi is S.One: + break + if bi is not S.One: + obj = Pow(bi, ei) + if obj.is_Number: + coeff *= obj + else: + # changes like sqrt(12) -> 2*sqrt(3) + for obj in Mul.make_args(obj): + if obj.is_Number: + coeff *= obj + else: + assert obj.is_Pow + bi, ei = obj.args + pnew[ei].append(bi) + + num_rat.extend(grow) + i += 1 + + # combine bases of the new powers + for e, b in pnew.items(): + pnew[e] = cls(*b) + + # handle -1 and I + if neg1e: + # treat I as (-1)**(1/2) and compute -1's total exponent + p, q = neg1e.as_numer_denom() + # if the integer part is odd, extract -1 + n, p = divmod(p, q) + if n % 2: + coeff = -coeff + # if it's a multiple of 1/2 extract I + if q == 2: + c_part.append(S.ImaginaryUnit) + elif p: + # see if there is any positive base this power of + # -1 can join + neg1e = Rational(p, q) + for e, b in pnew.items(): + if e == neg1e and b.is_positive: + pnew[e] = -b + break + else: + # keep it separate; we've already evaluated it as + # much as possible so evaluate=False + c_part.append(Pow(S.NegativeOne, neg1e, evaluate=False)) + + # add all the pnew powers + c_part.extend([Pow(b, e) for e, b in pnew.items()]) + + # oo, -oo + if coeff in (S.Infinity, S.NegativeInfinity): + def _handle_for_oo(c_part, coeff_sign): + new_c_part = [] + for t in c_part: + if t.is_extended_positive: + continue + if t.is_extended_negative: + coeff_sign *= -1 + continue + new_c_part.append(t) + return new_c_part, coeff_sign + c_part, coeff_sign = _handle_for_oo(c_part, 1) + nc_part, coeff_sign = _handle_for_oo(nc_part, coeff_sign) + coeff *= coeff_sign + + # zoo + if coeff is S.ComplexInfinity: + # zoo might be + # infinite_real + bounded_im + # bounded_real + infinite_im + # infinite_real + infinite_im + # and non-zero real or imaginary will not change that status. + c_part = [c for c in c_part if not (fuzzy_not(c.is_zero) and + c.is_extended_real is not None)] + nc_part = [c for c in nc_part if not (fuzzy_not(c.is_zero) and + c.is_extended_real is not None)] + + # 0 + elif coeff.is_zero: + # we know for sure the result will be 0 except the multiplicand + # is infinity or a matrix + if any(isinstance(c, MatrixExpr) for c in nc_part): + return [coeff], nc_part, order_symbols + if any(c.is_finite == False for c in c_part): + return [S.NaN], [], order_symbols + return [coeff], [], order_symbols + + # check for straggling Numbers that were produced + _new = [] + for i in c_part: + if i.is_Number: + coeff *= i + else: + _new.append(i) + c_part = _new + + # order commutative part canonically + _mulsort(c_part) + + # current code expects coeff to be always in slot-0 + if coeff is not S.One: + c_part.insert(0, coeff) + + # we are done + if (global_parameters.distribute and not nc_part and len(c_part) == 2 and + c_part[0].is_Number and c_part[0].is_finite and c_part[1].is_Add): + # 2*(1+a) -> 2 + 2 * a + coeff = c_part[0] + c_part = [Add(*[coeff*f for f in c_part[1].args])] + + return c_part, nc_part, order_symbols + + def _eval_power(self, expt): + + # don't break up NC terms: (A*B)**3 != A**3*B**3, it is A*B*A*B*A*B + cargs, nc = self.args_cnc(split_1=False) + + if expt.is_Integer: + return Mul(*[Pow(b, expt, evaluate=False) for b in cargs]) * \ + Pow(Mul._from_args(nc), expt, evaluate=False) + if expt.is_Rational and expt.q == 2: + if self.is_imaginary: + a = self.as_real_imag()[1] + if a.is_Rational: + n, d = abs(a/2).as_numer_denom() + n, t = integer_nthroot(n, 2) + if t: + d, t = integer_nthroot(d, 2) + if t: + from sympy.functions.elementary.complexes import sign + r = sympify(n)/d + return _unevaluated_Mul(r**expt.p, (1 + sign(a)*S.ImaginaryUnit)**expt.p) + + p = Pow(self, expt, evaluate=False) + + if expt.is_Rational or expt.is_Float: + return p._eval_expand_power_base() + + return p + + @classmethod + def class_key(cls): + return 3, 0, cls.__name__ + + def _eval_evalf(self, prec): + c, m = self.as_coeff_Mul() + if c is S.NegativeOne: + if m.is_Mul: + rv = -AssocOp._eval_evalf(m, prec) + else: + mnew = m._eval_evalf(prec) + if mnew is not None: + m = mnew + rv = -m + else: + rv = AssocOp._eval_evalf(self, prec) + if rv.is_number: + return rv.expand() + return rv + + @property + def _mpc_(self): + """ + Convert self to an mpmath mpc if possible + """ + from .numbers import Float + im_part, imag_unit = self.as_coeff_Mul() + if imag_unit is not S.ImaginaryUnit: + # ValueError may seem more reasonable but since it's a @property, + # we need to use AttributeError to keep from confusing things like + # hasattr. + raise AttributeError("Cannot convert Mul to mpc. Must be of the form Number*I") + + return (Float(0)._mpf_, Float(im_part)._mpf_) + + @cacheit + def as_two_terms(self): + """Return head and tail of self. + + This is the most efficient way to get the head and tail of an + expression. + + - if you want only the head, use self.args[0]; + - if you want to process the arguments of the tail then use + self.as_coef_mul() which gives the head and a tuple containing + the arguments of the tail when treated as a Mul. + - if you want the coefficient when self is treated as an Add + then use self.as_coeff_add()[0] + + Examples + ======== + + >>> from sympy.abc import x, y + >>> (3*x*y).as_two_terms() + (3, x*y) + """ + args = self.args + + if len(args) == 1: + return S.One, self + elif len(args) == 2: + return args + + else: + return args[0], self._new_rawargs(*args[1:]) + + @cacheit + def as_coeff_mul(self, *deps, rational=True, **kwargs): + if deps: + l1, l2 = sift(self.args, lambda x: x.has(*deps), binary=True) + return self._new_rawargs(*l2), tuple(l1) + args = self.args + if args[0].is_Number: + if not rational or args[0].is_Rational: + return args[0], args[1:] + elif args[0].is_extended_negative: + return S.NegativeOne, (-args[0],) + args[1:] + return S.One, args + + def as_coeff_Mul(self, rational=False): + """ + Efficiently extract the coefficient of a product. + """ + coeff, args = self.args[0], self.args[1:] + + if coeff.is_Number: + if not rational or coeff.is_Rational: + if len(args) == 1: + return coeff, args[0] + else: + return coeff, self._new_rawargs(*args) + elif coeff.is_extended_negative: + return S.NegativeOne, self._new_rawargs(*((-coeff,) + args)) + return S.One, self + + def as_real_imag(self, deep=True, **hints): + from sympy.functions.elementary.complexes import Abs, im, re + other = [] + coeffr = [] + coeffi = [] + addterms = S.One + for a in self.args: + r, i = a.as_real_imag() + if i.is_zero: + coeffr.append(r) + elif r.is_zero: + coeffi.append(i*S.ImaginaryUnit) + elif a.is_commutative: + aconj = a.conjugate() if other else None + # search for complex conjugate pairs: + for i, x in enumerate(other): + if x == aconj: + coeffr.append(Abs(x)**2) + del other[i] + break + else: + if a.is_Add: + addterms *= a + else: + other.append(a) + else: + other.append(a) + m = self.func(*other) + if hints.get('ignore') == m: + return + if len(coeffi) % 2: + imco = im(coeffi.pop(0)) + # all other pairs make a real factor; they will be + # put into reco below + else: + imco = S.Zero + reco = self.func(*(coeffr + coeffi)) + r, i = (reco*re(m), reco*im(m)) + if addterms == 1: + if m == 1: + if imco.is_zero: + return (reco, S.Zero) + else: + return (S.Zero, reco*imco) + if imco is S.Zero: + return (r, i) + return (-imco*i, imco*r) + from .function import expand_mul + addre, addim = expand_mul(addterms, deep=False).as_real_imag() + if imco is S.Zero: + return (r*addre - i*addim, i*addre + r*addim) + else: + r, i = -imco*i, imco*r + return (r*addre - i*addim, r*addim + i*addre) + + @staticmethod + def _expandsums(sums): + """ + Helper function for _eval_expand_mul. + + sums must be a list of instances of Basic. + """ + + L = len(sums) + if L == 1: + return sums[0].args + terms = [] + left = Mul._expandsums(sums[:L//2]) + right = Mul._expandsums(sums[L//2:]) + + terms = [Mul(a, b) for a in left for b in right] + added = Add(*terms) + return Add.make_args(added) # it may have collapsed down to one term + + def _eval_expand_mul(self, **hints): + from sympy.simplify.radsimp import fraction + + # Handle things like 1/(x*(x + 1)), which are automatically converted + # to 1/x*1/(x + 1) + expr = self + # default matches fraction's default + n, d = fraction(expr, hints.get('exact', False)) + if d.is_Mul: + n, d = [i._eval_expand_mul(**hints) if i.is_Mul else i + for i in (n, d)] + expr = n/d + if not expr.is_Mul: + return expr + + plain, sums, rewrite = [], [], False + for factor in expr.args: + if factor.is_Add: + sums.append(factor) + rewrite = True + else: + if factor.is_commutative: + plain.append(factor) + else: + sums.append(Basic(factor)) # Wrapper + + if not rewrite: + return expr + else: + plain = self.func(*plain) + if sums: + deep = hints.get("deep", False) + terms = self.func._expandsums(sums) + args = [] + for term in terms: + t = self.func(plain, term) + if t.is_Mul and any(a.is_Add for a in t.args) and deep: + t = t._eval_expand_mul() + args.append(t) + return Add(*args) + else: + return plain + + @cacheit + def _eval_derivative(self, s): + args = list(self.args) + terms = [] + for i in range(len(args)): + d = args[i].diff(s) + if d: + # Note: reduce is used in step of Mul as Mul is unable to + # handle subtypes and operation priority: + terms.append(reduce(lambda x, y: x*y, (args[:i] + [d] + args[i + 1:]), S.One)) + return Add.fromiter(terms) + + @cacheit + def _eval_derivative_n_times(self, s, n): + from .function import AppliedUndef + from .symbol import Symbol, symbols, Dummy + if not isinstance(s, (AppliedUndef, Symbol)): + # other types of s may not be well behaved, e.g. + # (cos(x)*sin(y)).diff([[x, y, z]]) + return super()._eval_derivative_n_times(s, n) + from .numbers import Integer + args = self.args + m = len(args) + if isinstance(n, (int, Integer)): + # https://en.wikipedia.org/wiki/General_Leibniz_rule#More_than_two_factors + terms = [] + from sympy.ntheory.multinomial import multinomial_coefficients_iterator + for kvals, c in multinomial_coefficients_iterator(m, n): + p = Mul(*[arg.diff((s, k)) for k, arg in zip(kvals, args)]) + terms.append(c * p) + return Add(*terms) + from sympy.concrete.summations import Sum + from sympy.functions.combinatorial.factorials import factorial + from sympy.functions.elementary.miscellaneous import Max + kvals = symbols("k1:%i" % m, cls=Dummy) + klast = n - sum(kvals) + nfact = factorial(n) + e, l = (# better to use the multinomial? + nfact/prod(map(factorial, kvals))/factorial(klast)*\ + Mul(*[args[t].diff((s, kvals[t])) for t in range(m-1)])*\ + args[-1].diff((s, Max(0, klast))), + [(k, 0, n) for k in kvals]) + return Sum(e, *l) + + def _eval_difference_delta(self, n, step): + from sympy.series.limitseq import difference_delta as dd + arg0 = self.args[0] + rest = Mul(*self.args[1:]) + return (arg0.subs(n, n + step) * dd(rest, n, step) + dd(arg0, n, step) * + rest) + + def _matches_simple(self, expr, repl_dict): + # handle (w*3).matches('x*5') -> {w: x*5/3} + coeff, terms = self.as_coeff_Mul() + terms = Mul.make_args(terms) + if len(terms) == 1: + newexpr = self.__class__._combine_inverse(expr, coeff) + return terms[0].matches(newexpr, repl_dict) + return + + def matches(self, expr, repl_dict=None, old=False): + expr = sympify(expr) + if self.is_commutative and expr.is_commutative: + return self._matches_commutative(expr, repl_dict, old) + elif self.is_commutative is not expr.is_commutative: + return None + + # Proceed only if both both expressions are non-commutative + c1, nc1 = self.args_cnc() + c2, nc2 = expr.args_cnc() + c1, c2 = [c or [1] for c in [c1, c2]] + + # TODO: Should these be self.func? + comm_mul_self = Mul(*c1) + comm_mul_expr = Mul(*c2) + + repl_dict = comm_mul_self.matches(comm_mul_expr, repl_dict, old) + + # If the commutative arguments didn't match and aren't equal, then + # then the expression as a whole doesn't match + if not repl_dict and c1 != c2: + return None + + # Now match the non-commutative arguments, expanding powers to + # multiplications + nc1 = Mul._matches_expand_pows(nc1) + nc2 = Mul._matches_expand_pows(nc2) + + repl_dict = Mul._matches_noncomm(nc1, nc2, repl_dict) + + return repl_dict or None + + @staticmethod + def _matches_expand_pows(arg_list): + new_args = [] + for arg in arg_list: + if arg.is_Pow and arg.exp > 0: + new_args.extend([arg.base] * arg.exp) + else: + new_args.append(arg) + return new_args + + @staticmethod + def _matches_noncomm(nodes, targets, repl_dict=None): + """Non-commutative multiplication matcher. + + `nodes` is a list of symbols within the matcher multiplication + expression, while `targets` is a list of arguments in the + multiplication expression being matched against. + """ + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + # List of possible future states to be considered + agenda = [] + # The current matching state, storing index in nodes and targets + state = (0, 0) + node_ind, target_ind = state + # Mapping between wildcard indices and the index ranges they match + wildcard_dict = {} + + while target_ind < len(targets) and node_ind < len(nodes): + node = nodes[node_ind] + + if node.is_Wild: + Mul._matches_add_wildcard(wildcard_dict, state) + + states_matches = Mul._matches_new_states(wildcard_dict, state, + nodes, targets) + if states_matches: + new_states, new_matches = states_matches + agenda.extend(new_states) + if new_matches: + for match in new_matches: + repl_dict[match] = new_matches[match] + if not agenda: + return None + else: + state = agenda.pop() + node_ind, target_ind = state + + return repl_dict + + @staticmethod + def _matches_add_wildcard(dictionary, state): + node_ind, target_ind = state + if node_ind in dictionary: + begin, end = dictionary[node_ind] + dictionary[node_ind] = (begin, target_ind) + else: + dictionary[node_ind] = (target_ind, target_ind) + + @staticmethod + def _matches_new_states(dictionary, state, nodes, targets): + node_ind, target_ind = state + node = nodes[node_ind] + target = targets[target_ind] + + # Don't advance at all if we've exhausted the targets but not the nodes + if target_ind >= len(targets) - 1 and node_ind < len(nodes) - 1: + return None + + if node.is_Wild: + match_attempt = Mul._matches_match_wilds(dictionary, node_ind, + nodes, targets) + if match_attempt: + # If the same node has been matched before, don't return + # anything if the current match is diverging from the previous + # match + other_node_inds = Mul._matches_get_other_nodes(dictionary, + nodes, node_ind) + for ind in other_node_inds: + other_begin, other_end = dictionary[ind] + curr_begin, curr_end = dictionary[node_ind] + + other_targets = targets[other_begin:other_end + 1] + current_targets = targets[curr_begin:curr_end + 1] + + for curr, other in zip(current_targets, other_targets): + if curr != other: + return None + + # A wildcard node can match more than one target, so only the + # target index is advanced + new_state = [(node_ind, target_ind + 1)] + # Only move on to the next node if there is one + if node_ind < len(nodes) - 1: + new_state.append((node_ind + 1, target_ind + 1)) + return new_state, match_attempt + else: + # If we're not at a wildcard, then make sure we haven't exhausted + # nodes but not targets, since in this case one node can only match + # one target + if node_ind >= len(nodes) - 1 and target_ind < len(targets) - 1: + return None + + match_attempt = node.matches(target) + + if match_attempt: + return [(node_ind + 1, target_ind + 1)], match_attempt + elif node == target: + return [(node_ind + 1, target_ind + 1)], None + else: + return None + + @staticmethod + def _matches_match_wilds(dictionary, wildcard_ind, nodes, targets): + """Determine matches of a wildcard with sub-expression in `target`.""" + wildcard = nodes[wildcard_ind] + begin, end = dictionary[wildcard_ind] + terms = targets[begin:end + 1] + # TODO: Should this be self.func? + mult = Mul(*terms) if len(terms) > 1 else terms[0] + return wildcard.matches(mult) + + @staticmethod + def _matches_get_other_nodes(dictionary, nodes, node_ind): + """Find other wildcards that may have already been matched.""" + ind_node = nodes[node_ind] + return [ind for ind in dictionary if nodes[ind] == ind_node] + + @staticmethod + def _combine_inverse(lhs, rhs): + """ + Returns lhs/rhs, but treats arguments like symbols, so things + like oo/oo return 1 (instead of a nan) and ``I`` behaves like + a symbol instead of sqrt(-1). + """ + from sympy.simplify.simplify import signsimp + from .symbol import Dummy + if lhs == rhs: + return S.One + + def check(l, r): + if l.is_Float and r.is_comparable: + # if both objects are added to 0 they will share the same "normalization" + # and are more likely to compare the same. Since Add(foo, 0) will not allow + # the 0 to pass, we use __add__ directly. + return l.__add__(0) == r.evalf().__add__(0) + return False + if check(lhs, rhs) or check(rhs, lhs): + return S.One + if any(i.is_Pow or i.is_Mul for i in (lhs, rhs)): + # gruntz and limit wants a literal I to not combine + # with a power of -1 + d = Dummy('I') + _i = {S.ImaginaryUnit: d} + i_ = {d: S.ImaginaryUnit} + a = lhs.xreplace(_i).as_powers_dict() + b = rhs.xreplace(_i).as_powers_dict() + blen = len(b) + for bi in tuple(b.keys()): + if bi in a: + a[bi] -= b.pop(bi) + if not a[bi]: + a.pop(bi) + if len(b) != blen: + lhs = Mul(*[k**v for k, v in a.items()]).xreplace(i_) + rhs = Mul(*[k**v for k, v in b.items()]).xreplace(i_) + rv = lhs/rhs + srv = signsimp(rv) + return srv if srv.is_Number else rv + + def as_powers_dict(self): + d = defaultdict(int) + for term in self.args: + for b, e in term.as_powers_dict().items(): + d[b] += e + return d + + def as_numer_denom(self): + # don't use _from_args to rebuild the numerators and denominators + # as the order is not guaranteed to be the same once they have + # been separated from each other + numers, denoms = list(zip(*[f.as_numer_denom() for f in self.args])) + return self.func(*numers), self.func(*denoms) + + def as_base_exp(self): + e1 = None + bases = [] + nc = 0 + for m in self.args: + b, e = m.as_base_exp() + if not b.is_commutative: + nc += 1 + if e1 is None: + e1 = e + elif e != e1 or nc > 1 or not e.is_Integer: + return self, S.One + bases.append(b) + return self.func(*bases), e1 + + def _eval_is_polynomial(self, syms): + return all(term._eval_is_polynomial(syms) for term in self.args) + + def _eval_is_rational_function(self, syms): + return all(term._eval_is_rational_function(syms) for term in self.args) + + def _eval_is_meromorphic(self, x, a): + return _fuzzy_group((arg.is_meromorphic(x, a) for arg in self.args), + quick_exit=True) + + def _eval_is_algebraic_expr(self, syms): + return all(term._eval_is_algebraic_expr(syms) for term in self.args) + + _eval_is_commutative = lambda self: _fuzzy_group( + a.is_commutative for a in self.args) + + def _eval_is_complex(self): + comp = _fuzzy_group(a.is_complex for a in self.args) + if comp is False: + if any(a.is_infinite for a in self.args): + if any(a.is_zero is not False for a in self.args): + return None + return False + return comp + + def _eval_is_zero_infinite_helper(self): + # + # Helper used by _eval_is_zero and _eval_is_infinite. + # + # Three-valued logic is tricky so let us reason this carefully. It + # would be nice to say that we just check is_zero/is_infinite in all + # args but we need to be careful about the case that one arg is zero + # and another is infinite like Mul(0, oo) or more importantly a case + # where it is not known if the arguments are zero or infinite like + # Mul(y, 1/x). If either y or x could be zero then there is a + # *possibility* that we have Mul(0, oo) which should give None for both + # is_zero and is_infinite. + # + # We keep track of whether we have seen a zero or infinity but we also + # need to keep track of whether we have *possibly* seen one which + # would be indicated by None. + # + # For each argument there is the possibility that is_zero might give + # True, False or None and likewise that is_infinite might give True, + # False or None, giving 9 combinations. The True cases for is_zero and + # is_infinite are mutually exclusive though so there are 3 main cases: + # + # - is_zero = True + # - is_infinite = True + # - is_zero and is_infinite are both either False or None + # + # At the end seen_zero and seen_infinite can be any of 9 combinations + # of True/False/None. Unless one is False though we cannot return + # anything except None: + # + # - is_zero=True needs seen_zero=True and seen_infinite=False + # - is_zero=False needs seen_zero=False + # - is_infinite=True needs seen_infinite=True and seen_zero=False + # - is_infinite=False needs seen_infinite=False + # - anything else gives both is_zero=None and is_infinite=None + # + # The loop only sets the flags to True or None and never back to False. + # Hence as soon as neither flag is False we exit early returning None. + # In particular as soon as we encounter a single arg that has + # is_zero=is_infinite=None we exit. This is a common case since it is + # the default assumptions for a Symbol and also the case for most + # expressions containing such a symbol. The early exit gives a big + # speedup for something like Mul(*symbols('x:1000')).is_zero. + # + seen_zero = seen_infinite = False + + for a in self.args: + if a.is_zero: + if seen_infinite is not False: + return None, None + seen_zero = True + elif a.is_infinite: + if seen_zero is not False: + return None, None + seen_infinite = True + else: + if seen_zero is False and a.is_zero is None: + if seen_infinite is not False: + return None, None + seen_zero = None + if seen_infinite is False and a.is_infinite is None: + if seen_zero is not False: + return None, None + seen_infinite = None + + return seen_zero, seen_infinite + + def _eval_is_zero(self): + # True iff any arg is zero and no arg is infinite but need to handle + # three valued logic carefully. + seen_zero, seen_infinite = self._eval_is_zero_infinite_helper() + + if seen_zero is False: + return False + elif seen_zero is True and seen_infinite is False: + return True + else: + return None + + def _eval_is_infinite(self): + # True iff any arg is infinite and no arg is zero but need to handle + # three valued logic carefully. + seen_zero, seen_infinite = self._eval_is_zero_infinite_helper() + + if seen_infinite is True and seen_zero is False: + return True + elif seen_infinite is False: + return False + else: + return None + + # We do not need to implement _eval_is_finite because the assumptions + # system can infer it from finite = not infinite. + + def _eval_is_rational(self): + r = _fuzzy_group((a.is_rational for a in self.args), quick_exit=True) + if r: + return r + elif r is False: + # All args except one are rational + if all(a.is_zero is False for a in self.args): + return False + + def _eval_is_algebraic(self): + r = _fuzzy_group((a.is_algebraic for a in self.args), quick_exit=True) + if r: + return r + elif r is False: + # All args except one are algebraic + if all(a.is_zero is False for a in self.args): + return False + + # without involving odd/even checks this code would suffice: + #_eval_is_integer = lambda self: _fuzzy_group( + # (a.is_integer for a in self.args), quick_exit=True) + def _eval_is_integer(self): + is_rational = self._eval_is_rational() + if is_rational is False: + return False + + numerators = [] + denominators = [] + unknown = False + for a in self.args: + hit = False + if a.is_integer: + if abs(a) is not S.One: + numerators.append(a) + elif a.is_Rational: + n, d = a.as_numer_denom() + if abs(n) is not S.One: + numerators.append(n) + if d is not S.One: + denominators.append(d) + elif a.is_Pow: + b, e = a.as_base_exp() + if not b.is_integer or not e.is_integer: + hit = unknown = True + if e.is_negative: + denominators.append(2 if a is S.Half else + Pow(a, S.NegativeOne)) + elif not hit: + # int b and pos int e: a = b**e is integer + assert not e.is_positive + # for rational self and e equal to zero: a = b**e is 1 + assert not e.is_zero + return # sign of e unknown -> self.is_integer unknown + else: + # x**2, 2**x, or x**y with x and y int-unknown -> unknown + return + else: + return + + if not denominators and not unknown: + return True + + allodd = lambda x: all(i.is_odd for i in x) + alleven = lambda x: all(i.is_even for i in x) + anyeven = lambda x: any(i.is_even for i in x) + + from .relational import is_gt + if not numerators and denominators and all( + is_gt(_, S.One) for _ in denominators): + return False + elif unknown: + return + elif allodd(numerators) and anyeven(denominators): + return False + elif anyeven(numerators) and denominators == [2]: + return True + elif alleven(numerators) and allodd(denominators + ) and (Mul(*denominators, evaluate=False) - 1 + ).is_positive: + return False + if len(denominators) == 1: + d = denominators[0] + if d.is_Integer and d.is_even: + # if minimal power of 2 in num vs den is not + # negative then we have an integer + if (Add(*[i.as_base_exp()[1] for i in + numerators if i.is_even]) - trailing(d.p) + ).is_nonnegative: + return True + if len(numerators) == 1: + n = numerators[0] + if n.is_Integer and n.is_even: + # if minimal power of 2 in den vs num is positive + # then we have have a non-integer + if (Add(*[i.as_base_exp()[1] for i in + denominators if i.is_even]) - trailing(n.p) + ).is_positive: + return False + + def _eval_is_polar(self): + has_polar = any(arg.is_polar for arg in self.args) + return has_polar and \ + all(arg.is_polar or arg.is_positive for arg in self.args) + + def _eval_is_extended_real(self): + return self._eval_real_imag(True) + + def _eval_real_imag(self, real): + zero = False + t_not_re_im = None + + for t in self.args: + if (t.is_complex or t.is_infinite) is False and t.is_extended_real is False: + return False + elif t.is_imaginary: # I + real = not real + elif t.is_extended_real: # 2 + if not zero: + z = t.is_zero + if not z and zero is False: + zero = z + elif z: + if all(a.is_finite for a in self.args): + return True + return + elif t.is_extended_real is False: + # symbolic or literal like `2 + I` or symbolic imaginary + if t_not_re_im: + return # complex terms might cancel + t_not_re_im = t + elif t.is_imaginary is False: # symbolic like `2` or `2 + I` + if t_not_re_im: + return # complex terms might cancel + t_not_re_im = t + else: + return + + if t_not_re_im: + if t_not_re_im.is_extended_real is False: + if real: # like 3 + return zero # 3*(smthng like 2 + I or i) is not real + if t_not_re_im.is_imaginary is False: # symbolic 2 or 2 + I + if not real: # like I + return zero # I*(smthng like 2 or 2 + I) is not real + elif zero is False: + return real # can't be trumped by 0 + elif real: + return real # doesn't matter what zero is + + def _eval_is_imaginary(self): + if all(a.is_zero is False and a.is_finite for a in self.args): + return self._eval_real_imag(False) + + def _eval_is_hermitian(self): + return self._eval_herm_antiherm(True) + + def _eval_is_antihermitian(self): + return self._eval_herm_antiherm(False) + + def _eval_herm_antiherm(self, herm): + for t in self.args: + if t.is_hermitian is None or t.is_antihermitian is None: + return + if t.is_hermitian: + continue + elif t.is_antihermitian: + herm = not herm + else: + return + + if herm is not False: + return herm + + is_zero = self._eval_is_zero() + if is_zero: + return True + elif is_zero is False: + return herm + + def _eval_is_irrational(self): + for t in self.args: + a = t.is_irrational + if a: + others = list(self.args) + others.remove(t) + if all((x.is_rational and fuzzy_not(x.is_zero)) is True for x in others): + return True + return + if a is None: + return + if all(x.is_real for x in self.args): + return False + + def _eval_is_extended_positive(self): + """Return True if self is positive, False if not, and None if it + cannot be determined. + + Explanation + =========== + + This algorithm is non-recursive and works by keeping track of the + sign which changes when a negative or nonpositive is encountered. + Whether a nonpositive or nonnegative is seen is also tracked since + the presence of these makes it impossible to return True, but + possible to return False if the end result is nonpositive. e.g. + + pos * neg * nonpositive -> pos or zero -> None is returned + pos * neg * nonnegative -> neg or zero -> False is returned + """ + return self._eval_pos_neg(1) + + def _eval_pos_neg(self, sign): + saw_NON = saw_NOT = False + for t in self.args: + if t.is_extended_positive: + continue + elif t.is_extended_negative: + sign = -sign + elif t.is_zero: + if all(a.is_finite for a in self.args): + return False + return + elif t.is_extended_nonpositive: + sign = -sign + saw_NON = True + elif t.is_extended_nonnegative: + saw_NON = True + # FIXME: is_positive/is_negative is False doesn't take account of + # Symbol('x', infinite=True, extended_real=True) which has + # e.g. is_positive is False but has uncertain sign. + elif t.is_positive is False: + sign = -sign + if saw_NOT: + return + saw_NOT = True + elif t.is_negative is False: + if saw_NOT: + return + saw_NOT = True + else: + return + if sign == 1 and saw_NON is False and saw_NOT is False: + return True + if sign < 0: + return False + + def _eval_is_extended_negative(self): + return self._eval_pos_neg(-1) + + def _eval_is_odd(self): + is_integer = self._eval_is_integer() + if is_integer is not True: + return is_integer + + from sympy.simplify.radsimp import fraction + n, d = fraction(self) + if d.is_Integer and d.is_even: + # if minimal power of 2 in num vs den is + # positive then we have an even number + if (Add(*[i.as_base_exp()[1] for i in + Mul.make_args(n) if i.is_even]) - trailing(d.p) + ).is_positive: + return False + return + r, acc = True, 1 + for t in self.args: + if abs(t) is S.One: + continue + if t.is_even: + return False + if r is False: + pass + elif acc != 1 and (acc + t).is_odd: + r = False + elif t.is_even is None: + r = None + acc = t + return r + + def _eval_is_even(self): + from sympy.simplify.radsimp import fraction + n, d = fraction(self) + if n.is_Integer and n.is_even: + # if minimal power of 2 in den vs num is not + # negative then this is not an integer and + # can't be even + if (Add(*[i.as_base_exp()[1] for i in + Mul.make_args(d) if i.is_even]) - trailing(n.p) + ).is_nonnegative: + return False + + def _eval_is_composite(self): + """ + Here we count the number of arguments that have a minimum value + greater than two. + If there are more than one of such a symbol then the result is composite. + Else, the result cannot be determined. + """ + number_of_args = 0 # count of symbols with minimum value greater than one + for arg in self.args: + if not (arg.is_integer and arg.is_positive): + return None + if (arg-1).is_positive: + number_of_args += 1 + + if number_of_args > 1: + return True + + def _eval_subs(self, old, new): + from sympy.functions.elementary.complexes import sign + from sympy.ntheory.factor_ import multiplicity + from sympy.simplify.powsimp import powdenest + from sympy.simplify.radsimp import fraction + + if not old.is_Mul: + return None + + # try keep replacement literal so -2*x doesn't replace 4*x + if old.args[0].is_Number and old.args[0] < 0: + if self.args[0].is_Number: + if self.args[0] < 0: + return self._subs(-old, -new) + return None + + def base_exp(a): + # if I and -1 are in a Mul, they get both end up with + # a -1 base (see issue 6421); all we want here are the + # true Pow or exp separated into base and exponent + from sympy.functions.elementary.exponential import exp + if a.is_Pow or isinstance(a, exp): + return a.as_base_exp() + return a, S.One + + def breakup(eq): + """break up powers of eq when treated as a Mul: + b**(Rational*e) -> b**e, Rational + commutatives come back as a dictionary {b**e: Rational} + noncommutatives come back as a list [(b**e, Rational)] + """ + + (c, nc) = (defaultdict(int), []) + for a in Mul.make_args(eq): + a = powdenest(a) + (b, e) = base_exp(a) + if e is not S.One: + (co, _) = e.as_coeff_mul() + b = Pow(b, e/co) + e = co + if a.is_commutative: + c[b] += e + else: + nc.append([b, e]) + return (c, nc) + + def rejoin(b, co): + """ + Put rational back with exponent; in general this is not ok, but + since we took it from the exponent for analysis, it's ok to put + it back. + """ + + (b, e) = base_exp(b) + return Pow(b, e*co) + + def ndiv(a, b): + """if b divides a in an extractive way (like 1/4 divides 1/2 + but not vice versa, and 2/5 does not divide 1/3) then return + the integer number of times it divides, else return 0. + """ + if not b.q % a.q or not a.q % b.q: + return int(a/b) + return 0 + + # give Muls in the denominator a chance to be changed (see issue 5651) + # rv will be the default return value + rv = None + n, d = fraction(self) + self2 = self + if d is not S.One: + self2 = n._subs(old, new)/d._subs(old, new) + if not self2.is_Mul: + return self2._subs(old, new) + if self2 != self: + rv = self2 + + # Now continue with regular substitution. + + # handle the leading coefficient and use it to decide if anything + # should even be started; we always know where to find the Rational + # so it's a quick test + + co_self = self2.args[0] + co_old = old.args[0] + co_xmul = None + if co_old.is_Rational and co_self.is_Rational: + # if coeffs are the same there will be no updating to do + # below after breakup() step; so skip (and keep co_xmul=None) + if co_old != co_self: + co_xmul = co_self.extract_multiplicatively(co_old) + elif co_old.is_Rational: + return rv + + # break self and old into factors + + (c, nc) = breakup(self2) + (old_c, old_nc) = breakup(old) + + # update the coefficients if we had an extraction + # e.g. if co_self were 2*(3/35*x)**2 and co_old = 3/5 + # then co_self in c is replaced by (3/5)**2 and co_residual + # is 2*(1/7)**2 + + if co_xmul and co_xmul.is_Rational and abs(co_old) != 1: + mult = S(multiplicity(abs(co_old), co_self)) + c.pop(co_self) + if co_old in c: + c[co_old] += mult + else: + c[co_old] = mult + co_residual = co_self/co_old**mult + else: + co_residual = 1 + + # do quick tests to see if we can't succeed + + ok = True + if len(old_nc) > len(nc): + # more non-commutative terms + ok = False + elif len(old_c) > len(c): + # more commutative terms + ok = False + elif {i[0] for i in old_nc}.difference({i[0] for i in nc}): + # unmatched non-commutative bases + ok = False + elif set(old_c).difference(set(c)): + # unmatched commutative terms + ok = False + elif any(sign(c[b]) != sign(old_c[b]) for b in old_c): + # differences in sign + ok = False + if not ok: + return rv + + if not old_c: + cdid = None + else: + rat = [] + for (b, old_e) in old_c.items(): + c_e = c[b] + rat.append(ndiv(c_e, old_e)) + if not rat[-1]: + return rv + cdid = min(rat) + + if not old_nc: + ncdid = None + for i in range(len(nc)): + nc[i] = rejoin(*nc[i]) + else: + ncdid = 0 # number of nc replacements we did + take = len(old_nc) # how much to look at each time + limit = cdid or S.Infinity # max number that we can take + failed = [] # failed terms will need subs if other terms pass + i = 0 + while limit and i + take <= len(nc): + hit = False + + # the bases must be equivalent in succession, and + # the powers must be extractively compatible on the + # first and last factor but equal in between. + + rat = [] + for j in range(take): + if nc[i + j][0] != old_nc[j][0]: + break + elif j == 0: + rat.append(ndiv(nc[i + j][1], old_nc[j][1])) + elif j == take - 1: + rat.append(ndiv(nc[i + j][1], old_nc[j][1])) + elif nc[i + j][1] != old_nc[j][1]: + break + else: + rat.append(1) + j += 1 + else: + ndo = min(rat) + if ndo: + if take == 1: + if cdid: + ndo = min(cdid, ndo) + nc[i] = Pow(new, ndo)*rejoin(nc[i][0], + nc[i][1] - ndo*old_nc[0][1]) + else: + ndo = 1 + + # the left residual + + l = rejoin(nc[i][0], nc[i][1] - ndo* + old_nc[0][1]) + + # eliminate all middle terms + + mid = new + + # the right residual (which may be the same as the middle if take == 2) + + ir = i + take - 1 + r = (nc[ir][0], nc[ir][1] - ndo* + old_nc[-1][1]) + if r[1]: + if i + take < len(nc): + nc[i:i + take] = [l*mid, r] + else: + r = rejoin(*r) + nc[i:i + take] = [l*mid*r] + else: + + # there was nothing left on the right + + nc[i:i + take] = [l*mid] + + limit -= ndo + ncdid += ndo + hit = True + if not hit: + + # do the subs on this failing factor + + failed.append(i) + i += 1 + else: + + if not ncdid: + return rv + + # although we didn't fail, certain nc terms may have + # failed so we rebuild them after attempting a partial + # subs on them + + failed.extend(range(i, len(nc))) + for i in failed: + nc[i] = rejoin(*nc[i]).subs(old, new) + + # rebuild the expression + + if cdid is None: + do = ncdid + elif ncdid is None: + do = cdid + else: + do = min(ncdid, cdid) + + margs = [] + for b in c: + if b in old_c: + + # calculate the new exponent + + e = c[b] - old_c[b]*do + margs.append(rejoin(b, e)) + else: + margs.append(rejoin(b.subs(old, new), c[b])) + if cdid and not ncdid: + + # in case we are replacing commutative with non-commutative, + # we want the new term to come at the front just like the + # rest of this routine + + margs = [Pow(new, cdid)] + margs + return co_residual*self2.func(*margs)*self2.func(*nc) + + def _eval_nseries(self, x, n, logx, cdir=0): + from .function import PoleError + from sympy.functions.elementary.integers import ceiling + from sympy.series.order import Order + + def coeff_exp(term, x): + lt = term.as_coeff_exponent(x) + if lt[0].has(x): + try: + lt = term.leadterm(x) + except ValueError: + return term, S.Zero + return lt + + ords = [] + + try: + for t in self.args: + coeff, exp = t.leadterm(x) + if not coeff.has(x): + ords.append((t, exp)) + else: + raise ValueError + + n0 = sum(t[1] for t in ords if t[1].is_number) + facs = [] + for t, m in ords: + n1 = ceiling(n - n0 + (m if m.is_number else 0)) + s = t.nseries(x, n=n1, logx=logx, cdir=cdir) + ns = s.getn() + if ns is not None: + if ns < n1: # less than expected + n -= n1 - ns # reduce n + facs.append(s) + + except (ValueError, NotImplementedError, TypeError, PoleError): + # XXX: Catching so many generic exceptions around a large block of + # code will mask bugs. Whatever purpose catching these exceptions + # serves should be handled in a different way. + n0 = sympify(sum(t[1] for t in ords if t[1].is_number)) + if n0.is_nonnegative: + n0 = S.Zero + facs = [t.nseries(x, n=ceiling(n-n0), logx=logx, cdir=cdir) for t in self.args] + from sympy.simplify.powsimp import powsimp + res = powsimp(self.func(*facs).expand(), combine='exp', deep=True) + if res.has(Order): + res += Order(x**n, x) + return res + + res = S.Zero + ords2 = [Add.make_args(factor) for factor in facs] + + for fac in product(*ords2): + ords3 = [coeff_exp(term, x) for term in fac] + coeffs, powers = zip(*ords3) + power = sum(powers) + if (power - n).is_negative: + res += Mul(*coeffs)*(x**power) + + def max_degree(e, x): + if e is x: + return S.One + if e.is_Atom: + return S.Zero + if e.is_Add: + return max(max_degree(a, x) for a in e.args) + if e.is_Mul: + return Add(*[max_degree(a, x) for a in e.args]) + if e.is_Pow: + return max_degree(e.base, x)*e.exp + return S.Zero + + if self.is_polynomial(x): + from sympy.polys.polyerrors import PolynomialError + from sympy.polys.polytools import degree + try: + if max_degree(self, x) >= n or degree(self, x) != degree(res, x): + res += Order(x**n, x) + except PolynomialError: + pass + else: + return res + + if res != self: + if (self - res).subs(x, 0) == S.Zero and n > 0: + lt = self._eval_as_leading_term(x, logx=logx, cdir=cdir) + if lt == S.Zero: + return res + res += Order(x**n, x) + return res + + def _eval_as_leading_term(self, x, logx, cdir): + return self.func(*[t.as_leading_term(x, logx=logx, cdir=cdir) for t in self.args]) + + def _eval_conjugate(self): + return self.func(*[t.conjugate() for t in self.args]) + + def _eval_transpose(self): + return self.func(*[t.transpose() for t in self.args[::-1]]) + + def _eval_adjoint(self): + return self.func(*[t.adjoint() for t in self.args[::-1]]) + + def as_content_primitive(self, radical=False, clear=True): + """Return the tuple (R, self/R) where R is the positive Rational + extracted from self. + + Examples + ======== + + >>> from sympy import sqrt + >>> (-3*sqrt(2)*(2 - 2*sqrt(2))).as_content_primitive() + (6, -sqrt(2)*(1 - sqrt(2))) + + See docstring of Expr.as_content_primitive for more examples. + """ + + coef = S.One + args = [] + for a in self.args: + c, p = a.as_content_primitive(radical=radical, clear=clear) + coef *= c + if p is not S.One: + args.append(p) + # don't use self._from_args here to reconstruct args + # since there may be identical args now that should be combined + # e.g. (2+2*x)*(3+3*x) should be (6, (1 + x)**2) not (6, (1+x)*(1+x)) + return coef, self.func(*args) + + def as_ordered_factors(self, order=None): + """Transform an expression into an ordered list of factors. + + Examples + ======== + + >>> from sympy import sin, cos + >>> from sympy.abc import x, y + + >>> (2*x*y*sin(x)*cos(x)).as_ordered_factors() + [2, x, y, sin(x), cos(x)] + + """ + cpart, ncpart = self.args_cnc() + cpart.sort(key=lambda expr: expr.sort_key(order=order)) + return cpart + ncpart + + @property + def _sorted_args(self): + return tuple(self.as_ordered_factors()) + +mul = AssocOpDispatcher('mul') + + +def prod(a, start=1): + """Return product of elements of a. Start with int 1 so if only + ints are included then an int result is returned. + + Examples + ======== + + >>> from sympy import prod, S + >>> prod(range(3)) + 0 + >>> type(_) is int + True + >>> prod([S(2), 3]) + 6 + >>> _.is_Integer + True + + You can start the product at something other than 1: + + >>> prod([1, 2], 3) + 6 + + """ + return reduce(operator.mul, a, start) + + +def _keep_coeff(coeff, factors, clear=True, sign=False): + """Return ``coeff*factors`` unevaluated if necessary. + + If ``clear`` is False, do not keep the coefficient as a factor + if it can be distributed on a single factor such that one or + more terms will still have integer coefficients. + + If ``sign`` is True, allow a coefficient of -1 to remain factored out. + + Examples + ======== + + >>> from sympy.core.mul import _keep_coeff + >>> from sympy.abc import x, y + >>> from sympy import S + + >>> _keep_coeff(S.Half, x + 2) + (x + 2)/2 + >>> _keep_coeff(S.Half, x + 2, clear=False) + x/2 + 1 + >>> _keep_coeff(S.Half, (x + 2)*y, clear=False) + y*(x + 2)/2 + >>> _keep_coeff(S(-1), x + y) + -x - y + >>> _keep_coeff(S(-1), x + y, sign=True) + -(x + y) + """ + if not coeff.is_Number: + if factors.is_Number: + factors, coeff = coeff, factors + else: + return coeff*factors + if factors is S.One: + return coeff + if coeff is S.One: + return factors + elif coeff is S.NegativeOne and not sign: + return -factors + elif factors.is_Add: + if not clear and coeff.is_Rational and coeff.q != 1: + args = [i.as_coeff_Mul() for i in factors.args] + args = [(_keep_coeff(c, coeff), m) for c, m in args] + if any(c.is_Integer for c, _ in args): + return Add._from_args([Mul._from_args( + i[1:] if i[0] == 1 else i) for i in args]) + return Mul(coeff, factors, evaluate=False) + elif factors.is_Mul: + margs = list(factors.args) + if margs[0].is_Number: + margs[0] *= coeff + if margs[0] == 1: + margs.pop(0) + else: + margs.insert(0, coeff) + return Mul._from_args(margs) + else: + m = coeff*factors + if m.is_Number and not factors.is_Number: + m = Mul._from_args((coeff, factors)) + return m + +def expand_2arg(e): + def do(e): + if e.is_Mul: + c, r = e.as_coeff_Mul() + if c.is_Number and r.is_Add: + return _unevaluated_Add(*[c*ri for ri in r.args]) + return e + return bottom_up(e, do) + + +from .numbers import Rational +from .power import Pow +from .add import Add, _unevaluated_Add diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/multidimensional.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/multidimensional.py new file mode 100644 index 0000000000000000000000000000000000000000..133e0ab6cba6a87c627feb6f6034a6daed1128c5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/multidimensional.py @@ -0,0 +1,131 @@ +""" +Provides functionality for multidimensional usage of scalar-functions. + +Read the vectorize docstring for more details. +""" + +from functools import wraps + + +def apply_on_element(f, args, kwargs, n): + """ + Returns a structure with the same dimension as the specified argument, + where each basic element is replaced by the function f applied on it. All + other arguments stay the same. + """ + # Get the specified argument. + if isinstance(n, int): + structure = args[n] + is_arg = True + elif isinstance(n, str): + structure = kwargs[n] + is_arg = False + + # Define reduced function that is only dependent on the specified argument. + def f_reduced(x): + if hasattr(x, "__iter__"): + return list(map(f_reduced, x)) + else: + if is_arg: + args[n] = x + else: + kwargs[n] = x + return f(*args, **kwargs) + + # f_reduced will call itself recursively so that in the end f is applied to + # all basic elements. + return list(map(f_reduced, structure)) + + +def iter_copy(structure): + """ + Returns a copy of an iterable object (also copying all embedded iterables). + """ + return [iter_copy(i) if hasattr(i, "__iter__") else i for i in structure] + + +def structure_copy(structure): + """ + Returns a copy of the given structure (numpy-array, list, iterable, ..). + """ + if hasattr(structure, "copy"): + return structure.copy() + return iter_copy(structure) + + +class vectorize: + """ + Generalizes a function taking scalars to accept multidimensional arguments. + + Examples + ======== + + >>> from sympy import vectorize, diff, sin, symbols, Function + >>> x, y, z = symbols('x y z') + >>> f, g, h = list(map(Function, 'fgh')) + + >>> @vectorize(0) + ... def vsin(x): + ... return sin(x) + + >>> vsin([1, x, y]) + [sin(1), sin(x), sin(y)] + + >>> @vectorize(0, 1) + ... def vdiff(f, y): + ... return diff(f, y) + + >>> vdiff([f(x, y, z), g(x, y, z), h(x, y, z)], [x, y, z]) + [[Derivative(f(x, y, z), x), Derivative(f(x, y, z), y), Derivative(f(x, y, z), z)], [Derivative(g(x, y, z), x), Derivative(g(x, y, z), y), Derivative(g(x, y, z), z)], [Derivative(h(x, y, z), x), Derivative(h(x, y, z), y), Derivative(h(x, y, z), z)]] + """ + def __init__(self, *mdargs): + """ + The given numbers and strings characterize the arguments that will be + treated as data structures, where the decorated function will be applied + to every single element. + If no argument is given, everything is treated multidimensional. + """ + for a in mdargs: + if not isinstance(a, (int, str)): + raise TypeError("a is of invalid type") + self.mdargs = mdargs + + def __call__(self, f): + """ + Returns a wrapper for the one-dimensional function that can handle + multidimensional arguments. + """ + @wraps(f) + def wrapper(*args, **kwargs): + # Get arguments that should be treated multidimensional + if self.mdargs: + mdargs = self.mdargs + else: + mdargs = range(len(args)) + kwargs.keys() + + arglength = len(args) + + for n in mdargs: + if isinstance(n, int): + if n >= arglength: + continue + entry = args[n] + is_arg = True + elif isinstance(n, str): + try: + entry = kwargs[n] + except KeyError: + continue + is_arg = False + if hasattr(entry, "__iter__"): + # Create now a copy of the given array and manipulate then + # the entries directly. + if is_arg: + args = list(args) + args[n] = structure_copy(entry) + else: + kwargs[n] = structure_copy(entry) + result = apply_on_element(wrapper, args, kwargs, n) + return result + return f(*args, **kwargs) + return wrapper diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/numbers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/numbers.py new file mode 100644 index 0000000000000000000000000000000000000000..9fa13fbb96aa25a8e60e048c0147a5e660804ccc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/numbers.py @@ -0,0 +1,4482 @@ +from __future__ import annotations + +from typing import overload + +import numbers +import decimal +import fractions +import math + +from .containers import Tuple +from .sympify import (SympifyError, _sympy_converter, sympify, _convert_numpy_types, + _sympify, _is_numpy_instance) +from .singleton import S, Singleton +from .basic import Basic +from .expr import Expr, AtomicExpr +from .evalf import pure_complex +from .cache import cacheit, clear_cache +from .decorators import _sympifyit +from .intfunc import num_digits, igcd, ilcm, mod_inverse, integer_nthroot +from .logic import fuzzy_not +from .kind import NumberKind +from .sorting import ordered +from sympy.external.gmpy import SYMPY_INTS, gmpy, flint +from sympy.multipledispatch import dispatch +import mpmath +import mpmath.libmp as mlib +from mpmath.libmp import bitcount, round_nearest as rnd +from mpmath.libmp.backend import MPZ +from mpmath.libmp import mpf_pow, mpf_pi, mpf_e, phi_fixed +from mpmath.ctx_mp_python import mpnumeric +from mpmath.libmp.libmpf import ( + finf as _mpf_inf, fninf as _mpf_ninf, + fnan as _mpf_nan, fzero, _normalize as mpf_normalize, + prec_to_dps, dps_to_prec) +from sympy.utilities.misc import debug +from sympy.utilities.exceptions import sympy_deprecation_warning +from .parameters import global_parameters + +_LOG2 = math.log(2) + + +def comp(z1, z2, tol=None): + r"""Return a bool indicating whether the error between z1 and z2 + is $\le$ ``tol``. + + Examples + ======== + + If ``tol`` is ``None`` then ``True`` will be returned if + :math:`|z1 - z2|\times 10^p \le 5` where $p$ is minimum value of the + decimal precision of each value. + + >>> from sympy import comp, pi + >>> pi4 = pi.n(4); pi4 + 3.142 + >>> comp(_, 3.142) + True + >>> comp(pi4, 3.141) + False + >>> comp(pi4, 3.143) + False + + A comparison of strings will be made + if ``z1`` is a Number and ``z2`` is a string or ``tol`` is ''. + + >>> comp(pi4, 3.1415) + True + >>> comp(pi4, 3.1415, '') + False + + When ``tol`` is provided and $z2$ is non-zero and + :math:`|z1| > 1` the error is normalized by :math:`|z1|`: + + >>> abs(pi4 - 3.14)/pi4 + 0.000509791731426756 + >>> comp(pi4, 3.14, .001) # difference less than 0.1% + True + >>> comp(pi4, 3.14, .0005) # difference less than 0.1% + False + + When :math:`|z1| \le 1` the absolute error is used: + + >>> 1/pi4 + 0.3183 + >>> abs(1/pi4 - 0.3183)/(1/pi4) + 3.07371499106316e-5 + >>> abs(1/pi4 - 0.3183) + 9.78393554684764e-6 + >>> comp(1/pi4, 0.3183, 1e-5) + True + + To see if the absolute error between ``z1`` and ``z2`` is less + than or equal to ``tol``, call this as ``comp(z1 - z2, 0, tol)`` + or ``comp(z1 - z2, tol=tol)``: + + >>> abs(pi4 - 3.14) + 0.00160156249999988 + >>> comp(pi4 - 3.14, 0, .002) + True + >>> comp(pi4 - 3.14, 0, .001) + False + """ + if isinstance(z2, str): + if not pure_complex(z1, or_real=True): + raise ValueError('when z2 is a str z1 must be a Number') + return str(z1) == z2 + if not z1: + z1, z2 = z2, z1 + if not z1: + return True + if not tol: + a, b = z1, z2 + if tol == '': + return str(a) == str(b) + if tol is None: + a, b = sympify(a), sympify(b) + if not all(i.is_number for i in (a, b)): + raise ValueError('expecting 2 numbers') + fa = a.atoms(Float) + fb = b.atoms(Float) + if not fa and not fb: + # no floats -- compare exactly + return a == b + # get a to be pure_complex + for _ in range(2): + ca = pure_complex(a, or_real=True) + if not ca: + if fa: + a = a.n(prec_to_dps(min(i._prec for i in fa))) + ca = pure_complex(a, or_real=True) + break + else: + fa, fb = fb, fa + a, b = b, a + cb = pure_complex(b) + if not cb and fb: + b = b.n(prec_to_dps(min(i._prec for i in fb))) + cb = pure_complex(b, or_real=True) + if ca and cb and (ca[1] or cb[1]): + return all(comp(i, j) for i, j in zip(ca, cb)) + tol = 10**prec_to_dps(min(a._prec, getattr(b, '_prec', a._prec))) + return int(abs(a - b)*tol) <= 5 + diff = abs(z1 - z2) + az1 = abs(z1) + if z2 and az1 > 1: + return diff/az1 <= tol + else: + return diff <= tol + + +def mpf_norm(mpf, prec): + """Return the mpf tuple normalized appropriately for the indicated + precision after doing a check to see if zero should be returned or + not when the mantissa is 0. ``mpf_normlize`` always assumes that this + is zero, but it may not be since the mantissa for mpf's values "+inf", + "-inf" and "nan" have a mantissa of zero, too. + + Note: this is not intended to validate a given mpf tuple, so sending + mpf tuples that were not created by mpmath may produce bad results. This + is only a wrapper to ``mpf_normalize`` which provides the check for non- + zero mpfs that have a 0 for the mantissa. + """ + sign, man, expt, bc = mpf + if not man: + # hack for mpf_normalize which does not do this; + # it assumes that if man is zero the result is 0 + # (see issue 6639) + if not bc: + return fzero + else: + # don't change anything; this should already + # be a well formed mpf tuple + return mpf + + # Necessary if mpmath is using the gmpy backend + from mpmath.libmp.backend import MPZ + rv = mpf_normalize(sign, MPZ(man), expt, bc, prec, rnd) + return rv + +# TODO: we should use the warnings module +_errdict = {"divide": False} + + +def seterr(divide=False): + """ + Should SymPy raise an exception on 0/0 or return a nan? + + divide == True .... raise an exception + divide == False ... return nan + """ + if _errdict["divide"] != divide: + clear_cache() + _errdict["divide"] = divide + + +def _as_integer_ratio(p): + neg_pow, man, expt, _ = getattr(p, '_mpf_', mpmath.mpf(p)._mpf_) + p = [1, -1][neg_pow % 2]*man + if expt < 0: + q = 2**-expt + else: + q = 1 + p *= 2**expt + return int(p), int(q) + + +def _decimal_to_Rational_prec(dec): + """Convert an ordinary decimal instance to a Rational.""" + if not dec.is_finite(): + raise TypeError("dec must be finite, got %s." % dec) + s, d, e = dec.as_tuple() + prec = len(d) + if e >= 0: # it's an integer + rv = Integer(int(dec)) + else: + s = (-1)**s + d = sum(di*10**i for i, di in enumerate(reversed(d))) + rv = Rational(s*d, 10**-e) + return rv, prec + +_dig = str.maketrans(dict.fromkeys('1234567890')) + +def _literal_float(s): + """return True if s is space-trimmed number literal else False + + Python allows underscore as digit separators: there must be a + digit on each side. So neither a leading underscore nor a + double underscore are valid as part of a number. A number does + not have to precede the decimal point, but there must be a + digit before the optional "e" or "E" that begins the signs + exponent of the number which must be an integer, perhaps with + underscore separators. + + SymPy allows space as a separator; if the calling routine replaces + them with underscores then the same semantics will be enforced + for them as for underscores: there can only be 1 *between* digits. + + We don't check for error from float(s) because we don't know + whether s is malicious or not. A regex for this could maybe + be written but will it be understood by most who read it? + """ + # mantissa and exponent + parts = s.split('e') + if len(parts) > 2: + return False + if len(parts) == 2: + m, e = parts + if e.startswith(tuple('+-')): + e = e[1:] + if not e: + return False + else: + m, e = s, '1' + # integer and fraction of mantissa + parts = m.split('.') + if len(parts) > 2: + return False + elif len(parts) == 2: + i, f = parts + else: + i, f = m, '1' + if not i and not f: + return False + if i and i[0] in '+-': + i = i[1:] + if not i: # -.3e4 -> -0.3e4 + i = '1' + f = f or '1' + # check that all groups contain only digits and are not null + for n in (i, f, e): + for g in n.split('_'): + if not g or g.translate(_dig): + return False + return True + +# (a,b) -> gcd(a,b) + +# TODO caching with decorator, but not to degrade performance + + +class Number(AtomicExpr): + """Represents atomic numbers in SymPy. + + Explanation + =========== + + Floating point numbers are represented by the Float class. + Rational numbers (of any size) are represented by the Rational class. + Integer numbers (of any size) are represented by the Integer class. + Float and Rational are subclasses of Number; Integer is a subclass + of Rational. + + For example, ``2/3`` is represented as ``Rational(2, 3)`` which is + a different object from the floating point number obtained with + Python division ``2/3``. Even for numbers that are exactly + represented in binary, there is a difference between how two forms, + such as ``Rational(1, 2)`` and ``Float(0.5)``, are used in SymPy. + The rational form is to be preferred in symbolic computations. + + Other kinds of numbers, such as algebraic numbers ``sqrt(2)`` or + complex numbers ``3 + 4*I``, are not instances of Number class as + they are not atomic. + + See Also + ======== + + Float, Integer, Rational + """ + is_commutative = True + is_number = True + is_Number = True + + __slots__ = () + + # Used to make max(x._prec, y._prec) return x._prec when only x is a float + _prec = -1 + + kind = NumberKind + + def __new__(cls, *obj): + if len(obj) == 1: + obj = obj[0] + + if isinstance(obj, Number): + return obj + if isinstance(obj, SYMPY_INTS): + return Integer(obj) + if isinstance(obj, tuple) and len(obj) == 2: + return Rational(*obj) + if isinstance(obj, (float, mpmath.mpf, decimal.Decimal)): + return Float(obj) + if isinstance(obj, str): + _obj = obj.lower() # float('INF') == float('inf') + if _obj == 'nan': + return S.NaN + elif _obj == 'inf': + return S.Infinity + elif _obj == '+inf': + return S.Infinity + elif _obj == '-inf': + return S.NegativeInfinity + val = sympify(obj) + if isinstance(val, Number): + return val + else: + raise ValueError('String "%s" does not denote a Number' % obj) + msg = "expected str|int|long|float|Decimal|Number object but got %r" + raise TypeError(msg % type(obj).__name__) + + def could_extract_minus_sign(self): + return bool(self.is_extended_negative) + + def invert(self, other, *gens, **args): + from sympy.polys.polytools import invert + if getattr(other, 'is_number', True): + return mod_inverse(self, other) + return invert(self, other, *gens, **args) + + def __divmod__(self, other): + from sympy.functions.elementary.complexes import sign + + try: + other = Number(other) + if self.is_infinite or S.NaN in (self, other): + return (S.NaN, S.NaN) + except TypeError: + return NotImplemented + if not other: + raise ZeroDivisionError('modulo by zero') + if self.is_Integer and other.is_Integer: + return Tuple(*divmod(self.p, other.p)) + elif isinstance(other, Float): + rat = self/Rational(other) + else: + rat = self/other + if other.is_finite: + w = int(rat) if rat >= 0 else int(rat) - 1 + r = self - other*w + if r == Float(other): + w += 1 + r = 0 + if isinstance(self, Float) or isinstance(other, Float): + r = Float(r) # in case w or r is 0 + else: + w = 0 if not self or (sign(self) == sign(other)) else -1 + r = other if w else self + return Tuple(w, r) + + def __rdivmod__(self, other): + try: + other = Number(other) + except TypeError: + return NotImplemented + return divmod(other, self) + + def _as_mpf_val(self, prec): + """Evaluation of mpf tuple accurate to at least prec bits.""" + raise NotImplementedError('%s needs ._as_mpf_val() method' % + (self.__class__.__name__)) + + def _eval_evalf(self, prec): + return Float._new(self._as_mpf_val(prec), prec) + + def _as_mpf_op(self, prec): + prec = max(prec, self._prec) + return self._as_mpf_val(prec), prec + + def __float__(self): + return mlib.to_float(self._as_mpf_val(53)) + + def floor(self): + raise NotImplementedError('%s needs .floor() method' % + (self.__class__.__name__)) + + def ceiling(self): + raise NotImplementedError('%s needs .ceiling() method' % + (self.__class__.__name__)) + + def __floor__(self): + return self.floor() + + def __ceil__(self): + return self.ceiling() + + def _eval_conjugate(self): + return self + + def _eval_order(self, *symbols): + from sympy.series.order import Order + # Order(5, x, y) -> Order(1,x,y) + return Order(S.One, *symbols) + + def _eval_subs(self, old, new): + if old == -self: + return -new + return self # there is no other possibility + + @classmethod + def class_key(cls): + return 1, 0, 'Number' + + @cacheit + def sort_key(self, order=None): + return self.class_key(), (0, ()), (), self + + def __neg__(self) -> Number: + raise NotImplementedError + + @overload + def __add__(self, other: Number | int | float) -> Number: ... + @overload + def __add__(self, other: Expr) -> Expr: ... + + @_sympifyit('other', NotImplemented) + def __add__(self, other) -> Expr: + if isinstance(other, Number) and global_parameters.evaluate: + if other is S.NaN: + return S.NaN + elif other is S.Infinity: + return S.Infinity + elif other is S.NegativeInfinity: + return S.NegativeInfinity + return AtomicExpr.__add__(self, other) + + @_sympifyit('other', NotImplemented) + def __sub__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other is S.NaN: + return S.NaN + elif other is S.Infinity: + return S.NegativeInfinity + elif other is S.NegativeInfinity: + return S.Infinity + return AtomicExpr.__sub__(self, other) + + @_sympifyit('other', NotImplemented) + def __mul__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other is S.NaN: + return S.NaN + elif other is S.Infinity: + if self.is_zero: + return S.NaN + elif self.is_positive: + return S.Infinity + else: + return S.NegativeInfinity + elif other is S.NegativeInfinity: + if self.is_zero: + return S.NaN + elif self.is_positive: + return S.NegativeInfinity + else: + return S.Infinity + elif isinstance(other, Tuple): + return NotImplemented + return AtomicExpr.__mul__(self, other) + + @_sympifyit('other', NotImplemented) + def __truediv__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other is S.NaN: + return S.NaN + elif other in (S.Infinity, S.NegativeInfinity): + return S.Zero + return AtomicExpr.__truediv__(self, other) + + def __eq__(self, other): + raise NotImplementedError('%s needs .__eq__() method' % + (self.__class__.__name__)) + + def __ne__(self, other): + raise NotImplementedError('%s needs .__ne__() method' % + (self.__class__.__name__)) + + def __lt__(self, other): + try: + other = _sympify(other) + except SympifyError: + raise TypeError("Invalid comparison %s < %s" % (self, other)) + raise NotImplementedError('%s needs .__lt__() method' % + (self.__class__.__name__)) + + def __le__(self, other): + try: + other = _sympify(other) + except SympifyError: + raise TypeError("Invalid comparison %s <= %s" % (self, other)) + raise NotImplementedError('%s needs .__le__() method' % + (self.__class__.__name__)) + + def __gt__(self, other): + try: + other = _sympify(other) + except SympifyError: + raise TypeError("Invalid comparison %s > %s" % (self, other)) + return _sympify(other).__lt__(self) + + def __ge__(self, other): + try: + other = _sympify(other) + except SympifyError: + raise TypeError("Invalid comparison %s >= %s" % (self, other)) + return _sympify(other).__le__(self) + + def __hash__(self): + return super().__hash__() + + def is_constant(self, *wrt, **flags): + return True + + def as_coeff_mul(self, *deps, rational=True, **kwargs): + # a -> c*t + if self.is_Rational or not rational: + return self, () + elif self.is_negative: + return S.NegativeOne, (-self,) + return S.One, (self,) + + def as_coeff_add(self, *deps): + # a -> c + t + if self.is_Rational: + return self, () + return S.Zero, (self,) + + def as_coeff_Mul(self, rational=False): + """Efficiently extract the coefficient of a product.""" + if not rational: + return self, S.One + return S.One, self + + def as_coeff_Add(self, rational=False): + """Efficiently extract the coefficient of a summation.""" + if not rational: + return self, S.Zero + return S.Zero, self + + def gcd(self, other): + """Compute GCD of `self` and `other`. """ + from sympy.polys.polytools import gcd + return gcd(self, other) + + def lcm(self, other): + """Compute LCM of `self` and `other`. """ + from sympy.polys.polytools import lcm + return lcm(self, other) + + def cofactors(self, other): + """Compute GCD and cofactors of `self` and `other`. """ + from sympy.polys.polytools import cofactors + return cofactors(self, other) + + +class Float(Number): + """Represent a floating-point number of arbitrary precision. + + Examples + ======== + + >>> from sympy import Float + >>> Float(3.5) + 3.50000000000000 + >>> Float(3) + 3.00000000000000 + + Creating Floats from strings (and Python ``int`` and ``long`` + types) will give a minimum precision of 15 digits, but the + precision will automatically increase to capture all digits + entered. + + >>> Float(1) + 1.00000000000000 + >>> Float(10**20) + 100000000000000000000. + >>> Float('1e20') + 100000000000000000000. + + However, *floating-point* numbers (Python ``float`` types) retain + only 15 digits of precision: + + >>> Float(1e20) + 1.00000000000000e+20 + >>> Float(1.23456789123456789) + 1.23456789123457 + + It may be preferable to enter high-precision decimal numbers + as strings: + + >>> Float('1.23456789123456789') + 1.23456789123456789 + + The desired number of digits can also be specified: + + >>> Float('1e-3', 3) + 0.00100 + >>> Float(100, 4) + 100.0 + + Float can automatically count significant figures if a null string + is sent for the precision; spaces or underscores are also allowed. (Auto- + counting is only allowed for strings, ints and longs). + + >>> Float('123 456 789.123_456', '') + 123456789.123456 + >>> Float('12e-3', '') + 0.012 + >>> Float(3, '') + 3. + + If a number is written in scientific notation, only the digits before the + exponent are considered significant if a decimal appears, otherwise the + "e" signifies only how to move the decimal: + + >>> Float('60.e2', '') # 2 digits significant + 6.0e+3 + >>> Float('60e2', '') # 4 digits significant + 6000. + >>> Float('600e-2', '') # 3 digits significant + 6.00 + + Notes + ===== + + Floats are inexact by their nature unless their value is a binary-exact + value. + + >>> approx, exact = Float(.1, 1), Float(.125, 1) + + For calculation purposes, evalf needs to be able to change the precision + but this will not increase the accuracy of the inexact value. The + following is the most accurate 5-digit approximation of a value of 0.1 + that had only 1 digit of precision: + + >>> approx.evalf(5) + 0.099609 + + By contrast, 0.125 is exact in binary (as it is in base 10) and so it + can be passed to Float or evalf to obtain an arbitrary precision with + matching accuracy: + + >>> Float(exact, 5) + 0.12500 + >>> exact.evalf(20) + 0.12500000000000000000 + + Trying to make a high-precision Float from a float is not disallowed, + but one must keep in mind that the *underlying float* (not the apparent + decimal value) is being obtained with high precision. For example, 0.3 + does not have a finite binary representation. The closest rational is + the fraction 5404319552844595/2**54. So if you try to obtain a Float of + 0.3 to 20 digits of precision you will not see the same thing as 0.3 + followed by 19 zeros: + + >>> Float(0.3, 20) + 0.29999999999999998890 + + If you want a 20-digit value of the decimal 0.3 (not the floating point + approximation of 0.3) you should send the 0.3 as a string. The underlying + representation is still binary but a higher precision than Python's float + is used: + + >>> Float('0.3', 20) + 0.30000000000000000000 + + Although you can increase the precision of an existing Float using Float + it will not increase the accuracy -- the underlying value is not changed: + + >>> def show(f): # binary rep of Float + ... from sympy import Mul, Pow + ... s, m, e, b = f._mpf_ + ... v = Mul(int(m), Pow(2, int(e), evaluate=False), evaluate=False) + ... print('%s at prec=%s' % (v, f._prec)) + ... + >>> t = Float('0.3', 3) + >>> show(t) + 4915/2**14 at prec=13 + >>> show(Float(t, 20)) # higher prec, not higher accuracy + 4915/2**14 at prec=70 + >>> show(Float(t, 2)) # lower prec + 307/2**10 at prec=10 + + The same thing happens when evalf is used on a Float: + + >>> show(t.evalf(20)) + 4915/2**14 at prec=70 + >>> show(t.evalf(2)) + 307/2**10 at prec=10 + + Finally, Floats can be instantiated with an mpf tuple (n, c, p) to + produce the number (-1)**n*c*2**p: + + >>> n, c, p = 1, 5, 0 + >>> (-1)**n*c*2**p + -5 + >>> Float((1, 5, 0)) + -5.00000000000000 + + An actual mpf tuple also contains the number of bits in c as the last + element of the tuple: + + >>> _._mpf_ + (1, 5, 0, 3) + + This is not needed for instantiation and is not the same thing as the + precision. The mpf tuple and the precision are two separate quantities + that Float tracks. + + In SymPy, a Float is a number that can be computed with arbitrary + precision. Although floating point 'inf' and 'nan' are not such + numbers, Float can create these numbers: + + >>> Float('-inf') + -oo + >>> _.is_Float + False + + Zero in Float only has a single value. Values are not separate for + positive and negative zeroes. + """ + __slots__ = ('_mpf_', '_prec') + + _mpf_: tuple[int, int, int, int] + + # A Float, though rational in form, does not behave like + # a rational in all Python expressions so we deal with + # exceptions (where we want to deal with the rational + # form of the Float as a rational) at the source rather + # than assigning a mathematically loaded category of 'rational' + is_rational = None + is_irrational = None + is_number = True + + is_real = True + is_extended_real = True + + is_Float = True + + _remove_non_digits = str.maketrans(dict.fromkeys("-+_.")) + + def __new__(cls, num, dps=None, precision=None): + if dps is not None and precision is not None: + raise ValueError('Both decimal and binary precision supplied. ' + 'Supply only one. ') + + if isinstance(num, str): + _num = num = num.strip() # Python ignores leading and trailing space + num = num.replace(' ', '_').lower() # Float treats spaces as digit sep; E -> e + if num.startswith('.') and len(num) > 1: + num = '0' + num + elif num.startswith('-.') and len(num) > 2: + num = '-0.' + num[2:] + elif num in ('inf', '+inf'): + return S.Infinity + elif num == '-inf': + return S.NegativeInfinity + elif num == 'nan': + return S.NaN + elif not _literal_float(num): + raise ValueError('string-float not recognized: %s' % _num) + elif isinstance(num, float) and num == 0: + num = '0' + elif isinstance(num, float) and num == float('inf'): + return S.Infinity + elif isinstance(num, float) and num == float('-inf'): + return S.NegativeInfinity + elif isinstance(num, float) and math.isnan(num): + return S.NaN + elif isinstance(num, (SYMPY_INTS, Integer)): + num = str(num) + elif num is S.Infinity: + return num + elif num is S.NegativeInfinity: + return num + elif num is S.NaN: + return num + elif _is_numpy_instance(num): # support for numpy datatypes + num = _convert_numpy_types(num) + elif isinstance(num, mpmath.mpf): + if precision is None: + if dps is None: + precision = num.context.prec + num = num._mpf_ + + if dps is None and precision is None: + dps = 15 + if isinstance(num, Float): + return num + if isinstance(num, str): + try: + Num = decimal.Decimal(num) + except decimal.InvalidOperation: + pass + else: + isint = '.' not in num + num, dps = _decimal_to_Rational_prec(Num) + if num.is_Integer and isint: + # 12e3 is shorthand for int, not float; + # 12.e3 would be the float version + dps = max(dps, num_digits(num)) + dps = max(15, dps) + precision = dps_to_prec(dps) + elif precision == '' and dps is None or precision is None and dps == '': + if not isinstance(num, str): + raise ValueError('The null string can only be used when ' + 'the number to Float is passed as a string or an integer.') + try: + Num = decimal.Decimal(num) + except decimal.InvalidOperation: + raise ValueError('string-float not recognized by Decimal: %s' % num) + else: + isint = '.' not in num + num, dps = _decimal_to_Rational_prec(Num) + if num.is_Integer and isint: + # without dec, e-notation is short for int + dps = max(dps, num_digits(num)) + precision = dps_to_prec(dps) + + # decimal precision(dps) is set and maybe binary precision(precision) + # as well.From here on binary precision is used to compute the Float. + # Hence, if supplied use binary precision else translate from decimal + # precision. + + if precision is None or precision == '': + precision = dps_to_prec(dps) + + precision = int(precision) + + if isinstance(num, float): + _mpf_ = mlib.from_float(num, precision, rnd) + elif isinstance(num, str): + _mpf_ = mlib.from_str(num, precision, rnd) + elif isinstance(num, decimal.Decimal): + if num.is_finite(): + _mpf_ = mlib.from_str(str(num), precision, rnd) + elif num.is_nan(): + return S.NaN + elif num.is_infinite(): + if num > 0: + return S.Infinity + return S.NegativeInfinity + else: + raise ValueError("unexpected decimal value %s" % str(num)) + elif isinstance(num, tuple) and len(num) in (3, 4): + if isinstance(num[1], str): + # it's a hexadecimal (coming from a pickled object) + num = list(num) + # If we're loading an object pickled in Python 2 into + # Python 3, we may need to strip a tailing 'L' because + # of a shim for int on Python 3, see issue #13470. + # Strip leading '0x' - gmpy2 only documents such inputs + # with base prefix as valid when the 2nd argument (base) is 0. + # When mpmath uses Sage as the backend, however, it + # ends up including '0x' when preparing the picklable tuple. + # See issue #19690. + num[1] = num[1].removeprefix('0x').removesuffix('L') + # Now we can assume that it is in standard form + num[1] = MPZ(num[1], 16) + _mpf_ = tuple(num) + else: + if len(num) == 4: + # handle normalization hack + return Float._new(num, precision) + else: + if not all(( + num[0] in (0, 1), + num[1] >= 0, + all(type(i) in (int, int) for i in num) + )): + raise ValueError('malformed mpf: %s' % (num,)) + # don't compute number or else it may + # over/underflow + return Float._new( + (num[0], num[1], num[2], bitcount(num[1])), + precision) + elif isinstance(num, (Number, NumberSymbol)): + _mpf_ = num._as_mpf_val(precision) + else: + _mpf_ = mpmath.mpf(num, prec=precision)._mpf_ + + return cls._new(_mpf_, precision, zero=False) + + @classmethod + def _new(cls, _mpf_, _prec, zero=True): + # special cases + if zero and _mpf_ == fzero: + return S.Zero # Float(0) -> 0.0; Float._new((0,0,0,0)) -> 0 + elif _mpf_ == _mpf_nan: + return S.NaN + elif _mpf_ == _mpf_inf: + return S.Infinity + elif _mpf_ == _mpf_ninf: + return S.NegativeInfinity + + obj = Expr.__new__(cls) + obj._mpf_ = mpf_norm(_mpf_, _prec) + obj._prec = _prec + return obj + + def __getnewargs_ex__(self): + sign, man, exp, bc = self._mpf_ + arg = (sign, hex(man)[2:], exp, bc) + kwargs = {'precision': self._prec} + return ((arg,), kwargs) + + def _hashable_content(self): + return (self._mpf_, self._prec) + + def floor(self): + return Integer(int(mlib.to_int( + mlib.mpf_floor(self._mpf_, self._prec)))) + + def ceiling(self): + return Integer(int(mlib.to_int( + mlib.mpf_ceil(self._mpf_, self._prec)))) + + def __floor__(self): + return self.floor() + + def __ceil__(self): + return self.ceiling() + + @property + def num(self): + return mpmath.mpf(self._mpf_) + + def _as_mpf_val(self, prec): + rv = mpf_norm(self._mpf_, prec) + if rv != self._mpf_ and self._prec == prec: + debug(self._mpf_, rv) + return rv + + def _as_mpf_op(self, prec): + return self._mpf_, max(prec, self._prec) + + def _eval_is_finite(self): + if self._mpf_ in (_mpf_inf, _mpf_ninf): + return False + return True + + def _eval_is_infinite(self): + if self._mpf_ in (_mpf_inf, _mpf_ninf): + return True + return False + + def _eval_is_integer(self): + if self._mpf_ == fzero: + return True + if not int_valued(self): + return False + + def _eval_is_negative(self): + if self._mpf_ in (_mpf_ninf, _mpf_inf): + return False + return self.num < 0 + + def _eval_is_positive(self): + if self._mpf_ in (_mpf_ninf, _mpf_inf): + return False + return self.num > 0 + + def _eval_is_extended_negative(self): + if self._mpf_ == _mpf_ninf: + return True + if self._mpf_ == _mpf_inf: + return False + return self.num < 0 + + def _eval_is_extended_positive(self): + if self._mpf_ == _mpf_inf: + return True + if self._mpf_ == _mpf_ninf: + return False + return self.num > 0 + + def _eval_is_zero(self): + return self._mpf_ == fzero + + def __bool__(self): + return self._mpf_ != fzero + + def __neg__(self): + if not self: + return self + return Float._new(mlib.mpf_neg(self._mpf_), self._prec) + + @_sympifyit('other', NotImplemented) + def __add__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + rhs, prec = other._as_mpf_op(self._prec) + return Float._new(mlib.mpf_add(self._mpf_, rhs, prec, rnd), prec) + return Number.__add__(self, other) + + @_sympifyit('other', NotImplemented) + def __sub__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + rhs, prec = other._as_mpf_op(self._prec) + return Float._new(mlib.mpf_sub(self._mpf_, rhs, prec, rnd), prec) + return Number.__sub__(self, other) + + @_sympifyit('other', NotImplemented) + def __mul__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + rhs, prec = other._as_mpf_op(self._prec) + return Float._new(mlib.mpf_mul(self._mpf_, rhs, prec, rnd), prec) + return Number.__mul__(self, other) + + @_sympifyit('other', NotImplemented) + def __truediv__(self, other): + if isinstance(other, Number) and other != 0 and global_parameters.evaluate: + rhs, prec = other._as_mpf_op(self._prec) + return Float._new(mlib.mpf_div(self._mpf_, rhs, prec, rnd), prec) + return Number.__truediv__(self, other) + + @_sympifyit('other', NotImplemented) + def __mod__(self, other): + if isinstance(other, Rational) and other.q != 1 and global_parameters.evaluate: + # calculate mod with Rationals, *then* round the result + return Float(Rational.__mod__(Rational(self), other), + precision=self._prec) + if isinstance(other, Float) and global_parameters.evaluate: + r = self/other + if int_valued(r): + return Float(0, precision=max(self._prec, other._prec)) + if isinstance(other, Number) and global_parameters.evaluate: + rhs, prec = other._as_mpf_op(self._prec) + return Float._new(mlib.mpf_mod(self._mpf_, rhs, prec, rnd), prec) + return Number.__mod__(self, other) + + @_sympifyit('other', NotImplemented) + def __rmod__(self, other): + if isinstance(other, Float) and global_parameters.evaluate: + return other.__mod__(self) + if isinstance(other, Number) and global_parameters.evaluate: + rhs, prec = other._as_mpf_op(self._prec) + return Float._new(mlib.mpf_mod(rhs, self._mpf_, prec, rnd), prec) + return Number.__rmod__(self, other) + + def _eval_power(self, expt): + """ + expt is symbolic object but not equal to 0, 1 + + (-p)**r -> exp(r*log(-p)) -> exp(r*(log(p) + I*Pi)) -> + -> p**r*(sin(Pi*r) + cos(Pi*r)*I) + """ + if equal_valued(self, 0): + if expt.is_extended_positive: + return self + if expt.is_extended_negative: + return S.ComplexInfinity + if isinstance(expt, Number): + if isinstance(expt, Integer): + prec = self._prec + return Float._new( + mlib.mpf_pow_int(self._mpf_, expt.p, prec, rnd), prec) + elif isinstance(expt, Rational) and \ + expt.p == 1 and expt.q % 2 and self.is_negative: + return Pow(S.NegativeOne, expt, evaluate=False)*( + -self)._eval_power(expt) + expt, prec = expt._as_mpf_op(self._prec) + mpfself = self._mpf_ + try: + y = mpf_pow(mpfself, expt, prec, rnd) + return Float._new(y, prec) + except mlib.ComplexResult: + re, im = mlib.mpc_pow( + (mpfself, fzero), (expt, fzero), prec, rnd) + return Float._new(re, prec) + \ + Float._new(im, prec)*S.ImaginaryUnit + + def __abs__(self): + return Float._new(mlib.mpf_abs(self._mpf_), self._prec) + + def __int__(self): + if self._mpf_ == fzero: + return 0 + return int(mlib.to_int(self._mpf_)) # uses round_fast = round_down + + def __eq__(self, other): + if isinstance(other, float): + other = Float(other) + return Basic.__eq__(self, other) + + def __ne__(self, other): + eq = self.__eq__(other) + if eq is NotImplemented: + return eq + else: + return not eq + + def __hash__(self): + float_val = float(self) + if not math.isinf(float_val): + return hash(float_val) + return Basic.__hash__(self) + + def _Frel(self, other, op): + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if other.is_Rational: + # test self*other.q other.p without losing precision + ''' + >>> f = Float(.1,2) + >>> i = 1234567890 + >>> (f*i)._mpf_ + (0, 471, 18, 9) + >>> mlib.mpf_mul(f._mpf_, mlib.from_int(i)) + (0, 505555550955, -12, 39) + ''' + smpf = mlib.mpf_mul(self._mpf_, mlib.from_int(other.q)) + ompf = mlib.from_int(other.p) + return _sympify(bool(op(smpf, ompf))) + elif other.is_Float: + return _sympify(bool( + op(self._mpf_, other._mpf_))) + elif other.is_comparable and other not in ( + S.Infinity, S.NegativeInfinity): + other = other.evalf(prec_to_dps(self._prec)) + if other._prec > 1: + if other.is_Number: + return _sympify(bool( + op(self._mpf_, other._as_mpf_val(self._prec)))) + + def __gt__(self, other): + if isinstance(other, NumberSymbol): + return other.__lt__(self) + rv = self._Frel(other, mlib.mpf_gt) + if rv is None: + return Expr.__gt__(self, other) + return rv + + def __ge__(self, other): + if isinstance(other, NumberSymbol): + return other.__le__(self) + rv = self._Frel(other, mlib.mpf_ge) + if rv is None: + return Expr.__ge__(self, other) + return rv + + def __lt__(self, other): + if isinstance(other, NumberSymbol): + return other.__gt__(self) + rv = self._Frel(other, mlib.mpf_lt) + if rv is None: + return Expr.__lt__(self, other) + return rv + + def __le__(self, other): + if isinstance(other, NumberSymbol): + return other.__ge__(self) + rv = self._Frel(other, mlib.mpf_le) + if rv is None: + return Expr.__le__(self, other) + return rv + + def epsilon_eq(self, other, epsilon="1e-15"): + return abs(self - other) < Float(epsilon) + + def __format__(self, format_spec): + return format(decimal.Decimal(str(self)), format_spec) + + +# Add sympify converters +_sympy_converter[float] = _sympy_converter[decimal.Decimal] = Float + +# this is here to work nicely in Sage +RealNumber = Float + + +class Rational(Number): + """Represents rational numbers (p/q) of any size. + + Examples + ======== + + >>> from sympy import Rational, nsimplify, S, pi + >>> Rational(1, 2) + 1/2 + + Rational is unprejudiced in accepting input. If a float is passed, the + underlying value of the binary representation will be returned: + + >>> Rational(.5) + 1/2 + >>> Rational(.2) + 3602879701896397/18014398509481984 + + If the simpler representation of the float is desired then consider + limiting the denominator to the desired value or convert the float to + a string (which is roughly equivalent to limiting the denominator to + 10**12): + + >>> Rational(str(.2)) + 1/5 + >>> Rational(.2).limit_denominator(10**12) + 1/5 + + An arbitrarily precise Rational is obtained when a string literal is + passed: + + >>> Rational("1.23") + 123/100 + >>> Rational('1e-2') + 1/100 + >>> Rational(".1") + 1/10 + >>> Rational('1e-2/3.2') + 1/320 + + The conversion of other types of strings can be handled by + the sympify() function, and conversion of floats to expressions + or simple fractions can be handled with nsimplify: + + >>> S('.[3]') # repeating digits in brackets + 1/3 + >>> S('3**2/10') # general expressions + 9/10 + >>> nsimplify(.3) # numbers that have a simple form + 3/10 + + But if the input does not reduce to a literal Rational, an error will + be raised: + + >>> Rational(pi) + Traceback (most recent call last): + ... + TypeError: invalid input: pi + + + Low-level + --------- + + Access numerator and denominator as .p and .q: + + >>> r = Rational(3, 4) + >>> r + 3/4 + >>> r.p + 3 + >>> r.q + 4 + + Note that p and q return integers (not SymPy Integers) so some care + is needed when using them in expressions: + + >>> r.p/r.q + 0.75 + + See Also + ======== + sympy.core.sympify.sympify, sympy.simplify.simplify.nsimplify + """ + is_real = True + is_integer = False + is_rational = True + is_number = True + + __slots__ = ('p', 'q') + + p: int + q: int + + is_Rational = True + + @cacheit + def __new__(cls, p, q=None, gcd=None): + if q is None: + if isinstance(p, Rational): + return p + + if isinstance(p, SYMPY_INTS): + pass + else: + if isinstance(p, (float, Float)): + return Rational(*_as_integer_ratio(p)) + + if not isinstance(p, str): + try: + p = sympify(p) + except (SympifyError, SyntaxError): + pass # error will raise below + else: + if p.count('/') > 1: + raise TypeError('invalid input: %s' % p) + p = p.replace(' ', '') + pq = p.rsplit('/', 1) + if len(pq) == 2: + p, q = pq + fp = fractions.Fraction(p) + fq = fractions.Fraction(q) + p = fp/fq + try: + p = fractions.Fraction(p) + except ValueError: + pass # error will raise below + else: + return cls._new(p.numerator, p.denominator, 1) + + if not isinstance(p, Rational): + raise TypeError('invalid input: %s' % p) + + q = 1 + + Q = 1 + + if not isinstance(p, SYMPY_INTS): + p = Rational(p) + Q *= p.q + p = p.p + else: + p = int(p) + + if not isinstance(q, SYMPY_INTS): + q = Rational(q) + p *= q.q + Q *= q.p + else: + Q *= int(q) + q = Q + + if gcd is not None: + sympy_deprecation_warning( + "gcd is deprecated in Rational, use nsimplify instead", + deprecated_since_version="1.11", + active_deprecations_target="deprecated-rational-gcd", + stacklevel=4, + ) + return cls._new(p, q, gcd) + + # p and q are now ints + return cls._new(p, q) + + @classmethod + def _new(cls, p, q, gcd=None): + if q == 0: + if p == 0: + if _errdict["divide"]: + raise ValueError("Indeterminate 0/0") + else: + return S.NaN + return S.ComplexInfinity + + if q < 0: + q = -q + p = -p + + if gcd is None: + gcd = igcd(abs(p), q) + + if gcd > 1: + p //= gcd + q //= gcd + + return cls.from_coprime_ints(p, q) + + @classmethod + def from_coprime_ints(cls, p: int, q: int) -> Rational: + """Create a Rational from a pair of coprime integers. + + Both ``p`` and ``q`` should be strictly of type ``int``. + + The caller should ensure that ``gcd(p,q) == 1`` and ``q > 0``. + + This may be more efficient than ``Rational(p, q)``. The validity of the + arguments may or may not be checked so it should not be relied upon to + pass unvalidated or invalid arguments to this function. + """ + if q == 1: + return Integer(p) + if p == 1 and q == 2: + return S.Half + + obj = Expr.__new__(cls) + obj.p = p + obj.q = q + return obj + + def limit_denominator(self, max_denominator=1000000): + """Closest Rational to self with denominator at most max_denominator. + + Examples + ======== + + >>> from sympy import Rational + >>> Rational('3.141592653589793').limit_denominator(10) + 22/7 + >>> Rational('3.141592653589793').limit_denominator(100) + 311/99 + + """ + f = fractions.Fraction(self.p, self.q) + return Rational(f.limit_denominator(fractions.Fraction(int(max_denominator)))) + + def __getnewargs__(self): + return (self.p, self.q) + + def _hashable_content(self): + return (self.p, self.q) + + def _eval_is_positive(self): + return self.p > 0 + + def _eval_is_zero(self): + return self.p == 0 + + def __neg__(self): + return Rational(-self.p, self.q) + + @_sympifyit('other', NotImplemented) + def __add__(self, other): + if global_parameters.evaluate: + if isinstance(other, Integer): + return Rational._new(self.p + self.q*other.p, self.q, 1) + elif isinstance(other, Rational): + #TODO: this can probably be optimized more + return Rational(self.p*other.q + self.q*other.p, self.q*other.q) + elif isinstance(other, Float): + return other + self + else: + return Number.__add__(self, other) + return Number.__add__(self, other) + __radd__ = __add__ + + @_sympifyit('other', NotImplemented) + def __sub__(self, other): + if global_parameters.evaluate: + if isinstance(other, Integer): + return Rational._new(self.p - self.q*other.p, self.q, 1) + elif isinstance(other, Rational): + return Rational(self.p*other.q - self.q*other.p, self.q*other.q) + elif isinstance(other, Float): + return -other + self + else: + return Number.__sub__(self, other) + return Number.__sub__(self, other) + @_sympifyit('other', NotImplemented) + def __rsub__(self, other): + if global_parameters.evaluate: + if isinstance(other, Integer): + return Rational._new(self.q*other.p - self.p, self.q, 1) + elif isinstance(other, Rational): + return Rational(self.q*other.p - self.p*other.q, self.q*other.q) + elif isinstance(other, Float): + return -self + other + else: + return Number.__rsub__(self, other) + return Number.__rsub__(self, other) + @_sympifyit('other', NotImplemented) + def __mul__(self, other): + if global_parameters.evaluate: + if isinstance(other, Integer): + return Rational._new(self.p*other.p, self.q, igcd(other.p, self.q)) + elif isinstance(other, Rational): + return Rational._new(self.p*other.p, self.q*other.q, igcd(self.p, other.q)*igcd(self.q, other.p)) + elif isinstance(other, Float): + return other*self + else: + return Number.__mul__(self, other) + return Number.__mul__(self, other) + __rmul__ = __mul__ + + @_sympifyit('other', NotImplemented) + def __truediv__(self, other): + if global_parameters.evaluate: + if isinstance(other, Integer): + if self.p and other.p == S.Zero: + return S.ComplexInfinity + else: + return Rational._new(self.p, self.q*other.p, igcd(self.p, other.p)) + elif isinstance(other, Rational): + return Rational._new(self.p*other.q, self.q*other.p, igcd(self.p, other.p)*igcd(self.q, other.q)) + elif isinstance(other, Float): + return self*(1/other) + else: + return Number.__truediv__(self, other) + return Number.__truediv__(self, other) + @_sympifyit('other', NotImplemented) + def __rtruediv__(self, other): + if global_parameters.evaluate: + if isinstance(other, Integer): + return Rational._new(other.p*self.q, self.p, igcd(self.p, other.p)) + elif isinstance(other, Rational): + return Rational._new(other.p*self.q, other.q*self.p, igcd(self.p, other.p)*igcd(self.q, other.q)) + elif isinstance(other, Float): + return other*(1/self) + else: + return Number.__rtruediv__(self, other) + return Number.__rtruediv__(self, other) + + @_sympifyit('other', NotImplemented) + def __mod__(self, other): + if global_parameters.evaluate: + if isinstance(other, Rational): + n = (self.p*other.q) // (other.p*self.q) + return Rational(self.p*other.q - n*other.p*self.q, self.q*other.q) + if isinstance(other, Float): + # calculate mod with Rationals, *then* round the answer + return Float(self.__mod__(Rational(other)), + precision=other._prec) + return Number.__mod__(self, other) + return Number.__mod__(self, other) + + @_sympifyit('other', NotImplemented) + def __rmod__(self, other): + if isinstance(other, Rational): + return Rational.__mod__(other, self) + return Number.__rmod__(self, other) + + def _eval_power(self, expt): + if isinstance(expt, Number): + if isinstance(expt, Float): + return self._eval_evalf(expt._prec)**expt + if expt.is_extended_negative: + # (3/4)**-2 -> (4/3)**2 + ne = -expt + if (ne is S.One): + return Rational(self.q, self.p) + if self.is_negative: + return S.NegativeOne**expt*Rational(self.q, -self.p)**ne + else: + return Rational(self.q, self.p)**ne + if expt is S.Infinity: # -oo already caught by test for negative + if self.p > self.q: + # (3/2)**oo -> oo + return S.Infinity + if self.p < -self.q: + # (-3/2)**oo -> oo + I*oo + return S.Infinity + S.Infinity*S.ImaginaryUnit + return S.Zero + if isinstance(expt, Integer): + # (4/3)**2 -> 4**2 / 3**2 + return Rational._new(self.p**expt.p, self.q**expt.p, 1) + if isinstance(expt, Rational): + intpart = expt.p // expt.q + if intpart: + intpart += 1 + remfracpart = intpart*expt.q - expt.p + ratfracpart = Rational(remfracpart, expt.q) + if self.p != 1: + return Integer(self.p)**expt*Integer(self.q)**ratfracpart*Rational._new(1, self.q**intpart, 1) + return Integer(self.q)**ratfracpart*Rational._new(1, self.q**intpart, 1) + else: + remfracpart = expt.q - expt.p + ratfracpart = Rational(remfracpart, expt.q) + if self.p != 1: + return Integer(self.p)**expt*Integer(self.q)**ratfracpart*Rational._new(1, self.q, 1) + return Integer(self.q)**ratfracpart*Rational._new(1, self.q, 1) + + if self.is_extended_negative and expt.is_even: + return (-self)**expt + + return + + def _as_mpf_val(self, prec): + return mlib.from_rational(self.p, self.q, prec, rnd) + + def _mpmath_(self, prec, rnd): + return mpmath.make_mpf(mlib.from_rational(self.p, self.q, prec, rnd)) + + def __abs__(self): + return Rational(abs(self.p), self.q) + + def __int__(self): + p, q = self.p, self.q + if p < 0: + return -int(-p//q) + return int(p//q) + + def floor(self): + return Integer(self.p // self.q) + + def ceiling(self): + return -Integer(-self.p // self.q) + + def __floor__(self): + return self.floor() + + def __ceil__(self): + return self.ceiling() + + def __eq__(self, other): + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if not isinstance(other, Number): + # S(0) == S.false is False + # S(0) == False is True + return False + if other.is_NumberSymbol: + if other.is_irrational: + return False + return other.__eq__(self) + if other.is_Rational: + # a Rational is always in reduced form so will never be 2/4 + # so we can just check equivalence of args + return self.p == other.p and self.q == other.q + return False + + def __ne__(self, other): + return not self == other + + def _Rrel(self, other, attr): + # if you want self < other, pass self, other, __gt__ + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if other.is_Number: + op = None + s, o = self, other + if other.is_NumberSymbol: + op = getattr(o, attr) + elif other.is_Float: + op = getattr(o, attr) + elif other.is_Rational: + s, o = Integer(s.p*o.q), Integer(s.q*o.p) + op = getattr(o, attr) + if op: + return op(s) + if o.is_number and o.is_extended_real: + return Integer(s.p), s.q*o + + def __gt__(self, other): + rv = self._Rrel(other, '__lt__') + if rv is None: + rv = self, other + elif not isinstance(rv, tuple): + return rv + return Expr.__gt__(*rv) + + def __ge__(self, other): + rv = self._Rrel(other, '__le__') + if rv is None: + rv = self, other + elif not isinstance(rv, tuple): + return rv + return Expr.__ge__(*rv) + + def __lt__(self, other): + rv = self._Rrel(other, '__gt__') + if rv is None: + rv = self, other + elif not isinstance(rv, tuple): + return rv + return Expr.__lt__(*rv) + + def __le__(self, other): + rv = self._Rrel(other, '__ge__') + if rv is None: + rv = self, other + elif not isinstance(rv, tuple): + return rv + return Expr.__le__(*rv) + + def __hash__(self): + return super().__hash__() + + def factors(self, limit=None, use_trial=True, use_rho=False, + use_pm1=False, verbose=False, visual=False): + """A wrapper to factorint which return factors of self that are + smaller than limit (or cheap to compute). Special methods of + factoring are disabled by default so that only trial division is used. + """ + from sympy.ntheory.factor_ import factorrat + + return factorrat(self, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose).copy() + + @property + def numerator(self): + return self.p + + @property + def denominator(self): + return self.q + + @_sympifyit('other', NotImplemented) + def gcd(self, other): + if isinstance(other, Rational): + if other == S.Zero: + return other + return Rational( + igcd(self.p, other.p), + ilcm(self.q, other.q)) + return Number.gcd(self, other) + + @_sympifyit('other', NotImplemented) + def lcm(self, other): + if isinstance(other, Rational): + return Rational( + self.p // igcd(self.p, other.p) * other.p, + igcd(self.q, other.q)) + return Number.lcm(self, other) + + def as_numer_denom(self): + return Integer(self.p), Integer(self.q) + + def as_content_primitive(self, radical=False, clear=True): + """Return the tuple (R, self/R) where R is the positive Rational + extracted from self. + + Examples + ======== + + >>> from sympy import S + >>> (S(-3)/2).as_content_primitive() + (3/2, -1) + + See docstring of Expr.as_content_primitive for more examples. + """ + + if self: + if self.is_positive: + return self, S.One + return -self, S.NegativeOne + return S.One, self + + def as_coeff_Mul(self, rational=False): + """Efficiently extract the coefficient of a product.""" + return self, S.One + + def as_coeff_Add(self, rational=False): + """Efficiently extract the coefficient of a summation.""" + return self, S.Zero + + +class Integer(Rational): + """Represents integer numbers of any size. + + Examples + ======== + + >>> from sympy import Integer + >>> Integer(3) + 3 + + If a float or a rational is passed to Integer, the fractional part + will be discarded; the effect is of rounding toward zero. + + >>> Integer(3.8) + 3 + >>> Integer(-3.8) + -3 + + A string is acceptable input if it can be parsed as an integer: + + >>> Integer("9" * 20) + 99999999999999999999 + + It is rarely needed to explicitly instantiate an Integer, because + Python integers are automatically converted to Integer when they + are used in SymPy expressions. + """ + q = 1 + is_integer = True + is_number = True + + is_Integer = True + + __slots__ = () + + def _as_mpf_val(self, prec): + return mlib.from_int(self.p, prec, rnd) + + def _mpmath_(self, prec, rnd): + return mpmath.make_mpf(self._as_mpf_val(prec)) + + @cacheit + def __new__(cls, i): + if isinstance(i, str): + i = i.replace(' ', '') + # whereas we cannot, in general, make a Rational from an + # arbitrary expression, we can make an Integer unambiguously + # (except when a non-integer expression happens to round to + # an integer). So we proceed by taking int() of the input and + # let the int routines determine whether the expression can + # be made into an int or whether an error should be raised. + try: + ival = int(i) + except TypeError: + raise TypeError( + "Argument of Integer should be of numeric type, got %s." % i) + # We only work with well-behaved integer types. This converts, for + # example, numpy.int32 instances. + if ival == 1: + return S.One + if ival == -1: + return S.NegativeOne + if ival == 0: + return S.Zero + obj = Expr.__new__(cls) + obj.p = ival + return obj + + def __getnewargs__(self): + return (self.p,) + + # Arithmetic operations are here for efficiency + def __int__(self): + return self.p + + def floor(self): + return Integer(self.p) + + def ceiling(self): + return Integer(self.p) + + def __floor__(self): + return self.floor() + + def __ceil__(self): + return self.ceiling() + + def __neg__(self): + return Integer(-self.p) + + def __abs__(self): + if self.p >= 0: + return self + else: + return Integer(-self.p) + + def __divmod__(self, other): + if isinstance(other, Integer) and global_parameters.evaluate: + return Tuple(*(divmod(self.p, other.p))) + else: + return Number.__divmod__(self, other) + + def __rdivmod__(self, other): + if isinstance(other, int) and global_parameters.evaluate: + return Tuple(*(divmod(other, self.p))) + else: + try: + other = Number(other) + except TypeError: + msg = "unsupported operand type(s) for divmod(): '%s' and '%s'" + oname = type(other).__name__ + sname = type(self).__name__ + raise TypeError(msg % (oname, sname)) + return Number.__divmod__(other, self) + + # TODO make it decorator + bytecodehacks? + def __add__(self, other): + if global_parameters.evaluate: + if isinstance(other, int): + return Integer(self.p + other) + elif isinstance(other, Integer): + return Integer(self.p + other.p) + elif isinstance(other, Rational): + return Rational._new(self.p*other.q + other.p, other.q, 1) + return Rational.__add__(self, other) + else: + return Add(self, other) + + def __radd__(self, other): + if global_parameters.evaluate: + if isinstance(other, int): + return Integer(other + self.p) + elif isinstance(other, Rational): + return Rational._new(other.p + self.p*other.q, other.q, 1) + return Rational.__radd__(self, other) + return Rational.__radd__(self, other) + + def __sub__(self, other): + if global_parameters.evaluate: + if isinstance(other, int): + return Integer(self.p - other) + elif isinstance(other, Integer): + return Integer(self.p - other.p) + elif isinstance(other, Rational): + return Rational._new(self.p*other.q - other.p, other.q, 1) + return Rational.__sub__(self, other) + return Rational.__sub__(self, other) + + def __rsub__(self, other): + if global_parameters.evaluate: + if isinstance(other, int): + return Integer(other - self.p) + elif isinstance(other, Rational): + return Rational._new(other.p - self.p*other.q, other.q, 1) + return Rational.__rsub__(self, other) + return Rational.__rsub__(self, other) + + def __mul__(self, other): + if global_parameters.evaluate: + if isinstance(other, int): + return Integer(self.p*other) + elif isinstance(other, Integer): + return Integer(self.p*other.p) + elif isinstance(other, Rational): + return Rational._new(self.p*other.p, other.q, igcd(self.p, other.q)) + return Rational.__mul__(self, other) + return Rational.__mul__(self, other) + + def __rmul__(self, other): + if global_parameters.evaluate: + if isinstance(other, int): + return Integer(other*self.p) + elif isinstance(other, Rational): + return Rational._new(other.p*self.p, other.q, igcd(self.p, other.q)) + return Rational.__rmul__(self, other) + return Rational.__rmul__(self, other) + + def __mod__(self, other): + if global_parameters.evaluate: + if isinstance(other, int): + return Integer(self.p % other) + elif isinstance(other, Integer): + return Integer(self.p % other.p) + return Rational.__mod__(self, other) + return Rational.__mod__(self, other) + + def __rmod__(self, other): + if global_parameters.evaluate: + if isinstance(other, int): + return Integer(other % self.p) + elif isinstance(other, Integer): + return Integer(other.p % self.p) + return Rational.__rmod__(self, other) + return Rational.__rmod__(self, other) + + def __eq__(self, other): + if isinstance(other, int): + return (self.p == other) + elif isinstance(other, Integer): + return (self.p == other.p) + return Rational.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + def __gt__(self, other): + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if other.is_Integer: + return _sympify(self.p > other.p) + return Rational.__gt__(self, other) + + def __lt__(self, other): + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if other.is_Integer: + return _sympify(self.p < other.p) + return Rational.__lt__(self, other) + + def __ge__(self, other): + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if other.is_Integer: + return _sympify(self.p >= other.p) + return Rational.__ge__(self, other) + + def __le__(self, other): + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if other.is_Integer: + return _sympify(self.p <= other.p) + return Rational.__le__(self, other) + + def __hash__(self): + return hash(self.p) + + def __index__(self): + return self.p + + ######################################## + + def _eval_is_odd(self): + return bool(self.p % 2) + + def _eval_power(self, expt): + """ + Tries to do some simplifications on self**expt + + Returns None if no further simplifications can be done. + + Explanation + =========== + + When exponent is a fraction (so we have for example a square root), + we try to find a simpler representation by factoring the argument + up to factors of 2**15, e.g. + + - sqrt(4) becomes 2 + - sqrt(-4) becomes 2*I + - (2**(3+7)*3**(6+7))**Rational(1,7) becomes 6*18**(3/7) + + Further simplification would require a special call to factorint on + the argument which is not done here for sake of speed. + + """ + from sympy.ntheory.factor_ import perfect_power + + if expt is S.Infinity: + if self.p > S.One: + return S.Infinity + # cases -1, 0, 1 are done in their respective classes + return S.Infinity + S.ImaginaryUnit*S.Infinity + if expt is S.NegativeInfinity: + return Rational._new(1, self, 1)**S.Infinity + if not isinstance(expt, Number): + # simplify when expt is even + # (-2)**k --> 2**k + if self.is_negative and expt.is_even: + return (-self)**expt + if isinstance(expt, Float): + # Rational knows how to exponentiate by a Float + return super()._eval_power(expt) + if not isinstance(expt, Rational): + return + if expt is S.Half and self.is_negative: + # we extract I for this special case since everyone is doing so + return S.ImaginaryUnit*Pow(-self, expt) + if expt.is_negative: + # invert base and change sign on exponent + ne = -expt + if self.is_negative: + return S.NegativeOne**expt*Rational._new(1, -self.p, 1)**ne + else: + return Rational._new(1, self.p, 1)**ne + # see if base is a perfect root, sqrt(4) --> 2 + x, xexact = integer_nthroot(abs(self.p), expt.q) + if xexact: + # if it's a perfect root we've finished + result = Integer(x**abs(expt.p)) + if self.is_negative: + result *= S.NegativeOne**expt + return result + + # The following is an algorithm where we collect perfect roots + # from the factors of base. + + # if it's not an nth root, it still might be a perfect power + b_pos = int(abs(self.p)) + p = perfect_power(b_pos) + if p is not False: + # XXX: Convert to int because perfect_power may return fmpz + # Ideally that should be fixed in perfect_power though... + dict = {int(p[0]): int(p[1])} + else: + dict = Integer(b_pos).factors(limit=2**15) + + # now process the dict of factors + out_int = 1 # integer part + out_rad = 1 # extracted radicals + sqr_int = 1 + sqr_gcd = 0 + sqr_dict = {} + for prime, exponent in dict.items(): + exponent *= expt.p + # remove multiples of expt.q: (2**12)**(1/10) -> 2*(2**2)**(1/10) + div_e, div_m = divmod(exponent, expt.q) + if div_e > 0: + out_int *= prime**div_e + if div_m > 0: + # see if the reduced exponent shares a gcd with e.q + # (2**2)**(1/10) -> 2**(1/5) + g = igcd(div_m, expt.q) + if g != 1: + out_rad *= Pow(prime, Rational._new(div_m//g, expt.q//g, 1)) + else: + sqr_dict[prime] = div_m + # identify gcd of remaining powers + for p, ex in sqr_dict.items(): + if sqr_gcd == 0: + sqr_gcd = ex + else: + sqr_gcd = igcd(sqr_gcd, ex) + if sqr_gcd == 1: + break + for k, v in sqr_dict.items(): + sqr_int *= k**(v//sqr_gcd) + if sqr_int == b_pos and out_int == 1 and out_rad == 1: + result = None + else: + result = out_int*out_rad*Pow(sqr_int, Rational(sqr_gcd, expt.q)) + if self.is_negative: + result *= Pow(S.NegativeOne, expt) + return result + + def _eval_is_prime(self): + from sympy.ntheory.primetest import isprime + + return isprime(self) + + def _eval_is_composite(self): + if self > 1: + return fuzzy_not(self.is_prime) + else: + return False + + def as_numer_denom(self): + return self, S.One + + @_sympifyit('other', NotImplemented) + def __floordiv__(self, other): + if not isinstance(other, Expr): + return NotImplemented + if isinstance(other, Integer): + return Integer(self.p // other) + return divmod(self, other)[0] + + def __rfloordiv__(self, other): + return Integer(Integer(other).p // self.p) + + # These bitwise operations (__lshift__, __rlshift__, ..., __invert__) are defined + # for Integer only and not for general SymPy expressions. This is to achieve + # compatibility with the numbers.Integral ABC which only defines these operations + # among instances of numbers.Integral. Therefore, these methods check explicitly for + # integer types rather than using sympify because they should not accept arbitrary + # symbolic expressions and there is no symbolic analogue of numbers.Integral's + # bitwise operations. + def __lshift__(self, other): + if isinstance(other, (int, Integer, numbers.Integral)): + return Integer(self.p << int(other)) + else: + return NotImplemented + + def __rlshift__(self, other): + if isinstance(other, (int, numbers.Integral)): + return Integer(int(other) << self.p) + else: + return NotImplemented + + def __rshift__(self, other): + if isinstance(other, (int, Integer, numbers.Integral)): + return Integer(self.p >> int(other)) + else: + return NotImplemented + + def __rrshift__(self, other): + if isinstance(other, (int, numbers.Integral)): + return Integer(int(other) >> self.p) + else: + return NotImplemented + + def __and__(self, other): + if isinstance(other, (int, Integer, numbers.Integral)): + return Integer(self.p & int(other)) + else: + return NotImplemented + + def __rand__(self, other): + if isinstance(other, (int, numbers.Integral)): + return Integer(int(other) & self.p) + else: + return NotImplemented + + def __xor__(self, other): + if isinstance(other, (int, Integer, numbers.Integral)): + return Integer(self.p ^ int(other)) + else: + return NotImplemented + + def __rxor__(self, other): + if isinstance(other, (int, numbers.Integral)): + return Integer(int(other) ^ self.p) + else: + return NotImplemented + + def __or__(self, other): + if isinstance(other, (int, Integer, numbers.Integral)): + return Integer(self.p | int(other)) + else: + return NotImplemented + + def __ror__(self, other): + if isinstance(other, (int, numbers.Integral)): + return Integer(int(other) | self.p) + else: + return NotImplemented + + def __invert__(self): + return Integer(~self.p) + +# Add sympify converters +_sympy_converter[int] = Integer + + +class AlgebraicNumber(Expr): + r""" + Class for representing algebraic numbers in SymPy. + + Symbolically, an instance of this class represents an element + $\alpha \in \mathbb{Q}(\theta) \hookrightarrow \mathbb{C}$. That is, the + algebraic number $\alpha$ is represented as an element of a particular + number field $\mathbb{Q}(\theta)$, with a particular embedding of this + field into the complex numbers. + + Formally, the primitive element $\theta$ is given by two data points: (1) + its minimal polynomial (which defines $\mathbb{Q}(\theta)$), and (2) a + particular complex number that is a root of this polynomial (which defines + the embedding $\mathbb{Q}(\theta) \hookrightarrow \mathbb{C}$). Finally, + the algebraic number $\alpha$ which we represent is then given by the + coefficients of a polynomial in $\theta$. + """ + + __slots__ = ('rep', 'root', 'alias', 'minpoly', '_own_minpoly') + + is_AlgebraicNumber = True + is_algebraic = True + is_number = True + + + kind = NumberKind + + # Optional alias symbol is not free. + # Actually, alias should be a Str, but some methods + # expect that it be an instance of Expr. + free_symbols: set[Basic] = set() + + def __new__(cls, expr, coeffs=None, alias=None, **args): + r""" + Construct a new algebraic number $\alpha$ belonging to a number field + $k = \mathbb{Q}(\theta)$. + + There are four instance attributes to be determined: + + =========== ============================================================================ + Attribute Type/Meaning + =========== ============================================================================ + ``root`` :py:class:`~.Expr` for $\theta$ as a complex number + ``minpoly`` :py:class:`~.Poly`, the minimal polynomial of $\theta$ + ``rep`` :py:class:`~sympy.polys.polyclasses.DMP` giving $\alpha$ as poly in $\theta$ + ``alias`` :py:class:`~.Symbol` for $\theta$, or ``None`` + =========== ============================================================================ + + See Parameters section for how they are determined. + + Parameters + ========== + + expr : :py:class:`~.Expr`, or pair $(m, r)$ + There are three distinct modes of construction, depending on what + is passed as *expr*. + + **(1)** *expr* is an :py:class:`~.AlgebraicNumber`: + In this case we begin by copying all four instance attributes from + *expr*. If *coeffs* were also given, we compose the two coeff + polynomials (see below). If an *alias* was given, it overrides. + + **(2)** *expr* is any other type of :py:class:`~.Expr`: + Then ``root`` will equal *expr*. Therefore it + must express an algebraic quantity, and we will compute its + ``minpoly``. + + **(3)** *expr* is an ordered pair $(m, r)$ giving the + ``minpoly`` $m$, and a ``root`` $r$ thereof, which together + define $\theta$. In this case $m$ may be either a univariate + :py:class:`~.Poly` or any :py:class:`~.Expr` which represents the + same, while $r$ must be some :py:class:`~.Expr` representing a + complex number that is a root of $m$, including both explicit + expressions in radicals, and instances of + :py:class:`~.ComplexRootOf` or :py:class:`~.AlgebraicNumber`. + + coeffs : list, :py:class:`~.ANP`, None, optional (default=None) + This defines ``rep``, giving the algebraic number $\alpha$ as a + polynomial in $\theta$. + + If a list, the elements should be integers or rational numbers. + If an :py:class:`~.ANP`, we take its coefficients (using its + :py:meth:`~.ANP.to_list()` method). If ``None``, then the list of + coefficients defaults to ``[1, 0]``, meaning that $\alpha = \theta$ + is the primitive element of the field. + + If *expr* was an :py:class:`~.AlgebraicNumber`, let $g(x)$ be its + ``rep`` polynomial, and let $f(x)$ be the polynomial defined by + *coeffs*. Then ``self.rep`` will represent the composition + $(f \circ g)(x)$. + + alias : str, :py:class:`~.Symbol`, None, optional (default=None) + This is a way to provide a name for the primitive element. We + described several ways in which the *expr* argument can define the + value of the primitive element, but none of these methods gave it + a name. Here, for example, *alias* could be set as + ``Symbol('theta')``, in order to make this symbol appear when + $\alpha$ is printed, or rendered as a polynomial, using the + :py:meth:`~.as_poly()` method. + + Examples + ======== + + Recall that we are constructing an algebraic number as a field element + $\alpha \in \mathbb{Q}(\theta)$. + + >>> from sympy import AlgebraicNumber, sqrt, CRootOf, S + >>> from sympy.abc import x + + Example (1): $\alpha = \theta = \sqrt{2}$ + + >>> a1 = AlgebraicNumber(sqrt(2)) + >>> a1.minpoly_of_element().as_expr(x) + x**2 - 2 + >>> a1.evalf(10) + 1.414213562 + + Example (2): $\alpha = 3 \sqrt{2} - 5$, $\theta = \sqrt{2}$. We can + either build on the last example: + + >>> a2 = AlgebraicNumber(a1, [3, -5]) + >>> a2.as_expr() + -5 + 3*sqrt(2) + + or start from scratch: + + >>> a2 = AlgebraicNumber(sqrt(2), [3, -5]) + >>> a2.as_expr() + -5 + 3*sqrt(2) + + Example (3): $\alpha = 6 \sqrt{2} - 11$, $\theta = \sqrt{2}$. Again we + can build on the previous example, and we see that the coeff polys are + composed: + + >>> a3 = AlgebraicNumber(a2, [2, -1]) + >>> a3.as_expr() + -11 + 6*sqrt(2) + + reflecting the fact that $(2x - 1) \circ (3x - 5) = 6x - 11$. + + Example (4): $\alpha = \sqrt{2}$, $\theta = \sqrt{2} + \sqrt{3}$. The + easiest way is to use the :py:func:`~.to_number_field()` function: + + >>> from sympy import to_number_field + >>> a4 = to_number_field(sqrt(2), sqrt(2) + sqrt(3)) + >>> a4.minpoly_of_element().as_expr(x) + x**2 - 2 + >>> a4.to_root() + sqrt(2) + >>> a4.primitive_element() + sqrt(2) + sqrt(3) + >>> a4.coeffs() + [1/2, 0, -9/2, 0] + + but if you already knew the right coefficients, you could construct it + directly: + + >>> a4 = AlgebraicNumber(sqrt(2) + sqrt(3), [S(1)/2, 0, S(-9)/2, 0]) + >>> a4.to_root() + sqrt(2) + >>> a4.primitive_element() + sqrt(2) + sqrt(3) + + Example (5): Construct the Golden Ratio as an element of the 5th + cyclotomic field, supposing we already know its coefficients. This time + we introduce the alias $\zeta$ for the primitive element of the field: + + >>> from sympy import cyclotomic_poly + >>> from sympy.abc import zeta + >>> a5 = AlgebraicNumber(CRootOf(cyclotomic_poly(5), -1), + ... [-1, -1, 0, 0], alias=zeta) + >>> a5.as_poly().as_expr() + -zeta**3 - zeta**2 + >>> a5.evalf() + 1.61803398874989 + + (The index ``-1`` to ``CRootOf`` selects the complex root with the + largest real and imaginary parts, which in this case is + $\mathrm{e}^{2i\pi/5}$. See :py:class:`~.ComplexRootOf`.) + + Example (6): Building on the last example, construct the number + $2 \phi \in \mathbb{Q}(\phi)$, where $\phi$ is the Golden Ratio: + + >>> from sympy.abc import phi + >>> a6 = AlgebraicNumber(a5.to_root(), coeffs=[2, 0], alias=phi) + >>> a6.as_poly().as_expr() + 2*phi + >>> a6.primitive_element().evalf() + 1.61803398874989 + + Note that we needed to use ``a5.to_root()``, since passing ``a5`` as + the first argument would have constructed the number $2 \phi$ as an + element of the field $\mathbb{Q}(\zeta)$: + + >>> a6_wrong = AlgebraicNumber(a5, coeffs=[2, 0]) + >>> a6_wrong.as_poly().as_expr() + -2*zeta**3 - 2*zeta**2 + >>> a6_wrong.primitive_element().evalf() + 0.309016994374947 + 0.951056516295154*I + + """ + from sympy.polys.polyclasses import ANP, DMP + from sympy.polys.numberfields import minimal_polynomial + + expr = sympify(expr) + rep0 = None + alias0 = None + + if isinstance(expr, (tuple, Tuple)): + minpoly, root = expr + + if not minpoly.is_Poly: + from sympy.polys.polytools import Poly + minpoly = Poly(minpoly) + elif expr.is_AlgebraicNumber: + minpoly, root, rep0, alias0 = (expr.minpoly, expr.root, + expr.rep, expr.alias) + else: + minpoly, root = minimal_polynomial( + expr, args.get('gen'), polys=True), expr + + dom = minpoly.get_domain() + + if coeffs is not None: + if not isinstance(coeffs, ANP): + rep = DMP.from_sympy_list(sympify(coeffs), 0, dom) + scoeffs = Tuple(*coeffs) + else: + rep = DMP.from_list(coeffs.to_list(), 0, dom) + scoeffs = Tuple(*coeffs.to_list()) + + else: + rep = DMP.from_list([1, 0], 0, dom) + scoeffs = Tuple(1, 0) + + if rep0 is not None: + from sympy.polys.densetools import dup_compose + c = dup_compose(rep.to_list(), rep0.to_list(), dom) + rep = DMP.from_list(c, 0, dom) + scoeffs = Tuple(*c) + + if rep.degree() >= minpoly.degree(): + rep = rep.rem(minpoly.rep) + + sargs = (root, scoeffs) + + alias = alias or alias0 + if alias is not None: + from .symbol import Symbol + if not isinstance(alias, Symbol): + alias = Symbol(alias) + sargs = sargs + (alias,) + + obj = Expr.__new__(cls, *sargs) + + obj.rep = rep + obj.root = root + obj.alias = alias + obj.minpoly = minpoly + + obj._own_minpoly = None + + return obj + + def __hash__(self): + return super().__hash__() + + def _eval_evalf(self, prec): + return self.as_expr()._evalf(prec) + + @property + def is_aliased(self): + """Returns ``True`` if ``alias`` was set. """ + return self.alias is not None + + def as_poly(self, x=None): + """Create a Poly instance from ``self``. """ + from sympy.polys.polytools import Poly, PurePoly + if x is not None: + return Poly.new(self.rep, x) + else: + if self.alias is not None: + return Poly.new(self.rep, self.alias) + else: + from .symbol import Dummy + return PurePoly.new(self.rep, Dummy('x')) + + def as_expr(self, x=None): + """Create a Basic expression from ``self``. """ + return self.as_poly(x or self.root).as_expr().expand() + + def coeffs(self): + """Returns all SymPy coefficients of an algebraic number. """ + return [ self.rep.dom.to_sympy(c) for c in self.rep.all_coeffs() ] + + def native_coeffs(self): + """Returns all native coefficients of an algebraic number. """ + return self.rep.all_coeffs() + + def to_algebraic_integer(self): + """Convert ``self`` to an algebraic integer. """ + from sympy.polys.polytools import Poly + + f = self.minpoly + + if f.LC() == 1: + return self + + coeff = f.LC()**(f.degree() - 1) + poly = f.compose(Poly(f.gen/f.LC())) + + minpoly = poly*coeff + root = f.LC()*self.root + + return AlgebraicNumber((minpoly, root), self.coeffs()) + + def _eval_simplify(self, **kwargs): + from sympy.polys.rootoftools import CRootOf + from sympy.polys import minpoly + measure, ratio = kwargs['measure'], kwargs['ratio'] + for r in [r for r in self.minpoly.all_roots() if r.func != CRootOf]: + if minpoly(self.root - r).is_Symbol: + # use the matching root if it's simpler + if measure(r) < ratio*measure(self.root): + return AlgebraicNumber(r) + return self + + def field_element(self, coeffs): + r""" + Form another element of the same number field. + + Explanation + =========== + + If we represent $\alpha \in \mathbb{Q}(\theta)$, form another element + $\beta \in \mathbb{Q}(\theta)$ of the same number field. + + Parameters + ========== + + coeffs : list, :py:class:`~.ANP` + Like the *coeffs* arg to the class + :py:meth:`constructor<.AlgebraicNumber.__new__>`, defines the + new element as a polynomial in the primitive element. + + If a list, the elements should be integers or rational numbers. + If an :py:class:`~.ANP`, we take its coefficients (using its + :py:meth:`~.ANP.to_list()` method). + + Examples + ======== + + >>> from sympy import AlgebraicNumber, sqrt + >>> a = AlgebraicNumber(sqrt(5), [-1, 1]) + >>> b = a.field_element([3, 2]) + >>> print(a) + 1 - sqrt(5) + >>> print(b) + 2 + 3*sqrt(5) + >>> print(b.primitive_element() == a.primitive_element()) + True + + See Also + ======== + + AlgebraicNumber + """ + return AlgebraicNumber( + (self.minpoly, self.root), coeffs=coeffs, alias=self.alias) + + @property + def is_primitive_element(self): + r""" + Say whether this algebraic number $\alpha \in \mathbb{Q}(\theta)$ is + equal to the primitive element $\theta$ for its field. + """ + c = self.coeffs() + # Second case occurs if self.minpoly is linear: + return c == [1, 0] or c == [self.root] + + def primitive_element(self): + r""" + Get the primitive element $\theta$ for the number field + $\mathbb{Q}(\theta)$ to which this algebraic number $\alpha$ belongs. + + Returns + ======= + + AlgebraicNumber + + """ + if self.is_primitive_element: + return self + return self.field_element([1, 0]) + + def to_primitive_element(self, radicals=True): + r""" + Convert ``self`` to an :py:class:`~.AlgebraicNumber` instance that is + equal to its own primitive element. + + Explanation + =========== + + If we represent $\alpha \in \mathbb{Q}(\theta)$, $\alpha \neq \theta$, + construct a new :py:class:`~.AlgebraicNumber` that represents + $\alpha \in \mathbb{Q}(\alpha)$. + + Examples + ======== + + >>> from sympy import sqrt, to_number_field + >>> from sympy.abc import x + >>> a = to_number_field(sqrt(2), sqrt(2) + sqrt(3)) + + The :py:class:`~.AlgebraicNumber` ``a`` represents the number + $\sqrt{2}$ in the field $\mathbb{Q}(\sqrt{2} + \sqrt{3})$. Rendering + ``a`` as a polynomial, + + >>> a.as_poly().as_expr(x) + x**3/2 - 9*x/2 + + reflects the fact that $\sqrt{2} = \theta^3/2 - 9 \theta/2$, where + $\theta = \sqrt{2} + \sqrt{3}$. + + ``a`` is not equal to its own primitive element. Its minpoly + + >>> a.minpoly.as_poly().as_expr(x) + x**4 - 10*x**2 + 1 + + is that of $\theta$. + + Converting to a primitive element, + + >>> a_prim = a.to_primitive_element() + >>> a_prim.minpoly.as_poly().as_expr(x) + x**2 - 2 + + we obtain an :py:class:`~.AlgebraicNumber` whose ``minpoly`` is that of + the number itself. + + Parameters + ========== + + radicals : boolean, optional (default=True) + If ``True``, then we will try to return an + :py:class:`~.AlgebraicNumber` whose ``root`` is an expression + in radicals. If that is not possible (or if *radicals* is + ``False``), ``root`` will be a :py:class:`~.ComplexRootOf`. + + Returns + ======= + + AlgebraicNumber + + See Also + ======== + + is_primitive_element + + """ + if self.is_primitive_element: + return self + m = self.minpoly_of_element() + r = self.to_root(radicals=radicals) + return AlgebraicNumber((m, r)) + + def minpoly_of_element(self): + r""" + Compute the minimal polynomial for this algebraic number. + + Explanation + =========== + + Recall that we represent an element $\alpha \in \mathbb{Q}(\theta)$. + Our instance attribute ``self.minpoly`` is the minimal polynomial for + our primitive element $\theta$. This method computes the minimal + polynomial for $\alpha$. + + """ + if self._own_minpoly is None: + if self.is_primitive_element: + self._own_minpoly = self.minpoly + else: + from sympy.polys.numberfields.minpoly import minpoly + theta = self.primitive_element() + self._own_minpoly = minpoly(self.as_expr(theta), polys=True) + return self._own_minpoly + + def to_root(self, radicals=True, minpoly=None): + """ + Convert to an :py:class:`~.Expr` that is not an + :py:class:`~.AlgebraicNumber`, specifically, either a + :py:class:`~.ComplexRootOf`, or, optionally and where possible, an + expression in radicals. + + Parameters + ========== + + radicals : boolean, optional (default=True) + If ``True``, then we will try to return the root as an expression + in radicals. If that is not possible, we will return a + :py:class:`~.ComplexRootOf`. + + minpoly : :py:class:`~.Poly` + If the minimal polynomial for `self` has been pre-computed, it can + be passed in order to save time. + + """ + if self.is_primitive_element and not isinstance(self.root, AlgebraicNumber): + return self.root + m = minpoly or self.minpoly_of_element() + roots = m.all_roots(radicals=radicals) + if len(roots) == 1: + return roots[0] + ex = self.as_expr() + for b in roots: + if m.same_root(b, ex): + return b + + +class RationalConstant(Rational): + """ + Abstract base class for rationals with specific behaviors + + Derived classes must define class attributes p and q and should probably all + be singletons. + """ + __slots__ = () + + def __new__(cls): + return AtomicExpr.__new__(cls) + + +class IntegerConstant(Integer): + __slots__ = () + + def __new__(cls): + return AtomicExpr.__new__(cls) + + +class Zero(IntegerConstant, metaclass=Singleton): + """The number zero. + + Zero is a singleton, and can be accessed by ``S.Zero`` + + Examples + ======== + + >>> from sympy import S, Integer + >>> Integer(0) is S.Zero + True + >>> 1/S.Zero + zoo + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Zero + """ + + p = 0 + q = 1 + is_positive = False + is_negative = False + is_zero = True + is_number = True + is_comparable = True + + __slots__ = () + + def __getnewargs__(self): + return () + + @staticmethod + def __abs__(): + return S.Zero + + @staticmethod + def __neg__(): + return S.Zero + + def _eval_power(self, expt): + if expt.is_extended_positive: + return self + if expt.is_extended_negative: + return S.ComplexInfinity + if expt.is_extended_real is False: + return S.NaN + if expt.is_zero: + return S.One + + # infinities are already handled with pos and neg + # tests above; now throw away leading numbers on Mul + # exponent since 0**-x = zoo**x even when x == 0 + coeff, terms = expt.as_coeff_Mul() + if coeff.is_negative: + return S.ComplexInfinity**terms + if coeff is not S.One: # there is a Number to discard + return self**terms + + def _eval_order(self, *symbols): + # Order(0,x) -> 0 + return self + + def __bool__(self): + return False + + +class One(IntegerConstant, metaclass=Singleton): + """The number one. + + One is a singleton, and can be accessed by ``S.One``. + + Examples + ======== + + >>> from sympy import S, Integer + >>> Integer(1) is S.One + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/1_%28number%29 + """ + is_number = True + is_positive = True + + p = 1 + q = 1 + + __slots__ = () + + def __getnewargs__(self): + return () + + @staticmethod + def __abs__(): + return S.One + + @staticmethod + def __neg__(): + return S.NegativeOne + + def _eval_power(self, expt): + return self + + def _eval_order(self, *symbols): + return + + @staticmethod + def factors(limit=None, use_trial=True, use_rho=False, use_pm1=False, + verbose=False, visual=False): + if visual: + return S.One + else: + return {} + + +class NegativeOne(IntegerConstant, metaclass=Singleton): + """The number negative one. + + NegativeOne is a singleton, and can be accessed by ``S.NegativeOne``. + + Examples + ======== + + >>> from sympy import S, Integer + >>> Integer(-1) is S.NegativeOne + True + + See Also + ======== + + One + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/%E2%88%921_%28number%29 + + """ + is_number = True + + p = -1 + q = 1 + + __slots__ = () + + def __getnewargs__(self): + return () + + @staticmethod + def __abs__(): + return S.One + + @staticmethod + def __neg__(): + return S.One + + def _eval_power(self, expt): + if expt.is_odd: + return S.NegativeOne + if expt.is_even: + return S.One + if isinstance(expt, Number): + if isinstance(expt, Float): + return Float(-1.0)**expt + if expt is S.NaN: + return S.NaN + if expt in (S.Infinity, S.NegativeInfinity): + return S.NaN + if expt is S.Half: + return S.ImaginaryUnit + if isinstance(expt, Rational): + if expt.q == 2: + return S.ImaginaryUnit**Integer(expt.p) + i, r = divmod(expt.p, expt.q) + if i: + return self**i*self**Rational(r, expt.q) + return + + +class Half(RationalConstant, metaclass=Singleton): + """The rational number 1/2. + + Half is a singleton, and can be accessed by ``S.Half``. + + Examples + ======== + + >>> from sympy import S, Rational + >>> Rational(1, 2) is S.Half + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/One_half + """ + is_number = True + + p = 1 + q = 2 + + __slots__ = () + + def __getnewargs__(self): + return () + + @staticmethod + def __abs__(): + return S.Half + + +class Infinity(Number, metaclass=Singleton): + r"""Positive infinite quantity. + + Explanation + =========== + + In real analysis the symbol `\infty` denotes an unbounded + limit: `x\to\infty` means that `x` grows without bound. + + Infinity is often used not only to define a limit but as a value + in the affinely extended real number system. Points labeled `+\infty` + and `-\infty` can be added to the topological space of the real numbers, + producing the two-point compactification of the real numbers. Adding + algebraic properties to this gives us the extended real numbers. + + Infinity is a singleton, and can be accessed by ``S.Infinity``, + or can be imported as ``oo``. + + Examples + ======== + + >>> from sympy import oo, exp, limit, Symbol + >>> 1 + oo + oo + >>> 42/oo + 0 + >>> x = Symbol('x') + >>> limit(exp(x), x, oo) + oo + + See Also + ======== + + NegativeInfinity, NaN + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Infinity + """ + + is_commutative = True + is_number = True + is_complex = False + is_extended_real = True + is_infinite = True + is_comparable = True + is_extended_positive = True + is_prime = False + + __slots__ = () + + def __new__(cls): + return AtomicExpr.__new__(cls) + + def _latex(self, printer): + return r"\infty" + + def _eval_subs(self, old, new): + if self == old: + return new + + def _eval_evalf(self, prec=None): + return Float('inf') + + def evalf(self, prec=None, **options): + return self._eval_evalf(prec) + + @_sympifyit('other', NotImplemented) + def __add__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other in (S.NegativeInfinity, S.NaN): + return S.NaN + return self + return Number.__add__(self, other) + __radd__ = __add__ + + @_sympifyit('other', NotImplemented) + def __sub__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other in (S.Infinity, S.NaN): + return S.NaN + return self + return Number.__sub__(self, other) + + @_sympifyit('other', NotImplemented) + def __rsub__(self, other): + return (-self).__add__(other) + + @_sympifyit('other', NotImplemented) + def __mul__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other.is_zero or other is S.NaN: + return S.NaN + if other.is_extended_positive: + return self + return S.NegativeInfinity + return Number.__mul__(self, other) + __rmul__ = __mul__ + + @_sympifyit('other', NotImplemented) + def __truediv__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other is S.Infinity or \ + other is S.NegativeInfinity or \ + other is S.NaN: + return S.NaN + if other.is_extended_nonnegative: + return self + return S.NegativeInfinity + return Number.__truediv__(self, other) + + def __abs__(self): + return S.Infinity + + def __neg__(self): + return S.NegativeInfinity + + def _eval_power(self, expt): + """ + ``expt`` is symbolic object but not equal to 0 or 1. + + ================ ======= ============================== + Expression Result Notes + ================ ======= ============================== + ``oo ** nan`` ``nan`` + ``oo ** -p`` ``0`` ``p`` is number, ``oo`` + ================ ======= ============================== + + See Also + ======== + Pow + NaN + NegativeInfinity + + """ + if expt.is_extended_positive: + return S.Infinity + if expt.is_extended_negative: + return S.Zero + if expt is S.NaN: + return S.NaN + if expt is S.ComplexInfinity: + return S.NaN + if expt.is_extended_real is False and expt.is_number: + from sympy.functions.elementary.complexes import re + expt_real = re(expt) + if expt_real.is_positive: + return S.ComplexInfinity + if expt_real.is_negative: + return S.Zero + if expt_real.is_zero: + return S.NaN + + return self**expt.evalf() + + def _as_mpf_val(self, prec): + return mlib.finf + + def __hash__(self): + return super().__hash__() + + def __eq__(self, other): + return other is S.Infinity or other == float('inf') + + def __ne__(self, other): + return other is not S.Infinity and other != float('inf') + + __gt__ = Expr.__gt__ + __ge__ = Expr.__ge__ + __lt__ = Expr.__lt__ + __le__ = Expr.__le__ + + @_sympifyit('other', NotImplemented) + def __mod__(self, other): + if not isinstance(other, Expr): + return NotImplemented + return S.NaN + + __rmod__ = __mod__ + + def floor(self): + return self + + def ceiling(self): + return self + +oo = S.Infinity + + +class NegativeInfinity(Number, metaclass=Singleton): + """Negative infinite quantity. + + NegativeInfinity is a singleton, and can be accessed + by ``S.NegativeInfinity``. + + See Also + ======== + + Infinity + """ + + is_extended_real = True + is_complex = False + is_commutative = True + is_infinite = True + is_comparable = True + is_extended_negative = True + is_number = True + is_prime = False + + __slots__ = () + + def __new__(cls): + return AtomicExpr.__new__(cls) + + def _latex(self, printer): + return r"-\infty" + + def _eval_subs(self, old, new): + if self == old: + return new + + def _eval_evalf(self, prec=None): + return Float('-inf') + + def evalf(self, prec=None, **options): + return self._eval_evalf(prec) + + @_sympifyit('other', NotImplemented) + def __add__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other in (S.Infinity, S.NaN): + return S.NaN + return self + return Number.__add__(self, other) + __radd__ = __add__ + + @_sympifyit('other', NotImplemented) + def __sub__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other in (S.NegativeInfinity, S.NaN): + return S.NaN + return self + return Number.__sub__(self, other) + + @_sympifyit('other', NotImplemented) + def __rsub__(self, other): + return (-self).__add__(other) + + @_sympifyit('other', NotImplemented) + def __mul__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other.is_zero or other is S.NaN: + return S.NaN + if other.is_extended_positive: + return self + return S.Infinity + return Number.__mul__(self, other) + __rmul__ = __mul__ + + @_sympifyit('other', NotImplemented) + def __truediv__(self, other): + if isinstance(other, Number) and global_parameters.evaluate: + if other is S.Infinity or \ + other is S.NegativeInfinity or \ + other is S.NaN: + return S.NaN + if other.is_extended_nonnegative: + return self + return S.Infinity + return Number.__truediv__(self, other) + + def __abs__(self): + return S.Infinity + + def __neg__(self): + return S.Infinity + + def _eval_power(self, expt): + """ + ``expt`` is symbolic object but not equal to 0 or 1. + + ================ ======= ============================== + Expression Result Notes + ================ ======= ============================== + ``(-oo) ** nan`` ``nan`` + ``(-oo) ** oo`` ``nan`` + ``(-oo) ** -oo`` ``nan`` + ``(-oo) ** e`` ``oo`` ``e`` is positive even integer + ``(-oo) ** o`` ``-oo`` ``o`` is positive odd integer + ================ ======= ============================== + + See Also + ======== + + Infinity + Pow + NaN + + """ + if expt.is_number: + if expt is S.NaN or \ + expt is S.Infinity or \ + expt is S.NegativeInfinity: + return S.NaN + + if isinstance(expt, Integer) and expt.is_extended_positive: + if expt.is_odd: + return S.NegativeInfinity + else: + return S.Infinity + + inf_part = S.Infinity**expt + s_part = S.NegativeOne**expt + if inf_part == 0 and s_part.is_finite: + return inf_part + if (inf_part is S.ComplexInfinity and + s_part.is_finite and not s_part.is_zero): + return S.ComplexInfinity + return s_part*inf_part + + def _as_mpf_val(self, prec): + return mlib.fninf + + def __hash__(self): + return super().__hash__() + + def __eq__(self, other): + return other is S.NegativeInfinity or other == float('-inf') + + def __ne__(self, other): + return other is not S.NegativeInfinity and other != float('-inf') + + __gt__ = Expr.__gt__ + __ge__ = Expr.__ge__ + __lt__ = Expr.__lt__ + __le__ = Expr.__le__ + + @_sympifyit('other', NotImplemented) + def __mod__(self, other): + if not isinstance(other, Expr): + return NotImplemented + return S.NaN + + __rmod__ = __mod__ + + def floor(self): + return self + + def ceiling(self): + return self + + def as_powers_dict(self): + return {S.NegativeOne: 1, S.Infinity: 1} + + +class NaN(Number, metaclass=Singleton): + """ + Not a Number. + + Explanation + =========== + + This serves as a place holder for numeric values that are indeterminate. + Most operations on NaN, produce another NaN. Most indeterminate forms, + such as ``0/0`` or ``oo - oo` produce NaN. Two exceptions are ``0**0`` + and ``oo**0``, which all produce ``1`` (this is consistent with Python's + float). + + NaN is loosely related to floating point nan, which is defined in the + IEEE 754 floating point standard, and corresponds to the Python + ``float('nan')``. Differences are noted below. + + NaN is mathematically not equal to anything else, even NaN itself. This + explains the initially counter-intuitive results with ``Eq`` and ``==`` in + the examples below. + + NaN is not comparable so inequalities raise a TypeError. This is in + contrast with floating point nan where all inequalities are false. + + NaN is a singleton, and can be accessed by ``S.NaN``, or can be imported + as ``nan``. + + Examples + ======== + + >>> from sympy import nan, S, oo, Eq + >>> nan is S.NaN + True + >>> oo - oo + nan + >>> nan + 1 + nan + >>> Eq(nan, nan) # mathematical equality + False + >>> nan == nan # structural equality + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/NaN + + """ + is_commutative = True + is_extended_real = None + is_real = None + is_rational = None + is_algebraic = None + is_transcendental = None + is_integer = None + is_comparable = False + is_finite = None + is_zero = None + is_prime = None + is_positive = None + is_negative = None + is_number = True + + __slots__ = () + + def __new__(cls): + return AtomicExpr.__new__(cls) + + def _latex(self, printer): + return r"\text{NaN}" + + def __neg__(self): + return self + + @_sympifyit('other', NotImplemented) + def __add__(self, other): + return self + + @_sympifyit('other', NotImplemented) + def __sub__(self, other): + return self + + @_sympifyit('other', NotImplemented) + def __mul__(self, other): + return self + + @_sympifyit('other', NotImplemented) + def __truediv__(self, other): + return self + + def floor(self): + return self + + def ceiling(self): + return self + + def _as_mpf_val(self, prec): + return _mpf_nan + + def __hash__(self): + return super().__hash__() + + def __eq__(self, other): + # NaN is structurally equal to another NaN + return other is S.NaN + + def __ne__(self, other): + return other is not S.NaN + + # Expr will _sympify and raise TypeError + __gt__ = Expr.__gt__ + __ge__ = Expr.__ge__ + __lt__ = Expr.__lt__ + __le__ = Expr.__le__ + +nan = S.NaN + +@dispatch(NaN, Expr) # type:ignore +def _eval_is_eq(a, b): # noqa:F811 + return False + + +class ComplexInfinity(AtomicExpr, metaclass=Singleton): + r"""Complex infinity. + + Explanation + =========== + + In complex analysis the symbol `\tilde\infty`, called "complex + infinity", represents a quantity with infinite magnitude, but + undetermined complex phase. + + ComplexInfinity is a singleton, and can be accessed by + ``S.ComplexInfinity``, or can be imported as ``zoo``. + + Examples + ======== + + >>> from sympy import zoo + >>> zoo + 42 + zoo + >>> 42/zoo + 0 + >>> zoo + zoo + nan + >>> zoo*zoo + zoo + + See Also + ======== + + Infinity + """ + + is_commutative = True + is_infinite = True + is_number = True + is_prime = False + is_complex = False + is_extended_real = False + + kind = NumberKind + + __slots__ = () + + def __new__(cls): + return AtomicExpr.__new__(cls) + + def _latex(self, printer): + return r"\tilde{\infty}" + + @staticmethod + def __abs__(): + return S.Infinity + + def floor(self): + return self + + def ceiling(self): + return self + + @staticmethod + def __neg__(): + return S.ComplexInfinity + + def _eval_power(self, expt): + if expt is S.ComplexInfinity: + return S.NaN + + if isinstance(expt, Number): + if expt.is_zero: + return S.NaN + else: + if expt.is_positive: + return S.ComplexInfinity + else: + return S.Zero + + +zoo = S.ComplexInfinity + + +class NumberSymbol(AtomicExpr): + + is_commutative = True + is_finite = True + is_number = True + + __slots__ = () + + is_NumberSymbol = True + + kind = NumberKind + + def __new__(cls): + return AtomicExpr.__new__(cls) + + def approximation(self, number_cls): + """ Return an interval with number_cls endpoints + that contains the value of NumberSymbol. + If not implemented, then return None. + """ + + def _eval_evalf(self, prec): + return Float._new(self._as_mpf_val(prec), prec) + + def __eq__(self, other): + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if self is other: + return True + if other.is_Number and self.is_irrational: + return False + + return False # NumberSymbol != non-(Number|self) + + def __ne__(self, other): + return not self == other + + def __le__(self, other): + if self is other: + return S.true + return Expr.__le__(self, other) + + def __ge__(self, other): + if self is other: + return S.true + return Expr.__ge__(self, other) + + def __int__(self): + # subclass with appropriate return value + raise NotImplementedError + + def __hash__(self): + return super().__hash__() + + +class Exp1(NumberSymbol, metaclass=Singleton): + r"""The `e` constant. + + Explanation + =========== + + The transcendental number `e = 2.718281828\ldots` is the base of the + natural logarithm and of the exponential function, `e = \exp(1)`. + Sometimes called Euler's number or Napier's constant. + + Exp1 is a singleton, and can be accessed by ``S.Exp1``, + or can be imported as ``E``. + + Examples + ======== + + >>> from sympy import exp, log, E + >>> E is exp(1) + True + >>> log(E) + 1 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/E_%28mathematical_constant%29 + """ + + is_real = True + is_positive = True + is_negative = False # XXX Forces is_negative/is_nonnegative + is_irrational = True + is_number = True + is_algebraic = False + is_transcendental = True + + __slots__ = () + + def _latex(self, printer): + return r"e" + + @staticmethod + def __abs__(): + return S.Exp1 + + def __int__(self): + return 2 + + def _as_mpf_val(self, prec): + return mpf_e(prec) + + def approximation_interval(self, number_cls): + if issubclass(number_cls, Integer): + return (Integer(2), Integer(3)) + elif issubclass(number_cls, Rational): + pass + + def _eval_power(self, expt): + if global_parameters.exp_is_pow: + return self._eval_power_exp_is_pow(expt) + else: + from sympy.functions.elementary.exponential import exp + return exp(expt) + + def _eval_power_exp_is_pow(self, arg): + if arg.is_Number: + if arg is oo: + return oo + elif arg == -oo: + return S.Zero + from sympy.functions.elementary.exponential import log + if isinstance(arg, log): + return arg.args[0] + + # don't autoexpand Pow or Mul (see the issue 3351): + elif not arg.is_Add: + Ioo = I*oo + if arg in [Ioo, -Ioo]: + return nan + + coeff = arg.coeff(pi*I) + if coeff: + if (2*coeff).is_integer: + if coeff.is_even: + return S.One + elif coeff.is_odd: + return S.NegativeOne + elif (coeff + S.Half).is_even: + return -I + elif (coeff + S.Half).is_odd: + return I + elif coeff.is_Rational: + ncoeff = coeff % 2 # restrict to [0, 2pi) + if ncoeff > 1: # restrict to (-pi, pi] + ncoeff -= 2 + if ncoeff != coeff: + return S.Exp1**(ncoeff*S.Pi*S.ImaginaryUnit) + + # Warning: code in risch.py will be very sensitive to changes + # in this (see DifferentialExtension). + + # look for a single log factor + + coeff, terms = arg.as_coeff_Mul() + + # but it can't be multiplied by oo + if coeff in (oo, -oo): + return + + coeffs, log_term = [coeff], None + for term in Mul.make_args(terms): + if isinstance(term, log): + if log_term is None: + log_term = term.args[0] + else: + return + elif term.is_comparable: + coeffs.append(term) + else: + return + + return log_term**Mul(*coeffs) if log_term else None + elif arg.is_Add: + out = [] + add = [] + argchanged = False + for a in arg.args: + if a is S.One: + add.append(a) + continue + newa = self**a + if isinstance(newa, Pow) and newa.base is self: + if newa.exp != a: + add.append(newa.exp) + argchanged = True + else: + add.append(a) + else: + out.append(newa) + if out or argchanged: + return Mul(*out)*Pow(self, Add(*add), evaluate=False) + elif arg.is_Matrix: + return arg.exp() + + def _eval_rewrite_as_sin(self, **kwargs): + from sympy.functions.elementary.trigonometric import sin + return sin(I + S.Pi/2) - I*sin(I) + + def _eval_rewrite_as_cos(self, **kwargs): + from sympy.functions.elementary.trigonometric import cos + return cos(I) + I*cos(I + S.Pi/2) + +E = S.Exp1 + + +class Pi(NumberSymbol, metaclass=Singleton): + r"""The `\pi` constant. + + Explanation + =========== + + The transcendental number `\pi = 3.141592654\ldots` represents the ratio + of a circle's circumference to its diameter, the area of the unit circle, + the half-period of trigonometric functions, and many other things + in mathematics. + + Pi is a singleton, and can be accessed by ``S.Pi``, or can + be imported as ``pi``. + + Examples + ======== + + >>> from sympy import S, pi, oo, sin, exp, integrate, Symbol + >>> S.Pi + pi + >>> pi > 3 + True + >>> pi.is_irrational + True + >>> x = Symbol('x') + >>> sin(x + 2*pi) + sin(x) + >>> integrate(exp(-x**2), (x, -oo, oo)) + sqrt(pi) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Pi + """ + + is_real = True + is_positive = True + is_negative = False + is_irrational = True + is_number = True + is_algebraic = False + is_transcendental = True + + __slots__ = () + + def _latex(self, printer): + return r"\pi" + + @staticmethod + def __abs__(): + return S.Pi + + def __int__(self): + return 3 + + def _as_mpf_val(self, prec): + return mpf_pi(prec) + + def approximation_interval(self, number_cls): + if issubclass(number_cls, Integer): + return (Integer(3), Integer(4)) + elif issubclass(number_cls, Rational): + return (Rational(223, 71, 1), Rational(22, 7, 1)) + +pi = S.Pi + + +class GoldenRatio(NumberSymbol, metaclass=Singleton): + r"""The golden ratio, `\phi`. + + Explanation + =========== + + `\phi = \frac{1 + \sqrt{5}}{2}` is an algebraic number. Two quantities + are in the golden ratio if their ratio is the same as the ratio of + their sum to the larger of the two quantities, i.e. their maximum. + + GoldenRatio is a singleton, and can be accessed by ``S.GoldenRatio``. + + Examples + ======== + + >>> from sympy import S + >>> S.GoldenRatio > 1 + True + >>> S.GoldenRatio.expand(func=True) + 1/2 + sqrt(5)/2 + >>> S.GoldenRatio.is_irrational + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Golden_ratio + """ + + is_real = True + is_positive = True + is_negative = False + is_irrational = True + is_number = True + is_algebraic = True + is_transcendental = False + + __slots__ = () + + def _latex(self, printer): + return r"\phi" + + def __int__(self): + return 1 + + def _as_mpf_val(self, prec): + # XXX track down why this has to be increased + rv = mlib.from_man_exp(phi_fixed(prec + 10), -prec - 10) + return mpf_norm(rv, prec) + + def _eval_expand_func(self, **hints): + from sympy.functions.elementary.miscellaneous import sqrt + return S.Half + S.Half*sqrt(5) + + def approximation_interval(self, number_cls): + if issubclass(number_cls, Integer): + return (S.One, Rational(2)) + elif issubclass(number_cls, Rational): + pass + + _eval_rewrite_as_sqrt = _eval_expand_func + + +class TribonacciConstant(NumberSymbol, metaclass=Singleton): + r"""The tribonacci constant. + + Explanation + =========== + + The tribonacci numbers are like the Fibonacci numbers, but instead + of starting with two predetermined terms, the sequence starts with + three predetermined terms and each term afterwards is the sum of the + preceding three terms. + + The tribonacci constant is the ratio toward which adjacent tribonacci + numbers tend. It is a root of the polynomial `x^3 - x^2 - x - 1 = 0`, + and also satisfies the equation `x + x^{-3} = 2`. + + TribonacciConstant is a singleton, and can be accessed + by ``S.TribonacciConstant``. + + Examples + ======== + + >>> from sympy import S + >>> S.TribonacciConstant > 1 + True + >>> S.TribonacciConstant.expand(func=True) + 1/3 + (19 - 3*sqrt(33))**(1/3)/3 + (3*sqrt(33) + 19)**(1/3)/3 + >>> S.TribonacciConstant.is_irrational + True + >>> S.TribonacciConstant.n(20) + 1.8392867552141611326 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Generalizations_of_Fibonacci_numbers#Tribonacci_numbers + """ + + is_real = True + is_positive = True + is_negative = False + is_irrational = True + is_number = True + is_algebraic = True + is_transcendental = False + + __slots__ = () + + def _latex(self, printer): + return r"\text{TribonacciConstant}" + + def __int__(self): + return 1 + + def _as_mpf_val(self, prec): + return self._eval_evalf(prec)._mpf_ + + def _eval_evalf(self, prec): + rv = self._eval_expand_func(function=True)._eval_evalf(prec + 4) + return Float(rv, precision=prec) + + def _eval_expand_func(self, **hints): + from sympy.functions.elementary.miscellaneous import cbrt, sqrt + return (1 + cbrt(19 - 3*sqrt(33)) + cbrt(19 + 3*sqrt(33))) / 3 + + def approximation_interval(self, number_cls): + if issubclass(number_cls, Integer): + return (S.One, Rational(2)) + elif issubclass(number_cls, Rational): + pass + + _eval_rewrite_as_sqrt = _eval_expand_func + + +class EulerGamma(NumberSymbol, metaclass=Singleton): + r"""The Euler-Mascheroni constant. + + Explanation + =========== + + `\gamma = 0.5772157\ldots` (also called Euler's constant) is a mathematical + constant recurring in analysis and number theory. It is defined as the + limiting difference between the harmonic series and the + natural logarithm: + + .. math:: \gamma = \lim\limits_{n\to\infty} + \left(\sum\limits_{k=1}^n\frac{1}{k} - \ln n\right) + + EulerGamma is a singleton, and can be accessed by ``S.EulerGamma``. + + Examples + ======== + + >>> from sympy import S + >>> S.EulerGamma.is_irrational + >>> S.EulerGamma > 0 + True + >>> S.EulerGamma > 1 + False + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Euler%E2%80%93Mascheroni_constant + """ + + is_real = True + is_positive = True + is_negative = False + is_irrational = None + is_number = True + + __slots__ = () + + def _latex(self, printer): + return r"\gamma" + + def __int__(self): + return 0 + + def _as_mpf_val(self, prec): + # XXX track down why this has to be increased + v = mlib.libhyper.euler_fixed(prec + 10) + rv = mlib.from_man_exp(v, -prec - 10) + return mpf_norm(rv, prec) + + def approximation_interval(self, number_cls): + if issubclass(number_cls, Integer): + return (S.Zero, S.One) + elif issubclass(number_cls, Rational): + return (S.Half, Rational(3, 5, 1)) + + +class Catalan(NumberSymbol, metaclass=Singleton): + r"""Catalan's constant. + + Explanation + =========== + + $G = 0.91596559\ldots$ is given by the infinite series + + .. math:: G = \sum_{k=0}^{\infty} \frac{(-1)^k}{(2k+1)^2} + + Catalan is a singleton, and can be accessed by ``S.Catalan``. + + Examples + ======== + + >>> from sympy import S + >>> S.Catalan.is_irrational + >>> S.Catalan > 0 + True + >>> S.Catalan > 1 + False + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Catalan%27s_constant + """ + + is_real = True + is_positive = True + is_negative = False + is_irrational = None + is_number = True + + __slots__ = () + + def __int__(self): + return 0 + + def _as_mpf_val(self, prec): + # XXX track down why this has to be increased + v = mlib.catalan_fixed(prec + 10) + rv = mlib.from_man_exp(v, -prec - 10) + return mpf_norm(rv, prec) + + def approximation_interval(self, number_cls): + if issubclass(number_cls, Integer): + return (S.Zero, S.One) + elif issubclass(number_cls, Rational): + return (Rational(9, 10, 1), S.One) + + def _eval_rewrite_as_Sum(self, k_sym=None, symbols=None, **hints): + if (k_sym is not None) or (symbols is not None): + return self + from .symbol import Dummy + from sympy.concrete.summations import Sum + k = Dummy('k', integer=True, nonnegative=True) + return Sum(S.NegativeOne**k / (2*k+1)**2, (k, 0, S.Infinity)) + + def _latex(self, printer): + return "G" + + +class ImaginaryUnit(AtomicExpr, metaclass=Singleton): + r"""The imaginary unit, `i = \sqrt{-1}`. + + I is a singleton, and can be accessed by ``S.I``, or can be + imported as ``I``. + + Examples + ======== + + >>> from sympy import I, sqrt + >>> sqrt(-1) + I + >>> I*I + -1 + >>> 1/I + -I + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Imaginary_unit + """ + + is_commutative = True + is_imaginary = True + is_finite = True + is_number = True + is_algebraic = True + is_transcendental = False + + kind = NumberKind + + __slots__ = () + + def _latex(self, printer): + return printer._settings['imaginary_unit_latex'] + + @staticmethod + def __abs__(): + return S.One + + def _eval_evalf(self, prec): + return self + + def _eval_conjugate(self): + return -S.ImaginaryUnit + + def _eval_power(self, expt): + """ + b is I = sqrt(-1) + e is symbolic object but not equal to 0, 1 + + I**r -> (-1)**(r/2) -> exp(r/2*Pi*I) -> sin(Pi*r/2) + cos(Pi*r/2)*I, r is decimal + I**0 mod 4 -> 1 + I**1 mod 4 -> I + I**2 mod 4 -> -1 + I**3 mod 4 -> -I + """ + + if isinstance(expt, Integer): + expt = expt % 4 + if expt == 0: + return S.One + elif expt == 1: + return S.ImaginaryUnit + elif expt == 2: + return S.NegativeOne + elif expt == 3: + return -S.ImaginaryUnit + if isinstance(expt, Rational): + i, r = divmod(expt, 2) + rv = Pow(S.ImaginaryUnit, r, evaluate=False) + if i % 2: + return Mul(S.NegativeOne, rv, evaluate=False) + return rv + + def as_base_exp(self): + return S.NegativeOne, S.Half + + @property + def _mpc_(self): + return (Float(0)._mpf_, Float(1)._mpf_) + + +I = S.ImaginaryUnit + + +def int_valued(x): + """return True only for a literal Number whose internal + representation as a fraction has a denominator of 1, + else False, i.e. integer, with no fractional part. + """ + if isinstance(x, (SYMPY_INTS, int)): + return True + if type(x) is float: + return x.is_integer() + if isinstance(x, Integer): + return True + if isinstance(x, Float): + # x = s*m*2**p; _mpf_ = s,m,e,p + return x._mpf_[2] >= 0 + return False # or add new types to recognize + + +def equal_valued(x, y): + """Compare expressions treating plain floats as rationals. + + Examples + ======== + + >>> from sympy import S, symbols, Rational, Float + >>> from sympy.core.numbers import equal_valued + >>> equal_valued(1, 2) + False + >>> equal_valued(1, 1) + True + + In SymPy expressions with Floats compare unequal to corresponding + expressions with rationals: + + >>> x = symbols('x') + >>> x**2 == x**2.0 + False + + However an individual Float compares equal to a Rational: + + >>> Rational(1, 2) == Float(0.5) + False + + In a future version of SymPy this might change so that Rational and Float + compare unequal. This function provides the behavior currently expected of + ``==`` so that it could still be used if the behavior of ``==`` were to + change in future. + + >>> equal_valued(1, 1.0) # Float vs Rational + True + >>> equal_valued(S(1).n(3), S(1).n(5)) # Floats of different precision + True + + Explanation + =========== + + In future SymPy versions Float and Rational might compare unequal and floats + with different precisions might compare unequal. In that context a function + is needed that can check if a number is equal to 1 or 0 etc. The idea is + that instead of testing ``if x == 1:`` if we want to accept floats like + ``1.0`` as well then the test can be written as ``if equal_valued(x, 1):`` + or ``if equal_valued(x, 2):``. Since this function is intended to be used + in situations where one or both operands are expected to be concrete + numbers like 1 or 0 the function does not recurse through the args of any + compound expression to compare any nested floats. + + References + ========== + + .. [1] https://github.com/sympy/sympy/pull/20033 + """ + x = _sympify(x) + y = _sympify(y) + + # Handle everything except Float/Rational first + if not x.is_Float and not y.is_Float: + return x == y + elif x.is_Float and y.is_Float: + # Compare values without regard for precision + return x._mpf_ == y._mpf_ + elif x.is_Float: + x, y = y, x + if not x.is_Rational: + return False + + # Now y is Float and x is Rational. A simple approach at this point would + # just be x == Rational(y) but if y has a large exponent creating a + # Rational could be prohibitively expensive. + + sign, man, exp, _ = y._mpf_ + p, q = x.p, x.q + + if sign: + man = -man + + if exp == 0: + # y odd integer + return q == 1 and man == p + elif exp > 0: + # y even integer + if q != 1: + return False + if p.bit_length() != man.bit_length() + exp: + return False + return man << exp == p + else: + # y non-integer. Need p == man and q == 2**-exp + if p != man: + return False + neg_exp = -exp + if q.bit_length() - 1 != neg_exp: + return False + return (1 << neg_exp) == q + + +def all_close(expr1, expr2, rtol=1e-5, atol=1e-8): + """Return True if expr1 and expr2 are numerically close. + + The expressions must have the same structure, but any Rational, Integer, or + Float numbers they contain are compared approximately using rtol and atol. + Any other parts of expressions are compared exactly. However, allowance is + made to allow for the additive and multiplicative identities. + + Relative tolerance is measured with respect to expr2 so when used in + testing expr2 should be the expected correct answer. + + Examples + ======== + + >>> from sympy import exp + >>> from sympy.abc import x, y + >>> from sympy.core.numbers import all_close + >>> expr1 = 0.1*exp(x - y) + >>> expr2 = exp(x - y)/10 + >>> expr1 + 0.1*exp(x - y) + >>> expr2 + exp(x - y)/10 + >>> expr1 == expr2 + False + >>> all_close(expr1, expr2) + True + + Identities are automatically supplied: + + >>> all_close(x, x + 1e-10) + True + >>> all_close(x, 1.0*x) + True + >>> all_close(x, 1.0*x + 1e-10) + True + + """ + NUM_TYPES = (Rational, Float) + + def _all_close(obj1, obj2): + if type(obj1) == type(obj2) and isinstance(obj1, (list, tuple)): + if len(obj1) != len(obj2): + return False + return all(_all_close(e1, e2) for e1, e2 in zip(obj1, obj2)) + else: + return _all_close_expr(_sympify(obj1), _sympify(obj2)) + + def _all_close_expr(expr1, expr2): + num1 = isinstance(expr1, NUM_TYPES) + num2 = isinstance(expr2, NUM_TYPES) + if num1 != num2: + return False + elif num1: + return _close_num(expr1, expr2) + if expr1.is_Add or expr1.is_Mul or expr2.is_Add or expr2.is_Mul: + return _all_close_ac(expr1, expr2) + if expr1.func != expr2.func or len(expr1.args) != len(expr2.args): + return False + args = zip(expr1.args, expr2.args) + return all(_all_close_expr(a1, a2) for a1, a2 in args) + + def _close_num(num1, num2): + return bool(abs(num1 - num2) <= atol + rtol*abs(num2)) + + def _all_close_ac(expr1, expr2): + # compare expressions with associative commutative operators for + # approximate equality by seeing that all terms have equivalent + # coefficients (which are always Rational or Float) + if expr1.is_Mul or expr2.is_Mul: + # as_coeff_mul automatically will supply coeff of 1 + c1, e1 = expr1.as_coeff_mul(rational=False) + c2, e2 = expr2.as_coeff_mul(rational=False) + if not _close_num(c1, c2): + return False + s1 = set(e1) + s2 = set(e2) + common = s1 & s2 + s1 -= common + s2 -= common + if not s1: + return True + if not any(i.has(Float) for j in (s1, s2) for i in j): + return False + # factors might not be matching, e.g. + # x != x**1.0, exp(x) != exp(1.0*x), etc... + s1 = [i.as_base_exp() for i in ordered(s1)] + s2 = [i.as_base_exp() for i in ordered(s2)] + unmatched = list(range(len(s1))) + for be1 in s1: + for i in unmatched: + be2 = s2[i] + if _all_close(be1, be2): + unmatched.remove(i) + break + else: + return False + return not(unmatched) + assert expr1.is_Add or expr2.is_Add + cd1 = expr1.as_coefficients_dict() + cd2 = expr2.as_coefficients_dict() + # this test will assure that the key of 1 is in + # each dict and that they have equal values + if not _close_num(cd1[1], cd2[1]): + return False + if len(cd1) != len(cd2): + return False + for k in list(cd1): + if k in cd2: + if not _close_num(cd1.pop(k), cd2.pop(k)): + return False + # k (or a close version in cd2) might have + # Floats in a factor of the term which will + # be handled below + else: + if not cd1: + return True + for k1 in cd1: + for k2 in cd2: + if _all_close_expr(k1, k2): + # found a matching key + # XXX there could be a corner case where + # more than 1 might match and the numbers are + # such that one is better than the other + # that is not being considered here + if not _close_num(cd1[k1], cd2[k2]): + return False + break + else: + # no key matched + return False + return True + + return _all_close(expr1, expr2) + + +@dispatch(Tuple, Number) # type:ignore +def _eval_is_eq(self, other): # noqa: F811 + return False + + +def sympify_fractions(f): + return Rational._new(f.numerator, f.denominator, 1) + +_sympy_converter[fractions.Fraction] = sympify_fractions + + +if gmpy is not None: + + def sympify_mpz(x): + return Integer(int(x)) + + def sympify_mpq(x): + return Rational(int(x.numerator), int(x.denominator)) + + _sympy_converter[type(gmpy.mpz(1))] = sympify_mpz + _sympy_converter[type(gmpy.mpq(1, 2))] = sympify_mpq + + +if flint is not None: + + def sympify_fmpz(x): + return Integer(int(x)) + + def sympify_fmpq(x): + return Rational(int(x.numerator), int(x.denominator)) + + _sympy_converter[type(flint.fmpz(1))] = sympify_fmpz + _sympy_converter[type(flint.fmpq(1, 2))] = sympify_fmpq + + +def sympify_mpmath(x): + return Expr._from_mpmath(x, x.context.prec) + +_sympy_converter[mpnumeric] = sympify_mpmath + + +def sympify_complex(a): + real, imag = list(map(sympify, (a.real, a.imag))) + return real + S.ImaginaryUnit*imag + +_sympy_converter[complex] = sympify_complex + +from .power import Pow +from .mul import Mul +Mul.identity = One() +from .add import Add +Add.identity = Zero() + + +def _register_classes(): + numbers.Number.register(Number) + numbers.Real.register(Float) + numbers.Rational.register(Rational) + numbers.Integral.register(Integer) + +_register_classes() + +_illegal = (S.NaN, S.Infinity, S.NegativeInfinity, S.ComplexInfinity) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/operations.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/operations.py new file mode 100644 index 0000000000000000000000000000000000000000..70d22127eb4d3f69fc5e304ab38f5cce9c4bb551 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/operations.py @@ -0,0 +1,741 @@ +from __future__ import annotations + +from typing import overload, TYPE_CHECKING + +from operator import attrgetter +from collections import defaultdict + +from sympy.utilities.exceptions import sympy_deprecation_warning + +from .sympify import _sympify as _sympify_, sympify +from .basic import Basic +from .cache import cacheit +from .sorting import ordered +from .logic import fuzzy_and +from .parameters import global_parameters +from sympy.utilities.iterables import sift +from sympy.multipledispatch.dispatcher import (Dispatcher, + ambiguity_register_error_ignore_dup, + str_signature, RaiseNotImplementedError) + + +if TYPE_CHECKING: + from sympy.core.expr import Expr + from sympy.core.add import Add + from sympy.core.mul import Mul + from sympy.logic.boolalg import Boolean, And, Or + + +class AssocOp(Basic): + """ Associative operations, can separate noncommutative and + commutative parts. + + (a op b) op c == a op (b op c) == a op b op c. + + Base class for Add and Mul. + + This is an abstract base class, concrete derived classes must define + the attribute `identity`. + + .. deprecated:: 1.7 + + Using arguments that aren't subclasses of :class:`~.Expr` in core + operators (:class:`~.Mul`, :class:`~.Add`, and :class:`~.Pow`) is + deprecated. See :ref:`non-expr-args-deprecated` for details. + + Parameters + ========== + + *args : + Arguments which are operated + + evaluate : bool, optional + Evaluate the operation. If not passed, refer to ``global_parameters.evaluate``. + """ + + # for performance reason, we don't let is_commutative go to assumptions, + # and keep it right here + __slots__: tuple[str, ...] = ('is_commutative',) + + _args_type: type[Basic] | None = None + + @cacheit + def __new__(cls, *args, evaluate=None, _sympify=True): + # Allow faster processing by passing ``_sympify=False``, if all arguments + # are already sympified. + if _sympify: + args = list(map(_sympify_, args)) + + # Disallow non-Expr args in Add/Mul + typ = cls._args_type + if typ is not None: + from .relational import Relational + if any(isinstance(arg, Relational) for arg in args): + raise TypeError("Relational cannot be used in %s" % cls.__name__) + + # This should raise TypeError once deprecation period is over: + for arg in args: + if not isinstance(arg, typ): + sympy_deprecation_warning( + f""" + +Using non-Expr arguments in {cls.__name__} is deprecated (in this case, one of +the arguments has type {type(arg).__name__!r}). + +If you really did intend to use a multiplication or addition operation with +this object, use the * or + operator instead. + + """, + deprecated_since_version="1.7", + active_deprecations_target="non-expr-args-deprecated", + stacklevel=4, + ) + + if evaluate is None: + evaluate = global_parameters.evaluate + if not evaluate: + obj = cls._from_args(args) + obj = cls._exec_constructor_postprocessors(obj) + return obj + + args = [a for a in args if a is not cls.identity] + + if len(args) == 0: + return cls.identity + if len(args) == 1: + return args[0] + + c_part, nc_part, order_symbols = cls.flatten(args) + is_commutative = not nc_part + obj = cls._from_args(c_part + nc_part, is_commutative) + obj = cls._exec_constructor_postprocessors(obj) + + if order_symbols is not None: + from sympy.series.order import Order + return Order(obj, *order_symbols) + return obj + + @classmethod + def _from_args(cls, args, is_commutative=None): + """Create new instance with already-processed args. + If the args are not in canonical order, then a non-canonical + result will be returned, so use with caution. The order of + args may change if the sign of the args is changed.""" + if len(args) == 0: + return cls.identity + elif len(args) == 1: + return args[0] + + obj = super().__new__(cls, *args) + if is_commutative is None: + is_commutative = fuzzy_and(a.is_commutative for a in args) + obj.is_commutative = is_commutative + return obj + + def _new_rawargs(self, *args, reeval=True, **kwargs): + """Create new instance of own class with args exactly as provided by + caller but returning the self class identity if args is empty. + + Examples + ======== + + This is handy when we want to optimize things, e.g. + + >>> from sympy import Mul, S + >>> from sympy.abc import x, y + >>> e = Mul(3, x, y) + >>> e.args + (3, x, y) + >>> Mul(*e.args[1:]) + x*y + >>> e._new_rawargs(*e.args[1:]) # the same as above, but faster + x*y + + Note: use this with caution. There is no checking of arguments at + all. This is best used when you are rebuilding an Add or Mul after + simply removing one or more args. If, for example, modifications, + result in extra 1s being inserted they will show up in the result: + + >>> m = (x*y)._new_rawargs(S.One, x); m + 1*x + >>> m == x + False + >>> m.is_Mul + True + + Another issue to be aware of is that the commutativity of the result + is based on the commutativity of self. If you are rebuilding the + terms that came from a commutative object then there will be no + problem, but if self was non-commutative then what you are + rebuilding may now be commutative. + + Although this routine tries to do as little as possible with the + input, getting the commutativity right is important, so this level + of safety is enforced: commutativity will always be recomputed if + self is non-commutative and kwarg `reeval=False` has not been + passed. + """ + if reeval and self.is_commutative is False: + is_commutative = None + else: + is_commutative = self.is_commutative + return self._from_args(args, is_commutative) + + @classmethod + def flatten(cls, seq): + """Return seq so that none of the elements are of type `cls`. This is + the vanilla routine that will be used if a class derived from AssocOp + does not define its own flatten routine.""" + # apply associativity, no commutativity property is used + new_seq = [] + while seq: + o = seq.pop() + if o.__class__ is cls: # classes must match exactly + seq.extend(o.args) + else: + new_seq.append(o) + new_seq.reverse() + + # c_part, nc_part, order_symbols + return [], new_seq, None + + def _matches_commutative(self, expr, repl_dict=None, old=False): + """ + Matches Add/Mul "pattern" to an expression "expr". + + repl_dict ... a dictionary of (wild: expression) pairs, that get + returned with the results + + This function is the main workhorse for Add/Mul. + + Examples + ======== + + >>> from sympy import symbols, Wild, sin + >>> a = Wild("a") + >>> b = Wild("b") + >>> c = Wild("c") + >>> x, y, z = symbols("x y z") + >>> (a+sin(b)*c)._matches_commutative(x+sin(y)*z) + {a_: x, b_: y, c_: z} + + In the example above, "a+sin(b)*c" is the pattern, and "x+sin(y)*z" is + the expression. + + The repl_dict contains parts that were already matched. For example + here: + + >>> (x+sin(b)*c)._matches_commutative(x+sin(y)*z, repl_dict={a: x}) + {a_: x, b_: y, c_: z} + + the only function of the repl_dict is to return it in the + result, e.g. if you omit it: + + >>> (x+sin(b)*c)._matches_commutative(x+sin(y)*z) + {b_: y, c_: z} + + the "a: x" is not returned in the result, but otherwise it is + equivalent. + + """ + from .function import _coeff_isneg + # make sure expr is Expr if pattern is Expr + from .expr import Expr + if isinstance(self, Expr) and not isinstance(expr, Expr): + return None + + if repl_dict is None: + repl_dict = {} + + # handle simple patterns + if self == expr: + return repl_dict + + d = self._matches_simple(expr, repl_dict) + if d is not None: + return d + + # eliminate exact part from pattern: (2+a+w1+w2).matches(expr) -> (w1+w2).matches(expr-a-2) + from .function import WildFunction + from .symbol import Wild + wild_part, exact_part = sift(self.args, lambda p: + p.has(Wild, WildFunction) and not expr.has(p), + binary=True) + if not exact_part: + wild_part = list(ordered(wild_part)) + if self.is_Add: + # in addition to normal ordered keys, impose + # sorting on Muls with leading Number to put + # them in order + wild_part = sorted(wild_part, key=lambda x: + x.args[0] if x.is_Mul and x.args[0].is_Number else + 0) + else: + exact = self._new_rawargs(*exact_part) + free = expr.free_symbols + if free and (exact.free_symbols - free): + # there are symbols in the exact part that are not + # in the expr; but if there are no free symbols, let + # the matching continue + return None + newexpr = self._combine_inverse(expr, exact) + if not old and (expr.is_Add or expr.is_Mul): + check = newexpr + if _coeff_isneg(check): + check = -check + if check.count_ops() > expr.count_ops(): + return None + newpattern = self._new_rawargs(*wild_part) + return newpattern.matches(newexpr, repl_dict) + + # now to real work ;) + i = 0 + saw = set() + while expr not in saw: + saw.add(expr) + args = tuple(ordered(self.make_args(expr))) + if self.is_Add and expr.is_Add: + # in addition to normal ordered keys, impose + # sorting on Muls with leading Number to put + # them in order + args = tuple(sorted(args, key=lambda x: + x.args[0] if x.is_Mul and x.args[0].is_Number else + 0)) + expr_list = (self.identity,) + args + for last_op in reversed(expr_list): + for w in reversed(wild_part): + d1 = w.matches(last_op, repl_dict) + if d1 is not None: + d2 = self.xreplace(d1).matches(expr, d1) + if d2 is not None: + return d2 + + if i == 0: + if self.is_Mul: + # make e**i look like Mul + if expr.is_Pow and expr.exp.is_Integer: + from .mul import Mul + if expr.exp > 0: + expr = Mul(*[expr.base, expr.base**(expr.exp - 1)], evaluate=False) + else: + expr = Mul(*[1/expr.base, expr.base**(expr.exp + 1)], evaluate=False) + i += 1 + continue + + elif self.is_Add: + # make i*e look like Add + c, e = expr.as_coeff_Mul() + if abs(c) > 1: + from .add import Add + if c > 0: + expr = Add(*[e, (c - 1)*e], evaluate=False) + else: + expr = Add(*[-e, (c + 1)*e], evaluate=False) + i += 1 + continue + + # try collection on non-Wild symbols + from sympy.simplify.radsimp import collect + was = expr + did = set() + for w in reversed(wild_part): + c, w = w.as_coeff_mul(Wild) + free = c.free_symbols - did + if free: + did.update(free) + expr = collect(expr, free) + if expr != was: + i += 0 + continue + + break # if we didn't continue, there is nothing more to do + + return + + def _has_matcher(self): + """Helper for .has() that checks for containment of + subexpressions within an expr by using sets of args + of similar nodes, e.g. x + 1 in x + y + 1 checks + to see that {x, 1} & {x, y, 1} == {x, 1} + """ + def _ncsplit(expr): + # this is not the same as args_cnc because here + # we don't assume expr is a Mul -- hence deal with args -- + # and always return a set. + cpart, ncpart = sift(expr.args, + lambda arg: arg.is_commutative is True, binary=True) + return set(cpart), ncpart + + c, nc = _ncsplit(self) + cls = self.__class__ + + def is_in(expr): + if isinstance(expr, cls): + if expr == self: + return True + _c, _nc = _ncsplit(expr) + if (c & _c) == c: + if not nc: + return True + elif len(nc) <= len(_nc): + for i in range(len(_nc) - len(nc) + 1): + if _nc[i:i + len(nc)] == nc: + return True + return False + return is_in + + def _eval_evalf(self, prec): + """ + Evaluate the parts of self that are numbers; if the whole thing + was a number with no functions it would have been evaluated, but + it wasn't so we must judiciously extract the numbers and reconstruct + the object. This is *not* simply replacing numbers with evaluated + numbers. Numbers should be handled in the largest pure-number + expression as possible. So the code below separates ``self`` into + number and non-number parts and evaluates the number parts and + walks the args of the non-number part recursively (doing the same + thing). + """ + from .add import Add + from .mul import Mul + from .symbol import Symbol + from .function import AppliedUndef + if isinstance(self, (Mul, Add)): + x, tail = self.as_independent(Symbol, AppliedUndef) + # if x is an AssocOp Function then the _evalf below will + # call _eval_evalf (here) so we must break the recursion + if not (tail is self.identity or + isinstance(x, AssocOp) and x.is_Function or + x is self.identity and isinstance(tail, AssocOp)): + # here, we have a number so we just call to _evalf with prec; + # prec is not the same as n, it is the binary precision so + # that's why we don't call to evalf. + x = x._evalf(prec) if x is not self.identity else self.identity + args = [] + tail_args = tuple(self.func.make_args(tail)) + for a in tail_args: + # here we call to _eval_evalf since we don't know what we + # are dealing with and all other _eval_evalf routines should + # be doing the same thing (i.e. taking binary prec and + # finding the evalf-able args) + newa = a._eval_evalf(prec) + if newa is None: + args.append(a) + else: + args.append(newa) + return self.func(x, *args) + + # this is the same as above, but there were no pure-number args to + # deal with + args = [] + for a in self.args: + newa = a._eval_evalf(prec) + if newa is None: + args.append(a) + else: + args.append(newa) + return self.func(*args) + + @overload + @classmethod + def make_args(cls: type[Add], expr: Expr) -> tuple[Expr, ...]: ... # type: ignore + @overload + @classmethod + def make_args(cls: type[Mul], expr: Expr) -> tuple[Expr, ...]: ... # type: ignore + @overload + @classmethod + def make_args(cls: type[And], expr: Boolean) -> tuple[Boolean, ...]: ... # type: ignore + @overload + @classmethod + def make_args(cls: type[Or], expr: Boolean) -> tuple[Boolean, ...]: ... # type: ignore + + @classmethod + def make_args(cls: type[Basic], expr: Basic) -> tuple[Basic, ...]: + """ + Return a sequence of elements `args` such that cls(*args) == expr + + Examples + ======== + + >>> from sympy import Symbol, Mul, Add + >>> x, y = map(Symbol, 'xy') + + >>> Mul.make_args(x*y) + (x, y) + >>> Add.make_args(x*y) + (x*y,) + >>> set(Add.make_args(x*y + y)) == set([y, x*y]) + True + + """ + if isinstance(expr, cls): + return expr.args + else: + return (sympify(expr),) + + def doit(self, **hints): + if hints.get('deep', True): + terms = [term.doit(**hints) for term in self.args] + else: + terms = self.args + return self.func(*terms, evaluate=True) + +class ShortCircuit(Exception): + pass + + +class LatticeOp(AssocOp): + """ + Join/meet operations of an algebraic lattice[1]. + + Explanation + =========== + + These binary operations are associative (op(op(a, b), c) = op(a, op(b, c))), + commutative (op(a, b) = op(b, a)) and idempotent (op(a, a) = op(a) = a). + Common examples are AND, OR, Union, Intersection, max or min. They have an + identity element (op(identity, a) = a) and an absorbing element + conventionally called zero (op(zero, a) = zero). + + This is an abstract base class, concrete derived classes must declare + attributes zero and identity. All defining properties are then respected. + + Examples + ======== + + >>> from sympy import Integer + >>> from sympy.core.operations import LatticeOp + >>> class my_join(LatticeOp): + ... zero = Integer(0) + ... identity = Integer(1) + >>> my_join(2, 3) == my_join(3, 2) + True + >>> my_join(2, my_join(3, 4)) == my_join(2, 3, 4) + True + >>> my_join(0, 1, 4, 2, 3, 4) + 0 + >>> my_join(1, 2) + 2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Lattice_%28order%29 + """ + + is_commutative = True + + def __new__(cls, *args, **options): + args = (_sympify_(arg) for arg in args) + + try: + # /!\ args is a generator and _new_args_filter + # must be careful to handle as such; this + # is done so short-circuiting can be done + # without having to sympify all values + _args = frozenset(cls._new_args_filter(args)) + except ShortCircuit: + return sympify(cls.zero) + if not _args: + return sympify(cls.identity) + elif len(_args) == 1: + return set(_args).pop() + else: + # XXX in almost every other case for __new__, *_args is + # passed along, but the expectation here is for _args + obj = super(AssocOp, cls).__new__(cls, *ordered(_args)) + obj._argset = _args + return obj + + @classmethod + def _new_args_filter(cls, arg_sequence, call_cls=None): + """Generator filtering args""" + ncls = call_cls or cls + for arg in arg_sequence: + if arg == ncls.zero: + raise ShortCircuit(arg) + elif arg == ncls.identity: + continue + elif arg.func == ncls: + yield from arg.args + else: + yield arg + + @classmethod + def make_args(cls, expr): + """ + Return a set of args such that cls(*arg_set) == expr. + """ + if isinstance(expr, cls): + return expr._argset + else: + return frozenset([sympify(expr)]) + + +class AssocOpDispatcher: + """ + Handler dispatcher for associative operators + + .. notes:: + This approach is experimental, and can be replaced or deleted in the future. + See https://github.com/sympy/sympy/pull/19463. + + Explanation + =========== + + If arguments of different types are passed, the classes which handle the operation for each type + are collected. Then, a class which performs the operation is selected by recursive binary dispatching. + Dispatching relation can be registered by ``register_handlerclass`` method. + + Priority registration is unordered. You cannot make ``A*B`` and ``B*A`` refer to + different handler classes. All logic dealing with the order of arguments must be implemented + in the handler class. + + Examples + ======== + + >>> from sympy import Add, Expr, Symbol + >>> from sympy.core.add import add + + >>> class NewExpr(Expr): + ... @property + ... def _add_handler(self): + ... return NewAdd + >>> class NewAdd(NewExpr, Add): + ... pass + >>> add.register_handlerclass((Add, NewAdd), NewAdd) + + >>> a, b = Symbol('a'), NewExpr() + >>> add(a, b) == NewAdd(a, b) + True + + """ + def __init__(self, name, doc=None): + self.name = name + self.doc = doc + self.handlerattr = "_%s_handler" % name + self._handlergetter = attrgetter(self.handlerattr) + self._dispatcher = Dispatcher(name) + + def __repr__(self): + return "" % self.name + + def register_handlerclass(self, classes, typ, on_ambiguity=ambiguity_register_error_ignore_dup): + """ + Register the handler class for two classes, in both straight and reversed order. + + Paramteters + =========== + + classes : tuple of two types + Classes who are compared with each other. + + typ: + Class which is registered to represent *cls1* and *cls2*. + Handler method of *self* must be implemented in this class. + """ + if not len(classes) == 2: + raise RuntimeError( + "Only binary dispatch is supported, but got %s types: <%s>." % ( + len(classes), str_signature(classes) + )) + if len(set(classes)) == 1: + raise RuntimeError( + "Duplicate types <%s> cannot be dispatched." % str_signature(classes) + ) + self._dispatcher.add(tuple(classes), typ, on_ambiguity=on_ambiguity) + self._dispatcher.add(tuple(reversed(classes)), typ, on_ambiguity=on_ambiguity) + + @cacheit + def __call__(self, *args, _sympify=True, **kwargs): + """ + Parameters + ========== + + *args : + Arguments which are operated + """ + if _sympify: + args = tuple(map(_sympify_, args)) + handlers = frozenset(map(self._handlergetter, args)) + + # no need to sympify again + return self.dispatch(handlers)(*args, _sympify=False, **kwargs) + + @cacheit + def dispatch(self, handlers): + """ + Select the handler class, and return its handler method. + """ + + # Quick exit for the case where all handlers are same + if len(handlers) == 1: + h, = handlers + if not isinstance(h, type): + raise RuntimeError("Handler {!r} is not a type.".format(h)) + return h + + # Recursively select with registered binary priority + for i, typ in enumerate(handlers): + + if not isinstance(typ, type): + raise RuntimeError("Handler {!r} is not a type.".format(typ)) + + if i == 0: + handler = typ + else: + prev_handler = handler + handler = self._dispatcher.dispatch(prev_handler, typ) + + if not isinstance(handler, type): + raise RuntimeError( + "Dispatcher for {!r} and {!r} must return a type, but got {!r}".format( + prev_handler, typ, handler + )) + + # return handler class + return handler + + @property + def __doc__(self): + docs = [ + "Multiply dispatched associative operator: %s" % self.name, + "Note that support for this is experimental, see the docs for :class:`AssocOpDispatcher` for details" + ] + + if self.doc: + docs.append(self.doc) + + s = "Registered handler classes\n" + s += '=' * len(s) + docs.append(s) + + amb_sigs = [] + + typ_sigs = defaultdict(list) + for sigs in self._dispatcher.ordering[::-1]: + key = self._dispatcher.funcs[sigs] + typ_sigs[key].append(sigs) + + for typ, sigs in typ_sigs.items(): + + sigs_str = ', '.join('<%s>' % str_signature(sig) for sig in sigs) + + if isinstance(typ, RaiseNotImplementedError): + amb_sigs.append(sigs_str) + continue + + s = 'Inputs: %s\n' % sigs_str + s += '-' * len(s) + '\n' + s += typ.__name__ + docs.append(s) + + if amb_sigs: + s = "Ambiguous handler classes\n" + s += '=' * len(s) + docs.append(s) + + s = '\n'.join(amb_sigs) + docs.append(s) + + return '\n\n'.join(docs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/parameters.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/parameters.py new file mode 100644 index 0000000000000000000000000000000000000000..d911a3652bf02fa5b24c43b138035a57be687228 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/parameters.py @@ -0,0 +1,161 @@ +"""Thread-safe global parameters""" + +from .cache import clear_cache +from contextlib import contextmanager +from threading import local + +class _global_parameters(local): + """ + Thread-local global parameters. + + Explanation + =========== + + This class generates thread-local container for SymPy's global parameters. + Every global parameters must be passed as keyword argument when generating + its instance. + A variable, `global_parameters` is provided as default instance for this class. + + WARNING! Although the global parameters are thread-local, SymPy's cache is not + by now. + This may lead to undesired result in multi-threading operations. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.core.cache import clear_cache + >>> from sympy.core.parameters import global_parameters as gp + + >>> gp.evaluate + True + >>> x+x + 2*x + + >>> log = [] + >>> def f(): + ... clear_cache() + ... gp.evaluate = False + ... log.append(x+x) + ... clear_cache() + >>> import threading + >>> thread = threading.Thread(target=f) + >>> thread.start() + >>> thread.join() + + >>> print(log) + [x + x] + + >>> gp.evaluate + True + >>> x+x + 2*x + + References + ========== + + .. [1] https://docs.python.org/3/library/threading.html + + """ + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + def __setattr__(self, name, value): + if getattr(self, name) != value: + clear_cache() + return super().__setattr__(name, value) + +global_parameters = _global_parameters(evaluate=True, distribute=True, exp_is_pow=False) + +class evaluate: + """ Control automatic evaluation + + Explanation + =========== + + This context manager controls whether or not all SymPy functions evaluate + by default. + + Note that much of SymPy expects evaluated expressions. This functionality + is experimental and is unlikely to function as intended on large + expressions. + + Examples + ======== + + >>> from sympy import evaluate + >>> from sympy.abc import x + >>> print(x + x) + 2*x + >>> with evaluate(False): + ... print(x + x) + x + x + """ + def __init__(self, x): + self.x = x + self.old = [] + + def __enter__(self): + self.old.append(global_parameters.evaluate) + global_parameters.evaluate = self.x + + def __exit__(self, exc_type, exc_val, exc_tb): + global_parameters.evaluate = self.old.pop() + +@contextmanager +def distribute(x): + """ Control automatic distribution of Number over Add + + Explanation + =========== + + This context manager controls whether or not Mul distribute Number over + Add. Plan is to avoid distributing Number over Add in all of sympy. Once + that is done, this contextmanager will be removed. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.core.parameters import distribute + >>> print(2*(x + 1)) + 2*x + 2 + >>> with distribute(False): + ... print(2*(x + 1)) + 2*(x + 1) + """ + + old = global_parameters.distribute + + try: + global_parameters.distribute = x + yield + finally: + global_parameters.distribute = old + + +@contextmanager +def _exp_is_pow(x): + """ + Control whether `e^x` should be represented as ``exp(x)`` or a ``Pow(E, x)``. + + Examples + ======== + + >>> from sympy import exp + >>> from sympy.abc import x + >>> from sympy.core.parameters import _exp_is_pow + >>> with _exp_is_pow(True): print(type(exp(x))) + + >>> with _exp_is_pow(False): print(type(exp(x))) + exp + """ + old = global_parameters.exp_is_pow + + clear_cache() + try: + global_parameters.exp_is_pow = x + yield + finally: + clear_cache() + global_parameters.exp_is_pow = old diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/power.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/power.py new file mode 100644 index 0000000000000000000000000000000000000000..0f257d030553ecc7b887ca9d1199ccc19b9a642f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/power.py @@ -0,0 +1,1847 @@ +from __future__ import annotations +from typing import Callable, TYPE_CHECKING +from itertools import product + +from .sympify import _sympify +from .cache import cacheit +from .singleton import S +from .expr import Expr +from .evalf import PrecisionExhausted +from .function import (expand_complex, expand_multinomial, + expand_mul, _mexpand, PoleError) +from .logic import fuzzy_bool, fuzzy_not, fuzzy_and, fuzzy_or +from .parameters import global_parameters +from .relational import is_gt, is_lt +from .kind import NumberKind, UndefinedKind +from sympy.utilities.iterables import sift +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.misc import as_int +from sympy.multipledispatch import Dispatcher + + +class Pow(Expr): + """ + Defines the expression x**y as "x raised to a power y" + + .. deprecated:: 1.7 + + Using arguments that aren't subclasses of :class:`~.Expr` in core + operators (:class:`~.Mul`, :class:`~.Add`, and :class:`~.Pow`) is + deprecated. See :ref:`non-expr-args-deprecated` for details. + + Singleton definitions involving (0, 1, -1, oo, -oo, I, -I): + + +--------------+---------+-----------------------------------------------+ + | expr | value | reason | + +==============+=========+===============================================+ + | z**0 | 1 | Although arguments over 0**0 exist, see [2]. | + +--------------+---------+-----------------------------------------------+ + | z**1 | z | | + +--------------+---------+-----------------------------------------------+ + | (-oo)**(-1) | 0 | | + +--------------+---------+-----------------------------------------------+ + | (-1)**-1 | -1 | | + +--------------+---------+-----------------------------------------------+ + | S.Zero**-1 | zoo | This is not strictly true, as 0**-1 may be | + | | | undefined, but is convenient in some contexts | + | | | where the base is assumed to be positive. | + +--------------+---------+-----------------------------------------------+ + | 1**-1 | 1 | | + +--------------+---------+-----------------------------------------------+ + | oo**-1 | 0 | | + +--------------+---------+-----------------------------------------------+ + | 0**oo | 0 | Because for all complex numbers z near | + | | | 0, z**oo -> 0. | + +--------------+---------+-----------------------------------------------+ + | 0**-oo | zoo | This is not strictly true, as 0**oo may be | + | | | oscillating between positive and negative | + | | | values or rotating in the complex plane. | + | | | It is convenient, however, when the base | + | | | is positive. | + +--------------+---------+-----------------------------------------------+ + | 1**oo | nan | Because there are various cases where | + | 1**-oo | | lim(x(t),t)=1, lim(y(t),t)=oo (or -oo), | + | | | but lim( x(t)**y(t), t) != 1. See [3]. | + +--------------+---------+-----------------------------------------------+ + | b**zoo | nan | Because b**z has no limit as z -> zoo | + +--------------+---------+-----------------------------------------------+ + | (-1)**oo | nan | Because of oscillations in the limit. | + | (-1)**(-oo) | | | + +--------------+---------+-----------------------------------------------+ + | oo**oo | oo | | + +--------------+---------+-----------------------------------------------+ + | oo**-oo | 0 | | + +--------------+---------+-----------------------------------------------+ + | (-oo)**oo | nan | | + | (-oo)**-oo | | | + +--------------+---------+-----------------------------------------------+ + | oo**I | nan | oo**e could probably be best thought of as | + | (-oo)**I | | the limit of x**e for real x as x tends to | + | | | oo. If e is I, then the limit does not exist | + | | | and nan is used to indicate that. | + +--------------+---------+-----------------------------------------------+ + | oo**(1+I) | zoo | If the real part of e is positive, then the | + | (-oo)**(1+I) | | limit of abs(x**e) is oo. So the limit value | + | | | is zoo. | + +--------------+---------+-----------------------------------------------+ + | oo**(-1+I) | 0 | If the real part of e is negative, then the | + | -oo**(-1+I) | | limit is 0. | + +--------------+---------+-----------------------------------------------+ + + Because symbolic computations are more flexible than floating point + calculations and we prefer to never return an incorrect answer, + we choose not to conform to all IEEE 754 conventions. This helps + us avoid extra test-case code in the calculation of limits. + + See Also + ======== + + sympy.core.numbers.Infinity + sympy.core.numbers.NegativeInfinity + sympy.core.numbers.NaN + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Exponentiation + .. [2] https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero + .. [3] https://en.wikipedia.org/wiki/Indeterminate_forms + + """ + is_Pow = True + + __slots__ = ('is_commutative',) + + if TYPE_CHECKING: + + @property + def args(self) -> tuple[Expr, Expr]: + ... + + @property + def base(self) -> Expr: + return self.args[0] + + @property + def exp(self) -> Expr: + return self.args[1] + + @property + def kind(self): + if self.exp.kind is NumberKind: + return self.base.kind + else: + return UndefinedKind + + @cacheit + def __new__(cls, b: Expr | complex, e: Expr | complex, evaluate=None) -> Expr: # type: ignore + if evaluate is None: + evaluate = global_parameters.evaluate + + base = _sympify(b) + exp = _sympify(e) + + # XXX: This can be removed when non-Expr args are disallowed rather + # than deprecated. + from .relational import Relational + if isinstance(base, Relational) or isinstance(exp, Relational): + raise TypeError('Relational cannot be used in Pow') + + # XXX: This should raise TypeError once deprecation period is over: + for arg in [base, exp]: + if not isinstance(arg, Expr): + sympy_deprecation_warning( + f""" + Using non-Expr arguments in Pow is deprecated (in this case, one of the + arguments is of type {type(arg).__name__!r}). + + If you really did intend to construct a power with this base, use the ** + operator instead.""", + deprecated_since_version="1.7", + active_deprecations_target="non-expr-args-deprecated", + stacklevel=4, + ) + + if evaluate: + if exp is S.ComplexInfinity: + return S.NaN + if exp is S.Infinity: + if is_gt(base, S.One): + return S.Infinity + if is_gt(base, S.NegativeOne) and is_lt(base, S.One): + return S.Zero + if is_lt(base, S.NegativeOne): + if base.is_finite: + return S.ComplexInfinity + if base.is_finite is False: + return S.NaN + if exp is S.Zero: + return S.One + elif exp is S.One: + return base + elif exp == -1 and not base: + return S.ComplexInfinity + elif exp.__class__.__name__ == "AccumulationBounds": + if base == S.Exp1: + from sympy.calculus.accumulationbounds import AccumBounds + return AccumBounds(Pow(base, exp.min), Pow(base, exp.max)) + # autosimplification if base is a number and exp odd/even + # if base is Number then the base will end up positive; we + # do not do this with arbitrary expressions since symbolic + # cancellation might occur as in (x - 1)/(1 - x) -> -1. If + # we returned Piecewise((-1, Ne(x, 1))) for such cases then + # we could do this...but we don't + elif (exp.is_Symbol and exp.is_integer or exp.is_Integer + ) and (base.is_number and base.is_Mul or base.is_Number + ) and base.could_extract_minus_sign(): + if exp.is_even: + base = -base + elif exp.is_odd: + return -Pow(-base, exp) + if S.NaN in (base, exp): # XXX S.NaN**x -> S.NaN under assumption that x != 0 + return S.NaN + elif base is S.One: + if abs(exp).is_infinite: + return S.NaN + return S.One + else: + # recognize base as E + from sympy.functions.elementary.exponential import exp_polar + if not exp.is_Atom and base is not S.Exp1 and not isinstance(base, exp_polar): + from .exprtools import factor_terms + from sympy.functions.elementary.exponential import log + from sympy.simplify.radsimp import fraction + c, ex = factor_terms(exp, sign=False).as_coeff_Mul() + num, den = fraction(ex) + if isinstance(den, log) and den.args[0] == base: + return S.Exp1**(c*num) + elif den.is_Add: + from sympy.functions.elementary.complexes import sign, im + s = sign(im(base)) + if s.is_Number and s and den == \ + log(-factor_terms(base, sign=False)) + s*S.ImaginaryUnit*S.Pi: + return S.Exp1**(c*num) + + obj = base._eval_power(exp) + if obj is not None: + return obj + obj = Expr.__new__(cls, base, exp) + obj = cls._exec_constructor_postprocessors(obj) + if not isinstance(obj, Pow): + return obj + obj.is_commutative = (base.is_commutative and exp.is_commutative) + return obj + + def inverse(self, argindex=1): + if self.base == S.Exp1: + from sympy.functions.elementary.exponential import log + return log + return None + + @classmethod + def class_key(cls): + return 3, 2, cls.__name__ + + def _eval_refine(self, assumptions): + from sympy.assumptions.ask import ask, Q + b, e = self.as_base_exp() + if ask(Q.integer(e), assumptions) and b.could_extract_minus_sign(): + if ask(Q.even(e), assumptions): + return Pow(-b, e) + elif ask(Q.odd(e), assumptions): + return -Pow(-b, e) + + def _eval_power(self, expt): + b, e = self.as_base_exp() + if b is S.NaN: + return (b**e)**expt # let __new__ handle it + + s = None + if expt.is_integer: + s = 1 + elif b.is_polar: # e.g. exp_polar, besselj, var('p', polar=True)... + s = 1 + elif e.is_extended_real is not None: + from sympy.functions.elementary.complexes import arg, im, re, sign + from sympy.functions.elementary.exponential import exp, log + from sympy.functions.elementary.integers import floor + # helper functions =========================== + def _half(e): + """Return True if the exponent has a literal 2 as the + denominator, else None.""" + if getattr(e, 'q', None) == 2: + return True + n, d = e.as_numer_denom() + if n.is_integer and d == 2: + return True + def _n2(e): + """Return ``e`` evaluated to a Number with 2 significant + digits, else None.""" + try: + rv = e.evalf(2, strict=True) + if rv.is_Number: + return rv + except PrecisionExhausted: + pass + # =================================================== + if e.is_extended_real: + # we need _half(expt) with constant floor or + # floor(S.Half - e*arg(b)/2/pi) == 0 + + + # handle -1 as special case + if e == -1: + # floor arg. is 1/2 + arg(b)/2/pi + if _half(expt): + if b.is_negative is True: + return S.NegativeOne**expt*Pow(-b, e*expt) + elif b.is_negative is False: # XXX ok if im(b) != 0? + return Pow(b, -expt) + elif e.is_even: + if b.is_extended_real: + b = abs(b) + if b.is_imaginary: + b = abs(im(b))*S.ImaginaryUnit + + if (abs(e) < 1) == True or e == 1: + s = 1 # floor = 0 + elif b.is_extended_nonnegative: + s = 1 # floor = 0 + elif re(b).is_extended_nonnegative and (abs(e) < 2) == True: + s = 1 # floor = 0 + elif _half(expt): + s = exp(2*S.Pi*S.ImaginaryUnit*expt*floor( + S.Half - e*arg(b)/(2*S.Pi))) + if s.is_extended_real and _n2(sign(s) - s) == 0: + s = sign(s) + else: + s = None + else: + # e.is_extended_real is False requires: + # _half(expt) with constant floor or + # floor(S.Half - im(e*log(b))/2/pi) == 0 + try: + s = exp(2*S.ImaginaryUnit*S.Pi*expt* + floor(S.Half - im(e*log(b))/2/S.Pi)) + # be careful to test that s is -1 or 1 b/c sign(I) == I: + # so check that s is real + if s.is_extended_real and _n2(sign(s) - s) == 0: + s = sign(s) + else: + s = None + except PrecisionExhausted: + s = None + + if s is not None: + return s*Pow(b, e*expt) + + def _eval_Mod(self, q): + r"""A dispatched function to compute `b^e \bmod q`, dispatched + by ``Mod``. + + Notes + ===== + + Algorithms: + + 1. For unevaluated integer power, use built-in ``pow`` function + with 3 arguments, if powers are not too large wrt base. + + 2. For very large powers, use totient reduction if $e \ge \log(m)$. + Bound on m, is for safe factorization memory wise i.e. $m^{1/4}$. + For pollard-rho to be faster than built-in pow $\log(e) > m^{1/4}$ + check is added. + + 3. For any unevaluated power found in `b` or `e`, the step 2 + will be recursed down to the base and the exponent + such that the $b \bmod q$ becomes the new base and + $\phi(q) + e \bmod \phi(q)$ becomes the new exponent, and then + the computation for the reduced expression can be done. + """ + + base, exp = self.base, self.exp + + if exp.is_integer and exp.is_positive: + if q.is_integer and base % q == 0: + return S.Zero + + from sympy.functions.combinatorial.numbers import totient + + if base.is_Integer and exp.is_Integer and q.is_Integer: + b, e, m = int(base), int(exp), int(q) + mb = m.bit_length() + if mb <= 80 and e >= mb and e.bit_length()**4 >= m: + phi = int(totient(m)) + return Integer(pow(b, phi + e%phi, m)) + return Integer(pow(b, e, m)) + + from .mod import Mod + + if isinstance(base, Pow) and base.is_integer and base.is_number: + base = Mod(base, q) + return Mod(Pow(base, exp, evaluate=False), q) + + if isinstance(exp, Pow) and exp.is_integer and exp.is_number: + bit_length = int(q).bit_length() + # XXX Mod-Pow actually attempts to do a hanging evaluation + # if this dispatched function returns None. + # May need some fixes in the dispatcher itself. + if bit_length <= 80: + phi = totient(q) + exp = phi + Mod(exp, phi) + return Mod(Pow(base, exp, evaluate=False), q) + + def _eval_is_even(self): + if self.exp.is_integer and self.exp.is_positive: + return self.base.is_even + + def _eval_is_negative(self): + ext_neg = Pow._eval_is_extended_negative(self) + if ext_neg is True: + return self.is_finite + return ext_neg + + def _eval_is_extended_positive(self): + if self.base == self.exp: + if self.base.is_extended_nonnegative: + return True + elif self.base.is_positive: + if self.exp.is_real: + return True + elif self.base.is_extended_negative: + if self.exp.is_even: + return True + if self.exp.is_odd: + return False + elif self.base.is_zero: + if self.exp.is_extended_real: + return self.exp.is_zero + elif self.base.is_extended_nonpositive: + if self.exp.is_odd: + return False + elif self.base.is_imaginary: + if self.exp.is_integer: + m = self.exp % 4 + if m.is_zero: + return True + if m.is_integer and m.is_zero is False: + return False + if self.exp.is_imaginary: + from sympy.functions.elementary.exponential import log + return log(self.base).is_imaginary + + def _eval_is_extended_negative(self): + if self.exp is S.Half: + if self.base.is_complex or self.base.is_extended_real: + return False + if self.base.is_extended_negative: + if self.exp.is_odd and self.base.is_finite: + return True + if self.exp.is_even: + return False + elif self.base.is_extended_positive: + if self.exp.is_extended_real: + return False + elif self.base.is_zero: + if self.exp.is_extended_real: + return False + elif self.base.is_extended_nonnegative: + if self.exp.is_extended_nonnegative: + return False + elif self.base.is_extended_nonpositive: + if self.exp.is_even: + return False + elif self.base.is_extended_real: + if self.exp.is_even: + return False + + def _eval_is_zero(self): + if self.base.is_zero: + if self.exp.is_extended_positive: + return True + elif self.exp.is_extended_nonpositive: + return False + elif self.base == S.Exp1: + return self.exp is S.NegativeInfinity + elif self.base.is_zero is False: + if self.base.is_finite and self.exp.is_finite: + return False + elif self.exp.is_negative: + return self.base.is_infinite + elif self.exp.is_nonnegative: + return False + elif self.exp.is_infinite and self.exp.is_extended_real: + if (1 - abs(self.base)).is_extended_positive: + return self.exp.is_extended_positive + elif (1 - abs(self.base)).is_extended_negative: + return self.exp.is_extended_negative + elif self.base.is_finite and self.exp.is_negative: + # when self.base.is_zero is None + return False + + def _eval_is_integer(self): + b, e = self.args + if b.is_rational: + if b.is_integer is False and e.is_positive: + return False # rat**nonneg + if b.is_integer and e.is_integer: + if b is S.NegativeOne: + return True + if e.is_nonnegative or e.is_positive: + return True + if b.is_integer and e.is_negative and (e.is_finite or e.is_integer): + if fuzzy_not((b - 1).is_zero) and fuzzy_not((b + 1).is_zero): + return False + if b.is_Number and e.is_Number: + check = self.func(*self.args) + return check.is_Integer + if e.is_negative and b.is_positive and (b - 1).is_positive: + return False + if e.is_negative and b.is_negative and (b + 1).is_negative: + return False + + def _eval_is_extended_real(self): + if self.base is S.Exp1: + if self.exp.is_extended_real: + return True + elif self.exp.is_imaginary: + return (2*S.ImaginaryUnit*self.exp/S.Pi).is_even + + from sympy.functions.elementary.exponential import log, exp + real_b = self.base.is_extended_real + if real_b is None: + if self.base.func == exp and self.base.exp.is_imaginary: + return self.exp.is_imaginary + if self.base.func == Pow and self.base.base is S.Exp1 and self.base.exp.is_imaginary: + return self.exp.is_imaginary + return + real_e = self.exp.is_extended_real + if real_e is None: + return + if real_b and real_e: + if self.base.is_extended_positive: + return True + elif self.base.is_extended_nonnegative and self.exp.is_extended_nonnegative: + return True + elif self.exp.is_integer and self.base.is_extended_nonzero: + return True + elif self.exp.is_integer and self.exp.is_nonnegative: + return True + elif self.base.is_extended_negative: + if self.exp.is_Rational: + return False + if real_e and self.exp.is_extended_negative and self.base.is_zero is False: + return Pow(self.base, -self.exp).is_extended_real + im_b = self.base.is_imaginary + im_e = self.exp.is_imaginary + if im_b: + if self.exp.is_integer: + if self.exp.is_even: + return True + elif self.exp.is_odd: + return False + elif im_e and log(self.base).is_imaginary: + return True + elif self.exp.is_Add: + c, a = self.exp.as_coeff_Add() + if c and c.is_Integer: + return Mul( + self.base**c, self.base**a, evaluate=False).is_extended_real + elif self.base in (-S.ImaginaryUnit, S.ImaginaryUnit): + if (self.exp/2).is_integer is False: + return False + if real_b and im_e: + if self.base is S.NegativeOne: + return True + c = self.exp.coeff(S.ImaginaryUnit) + if c: + if self.base.is_rational and c.is_rational: + if self.base.is_nonzero and (self.base - 1).is_nonzero and c.is_nonzero: + return False + ok = (c*log(self.base)/S.Pi).is_integer + if ok is not None: + return ok + + if real_b is False and real_e: # we already know it's not imag + if isinstance(self.exp, Rational) and self.exp.p == 1: + return False + from sympy.functions.elementary.complexes import arg + i = arg(self.base)*self.exp/S.Pi + if i.is_complex: # finite + return i.is_integer + + def _eval_is_complex(self): + + if self.base == S.Exp1: + return fuzzy_or([self.exp.is_complex, self.exp.is_extended_negative]) + + if all(a.is_complex for a in self.args) and self._eval_is_finite(): + return True + + def _eval_is_imaginary(self): + if self.base.is_commutative is False: + return False + + if self.base.is_imaginary: + if self.exp.is_integer: + odd = self.exp.is_odd + if odd is not None: + return odd + return + + if self.base == S.Exp1: + f = 2 * self.exp / (S.Pi*S.ImaginaryUnit) + # exp(pi*integer) = 1 or -1, so not imaginary + if f.is_even: + return False + # exp(pi*integer + pi/2) = I or -I, so it is imaginary + if f.is_odd: + return True + return None + + if self.exp.is_imaginary: + from sympy.functions.elementary.exponential import log + imlog = log(self.base).is_imaginary + if imlog is not None: + return False # I**i -> real; (2*I)**i -> complex ==> not imaginary + + if self.base.is_extended_real and self.exp.is_extended_real: + if self.base.is_positive: + return False + else: + rat = self.exp.is_rational + if not rat: + return rat + if self.exp.is_integer: + return False + else: + half = (2*self.exp).is_integer + if half: + return self.base.is_negative + return half + + if self.base.is_extended_real is False: # we already know it's not imag + from sympy.functions.elementary.complexes import arg + i = arg(self.base)*self.exp/S.Pi + isodd = (2*i).is_odd + if isodd is not None: + return isodd + + def _eval_is_odd(self): + if self.exp.is_integer: + if self.exp.is_positive: + return self.base.is_odd + elif self.exp.is_nonnegative and self.base.is_odd: + return True + elif self.base is S.NegativeOne: + return True + + def _eval_is_finite(self): + if self.exp.is_negative: + if self.base.is_zero: + return False + if self.base.is_infinite or self.base.is_nonzero: + return True + c1 = self.base.is_finite + if c1 is None: + return + c2 = self.exp.is_finite + if c2 is None: + return + if c1 and c2: + if self.exp.is_nonnegative or fuzzy_not(self.base.is_zero): + return True + + def _eval_is_prime(self): + ''' + An integer raised to the n(>=2)-th power cannot be a prime. + ''' + if self.base.is_integer and self.exp.is_integer and (self.exp - 1).is_positive: + return False + + def _eval_is_composite(self): + """ + A power is composite if both base and exponent are greater than 1 + """ + if (self.base.is_integer and self.exp.is_integer and + ((self.base - 1).is_positive and (self.exp - 1).is_positive or + (self.base + 1).is_negative and self.exp.is_positive and self.exp.is_even)): + return True + + def _eval_is_polar(self): + return self.base.is_polar + + def _eval_subs(self, old, new): + from sympy.calculus.accumulationbounds import AccumBounds + + if isinstance(self.exp, AccumBounds): + b = self.base.subs(old, new) + e = self.exp.subs(old, new) + if isinstance(e, AccumBounds): + return e.__rpow__(b) + return self.func(b, e) + + from sympy.functions.elementary.exponential import exp, log + + def _check(ct1, ct2, old): + """Return (bool, pow, remainder_pow) where, if bool is True, then the + exponent of Pow `old` will combine with `pow` so the substitution + is valid, otherwise bool will be False. + + For noncommutative objects, `pow` will be an integer, and a factor + `Pow(old.base, remainder_pow)` needs to be included. If there is + no such factor, None is returned. For commutative objects, + remainder_pow is always None. + + cti are the coefficient and terms of an exponent of self or old + In this _eval_subs routine a change like (b**(2*x)).subs(b**x, y) + will give y**2 since (b**x)**2 == b**(2*x); if that equality does + not hold then the substitution should not occur so `bool` will be + False. + + """ + coeff1, terms1 = ct1 + coeff2, terms2 = ct2 + if terms1 == terms2: + if old.is_commutative: + # Allow fractional powers for commutative objects + pow = coeff1/coeff2 + try: + as_int(pow, strict=False) + combines = True + except ValueError: + b, e = old.as_base_exp() + # These conditions ensure that (b**e)**f == b**(e*f) for any f + combines = b.is_positive and e.is_real or b.is_nonnegative and e.is_nonnegative + + return combines, pow, None + else: + # With noncommutative symbols, substitute only integer powers + if not isinstance(terms1, tuple): + terms1 = (terms1,) + if not all(term.is_integer for term in terms1): + return False, None, None + + try: + # Round pow toward zero + pow, remainder = divmod(as_int(coeff1), as_int(coeff2)) + if pow < 0 and remainder != 0: + pow += 1 + remainder -= as_int(coeff2) + + if remainder == 0: + remainder_pow = None + else: + remainder_pow = Mul(remainder, *terms1) + + return True, pow, remainder_pow + except ValueError: + # Can't substitute + pass + + return False, None, None + + if old == self.base or (old == exp and self.base == S.Exp1): + if new.is_Function and isinstance(new, Callable): + return new(self.exp._subs(old, new)) + else: + return new**self.exp._subs(old, new) + + # issue 10829: (4**x - 3*y + 2).subs(2**x, y) -> y**2 - 3*y + 2 + if isinstance(old, self.func) and self.exp == old.exp: + l = log(self.base, old.base) + if l.is_Number: + return Pow(new, l) + + if isinstance(old, self.func) and self.base == old.base: + if self.exp.is_Add is False: + ct1 = self.exp.as_independent(Symbol, as_Add=False) + ct2 = old.exp.as_independent(Symbol, as_Add=False) + ok, pow, remainder_pow = _check(ct1, ct2, old) + if ok: + # issue 5180: (x**(6*y)).subs(x**(3*y),z)->z**2 + result = self.func(new, pow) + if remainder_pow is not None: + result = Mul(result, Pow(old.base, remainder_pow)) + return result + else: # b**(6*x + a).subs(b**(3*x), y) -> y**2 * b**a + # exp(exp(x) + exp(x**2)).subs(exp(exp(x)), w) -> w * exp(exp(x**2)) + oarg = old.exp + new_l = [] + o_al = [] + ct2 = oarg.as_coeff_mul() + for a in self.exp.args: + newa = a._subs(old, new) + ct1 = newa.as_coeff_mul() + ok, pow, remainder_pow = _check(ct1, ct2, old) + if ok: + new_l.append(new**pow) + if remainder_pow is not None: + o_al.append(remainder_pow) + continue + elif not old.is_commutative and not newa.is_integer: + # If any term in the exponent is non-integer, + # we do not do any substitutions in the noncommutative case + return + o_al.append(newa) + if new_l: + expo = Add(*o_al) + new_l.append(Pow(self.base, expo, evaluate=False) if expo != 1 else self.base) + return Mul(*new_l) + + if (isinstance(old, exp) or (old.is_Pow and old.base is S.Exp1)) and self.exp.is_extended_real and self.base.is_positive: + ct1 = old.exp.as_independent(Symbol, as_Add=False) + ct2 = (self.exp*log(self.base)).as_independent( + Symbol, as_Add=False) + ok, pow, remainder_pow = _check(ct1, ct2, old) + if ok: + result = self.func(new, pow) # (2**x).subs(exp(x*log(2)), z) -> z + if remainder_pow is not None: + result = Mul(result, Pow(old.base, remainder_pow)) + return result + + def as_base_exp(self): + """Return base and exp of self. + + Explanation + =========== + + If base a Rational less than 1, then return 1/Rational, -exp. + If this extra processing is not needed, the base and exp + properties will give the raw arguments. + + Examples + ======== + + >>> from sympy import Pow, S + >>> p = Pow(S.Half, 2, evaluate=False) + >>> p.as_base_exp() + (2, -2) + >>> p.args + (1/2, 2) + >>> p.base, p.exp + (1/2, 2) + + """ + b, e = self.args + if b.is_Rational and b.p == 1 and b.q != 1: + return Integer(b.q), -e + return b, e + + def _eval_adjoint(self): + from sympy.functions.elementary.complexes import adjoint + i, p = self.exp.is_integer, self.base.is_positive + if i: + return adjoint(self.base)**self.exp + if p: + return self.base**adjoint(self.exp) + if i is False and p is False: + expanded = expand_complex(self) + if expanded != self: + return adjoint(expanded) + + def _eval_conjugate(self): + from sympy.functions.elementary.complexes import conjugate as c + i, p = self.exp.is_integer, self.base.is_positive + if i: + return c(self.base)**self.exp + if p: + return self.base**c(self.exp) + if i is False and p is False: + expanded = expand_complex(self) + if expanded != self: + return c(expanded) + if self.is_extended_real: + return self + + def _eval_transpose(self): + from sympy.functions.elementary.complexes import transpose + if self.base == S.Exp1: + return self.func(S.Exp1, self.exp.transpose()) + i, p = self.exp.is_integer, (self.base.is_complex or self.base.is_infinite) + if p: + return self.base**self.exp + if i: + return transpose(self.base)**self.exp + if i is False and p is False: + expanded = expand_complex(self) + if expanded != self: + return transpose(expanded) + + def _eval_expand_power_exp(self, **hints): + """a**(n + m) -> a**n*a**m""" + b = self.base + e = self.exp + if b == S.Exp1: + from sympy.concrete.summations import Sum + if isinstance(e, Sum) and e.is_commutative: + from sympy.concrete.products import Product + return Product(self.func(b, e.function), *e.limits) + if e.is_Add and (hints.get('force', False) or + b.is_zero is False or e._all_nonneg_or_nonppos()): + if e.is_commutative: + return Mul(*[self.func(b, x) for x in e.args]) + if b.is_commutative: + c, nc = sift(e.args, lambda x: x.is_commutative, binary=True) + if c: + return Mul(*[self.func(b, x) for x in c] + )*b**Add._from_args(nc) + return self + + def _eval_expand_power_base(self, **hints): + """(a*b)**n -> a**n * b**n""" + force = hints.get('force', False) + + b = self.base + e = self.exp + if not b.is_Mul: + return self + + cargs, nc = b.args_cnc(split_1=False) + + # expand each term - this is top-level-only + # expansion but we have to watch out for things + # that don't have an _eval_expand method + if nc: + nc = [i._eval_expand_power_base(**hints) + if hasattr(i, '_eval_expand_power_base') else i + for i in nc] + + if e.is_Integer: + if e.is_positive: + rv = Mul(*nc*e) + else: + rv = Mul(*[i**-1 for i in nc[::-1]]*-e) + if cargs: + rv *= Mul(*cargs)**e + return rv + + if not cargs: + return self.func(Mul(*nc), e, evaluate=False) + + nc = [Mul(*nc)] + + # sift the commutative bases + other, maybe_real = sift(cargs, lambda x: x.is_extended_real is False, + binary=True) + def pred(x): + if x is S.ImaginaryUnit: + return S.ImaginaryUnit + polar = x.is_polar + if polar: + return True + if polar is None: + return fuzzy_bool(x.is_extended_nonnegative) + sifted = sift(maybe_real, pred) + nonneg = sifted[True] + other += sifted[None] + neg = sifted[False] + imag = sifted[S.ImaginaryUnit] + if imag: + I = S.ImaginaryUnit + i = len(imag) % 4 + if i == 0: + pass + elif i == 1: + other.append(I) + elif i == 2: + if neg: + nonn = -neg.pop() + if nonn is not S.One: + nonneg.append(nonn) + else: + neg.append(S.NegativeOne) + else: + if neg: + nonn = -neg.pop() + if nonn is not S.One: + nonneg.append(nonn) + else: + neg.append(S.NegativeOne) + other.append(I) + del imag + + # bring out the bases that can be separated from the base + + if force or e.is_integer: + # treat all commutatives the same and put nc in other + cargs = nonneg + neg + other + other = nc + else: + # this is just like what is happening automatically, except + # that now we are doing it for an arbitrary exponent for which + # no automatic expansion is done + + assert not e.is_Integer + + # handle negatives by making them all positive and putting + # the residual -1 in other + if len(neg) > 1: + o = S.One + if not other and neg[0].is_Number: + o *= neg.pop(0) + if len(neg) % 2: + o = -o + for n in neg: + nonneg.append(-n) + if o is not S.One: + other.append(o) + elif neg and other: + if neg[0].is_Number and neg[0] is not S.NegativeOne: + other.append(S.NegativeOne) + nonneg.append(-neg[0]) + else: + other.extend(neg) + else: + other.extend(neg) + del neg + + cargs = nonneg + other += nc + + rv = S.One + if cargs: + if e.is_Rational: + npow, cargs = sift(cargs, lambda x: x.is_Pow and + x.exp.is_Rational and x.base.is_number, + binary=True) + rv = Mul(*[self.func(b.func(*b.args), e) for b in npow]) + rv *= Mul(*[self.func(b, e, evaluate=False) for b in cargs]) + if other: + rv *= self.func(Mul(*other), e, evaluate=False) + return rv + + def _eval_expand_multinomial(self, **hints): + """(a + b + ..)**n -> a**n + n*a**(n-1)*b + .., n is nonzero integer""" + + base, exp = self.args + result = self + + if exp.is_Rational and exp.p > 0 and base.is_Add: + if not exp.is_Integer: + n = Integer(exp.p // exp.q) + + if not n: + return result + else: + radical, result = self.func(base, exp - n), [] + + expanded_base_n = self.func(base, n) + if expanded_base_n.is_Pow: + expanded_base_n = \ + expanded_base_n._eval_expand_multinomial() + for term in Add.make_args(expanded_base_n): + result.append(term*radical) + + return Add(*result) + + n = int(exp) + + if base.is_commutative: + order_terms, other_terms = [], [] + + for b in base.args: + if b.is_Order: + order_terms.append(b) + else: + other_terms.append(b) + + if order_terms: + # (f(x) + O(x^n))^m -> f(x)^m + m*f(x)^{m-1} *O(x^n) + f = Add(*other_terms) + o = Add(*order_terms) + + if n == 2: + return expand_multinomial(f**n, deep=False) + n*f*o + else: + g = expand_multinomial(f**(n - 1), deep=False) + return expand_mul(f*g, deep=False) + n*g*o + + if base.is_number: + # Efficiently expand expressions of the form (a + b*I)**n + # where 'a' and 'b' are real numbers and 'n' is integer. + a, b = base.as_real_imag() + + if a.is_Rational and b.is_Rational: + if not a.is_Integer: + if not b.is_Integer: + k = self.func(a.q * b.q, n) + a, b = a.p*b.q, a.q*b.p + else: + k = self.func(a.q, n) + a, b = a.p, a.q*b + elif not b.is_Integer: + k = self.func(b.q, n) + a, b = a*b.q, b.p + else: + k = 1 + + a, b, c, d = int(a), int(b), 1, 0 + + while n: + if n & 1: + c, d = a*c - b*d, b*c + a*d + n -= 1 + a, b = a*a - b*b, 2*a*b + n //= 2 + + I = S.ImaginaryUnit + + if k == 1: + return c + I*d + else: + return Integer(c)/k + I*d/k + + p = other_terms + # (x + y)**3 -> x**3 + 3*x**2*y + 3*x*y**2 + y**3 + # in this particular example: + # p = [x,y]; n = 3 + # so now it's easy to get the correct result -- we get the + # coefficients first: + from sympy.ntheory.multinomial import multinomial_coefficients + from sympy.polys.polyutils import basic_from_dict + expansion_dict = multinomial_coefficients(len(p), n) + # in our example: {(3, 0): 1, (1, 2): 3, (0, 3): 1, (2, 1): 3} + # and now construct the expression. + return basic_from_dict(expansion_dict, *p) + else: + if n == 2: + return Add(*[f*g for f in base.args for g in base.args]) + else: + multi = (base**(n - 1))._eval_expand_multinomial() + if multi.is_Add: + return Add(*[f*g for f in base.args + for g in multi.args]) + else: + # XXX can this ever happen if base was an Add? + return Add(*[f*multi for f in base.args]) + elif (exp.is_Rational and exp.p < 0 and base.is_Add and + abs(exp.p) > exp.q): + return 1 / self.func(base, -exp)._eval_expand_multinomial() + elif exp.is_Add and base.is_Number and (hints.get('force', False) or + base.is_zero is False or exp._all_nonneg_or_nonppos()): + # a + b a b + # n --> n n, where n, a, b are Numbers + # XXX should be in expand_power_exp? + coeff, tail = [], [] + for term in exp.args: + if term.is_Number: + coeff.append(self.func(base, term)) + else: + tail.append(term) + return Mul(*(coeff + [self.func(base, Add._from_args(tail))])) + else: + return result + + def as_real_imag(self, deep=True, **hints): + if self.exp.is_Integer: + from sympy.polys.polytools import poly + + exp = self.exp + re_e, im_e = self.base.as_real_imag(deep=deep) + if not im_e: + return self, S.Zero + a, b = symbols('a b', cls=Dummy) + if exp >= 0: + if re_e.is_Number and im_e.is_Number: + # We can be more efficient in this case + expr = expand_multinomial(self.base**exp) + if expr != self: + return expr.as_real_imag() + + expr = poly( + (a + b)**exp) # a = re, b = im; expr = (a + b*I)**exp + else: + mag = re_e**2 + im_e**2 + re_e, im_e = re_e/mag, -im_e/mag + if re_e.is_Number and im_e.is_Number: + # We can be more efficient in this case + expr = expand_multinomial((re_e + im_e*S.ImaginaryUnit)**-exp) + if expr != self: + return expr.as_real_imag() + + expr = poly((a + b)**-exp) + + # Terms with even b powers will be real + r = [i for i in expr.terms() if not i[0][1] % 2] + re_part = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) + # Terms with odd b powers will be imaginary + r = [i for i in expr.terms() if i[0][1] % 4 == 1] + im_part1 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) + r = [i for i in expr.terms() if i[0][1] % 4 == 3] + im_part3 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) + + return (re_part.subs({a: re_e, b: S.ImaginaryUnit*im_e}), + im_part1.subs({a: re_e, b: im_e}) + im_part3.subs({a: re_e, b: -im_e})) + + from sympy.functions.elementary.trigonometric import atan2, cos, sin + + if self.exp.is_Rational: + re_e, im_e = self.base.as_real_imag(deep=deep) + + if im_e.is_zero and self.exp is S.Half: + if re_e.is_extended_nonnegative: + return self, S.Zero + if re_e.is_extended_nonpositive: + return S.Zero, (-self.base)**self.exp + + # XXX: This is not totally correct since for x**(p/q) with + # x being imaginary there are actually q roots, but + # only a single one is returned from here. + r = self.func(self.func(re_e, 2) + self.func(im_e, 2), S.Half) + + t = atan2(im_e, re_e) + + rp, tp = self.func(r, self.exp), t*self.exp + + return rp*cos(tp), rp*sin(tp) + elif self.base is S.Exp1: + from sympy.functions.elementary.exponential import exp + re_e, im_e = self.exp.as_real_imag() + if deep: + re_e = re_e.expand(deep, **hints) + im_e = im_e.expand(deep, **hints) + c, s = cos(im_e), sin(im_e) + return exp(re_e)*c, exp(re_e)*s + else: + from sympy.functions.elementary.complexes import im, re + if deep: + hints['complex'] = False + + expanded = self.expand(deep, **hints) + if hints.get('ignore') == expanded: + return None + else: + return (re(expanded), im(expanded)) + else: + return re(self), im(self) + + def _eval_derivative(self, s): + from sympy.functions.elementary.exponential import log + dbase = self.base.diff(s) + dexp = self.exp.diff(s) + return self * (dexp * log(self.base) + dbase * self.exp/self.base) + + def _eval_evalf(self, prec): + base, exp = self.as_base_exp() + if base == S.Exp1: + # Use mpmath function associated to class "exp": + from sympy.functions.elementary.exponential import exp as exp_function + return exp_function(self.exp, evaluate=False)._eval_evalf(prec) + base = base._evalf(prec) + if not exp.is_Integer: + exp = exp._evalf(prec) + if exp.is_negative and base.is_number and base.is_extended_real is False: + base = base.conjugate() / (base * base.conjugate())._evalf(prec) + exp = -exp + return self.func(base, exp).expand() + return self.func(base, exp) + + def _eval_is_polynomial(self, syms): + if self.exp.has(*syms): + return False + + if self.base.has(*syms): + return bool(self.base._eval_is_polynomial(syms) and + self.exp.is_Integer and (self.exp >= 0)) + else: + return True + + def _eval_is_rational(self): + # The evaluation of self.func below can be very expensive in the case + # of integer**integer if the exponent is large. We should try to exit + # before that if possible: + if (self.exp.is_integer and self.base.is_rational + and fuzzy_not(fuzzy_and([self.exp.is_negative, self.base.is_zero]))): + return True + p = self.func(*self.as_base_exp()) # in case it's unevaluated + if not p.is_Pow: + return p.is_rational + b, e = p.as_base_exp() + if e.is_Rational and b.is_Rational: + # we didn't check that e is not an Integer + # because Rational**Integer autosimplifies + return False + if e.is_integer: + if b.is_rational: + if fuzzy_not(b.is_zero) or e.is_nonnegative: + return True + if b == e: # always rational, even for 0**0 + return True + elif b.is_irrational: + return e.is_zero + if b is S.Exp1: + if e.is_rational and e.is_nonzero: + return False + + def _eval_is_algebraic(self): + def _is_one(expr): + try: + return (expr - 1).is_zero + except ValueError: + # when the operation is not allowed + return False + + if self.base.is_zero or _is_one(self.base): + return True + elif self.base is S.Exp1: + s = self.func(*self.args) + if s.func == self.func: + if self.exp.is_nonzero: + if self.exp.is_algebraic: + return False + elif (self.exp/S.Pi).is_rational: + return False + elif (self.exp/(S.ImaginaryUnit*S.Pi)).is_rational: + return True + else: + return s.is_algebraic + elif self.exp.is_rational: + if self.base.is_algebraic is False: + return self.exp.is_zero + if self.base.is_zero is False: + if self.exp.is_nonzero: + return self.base.is_algebraic + elif self.base.is_algebraic: + return True + if self.exp.is_positive: + return self.base.is_algebraic + elif self.base.is_algebraic and self.exp.is_algebraic: + if ((fuzzy_not(self.base.is_zero) + and fuzzy_not(_is_one(self.base))) + or self.base.is_integer is False + or self.base.is_irrational): + return self.exp.is_rational + + def _eval_is_rational_function(self, syms): + if self.exp.has(*syms): + return False + + if self.base.has(*syms): + return self.base._eval_is_rational_function(syms) and \ + self.exp.is_Integer + else: + return True + + def _eval_is_meromorphic(self, x, a): + # f**g is meromorphic if g is an integer and f is meromorphic. + # E**(log(f)*g) is meromorphic if log(f)*g is meromorphic + # and finite. + base_merom = self.base._eval_is_meromorphic(x, a) + exp_integer = self.exp.is_Integer + if exp_integer: + return base_merom + + exp_merom = self.exp._eval_is_meromorphic(x, a) + if base_merom is False: + # f**g = E**(log(f)*g) may be meromorphic if the + # singularities of log(f) and g cancel each other, + # for example, if g = 1/log(f). Hence, + return False if exp_merom else None + elif base_merom is None: + return None + + b = self.base.subs(x, a) + # b is extended complex as base is meromorphic. + # log(base) is finite and meromorphic when b != 0, zoo. + b_zero = b.is_zero + if b_zero: + log_defined = False + else: + log_defined = fuzzy_and((b.is_finite, fuzzy_not(b_zero))) + + if log_defined is False: # zero or pole of base + return exp_integer # False or None + elif log_defined is None: + return None + + if not exp_merom: + return exp_merom # False or None + + return self.exp.subs(x, a).is_finite + + def _eval_is_algebraic_expr(self, syms): + if self.exp.has(*syms): + return False + + if self.base.has(*syms): + return self.base._eval_is_algebraic_expr(syms) and \ + self.exp.is_Rational + else: + return True + + def _eval_rewrite_as_exp(self, base, expo, **kwargs): + from sympy.functions.elementary.exponential import exp, log + + if base.is_zero or base.has(exp) or expo.has(exp): + return base**expo + + evaluate = expo.has(Symbol) + + if base.has(Symbol): + # delay evaluation if expo is non symbolic + # (as exp(x*log(5)) automatically reduces to x**5) + if global_parameters.exp_is_pow: + return Pow(S.Exp1, log(base)*expo, evaluate=evaluate) + else: + return exp(log(base)*expo, evaluate=evaluate) + + else: + from sympy.functions.elementary.complexes import arg, Abs + return exp((log(Abs(base)) + S.ImaginaryUnit*arg(base))*expo) + + def as_numer_denom(self): + if not self.is_commutative: + return self, S.One + base, exp = self.as_base_exp() + n, d = base.as_numer_denom() + # this should be the same as ExpBase.as_numer_denom wrt + # exponent handling + neg_exp = exp.is_negative + if exp.is_Mul and not neg_exp and not exp.is_positive: + neg_exp = exp.could_extract_minus_sign() + int_exp = exp.is_integer + # the denominator cannot be separated from the numerator if + # its sign is unknown unless the exponent is an integer, e.g. + # sqrt(a/b) != sqrt(a)/sqrt(b) when a=1 and b=-1. But if the + # denominator is negative the numerator and denominator can + # be negated and the denominator (now positive) separated. + if not (d.is_extended_real or int_exp): + n = base + d = S.One + dnonpos = d.is_nonpositive + if dnonpos: + n, d = -n, -d + elif dnonpos is None and not int_exp: + n = base + d = S.One + if neg_exp: + n, d = d, n + exp = -exp + if exp.is_infinite: + if n is S.One and d is not S.One: + return n, self.func(d, exp) + if n is not S.One and d is S.One: + return self.func(n, exp), d + return self.func(n, exp), self.func(d, exp) + + def matches(self, expr, repl_dict=None, old=False): + expr = _sympify(expr) + if repl_dict is None: + repl_dict = {} + + # special case, pattern = 1 and expr.exp can match to 0 + if expr is S.One: + d = self.exp.matches(S.Zero, repl_dict) + if d is not None: + return d + + # make sure the expression to be matched is an Expr + if not isinstance(expr, Expr): + return None + + b, e = expr.as_base_exp() + + # special case number + sb, se = self.as_base_exp() + if sb.is_Symbol and se.is_Integer and expr: + if e.is_rational: + return sb.matches(b**(e/se), repl_dict) + return sb.matches(expr**(1/se), repl_dict) + + d = repl_dict.copy() + d = self.base.matches(b, d) + if d is None: + return None + + d = self.exp.xreplace(d).matches(e, d) + if d is None: + return Expr.matches(self, expr, repl_dict) + return d + + def _eval_nseries(self, x, n, logx, cdir=0): + # NOTE! This function is an important part of the gruntz algorithm + # for computing limits. It has to return a generalized power + # series with coefficients in C(log, log(x)). In more detail: + # It has to return an expression + # c_0*x**e_0 + c_1*x**e_1 + ... (finitely many terms) + # where e_i are numbers (not necessarily integers) and c_i are + # expressions involving only numbers, the log function, and log(x). + # The series expansion of b**e is computed as follows: + # 1) We express b as f*(1 + g) where f is the leading term of b. + # g has order O(x**d) where d is strictly positive. + # 2) Then b**e = (f**e)*((1 + g)**e). + # (1 + g)**e is computed using binomial series. + from sympy.functions.elementary.exponential import exp, log + from sympy.series.limits import limit + from sympy.series.order import Order + from sympy.core.sympify import sympify + if self.base is S.Exp1: + e_series = self.exp.nseries(x, n=n, logx=logx) + if e_series.is_Order: + return 1 + e_series + e0 = limit(e_series.removeO(), x, 0) + if e0 is S.NegativeInfinity: + return Order(x**n, x) + if e0 is S.Infinity: + return self + t = e_series - e0 + exp_series = term = exp(e0) + # series of exp(e0 + t) in t + for i in range(1, n): + term *= t/i + term = term.nseries(x, n=n, logx=logx) + exp_series += term + exp_series += Order(t**n, x) + from sympy.simplify.powsimp import powsimp + return powsimp(exp_series, deep=True, combine='exp') + from sympy.simplify.powsimp import powdenest + from .numbers import _illegal + self = powdenest(self, force=True).trigsimp() + b, e = self.as_base_exp() + + if e.has(*_illegal): + raise PoleError() + + if e.has(x): + return exp(e*log(b))._eval_nseries(x, n=n, logx=logx, cdir=cdir) + + if logx is not None and b.has(log): + from .symbol import Wild + c, ex = symbols('c, ex', cls=Wild, exclude=[x]) + b = b.replace(log(c*x**ex), log(c) + ex*logx) + self = b**e + + b = b.removeO() + try: + from sympy.functions.special.gamma_functions import polygamma + if b.has(polygamma, S.EulerGamma) and logx is not None: + raise ValueError() + _, m = b.leadterm(x) + except (ValueError, NotImplementedError, PoleError): + b = b._eval_nseries(x, n=max(2, n), logx=logx, cdir=cdir).removeO() + if b.has(S.NaN, S.ComplexInfinity): + raise NotImplementedError() + _, m = b.leadterm(x) + + if e.has(log): + from sympy.simplify.simplify import logcombine + e = logcombine(e).cancel() + + if not (m.is_zero or e.is_number and e.is_real): + if self == self._eval_as_leading_term(x, logx=logx, cdir=cdir): + res = exp(e*log(b))._eval_nseries(x, n=n, logx=logx, cdir=cdir) + if res == exp(e*log(b)): + return self + return res + + f = b.as_leading_term(x, logx=logx) + g = (_mexpand(b) - f).cancel() + g = g/f + if not m.is_number: + raise NotImplementedError() + maxpow = n - m*e + if maxpow.has(Symbol): + maxpow = sympify(n) + + if maxpow.is_negative: + return Order(x**(m*e), x) + + if g.is_zero: + r = f**e + if r != self: + r += Order(x**n, x) + return r + + def coeff_exp(term, x): + coeff, exp = S.One, S.Zero + for factor in Mul.make_args(term): + if factor.has(x): + base, exp = factor.as_base_exp() + if base != x: + try: + return term.leadterm(x) + except ValueError: + return term, S.Zero + else: + coeff *= factor + return coeff, exp + + def mul(d1, d2): + res = {} + for e1, e2 in product(d1, d2): + ex = e1 + e2 + if ex < maxpow: + res[ex] = res.get(ex, S.Zero) + d1[e1]*d2[e2] + return res + + try: + c, d = g.leadterm(x, logx=logx) + except (ValueError, NotImplementedError): + if limit(g/x**maxpow, x, 0) == 0: + # g has higher order zero + return f**e + e*f**e*g # first term of binomial series + else: + raise NotImplementedError() + if c.is_Float and d == S.Zero: + # Convert floats like 0.5 to exact SymPy numbers like S.Half, to + # prevent rounding errors which can induce wrong values of d leading + # to a NotImplementedError being returned from the block below. + g = g.replace(lambda x: x.is_Float, lambda x: Rational(x)) + _, d = g.leadterm(x, logx=logx) + if not d.is_positive: + g = g.simplify() + if g.is_zero: + return f**e + _, d = g.leadterm(x, logx=logx) + if not d.is_positive: + g = ((b - f)/f).expand() + _, d = g.leadterm(x, logx=logx) + if not d.is_positive: + raise NotImplementedError() + + from sympy.functions.elementary.integers import ceiling + gpoly = g._eval_nseries(x, n=ceiling(maxpow), logx=logx, cdir=cdir).removeO() + gterms = {} + + for term in Add.make_args(gpoly): + co1, e1 = coeff_exp(term, x) + gterms[e1] = gterms.get(e1, S.Zero) + co1 + + k = S.One + terms = {S.Zero: S.One} + tk = gterms + + from sympy.functions.combinatorial.factorials import factorial, ff + + while (k*d - maxpow).is_negative: + coeff = ff(e, k)/factorial(k) + for ex in tk: + terms[ex] = terms.get(ex, S.Zero) + coeff*tk[ex] + tk = mul(tk, gterms) + k += S.One + + from sympy.functions.elementary.complexes import im + + if not e.is_integer and m.is_zero and f.is_negative: + ndir = (b - f).dir(x, cdir) + if im(ndir).is_negative: + inco, inex = coeff_exp(f**e*(-1)**(-2*e), x) + elif im(ndir).is_zero: + inco, inex = coeff_exp(exp(e*log(b)).as_leading_term(x, logx=logx, cdir=cdir), x) + else: + inco, inex = coeff_exp(f**e, x) + else: + inco, inex = coeff_exp(f**e, x) + res = S.Zero + + for e1 in terms: + ex = e1 + inex + res += terms[e1]*inco*x**(ex) + + if not (e.is_integer and e.is_positive and (e*d - n).is_nonpositive and + res == _mexpand(self)): + try: + res += Order(x**n, x) + except NotImplementedError: + return exp(e*log(b))._eval_nseries(x, n=n, logx=logx, cdir=cdir) + return res + + def _eval_as_leading_term(self, x, logx, cdir): + from sympy.functions.elementary.exponential import exp, log + e = self.exp + b = self.base + if self.base is S.Exp1: + arg = e.as_leading_term(x, logx=logx) + arg0 = arg.subs(x, 0) + if arg0 is S.NaN: + arg0 = arg.limit(x, 0) + if arg0.is_infinite is False: + return S.Exp1**arg0 + raise PoleError("Cannot expand %s around 0" % (self)) + elif e.has(x): + lt = exp(e * log(b)) + return lt.as_leading_term(x, logx=logx, cdir=cdir) + else: + from sympy.functions.elementary.complexes import im + try: + f = b.as_leading_term(x, logx=logx, cdir=cdir) + except PoleError: + return self + if not e.is_integer and f.is_negative and not f.has(x): + ndir = (b - f).dir(x, cdir) + if im(ndir).is_negative: + # Normally, f**e would evaluate to exp(e*log(f)) but on branch cuts + # an other value is expected through the following computation + # exp(e*(log(f) - 2*pi*I)) == f**e*exp(-2*e*pi*I) == f**e*(-1)**(-2*e). + return self.func(f, e) * (-1)**(-2*e) + elif im(ndir).is_zero: + log_leadterm = log(b)._eval_as_leading_term(x, logx=logx, cdir=cdir) + if log_leadterm.is_infinite is False: + return exp(e*log_leadterm) + return self.func(f, e) + + @cacheit + def _taylor_term(self, n, x, *previous_terms): # of (1 + x)**e + from sympy.functions.combinatorial.factorials import binomial + return binomial(self.exp, n) * self.func(x, n) + + def taylor_term(self, n, x, *previous_terms): + if self.base is not S.Exp1: + return super().taylor_term(n, x, *previous_terms) + if n < 0: + return S.Zero + if n == 0: + return S.One + from .sympify import sympify + x = sympify(x) + if previous_terms: + p = previous_terms[-1] + if p is not None: + return p * x / n + from sympy.functions.combinatorial.factorials import factorial + return x**n/factorial(n) + + def _eval_rewrite_as_sin(self, base, exp, **hints): + if self.base is S.Exp1: + from sympy.functions.elementary.trigonometric import sin + return sin(S.ImaginaryUnit*self.exp + S.Pi/2) - S.ImaginaryUnit*sin(S.ImaginaryUnit*self.exp) + + def _eval_rewrite_as_cos(self, base, exp, **hints): + if self.base is S.Exp1: + from sympy.functions.elementary.trigonometric import cos + return cos(S.ImaginaryUnit*self.exp) + S.ImaginaryUnit*cos(S.ImaginaryUnit*self.exp + S.Pi/2) + + def _eval_rewrite_as_tanh(self, base, exp, **hints): + if self.base is S.Exp1: + from sympy.functions.elementary.hyperbolic import tanh + return (1 + tanh(self.exp/2))/(1 - tanh(self.exp/2)) + + def _eval_rewrite_as_sqrt(self, base, exp, **kwargs): + from sympy.functions.elementary.trigonometric import sin, cos + if base is not S.Exp1: + return None + if exp.is_Mul: + coeff = exp.coeff(S.Pi * S.ImaginaryUnit) + if coeff and coeff.is_number: + cosine, sine = cos(S.Pi*coeff), sin(S.Pi*coeff) + if not isinstance(cosine, cos) and not isinstance (sine, sin): + return cosine + S.ImaginaryUnit*sine + + def as_content_primitive(self, radical=False, clear=True): + """Return the tuple (R, self/R) where R is the positive Rational + extracted from self. + + Examples + ======== + + >>> from sympy import sqrt + >>> sqrt(4 + 4*sqrt(2)).as_content_primitive() + (2, sqrt(1 + sqrt(2))) + >>> sqrt(3 + 3*sqrt(2)).as_content_primitive() + (1, sqrt(3)*sqrt(1 + sqrt(2))) + + >>> from sympy import expand_power_base, powsimp, Mul + >>> from sympy.abc import x, y + + >>> ((2*x + 2)**2).as_content_primitive() + (4, (x + 1)**2) + >>> (4**((1 + y)/2)).as_content_primitive() + (2, 4**(y/2)) + >>> (3**((1 + y)/2)).as_content_primitive() + (1, 3**((y + 1)/2)) + >>> (3**((5 + y)/2)).as_content_primitive() + (9, 3**((y + 1)/2)) + >>> eq = 3**(2 + 2*x) + >>> powsimp(eq) == eq + True + >>> eq.as_content_primitive() + (9, 3**(2*x)) + >>> powsimp(Mul(*_)) + 3**(2*x + 2) + + >>> eq = (2 + 2*x)**y + >>> s = expand_power_base(eq); s.is_Mul, s + (False, (2*x + 2)**y) + >>> eq.as_content_primitive() + (1, (2*(x + 1))**y) + >>> s = expand_power_base(_[1]); s.is_Mul, s + (True, 2**y*(x + 1)**y) + + See docstring of Expr.as_content_primitive for more examples. + """ + + b, e = self.as_base_exp() + b = _keep_coeff(*b.as_content_primitive(radical=radical, clear=clear)) + ce, pe = e.as_content_primitive(radical=radical, clear=clear) + if b.is_Rational: + #e + #= ce*pe + #= ce*(h + t) + #= ce*h + ce*t + #=> self + #= b**(ce*h)*b**(ce*t) + #= b**(cehp/cehq)*b**(ce*t) + #= b**(iceh + r/cehq)*b**(ce*t) + #= b**(iceh)*b**(r/cehq)*b**(ce*t) + #= b**(iceh)*b**(ce*t + r/cehq) + h, t = pe.as_coeff_Add() + if h.is_Rational and b != S.Zero: + ceh = ce*h + c = self.func(b, ceh) + r = S.Zero + if not c.is_Rational: + iceh, r = divmod(ceh.p, ceh.q) + c = self.func(b, iceh) + return c, self.func(b, _keep_coeff(ce, t + r/ce/ceh.q)) + e = _keep_coeff(ce, pe) + # b**e = (h*t)**e = h**e*t**e = c*m*t**e + if e.is_Rational and b.is_Mul: + h, t = b.as_content_primitive(radical=radical, clear=clear) # h is positive + c, m = self.func(h, e).as_coeff_Mul() # so c is positive + m, me = m.as_base_exp() + if m is S.One or me == e: # probably always true + # return the following, not return c, m*Pow(t, e) + # which would change Pow into Mul; we let SymPy + # decide what to do by using the unevaluated Mul, e.g + # should it stay as sqrt(2 + 2*sqrt(5)) or become + # sqrt(2)*sqrt(1 + sqrt(5)) + return c, self.func(_keep_coeff(m, t), e) + return S.One, self.func(b, e) + + def is_constant(self, *wrt, **flags): + expr = self + if flags.get('simplify', True): + expr = expr.simplify() + b, e = expr.as_base_exp() + bz = b.equals(0) + if bz: # recalculate with assumptions in case it's unevaluated + new = b**e + if new != expr: + return new.is_constant() + econ = e.is_constant(*wrt) + bcon = b.is_constant(*wrt) + if bcon: + if econ: + return True + bz = b.equals(0) + if bz is False: + return False + elif bcon is None: + return None + + return e.equals(0) + + def _eval_difference_delta(self, n, step): + b, e = self.args + if e.has(n) and not b.has(n): + new_e = e.subs(n, n + step) + return (b**(new_e - e) - 1) * self + +power = Dispatcher('power') +power.add((object, object), Pow) + +from .add import Add +from .numbers import Integer, Rational +from .mul import Mul, _keep_coeff +from .symbol import Symbol, Dummy, symbols diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/random.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/random.py new file mode 100644 index 0000000000000000000000000000000000000000..c02986283523b39462a1e2c0b97e3fb230cff100 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/random.py @@ -0,0 +1,227 @@ +""" +When you need to use random numbers in SymPy library code, import from here +so there is only one generator working for SymPy. Imports from here should +behave the same as if they were being imported from Python's random module. +But only the routines currently used in SymPy are included here. To use others +import ``rng`` and access the method directly. For example, to capture the +current state of the generator use ``rng.getstate()``. + +There is intentionally no Random to import from here. If you want +to control the state of the generator, import ``seed`` and call it +with or without an argument to set the state. + +Examples +======== + +>>> from sympy.core.random import random, seed +>>> assert random() < 1 +>>> seed(1); a = random() +>>> b = random() +>>> seed(1); c = random() +>>> assert a == c +>>> assert a != b # remote possibility this will fail + +""" +from sympy.utilities.iterables import is_sequence +from sympy.utilities.misc import as_int + +import random as _random +rng = _random.Random() + +choice = rng.choice +random = rng.random +randint = rng.randint +randrange = rng.randrange +sample = rng.sample +# seed = rng.seed +shuffle = rng.shuffle +uniform = rng.uniform + +_assumptions_rng = _random.Random() +_assumptions_shuffle = _assumptions_rng.shuffle + + +def seed(a=None, version=2): + rng.seed(a=a, version=version) + _assumptions_rng.seed(a=a, version=version) + + +def random_complex_number(a=2, b=-1, c=3, d=1, rational=False, tolerance=None): + """ + Return a random complex number. + + To reduce chance of hitting branch cuts or anything, we guarantee + b <= Im z <= d, a <= Re z <= c + + When rational is True, a rational approximation to a random number + is obtained within specified tolerance, if any. + """ + from sympy.core.numbers import I + from sympy.simplify.simplify import nsimplify + A, B = uniform(a, c), uniform(b, d) + if not rational: + return A + I*B + return (nsimplify(A, rational=True, tolerance=tolerance) + + I*nsimplify(B, rational=True, tolerance=tolerance)) + + +def verify_numerically(f, g, z=None, tol=1.0e-6, a=2, b=-1, c=3, d=1): + """ + Test numerically that f and g agree when evaluated in the argument z. + + If z is None, all symbols will be tested. This routine does not test + whether there are Floats present with precision higher than 15 digits + so if there are, your results may not be what you expect due to round- + off errors. + + Examples + ======== + + >>> from sympy import sin, cos + >>> from sympy.abc import x + >>> from sympy.core.random import verify_numerically as tn + >>> tn(sin(x)**2 + cos(x)**2, 1, x) + True + """ + from sympy.core.symbol import Symbol + from sympy.core.sympify import sympify + from sympy.core.numbers import comp + f, g = (sympify(i) for i in (f, g)) + if z is None: + z = f.free_symbols | g.free_symbols + elif isinstance(z, Symbol): + z = [z] + reps = list(zip(z, [random_complex_number(a, b, c, d) for _ in z])) + z1 = f.subs(reps).n() + z2 = g.subs(reps).n() + return comp(z1, z2, tol) + + +def test_derivative_numerically(f, z, tol=1.0e-6, a=2, b=-1, c=3, d=1): + """ + Test numerically that the symbolically computed derivative of f + with respect to z is correct. + + This routine does not test whether there are Floats present with + precision higher than 15 digits so if there are, your results may + not be what you expect due to round-off errors. + + Examples + ======== + + >>> from sympy import sin + >>> from sympy.abc import x + >>> from sympy.core.random import test_derivative_numerically as td + >>> td(sin(x), x) + True + """ + from sympy.core.numbers import comp + from sympy.core.function import Derivative + z0 = random_complex_number(a, b, c, d) + f1 = f.diff(z).subs(z, z0) + f2 = Derivative(f, z).doit_numerically(z0) + return comp(f1.n(), f2.n(), tol) + + +def _randrange(seed=None): + """Return a randrange generator. + + ``seed`` can be + + * None - return randomly seeded generator + * int - return a generator seeded with the int + * list - the values to be returned will be taken from the list + in the order given; the provided list is not modified. + + Examples + ======== + + >>> from sympy.core.random import _randrange + >>> rr = _randrange() + >>> rr(1000) # doctest: +SKIP + 999 + >>> rr = _randrange(3) + >>> rr(1000) # doctest: +SKIP + 238 + >>> rr = _randrange([0, 5, 1, 3, 4]) + >>> rr(3), rr(3) + (0, 1) + """ + if seed is None: + return randrange + elif isinstance(seed, int): + rng.seed(seed) + return randrange + elif is_sequence(seed): + seed = list(seed) # make a copy + seed.reverse() + + def give(a, b=None, seq=seed): + if b is None: + a, b = 0, a + a, b = as_int(a), as_int(b) + w = b - a + if w < 1: + raise ValueError('_randrange got empty range') + try: + x = seq.pop() + except IndexError: + raise ValueError('_randrange sequence was too short') + if a <= x < b: + return x + else: + return give(a, b, seq) + return give + else: + raise ValueError('_randrange got an unexpected seed') + + +def _randint(seed=None): + """Return a randint generator. + + ``seed`` can be + + * None - return randomly seeded generator + * int - return a generator seeded with the int + * list - the values to be returned will be taken from the list + in the order given; the provided list is not modified. + + Examples + ======== + + >>> from sympy.core.random import _randint + >>> ri = _randint() + >>> ri(1, 1000) # doctest: +SKIP + 999 + >>> ri = _randint(3) + >>> ri(1, 1000) # doctest: +SKIP + 238 + >>> ri = _randint([0, 5, 1, 2, 4]) + >>> ri(1, 3), ri(1, 3) + (1, 2) + """ + if seed is None: + return randint + elif isinstance(seed, int): + rng.seed(seed) + return randint + elif is_sequence(seed): + seed = list(seed) # make a copy + seed.reverse() + + def give(a, b, seq=seed): + a, b = as_int(a), as_int(b) + w = b - a + if w < 0: + raise ValueError('_randint got empty range') + try: + x = seq.pop() + except IndexError: + raise ValueError('_randint sequence was too short') + if a <= x <= b: + return x + else: + return give(a, b, seq) + return give + else: + raise ValueError('_randint got an unexpected seed') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/relational.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/relational.py new file mode 100644 index 0000000000000000000000000000000000000000..28bf039c9be67a6f5cd6f11df1968961c0760373 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/relational.py @@ -0,0 +1,1622 @@ +from __future__ import annotations + +from .basic import Atom, Basic +from .coreerrors import LazyExceptionMessage +from .sorting import ordered +from .evalf import EvalfMixin +from .function import AppliedUndef +from .numbers import int_valued +from .singleton import S +from .sympify import _sympify, SympifyError +from .parameters import global_parameters +from .logic import fuzzy_bool, fuzzy_xor, fuzzy_and, fuzzy_not +from sympy.logic.boolalg import Boolean, BooleanAtom +from sympy.utilities.iterables import sift +from sympy.utilities.misc import filldedent +from sympy.utilities.exceptions import sympy_deprecation_warning + + +__all__ = ( + 'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', + 'Relational', 'Equality', 'Unequality', 'StrictLessThan', 'LessThan', + 'StrictGreaterThan', 'GreaterThan', +) + +from .expr import Expr +from sympy.multipledispatch import dispatch +from .containers import Tuple +from .symbol import Symbol + + +def _nontrivBool(side): + return isinstance(side, Boolean) and \ + not isinstance(side, Atom) + + +# Note, see issue 4986. Ideally, we wouldn't want to subclass both Boolean +# and Expr. +# from .. import Expr + + +def _canonical(cond): + # return a condition in which all relationals are canonical + reps = {r: r.canonical for r in cond.atoms(Relational)} + return cond.xreplace(reps) + # XXX: AttributeError was being caught here but it wasn't triggered by any of + # the tests so I've removed it... + + +def _canonical_coeff(rel): + # return -2*x + 1 < 0 as x > 1/2 + # XXX make this part of Relational.canonical? + rel = rel.canonical + if not rel.is_Relational or rel.rhs.is_Boolean: + return rel # Eq(x, True) + if not isinstance(rel.lhs, Expr): + return rel.reversed # e.g.: Eq(True, x) -> Eq(x, True) + b, l = rel.lhs.as_coeff_Add(rational=True) + m, lhs = l.as_coeff_Mul(rational=True) + rhs = (rel.rhs - b)/m + if m < 0: + return rel.reversed.func(lhs, rhs) + return rel.func(lhs, rhs) + + +class Relational(Boolean, EvalfMixin): + """Base class for all relation types. + + Explanation + =========== + + Subclasses of Relational should generally be instantiated directly, but + Relational can be instantiated with a valid ``rop`` value to dispatch to + the appropriate subclass. + + Parameters + ========== + + rop : str or None + Indicates what subclass to instantiate. Valid values can be found + in the keys of Relational.ValidRelationOperator. + + Examples + ======== + + >>> from sympy import Rel + >>> from sympy.abc import x, y + >>> Rel(y, x + x**2, '==') + Eq(y, x**2 + x) + + A relation's type can be defined upon creation using ``rop``. + The relation type of an existing expression can be obtained + using its ``rel_op`` property. + Here is a table of all the relation types, along with their + ``rop`` and ``rel_op`` values: + + +---------------------+----------------------------+------------+ + |Relation |``rop`` |``rel_op`` | + +=====================+============================+============+ + |``Equality`` |``==`` or ``eq`` or ``None``|``==`` | + +---------------------+----------------------------+------------+ + |``Unequality`` |``!=`` or ``ne`` |``!=`` | + +---------------------+----------------------------+------------+ + |``GreaterThan`` |``>=`` or ``ge`` |``>=`` | + +---------------------+----------------------------+------------+ + |``LessThan`` |``<=`` or ``le`` |``<=`` | + +---------------------+----------------------------+------------+ + |``StrictGreaterThan``|``>`` or ``gt`` |``>`` | + +---------------------+----------------------------+------------+ + |``StrictLessThan`` |``<`` or ``lt`` |``<`` | + +---------------------+----------------------------+------------+ + + For example, setting ``rop`` to ``==`` produces an + ``Equality`` relation, ``Eq()``. + So does setting ``rop`` to ``eq``, or leaving ``rop`` unspecified. + That is, the first three ``Rel()`` below all produce the same result. + Using a ``rop`` from a different row in the table produces a + different relation type. + For example, the fourth ``Rel()`` below using ``lt`` for ``rop`` + produces a ``StrictLessThan`` inequality: + + >>> from sympy import Rel + >>> from sympy.abc import x, y + >>> Rel(y, x + x**2, '==') + Eq(y, x**2 + x) + >>> Rel(y, x + x**2, 'eq') + Eq(y, x**2 + x) + >>> Rel(y, x + x**2) + Eq(y, x**2 + x) + >>> Rel(y, x + x**2, 'lt') + y < x**2 + x + + To obtain the relation type of an existing expression, + get its ``rel_op`` property. + For example, ``rel_op`` is ``==`` for the ``Equality`` relation above, + and ``<`` for the strict less than inequality above: + + >>> from sympy import Rel + >>> from sympy.abc import x, y + >>> my_equality = Rel(y, x + x**2, '==') + >>> my_equality.rel_op + '==' + >>> my_inequality = Rel(y, x + x**2, 'lt') + >>> my_inequality.rel_op + '<' + + """ + __slots__ = () + + ValidRelationOperator: dict[str | None, type[Relational]] = {} + + is_Relational = True + + # ValidRelationOperator - Defined below, because the necessary classes + # have not yet been defined + + def __new__(cls, lhs, rhs, rop=None, **assumptions): + # If called by a subclass, do nothing special and pass on to Basic. + if cls is not Relational: + return Basic.__new__(cls, lhs, rhs, **assumptions) + + # XXX: Why do this? There should be a separate function to make a + # particular subclass of Relational from a string. + # + # If called directly with an operator, look up the subclass + # corresponding to that operator and delegate to it + cls = cls.ValidRelationOperator.get(rop, None) + if cls is None: + raise ValueError("Invalid relational operator symbol: %r" % rop) + + if not issubclass(cls, (Eq, Ne)): + # validate that Booleans are not being used in a relational + # other than Eq/Ne; + # Note: Symbol is a subclass of Boolean but is considered + # acceptable here. + if any(map(_nontrivBool, (lhs, rhs))): + raise TypeError(filldedent(''' + A Boolean argument can only be used in + Eq and Ne; all other relationals expect + real expressions. + ''')) + + return cls(lhs, rhs, **assumptions) + + @property + def lhs(self): + """The left-hand side of the relation.""" + return self._args[0] + + @property + def rhs(self): + """The right-hand side of the relation.""" + return self._args[1] + + @property + def reversed(self): + """Return the relationship with sides reversed. + + Examples + ======== + + >>> from sympy import Eq + >>> from sympy.abc import x + >>> Eq(x, 1) + Eq(x, 1) + >>> _.reversed + Eq(1, x) + >>> x < 1 + x < 1 + >>> _.reversed + 1 > x + """ + ops = {Eq: Eq, Gt: Lt, Ge: Le, Lt: Gt, Le: Ge, Ne: Ne} + a, b = self.args + return Relational.__new__(ops.get(self.func, self.func), b, a) + + @property + def reversedsign(self): + """Return the relationship with signs reversed. + + Examples + ======== + + >>> from sympy import Eq + >>> from sympy.abc import x + >>> Eq(x, 1) + Eq(x, 1) + >>> _.reversedsign + Eq(-x, -1) + >>> x < 1 + x < 1 + >>> _.reversedsign + -x > -1 + """ + a, b = self.args + if not (isinstance(a, BooleanAtom) or isinstance(b, BooleanAtom)): + ops = {Eq: Eq, Gt: Lt, Ge: Le, Lt: Gt, Le: Ge, Ne: Ne} + return Relational.__new__(ops.get(self.func, self.func), -a, -b) + else: + return self + + @property + def negated(self): + """Return the negated relationship. + + Examples + ======== + + >>> from sympy import Eq + >>> from sympy.abc import x + >>> Eq(x, 1) + Eq(x, 1) + >>> _.negated + Ne(x, 1) + >>> x < 1 + x < 1 + >>> _.negated + x >= 1 + + Notes + ===== + + This works more or less identical to ``~``/``Not``. The difference is + that ``negated`` returns the relationship even if ``evaluate=False``. + Hence, this is useful in code when checking for e.g. negated relations + to existing ones as it will not be affected by the `evaluate` flag. + + """ + ops = {Eq: Ne, Ge: Lt, Gt: Le, Le: Gt, Lt: Ge, Ne: Eq} + # If there ever will be new Relational subclasses, the following line + # will work until it is properly sorted out + # return ops.get(self.func, lambda a, b, evaluate=False: ~(self.func(a, + # b, evaluate=evaluate)))(*self.args, evaluate=False) + return Relational.__new__(ops.get(self.func), *self.args) + + @property + def weak(self): + """return the non-strict version of the inequality or self + + EXAMPLES + ======== + + >>> from sympy.abc import x + >>> (x < 1).weak + x <= 1 + >>> _.weak + x <= 1 + """ + return self + + @property + def strict(self): + """return the strict version of the inequality or self + + EXAMPLES + ======== + + >>> from sympy.abc import x + >>> (x <= 1).strict + x < 1 + >>> _.strict + x < 1 + """ + return self + + def _eval_evalf(self, prec): + return self.func(*[s._evalf(prec) for s in self.args]) + + @property + def canonical(self): + """Return a canonical form of the relational by putting a + number on the rhs, canonically removing a sign or else + ordering the args canonically. No other simplification is + attempted. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> x < 2 + x < 2 + >>> _.reversed.canonical + x < 2 + >>> (-y < x).canonical + x > -y + >>> (-y > x).canonical + x < -y + >>> (-y < -x).canonical + x < y + + The canonicalization is recursively applied: + + >>> from sympy import Eq + >>> Eq(x < y, y > x).canonical + True + """ + args = tuple([i.canonical if isinstance(i, Relational) else i for i in self.args]) + if args != self.args: + r = self.func(*args) + if not isinstance(r, Relational): + return r + else: + r = self + if r.rhs.is_number: + if r.rhs.is_Number and r.lhs.is_Number and r.lhs > r.rhs: + r = r.reversed + elif r.lhs.is_number: + r = r.reversed + elif tuple(ordered(args)) != args: + r = r.reversed + + LHS_CEMS = getattr(r.lhs, 'could_extract_minus_sign', None) + RHS_CEMS = getattr(r.rhs, 'could_extract_minus_sign', None) + + if isinstance(r.lhs, BooleanAtom) or isinstance(r.rhs, BooleanAtom): + return r + + # Check if first value has negative sign + if LHS_CEMS and LHS_CEMS(): + return r.reversedsign + elif not r.rhs.is_number and RHS_CEMS and RHS_CEMS(): + # Right hand side has a minus, but not lhs. + # How does the expression with reversed signs behave? + # This is so that expressions of the type + # Eq(x, -y) and Eq(-x, y) + # have the same canonical representation + expr1, _ = ordered([r.lhs, -r.rhs]) + if expr1 != r.lhs: + return r.reversed.reversedsign + + return r + + def equals(self, other, failing_expression=False): + """Return True if the sides of the relationship are mathematically + identical and the type of relationship is the same. + If failing_expression is True, return the expression whose truth value + was unknown.""" + if isinstance(other, Relational): + if other in (self, self.reversed): + return True + a, b = self, other + if a.func in (Eq, Ne) or b.func in (Eq, Ne): + if a.func != b.func: + return False + left, right = [i.equals(j, + failing_expression=failing_expression) + for i, j in zip(a.args, b.args)] + if left is True: + return right + if right is True: + return left + lr, rl = [i.equals(j, failing_expression=failing_expression) + for i, j in zip(a.args, b.reversed.args)] + if lr is True: + return rl + if rl is True: + return lr + e = (left, right, lr, rl) + if all(i is False for i in e): + return False + for i in e: + if i not in (True, False): + return i + else: + if b.func != a.func: + b = b.reversed + if a.func != b.func: + return False + left = a.lhs.equals(b.lhs, + failing_expression=failing_expression) + if left is False: + return False + right = a.rhs.equals(b.rhs, + failing_expression=failing_expression) + if right is False: + return False + if left is True: + return right + return left + + def _eval_simplify(self, **kwargs): + from .add import Add + from .expr import Expr + r = self + r = r.func(*[i.simplify(**kwargs) for i in r.args]) + if r.is_Relational: + if not isinstance(r.lhs, Expr) or not isinstance(r.rhs, Expr): + return r + dif = r.lhs - r.rhs + # replace dif with a valid Number that will + # allow a definitive comparison with 0 + v = None + if dif.is_comparable: + v = dif.n(2) + if any(i._prec == 1 for i in v.as_real_imag()): + rv, iv = [i.n(2) for i in dif.as_real_imag()] + v = rv + S.ImaginaryUnit*iv + elif dif.equals(0): # XXX this is expensive + v = S.Zero + if v is not None: + r = r.func._eval_relation(v, S.Zero) + r = r.canonical + # If there is only one symbol in the expression, + # try to write it on a simplified form + free = list(filter(lambda x: x.is_real is not False, r.free_symbols)) + if len(free) == 1: + try: + from sympy.solvers.solveset import linear_coeffs + x = free.pop() + dif = r.lhs - r.rhs + m, b = linear_coeffs(dif, x) + if m.is_zero is False: + if m.is_negative: + # Dividing with a negative number, so change order of arguments + # canonical will put the symbol back on the lhs later + r = r.func(-b / m, x) + else: + r = r.func(x, -b / m) + else: + r = r.func(b, S.Zero) + except ValueError: + # maybe not a linear function, try polynomial + from sympy.polys.polyerrors import PolynomialError + from sympy.polys.polytools import gcd, Poly, poly + try: + p = poly(dif, x) + c = p.all_coeffs() + constant = c[-1] + c[-1] = 0 + scale = gcd(c) + c = [ctmp / scale for ctmp in c] + r = r.func(Poly.from_list(c, x).as_expr(), -constant / scale) + except PolynomialError: + pass + elif len(free) >= 2: + try: + from sympy.solvers.solveset import linear_coeffs + from sympy.polys.polytools import gcd + free = list(ordered(free)) + dif = r.lhs - r.rhs + m = linear_coeffs(dif, *free) + constant = m[-1] + del m[-1] + scale = gcd(m) + m = [mtmp / scale for mtmp in m] + nzm = list(filter(lambda f: f[0] != 0, list(zip(m, free)))) + if scale.is_zero is False: + if constant != 0: + # lhs: expression, rhs: constant + newexpr = Add(*[i * j for i, j in nzm]) + r = r.func(newexpr, -constant / scale) + else: + # keep first term on lhs + lhsterm = nzm[0][0] * nzm[0][1] + del nzm[0] + newexpr = Add(*[i * j for i, j in nzm]) + r = r.func(lhsterm, -newexpr) + + else: + r = r.func(constant, S.Zero) + except ValueError: + pass + # Did we get a simplified result? + r = r.canonical + measure = kwargs['measure'] + if measure(r) < kwargs['ratio'] * measure(self): + return r + else: + return self + + def _eval_trigsimp(self, **opts): + from sympy.simplify.trigsimp import trigsimp + return self.func(trigsimp(self.lhs, **opts), trigsimp(self.rhs, **opts)) + + def expand(self, **kwargs): + args = (arg.expand(**kwargs) for arg in self.args) + return self.func(*args) + + def __bool__(self) -> bool: + raise TypeError( + LazyExceptionMessage( + lambda: f"cannot determine truth value of Relational: {self}" + ) + ) + + def _eval_as_set(self): + # self is univariate and periodicity(self, x) in (0, None) + from sympy.solvers.inequalities import solve_univariate_inequality + from sympy.sets.conditionset import ConditionSet + syms = self.free_symbols + assert len(syms) == 1 + x = syms.pop() + try: + xset = solve_univariate_inequality(self, x, relational=False) + except NotImplementedError: + # solve_univariate_inequality raises NotImplementedError for + # unsolvable equations/inequalities. + xset = ConditionSet(x, self, S.Reals) + return xset + + @property + def binary_symbols(self): + # override where necessary + return set() + + +Rel = Relational + + +class Equality(Relational): + """ + An equal relation between two objects. + + Explanation + =========== + + Represents that two objects are equal. If they can be easily shown + to be definitively equal (or unequal), this will reduce to True (or + False). Otherwise, the relation is maintained as an unevaluated + Equality object. Use the ``simplify`` function on this object for + more nontrivial evaluation of the equality relation. + + As usual, the keyword argument ``evaluate=False`` can be used to + prevent any evaluation. + + Examples + ======== + + >>> from sympy import Eq, simplify, exp, cos + >>> from sympy.abc import x, y + >>> Eq(y, x + x**2) + Eq(y, x**2 + x) + >>> Eq(2, 5) + False + >>> Eq(2, 5, evaluate=False) + Eq(2, 5) + >>> _.doit() + False + >>> Eq(exp(x), exp(x).rewrite(cos)) + Eq(exp(x), sinh(x) + cosh(x)) + >>> simplify(_) + True + + See Also + ======== + + sympy.logic.boolalg.Equivalent : for representing equality between two + boolean expressions + + Notes + ===== + + Python treats 1 and True (and 0 and False) as being equal; SymPy + does not. And integer will always compare as unequal to a Boolean: + + >>> Eq(True, 1), True == 1 + (False, True) + + This class is not the same as the == operator. The == operator tests + for exact structural equality between two expressions; this class + compares expressions mathematically. + + If either object defines an ``_eval_Eq`` method, it can be used in place of + the default algorithm. If ``lhs._eval_Eq(rhs)`` or ``rhs._eval_Eq(lhs)`` + returns anything other than None, that return value will be substituted for + the Equality. If None is returned by ``_eval_Eq``, an Equality object will + be created as usual. + + Since this object is already an expression, it does not respond to + the method ``as_expr`` if one tries to create `x - y` from ``Eq(x, y)``. + If ``eq = Eq(x, y)`` then write `eq.lhs - eq.rhs` to get ``x - y``. + + .. deprecated:: 1.5 + + ``Eq(expr)`` with a single argument is a shorthand for ``Eq(expr, 0)``, + but this behavior is deprecated and will be removed in a future version + of SymPy. + + """ + rel_op = '==' + + __slots__ = () + + is_Equality = True + + def __new__(cls, lhs, rhs, **options): + evaluate = options.pop('evaluate', global_parameters.evaluate) + lhs = _sympify(lhs) + rhs = _sympify(rhs) + if evaluate: + val = is_eq(lhs, rhs) + if val is None: + return cls(lhs, rhs, evaluate=False) + else: + return _sympify(val) + + return Relational.__new__(cls, lhs, rhs) + + @classmethod + def _eval_relation(cls, lhs, rhs): + return _sympify(lhs == rhs) + + def _eval_rewrite_as_Add(self, L, R, evaluate=True, **kwargs): + """ + return Eq(L, R) as L - R. To control the evaluation of + the result set pass `evaluate=True` to give L - R; + if `evaluate=None` then terms in L and R will not cancel + but they will be listed in canonical order; otherwise + non-canonical args will be returned. If one side is 0, the + non-zero side will be returned. + + .. deprecated:: 1.13 + + The method ``Eq.rewrite(Add)`` is deprecated. + See :ref:`eq-rewrite-Add` for details. + + Examples + ======== + + >>> from sympy import Eq, Add + >>> from sympy.abc import b, x + >>> eq = Eq(x + b, x - b) + >>> eq.rewrite(Add) #doctest: +SKIP + 2*b + >>> eq.rewrite(Add, evaluate=None).args #doctest: +SKIP + (b, b, x, -x) + >>> eq.rewrite(Add, evaluate=False).args #doctest: +SKIP + (b, x, b, -x) + """ + sympy_deprecation_warning(""" + Eq.rewrite(Add) is deprecated. + + For ``eq = Eq(a, b)`` use ``eq.lhs - eq.rhs`` to obtain + ``a - b``. + """, + deprecated_since_version="1.13", + active_deprecations_target="eq-rewrite-Add", + stacklevel=5, + ) + from .add import _unevaluated_Add, Add + if L == 0: + return R + if R == 0: + return L + if evaluate: + # allow cancellation of args + return L - R + args = Add.make_args(L) + Add.make_args(-R) + if evaluate is None: + # no cancellation, but canonical + return _unevaluated_Add(*args) + # no cancellation, not canonical + return Add._from_args(args) + + @property + def binary_symbols(self): + if S.true in self.args or S.false in self.args: + if self.lhs.is_Symbol: + return {self.lhs} + elif self.rhs.is_Symbol: + return {self.rhs} + return set() + + def _eval_simplify(self, **kwargs): + # standard simplify + e = super()._eval_simplify(**kwargs) + if not isinstance(e, Equality): + return e + from .expr import Expr + if not isinstance(e.lhs, Expr) or not isinstance(e.rhs, Expr): + return e + free = self.free_symbols + if len(free) == 1: + try: + from .add import Add + from sympy.solvers.solveset import linear_coeffs + x = free.pop() + m, b = linear_coeffs( + Add(e.lhs, -e.rhs, evaluate=False), x) + if m.is_zero is False: + enew = e.func(x, -b / m) + else: + enew = e.func(m * x, -b) + measure = kwargs['measure'] + if measure(enew) <= kwargs['ratio'] * measure(e): + e = enew + except ValueError: + pass + return e.canonical + + def integrate(self, *args, **kwargs): + """See the integrate function in sympy.integrals""" + from sympy.integrals.integrals import integrate + return integrate(self, *args, **kwargs) + + def as_poly(self, *gens, **kwargs): + '''Returns lhs-rhs as a Poly + + Examples + ======== + + >>> from sympy import Eq + >>> from sympy.abc import x + >>> Eq(x**2, 1).as_poly(x) + Poly(x**2 - 1, x, domain='ZZ') + ''' + return (self.lhs - self.rhs).as_poly(*gens, **kwargs) + + +Eq = Equality + + +class Unequality(Relational): + """An unequal relation between two objects. + + Explanation + =========== + + Represents that two objects are not equal. If they can be shown to be + definitively equal, this will reduce to False; if definitively unequal, + this will reduce to True. Otherwise, the relation is maintained as an + Unequality object. + + Examples + ======== + + >>> from sympy import Ne + >>> from sympy.abc import x, y + >>> Ne(y, x+x**2) + Ne(y, x**2 + x) + + See Also + ======== + Equality + + Notes + ===== + This class is not the same as the != operator. The != operator tests + for exact structural equality between two expressions; this class + compares expressions mathematically. + + This class is effectively the inverse of Equality. As such, it uses the + same algorithms, including any available `_eval_Eq` methods. + + """ + rel_op = '!=' + + __slots__ = () + + def __new__(cls, lhs, rhs, **options): + lhs = _sympify(lhs) + rhs = _sympify(rhs) + evaluate = options.pop('evaluate', global_parameters.evaluate) + if evaluate: + val = is_neq(lhs, rhs) + if val is None: + return cls(lhs, rhs, evaluate=False) + else: + return _sympify(val) + + return Relational.__new__(cls, lhs, rhs, **options) + + @classmethod + def _eval_relation(cls, lhs, rhs): + return _sympify(lhs != rhs) + + @property + def binary_symbols(self): + if S.true in self.args or S.false in self.args: + if self.lhs.is_Symbol: + return {self.lhs} + elif self.rhs.is_Symbol: + return {self.rhs} + return set() + + def _eval_simplify(self, **kwargs): + # simplify as an equality + eq = Equality(*self.args)._eval_simplify(**kwargs) + if isinstance(eq, Equality): + # send back Ne with the new args + return self.func(*eq.args) + return eq.negated # result of Ne is the negated Eq + + +Ne = Unequality + + +class _Inequality(Relational): + """Internal base class for all *Than types. + + Each subclass must implement _eval_relation to provide the method for + comparing two real numbers. + + """ + __slots__ = () + + def __new__(cls, lhs, rhs, **options): + + try: + lhs = _sympify(lhs) + rhs = _sympify(rhs) + except SympifyError: + return NotImplemented + + evaluate = options.pop('evaluate', global_parameters.evaluate) + if evaluate: + for me in (lhs, rhs): + if me.is_extended_real is False: + raise TypeError("Invalid comparison of non-real %s" % me) + if me is S.NaN: + raise TypeError("Invalid NaN comparison") + # First we invoke the appropriate inequality method of `lhs` + # (e.g., `lhs.__lt__`). That method will try to reduce to + # boolean or raise an exception. It may keep calling + # superclasses until it reaches `Expr` (e.g., `Expr.__lt__`). + # In some cases, `Expr` will just invoke us again (if neither it + # nor a subclass was able to reduce to boolean or raise an + # exception). In that case, it must call us with + # `evaluate=False` to prevent infinite recursion. + return cls._eval_relation(lhs, rhs, **options) + + # make a "non-evaluated" Expr for the inequality + return Relational.__new__(cls, lhs, rhs, **options) + + @classmethod + def _eval_relation(cls, lhs, rhs, **options): + val = cls._eval_fuzzy_relation(lhs, rhs) + if val is None: + return cls(lhs, rhs, evaluate=False) + else: + return _sympify(val) + + +class _Greater(_Inequality): + """Not intended for general use + + _Greater is only used so that GreaterThan and StrictGreaterThan may + subclass it for the .gts and .lts properties. + + """ + __slots__ = () + + @property + def gts(self): + return self._args[0] + + @property + def lts(self): + return self._args[1] + + +class _Less(_Inequality): + """Not intended for general use. + + _Less is only used so that LessThan and StrictLessThan may subclass it for + the .gts and .lts properties. + + """ + __slots__ = () + + @property + def gts(self): + return self._args[1] + + @property + def lts(self): + return self._args[0] + + +class GreaterThan(_Greater): + r"""Class representations of inequalities. + + Explanation + =========== + + The ``*Than`` classes represent inequal relationships, where the left-hand + side is generally bigger or smaller than the right-hand side. For example, + the GreaterThan class represents an inequal relationship where the + left-hand side is at least as big as the right side, if not bigger. In + mathematical notation: + + lhs $\ge$ rhs + + In total, there are four ``*Than`` classes, to represent the four + inequalities: + + +-----------------+--------+ + |Class Name | Symbol | + +=================+========+ + |GreaterThan | ``>=`` | + +-----------------+--------+ + |LessThan | ``<=`` | + +-----------------+--------+ + |StrictGreaterThan| ``>`` | + +-----------------+--------+ + |StrictLessThan | ``<`` | + +-----------------+--------+ + + All classes take two arguments, lhs and rhs. + + +----------------------------+-----------------+ + |Signature Example | Math Equivalent | + +============================+=================+ + |GreaterThan(lhs, rhs) | lhs $\ge$ rhs | + +----------------------------+-----------------+ + |LessThan(lhs, rhs) | lhs $\le$ rhs | + +----------------------------+-----------------+ + |StrictGreaterThan(lhs, rhs) | lhs $>$ rhs | + +----------------------------+-----------------+ + |StrictLessThan(lhs, rhs) | lhs $<$ rhs | + +----------------------------+-----------------+ + + In addition to the normal .lhs and .rhs of Relations, ``*Than`` inequality + objects also have the .lts and .gts properties, which represent the "less + than side" and "greater than side" of the operator. Use of .lts and .gts + in an algorithm rather than .lhs and .rhs as an assumption of inequality + direction will make more explicit the intent of a certain section of code, + and will make it similarly more robust to client code changes: + + >>> from sympy import GreaterThan, StrictGreaterThan + >>> from sympy import LessThan, StrictLessThan + >>> from sympy import And, Ge, Gt, Le, Lt, Rel, S + >>> from sympy.abc import x, y, z + >>> from sympy.core.relational import Relational + + >>> e = GreaterThan(x, 1) + >>> e + x >= 1 + >>> '%s >= %s is the same as %s <= %s' % (e.gts, e.lts, e.lts, e.gts) + 'x >= 1 is the same as 1 <= x' + + Examples + ======== + + One generally does not instantiate these classes directly, but uses various + convenience methods: + + >>> for f in [Ge, Gt, Le, Lt]: # convenience wrappers + ... print(f(x, 2)) + x >= 2 + x > 2 + x <= 2 + x < 2 + + Another option is to use the Python inequality operators (``>=``, ``>``, + ``<=``, ``<``) directly. Their main advantage over the ``Ge``, ``Gt``, + ``Le``, and ``Lt`` counterparts, is that one can write a more + "mathematical looking" statement rather than littering the math with + oddball function calls. However there are certain (minor) caveats of + which to be aware (search for 'gotcha', below). + + >>> x >= 2 + x >= 2 + >>> _ == Ge(x, 2) + True + + However, it is also perfectly valid to instantiate a ``*Than`` class less + succinctly and less conveniently: + + >>> Rel(x, 1, ">") + x > 1 + >>> Relational(x, 1, ">") + x > 1 + + >>> StrictGreaterThan(x, 1) + x > 1 + >>> GreaterThan(x, 1) + x >= 1 + >>> LessThan(x, 1) + x <= 1 + >>> StrictLessThan(x, 1) + x < 1 + + Notes + ===== + + There are a couple of "gotchas" to be aware of when using Python's + operators. + + The first is that what your write is not always what you get: + + >>> 1 < x + x > 1 + + Due to the order that Python parses a statement, it may + not immediately find two objects comparable. When ``1 < x`` + is evaluated, Python recognizes that the number 1 is a native + number and that x is *not*. Because a native Python number does + not know how to compare itself with a SymPy object + Python will try the reflective operation, ``x > 1`` and that is the + form that gets evaluated, hence returned. + + If the order of the statement is important (for visual output to + the console, perhaps), one can work around this annoyance in a + couple ways: + + (1) "sympify" the literal before comparison + + >>> S(1) < x + 1 < x + + (2) use one of the wrappers or less succinct methods described + above + + >>> Lt(1, x) + 1 < x + >>> Relational(1, x, "<") + 1 < x + + The second gotcha involves writing equality tests between relationals + when one or both sides of the test involve a literal relational: + + >>> e = x < 1; e + x < 1 + >>> e == e # neither side is a literal + True + >>> e == x < 1 # expecting True, too + False + >>> e != x < 1 # expecting False + x < 1 + >>> x < 1 != x < 1 # expecting False or the same thing as before + Traceback (most recent call last): + ... + TypeError: cannot determine truth value of Relational + + The solution for this case is to wrap literal relationals in + parentheses: + + >>> e == (x < 1) + True + >>> e != (x < 1) + False + >>> (x < 1) != (x < 1) + False + + The third gotcha involves chained inequalities not involving + ``==`` or ``!=``. Occasionally, one may be tempted to write: + + >>> e = x < y < z + Traceback (most recent call last): + ... + TypeError: symbolic boolean expression has no truth value. + + Due to an implementation detail or decision of Python [1]_, + there is no way for SymPy to create a chained inequality with + that syntax so one must use And: + + >>> e = And(x < y, y < z) + >>> type( e ) + And + >>> e + (x < y) & (y < z) + + Although this can also be done with the '&' operator, it cannot + be done with the 'and' operarator: + + >>> (x < y) & (y < z) + (x < y) & (y < z) + >>> (x < y) and (y < z) + Traceback (most recent call last): + ... + TypeError: cannot determine truth value of Relational + + .. [1] This implementation detail is that Python provides no reliable + method to determine that a chained inequality is being built. + Chained comparison operators are evaluated pairwise, using "and" + logic (see + https://docs.python.org/3/reference/expressions.html#not-in). This + is done in an efficient way, so that each object being compared + is only evaluated once and the comparison can short-circuit. For + example, ``1 > 2 > 3`` is evaluated by Python as ``(1 > 2) and (2 + > 3)``. The ``and`` operator coerces each side into a bool, + returning the object itself when it short-circuits. The bool of + the --Than operators will raise TypeError on purpose, because + SymPy cannot determine the mathematical ordering of symbolic + expressions. Thus, if we were to compute ``x > y > z``, with + ``x``, ``y``, and ``z`` being Symbols, Python converts the + statement (roughly) into these steps: + + (1) x > y > z + (2) (x > y) and (y > z) + (3) (GreaterThanObject) and (y > z) + (4) (GreaterThanObject.__bool__()) and (y > z) + (5) TypeError + + Because of the ``and`` added at step 2, the statement gets turned into a + weak ternary statement, and the first object's ``__bool__`` method will + raise TypeError. Thus, creating a chained inequality is not possible. + + In Python, there is no way to override the ``and`` operator, or to + control how it short circuits, so it is impossible to make something + like ``x > y > z`` work. There was a PEP to change this, + :pep:`335`, but it was officially closed in March, 2012. + + """ + __slots__ = () + + rel_op = '>=' + + @classmethod + def _eval_fuzzy_relation(cls, lhs, rhs): + return is_ge(lhs, rhs) + + @property + def strict(self): + return Gt(*self.args) + +Ge = GreaterThan + + +class LessThan(_Less): + __doc__ = GreaterThan.__doc__ + __slots__ = () + + rel_op = '<=' + + @classmethod + def _eval_fuzzy_relation(cls, lhs, rhs): + return is_le(lhs, rhs) + + @property + def strict(self): + return Lt(*self.args) + +Le = LessThan + + +class StrictGreaterThan(_Greater): + __doc__ = GreaterThan.__doc__ + __slots__ = () + + rel_op = '>' + + @classmethod + def _eval_fuzzy_relation(cls, lhs, rhs): + return is_gt(lhs, rhs) + + @property + def weak(self): + return Ge(*self.args) + + +Gt = StrictGreaterThan + + +class StrictLessThan(_Less): + __doc__ = GreaterThan.__doc__ + __slots__ = () + + rel_op = '<' + + @classmethod + def _eval_fuzzy_relation(cls, lhs, rhs): + return is_lt(lhs, rhs) + + @property + def weak(self): + return Le(*self.args) + +Lt = StrictLessThan + +# A class-specific (not object-specific) data item used for a minor speedup. +# It is defined here, rather than directly in the class, because the classes +# that it references have not been defined until now (e.g. StrictLessThan). +Relational.ValidRelationOperator = { + None: Equality, + '==': Equality, + 'eq': Equality, + '!=': Unequality, + '<>': Unequality, + 'ne': Unequality, + '>=': GreaterThan, + 'ge': GreaterThan, + '<=': LessThan, + 'le': LessThan, + '>': StrictGreaterThan, + 'gt': StrictGreaterThan, + '<': StrictLessThan, + 'lt': StrictLessThan, +} + + +def _n2(a, b): + """Return (a - b).evalf(2) if a and b are comparable, else None. + This should only be used when a and b are already sympified. + """ + # /!\ it is very important (see issue 8245) not to + # use a re-evaluated number in the calculation of dif + if a.is_comparable and b.is_comparable: + dif = (a - b).evalf(2) + if dif.is_comparable: + return dif + + +@dispatch(Expr, Expr) +def _eval_is_ge(lhs, rhs): + return None + + +@dispatch(Basic, Basic) +def _eval_is_eq(lhs, rhs): + return None + + +@dispatch(Tuple, Expr) # type: ignore +def _eval_is_eq(lhs, rhs): # noqa:F811 + return False + + +@dispatch(Tuple, AppliedUndef) # type: ignore +def _eval_is_eq(lhs, rhs): # noqa:F811 + return None + + +@dispatch(Tuple, Symbol) # type: ignore +def _eval_is_eq(lhs, rhs): # noqa:F811 + return None + + +@dispatch(Tuple, Tuple) # type: ignore +def _eval_is_eq(lhs, rhs): # noqa:F811 + if len(lhs) != len(rhs): + return False + + return fuzzy_and(fuzzy_bool(is_eq(s, o)) for s, o in zip(lhs, rhs)) + + +def is_lt(lhs, rhs, assumptions=None): + """Fuzzy bool for lhs is strictly less than rhs. + + See the docstring for :func:`~.is_ge` for more. + """ + return fuzzy_not(is_ge(lhs, rhs, assumptions)) + + +def is_gt(lhs, rhs, assumptions=None): + """Fuzzy bool for lhs is strictly greater than rhs. + + See the docstring for :func:`~.is_ge` for more. + """ + return fuzzy_not(is_le(lhs, rhs, assumptions)) + + +def is_le(lhs, rhs, assumptions=None): + """Fuzzy bool for lhs is less than or equal to rhs. + + See the docstring for :func:`~.is_ge` for more. + """ + return is_ge(rhs, lhs, assumptions) + + +def is_ge(lhs, rhs, assumptions=None): + """ + Fuzzy bool for *lhs* is greater than or equal to *rhs*. + + Parameters + ========== + + lhs : Expr + The left-hand side of the expression, must be sympified, + and an instance of expression. Throws an exception if + lhs is not an instance of expression. + + rhs : Expr + The right-hand side of the expression, must be sympified + and an instance of expression. Throws an exception if + lhs is not an instance of expression. + + assumptions: Boolean, optional + Assumptions taken to evaluate the inequality. + + Returns + ======= + + ``True`` if *lhs* is greater than or equal to *rhs*, ``False`` if *lhs* + is less than *rhs*, and ``None`` if the comparison between *lhs* and + *rhs* is indeterminate. + + Explanation + =========== + + This function is intended to give a relatively fast determination and + deliberately does not attempt slow calculations that might help in + obtaining a determination of True or False in more difficult cases. + + The four comparison functions ``is_le``, ``is_lt``, ``is_ge``, and ``is_gt`` are + each implemented in terms of ``is_ge`` in the following way: + + is_ge(x, y) := is_ge(x, y) + is_le(x, y) := is_ge(y, x) + is_lt(x, y) := fuzzy_not(is_ge(x, y)) + is_gt(x, y) := fuzzy_not(is_ge(y, x)) + + Therefore, supporting new type with this function will ensure behavior for + other three functions as well. + + To maintain these equivalences in fuzzy logic it is important that in cases where + either x or y is non-real all comparisons will give None. + + Examples + ======== + + >>> from sympy import S, Q + >>> from sympy.core.relational import is_ge, is_le, is_gt, is_lt + >>> from sympy.abc import x + >>> is_ge(S(2), S(0)) + True + >>> is_ge(S(0), S(2)) + False + >>> is_le(S(0), S(2)) + True + >>> is_gt(S(0), S(2)) + False + >>> is_lt(S(2), S(0)) + False + + Assumptions can be passed to evaluate the quality which is otherwise + indeterminate. + + >>> print(is_ge(x, S(0))) + None + >>> is_ge(x, S(0), assumptions=Q.positive(x)) + True + + New types can be supported by dispatching to ``_eval_is_ge``. + + >>> from sympy import Expr, sympify + >>> from sympy.multipledispatch import dispatch + >>> class MyExpr(Expr): + ... def __new__(cls, arg): + ... return super().__new__(cls, sympify(arg)) + ... @property + ... def value(self): + ... return self.args[0] + >>> @dispatch(MyExpr, MyExpr) + ... def _eval_is_ge(a, b): + ... return is_ge(a.value, b.value) + >>> a = MyExpr(1) + >>> b = MyExpr(2) + >>> is_ge(b, a) + True + >>> is_le(a, b) + True + """ + from sympy.assumptions.wrapper import AssumptionsWrapper, is_extended_nonnegative + + if not (isinstance(lhs, Expr) and isinstance(rhs, Expr)): + raise TypeError("Can only compare inequalities with Expr") + + retval = _eval_is_ge(lhs, rhs) + + if retval is not None: + return retval + else: + n2 = _n2(lhs, rhs) + if n2 is not None: + # use float comparison for infinity. + # otherwise get stuck in infinite recursion + if n2 in (S.Infinity, S.NegativeInfinity): + n2 = float(n2) + return n2 >= 0 + + _lhs = AssumptionsWrapper(lhs, assumptions) + _rhs = AssumptionsWrapper(rhs, assumptions) + if _lhs.is_extended_real and _rhs.is_extended_real: + if (_lhs.is_infinite and _lhs.is_extended_positive) or (_rhs.is_infinite and _rhs.is_extended_negative): + return True + diff = lhs - rhs + if diff is not S.NaN: + rv = is_extended_nonnegative(diff, assumptions) + if rv is not None: + return rv + + +def is_neq(lhs, rhs, assumptions=None): + """Fuzzy bool for lhs does not equal rhs. + + See the docstring for :func:`~.is_eq` for more. + """ + return fuzzy_not(is_eq(lhs, rhs, assumptions)) + + +def is_eq(lhs, rhs, assumptions=None): + """ + Fuzzy bool representing mathematical equality between *lhs* and *rhs*. + + Parameters + ========== + + lhs : Expr + The left-hand side of the expression, must be sympified. + + rhs : Expr + The right-hand side of the expression, must be sympified. + + assumptions: Boolean, optional + Assumptions taken to evaluate the equality. + + Returns + ======= + + ``True`` if *lhs* is equal to *rhs*, ``False`` is *lhs* is not equal to *rhs*, + and ``None`` if the comparison between *lhs* and *rhs* is indeterminate. + + Explanation + =========== + + This function is intended to give a relatively fast determination and + deliberately does not attempt slow calculations that might help in + obtaining a determination of True or False in more difficult cases. + + :func:`~.is_neq` calls this function to return its value, so supporting + new type with this function will ensure correct behavior for ``is_neq`` + as well. + + Examples + ======== + + >>> from sympy import Q, S + >>> from sympy.core.relational import is_eq, is_neq + >>> from sympy.abc import x + >>> is_eq(S(0), S(0)) + True + >>> is_neq(S(0), S(0)) + False + >>> is_eq(S(0), S(2)) + False + >>> is_neq(S(0), S(2)) + True + + Assumptions can be passed to evaluate the equality which is otherwise + indeterminate. + + >>> print(is_eq(x, S(0))) + None + >>> is_eq(x, S(0), assumptions=Q.zero(x)) + True + + New types can be supported by dispatching to ``_eval_is_eq``. + + >>> from sympy import Basic, sympify + >>> from sympy.multipledispatch import dispatch + >>> class MyBasic(Basic): + ... def __new__(cls, arg): + ... return Basic.__new__(cls, sympify(arg)) + ... @property + ... def value(self): + ... return self.args[0] + ... + >>> @dispatch(MyBasic, MyBasic) + ... def _eval_is_eq(a, b): + ... return is_eq(a.value, b.value) + ... + >>> a = MyBasic(1) + >>> b = MyBasic(1) + >>> is_eq(a, b) + True + >>> is_neq(a, b) + False + + """ + # here, _eval_Eq is only called for backwards compatibility + # new code should use is_eq with multiple dispatch as + # outlined in the docstring + for side1, side2 in (lhs, rhs), (rhs, lhs): + eval_func = getattr(side1, '_eval_Eq', None) + if eval_func is not None: + retval = eval_func(side2) + if retval is not None: + return retval + + retval = _eval_is_eq(lhs, rhs) + if retval is not None: + return retval + + if dispatch(type(lhs), type(rhs)) != dispatch(type(rhs), type(lhs)): + retval = _eval_is_eq(rhs, lhs) + if retval is not None: + return retval + + # retval is still None, so go through the equality logic + # If expressions have the same structure, they must be equal. + if lhs == rhs: + return True # e.g. True == True + elif all(isinstance(i, BooleanAtom) for i in (rhs, lhs)): + return False # True != False + elif not (lhs.is_Symbol or rhs.is_Symbol) and ( + isinstance(lhs, Boolean) != + isinstance(rhs, Boolean)): + return False # only Booleans can equal Booleans + + from sympy.assumptions.wrapper import (AssumptionsWrapper, + is_infinite, is_extended_real) + from .add import Add + + _lhs = AssumptionsWrapper(lhs, assumptions) + _rhs = AssumptionsWrapper(rhs, assumptions) + + if _lhs.is_infinite or _rhs.is_infinite: + if fuzzy_xor([_lhs.is_infinite, _rhs.is_infinite]): + return False + if fuzzy_xor([_lhs.is_extended_real, _rhs.is_extended_real]): + return False + if fuzzy_and([_lhs.is_extended_real, _rhs.is_extended_real]): + return fuzzy_xor([_lhs.is_extended_positive, fuzzy_not(_rhs.is_extended_positive)]) + + # Try to split real/imaginary parts and equate them + I = S.ImaginaryUnit + + def split_real_imag(expr): + real_imag = lambda t: ( + 'real' if is_extended_real(t, assumptions) else + 'imag' if is_extended_real(I*t, assumptions) else None) + return sift(Add.make_args(expr), real_imag) + + lhs_ri = split_real_imag(lhs) + if not lhs_ri[None]: + rhs_ri = split_real_imag(rhs) + if not rhs_ri[None]: + eq_real = is_eq(Add(*lhs_ri['real']), Add(*rhs_ri['real']), assumptions) + eq_imag = is_eq(I * Add(*lhs_ri['imag']), I * Add(*rhs_ri['imag']), assumptions) + return fuzzy_and(map(fuzzy_bool, [eq_real, eq_imag])) + + from sympy.functions.elementary.complexes import arg + # Compare e.g. zoo with 1+I*oo by comparing args + arglhs = arg(lhs) + argrhs = arg(rhs) + # Guard against Eq(nan, nan) -> False + if not (arglhs == S.NaN and argrhs == S.NaN): + return fuzzy_bool(is_eq(arglhs, argrhs, assumptions)) + + if all(isinstance(i, Expr) for i in (lhs, rhs)): + # see if the difference evaluates + dif = lhs - rhs + _dif = AssumptionsWrapper(dif, assumptions) + z = _dif.is_zero + if z is not None: + if z is False and _dif.is_commutative: # issue 10728 + return False + if z: + return True + + # is_zero cannot help decide integer/rational with Float + c, t = dif.as_coeff_Add() + if c.is_Float: + if int_valued(c): + if t.is_integer is False: + return False + elif t.is_rational is False: + return False + + n2 = _n2(lhs, rhs) + if n2 is not None: + return _sympify(n2 == 0) + + # see if the ratio evaluates + n, d = dif.as_numer_denom() + rv = None + _n = AssumptionsWrapper(n, assumptions) + _d = AssumptionsWrapper(d, assumptions) + if _n.is_zero: + rv = _d.is_nonzero + elif _n.is_finite: + if _d.is_infinite: + rv = True + elif _n.is_zero is False: + rv = _d.is_infinite + if rv is None: + # if the condition that makes the denominator + # infinite does not make the original expression + # True then False can be returned + from sympy.simplify.simplify import clear_coefficients + l, r = clear_coefficients(d, S.Infinity) + args = [_.subs(l, r) for _ in (lhs, rhs)] + if args != [lhs, rhs]: + rv = fuzzy_bool(is_eq(*args, assumptions)) + if rv is True: + rv = None + elif any(is_infinite(a, assumptions) for a in Add.make_args(n)): + # (inf or nan)/x != 0 + rv = False + if rv is not None: + return rv diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/rules.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/rules.py new file mode 100644 index 0000000000000000000000000000000000000000..5ae331f71b21c8a6ef35f499c5c5c89239349e9c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/rules.py @@ -0,0 +1,66 @@ +""" +Replacement rules. +""" + +class Transform: + """ + Immutable mapping that can be used as a generic transformation rule. + + Parameters + ========== + + transform : callable + Computes the value corresponding to any key. + + filter : callable, optional + If supplied, specifies which objects are in the mapping. + + Examples + ======== + + >>> from sympy.core.rules import Transform + >>> from sympy.abc import x + + This Transform will return, as a value, one more than the key: + + >>> add1 = Transform(lambda x: x + 1) + >>> add1[1] + 2 + >>> add1[x] + x + 1 + + By default, all values are considered to be in the dictionary. If a filter + is supplied, only the objects for which it returns True are considered as + being in the dictionary: + + >>> add1_odd = Transform(lambda x: x + 1, lambda x: x%2 == 1) + >>> 2 in add1_odd + False + >>> add1_odd.get(2, 0) + 0 + >>> 3 in add1_odd + True + >>> add1_odd[3] + 4 + >>> add1_odd.get(3, 0) + 4 + """ + + def __init__(self, transform, filter=lambda x: True): + self._transform = transform + self._filter = filter + + def __contains__(self, item): + return self._filter(item) + + def __getitem__(self, key): + if self._filter(key): + return self._transform(key) + else: + raise KeyError(key) + + def get(self, item, default=None): + if item in self: + return self[item] + else: + return default diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/singleton.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/singleton.py new file mode 100644 index 0000000000000000000000000000000000000000..e8b9df959393270140bc3ef11b3d9a4e948c5e80 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/singleton.py @@ -0,0 +1,199 @@ +"""Singleton mechanism""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from .core import Registry +from .sympify import sympify + + +if TYPE_CHECKING: + from sympy.core.numbers import ( + Zero as _Zero, + One as _One, + NegativeOne as _NegativeOne, + Half as _Half, + Infinity as _Infinity, + NegativeInfinity as _NegativeInfinity, + ComplexInfinity as _ComplexInfinity, + NaN as _NaN, + ) + + +class SingletonRegistry(Registry): + """ + The registry for the singleton classes (accessible as ``S``). + + Explanation + =========== + + This class serves as two separate things. + + The first thing it is is the ``SingletonRegistry``. Several classes in + SymPy appear so often that they are singletonized, that is, using some + metaprogramming they are made so that they can only be instantiated once + (see the :class:`sympy.core.singleton.Singleton` class for details). For + instance, every time you create ``Integer(0)``, this will return the same + instance, :class:`sympy.core.numbers.Zero`. All singleton instances are + attributes of the ``S`` object, so ``Integer(0)`` can also be accessed as + ``S.Zero``. + + Singletonization offers two advantages: it saves memory, and it allows + fast comparison. It saves memory because no matter how many times the + singletonized objects appear in expressions in memory, they all point to + the same single instance in memory. The fast comparison comes from the + fact that you can use ``is`` to compare exact instances in Python + (usually, you need to use ``==`` to compare things). ``is`` compares + objects by memory address, and is very fast. + + Examples + ======== + + >>> from sympy import S, Integer + >>> a = Integer(0) + >>> a is S.Zero + True + + For the most part, the fact that certain objects are singletonized is an + implementation detail that users should not need to worry about. In SymPy + library code, ``is`` comparison is often used for performance purposes + The primary advantage of ``S`` for end users is the convenient access to + certain instances that are otherwise difficult to type, like ``S.Half`` + (instead of ``Rational(1, 2)``). + + When using ``is`` comparison, make sure the argument is sympified. For + instance, + + >>> x = 0 + >>> x is S.Zero + False + + This problem is not an issue when using ``==``, which is recommended for + most use-cases: + + >>> 0 == S.Zero + True + + The second thing ``S`` is is a shortcut for + :func:`sympy.core.sympify.sympify`. :func:`sympy.core.sympify.sympify` is + the function that converts Python objects such as ``int(1)`` into SymPy + objects such as ``Integer(1)``. It also converts the string form of an + expression into a SymPy expression, like ``sympify("x**2")`` -> + ``Symbol("x")**2``. ``S(1)`` is the same thing as ``sympify(1)`` + (basically, ``S.__call__`` has been defined to call ``sympify``). + + This is for convenience, since ``S`` is a single letter. It's mostly + useful for defining rational numbers. Consider an expression like ``x + + 1/2``. If you enter this directly in Python, it will evaluate the ``1/2`` + and give ``0.5``, because both arguments are ints (see also + :ref:`tutorial-gotchas-final-notes`). However, in SymPy, you usually want + the quotient of two integers to give an exact rational number. The way + Python's evaluation works, at least one side of an operator needs to be a + SymPy object for the SymPy evaluation to take over. You could write this + as ``x + Rational(1, 2)``, but this is a lot more typing. A shorter + version is ``x + S(1)/2``. Since ``S(1)`` returns ``Integer(1)``, the + division will return a ``Rational`` type, since it will call + ``Integer.__truediv__``, which knows how to return a ``Rational``. + + """ + __slots__ = () + + Zero: _Zero + One: _One + NegativeOne: _NegativeOne + Half: _Half + Infinity: _Infinity + NegativeInfinity: _NegativeInfinity + ComplexInfinity: _ComplexInfinity + NaN: _NaN + + # Also allow things like S(5) + __call__ = staticmethod(sympify) + + def __init__(self): + self._classes_to_install = {} + # Dict of classes that have been registered, but that have not have been + # installed as an attribute of this SingletonRegistry. + # Installation automatically happens at the first attempt to access the + # attribute. + # The purpose of this is to allow registration during class + # initialization during import, but not trigger object creation until + # actual use (which should not happen until after all imports are + # finished). + + def register(self, cls): + # Make sure a duplicate class overwrites the old one + if hasattr(self, cls.__name__): + delattr(self, cls.__name__) + self._classes_to_install[cls.__name__] = cls + + def __getattr__(self, name): + """Python calls __getattr__ if no attribute of that name was installed + yet. + + Explanation + =========== + + This __getattr__ checks whether a class with the requested name was + already registered but not installed; if no, raises an AttributeError. + Otherwise, retrieves the class, calculates its singleton value, installs + it as an attribute of the given name, and unregisters the class.""" + if name not in self._classes_to_install: + raise AttributeError( + "Attribute '%s' was not installed on SymPy registry %s" % ( + name, self)) + class_to_install = self._classes_to_install[name] + value_to_install = class_to_install() + self.__setattr__(name, value_to_install) + del self._classes_to_install[name] + return value_to_install + + def __repr__(self): + return "S" + +S = SingletonRegistry() + + +class Singleton(type): + """ + Metaclass for singleton classes. + + Explanation + =========== + + A singleton class has only one instance which is returned every time the + class is instantiated. Additionally, this instance can be accessed through + the global registry object ``S`` as ``S.``. + + Examples + ======== + + >>> from sympy import S, Basic + >>> from sympy.core.singleton import Singleton + >>> class MySingleton(Basic, metaclass=Singleton): + ... pass + >>> Basic() is Basic() + False + >>> MySingleton() is MySingleton() + True + >>> S.MySingleton is MySingleton() + True + + Notes + ===== + + Instance creation is delayed until the first time the value is accessed. + (SymPy versions before 1.0 would create the instance during class + creation time, which would be prone to import cycles.) + """ + def __init__(cls, *args, **kwargs): + cls._instance = obj = Basic.__new__(cls) + cls.__new__ = lambda cls: obj + cls.__getnewargs__ = lambda obj: () + cls.__getstate__ = lambda obj: None + S.register(cls) + + +# Delayed to avoid cyclic import +from .basic import Basic diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/sorting.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/sorting.py new file mode 100644 index 0000000000000000000000000000000000000000..399a7efa1f6cbe1ebdf6307c14b411df36fc7de0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/sorting.py @@ -0,0 +1,312 @@ +from collections import defaultdict + +from .sympify import sympify, SympifyError +from sympy.utilities.iterables import iterable, uniq + + +__all__ = ['default_sort_key', 'ordered'] + + +def default_sort_key(item, order=None): + """Return a key that can be used for sorting. + + The key has the structure: + + (class_key, (len(args), args), exponent.sort_key(), coefficient) + + This key is supplied by the sort_key routine of Basic objects when + ``item`` is a Basic object or an object (other than a string) that + sympifies to a Basic object. Otherwise, this function produces the + key. + + The ``order`` argument is passed along to the sort_key routine and is + used to determine how the terms *within* an expression are ordered. + (See examples below) ``order`` options are: 'lex', 'grlex', 'grevlex', + and reversed values of the same (e.g. 'rev-lex'). The default order + value is None (which translates to 'lex'). + + Examples + ======== + + >>> from sympy import S, I, default_sort_key, sin, cos, sqrt + >>> from sympy.core.function import UndefinedFunction + >>> from sympy.abc import x + + The following are equivalent ways of getting the key for an object: + + >>> x.sort_key() == default_sort_key(x) + True + + Here are some examples of the key that is produced: + + >>> default_sort_key(UndefinedFunction('f')) + ((0, 0, 'UndefinedFunction'), (1, ('f',)), ((1, 0, 'Number'), + (0, ()), (), 1), 1) + >>> default_sort_key('1') + ((0, 0, 'str'), (1, ('1',)), ((1, 0, 'Number'), (0, ()), (), 1), 1) + >>> default_sort_key(S.One) + ((1, 0, 'Number'), (0, ()), (), 1) + >>> default_sort_key(2) + ((1, 0, 'Number'), (0, ()), (), 2) + + While sort_key is a method only defined for SymPy objects, + default_sort_key will accept anything as an argument so it is + more robust as a sorting key. For the following, using key= + lambda i: i.sort_key() would fail because 2 does not have a sort_key + method; that's why default_sort_key is used. Note, that it also + handles sympification of non-string items likes ints: + + >>> a = [2, I, -I] + >>> sorted(a, key=default_sort_key) + [2, -I, I] + + The returned key can be used anywhere that a key can be specified for + a function, e.g. sort, min, max, etc...: + + >>> a.sort(key=default_sort_key); a[0] + 2 + >>> min(a, key=default_sort_key) + 2 + + Notes + ===== + + The key returned is useful for getting items into a canonical order + that will be the same across platforms. It is not directly useful for + sorting lists of expressions: + + >>> a, b = x, 1/x + + Since ``a`` has only 1 term, its value of sort_key is unaffected by + ``order``: + + >>> a.sort_key() == a.sort_key('rev-lex') + True + + If ``a`` and ``b`` are combined then the key will differ because there + are terms that can be ordered: + + >>> eq = a + b + >>> eq.sort_key() == eq.sort_key('rev-lex') + False + >>> eq.as_ordered_terms() + [x, 1/x] + >>> eq.as_ordered_terms('rev-lex') + [1/x, x] + + But since the keys for each of these terms are independent of ``order``'s + value, they do not sort differently when they appear separately in a list: + + >>> sorted(eq.args, key=default_sort_key) + [1/x, x] + >>> sorted(eq.args, key=lambda i: default_sort_key(i, order='rev-lex')) + [1/x, x] + + The order of terms obtained when using these keys is the order that would + be obtained if those terms were *factors* in a product. + + Although it is useful for quickly putting expressions in canonical order, + it does not sort expressions based on their complexity defined by the + number of operations, power of variables and others: + + >>> sorted([sin(x)*cos(x), sin(x)], key=default_sort_key) + [sin(x)*cos(x), sin(x)] + >>> sorted([x, x**2, sqrt(x), x**3], key=default_sort_key) + [sqrt(x), x, x**2, x**3] + + See Also + ======== + + ordered, sympy.core.expr.Expr.as_ordered_factors, sympy.core.expr.Expr.as_ordered_terms + + """ + from .basic import Basic + from .singleton import S + + if isinstance(item, Basic): + return item.sort_key(order=order) + + if iterable(item, exclude=str): + if isinstance(item, dict): + args = item.items() + unordered = True + elif isinstance(item, set): + args = item + unordered = True + else: + # e.g. tuple, list + args = list(item) + unordered = False + + args = [default_sort_key(arg, order=order) for arg in args] + + if unordered: + # e.g. dict, set + args = sorted(args) + + cls_index, args = 10, (len(args), tuple(args)) + else: + if not isinstance(item, str): + try: + item = sympify(item, strict=True) + except SympifyError: + # e.g. lambda x: x + pass + else: + if isinstance(item, Basic): + # e.g int -> Integer + return default_sort_key(item) + # e.g. UndefinedFunction + + # e.g. str + cls_index, args = 0, (1, (str(item),)) + + return (cls_index, 0, item.__class__.__name__ + ), args, S.One.sort_key(), S.One + + +def _node_count(e): + # this not only counts nodes, it affirms that the + # args are Basic (i.e. have an args property). If + # some object has a non-Basic arg, it needs to be + # fixed since it is intended that all Basic args + # are of Basic type (though this is not easy to enforce). + if e.is_Float: + return 0.5 + return 1 + sum(map(_node_count, e.args)) + + +def _nodes(e): + """ + A helper for ordered() which returns the node count of ``e`` which + for Basic objects is the number of Basic nodes in the expression tree + but for other objects is 1 (unless the object is an iterable or dict + for which the sum of nodes is returned). + """ + from .basic import Basic + from .function import Derivative + + if isinstance(e, Basic): + if isinstance(e, Derivative): + return _nodes(e.expr) + sum(i[1] if i[1].is_Number else + _nodes(i[1]) for i in e.variable_count) + return _node_count(e) + elif iterable(e): + return 1 + sum(_nodes(ei) for ei in e) + elif isinstance(e, dict): + return 1 + sum(_nodes(k) + _nodes(v) for k, v in e.items()) + else: + return 1 + + +def ordered(seq, keys=None, default=True, warn=False): + """Return an iterator of the seq where keys are used to break ties + in a conservative fashion: if, after applying a key, there are no + ties then no other keys will be computed. + + Two default keys will be applied if 1) keys are not provided or + 2) the given keys do not resolve all ties (but only if ``default`` + is True). The two keys are ``_nodes`` (which places smaller + expressions before large) and ``default_sort_key`` which (if the + ``sort_key`` for an object is defined properly) should resolve + any ties. This strategy is similar to sorting done by + ``Basic.compare``, but differs in that ``ordered`` never makes a + decision based on an objects name. + + If ``warn`` is True then an error will be raised if there were no + keys remaining to break ties. This can be used if it was expected that + there should be no ties between items that are not identical. + + Examples + ======== + + >>> from sympy import ordered, count_ops + >>> from sympy.abc import x, y + + The count_ops is not sufficient to break ties in this list and the first + two items appear in their original order (i.e. the sorting is stable): + + >>> list(ordered([y + 2, x + 2, x**2 + y + 3], + ... count_ops, default=False, warn=False)) + ... + [y + 2, x + 2, x**2 + y + 3] + + The default_sort_key allows the tie to be broken: + + >>> list(ordered([y + 2, x + 2, x**2 + y + 3])) + ... + [x + 2, y + 2, x**2 + y + 3] + + Here, sequences are sorted by length, then sum: + + >>> seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]], [ + ... lambda x: len(x), + ... lambda x: sum(x)]] + ... + >>> list(ordered(seq, keys, default=False, warn=False)) + [[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]] + + If ``warn`` is True, an error will be raised if there were not + enough keys to break ties: + + >>> list(ordered(seq, keys, default=False, warn=True)) + Traceback (most recent call last): + ... + ValueError: not enough keys to break ties + + + Notes + ===== + + The decorated sort is one of the fastest ways to sort a sequence for + which special item comparison is desired: the sequence is decorated, + sorted on the basis of the decoration (e.g. making all letters lower + case) and then undecorated. If one wants to break ties for items that + have the same decorated value, a second key can be used. But if the + second key is expensive to compute then it is inefficient to decorate + all items with both keys: only those items having identical first key + values need to be decorated. This function applies keys successively + only when needed to break ties. By yielding an iterator, use of the + tie-breaker is delayed as long as possible. + + This function is best used in cases when use of the first key is + expected to be a good hashing function; if there are no unique hashes + from application of a key, then that key should not have been used. The + exception, however, is that even if there are many collisions, if the + first group is small and one does not need to process all items in the + list then time will not be wasted sorting what one was not interested + in. For example, if one were looking for the minimum in a list and + there were several criteria used to define the sort order, then this + function would be good at returning that quickly if the first group + of candidates is small relative to the number of items being processed. + + """ + + d = defaultdict(list) + if keys: + if isinstance(keys, (list, tuple)): + keys = list(keys) + f = keys.pop(0) + else: + f = keys + keys = [] + for a in seq: + d[f(a)].append(a) + else: + if not default: + raise ValueError('if default=False then keys must be provided') + d[None].extend(seq) + + for k, value in sorted(d.items()): + if len(value) > 1: + if keys: + value = ordered(value, keys, default, warn) + elif default: + value = ordered(value, (_nodes, default_sort_key,), + default=False, warn=warn) + elif warn: + u = list(uniq(value)) + if len(u) > 1: + raise ValueError( + 'not enough keys to break ties: %s' % u) + yield from value diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/symbol.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/symbol.py new file mode 100644 index 0000000000000000000000000000000000000000..2e03ff0c84c1668b70ec5b3d7f8bc854a2e5e4ac --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/symbol.py @@ -0,0 +1,993 @@ +from __future__ import annotations + + +from .assumptions import StdFactKB, _assume_defined +from .basic import Basic, Atom +from .cache import cacheit +from .containers import Tuple +from .expr import Expr, AtomicExpr +from .function import AppliedUndef, FunctionClass +from .kind import NumberKind, UndefinedKind +from .logic import fuzzy_bool +from .singleton import S +from .sorting import ordered +from .sympify import sympify +from sympy.logic.boolalg import Boolean +from sympy.utilities.iterables import sift, is_sequence +from sympy.utilities.misc import filldedent + +import string +import re as _re +import random +from itertools import product +from typing import Any + + +class Str(Atom): + """ + Represents string in SymPy. + + Explanation + =========== + + Previously, ``Symbol`` was used where string is needed in ``args`` of SymPy + objects, e.g. denoting the name of the instance. However, since ``Symbol`` + represents mathematical scalar, this class should be used instead. + + """ + __slots__ = ('name',) + + def __new__(cls, name, **kwargs): + if not isinstance(name, str): + raise TypeError("name should be a string, not %s" % repr(type(name))) + obj = Expr.__new__(cls, **kwargs) + obj.name = name + return obj + + def __getnewargs__(self): + return (self.name,) + + def _hashable_content(self): + return (self.name,) + + +def _filter_assumptions(kwargs): + """Split the given dict into assumptions and non-assumptions. + Keys are taken as assumptions if they correspond to an + entry in ``_assume_defined``. + """ + assumptions, nonassumptions = map(dict, sift(kwargs.items(), + lambda i: i[0] in _assume_defined, + binary=True)) + Symbol._sanitize(assumptions) + return assumptions, nonassumptions + +def _symbol(s, matching_symbol=None, **assumptions): + """Return s if s is a Symbol, else if s is a string, return either + the matching_symbol if the names are the same or else a new symbol + with the same assumptions as the matching symbol (or the + assumptions as provided). + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.core.symbol import _symbol + >>> _symbol('y') + y + >>> _.is_real is None + True + >>> _symbol('y', real=True).is_real + True + + >>> x = Symbol('x') + >>> _symbol(x, real=True) + x + >>> _.is_real is None # ignore attribute if s is a Symbol + True + + Below, the variable sym has the name 'foo': + + >>> sym = Symbol('foo', real=True) + + Since 'x' is not the same as sym's name, a new symbol is created: + + >>> _symbol('x', sym).name + 'x' + + It will acquire any assumptions give: + + >>> _symbol('x', sym, real=False).is_real + False + + Since 'foo' is the same as sym's name, sym is returned + + >>> _symbol('foo', sym) + foo + + Any assumptions given are ignored: + + >>> _symbol('foo', sym, real=False).is_real + True + + NB: the symbol here may not be the same as a symbol with the same + name defined elsewhere as a result of different assumptions. + + See Also + ======== + + sympy.core.symbol.Symbol + + """ + if isinstance(s, str): + if matching_symbol and matching_symbol.name == s: + return matching_symbol + return Symbol(s, **assumptions) + elif isinstance(s, Symbol): + return s + else: + raise ValueError('symbol must be string for symbol name or Symbol') + +def uniquely_named_symbol(xname, exprs=(), compare=str, modify=None, **assumptions): + """ + Return a symbol whose name is derivated from *xname* but is unique + from any other symbols in *exprs*. + + *xname* and symbol names in *exprs* are passed to *compare* to be + converted to comparable forms. If ``compare(xname)`` is not unique, + it is recursively passed to *modify* until unique name is acquired. + + Parameters + ========== + + xname : str or Symbol + Base name for the new symbol. + + exprs : Expr or iterable of Expr + Expressions whose symbols are compared to *xname*. + + compare : function + Unary function which transforms *xname* and symbol names from + *exprs* to comparable form. + + modify : function + Unary function which modifies the string. Default is appending + the number, or increasing the number if exists. + + Examples + ======== + + By default, a number is appended to *xname* to generate unique name. + If the number already exists, it is recursively increased. + + >>> from sympy.core.symbol import uniquely_named_symbol, Symbol + >>> uniquely_named_symbol('x', Symbol('x')) + x0 + >>> uniquely_named_symbol('x', (Symbol('x'), Symbol('x0'))) + x1 + >>> uniquely_named_symbol('x0', (Symbol('x1'), Symbol('x0'))) + x2 + + Name generation can be controlled by passing *modify* parameter. + + >>> from sympy.abc import x + >>> uniquely_named_symbol('x', x, modify=lambda s: 2*s) + xx + + """ + def numbered_string_incr(s, start=0): + if not s: + return str(start) + i = len(s) - 1 + while i != -1: + if not s[i].isdigit(): + break + i -= 1 + n = str(int(s[i + 1:] or start - 1) + 1) + return s[:i + 1] + n + + default = None + if is_sequence(xname): + xname, default = xname + x = compare(xname) + if not exprs: + return _symbol(x, default, **assumptions) + if not is_sequence(exprs): + exprs = [exprs] + names = set().union( + [i.name for e in exprs for i in e.atoms(Symbol)] + + [i.func.name for e in exprs for i in e.atoms(AppliedUndef)]) + if modify is None: + modify = numbered_string_incr + while any(x == compare(s) for s in names): + x = modify(x) + return _symbol(x, default, **assumptions) +_uniquely_named_symbol = uniquely_named_symbol + + +# XXX: We need type: ignore below because Expr and Boolean are incompatible as +# superclasses. Really Symbol should not be a subclass of Boolean. + + +class Symbol(AtomicExpr, Boolean): # type: ignore + """ + Symbol class is used to create symbolic variables. + + Explanation + =========== + + Symbolic variables are placeholders for mathematical symbols that can represent numbers, constants, or any other mathematical entities and can be used in mathematical expressions and to perform symbolic computations. + + Assumptions: + + commutative = True + positive = True + real = True + imaginary = True + complex = True + complete list of more assumptions- :ref:`predicates` + + You can override the default assumptions in the constructor. + + Examples + ======== + + >>> from sympy import Symbol + >>> x = Symbol("x", positive=True) + >>> x.is_positive + True + >>> x.is_negative + False + + passing in greek letters: + + >>> from sympy import Symbol + >>> alpha = Symbol('alpha') + >>> alpha #doctest: +SKIP + α + + Trailing digits are automatically treated like subscripts of what precedes them in the name. + General format to add subscript to a symbol : + `` = Symbol('_')`` + + >>> from sympy import Symbol + >>> alpha_i = Symbol('alpha_i') + >>> alpha_i #doctest: +SKIP + αᵢ + + Parameters + ========== + + AtomicExpr: variable name + Boolean: Assumption with a boolean value(True or False) + """ + + is_comparable = False + + __slots__ = ('name', '_assumptions_orig', '_assumptions0') + + name: str + + is_Symbol = True + is_symbol = True + + @property + def kind(self): + if self.is_commutative: + return NumberKind + return UndefinedKind + + @property + def _diff_wrt(self): + """Allow derivatives wrt Symbols. + + Examples + ======== + + >>> from sympy import Symbol + >>> x = Symbol('x') + >>> x._diff_wrt + True + """ + return True + + @staticmethod + def _sanitize(assumptions, obj=None): + """Remove None, convert values to bool, check commutativity *in place*. + """ + + # be strict about commutativity: cannot be None + is_commutative = fuzzy_bool(assumptions.get('commutative', True)) + if is_commutative is None: + whose = '%s ' % obj.__name__ if obj else '' + raise ValueError( + '%scommutativity must be True or False.' % whose) + + # sanitize other assumptions so 1 -> True and 0 -> False + for key in list(assumptions.keys()): + v = assumptions[key] + if v is None: + assumptions.pop(key) + continue + assumptions[key] = bool(v) + + def _merge(self, assumptions): + base = self.assumptions0 + for k in set(assumptions) & set(base): + if assumptions[k] != base[k]: + raise ValueError(filldedent(''' + non-matching assumptions for %s: existing value + is %s and new value is %s''' % ( + k, base[k], assumptions[k]))) + base.update(assumptions) + return base + + def __new__(cls, name, **assumptions): + """Symbols are identified by name and assumptions:: + + >>> from sympy import Symbol + >>> Symbol("x") == Symbol("x") + True + >>> Symbol("x", real=True) == Symbol("x", real=False) + False + + """ + cls._sanitize(assumptions, cls) + return Symbol.__xnew_cached_(cls, name, **assumptions) + + + @staticmethod + @cacheit + def _canonical_assumptions(**assumptions): + # This is retained purely so that srepr can include commutative=True if + # that was explicitly specified but not if it was not. Ideally srepr + # should not distinguish these cases because the symbols otherwise + # compare equal and are considered equivalent. + # + # See https://github.com/sympy/sympy/issues/8873 + # + assumptions_orig = assumptions.copy() + + # The only assumption that is assumed by default is commutative=True: + assumptions.setdefault('commutative', True) + + assumptions_kb = StdFactKB(assumptions) + assumptions0 = dict(assumptions_kb) + + return assumptions_kb, assumptions_orig, assumptions0 + + @staticmethod + def __xnew__(cls, name, **assumptions): # never cached (e.g. dummy) + if not isinstance(name, str): + raise TypeError("name should be a string, not %s" % repr(type(name))) + + + obj = Expr.__new__(cls) + obj.name = name + + assumptions_kb, assumptions_orig, assumptions0 = Symbol._canonical_assumptions(**assumptions) + + obj._assumptions = assumptions_kb + obj._assumptions_orig = assumptions_orig + obj._assumptions0 = tuple(sorted(assumptions0.items())) + + # The three assumptions dicts are all a little different: + # + # >>> from sympy import Symbol + # >>> x = Symbol('x', finite=True) + # >>> x.is_positive # query an assumption + # >>> x._assumptions + # {'finite': True, 'infinite': False, 'commutative': True, 'positive': None} + # >>> x._assumptions0 + # {'finite': True, 'infinite': False, 'commutative': True} + # >>> x._assumptions_orig + # {'finite': True} + # + # Two symbols with the same name are equal if their _assumptions0 are + # the same. Arguably it should be _assumptions_orig that is being + # compared because that is more transparent to the user (it is + # what was passed to the constructor modulo changes made by _sanitize). + + return obj + + @staticmethod + @cacheit + def __xnew_cached_(cls, name, **assumptions): # symbols are always cached + return Symbol.__xnew__(cls, name, **assumptions) + + def __getnewargs_ex__(self): + return ((self.name,), self._assumptions_orig) + + # NOTE: __setstate__ is not needed for pickles created by __getnewargs_ex__ + # but was used before Symbol was changed to use __getnewargs_ex__ in v1.9. + # Pickles created in previous SymPy versions will still need __setstate__ + # so that they can be unpickled in SymPy > v1.9. + + def __setstate__(self, state): + for name, value in state.items(): + setattr(self, name, value) + + def _hashable_content(self): + return (self.name,) + self._assumptions0 + + def _eval_subs(self, old, new): + if old.is_Pow: + from sympy.core.power import Pow + return Pow(self, S.One, evaluate=False)._eval_subs(old, new) + + def _eval_refine(self, assumptions): + return self + + @property + def assumptions0(self): + return dict(self._assumptions0) + + @cacheit + def sort_key(self, order=None): + return self.class_key(), (1, (self.name,)), S.One.sort_key(), S.One + + def as_dummy(self): + # only put commutativity in explicitly if it is False + return Dummy(self.name) if self.is_commutative is not False \ + else Dummy(self.name, commutative=self.is_commutative) + + def as_real_imag(self, deep=True, **hints): + if hints.get('ignore') == self: + return None + else: + from sympy.functions.elementary.complexes import im, re + return (re(self), im(self)) + + def is_constant(self, *wrt, **flags): + if not wrt: + return False + return self not in wrt + + @property + def free_symbols(self): + return {self} + + binary_symbols = free_symbols # in this case, not always + + def as_set(self): + return S.UniversalSet + + +class Dummy(Symbol): + """Dummy symbols are each unique, even if they have the same name: + + Examples + ======== + + >>> from sympy import Dummy + >>> Dummy("x") == Dummy("x") + False + + If a name is not supplied then a string value of an internal count will be + used. This is useful when a temporary variable is needed and the name + of the variable used in the expression is not important. + + >>> Dummy() #doctest: +SKIP + _Dummy_10 + + """ + + # In the rare event that a Dummy object needs to be recreated, both the + # `name` and `dummy_index` should be passed. This is used by `srepr` for + # example: + # >>> d1 = Dummy() + # >>> d2 = eval(srepr(d1)) + # >>> d2 == d1 + # True + # + # If a new session is started between `srepr` and `eval`, there is a very + # small chance that `d2` will be equal to a previously-created Dummy. + + _count = 0 + _prng = random.Random() + _base_dummy_index = _prng.randint(10**6, 9*10**6) + + __slots__ = ('dummy_index',) + + is_Dummy = True + + def __new__(cls, name=None, dummy_index=None, **assumptions): + if dummy_index is not None: + assert name is not None, "If you specify a dummy_index, you must also provide a name" + + if name is None: + name = "Dummy_" + str(Dummy._count) + + if dummy_index is None: + dummy_index = Dummy._base_dummy_index + Dummy._count + Dummy._count += 1 + + cls._sanitize(assumptions, cls) + obj = Symbol.__xnew__(cls, name, **assumptions) + + obj.dummy_index = dummy_index + + return obj + + def __getnewargs_ex__(self): + return ((self.name, self.dummy_index), self._assumptions_orig) + + @cacheit + def sort_key(self, order=None): + return self.class_key(), ( + 2, (self.name, self.dummy_index)), S.One.sort_key(), S.One + + def _hashable_content(self): + return Symbol._hashable_content(self) + (self.dummy_index,) + + +class Wild(Symbol): + """ + A Wild symbol matches anything, or anything + without whatever is explicitly excluded. + + Parameters + ========== + + name : str + Name of the Wild instance. + + exclude : iterable, optional + Instances in ``exclude`` will not be matched. + + properties : iterable of functions, optional + Functions, each taking an expressions as input + and returns a ``bool``. All functions in ``properties`` + need to return ``True`` in order for the Wild instance + to match the expression. + + Examples + ======== + + >>> from sympy import Wild, WildFunction, cos, pi + >>> from sympy.abc import x, y, z + >>> a = Wild('a') + >>> x.match(a) + {a_: x} + >>> pi.match(a) + {a_: pi} + >>> (3*x**2).match(a*x) + {a_: 3*x} + >>> cos(x).match(a) + {a_: cos(x)} + >>> b = Wild('b', exclude=[x]) + >>> (3*x**2).match(b*x) + >>> b.match(a) + {a_: b_} + >>> A = WildFunction('A') + >>> A.match(a) + {a_: A_} + + Tips + ==== + + When using Wild, be sure to use the exclude + keyword to make the pattern more precise. + Without the exclude pattern, you may get matches + that are technically correct, but not what you + wanted. For example, using the above without + exclude: + + >>> from sympy import symbols + >>> a, b = symbols('a b', cls=Wild) + >>> (2 + 3*y).match(a*x + b*y) + {a_: 2/x, b_: 3} + + This is technically correct, because + (2/x)*x + 3*y == 2 + 3*y, but you probably + wanted it to not match at all. The issue is that + you really did not want a and b to include x and y, + and the exclude parameter lets you specify exactly + this. With the exclude parameter, the pattern will + not match. + + >>> a = Wild('a', exclude=[x, y]) + >>> b = Wild('b', exclude=[x, y]) + >>> (2 + 3*y).match(a*x + b*y) + + Exclude also helps remove ambiguity from matches. + + >>> E = 2*x**3*y*z + >>> a, b = symbols('a b', cls=Wild) + >>> E.match(a*b) + {a_: 2*y*z, b_: x**3} + >>> a = Wild('a', exclude=[x, y]) + >>> E.match(a*b) + {a_: z, b_: 2*x**3*y} + >>> a = Wild('a', exclude=[x, y, z]) + >>> E.match(a*b) + {a_: 2, b_: x**3*y*z} + + Wild also accepts a ``properties`` parameter: + + >>> a = Wild('a', properties=[lambda k: k.is_Integer]) + >>> E.match(a*b) + {a_: 2, b_: x**3*y*z} + + """ + is_Wild = True + + __slots__ = ('exclude', 'properties') + + def __new__(cls, name, exclude=(), properties=(), **assumptions): + exclude = tuple([sympify(x) for x in exclude]) + properties = tuple(properties) + cls._sanitize(assumptions, cls) + return Wild.__xnew__(cls, name, exclude, properties, **assumptions) + + def __getnewargs__(self): + return (self.name, self.exclude, self.properties) + + @staticmethod + @cacheit + def __xnew__(cls, name, exclude, properties, **assumptions): + obj = Symbol.__xnew__(cls, name, **assumptions) + obj.exclude = exclude + obj.properties = properties + return obj + + def _hashable_content(self): + return super()._hashable_content() + (self.exclude, self.properties) + + # TODO add check against another Wild + def matches(self, expr, repl_dict=None, old=False): + if any(expr.has(x) for x in self.exclude): + return None + if not all(f(expr) for f in self.properties): + return None + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + repl_dict[self] = expr + return repl_dict + + +_range = _re.compile('([0-9]*:[0-9]+|[a-zA-Z]?:[a-zA-Z])') + + +def symbols(names, *, cls=Symbol, **args) -> Any: + r""" + Transform strings into instances of :class:`Symbol` class. + + :func:`symbols` function returns a sequence of symbols with names taken + from ``names`` argument, which can be a comma or whitespace delimited + string, or a sequence of strings:: + + >>> from sympy import symbols, Function + + >>> x, y, z = symbols('x,y,z') + >>> a, b, c = symbols('a b c') + + The type of output is dependent on the properties of input arguments:: + + >>> symbols('x') + x + >>> symbols('x,') + (x,) + >>> symbols('x,y') + (x, y) + >>> symbols(('a', 'b', 'c')) + (a, b, c) + >>> symbols(['a', 'b', 'c']) + [a, b, c] + >>> symbols({'a', 'b', 'c'}) + {a, b, c} + + If an iterable container is needed for a single symbol, set the ``seq`` + argument to ``True`` or terminate the symbol name with a comma:: + + >>> symbols('x', seq=True) + (x,) + + To reduce typing, range syntax is supported to create indexed symbols. + Ranges are indicated by a colon and the type of range is determined by + the character to the right of the colon. If the character is a digit + then all contiguous digits to the left are taken as the nonnegative + starting value (or 0 if there is no digit left of the colon) and all + contiguous digits to the right are taken as 1 greater than the ending + value:: + + >>> symbols('x:10') + (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) + + >>> symbols('x5:10') + (x5, x6, x7, x8, x9) + >>> symbols('x5(:2)') + (x50, x51) + + >>> symbols('x5:10,y:5') + (x5, x6, x7, x8, x9, y0, y1, y2, y3, y4) + + >>> symbols(('x5:10', 'y:5')) + ((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4)) + + If the character to the right of the colon is a letter, then the single + letter to the left (or 'a' if there is none) is taken as the start + and all characters in the lexicographic range *through* the letter to + the right are used as the range:: + + >>> symbols('x:z') + (x, y, z) + >>> symbols('x:c') # null range + () + >>> symbols('x(:c)') + (xa, xb, xc) + + >>> symbols(':c') + (a, b, c) + + >>> symbols('a:d, x:z') + (a, b, c, d, x, y, z) + + >>> symbols(('a:d', 'x:z')) + ((a, b, c, d), (x, y, z)) + + Multiple ranges are supported; contiguous numerical ranges should be + separated by parentheses to disambiguate the ending number of one + range from the starting number of the next:: + + >>> symbols('x:2(1:3)') + (x01, x02, x11, x12) + >>> symbols(':3:2') # parsing is from left to right + (00, 01, 10, 11, 20, 21) + + Only one pair of parentheses surrounding ranges are removed, so to + include parentheses around ranges, double them. And to include spaces, + commas, or colons, escape them with a backslash:: + + >>> symbols('x((a:b))') + (x(a), x(b)) + >>> symbols(r'x(:1\,:2)') # or r'x((:1)\,(:2))' + (x(0,0), x(0,1)) + + All newly created symbols have assumptions set according to ``args``:: + + >>> a = symbols('a', integer=True) + >>> a.is_integer + True + + >>> x, y, z = symbols('x,y,z', real=True) + >>> x.is_real and y.is_real and z.is_real + True + + Despite its name, :func:`symbols` can create symbol-like objects like + instances of Function or Wild classes. To achieve this, set ``cls`` + keyword argument to the desired type:: + + >>> symbols('f,g,h', cls=Function) + (f, g, h) + + >>> type(_[0]) + + + """ + result = [] + + if isinstance(names, str): + marker = 0 + splitters = r'\,', r'\:', r'\ ' + literals: list[tuple[str, str]] = [] + for splitter in splitters: + if splitter in names: + while chr(marker) in names: + marker += 1 + lit_char = chr(marker) + marker += 1 + names = names.replace(splitter, lit_char) + literals.append((lit_char, splitter[1:])) + def literal(s): + if literals: + for c, l in literals: + s = s.replace(c, l) + return s + + names = names.strip() + as_seq = names.endswith(',') + if as_seq: + names = names[:-1].rstrip() + if not names: + raise ValueError('no symbols given') + + # split on commas + names = [n.strip() for n in names.split(',')] + if not all(n for n in names): + raise ValueError('missing symbol between commas') + # split on spaces + for i in range(len(names) - 1, -1, -1): + names[i: i + 1] = names[i].split() + + seq = args.pop('seq', as_seq) + + for name in names: + if not name: + raise ValueError('missing symbol') + + if ':' not in name: + symbol = cls(literal(name), **args) + result.append(symbol) + continue + + split: list[str] = _range.split(name) + split_list: list[list[str]] = [] + # remove 1 layer of bounding parentheses around ranges + for i in range(len(split) - 1): + if i and ':' in split[i] and split[i] != ':' and \ + split[i - 1].endswith('(') and \ + split[i + 1].startswith(')'): + split[i - 1] = split[i - 1][:-1] + split[i + 1] = split[i + 1][1:] + for s in split: + if ':' in s: + if s.endswith(':'): + raise ValueError('missing end range') + a, b = s.split(':') + if b[-1] in string.digits: + a_i = 0 if not a else int(a) + b_i = int(b) + split_list.append([str(c) for c in range(a_i, b_i)]) + else: + a = a or 'a' + split_list.append([string.ascii_letters[c] for c in range( + string.ascii_letters.index(a), + string.ascii_letters.index(b) + 1)]) # inclusive + if not split_list[-1]: + break + else: + split_list.append([s]) + else: + seq = True + if len(split_list) == 1: + names = split_list[0] + else: + names = [''.join(s) for s in product(*split_list)] + if literals: + result.extend([cls(literal(s), **args) for s in names]) + else: + result.extend([cls(s, **args) for s in names]) + + if not seq and len(result) <= 1: + if not result: + return () + return result[0] + + return tuple(result) + else: + for name in names: + result.append(symbols(name, cls=cls, **args)) + + return type(names)(result) + + +def var(names, **args): + """ + Create symbols and inject them into the global namespace. + + Explanation + =========== + + This calls :func:`symbols` with the same arguments and puts the results + into the *global* namespace. It's recommended not to use :func:`var` in + library code, where :func:`symbols` has to be used:: + + Examples + ======== + + >>> from sympy import var + + >>> var('x') + x + >>> x # noqa: F821 + x + + >>> var('a,ab,abc') + (a, ab, abc) + >>> abc # noqa: F821 + abc + + >>> var('x,y', real=True) + (x, y) + >>> x.is_real and y.is_real # noqa: F821 + True + + See :func:`symbols` documentation for more details on what kinds of + arguments can be passed to :func:`var`. + + """ + def traverse(symbols, frame): + """Recursively inject symbols to the global namespace. """ + for symbol in symbols: + if isinstance(symbol, Basic): + frame.f_globals[symbol.name] = symbol + elif isinstance(symbol, FunctionClass): + frame.f_globals[symbol.__name__] = symbol + else: + traverse(symbol, frame) + + from inspect import currentframe + frame = currentframe().f_back + + try: + syms = symbols(names, **args) + + if syms is not None: + if isinstance(syms, Basic): + frame.f_globals[syms.name] = syms + elif isinstance(syms, FunctionClass): + frame.f_globals[syms.__name__] = syms + else: + traverse(syms, frame) + finally: + del frame # break cyclic dependencies as stated in inspect docs + + return syms + +def disambiguate(*iter): + """ + Return a Tuple containing the passed expressions with symbols + that appear the same when printed replaced with numerically + subscripted symbols, and all Dummy symbols replaced with Symbols. + + Parameters + ========== + + iter: list of symbols or expressions. + + Examples + ======== + + >>> from sympy.core.symbol import disambiguate + >>> from sympy import Dummy, Symbol, Tuple + >>> from sympy.abc import y + + >>> tup = Symbol('_x'), Dummy('x'), Dummy('x') + >>> disambiguate(*tup) + (x_2, x, x_1) + + >>> eqs = Tuple(Symbol('x')/y, Dummy('x')/y) + >>> disambiguate(*eqs) + (x_1/y, x/y) + + >>> ix = Symbol('x', integer=True) + >>> vx = Symbol('x') + >>> disambiguate(vx + ix) + (x + x_1,) + + To make your own mapping of symbols to use, pass only the free symbols + of the expressions and create a dictionary: + + >>> free = eqs.free_symbols + >>> mapping = dict(zip(free, disambiguate(*free))) + >>> eqs.xreplace(mapping) + (x_1/y, x/y) + + """ + new_iter = Tuple(*iter) + key = lambda x:tuple(sorted(x.assumptions0.items())) + syms = ordered(new_iter.free_symbols, keys=key) + mapping = {} + for s in syms: + mapping.setdefault(str(s).lstrip('_'), []).append(s) + reps = {} + for k in mapping: + # the first or only symbol doesn't get subscripted but make + # sure that it's a Symbol, not a Dummy + mapk0 = Symbol("%s" % (k), **mapping[k][0].assumptions0) + if mapping[k][0] != mapk0: + reps[mapping[k][0]] = mapk0 + # the others get subscripts (and are made into Symbols) + skip = 0 + for i in range(1, len(mapping[k])): + while True: + name = "%s_%i" % (k, i + skip) + if name not in mapping: + break + skip += 1 + ki = mapping[k][i] + reps[ki] = Symbol(name, **ki.assumptions0) + return new_iter.xreplace(reps) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/sympify.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/sympify.py new file mode 100644 index 0000000000000000000000000000000000000000..df30fbb85d5f160540312de4eef1d0e6702fc974 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/sympify.py @@ -0,0 +1,646 @@ +"""sympify -- convert objects SymPy internal format""" + +from __future__ import annotations + +from typing import Any, Callable, overload, TYPE_CHECKING, TypeVar + +import mpmath.libmp as mlib + +from inspect import getmro +import string +from sympy.core.random import choice + +from .parameters import global_parameters + +from sympy.utilities.iterables import iterable + + +if TYPE_CHECKING: + + from sympy.core.basic import Basic + from sympy.core.expr import Expr + from sympy.core.numbers import Integer, Float + + Tbasic = TypeVar('Tbasic', bound=Basic) + + +class SympifyError(ValueError): + def __init__(self, expr, base_exc=None): + self.expr = expr + self.base_exc = base_exc + + def __str__(self): + if self.base_exc is None: + return "SympifyError: %r" % (self.expr,) + + return ("Sympify of expression '%s' failed, because of exception being " + "raised:\n%s: %s" % (self.expr, self.base_exc.__class__.__name__, + str(self.base_exc))) + + +converter: dict[type[Any], Callable[[Any], Basic]] = {} + +#holds the conversions defined in SymPy itself, i.e. non-user defined conversions +_sympy_converter: dict[type[Any], Callable[[Any], Basic]] = {} + +#alias for clearer use in the library +_external_converter = converter + +class CantSympify: + """ + Mix in this trait to a class to disallow sympification of its instances. + + Examples + ======== + + >>> from sympy import sympify + >>> from sympy.core.sympify import CantSympify + + >>> class Something(dict): + ... pass + ... + >>> sympify(Something()) + {} + + >>> class Something(dict, CantSympify): + ... pass + ... + >>> sympify(Something()) + Traceback (most recent call last): + ... + SympifyError: SympifyError: {} + + """ + + __slots__ = () + + +def _is_numpy_instance(a): + """ + Checks if an object is an instance of a type from the numpy module. + """ + # This check avoids unnecessarily importing NumPy. We check the whole + # __mro__ in case any base type is a numpy type. + return any(type_.__module__ == 'numpy' + for type_ in type(a).__mro__) + + +def _convert_numpy_types(a, **sympify_args): + """ + Converts a numpy datatype input to an appropriate SymPy type. + """ + import numpy as np + if not isinstance(a, np.floating): + if np.iscomplex(a): + return _sympy_converter[complex](a.item()) + else: + return sympify(a.item(), **sympify_args) + else: + from .numbers import Float + prec = np.finfo(a).nmant + 1 + # E.g. double precision means prec=53 but nmant=52 + # Leading bit of mantissa is always 1, so is not stored + if np.isposinf(a): + return Float('inf') + elif np.isneginf(a): + return Float('-inf') + else: + p, q = a.as_integer_ratio() + a = mlib.from_rational(p, q, prec) + return Float(a, precision=prec) + + +@overload +def sympify(a: int, *, strict: bool = False) -> Integer: ... # type: ignore +@overload +def sympify(a: float, *, strict: bool = False) -> Float: ... +@overload +def sympify(a: Expr | complex, *, strict: bool = False) -> Expr: ... +@overload +def sympify(a: Tbasic, *, strict: bool = False) -> Tbasic: ... +@overload +def sympify(a: Any, *, strict: bool = False) -> Basic: ... + +def sympify(a, locals=None, convert_xor=True, strict=False, rational=False, + evaluate=None): + """ + Converts an arbitrary expression to a type that can be used inside SymPy. + + Explanation + =========== + + It will convert Python ints into instances of :class:`~.Integer`, floats + into instances of :class:`~.Float`, etc. It is also able to coerce + symbolic expressions which inherit from :class:`~.Basic`. This can be + useful in cooperation with SAGE. + + .. warning:: + Note that this function uses ``eval``, and thus shouldn't be used on + unsanitized input. + + If the argument is already a type that SymPy understands, it will do + nothing but return that value. This can be used at the beginning of a + function to ensure you are working with the correct type. + + Examples + ======== + + >>> from sympy import sympify + + >>> sympify(2).is_integer + True + >>> sympify(2).is_real + True + + >>> sympify(2.0).is_real + True + >>> sympify("2.0").is_real + True + >>> sympify("2e-45").is_real + True + + If the expression could not be converted, a SympifyError is raised. + + >>> sympify("x***2") + Traceback (most recent call last): + ... + SympifyError: SympifyError: "could not parse 'x***2'" + + When attempting to parse non-Python syntax using ``sympify``, it raises a + ``SympifyError``: + + >>> sympify("2x+1") + Traceback (most recent call last): + ... + SympifyError: Sympify of expression 'could not parse '2x+1'' failed + + To parse non-Python syntax, use ``parse_expr`` from ``sympy.parsing.sympy_parser``. + + >>> from sympy.parsing.sympy_parser import parse_expr + >>> parse_expr("2x+1", transformations="all") + 2*x + 1 + + For more details about ``transformations``: see :func:`~sympy.parsing.sympy_parser.parse_expr` + + Locals + ------ + + The sympification happens with access to everything that is loaded + by ``from sympy import *``; anything used in a string that is not + defined by that import will be converted to a symbol. In the following, + the ``bitcount`` function is treated as a symbol and the ``O`` is + interpreted as the :class:`~.Order` object (used with series) and it raises + an error when used improperly: + + >>> s = 'bitcount(42)' + >>> sympify(s) + bitcount(42) + >>> sympify("O(x)") + O(x) + >>> sympify("O + 1") + Traceback (most recent call last): + ... + TypeError: unbound method... + + In order to have ``bitcount`` be recognized it can be imported into a + namespace dictionary and passed as locals: + + >>> ns = {} + >>> exec('from sympy.core.evalf import bitcount', ns) + >>> sympify(s, locals=ns) + 6 + + In order to have the ``O`` interpreted as a Symbol, identify it as such + in the namespace dictionary. This can be done in a variety of ways; all + three of the following are possibilities: + + >>> from sympy import Symbol + >>> ns["O"] = Symbol("O") # method 1 + >>> exec('from sympy.abc import O', ns) # method 2 + >>> ns.update(dict(O=Symbol("O"))) # method 3 + >>> sympify("O + 1", locals=ns) + O + 1 + + If you want *all* single-letter and Greek-letter variables to be symbols + then you can use the clashing-symbols dictionaries that have been defined + there as private variables: ``_clash1`` (single-letter variables), + ``_clash2`` (the multi-letter Greek names) or ``_clash`` (both single and + multi-letter names that are defined in ``abc``). + + >>> from sympy.abc import _clash1 + >>> set(_clash1) # if this fails, see issue #23903 + {'E', 'I', 'N', 'O', 'Q', 'S'} + >>> sympify('I & Q', _clash1) + I & Q + + Strict + ------ + + If the option ``strict`` is set to ``True``, only the types for which an + explicit conversion has been defined are converted. In the other + cases, a SympifyError is raised. + + >>> print(sympify(None)) + None + >>> sympify(None, strict=True) + Traceback (most recent call last): + ... + SympifyError: SympifyError: None + + .. deprecated:: 1.6 + + ``sympify(obj)`` automatically falls back to ``str(obj)`` when all + other conversion methods fail, but this is deprecated. ``strict=True`` + will disable this deprecated behavior. See + :ref:`deprecated-sympify-string-fallback`. + + Evaluation + ---------- + + If the option ``evaluate`` is set to ``False``, then arithmetic and + operators will be converted into their SymPy equivalents and the + ``evaluate=False`` option will be added. Nested ``Add`` or ``Mul`` will + be denested first. This is done via an AST transformation that replaces + operators with their SymPy equivalents, so if an operand redefines any + of those operations, the redefined operators will not be used. If + argument a is not a string, the mathematical expression is evaluated + before being passed to sympify, so adding ``evaluate=False`` will still + return the evaluated result of expression. + + >>> sympify('2**2 / 3 + 5') + 19/3 + >>> sympify('2**2 / 3 + 5', evaluate=False) + 2**2/3 + 5 + >>> sympify('4/2+7', evaluate=True) + 9 + >>> sympify('4/2+7', evaluate=False) + 4/2 + 7 + >>> sympify(4/2+7, evaluate=False) + 9.00000000000000 + + Extending + --------- + + To extend ``sympify`` to convert custom objects (not derived from ``Basic``), + just define a ``_sympy_`` method to your class. You can do that even to + classes that you do not own by subclassing or adding the method at runtime. + + >>> from sympy import Matrix + >>> class MyList1(object): + ... def __iter__(self): + ... yield 1 + ... yield 2 + ... return + ... def __getitem__(self, i): return list(self)[i] + ... def _sympy_(self): return Matrix(self) + >>> sympify(MyList1()) + Matrix([ + [1], + [2]]) + + If you do not have control over the class definition you could also use the + ``converter`` global dictionary. The key is the class and the value is a + function that takes a single argument and returns the desired SymPy + object, e.g. ``converter[MyList] = lambda x: Matrix(x)``. + + >>> class MyList2(object): # XXX Do not do this if you control the class! + ... def __iter__(self): # Use _sympy_! + ... yield 1 + ... yield 2 + ... return + ... def __getitem__(self, i): return list(self)[i] + >>> from sympy.core.sympify import converter + >>> converter[MyList2] = lambda x: Matrix(x) + >>> sympify(MyList2()) + Matrix([ + [1], + [2]]) + + Notes + ===== + + The keywords ``rational`` and ``convert_xor`` are only used + when the input is a string. + + convert_xor + ----------- + + >>> sympify('x^y',convert_xor=True) + x**y + >>> sympify('x^y',convert_xor=False) + x ^ y + + rational + -------- + + >>> sympify('0.1',rational=False) + 0.1 + >>> sympify('0.1',rational=True) + 1/10 + + Sometimes autosimplification during sympification results in expressions + that are very different in structure than what was entered. Until such + autosimplification is no longer done, the ``kernS`` function might be of + some use. In the example below you can see how an expression reduces to + $-1$ by autosimplification, but does not do so when ``kernS`` is used. + + >>> from sympy.core.sympify import kernS + >>> from sympy.abc import x + >>> -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1 + -1 + >>> s = '-2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1' + >>> sympify(s) + -1 + >>> kernS(s) + -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1 + + Parameters + ========== + + a : + - any object defined in SymPy + - standard numeric Python types: ``int``, ``long``, ``float``, ``Decimal`` + - strings (like ``"0.09"``, ``"2e-19"`` or ``'sin(x)'``) + - booleans, including ``None`` (will leave ``None`` unchanged) + - dicts, lists, sets or tuples containing any of the above + + convert_xor : bool, optional + If true, treats ``^`` as exponentiation. + If False, treats ``^`` as XOR itself. + Used only when input is a string. + + locals : any object defined in SymPy, optional + In order to have strings be recognized it can be imported + into a namespace dictionary and passed as locals. + + strict : bool, optional + If the option strict is set to ``True``, only the types for which + an explicit conversion has been defined are converted. In the + other cases, a SympifyError is raised. + + rational : bool, optional + If ``True``, converts floats into :class:`~.Rational`. + If ``False``, it lets floats remain as it is. + Used only when input is a string. + + evaluate : bool, optional + If False, then arithmetic and operators will be converted into + their SymPy equivalents. If True the expression will be evaluated + and the result will be returned. + + """ + # XXX: If a is a Basic subclass rather than instance (e.g. sin rather than + # sin(x)) then a.__sympy__ will be the property. Only on the instance will + # a.__sympy__ give the *value* of the property (True). Since sympify(sin) + # was used for a long time we allow it to pass. However if strict=True as + # is the case in internal calls to _sympify then we only allow + # is_sympy=True. + # + # https://github.com/sympy/sympy/issues/20124 + is_sympy = getattr(a, '__sympy__', None) + if is_sympy is True: + return a + elif is_sympy is not None: + if not strict: + return a + else: + raise SympifyError(a) + + if isinstance(a, CantSympify): + raise SympifyError(a) + + cls = getattr(a, "__class__", None) + + #Check if there exists a converter for any of the types in the mro + for superclass in getmro(cls): + #First check for user defined converters + conv = _external_converter.get(superclass) + if conv is None: + #if none exists, check for SymPy defined converters + conv = _sympy_converter.get(superclass) + if conv is not None: + return conv(a) + + if cls is type(None): + if strict: + raise SympifyError(a) + else: + return a + + if evaluate is None: + evaluate = global_parameters.evaluate + + # Support for basic numpy datatypes + if _is_numpy_instance(a): + import numpy as np + if np.isscalar(a): + return _convert_numpy_types(a, locals=locals, + convert_xor=convert_xor, strict=strict, rational=rational, + evaluate=evaluate) + + _sympy_ = getattr(a, "_sympy_", None) + if _sympy_ is not None: + return a._sympy_() + + if not strict: + # Put numpy array conversion _before_ float/int, see + # . + flat = getattr(a, "flat", None) + if flat is not None: + shape = getattr(a, "shape", None) + if shape is not None: + from sympy.tensor.array import Array + return Array(a.flat, a.shape) # works with e.g. NumPy arrays + + if not isinstance(a, str): + if _is_numpy_instance(a): + import numpy as np + assert not isinstance(a, np.number) + if isinstance(a, np.ndarray): + # Scalar arrays (those with zero dimensions) have sympify + # called on the scalar element. + if a.ndim == 0: + try: + return sympify(a.item(), + locals=locals, + convert_xor=convert_xor, + strict=strict, + rational=rational, + evaluate=evaluate) + except SympifyError: + pass + elif hasattr(a, '__float__'): + # float and int can coerce size-one numpy arrays to their lone + # element. See issue https://github.com/numpy/numpy/issues/10404. + return sympify(float(a)) + elif hasattr(a, '__int__'): + return sympify(int(a)) + + if strict: + raise SympifyError(a) + + if iterable(a): + try: + return type(a)([sympify(x, locals=locals, convert_xor=convert_xor, + rational=rational, evaluate=evaluate) for x in a]) + except TypeError: + # Not all iterables are rebuildable with their type. + pass + + if not isinstance(a, str): + raise SympifyError('cannot sympify object of type %r' % type(a)) + + from sympy.parsing.sympy_parser import (parse_expr, TokenError, + standard_transformations) + from sympy.parsing.sympy_parser import convert_xor as t_convert_xor + from sympy.parsing.sympy_parser import rationalize as t_rationalize + + transformations = standard_transformations + + if rational: + transformations += (t_rationalize,) + if convert_xor: + transformations += (t_convert_xor,) + + try: + a = a.replace('\n', '') + expr = parse_expr(a, local_dict=locals, transformations=transformations, evaluate=evaluate) + except (TokenError, SyntaxError) as exc: + raise SympifyError('could not parse %r' % a, exc) + + return expr + + +def _sympify(a): + """ + Short version of :func:`~.sympify` for internal usage for ``__add__`` and + ``__eq__`` methods where it is ok to allow some things (like Python + integers and floats) in the expression. This excludes things (like strings) + that are unwise to allow into such an expression. + + >>> from sympy import Integer + >>> Integer(1) == 1 + True + + >>> Integer(1) == '1' + False + + >>> from sympy.abc import x + >>> x + 1 + x + 1 + + >>> x + '1' + Traceback (most recent call last): + ... + TypeError: unsupported operand type(s) for +: 'Symbol' and 'str' + + see: sympify + + """ + return sympify(a, strict=True) + + +def kernS(s): + """Use a hack to try keep autosimplification from distributing a + a number into an Add; this modification does not + prevent the 2-arg Mul from becoming an Add, however. + + Examples + ======== + + >>> from sympy.core.sympify import kernS + >>> from sympy.abc import x, y + + The 2-arg Mul distributes a number (or minus sign) across the terms + of an expression, but kernS will prevent that: + + >>> 2*(x + y), -(x + 1) + (2*x + 2*y, -x - 1) + >>> kernS('2*(x + y)') + 2*(x + y) + >>> kernS('-(x + 1)') + -(x + 1) + + If use of the hack fails, the un-hacked string will be passed to sympify... + and you get what you get. + + XXX This hack should not be necessary once issue 4596 has been resolved. + """ + hit = False + quoted = '"' in s or "'" in s + if '(' in s and not quoted: + if s.count('(') != s.count(")"): + raise SympifyError('unmatched left parenthesis') + + # strip all space from s + s = ''.join(s.split()) + olds = s + # now use space to represent a symbol that + # will + # step 1. turn potential 2-arg Muls into 3-arg versions + # 1a. *( -> * *( + s = s.replace('*(', '* *(') + # 1b. close up exponentials + s = s.replace('** *', '**') + # 2. handle the implied multiplication of a negated + # parenthesized expression in two steps + # 2a: -(...) --> -( *(...) + target = '-( *(' + s = s.replace('-(', target) + # 2b: double the matching closing parenthesis + # -( *(...) --> -( *(...)) + i = nest = 0 + assert target.endswith('(') # assumption below + while True: + j = s.find(target, i) + if j == -1: + break + j += len(target) - 1 + for j in range(j, len(s)): + if s[j] == "(": + nest += 1 + elif s[j] == ")": + nest -= 1 + if nest == 0: + break + s = s[:j] + ")" + s[j:] + i = j + 2 # the first char after 2nd ) + if ' ' in s: + # get a unique kern + kern = '_' + while kern in s: + kern += choice(string.ascii_letters + string.digits) + s = s.replace(' ', kern) + hit = kern in s + else: + hit = False + + for i in range(2): + try: + expr = sympify(s) + break + except TypeError: # the kern might cause unknown errors... + if hit: + s = olds # maybe it didn't like the kern; use un-kerned s + hit = False + continue + expr = sympify(s) # let original error raise + + if not hit: + return expr + + from .symbol import Symbol + rep = {Symbol(kern): 1} + def _clear(expr): + if isinstance(expr, (list, tuple, set)): + return type(expr)([_clear(e) for e in expr]) + if hasattr(expr, 'subs'): + return expr.subs(rep, hack2=True) + return expr + expr = _clear(expr) + # hope that kern is not there anymore + return expr + + +# Avoid circular import +from .basic import Basic diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/trace.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/trace.py new file mode 100644 index 0000000000000000000000000000000000000000..58326ce1fdd5038f0b5805afe7c453314a22cb6a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/trace.py @@ -0,0 +1,12 @@ +from sympy.utilities.exceptions import sympy_deprecation_warning + +sympy_deprecation_warning( + """ + sympy.core.trace is deprecated. Use sympy.physics.quantum.trace + instead. + """, + deprecated_since_version="1.10", + active_deprecations_target="sympy-core-trace-deprecated", +) + +from sympy.physics.quantum.trace import Tr # noqa:F401 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/traversal.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/traversal.py new file mode 100644 index 0000000000000000000000000000000000000000..e4e000ef44bf636b9adc700964a7ee4c2372a019 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/traversal.py @@ -0,0 +1,304 @@ +from __future__ import annotations + +from typing import Iterator + +from .basic import Basic +from .sorting import ordered +from .sympify import sympify +from sympy.utilities.iterables import iterable + + + +def iterargs(expr): + """Yield the args of a Basic object in a breadth-first traversal. + Depth-traversal stops if `arg.args` is either empty or is not + an iterable. + + Examples + ======== + + >>> from sympy import Integral, Function + >>> from sympy.abc import x + >>> f = Function('f') + >>> from sympy.core.traversal import iterargs + >>> list(iterargs(Integral(f(x), (f(x), 1)))) + [Integral(f(x), (f(x), 1)), f(x), (f(x), 1), x, f(x), 1, x] + + See Also + ======== + iterfreeargs, preorder_traversal + """ + args = [expr] + for i in args: + yield i + args.extend(i.args) + + +def iterfreeargs(expr, _first=True): + """Yield the args of a Basic object in a breadth-first traversal. + Depth-traversal stops if `arg.args` is either empty or is not + an iterable. The bound objects of an expression will be returned + as canonical variables. + + Examples + ======== + + >>> from sympy import Integral, Function + >>> from sympy.abc import x + >>> f = Function('f') + >>> from sympy.core.traversal import iterfreeargs + >>> list(iterfreeargs(Integral(f(x), (f(x), 1)))) + [Integral(f(x), (f(x), 1)), 1] + + See Also + ======== + iterargs, preorder_traversal + """ + args = [expr] + for i in args: + yield i + if _first and hasattr(i, 'bound_symbols'): + void = i.canonical_variables.values() + for i in iterfreeargs(i.as_dummy(), _first=False): + if not i.has(*void): + yield i + args.extend(i.args) + + +class preorder_traversal: + """ + Do a pre-order traversal of a tree. + + This iterator recursively yields nodes that it has visited in a pre-order + fashion. That is, it yields the current node then descends through the + tree breadth-first to yield all of a node's children's pre-order + traversal. + + + For an expression, the order of the traversal depends on the order of + .args, which in many cases can be arbitrary. + + Parameters + ========== + node : SymPy expression + The expression to traverse. + keys : (default None) sort key(s) + The key(s) used to sort args of Basic objects. When None, args of Basic + objects are processed in arbitrary order. If key is defined, it will + be passed along to ordered() as the only key(s) to use to sort the + arguments; if ``key`` is simply True then the default keys of ordered + will be used. + + Yields + ====== + subtree : SymPy expression + All of the subtrees in the tree. + + Examples + ======== + + >>> from sympy import preorder_traversal, symbols + >>> x, y, z = symbols('x y z') + + The nodes are returned in the order that they are encountered unless key + is given; simply passing key=True will guarantee that the traversal is + unique. + + >>> list(preorder_traversal((x + y)*z, keys=None)) # doctest: +SKIP + [z*(x + y), z, x + y, y, x] + >>> list(preorder_traversal((x + y)*z, keys=True)) + [z*(x + y), z, x + y, x, y] + + """ + def __init__(self, node, keys=None): + self._skip_flag = False + self._pt = self._preorder_traversal(node, keys) + + def _preorder_traversal(self, node, keys): + yield node + if self._skip_flag: + self._skip_flag = False + return + if isinstance(node, Basic): + if not keys and hasattr(node, '_argset'): + # LatticeOp keeps args as a set. We should use this if we + # don't care about the order, to prevent unnecessary sorting. + args = node._argset + else: + args = node.args + if keys: + if keys != True: + args = ordered(args, keys, default=False) + else: + args = ordered(args) + for arg in args: + yield from self._preorder_traversal(arg, keys) + elif iterable(node): + for item in node: + yield from self._preorder_traversal(item, keys) + + def skip(self): + """ + Skip yielding current node's (last yielded node's) subtrees. + + Examples + ======== + + >>> from sympy import preorder_traversal, symbols + >>> x, y, z = symbols('x y z') + >>> pt = preorder_traversal((x + y*z)*z) + >>> for i in pt: + ... print(i) + ... if i == x + y*z: + ... pt.skip() + z*(x + y*z) + z + x + y*z + """ + self._skip_flag = True + + def __next__(self): + return next(self._pt) + + def __iter__(self) -> Iterator[Basic]: + return self + + +def use(expr, func, level=0, args=(), kwargs={}): + """ + Use ``func`` to transform ``expr`` at the given level. + + Examples + ======== + + >>> from sympy import use, expand + >>> from sympy.abc import x, y + + >>> f = (x + y)**2*x + 1 + + >>> use(f, expand, level=2) + x*(x**2 + 2*x*y + y**2) + 1 + >>> expand(f) + x**3 + 2*x**2*y + x*y**2 + 1 + + """ + def _use(expr, level): + if not level: + return func(expr, *args, **kwargs) + else: + if expr.is_Atom: + return expr + else: + level -= 1 + _args = [_use(arg, level) for arg in expr.args] + return expr.__class__(*_args) + + return _use(sympify(expr), level) + + +def walk(e, *target): + """Iterate through the args that are the given types (target) and + return a list of the args that were traversed; arguments + that are not of the specified types are not traversed. + + Examples + ======== + + >>> from sympy.core.traversal import walk + >>> from sympy import Min, Max + >>> from sympy.abc import x, y, z + >>> list(walk(Min(x, Max(y, Min(1, z))), Min)) + [Min(x, Max(y, Min(1, z)))] + >>> list(walk(Min(x, Max(y, Min(1, z))), Min, Max)) + [Min(x, Max(y, Min(1, z))), Max(y, Min(1, z)), Min(1, z)] + + See Also + ======== + + bottom_up + """ + if isinstance(e, target): + yield e + for i in e.args: + yield from walk(i, *target) + + +def bottom_up(rv, F, atoms=False, nonbasic=False): + """Apply ``F`` to all expressions in an expression tree from the + bottom up. If ``atoms`` is True, apply ``F`` even if there are no args; + if ``nonbasic`` is True, try to apply ``F`` to non-Basic objects. + """ + args = getattr(rv, 'args', None) + if args is not None: + if args: + args = tuple([bottom_up(a, F, atoms, nonbasic) for a in args]) + if args != rv.args: + rv = rv.func(*args) + rv = F(rv) + elif atoms: + rv = F(rv) + else: + if nonbasic: + try: + rv = F(rv) + except TypeError: + pass + + return rv + + +def postorder_traversal(node, keys=None): + """ + Do a postorder traversal of a tree. + + This generator recursively yields nodes that it has visited in a postorder + fashion. That is, it descends through the tree depth-first to yield all of + a node's children's postorder traversal before yielding the node itself. + + Parameters + ========== + + node : SymPy expression + The expression to traverse. + keys : (default None) sort key(s) + The key(s) used to sort args of Basic objects. When None, args of Basic + objects are processed in arbitrary order. If key is defined, it will + be passed along to ordered() as the only key(s) to use to sort the + arguments; if ``key`` is simply True then the default keys of + ``ordered`` will be used (node count and default_sort_key). + + Yields + ====== + subtree : SymPy expression + All of the subtrees in the tree. + + Examples + ======== + + >>> from sympy import postorder_traversal + >>> from sympy.abc import w, x, y, z + + The nodes are returned in the order that they are encountered unless key + is given; simply passing key=True will guarantee that the traversal is + unique. + + >>> list(postorder_traversal(w + (x + y)*z)) # doctest: +SKIP + [z, y, x, x + y, z*(x + y), w, w + z*(x + y)] + >>> list(postorder_traversal(w + (x + y)*z, keys=True)) + [w, z, x, y, x + y, z*(x + y), w + z*(x + y)] + + + """ + if isinstance(node, Basic): + args = node.args + if keys: + if keys != True: + args = ordered(args, keys, default=False) + else: + args = ordered(args) + for arg in args: + yield from postorder_traversal(arg, keys) + elif iterable(node): + for item in node: + yield from postorder_traversal(item, keys) + yield node diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2b27b4b036e5f2ed93a1ea88cd7d7144eb5615d4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/__init__.py @@ -0,0 +1,35 @@ +from sympy.crypto.crypto import (cycle_list, + encipher_shift, encipher_affine, encipher_substitution, + check_and_join, encipher_vigenere, decipher_vigenere, bifid5_square, + bifid6_square, encipher_hill, decipher_hill, + encipher_bifid5, encipher_bifid6, decipher_bifid5, + decipher_bifid6, encipher_kid_rsa, decipher_kid_rsa, + kid_rsa_private_key, kid_rsa_public_key, decipher_rsa, rsa_private_key, + rsa_public_key, encipher_rsa, lfsr_connection_polynomial, + lfsr_autocorrelation, lfsr_sequence, encode_morse, decode_morse, + elgamal_private_key, elgamal_public_key, decipher_elgamal, + encipher_elgamal, dh_private_key, dh_public_key, dh_shared_key, + padded_key, encipher_bifid, decipher_bifid, bifid_square, bifid5, + bifid6, bifid10, decipher_gm, encipher_gm, gm_public_key, + gm_private_key, bg_private_key, bg_public_key, encipher_bg, decipher_bg, + encipher_rot13, decipher_rot13, encipher_atbash, decipher_atbash, + encipher_railfence, decipher_railfence) + +__all__ = [ + 'cycle_list', 'encipher_shift', 'encipher_affine', + 'encipher_substitution', 'check_and_join', 'encipher_vigenere', + 'decipher_vigenere', 'bifid5_square', 'bifid6_square', 'encipher_hill', + 'decipher_hill', 'encipher_bifid5', 'encipher_bifid6', 'decipher_bifid5', + 'decipher_bifid6', 'encipher_kid_rsa', 'decipher_kid_rsa', + 'kid_rsa_private_key', 'kid_rsa_public_key', 'decipher_rsa', + 'rsa_private_key', 'rsa_public_key', 'encipher_rsa', + 'lfsr_connection_polynomial', 'lfsr_autocorrelation', 'lfsr_sequence', + 'encode_morse', 'decode_morse', 'elgamal_private_key', + 'elgamal_public_key', 'decipher_elgamal', 'encipher_elgamal', + 'dh_private_key', 'dh_public_key', 'dh_shared_key', 'padded_key', + 'encipher_bifid', 'decipher_bifid', 'bifid_square', 'bifid5', 'bifid6', + 'bifid10', 'decipher_gm', 'encipher_gm', 'gm_public_key', + 'gm_private_key', 'bg_private_key', 'bg_public_key', 'encipher_bg', + 'decipher_bg', 'encipher_rot13', 'decipher_rot13', 'encipher_atbash', + 'decipher_atbash', 'encipher_railfence', 'decipher_railfence', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/crypto.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/crypto.py new file mode 100644 index 0000000000000000000000000000000000000000..2c298e4ac08616dbe7d607a9d56d33b7fe9d5e2d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/crypto.py @@ -0,0 +1,3368 @@ +""" +This file contains some classical ciphers and routines +implementing a linear-feedback shift register (LFSR) +and the Diffie-Hellman key exchange. + +.. warning:: + + This module is intended for educational purposes only. Do not use the + functions in this module for real cryptographic applications. If you wish + to encrypt real data, we recommend using something like the `cryptography + `_ module. + +""" + +from string import whitespace, ascii_uppercase as uppercase, printable +from functools import reduce +import string +import warnings + +from itertools import cycle + +from sympy.external.gmpy import GROUND_TYPES +from sympy.core import Symbol +from sympy.core.numbers import Rational +from sympy.core.random import _randrange, _randint +from sympy.external.gmpy import gcd, invert +from sympy.functions.combinatorial.numbers import (totient as _euler, + reduced_totient as _carmichael) +from sympy.matrices import Matrix +from sympy.ntheory import isprime, primitive_root, factorint +from sympy.ntheory.generate import nextprime +from sympy.ntheory.modular import crt +from sympy.polys.domains import FF +from sympy.polys.polytools import Poly +from sympy.utilities.misc import as_int, filldedent, translate +from sympy.utilities.iterables import uniq, multiset +from sympy.utilities.decorator import doctest_depends_on + + +if GROUND_TYPES == 'flint': + __doctest_skip__ = ['lfsr_sequence'] + + +class NonInvertibleCipherWarning(RuntimeWarning): + """A warning raised if the cipher is not invertible.""" + def __init__(self, msg): + self.fullMessage = msg + + def __str__(self): + return '\n\t' + self.fullMessage + + def warn(self, stacklevel=3): + warnings.warn(self, stacklevel=stacklevel) + + +def AZ(s=None): + """Return the letters of ``s`` in uppercase. In case more than + one string is passed, each of them will be processed and a list + of upper case strings will be returned. + + Examples + ======== + + >>> from sympy.crypto.crypto import AZ + >>> AZ('Hello, world!') + 'HELLOWORLD' + >>> AZ('Hello, world!'.split()) + ['HELLO', 'WORLD'] + + See Also + ======== + + check_and_join + + """ + if not s: + return uppercase + t = isinstance(s, str) + if t: + s = [s] + rv = [check_and_join(i.upper().split(), uppercase, filter=True) + for i in s] + if t: + return rv[0] + return rv + +bifid5 = AZ().replace('J', '') +bifid6 = AZ() + string.digits +bifid10 = printable + + +def padded_key(key, symbols): + """Return a string of the distinct characters of ``symbols`` with + those of ``key`` appearing first. A ValueError is raised if + a) there are duplicate characters in ``symbols`` or + b) there are characters in ``key`` that are not in ``symbols``. + + Examples + ======== + + >>> from sympy.crypto.crypto import padded_key + >>> padded_key('PUPPY', 'OPQRSTUVWXY') + 'PUYOQRSTVWX' + >>> padded_key('RSA', 'ARTIST') + Traceback (most recent call last): + ... + ValueError: duplicate characters in symbols: T + + """ + syms = list(uniq(symbols)) + if len(syms) != len(symbols): + extra = ''.join(sorted({ + i for i in symbols if symbols.count(i) > 1})) + raise ValueError('duplicate characters in symbols: %s' % extra) + extra = set(key) - set(syms) + if extra: + raise ValueError( + 'characters in key but not symbols: %s' % ''.join( + sorted(extra))) + key0 = ''.join(list(uniq(key))) + # remove from syms characters in key0 + return key0 + translate(''.join(syms), None, key0) + + +def check_and_join(phrase, symbols=None, filter=None): + """ + Joins characters of ``phrase`` and if ``symbols`` is given, raises + an error if any character in ``phrase`` is not in ``symbols``. + + Parameters + ========== + + phrase + String or list of strings to be returned as a string. + + symbols + Iterable of characters allowed in ``phrase``. + + If ``symbols`` is ``None``, no checking is performed. + + Examples + ======== + + >>> from sympy.crypto.crypto import check_and_join + >>> check_and_join('a phrase') + 'a phrase' + >>> check_and_join('a phrase'.upper().split()) + 'APHRASE' + >>> check_and_join('a phrase!'.upper().split(), 'ARE', filter=True) + 'ARAE' + >>> check_and_join('a phrase!'.upper().split(), 'ARE') + Traceback (most recent call last): + ... + ValueError: characters in phrase but not symbols: "!HPS" + + """ + rv = ''.join(''.join(phrase)) + if symbols is not None: + symbols = check_and_join(symbols) + missing = ''.join(sorted(set(rv) - set(symbols))) + if missing: + if not filter: + raise ValueError( + 'characters in phrase but not symbols: "%s"' % missing) + rv = translate(rv, None, missing) + return rv + + +def _prep(msg, key, alp, default=None): + if not alp: + if not default: + alp = AZ() + msg = AZ(msg) + key = AZ(key) + else: + alp = default + else: + alp = ''.join(alp) + key = check_and_join(key, alp, filter=True) + msg = check_and_join(msg, alp, filter=True) + return msg, key, alp + + +def cycle_list(k, n): + """ + Returns the elements of the list ``range(n)`` shifted to the + left by ``k`` (so the list starts with ``k`` (mod ``n``)). + + Examples + ======== + + >>> from sympy.crypto.crypto import cycle_list + >>> cycle_list(3, 10) + [3, 4, 5, 6, 7, 8, 9, 0, 1, 2] + + """ + k = k % n + return list(range(k, n)) + list(range(k)) + + +######## shift cipher examples ############ + + +def encipher_shift(msg, key, symbols=None): + """ + Performs shift cipher encryption on plaintext msg, and returns the + ciphertext. + + Parameters + ========== + + key : int + The secret key. + + msg : str + Plaintext of upper-case letters. + + Returns + ======= + + str + Ciphertext of upper-case letters. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_shift, decipher_shift + >>> msg = "GONAVYBEATARMY" + >>> ct = encipher_shift(msg, 1); ct + 'HPOBWZCFBUBSNZ' + + To decipher the shifted text, change the sign of the key: + + >>> encipher_shift(ct, -1) + 'GONAVYBEATARMY' + + There is also a convenience function that does this with the + original key: + + >>> decipher_shift(ct, 1) + 'GONAVYBEATARMY' + + Notes + ===== + + ALGORITHM: + + STEPS: + 0. Number the letters of the alphabet from 0, ..., N + 1. Compute from the string ``msg`` a list ``L1`` of + corresponding integers. + 2. Compute from the list ``L1`` a new list ``L2``, given by + adding ``(k mod 26)`` to each element in ``L1``. + 3. Compute from the list ``L2`` a string ``ct`` of + corresponding letters. + + The shift cipher is also called the Caesar cipher, after + Julius Caesar, who, according to Suetonius, used it with a + shift of three to protect messages of military significance. + Caesar's nephew Augustus reportedly used a similar cipher, but + with a right shift of 1. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Caesar_cipher + .. [2] https://mathworld.wolfram.com/CaesarsMethod.html + + See Also + ======== + + decipher_shift + + """ + msg, _, A = _prep(msg, '', symbols) + shift = len(A) - key % len(A) + key = A[shift:] + A[:shift] + return translate(msg, key, A) + + +def decipher_shift(msg, key, symbols=None): + """ + Return the text by shifting the characters of ``msg`` to the + left by the amount given by ``key``. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_shift, decipher_shift + >>> msg = "GONAVYBEATARMY" + >>> ct = encipher_shift(msg, 1); ct + 'HPOBWZCFBUBSNZ' + + To decipher the shifted text, change the sign of the key: + + >>> encipher_shift(ct, -1) + 'GONAVYBEATARMY' + + Or use this function with the original key: + + >>> decipher_shift(ct, 1) + 'GONAVYBEATARMY' + + """ + return encipher_shift(msg, -key, symbols) + +def encipher_rot13(msg, symbols=None): + """ + Performs the ROT13 encryption on a given plaintext ``msg``. + + Explanation + =========== + + ROT13 is a substitution cipher which substitutes each letter + in the plaintext message for the letter furthest away from it + in the English alphabet. + + Equivalently, it is just a Caeser (shift) cipher with a shift + key of 13 (midway point of the alphabet). + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/ROT13 + + See Also + ======== + + decipher_rot13 + encipher_shift + + """ + return encipher_shift(msg, 13, symbols) + +def decipher_rot13(msg, symbols=None): + """ + Performs the ROT13 decryption on a given plaintext ``msg``. + + Explanation + ============ + + ``decipher_rot13`` is equivalent to ``encipher_rot13`` as both + ``decipher_shift`` with a key of 13 and ``encipher_shift`` key with a + key of 13 will return the same results. Nonetheless, + ``decipher_rot13`` has nonetheless been explicitly defined here for + consistency. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_rot13, decipher_rot13 + >>> msg = 'GONAVYBEATARMY' + >>> ciphertext = encipher_rot13(msg);ciphertext + 'TBANILORNGNEZL' + >>> decipher_rot13(ciphertext) + 'GONAVYBEATARMY' + >>> encipher_rot13(msg) == decipher_rot13(msg) + True + >>> msg == decipher_rot13(ciphertext) + True + + """ + return decipher_shift(msg, 13, symbols) + +######## affine cipher examples ############ + + +def encipher_affine(msg, key, symbols=None, _inverse=False): + r""" + Performs the affine cipher encryption on plaintext ``msg``, and + returns the ciphertext. + + Explanation + =========== + + Encryption is based on the map `x \rightarrow ax+b` (mod `N`) + where ``N`` is the number of characters in the alphabet. + Decryption is based on the map `x \rightarrow cx+d` (mod `N`), + where `c = a^{-1}` (mod `N`) and `d = -a^{-1}b` (mod `N`). + In particular, for the map to be invertible, we need + `\mathrm{gcd}(a, N) = 1` and an error will be raised if this is + not true. + + Parameters + ========== + + msg : str + Characters that appear in ``symbols``. + + a, b : int, int + A pair integers, with ``gcd(a, N) = 1`` (the secret key). + + symbols + String of characters (default = uppercase letters). + + When no symbols are given, ``msg`` is converted to upper case + letters and all other characters are ignored. + + Returns + ======= + + ct + String of characters (the ciphertext message) + + Notes + ===== + + ALGORITHM: + + STEPS: + 0. Number the letters of the alphabet from 0, ..., N + 1. Compute from the string ``msg`` a list ``L1`` of + corresponding integers. + 2. Compute from the list ``L1`` a new list ``L2``, given by + replacing ``x`` by ``a*x + b (mod N)``, for each element + ``x`` in ``L1``. + 3. Compute from the list ``L2`` a string ``ct`` of + corresponding letters. + + This is a straightforward generalization of the shift cipher with + the added complexity of requiring 2 characters to be deciphered in + order to recover the key. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Affine_cipher + + See Also + ======== + + decipher_affine + + """ + msg, _, A = _prep(msg, '', symbols) + N = len(A) + a, b = key + assert gcd(a, N) == 1 + if _inverse: + c = invert(a, N) + d = -b*c + a, b = c, d + B = ''.join([A[(a*i + b) % N] for i in range(N)]) + return translate(msg, A, B) + + +def decipher_affine(msg, key, symbols=None): + r""" + Return the deciphered text that was made from the mapping, + `x \rightarrow ax+b` (mod `N`), where ``N`` is the + number of characters in the alphabet. Deciphering is done by + reciphering with a new key: `x \rightarrow cx+d` (mod `N`), + where `c = a^{-1}` (mod `N`) and `d = -a^{-1}b` (mod `N`). + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_affine, decipher_affine + >>> msg = "GO NAVY BEAT ARMY" + >>> key = (3, 1) + >>> encipher_affine(msg, key) + 'TROBMVENBGBALV' + >>> decipher_affine(_, key) + 'GONAVYBEATARMY' + + See Also + ======== + + encipher_affine + + """ + return encipher_affine(msg, key, symbols, _inverse=True) + + +def encipher_atbash(msg, symbols=None): + r""" + Enciphers a given ``msg`` into its Atbash ciphertext and returns it. + + Explanation + =========== + + Atbash is a substitution cipher originally used to encrypt the Hebrew + alphabet. Atbash works on the principle of mapping each alphabet to its + reverse / counterpart (i.e. a would map to z, b to y etc.) + + Atbash is functionally equivalent to the affine cipher with ``a = 25`` + and ``b = 25`` + + See Also + ======== + + decipher_atbash + + """ + return encipher_affine(msg, (25, 25), symbols) + + +def decipher_atbash(msg, symbols=None): + r""" + Deciphers a given ``msg`` using Atbash cipher and returns it. + + Explanation + =========== + + ``decipher_atbash`` is functionally equivalent to ``encipher_atbash``. + However, it has still been added as a separate function to maintain + consistency. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_atbash, decipher_atbash + >>> msg = 'GONAVYBEATARMY' + >>> encipher_atbash(msg) + 'TLMZEBYVZGZINB' + >>> decipher_atbash(msg) + 'TLMZEBYVZGZINB' + >>> encipher_atbash(msg) == decipher_atbash(msg) + True + >>> msg == encipher_atbash(encipher_atbash(msg)) + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Atbash + + See Also + ======== + + encipher_atbash + + """ + return decipher_affine(msg, (25, 25), symbols) + +#################### substitution cipher ########################### + + +def encipher_substitution(msg, old, new=None): + r""" + Returns the ciphertext obtained by replacing each character that + appears in ``old`` with the corresponding character in ``new``. + If ``old`` is a mapping, then new is ignored and the replacements + defined by ``old`` are used. + + Explanation + =========== + + This is a more general than the affine cipher in that the key can + only be recovered by determining the mapping for each symbol. + Though in practice, once a few symbols are recognized the mappings + for other characters can be quickly guessed. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_substitution, AZ + >>> old = 'OEYAG' + >>> new = '034^6' + >>> msg = AZ("go navy! beat army!") + >>> ct = encipher_substitution(msg, old, new); ct + '60N^V4B3^T^RM4' + + To decrypt a substitution, reverse the last two arguments: + + >>> encipher_substitution(ct, new, old) + 'GONAVYBEATARMY' + + In the special case where ``old`` and ``new`` are a permutation of + order 2 (representing a transposition of characters) their order + is immaterial: + + >>> old = 'NAVY' + >>> new = 'ANYV' + >>> encipher = lambda x: encipher_substitution(x, old, new) + >>> encipher('NAVY') + 'ANYV' + >>> encipher(_) + 'NAVY' + + The substitution cipher, in general, is a method + whereby "units" (not necessarily single characters) of plaintext + are replaced with ciphertext according to a regular system. + + >>> ords = dict(zip('abc', ['\\%i' % ord(i) for i in 'abc'])) + >>> print(encipher_substitution('abc', ords)) + \97\98\99 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Substitution_cipher + + """ + return translate(msg, old, new) + + +###################################################################### +#################### Vigenere cipher examples ######################## +###################################################################### + +def encipher_vigenere(msg, key, symbols=None): + """ + Performs the Vigenere cipher encryption on plaintext ``msg``, and + returns the ciphertext. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_vigenere, AZ + >>> key = "encrypt" + >>> msg = "meet me on monday" + >>> encipher_vigenere(msg, key) + 'QRGKKTHRZQEBPR' + + Section 1 of the Kryptos sculpture at the CIA headquarters + uses this cipher and also changes the order of the + alphabet [2]_. Here is the first line of that section of + the sculpture: + + >>> from sympy.crypto.crypto import decipher_vigenere, padded_key + >>> alp = padded_key('KRYPTOS', AZ()) + >>> key = 'PALIMPSEST' + >>> msg = 'EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJ' + >>> decipher_vigenere(msg, key, alp) + 'BETWEENSUBTLESHADINGANDTHEABSENC' + + Explanation + =========== + + The Vigenere cipher is named after Blaise de Vigenere, a sixteenth + century diplomat and cryptographer, by a historical accident. + Vigenere actually invented a different and more complicated cipher. + The so-called *Vigenere cipher* was actually invented + by Giovan Batista Belaso in 1553. + + This cipher was used in the 1800's, for example, during the American + Civil War. The Confederacy used a brass cipher disk to implement the + Vigenere cipher (now on display in the NSA Museum in Fort + Meade) [1]_. + + The Vigenere cipher is a generalization of the shift cipher. + Whereas the shift cipher shifts each letter by the same amount + (that amount being the key of the shift cipher) the Vigenere + cipher shifts a letter by an amount determined by the key (which is + a word or phrase known only to the sender and receiver). + + For example, if the key was a single letter, such as "C", then the + so-called Vigenere cipher is actually a shift cipher with a + shift of `2` (since "C" is the 2nd letter of the alphabet, if + you start counting at `0`). If the key was a word with two + letters, such as "CA", then the so-called Vigenere cipher will + shift letters in even positions by `2` and letters in odd positions + are left alone (shifted by `0`, since "A" is the 0th letter, if + you start counting at `0`). + + + ALGORITHM: + + INPUT: + + ``msg``: string of characters that appear in ``symbols`` + (the plaintext) + + ``key``: a string of characters that appear in ``symbols`` + (the secret key) + + ``symbols``: a string of letters defining the alphabet + + + OUTPUT: + + ``ct``: string of characters (the ciphertext message) + + STEPS: + 0. Number the letters of the alphabet from 0, ..., N + 1. Compute from the string ``key`` a list ``L1`` of + corresponding integers. Let ``n1 = len(L1)``. + 2. Compute from the string ``msg`` a list ``L2`` of + corresponding integers. Let ``n2 = len(L2)``. + 3. Break ``L2`` up sequentially into sublists of size + ``n1``; the last sublist may be smaller than ``n1`` + 4. For each of these sublists ``L`` of ``L2``, compute a + new list ``C`` given by ``C[i] = L[i] + L1[i] (mod N)`` + to the ``i``-th element in the sublist, for each ``i``. + 5. Assemble these lists ``C`` by concatenation into a new + list of length ``n2``. + 6. Compute from the new list a string ``ct`` of + corresponding letters. + + Once it is known that the key is, say, `n` characters long, + frequency analysis can be applied to every `n`-th letter of + the ciphertext to determine the plaintext. This method is + called *Kasiski examination* (although it was first discovered + by Babbage). If they key is as long as the message and is + comprised of randomly selected characters -- a one-time pad -- the + message is theoretically unbreakable. + + The cipher Vigenere actually discovered is an "auto-key" cipher + described as follows. + + ALGORITHM: + + INPUT: + + ``key``: a string of letters (the secret key) + + ``msg``: string of letters (the plaintext message) + + OUTPUT: + + ``ct``: string of upper-case letters (the ciphertext message) + + STEPS: + 0. Number the letters of the alphabet from 0, ..., N + 1. Compute from the string ``msg`` a list ``L2`` of + corresponding integers. Let ``n2 = len(L2)``. + 2. Let ``n1`` be the length of the key. Append to the + string ``key`` the first ``n2 - n1`` characters of + the plaintext message. Compute from this string (also of + length ``n2``) a list ``L1`` of integers corresponding + to the letter numbers in the first step. + 3. Compute a new list ``C`` given by + ``C[i] = L1[i] + L2[i] (mod N)``. + 4. Compute from the new list a string ``ct`` of letters + corresponding to the new integers. + + To decipher the auto-key ciphertext, the key is used to decipher + the first ``n1`` characters and then those characters become the + key to decipher the next ``n1`` characters, etc...: + + >>> m = AZ('go navy, beat army! yes you can'); m + 'GONAVYBEATARMYYESYOUCAN' + >>> key = AZ('gold bug'); n1 = len(key); n2 = len(m) + >>> auto_key = key + m[:n2 - n1]; auto_key + 'GOLDBUGGONAVYBEATARMYYE' + >>> ct = encipher_vigenere(m, auto_key); ct + 'MCYDWSHKOGAMKZCELYFGAYR' + >>> n1 = len(key) + >>> pt = [] + >>> while ct: + ... part, ct = ct[:n1], ct[n1:] + ... pt.append(decipher_vigenere(part, key)) + ... key = pt[-1] + ... + >>> ''.join(pt) == m + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Vigenere_cipher + .. [2] https://web.archive.org/web/20071116100808/https://filebox.vt.edu/users/batman/kryptos.html + (short URL: https://goo.gl/ijr22d) + + """ + msg, key, A = _prep(msg, key, symbols) + map = {c: i for i, c in enumerate(A)} + key = [map[c] for c in key] + N = len(map) + k = len(key) + rv = [] + for i, m in enumerate(msg): + rv.append(A[(map[m] + key[i % k]) % N]) + rv = ''.join(rv) + return rv + + +def decipher_vigenere(msg, key, symbols=None): + """ + Decode using the Vigenere cipher. + + Examples + ======== + + >>> from sympy.crypto.crypto import decipher_vigenere + >>> key = "encrypt" + >>> ct = "QRGK kt HRZQE BPR" + >>> decipher_vigenere(ct, key) + 'MEETMEONMONDAY' + + """ + msg, key, A = _prep(msg, key, symbols) + map = {c: i for i, c in enumerate(A)} + N = len(A) # normally, 26 + K = [map[c] for c in key] + n = len(K) + C = [map[c] for c in msg] + rv = ''.join([A[(-K[i % n] + c) % N] for i, c in enumerate(C)]) + return rv + + +#################### Hill cipher ######################## + + +def encipher_hill(msg, key, symbols=None, pad="Q"): + r""" + Return the Hill cipher encryption of ``msg``. + + Explanation + =========== + + The Hill cipher [1]_, invented by Lester S. Hill in the 1920's [2]_, + was the first polygraphic cipher in which it was practical + (though barely) to operate on more than three symbols at once. + The following discussion assumes an elementary knowledge of + matrices. + + First, each letter is first encoded as a number starting with 0. + Suppose your message `msg` consists of `n` capital letters, with no + spaces. This may be regarded an `n`-tuple M of elements of + `Z_{26}` (if the letters are those of the English alphabet). A key + in the Hill cipher is a `k x k` matrix `K`, all of whose entries + are in `Z_{26}`, such that the matrix `K` is invertible (i.e., the + linear transformation `K: Z_{N}^k \rightarrow Z_{N}^k` + is one-to-one). + + + Parameters + ========== + + msg + Plaintext message of `n` upper-case letters. + + key + A `k \times k` invertible matrix `K`, all of whose entries are + in `Z_{26}` (or whatever number of symbols are being used). + + pad + Character (default "Q") to use to make length of text be a + multiple of ``k``. + + Returns + ======= + + ct + Ciphertext of upper-case letters. + + Notes + ===== + + ALGORITHM: + + STEPS: + 0. Number the letters of the alphabet from 0, ..., N + 1. Compute from the string ``msg`` a list ``L`` of + corresponding integers. Let ``n = len(L)``. + 2. Break the list ``L`` up into ``t = ceiling(n/k)`` + sublists ``L_1``, ..., ``L_t`` of size ``k`` (with + the last list "padded" to ensure its size is + ``k``). + 3. Compute new list ``C_1``, ..., ``C_t`` given by + ``C[i] = K*L_i`` (arithmetic is done mod N), for each + ``i``. + 4. Concatenate these into a list ``C = C_1 + ... + C_t``. + 5. Compute from ``C`` a string ``ct`` of corresponding + letters. This has length ``k*t``. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hill_cipher + .. [2] Lester S. Hill, Cryptography in an Algebraic Alphabet, + The American Mathematical Monthly Vol.36, June-July 1929, + pp.306-312. + + See Also + ======== + + decipher_hill + + """ + assert key.is_square + assert len(pad) == 1 + msg, pad, A = _prep(msg, pad, symbols) + map = {c: i for i, c in enumerate(A)} + P = [map[c] for c in msg] + N = len(A) + k = key.cols + n = len(P) + m, r = divmod(n, k) + if r: + P = P + [map[pad]]*(k - r) + m += 1 + rv = ''.join([A[c % N] for j in range(m) for c in + list(key*Matrix(k, 1, [P[i] + for i in range(k*j, k*(j + 1))]))]) + return rv + + +def decipher_hill(msg, key, symbols=None): + """ + Deciphering is the same as enciphering but using the inverse of the + key matrix. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_hill, decipher_hill + >>> from sympy import Matrix + + >>> key = Matrix([[1, 2], [3, 5]]) + >>> encipher_hill("meet me on monday", key) + 'UEQDUEODOCTCWQ' + >>> decipher_hill(_, key) + 'MEETMEONMONDAY' + + When the length of the plaintext (stripped of invalid characters) + is not a multiple of the key dimension, extra characters will + appear at the end of the enciphered and deciphered text. In order to + decipher the text, those characters must be included in the text to + be deciphered. In the following, the key has a dimension of 4 but + the text is 2 short of being a multiple of 4 so two characters will + be added. + + >>> key = Matrix([[1, 1, 1, 2], [0, 1, 1, 0], + ... [2, 2, 3, 4], [1, 1, 0, 1]]) + >>> msg = "ST" + >>> encipher_hill(msg, key) + 'HJEB' + >>> decipher_hill(_, key) + 'STQQ' + >>> encipher_hill(msg, key, pad="Z") + 'ISPK' + >>> decipher_hill(_, key) + 'STZZ' + + If the last two characters of the ciphertext were ignored in + either case, the wrong plaintext would be recovered: + + >>> decipher_hill("HD", key) + 'ORMV' + >>> decipher_hill("IS", key) + 'UIKY' + + See Also + ======== + + encipher_hill + + """ + assert key.is_square + msg, _, A = _prep(msg, '', symbols) + map = {c: i for i, c in enumerate(A)} + C = [map[c] for c in msg] + N = len(A) + k = key.cols + n = len(C) + m, r = divmod(n, k) + if r: + C = C + [0]*(k - r) + m += 1 + key_inv = key.inv_mod(N) + rv = ''.join([A[p % N] for j in range(m) for p in + list(key_inv*Matrix( + k, 1, [C[i] for i in range(k*j, k*(j + 1))]))]) + return rv + + +#################### Bifid cipher ######################## + + +def encipher_bifid(msg, key, symbols=None): + r""" + Performs the Bifid cipher encryption on plaintext ``msg``, and + returns the ciphertext. + + This is the version of the Bifid cipher that uses an `n \times n` + Polybius square. + + Parameters + ========== + + msg + Plaintext string. + + key + Short string for key. + + Duplicate characters are ignored and then it is padded with the + characters in ``symbols`` that were not in the short key. + + symbols + `n \times n` characters defining the alphabet. + + (default is string.printable) + + Returns + ======= + + ciphertext + Ciphertext using Bifid5 cipher without spaces. + + See Also + ======== + + decipher_bifid, encipher_bifid5, encipher_bifid6 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Bifid_cipher + + """ + msg, key, A = _prep(msg, key, symbols, bifid10) + long_key = ''.join(uniq(key)) or A + + n = len(A)**.5 + if n != int(n): + raise ValueError( + 'Length of alphabet (%s) is not a square number.' % len(A)) + N = int(n) + if len(long_key) < N**2: + long_key = list(long_key) + [x for x in A if x not in long_key] + + # the fractionalization + row_col = {ch: divmod(i, N) for i, ch in enumerate(long_key)} + r, c = zip(*[row_col[x] for x in msg]) + rc = r + c + ch = {i: ch for ch, i in row_col.items()} + rv = ''.join(ch[i] for i in zip(rc[::2], rc[1::2])) + return rv + + +def decipher_bifid(msg, key, symbols=None): + r""" + Performs the Bifid cipher decryption on ciphertext ``msg``, and + returns the plaintext. + + This is the version of the Bifid cipher that uses the `n \times n` + Polybius square. + + Parameters + ========== + + msg + Ciphertext string. + + key + Short string for key. + + Duplicate characters are ignored and then it is padded with the + characters in symbols that were not in the short key. + + symbols + `n \times n` characters defining the alphabet. + + (default=string.printable, a `10 \times 10` matrix) + + Returns + ======= + + deciphered + Deciphered text. + + Examples + ======== + + >>> from sympy.crypto.crypto import ( + ... encipher_bifid, decipher_bifid, AZ) + + Do an encryption using the bifid5 alphabet: + + >>> alp = AZ().replace('J', '') + >>> ct = AZ("meet me on monday!") + >>> key = AZ("gold bug") + >>> encipher_bifid(ct, key, alp) + 'IEILHHFSTSFQYE' + + When entering the text or ciphertext, spaces are ignored so it + can be formatted as desired. Re-entering the ciphertext from the + preceding, putting 4 characters per line and padding with an extra + J, does not cause problems for the deciphering: + + >>> decipher_bifid(''' + ... IEILH + ... HFSTS + ... FQYEJ''', key, alp) + 'MEETMEONMONDAY' + + When no alphabet is given, all 100 printable characters will be + used: + + >>> key = '' + >>> encipher_bifid('hello world!', key) + 'bmtwmg-bIo*w' + >>> decipher_bifid(_, key) + 'hello world!' + + If the key is changed, a different encryption is obtained: + + >>> key = 'gold bug' + >>> encipher_bifid('hello world!', 'gold_bug') + 'hg2sfuei7t}w' + + And if the key used to decrypt the message is not exact, the + original text will not be perfectly obtained: + + >>> decipher_bifid(_, 'gold pug') + 'heldo~wor6d!' + + """ + msg, _, A = _prep(msg, '', symbols, bifid10) + long_key = ''.join(uniq(key)) or A + + n = len(A)**.5 + if n != int(n): + raise ValueError( + 'Length of alphabet (%s) is not a square number.' % len(A)) + N = int(n) + if len(long_key) < N**2: + long_key = list(long_key) + [x for x in A if x not in long_key] + + # the reverse fractionalization + row_col = { + ch: divmod(i, N) for i, ch in enumerate(long_key)} + rc = [i for c in msg for i in row_col[c]] + n = len(msg) + rc = zip(*(rc[:n], rc[n:])) + ch = {i: ch for ch, i in row_col.items()} + rv = ''.join(ch[i] for i in rc) + return rv + + +def bifid_square(key): + """Return characters of ``key`` arranged in a square. + + Examples + ======== + + >>> from sympy.crypto.crypto import ( + ... bifid_square, AZ, padded_key, bifid5) + >>> bifid_square(AZ().replace('J', '')) + Matrix([ + [A, B, C, D, E], + [F, G, H, I, K], + [L, M, N, O, P], + [Q, R, S, T, U], + [V, W, X, Y, Z]]) + + >>> bifid_square(padded_key(AZ('gold bug!'), bifid5)) + Matrix([ + [G, O, L, D, B], + [U, A, C, E, F], + [H, I, K, M, N], + [P, Q, R, S, T], + [V, W, X, Y, Z]]) + + See Also + ======== + + padded_key + + """ + A = ''.join(uniq(''.join(key))) + n = len(A)**.5 + if n != int(n): + raise ValueError( + 'Length of alphabet (%s) is not a square number.' % len(A)) + n = int(n) + f = lambda i, j: Symbol(A[n*i + j]) + rv = Matrix(n, n, f) + return rv + + +def encipher_bifid5(msg, key): + r""" + Performs the Bifid cipher encryption on plaintext ``msg``, and + returns the ciphertext. + + Explanation + =========== + + This is the version of the Bifid cipher that uses the `5 \times 5` + Polybius square. The letter "J" is ignored so it must be replaced + with something else (traditionally an "I") before encryption. + + ALGORITHM: (5x5 case) + + STEPS: + 0. Create the `5 \times 5` Polybius square ``S`` associated + to ``key`` as follows: + + a) moving from left-to-right, top-to-bottom, + place the letters of the key into a `5 \times 5` + matrix, + b) if the key has less than 25 letters, add the + letters of the alphabet not in the key until the + `5 \times 5` square is filled. + + 1. Create a list ``P`` of pairs of numbers which are the + coordinates in the Polybius square of the letters in + ``msg``. + 2. Let ``L1`` be the list of all first coordinates of ``P`` + (length of ``L1 = n``), let ``L2`` be the list of all + second coordinates of ``P`` (so the length of ``L2`` + is also ``n``). + 3. Let ``L`` be the concatenation of ``L1`` and ``L2`` + (length ``L = 2*n``), except that consecutive numbers + are paired ``(L[2*i], L[2*i + 1])``. You can regard + ``L`` as a list of pairs of length ``n``. + 4. Let ``C`` be the list of all letters which are of the + form ``S[i, j]``, for all ``(i, j)`` in ``L``. As a + string, this is the ciphertext of ``msg``. + + Parameters + ========== + + msg : str + Plaintext string. + + Converted to upper case and filtered of anything but all letters + except J. + + key + Short string for key; non-alphabetic letters, J and duplicated + characters are ignored and then, if the length is less than 25 + characters, it is padded with other letters of the alphabet + (in alphabetical order). + + Returns + ======= + + ct + Ciphertext (all caps, no spaces). + + Examples + ======== + + >>> from sympy.crypto.crypto import ( + ... encipher_bifid5, decipher_bifid5) + + "J" will be omitted unless it is replaced with something else: + + >>> round_trip = lambda m, k: \ + ... decipher_bifid5(encipher_bifid5(m, k), k) + >>> key = 'a' + >>> msg = "JOSIE" + >>> round_trip(msg, key) + 'OSIE' + >>> round_trip(msg.replace("J", "I"), key) + 'IOSIE' + >>> j = "QIQ" + >>> round_trip(msg.replace("J", j), key).replace(j, "J") + 'JOSIE' + + + Notes + ===== + + The Bifid cipher was invented around 1901 by Felix Delastelle. + It is a *fractional substitution* cipher, where letters are + replaced by pairs of symbols from a smaller alphabet. The + cipher uses a `5 \times 5` square filled with some ordering of the + alphabet, except that "J" is replaced with "I" (this is a so-called + Polybius square; there is a `6 \times 6` analog if you add back in + "J" and also append onto the usual 26 letter alphabet, the digits + 0, 1, ..., 9). + According to Helen Gaines' book *Cryptanalysis*, this type of cipher + was used in the field by the German Army during World War I. + + See Also + ======== + + decipher_bifid5, encipher_bifid + + """ + msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid5) + key = padded_key(key, bifid5) + return encipher_bifid(msg, '', key) + + +def decipher_bifid5(msg, key): + r""" + Return the Bifid cipher decryption of ``msg``. + + Explanation + =========== + + This is the version of the Bifid cipher that uses the `5 \times 5` + Polybius square; the letter "J" is ignored unless a ``key`` of + length 25 is used. + + Parameters + ========== + + msg + Ciphertext string. + + key + Short string for key; duplicated characters are ignored and if + the length is less then 25 characters, it will be padded with + other letters from the alphabet omitting "J". + Non-alphabetic characters are ignored. + + Returns + ======= + + plaintext + Plaintext from Bifid5 cipher (all caps, no spaces). + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_bifid5, decipher_bifid5 + >>> key = "gold bug" + >>> encipher_bifid5('meet me on friday', key) + 'IEILEHFSTSFXEE' + >>> encipher_bifid5('meet me on monday', key) + 'IEILHHFSTSFQYE' + >>> decipher_bifid5(_, key) + 'MEETMEONMONDAY' + + """ + msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid5) + key = padded_key(key, bifid5) + return decipher_bifid(msg, '', key) + + +def bifid5_square(key=None): + r""" + 5x5 Polybius square. + + Produce the Polybius square for the `5 \times 5` Bifid cipher. + + Examples + ======== + + >>> from sympy.crypto.crypto import bifid5_square + >>> bifid5_square("gold bug") + Matrix([ + [G, O, L, D, B], + [U, A, C, E, F], + [H, I, K, M, N], + [P, Q, R, S, T], + [V, W, X, Y, Z]]) + + """ + if not key: + key = bifid5 + else: + _, key, _ = _prep('', key.upper(), None, bifid5) + key = padded_key(key, bifid5) + return bifid_square(key) + + +def encipher_bifid6(msg, key): + r""" + Performs the Bifid cipher encryption on plaintext ``msg``, and + returns the ciphertext. + + This is the version of the Bifid cipher that uses the `6 \times 6` + Polybius square. + + Parameters + ========== + + msg + Plaintext string (digits okay). + + key + Short string for key (digits okay). + + If ``key`` is less than 36 characters long, the square will be + filled with letters A through Z and digits 0 through 9. + + Returns + ======= + + ciphertext + Ciphertext from Bifid cipher (all caps, no spaces). + + See Also + ======== + + decipher_bifid6, encipher_bifid + + """ + msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid6) + key = padded_key(key, bifid6) + return encipher_bifid(msg, '', key) + + +def decipher_bifid6(msg, key): + r""" + Performs the Bifid cipher decryption on ciphertext ``msg``, and + returns the plaintext. + + This is the version of the Bifid cipher that uses the `6 \times 6` + Polybius square. + + Parameters + ========== + + msg + Ciphertext string (digits okay); converted to upper case + + key + Short string for key (digits okay). + + If ``key`` is less than 36 characters long, the square will be + filled with letters A through Z and digits 0 through 9. + All letters are converted to uppercase. + + Returns + ======= + + plaintext + Plaintext from Bifid cipher (all caps, no spaces). + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_bifid6, decipher_bifid6 + >>> key = "gold bug" + >>> encipher_bifid6('meet me on monday at 8am', key) + 'KFKLJJHF5MMMKTFRGPL' + >>> decipher_bifid6(_, key) + 'MEETMEONMONDAYAT8AM' + + """ + msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid6) + key = padded_key(key, bifid6) + return decipher_bifid(msg, '', key) + + +def bifid6_square(key=None): + r""" + 6x6 Polybius square. + + Produces the Polybius square for the `6 \times 6` Bifid cipher. + Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "9". + + Examples + ======== + + >>> from sympy.crypto.crypto import bifid6_square + >>> key = "gold bug" + >>> bifid6_square(key) + Matrix([ + [G, O, L, D, B, U], + [A, C, E, F, H, I], + [J, K, M, N, P, Q], + [R, S, T, V, W, X], + [Y, Z, 0, 1, 2, 3], + [4, 5, 6, 7, 8, 9]]) + + """ + if not key: + key = bifid6 + else: + _, key, _ = _prep('', key.upper(), None, bifid6) + key = padded_key(key, bifid6) + return bifid_square(key) + + +#################### RSA ############################# + +def _decipher_rsa_crt(i, d, factors): + """Decipher RSA using chinese remainder theorem from the information + of the relatively-prime factors of the modulus. + + Parameters + ========== + + i : integer + Ciphertext + + d : integer + The exponent component. + + factors : list of relatively-prime integers + The integers given must be coprime and the product must equal + the modulus component of the original RSA key. + + Examples + ======== + + How to decrypt RSA with CRT: + + >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key + >>> primes = [61, 53] + >>> e = 17 + >>> args = primes + [e] + >>> puk = rsa_public_key(*args) + >>> prk = rsa_private_key(*args) + + >>> from sympy.crypto.crypto import encipher_rsa, _decipher_rsa_crt + >>> msg = 65 + >>> crt_primes = primes + >>> encrypted = encipher_rsa(msg, puk) + >>> decrypted = _decipher_rsa_crt(encrypted, prk[1], primes) + >>> decrypted + 65 + """ + moduluses = [pow(i, d, p) for p in factors] + + result = crt(factors, moduluses) + if not result: + raise ValueError("CRT failed") + return result[0] + + +def _rsa_key(*args, public=True, private=True, totient='Euler', index=None, multipower=None): + r"""A private subroutine to generate RSA key + + Parameters + ========== + + public, private : bool, optional + Flag to generate either a public key, a private key. + + totient : 'Euler' or 'Carmichael' + Different notation used for totient. + + multipower : bool, optional + Flag to bypass warning for multipower RSA. + """ + + if len(args) < 2: + return False + + if totient not in ('Euler', 'Carmichael'): + raise ValueError( + "The argument totient={} should either be " \ + "'Euler', 'Carmichalel'." \ + .format(totient)) + + if totient == 'Euler': + _totient = _euler + else: + _totient = _carmichael + + if index is not None: + index = as_int(index) + if totient != 'Carmichael': + raise ValueError( + "Setting the 'index' keyword argument requires totient" + "notation to be specified as 'Carmichael'.") + + primes, e = args[:-1], args[-1] + + if not all(isprime(p) for p in primes): + new_primes = [] + for i in primes: + new_primes.extend(factorint(i, multiple=True)) + primes = new_primes + + n = reduce(lambda i, j: i*j, primes) + + tally = multiset(primes) + if all(v == 1 for v in tally.values()): + phi = int(_totient(tally)) + + else: + if not multipower: + NonInvertibleCipherWarning( + 'Non-distinctive primes found in the factors {}. ' + 'The cipher may not be decryptable for some numbers ' + 'in the complete residue system Z[{}], but the cipher ' + 'can still be valid if you restrict the domain to be ' + 'the reduced residue system Z*[{}]. You can pass ' + 'the flag multipower=True if you want to suppress this ' + 'warning.' + .format(primes, n, n) + # stacklevel=4 because most users will call a function that + # calls this function + ).warn(stacklevel=4) + phi = int(_totient(tally)) + + if gcd(e, phi) == 1: + if public and not private: + if isinstance(index, int): + e = e % phi + e += index * phi + return n, e + + if private and not public: + d = invert(e, phi) + if isinstance(index, int): + d += index * phi + return n, d + + return False + + +def rsa_public_key(*args, **kwargs): + r"""Return the RSA *public key* pair, `(n, e)` + + Parameters + ========== + + args : naturals + If specified as `p, q, e` where `p` and `q` are distinct primes + and `e` is a desired public exponent of the RSA, `n = p q` and + `e` will be verified against the totient + `\phi(n)` (Euler totient) or `\lambda(n)` (Carmichael totient) + to be `\gcd(e, \phi(n)) = 1` or `\gcd(e, \lambda(n)) = 1`. + + If specified as `p_1, p_2, \dots, p_n, e` where + `p_1, p_2, \dots, p_n` are specified as primes, + and `e` is specified as a desired public exponent of the RSA, + it will be able to form a multi-prime RSA, which is a more + generalized form of the popular 2-prime RSA. + + It can also be possible to form a single-prime RSA by specifying + the argument as `p, e`, which can be considered a trivial case + of a multiprime RSA. + + Furthermore, it can be possible to form a multi-power RSA by + specifying two or more pairs of the primes to be same. + However, unlike the two-distinct prime RSA or multi-prime + RSA, not every numbers in the complete residue system + (`\mathbb{Z}_n`) will be decryptable since the mapping + `\mathbb{Z}_{n} \rightarrow \mathbb{Z}_{n}` + will not be bijective. + (Only except for the trivial case when + `e = 1` + or more generally, + + .. math:: + e \in \left \{ 1 + k \lambda(n) + \mid k \in \mathbb{Z} \land k \geq 0 \right \} + + when RSA reduces to the identity.) + However, the RSA can still be decryptable for the numbers in the + reduced residue system (`\mathbb{Z}_n^{\times}`), since the + mapping + `\mathbb{Z}_{n}^{\times} \rightarrow \mathbb{Z}_{n}^{\times}` + can still be bijective. + + If you pass a non-prime integer to the arguments + `p_1, p_2, \dots, p_n`, the particular number will be + prime-factored and it will become either a multi-prime RSA or a + multi-power RSA in its canonical form, depending on whether the + product equals its radical or not. + `p_1 p_2 \dots p_n = \text{rad}(p_1 p_2 \dots p_n)` + + totient : bool, optional + If ``'Euler'``, it uses Euler's totient `\phi(n)` which is + :meth:`sympy.functions.combinatorial.numbers.totient` in SymPy. + + If ``'Carmichael'``, it uses Carmichael's totient `\lambda(n)` + which is :meth:`sympy.functions.combinatorial.numbers.reduced_totient` in SymPy. + + Unlike private key generation, this is a trivial keyword for + public key generation because + `\gcd(e, \phi(n)) = 1 \iff \gcd(e, \lambda(n)) = 1`. + + index : nonnegative integer, optional + Returns an arbitrary solution of a RSA public key at the index + specified at `0, 1, 2, \dots`. This parameter needs to be + specified along with ``totient='Carmichael'``. + + Similarly to the non-uniquenss of a RSA private key as described + in the ``index`` parameter documentation in + :meth:`rsa_private_key`, RSA public key is also not unique and + there is an infinite number of RSA public exponents which + can behave in the same manner. + + From any given RSA public exponent `e`, there are can be an + another RSA public exponent `e + k \lambda(n)` where `k` is an + integer, `\lambda` is a Carmichael's totient function. + + However, considering only the positive cases, there can be + a principal solution of a RSA public exponent `e_0` in + `0 < e_0 < \lambda(n)`, and all the other solutions + can be canonicalzed in a form of `e_0 + k \lambda(n)`. + + ``index`` specifies the `k` notation to yield any possible value + an RSA public key can have. + + An example of computing any arbitrary RSA public key: + + >>> from sympy.crypto.crypto import rsa_public_key + >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=0) + (3233, 17) + >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=1) + (3233, 797) + >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=2) + (3233, 1577) + + multipower : bool, optional + Any pair of non-distinct primes found in the RSA specification + will restrict the domain of the cryptosystem, as noted in the + explanation of the parameter ``args``. + + SymPy RSA key generator may give a warning before dispatching it + as a multi-power RSA, however, you can disable the warning if + you pass ``True`` to this keyword. + + Returns + ======= + + (n, e) : int, int + `n` is a product of any arbitrary number of primes given as + the argument. + + `e` is relatively prime (coprime) to the Euler totient + `\phi(n)`. + + False + Returned if less than two arguments are given, or `e` is + not relatively prime to the modulus. + + Examples + ======== + + >>> from sympy.crypto.crypto import rsa_public_key + + A public key of a two-prime RSA: + + >>> p, q, e = 3, 5, 7 + >>> rsa_public_key(p, q, e) + (15, 7) + >>> rsa_public_key(p, q, 30) + False + + A public key of a multiprime RSA: + + >>> primes = [2, 3, 5, 7, 11, 13] + >>> e = 7 + >>> args = primes + [e] + >>> rsa_public_key(*args) + (30030, 7) + + Notes + ===== + + Although the RSA can be generalized over any modulus `n`, using + two large primes had became the most popular specification because a + product of two large primes is usually the hardest to factor + relatively to the digits of `n` can have. + + However, it may need further understanding of the time complexities + of each prime-factoring algorithms to verify the claim. + + See Also + ======== + + rsa_private_key + encipher_rsa + decipher_rsa + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29 + + .. [2] https://cacr.uwaterloo.ca/techreports/2006/cacr2006-16.pdf + + .. [3] https://link.springer.com/content/pdf/10.1007/BFb0055738.pdf + + .. [4] https://www.itiis.org/digital-library/manuscript/1381 + """ + return _rsa_key(*args, public=True, private=False, **kwargs) + + +def rsa_private_key(*args, **kwargs): + r"""Return the RSA *private key* pair, `(n, d)` + + Parameters + ========== + + args : naturals + The keyword is identical to the ``args`` in + :meth:`rsa_public_key`. + + totient : bool, optional + If ``'Euler'``, it uses Euler's totient convention `\phi(n)` + which is :meth:`sympy.functions.combinatorial.numbers.totient` in SymPy. + + If ``'Carmichael'``, it uses Carmichael's totient convention + `\lambda(n)` which is + :meth:`sympy.functions.combinatorial.numbers.reduced_totient` in SymPy. + + There can be some output differences for private key generation + as examples below. + + Example using Euler's totient: + + >>> from sympy.crypto.crypto import rsa_private_key + >>> rsa_private_key(61, 53, 17, totient='Euler') + (3233, 2753) + + Example using Carmichael's totient: + + >>> from sympy.crypto.crypto import rsa_private_key + >>> rsa_private_key(61, 53, 17, totient='Carmichael') + (3233, 413) + + index : nonnegative integer, optional + Returns an arbitrary solution of a RSA private key at the index + specified at `0, 1, 2, \dots`. This parameter needs to be + specified along with ``totient='Carmichael'``. + + RSA private exponent is a non-unique solution of + `e d \mod \lambda(n) = 1` and it is possible in any form of + `d + k \lambda(n)`, where `d` is an another + already-computed private exponent, and `\lambda` is a + Carmichael's totient function, and `k` is any integer. + + However, considering only the positive cases, there can be + a principal solution of a RSA private exponent `d_0` in + `0 < d_0 < \lambda(n)`, and all the other solutions + can be canonicalzed in a form of `d_0 + k \lambda(n)`. + + ``index`` specifies the `k` notation to yield any possible value + an RSA private key can have. + + An example of computing any arbitrary RSA private key: + + >>> from sympy.crypto.crypto import rsa_private_key + >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=0) + (3233, 413) + >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=1) + (3233, 1193) + >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=2) + (3233, 1973) + + multipower : bool, optional + The keyword is identical to the ``multipower`` in + :meth:`rsa_public_key`. + + Returns + ======= + + (n, d) : int, int + `n` is a product of any arbitrary number of primes given as + the argument. + + `d` is the inverse of `e` (mod `\phi(n)`) where `e` is the + exponent given, and `\phi` is a Euler totient. + + False + Returned if less than two arguments are given, or `e` is + not relatively prime to the totient of the modulus. + + Examples + ======== + + >>> from sympy.crypto.crypto import rsa_private_key + + A private key of a two-prime RSA: + + >>> p, q, e = 3, 5, 7 + >>> rsa_private_key(p, q, e) + (15, 7) + >>> rsa_private_key(p, q, 30) + False + + A private key of a multiprime RSA: + + >>> primes = [2, 3, 5, 7, 11, 13] + >>> e = 7 + >>> args = primes + [e] + >>> rsa_private_key(*args) + (30030, 823) + + See Also + ======== + + rsa_public_key + encipher_rsa + decipher_rsa + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29 + + .. [2] https://cacr.uwaterloo.ca/techreports/2006/cacr2006-16.pdf + + .. [3] https://link.springer.com/content/pdf/10.1007/BFb0055738.pdf + + .. [4] https://www.itiis.org/digital-library/manuscript/1381 + """ + return _rsa_key(*args, public=False, private=True, **kwargs) + + +def _encipher_decipher_rsa(i, key, factors=None): + n, d = key + if not factors: + return pow(i, d, n) + + def _is_coprime_set(l): + is_coprime_set = True + for i in range(len(l)): + for j in range(i+1, len(l)): + if gcd(l[i], l[j]) != 1: + is_coprime_set = False + break + return is_coprime_set + + prod = reduce(lambda i, j: i*j, factors) + if prod == n and _is_coprime_set(factors): + return _decipher_rsa_crt(i, d, factors) + return _encipher_decipher_rsa(i, key, factors=None) + + +def encipher_rsa(i, key, factors=None): + r"""Encrypt the plaintext with RSA. + + Parameters + ========== + + i : integer + The plaintext to be encrypted for. + + key : (n, e) where n, e are integers + `n` is the modulus of the key and `e` is the exponent of the + key. The encryption is computed by `i^e \bmod n`. + + The key can either be a public key or a private key, however, + the message encrypted by a public key can only be decrypted by + a private key, and vice versa, as RSA is an asymmetric + cryptography system. + + factors : list of coprime integers + This is identical to the keyword ``factors`` in + :meth:`decipher_rsa`. + + Notes + ===== + + Some specifications may make the RSA not cryptographically + meaningful. + + For example, `0`, `1` will remain always same after taking any + number of exponentiation, thus, should be avoided. + + Furthermore, if `i^e < n`, `i` may easily be figured out by taking + `e` th root. + + And also, specifying the exponent as `1` or in more generalized form + as `1 + k \lambda(n)` where `k` is an nonnegative integer, + `\lambda` is a carmichael totient, the RSA becomes an identity + mapping. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_rsa + >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key + + Public Key Encryption: + + >>> p, q, e = 3, 5, 7 + >>> puk = rsa_public_key(p, q, e) + >>> msg = 12 + >>> encipher_rsa(msg, puk) + 3 + + Private Key Encryption: + + >>> p, q, e = 3, 5, 7 + >>> prk = rsa_private_key(p, q, e) + >>> msg = 12 + >>> encipher_rsa(msg, prk) + 3 + + Encryption using chinese remainder theorem: + + >>> encipher_rsa(msg, prk, factors=[p, q]) + 3 + """ + return _encipher_decipher_rsa(i, key, factors=factors) + + +def decipher_rsa(i, key, factors=None): + r"""Decrypt the ciphertext with RSA. + + Parameters + ========== + + i : integer + The ciphertext to be decrypted for. + + key : (n, d) where n, d are integers + `n` is the modulus of the key and `d` is the exponent of the + key. The decryption is computed by `i^d \bmod n`. + + The key can either be a public key or a private key, however, + the message encrypted by a public key can only be decrypted by + a private key, and vice versa, as RSA is an asymmetric + cryptography system. + + factors : list of coprime integers + As the modulus `n` created from RSA key generation is composed + of arbitrary prime factors + `n = {p_1}^{k_1}{p_2}^{k_2}\dots{p_n}^{k_n}` where + `p_1, p_2, \dots, p_n` are distinct primes and + `k_1, k_2, \dots, k_n` are positive integers, chinese remainder + theorem can be used to compute `i^d \bmod n` from the + fragmented modulo operations like + + .. math:: + i^d \bmod {p_1}^{k_1}, i^d \bmod {p_2}^{k_2}, \dots, + i^d \bmod {p_n}^{k_n} + + or like + + .. math:: + i^d \bmod {p_1}^{k_1}{p_2}^{k_2}, + i^d \bmod {p_3}^{k_3}, \dots , + i^d \bmod {p_n}^{k_n} + + as long as every moduli does not share any common divisor each + other. + + The raw primes used in generating the RSA key pair can be a good + option. + + Note that the speed advantage of using this is only viable for + very large cases (Like 2048-bit RSA keys) since the + overhead of using pure Python implementation of + :meth:`sympy.ntheory.modular.crt` may overcompensate the + theoretical speed advantage. + + Notes + ===== + + See the ``Notes`` section in the documentation of + :meth:`encipher_rsa` + + Examples + ======== + + >>> from sympy.crypto.crypto import decipher_rsa, encipher_rsa + >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key + + Public Key Encryption and Decryption: + + >>> p, q, e = 3, 5, 7 + >>> prk = rsa_private_key(p, q, e) + >>> puk = rsa_public_key(p, q, e) + >>> msg = 12 + >>> new_msg = encipher_rsa(msg, prk) + >>> new_msg + 3 + >>> decipher_rsa(new_msg, puk) + 12 + + Private Key Encryption and Decryption: + + >>> p, q, e = 3, 5, 7 + >>> prk = rsa_private_key(p, q, e) + >>> puk = rsa_public_key(p, q, e) + >>> msg = 12 + >>> new_msg = encipher_rsa(msg, puk) + >>> new_msg + 3 + >>> decipher_rsa(new_msg, prk) + 12 + + Decryption using chinese remainder theorem: + + >>> decipher_rsa(new_msg, prk, factors=[p, q]) + 12 + + See Also + ======== + + encipher_rsa + """ + return _encipher_decipher_rsa(i, key, factors=factors) + + +#################### kid krypto (kid RSA) ############################# + + +def kid_rsa_public_key(a, b, A, B): + r""" + Kid RSA is a version of RSA useful to teach grade school children + since it does not involve exponentiation. + + Explanation + =========== + + Alice wants to talk to Bob. Bob generates keys as follows. + Key generation: + + * Select positive integers `a, b, A, B` at random. + * Compute `M = a b - 1`, `e = A M + a`, `d = B M + b`, + `n = (e d - 1)//M`. + * The *public key* is `(n, e)`. Bob sends these to Alice. + * The *private key* is `(n, d)`, which Bob keeps secret. + + Encryption: If `p` is the plaintext message then the + ciphertext is `c = p e \pmod n`. + + Decryption: If `c` is the ciphertext message then the + plaintext is `p = c d \pmod n`. + + Examples + ======== + + >>> from sympy.crypto.crypto import kid_rsa_public_key + >>> a, b, A, B = 3, 4, 5, 6 + >>> kid_rsa_public_key(a, b, A, B) + (369, 58) + + """ + M = a*b - 1 + e = A*M + a + d = B*M + b + n = (e*d - 1)//M + return n, e + + +def kid_rsa_private_key(a, b, A, B): + """ + Compute `M = a b - 1`, `e = A M + a`, `d = B M + b`, + `n = (e d - 1) / M`. The *private key* is `d`, which Bob + keeps secret. + + Examples + ======== + + >>> from sympy.crypto.crypto import kid_rsa_private_key + >>> a, b, A, B = 3, 4, 5, 6 + >>> kid_rsa_private_key(a, b, A, B) + (369, 70) + + """ + M = a*b - 1 + e = A*M + a + d = B*M + b + n = (e*d - 1)//M + return n, d + + +def encipher_kid_rsa(msg, key): + """ + Here ``msg`` is the plaintext and ``key`` is the public key. + + Examples + ======== + + >>> from sympy.crypto.crypto import ( + ... encipher_kid_rsa, kid_rsa_public_key) + >>> msg = 200 + >>> a, b, A, B = 3, 4, 5, 6 + >>> key = kid_rsa_public_key(a, b, A, B) + >>> encipher_kid_rsa(msg, key) + 161 + + """ + n, e = key + return (msg*e) % n + + +def decipher_kid_rsa(msg, key): + """ + Here ``msg`` is the plaintext and ``key`` is the private key. + + Examples + ======== + + >>> from sympy.crypto.crypto import ( + ... kid_rsa_public_key, kid_rsa_private_key, + ... decipher_kid_rsa, encipher_kid_rsa) + >>> a, b, A, B = 3, 4, 5, 6 + >>> d = kid_rsa_private_key(a, b, A, B) + >>> msg = 200 + >>> pub = kid_rsa_public_key(a, b, A, B) + >>> pri = kid_rsa_private_key(a, b, A, B) + >>> ct = encipher_kid_rsa(msg, pub) + >>> decipher_kid_rsa(ct, pri) + 200 + + """ + n, d = key + return (msg*d) % n + + +#################### Morse Code ###################################### + +morse_char = { + ".-": "A", "-...": "B", + "-.-.": "C", "-..": "D", + ".": "E", "..-.": "F", + "--.": "G", "....": "H", + "..": "I", ".---": "J", + "-.-": "K", ".-..": "L", + "--": "M", "-.": "N", + "---": "O", ".--.": "P", + "--.-": "Q", ".-.": "R", + "...": "S", "-": "T", + "..-": "U", "...-": "V", + ".--": "W", "-..-": "X", + "-.--": "Y", "--..": "Z", + "-----": "0", ".----": "1", + "..---": "2", "...--": "3", + "....-": "4", ".....": "5", + "-....": "6", "--...": "7", + "---..": "8", "----.": "9", + ".-.-.-": ".", "--..--": ",", + "---...": ":", "-.-.-.": ";", + "..--..": "?", "-....-": "-", + "..--.-": "_", "-.--.": "(", + "-.--.-": ")", ".----.": "'", + "-...-": "=", ".-.-.": "+", + "-..-.": "/", ".--.-.": "@", + "...-..-": "$", "-.-.--": "!"} +char_morse = {v: k for k, v in morse_char.items()} + + +def encode_morse(msg, sep='|', mapping=None): + """ + Encodes a plaintext into popular Morse Code with letters + separated by ``sep`` and words by a double ``sep``. + + Examples + ======== + + >>> from sympy.crypto.crypto import encode_morse + >>> msg = 'ATTACK RIGHT FLANK' + >>> encode_morse(msg) + '.-|-|-|.-|-.-.|-.-||.-.|..|--.|....|-||..-.|.-..|.-|-.|-.-' + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Morse_code + + """ + + mapping = mapping or char_morse + assert sep not in mapping + word_sep = 2*sep + mapping[" "] = word_sep + suffix = msg and msg[-1] in whitespace + + # normalize whitespace + msg = (' ' if word_sep else '').join(msg.split()) + # omit unmapped chars + chars = set(''.join(msg.split())) + ok = set(mapping.keys()) + msg = translate(msg, None, ''.join(chars - ok)) + + morsestring = [] + words = msg.split() + for word in words: + morseword = [] + for letter in word: + morseletter = mapping[letter] + morseword.append(morseletter) + + word = sep.join(morseword) + morsestring.append(word) + + return word_sep.join(morsestring) + (word_sep if suffix else '') + + +def decode_morse(msg, sep='|', mapping=None): + """ + Decodes a Morse Code with letters separated by ``sep`` + (default is '|') and words by `word_sep` (default is '||) + into plaintext. + + Examples + ======== + + >>> from sympy.crypto.crypto import decode_morse + >>> mc = '--|---|...-|.||.|.-|...|-' + >>> decode_morse(mc) + 'MOVE EAST' + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Morse_code + + """ + + mapping = mapping or morse_char + word_sep = 2*sep + characterstring = [] + words = msg.strip(word_sep).split(word_sep) + for word in words: + letters = word.split(sep) + chars = [mapping[c] for c in letters] + word = ''.join(chars) + characterstring.append(word) + rv = " ".join(characterstring) + return rv + + +#################### LFSRs ########################################## + + +@doctest_depends_on(ground_types=['python', 'gmpy']) +def lfsr_sequence(key, fill, n): + r""" + This function creates an LFSR sequence. + + Parameters + ========== + + key : list + A list of finite field elements, `[c_0, c_1, \ldots, c_k].` + + fill : list + The list of the initial terms of the LFSR sequence, + `[x_0, x_1, \ldots, x_k].` + + n + Number of terms of the sequence that the function returns. + + Returns + ======= + + L + The LFSR sequence defined by + `x_{n+1} = c_k x_n + \ldots + c_0 x_{n-k}`, for + `n \leq k`. + + Notes + ===== + + S. Golomb [G]_ gives a list of three statistical properties a + sequence of numbers `a = \{a_n\}_{n=1}^\infty`, + `a_n \in \{0,1\}`, should display to be considered + "random". Define the autocorrelation of `a` to be + + .. math:: + + C(k) = C(k,a) = \lim_{N\rightarrow \infty} {1\over N}\sum_{n=1}^N (-1)^{a_n + a_{n+k}}. + + In the case where `a` is periodic with period + `P` then this reduces to + + .. math:: + + C(k) = {1\over P}\sum_{n=1}^P (-1)^{a_n + a_{n+k}}. + + Assume `a` is periodic with period `P`. + + - balance: + + .. math:: + + \left|\sum_{n=1}^P(-1)^{a_n}\right| \leq 1. + + - low autocorrelation: + + .. math:: + + C(k) = \left\{ \begin{array}{cc} 1,& k = 0,\\ \epsilon, & k \ne 0. \end{array} \right. + + (For sequences satisfying these first two properties, it is known + that `\epsilon = -1/P` must hold.) + + - proportional runs property: In each period, half the runs have + length `1`, one-fourth have length `2`, etc. + Moreover, there are as many runs of `1`'s as there are of + `0`'s. + + Examples + ======== + + >>> from sympy.crypto.crypto import lfsr_sequence + >>> from sympy.polys.domains import FF + >>> F = FF(2) + >>> fill = [F(1), F(1), F(0), F(1)] + >>> key = [F(1), F(0), F(0), F(1)] + >>> lfsr_sequence(key, fill, 10) + [1 mod 2, 1 mod 2, 0 mod 2, 1 mod 2, 0 mod 2, + 1 mod 2, 1 mod 2, 0 mod 2, 0 mod 2, 1 mod 2] + + References + ========== + + .. [G] Solomon Golomb, Shift register sequences, Aegean Park Press, + Laguna Hills, Ca, 1967 + + """ + if not isinstance(key, list): + raise TypeError("key must be a list") + if not isinstance(fill, list): + raise TypeError("fill must be a list") + p = key[0].modulus() + F = FF(p) + s = fill + k = len(fill) + L = [] + for i in range(n): + s0 = s[:] + L.append(s[0]) + s = s[1:k] + x = sum(int(key[i]*s0[i]) for i in range(k)) + s.append(F(x)) + return L # use [int(x) for x in L] for int version + + +def lfsr_autocorrelation(L, P, k): + """ + This function computes the LFSR autocorrelation function. + + Parameters + ========== + + L + A periodic sequence of elements of `GF(2)`. + L must have length larger than P. + + P + The period of L. + + k : int + An integer `k` (`0 < k < P`). + + Returns + ======= + + autocorrelation + The k-th value of the autocorrelation of the LFSR L. + + Examples + ======== + + >>> from sympy.crypto.crypto import ( + ... lfsr_sequence, lfsr_autocorrelation) + >>> from sympy.polys.domains import FF + >>> F = FF(2) + >>> fill = [F(1), F(1), F(0), F(1)] + >>> key = [F(1), F(0), F(0), F(1)] + >>> s = lfsr_sequence(key, fill, 20) + >>> lfsr_autocorrelation(s, 15, 7) + -1/15 + >>> lfsr_autocorrelation(s, 15, 0) + 1 + + """ + if not isinstance(L, list): + raise TypeError("L (=%s) must be a list" % L) + P = int(P) + k = int(k) + L0 = L[:P] # slices makes a copy + L1 = L0 + L0[:k] + L2 = [(-1)**(int(L1[i]) + int(L1[i + k])) for i in range(P)] + tot = sum(L2) + return Rational(tot, P) + + +def lfsr_connection_polynomial(s): + """ + This function computes the LFSR connection polynomial. + + Parameters + ========== + + s + A sequence of elements of even length, with entries in a finite + field. + + Returns + ======= + + C(x) + The connection polynomial of a minimal LFSR yielding s. + + This implements the algorithm in section 3 of J. L. Massey's + article [M]_. + + Examples + ======== + + >>> from sympy.crypto.crypto import ( + ... lfsr_sequence, lfsr_connection_polynomial) + >>> from sympy.polys.domains import FF + >>> F = FF(2) + >>> fill = [F(1), F(1), F(0), F(1)] + >>> key = [F(1), F(0), F(0), F(1)] + >>> s = lfsr_sequence(key, fill, 20) + >>> lfsr_connection_polynomial(s) + x**4 + x + 1 + >>> fill = [F(1), F(0), F(0), F(1)] + >>> key = [F(1), F(1), F(0), F(1)] + >>> s = lfsr_sequence(key, fill, 20) + >>> lfsr_connection_polynomial(s) + x**3 + 1 + >>> fill = [F(1), F(0), F(1)] + >>> key = [F(1), F(1), F(0)] + >>> s = lfsr_sequence(key, fill, 20) + >>> lfsr_connection_polynomial(s) + x**3 + x**2 + 1 + >>> fill = [F(1), F(0), F(1)] + >>> key = [F(1), F(0), F(1)] + >>> s = lfsr_sequence(key, fill, 20) + >>> lfsr_connection_polynomial(s) + x**3 + x + 1 + + References + ========== + + .. [M] James L. Massey, "Shift-Register Synthesis and BCH Decoding." + IEEE Trans. on Information Theory, vol. 15(1), pp. 122-127, + Jan 1969. + + """ + # Initialization: + p = s[0].modulus() + x = Symbol("x") + C = 1*x**0 + B = 1*x**0 + m = 1 + b = 1*x**0 + L = 0 + N = 0 + while N < len(s): + if L > 0: + dC = Poly(C).degree() + r = min(L + 1, dC + 1) + coeffsC = [C.subs(x, 0)] + [C.coeff(x**i) + for i in range(1, dC + 1)] + d = (int(s[N]) + sum(coeffsC[i]*int(s[N - i]) + for i in range(1, r))) % p + if L == 0: + d = int(s[N])*x**0 + if d == 0: + m += 1 + N += 1 + if d > 0: + if 2*L > N: + C = (C - d*((b**(p - 2)) % p)*x**m*B).expand() + m += 1 + N += 1 + else: + T = C + C = (C - d*((b**(p - 2)) % p)*x**m*B).expand() + L = N + 1 - L + m = 1 + b = d + B = T + N += 1 + dC = Poly(C).degree() + coeffsC = [C.subs(x, 0)] + [C.coeff(x**i) for i in range(1, dC + 1)] + return sum(coeffsC[i] % p*x**i for i in range(dC + 1) + if coeffsC[i] is not None) + + +#################### ElGamal ############################# + + +def elgamal_private_key(digit=10, seed=None): + r""" + Return three number tuple as private key. + + Explanation + =========== + + Elgamal encryption is based on the mathematical problem + called the Discrete Logarithm Problem (DLP). For example, + + `a^{b} \equiv c \pmod p` + + In general, if ``a`` and ``b`` are known, ``ct`` is easily + calculated. If ``b`` is unknown, it is hard to use + ``a`` and ``ct`` to get ``b``. + + Parameters + ========== + + digit : int + Minimum number of binary digits for key. + + Returns + ======= + + tuple : (p, r, d) + p = prime number. + + r = primitive root. + + d = random number. + + Notes + ===== + + For testing purposes, the ``seed`` parameter may be set to control + the output of this routine. See sympy.core.random._randrange. + + Examples + ======== + + >>> from sympy.crypto.crypto import elgamal_private_key + >>> from sympy.ntheory import is_primitive_root, isprime + >>> a, b, _ = elgamal_private_key() + >>> isprime(a) + True + >>> is_primitive_root(b, a) + True + + """ + randrange = _randrange(seed) + p = nextprime(2**digit) + return p, primitive_root(p), randrange(2, p) + + +def elgamal_public_key(key): + r""" + Return three number tuple as public key. + + Parameters + ========== + + key : (p, r, e) + Tuple generated by ``elgamal_private_key``. + + Returns + ======= + + tuple : (p, r, e) + `e = r**d \bmod p` + + `d` is a random number in private key. + + Examples + ======== + + >>> from sympy.crypto.crypto import elgamal_public_key + >>> elgamal_public_key((1031, 14, 636)) + (1031, 14, 212) + + """ + p, r, e = key + return p, r, pow(r, e, p) + + +def encipher_elgamal(i, key, seed=None): + r""" + Encrypt message with public key. + + Explanation + =========== + + ``i`` is a plaintext message expressed as an integer. + ``key`` is public key (p, r, e). In order to encrypt + a message, a random number ``a`` in ``range(2, p)`` + is generated and the encrypted message is returned as + `c_{1}` and `c_{2}` where: + + `c_{1} \equiv r^{a} \pmod p` + + `c_{2} \equiv m e^{a} \pmod p` + + Parameters + ========== + + msg + int of encoded message. + + key + Public key. + + Returns + ======= + + tuple : (c1, c2) + Encipher into two number. + + Notes + ===== + + For testing purposes, the ``seed`` parameter may be set to control + the output of this routine. See sympy.core.random._randrange. + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_elgamal, elgamal_private_key, elgamal_public_key + >>> pri = elgamal_private_key(5, seed=[3]); pri + (37, 2, 3) + >>> pub = elgamal_public_key(pri); pub + (37, 2, 8) + >>> msg = 36 + >>> encipher_elgamal(msg, pub, seed=[3]) + (8, 6) + + """ + p, r, e = key + if i < 0 or i >= p: + raise ValueError( + 'Message (%s) should be in range(%s)' % (i, p)) + randrange = _randrange(seed) + a = randrange(2, p) + return pow(r, a, p), i*pow(e, a, p) % p + + +def decipher_elgamal(msg, key): + r""" + Decrypt message with private key. + + `msg = (c_{1}, c_{2})` + + `key = (p, r, d)` + + According to extended Eucliden theorem, + `u c_{1}^{d} + p n = 1` + + `u \equiv 1/{{c_{1}}^d} \pmod p` + + `u c_{2} \equiv \frac{1}{c_{1}^d} c_{2} \equiv \frac{1}{r^{ad}} c_{2} \pmod p` + + `\frac{1}{r^{ad}} m e^a \equiv \frac{1}{r^{ad}} m {r^{d a}} \equiv m \pmod p` + + Examples + ======== + + >>> from sympy.crypto.crypto import decipher_elgamal + >>> from sympy.crypto.crypto import encipher_elgamal + >>> from sympy.crypto.crypto import elgamal_private_key + >>> from sympy.crypto.crypto import elgamal_public_key + + >>> pri = elgamal_private_key(5, seed=[3]) + >>> pub = elgamal_public_key(pri); pub + (37, 2, 8) + >>> msg = 17 + >>> decipher_elgamal(encipher_elgamal(msg, pub), pri) == msg + True + + """ + p, _, d = key + c1, c2 = msg + u = pow(c1, -d, p) + return u * c2 % p + + +################ Diffie-Hellman Key Exchange ######################### + +def dh_private_key(digit=10, seed=None): + r""" + Return three integer tuple as private key. + + Explanation + =========== + + Diffie-Hellman key exchange is based on the mathematical problem + called the Discrete Logarithm Problem (see ElGamal). + + Diffie-Hellman key exchange is divided into the following steps: + + * Alice and Bob agree on a base that consist of a prime ``p`` + and a primitive root of ``p`` called ``g`` + * Alice choses a number ``a`` and Bob choses a number ``b`` where + ``a`` and ``b`` are random numbers in range `[2, p)`. These are + their private keys. + * Alice then publicly sends Bob `g^{a} \pmod p` while Bob sends + Alice `g^{b} \pmod p` + * They both raise the received value to their secretly chosen + number (``a`` or ``b``) and now have both as their shared key + `g^{ab} \pmod p` + + Parameters + ========== + + digit + Minimum number of binary digits required in key. + + Returns + ======= + + tuple : (p, g, a) + p = prime number. + + g = primitive root of p. + + a = random number from 2 through p - 1. + + Notes + ===== + + For testing purposes, the ``seed`` parameter may be set to control + the output of this routine. See sympy.core.random._randrange. + + Examples + ======== + + >>> from sympy.crypto.crypto import dh_private_key + >>> from sympy.ntheory import isprime, is_primitive_root + >>> p, g, _ = dh_private_key() + >>> isprime(p) + True + >>> is_primitive_root(g, p) + True + >>> p, g, _ = dh_private_key(5) + >>> isprime(p) + True + >>> is_primitive_root(g, p) + True + + """ + p = nextprime(2**digit) + g = primitive_root(p) + randrange = _randrange(seed) + a = randrange(2, p) + return p, g, a + + +def dh_public_key(key): + r""" + Return three number tuple as public key. + + This is the tuple that Alice sends to Bob. + + Parameters + ========== + + key : (p, g, a) + A tuple generated by ``dh_private_key``. + + Returns + ======= + + tuple : int, int, int + A tuple of `(p, g, g^a \mod p)` with `p`, `g` and `a` given as + parameters.s + + Examples + ======== + + >>> from sympy.crypto.crypto import dh_private_key, dh_public_key + >>> p, g, a = dh_private_key(); + >>> _p, _g, x = dh_public_key((p, g, a)) + >>> p == _p and g == _g + True + >>> x == pow(g, a, p) + True + + """ + p, g, a = key + return p, g, pow(g, a, p) + + +def dh_shared_key(key, b): + """ + Return an integer that is the shared key. + + This is what Bob and Alice can both calculate using the public + keys they received from each other and their private keys. + + Parameters + ========== + + key : (p, g, x) + Tuple `(p, g, x)` generated by ``dh_public_key``. + + b + Random number in the range of `2` to `p - 1` + (Chosen by second key exchange member (Bob)). + + Returns + ======= + + int + A shared key. + + Examples + ======== + + >>> from sympy.crypto.crypto import ( + ... dh_private_key, dh_public_key, dh_shared_key) + >>> prk = dh_private_key(); + >>> p, g, x = dh_public_key(prk); + >>> sk = dh_shared_key((p, g, x), 1000) + >>> sk == pow(x, 1000, p) + True + + """ + p, _, x = key + if 1 >= b or b >= p: + raise ValueError(filldedent(''' + Value of b should be greater 1 and less + than prime %s.''' % p)) + + return pow(x, b, p) + + +################ Goldwasser-Micali Encryption ######################### + + +def _legendre(a, p): + """ + Returns the legendre symbol of a and p + assuming that p is a prime. + + i.e. 1 if a is a quadratic residue mod p + -1 if a is not a quadratic residue mod p + 0 if a is divisible by p + + Parameters + ========== + + a : int + The number to test. + + p : prime + The prime to test ``a`` against. + + Returns + ======= + + int + Legendre symbol (a / p). + + """ + sig = pow(a, (p - 1)//2, p) + if sig == 1: + return 1 + elif sig == 0: + return 0 + else: + return -1 + + +def _random_coprime_stream(n, seed=None): + randrange = _randrange(seed) + while True: + y = randrange(n) + if gcd(y, n) == 1: + yield y + + +def gm_private_key(p, q, a=None): + r""" + Check if ``p`` and ``q`` can be used as private keys for + the Goldwasser-Micali encryption. The method works + roughly as follows. + + Explanation + =========== + + #. Pick two large primes $p$ and $q$. + #. Call their product $N$. + #. Given a message as an integer $i$, write $i$ in its bit representation $b_0, \dots, b_n$. + #. For each $k$, + + if $b_k = 0$: + let $a_k$ be a random square + (quadratic residue) modulo $p q$ + such that ``jacobi_symbol(a, p*q) = 1`` + if $b_k = 1$: + let $a_k$ be a random non-square + (non-quadratic residue) modulo $p q$ + such that ``jacobi_symbol(a, p*q) = 1`` + + returns $\left[a_1, a_2, \dots\right]$ + + $b_k$ can be recovered by checking whether or not + $a_k$ is a residue. And from the $b_k$'s, the message + can be reconstructed. + + The idea is that, while ``jacobi_symbol(a, p*q)`` + can be easily computed (and when it is equal to $-1$ will + tell you that $a$ is not a square mod $p q$), quadratic + residuosity modulo a composite number is hard to compute + without knowing its factorization. + + Moreover, approximately half the numbers coprime to $p q$ have + :func:`~.jacobi_symbol` equal to $1$ . And among those, approximately half + are residues and approximately half are not. This maximizes the + entropy of the code. + + Parameters + ========== + + p, q, a + Initialization variables. + + Returns + ======= + + tuple : (p, q) + The input value ``p`` and ``q``. + + Raises + ====== + + ValueError + If ``p`` and ``q`` are not distinct odd primes. + + """ + if p == q: + raise ValueError("expected distinct primes, " + "got two copies of %i" % p) + elif not isprime(p) or not isprime(q): + raise ValueError("first two arguments must be prime, " + "got %i of %i" % (p, q)) + elif p == 2 or q == 2: + raise ValueError("first two arguments must not be even, " + "got %i of %i" % (p, q)) + return p, q + + +def gm_public_key(p, q, a=None, seed=None): + """ + Compute public keys for ``p`` and ``q``. + Note that in Goldwasser-Micali Encryption, + public keys are randomly selected. + + Parameters + ========== + + p, q, a : int, int, int + Initialization variables. + + Returns + ======= + + tuple : (a, N) + ``a`` is the input ``a`` if it is not ``None`` otherwise + some random integer coprime to ``p`` and ``q``. + + ``N`` is the product of ``p`` and ``q``. + + """ + + p, q = gm_private_key(p, q) + N = p * q + + if a is None: + randrange = _randrange(seed) + while True: + a = randrange(N) + if _legendre(a, p) == _legendre(a, q) == -1: + break + else: + if _legendre(a, p) != -1 or _legendre(a, q) != -1: + return False + return (a, N) + + +def encipher_gm(i, key, seed=None): + """ + Encrypt integer 'i' using public_key 'key' + Note that gm uses random encryption. + + Parameters + ========== + + i : int + The message to encrypt. + + key : (a, N) + The public key. + + Returns + ======= + + list : list of int + The randomized encrypted message. + + """ + if i < 0: + raise ValueError( + "message must be a non-negative " + "integer: got %d instead" % i) + a, N = key + bits = [] + while i > 0: + bits.append(i % 2) + i //= 2 + + gen = _random_coprime_stream(N, seed) + rev = reversed(bits) + encode = lambda b: next(gen)**2*pow(a, b) % N + return [ encode(b) for b in rev ] + + + +def decipher_gm(message, key): + """ + Decrypt message 'message' using public_key 'key'. + + Parameters + ========== + + message : list of int + The randomized encrypted message. + + key : (p, q) + The private key. + + Returns + ======= + + int + The encrypted message. + + """ + p, q = key + res = lambda m, p: _legendre(m, p) > 0 + bits = [res(m, p) * res(m, q) for m in message] + m = 0 + for b in bits: + m <<= 1 + m += not b + return m + + + +########### RailFence Cipher ############# + +def encipher_railfence(message,rails): + """ + Performs Railfence Encryption on plaintext and returns ciphertext + + Examples + ======== + + >>> from sympy.crypto.crypto import encipher_railfence + >>> message = "hello world" + >>> encipher_railfence(message,3) + 'horel ollwd' + + Parameters + ========== + + message : string, the message to encrypt. + rails : int, the number of rails. + + Returns + ======= + + The Encrypted string message. + + References + ========== + .. [1] https://en.wikipedia.org/wiki/Rail_fence_cipher + + """ + r = list(range(rails)) + p = cycle(r + r[-2:0:-1]) + return ''.join(sorted(message, key=lambda i: next(p))) + + +def decipher_railfence(ciphertext,rails): + """ + Decrypt the message using the given rails + + Examples + ======== + + >>> from sympy.crypto.crypto import decipher_railfence + >>> decipher_railfence("horel ollwd",3) + 'hello world' + + Parameters + ========== + + message : string, the message to encrypt. + rails : int, the number of rails. + + Returns + ======= + + The Decrypted string message. + + """ + r = list(range(rails)) + p = cycle(r + r[-2:0:-1]) + + idx = sorted(range(len(ciphertext)), key=lambda i: next(p)) + res = [''] * len(ciphertext) + for i, c in zip(idx, ciphertext): + res[i] = c + return ''.join(res) + + +################ Blum-Goldwasser cryptosystem ######################### + +def bg_private_key(p, q): + """ + Check if p and q can be used as private keys for + the Blum-Goldwasser cryptosystem. + + Explanation + =========== + + The three necessary checks for p and q to pass + so that they can be used as private keys: + + 1. p and q must both be prime + 2. p and q must be distinct + 3. p and q must be congruent to 3 mod 4 + + Parameters + ========== + + p, q + The keys to be checked. + + Returns + ======= + + p, q + Input values. + + Raises + ====== + + ValueError + If p and q do not pass the above conditions. + + """ + + if not isprime(p) or not isprime(q): + raise ValueError("the two arguments must be prime, " + "got %i and %i" %(p, q)) + elif p == q: + raise ValueError("the two arguments must be distinct, " + "got two copies of %i. " %p) + elif (p - 3) % 4 != 0 or (q - 3) % 4 != 0: + raise ValueError("the two arguments must be congruent to 3 mod 4, " + "got %i and %i" %(p, q)) + return p, q + +def bg_public_key(p, q): + """ + Calculates public keys from private keys. + + Explanation + =========== + + The function first checks the validity of + private keys passed as arguments and + then returns their product. + + Parameters + ========== + + p, q + The private keys. + + Returns + ======= + + N + The public key. + + """ + p, q = bg_private_key(p, q) + N = p * q + return N + +def encipher_bg(i, key, seed=None): + """ + Encrypts the message using public key and seed. + + Explanation + =========== + + ALGORITHM: + 1. Encodes i as a string of L bits, m. + 2. Select a random element r, where 1 < r < key, and computes + x = r^2 mod key. + 3. Use BBS pseudo-random number generator to generate L random bits, b, + using the initial seed as x. + 4. Encrypted message, c_i = m_i XOR b_i, 1 <= i <= L. + 5. x_L = x^(2^L) mod key. + 6. Return (c, x_L) + + Parameters + ========== + + i + Message, a non-negative integer + + key + The public key + + Returns + ======= + + Tuple + (encrypted_message, x_L) + + Raises + ====== + + ValueError + If i is negative. + + """ + + if i < 0: + raise ValueError( + "message must be a non-negative " + "integer: got %d instead" % i) + + enc_msg = [] + while i > 0: + enc_msg.append(i % 2) + i //= 2 + enc_msg.reverse() + L = len(enc_msg) + + r = _randint(seed)(2, key - 1) + x = r**2 % key + x_L = pow(int(x), int(2**L), int(key)) + + rand_bits = [] + for _ in range(L): + rand_bits.append(x % 2) + x = x**2 % key + + encrypt_msg = [m ^ b for (m, b) in zip(enc_msg, rand_bits)] + + return (encrypt_msg, x_L) + +def decipher_bg(message, key): + """ + Decrypts the message using private keys. + + Explanation + =========== + + ALGORITHM: + 1. Let, c be the encrypted message, y the second number received, + and p and q be the private keys. + 2. Compute, r_p = y^((p+1)/4 ^ L) mod p and + r_q = y^((q+1)/4 ^ L) mod q. + 3. Compute x_0 = (q(q^-1 mod p)r_p + p(p^-1 mod q)r_q) mod N. + 4. From, recompute the bits using the BBS generator, as in the + encryption algorithm. + 5. Compute original message by XORing c and b. + + Parameters + ========== + + message + Tuple of encrypted message and a non-negative integer. + + key + Tuple of private keys. + + Returns + ======= + + orig_msg + The original message + + """ + + p, q = key + encrypt_msg, y = message + public_key = p * q + L = len(encrypt_msg) + p_t = ((p + 1)/4)**L + q_t = ((q + 1)/4)**L + r_p = pow(int(y), int(p_t), int(p)) + r_q = pow(int(y), int(q_t), int(q)) + + x = (q * invert(q, p) * r_p + p * invert(p, q) * r_q) % public_key + + orig_bits = [] + for _ in range(L): + orig_bits.append(x % 2) + x = x**2 % public_key + + orig_msg = 0 + for (m, b) in zip(encrypt_msg, orig_bits): + orig_msg = orig_msg * 2 + orig_msg += (m ^ b) + + return orig_msg diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8846a99510601c9675103e21ef5a0a1e839fdd11 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/__init__.py @@ -0,0 +1,19 @@ +from .diffgeom import ( + BaseCovarDerivativeOp, BaseScalarField, BaseVectorField, Commutator, + contravariant_order, CoordSystem, CoordinateSymbol, + CovarDerivativeOp, covariant_order, Differential, intcurve_diffequ, + intcurve_series, LieDerivative, Manifold, metric_to_Christoffel_1st, + metric_to_Christoffel_2nd, metric_to_Ricci_components, + metric_to_Riemann_components, Patch, Point, TensorProduct, twoform_to_matrix, + vectors_in_basis, WedgeProduct, +) + +__all__ = [ + 'BaseCovarDerivativeOp', 'BaseScalarField', 'BaseVectorField', 'Commutator', + 'contravariant_order', 'CoordSystem', 'CoordinateSymbol', + 'CovarDerivativeOp', 'covariant_order', 'Differential', 'intcurve_diffequ', + 'intcurve_series', 'LieDerivative', 'Manifold', 'metric_to_Christoffel_1st', + 'metric_to_Christoffel_2nd', 'metric_to_Ricci_components', + 'metric_to_Riemann_components', 'Patch', 'Point', 'TensorProduct', + 'twoform_to_matrix', 'vectors_in_basis', 'WedgeProduct', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/diffgeom.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/diffgeom.py new file mode 100644 index 0000000000000000000000000000000000000000..a95f83122d6de0b7015b9a3ad0573cbfd97a7ef3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/diffgeom.py @@ -0,0 +1,2270 @@ +from __future__ import annotations +from typing import Any + +from functools import reduce +from itertools import permutations + +from sympy.combinatorics import Permutation +from sympy.core import ( + Basic, Expr, Function, diff, + Pow, Mul, Add, Lambda, S, Tuple, Dict +) +from sympy.core.cache import cacheit + +from sympy.core.symbol import Symbol, Dummy +from sympy.core.symbol import Str +from sympy.core.sympify import _sympify +from sympy.functions import factorial +from sympy.matrices import ImmutableDenseMatrix as Matrix +from sympy.solvers import solve + +from sympy.utilities.exceptions import (sympy_deprecation_warning, + SymPyDeprecationWarning, + ignore_warnings) + + +# TODO you are a bit excessive in the use of Dummies +# TODO dummy point, literal field +# TODO too often one needs to call doit or simplify on the output, check the +# tests and find out why +from sympy.tensor.array import ImmutableDenseNDimArray + + +class Manifold(Basic): + """ + A mathematical manifold. + + Explanation + =========== + + A manifold is a topological space that locally resembles + Euclidean space near each point [1]. + This class does not provide any means to study the topological + characteristics of the manifold that it represents, though. + + Parameters + ========== + + name : str + The name of the manifold. + + dim : int + The dimension of the manifold. + + Examples + ======== + + >>> from sympy.diffgeom import Manifold + >>> m = Manifold('M', 2) + >>> m + M + >>> m.dim + 2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Manifold + """ + + def __new__(cls, name, dim, **kwargs): + if not isinstance(name, Str): + name = Str(name) + dim = _sympify(dim) + obj = super().__new__(cls, name, dim) + + obj.patches = _deprecated_list( + """ + Manifold.patches is deprecated. The Manifold object is now + immutable. Instead use a separate list to keep track of the + patches. + """, []) + return obj + + @property + def name(self): + return self.args[0] + + @property + def dim(self): + return self.args[1] + + +class Patch(Basic): + """ + A patch on a manifold. + + Explanation + =========== + + Coordinate patch, or patch in short, is a simply-connected open set around + a point in the manifold [1]. On a manifold one can have many patches that + do not always include the whole manifold. On these patches coordinate + charts can be defined that permit the parameterization of any point on the + patch in terms of a tuple of real numbers (the coordinates). + + This class does not provide any means to study the topological + characteristics of the patch that it represents. + + Parameters + ========== + + name : str + The name of the patch. + + manifold : Manifold + The manifold on which the patch is defined. + + Examples + ======== + + >>> from sympy.diffgeom import Manifold, Patch + >>> m = Manifold('M', 2) + >>> p = Patch('P', m) + >>> p + P + >>> p.dim + 2 + + References + ========== + + .. [1] G. Sussman, J. Wisdom, W. Farr, Functional Differential Geometry + (2013) + + """ + def __new__(cls, name, manifold, **kwargs): + if not isinstance(name, Str): + name = Str(name) + obj = super().__new__(cls, name, manifold) + + obj.manifold.patches.append(obj) # deprecated + obj.coord_systems = _deprecated_list( + """ + Patch.coord_systms is deprecated. The Patch class is now + immutable. Instead use a separate list to keep track of coordinate + systems. + """, []) + return obj + + @property + def name(self): + return self.args[0] + + @property + def manifold(self): + return self.args[1] + + @property + def dim(self): + return self.manifold.dim + + +class CoordSystem(Basic): + """ + A coordinate system defined on the patch. + + Explanation + =========== + + Coordinate system is a system that uses one or more coordinates to uniquely + determine the position of the points or other geometric elements on a + manifold [1]. + + By passing ``Symbols`` to *symbols* parameter, user can define the name and + assumptions of coordinate symbols of the coordinate system. If not passed, + these symbols are generated automatically and are assumed to be real valued. + + By passing *relations* parameter, user can define the transform relations of + coordinate systems. Inverse transformation and indirect transformation can + be found automatically. If this parameter is not passed, coordinate + transformation cannot be done. + + Parameters + ========== + + name : str + The name of the coordinate system. + + patch : Patch + The patch where the coordinate system is defined. + + symbols : list of Symbols, optional + Defines the names and assumptions of coordinate symbols. + + relations : dict, optional + Key is a tuple of two strings, who are the names of the systems where + the coordinates transform from and transform to. + Value is a tuple of the symbols before transformation and a tuple of + the expressions after transformation. + + Examples + ======== + + We define two-dimensional Cartesian coordinate system and polar coordinate + system. + + >>> from sympy import symbols, pi, sqrt, atan2, cos, sin + >>> from sympy.diffgeom import Manifold, Patch, CoordSystem + >>> m = Manifold('M', 2) + >>> p = Patch('P', m) + >>> x, y = symbols('x y', real=True) + >>> r, theta = symbols('r theta', nonnegative=True) + >>> relation_dict = { + ... ('Car2D', 'Pol'): [(x, y), (sqrt(x**2 + y**2), atan2(y, x))], + ... ('Pol', 'Car2D'): [(r, theta), (r*cos(theta), r*sin(theta))] + ... } + >>> Car2D = CoordSystem('Car2D', p, (x, y), relation_dict) + >>> Pol = CoordSystem('Pol', p, (r, theta), relation_dict) + + ``symbols`` property returns ``CoordinateSymbol`` instances. These symbols + are not same with the symbols used to construct the coordinate system. + + >>> Car2D + Car2D + >>> Car2D.dim + 2 + >>> Car2D.symbols + (x, y) + >>> _[0].func + + + ``transformation()`` method returns the transformation function from + one coordinate system to another. ``transform()`` method returns the + transformed coordinates. + + >>> Car2D.transformation(Pol) + Lambda((x, y), Matrix([ + [sqrt(x**2 + y**2)], + [ atan2(y, x)]])) + >>> Car2D.transform(Pol) + Matrix([ + [sqrt(x**2 + y**2)], + [ atan2(y, x)]]) + >>> Car2D.transform(Pol, [1, 2]) + Matrix([ + [sqrt(5)], + [atan(2)]]) + + ``jacobian()`` method returns the Jacobian matrix of coordinate + transformation between two systems. ``jacobian_determinant()`` method + returns the Jacobian determinant of coordinate transformation between two + systems. + + >>> Pol.jacobian(Car2D) + Matrix([ + [cos(theta), -r*sin(theta)], + [sin(theta), r*cos(theta)]]) + >>> Pol.jacobian(Car2D, [1, pi/2]) + Matrix([ + [0, -1], + [1, 0]]) + >>> Car2D.jacobian_determinant(Pol) + 1/sqrt(x**2 + y**2) + >>> Car2D.jacobian_determinant(Pol, [1,0]) + 1 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Coordinate_system + + """ + def __new__(cls, name, patch, symbols=None, relations={}, **kwargs): + if not isinstance(name, Str): + name = Str(name) + + # canonicallize the symbols + if symbols is None: + names = kwargs.get('names', None) + if names is None: + symbols = Tuple( + *[Symbol('%s_%s' % (name.name, i), real=True) + for i in range(patch.dim)] + ) + else: + sympy_deprecation_warning( + f""" +The 'names' argument to CoordSystem is deprecated. Use 'symbols' instead. That +is, replace + + CoordSystem(..., names={names}) + +with + + CoordSystem(..., symbols=[{', '.join(["Symbol(" + repr(n) + ", real=True)" for n in names])}]) + """, + deprecated_since_version="1.7", + active_deprecations_target="deprecated-diffgeom-mutable", + ) + symbols = Tuple( + *[Symbol(n, real=True) for n in names] + ) + else: + syms = [] + for s in symbols: + if isinstance(s, Symbol): + syms.append(Symbol(s.name, **s._assumptions.generator)) + elif isinstance(s, str): + sympy_deprecation_warning( + f""" + +Passing a string as the coordinate symbol name to CoordSystem is deprecated. +Pass a Symbol with the appropriate name and assumptions instead. + +That is, replace {s} with Symbol({s!r}, real=True). + """, + + deprecated_since_version="1.7", + active_deprecations_target="deprecated-diffgeom-mutable", + ) + syms.append(Symbol(s, real=True)) + symbols = Tuple(*syms) + + # canonicallize the relations + rel_temp = {} + for k,v in relations.items(): + s1, s2 = k + if not isinstance(s1, Str): + s1 = Str(s1) + if not isinstance(s2, Str): + s2 = Str(s2) + key = Tuple(s1, s2) + + # Old version used Lambda as a value. + if isinstance(v, Lambda): + v = (tuple(v.signature), tuple(v.expr)) + else: + v = (tuple(v[0]), tuple(v[1])) + rel_temp[key] = v + relations = Dict(rel_temp) + + # construct the object + obj = super().__new__(cls, name, patch, symbols, relations) + + # Add deprecated attributes + obj.transforms = _deprecated_dict( + """ + CoordSystem.transforms is deprecated. The CoordSystem class is now + immutable. Use the 'relations' keyword argument to the + CoordSystems() constructor to specify relations. + """, {}) + obj._names = [str(n) for n in symbols] + obj.patch.coord_systems.append(obj) # deprecated + obj._dummies = [Dummy(str(n)) for n in symbols] # deprecated + obj._dummy = Dummy() + + return obj + + @property + def name(self): + return self.args[0] + + @property + def patch(self): + return self.args[1] + + @property + def manifold(self): + return self.patch.manifold + + @property + def symbols(self): + return tuple(CoordinateSymbol(self, i, **s._assumptions.generator) + for i,s in enumerate(self.args[2])) + + @property + def relations(self): + return self.args[3] + + @property + def dim(self): + return self.patch.dim + + ########################################################################## + # Finding transformation relation + ########################################################################## + + def transformation(self, sys): + """ + Return coordinate transformation function from *self* to *sys*. + + Parameters + ========== + + sys : CoordSystem + + Returns + ======= + + sympy.Lambda + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r, R2_p + >>> R2_r.transformation(R2_p) + Lambda((x, y), Matrix([ + [sqrt(x**2 + y**2)], + [ atan2(y, x)]])) + + """ + signature = self.args[2] + + key = Tuple(self.name, sys.name) + if self == sys: + expr = Matrix(self.symbols) + elif key in self.relations: + expr = Matrix(self.relations[key][1]) + elif key[::-1] in self.relations: + expr = Matrix(self._inverse_transformation(sys, self)) + else: + expr = Matrix(self._indirect_transformation(self, sys)) + return Lambda(signature, expr) + + @staticmethod + def _solve_inverse(sym1, sym2, exprs, sys1_name, sys2_name): + ret = solve( + [t[0] - t[1] for t in zip(sym2, exprs)], + list(sym1), dict=True) + + if len(ret) == 0: + temp = "Cannot solve inverse relation from {} to {}." + raise NotImplementedError(temp.format(sys1_name, sys2_name)) + elif len(ret) > 1: + temp = "Obtained multiple inverse relation from {} to {}." + raise ValueError(temp.format(sys1_name, sys2_name)) + + return ret[0] + + @classmethod + def _inverse_transformation(cls, sys1, sys2): + # Find the transformation relation from sys2 to sys1 + forward = sys1.transform(sys2) + inv_results = cls._solve_inverse(sys1.symbols, sys2.symbols, forward, + sys1.name, sys2.name) + signature = tuple(sys1.symbols) + return [inv_results[s] for s in signature] + + @classmethod + @cacheit + def _indirect_transformation(cls, sys1, sys2): + # Find the transformation relation between two indirectly connected + # coordinate systems + rel = sys1.relations + path = cls._dijkstra(sys1, sys2) + + transforms = [] + for s1, s2 in zip(path, path[1:]): + if (s1, s2) in rel: + transforms.append(rel[(s1, s2)]) + else: + sym2, inv_exprs = rel[(s2, s1)] + sym1 = tuple(Dummy() for i in sym2) + ret = cls._solve_inverse(sym2, sym1, inv_exprs, s2, s1) + ret = tuple(ret[s] for s in sym2) + transforms.append((sym1, ret)) + syms = sys1.args[2] + exprs = syms + for newsyms, newexprs in transforms: + exprs = tuple(e.subs(zip(newsyms, exprs)) for e in newexprs) + return exprs + + @staticmethod + def _dijkstra(sys1, sys2): + # Use Dijkstra algorithm to find the shortest path between two indirectly-connected + # coordinate systems + # return value is the list of the names of the systems. + relations = sys1.relations + graph = {} + for s1, s2 in relations.keys(): + if s1 not in graph: + graph[s1] = {s2} + else: + graph[s1].add(s2) + if s2 not in graph: + graph[s2] = {s1} + else: + graph[s2].add(s1) + + path_dict = {sys:[0, [], 0] for sys in graph} # minimum distance, path, times of visited + + def visit(sys): + path_dict[sys][2] = 1 + for newsys in graph[sys]: + distance = path_dict[sys][0] + 1 + if path_dict[newsys][0] >= distance or not path_dict[newsys][1]: + path_dict[newsys][0] = distance + path_dict[newsys][1] = list(path_dict[sys][1]) + path_dict[newsys][1].append(sys) + + visit(sys1.name) + + while True: + min_distance = max(path_dict.values(), key=lambda x:x[0])[0] + newsys = None + for sys, lst in path_dict.items(): + if 0 < lst[0] <= min_distance and not lst[2]: + min_distance = lst[0] + newsys = sys + if newsys is None: + break + visit(newsys) + + result = path_dict[sys2.name][1] + result.append(sys2.name) + + if result == [sys2.name]: + raise KeyError("Two coordinate systems are not connected.") + return result + + def connect_to(self, to_sys, from_coords, to_exprs, inverse=True, fill_in_gaps=False): + sympy_deprecation_warning( + """ + The CoordSystem.connect_to() method is deprecated. Instead, + generate a new instance of CoordSystem with the 'relations' + keyword argument (CoordSystem classes are now immutable). + """, + deprecated_since_version="1.7", + active_deprecations_target="deprecated-diffgeom-mutable", + ) + + from_coords, to_exprs = dummyfy(from_coords, to_exprs) + self.transforms[to_sys] = Matrix(from_coords), Matrix(to_exprs) + + if inverse: + to_sys.transforms[self] = self._inv_transf(from_coords, to_exprs) + + if fill_in_gaps: + self._fill_gaps_in_transformations() + + @staticmethod + def _inv_transf(from_coords, to_exprs): + # Will be removed when connect_to is removed + inv_from = [i.as_dummy() for i in from_coords] + inv_to = solve( + [t[0] - t[1] for t in zip(inv_from, to_exprs)], + list(from_coords), dict=True)[0] + inv_to = [inv_to[fc] for fc in from_coords] + return Matrix(inv_from), Matrix(inv_to) + + @staticmethod + def _fill_gaps_in_transformations(): + # Will be removed when connect_to is removed + raise NotImplementedError + + ########################################################################## + # Coordinate transformations + ########################################################################## + + def transform(self, sys, coordinates=None): + """ + Return the result of coordinate transformation from *self* to *sys*. + If coordinates are not given, coordinate symbols of *self* are used. + + Parameters + ========== + + sys : CoordSystem + + coordinates : Any iterable, optional. + + Returns + ======= + + sympy.ImmutableDenseMatrix containing CoordinateSymbol + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r, R2_p + >>> R2_r.transform(R2_p) + Matrix([ + [sqrt(x**2 + y**2)], + [ atan2(y, x)]]) + >>> R2_r.transform(R2_p, [0, 1]) + Matrix([ + [ 1], + [pi/2]]) + + """ + if coordinates is None: + coordinates = self.symbols + if self != sys: + transf = self.transformation(sys) + coordinates = transf(*coordinates) + else: + coordinates = Matrix(coordinates) + return coordinates + + def coord_tuple_transform_to(self, to_sys, coords): + """Transform ``coords`` to coord system ``to_sys``.""" + sympy_deprecation_warning( + """ + The CoordSystem.coord_tuple_transform_to() method is deprecated. + Use the CoordSystem.transform() method instead. + """, + deprecated_since_version="1.7", + active_deprecations_target="deprecated-diffgeom-mutable", + ) + + coords = Matrix(coords) + if self != to_sys: + with ignore_warnings(SymPyDeprecationWarning): + transf = self.transforms[to_sys] + coords = transf[1].subs(list(zip(transf[0], coords))) + return coords + + def jacobian(self, sys, coordinates=None): + """ + Return the jacobian matrix of a transformation on given coordinates. + If coordinates are not given, coordinate symbols of *self* are used. + + Parameters + ========== + + sys : CoordSystem + + coordinates : Any iterable, optional. + + Returns + ======= + + sympy.ImmutableDenseMatrix + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r, R2_p + >>> R2_p.jacobian(R2_r) + Matrix([ + [cos(theta), -rho*sin(theta)], + [sin(theta), rho*cos(theta)]]) + >>> R2_p.jacobian(R2_r, [1, 0]) + Matrix([ + [1, 0], + [0, 1]]) + + """ + result = self.transform(sys).jacobian(self.symbols) + if coordinates is not None: + result = result.subs(list(zip(self.symbols, coordinates))) + return result + jacobian_matrix = jacobian + + def jacobian_determinant(self, sys, coordinates=None): + """ + Return the jacobian determinant of a transformation on given + coordinates. If coordinates are not given, coordinate symbols of *self* + are used. + + Parameters + ========== + + sys : CoordSystem + + coordinates : Any iterable, optional. + + Returns + ======= + + sympy.Expr + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r, R2_p + >>> R2_r.jacobian_determinant(R2_p) + 1/sqrt(x**2 + y**2) + >>> R2_r.jacobian_determinant(R2_p, [1, 0]) + 1 + + """ + return self.jacobian(sys, coordinates).det() + + + ########################################################################## + # Points + ########################################################################## + + def point(self, coords): + """Create a ``Point`` with coordinates given in this coord system.""" + return Point(self, coords) + + def point_to_coords(self, point): + """Calculate the coordinates of a point in this coord system.""" + return point.coords(self) + + ########################################################################## + # Base fields. + ########################################################################## + + def base_scalar(self, coord_index): + """Return ``BaseScalarField`` that takes a point and returns one of the coordinates.""" + return BaseScalarField(self, coord_index) + coord_function = base_scalar + + def base_scalars(self): + """Returns a list of all coordinate functions. + For more details see the ``base_scalar`` method of this class.""" + return [self.base_scalar(i) for i in range(self.dim)] + coord_functions = base_scalars + + def base_vector(self, coord_index): + """Return a basis vector field. + The basis vector field for this coordinate system. It is also an + operator on scalar fields.""" + return BaseVectorField(self, coord_index) + + def base_vectors(self): + """Returns a list of all base vectors. + For more details see the ``base_vector`` method of this class.""" + return [self.base_vector(i) for i in range(self.dim)] + + def base_oneform(self, coord_index): + """Return a basis 1-form field. + The basis one-form field for this coordinate system. It is also an + operator on vector fields.""" + return Differential(self.coord_function(coord_index)) + + def base_oneforms(self): + """Returns a list of all base oneforms. + For more details see the ``base_oneform`` method of this class.""" + return [self.base_oneform(i) for i in range(self.dim)] + + +class CoordinateSymbol(Symbol): + """A symbol which denotes an abstract value of i-th coordinate of + the coordinate system with given context. + + Explanation + =========== + + Each coordinates in coordinate system are represented by unique symbol, + such as x, y, z in Cartesian coordinate system. + + You may not construct this class directly. Instead, use `symbols` method + of CoordSystem. + + Parameters + ========== + + coord_sys : CoordSystem + + index : integer + + Examples + ======== + + >>> from sympy import symbols, Lambda, Matrix, sqrt, atan2, cos, sin + >>> from sympy.diffgeom import Manifold, Patch, CoordSystem + >>> m = Manifold('M', 2) + >>> p = Patch('P', m) + >>> x, y = symbols('x y', real=True) + >>> r, theta = symbols('r theta', nonnegative=True) + >>> relation_dict = { + ... ('Car2D', 'Pol'): Lambda((x, y), Matrix([sqrt(x**2 + y**2), atan2(y, x)])), + ... ('Pol', 'Car2D'): Lambda((r, theta), Matrix([r*cos(theta), r*sin(theta)])) + ... } + >>> Car2D = CoordSystem('Car2D', p, [x, y], relation_dict) + >>> Pol = CoordSystem('Pol', p, [r, theta], relation_dict) + >>> x, y = Car2D.symbols + + ``CoordinateSymbol`` contains its coordinate symbol and index. + + >>> x.name + 'x' + >>> x.coord_sys == Car2D + True + >>> x.index + 0 + >>> x.is_real + True + + You can transform ``CoordinateSymbol`` into other coordinate system using + ``rewrite()`` method. + + >>> x.rewrite(Pol) + r*cos(theta) + >>> sqrt(x**2 + y**2).rewrite(Pol).simplify() + r + + """ + def __new__(cls, coord_sys, index, **assumptions): + name = coord_sys.args[2][index].name + obj = super().__new__(cls, name, **assumptions) + obj.coord_sys = coord_sys + obj.index = index + return obj + + def __getnewargs__(self): + return (self.coord_sys, self.index) + + def _hashable_content(self): + return ( + self.coord_sys, self.index + ) + tuple(sorted(self.assumptions0.items())) + + def _eval_rewrite(self, rule, args, **hints): + if isinstance(rule, CoordSystem): + return rule.transform(self.coord_sys)[self.index] + return super()._eval_rewrite(rule, args, **hints) + + +class Point(Basic): + """Point defined in a coordinate system. + + Explanation + =========== + + Mathematically, point is defined in the manifold and does not have any coordinates + by itself. Coordinate system is what imbues the coordinates to the point by coordinate + chart. However, due to the difficulty of realizing such logic, you must supply + a coordinate system and coordinates to define a Point here. + + The usage of this object after its definition is independent of the + coordinate system that was used in order to define it, however due to + limitations in the simplification routines you can arrive at complicated + expressions if you use inappropriate coordinate systems. + + Parameters + ========== + + coord_sys : CoordSystem + + coords : list + The coordinates of the point. + + Examples + ======== + + >>> from sympy import pi + >>> from sympy.diffgeom import Point + >>> from sympy.diffgeom.rn import R2, R2_r, R2_p + >>> rho, theta = R2_p.symbols + + >>> p = Point(R2_p, [rho, 3*pi/4]) + + >>> p.manifold == R2 + True + + >>> p.coords() + Matrix([ + [ rho], + [3*pi/4]]) + >>> p.coords(R2_r) + Matrix([ + [-sqrt(2)*rho/2], + [ sqrt(2)*rho/2]]) + + """ + + def __new__(cls, coord_sys, coords, **kwargs): + coords = Matrix(coords) + obj = super().__new__(cls, coord_sys, coords) + obj._coord_sys = coord_sys + obj._coords = coords + return obj + + @property + def patch(self): + return self._coord_sys.patch + + @property + def manifold(self): + return self._coord_sys.manifold + + @property + def dim(self): + return self.manifold.dim + + def coords(self, sys=None): + """ + Coordinates of the point in given coordinate system. If coordinate system + is not passed, it returns the coordinates in the coordinate system in which + the point was defined. + """ + if sys is None: + return self._coords + else: + return self._coord_sys.transform(sys, self._coords) + + @property + def free_symbols(self): + return self._coords.free_symbols + + +class BaseScalarField(Expr): + """Base scalar field over a manifold for a given coordinate system. + + Explanation + =========== + + A scalar field takes a point as an argument and returns a scalar. + A base scalar field of a coordinate system takes a point and returns one of + the coordinates of that point in the coordinate system in question. + + To define a scalar field you need to choose the coordinate system and the + index of the coordinate. + + The use of the scalar field after its definition is independent of the + coordinate system in which it was defined, however due to limitations in + the simplification routines you may arrive at more complicated + expression if you use unappropriate coordinate systems. + You can build complicated scalar fields by just building up SymPy + expressions containing ``BaseScalarField`` instances. + + Parameters + ========== + + coord_sys : CoordSystem + + index : integer + + Examples + ======== + + >>> from sympy import Function, pi + >>> from sympy.diffgeom import BaseScalarField + >>> from sympy.diffgeom.rn import R2_r, R2_p + >>> rho, _ = R2_p.symbols + >>> point = R2_p.point([rho, 0]) + >>> fx, fy = R2_r.base_scalars() + >>> ftheta = BaseScalarField(R2_r, 1) + + >>> fx(point) + rho + >>> fy(point) + 0 + + >>> (fx**2+fy**2).rcall(point) + rho**2 + + >>> g = Function('g') + >>> fg = g(ftheta-pi) + >>> fg.rcall(point) + g(-pi) + + """ + + is_commutative = True + + def __new__(cls, coord_sys, index, **kwargs): + index = _sympify(index) + obj = super().__new__(cls, coord_sys, index) + obj._coord_sys = coord_sys + obj._index = index + return obj + + @property + def coord_sys(self): + return self.args[0] + + @property + def index(self): + return self.args[1] + + @property + def patch(self): + return self.coord_sys.patch + + @property + def manifold(self): + return self.coord_sys.manifold + + @property + def dim(self): + return self.manifold.dim + + def __call__(self, *args): + """Evaluating the field at a point or doing nothing. + If the argument is a ``Point`` instance, the field is evaluated at that + point. The field is returned itself if the argument is any other + object. It is so in order to have working recursive calling mechanics + for all fields (check the ``__call__`` method of ``Expr``). + """ + point = args[0] + if len(args) != 1 or not isinstance(point, Point): + return self + coords = point.coords(self._coord_sys) + # XXX Calling doit is necessary with all the Subs expressions + # XXX Calling simplify is necessary with all the trig expressions + return simplify(coords[self._index]).doit() + + # XXX Workaround for limitations on the content of args + free_symbols: set[Any] = set() + + +class BaseVectorField(Expr): + r"""Base vector field over a manifold for a given coordinate system. + + Explanation + =========== + + A vector field is an operator taking a scalar field and returning a + directional derivative (which is also a scalar field). + A base vector field is the same type of operator, however the derivation is + specifically done with respect to a chosen coordinate. + + To define a base vector field you need to choose the coordinate system and + the index of the coordinate. + + The use of the vector field after its definition is independent of the + coordinate system in which it was defined, however due to limitations in the + simplification routines you may arrive at more complicated expression if you + use unappropriate coordinate systems. + + Parameters + ========== + coord_sys : CoordSystem + + index : integer + + Examples + ======== + + >>> from sympy import Function + >>> from sympy.diffgeom.rn import R2_p, R2_r + >>> from sympy.diffgeom import BaseVectorField + >>> from sympy import pprint + + >>> x, y = R2_r.symbols + >>> rho, theta = R2_p.symbols + >>> fx, fy = R2_r.base_scalars() + >>> point_p = R2_p.point([rho, theta]) + >>> point_r = R2_r.point([x, y]) + + >>> g = Function('g') + >>> s_field = g(fx, fy) + + >>> v = BaseVectorField(R2_r, 1) + >>> pprint(v(s_field)) + / d \| + |---(g(x, xi))|| + \dxi /|xi=y + >>> pprint(v(s_field).rcall(point_r).doit()) + d + --(g(x, y)) + dy + >>> pprint(v(s_field).rcall(point_p)) + / d \| + |---(g(rho*cos(theta), xi))|| + \dxi /|xi=rho*sin(theta) + + """ + + is_commutative = False + + def __new__(cls, coord_sys, index, **kwargs): + index = _sympify(index) + obj = super().__new__(cls, coord_sys, index) + obj._coord_sys = coord_sys + obj._index = index + return obj + + @property + def coord_sys(self): + return self.args[0] + + @property + def index(self): + return self.args[1] + + @property + def patch(self): + return self.coord_sys.patch + + @property + def manifold(self): + return self.coord_sys.manifold + + @property + def dim(self): + return self.manifold.dim + + def __call__(self, scalar_field): + """Apply on a scalar field. + The action of a vector field on a scalar field is a directional + differentiation. + If the argument is not a scalar field an error is raised. + """ + if covariant_order(scalar_field) or contravariant_order(scalar_field): + raise ValueError('Only scalar fields can be supplied as arguments to vector fields.') + + if scalar_field is None: + return self + + base_scalars = list(scalar_field.atoms(BaseScalarField)) + + # First step: e_x(x+r**2) -> e_x(x) + 2*r*e_x(r) + d_var = self._coord_sys._dummy + # TODO: you need a real dummy function for the next line + d_funcs = [Function('_#_%s' % i)(d_var) for i, + b in enumerate(base_scalars)] + d_result = scalar_field.subs(list(zip(base_scalars, d_funcs))) + d_result = d_result.diff(d_var) + + # Second step: e_x(x) -> 1 and e_x(r) -> cos(atan2(x, y)) + coords = self._coord_sys.symbols + d_funcs_deriv = [f.diff(d_var) for f in d_funcs] + d_funcs_deriv_sub = [] + for b in base_scalars: + jac = self._coord_sys.jacobian(b._coord_sys, coords) + d_funcs_deriv_sub.append(jac[b._index, self._index]) + d_result = d_result.subs(list(zip(d_funcs_deriv, d_funcs_deriv_sub))) + + # Remove the dummies + result = d_result.subs(list(zip(d_funcs, base_scalars))) + result = result.subs(list(zip(coords, self._coord_sys.coord_functions()))) + return result.doit() + + +def _find_coords(expr): + # Finds CoordinateSystems existing in expr + fields = expr.atoms(BaseScalarField, BaseVectorField) + return {f._coord_sys for f in fields} + + +class Commutator(Expr): + r"""Commutator of two vector fields. + + Explanation + =========== + + The commutator of two vector fields `v_1` and `v_2` is defined as the + vector field `[v_1, v_2]` that evaluated on each scalar field `f` is equal + to `v_1(v_2(f)) - v_2(v_1(f))`. + + Examples + ======== + + + >>> from sympy.diffgeom.rn import R2_p, R2_r + >>> from sympy.diffgeom import Commutator + >>> from sympy import simplify + + >>> fx, fy = R2_r.base_scalars() + >>> e_x, e_y = R2_r.base_vectors() + >>> e_r = R2_p.base_vector(0) + + >>> c_xy = Commutator(e_x, e_y) + >>> c_xr = Commutator(e_x, e_r) + >>> c_xy + 0 + + Unfortunately, the current code is not able to compute everything: + + >>> c_xr + Commutator(e_x, e_rho) + >>> simplify(c_xr(fy**2)) + -2*cos(theta)*y**2/(x**2 + y**2) + + """ + def __new__(cls, v1, v2): + if (covariant_order(v1) or contravariant_order(v1) != 1 + or covariant_order(v2) or contravariant_order(v2) != 1): + raise ValueError( + 'Only commutators of vector fields are supported.') + if v1 == v2: + return S.Zero + coord_sys = set().union(*[_find_coords(v) for v in (v1, v2)]) + if len(coord_sys) == 1: + # Only one coordinate systems is used, hence it is easy enough to + # actually evaluate the commutator. + if all(isinstance(v, BaseVectorField) for v in (v1, v2)): + return S.Zero + bases_1, bases_2 = [list(v.atoms(BaseVectorField)) + for v in (v1, v2)] + coeffs_1 = [v1.expand().coeff(b) for b in bases_1] + coeffs_2 = [v2.expand().coeff(b) for b in bases_2] + res = 0 + for c1, b1 in zip(coeffs_1, bases_1): + for c2, b2 in zip(coeffs_2, bases_2): + res += c1*b1(c2)*b2 - c2*b2(c1)*b1 + return res + else: + obj = super().__new__(cls, v1, v2) + obj._v1 = v1 # deprecated assignment + obj._v2 = v2 # deprecated assignment + return obj + + @property + def v1(self): + return self.args[0] + + @property + def v2(self): + return self.args[1] + + def __call__(self, scalar_field): + """Apply on a scalar field. + If the argument is not a scalar field an error is raised. + """ + return self.v1(self.v2(scalar_field)) - self.v2(self.v1(scalar_field)) + + +class Differential(Expr): + r"""Return the differential (exterior derivative) of a form field. + + Explanation + =========== + + The differential of a form (i.e. the exterior derivative) has a complicated + definition in the general case. + The differential `df` of the 0-form `f` is defined for any vector field `v` + as `df(v) = v(f)`. + + Examples + ======== + + >>> from sympy import Function + >>> from sympy.diffgeom.rn import R2_r + >>> from sympy.diffgeom import Differential + >>> from sympy import pprint + + >>> fx, fy = R2_r.base_scalars() + >>> e_x, e_y = R2_r.base_vectors() + >>> g = Function('g') + >>> s_field = g(fx, fy) + >>> dg = Differential(s_field) + + >>> dg + d(g(x, y)) + >>> pprint(dg(e_x)) + / d \| + |---(g(xi, y))|| + \dxi /|xi=x + >>> pprint(dg(e_y)) + / d \| + |---(g(x, xi))|| + \dxi /|xi=y + + Applying the exterior derivative operator twice always results in: + + >>> Differential(dg) + 0 + """ + + is_commutative = False + + def __new__(cls, form_field): + if contravariant_order(form_field): + raise ValueError( + 'A vector field was supplied as an argument to Differential.') + if isinstance(form_field, Differential): + return S.Zero + else: + obj = super().__new__(cls, form_field) + obj._form_field = form_field # deprecated assignment + return obj + + @property + def form_field(self): + return self.args[0] + + def __call__(self, *vector_fields): + """Apply on a list of vector_fields. + + Explanation + =========== + + If the number of vector fields supplied is not equal to 1 + the order of + the form field inside the differential the result is undefined. + + For 1-forms (i.e. differentials of scalar fields) the evaluation is + done as `df(v)=v(f)`. However if `v` is ``None`` instead of a vector + field, the differential is returned unchanged. This is done in order to + permit partial contractions for higher forms. + + In the general case the evaluation is done by applying the form field + inside the differential on a list with one less elements than the number + of elements in the original list. Lowering the number of vector fields + is achieved through replacing each pair of fields by their + commutator. + + If the arguments are not vectors or ``None``s an error is raised. + """ + if any((contravariant_order(a) != 1 or covariant_order(a)) and a is not None + for a in vector_fields): + raise ValueError('The arguments supplied to Differential should be vector fields or Nones.') + k = len(vector_fields) + if k == 1: + if vector_fields[0]: + return vector_fields[0].rcall(self._form_field) + return self + else: + # For higher form it is more complicated: + # Invariant formula: + # https://en.wikipedia.org/wiki/Exterior_derivative#Invariant_formula + # df(v1, ... vn) = +/- vi(f(v1..no i..vn)) + # +/- f([vi,vj],v1..no i, no j..vn) + f = self._form_field + v = vector_fields + ret = 0 + for i in range(k): + t = v[i].rcall(f.rcall(*v[:i] + v[i + 1:])) + ret += (-1)**i*t + for j in range(i + 1, k): + c = Commutator(v[i], v[j]) + if c: # TODO this is ugly - the Commutator can be Zero and + # this causes the next line to fail + t = f.rcall(*(c,) + v[:i] + v[i + 1:j] + v[j + 1:]) + ret += (-1)**(i + j)*t + return ret + + +class TensorProduct(Expr): + """Tensor product of forms. + + Explanation + =========== + + The tensor product permits the creation of multilinear functionals (i.e. + higher order tensors) out of lower order fields (e.g. 1-forms and vector + fields). However, the higher tensors thus created lack the interesting + features provided by the other type of product, the wedge product, namely + they are not antisymmetric and hence are not form fields. + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r + >>> from sympy.diffgeom import TensorProduct + + >>> fx, fy = R2_r.base_scalars() + >>> e_x, e_y = R2_r.base_vectors() + >>> dx, dy = R2_r.base_oneforms() + + >>> TensorProduct(dx, dy)(e_x, e_y) + 1 + >>> TensorProduct(dx, dy)(e_y, e_x) + 0 + >>> TensorProduct(dx, fx*dy)(fx*e_x, e_y) + x**2 + >>> TensorProduct(e_x, e_y)(fx**2, fy**2) + 4*x*y + >>> TensorProduct(e_y, dx)(fy) + dx + + You can nest tensor products. + + >>> tp1 = TensorProduct(dx, dy) + >>> TensorProduct(tp1, dx)(e_x, e_y, e_x) + 1 + + You can make partial contraction for instance when 'raising an index'. + Putting ``None`` in the second argument of ``rcall`` means that the + respective position in the tensor product is left as it is. + + >>> TP = TensorProduct + >>> metric = TP(dx, dx) + 3*TP(dy, dy) + >>> metric.rcall(e_y, None) + 3*dy + + Or automatically pad the args with ``None`` without specifying them. + + >>> metric.rcall(e_y) + 3*dy + + """ + def __new__(cls, *args): + scalar = Mul(*[m for m in args if covariant_order(m) + contravariant_order(m) == 0]) + multifields = [m for m in args if covariant_order(m) + contravariant_order(m)] + if multifields: + if len(multifields) == 1: + return scalar*multifields[0] + return scalar*super().__new__(cls, *multifields) + else: + return scalar + + def __call__(self, *fields): + """Apply on a list of fields. + + If the number of input fields supplied is not equal to the order of + the tensor product field, the list of arguments is padded with ``None``'s. + + The list of arguments is divided in sublists depending on the order of + the forms inside the tensor product. The sublists are provided as + arguments to these forms and the resulting expressions are given to the + constructor of ``TensorProduct``. + + """ + tot_order = covariant_order(self) + contravariant_order(self) + tot_args = len(fields) + if tot_args != tot_order: + fields = list(fields) + [None]*(tot_order - tot_args) + orders = [covariant_order(f) + contravariant_order(f) for f in self._args] + indices = [sum(orders[:i + 1]) for i in range(len(orders) - 1)] + fields = [fields[i:j] for i, j in zip([0] + indices, indices + [None])] + multipliers = [t[0].rcall(*t[1]) for t in zip(self._args, fields)] + return TensorProduct(*multipliers) + + +class WedgeProduct(TensorProduct): + """Wedge product of forms. + + Explanation + =========== + + In the context of integration only completely antisymmetric forms make + sense. The wedge product permits the creation of such forms. + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r + >>> from sympy.diffgeom import WedgeProduct + + >>> fx, fy = R2_r.base_scalars() + >>> e_x, e_y = R2_r.base_vectors() + >>> dx, dy = R2_r.base_oneforms() + + >>> WedgeProduct(dx, dy)(e_x, e_y) + 1 + >>> WedgeProduct(dx, dy)(e_y, e_x) + -1 + >>> WedgeProduct(dx, fx*dy)(fx*e_x, e_y) + x**2 + >>> WedgeProduct(e_x, e_y)(fy, None) + -e_x + + You can nest wedge products. + + >>> wp1 = WedgeProduct(dx, dy) + >>> WedgeProduct(wp1, dx)(e_x, e_y, e_x) + 0 + + """ + # TODO the calculation of signatures is slow + # TODO you do not need all these permutations (neither the prefactor) + def __call__(self, *fields): + """Apply on a list of vector_fields. + The expression is rewritten internally in terms of tensor products and evaluated.""" + orders = (covariant_order(e) + contravariant_order(e) for e in self.args) + mul = 1/Mul(*(factorial(o) for o in orders)) + perms = permutations(fields) + perms_par = (Permutation( + p).signature() for p in permutations(range(len(fields)))) + tensor_prod = TensorProduct(*self.args) + return mul*Add(*[tensor_prod(*p[0])*p[1] for p in zip(perms, perms_par)]) + + +class LieDerivative(Expr): + """Lie derivative with respect to a vector field. + + Explanation + =========== + + The transport operator that defines the Lie derivative is the pushforward of + the field to be derived along the integral curve of the field with respect + to which one derives. + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r, R2_p + >>> from sympy.diffgeom import (LieDerivative, TensorProduct) + + >>> fx, fy = R2_r.base_scalars() + >>> e_x, e_y = R2_r.base_vectors() + >>> e_rho, e_theta = R2_p.base_vectors() + >>> dx, dy = R2_r.base_oneforms() + + >>> LieDerivative(e_x, fy) + 0 + >>> LieDerivative(e_x, fx) + 1 + >>> LieDerivative(e_x, e_x) + 0 + + The Lie derivative of a tensor field by another tensor field is equal to + their commutator: + + >>> LieDerivative(e_x, e_rho) + Commutator(e_x, e_rho) + >>> LieDerivative(e_x + e_y, fx) + 1 + + >>> tp = TensorProduct(dx, dy) + >>> LieDerivative(e_x, tp) + LieDerivative(e_x, TensorProduct(dx, dy)) + >>> LieDerivative(e_x, tp) + LieDerivative(e_x, TensorProduct(dx, dy)) + + """ + def __new__(cls, v_field, expr): + expr_form_ord = covariant_order(expr) + if contravariant_order(v_field) != 1 or covariant_order(v_field): + raise ValueError('Lie derivatives are defined only with respect to' + ' vector fields. The supplied argument was not a ' + 'vector field.') + if expr_form_ord > 0: + obj = super().__new__(cls, v_field, expr) + # deprecated assignments + obj._v_field = v_field + obj._expr = expr + return obj + if expr.atoms(BaseVectorField): + return Commutator(v_field, expr) + else: + return v_field.rcall(expr) + + @property + def v_field(self): + return self.args[0] + + @property + def expr(self): + return self.args[1] + + def __call__(self, *args): + v = self.v_field + expr = self.expr + lead_term = v(expr(*args)) + rest = Add(*[Mul(*args[:i] + (Commutator(v, args[i]),) + args[i + 1:]) + for i in range(len(args))]) + return lead_term - rest + + +class BaseCovarDerivativeOp(Expr): + """Covariant derivative operator with respect to a base vector. + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r + >>> from sympy.diffgeom import BaseCovarDerivativeOp + >>> from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct + + >>> TP = TensorProduct + >>> fx, fy = R2_r.base_scalars() + >>> e_x, e_y = R2_r.base_vectors() + >>> dx, dy = R2_r.base_oneforms() + + >>> ch = metric_to_Christoffel_2nd(TP(dx, dx) + TP(dy, dy)) + >>> ch + [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] + >>> cvd = BaseCovarDerivativeOp(R2_r, 0, ch) + >>> cvd(fx) + 1 + >>> cvd(fx*e_x) + e_x + """ + + def __new__(cls, coord_sys, index, christoffel): + index = _sympify(index) + christoffel = ImmutableDenseNDimArray(christoffel) + obj = super().__new__(cls, coord_sys, index, christoffel) + # deprecated assignments + obj._coord_sys = coord_sys + obj._index = index + obj._christoffel = christoffel + return obj + + @property + def coord_sys(self): + return self.args[0] + + @property + def index(self): + return self.args[1] + + @property + def christoffel(self): + return self.args[2] + + def __call__(self, field): + """Apply on a scalar field. + + The action of a vector field on a scalar field is a directional + differentiation. + If the argument is not a scalar field the behaviour is undefined. + """ + if covariant_order(field) != 0: + raise NotImplementedError() + + field = vectors_in_basis(field, self._coord_sys) + + wrt_vector = self._coord_sys.base_vector(self._index) + wrt_scalar = self._coord_sys.coord_function(self._index) + vectors = list(field.atoms(BaseVectorField)) + + # First step: replace all vectors with something susceptible to + # derivation and do the derivation + # TODO: you need a real dummy function for the next line + d_funcs = [Function('_#_%s' % i)(wrt_scalar) for i, + b in enumerate(vectors)] + d_result = field.subs(list(zip(vectors, d_funcs))) + d_result = wrt_vector(d_result) + + # Second step: backsubstitute the vectors in + d_result = d_result.subs(list(zip(d_funcs, vectors))) + + # Third step: evaluate the derivatives of the vectors + derivs = [] + for v in vectors: + d = Add(*[(self._christoffel[k, wrt_vector._index, v._index] + *v._coord_sys.base_vector(k)) + for k in range(v._coord_sys.dim)]) + derivs.append(d) + to_subs = [wrt_vector(d) for d in d_funcs] + # XXX: This substitution can fail when there are Dummy symbols and the + # cache is disabled: https://github.com/sympy/sympy/issues/17794 + result = d_result.subs(list(zip(to_subs, derivs))) + + # Remove the dummies + result = result.subs(list(zip(d_funcs, vectors))) + return result.doit() + + +class CovarDerivativeOp(Expr): + """Covariant derivative operator. + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2_r + >>> from sympy.diffgeom import CovarDerivativeOp + >>> from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct + >>> TP = TensorProduct + >>> fx, fy = R2_r.base_scalars() + >>> e_x, e_y = R2_r.base_vectors() + >>> dx, dy = R2_r.base_oneforms() + >>> ch = metric_to_Christoffel_2nd(TP(dx, dx) + TP(dy, dy)) + + >>> ch + [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] + >>> cvd = CovarDerivativeOp(fx*e_x, ch) + >>> cvd(fx) + x + >>> cvd(fx*e_x) + x*e_x + + """ + + def __new__(cls, wrt, christoffel): + if len({v._coord_sys for v in wrt.atoms(BaseVectorField)}) > 1: + raise NotImplementedError() + if contravariant_order(wrt) != 1 or covariant_order(wrt): + raise ValueError('Covariant derivatives are defined only with ' + 'respect to vector fields. The supplied argument ' + 'was not a vector field.') + christoffel = ImmutableDenseNDimArray(christoffel) + obj = super().__new__(cls, wrt, christoffel) + # deprecated assignments + obj._wrt = wrt + obj._christoffel = christoffel + return obj + + @property + def wrt(self): + return self.args[0] + + @property + def christoffel(self): + return self.args[1] + + def __call__(self, field): + vectors = list(self._wrt.atoms(BaseVectorField)) + base_ops = [BaseCovarDerivativeOp(v._coord_sys, v._index, self._christoffel) + for v in vectors] + return self._wrt.subs(list(zip(vectors, base_ops))).rcall(field) + + +############################################################################### +# Integral curves on vector fields +############################################################################### +def intcurve_series(vector_field, param, start_point, n=6, coord_sys=None, coeffs=False): + r"""Return the series expansion for an integral curve of the field. + + Explanation + =========== + + Integral curve is a function `\gamma` taking a parameter in `R` to a point + in the manifold. It verifies the equation: + + `V(f)\big(\gamma(t)\big) = \frac{d}{dt}f\big(\gamma(t)\big)` + + where the given ``vector_field`` is denoted as `V`. This holds for any + value `t` for the parameter and any scalar field `f`. + + This equation can also be decomposed of a basis of coordinate functions + `V(f_i)\big(\gamma(t)\big) = \frac{d}{dt}f_i\big(\gamma(t)\big) \quad \forall i` + + This function returns a series expansion of `\gamma(t)` in terms of the + coordinate system ``coord_sys``. The equations and expansions are necessarily + done in coordinate-system-dependent way as there is no other way to + represent movement between points on the manifold (i.e. there is no such + thing as a difference of points for a general manifold). + + Parameters + ========== + vector_field + the vector field for which an integral curve will be given + + param + the argument of the function `\gamma` from R to the curve + + start_point + the point which corresponds to `\gamma(0)` + + n + the order to which to expand + + coord_sys + the coordinate system in which to expand + coeffs (default False) - if True return a list of elements of the expansion + + Examples + ======== + + Use the predefined R2 manifold: + + >>> from sympy.abc import t, x, y + >>> from sympy.diffgeom.rn import R2_p, R2_r + >>> from sympy.diffgeom import intcurve_series + + Specify a starting point and a vector field: + + >>> start_point = R2_r.point([x, y]) + >>> vector_field = R2_r.e_x + + Calculate the series: + + >>> intcurve_series(vector_field, t, start_point, n=3) + Matrix([ + [t + x], + [ y]]) + + Or get the elements of the expansion in a list: + + >>> series = intcurve_series(vector_field, t, start_point, n=3, coeffs=True) + >>> series[0] + Matrix([ + [x], + [y]]) + >>> series[1] + Matrix([ + [t], + [0]]) + >>> series[2] + Matrix([ + [0], + [0]]) + + The series in the polar coordinate system: + + >>> series = intcurve_series(vector_field, t, start_point, + ... n=3, coord_sys=R2_p, coeffs=True) + >>> series[0] + Matrix([ + [sqrt(x**2 + y**2)], + [ atan2(y, x)]]) + >>> series[1] + Matrix([ + [t*x/sqrt(x**2 + y**2)], + [ -t*y/(x**2 + y**2)]]) + >>> series[2] + Matrix([ + [t**2*(-x**2/(x**2 + y**2)**(3/2) + 1/sqrt(x**2 + y**2))/2], + [ t**2*x*y/(x**2 + y**2)**2]]) + + See Also + ======== + + intcurve_diffequ + + """ + if contravariant_order(vector_field) != 1 or covariant_order(vector_field): + raise ValueError('The supplied field was not a vector field.') + + def iter_vfield(scalar_field, i): + """Return ``vector_field`` called `i` times on ``scalar_field``.""" + return reduce(lambda s, v: v.rcall(s), [vector_field, ]*i, scalar_field) + + def taylor_terms_per_coord(coord_function): + """Return the series for one of the coordinates.""" + return [param**i*iter_vfield(coord_function, i).rcall(start_point)/factorial(i) + for i in range(n)] + coord_sys = coord_sys if coord_sys else start_point._coord_sys + coord_functions = coord_sys.coord_functions() + taylor_terms = [taylor_terms_per_coord(f) for f in coord_functions] + if coeffs: + return [Matrix(t) for t in zip(*taylor_terms)] + else: + return Matrix([sum(c) for c in taylor_terms]) + + +def intcurve_diffequ(vector_field, param, start_point, coord_sys=None): + r"""Return the differential equation for an integral curve of the field. + + Explanation + =========== + + Integral curve is a function `\gamma` taking a parameter in `R` to a point + in the manifold. It verifies the equation: + + `V(f)\big(\gamma(t)\big) = \frac{d}{dt}f\big(\gamma(t)\big)` + + where the given ``vector_field`` is denoted as `V`. This holds for any + value `t` for the parameter and any scalar field `f`. + + This function returns the differential equation of `\gamma(t)` in terms of the + coordinate system ``coord_sys``. The equations and expansions are necessarily + done in coordinate-system-dependent way as there is no other way to + represent movement between points on the manifold (i.e. there is no such + thing as a difference of points for a general manifold). + + Parameters + ========== + + vector_field + the vector field for which an integral curve will be given + + param + the argument of the function `\gamma` from R to the curve + + start_point + the point which corresponds to `\gamma(0)` + + coord_sys + the coordinate system in which to give the equations + + Returns + ======= + + a tuple of (equations, initial conditions) + + Examples + ======== + + Use the predefined R2 manifold: + + >>> from sympy.abc import t + >>> from sympy.diffgeom.rn import R2, R2_p, R2_r + >>> from sympy.diffgeom import intcurve_diffequ + + Specify a starting point and a vector field: + + >>> start_point = R2_r.point([0, 1]) + >>> vector_field = -R2.y*R2.e_x + R2.x*R2.e_y + + Get the equation: + + >>> equations, init_cond = intcurve_diffequ(vector_field, t, start_point) + >>> equations + [f_1(t) + Derivative(f_0(t), t), -f_0(t) + Derivative(f_1(t), t)] + >>> init_cond + [f_0(0), f_1(0) - 1] + + The series in the polar coordinate system: + + >>> equations, init_cond = intcurve_diffequ(vector_field, t, start_point, R2_p) + >>> equations + [Derivative(f_0(t), t), Derivative(f_1(t), t) - 1] + >>> init_cond + [f_0(0) - 1, f_1(0) - pi/2] + + See Also + ======== + + intcurve_series + + """ + if contravariant_order(vector_field) != 1 or covariant_order(vector_field): + raise ValueError('The supplied field was not a vector field.') + coord_sys = coord_sys if coord_sys else start_point._coord_sys + gammas = [Function('f_%d' % i)(param) for i in range( + start_point._coord_sys.dim)] + arbitrary_p = Point(coord_sys, gammas) + coord_functions = coord_sys.coord_functions() + equations = [simplify(diff(cf.rcall(arbitrary_p), param) - vector_field.rcall(cf).rcall(arbitrary_p)) + for cf in coord_functions] + init_cond = [simplify(cf.rcall(arbitrary_p).subs(param, 0) - cf.rcall(start_point)) + for cf in coord_functions] + return equations, init_cond + + +############################################################################### +# Helpers +############################################################################### +def dummyfy(args, exprs): + # TODO Is this a good idea? + d_args = Matrix([s.as_dummy() for s in args]) + reps = dict(zip(args, d_args)) + d_exprs = Matrix([_sympify(expr).subs(reps) for expr in exprs]) + return d_args, d_exprs + +############################################################################### +# Helpers +############################################################################### +def contravariant_order(expr, _strict=False): + """Return the contravariant order of an expression. + + Examples + ======== + + >>> from sympy.diffgeom import contravariant_order + >>> from sympy.diffgeom.rn import R2 + >>> from sympy.abc import a + + >>> contravariant_order(a) + 0 + >>> contravariant_order(a*R2.x + 2) + 0 + >>> contravariant_order(a*R2.x*R2.e_y + R2.e_x) + 1 + + """ + # TODO move some of this to class methods. + # TODO rewrite using the .as_blah_blah methods + if isinstance(expr, Add): + orders = [contravariant_order(e) for e in expr.args] + if len(set(orders)) != 1: + raise ValueError('Misformed expression containing contravariant fields of varying order.') + return orders[0] + elif isinstance(expr, Mul): + orders = [contravariant_order(e) for e in expr.args] + not_zero = [o for o in orders if o != 0] + if len(not_zero) > 1: + raise ValueError('Misformed expression containing multiplication between vectors.') + return 0 if not not_zero else not_zero[0] + elif isinstance(expr, Pow): + if covariant_order(expr.base) or covariant_order(expr.exp): + raise ValueError( + 'Misformed expression containing a power of a vector.') + return 0 + elif isinstance(expr, BaseVectorField): + return 1 + elif isinstance(expr, TensorProduct): + return sum(contravariant_order(a) for a in expr.args) + elif not _strict or expr.atoms(BaseScalarField): + return 0 + else: # If it does not contain anything related to the diffgeom module and it is _strict + return -1 + + +def covariant_order(expr, _strict=False): + """Return the covariant order of an expression. + + Examples + ======== + + >>> from sympy.diffgeom import covariant_order + >>> from sympy.diffgeom.rn import R2 + >>> from sympy.abc import a + + >>> covariant_order(a) + 0 + >>> covariant_order(a*R2.x + 2) + 0 + >>> covariant_order(a*R2.x*R2.dy + R2.dx) + 1 + + """ + # TODO move some of this to class methods. + # TODO rewrite using the .as_blah_blah methods + if isinstance(expr, Add): + orders = [covariant_order(e) for e in expr.args] + if len(set(orders)) != 1: + raise ValueError('Misformed expression containing form fields of varying order.') + return orders[0] + elif isinstance(expr, Mul): + orders = [covariant_order(e) for e in expr.args] + not_zero = [o for o in orders if o != 0] + if len(not_zero) > 1: + raise ValueError('Misformed expression containing multiplication between forms.') + return 0 if not not_zero else not_zero[0] + elif isinstance(expr, Pow): + if covariant_order(expr.base) or covariant_order(expr.exp): + raise ValueError( + 'Misformed expression containing a power of a form.') + return 0 + elif isinstance(expr, Differential): + return covariant_order(*expr.args) + 1 + elif isinstance(expr, TensorProduct): + return sum(covariant_order(a) for a in expr.args) + elif not _strict or expr.atoms(BaseScalarField): + return 0 + else: # If it does not contain anything related to the diffgeom module and it is _strict + return -1 + + +############################################################################### +# Coordinate transformation functions +############################################################################### +def vectors_in_basis(expr, to_sys): + """Transform all base vectors in base vectors of a specified coord basis. + While the new base vectors are in the new coordinate system basis, any + coefficients are kept in the old system. + + Examples + ======== + + >>> from sympy.diffgeom import vectors_in_basis + >>> from sympy.diffgeom.rn import R2_r, R2_p + + >>> vectors_in_basis(R2_r.e_x, R2_p) + -y*e_theta/(x**2 + y**2) + x*e_rho/sqrt(x**2 + y**2) + >>> vectors_in_basis(R2_p.e_r, R2_r) + sin(theta)*e_y + cos(theta)*e_x + + """ + vectors = list(expr.atoms(BaseVectorField)) + new_vectors = [] + for v in vectors: + cs = v._coord_sys + jac = cs.jacobian(to_sys, cs.coord_functions()) + new = (jac.T*Matrix(to_sys.base_vectors()))[v._index] + new_vectors.append(new) + return expr.subs(list(zip(vectors, new_vectors))) + + +############################################################################### +# Coordinate-dependent functions +############################################################################### +def twoform_to_matrix(expr): + """Return the matrix representing the twoform. + + For the twoform `w` return the matrix `M` such that `M[i,j]=w(e_i, e_j)`, + where `e_i` is the i-th base vector field for the coordinate system in + which the expression of `w` is given. + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2 + >>> from sympy.diffgeom import twoform_to_matrix, TensorProduct + >>> TP = TensorProduct + + >>> twoform_to_matrix(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) + Matrix([ + [1, 0], + [0, 1]]) + >>> twoform_to_matrix(R2.x*TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) + Matrix([ + [x, 0], + [0, 1]]) + >>> twoform_to_matrix(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy) - TP(R2.dx, R2.dy)/2) + Matrix([ + [ 1, 0], + [-1/2, 1]]) + + """ + if covariant_order(expr) != 2 or contravariant_order(expr): + raise ValueError('The input expression is not a two-form.') + coord_sys = _find_coords(expr) + if len(coord_sys) != 1: + raise ValueError('The input expression concerns more than one ' + 'coordinate systems, hence there is no unambiguous ' + 'way to choose a coordinate system for the matrix.') + coord_sys = coord_sys.pop() + vectors = coord_sys.base_vectors() + expr = expr.expand() + matrix_content = [[expr.rcall(v1, v2) for v1 in vectors] + for v2 in vectors] + return Matrix(matrix_content) + + +def metric_to_Christoffel_1st(expr): + """Return the nested list of Christoffel symbols for the given metric. + This returns the Christoffel symbol of first kind that represents the + Levi-Civita connection for the given metric. + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2 + >>> from sympy.diffgeom import metric_to_Christoffel_1st, TensorProduct + >>> TP = TensorProduct + + >>> metric_to_Christoffel_1st(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) + [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] + >>> metric_to_Christoffel_1st(R2.x*TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) + [[[1/2, 0], [0, 0]], [[0, 0], [0, 0]]] + + """ + matrix = twoform_to_matrix(expr) + if not matrix.is_symmetric(): + raise ValueError( + 'The two-form representing the metric is not symmetric.') + coord_sys = _find_coords(expr).pop() + deriv_matrices = [matrix.applyfunc(d) for d in coord_sys.base_vectors()] + indices = list(range(coord_sys.dim)) + christoffel = [[[(deriv_matrices[k][i, j] + deriv_matrices[j][i, k] - deriv_matrices[i][j, k])/2 + for k in indices] + for j in indices] + for i in indices] + return ImmutableDenseNDimArray(christoffel) + + +def metric_to_Christoffel_2nd(expr): + """Return the nested list of Christoffel symbols for the given metric. + This returns the Christoffel symbol of second kind that represents the + Levi-Civita connection for the given metric. + + Examples + ======== + + >>> from sympy.diffgeom.rn import R2 + >>> from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct + >>> TP = TensorProduct + + >>> metric_to_Christoffel_2nd(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) + [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] + >>> metric_to_Christoffel_2nd(R2.x*TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) + [[[1/(2*x), 0], [0, 0]], [[0, 0], [0, 0]]] + + """ + ch_1st = metric_to_Christoffel_1st(expr) + coord_sys = _find_coords(expr).pop() + indices = list(range(coord_sys.dim)) + # XXX workaround, inverting a matrix does not work if it contains non + # symbols + #matrix = twoform_to_matrix(expr).inv() + matrix = twoform_to_matrix(expr) + s_fields = set() + for e in matrix: + s_fields.update(e.atoms(BaseScalarField)) + s_fields = list(s_fields) + dums = coord_sys.symbols + matrix = matrix.subs(list(zip(s_fields, dums))).inv().subs(list(zip(dums, s_fields))) + # XXX end of workaround + christoffel = [[[Add(*[matrix[i, l]*ch_1st[l, j, k] for l in indices]) + for k in indices] + for j in indices] + for i in indices] + return ImmutableDenseNDimArray(christoffel) + + +def metric_to_Riemann_components(expr): + """Return the components of the Riemann tensor expressed in a given basis. + + Given a metric it calculates the components of the Riemann tensor in the + canonical basis of the coordinate system in which the metric expression is + given. + + Examples + ======== + + >>> from sympy import exp + >>> from sympy.diffgeom.rn import R2 + >>> from sympy.diffgeom import metric_to_Riemann_components, TensorProduct + >>> TP = TensorProduct + + >>> metric_to_Riemann_components(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) + [[[[0, 0], [0, 0]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]] + >>> non_trivial_metric = exp(2*R2.r)*TP(R2.dr, R2.dr) + \ + R2.r**2*TP(R2.dtheta, R2.dtheta) + >>> non_trivial_metric + exp(2*rho)*TensorProduct(drho, drho) + rho**2*TensorProduct(dtheta, dtheta) + >>> riemann = metric_to_Riemann_components(non_trivial_metric) + >>> riemann[0, :, :, :] + [[[0, 0], [0, 0]], [[0, exp(-2*rho)*rho], [-exp(-2*rho)*rho, 0]]] + >>> riemann[1, :, :, :] + [[[0, -1/rho], [1/rho, 0]], [[0, 0], [0, 0]]] + + """ + ch_2nd = metric_to_Christoffel_2nd(expr) + coord_sys = _find_coords(expr).pop() + indices = list(range(coord_sys.dim)) + deriv_ch = [[[[d(ch_2nd[i, j, k]) + for d in coord_sys.base_vectors()] + for k in indices] + for j in indices] + for i in indices] + riemann_a = [[[[deriv_ch[rho][sig][nu][mu] - deriv_ch[rho][sig][mu][nu] + for nu in indices] + for mu in indices] + for sig in indices] + for rho in indices] + riemann_b = [[[[Add(*[ch_2nd[rho, l, mu]*ch_2nd[l, sig, nu] - ch_2nd[rho, l, nu]*ch_2nd[l, sig, mu] for l in indices]) + for nu in indices] + for mu in indices] + for sig in indices] + for rho in indices] + riemann = [[[[riemann_a[rho][sig][mu][nu] + riemann_b[rho][sig][mu][nu] + for nu in indices] + for mu in indices] + for sig in indices] + for rho in indices] + return ImmutableDenseNDimArray(riemann) + + +def metric_to_Ricci_components(expr): + + """Return the components of the Ricci tensor expressed in a given basis. + + Given a metric it calculates the components of the Ricci tensor in the + canonical basis of the coordinate system in which the metric expression is + given. + + Examples + ======== + + >>> from sympy import exp + >>> from sympy.diffgeom.rn import R2 + >>> from sympy.diffgeom import metric_to_Ricci_components, TensorProduct + >>> TP = TensorProduct + + >>> metric_to_Ricci_components(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) + [[0, 0], [0, 0]] + >>> non_trivial_metric = exp(2*R2.r)*TP(R2.dr, R2.dr) + \ + R2.r**2*TP(R2.dtheta, R2.dtheta) + >>> non_trivial_metric + exp(2*rho)*TensorProduct(drho, drho) + rho**2*TensorProduct(dtheta, dtheta) + >>> metric_to_Ricci_components(non_trivial_metric) + [[1/rho, 0], [0, exp(-2*rho)*rho]] + + """ + riemann = metric_to_Riemann_components(expr) + coord_sys = _find_coords(expr).pop() + indices = list(range(coord_sys.dim)) + ricci = [[Add(*[riemann[k, i, k, j] for k in indices]) + for j in indices] + for i in indices] + return ImmutableDenseNDimArray(ricci) + +############################################################################### +# Classes for deprecation +############################################################################### + +class _deprecated_container: + # This class gives deprecation warning. + # When deprecated features are completely deleted, this should be removed as well. + # See https://github.com/sympy/sympy/pull/19368 + def __init__(self, message, data): + super().__init__(data) + self.message = message + + def warn(self): + sympy_deprecation_warning( + self.message, + deprecated_since_version="1.7", + active_deprecations_target="deprecated-diffgeom-mutable", + stacklevel=4 + ) + + def __iter__(self): + self.warn() + return super().__iter__() + + def __getitem__(self, key): + self.warn() + return super().__getitem__(key) + + def __contains__(self, key): + self.warn() + return super().__contains__(key) + + +class _deprecated_list(_deprecated_container, list): + pass + + +class _deprecated_dict(_deprecated_container, dict): + pass + + +# Import at end to avoid cyclic imports +from sympy.simplify.simplify import simplify diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/rn.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/rn.py new file mode 100644 index 0000000000000000000000000000000000000000..897c7e82bc804d260612f79c820af92632f3b281 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/diffgeom/rn.py @@ -0,0 +1,143 @@ +"""Predefined R^n manifolds together with common coord. systems. + +Coordinate systems are predefined as well as the transformation laws between +them. + +Coordinate functions can be accessed as attributes of the manifold (eg `R2.x`), +as attributes of the coordinate systems (eg `R2_r.x` and `R2_p.theta`), or by +using the usual `coord_sys.coord_function(index, name)` interface. +""" + +from typing import Any +import warnings + +from sympy.core.symbol import (Dummy, symbols) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (acos, atan2, cos, sin) +from .diffgeom import Manifold, Patch, CoordSystem + +__all__ = [ + 'R2', 'R2_origin', 'relations_2d', 'R2_r', 'R2_p', + 'R3', 'R3_origin', 'relations_3d', 'R3_r', 'R3_c', 'R3_s' +] + +############################################################################### +# R2 +############################################################################### +R2: Any = Manifold('R^2', 2) + +R2_origin: Any = Patch('origin', R2) + +x, y = symbols('x y', real=True) +r, theta = symbols('rho theta', nonnegative=True) + +relations_2d = { + ('rectangular', 'polar'): [(x, y), (sqrt(x**2 + y**2), atan2(y, x))], + ('polar', 'rectangular'): [(r, theta), (r*cos(theta), r*sin(theta))], +} + +R2_r: Any = CoordSystem('rectangular', R2_origin, (x, y), relations_2d) +R2_p: Any = CoordSystem('polar', R2_origin, (r, theta), relations_2d) + +# support deprecated feature +with warnings.catch_warnings(): + warnings.simplefilter("ignore") + x, y, r, theta = symbols('x y r theta', cls=Dummy) + R2_r.connect_to(R2_p, [x, y], + [sqrt(x**2 + y**2), atan2(y, x)], + inverse=False, fill_in_gaps=False) + R2_p.connect_to(R2_r, [r, theta], + [r*cos(theta), r*sin(theta)], + inverse=False, fill_in_gaps=False) + +# Defining the basis coordinate functions and adding shortcuts for them to the +# manifold and the patch. +R2.x, R2.y = R2_origin.x, R2_origin.y = R2_r.x, R2_r.y = R2_r.coord_functions() +R2.r, R2.theta = R2_origin.r, R2_origin.theta = R2_p.r, R2_p.theta = R2_p.coord_functions() + +# Defining the basis vector fields and adding shortcuts for them to the +# manifold and the patch. +R2.e_x, R2.e_y = R2_origin.e_x, R2_origin.e_y = R2_r.e_x, R2_r.e_y = R2_r.base_vectors() +R2.e_r, R2.e_theta = R2_origin.e_r, R2_origin.e_theta = R2_p.e_r, R2_p.e_theta = R2_p.base_vectors() + +# Defining the basis oneform fields and adding shortcuts for them to the +# manifold and the patch. +R2.dx, R2.dy = R2_origin.dx, R2_origin.dy = R2_r.dx, R2_r.dy = R2_r.base_oneforms() +R2.dr, R2.dtheta = R2_origin.dr, R2_origin.dtheta = R2_p.dr, R2_p.dtheta = R2_p.base_oneforms() + +############################################################################### +# R3 +############################################################################### +R3: Any = Manifold('R^3', 3) + +R3_origin: Any = Patch('origin', R3) + +x, y, z = symbols('x y z', real=True) +rho, psi, r, theta, phi = symbols('rho psi r theta phi', nonnegative=True) + +relations_3d = { + ('rectangular', 'cylindrical'): [(x, y, z), + (sqrt(x**2 + y**2), atan2(y, x), z)], + ('cylindrical', 'rectangular'): [(rho, psi, z), + (rho*cos(psi), rho*sin(psi), z)], + ('rectangular', 'spherical'): [(x, y, z), + (sqrt(x**2 + y**2 + z**2), + acos(z/sqrt(x**2 + y**2 + z**2)), + atan2(y, x))], + ('spherical', 'rectangular'): [(r, theta, phi), + (r*sin(theta)*cos(phi), + r*sin(theta)*sin(phi), + r*cos(theta))], + ('cylindrical', 'spherical'): [(rho, psi, z), + (sqrt(rho**2 + z**2), + acos(z/sqrt(rho**2 + z**2)), + psi)], + ('spherical', 'cylindrical'): [(r, theta, phi), + (r*sin(theta), phi, r*cos(theta))], +} + +R3_r: Any = CoordSystem('rectangular', R3_origin, (x, y, z), relations_3d) +R3_c: Any = CoordSystem('cylindrical', R3_origin, (rho, psi, z), relations_3d) +R3_s: Any = CoordSystem('spherical', R3_origin, (r, theta, phi), relations_3d) + +# support deprecated feature +with warnings.catch_warnings(): + warnings.simplefilter("ignore") + x, y, z, rho, psi, r, theta, phi = symbols('x y z rho psi r theta phi', cls=Dummy) + R3_r.connect_to(R3_c, [x, y, z], + [sqrt(x**2 + y**2), atan2(y, x), z], + inverse=False, fill_in_gaps=False) + R3_c.connect_to(R3_r, [rho, psi, z], + [rho*cos(psi), rho*sin(psi), z], + inverse=False, fill_in_gaps=False) + ## rectangular <-> spherical + R3_r.connect_to(R3_s, [x, y, z], + [sqrt(x**2 + y**2 + z**2), acos(z/ + sqrt(x**2 + y**2 + z**2)), atan2(y, x)], + inverse=False, fill_in_gaps=False) + R3_s.connect_to(R3_r, [r, theta, phi], + [r*sin(theta)*cos(phi), r*sin( + theta)*sin(phi), r*cos(theta)], + inverse=False, fill_in_gaps=False) + ## cylindrical <-> spherical + R3_c.connect_to(R3_s, [rho, psi, z], + [sqrt(rho**2 + z**2), acos(z/sqrt(rho**2 + z**2)), psi], + inverse=False, fill_in_gaps=False) + R3_s.connect_to(R3_c, [r, theta, phi], + [r*sin(theta), phi, r*cos(theta)], + inverse=False, fill_in_gaps=False) + +# Defining the basis coordinate functions. +R3_r.x, R3_r.y, R3_r.z = R3_r.coord_functions() +R3_c.rho, R3_c.psi, R3_c.z = R3_c.coord_functions() +R3_s.r, R3_s.theta, R3_s.phi = R3_s.coord_functions() + +# Defining the basis vector fields. +R3_r.e_x, R3_r.e_y, R3_r.e_z = R3_r.base_vectors() +R3_c.e_rho, R3_c.e_psi, R3_c.e_z = R3_c.base_vectors() +R3_s.e_r, R3_s.e_theta, R3_s.e_phi = R3_s.base_vectors() + +# Defining the basis oneform fields. +R3_r.dx, R3_r.dy, R3_r.dz = R3_r.base_oneforms() +R3_c.drho, R3_c.dpsi, R3_c.dz = R3_c.base_oneforms() +R3_s.dr, R3_s.dtheta, R3_s.dphi = R3_s.base_oneforms() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..968c4caa0d4562b71285f414bfb70f43d0b35111 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__init__.py @@ -0,0 +1,20 @@ +"""This module contains functions which operate on discrete sequences. + +Transforms - ``fft``, ``ifft``, ``ntt``, ``intt``, ``fwht``, ``ifwht``, + ``mobius_transform``, ``inverse_mobius_transform`` + +Convolutions - ``convolution``, ``convolution_fft``, ``convolution_ntt``, + ``convolution_fwht``, ``convolution_subset``, + ``covering_product``, ``intersecting_product`` +""" + +from .transforms import (fft, ifft, ntt, intt, fwht, ifwht, + mobius_transform, inverse_mobius_transform) +from .convolutions import convolution, covering_product, intersecting_product + +__all__ = [ + 'fft', 'ifft', 'ntt', 'intt', 'fwht', 'ifwht', 'mobius_transform', + 'inverse_mobius_transform', + + 'convolution', 'covering_product', 'intersecting_product', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33cb8c2e0d5d1be143aea21930e8b29392af4c55 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/convolutions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/convolutions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..896db06b05467ee2634d9d57e97c0a504394631b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/convolutions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/recurrences.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/recurrences.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6542bb0bbc13a638a4bf8f0c8075e71f2e13210 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/recurrences.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/transforms.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/transforms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c805d9f0a6534c5bec1a45df4df7c480a36cf7fb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/__pycache__/transforms.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/convolutions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/convolutions.py new file mode 100644 index 0000000000000000000000000000000000000000..ac9a3dbbb26b8b117ea1ee99cf7ebabbd21322cc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/convolutions.py @@ -0,0 +1,597 @@ +""" +Convolution (using **FFT**, **NTT**, **FWHT**), Subset Convolution, +Covering Product, Intersecting Product +""" + +from sympy.core import S, sympify, Rational +from sympy.core.function import expand_mul +from sympy.discrete.transforms import ( + fft, ifft, ntt, intt, fwht, ifwht, + mobius_transform, inverse_mobius_transform) +from sympy.external.gmpy import MPZ, lcm +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import as_int + + +def convolution(a, b, cycle=0, dps=None, prime=None, dyadic=None, subset=None): + """ + Performs convolution by determining the type of desired + convolution using hints. + + Exactly one of ``dps``, ``prime``, ``dyadic``, ``subset`` arguments + should be specified explicitly for identifying the type of convolution, + and the argument ``cycle`` can be specified optionally. + + For the default arguments, linear convolution is performed using **FFT**. + + Parameters + ========== + + a, b : iterables + The sequences for which convolution is performed. + cycle : Integer + Specifies the length for doing cyclic convolution. + dps : Integer + Specifies the number of decimal digits for precision for + performing **FFT** on the sequence. + prime : Integer + Prime modulus of the form `(m 2^k + 1)` to be used for + performing **NTT** on the sequence. + dyadic : bool + Identifies the convolution type as dyadic (*bitwise-XOR*) + convolution, which is performed using **FWHT**. + subset : bool + Identifies the convolution type as subset convolution. + + Examples + ======== + + >>> from sympy import convolution, symbols, S, I + >>> u, v, w, x, y, z = symbols('u v w x y z') + + >>> convolution([1 + 2*I, 4 + 3*I], [S(5)/4, 6], dps=3) + [1.25 + 2.5*I, 11.0 + 15.8*I, 24.0 + 18.0*I] + >>> convolution([1, 2, 3], [4, 5, 6], cycle=3) + [31, 31, 28] + + >>> convolution([111, 777], [888, 444], prime=19*2**10 + 1) + [1283, 19351, 14219] + >>> convolution([111, 777], [888, 444], prime=19*2**10 + 1, cycle=2) + [15502, 19351] + + >>> convolution([u, v], [x, y, z], dyadic=True) + [u*x + v*y, u*y + v*x, u*z, v*z] + >>> convolution([u, v], [x, y, z], dyadic=True, cycle=2) + [u*x + u*z + v*y, u*y + v*x + v*z] + + >>> convolution([u, v, w], [x, y, z], subset=True) + [u*x, u*y + v*x, u*z + w*x, v*z + w*y] + >>> convolution([u, v, w], [x, y, z], subset=True, cycle=3) + [u*x + v*z + w*y, u*y + v*x, u*z + w*x] + + """ + + c = as_int(cycle) + if c < 0: + raise ValueError("The length for cyclic convolution " + "must be non-negative") + + dyadic = True if dyadic else None + subset = True if subset else None + if sum(x is not None for x in (prime, dps, dyadic, subset)) > 1: + raise TypeError("Ambiguity in determining the type of convolution") + + if prime is not None: + ls = convolution_ntt(a, b, prime=prime) + return ls if not c else [sum(ls[i::c]) % prime for i in range(c)] + + if dyadic: + ls = convolution_fwht(a, b) + elif subset: + ls = convolution_subset(a, b) + else: + def loop(a): + dens = [] + for i in a: + if isinstance(i, Rational) and i.q - 1: + dens.append(i.q) + elif not isinstance(i, int): + return + if dens: + l = lcm(*dens) + return [i*l if type(i) is int else i.p*(l//i.q) for i in a], l + # no lcm of den to deal with + return a, 1 + ls = None + da = loop(a) + if da is not None: + db = loop(b) + if db is not None: + (ia, ma), (ib, mb) = da, db + den = ma*mb + ls = convolution_int(ia, ib) + if den != 1: + ls = [Rational(i, den) for i in ls] + if ls is None: + ls = convolution_fft(a, b, dps) + + return ls if not c else [sum(ls[i::c]) for i in range(c)] + + +#----------------------------------------------------------------------------# +# # +# Convolution for Complex domain # +# # +#----------------------------------------------------------------------------# + +def convolution_fft(a, b, dps=None): + """ + Performs linear convolution using Fast Fourier Transform. + + Parameters + ========== + + a, b : iterables + The sequences for which convolution is performed. + dps : Integer + Specifies the number of decimal digits for precision. + + Examples + ======== + + >>> from sympy import S, I + >>> from sympy.discrete.convolutions import convolution_fft + + >>> convolution_fft([2, 3], [4, 5]) + [8, 22, 15] + >>> convolution_fft([2, 5], [6, 7, 3]) + [12, 44, 41, 15] + >>> convolution_fft([1 + 2*I, 4 + 3*I], [S(5)/4, 6]) + [5/4 + 5*I/2, 11 + 63*I/4, 24 + 18*I] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Convolution_theorem + .. [2] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29 + + """ + + a, b = a[:], b[:] + n = m = len(a) + len(b) - 1 # convolution size + + if n > 0 and n&(n - 1): # not a power of 2 + n = 2**n.bit_length() + + # padding with zeros + a += [S.Zero]*(n - len(a)) + b += [S.Zero]*(n - len(b)) + + a, b = fft(a, dps), fft(b, dps) + a = [expand_mul(x*y) for x, y in zip(a, b)] + a = ifft(a, dps)[:m] + + return a + + +#----------------------------------------------------------------------------# +# # +# Convolution for GF(p) # +# # +#----------------------------------------------------------------------------# + +def convolution_ntt(a, b, prime): + """ + Performs linear convolution using Number Theoretic Transform. + + Parameters + ========== + + a, b : iterables + The sequences for which convolution is performed. + prime : Integer + Prime modulus of the form `(m 2^k + 1)` to be used for performing + **NTT** on the sequence. + + Examples + ======== + + >>> from sympy.discrete.convolutions import convolution_ntt + >>> convolution_ntt([2, 3], [4, 5], prime=19*2**10 + 1) + [8, 22, 15] + >>> convolution_ntt([2, 5], [6, 7, 3], prime=19*2**10 + 1) + [12, 44, 41, 15] + >>> convolution_ntt([333, 555], [222, 666], prime=19*2**10 + 1) + [15555, 14219, 19404] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Convolution_theorem + .. [2] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29 + + """ + + a, b, p = a[:], b[:], as_int(prime) + n = m = len(a) + len(b) - 1 # convolution size + + if n > 0 and n&(n - 1): # not a power of 2 + n = 2**n.bit_length() + + # padding with zeros + a += [0]*(n - len(a)) + b += [0]*(n - len(b)) + + a, b = ntt(a, p), ntt(b, p) + a = [x*y % p for x, y in zip(a, b)] + a = intt(a, p)[:m] + + return a + + +#----------------------------------------------------------------------------# +# # +# Convolution for 2**n-group # +# # +#----------------------------------------------------------------------------# + +def convolution_fwht(a, b): + """ + Performs dyadic (*bitwise-XOR*) convolution using Fast Walsh Hadamard + Transform. + + The convolution is automatically padded to the right with zeros, as the + *radix-2 FWHT* requires the number of sample points to be a power of 2. + + Parameters + ========== + + a, b : iterables + The sequences for which convolution is performed. + + Examples + ======== + + >>> from sympy import symbols, S, I + >>> from sympy.discrete.convolutions import convolution_fwht + + >>> u, v, x, y = symbols('u v x y') + >>> convolution_fwht([u, v], [x, y]) + [u*x + v*y, u*y + v*x] + + >>> convolution_fwht([2, 3], [4, 5]) + [23, 22] + >>> convolution_fwht([2, 5 + 4*I, 7], [6*I, 7, 3 + 4*I]) + [56 + 68*I, -10 + 30*I, 6 + 50*I, 48 + 32*I] + + >>> convolution_fwht([S(33)/7, S(55)/6, S(7)/4], [S(2)/3, 5]) + [2057/42, 1870/63, 7/6, 35/4] + + References + ========== + + .. [1] https://www.radioeng.cz/fulltexts/2002/02_03_40_42.pdf + .. [2] https://en.wikipedia.org/wiki/Hadamard_transform + + """ + + if not a or not b: + return [] + + a, b = a[:], b[:] + n = max(len(a), len(b)) + + if n&(n - 1): # not a power of 2 + n = 2**n.bit_length() + + # padding with zeros + a += [S.Zero]*(n - len(a)) + b += [S.Zero]*(n - len(b)) + + a, b = fwht(a), fwht(b) + a = [expand_mul(x*y) for x, y in zip(a, b)] + a = ifwht(a) + + return a + + +#----------------------------------------------------------------------------# +# # +# Subset Convolution # +# # +#----------------------------------------------------------------------------# + +def convolution_subset(a, b): + """ + Performs Subset Convolution of given sequences. + + The indices of each argument, considered as bit strings, correspond to + subsets of a finite set. + + The sequence is automatically padded to the right with zeros, as the + definition of subset based on bitmasks (indices) requires the size of + sequence to be a power of 2. + + Parameters + ========== + + a, b : iterables + The sequences for which convolution is performed. + + Examples + ======== + + >>> from sympy import symbols, S + >>> from sympy.discrete.convolutions import convolution_subset + >>> u, v, x, y, z = symbols('u v x y z') + + >>> convolution_subset([u, v], [x, y]) + [u*x, u*y + v*x] + >>> convolution_subset([u, v, x], [y, z]) + [u*y, u*z + v*y, x*y, x*z] + + >>> convolution_subset([1, S(2)/3], [3, 4]) + [3, 6] + >>> convolution_subset([1, 3, S(5)/7], [7]) + [7, 21, 5, 0] + + References + ========== + + .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf + + """ + + if not a or not b: + return [] + + if not iterable(a) or not iterable(b): + raise TypeError("Expected a sequence of coefficients for convolution") + + a = [sympify(arg) for arg in a] + b = [sympify(arg) for arg in b] + n = max(len(a), len(b)) + + if n&(n - 1): # not a power of 2 + n = 2**n.bit_length() + + # padding with zeros + a += [S.Zero]*(n - len(a)) + b += [S.Zero]*(n - len(b)) + + c = [S.Zero]*n + + for mask in range(n): + smask = mask + while smask > 0: + c[mask] += expand_mul(a[smask] * b[mask^smask]) + smask = (smask - 1)&mask + + c[mask] += expand_mul(a[smask] * b[mask^smask]) + + return c + + +#----------------------------------------------------------------------------# +# # +# Covering Product # +# # +#----------------------------------------------------------------------------# + +def covering_product(a, b): + """ + Returns the covering product of given sequences. + + The indices of each argument, considered as bit strings, correspond to + subsets of a finite set. + + The covering product of given sequences is a sequence which contains + the sum of products of the elements of the given sequences grouped by + the *bitwise-OR* of the corresponding indices. + + The sequence is automatically padded to the right with zeros, as the + definition of subset based on bitmasks (indices) requires the size of + sequence to be a power of 2. + + Parameters + ========== + + a, b : iterables + The sequences for which covering product is to be obtained. + + Examples + ======== + + >>> from sympy import symbols, S, I, covering_product + >>> u, v, x, y, z = symbols('u v x y z') + + >>> covering_product([u, v], [x, y]) + [u*x, u*y + v*x + v*y] + >>> covering_product([u, v, x], [y, z]) + [u*y, u*z + v*y + v*z, x*y, x*z] + + >>> covering_product([1, S(2)/3], [3, 4 + 5*I]) + [3, 26/3 + 25*I/3] + >>> covering_product([1, 3, S(5)/7], [7, 8]) + [7, 53, 5, 40/7] + + References + ========== + + .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf + + """ + + if not a or not b: + return [] + + a, b = a[:], b[:] + n = max(len(a), len(b)) + + if n&(n - 1): # not a power of 2 + n = 2**n.bit_length() + + # padding with zeros + a += [S.Zero]*(n - len(a)) + b += [S.Zero]*(n - len(b)) + + a, b = mobius_transform(a), mobius_transform(b) + a = [expand_mul(x*y) for x, y in zip(a, b)] + a = inverse_mobius_transform(a) + + return a + + +#----------------------------------------------------------------------------# +# # +# Intersecting Product # +# # +#----------------------------------------------------------------------------# + +def intersecting_product(a, b): + """ + Returns the intersecting product of given sequences. + + The indices of each argument, considered as bit strings, correspond to + subsets of a finite set. + + The intersecting product of given sequences is the sequence which + contains the sum of products of the elements of the given sequences + grouped by the *bitwise-AND* of the corresponding indices. + + The sequence is automatically padded to the right with zeros, as the + definition of subset based on bitmasks (indices) requires the size of + sequence to be a power of 2. + + Parameters + ========== + + a, b : iterables + The sequences for which intersecting product is to be obtained. + + Examples + ======== + + >>> from sympy import symbols, S, I, intersecting_product + >>> u, v, x, y, z = symbols('u v x y z') + + >>> intersecting_product([u, v], [x, y]) + [u*x + u*y + v*x, v*y] + >>> intersecting_product([u, v, x], [y, z]) + [u*y + u*z + v*y + x*y + x*z, v*z, 0, 0] + + >>> intersecting_product([1, S(2)/3], [3, 4 + 5*I]) + [9 + 5*I, 8/3 + 10*I/3] + >>> intersecting_product([1, 3, S(5)/7], [7, 8]) + [327/7, 24, 0, 0] + + References + ========== + + .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf + + """ + + if not a or not b: + return [] + + a, b = a[:], b[:] + n = max(len(a), len(b)) + + if n&(n - 1): # not a power of 2 + n = 2**n.bit_length() + + # padding with zeros + a += [S.Zero]*(n - len(a)) + b += [S.Zero]*(n - len(b)) + + a, b = mobius_transform(a, subset=False), mobius_transform(b, subset=False) + a = [expand_mul(x*y) for x, y in zip(a, b)] + a = inverse_mobius_transform(a, subset=False) + + return a + + +#----------------------------------------------------------------------------# +# # +# Integer Convolutions # +# # +#----------------------------------------------------------------------------# + +def convolution_int(a, b): + """Return the convolution of two sequences as a list. + + The iterables must consist solely of integers. + + Parameters + ========== + + a, b : Sequence + The sequences for which convolution is performed. + + Explanation + =========== + + This function performs the convolution of ``a`` and ``b`` by packing + each into a single integer, multiplying them together, and then + unpacking the result from the product. The intuition behind this is + that if we evaluate some polynomial [1]: + + .. math :: + 1156x^6 + 3808x^5 + 8440x^4 + 14856x^3 + 16164x^2 + 14040x + 8100 + + at say $x = 10^5$ we obtain $1156038080844014856161641404008100$. + Note we can read of the coefficients for each term every five digits. + If the $x$ we chose to evaluate at is large enough, the same will hold + for the product. + + The idea now is since big integer multiplication in libraries such + as GMP is highly optimised, this will be reasonably fast. + + Examples + ======== + + >>> from sympy.discrete.convolutions import convolution_int + + >>> convolution_int([2, 3], [4, 5]) + [8, 22, 15] + >>> convolution_int([1, 1, -1], [1, 1]) + [1, 2, 0, -1] + + References + ========== + + .. [1] Fateman, Richard J. + Can you save time in multiplying polynomials by encoding them as integers? + University of California, Berkeley, California (2004). + https://people.eecs.berkeley.edu/~fateman/papers/polysbyGMP.pdf + """ + # An upper bound on the largest coefficient in p(x)q(x) is given by (1 + min(dp, dq))N(p)N(q) + # where dp = deg(p), dq = deg(q), N(f) denotes the coefficient of largest modulus in f [1] + B = max(abs(c) for c in a)*max(abs(c) for c in b)*(1 + min(len(a) - 1, len(b) - 1)) + x, power = MPZ(1), 0 + while x <= (2*B): # multiply by two for negative coefficients, see [1] + x <<= 1 + power += 1 + + def to_integer(poly): + n, mul = MPZ(0), 0 + for c in reversed(poly): + if c and not mul: mul = -1 if c < 0 else 1 + n <<= power + n += mul*int(c) + return mul, n + + # Perform packing and multiplication + (a_mul, a_packed), (b_mul, b_packed) = to_integer(a), to_integer(b) + result = a_packed * b_packed + + # Perform unpacking + mul = a_mul * b_mul + mask, half, borrow, poly = x - 1, x >> 1, 0, [] + while result or borrow: + coeff = (result & mask) + borrow + result >>= power + borrow = coeff >= half + poly.append(mul * int(coeff if coeff < half else coeff - x)) + return poly or [0] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/recurrences.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/recurrences.py new file mode 100644 index 0000000000000000000000000000000000000000..0b0ed80d304161cf9ca298321aedc094c8cae1b3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/recurrences.py @@ -0,0 +1,166 @@ +""" +Recurrences +""" + +from sympy.core import S, sympify +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import as_int + + +def linrec(coeffs, init, n): + r""" + Evaluation of univariate linear recurrences of homogeneous type + having coefficients independent of the recurrence variable. + + Parameters + ========== + + coeffs : iterable + Coefficients of the recurrence + init : iterable + Initial values of the recurrence + n : Integer + Point of evaluation for the recurrence + + Notes + ===== + + Let `y(n)` be the recurrence of given type, ``c`` be the sequence + of coefficients, ``b`` be the sequence of initial/base values of the + recurrence and ``k`` (equal to ``len(c)``) be the order of recurrence. + Then, + + .. math :: y(n) = \begin{cases} b_n & 0 \le n < k \\ + c_0 y(n-1) + c_1 y(n-2) + \cdots + c_{k-1} y(n-k) & n \ge k + \end{cases} + + Let `x_0, x_1, \ldots, x_n` be a sequence and consider the transformation + that maps each polynomial `f(x)` to `T(f(x))` where each power `x^i` is + replaced by the corresponding value `x_i`. The sequence is then a solution + of the recurrence if and only if `T(x^i p(x)) = 0` for each `i \ge 0` where + `p(x) = x^k - c_0 x^(k-1) - \cdots - c_{k-1}` is the characteristic + polynomial. + + Then `T(f(x)p(x)) = 0` for each polynomial `f(x)` (as it is a linear + combination of powers `x^i`). Now, if `x^n` is congruent to + `g(x) = a_0 x^0 + a_1 x^1 + \cdots + a_{k-1} x^{k-1}` modulo `p(x)`, then + `T(x^n) = x_n` is equal to + `T(g(x)) = a_0 x_0 + a_1 x_1 + \cdots + a_{k-1} x_{k-1}`. + + Computation of `x^n`, + given `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}` + is performed using exponentiation by squaring (refer to [1_]) with + an additional reduction step performed to retain only first `k` powers + of `x` in the representation of `x^n`. + + Examples + ======== + + >>> from sympy.discrete.recurrences import linrec + >>> from sympy.abc import x, y, z + + >>> linrec(coeffs=[1, 1], init=[0, 1], n=10) + 55 + + >>> linrec(coeffs=[1, 1], init=[x, y], n=10) + 34*x + 55*y + + >>> linrec(coeffs=[x, y], init=[0, 1], n=5) + x**2*y + x*(x**3 + 2*x*y) + y**2 + + >>> linrec(coeffs=[1, 2, 3, 0, 0, 4], init=[x, y, z], n=16) + 13576*x + 5676*y + 2356*z + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Exponentiation_by_squaring + .. [2] https://en.wikipedia.org/w/index.php?title=Modular_exponentiation§ion=6#Matrices + + See Also + ======== + + sympy.polys.agca.extensions.ExtensionElement.__pow__ + + """ + + if not coeffs: + return S.Zero + + if not iterable(coeffs): + raise TypeError("Expected a sequence of coefficients for" + " the recurrence") + + if not iterable(init): + raise TypeError("Expected a sequence of values for the initialization" + " of the recurrence") + + n = as_int(n) + if n < 0: + raise ValueError("Point of evaluation of recurrence must be a " + "non-negative integer") + + c = [sympify(arg) for arg in coeffs] + b = [sympify(arg) for arg in init] + k = len(c) + + if len(b) > k: + raise TypeError("Count of initial values should not exceed the " + "order of the recurrence") + else: + b += [S.Zero]*(k - len(b)) # remaining initial values default to zero + + if n < k: + return b[n] + terms = [u*v for u, v in zip(linrec_coeffs(c, n), b)] + return sum(terms[:-1], terms[-1]) + + +def linrec_coeffs(c, n): + r""" + Compute the coefficients of n'th term in linear recursion + sequence defined by c. + + `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}`. + + It computes the coefficients by using binary exponentiation. + This function is used by `linrec` and `_eval_pow_by_cayley`. + + Parameters + ========== + + c = coefficients of the divisor polynomial + n = exponent of x, so dividend is x^n + + """ + + k = len(c) + + def _square_and_reduce(u, offset): + # squares `(u_0 + u_1 x + u_2 x^2 + \cdots + u_{k-1} x^k)` (and + # multiplies by `x` if offset is 1) and reduces the above result of + # length upto `2k` to `k` using the characteristic equation of the + # recurrence given by, `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}` + + w = [S.Zero]*(2*len(u) - 1 + offset) + for i, p in enumerate(u): + for j, q in enumerate(u): + w[offset + i + j] += p*q + + for j in range(len(w) - 1, k - 1, -1): + for i in range(k): + w[j - i - 1] += w[j]*c[i] + + return w[:k] + + def _final_coeffs(n): + # computes the final coefficient list - `cf` corresponding to the + # point at which recurrence is to be evalauted - `n`, such that, + # `y(n) = cf_0 y(k-1) + cf_1 y(k-2) + \cdots + cf_{k-1} y(0)` + + if n < k: + return [S.Zero]*n + [S.One] + [S.Zero]*(k - n - 1) + else: + return _square_and_reduce(_final_coeffs(n // 2), n % 2) + + return _final_coeffs(n) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d637a1996991cad159faa881723e5082335da8d0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_convolutions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_convolutions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..691ee84aef56c86196465ad3c8c1772768618d75 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_convolutions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_recurrences.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_recurrences.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..831efde4d68a0dde7875a93d5ae268ca24917a2d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_recurrences.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_transforms.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_transforms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b5320a25734ebb59a11ab4e5a5633bc2ba36cd5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/__pycache__/test_transforms.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_convolutions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_convolutions.py new file mode 100644 index 0000000000000000000000000000000000000000..96e5fc801ac63f95c01eb18d48143ae3a1ac6222 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_convolutions.py @@ -0,0 +1,392 @@ +from sympy.core.numbers import (E, Rational, pi) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.core import S, symbols, I +from sympy.discrete.convolutions import ( + convolution, convolution_fft, convolution_ntt, convolution_fwht, + convolution_subset, covering_product, intersecting_product, + convolution_int) +from sympy.testing.pytest import raises +from sympy.abc import x, y + +def test_convolution(): + # fft + a = [1, Rational(5, 3), sqrt(3), Rational(7, 5)] + b = [9, 5, 5, 4, 3, 2] + c = [3, 5, 3, 7, 8] + d = [1422, 6572, 3213, 5552] + e = [-1, Rational(5, 3), Rational(7, 5)] + + assert convolution(a, b) == convolution_fft(a, b) + assert convolution(a, b, dps=9) == convolution_fft(a, b, dps=9) + assert convolution(a, d, dps=7) == convolution_fft(d, a, dps=7) + assert convolution(a, d[1:], dps=3) == convolution_fft(d[1:], a, dps=3) + + # prime moduli of the form (m*2**k + 1), sequence length + # should be a divisor of 2**k + p = 7*17*2**23 + 1 + q = 19*2**10 + 1 + + # ntt + assert convolution(d, b, prime=q) == convolution_ntt(b, d, prime=q) + assert convolution(c, b, prime=p) == convolution_ntt(b, c, prime=p) + assert convolution(d, c, prime=p) == convolution_ntt(c, d, prime=p) + raises(TypeError, lambda: convolution(b, d, dps=5, prime=q)) + raises(TypeError, lambda: convolution(b, d, dps=6, prime=q)) + + # fwht + assert convolution(a, b, dyadic=True) == convolution_fwht(a, b) + assert convolution(a, b, dyadic=False) == convolution(a, b) + raises(TypeError, lambda: convolution(b, d, dps=2, dyadic=True)) + raises(TypeError, lambda: convolution(b, d, prime=p, dyadic=True)) + raises(TypeError, lambda: convolution(a, b, dps=2, dyadic=True)) + raises(TypeError, lambda: convolution(b, c, prime=p, dyadic=True)) + + # subset + assert convolution(a, b, subset=True) == convolution_subset(a, b) == \ + convolution(a, b, subset=True, dyadic=False) == \ + convolution(a, b, subset=True) + assert convolution(a, b, subset=False) == convolution(a, b) + raises(TypeError, lambda: convolution(a, b, subset=True, dyadic=True)) + raises(TypeError, lambda: convolution(c, d, subset=True, dps=6)) + raises(TypeError, lambda: convolution(a, c, subset=True, prime=q)) + + # integer + assert convolution([0], [0]) == convolution_int([0], [0]) + assert convolution(b, c) == convolution_int(b, c) + + # rational + assert convolution([Rational(1,2)], [Rational(1,2)]) == [Rational(1, 4)] + assert convolution(b, e) == [-9, 10, Rational(239, 15), Rational(34, 3), + Rational(32, 3), Rational(43, 5), Rational(113, 15), + Rational(14, 5)] + + +def test_cyclic_convolution(): + # fft + a = [1, Rational(5, 3), sqrt(3), Rational(7, 5)] + b = [9, 5, 5, 4, 3, 2] + + assert convolution([1, 2, 3], [4, 5, 6], cycle=0) == \ + convolution([1, 2, 3], [4, 5, 6], cycle=5) == \ + convolution([1, 2, 3], [4, 5, 6]) + + assert convolution([1, 2, 3], [4, 5, 6], cycle=3) == [31, 31, 28] + + a = [Rational(1, 3), Rational(7, 3), Rational(5, 9), Rational(2, 7), Rational(5, 8)] + b = [Rational(3, 5), Rational(4, 7), Rational(7, 8), Rational(8, 9)] + + assert convolution(a, b, cycle=0) == \ + convolution(a, b, cycle=len(a) + len(b) - 1) + + assert convolution(a, b, cycle=4) == [Rational(87277, 26460), Rational(30521, 11340), + Rational(11125, 4032), Rational(3653, 1080)] + + assert convolution(a, b, cycle=6) == [Rational(20177, 20160), Rational(676, 315), Rational(47, 24), + Rational(3053, 1080), Rational(16397, 5292), Rational(2497, 2268)] + + assert convolution(a, b, cycle=9) == \ + convolution(a, b, cycle=0) + [S.Zero] + + # ntt + a = [2313, 5323532, S(3232), 42142, 42242421] + b = [S(33456), 56757, 45754, 432423] + + assert convolution(a, b, prime=19*2**10 + 1, cycle=0) == \ + convolution(a, b, prime=19*2**10 + 1, cycle=8) == \ + convolution(a, b, prime=19*2**10 + 1) + + assert convolution(a, b, prime=19*2**10 + 1, cycle=5) == [96, 17146, 2664, + 15534, 3517] + + assert convolution(a, b, prime=19*2**10 + 1, cycle=7) == [4643, 3458, 1260, + 15534, 3517, 16314, 13688] + + assert convolution(a, b, prime=19*2**10 + 1, cycle=9) == \ + convolution(a, b, prime=19*2**10 + 1) + [0] + + # fwht + u, v, w, x, y = symbols('u v w x y') + p, q, r, s, t = symbols('p q r s t') + c = [u, v, w, x, y] + d = [p, q, r, s, t] + + assert convolution(a, b, dyadic=True, cycle=3) == \ + [2499522285783, 19861417974796, 4702176579021] + + assert convolution(a, b, dyadic=True, cycle=5) == [2718149225143, + 2114320852171, 20571217906407, 246166418903, 1413262436976] + + assert convolution(c, d, dyadic=True, cycle=4) == \ + [p*u + p*y + q*v + r*w + s*x + t*u + t*y, + p*v + q*u + q*y + r*x + s*w + t*v, + p*w + q*x + r*u + r*y + s*v + t*w, + p*x + q*w + r*v + s*u + s*y + t*x] + + assert convolution(c, d, dyadic=True, cycle=6) == \ + [p*u + q*v + r*w + r*y + s*x + t*w + t*y, + p*v + q*u + r*x + s*w + s*y + t*x, + p*w + q*x + r*u + s*v, + p*x + q*w + r*v + s*u, + p*y + t*u, + q*y + t*v] + + # subset + assert convolution(a, b, subset=True, cycle=7) == [18266671799811, + 178235365533, 213958794, 246166418903, 1413262436976, + 2397553088697, 1932759730434] + + assert convolution(a[1:], b, subset=True, cycle=4) == \ + [178104086592, 302255835516, 244982785880, 3717819845434] + + assert convolution(a, b[:-1], subset=True, cycle=6) == [1932837114162, + 178235365533, 213958794, 245166224504, 1413262436976, 2397553088697] + + assert convolution(c, d, subset=True, cycle=3) == \ + [p*u + p*x + q*w + r*v + r*y + s*u + t*w, + p*v + p*y + q*u + s*y + t*u + t*x, + p*w + q*y + r*u + t*v] + + assert convolution(c, d, subset=True, cycle=5) == \ + [p*u + q*y + t*v, + p*v + q*u + r*y + t*w, + p*w + r*u + s*y + t*x, + p*x + q*w + r*v + s*u, + p*y + t*u] + + raises(ValueError, lambda: convolution([1, 2, 3], [4, 5, 6], cycle=-1)) + + +def test_convolution_fft(): + assert all(convolution_fft([], x, dps=y) == [] for x in ([], [1]) for y in (None, 3)) + assert convolution_fft([1, 2, 3], [4, 5, 6]) == [4, 13, 28, 27, 18] + assert convolution_fft([1], [5, 6, 7]) == [5, 6, 7] + assert convolution_fft([1, 3], [5, 6, 7]) == [5, 21, 25, 21] + + assert convolution_fft([1 + 2*I], [2 + 3*I]) == [-4 + 7*I] + assert convolution_fft([1 + 2*I, 3 + 4*I, 5 + 3*I/5], [Rational(2, 5) + 4*I/7]) == \ + [Rational(-26, 35) + I*48/35, Rational(-38, 35) + I*116/35, Rational(58, 35) + I*542/175] + + assert convolution_fft([Rational(3, 4), Rational(5, 6)], [Rational(7, 8), Rational(1, 3), Rational(2, 5)]) == \ + [Rational(21, 32), Rational(47, 48), Rational(26, 45), Rational(1, 3)] + + assert convolution_fft([Rational(1, 9), Rational(2, 3), Rational(3, 5)], [Rational(2, 5), Rational(3, 7), Rational(4, 9)]) == \ + [Rational(2, 45), Rational(11, 35), Rational(8152, 14175), Rational(523, 945), Rational(4, 15)] + + assert convolution_fft([pi, E, sqrt(2)], [sqrt(3), 1/pi, 1/E]) == \ + [sqrt(3)*pi, 1 + sqrt(3)*E, E/pi + pi*exp(-1) + sqrt(6), + sqrt(2)/pi + 1, sqrt(2)*exp(-1)] + + assert convolution_fft([2321, 33123], [5321, 6321, 71323]) == \ + [12350041, 190918524, 374911166, 2362431729] + + assert convolution_fft([312313, 31278232], [32139631, 319631]) == \ + [10037624576503, 1005370659728895, 9997492572392] + + raises(TypeError, lambda: convolution_fft(x, y)) + raises(ValueError, lambda: convolution_fft([x, y], [y, x])) + + +def test_convolution_ntt(): + # prime moduli of the form (m*2**k + 1), sequence length + # should be a divisor of 2**k + p = 7*17*2**23 + 1 + q = 19*2**10 + 1 + r = 2*500000003 + 1 # only for sequences of length 1 or 2 + # s = 2*3*5*7 # composite modulus + + assert all(convolution_ntt([], x, prime=y) == [] for x in ([], [1]) for y in (p, q, r)) + assert convolution_ntt([2], [3], r) == [6] + assert convolution_ntt([2, 3], [4], r) == [8, 12] + + assert convolution_ntt([32121, 42144, 4214, 4241], [32132, 3232, 87242], p) == [33867619, + 459741727, 79180879, 831885249, 381344700, 369993322] + assert convolution_ntt([121913, 3171831, 31888131, 12], [17882, 21292, 29921, 312], q) == \ + [8158, 3065, 3682, 7090, 1239, 2232, 3744] + + assert convolution_ntt([12, 19, 21, 98, 67], [2, 6, 7, 8, 9], p) == \ + convolution_ntt([12, 19, 21, 98, 67], [2, 6, 7, 8, 9], q) + assert convolution_ntt([12, 19, 21, 98, 67], [21, 76, 17, 78, 69], p) == \ + convolution_ntt([12, 19, 21, 98, 67], [21, 76, 17, 78, 69], q) + + raises(ValueError, lambda: convolution_ntt([2, 3], [4, 5], r)) + raises(ValueError, lambda: convolution_ntt([x, y], [y, x], q)) + raises(TypeError, lambda: convolution_ntt(x, y, p)) + + +def test_convolution_fwht(): + assert convolution_fwht([], []) == [] + assert convolution_fwht([], [1]) == [] + assert convolution_fwht([1, 2, 3], [4, 5, 6]) == [32, 13, 18, 27] + + assert convolution_fwht([Rational(5, 7), Rational(6, 8), Rational(7, 3)], [2, 4, Rational(6, 7)]) == \ + [Rational(45, 7), Rational(61, 14), Rational(776, 147), Rational(419, 42)] + + a = [1, Rational(5, 3), sqrt(3), Rational(7, 5), 4 + 5*I] + b = [94, 51, 53, 45, 31, 27, 13] + c = [3 + 4*I, 5 + 7*I, 3, Rational(7, 6), 8] + + assert convolution_fwht(a, b) == [53*sqrt(3) + 366 + 155*I, + 45*sqrt(3) + Rational(5848, 15) + 135*I, + 94*sqrt(3) + Rational(1257, 5) + 65*I, + 51*sqrt(3) + Rational(3974, 15), + 13*sqrt(3) + 452 + 470*I, + Rational(4513, 15) + 255*I, + 31*sqrt(3) + Rational(1314, 5) + 265*I, + 27*sqrt(3) + Rational(3676, 15) + 225*I] + + assert convolution_fwht(b, c) == [Rational(1993, 2) + 733*I, Rational(6215, 6) + 862*I, + Rational(1659, 2) + 527*I, Rational(1988, 3) + 551*I, 1019 + 313*I, Rational(3955, 6) + 325*I, + Rational(1175, 2) + 52*I, Rational(3253, 6) + 91*I] + + assert convolution_fwht(a[3:], c) == [Rational(-54, 5) + I*293/5, -1 + I*204/5, + Rational(133, 15) + I*35/6, Rational(409, 30) + 15*I, Rational(56, 5), 32 + 40*I, 0, 0] + + u, v, w, x, y, z = symbols('u v w x y z') + + assert convolution_fwht([u, v], [x, y]) == [u*x + v*y, u*y + v*x] + + assert convolution_fwht([u, v, w], [x, y]) == \ + [u*x + v*y, u*y + v*x, w*x, w*y] + + assert convolution_fwht([u, v, w], [x, y, z]) == \ + [u*x + v*y + w*z, u*y + v*x, u*z + w*x, v*z + w*y] + + raises(TypeError, lambda: convolution_fwht(x, y)) + raises(TypeError, lambda: convolution_fwht(x*y, u + v)) + + +def test_convolution_subset(): + assert convolution_subset([], []) == [] + assert convolution_subset([], [Rational(1, 3)]) == [] + assert convolution_subset([6 + I*3/7], [Rational(2, 3)]) == [4 + I*2/7] + + a = [1, Rational(5, 3), sqrt(3), 4 + 5*I] + b = [64, 71, 55, 47, 33, 29, 15] + c = [3 + I*2/3, 5 + 7*I, 7, Rational(7, 5), 9] + + assert convolution_subset(a, b) == [64, Rational(533, 3), 55 + 64*sqrt(3), + 71*sqrt(3) + Rational(1184, 3) + 320*I, 33, 84, + 15 + 33*sqrt(3), 29*sqrt(3) + 157 + 165*I] + + assert convolution_subset(b, c) == [192 + I*128/3, 533 + I*1486/3, + 613 + I*110/3, Rational(5013, 5) + I*1249/3, + 675 + 22*I, 891 + I*751/3, + 771 + 10*I, Rational(3736, 5) + 105*I] + + assert convolution_subset(a, c) == convolution_subset(c, a) + assert convolution_subset(a[:2], b) == \ + [64, Rational(533, 3), 55, Rational(416, 3), 33, 84, 15, 25] + + assert convolution_subset(a[:2], c) == \ + [3 + I*2/3, 10 + I*73/9, 7, Rational(196, 15), 9, 15, 0, 0] + + u, v, w, x, y, z = symbols('u v w x y z') + + assert convolution_subset([u, v, w], [x, y]) == [u*x, u*y + v*x, w*x, w*y] + assert convolution_subset([u, v, w, x], [y, z]) == \ + [u*y, u*z + v*y, w*y, w*z + x*y] + + assert convolution_subset([u, v], [x, y, z]) == \ + convolution_subset([x, y, z], [u, v]) + + raises(TypeError, lambda: convolution_subset(x, z)) + raises(TypeError, lambda: convolution_subset(Rational(7, 3), u)) + + +def test_covering_product(): + assert covering_product([], []) == [] + assert covering_product([], [Rational(1, 3)]) == [] + assert covering_product([6 + I*3/7], [Rational(2, 3)]) == [4 + I*2/7] + + a = [1, Rational(5, 8), sqrt(7), 4 + 9*I] + b = [66, 81, 95, 49, 37, 89, 17] + c = [3 + I*2/3, 51 + 72*I, 7, Rational(7, 15), 91] + + assert covering_product(a, b) == [66, Rational(1383, 8), 95 + 161*sqrt(7), + 130*sqrt(7) + 1303 + 2619*I, 37, + Rational(671, 4), 17 + 54*sqrt(7), + 89*sqrt(7) + Rational(4661, 8) + 1287*I] + + assert covering_product(b, c) == [198 + 44*I, 7740 + 10638*I, + 1412 + I*190/3, Rational(42684, 5) + I*31202/3, + 9484 + I*74/3, 22163 + I*27394/3, + 10621 + I*34/3, Rational(90236, 15) + 1224*I] + + assert covering_product(a, c) == covering_product(c, a) + assert covering_product(b, c[:-1]) == [198 + 44*I, 7740 + 10638*I, + 1412 + I*190/3, Rational(42684, 5) + I*31202/3, + 111 + I*74/3, 6693 + I*27394/3, + 429 + I*34/3, Rational(23351, 15) + 1224*I] + + assert covering_product(a, c[:-1]) == [3 + I*2/3, + Rational(339, 4) + I*1409/12, 7 + 10*sqrt(7) + 2*sqrt(7)*I/3, + -403 + 772*sqrt(7)/15 + 72*sqrt(7)*I + I*12658/15] + + u, v, w, x, y, z = symbols('u v w x y z') + + assert covering_product([u, v, w], [x, y]) == \ + [u*x, u*y + v*x + v*y, w*x, w*y] + + assert covering_product([u, v, w, x], [y, z]) == \ + [u*y, u*z + v*y + v*z, w*y, w*z + x*y + x*z] + + assert covering_product([u, v], [x, y, z]) == \ + covering_product([x, y, z], [u, v]) + + raises(TypeError, lambda: covering_product(x, z)) + raises(TypeError, lambda: covering_product(Rational(7, 3), u)) + + +def test_intersecting_product(): + assert intersecting_product([], []) == [] + assert intersecting_product([], [Rational(1, 3)]) == [] + assert intersecting_product([6 + I*3/7], [Rational(2, 3)]) == [4 + I*2/7] + + a = [1, sqrt(5), Rational(3, 8) + 5*I, 4 + 7*I] + b = [67, 51, 65, 48, 36, 79, 27] + c = [3 + I*2/5, 5 + 9*I, 7, Rational(7, 19), 13] + + assert intersecting_product(a, b) == [195*sqrt(5) + Rational(6979, 8) + 1886*I, + 178*sqrt(5) + 520 + 910*I, Rational(841, 2) + 1344*I, + 192 + 336*I, 0, 0, 0, 0] + + assert intersecting_product(b, c) == [Rational(128553, 19) + I*9521/5, + Rational(17820, 19) + 1602*I, Rational(19264, 19), Rational(336, 19), 1846, 0, 0, 0] + + assert intersecting_product(a, c) == intersecting_product(c, a) + assert intersecting_product(b[1:], c[:-1]) == [Rational(64788, 19) + I*8622/5, + Rational(12804, 19) + 1152*I, Rational(11508, 19), Rational(252, 19), 0, 0, 0, 0] + + assert intersecting_product(a, c[:-2]) == \ + [Rational(-99, 5) + 10*sqrt(5) + 2*sqrt(5)*I/5 + I*3021/40, + -43 + 5*sqrt(5) + 9*sqrt(5)*I + 71*I, Rational(245, 8) + 84*I, 0] + + u, v, w, x, y, z = symbols('u v w x y z') + + assert intersecting_product([u, v, w], [x, y]) == \ + [u*x + u*y + v*x + w*x + w*y, v*y, 0, 0] + + assert intersecting_product([u, v, w, x], [y, z]) == \ + [u*y + u*z + v*y + w*y + w*z + x*y, v*z + x*z, 0, 0] + + assert intersecting_product([u, v], [x, y, z]) == \ + intersecting_product([x, y, z], [u, v]) + + raises(TypeError, lambda: intersecting_product(x, z)) + raises(TypeError, lambda: intersecting_product(u, Rational(8, 3))) + + +def test_convolution_int(): + assert convolution_int([1], [1]) == [1] + assert convolution_int([1, 1], [0]) == [0] + assert convolution_int([1, 2, 3], [4, 5, 6]) == [4, 13, 28, 27, 18] + assert convolution_int([1], [5, 6, 7]) == [5, 6, 7] + assert convolution_int([1, 3], [5, 6, 7]) == [5, 21, 25, 21] + assert convolution_int([10, -5, 1, 3], [-5, 6, 7]) == [-50, 85, 35, -44, 25, 21] + assert convolution_int([0, 1, 0, -1], [1, 0, -1, 0]) == [0, 1, 0, -2, 0, 1] + assert convolution_int( + [-341, -5, 1, 3, -71, -99, 43, 87], + [5, 6, 7, 12, 345, 21, -78, -7, -89] + ) == [-1705, -2071, -2412, -4106, -118035, -9774, 25998, 2981, 5509, + -34317, 19228, 38870, 5485, 1724, -4436, -7743] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_recurrences.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_recurrences.py new file mode 100644 index 0000000000000000000000000000000000000000..2c2186ca525b6680350a03edbe44ca88f8f95c3c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_recurrences.py @@ -0,0 +1,59 @@ +from sympy.core.numbers import Rational +from sympy.functions.combinatorial.numbers import fibonacci +from sympy.core import S, symbols +from sympy.testing.pytest import raises +from sympy.discrete.recurrences import linrec + +def test_linrec(): + assert linrec(coeffs=[1, 1], init=[1, 1], n=20) == 10946 + assert linrec(coeffs=[1, 2, 3, 4, 5], init=[1, 1, 0, 2], n=10) == 1040 + assert linrec(coeffs=[0, 0, 11, 13], init=[23, 27], n=25) == 59628567384 + assert linrec(coeffs=[0, 0, 1, 1, 2], init=[1, 5, 3], n=15) == 165 + assert linrec(coeffs=[11, 13, 15, 17], init=[1, 2, 3, 4], n=70) == \ + 56889923441670659718376223533331214868804815612050381493741233489928913241 + assert linrec(coeffs=[0]*55 + [1, 1, 2, 3], init=[0]*50 + [1, 2, 3], n=4000) == \ + 702633573874937994980598979769135096432444135301118916539 + + assert linrec(coeffs=[11, 13, 15, 17], init=[1, 2, 3, 4], n=10**4) + assert linrec(coeffs=[11, 13, 15, 17], init=[1, 2, 3, 4], n=10**5) + + assert all(linrec(coeffs=[1, 1], init=[0, 1], n=n) == fibonacci(n) + for n in range(95, 115)) + + assert all(linrec(coeffs=[1, 1], init=[1, 1], n=n) == fibonacci(n + 1) + for n in range(595, 615)) + + a = [S.Half, Rational(3, 4), Rational(5, 6), 7, Rational(8, 9), Rational(3, 5)] + b = [1, 2, 8, Rational(5, 7), Rational(3, 7), Rational(2, 9), 6] + x, y, z = symbols('x y z') + + assert linrec(coeffs=a[:5], init=b[:4], n=80) == \ + Rational(1726244235456268979436592226626304376013002142588105090705187189, + 1960143456748895967474334873705475211264) + + assert linrec(coeffs=a[:4], init=b[:4], n=50) == \ + Rational(368949940033050147080268092104304441, 504857282956046106624) + + assert linrec(coeffs=a[3:], init=b[:3], n=35) == \ + Rational(97409272177295731943657945116791049305244422833125109, + 814315512679031689453125) + + assert linrec(coeffs=[0]*60 + [Rational(2, 3), Rational(4, 5)], init=b, n=3000) == \ + Rational(26777668739896791448594650497024, 48084516708184142230517578125) + + raises(TypeError, lambda: linrec(coeffs=[11, 13, 15, 17], init=[1, 2, 3, 4, 5], n=1)) + raises(TypeError, lambda: linrec(coeffs=a[:4], init=b[:5], n=10000)) + raises(ValueError, lambda: linrec(coeffs=a[:4], init=b[:4], n=-10000)) + raises(TypeError, lambda: linrec(x, b, n=10000)) + raises(TypeError, lambda: linrec(a, y, n=10000)) + + assert linrec(coeffs=[x, y, z], init=[1, 1, 1], n=4) == \ + x**2 + x*y + x*z + y + z + assert linrec(coeffs=[1, 2, 1], init=[x, y, z], n=20) == \ + 269542*x + 664575*y + 578949*z + assert linrec(coeffs=[0, 3, 1, 2], init=[x, y], n=30) == \ + 58516436*x + 56372788*y + assert linrec(coeffs=[0]*50 + [1, 2, 3], init=[x, y, z], n=1000) == \ + 11477135884896*x + 25999077948732*y + 41975630244216*z + assert linrec(coeffs=[], init=[1, 1], n=20) == 0 + assert linrec(coeffs=[x, y, z], init=[1, 2, 3], n=2) == 3 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_transforms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..385514be4cdec2f19cf3a750bdbe0f4f6e21cc6e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/tests/test_transforms.py @@ -0,0 +1,154 @@ +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.core import S, Symbol, symbols, I, Rational +from sympy.discrete import (fft, ifft, ntt, intt, fwht, ifwht, + mobius_transform, inverse_mobius_transform) +from sympy.testing.pytest import raises + + +def test_fft_ifft(): + assert all(tf(ls) == ls for tf in (fft, ifft) + for ls in ([], [Rational(5, 3)])) + + ls = list(range(6)) + fls = [15, -7*sqrt(2)/2 - 4 - sqrt(2)*I/2 + 2*I, 2 + 3*I, + -4 + 7*sqrt(2)/2 - 2*I - sqrt(2)*I/2, -3, + -4 + 7*sqrt(2)/2 + sqrt(2)*I/2 + 2*I, + 2 - 3*I, -7*sqrt(2)/2 - 4 - 2*I + sqrt(2)*I/2] + + assert fft(ls) == fls + assert ifft(fls) == ls + [S.Zero]*2 + + ls = [1 + 2*I, 3 + 4*I, 5 + 6*I] + ifls = [Rational(9, 4) + 3*I, I*Rational(-7, 4), Rational(3, 4) + I, -2 - I/4] + + assert ifft(ls) == ifls + assert fft(ifls) == ls + [S.Zero] + + x = Symbol('x', real=True) + raises(TypeError, lambda: fft(x)) + raises(ValueError, lambda: ifft([x, 2*x, 3*x**2, 4*x**3])) + + +def test_ntt_intt(): + # prime moduli of the form (m*2**k + 1), sequence length + # should be a divisor of 2**k + p = 7*17*2**23 + 1 + q = 2*500000003 + 1 # only for sequences of length 1 or 2 + r = 2*3*5*7 # composite modulus + + assert all(tf(ls, p) == ls for tf in (ntt, intt) + for ls in ([], [5])) + + ls = list(range(6)) + nls = [15, 801133602, 738493201, 334102277, 998244350, 849020224, + 259751156, 12232587] + + assert ntt(ls, p) == nls + assert intt(nls, p) == ls + [0]*2 + + ls = [1 + 2*I, 3 + 4*I, 5 + 6*I] + x = Symbol('x', integer=True) + + raises(TypeError, lambda: ntt(x, p)) + raises(ValueError, lambda: intt([x, 2*x, 3*x**2, 4*x**3], p)) + raises(ValueError, lambda: intt(ls, p)) + raises(ValueError, lambda: ntt([1.2, 2.1, 3.5], p)) + raises(ValueError, lambda: ntt([3, 5, 6], q)) + raises(ValueError, lambda: ntt([4, 5, 7], r)) + raises(ValueError, lambda: ntt([1.0, 2.0, 3.0], p)) + + +def test_fwht_ifwht(): + assert all(tf(ls) == ls for tf in (fwht, ifwht) \ + for ls in ([], [Rational(7, 4)])) + + ls = [213, 321, 43235, 5325, 312, 53] + fls = [49459, 38061, -47661, -37759, 48729, 37543, -48391, -38277] + + assert fwht(ls) == fls + assert ifwht(fls) == ls + [S.Zero]*2 + + ls = [S.Half + 2*I, Rational(3, 7) + 4*I, Rational(5, 6) + 6*I, Rational(7, 3), Rational(9, 4)] + ifls = [Rational(533, 672) + I*3/2, Rational(23, 224) + I/2, Rational(1, 672), Rational(107, 224) - I, + Rational(155, 672) + I*3/2, Rational(-103, 224) + I/2, Rational(-377, 672), Rational(-19, 224) - I] + + assert ifwht(ls) == ifls + assert fwht(ifls) == ls + [S.Zero]*3 + + x, y = symbols('x y') + + raises(TypeError, lambda: fwht(x)) + + ls = [x, 2*x, 3*x**2, 4*x**3] + ifls = [x**3 + 3*x**2/4 + x*Rational(3, 4), + -x**3 + 3*x**2/4 - x/4, + -x**3 - 3*x**2/4 + x*Rational(3, 4), + x**3 - 3*x**2/4 - x/4] + + assert ifwht(ls) == ifls + assert fwht(ifls) == ls + + ls = [x, y, x**2, y**2, x*y] + fls = [x**2 + x*y + x + y**2 + y, + x**2 + x*y + x - y**2 - y, + -x**2 + x*y + x - y**2 + y, + -x**2 + x*y + x + y**2 - y, + x**2 - x*y + x + y**2 + y, + x**2 - x*y + x - y**2 - y, + -x**2 - x*y + x - y**2 + y, + -x**2 - x*y + x + y**2 - y] + + assert fwht(ls) == fls + assert ifwht(fls) == ls + [S.Zero]*3 + + ls = list(range(6)) + + assert fwht(ls) == [x*8 for x in ifwht(ls)] + + +def test_mobius_transform(): + assert all(tf(ls, subset=subset) == ls + for ls in ([], [Rational(7, 4)]) for subset in (True, False) + for tf in (mobius_transform, inverse_mobius_transform)) + + w, x, y, z = symbols('w x y z') + + assert mobius_transform([x, y]) == [x, x + y] + assert inverse_mobius_transform([x, x + y]) == [x, y] + assert mobius_transform([x, y], subset=False) == [x + y, y] + assert inverse_mobius_transform([x + y, y], subset=False) == [x, y] + + assert mobius_transform([w, x, y, z]) == [w, w + x, w + y, w + x + y + z] + assert inverse_mobius_transform([w, w + x, w + y, w + x + y + z]) == \ + [w, x, y, z] + assert mobius_transform([w, x, y, z], subset=False) == \ + [w + x + y + z, x + z, y + z, z] + assert inverse_mobius_transform([w + x + y + z, x + z, y + z, z], subset=False) == \ + [w, x, y, z] + + ls = [Rational(2, 3), Rational(6, 7), Rational(5, 8), 9, Rational(5, 3) + 7*I] + mls = [Rational(2, 3), Rational(32, 21), Rational(31, 24), Rational(1873, 168), + Rational(7, 3) + 7*I, Rational(67, 21) + 7*I, Rational(71, 24) + 7*I, + Rational(2153, 168) + 7*I] + + assert mobius_transform(ls) == mls + assert inverse_mobius_transform(mls) == ls + [S.Zero]*3 + + mls = [Rational(2153, 168) + 7*I, Rational(69, 7), Rational(77, 8), 9, Rational(5, 3) + 7*I, 0, 0, 0] + + assert mobius_transform(ls, subset=False) == mls + assert inverse_mobius_transform(mls, subset=False) == ls + [S.Zero]*3 + + ls = ls[:-1] + mls = [Rational(2, 3), Rational(32, 21), Rational(31, 24), Rational(1873, 168)] + + assert mobius_transform(ls) == mls + assert inverse_mobius_transform(mls) == ls + + mls = [Rational(1873, 168), Rational(69, 7), Rational(77, 8), 9] + + assert mobius_transform(ls, subset=False) == mls + assert inverse_mobius_transform(mls, subset=False) == ls + + raises(TypeError, lambda: mobius_transform(x, subset=True)) + raises(TypeError, lambda: inverse_mobius_transform(y, subset=False)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/transforms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..cb3550837021a4cf99e38c6b15f89ce8bb69b25a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/discrete/transforms.py @@ -0,0 +1,425 @@ +""" +Discrete Fourier Transform, Number Theoretic Transform, +Walsh Hadamard Transform, Mobius Transform +""" + +from sympy.core import S, Symbol, sympify +from sympy.core.function import expand_mul +from sympy.core.numbers import pi, I +from sympy.functions.elementary.trigonometric import sin, cos +from sympy.ntheory import isprime, primitive_root +from sympy.utilities.iterables import ibin, iterable +from sympy.utilities.misc import as_int + + +#----------------------------------------------------------------------------# +# # +# Discrete Fourier Transform # +# # +#----------------------------------------------------------------------------# + +def _fourier_transform(seq, dps, inverse=False): + """Utility function for the Discrete Fourier Transform""" + + if not iterable(seq): + raise TypeError("Expected a sequence of numeric coefficients " + "for Fourier Transform") + + a = [sympify(arg) for arg in seq] + if any(x.has(Symbol) for x in a): + raise ValueError("Expected non-symbolic coefficients") + + n = len(a) + if n < 2: + return a + + b = n.bit_length() - 1 + if n&(n - 1): # not a power of 2 + b += 1 + n = 2**b + + a += [S.Zero]*(n - len(a)) + for i in range(1, n): + j = int(ibin(i, b, str=True)[::-1], 2) + if i < j: + a[i], a[j] = a[j], a[i] + + ang = -2*pi/n if inverse else 2*pi/n + + if dps is not None: + ang = ang.evalf(dps + 2) + + w = [cos(ang*i) + I*sin(ang*i) for i in range(n // 2)] + + h = 2 + while h <= n: + hf, ut = h // 2, n // h + for i in range(0, n, h): + for j in range(hf): + u, v = a[i + j], expand_mul(a[i + j + hf]*w[ut * j]) + a[i + j], a[i + j + hf] = u + v, u - v + h *= 2 + + if inverse: + a = [(x/n).evalf(dps) for x in a] if dps is not None \ + else [x/n for x in a] + + return a + + +def fft(seq, dps=None): + r""" + Performs the Discrete Fourier Transform (**DFT**) in the complex domain. + + The sequence is automatically padded to the right with zeros, as the + *radix-2 FFT* requires the number of sample points to be a power of 2. + + This method should be used with default arguments only for short sequences + as the complexity of expressions increases with the size of the sequence. + + Parameters + ========== + + seq : iterable + The sequence on which **DFT** is to be applied. + dps : Integer + Specifies the number of decimal digits for precision. + + Examples + ======== + + >>> from sympy import fft, ifft + + >>> fft([1, 2, 3, 4]) + [10, -2 - 2*I, -2, -2 + 2*I] + >>> ifft(_) + [1, 2, 3, 4] + + >>> ifft([1, 2, 3, 4]) + [5/2, -1/2 + I/2, -1/2, -1/2 - I/2] + >>> fft(_) + [1, 2, 3, 4] + + >>> ifft([1, 7, 3, 4], dps=15) + [3.75, -0.5 - 0.75*I, -1.75, -0.5 + 0.75*I] + >>> fft(_) + [1.0, 7.0, 3.0, 4.0] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm + .. [2] https://mathworld.wolfram.com/FastFourierTransform.html + + """ + + return _fourier_transform(seq, dps=dps) + + +def ifft(seq, dps=None): + return _fourier_transform(seq, dps=dps, inverse=True) + +ifft.__doc__ = fft.__doc__ + + +#----------------------------------------------------------------------------# +# # +# Number Theoretic Transform # +# # +#----------------------------------------------------------------------------# + +def _number_theoretic_transform(seq, prime, inverse=False): + """Utility function for the Number Theoretic Transform""" + + if not iterable(seq): + raise TypeError("Expected a sequence of integer coefficients " + "for Number Theoretic Transform") + + p = as_int(prime) + if not isprime(p): + raise ValueError("Expected prime modulus for " + "Number Theoretic Transform") + + a = [as_int(x) % p for x in seq] + + n = len(a) + if n < 1: + return a + + b = n.bit_length() - 1 + if n&(n - 1): + b += 1 + n = 2**b + + if (p - 1) % n: + raise ValueError("Expected prime modulus of the form (m*2**k + 1)") + + a += [0]*(n - len(a)) + for i in range(1, n): + j = int(ibin(i, b, str=True)[::-1], 2) + if i < j: + a[i], a[j] = a[j], a[i] + + pr = primitive_root(p) + + rt = pow(pr, (p - 1) // n, p) + if inverse: + rt = pow(rt, p - 2, p) + + w = [1]*(n // 2) + for i in range(1, n // 2): + w[i] = w[i - 1]*rt % p + + h = 2 + while h <= n: + hf, ut = h // 2, n // h + for i in range(0, n, h): + for j in range(hf): + u, v = a[i + j], a[i + j + hf]*w[ut * j] + a[i + j], a[i + j + hf] = (u + v) % p, (u - v) % p + h *= 2 + + if inverse: + rv = pow(n, p - 2, p) + a = [x*rv % p for x in a] + + return a + + +def ntt(seq, prime): + r""" + Performs the Number Theoretic Transform (**NTT**), which specializes the + Discrete Fourier Transform (**DFT**) over quotient ring `Z/pZ` for prime + `p` instead of complex numbers `C`. + + The sequence is automatically padded to the right with zeros, as the + *radix-2 NTT* requires the number of sample points to be a power of 2. + + Parameters + ========== + + seq : iterable + The sequence on which **DFT** is to be applied. + prime : Integer + Prime modulus of the form `(m 2^k + 1)` to be used for performing + **NTT** on the sequence. + + Examples + ======== + + >>> from sympy import ntt, intt + >>> ntt([1, 2, 3, 4], prime=3*2**8 + 1) + [10, 643, 767, 122] + >>> intt(_, 3*2**8 + 1) + [1, 2, 3, 4] + >>> intt([1, 2, 3, 4], prime=3*2**8 + 1) + [387, 415, 384, 353] + >>> ntt(_, prime=3*2**8 + 1) + [1, 2, 3, 4] + + References + ========== + + .. [1] http://www.apfloat.org/ntt.html + .. [2] https://mathworld.wolfram.com/NumberTheoreticTransform.html + .. [3] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29 + + """ + + return _number_theoretic_transform(seq, prime=prime) + + +def intt(seq, prime): + return _number_theoretic_transform(seq, prime=prime, inverse=True) + +intt.__doc__ = ntt.__doc__ + + +#----------------------------------------------------------------------------# +# # +# Walsh Hadamard Transform # +# # +#----------------------------------------------------------------------------# + +def _walsh_hadamard_transform(seq, inverse=False): + """Utility function for the Walsh Hadamard Transform""" + + if not iterable(seq): + raise TypeError("Expected a sequence of coefficients " + "for Walsh Hadamard Transform") + + a = [sympify(arg) for arg in seq] + n = len(a) + if n < 2: + return a + + if n&(n - 1): + n = 2**n.bit_length() + + a += [S.Zero]*(n - len(a)) + h = 2 + while h <= n: + hf = h // 2 + for i in range(0, n, h): + for j in range(hf): + u, v = a[i + j], a[i + j + hf] + a[i + j], a[i + j + hf] = u + v, u - v + h *= 2 + + if inverse: + a = [x/n for x in a] + + return a + + +def fwht(seq): + r""" + Performs the Walsh Hadamard Transform (**WHT**), and uses Hadamard + ordering for the sequence. + + The sequence is automatically padded to the right with zeros, as the + *radix-2 FWHT* requires the number of sample points to be a power of 2. + + Parameters + ========== + + seq : iterable + The sequence on which WHT is to be applied. + + Examples + ======== + + >>> from sympy import fwht, ifwht + >>> fwht([4, 2, 2, 0, 0, 2, -2, 0]) + [8, 0, 8, 0, 8, 8, 0, 0] + >>> ifwht(_) + [4, 2, 2, 0, 0, 2, -2, 0] + + >>> ifwht([19, -1, 11, -9, -7, 13, -15, 5]) + [2, 0, 4, 0, 3, 10, 0, 0] + >>> fwht(_) + [19, -1, 11, -9, -7, 13, -15, 5] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hadamard_transform + .. [2] https://en.wikipedia.org/wiki/Fast_Walsh%E2%80%93Hadamard_transform + + """ + + return _walsh_hadamard_transform(seq) + + +def ifwht(seq): + return _walsh_hadamard_transform(seq, inverse=True) + +ifwht.__doc__ = fwht.__doc__ + + +#----------------------------------------------------------------------------# +# # +# Mobius Transform for Subset Lattice # +# # +#----------------------------------------------------------------------------# + +def _mobius_transform(seq, sgn, subset): + r"""Utility function for performing Mobius Transform using + Yate's Dynamic Programming method""" + + if not iterable(seq): + raise TypeError("Expected a sequence of coefficients") + + a = [sympify(arg) for arg in seq] + + n = len(a) + if n < 2: + return a + + if n&(n - 1): + n = 2**n.bit_length() + + a += [S.Zero]*(n - len(a)) + + if subset: + i = 1 + while i < n: + for j in range(n): + if j & i: + a[j] += sgn*a[j ^ i] + i *= 2 + + else: + i = 1 + while i < n: + for j in range(n): + if j & i: + continue + a[j] += sgn*a[j ^ i] + i *= 2 + + return a + + +def mobius_transform(seq, subset=True): + r""" + Performs the Mobius Transform for subset lattice with indices of + sequence as bitmasks. + + The indices of each argument, considered as bit strings, correspond + to subsets of a finite set. + + The sequence is automatically padded to the right with zeros, as the + definition of subset/superset based on bitmasks (indices) requires + the size of sequence to be a power of 2. + + Parameters + ========== + + seq : iterable + The sequence on which Mobius Transform is to be applied. + subset : bool + Specifies if Mobius Transform is applied by enumerating subsets + or supersets of the given set. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy import mobius_transform, inverse_mobius_transform + >>> x, y, z = symbols('x y z') + + >>> mobius_transform([x, y, z]) + [x, x + y, x + z, x + y + z] + >>> inverse_mobius_transform(_) + [x, y, z, 0] + + >>> mobius_transform([x, y, z], subset=False) + [x + y + z, y, z, 0] + >>> inverse_mobius_transform(_, subset=False) + [x, y, z, 0] + + >>> mobius_transform([1, 2, 3, 4]) + [1, 3, 4, 10] + >>> inverse_mobius_transform(_) + [1, 2, 3, 4] + >>> mobius_transform([1, 2, 3, 4], subset=False) + [10, 6, 7, 4] + >>> inverse_mobius_transform(_, subset=False) + [1, 2, 3, 4] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/M%C3%B6bius_inversion_formula + .. [2] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf + .. [3] https://arxiv.org/pdf/1211.0189.pdf + + """ + + return _mobius_transform(seq, sgn=+1, subset=subset) + +def inverse_mobius_transform(seq, subset=True): + return _mobius_transform(seq, sgn=-1, subset=subset) + +inverse_mobius_transform.__doc__ = mobius_transform.__doc__ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..549b4b96cdce0ee4d31960e89cb9dc26af0e105d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__init__.py @@ -0,0 +1,20 @@ +""" +Unified place for determining if external dependencies are installed or not. + +You should import all external modules using the import_module() function. + +For example + +>>> from sympy.external import import_module +>>> numpy = import_module('numpy') + +If the resulting library is not installed, or if the installed version +is less than a given minimum version, the function will return None. +Otherwise, it will return the library. See the docstring of +import_module() for more information. + +""" + +from sympy.external.importtools import import_module + +__all__ = ['import_module'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/gmpy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/gmpy.py new file mode 100644 index 0000000000000000000000000000000000000000..d26942864bf4786e72198d3640d488857b3313f4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/gmpy.py @@ -0,0 +1,342 @@ +from __future__ import annotations +import os +from ctypes import c_long, sizeof +from functools import reduce +from typing import Type +from warnings import warn + +from sympy.external import import_module + +from .pythonmpq import PythonMPQ + +from .ntheory import ( + bit_scan1 as python_bit_scan1, + bit_scan0 as python_bit_scan0, + remove as python_remove, + factorial as python_factorial, + sqrt as python_sqrt, + sqrtrem as python_sqrtrem, + gcd as python_gcd, + lcm as python_lcm, + gcdext as python_gcdext, + is_square as python_is_square, + invert as python_invert, + legendre as python_legendre, + jacobi as python_jacobi, + kronecker as python_kronecker, + iroot as python_iroot, + is_fermat_prp as python_is_fermat_prp, + is_euler_prp as python_is_euler_prp, + is_strong_prp as python_is_strong_prp, + is_fibonacci_prp as python_is_fibonacci_prp, + is_lucas_prp as python_is_lucas_prp, + is_selfridge_prp as python_is_selfridge_prp, + is_strong_lucas_prp as python_is_strong_lucas_prp, + is_strong_selfridge_prp as python_is_strong_selfridge_prp, + is_bpsw_prp as python_is_bpsw_prp, + is_strong_bpsw_prp as python_is_strong_bpsw_prp, +) + + +__all__ = [ + # GROUND_TYPES is either 'gmpy' or 'python' depending on which is used. If + # gmpy is installed then it will be used unless the environment variable + # SYMPY_GROUND_TYPES is set to something other than 'auto', 'gmpy', or + # 'gmpy2'. + 'GROUND_TYPES', + + # If HAS_GMPY is 0, no supported version of gmpy is available. Otherwise, + # HAS_GMPY will be 2 for gmpy2 if GROUND_TYPES is 'gmpy'. It used to be + # possible for HAS_GMPY to be 1 for gmpy but gmpy is no longer supported. + 'HAS_GMPY', + + # SYMPY_INTS is a tuple containing the base types for valid integer types. + # This is either (int,) or (int, type(mpz(0))) depending on GROUND_TYPES. + 'SYMPY_INTS', + + # MPQ is either gmpy.mpq or the Python equivalent from + # sympy.external.pythonmpq + 'MPQ', + + # MPZ is either gmpy.mpz or int. + 'MPZ', + + 'bit_scan1', + 'bit_scan0', + 'remove', + 'factorial', + 'sqrt', + 'is_square', + 'sqrtrem', + 'gcd', + 'lcm', + 'gcdext', + 'invert', + 'legendre', + 'jacobi', + 'kronecker', + 'iroot', + 'is_fermat_prp', + 'is_euler_prp', + 'is_strong_prp', + 'is_fibonacci_prp', + 'is_lucas_prp', + 'is_selfridge_prp', + 'is_strong_lucas_prp', + 'is_strong_selfridge_prp', + 'is_bpsw_prp', + 'is_strong_bpsw_prp', +] + + +# +# Tested python-flint version. Future versions might work but we will only use +# them if explicitly requested by SYMPY_GROUND_TYPES=flint. +# +_PYTHON_FLINT_VERSION_NEEDED = ["0.6", "0.7", "0.8", "0.9", "0.10"] + + +def _flint_version_okay(flint_version): + major, minor = flint_version.split('.')[:2] + flint_ver = f'{major}.{minor}' + return flint_ver in _PYTHON_FLINT_VERSION_NEEDED + +# +# We will only use gmpy2 >= 2.0.0 +# +_GMPY2_MIN_VERSION = '2.0.0' + + +def _get_flint(sympy_ground_types): + if sympy_ground_types not in ('auto', 'flint'): + return None + + try: + import flint + # Earlier versions of python-flint may not have __version__. + from flint import __version__ as _flint_version + except ImportError: + if sympy_ground_types == 'flint': + warn("SYMPY_GROUND_TYPES was set to flint but python-flint is not " + "installed. Falling back to other ground types.") + return None + + if _flint_version_okay(_flint_version): + return flint + elif sympy_ground_types == 'auto': + return None + else: + warn(f"Using python-flint {_flint_version} because SYMPY_GROUND_TYPES " + f"is set to flint but this version of SymPy is only tested " + f"with python-flint versions {_PYTHON_FLINT_VERSION_NEEDED}.") + return flint + + +def _get_gmpy2(sympy_ground_types): + if sympy_ground_types not in ('auto', 'gmpy', 'gmpy2'): + return None + + gmpy = import_module('gmpy2', min_module_version=_GMPY2_MIN_VERSION, + module_version_attr='version', module_version_attr_call_args=()) + + if sympy_ground_types != 'auto' and gmpy is None: + warn("gmpy2 library is not installed, switching to 'python' ground types") + + return gmpy + + +# +# SYMPY_GROUND_TYPES can be flint, gmpy, gmpy2, python or auto (default) +# +_SYMPY_GROUND_TYPES = os.environ.get('SYMPY_GROUND_TYPES', 'auto').lower() +_flint = None +_gmpy = None + +# +# First handle auto-detection of flint/gmpy2. We will prefer flint if available +# or otherwise gmpy2 if available and then lastly the python types. +# +if _SYMPY_GROUND_TYPES in ('auto', 'flint'): + _flint = _get_flint(_SYMPY_GROUND_TYPES) + if _flint is not None: + _SYMPY_GROUND_TYPES = 'flint' + else: + _SYMPY_GROUND_TYPES = 'auto' + +if _SYMPY_GROUND_TYPES in ('auto', 'gmpy', 'gmpy2'): + _gmpy = _get_gmpy2(_SYMPY_GROUND_TYPES) + if _gmpy is not None: + _SYMPY_GROUND_TYPES = 'gmpy' + else: + _SYMPY_GROUND_TYPES = 'python' + +if _SYMPY_GROUND_TYPES not in ('flint', 'gmpy', 'python'): + warn("SYMPY_GROUND_TYPES environment variable unrecognised. " + "Should be 'auto', 'flint', 'gmpy', 'gmpy2' or 'python'.") + _SYMPY_GROUND_TYPES = 'python' + +# +# At this point _SYMPY_GROUND_TYPES is either flint, gmpy or python. The blocks +# below define the values exported by this module in each case. +# + +# +# In gmpy2 and flint, there are functions that take a long (or unsigned long) +# argument. That is, it is not possible to input a value larger than that. +# +LONG_MAX = (1 << (8*sizeof(c_long) - 1)) - 1 + +# +# Type checkers are confused by what SYMPY_INTS is. There may be a better type +# hint for this like Type[Integral] or something. +# +SYMPY_INTS: tuple[Type, ...] + +if _SYMPY_GROUND_TYPES == 'gmpy': + + assert _gmpy is not None + + flint = None + gmpy = _gmpy + + HAS_GMPY = 2 + GROUND_TYPES = 'gmpy' + SYMPY_INTS = (int, type(gmpy.mpz(0))) + MPZ = gmpy.mpz + MPQ = gmpy.mpq + + bit_scan1 = gmpy.bit_scan1 + bit_scan0 = gmpy.bit_scan0 + remove = gmpy.remove + factorial = gmpy.fac + sqrt = gmpy.isqrt + is_square = gmpy.is_square + sqrtrem = gmpy.isqrt_rem + gcd = gmpy.gcd + lcm = gmpy.lcm + gcdext = gmpy.gcdext + invert = gmpy.invert + legendre = gmpy.legendre + jacobi = gmpy.jacobi + kronecker = gmpy.kronecker + + def iroot(x, n): + # In the latest gmpy2, the threshold for n is ULONG_MAX, + # but adjust to the older one. + if n <= LONG_MAX: + return gmpy.iroot(x, n) + return python_iroot(x, n) + + is_fermat_prp = gmpy.is_fermat_prp + is_euler_prp = gmpy.is_euler_prp + is_strong_prp = gmpy.is_strong_prp + is_fibonacci_prp = gmpy.is_fibonacci_prp + is_lucas_prp = gmpy.is_lucas_prp + is_selfridge_prp = gmpy.is_selfridge_prp + is_strong_lucas_prp = gmpy.is_strong_lucas_prp + is_strong_selfridge_prp = gmpy.is_strong_selfridge_prp + is_bpsw_prp = gmpy.is_bpsw_prp + is_strong_bpsw_prp = gmpy.is_strong_bpsw_prp + +elif _SYMPY_GROUND_TYPES == 'flint': + + assert _flint is not None + + flint = _flint + gmpy = None + + HAS_GMPY = 0 + GROUND_TYPES = 'flint' + SYMPY_INTS = (int, flint.fmpz) # type: ignore + MPZ = flint.fmpz # type: ignore + MPQ = flint.fmpq # type: ignore + + bit_scan1 = python_bit_scan1 + bit_scan0 = python_bit_scan0 + remove = python_remove + factorial = python_factorial + + def sqrt(x): + return flint.fmpz(x).isqrt() + + def is_square(x): + if x < 0: + return False + return flint.fmpz(x).sqrtrem()[1] == 0 + + def sqrtrem(x): + return flint.fmpz(x).sqrtrem() + + def gcd(*args): + return reduce(flint.fmpz.gcd, args, flint.fmpz(0)) + + def lcm(*args): + return reduce(flint.fmpz.lcm, args, flint.fmpz(1)) + + gcdext = python_gcdext + invert = python_invert + legendre = python_legendre + + def jacobi(x, y): + if y <= 0 or not y % 2: + raise ValueError("y should be an odd positive integer") + return flint.fmpz(x).jacobi(y) + + kronecker = python_kronecker + + def iroot(x, n): + if n <= LONG_MAX: + y = flint.fmpz(x).root(n) + return y, y**n == x + return python_iroot(x, n) + + is_fermat_prp = python_is_fermat_prp + is_euler_prp = python_is_euler_prp + is_strong_prp = python_is_strong_prp + is_fibonacci_prp = python_is_fibonacci_prp + is_lucas_prp = python_is_lucas_prp + is_selfridge_prp = python_is_selfridge_prp + is_strong_lucas_prp = python_is_strong_lucas_prp + is_strong_selfridge_prp = python_is_strong_selfridge_prp + is_bpsw_prp = python_is_bpsw_prp + is_strong_bpsw_prp = python_is_strong_bpsw_prp + +elif _SYMPY_GROUND_TYPES == 'python': + + flint = None + gmpy = None + + HAS_GMPY = 0 + GROUND_TYPES = 'python' + SYMPY_INTS = (int,) + MPZ = int + MPQ = PythonMPQ + + bit_scan1 = python_bit_scan1 + bit_scan0 = python_bit_scan0 + remove = python_remove + factorial = python_factorial + sqrt = python_sqrt + is_square = python_is_square + sqrtrem = python_sqrtrem + gcd = python_gcd + lcm = python_lcm + gcdext = python_gcdext + invert = python_invert + legendre = python_legendre + jacobi = python_jacobi + kronecker = python_kronecker + iroot = python_iroot + is_fermat_prp = python_is_fermat_prp + is_euler_prp = python_is_euler_prp + is_strong_prp = python_is_strong_prp + is_fibonacci_prp = python_is_fibonacci_prp + is_lucas_prp = python_is_lucas_prp + is_selfridge_prp = python_is_selfridge_prp + is_strong_lucas_prp = python_is_strong_lucas_prp + is_strong_selfridge_prp = python_is_strong_selfridge_prp + is_bpsw_prp = python_is_bpsw_prp + is_strong_bpsw_prp = python_is_strong_bpsw_prp + +else: + assert False diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/importtools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/importtools.py new file mode 100644 index 0000000000000000000000000000000000000000..5008b3dd4634d3cee10744a0a92b1204051f07cc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/importtools.py @@ -0,0 +1,187 @@ +"""Tools to assist importing optional external modules.""" + +import sys +import re + +# Override these in the module to change the default warning behavior. +# For example, you might set both to False before running the tests so that +# warnings are not printed to the console, or set both to True for debugging. + +WARN_NOT_INSTALLED = None # Default is False +WARN_OLD_VERSION = None # Default is True + + +def __sympy_debug(): + # helper function from sympy/__init__.py + # We don't just import SYMPY_DEBUG from that file because we don't want to + # import all of SymPy just to use this module. + import os + debug_str = os.getenv('SYMPY_DEBUG', 'False') + if debug_str in ('True', 'False'): + return eval(debug_str) + else: + raise RuntimeError("unrecognized value for SYMPY_DEBUG: %s" % + debug_str) + +if __sympy_debug(): + WARN_OLD_VERSION = True + WARN_NOT_INSTALLED = True + + +_component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) + +def version_tuple(vstring): + # Parse a version string to a tuple e.g. '1.2' -> (1, 2) + # Simplified from distutils.version.LooseVersion which was deprecated in + # Python 3.10. + components = [] + for x in _component_re.split(vstring): + if x and x != '.': + try: + x = int(x) + except ValueError: + pass + components.append(x) + return tuple(components) + + +def import_module(module, min_module_version=None, min_python_version=None, + warn_not_installed=None, warn_old_version=None, + module_version_attr='__version__', module_version_attr_call_args=None, + import_kwargs={}, catch=()): + """ + Import and return a module if it is installed. + + If the module is not installed, it returns None. + + A minimum version for the module can be given as the keyword argument + min_module_version. This should be comparable against the module version. + By default, module.__version__ is used to get the module version. To + override this, set the module_version_attr keyword argument. If the + attribute of the module to get the version should be called (e.g., + module.version()), then set module_version_attr_call_args to the args such + that module.module_version_attr(*module_version_attr_call_args) returns the + module's version. + + If the module version is less than min_module_version using the Python < + comparison, None will be returned, even if the module is installed. You can + use this to keep from importing an incompatible older version of a module. + + You can also specify a minimum Python version by using the + min_python_version keyword argument. This should be comparable against + sys.version_info. + + If the keyword argument warn_not_installed is set to True, the function will + emit a UserWarning when the module is not installed. + + If the keyword argument warn_old_version is set to True, the function will + emit a UserWarning when the library is installed, but cannot be imported + because of the min_module_version or min_python_version options. + + Note that because of the way warnings are handled, a warning will be + emitted for each module only once. You can change the default warning + behavior by overriding the values of WARN_NOT_INSTALLED and WARN_OLD_VERSION + in sympy.external.importtools. By default, WARN_NOT_INSTALLED is False and + WARN_OLD_VERSION is True. + + This function uses __import__() to import the module. To pass additional + options to __import__(), use the import_kwargs keyword argument. For + example, to import a submodule A.B, you must pass a nonempty fromlist option + to __import__. See the docstring of __import__(). + + This catches ImportError to determine if the module is not installed. To + catch additional errors, pass them as a tuple to the catch keyword + argument. + + Examples + ======== + + >>> from sympy.external import import_module + + >>> numpy = import_module('numpy') + + >>> numpy = import_module('numpy', min_python_version=(2, 7), + ... warn_old_version=False) + + >>> numpy = import_module('numpy', min_module_version='1.5', + ... warn_old_version=False) # numpy.__version__ is a string + + >>> # gmpy does not have __version__, but it does have gmpy.version() + + >>> gmpy = import_module('gmpy', min_module_version='1.14', + ... module_version_attr='version', module_version_attr_call_args=(), + ... warn_old_version=False) + + >>> # To import a submodule, you must pass a nonempty fromlist to + >>> # __import__(). The values do not matter. + >>> p3 = import_module('mpl_toolkits.mplot3d', + ... import_kwargs={'fromlist':['something']}) + + >>> # matplotlib.pyplot can raise RuntimeError when the display cannot be opened + >>> matplotlib = import_module('matplotlib', + ... import_kwargs={'fromlist':['pyplot']}, catch=(RuntimeError,)) + + """ + # keyword argument overrides default, and global variable overrides + # keyword argument. + warn_old_version = (WARN_OLD_VERSION if WARN_OLD_VERSION is not None + else warn_old_version or True) + warn_not_installed = (WARN_NOT_INSTALLED if WARN_NOT_INSTALLED is not None + else warn_not_installed or False) + + import warnings + + # Check Python first so we don't waste time importing a module we can't use + if min_python_version: + if sys.version_info < min_python_version: + if warn_old_version: + warnings.warn("Python version is too old to use %s " + "(%s or newer required)" % ( + module, '.'.join(map(str, min_python_version))), + UserWarning, stacklevel=2) + return + + try: + mod = __import__(module, **import_kwargs) + + ## there's something funny about imports with matplotlib and py3k. doing + ## from matplotlib import collections + ## gives python's stdlib collections module. explicitly re-importing + ## the module fixes this. + from_list = import_kwargs.get('fromlist', ()) + for submod in from_list: + if submod == 'collections' and mod.__name__ == 'matplotlib': + __import__(module + '.' + submod) + except ImportError: + if warn_not_installed: + warnings.warn("%s module is not installed" % module, UserWarning, + stacklevel=2) + return + except catch as e: + if warn_not_installed: + warnings.warn( + "%s module could not be used (%s)" % (module, repr(e)), + stacklevel=2) + return + + if min_module_version: + modversion = getattr(mod, module_version_attr) + if module_version_attr_call_args is not None: + modversion = modversion(*module_version_attr_call_args) + if version_tuple(modversion) < version_tuple(min_module_version): + if warn_old_version: + # Attempt to create a pretty string version of the version + if isinstance(min_module_version, str): + verstr = min_module_version + elif isinstance(min_module_version, (tuple, list)): + verstr = '.'.join(map(str, min_module_version)) + else: + # Either don't know what this is. Hopefully + # it's something that has a nice str version, like an int. + verstr = str(min_module_version) + warnings.warn("%s version is too old to use " + "(%s or newer required)" % (module, verstr), + UserWarning, stacklevel=2) + return + + return mod diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/ntheory.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/ntheory.py new file mode 100644 index 0000000000000000000000000000000000000000..a0c9bf813cf02b311f9a12ee7fbc4932ed551f3b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/ntheory.py @@ -0,0 +1,618 @@ +# sympy.external.ntheory +# +# This module provides pure Python implementations of some number theory +# functions that are alternately used from gmpy2 if it is installed. + +import math + +import mpmath.libmp as mlib + + +_small_trailing = [0] * 256 +for j in range(1, 8): + _small_trailing[1 << j :: 1 << (j + 1)] = [j] * (1 << (7 - j)) + + +def bit_scan1(x, n=0): + if not x: + return + x = abs(x >> n) + low_byte = x & 0xFF + if low_byte: + return _small_trailing[low_byte] + n + + t = 8 + n + x >>= 8 + # 2**m is quick for z up through 2**30 + z = x.bit_length() - 1 + if x == 1 << z: + return z + t + + if z < 300: + # fixed 8-byte reduction + while not x & 0xFF: + x >>= 8 + t += 8 + else: + # binary reduction important when there might be a large + # number of trailing 0s + p = z >> 1 + while not x & 0xFF: + while x & ((1 << p) - 1): + p >>= 1 + x >>= p + t += p + return t + _small_trailing[x & 0xFF] + + +def bit_scan0(x, n=0): + return bit_scan1(x + (1 << n), n) + + +def remove(x, f): + if f < 2: + raise ValueError("factor must be > 1") + if x == 0: + return 0, 0 + if f == 2: + b = bit_scan1(x) + return x >> b, b + m = 0 + y, rem = divmod(x, f) + while not rem: + x = y + m += 1 + if m > 5: + pow_list = [f**2] + while pow_list: + _f = pow_list[-1] + y, rem = divmod(x, _f) + if not rem: + m += 1 << len(pow_list) + x = y + pow_list.append(_f**2) + else: + pow_list.pop() + y, rem = divmod(x, f) + return x, m + + +def factorial(x): + """Return x!.""" + return int(mlib.ifac(int(x))) + + +def sqrt(x): + """Integer square root of x.""" + return int(mlib.isqrt(int(x))) + + +def sqrtrem(x): + """Integer square root of x and remainder.""" + s, r = mlib.sqrtrem(int(x)) + return (int(s), int(r)) + + +gcd = math.gcd +lcm = math.lcm + + +def _sign(n): + if n < 0: + return -1, -n + return 1, n + + +def gcdext(a, b): + if not a or not b: + g = abs(a) or abs(b) + if not g: + return (0, 0, 0) + return (g, a // g, b // g) + + x_sign, a = _sign(a) + y_sign, b = _sign(b) + x, r = 1, 0 + y, s = 0, 1 + + while b: + q, c = divmod(a, b) + a, b = b, c + x, r = r, x - q*r + y, s = s, y - q*s + + return (a, x * x_sign, y * y_sign) + + +def is_square(x): + """Return True if x is a square number.""" + if x < 0: + return False + + # Note that the possible values of y**2 % n for a given n are limited. + # For example, when n=4, y**2 % n can only take 0 or 1. + # In other words, if x % 4 is 2 or 3, then x is not a square number. + # Mathematically, it determines if it belongs to the set {y**2 % n}, + # but implementationally, it can be realized as a logical conjunction + # with an n-bit integer. + # see https://mersenneforum.org/showpost.php?p=110896 + # def magic(n): + # s = {y**2 % n for y in range(n)} + # s = set(range(n)) - s + # return sum(1 << bit for bit in s) + # >>> print(hex(magic(128))) + # 0xfdfdfdedfdfdfdecfdfdfdedfdfcfdec + # >>> print(hex(magic(99))) + # 0x5f6f9ffb6fb7ddfcb75befdec + # >>> print(hex(magic(91))) + # 0x6fd1bfcfed5f3679d3ebdec + # >>> print(hex(magic(85))) + # 0xdef9ae771ffe3b9d67dec + if 0xfdfdfdedfdfdfdecfdfdfdedfdfcfdec & (1 << (x & 127)): + return False # e.g. 2, 3 + m = x % 765765 # 765765 = 99 * 91 * 85 + if 0x5f6f9ffb6fb7ddfcb75befdec & (1 << (m % 99)): + return False # e.g. 17, 68 + if 0x6fd1bfcfed5f3679d3ebdec & (1 << (m % 91)): + return False # e.g. 97, 388 + if 0xdef9ae771ffe3b9d67dec & (1 << (m % 85)): + return False # e.g. 793, 1408 + return mlib.sqrtrem(int(x))[1] == 0 + + +def invert(x, m): + """Modular inverse of x modulo m. + + Returns y such that x*y == 1 mod m. + + Uses ``math.pow`` but reproduces the behaviour of ``gmpy2.invert`` + which raises ZeroDivisionError if no inverse exists. + """ + try: + return pow(x, -1, m) + except ValueError: + raise ZeroDivisionError("invert() no inverse exists") + + +def legendre(x, y): + """Legendre symbol (x / y). + + Following the implementation of gmpy2, + the error is raised only when y is an even number. + """ + if y <= 0 or not y % 2: + raise ValueError("y should be an odd prime") + x %= y + if not x: + return 0 + if pow(x, (y - 1) // 2, y) == 1: + return 1 + return -1 + + +def jacobi(x, y): + """Jacobi symbol (x / y).""" + if y <= 0 or not y % 2: + raise ValueError("y should be an odd positive integer") + x %= y + if not x: + return int(y == 1) + if y == 1 or x == 1: + return 1 + if gcd(x, y) != 1: + return 0 + j = 1 + while x != 0: + while x % 2 == 0 and x > 0: + x >>= 1 + if y % 8 in [3, 5]: + j = -j + x, y = y, x + if x % 4 == y % 4 == 3: + j = -j + x %= y + return j + + +def kronecker(x, y): + """Kronecker symbol (x / y).""" + if gcd(x, y) != 1: + return 0 + if y == 0: + return 1 + sign = -1 if y < 0 and x < 0 else 1 + y = abs(y) + s = bit_scan1(y) + y >>= s + if s % 2 and x % 8 in [3, 5]: + sign = -sign + return sign * jacobi(x, y) + + +def iroot(y, n): + if y < 0: + raise ValueError("y must be nonnegative") + if n < 1: + raise ValueError("n must be positive") + if y in (0, 1): + return y, True + if n == 1: + return y, True + if n == 2: + x, rem = mlib.sqrtrem(y) + return int(x), not rem + if n >= y.bit_length(): + return 1, False + # Get initial estimate for Newton's method. Care must be taken to + # avoid overflow + try: + guess = int(y**(1./n) + 0.5) + except OverflowError: + exp = math.log2(y)/n + if exp > 53: + shift = int(exp - 53) + guess = int(2.0**(exp - shift) + 1) << shift + else: + guess = int(2.0**exp) + if guess > 2**50: + # Newton iteration + xprev, x = -1, guess + while 1: + t = x**(n - 1) + xprev, x = x, ((n - 1)*x + y//t)//n + if abs(x - xprev) < 2: + break + else: + x = guess + # Compensate + t = x**n + while t < y: + x += 1 + t = x**n + while t > y: + x -= 1 + t = x**n + return x, t == y + + +def is_fermat_prp(n, a): + if a < 2: + raise ValueError("is_fermat_prp() requires 'a' greater than or equal to 2") + if n < 1: + raise ValueError("is_fermat_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + a %= n + if gcd(n, a) != 1: + raise ValueError("is_fermat_prp() requires gcd(n,a) == 1") + return pow(a, n - 1, n) == 1 + + +def is_euler_prp(n, a): + if a < 2: + raise ValueError("is_euler_prp() requires 'a' greater than or equal to 2") + if n < 1: + raise ValueError("is_euler_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + a %= n + if gcd(n, a) != 1: + raise ValueError("is_euler_prp() requires gcd(n,a) == 1") + return pow(a, n >> 1, n) == jacobi(a, n) % n + + +def _is_strong_prp(n, a): + s = bit_scan1(n - 1) + a = pow(a, n >> s, n) + if a == 1 or a == n - 1: + return True + for _ in range(s - 1): + a = pow(a, 2, n) + if a == n - 1: + return True + if a == 1: + return False + return False + + +def is_strong_prp(n, a): + if a < 2: + raise ValueError("is_strong_prp() requires 'a' greater than or equal to 2") + if n < 1: + raise ValueError("is_strong_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + a %= n + if gcd(n, a) != 1: + raise ValueError("is_strong_prp() requires gcd(n,a) == 1") + return _is_strong_prp(n, a) + + +def _lucas_sequence(n, P, Q, k): + r"""Return the modular Lucas sequence (U_k, V_k, Q_k). + + Explanation + =========== + + Given a Lucas sequence defined by P, Q, returns the kth values for + U and V, along with Q^k, all modulo n. This is intended for use with + possibly very large values of n and k, where the combinatorial functions + would be completely unusable. + + .. math :: + U_k = \begin{cases} + 0 & \text{if } k = 0\\ + 1 & \text{if } k = 1\\ + PU_{k-1} - QU_{k-2} & \text{if } k > 1 + \end{cases}\\ + V_k = \begin{cases} + 2 & \text{if } k = 0\\ + P & \text{if } k = 1\\ + PV_{k-1} - QV_{k-2} & \text{if } k > 1 + \end{cases} + + The modular Lucas sequences are used in numerous places in number theory, + especially in the Lucas compositeness tests and the various n + 1 proofs. + + Parameters + ========== + + n : int + n is an odd number greater than or equal to 3 + P : int + Q : int + D determined by D = P**2 - 4*Q is non-zero + k : int + k is a nonnegative integer + + Returns + ======= + + U, V, Qk : (int, int, int) + `(U_k \bmod{n}, V_k \bmod{n}, Q^k \bmod{n})` + + Examples + ======== + + >>> from sympy.external.ntheory import _lucas_sequence + >>> N = 10**2000 + 4561 + >>> sol = U, V, Qk = _lucas_sequence(N, 3, 1, N//2); sol + (0, 2, 1) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Lucas_sequence + + """ + if k == 0: + return (0, 2, 1) + D = P**2 - 4*Q + U = 1 + V = P + Qk = Q % n + if Q == 1: + # Optimization for extra strong tests. + for b in bin(k)[3:]: + U = (U*V) % n + V = (V*V - 2) % n + if b == "1": + U, V = U*P + V, V*P + U*D + if U & 1: + U += n + if V & 1: + V += n + U, V = U >> 1, V >> 1 + elif P == 1 and Q == -1: + # Small optimization for 50% of Selfridge parameters. + for b in bin(k)[3:]: + U = (U*V) % n + if Qk == 1: + V = (V*V - 2) % n + else: + V = (V*V + 2) % n + Qk = 1 + if b == "1": + # new_U = (U + V) // 2 + # new_V = (5*U + V) // 2 = 2*U + new_U + U, V = U + V, U << 1 + if U & 1: + U += n + U >>= 1 + V += U + Qk = -1 + Qk %= n + elif P == 1: + for b in bin(k)[3:]: + U = (U*V) % n + V = (V*V - 2*Qk) % n + Qk *= Qk + if b == "1": + # new_U = (U + V) // 2 + # new_V = new_U - 2*Q*U + U, V = U + V, (Q*U) << 1 + if U & 1: + U += n + U >>= 1 + V = U - V + Qk *= Q + Qk %= n + else: + # The general case with any P and Q. + for b in bin(k)[3:]: + U = (U*V) % n + V = (V*V - 2*Qk) % n + Qk *= Qk + if b == "1": + U, V = U*P + V, V*P + U*D + if U & 1: + U += n + if V & 1: + V += n + U, V = U >> 1, V >> 1 + Qk *= Q + Qk %= n + return (U % n, V % n, Qk) + + +def is_fibonacci_prp(n, p, q): + d = p**2 - 4*q + if d == 0 or p <= 0 or q not in [1, -1]: + raise ValueError("invalid values for p,q in is_fibonacci_prp()") + if n < 1: + raise ValueError("is_fibonacci_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + return _lucas_sequence(n, p, q, n)[1] == p % n + + +def is_lucas_prp(n, p, q): + d = p**2 - 4*q + if d == 0: + raise ValueError("invalid values for p,q in is_lucas_prp()") + if n < 1: + raise ValueError("is_lucas_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + if gcd(n, q*d) not in [1, n]: + raise ValueError("is_lucas_prp() requires gcd(n,2*q*D) == 1") + return _lucas_sequence(n, p, q, n - jacobi(d, n))[0] == 0 + + +def _is_selfridge_prp(n): + """Lucas compositeness test with the Selfridge parameters for n. + + Explanation + =========== + + The Lucas compositeness test checks whether n is a prime number. + The test can be run with arbitrary parameters ``P`` and ``Q``, which also change the performance of the test. + So, which parameters are most effective for running the Lucas compositeness test? + As an algorithm for determining ``P`` and ``Q``, Selfridge proposed method A [1]_ page 1401 + (Since two methods were proposed, referred to simply as A and B in the paper, + we will refer to one of them as "method A"). + + method A fixes ``P = 1``. Then, ``D`` defined by ``D = P**2 - 4Q`` is varied from 5, -7, 9, -11, 13, and so on, + with the first ``D`` being ``jacobi(D, n) == -1``. Once ``D`` is determined, + ``Q`` is determined to be ``(P**2 - D)//4``. + + References + ========== + + .. [1] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes, + Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417, + https://doi.org/10.1090%2FS0025-5718-1980-0583518-6 + http://mpqs.free.fr/LucasPseudoprimes.pdf + + """ + for D in range(5, 1_000_000, 2): + if D & 2: # if D % 4 == 3 + D = -D + j = jacobi(D, n) + if j == -1: + return _lucas_sequence(n, 1, (1-D) // 4, n + 1)[0] == 0 + if j == 0 and D % n: + return False + # When j == -1 is hard to find, suspect a square number + if D == 13 and is_square(n): + return False + raise ValueError("appropriate value for D cannot be found in is_selfridge_prp()") + + +def is_selfridge_prp(n): + if n < 1: + raise ValueError("is_selfridge_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + return _is_selfridge_prp(n) + + +def is_strong_lucas_prp(n, p, q): + D = p**2 - 4*q + if D == 0: + raise ValueError("invalid values for p,q in is_strong_lucas_prp()") + if n < 1: + raise ValueError("is_selfridge_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + if gcd(n, q*D) not in [1, n]: + raise ValueError("is_strong_lucas_prp() requires gcd(n,2*q*D) == 1") + j = jacobi(D, n) + s = bit_scan1(n - j) + U, V, Qk = _lucas_sequence(n, p, q, (n - j) >> s) + if U == 0 or V == 0: + return True + for _ in range(s - 1): + V = (V*V - 2*Qk) % n + if V == 0: + return True + Qk = pow(Qk, 2, n) + return False + + +def _is_strong_selfridge_prp(n): + for D in range(5, 1_000_000, 2): + if D & 2: # if D % 4 == 3 + D = -D + j = jacobi(D, n) + if j == -1: + s = bit_scan1(n + 1) + U, V, Qk = _lucas_sequence(n, 1, (1-D) // 4, (n + 1) >> s) + if U == 0 or V == 0: + return True + for _ in range(s - 1): + V = (V*V - 2*Qk) % n + if V == 0: + return True + Qk = pow(Qk, 2, n) + return False + if j == 0 and D % n: + return False + # When j == -1 is hard to find, suspect a square number + if D == 13 and is_square(n): + return False + raise ValueError("appropriate value for D cannot be found in is_strong_selfridge_prp()") + + +def is_strong_selfridge_prp(n): + if n < 1: + raise ValueError("is_strong_selfridge_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + return _is_strong_selfridge_prp(n) + + +def is_bpsw_prp(n): + if n < 1: + raise ValueError("is_bpsw_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + return _is_strong_prp(n, 2) and _is_selfridge_prp(n) + + +def is_strong_bpsw_prp(n): + if n < 1: + raise ValueError("is_strong_bpsw_prp() requires 'n' be greater than 0") + if n == 1: + return False + if n % 2 == 0: + return n == 2 + return _is_strong_prp(n, 2) and _is_strong_selfridge_prp(n) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/pythonmpq.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/pythonmpq.py new file mode 100644 index 0000000000000000000000000000000000000000..4f2d102974e04e139c00a39057976b5a5bf90776 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/pythonmpq.py @@ -0,0 +1,341 @@ +""" +PythonMPQ: Rational number type based on Python integers. + +This class is intended as a pure Python fallback for when gmpy2 is not +installed. If gmpy2 is installed then its mpq type will be used instead. The +mpq type is around 20x faster. We could just use the stdlib Fraction class +here but that is slower: + + from fractions import Fraction + from sympy.external.pythonmpq import PythonMPQ + nums = range(1000) + dens = range(5, 1005) + rats = [Fraction(n, d) for n, d in zip(nums, dens)] + sum(rats) # <--- 24 milliseconds + rats = [PythonMPQ(n, d) for n, d in zip(nums, dens)] + sum(rats) # <--- 7 milliseconds + +Both mpq and Fraction have some awkward features like the behaviour of +division with // and %: + + >>> from fractions import Fraction + >>> Fraction(2, 3) % Fraction(1, 4) + 1/6 + +For the QQ domain we do not want this behaviour because there should be no +remainder when dividing rational numbers. SymPy does not make use of this +aspect of mpq when gmpy2 is installed. Since this class is a fallback for that +case we do not bother implementing e.g. __mod__ so that we can be sure we +are not using it when gmpy2 is installed either. +""" + +from __future__ import annotations +import operator +from math import gcd +from decimal import Decimal +from fractions import Fraction +import sys +from typing import Type + + +# Used for __hash__ +_PyHASH_MODULUS = sys.hash_info.modulus +_PyHASH_INF = sys.hash_info.inf + + +class PythonMPQ: + """Rational number implementation that is intended to be compatible with + gmpy2's mpq. + + Also slightly faster than fractions.Fraction. + + PythonMPQ should be treated as immutable although no effort is made to + prevent mutation (since that might slow down calculations). + """ + __slots__ = ('numerator', 'denominator') + + def __new__(cls, numerator, denominator=None): + """Construct PythonMPQ with gcd computation and checks""" + if denominator is not None: + # + # PythonMPQ(n, d): require n and d to be int and d != 0 + # + if isinstance(numerator, int) and isinstance(denominator, int): + # This is the slow part: + divisor = gcd(numerator, denominator) + numerator //= divisor + denominator //= divisor + return cls._new_check(numerator, denominator) + else: + # + # PythonMPQ(q) + # + # Here q can be PythonMPQ, int, Decimal, float, Fraction or str + # + if isinstance(numerator, int): + return cls._new(numerator, 1) + elif isinstance(numerator, PythonMPQ): + return cls._new(numerator.numerator, numerator.denominator) + + # Let Fraction handle Decimal/float conversion and str parsing + if isinstance(numerator, (Decimal, float, str)): + numerator = Fraction(numerator) + if isinstance(numerator, Fraction): + return cls._new(numerator.numerator, numerator.denominator) + # + # Reject everything else. This is more strict than mpq which allows + # things like mpq(Fraction, Fraction) or mpq(Decimal, any). The mpq + # behaviour is somewhat inconsistent so we choose to accept only a + # more strict subset of what mpq allows. + # + raise TypeError("PythonMPQ() requires numeric or string argument") + + @classmethod + def _new_check(cls, numerator, denominator): + """Construct PythonMPQ, check divide by zero and canonicalize signs""" + if not denominator: + raise ZeroDivisionError(f'Zero divisor {numerator}/{denominator}') + elif denominator < 0: + numerator = -numerator + denominator = -denominator + return cls._new(numerator, denominator) + + @classmethod + def _new(cls, numerator, denominator): + """Construct PythonMPQ efficiently (no checks)""" + obj = super().__new__(cls) + obj.numerator = numerator + obj.denominator = denominator + return obj + + def __int__(self): + """Convert to int (truncates towards zero)""" + p, q = self.numerator, self.denominator + if p < 0: + return -(-p//q) + return p//q + + def __float__(self): + """Convert to float (approximately)""" + return self.numerator / self.denominator + + def __bool__(self): + """True/False if nonzero/zero""" + return bool(self.numerator) + + def __eq__(self, other): + """Compare equal with PythonMPQ, int, float, Decimal or Fraction""" + if isinstance(other, PythonMPQ): + return (self.numerator == other.numerator + and self.denominator == other.denominator) + elif isinstance(other, self._compatible_types): + return self.__eq__(PythonMPQ(other)) + else: + return NotImplemented + + def __hash__(self): + """hash - same as mpq/Fraction""" + try: + dinv = pow(self.denominator, -1, _PyHASH_MODULUS) + except ValueError: + hash_ = _PyHASH_INF + else: + hash_ = hash(hash(abs(self.numerator)) * dinv) + result = hash_ if self.numerator >= 0 else -hash_ + return -2 if result == -1 else result + + def __reduce__(self): + """Deconstruct for pickling""" + return type(self), (self.numerator, self.denominator) + + def __str__(self): + """Convert to string""" + if self.denominator != 1: + return f"{self.numerator}/{self.denominator}" + else: + return f"{self.numerator}" + + def __repr__(self): + """Convert to string""" + return f"MPQ({self.numerator},{self.denominator})" + + def _cmp(self, other, op): + """Helper for lt/le/gt/ge""" + if not isinstance(other, self._compatible_types): + return NotImplemented + lhs = self.numerator * other.denominator + rhs = other.numerator * self.denominator + return op(lhs, rhs) + + def __lt__(self, other): + """self < other""" + return self._cmp(other, operator.lt) + + def __le__(self, other): + """self <= other""" + return self._cmp(other, operator.le) + + def __gt__(self, other): + """self > other""" + return self._cmp(other, operator.gt) + + def __ge__(self, other): + """self >= other""" + return self._cmp(other, operator.ge) + + def __abs__(self): + """abs(q)""" + return self._new(abs(self.numerator), self.denominator) + + def __pos__(self): + """+q""" + return self + + def __neg__(self): + """-q""" + return self._new(-self.numerator, self.denominator) + + def __add__(self, other): + """q1 + q2""" + if isinstance(other, PythonMPQ): + # + # This is much faster than the naive method used in the stdlib + # fractions module. Not sure where this method comes from + # though... + # + # Compare timings for something like: + # nums = range(1000) + # rats = [PythonMPQ(n, d) for n, d in zip(nums[:-5], nums[5:])] + # sum(rats) # <-- time this + # + ap, aq = self.numerator, self.denominator + bp, bq = other.numerator, other.denominator + g = gcd(aq, bq) + if g == 1: + p = ap*bq + aq*bp + q = bq*aq + else: + q1, q2 = aq//g, bq//g + p, q = ap*q2 + bp*q1, q1*q2 + g2 = gcd(p, g) + p, q = (p // g2), q * (g // g2) + + elif isinstance(other, int): + p = self.numerator + self.denominator * other + q = self.denominator + else: + return NotImplemented + + return self._new(p, q) + + def __radd__(self, other): + """z1 + q2""" + if isinstance(other, int): + p = self.numerator + self.denominator * other + q = self.denominator + return self._new(p, q) + else: + return NotImplemented + + def __sub__(self ,other): + """q1 - q2""" + if isinstance(other, PythonMPQ): + ap, aq = self.numerator, self.denominator + bp, bq = other.numerator, other.denominator + g = gcd(aq, bq) + if g == 1: + p = ap*bq - aq*bp + q = bq*aq + else: + q1, q2 = aq//g, bq//g + p, q = ap*q2 - bp*q1, q1*q2 + g2 = gcd(p, g) + p, q = (p // g2), q * (g // g2) + elif isinstance(other, int): + p = self.numerator - self.denominator*other + q = self.denominator + else: + return NotImplemented + + return self._new(p, q) + + def __rsub__(self, other): + """z1 - q2""" + if isinstance(other, int): + p = self.denominator * other - self.numerator + q = self.denominator + return self._new(p, q) + else: + return NotImplemented + + def __mul__(self, other): + """q1 * q2""" + if isinstance(other, PythonMPQ): + ap, aq = self.numerator, self.denominator + bp, bq = other.numerator, other.denominator + x1 = gcd(ap, bq) + x2 = gcd(bp, aq) + p, q = ((ap//x1)*(bp//x2), (aq//x2)*(bq//x1)) + elif isinstance(other, int): + x = gcd(other, self.denominator) + p = self.numerator*(other//x) + q = self.denominator//x + else: + return NotImplemented + + return self._new(p, q) + + def __rmul__(self, other): + """z1 * q2""" + if isinstance(other, int): + x = gcd(self.denominator, other) + p = self.numerator*(other//x) + q = self.denominator//x + return self._new(p, q) + else: + return NotImplemented + + def __pow__(self, exp): + """q ** z""" + p, q = self.numerator, self.denominator + + if exp < 0: + p, q, exp = q, p, -exp + + return self._new_check(p**exp, q**exp) + + def __truediv__(self, other): + """q1 / q2""" + if isinstance(other, PythonMPQ): + ap, aq = self.numerator, self.denominator + bp, bq = other.numerator, other.denominator + x1 = gcd(ap, bp) + x2 = gcd(bq, aq) + p, q = ((ap//x1)*(bq//x2), (aq//x2)*(bp//x1)) + elif isinstance(other, int): + x = gcd(other, self.numerator) + p = self.numerator//x + q = self.denominator*(other//x) + else: + return NotImplemented + + return self._new_check(p, q) + + def __rtruediv__(self, other): + """z / q""" + if isinstance(other, int): + x = gcd(self.numerator, other) + p = self.denominator*(other//x) + q = self.numerator//x + return self._new_check(p, q) + else: + return NotImplemented + + _compatible_types: tuple[Type, ...] = () + +# +# These are the types that PythonMPQ will interoperate with for operations +# and comparisons such as ==, + etc. We define this down here so that we can +# include PythonMPQ in the list as well. +# +PythonMPQ._compatible_types = (PythonMPQ, int, Decimal, Fraction) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/functions/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/functions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ed93b2a11754aa26af5eef3932d177374b3ddfd6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/functions/__init__.py @@ -0,0 +1,115 @@ +"""A functions module, includes all the standard functions. + +Combinatorial - factorial, fibonacci, harmonic, bernoulli... +Elementary - hyperbolic, trigonometric, exponential, floor and ceiling, sqrt... +Special - gamma, zeta,spherical harmonics... +""" + +from sympy.functions.combinatorial.factorials import (factorial, factorial2, + rf, ff, binomial, RisingFactorial, FallingFactorial, subfactorial) +from sympy.functions.combinatorial.numbers import (carmichael, fibonacci, lucas, tribonacci, + harmonic, bernoulli, bell, euler, catalan, genocchi, andre, partition, divisor_sigma, + udivisor_sigma, legendre_symbol, jacobi_symbol, kronecker_symbol, mobius, + primenu, primeomega, totient, reduced_totient, primepi, motzkin) +from sympy.functions.elementary.miscellaneous import (sqrt, root, Min, Max, + Id, real_root, cbrt, Rem) +from sympy.functions.elementary.complexes import (re, im, sign, Abs, + conjugate, arg, polar_lift, periodic_argument, unbranched_argument, + principal_branch, transpose, adjoint, polarify, unpolarify) +from sympy.functions.elementary.trigonometric import (sin, cos, tan, + sec, csc, cot, sinc, asin, acos, atan, asec, acsc, acot, atan2) +from sympy.functions.elementary.exponential import (exp_polar, exp, log, + LambertW) +from sympy.functions.elementary.hyperbolic import (sinh, cosh, tanh, coth, + sech, csch, asinh, acosh, atanh, acoth, asech, acsch) +from sympy.functions.elementary.integers import floor, ceiling, frac +from sympy.functions.elementary.piecewise import (Piecewise, piecewise_fold, + piecewise_exclusive) +from sympy.functions.special.error_functions import (erf, erfc, erfi, erf2, + erfinv, erfcinv, erf2inv, Ei, expint, E1, li, Li, Si, Ci, Shi, Chi, + fresnels, fresnelc) +from sympy.functions.special.gamma_functions import (gamma, lowergamma, + uppergamma, polygamma, loggamma, digamma, trigamma, multigamma) +from sympy.functions.special.zeta_functions import (dirichlet_eta, zeta, + lerchphi, polylog, stieltjes, riemann_xi) +from sympy.functions.special.tensor_functions import (Eijk, LeviCivita, + KroneckerDelta) +from sympy.functions.special.singularity_functions import SingularityFunction +from sympy.functions.special.delta_functions import DiracDelta, Heaviside +from sympy.functions.special.bsplines import bspline_basis, bspline_basis_set, interpolating_spline +from sympy.functions.special.bessel import (besselj, bessely, besseli, besselk, + hankel1, hankel2, jn, yn, jn_zeros, hn1, hn2, airyai, airybi, airyaiprime, airybiprime, marcumq) +from sympy.functions.special.hyper import hyper, meijerg, appellf1 +from sympy.functions.special.polynomials import (legendre, assoc_legendre, + hermite, hermite_prob, chebyshevt, chebyshevu, chebyshevu_root, + chebyshevt_root, laguerre, assoc_laguerre, gegenbauer, jacobi, jacobi_normalized) +from sympy.functions.special.spherical_harmonics import Ynm, Ynm_c, Znm +from sympy.functions.special.elliptic_integrals import (elliptic_k, + elliptic_f, elliptic_e, elliptic_pi) +from sympy.functions.special.beta_functions import beta, betainc, betainc_regularized +from sympy.functions.special.mathieu_functions import (mathieus, mathieuc, + mathieusprime, mathieucprime) +ln = log + +__all__ = [ + 'factorial', 'factorial2', 'rf', 'ff', 'binomial', 'RisingFactorial', + 'FallingFactorial', 'subfactorial', + + 'carmichael', 'fibonacci', 'lucas', 'motzkin', 'tribonacci', 'harmonic', + 'bernoulli', 'bell', 'euler', 'catalan', 'genocchi', 'andre', 'partition', + 'divisor_sigma', 'udivisor_sigma', 'legendre_symbol', 'jacobi_symbol', 'kronecker_symbol', + 'mobius', 'primenu', 'primeomega', 'totient', 'reduced_totient', 'primepi', + + 'sqrt', 'root', 'Min', 'Max', 'Id', 'real_root', 'cbrt', 'Rem', + + 're', 'im', 'sign', 'Abs', 'conjugate', 'arg', 'polar_lift', + 'periodic_argument', 'unbranched_argument', 'principal_branch', + 'transpose', 'adjoint', 'polarify', 'unpolarify', + + 'sin', 'cos', 'tan', 'sec', 'csc', 'cot', 'sinc', 'asin', 'acos', 'atan', + 'asec', 'acsc', 'acot', 'atan2', + + 'exp_polar', 'exp', 'ln', 'log', 'LambertW', + + 'sinh', 'cosh', 'tanh', 'coth', 'sech', 'csch', 'asinh', 'acosh', 'atanh', + 'acoth', 'asech', 'acsch', + + 'floor', 'ceiling', 'frac', + + 'Piecewise', 'piecewise_fold', 'piecewise_exclusive', + + 'erf', 'erfc', 'erfi', 'erf2', 'erfinv', 'erfcinv', 'erf2inv', 'Ei', + 'expint', 'E1', 'li', 'Li', 'Si', 'Ci', 'Shi', 'Chi', 'fresnels', + 'fresnelc', + + 'gamma', 'lowergamma', 'uppergamma', 'polygamma', 'loggamma', 'digamma', + 'trigamma', 'multigamma', + + 'dirichlet_eta', 'zeta', 'lerchphi', 'polylog', 'stieltjes', 'riemann_xi', + + 'Eijk', 'LeviCivita', 'KroneckerDelta', + + 'SingularityFunction', + + 'DiracDelta', 'Heaviside', + + 'bspline_basis', 'bspline_basis_set', 'interpolating_spline', + + 'besselj', 'bessely', 'besseli', 'besselk', 'hankel1', 'hankel2', 'jn', + 'yn', 'jn_zeros', 'hn1', 'hn2', 'airyai', 'airybi', 'airyaiprime', + 'airybiprime', 'marcumq', + + 'hyper', 'meijerg', 'appellf1', + + 'legendre', 'assoc_legendre', 'hermite', 'hermite_prob', 'chebyshevt', + 'chebyshevu', 'chebyshevu_root', 'chebyshevt_root', 'laguerre', + 'assoc_laguerre', 'gegenbauer', 'jacobi', 'jacobi_normalized', + + 'Ynm', 'Ynm_c', 'Znm', + + 'elliptic_k', 'elliptic_f', 'elliptic_e', 'elliptic_pi', + + 'beta', 'betainc', 'betainc_regularized', + + 'mathieus', 'mathieuc', 'mathieusprime', 'mathieucprime', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bb85d4ff5d53eb44a039a95cfc2fff687322cc76 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/__init__.py @@ -0,0 +1,45 @@ +""" +A geometry module for the SymPy library. This module contains all of the +entities and functions needed to construct basic geometrical data and to +perform simple informational queries. + +Usage: +====== + +Examples +======== + +""" +from sympy.geometry.point import Point, Point2D, Point3D +from sympy.geometry.line import Line, Ray, Segment, Line2D, Segment2D, Ray2D, \ + Line3D, Segment3D, Ray3D +from sympy.geometry.plane import Plane +from sympy.geometry.ellipse import Ellipse, Circle +from sympy.geometry.polygon import Polygon, RegularPolygon, Triangle, rad, deg +from sympy.geometry.util import are_similar, centroid, convex_hull, idiff, \ + intersection, closest_points, farthest_points +from sympy.geometry.exceptions import GeometryError +from sympy.geometry.curve import Curve +from sympy.geometry.parabola import Parabola + +__all__ = [ + 'Point', 'Point2D', 'Point3D', + + 'Line', 'Ray', 'Segment', 'Line2D', 'Segment2D', 'Ray2D', 'Line3D', + 'Segment3D', 'Ray3D', + + 'Plane', + + 'Ellipse', 'Circle', + + 'Polygon', 'RegularPolygon', 'Triangle', 'rad', 'deg', + + 'are_similar', 'centroid', 'convex_hull', 'idiff', 'intersection', + 'closest_points', 'farthest_points', + + 'GeometryError', + + 'Curve', + + 'Parabola', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/curve.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/curve.py new file mode 100644 index 0000000000000000000000000000000000000000..c074f22cad79b1261ad44be4ccface972cdd3b82 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/curve.py @@ -0,0 +1,424 @@ +"""Curves in 2-dimensional Euclidean space. + +Contains +======== +Curve + +""" + +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.core import diff +from sympy.core.containers import Tuple +from sympy.core.symbol import _symbol +from sympy.geometry.entity import GeometryEntity, GeometrySet +from sympy.geometry.point import Point +from sympy.integrals import integrate +from sympy.matrices import Matrix, rot_axis3 +from sympy.utilities.iterables import is_sequence + +from mpmath.libmp.libmpf import prec_to_dps + + +class Curve(GeometrySet): + """A curve in space. + + A curve is defined by parametric functions for the coordinates, a + parameter and the lower and upper bounds for the parameter value. + + Parameters + ========== + + function : list of functions + limits : 3-tuple + Function parameter and lower and upper bounds. + + Attributes + ========== + + functions + parameter + limits + + Raises + ====== + + ValueError + When `functions` are specified incorrectly. + When `limits` are specified incorrectly. + + Examples + ======== + + >>> from sympy import Curve, sin, cos, interpolate + >>> from sympy.abc import t, a + >>> C = Curve((sin(t), cos(t)), (t, 0, 2)) + >>> C.functions + (sin(t), cos(t)) + >>> C.limits + (t, 0, 2) + >>> C.parameter + t + >>> C = Curve((t, interpolate([1, 4, 9, 16], t)), (t, 0, 1)); C + Curve((t, t**2), (t, 0, 1)) + >>> C.subs(t, 4) + Point2D(4, 16) + >>> C.arbitrary_point(a) + Point2D(a, a**2) + + See Also + ======== + + sympy.core.function.Function + sympy.polys.polyfuncs.interpolate + + """ + + def __new__(cls, function, limits): + if not is_sequence(function) or len(function) != 2: + raise ValueError("Function argument should be (x(t), y(t)) " + "but got %s" % str(function)) + if not is_sequence(limits) or len(limits) != 3: + raise ValueError("Limit argument should be (t, tmin, tmax) " + "but got %s" % str(limits)) + + return GeometryEntity.__new__(cls, Tuple(*function), Tuple(*limits)) + + def __call__(self, f): + return self.subs(self.parameter, f) + + def _eval_subs(self, old, new): + if old == self.parameter: + return Point(*[f.subs(old, new) for f in self.functions]) + + def _eval_evalf(self, prec=15, **options): + f, (t, a, b) = self.args + dps = prec_to_dps(prec) + f = tuple([i.evalf(n=dps, **options) for i in f]) + a, b = [i.evalf(n=dps, **options) for i in (a, b)] + return self.func(f, (t, a, b)) + + def arbitrary_point(self, parameter='t'): + """A parameterized point on the curve. + + Parameters + ========== + + parameter : str or Symbol, optional + Default value is 't'. + The Curve's parameter is selected with None or self.parameter + otherwise the provided symbol is used. + + Returns + ======= + + Point : + Returns a point in parametric form. + + Raises + ====== + + ValueError + When `parameter` already appears in the functions. + + Examples + ======== + + >>> from sympy import Curve, Symbol + >>> from sympy.abc import s + >>> C = Curve([2*s, s**2], (s, 0, 2)) + >>> C.arbitrary_point() + Point2D(2*t, t**2) + >>> C.arbitrary_point(C.parameter) + Point2D(2*s, s**2) + >>> C.arbitrary_point(None) + Point2D(2*s, s**2) + >>> C.arbitrary_point(Symbol('a')) + Point2D(2*a, a**2) + + See Also + ======== + + sympy.geometry.point.Point + + """ + if parameter is None: + return Point(*self.functions) + + tnew = _symbol(parameter, self.parameter, real=True) + t = self.parameter + if (tnew.name != t.name and + tnew.name in (f.name for f in self.free_symbols)): + raise ValueError('Symbol %s already appears in object ' + 'and cannot be used as a parameter.' % tnew.name) + return Point(*[w.subs(t, tnew) for w in self.functions]) + + @property + def free_symbols(self): + """Return a set of symbols other than the bound symbols used to + parametrically define the Curve. + + Returns + ======= + + set : + Set of all non-parameterized symbols. + + Examples + ======== + + >>> from sympy.abc import t, a + >>> from sympy import Curve + >>> Curve((t, t**2), (t, 0, 2)).free_symbols + set() + >>> Curve((t, t**2), (t, a, 2)).free_symbols + {a} + + """ + free = set() + for a in self.functions + self.limits[1:]: + free |= a.free_symbols + free = free.difference({self.parameter}) + return free + + @property + def ambient_dimension(self): + """The dimension of the curve. + + Returns + ======= + + int : + the dimension of curve. + + Examples + ======== + + >>> from sympy.abc import t + >>> from sympy import Curve + >>> C = Curve((t, t**2), (t, 0, 2)) + >>> C.ambient_dimension + 2 + + """ + + return len(self.args[0]) + + @property + def functions(self): + """The functions specifying the curve. + + Returns + ======= + + functions : + list of parameterized coordinate functions. + + Examples + ======== + + >>> from sympy.abc import t + >>> from sympy import Curve + >>> C = Curve((t, t**2), (t, 0, 2)) + >>> C.functions + (t, t**2) + + See Also + ======== + + parameter + + """ + return self.args[0] + + @property + def limits(self): + """The limits for the curve. + + Returns + ======= + + limits : tuple + Contains parameter and lower and upper limits. + + Examples + ======== + + >>> from sympy.abc import t + >>> from sympy import Curve + >>> C = Curve([t, t**3], (t, -2, 2)) + >>> C.limits + (t, -2, 2) + + See Also + ======== + + plot_interval + + """ + return self.args[1] + + @property + def parameter(self): + """The curve function variable. + + Returns + ======= + + Symbol : + returns a bound symbol. + + Examples + ======== + + >>> from sympy.abc import t + >>> from sympy import Curve + >>> C = Curve([t, t**2], (t, 0, 2)) + >>> C.parameter + t + + See Also + ======== + + functions + + """ + return self.args[1][0] + + @property + def length(self): + """The curve length. + + Examples + ======== + + >>> from sympy import Curve + >>> from sympy.abc import t + >>> Curve((t, t), (t, 0, 1)).length + sqrt(2) + + """ + integrand = sqrt(sum(diff(func, self.limits[0])**2 for func in self.functions)) + return integrate(integrand, self.limits) + + def plot_interval(self, parameter='t'): + """The plot interval for the default geometric plot of the curve. + + Parameters + ========== + + parameter : str or Symbol, optional + Default value is 't'; + otherwise the provided symbol is used. + + Returns + ======= + + List : + the plot interval as below: + [parameter, lower_bound, upper_bound] + + Examples + ======== + + >>> from sympy import Curve, sin + >>> from sympy.abc import x, s + >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval() + [t, 1, 2] + >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval(s) + [s, 1, 2] + + See Also + ======== + + limits : Returns limits of the parameter interval + + """ + t = _symbol(parameter, self.parameter, real=True) + return [t] + list(self.limits[1:]) + + def rotate(self, angle=0, pt=None): + """This function is used to rotate a curve along given point ``pt`` at given angle(in radian). + + Parameters + ========== + + angle : + the angle at which the curve will be rotated(in radian) in counterclockwise direction. + default value of angle is 0. + + pt : Point + the point along which the curve will be rotated. + If no point given, the curve will be rotated around origin. + + Returns + ======= + + Curve : + returns a curve rotated at given angle along given point. + + Examples + ======== + + >>> from sympy import Curve, pi + >>> from sympy.abc import x + >>> Curve((x, x), (x, 0, 1)).rotate(pi/2) + Curve((-x, x), (x, 0, 1)) + + """ + if pt: + pt = -Point(pt, dim=2) + else: + pt = Point(0,0) + rv = self.translate(*pt.args) + f = list(rv.functions) + f.append(0) + f = Matrix(1, 3, f) + f *= rot_axis3(angle) + rv = self.func(f[0, :2].tolist()[0], self.limits) + pt = -pt + return rv.translate(*pt.args) + + def scale(self, x=1, y=1, pt=None): + """Override GeometryEntity.scale since Curve is not made up of Points. + + Returns + ======= + + Curve : + returns scaled curve. + + Examples + ======== + + >>> from sympy import Curve + >>> from sympy.abc import x + >>> Curve((x, x), (x, 0, 1)).scale(2) + Curve((2*x, x), (x, 0, 1)) + + """ + if pt: + pt = Point(pt, dim=2) + return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) + fx, fy = self.functions + return self.func((fx*x, fy*y), self.limits) + + def translate(self, x=0, y=0): + """Translate the Curve by (x, y). + + Returns + ======= + + Curve : + returns a translated curve. + + Examples + ======== + + >>> from sympy import Curve + >>> from sympy.abc import x + >>> Curve((x, x), (x, 0, 1)).translate(1, 2) + Curve((x + 1, x + 2), (x, 0, 1)) + + """ + fx, fy = self.functions + return self.func((fx + x, fy + y), self.limits) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/ellipse.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/ellipse.py new file mode 100644 index 0000000000000000000000000000000000000000..199db25fde9b019893a275d69959154990e8a4a7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/ellipse.py @@ -0,0 +1,1768 @@ +"""Elliptical geometrical entities. + +Contains +* Ellipse +* Circle + +""" + +from sympy.core.expr import Expr +from sympy.core.relational import Eq +from sympy.core import S, pi, sympify +from sympy.core.evalf import N +from sympy.core.parameters import global_parameters +from sympy.core.logic import fuzzy_bool +from sympy.core.numbers import Rational, oo +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy, uniquely_named_symbol, _symbol +from sympy.simplify.simplify import simplify +from sympy.simplify.trigsimp import trigsimp +from sympy.functions.elementary.miscellaneous import sqrt, Max +from sympy.functions.elementary.trigonometric import cos, sin +from sympy.functions.special.elliptic_integrals import elliptic_e +from .entity import GeometryEntity, GeometrySet +from .exceptions import GeometryError +from .line import Line, Segment, Ray2D, Segment2D, Line2D, LinearEntity3D +from .point import Point, Point2D, Point3D +from .util import idiff, find +from sympy.polys import DomainError, Poly, PolynomialError +from sympy.polys.polyutils import _not_a_coeff, _nsort +from sympy.solvers import solve +from sympy.solvers.solveset import linear_coeffs +from sympy.utilities.misc import filldedent, func_name + +from mpmath.libmp.libmpf import prec_to_dps + +import random + +x, y = [Dummy('ellipse_dummy', real=True) for i in range(2)] + + +class Ellipse(GeometrySet): + """An elliptical GeometryEntity. + + Parameters + ========== + + center : Point, optional + Default value is Point(0, 0) + hradius : number or SymPy expression, optional + vradius : number or SymPy expression, optional + eccentricity : number or SymPy expression, optional + Two of `hradius`, `vradius` and `eccentricity` must be supplied to + create an Ellipse. The third is derived from the two supplied. + + Attributes + ========== + + center + hradius + vradius + area + circumference + eccentricity + periapsis + apoapsis + focus_distance + foci + + Raises + ====== + + GeometryError + When `hradius`, `vradius` and `eccentricity` are incorrectly supplied + as parameters. + TypeError + When `center` is not a Point. + + See Also + ======== + + Circle + + Notes + ----- + Constructed from a center and two radii, the first being the horizontal + radius (along the x-axis) and the second being the vertical radius (along + the y-axis). + + When symbolic value for hradius and vradius are used, any calculation that + refers to the foci or the major or minor axis will assume that the ellipse + has its major radius on the x-axis. If this is not true then a manual + rotation is necessary. + + Examples + ======== + + >>> from sympy import Ellipse, Point, Rational + >>> e1 = Ellipse(Point(0, 0), 5, 1) + >>> e1.hradius, e1.vradius + (5, 1) + >>> e2 = Ellipse(Point(3, 1), hradius=3, eccentricity=Rational(4, 5)) + >>> e2 + Ellipse(Point2D(3, 1), 3, 9/5) + + """ + + def __contains__(self, o): + if isinstance(o, Point): + res = self.equation(x, y).subs({x: o.x, y: o.y}) + return trigsimp(simplify(res)) is S.Zero + elif isinstance(o, Ellipse): + return self == o + return False + + def __eq__(self, o): + """Is the other GeometryEntity the same as this ellipse?""" + return isinstance(o, Ellipse) and (self.center == o.center and + self.hradius == o.hradius and + self.vradius == o.vradius) + + def __hash__(self): + return super().__hash__() + + def __new__( + cls, center=None, hradius=None, vradius=None, eccentricity=None, **kwargs): + + hradius = sympify(hradius) + vradius = sympify(vradius) + + if center is None: + center = Point(0, 0) + else: + if len(center) != 2: + raise ValueError('The center of "{}" must be a two dimensional point'.format(cls)) + center = Point(center, dim=2) + + if len(list(filter(lambda x: x is not None, (hradius, vradius, eccentricity)))) != 2: + raise ValueError(filldedent(''' + Exactly two arguments of "hradius", "vradius", and + "eccentricity" must not be None.''')) + + if eccentricity is not None: + eccentricity = sympify(eccentricity) + if eccentricity.is_negative: + raise GeometryError("Eccentricity of ellipse/circle should lie between [0, 1)") + elif hradius is None: + hradius = vradius / sqrt(1 - eccentricity**2) + elif vradius is None: + vradius = hradius * sqrt(1 - eccentricity**2) + + if hradius == vradius: + return Circle(center, hradius, **kwargs) + + if S.Zero in (hradius, vradius): + return Segment(Point(center[0] - hradius, center[1] - vradius), Point(center[0] + hradius, center[1] + vradius)) + + if hradius.is_real is False or vradius.is_real is False: + raise GeometryError("Invalid value encountered when computing hradius / vradius.") + + return GeometryEntity.__new__(cls, center, hradius, vradius, **kwargs) + + def _svg(self, scale_factor=1., fill_color="#66cc99"): + """Returns SVG ellipse element for the Ellipse. + + Parameters + ========== + + scale_factor : float + Multiplication factor for the SVG stroke-width. Default is 1. + fill_color : str, optional + Hex string for fill color. Default is "#66cc99". + """ + + c = N(self.center) + h, v = N(self.hradius), N(self.vradius) + return ( + '' + ).format(2. * scale_factor, fill_color, c.x, c.y, h, v) + + @property + def ambient_dimension(self): + return 2 + + @property + def apoapsis(self): + """The apoapsis of the ellipse. + + The greatest distance between the focus and the contour. + + Returns + ======= + + apoapsis : number + + See Also + ======== + + periapsis : Returns shortest distance between foci and contour + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.apoapsis + 2*sqrt(2) + 3 + + """ + return self.major * (1 + self.eccentricity) + + def arbitrary_point(self, parameter='t'): + """A parameterized point on the ellipse. + + Parameters + ========== + + parameter : str, optional + Default value is 't'. + + Returns + ======= + + arbitrary_point : Point + + Raises + ====== + + ValueError + When `parameter` already appears in the functions. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> e1 = Ellipse(Point(0, 0), 3, 2) + >>> e1.arbitrary_point() + Point2D(3*cos(t), 2*sin(t)) + + """ + t = _symbol(parameter, real=True) + if t.name in (f.name for f in self.free_symbols): + raise ValueError(filldedent('Symbol %s already appears in object ' + 'and cannot be used as a parameter.' % t.name)) + return Point(self.center.x + self.hradius*cos(t), + self.center.y + self.vradius*sin(t)) + + @property + def area(self): + """The area of the ellipse. + + Returns + ======= + + area : number + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.area + 3*pi + + """ + return simplify(S.Pi * self.hradius * self.vradius) + + @property + def bounds(self): + """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding + rectangle for the geometric figure. + + """ + + h, v = self.hradius, self.vradius + return (self.center.x - h, self.center.y - v, self.center.x + h, self.center.y + v) + + @property + def center(self): + """The center of the ellipse. + + Returns + ======= + + center : number + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.center + Point2D(0, 0) + + """ + return self.args[0] + + @property + def circumference(self): + """The circumference of the ellipse. + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.circumference + 12*elliptic_e(8/9) + + """ + if self.eccentricity == 1: + # degenerate + return 4*self.major + elif self.eccentricity == 0: + # circle + return 2*pi*self.hradius + else: + return 4*self.major*elliptic_e(self.eccentricity**2) + + @property + def eccentricity(self): + """The eccentricity of the ellipse. + + Returns + ======= + + eccentricity : number + + Examples + ======== + + >>> from sympy import Point, Ellipse, sqrt + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, sqrt(2)) + >>> e1.eccentricity + sqrt(7)/3 + + """ + return self.focus_distance / self.major + + def encloses_point(self, p): + """ + Return True if p is enclosed by (is inside of) self. + + Notes + ----- + Being on the border of self is considered False. + + Parameters + ========== + + p : Point + + Returns + ======= + + encloses_point : True, False or None + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Ellipse, S + >>> from sympy.abc import t + >>> e = Ellipse((0, 0), 3, 2) + >>> e.encloses_point((0, 0)) + True + >>> e.encloses_point(e.arbitrary_point(t).subs(t, S.Half)) + False + >>> e.encloses_point((4, 0)) + False + + """ + p = Point(p, dim=2) + if p in self: + return False + + if len(self.foci) == 2: + # if the combined distance from the foci to p (h1 + h2) is less + # than the combined distance from the foci to the minor axis + # (which is the same as the major axis length) then p is inside + # the ellipse + h1, h2 = [f.distance(p) for f in self.foci] + test = 2*self.major - (h1 + h2) + else: + test = self.radius - self.center.distance(p) + + return fuzzy_bool(test.is_positive) + + def equation(self, x='x', y='y', _slope=None): + """ + Returns the equation of an ellipse aligned with the x and y axes; + when slope is given, the equation returned corresponds to an ellipse + with a major axis having that slope. + + Parameters + ========== + + x : str, optional + Label for the x-axis. Default value is 'x'. + y : str, optional + Label for the y-axis. Default value is 'y'. + _slope : Expr, optional + The slope of the major axis. Ignored when 'None'. + + Returns + ======= + + equation : SymPy expression + + See Also + ======== + + arbitrary_point : Returns parameterized point on ellipse + + Examples + ======== + + >>> from sympy import Point, Ellipse, pi + >>> from sympy.abc import x, y + >>> e1 = Ellipse(Point(1, 0), 3, 2) + >>> eq1 = e1.equation(x, y); eq1 + y**2/4 + (x/3 - 1/3)**2 - 1 + >>> eq2 = e1.equation(x, y, _slope=1); eq2 + (-x + y + 1)**2/8 + (x + y - 1)**2/18 - 1 + + A point on e1 satisfies eq1. Let's use one on the x-axis: + + >>> p1 = e1.center + Point(e1.major, 0) + >>> assert eq1.subs(x, p1.x).subs(y, p1.y) == 0 + + When rotated the same as the rotated ellipse, about the center + point of the ellipse, it will satisfy the rotated ellipse's + equation, too: + + >>> r1 = p1.rotate(pi/4, e1.center) + >>> assert eq2.subs(x, r1.x).subs(y, r1.y) == 0 + + References + ========== + + .. [1] https://math.stackexchange.com/questions/108270/what-is-the-equation-of-an-ellipse-that-is-not-aligned-with-the-axis + .. [2] https://en.wikipedia.org/wiki/Ellipse#Shifted_ellipse + + """ + + x = _symbol(x, real=True) + y = _symbol(y, real=True) + + dx = x - self.center.x + dy = y - self.center.y + + if _slope is not None: + L = (dy - _slope*dx)**2 + l = (_slope*dy + dx)**2 + h = 1 + _slope**2 + b = h*self.major**2 + a = h*self.minor**2 + return l/b + L/a - 1 + + else: + t1 = (dx/self.hradius)**2 + t2 = (dy/self.vradius)**2 + return t1 + t2 - 1 + + def evolute(self, x='x', y='y'): + """The equation of evolute of the ellipse. + + Parameters + ========== + + x : str, optional + Label for the x-axis. Default value is 'x'. + y : str, optional + Label for the y-axis. Default value is 'y'. + + Returns + ======= + + equation : SymPy expression + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> e1 = Ellipse(Point(1, 0), 3, 2) + >>> e1.evolute() + 2**(2/3)*y**(2/3) + (3*x - 3)**(2/3) - 5**(2/3) + """ + if len(self.args) != 3: + raise NotImplementedError('Evolute of arbitrary Ellipse is not supported.') + x = _symbol(x, real=True) + y = _symbol(y, real=True) + t1 = (self.hradius*(x - self.center.x))**Rational(2, 3) + t2 = (self.vradius*(y - self.center.y))**Rational(2, 3) + return t1 + t2 - (self.hradius**2 - self.vradius**2)**Rational(2, 3) + + @property + def foci(self): + """The foci of the ellipse. + + Notes + ----- + The foci can only be calculated if the major/minor axes are known. + + Raises + ====== + + ValueError + When the major and minor axis cannot be determined. + + See Also + ======== + + sympy.geometry.point.Point + focus_distance : Returns the distance between focus and center + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.foci + (Point2D(-2*sqrt(2), 0), Point2D(2*sqrt(2), 0)) + + """ + c = self.center + hr, vr = self.hradius, self.vradius + if hr == vr: + return (c, c) + + # calculate focus distance manually, since focus_distance calls this + # routine + fd = sqrt(self.major**2 - self.minor**2) + if hr == self.minor: + # foci on the y-axis + return (c + Point(0, -fd), c + Point(0, fd)) + elif hr == self.major: + # foci on the x-axis + return (c + Point(-fd, 0), c + Point(fd, 0)) + + @property + def focus_distance(self): + """The focal distance of the ellipse. + + The distance between the center and one focus. + + Returns + ======= + + focus_distance : number + + See Also + ======== + + foci + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.focus_distance + 2*sqrt(2) + + """ + return Point.distance(self.center, self.foci[0]) + + @property + def hradius(self): + """The horizontal radius of the ellipse. + + Returns + ======= + + hradius : number + + See Also + ======== + + vradius, major, minor + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.hradius + 3 + + """ + return self.args[1] + + def intersection(self, o): + """The intersection of this ellipse and another geometrical entity + `o`. + + Parameters + ========== + + o : GeometryEntity + + Returns + ======= + + intersection : list of GeometryEntity objects + + Notes + ----- + Currently supports intersections with Point, Line, Segment, Ray, + Circle and Ellipse types. + + See Also + ======== + + sympy.geometry.entity.GeometryEntity + + Examples + ======== + + >>> from sympy import Ellipse, Point, Line + >>> e = Ellipse(Point(0, 0), 5, 7) + >>> e.intersection(Point(0, 0)) + [] + >>> e.intersection(Point(5, 0)) + [Point2D(5, 0)] + >>> e.intersection(Line(Point(0,0), Point(0, 1))) + [Point2D(0, -7), Point2D(0, 7)] + >>> e.intersection(Line(Point(5,0), Point(5, 1))) + [Point2D(5, 0)] + >>> e.intersection(Line(Point(6,0), Point(6, 1))) + [] + >>> e = Ellipse(Point(-1, 0), 4, 3) + >>> e.intersection(Ellipse(Point(1, 0), 4, 3)) + [Point2D(0, -3*sqrt(15)/4), Point2D(0, 3*sqrt(15)/4)] + >>> e.intersection(Ellipse(Point(5, 0), 4, 3)) + [Point2D(2, -3*sqrt(7)/4), Point2D(2, 3*sqrt(7)/4)] + >>> e.intersection(Ellipse(Point(100500, 0), 4, 3)) + [] + >>> e.intersection(Ellipse(Point(0, 0), 3, 4)) + [Point2D(3, 0), Point2D(-363/175, -48*sqrt(111)/175), Point2D(-363/175, 48*sqrt(111)/175)] + >>> e.intersection(Ellipse(Point(-1, 0), 3, 4)) + [Point2D(-17/5, -12/5), Point2D(-17/5, 12/5), Point2D(7/5, -12/5), Point2D(7/5, 12/5)] + """ + # TODO: Replace solve with nonlinsolve, when nonlinsolve will be able to solve in real domain + + if isinstance(o, Point): + if o in self: + return [o] + else: + return [] + + elif isinstance(o, (Segment2D, Ray2D)): + ellipse_equation = self.equation(x, y) + result = solve([ellipse_equation, Line( + o.points[0], o.points[1]).equation(x, y)], [x, y], + set=True)[1] + return list(ordered([Point(i) for i in result if i in o])) + + elif isinstance(o, Polygon): + return o.intersection(self) + + elif isinstance(o, (Ellipse, Line2D)): + if o == self: + return self + else: + ellipse_equation = self.equation(x, y) + return list(ordered([Point(i) for i in solve( + [ellipse_equation, o.equation(x, y)], [x, y], + set=True)[1]])) + elif isinstance(o, LinearEntity3D): + raise TypeError('Entity must be two dimensional, not three dimensional') + else: + raise TypeError('Intersection not handled for %s' % func_name(o)) + + def is_tangent(self, o): + """Is `o` tangent to the ellipse? + + Parameters + ========== + + o : GeometryEntity + An Ellipse, LinearEntity or Polygon + + Raises + ====== + + NotImplementedError + When the wrong type of argument is supplied. + + Returns + ======= + + is_tangent: boolean + True if o is tangent to the ellipse, False otherwise. + + See Also + ======== + + tangent_lines + + Examples + ======== + + >>> from sympy import Point, Ellipse, Line + >>> p0, p1, p2 = Point(0, 0), Point(3, 0), Point(3, 3) + >>> e1 = Ellipse(p0, 3, 2) + >>> l1 = Line(p1, p2) + >>> e1.is_tangent(l1) + True + + """ + if isinstance(o, Point2D): + return False + elif isinstance(o, Ellipse): + intersect = self.intersection(o) + if isinstance(intersect, Ellipse): + return True + elif intersect: + return all((self.tangent_lines(i)[0]).equals(o.tangent_lines(i)[0]) for i in intersect) + else: + return False + elif isinstance(o, Line2D): + hit = self.intersection(o) + if not hit: + return False + if len(hit) == 1: + return True + # might return None if it can't decide + return hit[0].equals(hit[1]) + elif isinstance(o, (Segment2D, Ray2D)): + intersect = self.intersection(o) + if len(intersect) == 1: + return o in self.tangent_lines(intersect[0])[0] + else: + return False + elif isinstance(o, Polygon): + return all(self.is_tangent(s) for s in o.sides) + elif isinstance(o, (LinearEntity3D, Point3D)): + raise TypeError('Entity must be two dimensional, not three dimensional') + else: + raise TypeError('Is_tangent not handled for %s' % func_name(o)) + + @property + def major(self): + """Longer axis of the ellipse (if it can be determined) else hradius. + + Returns + ======= + + major : number or expression + + See Also + ======== + + hradius, vradius, minor + + Examples + ======== + + >>> from sympy import Point, Ellipse, Symbol + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.major + 3 + + >>> a = Symbol('a') + >>> b = Symbol('b') + >>> Ellipse(p1, a, b).major + a + >>> Ellipse(p1, b, a).major + b + + >>> m = Symbol('m') + >>> M = m + 1 + >>> Ellipse(p1, m, M).major + m + 1 + + """ + ab = self.args[1:3] + if len(ab) == 1: + return ab[0] + a, b = ab + o = b - a < 0 + if o == True: + return a + elif o == False: + return b + return self.hradius + + @property + def minor(self): + """Shorter axis of the ellipse (if it can be determined) else vradius. + + Returns + ======= + + minor : number or expression + + See Also + ======== + + hradius, vradius, major + + Examples + ======== + + >>> from sympy import Point, Ellipse, Symbol + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.minor + 1 + + >>> a = Symbol('a') + >>> b = Symbol('b') + >>> Ellipse(p1, a, b).minor + b + >>> Ellipse(p1, b, a).minor + a + + >>> m = Symbol('m') + >>> M = m + 1 + >>> Ellipse(p1, m, M).minor + m + + """ + ab = self.args[1:3] + if len(ab) == 1: + return ab[0] + a, b = ab + o = a - b < 0 + if o == True: + return a + elif o == False: + return b + return self.vradius + + def normal_lines(self, p, prec=None): + """Normal lines between `p` and the ellipse. + + Parameters + ========== + + p : Point + + Returns + ======= + + normal_lines : list with 1, 2 or 4 Lines + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> e = Ellipse((0, 0), 2, 3) + >>> c = e.center + >>> e.normal_lines(c + Point(1, 0)) + [Line2D(Point2D(0, 0), Point2D(1, 0))] + >>> e.normal_lines(c) + [Line2D(Point2D(0, 0), Point2D(0, 1)), Line2D(Point2D(0, 0), Point2D(1, 0))] + + Off-axis points require the solution of a quartic equation. This + often leads to very large expressions that may be of little practical + use. An approximate solution of `prec` digits can be obtained by + passing in the desired value: + + >>> e.normal_lines((3, 3), prec=2) + [Line2D(Point2D(-0.81, -2.7), Point2D(0.19, -1.2)), + Line2D(Point2D(1.5, -2.0), Point2D(2.5, -2.7))] + + Whereas the above solution has an operation count of 12, the exact + solution has an operation count of 2020. + """ + p = Point(p, dim=2) + + # XXX change True to something like self.angle == 0 if the arbitrarily + # rotated ellipse is introduced. + # https://github.com/sympy/sympy/issues/2815) + if True: + rv = [] + if p.x == self.center.x: + rv.append(Line(self.center, slope=oo)) + if p.y == self.center.y: + rv.append(Line(self.center, slope=0)) + if rv: + # at these special orientations of p either 1 or 2 normals + # exist and we are done + return rv + + # find the 4 normal points and construct lines through them with + # the corresponding slope + eq = self.equation(x, y) + dydx = idiff(eq, y, x) + norm = -1/dydx + slope = Line(p, (x, y)).slope + seq = slope - norm + + # TODO: Replace solve with solveset, when this line is tested + yis = solve(seq, y)[0] + xeq = eq.subs(y, yis).as_numer_denom()[0].expand() + if len(xeq.free_symbols) == 1: + try: + # this is so much faster, it's worth a try + xsol = Poly(xeq, x).real_roots() + except (DomainError, PolynomialError, NotImplementedError): + # TODO: Replace solve with solveset, when these lines are tested + xsol = _nsort(solve(xeq, x), separated=True)[0] + points = [Point(i, solve(eq.subs(x, i), y)[0]) for i in xsol] + else: + raise NotImplementedError( + 'intersections for the general ellipse are not supported') + slopes = [norm.subs(zip((x, y), pt.args)) for pt in points] + if prec is not None: + points = [pt.n(prec) for pt in points] + slopes = [i if _not_a_coeff(i) else i.n(prec) for i in slopes] + return [Line(pt, slope=s) for pt, s in zip(points, slopes)] + + @property + def periapsis(self): + """The periapsis of the ellipse. + + The shortest distance between the focus and the contour. + + Returns + ======= + + periapsis : number + + See Also + ======== + + apoapsis : Returns greatest distance between focus and contour + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.periapsis + 3 - 2*sqrt(2) + + """ + return self.major * (1 - self.eccentricity) + + @property + def semilatus_rectum(self): + """ + Calculates the semi-latus rectum of the Ellipse. + + Semi-latus rectum is defined as one half of the chord through a + focus parallel to the conic section directrix of a conic section. + + Returns + ======= + + semilatus_rectum : number + + See Also + ======== + + apoapsis : Returns greatest distance between focus and contour + + periapsis : The shortest distance between the focus and the contour + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.semilatus_rectum + 1/3 + + References + ========== + + .. [1] https://mathworld.wolfram.com/SemilatusRectum.html + .. [2] https://en.wikipedia.org/wiki/Ellipse#Semi-latus_rectum + + """ + return self.major * (1 - self.eccentricity ** 2) + + def auxiliary_circle(self): + """Returns a Circle whose diameter is the major axis of the ellipse. + + Examples + ======== + + >>> from sympy import Ellipse, Point, symbols + >>> c = Point(1, 2) + >>> Ellipse(c, 8, 7).auxiliary_circle() + Circle(Point2D(1, 2), 8) + >>> a, b = symbols('a b') + >>> Ellipse(c, a, b).auxiliary_circle() + Circle(Point2D(1, 2), Max(a, b)) + """ + return Circle(self.center, Max(self.hradius, self.vradius)) + + def director_circle(self): + """ + Returns a Circle consisting of all points where two perpendicular + tangent lines to the ellipse cross each other. + + Returns + ======= + + Circle + A director circle returned as a geometric object. + + Examples + ======== + + >>> from sympy import Ellipse, Point, symbols + >>> c = Point(3,8) + >>> Ellipse(c, 7, 9).director_circle() + Circle(Point2D(3, 8), sqrt(130)) + >>> a, b = symbols('a b') + >>> Ellipse(c, a, b).director_circle() + Circle(Point2D(3, 8), sqrt(a**2 + b**2)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Director_circle + + """ + return Circle(self.center, sqrt(self.hradius**2 + self.vradius**2)) + + def plot_interval(self, parameter='t'): + """The plot interval for the default geometric plot of the Ellipse. + + Parameters + ========== + + parameter : str, optional + Default value is 't'. + + Returns + ======= + + plot_interval : list + [parameter, lower_bound, upper_bound] + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> e1 = Ellipse(Point(0, 0), 3, 2) + >>> e1.plot_interval() + [t, -pi, pi] + + """ + t = _symbol(parameter, real=True) + return [t, -S.Pi, S.Pi] + + def random_point(self, seed=None): + """A random point on the ellipse. + + Returns + ======= + + point : Point + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> e1 = Ellipse(Point(0, 0), 3, 2) + >>> e1.random_point() # gives some random point + Point2D(...) + >>> p1 = e1.random_point(seed=0); p1.n(2) + Point2D(2.1, 1.4) + + Notes + ===== + + When creating a random point, one may simply replace the + parameter with a random number. When doing so, however, the + random number should be made a Rational or else the point + may not test as being in the ellipse: + + >>> from sympy.abc import t + >>> from sympy import Rational + >>> arb = e1.arbitrary_point(t); arb + Point2D(3*cos(t), 2*sin(t)) + >>> arb.subs(t, .1) in e1 + False + >>> arb.subs(t, Rational(.1)) in e1 + True + >>> arb.subs(t, Rational('.1')) in e1 + True + + See Also + ======== + sympy.geometry.point.Point + arbitrary_point : Returns parameterized point on ellipse + """ + t = _symbol('t', real=True) + x, y = self.arbitrary_point(t).args + # get a random value in [-1, 1) corresponding to cos(t) + # and confirm that it will test as being in the ellipse + if seed is not None: + rng = random.Random(seed) + else: + rng = random + # simplify this now or else the Float will turn s into a Float + r = Rational(rng.random()) + c = 2*r - 1 + s = sqrt(1 - c**2) + return Point(x.subs(cos(t), c), y.subs(sin(t), s)) + + def reflect(self, line): + """Override GeometryEntity.reflect since the radius + is not a GeometryEntity. + + Examples + ======== + + >>> from sympy import Circle, Line + >>> Circle((0, 1), 1).reflect(Line((0, 0), (1, 1))) + Circle(Point2D(1, 0), -1) + >>> from sympy import Ellipse, Line, Point + >>> Ellipse(Point(3, 4), 1, 3).reflect(Line(Point(0, -4), Point(5, 0))) + Traceback (most recent call last): + ... + NotImplementedError: + General Ellipse is not supported but the equation of the reflected + Ellipse is given by the zeros of: f(x, y) = (9*x/41 + 40*y/41 + + 37/41)**2 + (40*x/123 - 3*y/41 - 364/123)**2 - 1 + + Notes + ===== + + Until the general ellipse (with no axis parallel to the x-axis) is + supported a NotImplemented error is raised and the equation whose + zeros define the rotated ellipse is given. + + """ + + if line.slope in (0, oo): + c = self.center + c = c.reflect(line) + return self.func(c, -self.hradius, self.vradius) + else: + x, y = [uniquely_named_symbol( + name, (self, line), modify=lambda s: '_' + s, real=True) + for name in 'xy'] + expr = self.equation(x, y) + p = Point(x, y).reflect(line) + result = expr.subs(zip((x, y), p.args + ), simultaneous=True) + raise NotImplementedError(filldedent( + 'General Ellipse is not supported but the equation ' + 'of the reflected Ellipse is given by the zeros of: ' + + "f(%s, %s) = %s" % (str(x), str(y), str(result)))) + + def rotate(self, angle=0, pt=None): + """Rotate ``angle`` radians counterclockwise about Point ``pt``. + + Note: since the general ellipse is not supported, only rotations that + are integer multiples of pi/2 are allowed. + + Examples + ======== + + >>> from sympy import Ellipse, pi + >>> Ellipse((1, 0), 2, 1).rotate(pi/2) + Ellipse(Point2D(0, 1), 1, 2) + >>> Ellipse((1, 0), 2, 1).rotate(pi) + Ellipse(Point2D(-1, 0), 2, 1) + """ + if self.hradius == self.vradius: + return self.func(self.center.rotate(angle, pt), self.hradius) + if (angle/S.Pi).is_integer: + return super().rotate(angle, pt) + if (2*angle/S.Pi).is_integer: + return self.func(self.center.rotate(angle, pt), self.vradius, self.hradius) + # XXX see https://github.com/sympy/sympy/issues/2815 for general ellipes + raise NotImplementedError('Only rotations of pi/2 are currently supported for Ellipse.') + + def scale(self, x=1, y=1, pt=None): + """Override GeometryEntity.scale since it is the major and minor + axes which must be scaled and they are not GeometryEntities. + + Examples + ======== + + >>> from sympy import Ellipse + >>> Ellipse((0, 0), 2, 1).scale(2, 4) + Circle(Point2D(0, 0), 4) + >>> Ellipse((0, 0), 2, 1).scale(2) + Ellipse(Point2D(0, 0), 4, 1) + """ + c = self.center + if pt: + pt = Point(pt, dim=2) + return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) + h = self.hradius + v = self.vradius + return self.func(c.scale(x, y), hradius=h*x, vradius=v*y) + + def tangent_lines(self, p): + """Tangent lines between `p` and the ellipse. + + If `p` is on the ellipse, returns the tangent line through point `p`. + Otherwise, returns the tangent line(s) from `p` to the ellipse, or + None if no tangent line is possible (e.g., `p` inside ellipse). + + Parameters + ========== + + p : Point + + Returns + ======= + + tangent_lines : list with 1 or 2 Lines + + Raises + ====== + + NotImplementedError + Can only find tangent lines for a point, `p`, on the ellipse. + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.line.Line + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> e1 = Ellipse(Point(0, 0), 3, 2) + >>> e1.tangent_lines(Point(3, 0)) + [Line2D(Point2D(3, 0), Point2D(3, -12))] + + """ + p = Point(p, dim=2) + if self.encloses_point(p): + return [] + + if p in self: + delta = self.center - p + rise = (self.vradius**2)*delta.x + run = -(self.hradius**2)*delta.y + p2 = Point(simplify(p.x + run), + simplify(p.y + rise)) + return [Line(p, p2)] + else: + if len(self.foci) == 2: + f1, f2 = self.foci + maj = self.hradius + test = (2*maj - + Point.distance(f1, p) - + Point.distance(f2, p)) + else: + test = self.radius - Point.distance(self.center, p) + if test.is_number and test.is_positive: + return [] + # else p is outside the ellipse or we can't tell. In case of the + # latter, the solutions returned will only be valid if + # the point is not inside the ellipse; if it is, nan will result. + eq = self.equation(x, y) + dydx = idiff(eq, y, x) + slope = Line(p, Point(x, y)).slope + + # TODO: Replace solve with solveset, when this line is tested + tangent_points = solve([slope - dydx, eq], [x, y]) + + # handle horizontal and vertical tangent lines + if len(tangent_points) == 1: + if tangent_points[0][ + 0] == p.x or tangent_points[0][1] == p.y: + return [Line(p, p + Point(1, 0)), Line(p, p + Point(0, 1))] + else: + return [Line(p, p + Point(0, 1)), Line(p, tangent_points[0])] + + # others + return [Line(p, tangent_points[0]), Line(p, tangent_points[1])] + + @property + def vradius(self): + """The vertical radius of the ellipse. + + Returns + ======= + + vradius : number + + See Also + ======== + + hradius, major, minor + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.vradius + 1 + + """ + return self.args[2] + + + def second_moment_of_area(self, point=None): + """Returns the second moment and product moment area of an ellipse. + + Parameters + ========== + + point : Point, two-tuple of sympifiable objects, or None(default=None) + point is the point about which second moment of area is to be found. + If "point=None" it will be calculated about the axis passing through the + centroid of the ellipse. + + Returns + ======= + + I_xx, I_yy, I_xy : number or SymPy expression + I_xx, I_yy are second moment of area of an ellise. + I_xy is product moment of area of an ellipse. + + Examples + ======== + + >>> from sympy import Point, Ellipse + >>> p1 = Point(0, 0) + >>> e1 = Ellipse(p1, 3, 1) + >>> e1.second_moment_of_area() + (3*pi/4, 27*pi/4, 0) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/List_of_second_moments_of_area + + """ + + I_xx = (S.Pi*(self.hradius)*(self.vradius**3))/4 + I_yy = (S.Pi*(self.hradius**3)*(self.vradius))/4 + I_xy = 0 + + if point is None: + return I_xx, I_yy, I_xy + + # parallel axis theorem + I_xx = I_xx + self.area*((point[1] - self.center.y)**2) + I_yy = I_yy + self.area*((point[0] - self.center.x)**2) + I_xy = I_xy + self.area*(point[0] - self.center.x)*(point[1] - self.center.y) + + return I_xx, I_yy, I_xy + + + def polar_second_moment_of_area(self): + """Returns the polar second moment of area of an Ellipse + + It is a constituent of the second moment of area, linked through + the perpendicular axis theorem. While the planar second moment of + area describes an object's resistance to deflection (bending) when + subjected to a force applied to a plane parallel to the central + axis, the polar second moment of area describes an object's + resistance to deflection when subjected to a moment applied in a + plane perpendicular to the object's central axis (i.e. parallel to + the cross-section) + + Examples + ======== + + >>> from sympy import symbols, Circle, Ellipse + >>> c = Circle((5, 5), 4) + >>> c.polar_second_moment_of_area() + 128*pi + >>> a, b = symbols('a, b') + >>> e = Ellipse((0, 0), a, b) + >>> e.polar_second_moment_of_area() + pi*a**3*b/4 + pi*a*b**3/4 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Polar_moment_of_inertia + + """ + second_moment = self.second_moment_of_area() + return second_moment[0] + second_moment[1] + + + def section_modulus(self, point=None): + """Returns a tuple with the section modulus of an ellipse + + Section modulus is a geometric property of an ellipse defined as the + ratio of second moment of area to the distance of the extreme end of + the ellipse from the centroidal axis. + + Parameters + ========== + + point : Point, two-tuple of sympifyable objects, or None(default=None) + point is the point at which section modulus is to be found. + If "point=None" section modulus will be calculated for the + point farthest from the centroidal axis of the ellipse. + + Returns + ======= + + S_x, S_y: numbers or SymPy expressions + S_x is the section modulus with respect to the x-axis + S_y is the section modulus with respect to the y-axis + A negative sign indicates that the section modulus is + determined for a point below the centroidal axis. + + Examples + ======== + + >>> from sympy import Symbol, Ellipse, Circle, Point2D + >>> d = Symbol('d', positive=True) + >>> c = Circle((0, 0), d/2) + >>> c.section_modulus() + (pi*d**3/32, pi*d**3/32) + >>> e = Ellipse(Point2D(0, 0), 2, 4) + >>> e.section_modulus() + (8*pi, 4*pi) + >>> e.section_modulus((2, 2)) + (16*pi, 4*pi) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Section_modulus + + """ + x_c, y_c = self.center + if point is None: + # taking x and y as maximum distances from centroid + x_min, y_min, x_max, y_max = self.bounds + y = max(y_c - y_min, y_max - y_c) + x = max(x_c - x_min, x_max - x_c) + else: + # taking x and y as distances of the given point from the center + point = Point2D(point) + y = point.y - y_c + x = point.x - x_c + + second_moment = self.second_moment_of_area() + S_x = second_moment[0]/y + S_y = second_moment[1]/x + + return S_x, S_y + + +class Circle(Ellipse): + r"""A circle in space. + + Constructed simply from a center and a radius, from three + non-collinear points, or the equation of a circle. + + Parameters + ========== + + center : Point + radius : number or SymPy expression + points : sequence of three Points + equation : equation of a circle + + Attributes + ========== + + radius (synonymous with hradius, vradius, major and minor) + circumference + equation + + Raises + ====== + + GeometryError + When the given equation is not that of a circle. + When trying to construct circle from incorrect parameters. + + See Also + ======== + + Ellipse, sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Circle, Eq + >>> from sympy.abc import x, y, a, b + + A circle constructed from a center and radius: + + >>> c1 = Circle(Point(0, 0), 5) + >>> c1.hradius, c1.vradius, c1.radius + (5, 5, 5) + + A circle constructed from three points: + + >>> c2 = Circle(Point(0, 0), Point(1, 1), Point(1, 0)) + >>> c2.hradius, c2.vradius, c2.radius, c2.center + (sqrt(2)/2, sqrt(2)/2, sqrt(2)/2, Point2D(1/2, 1/2)) + + A circle can be constructed from an equation in the form + `ax^2 + by^2 + gx + hy + c = 0`, too: + + >>> Circle(x**2 + y**2 - 25) + Circle(Point2D(0, 0), 5) + + If the variables corresponding to x and y are named something + else, their name or symbol can be supplied: + + >>> Circle(Eq(a**2 + b**2, 25), x='a', y=b) + Circle(Point2D(0, 0), 5) + """ + + def __new__(cls, *args, **kwargs): + evaluate = kwargs.get('evaluate', global_parameters.evaluate) + if len(args) == 1 and isinstance(args[0], (Expr, Eq)): + x = kwargs.get('x', 'x') + y = kwargs.get('y', 'y') + equation = args[0].expand() + if isinstance(equation, Eq): + equation = equation.lhs - equation.rhs + x = find(x, equation) + y = find(y, equation) + + try: + a, b, c, d, e = linear_coeffs(equation, x**2, y**2, x, y) + except ValueError: + raise GeometryError("The given equation is not that of a circle.") + + if S.Zero in (a, b) or a != b: + raise GeometryError("The given equation is not that of a circle.") + + center_x = -c/a/2 + center_y = -d/b/2 + r2 = (center_x**2) + (center_y**2) - e/a + + return Circle((center_x, center_y), sqrt(r2), evaluate=evaluate) + + else: + c, r = None, None + if len(args) == 3: + args = [Point(a, dim=2, evaluate=evaluate) for a in args] + t = Triangle(*args) + if not isinstance(t, Triangle): + return t + c = t.circumcenter + r = t.circumradius + elif len(args) == 2: + # Assume (center, radius) pair + c = Point(args[0], dim=2, evaluate=evaluate) + r = args[1] + # this will prohibit imaginary radius + try: + r = Point(r, 0, evaluate=evaluate).x + except ValueError: + raise GeometryError("Circle with imaginary radius is not permitted") + + if not (c is None or r is None): + if r == 0: + return c + return GeometryEntity.__new__(cls, c, r, **kwargs) + + raise GeometryError("Circle.__new__ received unknown arguments") + + def _eval_evalf(self, prec=15, **options): + pt, r = self.args + dps = prec_to_dps(prec) + pt = pt.evalf(n=dps, **options) + r = r.evalf(n=dps, **options) + return self.func(pt, r, evaluate=False) + + @property + def circumference(self): + """The circumference of the circle. + + Returns + ======= + + circumference : number or SymPy expression + + Examples + ======== + + >>> from sympy import Point, Circle + >>> c1 = Circle(Point(3, 4), 6) + >>> c1.circumference + 12*pi + + """ + return 2 * S.Pi * self.radius + + def equation(self, x='x', y='y'): + """The equation of the circle. + + Parameters + ========== + + x : str or Symbol, optional + Default value is 'x'. + y : str or Symbol, optional + Default value is 'y'. + + Returns + ======= + + equation : SymPy expression + + Examples + ======== + + >>> from sympy import Point, Circle + >>> c1 = Circle(Point(0, 0), 5) + >>> c1.equation() + x**2 + y**2 - 25 + + """ + x = _symbol(x, real=True) + y = _symbol(y, real=True) + t1 = (x - self.center.x)**2 + t2 = (y - self.center.y)**2 + return t1 + t2 - self.major**2 + + def intersection(self, o): + """The intersection of this circle with another geometrical entity. + + Parameters + ========== + + o : GeometryEntity + + Returns + ======= + + intersection : list of GeometryEntities + + Examples + ======== + + >>> from sympy import Point, Circle, Line, Ray + >>> p1, p2, p3 = Point(0, 0), Point(5, 5), Point(6, 0) + >>> p4 = Point(5, 0) + >>> c1 = Circle(p1, 5) + >>> c1.intersection(p2) + [] + >>> c1.intersection(p4) + [Point2D(5, 0)] + >>> c1.intersection(Ray(p1, p2)) + [Point2D(5*sqrt(2)/2, 5*sqrt(2)/2)] + >>> c1.intersection(Line(p2, p3)) + [] + + """ + return Ellipse.intersection(self, o) + + @property + def radius(self): + """The radius of the circle. + + Returns + ======= + + radius : number or SymPy expression + + See Also + ======== + + Ellipse.major, Ellipse.minor, Ellipse.hradius, Ellipse.vradius + + Examples + ======== + + >>> from sympy import Point, Circle + >>> c1 = Circle(Point(3, 4), 6) + >>> c1.radius + 6 + + """ + return self.args[1] + + def reflect(self, line): + """Override GeometryEntity.reflect since the radius + is not a GeometryEntity. + + Examples + ======== + + >>> from sympy import Circle, Line + >>> Circle((0, 1), 1).reflect(Line((0, 0), (1, 1))) + Circle(Point2D(1, 0), -1) + """ + c = self.center + c = c.reflect(line) + return self.func(c, -self.radius) + + def scale(self, x=1, y=1, pt=None): + """Override GeometryEntity.scale since the radius + is not a GeometryEntity. + + Examples + ======== + + >>> from sympy import Circle + >>> Circle((0, 0), 1).scale(2, 2) + Circle(Point2D(0, 0), 2) + >>> Circle((0, 0), 1).scale(2, 4) + Ellipse(Point2D(0, 0), 2, 4) + """ + c = self.center + if pt: + pt = Point(pt, dim=2) + return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) + c = c.scale(x, y) + x, y = [abs(i) for i in (x, y)] + if x == y: + return self.func(c, x*self.radius) + h = v = self.radius + return Ellipse(c, hradius=h*x, vradius=v*y) + + @property + def vradius(self): + """ + This Ellipse property is an alias for the Circle's radius. + + Whereas hradius, major and minor can use Ellipse's conventions, + the vradius does not exist for a circle. It is always a positive + value in order that the Circle, like Polygons, will have an + area that can be positive or negative as determined by the sign + of the hradius. + + Examples + ======== + + >>> from sympy import Point, Circle + >>> c1 = Circle(Point(3, 4), 6) + >>> c1.vradius + 6 + """ + return abs(self.radius) + + +from .polygon import Polygon, Triangle diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/entity.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/entity.py new file mode 100644 index 0000000000000000000000000000000000000000..5ea1e807542c43eb955c2d778cec0f101d78bdce --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/entity.py @@ -0,0 +1,641 @@ +"""The definition of the base geometrical entity with attributes common to +all derived geometrical entities. + +Contains +======== + +GeometryEntity +GeometricSet + +Notes +===== + +A GeometryEntity is any object that has special geometric properties. +A GeometrySet is a superclass of any GeometryEntity that can also +be viewed as a sympy.sets.Set. In particular, points are the only +GeometryEntity not considered a Set. + +Rn is a GeometrySet representing n-dimensional Euclidean space. R2 and +R3 are currently the only ambient spaces implemented. + +""" +from __future__ import annotations + +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.evalf import EvalfMixin, N +from sympy.core.numbers import oo +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import cos, sin, atan +from sympy.matrices import eye +from sympy.multipledispatch import dispatch +from sympy.printing import sstr +from sympy.sets import Set, Union, FiniteSet +from sympy.sets.handlers.intersection import intersection_sets +from sympy.sets.handlers.union import union_sets +from sympy.solvers.solvers import solve +from sympy.utilities.misc import func_name +from sympy.utilities.iterables import is_sequence + + +# How entities are ordered; used by __cmp__ in GeometryEntity +ordering_of_classes = [ + "Point2D", + "Point3D", + "Point", + "Segment2D", + "Ray2D", + "Line2D", + "Segment3D", + "Line3D", + "Ray3D", + "Segment", + "Ray", + "Line", + "Plane", + "Triangle", + "RegularPolygon", + "Polygon", + "Circle", + "Ellipse", + "Curve", + "Parabola" +] + + +x, y = [Dummy('entity_dummy') for i in range(2)] +T = Dummy('entity_dummy', real=True) + + +class GeometryEntity(Basic, EvalfMixin): + """The base class for all geometrical entities. + + This class does not represent any particular geometric entity, it only + provides the implementation of some methods common to all subclasses. + + """ + + __slots__: tuple[str, ...] = () + + def __cmp__(self, other): + """Comparison of two GeometryEntities.""" + n1 = self.__class__.__name__ + n2 = other.__class__.__name__ + c = (n1 > n2) - (n1 < n2) + if not c: + return 0 + + i1 = -1 + for cls in self.__class__.__mro__: + try: + i1 = ordering_of_classes.index(cls.__name__) + break + except ValueError: + i1 = -1 + if i1 == -1: + return c + + i2 = -1 + for cls in other.__class__.__mro__: + try: + i2 = ordering_of_classes.index(cls.__name__) + break + except ValueError: + i2 = -1 + if i2 == -1: + return c + + return (i1 > i2) - (i1 < i2) + + def __contains__(self, other): + """Subclasses should implement this method for anything more complex than equality.""" + if type(self) is type(other): + return self == other + raise NotImplementedError() + + def __getnewargs__(self): + """Returns a tuple that will be passed to __new__ on unpickling.""" + return tuple(self.args) + + def __ne__(self, o): + """Test inequality of two geometrical entities.""" + return not self == o + + def __new__(cls, *args, **kwargs): + # Points are sequences, but they should not + # be converted to Tuples, so use this detection function instead. + def is_seq_and_not_point(a): + # we cannot use isinstance(a, Point) since we cannot import Point + if hasattr(a, 'is_Point') and a.is_Point: + return False + return is_sequence(a) + + args = [Tuple(*a) if is_seq_and_not_point(a) else sympify(a) for a in args] + return Basic.__new__(cls, *args) + + def __radd__(self, a): + """Implementation of reverse add method.""" + return a.__add__(self) + + def __rtruediv__(self, a): + """Implementation of reverse division method.""" + return a.__truediv__(self) + + def __repr__(self): + """String representation of a GeometryEntity that can be evaluated + by sympy.""" + return type(self).__name__ + repr(self.args) + + def __rmul__(self, a): + """Implementation of reverse multiplication method.""" + return a.__mul__(self) + + def __rsub__(self, a): + """Implementation of reverse subtraction method.""" + return a.__sub__(self) + + def __str__(self): + """String representation of a GeometryEntity.""" + return type(self).__name__ + sstr(self.args) + + def _eval_subs(self, old, new): + from sympy.geometry.point import Point, Point3D + if is_sequence(old) or is_sequence(new): + if isinstance(self, Point3D): + old = Point3D(old) + new = Point3D(new) + else: + old = Point(old) + new = Point(new) + return self._subs(old, new) + + def _repr_svg_(self): + """SVG representation of a GeometryEntity suitable for IPython""" + + try: + bounds = self.bounds + except (NotImplementedError, TypeError): + # if we have no SVG representation, return None so IPython + # will fall back to the next representation + return None + + if not all(x.is_number and x.is_finite for x in bounds): + return None + + svg_top = ''' + + + + + + + + + + + ''' + + # Establish SVG canvas that will fit all the data + small space + xmin, ymin, xmax, ymax = map(N, bounds) + if xmin == xmax and ymin == ymax: + # This is a point; buffer using an arbitrary size + xmin, ymin, xmax, ymax = xmin - .5, ymin -.5, xmax + .5, ymax + .5 + else: + # Expand bounds by a fraction of the data ranges + expand = 0.1 # or 10%; this keeps arrowheads in view (R plots use 4%) + widest_part = max([xmax - xmin, ymax - ymin]) + expand_amount = widest_part * expand + xmin -= expand_amount + ymin -= expand_amount + xmax += expand_amount + ymax += expand_amount + dx = xmax - xmin + dy = ymax - ymin + width = min([max([100., dx]), 300]) + height = min([max([100., dy]), 300]) + + scale_factor = 1. if max(width, height) == 0 else max(dx, dy) / max(width, height) + try: + svg = self._svg(scale_factor) + except (NotImplementedError, TypeError): + # if we have no SVG representation, return None so IPython + # will fall back to the next representation + return None + + view_box = "{} {} {} {}".format(xmin, ymin, dx, dy) + transform = "matrix(1,0,0,-1,0,{})".format(ymax + ymin) + svg_top = svg_top.format(view_box, width, height) + + return svg_top + ( + '{}' + ).format(transform, svg) + + def _svg(self, scale_factor=1., fill_color="#66cc99"): + """Returns SVG path element for the GeometryEntity. + + Parameters + ========== + + scale_factor : float + Multiplication factor for the SVG stroke-width. Default is 1. + fill_color : str, optional + Hex string for fill color. Default is "#66cc99". + """ + raise NotImplementedError() + + def _sympy_(self): + return self + + @property + def ambient_dimension(self): + """What is the dimension of the space that the object is contained in?""" + raise NotImplementedError() + + @property + def bounds(self): + """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding + rectangle for the geometric figure. + + """ + + raise NotImplementedError() + + def encloses(self, o): + """ + Return True if o is inside (not on or outside) the boundaries of self. + + The object will be decomposed into Points and individual Entities need + only define an encloses_point method for their class. + + See Also + ======== + + sympy.geometry.ellipse.Ellipse.encloses_point + sympy.geometry.polygon.Polygon.encloses_point + + Examples + ======== + + >>> from sympy import RegularPolygon, Point, Polygon + >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices) + >>> t2 = Polygon(*RegularPolygon(Point(0, 0), 2, 3).vertices) + >>> t2.encloses(t) + True + >>> t.encloses(t2) + False + + """ + + from sympy.geometry.point import Point + from sympy.geometry.line import Segment, Ray, Line + from sympy.geometry.ellipse import Ellipse + from sympy.geometry.polygon import Polygon, RegularPolygon + + if isinstance(o, Point): + return self.encloses_point(o) + elif isinstance(o, Segment): + return all(self.encloses_point(x) for x in o.points) + elif isinstance(o, (Ray, Line)): + return False + elif isinstance(o, Ellipse): + return self.encloses_point(o.center) and \ + self.encloses_point( + Point(o.center.x + o.hradius, o.center.y)) and \ + not self.intersection(o) + elif isinstance(o, Polygon): + if isinstance(o, RegularPolygon): + if not self.encloses_point(o.center): + return False + return all(self.encloses_point(v) for v in o.vertices) + raise NotImplementedError() + + def equals(self, o): + return self == o + + def intersection(self, o): + """ + Returns a list of all of the intersections of self with o. + + Notes + ===== + + An entity is not required to implement this method. + + If two different types of entities can intersect, the item with + higher index in ordering_of_classes should implement + intersections with anything having a lower index. + + See Also + ======== + + sympy.geometry.util.intersection + + """ + raise NotImplementedError() + + def is_similar(self, other): + """Is this geometrical entity similar to another geometrical entity? + + Two entities are similar if a uniform scaling (enlarging or + shrinking) of one of the entities will allow one to obtain the other. + + Notes + ===== + + This method is not intended to be used directly but rather + through the `are_similar` function found in util.py. + An entity is not required to implement this method. + If two different types of entities can be similar, it is only + required that one of them be able to determine this. + + See Also + ======== + + scale + + """ + raise NotImplementedError() + + def reflect(self, line): + """ + Reflects an object across a line. + + Parameters + ========== + + line: Line + + Examples + ======== + + >>> from sympy import pi, sqrt, Line, RegularPolygon + >>> l = Line((0, pi), slope=sqrt(2)) + >>> pent = RegularPolygon((1, 2), 1, 5) + >>> rpent = pent.reflect(l) + >>> rpent + RegularPolygon(Point2D(-2*sqrt(2)*pi/3 - 1/3 + 4*sqrt(2)/3, 2/3 + 2*sqrt(2)/3 + 2*pi/3), -1, 5, -atan(2*sqrt(2)) + 3*pi/5) + + >>> from sympy import pi, Line, Circle, Point + >>> l = Line((0, pi), slope=1) + >>> circ = Circle(Point(0, 0), 5) + >>> rcirc = circ.reflect(l) + >>> rcirc + Circle(Point2D(-pi, pi), -5) + + """ + from sympy.geometry.point import Point + + g = self + l = line + o = Point(0, 0) + if l.slope.is_zero: + v = l.args[0].y + if not v: # x-axis + return g.scale(y=-1) + reps = [(p, p.translate(y=2*(v - p.y))) for p in g.atoms(Point)] + elif l.slope is oo: + v = l.args[0].x + if not v: # y-axis + return g.scale(x=-1) + reps = [(p, p.translate(x=2*(v - p.x))) for p in g.atoms(Point)] + else: + if not hasattr(g, 'reflect') and not all( + isinstance(arg, Point) for arg in g.args): + raise NotImplementedError( + 'reflect undefined or non-Point args in %s' % g) + a = atan(l.slope) + c = l.coefficients + d = -c[-1]/c[1] # y-intercept + # apply the transform to a single point + xf = Point(x, y) + xf = xf.translate(y=-d).rotate(-a, o).scale(y=-1 + ).rotate(a, o).translate(y=d) + # replace every point using that transform + reps = [(p, xf.xreplace({x: p.x, y: p.y})) for p in g.atoms(Point)] + return g.xreplace(dict(reps)) + + def rotate(self, angle, pt=None): + """Rotate ``angle`` radians counterclockwise about Point ``pt``. + + The default pt is the origin, Point(0, 0) + + See Also + ======== + + scale, translate + + Examples + ======== + + >>> from sympy import Point, RegularPolygon, Polygon, pi + >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices) + >>> t # vertex on x axis + Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2)) + >>> t.rotate(pi/2) # vertex on y axis now + Triangle(Point2D(0, 1), Point2D(-sqrt(3)/2, -1/2), Point2D(sqrt(3)/2, -1/2)) + + """ + newargs = [] + for a in self.args: + if isinstance(a, GeometryEntity): + newargs.append(a.rotate(angle, pt)) + else: + newargs.append(a) + return type(self)(*newargs) + + def scale(self, x=1, y=1, pt=None): + """Scale the object by multiplying the x,y-coordinates by x and y. + + If pt is given, the scaling is done relative to that point; the + object is shifted by -pt, scaled, and shifted by pt. + + See Also + ======== + + rotate, translate + + Examples + ======== + + >>> from sympy import RegularPolygon, Point, Polygon + >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices) + >>> t + Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2)) + >>> t.scale(2) + Triangle(Point2D(2, 0), Point2D(-1, sqrt(3)/2), Point2D(-1, -sqrt(3)/2)) + >>> t.scale(2, 2) + Triangle(Point2D(2, 0), Point2D(-1, sqrt(3)), Point2D(-1, -sqrt(3))) + + """ + from sympy.geometry.point import Point + if pt: + pt = Point(pt, dim=2) + return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) + return type(self)(*[a.scale(x, y) for a in self.args]) # if this fails, override this class + + def translate(self, x=0, y=0): + """Shift the object by adding to the x,y-coordinates the values x and y. + + See Also + ======== + + rotate, scale + + Examples + ======== + + >>> from sympy import RegularPolygon, Point, Polygon + >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices) + >>> t + Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2)) + >>> t.translate(2) + Triangle(Point2D(3, 0), Point2D(3/2, sqrt(3)/2), Point2D(3/2, -sqrt(3)/2)) + >>> t.translate(2, 2) + Triangle(Point2D(3, 2), Point2D(3/2, sqrt(3)/2 + 2), Point2D(3/2, 2 - sqrt(3)/2)) + + """ + newargs = [] + for a in self.args: + if isinstance(a, GeometryEntity): + newargs.append(a.translate(x, y)) + else: + newargs.append(a) + return self.func(*newargs) + + def parameter_value(self, other, t): + """Return the parameter corresponding to the given point. + Evaluating an arbitrary point of the entity at this parameter + value will return the given point. + + Examples + ======== + + >>> from sympy import Line, Point + >>> from sympy.abc import t + >>> a = Point(0, 0) + >>> b = Point(2, 2) + >>> Line(a, b).parameter_value((1, 1), t) + {t: 1/2} + >>> Line(a, b).arbitrary_point(t).subs(_) + Point2D(1, 1) + """ + from sympy.geometry.point import Point + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if not isinstance(other, Point): + raise ValueError("other must be a point") + sol = solve(self.arbitrary_point(T) - other, T, dict=True) + if not sol: + raise ValueError("Given point is not on %s" % func_name(self)) + return {t: sol[0][T]} + + +class GeometrySet(GeometryEntity, Set): + """Parent class of all GeometryEntity that are also Sets + (compatible with sympy.sets) + """ + __slots__ = () + + def _contains(self, other): + """sympy.sets uses the _contains method, so include it for compatibility.""" + + if isinstance(other, Set) and other.is_FiniteSet: + return all(self.__contains__(i) for i in other) + + return self.__contains__(other) + +@dispatch(GeometrySet, Set) # type:ignore # noqa:F811 +def union_sets(self, o): # noqa:F811 + """ Returns the union of self and o + for use with sympy.sets.Set, if possible. """ + + + # if its a FiniteSet, merge any points + # we contain and return a union with the rest + if o.is_FiniteSet: + other_points = [p for p in o if not self._contains(p)] + if len(other_points) == len(o): + return None + return Union(self, FiniteSet(*other_points)) + if self._contains(o): + return self + return None + + +@dispatch(GeometrySet, Set) # type: ignore # noqa:F811 +def intersection_sets(self, o): # noqa:F811 + """ Returns a sympy.sets.Set of intersection objects, + if possible. """ + + from sympy.geometry.point import Point + + try: + # if o is a FiniteSet, find the intersection directly + # to avoid infinite recursion + if o.is_FiniteSet: + inter = FiniteSet(*(p for p in o if self.contains(p))) + else: + inter = self.intersection(o) + except NotImplementedError: + # sympy.sets.Set.reduce expects None if an object + # doesn't know how to simplify + return None + + # put the points in a FiniteSet + points = FiniteSet(*[p for p in inter if isinstance(p, Point)]) + non_points = [p for p in inter if not isinstance(p, Point)] + + return Union(*(non_points + [points])) + +def translate(x, y): + """Return the matrix to translate a 2-D point by x and y.""" + rv = eye(3) + rv[2, 0] = x + rv[2, 1] = y + return rv + + +def scale(x, y, pt=None): + """Return the matrix to multiply a 2-D point's coordinates by x and y. + + If pt is given, the scaling is done relative to that point.""" + rv = eye(3) + rv[0, 0] = x + rv[1, 1] = y + if pt: + from sympy.geometry.point import Point + pt = Point(pt, dim=2) + tr1 = translate(*(-pt).args) + tr2 = translate(*pt.args) + return tr1*rv*tr2 + return rv + + +def rotate(th): + """Return the matrix to rotate a 2-D point about the origin by ``angle``. + + The angle is measured in radians. To Point a point about a point other + then the origin, translate the Point, do the rotation, and + translate it back: + + >>> from sympy.geometry.entity import rotate, translate + >>> from sympy import Point, pi + >>> rot_about_11 = translate(-1, -1)*rotate(pi/2)*translate(1, 1) + >>> Point(1, 1).transform(rot_about_11) + Point2D(1, 1) + >>> Point(0, 0).transform(rot_about_11) + Point2D(2, 0) + """ + s = sin(th) + rv = eye(3)*cos(th) + rv[0, 1] = s + rv[1, 0] = -s + rv[2, 2] = 1 + return rv diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/exceptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..41d97af718de2cebad3accefcd60e43ccf74a3f6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/exceptions.py @@ -0,0 +1,5 @@ +"""Geometry Errors.""" + +class GeometryError(ValueError): + """An exception raised by classes in the geometry module.""" + pass diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/line.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/line.py new file mode 100644 index 0000000000000000000000000000000000000000..ed73d43d0c9581f9d51f299cf4425acb11958e57 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/line.py @@ -0,0 +1,2877 @@ +"""Line-like geometrical entities. + +Contains +======== +LinearEntity +Line +Ray +Segment +LinearEntity2D +Line2D +Ray2D +Segment2D +LinearEntity3D +Line3D +Ray3D +Segment3D + +""" + +from sympy.core.containers import Tuple +from sympy.core.evalf import N +from sympy.core.expr import Expr +from sympy.core.numbers import Rational, oo, Float +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.sorting import ordered +from sympy.core.symbol import _symbol, Dummy, uniquely_named_symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (_pi_coeff, acos, tan, atan2) +from .entity import GeometryEntity, GeometrySet +from .exceptions import GeometryError +from .point import Point, Point3D +from .util import find, intersection +from sympy.logic.boolalg import And +from sympy.matrices import Matrix +from sympy.sets.sets import Intersection +from sympy.simplify.simplify import simplify +from sympy.solvers.solvers import solve +from sympy.solvers.solveset import linear_coeffs +from sympy.utilities.misc import Undecidable, filldedent + + +import random + + +t, u = [Dummy('line_dummy') for i in range(2)] + + +class LinearEntity(GeometrySet): + """A base class for all linear entities (Line, Ray and Segment) + in n-dimensional Euclidean space. + + Attributes + ========== + + ambient_dimension + direction + length + p1 + p2 + points + + Notes + ===== + + This is an abstract class and is not meant to be instantiated. + + See Also + ======== + + sympy.geometry.entity.GeometryEntity + + """ + def __new__(cls, p1, p2=None, **kwargs): + p1, p2 = Point._normalize_dimension(p1, p2) + if p1 == p2: + # sometimes we return a single point if we are not given two unique + # points. This is done in the specific subclass + raise ValueError( + "%s.__new__ requires two unique Points." % cls.__name__) + if len(p1) != len(p2): + raise ValueError( + "%s.__new__ requires two Points of equal dimension." % cls.__name__) + + return GeometryEntity.__new__(cls, p1, p2, **kwargs) + + def __contains__(self, other): + """Return a definitive answer or else raise an error if it cannot + be determined that other is on the boundaries of self.""" + result = self.contains(other) + + if result is not None: + return result + else: + raise Undecidable( + "Cannot decide whether '%s' contains '%s'" % (self, other)) + + def _span_test(self, other): + """Test whether the point `other` lies in the positive span of `self`. + A point x is 'in front' of a point y if x.dot(y) >= 0. Return + -1 if `other` is behind `self.p1`, 0 if `other` is `self.p1` and + and 1 if `other` is in front of `self.p1`.""" + if self.p1 == other: + return 0 + + rel_pos = other - self.p1 + d = self.direction + if d.dot(rel_pos) > 0: + return 1 + return -1 + + @property + def ambient_dimension(self): + """A property method that returns the dimension of LinearEntity + object. + + Parameters + ========== + + p1 : LinearEntity + + Returns + ======= + + dimension : integer + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(1, 1) + >>> l1 = Line(p1, p2) + >>> l1.ambient_dimension + 2 + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0, 0), Point(1, 1, 1) + >>> l1 = Line(p1, p2) + >>> l1.ambient_dimension + 3 + + """ + return len(self.p1) + + def angle_between(l1, l2): + """Return the non-reflex angle formed by rays emanating from + the origin with directions the same as the direction vectors + of the linear entities. + + Parameters + ========== + + l1 : LinearEntity + l2 : LinearEntity + + Returns + ======= + + angle : angle in radians + + Notes + ===== + + From the dot product of vectors v1 and v2 it is known that: + + ``dot(v1, v2) = |v1|*|v2|*cos(A)`` + + where A is the angle formed between the two vectors. We can + get the directional vectors of the two lines and readily + find the angle between the two using the above formula. + + See Also + ======== + + is_perpendicular, Ray2D.closing_angle + + Examples + ======== + + >>> from sympy import Line + >>> e = Line((0, 0), (1, 0)) + >>> ne = Line((0, 0), (1, 1)) + >>> sw = Line((1, 1), (0, 0)) + >>> ne.angle_between(e) + pi/4 + >>> sw.angle_between(e) + 3*pi/4 + + To obtain the non-obtuse angle at the intersection of lines, use + the ``smallest_angle_between`` method: + + >>> sw.smallest_angle_between(e) + pi/4 + + >>> from sympy import Point3D, Line3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(-1, 2, 0) + >>> l1, l2 = Line3D(p1, p2), Line3D(p2, p3) + >>> l1.angle_between(l2) + acos(-sqrt(2)/3) + >>> l1.smallest_angle_between(l2) + acos(sqrt(2)/3) + """ + if not isinstance(l1, LinearEntity) and not isinstance(l2, LinearEntity): + raise TypeError('Must pass only LinearEntity objects') + + v1, v2 = l1.direction, l2.direction + return acos(v1.dot(v2)/(abs(v1)*abs(v2))) + + def smallest_angle_between(l1, l2): + """Return the smallest angle formed at the intersection of the + lines containing the linear entities. + + Parameters + ========== + + l1 : LinearEntity + l2 : LinearEntity + + Returns + ======= + + angle : angle in radians + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2, p3 = Point(0, 0), Point(0, 4), Point(2, -2) + >>> l1, l2 = Line(p1, p2), Line(p1, p3) + >>> l1.smallest_angle_between(l2) + pi/4 + + See Also + ======== + + angle_between, is_perpendicular, Ray2D.closing_angle + """ + if not isinstance(l1, LinearEntity) and not isinstance(l2, LinearEntity): + raise TypeError('Must pass only LinearEntity objects') + + v1, v2 = l1.direction, l2.direction + return acos(abs(v1.dot(v2))/(abs(v1)*abs(v2))) + + def arbitrary_point(self, parameter='t'): + """A parameterized point on the Line. + + Parameters + ========== + + parameter : str, optional + The name of the parameter which will be used for the parametric + point. The default value is 't'. When this parameter is 0, the + first point used to define the line will be returned, and when + it is 1 the second point will be returned. + + Returns + ======= + + point : Point + + Raises + ====== + + ValueError + When ``parameter`` already appears in the Line's definition. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(1, 0), Point(5, 3) + >>> l1 = Line(p1, p2) + >>> l1.arbitrary_point() + Point2D(4*t + 1, 3*t) + >>> from sympy import Point3D, Line3D + >>> p1, p2 = Point3D(1, 0, 0), Point3D(5, 3, 1) + >>> l1 = Line3D(p1, p2) + >>> l1.arbitrary_point() + Point3D(4*t + 1, 3*t, t) + + """ + t = _symbol(parameter, real=True) + if t.name in (f.name for f in self.free_symbols): + raise ValueError(filldedent(''' + Symbol %s already appears in object + and cannot be used as a parameter. + ''' % t.name)) + # multiply on the right so the variable gets + # combined with the coordinates of the point + return self.p1 + (self.p2 - self.p1)*t + + @staticmethod + def are_concurrent(*lines): + """Is a sequence of linear entities concurrent? + + Two or more linear entities are concurrent if they all + intersect at a single point. + + Parameters + ========== + + lines + A sequence of linear entities. + + Returns + ======= + + True : if the set of linear entities intersect in one point + False : otherwise. + + See Also + ======== + + sympy.geometry.util.intersection + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(3, 5) + >>> p3, p4 = Point(-2, -2), Point(0, 2) + >>> l1, l2, l3 = Line(p1, p2), Line(p1, p3), Line(p1, p4) + >>> Line.are_concurrent(l1, l2, l3) + True + >>> l4 = Line(p2, p3) + >>> Line.are_concurrent(l2, l3, l4) + False + >>> from sympy import Point3D, Line3D + >>> p1, p2 = Point3D(0, 0, 0), Point3D(3, 5, 2) + >>> p3, p4 = Point3D(-2, -2, -2), Point3D(0, 2, 1) + >>> l1, l2, l3 = Line3D(p1, p2), Line3D(p1, p3), Line3D(p1, p4) + >>> Line3D.are_concurrent(l1, l2, l3) + True + >>> l4 = Line3D(p2, p3) + >>> Line3D.are_concurrent(l2, l3, l4) + False + + """ + common_points = Intersection(*lines) + if common_points.is_FiniteSet and len(common_points) == 1: + return True + return False + + def contains(self, other): + """Subclasses should implement this method and should return + True if other is on the boundaries of self; + False if not on the boundaries of self; + None if a determination cannot be made.""" + raise NotImplementedError() + + @property + def direction(self): + """The direction vector of the LinearEntity. + + Returns + ======= + + p : a Point; the ray from the origin to this point is the + direction of `self` + + Examples + ======== + + >>> from sympy import Line + >>> a, b = (1, 1), (1, 3) + >>> Line(a, b).direction + Point2D(0, 2) + >>> Line(b, a).direction + Point2D(0, -2) + + This can be reported so the distance from the origin is 1: + + >>> Line(b, a).direction.unit + Point2D(0, -1) + + See Also + ======== + + sympy.geometry.point.Point.unit + + """ + return self.p2 - self.p1 + + def intersection(self, other): + """The intersection with another geometrical entity. + + Parameters + ========== + + o : Point or LinearEntity + + Returns + ======= + + intersection : list of geometrical entities + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Line, Segment + >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(7, 7) + >>> l1 = Line(p1, p2) + >>> l1.intersection(p3) + [Point2D(7, 7)] + >>> p4, p5 = Point(5, 0), Point(0, 3) + >>> l2 = Line(p4, p5) + >>> l1.intersection(l2) + [Point2D(15/8, 15/8)] + >>> p6, p7 = Point(0, 5), Point(2, 6) + >>> s1 = Segment(p6, p7) + >>> l1.intersection(s1) + [] + >>> from sympy import Point3D, Line3D, Segment3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(7, 7, 7) + >>> l1 = Line3D(p1, p2) + >>> l1.intersection(p3) + [Point3D(7, 7, 7)] + >>> l1 = Line3D(Point3D(4,19,12), Point3D(5,25,17)) + >>> l2 = Line3D(Point3D(-3, -15, -19), direction_ratio=[2,8,8]) + >>> l1.intersection(l2) + [Point3D(1, 1, -3)] + >>> p6, p7 = Point3D(0, 5, 2), Point3D(2, 6, 3) + >>> s1 = Segment3D(p6, p7) + >>> l1.intersection(s1) + [] + + """ + def intersect_parallel_rays(ray1, ray2): + if ray1.direction.dot(ray2.direction) > 0: + # rays point in the same direction + # so return the one that is "in front" + return [ray2] if ray1._span_test(ray2.p1) >= 0 else [ray1] + else: + # rays point in opposite directions + st = ray1._span_test(ray2.p1) + if st < 0: + return [] + elif st == 0: + return [ray2.p1] + return [Segment(ray1.p1, ray2.p1)] + + def intersect_parallel_ray_and_segment(ray, seg): + st1, st2 = ray._span_test(seg.p1), ray._span_test(seg.p2) + if st1 < 0 and st2 < 0: + return [] + elif st1 >= 0 and st2 >= 0: + return [seg] + elif st1 >= 0: # st2 < 0: + return [Segment(ray.p1, seg.p1)] + else: # st1 < 0 and st2 >= 0: + return [Segment(ray.p1, seg.p2)] + + def intersect_parallel_segments(seg1, seg2): + if seg1.contains(seg2): + return [seg2] + if seg2.contains(seg1): + return [seg1] + + # direct the segments so they're oriented the same way + if seg1.direction.dot(seg2.direction) < 0: + seg2 = Segment(seg2.p2, seg2.p1) + # order the segments so seg1 is "behind" seg2 + if seg1._span_test(seg2.p1) < 0: + seg1, seg2 = seg2, seg1 + if seg2._span_test(seg1.p2) < 0: + return [] + return [Segment(seg2.p1, seg1.p2)] + + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if other.is_Point: + if self.contains(other): + return [other] + else: + return [] + elif isinstance(other, LinearEntity): + # break into cases based on whether + # the lines are parallel, non-parallel intersecting, or skew + pts = Point._normalize_dimension(self.p1, self.p2, other.p1, other.p2) + rank = Point.affine_rank(*pts) + + if rank == 1: + # we're collinear + if isinstance(self, Line): + return [other] + if isinstance(other, Line): + return [self] + + if isinstance(self, Ray) and isinstance(other, Ray): + return intersect_parallel_rays(self, other) + if isinstance(self, Ray) and isinstance(other, Segment): + return intersect_parallel_ray_and_segment(self, other) + if isinstance(self, Segment) and isinstance(other, Ray): + return intersect_parallel_ray_and_segment(other, self) + if isinstance(self, Segment) and isinstance(other, Segment): + return intersect_parallel_segments(self, other) + elif rank == 2: + # we're in the same plane + l1 = Line(*pts[:2]) + l2 = Line(*pts[2:]) + + # check to see if we're parallel. If we are, we can't + # be intersecting, since the collinear case was already + # handled + if l1.direction.is_scalar_multiple(l2.direction): + return [] + + # find the intersection as if everything were lines + # by solving the equation t*d + p1 == s*d' + p1' + m = Matrix([l1.direction, -l2.direction]).transpose() + v = Matrix([l2.p1 - l1.p1]).transpose() + + # we cannot use m.solve(v) because that only works for square matrices + m_rref, pivots = m.col_insert(2, v).rref(simplify=True) + # rank == 2 ensures we have 2 pivots, but let's check anyway + if len(pivots) != 2: + raise GeometryError("Failed when solving Mx=b when M={} and b={}".format(m, v)) + coeff = m_rref[0, 2] + line_intersection = l1.direction*coeff + self.p1 + + # if both are lines, skip a containment check + if isinstance(self, Line) and isinstance(other, Line): + return [line_intersection] + + if ((isinstance(self, Line) or + self.contains(line_intersection)) and + other.contains(line_intersection)): + return [line_intersection] + if not self.atoms(Float) and not other.atoms(Float): + # if it can fail when there are no Floats then + # maybe the following parametric check should be + # done + return [] + # floats may fail exact containment so check that the + # arbitrary points, when equal, both give a + # non-negative parameter when the arbitrary point + # coordinates are equated + tu = solve(self.arbitrary_point(t) - other.arbitrary_point(u), + t, u, dict=True)[0] + def ok(p, l): + if isinstance(l, Line): + # p > -oo + return True + if isinstance(l, Ray): + # p >= 0 + return p.is_nonnegative + if isinstance(l, Segment): + # 0 <= p <= 1 + return p.is_nonnegative and (1 - p).is_nonnegative + raise ValueError("unexpected line type") + if ok(tu[t], self) and ok(tu[u], other): + return [line_intersection] + return [] + else: + # we're skew + return [] + + return other.intersection(self) + + def is_parallel(l1, l2): + """Are two linear entities parallel? + + Parameters + ========== + + l1 : LinearEntity + l2 : LinearEntity + + Returns + ======= + + True : if l1 and l2 are parallel, + False : otherwise. + + See Also + ======== + + coefficients + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(1, 1) + >>> p3, p4 = Point(3, 4), Point(6, 7) + >>> l1, l2 = Line(p1, p2), Line(p3, p4) + >>> Line.is_parallel(l1, l2) + True + >>> p5 = Point(6, 6) + >>> l3 = Line(p3, p5) + >>> Line.is_parallel(l1, l3) + False + >>> from sympy import Point3D, Line3D + >>> p1, p2 = Point3D(0, 0, 0), Point3D(3, 4, 5) + >>> p3, p4 = Point3D(2, 1, 1), Point3D(8, 9, 11) + >>> l1, l2 = Line3D(p1, p2), Line3D(p3, p4) + >>> Line3D.is_parallel(l1, l2) + True + >>> p5 = Point3D(6, 6, 6) + >>> l3 = Line3D(p3, p5) + >>> Line3D.is_parallel(l1, l3) + False + + """ + if not isinstance(l1, LinearEntity) and not isinstance(l2, LinearEntity): + raise TypeError('Must pass only LinearEntity objects') + + return l1.direction.is_scalar_multiple(l2.direction) + + def is_perpendicular(l1, l2): + """Are two linear entities perpendicular? + + Parameters + ========== + + l1 : LinearEntity + l2 : LinearEntity + + Returns + ======= + + True : if l1 and l2 are perpendicular, + False : otherwise. + + See Also + ======== + + coefficients + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(-1, 1) + >>> l1, l2 = Line(p1, p2), Line(p1, p3) + >>> l1.is_perpendicular(l2) + True + >>> p4 = Point(5, 3) + >>> l3 = Line(p1, p4) + >>> l1.is_perpendicular(l3) + False + >>> from sympy import Point3D, Line3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(-1, 2, 0) + >>> l1, l2 = Line3D(p1, p2), Line3D(p2, p3) + >>> l1.is_perpendicular(l2) + False + >>> p4 = Point3D(5, 3, 7) + >>> l3 = Line3D(p1, p4) + >>> l1.is_perpendicular(l3) + False + + """ + if not isinstance(l1, LinearEntity) and not isinstance(l2, LinearEntity): + raise TypeError('Must pass only LinearEntity objects') + + return S.Zero.equals(l1.direction.dot(l2.direction)) + + def is_similar(self, other): + """ + Return True if self and other are contained in the same line. + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2, p3 = Point(0, 1), Point(3, 4), Point(2, 3) + >>> l1 = Line(p1, p2) + >>> l2 = Line(p1, p3) + >>> l1.is_similar(l2) + True + """ + l = Line(self.p1, self.p2) + return l.contains(other) + + @property + def length(self): + """ + The length of the line. + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(3, 5) + >>> l1 = Line(p1, p2) + >>> l1.length + oo + """ + return S.Infinity + + @property + def p1(self): + """The first defining point of a linear entity. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(5, 3) + >>> l = Line(p1, p2) + >>> l.p1 + Point2D(0, 0) + + """ + return self.args[0] + + @property + def p2(self): + """The second defining point of a linear entity. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(5, 3) + >>> l = Line(p1, p2) + >>> l.p2 + Point2D(5, 3) + + """ + return self.args[1] + + def parallel_line(self, p): + """Create a new Line parallel to this linear entity which passes + through the point `p`. + + Parameters + ========== + + p : Point + + Returns + ======= + + line : Line + + See Also + ======== + + is_parallel + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2, p3 = Point(0, 0), Point(2, 3), Point(-2, 2) + >>> l1 = Line(p1, p2) + >>> l2 = l1.parallel_line(p3) + >>> p3 in l2 + True + >>> l1.is_parallel(l2) + True + >>> from sympy import Point3D, Line3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(2, 3, 4), Point3D(-2, 2, 0) + >>> l1 = Line3D(p1, p2) + >>> l2 = l1.parallel_line(p3) + >>> p3 in l2 + True + >>> l1.is_parallel(l2) + True + + """ + p = Point(p, dim=self.ambient_dimension) + return Line(p, p + self.direction) + + def perpendicular_line(self, p): + """Create a new Line perpendicular to this linear entity which passes + through the point `p`. + + Parameters + ========== + + p : Point + + Returns + ======= + + line : Line + + See Also + ======== + + sympy.geometry.line.LinearEntity.is_perpendicular, perpendicular_segment + + Examples + ======== + + >>> from sympy import Point3D, Line3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(2, 3, 4), Point3D(-2, 2, 0) + >>> L = Line3D(p1, p2) + >>> P = L.perpendicular_line(p3); P + Line3D(Point3D(-2, 2, 0), Point3D(4/29, 6/29, 8/29)) + >>> L.is_perpendicular(P) + True + + In 3D the, the first point used to define the line is the point + through which the perpendicular was required to pass; the + second point is (arbitrarily) contained in the given line: + + >>> P.p2 in L + True + """ + p = Point(p, dim=self.ambient_dimension) + if p in self: + p = p + self.direction.orthogonal_direction + return Line(p, self.projection(p)) + + def perpendicular_segment(self, p): + """Create a perpendicular line segment from `p` to this line. + + The endpoints of the segment are ``p`` and the closest point in + the line containing self. (If self is not a line, the point might + not be in self.) + + Parameters + ========== + + p : Point + + Returns + ======= + + segment : Segment + + Notes + ===== + + Returns `p` itself if `p` is on this linear entity. + + See Also + ======== + + perpendicular_line + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(0, 2) + >>> l1 = Line(p1, p2) + >>> s1 = l1.perpendicular_segment(p3) + >>> l1.is_perpendicular(s1) + True + >>> p3 in s1 + True + >>> l1.perpendicular_segment(Point(4, 0)) + Segment2D(Point2D(4, 0), Point2D(2, 2)) + >>> from sympy import Point3D, Line3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(0, 2, 0) + >>> l1 = Line3D(p1, p2) + >>> s1 = l1.perpendicular_segment(p3) + >>> l1.is_perpendicular(s1) + True + >>> p3 in s1 + True + >>> l1.perpendicular_segment(Point3D(4, 0, 0)) + Segment3D(Point3D(4, 0, 0), Point3D(4/3, 4/3, 4/3)) + + """ + p = Point(p, dim=self.ambient_dimension) + if p in self: + return p + l = self.perpendicular_line(p) + # The intersection should be unique, so unpack the singleton + p2, = Intersection(Line(self.p1, self.p2), l) + + return Segment(p, p2) + + @property + def points(self): + """The two points used to define this linear entity. + + Returns + ======= + + points : tuple of Points + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(5, 11) + >>> l1 = Line(p1, p2) + >>> l1.points + (Point2D(0, 0), Point2D(5, 11)) + + """ + return (self.p1, self.p2) + + def projection(self, other): + """Project a point, line, ray, or segment onto this linear entity. + + Parameters + ========== + + other : Point or LinearEntity (Line, Ray, Segment) + + Returns + ======= + + projection : Point or LinearEntity (Line, Ray, Segment) + The return type matches the type of the parameter ``other``. + + Raises + ====== + + GeometryError + When method is unable to perform projection. + + Notes + ===== + + A projection involves taking the two points that define + the linear entity and projecting those points onto a + Line and then reforming the linear entity using these + projections. + A point P is projected onto a line L by finding the point + on L that is closest to P. This point is the intersection + of L and the line perpendicular to L that passes through P. + + See Also + ======== + + sympy.geometry.point.Point, perpendicular_line + + Examples + ======== + + >>> from sympy import Point, Line, Segment, Rational + >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(Rational(1, 2), 0) + >>> l1 = Line(p1, p2) + >>> l1.projection(p3) + Point2D(1/4, 1/4) + >>> p4, p5 = Point(10, 0), Point(12, 1) + >>> s1 = Segment(p4, p5) + >>> l1.projection(s1) + Segment2D(Point2D(5, 5), Point2D(13/2, 13/2)) + >>> p1, p2, p3 = Point(0, 0, 1), Point(1, 1, 2), Point(2, 0, 1) + >>> l1 = Line(p1, p2) + >>> l1.projection(p3) + Point3D(2/3, 2/3, 5/3) + >>> p4, p5 = Point(10, 0, 1), Point(12, 1, 3) + >>> s1 = Segment(p4, p5) + >>> l1.projection(s1) + Segment3D(Point3D(10/3, 10/3, 13/3), Point3D(5, 5, 6)) + + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + + def proj_point(p): + return Point.project(p - self.p1, self.direction) + self.p1 + + if isinstance(other, Point): + return proj_point(other) + elif isinstance(other, LinearEntity): + p1, p2 = proj_point(other.p1), proj_point(other.p2) + # test to see if we're degenerate + if p1 == p2: + return p1 + projected = other.__class__(p1, p2) + projected = Intersection(self, projected) + if projected.is_empty: + return projected + # if we happen to have intersected in only a point, return that + if projected.is_FiniteSet and len(projected) == 1: + # projected is a set of size 1, so unpack it in `a` + a, = projected + return a + # order args so projection is in the same direction as self + if self.direction.dot(projected.direction) < 0: + p1, p2 = projected.args + projected = projected.func(p2, p1) + return projected + + raise GeometryError( + "Do not know how to project %s onto %s" % (other, self)) + + def random_point(self, seed=None): + """A random point on a LinearEntity. + + Returns + ======= + + point : Point + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Line, Ray, Segment + >>> p1, p2 = Point(0, 0), Point(5, 3) + >>> line = Line(p1, p2) + >>> r = line.random_point(seed=42) # seed value is optional + >>> r.n(3) + Point2D(-0.72, -0.432) + >>> r in line + True + >>> Ray(p1, p2).random_point(seed=42).n(3) + Point2D(0.72, 0.432) + >>> Segment(p1, p2).random_point(seed=42).n(3) + Point2D(3.2, 1.92) + + """ + if seed is not None: + rng = random.Random(seed) + else: + rng = random + pt = self.arbitrary_point(t) + if isinstance(self, Ray): + v = abs(rng.gauss(0, 1)) + elif isinstance(self, Segment): + v = rng.random() + elif isinstance(self, Line): + v = rng.gauss(0, 1) + else: + raise NotImplementedError('unhandled line type') + return pt.subs(t, Rational(v)) + + def bisectors(self, other): + """Returns the perpendicular lines which pass through the intersections + of self and other that are in the same plane. + + Parameters + ========== + + line : Line3D + + Returns + ======= + + list: two Line instances + + Examples + ======== + + >>> from sympy import Point3D, Line3D + >>> r1 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)) + >>> r2 = Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0)) + >>> r1.bisectors(r2) + [Line3D(Point3D(0, 0, 0), Point3D(1, 1, 0)), Line3D(Point3D(0, 0, 0), Point3D(1, -1, 0))] + + """ + if not isinstance(other, LinearEntity): + raise GeometryError("Expecting LinearEntity, not %s" % other) + + l1, l2 = self, other + + # make sure dimensions match or else a warning will rise from + # intersection calculation + if l1.p1.ambient_dimension != l2.p1.ambient_dimension: + if isinstance(l1, Line2D): + l1, l2 = l2, l1 + _, p1 = Point._normalize_dimension(l1.p1, l2.p1, on_morph='ignore') + _, p2 = Point._normalize_dimension(l1.p2, l2.p2, on_morph='ignore') + l2 = Line(p1, p2) + + point = intersection(l1, l2) + + # Three cases: Lines may intersect in a point, may be equal or may not intersect. + if not point: + raise GeometryError("The lines do not intersect") + else: + pt = point[0] + if isinstance(pt, Line): + # Intersection is a line because both lines are coincident + return [self] + + + d1 = l1.direction.unit + d2 = l2.direction.unit + + bis1 = Line(pt, pt + d1 + d2) + bis2 = Line(pt, pt + d1 - d2) + + return [bis1, bis2] + + +class Line(LinearEntity): + """An infinite line in space. + + A 2D line is declared with two distinct points, point and slope, or + an equation. A 3D line may be defined with a point and a direction ratio. + + Parameters + ========== + + p1 : Point + p2 : Point + slope : SymPy expression + direction_ratio : list + equation : equation of a line + + Notes + ===== + + `Line` will automatically subclass to `Line2D` or `Line3D` based + on the dimension of `p1`. The `slope` argument is only relevant + for `Line2D` and the `direction_ratio` argument is only relevant + for `Line3D`. + + The order of the points will define the direction of the line + which is used when calculating the angle between lines. + + See Also + ======== + + sympy.geometry.point.Point + sympy.geometry.line.Line2D + sympy.geometry.line.Line3D + + Examples + ======== + + >>> from sympy import Line, Segment, Point, Eq + >>> from sympy.abc import x, y, a, b + + >>> L = Line(Point(2,3), Point(3,5)) + >>> L + Line2D(Point2D(2, 3), Point2D(3, 5)) + >>> L.points + (Point2D(2, 3), Point2D(3, 5)) + >>> L.equation() + -2*x + y + 1 + >>> L.coefficients + (-2, 1, 1) + + Instantiate with keyword ``slope``: + + >>> Line(Point(0, 0), slope=0) + Line2D(Point2D(0, 0), Point2D(1, 0)) + + Instantiate with another linear object + + >>> s = Segment((0, 0), (0, 1)) + >>> Line(s).equation() + x + + The line corresponding to an equation in the for `ax + by + c = 0`, + can be entered: + + >>> Line(3*x + y + 18) + Line2D(Point2D(0, -18), Point2D(1, -21)) + + If `x` or `y` has a different name, then they can be specified, too, + as a string (to match the name) or symbol: + + >>> Line(Eq(3*a + b, -18), x='a', y=b) + Line2D(Point2D(0, -18), Point2D(1, -21)) + """ + def __new__(cls, *args, **kwargs): + if len(args) == 1 and isinstance(args[0], (Expr, Eq)): + missing = uniquely_named_symbol('?', args) + if not kwargs: + x = 'x' + y = 'y' + else: + x = kwargs.pop('x', missing) + y = kwargs.pop('y', missing) + if kwargs: + raise ValueError('expecting only x and y as keywords') + + equation = args[0] + if isinstance(equation, Eq): + equation = equation.lhs - equation.rhs + + def find_or_missing(x): + try: + return find(x, equation) + except ValueError: + return missing + x = find_or_missing(x) + y = find_or_missing(y) + + a, b, c = linear_coeffs(equation, x, y) + + if b: + return Line((0, -c/b), slope=-a/b) + if a: + return Line((-c/a, 0), slope=oo) + + raise ValueError('not found in equation: %s' % (set('xy') - {x, y})) + + else: + if len(args) > 0: + p1 = args[0] + if len(args) > 1: + p2 = args[1] + else: + p2 = None + + if isinstance(p1, LinearEntity): + if p2: + raise ValueError('If p1 is a LinearEntity, p2 must be None.') + dim = len(p1.p1) + else: + p1 = Point(p1) + dim = len(p1) + if p2 is not None or isinstance(p2, Point) and p2.ambient_dimension != dim: + p2 = Point(p2) + + if dim == 2: + return Line2D(p1, p2, **kwargs) + elif dim == 3: + return Line3D(p1, p2, **kwargs) + return LinearEntity.__new__(cls, p1, p2, **kwargs) + + def contains(self, other): + """ + Return True if `other` is on this Line, or False otherwise. + + Examples + ======== + + >>> from sympy import Line,Point + >>> p1, p2 = Point(0, 1), Point(3, 4) + >>> l = Line(p1, p2) + >>> l.contains(p1) + True + >>> l.contains((0, 1)) + True + >>> l.contains((0, 0)) + False + >>> a = (0, 0, 0) + >>> b = (1, 1, 1) + >>> c = (2, 2, 2) + >>> l1 = Line(a, b) + >>> l2 = Line(b, a) + >>> l1 == l2 + False + >>> l1 in l2 + True + + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if isinstance(other, Point): + return Point.is_collinear(other, self.p1, self.p2) + if isinstance(other, LinearEntity): + return Point.is_collinear(self.p1, self.p2, other.p1, other.p2) + return False + + def distance(self, other): + """ + Finds the shortest distance between a line and a point. + + Raises + ====== + + NotImplementedError is raised if `other` is not a Point + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(1, 1) + >>> s = Line(p1, p2) + >>> s.distance(Point(-1, 1)) + sqrt(2) + >>> s.distance((-1, 2)) + 3*sqrt(2)/2 + >>> p1, p2 = Point(0, 0, 0), Point(1, 1, 1) + >>> s = Line(p1, p2) + >>> s.distance(Point(-1, 1, 1)) + 2*sqrt(6)/3 + >>> s.distance((-1, 1, 1)) + 2*sqrt(6)/3 + + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if self.contains(other): + return S.Zero + return self.perpendicular_segment(other).length + + def equals(self, other): + """Returns True if self and other are the same mathematical entities""" + if not isinstance(other, Line): + return False + return Point.is_collinear(self.p1, other.p1, self.p2, other.p2) + + def plot_interval(self, parameter='t'): + """The plot interval for the default geometric plot of line. Gives + values that will produce a line that is +/- 5 units long (where a + unit is the distance between the two points that define the line). + + Parameters + ========== + + parameter : str, optional + Default value is 't'. + + Returns + ======= + + plot_interval : list (plot interval) + [parameter, lower_bound, upper_bound] + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(5, 3) + >>> l1 = Line(p1, p2) + >>> l1.plot_interval() + [t, -5, 5] + + """ + t = _symbol(parameter, real=True) + return [t, -5, 5] + + +class Ray(LinearEntity): + """A Ray is a semi-line in the space with a source point and a direction. + + Parameters + ========== + + p1 : Point + The source of the Ray + p2 : Point or radian value + This point determines the direction in which the Ray propagates. + If given as an angle it is interpreted in radians with the positive + direction being ccw. + + Attributes + ========== + + source + + See Also + ======== + + sympy.geometry.line.Ray2D + sympy.geometry.line.Ray3D + sympy.geometry.point.Point + sympy.geometry.line.Line + + Notes + ===== + + `Ray` will automatically subclass to `Ray2D` or `Ray3D` based on the + dimension of `p1`. + + Examples + ======== + + >>> from sympy import Ray, Point, pi + >>> r = Ray(Point(2, 3), Point(3, 5)) + >>> r + Ray2D(Point2D(2, 3), Point2D(3, 5)) + >>> r.points + (Point2D(2, 3), Point2D(3, 5)) + >>> r.source + Point2D(2, 3) + >>> r.xdirection + oo + >>> r.ydirection + oo + >>> r.slope + 2 + >>> Ray(Point(0, 0), angle=pi/4).slope + 1 + + """ + def __new__(cls, p1, p2=None, **kwargs): + p1 = Point(p1) + if p2 is not None: + p1, p2 = Point._normalize_dimension(p1, Point(p2)) + dim = len(p1) + + if dim == 2: + return Ray2D(p1, p2, **kwargs) + elif dim == 3: + return Ray3D(p1, p2, **kwargs) + return LinearEntity.__new__(cls, p1, p2, **kwargs) + + def _svg(self, scale_factor=1., fill_color="#66cc99"): + """Returns SVG path element for the LinearEntity. + + Parameters + ========== + + scale_factor : float + Multiplication factor for the SVG stroke-width. Default is 1. + fill_color : str, optional + Hex string for fill color. Default is "#66cc99". + """ + verts = (N(self.p1), N(self.p2)) + coords = ["{},{}".format(p.x, p.y) for p in verts] + path = "M {} L {}".format(coords[0], " L ".join(coords[1:])) + + return ( + '' + ).format(2.*scale_factor, path, fill_color) + + def contains(self, other): + """ + Is other GeometryEntity contained in this Ray? + + Examples + ======== + + >>> from sympy import Ray,Point,Segment + >>> p1, p2 = Point(0, 0), Point(4, 4) + >>> r = Ray(p1, p2) + >>> r.contains(p1) + True + >>> r.contains((1, 1)) + True + >>> r.contains((1, 3)) + False + >>> s = Segment((1, 1), (2, 2)) + >>> r.contains(s) + True + >>> s = Segment((1, 2), (2, 5)) + >>> r.contains(s) + False + >>> r1 = Ray((2, 2), (3, 3)) + >>> r.contains(r1) + True + >>> r1 = Ray((2, 2), (3, 5)) + >>> r.contains(r1) + False + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if isinstance(other, Point): + if Point.is_collinear(self.p1, self.p2, other): + # if we're in the direction of the ray, our + # direction vector dot the ray's direction vector + # should be non-negative + return bool((self.p2 - self.p1).dot(other - self.p1) >= S.Zero) + return False + elif isinstance(other, Ray): + if Point.is_collinear(self.p1, self.p2, other.p1, other.p2): + return bool((self.p2 - self.p1).dot(other.p2 - other.p1) > S.Zero) + return False + elif isinstance(other, Segment): + return other.p1 in self and other.p2 in self + + # No other known entity can be contained in a Ray + return False + + def distance(self, other): + """ + Finds the shortest distance between the ray and a point. + + Raises + ====== + + NotImplementedError is raised if `other` is not a Point + + Examples + ======== + + >>> from sympy import Point, Ray + >>> p1, p2 = Point(0, 0), Point(1, 1) + >>> s = Ray(p1, p2) + >>> s.distance(Point(-1, -1)) + sqrt(2) + >>> s.distance((-1, 2)) + 3*sqrt(2)/2 + >>> p1, p2 = Point(0, 0, 0), Point(1, 1, 2) + >>> s = Ray(p1, p2) + >>> s + Ray3D(Point3D(0, 0, 0), Point3D(1, 1, 2)) + >>> s.distance(Point(-1, -1, 2)) + 4*sqrt(3)/3 + >>> s.distance((-1, -1, 2)) + 4*sqrt(3)/3 + + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if self.contains(other): + return S.Zero + + proj = Line(self.p1, self.p2).projection(other) + if self.contains(proj): + return abs(other - proj) + else: + return abs(other - self.source) + + def equals(self, other): + """Returns True if self and other are the same mathematical entities""" + if not isinstance(other, Ray): + return False + return self.source == other.source and other.p2 in self + + def plot_interval(self, parameter='t'): + """The plot interval for the default geometric plot of the Ray. Gives + values that will produce a ray that is 10 units long (where a unit is + the distance between the two points that define the ray). + + Parameters + ========== + + parameter : str, optional + Default value is 't'. + + Returns + ======= + + plot_interval : list + [parameter, lower_bound, upper_bound] + + Examples + ======== + + >>> from sympy import Ray, pi + >>> r = Ray((0, 0), angle=pi/4) + >>> r.plot_interval() + [t, 0, 10] + + """ + t = _symbol(parameter, real=True) + return [t, 0, 10] + + @property + def source(self): + """The point from which the ray emanates. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Ray + >>> p1, p2 = Point(0, 0), Point(4, 1) + >>> r1 = Ray(p1, p2) + >>> r1.source + Point2D(0, 0) + >>> p1, p2 = Point(0, 0, 0), Point(4, 1, 5) + >>> r1 = Ray(p2, p1) + >>> r1.source + Point3D(4, 1, 5) + + """ + return self.p1 + + +class Segment(LinearEntity): + """A line segment in space. + + Parameters + ========== + + p1 : Point + p2 : Point + + Attributes + ========== + + length : number or SymPy expression + midpoint : Point + + See Also + ======== + + sympy.geometry.line.Segment2D + sympy.geometry.line.Segment3D + sympy.geometry.point.Point + sympy.geometry.line.Line + + Notes + ===== + + If 2D or 3D points are used to define `Segment`, it will + be automatically subclassed to `Segment2D` or `Segment3D`. + + Examples + ======== + + >>> from sympy import Point, Segment + >>> Segment((1, 0), (1, 1)) # tuples are interpreted as pts + Segment2D(Point2D(1, 0), Point2D(1, 1)) + >>> s = Segment(Point(4, 3), Point(1, 1)) + >>> s.points + (Point2D(4, 3), Point2D(1, 1)) + >>> s.slope + 2/3 + >>> s.length + sqrt(13) + >>> s.midpoint + Point2D(5/2, 2) + >>> Segment((1, 0, 0), (1, 1, 1)) # tuples are interpreted as pts + Segment3D(Point3D(1, 0, 0), Point3D(1, 1, 1)) + >>> s = Segment(Point(4, 3, 9), Point(1, 1, 7)); s + Segment3D(Point3D(4, 3, 9), Point3D(1, 1, 7)) + >>> s.points + (Point3D(4, 3, 9), Point3D(1, 1, 7)) + >>> s.length + sqrt(17) + >>> s.midpoint + Point3D(5/2, 2, 8) + + """ + def __new__(cls, p1, p2, **kwargs): + p1, p2 = Point._normalize_dimension(Point(p1), Point(p2)) + dim = len(p1) + + if dim == 2: + return Segment2D(p1, p2, **kwargs) + elif dim == 3: + return Segment3D(p1, p2, **kwargs) + return LinearEntity.__new__(cls, p1, p2, **kwargs) + + def contains(self, other): + """ + Is the other GeometryEntity contained within this Segment? + + Examples + ======== + + >>> from sympy import Point, Segment + >>> p1, p2 = Point(0, 1), Point(3, 4) + >>> s = Segment(p1, p2) + >>> s2 = Segment(p2, p1) + >>> s.contains(s2) + True + >>> from sympy import Point3D, Segment3D + >>> p1, p2 = Point3D(0, 1, 1), Point3D(3, 4, 5) + >>> s = Segment3D(p1, p2) + >>> s2 = Segment3D(p2, p1) + >>> s.contains(s2) + True + >>> s.contains((p1 + p2)/2) + True + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if isinstance(other, Point): + if Point.is_collinear(other, self.p1, self.p2): + if isinstance(self, Segment2D): + # if it is collinear and is in the bounding box of the + # segment then it must be on the segment + vert = (1/self.slope).equals(0) + if vert is False: + isin = (self.p1.x - other.x)*(self.p2.x - other.x) <= 0 + if isin in (True, False): + return isin + if vert is True: + isin = (self.p1.y - other.y)*(self.p2.y - other.y) <= 0 + if isin in (True, False): + return isin + # use the triangle inequality + d1, d2 = other - self.p1, other - self.p2 + d = self.p2 - self.p1 + # without the call to simplify, SymPy cannot tell that an expression + # like (a+b)*(a/2+b/2) is always non-negative. If it cannot be + # determined, raise an Undecidable error + try: + # the triangle inequality says that |d1|+|d2| >= |d| and is strict + # only if other lies in the line segment + return bool(simplify(Eq(abs(d1) + abs(d2) - abs(d), 0))) + except TypeError: + raise Undecidable("Cannot determine if {} is in {}".format(other, self)) + if isinstance(other, Segment): + return other.p1 in self and other.p2 in self + + return False + + def equals(self, other): + """Returns True if self and other are the same mathematical entities""" + return isinstance(other, self.func) and list( + ordered(self.args)) == list(ordered(other.args)) + + def distance(self, other): + """ + Finds the shortest distance between a line segment and a point. + + Raises + ====== + + NotImplementedError is raised if `other` is not a Point + + Examples + ======== + + >>> from sympy import Point, Segment + >>> p1, p2 = Point(0, 1), Point(3, 4) + >>> s = Segment(p1, p2) + >>> s.distance(Point(10, 15)) + sqrt(170) + >>> s.distance((0, 12)) + sqrt(73) + >>> from sympy import Point3D, Segment3D + >>> p1, p2 = Point3D(0, 0, 3), Point3D(1, 1, 4) + >>> s = Segment3D(p1, p2) + >>> s.distance(Point3D(10, 15, 12)) + sqrt(341) + >>> s.distance((10, 15, 12)) + sqrt(341) + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if isinstance(other, Point): + vp1 = other - self.p1 + vp2 = other - self.p2 + + dot_prod_sign_1 = self.direction.dot(vp1) >= 0 + dot_prod_sign_2 = self.direction.dot(vp2) <= 0 + if dot_prod_sign_1 and dot_prod_sign_2: + return Line(self.p1, self.p2).distance(other) + if dot_prod_sign_1 and not dot_prod_sign_2: + return abs(vp2) + if not dot_prod_sign_1 and dot_prod_sign_2: + return abs(vp1) + raise NotImplementedError() + + @property + def length(self): + """The length of the line segment. + + See Also + ======== + + sympy.geometry.point.Point.distance + + Examples + ======== + + >>> from sympy import Point, Segment + >>> p1, p2 = Point(0, 0), Point(4, 3) + >>> s1 = Segment(p1, p2) + >>> s1.length + 5 + >>> from sympy import Point3D, Segment3D + >>> p1, p2 = Point3D(0, 0, 0), Point3D(4, 3, 3) + >>> s1 = Segment3D(p1, p2) + >>> s1.length + sqrt(34) + + """ + return Point.distance(self.p1, self.p2) + + @property + def midpoint(self): + """The midpoint of the line segment. + + See Also + ======== + + sympy.geometry.point.Point.midpoint + + Examples + ======== + + >>> from sympy import Point, Segment + >>> p1, p2 = Point(0, 0), Point(4, 3) + >>> s1 = Segment(p1, p2) + >>> s1.midpoint + Point2D(2, 3/2) + >>> from sympy import Point3D, Segment3D + >>> p1, p2 = Point3D(0, 0, 0), Point3D(4, 3, 3) + >>> s1 = Segment3D(p1, p2) + >>> s1.midpoint + Point3D(2, 3/2, 3/2) + + """ + return Point.midpoint(self.p1, self.p2) + + def perpendicular_bisector(self, p=None): + """The perpendicular bisector of this segment. + + If no point is specified or the point specified is not on the + bisector then the bisector is returned as a Line. Otherwise a + Segment is returned that joins the point specified and the + intersection of the bisector and the segment. + + Parameters + ========== + + p : Point + + Returns + ======= + + bisector : Line or Segment + + See Also + ======== + + LinearEntity.perpendicular_segment + + Examples + ======== + + >>> from sympy import Point, Segment + >>> p1, p2, p3 = Point(0, 0), Point(6, 6), Point(5, 1) + >>> s1 = Segment(p1, p2) + >>> s1.perpendicular_bisector() + Line2D(Point2D(3, 3), Point2D(-3, 9)) + + >>> s1.perpendicular_bisector(p3) + Segment2D(Point2D(5, 1), Point2D(3, 3)) + + """ + l = self.perpendicular_line(self.midpoint) + if p is not None: + p2 = Point(p, dim=self.ambient_dimension) + if p2 in l: + return Segment(p2, self.midpoint) + return l + + def plot_interval(self, parameter='t'): + """The plot interval for the default geometric plot of the Segment gives + values that will produce the full segment in a plot. + + Parameters + ========== + + parameter : str, optional + Default value is 't'. + + Returns + ======= + + plot_interval : list + [parameter, lower_bound, upper_bound] + + Examples + ======== + + >>> from sympy import Point, Segment + >>> p1, p2 = Point(0, 0), Point(5, 3) + >>> s1 = Segment(p1, p2) + >>> s1.plot_interval() + [t, 0, 1] + + """ + t = _symbol(parameter, real=True) + return [t, 0, 1] + + +class LinearEntity2D(LinearEntity): + """A base class for all linear entities (line, ray and segment) + in a 2-dimensional Euclidean space. + + Attributes + ========== + + p1 + p2 + coefficients + slope + points + + Notes + ===== + + This is an abstract class and is not meant to be instantiated. + + See Also + ======== + + sympy.geometry.entity.GeometryEntity + + """ + @property + def bounds(self): + """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding + rectangle for the geometric figure. + + """ + verts = self.points + xs = [p.x for p in verts] + ys = [p.y for p in verts] + return (min(xs), min(ys), max(xs), max(ys)) + + def perpendicular_line(self, p): + """Create a new Line perpendicular to this linear entity which passes + through the point `p`. + + Parameters + ========== + + p : Point + + Returns + ======= + + line : Line + + See Also + ======== + + sympy.geometry.line.LinearEntity.is_perpendicular, perpendicular_segment + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2, p3 = Point(0, 0), Point(2, 3), Point(-2, 2) + >>> L = Line(p1, p2) + >>> P = L.perpendicular_line(p3); P + Line2D(Point2D(-2, 2), Point2D(-5, 4)) + >>> L.is_perpendicular(P) + True + + In 2D, the first point of the perpendicular line is the + point through which was required to pass; the second + point is arbitrarily chosen. To get a line that explicitly + uses a point in the line, create a line from the perpendicular + segment from the line to the point: + + >>> Line(L.perpendicular_segment(p3)) + Line2D(Point2D(-2, 2), Point2D(4/13, 6/13)) + """ + p = Point(p, dim=self.ambient_dimension) + # any two lines in R^2 intersect, so blindly making + # a line through p in an orthogonal direction will work + # and is faster than finding the projection point as in 3D + return Line(p, p + self.direction.orthogonal_direction) + + @property + def slope(self): + """The slope of this linear entity, or infinity if vertical. + + Returns + ======= + + slope : number or SymPy expression + + See Also + ======== + + coefficients + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(0, 0), Point(3, 5) + >>> l1 = Line(p1, p2) + >>> l1.slope + 5/3 + + >>> p3 = Point(0, 4) + >>> l2 = Line(p1, p3) + >>> l2.slope + oo + + """ + d1, d2 = (self.p1 - self.p2).args + if d1 == 0: + return S.Infinity + return simplify(d2/d1) + + +class Line2D(LinearEntity2D, Line): + """An infinite line in space 2D. + + A line is declared with two distinct points or a point and slope + as defined using keyword `slope`. + + Parameters + ========== + + p1 : Point + pt : Point + slope : SymPy expression + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Line, Segment, Point + >>> L = Line(Point(2,3), Point(3,5)) + >>> L + Line2D(Point2D(2, 3), Point2D(3, 5)) + >>> L.points + (Point2D(2, 3), Point2D(3, 5)) + >>> L.equation() + -2*x + y + 1 + >>> L.coefficients + (-2, 1, 1) + + Instantiate with keyword ``slope``: + + >>> Line(Point(0, 0), slope=0) + Line2D(Point2D(0, 0), Point2D(1, 0)) + + Instantiate with another linear object + + >>> s = Segment((0, 0), (0, 1)) + >>> Line(s).equation() + x + """ + def __new__(cls, p1, pt=None, slope=None, **kwargs): + if isinstance(p1, LinearEntity): + if pt is not None: + raise ValueError('When p1 is a LinearEntity, pt should be None') + p1, pt = Point._normalize_dimension(*p1.args, dim=2) + else: + p1 = Point(p1, dim=2) + if pt is not None and slope is None: + try: + p2 = Point(pt, dim=2) + except (NotImplementedError, TypeError, ValueError): + raise ValueError(filldedent(''' + The 2nd argument was not a valid Point. + If it was a slope, enter it with keyword "slope". + ''')) + elif slope is not None and pt is None: + slope = sympify(slope) + if slope.is_finite is False: + # when infinite slope, don't change x + dx = 0 + dy = 1 + else: + # go over 1 up slope + dx = 1 + dy = slope + # XXX avoiding simplification by adding to coords directly + p2 = Point(p1.x + dx, p1.y + dy, evaluate=False) + else: + raise ValueError('A 2nd Point or keyword "slope" must be used.') + return LinearEntity2D.__new__(cls, p1, p2, **kwargs) + + def _svg(self, scale_factor=1., fill_color="#66cc99"): + """Returns SVG path element for the LinearEntity. + + Parameters + ========== + + scale_factor : float + Multiplication factor for the SVG stroke-width. Default is 1. + fill_color : str, optional + Hex string for fill color. Default is "#66cc99". + """ + verts = (N(self.p1), N(self.p2)) + coords = ["{},{}".format(p.x, p.y) for p in verts] + path = "M {} L {}".format(coords[0], " L ".join(coords[1:])) + + return ( + '' + ).format(2.*scale_factor, path, fill_color) + + @property + def coefficients(self): + """The coefficients (`a`, `b`, `c`) for `ax + by + c = 0`. + + See Also + ======== + + sympy.geometry.line.Line2D.equation + + Examples + ======== + + >>> from sympy import Point, Line + >>> from sympy.abc import x, y + >>> p1, p2 = Point(0, 0), Point(5, 3) + >>> l = Line(p1, p2) + >>> l.coefficients + (-3, 5, 0) + + >>> p3 = Point(x, y) + >>> l2 = Line(p1, p3) + >>> l2.coefficients + (-y, x, 0) + + """ + p1, p2 = self.points + if p1.x == p2.x: + return (S.One, S.Zero, -p1.x) + elif p1.y == p2.y: + return (S.Zero, S.One, -p1.y) + return tuple([simplify(i) for i in + (self.p1.y - self.p2.y, + self.p2.x - self.p1.x, + self.p1.x*self.p2.y - self.p1.y*self.p2.x)]) + + def equation(self, x='x', y='y'): + """The equation of the line: ax + by + c. + + Parameters + ========== + + x : str, optional + The name to use for the x-axis, default value is 'x'. + y : str, optional + The name to use for the y-axis, default value is 'y'. + + Returns + ======= + + equation : SymPy expression + + See Also + ======== + + sympy.geometry.line.Line2D.coefficients + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(1, 0), Point(5, 3) + >>> l1 = Line(p1, p2) + >>> l1.equation() + -3*x + 4*y + 3 + + """ + x = _symbol(x, real=True) + y = _symbol(y, real=True) + p1, p2 = self.points + if p1.x == p2.x: + return x - p1.x + elif p1.y == p2.y: + return y - p1.y + + a, b, c = self.coefficients + return a*x + b*y + c + + +class Ray2D(LinearEntity2D, Ray): + """ + A Ray is a semi-line in the space with a source point and a direction. + + Parameters + ========== + + p1 : Point + The source of the Ray + p2 : Point or radian value + This point determines the direction in which the Ray propagates. + If given as an angle it is interpreted in radians with the positive + direction being ccw. + + Attributes + ========== + + source + xdirection + ydirection + + See Also + ======== + + sympy.geometry.point.Point, Line + + Examples + ======== + + >>> from sympy import Point, pi, Ray + >>> r = Ray(Point(2, 3), Point(3, 5)) + >>> r + Ray2D(Point2D(2, 3), Point2D(3, 5)) + >>> r.points + (Point2D(2, 3), Point2D(3, 5)) + >>> r.source + Point2D(2, 3) + >>> r.xdirection + oo + >>> r.ydirection + oo + >>> r.slope + 2 + >>> Ray(Point(0, 0), angle=pi/4).slope + 1 + + """ + def __new__(cls, p1, pt=None, angle=None, **kwargs): + p1 = Point(p1, dim=2) + if pt is not None and angle is None: + try: + p2 = Point(pt, dim=2) + except (NotImplementedError, TypeError, ValueError): + raise ValueError(filldedent(''' + The 2nd argument was not a valid Point; if + it was meant to be an angle it should be + given with keyword "angle".''')) + if p1 == p2: + raise ValueError('A Ray requires two distinct points.') + elif angle is not None and pt is None: + # we need to know if the angle is an odd multiple of pi/2 + angle = sympify(angle) + c = _pi_coeff(angle) + p2 = None + if c is not None: + if c.is_Rational: + if c.q == 2: + if c.p == 1: + p2 = p1 + Point(0, 1) + elif c.p == 3: + p2 = p1 + Point(0, -1) + elif c.q == 1: + if c.p == 0: + p2 = p1 + Point(1, 0) + elif c.p == 1: + p2 = p1 + Point(-1, 0) + if p2 is None: + c *= S.Pi + else: + c = angle % (2*S.Pi) + if not p2: + m = 2*c/S.Pi + left = And(1 < m, m < 3) # is it in quadrant 2 or 3? + x = Piecewise((-1, left), (Piecewise((0, Eq(m % 1, 0)), (1, True)), True)) + y = Piecewise((-tan(c), left), (Piecewise((1, Eq(m, 1)), (-1, Eq(m, 3)), (tan(c), True)), True)) + p2 = p1 + Point(x, y) + else: + raise ValueError('A 2nd point or keyword "angle" must be used.') + + return LinearEntity2D.__new__(cls, p1, p2, **kwargs) + + @property + def xdirection(self): + """The x direction of the ray. + + Positive infinity if the ray points in the positive x direction, + negative infinity if the ray points in the negative x direction, + or 0 if the ray is vertical. + + See Also + ======== + + ydirection + + Examples + ======== + + >>> from sympy import Point, Ray + >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(0, -1) + >>> r1, r2 = Ray(p1, p2), Ray(p1, p3) + >>> r1.xdirection + oo + >>> r2.xdirection + 0 + + """ + if self.p1.x < self.p2.x: + return S.Infinity + elif self.p1.x == self.p2.x: + return S.Zero + else: + return S.NegativeInfinity + + @property + def ydirection(self): + """The y direction of the ray. + + Positive infinity if the ray points in the positive y direction, + negative infinity if the ray points in the negative y direction, + or 0 if the ray is horizontal. + + See Also + ======== + + xdirection + + Examples + ======== + + >>> from sympy import Point, Ray + >>> p1, p2, p3 = Point(0, 0), Point(-1, -1), Point(-1, 0) + >>> r1, r2 = Ray(p1, p2), Ray(p1, p3) + >>> r1.ydirection + -oo + >>> r2.ydirection + 0 + + """ + if self.p1.y < self.p2.y: + return S.Infinity + elif self.p1.y == self.p2.y: + return S.Zero + else: + return S.NegativeInfinity + + def closing_angle(r1, r2): + """Return the angle by which r2 must be rotated so it faces the same + direction as r1. + + Parameters + ========== + + r1 : Ray2D + r2 : Ray2D + + Returns + ======= + + angle : angle in radians (ccw angle is positive) + + See Also + ======== + + LinearEntity.angle_between + + Examples + ======== + + >>> from sympy import Ray, pi + >>> r1 = Ray((0, 0), (1, 0)) + >>> r2 = r1.rotate(-pi/2) + >>> angle = r1.closing_angle(r2); angle + pi/2 + >>> r2.rotate(angle).direction.unit == r1.direction.unit + True + >>> r2.closing_angle(r1) + -pi/2 + """ + if not all(isinstance(r, Ray2D) for r in (r1, r2)): + # although the direction property is defined for + # all linear entities, only the Ray is truly a + # directed object + raise TypeError('Both arguments must be Ray2D objects.') + + a1 = atan2(*list(reversed(r1.direction.args))) + a2 = atan2(*list(reversed(r2.direction.args))) + if a1*a2 < 0: + a1 = 2*S.Pi + a1 if a1 < 0 else a1 + a2 = 2*S.Pi + a2 if a2 < 0 else a2 + return a1 - a2 + + +class Segment2D(LinearEntity2D, Segment): + """A line segment in 2D space. + + Parameters + ========== + + p1 : Point + p2 : Point + + Attributes + ========== + + length : number or SymPy expression + midpoint : Point + + See Also + ======== + + sympy.geometry.point.Point, Line + + Examples + ======== + + >>> from sympy import Point, Segment + >>> Segment((1, 0), (1, 1)) # tuples are interpreted as pts + Segment2D(Point2D(1, 0), Point2D(1, 1)) + >>> s = Segment(Point(4, 3), Point(1, 1)); s + Segment2D(Point2D(4, 3), Point2D(1, 1)) + >>> s.points + (Point2D(4, 3), Point2D(1, 1)) + >>> s.slope + 2/3 + >>> s.length + sqrt(13) + >>> s.midpoint + Point2D(5/2, 2) + + """ + def __new__(cls, p1, p2, **kwargs): + p1 = Point(p1, dim=2) + p2 = Point(p2, dim=2) + + if p1 == p2: + return p1 + + return LinearEntity2D.__new__(cls, p1, p2, **kwargs) + + def _svg(self, scale_factor=1., fill_color="#66cc99"): + """Returns SVG path element for the LinearEntity. + + Parameters + ========== + + scale_factor : float + Multiplication factor for the SVG stroke-width. Default is 1. + fill_color : str, optional + Hex string for fill color. Default is "#66cc99". + """ + verts = (N(self.p1), N(self.p2)) + coords = ["{},{}".format(p.x, p.y) for p in verts] + path = "M {} L {}".format(coords[0], " L ".join(coords[1:])) + return ( + '' + ).format(2.*scale_factor, path, fill_color) + + +class LinearEntity3D(LinearEntity): + """An base class for all linear entities (line, ray and segment) + in a 3-dimensional Euclidean space. + + Attributes + ========== + + p1 + p2 + direction_ratio + direction_cosine + points + + Notes + ===== + + This is a base class and is not meant to be instantiated. + """ + def __new__(cls, p1, p2, **kwargs): + p1 = Point3D(p1, dim=3) + p2 = Point3D(p2, dim=3) + if p1 == p2: + # if it makes sense to return a Point, handle in subclass + raise ValueError( + "%s.__new__ requires two unique Points." % cls.__name__) + + return GeometryEntity.__new__(cls, p1, p2, **kwargs) + + ambient_dimension = 3 + + @property + def direction_ratio(self): + """The direction ratio of a given line in 3D. + + See Also + ======== + + sympy.geometry.line.Line3D.equation + + Examples + ======== + + >>> from sympy import Point3D, Line3D + >>> p1, p2 = Point3D(0, 0, 0), Point3D(5, 3, 1) + >>> l = Line3D(p1, p2) + >>> l.direction_ratio + [5, 3, 1] + """ + p1, p2 = self.points + return p1.direction_ratio(p2) + + @property + def direction_cosine(self): + """The normalized direction ratio of a given line in 3D. + + See Also + ======== + + sympy.geometry.line.Line3D.equation + + Examples + ======== + + >>> from sympy import Point3D, Line3D + >>> p1, p2 = Point3D(0, 0, 0), Point3D(5, 3, 1) + >>> l = Line3D(p1, p2) + >>> l.direction_cosine + [sqrt(35)/7, 3*sqrt(35)/35, sqrt(35)/35] + >>> sum(i**2 for i in _) + 1 + """ + p1, p2 = self.points + return p1.direction_cosine(p2) + + +class Line3D(LinearEntity3D, Line): + """An infinite 3D line in space. + + A line is declared with two distinct points or a point and direction_ratio + as defined using keyword `direction_ratio`. + + Parameters + ========== + + p1 : Point3D + pt : Point3D + direction_ratio : list + + See Also + ======== + + sympy.geometry.point.Point3D + sympy.geometry.line.Line + sympy.geometry.line.Line2D + + Examples + ======== + + >>> from sympy import Line3D, Point3D + >>> L = Line3D(Point3D(2, 3, 4), Point3D(3, 5, 1)) + >>> L + Line3D(Point3D(2, 3, 4), Point3D(3, 5, 1)) + >>> L.points + (Point3D(2, 3, 4), Point3D(3, 5, 1)) + """ + def __new__(cls, p1, pt=None, direction_ratio=(), **kwargs): + if isinstance(p1, LinearEntity3D): + if pt is not None: + raise ValueError('if p1 is a LinearEntity, pt must be None.') + p1, pt = p1.args + else: + p1 = Point(p1, dim=3) + if pt is not None and len(direction_ratio) == 0: + pt = Point(pt, dim=3) + elif len(direction_ratio) == 3 and pt is None: + pt = Point3D(p1.x + direction_ratio[0], p1.y + direction_ratio[1], + p1.z + direction_ratio[2]) + else: + raise ValueError('A 2nd Point or keyword "direction_ratio" must ' + 'be used.') + + return LinearEntity3D.__new__(cls, p1, pt, **kwargs) + + def equation(self, x='x', y='y', z='z'): + """Return the equations that define the line in 3D. + + Parameters + ========== + + x : str, optional + The name to use for the x-axis, default value is 'x'. + y : str, optional + The name to use for the y-axis, default value is 'y'. + z : str, optional + The name to use for the z-axis, default value is 'z'. + + Returns + ======= + + equation : Tuple of simultaneous equations + + Examples + ======== + + >>> from sympy import Point3D, Line3D, solve + >>> from sympy.abc import x, y, z + >>> p1, p2 = Point3D(1, 0, 0), Point3D(5, 3, 0) + >>> l1 = Line3D(p1, p2) + >>> eq = l1.equation(x, y, z); eq + (-3*x + 4*y + 3, z) + >>> solve(eq.subs(z, 0), (x, y, z)) + {x: 4*y/3 + 1} + """ + x, y, z, k = [_symbol(i, real=True) for i in (x, y, z, 'k')] + p1, p2 = self.points + d1, d2, d3 = p1.direction_ratio(p2) + x1, y1, z1 = p1 + eqs = [-d1*k + x - x1, -d2*k + y - y1, -d3*k + z - z1] + # eliminate k from equations by solving first eq with k for k + for i, e in enumerate(eqs): + if e.has(k): + kk = solve(e, k)[0] + eqs.pop(i) + break + return Tuple(*[i.subs(k, kk).as_numer_denom()[0] for i in eqs]) + + def distance(self, other): + """ + Finds the shortest distance between a line and another object. + + Parameters + ========== + + Point3D, Line3D, Plane, tuple, list + + Returns + ======= + + distance + + Notes + ===== + + This method accepts only 3D entities as it's parameter + + Tuples and lists are converted to Point3D and therefore must be of + length 3, 2 or 1. + + NotImplementedError is raised if `other` is not an instance of one + of the specified classes: Point3D, Line3D, or Plane. + + Examples + ======== + + >>> from sympy.geometry import Line3D + >>> l1 = Line3D((0, 0, 0), (0, 0, 1)) + >>> l2 = Line3D((0, 1, 0), (1, 1, 1)) + >>> l1.distance(l2) + 1 + + The computed distance may be symbolic, too: + + >>> from sympy.abc import x, y + >>> l1 = Line3D((0, 0, 0), (0, 0, 1)) + >>> l2 = Line3D((0, x, 0), (y, x, 1)) + >>> l1.distance(l2) + Abs(x*y)/Abs(sqrt(y**2)) + + """ + + from .plane import Plane # Avoid circular import + + if isinstance(other, (tuple, list)): + try: + other = Point3D(other) + except ValueError: + pass + + if isinstance(other, Point3D): + return super().distance(other) + + if isinstance(other, Line3D): + if self == other: + return S.Zero + if self.is_parallel(other): + return super().distance(other.p1) + + # Skew lines + self_direction = Matrix(self.direction_ratio) + other_direction = Matrix(other.direction_ratio) + normal = self_direction.cross(other_direction) + plane_through_self = Plane(p1=self.p1, normal_vector=normal) + return other.p1.distance(plane_through_self) + + if isinstance(other, Plane): + return other.distance(self) + + msg = f"{other} has type {type(other)}, which is unsupported" + raise NotImplementedError(msg) + + +class Ray3D(LinearEntity3D, Ray): + """ + A Ray is a semi-line in the space with a source point and a direction. + + Parameters + ========== + + p1 : Point3D + The source of the Ray + p2 : Point or a direction vector + direction_ratio: Determines the direction in which the Ray propagates. + + + Attributes + ========== + + source + xdirection + ydirection + zdirection + + See Also + ======== + + sympy.geometry.point.Point3D, Line3D + + + Examples + ======== + + >>> from sympy import Point3D, Ray3D + >>> r = Ray3D(Point3D(2, 3, 4), Point3D(3, 5, 0)) + >>> r + Ray3D(Point3D(2, 3, 4), Point3D(3, 5, 0)) + >>> r.points + (Point3D(2, 3, 4), Point3D(3, 5, 0)) + >>> r.source + Point3D(2, 3, 4) + >>> r.xdirection + oo + >>> r.ydirection + oo + >>> r.direction_ratio + [1, 2, -4] + + """ + def __new__(cls, p1, pt=None, direction_ratio=(), **kwargs): + if isinstance(p1, LinearEntity3D): + if pt is not None: + raise ValueError('If p1 is a LinearEntity, pt must be None') + p1, pt = p1.args + else: + p1 = Point(p1, dim=3) + if pt is not None and len(direction_ratio) == 0: + pt = Point(pt, dim=3) + elif len(direction_ratio) == 3 and pt is None: + pt = Point3D(p1.x + direction_ratio[0], p1.y + direction_ratio[1], + p1.z + direction_ratio[2]) + else: + raise ValueError(filldedent(''' + A 2nd Point or keyword "direction_ratio" must be used. + ''')) + + return LinearEntity3D.__new__(cls, p1, pt, **kwargs) + + @property + def xdirection(self): + """The x direction of the ray. + + Positive infinity if the ray points in the positive x direction, + negative infinity if the ray points in the negative x direction, + or 0 if the ray is vertical. + + See Also + ======== + + ydirection + + Examples + ======== + + >>> from sympy import Point3D, Ray3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(0, -1, 0) + >>> r1, r2 = Ray3D(p1, p2), Ray3D(p1, p3) + >>> r1.xdirection + oo + >>> r2.xdirection + 0 + + """ + if self.p1.x < self.p2.x: + return S.Infinity + elif self.p1.x == self.p2.x: + return S.Zero + else: + return S.NegativeInfinity + + @property + def ydirection(self): + """The y direction of the ray. + + Positive infinity if the ray points in the positive y direction, + negative infinity if the ray points in the negative y direction, + or 0 if the ray is horizontal. + + See Also + ======== + + xdirection + + Examples + ======== + + >>> from sympy import Point3D, Ray3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(-1, -1, -1), Point3D(-1, 0, 0) + >>> r1, r2 = Ray3D(p1, p2), Ray3D(p1, p3) + >>> r1.ydirection + -oo + >>> r2.ydirection + 0 + + """ + if self.p1.y < self.p2.y: + return S.Infinity + elif self.p1.y == self.p2.y: + return S.Zero + else: + return S.NegativeInfinity + + @property + def zdirection(self): + """The z direction of the ray. + + Positive infinity if the ray points in the positive z direction, + negative infinity if the ray points in the negative z direction, + or 0 if the ray is horizontal. + + See Also + ======== + + xdirection + + Examples + ======== + + >>> from sympy import Point3D, Ray3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(-1, -1, -1), Point3D(-1, 0, 0) + >>> r1, r2 = Ray3D(p1, p2), Ray3D(p1, p3) + >>> r1.ydirection + -oo + >>> r2.ydirection + 0 + >>> r2.zdirection + 0 + + """ + if self.p1.z < self.p2.z: + return S.Infinity + elif self.p1.z == self.p2.z: + return S.Zero + else: + return S.NegativeInfinity + + +class Segment3D(LinearEntity3D, Segment): + """A line segment in a 3D space. + + Parameters + ========== + + p1 : Point3D + p2 : Point3D + + Attributes + ========== + + length : number or SymPy expression + midpoint : Point3D + + See Also + ======== + + sympy.geometry.point.Point3D, Line3D + + Examples + ======== + + >>> from sympy import Point3D, Segment3D + >>> Segment3D((1, 0, 0), (1, 1, 1)) # tuples are interpreted as pts + Segment3D(Point3D(1, 0, 0), Point3D(1, 1, 1)) + >>> s = Segment3D(Point3D(4, 3, 9), Point3D(1, 1, 7)); s + Segment3D(Point3D(4, 3, 9), Point3D(1, 1, 7)) + >>> s.points + (Point3D(4, 3, 9), Point3D(1, 1, 7)) + >>> s.length + sqrt(17) + >>> s.midpoint + Point3D(5/2, 2, 8) + + """ + def __new__(cls, p1, p2, **kwargs): + p1 = Point(p1, dim=3) + p2 = Point(p2, dim=3) + + if p1 == p2: + return p1 + + return LinearEntity3D.__new__(cls, p1, p2, **kwargs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/parabola.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/parabola.py new file mode 100644 index 0000000000000000000000000000000000000000..183c593785bb610e6f451a0c87abb2aa34d22494 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/parabola.py @@ -0,0 +1,422 @@ +"""Parabolic geometrical entity. + +Contains +* Parabola + +""" + +from sympy.core import S +from sympy.core.sorting import ordered +from sympy.core.symbol import _symbol, symbols +from sympy.geometry.entity import GeometryEntity, GeometrySet +from sympy.geometry.point import Point, Point2D +from sympy.geometry.line import Line, Line2D, Ray2D, Segment2D, LinearEntity3D +from sympy.geometry.ellipse import Ellipse +from sympy.functions import sign +from sympy.simplify.simplify import simplify +from sympy.solvers.solvers import solve + + +class Parabola(GeometrySet): + """A parabolic GeometryEntity. + + A parabola is declared with a point, that is called 'focus', and + a line, that is called 'directrix'. + Only vertical or horizontal parabolas are currently supported. + + Parameters + ========== + + focus : Point + Default value is Point(0, 0) + directrix : Line + + Attributes + ========== + + focus + directrix + axis of symmetry + focal length + p parameter + vertex + eccentricity + + Raises + ====== + ValueError + When `focus` is not a two dimensional point. + When `focus` is a point of directrix. + NotImplementedError + When `directrix` is neither horizontal nor vertical. + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7,8))) + >>> p1.focus + Point2D(0, 0) + >>> p1.directrix + Line2D(Point2D(5, 8), Point2D(7, 8)) + + """ + + def __new__(cls, focus=None, directrix=None, **kwargs): + + if focus: + focus = Point(focus, dim=2) + else: + focus = Point(0, 0) + + directrix = Line(directrix) + + if directrix.contains(focus): + raise ValueError('The focus must not be a point of directrix') + + return GeometryEntity.__new__(cls, focus, directrix, **kwargs) + + @property + def ambient_dimension(self): + """Returns the ambient dimension of parabola. + + Returns + ======= + + ambient_dimension : integer + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> f1 = Point(0, 0) + >>> p1 = Parabola(f1, Line(Point(5, 8), Point(7, 8))) + >>> p1.ambient_dimension + 2 + + """ + return 2 + + @property + def axis_of_symmetry(self): + """Return the axis of symmetry of the parabola: a line + perpendicular to the directrix passing through the focus. + + Returns + ======= + + axis_of_symmetry : Line + + See Also + ======== + + sympy.geometry.line.Line + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) + >>> p1.axis_of_symmetry + Line2D(Point2D(0, 0), Point2D(0, 1)) + + """ + return self.directrix.perpendicular_line(self.focus) + + @property + def directrix(self): + """The directrix of the parabola. + + Returns + ======= + + directrix : Line + + See Also + ======== + + sympy.geometry.line.Line + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> l1 = Line(Point(5, 8), Point(7, 8)) + >>> p1 = Parabola(Point(0, 0), l1) + >>> p1.directrix + Line2D(Point2D(5, 8), Point2D(7, 8)) + + """ + return self.args[1] + + @property + def eccentricity(self): + """The eccentricity of the parabola. + + Returns + ======= + + eccentricity : number + + A parabola may also be characterized as a conic section with an + eccentricity of 1. As a consequence of this, all parabolas are + similar, meaning that while they can be different sizes, + they are all the same shape. + + See Also + ======== + + https://en.wikipedia.org/wiki/Parabola + + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) + >>> p1.eccentricity + 1 + + Notes + ----- + The eccentricity for every Parabola is 1 by definition. + + """ + return S.One + + def equation(self, x='x', y='y'): + """The equation of the parabola. + + Parameters + ========== + x : str, optional + Label for the x-axis. Default value is 'x'. + y : str, optional + Label for the y-axis. Default value is 'y'. + + Returns + ======= + equation : SymPy expression + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) + >>> p1.equation() + -x**2 - 16*y + 64 + >>> p1.equation('f') + -f**2 - 16*y + 64 + >>> p1.equation(y='z') + -x**2 - 16*z + 64 + + """ + x = _symbol(x, real=True) + y = _symbol(y, real=True) + + m = self.directrix.slope + if m is S.Infinity: + t1 = 4 * (self.p_parameter) * (x - self.vertex.x) + t2 = (y - self.vertex.y)**2 + elif m == 0: + t1 = 4 * (self.p_parameter) * (y - self.vertex.y) + t2 = (x - self.vertex.x)**2 + else: + a, b = self.focus + c, d = self.directrix.coefficients[:2] + t1 = (x - a)**2 + (y - b)**2 + t2 = self.directrix.equation(x, y)**2/(c**2 + d**2) + return t1 - t2 + + @property + def focal_length(self): + """The focal length of the parabola. + + Returns + ======= + + focal_lenght : number or symbolic expression + + Notes + ===== + + The distance between the vertex and the focus + (or the vertex and directrix), measured along the axis + of symmetry, is the "focal length". + + See Also + ======== + + https://en.wikipedia.org/wiki/Parabola + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) + >>> p1.focal_length + 4 + + """ + distance = self.directrix.distance(self.focus) + focal_length = distance/2 + + return focal_length + + @property + def focus(self): + """The focus of the parabola. + + Returns + ======= + + focus : Point + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> f1 = Point(0, 0) + >>> p1 = Parabola(f1, Line(Point(5, 8), Point(7, 8))) + >>> p1.focus + Point2D(0, 0) + + """ + return self.args[0] + + def intersection(self, o): + """The intersection of the parabola and another geometrical entity `o`. + + Parameters + ========== + + o : GeometryEntity, LinearEntity + + Returns + ======= + + intersection : list of GeometryEntity objects + + Examples + ======== + + >>> from sympy import Parabola, Point, Ellipse, Line, Segment + >>> p1 = Point(0,0) + >>> l1 = Line(Point(1, -2), Point(-1,-2)) + >>> parabola1 = Parabola(p1, l1) + >>> parabola1.intersection(Ellipse(Point(0, 0), 2, 5)) + [Point2D(-2, 0), Point2D(2, 0)] + >>> parabola1.intersection(Line(Point(-7, 3), Point(12, 3))) + [Point2D(-4, 3), Point2D(4, 3)] + >>> parabola1.intersection(Segment((-12, -65), (14, -68))) + [] + + """ + x, y = symbols('x y', real=True) + parabola_eq = self.equation() + if isinstance(o, Parabola): + if o in self: + return [o] + else: + return list(ordered([Point(i) for i in solve( + [parabola_eq, o.equation()], [x, y], set=True)[1]])) + elif isinstance(o, Point2D): + if simplify(parabola_eq.subs([(x, o._args[0]), (y, o._args[1])])) == 0: + return [o] + else: + return [] + elif isinstance(o, (Segment2D, Ray2D)): + result = solve([parabola_eq, + Line2D(o.points[0], o.points[1]).equation()], + [x, y], set=True)[1] + return list(ordered([Point2D(i) for i in result if i in o])) + elif isinstance(o, (Line2D, Ellipse)): + return list(ordered([Point2D(i) for i in solve( + [parabola_eq, o.equation()], [x, y], set=True)[1]])) + elif isinstance(o, LinearEntity3D): + raise TypeError('Entity must be two dimensional, not three dimensional') + else: + raise TypeError('Wrong type of argument were put') + + @property + def p_parameter(self): + """P is a parameter of parabola. + + Returns + ======= + + p : number or symbolic expression + + Notes + ===== + + The absolute value of p is the focal length. The sign on p tells + which way the parabola faces. Vertical parabolas that open up + and horizontal that open right, give a positive value for p. + Vertical parabolas that open down and horizontal that open left, + give a negative value for p. + + + See Also + ======== + + https://www.sparknotes.com/math/precalc/conicsections/section2/ + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) + >>> p1.p_parameter + -4 + + """ + m = self.directrix.slope + if m is S.Infinity: + x = self.directrix.coefficients[2] + p = sign(self.focus.args[0] + x) + elif m == 0: + y = self.directrix.coefficients[2] + p = sign(self.focus.args[1] + y) + else: + d = self.directrix.projection(self.focus) + p = sign(self.focus.x - d.x) + return p * self.focal_length + + @property + def vertex(self): + """The vertex of the parabola. + + Returns + ======= + + vertex : Point + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Parabola, Point, Line + >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) + >>> p1.vertex + Point2D(0, 4) + + """ + focus = self.focus + m = self.directrix.slope + if m is S.Infinity: + vertex = Point(focus.args[0] - self.p_parameter, focus.args[1]) + elif m == 0: + vertex = Point(focus.args[0], focus.args[1] - self.p_parameter) + else: + vertex = self.axis_of_symmetry.intersection(self)[0] + return vertex diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/plane.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/plane.py new file mode 100644 index 0000000000000000000000000000000000000000..509dc4be5dc41c5df7c33561fdbe5bb0b6620352 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/plane.py @@ -0,0 +1,878 @@ +"""Geometrical Planes. + +Contains +======== +Plane + +""" + +from sympy.core import Dummy, Rational, S, Symbol +from sympy.core.symbol import _symbol +from sympy.functions.elementary.trigonometric import cos, sin, acos, asin, sqrt +from .entity import GeometryEntity +from .line import (Line, Ray, Segment, Line3D, LinearEntity, LinearEntity3D, + Ray3D, Segment3D) +from .point import Point, Point3D +from sympy.matrices import Matrix +from sympy.polys.polytools import cancel +from sympy.solvers import solve, linsolve +from sympy.utilities.iterables import uniq, is_sequence +from sympy.utilities.misc import filldedent, func_name, Undecidable + +from mpmath.libmp.libmpf import prec_to_dps + +import random + + +x, y, z, t = [Dummy('plane_dummy') for i in range(4)] + + +class Plane(GeometryEntity): + """ + A plane is a flat, two-dimensional surface. A plane is the two-dimensional + analogue of a point (zero-dimensions), a line (one-dimension) and a solid + (three-dimensions). A plane can generally be constructed by two types of + inputs. They are: + - three non-collinear points + - a point and the plane's normal vector + + Attributes + ========== + + p1 + normal_vector + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> Plane(Point3D(1, 1, 1), Point3D(2, 3, 4), Point3D(2, 2, 2)) + Plane(Point3D(1, 1, 1), (-1, 2, -1)) + >>> Plane((1, 1, 1), (2, 3, 4), (2, 2, 2)) + Plane(Point3D(1, 1, 1), (-1, 2, -1)) + >>> Plane(Point3D(1, 1, 1), normal_vector=(1,4,7)) + Plane(Point3D(1, 1, 1), (1, 4, 7)) + + """ + def __new__(cls, p1, a=None, b=None, **kwargs): + p1 = Point3D(p1, dim=3) + if a and b: + p2 = Point(a, dim=3) + p3 = Point(b, dim=3) + if Point3D.are_collinear(p1, p2, p3): + raise ValueError('Enter three non-collinear points') + a = p1.direction_ratio(p2) + b = p1.direction_ratio(p3) + normal_vector = tuple(Matrix(a).cross(Matrix(b))) + else: + a = kwargs.pop('normal_vector', a) + evaluate = kwargs.get('evaluate', True) + if is_sequence(a) and len(a) == 3: + normal_vector = Point3D(a).args if evaluate else a + else: + raise ValueError(filldedent(''' + Either provide 3 3D points or a point with a + normal vector expressed as a sequence of length 3''')) + if all(coord.is_zero for coord in normal_vector): + raise ValueError('Normal vector cannot be zero vector') + return GeometryEntity.__new__(cls, p1, normal_vector, **kwargs) + + def __contains__(self, o): + k = self.equation(x, y, z) + if isinstance(o, (LinearEntity, LinearEntity3D)): + d = Point3D(o.arbitrary_point(t)) + e = k.subs([(x, d.x), (y, d.y), (z, d.z)]) + return e.equals(0) + try: + o = Point(o, dim=3, strict=True) + d = k.xreplace(dict(zip((x, y, z), o.args))) + return d.equals(0) + except TypeError: + return False + + def _eval_evalf(self, prec=15, **options): + pt, tup = self.args + dps = prec_to_dps(prec) + pt = pt.evalf(n=dps, **options) + tup = tuple([i.evalf(n=dps, **options) for i in tup]) + return self.func(pt, normal_vector=tup, evaluate=False) + + def angle_between(self, o): + """Angle between the plane and other geometric entity. + + Parameters + ========== + + LinearEntity3D, Plane. + + Returns + ======= + + angle : angle in radians + + Notes + ===== + + This method accepts only 3D entities as it's parameter, but if you want + to calculate the angle between a 2D entity and a plane you should + first convert to a 3D entity by projecting onto a desired plane and + then proceed to calculate the angle. + + Examples + ======== + + >>> from sympy import Point3D, Line3D, Plane + >>> a = Plane(Point3D(1, 2, 2), normal_vector=(1, 2, 3)) + >>> b = Line3D(Point3D(1, 3, 4), Point3D(2, 2, 2)) + >>> a.angle_between(b) + -asin(sqrt(21)/6) + + """ + if isinstance(o, LinearEntity3D): + a = Matrix(self.normal_vector) + b = Matrix(o.direction_ratio) + c = a.dot(b) + d = sqrt(sum(i**2 for i in self.normal_vector)) + e = sqrt(sum(i**2 for i in o.direction_ratio)) + return asin(c/(d*e)) + if isinstance(o, Plane): + a = Matrix(self.normal_vector) + b = Matrix(o.normal_vector) + c = a.dot(b) + d = sqrt(sum(i**2 for i in self.normal_vector)) + e = sqrt(sum(i**2 for i in o.normal_vector)) + return acos(c/(d*e)) + + + def arbitrary_point(self, u=None, v=None): + """ Returns an arbitrary point on the Plane. If given two + parameters, the point ranges over the entire plane. If given 1 + or no parameters, returns a point with one parameter which, + when varying from 0 to 2*pi, moves the point in a circle of + radius 1 about p1 of the Plane. + + Examples + ======== + + >>> from sympy import Plane, Ray + >>> from sympy.abc import u, v, t, r + >>> p = Plane((1, 1, 1), normal_vector=(1, 0, 0)) + >>> p.arbitrary_point(u, v) + Point3D(1, u + 1, v + 1) + >>> p.arbitrary_point(t) + Point3D(1, cos(t) + 1, sin(t) + 1) + + While arbitrary values of u and v can move the point anywhere in + the plane, the single-parameter point can be used to construct a + ray whose arbitrary point can be located at angle t and radius + r from p.p1: + + >>> Ray(p.p1, _).arbitrary_point(r) + Point3D(1, r*cos(t) + 1, r*sin(t) + 1) + + Returns + ======= + + Point3D + + """ + circle = v is None + if circle: + u = _symbol(u or 't', real=True) + else: + u = _symbol(u or 'u', real=True) + v = _symbol(v or 'v', real=True) + x, y, z = self.normal_vector + a, b, c = self.p1.args + # x1, y1, z1 is a nonzero vector parallel to the plane + if x.is_zero and y.is_zero: + x1, y1, z1 = S.One, S.Zero, S.Zero + else: + x1, y1, z1 = -y, x, S.Zero + # x2, y2, z2 is also parallel to the plane, and orthogonal to x1, y1, z1 + x2, y2, z2 = tuple(Matrix((x, y, z)).cross(Matrix((x1, y1, z1)))) + if circle: + x1, y1, z1 = (w/sqrt(x1**2 + y1**2 + z1**2) for w in (x1, y1, z1)) + x2, y2, z2 = (w/sqrt(x2**2 + y2**2 + z2**2) for w in (x2, y2, z2)) + p = Point3D(a + x1*cos(u) + x2*sin(u), \ + b + y1*cos(u) + y2*sin(u), \ + c + z1*cos(u) + z2*sin(u)) + else: + p = Point3D(a + x1*u + x2*v, b + y1*u + y2*v, c + z1*u + z2*v) + return p + + + @staticmethod + def are_concurrent(*planes): + """Is a sequence of Planes concurrent? + + Two or more Planes are concurrent if their intersections + are a common line. + + Parameters + ========== + + planes: list + + Returns + ======= + + Boolean + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> a = Plane(Point3D(5, 0, 0), normal_vector=(1, -1, 1)) + >>> b = Plane(Point3D(0, -2, 0), normal_vector=(3, 1, 1)) + >>> c = Plane(Point3D(0, -1, 0), normal_vector=(5, -1, 9)) + >>> Plane.are_concurrent(a, b) + True + >>> Plane.are_concurrent(a, b, c) + False + + """ + planes = list(uniq(planes)) + for i in planes: + if not isinstance(i, Plane): + raise ValueError('All objects should be Planes but got %s' % i.func) + if len(planes) < 2: + return False + planes = list(planes) + first = planes.pop(0) + sol = first.intersection(planes[0]) + if sol == []: + return False + else: + line = sol[0] + for i in planes[1:]: + l = first.intersection(i) + if not l or l[0] not in line: + return False + return True + + + def distance(self, o): + """Distance between the plane and another geometric entity. + + Parameters + ========== + + Point3D, LinearEntity3D, Plane. + + Returns + ======= + + distance + + Notes + ===== + + This method accepts only 3D entities as it's parameter, but if you want + to calculate the distance between a 2D entity and a plane you should + first convert to a 3D entity by projecting onto a desired plane and + then proceed to calculate the distance. + + Examples + ======== + + >>> from sympy import Point3D, Line3D, Plane + >>> a = Plane(Point3D(1, 1, 1), normal_vector=(1, 1, 1)) + >>> b = Point3D(1, 2, 3) + >>> a.distance(b) + sqrt(3) + >>> c = Line3D(Point3D(2, 3, 1), Point3D(1, 2, 2)) + >>> a.distance(c) + 0 + + """ + if self.intersection(o) != []: + return S.Zero + + if isinstance(o, (Segment3D, Ray3D)): + a, b = o.p1, o.p2 + pi, = self.intersection(Line3D(a, b)) + if pi in o: + return self.distance(pi) + elif a in Segment3D(pi, b): + return self.distance(a) + else: + assert isinstance(o, Segment3D) is True + return self.distance(b) + + # following code handles `Point3D`, `LinearEntity3D`, `Plane` + a = o if isinstance(o, Point3D) else o.p1 + n = Point3D(self.normal_vector).unit + d = (a - self.p1).dot(n) + return abs(d) + + + def equals(self, o): + """ + Returns True if self and o are the same mathematical entities. + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> a = Plane(Point3D(1, 2, 3), normal_vector=(1, 1, 1)) + >>> b = Plane(Point3D(1, 2, 3), normal_vector=(2, 2, 2)) + >>> c = Plane(Point3D(1, 2, 3), normal_vector=(-1, 4, 6)) + >>> a.equals(a) + True + >>> a.equals(b) + True + >>> a.equals(c) + False + """ + if isinstance(o, Plane): + a = self.equation() + b = o.equation() + return cancel(a/b).is_constant() + else: + return False + + + def equation(self, x=None, y=None, z=None): + """The equation of the Plane. + + Examples + ======== + + >>> from sympy import Point3D, Plane + >>> a = Plane(Point3D(1, 1, 2), Point3D(2, 4, 7), Point3D(3, 5, 1)) + >>> a.equation() + -23*x + 11*y - 2*z + 16 + >>> a = Plane(Point3D(1, 4, 2), normal_vector=(6, 6, 6)) + >>> a.equation() + 6*x + 6*y + 6*z - 42 + + """ + x, y, z = [i if i else Symbol(j, real=True) for i, j in zip((x, y, z), 'xyz')] + a = Point3D(x, y, z) + b = self.p1.direction_ratio(a) + c = self.normal_vector + return (sum(i*j for i, j in zip(b, c))) + + + def intersection(self, o): + """ The intersection with other geometrical entity. + + Parameters + ========== + + Point, Point3D, LinearEntity, LinearEntity3D, Plane + + Returns + ======= + + List + + Examples + ======== + + >>> from sympy import Point3D, Line3D, Plane + >>> a = Plane(Point3D(1, 2, 3), normal_vector=(1, 1, 1)) + >>> b = Point3D(1, 2, 3) + >>> a.intersection(b) + [Point3D(1, 2, 3)] + >>> c = Line3D(Point3D(1, 4, 7), Point3D(2, 2, 2)) + >>> a.intersection(c) + [Point3D(2, 2, 2)] + >>> d = Plane(Point3D(6, 0, 0), normal_vector=(2, -5, 3)) + >>> e = Plane(Point3D(2, 0, 0), normal_vector=(3, 4, -3)) + >>> d.intersection(e) + [Line3D(Point3D(78/23, -24/23, 0), Point3D(147/23, 321/23, 23))] + + """ + if not isinstance(o, GeometryEntity): + o = Point(o, dim=3) + if isinstance(o, Point): + if o in self: + return [o] + else: + return [] + if isinstance(o, (LinearEntity, LinearEntity3D)): + # recast to 3D + p1, p2 = o.p1, o.p2 + if isinstance(o, Segment): + o = Segment3D(p1, p2) + elif isinstance(o, Ray): + o = Ray3D(p1, p2) + elif isinstance(o, Line): + o = Line3D(p1, p2) + else: + raise ValueError('unhandled linear entity: %s' % o.func) + if o in self: + return [o] + else: + a = Point3D(o.arbitrary_point(t)) + p1, n = self.p1, Point3D(self.normal_vector) + + # TODO: Replace solve with solveset, when this line is tested + c = solve((a - p1).dot(n), t) + if not c: + return [] + else: + c = [i for i in c if i.is_real is not False] + if len(c) > 1: + c = [i for i in c if i.is_real] + if len(c) != 1: + raise Undecidable("not sure which point is real") + p = a.subs(t, c[0]) + if p not in o: + return [] # e.g. a segment might not intersect a plane + return [p] + if isinstance(o, Plane): + if self.equals(o): + return [self] + if self.is_parallel(o): + return [] + else: + x, y, z = map(Dummy, 'xyz') + a, b = Matrix([self.normal_vector]), Matrix([o.normal_vector]) + c = list(a.cross(b)) + d = self.equation(x, y, z) + e = o.equation(x, y, z) + result = list(linsolve([d, e], x, y, z))[0] + for i in (x, y, z): result = result.subs(i, 0) + return [Line3D(Point3D(result), direction_ratio=c)] + + + def is_coplanar(self, o): + """ Returns True if `o` is coplanar with self, else False. + + Examples + ======== + + >>> from sympy import Plane + >>> o = (0, 0, 0) + >>> p = Plane(o, (1, 1, 1)) + >>> p2 = Plane(o, (2, 2, 2)) + >>> p == p2 + False + >>> p.is_coplanar(p2) + True + """ + if isinstance(o, Plane): + return not cancel(self.equation(x, y, z)/o.equation(x, y, z)).has(x, y, z) + if isinstance(o, Point3D): + return o in self + elif isinstance(o, LinearEntity3D): + return all(i in self for i in self) + elif isinstance(o, GeometryEntity): # XXX should only be handling 2D objects now + return all(i == 0 for i in self.normal_vector[:2]) + + + def is_parallel(self, l): + """Is the given geometric entity parallel to the plane? + + Parameters + ========== + + LinearEntity3D or Plane + + Returns + ======= + + Boolean + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> a = Plane(Point3D(1,4,6), normal_vector=(2, 4, 6)) + >>> b = Plane(Point3D(3,1,3), normal_vector=(4, 8, 12)) + >>> a.is_parallel(b) + True + + """ + if isinstance(l, LinearEntity3D): + a = l.direction_ratio + b = self.normal_vector + return sum(i*j for i, j in zip(a, b)) == 0 + if isinstance(l, Plane): + a = Matrix(l.normal_vector) + b = Matrix(self.normal_vector) + return bool(a.cross(b).is_zero_matrix) + + + def is_perpendicular(self, l): + """Is the given geometric entity perpendicualar to the given plane? + + Parameters + ========== + + LinearEntity3D or Plane + + Returns + ======= + + Boolean + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> a = Plane(Point3D(1,4,6), normal_vector=(2, 4, 6)) + >>> b = Plane(Point3D(2, 2, 2), normal_vector=(-1, 2, -1)) + >>> a.is_perpendicular(b) + True + + """ + if isinstance(l, LinearEntity3D): + a = Matrix(l.direction_ratio) + b = Matrix(self.normal_vector) + if a.cross(b).is_zero_matrix: + return True + else: + return False + elif isinstance(l, Plane): + a = Matrix(l.normal_vector) + b = Matrix(self.normal_vector) + if a.dot(b) == 0: + return True + else: + return False + else: + return False + + @property + def normal_vector(self): + """Normal vector of the given plane. + + Examples + ======== + + >>> from sympy import Point3D, Plane + >>> a = Plane(Point3D(1, 1, 1), Point3D(2, 3, 4), Point3D(2, 2, 2)) + >>> a.normal_vector + (-1, 2, -1) + >>> a = Plane(Point3D(1, 1, 1), normal_vector=(1, 4, 7)) + >>> a.normal_vector + (1, 4, 7) + + """ + return self.args[1] + + @property + def p1(self): + """The only defining point of the plane. Others can be obtained from the + arbitrary_point method. + + See Also + ======== + + sympy.geometry.point.Point3D + + Examples + ======== + + >>> from sympy import Point3D, Plane + >>> a = Plane(Point3D(1, 1, 1), Point3D(2, 3, 4), Point3D(2, 2, 2)) + >>> a.p1 + Point3D(1, 1, 1) + + """ + return self.args[0] + + def parallel_plane(self, pt): + """ + Plane parallel to the given plane and passing through the point pt. + + Parameters + ========== + + pt: Point3D + + Returns + ======= + + Plane + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> a = Plane(Point3D(1, 4, 6), normal_vector=(2, 4, 6)) + >>> a.parallel_plane(Point3D(2, 3, 5)) + Plane(Point3D(2, 3, 5), (2, 4, 6)) + + """ + a = self.normal_vector + return Plane(pt, normal_vector=a) + + def perpendicular_line(self, pt): + """A line perpendicular to the given plane. + + Parameters + ========== + + pt: Point3D + + Returns + ======= + + Line3D + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> a = Plane(Point3D(1,4,6), normal_vector=(2, 4, 6)) + >>> a.perpendicular_line(Point3D(9, 8, 7)) + Line3D(Point3D(9, 8, 7), Point3D(11, 12, 13)) + + """ + a = self.normal_vector + return Line3D(pt, direction_ratio=a) + + def perpendicular_plane(self, *pts): + """ + Return a perpendicular passing through the given points. If the + direction ratio between the points is the same as the Plane's normal + vector then, to select from the infinite number of possible planes, + a third point will be chosen on the z-axis (or the y-axis + if the normal vector is already parallel to the z-axis). If less than + two points are given they will be supplied as follows: if no point is + given then pt1 will be self.p1; if a second point is not given it will + be a point through pt1 on a line parallel to the z-axis (if the normal + is not already the z-axis, otherwise on the line parallel to the + y-axis). + + Parameters + ========== + + pts: 0, 1 or 2 Point3D + + Returns + ======= + + Plane + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> a, b = Point3D(0, 0, 0), Point3D(0, 1, 0) + >>> Z = (0, 0, 1) + >>> p = Plane(a, normal_vector=Z) + >>> p.perpendicular_plane(a, b) + Plane(Point3D(0, 0, 0), (1, 0, 0)) + """ + if len(pts) > 2: + raise ValueError('No more than 2 pts should be provided.') + + pts = list(pts) + if len(pts) == 0: + pts.append(self.p1) + if len(pts) == 1: + x, y, z = self.normal_vector + if x == y == 0: + dir = (0, 1, 0) + else: + dir = (0, 0, 1) + pts.append(pts[0] + Point3D(*dir)) + + p1, p2 = [Point(i, dim=3) for i in pts] + l = Line3D(p1, p2) + n = Line3D(p1, direction_ratio=self.normal_vector) + if l in n: # XXX should an error be raised instead? + # there are infinitely many perpendicular planes; + x, y, z = self.normal_vector + if x == y == 0: + # the z axis is the normal so pick a pt on the y-axis + p3 = Point3D(0, 1, 0) # case 1 + else: + # else pick a pt on the z axis + p3 = Point3D(0, 0, 1) # case 2 + # in case that point is already given, move it a bit + if p3 in l: + p3 *= 2 # case 3 + else: + p3 = p1 + Point3D(*self.normal_vector) # case 4 + return Plane(p1, p2, p3) + + def projection_line(self, line): + """Project the given line onto the plane through the normal plane + containing the line. + + Parameters + ========== + + LinearEntity or LinearEntity3D + + Returns + ======= + + Point3D, Line3D, Ray3D or Segment3D + + Notes + ===== + + For the interaction between 2D and 3D lines(segments, rays), you should + convert the line to 3D by using this method. For example for finding the + intersection between a 2D and a 3D line, convert the 2D line to a 3D line + by projecting it on a required plane and then proceed to find the + intersection between those lines. + + Examples + ======== + + >>> from sympy import Plane, Line, Line3D, Point3D + >>> a = Plane(Point3D(1, 1, 1), normal_vector=(1, 1, 1)) + >>> b = Line(Point3D(1, 1), Point3D(2, 2)) + >>> a.projection_line(b) + Line3D(Point3D(4/3, 4/3, 1/3), Point3D(5/3, 5/3, -1/3)) + >>> c = Line3D(Point3D(1, 1, 1), Point3D(2, 2, 2)) + >>> a.projection_line(c) + Point3D(1, 1, 1) + + """ + if not isinstance(line, (LinearEntity, LinearEntity3D)): + raise NotImplementedError('Enter a linear entity only') + a, b = self.projection(line.p1), self.projection(line.p2) + if a == b: + # projection does not imply intersection so for + # this case (line parallel to plane's normal) we + # return the projection point + return a + if isinstance(line, (Line, Line3D)): + return Line3D(a, b) + if isinstance(line, (Ray, Ray3D)): + return Ray3D(a, b) + if isinstance(line, (Segment, Segment3D)): + return Segment3D(a, b) + + def projection(self, pt): + """Project the given point onto the plane along the plane normal. + + Parameters + ========== + + Point or Point3D + + Returns + ======= + + Point3D + + Examples + ======== + + >>> from sympy import Plane, Point3D + >>> A = Plane(Point3D(1, 1, 2), normal_vector=(1, 1, 1)) + + The projection is along the normal vector direction, not the z + axis, so (1, 1) does not project to (1, 1, 2) on the plane A: + + >>> b = Point3D(1, 1) + >>> A.projection(b) + Point3D(5/3, 5/3, 2/3) + >>> _ in A + True + + But the point (1, 1, 2) projects to (1, 1) on the XY-plane: + + >>> XY = Plane((0, 0, 0), (0, 0, 1)) + >>> XY.projection((1, 1, 2)) + Point3D(1, 1, 0) + """ + rv = Point(pt, dim=3) + if rv in self: + return rv + return self.intersection(Line3D(rv, rv + Point3D(self.normal_vector)))[0] + + def random_point(self, seed=None): + """ Returns a random point on the Plane. + + Returns + ======= + + Point3D + + Examples + ======== + + >>> from sympy import Plane + >>> p = Plane((1, 0, 0), normal_vector=(0, 1, 0)) + >>> r = p.random_point(seed=42) # seed value is optional + >>> r.n(3) + Point3D(2.29, 0, -1.35) + + The random point can be moved to lie on the circle of radius + 1 centered on p1: + + >>> c = p.p1 + (r - p.p1).unit + >>> c.distance(p.p1).equals(1) + True + """ + if seed is not None: + rng = random.Random(seed) + else: + rng = random + params = { + x: 2*Rational(rng.gauss(0, 1)) - 1, + y: 2*Rational(rng.gauss(0, 1)) - 1} + return self.arbitrary_point(x, y).subs(params) + + def parameter_value(self, other, u, v=None): + """Return the parameter(s) corresponding to the given point. + + Examples + ======== + + >>> from sympy import pi, Plane + >>> from sympy.abc import t, u, v + >>> p = Plane((2, 0, 0), (0, 0, 1), (0, 1, 0)) + + By default, the parameter value returned defines a point + that is a distance of 1 from the Plane's p1 value and + in line with the given point: + + >>> on_circle = p.arbitrary_point(t).subs(t, pi/4) + >>> on_circle.distance(p.p1) + 1 + >>> p.parameter_value(on_circle, t) + {t: pi/4} + + Moving the point twice as far from p1 does not change + the parameter value: + + >>> off_circle = p.p1 + (on_circle - p.p1)*2 + >>> off_circle.distance(p.p1) + 2 + >>> p.parameter_value(off_circle, t) + {t: pi/4} + + If the 2-value parameter is desired, supply the two + parameter symbols and a replacement dictionary will + be returned: + + >>> p.parameter_value(on_circle, u, v) + {u: sqrt(10)/10, v: sqrt(10)/30} + >>> p.parameter_value(off_circle, u, v) + {u: sqrt(10)/5, v: sqrt(10)/15} + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if not isinstance(other, Point): + raise ValueError("other must be a point") + if other == self.p1: + return other + if isinstance(u, Symbol) and v is None: + delta = self.arbitrary_point(u) - self.p1 + eq = delta - (other - self.p1).unit + sol = solve(eq, u, dict=True) + elif isinstance(u, Symbol) and isinstance(v, Symbol): + pt = self.arbitrary_point(u, v) + sol = solve(pt - other, (u, v), dict=True) + else: + raise ValueError('expecting 1 or 2 symbols') + if not sol: + raise ValueError("Given point is not on %s" % func_name(self)) + return sol[0] # {t: tval} or {u: uval, v: vval} + + @property + def ambient_dimension(self): + return self.p1.ambient_dimension diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/point.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/point.py new file mode 100644 index 0000000000000000000000000000000000000000..19e6c566f06de4df086912470dc35d0f4af3bd38 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/point.py @@ -0,0 +1,1378 @@ +"""Geometrical Points. + +Contains +======== +Point +Point2D +Point3D + +When methods of Point require 1 or more points as arguments, they +can be passed as a sequence of coordinates or Points: + +>>> from sympy import Point +>>> Point(1, 1).is_collinear((2, 2), (3, 4)) +False +>>> Point(1, 1).is_collinear(Point(2, 2), Point(3, 4)) +False + +""" + +import warnings + +from sympy.core import S, sympify, Expr +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.numbers import Float +from sympy.core.parameters import global_parameters +from sympy.simplify.simplify import nsimplify, simplify +from sympy.geometry.exceptions import GeometryError +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.complexes import im +from sympy.functions.elementary.trigonometric import cos, sin +from sympy.matrices import Matrix +from sympy.matrices.expressions import Transpose +from sympy.utilities.iterables import uniq, is_sequence +from sympy.utilities.misc import filldedent, func_name, Undecidable + +from .entity import GeometryEntity + +from mpmath.libmp.libmpf import prec_to_dps + + +class Point(GeometryEntity): + """A point in a n-dimensional Euclidean space. + + Parameters + ========== + + coords : sequence of n-coordinate values. In the special + case where n=2 or 3, a Point2D or Point3D will be created + as appropriate. + evaluate : if `True` (default), all floats are turn into + exact types. + dim : number of coordinates the point should have. If coordinates + are unspecified, they are padded with zeros. + on_morph : indicates what should happen when the number of + coordinates of a point need to be changed by adding or + removing zeros. Possible values are `'warn'`, `'error'`, or + `ignore` (default). No warning or error is given when `*args` + is empty and `dim` is given. An error is always raised when + trying to remove nonzero coordinates. + + + Attributes + ========== + + length + origin: A `Point` representing the origin of the + appropriately-dimensioned space. + + Raises + ====== + + TypeError : When instantiating with anything but a Point or sequence + ValueError : when instantiating with a sequence with length < 2 or + when trying to reduce dimensions if keyword `on_morph='error'` is + set. + + See Also + ======== + + sympy.geometry.line.Segment : Connects two Points + + Examples + ======== + + >>> from sympy import Point + >>> from sympy.abc import x + >>> Point(1, 2, 3) + Point3D(1, 2, 3) + >>> Point([1, 2]) + Point2D(1, 2) + >>> Point(0, x) + Point2D(0, x) + >>> Point(dim=4) + Point(0, 0, 0, 0) + + Floats are automatically converted to Rational unless the + evaluate flag is False: + + >>> Point(0.5, 0.25) + Point2D(1/2, 1/4) + >>> Point(0.5, 0.25, evaluate=False) + Point2D(0.5, 0.25) + + """ + + is_Point = True + + def __new__(cls, *args, **kwargs): + evaluate = kwargs.get('evaluate', global_parameters.evaluate) + on_morph = kwargs.get('on_morph', 'ignore') + + # unpack into coords + coords = args[0] if len(args) == 1 else args + + # check args and handle quickly handle Point instances + if isinstance(coords, Point): + # even if we're mutating the dimension of a point, we + # don't reevaluate its coordinates + evaluate = False + if len(coords) == kwargs.get('dim', len(coords)): + return coords + + if not is_sequence(coords): + raise TypeError(filldedent(''' + Expecting sequence of coordinates, not `{}`''' + .format(func_name(coords)))) + # A point where only `dim` is specified is initialized + # to zeros. + if len(coords) == 0 and kwargs.get('dim', None): + coords = (S.Zero,)*kwargs.get('dim') + + coords = Tuple(*coords) + dim = kwargs.get('dim', len(coords)) + + if len(coords) < 2: + raise ValueError(filldedent(''' + Point requires 2 or more coordinates or + keyword `dim` > 1.''')) + if len(coords) != dim: + message = ("Dimension of {} needs to be changed " + "from {} to {}.").format(coords, len(coords), dim) + if on_morph == 'ignore': + pass + elif on_morph == "error": + raise ValueError(message) + elif on_morph == 'warn': + warnings.warn(message, stacklevel=2) + else: + raise ValueError(filldedent(''' + on_morph value should be 'error', + 'warn' or 'ignore'.''')) + if any(coords[dim:]): + raise ValueError('Nonzero coordinates cannot be removed.') + if any(a.is_number and im(a).is_zero is False for a in coords): + raise ValueError('Imaginary coordinates are not permitted.') + if not all(isinstance(a, Expr) for a in coords): + raise TypeError('Coordinates must be valid SymPy expressions.') + + # pad with zeros appropriately + coords = coords[:dim] + (S.Zero,)*(dim - len(coords)) + + # Turn any Floats into rationals and simplify + # any expressions before we instantiate + if evaluate: + coords = coords.xreplace({ + f: simplify(nsimplify(f, rational=True)) + for f in coords.atoms(Float)}) + + # return 2D or 3D instances + if len(coords) == 2: + kwargs['_nocheck'] = True + return Point2D(*coords, **kwargs) + elif len(coords) == 3: + kwargs['_nocheck'] = True + return Point3D(*coords, **kwargs) + + # the general Point + return GeometryEntity.__new__(cls, *coords) + + def __abs__(self): + """Returns the distance between this point and the origin.""" + origin = Point([0]*len(self)) + return Point.distance(origin, self) + + def __add__(self, other): + """Add other to self by incrementing self's coordinates by + those of other. + + Notes + ===== + + >>> from sympy import Point + + When sequences of coordinates are passed to Point methods, they + are converted to a Point internally. This __add__ method does + not do that so if floating point values are used, a floating + point result (in terms of SymPy Floats) will be returned. + + >>> Point(1, 2) + (.1, .2) + Point2D(1.1, 2.2) + + If this is not desired, the `translate` method can be used or + another Point can be added: + + >>> Point(1, 2).translate(.1, .2) + Point2D(11/10, 11/5) + >>> Point(1, 2) + Point(.1, .2) + Point2D(11/10, 11/5) + + See Also + ======== + + sympy.geometry.point.Point.translate + + """ + try: + s, o = Point._normalize_dimension(self, Point(other, evaluate=False)) + except TypeError: + raise GeometryError("Don't know how to add {} and a Point object".format(other)) + + coords = [simplify(a + b) for a, b in zip(s, o)] + return Point(coords, evaluate=False) + + def __contains__(self, item): + return item in self.args + + def __truediv__(self, divisor): + """Divide point's coordinates by a factor.""" + divisor = sympify(divisor) + coords = [simplify(x/divisor) for x in self.args] + return Point(coords, evaluate=False) + + def __eq__(self, other): + if not isinstance(other, Point) or len(self.args) != len(other.args): + return False + return self.args == other.args + + def __getitem__(self, key): + return self.args[key] + + def __hash__(self): + return hash(self.args) + + def __iter__(self): + return self.args.__iter__() + + def __len__(self): + return len(self.args) + + def __mul__(self, factor): + """Multiply point's coordinates by a factor. + + Notes + ===== + + >>> from sympy import Point + + When multiplying a Point by a floating point number, + the coordinates of the Point will be changed to Floats: + + >>> Point(1, 2)*0.1 + Point2D(0.1, 0.2) + + If this is not desired, the `scale` method can be used or + else only multiply or divide by integers: + + >>> Point(1, 2).scale(1.1, 1.1) + Point2D(11/10, 11/5) + >>> Point(1, 2)*11/10 + Point2D(11/10, 11/5) + + See Also + ======== + + sympy.geometry.point.Point.scale + """ + factor = sympify(factor) + coords = [simplify(x*factor) for x in self.args] + return Point(coords, evaluate=False) + + def __rmul__(self, factor): + """Multiply a factor by point's coordinates.""" + return self.__mul__(factor) + + def __neg__(self): + """Negate the point.""" + coords = [-x for x in self.args] + return Point(coords, evaluate=False) + + def __sub__(self, other): + """Subtract two points, or subtract a factor from this point's + coordinates.""" + return self + [-x for x in other] + + @classmethod + def _normalize_dimension(cls, *points, **kwargs): + """Ensure that points have the same dimension. + By default `on_morph='warn'` is passed to the + `Point` constructor.""" + # if we have a built-in ambient dimension, use it + dim = getattr(cls, '_ambient_dimension', None) + # override if we specified it + dim = kwargs.get('dim', dim) + # if no dim was given, use the highest dimensional point + if dim is None: + dim = max(i.ambient_dimension for i in points) + if all(i.ambient_dimension == dim for i in points): + return list(points) + kwargs['dim'] = dim + kwargs['on_morph'] = kwargs.get('on_morph', 'warn') + return [Point(i, **kwargs) for i in points] + + @staticmethod + def affine_rank(*args): + """The affine rank of a set of points is the dimension + of the smallest affine space containing all the points. + For example, if the points lie on a line (and are not all + the same) their affine rank is 1. If the points lie on a plane + but not a line, their affine rank is 2. By convention, the empty + set has affine rank -1.""" + + if len(args) == 0: + return -1 + # make sure we're genuinely points + # and translate every point to the origin + points = Point._normalize_dimension(*[Point(i) for i in args]) + origin = points[0] + points = [i - origin for i in points[1:]] + + m = Matrix([i.args for i in points]) + # XXX fragile -- what is a better way? + return m.rank(iszerofunc = lambda x: + abs(x.n(2)) < 1e-12 if x.is_number else x.is_zero) + + @property + def ambient_dimension(self): + """Number of components this point has.""" + return getattr(self, '_ambient_dimension', len(self)) + + @classmethod + def are_coplanar(cls, *points): + """Return True if there exists a plane in which all the points + lie. A trivial True value is returned if `len(points) < 3` or + all Points are 2-dimensional. + + Parameters + ========== + + A set of points + + Raises + ====== + + ValueError : if less than 3 unique points are given + + Returns + ======= + + boolean + + Examples + ======== + + >>> from sympy import Point3D + >>> p1 = Point3D(1, 2, 2) + >>> p2 = Point3D(2, 7, 2) + >>> p3 = Point3D(0, 0, 2) + >>> p4 = Point3D(1, 1, 2) + >>> Point3D.are_coplanar(p1, p2, p3, p4) + True + >>> p5 = Point3D(0, 1, 3) + >>> Point3D.are_coplanar(p1, p2, p3, p5) + False + + """ + if len(points) <= 1: + return True + + points = cls._normalize_dimension(*[Point(i) for i in points]) + # quick exit if we are in 2D + if points[0].ambient_dimension == 2: + return True + points = list(uniq(points)) + return Point.affine_rank(*points) <= 2 + + def distance(self, other): + """The Euclidean distance between self and another GeometricEntity. + + Returns + ======= + + distance : number or symbolic expression. + + Raises + ====== + + TypeError : if other is not recognized as a GeometricEntity or is a + GeometricEntity for which distance is not defined. + + See Also + ======== + + sympy.geometry.line.Segment.length + sympy.geometry.point.Point.taxicab_distance + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(1, 1), Point(4, 5) + >>> l = Line((3, 1), (2, 2)) + >>> p1.distance(p2) + 5 + >>> p1.distance(l) + sqrt(2) + + The computed distance may be symbolic, too: + + >>> from sympy.abc import x, y + >>> p3 = Point(x, y) + >>> p3.distance((0, 0)) + sqrt(x**2 + y**2) + + """ + if not isinstance(other, GeometryEntity): + try: + other = Point(other, dim=self.ambient_dimension) + except TypeError: + raise TypeError("not recognized as a GeometricEntity: %s" % type(other)) + if isinstance(other, Point): + s, p = Point._normalize_dimension(self, Point(other)) + return sqrt(Add(*((a - b)**2 for a, b in zip(s, p)))) + distance = getattr(other, 'distance', None) + if distance is None: + raise TypeError("distance between Point and %s is not defined" % type(other)) + return distance(self) + + def dot(self, p): + """Return dot product of self with another Point.""" + if not is_sequence(p): + p = Point(p) # raise the error via Point + return Add(*(a*b for a, b in zip(self, p))) + + def equals(self, other): + """Returns whether the coordinates of self and other agree.""" + # a point is equal to another point if all its components are equal + if not isinstance(other, Point) or len(self) != len(other): + return False + return all(a.equals(b) for a, b in zip(self, other)) + + def _eval_evalf(self, prec=15, **options): + """Evaluate the coordinates of the point. + + This method will, where possible, create and return a new Point + where the coordinates are evaluated as floating point numbers to + the precision indicated (default=15). + + Parameters + ========== + + prec : int + + Returns + ======= + + point : Point + + Examples + ======== + + >>> from sympy import Point, Rational + >>> p1 = Point(Rational(1, 2), Rational(3, 2)) + >>> p1 + Point2D(1/2, 3/2) + >>> p1.evalf() + Point2D(0.5, 1.5) + + """ + dps = prec_to_dps(prec) + coords = [x.evalf(n=dps, **options) for x in self.args] + return Point(*coords, evaluate=False) + + def intersection(self, other): + """The intersection between this point and another GeometryEntity. + + Parameters + ========== + + other : GeometryEntity or sequence of coordinates + + Returns + ======= + + intersection : list of Points + + Notes + ===== + + The return value will either be an empty list if there is no + intersection, otherwise it will contain this point. + + Examples + ======== + + >>> from sympy import Point + >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(0, 0) + >>> p1.intersection(p2) + [] + >>> p1.intersection(p3) + [Point2D(0, 0)] + + """ + if not isinstance(other, GeometryEntity): + other = Point(other) + if isinstance(other, Point): + if self == other: + return [self] + p1, p2 = Point._normalize_dimension(self, other) + if p1 == self and p1 == p2: + return [self] + return [] + return other.intersection(self) + + def is_collinear(self, *args): + """Returns `True` if there exists a line + that contains `self` and `points`. Returns `False` otherwise. + A trivially True value is returned if no points are given. + + Parameters + ========== + + args : sequence of Points + + Returns + ======= + + is_collinear : boolean + + See Also + ======== + + sympy.geometry.line.Line + + Examples + ======== + + >>> from sympy import Point + >>> from sympy.abc import x + >>> p1, p2 = Point(0, 0), Point(1, 1) + >>> p3, p4, p5 = Point(2, 2), Point(x, x), Point(1, 2) + >>> Point.is_collinear(p1, p2, p3, p4) + True + >>> Point.is_collinear(p1, p2, p3, p5) + False + + """ + points = (self,) + args + points = Point._normalize_dimension(*[Point(i) for i in points]) + points = list(uniq(points)) + return Point.affine_rank(*points) <= 1 + + def is_concyclic(self, *args): + """Do `self` and the given sequence of points lie in a circle? + + Returns True if the set of points are concyclic and + False otherwise. A trivial value of True is returned + if there are fewer than 2 other points. + + Parameters + ========== + + args : sequence of Points + + Returns + ======= + + is_concyclic : boolean + + + Examples + ======== + + >>> from sympy import Point + + Define 4 points that are on the unit circle: + + >>> p1, p2, p3, p4 = Point(1, 0), (0, 1), (-1, 0), (0, -1) + + >>> p1.is_concyclic() == p1.is_concyclic(p2, p3, p4) == True + True + + Define a point not on that circle: + + >>> p = Point(1, 1) + + >>> p.is_concyclic(p1, p2, p3) + False + + """ + points = (self,) + args + points = Point._normalize_dimension(*[Point(i) for i in points]) + points = list(uniq(points)) + if not Point.affine_rank(*points) <= 2: + return False + origin = points[0] + points = [p - origin for p in points] + # points are concyclic if they are coplanar and + # there is a point c so that ||p_i-c|| == ||p_j-c|| for all + # i and j. Rearranging this equation gives us the following + # condition: the matrix `mat` must not a pivot in the last + # column. + mat = Matrix([list(i) + [i.dot(i)] for i in points]) + rref, pivots = mat.rref() + if len(origin) not in pivots: + return True + return False + + @property + def is_nonzero(self): + """True if any coordinate is nonzero, False if every coordinate is zero, + and None if it cannot be determined.""" + is_zero = self.is_zero + if is_zero is None: + return None + return not is_zero + + def is_scalar_multiple(self, p): + """Returns whether each coordinate of `self` is a scalar + multiple of the corresponding coordinate in point p. + """ + s, o = Point._normalize_dimension(self, Point(p)) + # 2d points happen a lot, so optimize this function call + if s.ambient_dimension == 2: + (x1, y1), (x2, y2) = s.args, o.args + rv = (x1*y2 - x2*y1).equals(0) + if rv is None: + raise Undecidable(filldedent( + '''Cannot determine if %s is a scalar multiple of + %s''' % (s, o))) + + # if the vectors p1 and p2 are linearly dependent, then they must + # be scalar multiples of each other + m = Matrix([s.args, o.args]) + return m.rank() < 2 + + @property + def is_zero(self): + """True if every coordinate is zero, False if any coordinate is not zero, + and None if it cannot be determined.""" + nonzero = [x.is_nonzero for x in self.args] + if any(nonzero): + return False + if any(x is None for x in nonzero): + return None + return True + + @property + def length(self): + """ + Treating a Point as a Line, this returns 0 for the length of a Point. + + Examples + ======== + + >>> from sympy import Point + >>> p = Point(0, 1) + >>> p.length + 0 + """ + return S.Zero + + def midpoint(self, p): + """The midpoint between self and point p. + + Parameters + ========== + + p : Point + + Returns + ======= + + midpoint : Point + + See Also + ======== + + sympy.geometry.line.Segment.midpoint + + Examples + ======== + + >>> from sympy import Point + >>> p1, p2 = Point(1, 1), Point(13, 5) + >>> p1.midpoint(p2) + Point2D(7, 3) + + """ + s, p = Point._normalize_dimension(self, Point(p)) + return Point([simplify((a + b)*S.Half) for a, b in zip(s, p)]) + + @property + def origin(self): + """A point of all zeros of the same ambient dimension + as the current point""" + return Point([0]*len(self), evaluate=False) + + @property + def orthogonal_direction(self): + """Returns a non-zero point that is orthogonal to the + line containing `self` and the origin. + + Examples + ======== + + >>> from sympy import Line, Point + >>> a = Point(1, 2, 3) + >>> a.orthogonal_direction + Point3D(-2, 1, 0) + >>> b = _ + >>> Line(b, b.origin).is_perpendicular(Line(a, a.origin)) + True + """ + dim = self.ambient_dimension + # if a coordinate is zero, we can put a 1 there and zeros elsewhere + if self[0].is_zero: + return Point([1] + (dim - 1)*[0]) + if self[1].is_zero: + return Point([0,1] + (dim - 2)*[0]) + # if the first two coordinates aren't zero, we can create a non-zero + # orthogonal vector by swapping them, negating one, and padding with zeros + return Point([-self[1], self[0]] + (dim - 2)*[0]) + + @staticmethod + def project(a, b): + """Project the point `a` onto the line between the origin + and point `b` along the normal direction. + + Parameters + ========== + + a : Point + b : Point + + Returns + ======= + + p : Point + + See Also + ======== + + sympy.geometry.line.LinearEntity.projection + + Examples + ======== + + >>> from sympy import Line, Point + >>> a = Point(1, 2) + >>> b = Point(2, 5) + >>> z = a.origin + >>> p = Point.project(a, b) + >>> Line(p, a).is_perpendicular(Line(p, b)) + True + >>> Point.is_collinear(z, p, b) + True + """ + a, b = Point._normalize_dimension(Point(a), Point(b)) + if b.is_zero: + raise ValueError("Cannot project to the zero vector.") + return b*(a.dot(b) / b.dot(b)) + + def taxicab_distance(self, p): + """The Taxicab Distance from self to point p. + + Returns the sum of the horizontal and vertical distances to point p. + + Parameters + ========== + + p : Point + + Returns + ======= + + taxicab_distance : The sum of the horizontal + and vertical distances to point p. + + See Also + ======== + + sympy.geometry.point.Point.distance + + Examples + ======== + + >>> from sympy import Point + >>> p1, p2 = Point(1, 1), Point(4, 5) + >>> p1.taxicab_distance(p2) + 7 + + """ + s, p = Point._normalize_dimension(self, Point(p)) + return Add(*(abs(a - b) for a, b in zip(s, p))) + + def canberra_distance(self, p): + """The Canberra Distance from self to point p. + + Returns the weighted sum of horizontal and vertical distances to + point p. + + Parameters + ========== + + p : Point + + Returns + ======= + + canberra_distance : The weighted sum of horizontal and vertical + distances to point p. The weight used is the sum of absolute values + of the coordinates. + + Examples + ======== + + >>> from sympy import Point + >>> p1, p2 = Point(1, 1), Point(3, 3) + >>> p1.canberra_distance(p2) + 1 + >>> p1, p2 = Point(0, 0), Point(3, 3) + >>> p1.canberra_distance(p2) + 2 + + Raises + ====== + + ValueError when both vectors are zero. + + See Also + ======== + + sympy.geometry.point.Point.distance + + """ + + s, p = Point._normalize_dimension(self, Point(p)) + if self.is_zero and p.is_zero: + raise ValueError("Cannot project to the zero vector.") + return Add(*((abs(a - b)/(abs(a) + abs(b))) for a, b in zip(s, p))) + + @property + def unit(self): + """Return the Point that is in the same direction as `self` + and a distance of 1 from the origin""" + return self / abs(self) + + +class Point2D(Point): + """A point in a 2-dimensional Euclidean space. + + Parameters + ========== + + coords + A sequence of 2 coordinate values. + + Attributes + ========== + + x + y + length + + Raises + ====== + + TypeError + When trying to add or subtract points with different dimensions. + When trying to create a point with more than two dimensions. + When `intersection` is called with object other than a Point. + + See Also + ======== + + sympy.geometry.line.Segment : Connects two Points + + Examples + ======== + + >>> from sympy import Point2D + >>> from sympy.abc import x + >>> Point2D(1, 2) + Point2D(1, 2) + >>> Point2D([1, 2]) + Point2D(1, 2) + >>> Point2D(0, x) + Point2D(0, x) + + Floats are automatically converted to Rational unless the + evaluate flag is False: + + >>> Point2D(0.5, 0.25) + Point2D(1/2, 1/4) + >>> Point2D(0.5, 0.25, evaluate=False) + Point2D(0.5, 0.25) + + """ + + _ambient_dimension = 2 + + def __new__(cls, *args, _nocheck=False, **kwargs): + if not _nocheck: + kwargs['dim'] = 2 + args = Point(*args, **kwargs) + return GeometryEntity.__new__(cls, *args) + + def __contains__(self, item): + return item == self + + @property + def bounds(self): + """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding + rectangle for the geometric figure. + + """ + + return (self.x, self.y, self.x, self.y) + + def rotate(self, angle, pt=None): + """Rotate ``angle`` radians counterclockwise about Point ``pt``. + + See Also + ======== + + translate, scale + + Examples + ======== + + >>> from sympy import Point2D, pi + >>> t = Point2D(1, 0) + >>> t.rotate(pi/2) + Point2D(0, 1) + >>> t.rotate(pi/2, (2, 0)) + Point2D(2, -1) + + """ + c = cos(angle) + s = sin(angle) + + rv = self + if pt is not None: + pt = Point(pt, dim=2) + rv -= pt + x, y = rv.args + rv = Point(c*x - s*y, s*x + c*y) + if pt is not None: + rv += pt + return rv + + def scale(self, x=1, y=1, pt=None): + """Scale the coordinates of the Point by multiplying by + ``x`` and ``y`` after subtracting ``pt`` -- default is (0, 0) -- + and then adding ``pt`` back again (i.e. ``pt`` is the point of + reference for the scaling). + + See Also + ======== + + rotate, translate + + Examples + ======== + + >>> from sympy import Point2D + >>> t = Point2D(1, 1) + >>> t.scale(2) + Point2D(2, 1) + >>> t.scale(2, 2) + Point2D(2, 2) + + """ + if pt: + pt = Point(pt, dim=2) + return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) + return Point(self.x*x, self.y*y) + + def transform(self, matrix): + """Return the point after applying the transformation described + by the 3x3 Matrix, ``matrix``. + + See Also + ======== + sympy.geometry.point.Point2D.rotate + sympy.geometry.point.Point2D.scale + sympy.geometry.point.Point2D.translate + """ + if not (matrix.is_Matrix and matrix.shape == (3, 3)): + raise ValueError("matrix must be a 3x3 matrix") + x, y = self.args + return Point(*(Matrix(1, 3, [x, y, 1])*matrix).tolist()[0][:2]) + + def translate(self, x=0, y=0): + """Shift the Point by adding x and y to the coordinates of the Point. + + See Also + ======== + + sympy.geometry.point.Point2D.rotate, scale + + Examples + ======== + + >>> from sympy import Point2D + >>> t = Point2D(0, 1) + >>> t.translate(2) + Point2D(2, 1) + >>> t.translate(2, 2) + Point2D(2, 3) + >>> t + Point2D(2, 2) + Point2D(2, 3) + + """ + return Point(self.x + x, self.y + y) + + @property + def coordinates(self): + """ + Returns the two coordinates of the Point. + + Examples + ======== + + >>> from sympy import Point2D + >>> p = Point2D(0, 1) + >>> p.coordinates + (0, 1) + """ + return self.args + + @property + def x(self): + """ + Returns the X coordinate of the Point. + + Examples + ======== + + >>> from sympy import Point2D + >>> p = Point2D(0, 1) + >>> p.x + 0 + """ + return self.args[0] + + @property + def y(self): + """ + Returns the Y coordinate of the Point. + + Examples + ======== + + >>> from sympy import Point2D + >>> p = Point2D(0, 1) + >>> p.y + 1 + """ + return self.args[1] + +class Point3D(Point): + """A point in a 3-dimensional Euclidean space. + + Parameters + ========== + + coords + A sequence of 3 coordinate values. + + Attributes + ========== + + x + y + z + length + + Raises + ====== + + TypeError + When trying to add or subtract points with different dimensions. + When `intersection` is called with object other than a Point. + + Examples + ======== + + >>> from sympy import Point3D + >>> from sympy.abc import x + >>> Point3D(1, 2, 3) + Point3D(1, 2, 3) + >>> Point3D([1, 2, 3]) + Point3D(1, 2, 3) + >>> Point3D(0, x, 3) + Point3D(0, x, 3) + + Floats are automatically converted to Rational unless the + evaluate flag is False: + + >>> Point3D(0.5, 0.25, 2) + Point3D(1/2, 1/4, 2) + >>> Point3D(0.5, 0.25, 3, evaluate=False) + Point3D(0.5, 0.25, 3) + + """ + + _ambient_dimension = 3 + + def __new__(cls, *args, _nocheck=False, **kwargs): + if not _nocheck: + kwargs['dim'] = 3 + args = Point(*args, **kwargs) + return GeometryEntity.__new__(cls, *args) + + def __contains__(self, item): + return item == self + + @staticmethod + def are_collinear(*points): + """Is a sequence of points collinear? + + Test whether or not a set of points are collinear. Returns True if + the set of points are collinear, or False otherwise. + + Parameters + ========== + + points : sequence of Point + + Returns + ======= + + are_collinear : boolean + + See Also + ======== + + sympy.geometry.line.Line3D + + Examples + ======== + + >>> from sympy import Point3D + >>> from sympy.abc import x + >>> p1, p2 = Point3D(0, 0, 0), Point3D(1, 1, 1) + >>> p3, p4, p5 = Point3D(2, 2, 2), Point3D(x, x, x), Point3D(1, 2, 6) + >>> Point3D.are_collinear(p1, p2, p3, p4) + True + >>> Point3D.are_collinear(p1, p2, p3, p5) + False + """ + return Point.is_collinear(*points) + + def direction_cosine(self, point): + """ + Gives the direction cosine between 2 points + + Parameters + ========== + + p : Point3D + + Returns + ======= + + list + + Examples + ======== + + >>> from sympy import Point3D + >>> p1 = Point3D(1, 2, 3) + >>> p1.direction_cosine(Point3D(2, 3, 5)) + [sqrt(6)/6, sqrt(6)/6, sqrt(6)/3] + """ + a = self.direction_ratio(point) + b = sqrt(Add(*(i**2 for i in a))) + return [(point.x - self.x) / b,(point.y - self.y) / b, + (point.z - self.z) / b] + + def direction_ratio(self, point): + """ + Gives the direction ratio between 2 points + + Parameters + ========== + + p : Point3D + + Returns + ======= + + list + + Examples + ======== + + >>> from sympy import Point3D + >>> p1 = Point3D(1, 2, 3) + >>> p1.direction_ratio(Point3D(2, 3, 5)) + [1, 1, 2] + """ + return [(point.x - self.x),(point.y - self.y),(point.z - self.z)] + + def intersection(self, other): + """The intersection between this point and another GeometryEntity. + + Parameters + ========== + + other : GeometryEntity or sequence of coordinates + + Returns + ======= + + intersection : list of Points + + Notes + ===== + + The return value will either be an empty list if there is no + intersection, otherwise it will contain this point. + + Examples + ======== + + >>> from sympy import Point3D + >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(0, 0, 0) + >>> p1.intersection(p2) + [] + >>> p1.intersection(p3) + [Point3D(0, 0, 0)] + + """ + if not isinstance(other, GeometryEntity): + other = Point(other, dim=3) + if isinstance(other, Point3D): + if self == other: + return [self] + return [] + return other.intersection(self) + + def scale(self, x=1, y=1, z=1, pt=None): + """Scale the coordinates of the Point by multiplying by + ``x`` and ``y`` after subtracting ``pt`` -- default is (0, 0) -- + and then adding ``pt`` back again (i.e. ``pt`` is the point of + reference for the scaling). + + See Also + ======== + + translate + + Examples + ======== + + >>> from sympy import Point3D + >>> t = Point3D(1, 1, 1) + >>> t.scale(2) + Point3D(2, 1, 1) + >>> t.scale(2, 2) + Point3D(2, 2, 1) + + """ + if pt: + pt = Point3D(pt) + return self.translate(*(-pt).args).scale(x, y, z).translate(*pt.args) + return Point3D(self.x*x, self.y*y, self.z*z) + + def transform(self, matrix): + """Return the point after applying the transformation described + by the 4x4 Matrix, ``matrix``. + + See Also + ======== + sympy.geometry.point.Point3D.scale + sympy.geometry.point.Point3D.translate + """ + if not (matrix.is_Matrix and matrix.shape == (4, 4)): + raise ValueError("matrix must be a 4x4 matrix") + x, y, z = self.args + m = Transpose(matrix) + return Point3D(*(Matrix(1, 4, [x, y, z, 1])*m).tolist()[0][:3]) + + def translate(self, x=0, y=0, z=0): + """Shift the Point by adding x and y to the coordinates of the Point. + + See Also + ======== + + scale + + Examples + ======== + + >>> from sympy import Point3D + >>> t = Point3D(0, 1, 1) + >>> t.translate(2) + Point3D(2, 1, 1) + >>> t.translate(2, 2) + Point3D(2, 3, 1) + >>> t + Point3D(2, 2, 2) + Point3D(2, 3, 3) + + """ + return Point3D(self.x + x, self.y + y, self.z + z) + + @property + def coordinates(self): + """ + Returns the three coordinates of the Point. + + Examples + ======== + + >>> from sympy import Point3D + >>> p = Point3D(0, 1, 2) + >>> p.coordinates + (0, 1, 2) + """ + return self.args + + @property + def x(self): + """ + Returns the X coordinate of the Point. + + Examples + ======== + + >>> from sympy import Point3D + >>> p = Point3D(0, 1, 3) + >>> p.x + 0 + """ + return self.args[0] + + @property + def y(self): + """ + Returns the Y coordinate of the Point. + + Examples + ======== + + >>> from sympy import Point3D + >>> p = Point3D(0, 1, 2) + >>> p.y + 1 + """ + return self.args[1] + + @property + def z(self): + """ + Returns the Z coordinate of the Point. + + Examples + ======== + + >>> from sympy import Point3D + >>> p = Point3D(0, 1, 1) + >>> p.z + 1 + """ + return self.args[2] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/polygon.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/polygon.py new file mode 100644 index 0000000000000000000000000000000000000000..63031183438e2d228f881fd82e1b0ecca04ec534 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/polygon.py @@ -0,0 +1,2891 @@ +from sympy.core import Expr, S, oo, pi, sympify +from sympy.core.evalf import N +from sympy.core.sorting import default_sort_key, ordered +from sympy.core.symbol import _symbol, Dummy, Symbol +from sympy.functions.elementary.complexes import sign +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import cos, sin, tan +from .ellipse import Circle +from .entity import GeometryEntity, GeometrySet +from .exceptions import GeometryError +from .line import Line, Segment, Ray +from .point import Point +from sympy.logic import And +from sympy.matrices import Matrix +from sympy.simplify.simplify import simplify +from sympy.solvers.solvers import solve +from sympy.utilities.iterables import has_dups, has_variety, uniq, rotate_left, least_rotation +from sympy.utilities.misc import as_int, func_name + +from mpmath.libmp.libmpf import prec_to_dps + +import warnings + + +x, y, T = [Dummy('polygon_dummy', real=True) for i in range(3)] + + +class Polygon(GeometrySet): + """A two-dimensional polygon. + + A simple polygon in space. Can be constructed from a sequence of points + or from a center, radius, number of sides and rotation angle. + + Parameters + ========== + + vertices + A sequence of points. + + n : int, optional + If $> 0$, an n-sided RegularPolygon is created. + Default value is $0$. + + Attributes + ========== + + area + angles + perimeter + vertices + centroid + sides + + Raises + ====== + + GeometryError + If all parameters are not Points. + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.line.Segment, Triangle + + Notes + ===== + + Polygons are treated as closed paths rather than 2D areas so + some calculations can be be negative or positive (e.g., area) + based on the orientation of the points. + + Any consecutive identical points are reduced to a single point + and any points collinear and between two points will be removed + unless they are needed to define an explicit intersection (see examples). + + A Triangle, Segment or Point will be returned when there are 3 or + fewer points provided. + + Examples + ======== + + >>> from sympy import Polygon, pi + >>> p1, p2, p3, p4, p5 = [(0, 0), (1, 0), (5, 1), (0, 1), (3, 0)] + >>> Polygon(p1, p2, p3, p4) + Polygon(Point2D(0, 0), Point2D(1, 0), Point2D(5, 1), Point2D(0, 1)) + >>> Polygon(p1, p2) + Segment2D(Point2D(0, 0), Point2D(1, 0)) + >>> Polygon(p1, p2, p5) + Segment2D(Point2D(0, 0), Point2D(3, 0)) + + The area of a polygon is calculated as positive when vertices are + traversed in a ccw direction. When the sides of a polygon cross the + area will have positive and negative contributions. The following + defines a Z shape where the bottom right connects back to the top + left. + + >>> Polygon((0, 2), (2, 2), (0, 0), (2, 0)).area + 0 + + When the keyword `n` is used to define the number of sides of the + Polygon then a RegularPolygon is created and the other arguments are + interpreted as center, radius and rotation. The unrotated RegularPolygon + will always have a vertex at Point(r, 0) where `r` is the radius of the + circle that circumscribes the RegularPolygon. Its method `spin` can be + used to increment that angle. + + >>> p = Polygon((0,0), 1, n=3) + >>> p + RegularPolygon(Point2D(0, 0), 1, 3, 0) + >>> p.vertices[0] + Point2D(1, 0) + >>> p.args[0] + Point2D(0, 0) + >>> p.spin(pi/2) + >>> p.vertices[0] + Point2D(0, 1) + + """ + + __slots__ = () + + def __new__(cls, *args, n = 0, **kwargs): + if n: + args = list(args) + # return a virtual polygon with n sides + if len(args) == 2: # center, radius + args.append(n) + elif len(args) == 3: # center, radius, rotation + args.insert(2, n) + return RegularPolygon(*args, **kwargs) + + vertices = [Point(a, dim=2, **kwargs) for a in args] + + # remove consecutive duplicates + nodup = [] + for p in vertices: + if nodup and p == nodup[-1]: + continue + nodup.append(p) + if len(nodup) > 1 and nodup[-1] == nodup[0]: + nodup.pop() # last point was same as first + + # remove collinear points + i = -3 + while i < len(nodup) - 3 and len(nodup) > 2: + a, b, c = nodup[i], nodup[i + 1], nodup[i + 2] + if Point.is_collinear(a, b, c): + nodup.pop(i + 1) + if a == c: + nodup.pop(i) + else: + i += 1 + + vertices = list(nodup) + + if len(vertices) > 3: + return GeometryEntity.__new__(cls, *vertices, **kwargs) + elif len(vertices) == 3: + return Triangle(*vertices, **kwargs) + elif len(vertices) == 2: + return Segment(*vertices, **kwargs) + else: + return Point(*vertices, **kwargs) + + @property + def area(self): + """ + The area of the polygon. + + Notes + ===== + + The area calculation can be positive or negative based on the + orientation of the points. If any side of the polygon crosses + any other side, there will be areas having opposite signs. + + See Also + ======== + + sympy.geometry.ellipse.Ellipse.area + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) + >>> poly = Polygon(p1, p2, p3, p4) + >>> poly.area + 3 + + In the Z shaped polygon (with the lower right connecting back + to the upper left) the areas cancel out: + + >>> Z = Polygon((0, 1), (1, 1), (0, 0), (1, 0)) + >>> Z.area + 0 + + In the M shaped polygon, areas do not cancel because no side + crosses any other (though there is a point of contact). + + >>> M = Polygon((0, 0), (0, 1), (2, 0), (3, 1), (3, 0)) + >>> M.area + -3/2 + + """ + area = 0 + args = self.args + for i in range(len(args)): + x1, y1 = args[i - 1].args + x2, y2 = args[i].args + area += x1*y2 - x2*y1 + return simplify(area) / 2 + + @staticmethod + def _is_clockwise(a, b, c): + """Return True/False for cw/ccw orientation. + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> a, b, c = [Point(i) for i in [(0, 0), (1, 1), (1, 0)]] + >>> Polygon._is_clockwise(a, b, c) + True + >>> Polygon._is_clockwise(a, c, b) + False + """ + ba = b - a + ca = c - a + t_area = simplify(ba.x*ca.y - ca.x*ba.y) + res = t_area.is_nonpositive + if res is None: + raise ValueError("Can't determine orientation") + return res + + @property + def angles(self): + """The internal angle at each vertex. + + Returns + ======= + + angles : dict + A dictionary where each key is a vertex and each value is the + internal angle at that vertex. The vertices are represented as + Points. + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.line.LinearEntity.angle_between + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) + >>> poly = Polygon(p1, p2, p3, p4) + >>> poly.angles[p1] + pi/2 + >>> poly.angles[p2] + acos(-4*sqrt(17)/17) + + """ + + args = self.vertices + n = len(args) + ret = {} + for i in range(n): + a, b, c = args[i - 2], args[i - 1], args[i] + reflex_ang = Ray(b, a).angle_between(Ray(b, c)) + if self._is_clockwise(a, b, c): + ret[b] = 2*S.Pi - reflex_ang + else: + ret[b] = reflex_ang + + # internal sum should be pi*(n - 2), not pi*(n+2) + # so if ratio is (n+2)/(n-2) > 1 it is wrong + wrong = ((sum(ret.values())/S.Pi-1)/(n - 2) - 1).is_positive + if wrong: + two_pi = 2*S.Pi + for b in ret: + ret[b] = two_pi - ret[b] + elif wrong is None: + raise ValueError("could not determine Polygon orientation.") + return ret + + @property + def ambient_dimension(self): + return self.vertices[0].ambient_dimension + + @property + def perimeter(self): + """The perimeter of the polygon. + + Returns + ======= + + perimeter : number or Basic instance + + See Also + ======== + + sympy.geometry.line.Segment.length + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) + >>> poly = Polygon(p1, p2, p3, p4) + >>> poly.perimeter + sqrt(17) + 7 + """ + p = 0 + args = self.vertices + for i in range(len(args)): + p += args[i - 1].distance(args[i]) + return simplify(p) + + @property + def vertices(self): + """The vertices of the polygon. + + Returns + ======= + + vertices : list of Points + + Notes + ===== + + When iterating over the vertices, it is more efficient to index self + rather than to request the vertices and index them. Only use the + vertices when you want to process all of them at once. This is even + more important with RegularPolygons that calculate each vertex. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) + >>> poly = Polygon(p1, p2, p3, p4) + >>> poly.vertices + [Point2D(0, 0), Point2D(1, 0), Point2D(5, 1), Point2D(0, 1)] + >>> poly.vertices[0] + Point2D(0, 0) + + """ + return list(self.args) + + @property + def centroid(self): + """The centroid of the polygon. + + Returns + ======= + + centroid : Point + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.util.centroid + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) + >>> poly = Polygon(p1, p2, p3, p4) + >>> poly.centroid + Point2D(31/18, 11/18) + + """ + A = 1/(6*self.area) + cx, cy = 0, 0 + args = self.args + for i in range(len(args)): + x1, y1 = args[i - 1].args + x2, y2 = args[i].args + v = x1*y2 - x2*y1 + cx += v*(x1 + x2) + cy += v*(y1 + y2) + return Point(simplify(A*cx), simplify(A*cy)) + + + def second_moment_of_area(self, point=None): + """Returns the second moment and product moment of area of a two dimensional polygon. + + Parameters + ========== + + point : Point, two-tuple of sympifyable objects, or None(default=None) + point is the point about which second moment of area is to be found. + If "point=None" it will be calculated about the axis passing through the + centroid of the polygon. + + Returns + ======= + + I_xx, I_yy, I_xy : number or SymPy expression + I_xx, I_yy are second moment of area of a two dimensional polygon. + I_xy is product moment of area of a two dimensional polygon. + + Examples + ======== + + >>> from sympy import Polygon, symbols + >>> a, b = symbols('a, b') + >>> p1, p2, p3, p4, p5 = [(0, 0), (a, 0), (a, b), (0, b), (a/3, b/3)] + >>> rectangle = Polygon(p1, p2, p3, p4) + >>> rectangle.second_moment_of_area() + (a*b**3/12, a**3*b/12, 0) + >>> rectangle.second_moment_of_area(p5) + (a*b**3/9, a**3*b/9, a**2*b**2/36) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Second_moment_of_area + + """ + + I_xx, I_yy, I_xy = 0, 0, 0 + args = self.vertices + for i in range(len(args)): + x1, y1 = args[i-1].args + x2, y2 = args[i].args + v = x1*y2 - x2*y1 + I_xx += (y1**2 + y1*y2 + y2**2)*v + I_yy += (x1**2 + x1*x2 + x2**2)*v + I_xy += (x1*y2 + 2*x1*y1 + 2*x2*y2 + x2*y1)*v + A = self.area + c_x = self.centroid[0] + c_y = self.centroid[1] + # parallel axis theorem + I_xx_c = (I_xx/12) - (A*(c_y**2)) + I_yy_c = (I_yy/12) - (A*(c_x**2)) + I_xy_c = (I_xy/24) - (A*(c_x*c_y)) + if point is None: + return I_xx_c, I_yy_c, I_xy_c + + I_xx = (I_xx_c + A*((point[1]-c_y)**2)) + I_yy = (I_yy_c + A*((point[0]-c_x)**2)) + I_xy = (I_xy_c + A*((point[0]-c_x)*(point[1]-c_y))) + + return I_xx, I_yy, I_xy + + + def first_moment_of_area(self, point=None): + """ + Returns the first moment of area of a two-dimensional polygon with + respect to a certain point of interest. + + First moment of area is a measure of the distribution of the area + of a polygon in relation to an axis. The first moment of area of + the entire polygon about its own centroid is always zero. Therefore, + here it is calculated for an area, above or below a certain point + of interest, that makes up a smaller portion of the polygon. This + area is bounded by the point of interest and the extreme end + (top or bottom) of the polygon. The first moment for this area is + is then determined about the centroidal axis of the initial polygon. + + References + ========== + + .. [1] https://skyciv.com/docs/tutorials/section-tutorials/calculating-the-statical-or-first-moment-of-area-of-beam-sections/?cc=BMD + .. [2] https://mechanicalc.com/reference/cross-sections + + Parameters + ========== + + point: Point, two-tuple of sympifyable objects, or None (default=None) + point is the point above or below which the area of interest lies + If ``point=None`` then the centroid acts as the point of interest. + + Returns + ======= + + Q_x, Q_y: number or SymPy expressions + Q_x is the first moment of area about the x-axis + Q_y is the first moment of area about the y-axis + A negative sign indicates that the section modulus is + determined for a section below (or left of) the centroidal axis + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> a, b = 50, 10 + >>> p1, p2, p3, p4 = [(0, b), (0, 0), (a, 0), (a, b)] + >>> p = Polygon(p1, p2, p3, p4) + >>> p.first_moment_of_area() + (625, 3125) + >>> p.first_moment_of_area(point=Point(30, 7)) + (525, 3000) + """ + if point: + xc, yc = self.centroid + else: + point = self.centroid + xc, yc = point + + h_line = Line(point, slope=0) + v_line = Line(point, slope=S.Infinity) + + h_poly = self.cut_section(h_line) + v_poly = self.cut_section(v_line) + + poly_1 = h_poly[0] if h_poly[0].area <= h_poly[1].area else h_poly[1] + poly_2 = v_poly[0] if v_poly[0].area <= v_poly[1].area else v_poly[1] + + Q_x = (poly_1.centroid.y - yc)*poly_1.area + Q_y = (poly_2.centroid.x - xc)*poly_2.area + + return Q_x, Q_y + + + def polar_second_moment_of_area(self): + """Returns the polar modulus of a two-dimensional polygon + + It is a constituent of the second moment of area, linked through + the perpendicular axis theorem. While the planar second moment of + area describes an object's resistance to deflection (bending) when + subjected to a force applied to a plane parallel to the central + axis, the polar second moment of area describes an object's + resistance to deflection when subjected to a moment applied in a + plane perpendicular to the object's central axis (i.e. parallel to + the cross-section) + + Examples + ======== + + >>> from sympy import Polygon, symbols + >>> a, b = symbols('a, b') + >>> rectangle = Polygon((0, 0), (a, 0), (a, b), (0, b)) + >>> rectangle.polar_second_moment_of_area() + a**3*b/12 + a*b**3/12 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Polar_moment_of_inertia + + """ + second_moment = self.second_moment_of_area() + return second_moment[0] + second_moment[1] + + + def section_modulus(self, point=None): + """Returns a tuple with the section modulus of a two-dimensional + polygon. + + Section modulus is a geometric property of a polygon defined as the + ratio of second moment of area to the distance of the extreme end of + the polygon from the centroidal axis. + + Parameters + ========== + + point : Point, two-tuple of sympifyable objects, or None(default=None) + point is the point at which section modulus is to be found. + If "point=None" it will be calculated for the point farthest from the + centroidal axis of the polygon. + + Returns + ======= + + S_x, S_y: numbers or SymPy expressions + S_x is the section modulus with respect to the x-axis + S_y is the section modulus with respect to the y-axis + A negative sign indicates that the section modulus is + determined for a point below the centroidal axis + + Examples + ======== + + >>> from sympy import symbols, Polygon, Point + >>> a, b = symbols('a, b', positive=True) + >>> rectangle = Polygon((0, 0), (a, 0), (a, b), (0, b)) + >>> rectangle.section_modulus() + (a*b**2/6, a**2*b/6) + >>> rectangle.section_modulus(Point(a/4, b/4)) + (-a*b**2/3, -a**2*b/3) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Section_modulus + + """ + x_c, y_c = self.centroid + if point is None: + # taking x and y as maximum distances from centroid + x_min, y_min, x_max, y_max = self.bounds + y = max(y_c - y_min, y_max - y_c) + x = max(x_c - x_min, x_max - x_c) + else: + # taking x and y as distances of the given point from the centroid + y = point.y - y_c + x = point.x - x_c + + second_moment= self.second_moment_of_area() + S_x = second_moment[0]/y + S_y = second_moment[1]/x + + return S_x, S_y + + + @property + def sides(self): + """The directed line segments that form the sides of the polygon. + + Returns + ======= + + sides : list of sides + Each side is a directed Segment. + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.line.Segment + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) + >>> poly = Polygon(p1, p2, p3, p4) + >>> poly.sides + [Segment2D(Point2D(0, 0), Point2D(1, 0)), + Segment2D(Point2D(1, 0), Point2D(5, 1)), + Segment2D(Point2D(5, 1), Point2D(0, 1)), Segment2D(Point2D(0, 1), Point2D(0, 0))] + + """ + res = [] + args = self.vertices + for i in range(-len(args), 0): + res.append(Segment(args[i], args[i + 1])) + return res + + @property + def bounds(self): + """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding + rectangle for the geometric figure. + + """ + + verts = self.vertices + xs = [p.x for p in verts] + ys = [p.y for p in verts] + return (min(xs), min(ys), max(xs), max(ys)) + + def is_convex(self): + """Is the polygon convex? + + A polygon is convex if all its interior angles are less than 180 + degrees and there are no intersections between sides. + + Returns + ======= + + is_convex : boolean + True if this polygon is convex, False otherwise. + + See Also + ======== + + sympy.geometry.util.convex_hull + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) + >>> poly = Polygon(p1, p2, p3, p4) + >>> poly.is_convex() + True + + """ + # Determine orientation of points + args = self.vertices + cw = self._is_clockwise(args[-2], args[-1], args[0]) + for i in range(1, len(args)): + if cw ^ self._is_clockwise(args[i - 2], args[i - 1], args[i]): + return False + # check for intersecting sides + sides = self.sides + for i, si in enumerate(sides): + pts = si.args + # exclude the sides connected to si + for j in range(1 if i == len(sides) - 1 else 0, i - 1): + sj = sides[j] + if sj.p1 not in pts and sj.p2 not in pts: + hit = si.intersection(sj) + if hit: + return False + return True + + def encloses_point(self, p): + """ + Return True if p is enclosed by (is inside of) self. + + Notes + ===== + + Being on the border of self is considered False. + + Parameters + ========== + + p : Point + + Returns + ======= + + encloses_point : True, False or None + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.ellipse.Ellipse.encloses_point + + Examples + ======== + + >>> from sympy import Polygon, Point + >>> p = Polygon((0, 0), (4, 0), (4, 4)) + >>> p.encloses_point(Point(2, 1)) + True + >>> p.encloses_point(Point(2, 2)) + False + >>> p.encloses_point(Point(5, 5)) + False + + References + ========== + + .. [1] https://paulbourke.net/geometry/polygonmesh/#insidepoly + + """ + p = Point(p, dim=2) + if p in self.vertices or any(p in s for s in self.sides): + return False + + # move to p, checking that the result is numeric + lit = [] + for v in self.vertices: + lit.append(v - p) # the difference is simplified + if lit[-1].free_symbols: + return None + + poly = Polygon(*lit) + + # polygon closure is assumed in the following test but Polygon removes duplicate pts so + # the last point has to be added so all sides are computed. Using Polygon.sides is + # not good since Segments are unordered. + args = poly.args + indices = list(range(-len(args), 1)) + + if poly.is_convex(): + orientation = None + for i in indices: + a = args[i] + b = args[i + 1] + test = ((-a.y)*(b.x - a.x) - (-a.x)*(b.y - a.y)).is_negative + if orientation is None: + orientation = test + elif test is not orientation: + return False + return True + + hit_odd = False + p1x, p1y = args[0].args + for i in indices[1:]: + p2x, p2y = args[i].args + if 0 > min(p1y, p2y): + if 0 <= max(p1y, p2y): + if 0 <= max(p1x, p2x): + if p1y != p2y: + xinters = (-p1y)*(p2x - p1x)/(p2y - p1y) + p1x + if p1x == p2x or 0 <= xinters: + hit_odd = not hit_odd + p1x, p1y = p2x, p2y + return hit_odd + + def arbitrary_point(self, parameter='t'): + """A parameterized point on the polygon. + + The parameter, varying from 0 to 1, assigns points to the position on + the perimeter that is that fraction of the total perimeter. So the + point evaluated at t=1/2 would return the point from the first vertex + that is 1/2 way around the polygon. + + Parameters + ========== + + parameter : str, optional + Default value is 't'. + + Returns + ======= + + arbitrary_point : Point + + Raises + ====== + + ValueError + When `parameter` already appears in the Polygon's definition. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Polygon, Symbol + >>> t = Symbol('t', real=True) + >>> tri = Polygon((0, 0), (1, 0), (1, 1)) + >>> p = tri.arbitrary_point('t') + >>> perimeter = tri.perimeter + >>> s1, s2 = [s.length for s in tri.sides[:2]] + >>> p.subs(t, (s1 + s2/2)/perimeter) + Point2D(1, 1/2) + + """ + t = _symbol(parameter, real=True) + if t.name in (f.name for f in self.free_symbols): + raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) + sides = [] + perimeter = self.perimeter + perim_fraction_start = 0 + for s in self.sides: + side_perim_fraction = s.length/perimeter + perim_fraction_end = perim_fraction_start + side_perim_fraction + pt = s.arbitrary_point(parameter).subs( + t, (t - perim_fraction_start)/side_perim_fraction) + sides.append( + (pt, (And(perim_fraction_start <= t, t < perim_fraction_end)))) + perim_fraction_start = perim_fraction_end + return Piecewise(*sides) + + def parameter_value(self, other, t): + if not isinstance(other,GeometryEntity): + other = Point(other, dim=self.ambient_dimension) + if not isinstance(other,Point): + raise ValueError("other must be a point") + if other.free_symbols: + raise NotImplementedError('non-numeric coordinates') + unknown = False + p = self.arbitrary_point(T) + for pt, cond in p.args: + sol = solve(pt - other, T, dict=True) + if not sol: + continue + value = sol[0][T] + if simplify(cond.subs(T, value)) == True: + return {t: value} + unknown = True + if unknown: + raise ValueError("Given point may not be on %s" % func_name(self)) + raise ValueError("Given point is not on %s" % func_name(self)) + + def plot_interval(self, parameter='t'): + """The plot interval for the default geometric plot of the polygon. + + Parameters + ========== + + parameter : str, optional + Default value is 't'. + + Returns + ======= + + plot_interval : list (plot interval) + [parameter, lower_bound, upper_bound] + + Examples + ======== + + >>> from sympy import Polygon + >>> p = Polygon((0, 0), (1, 0), (1, 1)) + >>> p.plot_interval() + [t, 0, 1] + + """ + t = Symbol(parameter, real=True) + return [t, 0, 1] + + def intersection(self, o): + """The intersection of polygon and geometry entity. + + The intersection may be empty and can contain individual Points and + complete Line Segments. + + Parameters + ========== + + other: GeometryEntity + + Returns + ======= + + intersection : list + The list of Segments and Points + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.line.Segment + + Examples + ======== + + >>> from sympy import Point, Polygon, Line + >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) + >>> poly1 = Polygon(p1, p2, p3, p4) + >>> p5, p6, p7 = map(Point, [(3, 2), (1, -1), (0, 2)]) + >>> poly2 = Polygon(p5, p6, p7) + >>> poly1.intersection(poly2) + [Point2D(1/3, 1), Point2D(2/3, 0), Point2D(9/5, 1/5), Point2D(7/3, 1)] + >>> poly1.intersection(Line(p1, p2)) + [Segment2D(Point2D(0, 0), Point2D(1, 0))] + >>> poly1.intersection(p1) + [Point2D(0, 0)] + """ + intersection_result = [] + k = o.sides if isinstance(o, Polygon) else [o] + for side in self.sides: + for side1 in k: + intersection_result.extend(side.intersection(side1)) + + intersection_result = list(uniq(intersection_result)) + points = [entity for entity in intersection_result if isinstance(entity, Point)] + segments = [entity for entity in intersection_result if isinstance(entity, Segment)] + + if points and segments: + points_in_segments = list(uniq([point for point in points for segment in segments if point in segment])) + if points_in_segments: + for i in points_in_segments: + points.remove(i) + return list(ordered(segments + points)) + else: + return list(ordered(intersection_result)) + + + def cut_section(self, line): + """ + Returns a tuple of two polygon segments that lie above and below + the intersecting line respectively. + + Parameters + ========== + + line: Line object of geometry module + line which cuts the Polygon. The part of the Polygon that lies + above and below this line is returned. + + Returns + ======= + + upper_polygon, lower_polygon: Polygon objects or None + upper_polygon is the polygon that lies above the given line. + lower_polygon is the polygon that lies below the given line. + upper_polygon and lower polygon are ``None`` when no polygon + exists above the line or below the line. + + Raises + ====== + + ValueError: When the line does not intersect the polygon + + Examples + ======== + + >>> from sympy import Polygon, Line + >>> a, b = 20, 10 + >>> p1, p2, p3, p4 = [(0, b), (0, 0), (a, 0), (a, b)] + >>> rectangle = Polygon(p1, p2, p3, p4) + >>> t = rectangle.cut_section(Line((0, 5), slope=0)) + >>> t + (Polygon(Point2D(0, 10), Point2D(0, 5), Point2D(20, 5), Point2D(20, 10)), + Polygon(Point2D(0, 5), Point2D(0, 0), Point2D(20, 0), Point2D(20, 5))) + >>> upper_segment, lower_segment = t + >>> upper_segment.area + 100 + >>> upper_segment.centroid + Point2D(10, 15/2) + >>> lower_segment.centroid + Point2D(10, 5/2) + + References + ========== + + .. [1] https://github.com/sympy/sympy/wiki/A-method-to-return-a-cut-section-of-any-polygon-geometry + + """ + intersection_points = self.intersection(line) + if not intersection_points: + raise ValueError("This line does not intersect the polygon") + + points = list(self.vertices) + points.append(points[0]) + + eq = line.equation(x, y) + + # considering equation of line to be `ax +by + c` + a = eq.coeff(x) + b = eq.coeff(y) + + upper_vertices = [] + lower_vertices = [] + # prev is true when previous point is above the line + prev = True + prev_point = None + for point in points: + # when coefficient of y is 0, right side of the line is + # considered + compare = eq.subs({x: point.x, y: point.y})/b if b \ + else eq.subs(x, point.x)/a + + # if point lies above line + if compare > 0: + if not prev: + # if previous point lies below the line, the intersection + # point of the polygon edge and the line has to be included + edge = Line(point, prev_point) + new_point = edge.intersection(line) + upper_vertices.append(new_point[0]) + lower_vertices.append(new_point[0]) + + upper_vertices.append(point) + prev = True + else: + if prev and prev_point: + edge = Line(point, prev_point) + new_point = edge.intersection(line) + upper_vertices.append(new_point[0]) + lower_vertices.append(new_point[0]) + lower_vertices.append(point) + prev = False + prev_point = point + + upper_polygon, lower_polygon = None, None + if upper_vertices and isinstance(Polygon(*upper_vertices), Polygon): + upper_polygon = Polygon(*upper_vertices) + if lower_vertices and isinstance(Polygon(*lower_vertices), Polygon): + lower_polygon = Polygon(*lower_vertices) + + return upper_polygon, lower_polygon + + + def distance(self, o): + """ + Returns the shortest distance between self and o. + + If o is a point, then self does not need to be convex. + If o is another polygon self and o must be convex. + + Examples + ======== + + >>> from sympy import Point, Polygon, RegularPolygon + >>> p1, p2 = map(Point, [(0, 0), (7, 5)]) + >>> poly = Polygon(*RegularPolygon(p1, 1, 3).vertices) + >>> poly.distance(p2) + sqrt(61) + """ + if isinstance(o, Point): + dist = oo + for side in self.sides: + current = side.distance(o) + if current == 0: + return S.Zero + elif current < dist: + dist = current + return dist + elif isinstance(o, Polygon) and self.is_convex() and o.is_convex(): + return self._do_poly_distance(o) + raise NotImplementedError() + + def _do_poly_distance(self, e2): + """ + Calculates the least distance between the exteriors of two + convex polygons e1 and e2. Does not check for the convexity + of the polygons as this is checked by Polygon.distance. + + Notes + ===== + + - Prints a warning if the two polygons possibly intersect as the return + value will not be valid in such a case. For a more through test of + intersection use intersection(). + + See Also + ======== + + sympy.geometry.point.Point.distance + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> square = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)) + >>> triangle = Polygon(Point(1, 2), Point(2, 2), Point(2, 1)) + >>> square._do_poly_distance(triangle) + sqrt(2)/2 + + Description of method used + ========================== + + Method: + [1] https://web.archive.org/web/20150509035744/http://cgm.cs.mcgill.ca/~orm/mind2p.html + Uses rotating calipers: + [2] https://en.wikipedia.org/wiki/Rotating_calipers + and antipodal points: + [3] https://en.wikipedia.org/wiki/Antipodal_point + """ + e1 = self + + '''Tests for a possible intersection between the polygons and outputs a warning''' + e1_center = e1.centroid + e2_center = e2.centroid + e1_max_radius = S.Zero + e2_max_radius = S.Zero + for vertex in e1.vertices: + r = Point.distance(e1_center, vertex) + if e1_max_radius < r: + e1_max_radius = r + for vertex in e2.vertices: + r = Point.distance(e2_center, vertex) + if e2_max_radius < r: + e2_max_radius = r + center_dist = Point.distance(e1_center, e2_center) + if center_dist <= e1_max_radius + e2_max_radius: + warnings.warn("Polygons may intersect producing erroneous output", + stacklevel=3) + + ''' + Find the upper rightmost vertex of e1 and the lowest leftmost vertex of e2 + ''' + e1_ymax = Point(0, -oo) + e2_ymin = Point(0, oo) + + for vertex in e1.vertices: + if vertex.y > e1_ymax.y or (vertex.y == e1_ymax.y and vertex.x > e1_ymax.x): + e1_ymax = vertex + for vertex in e2.vertices: + if vertex.y < e2_ymin.y or (vertex.y == e2_ymin.y and vertex.x < e2_ymin.x): + e2_ymin = vertex + min_dist = Point.distance(e1_ymax, e2_ymin) + + ''' + Produce a dictionary with vertices of e1 as the keys and, for each vertex, the points + to which the vertex is connected as its value. The same is then done for e2. + ''' + e1_connections = {} + e2_connections = {} + + for side in e1.sides: + if side.p1 in e1_connections: + e1_connections[side.p1].append(side.p2) + else: + e1_connections[side.p1] = [side.p2] + + if side.p2 in e1_connections: + e1_connections[side.p2].append(side.p1) + else: + e1_connections[side.p2] = [side.p1] + + for side in e2.sides: + if side.p1 in e2_connections: + e2_connections[side.p1].append(side.p2) + else: + e2_connections[side.p1] = [side.p2] + + if side.p2 in e2_connections: + e2_connections[side.p2].append(side.p1) + else: + e2_connections[side.p2] = [side.p1] + + e1_current = e1_ymax + e2_current = e2_ymin + support_line = Line(Point(S.Zero, S.Zero), Point(S.One, S.Zero)) + + ''' + Determine which point in e1 and e2 will be selected after e2_ymin and e1_ymax, + this information combined with the above produced dictionaries determines the + path that will be taken around the polygons + ''' + point1 = e1_connections[e1_ymax][0] + point2 = e1_connections[e1_ymax][1] + angle1 = support_line.angle_between(Line(e1_ymax, point1)) + angle2 = support_line.angle_between(Line(e1_ymax, point2)) + if angle1 < angle2: + e1_next = point1 + elif angle2 < angle1: + e1_next = point2 + elif Point.distance(e1_ymax, point1) > Point.distance(e1_ymax, point2): + e1_next = point2 + else: + e1_next = point1 + + point1 = e2_connections[e2_ymin][0] + point2 = e2_connections[e2_ymin][1] + angle1 = support_line.angle_between(Line(e2_ymin, point1)) + angle2 = support_line.angle_between(Line(e2_ymin, point2)) + if angle1 > angle2: + e2_next = point1 + elif angle2 > angle1: + e2_next = point2 + elif Point.distance(e2_ymin, point1) > Point.distance(e2_ymin, point2): + e2_next = point2 + else: + e2_next = point1 + + ''' + Loop which determines the distance between anti-podal pairs and updates the + minimum distance accordingly. It repeats until it reaches the starting position. + ''' + while True: + e1_angle = support_line.angle_between(Line(e1_current, e1_next)) + e2_angle = pi - support_line.angle_between(Line( + e2_current, e2_next)) + + if (e1_angle < e2_angle) is True: + support_line = Line(e1_current, e1_next) + e1_segment = Segment(e1_current, e1_next) + min_dist_current = e1_segment.distance(e2_current) + + if min_dist_current.evalf() < min_dist.evalf(): + min_dist = min_dist_current + + if e1_connections[e1_next][0] != e1_current: + e1_current = e1_next + e1_next = e1_connections[e1_next][0] + else: + e1_current = e1_next + e1_next = e1_connections[e1_next][1] + elif (e1_angle > e2_angle) is True: + support_line = Line(e2_next, e2_current) + e2_segment = Segment(e2_current, e2_next) + min_dist_current = e2_segment.distance(e1_current) + + if min_dist_current.evalf() < min_dist.evalf(): + min_dist = min_dist_current + + if e2_connections[e2_next][0] != e2_current: + e2_current = e2_next + e2_next = e2_connections[e2_next][0] + else: + e2_current = e2_next + e2_next = e2_connections[e2_next][1] + else: + support_line = Line(e1_current, e1_next) + e1_segment = Segment(e1_current, e1_next) + e2_segment = Segment(e2_current, e2_next) + min1 = e1_segment.distance(e2_next) + min2 = e2_segment.distance(e1_next) + + min_dist_current = min(min1, min2) + if min_dist_current.evalf() < min_dist.evalf(): + min_dist = min_dist_current + + if e1_connections[e1_next][0] != e1_current: + e1_current = e1_next + e1_next = e1_connections[e1_next][0] + else: + e1_current = e1_next + e1_next = e1_connections[e1_next][1] + + if e2_connections[e2_next][0] != e2_current: + e2_current = e2_next + e2_next = e2_connections[e2_next][0] + else: + e2_current = e2_next + e2_next = e2_connections[e2_next][1] + if e1_current == e1_ymax and e2_current == e2_ymin: + break + return min_dist + + def _svg(self, scale_factor=1., fill_color="#66cc99"): + """Returns SVG path element for the Polygon. + + Parameters + ========== + + scale_factor : float + Multiplication factor for the SVG stroke-width. Default is 1. + fill_color : str, optional + Hex string for fill color. Default is "#66cc99". + """ + verts = map(N, self.vertices) + coords = ["{},{}".format(p.x, p.y) for p in verts] + path = "M {} L {} z".format(coords[0], " L ".join(coords[1:])) + return ( + '' + ).format(2. * scale_factor, path, fill_color) + + def _hashable_content(self): + + D = {} + def ref_list(point_list): + kee = {} + for i, p in enumerate(ordered(set(point_list))): + kee[p] = i + D[i] = p + return [kee[p] for p in point_list] + + S1 = ref_list(self.args) + r_nor = rotate_left(S1, least_rotation(S1)) + S2 = ref_list(list(reversed(self.args))) + r_rev = rotate_left(S2, least_rotation(S2)) + if r_nor < r_rev: + r = r_nor + else: + r = r_rev + canonical_args = [ D[order] for order in r ] + return tuple(canonical_args) + + def __contains__(self, o): + """ + Return True if o is contained within the boundary lines of self.altitudes + + Parameters + ========== + + other : GeometryEntity + + Returns + ======= + + contained in : bool + The points (and sides, if applicable) are contained in self. + + See Also + ======== + + sympy.geometry.entity.GeometryEntity.encloses + + Examples + ======== + + >>> from sympy import Line, Segment, Point + >>> p = Point(0, 0) + >>> q = Point(1, 1) + >>> s = Segment(p, q*2) + >>> l = Line(p, q) + >>> p in q + False + >>> p in s + True + >>> q*3 in s + False + >>> s in l + True + + """ + + if isinstance(o, Polygon): + return self == o + elif isinstance(o, Segment): + return any(o in s for s in self.sides) + elif isinstance(o, Point): + if o in self.vertices: + return True + for side in self.sides: + if o in side: + return True + + return False + + def bisectors(p, prec=None): + """Returns angle bisectors of a polygon. If prec is given + then approximate the point defining the ray to that precision. + + The distance between the points defining the bisector ray is 1. + + Examples + ======== + + >>> from sympy import Polygon, Point + >>> p = Polygon(Point(0, 0), Point(2, 0), Point(1, 1), Point(0, 3)) + >>> p.bisectors(2) + {Point2D(0, 0): Ray2D(Point2D(0, 0), Point2D(0.71, 0.71)), + Point2D(0, 3): Ray2D(Point2D(0, 3), Point2D(0.23, 2.0)), + Point2D(1, 1): Ray2D(Point2D(1, 1), Point2D(0.19, 0.42)), + Point2D(2, 0): Ray2D(Point2D(2, 0), Point2D(1.1, 0.38))} + """ + b = {} + pts = list(p.args) + pts.append(pts[0]) # close it + cw = Polygon._is_clockwise(*pts[:3]) + if cw: + pts = list(reversed(pts)) + for v, a in p.angles.items(): + i = pts.index(v) + p1, p2 = Point._normalize_dimension(pts[i], pts[i + 1]) + ray = Ray(p1, p2).rotate(a/2, v) + dir = ray.direction + ray = Ray(ray.p1, ray.p1 + dir/dir.distance((0, 0))) + if prec is not None: + ray = Ray(ray.p1, ray.p2.n(prec)) + b[v] = ray + return b + + +class RegularPolygon(Polygon): + """ + A regular polygon. + + Such a polygon has all internal angles equal and all sides the same length. + + Parameters + ========== + + center : Point + radius : number or Basic instance + The distance from the center to a vertex + n : int + The number of sides + + Attributes + ========== + + vertices + center + radius + rotation + apothem + interior_angle + exterior_angle + circumcircle + incircle + angles + + Raises + ====== + + GeometryError + If the `center` is not a Point, or the `radius` is not a number or Basic + instance, or the number of sides, `n`, is less than three. + + Notes + ===== + + A RegularPolygon can be instantiated with Polygon with the kwarg n. + + Regular polygons are instantiated with a center, radius, number of sides + and a rotation angle. Whereas the arguments of a Polygon are vertices, the + vertices of the RegularPolygon must be obtained with the vertices method. + + See Also + ======== + + sympy.geometry.point.Point, Polygon + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> r = RegularPolygon(Point(0, 0), 5, 3) + >>> r + RegularPolygon(Point2D(0, 0), 5, 3, 0) + >>> r.vertices[0] + Point2D(5, 0) + + """ + + __slots__ = ('_n', '_center', '_radius', '_rot') + + def __new__(self, c, r, n, rot=0, **kwargs): + r, n, rot = map(sympify, (r, n, rot)) + c = Point(c, dim=2, **kwargs) + if not isinstance(r, Expr): + raise GeometryError("r must be an Expr object, not %s" % r) + if n.is_Number: + as_int(n) # let an error raise if necessary + if n < 3: + raise GeometryError("n must be a >= 3, not %s" % n) + + obj = GeometryEntity.__new__(self, c, r, n, **kwargs) + obj._n = n + obj._center = c + obj._radius = r + obj._rot = rot % (2*S.Pi/n) if rot.is_number else rot + return obj + + def _eval_evalf(self, prec=15, **options): + c, r, n, a = self.args + dps = prec_to_dps(prec) + c, r, a = [i.evalf(n=dps, **options) for i in (c, r, a)] + return self.func(c, r, n, a) + + @property + def args(self): + """ + Returns the center point, the radius, + the number of sides, and the orientation angle. + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> r = RegularPolygon(Point(0, 0), 5, 3) + >>> r.args + (Point2D(0, 0), 5, 3, 0) + """ + return self._center, self._radius, self._n, self._rot + + def __str__(self): + return 'RegularPolygon(%s, %s, %s, %s)' % tuple(self.args) + + def __repr__(self): + return 'RegularPolygon(%s, %s, %s, %s)' % tuple(self.args) + + @property + def area(self): + """Returns the area. + + Examples + ======== + + >>> from sympy import RegularPolygon + >>> square = RegularPolygon((0, 0), 1, 4) + >>> square.area + 2 + >>> _ == square.length**2 + True + """ + c, r, n, rot = self.args + return sign(r)*n*self.length**2/(4*tan(pi/n)) + + @property + def length(self): + """Returns the length of the sides. + + The half-length of the side and the apothem form two legs + of a right triangle whose hypotenuse is the radius of the + regular polygon. + + Examples + ======== + + >>> from sympy import RegularPolygon + >>> from sympy import sqrt + >>> s = square_in_unit_circle = RegularPolygon((0, 0), 1, 4) + >>> s.length + sqrt(2) + >>> sqrt((_/2)**2 + s.apothem**2) == s.radius + True + + """ + return self.radius*2*sin(pi/self._n) + + @property + def center(self): + """The center of the RegularPolygon + + This is also the center of the circumscribing circle. + + Returns + ======= + + center : Point + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.ellipse.Ellipse.center + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> rp = RegularPolygon(Point(0, 0), 5, 4) + >>> rp.center + Point2D(0, 0) + """ + return self._center + + centroid = center + + @property + def circumcenter(self): + """ + Alias for center. + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> rp = RegularPolygon(Point(0, 0), 5, 4) + >>> rp.circumcenter + Point2D(0, 0) + """ + return self.center + + @property + def radius(self): + """Radius of the RegularPolygon + + This is also the radius of the circumscribing circle. + + Returns + ======= + + radius : number or instance of Basic + + See Also + ======== + + sympy.geometry.line.Segment.length, sympy.geometry.ellipse.Circle.radius + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy import RegularPolygon, Point + >>> radius = Symbol('r') + >>> rp = RegularPolygon(Point(0, 0), radius, 4) + >>> rp.radius + r + + """ + return self._radius + + @property + def circumradius(self): + """ + Alias for radius. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy import RegularPolygon, Point + >>> radius = Symbol('r') + >>> rp = RegularPolygon(Point(0, 0), radius, 4) + >>> rp.circumradius + r + """ + return self.radius + + @property + def rotation(self): + """CCW angle by which the RegularPolygon is rotated + + Returns + ======= + + rotation : number or instance of Basic + + Examples + ======== + + >>> from sympy import pi + >>> from sympy.abc import a + >>> from sympy import RegularPolygon, Point + >>> RegularPolygon(Point(0, 0), 3, 4, pi/4).rotation + pi/4 + + Numerical rotation angles are made canonical: + + >>> RegularPolygon(Point(0, 0), 3, 4, a).rotation + a + >>> RegularPolygon(Point(0, 0), 3, 4, pi).rotation + 0 + + """ + return self._rot + + @property + def apothem(self): + """The inradius of the RegularPolygon. + + The apothem/inradius is the radius of the inscribed circle. + + Returns + ======= + + apothem : number or instance of Basic + + See Also + ======== + + sympy.geometry.line.Segment.length, sympy.geometry.ellipse.Circle.radius + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy import RegularPolygon, Point + >>> radius = Symbol('r') + >>> rp = RegularPolygon(Point(0, 0), radius, 4) + >>> rp.apothem + sqrt(2)*r/2 + + """ + return self.radius * cos(S.Pi/self._n) + + @property + def inradius(self): + """ + Alias for apothem. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy import RegularPolygon, Point + >>> radius = Symbol('r') + >>> rp = RegularPolygon(Point(0, 0), radius, 4) + >>> rp.inradius + sqrt(2)*r/2 + """ + return self.apothem + + @property + def interior_angle(self): + """Measure of the interior angles. + + Returns + ======= + + interior_angle : number + + See Also + ======== + + sympy.geometry.line.LinearEntity.angle_between + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> rp = RegularPolygon(Point(0, 0), 4, 8) + >>> rp.interior_angle + 3*pi/4 + + """ + return (self._n - 2)*S.Pi/self._n + + @property + def exterior_angle(self): + """Measure of the exterior angles. + + Returns + ======= + + exterior_angle : number + + See Also + ======== + + sympy.geometry.line.LinearEntity.angle_between + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> rp = RegularPolygon(Point(0, 0), 4, 8) + >>> rp.exterior_angle + pi/4 + + """ + return 2*S.Pi/self._n + + @property + def circumcircle(self): + """The circumcircle of the RegularPolygon. + + Returns + ======= + + circumcircle : Circle + + See Also + ======== + + circumcenter, sympy.geometry.ellipse.Circle + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> rp = RegularPolygon(Point(0, 0), 4, 8) + >>> rp.circumcircle + Circle(Point2D(0, 0), 4) + + """ + return Circle(self.center, self.radius) + + @property + def incircle(self): + """The incircle of the RegularPolygon. + + Returns + ======= + + incircle : Circle + + See Also + ======== + + inradius, sympy.geometry.ellipse.Circle + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> rp = RegularPolygon(Point(0, 0), 4, 7) + >>> rp.incircle + Circle(Point2D(0, 0), 4*cos(pi/7)) + + """ + return Circle(self.center, self.apothem) + + @property + def angles(self): + """ + Returns a dictionary with keys, the vertices of the Polygon, + and values, the interior angle at each vertex. + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> r = RegularPolygon(Point(0, 0), 5, 3) + >>> r.angles + {Point2D(-5/2, -5*sqrt(3)/2): pi/3, + Point2D(-5/2, 5*sqrt(3)/2): pi/3, + Point2D(5, 0): pi/3} + """ + ret = {} + ang = self.interior_angle + for v in self.vertices: + ret[v] = ang + return ret + + def encloses_point(self, p): + """ + Return True if p is enclosed by (is inside of) self. + + Notes + ===== + + Being on the border of self is considered False. + + The general Polygon.encloses_point method is called only if + a point is not within or beyond the incircle or circumcircle, + respectively. + + Parameters + ========== + + p : Point + + Returns + ======= + + encloses_point : True, False or None + + See Also + ======== + + sympy.geometry.ellipse.Ellipse.encloses_point + + Examples + ======== + + >>> from sympy import RegularPolygon, S, Point, Symbol + >>> p = RegularPolygon((0, 0), 3, 4) + >>> p.encloses_point(Point(0, 0)) + True + >>> r, R = p.inradius, p.circumradius + >>> p.encloses_point(Point((r + R)/2, 0)) + True + >>> p.encloses_point(Point(R/2, R/2 + (R - r)/10)) + False + >>> t = Symbol('t', real=True) + >>> p.encloses_point(p.arbitrary_point().subs(t, S.Half)) + False + >>> p.encloses_point(Point(5, 5)) + False + + """ + + c = self.center + d = Segment(c, p).length + if d >= self.radius: + return False + elif d < self.inradius: + return True + else: + # now enumerate the RegularPolygon like a general polygon. + return Polygon.encloses_point(self, p) + + def spin(self, angle): + """Increment *in place* the virtual Polygon's rotation by ccw angle. + + See also: rotate method which moves the center. + + >>> from sympy import Polygon, Point, pi + >>> r = Polygon(Point(0,0), 1, n=3) + >>> r.vertices[0] + Point2D(1, 0) + >>> r.spin(pi/6) + >>> r.vertices[0] + Point2D(sqrt(3)/2, 1/2) + + See Also + ======== + + rotation + rotate : Creates a copy of the RegularPolygon rotated about a Point + + """ + self._rot += angle + + def rotate(self, angle, pt=None): + """Override GeometryEntity.rotate to first rotate the RegularPolygon + about its center. + + >>> from sympy import Point, RegularPolygon, pi + >>> t = RegularPolygon(Point(1, 0), 1, 3) + >>> t.vertices[0] # vertex on x-axis + Point2D(2, 0) + >>> t.rotate(pi/2).vertices[0] # vertex on y axis now + Point2D(0, 2) + + See Also + ======== + + rotation + spin : Rotates a RegularPolygon in place + + """ + + r = type(self)(*self.args) # need a copy or else changes are in-place + r._rot += angle + return GeometryEntity.rotate(r, angle, pt) + + def scale(self, x=1, y=1, pt=None): + """Override GeometryEntity.scale since it is the radius that must be + scaled (if x == y) or else a new Polygon must be returned. + + >>> from sympy import RegularPolygon + + Symmetric scaling returns a RegularPolygon: + + >>> RegularPolygon((0, 0), 1, 4).scale(2, 2) + RegularPolygon(Point2D(0, 0), 2, 4, 0) + + Asymmetric scaling returns a kite as a Polygon: + + >>> RegularPolygon((0, 0), 1, 4).scale(2, 1) + Polygon(Point2D(2, 0), Point2D(0, 1), Point2D(-2, 0), Point2D(0, -1)) + + """ + if pt: + pt = Point(pt, dim=2) + return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) + if x != y: + return Polygon(*self.vertices).scale(x, y) + c, r, n, rot = self.args + r *= x + return self.func(c, r, n, rot) + + def reflect(self, line): + """Override GeometryEntity.reflect since this is not made of only + points. + + Examples + ======== + + >>> from sympy import RegularPolygon, Line + + >>> RegularPolygon((0, 0), 1, 4).reflect(Line((0, 1), slope=-2)) + RegularPolygon(Point2D(4/5, 2/5), -1, 4, atan(4/3)) + + """ + c, r, n, rot = self.args + v = self.vertices[0] + d = v - c + cc = c.reflect(line) + vv = v.reflect(line) + dd = vv - cc + # calculate rotation about the new center + # which will align the vertices + l1 = Ray((0, 0), dd) + l2 = Ray((0, 0), d) + ang = l1.closing_angle(l2) + rot += ang + # change sign of radius as point traversal is reversed + return self.func(cc, -r, n, rot) + + @property + def vertices(self): + """The vertices of the RegularPolygon. + + Returns + ======= + + vertices : list + Each vertex is a Point. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import RegularPolygon, Point + >>> rp = RegularPolygon(Point(0, 0), 5, 4) + >>> rp.vertices + [Point2D(5, 0), Point2D(0, 5), Point2D(-5, 0), Point2D(0, -5)] + + """ + c = self._center + r = abs(self._radius) + rot = self._rot + v = 2*S.Pi/self._n + + return [Point(c.x + r*cos(k*v + rot), c.y + r*sin(k*v + rot)) + for k in range(self._n)] + + def __eq__(self, o): + if not isinstance(o, Polygon): + return False + elif not isinstance(o, RegularPolygon): + return Polygon.__eq__(o, self) + return self.args == o.args + + def __hash__(self): + return super().__hash__() + + +class Triangle(Polygon): + """ + A polygon with three vertices and three sides. + + Parameters + ========== + + points : sequence of Points + keyword: asa, sas, or sss to specify sides/angles of the triangle + + Attributes + ========== + + vertices + altitudes + orthocenter + circumcenter + circumradius + circumcircle + inradius + incircle + exradii + medians + medial + nine_point_circle + + Raises + ====== + + GeometryError + If the number of vertices is not equal to three, or one of the vertices + is not a Point, or a valid keyword is not given. + + See Also + ======== + + sympy.geometry.point.Point, Polygon + + Examples + ======== + + >>> from sympy import Triangle, Point + >>> Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) + Triangle(Point2D(0, 0), Point2D(4, 0), Point2D(4, 3)) + + Keywords sss, sas, or asa can be used to give the desired + side lengths (in order) and interior angles (in degrees) that + define the triangle: + + >>> Triangle(sss=(3, 4, 5)) + Triangle(Point2D(0, 0), Point2D(3, 0), Point2D(3, 4)) + >>> Triangle(asa=(30, 1, 30)) + Triangle(Point2D(0, 0), Point2D(1, 0), Point2D(1/2, sqrt(3)/6)) + >>> Triangle(sas=(1, 45, 2)) + Triangle(Point2D(0, 0), Point2D(2, 0), Point2D(sqrt(2)/2, sqrt(2)/2)) + + """ + + def __new__(cls, *args, **kwargs): + if len(args) != 3: + if 'sss' in kwargs: + return _sss(*[simplify(a) for a in kwargs['sss']]) + if 'asa' in kwargs: + return _asa(*[simplify(a) for a in kwargs['asa']]) + if 'sas' in kwargs: + return _sas(*[simplify(a) for a in kwargs['sas']]) + msg = "Triangle instantiates with three points or a valid keyword." + raise GeometryError(msg) + + vertices = [Point(a, dim=2, **kwargs) for a in args] + + # remove consecutive duplicates + nodup = [] + for p in vertices: + if nodup and p == nodup[-1]: + continue + nodup.append(p) + if len(nodup) > 1 and nodup[-1] == nodup[0]: + nodup.pop() # last point was same as first + + # remove collinear points + i = -3 + while i < len(nodup) - 3 and len(nodup) > 2: + a, b, c = sorted( + [nodup[i], nodup[i + 1], nodup[i + 2]], key=default_sort_key) + if Point.is_collinear(a, b, c): + nodup[i] = a + nodup[i + 1] = None + nodup.pop(i + 1) + i += 1 + + vertices = list(filter(lambda x: x is not None, nodup)) + + if len(vertices) == 3: + return GeometryEntity.__new__(cls, *vertices, **kwargs) + elif len(vertices) == 2: + return Segment(*vertices, **kwargs) + else: + return Point(*vertices, **kwargs) + + @property + def vertices(self): + """The triangle's vertices + + Returns + ======= + + vertices : tuple + Each element in the tuple is a Point + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Triangle, Point + >>> t = Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) + >>> t.vertices + (Point2D(0, 0), Point2D(4, 0), Point2D(4, 3)) + + """ + return self.args + + def is_similar(t1, t2): + """Is another triangle similar to this one. + + Two triangles are similar if one can be uniformly scaled to the other. + + Parameters + ========== + + other: Triangle + + Returns + ======= + + is_similar : boolean + + See Also + ======== + + sympy.geometry.entity.GeometryEntity.is_similar + + Examples + ======== + + >>> from sympy import Triangle, Point + >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) + >>> t2 = Triangle(Point(0, 0), Point(-4, 0), Point(-4, -3)) + >>> t1.is_similar(t2) + True + + >>> t2 = Triangle(Point(0, 0), Point(-4, 0), Point(-4, -4)) + >>> t1.is_similar(t2) + False + + """ + if not isinstance(t2, Polygon): + return False + + s1_1, s1_2, s1_3 = [side.length for side in t1.sides] + s2 = [side.length for side in t2.sides] + + def _are_similar(u1, u2, u3, v1, v2, v3): + e1 = simplify(u1/v1) + e2 = simplify(u2/v2) + e3 = simplify(u3/v3) + return bool(e1 == e2) and bool(e2 == e3) + + # There's only 6 permutations, so write them out + return _are_similar(s1_1, s1_2, s1_3, *s2) or \ + _are_similar(s1_1, s1_3, s1_2, *s2) or \ + _are_similar(s1_2, s1_1, s1_3, *s2) or \ + _are_similar(s1_2, s1_3, s1_1, *s2) or \ + _are_similar(s1_3, s1_1, s1_2, *s2) or \ + _are_similar(s1_3, s1_2, s1_1, *s2) + + def is_equilateral(self): + """Are all the sides the same length? + + Returns + ======= + + is_equilateral : boolean + + See Also + ======== + + sympy.geometry.entity.GeometryEntity.is_similar, RegularPolygon + is_isosceles, is_right, is_scalene + + Examples + ======== + + >>> from sympy import Triangle, Point + >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) + >>> t1.is_equilateral() + False + + >>> from sympy import sqrt + >>> t2 = Triangle(Point(0, 0), Point(10, 0), Point(5, 5*sqrt(3))) + >>> t2.is_equilateral() + True + + """ + return not has_variety(s.length for s in self.sides) + + def is_isosceles(self): + """Are two or more of the sides the same length? + + Returns + ======= + + is_isosceles : boolean + + See Also + ======== + + is_equilateral, is_right, is_scalene + + Examples + ======== + + >>> from sympy import Triangle, Point + >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(2, 4)) + >>> t1.is_isosceles() + True + + """ + return has_dups(s.length for s in self.sides) + + def is_scalene(self): + """Are all the sides of the triangle of different lengths? + + Returns + ======= + + is_scalene : boolean + + See Also + ======== + + is_equilateral, is_isosceles, is_right + + Examples + ======== + + >>> from sympy import Triangle, Point + >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(1, 4)) + >>> t1.is_scalene() + True + + """ + return not has_dups(s.length for s in self.sides) + + def is_right(self): + """Is the triangle right-angled. + + Returns + ======= + + is_right : boolean + + See Also + ======== + + sympy.geometry.line.LinearEntity.is_perpendicular + is_equilateral, is_isosceles, is_scalene + + Examples + ======== + + >>> from sympy import Triangle, Point + >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) + >>> t1.is_right() + True + + """ + s = self.sides + return Segment.is_perpendicular(s[0], s[1]) or \ + Segment.is_perpendicular(s[1], s[2]) or \ + Segment.is_perpendicular(s[0], s[2]) + + @property + def altitudes(self): + """The altitudes of the triangle. + + An altitude of a triangle is a segment through a vertex, + perpendicular to the opposite side, with length being the + height of the vertex measured from the line containing the side. + + Returns + ======= + + altitudes : dict + The dictionary consists of keys which are vertices and values + which are Segments. + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.line.Segment.length + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.altitudes[p1] + Segment2D(Point2D(0, 0), Point2D(1/2, 1/2)) + + """ + s = self.sides + v = self.vertices + return {v[0]: s[1].perpendicular_segment(v[0]), + v[1]: s[2].perpendicular_segment(v[1]), + v[2]: s[0].perpendicular_segment(v[2])} + + @property + def orthocenter(self): + """The orthocenter of the triangle. + + The orthocenter is the intersection of the altitudes of a triangle. + It may lie inside, outside or on the triangle. + + Returns + ======= + + orthocenter : Point + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.orthocenter + Point2D(0, 0) + + """ + a = self.altitudes + v = self.vertices + return Line(a[v[0]]).intersection(Line(a[v[1]]))[0] + + @property + def circumcenter(self): + """The circumcenter of the triangle + + The circumcenter is the center of the circumcircle. + + Returns + ======= + + circumcenter : Point + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.circumcenter + Point2D(1/2, 1/2) + """ + a, b, c = [x.perpendicular_bisector() for x in self.sides] + return a.intersection(b)[0] + + @property + def circumradius(self): + """The radius of the circumcircle of the triangle. + + Returns + ======= + + circumradius : number of Basic instance + + See Also + ======== + + sympy.geometry.ellipse.Circle.radius + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy import Point, Triangle + >>> a = Symbol('a') + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, a) + >>> t = Triangle(p1, p2, p3) + >>> t.circumradius + sqrt(a**2/4 + 1/4) + """ + return Point.distance(self.circumcenter, self.vertices[0]) + + @property + def circumcircle(self): + """The circle which passes through the three vertices of the triangle. + + Returns + ======= + + circumcircle : Circle + + See Also + ======== + + sympy.geometry.ellipse.Circle + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.circumcircle + Circle(Point2D(1/2, 1/2), sqrt(2)/2) + + """ + return Circle(self.circumcenter, self.circumradius) + + def bisectors(self): + """The angle bisectors of the triangle. + + An angle bisector of a triangle is a straight line through a vertex + which cuts the corresponding angle in half. + + Returns + ======= + + bisectors : dict + Each key is a vertex (Point) and each value is the corresponding + bisector (Segment). + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.line.Segment + + Examples + ======== + + >>> from sympy import Point, Triangle, Segment + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> from sympy import sqrt + >>> t.bisectors()[p2] == Segment(Point(1, 0), Point(0, sqrt(2) - 1)) + True + + """ + # use lines containing sides so containment check during + # intersection calculation can be avoided, thus reducing + # the processing time for calculating the bisectors + s = [Line(l) for l in self.sides] + v = self.vertices + c = self.incenter + l1 = Segment(v[0], Line(v[0], c).intersection(s[1])[0]) + l2 = Segment(v[1], Line(v[1], c).intersection(s[2])[0]) + l3 = Segment(v[2], Line(v[2], c).intersection(s[0])[0]) + return {v[0]: l1, v[1]: l2, v[2]: l3} + + @property + def incenter(self): + """The center of the incircle. + + The incircle is the circle which lies inside the triangle and touches + all three sides. + + Returns + ======= + + incenter : Point + + See Also + ======== + + incircle, sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.incenter + Point2D(1 - sqrt(2)/2, 1 - sqrt(2)/2) + + """ + s = self.sides + l = Matrix([s[i].length for i in [1, 2, 0]]) + p = sum(l) + v = self.vertices + x = simplify(l.dot(Matrix([vi.x for vi in v]))/p) + y = simplify(l.dot(Matrix([vi.y for vi in v]))/p) + return Point(x, y) + + @property + def inradius(self): + """The radius of the incircle. + + Returns + ======= + + inradius : number of Basic instance + + See Also + ======== + + incircle, sympy.geometry.ellipse.Circle.radius + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(4, 0), Point(0, 3) + >>> t = Triangle(p1, p2, p3) + >>> t.inradius + 1 + + """ + return simplify(2 * self.area / self.perimeter) + + @property + def incircle(self): + """The incircle of the triangle. + + The incircle is the circle which lies inside the triangle and touches + all three sides. + + Returns + ======= + + incircle : Circle + + See Also + ======== + + sympy.geometry.ellipse.Circle + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(2, 0), Point(0, 2) + >>> t = Triangle(p1, p2, p3) + >>> t.incircle + Circle(Point2D(2 - sqrt(2), 2 - sqrt(2)), 2 - sqrt(2)) + + """ + return Circle(self.incenter, self.inradius) + + @property + def exradii(self): + """The radius of excircles of a triangle. + + An excircle of the triangle is a circle lying outside the triangle, + tangent to one of its sides and tangent to the extensions of the + other two. + + Returns + ======= + + exradii : dict + + See Also + ======== + + sympy.geometry.polygon.Triangle.inradius + + Examples + ======== + + The exradius touches the side of the triangle to which it is keyed, e.g. + the exradius touching side 2 is: + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(6, 0), Point(0, 2) + >>> t = Triangle(p1, p2, p3) + >>> t.exradii[t.sides[2]] + -2 + sqrt(10) + + References + ========== + + .. [1] https://mathworld.wolfram.com/Exradius.html + .. [2] https://mathworld.wolfram.com/Excircles.html + + """ + + side = self.sides + a = side[0].length + b = side[1].length + c = side[2].length + s = (a+b+c)/2 + area = self.area + exradii = {self.sides[0]: simplify(area/(s-a)), + self.sides[1]: simplify(area/(s-b)), + self.sides[2]: simplify(area/(s-c))} + + return exradii + + @property + def excenters(self): + """Excenters of the triangle. + + An excenter is the center of a circle that is tangent to a side of the + triangle and the extensions of the other two sides. + + Returns + ======= + + excenters : dict + + + Examples + ======== + + The excenters are keyed to the side of the triangle to which their corresponding + excircle is tangent: The center is keyed, e.g. the excenter of a circle touching + side 0 is: + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(6, 0), Point(0, 2) + >>> t = Triangle(p1, p2, p3) + >>> t.excenters[t.sides[0]] + Point2D(12*sqrt(10), 2/3 + sqrt(10)/3) + + See Also + ======== + + sympy.geometry.polygon.Triangle.exradii + + References + ========== + + .. [1] https://mathworld.wolfram.com/Excircles.html + + """ + + s = self.sides + v = self.vertices + a = s[0].length + b = s[1].length + c = s[2].length + x = [v[0].x, v[1].x, v[2].x] + y = [v[0].y, v[1].y, v[2].y] + + exc_coords = { + "x1": simplify(-a*x[0]+b*x[1]+c*x[2]/(-a+b+c)), + "x2": simplify(a*x[0]-b*x[1]+c*x[2]/(a-b+c)), + "x3": simplify(a*x[0]+b*x[1]-c*x[2]/(a+b-c)), + "y1": simplify(-a*y[0]+b*y[1]+c*y[2]/(-a+b+c)), + "y2": simplify(a*y[0]-b*y[1]+c*y[2]/(a-b+c)), + "y3": simplify(a*y[0]+b*y[1]-c*y[2]/(a+b-c)) + } + + excenters = { + s[0]: Point(exc_coords["x1"], exc_coords["y1"]), + s[1]: Point(exc_coords["x2"], exc_coords["y2"]), + s[2]: Point(exc_coords["x3"], exc_coords["y3"]) + } + + return excenters + + @property + def medians(self): + """The medians of the triangle. + + A median of a triangle is a straight line through a vertex and the + midpoint of the opposite side, and divides the triangle into two + equal areas. + + Returns + ======= + + medians : dict + Each key is a vertex (Point) and each value is the median (Segment) + at that point. + + See Also + ======== + + sympy.geometry.point.Point.midpoint, sympy.geometry.line.Segment.midpoint + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.medians[p1] + Segment2D(Point2D(0, 0), Point2D(1/2, 1/2)) + + """ + s = self.sides + v = self.vertices + return {v[0]: Segment(v[0], s[1].midpoint), + v[1]: Segment(v[1], s[2].midpoint), + v[2]: Segment(v[2], s[0].midpoint)} + + @property + def medial(self): + """The medial triangle of the triangle. + + The triangle which is formed from the midpoints of the three sides. + + Returns + ======= + + medial : Triangle + + See Also + ======== + + sympy.geometry.line.Segment.midpoint + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.medial + Triangle(Point2D(1/2, 0), Point2D(1/2, 1/2), Point2D(0, 1/2)) + + """ + s = self.sides + return Triangle(s[0].midpoint, s[1].midpoint, s[2].midpoint) + + @property + def nine_point_circle(self): + """The nine-point circle of the triangle. + + Nine-point circle is the circumcircle of the medial triangle, which + passes through the feet of altitudes and the middle points of segments + connecting the vertices and the orthocenter. + + Returns + ======= + + nine_point_circle : Circle + + See also + ======== + + sympy.geometry.line.Segment.midpoint + sympy.geometry.polygon.Triangle.medial + sympy.geometry.polygon.Triangle.orthocenter + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.nine_point_circle + Circle(Point2D(1/4, 1/4), sqrt(2)/4) + + """ + return Circle(*self.medial.vertices) + + @property + def eulerline(self): + """The Euler line of the triangle. + + The line which passes through circumcenter, centroid and orthocenter. + + Returns + ======= + + eulerline : Line (or Point for equilateral triangles in which case all + centers coincide) + + Examples + ======== + + >>> from sympy import Point, Triangle + >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) + >>> t = Triangle(p1, p2, p3) + >>> t.eulerline + Line2D(Point2D(0, 0), Point2D(1/2, 1/2)) + + """ + if self.is_equilateral(): + return self.orthocenter + return Line(self.orthocenter, self.circumcenter) + +def rad(d): + """Return the radian value for the given degrees (pi = 180 degrees).""" + return d*pi/180 + + +def deg(r): + """Return the degree value for the given radians (pi = 180 degrees).""" + return r/pi*180 + + +def _slope(d): + rv = tan(rad(d)) + return rv + + +def _asa(d1, l, d2): + """Return triangle having side with length l on the x-axis.""" + xy = Line((0, 0), slope=_slope(d1)).intersection( + Line((l, 0), slope=_slope(180 - d2)))[0] + return Triangle((0, 0), (l, 0), xy) + + +def _sss(l1, l2, l3): + """Return triangle having side of length l1 on the x-axis.""" + c1 = Circle((0, 0), l3) + c2 = Circle((l1, 0), l2) + inter = [a for a in c1.intersection(c2) if a.y.is_nonnegative] + if not inter: + return None + pt = inter[0] + return Triangle((0, 0), (l1, 0), pt) + + +def _sas(l1, d, l2): + """Return triangle having side with length l2 on the x-axis.""" + p1 = Point(0, 0) + p2 = Point(l2, 0) + p3 = Point(cos(rad(d))*l1, sin(rad(d))*l1) + return Triangle(p1, p2, p3) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/util.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/util.py new file mode 100644 index 0000000000000000000000000000000000000000..1d8fb77550f2faea8185ff0c373b5f1680e623ec --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/geometry/util.py @@ -0,0 +1,731 @@ +"""Utility functions for geometrical entities. + +Contains +======== +intersection +convex_hull +closest_points +farthest_points +are_coplanar +are_similar + +""" + +from collections import deque +from math import sqrt as _sqrt + +from sympy import nsimplify +from .entity import GeometryEntity +from .exceptions import GeometryError +from .point import Point, Point2D, Point3D +from sympy.core.containers import OrderedSet +from sympy.core.exprtools import factor_terms +from sympy.core.function import Function, expand_mul +from sympy.core.numbers import Float +from sympy.core.sorting import ordered +from sympy.core.symbol import Symbol +from sympy.core.singleton import S +from sympy.polys.polytools import cancel +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.utilities.iterables import is_sequence + +from mpmath.libmp.libmpf import prec_to_dps + + +def find(x, equation): + """ + Checks whether a Symbol matching ``x`` is present in ``equation`` + or not. If present, the matching symbol is returned, else a + ValueError is raised. If ``x`` is a string the matching symbol + will have the same name; if ``x`` is a Symbol then it will be + returned if found. + + Examples + ======== + + >>> from sympy.geometry.util import find + >>> from sympy import Dummy + >>> from sympy.abc import x + >>> find('x', x) + x + >>> find('x', Dummy('x')) + _x + + The dummy symbol is returned since it has a matching name: + + >>> _.name == 'x' + True + >>> find(x, Dummy('x')) + Traceback (most recent call last): + ... + ValueError: could not find x + """ + + free = equation.free_symbols + xs = [i for i in free if (i.name if isinstance(x, str) else i) == x] + if not xs: + raise ValueError('could not find %s' % x) + if len(xs) != 1: + raise ValueError('ambiguous %s' % x) + return xs[0] + + +def _ordered_points(p): + """Return the tuple of points sorted numerically according to args""" + return tuple(sorted(p, key=lambda x: x.args)) + + +def are_coplanar(*e): + """ Returns True if the given entities are coplanar otherwise False + + Parameters + ========== + + e: entities to be checked for being coplanar + + Returns + ======= + + Boolean + + Examples + ======== + + >>> from sympy import Point3D, Line3D + >>> from sympy.geometry.util import are_coplanar + >>> a = Line3D(Point3D(5, 0, 0), Point3D(1, -1, 1)) + >>> b = Line3D(Point3D(0, -2, 0), Point3D(3, 1, 1)) + >>> c = Line3D(Point3D(0, -1, 0), Point3D(5, -1, 9)) + >>> are_coplanar(a, b, c) + False + + """ + from .line import LinearEntity3D + from .plane import Plane + # XXX update tests for coverage + + e = set(e) + # first work with a Plane if present + for i in list(e): + if isinstance(i, Plane): + e.remove(i) + return all(p.is_coplanar(i) for p in e) + + if all(isinstance(i, Point3D) for i in e): + if len(e) < 3: + return False + + # remove pts that are collinear with 2 pts + a, b = e.pop(), e.pop() + for i in list(e): + if Point3D.are_collinear(a, b, i): + e.remove(i) + + if not e: + return False + else: + # define a plane + p = Plane(a, b, e.pop()) + for i in e: + if i not in p: + return False + return True + else: + pt3d = [] + for i in e: + if isinstance(i, Point3D): + pt3d.append(i) + elif isinstance(i, LinearEntity3D): + pt3d.extend(i.args) + elif isinstance(i, GeometryEntity): # XXX we should have a GeometryEntity3D class so we can tell the difference between 2D and 3D -- here we just want to deal with 2D objects; if new 3D objects are encountered that we didn't handle above, an error should be raised + # all 2D objects have some Point that defines them; so convert those points to 3D pts by making z=0 + for p in i.args: + if isinstance(p, Point): + pt3d.append(Point3D(*(p.args + (0,)))) + return are_coplanar(*pt3d) + + +def are_similar(e1, e2): + """Are two geometrical entities similar. + + Can one geometrical entity be uniformly scaled to the other? + + Parameters + ========== + + e1 : GeometryEntity + e2 : GeometryEntity + + Returns + ======= + + are_similar : boolean + + Raises + ====== + + GeometryError + When `e1` and `e2` cannot be compared. + + Notes + ===== + + If the two objects are equal then they are similar. + + See Also + ======== + + sympy.geometry.entity.GeometryEntity.is_similar + + Examples + ======== + + >>> from sympy import Point, Circle, Triangle, are_similar + >>> c1, c2 = Circle(Point(0, 0), 4), Circle(Point(1, 4), 3) + >>> t1 = Triangle(Point(0, 0), Point(1, 0), Point(0, 1)) + >>> t2 = Triangle(Point(0, 0), Point(2, 0), Point(0, 2)) + >>> t3 = Triangle(Point(0, 0), Point(3, 0), Point(0, 1)) + >>> are_similar(t1, t2) + True + >>> are_similar(t1, t3) + False + + """ + if e1 == e2: + return True + is_similar1 = getattr(e1, 'is_similar', None) + if is_similar1: + return is_similar1(e2) + is_similar2 = getattr(e2, 'is_similar', None) + if is_similar2: + return is_similar2(e1) + n1 = e1.__class__.__name__ + n2 = e2.__class__.__name__ + raise GeometryError( + "Cannot test similarity between %s and %s" % (n1, n2)) + + +def centroid(*args): + """Find the centroid (center of mass) of the collection containing only Points, + Segments or Polygons. The centroid is the weighted average of the individual centroid + where the weights are the lengths (of segments) or areas (of polygons). + Overlapping regions will add to the weight of that region. + + If there are no objects (or a mixture of objects) then None is returned. + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.line.Segment, + sympy.geometry.polygon.Polygon + + Examples + ======== + + >>> from sympy import Point, Segment, Polygon + >>> from sympy.geometry.util import centroid + >>> p = Polygon((0, 0), (10, 0), (10, 10)) + >>> q = p.translate(0, 20) + >>> p.centroid, q.centroid + (Point2D(20/3, 10/3), Point2D(20/3, 70/3)) + >>> centroid(p, q) + Point2D(20/3, 40/3) + >>> p, q = Segment((0, 0), (2, 0)), Segment((0, 0), (2, 2)) + >>> centroid(p, q) + Point2D(1, 2 - sqrt(2)) + >>> centroid(Point(0, 0), Point(2, 0)) + Point2D(1, 0) + + Stacking 3 polygons on top of each other effectively triples the + weight of that polygon: + + >>> p = Polygon((0, 0), (1, 0), (1, 1), (0, 1)) + >>> q = Polygon((1, 0), (3, 0), (3, 1), (1, 1)) + >>> centroid(p, q) + Point2D(3/2, 1/2) + >>> centroid(p, p, p, q) # centroid x-coord shifts left + Point2D(11/10, 1/2) + + Stacking the squares vertically above and below p has the same + effect: + + >>> centroid(p, p.translate(0, 1), p.translate(0, -1), q) + Point2D(11/10, 1/2) + + """ + from .line import Segment + from .polygon import Polygon + if args: + if all(isinstance(g, Point) for g in args): + c = Point(0, 0) + for g in args: + c += g + den = len(args) + elif all(isinstance(g, Segment) for g in args): + c = Point(0, 0) + L = 0 + for g in args: + l = g.length + c += g.midpoint*l + L += l + den = L + elif all(isinstance(g, Polygon) for g in args): + c = Point(0, 0) + A = 0 + for g in args: + a = g.area + c += g.centroid*a + A += a + den = A + c /= den + return c.func(*[i.simplify() for i in c.args]) + + +def closest_points(*args): + """Return the subset of points from a set of points that were + the closest to each other in the 2D plane. + + Parameters + ========== + + args + A collection of Points on 2D plane. + + Notes + ===== + + This can only be performed on a set of points whose coordinates can + be ordered on the number line. If there are no ties then a single + pair of Points will be in the set. + + Examples + ======== + + >>> from sympy import closest_points, Triangle + >>> Triangle(sss=(3, 4, 5)).args + (Point2D(0, 0), Point2D(3, 0), Point2D(3, 4)) + >>> closest_points(*_) + {(Point2D(0, 0), Point2D(3, 0))} + + References + ========== + + .. [1] https://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairPS.html + + .. [2] Sweep line algorithm + https://en.wikipedia.org/wiki/Sweep_line_algorithm + + """ + p = [Point2D(i) for i in set(args)] + if len(p) < 2: + raise ValueError('At least 2 distinct points must be given.') + + try: + p.sort(key=lambda x: x.args) + except TypeError: + raise ValueError("The points could not be sorted.") + + if not all(i.is_Rational for j in p for i in j.args): + def hypot(x, y): + arg = x*x + y*y + if arg.is_Rational: + return _sqrt(arg) + return sqrt(arg) + else: + from math import hypot + + rv = [(0, 1)] + best_dist = hypot(p[1].x - p[0].x, p[1].y - p[0].y) + left = 0 + box = deque([0, 1]) + for i in range(2, len(p)): + while left < i and p[i][0] - p[left][0] > best_dist: + box.popleft() + left += 1 + + for j in box: + d = hypot(p[i].x - p[j].x, p[i].y - p[j].y) + if d < best_dist: + rv = [(j, i)] + elif d == best_dist: + rv.append((j, i)) + else: + continue + best_dist = d + box.append(i) + + return {tuple([p[i] for i in pair]) for pair in rv} + + +def convex_hull(*args, polygon=True): + """The convex hull surrounding the Points contained in the list of entities. + + Parameters + ========== + + args : a collection of Points, Segments and/or Polygons + + Optional parameters + =================== + + polygon : Boolean. If True, returns a Polygon, if false a tuple, see below. + Default is True. + + Returns + ======= + + convex_hull : Polygon if ``polygon`` is True else as a tuple `(U, L)` where + ``L`` and ``U`` are the lower and upper hulls, respectively. + + Notes + ===== + + This can only be performed on a set of points whose coordinates can + be ordered on the number line. + + See Also + ======== + + sympy.geometry.point.Point, sympy.geometry.polygon.Polygon + + Examples + ======== + + >>> from sympy import convex_hull + >>> points = [(1, 1), (1, 2), (3, 1), (-5, 2), (15, 4)] + >>> convex_hull(*points) + Polygon(Point2D(-5, 2), Point2D(1, 1), Point2D(3, 1), Point2D(15, 4)) + >>> convex_hull(*points, **dict(polygon=False)) + ([Point2D(-5, 2), Point2D(15, 4)], + [Point2D(-5, 2), Point2D(1, 1), Point2D(3, 1), Point2D(15, 4)]) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Graham_scan + + .. [2] Andrew's Monotone Chain Algorithm + (A.M. Andrew, + "Another Efficient Algorithm for Convex Hulls in Two Dimensions", 1979) + https://web.archive.org/web/20210511015444/http://geomalgorithms.com/a10-_hull-1.html + + """ + from .line import Segment + from .polygon import Polygon + p = OrderedSet() + for e in args: + if not isinstance(e, GeometryEntity): + try: + e = Point(e) + except NotImplementedError: + raise ValueError('%s is not a GeometryEntity and cannot be made into Point' % str(e)) + if isinstance(e, Point): + p.add(e) + elif isinstance(e, Segment): + p.update(e.points) + elif isinstance(e, Polygon): + p.update(e.vertices) + else: + raise NotImplementedError( + 'Convex hull for %s not implemented.' % type(e)) + + # make sure all our points are of the same dimension + if any(len(x) != 2 for x in p): + raise ValueError('Can only compute the convex hull in two dimensions') + + p = list(p) + if len(p) == 1: + return p[0] if polygon else (p[0], None) + elif len(p) == 2: + s = Segment(p[0], p[1]) + return s if polygon else (s, None) + + def _orientation(p, q, r): + '''Return positive if p-q-r are clockwise, neg if ccw, zero if + collinear.''' + return (q.y - p.y)*(r.x - p.x) - (q.x - p.x)*(r.y - p.y) + + # scan to find upper and lower convex hulls of a set of 2d points. + U = [] + L = [] + try: + p.sort(key=lambda x: x.args) + except TypeError: + raise ValueError("The points could not be sorted.") + for p_i in p: + while len(U) > 1 and _orientation(U[-2], U[-1], p_i) <= 0: + U.pop() + while len(L) > 1 and _orientation(L[-2], L[-1], p_i) >= 0: + L.pop() + U.append(p_i) + L.append(p_i) + U.reverse() + convexHull = tuple(L + U[1:-1]) + + if len(convexHull) == 2: + s = Segment(convexHull[0], convexHull[1]) + return s if polygon else (s, None) + if polygon: + return Polygon(*convexHull) + else: + U.reverse() + return (U, L) + +def farthest_points(*args): + """Return the subset of points from a set of points that were + the furthest apart from each other in the 2D plane. + + Parameters + ========== + + args + A collection of Points on 2D plane. + + Notes + ===== + + This can only be performed on a set of points whose coordinates can + be ordered on the number line. If there are no ties then a single + pair of Points will be in the set. + + Examples + ======== + + >>> from sympy.geometry import farthest_points, Triangle + >>> Triangle(sss=(3, 4, 5)).args + (Point2D(0, 0), Point2D(3, 0), Point2D(3, 4)) + >>> farthest_points(*_) + {(Point2D(0, 0), Point2D(3, 4))} + + References + ========== + + .. [1] https://code.activestate.com/recipes/117225-convex-hull-and-diameter-of-2d-point-sets/ + + .. [2] Rotating Callipers Technique + https://en.wikipedia.org/wiki/Rotating_calipers + + """ + + def rotatingCalipers(Points): + U, L = convex_hull(*Points, **{"polygon": False}) + + if L is None: + if isinstance(U, Point): + raise ValueError('At least two distinct points must be given.') + yield U.args + else: + i = 0 + j = len(L) - 1 + while i < len(U) - 1 or j > 0: + yield U[i], L[j] + # if all the way through one side of hull, advance the other side + if i == len(U) - 1: + j -= 1 + elif j == 0: + i += 1 + # still points left on both lists, compare slopes of next hull edges + # being careful to avoid divide-by-zero in slope calculation + elif (U[i+1].y - U[i].y) * (L[j].x - L[j-1].x) > \ + (L[j].y - L[j-1].y) * (U[i+1].x - U[i].x): + i += 1 + else: + j -= 1 + + p = [Point2D(i) for i in set(args)] + + if not all(i.is_Rational for j in p for i in j.args): + def hypot(x, y): + arg = x*x + y*y + if arg.is_Rational: + return _sqrt(arg) + return sqrt(arg) + else: + from math import hypot + + rv = [] + diam = 0 + for pair in rotatingCalipers(args): + h, q = _ordered_points(pair) + d = hypot(h.x - q.x, h.y - q.y) + if d > diam: + rv = [(h, q)] + elif d == diam: + rv.append((h, q)) + else: + continue + diam = d + + return set(rv) + + +def idiff(eq, y, x, n=1): + """Return ``dy/dx`` assuming that ``eq == 0``. + + Parameters + ========== + + y : the dependent variable or a list of dependent variables (with y first) + x : the variable that the derivative is being taken with respect to + n : the order of the derivative (default is 1) + + Examples + ======== + + >>> from sympy.abc import x, y, a + >>> from sympy.geometry.util import idiff + + >>> circ = x**2 + y**2 - 4 + >>> idiff(circ, y, x) + -x/y + >>> idiff(circ, y, x, 2).simplify() + (-x**2 - y**2)/y**3 + + Here, ``a`` is assumed to be independent of ``x``: + + >>> idiff(x + a + y, y, x) + -1 + + Now the x-dependence of ``a`` is made explicit by listing ``a`` after + ``y`` in a list. + + >>> idiff(x + a + y, [y, a], x) + -Derivative(a, x) - 1 + + See Also + ======== + + sympy.core.function.Derivative: represents unevaluated derivatives + sympy.core.function.diff: explicitly differentiates wrt symbols + + """ + if is_sequence(y): + dep = set(y) + y = y[0] + elif isinstance(y, Symbol): + dep = {y} + elif isinstance(y, Function): + pass + else: + raise ValueError("expecting x-dependent symbol(s) or function(s) but got: %s" % y) + + f = {s: Function(s.name)(x) for s in eq.free_symbols + if s != x and s in dep} + + if isinstance(y, Symbol): + dydx = Function(y.name)(x).diff(x) + else: + dydx = y.diff(x) + + eq = eq.subs(f) + derivs = {} + for i in range(n): + # equation will be linear in dydx, a*dydx + b, so dydx = -b/a + deq = eq.diff(x) + b = deq.xreplace({dydx: S.Zero}) + a = (deq - b).xreplace({dydx: S.One}) + yp = factor_terms(expand_mul(cancel((-b/a).subs(derivs)), deep=False)) + if i == n - 1: + return yp.subs([(v, k) for k, v in f.items()]) + derivs[dydx] = yp + eq = dydx - yp + dydx = dydx.diff(x) + + +def intersection(*entities, pairwise=False, **kwargs): + """The intersection of a collection of GeometryEntity instances. + + Parameters + ========== + entities : sequence of GeometryEntity + pairwise (keyword argument) : Can be either True or False + + Returns + ======= + intersection : list of GeometryEntity + + Raises + ====== + NotImplementedError + When unable to calculate intersection. + + Notes + ===== + The intersection of any geometrical entity with itself should return + a list with one item: the entity in question. + An intersection requires two or more entities. If only a single + entity is given then the function will return an empty list. + It is possible for `intersection` to miss intersections that one + knows exists because the required quantities were not fully + simplified internally. + Reals should be converted to Rationals, e.g. Rational(str(real_num)) + or else failures due to floating point issues may result. + + Case 1: When the keyword argument 'pairwise' is False (default value): + In this case, the function returns a list of intersections common to + all entities. + + Case 2: When the keyword argument 'pairwise' is True: + In this case, the functions returns a list intersections that occur + between any pair of entities. + + See Also + ======== + + sympy.geometry.entity.GeometryEntity.intersection + + Examples + ======== + + >>> from sympy import Ray, Circle, intersection + >>> c = Circle((0, 1), 1) + >>> intersection(c, c.center) + [] + >>> right = Ray((0, 0), (1, 0)) + >>> up = Ray((0, 0), (0, 1)) + >>> intersection(c, right, up) + [Point2D(0, 0)] + >>> intersection(c, right, up, pairwise=True) + [Point2D(0, 0), Point2D(0, 2)] + >>> left = Ray((1, 0), (0, 0)) + >>> intersection(right, left) + [Segment2D(Point2D(0, 0), Point2D(1, 0))] + + """ + if len(entities) <= 1: + return [] + + entities = list(entities) + prec = None + for i, e in enumerate(entities): + if not isinstance(e, GeometryEntity): + # entities may be an immutable tuple + e = Point(e) + # convert to exact Rationals + d = {} + for f in e.atoms(Float): + prec = f._prec if prec is None else min(f._prec, prec) + d.setdefault(f, nsimplify(f, rational=True)) + entities[i] = e.xreplace(d) + + if not pairwise: + # find the intersection common to all objects + res = entities[0].intersection(entities[1]) + for entity in entities[2:]: + newres = [] + for x in res: + newres.extend(x.intersection(entity)) + res = newres + else: + # find all pairwise intersections + ans = [] + for j in range(len(entities)): + for k in range(j + 1, len(entities)): + ans.extend(intersection(entities[j], entities[k])) + res = list(ordered(set(ans))) + + # convert back to Floats + if prec is not None: + p = prec_to_dps(prec) + res = [i.n(p) for i in res] + return res diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..45412acad0ab9e5c7424b1888648a638ef208142 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/__init__.py @@ -0,0 +1,18 @@ +r""" +The :py:mod:`~sympy.holonomic` module is intended to deal with holonomic functions along +with various operations on them like addition, multiplication, composition, +integration and differentiation. The module also implements various kinds of +conversions such as converting holonomic functions to a different form and the +other way around. +""" + +from .holonomic import (DifferentialOperator, HolonomicFunction, DifferentialOperators, + from_hyper, from_meijerg, expr_to_holonomic) +from .recurrence import RecurrenceOperators, RecurrenceOperator, HolonomicSequence + +__all__ = [ + 'DifferentialOperator', 'HolonomicFunction', 'DifferentialOperators', + 'from_hyper', 'from_meijerg', 'expr_to_holonomic', + + 'RecurrenceOperators', 'RecurrenceOperator', 'HolonomicSequence', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/holonomic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/holonomic.py new file mode 100644 index 0000000000000000000000000000000000000000..e31c4d4511d4c07aa4049a62253cdb060758cf3d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/holonomic.py @@ -0,0 +1,2765 @@ +""" +This module implements Holonomic Functions and +various operations on them. +""" + +from sympy.core import Add, Mul, Pow +from sympy.core.numbers import (NaN, Infinity, NegativeInfinity, Float, I, pi, + equal_valued, int_valued) +from sympy.core.singleton import S +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy, Symbol +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import binomial, factorial, rf +from sympy.functions.elementary.exponential import exp_polar, exp, log +from sympy.functions.elementary.hyperbolic import (cosh, sinh) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin, sinc) +from sympy.functions.special.error_functions import (Ci, Shi, Si, erf, erfc, erfi) +from sympy.functions.special.gamma_functions import gamma +from sympy.functions.special.hyper import hyper, meijerg +from sympy.integrals import meijerint +from sympy.matrices import Matrix +from sympy.polys.rings import PolyElement +from sympy.polys.fields import FracElement +from sympy.polys.domains import QQ, RR +from sympy.polys.polyclasses import DMF +from sympy.polys.polyroots import roots +from sympy.polys.polytools import Poly +from sympy.polys.matrices import DomainMatrix +from sympy.printing import sstr +from sympy.series.limits import limit +from sympy.series.order import Order +from sympy.simplify.hyperexpand import hyperexpand +from sympy.simplify.simplify import nsimplify +from sympy.solvers.solvers import solve + +from .recurrence import HolonomicSequence, RecurrenceOperator, RecurrenceOperators +from .holonomicerrors import (NotPowerSeriesError, NotHyperSeriesError, + SingularityError, NotHolonomicError) + + +def _find_nonzero_solution(r, homosys): + ones = lambda shape: DomainMatrix.ones(shape, r.domain) + particular, nullspace = r._solve(homosys) + nullity = nullspace.shape[0] + nullpart = ones((1, nullity)) * nullspace + sol = (particular + nullpart).transpose() + return sol + + + +def DifferentialOperators(base, generator): + r""" + This function is used to create annihilators using ``Dx``. + + Explanation + =========== + + Returns an Algebra of Differential Operators also called Weyl Algebra + and the operator for differentiation i.e. the ``Dx`` operator. + + Parameters + ========== + + base: + Base polynomial ring for the algebra. + The base polynomial ring is the ring of polynomials in :math:`x` that + will appear as coefficients in the operators. + generator: + Generator of the algebra which can + be either a noncommutative ``Symbol`` or a string. e.g. "Dx" or "D". + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.abc import x + >>> from sympy.holonomic.holonomic import DifferentialOperators + >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') + >>> R + Univariate Differential Operator Algebra in intermediate Dx over the base ring ZZ[x] + >>> Dx*x + (1) + (x)*Dx + """ + + ring = DifferentialOperatorAlgebra(base, generator) + return (ring, ring.derivative_operator) + + +class DifferentialOperatorAlgebra: + r""" + An Ore Algebra is a set of noncommutative polynomials in the + intermediate ``Dx`` and coefficients in a base polynomial ring :math:`A`. + It follows the commutation rule: + + .. math :: + Dxa = \sigma(a)Dx + \delta(a) + + for :math:`a \subset A`. + + Where :math:`\sigma: A \Rightarrow A` is an endomorphism and :math:`\delta: A \rightarrow A` + is a skew-derivation i.e. :math:`\delta(ab) = \delta(a) b + \sigma(a) \delta(b)`. + + If one takes the sigma as identity map and delta as the standard derivation + then it becomes the algebra of Differential Operators also called + a Weyl Algebra i.e. an algebra whose elements are Differential Operators. + + This class represents a Weyl Algebra and serves as the parent ring for + Differential Operators. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy import symbols + >>> from sympy.holonomic.holonomic import DifferentialOperators + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') + >>> R + Univariate Differential Operator Algebra in intermediate Dx over the base ring + ZZ[x] + + See Also + ======== + + DifferentialOperator + """ + + def __init__(self, base, generator): + # the base polynomial ring for the algebra + self.base = base + # the operator representing differentiation i.e. `Dx` + self.derivative_operator = DifferentialOperator( + [base.zero, base.one], self) + + if generator is None: + self.gen_symbol = Symbol('Dx', commutative=False) + else: + if isinstance(generator, str): + self.gen_symbol = Symbol(generator, commutative=False) + elif isinstance(generator, Symbol): + self.gen_symbol = generator + + def __str__(self): + string = 'Univariate Differential Operator Algebra in intermediate '\ + + sstr(self.gen_symbol) + ' over the base ring ' + \ + (self.base).__str__() + + return string + + __repr__ = __str__ + + def __eq__(self, other): + return self.base == other.base and \ + self.gen_symbol == other.gen_symbol + + +class DifferentialOperator: + """ + Differential Operators are elements of Weyl Algebra. The Operators + are defined by a list of polynomials in the base ring and the + parent ring of the Operator i.e. the algebra it belongs to. + + Explanation + =========== + + Takes a list of polynomials for each power of ``Dx`` and the + parent ring which must be an instance of DifferentialOperatorAlgebra. + + A Differential Operator can be created easily using + the operator ``Dx``. See examples below. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import DifferentialOperator, DifferentialOperators + >>> from sympy import ZZ + >>> from sympy import symbols + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x),'Dx') + + >>> DifferentialOperator([0, 1, x**2], R) + (1)*Dx + (x**2)*Dx**2 + + >>> (x*Dx*x + 1 - Dx**2)**2 + (2*x**2 + 2*x + 1) + (4*x**3 + 2*x**2 - 4)*Dx + (x**4 - 6*x - 2)*Dx**2 + (-2*x**2)*Dx**3 + (1)*Dx**4 + + See Also + ======== + + DifferentialOperatorAlgebra + """ + + _op_priority = 20 + + def __init__(self, list_of_poly, parent): + """ + Parameters + ========== + + list_of_poly: + List of polynomials belonging to the base ring of the algebra. + parent: + Parent algebra of the operator. + """ + + # the parent ring for this operator + # must be an DifferentialOperatorAlgebra object + self.parent = parent + base = self.parent.base + self.x = base.gens[0] if isinstance(base.gens[0], Symbol) else base.gens[0][0] + # sequence of polynomials in x for each power of Dx + # the list should not have trailing zeroes + # represents the operator + # convert the expressions into ring elements using from_sympy + for i, j in enumerate(list_of_poly): + if not isinstance(j, base.dtype): + list_of_poly[i] = base.from_sympy(sympify(j)) + else: + list_of_poly[i] = base.from_sympy(base.to_sympy(j)) + + self.listofpoly = list_of_poly + # highest power of `Dx` + self.order = len(self.listofpoly) - 1 + + def __mul__(self, other): + """ + Multiplies two DifferentialOperator and returns another + DifferentialOperator instance using the commutation rule + Dx*a = a*Dx + a' + """ + + listofself = self.listofpoly + if isinstance(other, DifferentialOperator): + listofother = other.listofpoly + elif isinstance(other, self.parent.base.dtype): + listofother = [other] + else: + listofother = [self.parent.base.from_sympy(sympify(other))] + + # multiplies a polynomial `b` with a list of polynomials + def _mul_dmp_diffop(b, listofother): + if isinstance(listofother, list): + return [i * b for i in listofother] + return [b * listofother] + + sol = _mul_dmp_diffop(listofself[0], listofother) + + # compute Dx^i * b + def _mul_Dxi_b(b): + sol1 = [self.parent.base.zero] + sol2 = [] + + if isinstance(b, list): + for i in b: + sol1.append(i) + sol2.append(i.diff()) + else: + sol1.append(self.parent.base.from_sympy(b)) + sol2.append(self.parent.base.from_sympy(b).diff()) + + return _add_lists(sol1, sol2) + + for i in range(1, len(listofself)): + # find Dx^i * b in ith iteration + listofother = _mul_Dxi_b(listofother) + # solution = solution + listofself[i] * (Dx^i * b) + sol = _add_lists(sol, _mul_dmp_diffop(listofself[i], listofother)) + + return DifferentialOperator(sol, self.parent) + + def __rmul__(self, other): + if not isinstance(other, DifferentialOperator): + + if not isinstance(other, self.parent.base.dtype): + other = (self.parent.base).from_sympy(sympify(other)) + + sol = [other * j for j in self.listofpoly] + return DifferentialOperator(sol, self.parent) + + def __add__(self, other): + if isinstance(other, DifferentialOperator): + + sol = _add_lists(self.listofpoly, other.listofpoly) + return DifferentialOperator(sol, self.parent) + + list_self = self.listofpoly + if not isinstance(other, self.parent.base.dtype): + list_other = [((self.parent).base).from_sympy(sympify(other))] + else: + list_other = [other] + sol = [list_self[0] + list_other[0]] + list_self[1:] + return DifferentialOperator(sol, self.parent) + + __radd__ = __add__ + + def __sub__(self, other): + return self + (-1) * other + + def __rsub__(self, other): + return (-1) * self + other + + def __neg__(self): + return -1 * self + + def __truediv__(self, other): + return self * (S.One / other) + + def __pow__(self, n): + if n == 1: + return self + result = DifferentialOperator([self.parent.base.one], self.parent) + if n == 0: + return result + # if self is `Dx` + if self.listofpoly == self.parent.derivative_operator.listofpoly: + sol = [self.parent.base.zero]*n + [self.parent.base.one] + return DifferentialOperator(sol, self.parent) + x = self + while True: + if n % 2: + result *= x + n >>= 1 + if not n: + break + x *= x + return result + + def __str__(self): + listofpoly = self.listofpoly + print_str = '' + + for i, j in enumerate(listofpoly): + if j == self.parent.base.zero: + continue + + j = self.parent.base.to_sympy(j) + + if i == 0: + print_str += '(' + sstr(j) + ')' + continue + + if print_str: + print_str += ' + ' + + if i == 1: + print_str += '(' + sstr(j) + ')*%s' %(self.parent.gen_symbol) + continue + + print_str += '(' + sstr(j) + ')' + '*%s**' %(self.parent.gen_symbol) + sstr(i) + + return print_str + + __repr__ = __str__ + + def __eq__(self, other): + if isinstance(other, DifferentialOperator): + return self.listofpoly == other.listofpoly and \ + self.parent == other.parent + return self.listofpoly[0] == other and \ + all(i is self.parent.base.zero for i in self.listofpoly[1:]) + + def is_singular(self, x0): + """ + Checks if the differential equation is singular at x0. + """ + + base = self.parent.base + return x0 in roots(base.to_sympy(self.listofpoly[-1]), self.x) + + +class HolonomicFunction: + r""" + A Holonomic Function is a solution to a linear homogeneous ordinary + differential equation with polynomial coefficients. This differential + equation can also be represented by an annihilator i.e. a Differential + Operator ``L`` such that :math:`L.f = 0`. For uniqueness of these functions, + initial conditions can also be provided along with the annihilator. + + Explanation + =========== + + Holonomic functions have closure properties and thus forms a ring. + Given two Holonomic Functions f and g, their sum, product, + integral and derivative is also a Holonomic Function. + + For ordinary points initial condition should be a vector of values of + the derivatives i.e. :math:`[y(x_0), y'(x_0), y''(x_0) ... ]`. + + For regular singular points initial conditions can also be provided in this + format: + :math:`{s0: [C_0, C_1, ...], s1: [C^1_0, C^1_1, ...], ...}` + where s0, s1, ... are the roots of indicial equation and vectors + :math:`[C_0, C_1, ...], [C^0_0, C^0_1, ...], ...` are the corresponding initial + terms of the associated power series. See Examples below. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import QQ + >>> from sympy import symbols, S + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') + + >>> p = HolonomicFunction(Dx - 1, x, 0, [1]) # e^x + >>> q = HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]) # sin(x) + + >>> p + q # annihilator of e^x + sin(x) + HolonomicFunction((-1) + (1)*Dx + (-1)*Dx**2 + (1)*Dx**3, x, 0, [1, 2, 1]) + + >>> p * q # annihilator of e^x * sin(x) + HolonomicFunction((2) + (-2)*Dx + (1)*Dx**2, x, 0, [0, 1]) + + An example of initial conditions for regular singular points, + the indicial equation has only one root `1/2`. + + >>> HolonomicFunction(-S(1)/2 + x*Dx, x, 0, {S(1)/2: [1]}) + HolonomicFunction((-1/2) + (x)*Dx, x, 0, {1/2: [1]}) + + >>> HolonomicFunction(-S(1)/2 + x*Dx, x, 0, {S(1)/2: [1]}).to_expr() + sqrt(x) + + To plot a Holonomic Function, one can use `.evalf()` for numerical + computation. Here's an example on `sin(x)**2/x` using numpy and matplotlib. + + >>> import sympy.holonomic # doctest: +SKIP + >>> from sympy import var, sin # doctest: +SKIP + >>> import matplotlib.pyplot as plt # doctest: +SKIP + >>> import numpy as np # doctest: +SKIP + >>> var("x") # doctest: +SKIP + >>> r = np.linspace(1, 5, 100) # doctest: +SKIP + >>> y = sympy.holonomic.expr_to_holonomic(sin(x)**2/x, x0=1).evalf(r) # doctest: +SKIP + >>> plt.plot(r, y, label="holonomic function") # doctest: +SKIP + >>> plt.show() # doctest: +SKIP + + """ + + _op_priority = 20 + + def __init__(self, annihilator, x, x0=0, y0=None): + """ + + Parameters + ========== + + annihilator: + Annihilator of the Holonomic Function, represented by a + `DifferentialOperator` object. + x: + Variable of the function. + x0: + The point at which initial conditions are stored. + Generally an integer. + y0: + The initial condition. The proper format for the initial condition + is described in class docstring. To make the function unique, + length of the vector `y0` should be equal to or greater than the + order of differential equation. + """ + + # initial condition + self.y0 = y0 + # the point for initial conditions, default is zero. + self.x0 = x0 + # differential operator L such that L.f = 0 + self.annihilator = annihilator + self.x = x + + def __str__(self): + if self._have_init_cond(): + str_sol = 'HolonomicFunction(%s, %s, %s, %s)' % (str(self.annihilator),\ + sstr(self.x), sstr(self.x0), sstr(self.y0)) + else: + str_sol = 'HolonomicFunction(%s, %s)' % (str(self.annihilator),\ + sstr(self.x)) + + return str_sol + + __repr__ = __str__ + + def unify(self, other): + """ + Unifies the base polynomial ring of a given two Holonomic + Functions. + """ + + R1 = self.annihilator.parent.base + R2 = other.annihilator.parent.base + + dom1 = R1.dom + dom2 = R2.dom + + if R1 == R2: + return (self, other) + + R = (dom1.unify(dom2)).old_poly_ring(self.x) + + newparent, _ = DifferentialOperators(R, str(self.annihilator.parent.gen_symbol)) + + sol1 = [R1.to_sympy(i) for i in self.annihilator.listofpoly] + sol2 = [R2.to_sympy(i) for i in other.annihilator.listofpoly] + + sol1 = DifferentialOperator(sol1, newparent) + sol2 = DifferentialOperator(sol2, newparent) + + sol1 = HolonomicFunction(sol1, self.x, self.x0, self.y0) + sol2 = HolonomicFunction(sol2, other.x, other.x0, other.y0) + + return (sol1, sol2) + + def is_singularics(self): + """ + Returns True if the function have singular initial condition + in the dictionary format. + + Returns False if the function have ordinary initial condition + in the list format. + + Returns None for all other cases. + """ + + if isinstance(self.y0, dict): + return True + elif isinstance(self.y0, list): + return False + + def _have_init_cond(self): + """ + Checks if the function have initial condition. + """ + return bool(self.y0) + + def _singularics_to_ord(self): + """ + Converts a singular initial condition to ordinary if possible. + """ + a = list(self.y0)[0] + b = self.y0[a] + + if len(self.y0) == 1 and a == int(a) and a > 0: + a = int(a) + y0 = [S.Zero] * a + y0 += [j * factorial(a + i) for i, j in enumerate(b)] + + return HolonomicFunction(self.annihilator, self.x, self.x0, y0) + + def __add__(self, other): + # if the ground domains are different + if self.annihilator.parent.base != other.annihilator.parent.base: + a, b = self.unify(other) + return a + b + + deg1 = self.annihilator.order + deg2 = other.annihilator.order + dim = max(deg1, deg2) + R = self.annihilator.parent.base + K = R.get_field() + + rowsself = [self.annihilator] + rowsother = [other.annihilator] + gen = self.annihilator.parent.derivative_operator + + # constructing annihilators up to order dim + for i in range(dim - deg1): + diff1 = (gen * rowsself[-1]) + rowsself.append(diff1) + + for i in range(dim - deg2): + diff2 = (gen * rowsother[-1]) + rowsother.append(diff2) + + row = rowsself + rowsother + + # constructing the matrix of the ansatz + r = [] + + for expr in row: + p = [] + for i in range(dim + 1): + if i >= len(expr.listofpoly): + p.append(K.zero) + else: + p.append(K.new(expr.listofpoly[i].to_list())) + r.append(p) + + # solving the linear system using gauss jordan solver + r = DomainMatrix(r, (len(row), dim+1), K).transpose() + homosys = DomainMatrix.zeros((dim+1, 1), K) + sol = _find_nonzero_solution(r, homosys) + + # if a solution is not obtained then increasing the order by 1 in each + # iteration + while sol.is_zero_matrix: + dim += 1 + + diff1 = (gen * rowsself[-1]) + rowsself.append(diff1) + + diff2 = (gen * rowsother[-1]) + rowsother.append(diff2) + + row = rowsself + rowsother + r = [] + + for expr in row: + p = [] + for i in range(dim + 1): + if i >= len(expr.listofpoly): + p.append(K.zero) + else: + p.append(K.new(expr.listofpoly[i].to_list())) + r.append(p) + + # solving the linear system using gauss jordan solver + r = DomainMatrix(r, (len(row), dim+1), K).transpose() + homosys = DomainMatrix.zeros((dim+1, 1), K) + sol = _find_nonzero_solution(r, homosys) + + # taking only the coefficients needed to multiply with `self` + # can be also be done the other way by taking R.H.S and multiplying with + # `other` + sol = sol.flat()[:dim + 1 - deg1] + sol1 = _normalize(sol, self.annihilator.parent) + # annihilator of the solution + sol = sol1 * (self.annihilator) + sol = _normalize(sol.listofpoly, self.annihilator.parent, negative=False) + + if not (self._have_init_cond() and other._have_init_cond()): + return HolonomicFunction(sol, self.x) + + # both the functions have ordinary initial conditions + if self.is_singularics() == False and other.is_singularics() == False: + + # directly add the corresponding value + if self.x0 == other.x0: + # try to extended the initial conditions + # using the annihilator + y1 = _extend_y0(self, sol.order) + y2 = _extend_y0(other, sol.order) + y0 = [a + b for a, b in zip(y1, y2)] + return HolonomicFunction(sol, self.x, self.x0, y0) + + # change the initial conditions to a same point + selfat0 = self.annihilator.is_singular(0) + otherat0 = other.annihilator.is_singular(0) + if self.x0 == 0 and not selfat0 and not otherat0: + return self + other.change_ics(0) + if other.x0 == 0 and not selfat0 and not otherat0: + return self.change_ics(0) + other + + selfatx0 = self.annihilator.is_singular(self.x0) + otheratx0 = other.annihilator.is_singular(self.x0) + if not selfatx0 and not otheratx0: + return self + other.change_ics(self.x0) + return self.change_ics(other.x0) + other + + if self.x0 != other.x0: + return HolonomicFunction(sol, self.x) + + # if the functions have singular_ics + y1 = None + y2 = None + + if self.is_singularics() == False and other.is_singularics() == True: + # convert the ordinary initial condition to singular. + _y0 = [j / factorial(i) for i, j in enumerate(self.y0)] + y1 = {S.Zero: _y0} + y2 = other.y0 + elif self.is_singularics() == True and other.is_singularics() == False: + _y0 = [j / factorial(i) for i, j in enumerate(other.y0)] + y1 = self.y0 + y2 = {S.Zero: _y0} + elif self.is_singularics() == True and other.is_singularics() == True: + y1 = self.y0 + y2 = other.y0 + + # computing singular initial condition for the result + # taking union of the series terms of both functions + y0 = {} + for i in y1: + # add corresponding initial terms if the power + # on `x` is same + if i in y2: + y0[i] = [a + b for a, b in zip(y1[i], y2[i])] + else: + y0[i] = y1[i] + for i in y2: + if i not in y1: + y0[i] = y2[i] + return HolonomicFunction(sol, self.x, self.x0, y0) + + def integrate(self, limits, initcond=False): + """ + Integrates the given holonomic function. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import QQ + >>> from sympy import symbols + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') + >>> HolonomicFunction(Dx - 1, x, 0, [1]).integrate((x, 0, x)) # e^x - 1 + HolonomicFunction((-1)*Dx + (1)*Dx**2, x, 0, [0, 1]) + >>> HolonomicFunction(Dx**2 + 1, x, 0, [1, 0]).integrate((x, 0, x)) + HolonomicFunction((1)*Dx + (1)*Dx**3, x, 0, [0, 1, 0]) + """ + + # to get the annihilator, just multiply by Dx from right + D = self.annihilator.parent.derivative_operator + + # if the function have initial conditions of the series format + if self.is_singularics() == True: + + r = self._singularics_to_ord() + if r: + return r.integrate(limits, initcond=initcond) + + # computing singular initial condition for the function + # produced after integration. + y0 = {} + for i in self.y0: + c = self.y0[i] + c2 = [] + for j, cj in enumerate(c): + if cj == 0: + c2.append(S.Zero) + + # if power on `x` is -1, the integration becomes log(x) + # TODO: Implement this case + elif i + j + 1 == 0: + raise NotImplementedError("logarithmic terms in the series are not supported") + else: + c2.append(cj / S(i + j + 1)) + y0[i + 1] = c2 + + if hasattr(limits, "__iter__"): + raise NotImplementedError("Definite integration for singular initial conditions") + + return HolonomicFunction(self.annihilator * D, self.x, self.x0, y0) + + # if no initial conditions are available for the function + if not self._have_init_cond(): + if initcond: + return HolonomicFunction(self.annihilator * D, self.x, self.x0, [S.Zero]) + return HolonomicFunction(self.annihilator * D, self.x) + + # definite integral + # initial conditions for the answer will be stored at point `a`, + # where `a` is the lower limit of the integrand + if hasattr(limits, "__iter__"): + + if len(limits) == 3 and limits[0] == self.x: + x0 = self.x0 + a = limits[1] + b = limits[2] + definite = True + + else: + definite = False + + y0 = [S.Zero] + y0 += self.y0 + + indefinite_integral = HolonomicFunction(self.annihilator * D, self.x, self.x0, y0) + + if not definite: + return indefinite_integral + + # use evalf to get the values at `a` + if x0 != a: + try: + indefinite_expr = indefinite_integral.to_expr() + except (NotHyperSeriesError, NotPowerSeriesError): + indefinite_expr = None + + if indefinite_expr: + lower = indefinite_expr.subs(self.x, a) + if isinstance(lower, NaN): + lower = indefinite_expr.limit(self.x, a) + else: + lower = indefinite_integral.evalf(a) + + if b == self.x: + y0[0] = y0[0] - lower + return HolonomicFunction(self.annihilator * D, self.x, x0, y0) + + elif S(b).is_Number: + if indefinite_expr: + upper = indefinite_expr.subs(self.x, b) + if isinstance(upper, NaN): + upper = indefinite_expr.limit(self.x, b) + else: + upper = indefinite_integral.evalf(b) + + return upper - lower + + + # if the upper limit is `x`, the answer will be a function + if b == self.x: + return HolonomicFunction(self.annihilator * D, self.x, a, y0) + + # if the upper limits is a Number, a numerical value will be returned + elif S(b).is_Number: + try: + s = HolonomicFunction(self.annihilator * D, self.x, a,\ + y0).to_expr() + indefinite = s.subs(self.x, b) + if not isinstance(indefinite, NaN): + return indefinite + else: + return s.limit(self.x, b) + except (NotHyperSeriesError, NotPowerSeriesError): + return HolonomicFunction(self.annihilator * D, self.x, a, y0).evalf(b) + + return HolonomicFunction(self.annihilator * D, self.x) + + def diff(self, *args, **kwargs): + r""" + Differentiation of the given Holonomic function. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import ZZ + >>> from sympy import symbols + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x),'Dx') + >>> HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]).diff().to_expr() + cos(x) + >>> HolonomicFunction(Dx - 2, x, 0, [1]).diff().to_expr() + 2*exp(2*x) + + See Also + ======== + + integrate + """ + kwargs.setdefault('evaluate', True) + if args: + if args[0] != self.x: + return S.Zero + elif len(args) == 2: + sol = self + for i in range(args[1]): + sol = sol.diff(args[0]) + return sol + + ann = self.annihilator + + # if the function is constant. + if ann.listofpoly[0] == ann.parent.base.zero and ann.order == 1: + return S.Zero + + # if the coefficient of y in the differential equation is zero. + # a shifting is done to compute the answer in this case. + elif ann.listofpoly[0] == ann.parent.base.zero: + + sol = DifferentialOperator(ann.listofpoly[1:], ann.parent) + + if self._have_init_cond(): + # if ordinary initial condition + if self.is_singularics() == False: + return HolonomicFunction(sol, self.x, self.x0, self.y0[1:]) + # TODO: support for singular initial condition + return HolonomicFunction(sol, self.x) + else: + return HolonomicFunction(sol, self.x) + + # the general algorithm + R = ann.parent.base + K = R.get_field() + + seq_dmf = [K.new(i.to_list()) for i in ann.listofpoly] + + # -y = a1*y'/a0 + a2*y''/a0 ... + an*y^n/a0 + rhs = [i / seq_dmf[0] for i in seq_dmf[1:]] + rhs.insert(0, K.zero) + + # differentiate both lhs and rhs + sol = _derivate_diff_eq(rhs, K) + + # add the term y' in lhs to rhs + sol = _add_lists(sol, [K.zero, K.one]) + + sol = _normalize(sol[1:], self.annihilator.parent, negative=False) + + if not self._have_init_cond() or self.is_singularics() == True: + return HolonomicFunction(sol, self.x) + + y0 = _extend_y0(self, sol.order + 1)[1:] + return HolonomicFunction(sol, self.x, self.x0, y0) + + def __eq__(self, other): + if self.annihilator != other.annihilator or self.x != other.x: + return False + if self._have_init_cond() and other._have_init_cond(): + return self.x0 == other.x0 and self.y0 == other.y0 + return True + + def __mul__(self, other): + ann_self = self.annihilator + + if not isinstance(other, HolonomicFunction): + other = sympify(other) + + if other.has(self.x): + raise NotImplementedError(" Can't multiply a HolonomicFunction and expressions/functions.") + + if not self._have_init_cond(): + return self + y0 = _extend_y0(self, ann_self.order) + y1 = [(Poly.new(j, self.x) * other).rep for j in y0] + return HolonomicFunction(ann_self, self.x, self.x0, y1) + + if self.annihilator.parent.base != other.annihilator.parent.base: + a, b = self.unify(other) + return a * b + + ann_other = other.annihilator + + a = ann_self.order + b = ann_other.order + + R = ann_self.parent.base + K = R.get_field() + + list_self = [K.new(j.to_list()) for j in ann_self.listofpoly] + list_other = [K.new(j.to_list()) for j in ann_other.listofpoly] + + # will be used to reduce the degree + self_red = [-list_self[i] / list_self[a] for i in range(a)] + + other_red = [-list_other[i] / list_other[b] for i in range(b)] + + # coeff_mull[i][j] is the coefficient of Dx^i(f).Dx^j(g) + coeff_mul = [[K.zero for i in range(b + 1)] for j in range(a + 1)] + coeff_mul[0][0] = K.one + + # making the ansatz + lin_sys_elements = [[coeff_mul[i][j] for i in range(a) for j in range(b)]] + lin_sys = DomainMatrix(lin_sys_elements, (1, a*b), K).transpose() + + homo_sys = DomainMatrix.zeros((a*b, 1), K) + + sol = _find_nonzero_solution(lin_sys, homo_sys) + + # until a non trivial solution is found + while sol.is_zero_matrix: + + # updating the coefficients Dx^i(f).Dx^j(g) for next degree + for i in range(a - 1, -1, -1): + for j in range(b - 1, -1, -1): + coeff_mul[i][j + 1] += coeff_mul[i][j] + coeff_mul[i + 1][j] += coeff_mul[i][j] + if isinstance(coeff_mul[i][j], K.dtype): + coeff_mul[i][j] = DMFdiff(coeff_mul[i][j], K) + else: + coeff_mul[i][j] = coeff_mul[i][j].diff(self.x) + + # reduce the terms to lower power using annihilators of f, g + for i in range(a + 1): + if coeff_mul[i][b].is_zero: + continue + for j in range(b): + coeff_mul[i][j] += other_red[j] * coeff_mul[i][b] + coeff_mul[i][b] = K.zero + + # not d2 + 1, as that is already covered in previous loop + for j in range(b): + if coeff_mul[a][j] == 0: + continue + for i in range(a): + coeff_mul[i][j] += self_red[i] * coeff_mul[a][j] + coeff_mul[a][j] = K.zero + + lin_sys_elements.append([coeff_mul[i][j] for i in range(a) for j in range(b)]) + lin_sys = DomainMatrix(lin_sys_elements, (len(lin_sys_elements), a*b), K).transpose() + + sol = _find_nonzero_solution(lin_sys, homo_sys) + + sol_ann = _normalize(sol.flat(), self.annihilator.parent, negative=False) + + if not (self._have_init_cond() and other._have_init_cond()): + return HolonomicFunction(sol_ann, self.x) + + if self.is_singularics() == False and other.is_singularics() == False: + + # if both the conditions are at same point + if self.x0 == other.x0: + + # try to find more initial conditions + y0_self = _extend_y0(self, sol_ann.order) + y0_other = _extend_y0(other, sol_ann.order) + # h(x0) = f(x0) * g(x0) + y0 = [y0_self[0] * y0_other[0]] + + # coefficient of Dx^j(f)*Dx^i(g) in Dx^i(fg) + for i in range(1, min(len(y0_self), len(y0_other))): + coeff = [[0 for i in range(i + 1)] for j in range(i + 1)] + for j in range(i + 1): + for k in range(i + 1): + if j + k == i: + coeff[j][k] = binomial(i, j) + + sol = 0 + for j in range(i + 1): + for k in range(i + 1): + sol += coeff[j][k]* y0_self[j] * y0_other[k] + + y0.append(sol) + + return HolonomicFunction(sol_ann, self.x, self.x0, y0) + + # if the points are different, consider one + selfat0 = self.annihilator.is_singular(0) + otherat0 = other.annihilator.is_singular(0) + + if self.x0 == 0 and not selfat0 and not otherat0: + return self * other.change_ics(0) + if other.x0 == 0 and not selfat0 and not otherat0: + return self.change_ics(0) * other + + selfatx0 = self.annihilator.is_singular(self.x0) + otheratx0 = other.annihilator.is_singular(self.x0) + if not selfatx0 and not otheratx0: + return self * other.change_ics(self.x0) + return self.change_ics(other.x0) * other + + if self.x0 != other.x0: + return HolonomicFunction(sol_ann, self.x) + + # if the functions have singular_ics + y1 = None + y2 = None + + if self.is_singularics() == False and other.is_singularics() == True: + _y0 = [j / factorial(i) for i, j in enumerate(self.y0)] + y1 = {S.Zero: _y0} + y2 = other.y0 + elif self.is_singularics() == True and other.is_singularics() == False: + _y0 = [j / factorial(i) for i, j in enumerate(other.y0)] + y1 = self.y0 + y2 = {S.Zero: _y0} + elif self.is_singularics() == True and other.is_singularics() == True: + y1 = self.y0 + y2 = other.y0 + + y0 = {} + # multiply every possible pair of the series terms + for i in y1: + for j in y2: + k = min(len(y1[i]), len(y2[j])) + c = [sum((y1[i][b] * y2[j][a - b] for b in range(a + 1)), + start=S.Zero) for a in range(k)] + if not i + j in y0: + y0[i + j] = c + else: + y0[i + j] = [a + b for a, b in zip(c, y0[i + j])] + return HolonomicFunction(sol_ann, self.x, self.x0, y0) + + __rmul__ = __mul__ + + def __sub__(self, other): + return self + other * -1 + + def __rsub__(self, other): + return self * -1 + other + + def __neg__(self): + return -1 * self + + def __truediv__(self, other): + return self * (S.One / other) + + def __pow__(self, n): + if self.annihilator.order <= 1: + ann = self.annihilator + parent = ann.parent + + if self.y0 is None: + y0 = None + else: + y0 = [list(self.y0)[0] ** n] + + p0 = ann.listofpoly[0] + p1 = ann.listofpoly[1] + + p0 = (Poly.new(p0, self.x) * n).rep + + sol = [parent.base.to_sympy(i) for i in [p0, p1]] + dd = DifferentialOperator(sol, parent) + return HolonomicFunction(dd, self.x, self.x0, y0) + if n < 0: + raise NotHolonomicError("Negative Power on a Holonomic Function") + Dx = self.annihilator.parent.derivative_operator + result = HolonomicFunction(Dx, self.x, S.Zero, [S.One]) + if n == 0: + return result + x = self + while True: + if n % 2: + result *= x + n >>= 1 + if not n: + break + x *= x + return result + + def degree(self): + """ + Returns the highest power of `x` in the annihilator. + """ + return max(i.degree() for i in self.annihilator.listofpoly) + + def composition(self, expr, *args, **kwargs): + """ + Returns function after composition of a holonomic + function with an algebraic function. The method cannot compute + initial conditions for the result by itself, so they can be also be + provided. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import QQ + >>> from sympy import symbols + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') + >>> HolonomicFunction(Dx - 1, x).composition(x**2, 0, [1]) # e^(x**2) + HolonomicFunction((-2*x) + (1)*Dx, x, 0, [1]) + >>> HolonomicFunction(Dx**2 + 1, x).composition(x**2 - 1, 1, [1, 0]) + HolonomicFunction((4*x**3) + (-1)*Dx + (x)*Dx**2, x, 1, [1, 0]) + + See Also + ======== + + from_hyper + """ + + R = self.annihilator.parent + a = self.annihilator.order + diff = expr.diff(self.x) + listofpoly = self.annihilator.listofpoly + + for i, j in enumerate(listofpoly): + if isinstance(j, self.annihilator.parent.base.dtype): + listofpoly[i] = self.annihilator.parent.base.to_sympy(j) + + r = listofpoly[a].subs({self.x:expr}) + subs = [-listofpoly[i].subs({self.x:expr}) / r for i in range (a)] + coeffs = [S.Zero for i in range(a)] # coeffs[i] == coeff of (D^i f)(a) in D^k (f(a)) + coeffs[0] = S.One + system = [coeffs] + homogeneous = Matrix([[S.Zero for i in range(a)]]).transpose() + while True: + coeffs_next = [p.diff(self.x) for p in coeffs] + for i in range(a - 1): + coeffs_next[i + 1] += (coeffs[i] * diff) + for i in range(a): + coeffs_next[i] += (coeffs[-1] * subs[i] * diff) + coeffs = coeffs_next + # check for linear relations + system.append(coeffs) + sol, taus = (Matrix(system).transpose() + ).gauss_jordan_solve(homogeneous) + if sol.is_zero_matrix is not True: + break + + tau = list(taus)[0] + sol = sol.subs(tau, 1) + sol = _normalize(sol[0:], R, negative=False) + + # if initial conditions are given for the resulting function + if args: + return HolonomicFunction(sol, self.x, args[0], args[1]) + return HolonomicFunction(sol, self.x) + + def to_sequence(self, lb=True): + r""" + Finds recurrence relation for the coefficients in the series expansion + of the function about :math:`x_0`, where :math:`x_0` is the point at + which the initial condition is stored. + + Explanation + =========== + + If the point :math:`x_0` is ordinary, solution of the form :math:`[(R, n_0)]` + is returned. Where :math:`R` is the recurrence relation and :math:`n_0` is the + smallest ``n`` for which the recurrence holds true. + + If the point :math:`x_0` is regular singular, a list of solutions in + the format :math:`(R, p, n_0)` is returned, i.e. `[(R, p, n_0), ... ]`. + Each tuple in this vector represents a recurrence relation :math:`R` + associated with a root of the indicial equation ``p``. Conditions of + a different format can also be provided in this case, see the + docstring of HolonomicFunction class. + + If it's not possible to numerically compute a initial condition, + it is returned as a symbol :math:`C_j`, denoting the coefficient of + :math:`(x - x_0)^j` in the power series about :math:`x_0`. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import QQ + >>> from sympy import symbols, S + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') + >>> HolonomicFunction(Dx - 1, x, 0, [1]).to_sequence() + [(HolonomicSequence((-1) + (n + 1)Sn, n), u(0) = 1, 0)] + >>> HolonomicFunction((1 + x)*Dx**2 + Dx, x, 0, [0, 1]).to_sequence() + [(HolonomicSequence((n**2) + (n**2 + n)Sn, n), u(0) = 0, u(1) = 1, u(2) = -1/2, 2)] + >>> HolonomicFunction(-S(1)/2 + x*Dx, x, 0, {S(1)/2: [1]}).to_sequence() + [(HolonomicSequence((n), n), u(0) = 1, 1/2, 1)] + + See Also + ======== + + HolonomicFunction.series + + References + ========== + + .. [1] https://hal.inria.fr/inria-00070025/document + .. [2] https://www3.risc.jku.at/publications/download/risc_2244/DIPLFORM.pdf + + """ + + if self.x0 != 0: + return self.shift_x(self.x0).to_sequence() + + # check whether a power series exists if the point is singular + if self.annihilator.is_singular(self.x0): + return self._frobenius(lb=lb) + + dict1 = {} + n = Symbol('n', integer=True) + dom = self.annihilator.parent.base.dom + R, _ = RecurrenceOperators(dom.old_poly_ring(n), 'Sn') + + # substituting each term of the form `x^k Dx^j` in the + # annihilator, according to the formula below: + # x^k Dx^j = Sum(rf(n + 1 - k, j) * a(n + j - k) * x^n, (n, k, oo)) + # for explanation see [2]. + for i, j in enumerate(self.annihilator.listofpoly): + + listofdmp = j.all_coeffs() + degree = len(listofdmp) - 1 + + for k in range(degree + 1): + coeff = listofdmp[degree - k] + + if coeff == 0: + continue + + if (i - k, k) in dict1: + dict1[(i - k, k)] += (dom.to_sympy(coeff) * rf(n - k + 1, i)) + else: + dict1[(i - k, k)] = (dom.to_sympy(coeff) * rf(n - k + 1, i)) + + + sol = [] + keylist = [i[0] for i in dict1] + lower = min(keylist) + upper = max(keylist) + degree = self.degree() + + # the recurrence relation holds for all values of + # n greater than smallest_n, i.e. n >= smallest_n + smallest_n = lower + degree + dummys = {} + eqs = [] + unknowns = [] + + # an appropriate shift of the recurrence + for j in range(lower, upper + 1): + if j in keylist: + temp = sum((v.subs(n, n - lower) + for k, v in dict1.items() if k[0] == j), + start=S.Zero) + sol.append(temp) + else: + sol.append(S.Zero) + + # the recurrence relation + sol = RecurrenceOperator(sol, R) + + # computing the initial conditions for recurrence + order = sol.order + all_roots = roots(R.base.to_sympy(sol.listofpoly[-1]), n, filter='Z') + all_roots = all_roots.keys() + + if all_roots: + max_root = max(all_roots) + 1 + smallest_n = max(max_root, smallest_n) + order += smallest_n + + y0 = _extend_y0(self, order) + # u(n) = y^n(0)/factorial(n) + u0 = [j / factorial(i) for i, j in enumerate(y0)] + + # if sufficient conditions can't be computed then + # try to use the series method i.e. + # equate the coefficients of x^k in the equation formed by + # substituting the series in differential equation, to zero. + if len(u0) < order: + + for i in range(degree): + eq = S.Zero + + for j in dict1: + + if i + j[0] < 0: + dummys[i + j[0]] = S.Zero + + elif i + j[0] < len(u0): + dummys[i + j[0]] = u0[i + j[0]] + + elif not i + j[0] in dummys: + dummys[i + j[0]] = Symbol('C_%s' %(i + j[0])) + unknowns.append(dummys[i + j[0]]) + + if j[1] <= i: + eq += dict1[j].subs(n, i) * dummys[i + j[0]] + + eqs.append(eq) + + # solve the system of equations formed + soleqs = solve(eqs, *unknowns) + + if isinstance(soleqs, dict): + + for i in range(len(u0), order): + + if i not in dummys: + dummys[i] = Symbol('C_%s' %i) + + if dummys[i] in soleqs: + u0.append(soleqs[dummys[i]]) + + else: + u0.append(dummys[i]) + + if lb: + return [(HolonomicSequence(sol, u0), smallest_n)] + return [HolonomicSequence(sol, u0)] + + for i in range(len(u0), order): + + if i not in dummys: + dummys[i] = Symbol('C_%s' %i) + + s = False + for j in soleqs: + if dummys[i] in j: + u0.append(j[dummys[i]]) + s = True + if not s: + u0.append(dummys[i]) + + if lb: + return [(HolonomicSequence(sol, u0), smallest_n)] + + return [HolonomicSequence(sol, u0)] + + def _frobenius(self, lb=True): + # compute the roots of indicial equation + indicialroots = self._indicial() + + reals = [] + compl = [] + for i in ordered(indicialroots.keys()): + if i.is_real: + reals.extend([i] * indicialroots[i]) + else: + a, b = i.as_real_imag() + compl.extend([(i, a, b)] * indicialroots[i]) + + # sort the roots for a fixed ordering of solution + compl.sort(key=lambda x : x[1]) + compl.sort(key=lambda x : x[2]) + reals.sort() + + # grouping the roots, roots differ by an integer are put in the same group. + grp = [] + + for i in reals: + if len(grp) == 0: + grp.append([i]) + continue + for j in grp: + if int_valued(j[0] - i): + j.append(i) + break + else: + grp.append([i]) + + # True if none of the roots differ by an integer i.e. + # each element in group have only one member + independent = all(len(i) == 1 for i in grp) + + allpos = all(i >= 0 for i in reals) + allint = all(int_valued(i) for i in reals) + + # if initial conditions are provided + # then use them. + if self.is_singularics() == True: + rootstoconsider = [] + for i in ordered(self.y0.keys()): + for j in ordered(indicialroots.keys()): + if equal_valued(j, i): + rootstoconsider.append(i) + + elif allpos and allint: + rootstoconsider = [min(reals)] + + elif independent: + rootstoconsider = [i[0] for i in grp] + [j[0] for j in compl] + + elif not allint: + rootstoconsider = [i for i in reals if not int(i) == i] + + elif not allpos: + + if not self._have_init_cond() or S(self.y0[0]).is_finite == False: + rootstoconsider = [min(reals)] + + else: + posroots = [i for i in reals if i >= 0] + rootstoconsider = [min(posroots)] + + n = Symbol('n', integer=True) + dom = self.annihilator.parent.base.dom + R, _ = RecurrenceOperators(dom.old_poly_ring(n), 'Sn') + + finalsol = [] + char = ord('C') + + for p in rootstoconsider: + dict1 = {} + + for i, j in enumerate(self.annihilator.listofpoly): + + listofdmp = j.all_coeffs() + degree = len(listofdmp) - 1 + + for k in range(degree + 1): + coeff = listofdmp[degree - k] + + if coeff == 0: + continue + + if (i - k, k - i) in dict1: + dict1[(i - k, k - i)] += (dom.to_sympy(coeff) * rf(n - k + 1 + p, i)) + else: + dict1[(i - k, k - i)] = (dom.to_sympy(coeff) * rf(n - k + 1 + p, i)) + + sol = [] + keylist = [i[0] for i in dict1] + lower = min(keylist) + upper = max(keylist) + degree = max(i[1] for i in dict1) + degree2 = min(i[1] for i in dict1) + + smallest_n = lower + degree + dummys = {} + eqs = [] + unknowns = [] + + for j in range(lower, upper + 1): + if j in keylist: + temp = sum((v.subs(n, n - lower) + for k, v in dict1.items() if k[0] == j), + start=S.Zero) + sol.append(temp) + else: + sol.append(S.Zero) + + # the recurrence relation + sol = RecurrenceOperator(sol, R) + + # computing the initial conditions for recurrence + order = sol.order + all_roots = roots(R.base.to_sympy(sol.listofpoly[-1]), n, filter='Z') + all_roots = all_roots.keys() + + if all_roots: + max_root = max(all_roots) + 1 + smallest_n = max(max_root, smallest_n) + order += smallest_n + + u0 = [] + + if self.is_singularics() == True: + u0 = self.y0[p] + + elif self.is_singularics() == False and p >= 0 and int(p) == p and len(rootstoconsider) == 1: + y0 = _extend_y0(self, order + int(p)) + # u(n) = y^n(0)/factorial(n) + if len(y0) > int(p): + u0 = [y0[i] / factorial(i) for i in range(int(p), len(y0))] + + if len(u0) < order: + + for i in range(degree2, degree): + eq = S.Zero + + for j in dict1: + if i + j[0] < 0: + dummys[i + j[0]] = S.Zero + + elif i + j[0] < len(u0): + dummys[i + j[0]] = u0[i + j[0]] + + elif not i + j[0] in dummys: + letter = chr(char) + '_%s' %(i + j[0]) + dummys[i + j[0]] = Symbol(letter) + unknowns.append(dummys[i + j[0]]) + + if j[1] <= i: + eq += dict1[j].subs(n, i) * dummys[i + j[0]] + + eqs.append(eq) + + # solve the system of equations formed + soleqs = solve(eqs, *unknowns) + + if isinstance(soleqs, dict): + + for i in range(len(u0), order): + + if i not in dummys: + letter = chr(char) + '_%s' %i + dummys[i] = Symbol(letter) + + if dummys[i] in soleqs: + u0.append(soleqs[dummys[i]]) + + else: + u0.append(dummys[i]) + + if lb: + finalsol.append((HolonomicSequence(sol, u0), p, smallest_n)) + continue + else: + finalsol.append((HolonomicSequence(sol, u0), p)) + continue + + for i in range(len(u0), order): + + if i not in dummys: + letter = chr(char) + '_%s' %i + dummys[i] = Symbol(letter) + + s = False + for j in soleqs: + if dummys[i] in j: + u0.append(j[dummys[i]]) + s = True + if not s: + u0.append(dummys[i]) + if lb: + finalsol.append((HolonomicSequence(sol, u0), p, smallest_n)) + + else: + finalsol.append((HolonomicSequence(sol, u0), p)) + char += 1 + return finalsol + + def series(self, n=6, coefficient=False, order=True, _recur=None): + r""" + Finds the power series expansion of given holonomic function about :math:`x_0`. + + Explanation + =========== + + A list of series might be returned if :math:`x_0` is a regular point with + multiple roots of the indicial equation. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import QQ + >>> from sympy import symbols + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') + >>> HolonomicFunction(Dx - 1, x, 0, [1]).series() # e^x + 1 + x + x**2/2 + x**3/6 + x**4/24 + x**5/120 + O(x**6) + >>> HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]).series(n=8) # sin(x) + x - x**3/6 + x**5/120 - x**7/5040 + O(x**8) + + See Also + ======== + + HolonomicFunction.to_sequence + """ + + if _recur is None: + recurrence = self.to_sequence() + else: + recurrence = _recur + + if isinstance(recurrence, tuple) and len(recurrence) == 2: + recurrence = recurrence[0] + constantpower = 0 + elif isinstance(recurrence, tuple) and len(recurrence) == 3: + constantpower = recurrence[1] + recurrence = recurrence[0] + + elif len(recurrence) == 1 and len(recurrence[0]) == 2: + recurrence = recurrence[0][0] + constantpower = 0 + elif len(recurrence) == 1 and len(recurrence[0]) == 3: + constantpower = recurrence[0][1] + recurrence = recurrence[0][0] + else: + return [self.series(_recur=i) for i in recurrence] + + n = n - int(constantpower) + l = len(recurrence.u0) - 1 + k = recurrence.recurrence.order + x = self.x + x0 = self.x0 + seq_dmp = recurrence.recurrence.listofpoly + R = recurrence.recurrence.parent.base + K = R.get_field() + seq = [K.new(j.to_list()) for j in seq_dmp] + sub = [-seq[i] / seq[k] for i in range(k)] + sol = list(recurrence.u0) + + if l + 1 < n: + # use the initial conditions to find the next term + for i in range(l + 1 - k, n - k): + coeff = sum((DMFsubs(sub[j], i) * sol[i + j] + for j in range(k) if i + j >= 0), start=S.Zero) + sol.append(coeff) + + if coefficient: + return sol + + ser = sum((x**(i + constantpower) * j for i, j in enumerate(sol)), + start=S.Zero) + if order: + ser += Order(x**(n + int(constantpower)), x) + if x0 != 0: + return ser.subs(x, x - x0) + return ser + + def _indicial(self): + """ + Computes roots of the Indicial equation. + """ + + if self.x0 != 0: + return self.shift_x(self.x0)._indicial() + + list_coeff = self.annihilator.listofpoly + R = self.annihilator.parent.base + x = self.x + s = R.zero + y = R.one + + def _pole_degree(poly): + root_all = roots(R.to_sympy(poly), x, filter='Z') + if 0 in root_all.keys(): + return root_all[0] + else: + return 0 + + degree = max(j.degree() for j in list_coeff) + inf = 10 * (max(1, degree) + max(1, self.annihilator.order)) + + deg = lambda q: inf if q.is_zero else _pole_degree(q) + b = min(deg(q) - j for j, q in enumerate(list_coeff)) + + for i, j in enumerate(list_coeff): + listofdmp = j.all_coeffs() + degree = len(listofdmp) - 1 + if 0 <= i + b <= degree: + s = s + listofdmp[degree - i - b] * y + y *= R.from_sympy(x - i) + + return roots(R.to_sympy(s), x) + + def evalf(self, points, method='RK4', h=0.05, derivatives=False): + r""" + Finds numerical value of a holonomic function using numerical methods. + (RK4 by default). A set of points (real or complex) must be provided + which will be the path for the numerical integration. + + Explanation + =========== + + The path should be given as a list :math:`[x_1, x_2, \dots x_n]`. The numerical + values will be computed at each point in this order + :math:`x_1 \rightarrow x_2 \rightarrow x_3 \dots \rightarrow x_n`. + + Returns values of the function at :math:`x_1, x_2, \dots x_n` in a list. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import QQ + >>> from sympy import symbols + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') + + A straight line on the real axis from (0 to 1) + + >>> r = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1] + + Runge-Kutta 4th order on e^x from 0.1 to 1. + Exact solution at 1 is 2.71828182845905 + + >>> HolonomicFunction(Dx - 1, x, 0, [1]).evalf(r) + [1.10517083333333, 1.22140257085069, 1.34985849706254, 1.49182424008069, + 1.64872063859684, 1.82211796209193, 2.01375162659678, 2.22553956329232, + 2.45960141378007, 2.71827974413517] + + Euler's method for the same + + >>> HolonomicFunction(Dx - 1, x, 0, [1]).evalf(r, method='Euler') + [1.1, 1.21, 1.331, 1.4641, 1.61051, 1.771561, 1.9487171, 2.14358881, + 2.357947691, 2.5937424601] + + One can also observe that the value obtained using Runge-Kutta 4th order + is much more accurate than Euler's method. + """ + + from sympy.holonomic.numerical import _evalf + lp = False + + # if a point `b` is given instead of a mesh + if not hasattr(points, "__iter__"): + lp = True + b = S(points) + if self.x0 == b: + return _evalf(self, [b], method=method, derivatives=derivatives)[-1] + + if not b.is_Number: + raise NotImplementedError + + a = self.x0 + if a > b: + h = -h + n = int((b - a) / h) + points = [a + h] + for i in range(n - 1): + points.append(points[-1] + h) + + for i in roots(self.annihilator.parent.base.to_sympy(self.annihilator.listofpoly[-1]), self.x): + if i == self.x0 or i in points: + raise SingularityError(self, i) + + if lp: + return _evalf(self, points, method=method, derivatives=derivatives)[-1] + return _evalf(self, points, method=method, derivatives=derivatives) + + def change_x(self, z): + """ + Changes only the variable of Holonomic Function, for internal + purposes. For composition use HolonomicFunction.composition() + """ + + dom = self.annihilator.parent.base.dom + R = dom.old_poly_ring(z) + parent, _ = DifferentialOperators(R, 'Dx') + sol = [R(j.to_list()) for j in self.annihilator.listofpoly] + sol = DifferentialOperator(sol, parent) + return HolonomicFunction(sol, z, self.x0, self.y0) + + def shift_x(self, a): + """ + Substitute `x + a` for `x`. + """ + + x = self.x + listaftershift = self.annihilator.listofpoly + base = self.annihilator.parent.base + + sol = [base.from_sympy(base.to_sympy(i).subs(x, x + a)) for i in listaftershift] + sol = DifferentialOperator(sol, self.annihilator.parent) + x0 = self.x0 - a + if not self._have_init_cond(): + return HolonomicFunction(sol, x) + return HolonomicFunction(sol, x, x0, self.y0) + + def to_hyper(self, as_list=False, _recur=None): + r""" + Returns a hypergeometric function (or linear combination of them) + representing the given holonomic function. + + Explanation + =========== + + Returns an answer of the form: + `a_1 \cdot x^{b_1} \cdot{hyper()} + a_2 \cdot x^{b_2} \cdot{hyper()} \dots` + + This is very useful as one can now use ``hyperexpand`` to find the + symbolic expressions/functions. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import ZZ + >>> from sympy import symbols + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x),'Dx') + >>> # sin(x) + >>> HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]).to_hyper() + x*hyper((), (3/2,), -x**2/4) + >>> # exp(x) + >>> HolonomicFunction(Dx - 1, x, 0, [1]).to_hyper() + hyper((), (), x) + + See Also + ======== + + from_hyper, from_meijerg + """ + + if _recur is None: + recurrence = self.to_sequence() + else: + recurrence = _recur + + if isinstance(recurrence, tuple) and len(recurrence) == 2: + smallest_n = recurrence[1] + recurrence = recurrence[0] + constantpower = 0 + elif isinstance(recurrence, tuple) and len(recurrence) == 3: + smallest_n = recurrence[2] + constantpower = recurrence[1] + recurrence = recurrence[0] + elif len(recurrence) == 1 and len(recurrence[0]) == 2: + smallest_n = recurrence[0][1] + recurrence = recurrence[0][0] + constantpower = 0 + elif len(recurrence) == 1 and len(recurrence[0]) == 3: + smallest_n = recurrence[0][2] + constantpower = recurrence[0][1] + recurrence = recurrence[0][0] + else: + sol = self.to_hyper(as_list=as_list, _recur=recurrence[0]) + for i in recurrence[1:]: + sol += self.to_hyper(as_list=as_list, _recur=i) + return sol + + u0 = recurrence.u0 + r = recurrence.recurrence + x = self.x + x0 = self.x0 + + # order of the recurrence relation + m = r.order + + # when no recurrence exists, and the power series have finite terms + if m == 0: + nonzeroterms = roots(r.parent.base.to_sympy(r.listofpoly[0]), recurrence.n, filter='R') + + sol = S.Zero + for j, i in enumerate(nonzeroterms): + + if i < 0 or not int_valued(i): + continue + + i = int(i) + if i < len(u0): + if isinstance(u0[i], (PolyElement, FracElement)): + u0[i] = u0[i].as_expr() + sol += u0[i] * x**i + + else: + sol += Symbol('C_%s' %j) * x**i + + if isinstance(sol, (PolyElement, FracElement)): + sol = sol.as_expr() * x**constantpower + else: + sol = sol * x**constantpower + if as_list: + if x0 != 0: + return [(sol.subs(x, x - x0), )] + return [(sol, )] + if x0 != 0: + return sol.subs(x, x - x0) + return sol + + if smallest_n + m > len(u0): + raise NotImplementedError("Can't compute sufficient Initial Conditions") + + # check if the recurrence represents a hypergeometric series + if any(i != r.parent.base.zero for i in r.listofpoly[1:-1]): + raise NotHyperSeriesError(self, self.x0) + + a = r.listofpoly[0] + b = r.listofpoly[-1] + + # the constant multiple of argument of hypergeometric function + if isinstance(a.LC(), (PolyElement, FracElement)): + c = - (S(a.LC().as_expr()) * m**(a.degree())) / (S(b.LC().as_expr()) * m**(b.degree())) + else: + c = - (S(a.LC()) * m**(a.degree())) / (S(b.LC()) * m**(b.degree())) + + sol = 0 + + arg1 = roots(r.parent.base.to_sympy(a), recurrence.n) + arg2 = roots(r.parent.base.to_sympy(b), recurrence.n) + + # iterate through the initial conditions to find + # the hypergeometric representation of the given + # function. + # The answer will be a linear combination + # of different hypergeometric series which satisfies + # the recurrence. + if as_list: + listofsol = [] + for i in range(smallest_n + m): + + # if the recurrence relation doesn't hold for `n = i`, + # then a Hypergeometric representation doesn't exist. + # add the algebraic term a * x**i to the solution, + # where a is u0[i] + if i < smallest_n: + if as_list: + listofsol.append(((S(u0[i]) * x**(i+constantpower)).subs(x, x-x0), )) + else: + sol += S(u0[i]) * x**i + continue + + # if the coefficient u0[i] is zero, then the + # independent hypergeomtric series starting with + # x**i is not a part of the answer. + if S(u0[i]) == 0: + continue + + ap = [] + bq = [] + + # substitute m * n + i for n + for k in ordered(arg1.keys()): + ap.extend([nsimplify((i - k) / m)] * arg1[k]) + + for k in ordered(arg2.keys()): + bq.extend([nsimplify((i - k) / m)] * arg2[k]) + + # convention of (k + 1) in the denominator + if 1 in bq: + bq.remove(1) + else: + ap.append(1) + if as_list: + listofsol.append(((S(u0[i])*x**(i+constantpower)).subs(x, x-x0), (hyper(ap, bq, c*x**m)).subs(x, x-x0))) + else: + sol += S(u0[i]) * hyper(ap, bq, c * x**m) * x**i + if as_list: + return listofsol + sol = sol * x**constantpower + if x0 != 0: + return sol.subs(x, x - x0) + + return sol + + def to_expr(self): + """ + Converts a Holonomic Function back to elementary functions. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators + >>> from sympy import ZZ + >>> from sympy import symbols, S + >>> x = symbols('x') + >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x),'Dx') + >>> HolonomicFunction(x**2*Dx**2 + x*Dx + (x**2 - 1), x, 0, [0, S(1)/2]).to_expr() + besselj(1, x) + >>> HolonomicFunction((1 + x)*Dx**3 + Dx**2, x, 0, [1, 1, 1]).to_expr() + x*log(x + 1) + log(x + 1) + 1 + + """ + + return hyperexpand(self.to_hyper()).simplify() + + def change_ics(self, b, lenics=None): + """ + Changes the point `x0` to ``b`` for initial conditions. + + Examples + ======== + + >>> from sympy.holonomic import expr_to_holonomic + >>> from sympy import symbols, sin, exp + >>> x = symbols('x') + + >>> expr_to_holonomic(sin(x)).change_ics(1) + HolonomicFunction((1) + (1)*Dx**2, x, 1, [sin(1), cos(1)]) + + >>> expr_to_holonomic(exp(x)).change_ics(2) + HolonomicFunction((-1) + (1)*Dx, x, 2, [exp(2)]) + """ + + symbolic = True + + if lenics is None and len(self.y0) > self.annihilator.order: + lenics = len(self.y0) + dom = self.annihilator.parent.base.domain + + try: + sol = expr_to_holonomic(self.to_expr(), x=self.x, x0=b, lenics=lenics, domain=dom) + except (NotPowerSeriesError, NotHyperSeriesError): + symbolic = False + + if symbolic and sol.x0 == b: + return sol + + y0 = self.evalf(b, derivatives=True) + return HolonomicFunction(self.annihilator, self.x, b, y0) + + def to_meijerg(self): + """ + Returns a linear combination of Meijer G-functions. + + Examples + ======== + + >>> from sympy.holonomic import expr_to_holonomic + >>> from sympy import sin, cos, hyperexpand, log, symbols + >>> x = symbols('x') + >>> hyperexpand(expr_to_holonomic(cos(x) + sin(x)).to_meijerg()) + sin(x) + cos(x) + >>> hyperexpand(expr_to_holonomic(log(x)).to_meijerg()).simplify() + log(x) + + See Also + ======== + + to_hyper + """ + + # convert to hypergeometric first + rep = self.to_hyper(as_list=True) + sol = S.Zero + + for i in rep: + if len(i) == 1: + sol += i[0] + + elif len(i) == 2: + sol += i[0] * _hyper_to_meijerg(i[1]) + + return sol + + +def from_hyper(func, x0=0, evalf=False): + r""" + Converts a hypergeometric function to holonomic. + ``func`` is the Hypergeometric Function and ``x0`` is the point at + which initial conditions are required. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import from_hyper + >>> from sympy import symbols, hyper, S + >>> x = symbols('x') + >>> from_hyper(hyper([], [S(3)/2], x**2/4)) + HolonomicFunction((-x) + (2)*Dx + (x)*Dx**2, x, 1, [sinh(1), -sinh(1) + cosh(1)]) + """ + + a = func.ap + b = func.bq + z = func.args[2] + x = z.atoms(Symbol).pop() + R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') + + # generalized hypergeometric differential equation + xDx = x*Dx + r1 = 1 + for ai in a: # XXX gives sympify error if Mul is used with list of all factors + r1 *= xDx + ai + xDx_1 = xDx - 1 + # r2 = Mul(*([Dx] + [xDx_1 + bi for bi in b])) # XXX gives sympify error + r2 = Dx + for bi in b: + r2 *= xDx_1 + bi + sol = r1 - r2 + + simp = hyperexpand(func) + + if simp in (Infinity, NegativeInfinity): + return HolonomicFunction(sol, x).composition(z) + + # if the function is known symbolically + if not isinstance(simp, hyper): + y0 = _find_conditions(simp, x, x0, sol.order, use_limit=False) + while not y0: + # if values don't exist at 0, then try to find initial + # conditions at 1. If it doesn't exist at 1 too then + # try 2 and so on. + x0 += 1 + y0 = _find_conditions(simp, x, x0, sol.order, use_limit=False) + + return HolonomicFunction(sol, x).composition(z, x0, y0) + + if isinstance(simp, hyper): + x0 = 1 + # use evalf if the function can't be simplified + y0 = _find_conditions(simp, x, x0, sol.order, evalf, use_limit=False) + while not y0: + x0 += 1 + y0 = _find_conditions(simp, x, x0, sol.order, evalf, use_limit=False) + return HolonomicFunction(sol, x).composition(z, x0, y0) + + return HolonomicFunction(sol, x).composition(z) + + +def from_meijerg(func, x0=0, evalf=False, initcond=True, domain=QQ): + """ + Converts a Meijer G-function to Holonomic. + ``func`` is the G-Function and ``x0`` is the point at + which initial conditions are required. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import from_meijerg + >>> from sympy import symbols, meijerg, S + >>> x = symbols('x') + >>> from_meijerg(meijerg(([], []), ([S(1)/2], [0]), x**2/4)) + HolonomicFunction((1) + (1)*Dx**2, x, 0, [0, 1/sqrt(pi)]) + """ + + a = func.ap + b = func.bq + n = len(func.an) + m = len(func.bm) + p = len(a) + z = func.args[2] + x = z.atoms(Symbol).pop() + R, Dx = DifferentialOperators(domain.old_poly_ring(x), 'Dx') + + # compute the differential equation satisfied by the + # Meijer G-function. + xDx = x*Dx + xDx1 = xDx + 1 + r1 = x*(-1)**(m + n - p) + for ai in a: # XXX gives sympify error if args given in list + r1 *= xDx1 - ai + # r2 = Mul(*[xDx - bi for bi in b]) # gives sympify error + r2 = 1 + for bi in b: + r2 *= xDx - bi + sol = r1 - r2 + + if not initcond: + return HolonomicFunction(sol, x).composition(z) + + simp = hyperexpand(func) + + if simp in (Infinity, NegativeInfinity): + return HolonomicFunction(sol, x).composition(z) + + # computing initial conditions + if not isinstance(simp, meijerg): + y0 = _find_conditions(simp, x, x0, sol.order, use_limit=False) + while not y0: + x0 += 1 + y0 = _find_conditions(simp, x, x0, sol.order, use_limit=False) + + return HolonomicFunction(sol, x).composition(z, x0, y0) + + if isinstance(simp, meijerg): + x0 = 1 + y0 = _find_conditions(simp, x, x0, sol.order, evalf, use_limit=False) + while not y0: + x0 += 1 + y0 = _find_conditions(simp, x, x0, sol.order, evalf, use_limit=False) + + return HolonomicFunction(sol, x).composition(z, x0, y0) + + return HolonomicFunction(sol, x).composition(z) + + +x_1 = Dummy('x_1') +_lookup_table = None +domain_for_table = None +from sympy.integrals.meijerint import _mytype + + +def expr_to_holonomic(func, x=None, x0=0, y0=None, lenics=None, domain=None, initcond=True): + """ + Converts a function or an expression to a holonomic function. + + Parameters + ========== + + func: + The expression to be converted. + x: + variable for the function. + x0: + point at which initial condition must be computed. + y0: + One can optionally provide initial condition if the method + is not able to do it automatically. + lenics: + Number of terms in the initial condition. By default it is + equal to the order of the annihilator. + domain: + Ground domain for the polynomials in ``x`` appearing as coefficients + in the annihilator. + initcond: + Set it false if you do not want the initial conditions to be computed. + + Examples + ======== + + >>> from sympy.holonomic.holonomic import expr_to_holonomic + >>> from sympy import sin, exp, symbols + >>> x = symbols('x') + >>> expr_to_holonomic(sin(x)) + HolonomicFunction((1) + (1)*Dx**2, x, 0, [0, 1]) + >>> expr_to_holonomic(exp(x)) + HolonomicFunction((-1) + (1)*Dx, x, 0, [1]) + + See Also + ======== + + sympy.integrals.meijerint._rewrite1, _convert_poly_rat_alg, _create_table + """ + func = sympify(func) + syms = func.free_symbols + + if not x: + if len(syms) == 1: + x= syms.pop() + else: + raise ValueError("Specify the variable for the function") + elif x in syms: + syms.remove(x) + + extra_syms = list(syms) + + if domain is None: + if func.has(Float): + domain = RR + else: + domain = QQ + if len(extra_syms) != 0: + domain = domain[extra_syms].get_field() + + # try to convert if the function is polynomial or rational + solpoly = _convert_poly_rat_alg(func, x, x0=x0, y0=y0, lenics=lenics, domain=domain, initcond=initcond) + if solpoly: + return solpoly + + # create the lookup table + global _lookup_table, domain_for_table + if not _lookup_table: + domain_for_table = domain + _lookup_table = {} + _create_table(_lookup_table, domain=domain) + elif domain != domain_for_table: + domain_for_table = domain + _lookup_table = {} + _create_table(_lookup_table, domain=domain) + + # use the table directly to convert to Holonomic + if func.is_Function: + f = func.subs(x, x_1) + t = _mytype(f, x_1) + if t in _lookup_table: + l = _lookup_table[t] + sol = l[0][1].change_x(x) + else: + sol = _convert_meijerint(func, x, initcond=False, domain=domain) + if not sol: + raise NotImplementedError + if y0: + sol.y0 = y0 + if y0 or not initcond: + sol.x0 = x0 + return sol + if not lenics: + lenics = sol.annihilator.order + _y0 = _find_conditions(func, x, x0, lenics) + while not _y0: + x0 += 1 + _y0 = _find_conditions(func, x, x0, lenics) + return HolonomicFunction(sol.annihilator, x, x0, _y0) + + if y0 or not initcond: + sol = sol.composition(func.args[0]) + if y0: + sol.y0 = y0 + sol.x0 = x0 + return sol + if not lenics: + lenics = sol.annihilator.order + + _y0 = _find_conditions(func, x, x0, lenics) + while not _y0: + x0 += 1 + _y0 = _find_conditions(func, x, x0, lenics) + return sol.composition(func.args[0], x0, _y0) + + # iterate through the expression recursively + args = func.args + f = func.func + sol = expr_to_holonomic(args[0], x=x, initcond=False, domain=domain) + + if f is Add: + for i in range(1, len(args)): + sol += expr_to_holonomic(args[i], x=x, initcond=False, domain=domain) + + elif f is Mul: + for i in range(1, len(args)): + sol *= expr_to_holonomic(args[i], x=x, initcond=False, domain=domain) + + elif f is Pow: + sol = sol**args[1] + sol.x0 = x0 + if not sol: + raise NotImplementedError + if y0: + sol.y0 = y0 + if y0 or not initcond: + return sol + if sol.y0: + return sol + if not lenics: + lenics = sol.annihilator.order + if sol.annihilator.is_singular(x0): + r = sol._indicial() + l = list(r) + if len(r) == 1 and r[l[0]] == S.One: + r = l[0] + g = func / (x - x0)**r + singular_ics = _find_conditions(g, x, x0, lenics) + singular_ics = [j / factorial(i) for i, j in enumerate(singular_ics)] + y0 = {r:singular_ics} + return HolonomicFunction(sol.annihilator, x, x0, y0) + + _y0 = _find_conditions(func, x, x0, lenics) + while not _y0: + x0 += 1 + _y0 = _find_conditions(func, x, x0, lenics) + + return HolonomicFunction(sol.annihilator, x, x0, _y0) + + +## Some helper functions ## + +def _normalize(list_of, parent, negative=True): + """ + Normalize a given annihilator + """ + + num = [] + denom = [] + base = parent.base + K = base.get_field() + lcm_denom = base.from_sympy(S.One) + list_of_coeff = [] + + # convert polynomials to the elements of associated + # fraction field + for i, j in enumerate(list_of): + if isinstance(j, base.dtype): + list_of_coeff.append(K.new(j.to_list())) + elif not isinstance(j, K.dtype): + list_of_coeff.append(K.from_sympy(sympify(j))) + else: + list_of_coeff.append(j) + + # corresponding numerators of the sequence of polynomials + num.append(list_of_coeff[i].numer()) + + # corresponding denominators + denom.append(list_of_coeff[i].denom()) + + # lcm of denominators in the coefficients + for i in denom: + lcm_denom = i.lcm(lcm_denom) + + if negative: + lcm_denom = -lcm_denom + + lcm_denom = K.new(lcm_denom.to_list()) + + # multiply the coefficients with lcm + for i, j in enumerate(list_of_coeff): + list_of_coeff[i] = j * lcm_denom + + gcd_numer = base((list_of_coeff[-1].numer() / list_of_coeff[-1].denom()).to_list()) + + # gcd of numerators in the coefficients + for i in num: + gcd_numer = i.gcd(gcd_numer) + + gcd_numer = K.new(gcd_numer.to_list()) + + # divide all the coefficients by the gcd + for i, j in enumerate(list_of_coeff): + frac_ans = j / gcd_numer + list_of_coeff[i] = base((frac_ans.numer() / frac_ans.denom()).to_list()) + + return DifferentialOperator(list_of_coeff, parent) + + +def _derivate_diff_eq(listofpoly, K): + """ + Let a differential equation a0(x)y(x) + a1(x)y'(x) + ... = 0 + where a0, a1,... are polynomials or rational functions. The function + returns b0, b1, b2... such that the differential equation + b0(x)y(x) + b1(x)y'(x) +... = 0 is formed after differentiating the + former equation. + """ + + sol = [] + a = len(listofpoly) - 1 + sol.append(DMFdiff(listofpoly[0], K)) + + for i, j in enumerate(listofpoly[1:]): + sol.append(DMFdiff(j, K) + listofpoly[i]) + + sol.append(listofpoly[a]) + return sol + + +def _hyper_to_meijerg(func): + """ + Converts a `hyper` to meijerg. + """ + ap = func.ap + bq = func.bq + + if any(i <= 0 and int(i) == i for i in ap): + return hyperexpand(func) + + z = func.args[2] + + # parameters of the `meijerg` function. + an = (1 - i for i in ap) + anp = () + bm = (S.Zero, ) + bmq = (1 - i for i in bq) + + k = S.One + + for i in bq: + k = k * gamma(i) + + for i in ap: + k = k / gamma(i) + + return k * meijerg(an, anp, bm, bmq, -z) + + +def _add_lists(list1, list2): + """Takes polynomial sequences of two annihilators a and b and returns + the list of polynomials of sum of a and b. + """ + if len(list1) <= len(list2): + sol = [a + b for a, b in zip(list1, list2)] + list2[len(list1):] + else: + sol = [a + b for a, b in zip(list1, list2)] + list1[len(list2):] + return sol + + +def _extend_y0(Holonomic, n): + """ + Tries to find more initial conditions by substituting the initial + value point in the differential equation. + """ + + if Holonomic.annihilator.is_singular(Holonomic.x0) or Holonomic.is_singularics() == True: + return Holonomic.y0 + + annihilator = Holonomic.annihilator + a = annihilator.order + + listofpoly = [] + + y0 = Holonomic.y0 + R = annihilator.parent.base + K = R.get_field() + + for j in annihilator.listofpoly: + if isinstance(j, annihilator.parent.base.dtype): + listofpoly.append(K.new(j.to_list())) + + if len(y0) < a or n <= len(y0): + return y0 + list_red = [-listofpoly[i] / listofpoly[a] + for i in range(a)] + y1 = y0[:min(len(y0), a)] + for _ in range(n - a): + sol = 0 + for a, b in zip(y1, list_red): + r = DMFsubs(b, Holonomic.x0) + if not getattr(r, 'is_finite', True): + return y0 + if isinstance(r, (PolyElement, FracElement)): + r = r.as_expr() + sol += a * r + y1.append(sol) + list_red = _derivate_diff_eq(list_red, K) + return y0 + y1[len(y0):] + + +def DMFdiff(frac, K): + # differentiate a DMF object represented as p/q + if not isinstance(frac, DMF): + return frac.diff() + + p = K.numer(frac) + q = K.denom(frac) + sol_num = - p * q.diff() + q * p.diff() + sol_denom = q**2 + return K((sol_num.to_list(), sol_denom.to_list())) + + +def DMFsubs(frac, x0, mpm=False): + # substitute the point x0 in DMF object of the form p/q + if not isinstance(frac, DMF): + return frac + + p = frac.num + q = frac.den + sol_p = S.Zero + sol_q = S.Zero + + if mpm: + from mpmath import mp + + for i, j in enumerate(reversed(p)): + if mpm: + j = sympify(j)._to_mpmath(mp.prec) + sol_p += j * x0**i + + for i, j in enumerate(reversed(q)): + if mpm: + j = sympify(j)._to_mpmath(mp.prec) + sol_q += j * x0**i + + if isinstance(sol_p, (PolyElement, FracElement)): + sol_p = sol_p.as_expr() + if isinstance(sol_q, (PolyElement, FracElement)): + sol_q = sol_q.as_expr() + + return sol_p / sol_q + + +def _convert_poly_rat_alg(func, x, x0=0, y0=None, lenics=None, domain=QQ, initcond=True): + """ + Converts polynomials, rationals and algebraic functions to holonomic. + """ + + ispoly = func.is_polynomial() + if not ispoly: + israt = func.is_rational_function() + else: + israt = True + + if not (ispoly or israt): + basepoly, ratexp = func.as_base_exp() + if basepoly.is_polynomial() and ratexp.is_Number: + if isinstance(ratexp, Float): + ratexp = nsimplify(ratexp) + m, n = ratexp.p, ratexp.q + is_alg = True + else: + is_alg = False + else: + is_alg = True + + if not (ispoly or israt or is_alg): + return None + + R = domain.old_poly_ring(x) + _, Dx = DifferentialOperators(R, 'Dx') + + # if the function is constant + if not func.has(x): + return HolonomicFunction(Dx, x, 0, [func]) + + if ispoly: + # differential equation satisfied by polynomial + sol = func * Dx - func.diff(x) + sol = _normalize(sol.listofpoly, sol.parent, negative=False) + is_singular = sol.is_singular(x0) + + # try to compute the conditions for singular points + if y0 is None and x0 == 0 and is_singular: + rep = R.from_sympy(func).to_list() + for i, j in enumerate(reversed(rep)): + if j == 0: + continue + coeff = list(reversed(rep))[i:] + indicial = i + break + for i, j in enumerate(coeff): + if isinstance(j, (PolyElement, FracElement)): + coeff[i] = j.as_expr() + y0 = {indicial: S(coeff)} + + elif israt: + p, q = func.as_numer_denom() + # differential equation satisfied by rational + sol = p * q * Dx + p * q.diff(x) - q * p.diff(x) + sol = _normalize(sol.listofpoly, sol.parent, negative=False) + + elif is_alg: + sol = n * (x / m) * Dx - 1 + sol = HolonomicFunction(sol, x).composition(basepoly).annihilator + is_singular = sol.is_singular(x0) + + # try to compute the conditions for singular points + if y0 is None and x0 == 0 and is_singular and \ + (lenics is None or lenics <= 1): + rep = R.from_sympy(basepoly).to_list() + for i, j in enumerate(reversed(rep)): + if j == 0: + continue + if isinstance(j, (PolyElement, FracElement)): + j = j.as_expr() + + coeff = S(j)**ratexp + indicial = S(i) * ratexp + break + if isinstance(coeff, (PolyElement, FracElement)): + coeff = coeff.as_expr() + y0 = {indicial: S([coeff])} + + if y0 or not initcond: + return HolonomicFunction(sol, x, x0, y0) + + if not lenics: + lenics = sol.order + + if sol.is_singular(x0): + r = HolonomicFunction(sol, x, x0)._indicial() + l = list(r) + if len(r) == 1 and r[l[0]] == S.One: + r = l[0] + g = func / (x - x0)**r + singular_ics = _find_conditions(g, x, x0, lenics) + singular_ics = [j / factorial(i) for i, j in enumerate(singular_ics)] + y0 = {r:singular_ics} + return HolonomicFunction(sol, x, x0, y0) + + y0 = _find_conditions(func, x, x0, lenics) + while not y0: + x0 += 1 + y0 = _find_conditions(func, x, x0, lenics) + + return HolonomicFunction(sol, x, x0, y0) + + +def _convert_meijerint(func, x, initcond=True, domain=QQ): + args = meijerint._rewrite1(func, x) + + if args: + fac, po, g, _ = args + else: + return None + + # lists for sum of meijerg functions + fac_list = [fac * i[0] for i in g] + t = po.as_base_exp() + s = t[1] if t[0] == x else S.Zero + po_list = [s + i[1] for i in g] + G_list = [i[2] for i in g] + + # finds meijerg representation of x**s * meijerg(a1 ... ap, b1 ... bq, z) + def _shift(func, s): + z = func.args[-1] + if z.has(I): + z = z.subs(exp_polar, exp) + + d = z.collect(x, evaluate=False) + b = list(d)[0] + a = d[b] + + t = b.as_base_exp() + b = t[1] if t[0] == x else S.Zero + r = s / b + an = (i + r for i in func.args[0][0]) + ap = (i + r for i in func.args[0][1]) + bm = (i + r for i in func.args[1][0]) + bq = (i + r for i in func.args[1][1]) + + return a**-r, meijerg((an, ap), (bm, bq), z) + + coeff, m = _shift(G_list[0], po_list[0]) + sol = fac_list[0] * coeff * from_meijerg(m, initcond=initcond, domain=domain) + + # add all the meijerg functions after converting to holonomic + for i in range(1, len(G_list)): + coeff, m = _shift(G_list[i], po_list[i]) + sol += fac_list[i] * coeff * from_meijerg(m, initcond=initcond, domain=domain) + + return sol + + +def _create_table(table, domain=QQ): + """ + Creates the look-up table. For a similar implementation + see meijerint._create_lookup_table. + """ + + def add(formula, annihilator, arg, x0=0, y0=()): + """ + Adds a formula in the dictionary + """ + table.setdefault(_mytype(formula, x_1), []).append((formula, + HolonomicFunction(annihilator, arg, x0, y0))) + + R = domain.old_poly_ring(x_1) + _, Dx = DifferentialOperators(R, 'Dx') + + # add some basic functions + add(sin(x_1), Dx**2 + 1, x_1, 0, [0, 1]) + add(cos(x_1), Dx**2 + 1, x_1, 0, [1, 0]) + add(exp(x_1), Dx - 1, x_1, 0, 1) + add(log(x_1), Dx + x_1*Dx**2, x_1, 1, [0, 1]) + + add(erf(x_1), 2*x_1*Dx + Dx**2, x_1, 0, [0, 2/sqrt(pi)]) + add(erfc(x_1), 2*x_1*Dx + Dx**2, x_1, 0, [1, -2/sqrt(pi)]) + add(erfi(x_1), -2*x_1*Dx + Dx**2, x_1, 0, [0, 2/sqrt(pi)]) + + add(sinh(x_1), Dx**2 - 1, x_1, 0, [0, 1]) + add(cosh(x_1), Dx**2 - 1, x_1, 0, [1, 0]) + + add(sinc(x_1), x_1 + 2*Dx + x_1*Dx**2, x_1) + + add(Si(x_1), x_1*Dx + 2*Dx**2 + x_1*Dx**3, x_1) + add(Ci(x_1), x_1*Dx + 2*Dx**2 + x_1*Dx**3, x_1) + + add(Shi(x_1), -x_1*Dx + 2*Dx**2 + x_1*Dx**3, x_1) + + +def _find_conditions(func, x, x0, order, evalf=False, use_limit=True): + y0 = [] + for _ in range(order): + val = func.subs(x, x0) + if evalf: + val = val.evalf() + if use_limit and isinstance(val, NaN): + val = limit(func, x, x0) + if val.is_finite is False or isinstance(val, NaN): + return None + y0.append(val) + func = func.diff(x) + return y0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/holonomicerrors.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/holonomicerrors.py new file mode 100644 index 0000000000000000000000000000000000000000..459a94eb25b186e30b9577d972ebc62a36801f6f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/holonomicerrors.py @@ -0,0 +1,49 @@ +""" Common Exceptions for `holonomic` module. """ + +class BaseHolonomicError(Exception): + + def new(self, *args): + raise NotImplementedError("abstract base class") + +class NotPowerSeriesError(BaseHolonomicError): + + def __init__(self, holonomic, x0): + self.holonomic = holonomic + self.x0 = x0 + + def __str__(self): + s = 'A Power Series does not exists for ' + s += str(self.holonomic) + s += ' about %s.' %self.x0 + return s + +class NotHolonomicError(BaseHolonomicError): + + def __init__(self, m): + self.m = m + + def __str__(self): + return self.m + +class SingularityError(BaseHolonomicError): + + def __init__(self, holonomic, x0): + self.holonomic = holonomic + self.x0 = x0 + + def __str__(self): + s = str(self.holonomic) + s += ' has a singularity at %s.' %self.x0 + return s + +class NotHyperSeriesError(BaseHolonomicError): + + def __init__(self, holonomic, x0): + self.holonomic = holonomic + self.x0 = x0 + + def __str__(self): + s = 'Power series expansion of ' + s += str(self.holonomic) + s += ' about %s is not hypergeometric' %self.x0 + return s diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/numerical.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/numerical.py new file mode 100644 index 0000000000000000000000000000000000000000..418b7c627e2e3d74dcded080a9b6d351cdaa9f3f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/numerical.py @@ -0,0 +1,98 @@ +"""Numerical Methods for Holonomic Functions""" + +from sympy.core.sympify import sympify +from sympy.holonomic.holonomic import DMFsubs + +from mpmath import mp + + +def _evalf(func, points, derivatives=False, method='RK4'): + """ + Numerical methods for numerical integration along a given set of + points in the complex plane. + """ + + ann = func.annihilator + a = ann.order + R = ann.parent.base + K = R.get_field() + + if method == 'Euler': + meth = _euler + else: + meth = _rk4 + + dmf = [K.new(j.to_list()) for j in ann.listofpoly] + red = [-dmf[i] / dmf[a] for i in range(a)] + + y0 = func.y0 + if len(y0) < a: + raise TypeError("Not Enough Initial Conditions") + x0 = func.x0 + sol = [meth(red, x0, points[0], y0, a)] + + for i, j in enumerate(points[1:]): + sol.append(meth(red, points[i], j, sol[-1], a)) + + if not derivatives: + return [sympify(i[0]) for i in sol] + else: + return sympify(sol) + + +def _euler(red, x0, x1, y0, a): + """ + Euler's method for numerical integration. + From x0 to x1 with initial values given at x0 as vector y0. + """ + + A = sympify(x0)._to_mpmath(mp.prec) + B = sympify(x1)._to_mpmath(mp.prec) + y_0 = [sympify(i)._to_mpmath(mp.prec) for i in y0] + h = B - A + f_0 = y_0[1:] + f_0_n = 0 + + for i in range(a): + f_0_n += sympify(DMFsubs(red[i], A, mpm=True))._to_mpmath(mp.prec) * y_0[i] + f_0.append(f_0_n) + + return [y_0[i] + h * f_0[i] for i in range(a)] + + +def _rk4(red, x0, x1, y0, a): + """ + Runge-Kutta 4th order numerical method. + """ + + A = sympify(x0)._to_mpmath(mp.prec) + B = sympify(x1)._to_mpmath(mp.prec) + y_0 = [sympify(i)._to_mpmath(mp.prec) for i in y0] + h = B - A + + f_0_n = 0 + f_1_n = 0 + f_2_n = 0 + f_3_n = 0 + + f_0 = y_0[1:] + for i in range(a): + f_0_n += sympify(DMFsubs(red[i], A, mpm=True))._to_mpmath(mp.prec) * y_0[i] + f_0.append(f_0_n) + + f_1 = [y_0[i] + f_0[i]*h/2 for i in range(1, a)] + for i in range(a): + f_1_n += sympify(DMFsubs(red[i], A + h/2, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_0[i]*h/2) + f_1.append(f_1_n) + + f_2 = [y_0[i] + f_1[i]*h/2 for i in range(1, a)] + for i in range(a): + f_2_n += sympify(DMFsubs(red[i], A + h/2, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_1[i]*h/2) + f_2.append(f_2_n) + + f_3 = [y_0[i] + f_2[i]*h for i in range(1, a)] + for i in range(a): + f_3_n += sympify(DMFsubs(red[i], A + h, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_2[i]*h) + f_3.append(f_3_n) + + return [y_0[i] + h*(f_0[i]+2*f_1[i]+2*f_2[i]+f_3[i])/6 for i in range(a)] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/recurrence.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/recurrence.py new file mode 100644 index 0000000000000000000000000000000000000000..8c2c17ceda2d042c12778977cadd5ce9ee3b7479 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/holonomic/recurrence.py @@ -0,0 +1,342 @@ +"""Recurrence Operators""" + +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.printing import sstr +from sympy.core.sympify import sympify + + +def RecurrenceOperators(base, generator): + """ + Returns an Algebra of Recurrence Operators and the operator for + shifting i.e. the `Sn` operator. + The first argument needs to be the base polynomial ring for the algebra + and the second argument must be a generator which can be either a + noncommutative Symbol or a string. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy import symbols + >>> from sympy.holonomic.recurrence import RecurrenceOperators + >>> n = symbols('n', integer=True) + >>> R, Sn = RecurrenceOperators(ZZ.old_poly_ring(n), 'Sn') + """ + + ring = RecurrenceOperatorAlgebra(base, generator) + return (ring, ring.shift_operator) + + +class RecurrenceOperatorAlgebra: + """ + A Recurrence Operator Algebra is a set of noncommutative polynomials + in intermediate `Sn` and coefficients in a base ring A. It follows the + commutation rule: + Sn * a(n) = a(n + 1) * Sn + + This class represents a Recurrence Operator Algebra and serves as the parent ring + for Recurrence Operators. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy import symbols + >>> from sympy.holonomic.recurrence import RecurrenceOperators + >>> n = symbols('n', integer=True) + >>> R, Sn = RecurrenceOperators(ZZ.old_poly_ring(n), 'Sn') + >>> R + Univariate Recurrence Operator Algebra in intermediate Sn over the base ring + ZZ[n] + + See Also + ======== + + RecurrenceOperator + """ + + def __init__(self, base, generator): + # the base ring for the algebra + self.base = base + # the operator representing shift i.e. `Sn` + self.shift_operator = RecurrenceOperator( + [base.zero, base.one], self) + + if generator is None: + self.gen_symbol = symbols('Sn', commutative=False) + else: + if isinstance(generator, str): + self.gen_symbol = symbols(generator, commutative=False) + elif isinstance(generator, Symbol): + self.gen_symbol = generator + + def __str__(self): + string = 'Univariate Recurrence Operator Algebra in intermediate '\ + + sstr(self.gen_symbol) + ' over the base ring ' + \ + (self.base).__str__() + + return string + + __repr__ = __str__ + + def __eq__(self, other): + if self.base == other.base and self.gen_symbol == other.gen_symbol: + return True + else: + return False + + +def _add_lists(list1, list2): + if len(list1) <= len(list2): + sol = [a + b for a, b in zip(list1, list2)] + list2[len(list1):] + else: + sol = [a + b for a, b in zip(list1, list2)] + list1[len(list2):] + return sol + + +class RecurrenceOperator: + """ + The Recurrence Operators are defined by a list of polynomials + in the base ring and the parent ring of the Operator. + + Explanation + =========== + + Takes a list of polynomials for each power of Sn and the + parent ring which must be an instance of RecurrenceOperatorAlgebra. + + A Recurrence Operator can be created easily using + the operator `Sn`. See examples below. + + Examples + ======== + + >>> from sympy.holonomic.recurrence import RecurrenceOperator, RecurrenceOperators + >>> from sympy import ZZ + >>> from sympy import symbols + >>> n = symbols('n', integer=True) + >>> R, Sn = RecurrenceOperators(ZZ.old_poly_ring(n),'Sn') + + >>> RecurrenceOperator([0, 1, n**2], R) + (1)Sn + (n**2)Sn**2 + + >>> Sn*n + (n + 1)Sn + + >>> n*Sn*n + 1 - Sn**2*n + (1) + (n**2 + n)Sn + (-n - 2)Sn**2 + + See Also + ======== + + DifferentialOperatorAlgebra + """ + + _op_priority = 20 + + def __init__(self, list_of_poly, parent): + # the parent ring for this operator + # must be an RecurrenceOperatorAlgebra object + self.parent = parent + # sequence of polynomials in n for each power of Sn + # represents the operator + # convert the expressions into ring elements using from_sympy + if isinstance(list_of_poly, list): + for i, j in enumerate(list_of_poly): + if isinstance(j, int): + list_of_poly[i] = self.parent.base.from_sympy(S(j)) + elif not isinstance(j, self.parent.base.dtype): + list_of_poly[i] = self.parent.base.from_sympy(j) + + self.listofpoly = list_of_poly + self.order = len(self.listofpoly) - 1 + + def __mul__(self, other): + """ + Multiplies two Operators and returns another + RecurrenceOperator instance using the commutation rule + Sn * a(n) = a(n + 1) * Sn + """ + + listofself = self.listofpoly + base = self.parent.base + + if not isinstance(other, RecurrenceOperator): + if not isinstance(other, self.parent.base.dtype): + listofother = [self.parent.base.from_sympy(sympify(other))] + + else: + listofother = [other] + else: + listofother = other.listofpoly + # multiply a polynomial `b` with a list of polynomials + + def _mul_dmp_diffop(b, listofother): + if isinstance(listofother, list): + return [i * b for i in listofother] + return [b * listofother] + + sol = _mul_dmp_diffop(listofself[0], listofother) + + # compute Sn^i * b + def _mul_Sni_b(b): + sol = [base.zero] + + if isinstance(b, list): + for i in b: + j = base.to_sympy(i).subs(base.gens[0], base.gens[0] + S.One) + sol.append(base.from_sympy(j)) + + else: + j = b.subs(base.gens[0], base.gens[0] + S.One) + sol.append(base.from_sympy(j)) + + return sol + + for i in range(1, len(listofself)): + # find Sn^i * b in ith iteration + listofother = _mul_Sni_b(listofother) + # solution = solution + listofself[i] * (Sn^i * b) + sol = _add_lists(sol, _mul_dmp_diffop(listofself[i], listofother)) + + return RecurrenceOperator(sol, self.parent) + + def __rmul__(self, other): + if not isinstance(other, RecurrenceOperator): + + if isinstance(other, int): + other = S(other) + + if not isinstance(other, self.parent.base.dtype): + other = (self.parent.base).from_sympy(other) + + sol = [other * j for j in self.listofpoly] + return RecurrenceOperator(sol, self.parent) + + def __add__(self, other): + if isinstance(other, RecurrenceOperator): + + sol = _add_lists(self.listofpoly, other.listofpoly) + return RecurrenceOperator(sol, self.parent) + + else: + + if isinstance(other, int): + other = S(other) + list_self = self.listofpoly + if not isinstance(other, self.parent.base.dtype): + list_other = [((self.parent).base).from_sympy(other)] + else: + list_other = [other] + sol = [list_self[0] + list_other[0]] + list_self[1:] + + return RecurrenceOperator(sol, self.parent) + + __radd__ = __add__ + + def __sub__(self, other): + return self + (-1) * other + + def __rsub__(self, other): + return (-1) * self + other + + def __pow__(self, n): + if n == 1: + return self + result = RecurrenceOperator([self.parent.base.one], self.parent) + if n == 0: + return result + # if self is `Sn` + if self.listofpoly == self.parent.shift_operator.listofpoly: + sol = [self.parent.base.zero] * n + [self.parent.base.one] + return RecurrenceOperator(sol, self.parent) + x = self + while True: + if n % 2: + result *= x + n >>= 1 + if not n: + break + x *= x + return result + + def __str__(self): + listofpoly = self.listofpoly + print_str = '' + + for i, j in enumerate(listofpoly): + if j == self.parent.base.zero: + continue + + j = self.parent.base.to_sympy(j) + + if i == 0: + print_str += '(' + sstr(j) + ')' + continue + + if print_str: + print_str += ' + ' + + if i == 1: + print_str += '(' + sstr(j) + ')Sn' + continue + + print_str += '(' + sstr(j) + ')' + 'Sn**' + sstr(i) + + return print_str + + __repr__ = __str__ + + def __eq__(self, other): + if isinstance(other, RecurrenceOperator): + if self.listofpoly == other.listofpoly and self.parent == other.parent: + return True + else: + return False + return self.listofpoly[0] == other and \ + all(i is self.parent.base.zero for i in self.listofpoly[1:]) + + +class HolonomicSequence: + """ + A Holonomic Sequence is a type of sequence satisfying a linear homogeneous + recurrence relation with Polynomial coefficients. Alternatively, A sequence + is Holonomic if and only if its generating function is a Holonomic Function. + """ + + def __init__(self, recurrence, u0=[]): + self.recurrence = recurrence + if not isinstance(u0, list): + self.u0 = [u0] + else: + self.u0 = u0 + + if len(self.u0) == 0: + self._have_init_cond = False + else: + self._have_init_cond = True + self.n = recurrence.parent.base.gens[0] + + def __repr__(self): + str_sol = 'HolonomicSequence(%s, %s)' % ((self.recurrence).__repr__(), sstr(self.n)) + if not self._have_init_cond: + return str_sol + else: + cond_str = '' + seq_str = 0 + for i in self.u0: + cond_str += ', u(%s) = %s' % (sstr(seq_str), sstr(i)) + seq_str += 1 + + sol = str_sol + cond_str + return sol + + __str__ = __repr__ + + def __eq__(self, other): + if self.recurrence != other.recurrence or self.n != other.n: + return False + if self._have_init_cond and other._have_init_cond: + return self.u0 == other.u0 + return True diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e78fe96f84d68e9b119571eb22dedb7033811b23 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__init__.py @@ -0,0 +1,45 @@ +"""Integration functions that integrate a SymPy expression. + + Examples + ======== + + >>> from sympy import integrate, sin + >>> from sympy.abc import x + >>> integrate(1/x,x) + log(x) + >>> integrate(sin(x),x) + -cos(x) +""" +from .integrals import integrate, Integral, line_integrate +from .transforms import (mellin_transform, inverse_mellin_transform, + MellinTransform, InverseMellinTransform, + laplace_transform, inverse_laplace_transform, + laplace_correspondence, laplace_initial_conds, + LaplaceTransform, InverseLaplaceTransform, + fourier_transform, inverse_fourier_transform, + FourierTransform, InverseFourierTransform, + sine_transform, inverse_sine_transform, + SineTransform, InverseSineTransform, + cosine_transform, inverse_cosine_transform, + CosineTransform, InverseCosineTransform, + hankel_transform, inverse_hankel_transform, + HankelTransform, InverseHankelTransform) +from .singularityfunctions import singularityintegrate + +__all__ = [ + 'integrate', 'Integral', 'line_integrate', + + 'mellin_transform', 'inverse_mellin_transform', 'MellinTransform', + 'InverseMellinTransform', 'laplace_transform', + 'inverse_laplace_transform', 'LaplaceTransform', + 'laplace_correspondence', 'laplace_initial_conds', + 'InverseLaplaceTransform', 'fourier_transform', + 'inverse_fourier_transform', 'FourierTransform', + 'InverseFourierTransform', 'sine_transform', 'inverse_sine_transform', + 'SineTransform', 'InverseSineTransform', 'cosine_transform', + 'inverse_cosine_transform', 'CosineTransform', 'InverseCosineTransform', + 'hankel_transform', 'inverse_hankel_transform', 'HankelTransform', + 'InverseHankelTransform', + + 'singularityintegrate', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/deltafunctions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/deltafunctions.py new file mode 100644 index 0000000000000000000000000000000000000000..ae9fef0b0010a313e0866a54d978024dd475f882 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/deltafunctions.py @@ -0,0 +1,201 @@ +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.functions import DiracDelta, Heaviside +from .integrals import Integral, integrate + + +def change_mul(node, x): + """change_mul(node, x) + + Rearranges the operands of a product, bringing to front any simple + DiracDelta expression. + + Explanation + =========== + + If no simple DiracDelta expression was found, then all the DiracDelta + expressions are simplified (using DiracDelta.expand(diracdelta=True, wrt=x)). + + Return: (dirac, new node) + Where: + o dirac is either a simple DiracDelta expression or None (if no simple + expression was found); + o new node is either a simplified DiracDelta expressions or None (if it + could not be simplified). + + Examples + ======== + + >>> from sympy import DiracDelta, cos + >>> from sympy.integrals.deltafunctions import change_mul + >>> from sympy.abc import x, y + >>> change_mul(x*y*DiracDelta(x)*cos(x), x) + (DiracDelta(x), x*y*cos(x)) + >>> change_mul(x*y*DiracDelta(x**2 - 1)*cos(x), x) + (None, x*y*cos(x)*DiracDelta(x - 1)/2 + x*y*cos(x)*DiracDelta(x + 1)/2) + >>> change_mul(x*y*DiracDelta(cos(x))*cos(x), x) + (None, None) + + See Also + ======== + + sympy.functions.special.delta_functions.DiracDelta + deltaintegrate + """ + + new_args = [] + dirac = None + + #Sorting is needed so that we consistently collapse the same delta; + #However, we must preserve the ordering of non-commutative terms + c, nc = node.args_cnc() + sorted_args = sorted(c, key=default_sort_key) + sorted_args.extend(nc) + + for arg in sorted_args: + if arg.is_Pow and isinstance(arg.base, DiracDelta): + new_args.append(arg.func(arg.base, arg.exp - 1)) + arg = arg.base + if dirac is None and (isinstance(arg, DiracDelta) and arg.is_simple(x)): + dirac = arg + else: + new_args.append(arg) + if not dirac: # there was no simple dirac + new_args = [] + for arg in sorted_args: + if isinstance(arg, DiracDelta): + new_args.append(arg.expand(diracdelta=True, wrt=x)) + elif arg.is_Pow and isinstance(arg.base, DiracDelta): + new_args.append(arg.func(arg.base.expand(diracdelta=True, wrt=x), arg.exp)) + else: + new_args.append(arg) + if new_args != sorted_args: + nnode = Mul(*new_args).expand() + else: # if the node didn't change there is nothing to do + nnode = None + return (None, nnode) + return (dirac, Mul(*new_args)) + + +def deltaintegrate(f, x): + """ + deltaintegrate(f, x) + + Explanation + =========== + + The idea for integration is the following: + + - If we are dealing with a DiracDelta expression, i.e. DiracDelta(g(x)), + we try to simplify it. + + If we could simplify it, then we integrate the resulting expression. + We already know we can integrate a simplified expression, because only + simple DiracDelta expressions are involved. + + If we couldn't simplify it, there are two cases: + + 1) The expression is a simple expression: we return the integral, + taking care if we are dealing with a Derivative or with a proper + DiracDelta. + + 2) The expression is not simple (i.e. DiracDelta(cos(x))): we can do + nothing at all. + + - If the node is a multiplication node having a DiracDelta term: + + First we expand it. + + If the expansion did work, then we try to integrate the expansion. + + If not, we try to extract a simple DiracDelta term, then we have two + cases: + + 1) We have a simple DiracDelta term, so we return the integral. + + 2) We didn't have a simple term, but we do have an expression with + simplified DiracDelta terms, so we integrate this expression. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.integrals.deltafunctions import deltaintegrate + >>> from sympy import sin, cos, DiracDelta + >>> deltaintegrate(x*sin(x)*cos(x)*DiracDelta(x - 1), x) + sin(1)*cos(1)*Heaviside(x - 1) + >>> deltaintegrate(y**2*DiracDelta(x - z)*DiracDelta(y - z), y) + z**2*DiracDelta(x - z)*Heaviside(y - z) + + See Also + ======== + + sympy.functions.special.delta_functions.DiracDelta + sympy.integrals.integrals.Integral + """ + if not f.has(DiracDelta): + return None + + # g(x) = DiracDelta(h(x)) + if f.func == DiracDelta: + h = f.expand(diracdelta=True, wrt=x) + if h == f: # can't simplify the expression + #FIXME: the second term tells whether is DeltaDirac or Derivative + #For integrating derivatives of DiracDelta we need the chain rule + if f.is_simple(x): + if (len(f.args) <= 1 or f.args[1] == 0): + return Heaviside(f.args[0]) + else: + return (DiracDelta(f.args[0], f.args[1] - 1) / + f.args[0].as_poly().LC()) + else: # let's try to integrate the simplified expression + fh = integrate(h, x) + return fh + elif f.is_Mul or f.is_Pow: # g(x) = a*b*c*f(DiracDelta(h(x)))*d*e + g = f.expand() + if f != g: # the expansion worked + fh = integrate(g, x) + if fh is not None and not isinstance(fh, Integral): + return fh + else: + # no expansion performed, try to extract a simple DiracDelta term + deltaterm, rest_mult = change_mul(f, x) + + if not deltaterm: + if rest_mult: + fh = integrate(rest_mult, x) + return fh + else: + from sympy.solvers import solve + deltaterm = deltaterm.expand(diracdelta=True, wrt=x) + if deltaterm.is_Mul: # Take out any extracted factors + deltaterm, rest_mult_2 = change_mul(deltaterm, x) + rest_mult = rest_mult*rest_mult_2 + point = solve(deltaterm.args[0], x)[0] + + # Return the largest hyperreal term left after + # repeated integration by parts. For example, + # + # integrate(y*DiracDelta(x, 1),x) == y*DiracDelta(x,0), not 0 + # + # This is so Integral(y*DiracDelta(x).diff(x),x).doit() + # will return y*DiracDelta(x) instead of 0 or DiracDelta(x), + # both of which are correct everywhere the value is defined + # but give wrong answers for nested integration. + n = (0 if len(deltaterm.args)==1 else deltaterm.args[1]) + m = 0 + while n >= 0: + r = S.NegativeOne**n*rest_mult.diff(x, n).subs(x, point) + if r.is_zero: + n -= 1 + m += 1 + else: + if m == 0: + return r*Heaviside(x - point) + else: + return r*DiracDelta(x,m-1) + # In some very weak sense, x=0 is still a singularity, + # but we hope will not be of any practical consequence. + return S.Zero + return None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/heurisch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/heurisch.py new file mode 100644 index 0000000000000000000000000000000000000000..a27e2700afd08db16c7a86020eabe5feeb6e1c85 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/heurisch.py @@ -0,0 +1,781 @@ +from __future__ import annotations + +from collections import defaultdict +from functools import reduce +from itertools import permutations + +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.mul import Mul +from sympy.core.symbol import Wild, Dummy, Symbol +from sympy.core.basic import sympify +from sympy.core.numbers import Rational, pi, I +from sympy.core.relational import Eq, Ne +from sympy.core.singleton import S +from sympy.core.sorting import ordered +from sympy.core.traversal import iterfreeargs + +from sympy.functions import exp, sin, cos, tan, cot, asin, atan +from sympy.functions import log, sinh, cosh, tanh, coth, asinh +from sympy.functions import sqrt, erf, erfi, li, Ei +from sympy.functions import besselj, bessely, besseli, besselk +from sympy.functions import hankel1, hankel2, jn, yn +from sympy.functions.elementary.complexes import Abs, re, im, sign, arg +from sympy.functions.elementary.exponential import LambertW +from sympy.functions.elementary.integers import floor, ceiling +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.delta_functions import Heaviside, DiracDelta + +from sympy.simplify.radsimp import collect + +from sympy.logic.boolalg import And, Or +from sympy.utilities.iterables import uniq + +from sympy.polys import quo, gcd, lcm, factor_list, cancel, PolynomialError +from sympy.polys.monomials import itermonomials +from sympy.polys.polyroots import root_factors + +from sympy.polys.rings import PolyRing +from sympy.polys.solvers import solve_lin_sys +from sympy.polys.constructor import construct_domain + +from sympy.integrals.integrals import integrate + + +def components(f, x): + """ + Returns a set of all functional components of the given expression + which includes symbols, function applications and compositions and + non-integer powers. Fractional powers are collected with + minimal, positive exponents. + + Examples + ======== + + >>> from sympy import cos, sin + >>> from sympy.abc import x + >>> from sympy.integrals.heurisch import components + + >>> components(sin(x)*cos(x)**2, x) + {x, sin(x), cos(x)} + + See Also + ======== + + heurisch + """ + result = set() + + if f.has_free(x): + if f.is_symbol and f.is_commutative: + result.add(f) + elif f.is_Function or f.is_Derivative: + for g in f.args: + result |= components(g, x) + + result.add(f) + elif f.is_Pow: + result |= components(f.base, x) + + if not f.exp.is_Integer: + if f.exp.is_Rational: + result.add(f.base**Rational(1, f.exp.q)) + else: + result |= components(f.exp, x) | {f} + else: + for g in f.args: + result |= components(g, x) + + return result + +# name -> [] of symbols +_symbols_cache: dict[str, list[Dummy]] = {} + + +# NB @cacheit is not convenient here +def _symbols(name, n): + """get vector of symbols local to this module""" + try: + lsyms = _symbols_cache[name] + except KeyError: + lsyms = [] + _symbols_cache[name] = lsyms + + while len(lsyms) < n: + lsyms.append( Dummy('%s%i' % (name, len(lsyms))) ) + + return lsyms[:n] + + +def heurisch_wrapper(f, x, rewrite=False, hints=None, mappings=None, retries=3, + degree_offset=0, unnecessary_permutations=None, + _try_heurisch=None): + """ + A wrapper around the heurisch integration algorithm. + + Explanation + =========== + + This method takes the result from heurisch and checks for poles in the + denominator. For each of these poles, the integral is reevaluated, and + the final integration result is given in terms of a Piecewise. + + Examples + ======== + + >>> from sympy import cos, symbols + >>> from sympy.integrals.heurisch import heurisch, heurisch_wrapper + >>> n, x = symbols('n x') + >>> heurisch(cos(n*x), x) + sin(n*x)/n + >>> heurisch_wrapper(cos(n*x), x) + Piecewise((sin(n*x)/n, Ne(n, 0)), (x, True)) + + See Also + ======== + + heurisch + """ + from sympy.solvers.solvers import solve, denoms + f = sympify(f) + if not f.has_free(x): + return f*x + + res = heurisch(f, x, rewrite, hints, mappings, retries, degree_offset, + unnecessary_permutations, _try_heurisch) + if not isinstance(res, Basic): + return res + + # We consider each denominator in the expression, and try to find + # cases where one or more symbolic denominator might be zero. The + # conditions for these cases are stored in the list slns. + # + # Since denoms returns a set we use ordered. This is important because the + # ordering of slns determines the order of the resulting Piecewise so we + # need a deterministic order here to make the output deterministic. + slns = [] + for d in ordered(denoms(res)): + try: + slns += solve([d], dict=True, exclude=(x,)) + except NotImplementedError: + pass + if not slns: + return res + slns = list(uniq(slns)) + # Remove the solutions corresponding to poles in the original expression. + slns0 = [] + for d in denoms(f): + try: + slns0 += solve([d], dict=True, exclude=(x,)) + except NotImplementedError: + pass + slns = [s for s in slns if s not in slns0] + if not slns: + return res + if len(slns) > 1: + eqs = [] + for sub_dict in slns: + eqs.extend([Eq(key, value) for key, value in sub_dict.items()]) + slns = solve(eqs, dict=True, exclude=(x,)) + slns + # For each case listed in the list slns, we reevaluate the integral. + pairs = [] + for sub_dict in slns: + expr = heurisch(f.subs(sub_dict), x, rewrite, hints, mappings, retries, + degree_offset, unnecessary_permutations, + _try_heurisch) + cond = And(*[Eq(key, value) for key, value in sub_dict.items()]) + generic = Or(*[Ne(key, value) for key, value in sub_dict.items()]) + if expr is None: + expr = integrate(f.subs(sub_dict),x) + pairs.append((expr, cond)) + # If there is one condition, put the generic case first. Otherwise, + # doing so may lead to longer Piecewise formulas + if len(pairs) == 1: + pairs = [(heurisch(f, x, rewrite, hints, mappings, retries, + degree_offset, unnecessary_permutations, + _try_heurisch), + generic), + (pairs[0][0], True)] + else: + pairs.append((heurisch(f, x, rewrite, hints, mappings, retries, + degree_offset, unnecessary_permutations, + _try_heurisch), + True)) + return Piecewise(*pairs) + +class BesselTable: + """ + Derivatives of Bessel functions of orders n and n-1 + in terms of each other. + + See the docstring of DiffCache. + """ + + def __init__(self): + self.table = {} + self.n = Dummy('n') + self.z = Dummy('z') + self._create_table() + + def _create_table(t): + table, n, z = t.table, t.n, t.z + for f in (besselj, bessely, hankel1, hankel2): + table[f] = (f(n-1, z) - n*f(n, z)/z, + (n-1)*f(n-1, z)/z - f(n, z)) + + f = besseli + table[f] = (f(n-1, z) - n*f(n, z)/z, + (n-1)*f(n-1, z)/z + f(n, z)) + f = besselk + table[f] = (-f(n-1, z) - n*f(n, z)/z, + (n-1)*f(n-1, z)/z - f(n, z)) + + for f in (jn, yn): + table[f] = (f(n-1, z) - (n+1)*f(n, z)/z, + (n-1)*f(n-1, z)/z - f(n, z)) + + def diffs(t, f, n, z): + if f in t.table: + diff0, diff1 = t.table[f] + repl = [(t.n, n), (t.z, z)] + return (diff0.subs(repl), diff1.subs(repl)) + + def has(t, f): + return f in t.table + +_bessel_table = None + +class DiffCache: + """ + Store for derivatives of expressions. + + Explanation + =========== + + The standard form of the derivative of a Bessel function of order n + contains two Bessel functions of orders n-1 and n+1, respectively. + Such forms cannot be used in parallel Risch algorithm, because + there is a linear recurrence relation between the three functions + while the algorithm expects that functions and derivatives are + represented in terms of algebraically independent transcendentals. + + The solution is to take two of the functions, e.g., those of orders + n and n-1, and to express the derivatives in terms of the pair. + To guarantee that the proper form is used the two derivatives are + cached as soon as one is encountered. + + Derivatives of other functions are also cached at no extra cost. + All derivatives are with respect to the same variable `x`. + """ + + def __init__(self, x): + self.cache = {} + self.x = x + + global _bessel_table + if not _bessel_table: + _bessel_table = BesselTable() + + def get_diff(self, f): + cache = self.cache + + if f in cache: + pass + elif (not hasattr(f, 'func') or + not _bessel_table.has(f.func)): + cache[f] = cancel(f.diff(self.x)) + else: + n, z = f.args + d0, d1 = _bessel_table.diffs(f.func, n, z) + dz = self.get_diff(z) + cache[f] = d0*dz + cache[f.func(n-1, z)] = d1*dz + + return cache[f] + +def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3, + degree_offset=0, unnecessary_permutations=None, + _try_heurisch=None): + """ + Compute indefinite integral using heuristic Risch algorithm. + + Explanation + =========== + + This is a heuristic approach to indefinite integration in finite + terms using the extended heuristic (parallel) Risch algorithm, based + on Manuel Bronstein's "Poor Man's Integrator". + + The algorithm supports various classes of functions including + transcendental elementary or special functions like Airy, + Bessel, Whittaker and Lambert. + + Note that this algorithm is not a decision procedure. If it isn't + able to compute the antiderivative for a given function, then this is + not a proof that such a functions does not exist. One should use + recursive Risch algorithm in such case. It's an open question if + this algorithm can be made a full decision procedure. + + This is an internal integrator procedure. You should use top level + 'integrate' function in most cases, as this procedure needs some + preprocessing steps and otherwise may fail. + + Specification + ============= + + heurisch(f, x, rewrite=False, hints=None) + + where + f : expression + x : symbol + + rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh' + hints -> a list of functions that may appear in anti-derivate + + - hints = None --> no suggestions at all + - hints = [ ] --> try to figure out + - hints = [f1, ..., fn] --> we know better + + Examples + ======== + + >>> from sympy import tan + >>> from sympy.integrals.heurisch import heurisch + >>> from sympy.abc import x, y + + >>> heurisch(y*tan(x), x) + y*log(tan(x)**2 + 1)/2 + + See Manuel Bronstein's "Poor Man's Integrator": + + References + ========== + + .. [1] https://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html + + For more information on the implemented algorithm refer to: + + .. [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration + Method and its Implementation in Maple, Proceedings of + ISSAC'89, ACM Press, 212-217. + + .. [3] J. H. Davenport, On the Parallel Risch Algorithm (I), + Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157. + + .. [4] J. H. Davenport, On the Parallel Risch Algorithm (III): + Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6. + + .. [5] J. H. Davenport, B. M. Trager, On the Parallel Risch + Algorithm (II), ACM Transactions on Mathematical + Software 11 (1985), 356-362. + + See Also + ======== + + sympy.integrals.integrals.Integral.doit + sympy.integrals.integrals.Integral + sympy.integrals.heurisch.components + """ + f = sympify(f) + + # There are some functions that Heurisch cannot currently handle, + # so do not even try. + # Set _try_heurisch=True to skip this check + if _try_heurisch is not True: + if f.has(Abs, re, im, sign, Heaviside, DiracDelta, floor, ceiling, arg): + return + + if not f.has_free(x): + return f*x + + if not f.is_Add: + indep, f = f.as_independent(x) + else: + indep = S.One + + rewritables = { + (sin, cos, cot): tan, + (sinh, cosh, coth): tanh, + } + + if rewrite: + for candidates, rule in rewritables.items(): + f = f.rewrite(candidates, rule) + else: + for candidates in rewritables.keys(): + if f.has(*candidates): + break + else: + rewrite = True + + terms = components(f, x) + dcache = DiffCache(x) + + if hints is not None: + if not hints: + a = Wild('a', exclude=[x]) + b = Wild('b', exclude=[x]) + c = Wild('c', exclude=[x]) + + for g in set(terms): # using copy of terms + if g.is_Function: + if isinstance(g, li): + M = g.args[0].match(a*x**b) + + if M is not None: + terms.add( x*(li(M[a]*x**M[b]) - (M[a]*x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) + #terms.add( x*(li(M[a]*x**M[b]) - (x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) + #terms.add( x*(li(M[a]*x**M[b]) - x*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) + #terms.add( li(M[a]*x**M[b]) - Ei((M[b]+1)*log(M[a]*x**M[b])/M[b]) ) + + elif isinstance(g, exp): + M = g.args[0].match(a*x**2) + + if M is not None: + if M[a].is_positive: + terms.add(erfi(sqrt(M[a])*x)) + else: # M[a].is_negative or unknown + terms.add(erf(sqrt(-M[a])*x)) + + M = g.args[0].match(a*x**2 + b*x + c) + + if M is not None: + if M[a].is_positive: + terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))* + erfi(sqrt(M[a])*x + M[b]/(2*sqrt(M[a])))) + elif M[a].is_negative: + terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))* + erf(sqrt(-M[a])*x - M[b]/(2*sqrt(-M[a])))) + + M = g.args[0].match(a*log(x)**2) + + if M is not None: + if M[a].is_positive: + terms.add(erfi(sqrt(M[a])*log(x) + 1/(2*sqrt(M[a])))) + if M[a].is_negative: + terms.add(erf(sqrt(-M[a])*log(x) - 1/(2*sqrt(-M[a])))) + + elif g.is_Pow: + if g.exp.is_Rational and g.exp.q == 2: + M = g.base.match(a*x**2 + b) + + if M is not None and M[b].is_positive: + if M[a].is_positive: + terms.add(asinh(sqrt(M[a]/M[b])*x)) + elif M[a].is_negative: + terms.add(asin(sqrt(-M[a]/M[b])*x)) + + M = g.base.match(a*x**2 - b) + + if M is not None and M[b].is_positive: + if M[a].is_positive: + dF = 1/sqrt(M[a]*x**2 - M[b]) + F = log(2*sqrt(M[a])*sqrt(M[a]*x**2 - M[b]) + 2*M[a]*x)/sqrt(M[a]) + dcache.cache[F] = dF # hack: F.diff(x) doesn't automatically simplify to f + terms.add(F) + elif M[a].is_negative: + terms.add(-M[b]/2*sqrt(-M[a])* + atan(sqrt(-M[a])*x/sqrt(M[a]*x**2 - M[b]))) + + else: + terms |= set(hints) + + for g in set(terms): # using copy of terms + terms |= components(dcache.get_diff(g), x) + + # XXX: The commented line below makes heurisch more deterministic wrt + # PYTHONHASHSEED and the iteration order of sets. There are other places + # where sets are iterated over but this one is possibly the most important. + # Theoretically the order here should not matter but different orderings + # can expose potential bugs in the different code paths so potentially it + # is better to keep the non-determinism. + # + # terms = list(ordered(terms)) + + # TODO: caching is significant factor for why permutations work at all. Change this. + V = _symbols('x', len(terms)) + + + # sort mapping expressions from largest to smallest (last is always x). + mapping = list(reversed(list(zip(*ordered( # + [(a[0].as_independent(x)[1], a) for a in zip(terms, V)])))[1])) # + rev_mapping = {v: k for k, v in mapping} # + if mappings is None: # + # optimizing the number of permutations of mapping # + assert mapping[-1][0] == x # if not, find it and correct this comment + unnecessary_permutations = [mapping.pop(-1)] + # permute types of objects + types = defaultdict(list) + for i in mapping: + e, _ = i + types[type(e)].append(i) + mapping = [types[i] for i in types] + def _iter_mappings(): + for i in permutations(mapping): + # make the expression of a given type be ordered + yield [j for i in i for j in ordered(i)] + mappings = _iter_mappings() + else: + unnecessary_permutations = unnecessary_permutations or [] + + def _substitute(expr): + return expr.subs(mapping) + + for mapping in mappings: + mapping = list(mapping) + mapping = mapping + unnecessary_permutations + diffs = [ _substitute(dcache.get_diff(g)) for g in terms ] + denoms = [ g.as_numer_denom()[1] for g in diffs ] + if all(h.is_polynomial(*V) for h in denoms) and _substitute(f).is_rational_function(*V): + denom = reduce(lambda p, q: lcm(p, q, *V), denoms) + break + else: + if not rewrite: + result = heurisch(f, x, rewrite=True, hints=hints, + unnecessary_permutations=unnecessary_permutations) + + if result is not None: + return indep*result + return None + + numers = [ cancel(denom*g) for g in diffs ] + def _derivation(h): + return Add(*[ d * h.diff(v) for d, v in zip(numers, V) ]) + + def _deflation(p): + for y in V: + if not p.has(y): + continue + + if _derivation(p) is not S.Zero: + c, q = p.as_poly(y).primitive() + return _deflation(c)*gcd(q, q.diff(y)).as_expr() + + return p + + def _splitter(p): + for y in V: + if not p.has(y): + continue + + if _derivation(y) is not S.Zero: + c, q = p.as_poly(y).primitive() + + q = q.as_expr() + + h = gcd(q, _derivation(q), y) + s = quo(h, gcd(q, q.diff(y), y), y) + + c_split = _splitter(c) + + if s.as_poly(y).degree() == 0: + return (c_split[0], q * c_split[1]) + + q_split = _splitter(cancel(q / s)) + + return (c_split[0]*q_split[0]*s, c_split[1]*q_split[1]) + + return (S.One, p) + + special = {} + + for term in terms: + if term.is_Function: + if isinstance(term, tan): + special[1 + _substitute(term)**2] = False + elif isinstance(term, tanh): + special[1 + _substitute(term)] = False + special[1 - _substitute(term)] = False + elif isinstance(term, LambertW): + special[_substitute(term)] = True + + F = _substitute(f) + + P, Q = F.as_numer_denom() + + u_split = _splitter(denom) + v_split = _splitter(Q) + + polys = set(list(v_split) + [ u_split[0] ] + list(special.keys())) + + s = u_split[0] * Mul(*[ k for k, v in special.items() if v ]) + polified = [ p.as_poly(*V) for p in [s, P, Q] ] + + if None in polified: + return None + + #--- definitions for _integrate + a, b, c = [ p.total_degree() for p in polified ] + + poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr() + + def _exponent(g): + if g.is_Pow: + if g.exp.is_Rational and g.exp.q != 1: + if g.exp.p > 0: + return g.exp.p + g.exp.q - 1 + else: + return abs(g.exp.p + g.exp.q) + else: + return 1 + elif not g.is_Atom and g.args: + return max(_exponent(h) for h in g.args) + else: + return 1 + + A, B = _exponent(f), a + max(b, c) + + if A > 1 and B > 1: + monoms = tuple(ordered(itermonomials(V, A + B - 1 + degree_offset))) + else: + monoms = tuple(ordered(itermonomials(V, A + B + degree_offset))) + + poly_coeffs = _symbols('A', len(monoms)) + + poly_part = Add(*[ poly_coeffs[i]*monomial + for i, monomial in enumerate(monoms) ]) + + reducibles = set() + + for poly in ordered(polys): + coeff, factors = factor_list(poly, *V) + reducibles.add(coeff) + reducibles.update(fact for fact, mul in factors) + + def _integrate(field=None): + atans = set() + pairs = set() + + if field == 'Q': + irreducibles = set(reducibles) + else: + setV = set(V) + irreducibles = set() + for poly in ordered(reducibles): + zV = setV & set(iterfreeargs(poly)) + for z in ordered(zV): + s = set(root_factors(poly, z, filter=field)) + irreducibles |= s + break + + log_part, atan_part = [], [] + + for poly in ordered(irreducibles): + m = collect(poly, I, evaluate=False) + y = m.get(I, S.Zero) + if y: + x = m.get(S.One, S.Zero) + if x.has(I) or y.has(I): + continue # nontrivial x + I*y + pairs.add((x, y)) + irreducibles.remove(poly) + + while pairs: + x, y = pairs.pop() + if (x, -y) in pairs: + pairs.remove((x, -y)) + # Choosing b with no minus sign + if y.could_extract_minus_sign(): + y = -y + irreducibles.add(x*x + y*y) + atans.add(atan(x/y)) + else: + irreducibles.add(x + I*y) + + + B = _symbols('B', len(irreducibles)) + C = _symbols('C', len(atans)) + + # Note: the ordering matters here + for poly, b in reversed(list(zip(ordered(irreducibles), B))): + if poly.has(*V): + poly_coeffs.append(b) + log_part.append(b * log(poly)) + + for poly, c in reversed(list(zip(ordered(atans), C))): + if poly.has(*V): + poly_coeffs.append(c) + atan_part.append(c * poly) + + # TODO: Currently it's better to use symbolic expressions here instead + # of rational functions, because it's simpler and FracElement doesn't + # give big speed improvement yet. This is because cancellation is slow + # due to slow polynomial GCD algorithms. If this gets improved then + # revise this code. + candidate = poly_part/poly_denom + Add(*log_part) + Add(*atan_part) + h = F - _derivation(candidate) / denom + raw_numer = h.as_numer_denom()[0] + + # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field + # that we have to determine. We can't use simply atoms() because log(3), + # sqrt(y) and similar expressions can appear, leading to non-trivial + # domains. + syms = set(poly_coeffs) | set(V) + non_syms = set() + + def find_non_syms(expr): + if expr.is_Integer or expr.is_Rational: + pass # ignore trivial numbers + elif expr in syms: + pass # ignore variables + elif not expr.has_free(*syms): + non_syms.add(expr) + elif expr.is_Add or expr.is_Mul or expr.is_Pow: + list(map(find_non_syms, expr.args)) + else: + # TODO: Non-polynomial expression. This should have been + # filtered out at an earlier stage. + raise PolynomialError + + try: + find_non_syms(raw_numer) + except PolynomialError: + return None + else: + ground, _ = construct_domain(non_syms, field=True) + + coeff_ring = PolyRing(poly_coeffs, ground) + ring = PolyRing(V, coeff_ring) + try: + numer = ring.from_expr(raw_numer) + except ValueError: + raise PolynomialError + solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False) + + if solution is None: + return None + else: + return candidate.xreplace(solution).xreplace( + dict(zip(poly_coeffs, [S.Zero]*len(poly_coeffs)))) + + if all(isinstance(_, Symbol) for _ in V): + more_free = F.free_symbols - set(V) + else: + Fd = F.as_dummy() + more_free = Fd.xreplace(dict(zip(V, (Dummy() for _ in V))) + ).free_symbols & Fd.free_symbols + if not more_free: + # all free generators are identified in V + solution = _integrate('Q') + + if solution is None: + solution = _integrate() + else: + solution = _integrate() + + if solution is not None: + antideriv = solution.subs(rev_mapping) + antideriv = cancel(antideriv).expand() + + if antideriv.is_Add: + antideriv = antideriv.as_independent(x)[1] + + return indep*antideriv + else: + if retries >= 0: + result = heurisch(f, x, mappings=mappings, rewrite=rewrite, hints=hints, retries=retries - 1, unnecessary_permutations=unnecessary_permutations) + + if result is not None: + return indep*result + + return None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/integrals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/integrals.py new file mode 100644 index 0000000000000000000000000000000000000000..b9ed4a22802acc455f5162e109fc575223c97338 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/integrals.py @@ -0,0 +1,1640 @@ +from __future__ import annotations + +from sympy.concrete.expr_with_limits import AddWithLimits +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.exprtools import factor_terms +from sympy.core.function import diff +from sympy.core.logic import fuzzy_bool +from sympy.core.mul import Mul +from sympy.core.numbers import oo, pi +from sympy.core.relational import Ne +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, Wild) +from sympy.core.sympify import sympify +from sympy.functions import Piecewise, sqrt, piecewise_fold, tan, cot, atan +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.complexes import Abs, sign +from sympy.functions.elementary.miscellaneous import Min, Max +from sympy.functions.special.singularity_functions import Heaviside +from .rationaltools import ratint +from sympy.matrices import MatrixBase +from sympy.polys import Poly, PolynomialError +from sympy.series.formal import FormalPowerSeries +from sympy.series.limits import limit +from sympy.series.order import Order +from sympy.tensor.functions import shape +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import is_sequence +from sympy.utilities.misc import filldedent + + +class Integral(AddWithLimits): + """Represents unevaluated integral.""" + + __slots__ = () + + args: tuple[Expr, Tuple] # type: ignore + + def __new__(cls, function, *symbols, **assumptions) -> Integral: + """Create an unevaluated integral. + + Explanation + =========== + + Arguments are an integrand followed by one or more limits. + + If no limits are given and there is only one free symbol in the + expression, that symbol will be used, otherwise an error will be + raised. + + >>> from sympy import Integral + >>> from sympy.abc import x, y + >>> Integral(x) + Integral(x, x) + >>> Integral(y) + Integral(y, y) + + When limits are provided, they are interpreted as follows (using + ``x`` as though it were the variable of integration): + + (x,) or x - indefinite integral + (x, a) - "evaluate at" integral is an abstract antiderivative + (x, a, b) - definite integral + + The ``as_dummy`` method can be used to see which symbols cannot be + targeted by subs: those with a prepended underscore cannot be + changed with ``subs``. (Also, the integration variables themselves -- + the first element of a limit -- can never be changed by subs.) + + >>> i = Integral(x, x) + >>> at = Integral(x, (x, x)) + >>> i.as_dummy() + Integral(x, x) + >>> at.as_dummy() + Integral(_0, (_0, x)) + + """ + + #This will help other classes define their own definitions + #of behaviour with Integral. + if hasattr(function, '_eval_Integral'): + return function._eval_Integral(*symbols, **assumptions) + + if isinstance(function, Poly): + sympy_deprecation_warning( + """ + integrate(Poly) and Integral(Poly) are deprecated. Instead, + use the Poly.integrate() method, or convert the Poly to an + Expr first with the Poly.as_expr() method. + """, + deprecated_since_version="1.6", + active_deprecations_target="deprecated-integrate-poly") + + obj = AddWithLimits.__new__(cls, function, *symbols, **assumptions) + return obj + + def __getnewargs__(self): + return (self.function,) + tuple([tuple(xab) for xab in self.limits]) + + @property + def free_symbols(self): + """ + This method returns the symbols that will exist when the + integral is evaluated. This is useful if one is trying to + determine whether an integral depends on a certain + symbol or not. + + Examples + ======== + + >>> from sympy import Integral + >>> from sympy.abc import x, y + >>> Integral(x, (x, y, 1)).free_symbols + {y} + + See Also + ======== + + sympy.concrete.expr_with_limits.ExprWithLimits.function + sympy.concrete.expr_with_limits.ExprWithLimits.limits + sympy.concrete.expr_with_limits.ExprWithLimits.variables + """ + return super().free_symbols + + def _eval_is_zero(self): + # This is a very naive and quick test, not intended to do the integral to + # answer whether it is zero or not, e.g. Integral(sin(x), (x, 0, 2*pi)) + # is zero but this routine should return None for that case. But, like + # Mul, there are trivial situations for which the integral will be + # zero so we check for those. + if self.function.is_zero: + return True + got_none = False + for l in self.limits: + if len(l) == 3: + z = (l[1] == l[2]) or (l[1] - l[2]).is_zero + if z: + return True + elif z is None: + got_none = True + free = self.function.free_symbols + for xab in self.limits: + if len(xab) == 1: + free.add(xab[0]) + continue + if len(xab) == 2 and xab[0] not in free: + if xab[1].is_zero: + return True + elif xab[1].is_zero is None: + got_none = True + # take integration symbol out of free since it will be replaced + # with the free symbols in the limits + free.discard(xab[0]) + # add in the new symbols + for i in xab[1:]: + free.update(i.free_symbols) + if self.function.is_zero is False and got_none is False: + return False + + def transform(self, x, u): + r""" + Performs a change of variables from `x` to `u` using the relationship + given by `x` and `u` which will define the transformations `f` and `F` + (which are inverses of each other) as follows: + + 1) If `x` is a Symbol (which is a variable of integration) then `u` + will be interpreted as some function, f(u), with inverse F(u). + This, in effect, just makes the substitution of x with f(x). + + 2) If `u` is a Symbol then `x` will be interpreted as some function, + F(x), with inverse f(u). This is commonly referred to as + u-substitution. + + Once f and F have been identified, the transformation is made as + follows: + + .. math:: \int_a^b x \mathrm{d}x \rightarrow \int_{F(a)}^{F(b)} f(x) + \frac{\mathrm{d}}{\mathrm{d}x} + + where `F(x)` is the inverse of `f(x)` and the limits and integrand have + been corrected so as to retain the same value after integration. + + Notes + ===== + + The mappings, F(x) or f(u), must lead to a unique integral. Linear + or rational linear expression, ``2*x``, ``1/x`` and ``sqrt(x)``, will + always work; quadratic expressions like ``x**2 - 1`` are acceptable + as long as the resulting integrand does not depend on the sign of + the solutions (see examples). + + The integral will be returned unchanged if ``x`` is not a variable of + integration. + + ``x`` must be (or contain) only one of of the integration variables. If + ``u`` has more than one free symbol then it should be sent as a tuple + (``u``, ``uvar``) where ``uvar`` identifies which variable is replacing + the integration variable. + XXX can it contain another integration variable? + + Examples + ======== + + >>> from sympy.abc import a, x, u + >>> from sympy import Integral, cos, sqrt + + >>> i = Integral(x*cos(x**2 - 1), (x, 0, 1)) + + transform can change the variable of integration + + >>> i.transform(x, u) + Integral(u*cos(u**2 - 1), (u, 0, 1)) + + transform can perform u-substitution as long as a unique + integrand is obtained: + + >>> ui = i.transform(x**2 - 1, u) + >>> ui + Integral(cos(u)/2, (u, -1, 0)) + + This attempt fails because x = +/-sqrt(u + 1) and the + sign does not cancel out of the integrand: + + >>> Integral(cos(x**2 - 1), (x, 0, 1)).transform(x**2 - 1, u) + Traceback (most recent call last): + ... + ValueError: + The mapping between F(x) and f(u) did not give a unique integrand. + + transform can do a substitution. Here, the previous + result is transformed back into the original expression + using "u-substitution": + + >>> ui.transform(sqrt(u + 1), x) == i + True + + We can accomplish the same with a regular substitution: + + >>> ui.transform(u, x**2 - 1) == i + True + + If the `x` does not contain a symbol of integration then + the integral will be returned unchanged. Integral `i` does + not have an integration variable `a` so no change is made: + + >>> i.transform(a, x) == i + True + + When `u` has more than one free symbol the symbol that is + replacing `x` must be identified by passing `u` as a tuple: + + >>> Integral(x, (x, 0, 1)).transform(x, (u + a, u)) + Integral(a + u, (u, -a, 1 - a)) + >>> Integral(x, (x, 0, 1)).transform(x, (u + a, a)) + Integral(a + u, (a, -u, 1 - u)) + + See Also + ======== + + sympy.concrete.expr_with_limits.ExprWithLimits.variables : Lists the integration variables + as_dummy : Replace integration variables with dummy ones + """ + d = Dummy('d') + + xfree = x.free_symbols.intersection(self.variables) + if len(xfree) > 1: + raise ValueError( + 'F(x) can only contain one of: %s' % self.variables) + xvar = xfree.pop() if xfree else d + + if xvar not in self.variables: + return self + + u = sympify(u) + if isinstance(u, Expr): + ufree = u.free_symbols + if len(ufree) == 0: + raise ValueError(filldedent(''' + f(u) cannot be a constant''')) + if len(ufree) > 1: + raise ValueError(filldedent(''' + When f(u) has more than one free symbol, the one replacing x + must be identified: pass f(u) as (f(u), u)''')) + uvar = ufree.pop() + else: + u, uvar = u + if uvar not in u.free_symbols: + raise ValueError(filldedent(''' + Expecting a tuple (expr, symbol) where symbol identified + a free symbol in expr, but symbol is not in expr's free + symbols.''')) + if not isinstance(uvar, Symbol): + # This probably never evaluates to True + raise ValueError(filldedent(''' + Expecting a tuple (expr, symbol) but didn't get + a symbol; got %s''' % uvar)) + + if x.is_Symbol and u.is_Symbol: + return self.xreplace({x: u}) + + if not x.is_Symbol and not u.is_Symbol: + raise ValueError('either x or u must be a symbol') + + if uvar == xvar: + return self.transform(x, (u.subs(uvar, d), d)).xreplace({d: uvar}) + + if uvar in self.limits: + raise ValueError(filldedent(''' + u must contain the same variable as in x + or a variable that is not already an integration variable''')) + + from sympy.solvers.solvers import solve + if not x.is_Symbol: + F = [x.subs(xvar, d)] + soln = solve(u - x, xvar, check=False) + if not soln: + raise ValueError('no solution for solve(F(x) - f(u), x)') + f = [fi.subs(uvar, d) for fi in soln] + else: + f = [u.subs(uvar, d)] + from sympy.simplify.simplify import posify + pdiff, reps = posify(u - x) + puvar = uvar.subs([(v, k) for k, v in reps.items()]) + soln = [s.subs(reps) for s in solve(pdiff, puvar)] + if not soln: + raise ValueError('no solution for solve(F(x) - f(u), u)') + F = [fi.subs(xvar, d) for fi in soln] + + newfuncs = {(self.function.subs(xvar, fi)*fi.diff(d) + ).subs(d, uvar) for fi in f} + if len(newfuncs) > 1: + raise ValueError(filldedent(''' + The mapping between F(x) and f(u) did not give + a unique integrand.''')) + newfunc = newfuncs.pop() + + def _calc_limit_1(F, a, b): + """ + replace d with a, using subs if possible, otherwise limit + where sign of b is considered + """ + wok = F.subs(d, a) + if wok is S.NaN or wok.is_finite is False and a.is_finite: + return limit(sign(b)*F, d, a) + return wok + + def _calc_limit(a, b): + """ + replace d with a, using subs if possible, otherwise limit + where sign of b is considered + """ + avals = list({_calc_limit_1(Fi, a, b) for Fi in F}) + if len(avals) > 1: + raise ValueError(filldedent(''' + The mapping between F(x) and f(u) did not + give a unique limit.''')) + return avals[0] + + newlimits = [] + for xab in self.limits: + sym = xab[0] + if sym == xvar: + if len(xab) == 3: + a, b = xab[1:] + a, b = _calc_limit(a, b), _calc_limit(b, a) + if fuzzy_bool(a - b > 0): + a, b = b, a + newfunc = -newfunc + newlimits.append((uvar, a, b)) + elif len(xab) == 2: + a = _calc_limit(xab[1], 1) + newlimits.append((uvar, a)) + else: + newlimits.append(uvar) + else: + newlimits.append(xab) + + return self.func(newfunc, *newlimits) + + def doit(self, **hints): + """ + Perform the integration using any hints given. + + Examples + ======== + + >>> from sympy import Piecewise, S + >>> from sympy.abc import x, t + >>> p = x**2 + Piecewise((0, x/t < 0), (1, True)) + >>> p.integrate((t, S(4)/5, 1), (x, -1, 1)) + 1/3 + + See Also + ======== + + sympy.integrals.trigonometry.trigintegrate + sympy.integrals.heurisch.heurisch + sympy.integrals.rationaltools.ratint + as_sum : Approximate the integral using a sum + """ + if not hints.get('integrals', True): + return self + + deep = hints.get('deep', True) + meijerg = hints.get('meijerg', None) + conds = hints.get('conds', 'piecewise') + risch = hints.get('risch', None) + heurisch = hints.get('heurisch', None) + manual = hints.get('manual', None) + if len(list(filter(None, (manual, meijerg, risch, heurisch)))) > 1: + raise ValueError("At most one of manual, meijerg, risch, heurisch can be True") + elif manual: + meijerg = risch = heurisch = False + elif meijerg: + manual = risch = heurisch = False + elif risch: + manual = meijerg = heurisch = False + elif heurisch: + manual = meijerg = risch = False + eval_kwargs = {"meijerg": meijerg, "risch": risch, "manual": manual, "heurisch": heurisch, + "conds": conds} + + if conds not in ('separate', 'piecewise', 'none'): + raise ValueError('conds must be one of "separate", "piecewise", ' + '"none", got: %s' % conds) + + if risch and any(len(xab) > 1 for xab in self.limits): + raise ValueError('risch=True is only allowed for indefinite integrals.') + + # check for the trivial zero + if self.is_zero: + return S.Zero + + # hacks to handle integrals of + # nested summations + from sympy.concrete.summations import Sum + if isinstance(self.function, Sum): + if any(v in self.function.limits[0] for v in self.variables): + raise ValueError('Limit of the sum cannot be an integration variable.') + if any(l.is_infinite for l in self.function.limits[0][1:]): + return self + _i = self + _sum = self.function + return _sum.func(_i.func(_sum.function, *_i.limits).doit(), *_sum.limits).doit() + + # now compute and check the function + function = self.function + + # hack to use a consistent Heaviside(x, 1/2) + function = function.replace( + lambda x: isinstance(x, Heaviside) and x.args[1]*2 != 1, + lambda x: Heaviside(x.args[0])) + + if deep: + function = function.doit(**hints) + if function.is_zero: + return S.Zero + + # hacks to handle special cases + if isinstance(function, MatrixBase): + return function.applyfunc( + lambda f: self.func(f, *self.limits).doit(**hints)) + + if isinstance(function, FormalPowerSeries): + if len(self.limits) > 1: + raise NotImplementedError + xab = self.limits[0] + if len(xab) > 1: + return function.integrate(xab, **eval_kwargs) + else: + return function.integrate(xab[0], **eval_kwargs) + + # There is no trivial answer and special handling + # is done so continue + + # first make sure any definite limits have integration + # variables with matching assumptions + reps = {} + for xab in self.limits: + if len(xab) != 3: + # it makes sense to just make + # all x real but in practice with the + # current state of integration...this + # doesn't work out well + # x = xab[0] + # if x not in reps and not x.is_real: + # reps[x] = Dummy(real=True) + continue + x, a, b = xab + l = (a, b) + if all(i.is_nonnegative for i in l) and not x.is_nonnegative: + d = Dummy(positive=True) + elif all(i.is_nonpositive for i in l) and not x.is_nonpositive: + d = Dummy(negative=True) + elif all(i.is_real for i in l) and not x.is_real: + d = Dummy(real=True) + else: + d = None + if d: + reps[x] = d + if reps: + undo = {v: k for k, v in reps.items()} + did = self.xreplace(reps).doit(**hints) + if isinstance(did, tuple): # when separate=True + did = tuple([i.xreplace(undo) for i in did]) + else: + did = did.xreplace(undo) + return did + + # continue with existing assumptions + undone_limits = [] + # ulj = free symbols of any undone limits' upper and lower limits + ulj = set() + for xab in self.limits: + # compute uli, the free symbols in the + # Upper and Lower limits of limit I + if len(xab) == 1: + uli = set(xab[:1]) + elif len(xab) == 2: + uli = xab[1].free_symbols + elif len(xab) == 3: + uli = xab[1].free_symbols.union(xab[2].free_symbols) + # this integral can be done as long as there is no blocking + # limit that has been undone. An undone limit is blocking if + # it contains an integration variable that is in this limit's + # upper or lower free symbols or vice versa + if xab[0] in ulj or any(v[0] in uli for v in undone_limits): + undone_limits.append(xab) + ulj.update(uli) + function = self.func(*([function] + [xab])) + factored_function = function.factor() + if not isinstance(factored_function, Integral): + function = factored_function + continue + + if function.has(Abs, sign) and ( + (len(xab) < 3 and all(x.is_extended_real for x in xab)) or + (len(xab) == 3 and all(x.is_extended_real and not x.is_infinite for + x in xab[1:]))): + # some improper integrals are better off with Abs + xr = Dummy("xr", real=True) + function = (function.xreplace({xab[0]: xr}) + .rewrite(Piecewise).xreplace({xr: xab[0]})) + elif function.has(Min, Max): + function = function.rewrite(Piecewise) + if (function.has(Piecewise) and + not isinstance(function, Piecewise)): + function = piecewise_fold(function) + if isinstance(function, Piecewise): + if len(xab) == 1: + antideriv = function._eval_integral(xab[0], + **eval_kwargs) + else: + antideriv = self._eval_integral( + function, xab[0], **eval_kwargs) + else: + # There are a number of tradeoffs in using the + # Meijer G method. It can sometimes be a lot faster + # than other methods, and sometimes slower. And + # there are certain types of integrals for which it + # is more likely to work than others. These + # heuristics are incorporated in deciding what + # integration methods to try, in what order. See the + # integrate() docstring for details. + def try_meijerg(function, xab): + ret = None + if len(xab) == 3 and meijerg is not False: + x, a, b = xab + try: + res = meijerint_definite(function, x, a, b) + except NotImplementedError: + _debug('NotImplementedError ' + 'from meijerint_definite') + res = None + if res is not None: + f, cond = res + if conds == 'piecewise': + u = self.func(function, (x, a, b)) + # if Piecewise modifies cond too + # much it may not be recognized by + # _condsimp pattern matching so just + # turn off all evaluation + return Piecewise((f, cond), (u, True), + evaluate=False) + elif conds == 'separate': + if len(self.limits) != 1: + raise ValueError(filldedent(''' + conds=separate not supported in + multiple integrals''')) + ret = f, cond + else: + ret = f + return ret + + meijerg1 = meijerg + if (meijerg is not False and + len(xab) == 3 and xab[1].is_extended_real and xab[2].is_extended_real + and not function.is_Poly and + (xab[1].has(oo, -oo) or xab[2].has(oo, -oo))): + ret = try_meijerg(function, xab) + if ret is not None: + function = ret + continue + meijerg1 = False + # If the special meijerg code did not succeed in + # finding a definite integral, then the code using + # meijerint_indefinite will not either (it might + # find an antiderivative, but the answer is likely + # to be nonsensical). Thus if we are requested to + # only use Meijer G-function methods, we give up at + # this stage. Otherwise we just disable G-function + # methods. + if meijerg1 is False and meijerg is True: + antideriv = None + else: + antideriv = self._eval_integral( + function, xab[0], **eval_kwargs) + if antideriv is None and meijerg is True: + ret = try_meijerg(function, xab) + if ret is not None: + function = ret + continue + + final = hints.get('final', True) + # dotit may be iterated but floor terms making atan and acot + # continuous should only be added in the final round + if (final and not isinstance(antideriv, Integral) and + antideriv is not None): + for atan_term in antideriv.atoms(atan): + atan_arg = atan_term.args[0] + # Checking `atan_arg` to be linear combination of `tan` or `cot` + for tan_part in atan_arg.atoms(tan): + x1 = Dummy('x1') + tan_exp1 = atan_arg.subs(tan_part, x1) + # The coefficient of `tan` should be constant + coeff = tan_exp1.diff(x1) + if x1 not in coeff.free_symbols: + a = tan_part.args[0] + antideriv = antideriv.subs(atan_term, Add(atan_term, + sign(coeff)*pi*floor((a-pi/2)/pi))) + for cot_part in atan_arg.atoms(cot): + x1 = Dummy('x1') + cot_exp1 = atan_arg.subs(cot_part, x1) + # The coefficient of `cot` should be constant + coeff = cot_exp1.diff(x1) + if x1 not in coeff.free_symbols: + a = cot_part.args[0] + antideriv = antideriv.subs(atan_term, Add(atan_term, + sign(coeff)*pi*floor((a)/pi))) + + if antideriv is None: + undone_limits.append(xab) + function = self.func(*([function] + [xab])).factor() + factored_function = function.factor() + if not isinstance(factored_function, Integral): + function = factored_function + continue + else: + if len(xab) == 1: + function = antideriv + else: + if len(xab) == 3: + x, a, b = xab + elif len(xab) == 2: + x, b = xab + a = None + else: + raise NotImplementedError + + if deep: + if isinstance(a, Basic): + a = a.doit(**hints) + if isinstance(b, Basic): + b = b.doit(**hints) + + if antideriv.is_Poly: + gens = list(antideriv.gens) + gens.remove(x) + + antideriv = antideriv.as_expr() + + function = antideriv._eval_interval(x, a, b) + function = Poly(function, *gens) + else: + def is_indef_int(g, x): + return (isinstance(g, Integral) and + any(i == (x,) for i in g.limits)) + + def eval_factored(f, x, a, b): + # _eval_interval for integrals with + # (constant) factors + # a single indefinite integral is assumed + args = [] + for g in Mul.make_args(f): + if is_indef_int(g, x): + args.append(g._eval_interval(x, a, b)) + else: + args.append(g) + return Mul(*args) + + integrals, others, piecewises = [], [], [] + for f in Add.make_args(antideriv): + if any(is_indef_int(g, x) + for g in Mul.make_args(f)): + integrals.append(f) + elif any(isinstance(g, Piecewise) + for g in Mul.make_args(f)): + piecewises.append(piecewise_fold(f)) + else: + others.append(f) + uneval = Add(*[eval_factored(f, x, a, b) + for f in integrals]) + try: + evalued = Add(*others)._eval_interval(x, a, b) + evalued_pw = piecewise_fold(Add(*piecewises))._eval_interval(x, a, b) + function = uneval + evalued + evalued_pw + except NotImplementedError: + # This can happen if _eval_interval depends in a + # complicated way on limits that cannot be computed + undone_limits.append(xab) + function = self.func(*([function] + [xab])) + factored_function = function.factor() + if not isinstance(factored_function, Integral): + function = factored_function + return function + + def _eval_derivative(self, sym): + """Evaluate the derivative of the current Integral object by + differentiating under the integral sign [1], using the Fundamental + Theorem of Calculus [2] when possible. + + Explanation + =========== + + Whenever an Integral is encountered that is equivalent to zero or + has an integrand that is independent of the variable of integration + those integrals are performed. All others are returned as Integral + instances which can be resolved with doit() (provided they are integrable). + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Differentiation_under_the_integral_sign + .. [2] https://en.wikipedia.org/wiki/Fundamental_theorem_of_calculus + + Examples + ======== + + >>> from sympy import Integral + >>> from sympy.abc import x, y + >>> i = Integral(x + y, y, (y, 1, x)) + >>> i.diff(x) + Integral(x + y, (y, x)) + Integral(1, y, (y, 1, x)) + >>> i.doit().diff(x) == i.diff(x).doit() + True + >>> i.diff(y) + 0 + + The previous must be true since there is no y in the evaluated integral: + + >>> i.free_symbols + {x} + >>> i.doit() + 2*x**3/3 - x/2 - 1/6 + + """ + + # differentiate under the integral sign; we do not + # check for regularity conditions (TODO), see issue 4215 + + # get limits and the function + f, limits = self.function, list(self.limits) + + # the order matters if variables of integration appear in the limits + # so work our way in from the outside to the inside. + limit = limits.pop(-1) + if len(limit) == 3: + x, a, b = limit + elif len(limit) == 2: + x, b = limit + a = None + else: + a = b = None + x = limit[0] + + if limits: # f is the argument to an integral + f = self.func(f, *tuple(limits)) + + # assemble the pieces + def _do(f, ab): + dab_dsym = diff(ab, sym) + if not dab_dsym: + return S.Zero + if isinstance(f, Integral): + limits = [(x, x) if (len(l) == 1 and l[0] == x) else l + for l in f.limits] + f = self.func(f.function, *limits) + return f.subs(x, ab)*dab_dsym + + rv = S.Zero + if b is not None: + rv += _do(f, b) + if a is not None: + rv -= _do(f, a) + if len(limit) == 1 and sym == x: + # the dummy variable *is* also the real-world variable + arg = f + rv += arg + else: + # the dummy variable might match sym but it's + # only a dummy and the actual variable is determined + # by the limits, so mask off the variable of integration + # while differentiating + u = Dummy('u') + arg = f.subs(x, u).diff(sym).subs(u, x) + if arg: + rv += self.func(arg, (x, a, b)) + return rv + + def _eval_integral(self, f, x, meijerg=None, risch=None, manual=None, + heurisch=None, conds='piecewise',final=None): + """ + Calculate the anti-derivative to the function f(x). + + Explanation + =========== + + The following algorithms are applied (roughly in this order): + + 1. Simple heuristics (based on pattern matching and integral table): + + - most frequently used functions (e.g. polynomials, products of + trig functions) + + 2. Integration of rational functions: + + - A complete algorithm for integrating rational functions is + implemented (the Lazard-Rioboo-Trager algorithm). The algorithm + also uses the partial fraction decomposition algorithm + implemented in apart() as a preprocessor to make this process + faster. Note that the integral of a rational function is always + elementary, but in general, it may include a RootSum. + + 3. Full Risch algorithm: + + - The Risch algorithm is a complete decision + procedure for integrating elementary functions, which means that + given any elementary function, it will either compute an + elementary antiderivative, or else prove that none exists. + Currently, part of transcendental case is implemented, meaning + elementary integrals containing exponentials, logarithms, and + (soon!) trigonometric functions can be computed. The algebraic + case, e.g., functions containing roots, is much more difficult + and is not implemented yet. + + - If the routine fails (because the integrand is not elementary, or + because a case is not implemented yet), it continues on to the + next algorithms below. If the routine proves that the integrals + is nonelementary, it still moves on to the algorithms below, + because we might be able to find a closed-form solution in terms + of special functions. If risch=True, however, it will stop here. + + 4. The Meijer G-Function algorithm: + + - This algorithm works by first rewriting the integrand in terms of + very general Meijer G-Function (meijerg in SymPy), integrating + it, and then rewriting the result back, if possible. This + algorithm is particularly powerful for definite integrals (which + is actually part of a different method of Integral), since it can + compute closed-form solutions of definite integrals even when no + closed-form indefinite integral exists. But it also is capable + of computing many indefinite integrals as well. + + - Another advantage of this method is that it can use some results + about the Meijer G-Function to give a result in terms of a + Piecewise expression, which allows to express conditionally + convergent integrals. + + - Setting meijerg=True will cause integrate() to use only this + method. + + 5. The "manual integration" algorithm: + + - This algorithm tries to mimic how a person would find an + antiderivative by hand, for example by looking for a + substitution or applying integration by parts. This algorithm + does not handle as many integrands but can return results in a + more familiar form. + + - Sometimes this algorithm can evaluate parts of an integral; in + this case integrate() will try to evaluate the rest of the + integrand using the other methods here. + + - Setting manual=True will cause integrate() to use only this + method. + + 6. The Heuristic Risch algorithm: + + - This is a heuristic version of the Risch algorithm, meaning that + it is not deterministic. This is tried as a last resort because + it can be very slow. It is still used because not enough of the + full Risch algorithm is implemented, so that there are still some + integrals that can only be computed using this method. The goal + is to implement enough of the Risch and Meijer G-function methods + so that this can be deleted. + + Setting heurisch=True will cause integrate() to use only this + method. Set heurisch=False to not use it. + + """ + + from sympy.integrals.risch import risch_integrate, NonElementaryIntegral + from sympy.integrals.manualintegrate import manualintegrate + + if risch: + try: + return risch_integrate(f, x, conds=conds) + except NotImplementedError: + return None + + if manual: + try: + result = manualintegrate(f, x) + if result is not None and result.func != Integral: + return result + except (ValueError, PolynomialError): + pass + + eval_kwargs = {"meijerg": meijerg, "risch": risch, "manual": manual, + "heurisch": heurisch, "conds": conds} + + # if it is a poly(x) then let the polynomial integrate itself (fast) + # + # It is important to make this check first, otherwise the other code + # will return a SymPy expression instead of a Polynomial. + # + # see Polynomial for details. + if isinstance(f, Poly) and not (manual or meijerg or risch): + # Note: this is deprecated, but the deprecation warning is already + # issued in the Integral constructor. + return f.integrate(x) + + # Piecewise antiderivatives need to call special integrate. + if isinstance(f, Piecewise): + return f.piecewise_integrate(x, **eval_kwargs) + + # let's cut it short if `f` does not depend on `x`; if + # x is only a dummy, that will be handled below + if not f.has(x): + return f*x + + # try to convert to poly(x) and then integrate if successful (fast) + poly = f.as_poly(x) + if poly is not None and not (manual or meijerg or risch): + return poly.integrate().as_expr() + + if risch is not False: + try: + result, i = risch_integrate(f, x, separate_integral=True, + conds=conds) + except NotImplementedError: + pass + else: + if i: + # There was a nonelementary integral. Try integrating it. + + # if no part of the NonElementaryIntegral is integrated by + # the Risch algorithm, then use the original function to + # integrate, instead of re-written one + if result == 0: + return NonElementaryIntegral(f, x).doit(risch=False) + else: + return result + i.doit(risch=False) + else: + return result + + # since Integral(f=g1+g2+...) == Integral(g1) + Integral(g2) + ... + # we are going to handle Add terms separately, + # if `f` is not Add -- we only have one term + + # Note that in general, this is a bad idea, because Integral(g1) + + # Integral(g2) might not be computable, even if Integral(g1 + g2) is. + # For example, Integral(x**x + x**x*log(x)). But many heuristics only + # work term-wise. So we compute this step last, after trying + # risch_integrate. We also try risch_integrate again in this loop, + # because maybe the integral is a sum of an elementary part and a + # nonelementary part (like erf(x) + exp(x)). risch_integrate() is + # quite fast, so this is acceptable. + from sympy.simplify.fu import sincos_to_sum + parts = [] + args = Add.make_args(f) + for g in args: + coeff, g = g.as_independent(x) + + # g(x) = const + if g is S.One and not meijerg: + parts.append(coeff*x) + continue + + # g(x) = expr + O(x**n) + order_term = g.getO() + + if order_term is not None: + h = self._eval_integral(g.removeO(), x, **eval_kwargs) + + if h is not None: + h_order_expr = self._eval_integral(order_term.expr, x, **eval_kwargs) + + if h_order_expr is not None: + h_order_term = order_term.func( + h_order_expr, *order_term.variables) + parts.append(coeff*(h + h_order_term)) + continue + + # NOTE: if there is O(x**n) and we fail to integrate then + # there is no point in trying other methods because they + # will fail, too. + return None + + # c + # g(x) = (a*x+b) + if g.is_Pow and not g.exp.has(x) and not meijerg: + a = Wild('a', exclude=[x]) + b = Wild('b', exclude=[x]) + + M = g.base.match(a*x + b) + + if M is not None: + if g.exp == -1: + h = log(g.base) + elif conds != 'piecewise': + h = g.base**(g.exp + 1) / (g.exp + 1) + else: + h1 = log(g.base) + h2 = g.base**(g.exp + 1) / (g.exp + 1) + h = Piecewise((h2, Ne(g.exp, -1)), (h1, True)) + + parts.append(coeff * h / M[a]) + continue + + # poly(x) + # g(x) = ------- + # poly(x) + if g.is_rational_function(x) and not (manual or meijerg or risch): + parts.append(coeff * ratint(g, x)) + continue + + if not (manual or meijerg or risch): + # g(x) = Mul(trig) + h = trigintegrate(g, x, conds=conds) + if h is not None: + parts.append(coeff * h) + continue + + # g(x) has at least a DiracDelta term + h = deltaintegrate(g, x) + if h is not None: + parts.append(coeff * h) + continue + + from .singularityfunctions import singularityintegrate + # g(x) has at least a Singularity Function term + h = singularityintegrate(g, x) + if h is not None: + parts.append(coeff * h) + continue + + # Try risch again. + if risch is not False: + try: + h, i = risch_integrate(g, x, + separate_integral=True, conds=conds) + except NotImplementedError: + h = None + else: + if i: + h = h + i.doit(risch=False) + + parts.append(coeff*h) + continue + + # fall back to heurisch + if heurisch is not False: + from sympy.integrals.heurisch import (heurisch as heurisch_, + heurisch_wrapper) + try: + if conds == 'piecewise': + h = heurisch_wrapper(g, x, hints=[]) + else: + h = heurisch_(g, x, hints=[]) + except PolynomialError: + # XXX: this exception means there is a bug in the + # implementation of heuristic Risch integration + # algorithm. + h = None + else: + h = None + + if meijerg is not False and h is None: + # rewrite using G functions + try: + h = meijerint_indefinite(g, x) + except NotImplementedError: + _debug('NotImplementedError from meijerint_definite') + if h is not None: + parts.append(coeff * h) + continue + + if h is None and manual is not False: + try: + result = manualintegrate(g, x) + if result is not None and not isinstance(result, Integral): + if result.has(Integral) and not manual: + # Try to have other algorithms do the integrals + # manualintegrate can't handle, + # unless we were asked to use manual only. + # Keep the rest of eval_kwargs in case another + # method was set to False already + new_eval_kwargs = eval_kwargs + new_eval_kwargs["manual"] = False + new_eval_kwargs["final"] = False + result = result.func(*[ + arg.doit(**new_eval_kwargs) if + arg.has(Integral) else arg + for arg in result.args + ]).expand(multinomial=False, + log=False, + power_exp=False, + power_base=False) + if not result.has(Integral): + parts.append(coeff * result) + continue + except (ValueError, PolynomialError): + # can't handle some SymPy expressions + pass + + # if we failed maybe it was because we had + # a product that could have been expanded, + # so let's try an expansion of the whole + # thing before giving up; we don't try this + # at the outset because there are things + # that cannot be solved unless they are + # NOT expanded e.g., x**x*(1+log(x)). There + # should probably be a checker somewhere in this + # routine to look for such cases and try to do + # collection on the expressions if they are already + # in an expanded form + if not h and len(args) == 1: + f = sincos_to_sum(f).expand(mul=True, deep=False) + if f.is_Add: + # Note: risch will be identical on the expanded + # expression, but maybe it will be able to pick out parts, + # like x*(exp(x) + erf(x)). + return self._eval_integral(f, x, **eval_kwargs) + + if h is not None: + parts.append(coeff * h) + else: + return None + + return Add(*parts) + + def _eval_lseries(self, x, logx=None, cdir=0): + expr = self.as_dummy() + symb = x + for l in expr.limits: + if x in l[1:]: + symb = l[0] + break + for term in expr.function.lseries(symb, logx): + yield integrate(term, *expr.limits) + + def _eval_nseries(self, x, n, logx=None, cdir=0): + symb = x + for l in self.limits: + if x in l[1:]: + symb = l[0] + break + terms, order = self.function.nseries( + x=symb, n=n, logx=logx).as_coeff_add(Order) + order = [o.subs(symb, x) for o in order] + return integrate(terms, *self.limits) + Add(*order)*x + + def _eval_as_leading_term(self, x, logx, cdir): + series_gen = self.args[0].lseries(x) + for leading_term in series_gen: + if leading_term != 0: + break + return integrate(leading_term, *self.args[1:]) + + def _eval_simplify(self, **kwargs): + expr = factor_terms(self) + if isinstance(expr, Integral): + from sympy.simplify.simplify import simplify + return expr.func(*[simplify(i, **kwargs) for i in expr.args]) + return expr.simplify(**kwargs) + + def as_sum(self, n=None, method="midpoint", evaluate=True): + """ + Approximates a definite integral by a sum. + + Parameters + ========== + + n : + The number of subintervals to use, optional. + method : + One of: 'left', 'right', 'midpoint', 'trapezoid'. + evaluate : bool + If False, returns an unevaluated Sum expression. The default + is True, evaluate the sum. + + Notes + ===== + + These methods of approximate integration are described in [1]. + + Examples + ======== + + >>> from sympy import Integral, sin, sqrt + >>> from sympy.abc import x, n + >>> e = Integral(sin(x), (x, 3, 7)) + >>> e + Integral(sin(x), (x, 3, 7)) + + For demonstration purposes, this interval will only be split into 2 + regions, bounded by [3, 5] and [5, 7]. + + The left-hand rule uses function evaluations at the left of each + interval: + + >>> e.as_sum(2, 'left') + 2*sin(5) + 2*sin(3) + + The midpoint rule uses evaluations at the center of each interval: + + >>> e.as_sum(2, 'midpoint') + 2*sin(4) + 2*sin(6) + + The right-hand rule uses function evaluations at the right of each + interval: + + >>> e.as_sum(2, 'right') + 2*sin(5) + 2*sin(7) + + The trapezoid rule uses function evaluations on both sides of the + intervals. This is equivalent to taking the average of the left and + right hand rule results: + + >>> s = e.as_sum(2, 'trapezoid') + >>> s + 2*sin(5) + sin(3) + sin(7) + >>> (e.as_sum(2, 'left') + e.as_sum(2, 'right'))/2 == s + True + + Here, the discontinuity at x = 0 can be avoided by using the + midpoint or right-hand method: + + >>> e = Integral(1/sqrt(x), (x, 0, 1)) + >>> e.as_sum(5).n(4) + 1.730 + >>> e.as_sum(10).n(4) + 1.809 + >>> e.doit().n(4) # the actual value is 2 + 2.000 + + The left- or trapezoid method will encounter the discontinuity and + return infinity: + + >>> e.as_sum(5, 'left') + zoo + + The number of intervals can be symbolic. If omitted, a dummy symbol + will be used for it. + + >>> e = Integral(x**2, (x, 0, 2)) + >>> e.as_sum(n, 'right').expand() + 8/3 + 4/n + 4/(3*n**2) + + This shows that the midpoint rule is more accurate, as its error + term decays as the square of n: + + >>> e.as_sum(method='midpoint').expand() + 8/3 - 2/(3*_n**2) + + A symbolic sum is returned with evaluate=False: + + >>> e.as_sum(n, 'midpoint', evaluate=False) + 2*Sum((2*_k/n - 1/n)**2, (_k, 1, n))/n + + See Also + ======== + + Integral.doit : Perform the integration using any hints + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Riemann_sum#Riemann_summation_methods + """ + + from sympy.concrete.summations import Sum + limits = self.limits + if len(limits) > 1: + raise NotImplementedError( + "Multidimensional midpoint rule not implemented yet") + else: + limit = limits[0] + if (len(limit) != 3 or limit[1].is_finite is False or + limit[2].is_finite is False): + raise ValueError("Expecting a definite integral over " + "a finite interval.") + if n is None: + n = Dummy('n', integer=True, positive=True) + else: + n = sympify(n) + if (n.is_positive is False or n.is_integer is False or + n.is_finite is False): + raise ValueError("n must be a positive integer, got %s" % n) + x, a, b = limit + dx = (b - a)/n + k = Dummy('k', integer=True, positive=True) + f = self.function + + if method == "left": + result = dx*Sum(f.subs(x, a + (k-1)*dx), (k, 1, n)) + elif method == "right": + result = dx*Sum(f.subs(x, a + k*dx), (k, 1, n)) + elif method == "midpoint": + result = dx*Sum(f.subs(x, a + k*dx - dx/2), (k, 1, n)) + elif method == "trapezoid": + result = dx*((f.subs(x, a) + f.subs(x, b))/2 + + Sum(f.subs(x, a + k*dx), (k, 1, n - 1))) + else: + raise ValueError("Unknown method %s" % method) + return result.doit() if evaluate else result + + def principal_value(self, **kwargs): + """ + Compute the Cauchy Principal Value of the definite integral of a real function in the given interval + on the real axis. + + Explanation + =========== + + In mathematics, the Cauchy principal value, is a method for assigning values to certain improper + integrals which would otherwise be undefined. + + Examples + ======== + + >>> from sympy import Integral, oo + >>> from sympy.abc import x + >>> Integral(x+1, (x, -oo, oo)).principal_value() + oo + >>> f = 1 / (x**3) + >>> Integral(f, (x, -oo, oo)).principal_value() + 0 + >>> Integral(f, (x, -10, 10)).principal_value() + 0 + >>> Integral(f, (x, -10, oo)).principal_value() + Integral(f, (x, -oo, 10)).principal_value() + 0 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Cauchy_principal_value + .. [2] https://mathworld.wolfram.com/CauchyPrincipalValue.html + """ + if len(self.limits) != 1 or len(list(self.limits[0])) != 3: + raise ValueError("You need to insert a variable, lower_limit, and upper_limit correctly to calculate " + "cauchy's principal value") + x, a, b = self.limits[0] + if not (a.is_comparable and b.is_comparable and a <= b): + raise ValueError("The lower_limit must be smaller than or equal to the upper_limit to calculate " + "cauchy's principal value. Also, a and b need to be comparable.") + if a == b: + return S.Zero + + from sympy.calculus.singularities import singularities + + r = Dummy('r') + f = self.function + singularities_list = [s for s in singularities(f, x) if s.is_comparable and a <= s <= b] + for i in singularities_list: + if i in (a, b): + raise ValueError( + 'The principal value is not defined in the given interval due to singularity at %d.' % (i)) + F = integrate(f, x, **kwargs) + if F.has(Integral): + return self + if a is -oo and b is oo: + I = limit(F - F.subs(x, -x), x, oo) + else: + I = limit(F, x, b, '-') - limit(F, x, a, '+') + for s in singularities_list: + I += limit(((F.subs(x, s - r)) - F.subs(x, s + r)), r, 0, '+') + return I + + + +def integrate(*args, meijerg=None, conds='piecewise', risch=None, heurisch=None, manual=None, **kwargs): + """integrate(f, var, ...) + + .. deprecated:: 1.6 + + Using ``integrate()`` with :class:`~.Poly` is deprecated. Use + :meth:`.Poly.integrate` instead. See :ref:`deprecated-integrate-poly`. + + Explanation + =========== + + Compute definite or indefinite integral of one or more variables + using Risch-Norman algorithm and table lookup. This procedure is + able to handle elementary algebraic and transcendental functions + and also a huge class of special functions, including Airy, + Bessel, Whittaker and Lambert. + + var can be: + + - a symbol -- indefinite integration + - a tuple (symbol, a) -- indefinite integration with result + given with ``a`` replacing ``symbol`` + - a tuple (symbol, a, b) -- definite integration + + Several variables can be specified, in which case the result is + multiple integration. (If var is omitted and the integrand is + univariate, the indefinite integral in that variable will be performed.) + + Indefinite integrals are returned without terms that are independent + of the integration variables. (see examples) + + Definite improper integrals often entail delicate convergence + conditions. Pass conds='piecewise', 'separate' or 'none' to have + these returned, respectively, as a Piecewise function, as a separate + result (i.e. result will be a tuple), or not at all (default is + 'piecewise'). + + **Strategy** + + SymPy uses various approaches to definite integration. One method is to + find an antiderivative for the integrand, and then use the fundamental + theorem of calculus. Various functions are implemented to integrate + polynomial, rational and trigonometric functions, and integrands + containing DiracDelta terms. + + SymPy also implements the part of the Risch algorithm, which is a decision + procedure for integrating elementary functions, i.e., the algorithm can + either find an elementary antiderivative, or prove that one does not + exist. There is also a (very successful, albeit somewhat slow) general + implementation of the heuristic Risch algorithm. This algorithm will + eventually be phased out as more of the full Risch algorithm is + implemented. See the docstring of Integral._eval_integral() for more + details on computing the antiderivative using algebraic methods. + + The option risch=True can be used to use only the (full) Risch algorithm. + This is useful if you want to know if an elementary function has an + elementary antiderivative. If the indefinite Integral returned by this + function is an instance of NonElementaryIntegral, that means that the + Risch algorithm has proven that integral to be non-elementary. Note that + by default, additional methods (such as the Meijer G method outlined + below) are tried on these integrals, as they may be expressible in terms + of special functions, so if you only care about elementary answers, use + risch=True. Also note that an unevaluated Integral returned by this + function is not necessarily a NonElementaryIntegral, even with risch=True, + as it may just be an indication that the particular part of the Risch + algorithm needed to integrate that function is not yet implemented. + + Another family of strategies comes from re-writing the integrand in + terms of so-called Meijer G-functions. Indefinite integrals of a + single G-function can always be computed, and the definite integral + of a product of two G-functions can be computed from zero to + infinity. Various strategies are implemented to rewrite integrands + as G-functions, and use this information to compute integrals (see + the ``meijerint`` module). + + The option manual=True can be used to use only an algorithm that tries + to mimic integration by hand. This algorithm does not handle as many + integrands as the other algorithms implemented but may return results in + a more familiar form. The ``manualintegrate`` module has functions that + return the steps used (see the module docstring for more information). + + In general, the algebraic methods work best for computing + antiderivatives of (possibly complicated) combinations of elementary + functions. The G-function methods work best for computing definite + integrals from zero to infinity of moderately complicated + combinations of special functions, or indefinite integrals of very + simple combinations of special functions. + + The strategy employed by the integration code is as follows: + + - If computing a definite integral, and both limits are real, + and at least one limit is +- oo, try the G-function method of + definite integration first. + + - Try to find an antiderivative, using all available methods, ordered + by performance (that is try fastest method first, slowest last; in + particular polynomial integration is tried first, Meijer + G-functions second to last, and heuristic Risch last). + + - If still not successful, try G-functions irrespective of the + limits. + + The option meijerg=True, False, None can be used to, respectively: + always use G-function methods and no others, never use G-function + methods, or use all available methods (in order as described above). + It defaults to None. + + Examples + ======== + + >>> from sympy import integrate, log, exp, oo + >>> from sympy.abc import a, x, y + + >>> integrate(x*y, x) + x**2*y/2 + + >>> integrate(log(x), x) + x*log(x) - x + + >>> integrate(log(x), (x, 1, a)) + a*log(a) - a + 1 + + >>> integrate(x) + x**2/2 + + Terms that are independent of x are dropped by indefinite integration: + + >>> from sympy import sqrt + >>> integrate(sqrt(1 + x), (x, 0, x)) + 2*(x + 1)**(3/2)/3 - 2/3 + >>> integrate(sqrt(1 + x), x) + 2*(x + 1)**(3/2)/3 + + >>> integrate(x*y) + Traceback (most recent call last): + ... + ValueError: specify integration variables to integrate x*y + + Note that ``integrate(x)`` syntax is meant only for convenience + in interactive sessions and should be avoided in library code. + + >>> integrate(x**a*exp(-x), (x, 0, oo)) # same as conds='piecewise' + Piecewise((gamma(a + 1), re(a) > -1), + (Integral(x**a*exp(-x), (x, 0, oo)), True)) + + >>> integrate(x**a*exp(-x), (x, 0, oo), conds='none') + gamma(a + 1) + + >>> integrate(x**a*exp(-x), (x, 0, oo), conds='separate') + (gamma(a + 1), re(a) > -1) + + See Also + ======== + + Integral, Integral.doit + + """ + doit_flags = { + 'deep': False, + 'meijerg': meijerg, + 'conds': conds, + 'risch': risch, + 'heurisch': heurisch, + 'manual': manual + } + + integral = Integral(*args, **kwargs) + + if isinstance(integral, Integral): + return integral.doit(**doit_flags) + else: + new_args = [a.doit(**doit_flags) if isinstance(a, Integral) else a + for a in integral.args] + return integral.func(*new_args) + +def line_integrate(field, curve, vars): + """line_integrate(field, Curve, variables) + + Compute the line integral. + + Examples + ======== + + >>> from sympy import Curve, line_integrate, E, ln + >>> from sympy.abc import x, y, t + >>> C = Curve([E**t + 1, E**t - 1], (t, 0, ln(2))) + >>> line_integrate(x + y, C, [x, y]) + 3*sqrt(2) + + See Also + ======== + + sympy.integrals.integrals.integrate, Integral + """ + from sympy.geometry import Curve + F = sympify(field) + if not F: + raise ValueError( + "Expecting function specifying field as first argument.") + if not isinstance(curve, Curve): + raise ValueError("Expecting Curve entity as second argument.") + if not is_sequence(vars): + raise ValueError("Expecting ordered iterable for variables.") + if len(curve.functions) != len(vars): + raise ValueError("Field variable size does not match curve dimension.") + + if curve.parameter in vars: + raise ValueError("Curve parameter clashes with field parameters.") + + # Calculate derivatives for line parameter functions + # F(r) -> F(r(t)) and finally F(r(t)*r'(t)) + Ft = F + dldt = 0 + for i, var in enumerate(vars): + _f = curve.functions[i] + _dn = diff(_f, curve.parameter) + # ...arc length + dldt = dldt + (_dn * _dn) + Ft = Ft.subs(var, _f) + Ft = Ft * sqrt(dldt) + + integral = Integral(Ft, curve.limits).doit(deep=False) + return integral + + +### Property function dispatching ### + +@shape.register(Integral) +def _(expr): + return shape(expr.function) + +# Delayed imports +from .deltafunctions import deltaintegrate +from .meijerint import meijerint_definite, meijerint_indefinite, _debug +from .trigonometry import trigintegrate diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/intpoly.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/intpoly.py new file mode 100644 index 0000000000000000000000000000000000000000..38fd071183fb2192f4c1443d04c8f0ecfb6cc4ea --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/intpoly.py @@ -0,0 +1,1302 @@ +""" +Module to implement integration of uni/bivariate polynomials over +2D Polytopes and uni/bi/trivariate polynomials over 3D Polytopes. + +Uses evaluation techniques as described in Chin et al. (2015) [1]. + + +References +=========== + +.. [1] Chin, Eric B., Jean B. Lasserre, and N. Sukumar. "Numerical integration +of homogeneous functions on convex and nonconvex polygons and polyhedra." +Computational Mechanics 56.6 (2015): 967-981 + +PDF link : http://dilbert.engr.ucdavis.edu/~suku/quadrature/cls-integration.pdf +""" + +from functools import cmp_to_key + +from sympy.abc import x, y, z +from sympy.core import S, diff, Expr, Symbol +from sympy.core.sympify import _sympify +from sympy.geometry import Segment2D, Polygon, Point, Point2D +from sympy.polys.polytools import LC, gcd_list, degree_list, Poly +from sympy.simplify.simplify import nsimplify + + +def polytope_integrate(poly, expr=None, *, clockwise=False, max_degree=None): + """Integrates polynomials over 2/3-Polytopes. + + Explanation + =========== + + This function accepts the polytope in ``poly`` and the function in ``expr`` + (uni/bi/trivariate polynomials are implemented) and returns + the exact integral of ``expr`` over ``poly``. + + Parameters + ========== + + poly : The input Polygon. + + expr : The input polynomial. + + clockwise : Binary value to sort input points of 2-Polytope clockwise.(Optional) + + max_degree : The maximum degree of any monomial of the input polynomial.(Optional) + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import Point, Polygon + >>> from sympy.integrals.intpoly import polytope_integrate + >>> polygon = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)) + >>> polys = [1, x, y, x*y, x**2*y, x*y**2] + >>> expr = x*y + >>> polytope_integrate(polygon, expr) + 1/4 + >>> polytope_integrate(polygon, polys, max_degree=3) + {1: 1, x: 1/2, y: 1/2, x*y: 1/4, x*y**2: 1/6, x**2*y: 1/6} + """ + if clockwise: + if isinstance(poly, Polygon): + poly = Polygon(*point_sort(poly.vertices), evaluate=False) + else: + raise TypeError("clockwise=True works for only 2-Polytope" + "V-representation input") + + if isinstance(poly, Polygon): + # For Vertex Representation(2D case) + hp_params = hyperplane_parameters(poly) + facets = poly.sides + elif len(poly[0]) == 2: + # For Hyperplane Representation(2D case) + plen = len(poly) + if len(poly[0][0]) == 2: + intersections = [intersection(poly[(i - 1) % plen], poly[i], + "plane2D") + for i in range(0, plen)] + hp_params = poly + lints = len(intersections) + facets = [Segment2D(intersections[i], + intersections[(i + 1) % lints]) + for i in range(lints)] + else: + raise NotImplementedError("Integration for H-representation 3D" + "case not implemented yet.") + else: + # For Vertex Representation(3D case) + vertices = poly[0] + facets = poly[1:] + hp_params = hyperplane_parameters(facets, vertices) + + if max_degree is None: + if expr is None: + raise TypeError('Input expression must be a valid SymPy expression') + return main_integrate3d(expr, facets, vertices, hp_params) + + if max_degree is not None: + result = {} + if expr is not None: + f_expr = [] + for e in expr: + _ = decompose(e) + if len(_) == 1 and not _.popitem()[0]: + f_expr.append(e) + elif Poly(e).total_degree() <= max_degree: + f_expr.append(e) + expr = f_expr + + if not isinstance(expr, list) and expr is not None: + raise TypeError('Input polynomials must be list of expressions') + + if len(hp_params[0][0]) == 3: + result_dict = main_integrate3d(0, facets, vertices, hp_params, + max_degree) + else: + result_dict = main_integrate(0, facets, hp_params, max_degree) + + if expr is None: + return result_dict + + for poly in expr: + poly = _sympify(poly) + if poly not in result: + if poly.is_zero: + result[S.Zero] = S.Zero + continue + integral_value = S.Zero + monoms = decompose(poly, separate=True) + for monom in monoms: + monom = nsimplify(monom) + coeff, m = strip(monom) + integral_value += result_dict[m] * coeff + result[poly] = integral_value + return result + + if expr is None: + raise TypeError('Input expression must be a valid SymPy expression') + + return main_integrate(expr, facets, hp_params) + + +def strip(monom): + if monom.is_zero: + return S.Zero, S.Zero + elif monom.is_number: + return monom, S.One + else: + coeff = LC(monom) + return coeff, monom / coeff + +def _polynomial_integrate(polynomials, facets, hp_params): + dims = (x, y) + dim_length = len(dims) + integral_value = S.Zero + for deg in polynomials: + poly_contribute = S.Zero + facet_count = 0 + for hp in hp_params: + value_over_boundary = integration_reduction(facets, + facet_count, + hp[0], hp[1], + polynomials[deg], + dims, deg) + poly_contribute += value_over_boundary * (hp[1] / norm(hp[0])) + facet_count += 1 + poly_contribute /= (dim_length + deg) + integral_value += poly_contribute + + return integral_value + + +def main_integrate3d(expr, facets, vertices, hp_params, max_degree=None): + """Function to translate the problem of integrating uni/bi/tri-variate + polynomials over a 3-Polytope to integrating over its faces. + This is done using Generalized Stokes' Theorem and Euler's Theorem. + + Parameters + ========== + + expr : + The input polynomial. + facets : + Faces of the 3-Polytope(expressed as indices of `vertices`). + vertices : + Vertices that constitute the Polytope. + hp_params : + Hyperplane Parameters of the facets. + max_degree : optional + Max degree of constituent monomial in given list of polynomial. + + Examples + ======== + + >>> from sympy.integrals.intpoly import main_integrate3d, \ + hyperplane_parameters + >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ + (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ + [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ + [3, 1, 0, 2], [0, 4, 6, 2]] + >>> vertices = cube[0] + >>> faces = cube[1:] + >>> hp_params = hyperplane_parameters(faces, vertices) + >>> main_integrate3d(1, faces, vertices, hp_params) + -125 + """ + result = {} + dims = (x, y, z) + dim_length = len(dims) + if max_degree: + grad_terms = gradient_terms(max_degree, 3) + flat_list = [term for z_terms in grad_terms + for x_term in z_terms + for term in x_term] + + for term in flat_list: + result[term[0]] = 0 + + for facet_count, hp in enumerate(hp_params): + a, b = hp[0], hp[1] + x0 = vertices[facets[facet_count][0]] + + for i, monom in enumerate(flat_list): + # Every monomial is a tuple : + # (term, x_degree, y_degree, z_degree, value over boundary) + expr, x_d, y_d, z_d, z_index, y_index, x_index, _ = monom + degree = x_d + y_d + z_d + if b.is_zero: + value_over_face = S.Zero + else: + value_over_face = \ + integration_reduction_dynamic(facets, facet_count, a, + b, expr, degree, dims, + x_index, y_index, + z_index, x0, grad_terms, + i, vertices, hp) + monom[7] = value_over_face + result[expr] += value_over_face * \ + (b / norm(a)) / (dim_length + x_d + y_d + z_d) + return result + else: + integral_value = S.Zero + polynomials = decompose(expr) + for deg in polynomials: + poly_contribute = S.Zero + facet_count = 0 + for i, facet in enumerate(facets): + hp = hp_params[i] + if hp[1].is_zero: + continue + pi = polygon_integrate(facet, hp, i, facets, vertices, expr, deg) + poly_contribute += pi *\ + (hp[1] / norm(tuple(hp[0]))) + facet_count += 1 + poly_contribute /= (dim_length + deg) + integral_value += poly_contribute + return integral_value + + +def main_integrate(expr, facets, hp_params, max_degree=None): + """Function to translate the problem of integrating univariate/bivariate + polynomials over a 2-Polytope to integrating over its boundary facets. + This is done using Generalized Stokes's Theorem and Euler's Theorem. + + Parameters + ========== + + expr : + The input polynomial. + facets : + Facets(Line Segments) of the 2-Polytope. + hp_params : + Hyperplane Parameters of the facets. + max_degree : optional + The maximum degree of any monomial of the input polynomial. + + >>> from sympy.abc import x, y + >>> from sympy.integrals.intpoly import main_integrate,\ + hyperplane_parameters + >>> from sympy import Point, Polygon + >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) + >>> facets = triangle.sides + >>> hp_params = hyperplane_parameters(triangle) + >>> main_integrate(x**2 + y**2, facets, hp_params) + 325/6 + """ + dims = (x, y) + dim_length = len(dims) + result = {} + + if max_degree: + grad_terms = [[0, 0, 0, 0]] + gradient_terms(max_degree) + + for facet_count, hp in enumerate(hp_params): + a, b = hp[0], hp[1] + x0 = facets[facet_count].points[0] + + for i, monom in enumerate(grad_terms): + # Every monomial is a tuple : + # (term, x_degree, y_degree, value over boundary) + m, x_d, y_d, _ = monom + value = result.get(m, None) + degree = S.Zero + if b.is_zero: + value_over_boundary = S.Zero + else: + degree = x_d + y_d + value_over_boundary = \ + integration_reduction_dynamic(facets, facet_count, a, + b, m, degree, dims, x_d, + y_d, max_degree, x0, + grad_terms, i) + monom[3] = value_over_boundary + if value is not None: + result[m] += value_over_boundary * \ + (b / norm(a)) / (dim_length + degree) + else: + result[m] = value_over_boundary * \ + (b / norm(a)) / (dim_length + degree) + return result + else: + if not isinstance(expr, list): + polynomials = decompose(expr) + return _polynomial_integrate(polynomials, facets, hp_params) + else: + return {e: _polynomial_integrate(decompose(e), facets, hp_params) for e in expr} + + +def polygon_integrate(facet, hp_param, index, facets, vertices, expr, degree): + """Helper function to integrate the input uni/bi/trivariate polynomial + over a certain face of the 3-Polytope. + + Parameters + ========== + + facet : + Particular face of the 3-Polytope over which ``expr`` is integrated. + index : + The index of ``facet`` in ``facets``. + facets : + Faces of the 3-Polytope(expressed as indices of `vertices`). + vertices : + Vertices that constitute the facet. + expr : + The input polynomial. + degree : + Degree of ``expr``. + + Examples + ======== + + >>> from sympy.integrals.intpoly import polygon_integrate + >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ + (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ + [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ + [3, 1, 0, 2], [0, 4, 6, 2]] + >>> facet = cube[1] + >>> facets = cube[1:] + >>> vertices = cube[0] + >>> polygon_integrate(facet, [(0, 1, 0), 5], 0, facets, vertices, 1, 0) + -25 + """ + expr = S(expr) + if expr.is_zero: + return S.Zero + result = S.Zero + x0 = vertices[facet[0]] + facet_len = len(facet) + for i, fac in enumerate(facet): + side = (vertices[fac], vertices[facet[(i + 1) % facet_len]]) + result += distance_to_side(x0, side, hp_param[0]) *\ + lineseg_integrate(facet, i, side, expr, degree) + if not expr.is_number: + expr = diff(expr, x) * x0[0] + diff(expr, y) * x0[1] +\ + diff(expr, z) * x0[2] + result += polygon_integrate(facet, hp_param, index, facets, vertices, + expr, degree - 1) + result /= (degree + 2) + return result + + +def distance_to_side(point, line_seg, A): + """Helper function to compute the signed distance between given 3D point + and a line segment. + + Parameters + ========== + + point : 3D Point + line_seg : Line Segment + + Examples + ======== + + >>> from sympy.integrals.intpoly import distance_to_side + >>> point = (0, 0, 0) + >>> distance_to_side(point, [(0, 0, 1), (0, 1, 0)], (1, 0, 0)) + -sqrt(2)/2 + """ + x1, x2 = line_seg + rev_normal = [-1 * S(i)/norm(A) for i in A] + vector = [x2[i] - x1[i] for i in range(0, 3)] + vector = [vector[i]/norm(vector) for i in range(0, 3)] + + n_side = cross_product((0, 0, 0), rev_normal, vector) + vectorx0 = [line_seg[0][i] - point[i] for i in range(0, 3)] + dot_product = sum(vectorx0[i] * n_side[i] for i in range(0, 3)) + + return dot_product + + +def lineseg_integrate(polygon, index, line_seg, expr, degree): + """Helper function to compute the line integral of ``expr`` over ``line_seg``. + + Parameters + =========== + + polygon : + Face of a 3-Polytope. + index : + Index of line_seg in polygon. + line_seg : + Line Segment. + + Examples + ======== + + >>> from sympy.integrals.intpoly import lineseg_integrate + >>> polygon = [(0, 5, 0), (5, 5, 0), (5, 5, 5), (0, 5, 5)] + >>> line_seg = [(0, 5, 0), (5, 5, 0)] + >>> lineseg_integrate(polygon, 0, line_seg, 1, 0) + 5 + """ + expr = _sympify(expr) + if expr.is_zero: + return S.Zero + result = S.Zero + x0 = line_seg[0] + distance = norm(tuple([line_seg[1][i] - line_seg[0][i] for i in + range(3)])) + if isinstance(expr, Expr): + expr_dict = {x: line_seg[1][0], + y: line_seg[1][1], + z: line_seg[1][2]} + result += distance * expr.subs(expr_dict) + else: + result += distance * expr + + expr = diff(expr, x) * x0[0] + diff(expr, y) * x0[1] +\ + diff(expr, z) * x0[2] + + result += lineseg_integrate(polygon, index, line_seg, expr, degree - 1) + result /= (degree + 1) + return result + + +def integration_reduction(facets, index, a, b, expr, dims, degree): + """Helper method for main_integrate. Returns the value of the input + expression evaluated over the polytope facet referenced by a given index. + + Parameters + =========== + + facets : + List of facets of the polytope. + index : + Index referencing the facet to integrate the expression over. + a : + Hyperplane parameter denoting direction. + b : + Hyperplane parameter denoting distance. + expr : + The expression to integrate over the facet. + dims : + List of symbols denoting axes. + degree : + Degree of the homogeneous polynomial. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.integrals.intpoly import integration_reduction,\ + hyperplane_parameters + >>> from sympy import Point, Polygon + >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) + >>> facets = triangle.sides + >>> a, b = hyperplane_parameters(triangle)[0] + >>> integration_reduction(facets, 0, a, b, 1, (x, y), 0) + 5 + """ + expr = _sympify(expr) + if expr.is_zero: + return expr + + value = S.Zero + x0 = facets[index].points[0] + m = len(facets) + gens = (x, y) + + inner_product = diff(expr, gens[0]) * x0[0] + diff(expr, gens[1]) * x0[1] + + if inner_product != 0: + value += integration_reduction(facets, index, a, b, + inner_product, dims, degree - 1) + + value += left_integral2D(m, index, facets, x0, expr, gens) + + return value/(len(dims) + degree - 1) + + +def left_integral2D(m, index, facets, x0, expr, gens): + """Computes the left integral of Eq 10 in Chin et al. + For the 2D case, the integral is just an evaluation of the polynomial + at the intersection of two facets which is multiplied by the distance + between the first point of facet and that intersection. + + Parameters + ========== + + m : + No. of hyperplanes. + index : + Index of facet to find intersections with. + facets : + List of facets(Line Segments in 2D case). + x0 : + First point on facet referenced by index. + expr : + Input polynomial + gens : + Generators which generate the polynomial + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.integrals.intpoly import left_integral2D + >>> from sympy import Point, Polygon + >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) + >>> facets = triangle.sides + >>> left_integral2D(3, 0, facets, facets[0].points[0], 1, (x, y)) + 5 + """ + value = S.Zero + for j in range(m): + intersect = () + if j in ((index - 1) % m, (index + 1) % m): + intersect = intersection(facets[index], facets[j], "segment2D") + if intersect: + distance_origin = norm(tuple(map(lambda x, y: x - y, + intersect, x0))) + if is_vertex(intersect): + if isinstance(expr, Expr): + if len(gens) == 3: + expr_dict = {gens[0]: intersect[0], + gens[1]: intersect[1], + gens[2]: intersect[2]} + else: + expr_dict = {gens[0]: intersect[0], + gens[1]: intersect[1]} + value += distance_origin * expr.subs(expr_dict) + else: + value += distance_origin * expr + return value + + +def integration_reduction_dynamic(facets, index, a, b, expr, degree, dims, + x_index, y_index, max_index, x0, + monomial_values, monom_index, vertices=None, + hp_param=None): + """The same integration_reduction function which uses a dynamic + programming approach to compute terms by using the values of the integral + of previously computed terms. + + Parameters + ========== + + facets : + Facets of the Polytope. + index : + Index of facet to find intersections with.(Used in left_integral()). + a, b : + Hyperplane parameters. + expr : + Input monomial. + degree : + Total degree of ``expr``. + dims : + Tuple denoting axes variables. + x_index : + Exponent of 'x' in ``expr``. + y_index : + Exponent of 'y' in ``expr``. + max_index : + Maximum exponent of any monomial in ``monomial_values``. + x0 : + First point on ``facets[index]``. + monomial_values : + List of monomial values constituting the polynomial. + monom_index : + Index of monomial whose integration is being found. + vertices : optional + Coordinates of vertices constituting the 3-Polytope. + hp_param : optional + Hyperplane Parameter of the face of the facets[index]. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.integrals.intpoly import (integration_reduction_dynamic, \ + hyperplane_parameters) + >>> from sympy import Point, Polygon + >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) + >>> facets = triangle.sides + >>> a, b = hyperplane_parameters(triangle)[0] + >>> x0 = facets[0].points[0] + >>> monomial_values = [[0, 0, 0, 0], [1, 0, 0, 5],\ + [y, 0, 1, 15], [x, 1, 0, None]] + >>> integration_reduction_dynamic(facets, 0, a, b, x, 1, (x, y), 1, 0, 1,\ + x0, monomial_values, 3) + 25/2 + """ + value = S.Zero + m = len(facets) + + if expr == S.Zero: + return expr + + if len(dims) == 2: + if not expr.is_number: + _, x_degree, y_degree, _ = monomial_values[monom_index] + x_index = monom_index - max_index + \ + x_index - 2 if x_degree > 0 else 0 + y_index = monom_index - 1 if y_degree > 0 else 0 + x_value, y_value =\ + monomial_values[x_index][3], monomial_values[y_index][3] + + value += x_degree * x_value * x0[0] + y_degree * y_value * x0[1] + + value += left_integral2D(m, index, facets, x0, expr, dims) + else: + # For 3D use case the max_index contains the z_degree of the term + z_index = max_index + if not expr.is_number: + x_degree, y_degree, z_degree = y_index,\ + z_index - x_index - y_index, x_index + x_value = monomial_values[z_index - 1][y_index - 1][x_index][7]\ + if x_degree > 0 else 0 + y_value = monomial_values[z_index - 1][y_index][x_index][7]\ + if y_degree > 0 else 0 + z_value = monomial_values[z_index - 1][y_index][x_index - 1][7]\ + if z_degree > 0 else 0 + + value += x_degree * x_value * x0[0] + y_degree * y_value * x0[1] \ + + z_degree * z_value * x0[2] + + value += left_integral3D(facets, index, expr, + vertices, hp_param, degree) + return value / (len(dims) + degree - 1) + + +def left_integral3D(facets, index, expr, vertices, hp_param, degree): + """Computes the left integral of Eq 10 in Chin et al. + + Explanation + =========== + + For the 3D case, this is the sum of the integral values over constituting + line segments of the face (which is accessed by facets[index]) multiplied + by the distance between the first point of facet and that line segment. + + Parameters + ========== + + facets : + List of faces of the 3-Polytope. + index : + Index of face over which integral is to be calculated. + expr : + Input polynomial. + vertices : + List of vertices that constitute the 3-Polytope. + hp_param : + The hyperplane parameters of the face. + degree : + Degree of the ``expr``. + + Examples + ======== + + >>> from sympy.integrals.intpoly import left_integral3D + >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ + (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ + [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ + [3, 1, 0, 2], [0, 4, 6, 2]] + >>> facets = cube[1:] + >>> vertices = cube[0] + >>> left_integral3D(facets, 3, 1, vertices, ([0, -1, 0], -5), 0) + -50 + """ + value = S.Zero + facet = facets[index] + x0 = vertices[facet[0]] + facet_len = len(facet) + for i, fac in enumerate(facet): + side = (vertices[fac], vertices[facet[(i + 1) % facet_len]]) + value += distance_to_side(x0, side, hp_param[0]) * \ + lineseg_integrate(facet, i, side, expr, degree) + return value + + +def gradient_terms(binomial_power=0, no_of_gens=2): + """Returns a list of all the possible monomials between + 0 and y**binomial_power for 2D case and z**binomial_power + for 3D case. + + Parameters + ========== + + binomial_power : + Power upto which terms are generated. + no_of_gens : + Denotes whether terms are being generated for 2D or 3D case. + + Examples + ======== + + >>> from sympy.integrals.intpoly import gradient_terms + >>> gradient_terms(2) + [[1, 0, 0, 0], [y, 0, 1, 0], [y**2, 0, 2, 0], [x, 1, 0, 0], + [x*y, 1, 1, 0], [x**2, 2, 0, 0]] + >>> gradient_terms(2, 3) + [[[[1, 0, 0, 0, 0, 0, 0, 0]]], [[[y, 0, 1, 0, 1, 0, 0, 0], + [z, 0, 0, 1, 1, 0, 1, 0]], [[x, 1, 0, 0, 1, 1, 0, 0]]], + [[[y**2, 0, 2, 0, 2, 0, 0, 0], [y*z, 0, 1, 1, 2, 0, 1, 0], + [z**2, 0, 0, 2, 2, 0, 2, 0]], [[x*y, 1, 1, 0, 2, 1, 0, 0], + [x*z, 1, 0, 1, 2, 1, 1, 0]], [[x**2, 2, 0, 0, 2, 2, 0, 0]]]] + """ + if no_of_gens == 2: + count = 0 + terms = [None] * int((binomial_power ** 2 + 3 * binomial_power + 2) / 2) + for x_count in range(0, binomial_power + 1): + for y_count in range(0, binomial_power - x_count + 1): + terms[count] = [x**x_count*y**y_count, + x_count, y_count, 0] + count += 1 + else: + terms = [[[[x ** x_count * y ** y_count * + z ** (z_count - y_count - x_count), + x_count, y_count, z_count - y_count - x_count, + z_count, x_count, z_count - y_count - x_count, 0] + for y_count in range(z_count - x_count, -1, -1)] + for x_count in range(0, z_count + 1)] + for z_count in range(0, binomial_power + 1)] + return terms + + +def hyperplane_parameters(poly, vertices=None): + """A helper function to return the hyperplane parameters + of which the facets of the polytope are a part of. + + Parameters + ========== + + poly : + The input 2/3-Polytope. + vertices : + Vertex indices of 3-Polytope. + + Examples + ======== + + >>> from sympy import Point, Polygon + >>> from sympy.integrals.intpoly import hyperplane_parameters + >>> hyperplane_parameters(Polygon(Point(0, 3), Point(5, 3), Point(1, 1))) + [((0, 1), 3), ((1, -2), -1), ((-2, -1), -3)] + >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ + (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ + [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ + [3, 1, 0, 2], [0, 4, 6, 2]] + >>> hyperplane_parameters(cube[1:], cube[0]) + [([0, -1, 0], -5), ([0, 0, -1], -5), ([-1, 0, 0], -5), + ([0, 1, 0], 0), ([1, 0, 0], 0), ([0, 0, 1], 0)] + """ + if isinstance(poly, Polygon): + vertices = list(poly.vertices) + [poly.vertices[0]] # Close the polygon + params = [None] * (len(vertices) - 1) + + for i in range(len(vertices) - 1): + v1 = vertices[i] + v2 = vertices[i + 1] + + a1 = v1[1] - v2[1] + a2 = v2[0] - v1[0] + b = v2[0] * v1[1] - v2[1] * v1[0] + + factor = gcd_list([a1, a2, b]) + + b = S(b) / factor + a = (S(a1) / factor, S(a2) / factor) + params[i] = (a, b) + else: + params = [None] * len(poly) + for i, polygon in enumerate(poly): + v1, v2, v3 = [vertices[vertex] for vertex in polygon[:3]] + normal = cross_product(v1, v2, v3) + b = sum(normal[j] * v1[j] for j in range(0, 3)) + fac = gcd_list(normal) + if fac.is_zero: + fac = 1 + normal = [j / fac for j in normal] + b = b / fac + params[i] = (normal, b) + return params + + +def cross_product(v1, v2, v3): + """Returns the cross-product of vectors (v2 - v1) and (v3 - v1) + That is : (v2 - v1) X (v3 - v1) + """ + v2 = [v2[j] - v1[j] for j in range(0, 3)] + v3 = [v3[j] - v1[j] for j in range(0, 3)] + return [v3[2] * v2[1] - v3[1] * v2[2], + v3[0] * v2[2] - v3[2] * v2[0], + v3[1] * v2[0] - v3[0] * v2[1]] + + +def best_origin(a, b, lineseg, expr): + """Helper method for polytope_integrate. Currently not used in the main + algorithm. + + Explanation + =========== + + Returns a point on the lineseg whose vector inner product with the + divergence of `expr` yields an expression with the least maximum + total power. + + Parameters + ========== + + a : + Hyperplane parameter denoting direction. + b : + Hyperplane parameter denoting distance. + lineseg : + Line segment on which to find the origin. + expr : + The expression which determines the best point. + + Algorithm(currently works only for 2D use case) + =============================================== + + 1 > Firstly, check for edge cases. Here that would refer to vertical + or horizontal lines. + + 2 > If input expression is a polynomial containing more than one generator + then find out the total power of each of the generators. + + x**2 + 3 + x*y + x**4*y**5 ---> {x: 7, y: 6} + + If expression is a constant value then pick the first boundary point + of the line segment. + + 3 > First check if a point exists on the line segment where the value of + the highest power generator becomes 0. If not check if the value of + the next highest becomes 0. If none becomes 0 within line segment + constraints then pick the first boundary point of the line segment. + Actually, any point lying on the segment can be picked as best origin + in the last case. + + Examples + ======== + + >>> from sympy.integrals.intpoly import best_origin + >>> from sympy.abc import x, y + >>> from sympy import Point, Segment2D + >>> l = Segment2D(Point(0, 3), Point(1, 1)) + >>> expr = x**3*y**7 + >>> best_origin((2, 1), 3, l, expr) + (0, 3.0) + """ + a1, b1 = lineseg.points[0] + + def x_axis_cut(ls): + """Returns the point where the input line segment + intersects the x-axis. + + Parameters + ========== + + ls : + Line segment + """ + p, q = ls.points + if p.y.is_zero: + return tuple(p) + elif q.y.is_zero: + return tuple(q) + elif p.y/q.y < S.Zero: + return p.y * (p.x - q.x)/(q.y - p.y) + p.x, S.Zero + else: + return () + + def y_axis_cut(ls): + """Returns the point where the input line segment + intersects the y-axis. + + Parameters + ========== + + ls : + Line segment + """ + p, q = ls.points + if p.x.is_zero: + return tuple(p) + elif q.x.is_zero: + return tuple(q) + elif p.x/q.x < S.Zero: + return S.Zero, p.x * (p.y - q.y)/(q.x - p.x) + p.y + else: + return () + + gens = (x, y) + power_gens = {} + + for i in gens: + power_gens[i] = S.Zero + + if len(gens) > 1: + # Special case for vertical and horizontal lines + if len(gens) == 2: + if a[0] == 0: + if y_axis_cut(lineseg): + return S.Zero, b/a[1] + else: + return a1, b1 + elif a[1] == 0: + if x_axis_cut(lineseg): + return b/a[0], S.Zero + else: + return a1, b1 + + if isinstance(expr, Expr): # Find the sum total of power of each + if expr.is_Add: # generator and store in a dictionary. + for monomial in expr.args: + if monomial.is_Pow: + if monomial.args[0] in gens: + power_gens[monomial.args[0]] += monomial.args[1] + else: + for univariate in monomial.args: + term_type = len(univariate.args) + if term_type == 0 and univariate in gens: + power_gens[univariate] += 1 + elif term_type == 2 and univariate.args[0] in gens: + power_gens[univariate.args[0]] +=\ + univariate.args[1] + elif expr.is_Mul: + for term in expr.args: + term_type = len(term.args) + if term_type == 0 and term in gens: + power_gens[term] += 1 + elif term_type == 2 and term.args[0] in gens: + power_gens[term.args[0]] += term.args[1] + elif expr.is_Pow: + power_gens[expr.args[0]] = expr.args[1] + elif expr.is_Symbol: + power_gens[expr] += 1 + else: # If `expr` is a constant take first vertex of the line segment. + return a1, b1 + + # TODO : This part is quite hacky. Should be made more robust with + # TODO : respect to symbol names and scalable w.r.t higher dimensions. + power_gens = sorted(power_gens.items(), key=lambda k: str(k[0])) + if power_gens[0][1] >= power_gens[1][1]: + if y_axis_cut(lineseg): + x0 = (S.Zero, b / a[1]) + elif x_axis_cut(lineseg): + x0 = (b / a[0], S.Zero) + else: + x0 = (a1, b1) + else: + if x_axis_cut(lineseg): + x0 = (b/a[0], S.Zero) + elif y_axis_cut(lineseg): + x0 = (S.Zero, b/a[1]) + else: + x0 = (a1, b1) + else: + x0 = (b/a[0]) + return x0 + + +def decompose(expr, separate=False): + """Decomposes an input polynomial into homogeneous ones of + smaller or equal degree. + + Explanation + =========== + + Returns a dictionary with keys as the degree of the smaller + constituting polynomials. Values are the constituting polynomials. + + Parameters + ========== + + expr : Expr + Polynomial(SymPy expression). + separate : bool + If True then simply return a list of the constituent monomials + If not then break up the polynomial into constituent homogeneous + polynomials. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.integrals.intpoly import decompose + >>> decompose(x**2 + x*y + x + y + x**3*y**2 + y**5) + {1: x + y, 2: x**2 + x*y, 5: x**3*y**2 + y**5} + >>> decompose(x**2 + x*y + x + y + x**3*y**2 + y**5, True) + {x, x**2, y, y**5, x*y, x**3*y**2} + """ + poly_dict = {} + + if isinstance(expr, Expr) and not expr.is_number: + if expr.is_Symbol: + poly_dict[1] = expr + elif expr.is_Add: + symbols = expr.atoms(Symbol) + degrees = [(sum(degree_list(monom, *symbols)), monom) + for monom in expr.args] + if separate: + return {monom[1] for monom in degrees} + else: + for monom in degrees: + degree, term = monom + if poly_dict.get(degree): + poly_dict[degree] += term + else: + poly_dict[degree] = term + elif expr.is_Pow: + _, degree = expr.args + poly_dict[degree] = expr + else: # Now expr can only be of `Mul` type + degree = 0 + for term in expr.args: + term_type = len(term.args) + if term_type == 0 and term.is_Symbol: + degree += 1 + elif term_type == 2: + degree += term.args[1] + poly_dict[degree] = expr + else: + poly_dict[0] = expr + + if separate: + return set(poly_dict.values()) + return poly_dict + + +def point_sort(poly, normal=None, clockwise=True): + """Returns the same polygon with points sorted in clockwise or + anti-clockwise order. + + Note that it's necessary for input points to be sorted in some order + (clockwise or anti-clockwise) for the integration algorithm to work. + As a convention algorithm has been implemented keeping clockwise + orientation in mind. + + Parameters + ========== + + poly: + 2D or 3D Polygon. + normal : optional + The normal of the plane which the 3-Polytope is a part of. + clockwise : bool, optional + Returns points sorted in clockwise order if True and + anti-clockwise if False. + + Examples + ======== + + >>> from sympy.integrals.intpoly import point_sort + >>> from sympy import Point + >>> point_sort([Point(0, 0), Point(1, 0), Point(1, 1)]) + [Point2D(1, 1), Point2D(1, 0), Point2D(0, 0)] + """ + pts = poly.vertices if isinstance(poly, Polygon) else poly + n = len(pts) + if n < 2: + return list(pts) + + order = S.One if clockwise else S.NegativeOne + dim = len(pts[0]) + if dim == 2: + center = Point(sum((vertex.x for vertex in pts)) / n, + sum((vertex.y for vertex in pts)) / n) + else: + center = Point(sum((vertex.x for vertex in pts)) / n, + sum((vertex.y for vertex in pts)) / n, + sum((vertex.z for vertex in pts)) / n) + + def compare(a, b): + if a.x - center.x >= S.Zero and b.x - center.x < S.Zero: + return -order + elif a.x - center.x < 0 and b.x - center.x >= 0: + return order + elif a.x - center.x == 0 and b.x - center.x == 0: + if a.y - center.y >= 0 or b.y - center.y >= 0: + return -order if a.y > b.y else order + return -order if b.y > a.y else order + + det = (a.x - center.x) * (b.y - center.y) -\ + (b.x - center.x) * (a.y - center.y) + if det < 0: + return -order + elif det > 0: + return order + + first = (a.x - center.x) * (a.x - center.x) +\ + (a.y - center.y) * (a.y - center.y) + second = (b.x - center.x) * (b.x - center.x) +\ + (b.y - center.y) * (b.y - center.y) + return -order if first > second else order + + def compare3d(a, b): + det = cross_product(center, a, b) + dot_product = sum(det[i] * normal[i] for i in range(0, 3)) + if dot_product < 0: + return -order + elif dot_product > 0: + return order + + return sorted(pts, key=cmp_to_key(compare if dim==2 else compare3d)) + + +def norm(point): + """Returns the Euclidean norm of a point from origin. + + Parameters + ========== + + point: + This denotes a point in the dimension_al spac_e. + + Examples + ======== + + >>> from sympy.integrals.intpoly import norm + >>> from sympy import Point + >>> norm(Point(2, 7)) + sqrt(53) + """ + half = S.Half + if isinstance(point, (list, tuple)): + return sum(coord ** 2 for coord in point) ** half + elif isinstance(point, Point): + if isinstance(point, Point2D): + return (point.x ** 2 + point.y ** 2) ** half + else: + return (point.x ** 2 + point.y ** 2 + point.z) ** half + elif isinstance(point, dict): + return sum(i**2 for i in point.values()) ** half + + +def intersection(geom_1, geom_2, intersection_type): + """Returns intersection between geometric objects. + + Explanation + =========== + + Note that this function is meant for use in integration_reduction and + at that point in the calling function the lines denoted by the segments + surely intersect within segment boundaries. Coincident lines are taken + to be non-intersecting. Also, the hyperplane intersection for 2D case is + also implemented. + + Parameters + ========== + + geom_1, geom_2: + The input line segments. + + Examples + ======== + + >>> from sympy.integrals.intpoly import intersection + >>> from sympy import Point, Segment2D + >>> l1 = Segment2D(Point(1, 1), Point(3, 5)) + >>> l2 = Segment2D(Point(2, 0), Point(2, 5)) + >>> intersection(l1, l2, "segment2D") + (2, 3) + >>> p1 = ((-1, 0), 0) + >>> p2 = ((0, 1), 1) + >>> intersection(p1, p2, "plane2D") + (0, 1) + """ + if intersection_type[:-2] == "segment": + if intersection_type == "segment2D": + x1, y1 = geom_1.points[0] + x2, y2 = geom_1.points[1] + x3, y3 = geom_2.points[0] + x4, y4 = geom_2.points[1] + elif intersection_type == "segment3D": + x1, y1, z1 = geom_1.points[0] + x2, y2, z2 = geom_1.points[1] + x3, y3, z3 = geom_2.points[0] + x4, y4, z4 = geom_2.points[1] + + denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) + if denom: + t1 = x1 * y2 - y1 * x2 + t2 = x3 * y4 - x4 * y3 + return (S(t1 * (x3 - x4) - t2 * (x1 - x2)) / denom, + S(t1 * (y3 - y4) - t2 * (y1 - y2)) / denom) + if intersection_type[:-2] == "plane": + if intersection_type == "plane2D": # Intersection of hyperplanes + a1x, a1y = geom_1[0] + a2x, a2y = geom_2[0] + b1, b2 = geom_1[1], geom_2[1] + + denom = a1x * a2y - a2x * a1y + if denom: + return (S(b1 * a2y - b2 * a1y) / denom, + S(b2 * a1x - b1 * a2x) / denom) + + +def is_vertex(ent): + """If the input entity is a vertex return True. + + Parameter + ========= + + ent : + Denotes a geometric entity representing a point. + + Examples + ======== + + >>> from sympy import Point + >>> from sympy.integrals.intpoly import is_vertex + >>> is_vertex((2, 3)) + True + >>> is_vertex((2, 3, 6)) + True + >>> is_vertex(Point(2, 3)) + True + """ + if isinstance(ent, tuple): + if len(ent) in [2, 3]: + return True + elif isinstance(ent, Point): + return True + return False + + +def plot_polytope(poly): + """Plots the 2D polytope using the functions written in plotting + module which in turn uses matplotlib backend. + + Parameter + ========= + + poly: + Denotes a 2-Polytope. + """ + from sympy.plotting.plot import Plot, List2DSeries + + xl = [vertex.x for vertex in poly.vertices] + yl = [vertex.y for vertex in poly.vertices] + + xl.append(poly.vertices[0].x) # Closing the polygon + yl.append(poly.vertices[0].y) + + l2ds = List2DSeries(xl, yl) + p = Plot(l2ds, axes='label_axes=True') + p.show() + + +def plot_polynomial(expr): + """Plots the polynomial using the functions written in + plotting module which in turn uses matplotlib backend. + + Parameter + ========= + + expr: + Denotes a polynomial(SymPy expression). + """ + from sympy.plotting.plot import plot3d, plot + gens = expr.free_symbols + if len(gens) == 2: + plot3d(expr) + else: + plot(expr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/laplace.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/laplace.py new file mode 100644 index 0000000000000000000000000000000000000000..604c4a2711440f13c62f0d778e382e4daaf33148 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/laplace.py @@ -0,0 +1,2377 @@ +"""Laplace Transforms""" +import sys +import sympy +from sympy.core import S, pi, I +from sympy.core.add import Add +from sympy.core.cache import cacheit +from sympy.core.expr import Expr +from sympy.core.function import ( + AppliedUndef, Derivative, expand, expand_complex, expand_mul, expand_trig, + Lambda, WildFunction, diff, Subs) +from sympy.core.mul import Mul, prod +from sympy.core.relational import ( + _canonical, Ge, Gt, Lt, Unequality, Eq, Ne, Relational) +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy, symbols, Wild +from sympy.functions.elementary.complexes import ( + re, im, arg, Abs, polar_lift, periodic_argument) +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.hyperbolic import cosh, coth, sinh, asinh +from sympy.functions.elementary.miscellaneous import Max, Min, sqrt +from sympy.functions.elementary.piecewise import ( + Piecewise, piecewise_exclusive) +from sympy.functions.elementary.trigonometric import cos, sin, atan, sinc +from sympy.functions.special.bessel import besseli, besselj, besselk, bessely +from sympy.functions.special.delta_functions import DiracDelta, Heaviside +from sympy.functions.special.error_functions import erf, erfc, Ei +from sympy.functions.special.gamma_functions import ( + digamma, gamma, lowergamma, uppergamma) +from sympy.functions.special.singularity_functions import SingularityFunction +from sympy.integrals import integrate, Integral +from sympy.integrals.transforms import ( + _simplify, IntegralTransform, IntegralTransformError) +from sympy.logic.boolalg import to_cnf, conjuncts, disjuncts, Or, And +from sympy.matrices.matrixbase import MatrixBase +from sympy.polys.matrices.linsolve import _lin_eq2dict +from sympy.polys.polyerrors import PolynomialError +from sympy.polys.polyroots import roots +from sympy.polys.polytools import Poly +from sympy.polys.rationaltools import together +from sympy.polys.rootoftools import RootSum +from sympy.utilities.exceptions import ( + sympy_deprecation_warning, SymPyDeprecationWarning, ignore_warnings) +from sympy.utilities.misc import debugf + +_LT_level = 0 + + +def DEBUG_WRAP(func): + def wrap(*args, **kwargs): + from sympy import SYMPY_DEBUG + global _LT_level + + if not SYMPY_DEBUG: + return func(*args, **kwargs) + + if _LT_level == 0: + print('\n' + '-'*78, file=sys.stderr) + print('-LT- %s%s%s' % (' '*_LT_level, func.__name__, args), + file=sys.stderr) + _LT_level += 1 + if ( + func.__name__ == '_laplace_transform_integration' or + func.__name__ == '_inverse_laplace_transform_integration'): + sympy.SYMPY_DEBUG = False + print('**** %sIntegrating ...' % (' '*_LT_level), file=sys.stderr) + result = func(*args, **kwargs) + sympy.SYMPY_DEBUG = True + else: + result = func(*args, **kwargs) + _LT_level -= 1 + print('-LT- %s---> %s' % (' '*_LT_level, result), file=sys.stderr) + if _LT_level == 0: + print('-'*78 + '\n', file=sys.stderr) + return result + return wrap + + +def _debug(text): + from sympy import SYMPY_DEBUG + + if SYMPY_DEBUG: + print('-LT- %s%s' % (' '*_LT_level, text), file=sys.stderr) + + +def _simplifyconds(expr, s, a): + r""" + Naively simplify some conditions occurring in ``expr``, + given that `\operatorname{Re}(s) > a`. + + Examples + ======== + + >>> from sympy.integrals.laplace import _simplifyconds + >>> from sympy.abc import x + >>> from sympy import sympify as S + >>> _simplifyconds(abs(x**2) < 1, x, 1) + False + >>> _simplifyconds(abs(x**2) < 1, x, 2) + False + >>> _simplifyconds(abs(x**2) < 1, x, 0) + Abs(x**2) < 1 + >>> _simplifyconds(abs(1/x**2) < 1, x, 1) + True + >>> _simplifyconds(S(1) < abs(x), x, 1) + True + >>> _simplifyconds(S(1) < abs(1/x), x, 1) + False + + >>> from sympy import Ne + >>> _simplifyconds(Ne(1, x**3), x, 1) + True + >>> _simplifyconds(Ne(1, x**3), x, 2) + True + >>> _simplifyconds(Ne(1, x**3), x, 0) + Ne(1, x**3) + """ + + def power(ex): + if ex == s: + return 1 + if ex.is_Pow and ex.base == s: + return ex.exp + return None + + def bigger(ex1, ex2): + """ Return True only if |ex1| > |ex2|, False only if |ex1| < |ex2|. + Else return None. """ + if ex1.has(s) and ex2.has(s): + return None + if isinstance(ex1, Abs): + ex1 = ex1.args[0] + if isinstance(ex2, Abs): + ex2 = ex2.args[0] + if ex1.has(s): + return bigger(1/ex2, 1/ex1) + n = power(ex2) + if n is None: + return None + try: + if n > 0 and (Abs(ex1) <= Abs(a)**n) == S.true: + return False + if n < 0 and (Abs(ex1) >= Abs(a)**n) == S.true: + return True + except TypeError: + return None + + def replie(x, y): + """ simplify x < y """ + if (not (x.is_positive or isinstance(x, Abs)) + or not (y.is_positive or isinstance(y, Abs))): + return (x < y) + r = bigger(x, y) + if r is not None: + return not r + return (x < y) + + def replue(x, y): + b = bigger(x, y) + if b in (True, False): + return True + return Unequality(x, y) + + def repl(ex, *args): + if ex in (True, False): + return bool(ex) + return ex.replace(*args) + + from sympy.simplify.radsimp import collect_abs + expr = collect_abs(expr) + expr = repl(expr, Lt, replie) + expr = repl(expr, Gt, lambda x, y: replie(y, x)) + expr = repl(expr, Unequality, replue) + return S(expr) + + +@DEBUG_WRAP +def expand_dirac_delta(expr): + """ + Expand an expression involving DiractDelta to get it as a linear + combination of DiracDelta functions. + """ + return _lin_eq2dict(expr, expr.atoms(DiracDelta)) + + +@DEBUG_WRAP +def _laplace_transform_integration(f, t, s_, *, simplify): + """ The backend function for doing Laplace transforms by integration. + + This backend assumes that the frontend has already split sums + such that `f` is to an addition anymore. + """ + s = Dummy('s') + + if f.has(DiracDelta): + return None + + F = integrate(f*exp(-s*t), (t, S.Zero, S.Infinity)) + + if not F.has(Integral): + return _simplify(F.subs(s, s_), simplify), S.NegativeInfinity, S.true + + if not F.is_Piecewise: + return None + + F, cond = F.args[0] + if F.has(Integral): + return None + + def process_conds(conds): + """ Turn ``conds`` into a strip and auxiliary conditions. """ + from sympy.solvers.inequalities import _solve_inequality + a = S.NegativeInfinity + aux = S.true + conds = conjuncts(to_cnf(conds)) + p, q, w1, w2, w3, w4, w5 = symbols( + 'p q w1 w2 w3 w4 w5', cls=Wild, exclude=[s]) + patterns = ( + p*Abs(arg((s + w3)*q)) < w2, + p*Abs(arg((s + w3)*q)) <= w2, + Abs(periodic_argument((s + w3)**p*q, w1)) < w2, + Abs(periodic_argument((s + w3)**p*q, w1)) <= w2, + Abs(periodic_argument((polar_lift(s + w3))**p*q, w1)) < w2, + Abs(periodic_argument((polar_lift(s + w3))**p*q, w1)) <= w2) + for c in conds: + a_ = S.Infinity + aux_ = [] + for d in disjuncts(c): + if d.is_Relational and s in d.rhs.free_symbols: + d = d.reversed + if d.is_Relational and isinstance(d, (Ge, Gt)): + d = d.reversedsign + for pat in patterns: + m = d.match(pat) + if m: + break + if m and m[q].is_positive and m[w2]/m[p] == pi/2: + d = -re(s + m[w3]) < 0 + m = d.match(p - cos(w1*Abs(arg(s*w5))*w2)*Abs(s**w3)**w4 < 0) + if not m: + m = d.match( + cos(p - Abs(periodic_argument(s**w1*w5, q))*w2) * + Abs(s**w3)**w4 < 0) + if not m: + m = d.match( + p - cos( + Abs(periodic_argument(polar_lift(s)**w1*w5, q))*w2 + )*Abs(s**w3)**w4 < 0) + if m and all(m[wild].is_positive for wild in [ + w1, w2, w3, w4, w5]): + d = re(s) > m[p] + d_ = d.replace( + re, lambda x: x.expand().as_real_imag()[0]).subs(re(s), t) + if ( + not d.is_Relational or d.rel_op in ('==', '!=') + or d_.has(s) or not d_.has(t)): + aux_ += [d] + continue + soln = _solve_inequality(d_, t) + if not soln.is_Relational or soln.rel_op in ('==', '!='): + aux_ += [d] + continue + if soln.lts == t: + return None + else: + a_ = Min(soln.lts, a_) + if a_ is not S.Infinity: + a = Max(a_, a) + else: + aux = And(aux, Or(*aux_)) + return a, aux.canonical if aux.is_Relational else aux + + conds = [process_conds(c) for c in disjuncts(cond)] + conds2 = [x for x in conds if x[1] != + S.false and x[0] is not S.NegativeInfinity] + if not conds2: + conds2 = [x for x in conds if x[1] != S.false] + conds = list(ordered(conds2)) + + def cnt(expr): + if expr in (True, False): + return 0 + return expr.count_ops() + conds.sort(key=lambda x: (-x[0], cnt(x[1]))) + + if not conds: + return None + a, aux = conds[0] # XXX is [0] always the right one? + + def sbs(expr): + return expr.subs(s, s_) + if simplify: + F = _simplifyconds(F, s, a) + aux = _simplifyconds(aux, s, a) + return _simplify(F.subs(s, s_), simplify), sbs(a), _canonical(sbs(aux)) + + +@DEBUG_WRAP +def _laplace_deep_collect(f, t): + """ + This is an internal helper function that traverses through the expression + tree of `f(t)` and collects arguments. The purpose of it is that + anything like `f(w*t-1*t-c)` will be written as `f((w-1)*t-c)` such that + it can match `f(a*t+b)`. + """ + if not isinstance(f, Expr): + return f + if (p := f.as_poly(t)) is not None: + return p.as_expr() + func = f.func + args = [_laplace_deep_collect(arg, t) for arg in f.args] + return func(*args) + + +@cacheit +def _laplace_build_rules(): + """ + This is an internal helper function that returns the table of Laplace + transform rules in terms of the time variable `t` and the frequency + variable `s`. It is used by ``_laplace_apply_rules``. Each entry is a + tuple containing: + + (time domain pattern, + frequency-domain replacement, + condition for the rule to be applied, + convergence plane, + preparation function) + + The preparation function is a function with one argument that is applied + to the expression before matching. For most rules it should be + ``_laplace_deep_collect``. + """ + t = Dummy('t') + s = Dummy('s') + a = Wild('a', exclude=[t]) + b = Wild('b', exclude=[t]) + n = Wild('n', exclude=[t]) + tau = Wild('tau', exclude=[t]) + omega = Wild('omega', exclude=[t]) + def dco(f): return _laplace_deep_collect(f, t) + _debug('_laplace_build_rules is building rules') + + laplace_transform_rules = [ + (a, a/s, + S.true, S.Zero, dco), # 4.2.1 + (DiracDelta(a*t-b), exp(-s*b/a)/Abs(a), + Or(And(a > 0, b >= 0), And(a < 0, b <= 0)), + S.NegativeInfinity, dco), # Not in Bateman54 + (DiracDelta(a*t-b), S(0), + Or(And(a < 0, b >= 0), And(a > 0, b <= 0)), + S.NegativeInfinity, dco), # Not in Bateman54 + (Heaviside(a*t-b), exp(-s*b/a)/s, + And(a > 0, b > 0), S.Zero, dco), # 4.4.1 + (Heaviside(a*t-b), (1-exp(-s*b/a))/s, + And(a < 0, b < 0), S.Zero, dco), # 4.4.1 + (Heaviside(a*t-b), 1/s, + And(a > 0, b <= 0), S.Zero, dco), # 4.4.1 + (Heaviside(a*t-b), 0, + And(a < 0, b > 0), S.Zero, dco), # 4.4.1 + (t, 1/s**2, + S.true, S.Zero, dco), # 4.2.3 + (1/(a*t+b), -exp(-b/a*s)*Ei(-b/a*s)/a, + Abs(arg(b/a)) < pi, S.Zero, dco), # 4.2.6 + (1/sqrt(a*t+b), sqrt(a*pi/s)*exp(b/a*s)*erfc(sqrt(b/a*s))/a, + Abs(arg(b/a)) < pi, S.Zero, dco), # 4.2.18 + ((a*t+b)**(-S(3)/2), + 2*b**(-S(1)/2)-2*(pi*s/a)**(S(1)/2)*exp(b/a*s) * erfc(sqrt(b/a*s))/a, + Abs(arg(b/a)) < pi, S.Zero, dco), # 4.2.20 + (sqrt(t)/(t+b), sqrt(pi/s)-pi*sqrt(b)*exp(b*s)*erfc(sqrt(b*s)), + Abs(arg(b)) < pi, S.Zero, dco), # 4.2.22 + (1/(a*sqrt(t) + t**(3/2)), pi*a**(S(1)/2)*exp(a*s)*erfc(sqrt(a*s)), + S.true, S.Zero, dco), # Not in Bateman54 + (t**n, gamma(n+1)/s**(n+1), + n > -1, S.Zero, dco), # 4.3.1 + ((a*t+b)**n, uppergamma(n+1, b/a*s)*exp(-b/a*s)/s**(n+1)/a, + And(n > -1, Abs(arg(b/a)) < pi), S.Zero, dco), # 4.3.4 + (t**n/(t+a), a**n*gamma(n+1)*uppergamma(-n, a*s), + And(n > -1, Abs(arg(a)) < pi), S.Zero, dco), # 4.3.7 + (exp(a*t-tau), exp(-tau)/(s-a), + S.true, re(a), dco), # 4.5.1 + (t*exp(a*t-tau), exp(-tau)/(s-a)**2, + S.true, re(a), dco), # 4.5.2 + (t**n*exp(a*t), gamma(n+1)/(s-a)**(n+1), + re(n) > -1, re(a), dco), # 4.5.3 + (exp(-a*t**2), sqrt(pi/4/a)*exp(s**2/4/a)*erfc(s/sqrt(4*a)), + re(a) > 0, S.Zero, dco), # 4.5.21 + (t*exp(-a*t**2), + 1/(2*a)-2/sqrt(pi)/(4*a)**(S(3)/2)*s*erfc(s/sqrt(4*a)), + re(a) > 0, S.Zero, dco), # 4.5.22 + (exp(-a/t), 2*sqrt(a/s)*besselk(1, 2*sqrt(a*s)), + re(a) >= 0, S.Zero, dco), # 4.5.25 + (sqrt(t)*exp(-a/t), + S(1)/2*sqrt(pi/s**3)*(1+2*sqrt(a*s))*exp(-2*sqrt(a*s)), + re(a) >= 0, S.Zero, dco), # 4.5.26 + (exp(-a/t)/sqrt(t), sqrt(pi/s)*exp(-2*sqrt(a*s)), + re(a) >= 0, S.Zero, dco), # 4.5.27 + (exp(-a/t)/(t*sqrt(t)), sqrt(pi/a)*exp(-2*sqrt(a*s)), + re(a) > 0, S.Zero, dco), # 4.5.28 + (t**n*exp(-a/t), 2*(a/s)**((n+1)/2)*besselk(n+1, 2*sqrt(a*s)), + re(a) > 0, S.Zero, dco), # 4.5.29 + # TODO: rules with sqrt(a*t) and sqrt(a/t) have stopped working after + # changes to as_base_exp + # (exp(-2*sqrt(a*t)), + # s**(-1)-sqrt(pi*a)*s**(-S(3)/2)*exp(a/s) * erfc(sqrt(a/s)), + # Abs(arg(a)) < pi, S.Zero, dco), # 4.5.31 + # (exp(-2*sqrt(a*t))/sqrt(t), (pi/s)**(S(1)/2)*exp(a/s)*erfc(sqrt(a/s)), + # Abs(arg(a)) < pi, S.Zero, dco), # 4.5.33 + (exp(-a*exp(-t)), a**(-s)*lowergamma(s, a), + S.true, S.Zero, dco), # 4.5.36 + (exp(-a*exp(t)), a**s*uppergamma(-s, a), + re(a) > 0, S.Zero, dco), # 4.5.37 + (log(a*t), -log(exp(S.EulerGamma)*s/a)/s, + a > 0, S.Zero, dco), # 4.6.1 + (log(1+a*t), -exp(s/a)/s*Ei(-s/a), + Abs(arg(a)) < pi, S.Zero, dco), # 4.6.4 + (log(a*t+b), (log(b)-exp(s/b/a)/s*a*Ei(-s/b))/s*a, + And(a > 0, Abs(arg(b)) < pi), S.Zero, dco), # 4.6.5 + (log(t)/sqrt(t), -sqrt(pi/s)*log(4*s*exp(S.EulerGamma)), + S.true, S.Zero, dco), # 4.6.9 + (t**n*log(t), gamma(n+1)*s**(-n-1)*(digamma(n+1)-log(s)), + re(n) > -1, S.Zero, dco), # 4.6.11 + (log(a*t)**2, (log(exp(S.EulerGamma)*s/a)**2+pi**2/6)/s, + a > 0, S.Zero, dco), # 4.6.13 + (sin(omega*t), omega/(s**2+omega**2), + S.true, Abs(im(omega)), dco), # 4,7,1 + (Abs(sin(omega*t)), omega/(s**2+omega**2)*coth(pi*s/2/omega), + omega > 0, S.Zero, dco), # 4.7.2 + (sin(omega*t)/t, atan(omega/s), + S.true, Abs(im(omega)), dco), # 4.7.16 + (sin(omega*t)**2/t, log(1+4*omega**2/s**2)/4, + S.true, 2*Abs(im(omega)), dco), # 4.7.17 + (sin(omega*t)**2/t**2, + omega*atan(2*omega/s)-s*log(1+4*omega**2/s**2)/4, + S.true, 2*Abs(im(omega)), dco), # 4.7.20 + # (sin(2*sqrt(a*t)), sqrt(pi*a)/s/sqrt(s)*exp(-a/s), + # S.true, S.Zero, dco), # 4.7.32 + # (sin(2*sqrt(a*t))/t, pi*erf(sqrt(a/s)), + # S.true, S.Zero, dco), # 4.7.34 + (cos(omega*t), s/(s**2+omega**2), + S.true, Abs(im(omega)), dco), # 4.7.43 + (cos(omega*t)**2, (s**2+2*omega**2)/(s**2+4*omega**2)/s, + S.true, 2*Abs(im(omega)), dco), # 4.7.45 + # (sqrt(t)*cos(2*sqrt(a*t)), sqrt(pi)/2*s**(-S(5)/2)*(s-2*a)*exp(-a/s), + # S.true, S.Zero, dco), # 4.7.66 + # (cos(2*sqrt(a*t))/sqrt(t), sqrt(pi/s)*exp(-a/s), + # S.true, S.Zero, dco), # 4.7.67 + (sin(a*t)*sin(b*t), 2*a*b*s/(s**2+(a+b)**2)/(s**2+(a-b)**2), + S.true, Abs(im(a))+Abs(im(b)), dco), # 4.7.78 + (cos(a*t)*sin(b*t), b*(s**2-a**2+b**2)/(s**2+(a+b)**2)/(s**2+(a-b)**2), + S.true, Abs(im(a))+Abs(im(b)), dco), # 4.7.79 + (cos(a*t)*cos(b*t), s*(s**2+a**2+b**2)/(s**2+(a+b)**2)/(s**2+(a-b)**2), + S.true, Abs(im(a))+Abs(im(b)), dco), # 4.7.80 + (sinh(a*t), a/(s**2-a**2), + S.true, Abs(re(a)), dco), # 4.9.1 + (cosh(a*t), s/(s**2-a**2), + S.true, Abs(re(a)), dco), # 4.9.2 + (sinh(a*t)**2, 2*a**2/(s**3-4*a**2*s), + S.true, 2*Abs(re(a)), dco), # 4.9.3 + (cosh(a*t)**2, (s**2-2*a**2)/(s**3-4*a**2*s), + S.true, 2*Abs(re(a)), dco), # 4.9.4 + (sinh(a*t)/t, log((s+a)/(s-a))/2, + S.true, Abs(re(a)), dco), # 4.9.12 + (t**n*sinh(a*t), gamma(n+1)/2*((s-a)**(-n-1)-(s+a)**(-n-1)), + n > -2, Abs(a), dco), # 4.9.18 + (t**n*cosh(a*t), gamma(n+1)/2*((s-a)**(-n-1)+(s+a)**(-n-1)), + n > -1, Abs(a), dco), # 4.9.19 + # TODO + # (sinh(2*sqrt(a*t)), sqrt(pi*a)/s/sqrt(s)*exp(a/s), + # S.true, S.Zero, dco), # 4.9.34 + # (cosh(2*sqrt(a*t)), 1/s+sqrt(pi*a)/s/sqrt(s)*exp(a/s)*erf(sqrt(a/s)), + # S.true, S.Zero, dco), # 4.9.35 + # ( + # sqrt(t)*sinh(2*sqrt(a*t)), + # pi**(S(1)/2)*s**(-S(5)/2)*(s/2+a) * + # exp(a/s)*erf(sqrt(a/s))-a**(S(1)/2)*s**(-2), + # S.true, S.Zero, dco), # 4.9.36 + # (sqrt(t)*cosh(2*sqrt(a*t)), pi**(S(1)/2)*s**(-S(5)/2)*(s/2+a)*exp(a/s), + # S.true, S.Zero, dco), # 4.9.37 + # (sinh(2*sqrt(a*t))/sqrt(t), + # pi**(S(1)/2)*s**(-S(1)/2)*exp(a/s) * erf(sqrt(a/s)), + # S.true, S.Zero, dco), # 4.9.38 + # (cosh(2*sqrt(a*t))/sqrt(t), pi**(S(1)/2)*s**(-S(1)/2)*exp(a/s), + # S.true, S.Zero, dco), # 4.9.39 + # (sinh(sqrt(a*t))**2/sqrt(t), pi**(S(1)/2)/2*s**(-S(1)/2)*(exp(a/s)-1), + # S.true, S.Zero, dco), # 4.9.40 + # (cosh(sqrt(a*t))**2/sqrt(t), pi**(S(1)/2)/2*s**(-S(1)/2)*(exp(a/s)+1), + # S.true, S.Zero, dco), # 4.9.41 + (erf(a*t), exp(s**2/(2*a)**2)*erfc(s/(2*a))/s, + 4*Abs(arg(a)) < pi, S.Zero, dco), # 4.12.2 + # (erf(sqrt(a*t)), sqrt(a)/sqrt(s+a)/s, + # S.true, Max(S.Zero, -re(a)), dco), # 4.12.4 + # (exp(a*t)*erf(sqrt(a*t)), sqrt(a)/sqrt(s)/(s-a), + # S.true, Max(S.Zero, re(a)), dco), # 4.12.5 + # (erf(sqrt(a/t)/2), (1-exp(-sqrt(a*s)))/s, + # re(a) > 0, S.Zero, dco), # 4.12.6 + # (erfc(sqrt(a*t)), (sqrt(s+a)-sqrt(a))/sqrt(s+a)/s, + # S.true, -re(a), dco), # 4.12.9 + # (exp(a*t)*erfc(sqrt(a*t)), 1/(s+sqrt(a*s)), + # S.true, S.Zero, dco), # 4.12.10 + # (erfc(sqrt(a/t)/2), exp(-sqrt(a*s))/s, + # re(a) > 0, S.Zero, dco), # 4.2.11 + (besselj(n, a*t), a**n/(sqrt(s**2+a**2)*(s+sqrt(s**2+a**2))**n), + re(n) > -1, Abs(im(a)), dco), # 4.14.1 + (t**b*besselj(n, a*t), + 2**n/sqrt(pi)*gamma(n+S.Half)*a**n*(s**2+a**2)**(-n-S.Half), + And(re(n) > -S.Half, Eq(b, n)), Abs(im(a)), dco), # 4.14.7 + (t**b*besselj(n, a*t), + 2**(n+1)/sqrt(pi)*gamma(n+S(3)/2)*a**n*s*(s**2+a**2)**(-n-S(3)/2), + And(re(n) > -1, Eq(b, n+1)), Abs(im(a)), dco), # 4.14.8 + # (besselj(0, 2*sqrt(a*t)), exp(-a/s)/s, + # S.true, S.Zero, dco), # 4.14.25 + # (t**(b)*besselj(n, 2*sqrt(a*t)), a**(n/2)*s**(-n-1)*exp(-a/s), + # And(re(n) > -1, Eq(b, n*S.Half)), S.Zero, dco), # 4.14.30 + (besselj(0, a*sqrt(t**2+b*t)), + exp(b*s-b*sqrt(s**2+a**2))/sqrt(s**2+a**2), + Abs(arg(b)) < pi, Abs(im(a)), dco), # 4.15.19 + (besseli(n, a*t), a**n/(sqrt(s**2-a**2)*(s+sqrt(s**2-a**2))**n), + re(n) > -1, Abs(re(a)), dco), # 4.16.1 + (t**b*besseli(n, a*t), + 2**n/sqrt(pi)*gamma(n+S.Half)*a**n*(s**2-a**2)**(-n-S.Half), + And(re(n) > -S.Half, Eq(b, n)), Abs(re(a)), dco), # 4.16.6 + (t**b*besseli(n, a*t), + 2**(n+1)/sqrt(pi)*gamma(n+S(3)/2)*a**n*s*(s**2-a**2)**(-n-S(3)/2), + And(re(n) > -1, Eq(b, n+1)), Abs(re(a)), dco), # 4.16.7 + # (t**(b)*besseli(n, 2*sqrt(a*t)), a**(n/2)*s**(-n-1)*exp(a/s), + # And(re(n) > -1, Eq(b, n*S.Half)), S.Zero, dco), # 4.16.18 + (bessely(0, a*t), -2/pi*asinh(s/a)/sqrt(s**2+a**2), + S.true, Abs(im(a)), dco), # 4.15.44 + (besselk(0, a*t), log((s + sqrt(s**2-a**2))/a)/(sqrt(s**2-a**2)), + S.true, -re(a), dco) # 4.16.23 + ] + return laplace_transform_rules, t, s + + +@DEBUG_WRAP +def _laplace_rule_timescale(f, t, s): + """ + This function applies the time-scaling rule of the Laplace transform in + a straight-forward way. For example, if it gets ``(f(a*t), t, s)``, it will + compute ``LaplaceTransform(f(t)/a, t, s/a)`` if ``a>0``. + """ + + a = Wild('a', exclude=[t]) + g = WildFunction('g', nargs=1) + ma1 = f.match(g) + if ma1: + arg = ma1[g].args[0].collect(t) + ma2 = arg.match(a*t) + if ma2 and ma2[a].is_positive and ma2[a] != 1: + _debug(' rule: time scaling (4.1.4)') + r, pr, cr = _laplace_transform( + 1/ma2[a]*ma1[g].func(t), t, s/ma2[a], simplify=False) + return (r, pr, cr) + return None + + +@DEBUG_WRAP +def _laplace_rule_heaviside(f, t, s): + """ + This function deals with time-shifted Heaviside step functions. If the time + shift is positive, it applies the time-shift rule of the Laplace transform. + For example, if it gets ``(Heaviside(t-a)*f(t), t, s)``, it will compute + ``exp(-a*s)*LaplaceTransform(f(t+a), t, s)``. + + If the time shift is negative, the Heaviside function is simply removed + as it means nothing to the Laplace transform. + + The function does not remove a factor ``Heaviside(t)``; this is done by + the simple rules. + """ + + a = Wild('a', exclude=[t]) + y = Wild('y') + g = Wild('g') + if ma1 := f.match(Heaviside(y) * g): + if ma2 := ma1[y].match(t - a): + if ma2[a].is_positive: + _debug(' rule: time shift (4.1.4)') + r, pr, cr = _laplace_transform( + ma1[g].subs(t, t + ma2[a]), t, s, simplify=False) + return (exp(-ma2[a] * s) * r, pr, cr) + if ma2[a].is_negative: + _debug( + ' rule: Heaviside factor; negative time shift (4.1.4)') + r, pr, cr = _laplace_transform(ma1[g], t, s, simplify=False) + return (r, pr, cr) + if ma2 := ma1[y].match(a - t): + if ma2[a].is_positive: + _debug(' rule: Heaviside window open') + r, pr, cr = _laplace_transform( + (1 - Heaviside(t - ma2[a])) * ma1[g], t, s, simplify=False) + return (r, pr, cr) + if ma2[a].is_negative: + _debug(' rule: Heaviside window closed') + return (0, 0, S.true) + return None + + +@DEBUG_WRAP +def _laplace_rule_exp(f, t, s): + """ + If this function finds a factor ``exp(a*t)``, it applies the + frequency-shift rule of the Laplace transform and adjusts the convergence + plane accordingly. For example, if it gets ``(exp(-a*t)*f(t), t, s)``, it + will compute ``LaplaceTransform(f(t), t, s+a)``. + """ + + a = Wild('a', exclude=[t]) + y = Wild('y') + z = Wild('z') + ma1 = f.match(exp(y)*z) + if ma1: + ma2 = ma1[y].collect(t).match(a*t) + if ma2: + _debug(' rule: multiply with exp (4.1.5)') + r, pr, cr = _laplace_transform(ma1[z], t, s-ma2[a], + simplify=False) + return (r, pr+re(ma2[a]), cr) + return None + + +@DEBUG_WRAP +def _laplace_rule_delta(f, t, s): + """ + If this function finds a factor ``DiracDelta(b*t-a)``, it applies the + masking property of the delta distribution. For example, if it gets + ``(DiracDelta(t-a)*f(t), t, s)``, it will return + ``(f(a)*exp(-a*s), -a, True)``. + """ + # This rule is not in Bateman54 + + a = Wild('a', exclude=[t]) + b = Wild('b', exclude=[t]) + + y = Wild('y') + z = Wild('z') + ma1 = f.match(DiracDelta(y)*z) + if ma1 and not ma1[z].has(DiracDelta): + ma2 = ma1[y].collect(t).match(b*t-a) + if ma2: + _debug(' rule: multiply with DiracDelta') + loc = ma2[a]/ma2[b] + if re(loc) >= 0 and im(loc) == 0: + fn = exp(-ma2[a]/ma2[b]*s)*ma1[z] + if fn.has(sin, cos): + # Then it may be possible that a sinc() is present in the + # term; let's try this: + fn = fn.rewrite(sinc).ratsimp() + n, d = [x.subs(t, ma2[a]/ma2[b]) for x in fn.as_numer_denom()] + if d != 0: + return (n/d/ma2[b], S.NegativeInfinity, S.true) + else: + return None + else: + return (0, S.NegativeInfinity, S.true) + if ma1[y].is_polynomial(t): + ro = roots(ma1[y], t) + if ro != {} and set(ro.values()) == {1}: + slope = diff(ma1[y], t) + r = Add( + *[exp(-x*s)*ma1[z].subs(t, s)/slope.subs(t, x) + for x in list(ro.keys()) if im(x) == 0 and re(x) >= 0]) + return (r, S.NegativeInfinity, S.true) + return None + + +@DEBUG_WRAP +def _laplace_trig_split(fn): + """ + Helper function for `_laplace_rule_trig`. This function returns two terms + `f` and `g`. `f` contains all product terms with sin, cos, sinh, cosh in + them; `g` contains everything else. + """ + trigs = [S.One] + other = [S.One] + for term in Mul.make_args(fn): + if term.has(sin, cos, sinh, cosh, exp): + trigs.append(term) + else: + other.append(term) + f = Mul(*trigs) + g = Mul(*other) + return f, g + + +@DEBUG_WRAP +def _laplace_trig_expsum(f, t): + """ + Helper function for `_laplace_rule_trig`. This function expects the `f` + from `_laplace_trig_split`. It returns two lists `xm` and `xn`. `xm` is + a list of dictionaries with keys `k` and `a` representing a function + `k*exp(a*t)`. `xn` is a list of all terms that cannot be brought into + that form, which may happen, e.g., when a trigonometric function has + another function in its argument. + """ + c1 = Wild('c1', exclude=[t]) + c0 = Wild('c0', exclude=[t]) + p = Wild('p', exclude=[t]) + xm = [] + xn = [] + + x1 = f.rewrite(exp).expand() + + for term in Add.make_args(x1): + if not term.has(t): + xm.append({'k': term, 'a': 0, re: 0, im: 0}) + continue + term = _laplace_deep_collect(term.powsimp(combine='exp'), t) + + if (r := term.match(p*exp(c1*t+c0))) is not None: + xm.append({ + 'k': r[p]*exp(r[c0]), 'a': r[c1], + re: re(r[c1]), im: im(r[c1])}) + else: + xn.append(term) + return xm, xn + + +@DEBUG_WRAP +def _laplace_trig_ltex(xm, t, s): + """ + Helper function for `_laplace_rule_trig`. This function takes the list of + exponentials `xm` from `_laplace_trig_expsum` and simplifies complex + conjugate and real symmetric poles. It returns the result as a sum and + the convergence plane. + """ + results = [] + planes = [] + + def _simpc(coeffs): + nc = coeffs.copy() + for k in range(len(nc)): + ri = nc[k].as_real_imag() + if ri[0].has(im): + nc[k] = nc[k].rewrite(cos) + else: + nc[k] = (ri[0] + I*ri[1]).rewrite(cos) + return nc + + def _quadpole(t1, k1, k2, k3, s): + a, k0, a_r, a_i = t1['a'], t1['k'], t1[re], t1[im] + nc = [ + k0 + k1 + k2 + k3, + a*(k0 + k1 - k2 - k3) - 2*I*a_i*k1 + 2*I*a_i*k2, + ( + a**2*(-k0 - k1 - k2 - k3) + + a*(4*I*a_i*k0 + 4*I*a_i*k3) + + 4*a_i**2*k0 + 4*a_i**2*k3), + ( + a**3*(-k0 - k1 + k2 + k3) + + a**2*(4*I*a_i*k0 + 2*I*a_i*k1 - 2*I*a_i*k2 - 4*I*a_i*k3) + + a*(4*a_i**2*k0 - 4*a_i**2*k3)) + ] + dc = [ + S.One, S.Zero, 2*a_i**2 - 2*a_r**2, + S.Zero, a_i**4 + 2*a_i**2*a_r**2 + a_r**4] + n = Add( + *[x*s**y for x, y in zip(_simpc(nc), range(len(nc))[::-1])]) + d = Add( + *[x*s**y for x, y in zip(dc, range(len(dc))[::-1])]) + return n/d + + def _ccpole(t1, k1, s): + a, k0, a_r, a_i = t1['a'], t1['k'], t1[re], t1[im] + nc = [k0 + k1, -a*k0 - a*k1 + 2*I*a_i*k0] + dc = [S.One, -2*a_r, a_i**2 + a_r**2] + n = Add( + *[x*s**y for x, y in zip(_simpc(nc), range(len(nc))[::-1])]) + d = Add( + *[x*s**y for x, y in zip(dc, range(len(dc))[::-1])]) + return n/d + + def _rspole(t1, k2, s): + a, k0, a_r, a_i = t1['a'], t1['k'], t1[re], t1[im] + nc = [k0 + k2, a*k0 - a*k2 - 2*I*a_i*k0] + dc = [S.One, -2*I*a_i, -a_i**2 - a_r**2] + n = Add( + *[x*s**y for x, y in zip(_simpc(nc), range(len(nc))[::-1])]) + d = Add( + *[x*s**y for x, y in zip(dc, range(len(dc))[::-1])]) + return n/d + + def _sypole(t1, k3, s): + a, k0 = t1['a'], t1['k'] + nc = [k0 + k3, a*(k0 - k3)] + dc = [S.One, S.Zero, -a**2] + n = Add( + *[x*s**y for x, y in zip(_simpc(nc), range(len(nc))[::-1])]) + d = Add( + *[x*s**y for x, y in zip(dc, range(len(dc))[::-1])]) + return n/d + + def _simplepole(t1, s): + a, k0 = t1['a'], t1['k'] + n = k0 + d = s - a + return n/d + + while len(xm) > 0: + t1 = xm.pop() + i_imagsym = None + i_realsym = None + i_pointsym = None + # The following code checks all remaining poles. If t1 is a pole at + # a+b*I, then we check for a-b*I, -a+b*I, and -a-b*I, and + # assign the respective indices to i_imagsym, i_realsym, i_pointsym. + # -a-b*I / i_pointsym only applies if both a and b are != 0. + for i in range(len(xm)): + real_eq = t1[re] == xm[i][re] + realsym = t1[re] == -xm[i][re] + imag_eq = t1[im] == xm[i][im] + imagsym = t1[im] == -xm[i][im] + if realsym and imagsym and t1[re] != 0 and t1[im] != 0: + i_pointsym = i + elif realsym and imag_eq and t1[re] != 0: + i_realsym = i + elif real_eq and imagsym and t1[im] != 0: + i_imagsym = i + + # The next part looks for four possible pole constellations: + # quad: a+b*I, a-b*I, -a+b*I, -a-b*I + # cc: a+b*I, a-b*I (a may be zero) + # quad: a+b*I, -a+b*I (b may be zero) + # point: a+b*I, -a-b*I (a!=0 and b!=0 is needed, but that has been + # asserted when finding i_pointsym above.) + # If none apply, then t1 is a simple pole. + if ( + i_imagsym is not None and i_realsym is not None + and i_pointsym is not None): + results.append( + _quadpole(t1, + xm[i_imagsym]['k'], xm[i_realsym]['k'], + xm[i_pointsym]['k'], s)) + planes.append(Abs(re(t1['a']))) + # The three additional poles have now been used; to pop them + # easily we have to do it from the back. + indices_to_pop = [i_imagsym, i_realsym, i_pointsym] + indices_to_pop.sort(reverse=True) + for i in indices_to_pop: + xm.pop(i) + elif i_imagsym is not None: + results.append(_ccpole(t1, xm[i_imagsym]['k'], s)) + planes.append(t1[re]) + xm.pop(i_imagsym) + elif i_realsym is not None: + results.append(_rspole(t1, xm[i_realsym]['k'], s)) + planes.append(Abs(t1[re])) + xm.pop(i_realsym) + elif i_pointsym is not None: + results.append(_sypole(t1, xm[i_pointsym]['k'], s)) + planes.append(Abs(t1[re])) + xm.pop(i_pointsym) + else: + results.append(_simplepole(t1, s)) + planes.append(t1[re]) + + return Add(*results), Max(*planes) + + +@DEBUG_WRAP +def _laplace_rule_trig(fn, t_, s): + """ + This rule covers trigonometric factors by splitting everything into a + sum of exponential functions and collecting complex conjugate poles and + real symmetric poles. + """ + t = Dummy('t', real=True) + + if not fn.has(sin, cos, sinh, cosh): + return None + + f, g = _laplace_trig_split(fn.subs(t_, t)) + xm, xn = _laplace_trig_expsum(f, t) + + if len(xn) > 0: + # TODO not implemented yet, but also not important + return None + + if not g.has(t): + r, p = _laplace_trig_ltex(xm, t, s) + return g*r, p, S.true + else: + # Just transform `g` and make frequency-shifted copies + planes = [] + results = [] + G, G_plane, G_cond = _laplace_transform(g, t, s, simplify=False) + for x1 in xm: + results.append(x1['k']*G.subs(s, s-x1['a'])) + planes.append(G_plane+re(x1['a'])) + return Add(*results).subs(t, t_), Max(*planes), G_cond + + +@DEBUG_WRAP +def _laplace_rule_diff(f, t, s): + """ + This function looks for derivatives in the time domain and replaces it + by factors of `s` and initial conditions in the frequency domain. For + example, if it gets ``(diff(f(t), t), t, s)``, it will compute + ``s*LaplaceTransform(f(t), t, s) - f(0)``. + """ + + a = Wild('a', exclude=[t]) + n = Wild('n', exclude=[t]) + g = WildFunction('g') + ma1 = f.match(a*Derivative(g, (t, n))) + if ma1 and ma1[n].is_integer: + m = [z.has(t) for z in ma1[g].args] + if sum(m) == 1: + _debug(' rule: time derivative (4.1.8)') + d = [] + for k in range(ma1[n]): + if k == 0: + y = ma1[g].subs(t, 0) + else: + y = Derivative(ma1[g], (t, k)).subs(t, 0) + d.append(s**(ma1[n]-k-1)*y) + r, pr, cr = _laplace_transform(ma1[g], t, s, simplify=False) + return (ma1[a]*(s**ma1[n]*r - Add(*d)), pr, cr) + return None + + +@DEBUG_WRAP +def _laplace_rule_sdiff(f, t, s): + """ + This function looks for multiplications with polynoimials in `t` as they + correspond to differentiation in the frequency domain. For example, if it + gets ``(t*f(t), t, s)``, it will compute + ``-Derivative(LaplaceTransform(f(t), t, s), s)``. + """ + + if f.is_Mul: + pfac = [1] + ofac = [1] + for fac in Mul.make_args(f): + if fac.is_polynomial(t): + pfac.append(fac) + else: + ofac.append(fac) + if len(pfac) > 1: + pex = prod(pfac) + pc = Poly(pex, t).all_coeffs() + N = len(pc) + if N > 1: + oex = prod(ofac) + r_, p_, c_ = _laplace_transform(oex, t, s, simplify=False) + deri = [r_] + d1 = False + try: + d1 = -diff(deri[-1], s) + except ValueError: + d1 = False + if r_.has(LaplaceTransform): + for k in range(N-1): + deri.append((-1)**(k+1)*Derivative(r_, s, k+1)) + elif d1: + deri.append(d1) + for k in range(N-2): + deri.append(-diff(deri[-1], s)) + if d1: + r = Add(*[pc[N-n-1]*deri[n] for n in range(N)]) + return (r, p_, c_) + # We still have to cover the possibility that there is a symbolic positive + # integer exponent. + n = Wild('n', exclude=[t]) + g = Wild('g') + if ma1 := f.match(t**n*g): + if ma1[n].is_integer and ma1[n].is_positive: + r_, p_, c_ = _laplace_transform(ma1[g], t, s, simplify=False) + return (-1)**ma1[n]*diff(r_, (s, ma1[n])), p_, c_ + return None + + +@DEBUG_WRAP +def _laplace_expand(f, t, s): + """ + This function tries to expand its argument with successively stronger + methods: first it will expand on the top level, then it will expand any + multiplications in depth, then it will try all available expansion methods, + and finally it will try to expand trigonometric functions. + + If it can expand, it will then compute the Laplace transform of the + expanded term. + """ + + r = expand(f, deep=False) + if r.is_Add: + return _laplace_transform(r, t, s, simplify=False) + r = expand_mul(f) + if r.is_Add: + return _laplace_transform(r, t, s, simplify=False) + r = expand(f) + if r.is_Add: + return _laplace_transform(r, t, s, simplify=False) + if r != f: + return _laplace_transform(r, t, s, simplify=False) + r = expand(expand_trig(f)) + if r.is_Add: + return _laplace_transform(r, t, s, simplify=False) + return None + + +@DEBUG_WRAP +def _laplace_apply_prog_rules(f, t, s): + """ + This function applies all program rules and returns the result if one + of them gives a result. + """ + + prog_rules = [_laplace_rule_heaviside, _laplace_rule_delta, + _laplace_rule_timescale, _laplace_rule_exp, + _laplace_rule_trig, + _laplace_rule_diff, _laplace_rule_sdiff] + + for p_rule in prog_rules: + if (L := p_rule(f, t, s)) is not None: + return L + return None + + +@DEBUG_WRAP +def _laplace_apply_simple_rules(f, t, s): + """ + This function applies all simple rules and returns the result if one + of them gives a result. + """ + simple_rules, t_, s_ = _laplace_build_rules() + prep_old = '' + prep_f = '' + for t_dom, s_dom, check, plane, prep in simple_rules: + if prep_old != prep: + prep_f = prep(f.subs({t: t_})) + prep_old = prep + ma = prep_f.match(t_dom) + if ma: + try: + c = check.xreplace(ma) + except TypeError: + # This may happen if the time function has imaginary + # numbers in it. Then we give up. + continue + if c == S.true: + return (s_dom.xreplace(ma).subs({s_: s}), + plane.xreplace(ma), S.true) + return None + + +@DEBUG_WRAP +def _piecewise_to_heaviside(f, t): + """ + This function converts a Piecewise expression to an expression written + with Heaviside. It is not exact, but valid in the context of the Laplace + transform. + """ + if not t.is_real: + r = Dummy('r', real=True) + return _piecewise_to_heaviside(f.xreplace({t: r}), r).xreplace({r: t}) + x = piecewise_exclusive(f) + r = [] + for fn, cond in x.args: + # Here we do not need to do many checks because piecewise_exclusive + # has a clearly predictable output. However, if any of the conditions + # is not relative to t, this function just returns the input argument. + if isinstance(cond, Relational) and t in cond.args: + if isinstance(cond, (Eq, Ne)): + # We do not cover this case; these would be single-point + # exceptions that do not play a role in Laplace practice, + # except if they contain Dirac impulses, and then we can + # expect users to not try to use Piecewise for writing it. + return f + else: + r.append(Heaviside(cond.gts - cond.lts)*fn) + elif isinstance(cond, Or) and len(cond.args) == 2: + # Or(t<2, t>4), Or(t>4, t<=2), ... in any order with any <= >= + for c2 in cond.args: + if c2.lhs == t: + r.append(Heaviside(c2.gts - c2.lts)*fn) + else: + return f + elif isinstance(cond, And) and len(cond.args) == 2: + # And(t>2, t<4), And(t>4, t<=2), ... in any order with any <= >= + c0, c1 = cond.args + if c0.lhs == t and c1.lhs == t: + if '>' in c0.rel_op: + c0, c1 = c1, c0 + r.append( + (Heaviside(c1.gts - c1.lts) - + Heaviside(c0.lts - c0.gts))*fn) + else: + return f + else: + return f + return Add(*r) + + +def laplace_correspondence(f, fdict, /): + """ + This helper function takes a function `f` that is the result of a + ``laplace_transform`` or an ``inverse_laplace_transform``. It replaces all + unevaluated ``LaplaceTransform(y(t), t, s)`` by `Y(s)` for any `s` and + all ``InverseLaplaceTransform(Y(s), s, t)`` by `y(t)` for any `t` if + ``fdict`` contains a correspondence ``{y: Y}``. + + Parameters + ========== + + f : sympy expression + Expression containing unevaluated ``LaplaceTransform`` or + ``LaplaceTransform`` objects. + fdict : dictionary + Dictionary containing one or more function correspondences, + e.g., ``{x: X, y: Y}`` meaning that ``X`` and ``Y`` are the + Laplace transforms of ``x`` and ``y``, respectively. + + Examples + ======== + + >>> from sympy import laplace_transform, diff, Function + >>> from sympy import laplace_correspondence, inverse_laplace_transform + >>> from sympy.abc import t, s + >>> y = Function("y") + >>> Y = Function("Y") + >>> z = Function("z") + >>> Z = Function("Z") + >>> f = laplace_transform(diff(y(t), t, 1) + z(t), t, s, noconds=True) + >>> laplace_correspondence(f, {y: Y, z: Z}) + s*Y(s) + Z(s) - y(0) + >>> f = inverse_laplace_transform(Y(s), s, t) + >>> laplace_correspondence(f, {y: Y}) + y(t) + """ + p = Wild('p') + s = Wild('s') + t = Wild('t') + a = Wild('a') + if ( + not isinstance(f, Expr) + or (not f.has(LaplaceTransform) + and not f.has(InverseLaplaceTransform))): + return f + for y, Y in fdict.items(): + if ( + (m := f.match(LaplaceTransform(y(a), t, s))) is not None + and m[a] == m[t]): + return Y(m[s]) + if ( + (m := f.match(InverseLaplaceTransform(Y(a), s, t, p))) + is not None + and m[a] == m[s]): + return y(m[t]) + func = f.func + args = [laplace_correspondence(arg, fdict) for arg in f.args] + return func(*args) + + +def laplace_initial_conds(f, t, fdict, /): + """ + This helper function takes a function `f` that is the result of a + ``laplace_transform``. It takes an fdict of the form ``{y: [1, 4, 2]}``, + where the values in the list are the initial value, the initial slope, the + initial second derivative, etc., of the function `y(t)`, and replaces all + unevaluated initial conditions. + + Parameters + ========== + + f : sympy expression + Expression containing initial conditions of unevaluated functions. + t : sympy expression + Variable for which the initial conditions are to be applied. + fdict : dictionary + Dictionary containing a list of initial conditions for every + function, e.g., ``{y: [0, 1, 2], x: [3, 4, 5]}``. The order + of derivatives is ascending, so `0`, `1`, `2` are `y(0)`, `y'(0)`, + and `y''(0)`, respectively. + + Examples + ======== + + >>> from sympy import laplace_transform, diff, Function + >>> from sympy import laplace_correspondence, laplace_initial_conds + >>> from sympy.abc import t, s + >>> y = Function("y") + >>> Y = Function("Y") + >>> f = laplace_transform(diff(y(t), t, 3), t, s, noconds=True) + >>> g = laplace_correspondence(f, {y: Y}) + >>> laplace_initial_conds(g, t, {y: [2, 4, 8, 16, 32]}) + s**3*Y(s) - 2*s**2 - 4*s - 8 + """ + for y, ic in fdict.items(): + for k in range(len(ic)): + if k == 0: + f = f.replace(y(0), ic[0]) + elif k == 1: + f = f.replace(Subs(Derivative(y(t), t), t, 0), ic[1]) + else: + f = f.replace(Subs(Derivative(y(t), (t, k)), t, 0), ic[k]) + return f + + +@DEBUG_WRAP +def _laplace_transform(fn, t_, s_, *, simplify): + """ + Front-end function of the Laplace transform. It tries to apply all known + rules recursively, and if everything else fails, it tries to integrate. + """ + + terms_t = Add.make_args(fn) + terms_s = [] + terms = [] + planes = [] + conditions = [] + + for ff in terms_t: + k, ft = ff.as_independent(t_, as_Add=False) + if ft.has(SingularityFunction): + _terms = Add.make_args(ft.rewrite(Heaviside)) + for _term in _terms: + k1, f1 = _term.as_independent(t_, as_Add=False) + terms.append((k*k1, f1)) + elif ft.func == Piecewise and not ft.has(DiracDelta(t_)): + _terms = Add.make_args(_piecewise_to_heaviside(ft, t_)) + for _term in _terms: + k1, f1 = _term.as_independent(t_, as_Add=False) + terms.append((k*k1, f1)) + else: + terms.append((k, ft)) + + for k, ft in terms: + if ft.has(SingularityFunction): + r = (LaplaceTransform(ft, t_, s_), S.NegativeInfinity, True) + else: + if ft.has(Heaviside(t_)) and not ft.has(DiracDelta(t_)): + # For t>=0, Heaviside(t)=1 can be used, except if there is also + # a DiracDelta(t) present, in which case removing Heaviside(t) + # is unnecessary because _laplace_rule_delta can deal with it. + ft = ft.subs(Heaviside(t_), 1) + if ( + (r := _laplace_apply_simple_rules(ft, t_, s_)) + is not None or + (r := _laplace_apply_prog_rules(ft, t_, s_)) + is not None or + (r := _laplace_expand(ft, t_, s_)) is not None): + pass + elif any(undef.has(t_) for undef in ft.atoms(AppliedUndef)): + # If there are undefined functions f(t) then integration is + # unlikely to do anything useful so we skip it and given an + # unevaluated LaplaceTransform. + r = (LaplaceTransform(ft, t_, s_), S.NegativeInfinity, True) + elif (r := _laplace_transform_integration( + ft, t_, s_, simplify=simplify)) is not None: + pass + else: + r = (LaplaceTransform(ft, t_, s_), S.NegativeInfinity, True) + (ri_, pi_, ci_) = r + terms_s.append(k*ri_) + planes.append(pi_) + conditions.append(ci_) + + result = Add(*terms_s) + if simplify: + result = result.simplify(doit=False) + plane = Max(*planes) + condition = And(*conditions) + + return result, plane, condition + + +class LaplaceTransform(IntegralTransform): + """ + Class representing unevaluated Laplace transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute Laplace transforms, see the :func:`laplace_transform` + docstring. + + If this is called with ``.doit()``, it returns the Laplace transform as an + expression. If it is called with ``.doit(noconds=False)``, it returns a + tuple containing the same expression, a convergence plane, and conditions. + """ + + _name = 'Laplace' + + def _compute_transform(self, f, t, s, **hints): + _simplify = hints.get('simplify', False) + LT = _laplace_transform_integration(f, t, s, simplify=_simplify) + return LT + + def _as_integral(self, f, t, s): + return Integral(f*exp(-s*t), (t, S.Zero, S.Infinity)) + + def doit(self, **hints): + """ + Try to evaluate the transform in closed form. + + Explanation + =========== + + Standard hints are the following: + - ``noconds``: if True, do not return convergence conditions. The + default setting is `True`. + - ``simplify``: if True, it simplifies the final result. The + default setting is `False`. + """ + _noconds = hints.get('noconds', True) + _simplify = hints.get('simplify', False) + + debugf('[LT doit] (%s, %s, %s)', (self.function, + self.function_variable, + self.transform_variable)) + + t_ = self.function_variable + s_ = self.transform_variable + fn = self.function + + r = _laplace_transform(fn, t_, s_, simplify=_simplify) + + if _noconds: + return r[0] + else: + return r + + +def laplace_transform(f, t, s, legacy_matrix=True, **hints): + r""" + Compute the Laplace Transform `F(s)` of `f(t)`, + + .. math :: F(s) = \int_{0^{-}}^\infty e^{-st} f(t) \mathrm{d}t. + + Explanation + =========== + + For all sensible functions, this converges absolutely in a + half-plane + + .. math :: a < \operatorname{Re}(s) + + This function returns ``(F, a, cond)`` where ``F`` is the Laplace + transform of ``f``, `a` is the half-plane of convergence, and `cond` are + auxiliary convergence conditions. + + The implementation is rule-based, and if you are interested in which + rules are applied, and whether integration is attempted, you can switch + debug information on by setting ``sympy.SYMPY_DEBUG=True``. The numbers + of the rules in the debug information (and the code) refer to Bateman's + Tables of Integral Transforms [1]. + + The lower bound is `0-`, meaning that this bound should be approached + from the lower side. This is only necessary if distributions are involved. + At present, it is only done if `f(t)` contains ``DiracDelta``, in which + case the Laplace transform is computed implicitly as + + .. math :: + F(s) = \lim_{\tau\to 0^{-}} \int_{\tau}^\infty e^{-st} + f(t) \mathrm{d}t + + by applying rules. + + If the Laplace transform cannot be fully computed in closed form, this + function returns expressions containing unevaluated + :class:`LaplaceTransform` objects. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. If + ``noconds=True``, only `F` will be returned (i.e. not ``cond``, and also + not the plane ``a``). + + .. deprecated:: 1.9 + Legacy behavior for matrices where ``laplace_transform`` with + ``noconds=False`` (the default) returns a Matrix whose elements are + tuples. The behavior of ``laplace_transform`` for matrices will change + in a future release of SymPy to return a tuple of the transformed + Matrix and the convergence conditions for the matrix as a whole. Use + ``legacy_matrix=False`` to enable the new behavior. + + Examples + ======== + + >>> from sympy import DiracDelta, exp, laplace_transform + >>> from sympy.abc import t, s, a + >>> laplace_transform(t**4, t, s) + (24/s**5, 0, True) + >>> laplace_transform(t**a, t, s) + (gamma(a + 1)/(s*s**a), 0, re(a) > -1) + >>> laplace_transform(DiracDelta(t)-a*exp(-a*t), t, s, simplify=True) + (s/(a + s), -re(a), True) + + There are also helper functions that make it easy to solve differential + equations by Laplace transform. For example, to solve + + .. math :: m x''(t) + d x'(t) + k x(t) = 0 + + with initial value `0` and initial derivative `v`: + + >>> from sympy import Function, laplace_correspondence, diff, solve + >>> from sympy import laplace_initial_conds, inverse_laplace_transform + >>> from sympy.abc import d, k, m, v + >>> x = Function('x') + >>> X = Function('X') + >>> f = m*diff(x(t), t, 2) + d*diff(x(t), t) + k*x(t) + >>> F = laplace_transform(f, t, s, noconds=True) + >>> F = laplace_correspondence(F, {x: X}) + >>> F = laplace_initial_conds(F, t, {x: [0, v]}) + >>> F + d*s*X(s) + k*X(s) + m*(s**2*X(s) - v) + >>> Xs = solve(F, X(s))[0] + >>> Xs + m*v/(d*s + k + m*s**2) + >>> inverse_laplace_transform(Xs, s, t) + 2*v*exp(-d*t/(2*m))*sin(t*sqrt((-d**2 + 4*k*m)/m**2)/2)*Heaviside(t)/sqrt((-d**2 + 4*k*m)/m**2) + + References + ========== + + .. [1] Erdelyi, A. (ed.), Tables of Integral Transforms, Volume 1, + Bateman Manuscript Prooject, McGraw-Hill (1954), available: + https://resolver.caltech.edu/CaltechAUTHORS:20140123-101456353 + + See Also + ======== + + inverse_laplace_transform, mellin_transform, fourier_transform + hankel_transform, inverse_hankel_transform + + """ + + _noconds = hints.get('noconds', False) + _simplify = hints.get('simplify', False) + + if isinstance(f, MatrixBase) and hasattr(f, 'applyfunc'): + + conds = not hints.get('noconds', False) + + if conds and legacy_matrix: + adt = 'deprecated-laplace-transform-matrix' + sympy_deprecation_warning( + """ +Calling laplace_transform() on a Matrix with noconds=False (the default) is +deprecated. Either noconds=True or use legacy_matrix=False to get the new +behavior. + """, + deprecated_since_version='1.9', + active_deprecations_target=adt, + ) + # Temporarily disable the deprecation warning for non-Expr objects + # in Matrix + with ignore_warnings(SymPyDeprecationWarning): + return f.applyfunc( + lambda fij: laplace_transform(fij, t, s, **hints)) + else: + elements_trans = [laplace_transform( + fij, t, s, **hints) for fij in f] + if conds: + elements, avals, conditions = zip(*elements_trans) + f_laplace = type(f)(*f.shape, elements) + return f_laplace, Max(*avals), And(*conditions) + else: + return type(f)(*f.shape, elements_trans) + + LT, p, c = LaplaceTransform(f, t, s).doit(noconds=False, + simplify=_simplify) + + if not _noconds: + return LT, p, c + else: + return LT + + +@DEBUG_WRAP +def _inverse_laplace_transform_integration(F, s, t_, plane, *, simplify): + """ The backend function for inverse Laplace transforms. """ + from sympy.integrals.meijerint import meijerint_inversion, _get_coeff_exp + from sympy.integrals.transforms import inverse_mellin_transform + + # There are two strategies we can try: + # 1) Use inverse mellin transform, related by a simple change of variables. + # 2) Use the inversion integral. + + t = Dummy('t', real=True) + + def pw_simp(*args): + """ Simplify a piecewise expression from hyperexpand. """ + if len(args) != 3: + return Piecewise(*args) + arg = args[2].args[0].argument + coeff, exponent = _get_coeff_exp(arg, t) + e1 = args[0].args[0] + e2 = args[1].args[0] + return ( + Heaviside(1/Abs(coeff) - t**exponent)*e1 + + Heaviside(t**exponent - 1/Abs(coeff))*e2) + + if F.is_rational_function(s): + F = F.apart(s) + + if F.is_Add: + f = Add( + *[_inverse_laplace_transform_integration(X, s, t, plane, simplify) + for X in F.args]) + return _simplify(f.subs(t, t_), simplify), True + + try: + f, cond = inverse_mellin_transform(F, s, exp(-t), (None, S.Infinity), + needeval=True, noconds=False) + except IntegralTransformError: + f = None + + if f is None: + f = meijerint_inversion(F, s, t) + if f is None: + return None + if f.is_Piecewise: + f, cond = f.args[0] + if f.has(Integral): + return None + else: + cond = S.true + f = f.replace(Piecewise, pw_simp) + + if f.is_Piecewise: + # many of the functions called below can't work with piecewise + # (b/c it has a bool in args) + return f.subs(t, t_), cond + + u = Dummy('u') + + def simp_heaviside(arg, H0=S.Half): + a = arg.subs(exp(-t), u) + if a.has(t): + return Heaviside(arg, H0) + from sympy.solvers.inequalities import _solve_inequality + rel = _solve_inequality(a > 0, u) + if rel.lts == u: + k = log(rel.gts) + return Heaviside(t + k, H0) + else: + k = log(rel.lts) + return Heaviside(-(t + k), H0) + + f = f.replace(Heaviside, simp_heaviside) + + def simp_exp(arg): + return expand_complex(exp(arg)) + + f = f.replace(exp, simp_exp) + + return _simplify(f.subs(t, t_), simplify), cond + + +@DEBUG_WRAP +def _complete_the_square_in_denom(f, s): + from sympy.simplify.radsimp import fraction + [n, d] = fraction(f) + if d.is_polynomial(s): + cf = d.as_poly(s).all_coeffs() + if len(cf) == 3: + a, b, c = cf + d = a*((s+b/(2*a))**2+c/a-(b/(2*a))**2) + return n/d + + +@cacheit +def _inverse_laplace_build_rules(): + """ + This is an internal helper function that returns the table of inverse + Laplace transform rules in terms of the time variable `t` and the + frequency variable `s`. It is used by `_inverse_laplace_apply_rules`. + """ + s = Dummy('s') + t = Dummy('t') + a = Wild('a', exclude=[s]) + b = Wild('b', exclude=[s]) + c = Wild('c', exclude=[s]) + + _debug('_inverse_laplace_build_rules is building rules') + + def _frac(f, s): + try: + return f.factor(s) + except PolynomialError: + return f + + def same(f): return f + # This list is sorted according to the prep function needed. + _ILT_rules = [ + (a/s, a, S.true, same, 1), + ( + b*(s+a)**(-c), t**(c-1)*exp(-a*t)/gamma(c), + S.true, same, 1), + (1/(s**2+a**2)**2, (sin(a*t) - a*t*cos(a*t))/(2*a**3), + S.true, same, 1), + # The next two rules must be there in that order. For the second + # one, the condition would be a != 0 or, respectively, to take the + # limit a -> 0 after the transform if a == 0. It is much simpler if + # the case a == 0 has its own rule. + (1/(s**b), t**(b - 1)/gamma(b), S.true, same, 1), + (1/(s*(s+a)**b), lowergamma(b, a*t)/(a**b*gamma(b)), + S.true, same, 1) + ] + return _ILT_rules, s, t + + +@DEBUG_WRAP +def _inverse_laplace_apply_simple_rules(f, s, t): + """ + Helper function for the class InverseLaplaceTransform. + """ + if f == 1: + _debug(' rule: 1 o---o DiracDelta()') + return DiracDelta(t), S.true + + _ILT_rules, s_, t_ = _inverse_laplace_build_rules() + _prep = '' + fsubs = f.subs({s: s_}) + + for s_dom, t_dom, check, prep, fac in _ILT_rules: + if _prep != (prep, fac): + _F = prep(fsubs*fac) + _prep = (prep, fac) + ma = _F.match(s_dom) + if ma: + c = check + if c is not S.true: + args = [x.xreplace(ma) for x in c[0]] + c = c[1](*args) + if c == S.true: + return Heaviside(t)*t_dom.xreplace(ma).subs({t_: t}), S.true + + return None + + +@DEBUG_WRAP +def _inverse_laplace_diff(f, s, t, plane): + """ + Helper function for the class InverseLaplaceTransform. + """ + a = Wild('a', exclude=[s]) + n = Wild('n', exclude=[s]) + g = Wild('g') + ma = f.match(a*Derivative(g, (s, n))) + if ma and ma[n].is_integer: + _debug(' rule: t**n*f(t) o---o (-1)**n*diff(F(s), s, n)') + r, c = _inverse_laplace_transform( + ma[g], s, t, plane, simplify=False, dorational=False) + return (-t)**ma[n]*r, c + return None + + +@DEBUG_WRAP +def _inverse_laplace_time_shift(F, s, t, plane): + """ + Helper function for the class InverseLaplaceTransform. + """ + a = Wild('a', exclude=[s]) + g = Wild('g') + + if not F.has(s): + return F*DiracDelta(t), S.true + if not F.has(exp): + return None + + ma1 = F.match(exp(a*s)) + if ma1: + if ma1[a].is_negative: + _debug(' rule: exp(-a*s) o---o DiracDelta(t-a)') + return DiracDelta(t+ma1[a]), S.true + else: + return InverseLaplaceTransform(F, s, t, plane), S.true + + ma1 = F.match(exp(a*s)*g) + if ma1: + if ma1[a].is_negative: + _debug(' rule: exp(-a*s)*F(s) o---o Heaviside(t-a)*f(t-a)') + return _inverse_laplace_transform( + ma1[g], s, t+ma1[a], plane, simplify=False, dorational=True) + else: + return InverseLaplaceTransform(F, s, t, plane), S.true + return None + + +@DEBUG_WRAP +def _inverse_laplace_freq_shift(F, s, t, plane): + """ + Helper function for the class InverseLaplaceTransform. + """ + if not F.has(s): + return F*DiracDelta(t), S.true + if len(args := F.args) == 1: + a = Wild('a', exclude=[s]) + if (ma := args[0].match(s-a)) and re(ma[a]).is_positive: + _debug(' rule: F(s-a) o---o exp(-a*t)*f(t)') + return ( + exp(-ma[a]*t) * + InverseLaplaceTransform(F.func(s), s, t, plane), S.true) + return None + + +@DEBUG_WRAP +def _inverse_laplace_time_diff(F, s, t, plane): + """ + Helper function for the class InverseLaplaceTransform. + """ + n = Wild('n', exclude=[s]) + g = Wild('g') + + ma1 = F.match(s**n*g) + if ma1 and ma1[n].is_integer and ma1[n].is_positive: + _debug(' rule: s**n*F(s) o---o diff(f(t), t, n)') + r, c = _inverse_laplace_transform( + ma1[g], s, t, plane, simplify=False, dorational=True) + r = r.replace(Heaviside(t), 1) + if r.has(InverseLaplaceTransform): + return diff(r, t, ma1[n]), c + else: + return Heaviside(t)*diff(r, t, ma1[n]), c + return None + + +@DEBUG_WRAP +def _inverse_laplace_irrational(fn, s, t, plane): + """ + Helper function for the class InverseLaplaceTransform. + """ + + a = Wild('a', exclude=[s]) + b = Wild('b', exclude=[s]) + m = Wild('m', exclude=[s]) + n = Wild('n', exclude=[s]) + + result = None + condition = S.true + + fa = fn.as_ordered_factors() + + ma = [x.match((a*s**m+b)**n) for x in fa] + + if None in ma: + return None + + constants = S.One + zeros = [] + poles = [] + rest = [] + + for term in ma: + if term[a] == 0: + constants = constants*term + elif term[n].is_positive: + zeros.append(term) + elif term[n].is_negative: + poles.append(term) + else: + rest.append(term) + + # The code below assumes that the poles are sorted in a specific way: + poles = sorted(poles, key=lambda x: (x[n], x[b] != 0, x[b])) + zeros = sorted(zeros, key=lambda x: (x[n], x[b] != 0, x[b])) + + if len(rest) != 0: + return None + + if len(poles) == 1 and len(zeros) == 0: + if poles[0][n] == -1 and poles[0][m] == S.Half: + # 1/(a0*sqrt(s)+b0) == 1/a0 * 1/(sqrt(s)+b0/a0) + a_ = poles[0][b]/poles[0][a] + k_ = 1/poles[0][a]*constants + if a_.is_positive: + result = ( + k_/sqrt(pi)/sqrt(t) - + k_*a_*exp(a_**2*t)*erfc(a_*sqrt(t))) + _debug(' rule 5.3.4') + elif poles[0][n] == -2 and poles[0][m] == S.Half: + # 1/(a0*sqrt(s)+b0)**2 == 1/a0**2 * 1/(sqrt(s)+b0/a0)**2 + a_sq = poles[0][b]/poles[0][a] + a_ = a_sq**2 + k_ = 1/poles[0][a]**2*constants + if a_sq.is_positive: + result = ( + k_*(1 - 2/sqrt(pi)*sqrt(a_)*sqrt(t) + + (1-2*a_*t)*exp(a_*t)*(erf(sqrt(a_)*sqrt(t))-1))) + _debug(' rule 5.3.10') + elif poles[0][n] == -3 and poles[0][m] == S.Half: + # 1/(a0*sqrt(s)+b0)**3 == 1/a0**3 * 1/(sqrt(s)+b0/a0)**3 + a_ = poles[0][b]/poles[0][a] + k_ = 1/poles[0][a]**3*constants + if a_.is_positive: + result = ( + k_*(2/sqrt(pi)*(a_**2*t+1)*sqrt(t) - + a_*t*exp(a_**2*t)*(2*a_**2*t+3)*erfc(a_*sqrt(t)))) + _debug(' rule 5.3.13') + elif poles[0][n] == -4 and poles[0][m] == S.Half: + # 1/(a0*sqrt(s)+b0)**4 == 1/a0**4 * 1/(sqrt(s)+b0/a0)**4 + a_ = poles[0][b]/poles[0][a] + k_ = 1/poles[0][a]**4*constants/3 + if a_.is_positive: + result = ( + k_*(t*(4*a_**4*t**2+12*a_**2*t+3)*exp(a_**2*t) * + erfc(a_*sqrt(t)) - + 2/sqrt(pi)*a_**3*t**(S(5)/2)*(2*a_**2*t+5))) + _debug(' rule 5.3.16') + elif poles[0][n] == -S.Half and poles[0][m] == 2: + # 1/sqrt(a0*s**2+b0) == 1/sqrt(a0) * 1/sqrt(s**2+b0/a0) + a_ = sqrt(poles[0][b]/poles[0][a]) + k_ = 1/sqrt(poles[0][a])*constants + result = (k_*(besselj(0, a_*t))) + _debug(' rule 5.3.35/44') + + elif len(poles) == 1 and len(zeros) == 1: + if ( + poles[0][n] == -3 and poles[0][m] == S.Half and + zeros[0][n] == S.Half and zeros[0][b] == 0): + # sqrt(az*s)/(ap*sqrt(s+bp)**3) + # == sqrt(az)/ap * sqrt(s)/(sqrt(s+bp)**3) + a_ = poles[0][b] + k_ = sqrt(zeros[0][a])/poles[0][a]*constants + result = ( + k_*(2*a_**4*t**2+5*a_**2*t+1)*exp(a_**2*t) * + erfc(a_*sqrt(t)) - 2/sqrt(pi)*a_*(a_**2*t+2)*sqrt(t)) + _debug(' rule 5.3.14') + if ( + poles[0][n] == -1 and poles[0][m] == 1 and + zeros[0][n] == S.Half and zeros[0][m] == 1): + # sqrt(az*s+bz)/(ap*s+bp) + # == sqrt(az)/ap * (sqrt(s+bz/az)/(s+bp/ap)) + a_ = zeros[0][b]/zeros[0][a] + b_ = poles[0][b]/poles[0][a] + k_ = sqrt(zeros[0][a])/poles[0][a]*constants + result = ( + k_*(exp(-a_*t)/sqrt(t)/sqrt(pi)+sqrt(a_-b_) * + exp(-b_*t)*erf(sqrt(a_-b_)*sqrt(t)))) + _debug(' rule 5.3.22') + + elif len(poles) == 2 and len(zeros) == 0: + if ( + poles[0][n] == -1 and poles[0][m] == 1 and + poles[1][n] == -S.Half and poles[1][m] == 1 and + poles[1][b] == 0): + # 1/((a0*s+b0)*sqrt(a1*s)) + # == 1/(a0*sqrt(a1)) * 1/((s+b0/a0)*sqrt(s)) + a_ = -poles[0][b]/poles[0][a] + k_ = 1/sqrt(poles[1][a])/poles[0][a]*constants + if a_.is_positive: + result = (k_/sqrt(a_)*exp(a_*t)*erf(sqrt(a_)*sqrt(t))) + _debug(' rule 5.3.1') + elif ( + poles[0][n] == -1 and poles[0][m] == 1 and poles[0][b] == 0 and + poles[1][n] == -1 and poles[1][m] == S.Half): + # 1/(a0*s*(a1*sqrt(s)+b1)) + # == 1/(a0*a1) * 1/(s*(sqrt(s)+b1/a1)) + a_ = poles[1][b]/poles[1][a] + k_ = 1/poles[0][a]/poles[1][a]/a_*constants + if a_.is_positive: + result = k_*(1-exp(a_**2*t)*erfc(a_*sqrt(t))) + _debug(' rule 5.3.5') + elif ( + poles[0][n] == -1 and poles[0][m] == S.Half and + poles[1][n] == -S.Half and poles[1][m] == 1 and + poles[1][b] == 0): + # 1/((a0*sqrt(s)+b0)*(sqrt(a1*s)) + # == 1/(a0*sqrt(a1)) * 1/((sqrt(s)+b0/a0)"sqrt(s)) + a_ = poles[0][b]/poles[0][a] + k_ = 1/(poles[0][a]*sqrt(poles[1][a]))*constants + if a_.is_positive: + result = k_*exp(a_**2*t)*erfc(a_*sqrt(t)) + _debug(' rule 5.3.7') + elif ( + poles[0][n] == -S(3)/2 and poles[0][m] == 1 and + poles[0][b] == 0 and poles[1][n] == -1 and + poles[1][m] == S.Half): + # 1/((a0**(3/2)*s**(3/2))*(a1*sqrt(s)+b1)) + # == 1/(a0**(3/2)*a1) 1/((s**(3/2))*(sqrt(s)+b1/a1)) + # Note that Bateman54 5.3 (8) is incorrect; there (sqrt(p)+a) + # should be (sqrt(p)+a)**(-1). + a_ = poles[1][b]/poles[1][a] + k_ = 1/(poles[0][a]**(S(3)/2)*poles[1][a])/a_**2*constants + if a_.is_positive: + result = ( + k_*(2/sqrt(pi)*a_*sqrt(t)+exp(a_**2*t)*erfc(a_*sqrt(t))-1)) + _debug(' rule 5.3.8') + elif ( + poles[0][n] == -2 and poles[0][m] == S.Half and + poles[1][n] == -1 and poles[1][m] == 1 and + poles[1][b] == 0): + # 1/((a0*sqrt(s)+b0)**2*a1*s) + # == 1/a0**2/a1 * 1/(sqrt(s)+b0/a0)**2/s + a_sq = poles[0][b]/poles[0][a] + a_ = a_sq**2 + k_ = 1/poles[0][a]**2/poles[1][a]*constants + if a_sq.is_positive: + result = ( + k_*(1/a_ + (2*t-1/a_)*exp(a_*t)*erfc(sqrt(a_)*sqrt(t)) - + 2/sqrt(pi)/sqrt(a_)*sqrt(t))) + _debug(' rule 5.3.11') + elif ( + poles[0][n] == -2 and poles[0][m] == S.Half and + poles[1][n] == -S.Half and poles[1][m] == 1 and + poles[1][b] == 0): + # 1/((a0*sqrt(s)+b0)**2*sqrt(a1*s)) + # == 1/a0**2/sqrt(a1) * 1/(sqrt(s)+b0/a0)**2/sqrt(s) + a_ = poles[0][b]/poles[0][a] + k_ = 1/poles[0][a]**2/sqrt(poles[1][a])*constants + if a_.is_positive: + result = ( + k_*(2/sqrt(pi)*sqrt(t) - + 2*a_*t*exp(a_**2*t)*erfc(a_*sqrt(t)))) + _debug(' rule 5.3.12') + elif ( + poles[0][n] == -3 and poles[0][m] == S.Half and + poles[1][n] == -S.Half and poles[1][m] == 1 and + poles[1][b] == 0): + # 1 / (sqrt(a1*s)*(a0*sqrt(s+b0)**3)) + # == 1/(sqrt(a1)*a0) * 1/(sqrt(s)*(sqrt(s+b0)**3)) + a_ = poles[0][b] + k_ = constants/sqrt(poles[1][a])/poles[0][a] + result = k_*( + (2*a_**2*t+1)*t*exp(a_**2*t)*erfc(a_*sqrt(t)) - + 2/sqrt(pi)*a_*t**(S(3)/2)) + _debug(' rule 5.3.15') + elif ( + poles[0][n] == -1 and poles[0][m] == 1 and + poles[1][n] == -S.Half and poles[1][m] == 1): + # 1 / ( (a0*s+b0)* sqrt(a1*s+b1) ) + # == 1/(sqrt(a1)*a0) * 1 / ( (s+b0/a0)* sqrt(s+b1/a1) ) + a_ = poles[0][b]/poles[0][a] + b_ = poles[1][b]/poles[1][a] + k_ = constants/sqrt(poles[1][a])/poles[0][a] + result = k_*( + 1/sqrt(b_-a_)*exp(-a_*t)*erf(sqrt(b_-a_)*sqrt(t))) + _debug(' rule 5.3.23') + + elif len(poles) == 2 and len(zeros) == 1: + if ( + poles[0][n] == -1 and poles[0][m] == 1 and + poles[1][n] == -1 and poles[1][m] == S.Half and + zeros[0][n] == S.Half and zeros[0][m] == 1 and + zeros[0][b] == 0): + # sqrt(za0*s)/((a0*s+b0)*(a1*sqrt(s)+b1)) + # == sqrt(za0)/(a0*a1) * s/((s+b0/a0)*(sqrt(s)+b1/a1)) + a_sq = poles[1][b]/poles[1][a] + a_ = a_sq**2 + b_ = -poles[0][b]/poles[0][a] + k_ = sqrt(zeros[0][a])/poles[0][a]/poles[1][a]/(a_-b_)*constants + if a_sq.is_positive and b_.is_positive: + result = k_*( + a_*exp(a_*t)*erfc(sqrt(a_)*sqrt(t)) + + sqrt(a_)*sqrt(b_)*exp(b_*t)*erfc(sqrt(b_)*sqrt(t)) - + b_*exp(b_*t)) + _debug(' rule 5.3.6') + elif ( + poles[0][n] == -1 and poles[0][m] == 1 and + poles[0][b] == 0 and poles[1][n] == -1 and + poles[1][m] == S.Half and zeros[0][n] == 1 and + zeros[0][m] == S.Half): + # (az*sqrt(s)+bz)/(a0*s*(a1*sqrt(s)+b1)) + # == az/a0/a1 * (sqrt(z)+bz/az)/(s*(sqrt(s)+b1/a1)) + a_num = zeros[0][b]/zeros[0][a] + a_ = poles[1][b]/poles[1][a] + if a_+a_num == 0: + k_ = zeros[0][a]/poles[0][a]/poles[1][a]*constants + result = k_*( + 2*exp(a_**2*t)*erfc(a_*sqrt(t))-1) + _debug(' rule 5.3.17') + elif ( + poles[1][n] == -1 and poles[1][m] == 1 and + poles[1][b] == 0 and poles[0][n] == -2 and + poles[0][m] == S.Half and zeros[0][n] == 2 and + zeros[0][m] == S.Half): + # (az*sqrt(s)+bz)**2/(a1*s*(a0*sqrt(s)+b0)**2) + # == az**2/a1/a0**2 * (sqrt(z)+bz/az)**2/(s*(sqrt(s)+b0/a0)**2) + a_num = zeros[0][b]/zeros[0][a] + a_ = poles[0][b]/poles[0][a] + if a_+a_num == 0: + k_ = zeros[0][a]**2/poles[1][a]/poles[0][a]**2*constants + result = k_*( + 1 + 8*a_**2*t*exp(a_**2*t)*erfc(a_*sqrt(t)) - + 8/sqrt(pi)*a_*sqrt(t)) + _debug(' rule 5.3.18') + elif ( + poles[1][n] == -1 and poles[1][m] == 1 and + poles[1][b] == 0 and poles[0][n] == -3 and + poles[0][m] == S.Half and zeros[0][n] == 3 and + zeros[0][m] == S.Half): + # (az*sqrt(s)+bz)**3/(a1*s*(a0*sqrt(s)+b0)**3) + # == az**3/a1/a0**3 * (sqrt(z)+bz/az)**3/(s*(sqrt(s)+b0/a0)**3) + a_num = zeros[0][b]/zeros[0][a] + a_ = poles[0][b]/poles[0][a] + if a_+a_num == 0: + k_ = zeros[0][a]**3/poles[1][a]/poles[0][a]**3*constants + result = k_*( + 2*(8*a_**4*t**2+8*a_**2*t+1)*exp(a_**2*t) * + erfc(a_*sqrt(t))-8/sqrt(pi)*a_*sqrt(t)*(2*a_**2*t+1)-1) + _debug(' rule 5.3.19') + + elif len(poles) == 3 and len(zeros) == 0: + if ( + poles[0][n] == -1 and poles[0][b] == 0 and poles[0][m] == 1 and + poles[1][n] == -1 and poles[1][m] == 1 and + poles[2][n] == -S.Half and poles[2][m] == 1): + # 1/((a0*s)*(a1*s+b1)*sqrt(a2*s)) + # == 1/(a0*a1*sqrt(a2)) * 1/((s)*(s+b1/a1)*sqrt(s)) + a_ = -poles[1][b]/poles[1][a] + k_ = 1/poles[0][a]/poles[1][a]/sqrt(poles[2][a])*constants + if a_.is_positive: + result = k_ * ( + a_**(-S(3)/2) * exp(a_*t) * erf(sqrt(a_)*sqrt(t)) - + 2/a_/sqrt(pi)*sqrt(t)) + _debug(' rule 5.3.2') + elif ( + poles[0][n] == -1 and poles[0][m] == 1 and + poles[1][n] == -1 and poles[1][m] == S.Half and + poles[2][n] == -S.Half and poles[2][m] == 1 and + poles[2][b] == 0): + # 1/((a0*s+b0)*(a1*sqrt(s)+b1)*(sqrt(a2)*sqrt(s))) + # == 1/(a0*a1*sqrt(a2)) * 1/((s+b0/a0)*(sqrt(s)+b1/a1)*sqrt(s)) + a_sq = poles[1][b]/poles[1][a] + a_ = a_sq**2 + b_ = -poles[0][b]/poles[0][a] + k_ = ( + 1/poles[0][a]/poles[1][a]/sqrt(poles[2][a]) / + (sqrt(b_)*(a_-b_))) + if a_sq.is_positive and b_.is_positive: + result = k_ * ( + sqrt(b_)*exp(a_*t)*erfc(sqrt(a_)*sqrt(t)) + + sqrt(a_)*exp(b_*t)*erf(sqrt(b_)*sqrt(t)) - + sqrt(b_)*exp(b_*t)) + _debug(' rule 5.3.9') + + if result is None: + return None + else: + return Heaviside(t)*result, condition + + +@DEBUG_WRAP +def _inverse_laplace_early_prog_rules(F, s, t, plane): + """ + Helper function for the class InverseLaplaceTransform. + """ + prog_rules = [_inverse_laplace_irrational] + + for p_rule in prog_rules: + if (r := p_rule(F, s, t, plane)) is not None: + return r + return None + + +@DEBUG_WRAP +def _inverse_laplace_apply_prog_rules(F, s, t, plane): + """ + Helper function for the class InverseLaplaceTransform. + """ + prog_rules = [_inverse_laplace_time_shift, _inverse_laplace_freq_shift, + _inverse_laplace_time_diff, _inverse_laplace_diff, + _inverse_laplace_irrational] + + for p_rule in prog_rules: + if (r := p_rule(F, s, t, plane)) is not None: + return r + return None + + +@DEBUG_WRAP +def _inverse_laplace_expand(fn, s, t, plane): + """ + Helper function for the class InverseLaplaceTransform. + """ + if fn.is_Add: + return None + r = expand(fn, deep=False) + if r.is_Add: + return _inverse_laplace_transform( + r, s, t, plane, simplify=False, dorational=True) + r = expand_mul(fn) + if r.is_Add: + return _inverse_laplace_transform( + r, s, t, plane, simplify=False, dorational=True) + r = expand(fn) + if r.is_Add: + return _inverse_laplace_transform( + r, s, t, plane, simplify=False, dorational=True) + if fn.is_rational_function(s): + r = fn.apart(s).doit() + if r.is_Add: + return _inverse_laplace_transform( + r, s, t, plane, simplify=False, dorational=True) + return None + + +@DEBUG_WRAP +def _inverse_laplace_rational(fn, s, t, plane, *, simplify): + """ + Helper function for the class InverseLaplaceTransform. + """ + x_ = symbols('x_') + f = fn.apart(s) + terms = Add.make_args(f) + terms_t = [] + conditions = [S.true] + for term in terms: + [n, d] = term.as_numer_denom() + dc = d.as_poly(s).all_coeffs() + dc_lead = dc[0] + dc = [x/dc_lead for x in dc] + nc = [x/dc_lead for x in n.as_poly(s).all_coeffs()] + if len(dc) == 1: + N = len(nc)-1 + for c in enumerate(nc): + r = c[1]*DiracDelta(t, N-c[0]) + terms_t.append(r) + elif len(dc) == 2: + r = nc[0]*exp(-dc[1]*t) + terms_t.append(Heaviside(t)*r) + elif len(dc) == 3: + a = dc[1]/2 + b = (dc[2]-a**2).factor() + if len(nc) == 1: + nc = [S.Zero] + nc + l, m = tuple(nc) + if b == 0: + r = (m*t+l*(1-a*t))*exp(-a*t) + else: + hyp = False + if b.is_negative: + b = -b + hyp = True + b2 = list(roots(x_**2-b, x_).keys())[0] + bs = sqrt(b).simplify() + if hyp: + r = ( + l*exp(-a*t)*cosh(b2*t) + (m-a*l) / + bs*exp(-a*t)*sinh(bs*t)) + else: + r = l*exp(-a*t)*cos(b2*t) + (m-a*l)/bs*exp(-a*t)*sin(bs*t) + terms_t.append(Heaviside(t)*r) + else: + ft, cond = _inverse_laplace_transform( + term, s, t, plane, simplify=simplify, dorational=False) + terms_t.append(ft) + conditions.append(cond) + + result = Add(*terms_t) + if simplify: + result = result.simplify(doit=False) + return result, And(*conditions) + + +@DEBUG_WRAP +def _inverse_laplace_transform(fn, s_, t_, plane, *, simplify, dorational): + """ + Front-end function of the inverse Laplace transform. It tries to apply all + known rules recursively. If everything else fails, it tries to integrate. + """ + terms = Add.make_args(fn) + terms_t = [] + conditions = [] + + for term in terms: + if term.has(exp): + # Simplify expressions with exp() such that time-shifted + # expressions have negative exponents in the numerator instead of + # positive exponents in the numerator and denominator; this is a + # (necessary) trick. It will, for example, convert + # (s**2*exp(2*s) + 4*exp(s) - 4)*exp(-2*s)/(s*(s**2 + 1)) into + # (s**2 + 4*exp(-s) - 4*exp(-2*s))/(s*(s**2 + 1)) + term = term.subs(s_, -s_).together().subs(s_, -s_) + k, f = term.as_independent(s_, as_Add=False) + if ( + dorational and term.is_rational_function(s_) and + (r := _inverse_laplace_rational( + f, s_, t_, plane, simplify=simplify)) + is not None or + (r := _inverse_laplace_apply_simple_rules(f, s_, t_)) + is not None or + (r := _inverse_laplace_early_prog_rules(f, s_, t_, plane)) + is not None or + (r := _inverse_laplace_expand(f, s_, t_, plane)) + is not None or + (r := _inverse_laplace_apply_prog_rules(f, s_, t_, plane)) + is not None): + pass + elif any(undef.has(s_) for undef in f.atoms(AppliedUndef)): + # If there are undefined functions f(t) then integration is + # unlikely to do anything useful so we skip it and given an + # unevaluated LaplaceTransform. + r = (InverseLaplaceTransform(f, s_, t_, plane), S.true) + elif ( + r := _inverse_laplace_transform_integration( + f, s_, t_, plane, simplify=simplify)) is not None: + pass + else: + r = (InverseLaplaceTransform(f, s_, t_, plane), S.true) + (ri_, ci_) = r + terms_t.append(k*ri_) + conditions.append(ci_) + + result = Add(*terms_t) + if simplify: + result = result.simplify(doit=False) + condition = And(*conditions) + + return result, condition + + +class InverseLaplaceTransform(IntegralTransform): + """ + Class representing unevaluated inverse Laplace transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute inverse Laplace transforms, see the + :func:`inverse_laplace_transform` docstring. + """ + + _name = 'Inverse Laplace' + _none_sentinel = Dummy('None') + _c = Dummy('c') + + def __new__(cls, F, s, x, plane, **opts): + if plane is None: + plane = InverseLaplaceTransform._none_sentinel + return IntegralTransform.__new__(cls, F, s, x, plane, **opts) + + @property + def fundamental_plane(self): + plane = self.args[3] + if plane is InverseLaplaceTransform._none_sentinel: + plane = None + return plane + + def _compute_transform(self, F, s, t, **hints): + return _inverse_laplace_transform_integration( + F, s, t, self.fundamental_plane, **hints) + + def _as_integral(self, F, s, t): + c = self.__class__._c + return ( + Integral(exp(s*t)*F, (s, c - S.ImaginaryUnit*S.Infinity, + c + S.ImaginaryUnit*S.Infinity)) / + (2*S.Pi*S.ImaginaryUnit)) + + def doit(self, **hints): + """ + Try to evaluate the transform in closed form. + + Explanation + =========== + + Standard hints are the following: + - ``noconds``: if True, do not return convergence conditions. The + default setting is `True`. + - ``simplify``: if True, it simplifies the final result. The + default setting is `False`. + """ + _noconds = hints.get('noconds', True) + _simplify = hints.get('simplify', False) + + debugf('[ILT doit] (%s, %s, %s)', (self.function, + self.function_variable, + self.transform_variable)) + + s_ = self.function_variable + t_ = self.transform_variable + fn = self.function + plane = self.fundamental_plane + + r = _inverse_laplace_transform( + fn, s_, t_, plane, simplify=_simplify, dorational=True) + + if _noconds: + return r[0] + else: + return r + + +def inverse_laplace_transform(F, s, t, plane=None, **hints): + r""" + Compute the inverse Laplace transform of `F(s)`, defined as + + .. math :: + f(t) = \frac{1}{2\pi i} \int_{c-i\infty}^{c+i\infty} e^{st} + F(s) \mathrm{d}s, + + for `c` so large that `F(s)` has no singularites in the + half-plane `\operatorname{Re}(s) > c-\epsilon`. + + Explanation + =========== + + The plane can be specified by + argument ``plane``, but will be inferred if passed as None. + + Under certain regularity conditions, this recovers `f(t)` from its + Laplace Transform `F(s)`, for non-negative `t`, and vice + versa. + + If the integral cannot be computed in closed form, this function returns + an unevaluated :class:`InverseLaplaceTransform` object. + + Note that this function will always assume `t` to be real, + regardless of the SymPy assumption on `t`. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + + Examples + ======== + + >>> from sympy import inverse_laplace_transform, exp, Symbol + >>> from sympy.abc import s, t + >>> a = Symbol('a', positive=True) + >>> inverse_laplace_transform(exp(-a*s)/s, s, t) + Heaviside(-a + t) + + See Also + ======== + + laplace_transform + hankel_transform, inverse_hankel_transform + """ + _noconds = hints.get('noconds', True) + _simplify = hints.get('simplify', False) + + if isinstance(F, MatrixBase) and hasattr(F, 'applyfunc'): + return F.applyfunc( + lambda Fij: inverse_laplace_transform(Fij, s, t, plane, **hints)) + + r, c = InverseLaplaceTransform(F, s, t, plane).doit( + noconds=False, simplify=_simplify) + + if _noconds: + return r + else: + return r, c + + +def _fast_inverse_laplace(e, s, t): + """Fast inverse Laplace transform of rational function including RootSum""" + a, b, n = symbols('a, b, n', cls=Wild, exclude=[s]) + + def _ilt(e): + if not e.has(s): + return e + elif e.is_Add: + return _ilt_add(e) + elif e.is_Mul: + return _ilt_mul(e) + elif e.is_Pow: + return _ilt_pow(e) + elif isinstance(e, RootSum): + return _ilt_rootsum(e) + else: + raise NotImplementedError + + def _ilt_add(e): + return e.func(*map(_ilt, e.args)) + + def _ilt_mul(e): + coeff, expr = e.as_independent(s) + if expr.is_Mul: + raise NotImplementedError + return coeff * _ilt(expr) + + def _ilt_pow(e): + match = e.match((a*s + b)**n) + if match is not None: + nm, am, bm = match[n], match[a], match[b] + if nm.is_Integer and nm < 0: + return t**(-nm-1)*exp(-(bm/am)*t)/(am**-nm*gamma(-nm)) + if nm == 1: + return exp(-(bm/am)*t) / am + raise NotImplementedError + + def _ilt_rootsum(e): + expr = e.fun.expr + [variable] = e.fun.variables + return RootSum(e.poly, Lambda(variable, together(_ilt(expr)))) + + return _ilt(e) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/manualintegrate.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/manualintegrate.py new file mode 100644 index 0000000000000000000000000000000000000000..2908fb33003ba9c22da47e550edcfea2b41a26a0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/manualintegrate.py @@ -0,0 +1,2174 @@ +"""Integration method that emulates by-hand techniques. + +This module also provides functionality to get the steps used to evaluate a +particular integral, in the ``integral_steps`` function. This will return +nested ``Rule`` s representing the integration rules used. + +Each ``Rule`` class represents a (maybe parametrized) integration rule, e.g. +``SinRule`` for integrating ``sin(x)`` and ``ReciprocalSqrtQuadraticRule`` +for integrating ``1/sqrt(a+b*x+c*x**2)``. The ``eval`` method returns the +integration result. + +The ``manualintegrate`` function computes the integral by calling ``eval`` +on the rule returned by ``integral_steps``. + +The integrator can be extended with new heuristics and evaluation +techniques. To do so, extend the ``Rule`` class, implement ``eval`` method, +then write a function that accepts an ``IntegralInfo`` object and returns +either a ``Rule`` instance or ``None``. If the new technique requires a new +match, add the key and call to the antiderivative function to integral_steps. +To enable simple substitutions, add the match to find_substitutions. + +""" + +from __future__ import annotations +from typing import NamedTuple, Type, Callable, Sequence +from abc import ABC, abstractmethod +from dataclasses import dataclass +from collections import defaultdict +from collections.abc import Mapping + +from sympy.core.add import Add +from sympy.core.cache import cacheit +from sympy.core.containers import Dict +from sympy.core.expr import Expr +from sympy.core.function import Derivative +from sympy.core.logic import fuzzy_not +from sympy.core.mul import Mul +from sympy.core.numbers import Integer, Number, E +from sympy.core.power import Pow +from sympy.core.relational import Eq, Ne, Boolean +from sympy.core.singleton import S +from sympy.core.symbol import Dummy, Symbol, Wild +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.hyperbolic import (HyperbolicFunction, csch, + cosh, coth, sech, sinh, tanh, asinh) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (TrigonometricFunction, + cos, sin, tan, cot, csc, sec, acos, asin, atan, acot, acsc, asec) +from sympy.functions.special.delta_functions import Heaviside, DiracDelta +from sympy.functions.special.error_functions import (erf, erfi, fresnelc, + fresnels, Ci, Chi, Si, Shi, Ei, li) +from sympy.functions.special.gamma_functions import uppergamma +from sympy.functions.special.elliptic_integrals import elliptic_e, elliptic_f +from sympy.functions.special.polynomials import (chebyshevt, chebyshevu, + legendre, hermite, laguerre, assoc_laguerre, gegenbauer, jacobi, + OrthogonalPolynomial) +from sympy.functions.special.zeta_functions import polylog +from .integrals import Integral +from sympy.logic.boolalg import And +from sympy.ntheory.factor_ import primefactors +from sympy.polys.polytools import degree, lcm_list, gcd_list, Poly +from sympy.simplify.radsimp import fraction +from sympy.simplify.simplify import simplify +from sympy.solvers.solvers import solve +from sympy.strategies.core import switch, do_one, null_safe, condition +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import debug + + +@dataclass +class Rule(ABC): + integrand: Expr + variable: Symbol + + @abstractmethod + def eval(self) -> Expr: + pass + + @abstractmethod + def contains_dont_know(self) -> bool: + pass + + +@dataclass +class AtomicRule(Rule, ABC): + """A simple rule that does not depend on other rules""" + def contains_dont_know(self) -> bool: + return False + + +@dataclass +class ConstantRule(AtomicRule): + """integrate(a, x) -> a*x""" + def eval(self) -> Expr: + return self.integrand * self.variable + + +@dataclass +class ConstantTimesRule(Rule): + """integrate(a*f(x), x) -> a*integrate(f(x), x)""" + constant: Expr + other: Expr + substep: Rule + + def eval(self) -> Expr: + return self.constant * self.substep.eval() + + def contains_dont_know(self) -> bool: + return self.substep.contains_dont_know() + + +@dataclass +class PowerRule(AtomicRule): + """integrate(x**a, x)""" + base: Expr + exp: Expr + + def eval(self) -> Expr: + return Piecewise( + ((self.base**(self.exp + 1))/(self.exp + 1), Ne(self.exp, -1)), + (log(self.base), True), + ) + + +@dataclass +class NestedPowRule(AtomicRule): + """integrate((x**a)**b, x)""" + base: Expr + exp: Expr + + def eval(self) -> Expr: + m = self.base * self.integrand + return Piecewise((m / (self.exp + 1), Ne(self.exp, -1)), + (m * log(self.base), True)) + + +@dataclass +class AddRule(Rule): + """integrate(f(x) + g(x), x) -> integrate(f(x), x) + integrate(g(x), x)""" + substeps: list[Rule] + + def eval(self) -> Expr: + return Add(*(substep.eval() for substep in self.substeps)) + + def contains_dont_know(self) -> bool: + return any(substep.contains_dont_know() for substep in self.substeps) + + +@dataclass +class URule(Rule): + """integrate(f(g(x))*g'(x), x) -> integrate(f(u), u), u = g(x)""" + u_var: Symbol + u_func: Expr + substep: Rule + + def eval(self) -> Expr: + result = self.substep.eval() + if self.u_func.is_Pow: + base, exp_ = self.u_func.as_base_exp() + if exp_ == -1: + # avoid needless -log(1/x) from substitution + result = result.subs(log(self.u_var), -log(base)) + return result.subs(self.u_var, self.u_func) + + def contains_dont_know(self) -> bool: + return self.substep.contains_dont_know() + + +@dataclass +class PartsRule(Rule): + """integrate(u(x)*v'(x), x) -> u(x)*v(x) - integrate(u'(x)*v(x), x)""" + u: Symbol + dv: Expr + v_step: Rule + second_step: Rule | None # None when is a substep of CyclicPartsRule + + def eval(self) -> Expr: + assert self.second_step is not None + v = self.v_step.eval() + return self.u * v - self.second_step.eval() + + def contains_dont_know(self) -> bool: + return self.v_step.contains_dont_know() or ( + self.second_step is not None and self.second_step.contains_dont_know()) + + +@dataclass +class CyclicPartsRule(Rule): + """Apply PartsRule multiple times to integrate exp(x)*sin(x)""" + parts_rules: list[PartsRule] + coefficient: Expr + + def eval(self) -> Expr: + result = [] + sign = 1 + for rule in self.parts_rules: + result.append(sign * rule.u * rule.v_step.eval()) + sign *= -1 + return Add(*result) / (1 - self.coefficient) + + def contains_dont_know(self) -> bool: + return any(substep.contains_dont_know() for substep in self.parts_rules) + + +@dataclass +class TrigRule(AtomicRule, ABC): + pass + + +@dataclass +class SinRule(TrigRule): + """integrate(sin(x), x) -> -cos(x)""" + def eval(self) -> Expr: + return -cos(self.variable) + + +@dataclass +class CosRule(TrigRule): + """integrate(cos(x), x) -> sin(x)""" + def eval(self) -> Expr: + return sin(self.variable) + + +@dataclass +class SecTanRule(TrigRule): + """integrate(sec(x)*tan(x), x) -> sec(x)""" + def eval(self) -> Expr: + return sec(self.variable) + + +@dataclass +class CscCotRule(TrigRule): + """integrate(csc(x)*cot(x), x) -> -csc(x)""" + def eval(self) -> Expr: + return -csc(self.variable) + + +@dataclass +class Sec2Rule(TrigRule): + """integrate(sec(x)**2, x) -> tan(x)""" + def eval(self) -> Expr: + return tan(self.variable) + + +@dataclass +class Csc2Rule(TrigRule): + """integrate(csc(x)**2, x) -> -cot(x)""" + def eval(self) -> Expr: + return -cot(self.variable) + + +@dataclass +class HyperbolicRule(AtomicRule, ABC): + pass + + +@dataclass +class SinhRule(HyperbolicRule): + """integrate(sinh(x), x) -> cosh(x)""" + def eval(self) -> Expr: + return cosh(self.variable) + + +@dataclass +class CoshRule(HyperbolicRule): + """integrate(cosh(x), x) -> sinh(x)""" + def eval(self): + return sinh(self.variable) + + +@dataclass +class ExpRule(AtomicRule): + """integrate(a**x, x) -> a**x/ln(a)""" + base: Expr + exp: Expr + + def eval(self) -> Expr: + return self.integrand / log(self.base) + + +@dataclass +class ReciprocalRule(AtomicRule): + """integrate(1/x, x) -> ln(x)""" + base: Expr + + def eval(self) -> Expr: + return log(self.base) + + +@dataclass +class ArcsinRule(AtomicRule): + """integrate(1/sqrt(1-x**2), x) -> asin(x)""" + def eval(self) -> Expr: + return asin(self.variable) + + +@dataclass +class ArcsinhRule(AtomicRule): + """integrate(1/sqrt(1+x**2), x) -> asin(x)""" + def eval(self) -> Expr: + return asinh(self.variable) + + +@dataclass +class ReciprocalSqrtQuadraticRule(AtomicRule): + """integrate(1/sqrt(a+b*x+c*x**2), x) -> log(2*sqrt(c)*sqrt(a+b*x+c*x**2)+b+2*c*x)/sqrt(c)""" + a: Expr + b: Expr + c: Expr + + def eval(self) -> Expr: + a, b, c, x = self.a, self.b, self.c, self.variable + return log(2*sqrt(c)*sqrt(a+b*x+c*x**2)+b+2*c*x)/sqrt(c) + + +@dataclass +class SqrtQuadraticDenomRule(AtomicRule): + """integrate(poly(x)/sqrt(a+b*x+c*x**2), x)""" + a: Expr + b: Expr + c: Expr + coeffs: list[Expr] + + def eval(self) -> Expr: + a, b, c, coeffs, x = self.a, self.b, self.c, self.coeffs.copy(), self.variable + # Integrate poly/sqrt(a+b*x+c*x**2) using recursion. + # coeffs are coefficients of the polynomial. + # Let I_n = x**n/sqrt(a+b*x+c*x**2), then + # I_n = A * x**(n-1)*sqrt(a+b*x+c*x**2) - B * I_{n-1} - C * I_{n-2} + # where A = 1/(n*c), B = (2*n-1)*b/(2*n*c), C = (n-1)*a/(n*c) + # See https://github.com/sympy/sympy/pull/23608 for proof. + result_coeffs = [] + coeffs = coeffs.copy() + for i in range(len(coeffs)-2): + n = len(coeffs)-1-i + coeff = coeffs[i]/(c*n) + result_coeffs.append(coeff) + coeffs[i+1] -= (2*n-1)*b/2*coeff + coeffs[i+2] -= (n-1)*a*coeff + d, e = coeffs[-1], coeffs[-2] + s = sqrt(a+b*x+c*x**2) + constant = d-b*e/(2*c) + if constant == 0: + I0 = 0 + else: + step = inverse_trig_rule(IntegralInfo(1/s, x), degenerate=False) + I0 = constant*step.eval() + return Add(*(result_coeffs[i]*x**(len(coeffs)-2-i) + for i in range(len(result_coeffs))), e/c)*s + I0 + + +@dataclass +class SqrtQuadraticRule(AtomicRule): + """integrate(sqrt(a+b*x+c*x**2), x)""" + a: Expr + b: Expr + c: Expr + + def eval(self) -> Expr: + step = sqrt_quadratic_rule(IntegralInfo(self.integrand, self.variable), degenerate=False) + return step.eval() + + +@dataclass +class AlternativeRule(Rule): + """Multiple ways to do integration.""" + alternatives: list[Rule] + + def eval(self) -> Expr: + return self.alternatives[0].eval() + + def contains_dont_know(self) -> bool: + return any(substep.contains_dont_know() for substep in self.alternatives) + + +@dataclass +class DontKnowRule(Rule): + """Leave the integral as is.""" + def eval(self) -> Expr: + return Integral(self.integrand, self.variable) + + def contains_dont_know(self) -> bool: + return True + + +@dataclass +class DerivativeRule(AtomicRule): + """integrate(f'(x), x) -> f(x)""" + def eval(self) -> Expr: + assert isinstance(self.integrand, Derivative) + variable_count = list(self.integrand.variable_count) + for i, (var, count) in enumerate(variable_count): + if var == self.variable: + variable_count[i] = (var, count - 1) + break + return Derivative(self.integrand.expr, *variable_count) + + +@dataclass +class RewriteRule(Rule): + """Rewrite integrand to another form that is easier to handle.""" + rewritten: Expr + substep: Rule + + def eval(self) -> Expr: + return self.substep.eval() + + def contains_dont_know(self) -> bool: + return self.substep.contains_dont_know() + + +@dataclass +class CompleteSquareRule(RewriteRule): + """Rewrite a+b*x+c*x**2 to a-b**2/(4*c) + c*(x+b/(2*c))**2""" + pass + + +@dataclass +class PiecewiseRule(Rule): + subfunctions: Sequence[tuple[Rule, bool | Boolean]] + + def eval(self) -> Expr: + return Piecewise(*[(substep.eval(), cond) + for substep, cond in self.subfunctions]) + + def contains_dont_know(self) -> bool: + return any(substep.contains_dont_know() for substep, _ in self.subfunctions) + + +@dataclass +class HeavisideRule(Rule): + harg: Expr + ibnd: Expr + substep: Rule + + def eval(self) -> Expr: + # If we are integrating over x and the integrand has the form + # Heaviside(m*x+b)*g(x) == Heaviside(harg)*g(symbol) + # then there needs to be continuity at -b/m == ibnd, + # so we subtract the appropriate term. + result = self.substep.eval() + return Heaviside(self.harg) * (result - result.subs(self.variable, self.ibnd)) + + def contains_dont_know(self) -> bool: + return self.substep.contains_dont_know() + + +@dataclass +class DiracDeltaRule(AtomicRule): + n: Expr + a: Expr + b: Expr + + def eval(self) -> Expr: + n, a, b, x = self.n, self.a, self.b, self.variable + if n == 0: + return Heaviside(a+b*x)/b + return DiracDelta(a+b*x, n-1)/b + + +@dataclass +class TrigSubstitutionRule(Rule): + theta: Expr + func: Expr + rewritten: Expr + substep: Rule + restriction: bool | Boolean + + def eval(self) -> Expr: + theta, func, x = self.theta, self.func, self.variable + func = func.subs(sec(theta), 1/cos(theta)) + func = func.subs(csc(theta), 1/sin(theta)) + func = func.subs(cot(theta), 1/tan(theta)) + + trig_function = list(func.find(TrigonometricFunction)) + assert len(trig_function) == 1 + trig_function = trig_function[0] + relation = solve(x - func, trig_function) + assert len(relation) == 1 + numer, denom = fraction(relation[0]) + + if isinstance(trig_function, sin): + opposite = numer + hypotenuse = denom + adjacent = sqrt(denom**2 - numer**2) + inverse = asin(relation[0]) + elif isinstance(trig_function, cos): + adjacent = numer + hypotenuse = denom + opposite = sqrt(denom**2 - numer**2) + inverse = acos(relation[0]) + else: # tan + opposite = numer + adjacent = denom + hypotenuse = sqrt(denom**2 + numer**2) + inverse = atan(relation[0]) + + substitution = [ + (sin(theta), opposite/hypotenuse), + (cos(theta), adjacent/hypotenuse), + (tan(theta), opposite/adjacent), + (theta, inverse) + ] + return Piecewise( + (self.substep.eval().subs(substitution).trigsimp(), self.restriction) # type: ignore + ) + + def contains_dont_know(self) -> bool: + return self.substep.contains_dont_know() + + +@dataclass +class ArctanRule(AtomicRule): + """integrate(a/(b*x**2+c), x) -> a/b / sqrt(c/b) * atan(x/sqrt(c/b))""" + a: Expr + b: Expr + c: Expr + + def eval(self) -> Expr: + a, b, c, x = self.a, self.b, self.c, self.variable + return a/b / sqrt(c/b) * atan(x/sqrt(c/b)) + + +@dataclass +class OrthogonalPolyRule(AtomicRule, ABC): + n: Expr + + +@dataclass +class JacobiRule(OrthogonalPolyRule): + a: Expr + b: Expr + + def eval(self) -> Expr: + n, a, b, x = self.n, self.a, self.b, self.variable + return Piecewise( + (2*jacobi(n + 1, a - 1, b - 1, x)/(n + a + b), Ne(n + a + b, 0)), + (x, Eq(n, 0)), + ((a + b + 2)*x**2/4 + (a - b)*x/2, Eq(n, 1))) + + +@dataclass +class GegenbauerRule(OrthogonalPolyRule): + a: Expr + + def eval(self) -> Expr: + n, a, x = self.n, self.a, self.variable + return Piecewise( + (gegenbauer(n + 1, a - 1, x)/(2*(a - 1)), Ne(a, 1)), + (chebyshevt(n + 1, x)/(n + 1), Ne(n, -1)), + (S.Zero, True)) + + +@dataclass +class ChebyshevTRule(OrthogonalPolyRule): + def eval(self) -> Expr: + n, x = self.n, self.variable + return Piecewise( + ((chebyshevt(n + 1, x)/(n + 1) - + chebyshevt(n - 1, x)/(n - 1))/2, Ne(Abs(n), 1)), + (x**2/2, True)) + + +@dataclass +class ChebyshevURule(OrthogonalPolyRule): + def eval(self) -> Expr: + n, x = self.n, self.variable + return Piecewise( + (chebyshevt(n + 1, x)/(n + 1), Ne(n, -1)), + (S.Zero, True)) + + +@dataclass +class LegendreRule(OrthogonalPolyRule): + def eval(self) -> Expr: + n, x = self.n, self.variable + return(legendre(n + 1, x) - legendre(n - 1, x))/(2*n + 1) + + +@dataclass +class HermiteRule(OrthogonalPolyRule): + def eval(self) -> Expr: + n, x = self.n, self.variable + return hermite(n + 1, x)/(2*(n + 1)) + + +@dataclass +class LaguerreRule(OrthogonalPolyRule): + def eval(self) -> Expr: + n, x = self.n, self.variable + return laguerre(n, x) - laguerre(n + 1, x) + + +@dataclass +class AssocLaguerreRule(OrthogonalPolyRule): + a: Expr + + def eval(self) -> Expr: + return -assoc_laguerre(self.n + 1, self.a - 1, self.variable) + + +@dataclass +class IRule(AtomicRule, ABC): + a: Expr + b: Expr + + +@dataclass +class CiRule(IRule): + def eval(self) -> Expr: + a, b, x = self.a, self.b, self.variable + return cos(b)*Ci(a*x) - sin(b)*Si(a*x) + + +@dataclass +class ChiRule(IRule): + def eval(self) -> Expr: + a, b, x = self.a, self.b, self.variable + return cosh(b)*Chi(a*x) + sinh(b)*Shi(a*x) + + +@dataclass +class EiRule(IRule): + def eval(self) -> Expr: + a, b, x = self.a, self.b, self.variable + return exp(b)*Ei(a*x) + + +@dataclass +class SiRule(IRule): + def eval(self) -> Expr: + a, b, x = self.a, self.b, self.variable + return sin(b)*Ci(a*x) + cos(b)*Si(a*x) + + +@dataclass +class ShiRule(IRule): + def eval(self) -> Expr: + a, b, x = self.a, self.b, self.variable + return sinh(b)*Chi(a*x) + cosh(b)*Shi(a*x) + + +@dataclass +class LiRule(IRule): + def eval(self) -> Expr: + a, b, x = self.a, self.b, self.variable + return li(a*x + b)/a + + +@dataclass +class ErfRule(AtomicRule): + a: Expr + b: Expr + c: Expr + + def eval(self) -> Expr: + a, b, c, x = self.a, self.b, self.c, self.variable + if a.is_extended_real: + return Piecewise( + (sqrt(S.Pi)/sqrt(-a)/2 * exp(c - b**2/(4*a)) * + erf((-2*a*x - b)/(2*sqrt(-a))), a < 0), + (sqrt(S.Pi)/sqrt(a)/2 * exp(c - b**2/(4*a)) * + erfi((2*a*x + b)/(2*sqrt(a))), True)) + return sqrt(S.Pi)/sqrt(a)/2 * exp(c - b**2/(4*a)) * \ + erfi((2*a*x + b)/(2*sqrt(a))) + + +@dataclass +class FresnelCRule(AtomicRule): + a: Expr + b: Expr + c: Expr + + def eval(self) -> Expr: + a, b, c, x = self.a, self.b, self.c, self.variable + return sqrt(S.Pi)/sqrt(2*a) * ( + cos(b**2/(4*a) - c)*fresnelc((2*a*x + b)/sqrt(2*a*S.Pi)) + + sin(b**2/(4*a) - c)*fresnels((2*a*x + b)/sqrt(2*a*S.Pi))) + + +@dataclass +class FresnelSRule(AtomicRule): + a: Expr + b: Expr + c: Expr + + def eval(self) -> Expr: + a, b, c, x = self.a, self.b, self.c, self.variable + return sqrt(S.Pi)/sqrt(2*a) * ( + cos(b**2/(4*a) - c)*fresnels((2*a*x + b)/sqrt(2*a*S.Pi)) - + sin(b**2/(4*a) - c)*fresnelc((2*a*x + b)/sqrt(2*a*S.Pi))) + + +@dataclass +class PolylogRule(AtomicRule): + a: Expr + b: Expr + + def eval(self) -> Expr: + return polylog(self.b + 1, self.a * self.variable) + + +@dataclass +class UpperGammaRule(AtomicRule): + a: Expr + e: Expr + + def eval(self) -> Expr: + a, e, x = self.a, self.e, self.variable + return x**e * (-a*x)**(-e) * uppergamma(e + 1, -a*x)/a + + +@dataclass +class EllipticFRule(AtomicRule): + a: Expr + d: Expr + + def eval(self) -> Expr: + return elliptic_f(self.variable, self.d/self.a)/sqrt(self.a) + + +@dataclass +class EllipticERule(AtomicRule): + a: Expr + d: Expr + + def eval(self) -> Expr: + return elliptic_e(self.variable, self.d/self.a)*sqrt(self.a) + + +class IntegralInfo(NamedTuple): + integrand: Expr + symbol: Symbol + + +def manual_diff(f, symbol): + """Derivative of f in form expected by find_substitutions + + SymPy's derivatives for some trig functions (like cot) are not in a form + that works well with finding substitutions; this replaces the + derivatives for those particular forms with something that works better. + + """ + if f.args: + arg = f.args[0] + if isinstance(f, tan): + return arg.diff(symbol) * sec(arg)**2 + elif isinstance(f, cot): + return -arg.diff(symbol) * csc(arg)**2 + elif isinstance(f, sec): + return arg.diff(symbol) * sec(arg) * tan(arg) + elif isinstance(f, csc): + return -arg.diff(symbol) * csc(arg) * cot(arg) + elif isinstance(f, Add): + return sum(manual_diff(arg, symbol) for arg in f.args) + elif isinstance(f, Mul): + if len(f.args) == 2 and isinstance(f.args[0], Number): + return f.args[0] * manual_diff(f.args[1], symbol) + return f.diff(symbol) + +def manual_subs(expr, *args): + """ + A wrapper for `expr.subs(*args)` with additional logic for substitution + of invertible functions. + """ + if len(args) == 1: + sequence = args[0] + if isinstance(sequence, (Dict, Mapping)): + sequence = sequence.items() + elif not iterable(sequence): + raise ValueError("Expected an iterable of (old, new) pairs") + elif len(args) == 2: + sequence = [args] + else: + raise ValueError("subs accepts either 1 or 2 arguments") + + new_subs = [] + for old, new in sequence: + if isinstance(old, log): + # If log(x) = y, then exp(a*log(x)) = exp(a*y) + # that is, x**a = exp(a*y). Replace nontrivial powers of x + # before subs turns them into `exp(y)**a`, but + # do not replace x itself yet, to avoid `log(exp(y))`. + x0 = old.args[0] + expr = expr.replace(lambda x: x.is_Pow and x.base == x0, + lambda x: exp(x.exp*new)) + new_subs.append((x0, exp(new))) + + return expr.subs(list(sequence) + new_subs) + +# Method based on that on SIN, described in "Symbolic Integration: The +# Stormy Decade" + +inverse_trig_functions = (atan, asin, acos, acot, acsc, asec) + + +def find_substitutions(integrand, symbol, u_var): + results = [] + + def test_subterm(u, u_diff): + if u_diff == 0: + return False + substituted = integrand / u_diff + debug("substituted: {}, u: {}, u_var: {}".format(substituted, u, u_var)) + substituted = manual_subs(substituted, u, u_var).cancel() + + if substituted.has_free(symbol): + return False + # avoid increasing the degree of a rational function + if integrand.is_rational_function(symbol) and substituted.is_rational_function(u_var): + deg_before = max(degree(t, symbol) for t in integrand.as_numer_denom()) + deg_after = max(degree(t, u_var) for t in substituted.as_numer_denom()) + if deg_after > deg_before: + return False + return substituted.as_independent(u_var, as_Add=False) + + def exp_subterms(term: Expr): + linear_coeffs = [] + terms = [] + n = Wild('n', properties=[lambda n: n.is_Integer]) + for exp_ in term.find(exp): + arg = exp_.args[0] + if symbol not in arg.free_symbols: + continue + match = arg.match(n*symbol) + if match: + linear_coeffs.append(match[n]) + else: + terms.append(exp_) + if linear_coeffs: + terms.append(exp(gcd_list(linear_coeffs)*symbol)) + return terms + + def possible_subterms(term): + if isinstance(term, (TrigonometricFunction, HyperbolicFunction, + *inverse_trig_functions, + exp, log, Heaviside)): + return [term.args[0]] + elif isinstance(term, (chebyshevt, chebyshevu, + legendre, hermite, laguerre)): + return [term.args[1]] + elif isinstance(term, (gegenbauer, assoc_laguerre)): + return [term.args[2]] + elif isinstance(term, jacobi): + return [term.args[3]] + elif isinstance(term, Mul): + r = [] + for u in term.args: + r.append(u) + r.extend(possible_subterms(u)) + return r + elif isinstance(term, Pow): + r = [arg for arg in term.args if arg.has(symbol)] + if term.exp.is_Integer: + r.extend([term.base**d for d in primefactors(term.exp) + if 1 < d < abs(term.args[1])]) + if term.base.is_Add: + r.extend([t for t in possible_subterms(term.base) + if t.is_Pow]) + return r + elif isinstance(term, Add): + r = [] + for arg in term.args: + r.append(arg) + r.extend(possible_subterms(arg)) + return r + return [] + + for u in list(dict.fromkeys(possible_subterms(integrand) + exp_subterms(integrand))): + if u == symbol: + continue + u_diff = manual_diff(u, symbol) + new_integrand = test_subterm(u, u_diff) + if new_integrand is not False: + constant, new_integrand = new_integrand + if new_integrand == integrand.subs(symbol, u_var): + continue + substitution = (u, constant, new_integrand) + if substitution not in results: + results.append(substitution) + + return results + +def rewriter(condition, rewrite): + """Strategy that rewrites an integrand.""" + def _rewriter(integral): + integrand, symbol = integral + debug("Integral: {} is rewritten with {} on symbol: {}".format(integrand, rewrite, symbol)) + if condition(*integral): + rewritten = rewrite(*integral) + if rewritten != integrand: + substep = integral_steps(rewritten, symbol) + if not isinstance(substep, DontKnowRule) and substep: + return RewriteRule(integrand, symbol, rewritten, substep) + return _rewriter + +def proxy_rewriter(condition, rewrite): + """Strategy that rewrites an integrand based on some other criteria.""" + def _proxy_rewriter(criteria): + criteria, integral = criteria + integrand, symbol = integral + debug("Integral: {} is rewritten with {} on symbol: {} and criteria: {}".format(integrand, rewrite, symbol, criteria)) + args = criteria + list(integral) + if condition(*args): + rewritten = rewrite(*args) + if rewritten != integrand: + return RewriteRule(integrand, symbol, rewritten, integral_steps(rewritten, symbol)) + return _proxy_rewriter + +def multiplexer(conditions): + """Apply the rule that matches the condition, else None""" + def multiplexer_rl(expr): + for key, rule in conditions.items(): + if key(expr): + return rule(expr) + return multiplexer_rl + +def alternatives(*rules): + """Strategy that makes an AlternativeRule out of multiple possible results.""" + def _alternatives(integral): + alts = [] + count = 0 + debug("List of Alternative Rules") + for rule in rules: + count = count + 1 + debug("Rule {}: {}".format(count, rule)) + + result = rule(integral) + if (result and not isinstance(result, DontKnowRule) and + result != integral and result not in alts): + alts.append(result) + if len(alts) == 1: + return alts[0] + elif alts: + doable = [rule for rule in alts if not rule.contains_dont_know()] + if doable: + return AlternativeRule(*integral, doable) + else: + return AlternativeRule(*integral, alts) + return _alternatives + +def constant_rule(integral): + return ConstantRule(*integral) + +def power_rule(integral): + integrand, symbol = integral + base, expt = integrand.as_base_exp() + + if symbol not in expt.free_symbols and isinstance(base, Symbol): + if simplify(expt + 1) == 0: + return ReciprocalRule(integrand, symbol, base) + return PowerRule(integrand, symbol, base, expt) + elif symbol not in base.free_symbols and isinstance(expt, Symbol): + rule = ExpRule(integrand, symbol, base, expt) + + if fuzzy_not(log(base).is_zero): + return rule + elif log(base).is_zero: + return ConstantRule(1, symbol) + + return PiecewiseRule(integrand, symbol, [ + (rule, Ne(log(base), 0)), + (ConstantRule(1, symbol), True) + ]) + +def exp_rule(integral): + integrand, symbol = integral + if isinstance(integrand.args[0], Symbol): + return ExpRule(integrand, symbol, E, integrand.args[0]) + + +def orthogonal_poly_rule(integral): + orthogonal_poly_classes = { + jacobi: JacobiRule, + gegenbauer: GegenbauerRule, + chebyshevt: ChebyshevTRule, + chebyshevu: ChebyshevURule, + legendre: LegendreRule, + hermite: HermiteRule, + laguerre: LaguerreRule, + assoc_laguerre: AssocLaguerreRule + } + orthogonal_poly_var_index = { + jacobi: 3, + gegenbauer: 2, + assoc_laguerre: 2 + } + integrand, symbol = integral + for klass in orthogonal_poly_classes: + if isinstance(integrand, klass): + var_index = orthogonal_poly_var_index.get(klass, 1) + if (integrand.args[var_index] is symbol and not + any(v.has(symbol) for v in integrand.args[:var_index])): + return orthogonal_poly_classes[klass](integrand, symbol, *integrand.args[:var_index]) + + +_special_function_patterns: list[tuple[Type, Expr, Callable | None, tuple]] = [] +_wilds = [] +_symbol = Dummy('x') + + +def special_function_rule(integral): + integrand, symbol = integral + if not _special_function_patterns: + a = Wild('a', exclude=[_symbol], properties=[lambda x: not x.is_zero]) + b = Wild('b', exclude=[_symbol]) + c = Wild('c', exclude=[_symbol]) + d = Wild('d', exclude=[_symbol], properties=[lambda x: not x.is_zero]) + e = Wild('e', exclude=[_symbol], properties=[ + lambda x: not (x.is_nonnegative and x.is_integer)]) + _wilds.extend((a, b, c, d, e)) + # patterns consist of a SymPy class, a wildcard expr, an optional + # condition coded as a lambda (when Wild properties are not enough), + # followed by an applicable rule + linear_pattern = a*_symbol + b + quadratic_pattern = a*_symbol**2 + b*_symbol + c + _special_function_patterns.extend(( + (Mul, exp(linear_pattern, evaluate=False)/_symbol, None, EiRule), + (Mul, cos(linear_pattern, evaluate=False)/_symbol, None, CiRule), + (Mul, cosh(linear_pattern, evaluate=False)/_symbol, None, ChiRule), + (Mul, sin(linear_pattern, evaluate=False)/_symbol, None, SiRule), + (Mul, sinh(linear_pattern, evaluate=False)/_symbol, None, ShiRule), + (Pow, 1/log(linear_pattern, evaluate=False), None, LiRule), + (exp, exp(quadratic_pattern, evaluate=False), None, ErfRule), + (sin, sin(quadratic_pattern, evaluate=False), None, FresnelSRule), + (cos, cos(quadratic_pattern, evaluate=False), None, FresnelCRule), + (Mul, _symbol**e*exp(a*_symbol, evaluate=False), None, UpperGammaRule), + (Mul, polylog(b, a*_symbol, evaluate=False)/_symbol, None, PolylogRule), + (Pow, 1/sqrt(a - d*sin(_symbol, evaluate=False)**2), + lambda a, d: a != d, EllipticFRule), + (Pow, sqrt(a - d*sin(_symbol, evaluate=False)**2), + lambda a, d: a != d, EllipticERule), + )) + _integrand = integrand.subs(symbol, _symbol) + for type_, pattern, constraint, rule in _special_function_patterns: + if isinstance(_integrand, type_): + match = _integrand.match(pattern) + if match: + wild_vals = tuple(match.get(w) for w in _wilds + if match.get(w) is not None) + if constraint is None or constraint(*wild_vals): + return rule(integrand, symbol, *wild_vals) + + +def _add_degenerate_step(generic_cond, generic_step: Rule, degenerate_step: Rule | None) -> Rule: + if degenerate_step is None: + return generic_step + if isinstance(generic_step, PiecewiseRule): + subfunctions = [(substep, (cond & generic_cond).simplify()) + for substep, cond in generic_step.subfunctions] + else: + subfunctions = [(generic_step, generic_cond)] + if isinstance(degenerate_step, PiecewiseRule): + subfunctions += degenerate_step.subfunctions + else: + subfunctions.append((degenerate_step, S.true)) + return PiecewiseRule(generic_step.integrand, generic_step.variable, subfunctions) + + +def nested_pow_rule(integral: IntegralInfo): + # nested (c*(a+b*x)**d)**e + integrand, x = integral + + a_ = Wild('a', exclude=[x]) + b_ = Wild('b', exclude=[x, 0]) + pattern = a_+b_*x + generic_cond = S.true + + class NoMatch(Exception): + pass + + def _get_base_exp(expr: Expr) -> tuple[Expr, Expr]: + if not expr.has_free(x): + return S.One, S.Zero + if expr.is_Mul: + _, terms = expr.as_coeff_mul() + if not terms: + return S.One, S.Zero + results = [_get_base_exp(term) for term in terms] + bases = {b for b, _ in results} + bases.discard(S.One) + if len(bases) == 1: + return bases.pop(), Add(*(e for _, e in results)) + raise NoMatch + if expr.is_Pow: + b, e = expr.base, expr.exp # type: ignore + if e.has_free(x): + raise NoMatch + base_, sub_exp = _get_base_exp(b) + return base_, sub_exp * e + match = expr.match(pattern) + if match: + a, b = match[a_], match[b_] + base_ = x + a/b + nonlocal generic_cond + generic_cond = Ne(b, 0) + return base_, S.One + raise NoMatch + + try: + base, exp_ = _get_base_exp(integrand) + except NoMatch: + return + if generic_cond is S.true: + degenerate_step = None + else: + # equivalent with subs(b, 0) but no need to find b + degenerate_step = ConstantRule(integrand.subs(x, 0), x) + generic_step = NestedPowRule(integrand, x, base, exp_) + return _add_degenerate_step(generic_cond, generic_step, degenerate_step) + + +def inverse_trig_rule(integral: IntegralInfo, degenerate=True): + """ + Set degenerate=False on recursive call where coefficient of quadratic term + is assumed non-zero. + """ + integrand, symbol = integral + base, exp = integrand.as_base_exp() + a = Wild('a', exclude=[symbol]) + b = Wild('b', exclude=[symbol]) + c = Wild('c', exclude=[symbol, 0]) + match = base.match(a + b*symbol + c*symbol**2) + + if not match: + return + + def make_inverse_trig(RuleClass, a, sign_a, c, sign_c, h) -> Rule: + u_var = Dummy("u") + rewritten = 1/sqrt(sign_a*a + sign_c*c*(symbol-h)**2) # a>0, c>0 + quadratic_base = sqrt(c/a)*(symbol-h) + constant = 1/sqrt(c) + u_func = None + if quadratic_base is not symbol: + u_func = quadratic_base + quadratic_base = u_var + standard_form = 1/sqrt(sign_a + sign_c*quadratic_base**2) + substep = RuleClass(standard_form, quadratic_base) + if constant != 1: + substep = ConstantTimesRule(constant*standard_form, symbol, constant, standard_form, substep) + if u_func is not None: + substep = URule(rewritten, symbol, u_var, u_func, substep) + if h != 0: + substep = CompleteSquareRule(integrand, symbol, rewritten, substep) + return substep + + a, b, c = [match.get(i, S.Zero) for i in (a, b, c)] + generic_cond = Ne(c, 0) + if not degenerate or generic_cond is S.true: + degenerate_step = None + elif b.is_zero: + degenerate_step = ConstantRule(a ** exp, symbol) + else: + degenerate_step = sqrt_linear_rule(IntegralInfo((a + b * symbol) ** exp, symbol)) + + if simplify(2*exp + 1) == 0: + h, k = -b/(2*c), a - b**2/(4*c) # rewrite base to k + c*(symbol-h)**2 + non_square_cond = Ne(k, 0) + square_step = None + if non_square_cond is not S.true: + square_step = NestedPowRule(1/sqrt(c*(symbol-h)**2), symbol, symbol-h, S.NegativeOne) + if non_square_cond is S.false: + return square_step + generic_step = ReciprocalSqrtQuadraticRule(integrand, symbol, a, b, c) + step = _add_degenerate_step(non_square_cond, generic_step, square_step) + if k.is_real and c.is_real: + # list of ((rule, base_exp, a, sign_a, b, sign_b), condition) + rules = [] + for args, cond in ( # don't apply ArccoshRule to x**2-1 + ((ArcsinRule, k, 1, -c, -1, h), And(k > 0, c < 0)), # 1-x**2 + ((ArcsinhRule, k, 1, c, 1, h), And(k > 0, c > 0)), # 1+x**2 + ): + if cond is S.true: + return make_inverse_trig(*args) + if cond is not S.false: + rules.append((make_inverse_trig(*args), cond)) + if rules: + if not k.is_positive: # conditions are not thorough, need fall back rule + rules.append((generic_step, S.true)) + step = PiecewiseRule(integrand, symbol, rules) + else: + step = generic_step + return _add_degenerate_step(generic_cond, step, degenerate_step) + if exp == S.Half: + step = SqrtQuadraticRule(integrand, symbol, a, b, c) + return _add_degenerate_step(generic_cond, step, degenerate_step) + + +def add_rule(integral): + integrand, symbol = integral + results = [integral_steps(g, symbol) + for g in integrand.as_ordered_terms()] + return None if None in results else AddRule(integrand, symbol, results) + + +def mul_rule(integral: IntegralInfo): + integrand, symbol = integral + + # Constant times function case + coeff, f = integrand.as_independent(symbol) + if coeff != 1: + next_step = integral_steps(f, symbol) + if next_step is not None: + return ConstantTimesRule(integrand, symbol, coeff, f, next_step) + + +def _parts_rule(integrand, symbol) -> tuple[Expr, Expr, Expr, Expr, Rule] | None: + # LIATE rule: + # log, inverse trig, algebraic, trigonometric, exponential + def pull_out_algebraic(integrand): + integrand = integrand.cancel().together() + # iterating over Piecewise args would not work here + algebraic = ([] if isinstance(integrand, Piecewise) or not integrand.is_Mul + else [arg for arg in integrand.args if arg.is_algebraic_expr(symbol)]) + if algebraic: + u = Mul(*algebraic) + dv = (integrand / u).cancel() + return u, dv + + def pull_out_u(*functions) -> Callable[[Expr], tuple[Expr, Expr] | None]: + def pull_out_u_rl(integrand: Expr) -> tuple[Expr, Expr] | None: + if any(integrand.has(f) for f in functions): + args = [arg for arg in integrand.args + if any(isinstance(arg, cls) for cls in functions)] + if args: + u = Mul(*args) # type: ignore + dv = integrand / u + return u, dv + return None + + return pull_out_u_rl + + liate_rules = [pull_out_u(log), pull_out_u(*inverse_trig_functions), + pull_out_algebraic, pull_out_u(sin, cos), + pull_out_u(exp)] + + + dummy = Dummy("temporary") + # we can integrate log(x) and atan(x) by setting dv = 1 + if isinstance(integrand, (log, *inverse_trig_functions)): + integrand = dummy * integrand + + for index, rule in enumerate(liate_rules): + result = rule(integrand) + + if result: + u, dv = result + + # Don't pick u to be a constant if possible + if symbol not in u.free_symbols and not u.has(dummy): + return None + + u = u.subs(dummy, 1) + dv = dv.subs(dummy, 1) + + # Don't pick a non-polynomial algebraic to be differentiated + if rule == pull_out_algebraic and not u.is_polynomial(symbol): + return None + # Don't trade one logarithm for another + if isinstance(u, log): + rec_dv = 1/dv + if (rec_dv.is_polynomial(symbol) and + degree(rec_dv, symbol) == 1): + return None + + # Can integrate a polynomial times OrthogonalPolynomial + if rule == pull_out_algebraic: + if dv.is_Derivative or dv.has(TrigonometricFunction) or \ + isinstance(dv, OrthogonalPolynomial): + v_step = integral_steps(dv, symbol) + if v_step.contains_dont_know(): + return None + else: + du = u.diff(symbol) + v = v_step.eval() + return u, dv, v, du, v_step + + # make sure dv is amenable to integration + accept = False + if index < 2: # log and inverse trig are usually worth trying + accept = True + elif (rule == pull_out_algebraic and dv.args and + all(isinstance(a, (sin, cos, exp)) + for a in dv.args)): + accept = True + else: + for lrule in liate_rules[index + 1:]: + r = lrule(integrand) + if r and r[0].subs(dummy, 1).equals(dv): + accept = True + break + + if accept: + du = u.diff(symbol) + v_step = integral_steps(simplify(dv), symbol) + if not v_step.contains_dont_know(): + v = v_step.eval() + return u, dv, v, du, v_step + return None + + +def parts_rule(integral): + integrand, symbol = integral + constant, integrand = integrand.as_coeff_Mul() + + result = _parts_rule(integrand, symbol) + + steps = [] + if result: + u, dv, v, du, v_step = result + debug("u : {}, dv : {}, v : {}, du : {}, v_step: {}".format(u, dv, v, du, v_step)) + steps.append(result) + + if isinstance(v, Integral): + return + + # Set a limit on the number of times u can be used + if isinstance(u, (sin, cos, exp, sinh, cosh)): + cachekey = u.xreplace({symbol: _cache_dummy}) + if _parts_u_cache[cachekey] > 2: + return + _parts_u_cache[cachekey] += 1 + + # Try cyclic integration by parts a few times + for _ in range(4): + debug("Cyclic integration {} with v: {}, du: {}, integrand: {}".format(_, v, du, integrand)) + coefficient = ((v * du) / integrand).cancel() + if coefficient == 1: + break + if symbol not in coefficient.free_symbols: + rule = CyclicPartsRule(integrand, symbol, + [PartsRule(None, None, u, dv, v_step, None) + for (u, dv, v, du, v_step) in steps], + (-1) ** len(steps) * coefficient) + if (constant != 1) and rule: + rule = ConstantTimesRule(constant * integrand, symbol, constant, integrand, rule) + return rule + + # _parts_rule is sensitive to constants, factor it out + next_constant, next_integrand = (v * du).as_coeff_Mul() + result = _parts_rule(next_integrand, symbol) + + if result: + u, dv, v, du, v_step = result + u *= next_constant + du *= next_constant + steps.append((u, dv, v, du, v_step)) + else: + break + + def make_second_step(steps, integrand): + if steps: + u, dv, v, du, v_step = steps[0] + return PartsRule(integrand, symbol, u, dv, v_step, make_second_step(steps[1:], v * du)) + return integral_steps(integrand, symbol) + + if steps: + u, dv, v, du, v_step = steps[0] + rule = PartsRule(integrand, symbol, u, dv, v_step, make_second_step(steps[1:], v * du)) + if (constant != 1) and rule: + rule = ConstantTimesRule(constant * integrand, symbol, constant, integrand, rule) + return rule + + +def trig_rule(integral): + integrand, symbol = integral + if integrand == sin(symbol): + return SinRule(integrand, symbol) + if integrand == cos(symbol): + return CosRule(integrand, symbol) + if integrand == sec(symbol)**2: + return Sec2Rule(integrand, symbol) + if integrand == csc(symbol)**2: + return Csc2Rule(integrand, symbol) + + if isinstance(integrand, tan): + rewritten = sin(*integrand.args) / cos(*integrand.args) + elif isinstance(integrand, cot): + rewritten = cos(*integrand.args) / sin(*integrand.args) + elif isinstance(integrand, sec): + arg = integrand.args[0] + rewritten = ((sec(arg)**2 + tan(arg) * sec(arg)) / + (sec(arg) + tan(arg))) + elif isinstance(integrand, csc): + arg = integrand.args[0] + rewritten = ((csc(arg)**2 + cot(arg) * csc(arg)) / + (csc(arg) + cot(arg))) + else: + return + + return RewriteRule(integrand, symbol, rewritten, integral_steps(rewritten, symbol)) + +def trig_product_rule(integral: IntegralInfo): + integrand, symbol = integral + if integrand == sec(symbol) * tan(symbol): + return SecTanRule(integrand, symbol) + if integrand == csc(symbol) * cot(symbol): + return CscCotRule(integrand, symbol) + + +def quadratic_denom_rule(integral): + integrand, symbol = integral + a = Wild('a', exclude=[symbol]) + b = Wild('b', exclude=[symbol]) + c = Wild('c', exclude=[symbol]) + + match = integrand.match(a / (b * symbol ** 2 + c)) + + if match: + a, b, c = match[a], match[b], match[c] + general_rule = ArctanRule(integrand, symbol, a, b, c) + if b.is_extended_real and c.is_extended_real: + positive_cond = c/b > 0 + if positive_cond is S.true: + return general_rule + coeff = a/(2*sqrt(-c)*sqrt(b)) + constant = sqrt(-c/b) + r1 = 1/(symbol-constant) + r2 = 1/(symbol+constant) + log_steps = [ReciprocalRule(r1, symbol, symbol-constant), + ConstantTimesRule(-r2, symbol, -1, r2, ReciprocalRule(r2, symbol, symbol+constant))] + rewritten = sub = r1 - r2 + negative_step = AddRule(sub, symbol, log_steps) + if coeff != 1: + rewritten = Mul(coeff, sub, evaluate=False) + negative_step = ConstantTimesRule(rewritten, symbol, coeff, sub, negative_step) + negative_step = RewriteRule(integrand, symbol, rewritten, negative_step) + if positive_cond is S.false: + return negative_step + return PiecewiseRule(integrand, symbol, [(general_rule, positive_cond), (negative_step, S.true)]) + + power = PowerRule(integrand, symbol, symbol, -2) + if b != 1: + power = ConstantTimesRule(integrand, symbol, 1/b, symbol**-2, power) + + return PiecewiseRule(integrand, symbol, [(general_rule, Ne(c, 0)), (power, True)]) + + d = Wild('d', exclude=[symbol]) + match2 = integrand.match(a / (b * symbol ** 2 + c * symbol + d)) + if match2: + b, c = match2[b], match2[c] + if b.is_zero: + return + u = Dummy('u') + u_func = symbol + c/(2*b) + integrand2 = integrand.subs(symbol, u - c / (2*b)) + next_step = integral_steps(integrand2, u) + if next_step: + return URule(integrand2, symbol, u, u_func, next_step) + else: + return + e = Wild('e', exclude=[symbol]) + match3 = integrand.match((a* symbol + b) / (c * symbol ** 2 + d * symbol + e)) + if match3: + a, b, c, d, e = match3[a], match3[b], match3[c], match3[d], match3[e] + if c.is_zero: + return + denominator = c * symbol**2 + d * symbol + e + const = a/(2*c) + numer1 = (2*c*symbol+d) + numer2 = - const*d + b + u = Dummy('u') + step1 = URule(integrand, symbol, + u, denominator, integral_steps(u**(-1), u)) + if const != 1: + step1 = ConstantTimesRule(const*numer1/denominator, symbol, + const, numer1/denominator, step1) + if numer2.is_zero: + return step1 + step2 = integral_steps(numer2/denominator, symbol) + substeps = AddRule(integrand, symbol, [step1, step2]) + rewriten = const*numer1/denominator+numer2/denominator + return RewriteRule(integrand, symbol, rewriten, substeps) + + return + + +def sqrt_linear_rule(integral: IntegralInfo): + """ + Substitute common (a+b*x)**(1/n) + """ + integrand, x = integral + a = Wild('a', exclude=[x]) + b = Wild('b', exclude=[x, 0]) + a0 = b0 = 0 + bases, qs, bs = [], [], [] + for pow_ in integrand.find(Pow): # collect all (a+b*x)**(p/q) + base, exp_ = pow_.base, pow_.exp + if exp_.is_Integer or x not in base.free_symbols: # skip 1/x and sqrt(2) + continue + if not exp_.is_Rational: # exclude x**pi + return + match = base.match(a+b*x) + if not match: # skip non-linear + continue # for sqrt(x+sqrt(x)), although base is non-linear, we can still substitute sqrt(x) + a1, b1 = match[a], match[b] + if a0*b1 != a1*b0 or not (b0/b1).is_nonnegative: # cannot transform sqrt(x) to sqrt(x+1) or sqrt(-x) + return + if b0 == 0 or (b0/b1 > 1) is S.true: # choose the latter of sqrt(2*x) and sqrt(x) as representative + a0, b0 = a1, b1 + bases.append(base) + bs.append(b1) + qs.append(exp_.q) + if b0 == 0: # no such pattern found + return + q0: Integer = lcm_list(qs) + u_x = (a0 + b0*x)**(1/q0) + u = Dummy("u") + substituted = integrand.subs({base**(S.One/q): (b/b0)**(S.One/q)*u**(q0/q) + for base, b, q in zip(bases, bs, qs)}).subs(x, (u**q0-a0)/b0) + substep = integral_steps(substituted*u**(q0-1)*q0/b0, u) + if not substep.contains_dont_know(): + step: Rule = URule(integrand, x, u, u_x, substep) + generic_cond = Ne(b0, 0) + if generic_cond is not S.true: # possible degenerate case + simplified = integrand.subs(dict.fromkeys(bs, 0)) + degenerate_step = integral_steps(simplified, x) + step = PiecewiseRule(integrand, x, [(step, generic_cond), (degenerate_step, S.true)]) + return step + + +def sqrt_quadratic_rule(integral: IntegralInfo, degenerate=True): + integrand, x = integral + a = Wild('a', exclude=[x]) + b = Wild('b', exclude=[x]) + c = Wild('c', exclude=[x, 0]) + f = Wild('f') + n = Wild('n', properties=[lambda n: n.is_Integer and n.is_odd]) + match = integrand.match(f*sqrt(a+b*x+c*x**2)**n) + if not match: + return + a, b, c, f, n = match[a], match[b], match[c], match[f], match[n] + f_poly = f.as_poly(x) + if f_poly is None: + return + + generic_cond = Ne(c, 0) + if not degenerate or generic_cond is S.true: + degenerate_step = None + elif b.is_zero: + degenerate_step = integral_steps(f*sqrt(a)**n, x) + else: + degenerate_step = sqrt_linear_rule(IntegralInfo(f*sqrt(a+b*x)**n, x)) + + def sqrt_quadratic_denom_rule(numer_poly: Poly, integrand: Expr): + denom = sqrt(a+b*x+c*x**2) + deg = numer_poly.degree() + if deg <= 1: + # integrand == (d+e*x)/sqrt(a+b*x+c*x**2) + e, d = numer_poly.all_coeffs() if deg == 1 else (S.Zero, numer_poly.as_expr()) + # rewrite numerator to A*(2*c*x+b) + B + A = e/(2*c) + B = d-A*b + pre_substitute = (2*c*x+b)/denom + constant_step: Rule | None = None + linear_step: Rule | None = None + if A != 0: + u = Dummy("u") + pow_rule = PowerRule(1/sqrt(u), u, u, -S.Half) + linear_step = URule(pre_substitute, x, u, a+b*x+c*x**2, pow_rule) + if A != 1: + linear_step = ConstantTimesRule(A*pre_substitute, x, A, pre_substitute, linear_step) + if B != 0: + constant_step = inverse_trig_rule(IntegralInfo(1/denom, x), degenerate=False) + if B != 1: + constant_step = ConstantTimesRule(B/denom, x, B, 1/denom, constant_step) # type: ignore + if linear_step and constant_step: + add = Add(A*pre_substitute, B/denom, evaluate=False) + step: Rule | None = RewriteRule(integrand, x, add, AddRule(add, x, [linear_step, constant_step])) + else: + step = linear_step or constant_step + else: + coeffs = numer_poly.all_coeffs() + step = SqrtQuadraticDenomRule(integrand, x, a, b, c, coeffs) + return step + + if n > 0: # rewrite poly * sqrt(s)**(2*k-1) to poly*s**k / sqrt(s) + numer_poly = f_poly * (a+b*x+c*x**2)**((n+1)/2) + rewritten = numer_poly.as_expr()/sqrt(a+b*x+c*x**2) + substep = sqrt_quadratic_denom_rule(numer_poly, rewritten) + generic_step = RewriteRule(integrand, x, rewritten, substep) + elif n == -1: + generic_step = sqrt_quadratic_denom_rule(f_poly, integrand) + else: + return # todo: handle n < -1 case + return _add_degenerate_step(generic_cond, generic_step, degenerate_step) + + +def hyperbolic_rule(integral: tuple[Expr, Symbol]): + integrand, symbol = integral + if isinstance(integrand, HyperbolicFunction) and integrand.args[0] == symbol: + if integrand.func == sinh: + return SinhRule(integrand, symbol) + if integrand.func == cosh: + return CoshRule(integrand, symbol) + u = Dummy('u') + if integrand.func == tanh: + rewritten = sinh(symbol)/cosh(symbol) + return RewriteRule(integrand, symbol, rewritten, + URule(rewritten, symbol, u, cosh(symbol), ReciprocalRule(1/u, u, u))) + if integrand.func == coth: + rewritten = cosh(symbol)/sinh(symbol) + return RewriteRule(integrand, symbol, rewritten, + URule(rewritten, symbol, u, sinh(symbol), ReciprocalRule(1/u, u, u))) + else: + rewritten = integrand.rewrite(tanh) + if integrand.func == sech: + return RewriteRule(integrand, symbol, rewritten, + URule(rewritten, symbol, u, tanh(symbol/2), + ArctanRule(2/(u**2 + 1), u, S(2), S.One, S.One))) + if integrand.func == csch: + return RewriteRule(integrand, symbol, rewritten, + URule(rewritten, symbol, u, tanh(symbol/2), + ReciprocalRule(1/u, u, u))) + +@cacheit +def make_wilds(symbol): + a = Wild('a', exclude=[symbol]) + b = Wild('b', exclude=[symbol]) + m = Wild('m', exclude=[symbol], properties=[lambda n: isinstance(n, Integer)]) + n = Wild('n', exclude=[symbol], properties=[lambda n: isinstance(n, Integer)]) + + return a, b, m, n + +@cacheit +def sincos_pattern(symbol): + a, b, m, n = make_wilds(symbol) + pattern = sin(a*symbol)**m * cos(b*symbol)**n + + return pattern, a, b, m, n + +@cacheit +def tansec_pattern(symbol): + a, b, m, n = make_wilds(symbol) + pattern = tan(a*symbol)**m * sec(b*symbol)**n + + return pattern, a, b, m, n + +@cacheit +def cotcsc_pattern(symbol): + a, b, m, n = make_wilds(symbol) + pattern = cot(a*symbol)**m * csc(b*symbol)**n + + return pattern, a, b, m, n + +@cacheit +def heaviside_pattern(symbol): + m = Wild('m', exclude=[symbol]) + b = Wild('b', exclude=[symbol]) + g = Wild('g') + pattern = Heaviside(m*symbol + b) * g + + return pattern, m, b, g + +def uncurry(func): + def uncurry_rl(args): + return func(*args) + return uncurry_rl + +def trig_rewriter(rewrite): + def trig_rewriter_rl(args): + a, b, m, n, integrand, symbol = args + rewritten = rewrite(a, b, m, n, integrand, symbol) + if rewritten != integrand: + return RewriteRule(integrand, symbol, rewritten, integral_steps(rewritten, symbol)) + return trig_rewriter_rl + +sincos_botheven_condition = uncurry( + lambda a, b, m, n, i, s: m.is_even and n.is_even and + m.is_nonnegative and n.is_nonnegative) + +sincos_botheven = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (((1 - cos(2*a*symbol)) / 2) ** (m / 2)) * + (((1 + cos(2*b*symbol)) / 2) ** (n / 2)) )) + +sincos_sinodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd and m >= 3) + +sincos_sinodd = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (1 - cos(a*symbol)**2)**((m - 1) / 2) * + sin(a*symbol) * + cos(b*symbol) ** n)) + +sincos_cosodd_condition = uncurry(lambda a, b, m, n, i, s: n.is_odd and n >= 3) + +sincos_cosodd = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (1 - sin(b*symbol)**2)**((n - 1) / 2) * + cos(b*symbol) * + sin(a*symbol) ** m)) + +tansec_seceven_condition = uncurry(lambda a, b, m, n, i, s: n.is_even and n >= 4) +tansec_seceven = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (1 + tan(b*symbol)**2) ** (n/2 - 1) * + sec(b*symbol)**2 * + tan(a*symbol) ** m )) + +tansec_tanodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd) +tansec_tanodd = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (sec(a*symbol)**2 - 1) ** ((m - 1) / 2) * + tan(a*symbol) * + sec(b*symbol) ** n )) + +tan_tansquared_condition = uncurry(lambda a, b, m, n, i, s: m == 2 and n == 0) +tan_tansquared = trig_rewriter( + lambda a, b, m, n, i, symbol: ( sec(a*symbol)**2 - 1)) + +cotcsc_csceven_condition = uncurry(lambda a, b, m, n, i, s: n.is_even and n >= 4) +cotcsc_csceven = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (1 + cot(b*symbol)**2) ** (n/2 - 1) * + csc(b*symbol)**2 * + cot(a*symbol) ** m )) + +cotcsc_cotodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd) +cotcsc_cotodd = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (csc(a*symbol)**2 - 1) ** ((m - 1) / 2) * + cot(a*symbol) * + csc(b*symbol) ** n )) + +def trig_sincos_rule(integral): + integrand, symbol = integral + + if any(integrand.has(f) for f in (sin, cos)): + pattern, a, b, m, n = sincos_pattern(symbol) + match = integrand.match(pattern) + if not match: + return + + return multiplexer({ + sincos_botheven_condition: sincos_botheven, + sincos_sinodd_condition: sincos_sinodd, + sincos_cosodd_condition: sincos_cosodd + })(tuple( + [match.get(i, S.Zero) for i in (a, b, m, n)] + + [integrand, symbol])) + +def trig_tansec_rule(integral): + integrand, symbol = integral + + integrand = integrand.subs({ + 1 / cos(symbol): sec(symbol) + }) + + if any(integrand.has(f) for f in (tan, sec)): + pattern, a, b, m, n = tansec_pattern(symbol) + match = integrand.match(pattern) + if not match: + return + + return multiplexer({ + tansec_tanodd_condition: tansec_tanodd, + tansec_seceven_condition: tansec_seceven, + tan_tansquared_condition: tan_tansquared + })(tuple( + [match.get(i, S.Zero) for i in (a, b, m, n)] + + [integrand, symbol])) + +def trig_cotcsc_rule(integral): + integrand, symbol = integral + integrand = integrand.subs({ + 1 / sin(symbol): csc(symbol), + 1 / tan(symbol): cot(symbol), + cos(symbol) / tan(symbol): cot(symbol) + }) + + if any(integrand.has(f) for f in (cot, csc)): + pattern, a, b, m, n = cotcsc_pattern(symbol) + match = integrand.match(pattern) + if not match: + return + + return multiplexer({ + cotcsc_cotodd_condition: cotcsc_cotodd, + cotcsc_csceven_condition: cotcsc_csceven + })(tuple( + [match.get(i, S.Zero) for i in (a, b, m, n)] + + [integrand, symbol])) + +def trig_sindouble_rule(integral): + integrand, symbol = integral + a = Wild('a', exclude=[sin(2*symbol)]) + match = integrand.match(sin(2*symbol)*a) + if match: + sin_double = 2*sin(symbol)*cos(symbol)/sin(2*symbol) + return integral_steps(integrand * sin_double, symbol) + +def trig_powers_products_rule(integral): + return do_one(null_safe(trig_sincos_rule), + null_safe(trig_tansec_rule), + null_safe(trig_cotcsc_rule), + null_safe(trig_sindouble_rule))(integral) + +def trig_substitution_rule(integral): + integrand, symbol = integral + A = Wild('a', exclude=[0, symbol]) + B = Wild('b', exclude=[0, symbol]) + theta = Dummy("theta") + target_pattern = A + B*symbol**2 + + matches = integrand.find(target_pattern) + for expr in matches: + match = expr.match(target_pattern) + a = match.get(A, S.Zero) + b = match.get(B, S.Zero) + + a_positive = ((a.is_number and a > 0) or a.is_positive) + b_positive = ((b.is_number and b > 0) or b.is_positive) + a_negative = ((a.is_number and a < 0) or a.is_negative) + b_negative = ((b.is_number and b < 0) or b.is_negative) + x_func = None + if a_positive and b_positive: + # a**2 + b*x**2. Assume sec(theta) > 0, -pi/2 < theta < pi/2 + x_func = (sqrt(a)/sqrt(b)) * tan(theta) + # Do not restrict the domain: tan(theta) takes on any real + # value on the interval -pi/2 < theta < pi/2 so x takes on + # any value + restriction = True + elif a_positive and b_negative: + # a**2 - b*x**2. Assume cos(theta) > 0, -pi/2 < theta < pi/2 + constant = sqrt(a)/sqrt(-b) + x_func = constant * sin(theta) + restriction = And(symbol > -constant, symbol < constant) + elif a_negative and b_positive: + # b*x**2 - a**2. Assume sin(theta) > 0, 0 < theta < pi + constant = sqrt(-a)/sqrt(b) + x_func = constant * sec(theta) + restriction = And(symbol > -constant, symbol < constant) + if x_func: + # Manually simplify sqrt(trig(theta)**2) to trig(theta) + # Valid due to assumed domain restriction + substitutions = {} + for f in [sin, cos, tan, + sec, csc, cot]: + substitutions[sqrt(f(theta)**2)] = f(theta) + substitutions[sqrt(f(theta)**(-2))] = 1/f(theta) + + replaced = integrand.subs(symbol, x_func).trigsimp() + replaced = manual_subs(replaced, substitutions) + if not replaced.has(symbol): + replaced *= manual_diff(x_func, theta) + replaced = replaced.trigsimp() + secants = replaced.find(1/cos(theta)) + if secants: + replaced = replaced.xreplace({ + 1/cos(theta): sec(theta) + }) + + substep = integral_steps(replaced, theta) + if not substep.contains_dont_know(): + return TrigSubstitutionRule(integrand, symbol, + theta, x_func, replaced, substep, restriction) + +def heaviside_rule(integral): + integrand, symbol = integral + pattern, m, b, g = heaviside_pattern(symbol) + match = integrand.match(pattern) + if match and 0 != match[g]: + # f = Heaviside(m*x + b)*g + substep = integral_steps(match[g], symbol) + m, b = match[m], match[b] + return HeavisideRule(integrand, symbol, m*symbol + b, -b/m, substep) + + +def dirac_delta_rule(integral: IntegralInfo): + integrand, x = integral + if len(integrand.args) == 1: + n = S.Zero + else: + n = integrand.args[1] # type: ignore + if not n.is_Integer or n < 0: + return + a, b = Wild('a', exclude=[x]), Wild('b', exclude=[x, 0]) + match = integrand.args[0].match(a+b*x) + if not match: + return + a, b = match[a], match[b] + generic_cond = Ne(b, 0) + if generic_cond is S.true: + degenerate_step = None + else: + degenerate_step = ConstantRule(DiracDelta(a, n), x) + generic_step = DiracDeltaRule(integrand, x, n, a, b) + return _add_degenerate_step(generic_cond, generic_step, degenerate_step) + + +def substitution_rule(integral): + integrand, symbol = integral + + u_var = Dummy("u") + substitutions = find_substitutions(integrand, symbol, u_var) + count = 0 + if substitutions: + debug("List of Substitution Rules") + ways = [] + for u_func, c, substituted in substitutions: + subrule = integral_steps(substituted, u_var) + count = count + 1 + debug("Rule {}: {}".format(count, subrule)) + + if subrule.contains_dont_know(): + continue + + if simplify(c - 1) != 0: + _, denom = c.as_numer_denom() + if subrule: + subrule = ConstantTimesRule(c * substituted, u_var, c, substituted, subrule) + + if denom.free_symbols: + piecewise = [] + could_be_zero = [] + + if isinstance(denom, Mul): + could_be_zero = denom.args + else: + could_be_zero.append(denom) + + for expr in could_be_zero: + if not fuzzy_not(expr.is_zero): + substep = integral_steps(manual_subs(integrand, expr, 0), symbol) + + if substep: + piecewise.append(( + substep, + Eq(expr, 0) + )) + piecewise.append((subrule, True)) + subrule = PiecewiseRule(substituted, symbol, piecewise) + + ways.append(URule(integrand, symbol, u_var, u_func, subrule)) + + if len(ways) > 1: + return AlternativeRule(integrand, symbol, ways) + elif ways: + return ways[0] + + +partial_fractions_rule = rewriter( + lambda integrand, symbol: integrand.is_rational_function(), + lambda integrand, symbol: integrand.apart(symbol)) + +cancel_rule = rewriter( + # lambda integrand, symbol: integrand.is_algebraic_expr(), + # lambda integrand, symbol: isinstance(integrand, Mul), + lambda integrand, symbol: True, + lambda integrand, symbol: integrand.cancel()) + +distribute_expand_rule = rewriter( + lambda integrand, symbol: ( + isinstance(integrand, (Pow, Mul)) or all(arg.is_Pow or arg.is_polynomial(symbol) for arg in integrand.args)), + lambda integrand, symbol: integrand.expand()) + +trig_expand_rule = rewriter( + # If there are trig functions with different arguments, expand them + lambda integrand, symbol: ( + len({a.args[0] for a in integrand.atoms(TrigonometricFunction)}) > 1), + lambda integrand, symbol: integrand.expand(trig=True)) + +def derivative_rule(integral): + integrand = integral[0] + diff_variables = integrand.variables + undifferentiated_function = integrand.expr + integrand_variables = undifferentiated_function.free_symbols + + if integral.symbol in integrand_variables: + if integral.symbol in diff_variables: + return DerivativeRule(*integral) + else: + return DontKnowRule(integrand, integral.symbol) + else: + return ConstantRule(*integral) + +def rewrites_rule(integral): + integrand, symbol = integral + + if integrand.match(1/cos(symbol)): + rewritten = integrand.subs(1/cos(symbol), sec(symbol)) + return RewriteRule(integrand, symbol, rewritten, integral_steps(rewritten, symbol)) + +def fallback_rule(integral): + return DontKnowRule(*integral) + +# Cache is used to break cyclic integrals. +# Need to use the same dummy variable in cached expressions for them to match. +# Also record "u" of integration by parts, to avoid infinite repetition. +_integral_cache: dict[Expr, Expr | None] = {} +_parts_u_cache: dict[Expr, int] = defaultdict(int) +_cache_dummy = Dummy("z") + +def integral_steps(integrand, symbol, **options): + """Returns the steps needed to compute an integral. + + Explanation + =========== + + This function attempts to mirror what a student would do by hand as + closely as possible. + + SymPy Gamma uses this to provide a step-by-step explanation of an + integral. The code it uses to format the results of this function can be + found at + https://github.com/sympy/sympy_gamma/blob/master/app/logic/intsteps.py. + + Examples + ======== + + >>> from sympy import exp, sin + >>> from sympy.integrals.manualintegrate import integral_steps + >>> from sympy.abc import x + >>> print(repr(integral_steps(exp(x) / (1 + exp(2 * x)), x))) \ + # doctest: +NORMALIZE_WHITESPACE + URule(integrand=exp(x)/(exp(2*x) + 1), variable=x, u_var=_u, u_func=exp(x), + substep=ArctanRule(integrand=1/(_u**2 + 1), variable=_u, a=1, b=1, c=1)) + >>> print(repr(integral_steps(sin(x), x))) \ + # doctest: +NORMALIZE_WHITESPACE + SinRule(integrand=sin(x), variable=x) + >>> print(repr(integral_steps((x**2 + 3)**2, x))) \ + # doctest: +NORMALIZE_WHITESPACE + RewriteRule(integrand=(x**2 + 3)**2, variable=x, rewritten=x**4 + 6*x**2 + 9, + substep=AddRule(integrand=x**4 + 6*x**2 + 9, variable=x, + substeps=[PowerRule(integrand=x**4, variable=x, base=x, exp=4), + ConstantTimesRule(integrand=6*x**2, variable=x, constant=6, other=x**2, + substep=PowerRule(integrand=x**2, variable=x, base=x, exp=2)), + ConstantRule(integrand=9, variable=x)])) + + Returns + ======= + + rule : Rule + The first step; most rules have substeps that must also be + considered. These substeps can be evaluated using ``manualintegrate`` + to obtain a result. + + """ + cachekey = integrand.xreplace({symbol: _cache_dummy}) + if cachekey in _integral_cache: + if _integral_cache[cachekey] is None: + # Stop this attempt, because it leads around in a loop + return DontKnowRule(integrand, symbol) + else: + # TODO: This is for future development, as currently + # _integral_cache gets no values other than None + return (_integral_cache[cachekey].xreplace(_cache_dummy, symbol), + symbol) + else: + _integral_cache[cachekey] = None + + integral = IntegralInfo(integrand, symbol) + + def key(integral): + integrand = integral.integrand + + if symbol not in integrand.free_symbols: + return Number + for cls in (Symbol, TrigonometricFunction, OrthogonalPolynomial): + if isinstance(integrand, cls): + return cls + return type(integrand) + + def integral_is_subclass(*klasses): + def _integral_is_subclass(integral): + k = key(integral) + return k and issubclass(k, klasses) + return _integral_is_subclass + + result = do_one( + null_safe(special_function_rule), + null_safe(switch(key, { + Pow: do_one(null_safe(power_rule), null_safe(inverse_trig_rule), + null_safe(sqrt_linear_rule), + null_safe(quadratic_denom_rule)), + Symbol: power_rule, + exp: exp_rule, + Add: add_rule, + Mul: do_one(null_safe(mul_rule), null_safe(trig_product_rule), + null_safe(heaviside_rule), null_safe(quadratic_denom_rule), + null_safe(sqrt_linear_rule), + null_safe(sqrt_quadratic_rule)), + Derivative: derivative_rule, + TrigonometricFunction: trig_rule, + Heaviside: heaviside_rule, + DiracDelta: dirac_delta_rule, + OrthogonalPolynomial: orthogonal_poly_rule, + Number: constant_rule + })), + do_one( + null_safe(trig_rule), + null_safe(hyperbolic_rule), + null_safe(alternatives( + rewrites_rule, + substitution_rule, + condition( + integral_is_subclass(Mul, Pow), + partial_fractions_rule), + condition( + integral_is_subclass(Mul, Pow), + cancel_rule), + condition( + integral_is_subclass(Mul, log, + *inverse_trig_functions), + parts_rule), + condition( + integral_is_subclass(Mul, Pow), + distribute_expand_rule), + trig_powers_products_rule, + trig_expand_rule + )), + null_safe(condition(integral_is_subclass(Mul, Pow), nested_pow_rule)), + null_safe(trig_substitution_rule) + ), + fallback_rule)(integral) + del _integral_cache[cachekey] + return result + + +def manualintegrate(f, var): + """manualintegrate(f, var) + + Explanation + =========== + + Compute indefinite integral of a single variable using an algorithm that + resembles what a student would do by hand. + + Unlike :func:`~.integrate`, var can only be a single symbol. + + Examples + ======== + + >>> from sympy import sin, cos, tan, exp, log, integrate + >>> from sympy.integrals.manualintegrate import manualintegrate + >>> from sympy.abc import x + >>> manualintegrate(1 / x, x) + log(x) + >>> integrate(1/x) + log(x) + >>> manualintegrate(log(x), x) + x*log(x) - x + >>> integrate(log(x)) + x*log(x) - x + >>> manualintegrate(exp(x) / (1 + exp(2 * x)), x) + atan(exp(x)) + >>> integrate(exp(x) / (1 + exp(2 * x))) + RootSum(4*_z**2 + 1, Lambda(_i, _i*log(2*_i + exp(x)))) + >>> manualintegrate(cos(x)**4 * sin(x), x) + -cos(x)**5/5 + >>> integrate(cos(x)**4 * sin(x), x) + -cos(x)**5/5 + >>> manualintegrate(cos(x)**4 * sin(x)**3, x) + cos(x)**7/7 - cos(x)**5/5 + >>> integrate(cos(x)**4 * sin(x)**3, x) + cos(x)**7/7 - cos(x)**5/5 + >>> manualintegrate(tan(x), x) + -log(cos(x)) + >>> integrate(tan(x), x) + -log(cos(x)) + + See Also + ======== + + sympy.integrals.integrals.integrate + sympy.integrals.integrals.Integral.doit + sympy.integrals.integrals.Integral + """ + result = integral_steps(f, var).eval() + # Clear the cache of u-parts + _parts_u_cache.clear() + # If we got Piecewise with two parts, put generic first + if isinstance(result, Piecewise) and len(result.args) == 2: + cond = result.args[0][1] + if isinstance(cond, Eq) and result.args[1][1] == True: + result = result.func( + (result.args[1][0], Ne(*cond.args)), + (result.args[0][0], True)) + return result diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/meijerint.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/meijerint.py new file mode 100644 index 0000000000000000000000000000000000000000..89d8401c7eee0147df2e824dc1dc50b59ca7f0be --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/meijerint.py @@ -0,0 +1,2191 @@ +""" +Integrate functions by rewriting them as Meijer G-functions. + +There are three user-visible functions that can be used by other parts of the +sympy library to solve various integration problems: + +- meijerint_indefinite +- meijerint_definite +- meijerint_inversion + +They can be used to compute, respectively, indefinite integrals, definite +integrals over intervals of the real line, and inverse laplace-type integrals +(from c-I*oo to c+I*oo). See the respective docstrings for details. + +The main references for this are: + +[L] Luke, Y. L. (1969), The Special Functions and Their Approximations, + Volume 1 + +[R] Kelly B. Roach. Meijer G Function Representations. + In: Proceedings of the 1997 International Symposium on Symbolic and + Algebraic Computation, pages 205-211, New York, 1997. ACM. + +[P] A. P. Prudnikov, Yu. A. Brychkov and O. I. Marichev (1990). + Integrals and Series: More Special Functions, Vol. 3,. + Gordon and Breach Science Publisher +""" + +from __future__ import annotations +import itertools + +from sympy import SYMPY_DEBUG +from sympy.core import S, Expr +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core.containers import Tuple +from sympy.core.exprtools import factor_terms +from sympy.core.function import (expand, expand_mul, expand_power_base, + expand_trig, Function) +from sympy.core.mul import Mul +from sympy.core.intfunc import ilcm +from sympy.core.numbers import Rational, pi +from sympy.core.relational import Eq, Ne, _canonical_coeff +from sympy.core.sorting import default_sort_key, ordered +from sympy.core.symbol import Dummy, symbols, Wild, Symbol +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.complexes import (re, im, arg, Abs, sign, + unpolarify, polarify, polar_lift, principal_branch, unbranched_argument, + periodic_argument) +from sympy.functions.elementary.exponential import exp, exp_polar, log +from sympy.functions.elementary.integers import ceiling +from sympy.functions.elementary.hyperbolic import (cosh, sinh, + _rewrite_hyperbolics_as_exp, HyperbolicFunction) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold +from sympy.functions.elementary.trigonometric import (cos, sin, sinc, + TrigonometricFunction) +from sympy.functions.special.bessel import besselj, bessely, besseli, besselk +from sympy.functions.special.delta_functions import DiracDelta, Heaviside +from sympy.functions.special.elliptic_integrals import elliptic_k, elliptic_e +from sympy.functions.special.error_functions import (erf, erfc, erfi, Ei, + expint, Si, Ci, Shi, Chi, fresnels, fresnelc) +from sympy.functions.special.gamma_functions import gamma +from sympy.functions.special.hyper import hyper, meijerg +from sympy.functions.special.singularity_functions import SingularityFunction +from .integrals import Integral +from sympy.logic.boolalg import And, Or, BooleanAtom, Not, BooleanFunction +from sympy.polys import cancel, factor +from sympy.utilities.iterables import multiset_partitions +from sympy.utilities.misc import debug as _debug +from sympy.utilities.misc import debugf as _debugf + +# keep this at top for easy reference +z = Dummy('z') + + +def _has(res, *f): + # return True if res has f; in the case of Piecewise + # only return True if *all* pieces have f + res = piecewise_fold(res) + if getattr(res, 'is_Piecewise', False): + return all(_has(i, *f) for i in res.args) + return res.has(*f) + + +def _create_lookup_table(table): + """ Add formulae for the function -> meijerg lookup table. """ + def wild(n): + return Wild(n, exclude=[z]) + p, q, a, b, c = list(map(wild, 'pqabc')) + n = Wild('n', properties=[lambda x: x.is_Integer and x > 0]) + t = p*z**q + + def add(formula, an, ap, bm, bq, arg=t, fac=S.One, cond=True, hint=True): + table.setdefault(_mytype(formula, z), []).append((formula, + [(fac, meijerg(an, ap, bm, bq, arg))], cond, hint)) + + def addi(formula, inst, cond, hint=True): + table.setdefault( + _mytype(formula, z), []).append((formula, inst, cond, hint)) + + def constant(a): + return [(a, meijerg([1], [], [], [0], z)), + (a, meijerg([], [1], [0], [], z))] + table[()] = [(a, constant(a), True, True)] + + # [P], Section 8. + class IsNonPositiveInteger(Function): + + @classmethod + def eval(cls, arg): + arg = unpolarify(arg) + if arg.is_Integer is True: + return arg <= 0 + + # Section 8.4.2 + # TODO this needs more polar_lift (c/f entry for exp) + add(Heaviside(t - b)*(t - b)**(a - 1), [a], [], [], [0], t/b, + gamma(a)*b**(a - 1), And(b > 0)) + add(Heaviside(b - t)*(b - t)**(a - 1), [], [a], [0], [], t/b, + gamma(a)*b**(a - 1), And(b > 0)) + add(Heaviside(z - (b/p)**(1/q))*(t - b)**(a - 1), [a], [], [], [0], t/b, + gamma(a)*b**(a - 1), And(b > 0)) + add(Heaviside((b/p)**(1/q) - z)*(b - t)**(a - 1), [], [a], [0], [], t/b, + gamma(a)*b**(a - 1), And(b > 0)) + add((b + t)**(-a), [1 - a], [], [0], [], t/b, b**(-a)/gamma(a), + hint=Not(IsNonPositiveInteger(a))) + add(Abs(b - t)**(-a), [1 - a], [(1 - a)/2], [0], [(1 - a)/2], t/b, + 2*sin(pi*a/2)*gamma(1 - a)*Abs(b)**(-a), re(a) < 1) + add((t**a - b**a)/(t - b), [0, a], [], [0, a], [], t/b, + b**(a - 1)*sin(a*pi)/pi) + + # 12 + def A1(r, sign, nu): + return pi**Rational(-1, 2)*(-sign*nu/2)**(1 - 2*r) + + def tmpadd(r, sgn): + # XXX the a**2 is bad for matching + add((sqrt(a**2 + t) + sgn*a)**b/(a**2 + t)**r, + [(1 + b)/2, 1 - 2*r + b/2], [], + [(b - sgn*b)/2], [(b + sgn*b)/2], t/a**2, + a**(b - 2*r)*A1(r, sgn, b)) + tmpadd(0, 1) + tmpadd(0, -1) + tmpadd(S.Half, 1) + tmpadd(S.Half, -1) + + # 13 + def tmpadd(r, sgn): + add((sqrt(a + p*z**q) + sgn*sqrt(p)*z**(q/2))**b/(a + p*z**q)**r, + [1 - r + sgn*b/2], [1 - r - sgn*b/2], [0, S.Half], [], + p*z**q/a, a**(b/2 - r)*A1(r, sgn, b)) + tmpadd(0, 1) + tmpadd(0, -1) + tmpadd(S.Half, 1) + tmpadd(S.Half, -1) + # (those after look obscure) + + # Section 8.4.3 + add(exp(polar_lift(-1)*t), [], [], [0], []) + + # TODO can do sin^n, sinh^n by expansion ... where? + # 8.4.4 (hyperbolic functions) + add(sinh(t), [], [1], [S.Half], [1, 0], t**2/4, pi**Rational(3, 2)) + add(cosh(t), [], [S.Half], [0], [S.Half, S.Half], t**2/4, pi**Rational(3, 2)) + + # Section 8.4.5 + # TODO can do t + a. but can also do by expansion... (XXX not really) + add(sin(t), [], [], [S.Half], [0], t**2/4, sqrt(pi)) + add(cos(t), [], [], [0], [S.Half], t**2/4, sqrt(pi)) + + # Section 8.4.6 (sinc function) + add(sinc(t), [], [], [0], [Rational(-1, 2)], t**2/4, sqrt(pi)/2) + + # Section 8.5.5 + def make_log1(subs): + N = subs[n] + return [(S.NegativeOne**N*factorial(N), + meijerg([], [1]*(N + 1), [0]*(N + 1), [], t))] + + def make_log2(subs): + N = subs[n] + return [(factorial(N), + meijerg([1]*(N + 1), [], [], [0]*(N + 1), t))] + # TODO these only hold for positive p, and can be made more general + # but who uses log(x)*Heaviside(a-x) anyway ... + # TODO also it would be nice to derive them recursively ... + addi(log(t)**n*Heaviside(1 - t), make_log1, True) + addi(log(t)**n*Heaviside(t - 1), make_log2, True) + + def make_log3(subs): + return make_log1(subs) + make_log2(subs) + addi(log(t)**n, make_log3, True) + addi(log(t + a), + constant(log(a)) + [(S.One, meijerg([1, 1], [], [1], [0], t/a))], + True) + addi(log(Abs(t - a)), constant(log(Abs(a))) + + [(pi, meijerg([1, 1], [S.Half], [1], [0, S.Half], t/a))], + True) + # TODO log(x)/(x+a) and log(x)/(x-1) can also be done. should they + # be derivable? + # TODO further formulae in this section seem obscure + + # Sections 8.4.9-10 + # TODO + + # Section 8.4.11 + addi(Ei(t), + constant(-S.ImaginaryUnit*pi) + [(S.NegativeOne, meijerg([], [1], [0, 0], [], + t*polar_lift(-1)))], + True) + + # Section 8.4.12 + add(Si(t), [1], [], [S.Half], [0, 0], t**2/4, sqrt(pi)/2) + add(Ci(t), [], [1], [0, 0], [S.Half], t**2/4, -sqrt(pi)/2) + + # Section 8.4.13 + add(Shi(t), [S.Half], [], [0], [Rational(-1, 2), Rational(-1, 2)], polar_lift(-1)*t**2/4, + t*sqrt(pi)/4) + add(Chi(t), [], [S.Half, 1], [0, 0], [S.Half, S.Half], t**2/4, - + pi**S('3/2')/2) + + # generalized exponential integral + add(expint(a, t), [], [a], [a - 1, 0], [], t) + + # Section 8.4.14 + add(erf(t), [1], [], [S.Half], [0], t**2, 1/sqrt(pi)) + # TODO exp(-x)*erf(I*x) does not work + add(erfc(t), [], [1], [0, S.Half], [], t**2, 1/sqrt(pi)) + # This formula for erfi(z) yields a wrong(?) minus sign + #add(erfi(t), [1], [], [S.Half], [0], -t**2, I/sqrt(pi)) + add(erfi(t), [S.Half], [], [0], [Rational(-1, 2)], -t**2, t/sqrt(pi)) + + # Fresnel Integrals + add(fresnels(t), [1], [], [Rational(3, 4)], [0, Rational(1, 4)], pi**2*t**4/16, S.Half) + add(fresnelc(t), [1], [], [Rational(1, 4)], [0, Rational(3, 4)], pi**2*t**4/16, S.Half) + + ##### bessel-type functions ##### + # Section 8.4.19 + add(besselj(a, t), [], [], [a/2], [-a/2], t**2/4) + + # all of the following are derivable + #add(sin(t)*besselj(a, t), [Rational(1, 4), Rational(3, 4)], [], [(1+a)/2], + # [-a/2, a/2, (1-a)/2], t**2, 1/sqrt(2)) + #add(cos(t)*besselj(a, t), [Rational(1, 4), Rational(3, 4)], [], [a/2], + # [-a/2, (1+a)/2, (1-a)/2], t**2, 1/sqrt(2)) + #add(besselj(a, t)**2, [S.Half], [], [a], [-a, 0], t**2, 1/sqrt(pi)) + #add(besselj(a, t)*besselj(b, t), [0, S.Half], [], [(a + b)/2], + # [-(a+b)/2, (a - b)/2, (b - a)/2], t**2, 1/sqrt(pi)) + + # Section 8.4.20 + add(bessely(a, t), [], [-(a + 1)/2], [a/2, -a/2], [-(a + 1)/2], t**2/4) + + # TODO all of the following should be derivable + #add(sin(t)*bessely(a, t), [Rational(1, 4), Rational(3, 4)], [(1 - a - 1)/2], + # [(1 + a)/2, (1 - a)/2], [(1 - a - 1)/2, (1 - 1 - a)/2, (1 - 1 + a)/2], + # t**2, 1/sqrt(2)) + #add(cos(t)*bessely(a, t), [Rational(1, 4), Rational(3, 4)], [(0 - a - 1)/2], + # [(0 + a)/2, (0 - a)/2], [(0 - a - 1)/2, (1 - 0 - a)/2, (1 - 0 + a)/2], + # t**2, 1/sqrt(2)) + #add(besselj(a, t)*bessely(b, t), [0, S.Half], [(a - b - 1)/2], + # [(a + b)/2, (a - b)/2], [(a - b - 1)/2, -(a + b)/2, (b - a)/2], + # t**2, 1/sqrt(pi)) + #addi(bessely(a, t)**2, + # [(2/sqrt(pi), meijerg([], [S.Half, S.Half - a], [0, a, -a], + # [S.Half - a], t**2)), + # (1/sqrt(pi), meijerg([S.Half], [], [a], [-a, 0], t**2))], + # True) + #addi(bessely(a, t)*bessely(b, t), + # [(2/sqrt(pi), meijerg([], [0, S.Half, (1 - a - b)/2], + # [(a + b)/2, (a - b)/2, (b - a)/2, -(a + b)/2], + # [(1 - a - b)/2], t**2)), + # (1/sqrt(pi), meijerg([0, S.Half], [], [(a + b)/2], + # [-(a + b)/2, (a - b)/2, (b - a)/2], t**2))], + # True) + + # Section 8.4.21 ? + # Section 8.4.22 + add(besseli(a, t), [], [(1 + a)/2], [a/2], [-a/2, (1 + a)/2], t**2/4, pi) + # TODO many more formulas. should all be derivable + + # Section 8.4.23 + add(besselk(a, t), [], [], [a/2, -a/2], [], t**2/4, S.Half) + # TODO many more formulas. should all be derivable + + # Complete elliptic integrals K(z) and E(z) + add(elliptic_k(t), [S.Half, S.Half], [], [0], [0], -t, S.Half) + add(elliptic_e(t), [S.Half, 3*S.Half], [], [0], [0], -t, Rational(-1, 2)/2) + + +#################################################################### +# First some helper functions. +#################################################################### + +from sympy.utilities.timeutils import timethis +timeit = timethis('meijerg') + + +def _mytype(f: Basic, x: Symbol) -> tuple[type[Basic], ...]: + """ Create a hashable entity describing the type of f. """ + def key(x: type[Basic]) -> tuple[int, int, str]: + return x.class_key() + + if x not in f.free_symbols: + return () + elif f.is_Function: + return type(f), + return tuple(sorted((t for a in f.args for t in _mytype(a, x)), key=key)) + + +class _CoeffExpValueError(ValueError): + """ + Exception raised by _get_coeff_exp, for internal use only. + """ + pass + + +def _get_coeff_exp(expr, x): + """ + When expr is known to be of the form c*x**b, with c and/or b possibly 1, + return c, b. + + Examples + ======== + + >>> from sympy.abc import x, a, b + >>> from sympy.integrals.meijerint import _get_coeff_exp + >>> _get_coeff_exp(a*x**b, x) + (a, b) + >>> _get_coeff_exp(x, x) + (1, 1) + >>> _get_coeff_exp(2*x, x) + (2, 1) + >>> _get_coeff_exp(x**3, x) + (1, 3) + """ + from sympy.simplify import powsimp + (c, m) = expand_power_base(powsimp(expr)).as_coeff_mul(x) + if not m: + return c, S.Zero + [m] = m + if m.is_Pow: + if m.base != x: + raise _CoeffExpValueError('expr not of form a*x**b') + return c, m.exp + elif m == x: + return c, S.One + else: + raise _CoeffExpValueError('expr not of form a*x**b: %s' % expr) + + +def _exponents(expr, x): + """ + Find the exponents of ``x`` (not including zero) in ``expr``. + + Examples + ======== + + >>> from sympy.integrals.meijerint import _exponents + >>> from sympy.abc import x, y + >>> from sympy import sin + >>> _exponents(x, x) + {1} + >>> _exponents(x**2, x) + {2} + >>> _exponents(x**2 + x, x) + {1, 2} + >>> _exponents(x**3*sin(x + x**y) + 1/x, x) + {-1, 1, 3, y} + """ + def _exponents_(expr, x, res): + if expr == x: + res.update([1]) + return + if expr.is_Pow and expr.base == x: + res.update([expr.exp]) + return + for argument in expr.args: + _exponents_(argument, x, res) + res = set() + _exponents_(expr, x, res) + return res + + +def _functions(expr, x): + """ Find the types of functions in expr, to estimate the complexity. """ + return {e.func for e in expr.atoms(Function) if x in e.free_symbols} + + +def _find_splitting_points(expr, x): + """ + Find numbers a such that a linear substitution x -> x + a would + (hopefully) simplify expr. + + Examples + ======== + + >>> from sympy.integrals.meijerint import _find_splitting_points as fsp + >>> from sympy import sin + >>> from sympy.abc import x + >>> fsp(x, x) + {0} + >>> fsp((x-1)**3, x) + {1} + >>> fsp(sin(x+3)*x, x) + {-3, 0} + """ + p, q = [Wild(n, exclude=[x]) for n in 'pq'] + + def compute_innermost(expr, res): + if not isinstance(expr, Expr): + return + m = expr.match(p*x + q) + if m and m[p] != 0: + res.add(-m[q]/m[p]) + return + if expr.is_Atom: + return + for argument in expr.args: + compute_innermost(argument, res) + innermost = set() + compute_innermost(expr, innermost) + return innermost + + +def _split_mul(f, x): + """ + Split expression ``f`` into fac, po, g, where fac is a constant factor, + po = x**s for some s independent of s, and g is "the rest". + + Examples + ======== + + >>> from sympy.integrals.meijerint import _split_mul + >>> from sympy import sin + >>> from sympy.abc import s, x + >>> _split_mul((3*x)**s*sin(x**2)*x, x) + (3**s, x*x**s, sin(x**2)) + """ + fac = S.One + po = S.One + g = S.One + f = expand_power_base(f) + + args = Mul.make_args(f) + for a in args: + if a == x: + po *= x + elif x not in a.free_symbols: + fac *= a + else: + if a.is_Pow and x not in a.exp.free_symbols: + c, t = a.base.as_coeff_mul(x) + if t != (x,): + c, t = expand_mul(a.base).as_coeff_mul(x) + if t == (x,): + po *= x**a.exp + fac *= unpolarify(polarify(c**a.exp, subs=False)) + continue + g *= a + + return fac, po, g + + +def _mul_args(f): + """ + Return a list ``L`` such that ``Mul(*L) == f``. + + If ``f`` is not a ``Mul`` or ``Pow``, ``L=[f]``. + If ``f=g**n`` for an integer ``n``, ``L=[g]*n``. + If ``f`` is a ``Mul``, ``L`` comes from applying ``_mul_args`` to all factors of ``f``. + """ + args = Mul.make_args(f) + gs = [] + for g in args: + if g.is_Pow and g.exp.is_Integer: + n = g.exp + base = g.base + if n < 0: + n = -n + base = 1/base + gs += [base]*n + else: + gs.append(g) + return gs + + +def _mul_as_two_parts(f): + """ + Find all the ways to split ``f`` into a product of two terms. + Return None on failure. + + Explanation + =========== + + Although the order is canonical from multiset_partitions, this is + not necessarily the best order to process the terms. For example, + if the case of len(gs) == 2 is removed and multiset is allowed to + sort the terms, some tests fail. + + Examples + ======== + + >>> from sympy.integrals.meijerint import _mul_as_two_parts + >>> from sympy import sin, exp, ordered + >>> from sympy.abc import x + >>> list(ordered(_mul_as_two_parts(x*sin(x)*exp(x)))) + [(x, exp(x)*sin(x)), (x*exp(x), sin(x)), (x*sin(x), exp(x))] + """ + + gs = _mul_args(f) + if len(gs) < 2: + return None + if len(gs) == 2: + return [tuple(gs)] + return [(Mul(*x), Mul(*y)) for (x, y) in multiset_partitions(gs, 2)] + + +def _inflate_g(g, n): + """ Return C, h such that h is a G function of argument z**n and + g = C*h. """ + # TODO should this be a method of meijerg? + # See: [L, page 150, equation (5)] + def inflate(params, n): + """ (a1, .., ak) -> (a1/n, (a1+1)/n, ..., (ak + n-1)/n) """ + return [(a + i)/n for a, i in itertools.product(params, range(n))] + v = S(len(g.ap) - len(g.bq)) + C = n**(1 + g.nu + v/2) + C /= (2*pi)**((n - 1)*g.delta) + return C, meijerg(inflate(g.an, n), inflate(g.aother, n), + inflate(g.bm, n), inflate(g.bother, n), + g.argument**n * n**(n*v)) + + +def _flip_g(g): + """ Turn the G function into one of inverse argument + (i.e. G(1/x) -> G'(x)) """ + # See [L], section 5.2 + def tr(l): + return [1 - a for a in l] + return meijerg(tr(g.bm), tr(g.bother), tr(g.an), tr(g.aother), 1/g.argument) + + +def _inflate_fox_h(g, a): + r""" + Let d denote the integrand in the definition of the G function ``g``. + Consider the function H which is defined in the same way, but with + integrand d/Gamma(a*s) (contour conventions as usual). + + If ``a`` is rational, the function H can be written as C*G, for a constant C + and a G-function G. + + This function returns C, G. + """ + if a < 0: + return _inflate_fox_h(_flip_g(g), -a) + p = S(a.p) + q = S(a.q) + # We use the substitution s->qs, i.e. inflate g by q. We are left with an + # extra factor of Gamma(p*s), for which we use Gauss' multiplication + # theorem. + D, g = _inflate_g(g, q) + z = g.argument + D /= (2*pi)**((1 - p)/2)*p**Rational(-1, 2) + z /= p**p + bs = [(n + 1)/p for n in range(p)] + return D, meijerg(g.an, g.aother, g.bm, list(g.bother) + bs, z) + + +_dummies: dict[tuple[str, str], Dummy] = {} + + +def _dummy(name, token, expr, **kwargs): + """ + Return a dummy. This will return the same dummy if the same token+name is + requested more than once, and it is not already in expr. + This is for being cache-friendly. + """ + d = _dummy_(name, token, **kwargs) + if d in expr.free_symbols: + return Dummy(name, **kwargs) + return d + + +def _dummy_(name, token, **kwargs): + """ + Return a dummy associated to name and token. Same effect as declaring + it globally. + """ + if not (name, token) in _dummies: + _dummies[(name, token)] = Dummy(name, **kwargs) + return _dummies[(name, token)] + + +def _is_analytic(f, x): + """ Check if f(x), when expressed using G functions on the positive reals, + will in fact agree with the G functions almost everywhere """ + return not any(x in expr.free_symbols for expr in f.atoms(Heaviside, Abs)) + + +def _condsimp(cond, first=True): + """ + Do naive simplifications on ``cond``. + + Explanation + =========== + + Note that this routine is completely ad-hoc, simplification rules being + added as need arises rather than following any logical pattern. + + Examples + ======== + + >>> from sympy.integrals.meijerint import _condsimp as simp + >>> from sympy import Or, Eq + >>> from sympy.abc import x, y + >>> simp(Or(x < y, Eq(x, y))) + x <= y + """ + if first: + cond = cond.replace(lambda _: _.is_Relational, _canonical_coeff) + first = False + if not isinstance(cond, BooleanFunction): + return cond + p, q, r = symbols('p q r', cls=Wild) + # transforms tests use 0, 4, 5 and 11-14 + # meijer tests use 0, 2, 11, 14 + # joint_rv uses 6, 7 + rules = [ + (Or(p < q, Eq(p, q)), p <= q), # 0 + # The next two obviously are instances of a general pattern, but it is + # easier to spell out the few cases we care about. + (And(Abs(arg(p)) <= pi, Abs(arg(p) - 2*pi) <= pi), + Eq(arg(p) - pi, 0)), # 1 + (And(Abs(2*arg(p) + pi) <= pi, Abs(2*arg(p) - pi) <= pi), + Eq(arg(p), 0)), # 2 + (And(Abs(2*arg(p) + pi) < pi, Abs(2*arg(p) - pi) <= pi), + S.false), # 3 + (And(Abs(arg(p) - pi/2) <= pi/2, Abs(arg(p) + pi/2) <= pi/2), + Eq(arg(p), 0)), # 4 + (And(Abs(arg(p) - pi/2) <= pi/2, Abs(arg(p) + pi/2) < pi/2), + S.false), # 5 + (And(Abs(arg(p**2/2 + 1)) < pi, Ne(Abs(arg(p**2/2 + 1)), pi)), + S.true), # 6 + (Or(Abs(arg(p**2/2 + 1)) < pi, Ne(1/(p**2/2 + 1), 0)), + S.true), # 7 + (And(Abs(unbranched_argument(p)) <= pi, + Abs(unbranched_argument(exp_polar(-2*pi*S.ImaginaryUnit)*p)) <= pi), + Eq(unbranched_argument(exp_polar(-S.ImaginaryUnit*pi)*p), 0)), # 8 + (And(Abs(unbranched_argument(p)) <= pi/2, + Abs(unbranched_argument(exp_polar(-pi*S.ImaginaryUnit)*p)) <= pi/2), + Eq(unbranched_argument(exp_polar(-S.ImaginaryUnit*pi/2)*p), 0)), # 9 + (Or(p <= q, And(p < q, r)), p <= q), # 10 + (Ne(p**2, 1) & (p**2 > 1), p**2 > 1), # 11 + (Ne(1/p, 1) & (cos(Abs(arg(p)))*Abs(p) > 1), Abs(p) > 1), # 12 + (Ne(p, 2) & (cos(Abs(arg(p)))*Abs(p) > 2), Abs(p) > 2), # 13 + ((Abs(arg(p)) < pi/2) & (cos(Abs(arg(p)))*sqrt(Abs(p**2)) > 1), p**2 > 1), # 14 + ] + cond = cond.func(*[_condsimp(_, first) for _ in cond.args]) + change = True + while change: + change = False + for irule, (fro, to) in enumerate(rules): + if fro.func != cond.func: + continue + for n, arg1 in enumerate(cond.args): + if r in fro.args[0].free_symbols: + m = arg1.match(fro.args[1]) + num = 1 + else: + num = 0 + m = arg1.match(fro.args[0]) + if not m: + continue + otherargs = [x.subs(m) for x in fro.args[:num] + fro.args[num + 1:]] + otherlist = [n] + for arg2 in otherargs: + for k, arg3 in enumerate(cond.args): + if k in otherlist: + continue + if arg2 == arg3: + otherlist += [k] + break + if isinstance(arg3, And) and arg2.args[1] == r and \ + isinstance(arg2, And) and arg2.args[0] in arg3.args: + otherlist += [k] + break + if isinstance(arg3, And) and arg2.args[0] == r and \ + isinstance(arg2, And) and arg2.args[1] in arg3.args: + otherlist += [k] + break + if len(otherlist) != len(otherargs) + 1: + continue + newargs = [arg_ for (k, arg_) in enumerate(cond.args) + if k not in otherlist] + [to.subs(m)] + if SYMPY_DEBUG: + if irule not in (0, 2, 4, 5, 6, 7, 11, 12, 13, 14): + print('used new rule:', irule) + cond = cond.func(*newargs) + change = True + break + + # final tweak + def rel_touchup(rel): + if rel.rel_op != '==' or rel.rhs != 0: + return rel + + # handle Eq(*, 0) + LHS = rel.lhs + m = LHS.match(arg(p)**q) + if not m: + m = LHS.match(unbranched_argument(polar_lift(p)**q)) + if not m: + if isinstance(LHS, periodic_argument) and not LHS.args[0].is_polar \ + and LHS.args[1] is S.Infinity: + return (LHS.args[0] > 0) + return rel + return (m[p] > 0) + cond = cond.replace(lambda _: _.is_Relational, rel_touchup) + if SYMPY_DEBUG: + print('_condsimp: ', cond) + return cond + +def _eval_cond(cond): + """ Re-evaluate the conditions. """ + if isinstance(cond, bool): + return cond + return _condsimp(cond.doit()) + +#################################################################### +# Now the "backbone" functions to do actual integration. +#################################################################### + + +def _my_principal_branch(expr, period, full_pb=False): + """ Bring expr nearer to its principal branch by removing superfluous + factors. + This function does *not* guarantee to yield the principal branch, + to avoid introducing opaque principal_branch() objects, + unless full_pb=True. """ + res = principal_branch(expr, period) + if not full_pb: + res = res.replace(principal_branch, lambda x, y: x) + return res + + +def _rewrite_saxena_1(fac, po, g, x): + """ + Rewrite the integral fac*po*g dx, from zero to infinity, as + integral fac*G, where G has argument a*x. Note po=x**s. + Return fac, G. + """ + _, s = _get_coeff_exp(po, x) + a, b = _get_coeff_exp(g.argument, x) + period = g.get_period() + a = _my_principal_branch(a, period) + + # We substitute t = x**b. + C = fac/(Abs(b)*a**((s + 1)/b - 1)) + # Absorb a factor of (at)**((1 + s)/b - 1). + + def tr(l): + return [a + (1 + s)/b - 1 for a in l] + return C, meijerg(tr(g.an), tr(g.aother), tr(g.bm), tr(g.bother), + a*x) + + +def _check_antecedents_1(g, x, helper=False): + r""" + Return a condition under which the mellin transform of g exists. + Any power of x has already been absorbed into the G function, + so this is just $\int_0^\infty g\, dx$. + + See [L, section 5.6.1]. (Note that s=1.) + + If ``helper`` is True, only check if the MT exists at infinity, i.e. if + $\int_1^\infty g\, dx$ exists. + """ + # NOTE if you update these conditions, please update the documentation as well + delta = g.delta + eta, _ = _get_coeff_exp(g.argument, x) + m, n, p, q = S([len(g.bm), len(g.an), len(g.ap), len(g.bq)]) + + if p > q: + def tr(l): + return [1 - x for x in l] + return _check_antecedents_1(meijerg(tr(g.bm), tr(g.bother), + tr(g.an), tr(g.aother), x/eta), + x) + + tmp = [-re(b) < 1 for b in g.bm] + [1 < 1 - re(a) for a in g.an] + cond_3 = And(*tmp) + + tmp += [-re(b) < 1 for b in g.bother] + tmp += [1 < 1 - re(a) for a in g.aother] + cond_3_star = And(*tmp) + + cond_4 = (-re(g.nu) + (q + 1 - p)/2 > q - p) + + def debug(*msg): + _debug(*msg) + + def debugf(string, arg): + _debugf(string, arg) + + debug('Checking antecedents for 1 function:') + debugf(' delta=%s, eta=%s, m=%s, n=%s, p=%s, q=%s', + (delta, eta, m, n, p, q)) + debugf(' ap = %s, %s', (list(g.an), list(g.aother))) + debugf(' bq = %s, %s', (list(g.bm), list(g.bother))) + debugf(' cond_3=%s, cond_3*=%s, cond_4=%s', (cond_3, cond_3_star, cond_4)) + + conds = [] + + # case 1 + case1 = [] + tmp1 = [1 <= n, p < q, 1 <= m] + tmp2 = [1 <= p, 1 <= m, Eq(q, p + 1), Not(And(Eq(n, 0), Eq(m, p + 1)))] + tmp3 = [1 <= p, Eq(q, p)] + for k in range(ceiling(delta/2) + 1): + tmp3 += [Ne(Abs(unbranched_argument(eta)), (delta - 2*k)*pi)] + tmp = [delta > 0, Abs(unbranched_argument(eta)) < delta*pi] + extra = [Ne(eta, 0), cond_3] + if helper: + extra = [] + for t in [tmp1, tmp2, tmp3]: + case1 += [And(*(t + tmp + extra))] + conds += case1 + debug(' case 1:', case1) + + # case 2 + extra = [cond_3] + if helper: + extra = [] + case2 = [And(Eq(n, 0), p + 1 <= m, m <= q, + Abs(unbranched_argument(eta)) < delta*pi, *extra)] + conds += case2 + debug(' case 2:', case2) + + # case 3 + extra = [cond_3, cond_4] + if helper: + extra = [] + case3 = [And(p < q, 1 <= m, delta > 0, Eq(Abs(unbranched_argument(eta)), delta*pi), + *extra)] + case3 += [And(p <= q - 2, Eq(delta, 0), Eq(Abs(unbranched_argument(eta)), 0), *extra)] + conds += case3 + debug(' case 3:', case3) + + # TODO altered cases 4-7 + + # extra case from wofram functions site: + # (reproduced verbatim from Prudnikov, section 2.24.2) + # https://functions.wolfram.com/HypergeometricFunctions/MeijerG/21/02/01/ + case_extra = [] + case_extra += [Eq(p, q), Eq(delta, 0), Eq(unbranched_argument(eta), 0), Ne(eta, 0)] + if not helper: + case_extra += [cond_3] + s = [] + for a, b in zip(g.ap, g.bq): + s += [b - a] + case_extra += [re(Add(*s)) < 0] + case_extra = And(*case_extra) + conds += [case_extra] + debug(' extra case:', [case_extra]) + + case_extra_2 = [And(delta > 0, Abs(unbranched_argument(eta)) < delta*pi)] + if not helper: + case_extra_2 += [cond_3] + case_extra_2 = And(*case_extra_2) + conds += [case_extra_2] + debug(' second extra case:', [case_extra_2]) + + # TODO This leaves only one case from the three listed by Prudnikov. + # Investigate if these indeed cover everything; if so, remove the rest. + + return Or(*conds) + + +def _int0oo_1(g, x): + r""" + Evaluate $\int_0^\infty g\, dx$ using G functions, + assuming the necessary conditions are fulfilled. + + Examples + ======== + + >>> from sympy.abc import a, b, c, d, x, y + >>> from sympy import meijerg + >>> from sympy.integrals.meijerint import _int0oo_1 + >>> _int0oo_1(meijerg([a], [b], [c], [d], x*y), x) + gamma(-a)*gamma(c + 1)/(y*gamma(-d)*gamma(b + 1)) + """ + from sympy.simplify import gammasimp + # See [L, section 5.6.1]. Note that s=1. + eta, _ = _get_coeff_exp(g.argument, x) + res = 1/eta + # XXX TODO we should reduce order first + for b in g.bm: + res *= gamma(b + 1) + for a in g.an: + res *= gamma(1 - a - 1) + for b in g.bother: + res /= gamma(1 - b - 1) + for a in g.aother: + res /= gamma(a + 1) + return gammasimp(unpolarify(res)) + + +def _rewrite_saxena(fac, po, g1, g2, x, full_pb=False): + """ + Rewrite the integral ``fac*po*g1*g2`` from 0 to oo in terms of G + functions with argument ``c*x``. + + Explanation + =========== + + Return C, f1, f2 such that integral C f1 f2 from 0 to infinity equals + integral fac ``po``, ``g1``, ``g2`` from 0 to infinity. + + Examples + ======== + + >>> from sympy.integrals.meijerint import _rewrite_saxena + >>> from sympy.abc import s, t, m + >>> from sympy import meijerg + >>> g1 = meijerg([], [], [0], [], s*t) + >>> g2 = meijerg([], [], [m/2], [-m/2], t**2/4) + >>> r = _rewrite_saxena(1, t**0, g1, g2, t) + >>> r[0] + s/(4*sqrt(pi)) + >>> r[1] + meijerg(((), ()), ((-1/2, 0), ()), s**2*t/4) + >>> r[2] + meijerg(((), ()), ((m/2,), (-m/2,)), t/4) + """ + def pb(g): + a, b = _get_coeff_exp(g.argument, x) + per = g.get_period() + return meijerg(g.an, g.aother, g.bm, g.bother, + _my_principal_branch(a, per, full_pb)*x**b) + + _, s = _get_coeff_exp(po, x) + _, b1 = _get_coeff_exp(g1.argument, x) + _, b2 = _get_coeff_exp(g2.argument, x) + if (b1 < 0) == True: + b1 = -b1 + g1 = _flip_g(g1) + if (b2 < 0) == True: + b2 = -b2 + g2 = _flip_g(g2) + if not b1.is_Rational or not b2.is_Rational: + return + m1, n1 = b1.p, b1.q + m2, n2 = b2.p, b2.q + tau = ilcm(m1*n2, m2*n1) + r1 = tau//(m1*n2) + r2 = tau//(m2*n1) + + C1, g1 = _inflate_g(g1, r1) + C2, g2 = _inflate_g(g2, r2) + g1 = pb(g1) + g2 = pb(g2) + + fac *= C1*C2 + a1, b = _get_coeff_exp(g1.argument, x) + a2, _ = _get_coeff_exp(g2.argument, x) + + # arbitrarily tack on the x**s part to g1 + # TODO should we try both? + exp = (s + 1)/b - 1 + fac = fac/(Abs(b) * a1**exp) + + def tr(l): + return [a + exp for a in l] + g1 = meijerg(tr(g1.an), tr(g1.aother), tr(g1.bm), tr(g1.bother), a1*x) + g2 = meijerg(g2.an, g2.aother, g2.bm, g2.bother, a2*x) + + from sympy.simplify import powdenest + return powdenest(fac, polar=True), g1, g2 + + +def _check_antecedents(g1, g2, x): + """ Return a condition under which the integral theorem applies. """ + # Yes, this is madness. + # XXX TODO this is a testing *nightmare* + # NOTE if you update these conditions, please update the documentation as well + + # The following conditions are found in + # [P], Section 2.24.1 + # + # They are also reproduced (verbatim!) at + # https://functions.wolfram.com/HypergeometricFunctions/MeijerG/21/02/03/ + # + # Note: k=l=r=alpha=1 + sigma, _ = _get_coeff_exp(g1.argument, x) + omega, _ = _get_coeff_exp(g2.argument, x) + s, t, u, v = S([len(g1.bm), len(g1.an), len(g1.ap), len(g1.bq)]) + m, n, p, q = S([len(g2.bm), len(g2.an), len(g2.ap), len(g2.bq)]) + bstar = s + t - (u + v)/2 + cstar = m + n - (p + q)/2 + rho = g1.nu + (u - v)/2 + 1 + mu = g2.nu + (p - q)/2 + 1 + phi = q - p - (v - u) + eta = 1 - (v - u) - mu - rho + psi = (pi*(q - m - n) + Abs(unbranched_argument(omega)))/(q - p) + theta = (pi*(v - s - t) + Abs(unbranched_argument(sigma)))/(v - u) + + _debug('Checking antecedents:') + _debugf(' sigma=%s, s=%s, t=%s, u=%s, v=%s, b*=%s, rho=%s', + (sigma, s, t, u, v, bstar, rho)) + _debugf(' omega=%s, m=%s, n=%s, p=%s, q=%s, c*=%s, mu=%s,', + (omega, m, n, p, q, cstar, mu)) + _debugf(' phi=%s, eta=%s, psi=%s, theta=%s', (phi, eta, psi, theta)) + + def _c1(): + for g in [g1, g2]: + for i, j in itertools.product(g.an, g.bm): + diff = i - j + if diff.is_integer and diff.is_positive: + return False + return True + c1 = _c1() + c2 = And(*[re(1 + i + j) > 0 for i in g1.bm for j in g2.bm]) + c3 = And(*[re(1 + i + j) < 1 + 1 for i in g1.an for j in g2.an]) + c4 = And(*[(p - q)*re(1 + i - 1) - re(mu) > Rational(-3, 2) for i in g1.an]) + c5 = And(*[(p - q)*re(1 + i) - re(mu) > Rational(-3, 2) for i in g1.bm]) + c6 = And(*[(u - v)*re(1 + i - 1) - re(rho) > Rational(-3, 2) for i in g2.an]) + c7 = And(*[(u - v)*re(1 + i) - re(rho) > Rational(-3, 2) for i in g2.bm]) + c8 = (Abs(phi) + 2*re((rho - 1)*(q - p) + (v - u)*(q - p) + (mu - + 1)*(v - u)) > 0) + c9 = (Abs(phi) - 2*re((rho - 1)*(q - p) + (v - u)*(q - p) + (mu - + 1)*(v - u)) > 0) + c10 = (Abs(unbranched_argument(sigma)) < bstar*pi) + c11 = Eq(Abs(unbranched_argument(sigma)), bstar*pi) + c12 = (Abs(unbranched_argument(omega)) < cstar*pi) + c13 = Eq(Abs(unbranched_argument(omega)), cstar*pi) + + # The following condition is *not* implemented as stated on the wolfram + # function site. In the book of Prudnikov there is an additional part + # (the And involving re()). However, I only have this book in russian, and + # I don't read any russian. The following condition is what other people + # have told me it means. + # Worryingly, it is different from the condition implemented in REDUCE. + # The REDUCE implementation: + # https://reduce-algebra.svn.sourceforge.net/svnroot/reduce-algebra/trunk/packages/defint/definta.red + # (search for tst14) + # The Wolfram alpha version: + # https://functions.wolfram.com/HypergeometricFunctions/MeijerG/21/02/03/03/0014/ + z0 = exp(-(bstar + cstar)*pi*S.ImaginaryUnit) + zos = unpolarify(z0*omega/sigma) + zso = unpolarify(z0*sigma/omega) + if zos == 1/zso: + c14 = And(Eq(phi, 0), bstar + cstar <= 1, + Or(Ne(zos, 1), re(mu + rho + v - u) < 1, + re(mu + rho + q - p) < 1)) + else: + def _cond(z): + '''Returns True if abs(arg(1-z)) < pi, avoiding arg(0). + + Explanation + =========== + + If ``z`` is 1 then arg is NaN. This raises a + TypeError on `NaN < pi`. Previously this gave `False` so + this behavior has been hardcoded here but someone should + check if this NaN is more serious! This NaN is triggered by + test_meijerint() in test_meijerint.py: + `meijerint_definite(exp(x), x, 0, I)` + ''' + return z != 1 and Abs(arg(1 - z)) < pi + + c14 = And(Eq(phi, 0), bstar - 1 + cstar <= 0, + Or(And(Ne(zos, 1), _cond(zos)), + And(re(mu + rho + v - u) < 1, Eq(zos, 1)))) + + c14_alt = And(Eq(phi, 0), cstar - 1 + bstar <= 0, + Or(And(Ne(zso, 1), _cond(zso)), + And(re(mu + rho + q - p) < 1, Eq(zso, 1)))) + + # Since r=k=l=1, in our case there is c14_alt which is the same as calling + # us with (g1, g2) = (g2, g1). The conditions below enumerate all cases + # (i.e. we don't have to try arguments reversed by hand), and indeed try + # all symmetric cases. (i.e. whenever there is a condition involving c14, + # there is also a dual condition which is exactly what we would get when g1, + # g2 were interchanged, *but c14 was unaltered*). + # Hence the following seems correct: + c14 = Or(c14, c14_alt) + + ''' + When `c15` is NaN (e.g. from `psi` being NaN as happens during + 'test_issue_4992' and/or `theta` is NaN as in 'test_issue_6253', + both in `test_integrals.py`) the comparison to 0 formerly gave False + whereas now an error is raised. To keep the old behavior, the value + of NaN is replaced with False but perhaps a closer look at this condition + should be made: XXX how should conditions leading to c15=NaN be handled? + ''' + try: + lambda_c = (q - p)*Abs(omega)**(1/(q - p))*cos(psi) \ + + (v - u)*Abs(sigma)**(1/(v - u))*cos(theta) + # the TypeError might be raised here, e.g. if lambda_c is NaN + if _eval_cond(lambda_c > 0) != False: + c15 = (lambda_c > 0) + else: + def lambda_s0(c1, c2): + return c1*(q - p)*Abs(omega)**(1/(q - p))*sin(psi) \ + + c2*(v - u)*Abs(sigma)**(1/(v - u))*sin(theta) + lambda_s = Piecewise( + ((lambda_s0(+1, +1)*lambda_s0(-1, -1)), + And(Eq(unbranched_argument(sigma), 0), Eq(unbranched_argument(omega), 0))), + (lambda_s0(sign(unbranched_argument(omega)), +1)*lambda_s0(sign(unbranched_argument(omega)), -1), + And(Eq(unbranched_argument(sigma), 0), Ne(unbranched_argument(omega), 0))), + (lambda_s0(+1, sign(unbranched_argument(sigma)))*lambda_s0(-1, sign(unbranched_argument(sigma))), + And(Ne(unbranched_argument(sigma), 0), Eq(unbranched_argument(omega), 0))), + (lambda_s0(sign(unbranched_argument(omega)), sign(unbranched_argument(sigma))), True)) + tmp = [lambda_c > 0, + And(Eq(lambda_c, 0), Ne(lambda_s, 0), re(eta) > -1), + And(Eq(lambda_c, 0), Eq(lambda_s, 0), re(eta) > 0)] + c15 = Or(*tmp) + except TypeError: + c15 = False + for cond, i in [(c1, 1), (c2, 2), (c3, 3), (c4, 4), (c5, 5), (c6, 6), + (c7, 7), (c8, 8), (c9, 9), (c10, 10), (c11, 11), + (c12, 12), (c13, 13), (c14, 14), (c15, 15)]: + _debugf(' c%s: %s', (i, cond)) + + # We will return Or(*conds) + conds = [] + + def pr(count): + _debugf(' case %s: %s', (count, conds[-1])) + conds += [And(m*n*s*t != 0, bstar.is_positive is True, cstar.is_positive is True, c1, c2, c3, c10, + c12)] # 1 + pr(1) + conds += [And(Eq(u, v), Eq(bstar, 0), cstar.is_positive is True, sigma.is_positive is True, re(rho) < 1, + c1, c2, c3, c12)] # 2 + pr(2) + conds += [And(Eq(p, q), Eq(cstar, 0), bstar.is_positive is True, omega.is_positive is True, re(mu) < 1, + c1, c2, c3, c10)] # 3 + pr(3) + conds += [And(Eq(p, q), Eq(u, v), Eq(bstar, 0), Eq(cstar, 0), + sigma.is_positive is True, omega.is_positive is True, re(mu) < 1, re(rho) < 1, + Ne(sigma, omega), c1, c2, c3)] # 4 + pr(4) + conds += [And(Eq(p, q), Eq(u, v), Eq(bstar, 0), Eq(cstar, 0), + sigma.is_positive is True, omega.is_positive is True, re(mu + rho) < 1, + Ne(omega, sigma), c1, c2, c3)] # 5 + pr(5) + conds += [And(p > q, s.is_positive is True, bstar.is_positive is True, cstar >= 0, + c1, c2, c3, c5, c10, c13)] # 6 + pr(6) + conds += [And(p < q, t.is_positive is True, bstar.is_positive is True, cstar >= 0, + c1, c2, c3, c4, c10, c13)] # 7 + pr(7) + conds += [And(u > v, m.is_positive is True, cstar.is_positive is True, bstar >= 0, + c1, c2, c3, c7, c11, c12)] # 8 + pr(8) + conds += [And(u < v, n.is_positive is True, cstar.is_positive is True, bstar >= 0, + c1, c2, c3, c6, c11, c12)] # 9 + pr(9) + conds += [And(p > q, Eq(u, v), Eq(bstar, 0), cstar >= 0, sigma.is_positive is True, + re(rho) < 1, c1, c2, c3, c5, c13)] # 10 + pr(10) + conds += [And(p < q, Eq(u, v), Eq(bstar, 0), cstar >= 0, sigma.is_positive is True, + re(rho) < 1, c1, c2, c3, c4, c13)] # 11 + pr(11) + conds += [And(Eq(p, q), u > v, bstar >= 0, Eq(cstar, 0), omega.is_positive is True, + re(mu) < 1, c1, c2, c3, c7, c11)] # 12 + pr(12) + conds += [And(Eq(p, q), u < v, bstar >= 0, Eq(cstar, 0), omega.is_positive is True, + re(mu) < 1, c1, c2, c3, c6, c11)] # 13 + pr(13) + conds += [And(p < q, u > v, bstar >= 0, cstar >= 0, + c1, c2, c3, c4, c7, c11, c13)] # 14 + pr(14) + conds += [And(p > q, u < v, bstar >= 0, cstar >= 0, + c1, c2, c3, c5, c6, c11, c13)] # 15 + pr(15) + conds += [And(p > q, u > v, bstar >= 0, cstar >= 0, + c1, c2, c3, c5, c7, c8, c11, c13, c14)] # 16 + pr(16) + conds += [And(p < q, u < v, bstar >= 0, cstar >= 0, + c1, c2, c3, c4, c6, c9, c11, c13, c14)] # 17 + pr(17) + conds += [And(Eq(t, 0), s.is_positive is True, bstar.is_positive is True, phi.is_positive is True, c1, c2, c10)] # 18 + pr(18) + conds += [And(Eq(s, 0), t.is_positive is True, bstar.is_positive is True, phi.is_negative is True, c1, c3, c10)] # 19 + pr(19) + conds += [And(Eq(n, 0), m.is_positive is True, cstar.is_positive is True, phi.is_negative is True, c1, c2, c12)] # 20 + pr(20) + conds += [And(Eq(m, 0), n.is_positive is True, cstar.is_positive is True, phi.is_positive is True, c1, c3, c12)] # 21 + pr(21) + conds += [And(Eq(s*t, 0), bstar.is_positive is True, cstar.is_positive is True, + c1, c2, c3, c10, c12)] # 22 + pr(22) + conds += [And(Eq(m*n, 0), bstar.is_positive is True, cstar.is_positive is True, + c1, c2, c3, c10, c12)] # 23 + pr(23) + + # The following case is from [Luke1969]. As far as I can tell, it is *not* + # covered by Prudnikov's. + # Let G1 and G2 be the two G-functions. Suppose the integral exists from + # 0 to a > 0 (this is easy the easy part), that G1 is exponential decay at + # infinity, and that the mellin transform of G2 exists. + # Then the integral exists. + mt1_exists = _check_antecedents_1(g1, x, helper=True) + mt2_exists = _check_antecedents_1(g2, x, helper=True) + conds += [And(mt2_exists, Eq(t, 0), u < s, bstar.is_positive is True, c10, c1, c2, c3)] + pr('E1') + conds += [And(mt2_exists, Eq(s, 0), v < t, bstar.is_positive is True, c10, c1, c2, c3)] + pr('E2') + conds += [And(mt1_exists, Eq(n, 0), p < m, cstar.is_positive is True, c12, c1, c2, c3)] + pr('E3') + conds += [And(mt1_exists, Eq(m, 0), q < n, cstar.is_positive is True, c12, c1, c2, c3)] + pr('E4') + + # Let's short-circuit if this worked ... + # the rest is corner-cases and terrible to read. + r = Or(*conds) + if _eval_cond(r) != False: + return r + + conds += [And(m + n > p, Eq(t, 0), Eq(phi, 0), s.is_positive is True, bstar.is_positive is True, cstar.is_negative is True, + Abs(unbranched_argument(omega)) < (m + n - p + 1)*pi, + c1, c2, c10, c14, c15)] # 24 + pr(24) + conds += [And(m + n > q, Eq(s, 0), Eq(phi, 0), t.is_positive is True, bstar.is_positive is True, cstar.is_negative is True, + Abs(unbranched_argument(omega)) < (m + n - q + 1)*pi, + c1, c3, c10, c14, c15)] # 25 + pr(25) + conds += [And(Eq(p, q - 1), Eq(t, 0), Eq(phi, 0), s.is_positive is True, bstar.is_positive is True, + cstar >= 0, cstar*pi < Abs(unbranched_argument(omega)), + c1, c2, c10, c14, c15)] # 26 + pr(26) + conds += [And(Eq(p, q + 1), Eq(s, 0), Eq(phi, 0), t.is_positive is True, bstar.is_positive is True, + cstar >= 0, cstar*pi < Abs(unbranched_argument(omega)), + c1, c3, c10, c14, c15)] # 27 + pr(27) + conds += [And(p < q - 1, Eq(t, 0), Eq(phi, 0), s.is_positive is True, bstar.is_positive is True, + cstar >= 0, cstar*pi < Abs(unbranched_argument(omega)), + Abs(unbranched_argument(omega)) < (m + n - p + 1)*pi, + c1, c2, c10, c14, c15)] # 28 + pr(28) + conds += [And( + p > q + 1, Eq(s, 0), Eq(phi, 0), t.is_positive is True, bstar.is_positive is True, cstar >= 0, + cstar*pi < Abs(unbranched_argument(omega)), + Abs(unbranched_argument(omega)) < (m + n - q + 1)*pi, + c1, c3, c10, c14, c15)] # 29 + pr(29) + conds += [And(Eq(n, 0), Eq(phi, 0), s + t > 0, m.is_positive is True, cstar.is_positive is True, bstar.is_negative is True, + Abs(unbranched_argument(sigma)) < (s + t - u + 1)*pi, + c1, c2, c12, c14, c15)] # 30 + pr(30) + conds += [And(Eq(m, 0), Eq(phi, 0), s + t > v, n.is_positive is True, cstar.is_positive is True, bstar.is_negative is True, + Abs(unbranched_argument(sigma)) < (s + t - v + 1)*pi, + c1, c3, c12, c14, c15)] # 31 + pr(31) + conds += [And(Eq(n, 0), Eq(phi, 0), Eq(u, v - 1), m.is_positive is True, cstar.is_positive is True, + bstar >= 0, bstar*pi < Abs(unbranched_argument(sigma)), + Abs(unbranched_argument(sigma)) < (bstar + 1)*pi, + c1, c2, c12, c14, c15)] # 32 + pr(32) + conds += [And(Eq(m, 0), Eq(phi, 0), Eq(u, v + 1), n.is_positive is True, cstar.is_positive is True, + bstar >= 0, bstar*pi < Abs(unbranched_argument(sigma)), + Abs(unbranched_argument(sigma)) < (bstar + 1)*pi, + c1, c3, c12, c14, c15)] # 33 + pr(33) + conds += [And( + Eq(n, 0), Eq(phi, 0), u < v - 1, m.is_positive is True, cstar.is_positive is True, bstar >= 0, + bstar*pi < Abs(unbranched_argument(sigma)), + Abs(unbranched_argument(sigma)) < (s + t - u + 1)*pi, + c1, c2, c12, c14, c15)] # 34 + pr(34) + conds += [And( + Eq(m, 0), Eq(phi, 0), u > v + 1, n.is_positive is True, cstar.is_positive is True, bstar >= 0, + bstar*pi < Abs(unbranched_argument(sigma)), + Abs(unbranched_argument(sigma)) < (s + t - v + 1)*pi, + c1, c3, c12, c14, c15)] # 35 + pr(35) + + return Or(*conds) + + # NOTE An alternative, but as far as I can tell weaker, set of conditions + # can be found in [L, section 5.6.2]. + + +def _int0oo(g1, g2, x): + """ + Express integral from zero to infinity g1*g2 using a G function, + assuming the necessary conditions are fulfilled. + + Examples + ======== + + >>> from sympy.integrals.meijerint import _int0oo + >>> from sympy.abc import s, t, m + >>> from sympy import meijerg, S + >>> g1 = meijerg([], [], [-S(1)/2, 0], [], s**2*t/4) + >>> g2 = meijerg([], [], [m/2], [-m/2], t/4) + >>> _int0oo(g1, g2, t) + 4*meijerg(((0, 1/2), ()), ((m/2,), (-m/2,)), s**(-2))/s**2 + """ + # See: [L, section 5.6.2, equation (1)] + eta, _ = _get_coeff_exp(g1.argument, x) + omega, _ = _get_coeff_exp(g2.argument, x) + + def neg(l): + return [-x for x in l] + a1 = neg(g1.bm) + list(g2.an) + a2 = list(g2.aother) + neg(g1.bother) + b1 = neg(g1.an) + list(g2.bm) + b2 = list(g2.bother) + neg(g1.aother) + return meijerg(a1, a2, b1, b2, omega/eta)/eta + + +def _rewrite_inversion(fac, po, g, x): + """ Absorb ``po`` == x**s into g. """ + _, s = _get_coeff_exp(po, x) + a, b = _get_coeff_exp(g.argument, x) + + def tr(l): + return [t + s/b for t in l] + from sympy.simplify import powdenest + return (powdenest(fac/a**(s/b), polar=True), + meijerg(tr(g.an), tr(g.aother), tr(g.bm), tr(g.bother), g.argument)) + + +def _check_antecedents_inversion(g, x): + """ Check antecedents for the laplace inversion integral. """ + _debug('Checking antecedents for inversion:') + z = g.argument + _, e = _get_coeff_exp(z, x) + if e < 0: + _debug(' Flipping G.') + # We want to assume that argument gets large as |x| -> oo + return _check_antecedents_inversion(_flip_g(g), x) + + def statement_half(a, b, c, z, plus): + coeff, exponent = _get_coeff_exp(z, x) + a *= exponent + b *= coeff**c + c *= exponent + conds = [] + wp = b*exp(S.ImaginaryUnit*re(c)*pi/2) + wm = b*exp(-S.ImaginaryUnit*re(c)*pi/2) + if plus: + w = wp + else: + w = wm + conds += [And(Or(Eq(b, 0), re(c) <= 0), re(a) <= -1)] + conds += [And(Ne(b, 0), Eq(im(c), 0), re(c) > 0, re(w) < 0)] + conds += [And(Ne(b, 0), Eq(im(c), 0), re(c) > 0, re(w) <= 0, + re(a) <= -1)] + return Or(*conds) + + def statement(a, b, c, z): + """ Provide a convergence statement for z**a * exp(b*z**c), + c/f sphinx docs. """ + return And(statement_half(a, b, c, z, True), + statement_half(a, b, c, z, False)) + + # Notations from [L], section 5.7-10 + m, n, p, q = S([len(g.bm), len(g.an), len(g.ap), len(g.bq)]) + tau = m + n - p + nu = q - m - n + rho = (tau - nu)/2 + sigma = q - p + if sigma == 1: + epsilon = S.Half + elif sigma > 1: + epsilon = 1 + else: + epsilon = S.NaN + theta = ((1 - sigma)/2 + Add(*g.bq) - Add(*g.ap))/sigma + delta = g.delta + _debugf(' m=%s, n=%s, p=%s, q=%s, tau=%s, nu=%s, rho=%s, sigma=%s', + (m, n, p, q, tau, nu, rho, sigma)) + _debugf(' epsilon=%s, theta=%s, delta=%s', (epsilon, theta, delta)) + + # First check if the computation is valid. + if not (g.delta >= e/2 or (p >= 1 and p >= q)): + _debug(' Computation not valid for these parameters.') + return False + + # Now check if the inversion integral exists. + + # Test "condition A" + for a, b in itertools.product(g.an, g.bm): + if (a - b).is_integer and a > b: + _debug(' Not a valid G function.') + return False + + # There are two cases. If p >= q, we can directly use a slater expansion + # like [L], 5.2 (11). Note in particular that the asymptotics of such an + # expansion even hold when some of the parameters differ by integers, i.e. + # the formula itself would not be valid! (b/c G functions are cts. in their + # parameters) + # When p < q, we need to use the theorems of [L], 5.10. + + if p >= q: + _debug(' Using asymptotic Slater expansion.') + return And(*[statement(a - 1, 0, 0, z) for a in g.an]) + + def E(z): + return And(*[statement(a - 1, 0, 0, z) for a in g.an]) + + def H(z): + return statement(theta, -sigma, 1/sigma, z) + + def Hp(z): + return statement_half(theta, -sigma, 1/sigma, z, True) + + def Hm(z): + return statement_half(theta, -sigma, 1/sigma, z, False) + + # [L], section 5.10 + conds = [] + # Theorem 1 -- p < q from test above + conds += [And(1 <= n, 1 <= m, rho*pi - delta >= pi/2, delta > 0, + E(z*exp(S.ImaginaryUnit*pi*(nu + 1))))] + # Theorem 2, statements (2) and (3) + conds += [And(p + 1 <= m, m + 1 <= q, delta > 0, delta < pi/2, n == 0, + (m - p + 1)*pi - delta >= pi/2, + Hp(z*exp(S.ImaginaryUnit*pi*(q - m))), + Hm(z*exp(-S.ImaginaryUnit*pi*(q - m))))] + # Theorem 2, statement (5) -- p < q from test above + conds += [And(m == q, n == 0, delta > 0, + (sigma + epsilon)*pi - delta >= pi/2, H(z))] + # Theorem 3, statements (6) and (7) + conds += [And(Or(And(p <= q - 2, 1 <= tau, tau <= sigma/2), + And(p + 1 <= m + n, m + n <= (p + q)/2)), + delta > 0, delta < pi/2, (tau + 1)*pi - delta >= pi/2, + Hp(z*exp(S.ImaginaryUnit*pi*nu)), + Hm(z*exp(-S.ImaginaryUnit*pi*nu)))] + # Theorem 4, statements (10) and (11) -- p < q from test above + conds += [And(1 <= m, rho > 0, delta > 0, delta + rho*pi < pi/2, + (tau + epsilon)*pi - delta >= pi/2, + Hp(z*exp(S.ImaginaryUnit*pi*nu)), + Hm(z*exp(-S.ImaginaryUnit*pi*nu)))] + # Trivial case + conds += [m == 0] + + # TODO + # Theorem 5 is quite general + # Theorem 6 contains special cases for q=p+1 + + return Or(*conds) + + +def _int_inversion(g, x, t): + """ + Compute the laplace inversion integral, assuming the formula applies. + """ + b, a = _get_coeff_exp(g.argument, x) + C, g = _inflate_fox_h(meijerg(g.an, g.aother, g.bm, g.bother, b/t**a), -a) + return C/t*g + + +#################################################################### +# Finally, the real meat. +#################################################################### + +_lookup_table = None + + +@cacheit +@timeit +def _rewrite_single(f, x, recursive=True): + """ + Try to rewrite f as a sum of single G functions of the form + C*x**s*G(a*x**b), where b is a rational number and C is independent of x. + We guarantee that result.argument.as_coeff_mul(x) returns (a, (x**b,)) + or (a, ()). + Returns a list of tuples (C, s, G) and a condition cond. + Returns None on failure. + """ + from .transforms import (mellin_transform, inverse_mellin_transform, + IntegralTransformError, MellinTransformStripError) + + global _lookup_table + if not _lookup_table: + _lookup_table = {} + _create_lookup_table(_lookup_table) + + if isinstance(f, meijerg): + coeff, m = factor(f.argument, x).as_coeff_mul(x) + if len(m) > 1: + return None + m = m[0] + if m.is_Pow: + if m.base != x or not m.exp.is_Rational: + return None + elif m != x: + return None + return [(1, 0, meijerg(f.an, f.aother, f.bm, f.bother, coeff*m))], True + + f_ = f + f = f.subs(x, z) + t = _mytype(f, z) + if t in _lookup_table: + l = _lookup_table[t] + for formula, terms, cond, hint in l: + subs = f.match(formula, old=True) + if subs: + subs_ = {} + for fro, to in subs.items(): + subs_[fro] = unpolarify(polarify(to, lift=True), + exponents_only=True) + subs = subs_ + if not isinstance(hint, bool): + hint = hint.subs(subs) + if hint == False: + continue + if not isinstance(cond, (bool, BooleanAtom)): + cond = unpolarify(cond.subs(subs)) + if _eval_cond(cond) == False: + continue + if not isinstance(terms, list): + terms = terms(subs) + res = [] + for fac, g in terms: + r1 = _get_coeff_exp(unpolarify(fac.subs(subs).subs(z, x), + exponents_only=True), x) + try: + g = g.subs(subs).subs(z, x) + except ValueError: + continue + # NOTE these substitutions can in principle introduce oo, + # zoo and other absurdities. It shouldn't matter, + # but better be safe. + if Tuple(*(r1 + (g,))).has(S.Infinity, S.ComplexInfinity, S.NegativeInfinity): + continue + g = meijerg(g.an, g.aother, g.bm, g.bother, + unpolarify(g.argument, exponents_only=True)) + res.append(r1 + (g,)) + if res: + return res, cond + + # try recursive mellin transform + if not recursive: + return None + _debug('Trying recursive Mellin transform method.') + + def my_imt(F, s, x, strip): + """ Calling simplify() all the time is slow and not helpful, since + most of the time it only factors things in a way that has to be + un-done anyway. But sometimes it can remove apparent poles. """ + # XXX should this be in inverse_mellin_transform? + try: + return inverse_mellin_transform(F, s, x, strip, + as_meijerg=True, needeval=True) + except MellinTransformStripError: + from sympy.simplify import simplify + return inverse_mellin_transform( + simplify(cancel(expand(F))), s, x, strip, + as_meijerg=True, needeval=True) + f = f_ + s = _dummy('s', 'rewrite-single', f) + # to avoid infinite recursion, we have to force the two g functions case + + def my_integrator(f, x): + r = _meijerint_definite_4(f, x, only_double=True) + if r is not None: + from sympy.simplify import hyperexpand + res, cond = r + res = _my_unpolarify(hyperexpand(res, rewrite='nonrepsmall')) + return Piecewise((res, cond), + (Integral(f, (x, S.Zero, S.Infinity)), True)) + return Integral(f, (x, S.Zero, S.Infinity)) + try: + F, strip, _ = mellin_transform(f, x, s, integrator=my_integrator, + simplify=False, needeval=True) + g = my_imt(F, s, x, strip) + except IntegralTransformError: + g = None + if g is None: + # We try to find an expression by analytic continuation. + # (also if the dummy is already in the expression, there is no point in + # putting in another one) + a = _dummy_('a', 'rewrite-single') + if a not in f.free_symbols and _is_analytic(f, x): + try: + F, strip, _ = mellin_transform(f.subs(x, a*x), x, s, + integrator=my_integrator, + needeval=True, simplify=False) + g = my_imt(F, s, x, strip).subs(a, 1) + except IntegralTransformError: + g = None + if g is None or g.has(S.Infinity, S.NaN, S.ComplexInfinity): + _debug('Recursive Mellin transform failed.') + return None + args = Add.make_args(g) + res = [] + for f in args: + c, m = f.as_coeff_mul(x) + if len(m) > 1: + raise NotImplementedError('Unexpected form...') + g = m[0] + a, b = _get_coeff_exp(g.argument, x) + res += [(c, 0, meijerg(g.an, g.aother, g.bm, g.bother, + unpolarify(polarify( + a, lift=True), exponents_only=True) + *x**b))] + _debug('Recursive Mellin transform worked:', g) + return res, True + + +def _rewrite1(f, x, recursive=True): + """ + Try to rewrite ``f`` using a (sum of) single G functions with argument a*x**b. + Return fac, po, g such that f = fac*po*g, fac is independent of ``x``. + and po = x**s. + Here g is a result from _rewrite_single. + Return None on failure. + """ + fac, po, g = _split_mul(f, x) + g = _rewrite_single(g, x, recursive) + if g: + return fac, po, g[0], g[1] + + +def _rewrite2(f, x): + """ + Try to rewrite ``f`` as a product of two G functions of arguments a*x**b. + Return fac, po, g1, g2 such that f = fac*po*g1*g2, where fac is + independent of x and po is x**s. + Here g1 and g2 are results of _rewrite_single. + Returns None on failure. + """ + fac, po, g = _split_mul(f, x) + if any(_rewrite_single(expr, x, False) is None for expr in _mul_args(g)): + return None + l = _mul_as_two_parts(g) + if not l: + return None + l = list(ordered(l, [ + lambda p: max(len(_exponents(p[0], x)), len(_exponents(p[1], x))), + lambda p: max(len(_functions(p[0], x)), len(_functions(p[1], x))), + lambda p: max(len(_find_splitting_points(p[0], x)), + len(_find_splitting_points(p[1], x)))])) + + for recursive, (fac1, fac2) in itertools.product((False, True), l): + g1 = _rewrite_single(fac1, x, recursive) + g2 = _rewrite_single(fac2, x, recursive) + if g1 and g2: + cond = And(g1[1], g2[1]) + if cond != False: + return fac, po, g1[0], g2[0], cond + + +def meijerint_indefinite(f, x): + """ + Compute an indefinite integral of ``f`` by rewriting it as a G function. + + Examples + ======== + + >>> from sympy.integrals.meijerint import meijerint_indefinite + >>> from sympy import sin + >>> from sympy.abc import x + >>> meijerint_indefinite(sin(x), x) + -cos(x) + """ + f = sympify(f) + results = [] + for a in sorted(_find_splitting_points(f, x) | {S.Zero}, key=default_sort_key): + res = _meijerint_indefinite_1(f.subs(x, x + a), x) + if not res: + continue + res = res.subs(x, x - a) + if _has(res, hyper, meijerg): + results.append(res) + else: + return res + if f.has(HyperbolicFunction): + _debug('Try rewriting hyperbolics in terms of exp.') + rv = meijerint_indefinite( + _rewrite_hyperbolics_as_exp(f), x) + if rv: + if not isinstance(rv, list): + from sympy.simplify.radsimp import collect + return collect(factor_terms(rv), rv.atoms(exp)) + results.extend(rv) + if results: + return next(ordered(results)) + + +def _meijerint_indefinite_1(f, x): + """ Helper that does not attempt any substitution. """ + _debug('Trying to compute the indefinite integral of', f, 'wrt', x) + from sympy.simplify import hyperexpand, powdenest + + gs = _rewrite1(f, x) + if gs is None: + # Note: the code that calls us will do expand() and try again + return None + + fac, po, gl, cond = gs + _debug(' could rewrite:', gs) + res = S.Zero + for C, s, g in gl: + a, b = _get_coeff_exp(g.argument, x) + _, c = _get_coeff_exp(po, x) + c += s + + # we do a substitution t=a*x**b, get integrand fac*t**rho*g + fac_ = fac * C * x**(1 + c) / b + rho = (c + 1)/b + + # we now use t**rho*G(params, t) = G(params + rho, t) + # [L, page 150, equation (4)] + # and integral G(params, t) dt = G(1, params+1, 0, t) + # (or a similar expression with 1 and 0 exchanged ... pick the one + # which yields a well-defined function) + # [R, section 5] + # (Note that this dummy will immediately go away again, so we + # can safely pass S.One for ``expr``.) + t = _dummy('t', 'meijerint-indefinite', S.One) + + def tr(p): + return [a + rho for a in p] + if any(b.is_integer and (b <= 0) == True for b in tr(g.bm)): + r = -meijerg( + list(g.an), list(g.aother) + [1-rho], list(g.bm) + [-rho], list(g.bother), t) + else: + r = meijerg( + list(g.an) + [1-rho], list(g.aother), list(g.bm), list(g.bother) + [-rho], t) + # The antiderivative is most often expected to be defined + # in the neighborhood of x = 0. + if b.is_extended_nonnegative and not f.subs(x, 0).has(S.NaN, S.ComplexInfinity): + place = 0 # Assume we can expand at zero + else: + place = None + r = hyperexpand(r.subs(t, a*x**b), place=place) + + # now substitute back + # Note: we really do want the powers of x to combine. + res += powdenest(fac_*r, polar=True) + + def _clean(res): + """This multiplies out superfluous powers of x we created, and chops off + constants: + + >> _clean(x*(exp(x)/x - 1/x) + 3) + exp(x) + + cancel is used before mul_expand since it is possible for an + expression to have an additive constant that does not become isolated + with simple expansion. Such a situation was identified in issue 6369: + + Examples + ======== + + >>> from sympy import sqrt, cancel + >>> from sympy.abc import x + >>> a = sqrt(2*x + 1) + >>> bad = (3*x*a**5 + 2*x - a**5 + 1)/a**2 + >>> bad.expand().as_independent(x)[0] + 0 + >>> cancel(bad).expand().as_independent(x)[0] + 1 + """ + res = expand_mul(cancel(res), deep=False) + return Add._from_args(res.as_coeff_add(x)[1]) + + res = piecewise_fold(res, evaluate=None) + if res.is_Piecewise: + newargs = [] + for e, c in res.args: + e = _my_unpolarify(_clean(e)) + newargs += [(e, c)] + res = Piecewise(*newargs, evaluate=False) + else: + res = _my_unpolarify(_clean(res)) + return Piecewise((res, _my_unpolarify(cond)), (Integral(f, x), True)) + + +@timeit +def meijerint_definite(f, x, a, b): + """ + Integrate ``f`` over the interval [``a``, ``b``], by rewriting it as a product + of two G functions, or as a single G function. + + Return res, cond, where cond are convergence conditions. + + Examples + ======== + + >>> from sympy.integrals.meijerint import meijerint_definite + >>> from sympy import exp, oo + >>> from sympy.abc import x + >>> meijerint_definite(exp(-x**2), x, -oo, oo) + (sqrt(pi), True) + + This function is implemented as a succession of functions + meijerint_definite, _meijerint_definite_2, _meijerint_definite_3, + _meijerint_definite_4. Each function in the list calls the next one + (presumably) several times. This means that calling meijerint_definite + can be very costly. + """ + # This consists of three steps: + # 1) Change the integration limits to 0, oo + # 2) Rewrite in terms of G functions + # 3) Evaluate the integral + # + # There are usually several ways of doing this, and we want to try all. + # This function does (1), calls _meijerint_definite_2 for step (2). + _debugf('Integrating %s wrt %s from %s to %s.', (f, x, a, b)) + f = sympify(f) + if f.has(DiracDelta): + _debug('Integrand has DiracDelta terms - giving up.') + return None + + if f.has(SingularityFunction): + _debug('Integrand has Singularity Function terms - giving up.') + return None + + f_, x_, a_, b_ = f, x, a, b + + # Let's use a dummy in case any of the boundaries has x. + d = Dummy('x') + f = f.subs(x, d) + x = d + + if a == b: + return (S.Zero, True) + + results = [] + if a is S.NegativeInfinity and b is not S.Infinity: + return meijerint_definite(f.subs(x, -x), x, -b, -a) + + elif a is S.NegativeInfinity: + # Integrating -oo to oo. We need to find a place to split the integral. + _debug(' Integrating -oo to +oo.') + innermost = _find_splitting_points(f, x) + _debug(' Sensible splitting points:', innermost) + for c in sorted(innermost, key=default_sort_key, reverse=True) + [S.Zero]: + _debug(' Trying to split at', c) + if not c.is_extended_real: + _debug(' Non-real splitting point.') + continue + res1 = _meijerint_definite_2(f.subs(x, x + c), x) + if res1 is None: + _debug(' But could not compute first integral.') + continue + res2 = _meijerint_definite_2(f.subs(x, c - x), x) + if res2 is None: + _debug(' But could not compute second integral.') + continue + res1, cond1 = res1 + res2, cond2 = res2 + cond = _condsimp(And(cond1, cond2)) + if cond == False: + _debug(' But combined condition is always false.') + continue + res = res1 + res2 + return res, cond + + elif a is S.Infinity: + res = meijerint_definite(f, x, b, S.Infinity) + return -res[0], res[1] + + elif (a, b) == (S.Zero, S.Infinity): + # This is a common case - try it directly first. + res = _meijerint_definite_2(f, x) + if res: + if _has(res[0], meijerg): + results.append(res) + else: + return res + + else: + if b is S.Infinity: + for split in _find_splitting_points(f, x): + if (a - split >= 0) == True: + _debugf('Trying x -> x + %s', split) + res = _meijerint_definite_2(f.subs(x, x + split) + *Heaviside(x + split - a), x) + if res: + if _has(res[0], meijerg): + results.append(res) + else: + return res + + f = f.subs(x, x + a) + b = b - a + a = 0 + if b is not S.Infinity: + phi = exp(S.ImaginaryUnit*arg(b)) + b = Abs(b) + f = f.subs(x, phi*x) + f *= Heaviside(b - x)*phi + b = S.Infinity + + _debug('Changed limits to', a, b) + _debug('Changed function to', f) + res = _meijerint_definite_2(f, x) + if res: + if _has(res[0], meijerg): + results.append(res) + else: + return res + if f_.has(HyperbolicFunction): + _debug('Try rewriting hyperbolics in terms of exp.') + rv = meijerint_definite( + _rewrite_hyperbolics_as_exp(f_), x_, a_, b_) + if rv: + if not isinstance(rv, list): + from sympy.simplify.radsimp import collect + rv = (collect(factor_terms(rv[0]), rv[0].atoms(exp)),) + rv[1:] + return rv + results.extend(rv) + if results: + return next(ordered(results)) + + +def _guess_expansion(f, x): + """ Try to guess sensible rewritings for integrand f(x). """ + res = [(f, 'original integrand')] + + orig = res[-1][0] + saw = {orig} + expanded = expand_mul(orig) + if expanded not in saw: + res += [(expanded, 'expand_mul')] + saw.add(expanded) + + expanded = expand(orig) + if expanded not in saw: + res += [(expanded, 'expand')] + saw.add(expanded) + + if orig.has(TrigonometricFunction, HyperbolicFunction): + expanded = expand_mul(expand_trig(orig)) + if expanded not in saw: + res += [(expanded, 'expand_trig, expand_mul')] + saw.add(expanded) + + if orig.has(cos, sin): + from sympy.simplify.fu import sincos_to_sum + reduced = sincos_to_sum(orig) + if reduced not in saw: + res += [(reduced, 'trig power reduction')] + saw.add(reduced) + + return res + + +def _meijerint_definite_2(f, x): + """ + Try to integrate f dx from zero to infinity. + + The body of this function computes various 'simplifications' + f1, f2, ... of f (e.g. by calling expand_mul(), trigexpand() + - see _guess_expansion) and calls _meijerint_definite_3 with each of + these in succession. + If _meijerint_definite_3 succeeds with any of the simplified functions, + returns this result. + """ + # This function does preparation for (2), calls + # _meijerint_definite_3 for (2) and (3) combined. + + # use a positive dummy - we integrate from 0 to oo + # XXX if a nonnegative symbol is used there will be test failures + dummy = _dummy('x', 'meijerint-definite2', f, positive=True) + f = f.subs(x, dummy) + x = dummy + + if f == 0: + return S.Zero, True + + for g, explanation in _guess_expansion(f, x): + _debug('Trying', explanation) + res = _meijerint_definite_3(g, x) + if res: + return res + + +def _meijerint_definite_3(f, x): + """ + Try to integrate f dx from zero to infinity. + + This function calls _meijerint_definite_4 to try to compute the + integral. If this fails, it tries using linearity. + """ + res = _meijerint_definite_4(f, x) + if res and res[1] != False: + return res + if f.is_Add: + _debug('Expanding and evaluating all terms.') + ress = [_meijerint_definite_4(g, x) for g in f.args] + if all(r is not None for r in ress): + conds = [] + res = S.Zero + for r, c in ress: + res += r + conds += [c] + c = And(*conds) + if c != False: + return res, c + + +def _my_unpolarify(f): + return _eval_cond(unpolarify(f)) + + +@timeit +def _meijerint_definite_4(f, x, only_double=False): + """ + Try to integrate f dx from zero to infinity. + + Explanation + =========== + + This function tries to apply the integration theorems found in literature, + i.e. it tries to rewrite f as either one or a product of two G-functions. + + The parameter ``only_double`` is used internally in the recursive algorithm + to disable trying to rewrite f as a single G-function. + """ + from sympy.simplify import hyperexpand + # This function does (2) and (3) + _debug('Integrating', f) + # Try single G function. + if not only_double: + gs = _rewrite1(f, x, recursive=False) + if gs is not None: + fac, po, g, cond = gs + _debug('Could rewrite as single G function:', fac, po, g) + res = S.Zero + for C, s, f in g: + if C == 0: + continue + C, f = _rewrite_saxena_1(fac*C, po*x**s, f, x) + res += C*_int0oo_1(f, x) + cond = And(cond, _check_antecedents_1(f, x)) + if cond == False: + break + cond = _my_unpolarify(cond) + if cond == False: + _debug('But cond is always False.') + else: + _debug('Result before branch substitutions is:', res) + return _my_unpolarify(hyperexpand(res)), cond + + # Try two G functions. + gs = _rewrite2(f, x) + if gs is not None: + for full_pb in [False, True]: + fac, po, g1, g2, cond = gs + _debug('Could rewrite as two G functions:', fac, po, g1, g2) + res = S.Zero + for C1, s1, f1 in g1: + for C2, s2, f2 in g2: + r = _rewrite_saxena(fac*C1*C2, po*x**(s1 + s2), + f1, f2, x, full_pb) + if r is None: + _debug('Non-rational exponents.') + return + C, f1_, f2_ = r + _debug('Saxena subst for yielded:', C, f1_, f2_) + cond = And(cond, _check_antecedents(f1_, f2_, x)) + if cond == False: + break + res += C*_int0oo(f1_, f2_, x) + else: + continue + break + cond = _my_unpolarify(cond) + if cond == False: + _debugf('But cond is always False (full_pb=%s).', full_pb) + else: + _debugf('Result before branch substitutions is: %s', (res, )) + if only_double: + return res, cond + return _my_unpolarify(hyperexpand(res)), cond + + +def meijerint_inversion(f, x, t): + r""" + Compute the inverse laplace transform + $\int_{c+i\infty}^{c-i\infty} f(x) e^{tx}\, dx$, + for real c larger than the real part of all singularities of ``f``. + + Note that ``t`` is always assumed real and positive. + + Return None if the integral does not exist or could not be evaluated. + + Examples + ======== + + >>> from sympy.abc import x, t + >>> from sympy.integrals.meijerint import meijerint_inversion + >>> meijerint_inversion(1/x, x, t) + Heaviside(t) + """ + f_ = f + t_ = t + t = Dummy('t', polar=True) # We don't want sqrt(t**2) = abs(t) etc + f = f.subs(t_, t) + _debug('Laplace-inverting', f) + if not _is_analytic(f, x): + _debug('But expression is not analytic.') + return None + # Exponentials correspond to shifts; we filter them out and then + # shift the result later. If we are given an Add this will not + # work, but the calling code will take care of that. + shift = S.Zero + + if f.is_Mul: + args = list(f.args) + elif isinstance(f, exp): + args = [f] + else: + args = None + + if args: + newargs = [] + exponentials = [] + while args: + arg = args.pop() + if isinstance(arg, exp): + arg2 = expand(arg) + if arg2.is_Mul: + args += arg2.args + continue + try: + a, b = _get_coeff_exp(arg.args[0], x) + except _CoeffExpValueError: + b = 0 + if b == 1: + exponentials.append(a) + else: + newargs.append(arg) + elif arg.is_Pow: + arg2 = expand(arg) + if arg2.is_Mul: + args += arg2.args + continue + if x not in arg.base.free_symbols: + try: + a, b = _get_coeff_exp(arg.exp, x) + except _CoeffExpValueError: + b = 0 + if b == 1: + exponentials.append(a*log(arg.base)) + newargs.append(arg) + else: + newargs.append(arg) + shift = Add(*exponentials) + f = Mul(*newargs) + + if x not in f.free_symbols: + _debug('Expression consists of constant and exp shift:', f, shift) + cond = Eq(im(shift), 0) + if cond == False: + _debug('but shift is nonreal, cannot be a Laplace transform') + return None + res = f*DiracDelta(t + shift) + _debug('Result is a delta function, possibly conditional:', res, cond) + # cond is True or Eq + return Piecewise((res.subs(t, t_), cond)) + + gs = _rewrite1(f, x) + if gs is not None: + fac, po, g, cond = gs + _debug('Could rewrite as single G function:', fac, po, g) + res = S.Zero + for C, s, f in g: + C, f = _rewrite_inversion(fac*C, po*x**s, f, x) + res += C*_int_inversion(f, x, t) + cond = And(cond, _check_antecedents_inversion(f, x)) + if cond == False: + break + cond = _my_unpolarify(cond) + if cond == False: + _debug('But cond is always False.') + else: + _debug('Result before branch substitution:', res) + from sympy.simplify import hyperexpand + res = _my_unpolarify(hyperexpand(res)) + if not res.has(Heaviside): + res *= Heaviside(t) + res = res.subs(t, t + shift) + if not isinstance(cond, bool): + cond = cond.subs(t, t + shift) + from .transforms import InverseLaplaceTransform + return Piecewise((res.subs(t, t_), cond), + (InverseLaplaceTransform(f_.subs(t, t_), x, t_, None), True)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/meijerint_doc.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/meijerint_doc.py new file mode 100644 index 0000000000000000000000000000000000000000..1df385db6b6fe6d46d4a14217aa53d1fdd9670b5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/meijerint_doc.py @@ -0,0 +1,38 @@ +""" This module cooks up a docstring when imported. Its only purpose is to + be displayed in the sphinx documentation. """ + +from __future__ import annotations +from typing import Any + +from sympy.integrals.meijerint import _create_lookup_table +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.expr import Expr +from sympy.core.relational import Eq +from sympy.core.symbol import Symbol +from sympy.printing.latex import latex + +t: dict[tuple[type[Basic], ...], list[Any]] = {} +_create_lookup_table(t) + + +doc = "" +for about, category in t.items(): + if about == (): + doc += 'Elementary functions:\n\n' + else: + doc += 'Functions involving ' + ', '.join('`%s`' % latex( + list(category[0][0].atoms(func))[0]) for func in about) + ':\n\n' + for formula, gs, cond, hint in category: + if not isinstance(gs, list): + g: Expr = Symbol('\\text{generated}') + else: + g = Add(*[fac*f for (fac, f) in gs]) + obj = Eq(formula, g) + if cond is True: + cond = "" + else: + cond = ',\\text{ if } %s' % latex(cond) + doc += ".. math::\n %s%s\n\n" % (latex(obj), cond) + +__doc__ = doc diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/prde.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/prde.py new file mode 100644 index 0000000000000000000000000000000000000000..28e91ea0ff3a82cbeca24c6ed4267503ceb758b5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/prde.py @@ -0,0 +1,1333 @@ +""" +Algorithms for solving Parametric Risch Differential Equations. + +The methods used for solving Parametric Risch Differential Equations parallel +those for solving Risch Differential Equations. See the outline in the +docstring of rde.py for more information. + +The Parametric Risch Differential Equation problem is, given f, g1, ..., gm in +K(t), to determine if there exist y in K(t) and c1, ..., cm in Const(K) such +that Dy + f*y == Sum(ci*gi, (i, 1, m)), and to find such y and ci if they exist. + +For the algorithms here G is a list of tuples of factions of the terms on the +right hand side of the equation (i.e., gi in k(t)), and Q is a list of terms on +the right hand side of the equation (i.e., qi in k[t]). See the docstring of +each function for more information. +""" +import itertools +from functools import reduce + +from sympy.core.intfunc import ilcm +from sympy.core import Dummy, Add, Mul, Pow, S +from sympy.integrals.rde import (order_at, order_at_oo, weak_normalizer, + bound_degree) +from sympy.integrals.risch import (gcdex_diophantine, frac_in, derivation, + residue_reduce, splitfactor, residue_reduce_derivation, DecrementLevel, + recognize_log_derivative) +from sympy.polys import Poly, lcm, cancel, sqf_list +from sympy.polys.polymatrix import PolyMatrix as Matrix +from sympy.solvers import solve + +zeros = Matrix.zeros +eye = Matrix.eye + + +def prde_normal_denom(fa, fd, G, DE): + """ + Parametric Risch Differential Equation - Normal part of the denominator. + + Explanation + =========== + + Given a derivation D on k[t] and f, g1, ..., gm in k(t) with f weakly + normalized with respect to t, return the tuple (a, b, G, h) such that + a, h in k[t], b in k, G = [g1, ..., gm] in k(t)^m, and for any solution + c1, ..., cm in Const(k) and y in k(t) of Dy + f*y == Sum(ci*gi, (i, 1, m)), + q == y*h in k satisfies a*Dq + b*q == Sum(ci*Gi, (i, 1, m)). + """ + dn, ds = splitfactor(fd, DE) + Gas, Gds = list(zip(*G)) + gd = reduce(lambda i, j: i.lcm(j), Gds, Poly(1, DE.t)) + en, es = splitfactor(gd, DE) + + p = dn.gcd(en) + h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t))) + + a = dn*h + c = a*h + + ba = a*fa - dn*derivation(h, DE)*fd + ba, bd = ba.cancel(fd, include=True) + + G = [(c*A).cancel(D, include=True) for A, D in G] + + return (a, (ba, bd), G, h) + +def real_imag(ba, bd, gen): + """ + Helper function, to get the real and imaginary part of a rational function + evaluated at sqrt(-1) without actually evaluating it at sqrt(-1). + + Explanation + =========== + + Separates the even and odd power terms by checking the degree of terms wrt + mod 4. Returns a tuple (ba[0], ba[1], bd) where ba[0] is real part + of the numerator ba[1] is the imaginary part and bd is the denominator + of the rational function. + """ + bd = bd.as_poly(gen).as_dict() + ba = ba.as_poly(gen).as_dict() + denom_real = [value if key[0] % 4 == 0 else -value if key[0] % 4 == 2 else 0 for key, value in bd.items()] + denom_imag = [value if key[0] % 4 == 1 else -value if key[0] % 4 == 3 else 0 for key, value in bd.items()] + bd_real = sum(r for r in denom_real) + bd_imag = sum(r for r in denom_imag) + num_real = [value if key[0] % 4 == 0 else -value if key[0] % 4 == 2 else 0 for key, value in ba.items()] + num_imag = [value if key[0] % 4 == 1 else -value if key[0] % 4 == 3 else 0 for key, value in ba.items()] + ba_real = sum(r for r in num_real) + ba_imag = sum(r for r in num_imag) + ba = ((ba_real*bd_real + ba_imag*bd_imag).as_poly(gen), (ba_imag*bd_real - ba_real*bd_imag).as_poly(gen)) + bd = (bd_real*bd_real + bd_imag*bd_imag).as_poly(gen) + return (ba[0], ba[1], bd) + + +def prde_special_denom(a, ba, bd, G, DE, case='auto'): + """ + Parametric Risch Differential Equation - Special part of the denominator. + + Explanation + =========== + + Case is one of {'exp', 'tan', 'primitive'} for the hyperexponential, + hypertangent, and primitive cases, respectively. For the hyperexponential + (resp. hypertangent) case, given a derivation D on k[t] and a in k[t], + b in k, and g1, ..., gm in k(t) with Dt/t in k (resp. Dt/(t**2 + 1) in + k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp. + gcd(a, t**2 + 1) == 1), return the tuple (A, B, GG, h) such that A, B, h in + k[t], GG = [gg1, ..., ggm] in k(t)^m, and for any solution c1, ..., cm in + Const(k) and q in k of a*Dq + b*q == Sum(ci*gi, (i, 1, m)), r == q*h in + k[t] satisfies A*Dr + B*r == Sum(ci*ggi, (i, 1, m)). + + For case == 'primitive', k == k[t], so it returns (a, b, G, 1) in this + case. + """ + # TODO: Merge this with the very similar special_denom() in rde.py + if case == 'auto': + case = DE.case + + if case == 'exp': + p = Poly(DE.t, DE.t) + elif case == 'tan': + p = Poly(DE.t**2 + 1, DE.t) + elif case in ('primitive', 'base'): + B = ba.quo(bd) + return (a, B, G, Poly(1, DE.t)) + else: + raise ValueError("case must be one of {'exp', 'tan', 'primitive', " + "'base'}, not %s." % case) + + nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) + nc = min(order_at(Ga, p, DE.t) - order_at(Gd, p, DE.t) for Ga, Gd in G) + n = min(0, nc - min(0, nb)) + if not nb: + # Possible cancellation. + if case == 'exp': + dcoeff = DE.d.quo(Poly(DE.t, DE.t)) + with DecrementLevel(DE): # We are guaranteed to not have problems, + # because case != 'base'. + alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t) + etaa, etad = frac_in(dcoeff, DE.t) + A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) + if A is not None: + Q, m, z = A + if Q == 1: + n = min(n, m) + + elif case == 'tan': + dcoeff = DE.d.quo(Poly(DE.t**2 + 1, DE.t)) + with DecrementLevel(DE): # We are guaranteed to not have problems, + # because case != 'base'. + betaa, alphaa, alphad = real_imag(ba, bd*a, DE.t) + betad = alphad + etaa, etad = frac_in(dcoeff, DE.t) + if recognize_log_derivative(Poly(2, DE.t)*betaa, betad, DE): + A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) + B = parametric_log_deriv(betaa, betad, etaa, etad, DE) + if A is not None and B is not None: + Q, s, z = A + # TODO: Add test + if Q == 1: + n = min(n, s/2) + + N = max(0, -nb) + pN = p**N + pn = p**-n # This is 1/h + + A = a*pN + B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN + G = [(Ga*pN*pn).cancel(Gd, include=True) for Ga, Gd in G] + h = pn + + # (a*p**N, (b + n*a*Dp/p)*p**N, g1*p**(N - n), ..., gm*p**(N - n), p**-n) + return (A, B, G, h) + + +def prde_linear_constraints(a, b, G, DE): + """ + Parametric Risch Differential Equation - Generate linear constraints on the constants. + + Explanation + =========== + + Given a derivation D on k[t], a, b, in k[t] with gcd(a, b) == 1, and + G = [g1, ..., gm] in k(t)^m, return Q = [q1, ..., qm] in k[t]^m and a + matrix M with entries in k(t) such that for any solution c1, ..., cm in + Const(k) and p in k[t] of a*Dp + b*p == Sum(ci*gi, (i, 1, m)), + (c1, ..., cm) is a solution of Mx == 0, and p and the ci satisfy + a*Dp + b*p == Sum(ci*qi, (i, 1, m)). + + Because M has entries in k(t), and because Matrix does not play well with + Poly, M will be a Matrix of Basic expressions. + """ + m = len(G) + + Gns, Gds = list(zip(*G)) + d = reduce(lambda i, j: i.lcm(j), Gds) + d = Poly(d, field=True) + Q = [(ga*(d).quo(gd)).div(d) for ga, gd in G] + + if not all(ri.is_zero for _, ri in Q): + N = max(ri.degree(DE.t) for _, ri in Q) + M = Matrix(N + 1, m, lambda i, j: Q[j][1].nth(i), DE.t) + else: + M = Matrix(0, m, [], DE.t) # No constraints, return the empty matrix. + + qs, _ = list(zip(*Q)) + return (qs, M) + +def poly_linear_constraints(p, d): + """ + Given p = [p1, ..., pm] in k[t]^m and d in k[t], return + q = [q1, ..., qm] in k[t]^m and a matrix M with entries in k such + that Sum(ci*pi, (i, 1, m)), for c1, ..., cm in k, is divisible + by d if and only if (c1, ..., cm) is a solution of Mx = 0, in + which case the quotient is Sum(ci*qi, (i, 1, m)). + """ + m = len(p) + q, r = zip(*[pi.div(d) for pi in p]) + + if not all(ri.is_zero for ri in r): + n = max(ri.degree() for ri in r) + M = Matrix(n + 1, m, lambda i, j: r[j].nth(i), d.gens) + else: + M = Matrix(0, m, [], d.gens) # No constraints. + + return q, M + +def constant_system(A, u, DE): + """ + Generate a system for the constant solutions. + + Explanation + =========== + + Given a differential field (K, D) with constant field C = Const(K), a Matrix + A, and a vector (Matrix) u with coefficients in K, returns the tuple + (B, v, s), where B is a Matrix with coefficients in C and v is a vector + (Matrix) such that either v has coefficients in C, in which case s is True + and the solutions in C of Ax == u are exactly all the solutions of Bx == v, + or v has a non-constant coefficient, in which case s is False Ax == u has no + constant solution. + + This algorithm is used both in solving parametric problems and in + determining if an element a of K is a derivative of an element of K or the + logarithmic derivative of a K-radical using the structure theorem approach. + + Because Poly does not play well with Matrix yet, this algorithm assumes that + all matrix entries are Basic expressions. + """ + if not A: + return A, u + Au = A.row_join(u) + Au, _ = Au.rref() + # Warning: This will NOT return correct results if cancel() cannot reduce + # an identically zero expression to 0. The danger is that we might + # incorrectly prove that an integral is nonelementary (such as + # risch_integrate(exp((sin(x)**2 + cos(x)**2 - 1)*x**2), x). + # But this is a limitation in computer algebra in general, and implicit + # in the correctness of the Risch Algorithm is the computability of the + # constant field (actually, this same correctness problem exists in any + # algorithm that uses rref()). + # + # We therefore limit ourselves to constant fields that are computable + # via the cancel() function, in order to prevent a speed bottleneck from + # calling some more complex simplification function (rational function + # coefficients will fall into this class). Furthermore, (I believe) this + # problem will only crop up if the integral explicitly contains an + # expression in the constant field that is identically zero, but cannot + # be reduced to such by cancel(). Therefore, a careful user can avoid this + # problem entirely by being careful with the sorts of expressions that + # appear in his integrand in the variables other than the integration + # variable (the structure theorems should be able to completely decide these + # problems in the integration variable). + + A, u = Au[:, :-1], Au[:, -1] + + D = lambda x: derivation(x, DE, basic=True) + + for j, i in itertools.product(range(A.cols), range(A.rows)): + if A[i, j].expr.has(*DE.T): + # This assumes that const(F(t0, ..., tn) == const(K) == F + Ri = A[i, :] + # Rm+1; m = A.rows + DAij = D(A[i, j]) + Rm1 = Ri.applyfunc(lambda x: D(x) / DAij) + um1 = D(u[i]) / DAij + + Aj = A[:, j] + A = A - Aj * Rm1 + u = u - Aj * um1 + + A = A.col_join(Rm1) + u = u.col_join(Matrix([um1], u.gens)) + + return (A, u) + + +def prde_spde(a, b, Q, n, DE): + """ + Special Polynomial Differential Equation algorithm: Parametric Version. + + Explanation + =========== + + Given a derivation D on k[t], an integer n, and a, b, q1, ..., qm in k[t] + with deg(a) > 0 and gcd(a, b) == 1, return (A, B, Q, R, n1), with + Qq = [q1, ..., qm] and R = [r1, ..., rm], such that for any solution + c1, ..., cm in Const(k) and q in k[t] of degree at most n of + a*Dq + b*q == Sum(ci*gi, (i, 1, m)), p = (q - Sum(ci*ri, (i, 1, m)))/a has + degree at most n1 and satisfies A*Dp + B*p == Sum(ci*qi, (i, 1, m)) + """ + R, Z = list(zip(*[gcdex_diophantine(b, a, qi) for qi in Q])) + + A = a + B = b + derivation(a, DE) + Qq = [zi - derivation(ri, DE) for ri, zi in zip(R, Z)] + R = list(R) + n1 = n - a.degree(DE.t) + + return (A, B, Qq, R, n1) + + +def prde_no_cancel_b_large(b, Q, n, DE): + """ + Parametric Poly Risch Differential Equation - No cancellation: deg(b) large enough. + + Explanation + =========== + + Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with + b != 0 and either D == d/dt or deg(b) > max(0, deg(D) - 1), returns + h1, ..., hr in k[t] and a matrix A with coefficients in Const(k) such that + if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and + Dq + b*q == Sum(ci*qi, (i, 1, m)), then q = Sum(dj*hj, (j, 1, r)), where + d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. + """ + db = b.degree(DE.t) + m = len(Q) + H = [Poly(0, DE.t)]*m + + for N, i in itertools.product(range(n, -1, -1), range(m)): # [n, ..., 0] + si = Q[i].nth(N + db)/b.LC() + sitn = Poly(si*DE.t**N, DE.t) + H[i] = H[i] + sitn + Q[i] = Q[i] - derivation(sitn, DE) - b*sitn + + if all(qi.is_zero for qi in Q): + dc = -1 + else: + dc = max(qi.degree(DE.t) for qi in Q) + M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i), DE.t) + A, u = constant_system(M, zeros(dc + 1, 1, DE.t), DE) + c = eye(m, DE.t) + A = A.row_join(zeros(A.rows, m, DE.t)).col_join(c.row_join(-c)) + + return (H, A) + + +def prde_no_cancel_b_small(b, Q, n, DE): + """ + Parametric Poly Risch Differential Equation - No cancellation: deg(b) small enough. + + Explanation + =========== + + Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with + deg(b) < deg(D) - 1 and either D == d/dt or deg(D) >= 2, returns + h1, ..., hr in k[t] and a matrix A with coefficients in Const(k) such that + if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and + Dq + b*q == Sum(ci*qi, (i, 1, m)) then q = Sum(dj*hj, (j, 1, r)) where + d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. + """ + m = len(Q) + H = [Poly(0, DE.t)]*m + + for N, i in itertools.product(range(n, 0, -1), range(m)): # [n, ..., 1] + si = Q[i].nth(N + DE.d.degree(DE.t) - 1)/(N*DE.d.LC()) + sitn = Poly(si*DE.t**N, DE.t) + H[i] = H[i] + sitn + Q[i] = Q[i] - derivation(sitn, DE) - b*sitn + + if b.degree(DE.t) > 0: + for i in range(m): + si = Poly(Q[i].nth(b.degree(DE.t))/b.LC(), DE.t) + H[i] = H[i] + si + Q[i] = Q[i] - derivation(si, DE) - b*si + if all(qi.is_zero for qi in Q): + dc = -1 + else: + dc = max(qi.degree(DE.t) for qi in Q) + M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i), DE.t) + A, u = constant_system(M, zeros(dc + 1, 1, DE.t), DE) + c = eye(m, DE.t) + A = A.row_join(zeros(A.rows, m, DE.t)).col_join(c.row_join(-c)) + return (H, A) + + # else: b is in k, deg(qi) < deg(Dt) + + t = DE.t + if DE.case != 'base': + with DecrementLevel(DE): + t0 = DE.t # k = k0(t0) + ba, bd = frac_in(b, t0, field=True) + Q0 = [frac_in(qi.TC(), t0, field=True) for qi in Q] + f, B = param_rischDE(ba, bd, Q0, DE) + + # f = [f1, ..., fr] in k^r and B is a matrix with + # m + r columns and entries in Const(k) = Const(k0) + # such that Dy0 + b*y0 = Sum(ci*qi, (i, 1, m)) has + # a solution y0 in k with c1, ..., cm in Const(k) + # if and only y0 = Sum(dj*fj, (j, 1, r)) where + # d1, ..., dr ar in Const(k) and + # B*Matrix([c1, ..., cm, d1, ..., dr]) == 0. + + # Transform fractions (fa, fd) in f into constant + # polynomials fa/fd in k[t]. + # (Is there a better way?) + f = [Poly(fa.as_expr()/fd.as_expr(), t, field=True) + for fa, fd in f] + B = Matrix.from_Matrix(B.to_Matrix(), t) + else: + # Base case. Dy == 0 for all y in k and b == 0. + # Dy + b*y = Sum(ci*qi) is solvable if and only if + # Sum(ci*qi) == 0 in which case the solutions are + # y = d1*f1 for f1 = 1 and any d1 in Const(k) = k. + + f = [Poly(1, t, field=True)] # r = 1 + B = Matrix([[qi.TC() for qi in Q] + [S.Zero]], DE.t) + # The condition for solvability is + # B*Matrix([c1, ..., cm, d1]) == 0 + # There are no constraints on d1. + + # Coefficients of t^j (j > 0) in Sum(ci*qi) must be zero. + d = max(qi.degree(DE.t) for qi in Q) + if d > 0: + M = Matrix(d, m, lambda i, j: Q[j].nth(i + 1), DE.t) + A, _ = constant_system(M, zeros(d, 1, DE.t), DE) + else: + # No constraints on the hj. + A = Matrix(0, m, [], DE.t) + + # Solutions of the original equation are + # y = Sum(dj*fj, (j, 1, r) + Sum(ei*hi, (i, 1, m)), + # where ei == ci (i = 1, ..., m), when + # A*Matrix([c1, ..., cm]) == 0 and + # B*Matrix([c1, ..., cm, d1, ..., dr]) == 0 + + # Build combined constraint matrix with m + r + m columns. + + r = len(f) + I = eye(m, DE.t) + A = A.row_join(zeros(A.rows, r + m, DE.t)) + B = B.row_join(zeros(B.rows, m, DE.t)) + C = I.row_join(zeros(m, r, DE.t)).row_join(-I) + + return f + H, A.col_join(B).col_join(C) + + +def prde_cancel_liouvillian(b, Q, n, DE): + """ + Pg, 237. + """ + H = [] + + # Why use DecrementLevel? Below line answers that: + # Assuming that we can solve such problems over 'k' (not k[t]) + if DE.case == 'primitive': + with DecrementLevel(DE): + ba, bd = frac_in(b, DE.t, field=True) + + for i in range(n, -1, -1): + if DE.case == 'exp': # this re-checking can be avoided + with DecrementLevel(DE): + ba, bd = frac_in(b + (i*(derivation(DE.t, DE)/DE.t)).as_poly(b.gens), + DE.t, field=True) + with DecrementLevel(DE): + Qy = [frac_in(q.nth(i), DE.t, field=True) for q in Q] + fi, Ai = param_rischDE(ba, bd, Qy, DE) + fi = [Poly(fa.as_expr()/fd.as_expr(), DE.t, field=True) + for fa, fd in fi] + Ai = Ai.set_gens(DE.t) + + ri = len(fi) + + if i == n: + M = Ai + else: + M = Ai.col_join(M.row_join(zeros(M.rows, ri, DE.t))) + + Fi, hi = [None]*ri, [None]*ri + + # from eq. on top of p.238 (unnumbered) + for j in range(ri): + hji = fi[j] * (DE.t**i).as_poly(fi[j].gens) + hi[j] = hji + # building up Sum(djn*(D(fjn*t^n) - b*fjnt^n)) + Fi[j] = -(derivation(hji, DE) - b*hji) + + H += hi + # in the next loop instead of Q it has + # to be Q + Fi taking its place + Q = Q + Fi + + return (H, M) + + +def param_poly_rischDE(a, b, q, n, DE): + """Polynomial solutions of a parametric Risch differential equation. + + Explanation + =========== + + Given a derivation D in k[t], a, b in k[t] relatively prime, and q + = [q1, ..., qm] in k[t]^m, return h = [h1, ..., hr] in k[t]^r and + a matrix A with m + r columns and entries in Const(k) such that + a*Dp + b*p = Sum(ci*qi, (i, 1, m)) has a solution p of degree <= n + in k[t] with c1, ..., cm in Const(k) if and only if p = Sum(dj*hj, + (j, 1, r)) where d1, ..., dr are in Const(k) and (c1, ..., cm, + d1, ..., dr) is a solution of Ax == 0. + """ + m = len(q) + if n < 0: + # Only the trivial zero solution is possible. + # Find relations between the qi. + if all(qi.is_zero for qi in q): + return [], zeros(1, m, DE.t) # No constraints. + + N = max(qi.degree(DE.t) for qi in q) + M = Matrix(N + 1, m, lambda i, j: q[j].nth(i), DE.t) + A, _ = constant_system(M, zeros(M.rows, 1, DE.t), DE) + + return [], A + + if a.is_ground: + # Normalization: a = 1. + a = a.LC() + b, q = b.to_field().exquo_ground(a), [qi.to_field().exquo_ground(a) for qi in q] + + if not b.is_zero and (DE.case == 'base' or + b.degree() > max(0, DE.d.degree() - 1)): + return prde_no_cancel_b_large(b, q, n, DE) + + elif ((b.is_zero or b.degree() < DE.d.degree() - 1) + and (DE.case == 'base' or DE.d.degree() >= 2)): + return prde_no_cancel_b_small(b, q, n, DE) + + elif (DE.d.degree() >= 2 and + b.degree() == DE.d.degree() - 1 and + n > -b.as_poly().LC()/DE.d.as_poly().LC()): + raise NotImplementedError("prde_no_cancel_b_equal() is " + "not yet implemented.") + + else: + # Liouvillian cases + if DE.case in ('primitive', 'exp'): + return prde_cancel_liouvillian(b, q, n, DE) + else: + raise NotImplementedError("non-linear and hypertangent " + "cases have not yet been implemented") + + # else: deg(a) > 0 + + # Iterate SPDE as long as possible cumulating coefficient + # and terms for the recovery of original solutions. + alpha, beta = a.one, [a.zero]*m + while n >= 0: # and a, b relatively prime + a, b, q, r, n = prde_spde(a, b, q, n, DE) + beta = [betai + alpha*ri for betai, ri in zip(beta, r)] + alpha *= a + # Solutions p of a*Dp + b*p = Sum(ci*qi) correspond to + # solutions alpha*p + Sum(ci*betai) of the initial equation. + d = a.gcd(b) + if not d.is_ground: + break + + # a*Dp + b*p = Sum(ci*qi) may have a polynomial solution + # only if the sum is divisible by d. + + qq, M = poly_linear_constraints(q, d) + # qq = [qq1, ..., qqm] where qqi = qi.quo(d). + # M is a matrix with m columns an entries in k. + # Sum(fi*qi, (i, 1, m)), where f1, ..., fm are elements of k, is + # divisible by d if and only if M*Matrix([f1, ..., fm]) == 0, + # in which case the quotient is Sum(fi*qqi). + + A, _ = constant_system(M, zeros(M.rows, 1, DE.t), DE) + # A is a matrix with m columns and entries in Const(k). + # Sum(ci*qqi) is Sum(ci*qi).quo(d), and the remainder is zero + # for c1, ..., cm in Const(k) if and only if + # A*Matrix([c1, ...,cm]) == 0. + + V = A.nullspace() + # V = [v1, ..., vu] where each vj is a column matrix with + # entries aj1, ..., ajm in Const(k). + # Sum(aji*qi) is divisible by d with exact quotient Sum(aji*qqi). + # Sum(ci*qi) is divisible by d if and only if ci = Sum(dj*aji) + # (i = 1, ..., m) for some d1, ..., du in Const(k). + # In that case, solutions of + # a*Dp + b*p = Sum(ci*qi) = Sum(dj*Sum(aji*qi)) + # are the same as those of + # (a/d)*Dp + (b/d)*p = Sum(dj*rj) + # where rj = Sum(aji*qqi). + + if not V: # No non-trivial solution. + return [], eye(m, DE.t) # Could return A, but this has + # the minimum number of rows. + + Mqq = Matrix([qq]) # A single row. + r = [(Mqq*vj)[0] for vj in V] # [r1, ..., ru] + + # Solutions of (a/d)*Dp + (b/d)*p = Sum(dj*rj) correspond to + # solutions alpha*p + Sum(Sum(dj*aji)*betai) of the initial + # equation. These are equal to alpha*p + Sum(dj*fj) where + # fj = Sum(aji*betai). + Mbeta = Matrix([beta]) + f = [(Mbeta*vj)[0] for vj in V] # [f1, ..., fu] + + # + # Solve the reduced equation recursively. + # + g, B = param_poly_rischDE(a.quo(d), b.quo(d), r, n, DE) + + # g = [g1, ..., gv] in k[t]^v and and B is a matrix with u + v + # columns and entries in Const(k) such that + # (a/d)*Dp + (b/d)*p = Sum(dj*rj) has a solution p of degree <= n + # in k[t] if and only if p = Sum(ek*gk) where e1, ..., ev are in + # Const(k) and B*Matrix([d1, ..., du, e1, ..., ev]) == 0. + # The solutions of the original equation are then + # Sum(dj*fj, (j, 1, u)) + alpha*Sum(ek*gk, (k, 1, v)). + + # Collect solution components. + h = f + [alpha*gk for gk in g] + + # Build combined relation matrix. + A = -eye(m, DE.t) + for vj in V: + A = A.row_join(vj) + A = A.row_join(zeros(m, len(g), DE.t)) + A = A.col_join(zeros(B.rows, m, DE.t).row_join(B)) + + return h, A + + +def param_rischDE(fa, fd, G, DE): + """ + Solve a Parametric Risch Differential Equation: Dy + f*y == Sum(ci*Gi, (i, 1, m)). + + Explanation + =========== + + Given a derivation D in k(t), f in k(t), and G + = [G1, ..., Gm] in k(t)^m, return h = [h1, ..., hr] in k(t)^r and + a matrix A with m + r columns and entries in Const(k) such that + Dy + f*y = Sum(ci*Gi, (i, 1, m)) has a solution y + in k(t) with c1, ..., cm in Const(k) if and only if y = Sum(dj*hj, + (j, 1, r)) where d1, ..., dr are in Const(k) and (c1, ..., cm, + d1, ..., dr) is a solution of Ax == 0. + + Elements of k(t) are tuples (a, d) with a and d in k[t]. + """ + m = len(G) + q, (fa, fd) = weak_normalizer(fa, fd, DE) + # Solutions of the weakly normalized equation Dz + f*z = q*Sum(ci*Gi) + # correspond to solutions y = z/q of the original equation. + gamma = q + G = [(q*ga).cancel(gd, include=True) for ga, gd in G] + + a, (ba, bd), G, hn = prde_normal_denom(fa, fd, G, DE) + # Solutions q in k of a*Dq + b*q = Sum(ci*Gi) correspond + # to solutions z = q/hn of the weakly normalized equation. + gamma *= hn + + A, B, G, hs = prde_special_denom(a, ba, bd, G, DE) + # Solutions p in k[t] of A*Dp + B*p = Sum(ci*Gi) correspond + # to solutions q = p/hs of the previous equation. + gamma *= hs + + g = A.gcd(B) + a, b, g = A.quo(g), B.quo(g), [gia.cancel(gid*g, include=True) for + gia, gid in G] + + # a*Dp + b*p = Sum(ci*gi) may have a polynomial solution + # only if the sum is in k[t]. + + q, M = prde_linear_constraints(a, b, g, DE) + + # q = [q1, ..., qm] where qi in k[t] is the polynomial component + # of the partial fraction expansion of gi. + # M is a matrix with m columns and entries in k. + # Sum(fi*gi, (i, 1, m)), where f1, ..., fm are elements of k, + # is a polynomial if and only if M*Matrix([f1, ..., fm]) == 0, + # in which case the sum is equal to Sum(fi*qi). + + M, _ = constant_system(M, zeros(M.rows, 1, DE.t), DE) + # M is a matrix with m columns and entries in Const(k). + # Sum(ci*gi) is in k[t] for c1, ..., cm in Const(k) + # if and only if M*Matrix([c1, ..., cm]) == 0, + # in which case the sum is Sum(ci*qi). + + ## Reduce number of constants at this point + + V = M.nullspace() + # V = [v1, ..., vu] where each vj is a column matrix with + # entries aj1, ..., ajm in Const(k). + # Sum(aji*gi) is in k[t] and equal to Sum(aji*qi) (j = 1, ..., u). + # Sum(ci*gi) is in k[t] if and only is ci = Sum(dj*aji) + # (i = 1, ..., m) for some d1, ..., du in Const(k). + # In that case, + # Sum(ci*gi) = Sum(ci*qi) = Sum(dj*Sum(aji*qi)) = Sum(dj*rj) + # where rj = Sum(aji*qi) (j = 1, ..., u) in k[t]. + + if not V: # No non-trivial solution + return [], eye(m, DE.t) + + Mq = Matrix([q]) # A single row. + r = [(Mq*vj)[0] for vj in V] # [r1, ..., ru] + + # Solutions of a*Dp + b*p = Sum(dj*rj) correspond to solutions + # y = p/gamma of the initial equation with ci = Sum(dj*aji). + + try: + # We try n=5. At least for prde_spde, it will always + # terminate no matter what n is. + n = bound_degree(a, b, r, DE, parametric=True) + except NotImplementedError: + # A temporary bound is set. Eventually, it will be removed. + # the currently added test case takes large time + # even with n=5, and much longer with large n's. + n = 5 + + h, B = param_poly_rischDE(a, b, r, n, DE) + + # h = [h1, ..., hv] in k[t]^v and and B is a matrix with u + v + # columns and entries in Const(k) such that + # a*Dp + b*p = Sum(dj*rj) has a solution p of degree <= n + # in k[t] if and only if p = Sum(ek*hk) where e1, ..., ev are in + # Const(k) and B*Matrix([d1, ..., du, e1, ..., ev]) == 0. + # The solutions of the original equation for ci = Sum(dj*aji) + # (i = 1, ..., m) are then y = Sum(ek*hk, (k, 1, v))/gamma. + + ## Build combined relation matrix with m + u + v columns. + + A = -eye(m, DE.t) + for vj in V: + A = A.row_join(vj) + A = A.row_join(zeros(m, len(h), DE.t)) + A = A.col_join(zeros(B.rows, m, DE.t).row_join(B)) + + ## Eliminate d1, ..., du. + + W = A.nullspace() + + # W = [w1, ..., wt] where each wl is a column matrix with + # entries blk (k = 1, ..., m + u + v) in Const(k). + # The vectors (bl1, ..., blm) generate the space of those + # constant families (c1, ..., cm) for which a solution of + # the equation Dy + f*y == Sum(ci*Gi) exists. They generate + # the space and form a basis except possibly when Dy + f*y == 0 + # is solvable in k(t}. The corresponding solutions are + # y = Sum(blk'*hk, (k, 1, v))/gamma, where k' = k + m + u. + + v = len(h) + shape = (len(W), m+v) + elements = [wl[:m] + wl[-v:] for wl in W] # excise dj's. + items = [e for row in elements for e in row] + + # Need to set the shape in case W is empty + M = Matrix(*shape, items, DE.t) + N = M.nullspace() + + # N = [n1, ..., ns] where the ni in Const(k)^(m + v) are column + # vectors generating the space of linear relations between + # c1, ..., cm, e1, ..., ev. + + C = Matrix([ni[:] for ni in N], DE.t) # rows n1, ..., ns. + + return [hk.cancel(gamma, include=True) for hk in h], C + + +def limited_integrate_reduce(fa, fd, G, DE): + """ + Simpler version of step 1 & 2 for the limited integration problem. + + Explanation + =========== + + Given a derivation D on k(t) and f, g1, ..., gn in k(t), return + (a, b, h, N, g, V) such that a, b, h in k[t], N is a non-negative integer, + g in k(t), V == [v1, ..., vm] in k(t)^m, and for any solution v in k(t), + c1, ..., cm in C of f == Dv + Sum(ci*wi, (i, 1, m)), p = v*h is in k, and + p and the ci satisfy a*Dp + b*p == g + Sum(ci*vi, (i, 1, m)). Furthermore, + if S1irr == Sirr, then p is in k[t], and if t is nonlinear or Liouvillian + over k, then deg(p) <= N. + + So that the special part is always computed, this function calls the more + general prde_special_denom() automatically if it cannot determine that + S1irr == Sirr. Furthermore, it will automatically call bound_degree() when + t is linear and non-Liouvillian, which for the transcendental case, implies + that Dt == a*t + b with for some a, b in k*. + """ + dn, ds = splitfactor(fd, DE) + E = [splitfactor(gd, DE) for _, gd in G] + En, Es = list(zip(*E)) + c = reduce(lambda i, j: i.lcm(j), (dn,) + En) # lcm(dn, en1, ..., enm) + hn = c.gcd(c.diff(DE.t)) + a = hn + b = -derivation(hn, DE) + N = 0 + + # These are the cases where we know that S1irr = Sirr, but there could be + # others, and this algorithm will need to be extended to handle them. + if DE.case in ('base', 'primitive', 'exp', 'tan'): + hs = reduce(lambda i, j: i.lcm(j), (ds,) + Es) # lcm(ds, es1, ..., esm) + a = hn*hs + b -= (hn*derivation(hs, DE)).quo(hs) + mu = min(order_at_oo(fa, fd, DE.t), min(order_at_oo(ga, gd, DE.t) for + ga, gd in G)) + # So far, all the above are also nonlinear or Liouvillian, but if this + # changes, then this will need to be updated to call bound_degree() + # as per the docstring of this function (DE.case == 'other_linear'). + N = hn.degree(DE.t) + hs.degree(DE.t) + max(0, 1 - DE.d.degree(DE.t) - mu) + else: + # TODO: implement this + raise NotImplementedError + + V = [(-a*hn*ga).cancel(gd, include=True) for ga, gd in G] + return (a, b, a, N, (a*hn*fa).cancel(fd, include=True), V) + + +def limited_integrate(fa, fd, G, DE): + """ + Solves the limited integration problem: f = Dv + Sum(ci*wi, (i, 1, n)) + """ + fa, fd = fa*Poly(1/fd.LC(), DE.t), fd.monic() + # interpreting limited integration problem as a + # parametric Risch DE problem + Fa = Poly(0, DE.t) + Fd = Poly(1, DE.t) + G = [(fa, fd)] + G + h, A = param_rischDE(Fa, Fd, G, DE) + V = A.nullspace() + V = [v for v in V if v[0] != 0] + if not V: + return None + else: + # we can take any vector from V, we take V[0] + c0 = V[0][0] + # v = [-1, c1, ..., cm, d1, ..., dr] + v = V[0]/(-c0) + r = len(h) + m = len(v) - r - 1 + C = list(v[1: m + 1]) + y = -sum(v[m + 1 + i]*h[i][0].as_expr()/h[i][1].as_expr() \ + for i in range(r)) + y_num, y_den = y.as_numer_denom() + Ya, Yd = Poly(y_num, DE.t), Poly(y_den, DE.t) + Y = Ya*Poly(1/Yd.LC(), DE.t), Yd.monic() + return Y, C + + +def parametric_log_deriv_heu(fa, fd, wa, wd, DE, c1=None): + """ + Parametric logarithmic derivative heuristic. + + Explanation + =========== + + Given a derivation D on k[t], f in k(t), and a hyperexponential monomial + theta over k(t), raises either NotImplementedError, in which case the + heuristic failed, or returns None, in which case it has proven that no + solution exists, or returns a solution (n, m, v) of the equation + n*f == Dv/v + m*Dtheta/theta, with v in k(t)* and n, m in ZZ with n != 0. + + If this heuristic fails, the structure theorem approach will need to be + used. + + The argument w == Dtheta/theta + """ + # TODO: finish writing this and write tests + c1 = c1 or Dummy('c1') + + p, a = fa.div(fd) + q, b = wa.div(wd) + + B = max(0, derivation(DE.t, DE).degree(DE.t) - 1) + C = max(p.degree(DE.t), q.degree(DE.t)) + + if q.degree(DE.t) > B: + eqs = [p.nth(i) - c1*q.nth(i) for i in range(B + 1, C + 1)] + s = solve(eqs, c1) + if not s or not s[c1].is_Rational: + # deg(q) > B, no solution for c. + return None + + M, N = s[c1].as_numer_denom() + M_poly = M.as_poly(q.gens) + N_poly = N.as_poly(q.gens) + + nfmwa = N_poly*fa*wd - M_poly*wa*fd + nfmwd = fd*wd + Qv = is_log_deriv_k_t_radical_in_field(nfmwa, nfmwd, DE, 'auto') + if Qv is None: + # (N*f - M*w) is not the logarithmic derivative of a k(t)-radical. + return None + + Q, v = Qv + + if Q.is_zero or v.is_zero: + return None + + return (Q*N, Q*M, v) + + if p.degree(DE.t) > B: + return None + + c = lcm(fd.as_poly(DE.t).LC(), wd.as_poly(DE.t).LC()) + l = fd.monic().lcm(wd.monic())*Poly(c, DE.t) + ln, ls = splitfactor(l, DE) + z = ls*ln.gcd(ln.diff(DE.t)) + + if not z.has(DE.t): + # TODO: We treat this as 'no solution', until the structure + # theorem version of parametric_log_deriv is implemented. + return None + + u1, r1 = (fa*l.quo(fd)).div(z) # (l*f).div(z) + u2, r2 = (wa*l.quo(wd)).div(z) # (l*w).div(z) + + eqs = [r1.nth(i) - c1*r2.nth(i) for i in range(z.degree(DE.t))] + s = solve(eqs, c1) + if not s or not s[c1].is_Rational: + # deg(q) <= B, no solution for c. + return None + + M, N = s[c1].as_numer_denom() + + nfmwa = N.as_poly(DE.t)*fa*wd - M.as_poly(DE.t)*wa*fd + nfmwd = fd*wd + Qv = is_log_deriv_k_t_radical_in_field(nfmwa, nfmwd, DE) + if Qv is None: + # (N*f - M*w) is not the logarithmic derivative of a k(t)-radical. + return None + + Q, v = Qv + + if Q.is_zero or v.is_zero: + return None + + return (Q*N, Q*M, v) + + +def parametric_log_deriv(fa, fd, wa, wd, DE): + # TODO: Write the full algorithm using the structure theorems. +# try: + A = parametric_log_deriv_heu(fa, fd, wa, wd, DE) +# except NotImplementedError: + # Heuristic failed, we have to use the full method. + # TODO: This could be implemented more efficiently. + # It isn't too worrisome, because the heuristic handles most difficult + # cases. + return A + + +def is_deriv_k(fa, fd, DE): + r""" + Checks if Df/f is the derivative of an element of k(t). + + Explanation + =========== + + a in k(t) is the derivative of an element of k(t) if there exists b in k(t) + such that a = Db. Either returns (ans, u), such that Df/f == Du, or None, + which means that Df/f is not the derivative of an element of k(t). ans is + a list of tuples such that Add(*[i*j for i, j in ans]) == u. This is useful + for seeing exactly which elements of k(t) produce u. + + This function uses the structure theorem approach, which says that for any + f in K, Df/f is the derivative of a element of K if and only if there are ri + in QQ such that:: + + --- --- Dt + \ r * Dt + \ r * i Df + / i i / i --- = --. + --- --- t f + i in L i in E i + K/C(x) K/C(x) + + + Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is + transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i + in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic + monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i + is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some + a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of + hyperexponential monomials of K over C(x)). If K is an elementary extension + over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the + transcendence degree of K over C(x). Furthermore, because Const_D(K) == + Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and + deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x) + and L_K/C(x) are disjoint. + + The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed + recursively using this same function. Therefore, it is required to pass + them as indices to D (or T). E_args are the arguments of the + hyperexponentials indexed by E_K (i.e., if i is in E_K, then T[i] == + exp(E_args[i])). This is needed to compute the final answer u such that + Df/f == Du. + + log(f) will be the same as u up to a additive constant. This is because + they will both behave the same as monomials. For example, both log(x) and + log(2*x) == log(x) + log(2) satisfy Dt == 1/x, because log(2) is constant. + Therefore, the term const is returned. const is such that + log(const) + f == u. This is calculated by dividing the arguments of one + logarithm from the other. Therefore, it is necessary to pass the arguments + of the logarithmic terms in L_args. + + To handle the case where we are given Df/f, not f, use is_deriv_k_in_field(). + + See also + ======== + is_log_deriv_k_t_radical_in_field, is_log_deriv_k_t_radical + + """ + # Compute Df/f + dfa, dfd = (fd*derivation(fa, DE) - fa*derivation(fd, DE)), fd*fa + dfa, dfd = dfa.cancel(dfd, include=True) + + # Our assumption here is that each monomial is recursively transcendental + if len(DE.exts) != len(DE.D): + if [i for i in DE.cases if i == 'tan'] or \ + ({i for i in DE.cases if i == 'primitive'} - + set(DE.indices('log'))): + raise NotImplementedError("Real version of the structure " + "theorems with hypertangent support is not yet implemented.") + + # TODO: What should really be done in this case? + raise NotImplementedError("Nonelementary extensions not supported " + "in the structure theorems.") + + E_part = [DE.D[i].quo(Poly(DE.T[i], DE.T[i])).as_expr() for i in DE.indices('exp')] + L_part = [DE.D[i].as_expr() for i in DE.indices('log')] + + # The expression dfa/dfd might not be polynomial in any of its symbols so we + # use a Dummy as the generator for PolyMatrix. + dum = Dummy() + lhs = Matrix([E_part + L_part], dum) + rhs = Matrix([dfa.as_expr()/dfd.as_expr()], dum) + + A, u = constant_system(lhs, rhs, DE) + + u = u.to_Matrix() # Poly to Expr + + if not A or not all(derivation(i, DE, basic=True).is_zero for i in u): + # If the elements of u are not all constant + # Note: See comment in constant_system + + # Also note: derivation(basic=True) calls cancel() + return None + else: + if not all(i.is_Rational for i in u): + raise NotImplementedError("Cannot work with non-rational " + "coefficients in this case.") + else: + terms = ([DE.extargs[i] for i in DE.indices('exp')] + + [DE.T[i] for i in DE.indices('log')]) + ans = list(zip(terms, u)) + result = Add(*[Mul(i, j) for i, j in ans]) + argterms = ([DE.T[i] for i in DE.indices('exp')] + + [DE.extargs[i] for i in DE.indices('log')]) + l = [] + ld = [] + for i, j in zip(argterms, u): + # We need to get around things like sqrt(x**2) != x + # and also sqrt(x**2 + 2*x + 1) != x + 1 + # Issue 10798: i need not be a polynomial + i, d = i.as_numer_denom() + icoeff, iterms = sqf_list(i) + l.append(Mul(*([Pow(icoeff, j)] + [Pow(b, e*j) for b, e in iterms]))) + dcoeff, dterms = sqf_list(d) + ld.append(Mul(*([Pow(dcoeff, j)] + [Pow(b, e*j) for b, e in dterms]))) + const = cancel(fa.as_expr()/fd.as_expr()/Mul(*l)*Mul(*ld)) + + return (ans, result, const) + + +def is_log_deriv_k_t_radical(fa, fd, DE, Df=True): + r""" + Checks if Df is the logarithmic derivative of a k(t)-radical. + + Explanation + =========== + + b in k(t) can be written as the logarithmic derivative of a k(t) radical if + there exist n in ZZ and u in k(t) with n, u != 0 such that n*b == Du/u. + Either returns (ans, u, n, const) or None, which means that Df cannot be + written as the logarithmic derivative of a k(t)-radical. ans is a list of + tuples such that Mul(*[i**j for i, j in ans]) == u. This is useful for + seeing exactly what elements of k(t) produce u. + + This function uses the structure theorem approach, which says that for any + f in K, Df is the logarithmic derivative of a K-radical if and only if there + are ri in QQ such that:: + + --- --- Dt + \ r * Dt + \ r * i + / i i / i --- = Df. + --- --- t + i in L i in E i + K/C(x) K/C(x) + + + Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is + transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i + in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic + monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i + is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some + a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of + hyperexponential monomials of K over C(x)). If K is an elementary extension + over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the + transcendence degree of K over C(x). Furthermore, because Const_D(K) == + Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and + deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x) + and L_K/C(x) are disjoint. + + The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed + recursively using this same function. Therefore, it is required to pass + them as indices to D (or T). L_args are the arguments of the logarithms + indexed by L_K (i.e., if i is in L_K, then T[i] == log(L_args[i])). This is + needed to compute the final answer u such that n*f == Du/u. + + exp(f) will be the same as u up to a multiplicative constant. This is + because they will both behave the same as monomials. For example, both + exp(x) and exp(x + 1) == E*exp(x) satisfy Dt == t. Therefore, the term const + is returned. const is such that exp(const)*f == u. This is calculated by + subtracting the arguments of one exponential from the other. Therefore, it + is necessary to pass the arguments of the exponential terms in E_args. + + To handle the case where we are given Df, not f, use + is_log_deriv_k_t_radical_in_field(). + + See also + ======== + + is_log_deriv_k_t_radical_in_field, is_deriv_k + + """ + if Df: + dfa, dfd = (fd*derivation(fa, DE) - fa*derivation(fd, DE)).cancel(fd**2, + include=True) + else: + dfa, dfd = fa, fd + + # Our assumption here is that each monomial is recursively transcendental + if len(DE.exts) != len(DE.D): + if [i for i in DE.cases if i == 'tan'] or \ + ({i for i in DE.cases if i == 'primitive'} - + set(DE.indices('log'))): + raise NotImplementedError("Real version of the structure " + "theorems with hypertangent support is not yet implemented.") + + # TODO: What should really be done in this case? + raise NotImplementedError("Nonelementary extensions not supported " + "in the structure theorems.") + + E_part = [DE.D[i].quo(Poly(DE.T[i], DE.T[i])).as_expr() for i in DE.indices('exp')] + L_part = [DE.D[i].as_expr() for i in DE.indices('log')] + + # The expression dfa/dfd might not be polynomial in any of its symbols so we + # use a Dummy as the generator for PolyMatrix. + dum = Dummy() + lhs = Matrix([E_part + L_part], dum) + rhs = Matrix([dfa.as_expr()/dfd.as_expr()], dum) + + A, u = constant_system(lhs, rhs, DE) + + u = u.to_Matrix() # Poly to Expr + + if not A or not all(derivation(i, DE, basic=True).is_zero for i in u): + # If the elements of u are not all constant + # Note: See comment in constant_system + + # Also note: derivation(basic=True) calls cancel() + return None + else: + if not all(i.is_Rational for i in u): + # TODO: But maybe we can tell if they're not rational, like + # log(2)/log(3). Also, there should be an option to continue + # anyway, even if the result might potentially be wrong. + raise NotImplementedError("Cannot work with non-rational " + "coefficients in this case.") + else: + n = S.One*reduce(ilcm, [i.as_numer_denom()[1] for i in u]) + u *= n + terms = ([DE.T[i] for i in DE.indices('exp')] + + [DE.extargs[i] for i in DE.indices('log')]) + ans = list(zip(terms, u)) + result = Mul(*[Pow(i, j) for i, j in ans]) + + # exp(f) will be the same as result up to a multiplicative + # constant. We now find the log of that constant. + argterms = ([DE.extargs[i] for i in DE.indices('exp')] + + [DE.T[i] for i in DE.indices('log')]) + const = cancel(fa.as_expr()/fd.as_expr() - + Add(*[Mul(i, j/n) for i, j in zip(argterms, u)])) + + return (ans, result, n, const) + + +def is_log_deriv_k_t_radical_in_field(fa, fd, DE, case='auto', z=None): + """ + Checks if f can be written as the logarithmic derivative of a k(t)-radical. + + Explanation + =========== + + It differs from is_log_deriv_k_t_radical(fa, fd, DE, Df=False) + for any given fa, fd, DE in that it finds the solution in the + given field not in some (possibly unspecified extension) and + "in_field" with the function name is used to indicate that. + + f in k(t) can be written as the logarithmic derivative of a k(t) radical if + there exist n in ZZ and u in k(t) with n, u != 0 such that n*f == Du/u. + Either returns (n, u) or None, which means that f cannot be written as the + logarithmic derivative of a k(t)-radical. + + case is one of {'primitive', 'exp', 'tan', 'auto'} for the primitive, + hyperexponential, and hypertangent cases, respectively. If case is 'auto', + it will attempt to determine the type of the derivation automatically. + + See also + ======== + is_log_deriv_k_t_radical, is_deriv_k + + """ + fa, fd = fa.cancel(fd, include=True) + + # f must be simple + n, s = splitfactor(fd, DE) + if not s.is_one: + pass + + z = z or Dummy('z') + H, b = residue_reduce(fa, fd, DE, z=z) + if not b: + # I will have to verify, but I believe that the answer should be + # None in this case. This should never happen for the + # functions given when solving the parametric logarithmic + # derivative problem when integration elementary functions (see + # Bronstein's book, page 255), so most likely this indicates a bug. + return None + + roots = [(i, i.real_roots()) for i, _ in H] + if not all(len(j) == i.degree() and all(k.is_Rational for k in j) for + i, j in roots): + # If f is the logarithmic derivative of a k(t)-radical, then all the + # roots of the resultant must be rational numbers. + return None + + # [(a, i), ...], where i*log(a) is a term in the log-part of the integral + # of f + respolys, residues = list(zip(*roots)) or [[], []] + # Note: this might be empty, but everything below should work find in that + # case (it should be the same as if it were [[1, 1]]) + residueterms = [(H[j][1].subs(z, i), i) for j in range(len(H)) for + i in residues[j]] + + # TODO: finish writing this and write tests + + p = cancel(fa.as_expr()/fd.as_expr() - residue_reduce_derivation(H, DE, z)) + + p = p.as_poly(DE.t) + if p is None: + # f - Dg will be in k[t] if f is the logarithmic derivative of a k(t)-radical + return None + + if p.degree(DE.t) >= max(1, DE.d.degree(DE.t)): + return None + + if case == 'auto': + case = DE.case + + if case == 'exp': + wa, wd = derivation(DE.t, DE).cancel(Poly(DE.t, DE.t), include=True) + with DecrementLevel(DE): + pa, pd = frac_in(p, DE.t, cancel=True) + wa, wd = frac_in((wa, wd), DE.t) + A = parametric_log_deriv(pa, pd, wa, wd, DE) + if A is None: + return None + n, e, u = A + u *= DE.t**e + + elif case == 'primitive': + with DecrementLevel(DE): + pa, pd = frac_in(p, DE.t) + A = is_log_deriv_k_t_radical_in_field(pa, pd, DE, case='auto') + if A is None: + return None + n, u = A + + elif case == 'base': + # TODO: we can use more efficient residue reduction from ratint() + if not fd.is_sqf or fa.degree() >= fd.degree(): + # f is the logarithmic derivative in the base case if and only if + # f = fa/fd, fd is square-free, deg(fa) < deg(fd), and + # gcd(fa, fd) == 1. The last condition is handled by cancel() above. + return None + # Note: if residueterms = [], returns (1, 1) + # f had better be 0 in that case. + n = S.One*reduce(ilcm, [i.as_numer_denom()[1] for _, i in residueterms], 1) + u = Mul(*[Pow(i, j*n) for i, j in residueterms]) + return (n, u) + + elif case == 'tan': + raise NotImplementedError("The hypertangent case is " + "not yet implemented for is_log_deriv_k_t_radical_in_field()") + + elif case in ('other_linear', 'other_nonlinear'): + # XXX: If these are supported by the structure theorems, change to NotImplementedError. + raise ValueError("The %s case is not supported in this function." % case) + + else: + raise ValueError("case must be one of {'primitive', 'exp', 'tan', " + "'base', 'auto'}, not %s" % case) + + common_denom = S.One*reduce(ilcm, [i.as_numer_denom()[1] for i in [j for _, j in + residueterms]] + [n], 1) + residueterms = [(i, j*common_denom) for i, j in residueterms] + m = common_denom//n + if common_denom != n*m: # Verify exact division + raise ValueError("Inexact division") + u = cancel(u**m*Mul(*[Pow(i, j) for i, j in residueterms])) + + return (common_denom, u) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/quadrature.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/quadrature.py new file mode 100644 index 0000000000000000000000000000000000000000..b518bd427dc9980d6a941d2e1ef4d139c5f0f5f9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/quadrature.py @@ -0,0 +1,617 @@ +from sympy.core import S, Dummy, pi +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.trigonometric import sin, cos +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.gamma_functions import gamma +from sympy.polys.orthopolys import (legendre_poly, laguerre_poly, + hermite_poly, jacobi_poly) +from sympy.polys.rootoftools import RootOf + + +def gauss_legendre(n, n_digits): + r""" + Computes the Gauss-Legendre quadrature [1]_ points and weights. + + Explanation + =========== + + The Gauss-Legendre quadrature approximates the integral: + + .. math:: + \int_{-1}^1 f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `P_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{2}{\left(1-x_i^2\right) \left(P'_n(x_i)\right)^2} + + Parameters + ========== + + n : + The order of quadrature. + n_digits : + Number of significant digits of the points and weights to return. + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_legendre + >>> x, w = gauss_legendre(3, 5) + >>> x + [-0.7746, 0, 0.7746] + >>> w + [0.55556, 0.88889, 0.55556] + >>> x, w = gauss_legendre(4, 5) + >>> x + [-0.86114, -0.33998, 0.33998, 0.86114] + >>> w + [0.34785, 0.65215, 0.65215, 0.34785] + + See Also + ======== + + gauss_laguerre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gaussian_quadrature + .. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/legendre_rule/legendre_rule.html + """ + x = Dummy("x") + p = legendre_poly(n, x, polys=True) + pd = p.diff(x) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S.One/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append((2/((1-r**2) * pd.subs(x, r)**2)).n(n_digits)) + return xi, w + + +def gauss_laguerre(n, n_digits): + r""" + Computes the Gauss-Laguerre quadrature [1]_ points and weights. + + Explanation + =========== + + The Gauss-Laguerre quadrature approximates the integral: + + .. math:: + \int_0^{\infty} e^{-x} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + + The nodes `x_i` of an order `n` quadrature rule are the roots of `L_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{x_i}{(n+1)^2 \left(L_{n+1}(x_i)\right)^2} + + Parameters + ========== + + n : + The order of quadrature. + n_digits : + Number of significant digits of the points and weights to return. + + Returns + ======= + + (x, w) : The ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_laguerre + >>> x, w = gauss_laguerre(3, 5) + >>> x + [0.41577, 2.2943, 6.2899] + >>> w + [0.71109, 0.27852, 0.010389] + >>> x, w = gauss_laguerre(6, 5) + >>> x + [0.22285, 1.1889, 2.9927, 5.7751, 9.8375, 15.983] + >>> w + [0.45896, 0.417, 0.11337, 0.010399, 0.00026102, 8.9855e-7] + + See Also + ======== + + gauss_legendre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature + .. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/laguerre_rule/laguerre_rule.html + """ + x = Dummy("x") + p = laguerre_poly(n, x, polys=True) + p1 = laguerre_poly(n+1, x, polys=True) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S.One/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append((r/((n+1)**2 * p1.subs(x, r)**2)).n(n_digits)) + return xi, w + + +def gauss_hermite(n, n_digits): + r""" + Computes the Gauss-Hermite quadrature [1]_ points and weights. + + Explanation + =========== + + The Gauss-Hermite quadrature approximates the integral: + + .. math:: + \int_{-\infty}^{\infty} e^{-x^2} f(x)\,dx \approx + \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `H_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{2^{n-1} n! \sqrt{\pi}}{n^2 \left(H_{n-1}(x_i)\right)^2} + + Parameters + ========== + + n : + The order of quadrature. + n_digits : + Number of significant digits of the points and weights to return. + + Returns + ======= + + (x, w) : The ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_hermite + >>> x, w = gauss_hermite(3, 5) + >>> x + [-1.2247, 0, 1.2247] + >>> w + [0.29541, 1.1816, 0.29541] + + >>> x, w = gauss_hermite(6, 5) + >>> x + [-2.3506, -1.3358, -0.43608, 0.43608, 1.3358, 2.3506] + >>> w + [0.00453, 0.15707, 0.72463, 0.72463, 0.15707, 0.00453] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_gen_laguerre, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gauss-Hermite_Quadrature + .. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/hermite_rule/hermite_rule.html + .. [3] https://people.sc.fsu.edu/~jburkardt/cpp_src/gen_hermite_rule/gen_hermite_rule.html + """ + x = Dummy("x") + p = hermite_poly(n, x, polys=True) + p1 = hermite_poly(n-1, x, polys=True) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S.One/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append(((2**(n-1) * factorial(n) * sqrt(pi)) / + (n**2 * p1.subs(x, r)**2)).n(n_digits)) + return xi, w + + +def gauss_gen_laguerre(n, alpha, n_digits): + r""" + Computes the generalized Gauss-Laguerre quadrature [1]_ points and weights. + + Explanation + =========== + + The generalized Gauss-Laguerre quadrature approximates the integral: + + .. math:: + \int_{0}^\infty x^{\alpha} e^{-x} f(x)\,dx \approx + \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of + `L^{\alpha}_n` and the weights `w_i` are given by: + + .. math:: + w_i = \frac{\Gamma(\alpha+n)} + {n \Gamma(n) L^{\alpha}_{n-1}(x_i) L^{\alpha+1}_{n-1}(x_i)} + + Parameters + ========== + + n : + The order of quadrature. + + alpha : + The exponent of the singularity, `\alpha > -1`. + + n_digits : + Number of significant digits of the points and weights to return. + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.integrals.quadrature import gauss_gen_laguerre + >>> x, w = gauss_gen_laguerre(3, -S.Half, 5) + >>> x + [0.19016, 1.7845, 5.5253] + >>> w + [1.4493, 0.31413, 0.00906] + + >>> x, w = gauss_gen_laguerre(4, 3*S.Half, 5) + >>> x + [0.97851, 2.9904, 6.3193, 11.712] + >>> w + [0.53087, 0.67721, 0.11895, 0.0023152] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature + .. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/gen_laguerre_rule/gen_laguerre_rule.html + """ + x = Dummy("x") + p = laguerre_poly(n, x, alpha=alpha, polys=True) + p1 = laguerre_poly(n-1, x, alpha=alpha, polys=True) + p2 = laguerre_poly(n-1, x, alpha=alpha+1, polys=True) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S.One/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append((gamma(alpha+n) / + (n*gamma(n)*p1.subs(x, r)*p2.subs(x, r))).n(n_digits)) + return xi, w + + +def gauss_chebyshev_t(n, n_digits): + r""" + Computes the Gauss-Chebyshev quadrature [1]_ points and weights of + the first kind. + + Explanation + =========== + + The Gauss-Chebyshev quadrature of the first kind approximates the integral: + + .. math:: + \int_{-1}^{1} \frac{1}{\sqrt{1-x^2}} f(x)\,dx \approx + \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `T_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{\pi}{n} + + Parameters + ========== + + n : + The order of quadrature. + + n_digits : + Number of significant digits of the points and weights to return. + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_chebyshev_t + >>> x, w = gauss_chebyshev_t(3, 5) + >>> x + [0.86602, 0, -0.86602] + >>> w + [1.0472, 1.0472, 1.0472] + + >>> x, w = gauss_chebyshev_t(6, 5) + >>> x + [0.96593, 0.70711, 0.25882, -0.25882, -0.70711, -0.96593] + >>> w + [0.5236, 0.5236, 0.5236, 0.5236, 0.5236, 0.5236] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Chebyshev%E2%80%93Gauss_quadrature + .. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/chebyshev1_rule/chebyshev1_rule.html + """ + xi = [] + w = [] + for i in range(1, n+1): + xi.append((cos((2*i-S.One)/(2*n)*S.Pi)).n(n_digits)) + w.append((S.Pi/n).n(n_digits)) + return xi, w + + +def gauss_chebyshev_u(n, n_digits): + r""" + Computes the Gauss-Chebyshev quadrature [1]_ points and weights of + the second kind. + + Explanation + =========== + + The Gauss-Chebyshev quadrature of the second kind approximates the + integral: + + .. math:: + \int_{-1}^{1} \sqrt{1-x^2} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `U_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{\pi}{n+1} \sin^2 \left(\frac{i}{n+1}\pi\right) + + Parameters + ========== + + n : the order of quadrature + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_chebyshev_u + >>> x, w = gauss_chebyshev_u(3, 5) + >>> x + [0.70711, 0, -0.70711] + >>> w + [0.3927, 0.7854, 0.3927] + + >>> x, w = gauss_chebyshev_u(6, 5) + >>> x + [0.90097, 0.62349, 0.22252, -0.22252, -0.62349, -0.90097] + >>> w + [0.084489, 0.27433, 0.42658, 0.42658, 0.27433, 0.084489] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_t, gauss_jacobi, gauss_lobatto + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Chebyshev%E2%80%93Gauss_quadrature + .. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/chebyshev2_rule/chebyshev2_rule.html + """ + xi = [] + w = [] + for i in range(1, n+1): + xi.append((cos(i/(n+S.One)*S.Pi)).n(n_digits)) + w.append((S.Pi/(n+S.One)*sin(i*S.Pi/(n+S.One))**2).n(n_digits)) + return xi, w + + +def gauss_jacobi(n, alpha, beta, n_digits): + r""" + Computes the Gauss-Jacobi quadrature [1]_ points and weights. + + Explanation + =========== + + The Gauss-Jacobi quadrature of the first kind approximates the integral: + + .. math:: + \int_{-1}^1 (1-x)^\alpha (1+x)^\beta f(x)\,dx \approx + \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of + `P^{(\alpha,\beta)}_n` and the weights `w_i` are given by: + + .. math:: + w_i = -\frac{2n+\alpha+\beta+2}{n+\alpha+\beta+1} + \frac{\Gamma(n+\alpha+1)\Gamma(n+\beta+1)} + {\Gamma(n+\alpha+\beta+1)(n+1)!} + \frac{2^{\alpha+\beta}}{P'_n(x_i) + P^{(\alpha,\beta)}_{n+1}(x_i)} + + Parameters + ========== + + n : the order of quadrature + + alpha : the first parameter of the Jacobi Polynomial, `\alpha > -1` + + beta : the second parameter of the Jacobi Polynomial, `\beta > -1` + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.integrals.quadrature import gauss_jacobi + >>> x, w = gauss_jacobi(3, S.Half, -S.Half, 5) + >>> x + [-0.90097, -0.22252, 0.62349] + >>> w + [1.7063, 1.0973, 0.33795] + + >>> x, w = gauss_jacobi(6, 1, 1, 5) + >>> x + [-0.87174, -0.5917, -0.2093, 0.2093, 0.5917, 0.87174] + >>> w + [0.050584, 0.22169, 0.39439, 0.39439, 0.22169, 0.050584] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, + gauss_chebyshev_t, gauss_chebyshev_u, gauss_lobatto + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Jacobi_quadrature + .. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/jacobi_rule/jacobi_rule.html + .. [3] https://people.sc.fsu.edu/~jburkardt/cpp_src/gegenbauer_rule/gegenbauer_rule.html + """ + x = Dummy("x") + p = jacobi_poly(n, alpha, beta, x, polys=True) + pd = p.diff(x) + pn = jacobi_poly(n+1, alpha, beta, x, polys=True) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S.One/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append(( + - (2*n+alpha+beta+2) / (n+alpha+beta+S.One) * + (gamma(n+alpha+1)*gamma(n+beta+1)) / + (gamma(n+alpha+beta+S.One)*gamma(n+2)) * + 2**(alpha+beta) / (pd.subs(x, r) * pn.subs(x, r))).n(n_digits)) + return xi, w + + +def gauss_lobatto(n, n_digits): + r""" + Computes the Gauss-Lobatto quadrature [1]_ points and weights. + + Explanation + =========== + + The Gauss-Lobatto quadrature approximates the integral: + + .. math:: + \int_{-1}^1 f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `P'_(n-1)` + and the weights `w_i` are given by: + + .. math:: + &w_i = \frac{2}{n(n-1) \left[P_{n-1}(x_i)\right]^2},\quad x\neq\pm 1\\ + &w_i = \frac{2}{n(n-1)},\quad x=\pm 1 + + Parameters + ========== + + n : the order of quadrature + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_lobatto + >>> x, w = gauss_lobatto(3, 5) + >>> x + [-1, 0, 1] + >>> w + [0.33333, 1.3333, 0.33333] + >>> x, w = gauss_lobatto(4, 5) + >>> x + [-1, -0.44721, 0.44721, 1] + >>> w + [0.16667, 0.83333, 0.83333, 0.16667] + + See Also + ======== + + gauss_legendre,gauss_laguerre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gaussian_quadrature#Gauss.E2.80.93Lobatto_rules + .. [2] https://web.archive.org/web/20200118141346/http://people.math.sfu.ca/~cbm/aands/page_888.htm + """ + x = Dummy("x") + p = legendre_poly(n-1, x, polys=True) + pd = p.diff(x) + xi = [] + w = [] + for r in pd.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S.One/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append((2/(n*(n-1) * p.subs(x, r)**2)).n(n_digits)) + + xi.insert(0, -1) + xi.append(1) + w.insert(0, (S(2)/(n*(n-1))).n(n_digits)) + w.append((S(2)/(n*(n-1))).n(n_digits)) + return xi, w diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/rationaltools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/rationaltools.py new file mode 100644 index 0000000000000000000000000000000000000000..e95ff5da2e9d1be6f07d8fe6e9c572f692e92efb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/rationaltools.py @@ -0,0 +1,445 @@ +"""This module implements tools for integrating rational functions. """ + +from sympy.core.function import Lambda +from sympy.core.numbers import I +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.trigonometric import atan +from sympy.polys.polyerrors import DomainError +from sympy.polys.polyroots import roots +from sympy.polys.polytools import cancel +from sympy.polys.rootoftools import RootSum +from sympy.polys import Poly, resultant, ZZ + + +def ratint(f, x, **flags): + """ + Performs indefinite integration of rational functions. + + Explanation + =========== + + Given a field :math:`K` and a rational function :math:`f = p/q`, + where :math:`p` and :math:`q` are polynomials in :math:`K[x]`, + returns a function :math:`g` such that :math:`f = g'`. + + Examples + ======== + + >>> from sympy.integrals.rationaltools import ratint + >>> from sympy.abc import x + + >>> ratint(36/(x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2), x) + (12*x + 6)/(x**2 - 1) + 4*log(x - 2) - 4*log(x + 1) + + References + ========== + + .. [1] M. Bronstein, Symbolic Integration I: Transcendental + Functions, Second Edition, Springer-Verlag, 2005, pp. 35-70 + + See Also + ======== + + sympy.integrals.integrals.Integral.doit + sympy.integrals.rationaltools.ratint_logpart + sympy.integrals.rationaltools.ratint_ratpart + + """ + if isinstance(f, tuple): + p, q = f + else: + p, q = f.as_numer_denom() + + p, q = Poly(p, x, composite=False, field=True), Poly(q, x, composite=False, field=True) + + coeff, p, q = p.cancel(q) + poly, p = p.div(q) + + result = poly.integrate(x).as_expr() + + if p.is_zero: + return coeff*result + + g, h = ratint_ratpart(p, q, x) + + P, Q = h.as_numer_denom() + + P = Poly(P, x) + Q = Poly(Q, x) + + q, r = P.div(Q) + + result += g + q.integrate(x).as_expr() + + if not r.is_zero: + symbol = flags.get('symbol', 't') + + if not isinstance(symbol, Symbol): + t = Dummy(symbol) + else: + t = symbol.as_dummy() + + L = ratint_logpart(r, Q, x, t) + + real = flags.get('real') + + if real is None: + if isinstance(f, tuple): + p, q = f + atoms = p.atoms() | q.atoms() + else: + atoms = f.atoms() + + for elt in atoms - {x}: + if not elt.is_extended_real: + real = False + break + else: + real = True + + eps = S.Zero + + if not real: + for h, q in L: + _, h = h.primitive() + eps += RootSum( + q, Lambda(t, t*log(h.as_expr())), quadratic=True) + else: + for h, q in L: + _, h = h.primitive() + R = log_to_real(h, q, x, t) + + if R is not None: + eps += R + else: + eps += RootSum( + q, Lambda(t, t*log(h.as_expr())), quadratic=True) + + result += eps + + return coeff*result + + +def ratint_ratpart(f, g, x): + """ + Horowitz-Ostrogradsky algorithm. + + Explanation + =========== + + Given a field K and polynomials f and g in K[x], such that f and g + are coprime and deg(f) < deg(g), returns fractions A and B in K(x), + such that f/g = A' + B and B has square-free denominator. + + Examples + ======== + + >>> from sympy.integrals.rationaltools import ratint_ratpart + >>> from sympy.abc import x, y + >>> from sympy import Poly + >>> ratint_ratpart(Poly(1, x, domain='ZZ'), + ... Poly(x + 1, x, domain='ZZ'), x) + (0, 1/(x + 1)) + >>> ratint_ratpart(Poly(1, x, domain='EX'), + ... Poly(x**2 + y**2, x, domain='EX'), x) + (0, 1/(x**2 + y**2)) + >>> ratint_ratpart(Poly(36, x, domain='ZZ'), + ... Poly(x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2, x, domain='ZZ'), x) + ((12*x + 6)/(x**2 - 1), 12/(x**2 - x - 2)) + + See Also + ======== + + ratint, ratint_logpart + """ + from sympy.solvers.solvers import solve + + f = Poly(f, x) + g = Poly(g, x) + + u, v, _ = g.cofactors(g.diff()) + + n = u.degree() + m = v.degree() + + A_coeffs = [ Dummy('a' + str(n - i)) for i in range(0, n) ] + B_coeffs = [ Dummy('b' + str(m - i)) for i in range(0, m) ] + + C_coeffs = A_coeffs + B_coeffs + + A = Poly(A_coeffs, x, domain=ZZ[C_coeffs]) + B = Poly(B_coeffs, x, domain=ZZ[C_coeffs]) + + H = f - A.diff()*v + A*(u.diff()*v).quo(u) - B*u + + result = solve(H.coeffs(), C_coeffs) + + A = A.as_expr().subs(result) + B = B.as_expr().subs(result) + + rat_part = cancel(A/u.as_expr(), x) + log_part = cancel(B/v.as_expr(), x) + + return rat_part, log_part + + +def ratint_logpart(f, g, x, t=None): + r""" + Lazard-Rioboo-Trager algorithm. + + Explanation + =========== + + Given a field K and polynomials f and g in K[x], such that f and g + are coprime, deg(f) < deg(g) and g is square-free, returns a list + of tuples (s_i, q_i) of polynomials, for i = 1..n, such that s_i + in K[t, x] and q_i in K[t], and:: + + ___ ___ + d f d \ ` \ ` + -- - = -- ) ) a log(s_i(a, x)) + dx g dx /__, /__, + i=1..n a | q_i(a) = 0 + + Examples + ======== + + >>> from sympy.integrals.rationaltools import ratint_logpart + >>> from sympy.abc import x + >>> from sympy import Poly + >>> ratint_logpart(Poly(1, x, domain='ZZ'), + ... Poly(x**2 + x + 1, x, domain='ZZ'), x) + [(Poly(x + 3*_t/2 + 1/2, x, domain='QQ[_t]'), + ...Poly(3*_t**2 + 1, _t, domain='ZZ'))] + >>> ratint_logpart(Poly(12, x, domain='ZZ'), + ... Poly(x**2 - x - 2, x, domain='ZZ'), x) + [(Poly(x - 3*_t/8 - 1/2, x, domain='QQ[_t]'), + ...Poly(-_t**2 + 16, _t, domain='ZZ'))] + + See Also + ======== + + ratint, ratint_ratpart + """ + f, g = Poly(f, x), Poly(g, x) + + t = t or Dummy('t') + a, b = g, f - g.diff()*Poly(t, x) + + res, R = resultant(a, b, includePRS=True) + res = Poly(res, t, composite=False) + + assert res, "BUG: resultant(%s, %s) cannot be zero" % (a, b) + + R_map, H = {}, [] + + for r in R: + R_map[r.degree()] = r + + def _include_sign(c, sqf): + if c.is_extended_real and (c < 0) == True: + h, k = sqf[0] + c_poly = c.as_poly(h.gens) + sqf[0] = h*c_poly, k + + C, res_sqf = res.sqf_list() + _include_sign(C, res_sqf) + + for q, i in res_sqf: + _, q = q.primitive() + + if g.degree() == i: + H.append((g, q)) + else: + h = R_map[i] + h_lc = Poly(h.LC(), t, field=True) + + c, h_lc_sqf = h_lc.sqf_list(all=True) + _include_sign(c, h_lc_sqf) + + for a, j in h_lc_sqf: + h = h.quo(Poly(a.gcd(q)**j, x)) + + inv, coeffs = h_lc.invert(q), [S.One] + + for coeff in h.coeffs()[1:]: + coeff = coeff.as_poly(inv.gens) + T = (inv*coeff).rem(q) + coeffs.append(T.as_expr()) + + h = Poly(dict(list(zip(h.monoms(), coeffs))), x) + + H.append((h, q)) + + return H + + +def log_to_atan(f, g): + """ + Convert complex logarithms to real arctangents. + + Explanation + =========== + + Given a real field K and polynomials f and g in K[x], with g != 0, + returns a sum h of arctangents of polynomials in K[x], such that: + + dh d f + I g + -- = -- I log( ------- ) + dx dx f - I g + + Examples + ======== + + >>> from sympy.integrals.rationaltools import log_to_atan + >>> from sympy.abc import x + >>> from sympy import Poly, sqrt, S + >>> log_to_atan(Poly(x, x, domain='ZZ'), Poly(1, x, domain='ZZ')) + 2*atan(x) + >>> log_to_atan(Poly(x + S(1)/2, x, domain='QQ'), + ... Poly(sqrt(3)/2, x, domain='EX')) + 2*atan(2*sqrt(3)*x/3 + sqrt(3)/3) + + See Also + ======== + + log_to_real + """ + if f.degree() < g.degree(): + f, g = -g, f + + f = f.to_field() + g = g.to_field() + + p, q = f.div(g) + + if q.is_zero: + return 2*atan(p.as_expr()) + else: + s, t, h = g.gcdex(-f) + u = (f*s + g*t).quo(h) + A = 2*atan(u.as_expr()) + + return A + log_to_atan(s, t) + + +def _get_real_roots(f, x): + """get real roots of f if possible""" + rs = roots(f, filter='R') + + try: + num_roots = f.count_roots() + except DomainError: + return rs + else: + if len(rs) == num_roots: + return rs + else: + return None + + +def log_to_real(h, q, x, t): + r""" + Convert complex logarithms to real functions. + + Explanation + =========== + + Given real field K and polynomials h in K[t,x] and q in K[t], + returns real function f such that: + ___ + df d \ ` + -- = -- ) a log(h(a, x)) + dx dx /__, + a | q(a) = 0 + + Examples + ======== + + >>> from sympy.integrals.rationaltools import log_to_real + >>> from sympy.abc import x, y + >>> from sympy import Poly, S + >>> log_to_real(Poly(x + 3*y/2 + S(1)/2, x, domain='QQ[y]'), + ... Poly(3*y**2 + 1, y, domain='ZZ'), x, y) + 2*sqrt(3)*atan(2*sqrt(3)*x/3 + sqrt(3)/3)/3 + >>> log_to_real(Poly(x**2 - 1, x, domain='ZZ'), + ... Poly(-2*y + 1, y, domain='ZZ'), x, y) + log(x**2 - 1)/2 + + See Also + ======== + + log_to_atan + """ + from sympy.simplify.radsimp import collect + u, v = symbols('u,v', cls=Dummy) + + H = h.as_expr().xreplace({t: u + I*v}).expand() + Q = q.as_expr().xreplace({t: u + I*v}).expand() + + H_map = collect(H, I, evaluate=False) + Q_map = collect(Q, I, evaluate=False) + + a, b = H_map.get(S.One, S.Zero), H_map.get(I, S.Zero) + c, d = Q_map.get(S.One, S.Zero), Q_map.get(I, S.Zero) + + R = Poly(resultant(c, d, v), u) + + R_u = _get_real_roots(R, u) + + if R_u is None: + return None + + result = S.Zero + + for r_u in R_u.keys(): + C = Poly(c.xreplace({u: r_u}), v) + if not C: + # t was split into real and imaginary parts + # and denom Q(u, v) = c + I*d. We just found + # that c(r_u) is 0 so the roots are in d + C = Poly(d.xreplace({u: r_u}), v) + # we were going to reject roots from C that + # did not set d to zero, but since we are now + # using C = d and c is already 0, there is + # nothing to check + d = S.Zero + + R_v = _get_real_roots(C, v) + + if R_v is None: + return None + + R_v_paired = [] # take one from each pair of conjugate roots + for r_v in R_v: + if r_v not in R_v_paired and -r_v not in R_v_paired: + if r_v.is_negative or r_v.could_extract_minus_sign(): + R_v_paired.append(-r_v) + elif not r_v.is_zero: + R_v_paired.append(r_v) + + for r_v in R_v_paired: + + D = d.xreplace({u: r_u, v: r_v}) + + if D.evalf(chop=True) != 0: + continue + + A = Poly(a.xreplace({u: r_u, v: r_v}), x) + B = Poly(b.xreplace({u: r_u, v: r_v}), x) + + AB = (A**2 + B**2).as_expr() + + result += r_u*log(AB) + r_v*log_to_atan(A, B) + + R_q = _get_real_roots(q, t) + + if R_q is None: + return None + + for r in R_q.keys(): + result += r*log(h.as_expr().subs(t, r)) + + return result diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/rde.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/rde.py new file mode 100644 index 0000000000000000000000000000000000000000..9fb14a1d14b743b1e0885bf25a0d4b409e8a610d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/rde.py @@ -0,0 +1,800 @@ +""" +Algorithms for solving the Risch differential equation. + +Given a differential field K of characteristic 0 that is a simple +monomial extension of a base field k and f, g in K, the Risch +Differential Equation problem is to decide if there exist y in K such +that Dy + f*y == g and to find one if there are some. If t is a +monomial over k and the coefficients of f and g are in k(t), then y is +in k(t), and the outline of the algorithm here is given as: + +1. Compute the normal part n of the denominator of y. The problem is +then reduced to finding y' in k, where y == y'/n. +2. Compute the special part s of the denominator of y. The problem is +then reduced to finding y'' in k[t], where y == y''/(n*s) +3. Bound the degree of y''. +4. Reduce the equation Dy + f*y == g to a similar equation with f, g in +k[t]. +5. Find the solutions in k[t] of bounded degree of the reduced equation. + +See Chapter 6 of "Symbolic Integration I: Transcendental Functions" by +Manuel Bronstein. See also the docstring of risch.py. +""" + +from operator import mul +from functools import reduce + +from sympy.core import oo +from sympy.core.symbol import Dummy + +from sympy.polys import Poly, gcd, ZZ, cancel + +from sympy.functions.elementary.complexes import (im, re) +from sympy.functions.elementary.miscellaneous import sqrt + +from sympy.integrals.risch import (gcdex_diophantine, frac_in, derivation, + splitfactor, NonElementaryIntegralException, DecrementLevel, recognize_log_derivative) + +# TODO: Add messages to NonElementaryIntegralException errors + + +def order_at(a, p, t): + """ + Computes the order of a at p, with respect to t. + + Explanation + =========== + + For a, p in k[t], the order of a at p is defined as nu_p(a) = max({n + in Z+ such that p**n|a}), where a != 0. If a == 0, nu_p(a) = +oo. + + To compute the order at a rational function, a/b, use the fact that + nu_p(a/b) == nu_p(a) - nu_p(b). + """ + if a.is_zero: + return oo + if p == Poly(t, t): + return a.as_poly(t).ET()[0][0] + + # Uses binary search for calculating the power. power_list collects the tuples + # (p^k,k) where each k is some power of 2. After deciding the largest k + # such that k is power of 2 and p^k|a the loop iteratively calculates + # the actual power. + power_list = [] + p1 = p + r = a.rem(p1) + tracks_power = 1 + while r.is_zero: + power_list.append((p1,tracks_power)) + p1 = p1*p1 + tracks_power *= 2 + r = a.rem(p1) + n = 0 + product = Poly(1, t) + while len(power_list) != 0: + final = power_list.pop() + productf = product*final[0] + r = a.rem(productf) + if r.is_zero: + n += final[1] + product = productf + return n + + +def order_at_oo(a, d, t): + """ + Computes the order of a/d at oo (infinity), with respect to t. + + For f in k(t), the order or f at oo is defined as deg(d) - deg(a), where + f == a/d. + """ + if a.is_zero: + return oo + return d.degree(t) - a.degree(t) + + +def weak_normalizer(a, d, DE, z=None): + """ + Weak normalization. + + Explanation + =========== + + Given a derivation D on k[t] and f == a/d in k(t), return q in k[t] + such that f - Dq/q is weakly normalized with respect to t. + + f in k(t) is said to be "weakly normalized" with respect to t if + residue_p(f) is not a positive integer for any normal irreducible p + in k[t] such that f is in R_p (Definition 6.1.1). If f has an + elementary integral, this is equivalent to no logarithm of + integral(f) whose argument depends on t has a positive integer + coefficient, where the arguments of the logarithms not in k(t) are + in k[t]. + + Returns (q, f - Dq/q) + """ + z = z or Dummy('z') + dn, ds = splitfactor(d, DE) + + # Compute d1, where dn == d1*d2**2*...*dn**n is a square-free + # factorization of d. + g = gcd(dn, dn.diff(DE.t)) + d_sqf_part = dn.quo(g) + d1 = d_sqf_part.quo(gcd(d_sqf_part, g)) + + a1, b = gcdex_diophantine(d.quo(d1).as_poly(DE.t), d1.as_poly(DE.t), + a.as_poly(DE.t)) + r = (a - Poly(z, DE.t)*derivation(d1, DE)).as_poly(DE.t).resultant( + d1.as_poly(DE.t)) + r = Poly(r, z) + + if not r.expr.has(z): + return (Poly(1, DE.t), (a, d)) + + N = [i for i in r.real_roots() if i in ZZ and i > 0] + + q = reduce(mul, [gcd(a - Poly(n, DE.t)*derivation(d1, DE), d1) for n in N], + Poly(1, DE.t)) + + dq = derivation(q, DE) + sn = q*a - d*dq + sd = q*d + sn, sd = sn.cancel(sd, include=True) + + return (q, (sn, sd)) + + +def normal_denom(fa, fd, ga, gd, DE): + """ + Normal part of the denominator. + + Explanation + =========== + + Given a derivation D on k[t] and f, g in k(t) with f weakly + normalized with respect to t, either raise NonElementaryIntegralException, + in which case the equation Dy + f*y == g has no solution in k(t), or the + quadruplet (a, b, c, h) such that a, h in k[t], b, c in k, and for any + solution y in k(t) of Dy + f*y == g, q = y*h in k satisfies + a*Dq + b*q == c. + + This constitutes step 1 in the outline given in the rde.py docstring. + """ + dn, ds = splitfactor(fd, DE) + en, es = splitfactor(gd, DE) + + p = dn.gcd(en) + h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t))) + + a = dn*h + c = a*h + if c.div(en)[1]: + # en does not divide dn*h**2 + raise NonElementaryIntegralException + ca = c*ga + ca, cd = ca.cancel(gd, include=True) + + ba = a*fa - dn*derivation(h, DE)*fd + ba, bd = ba.cancel(fd, include=True) + + # (dn*h, dn*h*f - dn*Dh, dn*h**2*g, h) + return (a, (ba, bd), (ca, cd), h) + + +def special_denom(a, ba, bd, ca, cd, DE, case='auto'): + """ + Special part of the denominator. + + Explanation + =========== + + case is one of {'exp', 'tan', 'primitive'} for the hyperexponential, + hypertangent, and primitive cases, respectively. For the + hyperexponential (resp. hypertangent) case, given a derivation D on + k[t] and a in k[t], b, c, in k with Dt/t in k (resp. Dt/(t**2 + 1) in + k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp. + gcd(a, t**2 + 1) == 1), return the quadruplet (A, B, C, 1/h) such that + A, B, C, h in k[t] and for any solution q in k of a*Dq + b*q == c, + r = qh in k[t] satisfies A*Dr + B*r == C. + + For ``case == 'primitive'``, k == k[t], so it returns (a, b, c, 1) in + this case. + + This constitutes step 2 of the outline given in the rde.py docstring. + """ + # TODO: finish writing this and write tests + + if case == 'auto': + case = DE.case + + if case == 'exp': + p = Poly(DE.t, DE.t) + elif case == 'tan': + p = Poly(DE.t**2 + 1, DE.t) + elif case in ('primitive', 'base'): + B = ba.to_field().quo(bd) + C = ca.to_field().quo(cd) + return (a, B, C, Poly(1, DE.t)) + else: + raise ValueError("case must be one of {'exp', 'tan', 'primitive', " + "'base'}, not %s." % case) + + nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) + nc = order_at(ca, p, DE.t) - order_at(cd, p, DE.t) + + n = min(0, nc - min(0, nb)) + if not nb: + # Possible cancellation. + from .prde import parametric_log_deriv + if case == 'exp': + dcoeff = DE.d.quo(Poly(DE.t, DE.t)) + with DecrementLevel(DE): # We are guaranteed to not have problems, + # because case != 'base'. + alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t) + etaa, etad = frac_in(dcoeff, DE.t) + A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) + if A is not None: + Q, m, z = A + if Q == 1: + n = min(n, m) + + elif case == 'tan': + dcoeff = DE.d.quo(Poly(DE.t**2+1, DE.t)) + with DecrementLevel(DE): # We are guaranteed to not have problems, + # because case != 'base'. + alphaa, alphad = frac_in(im(-ba.eval(sqrt(-1))/bd.eval(sqrt(-1))/a.eval(sqrt(-1))), DE.t) + betaa, betad = frac_in(re(-ba.eval(sqrt(-1))/bd.eval(sqrt(-1))/a.eval(sqrt(-1))), DE.t) + etaa, etad = frac_in(dcoeff, DE.t) + + if recognize_log_derivative(Poly(2, DE.t)*betaa, betad, DE): + A = parametric_log_deriv(alphaa*Poly(sqrt(-1), DE.t)*betad+alphad*betaa, alphad*betad, etaa, etad, DE) + if A is not None: + Q, m, z = A + if Q == 1: + n = min(n, m) + N = max(0, -nb, n - nc) + pN = p**N + pn = p**-n + + A = a*pN + B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN + C = (ca*pN*pn).quo(cd) + h = pn + + # (a*p**N, (b + n*a*Dp/p)*p**N, c*p**(N - n), p**-n) + return (A, B, C, h) + + +def bound_degree(a, b, cQ, DE, case='auto', parametric=False): + """ + Bound on polynomial solutions. + + Explanation + =========== + + Given a derivation D on k[t] and ``a``, ``b``, ``c`` in k[t] with ``a != 0``, return + n in ZZ such that deg(q) <= n for any solution q in k[t] of + a*Dq + b*q == c, when parametric=False, or deg(q) <= n for any solution + c1, ..., cm in Const(k) and q in k[t] of a*Dq + b*q == Sum(ci*gi, (i, 1, m)) + when parametric=True. + + For ``parametric=False``, ``cQ`` is ``c``, a ``Poly``; for ``parametric=True``, ``cQ`` is Q == + [q1, ..., qm], a list of Polys. + + This constitutes step 3 of the outline given in the rde.py docstring. + """ + # TODO: finish writing this and write tests + + if case == 'auto': + case = DE.case + + da = a.degree(DE.t) + db = b.degree(DE.t) + + # The parametric and regular cases are identical, except for this part + if parametric: + dc = max(i.degree(DE.t) for i in cQ) + else: + dc = cQ.degree(DE.t) + + alpha = cancel(-b.as_poly(DE.t).LC().as_expr()/ + a.as_poly(DE.t).LC().as_expr()) + + if case == 'base': + n = max(0, dc - max(db, da - 1)) + if db == da - 1 and alpha.is_Integer: + n = max(0, alpha, dc - db) + + elif case == 'primitive': + if db > da: + n = max(0, dc - db) + else: + n = max(0, dc - da + 1) + + etaa, etad = frac_in(DE.d, DE.T[DE.level - 1]) + + t1 = DE.t + with DecrementLevel(DE): + alphaa, alphad = frac_in(alpha, DE.t) + if db == da - 1: + from .prde import limited_integrate + # if alpha == m*Dt + Dz for z in k and m in ZZ: + try: + (za, zd), m = limited_integrate(alphaa, alphad, [(etaa, etad)], + DE) + except NonElementaryIntegralException: + pass + else: + if len(m) != 1: + raise ValueError("Length of m should be 1") + n = max(n, m[0]) + + elif db == da: + # if alpha == Dz/z for z in k*: + # beta = -lc(a*Dz + b*z)/(z*lc(a)) + # if beta == m*Dt + Dw for w in k and m in ZZ: + # n = max(n, m) + from .prde import is_log_deriv_k_t_radical_in_field + A = is_log_deriv_k_t_radical_in_field(alphaa, alphad, DE) + if A is not None: + aa, z = A + if aa == 1: + beta = -(a*derivation(z, DE).as_poly(t1) + + b*z.as_poly(t1)).LC()/(z.as_expr()*a.LC()) + betaa, betad = frac_in(beta, DE.t) + from .prde import limited_integrate + try: + (za, zd), m = limited_integrate(betaa, betad, + [(etaa, etad)], DE) + except NonElementaryIntegralException: + pass + else: + if len(m) != 1: + raise ValueError("Length of m should be 1") + n = max(n, m[0].as_expr()) + + elif case == 'exp': + from .prde import parametric_log_deriv + + n = max(0, dc - max(db, da)) + if da == db: + etaa, etad = frac_in(DE.d.quo(Poly(DE.t, DE.t)), DE.T[DE.level - 1]) + with DecrementLevel(DE): + alphaa, alphad = frac_in(alpha, DE.t) + A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) + if A is not None: + # if alpha == m*Dt/t + Dz/z for z in k* and m in ZZ: + # n = max(n, m) + a, m, z = A + if a == 1: + n = max(n, m) + + elif case in ('tan', 'other_nonlinear'): + delta = DE.d.degree(DE.t) + lam = DE.d.LC() + alpha = cancel(alpha/lam) + n = max(0, dc - max(da + delta - 1, db)) + if db == da + delta - 1 and alpha.is_Integer: + n = max(0, alpha, dc - db) + + else: + raise ValueError("case must be one of {'exp', 'tan', 'primitive', " + "'other_nonlinear', 'base'}, not %s." % case) + + return n + + +def spde(a, b, c, n, DE): + """ + Rothstein's Special Polynomial Differential Equation algorithm. + + Explanation + =========== + + Given a derivation D on k[t], an integer n and ``a``,``b``,``c`` in k[t] with + ``a != 0``, either raise NonElementaryIntegralException, in which case the + equation a*Dq + b*q == c has no solution of degree at most ``n`` in + k[t], or return the tuple (B, C, m, alpha, beta) such that B, C, + alpha, beta in k[t], m in ZZ, and any solution q in k[t] of degree + at most n of a*Dq + b*q == c must be of the form + q == alpha*h + beta, where h in k[t], deg(h) <= m, and Dh + B*h == C. + + This constitutes step 4 of the outline given in the rde.py docstring. + """ + zero = Poly(0, DE.t) + + alpha = Poly(1, DE.t) + beta = Poly(0, DE.t) + + while True: + if c.is_zero: + return (zero, zero, 0, zero, beta) # -1 is more to the point + if (n < 0) is True: + raise NonElementaryIntegralException + + g = a.gcd(b) + if not c.rem(g).is_zero: # g does not divide c + raise NonElementaryIntegralException + + a, b, c = a.quo(g), b.quo(g), c.quo(g) + + if a.degree(DE.t) == 0: + b = b.to_field().quo(a) + c = c.to_field().quo(a) + return (b, c, n, alpha, beta) + + r, z = gcdex_diophantine(b, a, c) + b += derivation(a, DE) + c = z - derivation(r, DE) + n -= a.degree(DE.t) + + beta += alpha * r + alpha *= a + +def no_cancel_b_large(b, c, n, DE): + """ + Poly Risch Differential Equation - No cancellation: deg(b) large enough. + + Explanation + =========== + + Given a derivation D on k[t], ``n`` either an integer or +oo, and ``b``,``c`` + in k[t] with ``b != 0`` and either D == d/dt or + deg(b) > max(0, deg(D) - 1), either raise NonElementaryIntegralException, in + which case the equation ``Dq + b*q == c`` has no solution of degree at + most n in k[t], or a solution q in k[t] of this equation with + ``deg(q) < n``. + """ + q = Poly(0, DE.t) + + while not c.is_zero: + m = c.degree(DE.t) - b.degree(DE.t) + if not 0 <= m <= n: # n < 0 or m < 0 or m > n + raise NonElementaryIntegralException + + p = Poly(c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC()*DE.t**m, DE.t, + expand=False) + q = q + p + n = m - 1 + c = c - derivation(p, DE) - b*p + + return q + + +def no_cancel_b_small(b, c, n, DE): + """ + Poly Risch Differential Equation - No cancellation: deg(b) small enough. + + Explanation + =========== + + Given a derivation D on k[t], ``n`` either an integer or +oo, and ``b``,``c`` + in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or + deg(D) >= 2, either raise NonElementaryIntegralException, in which case the + equation Dq + b*q == c has no solution of degree at most n in k[t], + or a solution q in k[t] of this equation with deg(q) <= n, or the + tuple (h, b0, c0) such that h in k[t], b0, c0, in k, and for any + solution q in k[t] of degree at most n of Dq + bq == c, y == q - h + is a solution in k of Dy + b0*y == c0. + """ + q = Poly(0, DE.t) + + while not c.is_zero: + if n == 0: + m = 0 + else: + m = c.degree(DE.t) - DE.d.degree(DE.t) + 1 + + if not 0 <= m <= n: # n < 0 or m < 0 or m > n + raise NonElementaryIntegralException + + if m > 0: + p = Poly(c.as_poly(DE.t).LC()/(m*DE.d.as_poly(DE.t).LC())*DE.t**m, + DE.t, expand=False) + else: + if b.degree(DE.t) != c.degree(DE.t): + raise NonElementaryIntegralException + if b.degree(DE.t) == 0: + return (q, b.as_poly(DE.T[DE.level - 1]), + c.as_poly(DE.T[DE.level - 1])) + p = Poly(c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC(), DE.t, + expand=False) + + q = q + p + n = m - 1 + c = c - derivation(p, DE) - b*p + + return q + + +# TODO: better name for this function +def no_cancel_equal(b, c, n, DE): + """ + Poly Risch Differential Equation - No cancellation: deg(b) == deg(D) - 1 + + Explanation + =========== + + Given a derivation D on k[t] with deg(D) >= 2, n either an integer + or +oo, and b, c in k[t] with deg(b) == deg(D) - 1, either raise + NonElementaryIntegralException, in which case the equation Dq + b*q == c has + no solution of degree at most n in k[t], or a solution q in k[t] of + this equation with deg(q) <= n, or the tuple (h, m, C) such that h + in k[t], m in ZZ, and C in k[t], and for any solution q in k[t] of + degree at most n of Dq + b*q == c, y == q - h is a solution in k[t] + of degree at most m of Dy + b*y == C. + """ + q = Poly(0, DE.t) + lc = cancel(-b.as_poly(DE.t).LC()/DE.d.as_poly(DE.t).LC()) + if lc.is_Integer and lc.is_positive: + M = lc + else: + M = -1 + + while not c.is_zero: + m = max(M, c.degree(DE.t) - DE.d.degree(DE.t) + 1) + + if not 0 <= m <= n: # n < 0 or m < 0 or m > n + raise NonElementaryIntegralException + + u = cancel(m*DE.d.as_poly(DE.t).LC() + b.as_poly(DE.t).LC()) + if u.is_zero: + return (q, m, c) + if m > 0: + p = Poly(c.as_poly(DE.t).LC()/u*DE.t**m, DE.t, expand=False) + else: + if c.degree(DE.t) != DE.d.degree(DE.t) - 1: + raise NonElementaryIntegralException + else: + p = c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC() + + q = q + p + n = m - 1 + c = c - derivation(p, DE) - b*p + + return q + + +def cancel_primitive(b, c, n, DE): + """ + Poly Risch Differential Equation - Cancellation: Primitive case. + + Explanation + =========== + + Given a derivation D on k[t], n either an integer or +oo, ``b`` in k, and + ``c`` in k[t] with Dt in k and ``b != 0``, either raise + NonElementaryIntegralException, in which case the equation Dq + b*q == c + has no solution of degree at most n in k[t], or a solution q in k[t] of + this equation with deg(q) <= n. + """ + # Delayed imports + from .prde import is_log_deriv_k_t_radical_in_field + with DecrementLevel(DE): + ba, bd = frac_in(b, DE.t) + A = is_log_deriv_k_t_radical_in_field(ba, bd, DE) + if A is not None: + n, z = A + if n == 1: # b == Dz/z + raise NotImplementedError("is_deriv_in_field() is required to " + " solve this problem.") + # if z*c == Dp for p in k[t] and deg(p) <= n: + # return p/z + # else: + # raise NonElementaryIntegralException + + if c.is_zero: + return c # return 0 + + if n < c.degree(DE.t): + raise NonElementaryIntegralException + + q = Poly(0, DE.t) + while not c.is_zero: + m = c.degree(DE.t) + if n < m: + raise NonElementaryIntegralException + with DecrementLevel(DE): + a2a, a2d = frac_in(c.LC(), DE.t) + sa, sd = rischDE(ba, bd, a2a, a2d, DE) + stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False) + q += stm + n = m - 1 + c -= b*stm + derivation(stm, DE) + + return q + + +def cancel_exp(b, c, n, DE): + """ + Poly Risch Differential Equation - Cancellation: Hyperexponential case. + + Explanation + =========== + + Given a derivation D on k[t], n either an integer or +oo, ``b`` in k, and + ``c`` in k[t] with Dt/t in k and ``b != 0``, either raise + NonElementaryIntegralException, in which case the equation Dq + b*q == c + has no solution of degree at most n in k[t], or a solution q in k[t] of + this equation with deg(q) <= n. + """ + from .prde import parametric_log_deriv + eta = DE.d.quo(Poly(DE.t, DE.t)).as_expr() + + with DecrementLevel(DE): + etaa, etad = frac_in(eta, DE.t) + ba, bd = frac_in(b, DE.t) + A = parametric_log_deriv(ba, bd, etaa, etad, DE) + if A is not None: + a, m, z = A + if a == 1: + raise NotImplementedError("is_deriv_in_field() is required to " + "solve this problem.") + # if c*z*t**m == Dp for p in k and q = p/(z*t**m) in k[t] and + # deg(q) <= n: + # return q + # else: + # raise NonElementaryIntegralException + + if c.is_zero: + return c # return 0 + + if n < c.degree(DE.t): + raise NonElementaryIntegralException + + q = Poly(0, DE.t) + while not c.is_zero: + m = c.degree(DE.t) + if n < m: + raise NonElementaryIntegralException + # a1 = b + m*Dt/t + a1 = b.as_expr() + with DecrementLevel(DE): + # TODO: Write a dummy function that does this idiom + a1a, a1d = frac_in(a1, DE.t) + a1a = a1a*etad + etaa*a1d*Poly(m, DE.t) + a1d = a1d*etad + + a2a, a2d = frac_in(c.LC(), DE.t) + + sa, sd = rischDE(a1a, a1d, a2a, a2d, DE) + stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False) + q += stm + n = m - 1 + c -= b*stm + derivation(stm, DE) # deg(c) becomes smaller + return q + + +def solve_poly_rde(b, cQ, n, DE, parametric=False): + """ + Solve a Polynomial Risch Differential Equation with degree bound ``n``. + + This constitutes step 4 of the outline given in the rde.py docstring. + + For parametric=False, cQ is c, a Poly; for parametric=True, cQ is Q == + [q1, ..., qm], a list of Polys. + """ + # No cancellation + if not b.is_zero and (DE.case == 'base' or + b.degree(DE.t) > max(0, DE.d.degree(DE.t) - 1)): + + if parametric: + # Delayed imports + from .prde import prde_no_cancel_b_large + return prde_no_cancel_b_large(b, cQ, n, DE) + return no_cancel_b_large(b, cQ, n, DE) + + elif (b.is_zero or b.degree(DE.t) < DE.d.degree(DE.t) - 1) and \ + (DE.case == 'base' or DE.d.degree(DE.t) >= 2): + + if parametric: + from .prde import prde_no_cancel_b_small + return prde_no_cancel_b_small(b, cQ, n, DE) + + R = no_cancel_b_small(b, cQ, n, DE) + + if isinstance(R, Poly): + return R + else: + # XXX: Might k be a field? (pg. 209) + h, b0, c0 = R + with DecrementLevel(DE): + b0, c0 = b0.as_poly(DE.t), c0.as_poly(DE.t) + if b0 is None: # See above comment + raise ValueError("b0 should be a non-Null value") + if c0 is None: + raise ValueError("c0 should be a non-Null value") + y = solve_poly_rde(b0, c0, n, DE).as_poly(DE.t) + return h + y + + elif DE.d.degree(DE.t) >= 2 and b.degree(DE.t) == DE.d.degree(DE.t) - 1 and \ + n > -b.as_poly(DE.t).LC()/DE.d.as_poly(DE.t).LC(): + + # TODO: Is this check necessary, and if so, what should it do if it fails? + # b comes from the first element returned from spde() + if not b.as_poly(DE.t).LC().is_number: + raise TypeError("Result should be a number") + + if parametric: + raise NotImplementedError("prde_no_cancel_b_equal() is not yet " + "implemented.") + + R = no_cancel_equal(b, cQ, n, DE) + + if isinstance(R, Poly): + return R + else: + h, m, C = R + # XXX: Or should it be rischDE()? + y = solve_poly_rde(b, C, m, DE) + return h + y + + else: + # Cancellation + if b.is_zero: + raise NotImplementedError("Remaining cases for Poly (P)RDE are " + "not yet implemented (is_deriv_in_field() required).") + else: + if DE.case == 'exp': + if parametric: + raise NotImplementedError("Parametric RDE cancellation " + "hyperexponential case is not yet implemented.") + return cancel_exp(b, cQ, n, DE) + + elif DE.case == 'primitive': + if parametric: + raise NotImplementedError("Parametric RDE cancellation " + "primitive case is not yet implemented.") + return cancel_primitive(b, cQ, n, DE) + + else: + raise NotImplementedError("Other Poly (P)RDE cancellation " + "cases are not yet implemented (%s)." % DE.case) + + if parametric: + raise NotImplementedError("Remaining cases for Poly PRDE not yet " + "implemented.") + raise NotImplementedError("Remaining cases for Poly RDE not yet " + "implemented.") + + +def rischDE(fa, fd, ga, gd, DE): + """ + Solve a Risch Differential Equation: Dy + f*y == g. + + Explanation + =========== + + See the outline in the docstring of rde.py for more information + about the procedure used. Either raise NonElementaryIntegralException, in + which case there is no solution y in the given differential field, + or return y in k(t) satisfying Dy + f*y == g, or raise + NotImplementedError, in which case, the algorithms necessary to + solve the given Risch Differential Equation have not yet been + implemented. + """ + _, (fa, fd) = weak_normalizer(fa, fd, DE) + a, (ba, bd), (ca, cd), hn = normal_denom(fa, fd, ga, gd, DE) + A, B, C, hs = special_denom(a, ba, bd, ca, cd, DE) + try: + # Until this is fully implemented, use oo. Note that this will almost + # certainly cause non-termination in spde() (unless A == 1), and + # *might* lead to non-termination in the next step for a nonelementary + # integral (I don't know for certain yet). Fortunately, spde() is + # currently written recursively, so this will just give + # RuntimeError: maximum recursion depth exceeded. + n = bound_degree(A, B, C, DE) + except NotImplementedError: + # Useful for debugging: + # import warnings + # warnings.warn("rischDE: Proceeding with n = oo; may cause " + # "non-termination.") + n = oo + + B, C, m, alpha, beta = spde(A, B, C, n, DE) + if C.is_zero: + y = C + else: + y = solve_poly_rde(B, C, m, DE) + + return (alpha*y + beta, hn*hs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/risch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/risch.py new file mode 100644 index 0000000000000000000000000000000000000000..89e5f10bbb1d011d98a5884ce74ab25b615e1c51 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/risch.py @@ -0,0 +1,1851 @@ +""" +The Risch Algorithm for transcendental function integration. + +The core algorithms for the Risch algorithm are here. The subproblem +algorithms are in the rde.py and prde.py files for the Risch +Differential Equation solver and the parametric problems solvers, +respectively. All important information concerning the differential extension +for an integrand is stored in a DifferentialExtension object, which in the code +is usually called DE. Throughout the code and Inside the DifferentialExtension +object, the conventions/attribute names are that the base domain is QQ and each +differential extension is x, t0, t1, ..., tn-1 = DE.t. DE.x is the variable of +integration (Dx == 1), DE.D is a list of the derivatives of +x, t1, t2, ..., tn-1 = t, DE.T is the list [x, t1, t2, ..., tn-1], DE.t is the +outer-most variable of the differential extension at the given level (the level +can be adjusted using DE.increment_level() and DE.decrement_level()), +k is the field C(x, t0, ..., tn-2), where C is the constant field. The +numerator of a fraction is denoted by a and the denominator by +d. If the fraction is named f, fa == numer(f) and fd == denom(f). +Fractions are returned as tuples (fa, fd). DE.d and DE.t are used to +represent the topmost derivation and extension variable, respectively. +The docstring of a function signifies whether an argument is in k[t], in +which case it will just return a Poly in t, or in k(t), in which case it +will return the fraction (fa, fd). Other variable names probably come +from the names used in Bronstein's book. +""" +from types import GeneratorType +from functools import reduce + +from sympy.core.function import Lambda +from sympy.core.mul import Mul +from sympy.core.intfunc import ilcm +from sympy.core.numbers import I +from sympy.core.power import Pow +from sympy.core.relational import Ne +from sympy.core.singleton import S +from sympy.core.sorting import ordered, default_sort_key +from sympy.core.symbol import Dummy, Symbol +from sympy.functions.elementary.exponential import log, exp +from sympy.functions.elementary.hyperbolic import (cosh, coth, sinh, + tanh) +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (atan, sin, cos, + tan, acot, cot, asin, acos) +from .integrals import integrate, Integral +from .heurisch import _symbols +from sympy.polys.polyerrors import PolynomialError +from sympy.polys.polytools import (real_roots, cancel, Poly, gcd, + reduced) +from sympy.polys.rootoftools import RootSum +from sympy.utilities.iterables import numbered_symbols + + +def integer_powers(exprs): + """ + Rewrites a list of expressions as integer multiples of each other. + + Explanation + =========== + + For example, if you have [x, x/2, x**2 + 1, 2*x/3], then you can rewrite + this as [(x/6) * 6, (x/6) * 3, (x**2 + 1) * 1, (x/6) * 4]. This is useful + in the Risch integration algorithm, where we must write exp(x) + exp(x/2) + as (exp(x/2))**2 + exp(x/2), but not as exp(x) + sqrt(exp(x)) (this is + because only the transcendental case is implemented and we therefore cannot + integrate algebraic extensions). The integer multiples returned by this + function for each term are the smallest possible (their content equals 1). + + Returns a list of tuples where the first element is the base term and the + second element is a list of `(item, factor)` terms, where `factor` is the + integer multiplicative factor that must multiply the base term to obtain + the original item. + + The easiest way to understand this is to look at an example: + + >>> from sympy.abc import x + >>> from sympy.integrals.risch import integer_powers + >>> integer_powers([x, x/2, x**2 + 1, 2*x/3]) + [(x/6, [(x, 6), (x/2, 3), (2*x/3, 4)]), (x**2 + 1, [(x**2 + 1, 1)])] + + We can see how this relates to the example at the beginning of the + docstring. It chose x/6 as the first base term. Then, x can be written as + (x/2) * 2, so we get (0, 2), and so on. Now only element (x**2 + 1) + remains, and there are no other terms that can be written as a rational + multiple of that, so we get that it can be written as (x**2 + 1) * 1. + + """ + # Here is the strategy: + + # First, go through each term and determine if it can be rewritten as a + # rational multiple of any of the terms gathered so far. + # cancel(a/b).is_Rational is sufficient for this. If it is a multiple, we + # add its multiple to the dictionary. + + terms = {} + for term in exprs: + for trm, trm_list in terms.items(): + a = cancel(term/trm) + if a.is_Rational: + trm_list.append((term, a)) + break + else: + terms[term] = [(term, S.One)] + + # After we have done this, we have all the like terms together, so we just + # need to find a common denominator so that we can get the base term and + # integer multiples such that each term can be written as an integer + # multiple of the base term, and the content of the integers is 1. + + newterms = {} + for term, term_list in terms.items(): + common_denom = reduce(ilcm, [i.as_numer_denom()[1] for _, i in + term_list]) + newterm = term/common_denom + newmults = [(i, j*common_denom) for i, j in term_list] + newterms[newterm] = newmults + + return sorted(iter(newterms.items()), key=lambda item: item[0].sort_key()) + + +class DifferentialExtension: + """ + A container for all the information relating to a differential extension. + + Explanation + =========== + + The attributes of this object are (see also the docstring of __init__): + + - f: The original (Expr) integrand. + - x: The variable of integration. + - T: List of variables in the extension. + - D: List of derivations in the extension; corresponds to the elements of T. + - fa: Poly of the numerator of the integrand. + - fd: Poly of the denominator of the integrand. + - Tfuncs: Lambda() representations of each element of T (except for x). + For back-substitution after integration. + - backsubs: A (possibly empty) list of further substitutions to be made on + the final integral to make it look more like the integrand. + - exts: + - extargs: + - cases: List of string representations of the cases of T. + - t: The top level extension variable, as defined by the current level + (see level below). + - d: The top level extension derivation, as defined by the current + derivation (see level below). + - case: The string representation of the case of self.d. + (Note that self.T and self.D will always contain the complete extension, + regardless of the level. Therefore, you should ALWAYS use DE.t and DE.d + instead of DE.T[-1] and DE.D[-1]. If you want to have a list of the + derivations or variables only up to the current level, use + DE.D[:len(DE.D) + DE.level + 1] and DE.T[:len(DE.T) + DE.level + 1]. Note + that, in particular, the derivation() function does this.) + + The following are also attributes, but will probably not be useful other + than in internal use: + - newf: Expr form of fa/fd. + - level: The number (between -1 and -len(self.T)) such that + self.T[self.level] == self.t and self.D[self.level] == self.d. + Use the methods self.increment_level() and self.decrement_level() to change + the current level. + """ + # __slots__ is defined mainly so we can iterate over all the attributes + # of the class easily (the memory use doesn't matter too much, since we + # only create one DifferentialExtension per integration). Also, it's nice + # to have a safeguard when debugging. + __slots__ = ('f', 'x', 'T', 'D', 'fa', 'fd', 'Tfuncs', 'backsubs', + 'exts', 'extargs', 'cases', 'case', 't', 'd', 'newf', 'level', + 'ts', 'dummy') + + def __init__(self, f=None, x=None, handle_first='log', dummy=False, extension=None, rewrite_complex=None): + """ + Tries to build a transcendental extension tower from ``f`` with respect to ``x``. + + Explanation + =========== + + If it is successful, creates a DifferentialExtension object with, among + others, the attributes fa, fd, D, T, Tfuncs, and backsubs such that + fa and fd are Polys in T[-1] with rational coefficients in T[:-1], + fa/fd == f, and D[i] is a Poly in T[i] with rational coefficients in + T[:i] representing the derivative of T[i] for each i from 1 to len(T). + Tfuncs is a list of Lambda objects for back replacing the functions + after integrating. Lambda() is only used (instead of lambda) to make + them easier to test and debug. Note that Tfuncs corresponds to the + elements of T, except for T[0] == x, but they should be back-substituted + in reverse order. backsubs is a (possibly empty) back-substitution list + that should be applied on the completed integral to make it look more + like the original integrand. + + If it is unsuccessful, it raises NotImplementedError. + + You can also create an object by manually setting the attributes as a + dictionary to the extension keyword argument. You must include at least + D. Warning, any attribute that is not given will be set to None. The + attributes T, t, d, cases, case, x, and level are set automatically and + do not need to be given. The functions in the Risch Algorithm will NOT + check to see if an attribute is None before using it. This also does not + check to see if the extension is valid (non-algebraic) or even if it is + self-consistent. Therefore, this should only be used for + testing/debugging purposes. + """ + # XXX: If you need to debug this function, set the break point here + + if extension: + if 'D' not in extension: + raise ValueError("At least the key D must be included with " + "the extension flag to DifferentialExtension.") + for attr in extension: + setattr(self, attr, extension[attr]) + + self._auto_attrs() + + return + elif f is None or x is None: + raise ValueError("Either both f and x or a manual extension must " + "be given.") + + if handle_first not in ('log', 'exp'): + raise ValueError("handle_first must be 'log' or 'exp', not %s." % + str(handle_first)) + + # f will be the original function, self.f might change if we reset + # (e.g., we pull out a constant from an exponential) + self.f = f + self.x = x + # setting the default value 'dummy' + self.dummy = dummy + self.reset() + exp_new_extension, log_new_extension = True, True + + # case of 'automatic' choosing + if rewrite_complex is None: + rewrite_complex = I in self.f.atoms() + + if rewrite_complex: + rewritables = { + (sin, cos, cot, tan, sinh, cosh, coth, tanh): exp, + (asin, acos, acot, atan): log, + } + # rewrite the trigonometric components + for candidates, rule in rewritables.items(): + self.newf = self.newf.rewrite(candidates, rule) + self.newf = cancel(self.newf) + else: + if any(i.has(x) for i in self.f.atoms(sin, cos, tan, atan, asin, acos)): + raise NotImplementedError("Trigonometric extensions are not " + "supported (yet!)") + + exps = set() + pows = set() + numpows = set() + sympows = set() + logs = set() + symlogs = set() + + while True: + if self.newf.is_rational_function(*self.T): + break + + if not exp_new_extension and not log_new_extension: + # We couldn't find a new extension on the last pass, so I guess + # we can't do it. + raise NotImplementedError("Couldn't find an elementary " + "transcendental extension for %s. Try using a " % str(f) + + "manual extension with the extension flag.") + + exps, pows, numpows, sympows, log_new_extension = \ + self._rewrite_exps_pows(exps, pows, numpows, sympows, log_new_extension) + + logs, symlogs = self._rewrite_logs(logs, symlogs) + + if handle_first == 'exp' or not log_new_extension: + exp_new_extension = self._exp_part(exps) + if exp_new_extension is None: + # reset and restart + self.f = self.newf + self.reset() + exp_new_extension = True + continue + + if handle_first == 'log' or not exp_new_extension: + log_new_extension = self._log_part(logs) + + self.fa, self.fd = frac_in(self.newf, self.t) + self._auto_attrs() + + return + + def __getattr__(self, attr): + # Avoid AttributeErrors when debugging + if attr not in self.__slots__: + raise AttributeError("%s has no attribute %s" % (repr(self), repr(attr))) + return None + + def _rewrite_exps_pows(self, exps, pows, numpows, + sympows, log_new_extension): + """ + Rewrite exps/pows for better processing. + """ + from .prde import is_deriv_k + + # Pre-preparsing. + ################# + # Get all exp arguments, so we can avoid ahead of time doing + # something like t1 = exp(x), t2 = exp(x/2) == sqrt(t1). + + # Things like sqrt(exp(x)) do not automatically simplify to + # exp(x/2), so they will be viewed as algebraic. The easiest way + # to handle this is to convert all instances of exp(a)**Rational + # to exp(Rational*a) before doing anything else. Note that the + # _exp_part code can generate terms of this form, so we do need to + # do this at each pass (or else modify it to not do that). + + ratpows = [i for i in self.newf.atoms(Pow) + if (isinstance(i.base, exp) and i.exp.is_Rational)] + + ratpows_repl = [ + (i, i.base.base**(i.exp*i.base.exp)) for i in ratpows] + self.backsubs += [(j, i) for i, j in ratpows_repl] + self.newf = self.newf.xreplace(dict(ratpows_repl)) + + # To make the process deterministic, the args are sorted + # so that functions with smaller op-counts are processed first. + # Ties are broken with the default_sort_key. + + # XXX Although the method is deterministic no additional work + # has been done to guarantee that the simplest solution is + # returned and that it would be affected be using different + # variables. Though it is possible that this is the case + # one should know that it has not been done intentionally, so + # further improvements may be possible. + + # TODO: This probably doesn't need to be completely recomputed at + # each pass. + exps = update_sets(exps, self.newf.atoms(exp), + lambda i: i.exp.is_rational_function(*self.T) and + i.exp.has(*self.T)) + pows = update_sets(pows, self.newf.atoms(Pow), + lambda i: i.exp.is_rational_function(*self.T) and + i.exp.has(*self.T)) + numpows = update_sets(numpows, set(pows), + lambda i: not i.base.has(*self.T)) + sympows = update_sets(sympows, set(pows) - set(numpows), + lambda i: i.base.is_rational_function(*self.T) and + not i.exp.is_Integer) + + # The easiest way to deal with non-base E powers is to convert them + # into base E, integrate, and then convert back. + for i in ordered(pows): + old = i + new = exp(i.exp*log(i.base)) + # If exp is ever changed to automatically reduce exp(x*log(2)) + # to 2**x, then this will break. The solution is to not change + # exp to do that :) + if i in sympows: + if i.exp.is_Rational: + raise NotImplementedError("Algebraic extensions are " + "not supported (%s)." % str(i)) + # We can add a**b only if log(a) in the extension, because + # a**b == exp(b*log(a)). + basea, based = frac_in(i.base, self.t) + A = is_deriv_k(basea, based, self) + if A is None: + # Nonelementary monomial (so far) + + # TODO: Would there ever be any benefit from just + # adding log(base) as a new monomial? + # ANSWER: Yes, otherwise we can't integrate x**x (or + # rather prove that it has no elementary integral) + # without first manually rewriting it as exp(x*log(x)) + self.newf = self.newf.xreplace({old: new}) + self.backsubs += [(new, old)] + log_new_extension = self._log_part([log(i.base)]) + exps = update_sets(exps, self.newf.atoms(exp), lambda i: + i.exp.is_rational_function(*self.T) and i.exp.has(*self.T)) + continue + ans, u, const = A + newterm = exp(i.exp*(log(const) + u)) + # Under the current implementation, exp kills terms + # only if they are of the form a*log(x), where a is a + # Number. This case should have already been killed by the + # above tests. Again, if this changes to kill more than + # that, this will break, which maybe is a sign that you + # shouldn't be changing that. Actually, if anything, this + # auto-simplification should be removed. See + # https://groups.google.com/group/sympy/browse_thread/thread/a61d48235f16867f + + self.newf = self.newf.xreplace({i: newterm}) + + elif i not in numpows: + continue + else: + # i in numpows + newterm = new + # TODO: Just put it in self.Tfuncs + self.backsubs.append((new, old)) + self.newf = self.newf.xreplace({old: newterm}) + exps.append(newterm) + + return exps, pows, numpows, sympows, log_new_extension + + def _rewrite_logs(self, logs, symlogs): + """ + Rewrite logs for better processing. + """ + atoms = self.newf.atoms(log) + logs = update_sets(logs, atoms, + lambda i: i.args[0].is_rational_function(*self.T) and + i.args[0].has(*self.T)) + symlogs = update_sets(symlogs, atoms, + lambda i: i.has(*self.T) and i.args[0].is_Pow and + i.args[0].base.is_rational_function(*self.T) and + not i.args[0].exp.is_Integer) + + # We can handle things like log(x**y) by converting it to y*log(x) + # This will fix not only symbolic exponents of the argument, but any + # non-Integer exponent, like log(sqrt(x)). The exponent can also + # depend on x, like log(x**x). + for i in ordered(symlogs): + # Unlike in the exponential case above, we do not ever + # potentially add new monomials (above we had to add log(a)). + # Therefore, there is no need to run any is_deriv functions + # here. Just convert log(a**b) to b*log(a) and let + # log_new_extension() handle it from there. + lbase = log(i.args[0].base) + logs.append(lbase) + new = i.args[0].exp*lbase + self.newf = self.newf.xreplace({i: new}) + self.backsubs.append((new, i)) + + # remove any duplicates + logs = sorted(set(logs), key=default_sort_key) + + return logs, symlogs + + def _auto_attrs(self): + """ + Set attributes that are generated automatically. + """ + if not self.T: + # i.e., when using the extension flag and T isn't given + self.T = [i.gen for i in self.D] + if not self.x: + self.x = self.T[0] + self.cases = [get_case(d, t) for d, t in zip(self.D, self.T)] + self.level = -1 + self.t = self.T[self.level] + self.d = self.D[self.level] + self.case = self.cases[self.level] + + def _exp_part(self, exps): + """ + Try to build an exponential extension. + + Returns + ======= + + Returns True if there was a new extension, False if there was no new + extension but it was able to rewrite the given exponentials in terms + of the existing extension, and None if the entire extension building + process should be restarted. If the process fails because there is no + way around an algebraic extension (e.g., exp(log(x)/2)), it will raise + NotImplementedError. + """ + from .prde import is_log_deriv_k_t_radical + new_extension = False + restart = False + expargs = [i.exp for i in exps] + ip = integer_powers(expargs) + for arg, others in ip: + # Minimize potential problems with algebraic substitution + others.sort(key=lambda i: i[1]) + + arga, argd = frac_in(arg, self.t) + A = is_log_deriv_k_t_radical(arga, argd, self) + + if A is not None: + ans, u, n, const = A + # if n is 1 or -1, it's algebraic, but we can handle it + if n == -1: + # This probably will never happen, because + # Rational.as_numer_denom() returns the negative term in + # the numerator. But in case that changes, reduce it to + # n == 1. + n = 1 + u **= -1 + const *= -1 + ans = [(i, -j) for i, j in ans] + + if n == 1: + # Example: exp(x + x**2) over QQ(x, exp(x), exp(x**2)) + self.newf = self.newf.xreplace({exp(arg): exp(const)*Mul(*[ + u**power for u, power in ans])}) + self.newf = self.newf.xreplace({exp(p*exparg): + exp(const*p) * Mul(*[u**power for u, power in ans]) + for exparg, p in others}) + # TODO: Add something to backsubs to put exp(const*p) + # back together. + + continue + + else: + # Bad news: we have an algebraic radical. But maybe we + # could still avoid it by choosing a different extension. + # For example, integer_powers() won't handle exp(x/2 + 1) + # over QQ(x, exp(x)), but if we pull out the exp(1), it + # will. Or maybe we have exp(x + x**2/2), over + # QQ(x, exp(x), exp(x**2)), which is exp(x)*sqrt(exp(x**2)), + # but if we use QQ(x, exp(x), exp(x**2/2)), then they will + # all work. + # + # So here is what we do: If there is a non-zero const, pull + # it out and retry. Also, if len(ans) > 1, then rewrite + # exp(arg) as the product of exponentials from ans, and + # retry that. If const == 0 and len(ans) == 1, then we + # assume that it would have been handled by either + # integer_powers() or n == 1 above if it could be handled, + # so we give up at that point. For example, you can never + # handle exp(log(x)/2) because it equals sqrt(x). + + if const or len(ans) > 1: + rad = Mul(*[term**(power/n) for term, power in ans]) + self.newf = self.newf.xreplace({exp(p*exparg): + exp(const*p)*rad for exparg, p in others}) + self.newf = self.newf.xreplace(dict(list(zip(reversed(self.T), + reversed([f(self.x) for f in self.Tfuncs]))))) + restart = True + break + else: + # TODO: give algebraic dependence in error string + raise NotImplementedError("Cannot integrate over " + "algebraic extensions.") + + else: + arga, argd = frac_in(arg, self.t) + darga = (argd*derivation(Poly(arga, self.t), self) - + arga*derivation(Poly(argd, self.t), self)) + dargd = argd**2 + darga, dargd = darga.cancel(dargd, include=True) + darg = darga.as_expr()/dargd.as_expr() + self.t = next(self.ts) + self.T.append(self.t) + self.extargs.append(arg) + self.exts.append('exp') + self.D.append(darg.as_poly(self.t, expand=False)*Poly(self.t, + self.t, expand=False)) + if self.dummy: + i = Dummy("i") + else: + i = Symbol('i') + self.Tfuncs += [Lambda(i, exp(arg.subs(self.x, i)))] + self.newf = self.newf.xreplace( + {exp(exparg): self.t**p for exparg, p in others}) + new_extension = True + + if restart: + return None + return new_extension + + def _log_part(self, logs): + """ + Try to build a logarithmic extension. + + Returns + ======= + + Returns True if there was a new extension and False if there was no new + extension but it was able to rewrite the given logarithms in terms + of the existing extension. Unlike with exponential extensions, there + is no way that a logarithm is not transcendental over and cannot be + rewritten in terms of an already existing extension in a non-algebraic + way, so this function does not ever return None or raise + NotImplementedError. + """ + from .prde import is_deriv_k + new_extension = False + logargs = [i.args[0] for i in logs] + for arg in ordered(logargs): + # The log case is easier, because whenever a logarithm is algebraic + # over the base field, it is of the form a1*t1 + ... an*tn + c, + # which is a polynomial, so we can just replace it with that. + # In other words, we don't have to worry about radicals. + arga, argd = frac_in(arg, self.t) + A = is_deriv_k(arga, argd, self) + if A is not None: + ans, u, const = A + newterm = log(const) + u + self.newf = self.newf.xreplace({log(arg): newterm}) + continue + + else: + arga, argd = frac_in(arg, self.t) + darga = (argd*derivation(Poly(arga, self.t), self) - + arga*derivation(Poly(argd, self.t), self)) + dargd = argd**2 + darg = darga.as_expr()/dargd.as_expr() + self.t = next(self.ts) + self.T.append(self.t) + self.extargs.append(arg) + self.exts.append('log') + self.D.append(cancel(darg.as_expr()/arg).as_poly(self.t, + expand=False)) + if self.dummy: + i = Dummy("i") + else: + i = Symbol('i') + self.Tfuncs += [Lambda(i, log(arg.subs(self.x, i)))] + self.newf = self.newf.xreplace({log(arg): self.t}) + new_extension = True + + return new_extension + + @property + def _important_attrs(self): + """ + Returns some of the more important attributes of self. + + Explanation + =========== + + Used for testing and debugging purposes. + + The attributes are (fa, fd, D, T, Tfuncs, backsubs, + exts, extargs). + """ + return (self.fa, self.fd, self.D, self.T, self.Tfuncs, + self.backsubs, self.exts, self.extargs) + + # NOTE: this printing doesn't follow the Python's standard + # eval(repr(DE)) == DE, where DE is the DifferentialExtension object, + # also this printing is supposed to contain all the important + # attributes of a DifferentialExtension object + def __repr__(self): + # no need to have GeneratorType object printed in it + r = [(attr, getattr(self, attr)) for attr in self.__slots__ + if not isinstance(getattr(self, attr), GeneratorType)] + return self.__class__.__name__ + '(dict(%r))' % (r) + + # fancy printing of DifferentialExtension object + def __str__(self): + return (self.__class__.__name__ + '({fa=%s, fd=%s, D=%s})' % + (self.fa, self.fd, self.D)) + + # should only be used for debugging purposes, internally + # f1 = f2 = log(x) at different places in code execution + # may return D1 != D2 as True, since 'level' or other attribute + # may differ + def __eq__(self, other): + for attr in self.__class__.__slots__: + d1, d2 = getattr(self, attr), getattr(other, attr) + if not (isinstance(d1, GeneratorType) or d1 == d2): + return False + return True + + def reset(self): + """ + Reset self to an initial state. Used by __init__. + """ + self.t = self.x + self.T = [self.x] + self.D = [Poly(1, self.x)] + self.level = -1 + self.exts = [None] + self.extargs = [None] + if self.dummy: + self.ts = numbered_symbols('t', cls=Dummy) + else: + # For testing + self.ts = numbered_symbols('t') + # For various things that we change to make things work that we need to + # change back when we are done. + self.backsubs = [] + self.Tfuncs = [] + self.newf = self.f + + def indices(self, extension): + """ + Parameters + ========== + + extension : str + Represents a valid extension type. + + Returns + ======= + + list: A list of indices of 'exts' where extension of + type 'extension' is present. + + Examples + ======== + + >>> from sympy.integrals.risch import DifferentialExtension + >>> from sympy import log, exp + >>> from sympy.abc import x + >>> DE = DifferentialExtension(log(x) + exp(x), x, handle_first='exp') + >>> DE.indices('log') + [2] + >>> DE.indices('exp') + [1] + + """ + return [i for i, ext in enumerate(self.exts) if ext == extension] + + def increment_level(self): + """ + Increment the level of self. + + Explanation + =========== + + This makes the working differential extension larger. self.level is + given relative to the end of the list (-1, -2, etc.), so we do not need + do worry about it when building the extension. + """ + if self.level >= -1: + raise ValueError("The level of the differential extension cannot " + "be incremented any further.") + + self.level += 1 + self.t = self.T[self.level] + self.d = self.D[self.level] + self.case = self.cases[self.level] + return None + + def decrement_level(self): + """ + Decrease the level of self. + + Explanation + =========== + + This makes the working differential extension smaller. self.level is + given relative to the end of the list (-1, -2, etc.), so we do not need + do worry about it when building the extension. + """ + if self.level <= -len(self.T): + raise ValueError("The level of the differential extension cannot " + "be decremented any further.") + + self.level -= 1 + self.t = self.T[self.level] + self.d = self.D[self.level] + self.case = self.cases[self.level] + return None + + +def update_sets(seq, atoms, func): + s = set(seq) + s = atoms.intersection(s) + new = atoms - s + s.update(list(filter(func, new))) + return list(s) + + +class DecrementLevel: + """ + A context manager for decrementing the level of a DifferentialExtension. + """ + __slots__ = ('DE',) + + def __init__(self, DE): + self.DE = DE + return + + def __enter__(self): + self.DE.decrement_level() + + def __exit__(self, exc_type, exc_value, traceback): + self.DE.increment_level() + + +class NonElementaryIntegralException(Exception): + """ + Exception used by subroutines within the Risch algorithm to indicate to one + another that the function being integrated does not have an elementary + integral in the given differential field. + """ + # TODO: Rewrite algorithms below to use this (?) + + # TODO: Pass through information about why the integral was nonelementary, + # and store that in the resulting NonElementaryIntegral somehow. + pass + + +def gcdex_diophantine(a, b, c): + """ + Extended Euclidean Algorithm, Diophantine version. + + Explanation + =========== + + Given ``a``, ``b`` in K[x] and ``c`` in (a, b), the ideal generated by ``a`` and + ``b``, return (s, t) such that s*a + t*b == c and either s == 0 or s.degree() + < b.degree(). + """ + # Extended Euclidean Algorithm (Diophantine Version) pg. 13 + # TODO: This should go in densetools.py. + # XXX: Better name? + + s, g = a.half_gcdex(b) + s *= c.exquo(g) # Inexact division means c is not in (a, b) + if s and s.degree() >= b.degree(): + _, s = s.div(b) + t = (c - s*a).exquo(b) + return (s, t) + + +def frac_in(f, t, *, cancel=False, **kwargs): + """ + Returns the tuple (fa, fd), where fa and fd are Polys in t. + + Explanation + =========== + + This is a common idiom in the Risch Algorithm functions, so we abstract + it out here. ``f`` should be a basic expression, a Poly, or a tuple (fa, fd), + where fa and fd are either basic expressions or Polys, and f == fa/fd. + **kwargs are applied to Poly. + """ + if isinstance(f, tuple): + fa, fd = f + f = fa.as_expr()/fd.as_expr() + fa, fd = f.as_expr().as_numer_denom() + fa, fd = fa.as_poly(t, **kwargs), fd.as_poly(t, **kwargs) + if cancel: + fa, fd = fa.cancel(fd, include=True) + if fa is None or fd is None: + raise ValueError("Could not turn %s into a fraction in %s." % (f, t)) + return (fa, fd) + + +def as_poly_1t(p, t, z): + """ + (Hackish) way to convert an element ``p`` of K[t, 1/t] to K[t, z]. + + In other words, ``z == 1/t`` will be a dummy variable that Poly can handle + better. + + See issue 5131. + + Examples + ======== + + >>> from sympy import random_poly + >>> from sympy.integrals.risch import as_poly_1t + >>> from sympy.abc import x, z + + >>> p1 = random_poly(x, 10, -10, 10) + >>> p2 = random_poly(x, 10, -10, 10) + >>> p = p1 + p2.subs(x, 1/x) + >>> as_poly_1t(p, x, z).as_expr().subs(z, 1/x) == p + True + """ + # TODO: Use this on the final result. That way, we can avoid answers like + # (...)*exp(-x). + pa, pd = frac_in(p, t, cancel=True) + if not pd.is_monomial: + # XXX: Is there a better Poly exception that we could raise here? + # Either way, if you see this (from the Risch Algorithm) it indicates + # a bug. + raise PolynomialError("%s is not an element of K[%s, 1/%s]." % (p, t, t)) + + t_part, remainder = pa.div(pd) + + ans = t_part.as_poly(t, z, expand=False) + + if remainder: + one = remainder.one + tp = t*one + r = pd.degree() - remainder.degree() + z_part = remainder.transform(one, tp) * tp**r + z_part = z_part.replace(t, z).to_field().quo_ground(pd.LC()) + ans += z_part.as_poly(t, z, expand=False) + + return ans + + +def derivation(p, DE, coefficientD=False, basic=False): + """ + Computes Dp. + + Explanation + =========== + + Given the derivation D with D = d/dx and p is a polynomial in t over + K(x), return Dp. + + If coefficientD is True, it computes the derivation kD + (kappaD), which is defined as kD(sum(ai*Xi**i, (i, 0, n))) == + sum(Dai*Xi**i, (i, 1, n)) (Definition 3.2.2, page 80). X in this case is + T[-1], so coefficientD computes the derivative just with respect to T[:-1], + with T[-1] treated as a constant. + + If ``basic=True``, the returns a Basic expression. Elements of D can still be + instances of Poly. + """ + if basic: + r = 0 + else: + r = Poly(0, DE.t) + + t = DE.t + if coefficientD: + if DE.level <= -len(DE.T): + # 'base' case, the answer is 0. + return r + DE.decrement_level() + + D = DE.D[:len(DE.D) + DE.level + 1] + T = DE.T[:len(DE.T) + DE.level + 1] + + for d, v in zip(D, T): + pv = p.as_poly(v) + if pv is None or basic: + pv = p.as_expr() + + if basic: + r += d.as_expr()*pv.diff(v) + else: + r += (d.as_expr()*pv.diff(v).as_expr()).as_poly(t) + + if basic: + r = cancel(r) + if coefficientD: + DE.increment_level() + + return r + + +def get_case(d, t): + """ + Returns the type of the derivation d. + + Returns one of {'exp', 'tan', 'base', 'primitive', 'other_linear', + 'other_nonlinear'}. + """ + if not d.expr.has(t): + if d.is_one: + return 'base' + return 'primitive' + if d.rem(Poly(t, t)).is_zero: + return 'exp' + if d.rem(Poly(1 + t**2, t)).is_zero: + return 'tan' + if d.degree(t) > 1: + return 'other_nonlinear' + return 'other_linear' + + +def splitfactor(p, DE, coefficientD=False, z=None): + """ + Splitting factorization. + + Explanation + =========== + + Given a derivation D on k[t] and ``p`` in k[t], return (p_n, p_s) in + k[t] x k[t] such that p = p_n*p_s, p_s is special, and each square + factor of p_n is normal. + + Page. 100 + """ + kinv = [1/x for x in DE.T[:DE.level]] + if z: + kinv.append(z) + + One = Poly(1, DE.t, domain=p.get_domain()) + Dp = derivation(p, DE, coefficientD=coefficientD) + # XXX: Is this right? + if p.is_zero: + return (p, One) + + if not p.expr.has(DE.t): + s = p.as_poly(*kinv).gcd(Dp.as_poly(*kinv)).as_poly(DE.t) + n = p.exquo(s) + return (n, s) + + if not Dp.is_zero: + h = p.gcd(Dp).to_field() + g = p.gcd(p.diff(DE.t)).to_field() + s = h.exquo(g) + + if s.degree(DE.t) == 0: + return (p, One) + + q_split = splitfactor(p.exquo(s), DE, coefficientD=coefficientD) + + return (q_split[0], q_split[1]*s) + else: + return (p, One) + + +def splitfactor_sqf(p, DE, coefficientD=False, z=None, basic=False): + """ + Splitting Square-free Factorization. + + Explanation + =========== + + Given a derivation D on k[t] and ``p`` in k[t], returns (N1, ..., Nm) + and (S1, ..., Sm) in k[t]^m such that p = + (N1*N2**2*...*Nm**m)*(S1*S2**2*...*Sm**m) is a splitting + factorization of ``p`` and the Ni and Si are square-free and coprime. + """ + # TODO: This algorithm appears to be faster in every case + # TODO: Verify this and splitfactor() for multiple extensions + kkinv = [1/x for x in DE.T[:DE.level]] + DE.T[:DE.level] + if z: + kkinv = [z] + + S = [] + N = [] + p_sqf = p.sqf_list_include() + if p.is_zero: + return (((p, 1),), ()) + + for pi, i in p_sqf: + Si = pi.as_poly(*kkinv).gcd(derivation(pi, DE, + coefficientD=coefficientD,basic=basic).as_poly(*kkinv)).as_poly(DE.t) + pi = Poly(pi, DE.t) + Si = Poly(Si, DE.t) + Ni = pi.exquo(Si) + if not Si.is_one: + S.append((Si, i)) + if not Ni.is_one: + N.append((Ni, i)) + + return (tuple(N), tuple(S)) + + +def canonical_representation(a, d, DE): + """ + Canonical Representation. + + Explanation + =========== + + Given a derivation D on k[t] and f = a/d in k(t), return (f_p, f_s, + f_n) in k[t] x k(t) x k(t) such that f = f_p + f_s + f_n is the + canonical representation of f (f_p is a polynomial, f_s is reduced + (has a special denominator), and f_n is simple (has a normal + denominator). + """ + # Make d monic + l = Poly(1/d.LC(), DE.t) + a, d = a.mul(l), d.mul(l) + + q, r = a.div(d) + dn, ds = splitfactor(d, DE) + + b, c = gcdex_diophantine(dn.as_poly(DE.t), ds.as_poly(DE.t), r.as_poly(DE.t)) + b, c = b.as_poly(DE.t), c.as_poly(DE.t) + + return (q, (b, ds), (c, dn)) + + +def hermite_reduce(a, d, DE): + """ + Hermite Reduction - Mack's Linear Version. + + Given a derivation D on k(t) and f = a/d in k(t), returns g, h, r in + k(t) such that f = Dg + h + r, h is simple, and r is reduced. + + """ + # Make d monic + l = Poly(1/d.LC(), DE.t) + a, d = a.mul(l), d.mul(l) + + fp, fs, fn = canonical_representation(a, d, DE) + a, d = fn + l = Poly(1/d.LC(), DE.t) + a, d = a.mul(l), d.mul(l) + + ga = Poly(0, DE.t) + gd = Poly(1, DE.t) + + dd = derivation(d, DE) + dm = gcd(d.to_field(), dd.to_field()).as_poly(DE.t) + ds, _ = d.div(dm) + + while dm.degree(DE.t) > 0: + + ddm = derivation(dm, DE) + dm2 = gcd(dm.to_field(), ddm.to_field()) + dms, _ = dm.div(dm2) + ds_ddm = ds.mul(ddm) + ds_ddm_dm, _ = ds_ddm.div(dm) + + b, c = gcdex_diophantine(-ds_ddm_dm.as_poly(DE.t), + dms.as_poly(DE.t), a.as_poly(DE.t)) + b, c = b.as_poly(DE.t), c.as_poly(DE.t) + + db = derivation(b, DE).as_poly(DE.t) + ds_dms, _ = ds.div(dms) + a = c.as_poly(DE.t) - db.mul(ds_dms).as_poly(DE.t) + + ga = ga*dm + b*gd + gd = gd*dm + ga, gd = ga.cancel(gd, include=True) + dm = dm2 + + q, r = a.div(ds) + ga, gd = ga.cancel(gd, include=True) + + r, d = r.cancel(ds, include=True) + rra = q*fs[1] + fp*fs[1] + fs[0] + rrd = fs[1] + rra, rrd = rra.cancel(rrd, include=True) + + return ((ga, gd), (r, d), (rra, rrd)) + + +def polynomial_reduce(p, DE): + """ + Polynomial Reduction. + + Explanation + =========== + + Given a derivation D on k(t) and p in k[t] where t is a nonlinear + monomial over k, return q, r in k[t] such that p = Dq + r, and + deg(r) < deg_t(Dt). + """ + q = Poly(0, DE.t) + while p.degree(DE.t) >= DE.d.degree(DE.t): + m = p.degree(DE.t) - DE.d.degree(DE.t) + 1 + q0 = Poly(DE.t**m, DE.t).mul(Poly(p.as_poly(DE.t).LC()/ + (m*DE.d.LC()), DE.t)) + q += q0 + p = p - derivation(q0, DE) + + return (q, p) + + +def laurent_series(a, d, F, n, DE): + """ + Contribution of ``F`` to the full partial fraction decomposition of A/D. + + Explanation + =========== + + Given a field K of characteristic 0 and ``A``,``D``,``F`` in K[x] with D monic, + nonzero, coprime with A, and ``F`` the factor of multiplicity n in the square- + free factorization of D, return the principal parts of the Laurent series of + A/D at all the zeros of ``F``. + """ + if F.degree()==0: + return 0 + Z = _symbols('z', n) + z = Symbol('z') + Z.insert(0, z) + delta_a = Poly(0, DE.t) + delta_d = Poly(1, DE.t) + + E = d.quo(F**n) + ha, hd = (a, E*Poly(z**n, DE.t)) + dF = derivation(F,DE) + B, _ = gcdex_diophantine(E, F, Poly(1,DE.t)) + C, _ = gcdex_diophantine(dF, F, Poly(1,DE.t)) + + # initialization + F_store = F + V, DE_D_list, H_list= [], [], [] + + for j in range(0, n): + # jth derivative of z would be substituted with dfnth/(j+1) where dfnth =(d^n)f/(dx)^n + F_store = derivation(F_store, DE) + v = (F_store.as_expr())/(j + 1) + V.append(v) + DE_D_list.append(Poly(Z[j + 1],Z[j])) + + DE_new = DifferentialExtension(extension = {'D': DE_D_list}) #a differential indeterminate + for j in range(0, n): + zEha = Poly(z**(n + j), DE.t)*E**(j + 1)*ha + zEhd = hd + Pa, Pd = cancel((zEha, zEhd))[1], cancel((zEha, zEhd))[2] + Q = Pa.quo(Pd) + for i in range(0, j + 1): + Q = Q.subs(Z[i], V[i]) + Dha = (hd*derivation(ha, DE, basic=True).as_poly(DE.t) + + ha*derivation(hd, DE, basic=True).as_poly(DE.t) + + hd*derivation(ha, DE_new, basic=True).as_poly(DE.t) + + ha*derivation(hd, DE_new, basic=True).as_poly(DE.t)) + Dhd = Poly(j + 1, DE.t)*hd**2 + ha, hd = Dha, Dhd + + Ff, _ = F.div(gcd(F, Q)) + F_stara, F_stard = frac_in(Ff, DE.t) + if F_stara.degree(DE.t) - F_stard.degree(DE.t) > 0: + QBC = Poly(Q, DE.t)*B**(1 + j)*C**(n + j) + H = QBC + H_list.append(H) + H = (QBC*F_stard).rem(F_stara) + alphas = real_roots(F_stara) + for alpha in list(alphas): + delta_a = delta_a*Poly((DE.t - alpha)**(n - j), DE.t) + Poly(H.eval(alpha), DE.t) + delta_d = delta_d*Poly((DE.t - alpha)**(n - j), DE.t) + return (delta_a, delta_d, H_list) + + +def recognize_derivative(a, d, DE, z=None): + """ + Compute the squarefree factorization of the denominator of f + and for each Di the polynomial H in K[x] (see Theorem 2.7.1), using the + LaurentSeries algorithm. Write Di = GiEi where Gj = gcd(Hn, Di) and + gcd(Ei,Hn) = 1. Since the residues of f at the roots of Gj are all 0, and + the residue of f at a root alpha of Ei is Hi(a) != 0, f is the derivative of a + rational function if and only if Ei = 1 for each i, which is equivalent to + Di | H[-1] for each i. + """ + flag =True + a, d = a.cancel(d, include=True) + _, r = a.div(d) + Np, Sp = splitfactor_sqf(d, DE, coefficientD=True, z=z) + + j = 1 + for s, _ in Sp: + delta_a, delta_d, H = laurent_series(r, d, s, j, DE) + g = gcd(d, H[-1]).as_poly() + if g is not d: + flag = False + break + j = j + 1 + return flag + + +def recognize_log_derivative(a, d, DE, z=None): + """ + There exists a v in K(x)* such that f = dv/v + where f a rational function if and only if f can be written as f = A/D + where D is squarefree,deg(A) < deg(D), gcd(A, D) = 1, + and all the roots of the Rothstein-Trager resultant are integers. In that case, + any of the Rothstein-Trager, Lazard-Rioboo-Trager or Czichowski algorithm + produces u in K(x) such that du/dx = uf. + """ + + z = z or Dummy('z') + a, d = a.cancel(d, include=True) + _, a = a.div(d) + + pz = Poly(z, DE.t) + Dd = derivation(d, DE) + q = a - pz*Dd + r, _ = d.resultant(q, includePRS=True) + r = Poly(r, z) + Np, Sp = splitfactor_sqf(r, DE, coefficientD=True, z=z) + + for s, _ in Sp: + # TODO also consider the complex roots which should + # turn the flag false + a = real_roots(s.as_poly(z)) + + if not all(j.is_Integer for j in a): + return False + return True + +def residue_reduce(a, d, DE, z=None, invert=True): + """ + Lazard-Rioboo-Rothstein-Trager resultant reduction. + + Explanation + =========== + + Given a derivation ``D`` on k(t) and f in k(t) simple, return g + elementary over k(t) and a Boolean b in {True, False} such that f - + Dg in k[t] if b == True or f + h and f + h - Dg do not have an + elementary integral over k(t) for any h in k (reduced) if b == + False. + + Returns (G, b), where G is a tuple of tuples of the form (s_i, S_i), + such that g = Add(*[RootSum(s_i, lambda z: z*log(S_i(z, t))) for + S_i, s_i in G]). f - Dg is the remaining integral, which is elementary + only if b == True, and hence the integral of f is elementary only if + b == True. + + f - Dg is not calculated in this function because that would require + explicitly calculating the RootSum. Use residue_reduce_derivation(). + """ + # TODO: Use log_to_atan() from rationaltools.py + # If r = residue_reduce(...), then the logarithmic part is given by: + # sum([RootSum(a[0].as_poly(z), lambda i: i*log(a[1].as_expr()).subs(z, + # i)).subs(t, log(x)) for a in r[0]]) + + z = z or Dummy('z') + a, d = a.cancel(d, include=True) + a, d = a.to_field().mul_ground(1/d.LC()), d.to_field().mul_ground(1/d.LC()) + kkinv = [1/x for x in DE.T[:DE.level]] + DE.T[:DE.level] + + if a.is_zero: + return ([], True) + _, a = a.div(d) + + pz = Poly(z, DE.t) + + Dd = derivation(d, DE) + q = a - pz*Dd + + if Dd.degree(DE.t) <= d.degree(DE.t): + r, R = d.resultant(q, includePRS=True) + else: + r, R = q.resultant(d, includePRS=True) + + R_map, H = {}, [] + for i in R: + R_map[i.degree()] = i + + r = Poly(r, z) + Np, Sp = splitfactor_sqf(r, DE, coefficientD=True, z=z) + + for s, i in Sp: + if i == d.degree(DE.t): + s = Poly(s, z).monic() + H.append((s, d)) + else: + h = R_map.get(i) + if h is None: + continue + h_lc = Poly(h.as_poly(DE.t).LC(), DE.t, field=True) + + h_lc_sqf = h_lc.sqf_list_include(all=True) + + for a, j in h_lc_sqf: + h = Poly(h, DE.t, field=True).exquo(Poly(gcd(a, s**j, *kkinv), + DE.t)) + + s = Poly(s, z).monic() + + if invert: + h_lc = Poly(h.as_poly(DE.t).LC(), DE.t, field=True, expand=False) + inv, coeffs = h_lc.as_poly(z, field=True).invert(s), [S.One] + + for coeff in h.coeffs()[1:]: + L = reduced(inv*coeff.as_poly(inv.gens), [s])[1] + coeffs.append(L.as_expr()) + + h = Poly(dict(list(zip(h.monoms(), coeffs))), DE.t) + + H.append((s, h)) + + b = not any(cancel(i.as_expr()).has(DE.t, z) for i, _ in Np) + + return (H, b) + + +def residue_reduce_to_basic(H, DE, z): + """ + Converts the tuple returned by residue_reduce() into a Basic expression. + """ + # TODO: check what Lambda does with RootOf + i = Dummy('i') + s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) + + return sum(RootSum(a[0].as_poly(z), Lambda(i, i*log(a[1].as_expr()).subs( + {z: i}).subs(s))) for a in H) + + +def residue_reduce_derivation(H, DE, z): + """ + Computes the derivation of an expression returned by residue_reduce(). + + In general, this is a rational function in t, so this returns an + as_expr() result. + """ + # TODO: verify that this is correct for multiple extensions + i = Dummy('i') + return S(sum(RootSum(a[0].as_poly(z), Lambda(i, i*derivation(a[1], + DE).as_expr().subs(z, i)/a[1].as_expr().subs(z, i))) for a in H)) + + +def integrate_primitive_polynomial(p, DE): + """ + Integration of primitive polynomials. + + Explanation + =========== + + Given a primitive monomial t over k, and ``p`` in k[t], return q in k[t], + r in k, and a bool b in {True, False} such that r = p - Dq is in k if b is + True, or r = p - Dq does not have an elementary integral over k(t) if b is + False. + """ + Zero = Poly(0, DE.t) + q = Poly(0, DE.t) + + if not p.expr.has(DE.t): + return (Zero, p, True) + + from .prde import limited_integrate + while True: + if not p.expr.has(DE.t): + return (q, p, True) + + Dta, Dtb = frac_in(DE.d, DE.T[DE.level - 1]) + + with DecrementLevel(DE): # We had better be integrating the lowest extension (x) + # with ratint(). + a = p.LC() + aa, ad = frac_in(a, DE.t) + + try: + rv = limited_integrate(aa, ad, [(Dta, Dtb)], DE) + if rv is None: + raise NonElementaryIntegralException + (ba, bd), c = rv + except NonElementaryIntegralException: + return (q, p, False) + + m = p.degree(DE.t) + q0 = c[0].as_poly(DE.t)*Poly(DE.t**(m + 1)/(m + 1), DE.t) + \ + (ba.as_expr()/bd.as_expr()).as_poly(DE.t)*Poly(DE.t**m, DE.t) + + p = p - derivation(q0, DE) + q = q + q0 + + +def integrate_primitive(a, d, DE, z=None): + """ + Integration of primitive functions. + + Explanation + =========== + + Given a primitive monomial t over k and f in k(t), return g elementary over + k(t), i in k(t), and b in {True, False} such that i = f - Dg is in k if b + is True or i = f - Dg does not have an elementary integral over k(t) if b + is False. + + This function returns a Basic expression for the first argument. If b is + True, the second argument is Basic expression in k to recursively integrate. + If b is False, the second argument is an unevaluated Integral, which has + been proven to be nonelementary. + """ + # XXX: a and d must be canceled, or this might return incorrect results + z = z or Dummy("z") + s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) + + g1, h, r = hermite_reduce(a, d, DE) + g2, b = residue_reduce(h[0], h[1], DE, z=z) + if not b: + i = cancel(a.as_expr()/d.as_expr() - (g1[1]*derivation(g1[0], DE) - + g1[0]*derivation(g1[1], DE)).as_expr()/(g1[1]**2).as_expr() - + residue_reduce_derivation(g2, DE, z)) + i = NonElementaryIntegral(cancel(i).subs(s), DE.x) + return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z), i, b) + + # h - Dg2 + r + p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, + DE, z) + r[0].as_expr()/r[1].as_expr()) + p = p.as_poly(DE.t) + + q, i, b = integrate_primitive_polynomial(p, DE) + + ret = ((g1[0].as_expr()/g1[1].as_expr() + q.as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z)) + if not b: + # TODO: This does not do the right thing when b is False + i = NonElementaryIntegral(cancel(i.as_expr()).subs(s), DE.x) + else: + i = cancel(i.as_expr()) + + return (ret, i, b) + + +def integrate_hyperexponential_polynomial(p, DE, z): + """ + Integration of hyperexponential polynomials. + + Explanation + =========== + + Given a hyperexponential monomial t over k and ``p`` in k[t, 1/t], return q in + k[t, 1/t] and a bool b in {True, False} such that p - Dq in k if b is True, + or p - Dq does not have an elementary integral over k(t) if b is False. + """ + t1 = DE.t + dtt = DE.d.exquo(Poly(DE.t, DE.t)) + qa = Poly(0, DE.t) + qd = Poly(1, DE.t) + b = True + + if p.is_zero: + return(qa, qd, b) + + from sympy.integrals.rde import rischDE + + with DecrementLevel(DE): + for i in range(-p.degree(z), p.degree(t1) + 1): + if not i: + continue + elif i < 0: + # If you get AttributeError: 'NoneType' object has no attribute 'nth' + # then this should really not have expand=False + # But it shouldn't happen because p is already a Poly in t and z + a = p.as_poly(z, expand=False).nth(-i) + else: + # If you get AttributeError: 'NoneType' object has no attribute 'nth' + # then this should really not have expand=False + a = p.as_poly(t1, expand=False).nth(i) + + aa, ad = frac_in(a, DE.t, field=True) + aa, ad = aa.cancel(ad, include=True) + iDt = Poly(i, t1)*dtt + iDta, iDtd = frac_in(iDt, DE.t, field=True) + try: + va, vd = rischDE(iDta, iDtd, Poly(aa, DE.t), Poly(ad, DE.t), DE) + va, vd = frac_in((va, vd), t1, cancel=True) + except NonElementaryIntegralException: + b = False + else: + qa = qa*vd + va*Poly(t1**i)*qd + qd *= vd + + return (qa, qd, b) + + +def integrate_hyperexponential(a, d, DE, z=None, conds='piecewise'): + """ + Integration of hyperexponential functions. + + Explanation + =========== + + Given a hyperexponential monomial t over k and f in k(t), return g + elementary over k(t), i in k(t), and a bool b in {True, False} such that + i = f - Dg is in k if b is True or i = f - Dg does not have an elementary + integral over k(t) if b is False. + + This function returns a Basic expression for the first argument. If b is + True, the second argument is Basic expression in k to recursively integrate. + If b is False, the second argument is an unevaluated Integral, which has + been proven to be nonelementary. + """ + # XXX: a and d must be canceled, or this might return incorrect results + z = z or Dummy("z") + s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) + + g1, h, r = hermite_reduce(a, d, DE) + g2, b = residue_reduce(h[0], h[1], DE, z=z) + if not b: + i = cancel(a.as_expr()/d.as_expr() - (g1[1]*derivation(g1[0], DE) - + g1[0]*derivation(g1[1], DE)).as_expr()/(g1[1]**2).as_expr() - + residue_reduce_derivation(g2, DE, z)) + i = NonElementaryIntegral(cancel(i.subs(s)), DE.x) + return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z), i, b) + + # p should be a polynomial in t and 1/t, because Sirr == k[t, 1/t] + # h - Dg2 + r + p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, + DE, z) + r[0].as_expr()/r[1].as_expr()) + pp = as_poly_1t(p, DE.t, z) + + qa, qd, b = integrate_hyperexponential_polynomial(pp, DE, z) + + i = pp.nth(0, 0) + + ret = ((g1[0].as_expr()/g1[1].as_expr()).subs(s) \ + + residue_reduce_to_basic(g2, DE, z)) + + qas = qa.as_expr().subs(s) + qds = qd.as_expr().subs(s) + if conds == 'piecewise' and DE.x not in qds.free_symbols: + # We have to be careful if the exponent is S.Zero! + + # XXX: Does qd = 0 always necessarily correspond to the exponential + # equaling 1? + ret += Piecewise( + (qas/qds, Ne(qds, 0)), + (integrate((p - i).subs(DE.t, 1).subs(s), DE.x), True) + ) + else: + ret += qas/qds + + if not b: + i = p - (qd*derivation(qa, DE) - qa*derivation(qd, DE)).as_expr()/\ + (qd**2).as_expr() + i = NonElementaryIntegral(cancel(i).subs(s), DE.x) + return (ret, i, b) + + +def integrate_hypertangent_polynomial(p, DE): + """ + Integration of hypertangent polynomials. + + Explanation + =========== + + Given a differential field k such that sqrt(-1) is not in k, a + hypertangent monomial t over k, and p in k[t], return q in k[t] and + c in k such that p - Dq - c*D(t**2 + 1)/(t**1 + 1) is in k and p - + Dq does not have an elementary integral over k(t) if Dc != 0. + """ + # XXX: Make sure that sqrt(-1) is not in k. + q, r = polynomial_reduce(p, DE) + a = DE.d.exquo(Poly(DE.t**2 + 1, DE.t)) + c = Poly(r.nth(1)/(2*a.as_expr()), DE.t) + return (q, c) + + +def integrate_nonlinear_no_specials(a, d, DE, z=None): + """ + Integration of nonlinear monomials with no specials. + + Explanation + =========== + + Given a nonlinear monomial t over k such that Sirr ({p in k[t] | p is + special, monic, and irreducible}) is empty, and f in k(t), returns g + elementary over k(t) and a Boolean b in {True, False} such that f - Dg is + in k if b == True, or f - Dg does not have an elementary integral over k(t) + if b == False. + + This function is applicable to all nonlinear extensions, but in the case + where it returns b == False, it will only have proven that the integral of + f - Dg is nonelementary if Sirr is empty. + + This function returns a Basic expression. + """ + # TODO: Integral from k? + # TODO: split out nonelementary integral + # XXX: a and d must be canceled, or this might not return correct results + z = z or Dummy("z") + s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) + + g1, h, r = hermite_reduce(a, d, DE) + g2, b = residue_reduce(h[0], h[1], DE, z=z) + if not b: + return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z), b) + + # Because f has no specials, this should be a polynomial in t, or else + # there is a bug. + p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, + DE, z).as_expr() + r[0].as_expr()/r[1].as_expr()).as_poly(DE.t) + q1, q2 = polynomial_reduce(p, DE) + + if q2.expr.has(DE.t): + b = False + else: + b = True + + ret = (cancel(g1[0].as_expr()/g1[1].as_expr() + q1.as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z)) + return (ret, b) + + +class NonElementaryIntegral(Integral): + """ + Represents a nonelementary Integral. + + Explanation + =========== + + If the result of integrate() is an instance of this class, it is + guaranteed to be nonelementary. Note that integrate() by default will try + to find any closed-form solution, even in terms of special functions which + may themselves not be elementary. To make integrate() only give + elementary solutions, or, in the cases where it can prove the integral to + be nonelementary, instances of this class, use integrate(risch=True). + In this case, integrate() may raise NotImplementedError if it cannot make + such a determination. + + integrate() uses the deterministic Risch algorithm to integrate elementary + functions or prove that they have no elementary integral. In some cases, + this algorithm can split an integral into an elementary and nonelementary + part, so that the result of integrate will be the sum of an elementary + expression and a NonElementaryIntegral. + + Examples + ======== + + >>> from sympy import integrate, exp, log, Integral + >>> from sympy.abc import x + + >>> a = integrate(exp(-x**2), x, risch=True) + >>> print(a) + Integral(exp(-x**2), x) + >>> type(a) + + + >>> expr = (2*log(x)**2 - log(x) - x**2)/(log(x)**3 - x**2*log(x)) + >>> b = integrate(expr, x, risch=True) + >>> print(b) + -log(-x + log(x))/2 + log(x + log(x))/2 + Integral(1/log(x), x) + >>> type(b.atoms(Integral).pop()) + + + """ + # TODO: This is useful in and of itself, because isinstance(result, + # NonElementaryIntegral) will tell if the integral has been proven to be + # elementary. But should we do more? Perhaps a no-op .doit() if + # elementary=True? Or maybe some information on why the integral is + # nonelementary. + pass + + +def risch_integrate(f, x, extension=None, handle_first='log', + separate_integral=False, rewrite_complex=None, + conds='piecewise'): + r""" + The Risch Integration Algorithm. + + Explanation + =========== + + Only transcendental functions are supported. Currently, only exponentials + and logarithms are supported, but support for trigonometric functions is + forthcoming. + + If this function returns an unevaluated Integral in the result, it means + that it has proven that integral to be nonelementary. Any errors will + result in raising NotImplementedError. The unevaluated Integral will be + an instance of NonElementaryIntegral, a subclass of Integral. + + handle_first may be either 'exp' or 'log'. This changes the order in + which the extension is built, and may result in a different (but + equivalent) solution (for an example of this, see issue 5109). It is also + possible that the integral may be computed with one but not the other, + because not all cases have been implemented yet. It defaults to 'log' so + that the outer extension is exponential when possible, because more of the + exponential case has been implemented. + + If ``separate_integral`` is ``True``, the result is returned as a tuple (ans, i), + where the integral is ans + i, ans is elementary, and i is either a + NonElementaryIntegral or 0. This useful if you want to try further + integrating the NonElementaryIntegral part using other algorithms to + possibly get a solution in terms of special functions. It is False by + default. + + Examples + ======== + + >>> from sympy.integrals.risch import risch_integrate + >>> from sympy import exp, log, pprint + >>> from sympy.abc import x + + First, we try integrating exp(-x**2). Except for a constant factor of + 2/sqrt(pi), this is the famous error function. + + >>> pprint(risch_integrate(exp(-x**2), x)) + / + | + | 2 + | -x + | e dx + | + / + + The unevaluated Integral in the result means that risch_integrate() has + proven that exp(-x**2) does not have an elementary anti-derivative. + + In many cases, risch_integrate() can split out the elementary + anti-derivative part from the nonelementary anti-derivative part. + For example, + + >>> pprint(risch_integrate((2*log(x)**2 - log(x) - x**2)/(log(x)**3 - + ... x**2*log(x)), x)) + / + | + log(-x + log(x)) log(x + log(x)) | 1 + - ---------------- + --------------- + | ------ dx + 2 2 | log(x) + | + / + + This means that it has proven that the integral of 1/log(x) is + nonelementary. This function is also known as the logarithmic integral, + and is often denoted as Li(x). + + risch_integrate() currently only accepts purely transcendental functions + with exponentials and logarithms, though note that this can include + nested exponentials and logarithms, as well as exponentials with bases + other than E. + + >>> pprint(risch_integrate(exp(x)*exp(exp(x)), x)) + / x\ + \e / + e + >>> pprint(risch_integrate(exp(exp(x)), x)) + / + | + | / x\ + | \e / + | e dx + | + / + + >>> pprint(risch_integrate(x*x**x*log(x) + x**x + x*x**x, x)) + x + x*x + >>> pprint(risch_integrate(x**x, x)) + / + | + | x + | x dx + | + / + + >>> pprint(risch_integrate(-1/(x*log(x)*log(log(x))**2), x)) + 1 + ----------- + log(log(x)) + + """ + f = S(f) + + DE = extension or DifferentialExtension(f, x, handle_first=handle_first, + dummy=True, rewrite_complex=rewrite_complex) + fa, fd = DE.fa, DE.fd + + result = S.Zero + for case in reversed(DE.cases): + if not fa.expr.has(DE.t) and not fd.expr.has(DE.t) and not case == 'base': + DE.decrement_level() + fa, fd = frac_in((fa, fd), DE.t) + continue + + fa, fd = fa.cancel(fd, include=True) + if case == 'exp': + ans, i, b = integrate_hyperexponential(fa, fd, DE, conds=conds) + elif case == 'primitive': + ans, i, b = integrate_primitive(fa, fd, DE) + elif case == 'base': + # XXX: We can't call ratint() directly here because it doesn't + # handle polynomials correctly. + ans = integrate(fa.as_expr()/fd.as_expr(), DE.x, risch=False) + b = False + i = S.Zero + else: + raise NotImplementedError("Only exponential and logarithmic " + "extensions are currently supported.") + + result += ans + if b: + DE.decrement_level() + fa, fd = frac_in(i, DE.t) + else: + result = result.subs(DE.backsubs) + if not i.is_zero: + i = NonElementaryIntegral(i.function.subs(DE.backsubs),i.limits) + if not separate_integral: + result += i + return result + else: + + if isinstance(i, NonElementaryIntegral): + return (result, i) + else: + return (result, 0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/singularityfunctions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/singularityfunctions.py new file mode 100644 index 0000000000000000000000000000000000000000..3e33d0542c45b67b193f17e00c25837f3a82109a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/singularityfunctions.py @@ -0,0 +1,63 @@ +from sympy.functions import SingularityFunction, DiracDelta +from sympy.integrals import integrate + + +def singularityintegrate(f, x): + """ + This function handles the indefinite integrations of Singularity functions. + The ``integrate`` function calls this function internally whenever an + instance of SingularityFunction is passed as argument. + + Explanation + =========== + + The idea for integration is the following: + + - If we are dealing with a SingularityFunction expression, + i.e. ``SingularityFunction(x, a, n)``, we just return + ``SingularityFunction(x, a, n + 1)/(n + 1)`` if ``n >= 0`` and + ``SingularityFunction(x, a, n + 1)`` if ``n < 0``. + + - If the node is a multiplication or power node having a + SingularityFunction term we rewrite the whole expression in terms of + Heaviside and DiracDelta and then integrate the output. Lastly, we + rewrite the output of integration back in terms of SingularityFunction. + + - If none of the above case arises, we return None. + + Examples + ======== + + >>> from sympy.integrals.singularityfunctions import singularityintegrate + >>> from sympy import SingularityFunction, symbols, Function + >>> x, a, n, y = symbols('x a n y') + >>> f = Function('f') + >>> singularityintegrate(SingularityFunction(x, a, 3), x) + SingularityFunction(x, a, 4)/4 + >>> singularityintegrate(5*SingularityFunction(x, 5, -2), x) + 5*SingularityFunction(x, 5, -1) + >>> singularityintegrate(6*SingularityFunction(x, 5, -1), x) + 6*SingularityFunction(x, 5, 0) + >>> singularityintegrate(x*SingularityFunction(x, 0, -1), x) + 0 + >>> singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x) + f(1)*SingularityFunction(x, 1, 0) + + """ + + if not f.has(SingularityFunction): + return None + + if isinstance(f, SingularityFunction): + x, a, n = f.args + if n.is_positive or n.is_zero: + return SingularityFunction(x, a, n + 1)/(n + 1) + elif n in (-1, -2, -3, -4): + return SingularityFunction(x, a, n + 1) + + if f.is_Mul or f.is_Pow: + + expr = f.rewrite(DiracDelta) + expr = integrate(expr, x) + return expr.rewrite(SingularityFunction) + return None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/transforms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..19dbd990e4f0320e76707a1a2a8b1601fcd8a3df --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/transforms.py @@ -0,0 +1,1590 @@ +""" Integral Transforms """ +from functools import reduce, wraps +from itertools import repeat +from sympy.core import S, pi +from sympy.core.add import Add +from sympy.core.function import ( + AppliedUndef, count_ops, expand, expand_mul, Function) +from sympy.core.mul import Mul +from sympy.core.intfunc import igcd, ilcm +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Dummy +from sympy.core.traversal import postorder_traversal +from sympy.functions.combinatorial.factorials import factorial, rf +from sympy.functions.elementary.complexes import re, arg, Abs +from sympy.functions.elementary.exponential import exp, exp_polar +from sympy.functions.elementary.hyperbolic import cosh, coth, sinh, tanh +from sympy.functions.elementary.integers import ceiling +from sympy.functions.elementary.miscellaneous import Max, Min, sqrt +from sympy.functions.elementary.piecewise import piecewise_fold +from sympy.functions.elementary.trigonometric import cos, cot, sin, tan +from sympy.functions.special.bessel import besselj +from sympy.functions.special.delta_functions import Heaviside +from sympy.functions.special.gamma_functions import gamma +from sympy.functions.special.hyper import meijerg +from sympy.integrals import integrate, Integral +from sympy.integrals.meijerint import _dummy +from sympy.logic.boolalg import to_cnf, conjuncts, disjuncts, Or, And +from sympy.polys.polyroots import roots +from sympy.polys.polytools import factor, Poly +from sympy.polys.rootoftools import CRootOf +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import debug + + +########################################################################## +# Helpers / Utilities +########################################################################## + + +class IntegralTransformError(NotImplementedError): + """ + Exception raised in relation to problems computing transforms. + + Explanation + =========== + + This class is mostly used internally; if integrals cannot be computed + objects representing unevaluated transforms are usually returned. + + The hint ``needeval=True`` can be used to disable returning transform + objects, and instead raise this exception if an integral cannot be + computed. + """ + def __init__(self, transform, function, msg): + super().__init__( + "%s Transform could not be computed: %s." % (transform, msg)) + self.function = function + + +class IntegralTransform(Function): + """ + Base class for integral transforms. + + Explanation + =========== + + This class represents unevaluated transforms. + + To implement a concrete transform, derive from this class and implement + the ``_compute_transform(f, x, s, **hints)`` and ``_as_integral(f, x, s)`` + functions. If the transform cannot be computed, raise :obj:`IntegralTransformError`. + + Also set ``cls._name``. For instance, + + >>> from sympy import LaplaceTransform + >>> LaplaceTransform._name + 'Laplace' + + Implement ``self._collapse_extra`` if your function returns more than just a + number and possibly a convergence condition. + """ + + @property + def function(self): + """ The function to be transformed. """ + return self.args[0] + + @property + def function_variable(self): + """ The dependent variable of the function to be transformed. """ + return self.args[1] + + @property + def transform_variable(self): + """ The independent transform variable. """ + return self.args[2] + + @property + def free_symbols(self): + """ + This method returns the symbols that will exist when the transform + is evaluated. + """ + return self.function.free_symbols.union({self.transform_variable}) \ + - {self.function_variable} + + def _compute_transform(self, f, x, s, **hints): + raise NotImplementedError + + def _as_integral(self, f, x, s): + raise NotImplementedError + + def _collapse_extra(self, extra): + cond = And(*extra) + if cond == False: + raise IntegralTransformError(self.__class__.name, None, '') + return cond + + def _try_directly(self, **hints): + T = None + try_directly = not any(func.has(self.function_variable) + for func in self.function.atoms(AppliedUndef)) + if try_directly: + try: + T = self._compute_transform(self.function, + self.function_variable, self.transform_variable, **hints) + except IntegralTransformError: + debug('[IT _try ] Caught IntegralTransformError, returns None') + T = None + + fn = self.function + if not fn.is_Add: + fn = expand_mul(fn) + return fn, T + + def doit(self, **hints): + """ + Try to evaluate the transform in closed form. + + Explanation + =========== + + This general function handles linearity, but apart from that leaves + pretty much everything to _compute_transform. + + Standard hints are the following: + + - ``simplify``: whether or not to simplify the result + - ``noconds``: if True, do not return convergence conditions + - ``needeval``: if True, raise IntegralTransformError instead of + returning IntegralTransform objects + + The default values of these hints depend on the concrete transform, + usually the default is + ``(simplify, noconds, needeval) = (True, False, False)``. + """ + needeval = hints.pop('needeval', False) + simplify = hints.pop('simplify', True) + hints['simplify'] = simplify + + fn, T = self._try_directly(**hints) + + if T is not None: + return T + + if fn.is_Add: + hints['needeval'] = needeval + res = [self.__class__(*([x] + list(self.args[1:]))).doit(**hints) + for x in fn.args] + extra = [] + ress = [] + for x in res: + if not isinstance(x, tuple): + x = [x] + ress.append(x[0]) + if len(x) == 2: + # only a condition + extra.append(x[1]) + elif len(x) > 2: + # some region parameters and a condition (Mellin, Laplace) + extra += [x[1:]] + if simplify==True: + res = Add(*ress).simplify() + else: + res = Add(*ress) + if not extra: + return res + try: + extra = self._collapse_extra(extra) + if iterable(extra): + return (res,) + tuple(extra) + else: + return (res, extra) + except IntegralTransformError: + pass + + if needeval: + raise IntegralTransformError( + self.__class__._name, self.function, 'needeval') + + # TODO handle derivatives etc + + # pull out constant coefficients + coeff, rest = fn.as_coeff_mul(self.function_variable) + return coeff*self.__class__(*([Mul(*rest)] + list(self.args[1:]))) + + @property + def as_integral(self): + return self._as_integral(self.function, self.function_variable, + self.transform_variable) + + def _eval_rewrite_as_Integral(self, *args, **kwargs): + return self.as_integral + + +def _simplify(expr, doit): + if doit: + from sympy.simplify import simplify + from sympy.simplify.powsimp import powdenest + return simplify(powdenest(piecewise_fold(expr), polar=True)) + return expr + + +def _noconds_(default): + """ + This is a decorator generator for dropping convergence conditions. + + Explanation + =========== + + Suppose you define a function ``transform(*args)`` which returns a tuple of + the form ``(result, cond1, cond2, ...)``. + + Decorating it ``@_noconds_(default)`` will add a new keyword argument + ``noconds`` to it. If ``noconds=True``, the return value will be altered to + be only ``result``, whereas if ``noconds=False`` the return value will not + be altered. + + The default value of the ``noconds`` keyword will be ``default`` (i.e. the + argument of this function). + """ + def make_wrapper(func): + @wraps(func) + def wrapper(*args, noconds=default, **kwargs): + res = func(*args, **kwargs) + if noconds: + return res[0] + return res + return wrapper + return make_wrapper +_noconds = _noconds_(False) + + +########################################################################## +# Mellin Transform +########################################################################## + +def _default_integrator(f, x): + return integrate(f, (x, S.Zero, S.Infinity)) + + +@_noconds +def _mellin_transform(f, x, s_, integrator=_default_integrator, simplify=True): + """ Backend function to compute Mellin transforms. """ + # We use a fresh dummy, because assumptions on s might drop conditions on + # convergence of the integral. + s = _dummy('s', 'mellin-transform', f) + F = integrator(x**(s - 1) * f, x) + + if not F.has(Integral): + return _simplify(F.subs(s, s_), simplify), (S.NegativeInfinity, S.Infinity), S.true + + if not F.is_Piecewise: # XXX can this work if integration gives continuous result now? + raise IntegralTransformError('Mellin', f, 'could not compute integral') + + F, cond = F.args[0] + if F.has(Integral): + raise IntegralTransformError( + 'Mellin', f, 'integral in unexpected form') + + def process_conds(cond): + """ + Turn ``cond`` into a strip (a, b), and auxiliary conditions. + """ + from sympy.solvers.inequalities import _solve_inequality + a = S.NegativeInfinity + b = S.Infinity + aux = S.true + conds = conjuncts(to_cnf(cond)) + t = Dummy('t', real=True) + for c in conds: + a_ = S.Infinity + b_ = S.NegativeInfinity + aux_ = [] + for d in disjuncts(c): + d_ = d.replace( + re, lambda x: x.as_real_imag()[0]).subs(re(s), t) + if not d.is_Relational or \ + d.rel_op in ('==', '!=') \ + or d_.has(s) or not d_.has(t): + aux_ += [d] + continue + soln = _solve_inequality(d_, t) + if not soln.is_Relational or \ + soln.rel_op in ('==', '!='): + aux_ += [d] + continue + if soln.lts == t: + b_ = Max(soln.gts, b_) + else: + a_ = Min(soln.lts, a_) + if a_ is not S.Infinity and a_ != b: + a = Max(a_, a) + elif b_ is not S.NegativeInfinity and b_ != a: + b = Min(b_, b) + else: + aux = And(aux, Or(*aux_)) + return a, b, aux + + conds = [process_conds(c) for c in disjuncts(cond)] + conds = [x for x in conds if x[2] != False] + conds.sort(key=lambda x: (x[0] - x[1], count_ops(x[2]))) + + if not conds: + raise IntegralTransformError('Mellin', f, 'no convergence found') + + a, b, aux = conds[0] + return _simplify(F.subs(s, s_), simplify), (a, b), aux + + +class MellinTransform(IntegralTransform): + """ + Class representing unevaluated Mellin transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute Mellin transforms, see the :func:`mellin_transform` + docstring. + """ + + _name = 'Mellin' + + def _compute_transform(self, f, x, s, **hints): + return _mellin_transform(f, x, s, **hints) + + def _as_integral(self, f, x, s): + return Integral(f*x**(s - 1), (x, S.Zero, S.Infinity)) + + def _collapse_extra(self, extra): + a = [] + b = [] + cond = [] + for (sa, sb), c in extra: + a += [sa] + b += [sb] + cond += [c] + res = (Max(*a), Min(*b)), And(*cond) + if (res[0][0] >= res[0][1]) == True or res[1] == False: + raise IntegralTransformError( + 'Mellin', None, 'no combined convergence.') + return res + + +def mellin_transform(f, x, s, **hints): + r""" + Compute the Mellin transform `F(s)` of `f(x)`, + + .. math :: F(s) = \int_0^\infty x^{s-1} f(x) \mathrm{d}x. + + For all "sensible" functions, this converges absolutely in a strip + `a < \operatorname{Re}(s) < b`. + + Explanation + =========== + + The Mellin transform is related via change of variables to the Fourier + transform, and also to the (bilateral) Laplace transform. + + This function returns ``(F, (a, b), cond)`` + where ``F`` is the Mellin transform of ``f``, ``(a, b)`` is the fundamental strip + (as above), and ``cond`` are auxiliary convergence conditions. + + If the integral cannot be computed in closed form, this function returns + an unevaluated :class:`MellinTransform` object. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. If ``noconds=False``, + then only `F` will be returned (i.e. not ``cond``, and also not the strip + ``(a, b)``). + + Examples + ======== + + >>> from sympy import mellin_transform, exp + >>> from sympy.abc import x, s + >>> mellin_transform(exp(-x), x, s) + (gamma(s), (0, oo), True) + + See Also + ======== + + inverse_mellin_transform, laplace_transform, fourier_transform + hankel_transform, inverse_hankel_transform + """ + return MellinTransform(f, x, s).doit(**hints) + + +def _rewrite_sin(m_n, s, a, b): + """ + Re-write the sine function ``sin(m*s + n)`` as gamma functions, compatible + with the strip (a, b). + + Return ``(gamma1, gamma2, fac)`` so that ``f == fac/(gamma1 * gamma2)``. + + Examples + ======== + + >>> from sympy.integrals.transforms import _rewrite_sin + >>> from sympy import pi, S + >>> from sympy.abc import s + >>> _rewrite_sin((pi, 0), s, 0, 1) + (gamma(s), gamma(1 - s), pi) + >>> _rewrite_sin((pi, 0), s, 1, 0) + (gamma(s - 1), gamma(2 - s), -pi) + >>> _rewrite_sin((pi, 0), s, -1, 0) + (gamma(s + 1), gamma(-s), -pi) + >>> _rewrite_sin((pi, pi/2), s, S(1)/2, S(3)/2) + (gamma(s - 1/2), gamma(3/2 - s), -pi) + >>> _rewrite_sin((pi, pi), s, 0, 1) + (gamma(s), gamma(1 - s), -pi) + >>> _rewrite_sin((2*pi, 0), s, 0, S(1)/2) + (gamma(2*s), gamma(1 - 2*s), pi) + >>> _rewrite_sin((2*pi, 0), s, S(1)/2, 1) + (gamma(2*s - 1), gamma(2 - 2*s), -pi) + """ + # (This is a separate function because it is moderately complicated, + # and I want to doctest it.) + # We want to use pi/sin(pi*x) = gamma(x)*gamma(1-x). + # But there is one complication: the gamma functions determine the + # integration contour in the definition of the G-function. Usually + # it would not matter if this is slightly shifted, unless this way + # we create an undefined function! + # So we try to write this in such a way that the gammas are + # eminently on the right side of the strip. + m, n = m_n + + m = expand_mul(m/pi) + n = expand_mul(n/pi) + r = ceiling(-m*a - n.as_real_imag()[0]) # Don't use re(n), does not expand + return gamma(m*s + n + r), gamma(1 - n - r - m*s), (-1)**r*pi + + +class MellinTransformStripError(ValueError): + """ + Exception raised by _rewrite_gamma. Mainly for internal use. + """ + pass + + +def _rewrite_gamma(f, s, a, b): + """ + Try to rewrite the product f(s) as a product of gamma functions, + so that the inverse Mellin transform of f can be expressed as a meijer + G function. + + Explanation + =========== + + Return (an, ap), (bm, bq), arg, exp, fac such that + G((an, ap), (bm, bq), arg/z**exp)*fac is the inverse Mellin transform of f(s). + + Raises IntegralTransformError or MellinTransformStripError on failure. + + It is asserted that f has no poles in the fundamental strip designated by + (a, b). One of a and b is allowed to be None. The fundamental strip is + important, because it determines the inversion contour. + + This function can handle exponentials, linear factors, trigonometric + functions. + + This is a helper function for inverse_mellin_transform that will not + attempt any transformations on f. + + Examples + ======== + + >>> from sympy.integrals.transforms import _rewrite_gamma + >>> from sympy.abc import s + >>> from sympy import oo + >>> _rewrite_gamma(s*(s+3)*(s-1), s, -oo, oo) + (([], [-3, 0, 1]), ([-2, 1, 2], []), 1, 1, -1) + >>> _rewrite_gamma((s-1)**2, s, -oo, oo) + (([], [1, 1]), ([2, 2], []), 1, 1, 1) + + Importance of the fundamental strip: + + >>> _rewrite_gamma(1/s, s, 0, oo) + (([1], []), ([], [0]), 1, 1, 1) + >>> _rewrite_gamma(1/s, s, None, oo) + (([1], []), ([], [0]), 1, 1, 1) + >>> _rewrite_gamma(1/s, s, 0, None) + (([1], []), ([], [0]), 1, 1, 1) + >>> _rewrite_gamma(1/s, s, -oo, 0) + (([], [1]), ([0], []), 1, 1, -1) + >>> _rewrite_gamma(1/s, s, None, 0) + (([], [1]), ([0], []), 1, 1, -1) + >>> _rewrite_gamma(1/s, s, -oo, None) + (([], [1]), ([0], []), 1, 1, -1) + + >>> _rewrite_gamma(2**(-s+3), s, -oo, oo) + (([], []), ([], []), 1/2, 1, 8) + """ + # Our strategy will be as follows: + # 1) Guess a constant c such that the inversion integral should be + # performed wrt s'=c*s (instead of plain s). Write s for s'. + # 2) Process all factors, rewrite them independently as gamma functions in + # argument s, or exponentials of s. + # 3) Try to transform all gamma functions s.t. they have argument + # a+s or a-s. + # 4) Check that the resulting G function parameters are valid. + # 5) Combine all the exponentials. + + a_, b_ = S([a, b]) + + def left(c, is_numer): + """ + Decide whether pole at c lies to the left of the fundamental strip. + """ + # heuristically, this is the best chance for us to solve the inequalities + c = expand(re(c)) + if a_ is None and b_ is S.Infinity: + return True + if a_ is None: + return c < b_ + if b_ is None: + return c <= a_ + if (c >= b_) == True: + return False + if (c <= a_) == True: + return True + if is_numer: + return None + if a_.free_symbols or b_.free_symbols or c.free_symbols: + return None # XXX + #raise IntegralTransformError('Inverse Mellin', f, + # 'Could not determine position of singularity %s' + # ' relative to fundamental strip' % c) + raise MellinTransformStripError('Pole inside critical strip?') + + # 1) + s_multipliers = [] + for g in f.atoms(gamma): + if not g.has(s): + continue + arg = g.args[0] + if arg.is_Add: + arg = arg.as_independent(s)[1] + coeff, _ = arg.as_coeff_mul(s) + s_multipliers += [coeff] + for g in f.atoms(sin, cos, tan, cot): + if not g.has(s): + continue + arg = g.args[0] + if arg.is_Add: + arg = arg.as_independent(s)[1] + coeff, _ = arg.as_coeff_mul(s) + s_multipliers += [coeff/pi] + s_multipliers = [Abs(x) if x.is_extended_real else x for x in s_multipliers] + common_coefficient = S.One + for x in s_multipliers: + if not x.is_Rational: + common_coefficient = x + break + s_multipliers = [x/common_coefficient for x in s_multipliers] + if not (all(x.is_Rational for x in s_multipliers) and + common_coefficient.is_extended_real): + raise IntegralTransformError("Gamma", None, "Nonrational multiplier") + s_multiplier = common_coefficient/reduce(ilcm, [S(x.q) + for x in s_multipliers], S.One) + if s_multiplier == common_coefficient: + if len(s_multipliers) == 0: + s_multiplier = common_coefficient + else: + s_multiplier = common_coefficient \ + *reduce(igcd, [S(x.p) for x in s_multipliers]) + + f = f.subs(s, s/s_multiplier) + fac = S.One/s_multiplier + exponent = S.One/s_multiplier + if a_ is not None: + a_ *= s_multiplier + if b_ is not None: + b_ *= s_multiplier + + # 2) + numer, denom = f.as_numer_denom() + numer = Mul.make_args(numer) + denom = Mul.make_args(denom) + args = list(zip(numer, repeat(True))) + list(zip(denom, repeat(False))) + + facs = [] + dfacs = [] + # *_gammas will contain pairs (a, c) representing Gamma(a*s + c) + numer_gammas = [] + denom_gammas = [] + # exponentials will contain bases for exponentials of s + exponentials = [] + + def exception(fact): + return IntegralTransformError("Inverse Mellin", f, "Unrecognised form '%s'." % fact) + while args: + fact, is_numer = args.pop() + if is_numer: + ugammas, lgammas = numer_gammas, denom_gammas + ufacs = facs + else: + ugammas, lgammas = denom_gammas, numer_gammas + ufacs = dfacs + + def linear_arg(arg): + """ Test if arg is of form a*s+b, raise exception if not. """ + if not arg.is_polynomial(s): + raise exception(fact) + p = Poly(arg, s) + if p.degree() != 1: + raise exception(fact) + return p.all_coeffs() + + # constants + if not fact.has(s): + ufacs += [fact] + # exponentials + elif fact.is_Pow or isinstance(fact, exp): + if fact.is_Pow: + base = fact.base + exp_ = fact.exp + else: + base = exp_polar(1) + exp_ = fact.exp + if exp_.is_Integer: + cond = is_numer + if exp_ < 0: + cond = not cond + args += [(base, cond)]*Abs(exp_) + continue + elif not base.has(s): + a, b = linear_arg(exp_) + if not is_numer: + base = 1/base + exponentials += [base**a] + facs += [base**b] + else: + raise exception(fact) + # linear factors + elif fact.is_polynomial(s): + p = Poly(fact, s) + if p.degree() != 1: + # We completely factor the poly. For this we need the roots. + # Now roots() only works in some cases (low degree), and CRootOf + # only works without parameters. So try both... + coeff = p.LT()[1] + rs = roots(p, s) + if len(rs) != p.degree(): + rs = CRootOf.all_roots(p) + ufacs += [coeff] + args += [(s - c, is_numer) for c in rs] + continue + a, c = p.all_coeffs() + ufacs += [a] + c /= -a + # Now need to convert s - c + if left(c, is_numer): + ugammas += [(S.One, -c + 1)] + lgammas += [(S.One, -c)] + else: + ufacs += [-1] + ugammas += [(S.NegativeOne, c + 1)] + lgammas += [(S.NegativeOne, c)] + elif isinstance(fact, gamma): + a, b = linear_arg(fact.args[0]) + if is_numer: + if (a > 0 and (left(-b/a, is_numer) == False)) or \ + (a < 0 and (left(-b/a, is_numer) == True)): + raise NotImplementedError( + 'Gammas partially over the strip.') + ugammas += [(a, b)] + elif isinstance(fact, sin): + # We try to re-write all trigs as gammas. This is not in + # general the best strategy, since sometimes this is impossible, + # but rewriting as exponentials would work. However trig functions + # in inverse mellin transforms usually all come from simplifying + # gamma terms, so this should work. + a = fact.args[0] + if is_numer: + # No problem with the poles. + gamma1, gamma2, fac_ = gamma(a/pi), gamma(1 - a/pi), pi + else: + gamma1, gamma2, fac_ = _rewrite_sin(linear_arg(a), s, a_, b_) + args += [(gamma1, not is_numer), (gamma2, not is_numer)] + ufacs += [fac_] + elif isinstance(fact, tan): + a = fact.args[0] + args += [(sin(a, evaluate=False), is_numer), + (sin(pi/2 - a, evaluate=False), not is_numer)] + elif isinstance(fact, cos): + a = fact.args[0] + args += [(sin(pi/2 - a, evaluate=False), is_numer)] + elif isinstance(fact, cot): + a = fact.args[0] + args += [(sin(pi/2 - a, evaluate=False), is_numer), + (sin(a, evaluate=False), not is_numer)] + else: + raise exception(fact) + + fac *= Mul(*facs)/Mul(*dfacs) + + # 3) + an, ap, bm, bq = [], [], [], [] + for gammas, plus, minus, is_numer in [(numer_gammas, an, bm, True), + (denom_gammas, bq, ap, False)]: + while gammas: + a, c = gammas.pop() + if a != -1 and a != +1: + # We use the gamma function multiplication theorem. + p = Abs(S(a)) + newa = a/p + newc = c/p + if not a.is_Integer: + raise TypeError("a is not an integer") + for k in range(p): + gammas += [(newa, newc + k/p)] + if is_numer: + fac *= (2*pi)**((1 - p)/2) * p**(c - S.Half) + exponentials += [p**a] + else: + fac /= (2*pi)**((1 - p)/2) * p**(c - S.Half) + exponentials += [p**(-a)] + continue + if a == +1: + plus.append(1 - c) + else: + minus.append(c) + + # 4) + # TODO + + # 5) + arg = Mul(*exponentials) + + # for testability, sort the arguments + an.sort(key=default_sort_key) + ap.sort(key=default_sort_key) + bm.sort(key=default_sort_key) + bq.sort(key=default_sort_key) + + return (an, ap), (bm, bq), arg, exponent, fac + + +@_noconds_(True) +def _inverse_mellin_transform(F, s, x_, strip, as_meijerg=False): + """ A helper for the real inverse_mellin_transform function, this one here + assumes x to be real and positive. """ + x = _dummy('t', 'inverse-mellin-transform', F, positive=True) + # Actually, we won't try integration at all. Instead we use the definition + # of the Meijer G function as a fairly general inverse mellin transform. + F = F.rewrite(gamma) + for g in [factor(F), expand_mul(F), expand(F)]: + if g.is_Add: + # do all terms separately + ress = [_inverse_mellin_transform(G, s, x, strip, as_meijerg, + noconds=False) + for G in g.args] + conds = [p[1] for p in ress] + ress = [p[0] for p in ress] + res = Add(*ress) + if not as_meijerg: + res = factor(res, gens=res.atoms(Heaviside)) + return res.subs(x, x_), And(*conds) + + try: + a, b, C, e, fac = _rewrite_gamma(g, s, strip[0], strip[1]) + except IntegralTransformError: + continue + try: + G = meijerg(a, b, C/x**e) + except ValueError: + continue + if as_meijerg: + h = G + else: + try: + from sympy.simplify import hyperexpand + h = hyperexpand(G) + except NotImplementedError: + raise IntegralTransformError( + 'Inverse Mellin', F, 'Could not calculate integral') + + if h.is_Piecewise and len(h.args) == 3: + # XXX we break modularity here! + h = Heaviside(x - Abs(C))*h.args[0].args[0] \ + + Heaviside(Abs(C) - x)*h.args[1].args[0] + # We must ensure that the integral along the line we want converges, + # and return that value. + # See [L], 5.2 + cond = [Abs(arg(G.argument)) < G.delta*pi] + # Note: we allow ">=" here, this corresponds to convergence if we let + # limits go to oo symmetrically. ">" corresponds to absolute convergence. + cond += [And(Or(len(G.ap) != len(G.bq), 0 >= re(G.nu) + 1), + Abs(arg(G.argument)) == G.delta*pi)] + cond = Or(*cond) + if cond == False: + raise IntegralTransformError( + 'Inverse Mellin', F, 'does not converge') + return (h*fac).subs(x, x_), cond + + raise IntegralTransformError('Inverse Mellin', F, '') + +_allowed = None + + +class InverseMellinTransform(IntegralTransform): + """ + Class representing unevaluated inverse Mellin transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute inverse Mellin transforms, see the + :func:`inverse_mellin_transform` docstring. + """ + + _name = 'Inverse Mellin' + _none_sentinel = Dummy('None') + _c = Dummy('c') + + def __new__(cls, F, s, x, a, b, **opts): + if a is None: + a = InverseMellinTransform._none_sentinel + if b is None: + b = InverseMellinTransform._none_sentinel + return IntegralTransform.__new__(cls, F, s, x, a, b, **opts) + + @property + def fundamental_strip(self): + a, b = self.args[3], self.args[4] + if a is InverseMellinTransform._none_sentinel: + a = None + if b is InverseMellinTransform._none_sentinel: + b = None + return a, b + + def _compute_transform(self, F, s, x, **hints): + # IntegralTransform's doit will cause this hint to exist, but + # InverseMellinTransform should ignore it + hints.pop('simplify', True) + global _allowed + if _allowed is None: + _allowed = { + exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, coth, + factorial, rf} + for f in postorder_traversal(F): + if f.is_Function and f.has(s) and f.func not in _allowed: + raise IntegralTransformError('Inverse Mellin', F, + 'Component %s not recognised.' % f) + strip = self.fundamental_strip + return _inverse_mellin_transform(F, s, x, strip, **hints) + + def _as_integral(self, F, s, x): + c = self.__class__._c + return Integral(F*x**(-s), (s, c - S.ImaginaryUnit*S.Infinity, c + + S.ImaginaryUnit*S.Infinity))/(2*S.Pi*S.ImaginaryUnit) + + +def inverse_mellin_transform(F, s, x, strip, **hints): + r""" + Compute the inverse Mellin transform of `F(s)` over the fundamental + strip given by ``strip=(a, b)``. + + Explanation + =========== + + This can be defined as + + .. math:: f(x) = \frac{1}{2\pi i} \int_{c - i\infty}^{c + i\infty} x^{-s} F(s) \mathrm{d}s, + + for any `c` in the fundamental strip. Under certain regularity + conditions on `F` and/or `f`, + this recovers `f` from its Mellin transform `F` + (and vice versa), for positive real `x`. + + One of `a` or `b` may be passed as ``None``; a suitable `c` will be + inferred. + + If the integral cannot be computed in closed form, this function returns + an unevaluated :class:`InverseMellinTransform` object. + + Note that this function will assume x to be positive and real, regardless + of the SymPy assumptions! + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + + Examples + ======== + + >>> from sympy import inverse_mellin_transform, oo, gamma + >>> from sympy.abc import x, s + >>> inverse_mellin_transform(gamma(s), s, x, (0, oo)) + exp(-x) + + The fundamental strip matters: + + >>> f = 1/(s**2 - 1) + >>> inverse_mellin_transform(f, s, x, (-oo, -1)) + x*(1 - 1/x**2)*Heaviside(x - 1)/2 + >>> inverse_mellin_transform(f, s, x, (-1, 1)) + -x*Heaviside(1 - x)/2 - Heaviside(x - 1)/(2*x) + >>> inverse_mellin_transform(f, s, x, (1, oo)) + (1/2 - x**2/2)*Heaviside(1 - x)/x + + See Also + ======== + + mellin_transform + hankel_transform, inverse_hankel_transform + """ + return InverseMellinTransform(F, s, x, strip[0], strip[1]).doit(**hints) + + +########################################################################## +# Fourier Transform +########################################################################## + +@_noconds_(True) +def _fourier_transform(f, x, k, a, b, name, simplify=True): + r""" + Compute a general Fourier-type transform + + .. math:: + + F(k) = a \int_{-\infty}^{\infty} e^{bixk} f(x)\, dx. + + For suitable choice of *a* and *b*, this reduces to the standard Fourier + and inverse Fourier transforms. + """ + F = integrate(a*f*exp(b*S.ImaginaryUnit*x*k), (x, S.NegativeInfinity, S.Infinity)) + + if not F.has(Integral): + return _simplify(F, simplify), S.true + + integral_f = integrate(f, (x, S.NegativeInfinity, S.Infinity)) + if integral_f in (S.NegativeInfinity, S.Infinity, S.NaN) or integral_f.has(Integral): + raise IntegralTransformError(name, f, 'function not integrable on real axis') + + if not F.is_Piecewise: + raise IntegralTransformError(name, f, 'could not compute integral') + + F, cond = F.args[0] + if F.has(Integral): + raise IntegralTransformError(name, f, 'integral in unexpected form') + + return _simplify(F, simplify), cond + + +class FourierTypeTransform(IntegralTransform): + """ Base class for Fourier transforms.""" + + def a(self): + raise NotImplementedError( + "Class %s must implement a(self) but does not" % self.__class__) + + def b(self): + raise NotImplementedError( + "Class %s must implement b(self) but does not" % self.__class__) + + def _compute_transform(self, f, x, k, **hints): + return _fourier_transform(f, x, k, + self.a(), self.b(), + self.__class__._name, **hints) + + def _as_integral(self, f, x, k): + a = self.a() + b = self.b() + return Integral(a*f*exp(b*S.ImaginaryUnit*x*k), (x, S.NegativeInfinity, S.Infinity)) + + +class FourierTransform(FourierTypeTransform): + """ + Class representing unevaluated Fourier transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute Fourier transforms, see the :func:`fourier_transform` + docstring. + """ + + _name = 'Fourier' + + def a(self): + return 1 + + def b(self): + return -2*S.Pi + + +def fourier_transform(f, x, k, **hints): + r""" + Compute the unitary, ordinary-frequency Fourier transform of ``f``, defined + as + + .. math:: F(k) = \int_{-\infty}^\infty f(x) e^{-2\pi i x k} \mathrm{d} x. + + Explanation + =========== + + If the transform cannot be computed in closed form, this + function returns an unevaluated :class:`FourierTransform` object. + + For other Fourier transform conventions, see the function + :func:`sympy.integrals.transforms._fourier_transform`. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + Note that for this transform, by default ``noconds=True``. + + Examples + ======== + + >>> from sympy import fourier_transform, exp + >>> from sympy.abc import x, k + >>> fourier_transform(exp(-x**2), x, k) + sqrt(pi)*exp(-pi**2*k**2) + >>> fourier_transform(exp(-x**2), x, k, noconds=False) + (sqrt(pi)*exp(-pi**2*k**2), True) + + See Also + ======== + + inverse_fourier_transform + sine_transform, inverse_sine_transform + cosine_transform, inverse_cosine_transform + hankel_transform, inverse_hankel_transform + mellin_transform, laplace_transform + """ + return FourierTransform(f, x, k).doit(**hints) + + +class InverseFourierTransform(FourierTypeTransform): + """ + Class representing unevaluated inverse Fourier transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute inverse Fourier transforms, see the + :func:`inverse_fourier_transform` docstring. + """ + + _name = 'Inverse Fourier' + + def a(self): + return 1 + + def b(self): + return 2*S.Pi + + +def inverse_fourier_transform(F, k, x, **hints): + r""" + Compute the unitary, ordinary-frequency inverse Fourier transform of `F`, + defined as + + .. math:: f(x) = \int_{-\infty}^\infty F(k) e^{2\pi i x k} \mathrm{d} k. + + Explanation + =========== + + If the transform cannot be computed in closed form, this + function returns an unevaluated :class:`InverseFourierTransform` object. + + For other Fourier transform conventions, see the function + :func:`sympy.integrals.transforms._fourier_transform`. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + Note that for this transform, by default ``noconds=True``. + + Examples + ======== + + >>> from sympy import inverse_fourier_transform, exp, sqrt, pi + >>> from sympy.abc import x, k + >>> inverse_fourier_transform(sqrt(pi)*exp(-(pi*k)**2), k, x) + exp(-x**2) + >>> inverse_fourier_transform(sqrt(pi)*exp(-(pi*k)**2), k, x, noconds=False) + (exp(-x**2), True) + + See Also + ======== + + fourier_transform + sine_transform, inverse_sine_transform + cosine_transform, inverse_cosine_transform + hankel_transform, inverse_hankel_transform + mellin_transform, laplace_transform + """ + return InverseFourierTransform(F, k, x).doit(**hints) + + +########################################################################## +# Fourier Sine and Cosine Transform +########################################################################## + +@_noconds_(True) +def _sine_cosine_transform(f, x, k, a, b, K, name, simplify=True): + """ + Compute a general sine or cosine-type transform + F(k) = a int_0^oo b*sin(x*k) f(x) dx. + F(k) = a int_0^oo b*cos(x*k) f(x) dx. + + For suitable choice of a and b, this reduces to the standard sine/cosine + and inverse sine/cosine transforms. + """ + F = integrate(a*f*K(b*x*k), (x, S.Zero, S.Infinity)) + + if not F.has(Integral): + return _simplify(F, simplify), S.true + + if not F.is_Piecewise: + raise IntegralTransformError(name, f, 'could not compute integral') + + F, cond = F.args[0] + if F.has(Integral): + raise IntegralTransformError(name, f, 'integral in unexpected form') + + return _simplify(F, simplify), cond + + +class SineCosineTypeTransform(IntegralTransform): + """ + Base class for sine and cosine transforms. + Specify cls._kern. + """ + + def a(self): + raise NotImplementedError( + "Class %s must implement a(self) but does not" % self.__class__) + + def b(self): + raise NotImplementedError( + "Class %s must implement b(self) but does not" % self.__class__) + + + def _compute_transform(self, f, x, k, **hints): + return _sine_cosine_transform(f, x, k, + self.a(), self.b(), + self.__class__._kern, + self.__class__._name, **hints) + + def _as_integral(self, f, x, k): + a = self.a() + b = self.b() + K = self.__class__._kern + return Integral(a*f*K(b*x*k), (x, S.Zero, S.Infinity)) + + +class SineTransform(SineCosineTypeTransform): + """ + Class representing unevaluated sine transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute sine transforms, see the :func:`sine_transform` + docstring. + """ + + _name = 'Sine' + _kern = sin + + def a(self): + return sqrt(2)/sqrt(pi) + + def b(self): + return S.One + + +def sine_transform(f, x, k, **hints): + r""" + Compute the unitary, ordinary-frequency sine transform of `f`, defined + as + + .. math:: F(k) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty f(x) \sin(2\pi x k) \mathrm{d} x. + + Explanation + =========== + + If the transform cannot be computed in closed form, this + function returns an unevaluated :class:`SineTransform` object. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + Note that for this transform, by default ``noconds=True``. + + Examples + ======== + + >>> from sympy import sine_transform, exp + >>> from sympy.abc import x, k, a + >>> sine_transform(x*exp(-a*x**2), x, k) + sqrt(2)*k*exp(-k**2/(4*a))/(4*a**(3/2)) + >>> sine_transform(x**(-a), x, k) + 2**(1/2 - a)*k**(a - 1)*gamma(1 - a/2)/gamma(a/2 + 1/2) + + See Also + ======== + + fourier_transform, inverse_fourier_transform + inverse_sine_transform + cosine_transform, inverse_cosine_transform + hankel_transform, inverse_hankel_transform + mellin_transform, laplace_transform + """ + return SineTransform(f, x, k).doit(**hints) + + +class InverseSineTransform(SineCosineTypeTransform): + """ + Class representing unevaluated inverse sine transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute inverse sine transforms, see the + :func:`inverse_sine_transform` docstring. + """ + + _name = 'Inverse Sine' + _kern = sin + + def a(self): + return sqrt(2)/sqrt(pi) + + def b(self): + return S.One + + +def inverse_sine_transform(F, k, x, **hints): + r""" + Compute the unitary, ordinary-frequency inverse sine transform of `F`, + defined as + + .. math:: f(x) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty F(k) \sin(2\pi x k) \mathrm{d} k. + + Explanation + =========== + + If the transform cannot be computed in closed form, this + function returns an unevaluated :class:`InverseSineTransform` object. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + Note that for this transform, by default ``noconds=True``. + + Examples + ======== + + >>> from sympy import inverse_sine_transform, exp, sqrt, gamma + >>> from sympy.abc import x, k, a + >>> inverse_sine_transform(2**((1-2*a)/2)*k**(a - 1)* + ... gamma(-a/2 + 1)/gamma((a+1)/2), k, x) + x**(-a) + >>> inverse_sine_transform(sqrt(2)*k*exp(-k**2/(4*a))/(4*sqrt(a)**3), k, x) + x*exp(-a*x**2) + + See Also + ======== + + fourier_transform, inverse_fourier_transform + sine_transform + cosine_transform, inverse_cosine_transform + hankel_transform, inverse_hankel_transform + mellin_transform, laplace_transform + """ + return InverseSineTransform(F, k, x).doit(**hints) + + +class CosineTransform(SineCosineTypeTransform): + """ + Class representing unevaluated cosine transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute cosine transforms, see the :func:`cosine_transform` + docstring. + """ + + _name = 'Cosine' + _kern = cos + + def a(self): + return sqrt(2)/sqrt(pi) + + def b(self): + return S.One + + +def cosine_transform(f, x, k, **hints): + r""" + Compute the unitary, ordinary-frequency cosine transform of `f`, defined + as + + .. math:: F(k) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty f(x) \cos(2\pi x k) \mathrm{d} x. + + Explanation + =========== + + If the transform cannot be computed in closed form, this + function returns an unevaluated :class:`CosineTransform` object. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + Note that for this transform, by default ``noconds=True``. + + Examples + ======== + + >>> from sympy import cosine_transform, exp, sqrt, cos + >>> from sympy.abc import x, k, a + >>> cosine_transform(exp(-a*x), x, k) + sqrt(2)*a/(sqrt(pi)*(a**2 + k**2)) + >>> cosine_transform(exp(-a*sqrt(x))*cos(a*sqrt(x)), x, k) + a*exp(-a**2/(2*k))/(2*k**(3/2)) + + See Also + ======== + + fourier_transform, inverse_fourier_transform, + sine_transform, inverse_sine_transform + inverse_cosine_transform + hankel_transform, inverse_hankel_transform + mellin_transform, laplace_transform + """ + return CosineTransform(f, x, k).doit(**hints) + + +class InverseCosineTransform(SineCosineTypeTransform): + """ + Class representing unevaluated inverse cosine transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute inverse cosine transforms, see the + :func:`inverse_cosine_transform` docstring. + """ + + _name = 'Inverse Cosine' + _kern = cos + + def a(self): + return sqrt(2)/sqrt(pi) + + def b(self): + return S.One + + +def inverse_cosine_transform(F, k, x, **hints): + r""" + Compute the unitary, ordinary-frequency inverse cosine transform of `F`, + defined as + + .. math:: f(x) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty F(k) \cos(2\pi x k) \mathrm{d} k. + + Explanation + =========== + + If the transform cannot be computed in closed form, this + function returns an unevaluated :class:`InverseCosineTransform` object. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + Note that for this transform, by default ``noconds=True``. + + Examples + ======== + + >>> from sympy import inverse_cosine_transform, sqrt, pi + >>> from sympy.abc import x, k, a + >>> inverse_cosine_transform(sqrt(2)*a/(sqrt(pi)*(a**2 + k**2)), k, x) + exp(-a*x) + >>> inverse_cosine_transform(1/sqrt(k), k, x) + 1/sqrt(x) + + See Also + ======== + + fourier_transform, inverse_fourier_transform, + sine_transform, inverse_sine_transform + cosine_transform + hankel_transform, inverse_hankel_transform + mellin_transform, laplace_transform + """ + return InverseCosineTransform(F, k, x).doit(**hints) + + +########################################################################## +# Hankel Transform +########################################################################## + +@_noconds_(True) +def _hankel_transform(f, r, k, nu, name, simplify=True): + r""" + Compute a general Hankel transform + + .. math:: F_\nu(k) = \int_{0}^\infty f(r) J_\nu(k r) r \mathrm{d} r. + """ + F = integrate(f*besselj(nu, k*r)*r, (r, S.Zero, S.Infinity)) + + if not F.has(Integral): + return _simplify(F, simplify), S.true + + if not F.is_Piecewise: + raise IntegralTransformError(name, f, 'could not compute integral') + + F, cond = F.args[0] + if F.has(Integral): + raise IntegralTransformError(name, f, 'integral in unexpected form') + + return _simplify(F, simplify), cond + + +class HankelTypeTransform(IntegralTransform): + """ + Base class for Hankel transforms. + """ + + def doit(self, **hints): + return self._compute_transform(self.function, + self.function_variable, + self.transform_variable, + self.args[3], + **hints) + + def _compute_transform(self, f, r, k, nu, **hints): + return _hankel_transform(f, r, k, nu, self._name, **hints) + + def _as_integral(self, f, r, k, nu): + return Integral(f*besselj(nu, k*r)*r, (r, S.Zero, S.Infinity)) + + @property + def as_integral(self): + return self._as_integral(self.function, + self.function_variable, + self.transform_variable, + self.args[3]) + + +class HankelTransform(HankelTypeTransform): + """ + Class representing unevaluated Hankel transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute Hankel transforms, see the :func:`hankel_transform` + docstring. + """ + + _name = 'Hankel' + + +def hankel_transform(f, r, k, nu, **hints): + r""" + Compute the Hankel transform of `f`, defined as + + .. math:: F_\nu(k) = \int_{0}^\infty f(r) J_\nu(k r) r \mathrm{d} r. + + Explanation + =========== + + If the transform cannot be computed in closed form, this + function returns an unevaluated :class:`HankelTransform` object. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + Note that for this transform, by default ``noconds=True``. + + Examples + ======== + + >>> from sympy import hankel_transform, inverse_hankel_transform + >>> from sympy import exp + >>> from sympy.abc import r, k, m, nu, a + + >>> ht = hankel_transform(1/r**m, r, k, nu) + >>> ht + 2*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/(2**m*gamma(m/2 + nu/2)) + + >>> inverse_hankel_transform(ht, k, r, nu) + r**(-m) + + >>> ht = hankel_transform(exp(-a*r), r, k, 0) + >>> ht + a/(k**3*(a**2/k**2 + 1)**(3/2)) + + >>> inverse_hankel_transform(ht, k, r, 0) + exp(-a*r) + + See Also + ======== + + fourier_transform, inverse_fourier_transform + sine_transform, inverse_sine_transform + cosine_transform, inverse_cosine_transform + inverse_hankel_transform + mellin_transform, laplace_transform + """ + return HankelTransform(f, r, k, nu).doit(**hints) + + +class InverseHankelTransform(HankelTypeTransform): + """ + Class representing unevaluated inverse Hankel transforms. + + For usage of this class, see the :class:`IntegralTransform` docstring. + + For how to compute inverse Hankel transforms, see the + :func:`inverse_hankel_transform` docstring. + """ + + _name = 'Inverse Hankel' + + +def inverse_hankel_transform(F, k, r, nu, **hints): + r""" + Compute the inverse Hankel transform of `F` defined as + + .. math:: f(r) = \int_{0}^\infty F_\nu(k) J_\nu(k r) k \mathrm{d} k. + + Explanation + =========== + + If the transform cannot be computed in closed form, this + function returns an unevaluated :class:`InverseHankelTransform` object. + + For a description of possible hints, refer to the docstring of + :func:`sympy.integrals.transforms.IntegralTransform.doit`. + Note that for this transform, by default ``noconds=True``. + + Examples + ======== + + >>> from sympy import hankel_transform, inverse_hankel_transform + >>> from sympy import exp + >>> from sympy.abc import r, k, m, nu, a + + >>> ht = hankel_transform(1/r**m, r, k, nu) + >>> ht + 2*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/(2**m*gamma(m/2 + nu/2)) + + >>> inverse_hankel_transform(ht, k, r, nu) + r**(-m) + + >>> ht = hankel_transform(exp(-a*r), r, k, 0) + >>> ht + a/(k**3*(a**2/k**2 + 1)**(3/2)) + + >>> inverse_hankel_transform(ht, k, r, 0) + exp(-a*r) + + See Also + ======== + + fourier_transform, inverse_fourier_transform + sine_transform, inverse_sine_transform + cosine_transform, inverse_cosine_transform + hankel_transform + mellin_transform, laplace_transform + """ + return InverseHankelTransform(F, k, r, nu).doit(**hints) + + +########################################################################## +# Laplace Transform +########################################################################## + +# Stub classes and functions that used to be here +import sympy.integrals.laplace as _laplace + +LaplaceTransform = _laplace.LaplaceTransform +laplace_transform = _laplace.laplace_transform +laplace_correspondence = _laplace.laplace_correspondence +laplace_initial_conds = _laplace.laplace_initial_conds +InverseLaplaceTransform = _laplace.InverseLaplaceTransform +inverse_laplace_transform = _laplace.inverse_laplace_transform diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/trigonometry.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/trigonometry.py new file mode 100644 index 0000000000000000000000000000000000000000..dd6389bcc79f28ed6c255546685da1a0e061c327 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/trigonometry.py @@ -0,0 +1,335 @@ +from sympy.core import cacheit, Dummy, Ne, Integer, Rational, S, Wild +from sympy.functions import binomial, sin, cos, Piecewise, Abs +from .integrals import integrate + +# TODO sin(a*x)*cos(b*x) -> sin((a+b)x) + sin((a-b)x) ? + +# creating, each time, Wild's and sin/cos/Mul is expensive. Also, our match & +# subs are very slow when not cached, and if we create Wild each time, we +# effectively block caching. +# +# so we cache the pattern + +# need to use a function instead of lamda since hash of lambda changes on +# each call to _pat_sincos +def _integer_instance(n): + return isinstance(n, Integer) + +@cacheit +def _pat_sincos(x): + a = Wild('a', exclude=[x]) + n, m = [Wild(s, exclude=[x], properties=[_integer_instance]) + for s in 'nm'] + pat = sin(a*x)**n * cos(a*x)**m + return pat, a, n, m + +_u = Dummy('u') + + +def trigintegrate(f, x, conds='piecewise'): + """ + Integrate f = Mul(trig) over x. + + Examples + ======== + + >>> from sympy import sin, cos, tan, sec + >>> from sympy.integrals.trigonometry import trigintegrate + >>> from sympy.abc import x + + >>> trigintegrate(sin(x)*cos(x), x) + sin(x)**2/2 + + >>> trigintegrate(sin(x)**2, x) + x/2 - sin(x)*cos(x)/2 + + >>> trigintegrate(tan(x)*sec(x), x) + 1/cos(x) + + >>> trigintegrate(sin(x)*tan(x), x) + -log(sin(x) - 1)/2 + log(sin(x) + 1)/2 - sin(x) + + References + ========== + + .. [1] https://en.wikibooks.org/wiki/Calculus/Integration_techniques + + See Also + ======== + + sympy.integrals.integrals.Integral.doit + sympy.integrals.integrals.Integral + """ + pat, a, n, m = _pat_sincos(x) + + f = f.rewrite('sincos') + M = f.match(pat) + + if M is None: + return + + n, m = M[n], M[m] + if n.is_zero and m.is_zero: + return x + zz = x if n.is_zero else S.Zero + + a = M[a] + + if n.is_odd or m.is_odd: + u = _u + n_, m_ = n.is_odd, m.is_odd + + # take smallest n or m -- to choose simplest substitution + if n_ and m_: + + # Make sure to choose the positive one + # otherwise an incorrect integral can occur. + if n < 0 and m > 0: + m_ = True + n_ = False + elif m < 0 and n > 0: + n_ = True + m_ = False + # Both are negative so choose the smallest n or m + # in absolute value for simplest substitution. + elif (n < 0 and m < 0): + n_ = n > m + m_ = not (n > m) + + # Both n and m are odd and positive + else: + n_ = (n < m) # NB: careful here, one of the + m_ = not (n < m) # conditions *must* be true + + # n m u=C (n-1)/2 m + # S(x) * C(x) dx --> -(1-u^2) * u du + if n_: + ff = -(1 - u**2)**((n - 1)/2) * u**m + uu = cos(a*x) + + # n m u=S n (m-1)/2 + # S(x) * C(x) dx --> u * (1-u^2) du + elif m_: + ff = u**n * (1 - u**2)**((m - 1)/2) + uu = sin(a*x) + + fi = integrate(ff, u) # XXX cyclic deps + fx = fi.subs(u, uu) + if conds == 'piecewise': + return Piecewise((fx / a, Ne(a, 0)), (zz, True)) + return fx / a + + # n & m are both even + # + # 2k 2m 2l 2l + # we transform S (x) * C (x) into terms with only S (x) or C (x) + # + # example: + # 100 4 100 2 2 100 4 2 + # S (x) * C (x) = S (x) * (1-S (x)) = S (x) * (1 + S (x) - 2*S (x)) + # + # 104 102 100 + # = S (x) - 2*S (x) + S (x) + # 2k + # then S is integrated with recursive formula + + # take largest n or m -- to choose simplest substitution + n_ = (Abs(n) > Abs(m)) + m_ = (Abs(m) > Abs(n)) + res = S.Zero + + if n_: + # 2k 2 k i 2i + # C = (1 - S ) = sum(i, (-) * B(k, i) * S ) + if m > 0: + for i in range(0, m//2 + 1): + res += (S.NegativeOne**i * binomial(m//2, i) * + _sin_pow_integrate(n + 2*i, x)) + + elif m == 0: + res = _sin_pow_integrate(n, x) + else: + + # m < 0 , |n| > |m| + # / + # | + # | m n + # | cos (x) sin (x) dx = + # | + # | + #/ + # / + # | + # -1 m+1 n-1 n - 1 | m+2 n-2 + # ________ cos (x) sin (x) + _______ | cos (x) sin (x) dx + # | + # m + 1 m + 1 | + # / + + res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) + + Rational(n - 1, m + 1) * + trigintegrate(cos(x)**(m + 2)*sin(x)**(n - 2), x)) + + elif m_: + # 2k 2 k i 2i + # S = (1 - C ) = sum(i, (-) * B(k, i) * C ) + if n > 0: + + # / / + # | | + # | m n | -m n + # | cos (x)*sin (x) dx or | cos (x) * sin (x) dx + # | | + # / / + # + # |m| > |n| ; m, n >0 ; m, n belong to Z - {0} + # n 2 + # sin (x) term is expanded here in terms of cos (x), + # and then integrated. + # + + for i in range(0, n//2 + 1): + res += (S.NegativeOne**i * binomial(n//2, i) * + _cos_pow_integrate(m + 2*i, x)) + + elif n == 0: + + # / + # | + # | 1 + # | _ _ _ + # | m + # | cos (x) + # / + # + + res = _cos_pow_integrate(m, x) + else: + + # n < 0 , |m| > |n| + # / + # | + # | m n + # | cos (x) sin (x) dx = + # | + # | + #/ + # / + # | + # 1 m-1 n+1 m - 1 | m-2 n+2 + # _______ cos (x) sin (x) + _______ | cos (x) sin (x) dx + # | + # n + 1 n + 1 | + # / + + res = (Rational(1, n + 1) * cos(x)**(m - 1)*sin(x)**(n + 1) + + Rational(m - 1, n + 1) * + trigintegrate(cos(x)**(m - 2)*sin(x)**(n + 2), x)) + + else: + if m == n: + ##Substitute sin(2x)/2 for sin(x)cos(x) and then Integrate. + res = integrate((sin(2*x)*S.Half)**m, x) + elif (m == -n): + if n < 0: + # Same as the scheme described above. + # the function argument to integrate in the end will + # be 1, this cannot be integrated by trigintegrate. + # Hence use sympy.integrals.integrate. + res = (Rational(1, n + 1) * cos(x)**(m - 1) * sin(x)**(n + 1) + + Rational(m - 1, n + 1) * + integrate(cos(x)**(m - 2) * sin(x)**(n + 2), x)) + else: + res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) + + Rational(n - 1, m + 1) * + integrate(cos(x)**(m + 2)*sin(x)**(n - 2), x)) + if conds == 'piecewise': + return Piecewise((res.subs(x, a*x) / a, Ne(a, 0)), (zz, True)) + return res.subs(x, a*x) / a + + +def _sin_pow_integrate(n, x): + if n > 0: + if n == 1: + #Recursion break + return -cos(x) + + # n > 0 + # / / + # | | + # | n -1 n-1 n - 1 | n-2 + # | sin (x) dx = ______ cos (x) sin (x) + _______ | sin (x) dx + # | | + # | n n | + #/ / + # + # + + return (Rational(-1, n) * cos(x) * sin(x)**(n - 1) + + Rational(n - 1, n) * _sin_pow_integrate(n - 2, x)) + + if n < 0: + if n == -1: + ##Make sure this does not come back here again. + ##Recursion breaks here or at n==0. + return trigintegrate(1/sin(x), x) + + # n < 0 + # / / + # | | + # | n 1 n+1 n + 2 | n+2 + # | sin (x) dx = _______ cos (x) sin (x) + _______ | sin (x) dx + # | | + # | n + 1 n + 1 | + #/ / + # + + return (Rational(1, n + 1) * cos(x) * sin(x)**(n + 1) + + Rational(n + 2, n + 1) * _sin_pow_integrate(n + 2, x)) + + else: + #n == 0 + #Recursion break. + return x + + +def _cos_pow_integrate(n, x): + if n > 0: + if n == 1: + #Recursion break. + return sin(x) + + # n > 0 + # / / + # | | + # | n 1 n-1 n - 1 | n-2 + # | sin (x) dx = ______ sin (x) cos (x) + _______ | cos (x) dx + # | | + # | n n | + #/ / + # + + return (Rational(1, n) * sin(x) * cos(x)**(n - 1) + + Rational(n - 1, n) * _cos_pow_integrate(n - 2, x)) + + if n < 0: + if n == -1: + ##Recursion break + return trigintegrate(1/cos(x), x) + + # n < 0 + # / / + # | | + # | n -1 n+1 n + 2 | n+2 + # | cos (x) dx = _______ sin (x) cos (x) + _______ | cos (x) dx + # | | + # | n + 1 n + 1 | + #/ / + # + + return (Rational(-1, n + 1) * sin(x) * cos(x)**(n + 1) + + Rational(n + 2, n + 1) * _cos_pow_integrate(n + 2, x)) + else: + # n == 0 + #Recursion Break. + return x diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1b3f043ada6222d79dd52fd28b035e2ea45c5683 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/__init__.py @@ -0,0 +1,8 @@ +"""Helper module for setting up interactive SymPy sessions. """ + +from .printing import init_printing +from .session import init_session +from .traversal import interactive_traversal + + +__all__ = ['init_printing', 'init_session', 'interactive_traversal'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/printing.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/printing.py new file mode 100644 index 0000000000000000000000000000000000000000..2fcc73e3e96a5b7e25f7fc7ebf54a5781c3b15b9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/printing.py @@ -0,0 +1,532 @@ +"""Tools for setting up printing in interactive sessions. """ + +from io import BytesIO + +from sympy.printing.latex import latex as default_latex +from sympy.printing.preview import preview +from sympy.utilities.misc import debug +from sympy.printing.defaults import Printable +from sympy.external import import_module + + +def _init_python_printing(stringify_func, **settings): + """Setup printing in Python interactive session. """ + import sys + import builtins + + def _displayhook(arg): + """Python's pretty-printer display hook. + + This function was adapted from: + + https://www.python.org/dev/peps/pep-0217/ + + """ + if arg is not None: + builtins._ = None + print(stringify_func(arg, **settings)) + builtins._ = arg + + sys.displayhook = _displayhook + + +def _init_ipython_printing(ip, stringify_func, use_latex, euler, forecolor, + backcolor, fontsize, latex_mode, print_builtin, + latex_printer, scale, **settings): + """Setup printing in IPython interactive session. """ + IPython = import_module("IPython", min_module_version="1.0") + try: + from IPython.lib.latextools import latex_to_png + except ImportError: + pass + + # Guess best font color if none was given based on the ip.colors string. + # From the IPython documentation: + # It has four case-insensitive values: 'nocolor', 'neutral', 'linux', + # 'lightbg'. The default is neutral, which should be legible on either + # dark or light terminal backgrounds. linux is optimised for dark + # backgrounds and lightbg for light ones. + if forecolor is None: + color = ip.colors.lower() + if color == 'lightbg': + forecolor = 'Black' + elif color == 'linux': + forecolor = 'White' + else: + # No idea, go with gray. + forecolor = 'Gray' + debug("init_printing: Automatic foreground color:", forecolor) + + if use_latex == "svg": + extra_preamble = "\n\\special{color %s}" % forecolor + else: + extra_preamble = "" + + imagesize = 'tight' + offset = "0cm,0cm" + resolution = round(150*scale) + dvi = r"-T %s -D %d -bg %s -fg %s -O %s" % ( + imagesize, resolution, backcolor, forecolor, offset) + dvioptions = dvi.split() + + svg_scale = 150/72*scale + dvioptions_svg = ["--no-fonts", "--scale={}".format(svg_scale)] + + debug("init_printing: DVIOPTIONS:", dvioptions) + debug("init_printing: DVIOPTIONS_SVG:", dvioptions_svg) + + latex = latex_printer or default_latex + + def _print_plain(arg, p, cycle): + """caller for pretty, for use in IPython 0.11""" + if _can_print(arg): + p.text(stringify_func(arg)) + else: + p.text(IPython.lib.pretty.pretty(arg)) + + def _preview_wrapper(o): + exprbuffer = BytesIO() + try: + preview(o, output='png', viewer='BytesIO', euler=euler, + outputbuffer=exprbuffer, extra_preamble=extra_preamble, + dvioptions=dvioptions, fontsize=fontsize) + except Exception as e: + # IPython swallows exceptions + debug("png printing:", "_preview_wrapper exception raised:", + repr(e)) + raise + return exprbuffer.getvalue() + + def _svg_wrapper(o): + exprbuffer = BytesIO() + try: + preview(o, output='svg', viewer='BytesIO', euler=euler, + outputbuffer=exprbuffer, extra_preamble=extra_preamble, + dvioptions=dvioptions_svg, fontsize=fontsize) + except Exception as e: + # IPython swallows exceptions + debug("svg printing:", "_preview_wrapper exception raised:", + repr(e)) + raise + return exprbuffer.getvalue().decode('utf-8') + + def _matplotlib_wrapper(o): + # mathtext can't render some LaTeX commands. For example, it can't + # render any LaTeX environments such as array or matrix. So here we + # ensure that if mathtext fails to render, we return None. + try: + try: + return latex_to_png(o, color=forecolor, scale=scale) + except TypeError: # Old IPython version without color and scale + return latex_to_png(o) + except ValueError as e: + debug('matplotlib exception caught:', repr(e)) + return None + + + # Hook methods for builtin SymPy printers + printing_hooks = ('_latex', '_sympystr', '_pretty', '_sympyrepr') + + + def _can_print(o): + """Return True if type o can be printed with one of the SymPy printers. + + If o is a container type, this is True if and only if every element of + o can be printed in this way. + """ + + try: + # If you're adding another type, make sure you add it to printable_types + # later in this file as well + + builtin_types = (list, tuple, set, frozenset) + if isinstance(o, builtin_types): + # If the object is a custom subclass with a custom str or + # repr, use that instead. + if (type(o).__str__ not in (i.__str__ for i in builtin_types) or + type(o).__repr__ not in (i.__repr__ for i in builtin_types)): + return False + return all(_can_print(i) for i in o) + elif isinstance(o, dict): + return all(_can_print(i) and _can_print(o[i]) for i in o) + elif isinstance(o, bool): + return False + elif isinstance(o, Printable): + # types known to SymPy + return True + elif any(hasattr(o, hook) for hook in printing_hooks): + # types which add support themselves + return True + elif isinstance(o, (float, int)) and print_builtin: + return True + return False + except RuntimeError: + return False + # This is in case maximum recursion depth is reached. + # Since RecursionError is for versions of Python 3.5+ + # so this is to guard against RecursionError for older versions. + + def _print_latex_png(o): + """ + A function that returns a png rendered by an external latex + distribution, falling back to matplotlib rendering + """ + if _can_print(o): + s = latex(o, mode=latex_mode, **settings) + if latex_mode == 'plain': + s = '$\\displaystyle %s$' % s + try: + return _preview_wrapper(s) + except RuntimeError as e: + debug('preview failed with:', repr(e), + ' Falling back to matplotlib backend') + if latex_mode != 'inline': + s = latex(o, mode='inline', **settings) + return _matplotlib_wrapper(s) + + def _print_latex_svg(o): + """ + A function that returns a svg rendered by an external latex + distribution, no fallback available. + """ + if _can_print(o): + s = latex(o, mode=latex_mode, **settings) + if latex_mode == 'plain': + s = '$\\displaystyle %s$' % s + try: + return _svg_wrapper(s) + except RuntimeError as e: + debug('preview failed with:', repr(e), + ' No fallback available.') + + def _print_latex_matplotlib(o): + """ + A function that returns a png rendered by mathtext + """ + if _can_print(o): + s = latex(o, mode='inline', **settings) + return _matplotlib_wrapper(s) + + def _print_latex_text(o): + """ + A function to generate the latex representation of SymPy expressions. + """ + if _can_print(o): + s = latex(o, mode=latex_mode, **settings) + if latex_mode == 'plain': + return '$\\displaystyle %s$' % s + return s + + # Printable is our own type, so we handle it with methods instead of + # the approach required by builtin types. This allows downstream + # packages to override the methods in their own subclasses of Printable, + # which avoids the effects of gh-16002. + printable_types = [float, tuple, list, set, frozenset, dict, int] + + plaintext_formatter = ip.display_formatter.formatters['text/plain'] + + # Exception to the rule above: IPython has better dispatching rules + # for plaintext printing (xref ipython/ipython#8938), and we can't + # use `_repr_pretty_` without hitting a recursion error in _print_plain. + for cls in printable_types + [Printable]: + plaintext_formatter.for_type(cls, _print_plain) + + svg_formatter = ip.display_formatter.formatters['image/svg+xml'] + if use_latex in ('svg', ): + debug("init_printing: using svg formatter") + for cls in printable_types: + svg_formatter.for_type(cls, _print_latex_svg) + Printable._repr_svg_ = _print_latex_svg + else: + debug("init_printing: not using any svg formatter") + for cls in printable_types: + # Better way to set this, but currently does not work in IPython + #png_formatter.for_type(cls, None) + if cls in svg_formatter.type_printers: + svg_formatter.type_printers.pop(cls) + Printable._repr_svg_ = Printable._repr_disabled + + png_formatter = ip.display_formatter.formatters['image/png'] + if use_latex in (True, 'png'): + debug("init_printing: using png formatter") + for cls in printable_types: + png_formatter.for_type(cls, _print_latex_png) + Printable._repr_png_ = _print_latex_png + elif use_latex == 'matplotlib': + debug("init_printing: using matplotlib formatter") + for cls in printable_types: + png_formatter.for_type(cls, _print_latex_matplotlib) + Printable._repr_png_ = _print_latex_matplotlib + else: + debug("init_printing: not using any png formatter") + for cls in printable_types: + # Better way to set this, but currently does not work in IPython + #png_formatter.for_type(cls, None) + if cls in png_formatter.type_printers: + png_formatter.type_printers.pop(cls) + Printable._repr_png_ = Printable._repr_disabled + + latex_formatter = ip.display_formatter.formatters['text/latex'] + if use_latex in (True, 'mathjax'): + debug("init_printing: using mathjax formatter") + for cls in printable_types: + latex_formatter.for_type(cls, _print_latex_text) + Printable._repr_latex_ = _print_latex_text + else: + debug("init_printing: not using text/latex formatter") + for cls in printable_types: + # Better way to set this, but currently does not work in IPython + #latex_formatter.for_type(cls, None) + if cls in latex_formatter.type_printers: + latex_formatter.type_printers.pop(cls) + Printable._repr_latex_ = Printable._repr_disabled + +def _is_ipython(shell): + """Is a shell instance an IPython shell?""" + # shortcut, so we don't import IPython if we don't have to + from sys import modules + if 'IPython' not in modules: + return False + try: + from IPython.core.interactiveshell import InteractiveShell + except ImportError: + # IPython < 0.11 + try: + from IPython.iplib import InteractiveShell + except ImportError: + # Reaching this points means IPython has changed in a backward-incompatible way + # that we don't know about. Warn? + return False + return isinstance(shell, InteractiveShell) + +# Used by the doctester to override the default for no_global +NO_GLOBAL = False + +def init_printing(pretty_print=True, order=None, use_unicode=None, + use_latex=None, wrap_line=None, num_columns=None, + no_global=False, ip=None, euler=False, forecolor=None, + backcolor='Transparent', fontsize='10pt', + latex_mode='plain', print_builtin=True, + str_printer=None, pretty_printer=None, + latex_printer=None, scale=1.0, **settings): + r""" + Initializes pretty-printer depending on the environment. + + Parameters + ========== + + pretty_print : bool, default=True + If ``True``, use :func:`~.pretty_print` to stringify or the provided pretty + printer; if ``False``, use :func:`~.sstrrepr` to stringify or the provided string + printer. + order : string or None, default='lex' + There are a few different settings for this parameter: + ``'lex'`` (default), which is lexographic order; + ``'grlex'``, which is graded lexographic order; + ``'grevlex'``, which is reversed graded lexographic order; + ``'old'``, which is used for compatibility reasons and for long expressions; + ``None``, which sets it to lex. + use_unicode : bool or None, default=None + If ``True``, use unicode characters; + if ``False``, do not use unicode characters; + if ``None``, make a guess based on the environment. + use_latex : string, bool, or None, default=None + If ``True``, use default LaTeX rendering in GUI interfaces (png and + mathjax); + if ``False``, do not use LaTeX rendering; + if ``None``, make a guess based on the environment; + if ``'png'``, enable LaTeX rendering with an external LaTeX compiler, + falling back to matplotlib if external compilation fails; + if ``'matplotlib'``, enable LaTeX rendering with matplotlib; + if ``'mathjax'``, enable LaTeX text generation, for example MathJax + rendering in IPython notebook or text rendering in LaTeX documents; + if ``'svg'``, enable LaTeX rendering with an external latex compiler, + no fallback + wrap_line : bool + If True, lines will wrap at the end; if False, they will not wrap + but continue as one line. This is only relevant if ``pretty_print`` is + True. + num_columns : int or None, default=None + If ``int``, number of columns before wrapping is set to num_columns; if + ``None``, number of columns before wrapping is set to terminal width. + This is only relevant if ``pretty_print`` is ``True``. + no_global : bool, default=False + If ``True``, the settings become system wide; + if ``False``, use just for this console/session. + ip : An interactive console + This can either be an instance of IPython, + or a class that derives from code.InteractiveConsole. + euler : bool, optional, default=False + Loads the euler package in the LaTeX preamble for handwritten style + fonts (https://www.ctan.org/pkg/euler). + forecolor : string or None, optional, default=None + DVI setting for foreground color. ``None`` means that either ``'Black'``, + ``'White'``, or ``'Gray'`` will be selected based on a guess of the IPython + terminal color setting. See notes. + backcolor : string, optional, default='Transparent' + DVI setting for background color. See notes. + fontsize : string or int, optional, default='10pt' + A font size to pass to the LaTeX documentclass function in the + preamble. Note that the options are limited by the documentclass. + Consider using scale instead. + latex_mode : string, optional, default='plain' + The mode used in the LaTeX printer. Can be one of: + ``{'inline'|'plain'|'equation'|'equation*'}``. + print_builtin : boolean, optional, default=True + If ``True`` then floats and integers will be printed. If ``False`` the + printer will only print SymPy types. + str_printer : function, optional, default=None + A custom string printer function. This should mimic + :func:`~.sstrrepr`. + pretty_printer : function, optional, default=None + A custom pretty printer. This should mimic :func:`~.pretty`. + latex_printer : function, optional, default=None + A custom LaTeX printer. This should mimic :func:`~.latex`. + scale : float, optional, default=1.0 + Scale the LaTeX output when using the ``'png'`` or ``'svg'`` backends. + Useful for high dpi screens. + settings : + Any additional settings for the ``latex`` and ``pretty`` commands can + be used to fine-tune the output. + + Examples + ======== + + >>> from sympy.interactive import init_printing + >>> from sympy import Symbol, sqrt + >>> from sympy.abc import x, y + >>> sqrt(5) + sqrt(5) + >>> init_printing(pretty_print=True) # doctest: +SKIP + >>> sqrt(5) # doctest: +SKIP + ___ + \/ 5 + >>> theta = Symbol('theta') # doctest: +SKIP + >>> init_printing(use_unicode=True) # doctest: +SKIP + >>> theta # doctest: +SKIP + \u03b8 + >>> init_printing(use_unicode=False) # doctest: +SKIP + >>> theta # doctest: +SKIP + theta + >>> init_printing(order='lex') # doctest: +SKIP + >>> str(y + x + y**2 + x**2) # doctest: +SKIP + x**2 + x + y**2 + y + >>> init_printing(order='grlex') # doctest: +SKIP + >>> str(y + x + y**2 + x**2) # doctest: +SKIP + x**2 + x + y**2 + y + >>> init_printing(order='grevlex') # doctest: +SKIP + >>> str(y * x**2 + x * y**2) # doctest: +SKIP + x**2*y + x*y**2 + >>> init_printing(order='old') # doctest: +SKIP + >>> str(x**2 + y**2 + x + y) # doctest: +SKIP + x**2 + x + y**2 + y + >>> init_printing(num_columns=10) # doctest: +SKIP + >>> x**2 + x + y**2 + y # doctest: +SKIP + x + y + + x**2 + y**2 + + Notes + ===== + + The foreground and background colors can be selected when using ``'png'`` or + ``'svg'`` LaTeX rendering. Note that before the ``init_printing`` command is + executed, the LaTeX rendering is handled by the IPython console and not SymPy. + + The colors can be selected among the 68 standard colors known to ``dvips``, + for a list see [1]_. In addition, the background color can be + set to ``'Transparent'`` (which is the default value). + + When using the ``'Auto'`` foreground color, the guess is based on the + ``colors`` variable in the IPython console, see [2]_. Hence, if + that variable is set correctly in your IPython console, there is a high + chance that the output will be readable, although manual settings may be + needed. + + + References + ========== + + .. [1] https://en.wikibooks.org/wiki/LaTeX/Colors#The_68_standard_colors_known_to_dvips + + .. [2] https://ipython.readthedocs.io/en/stable/config/details.html#terminal-colors + + See Also + ======== + + sympy.printing.latex + sympy.printing.pretty + + """ + import sys + from sympy.printing.printer import Printer + + if pretty_print: + if pretty_printer is not None: + stringify_func = pretty_printer + else: + from sympy.printing import pretty as stringify_func + else: + if str_printer is not None: + stringify_func = str_printer + else: + from sympy.printing import sstrrepr as stringify_func + + # Even if ip is not passed, double check that not in IPython shell + in_ipython = False + if ip is None: + try: + ip = get_ipython() + except NameError: + pass + else: + in_ipython = (ip is not None) + + if ip and not in_ipython: + in_ipython = _is_ipython(ip) + + if in_ipython and pretty_print: + try: + from IPython.terminal.interactiveshell import TerminalInteractiveShell + from code import InteractiveConsole + except ImportError: + pass + else: + # This will be True if we are in the qtconsole or notebook + if not isinstance(ip, (InteractiveConsole, TerminalInteractiveShell)) \ + and 'ipython-console' not in ''.join(sys.argv): + if use_unicode is None: + debug("init_printing: Setting use_unicode to True") + use_unicode = True + if use_latex is None: + debug("init_printing: Setting use_latex to True") + use_latex = True + + if not NO_GLOBAL and not no_global: + Printer.set_global_settings(order=order, use_unicode=use_unicode, + wrap_line=wrap_line, num_columns=num_columns) + else: + _stringify_func = stringify_func + + if pretty_print: + stringify_func = lambda expr, **settings: \ + _stringify_func(expr, order=order, + use_unicode=use_unicode, + wrap_line=wrap_line, + num_columns=num_columns, + **settings) + else: + stringify_func = \ + lambda expr, **settings: _stringify_func( + expr, order=order, **settings) + + if in_ipython: + mode_in_settings = settings.pop("mode", None) + if mode_in_settings: + debug("init_printing: Mode is not able to be set due to internals" + "of IPython printing") + _init_ipython_printing(ip, stringify_func, use_latex, euler, + forecolor, backcolor, fontsize, latex_mode, + print_builtin, latex_printer, scale, + **settings) + else: + _init_python_printing(stringify_func, **settings) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/session.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/session.py new file mode 100644 index 0000000000000000000000000000000000000000..348b0938d69e5e7ffa9510f7d9ac759eb6683b8f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/session.py @@ -0,0 +1,463 @@ +"""Tools for setting up interactive sessions. """ + +from sympy.external.gmpy import GROUND_TYPES +from sympy.external.importtools import version_tuple + +from sympy.interactive.printing import init_printing + +from sympy.utilities.misc import ARCH + +preexec_source = """\ +from sympy import * +x, y, z, t = symbols('x y z t') +k, m, n = symbols('k m n', integer=True) +f, g, h = symbols('f g h', cls=Function) +init_printing() +""" + +verbose_message = """\ +These commands were executed: +%(source)s +Documentation can be found at https://docs.sympy.org/%(version)s +""" + +no_ipython = """\ +Could not locate IPython. Having IPython installed is greatly recommended. +See http://ipython.scipy.org for more details. If you use Debian/Ubuntu, +just install the 'ipython' package and start isympy again. +""" + + +def _make_message(ipython=True, quiet=False, source=None): + """Create a banner for an interactive session. """ + from sympy import __version__ as sympy_version + from sympy import SYMPY_DEBUG + + import sys + import os + + if quiet: + return "" + + python_version = "%d.%d.%d" % sys.version_info[:3] + + if ipython: + shell_name = "IPython" + else: + shell_name = "Python" + + info = ['ground types: %s' % GROUND_TYPES] + + cache = os.getenv('SYMPY_USE_CACHE') + + if cache is not None and cache.lower() == 'no': + info.append('cache: off') + + if SYMPY_DEBUG: + info.append('debugging: on') + + args = shell_name, sympy_version, python_version, ARCH, ', '.join(info) + message = "%s console for SymPy %s (Python %s-%s) (%s)\n" % args + + if source is None: + source = preexec_source + + _source = "" + + for line in source.split('\n')[:-1]: + if not line: + _source += '\n' + else: + _source += '>>> ' + line + '\n' + + doc_version = sympy_version + if 'dev' in doc_version: + doc_version = "dev" + else: + doc_version = "%s/" % doc_version + + message += '\n' + verbose_message % {'source': _source, + 'version': doc_version} + + return message + + +def int_to_Integer(s): + """ + Wrap integer literals with Integer. + + This is based on the decistmt example from + https://docs.python.org/3/library/tokenize.html. + + Only integer literals are converted. Float literals are left alone. + + Examples + ======== + + >>> from sympy import Integer # noqa: F401 + >>> from sympy.interactive.session import int_to_Integer + >>> s = '1.2 + 1/2 - 0x12 + a1' + >>> int_to_Integer(s) + '1.2 +Integer (1 )/Integer (2 )-Integer (0x12 )+a1 ' + >>> s = 'print (1/2)' + >>> int_to_Integer(s) + 'print (Integer (1 )/Integer (2 ))' + >>> exec(s) + 0.5 + >>> exec(int_to_Integer(s)) + 1/2 + """ + from tokenize import generate_tokens, untokenize, NUMBER, NAME, OP + from io import StringIO + + def _is_int(num): + """ + Returns true if string value num (with token NUMBER) represents an integer. + """ + # XXX: Is there something in the standard library that will do this? + if '.' in num or 'j' in num.lower() or 'e' in num.lower(): + return False + return True + + result = [] + g = generate_tokens(StringIO(s).readline) # tokenize the string + for toknum, tokval, _, _, _ in g: + if toknum == NUMBER and _is_int(tokval): # replace NUMBER tokens + result.extend([ + (NAME, 'Integer'), + (OP, '('), + (NUMBER, tokval), + (OP, ')') + ]) + else: + result.append((toknum, tokval)) + return untokenize(result) + + +def enable_automatic_int_sympification(shell): + """ + Allow IPython to automatically convert integer literals to Integer. + """ + import ast + old_run_cell = shell.run_cell + + def my_run_cell(cell, *args, **kwargs): + try: + # Check the cell for syntax errors. This way, the syntax error + # will show the original input, not the transformed input. The + # downside here is that IPython magic like %timeit will not work + # with transformed input (but on the other hand, IPython magic + # that doesn't expect transformed input will continue to work). + ast.parse(cell) + except SyntaxError: + pass + else: + cell = int_to_Integer(cell) + return old_run_cell(cell, *args, **kwargs) + + shell.run_cell = my_run_cell + + +def enable_automatic_symbols(shell): + """Allow IPython to automatically create symbols (``isympy -a``). """ + # XXX: This should perhaps use tokenize, like int_to_Integer() above. + # This would avoid re-executing the code, which can lead to subtle + # issues. For example: + # + # In [1]: a = 1 + # + # In [2]: for i in range(10): + # ...: a += 1 + # ...: + # + # In [3]: a + # Out[3]: 11 + # + # In [4]: a = 1 + # + # In [5]: for i in range(10): + # ...: a += 1 + # ...: print b + # ...: + # b + # b + # b + # b + # b + # b + # b + # b + # b + # b + # + # In [6]: a + # Out[6]: 12 + # + # Note how the for loop is executed again because `b` was not defined, but `a` + # was already incremented once, so the result is that it is incremented + # multiple times. + + import re + re_nameerror = re.compile( + "name '(?P[A-Za-z_][A-Za-z0-9_]*)' is not defined") + + def _handler(self, etype, value, tb, tb_offset=None): + """Handle :exc:`NameError` exception and allow injection of missing symbols. """ + if etype is NameError and tb.tb_next and not tb.tb_next.tb_next: + match = re_nameerror.match(str(value)) + + if match is not None: + # XXX: Make sure Symbol is in scope. Otherwise you'll get infinite recursion. + self.run_cell("%(symbol)s = Symbol('%(symbol)s')" % + {'symbol': match.group("symbol")}, store_history=False) + + try: + code = self.user_ns['In'][-1] + except (KeyError, IndexError): + pass + else: + self.run_cell(code, store_history=False) + return None + finally: + self.run_cell("del %s" % match.group("symbol"), + store_history=False) + + stb = self.InteractiveTB.structured_traceback( + etype, value, tb, tb_offset=tb_offset) + self._showtraceback(etype, value, stb) + + shell.set_custom_exc((NameError,), _handler) + + +def init_ipython_session(shell=None, argv=[], auto_symbols=False, auto_int_to_Integer=False): + """Construct new IPython session. """ + import IPython + + if version_tuple(IPython.__version__) >= version_tuple('0.11'): + if not shell: + # use an app to parse the command line, and init config + # IPython 1.0 deprecates the frontend module, so we import directly + # from the terminal module to prevent a deprecation message from being + # shown. + if version_tuple(IPython.__version__) >= version_tuple('1.0'): + from IPython.terminal import ipapp + else: + from IPython.frontend.terminal import ipapp + app = ipapp.TerminalIPythonApp() + + # don't draw IPython banner during initialization: + app.display_banner = False + app.initialize(argv) + + shell = app.shell + + if auto_symbols: + enable_automatic_symbols(shell) + if auto_int_to_Integer: + enable_automatic_int_sympification(shell) + + return shell + else: + from IPython.Shell import make_IPython + return make_IPython(argv) + + +def init_python_session(): + """Construct new Python session. """ + from code import InteractiveConsole + + class SymPyConsole(InteractiveConsole): + """An interactive console with readline support. """ + + def __init__(self): + ns_locals = {} + InteractiveConsole.__init__(self, locals=ns_locals) + try: + import rlcompleter + import readline + except ImportError: + pass + else: + import os + import atexit + + readline.set_completer(rlcompleter.Completer(ns_locals).complete) + readline.parse_and_bind('tab: complete') + + if hasattr(readline, 'read_history_file'): + history = os.path.expanduser('~/.sympy-history') + + try: + readline.read_history_file(history) + except OSError: + pass + + atexit.register(readline.write_history_file, history) + + return SymPyConsole() + + +def init_session(ipython=None, pretty_print=True, order=None, + use_unicode=None, use_latex=None, quiet=False, auto_symbols=False, + auto_int_to_Integer=False, str_printer=None, pretty_printer=None, + latex_printer=None, argv=[]): + """ + Initialize an embedded IPython or Python session. The IPython session is + initiated with the --pylab option, without the numpy imports, so that + matplotlib plotting can be interactive. + + Parameters + ========== + + pretty_print: boolean + If True, use pretty_print to stringify; + if False, use sstrrepr to stringify. + order: string or None + There are a few different settings for this parameter: + lex (default), which is lexographic order; + grlex, which is graded lexographic order; + grevlex, which is reversed graded lexographic order; + old, which is used for compatibility reasons and for long expressions; + None, which sets it to lex. + use_unicode: boolean or None + If True, use unicode characters; + if False, do not use unicode characters. + use_latex: boolean or None + If True, use latex rendering if IPython GUI's; + if False, do not use latex rendering. + quiet: boolean + If True, init_session will not print messages regarding its status; + if False, init_session will print messages regarding its status. + auto_symbols: boolean + If True, IPython will automatically create symbols for you. + If False, it will not. + The default is False. + auto_int_to_Integer: boolean + If True, IPython will automatically wrap int literals with Integer, so + that things like 1/2 give Rational(1, 2). + If False, it will not. + The default is False. + ipython: boolean or None + If True, printing will initialize for an IPython console; + if False, printing will initialize for a normal console; + The default is None, which automatically determines whether we are in + an ipython instance or not. + str_printer: function, optional, default=None + A custom string printer function. This should mimic + sympy.printing.sstrrepr(). + pretty_printer: function, optional, default=None + A custom pretty printer. This should mimic sympy.printing.pretty(). + latex_printer: function, optional, default=None + A custom LaTeX printer. This should mimic sympy.printing.latex() + This should mimic sympy.printing.latex(). + argv: list of arguments for IPython + See sympy.bin.isympy for options that can be used to initialize IPython. + + See Also + ======== + + sympy.interactive.printing.init_printing: for examples and the rest of the parameters. + + + Examples + ======== + + >>> from sympy import init_session, Symbol, sin, sqrt + >>> sin(x) #doctest: +SKIP + NameError: name 'x' is not defined + >>> init_session() #doctest: +SKIP + >>> sin(x) #doctest: +SKIP + sin(x) + >>> sqrt(5) #doctest: +SKIP + ___ + \\/ 5 + >>> init_session(pretty_print=False) #doctest: +SKIP + >>> sqrt(5) #doctest: +SKIP + sqrt(5) + >>> y + x + y**2 + x**2 #doctest: +SKIP + x**2 + x + y**2 + y + >>> init_session(order='grlex') #doctest: +SKIP + >>> y + x + y**2 + x**2 #doctest: +SKIP + x**2 + y**2 + x + y + >>> init_session(order='grevlex') #doctest: +SKIP + >>> y * x**2 + x * y**2 #doctest: +SKIP + x**2*y + x*y**2 + >>> init_session(order='old') #doctest: +SKIP + >>> x**2 + y**2 + x + y #doctest: +SKIP + x + y + x**2 + y**2 + >>> theta = Symbol('theta') #doctest: +SKIP + >>> theta #doctest: +SKIP + theta + >>> init_session(use_unicode=True) #doctest: +SKIP + >>> theta # doctest: +SKIP + \u03b8 + """ + import sys + + in_ipython = False + + if ipython is not False: + try: + import IPython + except ImportError: + if ipython is True: + raise RuntimeError("IPython is not available on this system") + ip = None + else: + try: + from IPython import get_ipython + ip = get_ipython() + except ImportError: + ip = None + in_ipython = bool(ip) + if ipython is None: + ipython = in_ipython + + if ipython is False: + ip = init_python_session() + mainloop = ip.interact + else: + ip = init_ipython_session(ip, argv=argv, auto_symbols=auto_symbols, + auto_int_to_Integer=auto_int_to_Integer) + + if version_tuple(IPython.__version__) >= version_tuple('0.11'): + # runsource is gone, use run_cell instead, which doesn't + # take a symbol arg. The second arg is `store_history`, + # and False means don't add the line to IPython's history. + ip.runsource = lambda src, symbol='exec': ip.run_cell(src, False) + + # Enable interactive plotting using pylab. + try: + ip.enable_pylab(import_all=False) + except Exception: + # Causes an import error if matplotlib is not installed. + # Causes other errors (depending on the backend) if there + # is no display, or if there is some problem in the + # backend, so we have a bare "except Exception" here + pass + if not in_ipython: + mainloop = ip.mainloop + + if auto_symbols and (not ipython or version_tuple(IPython.__version__) < version_tuple('0.11')): + raise RuntimeError("automatic construction of symbols is possible only in IPython 0.11 or above") + if auto_int_to_Integer and (not ipython or version_tuple(IPython.__version__) < version_tuple('0.11')): + raise RuntimeError("automatic int to Integer transformation is possible only in IPython 0.11 or above") + + _preexec_source = preexec_source + + ip.runsource(_preexec_source, symbol='exec') + init_printing(pretty_print=pretty_print, order=order, + use_unicode=use_unicode, use_latex=use_latex, ip=ip, + str_printer=str_printer, pretty_printer=pretty_printer, + latex_printer=latex_printer) + + message = _make_message(ipython, quiet, _preexec_source) + + if not in_ipython: + print(message) + mainloop() + sys.exit('Exiting ...') + else: + print(message) + import atexit + atexit.register(lambda: print("Exiting ...\n")) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/traversal.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/traversal.py new file mode 100644 index 0000000000000000000000000000000000000000..1315ec4ef7868b666bb6b978b3d8b20442d100b0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/interactive/traversal.py @@ -0,0 +1,95 @@ +from sympy.core.basic import Basic +from sympy.printing import pprint + +import random + +def interactive_traversal(expr): + """Traverse a tree asking a user which branch to choose. """ + + RED, BRED = '\033[0;31m', '\033[1;31m' + GREEN, BGREEN = '\033[0;32m', '\033[1;32m' + YELLOW, BYELLOW = '\033[0;33m', '\033[1;33m' # noqa + BLUE, BBLUE = '\033[0;34m', '\033[1;34m' # noqa + MAGENTA, BMAGENTA = '\033[0;35m', '\033[1;35m'# noqa + CYAN, BCYAN = '\033[0;36m', '\033[1;36m' # noqa + END = '\033[0m' + + def cprint(*args): + print("".join(map(str, args)) + END) + + def _interactive_traversal(expr, stage): + if stage > 0: + print() + + cprint("Current expression (stage ", BYELLOW, stage, END, "):") + print(BCYAN) + pprint(expr) + print(END) + + if isinstance(expr, Basic): + if expr.is_Add: + args = expr.as_ordered_terms() + elif expr.is_Mul: + args = expr.as_ordered_factors() + else: + args = expr.args + elif hasattr(expr, "__iter__"): + args = list(expr) + else: + return expr + + n_args = len(args) + + if not n_args: + return expr + + for i, arg in enumerate(args): + cprint(GREEN, "[", BGREEN, i, GREEN, "] ", BLUE, type(arg), END) + pprint(arg) + print() + + if n_args == 1: + choices = '0' + else: + choices = '0-%d' % (n_args - 1) + + try: + choice = input("Your choice [%s,f,l,r,d,?]: " % choices) + except EOFError: + result = expr + print() + else: + if choice == '?': + cprint(RED, "%s - select subexpression with the given index" % + choices) + cprint(RED, "f - select the first subexpression") + cprint(RED, "l - select the last subexpression") + cprint(RED, "r - select a random subexpression") + cprint(RED, "d - done\n") + + result = _interactive_traversal(expr, stage) + elif choice in ('d', ''): + result = expr + elif choice == 'f': + result = _interactive_traversal(args[0], stage + 1) + elif choice == 'l': + result = _interactive_traversal(args[-1], stage + 1) + elif choice == 'r': + result = _interactive_traversal(random.choice(args), stage + 1) + else: + try: + choice = int(choice) + except ValueError: + cprint(BRED, + "Choice must be a number in %s range\n" % choices) + result = _interactive_traversal(expr, stage) + else: + if choice < 0 or choice >= n_args: + cprint(BRED, "Choice must be in %s range\n" % choices) + result = _interactive_traversal(expr, stage) + else: + result = _interactive_traversal(args[choice], stage + 1) + + return result + + return _interactive_traversal(expr, 0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d023d86f2c6f0c64d7ac460c50eedc355e78b21f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/__init__.py @@ -0,0 +1,3 @@ +from sympy.liealgebras.cartan_type import CartanType + +__all__ = ['CartanType'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/cartan_matrix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/cartan_matrix.py new file mode 100644 index 0000000000000000000000000000000000000000..2d29b37bc9a1a26790ee88b5902951afe4fc4560 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/cartan_matrix.py @@ -0,0 +1,25 @@ +from .cartan_type import CartanType + +def CartanMatrix(ct): + """Access the Cartan matrix of a specific Lie algebra + + Examples + ======== + + >>> from sympy.liealgebras.cartan_matrix import CartanMatrix + >>> CartanMatrix("A2") + Matrix([ + [ 2, -1], + [-1, 2]]) + + >>> CartanMatrix(['C', 3]) + Matrix([ + [ 2, -1, 0], + [-1, 2, -1], + [ 0, -2, 2]]) + + This method works by returning the Cartan matrix + which corresponds to Cartan type t. + """ + + return CartanType(ct).cartan_matrix() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/cartan_type.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/cartan_type.py new file mode 100644 index 0000000000000000000000000000000000000000..16bb152469238ea912a30c2d0f8210d6f729bdb1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/cartan_type.py @@ -0,0 +1,73 @@ +from sympy.core import Atom, Basic + + +class CartanType_generator(): + """ + Constructor for actually creating things + """ + def __call__(self, *args): + c = args[0] + if isinstance(c, list): + letter, n = c[0], int(c[1]) + elif isinstance(c, str): + letter, n = c[0], int(c[1:]) + else: + raise TypeError("Argument must be a string (e.g. 'A3') or a list (e.g. ['A', 3])") + + if n < 0: + raise ValueError("Lie algebra rank cannot be negative") + if letter == "A": + from . import type_a + return type_a.TypeA(n) + if letter == "B": + from . import type_b + return type_b.TypeB(n) + + if letter == "C": + from . import type_c + return type_c.TypeC(n) + + if letter == "D": + from . import type_d + return type_d.TypeD(n) + + if letter == "E": + if n >= 6 and n <= 8: + from . import type_e + return type_e.TypeE(n) + + if letter == "F": + if n == 4: + from . import type_f + return type_f.TypeF(n) + + if letter == "G": + if n == 2: + from . import type_g + return type_g.TypeG(n) + +CartanType = CartanType_generator() + + +class Standard_Cartan(Atom): + """ + Concrete base class for Cartan types such as A4, etc + """ + + def __new__(cls, series, n): + obj = Basic.__new__(cls) + obj.n = n + obj.series = series + return obj + + def rank(self): + """ + Returns the rank of the Lie algebra + """ + return self.n + + def series(self): + """ + Returns the type of the Lie algebra + """ + return self.series diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/dynkin_diagram.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/dynkin_diagram.py new file mode 100644 index 0000000000000000000000000000000000000000..cc9e2dac4d54490b803eeaf9637cb9b66b01f058 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/dynkin_diagram.py @@ -0,0 +1,24 @@ +from .cartan_type import CartanType + + +def DynkinDiagram(t): + """Display the Dynkin diagram of a given Lie algebra + + Works by generating the CartanType for the input, t, and then returning the + Dynkin diagram method from the individual classes. + + Examples + ======== + + >>> from sympy.liealgebras.dynkin_diagram import DynkinDiagram + >>> print(DynkinDiagram("A3")) + 0---0---0 + 1 2 3 + + >>> print(DynkinDiagram("B4")) + 0---0---0=>=0 + 1 2 3 4 + + """ + + return CartanType(t).dynkin_diagram() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/root_system.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/root_system.py new file mode 100644 index 0000000000000000000000000000000000000000..36eb24605e78bbdc669736910d89be5606df1389 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/root_system.py @@ -0,0 +1,196 @@ +from .cartan_type import CartanType +from sympy.core.basic import Atom + +class RootSystem(Atom): + """Represent the root system of a simple Lie algebra + + Every simple Lie algebra has a unique root system. To find the root + system, we first consider the Cartan subalgebra of g, which is the maximal + abelian subalgebra, and consider the adjoint action of g on this + subalgebra. There is a root system associated with this action. Now, a + root system over a vector space V is a set of finite vectors Phi (called + roots), which satisfy: + + 1. The roots span V + 2. The only scalar multiples of x in Phi are x and -x + 3. For every x in Phi, the set Phi is closed under reflection + through the hyperplane perpendicular to x. + 4. If x and y are roots in Phi, then the projection of y onto + the line through x is a half-integral multiple of x. + + Now, there is a subset of Phi, which we will call Delta, such that: + 1. Delta is a basis of V + 2. Each root x in Phi can be written x = sum k_y y for y in Delta + + The elements of Delta are called the simple roots. + Therefore, we see that the simple roots span the root space of a given + simple Lie algebra. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Root_system + .. [2] Lie Algebras and Representation Theory - Humphreys + + """ + + def __new__(cls, cartantype): + """Create a new RootSystem object + + This method assigns an attribute called cartan_type to each instance of + a RootSystem object. When an instance of RootSystem is called, it + needs an argument, which should be an instance of a simple Lie algebra. + We then take the CartanType of this argument and set it as the + cartan_type attribute of the RootSystem instance. + + """ + obj = Atom.__new__(cls) + obj.cartan_type = CartanType(cartantype) + return obj + + def simple_roots(self): + """Generate the simple roots of the Lie algebra + + The rank of the Lie algebra determines the number of simple roots that + it has. This method obtains the rank of the Lie algebra, and then uses + the simple_root method from the Lie algebra classes to generate all the + simple roots. + + Examples + ======== + + >>> from sympy.liealgebras.root_system import RootSystem + >>> c = RootSystem("A3") + >>> roots = c.simple_roots() + >>> roots + {1: [1, -1, 0, 0], 2: [0, 1, -1, 0], 3: [0, 0, 1, -1]} + + """ + n = self.cartan_type.rank() + roots = {i: self.cartan_type.simple_root(i) for i in range(1, n+1)} + return roots + + + def all_roots(self): + """Generate all the roots of a given root system + + The result is a dictionary where the keys are integer numbers. It + generates the roots by getting the dictionary of all positive roots + from the bases classes, and then taking each root, and multiplying it + by -1 and adding it to the dictionary. In this way all the negative + roots are generated. + + """ + alpha = self.cartan_type.positive_roots() + keys = list(alpha.keys()) + k = max(keys) + for val in keys: + k += 1 + root = alpha[val] + newroot = [-x for x in root] + alpha[k] = newroot + return alpha + + def root_space(self): + """Return the span of the simple roots + + The root space is the vector space spanned by the simple roots, i.e. it + is a vector space with a distinguished basis, the simple roots. This + method returns a string that represents the root space as the span of + the simple roots, alpha[1],...., alpha[n]. + + Examples + ======== + + >>> from sympy.liealgebras.root_system import RootSystem + >>> c = RootSystem("A3") + >>> c.root_space() + 'alpha[1] + alpha[2] + alpha[3]' + + """ + n = self.cartan_type.rank() + rs = " + ".join("alpha["+str(i) +"]" for i in range(1, n+1)) + return rs + + def add_simple_roots(self, root1, root2): + """Add two simple roots together + + The function takes as input two integers, root1 and root2. It then + uses these integers as keys in the dictionary of simple roots, and gets + the corresponding simple roots, and then adds them together. + + Examples + ======== + + >>> from sympy.liealgebras.root_system import RootSystem + >>> c = RootSystem("A3") + >>> newroot = c.add_simple_roots(1, 2) + >>> newroot + [1, 0, -1, 0] + + """ + + alpha = self.simple_roots() + if root1 > len(alpha) or root2 > len(alpha): + raise ValueError("You've used a root that doesn't exist!") + a1 = alpha[root1] + a2 = alpha[root2] + newroot = [_a1 + _a2 for _a1, _a2 in zip(a1, a2)] + return newroot + + def add_as_roots(self, root1, root2): + """Add two roots together if and only if their sum is also a root + + It takes as input two vectors which should be roots. It then computes + their sum and checks if it is in the list of all possible roots. If it + is, it returns the sum. Otherwise it returns a string saying that the + sum is not a root. + + Examples + ======== + + >>> from sympy.liealgebras.root_system import RootSystem + >>> c = RootSystem("A3") + >>> c.add_as_roots([1, 0, -1, 0], [0, 0, 1, -1]) + [1, 0, 0, -1] + >>> c.add_as_roots([1, -1, 0, 0], [0, 0, -1, 1]) + 'The sum of these two roots is not a root' + + """ + alpha = self.all_roots() + newroot = [r1 + r2 for r1, r2 in zip(root1, root2)] + if newroot in alpha.values(): + return newroot + else: + return "The sum of these two roots is not a root" + + + def cartan_matrix(self): + """Cartan matrix of Lie algebra associated with this root system + + Examples + ======== + + >>> from sympy.liealgebras.root_system import RootSystem + >>> c = RootSystem("A3") + >>> c.cartan_matrix() + Matrix([ + [ 2, -1, 0], + [-1, 2, -1], + [ 0, -1, 2]]) + """ + return self.cartan_type.cartan_matrix() + + def dynkin_diagram(self): + """Dynkin diagram of the Lie algebra associated with this root system + + Examples + ======== + + >>> from sympy.liealgebras.root_system import RootSystem + >>> c = RootSystem("A3") + >>> print(c.dynkin_diagram()) + 0---0---0 + 1 2 3 + """ + return self.cartan_type.dynkin_diagram() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_a.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_a.py new file mode 100644 index 0000000000000000000000000000000000000000..96dc615366ae20d668d651620ac088f15751c50e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_a.py @@ -0,0 +1,164 @@ +from sympy.liealgebras.cartan_type import Standard_Cartan +from sympy.core.backend import eye + + +class TypeA(Standard_Cartan): + """ + This class contains the information about + the A series of simple Lie algebras. + ==== + """ + + def __new__(cls, n): + if n < 1: + raise ValueError("n cannot be less than 1") + return Standard_Cartan.__new__(cls, "A", n) + + + def dimension(self): + """Dimension of the vector space V underlying the Lie algebra + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A4") + >>> c.dimension() + 5 + """ + return self.n+1 + + + def basic_root(self, i, j): + """ + This is a method just to generate roots + with a 1 iin the ith position and a -1 + in the jth position. + + """ + + n = self.n + root = [0]*(n+1) + root[i] = 1 + root[j] = -1 + return root + + def simple_root(self, i): + """ + Every lie algebra has a unique root system. + Given a root system Q, there is a subset of the + roots such that an element of Q is called a + simple root if it cannot be written as the sum + of two elements in Q. If we let D denote the + set of simple roots, then it is clear that every + element of Q can be written as a linear combination + of elements of D with all coefficients non-negative. + + In A_n the ith simple root is the root which has a 1 + in the ith position, a -1 in the (i+1)th position, + and zeroes elsewhere. + + This method returns the ith simple root for the A series. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A4") + >>> c.simple_root(1) + [1, -1, 0, 0, 0] + + """ + + return self.basic_root(i-1, i) + + def positive_roots(self): + """ + This method generates all the positive roots of + A_n. This is half of all of the roots of A_n; + by multiplying all the positive roots by -1 we + get the negative roots. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A3") + >>> c.positive_roots() + {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], + 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} + """ + + n = self.n + posroots = {} + k = 0 + for i in range(0, n): + for j in range(i+1, n+1): + k += 1 + posroots[k] = self.basic_root(i, j) + return posroots + + def highest_root(self): + """ + Returns the highest weight root for A_n + """ + + return self.basic_root(0, self.n) + + def roots(self): + """ + Returns the total number of roots for A_n + """ + n = self.n + return n*(n+1) + + def cartan_matrix(self): + """ + Returns the Cartan matrix for A_n. + The Cartan matrix matrix for a Lie algebra is + generated by assigning an ordering to the simple + roots, (alpha[1], ...., alpha[l]). Then the ijth + entry of the Cartan matrix is (). + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType('A4') + >>> c.cartan_matrix() + Matrix([ + [ 2, -1, 0, 0], + [-1, 2, -1, 0], + [ 0, -1, 2, -1], + [ 0, 0, -1, 2]]) + + """ + + n = self.n + m = 2 * eye(n) + for i in range(1, n - 1): + m[i, i+1] = -1 + m[i, i-1] = -1 + m[0,1] = -1 + m[n-1, n-2] = -1 + return m + + def basis(self): + """ + Returns the number of independent generators of A_n + """ + n = self.n + return n**2 - 1 + + def lie_algebra(self): + """ + Returns the Lie algebra associated with A_n + """ + n = self.n + return "su(" + str(n + 1) + ")" + + def dynkin_diagram(self): + n = self.n + diag = "---".join("0" for i in range(1, n+1)) + "\n" + diag += " ".join(str(i) for i in range(1, n+1)) + return diag diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_b.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_b.py new file mode 100644 index 0000000000000000000000000000000000000000..c6ee85502261f4702769067c64021521a2bc1725 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_b.py @@ -0,0 +1,170 @@ +from .cartan_type import Standard_Cartan +from sympy.core.backend import eye + +class TypeB(Standard_Cartan): + + def __new__(cls, n): + if n < 2: + raise ValueError("n cannot be less than 2") + return Standard_Cartan.__new__(cls, "B", n) + + def dimension(self): + """Dimension of the vector space V underlying the Lie algebra + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("B3") + >>> c.dimension() + 3 + """ + + return self.n + + def basic_root(self, i, j): + """ + This is a method just to generate roots + with a 1 iin the ith position and a -1 + in the jth position. + + """ + root = [0]*self.n + root[i] = 1 + root[j] = -1 + return root + + def simple_root(self, i): + """ + Every lie algebra has a unique root system. + Given a root system Q, there is a subset of the + roots such that an element of Q is called a + simple root if it cannot be written as the sum + of two elements in Q. If we let D denote the + set of simple roots, then it is clear that every + element of Q can be written as a linear combination + of elements of D with all coefficients non-negative. + + In B_n the first n-1 simple roots are the same as the + roots in A_(n-1) (a 1 in the ith position, a -1 in + the (i+1)th position, and zeroes elsewhere). The n-th + simple root is the root with a 1 in the nth position + and zeroes elsewhere. + + This method returns the ith simple root for the B series. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("B3") + >>> c.simple_root(2) + [0, 1, -1] + + """ + n = self.n + if i < n: + return self.basic_root(i-1, i) + else: + root = [0]*self.n + root[n-1] = 1 + return root + + def positive_roots(self): + """ + This method generates all the positive roots of + A_n. This is half of all of the roots of B_n; + by multiplying all the positive roots by -1 we + get the negative roots. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A3") + >>> c.positive_roots() + {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], + 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} + """ + + n = self.n + posroots = {} + k = 0 + for i in range(0, n-1): + for j in range(i+1, n): + k += 1 + posroots[k] = self.basic_root(i, j) + k += 1 + root = self.basic_root(i, j) + root[j] = 1 + posroots[k] = root + + for i in range(0, n): + k += 1 + root = [0]*n + root[i] = 1 + posroots[k] = root + + return posroots + + def roots(self): + """ + Returns the total number of roots for B_n" + """ + + n = self.n + return 2*(n**2) + + def cartan_matrix(self): + """ + Returns the Cartan matrix for B_n. + The Cartan matrix matrix for a Lie algebra is + generated by assigning an ordering to the simple + roots, (alpha[1], ...., alpha[l]). Then the ijth + entry of the Cartan matrix is (). + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType('B4') + >>> c.cartan_matrix() + Matrix([ + [ 2, -1, 0, 0], + [-1, 2, -1, 0], + [ 0, -1, 2, -2], + [ 0, 0, -1, 2]]) + + """ + + n = self.n + m = 2* eye(n) + for i in range(1, n - 1): + m[i, i+1] = -1 + m[i, i-1] = -1 + m[0, 1] = -1 + m[n-2, n-1] = -2 + m[n-1, n-2] = -1 + return m + + def basis(self): + """ + Returns the number of independent generators of B_n + """ + + n = self.n + return (n**2 - n)/2 + + def lie_algebra(self): + """ + Returns the Lie algebra associated with B_n + """ + + n = self.n + return "so(" + str(2*n) + ")" + + def dynkin_diagram(self): + n = self.n + diag = "---".join("0" for i in range(1, n)) + "=>=0\n" + diag += " ".join(str(i) for i in range(1, n+1)) + return diag diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_c.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_c.py new file mode 100644 index 0000000000000000000000000000000000000000..615bb900b5ba9613fd02e43f476d34eef0d5d35c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_c.py @@ -0,0 +1,169 @@ +from .cartan_type import Standard_Cartan +from sympy.core.backend import eye + +class TypeC(Standard_Cartan): + + def __new__(cls, n): + if n < 3: + raise ValueError("n cannot be less than 3") + return Standard_Cartan.__new__(cls, "C", n) + + + def dimension(self): + """Dimension of the vector space V underlying the Lie algebra + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("C3") + >>> c.dimension() + 3 + """ + n = self.n + return n + + def basic_root(self, i, j): + """Generate roots with 1 in ith position and a -1 in jth position + """ + n = self.n + root = [0]*n + root[i] = 1 + root[j] = -1 + return root + + def simple_root(self, i): + """The ith simple root for the C series + + Every lie algebra has a unique root system. + Given a root system Q, there is a subset of the + roots such that an element of Q is called a + simple root if it cannot be written as the sum + of two elements in Q. If we let D denote the + set of simple roots, then it is clear that every + element of Q can be written as a linear combination + of elements of D with all coefficients non-negative. + + In C_n, the first n-1 simple roots are the same as + the roots in A_(n-1) (a 1 in the ith position, a -1 + in the (i+1)th position, and zeroes elsewhere). The + nth simple root is the root in which there is a 2 in + the nth position and zeroes elsewhere. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("C3") + >>> c.simple_root(2) + [0, 1, -1] + + """ + + n = self.n + if i < n: + return self.basic_root(i-1,i) + else: + root = [0]*self.n + root[n-1] = 2 + return root + + + def positive_roots(self): + """Generates all the positive roots of A_n + + This is half of all of the roots of C_n; by multiplying all the + positive roots by -1 we get the negative roots. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A3") + >>> c.positive_roots() + {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], + 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} + + """ + + n = self.n + posroots = {} + k = 0 + for i in range(0, n-1): + for j in range(i+1, n): + k += 1 + posroots[k] = self.basic_root(i, j) + k += 1 + root = self.basic_root(i, j) + root[j] = 1 + posroots[k] = root + + for i in range(0, n): + k += 1 + root = [0]*n + root[i] = 2 + posroots[k] = root + + return posroots + + def roots(self): + """ + Returns the total number of roots for C_n" + """ + + n = self.n + return 2*(n**2) + + def cartan_matrix(self): + """The Cartan matrix for C_n + + The Cartan matrix matrix for a Lie algebra is + generated by assigning an ordering to the simple + roots, (alpha[1], ...., alpha[l]). Then the ijth + entry of the Cartan matrix is (). + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType('C4') + >>> c.cartan_matrix() + Matrix([ + [ 2, -1, 0, 0], + [-1, 2, -1, 0], + [ 0, -1, 2, -1], + [ 0, 0, -2, 2]]) + + """ + + n = self.n + m = 2 * eye(n) + for i in range(1, n - 1): + m[i, i+1] = -1 + m[i, i-1] = -1 + m[0,1] = -1 + m[n-1, n-2] = -2 + return m + + + def basis(self): + """ + Returns the number of independent generators of C_n + """ + + n = self.n + return n*(2*n + 1) + + def lie_algebra(self): + """ + Returns the Lie algebra associated with C_n" + """ + + n = self.n + return "sp(" + str(2*n) + ")" + + def dynkin_diagram(self): + n = self.n + diag = "---".join("0" for i in range(1, n)) + "=<=0\n" + diag += " ".join(str(i) for i in range(1, n+1)) + return diag diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_d.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_d.py new file mode 100644 index 0000000000000000000000000000000000000000..9450d76e906c79e23db0ce223ed0de03d71c1199 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_d.py @@ -0,0 +1,173 @@ +from .cartan_type import Standard_Cartan +from sympy.core.backend import eye + +class TypeD(Standard_Cartan): + + def __new__(cls, n): + if n < 3: + raise ValueError("n cannot be less than 3") + return Standard_Cartan.__new__(cls, "D", n) + + + def dimension(self): + """Dmension of the vector space V underlying the Lie algebra + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("D4") + >>> c.dimension() + 4 + """ + + return self.n + + def basic_root(self, i, j): + """ + This is a method just to generate roots + with a 1 iin the ith position and a -1 + in the jth position. + + """ + + n = self.n + root = [0]*n + root[i] = 1 + root[j] = -1 + return root + + def simple_root(self, i): + """ + Every lie algebra has a unique root system. + Given a root system Q, there is a subset of the + roots such that an element of Q is called a + simple root if it cannot be written as the sum + of two elements in Q. If we let D denote the + set of simple roots, then it is clear that every + element of Q can be written as a linear combination + of elements of D with all coefficients non-negative. + + In D_n, the first n-1 simple roots are the same as + the roots in A_(n-1) (a 1 in the ith position, a -1 + in the (i+1)th position, and zeroes elsewhere). + The nth simple root is the root in which there 1s in + the nth and (n-1)th positions, and zeroes elsewhere. + + This method returns the ith simple root for the D series. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("D4") + >>> c.simple_root(2) + [0, 1, -1, 0] + + """ + + n = self.n + if i < n: + return self.basic_root(i-1, i) + else: + root = [0]*n + root[n-2] = 1 + root[n-1] = 1 + return root + + + def positive_roots(self): + """ + This method generates all the positive roots of + A_n. This is half of all of the roots of D_n + by multiplying all the positive roots by -1 we + get the negative roots. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A3") + >>> c.positive_roots() + {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], + 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} + """ + + n = self.n + posroots = {} + k = 0 + for i in range(0, n-1): + for j in range(i+1, n): + k += 1 + posroots[k] = self.basic_root(i, j) + k += 1 + root = self.basic_root(i, j) + root[j] = 1 + posroots[k] = root + return posroots + + def roots(self): + """ + Returns the total number of roots for D_n" + """ + + n = self.n + return 2*n*(n-1) + + def cartan_matrix(self): + """ + Returns the Cartan matrix for D_n. + The Cartan matrix matrix for a Lie algebra is + generated by assigning an ordering to the simple + roots, (alpha[1], ...., alpha[l]). Then the ijth + entry of the Cartan matrix is (). + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType('D4') + >>> c.cartan_matrix() + Matrix([ + [ 2, -1, 0, 0], + [-1, 2, -1, -1], + [ 0, -1, 2, 0], + [ 0, -1, 0, 2]]) + + """ + + n = self.n + m = 2*eye(n) + for i in range(1, n - 2): + m[i,i+1] = -1 + m[i,i-1] = -1 + m[n-2, n-3] = -1 + m[n-3, n-1] = -1 + m[n-1, n-3] = -1 + m[0, 1] = -1 + return m + + def basis(self): + """ + Returns the number of independent generators of D_n + """ + n = self.n + return n*(n-1)/2 + + def lie_algebra(self): + """ + Returns the Lie algebra associated with D_n" + """ + + n = self.n + return "so(" + str(2*n) + ")" + + def dynkin_diagram(self): + n = self.n + diag = " "*4*(n-3) + str(n-1) + "\n" + diag += " "*4*(n-3) + "0\n" + diag += " "*4*(n-3) +"|\n" + diag += " "*4*(n-3) + "|\n" + diag += "---".join("0" for i in range(1,n)) + "\n" + diag += " ".join(str(i) for i in range(1, n-1)) + " "+str(n) + return diag diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_e.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_e.py new file mode 100644 index 0000000000000000000000000000000000000000..3db9a820d31bff31acc58ba1592a1b10f8be53db --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_e.py @@ -0,0 +1,275 @@ +import itertools + +from .cartan_type import Standard_Cartan +from sympy.core.backend import eye, Rational +from sympy.core.singleton import S + +class TypeE(Standard_Cartan): + + def __new__(cls, n): + if n < 6 or n > 8: + raise ValueError("Invalid value of n") + return Standard_Cartan.__new__(cls, "E", n) + + def dimension(self): + """Dimension of the vector space V underlying the Lie algebra + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("E6") + >>> c.dimension() + 8 + """ + + return 8 + + def basic_root(self, i, j): + """ + This is a method just to generate roots + with a -1 in the ith position and a 1 + in the jth position. + + """ + + root = [0]*8 + root[i] = -1 + root[j] = 1 + return root + + def simple_root(self, i): + """ + Every Lie algebra has a unique root system. + Given a root system Q, there is a subset of the + roots such that an element of Q is called a + simple root if it cannot be written as the sum + of two elements in Q. If we let D denote the + set of simple roots, then it is clear that every + element of Q can be written as a linear combination + of elements of D with all coefficients non-negative. + + This method returns the ith simple root for E_n. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("E6") + >>> c.simple_root(2) + [1, 1, 0, 0, 0, 0, 0, 0] + """ + n = self.n + if i == 1: + root = [-0.5]*8 + root[0] = 0.5 + root[7] = 0.5 + return root + elif i == 2: + root = [0]*8 + root[1] = 1 + root[0] = 1 + return root + else: + if i in (7, 8) and n == 6: + raise ValueError("E6 only has six simple roots!") + if i == 8 and n == 7: + raise ValueError("E7 only has seven simple roots!") + + return self.basic_root(i - 3, i - 2) + + def positive_roots(self): + """ + This method generates all the positive roots of + A_n. This is half of all of the roots of E_n; + by multiplying all the positive roots by -1 we + get the negative roots. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A3") + >>> c.positive_roots() + {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], + 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} + """ + n = self.n + neghalf = Rational(-1, 2) + poshalf = S.Half + if n == 6: + posroots = {} + k = 0 + for i in range(n-1): + for j in range(i+1, n-1): + k += 1 + root = self.basic_root(i, j) + posroots[k] = root + k += 1 + root = self.basic_root(i, j) + root[i] = 1 + posroots[k] = root + + root = [poshalf, poshalf, poshalf, poshalf, poshalf, + neghalf, neghalf, poshalf] + for a, b, c, d, e in itertools.product( + range(2), range(2), range(2), range(2), range(2)): + if (a + b + c + d + e)%2 == 0: + k += 1 + if a == 1: + root[0] = neghalf + if b == 1: + root[1] = neghalf + if c == 1: + root[2] = neghalf + if d == 1: + root[3] = neghalf + if e == 1: + root[4] = neghalf + posroots[k] = root[:] + return posroots + if n == 7: + posroots = {} + k = 0 + for i in range(n-1): + for j in range(i+1, n-1): + k += 1 + root = self.basic_root(i, j) + posroots[k] = root + k += 1 + root = self.basic_root(i, j) + root[i] = 1 + posroots[k] = root + + k += 1 + posroots[k] = [0, 0, 0, 0, 0, 1, 1, 0] + root = [poshalf, poshalf, poshalf, poshalf, poshalf, + neghalf, neghalf, poshalf] + for a, b, c, d, e, f in itertools.product( + range(2), range(2), range(2), range(2), range(2), range(2)): + if (a + b + c + d + e + f)%2 == 0: + k += 1 + if a == 1: + root[0] = neghalf + if b == 1: + root[1] = neghalf + if c == 1: + root[2] = neghalf + if d == 1: + root[3] = neghalf + if e == 1: + root[4] = neghalf + if f == 1: + root[5] = poshalf + posroots[k] = root[:] + return posroots + if n == 8: + posroots = {} + k = 0 + for i in range(n): + for j in range(i+1, n): + k += 1 + root = self.basic_root(i, j) + posroots[k] = root + k += 1 + root = self.basic_root(i, j) + root[i] = 1 + posroots[k] = root + + root = [poshalf, poshalf, poshalf, poshalf, poshalf, + neghalf, neghalf, poshalf] + for a, b, c, d, e, f, g in itertools.product( + range(2), range(2), range(2), range(2), range(2), + range(2), range(2)): + if (a + b + c + d + e + f + g)%2 == 0: + k += 1 + if a == 1: + root[0] = neghalf + if b == 1: + root[1] = neghalf + if c == 1: + root[2] = neghalf + if d == 1: + root[3] = neghalf + if e == 1: + root[4] = neghalf + if f == 1: + root[5] = poshalf + if g == 1: + root[6] = poshalf + posroots[k] = root[:] + return posroots + + + + def roots(self): + """ + Returns the total number of roots of E_n + """ + + n = self.n + if n == 6: + return 72 + if n == 7: + return 126 + if n == 8: + return 240 + + + def cartan_matrix(self): + """ + Returns the Cartan matrix for G_2 + The Cartan matrix matrix for a Lie algebra is + generated by assigning an ordering to the simple + roots, (alpha[1], ...., alpha[l]). Then the ijth + entry of the Cartan matrix is (). + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType('A4') + >>> c.cartan_matrix() + Matrix([ + [ 2, -1, 0, 0], + [-1, 2, -1, 0], + [ 0, -1, 2, -1], + [ 0, 0, -1, 2]]) + + + """ + + n = self.n + m = 2*eye(n) + for i in range(3, n - 1): + m[i, i+1] = -1 + m[i, i-1] = -1 + m[0, 2] = m[2, 0] = -1 + m[1, 3] = m[3, 1] = -1 + m[2, 3] = -1 + m[n-1, n-2] = -1 + return m + + + def basis(self): + """ + Returns the number of independent generators of E_n + """ + + n = self.n + if n == 6: + return 78 + if n == 7: + return 133 + if n == 8: + return 248 + + def dynkin_diagram(self): + n = self.n + diag = " "*8 + str(2) + "\n" + diag += " "*8 + "0\n" + diag += " "*8 + "|\n" + diag += " "*8 + "|\n" + diag += "---".join("0" for i in range(1, n)) + "\n" + diag += "1 " + " ".join(str(i) for i in range(3, n+1)) + return diag diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_f.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_f.py new file mode 100644 index 0000000000000000000000000000000000000000..f04da557870f2cd21818cf69c454ef598e2ab65a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_f.py @@ -0,0 +1,162 @@ +from .cartan_type import Standard_Cartan +from sympy.core.backend import Matrix, Rational + + +class TypeF(Standard_Cartan): + + def __new__(cls, n): + if n != 4: + raise ValueError("n should be 4") + return Standard_Cartan.__new__(cls, "F", 4) + + def dimension(self): + """Dimension of the vector space V underlying the Lie algebra + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("F4") + >>> c.dimension() + 4 + """ + + return 4 + + + def basic_root(self, i, j): + """Generate roots with 1 in ith position and -1 in jth position + + """ + + n = self.n + root = [0]*n + root[i] = 1 + root[j] = -1 + return root + + def simple_root(self, i): + """The ith simple root of F_4 + + Every lie algebra has a unique root system. + Given a root system Q, there is a subset of the + roots such that an element of Q is called a + simple root if it cannot be written as the sum + of two elements in Q. If we let D denote the + set of simple roots, then it is clear that every + element of Q can be written as a linear combination + of elements of D with all coefficients non-negative. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("F4") + >>> c.simple_root(3) + [0, 0, 0, 1] + + """ + + if i < 3: + return self.basic_root(i-1, i) + if i == 3: + root = [0]*4 + root[3] = 1 + return root + if i == 4: + root = [Rational(-1, 2)]*4 + return root + + def positive_roots(self): + """Generate all the positive roots of A_n + + This is half of all of the roots of F_4; by multiplying all the + positive roots by -1 we get the negative roots. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A3") + >>> c.positive_roots() + {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], + 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} + + """ + + n = self.n + posroots = {} + k = 0 + for i in range(0, n-1): + for j in range(i+1, n): + k += 1 + posroots[k] = self.basic_root(i, j) + k += 1 + root = self.basic_root(i, j) + root[j] = 1 + posroots[k] = root + + for i in range(0, n): + k += 1 + root = [0]*n + root[i] = 1 + posroots[k] = root + + k += 1 + root = [Rational(1, 2)]*n + posroots[k] = root + for i in range(1, 4): + k += 1 + root = [Rational(1, 2)]*n + root[i] = Rational(-1, 2) + posroots[k] = root + + posroots[k+1] = [Rational(1, 2), Rational(1, 2), Rational(-1, 2), Rational(-1, 2)] + posroots[k+2] = [Rational(1, 2), Rational(-1, 2), Rational(1, 2), Rational(-1, 2)] + posroots[k+3] = [Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(1, 2)] + posroots[k+4] = [Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(-1, 2)] + + return posroots + + + def roots(self): + """ + Returns the total number of roots for F_4 + """ + return 48 + + def cartan_matrix(self): + """The Cartan matrix for F_4 + + The Cartan matrix matrix for a Lie algebra is + generated by assigning an ordering to the simple + roots, (alpha[1], ...., alpha[l]). Then the ijth + entry of the Cartan matrix is (). + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType('A4') + >>> c.cartan_matrix() + Matrix([ + [ 2, -1, 0, 0], + [-1, 2, -1, 0], + [ 0, -1, 2, -1], + [ 0, 0, -1, 2]]) + """ + + m = Matrix( 4, 4, [2, -1, 0, 0, -1, 2, -2, 0, 0, + -1, 2, -1, 0, 0, -1, 2]) + return m + + def basis(self): + """ + Returns the number of independent generators of F_4 + """ + return 52 + + def dynkin_diagram(self): + diag = "0---0=>=0---0\n" + diag += " ".join(str(i) for i in range(1, 5)) + return diag diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_g.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_g.py new file mode 100644 index 0000000000000000000000000000000000000000..014409cf5ed966b53c596b14e0073e89ceee05b6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/type_g.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- + +from .cartan_type import Standard_Cartan +from sympy.core.backend import Matrix + +class TypeG(Standard_Cartan): + + def __new__(cls, n): + if n != 2: + raise ValueError("n should be 2") + return Standard_Cartan.__new__(cls, "G", 2) + + + def dimension(self): + """Dimension of the vector space V underlying the Lie algebra + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("G2") + >>> c.dimension() + 3 + """ + return 3 + + def simple_root(self, i): + """The ith simple root of G_2 + + Every lie algebra has a unique root system. + Given a root system Q, there is a subset of the + roots such that an element of Q is called a + simple root if it cannot be written as the sum + of two elements in Q. If we let D denote the + set of simple roots, then it is clear that every + element of Q can be written as a linear combination + of elements of D with all coefficients non-negative. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("G2") + >>> c.simple_root(1) + [0, 1, -1] + + """ + if i == 1: + return [0, 1, -1] + else: + return [1, -2, 1] + + def positive_roots(self): + """Generate all the positive roots of A_n + + This is half of all of the roots of A_n; by multiplying all the + positive roots by -1 we get the negative roots. + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("A3") + >>> c.positive_roots() + {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], + 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} + + """ + + roots = {1: [0, 1, -1], 2: [1, -2, 1], 3: [1, -1, 0], 4: [1, 0, 1], + 5: [1, 1, -2], 6: [2, -1, -1]} + return roots + + def roots(self): + """ + Returns the total number of roots of G_2" + """ + return 12 + + def cartan_matrix(self): + """The Cartan matrix for G_2 + + The Cartan matrix matrix for a Lie algebra is + generated by assigning an ordering to the simple + roots, (alpha[1], ...., alpha[l]). Then the ijth + entry of the Cartan matrix is (). + + Examples + ======== + + >>> from sympy.liealgebras.cartan_type import CartanType + >>> c = CartanType("G2") + >>> c.cartan_matrix() + Matrix([ + [ 2, -1], + [-3, 2]]) + + """ + + m = Matrix( 2, 2, [2, -1, -3, 2]) + return m + + def basis(self): + """ + Returns the number of independent generators of G_2 + """ + return 14 + + def dynkin_diagram(self): + diag = "0≡<≡0\n1 2" + return diag diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/weyl_group.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/weyl_group.py new file mode 100644 index 0000000000000000000000000000000000000000..15ff70b6f1fc4649268a38ee13e1f717a1c9f5fa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/liealgebras/weyl_group.py @@ -0,0 +1,403 @@ +# -*- coding: utf-8 -*- + +from .cartan_type import CartanType +from mpmath import fac +from sympy.core.backend import Matrix, eye, Rational, igcd +from sympy.core.basic import Atom + +class WeylGroup(Atom): + + """ + For each semisimple Lie group, we have a Weyl group. It is a subgroup of + the isometry group of the root system. Specifically, it's the subgroup + that is generated by reflections through the hyperplanes orthogonal to + the roots. Therefore, Weyl groups are reflection groups, and so a Weyl + group is a finite Coxeter group. + + """ + + def __new__(cls, cartantype): + obj = Atom.__new__(cls) + obj.cartan_type = CartanType(cartantype) + return obj + + def generators(self): + """ + This method creates the generating reflections of the Weyl group for + a given Lie algebra. For a Lie algebra of rank n, there are n + different generating reflections. This function returns them as + a list. + + Examples + ======== + + >>> from sympy.liealgebras.weyl_group import WeylGroup + >>> c = WeylGroup("F4") + >>> c.generators() + ['r1', 'r2', 'r3', 'r4'] + """ + n = self.cartan_type.rank() + generators = [] + for i in range(1, n+1): + reflection = "r"+str(i) + generators.append(reflection) + return generators + + def group_order(self): + """ + This method returns the order of the Weyl group. + For types A, B, C, D, and E the order depends on + the rank of the Lie algebra. For types F and G, + the order is fixed. + + Examples + ======== + + >>> from sympy.liealgebras.weyl_group import WeylGroup + >>> c = WeylGroup("D4") + >>> c.group_order() + 192.0 + """ + n = self.cartan_type.rank() + if self.cartan_type.series == "A": + return fac(n+1) + + if self.cartan_type.series in ("B", "C"): + return fac(n)*(2**n) + + if self.cartan_type.series == "D": + return fac(n)*(2**(n-1)) + + if self.cartan_type.series == "E": + if n == 6: + return 51840 + if n == 7: + return 2903040 + if n == 8: + return 696729600 + if self.cartan_type.series == "F": + return 1152 + + if self.cartan_type.series == "G": + return 12 + + def group_name(self): + """ + This method returns some general information about the Weyl group for + a given Lie algebra. It returns the name of the group and the elements + it acts on, if relevant. + """ + n = self.cartan_type.rank() + if self.cartan_type.series == "A": + return "S"+str(n+1) + ": the symmetric group acting on " + str(n+1) + " elements." + + if self.cartan_type.series in ("B", "C"): + return "The hyperoctahedral group acting on " + str(2*n) + " elements." + + if self.cartan_type.series == "D": + return "The symmetry group of the " + str(n) + "-dimensional demihypercube." + + if self.cartan_type.series == "E": + if n == 6: + return "The symmetry group of the 6-polytope." + + if n == 7: + return "The symmetry group of the 7-polytope." + + if n == 8: + return "The symmetry group of the 8-polytope." + + if self.cartan_type.series == "F": + return "The symmetry group of the 24-cell, or icositetrachoron." + + if self.cartan_type.series == "G": + return "D6, the dihedral group of order 12, and symmetry group of the hexagon." + + def element_order(self, weylelt): + """ + This method returns the order of a given Weyl group element, which should + be specified by the user in the form of products of the generating + reflections, i.e. of the form r1*r2 etc. + + For types A-F, this method current works by taking the matrix form of + the specified element, and then finding what power of the matrix is the + identity. It then returns this power. + + Examples + ======== + + >>> from sympy.liealgebras.weyl_group import WeylGroup + >>> b = WeylGroup("B4") + >>> b.element_order('r1*r4*r2') + 4 + """ + n = self.cartan_type.rank() + if self.cartan_type.series == "A": + a = self.matrix_form(weylelt) + order = 1 + while a != eye(n+1): + a *= self.matrix_form(weylelt) + order += 1 + return order + + if self.cartan_type.series == "D": + a = self.matrix_form(weylelt) + order = 1 + while a != eye(n): + a *= self.matrix_form(weylelt) + order += 1 + return order + + if self.cartan_type.series == "E": + a = self.matrix_form(weylelt) + order = 1 + while a != eye(8): + a *= self.matrix_form(weylelt) + order += 1 + return order + + if self.cartan_type.series == "G": + elts = list(weylelt) + reflections = elts[1::3] + m = self.delete_doubles(reflections) + while self.delete_doubles(m) != m: + m = self.delete_doubles(m) + reflections = m + if len(reflections) % 2 == 1: + return 2 + + elif len(reflections) == 0: + return 1 + + else: + if len(reflections) == 1: + return 2 + else: + m = len(reflections) // 2 + lcm = (6 * m)/ igcd(m, 6) + order = lcm / m + return order + + + if self.cartan_type.series == 'F': + a = self.matrix_form(weylelt) + order = 1 + while a != eye(4): + a *= self.matrix_form(weylelt) + order += 1 + return order + + + if self.cartan_type.series in ("B", "C"): + a = self.matrix_form(weylelt) + order = 1 + while a != eye(n): + a *= self.matrix_form(weylelt) + order += 1 + return order + + def delete_doubles(self, reflections): + """ + This is a helper method for determining the order of an element in the + Weyl group of G2. It takes a Weyl element and if repeated simple reflections + in it, it deletes them. + """ + counter = 0 + copy = list(reflections) + for elt in copy: + if counter < len(copy)-1: + if copy[counter + 1] == elt: + del copy[counter] + del copy[counter] + counter += 1 + + + return copy + + + def matrix_form(self, weylelt): + """ + This method takes input from the user in the form of products of the + generating reflections, and returns the matrix corresponding to the + element of the Weyl group. Since each element of the Weyl group is + a reflection of some type, there is a corresponding matrix representation. + This method uses the standard representation for all the generating + reflections. + + Examples + ======== + + >>> from sympy.liealgebras.weyl_group import WeylGroup + >>> f = WeylGroup("F4") + >>> f.matrix_form('r2*r3') + Matrix([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, -1], + [0, 0, 1, 0]]) + + """ + elts = list(weylelt) + reflections = elts[1::3] + n = self.cartan_type.rank() + if self.cartan_type.series == 'A': + matrixform = eye(n+1) + for elt in reflections: + a = int(elt) + mat = eye(n+1) + mat[a-1, a-1] = 0 + mat[a-1, a] = 1 + mat[a, a-1] = 1 + mat[a, a] = 0 + matrixform *= mat + return matrixform + + if self.cartan_type.series == 'D': + matrixform = eye(n) + for elt in reflections: + a = int(elt) + mat = eye(n) + if a < n: + mat[a-1, a-1] = 0 + mat[a-1, a] = 1 + mat[a, a-1] = 1 + mat[a, a] = 0 + matrixform *= mat + else: + mat[n-2, n-1] = -1 + mat[n-2, n-2] = 0 + mat[n-1, n-2] = -1 + mat[n-1, n-1] = 0 + matrixform *= mat + return matrixform + + if self.cartan_type.series == 'G': + matrixform = eye(3) + for elt in reflections: + a = int(elt) + if a == 1: + gen1 = Matrix([[1, 0, 0], [0, 0, 1], [0, 1, 0]]) + matrixform *= gen1 + else: + gen2 = Matrix([[Rational(2, 3), Rational(2, 3), Rational(-1, 3)], + [Rational(2, 3), Rational(-1, 3), Rational(2, 3)], + [Rational(-1, 3), Rational(2, 3), Rational(2, 3)]]) + matrixform *= gen2 + return matrixform + + if self.cartan_type.series == 'F': + matrixform = eye(4) + for elt in reflections: + a = int(elt) + if a == 1: + mat = Matrix([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) + matrixform *= mat + elif a == 2: + mat = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) + matrixform *= mat + elif a == 3: + mat = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]]) + matrixform *= mat + else: + + mat = Matrix([[Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2)], + [Rational(1, 2), Rational(1, 2), Rational(-1, 2), Rational(-1, 2)], + [Rational(1, 2), Rational(-1, 2), Rational(1, 2), Rational(-1, 2)], + [Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(1, 2)]]) + matrixform *= mat + return matrixform + + if self.cartan_type.series == 'E': + matrixform = eye(8) + for elt in reflections: + a = int(elt) + if a == 1: + mat = Matrix([[Rational(3, 4), Rational(1, 4), Rational(1, 4), Rational(1, 4), + Rational(1, 4), Rational(1, 4), Rational(1, 4), Rational(-1, 4)], + [Rational(1, 4), Rational(3, 4), Rational(-1, 4), Rational(-1, 4), + Rational(-1, 4), Rational(-1, 4), Rational(1, 4), Rational(-1, 4)], + [Rational(1, 4), Rational(-1, 4), Rational(3, 4), Rational(-1, 4), + Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(1, 4)], + [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(3, 4), + Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(1, 4)], + [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), + Rational(3, 4), Rational(-1, 4), Rational(-1, 4), Rational(1, 4)], + [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), + Rational(-1, 4), Rational(3, 4), Rational(-1, 4), Rational(1, 4)], + [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), + Rational(-1, 4), Rational(-1, 4), Rational(-3, 4), Rational(1, 4)], + [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), + Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(3, 4)]]) + matrixform *= mat + elif a == 2: + mat = eye(8) + mat[0, 0] = 0 + mat[0, 1] = -1 + mat[1, 0] = -1 + mat[1, 1] = 0 + matrixform *= mat + else: + mat = eye(8) + mat[a-3, a-3] = 0 + mat[a-3, a-2] = 1 + mat[a-2, a-3] = 1 + mat[a-2, a-2] = 0 + matrixform *= mat + return matrixform + + + if self.cartan_type.series in ("B", "C"): + matrixform = eye(n) + for elt in reflections: + a = int(elt) + mat = eye(n) + if a == 1: + mat[0, 0] = -1 + matrixform *= mat + else: + mat[a - 2, a - 2] = 0 + mat[a-2, a-1] = 1 + mat[a - 1, a - 2] = 1 + mat[a -1, a - 1] = 0 + matrixform *= mat + return matrixform + + + + def coxeter_diagram(self): + """ + This method returns the Coxeter diagram corresponding to a Weyl group. + The Coxeter diagram can be obtained from a Lie algebra's Dynkin diagram + by deleting all arrows; the Coxeter diagram is the undirected graph. + The vertices of the Coxeter diagram represent the generating reflections + of the Weyl group, $s_i$. An edge is drawn between $s_i$ and $s_j$ if the order + $m(i, j)$ of $s_is_j$ is greater than two. If there is one edge, the order + $m(i, j)$ is 3. If there are two edges, the order $m(i, j)$ is 4, and if there + are three edges, the order $m(i, j)$ is 6. + + Examples + ======== + + >>> from sympy.liealgebras.weyl_group import WeylGroup + >>> c = WeylGroup("B3") + >>> print(c.coxeter_diagram()) + 0---0===0 + 1 2 3 + """ + n = self.cartan_type.rank() + if self.cartan_type.series in ("A", "D", "E"): + return self.cartan_type.dynkin_diagram() + + if self.cartan_type.series in ("B", "C"): + diag = "---".join("0" for i in range(1, n)) + "===0\n" + diag += " ".join(str(i) for i in range(1, n+1)) + return diag + + if self.cartan_type.series == "F": + diag = "0---0===0---0\n" + diag += " ".join(str(i) for i in range(1, 5)) + return diag + + if self.cartan_type.series == "G": + diag = "0≡≡≡0\n1 2" + return diag diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..cb26903a384e9df3a0f02a92c488c5442cee1486 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/__init__.py @@ -0,0 +1,12 @@ +from .boolalg import (to_cnf, to_dnf, to_nnf, And, Or, Not, Xor, Nand, Nor, Implies, + Equivalent, ITE, POSform, SOPform, simplify_logic, bool_map, true, false, + gateinputcount) +from .inference import satisfiable + +__all__ = [ + 'to_cnf', 'to_dnf', 'to_nnf', 'And', 'Or', 'Not', 'Xor', 'Nand', 'Nor', + 'Implies', 'Equivalent', 'ITE', 'POSform', 'SOPform', 'simplify_logic', + 'bool_map', 'true', 'false', 'gateinputcount', + + 'satisfiable', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/boolalg.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/boolalg.py new file mode 100644 index 0000000000000000000000000000000000000000..8e11a9b6361ac5d7e355d5d4fb176d8df443e07e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/boolalg.py @@ -0,0 +1,3587 @@ +""" +Boolean algebra module for SymPy +""" + +from __future__ import annotations +from typing import TYPE_CHECKING, overload, Any +from collections.abc import Iterable, Mapping + +from collections import defaultdict +from itertools import chain, combinations, product, permutations +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core.containers import Tuple +from sympy.core.decorators import sympify_method_args, sympify_return +from sympy.core.function import Application, Derivative +from sympy.core.kind import BooleanKind, NumberKind +from sympy.core.numbers import Number +from sympy.core.operations import LatticeOp +from sympy.core.singleton import Singleton, S +from sympy.core.sorting import ordered +from sympy.core.sympify import _sympy_converter, _sympify, sympify +from sympy.utilities.iterables import sift, ibin +from sympy.utilities.misc import filldedent + + +def as_Boolean(e): + """Like ``bool``, return the Boolean value of an expression, e, + which can be any instance of :py:class:`~.Boolean` or ``bool``. + + Examples + ======== + + >>> from sympy import true, false, nan + >>> from sympy.logic.boolalg import as_Boolean + >>> from sympy.abc import x + >>> as_Boolean(0) is false + True + >>> as_Boolean(1) is true + True + >>> as_Boolean(x) + x + >>> as_Boolean(2) + Traceback (most recent call last): + ... + TypeError: expecting bool or Boolean, not `2`. + >>> as_Boolean(nan) + Traceback (most recent call last): + ... + TypeError: expecting bool or Boolean, not `nan`. + + """ + from sympy.core.symbol import Symbol + if e == True: + return true + if e == False: + return false + if isinstance(e, Symbol): + z = e.is_zero + if z is None: + return e + return false if z else true + if isinstance(e, Boolean): + return e + raise TypeError('expecting bool or Boolean, not `%s`.' % e) + + +@sympify_method_args +class Boolean(Basic): + """A Boolean object is an object for which logic operations make sense.""" + + __slots__ = () + + kind = BooleanKind + + if TYPE_CHECKING: + + def __new__(cls, *args: Basic | complex) -> Boolean: + ... + + @overload # type: ignore + def subs(self, arg1: Mapping[Basic | complex, Boolean | complex], arg2: None=None) -> Boolean: ... + @overload + def subs(self, arg1: Iterable[tuple[Basic | complex, Boolean | complex]], arg2: None=None, **kwargs: Any) -> Boolean: ... + @overload + def subs(self, arg1: Boolean | complex, arg2: Boolean | complex) -> Boolean: ... + @overload + def subs(self, arg1: Mapping[Basic | complex, Basic | complex], arg2: None=None, **kwargs: Any) -> Basic: ... + @overload + def subs(self, arg1: Iterable[tuple[Basic | complex, Basic | complex]], arg2: None=None, **kwargs: Any) -> Basic: ... + @overload + def subs(self, arg1: Basic | complex, arg2: Basic | complex, **kwargs: Any) -> Basic: ... + + def subs(self, arg1: Mapping[Basic | complex, Basic | complex] | Basic | complex, # type: ignore + arg2: Basic | complex | None = None, **kwargs: Any) -> Basic: + ... + + def simplify(self, **kwargs) -> Boolean: + ... + + @sympify_return([('other', 'Boolean')], NotImplemented) + def __and__(self, other): + return And(self, other) + + __rand__ = __and__ + + @sympify_return([('other', 'Boolean')], NotImplemented) + def __or__(self, other): + return Or(self, other) + + __ror__ = __or__ + + def __invert__(self): + """Overloading for ~""" + return Not(self) + + @sympify_return([('other', 'Boolean')], NotImplemented) + def __rshift__(self, other): + return Implies(self, other) + + @sympify_return([('other', 'Boolean')], NotImplemented) + def __lshift__(self, other): + return Implies(other, self) + + __rrshift__ = __lshift__ + __rlshift__ = __rshift__ + + @sympify_return([('other', 'Boolean')], NotImplemented) + def __xor__(self, other): + return Xor(self, other) + + __rxor__ = __xor__ + + def equals(self, other): + """ + Returns ``True`` if the given formulas have the same truth table. + For two formulas to be equal they must have the same literals. + + Examples + ======== + + >>> from sympy.abc import A, B, C + >>> from sympy import And, Or, Not + >>> (A >> B).equals(~B >> ~A) + True + >>> Not(And(A, B, C)).equals(And(Not(A), Not(B), Not(C))) + False + >>> Not(And(A, Not(A))).equals(Or(B, Not(B))) + False + + """ + from sympy.logic.inference import satisfiable + from sympy.core.relational import Relational + + if self.has(Relational) or other.has(Relational): + raise NotImplementedError('handling of relationals') + return self.atoms() == other.atoms() and \ + not satisfiable(Not(Equivalent(self, other))) + + def to_nnf(self, simplify=True): + # override where necessary + return self + + def as_set(self): + """ + Rewrites Boolean expression in terms of real sets. + + Examples + ======== + + >>> from sympy import Symbol, Eq, Or, And + >>> x = Symbol('x', real=True) + >>> Eq(x, 0).as_set() + {0} + >>> (x > 0).as_set() + Interval.open(0, oo) + >>> And(-2 < x, x < 2).as_set() + Interval.open(-2, 2) + >>> Or(x < -2, 2 < x).as_set() + Union(Interval.open(-oo, -2), Interval.open(2, oo)) + + """ + from sympy.calculus.util import periodicity + from sympy.core.relational import Relational + + free = self.free_symbols + if len(free) == 1: + x = free.pop() + if x.kind is NumberKind: + reps = {} + for r in self.atoms(Relational): + if periodicity(r, x) not in (0, None): + s = r._eval_as_set() + if s in (S.EmptySet, S.UniversalSet, S.Reals): + reps[r] = s.as_relational(x) + continue + raise NotImplementedError(filldedent(''' + as_set is not implemented for relationals + with periodic solutions + ''')) + new = self.subs(reps) + if new.func != self.func: + return new.as_set() # restart with new obj + else: + return new._eval_as_set() + + return self._eval_as_set() + else: + raise NotImplementedError("Sorry, as_set has not yet been" + " implemented for multivariate" + " expressions") + + @property + def binary_symbols(self): + from sympy.core.relational import Eq, Ne + return set().union(*[i.binary_symbols for i in self.args + if i.is_Boolean or i.is_Symbol + or isinstance(i, (Eq, Ne))]) + + def _eval_refine(self, assumptions): + from sympy.assumptions import ask + ret = ask(self, assumptions) + if ret is True: + return true + elif ret is False: + return false + return None + + +class BooleanAtom(Boolean): + """ + Base class of :py:class:`~.BooleanTrue` and :py:class:`~.BooleanFalse`. + """ + is_Boolean = True + is_Atom = True + _op_priority = 11 # higher than Expr + + def simplify(self, *a, **kw): + return self + + def expand(self, *a, **kw): + return self + + @property + def canonical(self): + return self + + def _noop(self, other=None): + raise TypeError('BooleanAtom not allowed in this context.') + + __add__ = _noop + __radd__ = _noop + __sub__ = _noop + __rsub__ = _noop + __mul__ = _noop + __rmul__ = _noop + __pow__ = _noop + __rpow__ = _noop + __truediv__ = _noop + __rtruediv__ = _noop + __mod__ = _noop + __rmod__ = _noop + _eval_power = _noop + + def __lt__(self, other): + raise TypeError(filldedent(''' + A Boolean argument can only be used in + Eq and Ne; all other relationals expect + real expressions. + ''')) + + __le__ = __lt__ + __gt__ = __lt__ + __ge__ = __lt__ + # \\\ + + def _eval_simplify(self, **kwargs): + return self + + +class BooleanTrue(BooleanAtom, metaclass=Singleton): + """ + SymPy version of ``True``, a singleton that can be accessed via ``S.true``. + + This is the SymPy version of ``True``, for use in the logic module. The + primary advantage of using ``true`` instead of ``True`` is that shorthand Boolean + operations like ``~`` and ``>>`` will work as expected on this class, whereas with + True they act bitwise on 1. Functions in the logic module will return this + class when they evaluate to true. + + Notes + ===== + + There is liable to be some confusion as to when ``True`` should + be used and when ``S.true`` should be used in various contexts + throughout SymPy. An important thing to remember is that + ``sympify(True)`` returns ``S.true``. This means that for the most + part, you can just use ``True`` and it will automatically be converted + to ``S.true`` when necessary, similar to how you can generally use 1 + instead of ``S.One``. + + The rule of thumb is: + + "If the boolean in question can be replaced by an arbitrary symbolic + ``Boolean``, like ``Or(x, y)`` or ``x > 1``, use ``S.true``. + Otherwise, use ``True``" + + In other words, use ``S.true`` only on those contexts where the + boolean is being used as a symbolic representation of truth. + For example, if the object ends up in the ``.args`` of any expression, + then it must necessarily be ``S.true`` instead of ``True``, as + elements of ``.args`` must be ``Basic``. On the other hand, + ``==`` is not a symbolic operation in SymPy, since it always returns + ``True`` or ``False``, and does so in terms of structural equality + rather than mathematical, so it should return ``True``. The assumptions + system should use ``True`` and ``False``. Aside from not satisfying + the above rule of thumb, the assumptions system uses a three-valued logic + (``True``, ``False``, ``None``), whereas ``S.true`` and ``S.false`` + represent a two-valued logic. When in doubt, use ``True``. + + "``S.true == True is True``." + + While "``S.true is True``" is ``False``, "``S.true == True``" + is ``True``, so if there is any doubt over whether a function or + expression will return ``S.true`` or ``True``, just use ``==`` + instead of ``is`` to do the comparison, and it will work in either + case. Finally, for boolean flags, it's better to just use ``if x`` + instead of ``if x is True``. To quote PEP 8: + + Do not compare boolean values to ``True`` or ``False`` + using ``==``. + + * Yes: ``if greeting:`` + * No: ``if greeting == True:`` + * Worse: ``if greeting is True:`` + + Examples + ======== + + >>> from sympy import sympify, true, false, Or + >>> sympify(True) + True + >>> _ is True, _ is true + (False, True) + + >>> Or(true, false) + True + >>> _ is true + True + + Python operators give a boolean result for true but a + bitwise result for True + + >>> ~true, ~True # doctest: +SKIP + (False, -2) + >>> true >> true, True >> True + (True, 0) + + See Also + ======== + + sympy.logic.boolalg.BooleanFalse + + """ + def __bool__(self): + return True + + def __hash__(self): + return hash(True) + + def __eq__(self, other): + if other is True: + return True + if other is False: + return False + return super().__eq__(other) + + @property + def negated(self): + return false + + def as_set(self): + """ + Rewrite logic operators and relationals in terms of real sets. + + Examples + ======== + + >>> from sympy import true + >>> true.as_set() + UniversalSet + + """ + return S.UniversalSet + + +class BooleanFalse(BooleanAtom, metaclass=Singleton): + """ + SymPy version of ``False``, a singleton that can be accessed via ``S.false``. + + This is the SymPy version of ``False``, for use in the logic module. The + primary advantage of using ``false`` instead of ``False`` is that shorthand + Boolean operations like ``~`` and ``>>`` will work as expected on this class, + whereas with ``False`` they act bitwise on 0. Functions in the logic module + will return this class when they evaluate to false. + + Notes + ====== + + See the notes section in :py:class:`sympy.logic.boolalg.BooleanTrue` + + Examples + ======== + + >>> from sympy import sympify, true, false, Or + >>> sympify(False) + False + >>> _ is False, _ is false + (False, True) + + >>> Or(true, false) + True + >>> _ is true + True + + Python operators give a boolean result for false but a + bitwise result for False + + >>> ~false, ~False # doctest: +SKIP + (True, -1) + >>> false >> false, False >> False + (True, 0) + + See Also + ======== + + sympy.logic.boolalg.BooleanTrue + + """ + def __bool__(self): + return False + + def __hash__(self): + return hash(False) + + def __eq__(self, other): + if other is True: + return False + if other is False: + return True + return super().__eq__(other) + + @property + def negated(self): + return true + + def as_set(self): + """ + Rewrite logic operators and relationals in terms of real sets. + + Examples + ======== + + >>> from sympy import false + >>> false.as_set() + EmptySet + """ + return S.EmptySet + + +true = BooleanTrue() +false = BooleanFalse() +# We want S.true and S.false to work, rather than S.BooleanTrue and +# S.BooleanFalse, but making the class and instance names the same causes some +# major issues (like the inability to import the class directly from this +# file). +S.true = true +S.false = false + +_sympy_converter[bool] = lambda x: true if x else false + + +class BooleanFunction(Application, Boolean): + """Boolean function is a function that lives in a boolean space + It is used as base class for :py:class:`~.And`, :py:class:`~.Or`, + :py:class:`~.Not`, etc. + """ + is_Boolean = True + + def _eval_simplify(self, **kwargs): + rv = simplify_univariate(self) + if not isinstance(rv, BooleanFunction): + return rv.simplify(**kwargs) + rv = rv.func(*[a.simplify(**kwargs) for a in rv.args]) + return simplify_logic(rv) + + def simplify(self, **kwargs): + from sympy.simplify.simplify import simplify + return simplify(self, **kwargs) + + def __lt__(self, other): + raise TypeError(filldedent(''' + A Boolean argument can only be used in + Eq and Ne; all other relationals expect + real expressions. + ''')) + __le__ = __lt__ + __ge__ = __lt__ + __gt__ = __lt__ + + @classmethod + def binary_check_and_simplify(self, *args): + return [as_Boolean(i) for i in args] + + def to_nnf(self, simplify=True): + return self._to_nnf(*self.args, simplify=simplify) + + def to_anf(self, deep=True): + return self._to_anf(*self.args, deep=deep) + + @classmethod + def _to_nnf(cls, *args, **kwargs): + simplify = kwargs.get('simplify', True) + argset = set() + for arg in args: + if not is_literal(arg): + arg = arg.to_nnf(simplify) + if simplify: + if isinstance(arg, cls): + arg = arg.args + else: + arg = (arg,) + for a in arg: + if Not(a) in argset: + return cls.zero + argset.add(a) + else: + argset.add(arg) + return cls(*argset) + + @classmethod + def _to_anf(cls, *args, **kwargs): + deep = kwargs.get('deep', True) + new_args = [] + for arg in args: + if deep: + if not is_literal(arg) or isinstance(arg, Not): + arg = arg.to_anf(deep=deep) + new_args.append(arg) + return cls(*new_args, remove_true=False) + + # the diff method below is copied from Expr class + def diff(self, *symbols, **assumptions): + assumptions.setdefault("evaluate", True) + return Derivative(self, *symbols, **assumptions) + + def _eval_derivative(self, x): + if x in self.binary_symbols: + from sympy.core.relational import Eq + from sympy.functions.elementary.piecewise import Piecewise + return Piecewise( + (0, Eq(self.subs(x, 0), self.subs(x, 1))), + (1, True)) + elif x in self.free_symbols: + # not implemented, see https://www.encyclopediaofmath.org/ + # index.php/Boolean_differential_calculus + pass + else: + return S.Zero + + +class And(LatticeOp, BooleanFunction): + """ + Logical AND function. + + It evaluates its arguments in order, returning false immediately + when an argument is false and true if they are all true. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import And + >>> x & y + x & y + + Notes + ===== + + The ``&`` operator is provided as a convenience, but note that its use + here is different from its normal use in Python, which is bitwise + and. Hence, ``And(a, b)`` and ``a & b`` will produce different results if + ``a`` and ``b`` are integers. + + >>> And(x, y).subs(x, 1) + y + + """ + zero = false + identity = true + + nargs = None + + if TYPE_CHECKING: + + def __new__(cls, *args: Boolean | bool) -> Boolean: # type: ignore + ... + + @property + def args(self) -> tuple[Boolean, ...]: + ... + + @classmethod + def _new_args_filter(cls, args): + args = BooleanFunction.binary_check_and_simplify(*args) + args = LatticeOp._new_args_filter(args, And) + newargs = [] + rel = set() + for x in ordered(args): + if x.is_Relational: + c = x.canonical + if c in rel: + continue + elif c.negated.canonical in rel: + return [false] + else: + rel.add(c) + newargs.append(x) + return newargs + + def _eval_subs(self, old, new): + args = [] + bad = None + for i in self.args: + try: + i = i.subs(old, new) + except TypeError: + # store TypeError + if bad is None: + bad = i + continue + if i == False: + return false + elif i != True: + args.append(i) + if bad is not None: + # let it raise + bad.subs(old, new) + # If old is And, replace the parts of the arguments with new if all + # are there + if isinstance(old, And): + old_set = set(old.args) + if old_set.issubset(args): + args = set(args) - old_set + args.add(new) + + return self.func(*args) + + def _eval_simplify(self, **kwargs): + from sympy.core.relational import Equality, Relational + from sympy.solvers.solveset import linear_coeffs + # standard simplify + rv = super()._eval_simplify(**kwargs) + if not isinstance(rv, And): + return rv + + # simplify args that are equalities involving + # symbols so x == 0 & x == y -> x==0 & y == 0 + Rel, nonRel = sift(rv.args, lambda i: isinstance(i, Relational), + binary=True) + if not Rel: + return rv + eqs, other = sift(Rel, lambda i: isinstance(i, Equality), binary=True) + + measure = kwargs['measure'] + if eqs: + ratio = kwargs['ratio'] + reps = {} + sifted = {} + # group by length of free symbols + sifted = sift(ordered([ + (i.free_symbols, i) for i in eqs]), + lambda x: len(x[0])) + eqs = [] + nonlineqs = [] + while 1 in sifted: + for free, e in sifted.pop(1): + x = free.pop() + if (e.lhs != x or x in e.rhs.free_symbols) and x not in reps: + try: + m, b = linear_coeffs( + Add(e.lhs, -e.rhs, evaluate=False), x) + enew = e.func(x, -b/m) + if measure(enew) <= ratio*measure(e): + e = enew + else: + eqs.append(e) + continue + except ValueError: + pass + if x in reps: + eqs.append(e.subs(x, reps[x])) + elif e.lhs == x and x not in e.rhs.free_symbols: + reps[x] = e.rhs + eqs.append(e) + else: + # x is not yet identified, but may be later + nonlineqs.append(e) + resifted = defaultdict(list) + for k in sifted: + for f, e in sifted[k]: + e = e.xreplace(reps) + f = e.free_symbols + resifted[len(f)].append((f, e)) + sifted = resifted + for k in sifted: + eqs.extend([e for f, e in sifted[k]]) + nonlineqs = [ei.subs(reps) for ei in nonlineqs] + other = [ei.subs(reps) for ei in other] + rv = rv.func(*([i.canonical for i in (eqs + nonlineqs + other)] + nonRel)) + patterns = _simplify_patterns_and() + threeterm_patterns = _simplify_patterns_and3() + return _apply_patternbased_simplification(rv, patterns, + measure, false, + threeterm_patterns=threeterm_patterns) + + def _eval_as_set(self): + from sympy.sets.sets import Intersection + return Intersection(*[arg.as_set() for arg in self.args]) + + def _eval_rewrite_as_Nor(self, *args, **kwargs): + return Nor(*[Not(arg) for arg in self.args]) + + def to_anf(self, deep=True): + if deep: + result = And._to_anf(*self.args, deep=deep) + return distribute_xor_over_and(result) + return self + + +class Or(LatticeOp, BooleanFunction): + """ + Logical OR function + + It evaluates its arguments in order, returning true immediately + when an argument is true, and false if they are all false. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import Or + >>> x | y + x | y + + Notes + ===== + + The ``|`` operator is provided as a convenience, but note that its use + here is different from its normal use in Python, which is bitwise + or. Hence, ``Or(a, b)`` and ``a | b`` will return different things if + ``a`` and ``b`` are integers. + + >>> Or(x, y).subs(x, 0) + y + + """ + zero = true + identity = false + + if TYPE_CHECKING: + + def __new__(cls, *args: Boolean | bool) -> Boolean: # type: ignore + ... + + @property + def args(self) -> tuple[Boolean, ...]: + ... + + @classmethod + def _new_args_filter(cls, args): + newargs = [] + rel = [] + args = BooleanFunction.binary_check_and_simplify(*args) + for x in args: + if x.is_Relational: + c = x.canonical + if c in rel: + continue + nc = c.negated.canonical + if any(r == nc for r in rel): + return [true] + rel.append(c) + newargs.append(x) + return LatticeOp._new_args_filter(newargs, Or) + + def _eval_subs(self, old, new): + args = [] + bad = None + for i in self.args: + try: + i = i.subs(old, new) + except TypeError: + # store TypeError + if bad is None: + bad = i + continue + if i == True: + return true + elif i != False: + args.append(i) + if bad is not None: + # let it raise + bad.subs(old, new) + # If old is Or, replace the parts of the arguments with new if all + # are there + if isinstance(old, Or): + old_set = set(old.args) + if old_set.issubset(args): + args = set(args) - old_set + args.add(new) + + return self.func(*args) + + def _eval_as_set(self): + from sympy.sets.sets import Union + return Union(*[arg.as_set() for arg in self.args]) + + def _eval_rewrite_as_Nand(self, *args, **kwargs): + return Nand(*[Not(arg) for arg in self.args]) + + def _eval_simplify(self, **kwargs): + from sympy.core.relational import Le, Ge, Eq + lege = self.atoms(Le, Ge) + if lege: + reps = {i: self.func( + Eq(i.lhs, i.rhs), i.strict) for i in lege} + return self.xreplace(reps)._eval_simplify(**kwargs) + # standard simplify + rv = super()._eval_simplify(**kwargs) + if not isinstance(rv, Or): + return rv + patterns = _simplify_patterns_or() + return _apply_patternbased_simplification(rv, patterns, + kwargs['measure'], true) + + def to_anf(self, deep=True): + args = range(1, len(self.args) + 1) + args = (combinations(self.args, j) for j in args) + args = chain.from_iterable(args) # powerset + args = (And(*arg) for arg in args) + args = (to_anf(x, deep=deep) if deep else x for x in args) + return Xor(*list(args), remove_true=False) + + +class Not(BooleanFunction): + """ + Logical Not function (negation) + + + Returns ``true`` if the statement is ``false`` or ``False``. + Returns ``false`` if the statement is ``true`` or ``True``. + + Examples + ======== + + >>> from sympy import Not, And, Or + >>> from sympy.abc import x, A, B + >>> Not(True) + False + >>> Not(False) + True + >>> Not(And(True, False)) + True + >>> Not(Or(True, False)) + False + >>> Not(And(And(True, x), Or(x, False))) + ~x + >>> ~x + ~x + >>> Not(And(Or(A, B), Or(~A, ~B))) + ~((A | B) & (~A | ~B)) + + Notes + ===== + + - The ``~`` operator is provided as a convenience, but note that its use + here is different from its normal use in Python, which is bitwise + not. In particular, ``~a`` and ``Not(a)`` will be different if ``a`` is + an integer. Furthermore, since bools in Python subclass from ``int``, + ``~True`` is the same as ``~1`` which is ``-2``, which has a boolean + value of True. To avoid this issue, use the SymPy boolean types + ``true`` and ``false``. + + - As of Python 3.12, the bitwise not operator ``~`` used on a + Python ``bool`` is deprecated and will emit a warning. + + >>> from sympy import true + >>> ~True # doctest: +SKIP + -2 + >>> ~true + False + + """ + + is_Not = True + + @classmethod + def eval(cls, arg): + if isinstance(arg, Number) or arg in (True, False): + return false if arg else true + if arg.is_Not: + return arg.args[0] + # Simplify Relational objects. + if arg.is_Relational: + return arg.negated + + def _eval_as_set(self): + """ + Rewrite logic operators and relationals in terms of real sets. + + Examples + ======== + + >>> from sympy import Not, Symbol + >>> x = Symbol('x') + >>> Not(x > 0).as_set() + Interval(-oo, 0) + """ + return self.args[0].as_set().complement(S.Reals) + + def to_nnf(self, simplify=True): + if is_literal(self): + return self + + expr = self.args[0] + + func, args = expr.func, expr.args + + if func == And: + return Or._to_nnf(*[Not(arg) for arg in args], simplify=simplify) + + if func == Or: + return And._to_nnf(*[Not(arg) for arg in args], simplify=simplify) + + if func == Implies: + a, b = args + return And._to_nnf(a, Not(b), simplify=simplify) + + if func == Equivalent: + return And._to_nnf(Or(*args), Or(*[Not(arg) for arg in args]), + simplify=simplify) + + if func == Xor: + result = [] + for i in range(1, len(args)+1, 2): + for neg in combinations(args, i): + clause = [Not(s) if s in neg else s for s in args] + result.append(Or(*clause)) + return And._to_nnf(*result, simplify=simplify) + + if func == ITE: + a, b, c = args + return And._to_nnf(Or(a, Not(c)), Or(Not(a), Not(b)), simplify=simplify) + + raise ValueError("Illegal operator %s in expression" % func) + + def to_anf(self, deep=True): + return Xor._to_anf(true, self.args[0], deep=deep) + + +class Xor(BooleanFunction): + """ + Logical XOR (exclusive OR) function. + + + Returns True if an odd number of the arguments are True and the rest are + False. + + Returns False if an even number of the arguments are True and the rest are + False. + + Examples + ======== + + >>> from sympy.logic.boolalg import Xor + >>> from sympy import symbols + >>> x, y = symbols('x y') + >>> Xor(True, False) + True + >>> Xor(True, True) + False + >>> Xor(True, False, True, True, False) + True + >>> Xor(True, False, True, False) + False + >>> x ^ y + x ^ y + + Notes + ===== + + The ``^`` operator is provided as a convenience, but note that its use + here is different from its normal use in Python, which is bitwise xor. In + particular, ``a ^ b`` and ``Xor(a, b)`` will be different if ``a`` and + ``b`` are integers. + + >>> Xor(x, y).subs(y, 0) + x + + """ + def __new__(cls, *args, remove_true=True, **kwargs): + argset = set() + obj = super().__new__(cls, *args, **kwargs) + for arg in obj._args: + if isinstance(arg, Number) or arg in (True, False): + if arg: + arg = true + else: + continue + if isinstance(arg, Xor): + for a in arg.args: + argset.remove(a) if a in argset else argset.add(a) + elif arg in argset: + argset.remove(arg) + else: + argset.add(arg) + rel = [(r, r.canonical, r.negated.canonical) + for r in argset if r.is_Relational] + odd = False # is number of complimentary pairs odd? start 0 -> False + remove = [] + for i, (r, c, nc) in enumerate(rel): + for j in range(i + 1, len(rel)): + rj, cj = rel[j][:2] + if cj == nc: + odd = not odd + break + elif cj == c: + break + else: + continue + remove.append((r, rj)) + if odd: + argset.remove(true) if true in argset else argset.add(true) + for a, b in remove: + argset.remove(a) + argset.remove(b) + if len(argset) == 0: + return false + elif len(argset) == 1: + return argset.pop() + elif True in argset and remove_true: + argset.remove(True) + return Not(Xor(*argset)) + else: + obj._args = tuple(ordered(argset)) + obj._argset = frozenset(argset) + return obj + + # XXX: This should be cached on the object rather than using cacheit + # Maybe it can be computed in __new__? + @property # type: ignore + @cacheit + def args(self): + return tuple(ordered(self._argset)) + + def to_nnf(self, simplify=True): + args = [] + for i in range(0, len(self.args)+1, 2): + for neg in combinations(self.args, i): + clause = [Not(s) if s in neg else s for s in self.args] + args.append(Or(*clause)) + return And._to_nnf(*args, simplify=simplify) + + def _eval_rewrite_as_Or(self, *args, **kwargs): + a = self.args + return Or(*[_convert_to_varsSOP(x, self.args) + for x in _get_odd_parity_terms(len(a))]) + + def _eval_rewrite_as_And(self, *args, **kwargs): + a = self.args + return And(*[_convert_to_varsPOS(x, self.args) + for x in _get_even_parity_terms(len(a))]) + + def _eval_simplify(self, **kwargs): + # as standard simplify uses simplify_logic which writes things as + # And and Or, we only simplify the partial expressions before using + # patterns + rv = self.func(*[a.simplify(**kwargs) for a in self.args]) + rv = rv.to_anf() + if not isinstance(rv, Xor): # This shouldn't really happen here + return rv + patterns = _simplify_patterns_xor() + return _apply_patternbased_simplification(rv, patterns, + kwargs['measure'], None) + + def _eval_subs(self, old, new): + # If old is Xor, replace the parts of the arguments with new if all + # are there + if isinstance(old, Xor): + old_set = set(old.args) + if old_set.issubset(self.args): + args = set(self.args) - old_set + args.add(new) + return self.func(*args) + + +class Nand(BooleanFunction): + """ + Logical NAND function. + + It evaluates its arguments in order, giving True immediately if any + of them are False, and False if they are all True. + + Returns True if any of the arguments are False + Returns False if all arguments are True + + Examples + ======== + + >>> from sympy.logic.boolalg import Nand + >>> from sympy import symbols + >>> x, y = symbols('x y') + >>> Nand(False, True) + True + >>> Nand(True, True) + False + >>> Nand(x, y) + ~(x & y) + + """ + @classmethod + def eval(cls, *args): + return Not(And(*args)) + + +class Nor(BooleanFunction): + """ + Logical NOR function. + + It evaluates its arguments in order, giving False immediately if any + of them are True, and True if they are all False. + + Returns False if any argument is True + Returns True if all arguments are False + + Examples + ======== + + >>> from sympy.logic.boolalg import Nor + >>> from sympy import symbols + >>> x, y = symbols('x y') + + >>> Nor(True, False) + False + >>> Nor(True, True) + False + >>> Nor(False, True) + False + >>> Nor(False, False) + True + >>> Nor(x, y) + ~(x | y) + + """ + @classmethod + def eval(cls, *args): + return Not(Or(*args)) + + +class Xnor(BooleanFunction): + """ + Logical XNOR function. + + Returns False if an odd number of the arguments are True and the rest are + False. + + Returns True if an even number of the arguments are True and the rest are + False. + + Examples + ======== + + >>> from sympy.logic.boolalg import Xnor + >>> from sympy import symbols + >>> x, y = symbols('x y') + >>> Xnor(True, False) + False + >>> Xnor(True, True) + True + >>> Xnor(True, False, True, True, False) + False + >>> Xnor(True, False, True, False) + True + + """ + @classmethod + def eval(cls, *args): + return Not(Xor(*args)) + + +class Implies(BooleanFunction): + r""" + Logical implication. + + A implies B is equivalent to if A then B. Mathematically, it is written + as `A \Rightarrow B` and is equivalent to `\neg A \vee B` or ``~A | B``. + + Accepts two Boolean arguments; A and B. + Returns False if A is True and B is False + Returns True otherwise. + + Examples + ======== + + >>> from sympy.logic.boolalg import Implies + >>> from sympy import symbols + >>> x, y = symbols('x y') + + >>> Implies(True, False) + False + >>> Implies(False, False) + True + >>> Implies(True, True) + True + >>> Implies(False, True) + True + >>> x >> y + Implies(x, y) + >>> y << x + Implies(x, y) + + Notes + ===== + + The ``>>`` and ``<<`` operators are provided as a convenience, but note + that their use here is different from their normal use in Python, which is + bit shifts. Hence, ``Implies(a, b)`` and ``a >> b`` will return different + things if ``a`` and ``b`` are integers. In particular, since Python + considers ``True`` and ``False`` to be integers, ``True >> True`` will be + the same as ``1 >> 1``, i.e., 0, which has a truth value of False. To + avoid this issue, use the SymPy objects ``true`` and ``false``. + + >>> from sympy import true, false + >>> True >> False + 1 + >>> true >> false + False + + """ + @classmethod + def eval(cls, *args): + try: + newargs = [] + for x in args: + if isinstance(x, Number) or x in (0, 1): + newargs.append(bool(x)) + else: + newargs.append(x) + A, B = newargs + except ValueError: + raise ValueError( + "%d operand(s) used for an Implies " + "(pairs are required): %s" % (len(args), str(args))) + if A in (True, False) or B in (True, False): + return Or(Not(A), B) + elif A == B: + return true + elif A.is_Relational and B.is_Relational: + if A.canonical == B.canonical: + return true + if A.negated.canonical == B.canonical: + return B + else: + return Basic.__new__(cls, *args) + + def to_nnf(self, simplify=True): + a, b = self.args + return Or._to_nnf(Not(a), b, simplify=simplify) + + def to_anf(self, deep=True): + a, b = self.args + return Xor._to_anf(true, a, And(a, b), deep=deep) + + +class Equivalent(BooleanFunction): + """ + Equivalence relation. + + ``Equivalent(A, B)`` is True iff A and B are both True or both False. + + Returns True if all of the arguments are logically equivalent. + Returns False otherwise. + + For two arguments, this is equivalent to :py:class:`~.Xnor`. + + Examples + ======== + + >>> from sympy.logic.boolalg import Equivalent, And + >>> from sympy.abc import x + >>> Equivalent(False, False, False) + True + >>> Equivalent(True, False, False) + False + >>> Equivalent(x, And(x, True)) + True + + """ + def __new__(cls, *args, **options): + from sympy.core.relational import Relational + args = [_sympify(arg) for arg in args] + + argset = set(args) + for x in args: + if isinstance(x, Number) or x in [True, False]: # Includes 0, 1 + argset.discard(x) + argset.add(bool(x)) + rel = [] + for r in argset: + if isinstance(r, Relational): + rel.append((r, r.canonical, r.negated.canonical)) + remove = [] + for i, (r, c, nc) in enumerate(rel): + for j in range(i + 1, len(rel)): + rj, cj = rel[j][:2] + if cj == nc: + return false + elif cj == c: + remove.append((r, rj)) + break + for a, b in remove: + argset.remove(a) + argset.remove(b) + argset.add(True) + if len(argset) <= 1: + return true + if True in argset: + argset.discard(True) + return And(*argset) + if False in argset: + argset.discard(False) + return And(*[Not(arg) for arg in argset]) + _args = frozenset(argset) + obj = super().__new__(cls, _args) + obj._argset = _args + return obj + + # XXX: This should be cached on the object rather than using cacheit + # Maybe it can be computed in __new__? + @property # type: ignore + @cacheit + def args(self): + return tuple(ordered(self._argset)) + + def to_nnf(self, simplify=True): + args = [] + for a, b in zip(self.args, self.args[1:]): + args.append(Or(Not(a), b)) + args.append(Or(Not(self.args[-1]), self.args[0])) + return And._to_nnf(*args, simplify=simplify) + + def to_anf(self, deep=True): + a = And(*self.args) + b = And(*[to_anf(Not(arg), deep=False) for arg in self.args]) + b = distribute_xor_over_and(b) + return Xor._to_anf(a, b, deep=deep) + + +class ITE(BooleanFunction): + """ + If-then-else clause. + + ``ITE(A, B, C)`` evaluates and returns the result of B if A is true + else it returns the result of C. All args must be Booleans. + + From a logic gate perspective, ITE corresponds to a 2-to-1 multiplexer, + where A is the select signal. + + Examples + ======== + + >>> from sympy.logic.boolalg import ITE, And, Xor, Or + >>> from sympy.abc import x, y, z + >>> ITE(True, False, True) + False + >>> ITE(Or(True, False), And(True, True), Xor(True, True)) + True + >>> ITE(x, y, z) + ITE(x, y, z) + >>> ITE(True, x, y) + x + >>> ITE(False, x, y) + y + >>> ITE(x, y, y) + y + + Trying to use non-Boolean args will generate a TypeError: + + >>> ITE(True, [], ()) + Traceback (most recent call last): + ... + TypeError: expecting bool, Boolean or ITE, not `[]` + + """ + def __new__(cls, *args, **kwargs): + from sympy.core.relational import Eq, Ne + if len(args) != 3: + raise ValueError('expecting exactly 3 args') + a, b, c = args + # check use of binary symbols + if isinstance(a, (Eq, Ne)): + # in this context, we can evaluate the Eq/Ne + # if one arg is a binary symbol and the other + # is true/false + b, c = map(as_Boolean, (b, c)) + bin_syms = set().union(*[i.binary_symbols for i in (b, c)]) + if len(set(a.args) - bin_syms) == 1: + # one arg is a binary_symbols + _a = a + if a.lhs is true: + a = a.rhs + elif a.rhs is true: + a = a.lhs + elif a.lhs is false: + a = Not(a.rhs) + elif a.rhs is false: + a = Not(a.lhs) + else: + # binary can only equal True or False + a = false + if isinstance(_a, Ne): + a = Not(a) + else: + a, b, c = BooleanFunction.binary_check_and_simplify( + a, b, c) + rv = None + if kwargs.get('evaluate', True): + rv = cls.eval(a, b, c) + if rv is None: + rv = BooleanFunction.__new__(cls, a, b, c, evaluate=False) + return rv + + @classmethod + def eval(cls, *args): + from sympy.core.relational import Eq, Ne + # do the args give a singular result? + a, b, c = args + if isinstance(a, (Ne, Eq)): + _a = a + if true in a.args: + a = a.lhs if a.rhs is true else a.rhs + elif false in a.args: + a = Not(a.lhs) if a.rhs is false else Not(a.rhs) + else: + _a = None + if _a is not None and isinstance(_a, Ne): + a = Not(a) + if a is true: + return b + if a is false: + return c + if b == c: + return b + else: + # or maybe the results allow the answer to be expressed + # in terms of the condition + if b is true and c is false: + return a + if b is false and c is true: + return Not(a) + if [a, b, c] != args: + return cls(a, b, c, evaluate=False) + + def to_nnf(self, simplify=True): + a, b, c = self.args + return And._to_nnf(Or(Not(a), b), Or(a, c), simplify=simplify) + + def _eval_as_set(self): + return self.to_nnf().as_set() + + def _eval_rewrite_as_Piecewise(self, *args, **kwargs): + from sympy.functions.elementary.piecewise import Piecewise + return Piecewise((args[1], args[0]), (args[2], True)) + + +class Exclusive(BooleanFunction): + """ + True if only one or no argument is true. + + ``Exclusive(A, B, C)`` is equivalent to ``~(A & B) & ~(A & C) & ~(B & C)``. + + For two arguments, this is equivalent to :py:class:`~.Xor`. + + Examples + ======== + + >>> from sympy.logic.boolalg import Exclusive + >>> Exclusive(False, False, False) + True + >>> Exclusive(False, True, False) + True + >>> Exclusive(False, True, True) + False + + """ + @classmethod + def eval(cls, *args): + and_args = [] + for a, b in combinations(args, 2): + and_args.append(Not(And(a, b))) + return And(*and_args) + + +# end class definitions. Some useful methods + + +def conjuncts(expr): + """Return a list of the conjuncts in ``expr``. + + Examples + ======== + + >>> from sympy.logic.boolalg import conjuncts + >>> from sympy.abc import A, B + >>> conjuncts(A & B) + frozenset({A, B}) + >>> conjuncts(A | B) + frozenset({A | B}) + + """ + return And.make_args(expr) + + +def disjuncts(expr): + """Return a list of the disjuncts in ``expr``. + + Examples + ======== + + >>> from sympy.logic.boolalg import disjuncts + >>> from sympy.abc import A, B + >>> disjuncts(A | B) + frozenset({A, B}) + >>> disjuncts(A & B) + frozenset({A & B}) + + """ + return Or.make_args(expr) + + +def distribute_and_over_or(expr): + """ + Given a sentence ``expr`` consisting of conjunctions and disjunctions + of literals, return an equivalent sentence in CNF. + + Examples + ======== + + >>> from sympy.logic.boolalg import distribute_and_over_or, And, Or, Not + >>> from sympy.abc import A, B, C + >>> distribute_and_over_or(Or(A, And(Not(B), Not(C)))) + (A | ~B) & (A | ~C) + + """ + return _distribute((expr, And, Or)) + + +def distribute_or_over_and(expr): + """ + Given a sentence ``expr`` consisting of conjunctions and disjunctions + of literals, return an equivalent sentence in DNF. + + Note that the output is NOT simplified. + + Examples + ======== + + >>> from sympy.logic.boolalg import distribute_or_over_and, And, Or, Not + >>> from sympy.abc import A, B, C + >>> distribute_or_over_and(And(Or(Not(A), B), C)) + (B & C) | (C & ~A) + + """ + return _distribute((expr, Or, And)) + + +def distribute_xor_over_and(expr): + """ + Given a sentence ``expr`` consisting of conjunction and + exclusive disjunctions of literals, return an + equivalent exclusive disjunction. + + Note that the output is NOT simplified. + + Examples + ======== + + >>> from sympy.logic.boolalg import distribute_xor_over_and, And, Xor, Not + >>> from sympy.abc import A, B, C + >>> distribute_xor_over_and(And(Xor(Not(A), B), C)) + (B & C) ^ (C & ~A) + """ + return _distribute((expr, Xor, And)) + + +def _distribute(info): + """ + Distributes ``info[1]`` over ``info[2]`` with respect to ``info[0]``. + """ + if isinstance(info[0], info[2]): + for arg in info[0].args: + if isinstance(arg, info[1]): + conj = arg + break + else: + return info[0] + rest = info[2](*[a for a in info[0].args if a is not conj]) + return info[1](*list(map(_distribute, + [(info[2](c, rest), info[1], info[2]) + for c in conj.args])), remove_true=False) + elif isinstance(info[0], info[1]): + return info[1](*list(map(_distribute, + [(x, info[1], info[2]) + for x in info[0].args])), + remove_true=False) + else: + return info[0] + + +def to_anf(expr, deep=True): + r""" + Converts expr to Algebraic Normal Form (ANF). + + ANF is a canonical normal form, which means that two + equivalent formulas will convert to the same ANF. + + A logical expression is in ANF if it has the form + + .. math:: 1 \oplus a \oplus b \oplus ab \oplus abc + + i.e. it can be: + - purely true, + - purely false, + - conjunction of variables, + - exclusive disjunction. + + The exclusive disjunction can only contain true, variables + or conjunction of variables. No negations are permitted. + + If ``deep`` is ``False``, arguments of the boolean + expression are considered variables, i.e. only the + top-level expression is converted to ANF. + + Examples + ======== + >>> from sympy.logic.boolalg import And, Or, Not, Implies, Equivalent + >>> from sympy.logic.boolalg import to_anf + >>> from sympy.abc import A, B, C + >>> to_anf(Not(A)) + A ^ True + >>> to_anf(And(Or(A, B), Not(C))) + A ^ B ^ (A & B) ^ (A & C) ^ (B & C) ^ (A & B & C) + >>> to_anf(Implies(Not(A), Equivalent(B, C)), deep=False) + True ^ ~A ^ (~A & (Equivalent(B, C))) + + """ + expr = sympify(expr) + + if is_anf(expr): + return expr + return expr.to_anf(deep=deep) + + +def to_nnf(expr, simplify=True): + """ + Converts ``expr`` to Negation Normal Form (NNF). + + A logical expression is in NNF if it + contains only :py:class:`~.And`, :py:class:`~.Or` and :py:class:`~.Not`, + and :py:class:`~.Not` is applied only to literals. + If ``simplify`` is ``True``, the result contains no redundant clauses. + + Examples + ======== + + >>> from sympy.abc import A, B, C, D + >>> from sympy.logic.boolalg import Not, Equivalent, to_nnf + >>> to_nnf(Not((~A & ~B) | (C & D))) + (A | B) & (~C | ~D) + >>> to_nnf(Equivalent(A >> B, B >> A)) + (A | ~B | (A & ~B)) & (B | ~A | (B & ~A)) + + """ + if is_nnf(expr, simplify): + return expr + return expr.to_nnf(simplify) + + +def to_cnf(expr, simplify=False, force=False): + """ + Convert a propositional logical sentence ``expr`` to conjunctive normal + form: ``((A | ~B | ...) & (B | C | ...) & ...)``. + If ``simplify`` is ``True``, ``expr`` is evaluated to its simplest CNF + form using the Quine-McCluskey algorithm; this may take a long + time. If there are more than 8 variables the ``force`` flag must be set + to ``True`` to simplify (default is ``False``). + + Examples + ======== + + >>> from sympy.logic.boolalg import to_cnf + >>> from sympy.abc import A, B, D + >>> to_cnf(~(A | B) | D) + (D | ~A) & (D | ~B) + >>> to_cnf((A | B) & (A | ~A), True) + A | B + + """ + expr = sympify(expr) + if not isinstance(expr, BooleanFunction): + return expr + + if simplify: + if not force and len(_find_predicates(expr)) > 8: + raise ValueError(filldedent(''' + To simplify a logical expression with more + than 8 variables may take a long time and requires + the use of `force=True`.''')) + return simplify_logic(expr, 'cnf', True, force=force) + + # Don't convert unless we have to + if is_cnf(expr): + return expr + + expr = eliminate_implications(expr) + res = distribute_and_over_or(expr) + + return res + + +def to_dnf(expr, simplify=False, force=False): + """ + Convert a propositional logical sentence ``expr`` to disjunctive normal + form: ``((A & ~B & ...) | (B & C & ...) | ...)``. + If ``simplify`` is ``True``, ``expr`` is evaluated to its simplest DNF form using + the Quine-McCluskey algorithm; this may take a long + time. If there are more than 8 variables, the ``force`` flag must be set to + ``True`` to simplify (default is ``False``). + + Examples + ======== + + >>> from sympy.logic.boolalg import to_dnf + >>> from sympy.abc import A, B, C + >>> to_dnf(B & (A | C)) + (A & B) | (B & C) + >>> to_dnf((A & B) | (A & ~B) | (B & C) | (~B & C), True) + A | C + + """ + expr = sympify(expr) + if not isinstance(expr, BooleanFunction): + return expr + + if simplify: + if not force and len(_find_predicates(expr)) > 8: + raise ValueError(filldedent(''' + To simplify a logical expression with more + than 8 variables may take a long time and requires + the use of `force=True`.''')) + return simplify_logic(expr, 'dnf', True, force=force) + + # Don't convert unless we have to + if is_dnf(expr): + return expr + + expr = eliminate_implications(expr) + return distribute_or_over_and(expr) + + +def is_anf(expr): + r""" + Checks if ``expr`` is in Algebraic Normal Form (ANF). + + A logical expression is in ANF if it has the form + + .. math:: 1 \oplus a \oplus b \oplus ab \oplus abc + + i.e. it is purely true, purely false, conjunction of + variables or exclusive disjunction. The exclusive + disjunction can only contain true, variables or + conjunction of variables. No negations are permitted. + + Examples + ======== + + >>> from sympy.logic.boolalg import And, Not, Xor, true, is_anf + >>> from sympy.abc import A, B, C + >>> is_anf(true) + True + >>> is_anf(A) + True + >>> is_anf(And(A, B, C)) + True + >>> is_anf(Xor(A, Not(B))) + False + + """ + expr = sympify(expr) + + if is_literal(expr) and not isinstance(expr, Not): + return True + + if isinstance(expr, And): + for arg in expr.args: + if not arg.is_Symbol: + return False + return True + + elif isinstance(expr, Xor): + for arg in expr.args: + if isinstance(arg, And): + for a in arg.args: + if not a.is_Symbol: + return False + elif is_literal(arg): + if isinstance(arg, Not): + return False + else: + return False + return True + + else: + return False + + +def is_nnf(expr, simplified=True): + """ + Checks if ``expr`` is in Negation Normal Form (NNF). + + A logical expression is in NNF if it + contains only :py:class:`~.And`, :py:class:`~.Or` and :py:class:`~.Not`, + and :py:class:`~.Not` is applied only to literals. + If ``simplified`` is ``True``, checks if result contains no redundant clauses. + + Examples + ======== + + >>> from sympy.abc import A, B, C + >>> from sympy.logic.boolalg import Not, is_nnf + >>> is_nnf(A & B | ~C) + True + >>> is_nnf((A | ~A) & (B | C)) + False + >>> is_nnf((A | ~A) & (B | C), False) + True + >>> is_nnf(Not(A & B) | C) + False + >>> is_nnf((A >> B) & (B >> A)) + False + + """ + + expr = sympify(expr) + if is_literal(expr): + return True + + stack = [expr] + + while stack: + expr = stack.pop() + if expr.func in (And, Or): + if simplified: + args = expr.args + for arg in args: + if Not(arg) in args: + return False + stack.extend(expr.args) + + elif not is_literal(expr): + return False + + return True + + +def is_cnf(expr): + """ + Test whether or not an expression is in conjunctive normal form. + + Examples + ======== + + >>> from sympy.logic.boolalg import is_cnf + >>> from sympy.abc import A, B, C + >>> is_cnf(A | B | C) + True + >>> is_cnf(A & B & C) + True + >>> is_cnf((A & B) | C) + False + + """ + return _is_form(expr, And, Or) + + +def is_dnf(expr): + """ + Test whether or not an expression is in disjunctive normal form. + + Examples + ======== + + >>> from sympy.logic.boolalg import is_dnf + >>> from sympy.abc import A, B, C + >>> is_dnf(A | B | C) + True + >>> is_dnf(A & B & C) + True + >>> is_dnf((A & B) | C) + True + >>> is_dnf(A & (B | C)) + False + + """ + return _is_form(expr, Or, And) + + +def _is_form(expr, function1, function2): + """ + Test whether or not an expression is of the required form. + + """ + expr = sympify(expr) + + vals = function1.make_args(expr) if isinstance(expr, function1) else [expr] + for lit in vals: + if isinstance(lit, function2): + vals2 = function2.make_args(lit) if isinstance(lit, function2) else [lit] + for l in vals2: + if is_literal(l) is False: + return False + elif is_literal(lit) is False: + return False + + return True + + +def eliminate_implications(expr): + """ + Change :py:class:`~.Implies` and :py:class:`~.Equivalent` into + :py:class:`~.And`, :py:class:`~.Or`, and :py:class:`~.Not`. + That is, return an expression that is equivalent to ``expr``, but has only + ``&``, ``|``, and ``~`` as logical + operators. + + Examples + ======== + + >>> from sympy.logic.boolalg import Implies, Equivalent, \ + eliminate_implications + >>> from sympy.abc import A, B, C + >>> eliminate_implications(Implies(A, B)) + B | ~A + >>> eliminate_implications(Equivalent(A, B)) + (A | ~B) & (B | ~A) + >>> eliminate_implications(Equivalent(A, B, C)) + (A | ~C) & (B | ~A) & (C | ~B) + + """ + return to_nnf(expr, simplify=False) + + +def is_literal(expr): + """ + Returns True if expr is a literal, else False. + + Examples + ======== + + >>> from sympy import Or, Q + >>> from sympy.abc import A, B + >>> from sympy.logic.boolalg import is_literal + >>> is_literal(A) + True + >>> is_literal(~A) + True + >>> is_literal(Q.zero(A)) + True + >>> is_literal(A + B) + True + >>> is_literal(Or(A, B)) + False + + """ + from sympy.assumptions import AppliedPredicate + + if isinstance(expr, Not): + return is_literal(expr.args[0]) + elif expr in (True, False) or isinstance(expr, AppliedPredicate) or expr.is_Atom: + return True + elif not isinstance(expr, BooleanFunction) and all( + (isinstance(expr, AppliedPredicate) or a.is_Atom) for a in expr.args): + return True + return False + + +def to_int_repr(clauses, symbols): + """ + Takes clauses in CNF format and puts them into an integer representation. + + Examples + ======== + + >>> from sympy.logic.boolalg import to_int_repr + >>> from sympy.abc import x, y + >>> to_int_repr([x | y, y], [x, y]) == [{1, 2}, {2}] + True + + """ + + # Convert the symbol list into a dict + symbols = dict(zip(symbols, range(1, len(symbols) + 1))) + + def append_symbol(arg, symbols): + if isinstance(arg, Not): + return -symbols[arg.args[0]] + else: + return symbols[arg] + + return [{append_symbol(arg, symbols) for arg in Or.make_args(c)} + for c in clauses] + + +def term_to_integer(term): + """ + Return an integer corresponding to the base-2 digits given by *term*. + + Parameters + ========== + + term : a string or list of ones and zeros + + Examples + ======== + + >>> from sympy.logic.boolalg import term_to_integer + >>> term_to_integer([1, 0, 0]) + 4 + >>> term_to_integer('100') + 4 + + """ + + return int(''.join(list(map(str, list(term)))), 2) + + +integer_to_term = ibin # XXX could delete? + + +def truth_table(expr, variables, input=True): + """ + Return a generator of all possible configurations of the input variables, + and the result of the boolean expression for those values. + + Parameters + ========== + + expr : Boolean expression + + variables : list of variables + + input : bool (default ``True``) + Indicates whether to return the input combinations. + + Examples + ======== + + >>> from sympy.logic.boolalg import truth_table + >>> from sympy.abc import x,y + >>> table = truth_table(x >> y, [x, y]) + >>> for t in table: + ... print('{0} -> {1}'.format(*t)) + [0, 0] -> True + [0, 1] -> True + [1, 0] -> False + [1, 1] -> True + + >>> table = truth_table(x | y, [x, y]) + >>> list(table) + [([0, 0], False), ([0, 1], True), ([1, 0], True), ([1, 1], True)] + + If ``input`` is ``False``, ``truth_table`` returns only a list of truth values. + In this case, the corresponding input values of variables can be + deduced from the index of a given output. + + >>> from sympy.utilities.iterables import ibin + >>> vars = [y, x] + >>> values = truth_table(x >> y, vars, input=False) + >>> values = list(values) + >>> values + [True, False, True, True] + + >>> for i, value in enumerate(values): + ... print('{0} -> {1}'.format(list(zip( + ... vars, ibin(i, len(vars)))), value)) + [(y, 0), (x, 0)] -> True + [(y, 0), (x, 1)] -> False + [(y, 1), (x, 0)] -> True + [(y, 1), (x, 1)] -> True + + """ + variables = [sympify(v) for v in variables] + + expr = sympify(expr) + if not isinstance(expr, BooleanFunction) and not is_literal(expr): + return + + table = product((0, 1), repeat=len(variables)) + for term in table: + value = expr.xreplace(dict(zip(variables, term))) + + if input: + yield list(term), value + else: + yield value + + +def _check_pair(minterm1, minterm2): + """ + Checks if a pair of minterms differs by only one bit. If yes, returns + index, else returns `-1`. + """ + # Early termination seems to be faster than list comprehension, + # at least for large examples. + index = -1 + for x, i in enumerate(minterm1): # zip(minterm1, minterm2) is slower + if i != minterm2[x]: + if index == -1: + index = x + else: + return -1 + return index + + +def _convert_to_varsSOP(minterm, variables): + """ + Converts a term in the expansion of a function from binary to its + variable form (for SOP). + """ + temp = [variables[n] if val == 1 else Not(variables[n]) + for n, val in enumerate(minterm) if val != 3] + return And(*temp) + + +def _convert_to_varsPOS(maxterm, variables): + """ + Converts a term in the expansion of a function from binary to its + variable form (for POS). + """ + temp = [variables[n] if val == 0 else Not(variables[n]) + for n, val in enumerate(maxterm) if val != 3] + return Or(*temp) + + +def _convert_to_varsANF(term, variables): + """ + Converts a term in the expansion of a function from binary to its + variable form (for ANF). + + Parameters + ========== + + term : list of 1's and 0's (complementation pattern) + variables : list of variables + + """ + temp = [variables[n] for n, t in enumerate(term) if t == 1] + + if not temp: + return true + + return And(*temp) + + +def _get_odd_parity_terms(n): + """ + Returns a list of lists, with all possible combinations of n zeros and ones + with an odd number of ones. + """ + return [e for e in [ibin(i, n) for i in range(2**n)] if sum(e) % 2 == 1] + + +def _get_even_parity_terms(n): + """ + Returns a list of lists, with all possible combinations of n zeros and ones + with an even number of ones. + """ + return [e for e in [ibin(i, n) for i in range(2**n)] if sum(e) % 2 == 0] + + +def _simplified_pairs(terms): + """ + Reduces a set of minterms, if possible, to a simplified set of minterms + with one less variable in the terms using QM method. + """ + if not terms: + return [] + + simplified_terms = [] + todo = list(range(len(terms))) + + # Count number of ones as _check_pair can only potentially match if there + # is at most a difference of a single one + termdict = defaultdict(list) + for n, term in enumerate(terms): + ones = sum(1 for t in term if t == 1) + termdict[ones].append(n) + + variables = len(terms[0]) + for k in range(variables): + for i in termdict[k]: + for j in termdict[k+1]: + index = _check_pair(terms[i], terms[j]) + if index != -1: + # Mark terms handled + todo[i] = todo[j] = None + # Copy old term + newterm = terms[i][:] + # Set differing position to don't care + newterm[index] = 3 + # Add if not already there + if newterm not in simplified_terms: + simplified_terms.append(newterm) + + if simplified_terms: + # Further simplifications only among the new terms + simplified_terms = _simplified_pairs(simplified_terms) + + # Add remaining, non-simplified, terms + simplified_terms.extend([terms[i] for i in todo if i is not None]) + return simplified_terms + + +def _rem_redundancy(l1, terms): + """ + After the truth table has been sufficiently simplified, use the prime + implicant table method to recognize and eliminate redundant pairs, + and return the essential arguments. + """ + + if not terms: + return [] + + nterms = len(terms) + nl1 = len(l1) + + # Create dominating matrix + dommatrix = [[0]*nl1 for n in range(nterms)] + colcount = [0]*nl1 + rowcount = [0]*nterms + for primei, prime in enumerate(l1): + for termi, term in enumerate(terms): + # Check prime implicant covering term + if all(t == 3 or t == mt for t, mt in zip(prime, term)): + dommatrix[termi][primei] = 1 + colcount[primei] += 1 + rowcount[termi] += 1 + + # Keep track if anything changed + anythingchanged = True + # Then, go again + while anythingchanged: + anythingchanged = False + + for rowi in range(nterms): + # Still non-dominated? + if rowcount[rowi]: + row = dommatrix[rowi] + for row2i in range(nterms): + # Still non-dominated? + if rowi != row2i and rowcount[rowi] and (rowcount[rowi] <= rowcount[row2i]): + row2 = dommatrix[row2i] + if all(row2[n] >= row[n] for n in range(nl1)): + # row2 dominating row, remove row2 + rowcount[row2i] = 0 + anythingchanged = True + for primei, prime in enumerate(row2): + if prime: + # Make corresponding entry 0 + dommatrix[row2i][primei] = 0 + colcount[primei] -= 1 + + colcache = {} + + for coli in range(nl1): + # Still non-dominated? + if colcount[coli]: + if coli in colcache: + col = colcache[coli] + else: + col = [dommatrix[i][coli] for i in range(nterms)] + colcache[coli] = col + for col2i in range(nl1): + # Still non-dominated? + if coli != col2i and colcount[col2i] and (colcount[coli] >= colcount[col2i]): + if col2i in colcache: + col2 = colcache[col2i] + else: + col2 = [dommatrix[i][col2i] for i in range(nterms)] + colcache[col2i] = col2 + if all(col[n] >= col2[n] for n in range(nterms)): + # col dominating col2, remove col2 + colcount[col2i] = 0 + anythingchanged = True + for termi, term in enumerate(col2): + if term and dommatrix[termi][col2i]: + # Make corresponding entry 0 + dommatrix[termi][col2i] = 0 + rowcount[termi] -= 1 + + if not anythingchanged: + # Heuristically select the prime implicant covering most terms + maxterms = 0 + bestcolidx = -1 + for coli in range(nl1): + s = colcount[coli] + if s > maxterms: + bestcolidx = coli + maxterms = s + + # In case we found a prime implicant covering at least two terms + if bestcolidx != -1 and maxterms > 1: + for primei, prime in enumerate(l1): + if primei != bestcolidx: + for termi, term in enumerate(colcache[bestcolidx]): + if term and dommatrix[termi][primei]: + # Make corresponding entry 0 + dommatrix[termi][primei] = 0 + anythingchanged = True + rowcount[termi] -= 1 + colcount[primei] -= 1 + + return [l1[i] for i in range(nl1) if colcount[i]] + + +def _input_to_binlist(inputlist, variables): + binlist = [] + bits = len(variables) + for val in inputlist: + if isinstance(val, int): + binlist.append(ibin(val, bits)) + elif isinstance(val, dict): + nonspecvars = list(variables) + for key in val.keys(): + nonspecvars.remove(key) + for t in product((0, 1), repeat=len(nonspecvars)): + d = dict(zip(nonspecvars, t)) + d.update(val) + binlist.append([d[v] for v in variables]) + elif isinstance(val, (list, tuple)): + if len(val) != bits: + raise ValueError("Each term must contain {bits} bits as there are" + "\n{bits} variables (or be an integer)." + "".format(bits=bits)) + binlist.append(list(val)) + else: + raise TypeError("A term list can only contain lists," + " ints or dicts.") + return binlist + + +def SOPform(variables, minterms, dontcares=None): + """ + The SOPform function uses simplified_pairs and a redundant group- + eliminating algorithm to convert the list of all input combos that + generate '1' (the minterms) into the smallest sum-of-products form. + + The variables must be given as the first argument. + + Return a logical :py:class:`~.Or` function (i.e., the "sum of products" or + "SOP" form) that gives the desired outcome. If there are inputs that can + be ignored, pass them as a list, too. + + The result will be one of the (perhaps many) functions that satisfy + the conditions. + + Examples + ======== + + >>> from sympy.logic import SOPform + >>> from sympy import symbols + >>> w, x, y, z = symbols('w x y z') + >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], + ... [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]] + >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] + >>> SOPform([w, x, y, z], minterms, dontcares) + (y & z) | (~w & ~x) + + The terms can also be represented as integers: + + >>> minterms = [1, 3, 7, 11, 15] + >>> dontcares = [0, 2, 5] + >>> SOPform([w, x, y, z], minterms, dontcares) + (y & z) | (~w & ~x) + + They can also be specified using dicts, which does not have to be fully + specified: + + >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}] + >>> SOPform([w, x, y, z], minterms) + (x & ~w) | (y & z & ~x) + + Or a combination: + + >>> minterms = [4, 7, 11, [1, 1, 1, 1]] + >>> dontcares = [{w : 0, x : 0, y: 0}, 5] + >>> SOPform([w, x, y, z], minterms, dontcares) + (w & y & z) | (~w & ~y) | (x & z & ~w) + + See also + ======== + + POSform + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Quine-McCluskey_algorithm + .. [2] https://en.wikipedia.org/wiki/Don%27t-care_term + + """ + if not minterms: + return false + + variables = tuple(map(sympify, variables)) + + + minterms = _input_to_binlist(minterms, variables) + dontcares = _input_to_binlist((dontcares or []), variables) + for d in dontcares: + if d in minterms: + raise ValueError('%s in minterms is also in dontcares' % d) + + return _sop_form(variables, minterms, dontcares) + + +def _sop_form(variables, minterms, dontcares): + new = _simplified_pairs(minterms + dontcares) + essential = _rem_redundancy(new, minterms) + return Or(*[_convert_to_varsSOP(x, variables) for x in essential]) + + +def POSform(variables, minterms, dontcares=None): + """ + The POSform function uses simplified_pairs and a redundant-group + eliminating algorithm to convert the list of all input combinations + that generate '1' (the minterms) into the smallest product-of-sums form. + + The variables must be given as the first argument. + + Return a logical :py:class:`~.And` function (i.e., the "product of sums" + or "POS" form) that gives the desired outcome. If there are inputs that can + be ignored, pass them as a list, too. + + The result will be one of the (perhaps many) functions that satisfy + the conditions. + + Examples + ======== + + >>> from sympy.logic import POSform + >>> from sympy import symbols + >>> w, x, y, z = symbols('w x y z') + >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], + ... [1, 0, 1, 1], [1, 1, 1, 1]] + >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] + >>> POSform([w, x, y, z], minterms, dontcares) + z & (y | ~w) + + The terms can also be represented as integers: + + >>> minterms = [1, 3, 7, 11, 15] + >>> dontcares = [0, 2, 5] + >>> POSform([w, x, y, z], minterms, dontcares) + z & (y | ~w) + + They can also be specified using dicts, which does not have to be fully + specified: + + >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}] + >>> POSform([w, x, y, z], minterms) + (x | y) & (x | z) & (~w | ~x) + + Or a combination: + + >>> minterms = [4, 7, 11, [1, 1, 1, 1]] + >>> dontcares = [{w : 0, x : 0, y: 0}, 5] + >>> POSform([w, x, y, z], minterms, dontcares) + (w | x) & (y | ~w) & (z | ~y) + + See also + ======== + + SOPform + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Quine-McCluskey_algorithm + .. [2] https://en.wikipedia.org/wiki/Don%27t-care_term + + """ + if not minterms: + return false + + variables = tuple(map(sympify, variables)) + minterms = _input_to_binlist(minterms, variables) + dontcares = _input_to_binlist((dontcares or []), variables) + for d in dontcares: + if d in minterms: + raise ValueError('%s in minterms is also in dontcares' % d) + + maxterms = [] + for t in product((0, 1), repeat=len(variables)): + t = list(t) + if (t not in minterms) and (t not in dontcares): + maxterms.append(t) + + new = _simplified_pairs(maxterms + dontcares) + essential = _rem_redundancy(new, maxterms) + return And(*[_convert_to_varsPOS(x, variables) for x in essential]) + + +def ANFform(variables, truthvalues): + """ + The ANFform function converts the list of truth values to + Algebraic Normal Form (ANF). + + The variables must be given as the first argument. + + Return True, False, logical :py:class:`~.And` function (i.e., the + "Zhegalkin monomial") or logical :py:class:`~.Xor` function (i.e., + the "Zhegalkin polynomial"). When True and False + are represented by 1 and 0, respectively, then + :py:class:`~.And` is multiplication and :py:class:`~.Xor` is addition. + + Formally a "Zhegalkin monomial" is the product (logical + And) of a finite set of distinct variables, including + the empty set whose product is denoted 1 (True). + A "Zhegalkin polynomial" is the sum (logical Xor) of a + set of Zhegalkin monomials, with the empty set denoted + by 0 (False). + + Parameters + ========== + + variables : list of variables + truthvalues : list of 1's and 0's (result column of truth table) + + Examples + ======== + >>> from sympy.logic.boolalg import ANFform + >>> from sympy.abc import x, y + >>> ANFform([x], [1, 0]) + x ^ True + >>> ANFform([x, y], [0, 1, 1, 1]) + x ^ y ^ (x & y) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Zhegalkin_polynomial + + """ + + n_vars = len(variables) + n_values = len(truthvalues) + + if n_values != 2 ** n_vars: + raise ValueError("The number of truth values must be equal to 2^%d, " + "got %d" % (n_vars, n_values)) + + variables = tuple(map(sympify, variables)) + + coeffs = anf_coeffs(truthvalues) + terms = [] + + for i, t in enumerate(product((0, 1), repeat=n_vars)): + if coeffs[i] == 1: + terms.append(t) + + return Xor(*[_convert_to_varsANF(x, variables) for x in terms], + remove_true=False) + + +def anf_coeffs(truthvalues): + """ + Convert a list of truth values of some boolean expression + to the list of coefficients of the polynomial mod 2 (exclusive + disjunction) representing the boolean expression in ANF + (i.e., the "Zhegalkin polynomial"). + + There are `2^n` possible Zhegalkin monomials in `n` variables, since + each monomial is fully specified by the presence or absence of + each variable. + + We can enumerate all the monomials. For example, boolean + function with four variables ``(a, b, c, d)`` can contain + up to `2^4 = 16` monomials. The 13-th monomial is the + product ``a & b & d``, because 13 in binary is 1, 1, 0, 1. + + A given monomial's presence or absence in a polynomial corresponds + to that monomial's coefficient being 1 or 0 respectively. + + Examples + ======== + >>> from sympy.logic.boolalg import anf_coeffs, bool_monomial, Xor + >>> from sympy.abc import a, b, c + >>> truthvalues = [0, 1, 1, 0, 0, 1, 0, 1] + >>> coeffs = anf_coeffs(truthvalues) + >>> coeffs + [0, 1, 1, 0, 0, 0, 1, 0] + >>> polynomial = Xor(*[ + ... bool_monomial(k, [a, b, c]) + ... for k, coeff in enumerate(coeffs) if coeff == 1 + ... ]) + >>> polynomial + b ^ c ^ (a & b) + + """ + + s = '{:b}'.format(len(truthvalues)) + n = len(s) - 1 + + if len(truthvalues) != 2**n: + raise ValueError("The number of truth values must be a power of two, " + "got %d" % len(truthvalues)) + + coeffs = [[v] for v in truthvalues] + + for i in range(n): + tmp = [] + for j in range(2 ** (n-i-1)): + tmp.append(coeffs[2*j] + + list(map(lambda x, y: x^y, coeffs[2*j], coeffs[2*j+1]))) + coeffs = tmp + + return coeffs[0] + + +def bool_minterm(k, variables): + """ + Return the k-th minterm. + + Minterms are numbered by a binary encoding of the complementation + pattern of the variables. This convention assigns the value 1 to + the direct form and 0 to the complemented form. + + Parameters + ========== + + k : int or list of 1's and 0's (complementation pattern) + variables : list of variables + + Examples + ======== + + >>> from sympy.logic.boolalg import bool_minterm + >>> from sympy.abc import x, y, z + >>> bool_minterm([1, 0, 1], [x, y, z]) + x & z & ~y + >>> bool_minterm(6, [x, y, z]) + x & y & ~z + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Canonical_normal_form#Indexing_minterms + + """ + if isinstance(k, int): + k = ibin(k, len(variables)) + variables = tuple(map(sympify, variables)) + return _convert_to_varsSOP(k, variables) + + +def bool_maxterm(k, variables): + """ + Return the k-th maxterm. + + Each maxterm is assigned an index based on the opposite + conventional binary encoding used for minterms. The maxterm + convention assigns the value 0 to the direct form and 1 to + the complemented form. + + Parameters + ========== + + k : int or list of 1's and 0's (complementation pattern) + variables : list of variables + + Examples + ======== + >>> from sympy.logic.boolalg import bool_maxterm + >>> from sympy.abc import x, y, z + >>> bool_maxterm([1, 0, 1], [x, y, z]) + y | ~x | ~z + >>> bool_maxterm(6, [x, y, z]) + z | ~x | ~y + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Canonical_normal_form#Indexing_maxterms + + """ + if isinstance(k, int): + k = ibin(k, len(variables)) + variables = tuple(map(sympify, variables)) + return _convert_to_varsPOS(k, variables) + + +def bool_monomial(k, variables): + """ + Return the k-th monomial. + + Monomials are numbered by a binary encoding of the presence and + absences of the variables. This convention assigns the value + 1 to the presence of variable and 0 to the absence of variable. + + Each boolean function can be uniquely represented by a + Zhegalkin Polynomial (Algebraic Normal Form). The Zhegalkin + Polynomial of the boolean function with `n` variables can contain + up to `2^n` monomials. We can enumerate all the monomials. + Each monomial is fully specified by the presence or absence + of each variable. + + For example, boolean function with four variables ``(a, b, c, d)`` + can contain up to `2^4 = 16` monomials. The 13-th monomial is the + product ``a & b & d``, because 13 in binary is 1, 1, 0, 1. + + Parameters + ========== + + k : int or list of 1's and 0's + variables : list of variables + + Examples + ======== + >>> from sympy.logic.boolalg import bool_monomial + >>> from sympy.abc import x, y, z + >>> bool_monomial([1, 0, 1], [x, y, z]) + x & z + >>> bool_monomial(6, [x, y, z]) + x & y + + """ + if isinstance(k, int): + k = ibin(k, len(variables)) + variables = tuple(map(sympify, variables)) + return _convert_to_varsANF(k, variables) + + +def _find_predicates(expr): + """Helper to find logical predicates in BooleanFunctions. + + A logical predicate is defined here as anything within a BooleanFunction + that is not a BooleanFunction itself. + + """ + if not isinstance(expr, BooleanFunction): + return {expr} + return set().union(*(map(_find_predicates, expr.args))) + + +def simplify_logic(expr, form=None, deep=True, force=False, dontcare=None): + """ + This function simplifies a boolean function to its simplified version + in SOP or POS form. The return type is an :py:class:`~.Or` or + :py:class:`~.And` object in SymPy. + + Parameters + ========== + + expr : Boolean + + form : string (``'cnf'`` or ``'dnf'``) or ``None`` (default). + If ``'cnf'`` or ``'dnf'``, the simplest expression in the corresponding + normal form is returned; if ``None``, the answer is returned + according to the form with fewest args (in CNF by default). + + deep : bool (default ``True``) + Indicates whether to recursively simplify any + non-boolean functions contained within the input. + + force : bool (default ``False``) + As the simplifications require exponential time in the number + of variables, there is by default a limit on expressions with + 8 variables. When the expression has more than 8 variables + only symbolical simplification (controlled by ``deep``) is + made. By setting ``force`` to ``True``, this limit is removed. Be + aware that this can lead to very long simplification times. + + dontcare : Boolean + Optimize expression under the assumption that inputs where this + expression is true are don't care. This is useful in e.g. Piecewise + conditions, where later conditions do not need to consider inputs that + are converted by previous conditions. For example, if a previous + condition is ``And(A, B)``, the simplification of expr can be made + with don't cares for ``And(A, B)``. + + Examples + ======== + + >>> from sympy.logic import simplify_logic + >>> from sympy.abc import x, y, z + >>> b = (~x & ~y & ~z) | ( ~x & ~y & z) + >>> simplify_logic(b) + ~x & ~y + >>> simplify_logic(x | y, dontcare=y) + x + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Don%27t-care_term + + """ + + if form not in (None, 'cnf', 'dnf'): + raise ValueError("form can be cnf or dnf only") + expr = sympify(expr) + # check for quick exit if form is given: right form and all args are + # literal and do not involve Not + if form: + form_ok = False + if form == 'cnf': + form_ok = is_cnf(expr) + elif form == 'dnf': + form_ok = is_dnf(expr) + + if form_ok and all(is_literal(a) + for a in expr.args): + return expr + from sympy.core.relational import Relational + if deep: + variables = expr.atoms(Relational) + from sympy.simplify.simplify import simplify + s = tuple(map(simplify, variables)) + expr = expr.xreplace(dict(zip(variables, s))) + if not isinstance(expr, BooleanFunction): + return expr + # Replace Relationals with Dummys to possibly + # reduce the number of variables + repl = {} + undo = {} + from sympy.core.symbol import Dummy + variables = expr.atoms(Relational) + if dontcare is not None: + dontcare = sympify(dontcare) + variables.update(dontcare.atoms(Relational)) + while variables: + var = variables.pop() + if var.is_Relational: + d = Dummy() + undo[d] = var + repl[var] = d + nvar = var.negated + if nvar in variables: + repl[nvar] = Not(d) + variables.remove(nvar) + + expr = expr.xreplace(repl) + + if dontcare is not None: + dontcare = dontcare.xreplace(repl) + + # Get new variables after replacing + variables = _find_predicates(expr) + if not force and len(variables) > 8: + return expr.xreplace(undo) + if dontcare is not None: + # Add variables from dontcare + dcvariables = _find_predicates(dontcare) + variables.update(dcvariables) + # if too many restore to variables only + if not force and len(variables) > 8: + variables = _find_predicates(expr) + dontcare = None + # group into constants and variable values + c, v = sift(ordered(variables), lambda x: x in (True, False), binary=True) + variables = c + v + # standardize constants to be 1 or 0 in keeping with truthtable + c = [1 if i == True else 0 for i in c] + truthtable = _get_truthtable(v, expr, c) + if dontcare is not None: + dctruthtable = _get_truthtable(v, dontcare, c) + truthtable = [t for t in truthtable if t not in dctruthtable] + else: + dctruthtable = [] + big = len(truthtable) >= (2 ** (len(variables) - 1)) + if form == 'dnf' or form is None and big: + return _sop_form(variables, truthtable, dctruthtable).xreplace(undo) + return POSform(variables, truthtable, dctruthtable).xreplace(undo) + + +def _get_truthtable(variables, expr, const): + """ Return a list of all combinations leading to a True result for ``expr``. + """ + _variables = variables.copy() + def _get_tt(inputs): + if _variables: + v = _variables.pop() + tab = [[i[0].xreplace({v: false}), [0] + i[1]] for i in inputs if i[0] is not false] + tab.extend([[i[0].xreplace({v: true}), [1] + i[1]] for i in inputs if i[0] is not false]) + return _get_tt(tab) + return inputs + res = [const + k[1] for k in _get_tt([[expr, []]]) if k[0]] + if res == [[]]: + return [] + else: + return res + + +def _finger(eq): + """ + Assign a 5-item fingerprint to each symbol in the equation: + [ + # of times it appeared as a Symbol; + # of times it appeared as a Not(symbol); + # of times it appeared as a Symbol in an And or Or; + # of times it appeared as a Not(Symbol) in an And or Or; + a sorted tuple of tuples, (i, j, k), where i is the number of arguments + in an And or Or with which it appeared as a Symbol, and j is + the number of arguments that were Not(Symbol); k is the number + of times that (i, j) was seen. + ] + + Examples + ======== + + >>> from sympy.logic.boolalg import _finger as finger + >>> from sympy import And, Or, Not, Xor, to_cnf, symbols + >>> from sympy.abc import a, b, x, y + >>> eq = Or(And(Not(y), a), And(Not(y), b), And(x, y)) + >>> dict(finger(eq)) + {(0, 0, 1, 0, ((2, 0, 1),)): [x], + (0, 0, 1, 0, ((2, 1, 1),)): [a, b], + (0, 0, 1, 2, ((2, 0, 1),)): [y]} + >>> dict(finger(x & ~y)) + {(0, 1, 0, 0, ()): [y], (1, 0, 0, 0, ()): [x]} + + In the following, the (5, 2, 6) means that there were 6 Or + functions in which a symbol appeared as itself amongst 5 arguments in + which there were also 2 negated symbols, e.g. ``(a0 | a1 | a2 | ~a3 | ~a4)`` + is counted once for a0, a1 and a2. + + >>> dict(finger(to_cnf(Xor(*symbols('a:5'))))) + {(0, 0, 8, 8, ((5, 0, 1), (5, 2, 6), (5, 4, 1))): [a0, a1, a2, a3, a4]} + + The equation must not have more than one level of nesting: + + >>> dict(finger(And(Or(x, y), y))) + {(0, 0, 1, 0, ((2, 0, 1),)): [x], (1, 0, 1, 0, ((2, 0, 1),)): [y]} + >>> dict(finger(And(Or(x, And(a, x)), y))) + Traceback (most recent call last): + ... + NotImplementedError: unexpected level of nesting + + So y and x have unique fingerprints, but a and b do not. + """ + f = eq.free_symbols + d = dict(list(zip(f, [[0]*4 + [defaultdict(int)] for fi in f]))) + for a in eq.args: + if a.is_Symbol: + d[a][0] += 1 + elif a.is_Not: + d[a.args[0]][1] += 1 + else: + o = len(a.args), sum(isinstance(ai, Not) for ai in a.args) + for ai in a.args: + if ai.is_Symbol: + d[ai][2] += 1 + d[ai][-1][o] += 1 + elif ai.is_Not: + d[ai.args[0]][3] += 1 + else: + raise NotImplementedError('unexpected level of nesting') + inv = defaultdict(list) + for k, v in ordered(iter(d.items())): + v[-1] = tuple(sorted([i + (j,) for i, j in v[-1].items()])) + inv[tuple(v)].append(k) + return inv + + +def bool_map(bool1, bool2): + """ + Return the simplified version of *bool1*, and the mapping of variables + that makes the two expressions *bool1* and *bool2* represent the same + logical behaviour for some correspondence between the variables + of each. + If more than one mappings of this sort exist, one of them + is returned. + + For example, ``And(x, y)`` is logically equivalent to ``And(a, b)`` for + the mapping ``{x: a, y: b}`` or ``{x: b, y: a}``. + If no such mapping exists, return ``False``. + + Examples + ======== + + >>> from sympy import SOPform, bool_map, Or, And, Not, Xor + >>> from sympy.abc import w, x, y, z, a, b, c, d + >>> function1 = SOPform([x, z, y],[[1, 0, 1], [0, 0, 1]]) + >>> function2 = SOPform([a, b, c],[[1, 0, 1], [1, 0, 0]]) + >>> bool_map(function1, function2) + (y & ~z, {y: a, z: b}) + + The results are not necessarily unique, but they are canonical. Here, + ``(w, z)`` could be ``(a, d)`` or ``(d, a)``: + + >>> eq = Or(And(Not(y), w), And(Not(y), z), And(x, y)) + >>> eq2 = Or(And(Not(c), a), And(Not(c), d), And(b, c)) + >>> bool_map(eq, eq2) + ((x & y) | (w & ~y) | (z & ~y), {w: a, x: b, y: c, z: d}) + >>> eq = And(Xor(a, b), c, And(c,d)) + >>> bool_map(eq, eq.subs(c, x)) + (c & d & (a | b) & (~a | ~b), {a: a, b: b, c: d, d: x}) + + """ + + def match(function1, function2): + """Return the mapping that equates variables between two + simplified boolean expressions if possible. + + By "simplified" we mean that a function has been denested + and is either an And (or an Or) whose arguments are either + symbols (x), negated symbols (Not(x)), or Or (or an And) whose + arguments are only symbols or negated symbols. For example, + ``And(x, Not(y), Or(w, Not(z)))``. + + Basic.match is not robust enough (see issue 4835) so this is + a workaround that is valid for simplified boolean expressions + """ + + # do some quick checks + if function1.__class__ != function2.__class__: + return None # maybe simplification makes them the same? + if len(function1.args) != len(function2.args): + return None # maybe simplification makes them the same? + if function1.is_Symbol: + return {function1: function2} + + # get the fingerprint dictionaries + f1 = _finger(function1) + f2 = _finger(function2) + + # more quick checks + if len(f1) != len(f2): + return False + + # assemble the match dictionary if possible + matchdict = {} + for k in f1.keys(): + if k not in f2: + return False + if len(f1[k]) != len(f2[k]): + return False + for i, x in enumerate(f1[k]): + matchdict[x] = f2[k][i] + return matchdict + + a = simplify_logic(bool1) + b = simplify_logic(bool2) + m = match(a, b) + if m: + return a, m + return m + + +def _apply_patternbased_simplification(rv, patterns, measure, + dominatingvalue, + replacementvalue=None, + threeterm_patterns=None): + """ + Replace patterns of Relational + + Parameters + ========== + + rv : Expr + Boolean expression + + patterns : tuple + Tuple of tuples, with (pattern to simplify, simplified pattern) with + two terms. + + measure : function + Simplification measure. + + dominatingvalue : Boolean or ``None`` + The dominating value for the function of consideration. + For example, for :py:class:`~.And` ``S.false`` is dominating. + As soon as one expression is ``S.false`` in :py:class:`~.And`, + the whole expression is ``S.false``. + + replacementvalue : Boolean or ``None``, optional + The resulting value for the whole expression if one argument + evaluates to ``dominatingvalue``. + For example, for :py:class:`~.Nand` ``S.false`` is dominating, but + in this case the resulting value is ``S.true``. Default is ``None``. + If ``replacementvalue`` is ``None`` and ``dominatingvalue`` is not + ``None``, ``replacementvalue = dominatingvalue``. + + threeterm_patterns : tuple, optional + Tuple of tuples, with (pattern to simplify, simplified pattern) with + three terms. + + """ + from sympy.core.relational import Relational, _canonical + + if replacementvalue is None and dominatingvalue is not None: + replacementvalue = dominatingvalue + # Use replacement patterns for Relationals + Rel, nonRel = sift(rv.args, lambda i: isinstance(i, Relational), + binary=True) + if len(Rel) <= 1: + return rv + Rel, nonRealRel = sift(Rel, lambda i: not any(s.is_real is False + for s in i.free_symbols), + binary=True) + Rel = [i.canonical for i in Rel] + + if threeterm_patterns and len(Rel) >= 3: + Rel = _apply_patternbased_threeterm_simplification(Rel, + threeterm_patterns, rv.func, dominatingvalue, + replacementvalue, measure) + + Rel = _apply_patternbased_twoterm_simplification(Rel, patterns, + rv.func, dominatingvalue, replacementvalue, measure) + + rv = rv.func(*([_canonical(i) for i in ordered(Rel)] + + nonRel + nonRealRel)) + return rv + + +def _apply_patternbased_twoterm_simplification(Rel, patterns, func, + dominatingvalue, + replacementvalue, + measure): + """ Apply pattern-based two-term simplification.""" + from sympy.functions.elementary.miscellaneous import Min, Max + from sympy.core.relational import Ge, Gt, _Inequality + changed = True + while changed and len(Rel) >= 2: + changed = False + # Use only < or <= + Rel = [r.reversed if isinstance(r, (Ge, Gt)) else r for r in Rel] + # Sort based on ordered + Rel = list(ordered(Rel)) + # Eq and Ne must be tested reversed as well + rtmp = [(r, ) if isinstance(r, _Inequality) else (r, r.reversed) for r in Rel] + # Create a list of possible replacements + results = [] + # Try all combinations of possibly reversed relational + for ((i, pi), (j, pj)) in combinations(enumerate(rtmp), 2): + for pattern, simp in patterns: + res = [] + for p1, p2 in product(pi, pj): + # use SymPy matching + oldexpr = Tuple(p1, p2) + tmpres = oldexpr.match(pattern) + if tmpres: + res.append((tmpres, oldexpr)) + + if res: + for tmpres, oldexpr in res: + # we have a matching, compute replacement + np = simp.xreplace(tmpres) + if np == dominatingvalue: + # if dominatingvalue, the whole expression + # will be replacementvalue + return [replacementvalue] + # add replacement + if not isinstance(np, ITE) and not np.has(Min, Max): + # We only want to use ITE and Min/Max replacements if + # they simplify to a relational + costsaving = measure(func(*oldexpr.args)) - measure(np) + if costsaving > 0: + results.append((costsaving, ([i, j], np))) + if results: + # Sort results based on complexity + results = sorted(results, + key=lambda pair: pair[0], reverse=True) + # Replace the one providing most simplification + replacement = results[0][1] + idx, newrel = replacement + idx.sort() + # Remove the old relationals + for index in reversed(idx): + del Rel[index] + if dominatingvalue is None or newrel != Not(dominatingvalue): + # Insert the new one (no need to insert a value that will + # not affect the result) + if newrel.func == func: + for a in newrel.args: + Rel.append(a) + else: + Rel.append(newrel) + # We did change something so try again + changed = True + return Rel + + +def _apply_patternbased_threeterm_simplification(Rel, patterns, func, + dominatingvalue, + replacementvalue, + measure): + """ Apply pattern-based three-term simplification.""" + from sympy.functions.elementary.miscellaneous import Min, Max + from sympy.core.relational import Le, Lt, _Inequality + changed = True + while changed and len(Rel) >= 3: + changed = False + # Use only > or >= + Rel = [r.reversed if isinstance(r, (Le, Lt)) else r for r in Rel] + # Sort based on ordered + Rel = list(ordered(Rel)) + # Create a list of possible replacements + results = [] + # Eq and Ne must be tested reversed as well + rtmp = [(r, ) if isinstance(r, _Inequality) else (r, r.reversed) for r in Rel] + # Try all combinations of possibly reversed relational + for ((i, pi), (j, pj), (k, pk)) in permutations(enumerate(rtmp), 3): + for pattern, simp in patterns: + res = [] + for p1, p2, p3 in product(pi, pj, pk): + # use SymPy matching + oldexpr = Tuple(p1, p2, p3) + tmpres = oldexpr.match(pattern) + if tmpres: + res.append((tmpres, oldexpr)) + + if res: + for tmpres, oldexpr in res: + # we have a matching, compute replacement + np = simp.xreplace(tmpres) + if np == dominatingvalue: + # if dominatingvalue, the whole expression + # will be replacementvalue + return [replacementvalue] + # add replacement + if not isinstance(np, ITE) and not np.has(Min, Max): + # We only want to use ITE and Min/Max replacements if + # they simplify to a relational + costsaving = measure(func(*oldexpr.args)) - measure(np) + if costsaving > 0: + results.append((costsaving, ([i, j, k], np))) + if results: + # Sort results based on complexity + results = sorted(results, + key=lambda pair: pair[0], reverse=True) + # Replace the one providing most simplification + replacement = results[0][1] + idx, newrel = replacement + idx.sort() + # Remove the old relationals + for index in reversed(idx): + del Rel[index] + if dominatingvalue is None or newrel != Not(dominatingvalue): + # Insert the new one (no need to insert a value that will + # not affect the result) + if newrel.func == func: + for a in newrel.args: + Rel.append(a) + else: + Rel.append(newrel) + # We did change something so try again + changed = True + return Rel + + +@cacheit +def _simplify_patterns_and(): + """ Two-term patterns for And.""" + + from sympy.core import Wild + from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt + from sympy.functions.elementary.complexes import Abs + from sympy.functions.elementary.miscellaneous import Min, Max + a = Wild('a') + b = Wild('b') + c = Wild('c') + # Relationals patterns should be in alphabetical order + # (pattern1, pattern2, simplified) + # Do not use Ge, Gt + _matchers_and = ((Tuple(Eq(a, b), Lt(a, b)), false), + #(Tuple(Eq(a, b), Lt(b, a)), S.false), + #(Tuple(Le(b, a), Lt(a, b)), S.false), + #(Tuple(Lt(b, a), Le(a, b)), S.false), + (Tuple(Lt(b, a), Lt(a, b)), false), + (Tuple(Eq(a, b), Le(b, a)), Eq(a, b)), + #(Tuple(Eq(a, b), Le(a, b)), Eq(a, b)), + #(Tuple(Le(b, a), Lt(b, a)), Gt(a, b)), + (Tuple(Le(b, a), Le(a, b)), Eq(a, b)), + #(Tuple(Le(b, a), Ne(a, b)), Gt(a, b)), + #(Tuple(Lt(b, a), Ne(a, b)), Gt(a, b)), + (Tuple(Le(a, b), Lt(a, b)), Lt(a, b)), + (Tuple(Le(a, b), Ne(a, b)), Lt(a, b)), + (Tuple(Lt(a, b), Ne(a, b)), Lt(a, b)), + # Sign + (Tuple(Eq(a, b), Eq(a, -b)), And(Eq(a, S.Zero), Eq(b, S.Zero))), + # Min/Max/ITE + (Tuple(Le(b, a), Le(c, a)), Ge(a, Max(b, c))), + (Tuple(Le(b, a), Lt(c, a)), ITE(b > c, Ge(a, b), Gt(a, c))), + (Tuple(Lt(b, a), Lt(c, a)), Gt(a, Max(b, c))), + (Tuple(Le(a, b), Le(a, c)), Le(a, Min(b, c))), + (Tuple(Le(a, b), Lt(a, c)), ITE(b < c, Le(a, b), Lt(a, c))), + (Tuple(Lt(a, b), Lt(a, c)), Lt(a, Min(b, c))), + (Tuple(Le(a, b), Le(c, a)), ITE(Eq(b, c), Eq(a, b), ITE(b < c, false, And(Le(a, b), Ge(a, c))))), + (Tuple(Le(c, a), Le(a, b)), ITE(Eq(b, c), Eq(a, b), ITE(b < c, false, And(Le(a, b), Ge(a, c))))), + (Tuple(Lt(a, b), Lt(c, a)), ITE(b < c, false, And(Lt(a, b), Gt(a, c)))), + (Tuple(Lt(c, a), Lt(a, b)), ITE(b < c, false, And(Lt(a, b), Gt(a, c)))), + (Tuple(Le(a, b), Lt(c, a)), ITE(b <= c, false, And(Le(a, b), Gt(a, c)))), + (Tuple(Le(c, a), Lt(a, b)), ITE(b <= c, false, And(Lt(a, b), Ge(a, c)))), + (Tuple(Eq(a, b), Eq(a, c)), ITE(Eq(b, c), Eq(a, b), false)), + (Tuple(Lt(a, b), Lt(-b, a)), ITE(b > 0, Lt(Abs(a), b), false)), + (Tuple(Le(a, b), Le(-b, a)), ITE(b >= 0, Le(Abs(a), b), false)), + ) + return _matchers_and + + +@cacheit +def _simplify_patterns_and3(): + """ Three-term patterns for And.""" + + from sympy.core import Wild + from sympy.core.relational import Eq, Ge, Gt + + a = Wild('a') + b = Wild('b') + c = Wild('c') + # Relationals patterns should be in alphabetical order + # (pattern1, pattern2, pattern3, simplified) + # Do not use Le, Lt + _matchers_and = ((Tuple(Ge(a, b), Ge(b, c), Gt(c, a)), false), + (Tuple(Ge(a, b), Gt(b, c), Gt(c, a)), false), + (Tuple(Gt(a, b), Gt(b, c), Gt(c, a)), false), + # (Tuple(Ge(c, a), Gt(a, b), Gt(b, c)), S.false), + # Lower bound relations + # Commented out combinations that does not simplify + (Tuple(Ge(a, b), Ge(a, c), Ge(b, c)), And(Ge(a, b), Ge(b, c))), + (Tuple(Ge(a, b), Ge(a, c), Gt(b, c)), And(Ge(a, b), Gt(b, c))), + # (Tuple(Ge(a, b), Gt(a, c), Ge(b, c)), And(Ge(a, b), Ge(b, c))), + (Tuple(Ge(a, b), Gt(a, c), Gt(b, c)), And(Ge(a, b), Gt(b, c))), + # (Tuple(Gt(a, b), Ge(a, c), Ge(b, c)), And(Gt(a, b), Ge(b, c))), + (Tuple(Ge(a, c), Gt(a, b), Gt(b, c)), And(Gt(a, b), Gt(b, c))), + (Tuple(Ge(b, c), Gt(a, b), Gt(a, c)), And(Gt(a, b), Ge(b, c))), + (Tuple(Gt(a, b), Gt(a, c), Gt(b, c)), And(Gt(a, b), Gt(b, c))), + # Upper bound relations + # Commented out combinations that does not simplify + (Tuple(Ge(b, a), Ge(c, a), Ge(b, c)), And(Ge(c, a), Ge(b, c))), + (Tuple(Ge(b, a), Ge(c, a), Gt(b, c)), And(Ge(c, a), Gt(b, c))), + # (Tuple(Ge(b, a), Gt(c, a), Ge(b, c)), And(Gt(c, a), Ge(b, c))), + (Tuple(Ge(b, a), Gt(c, a), Gt(b, c)), And(Gt(c, a), Gt(b, c))), + # (Tuple(Gt(b, a), Ge(c, a), Ge(b, c)), And(Ge(c, a), Ge(b, c))), + (Tuple(Ge(c, a), Gt(b, a), Gt(b, c)), And(Ge(c, a), Gt(b, c))), + (Tuple(Ge(b, c), Gt(b, a), Gt(c, a)), And(Gt(c, a), Ge(b, c))), + (Tuple(Gt(b, a), Gt(c, a), Gt(b, c)), And(Gt(c, a), Gt(b, c))), + # Circular relation + (Tuple(Ge(a, b), Ge(b, c), Ge(c, a)), And(Eq(a, b), Eq(b, c))), + ) + return _matchers_and + + +@cacheit +def _simplify_patterns_or(): + """ Two-term patterns for Or.""" + + from sympy.core import Wild + from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt + from sympy.functions.elementary.complexes import Abs + from sympy.functions.elementary.miscellaneous import Min, Max + a = Wild('a') + b = Wild('b') + c = Wild('c') + # Relationals patterns should be in alphabetical order + # (pattern1, pattern2, simplified) + # Do not use Ge, Gt + _matchers_or = ((Tuple(Le(b, a), Le(a, b)), true), + #(Tuple(Le(b, a), Lt(a, b)), true), + (Tuple(Le(b, a), Ne(a, b)), true), + #(Tuple(Le(a, b), Lt(b, a)), true), + #(Tuple(Le(a, b), Ne(a, b)), true), + #(Tuple(Eq(a, b), Le(b, a)), Ge(a, b)), + #(Tuple(Eq(a, b), Lt(b, a)), Ge(a, b)), + (Tuple(Eq(a, b), Le(a, b)), Le(a, b)), + (Tuple(Eq(a, b), Lt(a, b)), Le(a, b)), + #(Tuple(Le(b, a), Lt(b, a)), Ge(a, b)), + (Tuple(Lt(b, a), Lt(a, b)), Ne(a, b)), + (Tuple(Lt(b, a), Ne(a, b)), Ne(a, b)), + (Tuple(Le(a, b), Lt(a, b)), Le(a, b)), + #(Tuple(Lt(a, b), Ne(a, b)), Ne(a, b)), + (Tuple(Eq(a, b), Ne(a, c)), ITE(Eq(b, c), true, Ne(a, c))), + (Tuple(Ne(a, b), Ne(a, c)), ITE(Eq(b, c), Ne(a, b), true)), + # Min/Max/ITE + (Tuple(Le(b, a), Le(c, a)), Ge(a, Min(b, c))), + #(Tuple(Ge(b, a), Ge(c, a)), Ge(Min(b, c), a)), + (Tuple(Le(b, a), Lt(c, a)), ITE(b > c, Lt(c, a), Le(b, a))), + (Tuple(Lt(b, a), Lt(c, a)), Gt(a, Min(b, c))), + #(Tuple(Gt(b, a), Gt(c, a)), Gt(Min(b, c), a)), + (Tuple(Le(a, b), Le(a, c)), Le(a, Max(b, c))), + #(Tuple(Le(b, a), Le(c, a)), Le(Max(b, c), a)), + (Tuple(Le(a, b), Lt(a, c)), ITE(b >= c, Le(a, b), Lt(a, c))), + (Tuple(Lt(a, b), Lt(a, c)), Lt(a, Max(b, c))), + #(Tuple(Lt(b, a), Lt(c, a)), Lt(Max(b, c), a)), + (Tuple(Le(a, b), Le(c, a)), ITE(b >= c, true, Or(Le(a, b), Ge(a, c)))), + (Tuple(Le(c, a), Le(a, b)), ITE(b >= c, true, Or(Le(a, b), Ge(a, c)))), + (Tuple(Lt(a, b), Lt(c, a)), ITE(b > c, true, Or(Lt(a, b), Gt(a, c)))), + (Tuple(Lt(c, a), Lt(a, b)), ITE(b > c, true, Or(Lt(a, b), Gt(a, c)))), + (Tuple(Le(a, b), Lt(c, a)), ITE(b >= c, true, Or(Le(a, b), Gt(a, c)))), + (Tuple(Le(c, a), Lt(a, b)), ITE(b >= c, true, Or(Lt(a, b), Ge(a, c)))), + (Tuple(Lt(b, a), Lt(a, -b)), ITE(b >= 0, Gt(Abs(a), b), true)), + (Tuple(Le(b, a), Le(a, -b)), ITE(b > 0, Ge(Abs(a), b), true)), + ) + return _matchers_or + + +@cacheit +def _simplify_patterns_xor(): + """ Two-term patterns for Xor.""" + + from sympy.functions.elementary.miscellaneous import Min, Max + from sympy.core import Wild + from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt + a = Wild('a') + b = Wild('b') + c = Wild('c') + # Relationals patterns should be in alphabetical order + # (pattern1, pattern2, simplified) + # Do not use Ge, Gt + _matchers_xor = (#(Tuple(Le(b, a), Lt(a, b)), true), + #(Tuple(Lt(b, a), Le(a, b)), true), + #(Tuple(Eq(a, b), Le(b, a)), Gt(a, b)), + #(Tuple(Eq(a, b), Lt(b, a)), Ge(a, b)), + (Tuple(Eq(a, b), Le(a, b)), Lt(a, b)), + (Tuple(Eq(a, b), Lt(a, b)), Le(a, b)), + (Tuple(Le(a, b), Lt(a, b)), Eq(a, b)), + (Tuple(Le(a, b), Le(b, a)), Ne(a, b)), + (Tuple(Le(b, a), Ne(a, b)), Le(a, b)), + # (Tuple(Lt(b, a), Lt(a, b)), Ne(a, b)), + (Tuple(Lt(b, a), Ne(a, b)), Lt(a, b)), + # (Tuple(Le(a, b), Lt(a, b)), Eq(a, b)), + # (Tuple(Le(a, b), Ne(a, b)), Ge(a, b)), + # (Tuple(Lt(a, b), Ne(a, b)), Gt(a, b)), + # Min/Max/ITE + (Tuple(Le(b, a), Le(c, a)), + And(Ge(a, Min(b, c)), Lt(a, Max(b, c)))), + (Tuple(Le(b, a), Lt(c, a)), + ITE(b > c, And(Gt(a, c), Lt(a, b)), + And(Ge(a, b), Le(a, c)))), + (Tuple(Lt(b, a), Lt(c, a)), + And(Gt(a, Min(b, c)), Le(a, Max(b, c)))), + (Tuple(Le(a, b), Le(a, c)), + And(Le(a, Max(b, c)), Gt(a, Min(b, c)))), + (Tuple(Le(a, b), Lt(a, c)), + ITE(b < c, And(Lt(a, c), Gt(a, b)), + And(Le(a, b), Ge(a, c)))), + (Tuple(Lt(a, b), Lt(a, c)), + And(Lt(a, Max(b, c)), Ge(a, Min(b, c)))), + ) + return _matchers_xor + + +def simplify_univariate(expr): + """return a simplified version of univariate boolean expression, else ``expr``""" + from sympy.functions.elementary.piecewise import Piecewise + from sympy.core.relational import Eq, Ne + if not isinstance(expr, BooleanFunction): + return expr + if expr.atoms(Eq, Ne): + return expr + c = expr + free = c.free_symbols + if len(free) != 1: + return c + x = free.pop() + ok, i = Piecewise((0, c), evaluate=False + )._intervals(x, err_on_Eq=True) + if not ok: + return c + if not i: + return false + args = [] + for a, b, _, _ in i: + if a is S.NegativeInfinity: + if b is S.Infinity: + c = true + else: + if c.subs(x, b) == True: + c = (x <= b) + else: + c = (x < b) + else: + incl_a = (c.subs(x, a) == True) + incl_b = (c.subs(x, b) == True) + if incl_a and incl_b: + if b.is_infinite: + c = (x >= a) + else: + c = And(a <= x, x <= b) + elif incl_a: + c = And(a <= x, x < b) + elif incl_b: + if b.is_infinite: + c = (x > a) + else: + c = And(a < x, x <= b) + else: + c = And(a < x, x < b) + args.append(c) + return Or(*args) + + +# Classes corresponding to logic gates +# Used in gateinputcount method +BooleanGates = (And, Or, Xor, Nand, Nor, Not, Xnor, ITE) + +def gateinputcount(expr): + """ + Return the total number of inputs for the logic gates realizing the + Boolean expression. + + Returns + ======= + + int + Number of gate inputs + + Note + ==== + + Not all Boolean functions count as gate here, only those that are + considered to be standard gates. These are: :py:class:`~.And`, + :py:class:`~.Or`, :py:class:`~.Xor`, :py:class:`~.Not`, and + :py:class:`~.ITE` (multiplexer). :py:class:`~.Nand`, :py:class:`~.Nor`, + and :py:class:`~.Xnor` will be evaluated to ``Not(And())`` etc. + + Examples + ======== + + >>> from sympy.logic import And, Or, Nand, Not, gateinputcount + >>> from sympy.abc import x, y, z + >>> expr = And(x, y) + >>> gateinputcount(expr) + 2 + >>> gateinputcount(Or(expr, z)) + 4 + + Note that ``Nand`` is automatically evaluated to ``Not(And())`` so + + >>> gateinputcount(Nand(x, y, z)) + 4 + >>> gateinputcount(Not(And(x, y, z))) + 4 + + Although this can be avoided by using ``evaluate=False`` + + >>> gateinputcount(Nand(x, y, z, evaluate=False)) + 3 + + Also note that a comparison will count as a Boolean variable: + + >>> gateinputcount(And(x > z, y >= 2)) + 2 + + As will a symbol: + >>> gateinputcount(x) + 0 + + """ + if not isinstance(expr, Boolean): + raise TypeError("Expression must be Boolean") + if isinstance(expr, BooleanGates): + return len(expr.args) + sum(gateinputcount(x) for x in expr.args) + return 0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/inference.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/inference.py new file mode 100644 index 0000000000000000000000000000000000000000..c3798231c09ae351ea7e7026d622b834fea3e3fa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/logic/inference.py @@ -0,0 +1,340 @@ +"""Inference in propositional logic""" + +from sympy.logic.boolalg import And, Not, conjuncts, to_cnf, BooleanFunction +from sympy.core.sorting import ordered +from sympy.core.sympify import sympify +from sympy.external.importtools import import_module + + +def literal_symbol(literal): + """ + The symbol in this literal (without the negation). + + Examples + ======== + + >>> from sympy.abc import A + >>> from sympy.logic.inference import literal_symbol + >>> literal_symbol(A) + A + >>> literal_symbol(~A) + A + + """ + + if literal is True or literal is False: + return literal + elif literal.is_Symbol: + return literal + elif literal.is_Not: + return literal_symbol(literal.args[0]) + else: + raise ValueError("Argument must be a boolean literal.") + + +def satisfiable(expr, algorithm=None, all_models=False, minimal=False, use_lra_theory=False): + """ + Check satisfiability of a propositional sentence. + Returns a model when it succeeds. + Returns {true: true} for trivially true expressions. + + On setting all_models to True, if given expr is satisfiable then + returns a generator of models. However, if expr is unsatisfiable + then returns a generator containing the single element False. + + Examples + ======== + + >>> from sympy.abc import A, B + >>> from sympy.logic.inference import satisfiable + >>> satisfiable(A & ~B) + {A: True, B: False} + >>> satisfiable(A & ~A) + False + >>> satisfiable(True) + {True: True} + >>> next(satisfiable(A & ~A, all_models=True)) + False + >>> models = satisfiable((A >> B) & B, all_models=True) + >>> next(models) + {A: False, B: True} + >>> next(models) + {A: True, B: True} + >>> def use_models(models): + ... for model in models: + ... if model: + ... # Do something with the model. + ... print(model) + ... else: + ... # Given expr is unsatisfiable. + ... print("UNSAT") + >>> use_models(satisfiable(A >> ~A, all_models=True)) + {A: False} + >>> use_models(satisfiable(A ^ A, all_models=True)) + UNSAT + + """ + if use_lra_theory: + if algorithm is not None and algorithm != "dpll2": + raise ValueError(f"Currently only dpll2 can handle using lra theory. {algorithm} is not handled.") + algorithm = "dpll2" + + if algorithm is None or algorithm == "pycosat": + pycosat = import_module('pycosat') + if pycosat is not None: + algorithm = "pycosat" + else: + if algorithm == "pycosat": + raise ImportError("pycosat module is not present") + # Silently fall back to dpll2 if pycosat + # is not installed + algorithm = "dpll2" + + if algorithm=="minisat22": + pysat = import_module('pysat') + if pysat is None: + algorithm = "dpll2" + + if algorithm=="z3": + z3 = import_module('z3') + if z3 is None: + algorithm = "dpll2" + + if algorithm == "dpll": + from sympy.logic.algorithms.dpll import dpll_satisfiable + return dpll_satisfiable(expr) + elif algorithm == "dpll2": + from sympy.logic.algorithms.dpll2 import dpll_satisfiable + return dpll_satisfiable(expr, all_models, use_lra_theory=use_lra_theory) + elif algorithm == "pycosat": + from sympy.logic.algorithms.pycosat_wrapper import pycosat_satisfiable + return pycosat_satisfiable(expr, all_models) + elif algorithm == "minisat22": + from sympy.logic.algorithms.minisat22_wrapper import minisat22_satisfiable + return minisat22_satisfiable(expr, all_models, minimal) + elif algorithm == "z3": + from sympy.logic.algorithms.z3_wrapper import z3_satisfiable + return z3_satisfiable(expr, all_models) + + raise NotImplementedError + + +def valid(expr): + """ + Check validity of a propositional sentence. + A valid propositional sentence is True under every assignment. + + Examples + ======== + + >>> from sympy.abc import A, B + >>> from sympy.logic.inference import valid + >>> valid(A | ~A) + True + >>> valid(A | B) + False + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Validity + + """ + return not satisfiable(Not(expr)) + + +def pl_true(expr, model=None, deep=False): + """ + Returns whether the given assignment is a model or not. + + If the assignment does not specify the value for every proposition, + this may return None to indicate 'not obvious'. + + Parameters + ========== + + model : dict, optional, default: {} + Mapping of symbols to boolean values to indicate assignment. + deep: boolean, optional, default: False + Gives the value of the expression under partial assignments + correctly. May still return None to indicate 'not obvious'. + + + Examples + ======== + + >>> from sympy.abc import A, B + >>> from sympy.logic.inference import pl_true + >>> pl_true( A & B, {A: True, B: True}) + True + >>> pl_true(A & B, {A: False}) + False + >>> pl_true(A & B, {A: True}) + >>> pl_true(A & B, {A: True}, deep=True) + >>> pl_true(A >> (B >> A)) + >>> pl_true(A >> (B >> A), deep=True) + True + >>> pl_true(A & ~A) + >>> pl_true(A & ~A, deep=True) + False + >>> pl_true(A & B & (~A | ~B), {A: True}) + >>> pl_true(A & B & (~A | ~B), {A: True}, deep=True) + False + + """ + + from sympy.core.symbol import Symbol + + boolean = (True, False) + + def _validate(expr): + if isinstance(expr, Symbol) or expr in boolean: + return True + if not isinstance(expr, BooleanFunction): + return False + return all(_validate(arg) for arg in expr.args) + + if expr in boolean: + return expr + expr = sympify(expr) + if not _validate(expr): + raise ValueError("%s is not a valid boolean expression" % expr) + if not model: + model = {} + model = {k: v for k, v in model.items() if v in boolean} + result = expr.subs(model) + if result in boolean: + return bool(result) + if deep: + model = dict.fromkeys(result.atoms(), True) + if pl_true(result, model): + if valid(result): + return True + else: + if not satisfiable(result): + return False + return None + + +def entails(expr, formula_set=None): + """ + Check whether the given expr_set entail an expr. + If formula_set is empty then it returns the validity of expr. + + Examples + ======== + + >>> from sympy.abc import A, B, C + >>> from sympy.logic.inference import entails + >>> entails(A, [A >> B, B >> C]) + False + >>> entails(C, [A >> B, B >> C, A]) + True + >>> entails(A >> B) + False + >>> entails(A >> (B >> A)) + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Logical_consequence + + """ + if formula_set: + formula_set = list(formula_set) + else: + formula_set = [] + formula_set.append(Not(expr)) + return not satisfiable(And(*formula_set)) + + +class KB: + """Base class for all knowledge bases""" + def __init__(self, sentence=None): + self.clauses_ = set() + if sentence: + self.tell(sentence) + + def tell(self, sentence): + raise NotImplementedError + + def ask(self, query): + raise NotImplementedError + + def retract(self, sentence): + raise NotImplementedError + + @property + def clauses(self): + return list(ordered(self.clauses_)) + + +class PropKB(KB): + """A KB for Propositional Logic. Inefficient, with no indexing.""" + + def tell(self, sentence): + """Add the sentence's clauses to the KB + + Examples + ======== + + >>> from sympy.logic.inference import PropKB + >>> from sympy.abc import x, y + >>> l = PropKB() + >>> l.clauses + [] + + >>> l.tell(x | y) + >>> l.clauses + [x | y] + + >>> l.tell(y) + >>> l.clauses + [y, x | y] + + """ + for c in conjuncts(to_cnf(sentence)): + self.clauses_.add(c) + + def ask(self, query): + """Checks if the query is true given the set of clauses. + + Examples + ======== + + >>> from sympy.logic.inference import PropKB + >>> from sympy.abc import x, y + >>> l = PropKB() + >>> l.tell(x & ~y) + >>> l.ask(x) + True + >>> l.ask(y) + False + + """ + return entails(query, self.clauses_) + + def retract(self, sentence): + """Remove the sentence's clauses from the KB + + Examples + ======== + + >>> from sympy.logic.inference import PropKB + >>> from sympy.abc import x, y + >>> l = PropKB() + >>> l.clauses + [] + + >>> l.tell(x | y) + >>> l.clauses + [x | y] + + >>> l.retract(x | y) + >>> l.clauses + [] + + """ + for c in conjuncts(to_cnf(sentence)): + self.clauses_.discard(c) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..37b558f3f03f149dae6af20254e9b88192f7f1ed --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/__init__.py @@ -0,0 +1,72 @@ +"""A module that handles matrices. + +Includes functions for fast creating matrices like zero, one/eye, random +matrix, etc. +""" +from .exceptions import ShapeError, NonSquareMatrixError +from .kind import MatrixKind +from .dense import ( + GramSchmidt, casoratian, diag, eye, hessian, jordan_cell, + list2numpy, matrix2numpy, matrix_multiply_elementwise, ones, + randMatrix, rot_axis1, rot_axis2, rot_axis3, rot_ccw_axis1, + rot_ccw_axis2, rot_ccw_axis3, rot_givens, + symarray, wronskian, zeros) +from .dense import MutableDenseMatrix +from .matrixbase import DeferredVector, MatrixBase + +MutableMatrix = MutableDenseMatrix +Matrix = MutableMatrix + +from .sparse import MutableSparseMatrix +from .sparsetools import banded +from .immutable import ImmutableDenseMatrix, ImmutableSparseMatrix + +ImmutableMatrix = ImmutableDenseMatrix +SparseMatrix = MutableSparseMatrix + +from .expressions import ( + MatrixSlice, BlockDiagMatrix, BlockMatrix, FunctionMatrix, Identity, + Inverse, MatAdd, MatMul, MatPow, MatrixExpr, MatrixSymbol, Trace, + Transpose, ZeroMatrix, OneMatrix, blockcut, block_collapse, matrix_symbols, Adjoint, + hadamard_product, HadamardProduct, HadamardPower, Determinant, det, + diagonalize_vector, DiagMatrix, DiagonalMatrix, DiagonalOf, trace, + DotProduct, kronecker_product, KroneckerProduct, + PermutationMatrix, MatrixPermute, MatrixSet, Permanent, per) + +from .utilities import dotprodsimp + +__all__ = [ + 'ShapeError', 'NonSquareMatrixError', 'MatrixKind', + + 'GramSchmidt', 'casoratian', 'diag', 'eye', 'hessian', 'jordan_cell', + 'list2numpy', 'matrix2numpy', 'matrix_multiply_elementwise', 'ones', + 'randMatrix', 'rot_axis1', 'rot_axis2', 'rot_axis3', 'symarray', + 'wronskian', 'zeros', 'rot_ccw_axis1', 'rot_ccw_axis2', 'rot_ccw_axis3', + 'rot_givens', + + 'MutableDenseMatrix', + + 'DeferredVector', 'MatrixBase', + + 'Matrix', 'MutableMatrix', + + 'MutableSparseMatrix', + + 'banded', + + 'ImmutableDenseMatrix', 'ImmutableSparseMatrix', + + 'ImmutableMatrix', 'SparseMatrix', + + 'MatrixSlice', 'BlockDiagMatrix', 'BlockMatrix', 'FunctionMatrix', + 'Identity', 'Inverse', 'MatAdd', 'MatMul', 'MatPow', 'MatrixExpr', + 'MatrixSymbol', 'Trace', 'Transpose', 'ZeroMatrix', 'OneMatrix', + 'blockcut', 'block_collapse', 'matrix_symbols', 'Adjoint', + 'hadamard_product', 'HadamardProduct', 'HadamardPower', 'Determinant', + 'det', 'diagonalize_vector', 'DiagMatrix', 'DiagonalMatrix', + 'DiagonalOf', 'trace', 'DotProduct', 'kronecker_product', + 'KroneckerProduct', 'PermutationMatrix', 'MatrixPermute', 'MatrixSet', + 'Permanent', 'per', + + 'dotprodsimp', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/common.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/common.py new file mode 100644 index 0000000000000000000000000000000000000000..bcb54726fe1a0c36658d8bf63b974db5a3ce8bad --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/common.py @@ -0,0 +1,3258 @@ +""" +A module containing deprecated matrix mixin classes. + +The classes in this module are deprecated and will be removed in a future +release. They are kept here for backwards compatibility in case downstream +code was subclassing them. + +Importing anything else from this module is deprecated so anything here +should either not be used or should be imported from somewhere else. +""" +from __future__ import annotations +from collections import defaultdict +from collections.abc import Iterable +from inspect import isfunction +from functools import reduce + +from sympy.assumptions.refine import refine +from sympy.core import SympifyError, Add +from sympy.core.basic import Atom +from sympy.core.decorators import call_highest_priority +from sympy.core.logic import fuzzy_and, FuzzyBool +from sympy.core.numbers import Integer +from sympy.core.mod import Mod +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.complexes import Abs, re, im +from sympy.utilities.exceptions import sympy_deprecation_warning +from .utilities import _dotprodsimp, _simplify +from sympy.polys.polytools import Poly +from sympy.utilities.iterables import flatten, is_sequence +from sympy.utilities.misc import as_int, filldedent +from sympy.tensor.array import NDimArray + +from .utilities import _get_intermediate_simp_bool + + +# These exception types were previously defined in this module but were moved +# to exceptions.py. We reimport them here for backwards compatibility in case +# downstream code was importing them from here. +from .exceptions import ( # noqa: F401 + MatrixError, ShapeError, NonSquareMatrixError, NonInvertibleMatrixError, + NonPositiveDefiniteMatrixError +) + + +_DEPRECATED_MIXINS = ( + 'MatrixShaping', + 'MatrixSpecial', + 'MatrixProperties', + 'MatrixOperations', + 'MatrixArithmetic', + 'MatrixCommon', + 'MatrixDeterminant', + 'MatrixReductions', + 'MatrixSubspaces', + 'MatrixEigen', + 'MatrixCalculus', + 'MatrixDeprecated', +) + + +class _MatrixDeprecatedMeta(type): + + # + # Override the default __instancecheck__ implementation to ensure that + # e.g. isinstance(M, MatrixCommon) still works when M is one of the + # matrix classes. Matrix no longer inherits from MatrixCommon so + # isinstance(M, MatrixCommon) would now return False by default. + # + # There were lots of places in the codebase where this was being done + # so it seems likely that downstream code may be doing it too. All use + # of these mixins is deprecated though so we give a deprecation warning + # unconditionally if they are being used with isinstance. + # + # Any code seeing this deprecation warning should be changed to use + # isinstance(M, MatrixBase) instead which also works in previous versions + # of SymPy. + # + + def __instancecheck__(cls, instance): + + sympy_deprecation_warning( + f""" + Checking whether an object is an instance of {cls.__name__} is + deprecated. + + Use `isinstance(obj, Matrix)` instead of `isinstance(obj, {cls.__name__})`. + """, + deprecated_since_version="1.13", + active_deprecations_target="deprecated-matrix-mixins", + stacklevel=3, + ) + + from sympy.matrices.matrixbase import MatrixBase + from sympy.matrices.matrices import ( + MatrixDeterminant, + MatrixReductions, + MatrixSubspaces, + MatrixEigen, + MatrixCalculus, + MatrixDeprecated + ) + + all_mixins = ( + MatrixRequired, + MatrixShaping, + MatrixSpecial, + MatrixProperties, + MatrixOperations, + MatrixArithmetic, + MatrixCommon, + MatrixDeterminant, + MatrixReductions, + MatrixSubspaces, + MatrixEigen, + MatrixCalculus, + MatrixDeprecated + ) + + if cls in all_mixins and isinstance(instance, MatrixBase): + return True + else: + return super().__instancecheck__(instance) + + +class MatrixRequired(metaclass=_MatrixDeprecatedMeta): + """Deprecated mixin class for making matrix classes.""" + + rows: int + cols: int + _simplify = None + + def __init_subclass__(cls, **kwargs): + + # Warn if any downstream code is subclassing this class or any of the + # deprecated mixin classes that are all ultimately subclasses of this + # class. + # + # We don't want to warn about the deprecated mixins themselves being + # created, but only about them being used as mixins by downstream code. + # Otherwise just importing this module would trigger a warning. + # Ultimately the whole module should be deprecated and removed but for + # SymPy 1.13 it is premature to do that given that this module was the + # main way to import matrix exception types in all previous versions. + + if cls.__name__ not in _DEPRECATED_MIXINS: + sympy_deprecation_warning( + f""" + Inheriting from the Matrix mixin classes is deprecated. + + The class {cls.__name__} is subclassing a deprecated mixin. + """, + deprecated_since_version="1.13", + active_deprecations_target="deprecated-matrix-mixins", + stacklevel=3, + ) + + super().__init_subclass__(**kwargs) + + @classmethod + def _new(cls, *args, **kwargs): + """`_new` must, at minimum, be callable as + `_new(rows, cols, mat) where mat is a flat list of the + elements of the matrix.""" + raise NotImplementedError("Subclasses must implement this.") + + def __eq__(self, other): + raise NotImplementedError("Subclasses must implement this.") + + def __getitem__(self, key): + """Implementations of __getitem__ should accept ints, in which + case the matrix is indexed as a flat list, tuples (i,j) in which + case the (i,j) entry is returned, slices, or mixed tuples (a,b) + where a and b are any combination of slices and integers.""" + raise NotImplementedError("Subclasses must implement this.") + + def __len__(self): + """The total number of entries in the matrix.""" + raise NotImplementedError("Subclasses must implement this.") + + @property + def shape(self): + raise NotImplementedError("Subclasses must implement this.") + + +class MatrixShaping(MatrixRequired): + """Provides basic matrix shaping and extracting of submatrices""" + + def _eval_col_del(self, col): + def entry(i, j): + return self[i, j] if j < col else self[i, j + 1] + return self._new(self.rows, self.cols - 1, entry) + + def _eval_col_insert(self, pos, other): + + def entry(i, j): + if j < pos: + return self[i, j] + elif pos <= j < pos + other.cols: + return other[i, j - pos] + return self[i, j - other.cols] + + return self._new(self.rows, self.cols + other.cols, entry) + + def _eval_col_join(self, other): + rows = self.rows + + def entry(i, j): + if i < rows: + return self[i, j] + return other[i - rows, j] + + return classof(self, other)._new(self.rows + other.rows, self.cols, + entry) + + def _eval_extract(self, rowsList, colsList): + mat = list(self) + cols = self.cols + indices = (i * cols + j for i in rowsList for j in colsList) + return self._new(len(rowsList), len(colsList), + [mat[i] for i in indices]) + + def _eval_get_diag_blocks(self): + sub_blocks = [] + + def recurse_sub_blocks(M): + for i in range(1, M.shape[0] + 1): + if i == 1: + to_the_right = M[0, i:] + to_the_bottom = M[i:, 0] + else: + to_the_right = M[:i, i:] + to_the_bottom = M[i:, :i] + if any(to_the_right) or any(to_the_bottom): + continue + sub_blocks.append(M[:i, :i]) + if M.shape != M[:i, :i].shape: + recurse_sub_blocks(M[i:, i:]) + return + + recurse_sub_blocks(self) + return sub_blocks + + def _eval_row_del(self, row): + def entry(i, j): + return self[i, j] if i < row else self[i + 1, j] + return self._new(self.rows - 1, self.cols, entry) + + def _eval_row_insert(self, pos, other): + entries = list(self) + insert_pos = pos * self.cols + entries[insert_pos:insert_pos] = list(other) + return self._new(self.rows + other.rows, self.cols, entries) + + def _eval_row_join(self, other): + cols = self.cols + + def entry(i, j): + if j < cols: + return self[i, j] + return other[i, j - cols] + + return classof(self, other)._new(self.rows, self.cols + other.cols, + entry) + + def _eval_tolist(self): + return [list(self[i,:]) for i in range(self.rows)] + + def _eval_todok(self): + dok = {} + rows, cols = self.shape + for i in range(rows): + for j in range(cols): + val = self[i, j] + if val != self.zero: + dok[i, j] = val + return dok + + def _eval_vec(self): + rows = self.rows + + def entry(n, _): + # we want to read off the columns first + j = n // rows + i = n - j * rows + return self[i, j] + + return self._new(len(self), 1, entry) + + def _eval_vech(self, diagonal): + c = self.cols + v = [] + if diagonal: + for j in range(c): + for i in range(j, c): + v.append(self[i, j]) + else: + for j in range(c): + for i in range(j + 1, c): + v.append(self[i, j]) + return self._new(len(v), 1, v) + + def col_del(self, col): + """Delete the specified column.""" + if col < 0: + col += self.cols + if not 0 <= col < self.cols: + raise IndexError("Column {} is out of range.".format(col)) + return self._eval_col_del(col) + + def col_insert(self, pos, other): + """Insert one or more columns at the given column position. + + Examples + ======== + + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(3, 1) + >>> M.col_insert(1, V) + Matrix([ + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0]]) + + See Also + ======== + + col + row_insert + """ + # Allows you to build a matrix even if it is null matrix + if not self: + return type(self)(other) + + pos = as_int(pos) + + if pos < 0: + pos = self.cols + pos + if pos < 0: + pos = 0 + elif pos > self.cols: + pos = self.cols + + if self.rows != other.rows: + raise ShapeError( + "The matrices have incompatible number of rows ({} and {})" + .format(self.rows, other.rows)) + + return self._eval_col_insert(pos, other) + + def col_join(self, other): + """Concatenates two matrices along self's last and other's first row. + + Examples + ======== + + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(1, 3) + >>> M.col_join(V) + Matrix([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [1, 1, 1]]) + + See Also + ======== + + col + row_join + """ + # A null matrix can always be stacked (see #10770) + if self.rows == 0 and self.cols != other.cols: + return self._new(0, other.cols, []).col_join(other) + + if self.cols != other.cols: + raise ShapeError( + "The matrices have incompatible number of columns ({} and {})" + .format(self.cols, other.cols)) + return self._eval_col_join(other) + + def col(self, j): + """Elementary column selector. + + Examples + ======== + + >>> from sympy import eye + >>> eye(2).col(0) + Matrix([ + [1], + [0]]) + + See Also + ======== + + row + col_del + col_join + col_insert + """ + return self[:, j] + + def extract(self, rowsList, colsList): + r"""Return a submatrix by specifying a list of rows and columns. + Negative indices can be given. All indices must be in the range + $-n \le i < n$ where $n$ is the number of rows or columns. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(4, 3, range(12)) + >>> m + Matrix([ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [9, 10, 11]]) + >>> m.extract([0, 1, 3], [0, 1]) + Matrix([ + [0, 1], + [3, 4], + [9, 10]]) + + Rows or columns can be repeated: + + >>> m.extract([0, 0, 1], [-1]) + Matrix([ + [2], + [2], + [5]]) + + Every other row can be taken by using range to provide the indices: + + >>> m.extract(range(0, m.rows, 2), [-1]) + Matrix([ + [2], + [8]]) + + RowsList or colsList can also be a list of booleans, in which case + the rows or columns corresponding to the True values will be selected: + + >>> m.extract([0, 1, 2, 3], [True, False, True]) + Matrix([ + [0, 2], + [3, 5], + [6, 8], + [9, 11]]) + """ + + if not is_sequence(rowsList) or not is_sequence(colsList): + raise TypeError("rowsList and colsList must be iterable") + # ensure rowsList and colsList are lists of integers + if rowsList and all(isinstance(i, bool) for i in rowsList): + rowsList = [index for index, item in enumerate(rowsList) if item] + if colsList and all(isinstance(i, bool) for i in colsList): + colsList = [index for index, item in enumerate(colsList) if item] + + # ensure everything is in range + rowsList = [a2idx(k, self.rows) for k in rowsList] + colsList = [a2idx(k, self.cols) for k in colsList] + + return self._eval_extract(rowsList, colsList) + + def get_diag_blocks(self): + """Obtains the square sub-matrices on the main diagonal of a square matrix. + + Useful for inverting symbolic matrices or solving systems of + linear equations which may be decoupled by having a block diagonal + structure. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y, z + >>> A = Matrix([[1, 3, 0, 0], [y, z*z, 0, 0], [0, 0, x, 0], [0, 0, 0, 0]]) + >>> a1, a2, a3 = A.get_diag_blocks() + >>> a1 + Matrix([ + [1, 3], + [y, z**2]]) + >>> a2 + Matrix([[x]]) + >>> a3 + Matrix([[0]]) + + """ + return self._eval_get_diag_blocks() + + @classmethod + def hstack(cls, *args): + """Return a matrix formed by joining args horizontally (i.e. + by repeated application of row_join). + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> Matrix.hstack(eye(2), 2*eye(2)) + Matrix([ + [1, 0, 2, 0], + [0, 1, 0, 2]]) + """ + if len(args) == 0: + return cls._new() + + kls = type(args[0]) + return reduce(kls.row_join, args) + + def reshape(self, rows, cols): + """Reshape the matrix. Total number of elements must remain the same. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 3, lambda i, j: 1) + >>> m + Matrix([ + [1, 1, 1], + [1, 1, 1]]) + >>> m.reshape(1, 6) + Matrix([[1, 1, 1, 1, 1, 1]]) + >>> m.reshape(3, 2) + Matrix([ + [1, 1], + [1, 1], + [1, 1]]) + + """ + if self.rows * self.cols != rows * cols: + raise ValueError("Invalid reshape parameters %d %d" % (rows, cols)) + return self._new(rows, cols, lambda i, j: self[i * cols + j]) + + def row_del(self, row): + """Delete the specified row.""" + if row < 0: + row += self.rows + if not 0 <= row < self.rows: + raise IndexError("Row {} is out of range.".format(row)) + + return self._eval_row_del(row) + + def row_insert(self, pos, other): + """Insert one or more rows at the given row position. + + Examples + ======== + + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(1, 3) + >>> M.row_insert(1, V) + Matrix([ + [0, 0, 0], + [1, 1, 1], + [0, 0, 0], + [0, 0, 0]]) + + See Also + ======== + + row + col_insert + """ + # Allows you to build a matrix even if it is null matrix + if not self: + return self._new(other) + + pos = as_int(pos) + + if pos < 0: + pos = self.rows + pos + if pos < 0: + pos = 0 + elif pos > self.rows: + pos = self.rows + + if self.cols != other.cols: + raise ShapeError( + "The matrices have incompatible number of columns ({} and {})" + .format(self.cols, other.cols)) + + return self._eval_row_insert(pos, other) + + def row_join(self, other): + """Concatenates two matrices along self's last and rhs's first column + + Examples + ======== + + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(3, 1) + >>> M.row_join(V) + Matrix([ + [0, 0, 0, 1], + [0, 0, 0, 1], + [0, 0, 0, 1]]) + + See Also + ======== + + row + col_join + """ + # A null matrix can always be stacked (see #10770) + if self.cols == 0 and self.rows != other.rows: + return self._new(other.rows, 0, []).row_join(other) + + if self.rows != other.rows: + raise ShapeError( + "The matrices have incompatible number of rows ({} and {})" + .format(self.rows, other.rows)) + return self._eval_row_join(other) + + def diagonal(self, k=0): + """Returns the kth diagonal of self. The main diagonal + corresponds to `k=0`; diagonals above and below correspond to + `k > 0` and `k < 0`, respectively. The values of `self[i, j]` + for which `j - i = k`, are returned in order of increasing + `i + j`, starting with `i + j = |k|`. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(3, 3, lambda i, j: j - i); m + Matrix([ + [ 0, 1, 2], + [-1, 0, 1], + [-2, -1, 0]]) + >>> _.diagonal() + Matrix([[0, 0, 0]]) + >>> m.diagonal(1) + Matrix([[1, 1]]) + >>> m.diagonal(-2) + Matrix([[-2]]) + + Even though the diagonal is returned as a Matrix, the element + retrieval can be done with a single index: + + >>> Matrix.diag(1, 2, 3).diagonal()[1] # instead of [0, 1] + 2 + + See Also + ======== + + diag + """ + rv = [] + k = as_int(k) + r = 0 if k > 0 else -k + c = 0 if r else k + while True: + if r == self.rows or c == self.cols: + break + rv.append(self[r, c]) + r += 1 + c += 1 + if not rv: + raise ValueError(filldedent(''' + The %s diagonal is out of range [%s, %s]''' % ( + k, 1 - self.rows, self.cols - 1))) + return self._new(1, len(rv), rv) + + def row(self, i): + """Elementary row selector. + + Examples + ======== + + >>> from sympy import eye + >>> eye(2).row(0) + Matrix([[1, 0]]) + + See Also + ======== + + col + row_del + row_join + row_insert + """ + return self[i, :] + + @property + def shape(self): + """The shape (dimensions) of the matrix as the 2-tuple (rows, cols). + + Examples + ======== + + >>> from sympy import zeros + >>> M = zeros(2, 3) + >>> M.shape + (2, 3) + >>> M.rows + 2 + >>> M.cols + 3 + """ + return (self.rows, self.cols) + + def todok(self): + """Return the matrix as dictionary of keys. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix.eye(3) + >>> M.todok() + {(0, 0): 1, (1, 1): 1, (2, 2): 1} + """ + return self._eval_todok() + + def tolist(self): + """Return the Matrix as a nested Python list. + + Examples + ======== + + >>> from sympy import Matrix, ones + >>> m = Matrix(3, 3, range(9)) + >>> m + Matrix([ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> m.tolist() + [[0, 1, 2], [3, 4, 5], [6, 7, 8]] + >>> ones(3, 0).tolist() + [[], [], []] + + When there are no rows then it will not be possible to tell how + many columns were in the original matrix: + + >>> ones(0, 3).tolist() + [] + + """ + if not self.rows: + return [] + if not self.cols: + return [[] for i in range(self.rows)] + return self._eval_tolist() + + def todod(M): + """Returns matrix as dict of dicts containing non-zero elements of the Matrix + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[0, 1],[0, 3]]) + >>> A + Matrix([ + [0, 1], + [0, 3]]) + >>> A.todod() + {0: {1: 1}, 1: {1: 3}} + + + """ + rowsdict = {} + Mlol = M.tolist() + for i, Mi in enumerate(Mlol): + row = {j: Mij for j, Mij in enumerate(Mi) if Mij} + if row: + rowsdict[i] = row + return rowsdict + + def vec(self): + """Return the Matrix converted into a one column matrix by stacking columns + + Examples + ======== + + >>> from sympy import Matrix + >>> m=Matrix([[1, 3], [2, 4]]) + >>> m + Matrix([ + [1, 3], + [2, 4]]) + >>> m.vec() + Matrix([ + [1], + [2], + [3], + [4]]) + + See Also + ======== + + vech + """ + return self._eval_vec() + + def vech(self, diagonal=True, check_symmetry=True): + """Reshapes the matrix into a column vector by stacking the + elements in the lower triangle. + + Parameters + ========== + + diagonal : bool, optional + If ``True``, it includes the diagonal elements. + + check_symmetry : bool, optional + If ``True``, it checks whether the matrix is symmetric. + + Examples + ======== + + >>> from sympy import Matrix + >>> m=Matrix([[1, 2], [2, 3]]) + >>> m + Matrix([ + [1, 2], + [2, 3]]) + >>> m.vech() + Matrix([ + [1], + [2], + [3]]) + >>> m.vech(diagonal=False) + Matrix([[2]]) + + Notes + ===== + + This should work for symmetric matrices and ``vech`` can + represent symmetric matrices in vector form with less size than + ``vec``. + + See Also + ======== + + vec + """ + if not self.is_square: + raise NonSquareMatrixError + + if check_symmetry and not self.is_symmetric(): + raise ValueError("The matrix is not symmetric.") + + return self._eval_vech(diagonal) + + @classmethod + def vstack(cls, *args): + """Return a matrix formed by joining args vertically (i.e. + by repeated application of col_join). + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> Matrix.vstack(eye(2), 2*eye(2)) + Matrix([ + [1, 0], + [0, 1], + [2, 0], + [0, 2]]) + """ + if len(args) == 0: + return cls._new() + + kls = type(args[0]) + return reduce(kls.col_join, args) + + +class MatrixSpecial(MatrixRequired): + """Construction of special matrices""" + + @classmethod + def _eval_diag(cls, rows, cols, diag_dict): + """diag_dict is a defaultdict containing + all the entries of the diagonal matrix.""" + def entry(i, j): + return diag_dict[(i, j)] + return cls._new(rows, cols, entry) + + @classmethod + def _eval_eye(cls, rows, cols): + vals = [cls.zero]*(rows*cols) + vals[::cols+1] = [cls.one]*min(rows, cols) + return cls._new(rows, cols, vals, copy=False) + + @classmethod + def _eval_jordan_block(cls, size: int, eigenvalue, band='upper'): + if band == 'lower': + def entry(i, j): + if i == j: + return eigenvalue + elif j + 1 == i: + return cls.one + return cls.zero + else: + def entry(i, j): + if i == j: + return eigenvalue + elif i + 1 == j: + return cls.one + return cls.zero + return cls._new(size, size, entry) + + @classmethod + def _eval_ones(cls, rows, cols): + def entry(i, j): + return cls.one + return cls._new(rows, cols, entry) + + @classmethod + def _eval_zeros(cls, rows, cols): + return cls._new(rows, cols, [cls.zero]*(rows*cols), copy=False) + + @classmethod + def _eval_wilkinson(cls, n): + def entry(i, j): + return cls.one if i + 1 == j else cls.zero + + D = cls._new(2*n + 1, 2*n + 1, entry) + + wminus = cls.diag(list(range(-n, n + 1)), unpack=True) + D + D.T + wplus = abs(cls.diag(list(range(-n, n + 1)), unpack=True)) + D + D.T + + return wminus, wplus + + @classmethod + def diag(kls, *args, strict=False, unpack=True, rows=None, cols=None, **kwargs): + """Returns a matrix with the specified diagonal. + If matrices are passed, a block-diagonal matrix + is created (i.e. the "direct sum" of the matrices). + + kwargs + ====== + + rows : rows of the resulting matrix; computed if + not given. + + cols : columns of the resulting matrix; computed if + not given. + + cls : class for the resulting matrix + + unpack : bool which, when True (default), unpacks a single + sequence rather than interpreting it as a Matrix. + + strict : bool which, when False (default), allows Matrices to + have variable-length rows. + + Examples + ======== + + >>> from sympy import Matrix + >>> Matrix.diag(1, 2, 3) + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + + The current default is to unpack a single sequence. If this is + not desired, set `unpack=False` and it will be interpreted as + a matrix. + + >>> Matrix.diag([1, 2, 3]) == Matrix.diag(1, 2, 3) + True + + When more than one element is passed, each is interpreted as + something to put on the diagonal. Lists are converted to + matrices. Filling of the diagonal always continues from + the bottom right hand corner of the previous item: this + will create a block-diagonal matrix whether the matrices + are square or not. + + >>> col = [1, 2, 3] + >>> row = [[4, 5]] + >>> Matrix.diag(col, row) + Matrix([ + [1, 0, 0], + [2, 0, 0], + [3, 0, 0], + [0, 4, 5]]) + + When `unpack` is False, elements within a list need not all be + of the same length. Setting `strict` to True would raise a + ValueError for the following: + + >>> Matrix.diag([[1, 2, 3], [4, 5], [6]], unpack=False) + Matrix([ + [1, 2, 3], + [4, 5, 0], + [6, 0, 0]]) + + The type of the returned matrix can be set with the ``cls`` + keyword. + + >>> from sympy import ImmutableMatrix + >>> from sympy.utilities.misc import func_name + >>> func_name(Matrix.diag(1, cls=ImmutableMatrix)) + 'ImmutableDenseMatrix' + + A zero dimension matrix can be used to position the start of + the filling at the start of an arbitrary row or column: + + >>> from sympy import ones + >>> r2 = ones(0, 2) + >>> Matrix.diag(r2, 1, 2) + Matrix([ + [0, 0, 1, 0], + [0, 0, 0, 2]]) + + See Also + ======== + eye + diagonal + .dense.diag + .expressions.blockmatrix.BlockMatrix + .sparsetools.banded + """ + from sympy.matrices.matrixbase import MatrixBase + from sympy.matrices.dense import Matrix + from sympy.matrices import SparseMatrix + klass = kwargs.get('cls', kls) + if unpack and len(args) == 1 and is_sequence(args[0]) and \ + not isinstance(args[0], MatrixBase): + args = args[0] + + # fill a default dict with the diagonal entries + diag_entries = defaultdict(int) + rmax = cmax = 0 # keep track of the biggest index seen + for m in args: + if isinstance(m, list): + if strict: + # if malformed, Matrix will raise an error + _ = Matrix(m) + r, c = _.shape + m = _.tolist() + else: + r, c, smat = SparseMatrix._handle_creation_inputs(m) + for (i, j), _ in smat.items(): + diag_entries[(i + rmax, j + cmax)] = _ + m = [] # to skip process below + elif hasattr(m, 'shape'): # a Matrix + # convert to list of lists + r, c = m.shape + m = m.tolist() + else: # in this case, we're a single value + diag_entries[(rmax, cmax)] = m + rmax += 1 + cmax += 1 + continue + # process list of lists + for i, mi in enumerate(m): + for j, _ in enumerate(mi): + diag_entries[(i + rmax, j + cmax)] = _ + rmax += r + cmax += c + if rows is None: + rows, cols = cols, rows + if rows is None: + rows, cols = rmax, cmax + else: + cols = rows if cols is None else cols + if rows < rmax or cols < cmax: + raise ValueError(filldedent(''' + The constructed matrix is {} x {} but a size of {} x {} + was specified.'''.format(rmax, cmax, rows, cols))) + return klass._eval_diag(rows, cols, diag_entries) + + @classmethod + def eye(kls, rows, cols=None, **kwargs): + """Returns an identity matrix. + + Parameters + ========== + + rows : rows of the matrix + cols : cols of the matrix (if None, cols=rows) + + kwargs + ====== + cls : class of the returned matrix + """ + if cols is None: + cols = rows + if rows < 0 or cols < 0: + raise ValueError("Cannot create a {} x {} matrix. " + "Both dimensions must be positive".format(rows, cols)) + klass = kwargs.get('cls', kls) + rows, cols = as_int(rows), as_int(cols) + + return klass._eval_eye(rows, cols) + + @classmethod + def jordan_block(kls, size=None, eigenvalue=None, *, band='upper', **kwargs): + """Returns a Jordan block + + Parameters + ========== + + size : Integer, optional + Specifies the shape of the Jordan block matrix. + + eigenvalue : Number or Symbol + Specifies the value for the main diagonal of the matrix. + + .. note:: + The keyword ``eigenval`` is also specified as an alias + of this keyword, but it is not recommended to use. + + We may deprecate the alias in later release. + + band : 'upper' or 'lower', optional + Specifies the position of the off-diagonal to put `1` s on. + + cls : Matrix, optional + Specifies the matrix class of the output form. + + If it is not specified, the class type where the method is + being executed on will be returned. + + Returns + ======= + + Matrix + A Jordan block matrix. + + Raises + ====== + + ValueError + If insufficient arguments are given for matrix size + specification, or no eigenvalue is given. + + Examples + ======== + + Creating a default Jordan block: + + >>> from sympy import Matrix + >>> from sympy.abc import x + >>> Matrix.jordan_block(4, x) + Matrix([ + [x, 1, 0, 0], + [0, x, 1, 0], + [0, 0, x, 1], + [0, 0, 0, x]]) + + Creating an alternative Jordan block matrix where `1` is on + lower off-diagonal: + + >>> Matrix.jordan_block(4, x, band='lower') + Matrix([ + [x, 0, 0, 0], + [1, x, 0, 0], + [0, 1, x, 0], + [0, 0, 1, x]]) + + Creating a Jordan block with keyword arguments + + >>> Matrix.jordan_block(size=4, eigenvalue=x) + Matrix([ + [x, 1, 0, 0], + [0, x, 1, 0], + [0, 0, x, 1], + [0, 0, 0, x]]) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Jordan_matrix + """ + klass = kwargs.pop('cls', kls) + + eigenval = kwargs.get('eigenval', None) + if eigenvalue is None and eigenval is None: + raise ValueError("Must supply an eigenvalue") + elif eigenvalue != eigenval and None not in (eigenval, eigenvalue): + raise ValueError( + "Inconsistent values are given: 'eigenval'={}, " + "'eigenvalue'={}".format(eigenval, eigenvalue)) + else: + if eigenval is not None: + eigenvalue = eigenval + + if size is None: + raise ValueError("Must supply a matrix size") + + size = as_int(size) + return klass._eval_jordan_block(size, eigenvalue, band) + + @classmethod + def ones(kls, rows, cols=None, **kwargs): + """Returns a matrix of ones. + + Parameters + ========== + + rows : rows of the matrix + cols : cols of the matrix (if None, cols=rows) + + kwargs + ====== + cls : class of the returned matrix + """ + if cols is None: + cols = rows + klass = kwargs.get('cls', kls) + rows, cols = as_int(rows), as_int(cols) + + return klass._eval_ones(rows, cols) + + @classmethod + def zeros(kls, rows, cols=None, **kwargs): + """Returns a matrix of zeros. + + Parameters + ========== + + rows : rows of the matrix + cols : cols of the matrix (if None, cols=rows) + + kwargs + ====== + cls : class of the returned matrix + """ + if cols is None: + cols = rows + if rows < 0 or cols < 0: + raise ValueError("Cannot create a {} x {} matrix. " + "Both dimensions must be positive".format(rows, cols)) + klass = kwargs.get('cls', kls) + rows, cols = as_int(rows), as_int(cols) + + return klass._eval_zeros(rows, cols) + + @classmethod + def companion(kls, poly): + """Returns a companion matrix of a polynomial. + + Examples + ======== + + >>> from sympy import Matrix, Poly, Symbol, symbols + >>> x = Symbol('x') + >>> c0, c1, c2, c3, c4 = symbols('c0:5') + >>> p = Poly(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + x**5, x) + >>> Matrix.companion(p) + Matrix([ + [0, 0, 0, 0, -c0], + [1, 0, 0, 0, -c1], + [0, 1, 0, 0, -c2], + [0, 0, 1, 0, -c3], + [0, 0, 0, 1, -c4]]) + """ + poly = kls._sympify(poly) + if not isinstance(poly, Poly): + raise ValueError("{} must be a Poly instance.".format(poly)) + if not poly.is_monic: + raise ValueError("{} must be a monic polynomial.".format(poly)) + if not poly.is_univariate: + raise ValueError( + "{} must be a univariate polynomial.".format(poly)) + + size = poly.degree() + if not size >= 1: + raise ValueError( + "{} must have degree not less than 1.".format(poly)) + + coeffs = poly.all_coeffs() + def entry(i, j): + if j == size - 1: + return -coeffs[-1 - i] + elif i == j + 1: + return kls.one + return kls.zero + return kls._new(size, size, entry) + + + @classmethod + def wilkinson(kls, n, **kwargs): + """Returns two square Wilkinson Matrix of size 2*n + 1 + $W_{2n + 1}^-, W_{2n + 1}^+ =$ Wilkinson(n) + + Examples + ======== + + >>> from sympy import Matrix + >>> wminus, wplus = Matrix.wilkinson(3) + >>> wminus + Matrix([ + [-3, 1, 0, 0, 0, 0, 0], + [ 1, -2, 1, 0, 0, 0, 0], + [ 0, 1, -1, 1, 0, 0, 0], + [ 0, 0, 1, 0, 1, 0, 0], + [ 0, 0, 0, 1, 1, 1, 0], + [ 0, 0, 0, 0, 1, 2, 1], + [ 0, 0, 0, 0, 0, 1, 3]]) + >>> wplus + Matrix([ + [3, 1, 0, 0, 0, 0, 0], + [1, 2, 1, 0, 0, 0, 0], + [0, 1, 1, 1, 0, 0, 0], + [0, 0, 1, 0, 1, 0, 0], + [0, 0, 0, 1, 1, 1, 0], + [0, 0, 0, 0, 1, 2, 1], + [0, 0, 0, 0, 0, 1, 3]]) + + References + ========== + + .. [1] https://blogs.mathworks.com/cleve/2013/04/15/wilkinsons-matrices-2/ + .. [2] J. H. Wilkinson, The Algebraic Eigenvalue Problem, Claredon Press, Oxford, 1965, 662 pp. + + """ + klass = kwargs.get('cls', kls) + n = as_int(n) + return klass._eval_wilkinson(n) + +class MatrixProperties(MatrixRequired): + """Provides basic properties of a matrix.""" + + def _eval_atoms(self, *types): + result = set() + for i in self: + result.update(i.atoms(*types)) + return result + + def _eval_free_symbols(self): + return set().union(*(i.free_symbols for i in self if i)) + + def _eval_has(self, *patterns): + return any(a.has(*patterns) for a in self) + + def _eval_is_anti_symmetric(self, simpfunc): + if not all(simpfunc(self[i, j] + self[j, i]).is_zero for i in range(self.rows) for j in range(self.cols)): + return False + return True + + def _eval_is_diagonal(self): + for i in range(self.rows): + for j in range(self.cols): + if i != j and self[i, j]: + return False + return True + + # _eval_is_hermitian is called by some general SymPy + # routines and has a different *args signature. Make + # sure the names don't clash by adding `_matrix_` in name. + def _eval_is_matrix_hermitian(self, simpfunc): + mat = self._new(self.rows, self.cols, lambda i, j: simpfunc(self[i, j] - self[j, i].conjugate())) + return mat.is_zero_matrix + + def _eval_is_Identity(self) -> FuzzyBool: + def dirac(i, j): + if i == j: + return 1 + return 0 + + return all(self[i, j] == dirac(i, j) + for i in range(self.rows) + for j in range(self.cols)) + + def _eval_is_lower_hessenberg(self): + return all(self[i, j].is_zero + for i in range(self.rows) + for j in range(i + 2, self.cols)) + + def _eval_is_lower(self): + return all(self[i, j].is_zero + for i in range(self.rows) + for j in range(i + 1, self.cols)) + + def _eval_is_symbolic(self): + return self.has(Symbol) + + def _eval_is_symmetric(self, simpfunc): + mat = self._new(self.rows, self.cols, lambda i, j: simpfunc(self[i, j] - self[j, i])) + return mat.is_zero_matrix + + def _eval_is_zero_matrix(self): + if any(i.is_zero == False for i in self): + return False + if any(i.is_zero is None for i in self): + return None + return True + + def _eval_is_upper_hessenberg(self): + return all(self[i, j].is_zero + for i in range(2, self.rows) + for j in range(min(self.cols, (i - 1)))) + + def _eval_values(self): + return [i for i in self if not i.is_zero] + + def _has_positive_diagonals(self): + diagonal_entries = (self[i, i] for i in range(self.rows)) + return fuzzy_and(x.is_positive for x in diagonal_entries) + + def _has_nonnegative_diagonals(self): + diagonal_entries = (self[i, i] for i in range(self.rows)) + return fuzzy_and(x.is_nonnegative for x in diagonal_entries) + + def atoms(self, *types): + """Returns the atoms that form the current object. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import Matrix + >>> Matrix([[x]]) + Matrix([[x]]) + >>> _.atoms() + {x} + >>> Matrix([[x, y], [y, x]]) + Matrix([ + [x, y], + [y, x]]) + >>> _.atoms() + {x, y} + """ + + types = tuple(t if isinstance(t, type) else type(t) for t in types) + if not types: + types = (Atom,) + return self._eval_atoms(*types) + + @property + def free_symbols(self): + """Returns the free symbols within the matrix. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import Matrix + >>> Matrix([[x], [1]]).free_symbols + {x} + """ + return self._eval_free_symbols() + + def has(self, *patterns): + """Test whether any subexpression matches any of the patterns. + + Examples + ======== + + >>> from sympy import Matrix, SparseMatrix, Float + >>> from sympy.abc import x, y + >>> A = Matrix(((1, x), (0.2, 3))) + >>> B = SparseMatrix(((1, x), (0.2, 3))) + >>> A.has(x) + True + >>> A.has(y) + False + >>> A.has(Float) + True + >>> B.has(x) + True + >>> B.has(y) + False + >>> B.has(Float) + True + """ + return self._eval_has(*patterns) + + def is_anti_symmetric(self, simplify=True): + """Check if matrix M is an antisymmetric matrix, + that is, M is a square matrix with all M[i, j] == -M[j, i]. + + When ``simplify=True`` (default), the sum M[i, j] + M[j, i] is + simplified before testing to see if it is zero. By default, + the SymPy simplify function is used. To use a custom function + set simplify to a function that accepts a single argument which + returns a simplified expression. To skip simplification, set + simplify to False but note that although this will be faster, + it may induce false negatives. + + Examples + ======== + + >>> from sympy import Matrix, symbols + >>> m = Matrix(2, 2, [0, 1, -1, 0]) + >>> m + Matrix([ + [ 0, 1], + [-1, 0]]) + >>> m.is_anti_symmetric() + True + >>> x, y = symbols('x y') + >>> m = Matrix(2, 3, [0, 0, x, -y, 0, 0]) + >>> m + Matrix([ + [ 0, 0, x], + [-y, 0, 0]]) + >>> m.is_anti_symmetric() + False + + >>> from sympy.abc import x, y + >>> m = Matrix(3, 3, [0, x**2 + 2*x + 1, y, + ... -(x + 1)**2, 0, x*y, + ... -y, -x*y, 0]) + + Simplification of matrix elements is done by default so even + though two elements which should be equal and opposite would not + pass an equality test, the matrix is still reported as + anti-symmetric: + + >>> m[0, 1] == -m[1, 0] + False + >>> m.is_anti_symmetric() + True + + If ``simplify=False`` is used for the case when a Matrix is already + simplified, this will speed things up. Here, we see that without + simplification the matrix does not appear anti-symmetric: + + >>> print(m.is_anti_symmetric(simplify=False)) + None + + But if the matrix were already expanded, then it would appear + anti-symmetric and simplification in the is_anti_symmetric routine + is not needed: + + >>> m = m.expand() + >>> m.is_anti_symmetric(simplify=False) + True + """ + # accept custom simplification + simpfunc = simplify + if not isfunction(simplify): + simpfunc = _simplify if simplify else lambda x: x + + if not self.is_square: + return False + return self._eval_is_anti_symmetric(simpfunc) + + def is_diagonal(self): + """Check if matrix is diagonal, + that is matrix in which the entries outside the main diagonal are all zero. + + Examples + ======== + + >>> from sympy import Matrix, diag + >>> m = Matrix(2, 2, [1, 0, 0, 2]) + >>> m + Matrix([ + [1, 0], + [0, 2]]) + >>> m.is_diagonal() + True + + >>> m = Matrix(2, 2, [1, 1, 0, 2]) + >>> m + Matrix([ + [1, 1], + [0, 2]]) + >>> m.is_diagonal() + False + + >>> m = diag(1, 2, 3) + >>> m + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + >>> m.is_diagonal() + True + + See Also + ======== + + is_lower + is_upper + sympy.matrices.matrixbase.MatrixCommon.is_diagonalizable + diagonalize + """ + return self._eval_is_diagonal() + + @property + def is_weakly_diagonally_dominant(self): + r"""Tests if the matrix is row weakly diagonally dominant. + + Explanation + =========== + + A $n, n$ matrix $A$ is row weakly diagonally dominant if + + .. math:: + \left|A_{i, i}\right| \ge \sum_{j = 0, j \neq i}^{n-1} + \left|A_{i, j}\right| \quad {\text{for all }} + i \in \{ 0, ..., n-1 \} + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) + >>> A.is_weakly_diagonally_dominant + True + + >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) + >>> A.is_weakly_diagonally_dominant + False + + >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) + >>> A.is_weakly_diagonally_dominant + True + + Notes + ===== + + If you want to test whether a matrix is column diagonally + dominant, you can apply the test after transposing the matrix. + """ + if not self.is_square: + return False + + rows, cols = self.shape + + def test_row(i): + summation = self.zero + for j in range(cols): + if i != j: + summation += Abs(self[i, j]) + return (Abs(self[i, i]) - summation).is_nonnegative + + return fuzzy_and(test_row(i) for i in range(rows)) + + @property + def is_strongly_diagonally_dominant(self): + r"""Tests if the matrix is row strongly diagonally dominant. + + Explanation + =========== + + A $n, n$ matrix $A$ is row strongly diagonally dominant if + + .. math:: + \left|A_{i, i}\right| > \sum_{j = 0, j \neq i}^{n-1} + \left|A_{i, j}\right| \quad {\text{for all }} + i \in \{ 0, ..., n-1 \} + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) + >>> A.is_strongly_diagonally_dominant + False + + >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) + >>> A.is_strongly_diagonally_dominant + False + + >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) + >>> A.is_strongly_diagonally_dominant + True + + Notes + ===== + + If you want to test whether a matrix is column diagonally + dominant, you can apply the test after transposing the matrix. + """ + if not self.is_square: + return False + + rows, cols = self.shape + + def test_row(i): + summation = self.zero + for j in range(cols): + if i != j: + summation += Abs(self[i, j]) + return (Abs(self[i, i]) - summation).is_positive + + return fuzzy_and(test_row(i) for i in range(rows)) + + @property + def is_hermitian(self): + """Checks if the matrix is Hermitian. + + In a Hermitian matrix element i,j is the complex conjugate of + element j,i. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy import I + >>> from sympy.abc import x + >>> a = Matrix([[1, I], [-I, 1]]) + >>> a + Matrix([ + [ 1, I], + [-I, 1]]) + >>> a.is_hermitian + True + >>> a[0, 0] = 2*I + >>> a.is_hermitian + False + >>> a[0, 0] = x + >>> a.is_hermitian + >>> a[0, 1] = a[1, 0]*I + >>> a.is_hermitian + False + """ + if not self.is_square: + return False + + return self._eval_is_matrix_hermitian(_simplify) + + @property + def is_Identity(self) -> FuzzyBool: + if not self.is_square: + return False + return self._eval_is_Identity() + + @property + def is_lower_hessenberg(self): + r"""Checks if the matrix is in the lower-Hessenberg form. + + The lower hessenberg matrix has zero entries + above the first superdiagonal. + + Examples + ======== + + >>> from sympy import Matrix + >>> a = Matrix([[1, 2, 0, 0], [5, 2, 3, 0], [3, 4, 3, 7], [5, 6, 1, 1]]) + >>> a + Matrix([ + [1, 2, 0, 0], + [5, 2, 3, 0], + [3, 4, 3, 7], + [5, 6, 1, 1]]) + >>> a.is_lower_hessenberg + True + + See Also + ======== + + is_upper_hessenberg + is_lower + """ + return self._eval_is_lower_hessenberg() + + @property + def is_lower(self): + """Check if matrix is a lower triangular matrix. True can be returned + even if the matrix is not square. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, [1, 0, 0, 1]) + >>> m + Matrix([ + [1, 0], + [0, 1]]) + >>> m.is_lower + True + + >>> m = Matrix(4, 3, [0, 0, 0, 2, 0, 0, 1, 4, 0, 6, 6, 5]) + >>> m + Matrix([ + [0, 0, 0], + [2, 0, 0], + [1, 4, 0], + [6, 6, 5]]) + >>> m.is_lower + True + + >>> from sympy.abc import x, y + >>> m = Matrix(2, 2, [x**2 + y, y**2 + x, 0, x + y]) + >>> m + Matrix([ + [x**2 + y, x + y**2], + [ 0, x + y]]) + >>> m.is_lower + False + + See Also + ======== + + is_upper + is_diagonal + is_lower_hessenberg + """ + return self._eval_is_lower() + + @property + def is_square(self): + """Checks if a matrix is square. + + A matrix is square if the number of rows equals the number of columns. + The empty matrix is square by definition, since the number of rows and + the number of columns are both zero. + + Examples + ======== + + >>> from sympy import Matrix + >>> a = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> b = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> c = Matrix([]) + >>> a.is_square + False + >>> b.is_square + True + >>> c.is_square + True + """ + return self.rows == self.cols + + def is_symbolic(self): + """Checks if any elements contain Symbols. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.is_symbolic() + True + + """ + return self._eval_is_symbolic() + + def is_symmetric(self, simplify=True): + """Check if matrix is symmetric matrix, + that is square matrix and is equal to its transpose. + + By default, simplifications occur before testing symmetry. + They can be skipped using 'simplify=False'; while speeding things a bit, + this may however induce false negatives. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, [0, 1, 1, 2]) + >>> m + Matrix([ + [0, 1], + [1, 2]]) + >>> m.is_symmetric() + True + + >>> m = Matrix(2, 2, [0, 1, 2, 0]) + >>> m + Matrix([ + [0, 1], + [2, 0]]) + >>> m.is_symmetric() + False + + >>> m = Matrix(2, 3, [0, 0, 0, 0, 0, 0]) + >>> m + Matrix([ + [0, 0, 0], + [0, 0, 0]]) + >>> m.is_symmetric() + False + + >>> from sympy.abc import x, y + >>> m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) + >>> m + Matrix([ + [ 1, x**2 + 2*x + 1, y], + [(x + 1)**2, 2, 0], + [ y, 0, 3]]) + >>> m.is_symmetric() + True + + If the matrix is already simplified, you may speed-up is_symmetric() + test by using 'simplify=False'. + + >>> bool(m.is_symmetric(simplify=False)) + False + >>> m1 = m.expand() + >>> m1.is_symmetric(simplify=False) + True + """ + simpfunc = simplify + if not isfunction(simplify): + simpfunc = _simplify if simplify else lambda x: x + + if not self.is_square: + return False + + return self._eval_is_symmetric(simpfunc) + + @property + def is_upper_hessenberg(self): + """Checks if the matrix is the upper-Hessenberg form. + + The upper hessenberg matrix has zero entries + below the first subdiagonal. + + Examples + ======== + + >>> from sympy import Matrix + >>> a = Matrix([[1, 4, 2, 3], [3, 4, 1, 7], [0, 2, 3, 4], [0, 0, 1, 3]]) + >>> a + Matrix([ + [1, 4, 2, 3], + [3, 4, 1, 7], + [0, 2, 3, 4], + [0, 0, 1, 3]]) + >>> a.is_upper_hessenberg + True + + See Also + ======== + + is_lower_hessenberg + is_upper + """ + return self._eval_is_upper_hessenberg() + + @property + def is_upper(self): + """Check if matrix is an upper triangular matrix. True can be returned + even if the matrix is not square. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, [1, 0, 0, 1]) + >>> m + Matrix([ + [1, 0], + [0, 1]]) + >>> m.is_upper + True + + >>> m = Matrix(4, 3, [5, 1, 9, 0, 4, 6, 0, 0, 5, 0, 0, 0]) + >>> m + Matrix([ + [5, 1, 9], + [0, 4, 6], + [0, 0, 5], + [0, 0, 0]]) + >>> m.is_upper + True + + >>> m = Matrix(2, 3, [4, 2, 5, 6, 1, 1]) + >>> m + Matrix([ + [4, 2, 5], + [6, 1, 1]]) + >>> m.is_upper + False + + See Also + ======== + + is_lower + is_diagonal + is_upper_hessenberg + """ + return all(self[i, j].is_zero + for i in range(1, self.rows) + for j in range(min(i, self.cols))) + + @property + def is_zero_matrix(self): + """Checks if a matrix is a zero matrix. + + A matrix is zero if every element is zero. A matrix need not be square + to be considered zero. The empty matrix is zero by the principle of + vacuous truth. For a matrix that may or may not be zero (e.g. + contains a symbol), this will be None + + Examples + ======== + + >>> from sympy import Matrix, zeros + >>> from sympy.abc import x + >>> a = Matrix([[0, 0], [0, 0]]) + >>> b = zeros(3, 4) + >>> c = Matrix([[0, 1], [0, 0]]) + >>> d = Matrix([]) + >>> e = Matrix([[x, 0], [0, 0]]) + >>> a.is_zero_matrix + True + >>> b.is_zero_matrix + True + >>> c.is_zero_matrix + False + >>> d.is_zero_matrix + True + >>> e.is_zero_matrix + """ + return self._eval_is_zero_matrix() + + def values(self): + """Return non-zero values of self.""" + return self._eval_values() + + +class MatrixOperations(MatrixRequired): + """Provides basic matrix shape and elementwise + operations. Should not be instantiated directly.""" + + def _eval_adjoint(self): + return self.transpose().conjugate() + + def _eval_applyfunc(self, f): + out = self._new(self.rows, self.cols, [f(x) for x in self]) + return out + + def _eval_as_real_imag(self): # type: ignore + return (self.applyfunc(re), self.applyfunc(im)) + + def _eval_conjugate(self): + return self.applyfunc(lambda x: x.conjugate()) + + def _eval_permute_cols(self, perm): + # apply the permutation to a list + mapping = list(perm) + + def entry(i, j): + return self[i, mapping[j]] + + return self._new(self.rows, self.cols, entry) + + def _eval_permute_rows(self, perm): + # apply the permutation to a list + mapping = list(perm) + + def entry(i, j): + return self[mapping[i], j] + + return self._new(self.rows, self.cols, entry) + + def _eval_trace(self): + return sum(self[i, i] for i in range(self.rows)) + + def _eval_transpose(self): + return self._new(self.cols, self.rows, lambda i, j: self[j, i]) + + def adjoint(self): + """Conjugate transpose or Hermitian conjugation.""" + return self._eval_adjoint() + + def applyfunc(self, f): + """Apply a function to each element of the matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, lambda i, j: i*2+j) + >>> m + Matrix([ + [0, 1], + [2, 3]]) + >>> m.applyfunc(lambda i: 2*i) + Matrix([ + [0, 2], + [4, 6]]) + + """ + if not callable(f): + raise TypeError("`f` must be callable.") + + return self._eval_applyfunc(f) + + def as_real_imag(self, deep=True, **hints): + """Returns a tuple containing the (real, imaginary) part of matrix.""" + # XXX: Ignoring deep and hints... + return self._eval_as_real_imag() + + def conjugate(self): + """Return the by-element conjugation. + + Examples + ======== + + >>> from sympy import SparseMatrix, I + >>> a = SparseMatrix(((1, 2 + I), (3, 4), (I, -I))) + >>> a + Matrix([ + [1, 2 + I], + [3, 4], + [I, -I]]) + >>> a.C + Matrix([ + [ 1, 2 - I], + [ 3, 4], + [-I, I]]) + + See Also + ======== + + transpose: Matrix transposition + H: Hermite conjugation + sympy.matrices.matrixbase.MatrixBase.D: Dirac conjugation + """ + return self._eval_conjugate() + + def doit(self, **hints): + return self.applyfunc(lambda x: x.doit(**hints)) + + def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): + """Apply evalf() to each element of self.""" + options = {'subs':subs, 'maxn':maxn, 'chop':chop, 'strict':strict, + 'quad':quad, 'verbose':verbose} + return self.applyfunc(lambda i: i.evalf(n, **options)) + + def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, + mul=True, log=True, multinomial=True, basic=True, **hints): + """Apply core.function.expand to each entry of the matrix. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import Matrix + >>> Matrix(1, 1, [x*(x+1)]) + Matrix([[x*(x + 1)]]) + >>> _.expand() + Matrix([[x**2 + x]]) + + """ + return self.applyfunc(lambda x: x.expand( + deep, modulus, power_base, power_exp, mul, log, multinomial, basic, + **hints)) + + @property + def H(self): + """Return Hermite conjugate. + + Examples + ======== + + >>> from sympy import Matrix, I + >>> m = Matrix((0, 1 + I, 2, 3)) + >>> m + Matrix([ + [ 0], + [1 + I], + [ 2], + [ 3]]) + >>> m.H + Matrix([[0, 1 - I, 2, 3]]) + + See Also + ======== + + conjugate: By-element conjugation + sympy.matrices.matrixbase.MatrixBase.D: Dirac conjugation + """ + return self.T.C + + def permute(self, perm, orientation='rows', direction='forward'): + r"""Permute the rows or columns of a matrix by the given list of + swaps. + + Parameters + ========== + + perm : Permutation, list, or list of lists + A representation for the permutation. + + If it is ``Permutation``, it is used directly with some + resizing with respect to the matrix size. + + If it is specified as list of lists, + (e.g., ``[[0, 1], [0, 2]]``), then the permutation is formed + from applying the product of cycles. The direction how the + cyclic product is applied is described in below. + + If it is specified as a list, the list should represent + an array form of a permutation. (e.g., ``[1, 2, 0]``) which + would would form the swapping function + `0 \mapsto 1, 1 \mapsto 2, 2\mapsto 0`. + + orientation : 'rows', 'cols' + A flag to control whether to permute the rows or the columns + + direction : 'forward', 'backward' + A flag to control whether to apply the permutations from + the start of the list first, or from the back of the list + first. + + For example, if the permutation specification is + ``[[0, 1], [0, 2]]``, + + If the flag is set to ``'forward'``, the cycle would be + formed as `0 \mapsto 2, 2 \mapsto 1, 1 \mapsto 0`. + + If the flag is set to ``'backward'``, the cycle would be + formed as `0 \mapsto 1, 1 \mapsto 2, 2 \mapsto 0`. + + If the argument ``perm`` is not in a form of list of lists, + this flag takes no effect. + + Examples + ======== + + >>> from sympy import eye + >>> M = eye(3) + >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='forward') + Matrix([ + [0, 0, 1], + [1, 0, 0], + [0, 1, 0]]) + + >>> from sympy import eye + >>> M = eye(3) + >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='backward') + Matrix([ + [0, 1, 0], + [0, 0, 1], + [1, 0, 0]]) + + Notes + ===== + + If a bijective function + `\sigma : \mathbb{N}_0 \rightarrow \mathbb{N}_0` denotes the + permutation. + + If the matrix `A` is the matrix to permute, represented as + a horizontal or a vertical stack of vectors: + + .. math:: + A = + \begin{bmatrix} + a_0 \\ a_1 \\ \vdots \\ a_{n-1} + \end{bmatrix} = + \begin{bmatrix} + \alpha_0 & \alpha_1 & \cdots & \alpha_{n-1} + \end{bmatrix} + + If the matrix `B` is the result, the permutation of matrix rows + is defined as: + + .. math:: + B := \begin{bmatrix} + a_{\sigma(0)} \\ a_{\sigma(1)} \\ \vdots \\ a_{\sigma(n-1)} + \end{bmatrix} + + And the permutation of matrix columns is defined as: + + .. math:: + B := \begin{bmatrix} + \alpha_{\sigma(0)} & \alpha_{\sigma(1)} & + \cdots & \alpha_{\sigma(n-1)} + \end{bmatrix} + """ + from sympy.combinatorics import Permutation + + # allow british variants and `columns` + if direction == 'forwards': + direction = 'forward' + if direction == 'backwards': + direction = 'backward' + if orientation == 'columns': + orientation = 'cols' + + if direction not in ('forward', 'backward'): + raise TypeError("direction='{}' is an invalid kwarg. " + "Try 'forward' or 'backward'".format(direction)) + if orientation not in ('rows', 'cols'): + raise TypeError("orientation='{}' is an invalid kwarg. " + "Try 'rows' or 'cols'".format(orientation)) + + if not isinstance(perm, (Permutation, Iterable)): + raise ValueError( + "{} must be a list, a list of lists, " + "or a SymPy permutation object.".format(perm)) + + # ensure all swaps are in range + max_index = self.rows if orientation == 'rows' else self.cols + if not all(0 <= t <= max_index for t in flatten(list(perm))): + raise IndexError("`swap` indices out of range.") + + if perm and not isinstance(perm, Permutation) and \ + isinstance(perm[0], Iterable): + if direction == 'forward': + perm = list(reversed(perm)) + perm = Permutation(perm, size=max_index+1) + else: + perm = Permutation(perm, size=max_index+1) + + if orientation == 'rows': + return self._eval_permute_rows(perm) + if orientation == 'cols': + return self._eval_permute_cols(perm) + + def permute_cols(self, swaps, direction='forward'): + """Alias for + ``self.permute(swaps, orientation='cols', direction=direction)`` + + See Also + ======== + + permute + """ + return self.permute(swaps, orientation='cols', direction=direction) + + def permute_rows(self, swaps, direction='forward'): + """Alias for + ``self.permute(swaps, orientation='rows', direction=direction)`` + + See Also + ======== + + permute + """ + return self.permute(swaps, orientation='rows', direction=direction) + + def refine(self, assumptions=True): + """Apply refine to each element of the matrix. + + Examples + ======== + + >>> from sympy import Symbol, Matrix, Abs, sqrt, Q + >>> x = Symbol('x') + >>> Matrix([[Abs(x)**2, sqrt(x**2)],[sqrt(x**2), Abs(x)**2]]) + Matrix([ + [ Abs(x)**2, sqrt(x**2)], + [sqrt(x**2), Abs(x)**2]]) + >>> _.refine(Q.real(x)) + Matrix([ + [ x**2, Abs(x)], + [Abs(x), x**2]]) + + """ + return self.applyfunc(lambda x: refine(x, assumptions)) + + def replace(self, F, G, map=False, simultaneous=True, exact=None): + """Replaces Function F in Matrix entries with Function G. + + Examples + ======== + + >>> from sympy import symbols, Function, Matrix + >>> F, G = symbols('F, G', cls=Function) + >>> M = Matrix(2, 2, lambda i, j: F(i+j)) ; M + Matrix([ + [F(0), F(1)], + [F(1), F(2)]]) + >>> N = M.replace(F,G) + >>> N + Matrix([ + [G(0), G(1)], + [G(1), G(2)]]) + """ + return self.applyfunc( + lambda x: x.replace(F, G, map=map, simultaneous=simultaneous, exact=exact)) + + def rot90(self, k=1): + """Rotates Matrix by 90 degrees + + Parameters + ========== + + k : int + Specifies how many times the matrix is rotated by 90 degrees + (clockwise when positive, counter-clockwise when negative). + + Examples + ======== + + >>> from sympy import Matrix, symbols + >>> A = Matrix(2, 2, symbols('a:d')) + >>> A + Matrix([ + [a, b], + [c, d]]) + + Rotating the matrix clockwise one time: + + >>> A.rot90(1) + Matrix([ + [c, a], + [d, b]]) + + Rotating the matrix anticlockwise two times: + + >>> A.rot90(-2) + Matrix([ + [d, c], + [b, a]]) + """ + + mod = k%4 + if mod == 0: + return self + if mod == 1: + return self[::-1, ::].T + if mod == 2: + return self[::-1, ::-1] + if mod == 3: + return self[::, ::-1].T + + def simplify(self, **kwargs): + """Apply simplify to each element of the matrix. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import SparseMatrix, sin, cos + >>> SparseMatrix(1, 1, [x*sin(y)**2 + x*cos(y)**2]) + Matrix([[x*sin(y)**2 + x*cos(y)**2]]) + >>> _.simplify() + Matrix([[x]]) + """ + return self.applyfunc(lambda x: x.simplify(**kwargs)) + + def subs(self, *args, **kwargs): # should mirror core.basic.subs + """Return a new matrix with subs applied to each entry. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import SparseMatrix, Matrix + >>> SparseMatrix(1, 1, [x]) + Matrix([[x]]) + >>> _.subs(x, y) + Matrix([[y]]) + >>> Matrix(_).subs(y, x) + Matrix([[x]]) + """ + + if len(args) == 1 and not isinstance(args[0], (dict, set)) and iter(args[0]) and not is_sequence(args[0]): + args = (list(args[0]),) + + return self.applyfunc(lambda x: x.subs(*args, **kwargs)) + + def trace(self): + """ + Returns the trace of a square matrix i.e. the sum of the + diagonal elements. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix(2, 2, [1, 2, 3, 4]) + >>> A.trace() + 5 + + """ + if self.rows != self.cols: + raise NonSquareMatrixError() + return self._eval_trace() + + def transpose(self): + """ + Returns the transpose of the matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix(2, 2, [1, 2, 3, 4]) + >>> A.transpose() + Matrix([ + [1, 3], + [2, 4]]) + + >>> from sympy import Matrix, I + >>> m=Matrix(((1, 2+I), (3, 4))) + >>> m + Matrix([ + [1, 2 + I], + [3, 4]]) + >>> m.transpose() + Matrix([ + [ 1, 3], + [2 + I, 4]]) + >>> m.T == m.transpose() + True + + See Also + ======== + + conjugate: By-element conjugation + + """ + return self._eval_transpose() + + @property + def T(self): + '''Matrix transposition''' + return self.transpose() + + @property + def C(self): + '''By-element conjugation''' + return self.conjugate() + + def n(self, *args, **kwargs): + """Apply evalf() to each element of self.""" + return self.evalf(*args, **kwargs) + + def xreplace(self, rule): # should mirror core.basic.xreplace + """Return a new matrix with xreplace applied to each entry. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import SparseMatrix, Matrix + >>> SparseMatrix(1, 1, [x]) + Matrix([[x]]) + >>> _.xreplace({x: y}) + Matrix([[y]]) + >>> Matrix(_).xreplace({y: x}) + Matrix([[x]]) + """ + return self.applyfunc(lambda x: x.xreplace(rule)) + + def _eval_simplify(self, **kwargs): + # XXX: We can't use self.simplify here as mutable subclasses will + # override simplify and have it return None + return MatrixOperations.simplify(self, **kwargs) + + def _eval_trigsimp(self, **opts): + from sympy.simplify.trigsimp import trigsimp + return self.applyfunc(lambda x: trigsimp(x, **opts)) + + def upper_triangular(self, k=0): + """Return the elements on and above the kth diagonal of a matrix. + If k is not specified then simply returns upper-triangular portion + of a matrix + + Examples + ======== + + >>> from sympy import ones + >>> A = ones(4) + >>> A.upper_triangular() + Matrix([ + [1, 1, 1, 1], + [0, 1, 1, 1], + [0, 0, 1, 1], + [0, 0, 0, 1]]) + + >>> A.upper_triangular(2) + Matrix([ + [0, 0, 1, 1], + [0, 0, 0, 1], + [0, 0, 0, 0], + [0, 0, 0, 0]]) + + >>> A.upper_triangular(-1) + Matrix([ + [1, 1, 1, 1], + [1, 1, 1, 1], + [0, 1, 1, 1], + [0, 0, 1, 1]]) + + """ + + def entry(i, j): + return self[i, j] if i + k <= j else self.zero + + return self._new(self.rows, self.cols, entry) + + + def lower_triangular(self, k=0): + """Return the elements on and below the kth diagonal of a matrix. + If k is not specified then simply returns lower-triangular portion + of a matrix + + Examples + ======== + + >>> from sympy import ones + >>> A = ones(4) + >>> A.lower_triangular() + Matrix([ + [1, 0, 0, 0], + [1, 1, 0, 0], + [1, 1, 1, 0], + [1, 1, 1, 1]]) + + >>> A.lower_triangular(-2) + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [1, 0, 0, 0], + [1, 1, 0, 0]]) + + >>> A.lower_triangular(1) + Matrix([ + [1, 1, 0, 0], + [1, 1, 1, 0], + [1, 1, 1, 1], + [1, 1, 1, 1]]) + + """ + + def entry(i, j): + return self[i, j] if i + k >= j else self.zero + + return self._new(self.rows, self.cols, entry) + + + +class MatrixArithmetic(MatrixRequired): + """Provides basic matrix arithmetic operations. + Should not be instantiated directly.""" + + _op_priority = 10.01 + + def _eval_Abs(self): + return self._new(self.rows, self.cols, lambda i, j: Abs(self[i, j])) + + def _eval_add(self, other): + return self._new(self.rows, self.cols, + lambda i, j: self[i, j] + other[i, j]) + + def _eval_matrix_mul(self, other): + def entry(i, j): + vec = [self[i,k]*other[k,j] for k in range(self.cols)] + try: + return Add(*vec) + except (TypeError, SympifyError): + # Some matrices don't work with `sum` or `Add` + # They don't work with `sum` because `sum` tries to add `0` + # Fall back to a safe way to multiply if the `Add` fails. + return reduce(lambda a, b: a + b, vec) + + return self._new(self.rows, other.cols, entry) + + def _eval_matrix_mul_elementwise(self, other): + return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other[i,j]) + + def _eval_matrix_rmul(self, other): + def entry(i, j): + return sum(other[i,k]*self[k,j] for k in range(other.cols)) + return self._new(other.rows, self.cols, entry) + + def _eval_pow_by_recursion(self, num): + if num == 1: + return self + + if num % 2 == 1: + a, b = self, self._eval_pow_by_recursion(num - 1) + else: + a = b = self._eval_pow_by_recursion(num // 2) + + return a.multiply(b) + + def _eval_pow_by_cayley(self, exp): + from sympy.discrete.recurrences import linrec_coeffs + row = self.shape[0] + p = self.charpoly() + + coeffs = (-p).all_coeffs()[1:] + coeffs = linrec_coeffs(coeffs, exp) + new_mat = self.eye(row) + ans = self.zeros(row) + + for i in range(row): + ans += coeffs[i]*new_mat + new_mat *= self + + return ans + + def _eval_pow_by_recursion_dotprodsimp(self, num, prevsimp=None): + if prevsimp is None: + prevsimp = [True]*len(self) + + if num == 1: + return self + + if num % 2 == 1: + a, b = self, self._eval_pow_by_recursion_dotprodsimp(num - 1, + prevsimp=prevsimp) + else: + a = b = self._eval_pow_by_recursion_dotprodsimp(num // 2, + prevsimp=prevsimp) + + m = a.multiply(b, dotprodsimp=False) + lenm = len(m) + elems = [None]*lenm + + for i in range(lenm): + if prevsimp[i]: + elems[i], prevsimp[i] = _dotprodsimp(m[i], withsimp=True) + else: + elems[i] = m[i] + + return m._new(m.rows, m.cols, elems) + + def _eval_scalar_mul(self, other): + return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other) + + def _eval_scalar_rmul(self, other): + return self._new(self.rows, self.cols, lambda i, j: other*self[i,j]) + + def _eval_Mod(self, other): + return self._new(self.rows, self.cols, lambda i, j: Mod(self[i, j], other)) + + # Python arithmetic functions + def __abs__(self): + """Returns a new matrix with entry-wise absolute values.""" + return self._eval_Abs() + + @call_highest_priority('__radd__') + def __add__(self, other): + """Return self + other, raising ShapeError if shapes do not match.""" + if isinstance(other, NDimArray): # Matrix and array addition is currently not implemented + return NotImplemented + other = _matrixify(other) + # matrix-like objects can have shapes. This is + # our first sanity check. + if hasattr(other, 'shape'): + if self.shape != other.shape: + raise ShapeError("Matrix size mismatch: %s + %s" % ( + self.shape, other.shape)) + + # honest SymPy matrices defer to their class's routine + if getattr(other, 'is_Matrix', False): + # call the highest-priority class's _eval_add + a, b = self, other + if a.__class__ != classof(a, b): + b, a = a, b + return a._eval_add(b) + # Matrix-like objects can be passed to CommonMatrix routines directly. + if getattr(other, 'is_MatrixLike', False): + return MatrixArithmetic._eval_add(self, other) + + raise TypeError('cannot add %s and %s' % (type(self), type(other))) + + @call_highest_priority('__rtruediv__') + def __truediv__(self, other): + return self * (self.one / other) + + @call_highest_priority('__rmatmul__') + def __matmul__(self, other): + other = _matrixify(other) + if not getattr(other, 'is_Matrix', False) and not getattr(other, 'is_MatrixLike', False): + return NotImplemented + + return self.__mul__(other) + + def __mod__(self, other): + return self.applyfunc(lambda x: x % other) + + @call_highest_priority('__rmul__') + def __mul__(self, other): + """Return self*other where other is either a scalar or a matrix + of compatible dimensions. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> 2*A == A*2 == Matrix([[2, 4, 6], [8, 10, 12]]) + True + >>> B = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> A*B + Matrix([ + [30, 36, 42], + [66, 81, 96]]) + >>> B*A + Traceback (most recent call last): + ... + ShapeError: Matrices size mismatch. + >>> + + See Also + ======== + + matrix_multiply_elementwise + """ + + return self.multiply(other) + + def multiply(self, other, dotprodsimp=None): + """Same as __mul__() but with optional simplification. + + Parameters + ========== + + dotprodsimp : bool, optional + Specifies whether intermediate term algebraic simplification is used + during matrix multiplications to control expression blowup and thus + speed up calculation. Default is off. + """ + + isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) + other = _matrixify(other) + # matrix-like objects can have shapes. This is + # our first sanity check. Double check other is not explicitly not a Matrix. + if (hasattr(other, 'shape') and len(other.shape) == 2 and + (getattr(other, 'is_Matrix', True) or + getattr(other, 'is_MatrixLike', True))): + if self.shape[1] != other.shape[0]: + raise ShapeError("Matrix size mismatch: %s * %s." % ( + self.shape, other.shape)) + + # honest SymPy matrices defer to their class's routine + if getattr(other, 'is_Matrix', False): + m = self._eval_matrix_mul(other) + if isimpbool: + return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) + return m + + # Matrix-like objects can be passed to CommonMatrix routines directly. + if getattr(other, 'is_MatrixLike', False): + return MatrixArithmetic._eval_matrix_mul(self, other) + + # if 'other' is not iterable then scalar multiplication. + if not isinstance(other, Iterable): + try: + return self._eval_scalar_mul(other) + except TypeError: + pass + + return NotImplemented + + def multiply_elementwise(self, other): + """Return the Hadamard product (elementwise product) of A and B + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) + >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) + >>> A.multiply_elementwise(B) + Matrix([ + [ 0, 10, 200], + [300, 40, 5]]) + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.cross + sympy.matrices.matrixbase.MatrixBase.dot + multiply + """ + if self.shape != other.shape: + raise ShapeError("Matrix shapes must agree {} != {}".format(self.shape, other.shape)) + + return self._eval_matrix_mul_elementwise(other) + + def __neg__(self): + return self._eval_scalar_mul(-1) + + @call_highest_priority('__rpow__') + def __pow__(self, exp): + """Return self**exp a scalar or symbol.""" + + return self.pow(exp) + + + def pow(self, exp, method=None): + r"""Return self**exp a scalar or symbol. + + Parameters + ========== + + method : multiply, mulsimp, jordan, cayley + If multiply then it returns exponentiation using recursion. + If jordan then Jordan form exponentiation will be used. + If cayley then the exponentiation is done using Cayley-Hamilton + theorem. + If mulsimp then the exponentiation is done using recursion + with dotprodsimp. This specifies whether intermediate term + algebraic simplification is used during naive matrix power to + control expression blowup and thus speed up calculation. + If None, then it heuristically decides which method to use. + + """ + + if method is not None and method not in ['multiply', 'mulsimp', 'jordan', 'cayley']: + raise TypeError('No such method') + if self.rows != self.cols: + raise NonSquareMatrixError() + a = self + jordan_pow = getattr(a, '_matrix_pow_by_jordan_blocks', None) + exp = sympify(exp) + + if exp.is_zero: + return a._new(a.rows, a.cols, lambda i, j: int(i == j)) + if exp == 1: + return a + + diagonal = getattr(a, 'is_diagonal', None) + if diagonal is not None and diagonal(): + return a._new(a.rows, a.cols, lambda i, j: a[i,j]**exp if i == j else 0) + + if exp.is_Number and exp % 1 == 0: + if a.rows == 1: + return a._new([[a[0]**exp]]) + if exp < 0: + exp = -exp + a = a.inv() + # When certain conditions are met, + # Jordan block algorithm is faster than + # computation by recursion. + if method == 'jordan': + try: + return jordan_pow(exp) + except MatrixError: + if method == 'jordan': + raise + + elif method == 'cayley': + if not exp.is_Number or exp % 1 != 0: + raise ValueError("cayley method is only valid for integer powers") + return a._eval_pow_by_cayley(exp) + + elif method == "mulsimp": + if not exp.is_Number or exp % 1 != 0: + raise ValueError("mulsimp method is only valid for integer powers") + return a._eval_pow_by_recursion_dotprodsimp(exp) + + elif method == "multiply": + if not exp.is_Number or exp % 1 != 0: + raise ValueError("multiply method is only valid for integer powers") + return a._eval_pow_by_recursion(exp) + + elif method is None and exp.is_Number and exp % 1 == 0: + if exp.is_Float: + exp = Integer(exp) + # Decide heuristically which method to apply + if a.rows == 2 and exp > 100000: + return jordan_pow(exp) + elif _get_intermediate_simp_bool(True, None): + return a._eval_pow_by_recursion_dotprodsimp(exp) + elif exp > 10000: + return a._eval_pow_by_cayley(exp) + else: + return a._eval_pow_by_recursion(exp) + + if jordan_pow: + try: + return jordan_pow(exp) + except NonInvertibleMatrixError: + # Raised by jordan_pow on zero determinant matrix unless exp is + # definitely known to be a non-negative integer. + # Here we raise if n is definitely not a non-negative integer + # but otherwise we can leave this as an unevaluated MatPow. + if exp.is_integer is False or exp.is_nonnegative is False: + raise + + from sympy.matrices.expressions import MatPow + return MatPow(a, exp) + + @call_highest_priority('__add__') + def __radd__(self, other): + return self + other + + @call_highest_priority('__matmul__') + def __rmatmul__(self, other): + other = _matrixify(other) + if not getattr(other, 'is_Matrix', False) and not getattr(other, 'is_MatrixLike', False): + return NotImplemented + + return self.__rmul__(other) + + @call_highest_priority('__mul__') + def __rmul__(self, other): + return self.rmultiply(other) + + def rmultiply(self, other, dotprodsimp=None): + """Same as __rmul__() but with optional simplification. + + Parameters + ========== + + dotprodsimp : bool, optional + Specifies whether intermediate term algebraic simplification is used + during matrix multiplications to control expression blowup and thus + speed up calculation. Default is off. + """ + isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) + other = _matrixify(other) + # matrix-like objects can have shapes. This is + # our first sanity check. Double check other is not explicitly not a Matrix. + if (hasattr(other, 'shape') and len(other.shape) == 2 and + (getattr(other, 'is_Matrix', True) or + getattr(other, 'is_MatrixLike', True))): + if self.shape[0] != other.shape[1]: + raise ShapeError("Matrix size mismatch.") + + # honest SymPy matrices defer to their class's routine + if getattr(other, 'is_Matrix', False): + m = self._eval_matrix_rmul(other) + if isimpbool: + return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) + return m + # Matrix-like objects can be passed to CommonMatrix routines directly. + if getattr(other, 'is_MatrixLike', False): + return MatrixArithmetic._eval_matrix_rmul(self, other) + + # if 'other' is not iterable then scalar multiplication. + if not isinstance(other, Iterable): + try: + return self._eval_scalar_rmul(other) + except TypeError: + pass + + return NotImplemented + + @call_highest_priority('__sub__') + def __rsub__(self, a): + return (-self) + a + + @call_highest_priority('__rsub__') + def __sub__(self, a): + return self + (-a) + + +class MatrixCommon(MatrixArithmetic, MatrixOperations, MatrixProperties, + MatrixSpecial, MatrixShaping): + """All common matrix operations including basic arithmetic, shaping, + and special matrices like `zeros`, and `eye`.""" + _diff_wrt: bool = True + + +class _MinimalMatrix: + """Class providing the minimum functionality + for a matrix-like object and implementing every method + required for a `MatrixRequired`. This class does not have everything + needed to become a full-fledged SymPy object, but it will satisfy the + requirements of anything inheriting from `MatrixRequired`. If you wish + to make a specialized matrix type, make sure to implement these + methods and properties with the exception of `__init__` and `__repr__` + which are included for convenience.""" + + is_MatrixLike = True + _sympify = staticmethod(sympify) + _class_priority = 3 + zero = S.Zero + one = S.One + + is_Matrix = True + is_MatrixExpr = False + + @classmethod + def _new(cls, *args, **kwargs): + return cls(*args, **kwargs) + + def __init__(self, rows, cols=None, mat=None, copy=False): + if isfunction(mat): + # if we passed in a function, use that to populate the indices + mat = [mat(i, j) for i in range(rows) for j in range(cols)] + if cols is None and mat is None: + mat = rows + rows, cols = getattr(mat, 'shape', (rows, cols)) + try: + # if we passed in a list of lists, flatten it and set the size + if cols is None and mat is None: + mat = rows + cols = len(mat[0]) + rows = len(mat) + mat = [x for l in mat for x in l] + except (IndexError, TypeError): + pass + self.mat = tuple(self._sympify(x) for x in mat) + self.rows, self.cols = rows, cols + if self.rows is None or self.cols is None: + raise NotImplementedError("Cannot initialize matrix with given parameters") + + def __getitem__(self, key): + def _normalize_slices(row_slice, col_slice): + """Ensure that row_slice and col_slice do not have + `None` in their arguments. Any integers are converted + to slices of length 1""" + if not isinstance(row_slice, slice): + row_slice = slice(row_slice, row_slice + 1, None) + row_slice = slice(*row_slice.indices(self.rows)) + + if not isinstance(col_slice, slice): + col_slice = slice(col_slice, col_slice + 1, None) + col_slice = slice(*col_slice.indices(self.cols)) + + return (row_slice, col_slice) + + def _coord_to_index(i, j): + """Return the index in _mat corresponding + to the (i,j) position in the matrix. """ + return i * self.cols + j + + if isinstance(key, tuple): + i, j = key + if isinstance(i, slice) or isinstance(j, slice): + # if the coordinates are not slices, make them so + # and expand the slices so they don't contain `None` + i, j = _normalize_slices(i, j) + + rowsList, colsList = list(range(self.rows))[i], \ + list(range(self.cols))[j] + indices = (i * self.cols + j for i in rowsList for j in + colsList) + return self._new(len(rowsList), len(colsList), + [self.mat[i] for i in indices]) + + # if the key is a tuple of ints, change + # it to an array index + key = _coord_to_index(i, j) + return self.mat[key] + + def __eq__(self, other): + try: + classof(self, other) + except TypeError: + return False + return ( + self.shape == other.shape and list(self) == list(other)) + + def __len__(self): + return self.rows*self.cols + + def __repr__(self): + return "_MinimalMatrix({}, {}, {})".format(self.rows, self.cols, + self.mat) + + @property + def shape(self): + return (self.rows, self.cols) + + +class _CastableMatrix: # this is needed here ONLY FOR TESTS. + def as_mutable(self): + return self + + def as_immutable(self): + return self + + +class _MatrixWrapper: + """Wrapper class providing the minimum functionality for a matrix-like + object: .rows, .cols, .shape, indexability, and iterability. CommonMatrix + math operations should work on matrix-like objects. This one is intended for + matrix-like objects which use the same indexing format as SymPy with respect + to returning matrix elements instead of rows for non-tuple indexes. + """ + + is_Matrix = False # needs to be here because of __getattr__ + is_MatrixLike = True + + def __init__(self, mat, shape): + self.mat = mat + self.shape = shape + self.rows, self.cols = shape + + def __getitem__(self, key): + if isinstance(key, tuple): + return sympify(self.mat.__getitem__(key)) + + return sympify(self.mat.__getitem__((key // self.rows, key % self.cols))) + + def __iter__(self): # supports numpy.matrix and numpy.array + mat = self.mat + cols = self.cols + + return iter(sympify(mat[r, c]) for r in range(self.rows) for c in range(cols)) + + +def _matrixify(mat): + """If `mat` is a Matrix or is matrix-like, + return a Matrix or MatrixWrapper object. Otherwise + `mat` is passed through without modification.""" + + if getattr(mat, 'is_Matrix', False) or getattr(mat, 'is_MatrixLike', False): + return mat + + if not(getattr(mat, 'is_Matrix', True) or getattr(mat, 'is_MatrixLike', True)): + return mat + + shape = None + + if hasattr(mat, 'shape'): # numpy, scipy.sparse + if len(mat.shape) == 2: + shape = mat.shape + elif hasattr(mat, 'rows') and hasattr(mat, 'cols'): # mpmath + shape = (mat.rows, mat.cols) + + if shape: + return _MatrixWrapper(mat, shape) + + return mat + + +def a2idx(j, n=None): + """Return integer after making positive and validating against n.""" + if not isinstance(j, int): + jindex = getattr(j, '__index__', None) + if jindex is not None: + j = jindex() + else: + raise IndexError("Invalid index a[%r]" % (j,)) + if n is not None: + if j < 0: + j += n + if not (j >= 0 and j < n): + raise IndexError("Index out of range: a[%s]" % (j,)) + return int(j) + + +def classof(A, B): + """ + Get the type of the result when combining matrices of different types. + + Currently the strategy is that immutability is contagious. + + Examples + ======== + + >>> from sympy import Matrix, ImmutableMatrix + >>> from sympy.matrices.matrixbase import classof + >>> M = Matrix([[1, 2], [3, 4]]) # a Mutable Matrix + >>> IM = ImmutableMatrix([[1, 2], [3, 4]]) + >>> classof(M, IM) + + """ + priority_A = getattr(A, '_class_priority', None) + priority_B = getattr(B, '_class_priority', None) + if None not in (priority_A, priority_B): + if A._class_priority > B._class_priority: + return A.__class__ + else: + return B.__class__ + + try: + import numpy + except ImportError: + pass + else: + if isinstance(A, numpy.ndarray): + return B.__class__ + if isinstance(B, numpy.ndarray): + return A.__class__ + + raise TypeError("Incompatible classes %s, %s" % (A.__class__, B.__class__)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/decompositions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/decompositions.py new file mode 100644 index 0000000000000000000000000000000000000000..a8dd466d84c957b870396a050fd25ec21e7113a3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/decompositions.py @@ -0,0 +1,1621 @@ +import copy + +from sympy.core import S +from sympy.core.function import expand_mul +from sympy.functions.elementary.miscellaneous import Min, sqrt +from sympy.functions.elementary.complexes import sign + +from .exceptions import NonSquareMatrixError, NonPositiveDefiniteMatrixError +from .utilities import _get_intermediate_simp, _iszero +from .determinant import _find_reasonable_pivot_naive + + +def _rank_decomposition(M, iszerofunc=_iszero, simplify=False): + r"""Returns a pair of matrices (`C`, `F`) with matching rank + such that `A = C F`. + + Parameters + ========== + + iszerofunc : Function, optional + A function used for detecting whether an element can + act as a pivot. ``lambda x: x.is_zero`` is used by default. + + simplify : Bool or Function, optional + A function used to simplify elements when looking for a + pivot. By default SymPy's ``simplify`` is used. + + Returns + ======= + + (C, F) : Matrices + `C` and `F` are full-rank matrices with rank as same as `A`, + whose product gives `A`. + + See Notes for additional mathematical details. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([ + ... [1, 3, 1, 4], + ... [2, 7, 3, 9], + ... [1, 5, 3, 1], + ... [1, 2, 0, 8] + ... ]) + >>> C, F = A.rank_decomposition() + >>> C + Matrix([ + [1, 3, 4], + [2, 7, 9], + [1, 5, 1], + [1, 2, 8]]) + >>> F + Matrix([ + [1, 0, -2, 0], + [0, 1, 1, 0], + [0, 0, 0, 1]]) + >>> C * F == A + True + + Notes + ===== + + Obtaining `F`, an RREF of `A`, is equivalent to creating a + product + + .. math:: + E_n E_{n-1} ... E_1 A = F + + where `E_n, E_{n-1}, \dots, E_1` are the elimination matrices or + permutation matrices equivalent to each row-reduction step. + + The inverse of the same product of elimination matrices gives + `C`: + + .. math:: + C = \left(E_n E_{n-1} \dots E_1\right)^{-1} + + It is not necessary, however, to actually compute the inverse: + the columns of `C` are those from the original matrix with the + same column indices as the indices of the pivot columns of `F`. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Rank_factorization + + .. [2] Piziak, R.; Odell, P. L. (1 June 1999). + "Full Rank Factorization of Matrices". + Mathematics Magazine. 72 (3): 193. doi:10.2307/2690882 + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.rref + """ + + F, pivot_cols = M.rref(simplify=simplify, iszerofunc=iszerofunc, + pivots=True) + rank = len(pivot_cols) + + C = M.extract(range(M.rows), pivot_cols) + F = F[:rank, :] + + return C, F + + +def _liupc(M): + """Liu's algorithm, for pre-determination of the Elimination Tree of + the given matrix, used in row-based symbolic Cholesky factorization. + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> S = SparseMatrix([ + ... [1, 0, 3, 2], + ... [0, 0, 1, 0], + ... [4, 0, 0, 5], + ... [0, 6, 7, 0]]) + >>> S.liupc() + ([[0], [], [0], [1, 2]], [4, 3, 4, 4]) + + References + ========== + + .. [1] Symbolic Sparse Cholesky Factorization using Elimination Trees, + Jeroen Van Grondelle (1999) + https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.7582 + """ + # Algorithm 2.4, p 17 of reference + + # get the indices of the elements that are non-zero on or below diag + R = [[] for r in range(M.rows)] + + for r, c, _ in M.row_list(): + if c <= r: + R[r].append(c) + + inf = len(R) # nothing will be this large + parent = [inf]*M.rows + virtual = [inf]*M.rows + + for r in range(M.rows): + for c in R[r][:-1]: + while virtual[c] < r: + t = virtual[c] + virtual[c] = r + c = t + + if virtual[c] == inf: + parent[c] = virtual[c] = r + + return R, parent + +def _row_structure_symbolic_cholesky(M): + """Symbolic cholesky factorization, for pre-determination of the + non-zero structure of the Cholesky factororization. + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> S = SparseMatrix([ + ... [1, 0, 3, 2], + ... [0, 0, 1, 0], + ... [4, 0, 0, 5], + ... [0, 6, 7, 0]]) + >>> S.row_structure_symbolic_cholesky() + [[0], [], [0], [1, 2]] + + References + ========== + + .. [1] Symbolic Sparse Cholesky Factorization using Elimination Trees, + Jeroen Van Grondelle (1999) + https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.7582 + """ + + R, parent = M.liupc() + inf = len(R) # this acts as infinity + Lrow = copy.deepcopy(R) + + for k in range(M.rows): + for j in R[k]: + while j != inf and j != k: + Lrow[k].append(j) + j = parent[j] + + Lrow[k] = sorted(set(Lrow[k])) + + return Lrow + + +def _cholesky(M, hermitian=True): + """Returns the Cholesky-type decomposition L of a matrix A + such that L * L.H == A if hermitian flag is True, + or L * L.T == A if hermitian is False. + + A must be a Hermitian positive-definite matrix if hermitian is True, + or a symmetric matrix if it is False. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) + >>> A.cholesky() + Matrix([ + [ 5, 0, 0], + [ 3, 3, 0], + [-1, 1, 3]]) + >>> A.cholesky() * A.cholesky().T + Matrix([ + [25, 15, -5], + [15, 18, 0], + [-5, 0, 11]]) + + The matrix can have complex entries: + + >>> from sympy import I + >>> A = Matrix(((9, 3*I), (-3*I, 5))) + >>> A.cholesky() + Matrix([ + [ 3, 0], + [-I, 2]]) + >>> A.cholesky() * A.cholesky().H + Matrix([ + [ 9, 3*I], + [-3*I, 5]]) + + Non-hermitian Cholesky-type decomposition may be useful when the + matrix is not positive-definite. + + >>> A = Matrix([[1, 2], [2, 1]]) + >>> L = A.cholesky(hermitian=False) + >>> L + Matrix([ + [1, 0], + [2, sqrt(3)*I]]) + >>> L*L.T == A + True + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.LDLdecomposition + sympy.matrices.matrixbase.MatrixBase.LUdecomposition + QRdecomposition + """ + + from .dense import MutableDenseMatrix + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + if hermitian and not M.is_hermitian: + raise ValueError("Matrix must be Hermitian.") + if not hermitian and not M.is_symmetric(): + raise ValueError("Matrix must be symmetric.") + + L = MutableDenseMatrix.zeros(M.rows, M.rows) + + if hermitian: + for i in range(M.rows): + for j in range(i): + L[i, j] = ((1 / L[j, j])*(M[i, j] - + sum(L[i, k]*L[j, k].conjugate() for k in range(j)))) + + Lii2 = (M[i, i] - + sum(L[i, k]*L[i, k].conjugate() for k in range(i))) + + if Lii2.is_positive is False: + raise NonPositiveDefiniteMatrixError( + "Matrix must be positive-definite") + + L[i, i] = sqrt(Lii2) + + else: + for i in range(M.rows): + for j in range(i): + L[i, j] = ((1 / L[j, j])*(M[i, j] - + sum(L[i, k]*L[j, k] for k in range(j)))) + + L[i, i] = sqrt(M[i, i] - + sum(L[i, k]**2 for k in range(i))) + + return M._new(L) + +def _cholesky_sparse(M, hermitian=True): + """ + Returns the Cholesky decomposition L of a matrix A + such that L * L.T = A + + A must be a square, symmetric, positive-definite + and non-singular matrix + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> A = SparseMatrix(((25,15,-5),(15,18,0),(-5,0,11))) + >>> A.cholesky() + Matrix([ + [ 5, 0, 0], + [ 3, 3, 0], + [-1, 1, 3]]) + >>> A.cholesky() * A.cholesky().T == A + True + + The matrix can have complex entries: + + >>> from sympy import I + >>> A = SparseMatrix(((9, 3*I), (-3*I, 5))) + >>> A.cholesky() + Matrix([ + [ 3, 0], + [-I, 2]]) + >>> A.cholesky() * A.cholesky().H + Matrix([ + [ 9, 3*I], + [-3*I, 5]]) + + Non-hermitian Cholesky-type decomposition may be useful when the + matrix is not positive-definite. + + >>> A = SparseMatrix([[1, 2], [2, 1]]) + >>> L = A.cholesky(hermitian=False) + >>> L + Matrix([ + [1, 0], + [2, sqrt(3)*I]]) + >>> L*L.T == A + True + + See Also + ======== + + sympy.matrices.sparse.SparseMatrix.LDLdecomposition + sympy.matrices.matrixbase.MatrixBase.LUdecomposition + QRdecomposition + """ + + from .dense import MutableDenseMatrix + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + if hermitian and not M.is_hermitian: + raise ValueError("Matrix must be Hermitian.") + if not hermitian and not M.is_symmetric(): + raise ValueError("Matrix must be symmetric.") + + dps = _get_intermediate_simp(expand_mul, expand_mul) + Crowstruc = M.row_structure_symbolic_cholesky() + C = MutableDenseMatrix.zeros(M.rows) + + for i in range(len(Crowstruc)): + for j in Crowstruc[i]: + if i != j: + C[i, j] = M[i, j] + summ = 0 + + for p1 in Crowstruc[i]: + if p1 < j: + for p2 in Crowstruc[j]: + if p2 < j: + if p1 == p2: + if hermitian: + summ += C[i, p1]*C[j, p1].conjugate() + else: + summ += C[i, p1]*C[j, p1] + else: + break + else: + break + + C[i, j] = dps((C[i, j] - summ) / C[j, j]) + + else: # i == j + C[j, j] = M[j, j] + summ = 0 + + for k in Crowstruc[j]: + if k < j: + if hermitian: + summ += C[j, k]*C[j, k].conjugate() + else: + summ += C[j, k]**2 + else: + break + + Cjj2 = dps(C[j, j] - summ) + + if hermitian and Cjj2.is_positive is False: + raise NonPositiveDefiniteMatrixError( + "Matrix must be positive-definite") + + C[j, j] = sqrt(Cjj2) + + return M._new(C) + + +def _LDLdecomposition(M, hermitian=True): + """Returns the LDL Decomposition (L, D) of matrix A, + such that L * D * L.H == A if hermitian flag is True, or + L * D * L.T == A if hermitian is False. + This method eliminates the use of square root. + Further this ensures that all the diagonal entries of L are 1. + A must be a Hermitian positive-definite matrix if hermitian is True, + or a symmetric matrix otherwise. + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) + >>> L, D = A.LDLdecomposition() + >>> L + Matrix([ + [ 1, 0, 0], + [ 3/5, 1, 0], + [-1/5, 1/3, 1]]) + >>> D + Matrix([ + [25, 0, 0], + [ 0, 9, 0], + [ 0, 0, 9]]) + >>> L * D * L.T * A.inv() == eye(A.rows) + True + + The matrix can have complex entries: + + >>> from sympy import I + >>> A = Matrix(((9, 3*I), (-3*I, 5))) + >>> L, D = A.LDLdecomposition() + >>> L + Matrix([ + [ 1, 0], + [-I/3, 1]]) + >>> D + Matrix([ + [9, 0], + [0, 4]]) + >>> L*D*L.H == A + True + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.cholesky + sympy.matrices.matrixbase.MatrixBase.LUdecomposition + QRdecomposition + """ + + from .dense import MutableDenseMatrix + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + if hermitian and not M.is_hermitian: + raise ValueError("Matrix must be Hermitian.") + if not hermitian and not M.is_symmetric(): + raise ValueError("Matrix must be symmetric.") + + D = MutableDenseMatrix.zeros(M.rows, M.rows) + L = MutableDenseMatrix.eye(M.rows) + + if hermitian: + for i in range(M.rows): + for j in range(i): + L[i, j] = (1 / D[j, j])*(M[i, j] - sum( + L[i, k]*L[j, k].conjugate()*D[k, k] for k in range(j))) + + D[i, i] = (M[i, i] - + sum(L[i, k]*L[i, k].conjugate()*D[k, k] for k in range(i))) + + if D[i, i].is_positive is False: + raise NonPositiveDefiniteMatrixError( + "Matrix must be positive-definite") + + else: + for i in range(M.rows): + for j in range(i): + L[i, j] = (1 / D[j, j])*(M[i, j] - sum( + L[i, k]*L[j, k]*D[k, k] for k in range(j))) + + D[i, i] = M[i, i] - sum(L[i, k]**2*D[k, k] for k in range(i)) + + return M._new(L), M._new(D) + +def _LDLdecomposition_sparse(M, hermitian=True): + """ + Returns the LDL Decomposition (matrices ``L`` and ``D``) of matrix + ``A``, such that ``L * D * L.T == A``. ``A`` must be a square, + symmetric, positive-definite and non-singular. + + This method eliminates the use of square root and ensures that all + the diagonal entries of L are 1. + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) + >>> L, D = A.LDLdecomposition() + >>> L + Matrix([ + [ 1, 0, 0], + [ 3/5, 1, 0], + [-1/5, 1/3, 1]]) + >>> D + Matrix([ + [25, 0, 0], + [ 0, 9, 0], + [ 0, 0, 9]]) + >>> L * D * L.T == A + True + + """ + + from .dense import MutableDenseMatrix + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + if hermitian and not M.is_hermitian: + raise ValueError("Matrix must be Hermitian.") + if not hermitian and not M.is_symmetric(): + raise ValueError("Matrix must be symmetric.") + + dps = _get_intermediate_simp(expand_mul, expand_mul) + Lrowstruc = M.row_structure_symbolic_cholesky() + L = MutableDenseMatrix.eye(M.rows) + D = MutableDenseMatrix.zeros(M.rows, M.cols) + + for i in range(len(Lrowstruc)): + for j in Lrowstruc[i]: + if i != j: + L[i, j] = M[i, j] + summ = 0 + + for p1 in Lrowstruc[i]: + if p1 < j: + for p2 in Lrowstruc[j]: + if p2 < j: + if p1 == p2: + if hermitian: + summ += L[i, p1]*L[j, p1].conjugate()*D[p1, p1] + else: + summ += L[i, p1]*L[j, p1]*D[p1, p1] + else: + break + else: + break + + L[i, j] = dps((L[i, j] - summ) / D[j, j]) + + else: # i == j + D[i, i] = M[i, i] + summ = 0 + + for k in Lrowstruc[i]: + if k < i: + if hermitian: + summ += L[i, k]*L[i, k].conjugate()*D[k, k] + else: + summ += L[i, k]**2*D[k, k] + else: + break + + D[i, i] = dps(D[i, i] - summ) + + if hermitian and D[i, i].is_positive is False: + raise NonPositiveDefiniteMatrixError( + "Matrix must be positive-definite") + + return M._new(L), M._new(D) + + +def _LUdecomposition(M, iszerofunc=_iszero, simpfunc=None, rankcheck=False): + """Returns (L, U, perm) where L is a lower triangular matrix with unit + diagonal, U is an upper triangular matrix, and perm is a list of row + swap index pairs. If A is the original matrix, then + ``A = (L*U).permuteBkwd(perm)``, and the row permutation matrix P such + that $P A = L U$ can be computed by ``P = eye(A.rows).permuteFwd(perm)``. + + See documentation for LUCombined for details about the keyword argument + rankcheck, iszerofunc, and simpfunc. + + Parameters + ========== + + rankcheck : bool, optional + Determines if this function should detect the rank + deficiency of the matrixis and should raise a + ``ValueError``. + + iszerofunc : function, optional + A function which determines if a given expression is zero. + + The function should be a callable that takes a single + SymPy expression and returns a 3-valued boolean value + ``True``, ``False``, or ``None``. + + It is internally used by the pivot searching algorithm. + See the notes section for a more information about the + pivot searching algorithm. + + simpfunc : function or None, optional + A function that simplifies the input. + + If this is specified as a function, this function should be + a callable that takes a single SymPy expression and returns + an another SymPy expression that is algebraically + equivalent. + + If ``None``, it indicates that the pivot search algorithm + should not attempt to simplify any candidate pivots. + + It is internally used by the pivot searching algorithm. + See the notes section for a more information about the + pivot searching algorithm. + + Examples + ======== + + >>> from sympy import Matrix + >>> a = Matrix([[4, 3], [6, 3]]) + >>> L, U, _ = a.LUdecomposition() + >>> L + Matrix([ + [ 1, 0], + [3/2, 1]]) + >>> U + Matrix([ + [4, 3], + [0, -3/2]]) + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.cholesky + sympy.matrices.dense.DenseMatrix.LDLdecomposition + QRdecomposition + LUdecomposition_Simple + LUdecompositionFF + LUsolve + """ + + combined, p = M.LUdecomposition_Simple(iszerofunc=iszerofunc, + simpfunc=simpfunc, rankcheck=rankcheck) + + # L is lower triangular ``M.rows x M.rows`` + # U is upper triangular ``M.rows x M.cols`` + # L has unit diagonal. For each column in combined, the subcolumn + # below the diagonal of combined is shared by L. + # If L has more columns than combined, then the remaining subcolumns + # below the diagonal of L are zero. + # The upper triangular portion of L and combined are equal. + def entry_L(i, j): + if i < j: + # Super diagonal entry + return M.zero + elif i == j: + return M.one + elif j < combined.cols: + return combined[i, j] + + # Subdiagonal entry of L with no corresponding + # entry in combined + return M.zero + + def entry_U(i, j): + return M.zero if i > j else combined[i, j] + + L = M._new(combined.rows, combined.rows, entry_L) + U = M._new(combined.rows, combined.cols, entry_U) + + return L, U, p + +def _LUdecomposition_Simple(M, iszerofunc=_iszero, simpfunc=None, + rankcheck=False): + r"""Compute the PLU decomposition of the matrix. + + Parameters + ========== + + rankcheck : bool, optional + Determines if this function should detect the rank + deficiency of the matrixis and should raise a + ``ValueError``. + + iszerofunc : function, optional + A function which determines if a given expression is zero. + + The function should be a callable that takes a single + SymPy expression and returns a 3-valued boolean value + ``True``, ``False``, or ``None``. + + It is internally used by the pivot searching algorithm. + See the notes section for a more information about the + pivot searching algorithm. + + simpfunc : function or None, optional + A function that simplifies the input. + + If this is specified as a function, this function should be + a callable that takes a single SymPy expression and returns + an another SymPy expression that is algebraically + equivalent. + + If ``None``, it indicates that the pivot search algorithm + should not attempt to simplify any candidate pivots. + + It is internally used by the pivot searching algorithm. + See the notes section for a more information about the + pivot searching algorithm. + + Returns + ======= + + (lu, row_swaps) : (Matrix, list) + If the original matrix is a $m, n$ matrix: + + *lu* is a $m, n$ matrix, which contains result of the + decomposition in a compressed form. See the notes section + to see how the matrix is compressed. + + *row_swaps* is a $m$-element list where each element is a + pair of row exchange indices. + + ``A = (L*U).permute_backward(perm)``, and the row + permutation matrix $P$ from the formula $P A = L U$ can be + computed by ``P=eye(A.row).permute_forward(perm)``. + + Raises + ====== + + ValueError + Raised if ``rankcheck=True`` and the matrix is found to + be rank deficient during the computation. + + Notes + ===== + + About the PLU decomposition: + + PLU decomposition is a generalization of a LU decomposition + which can be extended for rank-deficient matrices. + + It can further be generalized for non-square matrices, and this + is the notation that SymPy is using. + + PLU decomposition is a decomposition of a $m, n$ matrix $A$ in + the form of $P A = L U$ where + + * $L$ is a $m, m$ lower triangular matrix with unit diagonal + entries. + * $U$ is a $m, n$ upper triangular matrix. + * $P$ is a $m, m$ permutation matrix. + + So, for a square matrix, the decomposition would look like: + + .. math:: + L = \begin{bmatrix} + 1 & 0 & 0 & \cdots & 0 \\ + L_{1, 0} & 1 & 0 & \cdots & 0 \\ + L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 \\ + \vdots & \vdots & \vdots & \ddots & \vdots \\ + L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & 1 + \end{bmatrix} + + .. math:: + U = \begin{bmatrix} + U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\ + 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\ + 0 & 0 & U_{2, 2} & \cdots & U_{2, n-1} \\ + \vdots & \vdots & \vdots & \ddots & \vdots \\ + 0 & 0 & 0 & \cdots & U_{n-1, n-1} + \end{bmatrix} + + And for a matrix with more rows than the columns, + the decomposition would look like: + + .. math:: + L = \begin{bmatrix} + 1 & 0 & 0 & \cdots & 0 & 0 & \cdots & 0 \\ + L_{1, 0} & 1 & 0 & \cdots & 0 & 0 & \cdots & 0 \\ + L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 & 0 & \cdots & 0 \\ + \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots + & \vdots \\ + L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & 1 & 0 + & \cdots & 0 \\ + L_{n, 0} & L_{n, 1} & L_{n, 2} & \cdots & L_{n, n-1} & 1 + & \cdots & 0 \\ + \vdots & \vdots & \vdots & \ddots & \vdots & \vdots + & \ddots & \vdots \\ + L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & L_{m-1, n-1} + & 0 & \cdots & 1 \\ + \end{bmatrix} + + .. math:: + U = \begin{bmatrix} + U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\ + 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\ + 0 & 0 & U_{2, 2} & \cdots & U_{2, n-1} \\ + \vdots & \vdots & \vdots & \ddots & \vdots \\ + 0 & 0 & 0 & \cdots & U_{n-1, n-1} \\ + 0 & 0 & 0 & \cdots & 0 \\ + \vdots & \vdots & \vdots & \ddots & \vdots \\ + 0 & 0 & 0 & \cdots & 0 + \end{bmatrix} + + Finally, for a matrix with more columns than the rows, the + decomposition would look like: + + .. math:: + L = \begin{bmatrix} + 1 & 0 & 0 & \cdots & 0 \\ + L_{1, 0} & 1 & 0 & \cdots & 0 \\ + L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 \\ + \vdots & \vdots & \vdots & \ddots & \vdots \\ + L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & 1 + \end{bmatrix} + + .. math:: + U = \begin{bmatrix} + U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, m-1} + & \cdots & U_{0, n-1} \\ + 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, m-1} + & \cdots & U_{1, n-1} \\ + 0 & 0 & U_{2, 2} & \cdots & U_{2, m-1} + & \cdots & U_{2, n-1} \\ + \vdots & \vdots & \vdots & \ddots & \vdots + & \cdots & \vdots \\ + 0 & 0 & 0 & \cdots & U_{m-1, m-1} + & \cdots & U_{m-1, n-1} \\ + \end{bmatrix} + + About the compressed LU storage: + + The results of the decomposition are often stored in compressed + forms rather than returning $L$ and $U$ matrices individually. + + It may be less intiuitive, but it is commonly used for a lot of + numeric libraries because of the efficiency. + + The storage matrix is defined as following for this specific + method: + + * The subdiagonal elements of $L$ are stored in the subdiagonal + portion of $LU$, that is $LU_{i, j} = L_{i, j}$ whenever + $i > j$. + * The elements on the diagonal of $L$ are all 1, and are not + explicitly stored. + * $U$ is stored in the upper triangular portion of $LU$, that is + $LU_{i, j} = U_{i, j}$ whenever $i <= j$. + * For a case of $m > n$, the right side of the $L$ matrix is + trivial to store. + * For a case of $m < n$, the below side of the $U$ matrix is + trivial to store. + + So, for a square matrix, the compressed output matrix would be: + + .. math:: + LU = \begin{bmatrix} + U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\ + L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\ + L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, n-1} \\ + \vdots & \vdots & \vdots & \ddots & \vdots \\ + L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & U_{n-1, n-1} + \end{bmatrix} + + For a matrix with more rows than the columns, the compressed + output matrix would be: + + .. math:: + LU = \begin{bmatrix} + U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\ + L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\ + L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, n-1} \\ + \vdots & \vdots & \vdots & \ddots & \vdots \\ + L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots + & U_{n-1, n-1} \\ + \vdots & \vdots & \vdots & \ddots & \vdots \\ + L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots + & L_{m-1, n-1} \\ + \end{bmatrix} + + For a matrix with more columns than the rows, the compressed + output matrix would be: + + .. math:: + LU = \begin{bmatrix} + U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, m-1} + & \cdots & U_{0, n-1} \\ + L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, m-1} + & \cdots & U_{1, n-1} \\ + L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, m-1} + & \cdots & U_{2, n-1} \\ + \vdots & \vdots & \vdots & \ddots & \vdots + & \cdots & \vdots \\ + L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & U_{m-1, m-1} + & \cdots & U_{m-1, n-1} \\ + \end{bmatrix} + + About the pivot searching algorithm: + + When a matrix contains symbolic entries, the pivot search algorithm + differs from the case where every entry can be categorized as zero or + nonzero. + The algorithm searches column by column through the submatrix whose + top left entry coincides with the pivot position. + If it exists, the pivot is the first entry in the current search + column that iszerofunc guarantees is nonzero. + If no such candidate exists, then each candidate pivot is simplified + if simpfunc is not None. + The search is repeated, with the difference that a candidate may be + the pivot if ``iszerofunc()`` cannot guarantee that it is nonzero. + In the second search the pivot is the first candidate that + iszerofunc can guarantee is nonzero. + If no such candidate exists, then the pivot is the first candidate + for which iszerofunc returns None. + If no such candidate exists, then the search is repeated in the next + column to the right. + The pivot search algorithm differs from the one in ``rref()``, which + relies on ``_find_reasonable_pivot()``. + Future versions of ``LUdecomposition_simple()`` may use + ``_find_reasonable_pivot()``. + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.LUdecomposition + LUdecompositionFF + LUsolve + """ + + if rankcheck: + # https://github.com/sympy/sympy/issues/9796 + pass + + if S.Zero in M.shape: + # Define LU decomposition of a matrix with no entries as a matrix + # of the same dimensions with all zero entries. + return M.zeros(M.rows, M.cols), [] + + dps = _get_intermediate_simp() + lu = M.as_mutable() + row_swaps = [] + + pivot_col = 0 + + for pivot_row in range(0, lu.rows - 1): + # Search for pivot. Prefer entry that iszeropivot determines + # is nonzero, over entry that iszeropivot cannot guarantee + # is zero. + # XXX ``_find_reasonable_pivot`` uses slow zero testing. Blocked by bug #10279 + # Future versions of LUdecomposition_simple can pass iszerofunc and simpfunc + # to _find_reasonable_pivot(). + # In pass 3 of _find_reasonable_pivot(), the predicate in ``if x.equals(S.Zero):`` + # calls sympy.simplify(), and not the simplification function passed in via + # the keyword argument simpfunc. + iszeropivot = True + + while pivot_col != M.cols and iszeropivot: + sub_col = (lu[r, pivot_col] for r in range(pivot_row, M.rows)) + + pivot_row_offset, pivot_value, is_assumed_non_zero, ind_simplified_pairs =\ + _find_reasonable_pivot_naive(sub_col, iszerofunc, simpfunc) + + iszeropivot = pivot_value is None + + if iszeropivot: + # All candidate pivots in this column are zero. + # Proceed to next column. + pivot_col += 1 + + if rankcheck and pivot_col != pivot_row: + # All entries including and below the pivot position are + # zero, which indicates that the rank of the matrix is + # strictly less than min(num rows, num cols) + # Mimic behavior of previous implementation, by throwing a + # ValueError. + raise ValueError("Rank of matrix is strictly less than" + " number of rows or columns." + " Pass keyword argument" + " rankcheck=False to compute" + " the LU decomposition of this matrix.") + + candidate_pivot_row = None if pivot_row_offset is None else pivot_row + pivot_row_offset + + if candidate_pivot_row is None and iszeropivot: + # If candidate_pivot_row is None and iszeropivot is True + # after pivot search has completed, then the submatrix + # below and to the right of (pivot_row, pivot_col) is + # all zeros, indicating that Gaussian elimination is + # complete. + return lu, row_swaps + + # Update entries simplified during pivot search. + for offset, val in ind_simplified_pairs: + lu[pivot_row + offset, pivot_col] = val + + if pivot_row != candidate_pivot_row: + # Row swap book keeping: + # Record which rows were swapped. + # Update stored portion of L factor by multiplying L on the + # left and right with the current permutation. + # Swap rows of U. + row_swaps.append([pivot_row, candidate_pivot_row]) + + # Update L. + lu[pivot_row, 0:pivot_row], lu[candidate_pivot_row, 0:pivot_row] = \ + lu[candidate_pivot_row, 0:pivot_row], lu[pivot_row, 0:pivot_row] + + # Swap pivot row of U with candidate pivot row. + lu[pivot_row, pivot_col:lu.cols], lu[candidate_pivot_row, pivot_col:lu.cols] = \ + lu[candidate_pivot_row, pivot_col:lu.cols], lu[pivot_row, pivot_col:lu.cols] + + # Introduce zeros below the pivot by adding a multiple of the + # pivot row to a row under it, and store the result in the + # row under it. + # Only entries in the target row whose index is greater than + # start_col may be nonzero. + start_col = pivot_col + 1 + + for row in range(pivot_row + 1, lu.rows): + # Store factors of L in the subcolumn below + # (pivot_row, pivot_row). + lu[row, pivot_row] = \ + dps(lu[row, pivot_col]/lu[pivot_row, pivot_col]) + + # Form the linear combination of the pivot row and the current + # row below the pivot row that zeros the entries below the pivot. + # Employing slicing instead of a loop here raises + # NotImplementedError: Cannot add Zero to MutableSparseMatrix + # in sympy/matrices/tests/test_sparse.py. + # c = pivot_row + 1 if pivot_row == pivot_col else pivot_col + for c in range(start_col, lu.cols): + lu[row, c] = dps(lu[row, c] - lu[row, pivot_row]*lu[pivot_row, c]) + + if pivot_row != pivot_col: + # matrix rank < min(num rows, num cols), + # so factors of L are not stored directly below the pivot. + # These entries are zero by construction, so don't bother + # computing them. + for row in range(pivot_row + 1, lu.rows): + lu[row, pivot_col] = M.zero + + pivot_col += 1 + + if pivot_col == lu.cols: + # All candidate pivots are zero implies that Gaussian + # elimination is complete. + return lu, row_swaps + + if rankcheck: + if iszerofunc( + lu[Min(lu.rows, lu.cols) - 1, Min(lu.rows, lu.cols) - 1]): + raise ValueError("Rank of matrix is strictly less than" + " number of rows or columns." + " Pass keyword argument" + " rankcheck=False to compute" + " the LU decomposition of this matrix.") + + return lu, row_swaps + +def _LUdecompositionFF(M): + """Compute a fraction-free LU decomposition. + + Returns 4 matrices P, L, D, U such that PA = L D**-1 U. + If the elements of the matrix belong to some integral domain I, then all + elements of L, D and U are guaranteed to belong to I. + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.LUdecomposition + LUdecomposition_Simple + LUsolve + + References + ========== + + .. [1] W. Zhou & D.J. Jeffrey, "Fraction-free matrix factors: new forms + for LU and QR factors". Frontiers in Computer Science in China, + Vol 2, no. 1, pp. 67-80, 2008. + """ + + from sympy.matrices import SparseMatrix + + zeros = SparseMatrix.zeros + eye = SparseMatrix.eye + n, m = M.rows, M.cols + U, L, P = M.as_mutable(), eye(n), eye(n) + DD = zeros(n, n) + oldpivot = 1 + + for k in range(n - 1): + if U[k, k] == 0: + for kpivot in range(k + 1, n): + if U[kpivot, k]: + break + else: + raise ValueError("Matrix is not full rank") + + U[k, k:], U[kpivot, k:] = U[kpivot, k:], U[k, k:] + L[k, :k], L[kpivot, :k] = L[kpivot, :k], L[k, :k] + P[k, :], P[kpivot, :] = P[kpivot, :], P[k, :] + + L [k, k] = Ukk = U[k, k] + DD[k, k] = oldpivot * Ukk + + for i in range(k + 1, n): + L[i, k] = Uik = U[i, k] + + for j in range(k + 1, m): + U[i, j] = (Ukk * U[i, j] - U[k, j] * Uik) / oldpivot + + U[i, k] = 0 + + oldpivot = Ukk + + DD[n - 1, n - 1] = oldpivot + + return P, L, DD, U + +def _singular_value_decomposition(A): + r"""Returns a Condensed Singular Value decomposition. + + Explanation + =========== + + A Singular Value decomposition is a decomposition in the form $A = U \Sigma V^H$ + where + + - $U, V$ are column orthogonal matrix. + - $\Sigma$ is a diagonal matrix, where the main diagonal contains singular + values of matrix A. + + A column orthogonal matrix satisfies + $\mathbb{I} = U^H U$ while a full orthogonal matrix satisfies + relation $\mathbb{I} = U U^H = U^H U$ where $\mathbb{I}$ is an identity + matrix with matching dimensions. + + For matrices which are not square or are rank-deficient, it is + sufficient to return a column orthogonal matrix because augmenting + them may introduce redundant computations. + In condensed Singular Value Decomposition we only return column orthogonal + matrices because of this reason + + If you want to augment the results to return a full orthogonal + decomposition, you should use the following procedures. + + - Augment the $U, V$ matrices with columns that are orthogonal to every + other columns and make it square. + - Augment the $\Sigma$ matrix with zero rows to make it have the same + shape as the original matrix. + + The procedure will be illustrated in the examples section. + + Examples + ======== + + we take a full rank matrix first: + + >>> from sympy import Matrix + >>> A = Matrix([[1, 2],[2,1]]) + >>> U, S, V = A.singular_value_decomposition() + >>> U + Matrix([ + [ sqrt(2)/2, sqrt(2)/2], + [-sqrt(2)/2, sqrt(2)/2]]) + >>> S + Matrix([ + [1, 0], + [0, 3]]) + >>> V + Matrix([ + [-sqrt(2)/2, sqrt(2)/2], + [ sqrt(2)/2, sqrt(2)/2]]) + + If a matrix if square and full rank both U, V + are orthogonal in both directions + + >>> U * U.H + Matrix([ + [1, 0], + [0, 1]]) + >>> U.H * U + Matrix([ + [1, 0], + [0, 1]]) + + >>> V * V.H + Matrix([ + [1, 0], + [0, 1]]) + >>> V.H * V + Matrix([ + [1, 0], + [0, 1]]) + >>> A == U * S * V.H + True + + >>> C = Matrix([ + ... [1, 0, 0, 0, 2], + ... [0, 0, 3, 0, 0], + ... [0, 0, 0, 0, 0], + ... [0, 2, 0, 0, 0], + ... ]) + >>> U, S, V = C.singular_value_decomposition() + + >>> V.H * V + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> V * V.H + Matrix([ + [1/5, 0, 0, 0, 2/5], + [ 0, 1, 0, 0, 0], + [ 0, 0, 1, 0, 0], + [ 0, 0, 0, 0, 0], + [2/5, 0, 0, 0, 4/5]]) + + If you want to augment the results to be a full orthogonal + decomposition, you should augment $V$ with an another orthogonal + column. + + You are able to append an arbitrary standard basis that are linearly + independent to every other columns and you can run the Gram-Schmidt + process to make them augmented as orthogonal basis. + + >>> V_aug = V.row_join(Matrix([[0,0,0,0,1], + ... [0,0,0,1,0]]).H) + >>> V_aug = V_aug.QRdecomposition()[0] + >>> V_aug + Matrix([ + [0, sqrt(5)/5, 0, -2*sqrt(5)/5, 0], + [1, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 0, 1], + [0, 2*sqrt(5)/5, 0, sqrt(5)/5, 0]]) + >>> V_aug.H * V_aug + Matrix([ + [1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1]]) + >>> V_aug * V_aug.H + Matrix([ + [1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1]]) + + Similarly we augment U + + >>> U_aug = U.row_join(Matrix([0,0,1,0])) + >>> U_aug = U_aug.QRdecomposition()[0] + >>> U_aug + Matrix([ + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1], + [1, 0, 0, 0]]) + + >>> U_aug.H * U_aug + Matrix([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1]]) + >>> U_aug * U_aug.H + Matrix([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1]]) + + We add 2 zero columns and one row to S + + >>> S_aug = S.col_join(Matrix([[0,0,0]])) + >>> S_aug = S_aug.row_join(Matrix([[0,0,0,0], + ... [0,0,0,0]]).H) + >>> S_aug + Matrix([ + [2, 0, 0, 0, 0], + [0, sqrt(5), 0, 0, 0], + [0, 0, 3, 0, 0], + [0, 0, 0, 0, 0]]) + + + + >>> U_aug * S_aug * V_aug.H == C + True + + """ + + AH = A.H + m, n = A.shape + if m >= n: + V, S = (AH * A).diagonalize() + + ranked = [] + for i, x in enumerate(S.diagonal()): + if not x.is_zero: + ranked.append(i) + + V = V[:, ranked] + + Singular_vals = [sqrt(S[i, i]) for i in range(S.rows) if i in ranked] + + S = S.diag(*Singular_vals) + V, _ = V.QRdecomposition() + U = A * V * S.inv() + else: + U, S = (A * AH).diagonalize() + + ranked = [] + for i, x in enumerate(S.diagonal()): + if not x.is_zero: + ranked.append(i) + + U = U[:, ranked] + Singular_vals = [sqrt(S[i, i]) for i in range(S.rows) if i in ranked] + + S = S.diag(*Singular_vals) + U, _ = U.QRdecomposition() + V = AH * U * S.inv() + + return U, S, V + +def _QRdecomposition_optional(M, normalize=True): + def dot(u, v): + return u.dot(v, hermitian=True) + + dps = _get_intermediate_simp(expand_mul, expand_mul) + + A = M.as_mutable() + ranked = [] + + Q = A + R = A.zeros(A.cols) + + for j in range(A.cols): + for i in range(j): + if Q[:, i].is_zero_matrix: + continue + + R[i, j] = dot(Q[:, i], Q[:, j]) / dot(Q[:, i], Q[:, i]) + R[i, j] = dps(R[i, j]) + Q[:, j] -= Q[:, i] * R[i, j] + + Q[:, j] = dps(Q[:, j]) + if Q[:, j].is_zero_matrix is not True: + ranked.append(j) + R[j, j] = M.one + + Q = Q.extract(range(Q.rows), ranked) + R = R.extract(ranked, range(R.cols)) + + if normalize: + # Normalization + for i in range(Q.cols): + norm = Q[:, i].norm() + Q[:, i] /= norm + R[i, :] *= norm + + return M.__class__(Q), M.__class__(R) + + +def _QRdecomposition(M): + r"""Returns a QR decomposition. + + Explanation + =========== + + A QR decomposition is a decomposition in the form $A = Q R$ + where + + - $Q$ is a column orthogonal matrix. + - $R$ is a upper triangular (trapezoidal) matrix. + + A column orthogonal matrix satisfies + $\mathbb{I} = Q^H Q$ while a full orthogonal matrix satisfies + relation $\mathbb{I} = Q Q^H = Q^H Q$ where $I$ is an identity + matrix with matching dimensions. + + For matrices which are not square or are rank-deficient, it is + sufficient to return a column orthogonal matrix because augmenting + them may introduce redundant computations. + And an another advantage of this is that you can easily inspect the + matrix rank by counting the number of columns of $Q$. + + If you want to augment the results to return a full orthogonal + decomposition, you should use the following procedures. + + - Augment the $Q$ matrix with columns that are orthogonal to every + other columns and make it square. + - Augment the $R$ matrix with zero rows to make it have the same + shape as the original matrix. + + The procedure will be illustrated in the examples section. + + Examples + ======== + + A full rank matrix example: + + >>> from sympy import Matrix + >>> A = Matrix([[12, -51, 4], [6, 167, -68], [-4, 24, -41]]) + >>> Q, R = A.QRdecomposition() + >>> Q + Matrix([ + [ 6/7, -69/175, -58/175], + [ 3/7, 158/175, 6/175], + [-2/7, 6/35, -33/35]]) + >>> R + Matrix([ + [14, 21, -14], + [ 0, 175, -70], + [ 0, 0, 35]]) + + If the matrix is square and full rank, the $Q$ matrix becomes + orthogonal in both directions, and needs no augmentation. + + >>> Q * Q.H + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> Q.H * Q + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + + >>> A == Q*R + True + + A rank deficient matrix example: + + >>> A = Matrix([[12, -51, 0], [6, 167, 0], [-4, 24, 0]]) + >>> Q, R = A.QRdecomposition() + >>> Q + Matrix([ + [ 6/7, -69/175], + [ 3/7, 158/175], + [-2/7, 6/35]]) + >>> R + Matrix([ + [14, 21, 0], + [ 0, 175, 0]]) + + QRdecomposition might return a matrix Q that is rectangular. + In this case the orthogonality condition might be satisfied as + $\mathbb{I} = Q.H*Q$ but not in the reversed product + $\mathbb{I} = Q * Q.H$. + + >>> Q.H * Q + Matrix([ + [1, 0], + [0, 1]]) + >>> Q * Q.H + Matrix([ + [27261/30625, 348/30625, -1914/6125], + [ 348/30625, 30589/30625, 198/6125], + [ -1914/6125, 198/6125, 136/1225]]) + + If you want to augment the results to be a full orthogonal + decomposition, you should augment $Q$ with an another orthogonal + column. + + You are able to append an identity matrix, + and you can run the Gram-Schmidt + process to make them augmented as orthogonal basis. + + >>> Q_aug = Q.row_join(Matrix.eye(3)) + >>> Q_aug = Q_aug.QRdecomposition()[0] + >>> Q_aug + Matrix([ + [ 6/7, -69/175, 58/175], + [ 3/7, 158/175, -6/175], + [-2/7, 6/35, 33/35]]) + >>> Q_aug.H * Q_aug + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> Q_aug * Q_aug.H + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + + Augmenting the $R$ matrix with zero row is straightforward. + + >>> R_aug = R.col_join(Matrix([[0, 0, 0]])) + >>> R_aug + Matrix([ + [14, 21, 0], + [ 0, 175, 0], + [ 0, 0, 0]]) + >>> Q_aug * R_aug == A + True + + A zero matrix example: + + >>> from sympy import Matrix + >>> A = Matrix.zeros(3, 4) + >>> Q, R = A.QRdecomposition() + + They may return matrices with zero rows and columns. + + >>> Q + Matrix(3, 0, []) + >>> R + Matrix(0, 4, []) + >>> Q*R + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0]]) + + As the same augmentation rule described above, $Q$ can be augmented + with columns of an identity matrix and $R$ can be augmented with + rows of a zero matrix. + + >>> Q_aug = Q.row_join(Matrix.eye(3)) + >>> R_aug = R.col_join(Matrix.zeros(3, 4)) + >>> Q_aug * Q_aug.T + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> R_aug + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0]]) + >>> Q_aug * R_aug == A + True + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.cholesky + sympy.matrices.dense.DenseMatrix.LDLdecomposition + sympy.matrices.matrixbase.MatrixBase.LUdecomposition + QRsolve + """ + return _QRdecomposition_optional(M, normalize=True) + +def _upper_hessenberg_decomposition(A): + """Converts a matrix into Hessenberg matrix H. + + Returns 2 matrices H, P s.t. + $P H P^{T} = A$, where H is an upper hessenberg matrix + and P is an orthogonal matrix + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([ + ... [1,2,3], + ... [-3,5,6], + ... [4,-8,9], + ... ]) + >>> H, P = A.upper_hessenberg_decomposition() + >>> H + Matrix([ + [1, 6/5, 17/5], + [5, 213/25, -134/25], + [0, 216/25, 137/25]]) + >>> P + Matrix([ + [1, 0, 0], + [0, -3/5, 4/5], + [0, 4/5, 3/5]]) + >>> P * H * P.H == A + True + + + References + ========== + + .. [#] https://mathworld.wolfram.com/HessenbergDecomposition.html + """ + + M = A.as_mutable() + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + + n = M.cols + P = M.eye(n) + H = M + + for j in range(n - 2): + + u = H[j + 1:, j] + + if u[1:, :].is_zero_matrix: + continue + + if sign(u[0]) != 0: + u[0] = u[0] + sign(u[0]) * u.norm() + else: + u[0] = u[0] + u.norm() + + v = u / u.norm() + + H[j + 1:, :] = H[j + 1:, :] - 2 * v * (v.H * H[j + 1:, :]) + H[:, j + 1:] = H[:, j + 1:] - (H[:, j + 1:] * (2 * v)) * v.H + P[:, j + 1:] = P[:, j + 1:] - (P[:, j + 1:] * (2 * v)) * v.H + + return H, P diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/dense.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/dense.py new file mode 100644 index 0000000000000000000000000000000000000000..98bf9931df54f67abfd9c4dc810b46fdcf70288f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/dense.py @@ -0,0 +1,1094 @@ +from __future__ import annotations +import random + +from sympy.core.basic import Basic +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import cos, sin +from sympy.utilities.decorator import doctest_depends_on +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import is_sequence + +from .exceptions import ShapeError +from .decompositions import _cholesky, _LDLdecomposition +from .matrixbase import MatrixBase +from .repmatrix import MutableRepMatrix, RepMatrix +from .solvers import _lower_triangular_solve, _upper_triangular_solve + + +__doctest_requires__ = {('symarray',): ['numpy']} + + +def _iszero(x): + """Returns True if x is zero.""" + return x.is_zero + + +class DenseMatrix(RepMatrix): + """Matrix implementation based on DomainMatrix as the internal representation""" + + # + # DenseMatrix is a superclass for both MutableDenseMatrix and + # ImmutableDenseMatrix. Methods shared by both classes but not for the + # Sparse classes should be implemented here. + # + + is_MatrixExpr: bool = False + + _op_priority = 10.01 + _class_priority = 4 + + @property + def _mat(self): + sympy_deprecation_warning( + """ + The private _mat attribute of Matrix is deprecated. Use the + .flat() method instead. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-private-matrix-attributes" + ) + + return self.flat() + + def _eval_inverse(self, **kwargs): + return self.inv(method=kwargs.get('method', 'GE'), + iszerofunc=kwargs.get('iszerofunc', _iszero), + try_block_diag=kwargs.get('try_block_diag', False)) + + def as_immutable(self): + """Returns an Immutable version of this Matrix + """ + from .immutable import ImmutableDenseMatrix as cls + return cls._fromrep(self._rep.copy()) + + def as_mutable(self): + """Returns a mutable version of this matrix + + Examples + ======== + + >>> from sympy import ImmutableMatrix + >>> X = ImmutableMatrix([[1, 2], [3, 4]]) + >>> Y = X.as_mutable() + >>> Y[1, 1] = 5 # Can set values in Y + >>> Y + Matrix([ + [1, 2], + [3, 5]]) + """ + return Matrix(self) + + def cholesky(self, hermitian=True): + return _cholesky(self, hermitian=hermitian) + + def LDLdecomposition(self, hermitian=True): + return _LDLdecomposition(self, hermitian=hermitian) + + def lower_triangular_solve(self, rhs): + return _lower_triangular_solve(self, rhs) + + def upper_triangular_solve(self, rhs): + return _upper_triangular_solve(self, rhs) + + cholesky.__doc__ = _cholesky.__doc__ + LDLdecomposition.__doc__ = _LDLdecomposition.__doc__ + lower_triangular_solve.__doc__ = _lower_triangular_solve.__doc__ + upper_triangular_solve.__doc__ = _upper_triangular_solve.__doc__ + + +def _force_mutable(x): + """Return a matrix as a Matrix, otherwise return x.""" + if getattr(x, 'is_Matrix', False): + return x.as_mutable() + elif isinstance(x, Basic): + return x + elif hasattr(x, '__array__'): + a = x.__array__() + if len(a.shape) == 0: + return sympify(a) + return Matrix(x) + return x + + +class MutableDenseMatrix(DenseMatrix, MutableRepMatrix): + + def simplify(self, **kwargs): + """Applies simplify to the elements of a matrix in place. + + This is a shortcut for M.applyfunc(lambda x: simplify(x, ratio, measure)) + + See Also + ======== + + sympy.simplify.simplify.simplify + """ + from sympy.simplify.simplify import simplify as _simplify + for (i, j), element in self.todok().items(): + self[i, j] = _simplify(element, **kwargs) + + +MutableMatrix = Matrix = MutableDenseMatrix + +########### +# Numpy Utility Functions: +# list2numpy, matrix2numpy, symmarray +########### + + +def list2numpy(l, dtype=object): # pragma: no cover + """Converts Python list of SymPy expressions to a NumPy array. + + See Also + ======== + + matrix2numpy + """ + from numpy import empty + a = empty(len(l), dtype) + for i, s in enumerate(l): + a[i] = s + return a + + +def matrix2numpy(m, dtype=object): # pragma: no cover + """Converts SymPy's matrix to a NumPy array. + + See Also + ======== + + list2numpy + """ + from numpy import empty + a = empty(m.shape, dtype) + for i in range(m.rows): + for j in range(m.cols): + a[i, j] = m[i, j] + return a + + +########### +# Rotation matrices: +# rot_givens, rot_axis[123], rot_ccw_axis[123] +########### + + +def rot_givens(i, j, theta, dim=3): + r"""Returns a a Givens rotation matrix, a a rotation in the + plane spanned by two coordinates axes. + + Explanation + =========== + + The Givens rotation corresponds to a generalization of rotation + matrices to any number of dimensions, given by: + + .. math:: + G(i, j, \theta) = + \begin{bmatrix} + 1 & \cdots & 0 & \cdots & 0 & \cdots & 0 \\ + \vdots & \ddots & \vdots & & \vdots & & \vdots \\ + 0 & \cdots & c & \cdots & -s & \cdots & 0 \\ + \vdots & & \vdots & \ddots & \vdots & & \vdots \\ + 0 & \cdots & s & \cdots & c & \cdots & 0 \\ + \vdots & & \vdots & & \vdots & \ddots & \vdots \\ + 0 & \cdots & 0 & \cdots & 0 & \cdots & 1 + \end{bmatrix} + + Where $c = \cos(\theta)$ and $s = \sin(\theta)$ appear at the intersections + ``i``\th and ``j``\th rows and columns. + + For fixed ``i > j``\, the non-zero elements of a Givens matrix are + given by: + + - $g_{kk} = 1$ for $k \ne i,\,j$ + - $g_{kk} = c$ for $k = i,\,j$ + - $g_{ji} = -g_{ij} = -s$ + + Parameters + ========== + + i : int between ``0`` and ``dim - 1`` + Represents first axis + j : int between ``0`` and ``dim - 1`` + Represents second axis + dim : int bigger than 1 + Number of dimensions. Defaults to 3. + + Examples + ======== + + >>> from sympy import pi, rot_givens + + A counterclockwise rotation of pi/3 (60 degrees) around + the third axis (z-axis): + + >>> rot_givens(1, 0, pi/3) + Matrix([ + [ 1/2, -sqrt(3)/2, 0], + [sqrt(3)/2, 1/2, 0], + [ 0, 0, 1]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_givens(1, 0, pi/2) + Matrix([ + [0, -1, 0], + [1, 0, 0], + [0, 0, 1]]) + + This can be generalized to any number + of dimensions: + + >>> rot_givens(1, 0, pi/2, dim=4) + Matrix([ + [0, -1, 0, 0], + [1, 0, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1]]) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Givens_rotation + + See Also + ======== + + rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis (clockwise around the x axis) + rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis (clockwise around the y axis) + rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis (clockwise around the z axis) + rot_ccw_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis (counterclockwise around the x axis) + rot_ccw_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis (counterclockwise around the y axis) + rot_ccw_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis (counterclockwise around the z axis) + """ + if not isinstance(dim, int) or dim < 2: + raise ValueError('dim must be an integer biggen than one, ' + 'got {}.'.format(dim)) + + if i == j: + raise ValueError('i and j must be different, ' + 'got ({}, {})'.format(i, j)) + + for ij in [i, j]: + if not isinstance(ij, int) or ij < 0 or ij > dim - 1: + raise ValueError('i and j must be integers between 0 and ' + '{}, got i={} and j={}.'.format(dim-1, i, j)) + + theta = sympify(theta) + c = cos(theta) + s = sin(theta) + M = eye(dim) + M[i, i] = c + M[j, j] = c + M[i, j] = s + M[j, i] = -s + return M + + +def rot_axis3(theta): + r"""Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis. + + Explanation + =========== + + For a right-handed coordinate system, this corresponds to a + clockwise rotation around the `z`-axis, given by: + + .. math:: + + R = \begin{bmatrix} + \cos(\theta) & \sin(\theta) & 0 \\ + -\sin(\theta) & \cos(\theta) & 0 \\ + 0 & 0 & 1 + \end{bmatrix} + + Examples + ======== + + >>> from sympy import pi, rot_axis3 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_axis3(theta) + Matrix([ + [ 1/2, sqrt(3)/2, 0], + [-sqrt(3)/2, 1/2, 0], + [ 0, 0, 1]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_axis3(pi/2) + Matrix([ + [ 0, 1, 0], + [-1, 0, 0], + [ 0, 0, 1]]) + + See Also + ======== + + rot_givens: Returns a Givens rotation matrix (generalized rotation for + any number of dimensions) + rot_ccw_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis (counterclockwise around the z axis) + rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis (clockwise around the x axis) + rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis (clockwise around the y axis) + """ + return rot_givens(0, 1, theta, dim=3) + + +def rot_axis2(theta): + r"""Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis. + + Explanation + =========== + + For a right-handed coordinate system, this corresponds to a + clockwise rotation around the `y`-axis, given by: + + .. math:: + + R = \begin{bmatrix} + \cos(\theta) & 0 & -\sin(\theta) \\ + 0 & 1 & 0 \\ + \sin(\theta) & 0 & \cos(\theta) + \end{bmatrix} + + Examples + ======== + + >>> from sympy import pi, rot_axis2 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_axis2(theta) + Matrix([ + [ 1/2, 0, -sqrt(3)/2], + [ 0, 1, 0], + [sqrt(3)/2, 0, 1/2]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_axis2(pi/2) + Matrix([ + [0, 0, -1], + [0, 1, 0], + [1, 0, 0]]) + + See Also + ======== + + rot_givens: Returns a Givens rotation matrix (generalized rotation for + any number of dimensions) + rot_ccw_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis (clockwise around the y axis) + rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis (counterclockwise around the x axis) + rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis (counterclockwise around the z axis) + """ + return rot_givens(2, 0, theta, dim=3) + + +def rot_axis1(theta): + r"""Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis. + + Explanation + =========== + + For a right-handed coordinate system, this corresponds to a + clockwise rotation around the `x`-axis, given by: + + .. math:: + + R = \begin{bmatrix} + 1 & 0 & 0 \\ + 0 & \cos(\theta) & \sin(\theta) \\ + 0 & -\sin(\theta) & \cos(\theta) + \end{bmatrix} + + Examples + ======== + + >>> from sympy import pi, rot_axis1 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_axis1(theta) + Matrix([ + [1, 0, 0], + [0, 1/2, sqrt(3)/2], + [0, -sqrt(3)/2, 1/2]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_axis1(pi/2) + Matrix([ + [1, 0, 0], + [0, 0, 1], + [0, -1, 0]]) + + See Also + ======== + + rot_givens: Returns a Givens rotation matrix (generalized rotation for + any number of dimensions) + rot_ccw_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis (counterclockwise around the x axis) + rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis (clockwise around the y axis) + rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis (clockwise around the z axis) + """ + return rot_givens(1, 2, theta, dim=3) + + +def rot_ccw_axis3(theta): + r"""Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis. + + Explanation + =========== + + For a right-handed coordinate system, this corresponds to a + counterclockwise rotation around the `z`-axis, given by: + + .. math:: + + R = \begin{bmatrix} + \cos(\theta) & -\sin(\theta) & 0 \\ + \sin(\theta) & \cos(\theta) & 0 \\ + 0 & 0 & 1 + \end{bmatrix} + + Examples + ======== + + >>> from sympy import pi, rot_ccw_axis3 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_ccw_axis3(theta) + Matrix([ + [ 1/2, -sqrt(3)/2, 0], + [sqrt(3)/2, 1/2, 0], + [ 0, 0, 1]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_ccw_axis3(pi/2) + Matrix([ + [0, -1, 0], + [1, 0, 0], + [0, 0, 1]]) + + See Also + ======== + + rot_givens: Returns a Givens rotation matrix (generalized rotation for + any number of dimensions) + rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis (clockwise around the z axis) + rot_ccw_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis (counterclockwise around the x axis) + rot_ccw_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis (counterclockwise around the y axis) + """ + return rot_givens(1, 0, theta, dim=3) + + +def rot_ccw_axis2(theta): + r"""Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis. + + Explanation + =========== + + For a right-handed coordinate system, this corresponds to a + counterclockwise rotation around the `y`-axis, given by: + + .. math:: + + R = \begin{bmatrix} + \cos(\theta) & 0 & \sin(\theta) \\ + 0 & 1 & 0 \\ + -\sin(\theta) & 0 & \cos(\theta) + \end{bmatrix} + + Examples + ======== + + >>> from sympy import pi, rot_ccw_axis2 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_ccw_axis2(theta) + Matrix([ + [ 1/2, 0, sqrt(3)/2], + [ 0, 1, 0], + [-sqrt(3)/2, 0, 1/2]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_ccw_axis2(pi/2) + Matrix([ + [ 0, 0, 1], + [ 0, 1, 0], + [-1, 0, 0]]) + + See Also + ======== + + rot_givens: Returns a Givens rotation matrix (generalized rotation for + any number of dimensions) + rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis (clockwise around the y axis) + rot_ccw_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis (counterclockwise around the x axis) + rot_ccw_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis (counterclockwise around the z axis) + """ + return rot_givens(0, 2, theta, dim=3) + + +def rot_ccw_axis1(theta): + r"""Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis. + + Explanation + =========== + + For a right-handed coordinate system, this corresponds to a + counterclockwise rotation around the `x`-axis, given by: + + .. math:: + + R = \begin{bmatrix} + 1 & 0 & 0 \\ + 0 & \cos(\theta) & -\sin(\theta) \\ + 0 & \sin(\theta) & \cos(\theta) + \end{bmatrix} + + Examples + ======== + + >>> from sympy import pi, rot_ccw_axis1 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_ccw_axis1(theta) + Matrix([ + [1, 0, 0], + [0, 1/2, -sqrt(3)/2], + [0, sqrt(3)/2, 1/2]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_ccw_axis1(pi/2) + Matrix([ + [1, 0, 0], + [0, 0, -1], + [0, 1, 0]]) + + See Also + ======== + + rot_givens: Returns a Givens rotation matrix (generalized rotation for + any number of dimensions) + rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis (clockwise around the x axis) + rot_ccw_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis (counterclockwise around the y axis) + rot_ccw_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis (counterclockwise around the z axis) + """ + return rot_givens(2, 1, theta, dim=3) + + +@doctest_depends_on(modules=('numpy',)) +def symarray(prefix, shape, **kwargs): # pragma: no cover + r"""Create a numpy ndarray of symbols (as an object array). + + The created symbols are named ``prefix_i1_i2_``... You should thus provide a + non-empty prefix if you want your symbols to be unique for different output + arrays, as SymPy symbols with identical names are the same object. + + Parameters + ---------- + + prefix : string + A prefix prepended to the name of every symbol. + + shape : int or tuple + Shape of the created array. If an int, the array is one-dimensional; for + more than one dimension the shape must be a tuple. + + \*\*kwargs : dict + keyword arguments passed on to Symbol + + Examples + ======== + These doctests require numpy. + + >>> from sympy import symarray + >>> symarray('', 3) + [_0 _1 _2] + + If you want multiple symarrays to contain distinct symbols, you *must* + provide unique prefixes: + + >>> a = symarray('', 3) + >>> b = symarray('', 3) + >>> a[0] == b[0] + True + >>> a = symarray('a', 3) + >>> b = symarray('b', 3) + >>> a[0] == b[0] + False + + Creating symarrays with a prefix: + + >>> symarray('a', 3) + [a_0 a_1 a_2] + + For more than one dimension, the shape must be given as a tuple: + + >>> symarray('a', (2, 3)) + [[a_0_0 a_0_1 a_0_2] + [a_1_0 a_1_1 a_1_2]] + >>> symarray('a', (2, 3, 2)) + [[[a_0_0_0 a_0_0_1] + [a_0_1_0 a_0_1_1] + [a_0_2_0 a_0_2_1]] + + [[a_1_0_0 a_1_0_1] + [a_1_1_0 a_1_1_1] + [a_1_2_0 a_1_2_1]]] + + For setting assumptions of the underlying Symbols: + + >>> [s.is_real for s in symarray('a', 2, real=True)] + [True, True] + """ + from numpy import empty, ndindex + arr = empty(shape, dtype=object) + for index in ndindex(shape): + arr[index] = Symbol('%s_%s' % (prefix, '_'.join(map(str, index))), + **kwargs) + return arr + + +############### +# Functions +############### + +def casoratian(seqs, n, zero=True): + """Given linear difference operator L of order 'k' and homogeneous + equation Ly = 0 we want to compute kernel of L, which is a set + of 'k' sequences: a(n), b(n), ... z(n). + + Solutions of L are linearly independent iff their Casoratian, + denoted as C(a, b, ..., z), do not vanish for n = 0. + + Casoratian is defined by k x k determinant:: + + + a(n) b(n) . . . z(n) + + | a(n+1) b(n+1) . . . z(n+1) | + | . . . . | + | . . . . | + | . . . . | + + a(n+k-1) b(n+k-1) . . . z(n+k-1) + + + It proves very useful in rsolve_hyper() where it is applied + to a generating set of a recurrence to factor out linearly + dependent solutions and return a basis: + + >>> from sympy import Symbol, casoratian, factorial + >>> n = Symbol('n', integer=True) + + Exponential and factorial are linearly independent: + + >>> casoratian([2**n, factorial(n)], n) != 0 + True + + """ + + seqs = list(map(sympify, seqs)) + + if not zero: + f = lambda i, j: seqs[j].subs(n, n + i) + else: + f = lambda i, j: seqs[j].subs(n, i) + + k = len(seqs) + + return Matrix(k, k, f).det() + + +def eye(*args, **kwargs): + """Create square identity matrix n x n + + See Also + ======== + + diag + zeros + ones + """ + + return Matrix.eye(*args, **kwargs) + + +def diag(*values, strict=True, unpack=False, **kwargs): + """Returns a matrix with the provided values placed on the + diagonal. If non-square matrices are included, they will + produce a block-diagonal matrix. + + Examples + ======== + + This version of diag is a thin wrapper to Matrix.diag that differs + in that it treats all lists like matrices -- even when a single list + is given. If this is not desired, either put a `*` before the list or + set `unpack=True`. + + >>> from sympy import diag + + >>> diag([1, 2, 3], unpack=True) # = diag(1,2,3) or diag(*[1,2,3]) + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + + >>> diag([1, 2, 3]) # a column vector + Matrix([ + [1], + [2], + [3]]) + + See Also + ======== + .matrixbase.MatrixBase.eye + .matrixbase.MatrixBase.diagonal + .matrixbase.MatrixBase.diag + .expressions.blockmatrix.BlockMatrix + """ + return Matrix.diag(*values, strict=strict, unpack=unpack, **kwargs) + + +def GramSchmidt(vlist, orthonormal=False): + """Apply the Gram-Schmidt process to a set of vectors. + + Parameters + ========== + + vlist : List of Matrix + Vectors to be orthogonalized for. + + orthonormal : Bool, optional + If true, return an orthonormal basis. + + Returns + ======= + + vlist : List of Matrix + Orthogonalized vectors + + Notes + ===== + + This routine is mostly duplicate from ``Matrix.orthogonalize``, + except for some difference that this always raises error when + linearly dependent vectors are found, and the keyword ``normalize`` + has been named as ``orthonormal`` in this function. + + See Also + ======== + + .matrixbase.MatrixBase.orthogonalize + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process + """ + return MutableDenseMatrix.orthogonalize( + *vlist, normalize=orthonormal, rankcheck=True + ) + + +def hessian(f, varlist, constraints=()): + """Compute Hessian matrix for a function f wrt parameters in varlist + which may be given as a sequence or a row/column vector. A list of + constraints may optionally be given. + + Examples + ======== + + >>> from sympy import Function, hessian, pprint + >>> from sympy.abc import x, y + >>> f = Function('f')(x, y) + >>> g1 = Function('g')(x, y) + >>> g2 = x**2 + 3*y + >>> pprint(hessian(f, (x, y), [g1, g2])) + [ d d ] + [ 0 0 --(g(x, y)) --(g(x, y)) ] + [ dx dy ] + [ ] + [ 0 0 2*x 3 ] + [ ] + [ 2 2 ] + [d d d ] + [--(g(x, y)) 2*x ---(f(x, y)) -----(f(x, y))] + [dx 2 dy dx ] + [ dx ] + [ ] + [ 2 2 ] + [d d d ] + [--(g(x, y)) 3 -----(f(x, y)) ---(f(x, y)) ] + [dy dy dx 2 ] + [ dy ] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hessian_matrix + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.jacobian + wronskian + """ + # f is the expression representing a function f, return regular matrix + if isinstance(varlist, MatrixBase): + if 1 not in varlist.shape: + raise ShapeError("`varlist` must be a column or row vector.") + if varlist.cols == 1: + varlist = varlist.T + varlist = varlist.tolist()[0] + if is_sequence(varlist): + n = len(varlist) + if not n: + raise ShapeError("`len(varlist)` must not be zero.") + else: + raise ValueError("Improper variable list in hessian function") + if not getattr(f, 'diff'): + # check differentiability + raise ValueError("Function `f` (%s) is not differentiable" % f) + m = len(constraints) + N = m + n + out = zeros(N) + for k, g in enumerate(constraints): + if not getattr(g, 'diff'): + # check differentiability + raise ValueError("Function `f` (%s) is not differentiable" % f) + for i in range(n): + out[k, i + m] = g.diff(varlist[i]) + for i in range(n): + for j in range(i, n): + out[i + m, j + m] = f.diff(varlist[i]).diff(varlist[j]) + for i in range(N): + for j in range(i + 1, N): + out[j, i] = out[i, j] + return out + + +def jordan_cell(eigenval, n): + """ + Create a Jordan block: + + Examples + ======== + + >>> from sympy import jordan_cell + >>> from sympy.abc import x + >>> jordan_cell(x, 4) + Matrix([ + [x, 1, 0, 0], + [0, x, 1, 0], + [0, 0, x, 1], + [0, 0, 0, x]]) + """ + + return Matrix.jordan_block(size=n, eigenvalue=eigenval) + + +def matrix_multiply_elementwise(A, B): + """Return the Hadamard product (elementwise product) of A and B + + >>> from sympy import Matrix, matrix_multiply_elementwise + >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) + >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) + >>> matrix_multiply_elementwise(A, B) + Matrix([ + [ 0, 10, 200], + [300, 40, 5]]) + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.__mul__ + """ + return A.multiply_elementwise(B) + + +def ones(*args, **kwargs): + """Returns a matrix of ones with ``rows`` rows and ``cols`` columns; + if ``cols`` is omitted a square matrix will be returned. + + See Also + ======== + + zeros + eye + diag + """ + + if 'c' in kwargs: + kwargs['cols'] = kwargs.pop('c') + + return Matrix.ones(*args, **kwargs) + + +def randMatrix(r, c=None, min=0, max=99, seed=None, symmetric=False, + percent=100, prng=None): + """Create random matrix with dimensions ``r`` x ``c``. If ``c`` is omitted + the matrix will be square. If ``symmetric`` is True the matrix must be + square. If ``percent`` is less than 100 then only approximately the given + percentage of elements will be non-zero. + + The pseudo-random number generator used to generate matrix is chosen in the + following way. + + * If ``prng`` is supplied, it will be used as random number generator. + It should be an instance of ``random.Random``, or at least have + ``randint`` and ``shuffle`` methods with same signatures. + * if ``prng`` is not supplied but ``seed`` is supplied, then new + ``random.Random`` with given ``seed`` will be created; + * otherwise, a new ``random.Random`` with default seed will be used. + + Examples + ======== + + >>> from sympy import randMatrix + >>> randMatrix(3) # doctest:+SKIP + [25, 45, 27] + [44, 54, 9] + [23, 96, 46] + >>> randMatrix(3, 2) # doctest:+SKIP + [87, 29] + [23, 37] + [90, 26] + >>> randMatrix(3, 3, 0, 2) # doctest:+SKIP + [0, 2, 0] + [2, 0, 1] + [0, 0, 1] + >>> randMatrix(3, symmetric=True) # doctest:+SKIP + [85, 26, 29] + [26, 71, 43] + [29, 43, 57] + >>> A = randMatrix(3, seed=1) + >>> B = randMatrix(3, seed=2) + >>> A == B + False + >>> A == randMatrix(3, seed=1) + True + >>> randMatrix(3, symmetric=True, percent=50) # doctest:+SKIP + [77, 70, 0], + [70, 0, 0], + [ 0, 0, 88] + """ + # Note that ``Random()`` is equivalent to ``Random(None)`` + prng = prng or random.Random(seed) + + if c is None: + c = r + + if symmetric and r != c: + raise ValueError('For symmetric matrices, r must equal c, but %i != %i' % (r, c)) + + ij = range(r * c) + if percent != 100: + ij = prng.sample(ij, int(len(ij)*percent // 100)) + + m = zeros(r, c) + + if not symmetric: + for ijk in ij: + i, j = divmod(ijk, c) + m[i, j] = prng.randint(min, max) + else: + for ijk in ij: + i, j = divmod(ijk, c) + if i <= j: + m[i, j] = m[j, i] = prng.randint(min, max) + + return m + + +def wronskian(functions, var, method='bareiss'): + """ + Compute Wronskian for [] of functions + + :: + + | f1 f2 ... fn | + | f1' f2' ... fn' | + | . . . . | + W(f1, ..., fn) = | . . . . | + | . . . . | + | (n) (n) (n) | + | D (f1) D (f2) ... D (fn) | + + see: https://en.wikipedia.org/wiki/Wronskian + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.jacobian + hessian + """ + + functions = [sympify(f) for f in functions] + n = len(functions) + if n == 0: + return S.One + W = Matrix(n, n, lambda i, j: functions[i].diff(var, j)) + return W.det(method) + + +def zeros(*args, **kwargs): + """Returns a matrix of zeros with ``rows`` rows and ``cols`` columns; + if ``cols`` is omitted a square matrix will be returned. + + See Also + ======== + + ones + eye + diag + """ + + if 'c' in kwargs: + kwargs['cols'] = kwargs.pop('c') + + return Matrix.zeros(*args, **kwargs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/determinant.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/determinant.py new file mode 100644 index 0000000000000000000000000000000000000000..9206c0714999ebe0cde5c4300d9b3293939177df --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/determinant.py @@ -0,0 +1,1021 @@ +from types import FunctionType + +from sympy.core.cache import cacheit +from sympy.core.numbers import Float, Integer +from sympy.core.singleton import S +from sympy.core.symbol import uniquely_named_symbol +from sympy.core.mul import Mul +from sympy.polys import PurePoly, cancel +from sympy.functions.combinatorial.numbers import nC +from sympy.polys.matrices.domainmatrix import DomainMatrix +from sympy.polys.matrices.ddm import DDM + +from .exceptions import NonSquareMatrixError +from .utilities import ( + _get_intermediate_simp, _get_intermediate_simp_bool, + _iszero, _is_zero_after_expand_mul, _dotprodsimp, _simplify) + + +def _find_reasonable_pivot(col, iszerofunc=_iszero, simpfunc=_simplify): + """ Find the lowest index of an item in ``col`` that is + suitable for a pivot. If ``col`` consists only of + Floats, the pivot with the largest norm is returned. + Otherwise, the first element where ``iszerofunc`` returns + False is used. If ``iszerofunc`` does not return false, + items are simplified and retested until a suitable + pivot is found. + + Returns a 4-tuple + (pivot_offset, pivot_val, assumed_nonzero, newly_determined) + where pivot_offset is the index of the pivot, pivot_val is + the (possibly simplified) value of the pivot, assumed_nonzero + is True if an assumption that the pivot was non-zero + was made without being proved, and newly_determined are + elements that were simplified during the process of pivot + finding.""" + + newly_determined = [] + col = list(col) + # a column that contains a mix of floats and integers + # but at least one float is considered a numerical + # column, and so we do partial pivoting + if all(isinstance(x, (Float, Integer)) for x in col) and any( + isinstance(x, Float) for x in col): + col_abs = [abs(x) for x in col] + max_value = max(col_abs) + if iszerofunc(max_value): + # just because iszerofunc returned True, doesn't + # mean the value is numerically zero. Make sure + # to replace all entries with numerical zeros + if max_value != 0: + newly_determined = [(i, 0) for i, x in enumerate(col) if x != 0] + return (None, None, False, newly_determined) + index = col_abs.index(max_value) + return (index, col[index], False, newly_determined) + + # PASS 1 (iszerofunc directly) + possible_zeros = [] + for i, x in enumerate(col): + is_zero = iszerofunc(x) + # is someone wrote a custom iszerofunc, it may return + # BooleanFalse or BooleanTrue instead of True or False, + # so use == for comparison instead of `is` + if is_zero == False: + # we found something that is definitely not zero + return (i, x, False, newly_determined) + possible_zeros.append(is_zero) + + # by this point, we've found no certain non-zeros + if all(possible_zeros): + # if everything is definitely zero, we have + # no pivot + return (None, None, False, newly_determined) + + # PASS 2 (iszerofunc after simplify) + # we haven't found any for-sure non-zeros, so + # go through the elements iszerofunc couldn't + # make a determination about and opportunistically + # simplify to see if we find something + for i, x in enumerate(col): + if possible_zeros[i] is not None: + continue + simped = simpfunc(x) + is_zero = iszerofunc(simped) + if is_zero in (True, False): + newly_determined.append((i, simped)) + if is_zero == False: + return (i, simped, False, newly_determined) + possible_zeros[i] = is_zero + + # after simplifying, some things that were recognized + # as zeros might be zeros + if all(possible_zeros): + # if everything is definitely zero, we have + # no pivot + return (None, None, False, newly_determined) + + # PASS 3 (.equals(0)) + # some expressions fail to simplify to zero, but + # ``.equals(0)`` evaluates to True. As a last-ditch + # attempt, apply ``.equals`` to these expressions + for i, x in enumerate(col): + if possible_zeros[i] is not None: + continue + if x.equals(S.Zero): + # ``.iszero`` may return False with + # an implicit assumption (e.g., ``x.equals(0)`` + # when ``x`` is a symbol), so only treat it + # as proved when ``.equals(0)`` returns True + possible_zeros[i] = True + newly_determined.append((i, S.Zero)) + + if all(possible_zeros): + return (None, None, False, newly_determined) + + # at this point there is nothing that could definitely + # be a pivot. To maintain compatibility with existing + # behavior, we'll assume that an illdetermined thing is + # non-zero. We should probably raise a warning in this case + i = possible_zeros.index(None) + return (i, col[i], True, newly_determined) + + +def _find_reasonable_pivot_naive(col, iszerofunc=_iszero, simpfunc=None): + """ + Helper that computes the pivot value and location from a + sequence of contiguous matrix column elements. As a side effect + of the pivot search, this function may simplify some of the elements + of the input column. A list of these simplified entries and their + indices are also returned. + This function mimics the behavior of _find_reasonable_pivot(), + but does less work trying to determine if an indeterminate candidate + pivot simplifies to zero. This more naive approach can be much faster, + with the trade-off that it may erroneously return a pivot that is zero. + + ``col`` is a sequence of contiguous column entries to be searched for + a suitable pivot. + ``iszerofunc`` is a callable that returns a Boolean that indicates + if its input is zero, or None if no such determination can be made. + ``simpfunc`` is a callable that simplifies its input. It must return + its input if it does not simplify its input. Passing in + ``simpfunc=None`` indicates that the pivot search should not attempt + to simplify any candidate pivots. + + Returns a 4-tuple: + (pivot_offset, pivot_val, assumed_nonzero, newly_determined) + ``pivot_offset`` is the sequence index of the pivot. + ``pivot_val`` is the value of the pivot. + pivot_val and col[pivot_index] are equivalent, but will be different + when col[pivot_index] was simplified during the pivot search. + ``assumed_nonzero`` is a boolean indicating if the pivot cannot be + guaranteed to be zero. If assumed_nonzero is true, then the pivot + may or may not be non-zero. If assumed_nonzero is false, then + the pivot is non-zero. + ``newly_determined`` is a list of index-value pairs of pivot candidates + that were simplified during the pivot search. + """ + + # indeterminates holds the index-value pairs of each pivot candidate + # that is neither zero or non-zero, as determined by iszerofunc(). + # If iszerofunc() indicates that a candidate pivot is guaranteed + # non-zero, or that every candidate pivot is zero then the contents + # of indeterminates are unused. + # Otherwise, the only viable candidate pivots are symbolic. + # In this case, indeterminates will have at least one entry, + # and all but the first entry are ignored when simpfunc is None. + indeterminates = [] + for i, col_val in enumerate(col): + col_val_is_zero = iszerofunc(col_val) + if col_val_is_zero == False: + # This pivot candidate is non-zero. + return i, col_val, False, [] + elif col_val_is_zero is None: + # The candidate pivot's comparison with zero + # is indeterminate. + indeterminates.append((i, col_val)) + + if len(indeterminates) == 0: + # All candidate pivots are guaranteed to be zero, i.e. there is + # no pivot. + return None, None, False, [] + + if simpfunc is None: + # Caller did not pass in a simplification function that might + # determine if an indeterminate pivot candidate is guaranteed + # to be nonzero, so assume the first indeterminate candidate + # is non-zero. + return indeterminates[0][0], indeterminates[0][1], True, [] + + # newly_determined holds index-value pairs of candidate pivots + # that were simplified during the search for a non-zero pivot. + newly_determined = [] + for i, col_val in indeterminates: + tmp_col_val = simpfunc(col_val) + if id(col_val) != id(tmp_col_val): + # simpfunc() simplified this candidate pivot. + newly_determined.append((i, tmp_col_val)) + if iszerofunc(tmp_col_val) == False: + # Candidate pivot simplified to a guaranteed non-zero value. + return i, tmp_col_val, False, newly_determined + + return indeterminates[0][0], indeterminates[0][1], True, newly_determined + + +# This functions is a candidate for caching if it gets implemented for matrices. +def _berkowitz_toeplitz_matrix(M): + """Return (A,T) where T the Toeplitz matrix used in the Berkowitz algorithm + corresponding to ``M`` and A is the first principal submatrix. + """ + + # the 0 x 0 case is trivial + if M.rows == 0 and M.cols == 0: + return M._new(1,1, [M.one]) + + # + # Partition M = [ a_11 R ] + # [ C A ] + # + + a, R = M[0,0], M[0, 1:] + C, A = M[1:, 0], M[1:,1:] + + # + # The Toeplitz matrix looks like + # + # [ 1 ] + # [ -a 1 ] + # [ -RC -a 1 ] + # [ -RAC -RC -a 1 ] + # [ -RA**2C -RAC -RC -a 1 ] + # etc. + + # Compute the diagonal entries. + # Because multiplying matrix times vector is so much + # more efficient than matrix times matrix, recursively + # compute -R * A**n * C. + diags = [C] + for i in range(M.rows - 2): + diags.append(A.multiply(diags[i], dotprodsimp=None)) + diags = [(-R).multiply(d, dotprodsimp=None)[0, 0] for d in diags] + diags = [M.one, -a] + diags + + def entry(i,j): + if j > i: + return M.zero + return diags[i - j] + + toeplitz = M._new(M.cols + 1, M.rows, entry) + return (A, toeplitz) + + +# This functions is a candidate for caching if it gets implemented for matrices. +def _berkowitz_vector(M): + """ Run the Berkowitz algorithm and return a vector whose entries + are the coefficients of the characteristic polynomial of ``M``. + + Given N x N matrix, efficiently compute + coefficients of characteristic polynomials of ``M`` + without division in the ground domain. + + This method is particularly useful for computing determinant, + principal minors and characteristic polynomial when ``M`` + has complicated coefficients e.g. polynomials. Semi-direct + usage of this algorithm is also important in computing + efficiently sub-resultant PRS. + + Assuming that M is a square matrix of dimension N x N and + I is N x N identity matrix, then the Berkowitz vector is + an N x 1 vector whose entries are coefficients of the + polynomial + + charpoly(M) = det(t*I - M) + + As a consequence, all polynomials generated by Berkowitz + algorithm are monic. + + For more information on the implemented algorithm refer to: + + [1] S.J. Berkowitz, On computing the determinant in small + parallel time using a small number of processors, ACM, + Information Processing Letters 18, 1984, pp. 147-150 + + [2] M. Keber, Division-Free computation of sub-resultants + using Bezout matrices, Tech. Report MPI-I-2006-1-006, + Saarbrucken, 2006 + """ + + # handle the trivial cases + if M.rows == 0 and M.cols == 0: + return M._new(1, 1, [M.one]) + elif M.rows == 1 and M.cols == 1: + return M._new(2, 1, [M.one, -M[0,0]]) + + submat, toeplitz = _berkowitz_toeplitz_matrix(M) + + return toeplitz.multiply(_berkowitz_vector(submat), dotprodsimp=None) + + +def _adjugate(M, method="berkowitz"): + """Returns the adjugate, or classical adjoint, of + a matrix. That is, the transpose of the matrix of cofactors. + + https://en.wikipedia.org/wiki/Adjugate + + Parameters + ========== + + method : string, optional + Method to use to find the cofactors, can be "bareiss", "berkowitz", + "bird", "laplace" or "lu". + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2], [3, 4]]) + >>> M.adjugate() + Matrix([ + [ 4, -2], + [-3, 1]]) + + See Also + ======== + + cofactor_matrix + sympy.matrices.matrixbase.MatrixBase.transpose + """ + + return M.cofactor_matrix(method=method).transpose() + + +# This functions is a candidate for caching if it gets implemented for matrices. +def _charpoly(M, x='lambda', simplify=_simplify): + """Computes characteristic polynomial det(x*I - M) where I is + the identity matrix. + + A PurePoly is returned, so using different variables for ``x`` does + not affect the comparison or the polynomials: + + Parameters + ========== + + x : string, optional + Name for the "lambda" variable, defaults to "lambda". + + simplify : function, optional + Simplification function to use on the characteristic polynomial + calculated. Defaults to ``simplify``. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[1, 3], [2, 0]]) + >>> M.charpoly() + PurePoly(lambda**2 - lambda - 6, lambda, domain='ZZ') + >>> M.charpoly(x) == M.charpoly(y) + True + >>> M.charpoly(x) == M.charpoly(y) + True + + Specifying ``x`` is optional; a symbol named ``lambda`` is used by + default (which looks good when pretty-printed in unicode): + + >>> M.charpoly().as_expr() + lambda**2 - lambda - 6 + + And if ``x`` clashes with an existing symbol, underscores will + be prepended to the name to make it unique: + + >>> M = Matrix([[1, 2], [x, 0]]) + >>> M.charpoly(x).as_expr() + _x**2 - _x - 2*x + + Whether you pass a symbol or not, the generator can be obtained + with the gen attribute since it may not be the same as the symbol + that was passed: + + >>> M.charpoly(x).gen + _x + >>> M.charpoly(x).gen == x + False + + Notes + ===== + + The Samuelson-Berkowitz algorithm is used to compute + the characteristic polynomial efficiently and without any + division operations. Thus the characteristic polynomial over any + commutative ring without zero divisors can be computed. + + If the determinant det(x*I - M) can be found out easily as + in the case of an upper or a lower triangular matrix, then + instead of Samuelson-Berkowitz algorithm, eigenvalues are computed + and the characteristic polynomial with their help. + + See Also + ======== + + det + """ + + if not M.is_square: + raise NonSquareMatrixError() + + # Use DomainMatrix. We are already going to convert this to a Poly so there + # is no need to worry about expanding powers etc. Also since this algorithm + # does not require division or zero detection it is fine to use EX. + # + # M.to_DM() will fall back on EXRAW rather than EX. EXRAW is a lot faster + # for elementary arithmetic because it does not call cancel for each + # operation but it generates large unsimplified results that are slow in + # the subsequent call to simplify. Using EX instead is faster overall + # but at least in some cases EXRAW+simplify gives a simpler result so we + # preserve that existing behaviour of charpoly for now... + dM = M.to_DM() + + K = dM.domain + + cp = dM.charpoly() + + x = uniquely_named_symbol(x, [M], modify=lambda s: '_' + s) + + if K.is_EXRAW or simplify is not _simplify: + # XXX: Converting back to Expr is expensive. We only do it if the + # caller supplied a custom simplify function for backwards + # compatibility or otherwise if the domain was EX. For any other domain + # there should be no benefit in simplifying at this stage because Poly + # will put everything into canonical form anyway. + berk_vector = [K.to_sympy(c) for c in cp] + berk_vector = [simplify(a) for a in berk_vector] + p = PurePoly(berk_vector, x) + + else: + # Convert from the list of domain elements directly to Poly. + p = PurePoly(cp, x, domain=K) + + return p + + +def _cofactor(M, i, j, method="berkowitz"): + """Calculate the cofactor of an element. + + Parameters + ========== + + method : string, optional + Method to use to find the cofactors, can be "bareiss", "berkowitz", + "bird", "laplace" or "lu". + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2], [3, 4]]) + >>> M.cofactor(0, 1) + -3 + + See Also + ======== + + cofactor_matrix + minor + minor_submatrix + """ + + if not M.is_square or M.rows < 1: + raise NonSquareMatrixError() + + return S.NegativeOne**((i + j) % 2) * M.minor(i, j, method) + + +def _cofactor_matrix(M, method="berkowitz"): + """Return a matrix containing the cofactor of each element. + + Parameters + ========== + + method : string, optional + Method to use to find the cofactors, can be "bareiss", "berkowitz", + "bird", "laplace" or "lu". + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2], [3, 4]]) + >>> M.cofactor_matrix() + Matrix([ + [ 4, -3], + [-2, 1]]) + + See Also + ======== + + cofactor + minor + minor_submatrix + """ + + if not M.is_square: + raise NonSquareMatrixError() + + return M._new(M.rows, M.cols, + lambda i, j: M.cofactor(i, j, method)) + +def _per(M): + """Returns the permanent of a matrix. Unlike determinant, + permanent is defined for both square and non-square matrices. + + For an m x n matrix, with m less than or equal to n, + it is given as the sum over the permutations s of size + less than or equal to m on [1, 2, . . . n] of the product + from i = 1 to m of M[i, s[i]]. Taking the transpose will + not affect the value of the permanent. + + In the case of a square matrix, this is the same as the permutation + definition of the determinant, but it does not take the sign of the + permutation into account. Computing the permanent with this definition + is quite inefficient, so here the Ryser formula is used. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> M.per() + 450 + >>> M = Matrix([1, 5, 7]) + >>> M.per() + 13 + + References + ========== + + .. [1] Prof. Frank Ben's notes: https://math.berkeley.edu/~bernd/ban275.pdf + .. [2] Wikipedia article on Permanent: https://en.wikipedia.org/wiki/Permanent_%28mathematics%29 + .. [3] https://reference.wolfram.com/language/ref/Permanent.html + .. [4] Permanent of a rectangular matrix : https://arxiv.org/pdf/0904.3251.pdf + """ + import itertools + + m, n = M.shape + if m > n: + M = M.T + m, n = n, m + s = list(range(n)) + + subsets = [] + for i in range(1, m + 1): + subsets += list(map(list, itertools.combinations(s, i))) + + perm = 0 + for subset in subsets: + prod = 1 + sub_len = len(subset) + for i in range(m): + prod *= sum(M[i, j] for j in subset) + perm += prod * S.NegativeOne**sub_len * nC(n - sub_len, m - sub_len) + perm *= S.NegativeOne**m + return perm.simplify() + +def _det_DOM(M): + DOM = DomainMatrix.from_Matrix(M, field=True, extension=True) + K = DOM.domain + return K.to_sympy(DOM.det()) + +# This functions is a candidate for caching if it gets implemented for matrices. +def _det(M, method="bareiss", iszerofunc=None): + """Computes the determinant of a matrix if ``M`` is a concrete matrix object + otherwise return an expressions ``Determinant(M)`` if ``M`` is a + ``MatrixSymbol`` or other expression. + + Parameters + ========== + + method : string, optional + Specifies the algorithm used for computing the matrix determinant. + + If the matrix is at most 3x3, a hard-coded formula is used and the + specified method is ignored. Otherwise, it defaults to + ``'bareiss'``. + + Also, if the matrix is an upper or a lower triangular matrix, determinant + is computed by simple multiplication of diagonal elements, and the + specified method is ignored. + + If it is set to ``'domain-ge'``, then Gaussian elimination method will + be used via using DomainMatrix. + + If it is set to ``'bareiss'``, Bareiss' fraction-free algorithm will + be used. + + If it is set to ``'berkowitz'``, Berkowitz' algorithm will be used. + + If it is set to ``'bird'``, Bird's algorithm will be used [1]_. + + If it is set to ``'laplace'``, Laplace's algorithm will be used. + + Otherwise, if it is set to ``'lu'``, LU decomposition will be used. + + .. note:: + For backward compatibility, legacy keys like "bareis" and + "det_lu" can still be used to indicate the corresponding + methods. + And the keys are also case-insensitive for now. However, it is + suggested to use the precise keys for specifying the method. + + iszerofunc : FunctionType or None, optional + If it is set to ``None``, it will be defaulted to ``_iszero`` if the + method is set to ``'bareiss'``, and ``_is_zero_after_expand_mul`` if + the method is set to ``'lu'``. + + It can also accept any user-specified zero testing function, if it + is formatted as a function which accepts a single symbolic argument + and returns ``True`` if it is tested as zero and ``False`` if it + tested as non-zero, and also ``None`` if it is undecidable. + + Returns + ======= + + det : Basic + Result of determinant. + + Raises + ====== + + ValueError + If unrecognized keys are given for ``method`` or ``iszerofunc``. + + NonSquareMatrixError + If attempted to calculate determinant from a non-square matrix. + + Examples + ======== + + >>> from sympy import Matrix, eye, det + >>> I3 = eye(3) + >>> det(I3) + 1 + >>> M = Matrix([[1, 2], [3, 4]]) + >>> det(M) + -2 + >>> det(M) == M.det() + True + >>> M.det(method="domain-ge") + -2 + + References + ========== + + .. [1] Bird, R. S. (2011). A simple division-free algorithm for computing + determinants. Inf. Process. Lett., 111(21), 1072-1074. doi: + 10.1016/j.ipl.2011.08.006 + """ + + # sanitize `method` + method = method.lower() + + if method == "bareis": + method = "bareiss" + elif method == "det_lu": + method = "lu" + + if method not in ("bareiss", "berkowitz", "lu", "domain-ge", "bird", + "laplace"): + raise ValueError("Determinant method '%s' unrecognized" % method) + + if iszerofunc is None: + if method == "bareiss": + iszerofunc = _is_zero_after_expand_mul + elif method == "lu": + iszerofunc = _iszero + + elif not isinstance(iszerofunc, FunctionType): + raise ValueError("Zero testing method '%s' unrecognized" % iszerofunc) + + n = M.rows + + if n == M.cols: # square check is done in individual method functions + if n == 0: + return M.one + elif n == 1: + return M[0, 0] + elif n == 2: + m = M[0, 0] * M[1, 1] - M[0, 1] * M[1, 0] + return _get_intermediate_simp(_dotprodsimp)(m) + elif n == 3: + m = (M[0, 0] * M[1, 1] * M[2, 2] + + M[0, 1] * M[1, 2] * M[2, 0] + + M[0, 2] * M[1, 0] * M[2, 1] + - M[0, 2] * M[1, 1] * M[2, 0] + - M[0, 0] * M[1, 2] * M[2, 1] + - M[0, 1] * M[1, 0] * M[2, 2]) + return _get_intermediate_simp(_dotprodsimp)(m) + + dets = [] + for b in M.strongly_connected_components(): + if method == "domain-ge": # uses DomainMatrix to evaluate determinant + det = _det_DOM(M[b, b]) + elif method == "bareiss": + det = M[b, b]._eval_det_bareiss(iszerofunc=iszerofunc) + elif method == "berkowitz": + det = M[b, b]._eval_det_berkowitz() + elif method == "lu": + det = M[b, b]._eval_det_lu(iszerofunc=iszerofunc) + elif method == "bird": + det = M[b, b]._eval_det_bird() + elif method == "laplace": + det = M[b, b]._eval_det_laplace() + dets.append(det) + return Mul(*dets) + + +# This functions is a candidate for caching if it gets implemented for matrices. +def _det_bareiss(M, iszerofunc=_is_zero_after_expand_mul): + """Compute matrix determinant using Bareiss' fraction-free + algorithm which is an extension of the well known Gaussian + elimination method. This approach is best suited for dense + symbolic matrices and will result in a determinant with + minimal number of fractions. It means that less term + rewriting is needed on resulting formulae. + + Parameters + ========== + + iszerofunc : function, optional + The function to use to determine zeros when doing an LU decomposition. + Defaults to ``lambda x: x.is_zero``. + + TODO: Implement algorithm for sparse matrices (SFF), + http://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps. + """ + + # Recursively implemented Bareiss' algorithm as per Deanna Richelle Leggett's + # thesis http://www.math.usm.edu/perry/Research/Thesis_DRL.pdf + def bareiss(mat, cumm=1): + if mat.rows == 0: + return mat.one + elif mat.rows == 1: + return mat[0, 0] + + # find a pivot and extract the remaining matrix + # With the default iszerofunc, _find_reasonable_pivot slows down + # the computation by the factor of 2.5 in one test. + # Relevant issues: #10279 and #13877. + pivot_pos, pivot_val, _, _ = _find_reasonable_pivot(mat[:, 0], iszerofunc=iszerofunc) + if pivot_pos is None: + return mat.zero + + # if we have a valid pivot, we'll do a "row swap", so keep the + # sign of the det + sign = (-1) ** (pivot_pos % 2) + + # we want every row but the pivot row and every column + rows = [i for i in range(mat.rows) if i != pivot_pos] + cols = list(range(mat.cols)) + tmp_mat = mat.extract(rows, cols) + + def entry(i, j): + ret = (pivot_val*tmp_mat[i, j + 1] - mat[pivot_pos, j + 1]*tmp_mat[i, 0]) / cumm + if _get_intermediate_simp_bool(True): + return _dotprodsimp(ret) + elif not ret.is_Atom: + return cancel(ret) + return ret + + return sign*bareiss(M._new(mat.rows - 1, mat.cols - 1, entry), pivot_val) + + if not M.is_square: + raise NonSquareMatrixError() + + if M.rows == 0: + return M.one + # sympy/matrices/tests/test_matrices.py contains a test that + # suggests that the determinant of a 0 x 0 matrix is one, by + # convention. + + return bareiss(M) + + +def _det_berkowitz(M): + """ Use the Berkowitz algorithm to compute the determinant.""" + + if not M.is_square: + raise NonSquareMatrixError() + + if M.rows == 0: + return M.one + # sympy/matrices/tests/test_matrices.py contains a test that + # suggests that the determinant of a 0 x 0 matrix is one, by + # convention. + + berk_vector = _berkowitz_vector(M) + return (-1)**(len(berk_vector) - 1) * berk_vector[-1] + + +# This functions is a candidate for caching if it gets implemented for matrices. +def _det_LU(M, iszerofunc=_iszero, simpfunc=None): + """ Computes the determinant of a matrix from its LU decomposition. + This function uses the LU decomposition computed by + LUDecomposition_Simple(). + + The keyword arguments iszerofunc and simpfunc are passed to + LUDecomposition_Simple(). + iszerofunc is a callable that returns a boolean indicating if its + input is zero, or None if it cannot make the determination. + simpfunc is a callable that simplifies its input. + The default is simpfunc=None, which indicate that the pivot search + algorithm should not attempt to simplify any candidate pivots. + If simpfunc fails to simplify its input, then it must return its input + instead of a copy. + + Parameters + ========== + + iszerofunc : function, optional + The function to use to determine zeros when doing an LU decomposition. + Defaults to ``lambda x: x.is_zero``. + + simpfunc : function, optional + The simplification function to use when looking for zeros for pivots. + """ + + if not M.is_square: + raise NonSquareMatrixError() + + if M.rows == 0: + return M.one + # sympy/matrices/tests/test_matrices.py contains a test that + # suggests that the determinant of a 0 x 0 matrix is one, by + # convention. + + lu, row_swaps = M.LUdecomposition_Simple(iszerofunc=iszerofunc, + simpfunc=simpfunc) + # P*A = L*U => det(A) = det(L)*det(U)/det(P) = det(P)*det(U). + # Lower triangular factor L encoded in lu has unit diagonal => det(L) = 1. + # P is a permutation matrix => det(P) in {-1, 1} => 1/det(P) = det(P). + # LUdecomposition_Simple() returns a list of row exchange index pairs, rather + # than a permutation matrix, but det(P) = (-1)**len(row_swaps). + + # Avoid forming the potentially time consuming product of U's diagonal entries + # if the product is zero. + # Bottom right entry of U is 0 => det(A) = 0. + # It may be impossible to determine if this entry of U is zero when it is symbolic. + if iszerofunc(lu[lu.rows-1, lu.rows-1]): + return M.zero + + # Compute det(P) + det = -M.one if len(row_swaps)%2 else M.one + + # Compute det(U) by calculating the product of U's diagonal entries. + # The upper triangular portion of lu is the upper triangular portion of the + # U factor in the LU decomposition. + for k in range(lu.rows): + det *= lu[k, k] + + # return det(P)*det(U) + return det + + +@cacheit +def __det_laplace(M): + """Compute the determinant of a matrix using Laplace expansion. + + This is a recursive function, and it should not be called directly. + Use _det_laplace() instead. The reason for splitting this function + into two is to allow caching of determinants of submatrices. While + one could also define this function inside _det_laplace(), that + would remove the advantage of using caching in Cramer Solve. + """ + n = M.shape[0] + if n == 1: + return M[0] + elif n == 2: + return M[0, 0] * M[1, 1] - M[0, 1] * M[1, 0] + else: + return sum((-1) ** i * M[0, i] * + __det_laplace(M.minor_submatrix(0, i)) for i in range(n)) + + +def _det_laplace(M): + """Compute the determinant of a matrix using Laplace expansion. + + While Laplace expansion is not the most efficient method of computing + a determinant, it is a simple one, and it has the advantage of + being division free. To improve efficiency, this function uses + caching to avoid recomputing determinants of submatrices. + """ + if not M.is_square: + raise NonSquareMatrixError() + if M.shape[0] == 0: + return M.one + # sympy/matrices/tests/test_matrices.py contains a test that + # suggests that the determinant of a 0 x 0 matrix is one, by + # convention. + return __det_laplace(M.as_immutable()) + + +def _det_bird(M): + r"""Compute the determinant of a matrix using Bird's algorithm. + + Bird's algorithm is a simple division-free algorithm for computing, which + is of lower order than the Laplace's algorithm. It is described in [1]_. + + References + ========== + + .. [1] Bird, R. S. (2011). A simple division-free algorithm for computing + determinants. Inf. Process. Lett., 111(21), 1072-1074. doi: + 10.1016/j.ipl.2011.08.006 + """ + def mu(X): + n = X.shape[0] + zero = X.domain.zero + + total = zero + diag_sums = [zero] + for i in reversed(range(1, n)): + total -= X[i][i] + diag_sums.append(total) + diag_sums = diag_sums[::-1] + + elems = [[zero] * i + [diag_sums[i]] + X_i[i + 1:] for i, X_i in + enumerate(X)] + return DDM(elems, X.shape, X.domain) + + Mddm = M._rep.to_ddm() + n = M.shape[0] + if n == 0: + return M.one + # sympy/matrices/tests/test_matrices.py contains a test that + # suggests that the determinant of a 0 x 0 matrix is one, by + # convention. + Fn1 = Mddm + for _ in range(n - 1): + Fn1 = mu(Fn1).matmul(Mddm) + detA = Fn1[0][0] + if n % 2 == 0: + detA = -detA + + return Mddm.domain.to_sympy(detA) + + +def _minor(M, i, j, method="berkowitz"): + """Return the (i,j) minor of ``M``. That is, + return the determinant of the matrix obtained by deleting + the `i`th row and `j`th column from ``M``. + + Parameters + ========== + + i, j : int + The row and column to exclude to obtain the submatrix. + + method : string, optional + Method to use to find the determinant of the submatrix, can be + "bareiss", "berkowitz", "bird", "laplace" or "lu". + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> M.minor(1, 1) + -12 + + See Also + ======== + + minor_submatrix + cofactor + det + """ + + if not M.is_square: + raise NonSquareMatrixError() + + return M.minor_submatrix(i, j).det(method=method) + + +def _minor_submatrix(M, i, j): + """Return the submatrix obtained by removing the `i`th row + and `j`th column from ``M`` (works with Pythonic negative indices). + + Parameters + ========== + + i, j : int + The row and column to exclude to obtain the submatrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> M.minor_submatrix(1, 1) + Matrix([ + [1, 3], + [7, 9]]) + + See Also + ======== + + minor + cofactor + """ + + if i < 0: + i += M.rows + if j < 0: + j += M.cols + + if not 0 <= i < M.rows or not 0 <= j < M.cols: + raise ValueError("`i` and `j` must satisfy 0 <= i < ``M.rows`` " + "(%d)" % M.rows + "and 0 <= j < ``M.cols`` (%d)." % M.cols) + + rows = [a for a in range(M.rows) if a != i] + cols = [a for a in range(M.cols) if a != j] + + return M.extract(rows, cols) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/eigen.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/eigen.py new file mode 100644 index 0000000000000000000000000000000000000000..87b2418efcece1c0b158ec56995bb011286feb3c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/eigen.py @@ -0,0 +1,1346 @@ +from types import FunctionType +from collections import Counter + +from mpmath import mp, workprec +from mpmath.libmp.libmpf import prec_to_dps + +from sympy.core.sorting import default_sort_key +from sympy.core.evalf import DEFAULT_MAXPREC, PrecisionExhausted +from sympy.core.logic import fuzzy_and, fuzzy_or +from sympy.core.numbers import Float +from sympy.core.sympify import _sympify +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.polys import roots, CRootOf, ZZ, QQ, EX +from sympy.polys.matrices import DomainMatrix +from sympy.polys.matrices.eigen import dom_eigenvects, dom_eigenvects_to_sympy +from sympy.polys.polytools import gcd + +from .exceptions import MatrixError, NonSquareMatrixError +from .determinant import _find_reasonable_pivot + +from .utilities import _iszero, _simplify + + +__doctest_requires__ = { + ('_is_indefinite', + '_is_negative_definite', + '_is_negative_semidefinite', + '_is_positive_definite', + '_is_positive_semidefinite'): ['matplotlib'], +} + + +def _eigenvals_eigenvects_mpmath(M): + norm2 = lambda v: mp.sqrt(sum(i**2 for i in v)) + + v1 = None + prec = max(x._prec for x in M.atoms(Float)) + eps = 2**-prec + + while prec < DEFAULT_MAXPREC: + with workprec(prec): + A = mp.matrix(M.evalf(n=prec_to_dps(prec))) + E, ER = mp.eig(A) + v2 = norm2([i for e in E for i in (mp.re(e), mp.im(e))]) + if v1 is not None and mp.fabs(v1 - v2) < eps: + return E, ER + v1 = v2 + prec *= 2 + + # we get here because the next step would have taken us + # past MAXPREC or because we never took a step; in case + # of the latter, we refuse to send back a solution since + # it would not have been verified; we also resist taking + # a small step to arrive exactly at MAXPREC since then + # the two calculations might be artificially close. + raise PrecisionExhausted + + +def _eigenvals_mpmath(M, multiple=False): + """Compute eigenvalues using mpmath""" + E, _ = _eigenvals_eigenvects_mpmath(M) + result = [_sympify(x) for x in E] + if multiple: + return result + return dict(Counter(result)) + + +def _eigenvects_mpmath(M): + E, ER = _eigenvals_eigenvects_mpmath(M) + result = [] + for i in range(M.rows): + eigenval = _sympify(E[i]) + eigenvect = _sympify(ER[:, i]) + result.append((eigenval, 1, [eigenvect])) + + return result + + +# This function is a candidate for caching if it gets implemented for matrices. +def _eigenvals( + M, error_when_incomplete=True, *, simplify=False, multiple=False, + rational=False, **flags): + r"""Compute eigenvalues of the matrix. + + Parameters + ========== + + error_when_incomplete : bool, optional + If it is set to ``True``, it will raise an error if not all + eigenvalues are computed. This is caused by ``roots`` not returning + a full list of eigenvalues. + + simplify : bool or function, optional + If it is set to ``True``, it attempts to return the most + simplified form of expressions returned by applying default + simplification method in every routine. + + If it is set to ``False``, it will skip simplification in this + particular routine to save computation resources. + + If a function is passed to, it will attempt to apply + the particular function as simplification method. + + rational : bool, optional + If it is set to ``True``, every floating point numbers would be + replaced with rationals before computation. It can solve some + issues of ``roots`` routine not working well with floats. + + multiple : bool, optional + If it is set to ``True``, the result will be in the form of a + list. + + If it is set to ``False``, the result will be in the form of a + dictionary. + + Returns + ======= + + eigs : list or dict + Eigenvalues of a matrix. The return format would be specified by + the key ``multiple``. + + Raises + ====== + + MatrixError + If not enough roots had got computed. + + NonSquareMatrixError + If attempted to compute eigenvalues from a non-square matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix(3, 3, [0, 1, 1, 1, 0, 0, 1, 1, 1]) + >>> M.eigenvals() + {-1: 1, 0: 1, 2: 1} + + See Also + ======== + + MatrixBase.charpoly + eigenvects + + Notes + ===== + + Eigenvalues of a matrix $A$ can be computed by solving a matrix + equation $\det(A - \lambda I) = 0$ + + It's not always possible to return radical solutions for + eigenvalues for matrices larger than $4, 4$ shape due to + Abel-Ruffini theorem. + + If there is no radical solution is found for the eigenvalue, + it may return eigenvalues in the form of + :class:`sympy.polys.rootoftools.ComplexRootOf`. + """ + if not M: + if multiple: + return [] + return {} + + if not M.is_square: + raise NonSquareMatrixError("{} must be a square matrix.".format(M)) + + if M._rep.domain not in (ZZ, QQ): + # Skip this check for ZZ/QQ because it can be slow + if all(x.is_number for x in M) and M.has(Float): + return _eigenvals_mpmath(M, multiple=multiple) + + if rational: + from sympy.simplify import nsimplify + M = M.applyfunc( + lambda x: nsimplify(x, rational=True) if x.has(Float) else x) + + if multiple: + return _eigenvals_list( + M, error_when_incomplete=error_when_incomplete, simplify=simplify, + **flags) + return _eigenvals_dict( + M, error_when_incomplete=error_when_incomplete, simplify=simplify, + **flags) + + +eigenvals_error_message = \ +"It is not always possible to express the eigenvalues of a matrix " + \ +"of size 5x5 or higher in radicals. " + \ +"We have CRootOf, but domains other than the rationals are not " + \ +"currently supported. " + \ +"If there are no symbols in the matrix, " + \ +"it should still be possible to compute numeric approximations " + \ +"of the eigenvalues using " + \ +"M.evalf().eigenvals() or M.charpoly().nroots()." + + +def _eigenvals_list( + M, error_when_incomplete=True, simplify=False, **flags): + iblocks = M.strongly_connected_components() + all_eigs = [] + is_dom = M._rep.domain in (ZZ, QQ) + for b in iblocks: + + # Fast path for a 1x1 block: + if is_dom and len(b) == 1: + index = b[0] + val = M[index, index] + all_eigs.append(val) + continue + + block = M[b, b] + + if isinstance(simplify, FunctionType): + charpoly = block.charpoly(simplify=simplify) + else: + charpoly = block.charpoly() + + eigs = roots(charpoly, multiple=True, **flags) + + if len(eigs) != block.rows: + try: + eigs = charpoly.all_roots(multiple=True) + except NotImplementedError: + if error_when_incomplete: + raise MatrixError(eigenvals_error_message) + else: + eigs = [] + + all_eigs += eigs + + if not simplify: + return all_eigs + if not isinstance(simplify, FunctionType): + simplify = _simplify + return [simplify(value) for value in all_eigs] + + +def _eigenvals_dict( + M, error_when_incomplete=True, simplify=False, **flags): + iblocks = M.strongly_connected_components() + all_eigs = {} + is_dom = M._rep.domain in (ZZ, QQ) + for b in iblocks: + + # Fast path for a 1x1 block: + if is_dom and len(b) == 1: + index = b[0] + val = M[index, index] + all_eigs[val] = all_eigs.get(val, 0) + 1 + continue + + block = M[b, b] + + if isinstance(simplify, FunctionType): + charpoly = block.charpoly(simplify=simplify) + else: + charpoly = block.charpoly() + + eigs = roots(charpoly, multiple=False, **flags) + + if sum(eigs.values()) != block.rows: + try: + eigs = dict(charpoly.all_roots(multiple=False)) + except NotImplementedError: + if error_when_incomplete: + raise MatrixError(eigenvals_error_message) + else: + eigs = {} + + for k, v in eigs.items(): + if k in all_eigs: + all_eigs[k] += v + else: + all_eigs[k] = v + + if not simplify: + return all_eigs + if not isinstance(simplify, FunctionType): + simplify = _simplify + return {simplify(key): value for key, value in all_eigs.items()} + + +def _eigenspace(M, eigenval, iszerofunc=_iszero, simplify=False): + """Get a basis for the eigenspace for a particular eigenvalue""" + m = M - M.eye(M.rows) * eigenval + ret = m.nullspace(iszerofunc=iszerofunc) + + # The nullspace for a real eigenvalue should be non-trivial. + # If we didn't find an eigenvector, try once more a little harder + if len(ret) == 0 and simplify: + ret = m.nullspace(iszerofunc=iszerofunc, simplify=True) + if len(ret) == 0: + raise NotImplementedError( + "Can't evaluate eigenvector for eigenvalue {}".format(eigenval)) + return ret + + +def _eigenvects_DOM(M, **kwargs): + DOM = DomainMatrix.from_Matrix(M, field=True, extension=True) + DOM = DOM.to_dense() + + if DOM.domain != EX: + rational, algebraic = dom_eigenvects(DOM) + eigenvects = dom_eigenvects_to_sympy( + rational, algebraic, M.__class__, **kwargs) + eigenvects = sorted(eigenvects, key=lambda x: default_sort_key(x[0])) + + return eigenvects + return None + + +def _eigenvects_sympy(M, iszerofunc, simplify=True, **flags): + eigenvals = M.eigenvals(rational=False, **flags) + + # Make sure that we have all roots in radical form + for x in eigenvals: + if x.has(CRootOf): + raise MatrixError( + "Eigenvector computation is not implemented if the matrix have " + "eigenvalues in CRootOf form") + + eigenvals = sorted(eigenvals.items(), key=default_sort_key) + ret = [] + for val, mult in eigenvals: + vects = _eigenspace(M, val, iszerofunc=iszerofunc, simplify=simplify) + ret.append((val, mult, vects)) + return ret + + +# This functions is a candidate for caching if it gets implemented for matrices. +def _eigenvects(M, error_when_incomplete=True, iszerofunc=_iszero, *, chop=False, **flags): + """Compute eigenvectors of the matrix. + + Parameters + ========== + + error_when_incomplete : bool, optional + Raise an error when not all eigenvalues are computed. This is + caused by ``roots`` not returning a full list of eigenvalues. + + iszerofunc : function, optional + Specifies a zero testing function to be used in ``rref``. + + Default value is ``_iszero``, which uses SymPy's naive and fast + default assumption handler. + + It can also accept any user-specified zero testing function, if it + is formatted as a function which accepts a single symbolic argument + and returns ``True`` if it is tested as zero and ``False`` if it + is tested as non-zero, and ``None`` if it is undecidable. + + simplify : bool or function, optional + If ``True``, ``as_content_primitive()`` will be used to tidy up + normalization artifacts. + + It will also be used by the ``nullspace`` routine. + + chop : bool or positive number, optional + If the matrix contains any Floats, they will be changed to Rationals + for computation purposes, but the answers will be returned after + being evaluated with evalf. The ``chop`` flag is passed to ``evalf``. + When ``chop=True`` a default precision will be used; a number will + be interpreted as the desired level of precision. + + Returns + ======= + + ret : [(eigenval, multiplicity, eigenspace), ...] + A ragged list containing tuples of data obtained by ``eigenvals`` + and ``nullspace``. + + ``eigenspace`` is a list containing the ``eigenvector`` for each + eigenvalue. + + ``eigenvector`` is a vector in the form of a ``Matrix``. e.g. + a vector of length 3 is returned as ``Matrix([a_1, a_2, a_3])``. + + Raises + ====== + + NotImplementedError + If failed to compute nullspace. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix(3, 3, [0, 1, 1, 1, 0, 0, 1, 1, 1]) + >>> M.eigenvects() + [(-1, 1, [Matrix([ + [-1], + [ 1], + [ 0]])]), (0, 1, [Matrix([ + [ 0], + [-1], + [ 1]])]), (2, 1, [Matrix([ + [2/3], + [1/3], + [ 1]])])] + + See Also + ======== + + eigenvals + MatrixBase.nullspace + """ + simplify = flags.get('simplify', True) + primitive = flags.get('simplify', False) + flags.pop('simplify', None) # remove this if it's there + flags.pop('multiple', None) # remove this if it's there + + if not isinstance(simplify, FunctionType): + simpfunc = _simplify if simplify else lambda x: x + + has_floats = M.has(Float) + if has_floats: + if all(x.is_number for x in M): + return _eigenvects_mpmath(M) + from sympy.simplify import nsimplify + M = M.applyfunc(lambda x: nsimplify(x, rational=True)) + + ret = _eigenvects_DOM(M) + if ret is None: + ret = _eigenvects_sympy(M, iszerofunc, simplify=simplify, **flags) + + if primitive: + # if the primitive flag is set, get rid of any common + # integer denominators + def denom_clean(l): + return [(v / gcd(list(v))).applyfunc(simpfunc) for v in l] + + ret = [(val, mult, denom_clean(es)) for val, mult, es in ret] + + if has_floats: + # if we had floats to start with, turn the eigenvectors to floats + ret = [(val.evalf(chop=chop), mult, [v.evalf(chop=chop) for v in es]) + for val, mult, es in ret] + + return ret + + +def _is_diagonalizable_with_eigen(M, reals_only=False): + """See _is_diagonalizable. This function returns the bool along with the + eigenvectors to avoid calculating them again in functions like + ``diagonalize``.""" + + if not M.is_square: + return False, [] + + eigenvecs = M.eigenvects(simplify=True) + + for val, mult, basis in eigenvecs: + if reals_only and not val.is_real: # if we have a complex eigenvalue + return False, eigenvecs + + if mult != len(basis): # if the geometric multiplicity doesn't equal the algebraic + return False, eigenvecs + + return True, eigenvecs + +def _is_diagonalizable(M, reals_only=False, **kwargs): + """Returns ``True`` if a matrix is diagonalizable. + + Parameters + ========== + + reals_only : bool, optional + If ``True``, it tests whether the matrix can be diagonalized + to contain only real numbers on the diagonal. + + + If ``False``, it tests whether the matrix can be diagonalized + at all, even with numbers that may not be real. + + Examples + ======== + + Example of a diagonalizable matrix: + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2, 0], [0, 3, 0], [2, -4, 2]]) + >>> M.is_diagonalizable() + True + + Example of a non-diagonalizable matrix: + + >>> M = Matrix([[0, 1], [0, 0]]) + >>> M.is_diagonalizable() + False + + Example of a matrix that is diagonalized in terms of non-real entries: + + >>> M = Matrix([[0, 1], [-1, 0]]) + >>> M.is_diagonalizable(reals_only=False) + True + >>> M.is_diagonalizable(reals_only=True) + False + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.is_diagonal + diagonalize + """ + if not M.is_square: + return False + + if all(e.is_real for e in M) and M.is_symmetric(): + return True + + if all(e.is_complex for e in M) and M.is_hermitian: + return True + + return _is_diagonalizable_with_eigen(M, reals_only=reals_only)[0] + + +#G&VL, Matrix Computations, Algo 5.4.2 +def _householder_vector(x): + if not x.cols == 1: + raise ValueError("Input must be a column matrix") + v = x.copy() + v_plus = x.copy() + v_minus = x.copy() + q = x[0, 0] / abs(x[0, 0]) + norm_x = x.norm() + v_plus[0, 0] = x[0, 0] + q * norm_x + v_minus[0, 0] = x[0, 0] - q * norm_x + if x[1:, 0].norm() == 0: + bet = 0 + v[0, 0] = 1 + else: + if v_plus.norm() <= v_minus.norm(): + v = v_plus + else: + v = v_minus + v = v / v[0] + bet = 2 / (v.norm() ** 2) + return v, bet + + +def _bidiagonal_decmp_hholder(M): + m = M.rows + n = M.cols + A = M.as_mutable() + U, V = A.eye(m), A.eye(n) + for i in range(min(m, n)): + v, bet = _householder_vector(A[i:, i]) + hh_mat = A.eye(m - i) - bet * v * v.H + A[i:, i:] = hh_mat * A[i:, i:] + temp = A.eye(m) + temp[i:, i:] = hh_mat + U = U * temp + if i + 1 <= n - 2: + v, bet = _householder_vector(A[i, i+1:].T) + hh_mat = A.eye(n - i - 1) - bet * v * v.H + A[i:, i+1:] = A[i:, i+1:] * hh_mat + temp = A.eye(n) + temp[i+1:, i+1:] = hh_mat + V = temp * V + return U, A, V + + +def _eval_bidiag_hholder(M): + m = M.rows + n = M.cols + A = M.as_mutable() + for i in range(min(m, n)): + v, bet = _householder_vector(A[i:, i]) + hh_mat = A.eye(m-i) - bet * v * v.H + A[i:, i:] = hh_mat * A[i:, i:] + if i + 1 <= n - 2: + v, bet = _householder_vector(A[i, i+1:].T) + hh_mat = A.eye(n - i - 1) - bet * v * v.H + A[i:, i+1:] = A[i:, i+1:] * hh_mat + return A + + +def _bidiagonal_decomposition(M, upper=True): + """ + Returns $(U,B,V.H)$ for + + $$A = UBV^{H}$$ + + where $A$ is the input matrix, and $B$ is its Bidiagonalized form + + Note: Bidiagonal Computation can hang for symbolic matrices. + + Parameters + ========== + + upper : bool. Whether to do upper bidiagnalization or lower. + True for upper and False for lower. + + References + ========== + + .. [1] Algorithm 5.4.2, Matrix computations by Golub and Van Loan, 4th edition + .. [2] Complex Matrix Bidiagonalization, https://github.com/vslobody/Householder-Bidiagonalization + + """ + + if not isinstance(upper, bool): + raise ValueError("upper must be a boolean") + + if upper: + return _bidiagonal_decmp_hholder(M) + + X = _bidiagonal_decmp_hholder(M.H) + return X[2].H, X[1].H, X[0].H + + +def _bidiagonalize(M, upper=True): + """ + Returns $B$, the Bidiagonalized form of the input matrix. + + Note: Bidiagonal Computation can hang for symbolic matrices. + + Parameters + ========== + + upper : bool. Whether to do upper bidiagnalization or lower. + True for upper and False for lower. + + References + ========== + + .. [1] Algorithm 5.4.2, Matrix computations by Golub and Van Loan, 4th edition + .. [2] Complex Matrix Bidiagonalization : https://github.com/vslobody/Householder-Bidiagonalization + + """ + + if not isinstance(upper, bool): + raise ValueError("upper must be a boolean") + + if upper: + return _eval_bidiag_hholder(M) + return _eval_bidiag_hholder(M.H).H + + +def _diagonalize(M, reals_only=False, sort=False, normalize=False): + """ + Return (P, D), where D is diagonal and + + D = P^-1 * M * P + + where M is current matrix. + + Parameters + ========== + + reals_only : bool. Whether to throw an error if complex numbers are need + to diagonalize. (Default: False) + + sort : bool. Sort the eigenvalues along the diagonal. (Default: False) + + normalize : bool. If True, normalize the columns of P. (Default: False) + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2]) + >>> M + Matrix([ + [1, 2, 0], + [0, 3, 0], + [2, -4, 2]]) + >>> (P, D) = M.diagonalize() + >>> D + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + >>> P + Matrix([ + [-1, 0, -1], + [ 0, 0, -1], + [ 2, 1, 2]]) + >>> P.inv() * M * P + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.is_diagonal + is_diagonalizable + """ + + if not M.is_square: + raise NonSquareMatrixError() + + is_diagonalizable, eigenvecs = _is_diagonalizable_with_eigen(M, + reals_only=reals_only) + + if not is_diagonalizable: + raise MatrixError("Matrix is not diagonalizable") + + if sort: + eigenvecs = sorted(eigenvecs, key=default_sort_key) + + p_cols, diag = [], [] + + for val, mult, basis in eigenvecs: + diag += [val] * mult + p_cols += basis + + if normalize: + p_cols = [v / v.norm() for v in p_cols] + + return M.hstack(*p_cols), M.diag(*diag) + + +def _fuzzy_positive_definite(M): + positive_diagonals = M._has_positive_diagonals() + if positive_diagonals is False: + return False + + if positive_diagonals and M.is_strongly_diagonally_dominant: + return True + + return None + + +def _fuzzy_positive_semidefinite(M): + nonnegative_diagonals = M._has_nonnegative_diagonals() + if nonnegative_diagonals is False: + return False + + if nonnegative_diagonals and M.is_weakly_diagonally_dominant: + return True + + return None + + +def _is_positive_definite(M): + if not M.is_hermitian: + if not M.is_square: + return False + M = M + M.H + + fuzzy = _fuzzy_positive_definite(M) + if fuzzy is not None: + return fuzzy + + return _is_positive_definite_GE(M) + + +def _is_positive_semidefinite(M): + if not M.is_hermitian: + if not M.is_square: + return False + M = M + M.H + + fuzzy = _fuzzy_positive_semidefinite(M) + if fuzzy is not None: + return fuzzy + + return _is_positive_semidefinite_cholesky(M) + + +def _is_negative_definite(M): + return _is_positive_definite(-M) + + +def _is_negative_semidefinite(M): + return _is_positive_semidefinite(-M) + + +def _is_indefinite(M): + if M.is_hermitian: + eigen = M.eigenvals() + args1 = [x.is_positive for x in eigen.keys()] + any_positive = fuzzy_or(args1) + args2 = [x.is_negative for x in eigen.keys()] + any_negative = fuzzy_or(args2) + + return fuzzy_and([any_positive, any_negative]) + + elif M.is_square: + return (M + M.H).is_indefinite + + return False + + +def _is_positive_definite_GE(M): + """A division-free gaussian elimination method for testing + positive-definiteness.""" + M = M.as_mutable() + size = M.rows + + for i in range(size): + is_positive = M[i, i].is_positive + if is_positive is not True: + return is_positive + for j in range(i+1, size): + M[j, i+1:] = M[i, i] * M[j, i+1:] - M[j, i] * M[i, i+1:] + return True + + +def _is_positive_semidefinite_cholesky(M): + """Uses Cholesky factorization with complete pivoting + + References + ========== + + .. [1] http://eprints.ma.man.ac.uk/1199/1/covered/MIMS_ep2008_116.pdf + + .. [2] https://www.value-at-risk.net/cholesky-factorization/ + """ + M = M.as_mutable() + for k in range(M.rows): + diags = [M[i, i] for i in range(k, M.rows)] + pivot, pivot_val, nonzero, _ = _find_reasonable_pivot(diags) + + if nonzero: + return None + + if pivot is None: + for i in range(k+1, M.rows): + for j in range(k, M.cols): + iszero = M[i, j].is_zero + if iszero is None: + return None + elif iszero is False: + return False + return True + + if M[k, k].is_negative or pivot_val.is_negative: + return False + elif not (M[k, k].is_nonnegative and pivot_val.is_nonnegative): + return None + + if pivot > 0: + M.col_swap(k, k+pivot) + M.row_swap(k, k+pivot) + + M[k, k] = sqrt(M[k, k]) + M[k, k+1:] /= M[k, k] + M[k+1:, k+1:] -= M[k, k+1:].H * M[k, k+1:] + + return M[-1, -1].is_nonnegative + + +_doc_positive_definite = \ + r"""Finds out the definiteness of a matrix. + + Explanation + =========== + + A square real matrix $A$ is: + + - A positive definite matrix if $x^T A x > 0$ + for all non-zero real vectors $x$. + - A positive semidefinite matrix if $x^T A x \geq 0$ + for all non-zero real vectors $x$. + - A negative definite matrix if $x^T A x < 0$ + for all non-zero real vectors $x$. + - A negative semidefinite matrix if $x^T A x \leq 0$ + for all non-zero real vectors $x$. + - An indefinite matrix if there exists non-zero real vectors + $x, y$ with $x^T A x > 0 > y^T A y$. + + A square complex matrix $A$ is: + + - A positive definite matrix if $\text{re}(x^H A x) > 0$ + for all non-zero complex vectors $x$. + - A positive semidefinite matrix if $\text{re}(x^H A x) \geq 0$ + for all non-zero complex vectors $x$. + - A negative definite matrix if $\text{re}(x^H A x) < 0$ + for all non-zero complex vectors $x$. + - A negative semidefinite matrix if $\text{re}(x^H A x) \leq 0$ + for all non-zero complex vectors $x$. + - An indefinite matrix if there exists non-zero complex vectors + $x, y$ with $\text{re}(x^H A x) > 0 > \text{re}(y^H A y)$. + + A matrix need not be symmetric or hermitian to be positive definite. + + - A real non-symmetric matrix is positive definite if and only if + $\frac{A + A^T}{2}$ is positive definite. + - A complex non-hermitian matrix is positive definite if and only if + $\frac{A + A^H}{2}$ is positive definite. + + And this extension can apply for all the definitions above. + + However, for complex cases, you can restrict the definition of + $\text{re}(x^H A x) > 0$ to $x^H A x > 0$ and require the matrix + to be hermitian. + But we do not present this restriction for computation because you + can check ``M.is_hermitian`` independently with this and use + the same procedure. + + Examples + ======== + + An example of symmetric positive definite matrix: + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import Matrix, symbols + >>> from sympy.plotting import plot3d + >>> a, b = symbols('a b') + >>> x = Matrix([a, b]) + + >>> A = Matrix([[1, 0], [0, 1]]) + >>> A.is_positive_definite + True + >>> A.is_positive_semidefinite + True + + >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) + + An example of symmetric positive semidefinite matrix: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> A = Matrix([[1, -1], [-1, 1]]) + >>> A.is_positive_definite + False + >>> A.is_positive_semidefinite + True + + >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) + + An example of symmetric negative definite matrix: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> A = Matrix([[-1, 0], [0, -1]]) + >>> A.is_negative_definite + True + >>> A.is_negative_semidefinite + True + >>> A.is_indefinite + False + + >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) + + An example of symmetric indefinite matrix: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> A = Matrix([[1, 2], [2, -1]]) + >>> A.is_indefinite + True + + >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) + + An example of non-symmetric positive definite matrix. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> A = Matrix([[1, 2], [-2, 1]]) + >>> A.is_positive_definite + True + >>> A.is_positive_semidefinite + True + + >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) + + Notes + ===== + + Although some people trivialize the definition of positive definite + matrices only for symmetric or hermitian matrices, this restriction + is not correct because it does not classify all instances of + positive definite matrices from the definition $x^T A x > 0$ or + $\text{re}(x^H A x) > 0$. + + For instance, ``Matrix([[1, 2], [-2, 1]])`` presented in + the example above is an example of real positive definite matrix + that is not symmetric. + + However, since the following formula holds true; + + .. math:: + \text{re}(x^H A x) > 0 \iff + \text{re}(x^H \frac{A + A^H}{2} x) > 0 + + We can classify all positive definite matrices that may or may not + be symmetric or hermitian by transforming the matrix to + $\frac{A + A^T}{2}$ or $\frac{A + A^H}{2}$ + (which is guaranteed to be always real symmetric or complex + hermitian) and we can defer most of the studies to symmetric or + hermitian positive definite matrices. + + But it is a different problem for the existence of Cholesky + decomposition. Because even though a non symmetric or a non + hermitian matrix can be positive definite, Cholesky or LDL + decomposition does not exist because the decompositions require the + matrix to be symmetric or hermitian. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Definiteness_of_a_matrix#Eigenvalues + + .. [2] https://mathworld.wolfram.com/PositiveDefiniteMatrix.html + + .. [3] Johnson, C. R. "Positive Definite Matrices." Amer. + Math. Monthly 77, 259-264 1970. + """ + +_is_positive_definite.__doc__ = _doc_positive_definite +_is_positive_semidefinite.__doc__ = _doc_positive_definite +_is_negative_definite.__doc__ = _doc_positive_definite +_is_negative_semidefinite.__doc__ = _doc_positive_definite +_is_indefinite.__doc__ = _doc_positive_definite + + +def _jordan_form(M, calc_transform=True, *, chop=False): + """Return $(P, J)$ where $J$ is a Jordan block + matrix and $P$ is a matrix such that $M = P J P^{-1}$ + + Parameters + ========== + + calc_transform : bool + If ``False``, then only $J$ is returned. + + chop : bool + All matrices are converted to exact types when computing + eigenvalues and eigenvectors. As a result, there may be + approximation errors. If ``chop==True``, these errors + will be truncated. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[ 6, 5, -2, -3], [-3, -1, 3, 3], [ 2, 1, -2, -3], [-1, 1, 5, 5]]) + >>> P, J = M.jordan_form() + >>> J + Matrix([ + [2, 1, 0, 0], + [0, 2, 0, 0], + [0, 0, 2, 1], + [0, 0, 0, 2]]) + + See Also + ======== + + jordan_block + """ + + if not M.is_square: + raise NonSquareMatrixError("Only square matrices have Jordan forms") + + mat = M + has_floats = M.has(Float) + + if has_floats: + try: + max_prec = max(term._prec for term in M.values() if isinstance(term, Float)) + except ValueError: + # if no term in the matrix is explicitly a Float calling max() + # will throw a error so setting max_prec to default value of 53 + max_prec = 53 + + # setting minimum max_dps to 15 to prevent loss of precision in + # matrix containing non evaluated expressions + max_dps = max(prec_to_dps(max_prec), 15) + + def restore_floats(*args): + """If ``has_floats`` is `True`, cast all ``args`` as + matrices of floats.""" + + if has_floats: + args = [m.evalf(n=max_dps, chop=chop) for m in args] + if len(args) == 1: + return args[0] + + return args + + # cache calculations for some speedup + mat_cache = {} + + def eig_mat(val, pow): + """Cache computations of ``(M - val*I)**pow`` for quick + retrieval""" + + if (val, pow) in mat_cache: + return mat_cache[(val, pow)] + + if (val, pow - 1) in mat_cache: + mat_cache[(val, pow)] = mat_cache[(val, pow - 1)].multiply( + mat_cache[(val, 1)], dotprodsimp=None) + else: + mat_cache[(val, pow)] = (mat - val*M.eye(M.rows)).pow(pow) + + return mat_cache[(val, pow)] + + # helper functions + def nullity_chain(val, algebraic_multiplicity): + """Calculate the sequence [0, nullity(E), nullity(E**2), ...] + until it is constant where ``E = M - val*I``""" + + # mat.rank() is faster than computing the null space, + # so use the rank-nullity theorem + cols = M.cols + ret = [0] + nullity = cols - eig_mat(val, 1).rank() + i = 2 + + while nullity != ret[-1]: + ret.append(nullity) + + if nullity == algebraic_multiplicity: + break + + nullity = cols - eig_mat(val, i).rank() + i += 1 + + # Due to issues like #7146 and #15872, SymPy sometimes + # gives the wrong rank. In this case, raise an error + # instead of returning an incorrect matrix + if nullity < ret[-1] or nullity > algebraic_multiplicity: + raise MatrixError( + "SymPy had encountered an inconsistent " + "result while computing Jordan block: " + "{}".format(M)) + + return ret + + def blocks_from_nullity_chain(d): + """Return a list of the size of each Jordan block. + If d_n is the nullity of E**n, then the number + of Jordan blocks of size n is + + 2*d_n - d_(n-1) - d_(n+1)""" + + # d[0] is always the number of columns, so skip past it + mid = [2*d[n] - d[n - 1] - d[n + 1] for n in range(1, len(d) - 1)] + # d is assumed to plateau with "d[ len(d) ] == d[-1]", so + # 2*d_n - d_(n-1) - d_(n+1) == d_n - d_(n-1) + end = [d[-1] - d[-2]] if len(d) > 1 else [d[0]] + + return mid + end + + def pick_vec(small_basis, big_basis): + """Picks a vector from big_basis that isn't in + the subspace spanned by small_basis""" + + if len(small_basis) == 0: + return big_basis[0] + + for v in big_basis: + _, pivots = M.hstack(*(small_basis + [v])).echelon_form( + with_pivots=True) + + if pivots[-1] == len(small_basis): + return v + + # roots doesn't like Floats, so replace them with Rationals + if has_floats: + from sympy.simplify import nsimplify + mat = mat.applyfunc(lambda x: nsimplify(x, rational=True)) + + # first calculate the jordan block structure + eigs = mat.eigenvals() + + # Make sure that we have all roots in radical form + for x in eigs: + if x.has(CRootOf): + raise MatrixError( + "Jordan normal form is not implemented if the matrix have " + "eigenvalues in CRootOf form") + + # most matrices have distinct eigenvalues + # and so are diagonalizable. In this case, don't + # do extra work! + if len(eigs.keys()) == mat.cols: + blocks = sorted(eigs.keys(), key=default_sort_key) + jordan_mat = mat.diag(*blocks) + + if not calc_transform: + return restore_floats(jordan_mat) + + jordan_basis = [eig_mat(eig, 1).nullspace()[0] + for eig in blocks] + basis_mat = mat.hstack(*jordan_basis) + + return restore_floats(basis_mat, jordan_mat) + + block_structure = [] + + for eig in sorted(eigs.keys(), key=default_sort_key): + algebraic_multiplicity = eigs[eig] + chain = nullity_chain(eig, algebraic_multiplicity) + block_sizes = blocks_from_nullity_chain(chain) + + # if block_sizes = = [a, b, c, ...], then the number of + # Jordan blocks of size 1 is a, of size 2 is b, etc. + # create an array that has (eig, block_size) with one + # entry for each block + size_nums = [(i+1, num) for i, num in enumerate(block_sizes)] + + # we expect larger Jordan blocks to come earlier + size_nums.reverse() + + block_structure.extend( + [(eig, size) for size, num in size_nums for _ in range(num)]) + + jordan_form_size = sum(size for eig, size in block_structure) + + if jordan_form_size != M.rows: + raise MatrixError( + "SymPy had encountered an inconsistent result while " + "computing Jordan block. : {}".format(M)) + + blocks = (mat.jordan_block(size=size, eigenvalue=eig) for eig, size in block_structure) + jordan_mat = mat.diag(*blocks) + + if not calc_transform: + return restore_floats(jordan_mat) + + # For each generalized eigenspace, calculate a basis. + # We start by looking for a vector in null( (A - eig*I)**n ) + # which isn't in null( (A - eig*I)**(n-1) ) where n is + # the size of the Jordan block + # + # Ideally we'd just loop through block_structure and + # compute each generalized eigenspace. However, this + # causes a lot of unneeded computation. Instead, we + # go through the eigenvalues separately, since we know + # their generalized eigenspaces must have bases that + # are linearly independent. + jordan_basis = [] + + for eig in sorted(eigs.keys(), key=default_sort_key): + eig_basis = [] + + for block_eig, size in block_structure: + if block_eig != eig: + continue + + null_big = (eig_mat(eig, size)).nullspace() + null_small = (eig_mat(eig, size - 1)).nullspace() + + # we want to pick something that is in the big basis + # and not the small, but also something that is independent + # of any other generalized eigenvectors from a different + # generalized eigenspace sharing the same eigenvalue. + vec = pick_vec(null_small + eig_basis, null_big) + new_vecs = [eig_mat(eig, i).multiply(vec, dotprodsimp=None) + for i in range(size)] + + eig_basis.extend(new_vecs) + jordan_basis.extend(reversed(new_vecs)) + + basis_mat = mat.hstack(*jordan_basis) + + return restore_floats(basis_mat, jordan_mat) + + +def _left_eigenvects(M, **flags): + """Returns left eigenvectors and eigenvalues. + + This function returns the list of triples (eigenval, multiplicity, + basis) for the left eigenvectors. Options are the same as for + eigenvects(), i.e. the ``**flags`` arguments gets passed directly to + eigenvects(). + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[0, 1, 1], [1, 0, 0], [1, 1, 1]]) + >>> M.eigenvects() + [(-1, 1, [Matrix([ + [-1], + [ 1], + [ 0]])]), (0, 1, [Matrix([ + [ 0], + [-1], + [ 1]])]), (2, 1, [Matrix([ + [2/3], + [1/3], + [ 1]])])] + >>> M.left_eigenvects() + [(-1, 1, [Matrix([[-2, 1, 1]])]), (0, 1, [Matrix([[-1, -1, 1]])]), (2, + 1, [Matrix([[1, 1, 1]])])] + + """ + + eigs = M.transpose().eigenvects(**flags) + + return [(val, mult, [l.transpose() for l in basis]) for val, mult, basis in eigs] + + +def _singular_values(M): + """Compute the singular values of a Matrix + + Examples + ======== + + >>> from sympy import Matrix, Symbol + >>> x = Symbol('x', real=True) + >>> M = Matrix([[0, 1, 0], [0, x, 0], [-1, 0, 0]]) + >>> M.singular_values() + [sqrt(x**2 + 1), 1, 0] + + See Also + ======== + + condition_number + """ + + if M.rows >= M.cols: + valmultpairs = M.H.multiply(M).eigenvals() + else: + valmultpairs = M.multiply(M.H).eigenvals() + + # Expands result from eigenvals into a simple list + vals = [] + + for k, v in valmultpairs.items(): + vals += [sqrt(k)] * v # dangerous! same k in several spots! + + # Pad with zeros if singular values are computed in reverse way, + # to give consistent format. + if len(vals) < M.cols: + vals += [M.zero] * (M.cols - len(vals)) + + # sort them in descending order + vals.sort(reverse=True, key=default_sort_key) + + return vals diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/exceptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..bfc7cfa0bdffd59ff2bc5a9cd85cf9b04ed1a63d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/exceptions.py @@ -0,0 +1,26 @@ +""" +Exceptions raised by the matrix module. +""" + + +class MatrixError(Exception): + pass + + +class ShapeError(ValueError, MatrixError): + """Wrong matrix shape""" + pass + + +class NonSquareMatrixError(ShapeError): + pass + + +class NonInvertibleMatrixError(ValueError, MatrixError): + """The matrix in not invertible (division by multidimensional zero error).""" + pass + + +class NonPositiveDefiniteMatrixError(ValueError, MatrixError): + """The matrix is not a positive-definite matrix.""" + pass diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/graph.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/graph.py new file mode 100644 index 0000000000000000000000000000000000000000..4c6356db884cfcd3c759ada07ac559f43dbcbbcb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/graph.py @@ -0,0 +1,279 @@ +from sympy.utilities.iterables import \ + flatten, connected_components, strongly_connected_components +from .exceptions import NonSquareMatrixError + + +def _connected_components(M): + """Returns the list of connected vertices of the graph when + a square matrix is viewed as a weighted graph. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([ + ... [66, 0, 0, 68, 0, 0, 0, 0, 67], + ... [0, 55, 0, 0, 0, 0, 54, 53, 0], + ... [0, 0, 0, 0, 1, 2, 0, 0, 0], + ... [86, 0, 0, 88, 0, 0, 0, 0, 87], + ... [0, 0, 10, 0, 11, 12, 0, 0, 0], + ... [0, 0, 20, 0, 21, 22, 0, 0, 0], + ... [0, 45, 0, 0, 0, 0, 44, 43, 0], + ... [0, 35, 0, 0, 0, 0, 34, 33, 0], + ... [76, 0, 0, 78, 0, 0, 0, 0, 77]]) + >>> A.connected_components() + [[0, 3, 8], [1, 6, 7], [2, 4, 5]] + + Notes + ===== + + Even if any symbolic elements of the matrix can be indeterminate + to be zero mathematically, this only takes the account of the + structural aspect of the matrix, so they will considered to be + nonzero. + """ + if not M.is_square: + raise NonSquareMatrixError + + V = range(M.rows) + E = sorted(M.todok().keys()) + return connected_components((V, E)) + + +def _strongly_connected_components(M): + """Returns the list of strongly connected vertices of the graph when + a square matrix is viewed as a weighted graph. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([ + ... [44, 0, 0, 0, 43, 0, 45, 0, 0], + ... [0, 66, 62, 61, 0, 68, 0, 60, 67], + ... [0, 0, 22, 21, 0, 0, 0, 20, 0], + ... [0, 0, 12, 11, 0, 0, 0, 10, 0], + ... [34, 0, 0, 0, 33, 0, 35, 0, 0], + ... [0, 86, 82, 81, 0, 88, 0, 80, 87], + ... [54, 0, 0, 0, 53, 0, 55, 0, 0], + ... [0, 0, 2, 1, 0, 0, 0, 0, 0], + ... [0, 76, 72, 71, 0, 78, 0, 70, 77]]) + >>> A.strongly_connected_components() + [[0, 4, 6], [2, 3, 7], [1, 5, 8]] + """ + if not M.is_square: + raise NonSquareMatrixError + + # RepMatrix uses the more efficient DomainMatrix.scc() method + rep = getattr(M, '_rep', None) + if rep is not None: + return rep.scc() + + V = range(M.rows) + E = sorted(M.todok().keys()) + return strongly_connected_components((V, E)) + + +def _connected_components_decomposition(M): + """Decomposes a square matrix into block diagonal form only + using the permutations. + + Explanation + =========== + + The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a + permutation matrix and $B$ is a block diagonal matrix. + + Returns + ======= + + P, B : PermutationMatrix, BlockDiagMatrix + *P* is a permutation matrix for the similarity transform + as in the explanation. And *B* is the block diagonal matrix of + the result of the permutation. + + If you would like to get the diagonal blocks from the + BlockDiagMatrix, see + :meth:`~sympy.matrices.expressions.blockmatrix.BlockDiagMatrix.get_diag_blocks`. + + Examples + ======== + + >>> from sympy import Matrix, pprint + >>> A = Matrix([ + ... [66, 0, 0, 68, 0, 0, 0, 0, 67], + ... [0, 55, 0, 0, 0, 0, 54, 53, 0], + ... [0, 0, 0, 0, 1, 2, 0, 0, 0], + ... [86, 0, 0, 88, 0, 0, 0, 0, 87], + ... [0, 0, 10, 0, 11, 12, 0, 0, 0], + ... [0, 0, 20, 0, 21, 22, 0, 0, 0], + ... [0, 45, 0, 0, 0, 0, 44, 43, 0], + ... [0, 35, 0, 0, 0, 0, 34, 33, 0], + ... [76, 0, 0, 78, 0, 0, 0, 0, 77]]) + + >>> P, B = A.connected_components_decomposition() + >>> pprint(P) + PermutationMatrix((1 3)(2 8 5 7 4 6)) + >>> pprint(B) + [[66 68 67] ] + [[ ] ] + [[86 88 87] 0 0 ] + [[ ] ] + [[76 78 77] ] + [ ] + [ [55 54 53] ] + [ [ ] ] + [ 0 [45 44 43] 0 ] + [ [ ] ] + [ [35 34 33] ] + [ ] + [ [0 1 2 ]] + [ [ ]] + [ 0 0 [10 11 12]] + [ [ ]] + [ [20 21 22]] + + >>> P = P.as_explicit() + >>> B = B.as_explicit() + >>> P.T*B*P == A + True + + Notes + ===== + + This problem corresponds to the finding of the connected components + of a graph, when a matrix is viewed as a weighted graph. + """ + from sympy.combinatorics.permutations import Permutation + from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix + from sympy.matrices.expressions.permutation import PermutationMatrix + + iblocks = M.connected_components() + + p = Permutation(flatten(iblocks)) + P = PermutationMatrix(p) + + blocks = [] + for b in iblocks: + blocks.append(M[b, b]) + B = BlockDiagMatrix(*blocks) + return P, B + + +def _strongly_connected_components_decomposition(M, lower=True): + """Decomposes a square matrix into block triangular form only + using the permutations. + + Explanation + =========== + + The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a + permutation matrix and $B$ is a block diagonal matrix. + + Parameters + ========== + + lower : bool + Makes $B$ lower block triangular when ``True``. + Otherwise, makes $B$ upper block triangular. + + Returns + ======= + + P, B : PermutationMatrix, BlockMatrix + *P* is a permutation matrix for the similarity transform + as in the explanation. And *B* is the block triangular matrix of + the result of the permutation. + + Examples + ======== + + >>> from sympy import Matrix, pprint + >>> A = Matrix([ + ... [44, 0, 0, 0, 43, 0, 45, 0, 0], + ... [0, 66, 62, 61, 0, 68, 0, 60, 67], + ... [0, 0, 22, 21, 0, 0, 0, 20, 0], + ... [0, 0, 12, 11, 0, 0, 0, 10, 0], + ... [34, 0, 0, 0, 33, 0, 35, 0, 0], + ... [0, 86, 82, 81, 0, 88, 0, 80, 87], + ... [54, 0, 0, 0, 53, 0, 55, 0, 0], + ... [0, 0, 2, 1, 0, 0, 0, 0, 0], + ... [0, 76, 72, 71, 0, 78, 0, 70, 77]]) + + A lower block triangular decomposition: + + >>> P, B = A.strongly_connected_components_decomposition() + >>> pprint(P) + PermutationMatrix((8)(1 4 3 2 6)(5 7)) + >>> pprint(B) + [[44 43 45] [0 0 0] [0 0 0] ] + [[ ] [ ] [ ] ] + [[34 33 35] [0 0 0] [0 0 0] ] + [[ ] [ ] [ ] ] + [[54 53 55] [0 0 0] [0 0 0] ] + [ ] + [ [0 0 0] [22 21 20] [0 0 0] ] + [ [ ] [ ] [ ] ] + [ [0 0 0] [12 11 10] [0 0 0] ] + [ [ ] [ ] [ ] ] + [ [0 0 0] [2 1 0 ] [0 0 0] ] + [ ] + [ [0 0 0] [62 61 60] [66 68 67]] + [ [ ] [ ] [ ]] + [ [0 0 0] [82 81 80] [86 88 87]] + [ [ ] [ ] [ ]] + [ [0 0 0] [72 71 70] [76 78 77]] + + >>> P = P.as_explicit() + >>> B = B.as_explicit() + >>> P.T * B * P == A + True + + An upper block triangular decomposition: + + >>> P, B = A.strongly_connected_components_decomposition(lower=False) + >>> pprint(P) + PermutationMatrix((0 1 5 7 4 3 2 8 6)) + >>> pprint(B) + [[66 68 67] [62 61 60] [0 0 0] ] + [[ ] [ ] [ ] ] + [[86 88 87] [82 81 80] [0 0 0] ] + [[ ] [ ] [ ] ] + [[76 78 77] [72 71 70] [0 0 0] ] + [ ] + [ [0 0 0] [22 21 20] [0 0 0] ] + [ [ ] [ ] [ ] ] + [ [0 0 0] [12 11 10] [0 0 0] ] + [ [ ] [ ] [ ] ] + [ [0 0 0] [2 1 0 ] [0 0 0] ] + [ ] + [ [0 0 0] [0 0 0] [44 43 45]] + [ [ ] [ ] [ ]] + [ [0 0 0] [0 0 0] [34 33 35]] + [ [ ] [ ] [ ]] + [ [0 0 0] [0 0 0] [54 53 55]] + + >>> P = P.as_explicit() + >>> B = B.as_explicit() + >>> P.T * B * P == A + True + """ + from sympy.combinatorics.permutations import Permutation + from sympy.matrices.expressions.blockmatrix import BlockMatrix + from sympy.matrices.expressions.permutation import PermutationMatrix + + iblocks = M.strongly_connected_components() + if not lower: + iblocks = list(reversed(iblocks)) + + p = Permutation(flatten(iblocks)) + P = PermutationMatrix(p) + + rows = [] + for a in iblocks: + cols = [] + for b in iblocks: + cols.append(M[a, b]) + rows.append(cols) + B = BlockMatrix(rows) + return P, B diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/immutable.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/immutable.py new file mode 100644 index 0000000000000000000000000000000000000000..7ec2174bf1c785e1a4698e1b55078d300e62dafe --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/immutable.py @@ -0,0 +1,196 @@ +from mpmath.matrices.matrices import _matrix + +from sympy.core import Basic, Dict, Tuple +from sympy.core.numbers import Integer +from sympy.core.cache import cacheit +from sympy.core.sympify import _sympy_converter as sympify_converter, _sympify +from sympy.matrices.dense import DenseMatrix +from sympy.matrices.expressions import MatrixExpr +from sympy.matrices.matrixbase import MatrixBase +from sympy.matrices.repmatrix import RepMatrix +from sympy.matrices.sparse import SparseRepMatrix +from sympy.multipledispatch import dispatch + + +def sympify_matrix(arg): + return arg.as_immutable() + + +sympify_converter[MatrixBase] = sympify_matrix + + +def sympify_mpmath_matrix(arg): + mat = [_sympify(x) for x in arg] + return ImmutableDenseMatrix(arg.rows, arg.cols, mat) + + +sympify_converter[_matrix] = sympify_mpmath_matrix + + +class ImmutableRepMatrix(RepMatrix, MatrixExpr): # type: ignore + """Immutable matrix based on RepMatrix + + Uses DomainMAtrix as the internal representation. + """ + + # + # This is a subclass of RepMatrix that adds/overrides some methods to make + # the instances Basic and immutable. ImmutableRepMatrix is a superclass for + # both ImmutableDenseMatrix and ImmutableSparseMatrix. + # + + def __new__(cls, *args, **kwargs): + return cls._new(*args, **kwargs) + + __hash__ = MatrixExpr.__hash__ + + def copy(self): + return self + + @property + def cols(self): + return self._cols + + @property + def rows(self): + return self._rows + + @property + def shape(self): + return self._rows, self._cols + + def as_immutable(self): + return self + + def _entry(self, i, j, **kwargs): + return self[i, j] + + def __setitem__(self, *args): + raise TypeError("Cannot set values of {}".format(self.__class__)) + + def is_diagonalizable(self, reals_only=False, **kwargs): + return super().is_diagonalizable( + reals_only=reals_only, **kwargs) + + is_diagonalizable.__doc__ = SparseRepMatrix.is_diagonalizable.__doc__ + is_diagonalizable = cacheit(is_diagonalizable) + + def analytic_func(self, f, x): + return self.as_mutable().analytic_func(f, x).as_immutable() + + +class ImmutableDenseMatrix(DenseMatrix, ImmutableRepMatrix): # type: ignore + """Create an immutable version of a matrix. + + Examples + ======== + + >>> from sympy import eye, ImmutableMatrix + >>> ImmutableMatrix(eye(3)) + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> _[0, 0] = 42 + Traceback (most recent call last): + ... + TypeError: Cannot set values of ImmutableDenseMatrix + """ + + # MatrixExpr is set as NotIterable, but we want explicit matrices to be + # iterable + _iterable = True + _class_priority = 8 + _op_priority = 10.001 + + @classmethod + def _new(cls, *args, **kwargs): + if len(args) == 1 and isinstance(args[0], ImmutableDenseMatrix): + return args[0] + if kwargs.get('copy', True) is False: + if len(args) != 3: + raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]") + rows, cols, flat_list = args + else: + rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs) + flat_list = list(flat_list) # create a shallow copy + + rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list) + + return cls._fromrep(rep) + + @classmethod + def _fromrep(cls, rep): + rows, cols = rep.shape + flat_list = rep.to_sympy().to_list_flat() + obj = Basic.__new__(cls, + Integer(rows), + Integer(cols), + Tuple(*flat_list, sympify=False)) + obj._rows = rows + obj._cols = cols + obj._rep = rep + return obj + + +# make sure ImmutableDenseMatrix is aliased as ImmutableMatrix +ImmutableMatrix = ImmutableDenseMatrix + + +class ImmutableSparseMatrix(SparseRepMatrix, ImmutableRepMatrix): # type:ignore + """Create an immutable version of a sparse matrix. + + Examples + ======== + + >>> from sympy import eye, ImmutableSparseMatrix + >>> ImmutableSparseMatrix(1, 1, {}) + Matrix([[0]]) + >>> ImmutableSparseMatrix(eye(3)) + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> _[0, 0] = 42 + Traceback (most recent call last): + ... + TypeError: Cannot set values of ImmutableSparseMatrix + >>> _.shape + (3, 3) + """ + is_Matrix = True + _class_priority = 9 + + @classmethod + def _new(cls, *args, **kwargs): + rows, cols, smat = cls._handle_creation_inputs(*args, **kwargs) + + rep = cls._smat_to_DomainMatrix(rows, cols, smat) + + return cls._fromrep(rep) + + @classmethod + def _fromrep(cls, rep): + rows, cols = rep.shape + smat = rep.to_sympy().to_dok() + obj = Basic.__new__(cls, Integer(rows), Integer(cols), Dict(smat)) + obj._rows = rows + obj._cols = cols + obj._rep = rep + return obj + + +@dispatch(ImmutableDenseMatrix, ImmutableDenseMatrix) +def _eval_is_eq(lhs, rhs): # noqa:F811 + """Helper method for Equality with matrices.sympy. + + Relational automatically converts matrices to ImmutableDenseMatrix + instances, so this method only applies here. Returns True if the + matrices are definitively the same, False if they are definitively + different, and None if undetermined (e.g. if they contain Symbols). + Returning None triggers default handling of Equalities. + + """ + if lhs.shape != rhs.shape: + return False + return (lhs - rhs).is_zero_matrix diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/inverse.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/inverse.py new file mode 100644 index 0000000000000000000000000000000000000000..61d9e12edf013d2f5555d61786343aa3840edfd3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/inverse.py @@ -0,0 +1,524 @@ +from sympy.polys.matrices.exceptions import DMNonInvertibleMatrixError +from sympy.polys.domains import EX + +from .exceptions import MatrixError, NonSquareMatrixError, NonInvertibleMatrixError +from .utilities import _iszero + + +def _pinv_full_rank(M): + """Subroutine for full row or column rank matrices. + + For full row rank matrices, inverse of ``A * A.H`` Exists. + For full column rank matrices, inverse of ``A.H * A`` Exists. + + This routine can apply for both cases by checking the shape + and have small decision. + """ + + if M.is_zero_matrix: + return M.H + + if M.rows >= M.cols: + return M.H.multiply(M).inv().multiply(M.H) + else: + return M.H.multiply(M.multiply(M.H).inv()) + +def _pinv_rank_decomposition(M): + """Subroutine for rank decomposition + + With rank decompositions, `A` can be decomposed into two full- + rank matrices, and each matrix can take pseudoinverse + individually. + """ + + if M.is_zero_matrix: + return M.H + + B, C = M.rank_decomposition() + + Bp = _pinv_full_rank(B) + Cp = _pinv_full_rank(C) + + return Cp.multiply(Bp) + +def _pinv_diagonalization(M): + """Subroutine using diagonalization + + This routine can sometimes fail if SymPy's eigenvalue + computation is not reliable. + """ + + if M.is_zero_matrix: + return M.H + + A = M + AH = M.H + + try: + if M.rows >= M.cols: + P, D = AH.multiply(A).diagonalize(normalize=True) + D_pinv = D.applyfunc(lambda x: 0 if _iszero(x) else 1 / x) + + return P.multiply(D_pinv).multiply(P.H).multiply(AH) + + else: + P, D = A.multiply(AH).diagonalize( + normalize=True) + D_pinv = D.applyfunc(lambda x: 0 if _iszero(x) else 1 / x) + + return AH.multiply(P).multiply(D_pinv).multiply(P.H) + + except MatrixError: + raise NotImplementedError( + 'pinv for rank-deficient matrices where ' + 'diagonalization of A.H*A fails is not supported yet.') + +def _pinv(M, method='RD'): + """Calculate the Moore-Penrose pseudoinverse of the matrix. + + The Moore-Penrose pseudoinverse exists and is unique for any matrix. + If the matrix is invertible, the pseudoinverse is the same as the + inverse. + + Parameters + ========== + + method : String, optional + Specifies the method for computing the pseudoinverse. + + If ``'RD'``, Rank-Decomposition will be used. + + If ``'ED'``, Diagonalization will be used. + + Examples + ======== + + Computing pseudoinverse by rank decomposition : + + >>> from sympy import Matrix + >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> A.pinv() + Matrix([ + [-17/18, 4/9], + [ -1/9, 1/9], + [ 13/18, -2/9]]) + + Computing pseudoinverse by diagonalization : + + >>> B = A.pinv(method='ED') + >>> B.simplify() + >>> B + Matrix([ + [-17/18, 4/9], + [ -1/9, 1/9], + [ 13/18, -2/9]]) + + See Also + ======== + + inv + pinv_solve + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Moore-Penrose_pseudoinverse + + """ + + # Trivial case: pseudoinverse of all-zero matrix is its transpose. + if M.is_zero_matrix: + return M.H + + if method == 'RD': + return _pinv_rank_decomposition(M) + elif method == 'ED': + return _pinv_diagonalization(M) + else: + raise ValueError('invalid pinv method %s' % repr(method)) + + +def _verify_invertible(M, iszerofunc=_iszero): + """Initial check to see if a matrix is invertible. Raises or returns + determinant for use in _inv_ADJ.""" + + if not M.is_square: + raise NonSquareMatrixError("A Matrix must be square to invert.") + + d = M.det(method='berkowitz') + zero = d.equals(0) + + if zero is None: # if equals() can't decide, will rref be able to? + ok = M.rref(simplify=True)[0] + zero = any(iszerofunc(ok[j, j]) for j in range(ok.rows)) + + if zero: + raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") + + return d + +def _inv_ADJ(M, iszerofunc=_iszero): + """Calculates the inverse using the adjugate matrix and a determinant. + + See Also + ======== + + inv + inverse_GE + inverse_LU + inverse_CH + inverse_LDL + """ + + d = _verify_invertible(M, iszerofunc=iszerofunc) + + return M.adjugate() / d + +def _inv_GE(M, iszerofunc=_iszero): + """Calculates the inverse using Gaussian elimination. + + See Also + ======== + + inv + inverse_ADJ + inverse_LU + inverse_CH + inverse_LDL + """ + + from .dense import Matrix + + if not M.is_square: + raise NonSquareMatrixError("A Matrix must be square to invert.") + + big = Matrix.hstack(M.as_mutable(), Matrix.eye(M.rows)) + red = big.rref(iszerofunc=iszerofunc, simplify=True)[0] + + if any(iszerofunc(red[j, j]) for j in range(red.rows)): + raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") + + return M._new(red[:, big.rows:]) + +def _inv_LU(M, iszerofunc=_iszero): + """Calculates the inverse using LU decomposition. + + See Also + ======== + + inv + inverse_ADJ + inverse_GE + inverse_CH + inverse_LDL + """ + + if not M.is_square: + raise NonSquareMatrixError("A Matrix must be square to invert.") + if M.free_symbols: + _verify_invertible(M, iszerofunc=iszerofunc) + + return M.LUsolve(M.eye(M.rows), iszerofunc=_iszero) + +def _inv_CH(M, iszerofunc=_iszero): + """Calculates the inverse using cholesky decomposition. + + See Also + ======== + + inv + inverse_ADJ + inverse_GE + inverse_LU + inverse_LDL + """ + + _verify_invertible(M, iszerofunc=iszerofunc) + + return M.cholesky_solve(M.eye(M.rows)) + +def _inv_LDL(M, iszerofunc=_iszero): + """Calculates the inverse using LDL decomposition. + + See Also + ======== + + inv + inverse_ADJ + inverse_GE + inverse_LU + inverse_CH + """ + + _verify_invertible(M, iszerofunc=iszerofunc) + + return M.LDLsolve(M.eye(M.rows)) + +def _inv_QR(M, iszerofunc=_iszero): + """Calculates the inverse using QR decomposition. + + See Also + ======== + + inv + inverse_ADJ + inverse_GE + inverse_CH + inverse_LDL + """ + + _verify_invertible(M, iszerofunc=iszerofunc) + + return M.QRsolve(M.eye(M.rows)) + +def _try_DM(M, use_EX=False): + """Try to convert a matrix to a ``DomainMatrix``.""" + dM = M.to_DM() + K = dM.domain + + # Return DomainMatrix if a domain is found. Only use EX if use_EX=True. + if not use_EX and K.is_EXRAW: + return None + elif K.is_EXRAW: + return dM.convert_to(EX) + else: + return dM + + +def _use_exact_domain(dom): + """Check whether to convert to an exact domain.""" + # DomainMatrix can handle RR and CC with partial pivoting. Other inexact + # domains like RR[a,b,...] can only be handled by converting to an exact + # domain like QQ[a,b,...] + if dom.is_RR or dom.is_CC: + return False + else: + return not dom.is_Exact + + +def _inv_DM(dM, cancel=True): + """Calculates the inverse using ``DomainMatrix``. + + See Also + ======== + + inv + inverse_ADJ + inverse_GE + inverse_CH + inverse_LDL + sympy.polys.matrices.domainmatrix.DomainMatrix.inv + """ + m, n = dM.shape + dom = dM.domain + + if m != n: + raise NonSquareMatrixError("A Matrix must be square to invert.") + + # Convert RR[a,b,...] to QQ[a,b,...] + use_exact = _use_exact_domain(dom) + + if use_exact: + dom_exact = dom.get_exact() + dM = dM.convert_to(dom_exact) + + try: + dMi, den = dM.inv_den() + except DMNonInvertibleMatrixError: + raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") + + if use_exact: + dMi = dMi.convert_to(dom) + den = dom.convert_from(den, dom_exact) + + if cancel: + # Convert to field and cancel with the denominator. + if not dMi.domain.is_Field: + dMi = dMi.to_field() + Mi = (dMi / den).to_Matrix() + else: + # Convert to Matrix and divide without cancelling + Mi = dMi.to_Matrix() / dMi.domain.to_sympy(den) + + return Mi + +def _inv_block(M, iszerofunc=_iszero): + """Calculates the inverse using BLOCKWISE inversion. + + See Also + ======== + + inv + inverse_ADJ + inverse_GE + inverse_CH + inverse_LDL + """ + from sympy.matrices.expressions.blockmatrix import BlockMatrix + i = M.shape[0] + if i <= 20 : + return M.inv(method="LU", iszerofunc=_iszero) + A = M[:i // 2, :i //2] + B = M[:i // 2, i // 2:] + C = M[i // 2:, :i // 2] + D = M[i // 2:, i // 2:] + try: + D_inv = _inv_block(D) + except NonInvertibleMatrixError: + return M.inv(method="LU", iszerofunc=_iszero) + B_D_i = B*D_inv + BDC = B_D_i*C + A_n = A - BDC + try: + A_n = _inv_block(A_n) + except NonInvertibleMatrixError: + return M.inv(method="LU", iszerofunc=_iszero) + B_n = -A_n*B_D_i + dc = D_inv*C + C_n = -dc*A_n + D_n = D_inv + dc*-B_n + nn = BlockMatrix([[A_n, B_n], [C_n, D_n]]).as_explicit() + return nn + +def _inv(M, method=None, iszerofunc=_iszero, try_block_diag=False): + """ + Return the inverse of a matrix using the method indicated. The default + is DM if a suitable domain is found or otherwise GE for dense matrices + LDL for sparse matrices. + + Parameters + ========== + + method : ('DM', 'DMNC', 'GE', 'LU', 'ADJ', 'CH', 'LDL', 'QR') + + iszerofunc : function, optional + Zero-testing function to use. + + try_block_diag : bool, optional + If True then will try to form block diagonal matrices using the + method get_diag_blocks(), invert these individually, and then + reconstruct the full inverse matrix. + + Examples + ======== + + >>> from sympy import SparseMatrix, Matrix + >>> A = SparseMatrix([ + ... [ 2, -1, 0], + ... [-1, 2, -1], + ... [ 0, 0, 2]]) + >>> A.inv('CH') + Matrix([ + [2/3, 1/3, 1/6], + [1/3, 2/3, 1/3], + [ 0, 0, 1/2]]) + >>> A.inv(method='LDL') # use of 'method=' is optional + Matrix([ + [2/3, 1/3, 1/6], + [1/3, 2/3, 1/3], + [ 0, 0, 1/2]]) + >>> A * _ + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> A = Matrix(A) + >>> A.inv('CH') + Matrix([ + [2/3, 1/3, 1/6], + [1/3, 2/3, 1/3], + [ 0, 0, 1/2]]) + >>> A.inv('ADJ') == A.inv('GE') == A.inv('LU') == A.inv('CH') == A.inv('LDL') == A.inv('QR') + True + + Notes + ===== + + According to the ``method`` keyword, it calls the appropriate method: + + DM .... Use DomainMatrix ``inv_den`` method + DMNC .... Use DomainMatrix ``inv_den`` method without cancellation + GE .... inverse_GE(); default for dense matrices + LU .... inverse_LU() + ADJ ... inverse_ADJ() + CH ... inverse_CH() + LDL ... inverse_LDL(); default for sparse matrices + QR ... inverse_QR() + + Note, the GE and LU methods may require the matrix to be simplified + before it is inverted in order to properly detect zeros during + pivoting. In difficult cases a custom zero detection function can + be provided by setting the ``iszerofunc`` argument to a function that + should return True if its argument is zero. The ADJ routine computes + the determinant and uses that to detect singular matrices in addition + to testing for zeros on the diagonal. + + See Also + ======== + + inverse_ADJ + inverse_GE + inverse_LU + inverse_CH + inverse_LDL + + Raises + ====== + + ValueError + If the determinant of the matrix is zero. + """ + + from sympy.matrices import diag, SparseMatrix + + if not M.is_square: + raise NonSquareMatrixError("A Matrix must be square to invert.") + + if try_block_diag: + blocks = M.get_diag_blocks() + r = [] + + for block in blocks: + r.append(block.inv(method=method, iszerofunc=iszerofunc)) + + return diag(*r) + + # Default: Use DomainMatrix if the domain is not EX. + # If DM is requested explicitly then use it even if the domain is EX. + if method is None and iszerofunc is _iszero: + dM = _try_DM(M, use_EX=False) + if dM is not None: + method = 'DM' + elif method in ("DM", "DMNC"): + dM = _try_DM(M, use_EX=True) + + # A suitable domain was not found, fall back to GE for dense matrices + # and LDL for sparse matrices. + if method is None: + if isinstance(M, SparseMatrix): + method = 'LDL' + else: + method = 'GE' + + if method == "DM": + rv = _inv_DM(dM) + elif method == "DMNC": + rv = _inv_DM(dM, cancel=False) + elif method == "GE": + rv = M.inverse_GE(iszerofunc=iszerofunc) + elif method == "LU": + rv = M.inverse_LU(iszerofunc=iszerofunc) + elif method == "ADJ": + rv = M.inverse_ADJ(iszerofunc=iszerofunc) + elif method == "CH": + rv = M.inverse_CH(iszerofunc=iszerofunc) + elif method == "LDL": + rv = M.inverse_LDL(iszerofunc=iszerofunc) + elif method == "QR": + rv = M.inverse_QR(iszerofunc=iszerofunc) + elif method == "BLOCK": + rv = M.inverse_BLOCK(iszerofunc=iszerofunc) + else: + raise ValueError("Inversion method unrecognized") + + return M._new(rv) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/kind.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/kind.py new file mode 100644 index 0000000000000000000000000000000000000000..f9f53ffe16f7cbde60213e49071a2a74e80e5c6c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/kind.py @@ -0,0 +1,97 @@ +# sympy.matrices.kind + +from sympy.core.kind import Kind, _NumberKind, NumberKind +from sympy.core.mul import Mul + + +class MatrixKind(Kind): + """ + Kind for all matrices in SymPy. + + Basic class for this kind is ``MatrixBase`` and ``MatrixExpr``, + but any expression representing the matrix can have this. + + Parameters + ========== + + element_kind : Kind + Kind of the element. Default is + :class:`sympy.core.kind.NumberKind`, + which means that the matrix contains only numbers. + + Examples + ======== + + Any instance of matrix class has kind ``MatrixKind``: + + >>> from sympy import MatrixSymbol + >>> A = MatrixSymbol('A', 2, 2) + >>> A.kind + MatrixKind(NumberKind) + + An expression representing a matrix may not be an instance of + the Matrix class, but it will have kind ``MatrixKind``: + + >>> from sympy import MatrixExpr, Integral + >>> from sympy.abc import x + >>> intM = Integral(A, x) + >>> isinstance(intM, MatrixExpr) + False + >>> intM.kind + MatrixKind(NumberKind) + + Use ``isinstance()`` to check for ``MatrixKind`` without specifying the + element kind. Use ``is`` to check the kind including the element kind: + + >>> from sympy import Matrix + >>> from sympy.core import NumberKind + >>> from sympy.matrices import MatrixKind + >>> M = Matrix([1, 2]) + >>> isinstance(M.kind, MatrixKind) + True + >>> M.kind is MatrixKind(NumberKind) + True + + See Also + ======== + + sympy.core.kind.NumberKind + sympy.core.kind.UndefinedKind + sympy.core.containers.TupleKind + sympy.sets.sets.SetKind + + """ + def __new__(cls, element_kind=NumberKind): + obj = super().__new__(cls, element_kind) + obj.element_kind = element_kind + return obj + + def __repr__(self): + return "MatrixKind(%s)" % self.element_kind + + +@Mul._kind_dispatcher.register(_NumberKind, MatrixKind) +def num_mat_mul(k1, k2): + """ + Return MatrixKind. The element kind is selected by recursive dispatching. + Do not need to dispatch in reversed order because KindDispatcher + searches for this automatically. + """ + # Deal with Mul._kind_dispatcher's commutativity + # XXX: this function is called with either k1 or k2 as MatrixKind because + # the Mul kind dispatcher is commutative. Maybe it shouldn't be. Need to + # swap the args here because NumberKind does not have an element_kind + # attribute. + if not isinstance(k2, MatrixKind): + k1, k2 = k2, k1 + elemk = Mul._kind_dispatcher(k1, k2.element_kind) + return MatrixKind(elemk) + + +@Mul._kind_dispatcher.register(MatrixKind, MatrixKind) +def mat_mat_mul(k1, k2): + """ + Return MatrixKind. The element kind is selected by recursive dispatching. + """ + elemk = Mul._kind_dispatcher(k1.element_kind, k2.element_kind) + return MatrixKind(elemk) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/matrices.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/matrices.py new file mode 100644 index 0000000000000000000000000000000000000000..fed41a626cb395ac0529071317630d853e0d3a96 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/matrices.py @@ -0,0 +1,687 @@ +# +# A module consisting of deprecated matrix classes. New code should not be +# added here. +# +from sympy.core.basic import Basic +from sympy.core.symbol import Dummy + +from .common import MatrixCommon + +from .exceptions import NonSquareMatrixError + +from .utilities import _iszero, _is_zero_after_expand_mul, _simplify + +from .determinant import ( + _find_reasonable_pivot, _find_reasonable_pivot_naive, + _adjugate, _charpoly, _cofactor, _cofactor_matrix, _per, + _det, _det_bareiss, _det_berkowitz, _det_bird, _det_laplace, _det_LU, + _minor, _minor_submatrix) + +from .reductions import _is_echelon, _echelon_form, _rank, _rref +from .subspaces import _columnspace, _nullspace, _rowspace, _orthogonalize + +from .eigen import ( + _eigenvals, _eigenvects, + _bidiagonalize, _bidiagonal_decomposition, + _is_diagonalizable, _diagonalize, + _is_positive_definite, _is_positive_semidefinite, + _is_negative_definite, _is_negative_semidefinite, _is_indefinite, + _jordan_form, _left_eigenvects, _singular_values) + + +# This class was previously defined in this module, but was moved to +# sympy.matrices.matrixbase. We import it here for backwards compatibility in +# case someone was importing it from here. +from .matrixbase import MatrixBase + + +__doctest_requires__ = { + ('MatrixEigen.is_indefinite', + 'MatrixEigen.is_negative_definite', + 'MatrixEigen.is_negative_semidefinite', + 'MatrixEigen.is_positive_definite', + 'MatrixEigen.is_positive_semidefinite'): ['matplotlib'], +} + + +class MatrixDeterminant(MatrixCommon): + """Provides basic matrix determinant operations. Should not be instantiated + directly. See ``determinant.py`` for their implementations.""" + + def _eval_det_bareiss(self, iszerofunc=_is_zero_after_expand_mul): + return _det_bareiss(self, iszerofunc=iszerofunc) + + def _eval_det_berkowitz(self): + return _det_berkowitz(self) + + def _eval_det_lu(self, iszerofunc=_iszero, simpfunc=None): + return _det_LU(self, iszerofunc=iszerofunc, simpfunc=simpfunc) + + def _eval_det_bird(self): + return _det_bird(self) + + def _eval_det_laplace(self): + return _det_laplace(self) + + def _eval_determinant(self): # for expressions.determinant.Determinant + return _det(self) + + def adjugate(self, method="berkowitz"): + return _adjugate(self, method=method) + + def charpoly(self, x='lambda', simplify=_simplify): + return _charpoly(self, x=x, simplify=simplify) + + def cofactor(self, i, j, method="berkowitz"): + return _cofactor(self, i, j, method=method) + + def cofactor_matrix(self, method="berkowitz"): + return _cofactor_matrix(self, method=method) + + def det(self, method="bareiss", iszerofunc=None): + return _det(self, method=method, iszerofunc=iszerofunc) + + def per(self): + return _per(self) + + def minor(self, i, j, method="berkowitz"): + return _minor(self, i, j, method=method) + + def minor_submatrix(self, i, j): + return _minor_submatrix(self, i, j) + + _find_reasonable_pivot.__doc__ = _find_reasonable_pivot.__doc__ + _find_reasonable_pivot_naive.__doc__ = _find_reasonable_pivot_naive.__doc__ + _eval_det_bareiss.__doc__ = _det_bareiss.__doc__ + _eval_det_berkowitz.__doc__ = _det_berkowitz.__doc__ + _eval_det_bird.__doc__ = _det_bird.__doc__ + _eval_det_laplace.__doc__ = _det_laplace.__doc__ + _eval_det_lu.__doc__ = _det_LU.__doc__ + _eval_determinant.__doc__ = _det.__doc__ + adjugate.__doc__ = _adjugate.__doc__ + charpoly.__doc__ = _charpoly.__doc__ + cofactor.__doc__ = _cofactor.__doc__ + cofactor_matrix.__doc__ = _cofactor_matrix.__doc__ + det.__doc__ = _det.__doc__ + per.__doc__ = _per.__doc__ + minor.__doc__ = _minor.__doc__ + minor_submatrix.__doc__ = _minor_submatrix.__doc__ + + +class MatrixReductions(MatrixDeterminant): + """Provides basic matrix row/column operations. Should not be instantiated + directly. See ``reductions.py`` for some of their implementations.""" + + def echelon_form(self, iszerofunc=_iszero, simplify=False, with_pivots=False): + return _echelon_form(self, iszerofunc=iszerofunc, simplify=simplify, + with_pivots=with_pivots) + + @property + def is_echelon(self): + return _is_echelon(self) + + def rank(self, iszerofunc=_iszero, simplify=False): + return _rank(self, iszerofunc=iszerofunc, simplify=simplify) + + def rref_rhs(self, rhs): + """Return reduced row-echelon form of matrix, matrix showing + rhs after reduction steps. ``rhs`` must have the same number + of rows as ``self``. + + Examples + ======== + + >>> from sympy import Matrix, symbols + >>> r1, r2 = symbols('r1 r2') + >>> Matrix([[1, 1], [2, 1]]).rref_rhs(Matrix([r1, r2])) + (Matrix([ + [1, 0], + [0, 1]]), Matrix([ + [ -r1 + r2], + [2*r1 - r2]])) + """ + r, _ = _rref(self.hstack(self, self.eye(self.rows), rhs)) + return r[:, :self.cols], r[:, -rhs.cols:] + + def rref(self, iszerofunc=_iszero, simplify=False, pivots=True, + normalize_last=True): + return _rref(self, iszerofunc=iszerofunc, simplify=simplify, + pivots=pivots, normalize_last=normalize_last) + + echelon_form.__doc__ = _echelon_form.__doc__ + is_echelon.__doc__ = _is_echelon.__doc__ + rank.__doc__ = _rank.__doc__ + rref.__doc__ = _rref.__doc__ + + def _normalize_op_args(self, op, col, k, col1, col2, error_str="col"): + """Validate the arguments for a row/column operation. ``error_str`` + can be one of "row" or "col" depending on the arguments being parsed.""" + if op not in ["n->kn", "n<->m", "n->n+km"]: + raise ValueError("Unknown {} operation '{}'. Valid col operations " + "are 'n->kn', 'n<->m', 'n->n+km'".format(error_str, op)) + + # define self_col according to error_str + self_cols = self.cols if error_str == 'col' else self.rows + + # normalize and validate the arguments + if op == "n->kn": + col = col if col is not None else col1 + if col is None or k is None: + raise ValueError("For a {0} operation 'n->kn' you must provide the " + "kwargs `{0}` and `k`".format(error_str)) + if not 0 <= col < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col)) + + elif op == "n<->m": + # we need two cols to swap. It does not matter + # how they were specified, so gather them together and + # remove `None` + cols = {col, k, col1, col2}.difference([None]) + if len(cols) > 2: + # maybe the user left `k` by mistake? + cols = {col, col1, col2}.difference([None]) + if len(cols) != 2: + raise ValueError("For a {0} operation 'n<->m' you must provide the " + "kwargs `{0}1` and `{0}2`".format(error_str)) + col1, col2 = cols + if not 0 <= col1 < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col1)) + if not 0 <= col2 < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col2)) + + elif op == "n->n+km": + col = col1 if col is None else col + col2 = col1 if col2 is None else col2 + if col is None or col2 is None or k is None: + raise ValueError("For a {0} operation 'n->n+km' you must provide the " + "kwargs `{0}`, `k`, and `{0}2`".format(error_str)) + if col == col2: + raise ValueError("For a {0} operation 'n->n+km' `{0}` and `{0}2` must " + "be different.".format(error_str)) + if not 0 <= col < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col)) + if not 0 <= col2 < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col2)) + + else: + raise ValueError('invalid operation %s' % repr(op)) + + return op, col, k, col1, col2 + + def _eval_col_op_multiply_col_by_const(self, col, k): + def entry(i, j): + if j == col: + return k * self[i, j] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_col_op_swap(self, col1, col2): + def entry(i, j): + if j == col1: + return self[i, col2] + elif j == col2: + return self[i, col1] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_col_op_add_multiple_to_other_col(self, col, k, col2): + def entry(i, j): + if j == col: + return self[i, j] + k * self[i, col2] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_row_op_swap(self, row1, row2): + def entry(i, j): + if i == row1: + return self[row2, j] + elif i == row2: + return self[row1, j] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_row_op_multiply_row_by_const(self, row, k): + def entry(i, j): + if i == row: + return k * self[i, j] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_row_op_add_multiple_to_other_row(self, row, k, row2): + def entry(i, j): + if i == row: + return self[i, j] + k * self[row2, j] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def elementary_col_op(self, op="n->kn", col=None, k=None, col1=None, col2=None): + """Performs the elementary column operation `op`. + + `op` may be one of + + * ``"n->kn"`` (column n goes to k*n) + * ``"n<->m"`` (swap column n and column m) + * ``"n->n+km"`` (column n goes to column n + k*column m) + + Parameters + ========== + + op : string; the elementary row operation + col : the column to apply the column operation + k : the multiple to apply in the column operation + col1 : one column of a column swap + col2 : second column of a column swap or column "m" in the column operation + "n->n+km" + """ + + op, col, k, col1, col2 = self._normalize_op_args(op, col, k, col1, col2, "col") + + # now that we've validated, we're all good to dispatch + if op == "n->kn": + return self._eval_col_op_multiply_col_by_const(col, k) + if op == "n<->m": + return self._eval_col_op_swap(col1, col2) + if op == "n->n+km": + return self._eval_col_op_add_multiple_to_other_col(col, k, col2) + + def elementary_row_op(self, op="n->kn", row=None, k=None, row1=None, row2=None): + """Performs the elementary row operation `op`. + + `op` may be one of + + * ``"n->kn"`` (row n goes to k*n) + * ``"n<->m"`` (swap row n and row m) + * ``"n->n+km"`` (row n goes to row n + k*row m) + + Parameters + ========== + + op : string; the elementary row operation + row : the row to apply the row operation + k : the multiple to apply in the row operation + row1 : one row of a row swap + row2 : second row of a row swap or row "m" in the row operation + "n->n+km" + """ + + op, row, k, row1, row2 = self._normalize_op_args(op, row, k, row1, row2, "row") + + # now that we've validated, we're all good to dispatch + if op == "n->kn": + return self._eval_row_op_multiply_row_by_const(row, k) + if op == "n<->m": + return self._eval_row_op_swap(row1, row2) + if op == "n->n+km": + return self._eval_row_op_add_multiple_to_other_row(row, k, row2) + + +class MatrixSubspaces(MatrixReductions): + """Provides methods relating to the fundamental subspaces of a matrix. + Should not be instantiated directly. See ``subspaces.py`` for their + implementations.""" + + def columnspace(self, simplify=False): + return _columnspace(self, simplify=simplify) + + def nullspace(self, simplify=False, iszerofunc=_iszero): + return _nullspace(self, simplify=simplify, iszerofunc=iszerofunc) + + def rowspace(self, simplify=False): + return _rowspace(self, simplify=simplify) + + # This is a classmethod but is converted to such later in order to allow + # assignment of __doc__ since that does not work for already wrapped + # classmethods in Python 3.6. + def orthogonalize(cls, *vecs, **kwargs): + return _orthogonalize(cls, *vecs, **kwargs) + + columnspace.__doc__ = _columnspace.__doc__ + nullspace.__doc__ = _nullspace.__doc__ + rowspace.__doc__ = _rowspace.__doc__ + orthogonalize.__doc__ = _orthogonalize.__doc__ + + orthogonalize = classmethod(orthogonalize) # type:ignore + + +class MatrixEigen(MatrixSubspaces): + """Provides basic matrix eigenvalue/vector operations. + Should not be instantiated directly. See ``eigen.py`` for their + implementations.""" + + def eigenvals(self, error_when_incomplete=True, **flags): + return _eigenvals(self, error_when_incomplete=error_when_incomplete, **flags) + + def eigenvects(self, error_when_incomplete=True, iszerofunc=_iszero, **flags): + return _eigenvects(self, error_when_incomplete=error_when_incomplete, + iszerofunc=iszerofunc, **flags) + + def is_diagonalizable(self, reals_only=False, **kwargs): + return _is_diagonalizable(self, reals_only=reals_only, **kwargs) + + def diagonalize(self, reals_only=False, sort=False, normalize=False): + return _diagonalize(self, reals_only=reals_only, sort=sort, + normalize=normalize) + + def bidiagonalize(self, upper=True): + return _bidiagonalize(self, upper=upper) + + def bidiagonal_decomposition(self, upper=True): + return _bidiagonal_decomposition(self, upper=upper) + + @property + def is_positive_definite(self): + return _is_positive_definite(self) + + @property + def is_positive_semidefinite(self): + return _is_positive_semidefinite(self) + + @property + def is_negative_definite(self): + return _is_negative_definite(self) + + @property + def is_negative_semidefinite(self): + return _is_negative_semidefinite(self) + + @property + def is_indefinite(self): + return _is_indefinite(self) + + def jordan_form(self, calc_transform=True, **kwargs): + return _jordan_form(self, calc_transform=calc_transform, **kwargs) + + def left_eigenvects(self, **flags): + return _left_eigenvects(self, **flags) + + def singular_values(self): + return _singular_values(self) + + eigenvals.__doc__ = _eigenvals.__doc__ + eigenvects.__doc__ = _eigenvects.__doc__ + is_diagonalizable.__doc__ = _is_diagonalizable.__doc__ + diagonalize.__doc__ = _diagonalize.__doc__ + is_positive_definite.__doc__ = _is_positive_definite.__doc__ + is_positive_semidefinite.__doc__ = _is_positive_semidefinite.__doc__ + is_negative_definite.__doc__ = _is_negative_definite.__doc__ + is_negative_semidefinite.__doc__ = _is_negative_semidefinite.__doc__ + is_indefinite.__doc__ = _is_indefinite.__doc__ + jordan_form.__doc__ = _jordan_form.__doc__ + left_eigenvects.__doc__ = _left_eigenvects.__doc__ + singular_values.__doc__ = _singular_values.__doc__ + bidiagonalize.__doc__ = _bidiagonalize.__doc__ + bidiagonal_decomposition.__doc__ = _bidiagonal_decomposition.__doc__ + + +class MatrixCalculus(MatrixCommon): + """Provides calculus-related matrix operations.""" + + def diff(self, *args, evaluate=True, **kwargs): + """Calculate the derivative of each element in the matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.diff(x) + Matrix([ + [1, 0], + [0, 0]]) + + See Also + ======== + + integrate + limit + """ + # XXX this should be handled here rather than in Derivative + from sympy.tensor.array.array_derivatives import ArrayDerivative + deriv = ArrayDerivative(self, *args, evaluate=evaluate) + # XXX This can rather changed to always return immutable matrix + if not isinstance(self, Basic) and evaluate: + return deriv.as_mutable() + return deriv + + def _eval_derivative(self, arg): + return self.applyfunc(lambda x: x.diff(arg)) + + def integrate(self, *args, **kwargs): + """Integrate each element of the matrix. ``args`` will + be passed to the ``integrate`` function. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.integrate((x, )) + Matrix([ + [x**2/2, x*y], + [ x, 0]]) + >>> M.integrate((x, 0, 2)) + Matrix([ + [2, 2*y], + [2, 0]]) + + See Also + ======== + + limit + diff + """ + return self.applyfunc(lambda x: x.integrate(*args, **kwargs)) + + def jacobian(self, X): + """Calculates the Jacobian matrix (derivative of a vector-valued function). + + Parameters + ========== + + ``self`` : vector of expressions representing functions f_i(x_1, ..., x_n). + X : set of x_i's in order, it can be a list or a Matrix + + Both ``self`` and X can be a row or a column matrix in any order + (i.e., jacobian() should always work). + + Examples + ======== + + >>> from sympy import sin, cos, Matrix + >>> from sympy.abc import rho, phi + >>> X = Matrix([rho*cos(phi), rho*sin(phi), rho**2]) + >>> Y = Matrix([rho, phi]) + >>> X.jacobian(Y) + Matrix([ + [cos(phi), -rho*sin(phi)], + [sin(phi), rho*cos(phi)], + [ 2*rho, 0]]) + >>> X = Matrix([rho*cos(phi), rho*sin(phi)]) + >>> X.jacobian(Y) + Matrix([ + [cos(phi), -rho*sin(phi)], + [sin(phi), rho*cos(phi)]]) + + See Also + ======== + + hessian + wronskian + """ + if not isinstance(X, MatrixBase): + X = self._new(X) + # Both X and ``self`` can be a row or a column matrix, so we need to make + # sure all valid combinations work, but everything else fails: + if self.shape[0] == 1: + m = self.shape[1] + elif self.shape[1] == 1: + m = self.shape[0] + else: + raise TypeError("``self`` must be a row or a column matrix") + if X.shape[0] == 1: + n = X.shape[1] + elif X.shape[1] == 1: + n = X.shape[0] + else: + raise TypeError("X must be a row or a column matrix") + + # m is the number of functions and n is the number of variables + # computing the Jacobian is now easy: + return self._new(m, n, lambda j, i: self[j].diff(X[i])) + + def limit(self, *args): + """Calculate the limit of each element in the matrix. + ``args`` will be passed to the ``limit`` function. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.limit(x, 2) + Matrix([ + [2, y], + [1, 0]]) + + See Also + ======== + + integrate + diff + """ + return self.applyfunc(lambda x: x.limit(*args)) + + +# https://github.com/sympy/sympy/pull/12854 +class MatrixDeprecated(MatrixCommon): + """A class to house deprecated matrix methods.""" + def berkowitz_charpoly(self, x=Dummy('lambda'), simplify=_simplify): + return self.charpoly(x=x) + + def berkowitz_det(self): + """Computes determinant using Berkowitz method. + + See Also + ======== + + det + berkowitz + """ + return self.det(method='berkowitz') + + def berkowitz_eigenvals(self, **flags): + """Computes eigenvalues of a Matrix using Berkowitz method. + + See Also + ======== + + berkowitz + """ + return self.eigenvals(**flags) + + def berkowitz_minors(self): + """Computes principal minors using Berkowitz method. + + See Also + ======== + + berkowitz + """ + sign, minors = self.one, [] + + for poly in self.berkowitz(): + minors.append(sign * poly[-1]) + sign = -sign + + return tuple(minors) + + def berkowitz(self): + from sympy.matrices import zeros + berk = ((1,),) + if not self: + return berk + + if not self.is_square: + raise NonSquareMatrixError() + + A, N = self, self.rows + transforms = [0] * (N - 1) + + for n in range(N, 1, -1): + T, k = zeros(n + 1, n), n - 1 + + R, C = -A[k, :k], A[:k, k] + A, a = A[:k, :k], -A[k, k] + + items = [C] + + for i in range(0, n - 2): + items.append(A * items[i]) + + for i, B in enumerate(items): + items[i] = (R * B)[0, 0] + + items = [self.one, a] + items + + for i in range(n): + T[i:, i] = items[:n - i + 1] + + transforms[k - 1] = T + + polys = [self._new([self.one, -A[0, 0]])] + + for i, T in enumerate(transforms): + polys.append(T * polys[i]) + + return berk + tuple(map(tuple, polys)) + + def cofactorMatrix(self, method="berkowitz"): + return self.cofactor_matrix(method=method) + + def det_bareis(self): + return _det_bareiss(self) + + def det_LU_decomposition(self): + """Compute matrix determinant using LU decomposition. + + + Note that this method fails if the LU decomposition itself + fails. In particular, if the matrix has no inverse this method + will fail. + + TODO: Implement algorithm for sparse matrices (SFF), + https://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps + + See Also + ======== + + + det + det_bareiss + berkowitz_det + """ + return self.det(method='lu') + + def jordan_cell(self, eigenval, n): + return self.jordan_block(size=n, eigenvalue=eigenval) + + def jordan_cells(self, calc_transformation=True): + P, J = self.jordan_form() + return P, J.get_diag_blocks() + + def minorEntry(self, i, j, method="berkowitz"): + return self.minor(i, j, method=method) + + def minorMatrix(self, i, j): + return self.minor_submatrix(i, j) + + def permuteBkwd(self, perm): + """Permute the rows of the matrix with the given permutation in reverse.""" + return self.permute_rows(perm, direction='backward') + + def permuteFwd(self, perm): + """Permute the rows of the matrix with the given permutation.""" + return self.permute_rows(perm, direction='forward') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/matrixbase.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/matrixbase.py new file mode 100644 index 0000000000000000000000000000000000000000..49acc04043b30e003f7eed256f2e06e6a6556401 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/matrixbase.py @@ -0,0 +1,5428 @@ +from __future__ import annotations +from collections import defaultdict +from collections.abc import Iterable +from inspect import isfunction +from functools import reduce + +from sympy.assumptions.refine import refine +from sympy.core import SympifyError, Add +from sympy.core.basic import Atom, Basic +from sympy.core.kind import UndefinedKind +from sympy.core.numbers import Integer +from sympy.core.mod import Mod +from sympy.core.symbol import Symbol, Dummy +from sympy.core.sympify import sympify, _sympify +from sympy.core.function import diff +from sympy.polys import cancel +from sympy.functions.elementary.complexes import Abs, re, im +from sympy.printing import sstr +from sympy.functions.elementary.miscellaneous import Max, Min, sqrt +from sympy.functions.special.tensor_functions import KroneckerDelta, LeviCivita +from sympy.core.singleton import S +from sympy.printing.defaults import Printable +from sympy.printing.str import StrPrinter +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.combinatorial.factorials import binomial, factorial + +import mpmath as mp +from collections.abc import Callable +from sympy.utilities.iterables import reshape +from sympy.core.expr import Expr +from sympy.core.power import Pow +from sympy.core.symbol import uniquely_named_symbol + +from .utilities import _dotprodsimp, _simplify as _utilities_simplify +from sympy.polys.polytools import Poly +from sympy.utilities.iterables import flatten, is_sequence +from sympy.utilities.misc import as_int, filldedent +from sympy.core.decorators import call_highest_priority +from sympy.core.logic import fuzzy_and, FuzzyBool +from sympy.tensor.array import NDimArray +from sympy.utilities.iterables import NotIterable + +from .utilities import _get_intermediate_simp_bool + +from .kind import MatrixKind + +from .exceptions import ( + MatrixError, ShapeError, NonSquareMatrixError, NonInvertibleMatrixError, +) + +from .utilities import _iszero, _is_zero_after_expand_mul + +from .determinant import ( + _find_reasonable_pivot, _find_reasonable_pivot_naive, + _adjugate, _charpoly, _cofactor, _cofactor_matrix, _per, + _det, _det_bareiss, _det_berkowitz, _det_bird, _det_laplace, _det_LU, + _minor, _minor_submatrix) + +from .reductions import _is_echelon, _echelon_form, _rank, _rref + +from .solvers import ( + _diagonal_solve, _lower_triangular_solve, _upper_triangular_solve, + _cholesky_solve, _LDLsolve, _LUsolve, _QRsolve, _gauss_jordan_solve, + _pinv_solve, _cramer_solve, _solve, _solve_least_squares) + +from .inverse import ( + _pinv, _inv_ADJ, _inv_GE, _inv_LU, _inv_CH, _inv_LDL, _inv_QR, + _inv, _inv_block) + +from .subspaces import _columnspace, _nullspace, _rowspace, _orthogonalize + +from .eigen import ( + _eigenvals, _eigenvects, + _bidiagonalize, _bidiagonal_decomposition, + _is_diagonalizable, _diagonalize, + _is_positive_definite, _is_positive_semidefinite, + _is_negative_definite, _is_negative_semidefinite, _is_indefinite, + _jordan_form, _left_eigenvects, _singular_values) + +from .decompositions import ( + _rank_decomposition, _cholesky, _LDLdecomposition, + _LUdecomposition, _LUdecomposition_Simple, _LUdecompositionFF, + _singular_value_decomposition, _QRdecomposition, _upper_hessenberg_decomposition) + +from .graph import ( + _connected_components, _connected_components_decomposition, + _strongly_connected_components, _strongly_connected_components_decomposition) + + +__doctest_requires__ = { + ('MatrixBase.is_indefinite', + 'MatrixBase.is_positive_definite', + 'MatrixBase.is_positive_semidefinite', + 'MatrixBase.is_negative_definite', + 'MatrixBase.is_negative_semidefinite'): ['matplotlib'], +} + + +class MatrixBase(Printable): + """All common matrix operations including basic arithmetic, shaping, + and special matrices like `zeros`, and `eye`.""" + + _op_priority = 10.01 + + # Added just for numpy compatibility + __array_priority__ = 11 + + is_Matrix = True + _class_priority = 3 + _sympify = staticmethod(sympify) + zero = S.Zero + one = S.One + + _diff_wrt: bool = True + rows: int + cols: int + _simplify = None + + @classmethod + def _new(cls, *args, **kwargs): + """`_new` must, at minimum, be callable as + `_new(rows, cols, mat) where mat is a flat list of the + elements of the matrix.""" + raise NotImplementedError("Subclasses must implement this.") + + def __eq__(self, other): + raise NotImplementedError("Subclasses must implement this.") + + def __getitem__(self, key): + """Implementations of __getitem__ should accept ints, in which + case the matrix is indexed as a flat list, tuples (i,j) in which + case the (i,j) entry is returned, slices, or mixed tuples (a,b) + where a and b are any combination of slices and integers.""" + raise NotImplementedError("Subclasses must implement this.") + + @property + def shape(self): + """The shape (dimensions) of the matrix as the 2-tuple (rows, cols). + + Examples + ======== + + >>> from sympy import zeros + >>> M = zeros(2, 3) + >>> M.shape + (2, 3) + >>> M.rows + 2 + >>> M.cols + 3 + """ + return (self.rows, self.cols) + + def _eval_col_del(self, col): + def entry(i, j): + return self[i, j] if j < col else self[i, j + 1] + return self._new(self.rows, self.cols - 1, entry) + + def _eval_col_insert(self, pos, other): + + def entry(i, j): + if j < pos: + return self[i, j] + elif pos <= j < pos + other.cols: + return other[i, j - pos] + return self[i, j - other.cols] + + return self._new(self.rows, self.cols + other.cols, entry) + + def _eval_col_join(self, other): + rows = self.rows + + def entry(i, j): + if i < rows: + return self[i, j] + return other[i - rows, j] + + return classof(self, other)._new(self.rows + other.rows, self.cols, + entry) + + def _eval_extract(self, rowsList, colsList): + mat = list(self) + cols = self.cols + indices = (i * cols + j for i in rowsList for j in colsList) + return self._new(len(rowsList), len(colsList), + [mat[i] for i in indices]) + + def _eval_get_diag_blocks(self): + sub_blocks = [] + + def recurse_sub_blocks(M): + for i in range(1, M.shape[0] + 1): + if i == 1: + to_the_right = M[0, i:] + to_the_bottom = M[i:, 0] + else: + to_the_right = M[:i, i:] + to_the_bottom = M[i:, :i] + if any(to_the_right) or any(to_the_bottom): + continue + sub_blocks.append(M[:i, :i]) + if M.shape != M[:i, :i].shape: + recurse_sub_blocks(M[i:, i:]) + return + + recurse_sub_blocks(self) + return sub_blocks + + def _eval_row_del(self, row): + def entry(i, j): + return self[i, j] if i < row else self[i + 1, j] + return self._new(self.rows - 1, self.cols, entry) + + def _eval_row_insert(self, pos, other): + entries = list(self) + insert_pos = pos * self.cols + entries[insert_pos:insert_pos] = list(other) + return self._new(self.rows + other.rows, self.cols, entries) + + def _eval_row_join(self, other): + cols = self.cols + + def entry(i, j): + if j < cols: + return self[i, j] + return other[i, j - cols] + + return classof(self, other)._new(self.rows, self.cols + other.cols, + entry) + + def _eval_tolist(self): + return [list(self[i,:]) for i in range(self.rows)] + + def _eval_todok(self): + dok = {} + rows, cols = self.shape + for i in range(rows): + for j in range(cols): + val = self[i, j] + if val != self.zero: + dok[i, j] = val + return dok + + @classmethod + def _eval_from_dok(cls, rows, cols, dok): + out_flat = [cls.zero] * (rows * cols) + for (i, j), val in dok.items(): + out_flat[i * cols + j] = val + return cls._new(rows, cols, out_flat) + + def _eval_vec(self): + rows = self.rows + + def entry(n, _): + # we want to read off the columns first + j = n // rows + i = n - j * rows + return self[i, j] + + return self._new(len(self), 1, entry) + + def _eval_vech(self, diagonal): + c = self.cols + v = [] + if diagonal: + for j in range(c): + for i in range(j, c): + v.append(self[i, j]) + else: + for j in range(c): + for i in range(j + 1, c): + v.append(self[i, j]) + return self._new(len(v), 1, v) + + def col_del(self, col): + """Delete the specified column.""" + if col < 0: + col += self.cols + if not 0 <= col < self.cols: + raise IndexError("Column {} is out of range.".format(col)) + return self._eval_col_del(col) + + def col_insert(self, pos, other): + """Insert one or more columns at the given column position. + + Examples + ======== + + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(3, 1) + >>> M.col_insert(1, V) + Matrix([ + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0]]) + + See Also + ======== + + col + row_insert + """ + # Allows you to build a matrix even if it is null matrix + if not self: + return type(self)(other) + + pos = as_int(pos) + + if pos < 0: + pos = self.cols + pos + if pos < 0: + pos = 0 + elif pos > self.cols: + pos = self.cols + + if self.rows != other.rows: + raise ShapeError( + "The matrices have incompatible number of rows ({} and {})" + .format(self.rows, other.rows)) + + return self._eval_col_insert(pos, other) + + def col_join(self, other): + """Concatenates two matrices along self's last and other's first row. + + Examples + ======== + + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(1, 3) + >>> M.col_join(V) + Matrix([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [1, 1, 1]]) + + See Also + ======== + + col + row_join + """ + # A null matrix can always be stacked (see #10770) + if self.rows == 0 and self.cols != other.cols: + return self._new(0, other.cols, []).col_join(other) + + if self.cols != other.cols: + raise ShapeError( + "The matrices have incompatible number of columns ({} and {})" + .format(self.cols, other.cols)) + return self._eval_col_join(other) + + def col(self, j): + """Elementary column selector. + + Examples + ======== + + >>> from sympy import eye + >>> eye(2).col(0) + Matrix([ + [1], + [0]]) + + See Also + ======== + + row + col_del + col_join + col_insert + """ + return self[:, j] + + def extract(self, rowsList, colsList): + r"""Return a submatrix by specifying a list of rows and columns. + Negative indices can be given. All indices must be in the range + $-n \le i < n$ where $n$ is the number of rows or columns. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(4, 3, range(12)) + >>> m + Matrix([ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [9, 10, 11]]) + >>> m.extract([0, 1, 3], [0, 1]) + Matrix([ + [0, 1], + [3, 4], + [9, 10]]) + + Rows or columns can be repeated: + + >>> m.extract([0, 0, 1], [-1]) + Matrix([ + [2], + [2], + [5]]) + + Every other row can be taken by using range to provide the indices: + + >>> m.extract(range(0, m.rows, 2), [-1]) + Matrix([ + [2], + [8]]) + + RowsList or colsList can also be a list of booleans, in which case + the rows or columns corresponding to the True values will be selected: + + >>> m.extract([0, 1, 2, 3], [True, False, True]) + Matrix([ + [0, 2], + [3, 5], + [6, 8], + [9, 11]]) + """ + + if not is_sequence(rowsList) or not is_sequence(colsList): + raise TypeError("rowsList and colsList must be iterable") + # ensure rowsList and colsList are lists of integers + if rowsList and all(isinstance(i, bool) for i in rowsList): + rowsList = [index for index, item in enumerate(rowsList) if item] + if colsList and all(isinstance(i, bool) for i in colsList): + colsList = [index for index, item in enumerate(colsList) if item] + + # ensure everything is in range + rowsList = [a2idx(k, self.rows) for k in rowsList] + colsList = [a2idx(k, self.cols) for k in colsList] + + return self._eval_extract(rowsList, colsList) + + def get_diag_blocks(self): + """Obtains the square sub-matrices on the main diagonal of a square matrix. + + Useful for inverting symbolic matrices or solving systems of + linear equations which may be decoupled by having a block diagonal + structure. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y, z + >>> A = Matrix([[1, 3, 0, 0], [y, z*z, 0, 0], [0, 0, x, 0], [0, 0, 0, 0]]) + >>> a1, a2, a3 = A.get_diag_blocks() + >>> a1 + Matrix([ + [1, 3], + [y, z**2]]) + >>> a2 + Matrix([[x]]) + >>> a3 + Matrix([[0]]) + + """ + return self._eval_get_diag_blocks() + + @classmethod + def hstack(cls, *args): + """Return a matrix formed by joining args horizontally (i.e. + by repeated application of row_join). + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> Matrix.hstack(eye(2), 2*eye(2)) + Matrix([ + [1, 0, 2, 0], + [0, 1, 0, 2]]) + """ + if len(args) == 0: + return cls._new() + + kls = type(args[0]) + return reduce(kls.row_join, args) + + def reshape(self, rows, cols): + """Reshape the matrix. Total number of elements must remain the same. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 3, lambda i, j: 1) + >>> m + Matrix([ + [1, 1, 1], + [1, 1, 1]]) + >>> m.reshape(1, 6) + Matrix([[1, 1, 1, 1, 1, 1]]) + >>> m.reshape(3, 2) + Matrix([ + [1, 1], + [1, 1], + [1, 1]]) + + """ + if self.rows * self.cols != rows * cols: + raise ValueError("Invalid reshape parameters %d %d" % (rows, cols)) + dok = {divmod(i*self.cols + j, cols): + v for (i, j), v in self.todok().items()} + return self._eval_from_dok(rows, cols, dok) + + def row_del(self, row): + """Delete the specified row.""" + if row < 0: + row += self.rows + if not 0 <= row < self.rows: + raise IndexError("Row {} is out of range.".format(row)) + + return self._eval_row_del(row) + + def row_insert(self, pos, other): + """Insert one or more rows at the given row position. + + Examples + ======== + + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(1, 3) + >>> M.row_insert(1, V) + Matrix([ + [0, 0, 0], + [1, 1, 1], + [0, 0, 0], + [0, 0, 0]]) + + See Also + ======== + + row + col_insert + """ + # Allows you to build a matrix even if it is null matrix + if not self: + return self._new(other) + + pos = as_int(pos) + + if pos < 0: + pos = self.rows + pos + if pos < 0: + pos = 0 + elif pos > self.rows: + pos = self.rows + + if self.cols != other.cols: + raise ShapeError( + "The matrices have incompatible number of columns ({} and {})" + .format(self.cols, other.cols)) + + return self._eval_row_insert(pos, other) + + def row_join(self, other): + """Concatenates two matrices along self's last and rhs's first column + + Examples + ======== + + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(3, 1) + >>> M.row_join(V) + Matrix([ + [0, 0, 0, 1], + [0, 0, 0, 1], + [0, 0, 0, 1]]) + + See Also + ======== + + row + col_join + """ + # A null matrix can always be stacked (see #10770) + if self.cols == 0 and self.rows != other.rows: + return self._new(other.rows, 0, []).row_join(other) + + if self.rows != other.rows: + raise ShapeError( + "The matrices have incompatible number of rows ({} and {})" + .format(self.rows, other.rows)) + return self._eval_row_join(other) + + def diagonal(self, k=0): + """Returns the kth diagonal of self. The main diagonal + corresponds to `k=0`; diagonals above and below correspond to + `k > 0` and `k < 0`, respectively. The values of `self[i, j]` + for which `j - i = k`, are returned in order of increasing + `i + j`, starting with `i + j = |k|`. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(3, 3, lambda i, j: j - i); m + Matrix([ + [ 0, 1, 2], + [-1, 0, 1], + [-2, -1, 0]]) + >>> _.diagonal() + Matrix([[0, 0, 0]]) + >>> m.diagonal(1) + Matrix([[1, 1]]) + >>> m.diagonal(-2) + Matrix([[-2]]) + + Even though the diagonal is returned as a Matrix, the element + retrieval can be done with a single index: + + >>> Matrix.diag(1, 2, 3).diagonal()[1] # instead of [0, 1] + 2 + + See Also + ======== + + diag + """ + rv = [] + k = as_int(k) + r = 0 if k > 0 else -k + c = 0 if r else k + while True: + if r == self.rows or c == self.cols: + break + rv.append(self[r, c]) + r += 1 + c += 1 + if not rv: + raise ValueError(filldedent(''' + The %s diagonal is out of range [%s, %s]''' % ( + k, 1 - self.rows, self.cols - 1))) + return self._new(1, len(rv), rv) + + def row(self, i): + """Elementary row selector. + + Examples + ======== + + >>> from sympy import eye + >>> eye(2).row(0) + Matrix([[1, 0]]) + + See Also + ======== + + col + row_del + row_join + row_insert + """ + return self[i, :] + + def todok(self): + """Return the matrix as dictionary of keys. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix.eye(3) + >>> M.todok() + {(0, 0): 1, (1, 1): 1, (2, 2): 1} + """ + return self._eval_todok() + + @classmethod + def from_dok(cls, rows, cols, dok): + """Create a matrix from a dictionary of keys. + + Examples + ======== + + >>> from sympy import Matrix + >>> d = {(0, 0): 1, (1, 2): 3, (2, 1): 4} + >>> Matrix.from_dok(3, 3, d) + Matrix([ + [1, 0, 0], + [0, 0, 3], + [0, 4, 0]]) + """ + dok = {ij: cls._sympify(val) for ij, val in dok.items()} + return cls._eval_from_dok(rows, cols, dok) + + def tolist(self): + """Return the Matrix as a nested Python list. + + Examples + ======== + + >>> from sympy import Matrix, ones + >>> m = Matrix(3, 3, range(9)) + >>> m + Matrix([ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> m.tolist() + [[0, 1, 2], [3, 4, 5], [6, 7, 8]] + >>> ones(3, 0).tolist() + [[], [], []] + + When there are no rows then it will not be possible to tell how + many columns were in the original matrix: + + >>> ones(0, 3).tolist() + [] + + """ + if not self.rows: + return [] + if not self.cols: + return [[] for i in range(self.rows)] + return self._eval_tolist() + + def todod(M): + """Returns matrix as dict of dicts containing non-zero elements of the Matrix + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[0, 1],[0, 3]]) + >>> A + Matrix([ + [0, 1], + [0, 3]]) + >>> A.todod() + {0: {1: 1}, 1: {1: 3}} + + + """ + rowsdict = {} + Mlol = M.tolist() + for i, Mi in enumerate(Mlol): + row = {j: Mij for j, Mij in enumerate(Mi) if Mij} + if row: + rowsdict[i] = row + return rowsdict + + def vec(self): + """Return the Matrix converted into a one column matrix by stacking columns + + Examples + ======== + + >>> from sympy import Matrix + >>> m=Matrix([[1, 3], [2, 4]]) + >>> m + Matrix([ + [1, 3], + [2, 4]]) + >>> m.vec() + Matrix([ + [1], + [2], + [3], + [4]]) + + See Also + ======== + + vech + """ + return self._eval_vec() + + def vech(self, diagonal=True, check_symmetry=True): + """Reshapes the matrix into a column vector by stacking the + elements in the lower triangle. + + Parameters + ========== + + diagonal : bool, optional + If ``True``, it includes the diagonal elements. + + check_symmetry : bool, optional + If ``True``, it checks whether the matrix is symmetric. + + Examples + ======== + + >>> from sympy import Matrix + >>> m=Matrix([[1, 2], [2, 3]]) + >>> m + Matrix([ + [1, 2], + [2, 3]]) + >>> m.vech() + Matrix([ + [1], + [2], + [3]]) + >>> m.vech(diagonal=False) + Matrix([[2]]) + + Notes + ===== + + This should work for symmetric matrices and ``vech`` can + represent symmetric matrices in vector form with less size than + ``vec``. + + See Also + ======== + + vec + """ + if not self.is_square: + raise NonSquareMatrixError + + if check_symmetry and not self.is_symmetric(): + raise ValueError("The matrix is not symmetric.") + + return self._eval_vech(diagonal) + + @classmethod + def vstack(cls, *args): + """Return a matrix formed by joining args vertically (i.e. + by repeated application of col_join). + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> Matrix.vstack(eye(2), 2*eye(2)) + Matrix([ + [1, 0], + [0, 1], + [2, 0], + [0, 2]]) + """ + if len(args) == 0: + return cls._new() + + kls = type(args[0]) + return reduce(kls.col_join, args) + + @classmethod + def _eval_diag(cls, rows, cols, diag_dict): + """diag_dict is a defaultdict containing + all the entries of the diagonal matrix.""" + def entry(i, j): + return diag_dict[(i, j)] + return cls._new(rows, cols, entry) + + @classmethod + def _eval_eye(cls, rows, cols): + vals = [cls.zero]*(rows*cols) + vals[::cols+1] = [cls.one]*min(rows, cols) + return cls._new(rows, cols, vals, copy=False) + + @classmethod + def _eval_jordan_block(cls, size: int, eigenvalue, band='upper'): + if band == 'lower': + def entry(i, j): + if i == j: + return eigenvalue + elif j + 1 == i: + return cls.one + return cls.zero + else: + def entry(i, j): + if i == j: + return eigenvalue + elif i + 1 == j: + return cls.one + return cls.zero + return cls._new(size, size, entry) + + @classmethod + def _eval_ones(cls, rows, cols): + def entry(i, j): + return cls.one + return cls._new(rows, cols, entry) + + @classmethod + def _eval_zeros(cls, rows, cols): + return cls._new(rows, cols, [cls.zero]*(rows*cols), copy=False) + + @classmethod + def _eval_wilkinson(cls, n): + def entry(i, j): + return cls.one if i + 1 == j else cls.zero + + D = cls._new(2*n + 1, 2*n + 1, entry) + + wminus = cls.diag(list(range(-n, n + 1)), unpack=True) + D + D.T + wplus = abs(cls.diag(list(range(-n, n + 1)), unpack=True)) + D + D.T + + return wminus, wplus + + @classmethod + def diag(kls, *args, strict=False, unpack=True, rows=None, cols=None, **kwargs): + """Returns a matrix with the specified diagonal. + If matrices are passed, a block-diagonal matrix + is created (i.e. the "direct sum" of the matrices). + + kwargs + ====== + + rows : rows of the resulting matrix; computed if + not given. + + cols : columns of the resulting matrix; computed if + not given. + + cls : class for the resulting matrix + + unpack : bool which, when True (default), unpacks a single + sequence rather than interpreting it as a Matrix. + + strict : bool which, when False (default), allows Matrices to + have variable-length rows. + + Examples + ======== + + >>> from sympy import Matrix + >>> Matrix.diag(1, 2, 3) + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + + The current default is to unpack a single sequence. If this is + not desired, set `unpack=False` and it will be interpreted as + a matrix. + + >>> Matrix.diag([1, 2, 3]) == Matrix.diag(1, 2, 3) + True + + When more than one element is passed, each is interpreted as + something to put on the diagonal. Lists are converted to + matrices. Filling of the diagonal always continues from + the bottom right hand corner of the previous item: this + will create a block-diagonal matrix whether the matrices + are square or not. + + >>> col = [1, 2, 3] + >>> row = [[4, 5]] + >>> Matrix.diag(col, row) + Matrix([ + [1, 0, 0], + [2, 0, 0], + [3, 0, 0], + [0, 4, 5]]) + + When `unpack` is False, elements within a list need not all be + of the same length. Setting `strict` to True would raise a + ValueError for the following: + + >>> Matrix.diag([[1, 2, 3], [4, 5], [6]], unpack=False) + Matrix([ + [1, 2, 3], + [4, 5, 0], + [6, 0, 0]]) + + The type of the returned matrix can be set with the ``cls`` + keyword. + + >>> from sympy import ImmutableMatrix + >>> from sympy.utilities.misc import func_name + >>> func_name(Matrix.diag(1, cls=ImmutableMatrix)) + 'ImmutableDenseMatrix' + + A zero dimension matrix can be used to position the start of + the filling at the start of an arbitrary row or column: + + >>> from sympy import ones + >>> r2 = ones(0, 2) + >>> Matrix.diag(r2, 1, 2) + Matrix([ + [0, 0, 1, 0], + [0, 0, 0, 2]]) + + See Also + ======== + eye + diagonal + .dense.diag + .expressions.blockmatrix.BlockMatrix + .sparsetools.banded + """ + from sympy.matrices.matrixbase import MatrixBase + from sympy.matrices.dense import Matrix + from sympy.matrices import SparseMatrix + klass = kwargs.get('cls', kls) + if unpack and len(args) == 1 and is_sequence(args[0]) and \ + not isinstance(args[0], MatrixBase): + args = args[0] + + # fill a default dict with the diagonal entries + diag_entries = defaultdict(int) + rmax = cmax = 0 # keep track of the biggest index seen + for m in args: + if isinstance(m, list): + if strict: + # if malformed, Matrix will raise an error + _ = Matrix(m) + r, c = _.shape + m = _.tolist() + else: + r, c, smat = SparseMatrix._handle_creation_inputs(m) + for (i, j), _ in smat.items(): + diag_entries[(i + rmax, j + cmax)] = _ + m = [] # to skip process below + elif hasattr(m, 'shape'): # a Matrix + # convert to list of lists + r, c = m.shape + m = m.tolist() + else: # in this case, we're a single value + diag_entries[(rmax, cmax)] = m + rmax += 1 + cmax += 1 + continue + # process list of lists + for i, mi in enumerate(m): + for j, _ in enumerate(mi): + diag_entries[(i + rmax, j + cmax)] = _ + rmax += r + cmax += c + if rows is None: + rows, cols = cols, rows + if rows is None: + rows, cols = rmax, cmax + else: + cols = rows if cols is None else cols + if rows < rmax or cols < cmax: + raise ValueError(filldedent(''' + The constructed matrix is {} x {} but a size of {} x {} + was specified.'''.format(rmax, cmax, rows, cols))) + return klass._eval_diag(rows, cols, diag_entries) + + @classmethod + def eye(kls, rows, cols=None, **kwargs): + """Returns an identity matrix. + + Parameters + ========== + + rows : rows of the matrix + cols : cols of the matrix (if None, cols=rows) + + kwargs + ====== + cls : class of the returned matrix + """ + if cols is None: + cols = rows + if rows < 0 or cols < 0: + raise ValueError("Cannot create a {} x {} matrix. " + "Both dimensions must be positive".format(rows, cols)) + klass = kwargs.get('cls', kls) + rows, cols = as_int(rows), as_int(cols) + + return klass._eval_eye(rows, cols) + + @classmethod + def jordan_block(kls, size=None, eigenvalue=None, *, band='upper', **kwargs): + """Returns a Jordan block + + Parameters + ========== + + size : Integer, optional + Specifies the shape of the Jordan block matrix. + + eigenvalue : Number or Symbol + Specifies the value for the main diagonal of the matrix. + + .. note:: + The keyword ``eigenval`` is also specified as an alias + of this keyword, but it is not recommended to use. + + We may deprecate the alias in later release. + + band : 'upper' or 'lower', optional + Specifies the position of the off-diagonal to put `1` s on. + + cls : Matrix, optional + Specifies the matrix class of the output form. + + If it is not specified, the class type where the method is + being executed on will be returned. + + Returns + ======= + + Matrix + A Jordan block matrix. + + Raises + ====== + + ValueError + If insufficient arguments are given for matrix size + specification, or no eigenvalue is given. + + Examples + ======== + + Creating a default Jordan block: + + >>> from sympy import Matrix + >>> from sympy.abc import x + >>> Matrix.jordan_block(4, x) + Matrix([ + [x, 1, 0, 0], + [0, x, 1, 0], + [0, 0, x, 1], + [0, 0, 0, x]]) + + Creating an alternative Jordan block matrix where `1` is on + lower off-diagonal: + + >>> Matrix.jordan_block(4, x, band='lower') + Matrix([ + [x, 0, 0, 0], + [1, x, 0, 0], + [0, 1, x, 0], + [0, 0, 1, x]]) + + Creating a Jordan block with keyword arguments + + >>> Matrix.jordan_block(size=4, eigenvalue=x) + Matrix([ + [x, 1, 0, 0], + [0, x, 1, 0], + [0, 0, x, 1], + [0, 0, 0, x]]) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Jordan_matrix + """ + klass = kwargs.pop('cls', kls) + + eigenval = kwargs.get('eigenval', None) + if eigenvalue is None and eigenval is None: + raise ValueError("Must supply an eigenvalue") + elif eigenvalue != eigenval and None not in (eigenval, eigenvalue): + raise ValueError( + "Inconsistent values are given: 'eigenval'={}, " + "'eigenvalue'={}".format(eigenval, eigenvalue)) + else: + if eigenval is not None: + eigenvalue = eigenval + + if size is None: + raise ValueError("Must supply a matrix size") + + size = as_int(size) + return klass._eval_jordan_block(size, eigenvalue, band) + + @classmethod + def ones(kls, rows, cols=None, **kwargs): + """Returns a matrix of ones. + + Parameters + ========== + + rows : rows of the matrix + cols : cols of the matrix (if None, cols=rows) + + kwargs + ====== + cls : class of the returned matrix + """ + if cols is None: + cols = rows + klass = kwargs.get('cls', kls) + rows, cols = as_int(rows), as_int(cols) + + return klass._eval_ones(rows, cols) + + @classmethod + def zeros(kls, rows, cols=None, **kwargs): + """Returns a matrix of zeros. + + Parameters + ========== + + rows : rows of the matrix + cols : cols of the matrix (if None, cols=rows) + + kwargs + ====== + cls : class of the returned matrix + """ + if cols is None: + cols = rows + if rows < 0 or cols < 0: + raise ValueError("Cannot create a {} x {} matrix. " + "Both dimensions must be positive".format(rows, cols)) + klass = kwargs.get('cls', kls) + rows, cols = as_int(rows), as_int(cols) + + return klass._eval_zeros(rows, cols) + + @classmethod + def companion(kls, poly): + """Returns a companion matrix of a polynomial. + + Examples + ======== + + >>> from sympy import Matrix, Poly, Symbol, symbols + >>> x = Symbol('x') + >>> c0, c1, c2, c3, c4 = symbols('c0:5') + >>> p = Poly(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + x**5, x) + >>> Matrix.companion(p) + Matrix([ + [0, 0, 0, 0, -c0], + [1, 0, 0, 0, -c1], + [0, 1, 0, 0, -c2], + [0, 0, 1, 0, -c3], + [0, 0, 0, 1, -c4]]) + """ + poly = kls._sympify(poly) + if not isinstance(poly, Poly): + raise ValueError("{} must be a Poly instance.".format(poly)) + if not poly.is_monic: + raise ValueError("{} must be a monic polynomial.".format(poly)) + if not poly.is_univariate: + raise ValueError( + "{} must be a univariate polynomial.".format(poly)) + + size = poly.degree() + if not size >= 1: + raise ValueError( + "{} must have degree not less than 1.".format(poly)) + + coeffs = poly.all_coeffs() + def entry(i, j): + if j == size - 1: + return -coeffs[-1 - i] + elif i == j + 1: + return kls.one + return kls.zero + return kls._new(size, size, entry) + + + @classmethod + def wilkinson(kls, n, **kwargs): + """Returns two square Wilkinson Matrix of size 2*n + 1 + $W_{2n + 1}^-, W_{2n + 1}^+ =$ Wilkinson(n) + + Examples + ======== + + >>> from sympy import Matrix + >>> wminus, wplus = Matrix.wilkinson(3) + >>> wminus + Matrix([ + [-3, 1, 0, 0, 0, 0, 0], + [ 1, -2, 1, 0, 0, 0, 0], + [ 0, 1, -1, 1, 0, 0, 0], + [ 0, 0, 1, 0, 1, 0, 0], + [ 0, 0, 0, 1, 1, 1, 0], + [ 0, 0, 0, 0, 1, 2, 1], + [ 0, 0, 0, 0, 0, 1, 3]]) + >>> wplus + Matrix([ + [3, 1, 0, 0, 0, 0, 0], + [1, 2, 1, 0, 0, 0, 0], + [0, 1, 1, 1, 0, 0, 0], + [0, 0, 1, 0, 1, 0, 0], + [0, 0, 0, 1, 1, 1, 0], + [0, 0, 0, 0, 1, 2, 1], + [0, 0, 0, 0, 0, 1, 3]]) + + References + ========== + + .. [1] https://blogs.mathworks.com/cleve/2013/04/15/wilkinsons-matrices-2/ + .. [2] J. H. Wilkinson, The Algebraic Eigenvalue Problem, Claredon Press, Oxford, 1965, 662 pp. + + """ + klass = kwargs.get('cls', kls) + n = as_int(n) + return klass._eval_wilkinson(n) + + # The RepMatrix subclass uses more efficient sparse implementations of + # _eval_iter_values and other things. + + def _eval_iter_values(self): + return (i for i in self if i is not S.Zero) + + def _eval_values(self): + return list(self.iter_values()) + + def _eval_iter_items(self): + for i in range(self.rows): + for j in range(self.cols): + if self[i, j]: + yield (i, j), self[i, j] + + def _eval_atoms(self, *types): + values = self.values() + if len(values) < self.rows * self.cols and isinstance(S.Zero, types): + s = {S.Zero} + else: + s = set() + return s.union(*[v.atoms(*types) for v in values]) + + def _eval_free_symbols(self): + return set().union(*(i.free_symbols for i in set(self.values()))) + + def _eval_has(self, *patterns): + return any(a.has(*patterns) for a in self.iter_values()) + + def _eval_is_symbolic(self): + return self.has(Symbol) + + # _eval_is_hermitian is called by some general SymPy + # routines and has a different *args signature. Make + # sure the names don't clash by adding `_matrix_` in name. + def _eval_is_matrix_hermitian(self, simpfunc): + herm = lambda i, j: simpfunc(self[i, j] - self[j, i].adjoint()).is_zero + return fuzzy_and(herm(i, j) for (i, j), v in self.iter_items()) + + def _eval_is_zero_matrix(self): + return fuzzy_and(v.is_zero for v in self.iter_values()) + + def _eval_is_Identity(self) -> FuzzyBool: + one = self.one + zero = self.zero + ident = lambda i, j, v: v is one if i == j else v is zero + return all(ident(i, j, v) for (i, j), v in self.iter_items()) + + def _eval_is_diagonal(self): + return fuzzy_and(v.is_zero for (i, j), v in self.iter_items() if i != j) + + def _eval_is_lower(self): + return all(v.is_zero for (i, j), v in self.iter_items() if i < j) + + def _eval_is_upper(self): + return all(v.is_zero for (i, j), v in self.iter_items() if i > j) + + def _eval_is_lower_hessenberg(self): + return all(v.is_zero for (i, j), v in self.iter_items() if i + 1 < j) + + def _eval_is_upper_hessenberg(self): + return all(v.is_zero for (i, j), v in self.iter_items() if i > j + 1) + + def _eval_is_symmetric(self, simpfunc): + sym = lambda i, j: simpfunc(self[i, j] - self[j, i]).is_zero + return fuzzy_and(sym(i, j) for (i, j), v in self.iter_items()) + + def _eval_is_anti_symmetric(self, simpfunc): + anti = lambda i, j: simpfunc(self[i, j] + self[j, i]).is_zero + return fuzzy_and(anti(i, j) for (i, j), v in self.iter_items()) + + def _has_positive_diagonals(self): + diagonal_entries = (self[i, i] for i in range(self.rows)) + return fuzzy_and(x.is_positive for x in diagonal_entries) + + def _has_nonnegative_diagonals(self): + diagonal_entries = (self[i, i] for i in range(self.rows)) + return fuzzy_and(x.is_nonnegative for x in diagonal_entries) + + def atoms(self, *types): + """Returns the atoms that form the current object. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import Matrix + >>> Matrix([[x]]) + Matrix([[x]]) + >>> _.atoms() + {x} + >>> Matrix([[x, y], [y, x]]) + Matrix([ + [x, y], + [y, x]]) + >>> _.atoms() + {x, y} + """ + + types = tuple(t if isinstance(t, type) else type(t) for t in types) + if not types: + types = (Atom,) + return self._eval_atoms(*types) + + @property + def free_symbols(self): + """Returns the free symbols within the matrix. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import Matrix + >>> Matrix([[x], [1]]).free_symbols + {x} + """ + return self._eval_free_symbols() + + def has(self, *patterns): + """Test whether any subexpression matches any of the patterns. + + Examples + ======== + + >>> from sympy import Matrix, SparseMatrix, Float + >>> from sympy.abc import x, y + >>> A = Matrix(((1, x), (0.2, 3))) + >>> B = SparseMatrix(((1, x), (0.2, 3))) + >>> A.has(x) + True + >>> A.has(y) + False + >>> A.has(Float) + True + >>> B.has(x) + True + >>> B.has(y) + False + >>> B.has(Float) + True + """ + return self._eval_has(*patterns) + + def is_anti_symmetric(self, simplify=True): + """Check if matrix M is an antisymmetric matrix, + that is, M is a square matrix with all M[i, j] == -M[j, i]. + + When ``simplify=True`` (default), the sum M[i, j] + M[j, i] is + simplified before testing to see if it is zero. By default, + the SymPy simplify function is used. To use a custom function + set simplify to a function that accepts a single argument which + returns a simplified expression. To skip simplification, set + simplify to False but note that although this will be faster, + it may induce false negatives. + + Examples + ======== + + >>> from sympy import Matrix, symbols + >>> m = Matrix(2, 2, [0, 1, -1, 0]) + >>> m + Matrix([ + [ 0, 1], + [-1, 0]]) + >>> m.is_anti_symmetric() + True + >>> x, y = symbols('x y') + >>> m = Matrix(2, 3, [0, 0, x, -y, 0, 0]) + >>> m + Matrix([ + [ 0, 0, x], + [-y, 0, 0]]) + >>> m.is_anti_symmetric() + False + + >>> from sympy.abc import x, y + >>> m = Matrix(3, 3, [0, x**2 + 2*x + 1, y, + ... -(x + 1)**2, 0, x*y, + ... -y, -x*y, 0]) + + Simplification of matrix elements is done by default so even + though two elements which should be equal and opposite would not + pass an equality test, the matrix is still reported as + anti-symmetric: + + >>> m[0, 1] == -m[1, 0] + False + >>> m.is_anti_symmetric() + True + + If ``simplify=False`` is used for the case when a Matrix is already + simplified, this will speed things up. Here, we see that without + simplification the matrix does not appear anti-symmetric: + + >>> print(m.is_anti_symmetric(simplify=False)) + None + + But if the matrix were already expanded, then it would appear + anti-symmetric and simplification in the is_anti_symmetric routine + is not needed: + + >>> m = m.expand() + >>> m.is_anti_symmetric(simplify=False) + True + """ + # accept custom simplification + simpfunc = simplify + if not isfunction(simplify): + simpfunc = _utilities_simplify if simplify else lambda x: x + + if not self.is_square: + return False + return self._eval_is_anti_symmetric(simpfunc) + + def is_diagonal(self): + """Check if matrix is diagonal, + that is matrix in which the entries outside the main diagonal are all zero. + + Examples + ======== + + >>> from sympy import Matrix, diag + >>> m = Matrix(2, 2, [1, 0, 0, 2]) + >>> m + Matrix([ + [1, 0], + [0, 2]]) + >>> m.is_diagonal() + True + + >>> m = Matrix(2, 2, [1, 1, 0, 2]) + >>> m + Matrix([ + [1, 1], + [0, 2]]) + >>> m.is_diagonal() + False + + >>> m = diag(1, 2, 3) + >>> m + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + >>> m.is_diagonal() + True + + See Also + ======== + + is_lower + is_upper + sympy.matrices.matrixbase.MatrixBase.is_diagonalizable + diagonalize + """ + return self._eval_is_diagonal() + + @property + def is_weakly_diagonally_dominant(self): + r"""Tests if the matrix is row weakly diagonally dominant. + + Explanation + =========== + + A $n, n$ matrix $A$ is row weakly diagonally dominant if + + .. math:: + \left|A_{i, i}\right| \ge \sum_{j = 0, j \neq i}^{n-1} + \left|A_{i, j}\right| \quad {\text{for all }} + i \in \{ 0, ..., n-1 \} + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) + >>> A.is_weakly_diagonally_dominant + True + + >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) + >>> A.is_weakly_diagonally_dominant + False + + >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) + >>> A.is_weakly_diagonally_dominant + True + + Notes + ===== + + If you want to test whether a matrix is column diagonally + dominant, you can apply the test after transposing the matrix. + """ + if not self.is_square: + return False + + rows, cols = self.shape + + def test_row(i): + summation = self.zero + for j in range(cols): + if i != j: + summation += Abs(self[i, j]) + return (Abs(self[i, i]) - summation).is_nonnegative + + return fuzzy_and(test_row(i) for i in range(rows)) + + @property + def is_strongly_diagonally_dominant(self): + r"""Tests if the matrix is row strongly diagonally dominant. + + Explanation + =========== + + A $n, n$ matrix $A$ is row strongly diagonally dominant if + + .. math:: + \left|A_{i, i}\right| > \sum_{j = 0, j \neq i}^{n-1} + \left|A_{i, j}\right| \quad {\text{for all }} + i \in \{ 0, ..., n-1 \} + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) + >>> A.is_strongly_diagonally_dominant + False + + >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) + >>> A.is_strongly_diagonally_dominant + False + + >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) + >>> A.is_strongly_diagonally_dominant + True + + Notes + ===== + + If you want to test whether a matrix is column diagonally + dominant, you can apply the test after transposing the matrix. + """ + if not self.is_square: + return False + + rows, cols = self.shape + + def test_row(i): + summation = self.zero + for j in range(cols): + if i != j: + summation += Abs(self[i, j]) + return (Abs(self[i, i]) - summation).is_positive + + return fuzzy_and(test_row(i) for i in range(rows)) + + @property + def is_hermitian(self): + """Checks if the matrix is Hermitian. + + In a Hermitian matrix element i,j is the complex conjugate of + element j,i. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy import I + >>> from sympy.abc import x + >>> a = Matrix([[1, I], [-I, 1]]) + >>> a + Matrix([ + [ 1, I], + [-I, 1]]) + >>> a.is_hermitian + True + >>> a[0, 0] = 2*I + >>> a.is_hermitian + False + >>> a[0, 0] = x + >>> a.is_hermitian + >>> a[0, 1] = a[1, 0]*I + >>> a.is_hermitian + False + """ + if not self.is_square: + return False + + return self._eval_is_matrix_hermitian(_utilities_simplify) + + @property + def is_Identity(self) -> FuzzyBool: + if not self.is_square: + return False + return self._eval_is_Identity() + + @property + def is_lower_hessenberg(self): + r"""Checks if the matrix is in the lower-Hessenberg form. + + The lower hessenberg matrix has zero entries + above the first superdiagonal. + + Examples + ======== + + >>> from sympy import Matrix + >>> a = Matrix([[1, 2, 0, 0], [5, 2, 3, 0], [3, 4, 3, 7], [5, 6, 1, 1]]) + >>> a + Matrix([ + [1, 2, 0, 0], + [5, 2, 3, 0], + [3, 4, 3, 7], + [5, 6, 1, 1]]) + >>> a.is_lower_hessenberg + True + + See Also + ======== + + is_upper_hessenberg + is_lower + """ + return self._eval_is_lower_hessenberg() + + @property + def is_lower(self): + """Check if matrix is a lower triangular matrix. True can be returned + even if the matrix is not square. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, [1, 0, 0, 1]) + >>> m + Matrix([ + [1, 0], + [0, 1]]) + >>> m.is_lower + True + + >>> m = Matrix(4, 3, [0, 0, 0, 2, 0, 0, 1, 4, 0, 6, 6, 5]) + >>> m + Matrix([ + [0, 0, 0], + [2, 0, 0], + [1, 4, 0], + [6, 6, 5]]) + >>> m.is_lower + True + + >>> from sympy.abc import x, y + >>> m = Matrix(2, 2, [x**2 + y, y**2 + x, 0, x + y]) + >>> m + Matrix([ + [x**2 + y, x + y**2], + [ 0, x + y]]) + >>> m.is_lower + False + + See Also + ======== + + is_upper + is_diagonal + is_lower_hessenberg + """ + return self._eval_is_lower() + + @property + def is_square(self): + """Checks if a matrix is square. + + A matrix is square if the number of rows equals the number of columns. + The empty matrix is square by definition, since the number of rows and + the number of columns are both zero. + + Examples + ======== + + >>> from sympy import Matrix + >>> a = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> b = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> c = Matrix([]) + >>> a.is_square + False + >>> b.is_square + True + >>> c.is_square + True + """ + return self.rows == self.cols + + def is_symbolic(self): + """Checks if any elements contain Symbols. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.is_symbolic() + True + + """ + return self._eval_is_symbolic() + + def is_symmetric(self, simplify=True): + """Check if matrix is symmetric matrix, + that is square matrix and is equal to its transpose. + + By default, simplifications occur before testing symmetry. + They can be skipped using 'simplify=False'; while speeding things a bit, + this may however induce false negatives. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, [0, 1, 1, 2]) + >>> m + Matrix([ + [0, 1], + [1, 2]]) + >>> m.is_symmetric() + True + + >>> m = Matrix(2, 2, [0, 1, 2, 0]) + >>> m + Matrix([ + [0, 1], + [2, 0]]) + >>> m.is_symmetric() + False + + >>> m = Matrix(2, 3, [0, 0, 0, 0, 0, 0]) + >>> m + Matrix([ + [0, 0, 0], + [0, 0, 0]]) + >>> m.is_symmetric() + False + + >>> from sympy.abc import x, y + >>> m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) + >>> m + Matrix([ + [ 1, x**2 + 2*x + 1, y], + [(x + 1)**2, 2, 0], + [ y, 0, 3]]) + >>> m.is_symmetric() + True + + If the matrix is already simplified, you may speed-up is_symmetric() + test by using 'simplify=False'. + + >>> bool(m.is_symmetric(simplify=False)) + False + >>> m1 = m.expand() + >>> m1.is_symmetric(simplify=False) + True + """ + simpfunc = simplify + if not isfunction(simplify): + simpfunc = _utilities_simplify if simplify else lambda x: x + + if not self.is_square: + return False + + return self._eval_is_symmetric(simpfunc) + + @property + def is_upper_hessenberg(self): + """Checks if the matrix is the upper-Hessenberg form. + + The upper hessenberg matrix has zero entries + below the first subdiagonal. + + Examples + ======== + + >>> from sympy import Matrix + >>> a = Matrix([[1, 4, 2, 3], [3, 4, 1, 7], [0, 2, 3, 4], [0, 0, 1, 3]]) + >>> a + Matrix([ + [1, 4, 2, 3], + [3, 4, 1, 7], + [0, 2, 3, 4], + [0, 0, 1, 3]]) + >>> a.is_upper_hessenberg + True + + See Also + ======== + + is_lower_hessenberg + is_upper + """ + return self._eval_is_upper_hessenberg() + + @property + def is_upper(self): + """Check if matrix is an upper triangular matrix. True can be returned + even if the matrix is not square. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, [1, 0, 0, 1]) + >>> m + Matrix([ + [1, 0], + [0, 1]]) + >>> m.is_upper + True + + >>> m = Matrix(4, 3, [5, 1, 9, 0, 4, 6, 0, 0, 5, 0, 0, 0]) + >>> m + Matrix([ + [5, 1, 9], + [0, 4, 6], + [0, 0, 5], + [0, 0, 0]]) + >>> m.is_upper + True + + >>> m = Matrix(2, 3, [4, 2, 5, 6, 1, 1]) + >>> m + Matrix([ + [4, 2, 5], + [6, 1, 1]]) + >>> m.is_upper + False + + See Also + ======== + + is_lower + is_diagonal + is_upper_hessenberg + """ + return self._eval_is_upper() + + @property + def is_zero_matrix(self): + """Checks if a matrix is a zero matrix. + + A matrix is zero if every element is zero. A matrix need not be square + to be considered zero. The empty matrix is zero by the principle of + vacuous truth. For a matrix that may or may not be zero (e.g. + contains a symbol), this will be None + + Examples + ======== + + >>> from sympy import Matrix, zeros + >>> from sympy.abc import x + >>> a = Matrix([[0, 0], [0, 0]]) + >>> b = zeros(3, 4) + >>> c = Matrix([[0, 1], [0, 0]]) + >>> d = Matrix([]) + >>> e = Matrix([[x, 0], [0, 0]]) + >>> a.is_zero_matrix + True + >>> b.is_zero_matrix + True + >>> c.is_zero_matrix + False + >>> d.is_zero_matrix + True + >>> e.is_zero_matrix + """ + return self._eval_is_zero_matrix() + + def values(self): + """Return non-zero values of self. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix([[0, 1], [2, 3]]) + >>> m.values() + [1, 2, 3] + + See Also + ======== + + iter_values + tolist + flat + """ + return self._eval_values() + + def iter_values(self): + """ + Iterate over non-zero values of self. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix([[0, 1], [2, 3]]) + >>> list(m.iter_values()) + [1, 2, 3] + + See Also + ======== + + values + """ + return self._eval_iter_values() + + def iter_items(self): + """Iterate over indices and values of nonzero items. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix([[0, 1], [2, 3]]) + >>> list(m.iter_items()) + [((0, 1), 1), ((1, 0), 2), ((1, 1), 3)] + + See Also + ======== + + iter_values + todok + """ + return self._eval_iter_items() + + def _eval_adjoint(self): + return self.transpose().applyfunc(lambda x: x.adjoint()) + + def _eval_applyfunc(self, f): + cols = self.cols + size = self.rows*self.cols + + dok = self.todok() + valmap = {v: f(v) for v in dok.values()} + + if len(dok) < size and ((fzero := f(S.Zero)) is not S.Zero): + out_flat = [fzero]*size + for (i, j), v in dok.items(): + out_flat[i*cols + j] = valmap[v] + out = self._new(self.rows, self.cols, out_flat) + else: + fdok = {ij: valmap[v] for ij, v in dok.items()} + out = self.from_dok(self.rows, self.cols, fdok) + + return out + + def _eval_as_real_imag(self): # type: ignore + return (self.applyfunc(re), self.applyfunc(im)) + + def _eval_conjugate(self): + return self.applyfunc(lambda x: x.conjugate()) + + def _eval_permute_cols(self, perm): + # apply the permutation to a list + mapping = list(perm) + + def entry(i, j): + return self[i, mapping[j]] + + return self._new(self.rows, self.cols, entry) + + def _eval_permute_rows(self, perm): + # apply the permutation to a list + mapping = list(perm) + + def entry(i, j): + return self[mapping[i], j] + + return self._new(self.rows, self.cols, entry) + + def _eval_trace(self): + return sum(self[i, i] for i in range(self.rows)) + + def _eval_transpose(self): + return self._new(self.cols, self.rows, lambda i, j: self[j, i]) + + def adjoint(self): + """Conjugate transpose or Hermitian conjugation.""" + return self._eval_adjoint() + + def applyfunc(self, f): + """Apply a function to each element of the matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, lambda i, j: i*2+j) + >>> m + Matrix([ + [0, 1], + [2, 3]]) + >>> m.applyfunc(lambda i: 2*i) + Matrix([ + [0, 2], + [4, 6]]) + + """ + if not callable(f): + raise TypeError("`f` must be callable.") + + return self._eval_applyfunc(f) + + def as_real_imag(self, deep=True, **hints): + """Returns a tuple containing the (real, imaginary) part of matrix.""" + # XXX: Ignoring deep and hints... + return self._eval_as_real_imag() + + def conjugate(self): + """Return the by-element conjugation. + + Examples + ======== + + >>> from sympy import SparseMatrix, I + >>> a = SparseMatrix(((1, 2 + I), (3, 4), (I, -I))) + >>> a + Matrix([ + [1, 2 + I], + [3, 4], + [I, -I]]) + >>> a.C + Matrix([ + [ 1, 2 - I], + [ 3, 4], + [-I, I]]) + + See Also + ======== + + transpose: Matrix transposition + H: Hermite conjugation + sympy.matrices.matrixbase.MatrixBase.D: Dirac conjugation + """ + return self._eval_conjugate() + + def doit(self, **hints): + return self.applyfunc(lambda x: x.doit(**hints)) + + def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): + """Apply evalf() to each element of self.""" + options = {'subs':subs, 'maxn':maxn, 'chop':chop, 'strict':strict, + 'quad':quad, 'verbose':verbose} + return self.applyfunc(lambda i: i.evalf(n, **options)) + + def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, + mul=True, log=True, multinomial=True, basic=True, **hints): + """Apply core.function.expand to each entry of the matrix. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import Matrix + >>> Matrix(1, 1, [x*(x+1)]) + Matrix([[x*(x + 1)]]) + >>> _.expand() + Matrix([[x**2 + x]]) + + """ + return self.applyfunc(lambda x: x.expand( + deep, modulus, power_base, power_exp, mul, log, multinomial, basic, + **hints)) + + @property + def H(self): + """Return Hermite conjugate. + + Examples + ======== + + >>> from sympy import Matrix, I + >>> m = Matrix((0, 1 + I, 2, 3)) + >>> m + Matrix([ + [ 0], + [1 + I], + [ 2], + [ 3]]) + >>> m.H + Matrix([[0, 1 - I, 2, 3]]) + + See Also + ======== + + conjugate: By-element conjugation + sympy.matrices.matrixbase.MatrixBase.D: Dirac conjugation + """ + return self.adjoint() + + def permute(self, perm, orientation='rows', direction='forward'): + r"""Permute the rows or columns of a matrix by the given list of + swaps. + + Parameters + ========== + + perm : Permutation, list, or list of lists + A representation for the permutation. + + If it is ``Permutation``, it is used directly with some + resizing with respect to the matrix size. + + If it is specified as list of lists, + (e.g., ``[[0, 1], [0, 2]]``), then the permutation is formed + from applying the product of cycles. The direction how the + cyclic product is applied is described in below. + + If it is specified as a list, the list should represent + an array form of a permutation. (e.g., ``[1, 2, 0]``) which + would would form the swapping function + `0 \mapsto 1, 1 \mapsto 2, 2\mapsto 0`. + + orientation : 'rows', 'cols' + A flag to control whether to permute the rows or the columns + + direction : 'forward', 'backward' + A flag to control whether to apply the permutations from + the start of the list first, or from the back of the list + first. + + For example, if the permutation specification is + ``[[0, 1], [0, 2]]``, + + If the flag is set to ``'forward'``, the cycle would be + formed as `0 \mapsto 2, 2 \mapsto 1, 1 \mapsto 0`. + + If the flag is set to ``'backward'``, the cycle would be + formed as `0 \mapsto 1, 1 \mapsto 2, 2 \mapsto 0`. + + If the argument ``perm`` is not in a form of list of lists, + this flag takes no effect. + + Examples + ======== + + >>> from sympy import eye + >>> M = eye(3) + >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='forward') + Matrix([ + [0, 0, 1], + [1, 0, 0], + [0, 1, 0]]) + + >>> from sympy import eye + >>> M = eye(3) + >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='backward') + Matrix([ + [0, 1, 0], + [0, 0, 1], + [1, 0, 0]]) + + Notes + ===== + + If a bijective function + `\sigma : \mathbb{N}_0 \rightarrow \mathbb{N}_0` denotes the + permutation. + + If the matrix `A` is the matrix to permute, represented as + a horizontal or a vertical stack of vectors: + + .. math:: + A = + \begin{bmatrix} + a_0 \\ a_1 \\ \vdots \\ a_{n-1} + \end{bmatrix} = + \begin{bmatrix} + \alpha_0 & \alpha_1 & \cdots & \alpha_{n-1} + \end{bmatrix} + + If the matrix `B` is the result, the permutation of matrix rows + is defined as: + + .. math:: + B := \begin{bmatrix} + a_{\sigma(0)} \\ a_{\sigma(1)} \\ \vdots \\ a_{\sigma(n-1)} + \end{bmatrix} + + And the permutation of matrix columns is defined as: + + .. math:: + B := \begin{bmatrix} + \alpha_{\sigma(0)} & \alpha_{\sigma(1)} & + \cdots & \alpha_{\sigma(n-1)} + \end{bmatrix} + """ + from sympy.combinatorics import Permutation + + # allow british variants and `columns` + if direction == 'forwards': + direction = 'forward' + if direction == 'backwards': + direction = 'backward' + if orientation == 'columns': + orientation = 'cols' + + if direction not in ('forward', 'backward'): + raise TypeError("direction='{}' is an invalid kwarg. " + "Try 'forward' or 'backward'".format(direction)) + if orientation not in ('rows', 'cols'): + raise TypeError("orientation='{}' is an invalid kwarg. " + "Try 'rows' or 'cols'".format(orientation)) + + if not isinstance(perm, (Permutation, Iterable)): + raise ValueError( + "{} must be a list, a list of lists, " + "or a SymPy permutation object.".format(perm)) + + # ensure all swaps are in range + max_index = self.rows if orientation == 'rows' else self.cols + if not all(0 <= t <= max_index for t in flatten(list(perm))): + raise IndexError("`swap` indices out of range.") + + if perm and not isinstance(perm, Permutation) and \ + isinstance(perm[0], Iterable): + if direction == 'forward': + perm = list(reversed(perm)) + perm = Permutation(perm, size=max_index+1) + else: + perm = Permutation(perm, size=max_index+1) + + if orientation == 'rows': + return self._eval_permute_rows(perm) + if orientation == 'cols': + return self._eval_permute_cols(perm) + + def permute_cols(self, swaps, direction='forward'): + """Alias for + ``self.permute(swaps, orientation='cols', direction=direction)`` + + See Also + ======== + + permute + """ + return self.permute(swaps, orientation='cols', direction=direction) + + def permute_rows(self, swaps, direction='forward'): + """Alias for + ``self.permute(swaps, orientation='rows', direction=direction)`` + + See Also + ======== + + permute + """ + return self.permute(swaps, orientation='rows', direction=direction) + + def refine(self, assumptions=True): + """Apply refine to each element of the matrix. + + Examples + ======== + + >>> from sympy import Symbol, Matrix, Abs, sqrt, Q + >>> x = Symbol('x') + >>> Matrix([[Abs(x)**2, sqrt(x**2)],[sqrt(x**2), Abs(x)**2]]) + Matrix([ + [ Abs(x)**2, sqrt(x**2)], + [sqrt(x**2), Abs(x)**2]]) + >>> _.refine(Q.real(x)) + Matrix([ + [ x**2, Abs(x)], + [Abs(x), x**2]]) + + """ + return self.applyfunc(lambda x: refine(x, assumptions)) + + def replace(self, F, G, map=False, simultaneous=True, exact=None): + """Replaces Function F in Matrix entries with Function G. + + Examples + ======== + + >>> from sympy import symbols, Function, Matrix + >>> F, G = symbols('F, G', cls=Function) + >>> M = Matrix(2, 2, lambda i, j: F(i+j)) ; M + Matrix([ + [F(0), F(1)], + [F(1), F(2)]]) + >>> N = M.replace(F,G) + >>> N + Matrix([ + [G(0), G(1)], + [G(1), G(2)]]) + """ + kwargs = {'map': map, 'simultaneous': simultaneous, 'exact': exact} + + if map: + + d = {} + def func(eij): + eij, dij = eij.replace(F, G, **kwargs) + d.update(dij) + return eij + + M = self.applyfunc(func) + return M, d + + else: + return self.applyfunc(lambda i: i.replace(F, G, **kwargs)) + + def rot90(self, k=1): + """Rotates Matrix by 90 degrees + + Parameters + ========== + + k : int + Specifies how many times the matrix is rotated by 90 degrees + (clockwise when positive, counter-clockwise when negative). + + Examples + ======== + + >>> from sympy import Matrix, symbols + >>> A = Matrix(2, 2, symbols('a:d')) + >>> A + Matrix([ + [a, b], + [c, d]]) + + Rotating the matrix clockwise one time: + + >>> A.rot90(1) + Matrix([ + [c, a], + [d, b]]) + + Rotating the matrix anticlockwise two times: + + >>> A.rot90(-2) + Matrix([ + [d, c], + [b, a]]) + """ + + mod = k%4 + if mod == 0: + return self + if mod == 1: + return self[::-1, ::].T + if mod == 2: + return self[::-1, ::-1] + if mod == 3: + return self[::, ::-1].T + + def simplify(self, **kwargs): + """Apply simplify to each element of the matrix. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import SparseMatrix, sin, cos + >>> SparseMatrix(1, 1, [x*sin(y)**2 + x*cos(y)**2]) + Matrix([[x*sin(y)**2 + x*cos(y)**2]]) + >>> _.simplify() + Matrix([[x]]) + """ + return self.applyfunc(lambda x: x.simplify(**kwargs)) + + def subs(self, *args, **kwargs): # should mirror core.basic.subs + """Return a new matrix with subs applied to each entry. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import SparseMatrix, Matrix + >>> SparseMatrix(1, 1, [x]) + Matrix([[x]]) + >>> _.subs(x, y) + Matrix([[y]]) + >>> Matrix(_).subs(y, x) + Matrix([[x]]) + """ + + if len(args) == 1 and not isinstance(args[0], (dict, set)) and iter(args[0]) and not is_sequence(args[0]): + args = (list(args[0]),) + + return self.applyfunc(lambda x: x.subs(*args, **kwargs)) + + def trace(self): + """ + Returns the trace of a square matrix i.e. the sum of the + diagonal elements. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix(2, 2, [1, 2, 3, 4]) + >>> A.trace() + 5 + + """ + if self.rows != self.cols: + raise NonSquareMatrixError() + return self._eval_trace() + + def transpose(self): + """ + Returns the transpose of the matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix(2, 2, [1, 2, 3, 4]) + >>> A.transpose() + Matrix([ + [1, 3], + [2, 4]]) + + >>> from sympy import Matrix, I + >>> m=Matrix(((1, 2+I), (3, 4))) + >>> m + Matrix([ + [1, 2 + I], + [3, 4]]) + >>> m.transpose() + Matrix([ + [ 1, 3], + [2 + I, 4]]) + >>> m.T == m.transpose() + True + + See Also + ======== + + conjugate: By-element conjugation + + """ + return self._eval_transpose() + + @property + def T(self): + '''Matrix transposition''' + return self.transpose() + + @property + def C(self): + '''By-element conjugation''' + return self.conjugate() + + def n(self, *args, **kwargs): + """Apply evalf() to each element of self.""" + return self.evalf(*args, **kwargs) + + def xreplace(self, rule): # should mirror core.basic.xreplace + """Return a new matrix with xreplace applied to each entry. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import SparseMatrix, Matrix + >>> SparseMatrix(1, 1, [x]) + Matrix([[x]]) + >>> _.xreplace({x: y}) + Matrix([[y]]) + >>> Matrix(_).xreplace({y: x}) + Matrix([[x]]) + """ + return self.applyfunc(lambda x: x.xreplace(rule)) + + def _eval_simplify(self, **kwargs): + # XXX: We can't use self.simplify here as mutable subclasses will + # override simplify and have it return None + return self.applyfunc(lambda x: x.simplify(**kwargs)) + + def _eval_trigsimp(self, **opts): + from sympy.simplify.trigsimp import trigsimp + return self.applyfunc(lambda x: trigsimp(x, **opts)) + + def upper_triangular(self, k=0): + """Return the elements on and above the kth diagonal of a matrix. + If k is not specified then simply returns upper-triangular portion + of a matrix + + Examples + ======== + + >>> from sympy import ones + >>> A = ones(4) + >>> A.upper_triangular() + Matrix([ + [1, 1, 1, 1], + [0, 1, 1, 1], + [0, 0, 1, 1], + [0, 0, 0, 1]]) + + >>> A.upper_triangular(2) + Matrix([ + [0, 0, 1, 1], + [0, 0, 0, 1], + [0, 0, 0, 0], + [0, 0, 0, 0]]) + + >>> A.upper_triangular(-1) + Matrix([ + [1, 1, 1, 1], + [1, 1, 1, 1], + [0, 1, 1, 1], + [0, 0, 1, 1]]) + + """ + + def entry(i, j): + return self[i, j] if i + k <= j else self.zero + + return self._new(self.rows, self.cols, entry) + + def lower_triangular(self, k=0): + """Return the elements on and below the kth diagonal of a matrix. + If k is not specified then simply returns lower-triangular portion + of a matrix + + Examples + ======== + + >>> from sympy import ones + >>> A = ones(4) + >>> A.lower_triangular() + Matrix([ + [1, 0, 0, 0], + [1, 1, 0, 0], + [1, 1, 1, 0], + [1, 1, 1, 1]]) + + >>> A.lower_triangular(-2) + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [1, 0, 0, 0], + [1, 1, 0, 0]]) + + >>> A.lower_triangular(1) + Matrix([ + [1, 1, 0, 0], + [1, 1, 1, 0], + [1, 1, 1, 1], + [1, 1, 1, 1]]) + + """ + + def entry(i, j): + return self[i, j] if i + k >= j else self.zero + + return self._new(self.rows, self.cols, entry) + + def _eval_Abs(self): + return self._new(self.rows, self.cols, lambda i, j: Abs(self[i, j])) + + def _eval_add(self, other): + return self._new(self.rows, self.cols, + lambda i, j: self[i, j] + other[i, j]) + + def _eval_matrix_mul(self, other): + def entry(i, j): + vec = [self[i,k]*other[k,j] for k in range(self.cols)] + try: + return Add(*vec) + except (TypeError, SympifyError): + # Some matrices don't work with `sum` or `Add` + # They don't work with `sum` because `sum` tries to add `0` + # Fall back to a safe way to multiply if the `Add` fails. + return reduce(lambda a, b: a + b, vec) + + return self._new(self.rows, other.cols, entry) + + def _eval_matrix_mul_elementwise(self, other): + return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other[i,j]) + + def _eval_matrix_rmul(self, other): + def entry(i, j): + return sum(other[i,k]*self[k,j] for k in range(other.cols)) + return self._new(other.rows, self.cols, entry) + + def _eval_pow_by_recursion(self, num): + if num == 1: + return self + + if num % 2 == 1: + a, b = self, self._eval_pow_by_recursion(num - 1) + else: + a = b = self._eval_pow_by_recursion(num // 2) + + return a.multiply(b) + + def _eval_pow_by_cayley(self, exp): + from sympy.discrete.recurrences import linrec_coeffs + row = self.shape[0] + p = self.charpoly() + + coeffs = (-p).all_coeffs()[1:] + coeffs = linrec_coeffs(coeffs, exp) + new_mat = self.eye(row) + ans = self.zeros(row) + + for i in range(row): + ans += coeffs[i]*new_mat + new_mat *= self + + return ans + + def _eval_pow_by_recursion_dotprodsimp(self, num, prevsimp=None): + if prevsimp is None: + prevsimp = [True]*len(self) + + if num == 1: + return self + + if num % 2 == 1: + a, b = self, self._eval_pow_by_recursion_dotprodsimp(num - 1, + prevsimp=prevsimp) + else: + a = b = self._eval_pow_by_recursion_dotprodsimp(num // 2, + prevsimp=prevsimp) + + m = a.multiply(b, dotprodsimp=False) + lenm = len(m) + elems = [None]*lenm + + for i in range(lenm): + if prevsimp[i]: + elems[i], prevsimp[i] = _dotprodsimp(m[i], withsimp=True) + else: + elems[i] = m[i] + + return m._new(m.rows, m.cols, elems) + + def _eval_scalar_mul(self, other): + return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other) + + def _eval_scalar_rmul(self, other): + return self._new(self.rows, self.cols, lambda i, j: other*self[i,j]) + + def _eval_Mod(self, other): + return self._new(self.rows, self.cols, lambda i, j: Mod(self[i, j], other)) + + # Python arithmetic functions + def __abs__(self): + """Returns a new matrix with entry-wise absolute values.""" + return self._eval_Abs() + + @call_highest_priority('__radd__') + def __add__(self, other): + """Return self + other, raising ShapeError if shapes do not match.""" + + other, T = _coerce_operand(self, other) + + if T != "is_matrix": + return NotImplemented + + if self.shape != other.shape: + raise ShapeError(f"Matrix size mismatch: {self.shape} + {other.shape}.") + + # Unify matrix types + a, b = self, other + if a.__class__ != classof(a, b): + b, a = a, b + + return a._eval_add(b) + + @call_highest_priority('__rtruediv__') + def __truediv__(self, other): + return self * (self.one / other) + + @call_highest_priority('__rmatmul__') + def __matmul__(self, other): + self, other, T = _unify_with_other(self, other) + + if T != "is_matrix": + return NotImplemented + + return self.__mul__(other) + + def __mod__(self, other): + return self.applyfunc(lambda x: x % other) + + @call_highest_priority('__rmul__') + def __mul__(self, other): + """Return self*other where other is either a scalar or a matrix + of compatible dimensions. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> 2*A == A*2 == Matrix([[2, 4, 6], [8, 10, 12]]) + True + >>> B = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> A*B + Matrix([ + [30, 36, 42], + [66, 81, 96]]) + >>> B*A + Traceback (most recent call last): + ... + ShapeError: Matrices size mismatch. + >>> + + See Also + ======== + + matrix_multiply_elementwise + """ + + return self.multiply(other) + + def multiply(self, other, dotprodsimp=None): + """Same as __mul__() but with optional simplification. + + Parameters + ========== + + dotprodsimp : bool, optional + Specifies whether intermediate term algebraic simplification is used + during matrix multiplications to control expression blowup and thus + speed up calculation. Default is off. + """ + + isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) + + self, other, T = _unify_with_other(self, other) + + if T == "possible_scalar": + try: + return self._eval_scalar_mul(other) + except TypeError: + return NotImplemented + + elif T == "is_matrix": + + if self.shape[1] != other.shape[0]: + raise ShapeError(f"Matrix size mismatch: {self.shape} * {other.shape}.") + + m = self._eval_matrix_mul(other) + + if isimpbool: + m = m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) + + return m + + else: + return NotImplemented + + def multiply_elementwise(self, other): + """Return the Hadamard product (elementwise product) of A and B + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) + >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) + >>> A.multiply_elementwise(B) + Matrix([ + [ 0, 10, 200], + [300, 40, 5]]) + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.cross + sympy.matrices.matrixbase.MatrixBase.dot + multiply + """ + if self.shape != other.shape: + raise ShapeError("Matrix shapes must agree {} != {}".format(self.shape, other.shape)) + + return self._eval_matrix_mul_elementwise(other) + + def __neg__(self): + return self._eval_scalar_mul(-1) + + @call_highest_priority('__rpow__') + def __pow__(self, exp): + """Return self**exp a scalar or symbol.""" + + return self.pow(exp) + + + def pow(self, exp, method=None): + r"""Return self**exp a scalar or symbol. + + Parameters + ========== + + method : multiply, mulsimp, jordan, cayley + If multiply then it returns exponentiation using recursion. + If jordan then Jordan form exponentiation will be used. + If cayley then the exponentiation is done using Cayley-Hamilton + theorem. + If mulsimp then the exponentiation is done using recursion + with dotprodsimp. This specifies whether intermediate term + algebraic simplification is used during naive matrix power to + control expression blowup and thus speed up calculation. + If None, then it heuristically decides which method to use. + + """ + + if method is not None and method not in ['multiply', 'mulsimp', 'jordan', 'cayley']: + raise TypeError('No such method') + if self.rows != self.cols: + raise NonSquareMatrixError() + a = self + jordan_pow = getattr(a, '_matrix_pow_by_jordan_blocks', None) + exp = sympify(exp) + + if exp.is_zero: + return a._new(a.rows, a.cols, lambda i, j: int(i == j)) + if exp == 1: + return a + + diagonal = getattr(a, 'is_diagonal', None) + if diagonal is not None and diagonal(): + return a._new(a.rows, a.cols, lambda i, j: a[i,j]**exp if i == j else 0) + + if exp.is_Number and exp % 1 == 0: + if a.rows == 1: + return a._new([[a[0]**exp]]) + if exp < 0: + exp = -exp + a = a.inv() + # When certain conditions are met, + # Jordan block algorithm is faster than + # computation by recursion. + if method == 'jordan': + try: + return jordan_pow(exp) + except MatrixError: + if method == 'jordan': + raise + + elif method == 'cayley': + if not exp.is_Number or exp % 1 != 0: + raise ValueError("cayley method is only valid for integer powers") + return a._eval_pow_by_cayley(exp) + + elif method == "mulsimp": + if not exp.is_Number or exp % 1 != 0: + raise ValueError("mulsimp method is only valid for integer powers") + return a._eval_pow_by_recursion_dotprodsimp(exp) + + elif method == "multiply": + if not exp.is_Number or exp % 1 != 0: + raise ValueError("multiply method is only valid for integer powers") + return a._eval_pow_by_recursion(exp) + + elif method is None and exp.is_Number and exp % 1 == 0: + if exp.is_Float: + exp = Integer(exp) + # Decide heuristically which method to apply + if a.rows == 2 and exp > 100000: + return jordan_pow(exp) + elif _get_intermediate_simp_bool(True, None): + return a._eval_pow_by_recursion_dotprodsimp(exp) + elif exp > 10000: + return a._eval_pow_by_cayley(exp) + else: + return a._eval_pow_by_recursion(exp) + + if jordan_pow: + try: + return jordan_pow(exp) + except NonInvertibleMatrixError: + # Raised by jordan_pow on zero determinant matrix unless exp is + # definitely known to be a non-negative integer. + # Here we raise if n is definitely not a non-negative integer + # but otherwise we can leave this as an unevaluated MatPow. + if exp.is_integer is False or exp.is_nonnegative is False: + raise + + from sympy.matrices.expressions import MatPow + return MatPow(a, exp) + + @call_highest_priority('__add__') + def __radd__(self, other): + return self.__add__(other) + + @call_highest_priority('__matmul__') + def __rmatmul__(self, other): + self, other, T = _unify_with_other(self, other) + + if T != "is_matrix": + return NotImplemented + + return self.__rmul__(other) + + @call_highest_priority('__mul__') + def __rmul__(self, other): + return self.rmultiply(other) + + def rmultiply(self, other, dotprodsimp=None): + """Same as __rmul__() but with optional simplification. + + Parameters + ========== + + dotprodsimp : bool, optional + Specifies whether intermediate term algebraic simplification is used + during matrix multiplications to control expression blowup and thus + speed up calculation. Default is off. + """ + isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) + self, other, T = _unify_with_other(self, other) + + if T == "possible_scalar": + try: + return self._eval_scalar_rmul(other) + except TypeError: + return NotImplemented + + elif T == "is_matrix": + if self.shape[0] != other.shape[1]: + raise ShapeError("Matrix size mismatch.") + + m = self._eval_matrix_rmul(other) + + if isimpbool: + return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) + + return m + + else: + return NotImplemented + + @call_highest_priority('__sub__') + def __rsub__(self, a): + return (-self) + a + + @call_highest_priority('__rsub__') + def __sub__(self, a): + return self + (-a) + + def _eval_det_bareiss(self, iszerofunc=_is_zero_after_expand_mul): + return _det_bareiss(self, iszerofunc=iszerofunc) + + def _eval_det_berkowitz(self): + return _det_berkowitz(self) + + def _eval_det_lu(self, iszerofunc=_iszero, simpfunc=None): + return _det_LU(self, iszerofunc=iszerofunc, simpfunc=simpfunc) + + def _eval_det_bird(self): + return _det_bird(self) + + def _eval_det_laplace(self): + return _det_laplace(self) + + def _eval_determinant(self): # for expressions.determinant.Determinant + return _det(self) + + def adjugate(self, method="berkowitz"): + return _adjugate(self, method=method) + + def charpoly(self, x='lambda', simplify=_utilities_simplify): + return _charpoly(self, x=x, simplify=simplify) + + def cofactor(self, i, j, method="berkowitz"): + return _cofactor(self, i, j, method=method) + + def cofactor_matrix(self, method="berkowitz"): + return _cofactor_matrix(self, method=method) + + def det(self, method="bareiss", iszerofunc=None): + return _det(self, method=method, iszerofunc=iszerofunc) + + def per(self): + return _per(self) + + def minor(self, i, j, method="berkowitz"): + return _minor(self, i, j, method=method) + + def minor_submatrix(self, i, j): + return _minor_submatrix(self, i, j) + + _find_reasonable_pivot.__doc__ = _find_reasonable_pivot.__doc__ + _find_reasonable_pivot_naive.__doc__ = _find_reasonable_pivot_naive.__doc__ + _eval_det_bareiss.__doc__ = _det_bareiss.__doc__ + _eval_det_berkowitz.__doc__ = _det_berkowitz.__doc__ + _eval_det_bird.__doc__ = _det_bird.__doc__ + _eval_det_laplace.__doc__ = _det_laplace.__doc__ + _eval_det_lu.__doc__ = _det_LU.__doc__ + _eval_determinant.__doc__ = _det.__doc__ + adjugate.__doc__ = _adjugate.__doc__ + charpoly.__doc__ = _charpoly.__doc__ + cofactor.__doc__ = _cofactor.__doc__ + cofactor_matrix.__doc__ = _cofactor_matrix.__doc__ + det.__doc__ = _det.__doc__ + per.__doc__ = _per.__doc__ + minor.__doc__ = _minor.__doc__ + minor_submatrix.__doc__ = _minor_submatrix.__doc__ + + def echelon_form(self, iszerofunc=_iszero, simplify=False, with_pivots=False): + return _echelon_form(self, iszerofunc=iszerofunc, simplify=simplify, + with_pivots=with_pivots) + + @property + def is_echelon(self): + return _is_echelon(self) + + def rank(self, iszerofunc=_iszero, simplify=False): + return _rank(self, iszerofunc=iszerofunc, simplify=simplify) + + def rref_rhs(self, rhs): + """Return reduced row-echelon form of matrix, matrix showing + rhs after reduction steps. ``rhs`` must have the same number + of rows as ``self``. + + Examples + ======== + + >>> from sympy import Matrix, symbols + >>> r1, r2 = symbols('r1 r2') + >>> Matrix([[1, 1], [2, 1]]).rref_rhs(Matrix([r1, r2])) + (Matrix([ + [1, 0], + [0, 1]]), Matrix([ + [ -r1 + r2], + [2*r1 - r2]])) + """ + r, _ = _rref(self.hstack(self, self.eye(self.rows), rhs)) + return r[:, :self.cols], r[:, -rhs.cols:] + + def rref(self, iszerofunc=_iszero, simplify=False, pivots=True, + normalize_last=True): + return _rref(self, iszerofunc=iszerofunc, simplify=simplify, + pivots=pivots, normalize_last=normalize_last) + + echelon_form.__doc__ = _echelon_form.__doc__ + is_echelon.__doc__ = _is_echelon.__doc__ + rank.__doc__ = _rank.__doc__ + rref.__doc__ = _rref.__doc__ + + def _normalize_op_args(self, op, col, k, col1, col2, error_str="col"): + """Validate the arguments for a row/column operation. ``error_str`` + can be one of "row" or "col" depending on the arguments being parsed.""" + if op not in ["n->kn", "n<->m", "n->n+km"]: + raise ValueError("Unknown {} operation '{}'. Valid col operations " + "are 'n->kn', 'n<->m', 'n->n+km'".format(error_str, op)) + + # define self_col according to error_str + self_cols = self.cols if error_str == 'col' else self.rows + + # normalize and validate the arguments + if op == "n->kn": + col = col if col is not None else col1 + if col is None or k is None: + raise ValueError("For a {0} operation 'n->kn' you must provide the " + "kwargs `{0}` and `k`".format(error_str)) + if not 0 <= col < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col)) + + elif op == "n<->m": + # we need two cols to swap. It does not matter + # how they were specified, so gather them together and + # remove `None` + cols = {col, k, col1, col2}.difference([None]) + if len(cols) > 2: + # maybe the user left `k` by mistake? + cols = {col, col1, col2}.difference([None]) + if len(cols) != 2: + raise ValueError("For a {0} operation 'n<->m' you must provide the " + "kwargs `{0}1` and `{0}2`".format(error_str)) + col1, col2 = cols + if not 0 <= col1 < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col1)) + if not 0 <= col2 < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col2)) + + elif op == "n->n+km": + col = col1 if col is None else col + col2 = col1 if col2 is None else col2 + if col is None or col2 is None or k is None: + raise ValueError("For a {0} operation 'n->n+km' you must provide the " + "kwargs `{0}`, `k`, and `{0}2`".format(error_str)) + if col == col2: + raise ValueError("For a {0} operation 'n->n+km' `{0}` and `{0}2` must " + "be different.".format(error_str)) + if not 0 <= col < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col)) + if not 0 <= col2 < self_cols: + raise ValueError("This matrix does not have a {} '{}'".format(error_str, col2)) + + else: + raise ValueError('invalid operation %s' % repr(op)) + + return op, col, k, col1, col2 + + def _eval_col_op_multiply_col_by_const(self, col, k): + def entry(i, j): + if j == col: + return k * self[i, j] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_col_op_swap(self, col1, col2): + def entry(i, j): + if j == col1: + return self[i, col2] + elif j == col2: + return self[i, col1] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_col_op_add_multiple_to_other_col(self, col, k, col2): + def entry(i, j): + if j == col: + return self[i, j] + k * self[i, col2] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_row_op_swap(self, row1, row2): + def entry(i, j): + if i == row1: + return self[row2, j] + elif i == row2: + return self[row1, j] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_row_op_multiply_row_by_const(self, row, k): + def entry(i, j): + if i == row: + return k * self[i, j] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def _eval_row_op_add_multiple_to_other_row(self, row, k, row2): + def entry(i, j): + if i == row: + return self[i, j] + k * self[row2, j] + return self[i, j] + return self._new(self.rows, self.cols, entry) + + def elementary_col_op(self, op="n->kn", col=None, k=None, col1=None, col2=None): + """Performs the elementary column operation `op`. + + `op` may be one of + + * ``"n->kn"`` (column n goes to k*n) + * ``"n<->m"`` (swap column n and column m) + * ``"n->n+km"`` (column n goes to column n + k*column m) + + Parameters + ========== + + op : string; the elementary row operation + col : the column to apply the column operation + k : the multiple to apply in the column operation + col1 : one column of a column swap + col2 : second column of a column swap or column "m" in the column operation + "n->n+km" + """ + + op, col, k, col1, col2 = self._normalize_op_args(op, col, k, col1, col2, "col") + + # now that we've validated, we're all good to dispatch + if op == "n->kn": + return self._eval_col_op_multiply_col_by_const(col, k) + if op == "n<->m": + return self._eval_col_op_swap(col1, col2) + if op == "n->n+km": + return self._eval_col_op_add_multiple_to_other_col(col, k, col2) + + def elementary_row_op(self, op="n->kn", row=None, k=None, row1=None, row2=None): + """Performs the elementary row operation `op`. + + `op` may be one of + + * ``"n->kn"`` (row n goes to k*n) + * ``"n<->m"`` (swap row n and row m) + * ``"n->n+km"`` (row n goes to row n + k*row m) + + Parameters + ========== + + op : string; the elementary row operation + row : the row to apply the row operation + k : the multiple to apply in the row operation + row1 : one row of a row swap + row2 : second row of a row swap or row "m" in the row operation + "n->n+km" + """ + + op, row, k, row1, row2 = self._normalize_op_args(op, row, k, row1, row2, "row") + + # now that we've validated, we're all good to dispatch + if op == "n->kn": + return self._eval_row_op_multiply_row_by_const(row, k) + if op == "n<->m": + return self._eval_row_op_swap(row1, row2) + if op == "n->n+km": + return self._eval_row_op_add_multiple_to_other_row(row, k, row2) + + def columnspace(self, simplify=False): + return _columnspace(self, simplify=simplify) + + def nullspace(self, simplify=False, iszerofunc=_iszero): + return _nullspace(self, simplify=simplify, iszerofunc=iszerofunc) + + def rowspace(self, simplify=False): + return _rowspace(self, simplify=simplify) + + # This is a classmethod but is converted to such later in order to allow + # assignment of __doc__ since that does not work for already wrapped + # classmethods in Python 3.6. + def orthogonalize(cls, *vecs, **kwargs): + return _orthogonalize(cls, *vecs, **kwargs) + + columnspace.__doc__ = _columnspace.__doc__ + nullspace.__doc__ = _nullspace.__doc__ + rowspace.__doc__ = _rowspace.__doc__ + orthogonalize.__doc__ = _orthogonalize.__doc__ + + orthogonalize = classmethod(orthogonalize) # type:ignore + + def eigenvals(self, error_when_incomplete=True, **flags): + return _eigenvals(self, error_when_incomplete=error_when_incomplete, **flags) + + def eigenvects(self, error_when_incomplete=True, iszerofunc=_iszero, **flags): + return _eigenvects(self, error_when_incomplete=error_when_incomplete, + iszerofunc=iszerofunc, **flags) + + def is_diagonalizable(self, reals_only=False, **kwargs): + return _is_diagonalizable(self, reals_only=reals_only, **kwargs) + + def diagonalize(self, reals_only=False, sort=False, normalize=False): + return _diagonalize(self, reals_only=reals_only, sort=sort, + normalize=normalize) + + def bidiagonalize(self, upper=True): + return _bidiagonalize(self, upper=upper) + + def bidiagonal_decomposition(self, upper=True): + return _bidiagonal_decomposition(self, upper=upper) + + @property + def is_positive_definite(self): + return _is_positive_definite(self) + + @property + def is_positive_semidefinite(self): + return _is_positive_semidefinite(self) + + @property + def is_negative_definite(self): + return _is_negative_definite(self) + + @property + def is_negative_semidefinite(self): + return _is_negative_semidefinite(self) + + @property + def is_indefinite(self): + return _is_indefinite(self) + + def jordan_form(self, calc_transform=True, **kwargs): + return _jordan_form(self, calc_transform=calc_transform, **kwargs) + + def left_eigenvects(self, **flags): + return _left_eigenvects(self, **flags) + + def singular_values(self): + return _singular_values(self) + + eigenvals.__doc__ = _eigenvals.__doc__ + eigenvects.__doc__ = _eigenvects.__doc__ + is_diagonalizable.__doc__ = _is_diagonalizable.__doc__ + diagonalize.__doc__ = _diagonalize.__doc__ + is_positive_definite.__doc__ = _is_positive_definite.__doc__ + is_positive_semidefinite.__doc__ = _is_positive_semidefinite.__doc__ + is_negative_definite.__doc__ = _is_negative_definite.__doc__ + is_negative_semidefinite.__doc__ = _is_negative_semidefinite.__doc__ + is_indefinite.__doc__ = _is_indefinite.__doc__ + jordan_form.__doc__ = _jordan_form.__doc__ + left_eigenvects.__doc__ = _left_eigenvects.__doc__ + singular_values.__doc__ = _singular_values.__doc__ + bidiagonalize.__doc__ = _bidiagonalize.__doc__ + bidiagonal_decomposition.__doc__ = _bidiagonal_decomposition.__doc__ + + def diff(self, *args, evaluate=True, **kwargs): + """Calculate the derivative of each element in the matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.diff(x) + Matrix([ + [1, 0], + [0, 0]]) + + See Also + ======== + + integrate + limit + """ + # XXX this should be handled here rather than in Derivative + from sympy.tensor.array.array_derivatives import ArrayDerivative + deriv = ArrayDerivative(self, *args, evaluate=evaluate) + # XXX This can rather changed to always return immutable matrix + if not isinstance(self, Basic) and evaluate: + return deriv.as_mutable() + return deriv + + def _eval_derivative(self, arg): + return self.applyfunc(lambda x: x.diff(arg)) + + def integrate(self, *args, **kwargs): + """Integrate each element of the matrix. ``args`` will + be passed to the ``integrate`` function. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.integrate((x, )) + Matrix([ + [x**2/2, x*y], + [ x, 0]]) + >>> M.integrate((x, 0, 2)) + Matrix([ + [2, 2*y], + [2, 0]]) + + See Also + ======== + + limit + diff + """ + return self.applyfunc(lambda x: x.integrate(*args, **kwargs)) + + def jacobian(self, X): + """Calculates the Jacobian matrix (derivative of a vector-valued function). + + Parameters + ========== + + ``self`` : vector of expressions representing functions f_i(x_1, ..., x_n). + X : set of x_i's in order, it can be a list or a Matrix + + Both ``self`` and X can be a row or a column matrix in any order + (i.e., jacobian() should always work). + + Examples + ======== + + >>> from sympy import sin, cos, Matrix + >>> from sympy.abc import rho, phi + >>> X = Matrix([rho*cos(phi), rho*sin(phi), rho**2]) + >>> Y = Matrix([rho, phi]) + >>> X.jacobian(Y) + Matrix([ + [cos(phi), -rho*sin(phi)], + [sin(phi), rho*cos(phi)], + [ 2*rho, 0]]) + >>> X = Matrix([rho*cos(phi), rho*sin(phi)]) + >>> X.jacobian(Y) + Matrix([ + [cos(phi), -rho*sin(phi)], + [sin(phi), rho*cos(phi)]]) + + See Also + ======== + + hessian + wronskian + """ + from sympy.matrices.matrixbase import MatrixBase + if not isinstance(X, MatrixBase): + X = self._new(X) + # Both X and ``self`` can be a row or a column matrix, so we need to make + # sure all valid combinations work, but everything else fails: + if self.shape[0] == 1: + m = self.shape[1] + elif self.shape[1] == 1: + m = self.shape[0] + else: + raise TypeError("``self`` must be a row or a column matrix") + if X.shape[0] == 1: + n = X.shape[1] + elif X.shape[1] == 1: + n = X.shape[0] + else: + raise TypeError("X must be a row or a column matrix") + + # m is the number of functions and n is the number of variables + # computing the Jacobian is now easy: + return self._new(m, n, lambda j, i: self[j].diff(X[i])) + + def limit(self, *args): + """Calculate the limit of each element in the matrix. + ``args`` will be passed to the ``limit`` function. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x, y + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.limit(x, 2) + Matrix([ + [2, y], + [1, 0]]) + + See Also + ======== + + integrate + diff + """ + return self.applyfunc(lambda x: x.limit(*args)) + + def berkowitz_charpoly(self, x=Dummy('lambda'), simplify=_utilities_simplify): + return self.charpoly(x=x) + + def berkowitz_det(self): + """Computes determinant using Berkowitz method. + + See Also + ======== + + det + """ + return self.det(method='berkowitz') + + def berkowitz_eigenvals(self, **flags): + """Computes eigenvalues of a Matrix using Berkowitz method.""" + return self.eigenvals(**flags) + + def berkowitz_minors(self): + """Computes principal minors using Berkowitz method.""" + sign, minors = self.one, [] + + for poly in self.berkowitz(): + minors.append(sign * poly[-1]) + sign = -sign + + return tuple(minors) + + def berkowitz(self): + from sympy.matrices import zeros + berk = ((1,),) + if not self: + return berk + + if not self.is_square: + raise NonSquareMatrixError() + + A, N = self, self.rows + transforms = [0] * (N - 1) + + for n in range(N, 1, -1): + T, k = zeros(n + 1, n), n - 1 + + R, C = -A[k, :k], A[:k, k] + A, a = A[:k, :k], -A[k, k] + + items = [C] + + for i in range(0, n - 2): + items.append(A * items[i]) + + for i, B in enumerate(items): + items[i] = (R * B)[0, 0] + + items = [self.one, a] + items + + for i in range(n): + T[i:, i] = items[:n - i + 1] + + transforms[k - 1] = T + + polys = [self._new([self.one, -A[0, 0]])] + + for i, T in enumerate(transforms): + polys.append(T * polys[i]) + + return berk + tuple(map(tuple, polys)) + + def cofactorMatrix(self, method="berkowitz"): + return self.cofactor_matrix(method=method) + + def det_bareis(self): + return _det_bareiss(self) + + def det_LU_decomposition(self): + """Compute matrix determinant using LU decomposition. + + + Note that this method fails if the LU decomposition itself + fails. In particular, if the matrix has no inverse this method + will fail. + + TODO: Implement algorithm for sparse matrices (SFF), + http://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps. + + See Also + ======== + + + det + berkowitz_det + """ + return self.det(method='lu') + + def jordan_cell(self, eigenval, n): + return self.jordan_block(size=n, eigenvalue=eigenval) + + def jordan_cells(self, calc_transformation=True): + P, J = self.jordan_form() + return P, J.get_diag_blocks() + + def minorEntry(self, i, j, method="berkowitz"): + return self.minor(i, j, method=method) + + def minorMatrix(self, i, j): + return self.minor_submatrix(i, j) + + def permuteBkwd(self, perm): + """Permute the rows of the matrix with the given permutation in reverse.""" + return self.permute_rows(perm, direction='backward') + + def permuteFwd(self, perm): + """Permute the rows of the matrix with the given permutation.""" + return self.permute_rows(perm, direction='forward') + + @property + def kind(self) -> MatrixKind: + elem_kinds = {e.kind for e in self.flat()} + if len(elem_kinds) == 1: + elemkind, = elem_kinds + else: + elemkind = UndefinedKind + return MatrixKind(elemkind) + + def flat(self): + """ + Returns a flat list of all elements in the matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix([[0, 2], [3, 4]]) + >>> m.flat() + [0, 2, 3, 4] + + See Also + ======== + + tolist + values + """ + return [self[i, j] for i in range(self.rows) for j in range(self.cols)] + + def __array__(self, dtype=object, copy=None): + if copy is not None and not copy: + raise TypeError("Cannot implement copy=False when converting Matrix to ndarray") + from .dense import matrix2numpy + return matrix2numpy(self, dtype=dtype) + + def __len__(self): + """Return the number of elements of ``self``. + + Implemented mainly so bool(Matrix()) == False. + """ + return self.rows * self.cols + + def _matrix_pow_by_jordan_blocks(self, num): + from sympy.matrices import diag, MutableMatrix + + def jordan_cell_power(jc, n): + N = jc.shape[0] + l = jc[0,0] + if l.is_zero: + if N == 1 and n.is_nonnegative: + jc[0,0] = l**n + elif not (n.is_integer and n.is_nonnegative): + raise NonInvertibleMatrixError("Non-invertible matrix can only be raised to a nonnegative integer") + else: + for i in range(N): + jc[0,i] = KroneckerDelta(i, n) + else: + for i in range(N): + bn = binomial(n, i) + if isinstance(bn, binomial): + bn = bn._eval_expand_func() + jc[0,i] = l**(n-i)*bn + for i in range(N): + for j in range(1, N-i): + jc[j,i+j] = jc [j-1,i+j-1] + + P, J = self.jordan_form() + jordan_cells = J.get_diag_blocks() + # Make sure jordan_cells matrices are mutable: + jordan_cells = [MutableMatrix(j) for j in jordan_cells] + for j in jordan_cells: + jordan_cell_power(j, num) + return self._new(P.multiply(diag(*jordan_cells)) + .multiply(P.inv())) + + def __str__(self): + if S.Zero in self.shape: + return 'Matrix(%s, %s, [])' % (self.rows, self.cols) + return "Matrix(%s)" % str(self.tolist()) + + def _format_str(self, printer=None): + if not printer: + printer = StrPrinter() + # Handle zero dimensions: + if S.Zero in self.shape: + return 'Matrix(%s, %s, [])' % (self.rows, self.cols) + if self.rows == 1: + return "Matrix([%s])" % self.table(printer, rowsep=',\n') + return "Matrix([\n%s])" % self.table(printer, rowsep=',\n') + + @classmethod + def irregular(cls, ntop, *matrices, **kwargs): + """Return a matrix filled by the given matrices which + are listed in order of appearance from left to right, top to + bottom as they first appear in the matrix. They must fill the + matrix completely. + + Examples + ======== + + >>> from sympy import ones, Matrix + >>> Matrix.irregular(3, ones(2,1), ones(3,3)*2, ones(2,2)*3, + ... ones(1,1)*4, ones(2,2)*5, ones(1,2)*6, ones(1,2)*7) + Matrix([ + [1, 2, 2, 2, 3, 3], + [1, 2, 2, 2, 3, 3], + [4, 2, 2, 2, 5, 5], + [6, 6, 7, 7, 5, 5]]) + """ + ntop = as_int(ntop) + # make sure we are working with explicit matrices + b = [i.as_explicit() if hasattr(i, 'as_explicit') else i + for i in matrices] + q = list(range(len(b))) + dat = [i.rows for i in b] + active = [q.pop(0) for _ in range(ntop)] + cols = sum(b[i].cols for i in active) + rows = [] + while any(dat): + r = [] + for a, j in enumerate(active): + r.extend(b[j][-dat[j], :]) + dat[j] -= 1 + if dat[j] == 0 and q: + active[a] = q.pop(0) + if len(r) != cols: + raise ValueError(filldedent(''' + Matrices provided do not appear to fill + the space completely.''')) + rows.append(r) + return cls._new(rows) + + @classmethod + def _handle_ndarray(cls, arg): + # NumPy array or matrix or some other object that implements + # __array__. So let's first use this method to get a + # numpy.array() and then make a Python list out of it. + arr = arg.__array__() + if len(arr.shape) == 2: + rows, cols = arr.shape[0], arr.shape[1] + flat_list = [cls._sympify(i) for i in arr.ravel()] + return rows, cols, flat_list + elif len(arr.shape) == 1: + flat_list = [cls._sympify(i) for i in arr] + return arr.shape[0], 1, flat_list + else: + raise NotImplementedError( + "SymPy supports just 1D and 2D matrices") + + @classmethod + def _handle_creation_inputs(cls, *args, **kwargs): + """Return the number of rows, cols and flat matrix elements. + + Examples + ======== + + >>> from sympy import Matrix, I + + Matrix can be constructed as follows: + + * from a nested list of iterables + + >>> Matrix( ((1, 2+I), (3, 4)) ) + Matrix([ + [1, 2 + I], + [3, 4]]) + + * from un-nested iterable (interpreted as a column) + + >>> Matrix( [1, 2] ) + Matrix([ + [1], + [2]]) + + * from un-nested iterable with dimensions + + >>> Matrix(1, 2, [1, 2] ) + Matrix([[1, 2]]) + + * from no arguments (a 0 x 0 matrix) + + >>> Matrix() + Matrix(0, 0, []) + + * from a rule + + >>> Matrix(2, 2, lambda i, j: i/(j + 1) ) + Matrix([ + [0, 0], + [1, 1/2]]) + + See Also + ======== + irregular - filling a matrix with irregular blocks + """ + from sympy.matrices import SparseMatrix + from sympy.matrices.expressions.matexpr import MatrixSymbol + from sympy.matrices.expressions.blockmatrix import BlockMatrix + + flat_list = None + + if len(args) == 1: + # Matrix(SparseMatrix(...)) + if isinstance(args[0], SparseMatrix): + return args[0].rows, args[0].cols, flatten(args[0].tolist()) + + # Matrix(Matrix(...)) + elif isinstance(args[0], MatrixBase): + return args[0].rows, args[0].cols, args[0].flat() + + # Matrix(MatrixSymbol('X', 2, 2)) + elif isinstance(args[0], Basic) and args[0].is_Matrix: + return args[0].rows, args[0].cols, args[0].as_explicit().flat() + + elif isinstance(args[0], mp.matrix): + M = args[0] + flat_list = [cls._sympify(x) for x in M] + return M.rows, M.cols, flat_list + + # Matrix(numpy.ones((2, 2))) + elif hasattr(args[0], "__array__"): + return cls._handle_ndarray(args[0]) + + # Matrix([1, 2, 3]) or Matrix([[1, 2], [3, 4]]) + elif is_sequence(args[0]) \ + and not isinstance(args[0], DeferredVector): + dat = list(args[0]) + ismat = lambda i: isinstance(i, MatrixBase) and ( + evaluate or isinstance(i, (BlockMatrix, MatrixSymbol))) + raw = lambda i: is_sequence(i) and not ismat(i) + evaluate = kwargs.get('evaluate', True) + + + if evaluate: + + def make_explicit(x): + """make Block and Symbol explicit""" + if isinstance(x, BlockMatrix): + return x.as_explicit() + elif isinstance(x, MatrixSymbol) and all(_.is_Integer for _ in x.shape): + return x.as_explicit() + else: + return x + + def make_explicit_row(row): + # Could be list or could be list of lists + if isinstance(row, (list, tuple)): + return [make_explicit(x) for x in row] + else: + return make_explicit(row) + + if isinstance(dat, (list, tuple)): + dat = [make_explicit_row(row) for row in dat] + + if len(dat) == 0: + rows = cols = 0 + flat_list = [] + elif all(raw(i) for i in dat) and len(dat[0]) == 0: + if not all(len(i) == 0 for i in dat): + raise ValueError('mismatched dimensions') + rows = len(dat) + cols = 0 + flat_list = [] + elif not any(raw(i) or ismat(i) for i in dat): + # a column as a list of values + flat_list = [cls._sympify(i) for i in dat] + rows = len(flat_list) + cols = 1 if rows else 0 + elif evaluate and all(ismat(i) for i in dat): + # a column as a list of matrices + ncol = {i.cols for i in dat if any(i.shape)} + if ncol: + if len(ncol) != 1: + raise ValueError('mismatched dimensions') + flat_list = [_ for i in dat for r in i.tolist() for _ in r] + cols = ncol.pop() + rows = len(flat_list)//cols + else: + rows = cols = 0 + flat_list = [] + elif evaluate and any(ismat(i) for i in dat): + ncol = set() + flat_list = [] + for i in dat: + if ismat(i): + flat_list.extend( + [k for j in i.tolist() for k in j]) + if any(i.shape): + ncol.add(i.cols) + elif raw(i): + if i: + ncol.add(len(i)) + flat_list.extend([cls._sympify(ij) for ij in i]) + else: + ncol.add(1) + flat_list.append(i) + if len(ncol) > 1: + raise ValueError('mismatched dimensions') + cols = ncol.pop() + rows = len(flat_list)//cols + else: + # list of lists; each sublist is a logical row + # which might consist of many rows if the values in + # the row are matrices + flat_list = [] + ncol = set() + rows = cols = 0 + for row in dat: + if not is_sequence(row) and \ + not getattr(row, 'is_Matrix', False): + raise ValueError('expecting list of lists') + + if hasattr(row, '__array__'): + if 0 in row.shape: + continue + + if evaluate and all(ismat(i) for i in row): + r, c, flatT = cls._handle_creation_inputs( + [i.T for i in row]) + T = reshape(flatT, [c]) + flat = \ + [T[i][j] for j in range(c) for i in range(r)] + r, c = c, r + else: + r = 1 + if getattr(row, 'is_Matrix', False): + c = 1 + flat = [row] + else: + c = len(row) + flat = [cls._sympify(i) for i in row] + ncol.add(c) + if len(ncol) > 1: + raise ValueError('mismatched dimensions') + flat_list.extend(flat) + rows += r + cols = ncol.pop() if ncol else 0 + + elif len(args) == 3: + rows = as_int(args[0]) + cols = as_int(args[1]) + + if rows < 0 or cols < 0: + raise ValueError("Cannot create a {} x {} matrix. " + "Both dimensions must be positive".format(rows, cols)) + + # Matrix(2, 2, lambda i, j: i+j) + if len(args) == 3 and isinstance(args[2], Callable): + op = args[2] + flat_list = [] + for i in range(rows): + flat_list.extend( + [cls._sympify(op(cls._sympify(i), cls._sympify(j))) + for j in range(cols)]) + + # Matrix(2, 2, [1, 2, 3, 4]) + elif len(args) == 3 and is_sequence(args[2]): + flat_list = args[2] + if len(flat_list) != rows * cols: + raise ValueError( + 'List length should be equal to rows*columns') + flat_list = [cls._sympify(i) for i in flat_list] + + + # Matrix() + elif len(args) == 0: + # Empty Matrix + rows = cols = 0 + flat_list = [] + + if flat_list is None: + raise TypeError(filldedent(''' + Data type not understood; expecting list of lists + or lists of values.''')) + + return rows, cols, flat_list + + def _setitem(self, key, value): + """Helper to set value at location given by key. + + Examples + ======== + + >>> from sympy import Matrix, I, zeros, ones + >>> m = Matrix(((1, 2+I), (3, 4))) + >>> m + Matrix([ + [1, 2 + I], + [3, 4]]) + >>> m[1, 0] = 9 + >>> m + Matrix([ + [1, 2 + I], + [9, 4]]) + >>> m[1, 0] = [[0, 1]] + + To replace row r you assign to position r*m where m + is the number of columns: + + >>> M = zeros(4) + >>> m = M.cols + >>> M[3*m] = ones(1, m)*2; M + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [2, 2, 2, 2]]) + + And to replace column c you can assign to position c: + + >>> M[2] = ones(m, 1)*4; M + Matrix([ + [0, 0, 4, 0], + [0, 0, 4, 0], + [0, 0, 4, 0], + [2, 2, 4, 2]]) + """ + from .dense import Matrix + + is_slice = isinstance(key, slice) + i, j = key = self.key2ij(key) + is_mat = isinstance(value, MatrixBase) + if isinstance(i, slice) or isinstance(j, slice): + if is_mat: + self.copyin_matrix(key, value) + return + if not isinstance(value, Expr) and is_sequence(value): + self.copyin_list(key, value) + return + raise ValueError('unexpected value: %s' % value) + else: + if (not is_mat and + not isinstance(value, Basic) and is_sequence(value)): + value = Matrix(value) + is_mat = True + if is_mat: + if is_slice: + key = (slice(*divmod(i, self.cols)), + slice(*divmod(j, self.cols))) + else: + key = (slice(i, i + value.rows), + slice(j, j + value.cols)) + self.copyin_matrix(key, value) + else: + return i, j, self._sympify(value) + return + + def add(self, b): + """Return self + b.""" + return self + b + + def condition_number(self): + """Returns the condition number of a matrix. + + This is the maximum singular value divided by the minimum singular value + + Examples + ======== + + >>> from sympy import Matrix, S + >>> A = Matrix([[1, 0, 0], [0, 10, 0], [0, 0, S.One/10]]) + >>> A.condition_number() + 100 + + See Also + ======== + + singular_values + """ + + if not self: + return self.zero + singularvalues = self.singular_values() + return Max(*singularvalues) / Min(*singularvalues) + + def copy(self): + """ + Returns the copy of a matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix(2, 2, [1, 2, 3, 4]) + >>> A.copy() + Matrix([ + [1, 2], + [3, 4]]) + + """ + return self._new(self.rows, self.cols, self.flat()) + + def cross(self, b): + r""" + Return the cross product of ``self`` and ``b`` relaxing the condition + of compatible dimensions: if each has 3 elements, a matrix of the + same type and shape as ``self`` will be returned. If ``b`` has the same + shape as ``self`` then common identities for the cross product (like + `a \times b = - b \times a`) will hold. + + Parameters + ========== + b : 3x1 or 1x3 Matrix + + See Also + ======== + + dot + hat + vee + multiply + multiply_elementwise + """ + from sympy.matrices.expressions.matexpr import MatrixExpr + + if not isinstance(b, (MatrixBase, MatrixExpr)): + raise TypeError( + "{} must be a Matrix, not {}.".format(b, type(b))) + + if not (self.rows * self.cols == b.rows * b.cols == 3): + raise ShapeError("Dimensions incorrect for cross product: %s x %s" % + ((self.rows, self.cols), (b.rows, b.cols))) + else: + return self._new(self.rows, self.cols, ( + (self[1] * b[2] - self[2] * b[1]), + (self[2] * b[0] - self[0] * b[2]), + (self[0] * b[1] - self[1] * b[0]))) + + def hat(self): + r""" + Return the skew-symmetric matrix representing the cross product, + so that ``self.hat() * b`` is equivalent to ``self.cross(b)``. + + Examples + ======== + + Calling ``hat`` creates a skew-symmetric 3x3 Matrix from a 3x1 Matrix: + + >>> from sympy import Matrix + >>> a = Matrix([1, 2, 3]) + >>> a.hat() + Matrix([ + [ 0, -3, 2], + [ 3, 0, -1], + [-2, 1, 0]]) + + Multiplying it with another 3x1 Matrix calculates the cross product: + + >>> b = Matrix([3, 2, 1]) + >>> a.hat() * b + Matrix([ + [-4], + [ 8], + [-4]]) + + Which is equivalent to calling the ``cross`` method: + + >>> a.cross(b) + Matrix([ + [-4], + [ 8], + [-4]]) + + See Also + ======== + + dot + cross + vee + multiply + multiply_elementwise + """ + + if self.shape != (3, 1): + raise ShapeError("Dimensions incorrect, expected (3, 1), got " + + str(self.shape)) + else: + x, y, z = self + return self._new(3, 3, ( + 0, -z, y, + z, 0, -x, + -y, x, 0)) + + def vee(self): + r""" + Return a 3x1 vector from a skew-symmetric matrix representing the cross product, + so that ``self * b`` is equivalent to ``self.vee().cross(b)``. + + Examples + ======== + + Calling ``vee`` creates a vector from a skew-symmetric Matrix: + + >>> from sympy import Matrix + >>> A = Matrix([[0, -3, 2], [3, 0, -1], [-2, 1, 0]]) + >>> a = A.vee() + >>> a + Matrix([ + [1], + [2], + [3]]) + + Calculating the matrix product of the original matrix with a vector + is equivalent to a cross product: + + >>> b = Matrix([3, 2, 1]) + >>> A * b + Matrix([ + [-4], + [ 8], + [-4]]) + + >>> a.cross(b) + Matrix([ + [-4], + [ 8], + [-4]]) + + ``vee`` can also be used to retrieve angular velocity expressions. + Defining a rotation matrix: + + >>> from sympy import rot_ccw_axis3, trigsimp + >>> from sympy.physics.mechanics import dynamicsymbols + >>> theta = dynamicsymbols('theta') + >>> R = rot_ccw_axis3(theta) + >>> R + Matrix([ + [cos(theta(t)), -sin(theta(t)), 0], + [sin(theta(t)), cos(theta(t)), 0], + [ 0, 0, 1]]) + + We can retrieve the angular velocity: + + >>> Omega = R.T * R.diff() + >>> Omega = trigsimp(Omega) + >>> Omega.vee() + Matrix([ + [ 0], + [ 0], + [Derivative(theta(t), t)]]) + + See Also + ======== + + dot + cross + hat + multiply + multiply_elementwise + """ + + if self.shape != (3, 3): + raise ShapeError("Dimensions incorrect, expected (3, 3), got " + + str(self.shape)) + elif not self.is_anti_symmetric(): + raise ValueError("Matrix is not skew-symmetric") + else: + return self._new(3, 1, ( + self[2, 1], + self[0, 2], + self[1, 0])) + + @property + def D(self): + """Return Dirac conjugate (if ``self.rows == 4``). + + Examples + ======== + + >>> from sympy import Matrix, I, eye + >>> m = Matrix((0, 1 + I, 2, 3)) + >>> m.D + Matrix([[0, 1 - I, -2, -3]]) + >>> m = (eye(4) + I*eye(4)) + >>> m[0, 3] = 2 + >>> m.D + Matrix([ + [1 - I, 0, 0, 0], + [ 0, 1 - I, 0, 0], + [ 0, 0, -1 + I, 0], + [ 2, 0, 0, -1 + I]]) + + If the matrix does not have 4 rows an AttributeError will be raised + because this property is only defined for matrices with 4 rows. + + >>> Matrix(eye(2)).D + Traceback (most recent call last): + ... + AttributeError: Matrix has no attribute D. + + See Also + ======== + + sympy.matrices.matrixbase.MatrixBase.conjugate: By-element conjugation + sympy.matrices.matrixbase.MatrixBase.H: Hermite conjugation + """ + from sympy.physics.matrices import mgamma + if self.rows != 4: + # In Python 3.2, properties can only return an AttributeError + # so we can't raise a ShapeError -- see commit which added the + # first line of this inline comment. Also, there is no need + # for a message since MatrixBase will raise the AttributeError + raise AttributeError + return self.H * mgamma(0) + + def dot(self, b, hermitian=None, conjugate_convention=None): + """Return the dot or inner product of two vectors of equal length. + Here ``self`` must be a ``Matrix`` of size 1 x n or n x 1, and ``b`` + must be either a matrix of size 1 x n, n x 1, or a list/tuple of length n. + A scalar is returned. + + By default, ``dot`` does not conjugate ``self`` or ``b``, even if there are + complex entries. Set ``hermitian=True`` (and optionally a ``conjugate_convention``) + to compute the hermitian inner product. + + Possible kwargs are ``hermitian`` and ``conjugate_convention``. + + If ``conjugate_convention`` is ``"left"``, ``"math"`` or ``"maths"``, + the conjugate of the first vector (``self``) is used. If ``"right"`` + or ``"physics"`` is specified, the conjugate of the second vector ``b`` is used. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> v = Matrix([1, 1, 1]) + >>> M.row(0).dot(v) + 6 + >>> M.col(0).dot(v) + 12 + >>> v = [3, 2, 1] + >>> M.row(0).dot(v) + 10 + + >>> from sympy import I + >>> q = Matrix([1*I, 1*I, 1*I]) + >>> q.dot(q, hermitian=False) + -3 + + >>> q.dot(q, hermitian=True) + 3 + + >>> q1 = Matrix([1, 1, 1*I]) + >>> q.dot(q1, hermitian=True, conjugate_convention="maths") + 1 - 2*I + >>> q.dot(q1, hermitian=True, conjugate_convention="physics") + 1 + 2*I + + + See Also + ======== + + cross + multiply + multiply_elementwise + """ + from .dense import Matrix + + if not isinstance(b, MatrixBase): + if is_sequence(b): + if len(b) != self.cols and len(b) != self.rows: + raise ShapeError( + "Dimensions incorrect for dot product: %s, %s" % ( + self.shape, len(b))) + return self.dot(Matrix(b)) + else: + raise TypeError( + "`b` must be an ordered iterable or Matrix, not %s." % + type(b)) + + if (1 not in self.shape) or (1 not in b.shape): + raise ShapeError + if len(self) != len(b): + raise ShapeError( + "Dimensions incorrect for dot product: %s, %s" % (self.shape, b.shape)) + + mat = self + n = len(mat) + if mat.shape != (1, n): + mat = mat.reshape(1, n) + if b.shape != (n, 1): + b = b.reshape(n, 1) + + # Now ``mat`` is a row vector and ``b`` is a column vector. + + # If it so happens that only conjugate_convention is passed + # then automatically set hermitian to True. If only hermitian + # is true but no conjugate_convention is not passed then + # automatically set it to ``"maths"`` + + if conjugate_convention is not None and hermitian is None: + hermitian = True + if hermitian and conjugate_convention is None: + conjugate_convention = "maths" + + if hermitian == True: + if conjugate_convention in ("maths", "left", "math"): + mat = mat.conjugate() + elif conjugate_convention in ("physics", "right"): + b = b.conjugate() + else: + raise ValueError("Unknown conjugate_convention was entered." + " conjugate_convention must be one of the" + " following: math, maths, left, physics or right.") + return (mat * b)[0] + + def dual(self): + """Returns the dual of a matrix. + + A dual of a matrix is: + + ``(1/2)*levicivita(i, j, k, l)*M(k, l)`` summed over indices `k` and `l` + + Since the levicivita method is anti_symmetric for any pairwise + exchange of indices, the dual of a symmetric matrix is the zero + matrix. Strictly speaking the dual defined here assumes that the + 'matrix' `M` is a contravariant anti_symmetric second rank tensor, + so that the dual is a covariant second rank tensor. + + """ + from sympy.matrices import zeros + + M, n = self[:, :], self.rows + work = zeros(n) + if self.is_symmetric(): + return work + + for i in range(1, n): + for j in range(1, n): + acum = 0 + for k in range(1, n): + acum += LeviCivita(i, j, 0, k) * M[0, k] + work[i, j] = acum + work[j, i] = -acum + + for l in range(1, n): + acum = 0 + for a in range(1, n): + for b in range(1, n): + acum += LeviCivita(0, l, a, b) * M[a, b] + acum /= 2 + work[0, l] = -acum + work[l, 0] = acum + + return work + + def _eval_matrix_exp_jblock(self): + """A helper function to compute an exponential of a Jordan block + matrix + + Examples + ======== + + >>> from sympy import Symbol, Matrix + >>> l = Symbol('lamda') + + A trivial example of 1*1 Jordan block: + + >>> m = Matrix.jordan_block(1, l) + >>> m._eval_matrix_exp_jblock() + Matrix([[exp(lamda)]]) + + An example of 3*3 Jordan block: + + >>> m = Matrix.jordan_block(3, l) + >>> m._eval_matrix_exp_jblock() + Matrix([ + [exp(lamda), exp(lamda), exp(lamda)/2], + [ 0, exp(lamda), exp(lamda)], + [ 0, 0, exp(lamda)]]) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Matrix_function#Jordan_decomposition + """ + size = self.rows + l = self[0, 0] + exp_l = exp(l) + + bands = {i: exp_l / factorial(i) for i in range(size)} + + from .sparsetools import banded + return self.__class__(banded(size, bands)) + + + def analytic_func(self, f, x): + """ + Computes f(A) where A is a Square Matrix + and f is an analytic function. + + Examples + ======== + + >>> from sympy import Symbol, Matrix, S, log + + >>> x = Symbol('x') + >>> m = Matrix([[S(5)/4, S(3)/4], [S(3)/4, S(5)/4]]) + >>> f = log(x) + >>> m.analytic_func(f, x) + Matrix([ + [ 0, log(2)], + [log(2), 0]]) + + Parameters + ========== + + f : Expr + Analytic Function + x : Symbol + parameter of f + + """ + + f, x = _sympify(f), _sympify(x) + if not self.is_square: + raise NonSquareMatrixError + if not x.is_symbol: + raise ValueError("{} must be a symbol.".format(x)) + if x not in f.free_symbols: + raise ValueError( + "{} must be a parameter of {}.".format(x, f)) + if x in self.free_symbols: + raise ValueError( + "{} must not be a parameter of {}.".format(x, self)) + + eigen = self.eigenvals() + max_mul = max(eigen.values()) + derivative = {} + dd = f + for i in range(max_mul - 1): + dd = diff(dd, x) + derivative[i + 1] = dd + n = self.shape[0] + r = self.zeros(n) + f_val = self.zeros(n, 1) + row = 0 + + for i in eigen: + mul = eigen[i] + f_val[row] = f.subs(x, i) + if f_val[row].is_number and not f_val[row].is_complex: + raise ValueError( + "Cannot evaluate the function because the " + "function {} is not analytic at the given " + "eigenvalue {}".format(f, f_val[row])) + val = 1 + for a in range(n): + r[row, a] = val + val *= i + if mul > 1: + coe = [1 for ii in range(n)] + deri = 1 + while mul > 1: + row = row + 1 + mul -= 1 + d_i = derivative[deri].subs(x, i) + if d_i.is_number and not d_i.is_complex: + raise ValueError( + "Cannot evaluate the function because the " + "derivative {} is not analytic at the given " + "eigenvalue {}".format(derivative[deri], d_i)) + f_val[row] = d_i + for a in range(n): + if a - deri + 1 <= 0: + r[row, a] = 0 + coe[a] = 0 + continue + coe[a] = coe[a]*(a - deri + 1) + r[row, a] = coe[a]*pow(i, a - deri) + deri += 1 + row += 1 + c = r.solve(f_val) + ans = self.zeros(n) + pre = self.eye(n) + for i in range(n): + ans = ans + c[i]*pre + pre *= self + return ans + + + def exp(self): + """Return the exponential of a square matrix. + + Examples + ======== + + >>> from sympy import Symbol, Matrix + + >>> t = Symbol('t') + >>> m = Matrix([[0, 1], [-1, 0]]) * t + >>> m.exp() + Matrix([ + [ exp(I*t)/2 + exp(-I*t)/2, -I*exp(I*t)/2 + I*exp(-I*t)/2], + [I*exp(I*t)/2 - I*exp(-I*t)/2, exp(I*t)/2 + exp(-I*t)/2]]) + """ + if not self.is_square: + raise NonSquareMatrixError( + "Exponentiation is valid only for square matrices") + try: + P, J = self.jordan_form() + cells = J.get_diag_blocks() + except MatrixError: + raise NotImplementedError( + "Exponentiation is implemented only for matrices for which the Jordan normal form can be computed") + + blocks = [cell._eval_matrix_exp_jblock() for cell in cells] + from sympy.matrices import diag + eJ = diag(*blocks) + # n = self.rows + ret = P.multiply(eJ, dotprodsimp=None).multiply(P.inv(), dotprodsimp=None) + if all(value.is_real for value in self.values()): + return type(self)(re(ret)) + else: + return type(self)(ret) + + def _eval_matrix_log_jblock(self): + """Helper function to compute logarithm of a jordan block. + + Examples + ======== + + >>> from sympy import Symbol, Matrix + >>> l = Symbol('lamda') + + A trivial example of 1*1 Jordan block: + + >>> m = Matrix.jordan_block(1, l) + >>> m._eval_matrix_log_jblock() + Matrix([[log(lamda)]]) + + An example of 3*3 Jordan block: + + >>> m = Matrix.jordan_block(3, l) + >>> m._eval_matrix_log_jblock() + Matrix([ + [log(lamda), 1/lamda, -1/(2*lamda**2)], + [ 0, log(lamda), 1/lamda], + [ 0, 0, log(lamda)]]) + """ + size = self.rows + l = self[0, 0] + + if l.is_zero: + raise MatrixError( + 'Could not take logarithm or reciprocal for the given ' + 'eigenvalue {}'.format(l)) + + bands = {0: log(l)} + for i in range(1, size): + bands[i] = -((-l) ** -i) / i + + from .sparsetools import banded + return self.__class__(banded(size, bands)) + + def log(self, simplify=cancel): + """Return the logarithm of a square matrix. + + Parameters + ========== + + simplify : function, bool + The function to simplify the result with. + + Default is ``cancel``, which is effective to reduce the + expression growing for taking reciprocals and inverses for + symbolic matrices. + + Examples + ======== + + >>> from sympy import S, Matrix + + Examples for positive-definite matrices: + + >>> m = Matrix([[1, 1], [0, 1]]) + >>> m.log() + Matrix([ + [0, 1], + [0, 0]]) + + >>> m = Matrix([[S(5)/4, S(3)/4], [S(3)/4, S(5)/4]]) + >>> m.log() + Matrix([ + [ 0, log(2)], + [log(2), 0]]) + + Examples for non positive-definite matrices: + + >>> m = Matrix([[S(3)/4, S(5)/4], [S(5)/4, S(3)/4]]) + >>> m.log() + Matrix([ + [ I*pi/2, log(2) - I*pi/2], + [log(2) - I*pi/2, I*pi/2]]) + + >>> m = Matrix( + ... [[0, 0, 0, 1], + ... [0, 0, 1, 0], + ... [0, 1, 0, 0], + ... [1, 0, 0, 0]]) + >>> m.log() + Matrix([ + [ I*pi/2, 0, 0, -I*pi/2], + [ 0, I*pi/2, -I*pi/2, 0], + [ 0, -I*pi/2, I*pi/2, 0], + [-I*pi/2, 0, 0, I*pi/2]]) + """ + if not self.is_square: + raise NonSquareMatrixError( + "Logarithm is valid only for square matrices") + + try: + if simplify: + P, J = simplify(self).jordan_form() + else: + P, J = self.jordan_form() + + cells = J.get_diag_blocks() + except MatrixError: + raise NotImplementedError( + "Logarithm is implemented only for matrices for which " + "the Jordan normal form can be computed") + + blocks = [ + cell._eval_matrix_log_jblock() + for cell in cells] + from sympy.matrices import diag + eJ = diag(*blocks) + + if simplify: + ret = simplify(P * eJ * simplify(P.inv())) + ret = self.__class__(ret) + else: + ret = P * eJ * P.inv() + + return ret + + def is_nilpotent(self): + """Checks if a matrix is nilpotent. + + A matrix B is nilpotent if for some integer k, B**k is + a zero matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> a = Matrix([[0, 0, 0], [1, 0, 0], [1, 1, 0]]) + >>> a.is_nilpotent() + True + + >>> a = Matrix([[1, 0, 1], [1, 0, 0], [1, 1, 0]]) + >>> a.is_nilpotent() + False + """ + if not self: + return True + if not self.is_square: + raise NonSquareMatrixError( + "Nilpotency is valid only for square matrices") + x = uniquely_named_symbol('x', self, modify=lambda s: '_' + s) + p = self.charpoly(x) + if p.args[0] == x ** self.rows: + return True + return False + + def key2bounds(self, keys): + """Converts a key with potentially mixed types of keys (integer and slice) + into a tuple of ranges and raises an error if any index is out of ``self``'s + range. + + See Also + ======== + + key2ij + """ + islice, jslice = [isinstance(k, slice) for k in keys] + if islice: + if not self.rows: + rlo = rhi = 0 + else: + rlo, rhi = keys[0].indices(self.rows)[:2] + else: + rlo = a2idx(keys[0], self.rows) + rhi = rlo + 1 + if jslice: + if not self.cols: + clo = chi = 0 + else: + clo, chi = keys[1].indices(self.cols)[:2] + else: + clo = a2idx(keys[1], self.cols) + chi = clo + 1 + return rlo, rhi, clo, chi + + def key2ij(self, key): + """Converts key into canonical form, converting integers or indexable + items into valid integers for ``self``'s range or returning slices + unchanged. + + See Also + ======== + + key2bounds + """ + if is_sequence(key): + if not len(key) == 2: + raise TypeError('key must be a sequence of length 2') + return [a2idx(i, n) if not isinstance(i, slice) else i + for i, n in zip(key, self.shape)] + elif isinstance(key, slice): + return key.indices(len(self))[:2] + else: + return divmod(a2idx(key, len(self)), self.cols) + + def normalized(self, iszerofunc=_iszero): + """Return the normalized version of ``self``. + + Parameters + ========== + + iszerofunc : Function, optional + A function to determine whether ``self`` is a zero vector. + The default ``_iszero`` tests to see if each element is + exactly zero. + + Returns + ======= + + Matrix + Normalized vector form of ``self``. + It has the same length as a unit vector. However, a zero vector + will be returned for a vector with norm 0. + + Raises + ====== + + ShapeError + If the matrix is not in a vector form. + + See Also + ======== + + norm + """ + if self.rows != 1 and self.cols != 1: + raise ShapeError("A Matrix must be a vector to normalize.") + norm = self.norm() + if iszerofunc(norm): + out = self.zeros(self.rows, self.cols) + else: + out = self.applyfunc(lambda i: i / norm) + return out + + def norm(self, ord=None): + """Return the Norm of a Matrix or Vector. + + In the simplest case this is the geometric size of the vector + Other norms can be specified by the ord parameter + + + ===== ============================ ========================== + ord norm for matrices norm for vectors + ===== ============================ ========================== + None Frobenius norm 2-norm + 'fro' Frobenius norm - does not exist + inf maximum row sum max(abs(x)) + -inf -- min(abs(x)) + 1 maximum column sum as below + -1 -- as below + 2 2-norm (largest sing. value) as below + -2 smallest singular value as below + other - does not exist sum(abs(x)**ord)**(1./ord) + ===== ============================ ========================== + + Examples + ======== + + >>> from sympy import Matrix, Symbol, trigsimp, cos, sin, oo + >>> x = Symbol('x', real=True) + >>> v = Matrix([cos(x), sin(x)]) + >>> trigsimp( v.norm() ) + 1 + >>> v.norm(10) + (sin(x)**10 + cos(x)**10)**(1/10) + >>> A = Matrix([[1, 1], [1, 1]]) + >>> A.norm(1) # maximum sum of absolute values of A is 2 + 2 + >>> A.norm(2) # Spectral norm (max of |Ax|/|x| under 2-vector-norm) + 2 + >>> A.norm(-2) # Inverse spectral norm (smallest singular value) + 0 + >>> A.norm() # Frobenius Norm + 2 + >>> A.norm(oo) # Infinity Norm + 2 + >>> Matrix([1, -2]).norm(oo) + 2 + >>> Matrix([-1, 2]).norm(-oo) + 1 + + See Also + ======== + + normalized + """ + # Row or Column Vector Norms + vals = list(self.values()) or [0] + if S.One in self.shape: + if ord in (2, None): # Common case sqrt() + return sqrt(Add(*(abs(i) ** 2 for i in vals))) + + elif ord == 1: # sum(abs(x)) + return Add(*(abs(i) for i in vals)) + + elif ord is S.Infinity: # max(abs(x)) + return Max(*[abs(i) for i in vals]) + + elif ord is S.NegativeInfinity: # min(abs(x)) + return Min(*[abs(i) for i in vals]) + + # Otherwise generalize the 2-norm, Sum(x_i**ord)**(1/ord) + # Note that while useful this is not mathematically a norm + try: + return Pow(Add(*(abs(i) ** ord for i in vals)), S.One / ord) + except (NotImplementedError, TypeError): + raise ValueError("Expected order to be Number, Symbol, oo") + + # Matrix Norms + else: + if ord == 1: # Maximum column sum + m = self.applyfunc(abs) + return Max(*[sum(m.col(i)) for i in range(m.cols)]) + + elif ord == 2: # Spectral Norm + # Maximum singular value + return Max(*self.singular_values()) + + elif ord == -2: + # Minimum singular value + return Min(*self.singular_values()) + + elif ord is S.Infinity: # Infinity Norm - Maximum row sum + m = self.applyfunc(abs) + return Max(*[sum(m.row(i)) for i in range(m.rows)]) + + elif (ord is None or isinstance(ord, + str) and ord.lower() in + ['f', 'fro', 'frobenius', 'vector']): + # Reshape as vector and send back to norm function + return self.vec().norm(ord=2) + + else: + raise NotImplementedError("Matrix Norms under development") + + def print_nonzero(self, symb="X"): + """Shows location of non-zero entries for fast shape lookup. + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> m = Matrix(2, 3, lambda i, j: i*3+j) + >>> m + Matrix([ + [0, 1, 2], + [3, 4, 5]]) + >>> m.print_nonzero() + [ XX] + [XXX] + >>> m = eye(4) + >>> m.print_nonzero("x") + [x ] + [ x ] + [ x ] + [ x] + + """ + s = [] + for i in range(self.rows): + line = [] + for j in range(self.cols): + if self[i, j] == 0: + line.append(" ") + else: + line.append(str(symb)) + s.append("[%s]" % ''.join(line)) + print('\n'.join(s)) + + def project(self, v): + """Return the projection of ``self`` onto the line containing ``v``. + + Examples + ======== + + >>> from sympy import Matrix, S, sqrt + >>> V = Matrix([sqrt(3)/2, S.Half]) + >>> x = Matrix([[1, 0]]) + >>> V.project(x) + Matrix([[sqrt(3)/2, 0]]) + >>> V.project(-x) + Matrix([[sqrt(3)/2, 0]]) + """ + return v * (self.dot(v) / v.dot(v)) + + def table(self, printer, rowstart='[', rowend=']', rowsep='\n', + colsep=', ', align='right'): + r""" + String form of Matrix as a table. + + ``printer`` is the printer to use for on the elements (generally + something like StrPrinter()) + + ``rowstart`` is the string used to start each row (by default '['). + + ``rowend`` is the string used to end each row (by default ']'). + + ``rowsep`` is the string used to separate rows (by default a newline). + + ``colsep`` is the string used to separate columns (by default ', '). + + ``align`` defines how the elements are aligned. Must be one of 'left', + 'right', or 'center'. You can also use '<', '>', and '^' to mean the + same thing, respectively. + + This is used by the string printer for Matrix. + + Examples + ======== + + >>> from sympy import Matrix, StrPrinter + >>> M = Matrix([[1, 2], [-33, 4]]) + >>> printer = StrPrinter() + >>> M.table(printer) + '[ 1, 2]\n[-33, 4]' + >>> print(M.table(printer)) + [ 1, 2] + [-33, 4] + >>> print(M.table(printer, rowsep=',\n')) + [ 1, 2], + [-33, 4] + >>> print('[%s]' % M.table(printer, rowsep=',\n')) + [[ 1, 2], + [-33, 4]] + >>> print(M.table(printer, colsep=' ')) + [ 1 2] + [-33 4] + >>> print(M.table(printer, align='center')) + [ 1 , 2] + [-33, 4] + >>> print(M.table(printer, rowstart='{', rowend='}')) + { 1, 2} + {-33, 4} + """ + # Handle zero dimensions: + if S.Zero in self.shape: + return '[]' + # Build table of string representations of the elements + res = [] + # Track per-column max lengths for pretty alignment + maxlen = [0] * self.cols + for i in range(self.rows): + res.append([]) + for j in range(self.cols): + s = printer._print(self[i, j]) + res[-1].append(s) + maxlen[j] = max(len(s), maxlen[j]) + # Patch strings together + align = { + 'left': 'ljust', + 'right': 'rjust', + 'center': 'center', + '<': 'ljust', + '>': 'rjust', + '^': 'center', + }[align] + for i, row in enumerate(res): + for j, elem in enumerate(row): + row[j] = getattr(elem, align)(maxlen[j]) + res[i] = rowstart + colsep.join(row) + rowend + return rowsep.join(res) + + def rank_decomposition(self, iszerofunc=_iszero, simplify=False): + return _rank_decomposition(self, iszerofunc=iszerofunc, + simplify=simplify) + + def cholesky(self, hermitian=True): + raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix') + + def LDLdecomposition(self, hermitian=True): + raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix') + + def LUdecomposition(self, iszerofunc=_iszero, simpfunc=None, + rankcheck=False): + return _LUdecomposition(self, iszerofunc=iszerofunc, simpfunc=simpfunc, + rankcheck=rankcheck) + + def LUdecomposition_Simple(self, iszerofunc=_iszero, simpfunc=None, + rankcheck=False): + return _LUdecomposition_Simple(self, iszerofunc=iszerofunc, + simpfunc=simpfunc, rankcheck=rankcheck) + + def LUdecompositionFF(self): + return _LUdecompositionFF(self) + + def singular_value_decomposition(self): + return _singular_value_decomposition(self) + + def QRdecomposition(self): + return _QRdecomposition(self) + + def upper_hessenberg_decomposition(self): + return _upper_hessenberg_decomposition(self) + + def diagonal_solve(self, rhs): + return _diagonal_solve(self, rhs) + + def lower_triangular_solve(self, rhs): + raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix') + + def upper_triangular_solve(self, rhs): + raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix') + + def cholesky_solve(self, rhs): + return _cholesky_solve(self, rhs) + + def LDLsolve(self, rhs): + return _LDLsolve(self, rhs) + + def LUsolve(self, rhs, iszerofunc=_iszero): + return _LUsolve(self, rhs, iszerofunc=iszerofunc) + + def QRsolve(self, b): + return _QRsolve(self, b) + + def gauss_jordan_solve(self, B, freevar=False): + return _gauss_jordan_solve(self, B, freevar=freevar) + + def pinv_solve(self, B, arbitrary_matrix=None): + return _pinv_solve(self, B, arbitrary_matrix=arbitrary_matrix) + + def cramer_solve(self, rhs, det_method="laplace"): + return _cramer_solve(self, rhs, det_method=det_method) + + def solve(self, rhs, method='GJ'): + return _solve(self, rhs, method=method) + + def solve_least_squares(self, rhs, method='CH'): + return _solve_least_squares(self, rhs, method=method) + + def pinv(self, method='RD'): + return _pinv(self, method=method) + + def inverse_ADJ(self, iszerofunc=_iszero): + return _inv_ADJ(self, iszerofunc=iszerofunc) + + def inverse_BLOCK(self, iszerofunc=_iszero): + return _inv_block(self, iszerofunc=iszerofunc) + + def inverse_GE(self, iszerofunc=_iszero): + return _inv_GE(self, iszerofunc=iszerofunc) + + def inverse_LU(self, iszerofunc=_iszero): + return _inv_LU(self, iszerofunc=iszerofunc) + + def inverse_CH(self, iszerofunc=_iszero): + return _inv_CH(self, iszerofunc=iszerofunc) + + def inverse_LDL(self, iszerofunc=_iszero): + return _inv_LDL(self, iszerofunc=iszerofunc) + + def inverse_QR(self, iszerofunc=_iszero): + return _inv_QR(self, iszerofunc=iszerofunc) + + def inv(self, method=None, iszerofunc=_iszero, try_block_diag=False): + return _inv(self, method=method, iszerofunc=iszerofunc, + try_block_diag=try_block_diag) + + def connected_components(self): + return _connected_components(self) + + def connected_components_decomposition(self): + return _connected_components_decomposition(self) + + def strongly_connected_components(self): + return _strongly_connected_components(self) + + def strongly_connected_components_decomposition(self, lower=True): + return _strongly_connected_components_decomposition(self, lower=lower) + + _sage_ = Basic._sage_ + + rank_decomposition.__doc__ = _rank_decomposition.__doc__ + cholesky.__doc__ = _cholesky.__doc__ + LDLdecomposition.__doc__ = _LDLdecomposition.__doc__ + LUdecomposition.__doc__ = _LUdecomposition.__doc__ + LUdecomposition_Simple.__doc__ = _LUdecomposition_Simple.__doc__ + LUdecompositionFF.__doc__ = _LUdecompositionFF.__doc__ + singular_value_decomposition.__doc__ = _singular_value_decomposition.__doc__ + QRdecomposition.__doc__ = _QRdecomposition.__doc__ + upper_hessenberg_decomposition.__doc__ = _upper_hessenberg_decomposition.__doc__ + + diagonal_solve.__doc__ = _diagonal_solve.__doc__ + lower_triangular_solve.__doc__ = _lower_triangular_solve.__doc__ + upper_triangular_solve.__doc__ = _upper_triangular_solve.__doc__ + cholesky_solve.__doc__ = _cholesky_solve.__doc__ + LDLsolve.__doc__ = _LDLsolve.__doc__ + LUsolve.__doc__ = _LUsolve.__doc__ + QRsolve.__doc__ = _QRsolve.__doc__ + gauss_jordan_solve.__doc__ = _gauss_jordan_solve.__doc__ + pinv_solve.__doc__ = _pinv_solve.__doc__ + cramer_solve.__doc__ = _cramer_solve.__doc__ + solve.__doc__ = _solve.__doc__ + solve_least_squares.__doc__ = _solve_least_squares.__doc__ + + pinv.__doc__ = _pinv.__doc__ + inverse_ADJ.__doc__ = _inv_ADJ.__doc__ + inverse_GE.__doc__ = _inv_GE.__doc__ + inverse_LU.__doc__ = _inv_LU.__doc__ + inverse_CH.__doc__ = _inv_CH.__doc__ + inverse_LDL.__doc__ = _inv_LDL.__doc__ + inverse_QR.__doc__ = _inv_QR.__doc__ + inverse_BLOCK.__doc__ = _inv_block.__doc__ + inv.__doc__ = _inv.__doc__ + + connected_components.__doc__ = _connected_components.__doc__ + connected_components_decomposition.__doc__ = \ + _connected_components_decomposition.__doc__ + strongly_connected_components.__doc__ = \ + _strongly_connected_components.__doc__ + strongly_connected_components_decomposition.__doc__ = \ + _strongly_connected_components_decomposition.__doc__ + + +def _convert_matrix(typ, mat): + """Convert mat to a Matrix of type typ.""" + from sympy.matrices.matrixbase import MatrixBase + if getattr(mat, "is_Matrix", False) and not isinstance(mat, MatrixBase): + # This is needed for interop between Matrix and the redundant matrix + # mixin types like _MinimalMatrix etc. If anyone should happen to be + # using those then this keeps them working. Really _MinimalMatrix etc + # should be deprecated and removed though. + return typ(*mat.shape, list(mat)) + else: + return typ(mat) + + +def _has_matrix_shape(other): + shape = getattr(other, 'shape', None) + if shape is None: + return False + return isinstance(shape, tuple) and len(shape) == 2 + + +def _has_rows_cols(other): + return hasattr(other, 'rows') and hasattr(other, 'cols') + + +def _coerce_operand(self, other): + """Convert other to a Matrix, or check for possible scalar.""" + + INVALID = None, 'invalid_type' + + # Disallow mixing Matrix and Array + if isinstance(other, NDimArray): + return INVALID + + is_Matrix = getattr(other, 'is_Matrix', None) + + # Return a Matrix as-is + if is_Matrix: + return other, 'is_matrix' + + # Try to convert numpy array, mpmath matrix etc. + if is_Matrix is None: + if _has_matrix_shape(other) or _has_rows_cols(other): + return _convert_matrix(type(self), other), 'is_matrix' + + # Could be a scalar but only if not iterable... + if not isinstance(other, Iterable): + return other, 'possible_scalar' + + return INVALID + + +def classof(A, B): + """ + Get the type of the result when combining matrices of different types. + + Currently the strategy is that immutability is contagious. + + Examples + ======== + + >>> from sympy import Matrix, ImmutableMatrix + >>> from sympy.matrices.matrixbase import classof + >>> M = Matrix([[1, 2], [3, 4]]) # a Mutable Matrix + >>> IM = ImmutableMatrix([[1, 2], [3, 4]]) + >>> classof(M, IM) + + """ + priority_A = getattr(A, '_class_priority', None) + priority_B = getattr(B, '_class_priority', None) + if None not in (priority_A, priority_B): + if A._class_priority > B._class_priority: + return A.__class__ + else: + return B.__class__ + + try: + import numpy + except ImportError: + pass + else: + if isinstance(A, numpy.ndarray): + return B.__class__ + if isinstance(B, numpy.ndarray): + return A.__class__ + + raise TypeError("Incompatible classes %s, %s" % (A.__class__, B.__class__)) + + +def _unify_with_other(self, other): + """Unify self and other into a single matrix type, or check for scalar.""" + other, T = _coerce_operand(self, other) + + if T == "is_matrix": + typ = classof(self, other) + if typ != self.__class__: + self = _convert_matrix(typ, self) + if typ != other.__class__: + other = _convert_matrix(typ, other) + + return self, other, T + + +def a2idx(j, n=None): + """Return integer after making positive and validating against n.""" + if not isinstance(j, int): + jindex = getattr(j, '__index__', None) + if jindex is not None: + j = jindex() + else: + raise IndexError("Invalid index a[%r]" % (j,)) + if n is not None: + if j < 0: + j += n + if not (j >= 0 and j < n): + raise IndexError("Index out of range: a[%s]" % (j,)) + return int(j) + + +class DeferredVector(Symbol, NotIterable): # type: ignore + """A vector whose components are deferred (e.g. for use with lambdify). + + Examples + ======== + + >>> from sympy import DeferredVector, lambdify + >>> X = DeferredVector( 'X' ) + >>> X + X + >>> expr = (X[0] + 2, X[2] + 3) + >>> func = lambdify( X, expr) + >>> func( [1, 2, 3] ) + (3, 6) + """ + + def __getitem__(self, i): + if i == -0: + i = 0 + if i < 0: + raise IndexError('DeferredVector index out of range') + component_name = '%s[%d]' % (self.name, i) + return Symbol(component_name) + + def __str__(self): + return sstr(self) + + def __repr__(self): + return "DeferredVector('%s')" % self.name diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/normalforms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/normalforms.py new file mode 100644 index 0000000000000000000000000000000000000000..61a7d26bbdb8c8a3e8e3044d39b2403b2e14b7d5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/normalforms.py @@ -0,0 +1,156 @@ +'''Functions returning normal forms of matrices''' + +from sympy.polys.domains.integerring import ZZ +from sympy.polys.polytools import Poly +from sympy.polys.matrices import DomainMatrix +from sympy.polys.matrices.normalforms import ( + smith_normal_form as _snf, + is_smith_normal_form as _is_snf, + smith_normal_decomp as _snd, + invariant_factors as _invf, + hermite_normal_form as _hnf, + ) + + +def _to_domain(m, domain=None): + """Convert Matrix to DomainMatrix""" + # XXX: deprecated support for RawMatrix: + ring = getattr(m, "ring", None) + m = m.applyfunc(lambda e: e.as_expr() if isinstance(e, Poly) else e) + + dM = DomainMatrix.from_Matrix(m) + + domain = domain or ring + if domain is not None: + dM = dM.convert_to(domain) + return dM + + +def smith_normal_form(m, domain=None): + ''' + Return the Smith Normal Form of a matrix `m` over the ring `domain`. + This will only work if the ring is a principal ideal domain. + + Examples + ======== + + >>> from sympy import Matrix, ZZ + >>> from sympy.matrices.normalforms import smith_normal_form + >>> m = Matrix([[12, 6, 4], [3, 9, 6], [2, 16, 14]]) + >>> print(smith_normal_form(m, domain=ZZ)) + Matrix([[1, 0, 0], [0, 10, 0], [0, 0, 30]]) + + ''' + dM = _to_domain(m, domain) + return _snf(dM).to_Matrix() + + +def is_smith_normal_form(m, domain=None): + ''' + Checks that the matrix is in Smith Normal Form + ''' + dM = _to_domain(m, domain) + return _is_snf(dM) + + +def smith_normal_decomp(m, domain=None): + ''' + Return the Smith Normal Decomposition of a matrix `m` over the ring + `domain`. This will only work if the ring is a principal ideal domain. + + Examples + ======== + + >>> from sympy import Matrix, ZZ + >>> from sympy.matrices.normalforms import smith_normal_decomp + >>> m = Matrix([[12, 6, 4], [3, 9, 6], [2, 16, 14]]) + >>> a, s, t = smith_normal_decomp(m, domain=ZZ) + >>> assert a == s * m * t + ''' + dM = _to_domain(m, domain) + a, s, t = _snd(dM) + return a.to_Matrix(), s.to_Matrix(), t.to_Matrix() + + +def invariant_factors(m, domain=None): + ''' + Return the tuple of abelian invariants for a matrix `m` + (as in the Smith-Normal form) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Smith_normal_form#Algorithm + .. [2] https://web.archive.org/web/20200331143852/https://sierra.nmsu.edu/morandi/notes/SmithNormalForm.pdf + + ''' + dM = _to_domain(m, domain) + factors = _invf(dM) + factors = tuple(dM.domain.to_sympy(f) for f in factors) + # XXX: deprecated. + if hasattr(m, "ring"): + if m.ring.is_PolynomialRing: + K = m.ring + to_poly = lambda f: Poly(f, K.symbols, domain=K.domain) + factors = tuple(to_poly(f) for f in factors) + return factors + + +def hermite_normal_form(A, *, D=None, check_rank=False): + r""" + Compute the Hermite Normal Form of a Matrix *A* of integers. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.matrices.normalforms import hermite_normal_form + >>> m = Matrix([[12, 6, 4], [3, 9, 6], [2, 16, 14]]) + >>> print(hermite_normal_form(m)) + Matrix([[10, 0, 2], [0, 15, 3], [0, 0, 2]]) + + Parameters + ========== + + A : $m \times n$ ``Matrix`` of integers. + + D : int, optional + Let $W$ be the HNF of *A*. If known in advance, a positive integer *D* + being any multiple of $\det(W)$ may be provided. In this case, if *A* + also has rank $m$, then we may use an alternative algorithm that works + mod *D* in order to prevent coefficient explosion. + + check_rank : boolean, optional (default=False) + The basic assumption is that, if you pass a value for *D*, then + you already believe that *A* has rank $m$, so we do not waste time + checking it for you. If you do want this to be checked (and the + ordinary, non-modulo *D* algorithm to be used if the check fails), then + set *check_rank* to ``True``. + + Returns + ======= + + ``Matrix`` + The HNF of matrix *A*. + + Raises + ====== + + DMDomainError + If the domain of the matrix is not :ref:`ZZ`. + + DMShapeError + If the mod *D* algorithm is used but the matrix has more rows than + columns. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Algorithms 2.4.5 and 2.4.8.) + + """ + # Accept any of Python int, SymPy Integer, and ZZ itself: + if D is not None and not ZZ.of_type(D): + D = ZZ(int(D)) + return _hnf(A._rep, D=D, check_rank=check_rank).to_Matrix() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/reductions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/reductions.py new file mode 100644 index 0000000000000000000000000000000000000000..aace8c0336358e1869a34d99f79390cc0c0163fe --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/reductions.py @@ -0,0 +1,387 @@ +from types import FunctionType + +from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.domains import ZZ, QQ + +from .utilities import _get_intermediate_simp, _iszero, _dotprodsimp, _simplify +from .determinant import _find_reasonable_pivot + + +def _row_reduce_list(mat, rows, cols, one, iszerofunc, simpfunc, + normalize_last=True, normalize=True, zero_above=True): + """Row reduce a flat list representation of a matrix and return a tuple + (rref_matrix, pivot_cols, swaps) where ``rref_matrix`` is a flat list, + ``pivot_cols`` are the pivot columns and ``swaps`` are any row swaps that + were used in the process of row reduction. + + Parameters + ========== + + mat : list + list of matrix elements, must be ``rows`` * ``cols`` in length + + rows, cols : integer + number of rows and columns in flat list representation + + one : SymPy object + represents the value one, from ``Matrix.one`` + + iszerofunc : determines if an entry can be used as a pivot + + simpfunc : used to simplify elements and test if they are + zero if ``iszerofunc`` returns `None` + + normalize_last : indicates where all row reduction should + happen in a fraction-free manner and then the rows are + normalized (so that the pivots are 1), or whether + rows should be normalized along the way (like the naive + row reduction algorithm) + + normalize : whether pivot rows should be normalized so that + the pivot value is 1 + + zero_above : whether entries above the pivot should be zeroed. + If ``zero_above=False``, an echelon matrix will be returned. + """ + + def get_col(i): + return mat[i::cols] + + def row_swap(i, j): + mat[i*cols:(i + 1)*cols], mat[j*cols:(j + 1)*cols] = \ + mat[j*cols:(j + 1)*cols], mat[i*cols:(i + 1)*cols] + + def cross_cancel(a, i, b, j): + """Does the row op row[i] = a*row[i] - b*row[j]""" + q = (j - i)*cols + for p in range(i*cols, (i + 1)*cols): + mat[p] = isimp(a*mat[p] - b*mat[p + q]) + + isimp = _get_intermediate_simp(_dotprodsimp) + piv_row, piv_col = 0, 0 + pivot_cols = [] + swaps = [] + + # use a fraction free method to zero above and below each pivot + while piv_col < cols and piv_row < rows: + pivot_offset, pivot_val, \ + assumed_nonzero, newly_determined = _find_reasonable_pivot( + get_col(piv_col)[piv_row:], iszerofunc, simpfunc) + + # _find_reasonable_pivot may have simplified some things + # in the process. Let's not let them go to waste + for (offset, val) in newly_determined: + offset += piv_row + mat[offset*cols + piv_col] = val + + if pivot_offset is None: + piv_col += 1 + continue + + pivot_cols.append(piv_col) + if pivot_offset != 0: + row_swap(piv_row, pivot_offset + piv_row) + swaps.append((piv_row, pivot_offset + piv_row)) + + # if we aren't normalizing last, we normalize + # before we zero the other rows + if normalize_last is False: + i, j = piv_row, piv_col + mat[i*cols + j] = one + for p in range(i*cols + j + 1, (i + 1)*cols): + mat[p] = isimp(mat[p] / pivot_val) + # after normalizing, the pivot value is 1 + pivot_val = one + + # zero above and below the pivot + for row in range(rows): + # don't zero our current row + if row == piv_row: + continue + # don't zero above the pivot unless we're told. + if zero_above is False and row < piv_row: + continue + # if we're already a zero, don't do anything + val = mat[row*cols + piv_col] + if iszerofunc(val): + continue + + cross_cancel(pivot_val, row, val, piv_row) + piv_row += 1 + + # normalize each row + if normalize_last is True and normalize is True: + for piv_i, piv_j in enumerate(pivot_cols): + pivot_val = mat[piv_i*cols + piv_j] + mat[piv_i*cols + piv_j] = one + for p in range(piv_i*cols + piv_j + 1, (piv_i + 1)*cols): + mat[p] = isimp(mat[p] / pivot_val) + + return mat, tuple(pivot_cols), tuple(swaps) + + +# This functions is a candidate for caching if it gets implemented for matrices. +def _row_reduce(M, iszerofunc, simpfunc, normalize_last=True, + normalize=True, zero_above=True): + + mat, pivot_cols, swaps = _row_reduce_list(list(M), M.rows, M.cols, M.one, + iszerofunc, simpfunc, normalize_last=normalize_last, + normalize=normalize, zero_above=zero_above) + + return M._new(M.rows, M.cols, mat), pivot_cols, swaps + + +def _is_echelon(M, iszerofunc=_iszero): + """Returns `True` if the matrix is in echelon form. That is, all rows of + zeros are at the bottom, and below each leading non-zero in a row are + exclusively zeros.""" + + if M.rows <= 0 or M.cols <= 0: + return True + + zeros_below = all(iszerofunc(t) for t in M[1:, 0]) + + if iszerofunc(M[0, 0]): + return zeros_below and _is_echelon(M[:, 1:], iszerofunc) + + return zeros_below and _is_echelon(M[1:, 1:], iszerofunc) + + +def _echelon_form(M, iszerofunc=_iszero, simplify=False, with_pivots=False): + """Returns a matrix row-equivalent to ``M`` that is in echelon form. Note + that echelon form of a matrix is *not* unique, however, properties like the + row space and the null space are preserved. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2], [3, 4]]) + >>> M.echelon_form() + Matrix([ + [1, 2], + [0, -2]]) + """ + + simpfunc = simplify if isinstance(simplify, FunctionType) else _simplify + + mat, pivots, _ = _row_reduce(M, iszerofunc, simpfunc, + normalize_last=True, normalize=False, zero_above=False) + + if with_pivots: + return mat, pivots + + return mat + + +# This functions is a candidate for caching if it gets implemented for matrices. +def _rank(M, iszerofunc=_iszero, simplify=False): + """Returns the rank of a matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x + >>> m = Matrix([[1, 2], [x, 1 - 1/x]]) + >>> m.rank() + 2 + >>> n = Matrix(3, 3, range(1, 10)) + >>> n.rank() + 2 + """ + + def _permute_complexity_right(M, iszerofunc): + """Permute columns with complicated elements as + far right as they can go. Since the ``sympy`` row reduction + algorithms start on the left, having complexity right-shifted + speeds things up. + + Returns a tuple (mat, perm) where perm is a permutation + of the columns to perform to shift the complex columns right, and mat + is the permuted matrix.""" + + def complexity(i): + # the complexity of a column will be judged by how many + # element's zero-ness cannot be determined + return sum(1 if iszerofunc(e) is None else 0 for e in M[:, i]) + + complex = [(complexity(i), i) for i in range(M.cols)] + perm = [j for (i, j) in sorted(complex)] + + return (M.permute(perm, orientation='cols'), perm) + + simpfunc = simplify if isinstance(simplify, FunctionType) else _simplify + + # for small matrices, we compute the rank explicitly + # if is_zero on elements doesn't answer the question + # for small matrices, we fall back to the full routine. + if M.rows <= 0 or M.cols <= 0: + return 0 + + if M.rows <= 1 or M.cols <= 1: + zeros = [iszerofunc(x) for x in M] + + if False in zeros: + return 1 + + if M.rows == 2 and M.cols == 2: + zeros = [iszerofunc(x) for x in M] + + if False not in zeros and None not in zeros: + return 0 + + d = M.det() + + if iszerofunc(d) and False in zeros: + return 1 + if iszerofunc(d) is False: + return 2 + + mat, _ = _permute_complexity_right(M, iszerofunc=iszerofunc) + _, pivots, _ = _row_reduce(mat, iszerofunc, simpfunc, normalize_last=True, + normalize=False, zero_above=False) + + return len(pivots) + + +def _to_DM_ZZ_QQ(M): + # We have to test for _rep here because there are tests that otherwise fail + # with e.g. "AttributeError: 'SubspaceOnlyMatrix' object has no attribute + # '_rep'." There is almost certainly no value in such tests. The + # presumption seems to be that someone could create a new class by + # inheriting some of the Matrix classes and not the full set that is used + # by the standard Matrix class but if anyone tried that it would fail in + # many ways. + if not hasattr(M, '_rep'): + return None + + rep = M._rep + K = rep.domain + + if K.is_ZZ: + return rep + elif K.is_QQ: + try: + return rep.convert_to(ZZ) + except CoercionFailed: + return rep + else: + if not all(e.is_Rational for e in M): + return None + try: + return rep.convert_to(ZZ) + except CoercionFailed: + return rep.convert_to(QQ) + + +def _rref_dm(dM): + """Compute the reduced row echelon form of a DomainMatrix.""" + K = dM.domain + + if K.is_ZZ: + dM_rref, den, pivots = dM.rref_den(keep_domain=False) + dM_rref = dM_rref.to_field() / den + elif K.is_QQ: + dM_rref, pivots = dM.rref() + else: + assert False # pragma: no cover + + M_rref = dM_rref.to_Matrix() + + return M_rref, pivots + + +def _rref(M, iszerofunc=_iszero, simplify=False, pivots=True, + normalize_last=True): + """Return reduced row-echelon form of matrix and indices + of pivot vars. + + Parameters + ========== + + iszerofunc : Function + A function used for detecting whether an element can + act as a pivot. ``lambda x: x.is_zero`` is used by default. + + simplify : Function + A function used to simplify elements when looking for a pivot. + By default SymPy's ``simplify`` is used. + + pivots : True or False + If ``True``, a tuple containing the row-reduced matrix and a tuple + of pivot columns is returned. If ``False`` just the row-reduced + matrix is returned. + + normalize_last : True or False + If ``True``, no pivots are normalized to `1` until after all + entries above and below each pivot are zeroed. This means the row + reduction algorithm is fraction free until the very last step. + If ``False``, the naive row reduction procedure is used where + each pivot is normalized to be `1` before row operations are + used to zero above and below the pivot. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x + >>> m = Matrix([[1, 2], [x, 1 - 1/x]]) + >>> m.rref() + (Matrix([ + [1, 0], + [0, 1]]), (0, 1)) + >>> rref_matrix, rref_pivots = m.rref() + >>> rref_matrix + Matrix([ + [1, 0], + [0, 1]]) + >>> rref_pivots + (0, 1) + + ``iszerofunc`` can correct rounding errors in matrices with float + values. In the following example, calling ``rref()`` leads to + floating point errors, incorrectly row reducing the matrix. + ``iszerofunc= lambda x: abs(x) < 1e-9`` sets sufficiently small numbers + to zero, avoiding this error. + + >>> m = Matrix([[0.9, -0.1, -0.2, 0], [-0.8, 0.9, -0.4, 0], [-0.1, -0.8, 0.6, 0]]) + >>> m.rref() + (Matrix([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0]]), (0, 1, 2)) + >>> m.rref(iszerofunc=lambda x:abs(x)<1e-9) + (Matrix([ + [1, 0, -0.301369863013699, 0], + [0, 1, -0.712328767123288, 0], + [0, 0, 0, 0]]), (0, 1)) + + Notes + ===== + + The default value of ``normalize_last=True`` can provide significant + speedup to row reduction, especially on matrices with symbols. However, + if you depend on the form row reduction algorithm leaves entries + of the matrix, set ``normalize_last=False`` + """ + # Try to use DomainMatrix for ZZ or QQ + dM = _to_DM_ZZ_QQ(M) + + if dM is not None: + # Use DomainMatrix for ZZ or QQ + mat, pivot_cols = _rref_dm(dM) + else: + # Use the generic Matrix routine. + if isinstance(simplify, FunctionType): + simpfunc = simplify + else: + simpfunc = _simplify + + mat, pivot_cols, _ = _row_reduce(M, iszerofunc, simpfunc, + normalize_last, normalize=True, zero_above=True) + + if pivots: + return mat, pivot_cols + else: + return mat diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/repmatrix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/repmatrix.py new file mode 100644 index 0000000000000000000000000000000000000000..57f32fae34786f68f579fad7de38c9e3cf43e131 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/repmatrix.py @@ -0,0 +1,1034 @@ +from collections import defaultdict + +from operator import index as index_ + +from sympy.core.expr import Expr +from sympy.core.kind import Kind, NumberKind, UndefinedKind +from sympy.core.numbers import Integer, Rational +from sympy.core.sympify import _sympify, SympifyError +from sympy.core.singleton import S +from sympy.polys.domains import ZZ, QQ, GF, EXRAW +from sympy.polys.matrices import DomainMatrix +from sympy.polys.matrices.exceptions import DMNonInvertibleMatrixError +from sympy.polys.polyerrors import CoercionFailed, NotInvertible +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import is_sequence +from sympy.utilities.misc import filldedent, as_int + +from .exceptions import ShapeError, NonSquareMatrixError, NonInvertibleMatrixError +from .matrixbase import classof, MatrixBase +from .kind import MatrixKind + + +class RepMatrix(MatrixBase): + """Matrix implementation based on DomainMatrix as an internal representation. + + The RepMatrix class is a superclass for Matrix, ImmutableMatrix, + SparseMatrix and ImmutableSparseMatrix which are the main usable matrix + classes in SymPy. Most methods on this class are simply forwarded to + DomainMatrix. + """ + + # + # MatrixBase is the common superclass for all of the usable explicit matrix + # classes in SymPy. The idea is that MatrixBase is an abstract class though + # and that subclasses will implement the lower-level methods. + # + # RepMatrix is a subclass of MatrixBase that uses DomainMatrix as an + # internal representation and delegates lower-level methods to + # DomainMatrix. All of SymPy's standard explicit matrix classes subclass + # RepMatrix and so use DomainMatrix internally. + # + # A RepMatrix uses an internal DomainMatrix with the domain set to ZZ, QQ + # or EXRAW. The EXRAW domain is equivalent to the previous implementation + # of Matrix that used Expr for the elements. The ZZ and QQ domains are used + # when applicable just because they are compatible with the previous + # implementation but are much more efficient. Other domains such as QQ[x] + # are not used because they differ from Expr in some way (e.g. automatic + # expansion of powers and products). + # + + _rep: DomainMatrix + + def __eq__(self, other): + # Skip sympify for mutable matrices... + if not isinstance(other, RepMatrix): + try: + other = _sympify(other) + except SympifyError: + return NotImplemented + if not isinstance(other, RepMatrix): + return NotImplemented + + return self._rep.unify_eq(other._rep) + + def to_DM(self, domain=None, **kwargs): + """Convert to a :class:`~.DomainMatrix`. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2], [3, 4]]) + >>> M.to_DM() + DomainMatrix({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ) + + The :meth:`DomainMatrix.to_Matrix` method can be used to convert back: + + >>> M.to_DM().to_Matrix() == M + True + + The domain can be given explicitly or otherwise it will be chosen by + :func:`construct_domain`. Any keyword arguments (besides ``domain``) + are passed to :func:`construct_domain`: + + >>> from sympy import QQ, symbols + >>> x = symbols('x') + >>> M = Matrix([[x, 1], [1, x]]) + >>> M + Matrix([ + [x, 1], + [1, x]]) + >>> M.to_DM().domain + ZZ[x] + >>> M.to_DM(field=True).domain + ZZ(x) + >>> M.to_DM(domain=QQ[x]).domain + QQ[x] + + See Also + ======== + + DomainMatrix + DomainMatrix.to_Matrix + DomainMatrix.convert_to + DomainMatrix.choose_domain + construct_domain + """ + if domain is not None: + if kwargs: + raise TypeError("Options cannot be used with domain parameter") + return self._rep.convert_to(domain) + + rep = self._rep + dom = rep.domain + + # If the internal DomainMatrix is already ZZ or QQ then we can maybe + # bypass calling construct_domain or performing any conversions. Some + # kwargs might affect this though e.g. field=True (not sure if there + # are others). + if not kwargs: + if dom.is_ZZ: + return rep.copy() + elif dom.is_QQ: + # All elements might be integers + try: + return rep.convert_to(ZZ) + except CoercionFailed: + pass + return rep.copy() + + # Let construct_domain choose a domain + rep_dom = rep.choose_domain(**kwargs) + + # XXX: There should be an option to construct_domain to choose EXRAW + # instead of EX. At least converting to EX does not initially trigger + # EX.simplify which is what we want here but should probably be + # considered a bug in EX. Perhaps also this could be handled in + # DomainMatrix.choose_domain rather than here... + if rep_dom.domain.is_EX: + rep_dom = rep_dom.convert_to(EXRAW) + + return rep_dom + + @classmethod + def _unify_element_sympy(cls, rep, element): + domain = rep.domain + element = _sympify(element) + + if domain != EXRAW: + # The domain can only be ZZ, QQ or EXRAW + if element.is_Integer: + new_domain = domain + elif element.is_Rational: + new_domain = QQ + else: + new_domain = EXRAW + + # XXX: This converts the domain for all elements in the matrix + # which can be slow. This happens e.g. if __setitem__ changes one + # element to something that does not fit in the domain + if new_domain != domain: + rep = rep.convert_to(new_domain) + domain = new_domain + + if domain != EXRAW: + element = new_domain.from_sympy(element) + + if domain == EXRAW and not isinstance(element, Expr): + sympy_deprecation_warning( + """ + non-Expr objects in a Matrix is deprecated. Matrix represents + a mathematical matrix. To represent a container of non-numeric + entities, Use a list of lists, TableForm, NumPy array, or some + other data structure instead. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-non-expr-in-matrix", + stacklevel=4, + ) + + return rep, element + + @classmethod + def _dod_to_DomainMatrix(cls, rows, cols, dod, types): + + if not all(issubclass(typ, Expr) for typ in types): + sympy_deprecation_warning( + """ + non-Expr objects in a Matrix is deprecated. Matrix represents + a mathematical matrix. To represent a container of non-numeric + entities, Use a list of lists, TableForm, NumPy array, or some + other data structure instead. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-non-expr-in-matrix", + stacklevel=6, + ) + + rep = DomainMatrix(dod, (rows, cols), EXRAW) + + if all(issubclass(typ, Rational) for typ in types): + if all(issubclass(typ, Integer) for typ in types): + rep = rep.convert_to(ZZ) + else: + rep = rep.convert_to(QQ) + + return rep + + @classmethod + def _flat_list_to_DomainMatrix(cls, rows, cols, flat_list): + + elements_dod = defaultdict(dict) + for n, element in enumerate(flat_list): + if element != 0: + i, j = divmod(n, cols) + elements_dod[i][j] = element + + types = set(map(type, flat_list)) + + rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types) + return rep + + @classmethod + def _smat_to_DomainMatrix(cls, rows, cols, smat): + + elements_dod = defaultdict(dict) + for (i, j), element in smat.items(): + if element != 0: + elements_dod[i][j] = element + + types = set(map(type, smat.values())) + + rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types) + return rep + + def flat(self): + return self._rep.to_sympy().to_list_flat() + + def _eval_tolist(self): + return self._rep.to_sympy().to_list() + + def _eval_todok(self): + return self._rep.to_sympy().to_dok() + + @classmethod + def _eval_from_dok(cls, rows, cols, dok): + return cls._fromrep(cls._smat_to_DomainMatrix(rows, cols, dok)) + + def _eval_values(self): + return list(self._eval_iter_values()) + + def _eval_iter_values(self): + rep = self._rep + K = rep.domain + values = rep.iter_values() + if not K.is_EXRAW: + values = map(K.to_sympy, values) + return values + + def _eval_iter_items(self): + rep = self._rep + K = rep.domain + to_sympy = K.to_sympy + items = rep.iter_items() + if not K.is_EXRAW: + items = ((i, to_sympy(v)) for i, v in items) + return items + + def copy(self): + return self._fromrep(self._rep.copy()) + + @property + def kind(self) -> MatrixKind: + domain = self._rep.domain + element_kind: Kind + if domain in (ZZ, QQ): + element_kind = NumberKind + elif domain == EXRAW: + kinds = {e.kind for e in self.values()} + if len(kinds) == 1: + [element_kind] = kinds + else: + element_kind = UndefinedKind + else: # pragma: no cover + raise RuntimeError("Domain should only be ZZ, QQ or EXRAW") + return MatrixKind(element_kind) + + def _eval_has(self, *patterns): + # if the matrix has any zeros, see if S.Zero + # has the pattern. If _smat is full length, + # the matrix has no zeros. + zhas = False + dok = self.todok() + if len(dok) != self.rows*self.cols: + zhas = S.Zero.has(*patterns) + return zhas or any(value.has(*patterns) for value in dok.values()) + + def _eval_is_Identity(self): + if not all(self[i, i] == 1 for i in range(self.rows)): + return False + return len(self.todok()) == self.rows + + def _eval_is_symmetric(self, simpfunc): + diff = (self - self.T).applyfunc(simpfunc) + return len(diff.values()) == 0 + + def _eval_transpose(self): + """Returns the transposed SparseMatrix of this SparseMatrix. + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> a = SparseMatrix(((1, 2), (3, 4))) + >>> a + Matrix([ + [1, 2], + [3, 4]]) + >>> a.T + Matrix([ + [1, 3], + [2, 4]]) + """ + return self._fromrep(self._rep.transpose()) + + def _eval_col_join(self, other): + return self._fromrep(self._rep.vstack(other._rep)) + + def _eval_row_join(self, other): + return self._fromrep(self._rep.hstack(other._rep)) + + def _eval_extract(self, rowsList, colsList): + return self._fromrep(self._rep.extract(rowsList, colsList)) + + def __getitem__(self, key): + return _getitem_RepMatrix(self, key) + + @classmethod + def _eval_zeros(cls, rows, cols): + rep = DomainMatrix.zeros((rows, cols), ZZ) + return cls._fromrep(rep) + + @classmethod + def _eval_eye(cls, rows, cols): + rep = DomainMatrix.eye((rows, cols), ZZ) + return cls._fromrep(rep) + + def _eval_add(self, other): + return classof(self, other)._fromrep(self._rep + other._rep) + + def _eval_matrix_mul(self, other): + return classof(self, other)._fromrep(self._rep * other._rep) + + def _eval_matrix_mul_elementwise(self, other): + selfrep, otherrep = self._rep.unify(other._rep) + newrep = selfrep.mul_elementwise(otherrep) + return classof(self, other)._fromrep(newrep) + + def _eval_scalar_mul(self, other): + rep, other = self._unify_element_sympy(self._rep, other) + return self._fromrep(rep.scalarmul(other)) + + def _eval_scalar_rmul(self, other): + rep, other = self._unify_element_sympy(self._rep, other) + return self._fromrep(rep.rscalarmul(other)) + + def _eval_Abs(self): + return self._fromrep(self._rep.applyfunc(abs)) + + def _eval_conjugate(self): + rep = self._rep + domain = rep.domain + if domain in (ZZ, QQ): + return self.copy() + else: + return self._fromrep(rep.applyfunc(lambda e: e.conjugate())) + + def equals(self, other, failing_expression=False): + """Applies ``equals`` to corresponding elements of the matrices, + trying to prove that the elements are equivalent, returning True + if they are, False if any pair is not, and None (or the first + failing expression if failing_expression is True) if it cannot + be decided if the expressions are equivalent or not. This is, in + general, an expensive operation. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import x + >>> A = Matrix([x*(x - 1), 0]) + >>> B = Matrix([x**2 - x, 0]) + >>> A == B + False + >>> A.simplify() == B.simplify() + True + >>> A.equals(B) + True + >>> A.equals(2) + False + + See Also + ======== + sympy.core.expr.Expr.equals + """ + if self.shape != getattr(other, 'shape', None): + return False + + rv = True + for i in range(self.rows): + for j in range(self.cols): + ans = self[i, j].equals(other[i, j], failing_expression) + if ans is False: + return False + elif ans is not True and rv is True: + rv = ans + return rv + + def inv_mod(M, m): + r""" + Returns the inverse of the integer matrix ``M`` modulo ``m``. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix(2, 2, [1, 2, 3, 4]) + >>> A.inv_mod(5) + Matrix([ + [3, 1], + [4, 2]]) + >>> A.inv_mod(3) + Matrix([ + [1, 1], + [0, 1]]) + + """ + + if not M.is_square: + raise NonSquareMatrixError() + + try: + m = as_int(m) + except ValueError: + raise TypeError("inv_mod: modulus m must be an integer") + + K = GF(m, symmetric=False) + + try: + dM = M.to_DM(K) + except CoercionFailed: + raise ValueError("inv_mod: matrix entries must be integers") + + if K.is_Field: + try: + dMi = dM.inv() + except DMNonInvertibleMatrixError as exc: + msg = f'Matrix is not invertible (mod {m})' + raise NonInvertibleMatrixError(msg) from exc + else: + dMadj, det = dM.adj_det() + try: + detinv = 1 / det + except NotInvertible: + msg = f'Matrix is not invertible (mod {m})' + raise NonInvertibleMatrixError(msg) + dMi = dMadj * detinv + + return dMi.to_Matrix() + + def lll(self, delta=0.75): + """LLL-reduced basis for the rowspace of a matrix of integers. + + Performs the Lenstra–Lenstra–Lovász (LLL) basis reduction algorithm. + + The implementation is provided by :class:`~DomainMatrix`. See + :meth:`~DomainMatrix.lll` for more details. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 0, 0, 0, -20160], + ... [0, 1, 0, 0, 33768], + ... [0, 0, 1, 0, 39578], + ... [0, 0, 0, 1, 47757]]) + >>> M.lll() + Matrix([ + [ 10, -3, -2, 8, -4], + [ 3, -9, 8, 1, -11], + [ -3, 13, -9, -3, -9], + [-12, -7, -11, 9, -1]]) + + See Also + ======== + + lll_transform + sympy.polys.matrices.domainmatrix.DomainMatrix.lll + """ + delta = QQ.from_sympy(_sympify(delta)) + dM = self._rep.convert_to(ZZ) + basis = dM.lll(delta=delta) + return self._fromrep(basis) + + def lll_transform(self, delta=0.75): + """LLL-reduced basis and transformation matrix. + + Performs the Lenstra–Lenstra–Lovász (LLL) basis reduction algorithm. + + The implementation is provided by :class:`~DomainMatrix`. See + :meth:`~DomainMatrix.lll_transform` for more details. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 0, 0, 0, -20160], + ... [0, 1, 0, 0, 33768], + ... [0, 0, 1, 0, 39578], + ... [0, 0, 0, 1, 47757]]) + >>> B, T = M.lll_transform() + >>> B + Matrix([ + [ 10, -3, -2, 8, -4], + [ 3, -9, 8, 1, -11], + [ -3, 13, -9, -3, -9], + [-12, -7, -11, 9, -1]]) + >>> T + Matrix([ + [ 10, -3, -2, 8], + [ 3, -9, 8, 1], + [ -3, 13, -9, -3], + [-12, -7, -11, 9]]) + + The transformation matrix maps the original basis to the LLL-reduced + basis: + + >>> T * M == B + True + + See Also + ======== + + lll + sympy.polys.matrices.domainmatrix.DomainMatrix.lll_transform + """ + delta = QQ.from_sympy(_sympify(delta)) + dM = self._rep.convert_to(ZZ) + basis, transform = dM.lll_transform(delta=delta) + B = self._fromrep(basis) + T = self._fromrep(transform) + return B, T + + +class MutableRepMatrix(RepMatrix): + """Mutable matrix based on DomainMatrix as the internal representation""" + + # + # MutableRepMatrix is a subclass of RepMatrix that adds/overrides methods + # to make the instances mutable. MutableRepMatrix is a superclass for both + # MutableDenseMatrix and MutableSparseMatrix. + # + + is_zero = False + + def __new__(cls, *args, **kwargs): + return cls._new(*args, **kwargs) + + @classmethod + def _new(cls, *args, copy=True, **kwargs): + if copy is False: + # The input was rows, cols, [list]. + # It should be used directly without creating a copy. + if len(args) != 3: + raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]") + rows, cols, flat_list = args + else: + rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs) + flat_list = list(flat_list) # create a shallow copy + + rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list) + + return cls._fromrep(rep) + + @classmethod + def _fromrep(cls, rep): + obj = super().__new__(cls) + obj.rows, obj.cols = rep.shape + obj._rep = rep + return obj + + def copy(self): + return self._fromrep(self._rep.copy()) + + def as_mutable(self): + return self.copy() + + def __setitem__(self, key, value): + """ + + Examples + ======== + + >>> from sympy import Matrix, I, zeros, ones + >>> m = Matrix(((1, 2+I), (3, 4))) + >>> m + Matrix([ + [1, 2 + I], + [3, 4]]) + >>> m[1, 0] = 9 + >>> m + Matrix([ + [1, 2 + I], + [9, 4]]) + >>> m[1, 0] = [[0, 1]] + + To replace row r you assign to position r*m where m + is the number of columns: + + >>> M = zeros(4) + >>> m = M.cols + >>> M[3*m] = ones(1, m)*2; M + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [2, 2, 2, 2]]) + + And to replace column c you can assign to position c: + + >>> M[2] = ones(m, 1)*4; M + Matrix([ + [0, 0, 4, 0], + [0, 0, 4, 0], + [0, 0, 4, 0], + [2, 2, 4, 2]]) + """ + rv = self._setitem(key, value) + if rv is not None: + i, j, value = rv + self._rep, value = self._unify_element_sympy(self._rep, value) + self._rep.rep.setitem(i, j, value) + + def _eval_col_del(self, col): + self._rep = DomainMatrix.hstack(self._rep[:,:col], self._rep[:,col+1:]) + self.cols -= 1 + + def _eval_row_del(self, row): + self._rep = DomainMatrix.vstack(self._rep[:row,:], self._rep[row+1:, :]) + self.rows -= 1 + + def _eval_col_insert(self, col, other): + other = self._new(other) + return self.hstack(self[:,:col], other, self[:,col:]) + + def _eval_row_insert(self, row, other): + other = self._new(other) + return self.vstack(self[:row,:], other, self[row:,:]) + + def col_op(self, j, f): + """In-place operation on col j using two-arg functor whose args are + interpreted as (self[i, j], i). + + Examples + ======== + + >>> from sympy import eye + >>> M = eye(3) + >>> M.col_op(1, lambda v, i: v + 2*M[i, 0]); M + Matrix([ + [1, 2, 0], + [0, 1, 0], + [0, 0, 1]]) + + See Also + ======== + col + row_op + """ + for i in range(self.rows): + self[i, j] = f(self[i, j], i) + + def col_swap(self, i, j): + """Swap the two given columns of the matrix in-place. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 0], [1, 0]]) + >>> M + Matrix([ + [1, 0], + [1, 0]]) + >>> M.col_swap(0, 1) + >>> M + Matrix([ + [0, 1], + [0, 1]]) + + See Also + ======== + + col + row_swap + """ + for k in range(0, self.rows): + self[k, i], self[k, j] = self[k, j], self[k, i] + + def row_op(self, i, f): + """In-place operation on row ``i`` using two-arg functor whose args are + interpreted as ``(self[i, j], j)``. + + Examples + ======== + + >>> from sympy import eye + >>> M = eye(3) + >>> M.row_op(1, lambda v, j: v + 2*M[0, j]); M + Matrix([ + [1, 0, 0], + [2, 1, 0], + [0, 0, 1]]) + + See Also + ======== + row + zip_row_op + col_op + + """ + for j in range(self.cols): + self[i, j] = f(self[i, j], j) + + #The next three methods give direct support for the most common row operations inplace. + def row_mult(self,i,factor): + """Multiply the given row by the given factor in-place. + + Examples + ======== + + >>> from sympy import eye + >>> M = eye(3) + >>> M.row_mult(1,7); M + Matrix([ + [1, 0, 0], + [0, 7, 0], + [0, 0, 1]]) + + """ + for j in range(self.cols): + self[i,j] *= factor + + def row_add(self,s,t,k): + """Add k times row s (source) to row t (target) in place. + + Examples + ======== + + >>> from sympy import eye + >>> M = eye(3) + >>> M.row_add(0, 2,3); M + Matrix([ + [1, 0, 0], + [0, 1, 0], + [3, 0, 1]]) + """ + + for j in range(self.cols): + self[t,j] += k*self[s,j] + + def row_swap(self, i, j): + """Swap the two given rows of the matrix in-place. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[0, 1], [1, 0]]) + >>> M + Matrix([ + [0, 1], + [1, 0]]) + >>> M.row_swap(0, 1) + >>> M + Matrix([ + [1, 0], + [0, 1]]) + + See Also + ======== + + row + col_swap + """ + for k in range(0, self.cols): + self[i, k], self[j, k] = self[j, k], self[i, k] + + def zip_row_op(self, i, k, f): + """In-place operation on row ``i`` using two-arg functor whose args are + interpreted as ``(self[i, j], self[k, j])``. + + Examples + ======== + + >>> from sympy import eye + >>> M = eye(3) + >>> M.zip_row_op(1, 0, lambda v, u: v + 2*u); M + Matrix([ + [1, 0, 0], + [2, 1, 0], + [0, 0, 1]]) + + See Also + ======== + row + row_op + col_op + + """ + for j in range(self.cols): + self[i, j] = f(self[i, j], self[k, j]) + + def copyin_list(self, key, value): + """Copy in elements from a list. + + Parameters + ========== + + key : slice + The section of this matrix to replace. + value : iterable + The iterable to copy values from. + + Examples + ======== + + >>> from sympy import eye + >>> I = eye(3) + >>> I[:2, 0] = [1, 2] # col + >>> I + Matrix([ + [1, 0, 0], + [2, 1, 0], + [0, 0, 1]]) + >>> I[1, :2] = [[3, 4]] + >>> I + Matrix([ + [1, 0, 0], + [3, 4, 0], + [0, 0, 1]]) + + See Also + ======== + + copyin_matrix + """ + if not is_sequence(value): + raise TypeError("`value` must be an ordered iterable, not %s." % type(value)) + return self.copyin_matrix(key, type(self)(value)) + + def copyin_matrix(self, key, value): + """Copy in values from a matrix into the given bounds. + + Parameters + ========== + + key : slice + The section of this matrix to replace. + value : Matrix + The matrix to copy values from. + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> M = Matrix([[0, 1], [2, 3], [4, 5]]) + >>> I = eye(3) + >>> I[:3, :2] = M + >>> I + Matrix([ + [0, 1, 0], + [2, 3, 0], + [4, 5, 1]]) + >>> I[0, 1] = M + >>> I + Matrix([ + [0, 0, 1], + [2, 2, 3], + [4, 4, 5]]) + + See Also + ======== + + copyin_list + """ + rlo, rhi, clo, chi = self.key2bounds(key) + shape = value.shape + dr, dc = rhi - rlo, chi - clo + if shape != (dr, dc): + raise ShapeError(filldedent("The Matrix `value` doesn't have the " + "same dimensions " + "as the in sub-Matrix given by `key`.")) + + for i in range(value.rows): + for j in range(value.cols): + self[i + rlo, j + clo] = value[i, j] + + def fill(self, value): + """Fill self with the given value. + + Notes + ===== + + Unless many values are going to be deleted (i.e. set to zero) + this will create a matrix that is slower than a dense matrix in + operations. + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> M = SparseMatrix.zeros(3); M + Matrix([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0]]) + >>> M.fill(1); M + Matrix([ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1]]) + + See Also + ======== + + zeros + ones + """ + value = _sympify(value) + if not value: + self._rep = DomainMatrix.zeros(self.shape, EXRAW) + else: + elements_dod = {i: dict.fromkeys(range(self.cols), value) for i in range(self.rows)} + self._rep = DomainMatrix(elements_dod, self.shape, EXRAW) + + +def _getitem_RepMatrix(self, key): + """Return portion of self defined by key. If the key involves a slice + then a list will be returned (if key is a single slice) or a matrix + (if key was a tuple involving a slice). + + Examples + ======== + + >>> from sympy import Matrix, I + >>> m = Matrix([ + ... [1, 2 + I], + ... [3, 4 ]]) + + If the key is a tuple that does not involve a slice then that element + is returned: + + >>> m[1, 0] + 3 + + When a tuple key involves a slice, a matrix is returned. Here, the + first column is selected (all rows, column 0): + + >>> m[:, 0] + Matrix([ + [1], + [3]]) + + If the slice is not a tuple then it selects from the underlying + list of elements that are arranged in row order and a list is + returned if a slice is involved: + + >>> m[0] + 1 + >>> m[::2] + [1, 3] + """ + if isinstance(key, tuple): + i, j = key + try: + return self._rep.getitem_sympy(index_(i), index_(j)) + except (TypeError, IndexError): + if (isinstance(i, Expr) and not i.is_number) or (isinstance(j, Expr) and not j.is_number): + if ((j < 0) is True) or ((j >= self.shape[1]) is True) or\ + ((i < 0) is True) or ((i >= self.shape[0]) is True): + raise ValueError("index out of boundary") + from sympy.matrices.expressions.matexpr import MatrixElement + return MatrixElement(self, i, j) + + if isinstance(i, slice): + i = range(self.rows)[i] + elif is_sequence(i): + pass + else: + i = [i] + if isinstance(j, slice): + j = range(self.cols)[j] + elif is_sequence(j): + pass + else: + j = [j] + return self.extract(i, j) + + else: + # Index/slice like a flattened list + rows, cols = self.shape + + # Raise the appropriate exception: + if not rows * cols: + return [][key] + + rep = self._rep.rep + domain = rep.domain + is_slice = isinstance(key, slice) + + if is_slice: + values = [rep.getitem(*divmod(n, cols)) for n in range(rows * cols)[key]] + else: + values = [rep.getitem(*divmod(index_(key), cols))] + + if domain != EXRAW: + to_sympy = domain.to_sympy + values = [to_sympy(val) for val in values] + + if is_slice: + return values + else: + return values[0] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/solvers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/solvers.py new file mode 100644 index 0000000000000000000000000000000000000000..1fba990df80dcf46304ecb1412f5382f60948c51 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/solvers.py @@ -0,0 +1,942 @@ +from sympy.core.function import expand_mul +from sympy.core.symbol import Dummy, uniquely_named_symbol, symbols +from sympy.utilities.iterables import numbered_symbols + +from .exceptions import ShapeError, NonSquareMatrixError, NonInvertibleMatrixError +from .eigen import _fuzzy_positive_definite +from .utilities import _get_intermediate_simp, _iszero + + +def _diagonal_solve(M, rhs): + """Solves ``Ax = B`` efficiently, where A is a diagonal Matrix, + with non-zero diagonal entries. + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> A = eye(2)*2 + >>> B = Matrix([[1, 2], [3, 4]]) + >>> A.diagonal_solve(B) == B/2 + True + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.lower_triangular_solve + sympy.matrices.dense.DenseMatrix.upper_triangular_solve + gauss_jordan_solve + cholesky_solve + LDLsolve + LUsolve + QRsolve + pinv_solve + cramer_solve + """ + + if not M.is_diagonal(): + raise TypeError("Matrix should be diagonal") + if rhs.rows != M.rows: + raise TypeError("Size mismatch") + + return M._new( + rhs.rows, rhs.cols, lambda i, j: rhs[i, j] / M[i, i]) + + +def _lower_triangular_solve(M, rhs): + """Solves ``Ax = B``, where A is a lower triangular matrix. + + See Also + ======== + + upper_triangular_solve + gauss_jordan_solve + cholesky_solve + diagonal_solve + LDLsolve + LUsolve + QRsolve + pinv_solve + cramer_solve + """ + + from .dense import MutableDenseMatrix + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + if rhs.rows != M.rows: + raise ShapeError("Matrices size mismatch.") + if not M.is_lower: + raise ValueError("Matrix must be lower triangular.") + + dps = _get_intermediate_simp() + X = MutableDenseMatrix.zeros(M.rows, rhs.cols) + + for j in range(rhs.cols): + for i in range(M.rows): + if M[i, i] == 0: + raise TypeError("Matrix must be non-singular.") + + X[i, j] = dps((rhs[i, j] - sum(M[i, k]*X[k, j] + for k in range(i))) / M[i, i]) + + return M._new(X) + +def _lower_triangular_solve_sparse(M, rhs): + """Solves ``Ax = B``, where A is a lower triangular matrix. + + See Also + ======== + + upper_triangular_solve + gauss_jordan_solve + cholesky_solve + diagonal_solve + LDLsolve + LUsolve + QRsolve + pinv_solve + cramer_solve + """ + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + if rhs.rows != M.rows: + raise ShapeError("Matrices size mismatch.") + if not M.is_lower: + raise ValueError("Matrix must be lower triangular.") + + dps = _get_intermediate_simp() + rows = [[] for i in range(M.rows)] + + for i, j, v in M.row_list(): + if i > j: + rows[i].append((j, v)) + + X = rhs.as_mutable() + + for j in range(rhs.cols): + for i in range(rhs.rows): + for u, v in rows[i]: + X[i, j] -= v*X[u, j] + + X[i, j] = dps(X[i, j] / M[i, i]) + + return M._new(X) + + +def _upper_triangular_solve(M, rhs): + """Solves ``Ax = B``, where A is an upper triangular matrix. + + See Also + ======== + + lower_triangular_solve + gauss_jordan_solve + cholesky_solve + diagonal_solve + LDLsolve + LUsolve + QRsolve + pinv_solve + cramer_solve + """ + + from .dense import MutableDenseMatrix + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + if rhs.rows != M.rows: + raise ShapeError("Matrix size mismatch.") + if not M.is_upper: + raise TypeError("Matrix is not upper triangular.") + + dps = _get_intermediate_simp() + X = MutableDenseMatrix.zeros(M.rows, rhs.cols) + + for j in range(rhs.cols): + for i in reversed(range(M.rows)): + if M[i, i] == 0: + raise ValueError("Matrix must be non-singular.") + + X[i, j] = dps((rhs[i, j] - sum(M[i, k]*X[k, j] + for k in range(i + 1, M.rows))) / M[i, i]) + + return M._new(X) + +def _upper_triangular_solve_sparse(M, rhs): + """Solves ``Ax = B``, where A is an upper triangular matrix. + + See Also + ======== + + lower_triangular_solve + gauss_jordan_solve + cholesky_solve + diagonal_solve + LDLsolve + LUsolve + QRsolve + pinv_solve + cramer_solve + """ + + if not M.is_square: + raise NonSquareMatrixError("Matrix must be square.") + if rhs.rows != M.rows: + raise ShapeError("Matrix size mismatch.") + if not M.is_upper: + raise TypeError("Matrix is not upper triangular.") + + dps = _get_intermediate_simp() + rows = [[] for i in range(M.rows)] + + for i, j, v in M.row_list(): + if i < j: + rows[i].append((j, v)) + + X = rhs.as_mutable() + + for j in range(rhs.cols): + for i in reversed(range(rhs.rows)): + for u, v in reversed(rows[i]): + X[i, j] -= v*X[u, j] + + X[i, j] = dps(X[i, j] / M[i, i]) + + return M._new(X) + + +def _cholesky_solve(M, rhs): + """Solves ``Ax = B`` using Cholesky decomposition, + for a general square non-singular matrix. + For a non-square matrix with rows > cols, + the least squares solution is returned. + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.lower_triangular_solve + sympy.matrices.dense.DenseMatrix.upper_triangular_solve + gauss_jordan_solve + diagonal_solve + LDLsolve + LUsolve + QRsolve + pinv_solve + cramer_solve + """ + + if M.rows < M.cols: + raise NotImplementedError( + 'Under-determined System. Try M.gauss_jordan_solve(rhs)') + + hermitian = True + reform = False + + if M.is_symmetric(): + hermitian = False + elif not M.is_hermitian: + reform = True + + if reform or _fuzzy_positive_definite(M) is False: + H = M.H + M = H.multiply(M) + rhs = H.multiply(rhs) + hermitian = not M.is_symmetric() + + L = M.cholesky(hermitian=hermitian) + Y = L.lower_triangular_solve(rhs) + + if hermitian: + return (L.H).upper_triangular_solve(Y) + else: + return (L.T).upper_triangular_solve(Y) + + +def _LDLsolve(M, rhs): + """Solves ``Ax = B`` using LDL decomposition, + for a general square and non-singular matrix. + + For a non-square matrix with rows > cols, + the least squares solution is returned. + + Examples + ======== + + >>> from sympy import Matrix, eye + >>> A = eye(2)*2 + >>> B = Matrix([[1, 2], [3, 4]]) + >>> A.LDLsolve(B) == B/2 + True + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.LDLdecomposition + sympy.matrices.dense.DenseMatrix.lower_triangular_solve + sympy.matrices.dense.DenseMatrix.upper_triangular_solve + gauss_jordan_solve + cholesky_solve + diagonal_solve + LUsolve + QRsolve + pinv_solve + cramer_solve + """ + + if M.rows < M.cols: + raise NotImplementedError( + 'Under-determined System. Try M.gauss_jordan_solve(rhs)') + + hermitian = True + reform = False + + if M.is_symmetric(): + hermitian = False + elif not M.is_hermitian: + reform = True + + if reform or _fuzzy_positive_definite(M) is False: + H = M.H + M = H.multiply(M) + rhs = H.multiply(rhs) + hermitian = not M.is_symmetric() + + L, D = M.LDLdecomposition(hermitian=hermitian) + Y = L.lower_triangular_solve(rhs) + Z = D.diagonal_solve(Y) + + if hermitian: + return (L.H).upper_triangular_solve(Z) + else: + return (L.T).upper_triangular_solve(Z) + + +def _LUsolve(M, rhs, iszerofunc=_iszero): + """Solve the linear system ``Ax = rhs`` for ``x`` where ``A = M``. + + This is for symbolic matrices, for real or complex ones use + mpmath.lu_solve or mpmath.qr_solve. + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.lower_triangular_solve + sympy.matrices.dense.DenseMatrix.upper_triangular_solve + gauss_jordan_solve + cholesky_solve + diagonal_solve + LDLsolve + QRsolve + pinv_solve + LUdecomposition + cramer_solve + """ + + if rhs.rows != M.rows: + raise ShapeError( + "``M`` and ``rhs`` must have the same number of rows.") + + m = M.rows + n = M.cols + + if m < n: + raise NotImplementedError("Underdetermined systems not supported.") + + try: + A, perm = M.LUdecomposition_Simple( + iszerofunc=iszerofunc, rankcheck=True) + except ValueError: + raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") + + dps = _get_intermediate_simp() + b = rhs.permute_rows(perm).as_mutable() + + # forward substitution, all diag entries are scaled to 1 + for i in range(m): + for j in range(min(i, n)): + scale = A[i, j] + b.zip_row_op(i, j, lambda x, y: dps(x - scale * y)) + + # consistency check for overdetermined systems + if m > n: + for i in range(n, m): + for j in range(b.cols): + if not iszerofunc(b[i, j]): + raise ValueError("The system is inconsistent.") + + b = b[0:n, :] # truncate zero rows if consistent + + # backward substitution + for i in range(n - 1, -1, -1): + for j in range(i + 1, n): + scale = A[i, j] + b.zip_row_op(i, j, lambda x, y: dps(x - scale * y)) + + scale = A[i, i] + b.row_op(i, lambda x, _: dps(scale**-1 * x)) + + return rhs.__class__(b) + + +def _QRsolve(M, b): + """Solve the linear system ``Ax = b``. + + ``M`` is the matrix ``A``, the method argument is the vector + ``b``. The method returns the solution vector ``x``. If ``b`` is a + matrix, the system is solved for each column of ``b`` and the + return value is a matrix of the same shape as ``b``. + + This method is slower (approximately by a factor of 2) but + more stable for floating-point arithmetic than the LUsolve method. + However, LUsolve usually uses an exact arithmetic, so you do not need + to use QRsolve. + + This is mainly for educational purposes and symbolic matrices, for real + (or complex) matrices use mpmath.qr_solve. + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.lower_triangular_solve + sympy.matrices.dense.DenseMatrix.upper_triangular_solve + gauss_jordan_solve + cholesky_solve + diagonal_solve + LDLsolve + LUsolve + pinv_solve + QRdecomposition + cramer_solve + """ + + dps = _get_intermediate_simp(expand_mul, expand_mul) + Q, R = M.QRdecomposition() + y = Q.T * b + + # back substitution to solve R*x = y: + # We build up the result "backwards" in the vector 'x' and reverse it + # only in the end. + x = [] + n = R.rows + + for j in range(n - 1, -1, -1): + tmp = y[j, :] + + for k in range(j + 1, n): + tmp -= R[j, k] * x[n - 1 - k] + + tmp = dps(tmp) + + x.append(tmp / R[j, j]) + + return M.vstack(*x[::-1]) + + +def _gauss_jordan_solve(M, B, freevar=False): + """ + Solves ``Ax = B`` using Gauss Jordan elimination. + + There may be zero, one, or infinite solutions. If one solution + exists, it will be returned. If infinite solutions exist, it will + be returned parametrically. If no solutions exist, It will throw + ValueError. + + Parameters + ========== + + B : Matrix + The right hand side of the equation to be solved for. Must have + the same number of rows as matrix A. + + freevar : boolean, optional + Flag, when set to `True` will return the indices of the free + variables in the solutions (column Matrix), for a system that is + undetermined (e.g. A has more columns than rows), for which + infinite solutions are possible, in terms of arbitrary + values of free variables. Default `False`. + + Returns + ======= + + x : Matrix + The matrix that will satisfy ``Ax = B``. Will have as many rows as + matrix A has columns, and as many columns as matrix B. + + params : Matrix + If the system is underdetermined (e.g. A has more columns than + rows), infinite solutions are possible, in terms of arbitrary + parameters. These arbitrary parameters are returned as params + Matrix. + + free_var_index : List, optional + If the system is underdetermined (e.g. A has more columns than + rows), infinite solutions are possible, in terms of arbitrary + values of free variables. Then the indices of the free variables + in the solutions (column Matrix) are returned by free_var_index, + if the flag `freevar` is set to `True`. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[1, 2, 1, 1], [1, 2, 2, -1], [2, 4, 0, 6]]) + >>> B = Matrix([7, 12, 4]) + >>> sol, params = A.gauss_jordan_solve(B) + >>> sol + Matrix([ + [-2*tau0 - 3*tau1 + 2], + [ tau0], + [ 2*tau1 + 5], + [ tau1]]) + >>> params + Matrix([ + [tau0], + [tau1]]) + >>> taus_zeroes = { tau:0 for tau in params } + >>> sol_unique = sol.xreplace(taus_zeroes) + >>> sol_unique + Matrix([ + [2], + [0], + [5], + [0]]) + + + >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]]) + >>> B = Matrix([3, 6, 9]) + >>> sol, params = A.gauss_jordan_solve(B) + >>> sol + Matrix([ + [-1], + [ 2], + [ 0]]) + >>> params + Matrix(0, 1, []) + + >>> A = Matrix([[2, -7], [-1, 4]]) + >>> B = Matrix([[-21, 3], [12, -2]]) + >>> sol, params = A.gauss_jordan_solve(B) + >>> sol + Matrix([ + [0, -2], + [3, -1]]) + >>> params + Matrix(0, 2, []) + + + >>> from sympy import Matrix + >>> A = Matrix([[1, 2, 1, 1], [1, 2, 2, -1], [2, 4, 0, 6]]) + >>> B = Matrix([7, 12, 4]) + >>> sol, params, freevars = A.gauss_jordan_solve(B, freevar=True) + >>> sol + Matrix([ + [-2*tau0 - 3*tau1 + 2], + [ tau0], + [ 2*tau1 + 5], + [ tau1]]) + >>> params + Matrix([ + [tau0], + [tau1]]) + >>> freevars + [1, 3] + + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.lower_triangular_solve + sympy.matrices.dense.DenseMatrix.upper_triangular_solve + cholesky_solve + diagonal_solve + LDLsolve + LUsolve + QRsolve + pinv + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gaussian_elimination + + """ + + from sympy.matrices import Matrix, zeros + + cls = M.__class__ + aug = M.hstack(M.copy(), B.copy()) + B_cols = B.cols + row, col = aug[:, :-B_cols].shape + + # solve by reduced row echelon form + A, pivots = aug.rref(simplify=True) + A, v = A[:, :-B_cols], A[:, -B_cols:] + pivots = list(filter(lambda p: p < col, pivots)) + rank = len(pivots) + + # Get index of free symbols (free parameters) + # non-pivots columns are free variables + free_var_index = [c for c in range(A.cols) if c not in pivots] + + # Bring to block form + permutation = Matrix(pivots + free_var_index).T + + # check for existence of solutions + # rank of aug Matrix should be equal to rank of coefficient matrix + if not v[rank:, :].is_zero_matrix: + raise ValueError("Linear system has no solution") + + # Free parameters + # what are current unnumbered free symbol names? + name = uniquely_named_symbol('tau', [aug], + compare=lambda i: str(i).rstrip('1234567890'), + modify=lambda s: '_' + s).name + gen = numbered_symbols(name) + tau = Matrix([next(gen) for k in range((col - rank)*B_cols)]).reshape( + col - rank, B_cols) + + # Full parametric solution + V = A[:rank, free_var_index] + vt = v[:rank, :] + free_sol = tau.vstack(vt - V * tau, tau) + + # Undo permutation + sol = zeros(col, B_cols) + + for k in range(col): + sol[permutation[k], :] = free_sol[k,:] + + sol, tau = cls(sol), cls(tau) + + if freevar: + return sol, tau, free_var_index + else: + return sol, tau + + +def _pinv_solve(M, B, arbitrary_matrix=None): + """Solve ``Ax = B`` using the Moore-Penrose pseudoinverse. + + There may be zero, one, or infinite solutions. If one solution + exists, it will be returned. If infinite solutions exist, one will + be returned based on the value of arbitrary_matrix. If no solutions + exist, the least-squares solution is returned. + + Parameters + ========== + + B : Matrix + The right hand side of the equation to be solved for. Must have + the same number of rows as matrix A. + arbitrary_matrix : Matrix + If the system is underdetermined (e.g. A has more columns than + rows), infinite solutions are possible, in terms of an arbitrary + matrix. This parameter may be set to a specific matrix to use + for that purpose; if so, it must be the same shape as x, with as + many rows as matrix A has columns, and as many columns as matrix + B. If left as None, an appropriate matrix containing dummy + symbols in the form of ``wn_m`` will be used, with n and m being + row and column position of each symbol. + + Returns + ======= + + x : Matrix + The matrix that will satisfy ``Ax = B``. Will have as many rows as + matrix A has columns, and as many columns as matrix B. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> B = Matrix([7, 8]) + >>> A.pinv_solve(B) + Matrix([ + [ _w0_0/6 - _w1_0/3 + _w2_0/6 - 55/18], + [-_w0_0/3 + 2*_w1_0/3 - _w2_0/3 + 1/9], + [ _w0_0/6 - _w1_0/3 + _w2_0/6 + 59/18]]) + >>> A.pinv_solve(B, arbitrary_matrix=Matrix([0, 0, 0])) + Matrix([ + [-55/18], + [ 1/9], + [ 59/18]]) + + See Also + ======== + + sympy.matrices.dense.DenseMatrix.lower_triangular_solve + sympy.matrices.dense.DenseMatrix.upper_triangular_solve + gauss_jordan_solve + cholesky_solve + diagonal_solve + LDLsolve + LUsolve + QRsolve + pinv + + Notes + ===== + + This may return either exact solutions or least squares solutions. + To determine which, check ``A * A.pinv() * B == B``. It will be + True if exact solutions exist, and False if only a least-squares + solution exists. Be aware that the left hand side of that equation + may need to be simplified to correctly compare to the right hand + side. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Moore-Penrose_pseudoinverse#Obtaining_all_solutions_of_a_linear_system + + """ + + from sympy.matrices import eye + + A = M + A_pinv = M.pinv() + + if arbitrary_matrix is None: + rows, cols = A.cols, B.cols + w = symbols('w:{}_:{}'.format(rows, cols), cls=Dummy) + arbitrary_matrix = M.__class__(cols, rows, w).T + + return A_pinv.multiply(B) + (eye(A.cols) - + A_pinv.multiply(A)).multiply(arbitrary_matrix) + + +def _cramer_solve(M, rhs, det_method="laplace"): + """Solves system of linear equations using Cramer's rule. + + This method is relatively inefficient compared to other methods. + However it only uses a single division, assuming a division-free determinant + method is provided. This is helpful to minimize the chance of divide-by-zero + cases in symbolic solutions to linear systems. + + Parameters + ========== + M : Matrix + The matrix representing the left hand side of the equation. + rhs : Matrix + The matrix representing the right hand side of the equation. + det_method : str or callable + The method to use to calculate the determinant of the matrix. + The default is ``'laplace'``. If a callable is passed, it should take a + single argument, the matrix, and return the determinant of the matrix. + + Returns + ======= + x : Matrix + The matrix that will satisfy ``Ax = B``. Will have as many rows as + matrix A has columns, and as many columns as matrix B. + + Examples + ======== + + >>> from sympy import Matrix + >>> A = Matrix([[0, -6, 1], [0, -6, -1], [-5, -2, 3]]) + >>> B = Matrix([[-30, -9], [-18, -27], [-26, 46]]) + >>> x = A.cramer_solve(B) + >>> x + Matrix([ + [ 0, -5], + [ 4, 3], + [-6, 9]]) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Cramer%27s_rule#Explicit_formulas_for_small_systems + + """ + from .dense import zeros + + def entry(i, j): + return rhs[i, sol] if j == col else M[i, j] + + if det_method == "bird": + from .determinant import _det_bird + det = _det_bird + elif det_method == "laplace": + from .determinant import _det_laplace + det = _det_laplace + elif isinstance(det_method, str): + det = lambda matrix: matrix.det(method=det_method) + else: + det = det_method + det_M = det(M) + x = zeros(*rhs.shape) + for sol in range(rhs.shape[1]): + for col in range(rhs.shape[0]): + x[col, sol] = det(M.__class__(*M.shape, entry)) / det_M + return M.__class__(x) + + +def _solve(M, rhs, method='GJ'): + """Solves linear equation where the unique solution exists. + + Parameters + ========== + + rhs : Matrix + Vector representing the right hand side of the linear equation. + + method : string, optional + If set to ``'GJ'`` or ``'GE'``, the Gauss-Jordan elimination will be + used, which is implemented in the routine ``gauss_jordan_solve``. + + If set to ``'LU'``, ``LUsolve`` routine will be used. + + If set to ``'QR'``, ``QRsolve`` routine will be used. + + If set to ``'PINV'``, ``pinv_solve`` routine will be used. + + If set to ``'CRAMER'``, ``cramer_solve`` routine will be used. + + It also supports the methods available for special linear systems + + For positive definite systems: + + If set to ``'CH'``, ``cholesky_solve`` routine will be used. + + If set to ``'LDL'``, ``LDLsolve`` routine will be used. + + To use a different method and to compute the solution via the + inverse, use a method defined in the .inv() docstring. + + Returns + ======= + + solutions : Matrix + Vector representing the solution. + + Raises + ====== + + ValueError + If there is not a unique solution then a ``ValueError`` will be + raised. + + If ``M`` is not square, a ``ValueError`` and a different routine + for solving the system will be suggested. + """ + + if method in ('GJ', 'GE'): + try: + soln, param = M.gauss_jordan_solve(rhs) + + if param: + raise NonInvertibleMatrixError("Matrix det == 0; not invertible. " + "Try ``M.gauss_jordan_solve(rhs)`` to obtain a parametric solution.") + + except ValueError: + raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") + + return soln + + elif method == 'LU': + return M.LUsolve(rhs) + elif method == 'CH': + return M.cholesky_solve(rhs) + elif method == 'QR': + return M.QRsolve(rhs) + elif method == 'LDL': + return M.LDLsolve(rhs) + elif method == 'PINV': + return M.pinv_solve(rhs) + elif method == 'CRAMER': + return M.cramer_solve(rhs) + else: + return M.inv(method=method).multiply(rhs) + + +def _solve_least_squares(M, rhs, method='CH'): + """Return the least-square fit to the data. + + Parameters + ========== + + rhs : Matrix + Vector representing the right hand side of the linear equation. + + method : string or boolean, optional + If set to ``'CH'``, ``cholesky_solve`` routine will be used. + + If set to ``'LDL'``, ``LDLsolve`` routine will be used. + + If set to ``'QR'``, ``QRsolve`` routine will be used. + + If set to ``'PINV'``, ``pinv_solve`` routine will be used. + + Otherwise, the conjugate of ``M`` will be used to create a system + of equations that is passed to ``solve`` along with the hint + defined by ``method``. + + Returns + ======= + + solutions : Matrix + Vector representing the solution. + + Examples + ======== + + >>> from sympy import Matrix, ones + >>> A = Matrix([1, 2, 3]) + >>> B = Matrix([2, 3, 4]) + >>> S = Matrix(A.row_join(B)) + >>> S + Matrix([ + [1, 2], + [2, 3], + [3, 4]]) + + If each line of S represent coefficients of Ax + By + and x and y are [2, 3] then S*xy is: + + >>> r = S*Matrix([2, 3]); r + Matrix([ + [ 8], + [13], + [18]]) + + But let's add 1 to the middle value and then solve for the + least-squares value of xy: + + >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy + Matrix([ + [ 5/3], + [10/3]]) + + The error is given by S*xy - r: + + >>> S*xy - r + Matrix([ + [1/3], + [1/3], + [1/3]]) + >>> _.norm().n(2) + 0.58 + + If a different xy is used, the norm will be higher: + + >>> xy += ones(2, 1)/10 + >>> (S*xy - r).norm().n(2) + 1.5 + + """ + + if method == 'CH': + return M.cholesky_solve(rhs) + elif method == 'QR': + return M.QRsolve(rhs) + elif method == 'LDL': + return M.LDLsolve(rhs) + elif method == 'PINV': + return M.pinv_solve(rhs) + else: + t = M.H + return (t * M).solve(t * rhs, method=method) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/sparse.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/sparse.py new file mode 100644 index 0000000000000000000000000000000000000000..95a7b3ca0ac29cf4409ec1eeecd059f9643e9bbc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/sparse.py @@ -0,0 +1,473 @@ +from collections.abc import Callable + +from sympy.core.containers import Dict +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import is_sequence +from sympy.utilities.misc import as_int + +from .matrixbase import MatrixBase +from .repmatrix import MutableRepMatrix, RepMatrix + +from .utilities import _iszero + +from .decompositions import ( + _liupc, _row_structure_symbolic_cholesky, _cholesky_sparse, + _LDLdecomposition_sparse) + +from .solvers import ( + _lower_triangular_solve_sparse, _upper_triangular_solve_sparse) + + +class SparseRepMatrix(RepMatrix): + """ + A sparse matrix (a matrix with a large number of zero elements). + + Examples + ======== + + >>> from sympy import SparseMatrix, ones + >>> SparseMatrix(2, 2, range(4)) + Matrix([ + [0, 1], + [2, 3]]) + >>> SparseMatrix(2, 2, {(1, 1): 2}) + Matrix([ + [0, 0], + [0, 2]]) + + A SparseMatrix can be instantiated from a ragged list of lists: + + >>> SparseMatrix([[1, 2, 3], [1, 2], [1]]) + Matrix([ + [1, 2, 3], + [1, 2, 0], + [1, 0, 0]]) + + For safety, one may include the expected size and then an error + will be raised if the indices of any element are out of range or + (for a flat list) if the total number of elements does not match + the expected shape: + + >>> SparseMatrix(2, 2, [1, 2]) + Traceback (most recent call last): + ... + ValueError: List length (2) != rows*columns (4) + + Here, an error is not raised because the list is not flat and no + element is out of range: + + >>> SparseMatrix(2, 2, [[1, 2]]) + Matrix([ + [1, 2], + [0, 0]]) + + But adding another element to the first (and only) row will cause + an error to be raised: + + >>> SparseMatrix(2, 2, [[1, 2, 3]]) + Traceback (most recent call last): + ... + ValueError: The location (0, 2) is out of designated range: (1, 1) + + To autosize the matrix, pass None for rows: + + >>> SparseMatrix(None, [[1, 2, 3]]) + Matrix([[1, 2, 3]]) + >>> SparseMatrix(None, {(1, 1): 1, (3, 3): 3}) + Matrix([ + [0, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 3]]) + + Values that are themselves a Matrix are automatically expanded: + + >>> SparseMatrix(4, 4, {(1, 1): ones(2)}) + Matrix([ + [0, 0, 0, 0], + [0, 1, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 0]]) + + A ValueError is raised if the expanding matrix tries to overwrite + a different element already present: + + >>> SparseMatrix(3, 3, {(0, 0): ones(2), (1, 1): 2}) + Traceback (most recent call last): + ... + ValueError: collision at (1, 1) + + See Also + ======== + DenseMatrix + MutableSparseMatrix + ImmutableSparseMatrix + """ + + @classmethod + def _handle_creation_inputs(cls, *args, **kwargs): + if len(args) == 1 and isinstance(args[0], MatrixBase): + rows = args[0].rows + cols = args[0].cols + smat = args[0].todok() + return rows, cols, smat + + smat = {} + # autosizing + if len(args) == 2 and args[0] is None: + args = [None, None, args[1]] + + if len(args) == 3: + r, c = args[:2] + if r is c is None: + rows = cols = None + elif None in (r, c): + raise ValueError( + 'Pass rows=None and no cols for autosizing.') + else: + rows, cols = as_int(args[0]), as_int(args[1]) + + if isinstance(args[2], Callable): + op = args[2] + + if None in (rows, cols): + raise ValueError( + "{} and {} must be integers for this " + "specification.".format(rows, cols)) + + row_indices = [cls._sympify(i) for i in range(rows)] + col_indices = [cls._sympify(j) for j in range(cols)] + + for i in row_indices: + for j in col_indices: + value = cls._sympify(op(i, j)) + if value != cls.zero: + smat[i, j] = value + + return rows, cols, smat + + elif isinstance(args[2], (dict, Dict)): + def update(i, j, v): + # update smat and make sure there are no collisions + if v: + if (i, j) in smat and v != smat[i, j]: + raise ValueError( + "There is a collision at {} for {} and {}." + .format((i, j), v, smat[i, j]) + ) + smat[i, j] = v + + # manual copy, copy.deepcopy() doesn't work + for (r, c), v in args[2].items(): + if isinstance(v, MatrixBase): + for (i, j), vv in v.todok().items(): + update(r + i, c + j, vv) + elif isinstance(v, (list, tuple)): + _, _, smat = cls._handle_creation_inputs(v, **kwargs) + for i, j in smat: + update(r + i, c + j, smat[i, j]) + else: + v = cls._sympify(v) + update(r, c, cls._sympify(v)) + + elif is_sequence(args[2]): + flat = not any(is_sequence(i) for i in args[2]) + if not flat: + _, _, smat = \ + cls._handle_creation_inputs(args[2], **kwargs) + else: + flat_list = args[2] + if len(flat_list) != rows * cols: + raise ValueError( + "The length of the flat list ({}) does not " + "match the specified size ({} * {})." + .format(len(flat_list), rows, cols) + ) + + for i in range(rows): + for j in range(cols): + value = flat_list[i*cols + j] + value = cls._sympify(value) + if value != cls.zero: + smat[i, j] = value + + if rows is None: # autosizing + keys = smat.keys() + rows = max(r for r, _ in keys) + 1 if keys else 0 + cols = max(c for _, c in keys) + 1 if keys else 0 + + else: + for i, j in smat.keys(): + if i and i >= rows or j and j >= cols: + raise ValueError( + "The location {} is out of the designated range" + "[{}, {}]x[{}, {}]" + .format((i, j), 0, rows - 1, 0, cols - 1) + ) + + return rows, cols, smat + + elif len(args) == 1 and isinstance(args[0], (list, tuple)): + # list of values or lists + v = args[0] + c = 0 + for i, row in enumerate(v): + if not isinstance(row, (list, tuple)): + row = [row] + for j, vv in enumerate(row): + if vv != cls.zero: + smat[i, j] = cls._sympify(vv) + c = max(c, len(row)) + rows = len(v) if c else 0 + cols = c + return rows, cols, smat + + else: + # handle full matrix forms with _handle_creation_inputs + rows, cols, mat = super()._handle_creation_inputs(*args) + for i in range(rows): + for j in range(cols): + value = mat[cols*i + j] + if value != cls.zero: + smat[i, j] = value + + return rows, cols, smat + + @property + def _smat(self): + + sympy_deprecation_warning( + """ + The private _smat attribute of SparseMatrix is deprecated. Use the + .todok() method instead. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-private-matrix-attributes" + ) + + return self.todok() + + def _eval_inverse(self, **kwargs): + return self.inv(method=kwargs.get('method', 'LDL'), + iszerofunc=kwargs.get('iszerofunc', _iszero), + try_block_diag=kwargs.get('try_block_diag', False)) + + def applyfunc(self, f): + """Apply a function to each element of the matrix. + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> m = SparseMatrix(2, 2, lambda i, j: i*2+j) + >>> m + Matrix([ + [0, 1], + [2, 3]]) + >>> m.applyfunc(lambda i: 2*i) + Matrix([ + [0, 2], + [4, 6]]) + + """ + if not callable(f): + raise TypeError("`f` must be callable.") + + # XXX: This only applies the function to the nonzero elements of the + # matrix so is inconsistent with DenseMatrix.applyfunc e.g. + # zeros(2, 2).applyfunc(lambda x: x + 1) + dok = {} + for k, v in self.todok().items(): + fv = f(v) + if fv != 0: + dok[k] = fv + + return self._new(self.rows, self.cols, dok) + + def as_immutable(self): + """Returns an Immutable version of this Matrix.""" + from .immutable import ImmutableSparseMatrix + return ImmutableSparseMatrix(self) + + def as_mutable(self): + """Returns a mutable version of this matrix. + + Examples + ======== + + >>> from sympy import ImmutableMatrix + >>> X = ImmutableMatrix([[1, 2], [3, 4]]) + >>> Y = X.as_mutable() + >>> Y[1, 1] = 5 # Can set values in Y + >>> Y + Matrix([ + [1, 2], + [3, 5]]) + """ + return MutableSparseMatrix(self) + + def col_list(self): + """Returns a column-sorted list of non-zero elements of the matrix. + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> a=SparseMatrix(((1, 2), (3, 4))) + >>> a + Matrix([ + [1, 2], + [3, 4]]) + >>> a.CL + [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)] + + See Also + ======== + + sympy.matrices.sparse.SparseMatrix.row_list + """ + return [tuple(k + (self[k],)) for k in sorted(self.todok().keys(), key=lambda k: list(reversed(k)))] + + def nnz(self): + """Returns the number of non-zero elements in Matrix.""" + return len(self.todok()) + + def row_list(self): + """Returns a row-sorted list of non-zero elements of the matrix. + + Examples + ======== + + >>> from sympy import SparseMatrix + >>> a = SparseMatrix(((1, 2), (3, 4))) + >>> a + Matrix([ + [1, 2], + [3, 4]]) + >>> a.RL + [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)] + + See Also + ======== + + sympy.matrices.sparse.SparseMatrix.col_list + """ + return [tuple(k + (self[k],)) for k in + sorted(self.todok().keys(), key=list)] + + def scalar_multiply(self, scalar): + "Scalar element-wise multiplication" + return scalar * self + + def solve_least_squares(self, rhs, method='LDL'): + """Return the least-square fit to the data. + + By default the cholesky_solve routine is used (method='CH'); other + methods of matrix inversion can be used. To find out which are + available, see the docstring of the .inv() method. + + Examples + ======== + + >>> from sympy import SparseMatrix, Matrix, ones + >>> A = Matrix([1, 2, 3]) + >>> B = Matrix([2, 3, 4]) + >>> S = SparseMatrix(A.row_join(B)) + >>> S + Matrix([ + [1, 2], + [2, 3], + [3, 4]]) + + If each line of S represent coefficients of Ax + By + and x and y are [2, 3] then S*xy is: + + >>> r = S*Matrix([2, 3]); r + Matrix([ + [ 8], + [13], + [18]]) + + But let's add 1 to the middle value and then solve for the + least-squares value of xy: + + >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy + Matrix([ + [ 5/3], + [10/3]]) + + The error is given by S*xy - r: + + >>> S*xy - r + Matrix([ + [1/3], + [1/3], + [1/3]]) + >>> _.norm().n(2) + 0.58 + + If a different xy is used, the norm will be higher: + + >>> xy += ones(2, 1)/10 + >>> (S*xy - r).norm().n(2) + 1.5 + + """ + t = self.T + return (t*self).inv(method=method)*t*rhs + + def solve(self, rhs, method='LDL'): + """Return solution to self*soln = rhs using given inversion method. + + For a list of possible inversion methods, see the .inv() docstring. + """ + if not self.is_square: + if self.rows < self.cols: + raise ValueError('Under-determined system.') + elif self.rows > self.cols: + raise ValueError('For over-determined system, M, having ' + 'more rows than columns, try M.solve_least_squares(rhs).') + else: + return self.inv(method=method).multiply(rhs) + + RL = property(row_list, None, None, "Alternate faster representation") + CL = property(col_list, None, None, "Alternate faster representation") + + def liupc(self): + return _liupc(self) + + def row_structure_symbolic_cholesky(self): + return _row_structure_symbolic_cholesky(self) + + def cholesky(self, hermitian=True): + return _cholesky_sparse(self, hermitian=hermitian) + + def LDLdecomposition(self, hermitian=True): + return _LDLdecomposition_sparse(self, hermitian=hermitian) + + def lower_triangular_solve(self, rhs): + return _lower_triangular_solve_sparse(self, rhs) + + def upper_triangular_solve(self, rhs): + return _upper_triangular_solve_sparse(self, rhs) + + liupc.__doc__ = _liupc.__doc__ + row_structure_symbolic_cholesky.__doc__ = _row_structure_symbolic_cholesky.__doc__ + cholesky.__doc__ = _cholesky_sparse.__doc__ + LDLdecomposition.__doc__ = _LDLdecomposition_sparse.__doc__ + lower_triangular_solve.__doc__ = lower_triangular_solve.__doc__ + upper_triangular_solve.__doc__ = upper_triangular_solve.__doc__ + + +class MutableSparseMatrix(SparseRepMatrix, MutableRepMatrix): + + @classmethod + def _new(cls, *args, **kwargs): + rows, cols, smat = cls._handle_creation_inputs(*args, **kwargs) + + rep = cls._smat_to_DomainMatrix(rows, cols, smat) + + return cls._fromrep(rep) + + +SparseMatrix = MutableSparseMatrix diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/sparsetools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/sparsetools.py new file mode 100644 index 0000000000000000000000000000000000000000..50048f6dc7e5cf160366963d16427987616ddce7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/sparsetools.py @@ -0,0 +1,300 @@ +from sympy.core.containers import Dict +from sympy.core.symbol import Dummy +from sympy.utilities.iterables import is_sequence +from sympy.utilities.misc import as_int, filldedent + +from .sparse import MutableSparseMatrix as SparseMatrix + + +def _doktocsr(dok): + """Converts a sparse matrix to Compressed Sparse Row (CSR) format. + + Parameters + ========== + + A : contains non-zero elements sorted by key (row, column) + JA : JA[i] is the column corresponding to A[i] + IA : IA[i] contains the index in A for the first non-zero element + of row[i]. Thus IA[i+1] - IA[i] gives number of non-zero + elements row[i]. The length of IA is always 1 more than the + number of rows in the matrix. + + Examples + ======== + + >>> from sympy.matrices.sparsetools import _doktocsr + >>> from sympy import SparseMatrix, diag + >>> m = SparseMatrix(diag(1, 2, 3)) + >>> m[2, 0] = -1 + >>> _doktocsr(m) + [[1, 2, -1, 3], [0, 1, 0, 2], [0, 1, 2, 4], [3, 3]] + + """ + row, JA, A = [list(i) for i in zip(*dok.row_list())] + IA = [0]*((row[0] if row else 0) + 1) + for i, r in enumerate(row): + IA.extend([i]*(r - row[i - 1])) # if i = 0 nothing is extended + IA.extend([len(A)]*(dok.rows - len(IA) + 1)) + shape = [dok.rows, dok.cols] + return [A, JA, IA, shape] + + +def _csrtodok(csr): + """Converts a CSR representation to DOK representation. + + Examples + ======== + + >>> from sympy.matrices.sparsetools import _csrtodok + >>> _csrtodok([[5, 8, 3, 6], [0, 1, 2, 1], [0, 0, 2, 3, 4], [4, 3]]) + Matrix([ + [0, 0, 0], + [5, 8, 0], + [0, 0, 3], + [0, 6, 0]]) + + """ + smat = {} + A, JA, IA, shape = csr + for i in range(len(IA) - 1): + indices = slice(IA[i], IA[i + 1]) + for l, m in zip(A[indices], JA[indices]): + smat[i, m] = l + return SparseMatrix(*shape, smat) + + +def banded(*args, **kwargs): + """Returns a SparseMatrix from the given dictionary describing + the diagonals of the matrix. The keys are positive for upper + diagonals and negative for those below the main diagonal. The + values may be: + + * expressions or single-argument functions, + + * lists or tuples of values, + + * matrices + + Unless dimensions are given, the size of the returned matrix will + be large enough to contain the largest non-zero value provided. + + kwargs + ====== + + rows : rows of the resulting matrix; computed if + not given. + + cols : columns of the resulting matrix; computed if + not given. + + Examples + ======== + + >>> from sympy import banded, ones, Matrix + >>> from sympy.abc import x + + If explicit values are given in tuples, + the matrix will autosize to contain all values, otherwise + a single value is filled onto the entire diagonal: + + >>> banded({1: (1, 2, 3), -1: (4, 5, 6), 0: x}) + Matrix([ + [x, 1, 0, 0], + [4, x, 2, 0], + [0, 5, x, 3], + [0, 0, 6, x]]) + + A function accepting a single argument can be used to fill the + diagonal as a function of diagonal index (which starts at 0). + The size (or shape) of the matrix must be given to obtain more + than a 1x1 matrix: + + >>> s = lambda d: (1 + d)**2 + >>> banded(5, {0: s, 2: s, -2: 2}) + Matrix([ + [1, 0, 1, 0, 0], + [0, 4, 0, 4, 0], + [2, 0, 9, 0, 9], + [0, 2, 0, 16, 0], + [0, 0, 2, 0, 25]]) + + The diagonal of matrices placed on a diagonal will coincide + with the indicated diagonal: + + >>> vert = Matrix([1, 2, 3]) + >>> banded({0: vert}, cols=3) + Matrix([ + [1, 0, 0], + [2, 1, 0], + [3, 2, 1], + [0, 3, 2], + [0, 0, 3]]) + + >>> banded(4, {0: ones(2)}) + Matrix([ + [1, 1, 0, 0], + [1, 1, 0, 0], + [0, 0, 1, 1], + [0, 0, 1, 1]]) + + Errors are raised if the designated size will not hold + all values an integral number of times. Here, the rows + are designated as odd (but an even number is required to + hold the off-diagonal 2x2 ones): + + >>> banded({0: 2, 1: ones(2)}, rows=5) + Traceback (most recent call last): + ... + ValueError: + sequence does not fit an integral number of times in the matrix + + And here, an even number of rows is given...but the square + matrix has an even number of columns, too. As we saw + in the previous example, an odd number is required: + + >>> banded(4, {0: 2, 1: ones(2)}) # trying to make 4x4 and cols must be odd + Traceback (most recent call last): + ... + ValueError: + sequence does not fit an integral number of times in the matrix + + A way around having to count rows is to enclosing matrix elements + in a tuple and indicate the desired number of them to the right: + + >>> banded({0: 2, 2: (ones(2),)*3}) + Matrix([ + [2, 0, 1, 1, 0, 0, 0, 0], + [0, 2, 1, 1, 0, 0, 0, 0], + [0, 0, 2, 0, 1, 1, 0, 0], + [0, 0, 0, 2, 1, 1, 0, 0], + [0, 0, 0, 0, 2, 0, 1, 1], + [0, 0, 0, 0, 0, 2, 1, 1]]) + + An error will be raised if more than one value + is written to a given entry. Here, the ones overlap + with the main diagonal if they are placed on the + first diagonal: + + >>> banded({0: (2,)*5, 1: (ones(2),)*3}) + Traceback (most recent call last): + ... + ValueError: collision at (1, 1) + + By placing a 0 at the bottom left of the 2x2 matrix of + ones, the collision is avoided: + + >>> u2 = Matrix([ + ... [1, 1], + ... [0, 1]]) + >>> banded({0: [2]*5, 1: [u2]*3}) + Matrix([ + [2, 1, 1, 0, 0, 0, 0], + [0, 2, 1, 0, 0, 0, 0], + [0, 0, 2, 1, 1, 0, 0], + [0, 0, 0, 2, 1, 0, 0], + [0, 0, 0, 0, 2, 1, 1], + [0, 0, 0, 0, 0, 0, 1]]) + """ + try: + if len(args) not in (1, 2, 3): + raise TypeError + if not isinstance(args[-1], (dict, Dict)): + raise TypeError + if len(args) == 1: + rows = kwargs.get('rows', None) + cols = kwargs.get('cols', None) + if rows is not None: + rows = as_int(rows) + if cols is not None: + cols = as_int(cols) + elif len(args) == 2: + rows = cols = as_int(args[0]) + else: + rows, cols = map(as_int, args[:2]) + # fails with ValueError if any keys are not ints + _ = all(as_int(k) for k in args[-1]) + except (ValueError, TypeError): + raise TypeError(filldedent( + '''unrecognized input to banded: + expecting [[row,] col,] {int: value}''')) + def rc(d): + # return row,col coord of diagonal start + r = -d if d < 0 else 0 + c = 0 if r else d + return r, c + smat = {} + undone = [] + tba = Dummy() + # first handle objects with size + for d, v in args[-1].items(): + r, c = rc(d) + # note: only list and tuple are recognized since this + # will allow other Basic objects like Tuple + # into the matrix if so desired + if isinstance(v, (list, tuple)): + extra = 0 + for i, vi in enumerate(v): + i += extra + if is_sequence(vi): + vi = SparseMatrix(vi) + smat[r + i, c + i] = vi + extra += min(vi.shape) - 1 + else: + smat[r + i, c + i] = vi + elif is_sequence(v): + v = SparseMatrix(v) + rv, cv = v.shape + if rows and cols: + nr, xr = divmod(rows - r, rv) + nc, xc = divmod(cols - c, cv) + x = xr or xc + do = min(nr, nc) + elif rows: + do, x = divmod(rows - r, rv) + elif cols: + do, x = divmod(cols - c, cv) + else: + do = 1 + x = 0 + if x: + raise ValueError(filldedent(''' + sequence does not fit an integral number of times + in the matrix''')) + j = min(v.shape) + for i in range(do): + smat[r, c] = v + r += j + c += j + elif v: + smat[r, c] = tba + undone.append((d, v)) + s = SparseMatrix(None, smat) # to expand matrices + smat = s.todok() + # check for dim errors here + if rows is not None and rows < s.rows: + raise ValueError('Designated rows %s < needed %s' % (rows, s.rows)) + if cols is not None and cols < s.cols: + raise ValueError('Designated cols %s < needed %s' % (cols, s.cols)) + if rows is cols is None: + rows = s.rows + cols = s.cols + elif rows is not None and cols is None: + cols = max(rows, s.cols) + elif cols is not None and rows is None: + rows = max(cols, s.rows) + def update(i, j, v): + # update smat and make sure there are + # no collisions + if v: + if (i, j) in smat and smat[i, j] not in (tba, v): + raise ValueError('collision at %s' % ((i, j),)) + smat[i, j] = v + if undone: + for d, vi in undone: + r, c = rc(d) + v = vi if callable(vi) else lambda _: vi + i = 0 + while r + i < rows and c + i < cols: + update(r + i, c + i, v(i)) + i += 1 + return SparseMatrix(rows, cols, smat) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/subspaces.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/subspaces.py new file mode 100644 index 0000000000000000000000000000000000000000..1ab0b71b4289ebaeb6394059c6a7cd49d3a148a1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/subspaces.py @@ -0,0 +1,174 @@ +from .utilities import _iszero + + +def _columnspace(M, simplify=False): + """Returns a list of vectors (Matrix objects) that span columnspace of ``M`` + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6]) + >>> M + Matrix([ + [ 1, 3, 0], + [-2, -6, 0], + [ 3, 9, 6]]) + >>> M.columnspace() + [Matrix([ + [ 1], + [-2], + [ 3]]), Matrix([ + [0], + [0], + [6]])] + + See Also + ======== + + nullspace + rowspace + """ + + reduced, pivots = M.echelon_form(simplify=simplify, with_pivots=True) + + return [M.col(i) for i in pivots] + + +def _nullspace(M, simplify=False, iszerofunc=_iszero): + """Returns list of vectors (Matrix objects) that span nullspace of ``M`` + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6]) + >>> M + Matrix([ + [ 1, 3, 0], + [-2, -6, 0], + [ 3, 9, 6]]) + >>> M.nullspace() + [Matrix([ + [-3], + [ 1], + [ 0]])] + + See Also + ======== + + columnspace + rowspace + """ + + reduced, pivots = M.rref(iszerofunc=iszerofunc, simplify=simplify) + + free_vars = [i for i in range(M.cols) if i not in pivots] + basis = [] + + for free_var in free_vars: + # for each free variable, we will set it to 1 and all others + # to 0. Then, we will use back substitution to solve the system + vec = [M.zero] * M.cols + vec[free_var] = M.one + + for piv_row, piv_col in enumerate(pivots): + vec[piv_col] -= reduced[piv_row, free_var] + + basis.append(vec) + + return [M._new(M.cols, 1, b) for b in basis] + + +def _rowspace(M, simplify=False): + """Returns a list of vectors that span the row space of ``M``. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6]) + >>> M + Matrix([ + [ 1, 3, 0], + [-2, -6, 0], + [ 3, 9, 6]]) + >>> M.rowspace() + [Matrix([[1, 3, 0]]), Matrix([[0, 0, 6]])] + """ + + reduced, pivots = M.echelon_form(simplify=simplify, with_pivots=True) + + return [reduced.row(i) for i in range(len(pivots))] + + +def _orthogonalize(cls, *vecs, normalize=False, rankcheck=False): + """Apply the Gram-Schmidt orthogonalization procedure + to vectors supplied in ``vecs``. + + Parameters + ========== + + vecs + vectors to be made orthogonal + + normalize : bool + If ``True``, return an orthonormal basis. + + rankcheck : bool + If ``True``, the computation does not stop when encountering + linearly dependent vectors. + + If ``False``, it will raise ``ValueError`` when any zero + or linearly dependent vectors are found. + + Returns + ======= + + list + List of orthogonal (or orthonormal) basis vectors. + + Examples + ======== + + >>> from sympy import I, Matrix + >>> v = [Matrix([1, I]), Matrix([1, -I])] + >>> Matrix.orthogonalize(*v) + [Matrix([ + [1], + [I]]), Matrix([ + [ 1], + [-I]])] + + See Also + ======== + + MatrixBase.QRdecomposition + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process + """ + from .decompositions import _QRdecomposition_optional + + if not vecs: + return [] + + all_row_vecs = (vecs[0].rows == 1) + + vecs = [x.vec() for x in vecs] + M = cls.hstack(*vecs) + Q, R = _QRdecomposition_optional(M, normalize=normalize) + + if rankcheck and Q.cols < len(vecs): + raise ValueError("GramSchmidt: vector set not linearly independent") + + ret = [] + for i in range(Q.cols): + if all_row_vecs: + col = cls(Q[:, i].T) + else: + col = cls(Q[:, i]) + ret.append(col) + return ret diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/utilities.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..b8a680b47e63615e210e561639a192ba47c642d3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/matrices/utilities.py @@ -0,0 +1,72 @@ +from contextlib import contextmanager +from threading import local + +from sympy.core.function import expand_mul + + +class DotProdSimpState(local): + def __init__(self): + self.state = None + +_dotprodsimp_state = DotProdSimpState() + +@contextmanager +def dotprodsimp(x): + old = _dotprodsimp_state.state + + try: + _dotprodsimp_state.state = x + yield + finally: + _dotprodsimp_state.state = old + + +def _dotprodsimp(expr, withsimp=False): + """Wrapper for simplify.dotprodsimp to avoid circular imports.""" + from sympy.simplify.simplify import dotprodsimp as dps + return dps(expr, withsimp=withsimp) + + +def _get_intermediate_simp(deffunc=lambda x: x, offfunc=lambda x: x, + onfunc=_dotprodsimp, dotprodsimp=None): + """Support function for controlling intermediate simplification. Returns a + simplification function according to the global setting of dotprodsimp + operation. + + ``deffunc`` - Function to be used by default. + ``offfunc`` - Function to be used if dotprodsimp has been turned off. + ``onfunc`` - Function to be used if dotprodsimp has been turned on. + ``dotprodsimp`` - True, False or None. Will be overridden by global + _dotprodsimp_state.state if that is not None. + """ + + if dotprodsimp is False or _dotprodsimp_state.state is False: + return offfunc + if dotprodsimp is True or _dotprodsimp_state.state is True: + return onfunc + + return deffunc # None, None + + +def _get_intermediate_simp_bool(default=False, dotprodsimp=None): + """Same as ``_get_intermediate_simp`` but returns bools instead of functions + by default.""" + + return _get_intermediate_simp(default, False, True, dotprodsimp) + + +def _iszero(x): + """Returns True if x is zero.""" + return getattr(x, 'is_zero', None) + + +def _is_zero_after_expand_mul(x): + """Tests by expand_mul only, suitable for polynomials and rational + functions.""" + return expand_mul(x) == 0 + + +def _simplify(expr): + """ Wrapper to avoid circular imports. """ + from sympy.simplify.simplify import simplify + return simplify(expr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5447651645e3e2e92df3002822e87a773ade0df8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/__init__.py @@ -0,0 +1,11 @@ +from .core import dispatch +from .dispatcher import (Dispatcher, halt_ordering, restart_ordering, + MDNotImplementedError) + +__version__ = '0.4.9' + +__all__ = [ + 'dispatch', + + 'Dispatcher', 'halt_ordering', 'restart_ordering', 'MDNotImplementedError', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/conflict.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/conflict.py new file mode 100644 index 0000000000000000000000000000000000000000..98c6742c9c03860233ef0004b241ea3944ac6d4d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/conflict.py @@ -0,0 +1,68 @@ +from .utils import _toposort, groupby + +class AmbiguityWarning(Warning): + pass + + +def supercedes(a, b): + """ A is consistent and strictly more specific than B """ + return len(a) == len(b) and all(map(issubclass, a, b)) + + +def consistent(a, b): + """ It is possible for an argument list to satisfy both A and B """ + return (len(a) == len(b) and + all(issubclass(aa, bb) or issubclass(bb, aa) + for aa, bb in zip(a, b))) + + +def ambiguous(a, b): + """ A is consistent with B but neither is strictly more specific """ + return consistent(a, b) and not (supercedes(a, b) or supercedes(b, a)) + + +def ambiguities(signatures): + """ All signature pairs such that A is ambiguous with B """ + signatures = list(map(tuple, signatures)) + return {(a, b) for a in signatures for b in signatures + if hash(a) < hash(b) + and ambiguous(a, b) + and not any(supercedes(c, a) and supercedes(c, b) + for c in signatures)} + + +def super_signature(signatures): + """ A signature that would break ambiguities """ + n = len(signatures[0]) + assert all(len(s) == n for s in signatures) + + return [max([type.mro(sig[i]) for sig in signatures], key=len)[0] + for i in range(n)] + + +def edge(a, b, tie_breaker=hash): + """ A should be checked before B + + Tie broken by tie_breaker, defaults to ``hash`` + """ + if supercedes(a, b): + if supercedes(b, a): + return tie_breaker(a) > tie_breaker(b) + else: + return True + return False + + +def ordering(signatures): + """ A sane ordering of signatures to check, first to last + + Topoological sort of edges as given by ``edge`` and ``supercedes`` + """ + signatures = list(map(tuple, signatures)) + edges = [(a, b) for a in signatures for b in signatures if edge(a, b)] + edges = groupby(lambda x: x[0], edges) + for s in signatures: + if s not in edges: + edges[s] = [] + edges = {k: [b for a, b in v] for k, v in edges.items()} + return _toposort(edges) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/core.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/core.py new file mode 100644 index 0000000000000000000000000000000000000000..2856ff728c4eb97c5a59fffabddb4bf3c8b4baf2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/core.py @@ -0,0 +1,83 @@ +from __future__ import annotations +from typing import Any + +import inspect + +from .dispatcher import Dispatcher, MethodDispatcher, ambiguity_warn + +# XXX: This parameter to dispatch isn't documented and isn't used anywhere in +# sympy. Maybe it should just be removed. +global_namespace: dict[str, Any] = {} + + +def dispatch(*types, namespace=global_namespace, on_ambiguity=ambiguity_warn): + """ Dispatch function on the types of the inputs + + Supports dispatch on all non-keyword arguments. + + Collects implementations based on the function name. Ignores namespaces. + + If ambiguous type signatures occur a warning is raised when the function is + defined suggesting the additional method to break the ambiguity. + + Examples + -------- + + >>> from sympy.multipledispatch import dispatch + >>> @dispatch(int) + ... def f(x): + ... return x + 1 + + >>> @dispatch(float) + ... def f(x): # noqa: F811 + ... return x - 1 + + >>> f(3) + 4 + >>> f(3.0) + 2.0 + + Specify an isolated namespace with the namespace keyword argument + + >>> my_namespace = dict() + >>> @dispatch(int, namespace=my_namespace) + ... def foo(x): + ... return x + 1 + + Dispatch on instance methods within classes + + >>> class MyClass(object): + ... @dispatch(list) + ... def __init__(self, data): + ... self.data = data + ... @dispatch(int) + ... def __init__(self, datum): # noqa: F811 + ... self.data = [datum] + """ + types = tuple(types) + + def _(func): + name = func.__name__ + + if ismethod(func): + dispatcher = inspect.currentframe().f_back.f_locals.get( + name, + MethodDispatcher(name)) + else: + if name not in namespace: + namespace[name] = Dispatcher(name) + dispatcher = namespace[name] + + dispatcher.add(types, func, on_ambiguity=on_ambiguity) + return dispatcher + return _ + + +def ismethod(func): + """ Is func a method? + + Note that this has to work as the method is defined but before the class is + defined. At this stage methods look like functions. + """ + signature = inspect.signature(func) + return signature.parameters.get('self', None) is not None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/dispatcher.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/dispatcher.py new file mode 100644 index 0000000000000000000000000000000000000000..89471d678e1c330138a91ec6a41a324d29a037d7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/dispatcher.py @@ -0,0 +1,413 @@ +from __future__ import annotations + +from warnings import warn +import inspect +from .conflict import ordering, ambiguities, super_signature, AmbiguityWarning +from .utils import expand_tuples +import itertools as itl + + +class MDNotImplementedError(NotImplementedError): + """ A NotImplementedError for multiple dispatch """ + + +### Functions for on_ambiguity + +def ambiguity_warn(dispatcher, ambiguities): + """ Raise warning when ambiguity is detected + + Parameters + ---------- + dispatcher : Dispatcher + The dispatcher on which the ambiguity was detected + ambiguities : set + Set of type signature pairs that are ambiguous within this dispatcher + + See Also: + Dispatcher.add + warning_text + """ + warn(warning_text(dispatcher.name, ambiguities), AmbiguityWarning) + + +class RaiseNotImplementedError: + """Raise ``NotImplementedError`` when called.""" + + def __init__(self, dispatcher): + self.dispatcher = dispatcher + + def __call__(self, *args, **kwargs): + types = tuple(type(a) for a in args) + raise NotImplementedError( + "Ambiguous signature for %s: <%s>" % ( + self.dispatcher.name, str_signature(types) + )) + +def ambiguity_register_error_ignore_dup(dispatcher, ambiguities): + """ + If super signature for ambiguous types is duplicate types, ignore it. + Else, register instance of ``RaiseNotImplementedError`` for ambiguous types. + + Parameters + ---------- + dispatcher : Dispatcher + The dispatcher on which the ambiguity was detected + ambiguities : set + Set of type signature pairs that are ambiguous within this dispatcher + + See Also: + Dispatcher.add + ambiguity_warn + """ + for amb in ambiguities: + signature = tuple(super_signature(amb)) + if len(set(signature)) == 1: + continue + dispatcher.add( + signature, RaiseNotImplementedError(dispatcher), + on_ambiguity=ambiguity_register_error_ignore_dup + ) + +### + + +_unresolved_dispatchers: set[Dispatcher] = set() +_resolve = [True] + + +def halt_ordering(): + _resolve[0] = False + + +def restart_ordering(on_ambiguity=ambiguity_warn): + _resolve[0] = True + while _unresolved_dispatchers: + dispatcher = _unresolved_dispatchers.pop() + dispatcher.reorder(on_ambiguity=on_ambiguity) + + +class Dispatcher: + """ Dispatch methods based on type signature + + Use ``dispatch`` to add implementations + + Examples + -------- + + >>> from sympy.multipledispatch import dispatch + >>> @dispatch(int) + ... def f(x): + ... return x + 1 + + >>> @dispatch(float) + ... def f(x): # noqa: F811 + ... return x - 1 + + >>> f(3) + 4 + >>> f(3.0) + 2.0 + """ + __slots__ = '__name__', 'name', 'funcs', 'ordering', '_cache', 'doc' + + def __init__(self, name, doc=None): + self.name = self.__name__ = name + self.funcs = {} + self._cache = {} + self.ordering = [] + self.doc = doc + + def register(self, *types, **kwargs): + """ Register dispatcher with new implementation + + >>> from sympy.multipledispatch.dispatcher import Dispatcher + >>> f = Dispatcher('f') + >>> @f.register(int) + ... def inc(x): + ... return x + 1 + + >>> @f.register(float) + ... def dec(x): + ... return x - 1 + + >>> @f.register(list) + ... @f.register(tuple) + ... def reverse(x): + ... return x[::-1] + + >>> f(1) + 2 + + >>> f(1.0) + 0.0 + + >>> f([1, 2, 3]) + [3, 2, 1] + """ + def _(func): + self.add(types, func, **kwargs) + return func + return _ + + @classmethod + def get_func_params(cls, func): + if hasattr(inspect, "signature"): + sig = inspect.signature(func) + return sig.parameters.values() + + @classmethod + def get_func_annotations(cls, func): + """ Get annotations of function positional parameters + """ + params = cls.get_func_params(func) + if params: + Parameter = inspect.Parameter + + params = (param for param in params + if param.kind in + (Parameter.POSITIONAL_ONLY, + Parameter.POSITIONAL_OR_KEYWORD)) + + annotations = tuple( + param.annotation + for param in params) + + if not any(ann is Parameter.empty for ann in annotations): + return annotations + + def add(self, signature, func, on_ambiguity=ambiguity_warn): + """ Add new types/method pair to dispatcher + + >>> from sympy.multipledispatch import Dispatcher + >>> D = Dispatcher('add') + >>> D.add((int, int), lambda x, y: x + y) + >>> D.add((float, float), lambda x, y: x + y) + + >>> D(1, 2) + 3 + >>> D(1, 2.0) + Traceback (most recent call last): + ... + NotImplementedError: Could not find signature for add: + + When ``add`` detects a warning it calls the ``on_ambiguity`` callback + with a dispatcher/itself, and a set of ambiguous type signature pairs + as inputs. See ``ambiguity_warn`` for an example. + """ + # Handle annotations + if not signature: + annotations = self.get_func_annotations(func) + if annotations: + signature = annotations + + # Handle union types + if any(isinstance(typ, tuple) for typ in signature): + for typs in expand_tuples(signature): + self.add(typs, func, on_ambiguity) + return + + for typ in signature: + if not isinstance(typ, type): + str_sig = ', '.join(c.__name__ if isinstance(c, type) + else str(c) for c in signature) + raise TypeError("Tried to dispatch on non-type: %s\n" + "In signature: <%s>\n" + "In function: %s" % + (typ, str_sig, self.name)) + + self.funcs[signature] = func + self.reorder(on_ambiguity=on_ambiguity) + self._cache.clear() + + def reorder(self, on_ambiguity=ambiguity_warn): + if _resolve[0]: + self.ordering = ordering(self.funcs) + amb = ambiguities(self.funcs) + if amb: + on_ambiguity(self, amb) + else: + _unresolved_dispatchers.add(self) + + def __call__(self, *args, **kwargs): + types = tuple([type(arg) for arg in args]) + try: + func = self._cache[types] + except KeyError: + func = self.dispatch(*types) + if not func: + raise NotImplementedError( + 'Could not find signature for %s: <%s>' % + (self.name, str_signature(types))) + self._cache[types] = func + try: + return func(*args, **kwargs) + + except MDNotImplementedError: + funcs = self.dispatch_iter(*types) + next(funcs) # burn first + for func in funcs: + try: + return func(*args, **kwargs) + except MDNotImplementedError: + pass + raise NotImplementedError("Matching functions for " + "%s: <%s> found, but none completed successfully" + % (self.name, str_signature(types))) + + def __str__(self): + return "" % self.name + __repr__ = __str__ + + def dispatch(self, *types): + """ Deterimine appropriate implementation for this type signature + + This method is internal. Users should call this object as a function. + Implementation resolution occurs within the ``__call__`` method. + + >>> from sympy.multipledispatch import dispatch + >>> @dispatch(int) + ... def inc(x): + ... return x + 1 + + >>> implementation = inc.dispatch(int) + >>> implementation(3) + 4 + + >>> print(inc.dispatch(float)) + None + + See Also: + ``sympy.multipledispatch.conflict`` - module to determine resolution order + """ + + if types in self.funcs: + return self.funcs[types] + + try: + return next(self.dispatch_iter(*types)) + except StopIteration: + return None + + def dispatch_iter(self, *types): + n = len(types) + for signature in self.ordering: + if len(signature) == n and all(map(issubclass, types, signature)): + result = self.funcs[signature] + yield result + + def resolve(self, types): + """ Deterimine appropriate implementation for this type signature + + .. deprecated:: 0.4.4 + Use ``dispatch(*types)`` instead + """ + warn("resolve() is deprecated, use dispatch(*types)", + DeprecationWarning) + + return self.dispatch(*types) + + def __getstate__(self): + return {'name': self.name, + 'funcs': self.funcs} + + def __setstate__(self, d): + self.name = d['name'] + self.funcs = d['funcs'] + self.ordering = ordering(self.funcs) + self._cache = {} + + @property + def __doc__(self): + docs = ["Multiply dispatched method: %s" % self.name] + + if self.doc: + docs.append(self.doc) + + other = [] + for sig in self.ordering[::-1]: + func = self.funcs[sig] + if func.__doc__: + s = 'Inputs: <%s>\n' % str_signature(sig) + s += '-' * len(s) + '\n' + s += func.__doc__.strip() + docs.append(s) + else: + other.append(str_signature(sig)) + + if other: + docs.append('Other signatures:\n ' + '\n '.join(other)) + + return '\n\n'.join(docs) + + def _help(self, *args): + return self.dispatch(*map(type, args)).__doc__ + + def help(self, *args, **kwargs): + """ Print docstring for the function corresponding to inputs """ + print(self._help(*args)) + + def _source(self, *args): + func = self.dispatch(*map(type, args)) + if not func: + raise TypeError("No function found") + return source(func) + + def source(self, *args, **kwargs): + """ Print source code for the function corresponding to inputs """ + print(self._source(*args)) + + +def source(func): + s = 'File: %s\n\n' % inspect.getsourcefile(func) + s = s + inspect.getsource(func) + return s + + +class MethodDispatcher(Dispatcher): + """ Dispatch methods based on type signature + + See Also: + Dispatcher + """ + + @classmethod + def get_func_params(cls, func): + if hasattr(inspect, "signature"): + sig = inspect.signature(func) + return itl.islice(sig.parameters.values(), 1, None) + + def __get__(self, instance, owner): + self.obj = instance + self.cls = owner + return self + + def __call__(self, *args, **kwargs): + types = tuple([type(arg) for arg in args]) + func = self.dispatch(*types) + if not func: + raise NotImplementedError('Could not find signature for %s: <%s>' % + (self.name, str_signature(types))) + return func(self.obj, *args, **kwargs) + + +def str_signature(sig): + """ String representation of type signature + + >>> from sympy.multipledispatch.dispatcher import str_signature + >>> str_signature((int, float)) + 'int, float' + """ + return ', '.join(cls.__name__ for cls in sig) + + +def warning_text(name, amb): + """ The text for ambiguity warnings """ + text = "\nAmbiguities exist in dispatched function %s\n\n" % (name) + text += "The following signatures may result in ambiguous behavior:\n" + for pair in amb: + text += "\t" + \ + ', '.join('[' + str_signature(s) + ']' for s in pair) + "\n" + text += "\n\nConsider making the following additions:\n\n" + text += '\n\n'.join(['@dispatch(' + str_signature(super_signature(s)) + + ')\ndef %s(...)' % name for s in amb]) + return text diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/utils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..11f563772385124c2fc0d285f7aa6e0747b8b412 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/multipledispatch/utils.py @@ -0,0 +1,105 @@ +from collections import OrderedDict + + +def expand_tuples(L): + """ + >>> from sympy.multipledispatch.utils import expand_tuples + >>> expand_tuples([1, (2, 3)]) + [(1, 2), (1, 3)] + + >>> expand_tuples([1, 2]) + [(1, 2)] + """ + if not L: + return [()] + elif not isinstance(L[0], tuple): + rest = expand_tuples(L[1:]) + return [(L[0],) + t for t in rest] + else: + rest = expand_tuples(L[1:]) + return [(item,) + t for t in rest for item in L[0]] + + +# Taken from theano/theano/gof/sched.py +# Avoids licensing issues because this was written by Matthew Rocklin +def _toposort(edges): + """ Topological sort algorithm by Kahn [1] - O(nodes + vertices) + + inputs: + edges - a dict of the form {a: {b, c}} where b and c depend on a + outputs: + L - an ordered list of nodes that satisfy the dependencies of edges + + >>> from sympy.multipledispatch.utils import _toposort + >>> _toposort({1: (2, 3), 2: (3, )}) + [1, 2, 3] + + Closely follows the wikipedia page [2] + + [1] Kahn, Arthur B. (1962), "Topological sorting of large networks", + Communications of the ACM + [2] https://en.wikipedia.org/wiki/Toposort#Algorithms + """ + incoming_edges = reverse_dict(edges) + incoming_edges = {k: set(val) for k, val in incoming_edges.items()} + S = OrderedDict.fromkeys(v for v in edges if v not in incoming_edges) + L = [] + + while S: + n, _ = S.popitem() + L.append(n) + for m in edges.get(n, ()): + assert n in incoming_edges[m] + incoming_edges[m].remove(n) + if not incoming_edges[m]: + S[m] = None + if any(incoming_edges.get(v, None) for v in edges): + raise ValueError("Input has cycles") + return L + + +def reverse_dict(d): + """Reverses direction of dependence dict + + >>> d = {'a': (1, 2), 'b': (2, 3), 'c':()} + >>> reverse_dict(d) # doctest: +SKIP + {1: ('a',), 2: ('a', 'b'), 3: ('b',)} + + :note: dict order are not deterministic. As we iterate on the + input dict, it make the output of this function depend on the + dict order. So this function output order should be considered + as undeterministic. + + """ + result = {} + for key in d: + for val in d[key]: + result[val] = result.get(val, ()) + (key, ) + return result + + +# Taken from toolz +# Avoids licensing issues because this version was authored by Matthew Rocklin +def groupby(func, seq): + """ Group a collection by a key function + + >>> from sympy.multipledispatch.utils import groupby + >>> names = ['Alice', 'Bob', 'Charlie', 'Dan', 'Edith', 'Frank'] + >>> groupby(len, names) # doctest: +SKIP + {3: ['Bob', 'Dan'], 5: ['Alice', 'Edith', 'Frank'], 7: ['Charlie']} + + >>> iseven = lambda x: x % 2 == 0 + >>> groupby(iseven, [1, 2, 3, 4, 5, 6, 7, 8]) # doctest: +SKIP + {False: [1, 3, 5, 7], True: [2, 4, 6, 8]} + + See Also: + ``countby`` + """ + + d = {} + for item in seq: + key = func(item) + if key not in d: + d[key] = [] + d[key].append(item) + return d diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..19576c8935da455743d27f0a263caecca94f59f8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/__init__.py @@ -0,0 +1,67 @@ +""" +Number theory module (primes, etc) +""" + +from .generate import nextprime, prevprime, prime, primepi, primerange, \ + randprime, Sieve, sieve, primorial, cycle_length, composite, compositepi +from .primetest import isprime, is_gaussian_prime, is_mersenne_prime +from .factor_ import divisors, proper_divisors, factorint, multiplicity, \ + multiplicity_in_factorial, perfect_power, factor_cache, pollard_pm1, \ + pollard_rho, primefactors, totient, \ + divisor_count, proper_divisor_count, divisor_sigma, factorrat, \ + reduced_totient, primenu, primeomega, mersenne_prime_exponent, \ + is_perfect, is_abundant, is_deficient, is_amicable, is_carmichael, \ + abundance, dra, drm + +from .partitions_ import npartitions +from .residue_ntheory import is_primitive_root, is_quad_residue, \ + legendre_symbol, jacobi_symbol, n_order, sqrt_mod, quadratic_residues, \ + primitive_root, nthroot_mod, is_nthpow_residue, sqrt_mod_iter, mobius, \ + discrete_log, quadratic_congruence, polynomial_congruence +from .multinomial import binomial_coefficients, binomial_coefficients_list, \ + multinomial_coefficients +from .continued_fraction import continued_fraction_periodic, \ + continued_fraction_iterator, continued_fraction_reduce, \ + continued_fraction_convergents, continued_fraction +from .digits import count_digits, digits, is_palindromic +from .egyptian_fraction import egyptian_fraction +from .ecm import ecm +from .qs import qs, qs_factor +__all__ = [ + 'nextprime', 'prevprime', 'prime', 'primepi', 'primerange', 'randprime', + 'Sieve', 'sieve', 'primorial', 'cycle_length', 'composite', 'compositepi', + + 'isprime', 'is_gaussian_prime', 'is_mersenne_prime', + + + 'divisors', 'proper_divisors', 'factorint', 'multiplicity', 'perfect_power', + 'pollard_pm1', 'factor_cache', 'pollard_rho', 'primefactors', 'totient', + 'divisor_count', 'proper_divisor_count', 'divisor_sigma', 'factorrat', + 'reduced_totient', 'primenu', 'primeomega', 'mersenne_prime_exponent', + 'is_perfect', 'is_abundant', 'is_deficient', 'is_amicable', + 'is_carmichael', 'abundance', 'dra', 'drm', 'multiplicity_in_factorial', + + 'npartitions', + + 'is_primitive_root', 'is_quad_residue', 'legendre_symbol', + 'jacobi_symbol', 'n_order', 'sqrt_mod', 'quadratic_residues', + 'primitive_root', 'nthroot_mod', 'is_nthpow_residue', 'sqrt_mod_iter', + 'mobius', 'discrete_log', 'quadratic_congruence', 'polynomial_congruence', + + 'binomial_coefficients', 'binomial_coefficients_list', + 'multinomial_coefficients', + + 'continued_fraction_periodic', 'continued_fraction_iterator', + 'continued_fraction_reduce', 'continued_fraction_convergents', + 'continued_fraction', + + 'digits', + 'count_digits', + 'is_palindromic', + + 'egyptian_fraction', + + 'ecm', + + 'qs', 'qs_factor', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/bbp_pi.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/bbp_pi.py new file mode 100644 index 0000000000000000000000000000000000000000..e2ff4b755d74d4e075ac7195f991c8182d175693 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/bbp_pi.py @@ -0,0 +1,190 @@ +''' +This implementation is a heavily modified fixed point implementation of +BBP_formula for calculating the nth position of pi. The original hosted +at: https://web.archive.org/web/20151116045029/http://en.literateprograms.org/Pi_with_the_BBP_formula_(Python) + +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub-license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Modifications: + +1.Once the nth digit and desired number of digits is selected, the +number of digits of working precision is calculated to ensure that +the hexadecimal digits returned are accurate. This is calculated as + + int(math.log(start + prec)/math.log(16) + prec + 3) + --------------------------------------- -------- + / / + number of hex digits additional digits + +This was checked by the following code which completed without +errors (and dig are the digits included in the test_bbp.py file): + + for i in range(0,1000): + for j in range(1,1000): + a, b = pi_hex_digits(i, j), dig[i:i+j] + if a != b: + print('%s\n%s'%(a,b)) + +Deceasing the additional digits by 1 generated errors, so '3' is +the smallest additional precision needed to calculate the above +loop without errors. The following trailing 10 digits were also +checked to be accurate (and the times were slightly faster with +some of the constant modifications that were made): + + >> from time import time + >> t=time();pi_hex_digits(10**2-10 + 1, 10), time()-t + ('e90c6cc0ac', 0.0) + >> t=time();pi_hex_digits(10**4-10 + 1, 10), time()-t + ('26aab49ec6', 0.17100000381469727) + >> t=time();pi_hex_digits(10**5-10 + 1, 10), time()-t + ('a22673c1a5', 4.7109999656677246) + >> t=time();pi_hex_digits(10**6-10 + 1, 10), time()-t + ('9ffd342362', 59.985999822616577) + >> t=time();pi_hex_digits(10**7-10 + 1, 10), time()-t + ('c1a42e06a1', 689.51800012588501) + +2. The while loop to evaluate whether the series has converged quits +when the addition amount `dt` has dropped to zero. + +3. the formatting string to convert the decimal to hexadecimal is +calculated for the given precision. + +4. pi_hex_digits(n) changed to have coefficient to the formula in an +array (perhaps just a matter of preference). + +''' + +from sympy.utilities.misc import as_int + + +def _series(j, n, prec=14): + + # Left sum from the bbp algorithm + s = 0 + D = _dn(n, prec) + D4 = 4 * D + d = j + for k in range(n + 1): + s += (pow(16, n - k, d) << D4) // d + d += 8 + + # Right sum iterates to infinity for full precision, but we + # stop at the point where one iteration is beyond the precision + # specified. + + t = 0 + k = n + 1 + e = D4 - 4 # 4*(D + n - k) + d = 8 * k + j + while True: + dt = (1 << e) // d + if not dt: + break + t += dt + # k += 1 + e -= 4 + d += 8 + total = s + t + + return total + + +def pi_hex_digits(n, prec=14): + """Returns a string containing ``prec`` (default 14) digits + starting at the nth digit of pi in hex. Counting of digits + starts at 0 and the decimal is not counted, so for n = 0 the + returned value starts with 3; n = 1 corresponds to the first + digit past the decimal point (which in hex is 2). + + Parameters + ========== + + n : non-negative integer + prec : non-negative integer. default = 14 + + Returns + ======= + + str : Returns a string containing ``prec`` digits + starting at the nth digit of pi in hex. + If ``prec`` = 0, returns empty string. + + Raises + ====== + + ValueError + If ``n`` < 0 or ``prec`` < 0. + Or ``n`` or ``prec`` is not an integer. + + Examples + ======== + + >>> from sympy.ntheory.bbp_pi import pi_hex_digits + >>> pi_hex_digits(0) + '3243f6a8885a30' + >>> pi_hex_digits(0, 3) + '324' + + These are consistent with the following results + + >>> import math + >>> hex(int(math.pi * 2**((14-1)*4))) + '0x3243f6a8885a30' + >>> hex(int(math.pi * 2**((3-1)*4))) + '0x324' + + References + ========== + + .. [1] http://www.numberworld.org/digits/Pi/ + """ + n, prec = as_int(n), as_int(prec) + if n < 0: + raise ValueError('n cannot be negative') + if prec < 0: + raise ValueError('prec cannot be negative') + if prec == 0: + return '' + + # main of implementation arrays holding formulae coefficients + n -= 1 + a = [4, 2, 1, 1] + j = [1, 4, 5, 6] + + #formulae + D = _dn(n, prec) + x = + (a[0]*_series(j[0], n, prec) + - a[1]*_series(j[1], n, prec) + - a[2]*_series(j[2], n, prec) + - a[3]*_series(j[3], n, prec)) & (16**D - 1) + + s = ("%0" + "%ix" % prec) % (x // 16**(D - prec)) + return s + + +def _dn(n, prec): + # controller for n dependence on precision + # n = starting digit index + # prec = the number of total digits to compute + n += 1 # because we subtract 1 for _series + + # assert int(math.log(n + prec)/math.log(16)) ==\ + # ((n + prec).bit_length() - 1) // 4 + return ((n + prec).bit_length() - 1) // 4 + prec + 3 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/continued_fraction.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/continued_fraction.py new file mode 100644 index 0000000000000000000000000000000000000000..62f8e2d729ada3414a87d6f0583e06bee2a2b220 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/continued_fraction.py @@ -0,0 +1,369 @@ +from __future__ import annotations +import itertools +from sympy.core.exprtools import factor_terms +from sympy.core.numbers import Integer, Rational +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.core.sympify import _sympify +from sympy.utilities.misc import as_int + + +def continued_fraction(a) -> list: + """Return the continued fraction representation of a Rational or + quadratic irrational. + + Examples + ======== + + >>> from sympy.ntheory.continued_fraction import continued_fraction + >>> from sympy import sqrt + >>> continued_fraction((1 + 2*sqrt(3))/5) + [0, 1, [8, 3, 34, 3]] + + See Also + ======== + continued_fraction_periodic, continued_fraction_reduce, continued_fraction_convergents + """ + e = _sympify(a) + if all(i.is_Rational for i in e.atoms()): + if e.is_Integer: + return continued_fraction_periodic(e, 1, 0) + elif e.is_Rational: + return continued_fraction_periodic(e.p, e.q, 0) + elif e.is_Pow and e.exp is S.Half and e.base.is_Integer: + return continued_fraction_periodic(0, 1, e.base) + elif e.is_Mul and len(e.args) == 2 and ( + e.args[0].is_Rational and + e.args[1].is_Pow and + e.args[1].base.is_Integer and + e.args[1].exp is S.Half): + a, b = e.args + return continued_fraction_periodic(0, a.q, b.base, a.p) + else: + # this should not have to work very hard- no + # simplification, cancel, etc... which should be + # done by the user. e.g. This is a fancy 1 but + # the user should simplify it first: + # sqrt(2)*(1 + sqrt(2))/(sqrt(2) + 2) + p, d = e.expand().as_numer_denom() + if d.is_Integer: + if p.is_Rational: + return continued_fraction_periodic(p, d) + # look for a + b*c + # with c = sqrt(s) + if p.is_Add and len(p.args) == 2: + a, bc = p.args + else: + a = S.Zero + bc = p + if a.is_Integer: + b = S.NaN + if bc.is_Mul and len(bc.args) == 2: + b, c = bc.args + elif bc.is_Pow: + b = Integer(1) + c = bc + if b.is_Integer and ( + c.is_Pow and c.exp is S.Half and + c.base.is_Integer): + # (a + b*sqrt(c))/d + c = c.base + return continued_fraction_periodic(a, d, c, b) + raise ValueError( + 'expecting a rational or quadratic irrational, not %s' % e) + + +def continued_fraction_periodic(p, q, d=0, s=1) -> list: + r""" + Find the periodic continued fraction expansion of a quadratic irrational. + + Compute the continued fraction expansion of a rational or a + quadratic irrational number, i.e. `\frac{p + s\sqrt{d}}{q}`, where + `p`, `q \ne 0` and `d \ge 0` are integers. + + Returns the continued fraction representation (canonical form) as + a list of integers, optionally ending (for quadratic irrationals) + with list of integers representing the repeating digits. + + Parameters + ========== + + p : int + the rational part of the number's numerator + q : int + the denominator of the number + d : int, optional + the irrational part (discriminator) of the number's numerator + s : int, optional + the coefficient of the irrational part + + Examples + ======== + + >>> from sympy.ntheory.continued_fraction import continued_fraction_periodic + >>> continued_fraction_periodic(3, 2, 7) + [2, [1, 4, 1, 1]] + + Golden ratio has the simplest continued fraction expansion: + + >>> continued_fraction_periodic(1, 2, 5) + [[1]] + + If the discriminator is zero or a perfect square then the number will be a + rational number: + + >>> continued_fraction_periodic(4, 3, 0) + [1, 3] + >>> continued_fraction_periodic(4, 3, 49) + [3, 1, 2] + + See Also + ======== + + continued_fraction_iterator, continued_fraction_reduce + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Periodic_continued_fraction + .. [2] K. Rosen. Elementary Number theory and its applications. + Addison-Wesley, 3 Sub edition, pages 379-381, January 1992. + + """ + from sympy.functions import sqrt, floor + + p, q, d, s = list(map(as_int, [p, q, d, s])) + + if d < 0: + raise ValueError("expected non-negative for `d` but got %s" % d) + + if q == 0: + raise ValueError("The denominator cannot be 0.") + + if not s: + d = 0 + + # check for rational case + sd = sqrt(d) + if sd.is_Integer: + return list(continued_fraction_iterator(Rational(p + s*sd, q))) + + # irrational case with sd != Integer + if q < 0: + p, q, s = -p, -q, -s + + n = (p + s*sd)/q + if n < 0: + w = floor(-n) + f = -n - w + one_f = continued_fraction(1 - f) # 1-f < 1 so cf is [0 ... [...]] + one_f[0] -= w + 1 + return one_f + + d *= s**2 + sd *= s + + if (d - p**2)%q: + d *= q**2 + sd *= q + p *= q + q *= q + + terms: list[int] = [] + pq = {} + + while (p, q) not in pq: + pq[(p, q)] = len(terms) + terms.append((p + sd)//q) + p = terms[-1]*q - p + q = (d - p**2)//q + + i = pq[(p, q)] + return terms[:i] + [terms[i:]] # type: ignore + + +def continued_fraction_reduce(cf): + """ + Reduce a continued fraction to a rational or quadratic irrational. + + Compute the rational or quadratic irrational number from its + terminating or periodic continued fraction expansion. The + continued fraction expansion (cf) should be supplied as a + terminating iterator supplying the terms of the expansion. For + terminating continued fractions, this is equivalent to + ``list(continued_fraction_convergents(cf))[-1]``, only a little more + efficient. If the expansion has a repeating part, a list of the + repeating terms should be returned as the last element from the + iterator. This is the format returned by + continued_fraction_periodic. + + For quadratic irrationals, returns the largest solution found, + which is generally the one sought, if the fraction is in canonical + form (all terms positive except possibly the first). + + Examples + ======== + + >>> from sympy.ntheory.continued_fraction import continued_fraction_reduce + >>> continued_fraction_reduce([1, 2, 3, 4, 5]) + 225/157 + >>> continued_fraction_reduce([-2, 1, 9, 7, 1, 2]) + -256/233 + >>> continued_fraction_reduce([2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8]).n(10) + 2.718281835 + >>> continued_fraction_reduce([1, 4, 2, [3, 1]]) + (sqrt(21) + 287)/238 + >>> continued_fraction_reduce([[1]]) + (1 + sqrt(5))/2 + >>> from sympy.ntheory.continued_fraction import continued_fraction_periodic + >>> continued_fraction_reduce(continued_fraction_periodic(8, 5, 13)) + (sqrt(13) + 8)/5 + + See Also + ======== + + continued_fraction_periodic + + """ + from sympy.solvers import solve + + period = [] + x = Dummy('x') + + def untillist(cf): + for nxt in cf: + if isinstance(nxt, list): + period.extend(nxt) + yield x + break + yield nxt + + a = S.Zero + for a in continued_fraction_convergents(untillist(cf)): + pass + + if period: + y = Dummy('y') + solns = solve(continued_fraction_reduce(period + [y]) - y, y) + solns.sort() + pure = solns[-1] + rv = a.subs(x, pure).radsimp() + else: + rv = a + if rv.is_Add: + rv = factor_terms(rv) + if rv.is_Mul and rv.args[0] == -1: + rv = rv.func(*rv.args) + return rv + + +def continued_fraction_iterator(x): + """ + Return continued fraction expansion of x as iterator. + + Examples + ======== + + >>> from sympy import Rational, pi + >>> from sympy.ntheory.continued_fraction import continued_fraction_iterator + + >>> list(continued_fraction_iterator(Rational(3, 8))) + [0, 2, 1, 2] + >>> list(continued_fraction_iterator(Rational(-3, 8))) + [-1, 1, 1, 1, 2] + + >>> for i, v in enumerate(continued_fraction_iterator(pi)): + ... if i > 7: + ... break + ... print(v) + 3 + 7 + 15 + 1 + 292 + 1 + 1 + 1 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Continued_fraction + + """ + from sympy.functions import floor + while True: + i = floor(x) + yield i + x -= i + if not x: + break + x = 1/x + + +def continued_fraction_convergents(cf): + """ + Return an iterator over the convergents of a continued fraction (cf). + + The parameter should be in either of the following to forms: + - A list of partial quotients, possibly with the last element being a list + of repeating partial quotients, such as might be returned by + continued_fraction and continued_fraction_periodic. + - An iterable returning successive partial quotients of the continued + fraction, such as might be returned by continued_fraction_iterator. + + In computing the convergents, the continued fraction need not be strictly + in canonical form (all integers, all but the first positive). + Rational and negative elements may be present in the expansion. + + Examples + ======== + + >>> from sympy.core import pi + >>> from sympy import S + >>> from sympy.ntheory.continued_fraction import \ + continued_fraction_convergents, continued_fraction_iterator + + >>> list(continued_fraction_convergents([0, 2, 1, 2])) + [0, 1/2, 1/3, 3/8] + + >>> list(continued_fraction_convergents([1, S('1/2'), -7, S('1/4')])) + [1, 3, 19/5, 7] + + >>> it = continued_fraction_convergents(continued_fraction_iterator(pi)) + >>> for n in range(7): + ... print(next(it)) + 3 + 22/7 + 333/106 + 355/113 + 103993/33102 + 104348/33215 + 208341/66317 + + >>> it = continued_fraction_convergents([1, [1, 2]]) # sqrt(3) + >>> for n in range(7): + ... print(next(it)) + 1 + 2 + 5/3 + 7/4 + 19/11 + 26/15 + 71/41 + + See Also + ======== + + continued_fraction_iterator, continued_fraction, continued_fraction_periodic + + """ + if isinstance(cf, list) and isinstance(cf[-1], list): + cf = itertools.chain(cf[:-1], itertools.cycle(cf[-1])) + p_2, q_2 = S.Zero, S.One + p_1, q_1 = S.One, S.Zero + for a in cf: + p, q = a*p_1 + p_2, a*q_1 + q_2 + p_2, q_2 = p_1, q_1 + p_1, q_1 = p, q + yield p/q diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/digits.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/digits.py new file mode 100644 index 0000000000000000000000000000000000000000..a0414815871f6f888ccd2823546ab2b0c2c9f515 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/digits.py @@ -0,0 +1,150 @@ +from collections import defaultdict + +from sympy.utilities.iterables import multiset, is_palindromic as _palindromic +from sympy.utilities.misc import as_int + + +def digits(n, b=10, digits=None): + """ + Return a list of the digits of ``n`` in base ``b``. The first + element in the list is ``b`` (or ``-b`` if ``n`` is negative). + + Examples + ======== + + >>> from sympy.ntheory.digits import digits + >>> digits(35) + [10, 3, 5] + + If the number is negative, the negative sign will be placed on the + base (which is the first element in the returned list): + + >>> digits(-35) + [-10, 3, 5] + + Bases other than 10 (and greater than 1) can be selected with ``b``: + + >>> digits(27, b=2) + [2, 1, 1, 0, 1, 1] + + Use the ``digits`` keyword if a certain number of digits is desired: + + >>> digits(35, digits=4) + [10, 0, 0, 3, 5] + + Parameters + ========== + + n: integer + The number whose digits are returned. + + b: integer + The base in which digits are computed. + + digits: integer (or None for all digits) + The number of digits to be returned (padded with zeros, if + necessary). + + See Also + ======== + sympy.core.intfunc.num_digits, count_digits + """ + + b = as_int(b) + n = as_int(n) + if b < 2: + raise ValueError("b must be greater than 1") + else: + x, y = abs(n), [] + while x >= b: + x, r = divmod(x, b) + y.append(r) + y.append(x) + y.append(-b if n < 0 else b) + y.reverse() + ndig = len(y) - 1 + if digits is not None: + if ndig > digits: + raise ValueError( + "For %s, at least %s digits are needed." % (n, ndig)) + elif ndig < digits: + y[1:1] = [0]*(digits - ndig) + return y + + +def count_digits(n, b=10): + """ + Return a dictionary whose keys are the digits of ``n`` in the + given base, ``b``, with keys indicating the digits appearing in the + number and values indicating how many times that digit appeared. + + Examples + ======== + + >>> from sympy.ntheory import count_digits + + >>> count_digits(1111339) + {1: 4, 3: 2, 9: 1} + + The digits returned are always represented in base-10 + but the number itself can be entered in any format that is + understood by Python; the base of the number can also be + given if it is different than 10: + + >>> n = 0xFA; n + 250 + >>> count_digits(_) + {0: 1, 2: 1, 5: 1} + >>> count_digits(n, 16) + {10: 1, 15: 1} + + The default dictionary will return a 0 for any digit that did + not appear in the number. For example, which digits appear 7 + times in ``77!``: + + >>> from sympy import factorial + >>> c77 = count_digits(factorial(77)) + >>> [i for i in range(10) if c77[i] == 7] + [1, 3, 7, 9] + + See Also + ======== + sympy.core.intfunc.num_digits, digits + """ + rv = defaultdict(int, multiset(digits(n, b)).items()) + rv.pop(b) if b in rv else rv.pop(-b) # b or -b is there + return rv + + +def is_palindromic(n, b=10): + """return True if ``n`` is the same when read from left to right + or right to left in the given base, ``b``. + + Examples + ======== + + >>> from sympy.ntheory import is_palindromic + + >>> all(is_palindromic(i) for i in (-11, 1, 22, 121)) + True + + The second argument allows you to test numbers in other + bases. For example, 88 is palindromic in base-10 but not + in base-8: + + >>> is_palindromic(88, 8) + False + + On the other hand, a number can be palindromic in base-8 but + not in base-10: + + >>> 0o121, is_palindromic(0o121) + (81, False) + + Or it might be palindromic in both bases: + + >>> oct(121), is_palindromic(121, 8) and is_palindromic(121) + ('0o171', True) + + """ + return _palindromic(digits(n, b), 1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/ecm.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/ecm.py new file mode 100644 index 0000000000000000000000000000000000000000..498c0c8fdf8478688465c4bae307818e9685b686 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/ecm.py @@ -0,0 +1,348 @@ +from math import log + +from sympy.core.random import _randint +from sympy.external.gmpy import gcd, invert, sqrt +from sympy.utilities.misc import as_int +from .generate import sieve, primerange +from .primetest import isprime + + +#----------------------------------------------------------------------------# +# # +# Lenstra's Elliptic Curve Factorization # +# # +#----------------------------------------------------------------------------# + + +class Point: + """Montgomery form of Points in an elliptic curve. + In this form, the addition and doubling of points + does not need any y-coordinate information thus + decreasing the number of operations. + Using Montgomery form we try to perform point addition + and doubling in least amount of multiplications. + + The elliptic curve used here is of the form + (E : b*y**2*z = x**3 + a*x**2*z + x*z**2). + The a_24 parameter is equal to (a + 2)/4. + + References + ========== + + .. [1] Kris Gaj, Soonhak Kwon, Patrick Baier, Paul Kohlbrenner, Hoang Le, Mohammed Khaleeluddin, Ramakrishna Bachimanchi, + Implementing the Elliptic Curve Method of Factoring in Reconfigurable Hardware, + Cryptographic Hardware and Embedded Systems - CHES 2006 (2006), pp. 119-133, + https://doi.org/10.1007/11894063_10 + https://www.hyperelliptic.org/tanja/SHARCS/talks06/Gaj.pdf + + """ + + def __init__(self, x_cord, z_cord, a_24, mod): + """ + Initial parameters for the Point class. + + Parameters + ========== + + x_cord : X coordinate of the Point + z_cord : Z coordinate of the Point + a_24 : Parameter of the elliptic curve in Montgomery form + mod : modulus + """ + self.x_cord = x_cord + self.z_cord = z_cord + self.a_24 = a_24 + self.mod = mod + + def __eq__(self, other): + """Two points are equal if X/Z of both points are equal + """ + if self.a_24 != other.a_24 or self.mod != other.mod: + return False + return self.x_cord * other.z_cord % self.mod ==\ + other.x_cord * self.z_cord % self.mod + + def add(self, Q, diff): + """ + Add two points self and Q where diff = self - Q. Moreover the assumption + is self.x_cord*Q.x_cord*(self.x_cord - Q.x_cord) != 0. This algorithm + requires 6 multiplications. Here the difference between the points + is already known and using this algorithm speeds up the addition + by reducing the number of multiplication required. Also in the + mont_ladder algorithm is constructed in a way so that the difference + between intermediate points is always equal to the initial point. + So, we always know what the difference between the point is. + + + Parameters + ========== + + Q : point on the curve in Montgomery form + diff : self - Q + + Examples + ======== + + >>> from sympy.ntheory.ecm import Point + >>> p1 = Point(11, 16, 7, 29) + >>> p2 = Point(13, 10, 7, 29) + >>> p3 = p2.add(p1, p1) + >>> p3.x_cord + 23 + >>> p3.z_cord + 17 + """ + u = (self.x_cord - self.z_cord)*(Q.x_cord + Q.z_cord) + v = (self.x_cord + self.z_cord)*(Q.x_cord - Q.z_cord) + add, subt = u + v, u - v + x_cord = diff.z_cord * add * add % self.mod + z_cord = diff.x_cord * subt * subt % self.mod + return Point(x_cord, z_cord, self.a_24, self.mod) + + def double(self): + """ + Doubles a point in an elliptic curve in Montgomery form. + This algorithm requires 5 multiplications. + + Examples + ======== + + >>> from sympy.ntheory.ecm import Point + >>> p1 = Point(11, 16, 7, 29) + >>> p2 = p1.double() + >>> p2.x_cord + 13 + >>> p2.z_cord + 10 + """ + u = pow(self.x_cord + self.z_cord, 2, self.mod) + v = pow(self.x_cord - self.z_cord, 2, self.mod) + diff = u - v + x_cord = u*v % self.mod + z_cord = diff*(v + self.a_24*diff) % self.mod + return Point(x_cord, z_cord, self.a_24, self.mod) + + def mont_ladder(self, k): + """ + Scalar multiplication of a point in Montgomery form + using Montgomery Ladder Algorithm. + A total of 11 multiplications are required in each step of this + algorithm. + + Parameters + ========== + + k : The positive integer multiplier + + Examples + ======== + + >>> from sympy.ntheory.ecm import Point + >>> p1 = Point(11, 16, 7, 29) + >>> p3 = p1.mont_ladder(3) + >>> p3.x_cord + 23 + >>> p3.z_cord + 17 + """ + Q = self + R = self.double() + for i in bin(k)[3:]: + if i == '1': + Q = R.add(Q, self) + R = R.double() + else: + R = Q.add(R, self) + Q = Q.double() + return Q + + +def _ecm_one_factor(n, B1=10000, B2=100000, max_curve=200, seed=None): + """Returns one factor of n using + Lenstra's 2 Stage Elliptic curve Factorization + with Suyama's Parameterization. Here Montgomery + arithmetic is used for fast computation of addition + and doubling of points in elliptic curve. + + Explanation + =========== + + This ECM method considers elliptic curves in Montgomery + form (E : b*y**2*z = x**3 + a*x**2*z + x*z**2) and involves + elliptic curve operations (mod N), where the elements in + Z are reduced (mod N). Since N is not a prime, E over FF(N) + is not really an elliptic curve but we can still do point additions + and doubling as if FF(N) was a field. + + Stage 1 : The basic algorithm involves taking a random point (P) on an + elliptic curve in FF(N). The compute k*P using Montgomery ladder algorithm. + Let q be an unknown factor of N. Then the order of the curve E, |E(FF(q))|, + might be a smooth number that divides k. Then we have k = l * |E(FF(q))| + for some l. For any point belonging to the curve E, |E(FF(q))|*P = O, + hence k*P = l*|E(FF(q))|*P. Thus kP.z_cord = 0 (mod q), and the unknownn + factor of N (q) can be recovered by taking gcd(kP.z_cord, N). + + Stage 2 : This is a continuation of Stage 1 if k*P != O. The idea utilize + the fact that even if kP != 0, the value of k might miss just one large + prime divisor of |E(FF(q))|. In this case we only need to compute the + scalar multiplication by p to get p*k*P = O. Here a second bound B2 + restrict the size of possible values of p. + + Parameters + ========== + + n : Number to be Factored. Assume that it is a composite number. + B1 : Stage 1 Bound. Must be an even number. + B2 : Stage 2 Bound. Must be an even number. + max_curve : Maximum number of curves generated + + Returns + ======= + + integer | None : a non-trivial divisor of ``n``. ``None`` if not found + + References + ========== + + .. [1] Carl Pomerance, Richard Crandall, Prime Numbers: A Computational Perspective, + 2nd Edition (2005), page 344, ISBN:978-0387252827 + """ + randint = _randint(seed) + + # When calculating T, if (B1 - 2*D) is negative, it cannot be calculated. + D = min(sqrt(B2), B1 // 2 - 1) + sieve.extend(D) + beta = [0] * D + S = [0] * D + k = 1 + for p in primerange(2, B1 + 1): + k *= pow(p, int(log(B1, p))) + + # Pre-calculate the prime numbers to be used in stage 2. + # Using the fact that the x-coordinates of point P and its + # inverse -P coincide, the number of primes to be checked + # in stage 2 can be reduced. + deltas_list = [] + for r in range(B1 + 2*D, B2 + 2*D, 4*D): + # d in deltas iff r+(2d+1) and/or r-(2d+1) is prime + deltas = {abs(q - r) >> 1 for q in primerange(r - 2*D, r + 2*D)} + deltas_list.append(list(deltas)) + + for _ in range(max_curve): + #Suyama's Parametrization + sigma = randint(6, n - 1) + u = (sigma**2 - 5) % n + v = (4*sigma) % n + u_3 = pow(u, 3, n) + + try: + # We use the elliptic curve y**2 = x**3 + a*x**2 + x + # where a = pow(v - u, 3, n)*(3*u + v)*invert(4*u_3*v, n) - 2 + # However, we do not declare a because it is more convenient + # to use a24 = (a + 2)*invert(4, n) in the calculation. + a24 = pow(v - u, 3, n)*(3*u + v)*invert(16*u_3*v, n) % n + except ZeroDivisionError: + #If the invert(16*u_3*v, n) doesn't exist (i.e., g != 1) + g = gcd(2*u_3*v, n) + #If g = n, try another curve + if g == n: + continue + return g + + Q = Point(u_3, pow(v, 3, n), a24, n) + Q = Q.mont_ladder(k) + g = gcd(Q.z_cord, n) + + #Stage 1 factor + if g != 1 and g != n: + return g + #Stage 1 failure. Q.z = 0, Try another curve + elif g == n: + continue + + #Stage 2 - Improved Standard Continuation + S[0] = Q + Q2 = Q.double() + S[1] = Q2.add(Q, Q) + beta[0] = (S[0].x_cord*S[0].z_cord) % n + beta[1] = (S[1].x_cord*S[1].z_cord) % n + for d in range(2, D): + S[d] = S[d - 1].add(Q2, S[d - 2]) + beta[d] = (S[d].x_cord*S[d].z_cord) % n + # i.e., S[i] = Q.mont_ladder(2*i + 1) + + g = 1 + W = Q.mont_ladder(4*D) + T = Q.mont_ladder(B1 - 2*D) + R = Q.mont_ladder(B1 + 2*D) + for deltas in deltas_list: + # R = Q.mont_ladder(r) where r in range(B1 + 2*D, B2 + 2*D, 4*D) + alpha = (R.x_cord*R.z_cord) % n + for delta in deltas: + # We want to calculate + # f = R.x_cord * S[delta].z_cord - S[delta].x_cord * R.z_cord + f = (R.x_cord - S[delta].x_cord)*\ + (R.z_cord + S[delta].z_cord) - alpha + beta[delta] + g = (g*f) % n + T, R = R, R.add(W, T) + g = gcd(n, g) + + #Stage 2 Factor found + if g != 1 and g != n: + return g + + +def ecm(n, B1=10000, B2=100000, max_curve=200, seed=1234): + """Performs factorization using Lenstra's Elliptic curve method. + + This function repeatedly calls ``_ecm_one_factor`` to compute the factors + of n. First all the small factors are taken out using trial division. + Then ``_ecm_one_factor`` is used to compute one factor at a time. + + Parameters + ========== + + n : Number to be Factored + B1 : Stage 1 Bound. Must be an even number. + B2 : Stage 2 Bound. Must be an even number. + max_curve : Maximum number of curves generated + seed : Initialize pseudorandom generator + + Examples + ======== + + >>> from sympy.ntheory import ecm + >>> ecm(25645121643901801) + {5394769, 4753701529} + >>> ecm(9804659461513846513) + {4641991, 2112166839943} + """ + from .factor_ import _perfect_power + n = as_int(n) + if B1 % 2 != 0 or B2 % 2 != 0: + raise ValueError("both bounds must be even") + TF_LIMIT = 100000 + factors = set() + for prime in sieve.primerange(2, TF_LIMIT): + if n % prime == 0: + factors.add(prime) + while(n % prime == 0): + n //= prime + + queue = [] + def check(m): + if isprime(m): + factors.add(m) + return + if result := _perfect_power(m, TF_LIMIT): + return check(result[0]) + queue.append(m) + check(n) + while queue: + n = queue.pop() + factor = _ecm_one_factor(n, B1, B2, max_curve, seed) + if factor is None: + raise ValueError("Increase the bounds") + check(factor) + check(n // factor) + return factors diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/egyptian_fraction.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/egyptian_fraction.py new file mode 100644 index 0000000000000000000000000000000000000000..8a42540b372042f596808684fef8e3fc57935b74 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/egyptian_fraction.py @@ -0,0 +1,223 @@ +from sympy.core.containers import Tuple +from sympy.core.numbers import (Integer, Rational) +from sympy.core.singleton import S +import sympy.polys + +from math import gcd + + +def egyptian_fraction(r, algorithm="Greedy"): + """ + Return the list of denominators of an Egyptian fraction + expansion [1]_ of the said rational `r`. + + Parameters + ========== + + r : Rational or (p, q) + a positive rational number, ``p/q``. + algorithm : { "Greedy", "Graham Jewett", "Takenouchi", "Golomb" }, optional + Denotes the algorithm to be used (the default is "Greedy"). + + Examples + ======== + + >>> from sympy import Rational + >>> from sympy.ntheory.egyptian_fraction import egyptian_fraction + >>> egyptian_fraction(Rational(3, 7)) + [3, 11, 231] + >>> egyptian_fraction((3, 7), "Graham Jewett") + [7, 8, 9, 56, 57, 72, 3192] + >>> egyptian_fraction((3, 7), "Takenouchi") + [4, 7, 28] + >>> egyptian_fraction((3, 7), "Golomb") + [3, 15, 35] + >>> egyptian_fraction((11, 5), "Golomb") + [1, 2, 3, 4, 9, 234, 1118, 2580] + + See Also + ======== + + sympy.core.numbers.Rational + + Notes + ===== + + Currently the following algorithms are supported: + + 1) Greedy Algorithm + + Also called the Fibonacci-Sylvester algorithm [2]_. + At each step, extract the largest unit fraction less + than the target and replace the target with the remainder. + + It has some distinct properties: + + a) Given `p/q` in lowest terms, generates an expansion of maximum + length `p`. Even as the numerators get large, the number of + terms is seldom more than a handful. + + b) Uses minimal memory. + + c) The terms can blow up (standard examples of this are 5/121 and + 31/311). The denominator is at most squared at each step + (doubly-exponential growth) and typically exhibits + singly-exponential growth. + + 2) Graham Jewett Algorithm + + The algorithm suggested by the result of Graham and Jewett. + Note that this has a tendency to blow up: the length of the + resulting expansion is always ``2**(x/gcd(x, y)) - 1``. See [3]_. + + 3) Takenouchi Algorithm + + The algorithm suggested by Takenouchi (1921). + Differs from the Graham-Jewett algorithm only in the handling + of duplicates. See [3]_. + + 4) Golomb's Algorithm + + A method given by Golumb (1962), using modular arithmetic and + inverses. It yields the same results as a method using continued + fractions proposed by Bleicher (1972). See [4]_. + + If the given rational is greater than or equal to 1, a greedy algorithm + of summing the harmonic sequence 1/1 + 1/2 + 1/3 + ... is used, taking + all the unit fractions of this sequence until adding one more would be + greater than the given number. This list of denominators is prefixed + to the result from the requested algorithm used on the remainder. For + example, if r is 8/3, using the Greedy algorithm, we get [1, 2, 3, 4, + 5, 6, 7, 14, 420], where the beginning of the sequence, [1, 2, 3, 4, 5, + 6, 7] is part of the harmonic sequence summing to 363/140, leaving a + remainder of 31/420, which yields [14, 420] by the Greedy algorithm. + The result of egyptian_fraction(Rational(8, 3), "Golomb") is [1, 2, 3, + 4, 5, 6, 7, 14, 574, 2788, 6460, 11590, 33062, 113820], and so on. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Egyptian_fraction + .. [2] https://en.wikipedia.org/wiki/Greedy_algorithm_for_Egyptian_fractions + .. [3] https://www.ics.uci.edu/~eppstein/numth/egypt/conflict.html + .. [4] https://web.archive.org/web/20180413004012/https://ami.ektf.hu/uploads/papers/finalpdf/AMI_42_from129to134.pdf + + """ + + if not isinstance(r, Rational): + if isinstance(r, (Tuple, tuple)) and len(r) == 2: + r = Rational(*r) + else: + raise ValueError("Value must be a Rational or tuple of ints") + if r <= 0: + raise ValueError("Value must be positive") + + # common cases that all methods agree on + x, y = r.as_numer_denom() + if y == 1 and x == 2: + return [Integer(i) for i in [1, 2, 3, 6]] + if x == y + 1: + return [S.One, y] + + prefix, rem = egypt_harmonic(r) + if rem == 0: + return prefix + # work in Python ints + x, y = rem.p, rem.q + # assert x < y and gcd(x, y) = 1 + + if algorithm == "Greedy": + postfix = egypt_greedy(x, y) + elif algorithm == "Graham Jewett": + postfix = egypt_graham_jewett(x, y) + elif algorithm == "Takenouchi": + postfix = egypt_takenouchi(x, y) + elif algorithm == "Golomb": + postfix = egypt_golomb(x, y) + else: + raise ValueError("Entered invalid algorithm") + return prefix + [Integer(i) for i in postfix] + + +def egypt_greedy(x, y): + # assumes gcd(x, y) == 1 + if x == 1: + return [y] + else: + a = (-y) % x + b = y*(y//x + 1) + c = gcd(a, b) + if c > 1: + num, denom = a//c, b//c + else: + num, denom = a, b + return [y//x + 1] + egypt_greedy(num, denom) + + +def egypt_graham_jewett(x, y): + # assumes gcd(x, y) == 1 + l = [y] * x + + # l is now a list of integers whose reciprocals sum to x/y. + # we shall now proceed to manipulate the elements of l without + # changing the reciprocated sum until all elements are unique. + + while len(l) != len(set(l)): + l.sort() # so the list has duplicates. find a smallest pair + for i in range(len(l) - 1): + if l[i] == l[i + 1]: + break + # we have now identified a pair of identical + # elements: l[i] and l[i + 1]. + # now comes the application of the result of graham and jewett: + l[i + 1] = l[i] + 1 + # and we just iterate that until the list has no duplicates. + l.append(l[i]*(l[i] + 1)) + return sorted(l) + + +def egypt_takenouchi(x, y): + # assumes gcd(x, y) == 1 + # special cases for 3/y + if x == 3: + if y % 2 == 0: + return [y//2, y] + i = (y - 1)//2 + j = i + 1 + k = j + i + return [j, k, j*k] + l = [y] * x + while len(l) != len(set(l)): + l.sort() + for i in range(len(l) - 1): + if l[i] == l[i + 1]: + break + k = l[i] + if k % 2 == 0: + l[i] = l[i] // 2 + del l[i + 1] + else: + l[i], l[i + 1] = (k + 1)//2, k*(k + 1)//2 + return sorted(l) + + +def egypt_golomb(x, y): + # assumes x < y and gcd(x, y) == 1 + if x == 1: + return [y] + xp = sympy.polys.ZZ.invert(int(x), int(y)) + rv = [xp*y] + rv.extend(egypt_golomb((x*xp - 1)//y, xp)) + return sorted(rv) + + +def egypt_harmonic(r): + # assumes r is Rational + rv = [] + d = S.One + acc = S.Zero + while acc + 1/d <= r: + acc += 1/d + rv.append(d) + d += 1 + return (rv, r - acc) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/elliptic_curve.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/elliptic_curve.py new file mode 100644 index 0000000000000000000000000000000000000000..c969470a6c19a3d17e637529b6615eeba326e84a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/elliptic_curve.py @@ -0,0 +1,397 @@ +from sympy.core.numbers import oo +from sympy.core.symbol import symbols +from sympy.polys.domains import FiniteField, QQ, RationalField, FF +from sympy.polys.polytools import Poly +from sympy.solvers.solvers import solve +from sympy.utilities.iterables import is_sequence +from sympy.utilities.misc import as_int +from .factor_ import divisors +from .residue_ntheory import polynomial_congruence + + +class EllipticCurve: + """ + Create the following Elliptic Curve over domain. + + `y^{2} + a_{1} x y + a_{3} y = x^{3} + a_{2} x^{2} + a_{4} x + a_{6}` + + The default domain is ``QQ``. If no coefficient ``a1``, ``a2``, ``a3``, + is given then it creates a curve with the following form: + + `y^{2} = x^{3} + a_{4} x + a_{6}` + + Examples + ======== + + References + ========== + + .. [1] J. Silverman "A Friendly Introduction to Number Theory" Third Edition + .. [2] https://mathworld.wolfram.com/EllipticDiscriminant.html + .. [3] G. Hardy, E. Wright "An Introduction to the Theory of Numbers" Sixth Edition + + """ + + def __init__(self, a4, a6, a1=0, a2=0, a3=0, modulus=0): + if modulus == 0: + domain = QQ + else: + domain = FF(modulus) + a1, a2, a3, a4, a6 = map(domain.convert, (a1, a2, a3, a4, a6)) + self._domain = domain + self.modulus = modulus + # Calculate discriminant + b2 = a1**2 + 4 * a2 + b4 = 2 * a4 + a1 * a3 + b6 = a3**2 + 4 * a6 + b8 = a1**2 * a6 + 4 * a2 * a6 - a1 * a3 * a4 + a2 * a3**2 - a4**2 + self._b2, self._b4, self._b6, self._b8 = b2, b4, b6, b8 + self._discrim = -b2**2 * b8 - 8 * b4**3 - 27 * b6**2 + 9 * b2 * b4 * b6 + self._a1 = a1 + self._a2 = a2 + self._a3 = a3 + self._a4 = a4 + self._a6 = a6 + x, y, z = symbols('x y z') + self.x, self.y, self.z = x, y, z + self._poly = Poly(y**2*z + a1*x*y*z + a3*y*z**2 - x**3 - a2*x**2*z - a4*x*z**2 - a6*z**3, domain=domain) + if isinstance(self._domain, FiniteField): + self._rank = 0 + elif isinstance(self._domain, RationalField): + self._rank = None + + def __call__(self, x, y, z=1): + return EllipticCurvePoint(x, y, z, self) + + def __contains__(self, point): + if is_sequence(point): + if len(point) == 2: + z1 = 1 + else: + z1 = point[2] + x1, y1 = point[:2] + elif isinstance(point, EllipticCurvePoint): + x1, y1, z1 = point.x, point.y, point.z + else: + raise ValueError('Invalid point.') + if self.characteristic == 0 and z1 == 0: + return True + return self._poly.subs({self.x: x1, self.y: y1, self.z: z1}) == 0 + + def __repr__(self): + return self._poly.__repr__() + + def minimal(self): + """ + Return minimal Weierstrass equation. + + Examples + ======== + + >>> from sympy.ntheory.elliptic_curve import EllipticCurve + + >>> e1 = EllipticCurve(-10, -20, 0, -1, 1) + >>> e1.minimal() + Poly(-x**3 + 13392*x*z**2 + y**2*z + 1080432*z**3, x, y, z, domain='QQ') + + """ + char = self.characteristic + if char == 2: + return self + if char == 3: + return EllipticCurve(self._b4/2, self._b6/4, a2=self._b2/4, modulus=self.modulus) + c4 = self._b2**2 - 24*self._b4 + c6 = -self._b2**3 + 36*self._b2*self._b4 - 216*self._b6 + return EllipticCurve(-27*c4, -54*c6, modulus=self.modulus) + + def points(self): + """ + Return points of curve over Finite Field. + + Examples + ======== + + >>> from sympy.ntheory.elliptic_curve import EllipticCurve + >>> e2 = EllipticCurve(1, 1, 1, 1, 1, modulus=5) + >>> e2.points() + {(0, 2), (1, 4), (2, 0), (2, 2), (3, 0), (3, 1), (4, 0)} + + """ + + char = self.characteristic + all_pt = set() + if char >= 1: + for i in range(char): + congruence_eq = self._poly.subs({self.x: i, self.z: 1}).expr + sol = polynomial_congruence(congruence_eq, char) + all_pt.update((i, num) for num in sol) + return all_pt + else: + raise ValueError("Infinitely many points") + + def points_x(self, x): + """Returns points on the curve for the given x-coordinate.""" + pt = [] + if self._domain == QQ: + for y in solve(self._poly.subs(self.x, x)): + pt.append((x, y)) + else: + congruence_eq = self._poly.subs({self.x: x, self.z: 1}).expr + for y in polynomial_congruence(congruence_eq, self.characteristic): + pt.append((x, y)) + return pt + + def torsion_points(self): + """ + Return torsion points of curve over Rational number. + + Return point objects those are finite order. + According to Nagell-Lutz theorem, torsion point p(x, y) + x and y are integers, either y = 0 or y**2 is divisor + of discriminent. According to Mazur's theorem, there are + at most 15 points in torsion collection. + + Examples + ======== + + >>> from sympy.ntheory.elliptic_curve import EllipticCurve + >>> e2 = EllipticCurve(-43, 166) + >>> sorted(e2.torsion_points()) + [(-5, -16), (-5, 16), O, (3, -8), (3, 8), (11, -32), (11, 32)] + + """ + if self.characteristic > 0: + raise ValueError("No torsion point for Finite Field.") + l = [EllipticCurvePoint.point_at_infinity(self)] + for xx in solve(self._poly.subs({self.y: 0, self.z: 1})): + if xx.is_rational: + l.append(self(xx, 0)) + for i in divisors(self.discriminant, generator=True): + j = int(i**.5) + if j**2 == i: + for xx in solve(self._poly.subs({self.y: j, self.z: 1})): + if not xx.is_rational: + continue + p = self(xx, j) + if p.order() != oo: + l.extend([p, -p]) + return l + + @property + def characteristic(self): + """ + Return domain characteristic. + + Examples + ======== + + >>> from sympy.ntheory.elliptic_curve import EllipticCurve + >>> e2 = EllipticCurve(-43, 166) + >>> e2.characteristic + 0 + + """ + return self._domain.characteristic() + + @property + def discriminant(self): + """ + Return curve discriminant. + + Examples + ======== + + >>> from sympy.ntheory.elliptic_curve import EllipticCurve + >>> e2 = EllipticCurve(0, 17) + >>> e2.discriminant + -124848 + + """ + return int(self._discrim) + + @property + def is_singular(self): + """ + Return True if curve discriminant is equal to zero. + """ + return self.discriminant == 0 + + @property + def j_invariant(self): + """ + Return curve j-invariant. + + Examples + ======== + + >>> from sympy.ntheory.elliptic_curve import EllipticCurve + >>> e1 = EllipticCurve(-2, 0, 0, 1, 1) + >>> e1.j_invariant + 1404928/389 + + """ + c4 = self._b2**2 - 24*self._b4 + return self._domain.to_sympy(c4**3 / self._discrim) + + @property + def order(self): + """ + Number of points in Finite field. + + Examples + ======== + + >>> from sympy.ntheory.elliptic_curve import EllipticCurve + >>> e2 = EllipticCurve(1, 0, modulus=19) + >>> e2.order + 19 + + """ + if self.characteristic == 0: + raise NotImplementedError("Still not implemented") + return len(self.points()) + + @property + def rank(self): + """ + Number of independent points of infinite order. + + For Finite field, it must be 0. + """ + if self._rank is not None: + return self._rank + raise NotImplementedError("Still not implemented") + + +class EllipticCurvePoint: + """ + Point of Elliptic Curve + + Examples + ======== + + >>> from sympy.ntheory.elliptic_curve import EllipticCurve + >>> e1 = EllipticCurve(-17, 16) + >>> p1 = e1(0, -4, 1) + >>> p2 = e1(1, 0) + >>> p1 + p2 + (15, -56) + >>> e3 = EllipticCurve(-1, 9) + >>> e3(1, -3) * 3 + (664/169, 17811/2197) + >>> (e3(1, -3) * 3).order() + oo + >>> e2 = EllipticCurve(-2, 0, 0, 1, 1) + >>> p = e2(-1,1) + >>> q = e2(0, -1) + >>> p+q + (4, 8) + >>> p-q + (1, 0) + >>> 3*p-5*q + (328/361, -2800/6859) + """ + + @staticmethod + def point_at_infinity(curve): + return EllipticCurvePoint(0, 1, 0, curve) + + def __init__(self, x, y, z, curve): + dom = curve._domain.convert + self.x = dom(x) + self.y = dom(y) + self.z = dom(z) + self._curve = curve + self._domain = self._curve._domain + if not self._curve.__contains__(self): + raise ValueError("The curve does not contain this point") + + def __add__(self, p): + if self.z == 0: + return p + if p.z == 0: + return self + x1, y1 = self.x/self.z, self.y/self.z + x2, y2 = p.x/p.z, p.y/p.z + a1 = self._curve._a1 + a2 = self._curve._a2 + a3 = self._curve._a3 + a4 = self._curve._a4 + a6 = self._curve._a6 + if x1 != x2: + slope = (y1 - y2) / (x1 - x2) + yint = (y1 * x2 - y2 * x1) / (x2 - x1) + else: + if (y1 + y2) == 0: + return self.point_at_infinity(self._curve) + slope = (3 * x1**2 + 2*a2*x1 + a4 - a1*y1) / (a1 * x1 + a3 + 2 * y1) + yint = (-x1**3 + a4*x1 + 2*a6 - a3*y1) / (a1*x1 + a3 + 2*y1) + x3 = slope**2 + a1*slope - a2 - x1 - x2 + y3 = -(slope + a1) * x3 - yint - a3 + return self._curve(x3, y3, 1) + + def __lt__(self, other): + return (self.x, self.y, self.z) < (other.x, other.y, other.z) + + def __mul__(self, n): + n = as_int(n) + r = self.point_at_infinity(self._curve) + if n == 0: + return r + if n < 0: + return -self * -n + p = self + while n: + if n & 1: + r = r + p + n >>= 1 + p = p + p + return r + + def __rmul__(self, n): + return self * n + + def __neg__(self): + return EllipticCurvePoint(self.x, -self.y - self._curve._a1*self.x - self._curve._a3, self.z, self._curve) + + def __repr__(self): + if self.z == 0: + return 'O' + dom = self._curve._domain + try: + return '({}, {})'.format(dom.to_sympy(self.x), dom.to_sympy(self.y)) + except TypeError: + pass + return '({}, {})'.format(self.x, self.y) + + def __sub__(self, other): + return self.__add__(-other) + + def order(self): + """ + Return point order n where nP = 0. + + """ + if self.z == 0: + return 1 + if self.y == 0: # P = -P + return 2 + p = self * 2 + if p.y == -self.y: # 2P = -P + return 3 + i = 2 + if self._domain != QQ: + while int(p.x) == p.x and int(p.y) == p.y: + p = self + p + i += 1 + if p.z == 0: + return i + return oo + while p.x.numerator == p.x and p.y.numerator == p.y: + p = self + p + i += 1 + if i > 12: + return oo + if p.z == 0: + return i + return oo diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/factor_.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/factor_.py new file mode 100644 index 0000000000000000000000000000000000000000..2dc6ac81c237f000e55014f5e170b27b41335786 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/factor_.py @@ -0,0 +1,2841 @@ +""" +Integer factorization +""" +from __future__ import annotations + +from bisect import bisect_left +from collections import defaultdict, OrderedDict +from collections.abc import MutableMapping +import math + +from sympy.core.containers import Dict +from sympy.core.mul import Mul +from sympy.core.numbers import Rational, Integer +from sympy.core.intfunc import num_digits +from sympy.core.power import Pow +from sympy.core.random import _randint +from sympy.core.singleton import S +from sympy.external.gmpy import (SYMPY_INTS, gcd, sqrt as isqrt, + sqrtrem, iroot, bit_scan1, remove) +from .primetest import isprime, MERSENNE_PRIME_EXPONENTS, is_mersenne_prime +from .generate import sieve, primerange, nextprime +from .digits import digits +from sympy.utilities.decorator import deprecated +from sympy.utilities.iterables import flatten +from sympy.utilities.misc import as_int, filldedent +from .ecm import _ecm_one_factor + + +def smoothness(n): + """ + Return the B-smooth and B-power smooth values of n. + + The smoothness of n is the largest prime factor of n; the power- + smoothness is the largest divisor raised to its multiplicity. + + Examples + ======== + + >>> from sympy.ntheory.factor_ import smoothness + >>> smoothness(2**7*3**2) + (3, 128) + >>> smoothness(2**4*13) + (13, 16) + >>> smoothness(2) + (2, 2) + + See Also + ======== + + factorint, smoothness_p + """ + + if n == 1: + return (1, 1) # not prime, but otherwise this causes headaches + facs = factorint(n) + return max(facs), max(m**facs[m] for m in facs) + + +def smoothness_p(n, m=-1, power=0, visual=None): + """ + Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...] + where: + + 1. p**M is the base-p divisor of n + 2. sm(p + m) is the smoothness of p + m (m = -1 by default) + 3. psm(p + m) is the power smoothness of p + m + + The list is sorted according to smoothness (default) or by power smoothness + if power=1. + + The smoothness of the numbers to the left (m = -1) or right (m = 1) of a + factor govern the results that are obtained from the p +/- 1 type factoring + methods. + + >>> from sympy.ntheory.factor_ import smoothness_p, factorint + >>> smoothness_p(10431, m=1) + (1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))]) + >>> smoothness_p(10431) + (-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))]) + >>> smoothness_p(10431, power=1) + (-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))]) + + If visual=True then an annotated string will be returned: + + >>> print(smoothness_p(21477639576571, visual=1)) + p**i=4410317**1 has p-1 B=1787, B-pow=1787 + p**i=4869863**1 has p-1 B=2434931, B-pow=2434931 + + This string can also be generated directly from a factorization dictionary + and vice versa: + + >>> factorint(17*9) + {3: 2, 17: 1} + >>> smoothness_p(_) + 'p**i=3**2 has p-1 B=2, B-pow=2\\np**i=17**1 has p-1 B=2, B-pow=16' + >>> smoothness_p(_) + {3: 2, 17: 1} + + The table of the output logic is: + + ====== ====== ======= ======= + | Visual + ------ ---------------------- + Input True False other + ====== ====== ======= ======= + dict str tuple str + str str tuple dict + tuple str tuple str + n str tuple tuple + mul str tuple tuple + ====== ====== ======= ======= + + See Also + ======== + + factorint, smoothness + """ + + # visual must be True, False or other (stored as None) + if visual in (1, 0): + visual = bool(visual) + elif visual not in (True, False): + visual = None + + if isinstance(n, str): + if visual: + return n + d = {} + for li in n.splitlines(): + k, v = [int(i) for i in + li.split('has')[0].split('=')[1].split('**')] + d[k] = v + if visual is not True and visual is not False: + return d + return smoothness_p(d, visual=False) + elif not isinstance(n, tuple): + facs = factorint(n, visual=False) + + if power: + k = -1 + else: + k = 1 + if isinstance(n, tuple): + rv = n + else: + rv = (m, sorted([(f, + tuple([M] + list(smoothness(f + m)))) + for f, M in list(facs.items())], + key=lambda x: (x[1][k], x[0]))) + + if visual is False or (visual is not True) and (type(n) in [int, Mul]): + return rv + lines = [] + for dat in rv[1]: + dat = flatten(dat) + dat.insert(2, m) + lines.append('p**i=%i**%i has p%+i B=%i, B-pow=%i' % tuple(dat)) + return '\n'.join(lines) + + +def multiplicity(p, n): + """ + Find the greatest integer m such that p**m divides n. + + Examples + ======== + + >>> from sympy import multiplicity, Rational + >>> [multiplicity(5, n) for n in [8, 5, 25, 125, 250]] + [0, 1, 2, 3, 3] + >>> multiplicity(3, Rational(1, 9)) + -2 + + Note: when checking for the multiplicity of a number in a + large factorial it is most efficient to send it as an unevaluated + factorial or to call ``multiplicity_in_factorial`` directly: + + >>> from sympy.ntheory import multiplicity_in_factorial + >>> from sympy import factorial + >>> p = factorial(25) + >>> n = 2**100 + >>> nfac = factorial(n, evaluate=False) + >>> multiplicity(p, nfac) + 52818775009509558395695966887 + >>> _ == multiplicity_in_factorial(p, n) + True + + See Also + ======== + + trailing + + """ + try: + p, n = as_int(p), as_int(n) + except ValueError: + from sympy.functions.combinatorial.factorials import factorial + if all(isinstance(i, (SYMPY_INTS, Rational)) for i in (p, n)): + p = Rational(p) + n = Rational(n) + if p.q == 1: + if n.p == 1: + return -multiplicity(p.p, n.q) + return multiplicity(p.p, n.p) - multiplicity(p.p, n.q) + elif p.p == 1: + return multiplicity(p.q, n.q) + else: + like = min( + multiplicity(p.p, n.p), + multiplicity(p.q, n.q)) + cross = min( + multiplicity(p.q, n.p), + multiplicity(p.p, n.q)) + return like - cross + elif (isinstance(p, (SYMPY_INTS, Integer)) and + isinstance(n, factorial) and + isinstance(n.args[0], Integer) and + n.args[0] >= 0): + return multiplicity_in_factorial(p, n.args[0]) + raise ValueError('expecting ints or fractions, got %s and %s' % (p, n)) + + if n == 0: + raise ValueError('no such integer exists: multiplicity of %s is not-defined' %(n)) + return remove(n, p)[1] + + +def multiplicity_in_factorial(p, n): + """return the largest integer ``m`` such that ``p**m`` divides ``n!`` + without calculating the factorial of ``n``. + + Parameters + ========== + + p : Integer + positive integer + n : Integer + non-negative integer + + Examples + ======== + + >>> from sympy.ntheory import multiplicity_in_factorial + >>> from sympy import factorial + + >>> multiplicity_in_factorial(2, 3) + 1 + + An instructive use of this is to tell how many trailing zeros + a given factorial has. For example, there are 6 in 25!: + + >>> factorial(25) + 15511210043330985984000000 + >>> multiplicity_in_factorial(10, 25) + 6 + + For large factorials, it is much faster/feasible to use + this function rather than computing the actual factorial: + + >>> multiplicity_in_factorial(factorial(25), 2**100) + 52818775009509558395695966887 + + See Also + ======== + + multiplicity + + """ + + p, n = as_int(p), as_int(n) + + if p <= 0: + raise ValueError('expecting positive integer got %s' % p ) + + if n < 0: + raise ValueError('expecting non-negative integer got %s' % n ) + + # keep only the largest of a given multiplicity since those + # of a given multiplicity will be goverened by the behavior + # of the largest factor + f = defaultdict(int) + for k, v in factorint(p).items(): + f[v] = max(k, f[v]) + # multiplicity of p in n! depends on multiplicity + # of prime `k` in p, so we floor divide by `v` + # and keep it if smaller than the multiplicity of p + # seen so far + return min((n + k - sum(digits(n, k)))//(k - 1)//v for v, k in f.items()) + + +def _perfect_power(n, next_p=2): + """ Return integers ``(b, e)`` such that ``n == b**e`` if ``n`` is a unique + perfect power with ``e > 1``, else ``False`` (e.g. 1 is not a perfect power). + + Explanation + =========== + + This is a low-level helper for ``perfect_power``, for internal use. + + Parameters + ========== + + n : int + assume that n is a nonnegative integer + next_p : int + Assume that n has no factor less than next_p. + i.e., all(n % p for p in range(2, next_p)) is True + + Examples + ======== + >>> from sympy.ntheory.factor_ import _perfect_power + >>> _perfect_power(16) + (2, 4) + >>> _perfect_power(17) + False + + """ + if n <= 3: + return False + + factors = {} + g = 0 + multi = 1 + + def done(n, factors, g, multi): + g = gcd(g, multi) + if g == 1: + return False + factors[n] = multi + return math.prod(p**(e//g) for p, e in factors.items()), g + + # If n is small, only trial factoring is faster + if n <= 1_000_000: + n = _factorint_small(factors, n, 1_000, 1_000, next_p)[0] + if n > 1: + return False + g = gcd(*factors.values()) + if g == 1: + return False + return math.prod(p**(e//g) for p, e in factors.items()), g + + # divide by 2 + if next_p < 3: + g = bit_scan1(n) + if g: + if g == 1: + return False + n >>= g + factors[2] = g + if n == 1: + return 2, g + else: + # If `m**g`, then we have found perfect power. + # Otherwise, there is no possibility of perfect power, especially if `g` is prime. + m, _exact = iroot(n, g) + if _exact: + return 2*m, g + elif isprime(g): + return False + next_p = 3 + + # square number? + while n & 7 == 1: # n % 8 == 1: + m, _exact = iroot(n, 2) + if _exact: + n = m + multi <<= 1 + else: + break + if n < next_p**3: + return done(n, factors, g, multi) + + # trial factoring + # Since the maximum value an exponent can take is `log_{next_p}(n)`, + # the number of exponents to be checked can be reduced by performing a trial factoring. + # The value of `tf_max` needs more consideration. + tf_max = n.bit_length()//27 + 24 + if next_p < tf_max: + for p in primerange(next_p, tf_max): + m, t = remove(n, p) + if t: + n = m + t *= multi + _g = gcd(g, t) + if _g == 1: + return False + factors[p] = t + if n == 1: + return math.prod(p**(e//_g) + for p, e in factors.items()), _g + elif g == 0 or _g < g: # If g is updated + g = _g + m, _exact = iroot(n**multi, g) + if _exact: + return m * math.prod(p**(e//g) + for p, e in factors.items()), g + elif isprime(g): + return False + next_p = tf_max + if n < next_p**3: + return done(n, factors, g, multi) + + # check iroot + if g: + # If g is non-zero, the exponent is a divisor of g. + # 2 can be omitted since it has already been checked. + prime_iter = sorted(factorint(g >> bit_scan1(g)).keys()) + else: + # The maximum possible value of the exponent is `log_{next_p}(n)`. + # To compensate for the presence of computational error, 2 is added. + prime_iter = primerange(3, int(math.log(n, next_p)) + 2) + logn = math.log2(n) + threshold = logn / 40 # Threshold for direct calculation + for p in prime_iter: + if threshold < p: + # If p is large, find the power root p directly without `iroot`. + while True: + b = pow(2, logn / p) + rb = int(b + 0.5) + if abs(rb - b) < 0.01 and rb**p == n: + n = rb + multi *= p + logn = math.log2(n) + else: + break + else: + while True: + m, _exact = iroot(n, p) + if _exact: + n = m + multi *= p + logn = math.log2(n) + else: + break + if n < next_p**(p + 2): + break + return done(n, factors, g, multi) + + +def perfect_power(n, candidates=None, big=True, factor=True): + """ + Return ``(b, e)`` such that ``n`` == ``b**e`` if ``n`` is a unique + perfect power with ``e > 1``, else ``False`` (e.g. 1 is not a + perfect power). A ValueError is raised if ``n`` is not Rational. + + By default, the base is recursively decomposed and the exponents + collected so the largest possible ``e`` is sought. If ``big=False`` + then the smallest possible ``e`` (thus prime) will be chosen. + + If ``factor=True`` then simultaneous factorization of ``n`` is + attempted since finding a factor indicates the only possible root + for ``n``. This is True by default since only a few small factors will + be tested in the course of searching for the perfect power. + + The use of ``candidates`` is primarily for internal use; if provided, + False will be returned if ``n`` cannot be written as a power with one + of the candidates as an exponent and factoring (beyond testing for + a factor of 2) will not be attempted. + + Examples + ======== + + >>> from sympy import perfect_power, Rational + >>> perfect_power(16) + (2, 4) + >>> perfect_power(16, big=False) + (4, 2) + + Negative numbers can only have odd perfect powers: + + >>> perfect_power(-4) + False + >>> perfect_power(-8) + (-2, 3) + + Rationals are also recognized: + + >>> perfect_power(Rational(1, 2)**3) + (1/2, 3) + >>> perfect_power(Rational(-3, 2)**3) + (-3/2, 3) + + Notes + ===== + + To know whether an integer is a perfect power of 2 use + + >>> is2pow = lambda n: bool(n and not n & (n - 1)) + >>> [(i, is2pow(i)) for i in range(5)] + [(0, False), (1, True), (2, True), (3, False), (4, True)] + + It is not necessary to provide ``candidates``. When provided + it will be assumed that they are ints. The first one that is + larger than the computed maximum possible exponent will signal + failure for the routine. + + >>> perfect_power(3**8, [9]) + False + >>> perfect_power(3**8, [2, 4, 8]) + (3, 8) + >>> perfect_power(3**8, [4, 8], big=False) + (9, 4) + + See Also + ======== + sympy.core.intfunc.integer_nthroot + sympy.ntheory.primetest.is_square + """ + # negative handling + if n < 0: + if candidates is None: + pp = perfect_power(-n, big=True, factor=factor) + if not pp: + return False + + b, e = pp + e2 = e & (-e) + b, e = b ** e2, e // e2 + + if e <= 1: + return False + + if big or isprime(e): + return -b, e + + for p in primerange(3, e + 1): + if e % p == 0: + return - b ** (e // p), p + + odd_candidates = {i for i in candidates if i % 2} + if not odd_candidates: + return False + + pp = perfect_power(-n, odd_candidates, big, factor) + if pp: + return -pp[0], pp[1] + + return False + + # non-integer handling + if isinstance(n, Rational) and not isinstance(n, Integer): + p, q = n.p, n.q + + if p == 1: + qq = perfect_power(q, candidates, big, factor) + return (S.One / qq[0], qq[1]) if qq is not False else False + + if not (pp:=perfect_power(p, factor=factor)): + return False + if not (qq:=perfect_power(q, factor=factor)): + return False + (num_base, num_exp), (den_base, den_exp) = pp, qq + + def compute_tuple(exponent): + """Helper to compute final result given an exponent""" + new_num = num_base ** (num_exp // exponent) + new_den = den_base ** (den_exp // exponent) + return n.func(new_num, new_den), exponent + + if candidates: + valid_candidates = [i for i in candidates + if num_exp % i == 0 and den_exp % i == 0] + if not valid_candidates: + return False + + e = max(valid_candidates) if big else min(valid_candidates) + return compute_tuple(e) + + g = math.gcd(num_exp, den_exp) + if g == 1: + return False + + if big: + return compute_tuple(g) + + e = next(p for p in primerange(2, g + 1) if g % p == 0) + return compute_tuple(e) + + if candidates is not None: + candidates = set(candidates) + + # positive integer handling + n = as_int(n) + + if candidates is None and big: + return _perfect_power(n) + + if n <= 3: + # no unique exponent for 0, 1 + # 2 and 3 have exponents of 1 + return False + logn = math.log2(n) + max_possible = int(logn) + 2 # only check values less than this + not_square = n % 10 in [2, 3, 7, 8] # squares cannot end in 2, 3, 7, 8 + min_possible = 2 + not_square + if not candidates: + candidates = primerange(min_possible, max_possible) + else: + candidates = sorted([i for i in candidates + if min_possible <= i < max_possible]) + if n%2 == 0: + e = bit_scan1(n) + candidates = [i for i in candidates if e%i == 0] + if big: + candidates = reversed(candidates) + for e in candidates: + r, ok = iroot(n, e) + if ok: + return int(r), e + return False + + def _factors(): + rv = 2 + n % 2 + while True: + yield rv + rv = nextprime(rv) + + for fac, e in zip(_factors(), candidates): + # see if there is a factor present + if factor and n % fac == 0: + # find what the potential power is + e = remove(n, fac)[1] + # if it's a trivial power we are done + if e == 1: + return False + + # maybe the e-th root of n is exact + r, exact = iroot(n, e) + if not exact: + # Having a factor, we know that e is the maximal + # possible value for a root of n. + # If n = fac**e*m can be written as a perfect + # power then see if m can be written as r**E where + # gcd(e, E) != 1 so n = (fac**(e//E)*r)**E + m = n//fac**e + rE = perfect_power(m, candidates=divisors(e, generator=True)) + if not rE: + return False + else: + r, E = rE + r, e = fac**(e//E)*r, E + if not big: + e0 = primefactors(e) + if e0[0] != e: + r, e = r**(e//e0[0]), e0[0] + return int(r), e + + # Weed out downright impossible candidates + if logn/e < 40: + b = 2.0**(logn/e) + if abs(int(b + 0.5) - b) > 0.01: + continue + + # now see if the plausible e makes a perfect power + r, exact = iroot(n, e) + if exact: + if big: + m = perfect_power(r, big=big, factor=factor) + if m: + r, e = m[0], e*m[1] + return int(r), e + + return False + + +class FactorCache(MutableMapping): + """ Provides a cache for prime factors. + ``factor_cache`` is pre-prepared as an instance of ``FactorCache``, + and ``factorint`` internally references it to speed up + the factorization of prime factors. + + While cache is automatically added during the execution of ``factorint``, + users can also manually add prime factors independently. + + >>> from sympy import factor_cache + >>> factor_cache[15] = 5 + + Furthermore, by customizing ``get_external``, + it is also possible to use external databases. + The following is an example using http://factordb.com . + + .. code-block:: python + + import requests + from sympy import factor_cache + + def get_external(self, n: int) -> list[int] | None: + res = requests.get("http://factordb.com/api", params={"query": str(n)}) + if res.status_code != requests.codes.ok: + return None + j = res.json() + if j.get("status") in ["FF", "P"]: + return list(int(p) for p, _ in j.get("factors")) + + factor_cache.get_external = get_external + + Be aware that writing this code will trigger internet access + to factordb.com when calling ``factorint``. + + """ + def __init__(self, maxsize: int | None = None): + self._cache: OrderedDict[int, int] = OrderedDict() + self.maxsize = maxsize + + def __len__(self) -> int: + return len(self._cache) + + def __contains__(self, n) -> bool: + return n in self._cache + + def __getitem__(self, n: int) -> int: + factor = self.get(n) + if factor is None: + raise KeyError(f"{n} does not exist.") + return factor + + def __setitem__(self, n: int, factor: int): + if not (1 < factor <= n and n % factor == 0 and isprime(factor)): + raise ValueError(f"{factor} is not a prime factor of {n}") + self._cache[n] = max(self._cache.get(n, 0), factor) + if self.maxsize is not None and len(self._cache) > self.maxsize: + self._cache.popitem(False) + + def __delitem__(self, n: int): + if n not in self._cache: + raise KeyError(f"{n} does not exist.") + del self._cache[n] + + def __iter__(self): + return self._cache.__iter__() + + def cache_clear(self) -> None: + """ Clear the cache """ + self._cache = OrderedDict() + + @property + def maxsize(self) -> int | None: + """ Returns the maximum cache size; if ``None``, it is unlimited. """ + return self._maxsize + + @maxsize.setter + def maxsize(self, value: int | None) -> None: + if value is not None and value <= 0: + raise ValueError("maxsize must be None or a non-negative integer.") + self._maxsize = value + if value is not None: + while len(self._cache) > value: + self._cache.popitem(False) + + def get(self, n: int, default=None): + """ Return the prime factor of ``n``. + If it does not exist in the cache, return the value of ``default``. + """ + if n <= sieve._list[-1]: + if sieve._list[bisect_left(sieve._list, n)] == n: + return n + if n in self._cache: + self._cache.move_to_end(n) + return self._cache[n] + if factors := self.get_external(n): + self.add(n, factors) + return self._cache[n] + return default + + def add(self, n: int, factors: list[int]) -> None: + for p in sorted(factors, reverse=True): + self[n] = p + n, _ = remove(n, p) + + def get_external(self, n: int) -> list[int] | None: + return None + + +factor_cache = FactorCache(maxsize=1000) + + +def pollard_rho(n, s=2, a=1, retries=5, seed=1234, max_steps=None, F=None): + r""" + Use Pollard's rho method to try to extract a nontrivial factor + of ``n``. The returned factor may be a composite number. If no + factor is found, ``None`` is returned. + + The algorithm generates pseudo-random values of x with a generator + function, replacing x with F(x). If F is not supplied then the + function x**2 + ``a`` is used. The first value supplied to F(x) is ``s``. + Upon failure (if ``retries`` is > 0) a new ``a`` and ``s`` will be + supplied; the ``a`` will be ignored if F was supplied. + + The sequence of numbers generated by such functions generally have a + a lead-up to some number and then loop around back to that number and + begin to repeat the sequence, e.g. 1, 2, 3, 4, 5, 3, 4, 5 -- this leader + and loop look a bit like the Greek letter rho, and thus the name, 'rho'. + + For a given function, very different leader-loop values can be obtained + so it is a good idea to allow for retries: + + >>> from sympy.ntheory.generate import cycle_length + >>> n = 16843009 + >>> F = lambda x:(2048*pow(x, 2, n) + 32767) % n + >>> for s in range(5): + ... print('loop length = %4i; leader length = %3i' % next(cycle_length(F, s))) + ... + loop length = 2489; leader length = 43 + loop length = 78; leader length = 121 + loop length = 1482; leader length = 100 + loop length = 1482; leader length = 286 + loop length = 1482; leader length = 101 + + Here is an explicit example where there is a three element leadup to + a sequence of 3 numbers (11, 14, 4) that then repeat: + + >>> x=2 + >>> for i in range(9): + ... print(x) + ... x=(x**2+12)%17 + ... + 2 + 16 + 13 + 11 + 14 + 4 + 11 + 14 + 4 + >>> next(cycle_length(lambda x: (x**2+12)%17, 2)) + (3, 3) + >>> list(cycle_length(lambda x: (x**2+12)%17, 2, values=True)) + [2, 16, 13, 11, 14, 4] + + Instead of checking the differences of all generated values for a gcd + with n, only the kth and 2*kth numbers are checked, e.g. 1st and 2nd, + 2nd and 4th, 3rd and 6th until it has been detected that the loop has been + traversed. Loops may be many thousands of steps long before rho finds a + factor or reports failure. If ``max_steps`` is specified, the iteration + is cancelled with a failure after the specified number of steps. + + Examples + ======== + + >>> from sympy import pollard_rho + >>> n=16843009 + >>> F=lambda x:(2048*pow(x,2,n) + 32767) % n + >>> pollard_rho(n, F=F) + 257 + + Use the default setting with a bad value of ``a`` and no retries: + + >>> pollard_rho(n, a=n-2, retries=0) + + If retries is > 0 then perhaps the problem will correct itself when + new values are generated for a: + + >>> pollard_rho(n, a=n-2, retries=1) + 257 + + References + ========== + + .. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers: + A Computational Perspective", Springer, 2nd edition, 229-231 + + """ + n = int(n) + if n < 5: + raise ValueError('pollard_rho should receive n > 4') + randint = _randint(seed + retries) + V = s + for i in range(retries + 1): + U = V + if not F: + F = lambda x: (pow(x, 2, n) + a) % n + j = 0 + while 1: + if max_steps and (j > max_steps): + break + j += 1 + U = F(U) + V = F(F(V)) # V is 2x further along than U + g = gcd(U - V, n) + if g == 1: + continue + if g == n: + break + return int(g) + V = randint(0, n - 1) + a = randint(1, n - 3) # for x**2 + a, a%n should not be 0 or -2 + F = None + return None + + +def pollard_pm1(n, B=10, a=2, retries=0, seed=1234): + """ + Use Pollard's p-1 method to try to extract a nontrivial factor + of ``n``. Either a divisor (perhaps composite) or ``None`` is returned. + + The value of ``a`` is the base that is used in the test gcd(a**M - 1, n). + The default is 2. If ``retries`` > 0 then if no factor is found after the + first attempt, a new ``a`` will be generated randomly (using the ``seed``) + and the process repeated. + + Note: the value of M is lcm(1..B) = reduce(ilcm, range(2, B + 1)). + + A search is made for factors next to even numbers having a power smoothness + less than ``B``. Choosing a larger B increases the likelihood of finding a + larger factor but takes longer. Whether a factor of n is found or not + depends on ``a`` and the power smoothness of the even number just less than + the factor p (hence the name p - 1). + + Although some discussion of what constitutes a good ``a`` some + descriptions are hard to interpret. At the modular.math site referenced + below it is stated that if gcd(a**M - 1, n) = N then a**M % q**r is 1 + for every prime power divisor of N. But consider the following: + + >>> from sympy.ntheory.factor_ import smoothness_p, pollard_pm1 + >>> n=257*1009 + >>> smoothness_p(n) + (-1, [(257, (1, 2, 256)), (1009, (1, 7, 16))]) + + So we should (and can) find a root with B=16: + + >>> pollard_pm1(n, B=16, a=3) + 1009 + + If we attempt to increase B to 256 we find that it does not work: + + >>> pollard_pm1(n, B=256) + >>> + + But if the value of ``a`` is changed we find that only multiples of + 257 work, e.g.: + + >>> pollard_pm1(n, B=256, a=257) + 1009 + + Checking different ``a`` values shows that all the ones that did not + work had a gcd value not equal to ``n`` but equal to one of the + factors: + + >>> from sympy import ilcm, igcd, factorint, Pow + >>> M = 1 + >>> for i in range(2, 256): + ... M = ilcm(M, i) + ... + >>> set([igcd(pow(a, M, n) - 1, n) for a in range(2, 256) if + ... igcd(pow(a, M, n) - 1, n) != n]) + {1009} + + But does aM % d for every divisor of n give 1? + + >>> aM = pow(255, M, n) + >>> [(d, aM%Pow(*d.args)) for d in factorint(n, visual=True).args] + [(257**1, 1), (1009**1, 1)] + + No, only one of them. So perhaps the principle is that a root will + be found for a given value of B provided that: + + 1) the power smoothness of the p - 1 value next to the root + does not exceed B + 2) a**M % p != 1 for any of the divisors of n. + + By trying more than one ``a`` it is possible that one of them + will yield a factor. + + Examples + ======== + + With the default smoothness bound, this number cannot be cracked: + + >>> from sympy.ntheory import pollard_pm1 + >>> pollard_pm1(21477639576571) + + Increasing the smoothness bound helps: + + >>> pollard_pm1(21477639576571, B=2000) + 4410317 + + Looking at the smoothness of the factors of this number we find: + + >>> from sympy.ntheory.factor_ import smoothness_p, factorint + >>> print(smoothness_p(21477639576571, visual=1)) + p**i=4410317**1 has p-1 B=1787, B-pow=1787 + p**i=4869863**1 has p-1 B=2434931, B-pow=2434931 + + The B and B-pow are the same for the p - 1 factorizations of the divisors + because those factorizations had a very large prime factor: + + >>> factorint(4410317 - 1) + {2: 2, 617: 1, 1787: 1} + >>> factorint(4869863-1) + {2: 1, 2434931: 1} + + Note that until B reaches the B-pow value of 1787, the number is not cracked; + + >>> pollard_pm1(21477639576571, B=1786) + >>> pollard_pm1(21477639576571, B=1787) + 4410317 + + The B value has to do with the factors of the number next to the divisor, + not the divisors themselves. A worst case scenario is that the number next + to the factor p has a large prime divisisor or is a perfect power. If these + conditions apply then the power-smoothness will be about p/2 or p. The more + realistic is that there will be a large prime factor next to p requiring + a B value on the order of p/2. Although primes may have been searched for + up to this level, the p/2 is a factor of p - 1, something that we do not + know. The modular.math reference below states that 15% of numbers in the + range of 10**15 to 15**15 + 10**4 are 10**6 power smooth so a B of 10**6 + will fail 85% of the time in that range. From 10**8 to 10**8 + 10**3 the + percentages are nearly reversed...but in that range the simple trial + division is quite fast. + + References + ========== + + .. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers: + A Computational Perspective", Springer, 2nd edition, 236-238 + .. [2] https://web.archive.org/web/20150716201437/http://modular.math.washington.edu/edu/2007/spring/ent/ent-html/node81.html + .. [3] https://www.cs.toronto.edu/~yuvalf/Factorization.pdf + """ + + n = int(n) + if n < 4 or B < 3: + raise ValueError('pollard_pm1 should receive n > 3 and B > 2') + randint = _randint(seed + B) + + # computing a**lcm(1,2,3,..B) % n for B > 2 + # it looks weird, but it's right: primes run [2, B] + # and the answer's not right until the loop is done. + for i in range(retries + 1): + aM = a + for p in sieve.primerange(2, B + 1): + e = int(math.log(B, p)) + aM = pow(aM, pow(p, e), n) + g = gcd(aM - 1, n) + if 1 < g < n: + return int(g) + + # get a new a: + # since the exponent, lcm(1..B), is even, if we allow 'a' to be 'n-1' + # then (n - 1)**even % n will be 1 which will give a g of 0 and 1 will + # give a zero, too, so we set the range as [2, n-2]. Some references + # say 'a' should be coprime to n, but either will detect factors. + a = randint(2, n - 2) + + +def _trial(factors, n, candidates, verbose=False): + """ + Helper function for integer factorization. Trial factors ``n` + against all integers given in the sequence ``candidates`` + and updates the dict ``factors`` in-place. Returns the reduced + value of ``n`` and a flag indicating whether any factors were found. + """ + if verbose: + factors0 = list(factors.keys()) + nfactors = len(factors) + for d in candidates: + if n % d == 0: + if n != d: + factor_cache[n] = d + n, m = remove(n // d, d) + factors[d] = m + 1 + if verbose: + for k in sorted(set(factors).difference(set(factors0))): + print(factor_msg % (k, factors[k])) + return int(n), len(factors) != nfactors + + +def _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, + verbose, next_p): + """ + Helper function for integer factorization. Checks if ``n`` + is a prime or a perfect power, and in those cases updates the factorization. + """ + if verbose: + print('Check for termination') + if n == 1: + if verbose: + print(complete_msg) + return True + if n < next_p**2 or isprime(n): + factor_cache[n] = n + factors[int(n)] = 1 + if verbose: + print(complete_msg) + return True + + # since we've already been factoring there is no need to do + # simultaneous factoring with the power check + p = _perfect_power(n, next_p) + if not p: + return False + base, exp = p + if base < next_p**2 or isprime(base): + factor_cache[n] = base + factors[base] = exp + else: + facs = factorint(base, limit, use_trial, use_rho, use_pm1, + verbose=False) + for b, e in facs.items(): + if verbose: + print(factor_msg % (b, e)) + factors[b] = exp*e + if verbose: + print(complete_msg) + return True + + +trial_int_msg = "Trial division with ints [%i ... %i] and fail_max=%i" +trial_msg = "Trial division with primes [%i ... %i]" +rho_msg = "Pollard's rho with retries %i, max_steps %i and seed %i" +pm1_msg = "Pollard's p-1 with smoothness bound %i and seed %i" +ecm_msg = "Elliptic Curve with B1 bound %i, B2 bound %i, num_curves %i" +factor_msg = '\t%i ** %i' +fermat_msg = 'Close factors satisfying Fermat condition found.' +complete_msg = 'Factorization is complete.' + + +def _factorint_small(factors, n, limit, fail_max, next_p=2): + """ + Return the value of n and either a 0 (indicating that factorization up + to the limit was complete) or else the next near-prime that would have + been tested. + + Factoring stops if there are fail_max unsuccessful tests in a row. + + If factors of n were found they will be in the factors dictionary as + {factor: multiplicity} and the returned value of n will have had those + factors removed. The factors dictionary is modified in-place. + + """ + + def done(n, d): + """return n, d if the sqrt(n) was not reached yet, else + n, 0 indicating that factoring is done. + """ + if d*d <= n: + return n, d + return n, 0 + + limit2 = limit**2 + threshold2 = min(n, limit2) + + if next_p < 3: + if not n & 1: + m = bit_scan1(n) + factors[2] = m + n >>= m + threshold2 = min(n, limit2) + next_p = 3 + if threshold2 < 9: # next_p**2 = 9 + return done(n, next_p) + + if next_p < 5: + if not n % 3: + n //= 3 + m = 1 + while not n % 3: + n //= 3 + m += 1 + if m == 20: + n, mm = remove(n, 3) + m += mm + break + factors[3] = m + threshold2 = min(n, limit2) + next_p = 5 + if threshold2 < 25: # next_p**2 = 25 + return done(n, next_p) + + # Because of the order of checks, starting from `min_p = 6k+5`, + # useless checks are caused. + # We want to calculate + # next_p += [-1, -2, 3, 2, 1, 0][next_p % 6] + p6 = next_p % 6 + next_p += (-1 if p6 < 2 else 5) - p6 + + fails = 0 + while fails < fail_max: + # next_p % 6 == 5 + if n % next_p: + fails += 1 + else: + n //= next_p + m = 1 + while not n % next_p: + n //= next_p + m += 1 + if m == 20: + n, mm = remove(n, next_p) + m += mm + break + factors[next_p] = m + fails = 0 + threshold2 = min(n, limit2) + next_p += 2 + if threshold2 < next_p**2: + return done(n, next_p) + + # next_p % 6 == 1 + if n % next_p: + fails += 1 + else: + n //= next_p + m = 1 + while not n % next_p: + n //= next_p + m += 1 + if m == 20: + n, mm = remove(n, next_p) + m += mm + break + factors[next_p] = m + fails = 0 + threshold2 = min(n, limit2) + next_p += 4 + if threshold2 < next_p**2: + return done(n, next_p) + return done(n, next_p) + + +def factorint(n, limit=None, use_trial=True, use_rho=True, use_pm1=True, + use_ecm=True, verbose=False, visual=None, multiple=False): + r""" + Given a positive integer ``n``, ``factorint(n)`` returns a dict containing + the prime factors of ``n`` as keys and their respective multiplicities + as values. For example: + + >>> from sympy.ntheory import factorint + >>> factorint(2000) # 2000 = (2**4) * (5**3) + {2: 4, 5: 3} + >>> factorint(65537) # This number is prime + {65537: 1} + + For input less than 2, factorint behaves as follows: + + - ``factorint(1)`` returns the empty factorization, ``{}`` + - ``factorint(0)`` returns ``{0:1}`` + - ``factorint(-n)`` adds ``-1:1`` to the factors and then factors ``n`` + + Partial Factorization: + + If ``limit`` (> 3) is specified, the search is stopped after performing + trial division up to (and including) the limit (or taking a + corresponding number of rho/p-1 steps). This is useful if one has + a large number and only is interested in finding small factors (if + any). Note that setting a limit does not prevent larger factors + from being found early; it simply means that the largest factor may + be composite. Since checking for perfect power is relatively cheap, it is + done regardless of the limit setting. + + This number, for example, has two small factors and a huge + semi-prime factor that cannot be reduced easily: + + >>> from sympy.ntheory import isprime + >>> a = 1407633717262338957430697921446883 + >>> f = factorint(a, limit=10000) + >>> f == {991: 1, int(202916782076162456022877024859): 1, 7: 1} + True + >>> isprime(max(f)) + False + + This number has a small factor and a residual perfect power whose + base is greater than the limit: + + >>> factorint(3*101**7, limit=5) + {3: 1, 101: 7} + + List of Factors: + + If ``multiple`` is set to ``True`` then a list containing the + prime factors including multiplicities is returned. + + >>> factorint(24, multiple=True) + [2, 2, 2, 3] + + Visual Factorization: + + If ``visual`` is set to ``True``, then it will return a visual + factorization of the integer. For example: + + >>> from sympy import pprint + >>> pprint(factorint(4200, visual=True)) + 3 1 2 1 + 2 *3 *5 *7 + + Note that this is achieved by using the evaluate=False flag in Mul + and Pow. If you do other manipulations with an expression where + evaluate=False, it may evaluate. Therefore, you should use the + visual option only for visualization, and use the normal dictionary + returned by visual=False if you want to perform operations on the + factors. + + You can easily switch between the two forms by sending them back to + factorint: + + >>> from sympy import Mul + >>> regular = factorint(1764); regular + {2: 2, 3: 2, 7: 2} + >>> pprint(factorint(regular)) + 2 2 2 + 2 *3 *7 + + >>> visual = factorint(1764, visual=True); pprint(visual) + 2 2 2 + 2 *3 *7 + >>> print(factorint(visual)) + {2: 2, 3: 2, 7: 2} + + If you want to send a number to be factored in a partially factored form + you can do so with a dictionary or unevaluated expression: + + >>> factorint(factorint({4: 2, 12: 3})) # twice to toggle to dict form + {2: 10, 3: 3} + >>> factorint(Mul(4, 12, evaluate=False)) + {2: 4, 3: 1} + + The table of the output logic is: + + ====== ====== ======= ======= + Visual + ------ ---------------------- + Input True False other + ====== ====== ======= ======= + dict mul dict mul + n mul dict dict + mul mul dict dict + ====== ====== ======= ======= + + Notes + ===== + + Algorithm: + + The function switches between multiple algorithms. Trial division + quickly finds small factors (of the order 1-5 digits), and finds + all large factors if given enough time. The Pollard rho and p-1 + algorithms are used to find large factors ahead of time; they + will often find factors of the order of 10 digits within a few + seconds: + + >>> factors = factorint(12345678910111213141516) + >>> for base, exp in sorted(factors.items()): + ... print('%s %s' % (base, exp)) + ... + 2 2 + 2507191691 1 + 1231026625769 1 + + Any of these methods can optionally be disabled with the following + boolean parameters: + + - ``use_trial``: Toggle use of trial division + - ``use_rho``: Toggle use of Pollard's rho method + - ``use_pm1``: Toggle use of Pollard's p-1 method + + ``factorint`` also periodically checks if the remaining part is + a prime number or a perfect power, and in those cases stops. + + For unevaluated factorial, it uses Legendre's formula(theorem). + + + If ``verbose`` is set to ``True``, detailed progress is printed. + + See Also + ======== + + smoothness, smoothness_p, divisors + + """ + if isinstance(n, Dict): + n = dict(n) + if multiple: + fac = factorint(n, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose, visual=False, multiple=False) + factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p]) + for p in sorted(fac)), []) + return factorlist + + factordict = {} + if visual and not isinstance(n, (Mul, dict)): + factordict = factorint(n, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose, visual=False) + elif isinstance(n, Mul): + factordict = {int(k): int(v) for k, v in + n.as_powers_dict().items()} + elif isinstance(n, dict): + factordict = n + if factordict and isinstance(n, (Mul, dict)): + # check it + for key in list(factordict.keys()): + if isprime(key): + continue + e = factordict.pop(key) + d = factorint(key, limit=limit, use_trial=use_trial, use_rho=use_rho, + use_pm1=use_pm1, verbose=verbose, visual=False) + for k, v in d.items(): + if k in factordict: + factordict[k] += v*e + else: + factordict[k] = v*e + if visual or (type(n) is dict and + visual is not True and + visual is not False): + if factordict == {}: + return S.One + if -1 in factordict: + factordict.pop(-1) + args = [S.NegativeOne] + else: + args = [] + args.extend([Pow(*i, evaluate=False) + for i in sorted(factordict.items())]) + return Mul(*args, evaluate=False) + elif isinstance(n, (dict, Mul)): + return factordict + + assert use_trial or use_rho or use_pm1 or use_ecm + + from sympy.functions.combinatorial.factorials import factorial + if isinstance(n, factorial): + x = as_int(n.args[0]) + if x >= 20: + factors = {} + m = 2 # to initialize the if condition below + for p in sieve.primerange(2, x + 1): + if m > 1: + m, q = 0, x // p + while q != 0: + m += q + q //= p + factors[p] = m + if factors and verbose: + for k in sorted(factors): + print(factor_msg % (k, factors[k])) + if verbose: + print(complete_msg) + return factors + else: + # if n < 20!, direct computation is faster + # since it uses a lookup table + n = n.func(x) + + n = as_int(n) + if limit: + limit = int(limit) + use_ecm = False + + # special cases + if n < 0: + factors = factorint( + -n, limit=limit, use_trial=use_trial, use_rho=use_rho, + use_pm1=use_pm1, verbose=verbose, visual=False) + factors[-1] = 1 + return factors + + if limit and limit < 2: + if n == 1: + return {} + return {n: 1} + elif n < 10: + # doing this we are assured of getting a limit > 2 + # when we have to compute it later + return [{0: 1}, {}, {2: 1}, {3: 1}, {2: 2}, {5: 1}, + {2: 1, 3: 1}, {7: 1}, {2: 3}, {3: 2}][n] + + factors = {} + + # do simplistic factorization + if verbose: + sn = str(n) + if len(sn) > 50: + print('Factoring %s' % sn[:5] + \ + '..(%i other digits)..' % (len(sn) - 10) + sn[-5:]) + else: + print('Factoring', n) + + # this is the preliminary factorization for small factors + # We want to guarantee that there are no small prime factors, + # so we run even if `use_trial` is False. + small = 2**15 + fail_max = 600 + small = min(small, limit or small) + if verbose: + print(trial_int_msg % (2, small, fail_max)) + n, next_p = _factorint_small(factors, n, small, fail_max) + if factors and verbose: + for k in sorted(factors): + print(factor_msg % (k, factors[k])) + if next_p == 0: + if n > 1: + factors[int(n)] = 1 + if verbose: + print(complete_msg) + return factors + # Check if it exists in the cache + while p := factor_cache.get(n): + n, e = remove(n, p) + factors[int(p)] = int(e) + # first check if the simplistic run didn't finish + # because of the limit and check for a perfect + # power before exiting + if limit and next_p > limit: + if verbose: + print('Exceeded limit:', limit) + if _check_termination(factors, n, limit, use_trial, + use_rho, use_pm1, verbose, next_p): + return factors + if n > 1: + factors[int(n)] = 1 + return factors + if _check_termination(factors, n, limit, use_trial, + use_rho, use_pm1, verbose, next_p): + return factors + + # continue with more advanced factorization methods + # ...do a Fermat test since it's so easy and we need the + # square root anyway. Finding 2 factors is easy if they are + # "close enough." This is the big root equivalent of dividing by + # 2, 3, 5. + sqrt_n = isqrt(n) + a = sqrt_n + 1 + # If `n % 4 == 1`, `a` must be odd for `a**2 - n` to be a square number. + if (n % 4 == 1) ^ (a & 1): + a += 1 + a2 = a**2 + b2 = a2 - n + for _ in range(3): + b, fermat = sqrtrem(b2) + if not fermat: + if verbose: + print(fermat_msg) + for r in [a - b, a + b]: + facs = factorint(r, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose) + for k, v in facs.items(): + factors[k] = factors.get(k, 0) + v + factor_cache.add(n, facs) + if verbose: + print(complete_msg) + return factors + b2 += (a + 1) << 2 # equiv to (a + 2)**2 - n + a += 2 + + # these are the limits for trial division which will + # be attempted in parallel with pollard methods + low, high = next_p, 2*next_p + + # add 1 to make sure limit is reached in primerange calls + _limit = (limit or sqrt_n) + 1 + iteration = 0 + while 1: + high_ = min(high, _limit) + + # Trial division + if use_trial: + if verbose: + print(trial_msg % (low, high_)) + ps = sieve.primerange(low, high_) + n, found_trial = _trial(factors, n, ps, verbose) + next_p = high_ + if found_trial and _check_termination(factors, n, limit, use_trial, + use_rho, use_pm1, verbose, next_p): + return factors + else: + found_trial = False + + if high > _limit: + if verbose: + print('Exceeded limit:', _limit) + if n > 1: + factors[int(n)] = 1 + if verbose: + print(complete_msg) + return factors + + # Only used advanced methods when no small factors were found + if not found_trial: + # Pollard p-1 + if use_pm1: + if verbose: + print(pm1_msg % (low, high_)) + c = pollard_pm1(n, B=low, seed=high_) + if c: + if c < next_p**2 or isprime(c): + ps = [c] + else: + ps = factorint(c, limit=limit, + use_trial=use_trial, + use_rho=use_rho, + use_pm1=use_pm1, + use_ecm=use_ecm, + verbose=verbose) + n, _ = _trial(factors, n, ps, verbose=False) + if _check_termination(factors, n, limit, use_trial, + use_rho, use_pm1, verbose, next_p): + return factors + + # Pollard rho + if use_rho: + if verbose: + print(rho_msg % (1, low, high_)) + c = pollard_rho(n, retries=1, max_steps=low, seed=high_) + if c: + if c < next_p**2 or isprime(c): + ps = [c] + else: + ps = factorint(c, limit=limit, + use_trial=use_trial, + use_rho=use_rho, + use_pm1=use_pm1, + use_ecm=use_ecm, + verbose=verbose) + n, _ = _trial(factors, n, ps, verbose=False) + if _check_termination(factors, n, limit, use_trial, + use_rho, use_pm1, verbose, next_p): + return factors + # Use subexponential algorithms if use_ecm + # Use pollard algorithms for finding small factors for 3 iterations + # if after small factors the number of digits of n >= 25 then use ecm + iteration += 1 + if use_ecm and iteration >= 3 and num_digits(n) >= 24: + break + low, high = high, high*2 + + B1 = 10000 + B2 = 100*B1 + num_curves = 50 + while(1): + if verbose: + print(ecm_msg % (B1, B2, num_curves)) + factor = _ecm_one_factor(n, B1, B2, num_curves, seed=B1) + if factor: + if factor < next_p**2 or isprime(factor): + ps = [factor] + else: + ps = factorint(factor, limit=limit, + use_trial=use_trial, + use_rho=use_rho, + use_pm1=use_pm1, + use_ecm=use_ecm, + verbose=verbose) + n, _ = _trial(factors, n, ps, verbose=False) + if _check_termination(factors, n, limit, use_trial, + use_rho, use_pm1, verbose, next_p): + return factors + B1 *= 5 + B2 = 100*B1 + num_curves *= 4 + + +def factorrat(rat, limit=None, use_trial=True, use_rho=True, use_pm1=True, + verbose=False, visual=None, multiple=False): + r""" + Given a Rational ``r``, ``factorrat(r)`` returns a dict containing + the prime factors of ``r`` as keys and their respective multiplicities + as values. For example: + + >>> from sympy import factorrat, S + >>> factorrat(S(8)/9) # 8/9 = (2**3) * (3**-2) + {2: 3, 3: -2} + >>> factorrat(S(-1)/987) # -1/789 = -1 * (3**-1) * (7**-1) * (47**-1) + {-1: 1, 3: -1, 7: -1, 47: -1} + + Please see the docstring for ``factorint`` for detailed explanations + and examples of the following keywords: + + - ``limit``: Integer limit up to which trial division is done + - ``use_trial``: Toggle use of trial division + - ``use_rho``: Toggle use of Pollard's rho method + - ``use_pm1``: Toggle use of Pollard's p-1 method + - ``verbose``: Toggle detailed printing of progress + - ``multiple``: Toggle returning a list of factors or dict + - ``visual``: Toggle product form of output + """ + if multiple: + fac = factorrat(rat, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose, visual=False, multiple=False) + factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p]) + for p, _ in sorted(fac.items(), + key=lambda elem: elem[0] + if elem[1] > 0 + else 1/elem[0])), []) + return factorlist + + f = factorint(rat.p, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose).copy() + f = defaultdict(int, f) + for p, e in factorint(rat.q, limit=limit, + use_trial=use_trial, + use_rho=use_rho, + use_pm1=use_pm1, + verbose=verbose).items(): + f[p] += -e + + if len(f) > 1 and 1 in f: + del f[1] + if not visual: + return dict(f) + else: + if -1 in f: + f.pop(-1) + args = [S.NegativeOne] + else: + args = [] + args.extend([Pow(*i, evaluate=False) + for i in sorted(f.items())]) + return Mul(*args, evaluate=False) + + +def primefactors(n, limit=None, verbose=False, **kwargs): + """Return a sorted list of n's prime factors, ignoring multiplicity + and any composite factor that remains if the limit was set too low + for complete factorization. Unlike factorint(), primefactors() does + not return -1 or 0. + + Parameters + ========== + + n : integer + limit, verbose, **kwargs : + Additional keyword arguments to be passed to ``factorint``. + Since ``kwargs`` is new in version 1.13, + ``limit`` and ``verbose`` are retained for compatibility purposes. + + Returns + ======= + + list(int) : List of prime numbers dividing ``n`` + + Examples + ======== + + >>> from sympy.ntheory import primefactors, factorint, isprime + >>> primefactors(6) + [2, 3] + >>> primefactors(-5) + [5] + + >>> sorted(factorint(123456).items()) + [(2, 6), (3, 1), (643, 1)] + >>> primefactors(123456) + [2, 3, 643] + + >>> sorted(factorint(10000000001, limit=200).items()) + [(101, 1), (99009901, 1)] + >>> isprime(99009901) + False + >>> primefactors(10000000001, limit=300) + [101] + + See Also + ======== + + factorint, divisors + + """ + n = int(n) + kwargs.update({"visual": None, "multiple": False, + "limit": limit, "verbose": verbose}) + factors = sorted(factorint(n=n, **kwargs).keys()) + # We want to calculate + # s = [f for f in factors if isprime(f)] + s = [f for f in factors[:-1:] if f not in [-1, 0, 1]] + if factors and isprime(factors[-1]): + s += [factors[-1]] + return s + + +def _divisors(n, proper=False): + """Helper function for divisors which generates the divisors. + + Parameters + ========== + + n : int + a nonnegative integer + proper: bool + If `True`, returns the generator that outputs only the proper divisor (i.e., excluding n). + + """ + if n <= 1: + if not proper and n: + yield 1 + return + + factordict = factorint(n) + ps = sorted(factordict.keys()) + + def rec_gen(n=0): + if n == len(ps): + yield 1 + else: + pows = [1] + for _ in range(factordict[ps[n]]): + pows.append(pows[-1] * ps[n]) + yield from (p * q for q in rec_gen(n + 1) for p in pows) + + if proper: + yield from (p for p in rec_gen() if p != n) + else: + yield from rec_gen() + + +def divisors(n, generator=False, proper=False): + r""" + Return all divisors of n sorted from 1..n by default. + If generator is ``True`` an unordered generator is returned. + + The number of divisors of n can be quite large if there are many + prime factors (counting repeated factors). If only the number of + factors is desired use divisor_count(n). + + Examples + ======== + + >>> from sympy import divisors, divisor_count + >>> divisors(24) + [1, 2, 3, 4, 6, 8, 12, 24] + >>> divisor_count(24) + 8 + + >>> list(divisors(120, generator=True)) + [1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60, 120] + + Notes + ===== + + This is a slightly modified version of Tim Peters referenced at: + https://stackoverflow.com/questions/1010381/python-factorization + + See Also + ======== + + primefactors, factorint, divisor_count + """ + rv = _divisors(as_int(abs(n)), proper) + return rv if generator else sorted(rv) + + +def divisor_count(n, modulus=1, proper=False): + """ + Return the number of divisors of ``n``. If ``modulus`` is not 1 then only + those that are divisible by ``modulus`` are counted. If ``proper`` is True + then the divisor of ``n`` will not be counted. + + Examples + ======== + + >>> from sympy import divisor_count + >>> divisor_count(6) + 4 + >>> divisor_count(6, 2) + 2 + >>> divisor_count(6, proper=True) + 3 + + See Also + ======== + + factorint, divisors, totient, proper_divisor_count + + """ + + if not modulus: + return 0 + elif modulus != 1: + n, r = divmod(n, modulus) + if r: + return 0 + if n == 0: + return 0 + n = Mul(*[v + 1 for k, v in factorint(n).items() if k > 1]) + if n and proper: + n -= 1 + return n + + +def proper_divisors(n, generator=False): + """ + Return all divisors of n except n, sorted by default. + If generator is ``True`` an unordered generator is returned. + + Examples + ======== + + >>> from sympy import proper_divisors, proper_divisor_count + >>> proper_divisors(24) + [1, 2, 3, 4, 6, 8, 12] + >>> proper_divisor_count(24) + 7 + >>> list(proper_divisors(120, generator=True)) + [1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60] + + See Also + ======== + + factorint, divisors, proper_divisor_count + + """ + return divisors(n, generator=generator, proper=True) + + +def proper_divisor_count(n, modulus=1): + """ + Return the number of proper divisors of ``n``. + + Examples + ======== + + >>> from sympy import proper_divisor_count + >>> proper_divisor_count(6) + 3 + >>> proper_divisor_count(6, modulus=2) + 1 + + See Also + ======== + + divisors, proper_divisors, divisor_count + + """ + return divisor_count(n, modulus=modulus, proper=True) + + +def _udivisors(n): + """Helper function for udivisors which generates the unitary divisors. + + Parameters + ========== + + n : int + a nonnegative integer + + """ + if n <= 1: + if n == 1: + yield 1 + return + + factorpows = [p**e for p, e in factorint(n).items()] + # We want to calculate + # yield from (math.prod(s) for s in powersets(factorpows)) + for i in range(2**len(factorpows)): + d = 1 + for k in range(i.bit_length()): + if i & 1: + d *= factorpows[k] + i >>= 1 + yield d + + +def udivisors(n, generator=False): + r""" + Return all unitary divisors of n sorted from 1..n by default. + If generator is ``True`` an unordered generator is returned. + + The number of unitary divisors of n can be quite large if there are many + prime factors. If only the number of unitary divisors is desired use + udivisor_count(n). + + Examples + ======== + + >>> from sympy.ntheory.factor_ import udivisors, udivisor_count + >>> udivisors(15) + [1, 3, 5, 15] + >>> udivisor_count(15) + 4 + + >>> sorted(udivisors(120, generator=True)) + [1, 3, 5, 8, 15, 24, 40, 120] + + See Also + ======== + + primefactors, factorint, divisors, divisor_count, udivisor_count + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Unitary_divisor + .. [2] https://mathworld.wolfram.com/UnitaryDivisor.html + + """ + rv = _udivisors(as_int(abs(n))) + return rv if generator else sorted(rv) + + +def udivisor_count(n): + """ + Return the number of unitary divisors of ``n``. + + Parameters + ========== + + n : integer + + Examples + ======== + + >>> from sympy.ntheory.factor_ import udivisor_count + >>> udivisor_count(120) + 8 + + See Also + ======== + + factorint, divisors, udivisors, divisor_count, totient + + References + ========== + + .. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html + + """ + + if n == 0: + return 0 + return 2**len([p for p in factorint(n) if p > 1]) + + +def _antidivisors(n): + """Helper function for antidivisors which generates the antidivisors. + + Parameters + ========== + + n : int + a nonnegative integer + + """ + if n <= 2: + return + for d in _divisors(n): + y = 2*d + if n > y and n % y: + yield y + for d in _divisors(2*n-1): + if n > d >= 2 and n % d: + yield d + for d in _divisors(2*n+1): + if n > d >= 2 and n % d: + yield d + + +def antidivisors(n, generator=False): + r""" + Return all antidivisors of n sorted from 1..n by default. + + Antidivisors [1]_ of n are numbers that do not divide n by the largest + possible margin. If generator is True an unordered generator is returned. + + Examples + ======== + + >>> from sympy.ntheory.factor_ import antidivisors + >>> antidivisors(24) + [7, 16] + + >>> sorted(antidivisors(128, generator=True)) + [3, 5, 15, 17, 51, 85] + + See Also + ======== + + primefactors, factorint, divisors, divisor_count, antidivisor_count + + References + ========== + + .. [1] definition is described in https://oeis.org/A066272/a066272a.html + + """ + rv = _antidivisors(as_int(abs(n))) + return rv if generator else sorted(rv) + + +def antidivisor_count(n): + """ + Return the number of antidivisors [1]_ of ``n``. + + Parameters + ========== + + n : integer + + Examples + ======== + + >>> from sympy.ntheory.factor_ import antidivisor_count + >>> antidivisor_count(13) + 4 + >>> antidivisor_count(27) + 5 + + See Also + ======== + + factorint, divisors, antidivisors, divisor_count, totient + + References + ========== + + .. [1] formula from https://oeis.org/A066272 + + """ + + n = as_int(abs(n)) + if n <= 2: + return 0 + return divisor_count(2*n - 1) + divisor_count(2*n + 1) + \ + divisor_count(n) - divisor_count(n, 2) - 5 + +@deprecated("""\ +The `sympy.ntheory.factor_.totient` has been moved to `sympy.functions.combinatorial.numbers.totient`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def totient(n): + r""" + Calculate the Euler totient function phi(n) + + .. deprecated:: 1.13 + + The ``totient`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.totient` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + ``totient(n)`` or `\phi(n)` is the number of positive integers `\leq` n + that are relatively prime to n. + + Parameters + ========== + + n : integer + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import totient + >>> totient(1) + 1 + >>> totient(25) + 20 + >>> totient(45) == totient(5)*totient(9) + True + + See Also + ======== + + divisor_count + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Euler%27s_totient_function + .. [2] https://mathworld.wolfram.com/TotientFunction.html + + """ + from sympy.functions.combinatorial.numbers import totient as _totient + return _totient(n) + + +@deprecated("""\ +The `sympy.ntheory.factor_.reduced_totient` has been moved to `sympy.functions.combinatorial.numbers.reduced_totient`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def reduced_totient(n): + r""" + Calculate the Carmichael reduced totient function lambda(n) + + .. deprecated:: 1.13 + + The ``reduced_totient`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.reduced_totient` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + ``reduced_totient(n)`` or `\lambda(n)` is the smallest m > 0 such that + `k^m \equiv 1 \mod n` for all k relatively prime to n. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import reduced_totient + >>> reduced_totient(1) + 1 + >>> reduced_totient(8) + 2 + >>> reduced_totient(30) + 4 + + See Also + ======== + + totient + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Carmichael_function + .. [2] https://mathworld.wolfram.com/CarmichaelFunction.html + + """ + from sympy.functions.combinatorial.numbers import reduced_totient as _reduced_totient + return _reduced_totient(n) + + +@deprecated("""\ +The `sympy.ntheory.factor_.divisor_sigma` has been moved to `sympy.functions.combinatorial.numbers.divisor_sigma`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def divisor_sigma(n, k=1): + r""" + Calculate the divisor function `\sigma_k(n)` for positive integer n + + .. deprecated:: 1.13 + + The ``divisor_sigma`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.divisor_sigma` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + ``divisor_sigma(n, k)`` is equal to ``sum([x**k for x in divisors(n)])`` + + If n's prime factorization is: + + .. math :: + n = \prod_{i=1}^\omega p_i^{m_i}, + + then + + .. math :: + \sigma_k(n) = \prod_{i=1}^\omega (1+p_i^k+p_i^{2k}+\cdots + + p_i^{m_ik}). + + Parameters + ========== + + n : integer + + k : integer, optional + power of divisors in the sum + + for k = 0, 1: + ``divisor_sigma(n, 0)`` is equal to ``divisor_count(n)`` + ``divisor_sigma(n, 1)`` is equal to ``sum(divisors(n))`` + + Default for k is 1. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import divisor_sigma + >>> divisor_sigma(18, 0) + 6 + >>> divisor_sigma(39, 1) + 56 + >>> divisor_sigma(12, 2) + 210 + >>> divisor_sigma(37) + 38 + + See Also + ======== + + divisor_count, totient, divisors, factorint + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Divisor_function + + """ + from sympy.functions.combinatorial.numbers import divisor_sigma as func_divisor_sigma + return func_divisor_sigma(n, k) + + +def _divisor_sigma(n:int, k:int=1) -> int: + r""" Calculate the divisor function `\sigma_k(n)` for positive integer n + + Parameters + ========== + + n : int + positive integer + k : int + nonnegative integer + + See Also + ======== + + sympy.functions.combinatorial.numbers.divisor_sigma + + """ + if k == 0: + return math.prod(e + 1 for e in factorint(n).values()) + return math.prod((p**(k*(e + 1)) - 1)//(p**k - 1) for p, e in factorint(n).items()) + + +def core(n, t=2): + r""" + Calculate core(n, t) = `core_t(n)` of a positive integer n + + ``core_2(n)`` is equal to the squarefree part of n + + If n's prime factorization is: + + .. math :: + n = \prod_{i=1}^\omega p_i^{m_i}, + + then + + .. math :: + core_t(n) = \prod_{i=1}^\omega p_i^{m_i \mod t}. + + Parameters + ========== + + n : integer + + t : integer + core(n, t) calculates the t-th power free part of n + + ``core(n, 2)`` is the squarefree part of ``n`` + ``core(n, 3)`` is the cubefree part of ``n`` + + Default for t is 2. + + Examples + ======== + + >>> from sympy.ntheory.factor_ import core + >>> core(24, 2) + 6 + >>> core(9424, 3) + 1178 + >>> core(379238) + 379238 + >>> core(15**11, 10) + 15 + + See Also + ======== + + factorint, sympy.solvers.diophantine.diophantine.square_factor + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Square-free_integer#Squarefree_core + + """ + + n = as_int(n) + t = as_int(t) + if n <= 0: + raise ValueError("n must be a positive integer") + elif t <= 1: + raise ValueError("t must be >= 2") + else: + y = 1 + for p, e in factorint(n).items(): + y *= p**(e % t) + return y + + +@deprecated("""\ +The `sympy.ntheory.factor_.udivisor_sigma` has been moved to `sympy.functions.combinatorial.numbers.udivisor_sigma`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def udivisor_sigma(n, k=1): + r""" + Calculate the unitary divisor function `\sigma_k^*(n)` for positive integer n + + .. deprecated:: 1.13 + + The ``udivisor_sigma`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.udivisor_sigma` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + ``udivisor_sigma(n, k)`` is equal to ``sum([x**k for x in udivisors(n)])`` + + If n's prime factorization is: + + .. math :: + n = \prod_{i=1}^\omega p_i^{m_i}, + + then + + .. math :: + \sigma_k^*(n) = \prod_{i=1}^\omega (1+ p_i^{m_ik}). + + Parameters + ========== + + k : power of divisors in the sum + + for k = 0, 1: + ``udivisor_sigma(n, 0)`` is equal to ``udivisor_count(n)`` + ``udivisor_sigma(n, 1)`` is equal to ``sum(udivisors(n))`` + + Default for k is 1. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import udivisor_sigma + >>> udivisor_sigma(18, 0) + 4 + >>> udivisor_sigma(74, 1) + 114 + >>> udivisor_sigma(36, 3) + 47450 + >>> udivisor_sigma(111) + 152 + + See Also + ======== + + divisor_count, totient, divisors, udivisors, udivisor_count, divisor_sigma, + factorint + + References + ========== + + .. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html + + """ + from sympy.functions.combinatorial.numbers import udivisor_sigma as _udivisor_sigma + return _udivisor_sigma(n, k) + + +@deprecated("""\ +The `sympy.ntheory.factor_.primenu` has been moved to `sympy.functions.combinatorial.numbers.primenu`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def primenu(n): + r""" + Calculate the number of distinct prime factors for a positive integer n. + + .. deprecated:: 1.13 + + The ``primenu`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.primenu` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + If n's prime factorization is: + + .. math :: + n = \prod_{i=1}^k p_i^{m_i}, + + then ``primenu(n)`` or `\nu(n)` is: + + .. math :: + \nu(n) = k. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import primenu + >>> primenu(1) + 0 + >>> primenu(30) + 3 + + See Also + ======== + + factorint + + References + ========== + + .. [1] https://mathworld.wolfram.com/PrimeFactor.html + + """ + from sympy.functions.combinatorial.numbers import primenu as _primenu + return _primenu(n) + + +@deprecated("""\ +The `sympy.ntheory.factor_.primeomega` has been moved to `sympy.functions.combinatorial.numbers.primeomega`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def primeomega(n): + r""" + Calculate the number of prime factors counting multiplicities for a + positive integer n. + + .. deprecated:: 1.13 + + The ``primeomega`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.primeomega` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + If n's prime factorization is: + + .. math :: + n = \prod_{i=1}^k p_i^{m_i}, + + then ``primeomega(n)`` or `\Omega(n)` is: + + .. math :: + \Omega(n) = \sum_{i=1}^k m_i. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import primeomega + >>> primeomega(1) + 0 + >>> primeomega(20) + 3 + + See Also + ======== + + factorint + + References + ========== + + .. [1] https://mathworld.wolfram.com/PrimeFactor.html + + """ + from sympy.functions.combinatorial.numbers import primeomega as _primeomega + return _primeomega(n) + + +def mersenne_prime_exponent(nth): + """Returns the exponent ``i`` for the nth Mersenne prime (which + has the form `2^i - 1`). + + Examples + ======== + + >>> from sympy.ntheory.factor_ import mersenne_prime_exponent + >>> mersenne_prime_exponent(1) + 2 + >>> mersenne_prime_exponent(20) + 4423 + """ + n = as_int(nth) + if n < 1: + raise ValueError("nth must be a positive integer; mersenne_prime_exponent(1) == 2") + if n > 51: + raise ValueError("There are only 51 perfect numbers; nth must be less than or equal to 51") + return MERSENNE_PRIME_EXPONENTS[n - 1] + + +def is_perfect(n): + """Returns True if ``n`` is a perfect number, else False. + + A perfect number is equal to the sum of its positive, proper divisors. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import divisor_sigma + >>> from sympy.ntheory.factor_ import is_perfect, divisors + >>> is_perfect(20) + False + >>> is_perfect(6) + True + >>> 6 == divisor_sigma(6) - 6 == sum(divisors(6)[:-1]) + True + + References + ========== + + .. [1] https://mathworld.wolfram.com/PerfectNumber.html + .. [2] https://en.wikipedia.org/wiki/Perfect_number + + """ + n = as_int(n) + if n < 1: + return False + if n % 2 == 0: + m = (n.bit_length() + 1) >> 1 + if (1 << (m - 1)) * ((1 << m) - 1) != n: + # Even perfect numbers must be of the form `2^{m-1}(2^m-1)` + return False + return m in MERSENNE_PRIME_EXPONENTS or is_mersenne_prime(2**m - 1) + + # n is an odd integer + if n < 10**2000: # https://www.lirmm.fr/~ochem/opn/ + return False + if n % 105 == 0: # not divis by 105 + return False + if all(n % m != r for m, r in [(12, 1), (468, 117), (324, 81)]): + return False + # there are many criteria that the factor structure of n + # must meet; since we will have to factor it to test the + # structure we will have the factors and can then check + # to see whether it is a perfect number or not. So we + # skip the structure checks and go straight to the final + # test below. + result = abundance(n) == 0 + if result: + raise ValueError(filldedent('''In 1888, Sylvester stated: " + ...a prolonged meditation on the subject has satisfied + me that the existence of any one such [odd perfect number] + -- its escape, so to say, from the complex web of conditions + which hem it in on all sides -- would be little short of a + miracle." I guess SymPy just found that miracle and it + factors like this: %s''' % factorint(n))) + return result + + +def abundance(n): + """Returns the difference between the sum of the positive + proper divisors of a number and the number. + + Examples + ======== + + >>> from sympy.ntheory import abundance, is_perfect, is_abundant + >>> abundance(6) + 0 + >>> is_perfect(6) + True + >>> abundance(10) + -2 + >>> is_abundant(10) + False + """ + return _divisor_sigma(n) - 2 * n + + +def is_abundant(n): + """Returns True if ``n`` is an abundant number, else False. + + A abundant number is smaller than the sum of its positive proper divisors. + + Examples + ======== + + >>> from sympy.ntheory.factor_ import is_abundant + >>> is_abundant(20) + True + >>> is_abundant(15) + False + + References + ========== + + .. [1] https://mathworld.wolfram.com/AbundantNumber.html + + """ + n = as_int(n) + if is_perfect(n): + return False + return n % 6 == 0 or bool(abundance(n) > 0) + + +def is_deficient(n): + """Returns True if ``n`` is a deficient number, else False. + + A deficient number is greater than the sum of its positive proper divisors. + + Examples + ======== + + >>> from sympy.ntheory.factor_ import is_deficient + >>> is_deficient(20) + False + >>> is_deficient(15) + True + + References + ========== + + .. [1] https://mathworld.wolfram.com/DeficientNumber.html + + """ + n = as_int(n) + if is_perfect(n): + return False + return bool(abundance(n) < 0) + + +def is_amicable(m, n): + """Returns True if the numbers `m` and `n` are "amicable", else False. + + Amicable numbers are two different numbers so related that the sum + of the proper divisors of each is equal to that of the other. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import divisor_sigma + >>> from sympy.ntheory.factor_ import is_amicable + >>> is_amicable(220, 284) + True + >>> divisor_sigma(220) == divisor_sigma(284) + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Amicable_numbers + + """ + return m != n and m + n == _divisor_sigma(m) == _divisor_sigma(n) + + +def is_carmichael(n): + """ Returns True if the numbers `n` is Carmichael number, else False. + + Parameters + ========== + + n : Integer + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Carmichael_number + .. [2] https://oeis.org/A002997 + + """ + if n < 561: + return False + return n % 2 and not isprime(n) and \ + all(e == 1 and (n - 1) % (p - 1) == 0 for p, e in factorint(n).items()) + + +def find_carmichael_numbers_in_range(x, y): + """ Returns a list of the number of Carmichael in the range + + See Also + ======== + + is_carmichael + + """ + if 0 <= x <= y: + if x % 2 == 0: + return [i for i in range(x + 1, y, 2) if is_carmichael(i)] + else: + return [i for i in range(x, y, 2) if is_carmichael(i)] + else: + raise ValueError('The provided range is not valid. x and y must be non-negative integers and x <= y') + + +def find_first_n_carmichaels(n): + """ Returns the first n Carmichael numbers. + + Parameters + ========== + + n : Integer + + See Also + ======== + + is_carmichael + + """ + i = 561 + carmichaels = [] + + while len(carmichaels) < n: + if is_carmichael(i): + carmichaels.append(i) + i += 2 + + return carmichaels + + +def dra(n, b): + """ + Returns the additive digital root of a natural number ``n`` in base ``b`` + which is a single digit value obtained by an iterative process of summing + digits, on each iteration using the result from the previous iteration to + compute a digit sum. + + Examples + ======== + + >>> from sympy.ntheory.factor_ import dra + >>> dra(3110, 12) + 8 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Digital_root + + """ + + num = abs(as_int(n)) + b = as_int(b) + if b <= 1: + raise ValueError("Base should be an integer greater than 1") + + if num == 0: + return 0 + + return (1 + (num - 1) % (b - 1)) + + +def drm(n, b): + """ + Returns the multiplicative digital root of a natural number ``n`` in a given + base ``b`` which is a single digit value obtained by an iterative process of + multiplying digits, on each iteration using the result from the previous + iteration to compute the digit multiplication. + + Examples + ======== + + >>> from sympy.ntheory.factor_ import drm + >>> drm(9876, 10) + 0 + + >>> drm(49, 10) + 8 + + References + ========== + + .. [1] https://mathworld.wolfram.com/MultiplicativeDigitalRoot.html + + """ + + n = abs(as_int(n)) + b = as_int(b) + if b <= 1: + raise ValueError("Base should be an integer greater than 1") + while n > b: + mul = 1 + while n > 1: + n, r = divmod(n, b) + if r == 0: + return 0 + mul *= r + n = mul + return n diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/generate.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/generate.py new file mode 100644 index 0000000000000000000000000000000000000000..855bb44acfcb6241e6b0bcb81e7a2cfc8ced861f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/generate.py @@ -0,0 +1,1157 @@ +""" +Generating and counting primes. + +""" + +from bisect import bisect, bisect_left +from itertools import count +# Using arrays for sieving instead of lists greatly reduces +# memory consumption +from array import array as _array + +from sympy.core.random import randint +from sympy.external.gmpy import sqrt +from .primetest import isprime +from sympy.utilities.decorator import deprecated +from sympy.utilities.misc import as_int + + +def _as_int_ceiling(a): + """ Wrapping ceiling in as_int will raise an error if there was a problem + determining whether the expression was exactly an integer or not.""" + from sympy.functions.elementary.integers import ceiling + return as_int(ceiling(a)) + + +class Sieve: + """A list of prime numbers, implemented as a dynamically + growing sieve of Eratosthenes. When a lookup is requested involving + an odd number that has not been sieved, the sieve is automatically + extended up to that number. Implementation details limit the number of + primes to ``2^32-1``. + + Examples + ======== + + >>> from sympy import sieve + >>> sieve._reset() # this line for doctest only + >>> 25 in sieve + False + >>> sieve._list + array('L', [2, 3, 5, 7, 11, 13, 17, 19, 23]) + """ + + # data shared (and updated) by all Sieve instances + def __init__(self, sieve_interval=1_000_000): + """ Initial parameters for the Sieve class. + + Parameters + ========== + + sieve_interval (int): Amount of memory to be used + + Raises + ====== + + ValueError + If ``sieve_interval`` is not positive. + + """ + self._n = 6 + self._list = _array('L', [2, 3, 5, 7, 11, 13]) # primes + self._tlist = _array('L', [0, 1, 1, 2, 2, 4]) # totient + self._mlist = _array('i', [0, 1, -1, -1, 0, -1]) # mobius + if sieve_interval <= 0: + raise ValueError("sieve_interval should be a positive integer") + self.sieve_interval = sieve_interval + assert all(len(i) == self._n for i in (self._list, self._tlist, self._mlist)) + + def __repr__(self): + return ("<%s sieve (%i): %i, %i, %i, ... %i, %i\n" + "%s sieve (%i): %i, %i, %i, ... %i, %i\n" + "%s sieve (%i): %i, %i, %i, ... %i, %i>") % ( + 'prime', len(self._list), + self._list[0], self._list[1], self._list[2], + self._list[-2], self._list[-1], + 'totient', len(self._tlist), + self._tlist[0], self._tlist[1], + self._tlist[2], self._tlist[-2], self._tlist[-1], + 'mobius', len(self._mlist), + self._mlist[0], self._mlist[1], + self._mlist[2], self._mlist[-2], self._mlist[-1]) + + def _reset(self, prime=None, totient=None, mobius=None): + """Reset all caches (default). To reset one or more set the + desired keyword to True.""" + if all(i is None for i in (prime, totient, mobius)): + prime = totient = mobius = True + if prime: + self._list = self._list[:self._n] + if totient: + self._tlist = self._tlist[:self._n] + if mobius: + self._mlist = self._mlist[:self._n] + + def extend(self, n): + """Grow the sieve to cover all primes <= n. + + Examples + ======== + + >>> from sympy import sieve + >>> sieve._reset() # this line for doctest only + >>> sieve.extend(30) + >>> sieve[10] == 29 + True + """ + n = int(n) + # `num` is even at any point in the function. + # This satisfies the condition required by `self._primerange`. + num = self._list[-1] + 1 + if n < num: + return + num2 = num**2 + while num2 <= n: + self._list += _array('L', self._primerange(num, num2)) + num, num2 = num2, num2**2 + # Merge the sieves + self._list += _array('L', self._primerange(num, n + 1)) + + def _primerange(self, a, b): + """ Generate all prime numbers in the range (a, b). + + Parameters + ========== + + a, b : positive integers assuming the following conditions + * a is an even number + * 2 < self._list[-1] < a < b < nextprime(self._list[-1])**2 + + Yields + ====== + + p (int): prime numbers such that ``a < p < b`` + + Examples + ======== + + >>> from sympy.ntheory.generate import Sieve + >>> s = Sieve() + >>> s._list[-1] + 13 + >>> list(s._primerange(18, 31)) + [19, 23, 29] + + """ + if b % 2: + b -= 1 + while a < b: + block_size = min(self.sieve_interval, (b - a) // 2) + # Create the list such that block[x] iff (a + 2x + 1) is prime. + # Note that even numbers are not considered here. + block = [True] * block_size + for p in self._list[1:bisect(self._list, sqrt(a + 2 * block_size + 1))]: + for t in range((-(a + 1 + p) // 2) % p, block_size, p): + block[t] = False + for idx, p in enumerate(block): + if p: + yield a + 2 * idx + 1 + a += 2 * block_size + + def extend_to_no(self, i): + """Extend to include the ith prime number. + + Parameters + ========== + + i : integer + + Examples + ======== + + >>> from sympy import sieve + >>> sieve._reset() # this line for doctest only + >>> sieve.extend_to_no(9) + >>> sieve._list + array('L', [2, 3, 5, 7, 11, 13, 17, 19, 23]) + + Notes + ===== + + The list is extended by 50% if it is too short, so it is + likely that it will be longer than requested. + """ + i = as_int(i) + while len(self._list) < i: + self.extend(int(self._list[-1] * 1.5)) + + def primerange(self, a, b=None): + """Generate all prime numbers in the range [2, a) or [a, b). + + Examples + ======== + + >>> from sympy import sieve, prime + + All primes less than 19: + + >>> print([i for i in sieve.primerange(19)]) + [2, 3, 5, 7, 11, 13, 17] + + All primes greater than or equal to 7 and less than 19: + + >>> print([i for i in sieve.primerange(7, 19)]) + [7, 11, 13, 17] + + All primes through the 10th prime + + >>> list(sieve.primerange(prime(10) + 1)) + [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + + """ + if b is None: + b = _as_int_ceiling(a) + a = 2 + else: + a = max(2, _as_int_ceiling(a)) + b = _as_int_ceiling(b) + if a >= b: + return + self.extend(b) + yield from self._list[bisect_left(self._list, a): + bisect_left(self._list, b)] + + def totientrange(self, a, b): + """Generate all totient numbers for the range [a, b). + + Examples + ======== + + >>> from sympy import sieve + >>> print([i for i in sieve.totientrange(7, 18)]) + [6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16] + """ + a = max(1, _as_int_ceiling(a)) + b = _as_int_ceiling(b) + n = len(self._tlist) + if a >= b: + return + elif b <= n: + for i in range(a, b): + yield self._tlist[i] + else: + self._tlist += _array('L', range(n, b)) + for i in range(1, n): + ti = self._tlist[i] + if ti == i - 1: + startindex = (n + i - 1) // i * i + for j in range(startindex, b, i): + self._tlist[j] -= self._tlist[j] // i + if i >= a: + yield ti + + for i in range(n, b): + ti = self._tlist[i] + if ti == i: + for j in range(i, b, i): + self._tlist[j] -= self._tlist[j] // i + if i >= a: + yield self._tlist[i] + + def mobiusrange(self, a, b): + """Generate all mobius numbers for the range [a, b). + + Parameters + ========== + + a : integer + First number in range + + b : integer + First number outside of range + + Examples + ======== + + >>> from sympy import sieve + >>> print([i for i in sieve.mobiusrange(7, 18)]) + [-1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1] + """ + a = max(1, _as_int_ceiling(a)) + b = _as_int_ceiling(b) + n = len(self._mlist) + if a >= b: + return + elif b <= n: + for i in range(a, b): + yield self._mlist[i] + else: + self._mlist += _array('i', [0]*(b - n)) + for i in range(1, n): + mi = self._mlist[i] + startindex = (n + i - 1) // i * i + for j in range(startindex, b, i): + self._mlist[j] -= mi + if i >= a: + yield mi + + for i in range(n, b): + mi = self._mlist[i] + for j in range(2 * i, b, i): + self._mlist[j] -= mi + if i >= a: + yield mi + + def search(self, n): + """Return the indices i, j of the primes that bound n. + + If n is prime then i == j. + + Although n can be an expression, if ceiling cannot convert + it to an integer then an n error will be raised. + + Examples + ======== + + >>> from sympy import sieve + >>> sieve.search(25) + (9, 10) + >>> sieve.search(23) + (9, 9) + """ + test = _as_int_ceiling(n) + n = as_int(n) + if n < 2: + raise ValueError("n should be >= 2 but got: %s" % n) + if n > self._list[-1]: + self.extend(n) + b = bisect(self._list, n) + if self._list[b - 1] == test: + return b, b + else: + return b, b + 1 + + def __contains__(self, n): + try: + n = as_int(n) + assert n >= 2 + except (ValueError, AssertionError): + return False + if n % 2 == 0: + return n == 2 + a, b = self.search(n) + return a == b + + def __iter__(self): + for n in count(1): + yield self[n] + + def __getitem__(self, n): + """Return the nth prime number""" + if isinstance(n, slice): + self.extend_to_no(n.stop) + start = n.start if n.start is not None else 0 + if start < 1: + # sieve[:5] would be empty (starting at -1), let's + # just be explicit and raise. + raise IndexError("Sieve indices start at 1.") + return self._list[start - 1:n.stop - 1:n.step] + else: + if n < 1: + # offset is one, so forbid explicit access to sieve[0] + # (would surprisingly return the last one). + raise IndexError("Sieve indices start at 1.") + n = as_int(n) + self.extend_to_no(n) + return self._list[n - 1] + +# Generate a global object for repeated use in trial division etc +sieve = Sieve() + +def prime(nth): + r""" + Return the nth prime number, where primes are indexed starting from 1: + prime(1) = 2, prime(2) = 3, etc. + + Parameters + ========== + + nth : int + The position of the prime number to return (must be a positive integer). + + Returns + ======= + + int + The nth prime number. + + Examples + ======== + + >>> from sympy import prime + >>> prime(10) + 29 + >>> prime(1) + 2 + >>> prime(100000) + 1299709 + + See Also + ======== + + sympy.ntheory.primetest.isprime : Test if a number is prime. + primerange : Generate all primes in a given range. + primepi : Return the number of primes less than or equal to a given number. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Prime_number_theorem + .. [2] https://en.wikipedia.org/wiki/Logarithmic_integral_function + .. [3] https://en.wikipedia.org/wiki/Skewes%27_number + """ + n = as_int(nth) + if n < 1: + raise ValueError("nth must be a positive integer; prime(1) == 2") + + # Check if n is within the sieve range + if n <= len(sieve._list): + return sieve[n] + + from sympy.functions.elementary.exponential import log + from sympy.functions.special.error_functions import li + + if n < 1000: + # Extend sieve up to 8*n as this is empirically sufficient + sieve.extend(8 * n) + return sieve[n] + + a = 2 + # Estimate an upper bound for the nth prime using the prime number theorem + b = int(n * (log(n).evalf() + log(log(n)).evalf())) + + # Binary search for the least m such that li(m) > n + while a < b: + mid = (a + b) >> 1 + if li(mid).evalf() > n: + b = mid + else: + a = mid + 1 + + return nextprime(a - 1, n - _primepi(a - 1)) + + +@deprecated("""\ +The `sympy.ntheory.generate.primepi` has been moved to `sympy.functions.combinatorial.numbers.primepi`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def primepi(n): + r""" Represents the prime counting function pi(n) = the number + of prime numbers less than or equal to n. + + .. deprecated:: 1.13 + + The ``primepi`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.primepi` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + Algorithm Description: + + In sieve method, we remove all multiples of prime p + except p itself. + + Let phi(i,j) be the number of integers 2 <= k <= i + which remain after sieving from primes less than + or equal to j. + Clearly, pi(n) = phi(n, sqrt(n)) + + If j is not a prime, + phi(i,j) = phi(i, j - 1) + + if j is a prime, + We remove all numbers(except j) whose + smallest prime factor is j. + + Let $x= j \times a$ be such a number, where $2 \le a \le i / j$ + Now, after sieving from primes $\le j - 1$, + a must remain + (because x, and hence a has no prime factor $\le j - 1$) + Clearly, there are phi(i / j, j - 1) such a + which remain on sieving from primes $\le j - 1$ + + Now, if a is a prime less than equal to j - 1, + $x= j \times a$ has smallest prime factor = a, and + has already been removed(by sieving from a). + So, we do not need to remove it again. + (Note: there will be pi(j - 1) such x) + + Thus, number of x, that will be removed are: + phi(i / j, j - 1) - phi(j - 1, j - 1) + (Note that pi(j - 1) = phi(j - 1, j - 1)) + + $\Rightarrow$ phi(i,j) = phi(i, j - 1) - phi(i / j, j - 1) + phi(j - 1, j - 1) + + So,following recursion is used and implemented as dp: + + phi(a, b) = phi(a, b - 1), if b is not a prime + phi(a, b) = phi(a, b-1)-phi(a / b, b-1) + phi(b-1, b-1), if b is prime + + Clearly a is always of the form floor(n / k), + which can take at most $2\sqrt{n}$ values. + Two arrays arr1,arr2 are maintained + arr1[i] = phi(i, j), + arr2[i] = phi(n // i, j) + + Finally the answer is arr2[1] + + Examples + ======== + + >>> from sympy import primepi, prime, prevprime, isprime + >>> primepi(25) + 9 + + So there are 9 primes less than or equal to 25. Is 25 prime? + + >>> isprime(25) + False + + It is not. So the first prime less than 25 must be the + 9th prime: + + >>> prevprime(25) == prime(9) + True + + See Also + ======== + + sympy.ntheory.primetest.isprime : Test if n is prime + primerange : Generate all primes in a given range + prime : Return the nth prime + """ + from sympy.functions.combinatorial.numbers import primepi as func_primepi + return func_primepi(n) + + +def _primepi(n:int) -> int: + r""" Represents the prime counting function pi(n) = the number + of prime numbers less than or equal to n. + + Explanation + =========== + + In sieve method, we remove all multiples of prime p + except p itself. + + Let phi(i,j) be the number of integers 2 <= k <= i + which remain after sieving from primes less than + or equal to j. + Clearly, pi(n) = phi(n, sqrt(n)) + + If j is not a prime, + phi(i,j) = phi(i, j - 1) + + if j is a prime, + We remove all numbers(except j) whose + smallest prime factor is j. + + Let $x= j \times a$ be such a number, where $2 \le a \le i / j$ + Now, after sieving from primes $\le j - 1$, + a must remain + (because x, and hence a has no prime factor $\le j - 1$) + Clearly, there are phi(i / j, j - 1) such a + which remain on sieving from primes $\le j - 1$ + + Now, if a is a prime less than equal to j - 1, + $x= j \times a$ has smallest prime factor = a, and + has already been removed(by sieving from a). + So, we do not need to remove it again. + (Note: there will be pi(j - 1) such x) + + Thus, number of x, that will be removed are: + phi(i / j, j - 1) - phi(j - 1, j - 1) + (Note that pi(j - 1) = phi(j - 1, j - 1)) + + $\Rightarrow$ phi(i,j) = phi(i, j - 1) - phi(i / j, j - 1) + phi(j - 1, j - 1) + + So,following recursion is used and implemented as dp: + + phi(a, b) = phi(a, b - 1), if b is not a prime + phi(a, b) = phi(a, b-1)-phi(a / b, b-1) + phi(b-1, b-1), if b is prime + + Clearly a is always of the form floor(n / k), + which can take at most $2\sqrt{n}$ values. + Two arrays arr1,arr2 are maintained + arr1[i] = phi(i, j), + arr2[i] = phi(n // i, j) + + Finally the answer is arr2[1] + + Parameters + ========== + + n : int + + """ + if n < 2: + return 0 + if n <= sieve._list[-1]: + return sieve.search(n)[0] + lim = sqrt(n) + arr1 = [(i + 1) >> 1 for i in range(lim + 1)] + arr2 = [0] + [(n//i + 1) >> 1 for i in range(1, lim + 1)] + skip = [False] * (lim + 1) + for i in range(3, lim + 1, 2): + # Presently, arr1[k]=phi(k,i - 1), + # arr2[k] = phi(n // k,i - 1) # not all k's do this + if skip[i]: + # skip if i is a composite number + continue + p = arr1[i - 1] + for j in range(i, lim + 1, i): + skip[j] = True + # update arr2 + # phi(n/j, i) = phi(n/j, i-1) - phi(n/(i*j), i-1) + phi(i-1, i-1) + for j in range(1, min(n // (i * i), lim) + 1, 2): + # No need for arr2[j] in j such that skip[j] is True to + # compute the final required arr2[1]. + if skip[j]: + continue + st = i * j + if st <= lim: + arr2[j] -= arr2[st] - p + else: + arr2[j] -= arr1[n // st] - p + # update arr1 + # phi(j, i) = phi(j, i-1) - phi(j/i, i-1) + phi(i-1, i-1) + # where the range below i**2 is fixed and + # does not need to be calculated. + for j in range(lim, min(lim, i*i - 1), -1): + arr1[j] -= arr1[j // i] - p + return arr2[1] + + +def nextprime(n, ith=1): + """ Return the ith prime greater than n. + + Parameters + ========== + + n : integer + ith : positive integer + + Returns + ======= + + int : Return the ith prime greater than n + + Raises + ====== + + ValueError + If ``ith <= 0``. + If ``n`` or ``ith`` is not an integer. + + Notes + ===== + + Potential primes are located at 6*j +/- 1. This + property is used during searching. + + >>> from sympy import nextprime + >>> [(i, nextprime(i)) for i in range(10, 15)] + [(10, 11), (11, 13), (12, 13), (13, 17), (14, 17)] + >>> nextprime(2, ith=2) # the 2nd prime after 2 + 5 + + See Also + ======== + + prevprime : Return the largest prime smaller than n + primerange : Generate all primes in a given range + + """ + n = int(n) + i = as_int(ith) + if i <= 0: + raise ValueError("ith should be positive") + if n < 2: + n = 2 + i -= 1 + if n <= sieve._list[-2]: + l, _ = sieve.search(n) + if l + i - 1 < len(sieve._list): + return sieve._list[l + i - 1] + n = sieve._list[-1] + i += l - len(sieve._list) + nn = 6*(n//6) + if nn == n: + n += 1 + if isprime(n): + i -= 1 + if not i: + return n + n += 4 + elif n - nn == 5: + n += 2 + if isprime(n): + i -= 1 + if not i: + return n + n += 4 + else: + n = nn + 5 + while 1: + if isprime(n): + i -= 1 + if not i: + return n + n += 2 + if isprime(n): + i -= 1 + if not i: + return n + n += 4 + + +def prevprime(n): + """ Return the largest prime smaller than n. + + Notes + ===== + + Potential primes are located at 6*j +/- 1. This + property is used during searching. + + >>> from sympy import prevprime + >>> [(i, prevprime(i)) for i in range(10, 15)] + [(10, 7), (11, 7), (12, 11), (13, 11), (14, 13)] + + See Also + ======== + + nextprime : Return the ith prime greater than n + primerange : Generates all primes in a given range + """ + n = _as_int_ceiling(n) + if n < 3: + raise ValueError("no preceding primes") + if n < 8: + return {3: 2, 4: 3, 5: 3, 6: 5, 7: 5}[n] + if n <= sieve._list[-1]: + l, u = sieve.search(n) + if l == u: + return sieve[l-1] + else: + return sieve[l] + nn = 6*(n//6) + if n - nn <= 1: + n = nn - 1 + if isprime(n): + return n + n -= 4 + else: + n = nn + 1 + while 1: + if isprime(n): + return n + n -= 2 + if isprime(n): + return n + n -= 4 + + +def primerange(a, b=None): + """ Generate a list of all prime numbers in the range [2, a), + or [a, b). + + If the range exists in the default sieve, the values will + be returned from there; otherwise values will be returned + but will not modify the sieve. + + Examples + ======== + + >>> from sympy import primerange, prime + + All primes less than 19: + + >>> list(primerange(19)) + [2, 3, 5, 7, 11, 13, 17] + + All primes greater than or equal to 7 and less than 19: + + >>> list(primerange(7, 19)) + [7, 11, 13, 17] + + All primes through the 10th prime + + >>> list(primerange(prime(10) + 1)) + [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + + The Sieve method, primerange, is generally faster but it will + occupy more memory as the sieve stores values. The default + instance of Sieve, named sieve, can be used: + + >>> from sympy import sieve + >>> list(sieve.primerange(1, 30)) + [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + + Notes + ===== + + Some famous conjectures about the occurrence of primes in a given + range are [1]: + + - Twin primes: though often not, the following will give 2 primes + an infinite number of times: + primerange(6*n - 1, 6*n + 2) + - Legendre's: the following always yields at least one prime + primerange(n**2, (n+1)**2+1) + - Bertrand's (proven): there is always a prime in the range + primerange(n, 2*n) + - Brocard's: there are at least four primes in the range + primerange(prime(n)**2, prime(n+1)**2) + + The average gap between primes is log(n) [2]; the gap between + primes can be arbitrarily large since sequences of composite + numbers are arbitrarily large, e.g. the numbers in the sequence + n! + 2, n! + 3 ... n! + n are all composite. + + See Also + ======== + + prime : Return the nth prime + nextprime : Return the ith prime greater than n + prevprime : Return the largest prime smaller than n + randprime : Returns a random prime in a given range + primorial : Returns the product of primes based on condition + Sieve.primerange : return range from already computed primes + or extend the sieve to contain the requested + range. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Prime_number + .. [2] https://primes.utm.edu/notes/gaps.html + """ + if b is None: + a, b = 2, a + if a >= b: + return + # If we already have the range, return it. + largest_known_prime = sieve._list[-1] + if b <= largest_known_prime: + yield from sieve.primerange(a, b) + return + # If we know some of it, return it. + if a <= largest_known_prime: + yield from sieve._list[bisect_left(sieve._list, a):] + a = largest_known_prime + 1 + elif a % 2: + a -= 1 + tail = min(b, (largest_known_prime)**2) + if a < tail: + yield from sieve._primerange(a, tail) + a = tail + if b <= a: + return + # otherwise compute, without storing, the desired range. + while 1: + a = nextprime(a) + if a < b: + yield a + else: + return + + +def randprime(a, b): + """ Return a random prime number in the range [a, b). + + Bertrand's postulate assures that + randprime(a, 2*a) will always succeed for a > 1. + + Note that due to implementation difficulties, + the prime numbers chosen are not uniformly random. + For example, there are two primes in the range [112, 128), + ``113`` and ``127``, but ``randprime(112, 128)`` returns ``127`` + with a probability of 15/17. + + Examples + ======== + + >>> from sympy import randprime, isprime + >>> randprime(1, 30) #doctest: +SKIP + 13 + >>> isprime(randprime(1, 30)) + True + + See Also + ======== + + primerange : Generate all primes in a given range + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Bertrand's_postulate + + """ + if a >= b: + return + a, b = map(int, (a, b)) + n = randint(a - 1, b) + p = nextprime(n) + if p >= b: + p = prevprime(b) + if p < a: + raise ValueError("no primes exist in the specified range") + return p + + +def primorial(n, nth=True): + """ + Returns the product of the first n primes (default) or + the primes less than or equal to n (when ``nth=False``). + + Examples + ======== + + >>> from sympy.ntheory.generate import primorial, primerange + >>> from sympy import factorint, Mul, primefactors, sqrt + >>> primorial(4) # the first 4 primes are 2, 3, 5, 7 + 210 + >>> primorial(4, nth=False) # primes <= 4 are 2 and 3 + 6 + >>> primorial(1) + 2 + >>> primorial(1, nth=False) + 1 + >>> primorial(sqrt(101), nth=False) + 210 + + One can argue that the primes are infinite since if you take + a set of primes and multiply them together (e.g. the primorial) and + then add or subtract 1, the result cannot be divided by any of the + original factors, hence either 1 or more new primes must divide this + product of primes. + + In this case, the number itself is a new prime: + + >>> factorint(primorial(4) + 1) + {211: 1} + + In this case two new primes are the factors: + + >>> factorint(primorial(4) - 1) + {11: 1, 19: 1} + + Here, some primes smaller and larger than the primes multiplied together + are obtained: + + >>> p = list(primerange(10, 20)) + >>> sorted(set(primefactors(Mul(*p) + 1)).difference(set(p))) + [2, 5, 31, 149] + + See Also + ======== + + primerange : Generate all primes in a given range + + """ + if nth: + n = as_int(n) + else: + n = int(n) + if n < 1: + raise ValueError("primorial argument must be >= 1") + p = 1 + if nth: + for i in range(1, n + 1): + p *= prime(i) + else: + for i in primerange(2, n + 1): + p *= i + return p + + +def cycle_length(f, x0, nmax=None, values=False): + """For a given iterated sequence, return a generator that gives + the length of the iterated cycle (lambda) and the length of terms + before the cycle begins (mu); if ``values`` is True then the + terms of the sequence will be returned instead. The sequence is + started with value ``x0``. + + Note: more than the first lambda + mu terms may be returned and this + is the cost of cycle detection with Brent's method; there are, however, + generally less terms calculated than would have been calculated if the + proper ending point were determined, e.g. by using Floyd's method. + + >>> from sympy.ntheory.generate import cycle_length + + This will yield successive values of i <-- func(i): + + >>> def gen(func, i): + ... while 1: + ... yield i + ... i = func(i) + ... + + A function is defined: + + >>> func = lambda i: (i**2 + 1) % 51 + + and given a seed of 4 and the mu and lambda terms calculated: + + >>> next(cycle_length(func, 4)) + (6, 3) + + We can see what is meant by looking at the output: + + >>> iter = cycle_length(func, 4, values=True) + >>> list(iter) + [4, 17, 35, 2, 5, 26, 14, 44, 50, 2, 5, 26, 14] + + There are 6 repeating values after the first 3. + + If a sequence is suspected of being longer than you might wish, ``nmax`` + can be used to exit early (and mu will be returned as None): + + >>> next(cycle_length(func, 4, nmax = 4)) + (4, None) + >>> list(cycle_length(func, 4, nmax = 4, values=True)) + [4, 17, 35, 2] + + Code modified from: + https://en.wikipedia.org/wiki/Cycle_detection. + """ + + nmax = int(nmax or 0) + + # main phase: search successive powers of two + power = lam = 1 + tortoise, hare = x0, f(x0) # f(x0) is the element/node next to x0. + i = 1 + if values: + yield tortoise + while tortoise != hare and (not nmax or i < nmax): + i += 1 + if power == lam: # time to start a new power of two? + tortoise = hare + power *= 2 + lam = 0 + if values: + yield hare + hare = f(hare) + lam += 1 + if nmax and i == nmax: + if values: + return + else: + yield nmax, None + return + if not values: + # Find the position of the first repetition of length lambda + mu = 0 + tortoise = hare = x0 + for i in range(lam): + hare = f(hare) + while tortoise != hare: + tortoise = f(tortoise) + hare = f(hare) + mu += 1 + yield lam, mu + + +def composite(nth): + """ Return the nth composite number, with the composite numbers indexed as + composite(1) = 4, composite(2) = 6, etc.... + + Examples + ======== + + >>> from sympy import composite + >>> composite(36) + 52 + >>> composite(1) + 4 + >>> composite(17737) + 20000 + + See Also + ======== + + sympy.ntheory.primetest.isprime : Test if n is prime + primerange : Generate all primes in a given range + primepi : Return the number of primes less than or equal to n + prime : Return the nth prime + compositepi : Return the number of positive composite numbers less than or equal to n + """ + n = as_int(nth) + if n < 1: + raise ValueError("nth must be a positive integer; composite(1) == 4") + composite_arr = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18] + if n <= 10: + return composite_arr[n - 1] + + a, b = 4, sieve._list[-1] + if n <= b - _primepi(b) - 1: + while a < b - 1: + mid = (a + b) >> 1 + if mid - _primepi(mid) - 1 > n: + b = mid + else: + a = mid + if isprime(a): + a -= 1 + return a + + from sympy.functions.elementary.exponential import log + from sympy.functions.special.error_functions import li + a = 4 # Lower bound for binary search + b = int(n*(log(n) + log(log(n)))) # Upper bound for the search. + + while a < b: + mid = (a + b) >> 1 + if mid - li(mid) - 1 > n: + b = mid + else: + a = mid + 1 + + n_composites = a - _primepi(a) - 1 + while n_composites > n: + if not isprime(a): + n_composites -= 1 + a -= 1 + if isprime(a): + a -= 1 + return a + + +def compositepi(n): + """ Return the number of positive composite numbers less than or equal to n. + The first positive composite is 4, i.e. compositepi(4) = 1. + + Examples + ======== + + >>> from sympy import compositepi + >>> compositepi(25) + 15 + >>> compositepi(1000) + 831 + + See Also + ======== + + sympy.ntheory.primetest.isprime : Test if n is prime + primerange : Generate all primes in a given range + prime : Return the nth prime + primepi : Return the number of primes less than or equal to n + composite : Return the nth composite number + """ + n = int(n) + if n < 4: + return 0 + return n - _primepi(n) - 1 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/modular.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/modular.py new file mode 100644 index 0000000000000000000000000000000000000000..628a3d8c5a7fb4b6c51ad337df66d74f90282496 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/modular.py @@ -0,0 +1,291 @@ +from math import prod + +from sympy.external.gmpy import gcd, gcdext +from sympy.ntheory.primetest import isprime +from sympy.polys.domains import ZZ +from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2 +from sympy.utilities.misc import as_int + + +def symmetric_residue(a, m): + """Return the residual mod m such that it is within half of the modulus. + + >>> from sympy.ntheory.modular import symmetric_residue + >>> symmetric_residue(1, 6) + 1 + >>> symmetric_residue(4, 6) + -2 + """ + if a <= m // 2: + return a + return a - m + + +def crt(m, v, symmetric=False, check=True): + r"""Chinese Remainder Theorem. + + The moduli in m are assumed to be pairwise coprime. The output + is then an integer f, such that f = v_i mod m_i for each pair out + of v and m. If ``symmetric`` is False a positive integer will be + returned, else \|f\| will be less than or equal to the LCM of the + moduli, and thus f may be negative. + + If the moduli are not co-prime the correct result will be returned + if/when the test of the result is found to be incorrect. This result + will be None if there is no solution. + + The keyword ``check`` can be set to False if it is known that the moduli + are coprime. + + Examples + ======== + + As an example consider a set of residues ``U = [49, 76, 65]`` + and a set of moduli ``M = [99, 97, 95]``. Then we have:: + + >>> from sympy.ntheory.modular import crt + + >>> crt([99, 97, 95], [49, 76, 65]) + (639985, 912285) + + This is the correct result because:: + + >>> [639985 % m for m in [99, 97, 95]] + [49, 76, 65] + + If the moduli are not co-prime, you may receive an incorrect result + if you use ``check=False``: + + >>> crt([12, 6, 17], [3, 4, 2], check=False) + (954, 1224) + >>> [954 % m for m in [12, 6, 17]] + [6, 0, 2] + >>> crt([12, 6, 17], [3, 4, 2]) is None + True + >>> crt([3, 6], [2, 5]) + (5, 6) + + Note: the order of gf_crt's arguments is reversed relative to crt, + and that solve_congruence takes residue, modulus pairs. + + Programmer's note: rather than checking that all pairs of moduli share + no GCD (an O(n**2) test) and rather than factoring all moduli and seeing + that there is no factor in common, a check that the result gives the + indicated residuals is performed -- an O(n) operation. + + See Also + ======== + + solve_congruence + sympy.polys.galoistools.gf_crt : low level crt routine used by this routine + """ + if check: + m = list(map(as_int, m)) + v = list(map(as_int, v)) + + result = gf_crt(v, m, ZZ) + mm = prod(m) + + if check: + if not all(v % m == result % m for v, m in zip(v, m)): + result = solve_congruence(*list(zip(v, m)), + check=False, symmetric=symmetric) + if result is None: + return result + result, mm = result + + if symmetric: + return int(symmetric_residue(result, mm)), int(mm) + return int(result), int(mm) + + +def crt1(m): + """First part of Chinese Remainder Theorem, for multiple application. + + Examples + ======== + + >>> from sympy.ntheory.modular import crt, crt1, crt2 + >>> m = [99, 97, 95] + >>> v = [49, 76, 65] + + The following two codes have the same result. + + >>> crt(m, v) + (639985, 912285) + + >>> mm, e, s = crt1(m) + >>> crt2(m, v, mm, e, s) + (639985, 912285) + + However, it is faster when we want to fix ``m`` and + compute for multiple ``v``, i.e. the following cases: + + >>> mm, e, s = crt1(m) + >>> vs = [[52, 21, 37], [19, 46, 76]] + >>> for v in vs: + ... print(crt2(m, v, mm, e, s)) + (397042, 912285) + (803206, 912285) + + See Also + ======== + + sympy.polys.galoistools.gf_crt1 : low level crt routine used by this routine + sympy.ntheory.modular.crt + sympy.ntheory.modular.crt2 + + """ + + return gf_crt1(m, ZZ) + + +def crt2(m, v, mm, e, s, symmetric=False): + """Second part of Chinese Remainder Theorem, for multiple application. + + See ``crt1`` for usage. + + Examples + ======== + + >>> from sympy.ntheory.modular import crt1, crt2 + >>> mm, e, s = crt1([18, 42, 6]) + >>> crt2([18, 42, 6], [0, 0, 0], mm, e, s) + (0, 4536) + + See Also + ======== + + sympy.polys.galoistools.gf_crt2 : low level crt routine used by this routine + sympy.ntheory.modular.crt + sympy.ntheory.modular.crt1 + + """ + + result = gf_crt2(v, m, mm, e, s, ZZ) + + if symmetric: + return int(symmetric_residue(result, mm)), int(mm) + return int(result), int(mm) + + +def solve_congruence(*remainder_modulus_pairs, **hint): + """Compute the integer ``n`` that has the residual ``ai`` when it is + divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to + this function: ((a1, m1), (a2, m2), ...). If there is no solution, + return None. Otherwise return ``n`` and its modulus. + + The ``mi`` values need not be co-prime. If it is known that the moduli are + not co-prime then the hint ``check`` can be set to False (default=True) and + the check for a quicker solution via crt() (valid when the moduli are + co-prime) will be skipped. + + If the hint ``symmetric`` is True (default is False), the value of ``n`` + will be within 1/2 of the modulus, possibly negative. + + Examples + ======== + + >>> from sympy.ntheory.modular import solve_congruence + + What number is 2 mod 3, 3 mod 5 and 2 mod 7? + + >>> solve_congruence((2, 3), (3, 5), (2, 7)) + (23, 105) + >>> [23 % m for m in [3, 5, 7]] + [2, 3, 2] + + If you prefer to work with all remainder in one list and + all moduli in another, send the arguments like this: + + >>> solve_congruence(*zip((2, 3, 2), (3, 5, 7))) + (23, 105) + + The moduli need not be co-prime; in this case there may or + may not be a solution: + + >>> solve_congruence((2, 3), (4, 6)) is None + True + + >>> solve_congruence((2, 3), (5, 6)) + (5, 6) + + The symmetric flag will make the result be within 1/2 of the modulus: + + >>> solve_congruence((2, 3), (5, 6), symmetric=True) + (-1, 6) + + See Also + ======== + + crt : high level routine implementing the Chinese Remainder Theorem + + """ + def combine(c1, c2): + """Return the tuple (a, m) which satisfies the requirement + that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Method_of_successive_substitution + """ + a1, m1 = c1 + a2, m2 = c2 + a, b, c = m1, a2 - a1, m2 + g = gcd(a, b, c) + a, b, c = [i//g for i in [a, b, c]] + if a != 1: + g, inv_a, _ = gcdext(a, c) + if g != 1: + return None + b *= inv_a + a, m = a1 + m1*b, m1*c + return a, m + + rm = remainder_modulus_pairs + symmetric = hint.get('symmetric', False) + + if hint.get('check', True): + rm = [(as_int(r), as_int(m)) for r, m in rm] + + # ignore redundant pairs but raise an error otherwise; also + # make sure that a unique set of bases is sent to gf_crt if + # they are all prime. + # + # The routine will work out less-trivial violations and + # return None, e.g. for the pairs (1,3) and (14,42) there + # is no answer because 14 mod 42 (having a gcd of 14) implies + # (14/2) mod (42/2), (14/7) mod (42/7) and (14/14) mod (42/14) + # which, being 0 mod 3, is inconsistent with 1 mod 3. But to + # preprocess the input beyond checking of another pair with 42 + # or 3 as the modulus (for this example) is not necessary. + uniq = {} + for r, m in rm: + r %= m + if m in uniq: + if r != uniq[m]: + return None + continue + uniq[m] = r + rm = [(r, m) for m, r in uniq.items()] + del uniq + + # if the moduli are co-prime, the crt will be significantly faster; + # checking all pairs for being co-prime gets to be slow but a prime + # test is a good trade-off + if all(isprime(m) for r, m in rm): + r, m = list(zip(*rm)) + return crt(m, r, symmetric=symmetric, check=False) + + rv = (0, 1) + for rmi in rm: + rv = combine(rv, rmi) + if rv is None: + break + n, m = rv + n = n % m + else: + if symmetric: + return symmetric_residue(n, m), m + return n, m diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/multinomial.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/multinomial.py new file mode 100644 index 0000000000000000000000000000000000000000..8ec50fdb533be547b9a8e60dc47568965bf89436 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/multinomial.py @@ -0,0 +1,188 @@ +from sympy.utilities.misc import as_int + + +def binomial_coefficients(n): + """Return a dictionary containing pairs :math:`{(k1,k2) : C_kn}` where + :math:`C_kn` are binomial coefficients and :math:`n=k1+k2`. + + Examples + ======== + + >>> from sympy.ntheory import binomial_coefficients + >>> binomial_coefficients(9) + {(0, 9): 1, (1, 8): 9, (2, 7): 36, (3, 6): 84, + (4, 5): 126, (5, 4): 126, (6, 3): 84, (7, 2): 36, (8, 1): 9, (9, 0): 1} + + See Also + ======== + + binomial_coefficients_list, multinomial_coefficients + """ + n = as_int(n) + d = {(0, n): 1, (n, 0): 1} + a = 1 + for k in range(1, n//2 + 1): + a = (a * (n - k + 1))//k + d[k, n - k] = d[n - k, k] = a + return d + + +def binomial_coefficients_list(n): + """ Return a list of binomial coefficients as rows of the Pascal's + triangle. + + Examples + ======== + + >>> from sympy.ntheory import binomial_coefficients_list + >>> binomial_coefficients_list(9) + [1, 9, 36, 84, 126, 126, 84, 36, 9, 1] + + See Also + ======== + + binomial_coefficients, multinomial_coefficients + """ + n = as_int(n) + d = [1] * (n + 1) + a = 1 + for k in range(1, n//2 + 1): + a = (a * (n - k + 1))//k + d[k] = d[n - k] = a + return d + + +def multinomial_coefficients(m, n): + r"""Return a dictionary containing pairs ``{(k1,k2,..,km) : C_kn}`` + where ``C_kn`` are multinomial coefficients such that + ``n=k1+k2+..+km``. + + Examples + ======== + + >>> from sympy.ntheory import multinomial_coefficients + >>> multinomial_coefficients(2, 5) # indirect doctest + {(0, 5): 1, (1, 4): 5, (2, 3): 10, (3, 2): 10, (4, 1): 5, (5, 0): 1} + + Notes + ===== + + The algorithm is based on the following result: + + .. math:: + \binom{n}{k_1, \ldots, k_m} = + \frac{k_1 + 1}{n - k_1} \sum_{i=2}^m \binom{n}{k_1 + 1, \ldots, k_i - 1, \ldots} + + Code contributed to Sage by Yann Laigle-Chapuy, copied with permission + of the author. + + See Also + ======== + + binomial_coefficients_list, binomial_coefficients + """ + m = as_int(m) + n = as_int(n) + if not m: + if n: + return {} + return {(): 1} + if m == 2: + return binomial_coefficients(n) + if m >= 2*n and n > 1: + return dict(multinomial_coefficients_iterator(m, n)) + t = [n] + [0] * (m - 1) + r = {tuple(t): 1} + if n: + j = 0 # j will be the leftmost nonzero position + else: + j = m + # enumerate tuples in co-lex order + while j < m - 1: + # compute next tuple + tj = t[j] + if j: + t[j] = 0 + t[0] = tj + if tj > 1: + t[j + 1] += 1 + j = 0 + start = 1 + v = 0 + else: + j += 1 + start = j + 1 + v = r[tuple(t)] + t[j] += 1 + # compute the value + # NB: the initialization of v was done above + for k in range(start, m): + if t[k]: + t[k] -= 1 + v += r[tuple(t)] + t[k] += 1 + t[0] -= 1 + r[tuple(t)] = (v * tj) // (n - t[0]) + return r + + +def multinomial_coefficients_iterator(m, n, _tuple=tuple): + """multinomial coefficient iterator + + This routine has been optimized for `m` large with respect to `n` by taking + advantage of the fact that when the monomial tuples `t` are stripped of + zeros, their coefficient is the same as that of the monomial tuples from + ``multinomial_coefficients(n, n)``. Therefore, the latter coefficients are + precomputed to save memory and time. + + >>> from sympy.ntheory.multinomial import multinomial_coefficients + >>> m53, m33 = multinomial_coefficients(5,3), multinomial_coefficients(3,3) + >>> m53[(0,0,0,1,2)] == m53[(0,0,1,0,2)] == m53[(1,0,2,0,0)] == m33[(0,1,2)] + True + + Examples + ======== + + >>> from sympy.ntheory.multinomial import multinomial_coefficients_iterator + >>> it = multinomial_coefficients_iterator(20,3) + >>> next(it) + ((3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 1) + """ + m = as_int(m) + n = as_int(n) + if m < 2*n or n == 1: + mc = multinomial_coefficients(m, n) + yield from mc.items() + else: + mc = multinomial_coefficients(n, n) + mc1 = {} + for k, v in mc.items(): + mc1[_tuple(filter(None, k))] = v + mc = mc1 + + t = [n] + [0] * (m - 1) + t1 = _tuple(t) + b = _tuple(filter(None, t1)) + yield (t1, mc[b]) + if n: + j = 0 # j will be the leftmost nonzero position + else: + j = m + # enumerate tuples in co-lex order + while j < m - 1: + # compute next tuple + tj = t[j] + if j: + t[j] = 0 + t[0] = tj + if tj > 1: + t[j + 1] += 1 + j = 0 + else: + j += 1 + t[j] += 1 + + t[0] -= 1 + t1 = _tuple(t) + b = _tuple(filter(None, t1)) + yield (t1, mc[b]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/partitions_.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/partitions_.py new file mode 100644 index 0000000000000000000000000000000000000000..953fa9e2fef146b0d3a9baad0ec5e1353ad6f237 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/partitions_.py @@ -0,0 +1,277 @@ +from mpmath.libmp import (fzero, from_int, from_rational, + fone, fhalf, bitcount, to_int, mpf_mul, mpf_div, mpf_sub, + mpf_add, mpf_sqrt, mpf_pi, mpf_cosh_sinh, mpf_cos, mpf_sin) +from .residue_ntheory import _sqrt_mod_prime_power, is_quad_residue +from sympy.utilities.decorator import deprecated +from sympy.utilities.memoization import recurrence_memo + +import math +from itertools import count + +def _pre(): + maxn = 10**5 + global _factor, _totient + _factor = [0]*maxn + _totient = [1]*maxn + lim = int(maxn**0.5) + 5 + for i in range(2, lim): + if _factor[i] == 0: + for j in range(i*i, maxn, i): + if _factor[j] == 0: + _factor[j] = i + for i in range(2, maxn): + if _factor[i] == 0: + _factor[i] = i + _totient[i] = i-1 + continue + x = _factor[i] + y = i//x + if y % x == 0: + _totient[i] = _totient[y]*x + else: + _totient[i] = _totient[y]*(x - 1) + +def _a(n, k, prec): + """ Compute the inner sum in HRR formula [1]_ + + References + ========== + + .. [1] https://msp.org/pjm/1956/6-1/pjm-v6-n1-p18-p.pdf + + """ + if k == 1: + return fone + + k1 = k + e = 0 + p = _factor[k] + while k1 % p == 0: + k1 //= p + e += 1 + k2 = k//k1 # k2 = p^e + v = 1 - 24*n + pi = mpf_pi(prec) + + if k1 == 1: + # k = p^e + if p == 2: + mod = 8*k + v = mod + v % mod + v = (v*pow(9, k - 1, mod)) % mod + m = _sqrt_mod_prime_power(v, 2, e + 3)[0] + arg = mpf_div(mpf_mul( + from_int(4*m), pi, prec), from_int(mod), prec) + return mpf_mul(mpf_mul( + from_int((-1)**e*(2 - (m % 4))), + mpf_sqrt(from_int(k), prec), prec), + mpf_sin(arg, prec), prec) + if p == 3: + mod = 3*k + v = mod + v % mod + if e > 1: + v = (v*pow(64, k//3 - 1, mod)) % mod + m = _sqrt_mod_prime_power(v, 3, e + 1)[0] + arg = mpf_div(mpf_mul(from_int(4*m), pi, prec), + from_int(mod), prec) + return mpf_mul(mpf_mul( + from_int(2*(-1)**(e + 1)*(3 - 2*(m % 3))), + mpf_sqrt(from_int(k//3), prec), prec), + mpf_sin(arg, prec), prec) + v = k + v % k + jacobi3 = -1 if k % 12 in [5, 7] else 1 + if v % p == 0: + if e == 1: + return mpf_mul( + from_int(jacobi3), + mpf_sqrt(from_int(k), prec), prec) + return fzero + if not is_quad_residue(v, p): + return fzero + _phi = p**(e - 1)*(p - 1) + v = (v*pow(576, _phi - 1, k)) + m = _sqrt_mod_prime_power(v, p, e)[0] + arg = mpf_div( + mpf_mul(from_int(4*m), pi, prec), + from_int(k), prec) + return mpf_mul(mpf_mul( + from_int(2*jacobi3), + mpf_sqrt(from_int(k), prec), prec), + mpf_cos(arg, prec), prec) + + if p != 2 or e >= 3: + d1, d2 = math.gcd(k1, 24), math.gcd(k2, 24) + e = 24//(d1*d2) + n1 = ((d2*e*n + (k2**2 - 1)//d1)* + pow(e*k2*k2*d2, _totient[k1] - 1, k1)) % k1 + n2 = ((d1*e*n + (k1**2 - 1)//d2)* + pow(e*k1*k1*d1, _totient[k2] - 1, k2)) % k2 + return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec) + if e == 2: + n1 = ((8*n + 5)*pow(128, _totient[k1] - 1, k1)) % k1 + n2 = (4 + ((n - 2 - (k1**2 - 1)//8)*(k1**2)) % 4) % 4 + return mpf_mul(mpf_mul( + from_int(-1), + _a(n1, k1, prec), prec), + _a(n2, k2, prec)) + n1 = ((8*n + 1)*pow(32, _totient[k1] - 1, k1)) % k1 + n2 = (2 + (n - (k1**2 - 1)//8) % 2) % 2 + return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec) + +def _d(n, j, prec, sq23pi, sqrt8): + """ + Compute the sinh term in the outer sum of the HRR formula. + The constants sqrt(2/3*pi) and sqrt(8) must be precomputed. + """ + j = from_int(j) + pi = mpf_pi(prec) + a = mpf_div(sq23pi, j, prec) + b = mpf_sub(from_int(n), from_rational(1, 24, prec), prec) + c = mpf_sqrt(b, prec) + ch, sh = mpf_cosh_sinh(mpf_mul(a, c), prec) + D = mpf_div( + mpf_sqrt(j, prec), + mpf_mul(mpf_mul(sqrt8, b), pi), prec) + E = mpf_sub(mpf_mul(a, ch), mpf_div(sh, c, prec), prec) + return mpf_mul(D, E) + + +@recurrence_memo([1, 1]) +def _partition_rec(n: int, prev) -> int: + """ Calculate the partition function P(n) + + Parameters + ========== + + n : int + nonnegative integer + + """ + v = 0 + penta = 0 # pentagonal number: 1, 5, 12, ... + for i in count(): + penta += 3*i + 1 + np = n - penta + if np < 0: + break + s = prev[np] + np -= i + 1 + # np = n - gp where gp = generalized pentagonal: 2, 7, 15, ... + if 0 <= np: + s += prev[np] + v += -s if i % 2 else s + return v + + +def _partition(n: int) -> int: + """ Calculate the partition function P(n) + + Parameters + ========== + + n : int + + """ + if n < 0: + return 0 + if (n <= 200_000 and n - _partition_rec.cache_length() < 70 or + _partition_rec.cache_length() == 2 and n < 14_400): + # There will be 2*10**5 elements created here + # and n elements created by partition, so in case we + # are going to be working with small n, we just + # use partition to calculate (and cache) the values + # since lookup is used there while summation, using + # _factor and _totient, will be used below. But we + # only do so if n is relatively close to the length + # of the cache since doing 1 calculation here is about + # the same as adding 70 elements to the cache. In addition, + # the startup here costs about the same as calculating the first + # 14,400 values via partition, so we delay startup here unless n + # is smaller than that. + return _partition_rec(n) + if '_factor' not in globals(): + _pre() + # Estimate number of bits in p(n). This formula could be tidied + pbits = int(( + math.pi*(2*n/3.)**0.5 - + math.log(4*n))/math.log(10) + 1) * \ + math.log2(10) + prec = p = int(pbits*1.1 + 100) + + # find the number of terms needed so rounded sum will be accurate + # using Rademacher's bound M(n, N) for the remainder after a partial + # sum of N terms (https://arxiv.org/pdf/1205.5991.pdf, (1.8)) + c1 = 44*math.pi**2/(225*math.sqrt(3)) + c2 = math.pi*math.sqrt(2)/75 + c3 = math.pi*math.sqrt(2/3) + def _M(n, N): + sqrt = math.sqrt + return c1/sqrt(N) + c2*sqrt(N/(n - 1))*math.sinh(c3*sqrt(n)/N) + big = max(9, math.ceil(n**0.5)) # should be too large (for n > 65, ceil should work) + assert _M(n, big) < 0.5 # else double big until too large + while big > 40 and _M(n, big) < 0.5: + big //= 2 + small = big + big = small*2 + while big - small > 1: + N = (big + small)//2 + if (er := _M(n, N)) < 0.5: + big = N + elif er >= 0.5: + small = N + M = big # done with function M; now have value + + # sanity check for expected size of answer + if M > 10**5: # i.e. M > maxn + raise ValueError("Input too big") # i.e. n > 149832547102 + + # calculate it + s = fzero + sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p) + sqrt8 = mpf_sqrt(from_int(8), p) + for q in range(1, M): + a = _a(n, q, p) + d = _d(n, q, p, sq23pi, sqrt8) + s = mpf_add(s, mpf_mul(a, d), prec) + # On average, the terms decrease rapidly in magnitude. + # Dynamically reducing the precision greatly improves + # performance. + p = bitcount(abs(to_int(d))) + 50 + return int(to_int(mpf_add(s, fhalf, prec))) + + +@deprecated("""\ +The `sympy.ntheory.partitions_.npartitions` has been moved to `sympy.functions.combinatorial.numbers.partition`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def npartitions(n, verbose=False): + """ + Calculate the partition function P(n), i.e. the number of ways that + n can be written as a sum of positive integers. + + .. deprecated:: 1.13 + + The ``npartitions`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.partition` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + P(n) is computed using the Hardy-Ramanujan-Rademacher formula [1]_. + + + The correctness of this implementation has been tested through $10^{10}$. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import partition + >>> partition(25) + 1958 + + References + ========== + + .. [1] https://mathworld.wolfram.com/PartitionFunctionP.html + + """ + from sympy.functions.combinatorial.numbers import partition as func_partition + return func_partition(n) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/primetest.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/primetest.py new file mode 100644 index 0000000000000000000000000000000000000000..ff3cb82cc51bf57ca345a7d72ee715c861f62e2a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/primetest.py @@ -0,0 +1,830 @@ +""" +Primality testing + +""" + +from itertools import count + +from sympy.core.sympify import sympify +from sympy.external.gmpy import (gmpy as _gmpy, gcd, jacobi, + is_square as gmpy_is_square, + bit_scan1, is_fermat_prp, is_euler_prp, + is_selfridge_prp, is_strong_selfridge_prp, + is_strong_bpsw_prp) +from sympy.external.ntheory import _lucas_sequence +from sympy.utilities.misc import as_int, filldedent + +# Note: This list should be updated whenever new Mersenne primes are found. +# Refer: https://www.mersenne.org/ +MERSENNE_PRIME_EXPONENTS = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, + 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049, + 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917, 20996011, 24036583, + 25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933, + 136279841) + + +def is_fermat_pseudoprime(n, a): + r"""Returns True if ``n`` is prime or is an odd composite integer that + is coprime to ``a`` and satisfy the modular arithmetic congruence relation: + + .. math :: + a^{n-1} \equiv 1 \pmod{n} + + (where mod refers to the modulo operation). + + Parameters + ========== + + n : Integer + ``n`` is a positive integer. + a : Integer + ``a`` is a positive integer. + ``a`` and ``n`` should be relatively prime. + + Returns + ======= + + bool : If ``n`` is prime, it always returns ``True``. + The composite number that returns ``True`` is called an Fermat pseudoprime. + + Examples + ======== + + >>> from sympy.ntheory.primetest import is_fermat_pseudoprime + >>> from sympy.ntheory.factor_ import isprime + >>> for n in range(1, 1000): + ... if is_fermat_pseudoprime(n, 2) and not isprime(n): + ... print(n) + 341 + 561 + 645 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Fermat_pseudoprime + """ + n, a = as_int(n), as_int(a) + if a == 1: + return n == 2 or bool(n % 2) + return is_fermat_prp(n, a) + + +def is_euler_pseudoprime(n, a): + r"""Returns True if ``n`` is prime or is an odd composite integer that + is coprime to ``a`` and satisfy the modular arithmetic congruence relation: + + .. math :: + a^{(n-1)/2} \equiv \pm 1 \pmod{n} + + (where mod refers to the modulo operation). + + Parameters + ========== + + n : Integer + ``n`` is a positive integer. + a : Integer + ``a`` is a positive integer. + ``a`` and ``n`` should be relatively prime. + + Returns + ======= + + bool : If ``n`` is prime, it always returns ``True``. + The composite number that returns ``True`` is called an Euler pseudoprime. + + Examples + ======== + + >>> from sympy.ntheory.primetest import is_euler_pseudoprime + >>> from sympy.ntheory.factor_ import isprime + >>> for n in range(1, 1000): + ... if is_euler_pseudoprime(n, 2) and not isprime(n): + ... print(n) + 341 + 561 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Euler_pseudoprime + """ + n, a = as_int(n), as_int(a) + if a < 1: + raise ValueError("a should be an integer greater than 0") + if n < 1: + raise ValueError("n should be an integer greater than 0") + if n == 1: + return False + if a == 1: + return n == 2 or bool(n % 2) # (prime or odd composite) + if n % 2 == 0: + return n == 2 + if gcd(n, a) != 1: + raise ValueError("The two numbers should be relatively prime") + return pow(a, (n - 1) // 2, n) in [1, n - 1] + + +def is_euler_jacobi_pseudoprime(n, a): + r"""Returns True if ``n`` is prime or is an odd composite integer that + is coprime to ``a`` and satisfy the modular arithmetic congruence relation: + + .. math :: + a^{(n-1)/2} \equiv \left(\frac{a}{n}\right) \pmod{n} + + (where mod refers to the modulo operation). + + Parameters + ========== + + n : Integer + ``n`` is a positive integer. + a : Integer + ``a`` is a positive integer. + ``a`` and ``n`` should be relatively prime. + + Returns + ======= + + bool : If ``n`` is prime, it always returns ``True``. + The composite number that returns ``True`` is called an Euler-Jacobi pseudoprime. + + Examples + ======== + + >>> from sympy.ntheory.primetest import is_euler_jacobi_pseudoprime + >>> from sympy.ntheory.factor_ import isprime + >>> for n in range(1, 1000): + ... if is_euler_jacobi_pseudoprime(n, 2) and not isprime(n): + ... print(n) + 561 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Euler%E2%80%93Jacobi_pseudoprime + """ + n, a = as_int(n), as_int(a) + if a == 1: + return n == 2 or bool(n % 2) + return is_euler_prp(n, a) + + +def is_square(n, prep=True): + """Return True if n == a * a for some integer a, else False. + If n is suspected of *not* being a square then this is a + quick method of confirming that it is not. + + Examples + ======== + + >>> from sympy.ntheory.primetest import is_square + >>> is_square(25) + True + >>> is_square(2) + False + + References + ========== + + .. [1] https://mersenneforum.org/showpost.php?p=110896 + + See Also + ======== + sympy.core.intfunc.isqrt + """ + if prep: + n = as_int(n) + if n < 0: + return False + if n in (0, 1): + return True + return gmpy_is_square(n) + + +def _test(n, base, s, t): + """Miller-Rabin strong pseudoprime test for one base. + Return False if n is definitely composite, True if n is + probably prime, with a probability greater than 3/4. + + """ + # do the Fermat test + b = pow(base, t, n) + if b == 1 or b == n - 1: + return True + for _ in range(s - 1): + b = pow(b, 2, n) + if b == n - 1: + return True + # see I. Niven et al. "An Introduction to Theory of Numbers", page 78 + if b == 1: + return False + return False + + +def mr(n, bases): + """Perform a Miller-Rabin strong pseudoprime test on n using a + given list of bases/witnesses. + + References + ========== + + .. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers: + A Computational Perspective", Springer, 2nd edition, 135-138 + + A list of thresholds and the bases they require are here: + https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants + + Examples + ======== + + >>> from sympy.ntheory.primetest import mr + >>> mr(1373651, [2, 3]) + False + >>> mr(479001599, [31, 73]) + True + + """ + from sympy.polys.domains import ZZ + + n = as_int(n) + if n < 2 or (n > 2 and n % 2 == 0): + return False + # remove powers of 2 from n-1 (= t * 2**s) + s = bit_scan1(n - 1) + t = n >> s + for base in bases: + # Bases >= n are wrapped, bases < 2 are invalid + if base >= n: + base %= n + if base >= 2: + base = ZZ(base) + if not _test(n, base, s, t): + return False + return True + + +def _lucas_extrastrong_params(n): + """Calculates the "extra strong" parameters (D, P, Q) for n. + + Parameters + ========== + + n : int + positive odd integer + + Returns + ======= + + D, P, Q: "extra strong" parameters. + ``(0, 0, 0)`` if we find a nontrivial divisor of ``n``. + + Examples + ======== + + >>> from sympy.ntheory.primetest import _lucas_extrastrong_params + >>> _lucas_extrastrong_params(101) + (12, 4, 1) + >>> _lucas_extrastrong_params(15) + (0, 0, 0) + + References + ========== + .. [1] OEIS A217719: Extra Strong Lucas Pseudoprimes + https://oeis.org/A217719 + .. [2] https://en.wikipedia.org/wiki/Lucas_pseudoprime + + """ + for P in count(3): + D = P**2 - 4 + j = jacobi(D, n) + if j == -1: + return (D, P, 1) + elif j == 0 and D % n: + return (0, 0, 0) + + +def is_lucas_prp(n): + """Standard Lucas compositeness test with Selfridge parameters. Returns + False if n is definitely composite, and True if n is a Lucas probable + prime. + + This is typically used in combination with the Miller-Rabin test. + + References + ========== + .. [1] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes, + Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417, + https://doi.org/10.1090%2FS0025-5718-1980-0583518-6 + http://mpqs.free.fr/LucasPseudoprimes.pdf + .. [2] OEIS A217120: Lucas Pseudoprimes + https://oeis.org/A217120 + .. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime + + Examples + ======== + + >>> from sympy.ntheory.primetest import isprime, is_lucas_prp + >>> for i in range(10000): + ... if is_lucas_prp(i) and not isprime(i): + ... print(i) + 323 + 377 + 1159 + 1829 + 3827 + 5459 + 5777 + 9071 + 9179 + """ + n = as_int(n) + if n < 2: + return False + return is_selfridge_prp(n) + + +def is_strong_lucas_prp(n): + """Strong Lucas compositeness test with Selfridge parameters. Returns + False if n is definitely composite, and True if n is a strong Lucas + probable prime. + + This is often used in combination with the Miller-Rabin test, and + in particular, when combined with M-R base 2 creates the strong BPSW test. + + References + ========== + .. [1] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes, + Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417, + https://doi.org/10.1090%2FS0025-5718-1980-0583518-6 + http://mpqs.free.fr/LucasPseudoprimes.pdf + .. [2] OEIS A217255: Strong Lucas Pseudoprimes + https://oeis.org/A217255 + .. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime + .. [4] https://en.wikipedia.org/wiki/Baillie-PSW_primality_test + + Examples + ======== + + >>> from sympy.ntheory.primetest import isprime, is_strong_lucas_prp + >>> for i in range(20000): + ... if is_strong_lucas_prp(i) and not isprime(i): + ... print(i) + 5459 + 5777 + 10877 + 16109 + 18971 + """ + n = as_int(n) + if n < 2: + return False + return is_strong_selfridge_prp(n) + + +def is_extra_strong_lucas_prp(n): + """Extra Strong Lucas compositeness test. Returns False if n is + definitely composite, and True if n is an "extra strong" Lucas probable + prime. + + The parameters are selected using P = 3, Q = 1, then incrementing P until + (D|n) == -1. The test itself is as defined in [1]_, from the + Mo and Jones preprint. The parameter selection and test are the same as + used in OEIS A217719, Perl's Math::Prime::Util, and the Lucas pseudoprime + page on Wikipedia. + + It is 20-50% faster than the strong test. + + Because of the different parameters selected, there is no relationship + between the strong Lucas pseudoprimes and extra strong Lucas pseudoprimes. + In particular, one is not a subset of the other. + + References + ========== + .. [1] Jon Grantham, Frobenius Pseudoprimes, + Math. Comp. Vol 70, Number 234 (2001), pp. 873-891, + https://doi.org/10.1090%2FS0025-5718-00-01197-2 + .. [2] OEIS A217719: Extra Strong Lucas Pseudoprimes + https://oeis.org/A217719 + .. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime + + Examples + ======== + + >>> from sympy.ntheory.primetest import isprime, is_extra_strong_lucas_prp + >>> for i in range(20000): + ... if is_extra_strong_lucas_prp(i) and not isprime(i): + ... print(i) + 989 + 3239 + 5777 + 10877 + """ + # Implementation notes: + # 1) the parameters differ from Thomas R. Nicely's. His parameter + # selection leads to pseudoprimes that overlap M-R tests, and + # contradict Baillie and Wagstaff's suggestion of (D|n) = -1. + # 2) The MathWorld page as of June 2013 specifies Q=-1. The Lucas + # sequence must have Q=1. See Grantham theorem 2.3, any of the + # references on the MathWorld page, or run it and see Q=-1 is wrong. + n = as_int(n) + if n == 2: + return True + if n < 2 or (n % 2) == 0: + return False + if gmpy_is_square(n): + return False + + D, P, Q = _lucas_extrastrong_params(n) + if D == 0: + return False + + # remove powers of 2 from n+1 (= k * 2**s) + s = bit_scan1(n + 1) + k = (n + 1) >> s + + U, V, _ = _lucas_sequence(n, P, Q, k) + + if U == 0 and (V == 2 or V == n - 2): + return True + for _ in range(1, s): + if V == 0: + return True + V = (V*V - 2) % n + return False + + +def proth_test(n): + r""" Test if the Proth number `n = k2^m + 1` is prime. where k is a positive odd number and `2^m > k`. + + Parameters + ========== + + n : Integer + ``n`` is Proth number + + Returns + ======= + + bool : If ``True``, then ``n`` is the Proth prime + + Raises + ====== + + ValueError + If ``n`` is not Proth number. + + Examples + ======== + + >>> from sympy.ntheory.primetest import proth_test + >>> proth_test(41) + True + >>> proth_test(57) + False + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Proth_prime + + """ + n = as_int(n) + if n < 3: + raise ValueError("n is not Proth number") + m = bit_scan1(n - 1) + k = n >> m + if m < k.bit_length(): + raise ValueError("n is not Proth number") + if n % 3 == 0: + return n == 3 + if k % 3: # n % 12 == 5 + return pow(3, n >> 1, n) == n - 1 + # If `n` is a square number, then `jacobi(a, n) = 1` for any `a` + if gmpy_is_square(n): + return False + # `a` may be chosen at random. + # In any case, we want to find `a` such that `jacobi(a, n) = -1`. + for a in range(5, n): + j = jacobi(a, n) + if j == -1: + return pow(a, n >> 1, n) == n - 1 + if j == 0: + return False + + +def _lucas_lehmer_primality_test(p): + r""" Test if the Mersenne number `M_p = 2^p-1` is prime. + + Parameters + ========== + + p : int + ``p`` is an odd prime number + + Returns + ======= + + bool : If ``True``, then `M_p` is the Mersenne prime + + Examples + ======== + + >>> from sympy.ntheory.primetest import _lucas_lehmer_primality_test + >>> _lucas_lehmer_primality_test(5) # 2**5 - 1 = 31 is prime + True + >>> _lucas_lehmer_primality_test(11) # 2**11 - 1 = 2047 is not prime + False + + See Also + ======== + + is_mersenne_prime + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Lucas%E2%80%93Lehmer_primality_test + + """ + v = 4 + m = 2**p - 1 + for _ in range(p - 2): + v = pow(v, 2, m) - 2 + return v == 0 + + +def is_mersenne_prime(n): + """Returns True if ``n`` is a Mersenne prime, else False. + + A Mersenne prime is a prime number having the form `2^i - 1`. + + Examples + ======== + + >>> from sympy.ntheory.factor_ import is_mersenne_prime + >>> is_mersenne_prime(6) + False + >>> is_mersenne_prime(127) + True + + References + ========== + + .. [1] https://mathworld.wolfram.com/MersennePrime.html + + """ + n = as_int(n) + if n < 1: + return False + if n & (n + 1): + # n is not Mersenne number + return False + p = n.bit_length() + if p in MERSENNE_PRIME_EXPONENTS: + return True + if p < 65_000_000 or not isprime(p): + # According to GIMPS, verification was completed on September 19, 2023 for p less than 65 million. + # https://www.mersenne.org/report_milestones/ + # If p is composite number, then n=2**p-1 is composite number. + return False + result = _lucas_lehmer_primality_test(p) + if result: + raise ValueError(filldedent(''' + This Mersenne Prime, 2^%s - 1, should + be added to SymPy's known values.''' % p)) + return result + + +_MR_BASES_32 = [15591, 2018, 166, 7429, 8064, 16045, 10503, 4399, 1949, 1295, + 2776, 3620, 560, 3128, 5212, 2657, 2300, 2021, 4652, 1471, + 9336, 4018, 2398, 20462, 10277, 8028, 2213, 6219, 620, 3763, + 4852, 5012, 3185, 1333, 6227,5298, 1074, 2391, 5113, 7061, + 803, 1269, 3875, 422, 751, 580, 4729, 10239, 746, 2951, 556, + 2206, 3778, 481, 1522, 3476, 481, 2487, 3266, 5633, 488, 3373, + 6441, 3344, 17, 15105, 1490, 4154, 2036, 1882, 1813, 467, + 3307, 14042, 6371, 658, 1005, 903, 737, 1887, 7447, 1888, + 2848, 1784, 7559, 3400, 951, 13969, 4304, 177, 41, 19875, + 3110, 13221, 8726, 571, 7043, 6943, 1199, 352, 6435, 165, + 1169, 3315, 978, 233, 3003, 2562, 2994, 10587, 10030, 2377, + 1902, 5354, 4447, 1555, 263, 27027, 2283, 305, 669, 1912, 601, + 6186, 429, 1930, 14873, 1784, 1661, 524, 3577, 236, 2360, + 6146, 2850, 55637, 1753, 4178, 8466, 222, 2579, 2743, 2031, + 2226, 2276, 374, 2132, 813, 23788, 1610, 4422, 5159, 1725, + 3597, 3366, 14336, 579, 165, 1375, 10018, 12616, 9816, 1371, + 536, 1867, 10864, 857, 2206, 5788, 434, 8085, 17618, 727, + 3639, 1595, 4944, 2129, 2029, 8195, 8344, 6232, 9183, 8126, + 1870, 3296, 7455, 8947, 25017, 541, 19115, 368, 566, 5674, + 411, 522, 1027, 8215, 2050, 6544, 10049, 614, 774, 2333, 3007, + 35201, 4706, 1152, 1785, 1028, 1540, 3743, 493, 4474, 2521, + 26845, 8354, 864, 18915, 5465, 2447, 42, 4511, 1660, 166, + 1249, 6259, 2553, 304, 272, 7286, 73, 6554, 899, 2816, 5197, + 13330, 7054, 2818, 3199, 811, 922, 350, 7514, 4452, 3449, + 2663, 4708, 418, 1621, 1171, 3471, 88, 11345, 412, 1559, 194] + + +def isprime(n): + """ + Test if n is a prime number (True) or not (False). For n < 2^64 the + answer is definitive; larger n values have a small probability of actually + being pseudoprimes. + + Negative numbers (e.g. -2) are not considered prime. + + The first step is looking for trivial factors, which if found enables + a quick return. Next, if the sieve is large enough, use bisection search + on the sieve. For small numbers, a set of deterministic Miller-Rabin + tests are performed with bases that are known to have no counterexamples + in their range. Finally if the number is larger than 2^64, a strong + BPSW test is performed. While this is a probable prime test and we + believe counterexamples exist, there are no known counterexamples. + + Examples + ======== + + >>> from sympy.ntheory import isprime + >>> isprime(13) + True + >>> isprime(15) + False + + Notes + ===== + + This routine is intended only for integer input, not numerical + expressions which may represent numbers. Floats are also + rejected as input because they represent numbers of limited + precision. While it is tempting to permit 7.0 to represent an + integer there are errors that may "pass silently" if this is + allowed: + + >>> from sympy import Float, S + >>> int(1e3) == 1e3 == 10**3 + True + >>> int(1e23) == 1e23 + True + >>> int(1e23) == 10**23 + False + + >>> near_int = 1 + S(1)/10**19 + >>> near_int == int(near_int) + False + >>> n = Float(near_int, 10) # truncated by precision + >>> n % 1 == 0 + True + >>> n = Float(near_int, 20) + >>> n % 1 == 0 + False + + See Also + ======== + + sympy.ntheory.generate.primerange : Generates all primes in a given range + sympy.functions.combinatorial.numbers.primepi : Return the number of primes less than or equal to n + sympy.ntheory.generate.prime : Return the nth prime + + References + ========== + .. [1] https://en.wikipedia.org/wiki/Strong_pseudoprime + .. [2] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes, + Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417, + https://doi.org/10.1090%2FS0025-5718-1980-0583518-6 + http://mpqs.free.fr/LucasPseudoprimes.pdf + .. [3] https://en.wikipedia.org/wiki/Baillie-PSW_primality_test + """ + n = as_int(n) + + # Step 1, do quick composite testing via trial division. The individual + # modulo tests benchmark faster than one or two primorial igcds for me. + # The point here is just to speedily handle small numbers and many + # composites. Step 2 only requires that n <= 2 get handled here. + if n in [2, 3, 5]: + return True + if n < 2 or (n % 2) == 0 or (n % 3) == 0 or (n % 5) == 0: + return False + if n < 49: + return True + if (n % 7) == 0 or (n % 11) == 0 or (n % 13) == 0 or (n % 17) == 0 or \ + (n % 19) == 0 or (n % 23) == 0 or (n % 29) == 0 or (n % 31) == 0 or \ + (n % 37) == 0 or (n % 41) == 0 or (n % 43) == 0 or (n % 47) == 0: + return False + if n < 2809: + return True + if n < 65077: + # There are only five Euler pseudoprimes with a least prime factor greater than 47 + return pow(2, n >> 1, n) in [1, n - 1] and n not in [8321, 31621, 42799, 49141, 49981] + + # bisection search on the sieve if the sieve is large enough + from sympy.ntheory.generate import sieve as s + if n <= s._list[-1]: + l, u = s.search(n) + return l == u + from sympy.ntheory.factor_ import factor_cache + if (ret := factor_cache.get(n)) is not None: + return ret == n + + # If we have GMPY2, skip straight to step 3 and do a strong BPSW test. + # This should be a bit faster than our step 2, and for large values will + # be a lot faster than our step 3 (C+GMP vs. Python). + if _gmpy is not None: + return is_strong_bpsw_prp(n) + + + # Step 2: deterministic Miller-Rabin testing for numbers < 2^64. See: + # https://miller-rabin.appspot.com/ + # for lists. We have made sure the M-R routine will successfully handle + # bases larger than n, so we can use the minimal set. + # In September 2015 deterministic numbers were extended to over 2^81. + # https://arxiv.org/pdf/1509.00864.pdf + # https://oeis.org/A014233 + if n < 341531: + return mr(n, [9345883071009581737]) + if n < 4296595241: + # Michal Forisek and Jakub Jancina, + # Fast Primality Testing for Integers That Fit into a Machine Word + # https://ceur-ws.org/Vol-1326/020-Forisek.pdf + h = ((n >> 16) ^ n) * 0x45d9f3b + h = ((h >> 16) ^ h) * 0x45d9f3b + h = ((h >> 16) ^ h) & 255 + return mr(n, [_MR_BASES_32[h]]) + if n < 350269456337: + return mr(n, [4230279247111683200, 14694767155120705706, 16641139526367750375]) + if n < 55245642489451: + return mr(n, [2, 141889084524735, 1199124725622454117, 11096072698276303650]) + if n < 7999252175582851: + return mr(n, [2, 4130806001517, 149795463772692060, 186635894390467037, 3967304179347715805]) + if n < 585226005592931977: + return mr(n, [2, 123635709730000, 9233062284813009, 43835965440333360, 761179012939631437, 1263739024124850375]) + if n < 18446744073709551616: + return mr(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022]) + if n < 318665857834031151167461: + return mr(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]) + if n < 3317044064679887385961981: + return mr(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]) + + # We could do this instead at any point: + #if n < 18446744073709551616: + # return mr(n, [2]) and is_extra_strong_lucas_prp(n) + + # Here are tests that are safe for MR routines that don't understand + # large bases. + #if n < 9080191: + # return mr(n, [31, 73]) + #if n < 19471033: + # return mr(n, [2, 299417]) + #if n < 38010307: + # return mr(n, [2, 9332593]) + #if n < 316349281: + # return mr(n, [11000544, 31481107]) + #if n < 4759123141: + # return mr(n, [2, 7, 61]) + #if n < 105936894253: + # return mr(n, [2, 1005905886, 1340600841]) + #if n < 31858317218647: + # return mr(n, [2, 642735, 553174392, 3046413974]) + #if n < 3071837692357849: + # return mr(n, [2, 75088, 642735, 203659041, 3613982119]) + #if n < 18446744073709551616: + # return mr(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022]) + + # Step 3: BPSW. + # + # Time for isprime(10**2000 + 4561), no gmpy or gmpy2 installed + # 44.0s old isprime using 46 bases + # 5.3s strong BPSW + one random base + # 4.3s extra strong BPSW + one random base + # 4.1s strong BPSW + # 3.2s extra strong BPSW + + # Classic BPSW from page 1401 of the paper. See alternate ideas below. + return is_strong_bpsw_prp(n) + + # Using extra strong test, which is somewhat faster + #return mr(n, [2]) and is_extra_strong_lucas_prp(n) + + # Add a random M-R base + #import random + #return mr(n, [2, random.randint(3, n-1)]) and is_strong_lucas_prp(n) + + +def is_gaussian_prime(num): + r"""Test if num is a Gaussian prime number. + + References + ========== + + .. [1] https://oeis.org/wiki/Gaussian_primes + """ + + num = sympify(num) + a, b = num.as_real_imag() + a = as_int(a, strict=False) + b = as_int(b, strict=False) + if a == 0: + b = abs(b) + return isprime(b) and b % 4 == 3 + elif b == 0: + a = abs(a) + return isprime(a) and a % 4 == 3 + return isprime(a**2 + b**2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/qs.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/qs.py new file mode 100644 index 0000000000000000000000000000000000000000..acc9a7b6e0151695538a99a738ef397166497ba5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/qs.py @@ -0,0 +1,451 @@ +from math import exp, log +from sympy.core.random import _randint +from sympy.external.gmpy import bit_scan1, gcd, invert, sqrt as isqrt +from sympy.ntheory.factor_ import _perfect_power +from sympy.ntheory.primetest import isprime +from sympy.ntheory.residue_ntheory import _sqrt_mod_prime_power + + +class SievePolynomial: + def __init__(self, a, b, N): + """This class denotes the sieve polynomial. + Provide methods to compute `(a*x + b)**2 - N` and + `a*x + b` when given `x`. + + Parameters + ========== + + a : parameter of the sieve polynomial + b : parameter of the sieve polynomial + N : number to be factored + + """ + self.a = a + self.b = b + self.a2 = a**2 + self.ab = 2*a*b + self.b2 = b**2 - N + + def eval_u(self, x): + return self.a*x + self.b + + def eval_v(self, x): + return (self.a2*x + self.ab)*x + self.b2 + + +class FactorBaseElem: + """This class stores an element of the `factor_base`. + """ + def __init__(self, prime, tmem_p, log_p): + """ + Initialization of factor_base_elem. + + Parameters + ========== + + prime : prime number of the factor_base + tmem_p : Integer square root of x**2 = n mod prime + log_p : Compute Natural Logarithm of the prime + """ + self.prime = prime + self.tmem_p = tmem_p + self.log_p = log_p + # `soln1` and `soln2` are solutions to + # the equation `(a*x + b)**2 - N = 0 (mod p)`. + self.soln1 = None + self.soln2 = None + self.b_ainv = None + + +def _generate_factor_base(prime_bound, n): + """Generate `factor_base` for Quadratic Sieve. The `factor_base` + consists of all the points whose ``legendre_symbol(n, p) == 1`` + and ``p < num_primes``. Along with the prime `factor_base` also stores + natural logarithm of prime and the residue n modulo p. + It also returns the of primes numbers in the `factor_base` which are + close to 1000 and 5000. + + Parameters + ========== + + prime_bound : upper prime bound of the factor_base + n : integer to be factored + """ + from sympy.ntheory.generate import sieve + factor_base = [] + idx_1000, idx_5000 = None, None + for prime in sieve.primerange(1, prime_bound): + if pow(n, (prime - 1) // 2, prime) == 1: + if prime > 1000 and idx_1000 is None: + idx_1000 = len(factor_base) - 1 + if prime > 5000 and idx_5000 is None: + idx_5000 = len(factor_base) - 1 + residue = _sqrt_mod_prime_power(n, prime, 1)[0] + log_p = round(log(prime)*2**10) + factor_base.append(FactorBaseElem(prime, residue, log_p)) + return idx_1000, idx_5000, factor_base + + +def _generate_polynomial(N, M, factor_base, idx_1000, idx_5000, randint): + """ Generate sieve polynomials indefinitely. + Information such as `soln1` in the `factor_base` associated with + the polynomial is modified in place. + + Parameters + ========== + + N : Number to be factored + M : sieve interval + factor_base : factor_base primes + idx_1000 : index of prime number in the factor_base near 1000 + idx_5000 : index of prime number in the factor_base near to 5000 + randint : A callable that takes two integers (a, b) and returns a random integer + n such that a <= n <= b, similar to `random.randint`. + """ + approx_val = log(2*N)/2 - log(M) + start = idx_1000 or 0 + end = idx_5000 or (len(factor_base) - 1) + while True: + # Choose `a` that is close to `sqrt(2*N) / M` + best_a, best_q, best_ratio = None, None, None + for _ in range(50): + a = 1 + q = [] + while log(a) < approx_val: + rand_p = 0 + while(rand_p == 0 or rand_p in q): + rand_p = randint(start, end) + p = factor_base[rand_p].prime + a *= p + q.append(rand_p) + ratio = exp(log(a) - approx_val) + if best_ratio is None or abs(ratio - 1) < abs(best_ratio - 1): + best_q = q + best_a = a + best_ratio = ratio + + # Set `b` using the Chinese remainder theorem + a = best_a + q = best_q + B = [] + for val in q: + q_l = factor_base[val].prime + gamma = factor_base[val].tmem_p * invert(a // q_l, q_l) % q_l + if 2*gamma > q_l: + gamma = q_l - gamma + B.append(a//q_l*gamma) + b = sum(B) + g = SievePolynomial(a, b, N) + for fb in factor_base: + if a % fb.prime == 0: + fb.soln1 = None + continue + a_inv = invert(a, fb.prime) + fb.b_ainv = [2*b_elem*a_inv % fb.prime for b_elem in B] + fb.soln1 = (a_inv*(fb.tmem_p - b)) % fb.prime + fb.soln2 = (a_inv*(-fb.tmem_p - b)) % fb.prime + yield g + + # Update `b` with Gray code + for i in range(1, 2**(len(B)-1)): + v = bit_scan1(i) + neg_pow = 2*((i >> (v + 1)) % 2) - 1 + b = g.b + 2*neg_pow*B[v] + a = g.a + g = SievePolynomial(a, b, N) + for fb in factor_base: + if fb.soln1 is None: + continue + fb.soln1 = (fb.soln1 - neg_pow*fb.b_ainv[v]) % fb.prime + fb.soln2 = (fb.soln2 - neg_pow*fb.b_ainv[v]) % fb.prime + yield g + + +def _gen_sieve_array(M, factor_base): + """Sieve Stage of the Quadratic Sieve. For every prime in the factor_base + that does not divide the coefficient `a` we add log_p over the sieve_array + such that ``-M <= soln1 + i*p <= M`` and ``-M <= soln2 + i*p <= M`` where `i` + is an integer. When p = 2 then log_p is only added using + ``-M <= soln1 + i*p <= M``. + + Parameters + ========== + + M : sieve interval + factor_base : factor_base primes + """ + sieve_array = [0]*(2*M + 1) + for factor in factor_base: + if factor.soln1 is None: #The prime does not divides a + continue + for idx in range((M + factor.soln1) % factor.prime, 2*M, factor.prime): + sieve_array[idx] += factor.log_p + if factor.prime == 2: + continue + #if prime is 2 then sieve only with soln_1_p + for idx in range((M + factor.soln2) % factor.prime, 2*M, factor.prime): + sieve_array[idx] += factor.log_p + return sieve_array + + +def _check_smoothness(num, factor_base): + r""" Check if `num` is smooth with respect to the given `factor_base` + and compute its factorization vector. + + Parameters + ========== + + num : integer whose smootheness is to be checked + factor_base : factor_base primes + """ + if num < 0: + num *= -1 + vec = 1 + else: + vec = 0 + for i, fb in enumerate(factor_base, 1): + if num % fb.prime: + continue + e = 1 + num //= fb.prime + while num % fb.prime == 0: + e += 1 + num //= fb.prime + if e % 2: + vec += 1 << i + return vec, num + + +def _trial_division_stage(N, M, factor_base, sieve_array, sieve_poly, partial_relations, ERROR_TERM): + """Trial division stage. Here we trial divide the values generetated + by sieve_poly in the sieve interval and if it is a smooth number then + it is stored in `smooth_relations`. Moreover, if we find two partial relations + with same large prime then they are combined to form a smooth relation. + First we iterate over sieve array and look for values which are greater + than accumulated_val, as these values have a high chance of being smooth + number. Then using these values we find smooth relations. + In general, let ``t**2 = u*p modN`` and ``r**2 = v*p modN`` be two partial relations + with the same large prime p. Then they can be combined ``(t*r/p)**2 = u*v modN`` + to form a smooth relation. + + Parameters + ========== + + N : Number to be factored + M : sieve interval + factor_base : factor_base primes + sieve_array : stores log_p values + sieve_poly : polynomial from which we find smooth relations + partial_relations : stores partial relations with one large prime + ERROR_TERM : error term for accumulated_val + """ + accumulated_val = (log(M) + log(N)/2 - ERROR_TERM) * 2**10 + smooth_relations = [] + proper_factor = set() + partial_relation_upper_bound = 128*factor_base[-1].prime + for x, val in enumerate(sieve_array, -M): + if val < accumulated_val: + continue + v = sieve_poly.eval_v(x) + vec, num = _check_smoothness(v, factor_base) + if num == 1: + smooth_relations.append((sieve_poly.eval_u(x), v, vec)) + elif num < partial_relation_upper_bound and isprime(num): + if N % num == 0: + proper_factor.add(num) + continue + u = sieve_poly.eval_u(x) + if num in partial_relations: + u_prev, v_prev, vec_prev = partial_relations.pop(num) + u = u*u_prev*invert(num, N) % N + v = v*v_prev // num**2 + vec ^= vec_prev + smooth_relations.append((u, v, vec)) + else: + partial_relations[num] = (u, v, vec) + return smooth_relations, proper_factor + + +def _find_factor(N, smooth_relations, col): + """ Finds proper factor of N using fast gaussian reduction for modulo 2 matrix. + + Parameters + ========== + + N : Number to be factored + smooth_relations : Smooth relations vectors matrix + col : Number of columns in the matrix + + Reference + ========== + + .. [1] A fast algorithm for gaussian elimination over GF(2) and + its implementation on the GAPP. Cetin K.Koc, Sarath N.Arachchige + """ + matrix = [s_relation[2] for s_relation in smooth_relations] + row = len(matrix) + mark = [False] * row + for pos in range(col): + m = 1 << pos + for i in range(row): + if p := matrix[i] & m: + add_col = p ^ matrix[i] + matrix[i] = m + mark[i] = True + for j in range(i + 1, row): + if matrix[j] & m: + matrix[j] ^= add_col + break + + for m, mat, rel in zip(mark, matrix, smooth_relations): + if m: + continue + u, v = rel[0], rel[1] + for m1, mat1, rel1 in zip(mark, matrix, smooth_relations): + if m1 and mat & mat1: + u *= rel1[0] + v *= rel1[1] + # assert is_square(v) + v = isqrt(v) + if 1 < (g := gcd(u - v, N)) < N: + yield g + + +def qs(N, prime_bound, M, ERROR_TERM=25, seed=1234): + """Performs factorization using Self-Initializing Quadratic Sieve. + In SIQS, let N be a number to be factored, and this N should not be a + perfect power. If we find two integers such that ``X**2 = Y**2 modN`` and + ``X != +-Y modN``, then `gcd(X + Y, N)` will reveal a proper factor of N. + In order to find these integers X and Y we try to find relations of form + t**2 = u modN where u is a product of small primes. If we have enough of + these relations then we can form ``(t1*t2...ti)**2 = u1*u2...ui modN`` such that + the right hand side is a square, thus we found a relation of ``X**2 = Y**2 modN``. + + Here, several optimizations are done like using multiple polynomials for + sieving, fast changing between polynomials and using partial relations. + The use of partial relations can speeds up the factoring by 2 times. + + Parameters + ========== + + N : Number to be Factored + prime_bound : upper bound for primes in the factor base + M : Sieve Interval + ERROR_TERM : Error term for checking smoothness + seed : seed of random number generator + + Returns + ======= + + set(int) : A set of factors of N without considering multiplicity. + Returns ``{N}`` if factorization fails. + + Examples + ======== + + >>> from sympy.ntheory import qs + >>> qs(25645121643901801, 2000, 10000) + {5394769, 4753701529} + >>> qs(9804659461513846513, 2000, 10000) + {4641991, 2112166839943} + + See Also + ======== + + qs_factor + + References + ========== + + .. [1] https://pdfs.semanticscholar.org/5c52/8a975c1405bd35c65993abf5a4edb667c1db.pdf + .. [2] https://www.rieselprime.de/ziki/Self-initializing_quadratic_sieve + """ + return set(qs_factor(N, prime_bound, M, ERROR_TERM, seed)) + + +def qs_factor(N, prime_bound, M, ERROR_TERM=25, seed=1234): + """ Performs factorization using Self-Initializing Quadratic Sieve. + + Parameters + ========== + + N : Number to be Factored + prime_bound : upper bound for primes in the factor base + M : Sieve Interval + ERROR_TERM : Error term for checking smoothness + seed : seed of random number generator + + Returns + ======= + + dict[int, int] : Factors of N. + Returns ``{N: 1}`` if factorization fails. + Note that the key is not always a prime number. + + Examples + ======== + + >>> from sympy.ntheory import qs_factor + >>> qs_factor(1009 * 100003, 2000, 10000) + {1009: 1, 100003: 1} + + See Also + ======== + + qs + + """ + if N < 2: + raise ValueError("N should be greater than 1") + factors = {} + smooth_relations = [] + partial_relations = {} + # Eliminate the possibility of even numbers, + # prime numbers, and perfect powers. + if N % 2 == 0: + e = 1 + N //= 2 + while N % 2 == 0: + N //= 2 + e += 1 + factors[2] = e + if isprime(N): + factors[N] = 1 + return factors + if result := _perfect_power(N, 3): + n, e = result + factors[n] = e + return factors + N_copy = N + randint = _randint(seed) + idx_1000, idx_5000, factor_base = _generate_factor_base(prime_bound, N) + threshold = len(factor_base) * 105//100 + for g in _generate_polynomial(N, M, factor_base, idx_1000, idx_5000, randint): + sieve_array = _gen_sieve_array(M, factor_base) + s_rel, p_f = _trial_division_stage(N, M, factor_base, sieve_array, g, partial_relations, ERROR_TERM) + smooth_relations += s_rel + for p in p_f: + if N_copy % p: + continue + e = 1 + N_copy //= p + while N_copy % p == 0: + N_copy //= p + e += 1 + factors[p] = e + if threshold <= len(smooth_relations): + break + + for factor in _find_factor(N, smooth_relations, len(factor_base) + 1): + if N_copy % factor == 0: + e = 1 + N_copy //= factor + while N_copy % factor == 0: + N_copy //= factor + e += 1 + factors[factor] = e + if N_copy == 1 or isprime(N_copy): + break + if N_copy != 1: + factors[N_copy] = 1 + return factors diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/residue_ntheory.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/residue_ntheory.py new file mode 100644 index 0000000000000000000000000000000000000000..eba024161194605aabebd10ee30bf09acb90270b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/ntheory/residue_ntheory.py @@ -0,0 +1,1963 @@ +from __future__ import annotations + +from sympy.external.gmpy import (gcd, lcm, invert, sqrt, jacobi, + bit_scan1, remove) +from sympy.polys import Poly +from sympy.polys.domains import ZZ +from sympy.polys.galoistools import gf_crt1, gf_crt2, linear_congruence, gf_csolve +from .primetest import isprime +from .generate import primerange +from .factor_ import factorint, _perfect_power +from .modular import crt +from sympy.utilities.decorator import deprecated +from sympy.utilities.memoization import recurrence_memo +from sympy.utilities.misc import as_int +from sympy.utilities.iterables import iproduct +from sympy.core.random import _randint, randint + +from itertools import product + + +def n_order(a, n): + r""" Returns the order of ``a`` modulo ``n``. + + Explanation + =========== + + The order of ``a`` modulo ``n`` is the smallest integer + ``k`` such that `a^k` leaves a remainder of 1 with ``n``. + + Parameters + ========== + + a : integer + n : integer, n > 1. a and n should be relatively prime + + Returns + ======= + + int : the order of ``a`` modulo ``n`` + + Raises + ====== + + ValueError + If `n \le 1` or `\gcd(a, n) \neq 1`. + If ``a`` or ``n`` is not an integer. + + Examples + ======== + + >>> from sympy.ntheory import n_order + >>> n_order(3, 7) + 6 + >>> n_order(4, 7) + 3 + + See Also + ======== + + is_primitive_root + We say that ``a`` is a primitive root of ``n`` + when the order of ``a`` modulo ``n`` equals ``totient(n)`` + + """ + a, n = as_int(a), as_int(n) + if n <= 1: + raise ValueError("n should be an integer greater than 1") + a = a % n + # Trivial + if a == 1: + return 1 + if gcd(a, n) != 1: + raise ValueError("The two numbers should be relatively prime") + a_order = 1 + for p, e in factorint(n).items(): + pe = p**e + pe_order = (p - 1) * p**(e - 1) + factors = factorint(p - 1) + if e > 1: + factors[p] = e - 1 + order = 1 + for px, ex in factors.items(): + x = pow(a, pe_order // px**ex, pe) + while x != 1: + x = pow(x, px, pe) + order *= px + a_order = lcm(a_order, order) + return int(a_order) + + +def _primitive_root_prime_iter(p): + r""" Generates the primitive roots for a prime ``p``. + + Explanation + =========== + + The primitive roots generated are not necessarily sorted. + However, the first one is the smallest primitive root. + + Find the element whose order is ``p-1`` from the smaller one. + If we can find the first primitive root ``g``, we can use the following theorem. + + .. math :: + \operatorname{ord}(g^k) = \frac{\operatorname{ord}(g)}{\gcd(\operatorname{ord}(g), k)} + + From the assumption that `\operatorname{ord}(g)=p-1`, + it is a necessary and sufficient condition for + `\operatorname{ord}(g^k)=p-1` that `\gcd(p-1, k)=1`. + + Parameters + ========== + + p : odd prime + + Yields + ====== + + int + the primitive roots of ``p`` + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _primitive_root_prime_iter + >>> sorted(_primitive_root_prime_iter(19)) + [2, 3, 10, 13, 14, 15] + + References + ========== + + .. [1] W. Stein "Elementary Number Theory" (2011), page 44 + + """ + if p == 3: + yield 2 + return + # Let p = +-1 (mod 4a). Legendre symbol (a/p) = 1, so `a` is not the primitive root. + # Corollary : If p = +-1 (mod 8), then 2 is not the primitive root of p. + g_min = 3 if p % 8 in [1, 7] else 2 + if p < 41: + # small case + g = 5 if p == 23 else g_min + else: + v = [(p - 1) // i for i in factorint(p - 1).keys()] + for g in range(g_min, p): + if all(pow(g, pw, p) != 1 for pw in v): + break + yield g + # g**k is the primitive root of p iff gcd(p - 1, k) = 1 + for k in range(3, p, 2): + if gcd(p - 1, k) == 1: + yield pow(g, k, p) + + +def _primitive_root_prime_power_iter(p, e): + r""" Generates the primitive roots of `p^e`. + + Explanation + =========== + + Let ``g`` be the primitive root of ``p``. + If `g^{p-1} \not\equiv 1 \pmod{p^2}`, then ``g`` is primitive root of `p^e`. + Thus, if we find a primitive root ``g`` of ``p``, + then `g, g+p, g+2p, \ldots, g+(p-1)p` are primitive roots of `p^2` except one. + That one satisfies `\hat{g}^{p-1} \equiv 1 \pmod{p^2}`. + If ``h`` is the primitive root of `p^2`, + then `h, h+p^2, h+2p^2, \ldots, h+(p^{e-2}-1)p^e` are primitive roots of `p^e`. + + Parameters + ========== + + p : odd prime + e : positive integer + + Yields + ====== + + int + the primitive roots of `p^e` + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _primitive_root_prime_power_iter + >>> sorted(_primitive_root_prime_power_iter(5, 2)) + [2, 3, 8, 12, 13, 17, 22, 23] + + """ + if e == 1: + yield from _primitive_root_prime_iter(p) + else: + p2 = p**2 + for g in _primitive_root_prime_iter(p): + t = (g - pow(g, 2 - p, p2)) % p2 + for k in range(0, p2, p): + if k != t: + yield from (g + k + m for m in range(0, p**e, p2)) + + +def _primitive_root_prime_power2_iter(p, e): + r""" Generates the primitive roots of `2p^e`. + + Explanation + =========== + + If ``g`` is the primitive root of ``p**e``, + then the odd one of ``g`` and ``g+p**e`` is the primitive root of ``2*p**e``. + + Parameters + ========== + + p : odd prime + e : positive integer + + Yields + ====== + + int + the primitive roots of `2p^e` + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _primitive_root_prime_power2_iter + >>> sorted(_primitive_root_prime_power2_iter(5, 2)) + [3, 13, 17, 23, 27, 33, 37, 47] + + """ + for g in _primitive_root_prime_power_iter(p, e): + if g % 2 == 1: + yield g + else: + yield g + p**e + + +def primitive_root(p, smallest=True): + r""" Returns a primitive root of ``p`` or None. + + Explanation + =========== + + For the definition of primitive root, + see the explanation of ``is_primitive_root``. + + The primitive root of ``p`` exist only for + `p = 2, 4, q^e, 2q^e` (``q`` is an odd prime). + Now, if we know the primitive root of ``q``, + we can calculate the primitive root of `q^e`, + and if we know the primitive root of `q^e`, + we can calculate the primitive root of `2q^e`. + When there is no need to find the smallest primitive root, + this property can be used to obtain a fast primitive root. + On the other hand, when we want the smallest primitive root, + we naively determine whether it is a primitive root or not. + + Parameters + ========== + + p : integer, p > 1 + smallest : if True the smallest primitive root is returned or None + + Returns + ======= + + int | None : + If the primitive root exists, return the primitive root of ``p``. + If not, return None. + + Raises + ====== + + ValueError + If `p \le 1` or ``p`` is not an integer. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import primitive_root + >>> primitive_root(19) + 2 + >>> primitive_root(21) is None + True + >>> primitive_root(50, smallest=False) + 27 + + See Also + ======== + + is_primitive_root + + References + ========== + + .. [1] W. Stein "Elementary Number Theory" (2011), page 44 + .. [2] P. Hackman "Elementary Number Theory" (2009), Chapter C + + """ + p = as_int(p) + if p <= 1: + raise ValueError("p should be an integer greater than 1") + if p <= 4: + return p - 1 + p_even = p % 2 == 0 + if not p_even: + q = p # p is odd + elif p % 4: + q = p//2 # p had 1 factor of 2 + else: + return None # p had more than one factor of 2 + if isprime(q): + e = 1 + else: + m = _perfect_power(q, 3) + if not m: + return None + q, e = m + if not isprime(q): + return None + if not smallest: + if p_even: + return next(_primitive_root_prime_power2_iter(q, e)) + return next(_primitive_root_prime_power_iter(q, e)) + if p_even: + for i in range(3, p, 2): + if i % q and is_primitive_root(i, p): + return i + g = next(_primitive_root_prime_iter(q)) + if e == 1 or pow(g, q - 1, q**2) != 1: + return g + for i in range(g + 1, p): + if i % q and is_primitive_root(i, p): + return i + + +def is_primitive_root(a, p): + r""" Returns True if ``a`` is a primitive root of ``p``. + + Explanation + =========== + + ``a`` is said to be the primitive root of ``p`` if `\gcd(a, p) = 1` and + `\phi(p)` is the smallest positive number s.t. + + `a^{\phi(p)} \equiv 1 \pmod{p}`. + + where `\phi(p)` is Euler's totient function. + + The primitive root of ``p`` exist only for + `p = 2, 4, q^e, 2q^e` (``q`` is an odd prime). + Hence, if it is not such a ``p``, it returns False. + To determine the primitive root, we need to know + the prime factorization of ``q-1``. + The hardness of the determination depends on this complexity. + + Parameters + ========== + + a : integer + p : integer, ``p`` > 1. ``a`` and ``p`` should be relatively prime + + Returns + ======= + + bool : If True, ``a`` is the primitive root of ``p``. + + Raises + ====== + + ValueError + If `p \le 1` or `\gcd(a, p) \neq 1`. + If ``a`` or ``p`` is not an integer. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import totient + >>> from sympy.ntheory import is_primitive_root, n_order + >>> is_primitive_root(3, 10) + True + >>> is_primitive_root(9, 10) + False + >>> n_order(3, 10) == totient(10) + True + >>> n_order(9, 10) == totient(10) + False + + See Also + ======== + + primitive_root + + """ + a, p = as_int(a), as_int(p) + if p <= 1: + raise ValueError("p should be an integer greater than 1") + a = a % p + if gcd(a, p) != 1: + raise ValueError("The two numbers should be relatively prime") + # Primitive root of p exist only for + # p = 2, 4, q**e, 2*q**e (q is odd prime) + if p <= 4: + # The primitive root is only p-1. + return a == p - 1 + if p % 2: + q = p # p is odd + elif p % 4: + q = p//2 # p had 1 factor of 2 + else: + return False # p had more than one factor of 2 + if isprime(q): + group_order = q - 1 + factors = factorint(q - 1).keys() + else: + m = _perfect_power(q, 3) + if not m: + return False + q, e = m + if not isprime(q): + return False + group_order = q**(e - 1)*(q - 1) + factors = set(factorint(q - 1).keys()) + factors.add(q) + return all(pow(a, group_order // prime, p) != 1 for prime in factors) + + +def _sqrt_mod_tonelli_shanks(a, p): + """ + Returns the square root in the case of ``p`` prime with ``p == 1 (mod 8)`` + + Assume that the root exists. + + Parameters + ========== + + a : int + p : int + prime number. should be ``p % 8 == 1`` + + Returns + ======= + + int : Generally, there are two roots, but only one is returned. + Which one is returned is random. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _sqrt_mod_tonelli_shanks + >>> _sqrt_mod_tonelli_shanks(2, 17) in [6, 11] + True + + References + ========== + + .. [1] Carl Pomerance, Richard Crandall, Prime Numbers: A Computational Perspective, + 2nd Edition (2005), page 101, ISBN:978-0387252827 + + """ + s = bit_scan1(p - 1) + t = p >> s + # find a non-quadratic residue + if p % 12 == 5: + # Legendre symbol (3/p) == -1 if p % 12 in [5, 7] + d = 3 + elif p % 5 in [2, 3]: + # Legendre symbol (5/p) == -1 if p % 5 in [2, 3] + d = 5 + else: + while 1: + d = randint(6, p - 1) + if jacobi(d, p) == -1: + break + #assert legendre_symbol(d, p) == -1 + A = pow(a, t, p) + D = pow(d, t, p) + m = 0 + for i in range(s): + adm = A*pow(D, m, p) % p + adm = pow(adm, 2**(s - 1 - i), p) + if adm % p == p - 1: + m += 2**i + #assert A*pow(D, m, p) % p == 1 + x = pow(a, (t + 1)//2, p)*pow(D, m//2, p) % p + return x + + +def sqrt_mod(a, p, all_roots=False): + """ + Find a root of ``x**2 = a mod p``. + + Parameters + ========== + + a : integer + p : positive integer + all_roots : if True the list of roots is returned or None + + Notes + ===== + + If there is no root it is returned None; else the returned root + is less or equal to ``p // 2``; in general is not the smallest one. + It is returned ``p // 2`` only if it is the only root. + + Use ``all_roots`` only when it is expected that all the roots fit + in memory; otherwise use ``sqrt_mod_iter``. + + Examples + ======== + + >>> from sympy.ntheory import sqrt_mod + >>> sqrt_mod(11, 43) + 21 + >>> sqrt_mod(17, 32, True) + [7, 9, 23, 25] + """ + if all_roots: + return sorted(sqrt_mod_iter(a, p)) + p = abs(as_int(p)) + halfp = p // 2 + x = None + for r in sqrt_mod_iter(a, p): + if r < halfp: + return r + elif r > halfp: + return p - r + else: + x = r + return x + + +def sqrt_mod_iter(a, p, domain=int): + """ + Iterate over solutions to ``x**2 = a mod p``. + + Parameters + ========== + + a : integer + p : positive integer + domain : integer domain, ``int``, ``ZZ`` or ``Integer`` + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import sqrt_mod_iter + >>> list(sqrt_mod_iter(11, 43)) + [21, 22] + + See Also + ======== + + sqrt_mod : Same functionality, but you want a sorted list or only one solution. + + """ + a, p = as_int(a), abs(as_int(p)) + v = [] + pv = [] + _product = product + for px, ex in factorint(p).items(): + if a % px: + # `len(rx)` is at most 4 + rx = _sqrt_mod_prime_power(a, px, ex) + else: + # `len(list(rx))` can be assumed to be large. + # The `itertools.product` is disadvantageous in terms of memory usage. + # It is also inferior to iproduct in speed if not all Cartesian products are needed. + rx = _sqrt_mod1(a, px, ex) + _product = iproduct + if not rx: + return + v.append(rx) + pv.append(px**ex) + if len(v) == 1: + yield from map(domain, v[0]) + else: + mm, e, s = gf_crt1(pv, ZZ) + for vx in _product(*v): + yield domain(gf_crt2(vx, pv, mm, e, s, ZZ)) + + +def _sqrt_mod_prime_power(a, p, k): + """ + Find the solutions to ``x**2 = a mod p**k`` when ``a % p != 0``. + If no solution exists, return ``None``. + Solutions are returned in an ascending list. + + Parameters + ========== + + a : integer + p : prime number + k : positive integer + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _sqrt_mod_prime_power + >>> _sqrt_mod_prime_power(11, 43, 1) + [21, 22] + + References + ========== + + .. [1] P. Hackman "Elementary Number Theory" (2009), page 160 + .. [2] http://www.numbertheory.org/php/squareroot.html + .. [3] [Gathen99]_ + """ + pk = p**k + a = a % pk + + if p == 2: + # see Ref.[2] + if a % 8 != 1: + return None + # Trivial + if k <= 3: + return list(range(1, pk, 2)) + r = 1 + # r is one of the solutions to x**2 - a = 0 (mod 2**3). + # Hensel lift them to solutions of x**2 - a = 0 (mod 2**k) + # if r**2 - a = 0 mod 2**nx but not mod 2**(nx+1) + # then r + 2**(nx - 1) is a root mod 2**(nx+1) + for nx in range(3, k): + if ((r**2 - a) >> nx) % 2: + r += 1 << (nx - 1) + # r is a solution of x**2 - a = 0 (mod 2**k), and + # there exist other solutions -r, r+h, -(r+h), and these are all solutions. + h = 1 << (k - 1) + return sorted([r, pk - r, (r + h) % pk, -(r + h) % pk]) + + # If the Legendre symbol (a/p) is not 1, no solution exists. + if jacobi(a, p) != 1: + return None + if p % 4 == 3: + res = pow(a, (p + 1) // 4, p) + elif p % 8 == 5: + res = pow(a, (p + 3) // 8, p) + if pow(res, 2, p) != a % p: + res = res * pow(2, (p - 1) // 4, p) % p + else: + res = _sqrt_mod_tonelli_shanks(a, p) + if k > 1: + # Hensel lifting with Newton iteration, see Ref.[3] chapter 9 + # with f(x) = x**2 - a; one has f'(a) != 0 (mod p) for p != 2 + px = p + for _ in range(k.bit_length() - 1): + px = px**2 + frinv = invert(2*res, px) + res = (res - (res**2 - a)*frinv) % px + if k & (k - 1): # If k is not a power of 2 + frinv = invert(2*res, pk) + res = (res - (res**2 - a)*frinv) % pk + return sorted([res, pk - res]) + + +def _sqrt_mod1(a, p, n): + """ + Find solution to ``x**2 == a mod p**n`` when ``a % p == 0``. + If no solution exists, return ``None``. + + Parameters + ========== + + a : integer + p : prime number, p must divide a + n : positive integer + + References + ========== + + .. [1] http://www.numbertheory.org/php/squareroot.html + """ + pn = p**n + a = a % pn + if a == 0: + # case gcd(a, p**k) = p**n + return range(0, pn, p**((n + 1) // 2)) + # case gcd(a, p**k) = p**r, r < n + a, r = remove(a, p) + if r % 2 == 1: + return None + res = _sqrt_mod_prime_power(a, p, n - r) + if res is None: + return None + m = r // 2 + return (x for rx in res for x in range(rx*p**m, pn, p**(n - m))) + + +def is_quad_residue(a, p): + """ + Returns True if ``a`` (mod ``p``) is in the set of squares mod ``p``, + i.e a % p in set([i**2 % p for i in range(p)]). + + Parameters + ========== + + a : integer + p : positive integer + + Returns + ======= + + bool : If True, ``x**2 == a (mod p)`` has solution. + + Raises + ====== + + ValueError + If ``a``, ``p`` is not integer. + If ``p`` is not positive. + + Examples + ======== + + >>> from sympy.ntheory import is_quad_residue + >>> is_quad_residue(21, 100) + True + + Indeed, ``pow(39, 2, 100)`` would be 21. + + >>> is_quad_residue(21, 120) + False + + That is, for any integer ``x``, ``pow(x, 2, 120)`` is not 21. + + If ``p`` is an odd + prime, an iterative method is used to make the determination: + + >>> from sympy.ntheory import is_quad_residue + >>> sorted(set([i**2 % 7 for i in range(7)])) + [0, 1, 2, 4] + >>> [j for j in range(7) if is_quad_residue(j, 7)] + [0, 1, 2, 4] + + See Also + ======== + + legendre_symbol, jacobi_symbol, sqrt_mod + """ + a, p = as_int(a), as_int(p) + if p < 1: + raise ValueError('p must be > 0') + a %= p + if a < 2 or p < 3: + return True + # Since we want to compute the Jacobi symbol, + # we separate p into the odd part and the rest. + t = bit_scan1(p) + if t: + # The existence of a solution to a power of 2 is determined + # using the logic of `p==2` in `_sqrt_mod_prime_power` and `_sqrt_mod1`. + a_ = a % (1 << t) + if a_: + r = bit_scan1(a_) + if r % 2 or (a_ >> r) & 6: + return False + p >>= t + a %= p + if a < 2 or p < 3: + return True + # If Jacobi symbol is -1 or p is prime, can be determined by Jacobi symbol only + j = jacobi(a, p) + if j == -1 or isprime(p): + return j == 1 + # Checks if `x**2 = a (mod p)` has a solution + for px, ex in factorint(p).items(): + if a % px: + if jacobi(a, px) != 1: + return False + else: + a_ = a % px**ex + if a_ == 0: + continue + a_, r = remove(a_, px) + if r % 2 or jacobi(a_, px) != 1: + return False + return True + + +def is_nthpow_residue(a, n, m): + """ + Returns True if ``x**n == a (mod m)`` has solutions. + + References + ========== + + .. [1] P. Hackman "Elementary Number Theory" (2009), page 76 + + """ + a = a % m + a, n, m = as_int(a), as_int(n), as_int(m) + if m <= 0: + raise ValueError('m must be > 0') + if n < 0: + raise ValueError('n must be >= 0') + if n == 0: + if m == 1: + return False + return a == 1 + if a == 0: + return True + if n == 1: + return True + if n == 2: + return is_quad_residue(a, m) + return all(_is_nthpow_residue_bign_prime_power(a, n, p, e) + for p, e in factorint(m).items()) + + +def _is_nthpow_residue_bign_prime_power(a, n, p, k): + r""" + Returns True if `x^n = a \pmod{p^k}` has solutions for `n > 2`. + + Parameters + ========== + + a : positive integer + n : integer, n > 2 + p : prime number + k : positive integer + + """ + while a % p == 0: + a %= pow(p, k) + if not a: + return True + a, mu = remove(a, p) + if mu % n: + return False + k -= mu + if p != 2: + f = p**(k - 1)*(p - 1) # f = totient(p**k) + return pow(a, f // gcd(f, n), pow(p, k)) == 1 + if n & 1: + return True + c = min(bit_scan1(n) + 2, k) + return a % pow(2, c) == 1 + + +def _nthroot_mod1(s, q, p, all_roots): + """ + Root of ``x**q = s mod p``, ``p`` prime and ``q`` divides ``p - 1``. + Assume that the root exists. + + Parameters + ========== + + s : integer + q : integer, n > 2. ``q`` divides ``p - 1``. + p : prime number + all_roots : if False returns the smallest root, else the list of roots + + Returns + ======= + + list[int] | int : + Root of ``x**q = s mod p``. If ``all_roots == True``, + returned ascending list. otherwise, returned an int. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _nthroot_mod1 + >>> _nthroot_mod1(5, 3, 13, False) + 7 + >>> _nthroot_mod1(13, 4, 17, True) + [3, 5, 12, 14] + + References + ========== + + .. [1] A. M. Johnston, A Generalized qth Root Algorithm, + ACM-SIAM Symposium on Discrete Algorithms (1999), pp. 929-930 + + """ + g = next(_primitive_root_prime_iter(p)) + r = s + for qx, ex in factorint(q).items(): + f = (p - 1) // qx**ex + while f % qx == 0: + f //= qx + z = f*invert(-f, qx) + x = (1 + z) // qx + t = discrete_log(p, pow(r, f, p), pow(g, f*qx, p)) + for _ in range(ex): + # assert t == discrete_log(p, pow(r, f, p), pow(g, f*qx, p)) + r = pow(r, x, p)*pow(g, -z*t % (p - 1), p) % p + t //= qx + res = [r] + h = pow(g, (p - 1) // q, p) + #assert pow(h, q, p) == 1 + hx = r + for _ in range(q - 1): + hx = (hx*h) % p + res.append(hx) + if all_roots: + res.sort() + return res + return min(res) + + +def _nthroot_mod_prime_power(a, n, p, k): + """ Root of ``x**n = a mod p**k``. + + Parameters + ========== + + a : integer + n : integer, n > 2 + p : prime number + k : positive integer + + Returns + ======= + + list[int] : + Ascending list of roots of ``x**n = a mod p**k``. + If no solution exists, return ``[]``. + + """ + if not _is_nthpow_residue_bign_prime_power(a, n, p, k): + return [] + a_mod_p = a % p + if a_mod_p == 0: + base_roots = [0] + elif (p - 1) % n == 0: + base_roots = _nthroot_mod1(a_mod_p, n, p, all_roots=True) + else: + # The roots of ``x**n - a = 0 (mod p)`` are roots of + # ``gcd(x**n - a, x**(p - 1) - 1) = 0 (mod p)`` + pa = n + pb = p - 1 + b = 1 + if pa < pb: + a_mod_p, pa, b, pb = b, pb, a_mod_p, pa + # gcd(x**pa - a, x**pb - b) = gcd(x**pb - b, x**pc - c) + # where pc = pa % pb; c = b**-q * a mod p + while pb: + q, pc = divmod(pa, pb) + c = pow(b, -q, p) * a_mod_p % p + pa, pb = pb, pc + a_mod_p, b = b, c + if pa == 1: + base_roots = [a_mod_p] + elif pa == 2: + base_roots = sqrt_mod(a_mod_p, p, all_roots=True) + else: + base_roots = _nthroot_mod1(a_mod_p, pa, p, all_roots=True) + if k == 1: + return base_roots + a %= p**k + tot_roots = set() + for root in base_roots: + diff = pow(root, n - 1, p)*n % p + new_base = p + if diff != 0: + m_inv = invert(diff, p) + for _ in range(k - 1): + new_base *= p + tmp = pow(root, n, new_base) - a + tmp *= m_inv + root = (root - tmp) % new_base + tot_roots.add(root) + else: + roots_in_base = {root} + for _ in range(k - 1): + new_base *= p + new_roots = set() + for k_ in roots_in_base: + if pow(k_, n, new_base) != a % new_base: + continue + while k_ not in new_roots: + new_roots.add(k_) + k_ = (k_ + (new_base // p)) % new_base + roots_in_base = new_roots + tot_roots = tot_roots | roots_in_base + return sorted(tot_roots) + + +def nthroot_mod(a, n, p, all_roots=False): + """ + Find the solutions to ``x**n = a mod p``. + + Parameters + ========== + + a : integer + n : positive integer + p : positive integer + all_roots : if False returns the smallest root, else the list of roots + + Returns + ======= + + list[int] | int | None : + solutions to ``x**n = a mod p``. + The table of the output type is: + + ========== ========== ========== + all_roots has roots Returns + ========== ========== ========== + True Yes list[int] + True No [] + False Yes int + False No None + ========== ========== ========== + + Raises + ====== + + ValueError + If ``a``, ``n`` or ``p`` is not integer. + If ``n`` or ``p`` is not positive. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import nthroot_mod + >>> nthroot_mod(11, 4, 19) + 8 + >>> nthroot_mod(11, 4, 19, True) + [8, 11] + >>> nthroot_mod(68, 3, 109) + 23 + + References + ========== + + .. [1] P. Hackman "Elementary Number Theory" (2009), page 76 + + """ + a = a % p + a, n, p = as_int(a), as_int(n), as_int(p) + + if n < 1: + raise ValueError("n should be positive") + if p < 1: + raise ValueError("p should be positive") + if n == 1: + return [a] if all_roots else a + if n == 2: + return sqrt_mod(a, p, all_roots) + base = [] + prime_power = [] + for q, e in factorint(p).items(): + tot_roots = _nthroot_mod_prime_power(a, n, q, e) + if not tot_roots: + return [] if all_roots else None + prime_power.append(q**e) + base.append(sorted(tot_roots)) + P, E, S = gf_crt1(prime_power, ZZ) + ret = sorted(map(int, {gf_crt2(c, prime_power, P, E, S, ZZ) + for c in product(*base)})) + if all_roots: + return ret + if ret: + return ret[0] + + +def quadratic_residues(p) -> list[int]: + """ + Returns the list of quadratic residues. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import quadratic_residues + >>> quadratic_residues(7) + [0, 1, 2, 4] + """ + p = as_int(p) + r = {pow(i, 2, p) for i in range(p // 2 + 1)} + return sorted(r) + + +@deprecated("""\ +The `sympy.ntheory.residue_ntheory.legendre_symbol` has been moved to `sympy.functions.combinatorial.numbers.legendre_symbol`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def legendre_symbol(a, p): + r""" + Returns the Legendre symbol `(a / p)`. + + .. deprecated:: 1.13 + + The ``legendre_symbol`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.legendre_symbol` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + For an integer ``a`` and an odd prime ``p``, the Legendre symbol is + defined as + + .. math :: + \genfrac(){}{}{a}{p} = \begin{cases} + 0 & \text{if } p \text{ divides } a\\ + 1 & \text{if } a \text{ is a quadratic residue modulo } p\\ + -1 & \text{if } a \text{ is a quadratic nonresidue modulo } p + \end{cases} + + Parameters + ========== + + a : integer + p : odd prime + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import legendre_symbol + >>> [legendre_symbol(i, 7) for i in range(7)] + [0, 1, 1, -1, 1, -1, -1] + >>> sorted(set([i**2 % 7 for i in range(7)])) + [0, 1, 2, 4] + + See Also + ======== + + is_quad_residue, jacobi_symbol + + """ + from sympy.functions.combinatorial.numbers import legendre_symbol as _legendre_symbol + return _legendre_symbol(a, p) + + +@deprecated("""\ +The `sympy.ntheory.residue_ntheory.jacobi_symbol` has been moved to `sympy.functions.combinatorial.numbers.jacobi_symbol`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def jacobi_symbol(m, n): + r""" + Returns the Jacobi symbol `(m / n)`. + + .. deprecated:: 1.13 + + The ``jacobi_symbol`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.jacobi_symbol` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + For any integer ``m`` and any positive odd integer ``n`` the Jacobi symbol + is defined as the product of the Legendre symbols corresponding to the + prime factors of ``n``: + + .. math :: + \genfrac(){}{}{m}{n} = + \genfrac(){}{}{m}{p^{1}}^{\alpha_1} + \genfrac(){}{}{m}{p^{2}}^{\alpha_2} + ... + \genfrac(){}{}{m}{p^{k}}^{\alpha_k} + \text{ where } n = + p_1^{\alpha_1} + p_2^{\alpha_2} + ... + p_k^{\alpha_k} + + Like the Legendre symbol, if the Jacobi symbol `\genfrac(){}{}{m}{n} = -1` + then ``m`` is a quadratic nonresidue modulo ``n``. + + But, unlike the Legendre symbol, if the Jacobi symbol + `\genfrac(){}{}{m}{n} = 1` then ``m`` may or may not be a quadratic residue + modulo ``n``. + + Parameters + ========== + + m : integer + n : odd positive integer + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import jacobi_symbol, legendre_symbol + >>> from sympy import S + >>> jacobi_symbol(45, 77) + -1 + >>> jacobi_symbol(60, 121) + 1 + + The relationship between the ``jacobi_symbol`` and ``legendre_symbol`` can + be demonstrated as follows: + + >>> L = legendre_symbol + >>> S(45).factors() + {3: 2, 5: 1} + >>> jacobi_symbol(7, 45) == L(7, 3)**2 * L(7, 5)**1 + True + + See Also + ======== + + is_quad_residue, legendre_symbol + """ + from sympy.functions.combinatorial.numbers import jacobi_symbol as _jacobi_symbol + return _jacobi_symbol(m, n) + + +@deprecated("""\ +The `sympy.ntheory.residue_ntheory.mobius` has been moved to `sympy.functions.combinatorial.numbers.mobius`.""", +deprecated_since_version="1.13", +active_deprecations_target='deprecated-ntheory-symbolic-functions') +def mobius(n): + """ + Mobius function maps natural number to {-1, 0, 1} + + .. deprecated:: 1.13 + + The ``mobius`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.mobius` + instead. See its documentation for more information. See + :ref:`deprecated-ntheory-symbolic-functions` for details. + + It is defined as follows: + 1) `1` if `n = 1`. + 2) `0` if `n` has a squared prime factor. + 3) `(-1)^k` if `n` is a square-free positive integer with `k` + number of prime factors. + + It is an important multiplicative function in number theory + and combinatorics. It has applications in mathematical series, + algebraic number theory and also physics (Fermion operator has very + concrete realization with Mobius Function model). + + Parameters + ========== + + n : positive integer + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import mobius + >>> mobius(13*7) + 1 + >>> mobius(1) + 1 + >>> mobius(13*7*5) + -1 + >>> mobius(13**2) + 0 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/M%C3%B6bius_function + .. [2] Thomas Koshy "Elementary Number Theory with Applications" + + """ + from sympy.functions.combinatorial.numbers import mobius as _mobius + return _mobius(n) + + +def _discrete_log_trial_mul(n, a, b, order=None): + """ + Trial multiplication algorithm for computing the discrete logarithm of + ``a`` to the base ``b`` modulo ``n``. + + The algorithm finds the discrete logarithm using exhaustive search. This + naive method is used as fallback algorithm of ``discrete_log`` when the + group order is very small. The value ``n`` must be greater than 1. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _discrete_log_trial_mul + >>> _discrete_log_trial_mul(41, 15, 7) + 3 + + See Also + ======== + + discrete_log + + References + ========== + + .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & + Vanstone, S. A. (1997). + """ + a %= n + b %= n + if order is None: + order = n + x = 1 + for i in range(order): + if x == a: + return i + x = x * b % n + raise ValueError("Log does not exist") + + +def _discrete_log_shanks_steps(n, a, b, order=None): + """ + Baby-step giant-step algorithm for computing the discrete logarithm of + ``a`` to the base ``b`` modulo ``n``. + + The algorithm is a time-memory trade-off of the method of exhaustive + search. It uses `O(sqrt(m))` memory, where `m` is the group order. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _discrete_log_shanks_steps + >>> _discrete_log_shanks_steps(41, 15, 7) + 3 + + See Also + ======== + + discrete_log + + References + ========== + + .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & + Vanstone, S. A. (1997). + """ + a %= n + b %= n + if order is None: + order = n_order(b, n) + m = sqrt(order) + 1 + T = {} + x = 1 + for i in range(m): + T[x] = i + x = x * b % n + z = pow(b, -m, n) + x = a + for i in range(m): + if x in T: + return i * m + T[x] + x = x * z % n + raise ValueError("Log does not exist") + + +def _discrete_log_pollard_rho(n, a, b, order=None, retries=10, rseed=None): + """ + Pollard's Rho algorithm for computing the discrete logarithm of ``a`` to + the base ``b`` modulo ``n``. + + It is a randomized algorithm with the same expected running time as + ``_discrete_log_shanks_steps``, but requires a negligible amount of memory. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _discrete_log_pollard_rho + >>> _discrete_log_pollard_rho(227, 3**7, 3) + 7 + + See Also + ======== + + discrete_log + + References + ========== + + .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & + Vanstone, S. A. (1997). + """ + a %= n + b %= n + + if order is None: + order = n_order(b, n) + randint = _randint(rseed) + + for i in range(retries): + aa = randint(1, order - 1) + ba = randint(1, order - 1) + xa = pow(b, aa, n) * pow(a, ba, n) % n + + c = xa % 3 + if c == 0: + xb = a * xa % n + ab = aa + bb = (ba + 1) % order + elif c == 1: + xb = xa * xa % n + ab = (aa + aa) % order + bb = (ba + ba) % order + else: + xb = b * xa % n + ab = (aa + 1) % order + bb = ba + + for j in range(order): + c = xa % 3 + if c == 0: + xa = a * xa % n + ba = (ba + 1) % order + elif c == 1: + xa = xa * xa % n + aa = (aa + aa) % order + ba = (ba + ba) % order + else: + xa = b * xa % n + aa = (aa + 1) % order + + c = xb % 3 + if c == 0: + xb = a * xb % n + bb = (bb + 1) % order + elif c == 1: + xb = xb * xb % n + ab = (ab + ab) % order + bb = (bb + bb) % order + else: + xb = b * xb % n + ab = (ab + 1) % order + + c = xb % 3 + if c == 0: + xb = a * xb % n + bb = (bb + 1) % order + elif c == 1: + xb = xb * xb % n + ab = (ab + ab) % order + bb = (bb + bb) % order + else: + xb = b * xb % n + ab = (ab + 1) % order + + if xa == xb: + r = (ba - bb) % order + try: + e = invert(r, order) * (ab - aa) % order + if (pow(b, e, n) - a) % n == 0: + return e + except ZeroDivisionError: + pass + break + raise ValueError("Pollard's Rho failed to find logarithm") + + +def _discrete_log_is_smooth(n: int, factorbase: list): + """Try to factor n with respect to a given factorbase. + Upon success a list of exponents with respect to the factorbase is returned. + Otherwise None.""" + factors = [0]*len(factorbase) + for i, p in enumerate(factorbase): + while n % p == 0: # divide by p as many times as possible + factors[i] += 1 + n = n // p + if n != 1: + return None # the number factors if at the end nothing is left + return factors + + +def _discrete_log_index_calculus(n, a, b, order, rseed=None): + """ + Index Calculus algorithm for computing the discrete logarithm of ``a`` to + the base ``b`` modulo ``n``. + + The group order must be given and prime. It is not suitable for small orders + and the algorithm might fail to find a solution in such situations. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _discrete_log_index_calculus + >>> _discrete_log_index_calculus(24570203447, 23859756228, 2, 12285101723) + 4519867240 + + See Also + ======== + + discrete_log + + References + ========== + + .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & + Vanstone, S. A. (1997). + """ + randint = _randint(rseed) + from math import sqrt, exp, log + a %= n + b %= n + # assert isprime(order), "The order of the base must be prime." + # First choose a heuristic the bound B for the factorbase. + # We have added an extra term to the asymptotic value which + # is closer to the theoretical optimum for n up to 2^70. + B = int(exp(0.5 * sqrt( log(n) * log(log(n)) )*( 1 + 1/log(log(n)) ))) + max = 5 * B * B # expected number of tries to find a relation + factorbase = list(primerange(B)) # compute the factorbase + lf = len(factorbase) # length of the factorbase + ordermo = order-1 + abx = a + for x in range(order): + if abx == 1: + return (order - x) % order + relationa = _discrete_log_is_smooth(abx, factorbase) + if relationa: + relationa = [r % order for r in relationa] + [x] + break + abx = abx * b % n # abx = a*pow(b, x, n) % n + + else: + raise ValueError("Index Calculus failed") + + relations = [None] * lf + k = 1 # number of relations found + kk = 0 + while k < 3 * lf and kk < max: # find relations for all primes in our factor base + x = randint(1,ordermo) + relation = _discrete_log_is_smooth(pow(b,x,n), factorbase) + if relation is None: + kk += 1 + continue + k += 1 + kk = 0 + relation += [ x ] + index = lf # determine the index of the first nonzero entry + for i in range(lf): + ri = relation[i] % order + if ri> 0 and relations[i] is not None: # make this entry zero if we can + for j in range(lf+1): + relation[j] = (relation[j] - ri*relations[i][j]) % order + else: + relation[i] = ri + if relation[i] > 0 and index == lf: # is this the index of the first nonzero entry? + index = i + if index == lf or relations[index] is not None: # the relation contains no new information + continue + # the relation contains new information + rinv = pow(relation[index],-1,order) # normalize the first nonzero entry + for j in range(index,lf+1): + relation[j] = rinv * relation[j] % order + relations[index] = relation + for i in range(lf): # subtract the new relation from the one for a + if relationa[i] > 0 and relations[i] is not None: + rbi = relationa[i] + for j in range(lf+1): + relationa[j] = (relationa[j] - rbi*relations[i][j]) % order + if relationa[i] > 0: # the index of the first nonzero entry + break # we do not need to reduce further at this point + else: # all unknowns are gone + #print(f"Success after {k} relations out of {lf}") + x = (order -relationa[lf]) % order + if pow(b,x,n) == a: + return x + raise ValueError("Index Calculus failed") + raise ValueError("Index Calculus failed") + + +def _discrete_log_pohlig_hellman(n, a, b, order=None, order_factors=None): + """ + Pohlig-Hellman algorithm for computing the discrete logarithm of ``a`` to + the base ``b`` modulo ``n``. + + In order to compute the discrete logarithm, the algorithm takes advantage + of the factorization of the group order. It is more efficient when the + group order factors into many small primes. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _discrete_log_pohlig_hellman + >>> _discrete_log_pohlig_hellman(251, 210, 71) + 197 + + See Also + ======== + + discrete_log + + References + ========== + + .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & + Vanstone, S. A. (1997). + """ + from .modular import crt + a %= n + b %= n + + if order is None: + order = n_order(b, n) + if order_factors is None: + order_factors = factorint(order) + l = [0] * len(order_factors) + + for i, (pi, ri) in enumerate(order_factors.items()): + for j in range(ri): + aj = pow(a * pow(b, -l[i], n), order // pi**(j + 1), n) + bj = pow(b, order // pi, n) + cj = discrete_log(n, aj, bj, pi, True) + l[i] += cj * pi**j + + d, _ = crt([pi**ri for pi, ri in order_factors.items()], l) + return d + + +def discrete_log(n, a, b, order=None, prime_order=None): + """ + Compute the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. + + This is a recursive function to reduce the discrete logarithm problem in + cyclic groups of composite order to the problem in cyclic groups of prime + order. + + It employs different algorithms depending on the problem (subgroup order + size, prime order or not): + + * Trial multiplication + * Baby-step giant-step + * Pollard's Rho + * Index Calculus + * Pohlig-Hellman + + Examples + ======== + + >>> from sympy.ntheory import discrete_log + >>> discrete_log(41, 15, 7) + 3 + + References + ========== + + .. [1] https://mathworld.wolfram.com/DiscreteLogarithm.html + .. [2] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & + Vanstone, S. A. (1997). + + """ + from math import sqrt, log + n, a, b = as_int(n), as_int(a), as_int(b) + + if n < 1: + raise ValueError("n should be positive") + if n == 1: + return 0 + + if order is None: + # Compute the order and its factoring in one pass + # order = totient(n), factors = factorint(order) + factors = {} + for px, kx in factorint(n).items(): + if kx > 1: + if px in factors: + factors[px] += kx - 1 + else: + factors[px] = kx - 1 + for py, ky in factorint(px - 1).items(): + if py in factors: + factors[py] += ky + else: + factors[py] = ky + order = 1 + for px, kx in factors.items(): + order *= px**kx + # Now the `order` is the order of the group and factors = factorint(order) + # The order of `b` divides the order of the group. + order_factors = {} + for p, e in factors.items(): + i = 0 + for _ in range(e): + if pow(b, order // p, n) == 1: + order //= p + i += 1 + else: + break + if i < e: + order_factors[p] = e - i + + if prime_order is None: + prime_order = isprime(order) + + if order < 1000: + return _discrete_log_trial_mul(n, a, b, order) + elif prime_order: + # Shanks and Pollard rho are O(sqrt(order)) while index calculus is O(exp(2*sqrt(log(n)log(log(n))))) + # we compare the expected running times to determine the algorithm which is expected to be faster + if 4*sqrt(log(n)*log(log(n))) < log(order) - 10: # the number 10 was determined experimental + return _discrete_log_index_calculus(n, a, b, order) + elif order < 1000000000000: + # Shanks seems typically faster, but uses O(sqrt(order)) memory + return _discrete_log_shanks_steps(n, a, b, order) + return _discrete_log_pollard_rho(n, a, b, order) + + return _discrete_log_pohlig_hellman(n, a, b, order, order_factors) + + + +def quadratic_congruence(a, b, c, n): + r""" + Find the solutions to `a x^2 + b x + c \equiv 0 \pmod{n}`. + + Parameters + ========== + + a : int + b : int + c : int + n : int + A positive integer. + + Returns + ======= + + list[int] : + A sorted list of solutions. If no solution exists, ``[]``. + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import quadratic_congruence + >>> quadratic_congruence(2, 5, 3, 7) # 2x^2 + 5x + 3 = 0 (mod 7) + [2, 6] + >>> quadratic_congruence(8, 6, 4, 15) # No solution + [] + + See Also + ======== + + polynomial_congruence : Solve the polynomial congruence + + """ + a = as_int(a) + b = as_int(b) + c = as_int(c) + n = as_int(n) + if n <= 1: + raise ValueError("n should be an integer greater than 1") + a %= n + b %= n + c %= n + + if a == 0: + return linear_congruence(b, -c, n) + if n == 2: + # assert a == 1 + roots = [] + if c == 0: + roots.append(0) + if (b + c) % 2: + roots.append(1) + return roots + if gcd(2*a, n) == 1: + inv_a = invert(a, n) + b *= inv_a + c *= inv_a + if b % 2: + b += n + b >>= 1 + return sorted((i - b) % n for i in sqrt_mod_iter(b**2 - c, n)) + res = set() + for i in sqrt_mod_iter(b**2 - 4*a*c, 4*a*n): + q, rem = divmod(i - b, 2*a) + if rem == 0: + res.add(q % n) + + return sorted(res) + + +def _valid_expr(expr): + """ + return coefficients of expr if it is a univariate polynomial + with integer coefficients else raise a ValueError. + """ + + if not expr.is_polynomial(): + raise ValueError("The expression should be a polynomial") + polynomial = Poly(expr) + if not polynomial.is_univariate: + raise ValueError("The expression should be univariate") + if not polynomial.domain == ZZ: + raise ValueError("The expression should should have integer coefficients") + return polynomial.all_coeffs() + + +def polynomial_congruence(expr, m): + """ + Find the solutions to a polynomial congruence equation modulo m. + + Parameters + ========== + + expr : integer coefficient polynomial + m : positive integer + + Examples + ======== + + >>> from sympy.ntheory import polynomial_congruence + >>> from sympy.abc import x + >>> expr = x**6 - 2*x**5 -35 + >>> polynomial_congruence(expr, 6125) + [3257] + + See Also + ======== + + sympy.polys.galoistools.gf_csolve : low level solving routine used by this routine + + """ + coefficients = _valid_expr(expr) + coefficients = [num % m for num in coefficients] + rank = len(coefficients) + if rank == 3: + return quadratic_congruence(*coefficients, m) + if rank == 2: + return quadratic_congruence(0, *coefficients, m) + if coefficients[0] == 1 and 1 + coefficients[-1] == sum(coefficients): + return nthroot_mod(-coefficients[-1], rank - 1, m, True) + return gf_csolve(coefficients, m) + + +def binomial_mod(n, m, k): + """Compute ``binomial(n, m) % k``. + + Explanation + =========== + + Returns ``binomial(n, m) % k`` using a generalization of Lucas' + Theorem for prime powers given by Granville [1]_, in conjunction with + the Chinese Remainder Theorem. The residue for each prime power + is calculated in time O(log^2(n) + q^4*log(n)log(p) + q^4*p*log^3(p)). + + Parameters + ========== + + n : an integer + m : an integer + k : a positive integer + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import binomial_mod + >>> binomial_mod(10, 2, 6) # binomial(10, 2) = 45 + 3 + >>> binomial_mod(17, 9, 10) # binomial(17, 9) = 24310 + 0 + + References + ========== + + .. [1] Binomial coefficients modulo prime powers, Andrew Granville, + Available: https://web.archive.org/web/20170202003812/http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf + """ + if k < 1: raise ValueError('k is required to be positive') + # We decompose q into a product of prime powers and apply + # the generalization of Lucas' Theorem given by Granville + # to obtain binomial(n, k) mod p^e, and then use the Chinese + # Remainder Theorem to obtain the result mod q + if n < 0 or m < 0 or m > n: return 0 + factorisation = factorint(k) + residues = [_binomial_mod_prime_power(n, m, p, e) for p, e in factorisation.items()] + return crt([p**pw for p, pw in factorisation.items()], residues, check=False)[0] + + +def _binomial_mod_prime_power(n, m, p, q): + """Compute ``binomial(n, m) % p**q`` for a prime ``p``. + + Parameters + ========== + + n : positive integer + m : a nonnegative integer + p : a prime + q : a positive integer (the prime exponent) + + Examples + ======== + + >>> from sympy.ntheory.residue_ntheory import _binomial_mod_prime_power + >>> _binomial_mod_prime_power(10, 2, 3, 2) # binomial(10, 2) = 45 + 0 + >>> _binomial_mod_prime_power(17, 9, 2, 4) # binomial(17, 9) = 24310 + 6 + + References + ========== + + .. [1] Binomial coefficients modulo prime powers, Andrew Granville, + Available: https://web.archive.org/web/20170202003812/http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf + """ + # Function/variable naming within this function follows Ref.[1] + # n!_p will be used to denote the product of integers <= n not divisible by + # p, with binomial(n, m)_p the same as binomial(n, m), but defined using + # n!_p in place of n! + modulo = pow(p, q) + + def up_factorial(u): + """Compute (u*p)!_p modulo p^q.""" + r = q // 2 + fac = prod = 1 + if r == 1 and p == 2 or 2*r + 1 in (p, p*p): + if q % 2 == 1: r += 1 + modulo, div = pow(p, 2*r), pow(p, 2*r - q) + else: + modulo, div = pow(p, 2*r + 1), pow(p, (2*r + 1) - q) + for j in range(1, r + 1): + for mul in range((j - 1)*p + 1, j*p): # ignore jp itself + fac *= mul + fac %= modulo + bj_ = bj(u, j, r) + prod *= pow(fac, bj_, modulo) + prod %= modulo + if p == 2: + sm = u // 2 + for j in range(1, r + 1): sm += j//2 * bj(u, j, r) + if sm % 2 == 1: prod *= -1 + prod %= modulo//div + return prod % modulo + + def bj(u, j, r): + """Compute the exponent of (j*p)!_p in the calculation of (u*p)!_p.""" + prod = u + for i in range(1, r + 1): + if i != j: prod *= u*u - i*i + for i in range(1, r + 1): + if i != j: prod //= j*j - i*i + return prod // j + + def up_plus_v_binom(u, v): + """Compute binomial(u*p + v, v)_p modulo p^q.""" + prod = 1 + div = invert(factorial(v), modulo) + for j in range(1, q): + b = div + for v_ in range(j*p + 1, j*p + v + 1): + b *= v_ + b %= modulo + aj = u + for i in range(1, q): + if i != j: aj *= u - i + for i in range(1, q): + if i != j: aj //= j - i + aj //= j + prod *= pow(b, aj, modulo) + prod %= modulo + return prod + + @recurrence_memo([1]) + def factorial(v, prev): + """Compute v! modulo p^q.""" + return v*prev[-1] % modulo + + def factorial_p(n): + """Compute n!_p modulo p^q.""" + u, v = divmod(n, p) + return (factorial(v) * up_factorial(u) * up_plus_v_binom(u, v)) % modulo + + prod = 1 + Nj, Mj, Rj = n, m, n - m + # e0 will be the p-adic valuation of binomial(n, m) at p + e0 = carry = eq_1 = j = 0 + while Nj: + numerator = factorial_p(Nj % modulo) + denominator = factorial_p(Mj % modulo) * factorial_p(Rj % modulo) % modulo + Nj, (Mj, mj), (Rj, rj) = Nj//p, divmod(Mj, p), divmod(Rj, p) + carry = (mj + rj + carry) // p + e0 += carry + if j >= q - 1: eq_1 += carry + prod *= numerator * invert(denominator, modulo) + prod %= modulo + j += 1 + + mul = pow(1 if p == 2 and q >= 3 else -1, eq_1, modulo) + return (pow(p, e0, modulo) * mul * prod) % modulo diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b39d031bca26bc599eb9eb0e12dfe48f7e6db174 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/__init__.py @@ -0,0 +1,4 @@ +"""Used for translating a string into a SymPy expression. """ +__all__ = ['parse_expr'] + +from .sympy_parser import parse_expr diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/ast_parser.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/ast_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..95a773d5bec6e130810b7b7925fdff57270aec17 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/ast_parser.py @@ -0,0 +1,79 @@ +""" +This module implements the functionality to take any Python expression as a +string and fix all numbers and other things before evaluating it, +thus + +1/2 + +returns + +Integer(1)/Integer(2) + +We use the ast module for this. It is well documented at docs.python.org. + +Some tips to understand how this works: use dump() to get a nice +representation of any node. Then write a string of what you want to get, +e.g. "Integer(1)", parse it, dump it and you'll see that you need to do +"Call(Name('Integer', Load()), [node], [], None, None)". You do not need +to bother with lineno and col_offset, just call fix_missing_locations() +before returning the node. +""" + +from sympy.core.basic import Basic +from sympy.core.sympify import SympifyError + +from ast import parse, NodeTransformer, Call, Name, Load, \ + fix_missing_locations, Constant, Tuple + +class Transform(NodeTransformer): + + def __init__(self, local_dict, global_dict): + NodeTransformer.__init__(self) + self.local_dict = local_dict + self.global_dict = global_dict + + def visit_Constant(self, node): + if isinstance(node.value, int): + return fix_missing_locations(Call(func=Name('Integer', Load()), + args=[node], keywords=[])) + elif isinstance(node.value, float): + return fix_missing_locations(Call(func=Name('Float', Load()), + args=[node], keywords=[])) + return node + + def visit_Name(self, node): + if node.id in self.local_dict: + return node + elif node.id in self.global_dict: + name_obj = self.global_dict[node.id] + + if isinstance(name_obj, (Basic, type)) or callable(name_obj): + return node + elif node.id in ['True', 'False']: + return node + return fix_missing_locations(Call(func=Name('Symbol', Load()), + args=[Constant(node.id)], keywords=[])) + + def visit_Lambda(self, node): + args = [self.visit(arg) for arg in node.args.args] + body = self.visit(node.body) + n = Call(func=Name('Lambda', Load()), + args=[Tuple(args, Load()), body], keywords=[]) + return fix_missing_locations(n) + +def parse_expr(s, local_dict): + """ + Converts the string "s" to a SymPy expression, in local_dict. + + It converts all numbers to Integers before feeding it to Python and + automatically creates Symbols. + """ + global_dict = {} + exec('from sympy import *', global_dict) + try: + a = parse(s.strip(), mode="eval") + except SyntaxError: + raise SympifyError("Cannot parse %s." % repr(s)) + a = Transform(local_dict, global_dict).visit(a) + e = compile(a, "", "eval") + return eval(e, global_dict, local_dict) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/mathematica.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/mathematica.py new file mode 100644 index 0000000000000000000000000000000000000000..b5824a8c33ee402d03e6c5617eeeea21d4a457d1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/mathematica.py @@ -0,0 +1,1085 @@ +from __future__ import annotations +import re +import typing +from itertools import product +from typing import Any, Callable + +import sympy +from sympy import Mul, Add, Pow, Rational, log, exp, sqrt, cos, sin, tan, asin, acos, acot, asec, acsc, sinh, cosh, tanh, asinh, \ + acosh, atanh, acoth, asech, acsch, expand, im, flatten, polylog, cancel, expand_trig, sign, simplify, \ + UnevaluatedExpr, S, atan, atan2, Mod, Max, Min, rf, Ei, Si, Ci, airyai, airyaiprime, airybi, primepi, prime, \ + isprime, cot, sec, csc, csch, sech, coth, Function, I, pi, Tuple, GreaterThan, StrictGreaterThan, StrictLessThan, \ + LessThan, Equality, Or, And, Lambda, Integer, Dummy, symbols +from sympy.core.sympify import sympify, _sympify +from sympy.functions.special.bessel import airybiprime +from sympy.functions.special.error_functions import li +from sympy.utilities.exceptions import sympy_deprecation_warning + + +def mathematica(s, additional_translations=None): + sympy_deprecation_warning( + """The ``mathematica`` function for the Mathematica parser is now +deprecated. Use ``parse_mathematica`` instead. +The parameter ``additional_translation`` can be replaced by SymPy's +.replace( ) or .subs( ) methods on the output expression instead.""", + deprecated_since_version="1.11", + active_deprecations_target="mathematica-parser-new", + ) + parser = MathematicaParser(additional_translations) + return sympify(parser._parse_old(s)) + + +def parse_mathematica(s): + """ + Translate a string containing a Wolfram Mathematica expression to a SymPy + expression. + + If the translator is unable to find a suitable SymPy expression, the + ``FullForm`` of the Mathematica expression will be output, using SymPy + ``Function`` objects as nodes of the syntax tree. + + Examples + ======== + + >>> from sympy.parsing.mathematica import parse_mathematica + >>> parse_mathematica("Sin[x]^2 Tan[y]") + sin(x)**2*tan(y) + >>> e = parse_mathematica("F[7,5,3]") + >>> e + F(7, 5, 3) + >>> from sympy import Function, Max, Min + >>> e.replace(Function("F"), lambda *x: Max(*x)*Min(*x)) + 21 + + Both standard input form and Mathematica full form are supported: + + >>> parse_mathematica("x*(a + b)") + x*(a + b) + >>> parse_mathematica("Times[x, Plus[a, b]]") + x*(a + b) + + To get a matrix from Wolfram's code: + + >>> m = parse_mathematica("{{a, b}, {c, d}}") + >>> m + ((a, b), (c, d)) + >>> from sympy import Matrix + >>> Matrix(m) + Matrix([ + [a, b], + [c, d]]) + + If the translation into equivalent SymPy expressions fails, an SymPy + expression equivalent to Wolfram Mathematica's "FullForm" will be created: + + >>> parse_mathematica("x_.") + Optional(Pattern(x, Blank())) + >>> parse_mathematica("Plus @@ {x, y, z}") + Apply(Plus, (x, y, z)) + >>> parse_mathematica("f[x_, 3] := x^3 /; x > 0") + SetDelayed(f(Pattern(x, Blank()), 3), Condition(x**3, x > 0)) + """ + parser = MathematicaParser() + return parser.parse(s) + + +def _parse_Function(*args): + if len(args) == 1: + arg = args[0] + Slot = Function("Slot") + slots = arg.atoms(Slot) + numbers = [a.args[0] for a in slots] + number_of_arguments = max(numbers) + if isinstance(number_of_arguments, Integer): + variables = symbols(f"dummy0:{number_of_arguments}", cls=Dummy) + return Lambda(variables, arg.xreplace({Slot(i+1): v for i, v in enumerate(variables)})) + return Lambda((), arg) + elif len(args) == 2: + variables = args[0] + body = args[1] + return Lambda(variables, body) + else: + raise SyntaxError("Function node expects 1 or 2 arguments") + + +def _deco(cls): + cls._initialize_class() + return cls + + +@_deco +class MathematicaParser: + """ + An instance of this class converts a string of a Wolfram Mathematica + expression to a SymPy expression. + + The main parser acts internally in three stages: + + 1. tokenizer: tokenizes the Mathematica expression and adds the missing * + operators. Handled by ``_from_mathematica_to_tokens(...)`` + 2. full form list: sort the list of strings output by the tokenizer into a + syntax tree of nested lists and strings, equivalent to Mathematica's + ``FullForm`` expression output. This is handled by the function + ``_from_tokens_to_fullformlist(...)``. + 3. SymPy expression: the syntax tree expressed as full form list is visited + and the nodes with equivalent classes in SymPy are replaced. Unknown + syntax tree nodes are cast to SymPy ``Function`` objects. This is + handled by ``_from_fullformlist_to_sympy(...)``. + + """ + + # left: Mathematica, right: SymPy + CORRESPONDENCES = { + 'Sqrt[x]': 'sqrt(x)', + 'Rational[x,y]': 'Rational(x,y)', + 'Exp[x]': 'exp(x)', + 'Log[x]': 'log(x)', + 'Log[x,y]': 'log(y,x)', + 'Log2[x]': 'log(x,2)', + 'Log10[x]': 'log(x,10)', + 'Mod[x,y]': 'Mod(x,y)', + 'Max[*x]': 'Max(*x)', + 'Min[*x]': 'Min(*x)', + 'Pochhammer[x,y]':'rf(x,y)', + 'ArcTan[x,y]':'atan2(y,x)', + 'ExpIntegralEi[x]': 'Ei(x)', + 'SinIntegral[x]': 'Si(x)', + 'CosIntegral[x]': 'Ci(x)', + 'AiryAi[x]': 'airyai(x)', + 'AiryAiPrime[x]': 'airyaiprime(x)', + 'AiryBi[x]' :'airybi(x)', + 'AiryBiPrime[x]' :'airybiprime(x)', + 'LogIntegral[x]':' li(x)', + 'PrimePi[x]': 'primepi(x)', + 'Prime[x]': 'prime(x)', + 'PrimeQ[x]': 'isprime(x)' + } + + # trigonometric, e.t.c. + for arc, tri, h in product(('', 'Arc'), ( + 'Sin', 'Cos', 'Tan', 'Cot', 'Sec', 'Csc'), ('', 'h')): + fm = arc + tri + h + '[x]' + if arc: # arc func + fs = 'a' + tri.lower() + h + '(x)' + else: # non-arc func + fs = tri.lower() + h + '(x)' + CORRESPONDENCES.update({fm: fs}) + + REPLACEMENTS = { + ' ': '', + '^': '**', + '{': '[', + '}': ']', + } + + RULES = { + # a single whitespace to '*' + 'whitespace': ( + re.compile(r''' + (?:(?<=[a-zA-Z\d])|(?<=\d\.)) # a letter or a number + \s+ # any number of whitespaces + (?:(?=[a-zA-Z\d])|(?=\.\d)) # a letter or a number + ''', re.VERBOSE), + '*'), + + # add omitted '*' character + 'add*_1': ( + re.compile(r''' + (?:(?<=[])\d])|(?<=\d\.)) # ], ) or a number + # '' + (?=[(a-zA-Z]) # ( or a single letter + ''', re.VERBOSE), + '*'), + + # add omitted '*' character (variable letter preceding) + 'add*_2': ( + re.compile(r''' + (?<=[a-zA-Z]) # a letter + \( # ( as a character + (?=.) # any characters + ''', re.VERBOSE), + '*('), + + # convert 'Pi' to 'pi' + 'Pi': ( + re.compile(r''' + (?: + \A|(?<=[^a-zA-Z]) + ) + Pi # 'Pi' is 3.14159... in Mathematica + (?=[^a-zA-Z]) + ''', re.VERBOSE), + 'pi'), + } + + # Mathematica function name pattern + FM_PATTERN = re.compile(r''' + (?: + \A|(?<=[^a-zA-Z]) # at the top or a non-letter + ) + [A-Z][a-zA-Z\d]* # Function + (?=\[) # [ as a character + ''', re.VERBOSE) + + # list or matrix pattern (for future usage) + ARG_MTRX_PATTERN = re.compile(r''' + \{.*\} + ''', re.VERBOSE) + + # regex string for function argument pattern + ARGS_PATTERN_TEMPLATE = r''' + (?: + \A|(?<=[^a-zA-Z]) + ) + {arguments} # model argument like x, y,... + (?=[^a-zA-Z]) + ''' + + # will contain transformed CORRESPONDENCES dictionary + TRANSLATIONS: dict[tuple[str, int], dict[str, Any]] = {} + + # cache for a raw users' translation dictionary + cache_original: dict[tuple[str, int], dict[str, Any]] = {} + + # cache for a compiled users' translation dictionary + cache_compiled: dict[tuple[str, int], dict[str, Any]] = {} + + @classmethod + def _initialize_class(cls): + # get a transformed CORRESPONDENCES dictionary + d = cls._compile_dictionary(cls.CORRESPONDENCES) + cls.TRANSLATIONS.update(d) + + def __init__(self, additional_translations=None): + self.translations = {} + + # update with TRANSLATIONS (class constant) + self.translations.update(self.TRANSLATIONS) + + if additional_translations is None: + additional_translations = {} + + # check the latest added translations + if self.__class__.cache_original != additional_translations: + if not isinstance(additional_translations, dict): + raise ValueError('The argument must be dict type') + + # get a transformed additional_translations dictionary + d = self._compile_dictionary(additional_translations) + + # update cache + self.__class__.cache_original = additional_translations + self.__class__.cache_compiled = d + + # merge user's own translations + self.translations.update(self.__class__.cache_compiled) + + @classmethod + def _compile_dictionary(cls, dic): + # for return + d = {} + + for fm, fs in dic.items(): + # check function form + cls._check_input(fm) + cls._check_input(fs) + + # uncover '*' hiding behind a whitespace + fm = cls._apply_rules(fm, 'whitespace') + fs = cls._apply_rules(fs, 'whitespace') + + # remove whitespace(s) + fm = cls._replace(fm, ' ') + fs = cls._replace(fs, ' ') + + # search Mathematica function name + m = cls.FM_PATTERN.search(fm) + + # if no-hit + if m is None: + err = "'{f}' function form is invalid.".format(f=fm) + raise ValueError(err) + + # get Mathematica function name like 'Log' + fm_name = m.group() + + # get arguments of Mathematica function + args, end = cls._get_args(m) + + # function side check. (e.g.) '2*Func[x]' is invalid. + if m.start() != 0 or end != len(fm): + err = "'{f}' function form is invalid.".format(f=fm) + raise ValueError(err) + + # check the last argument's 1st character + if args[-1][0] == '*': + key_arg = '*' + else: + key_arg = len(args) + + key = (fm_name, key_arg) + + # convert '*x' to '\\*x' for regex + re_args = [x if x[0] != '*' else '\\' + x for x in args] + + # for regex. Example: (?:(x|y|z)) + xyz = '(?:(' + '|'.join(re_args) + '))' + + # string for regex compile + patStr = cls.ARGS_PATTERN_TEMPLATE.format(arguments=xyz) + + pat = re.compile(patStr, re.VERBOSE) + + # update dictionary + d[key] = {} + d[key]['fs'] = fs # SymPy function template + d[key]['args'] = args # args are ['x', 'y'] for example + d[key]['pat'] = pat + + return d + + def _convert_function(self, s): + '''Parse Mathematica function to SymPy one''' + + # compiled regex object + pat = self.FM_PATTERN + + scanned = '' # converted string + cur = 0 # position cursor + while True: + m = pat.search(s) + + if m is None: + # append the rest of string + scanned += s + break + + # get Mathematica function name + fm = m.group() + + # get arguments, and the end position of fm function + args, end = self._get_args(m) + + # the start position of fm function + bgn = m.start() + + # convert Mathematica function to SymPy one + s = self._convert_one_function(s, fm, args, bgn, end) + + # update cursor + cur = bgn + + # append converted part + scanned += s[:cur] + + # shrink s + s = s[cur:] + + return scanned + + def _convert_one_function(self, s, fm, args, bgn, end): + # no variable-length argument + if (fm, len(args)) in self.translations: + key = (fm, len(args)) + + # x, y,... model arguments + x_args = self.translations[key]['args'] + + # make CORRESPONDENCES between model arguments and actual ones + d = dict(zip(x_args, args)) + + # with variable-length argument + elif (fm, '*') in self.translations: + key = (fm, '*') + + # x, y,..*args (model arguments) + x_args = self.translations[key]['args'] + + # make CORRESPONDENCES between model arguments and actual ones + d = {} + for i, x in enumerate(x_args): + if x[0] == '*': + d[x] = ','.join(args[i:]) + break + d[x] = args[i] + + # out of self.translations + else: + err = "'{f}' is out of the whitelist.".format(f=fm) + raise ValueError(err) + + # template string of converted function + template = self.translations[key]['fs'] + + # regex pattern for x_args + pat = self.translations[key]['pat'] + + scanned = '' + cur = 0 + while True: + m = pat.search(template) + + if m is None: + scanned += template + break + + # get model argument + x = m.group() + + # get a start position of the model argument + xbgn = m.start() + + # add the corresponding actual argument + scanned += template[:xbgn] + d[x] + + # update cursor to the end of the model argument + cur = m.end() + + # shrink template + template = template[cur:] + + # update to swapped string + s = s[:bgn] + scanned + s[end:] + + return s + + @classmethod + def _get_args(cls, m): + '''Get arguments of a Mathematica function''' + + s = m.string # whole string + anc = m.end() + 1 # pointing the first letter of arguments + square, curly = [], [] # stack for brackets + args = [] + + # current cursor + cur = anc + for i, c in enumerate(s[anc:], anc): + # extract one argument + if c == ',' and (not square) and (not curly): + args.append(s[cur:i]) # add an argument + cur = i + 1 # move cursor + + # handle list or matrix (for future usage) + if c == '{': + curly.append(c) + elif c == '}': + curly.pop() + + # seek corresponding ']' with skipping irrevant ones + if c == '[': + square.append(c) + elif c == ']': + if square: + square.pop() + else: # empty stack + args.append(s[cur:i]) + break + + # the next position to ']' bracket (the function end) + func_end = i + 1 + + return args, func_end + + @classmethod + def _replace(cls, s, bef): + aft = cls.REPLACEMENTS[bef] + s = s.replace(bef, aft) + return s + + @classmethod + def _apply_rules(cls, s, bef): + pat, aft = cls.RULES[bef] + return pat.sub(aft, s) + + @classmethod + def _check_input(cls, s): + for bracket in (('[', ']'), ('{', '}'), ('(', ')')): + if s.count(bracket[0]) != s.count(bracket[1]): + err = "'{f}' function form is invalid.".format(f=s) + raise ValueError(err) + + if '{' in s: + err = "Currently list is not supported." + raise ValueError(err) + + def _parse_old(self, s): + # input check + self._check_input(s) + + # uncover '*' hiding behind a whitespace + s = self._apply_rules(s, 'whitespace') + + # remove whitespace(s) + s = self._replace(s, ' ') + + # add omitted '*' character + s = self._apply_rules(s, 'add*_1') + s = self._apply_rules(s, 'add*_2') + + # translate function + s = self._convert_function(s) + + # '^' to '**' + s = self._replace(s, '^') + + # 'Pi' to 'pi' + s = self._apply_rules(s, 'Pi') + + # '{', '}' to '[', ']', respectively +# s = cls._replace(s, '{') # currently list is not taken into account +# s = cls._replace(s, '}') + + return s + + def parse(self, s): + s2 = self._from_mathematica_to_tokens(s) + s3 = self._from_tokens_to_fullformlist(s2) + s4 = self._from_fullformlist_to_sympy(s3) + return s4 + + INFIX = "Infix" + PREFIX = "Prefix" + POSTFIX = "Postfix" + FLAT = "Flat" + RIGHT = "Right" + LEFT = "Left" + + _mathematica_op_precedence: list[tuple[str, str | None, dict[str, str | Callable]]] = [ + (POSTFIX, None, {";": lambda x: x + ["Null"] if isinstance(x, list) and x and x[0] == "CompoundExpression" else ["CompoundExpression", x, "Null"]}), + (INFIX, FLAT, {";": "CompoundExpression"}), + (INFIX, RIGHT, {"=": "Set", ":=": "SetDelayed", "+=": "AddTo", "-=": "SubtractFrom", "*=": "TimesBy", "/=": "DivideBy"}), + (INFIX, LEFT, {"//": lambda x, y: [x, y]}), + (POSTFIX, None, {"&": "Function"}), + (INFIX, LEFT, {"/.": "ReplaceAll"}), + (INFIX, RIGHT, {"->": "Rule", ":>": "RuleDelayed"}), + (INFIX, LEFT, {"/;": "Condition"}), + (INFIX, FLAT, {"|": "Alternatives"}), + (POSTFIX, None, {"..": "Repeated", "...": "RepeatedNull"}), + (INFIX, FLAT, {"||": "Or"}), + (INFIX, FLAT, {"&&": "And"}), + (PREFIX, None, {"!": "Not"}), + (INFIX, FLAT, {"===": "SameQ", "=!=": "UnsameQ"}), + (INFIX, FLAT, {"==": "Equal", "!=": "Unequal", "<=": "LessEqual", "<": "Less", ">=": "GreaterEqual", ">": "Greater"}), + (INFIX, None, {";;": "Span"}), + (INFIX, FLAT, {"+": "Plus", "-": "Plus"}), + (INFIX, FLAT, {"*": "Times", "/": "Times"}), + (INFIX, FLAT, {".": "Dot"}), + (PREFIX, None, {"-": lambda x: MathematicaParser._get_neg(x), + "+": lambda x: x}), + (INFIX, RIGHT, {"^": "Power"}), + (INFIX, RIGHT, {"@@": "Apply", "/@": "Map", "//@": "MapAll", "@@@": lambda x, y: ["Apply", x, y, ["List", "1"]]}), + (POSTFIX, None, {"'": "Derivative", "!": "Factorial", "!!": "Factorial2", "--": "Decrement"}), + (INFIX, None, {"[": lambda x, y: [x, *y], "[[": lambda x, y: ["Part", x, *y]}), + (PREFIX, None, {"{": lambda x: ["List", *x], "(": lambda x: x[0]}), + (INFIX, None, {"?": "PatternTest"}), + (POSTFIX, None, { + "_": lambda x: ["Pattern", x, ["Blank"]], + "_.": lambda x: ["Optional", ["Pattern", x, ["Blank"]]], + "__": lambda x: ["Pattern", x, ["BlankSequence"]], + "___": lambda x: ["Pattern", x, ["BlankNullSequence"]], + }), + (INFIX, None, {"_": lambda x, y: ["Pattern", x, ["Blank", y]]}), + (PREFIX, None, {"#": "Slot", "##": "SlotSequence"}), + ] + + _missing_arguments_default = { + "#": lambda: ["Slot", "1"], + "##": lambda: ["SlotSequence", "1"], + } + + _literal = r"[A-Za-z][A-Za-z0-9]*" + _number = r"(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)" + + _enclosure_open = ["(", "[", "[[", "{"] + _enclosure_close = [")", "]", "]]", "}"] + + @classmethod + def _get_neg(cls, x): + return f"-{x}" if isinstance(x, str) and re.match(MathematicaParser._number, x) else ["Times", "-1", x] + + @classmethod + def _get_inv(cls, x): + return ["Power", x, "-1"] + + _regex_tokenizer = None + + def _get_tokenizer(self): + if self._regex_tokenizer is not None: + # Check if the regular expression has already been compiled: + return self._regex_tokenizer + tokens = [self._literal, self._number] + tokens_escape = self._enclosure_open[:] + self._enclosure_close[:] + for typ, strat, symdict in self._mathematica_op_precedence: + for k in symdict: + tokens_escape.append(k) + tokens_escape.sort(key=lambda x: -len(x)) + tokens.extend(map(re.escape, tokens_escape)) + tokens.append(",") + tokens.append("\n") + tokenizer = re.compile("(" + "|".join(tokens) + ")") + self._regex_tokenizer = tokenizer + return self._regex_tokenizer + + def _from_mathematica_to_tokens(self, code: str): + tokenizer = self._get_tokenizer() + + # Find strings: + code_splits: list[str | list] = [] + while True: + string_start = code.find("\"") + if string_start == -1: + if len(code) > 0: + code_splits.append(code) + break + match_end = re.search(r'(? 0: + code_splits.append(code[:string_start]) + code_splits.append(["_Str", code[string_start+1:string_end].replace('\\"', '"')]) + code = code[string_end+1:] + + # Remove comments: + for i, code_split in enumerate(code_splits): + if isinstance(code_split, list): + continue + while True: + pos_comment_start = code_split.find("(*") + if pos_comment_start == -1: + break + pos_comment_end = code_split.find("*)") + if pos_comment_end == -1 or pos_comment_end < pos_comment_start: + raise SyntaxError("mismatch in comment (* *) code") + code_split = code_split[:pos_comment_start] + code_split[pos_comment_end+2:] + code_splits[i] = code_split + + # Tokenize the input strings with a regular expression: + token_lists = [tokenizer.findall(i) if isinstance(i, str) and i.isascii() else [i] for i in code_splits] + tokens = [j for i in token_lists for j in i] + + # Remove newlines at the beginning + while tokens and tokens[0] == "\n": + tokens.pop(0) + # Remove newlines at the end + while tokens and tokens[-1] == "\n": + tokens.pop(-1) + + return tokens + + def _is_op(self, token: str | list) -> bool: + if isinstance(token, list): + return False + if re.match(self._literal, token): + return False + if re.match("-?" + self._number, token): + return False + return True + + def _is_valid_star1(self, token: str | list) -> bool: + if token in (")", "}"): + return True + return not self._is_op(token) + + def _is_valid_star2(self, token: str | list) -> bool: + if token in ("(", "{"): + return True + return not self._is_op(token) + + def _from_tokens_to_fullformlist(self, tokens: list): + stack: list[list] = [[]] + open_seq = [] + pointer: int = 0 + while pointer < len(tokens): + token = tokens[pointer] + if token in self._enclosure_open: + stack[-1].append(token) + open_seq.append(token) + stack.append([]) + elif token == ",": + if len(stack[-1]) == 0 and stack[-2][-1] == open_seq[-1]: + raise SyntaxError("%s cannot be followed by comma ," % open_seq[-1]) + stack[-1] = self._parse_after_braces(stack[-1]) + stack.append([]) + elif token in self._enclosure_close: + ind = self._enclosure_close.index(token) + if self._enclosure_open[ind] != open_seq[-1]: + unmatched_enclosure = SyntaxError("unmatched enclosure") + if token == "]]" and open_seq[-1] == "[": + if open_seq[-2] == "[": + # These two lines would be logically correct, but are + # unnecessary: + # token = "]" + # tokens[pointer] = "]" + tokens.insert(pointer+1, "]") + elif open_seq[-2] == "[[": + if tokens[pointer+1] == "]": + tokens[pointer+1] = "]]" + elif tokens[pointer+1] == "]]": + tokens[pointer+1] = "]]" + tokens.insert(pointer+2, "]") + else: + raise unmatched_enclosure + else: + raise unmatched_enclosure + if len(stack[-1]) == 0 and stack[-2][-1] == "(": + raise SyntaxError("( ) not valid syntax") + last_stack = self._parse_after_braces(stack[-1], True) + stack[-1] = last_stack + new_stack_element = [] + while stack[-1][-1] != open_seq[-1]: + new_stack_element.append(stack.pop()) + new_stack_element.reverse() + if open_seq[-1] == "(" and len(new_stack_element) != 1: + raise SyntaxError("( must be followed by one expression, %i detected" % len(new_stack_element)) + stack[-1].append(new_stack_element) + open_seq.pop(-1) + else: + stack[-1].append(token) + pointer += 1 + if len(stack) != 1: + raise RuntimeError("Stack should have only one element") + return self._parse_after_braces(stack[0]) + + def _util_remove_newlines(self, lines: list, tokens: list, inside_enclosure: bool): + pointer = 0 + size = len(tokens) + while pointer < size: + token = tokens[pointer] + if token == "\n": + if inside_enclosure: + # Ignore newlines inside enclosures + tokens.pop(pointer) + size -= 1 + continue + if pointer == 0: + tokens.pop(0) + size -= 1 + continue + if pointer > 1: + try: + prev_expr = self._parse_after_braces(tokens[:pointer], inside_enclosure) + except SyntaxError: + tokens.pop(pointer) + size -= 1 + continue + else: + prev_expr = tokens[0] + if len(prev_expr) > 0 and prev_expr[0] == "CompoundExpression": + lines.extend(prev_expr[1:]) + else: + lines.append(prev_expr) + for i in range(pointer): + tokens.pop(0) + size -= pointer + pointer = 0 + continue + pointer += 1 + + def _util_add_missing_asterisks(self, tokens: list): + size: int = len(tokens) + pointer: int = 0 + while pointer < size: + if (pointer > 0 and + self._is_valid_star1(tokens[pointer - 1]) and + self._is_valid_star2(tokens[pointer])): + # This is a trick to add missing * operators in the expression, + # `"*" in op_dict` makes sure the precedence level is the same as "*", + # while `not self._is_op( ... )` makes sure this and the previous + # expression are not operators. + if tokens[pointer] == "(": + # ( has already been processed by now, replace: + tokens[pointer] = "*" + tokens[pointer + 1] = tokens[pointer + 1][0] + else: + tokens.insert(pointer, "*") + pointer += 1 + size += 1 + pointer += 1 + + def _parse_after_braces(self, tokens: list, inside_enclosure: bool = False): + op_dict: dict + changed: bool = False + lines: list = [] + + self._util_remove_newlines(lines, tokens, inside_enclosure) + + for op_type, grouping_strat, op_dict in reversed(self._mathematica_op_precedence): + if "*" in op_dict: + self._util_add_missing_asterisks(tokens) + size: int = len(tokens) + pointer: int = 0 + while pointer < size: + token = tokens[pointer] + if isinstance(token, str) and token in op_dict: + op_name: str | Callable = op_dict[token] + node: list + first_index: int + if isinstance(op_name, str): + node = [op_name] + first_index = 1 + else: + node = [] + first_index = 0 + if token in ("+", "-") and op_type == self.PREFIX and pointer > 0 and not self._is_op(tokens[pointer - 1]): + # Make sure that PREFIX + - don't match expressions like a + b or a - b, + # the INFIX + - are supposed to match that expression: + pointer += 1 + continue + if op_type == self.INFIX: + if pointer == 0 or pointer == size - 1 or self._is_op(tokens[pointer - 1]) or self._is_op(tokens[pointer + 1]): + pointer += 1 + continue + changed = True + tokens[pointer] = node + if op_type == self.INFIX: + arg1 = tokens.pop(pointer-1) + arg2 = tokens.pop(pointer) + if token == "/": + arg2 = self._get_inv(arg2) + elif token == "-": + arg2 = self._get_neg(arg2) + pointer -= 1 + size -= 2 + node.append(arg1) + node_p = node + if grouping_strat == self.FLAT: + while pointer + 2 < size and self._check_op_compatible(tokens[pointer+1], token): + node_p.append(arg2) + other_op = tokens.pop(pointer+1) + arg2 = tokens.pop(pointer+1) + if other_op == "/": + arg2 = self._get_inv(arg2) + elif other_op == "-": + arg2 = self._get_neg(arg2) + size -= 2 + node_p.append(arg2) + elif grouping_strat == self.RIGHT: + while pointer + 2 < size and tokens[pointer+1] == token: + node_p.append([op_name, arg2]) + node_p = node_p[-1] + tokens.pop(pointer+1) + arg2 = tokens.pop(pointer+1) + size -= 2 + node_p.append(arg2) + elif grouping_strat == self.LEFT: + while pointer + 1 < size and tokens[pointer+1] == token: + if isinstance(op_name, str): + node_p[first_index] = [op_name, node_p[first_index], arg2] + else: + node_p[first_index] = op_name(node_p[first_index], arg2) + tokens.pop(pointer+1) + arg2 = tokens.pop(pointer+1) + size -= 2 + node_p.append(arg2) + else: + node.append(arg2) + elif op_type == self.PREFIX: + if grouping_strat is not None: + raise TypeError("'Prefix' op_type should not have a grouping strat") + if pointer == size - 1 or self._is_op(tokens[pointer + 1]): + tokens[pointer] = self._missing_arguments_default[token]() + else: + node.append(tokens.pop(pointer+1)) + size -= 1 + elif op_type == self.POSTFIX: + if grouping_strat is not None: + raise TypeError("'Prefix' op_type should not have a grouping strat") + if pointer == 0 or self._is_op(tokens[pointer - 1]): + tokens[pointer] = self._missing_arguments_default[token]() + else: + node.append(tokens.pop(pointer-1)) + pointer -= 1 + size -= 1 + if isinstance(op_name, Callable): # type: ignore + op_call: Callable = typing.cast(Callable, op_name) + new_node = op_call(*node) + node.clear() + if isinstance(new_node, list): + node.extend(new_node) + else: + tokens[pointer] = new_node + pointer += 1 + if len(tokens) > 1 or (len(lines) == 0 and len(tokens) == 0): + if changed: + # Trick to deal with cases in which an operator with lower + # precedence should be transformed before an operator of higher + # precedence. Such as in the case of `#&[x]` (that is + # equivalent to `Lambda(d_, d_)(x)` in SymPy). In this case the + # operator `&` has lower precedence than `[`, but needs to be + # evaluated first because otherwise `# (&[x])` is not a valid + # expression: + return self._parse_after_braces(tokens, inside_enclosure) + raise SyntaxError("unable to create a single AST for the expression") + if len(lines) > 0: + if tokens[0] and tokens[0][0] == "CompoundExpression": + tokens = tokens[0][1:] + compound_expression = ["CompoundExpression", *lines, *tokens] + return compound_expression + return tokens[0] + + def _check_op_compatible(self, op1: str, op2: str): + if op1 == op2: + return True + muldiv = {"*", "/"} + addsub = {"+", "-"} + if op1 in muldiv and op2 in muldiv: + return True + if op1 in addsub and op2 in addsub: + return True + return False + + def _from_fullform_to_fullformlist(self, wmexpr: str): + """ + Parses FullForm[Downvalues[]] generated by Mathematica + """ + out: list = [] + stack = [out] + generator = re.finditer(r'[\[\],]', wmexpr) + last_pos = 0 + for match in generator: + if match is None: + break + position = match.start() + last_expr = wmexpr[last_pos:position].replace(',', '').replace(']', '').replace('[', '').strip() + + if match.group() == ',': + if last_expr != '': + stack[-1].append(last_expr) + elif match.group() == ']': + if last_expr != '': + stack[-1].append(last_expr) + stack.pop() + elif match.group() == '[': + stack[-1].append([last_expr]) + stack.append(stack[-1][-1]) + last_pos = match.end() + return out[0] + + def _from_fullformlist_to_fullformsympy(self, pylist: list): + from sympy import Function, Symbol + + def converter(expr): + if isinstance(expr, list): + if len(expr) > 0: + head = expr[0] + args = [converter(arg) for arg in expr[1:]] + return Function(head)(*args) + else: + raise ValueError("Empty list of expressions") + elif isinstance(expr, str): + return Symbol(expr) + else: + return _sympify(expr) + + return converter(pylist) + + _node_conversions = { + "Times": Mul, + "Plus": Add, + "Power": Pow, + "Rational": Rational, + "Log": lambda *a: log(*reversed(a)), + "Log2": lambda x: log(x, 2), + "Log10": lambda x: log(x, 10), + "Exp": exp, + "Sqrt": sqrt, + + "Sin": sin, + "Cos": cos, + "Tan": tan, + "Cot": cot, + "Sec": sec, + "Csc": csc, + + "ArcSin": asin, + "ArcCos": acos, + "ArcTan": lambda *a: atan2(*reversed(a)) if len(a) == 2 else atan(*a), + "ArcCot": acot, + "ArcSec": asec, + "ArcCsc": acsc, + + "Sinh": sinh, + "Cosh": cosh, + "Tanh": tanh, + "Coth": coth, + "Sech": sech, + "Csch": csch, + + "ArcSinh": asinh, + "ArcCosh": acosh, + "ArcTanh": atanh, + "ArcCoth": acoth, + "ArcSech": asech, + "ArcCsch": acsch, + + "Expand": expand, + "Im": im, + "Re": sympy.re, + "Flatten": flatten, + "Polylog": polylog, + "Cancel": cancel, + # Gamma=gamma, + "TrigExpand": expand_trig, + "Sign": sign, + "Simplify": simplify, + "Defer": UnevaluatedExpr, + "Identity": S, + # Sum=Sum_doit, + # Module=With, + # Block=With, + "Null": lambda *a: S.Zero, + "Mod": Mod, + "Max": Max, + "Min": Min, + "Pochhammer": rf, + "ExpIntegralEi": Ei, + "SinIntegral": Si, + "CosIntegral": Ci, + "AiryAi": airyai, + "AiryAiPrime": airyaiprime, + "AiryBi": airybi, + "AiryBiPrime": airybiprime, + "LogIntegral": li, + "PrimePi": primepi, + "Prime": prime, + "PrimeQ": isprime, + + "List": Tuple, + "Greater": StrictGreaterThan, + "GreaterEqual": GreaterThan, + "Less": StrictLessThan, + "LessEqual": LessThan, + "Equal": Equality, + "Or": Or, + "And": And, + + "Function": _parse_Function, + } + + _atom_conversions = { + "I": I, + "Pi": pi, + } + + def _from_fullformlist_to_sympy(self, full_form_list): + + def recurse(expr): + if isinstance(expr, list): + if isinstance(expr[0], list): + head = recurse(expr[0]) + else: + head = self._node_conversions.get(expr[0], Function(expr[0])) + return head(*[recurse(arg) for arg in expr[1:]]) + else: + return self._atom_conversions.get(expr, sympify(expr)) + + return recurse(full_form_list) + + def _from_fullformsympy_to_sympy(self, mform): + + expr = mform + for mma_form, sympy_node in self._node_conversions.items(): + expr = expr.replace(Function(mma_form), sympy_node) + return expr diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/maxima.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/maxima.py new file mode 100644 index 0000000000000000000000000000000000000000..7a8ee5b17bb03a36e338803cb10f9ebf22763c2c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/maxima.py @@ -0,0 +1,71 @@ +import re +from sympy.concrete.products import product +from sympy.concrete.summations import Sum +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import (cos, sin) + + +class MaximaHelpers: + def maxima_expand(expr): + return expr.expand() + + def maxima_float(expr): + return expr.evalf() + + def maxima_trigexpand(expr): + return expr.expand(trig=True) + + def maxima_sum(a1, a2, a3, a4): + return Sum(a1, (a2, a3, a4)).doit() + + def maxima_product(a1, a2, a3, a4): + return product(a1, (a2, a3, a4)) + + def maxima_csc(expr): + return 1/sin(expr) + + def maxima_sec(expr): + return 1/cos(expr) + +sub_dict = { + 'pi': re.compile(r'%pi'), + 'E': re.compile(r'%e'), + 'I': re.compile(r'%i'), + '**': re.compile(r'\^'), + 'oo': re.compile(r'\binf\b'), + '-oo': re.compile(r'\bminf\b'), + "'-'": re.compile(r'\bminus\b'), + 'maxima_expand': re.compile(r'\bexpand\b'), + 'maxima_float': re.compile(r'\bfloat\b'), + 'maxima_trigexpand': re.compile(r'\btrigexpand'), + 'maxima_sum': re.compile(r'\bsum\b'), + 'maxima_product': re.compile(r'\bproduct\b'), + 'cancel': re.compile(r'\bratsimp\b'), + 'maxima_csc': re.compile(r'\bcsc\b'), + 'maxima_sec': re.compile(r'\bsec\b') +} + +var_name = re.compile(r'^\s*(\w+)\s*:') + + +def parse_maxima(str, globals=None, name_dict={}): + str = str.strip() + str = str.rstrip('; ') + + for k, v in sub_dict.items(): + str = v.sub(k, str) + + assign_var = None + var_match = var_name.search(str) + if var_match: + assign_var = var_match.group(1) + str = str[var_match.end():].strip() + + dct = MaximaHelpers.__dict__.copy() + dct.update(name_dict) + obj = sympify(str, locals=dct) + + if assign_var and globals: + globals[assign_var] = obj + + return obj diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/sym_expr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/sym_expr.py new file mode 100644 index 0000000000000000000000000000000000000000..9dbd0e94eb51147b51825fcf15cbec5ae18bb1b6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/sym_expr.py @@ -0,0 +1,279 @@ +from sympy.printing import pycode, ccode, fcode +from sympy.external import import_module +from sympy.utilities.decorator import doctest_depends_on + +lfortran = import_module('lfortran') +cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']}) + +if lfortran: + from sympy.parsing.fortran.fortran_parser import src_to_sympy +if cin: + from sympy.parsing.c.c_parser import parse_c + +@doctest_depends_on(modules=['lfortran', 'clang.cindex']) +class SymPyExpression: # type: ignore + """Class to store and handle SymPy expressions + + This class will hold SymPy Expressions and handle the API for the + conversion to and from different languages. + + It works with the C and the Fortran Parser to generate SymPy expressions + which are stored here and which can be converted to multiple language's + source code. + + Notes + ===== + + The module and its API are currently under development and experimental + and can be changed during development. + + The Fortran parser does not support numeric assignments, so all the + variables have been Initialized to zero. + + The module also depends on external dependencies: + + - LFortran which is required to use the Fortran parser + - Clang which is required for the C parser + + Examples + ======== + + Example of parsing C code: + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src = ''' + ... int a,b; + ... float c = 2, d =4; + ... ''' + >>> a = SymPyExpression(src, 'c') + >>> a.return_expr() + [Declaration(Variable(a, type=intc)), + Declaration(Variable(b, type=intc)), + Declaration(Variable(c, type=float32, value=2.0)), + Declaration(Variable(d, type=float32, value=4.0))] + + An example of variable definition: + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src2 = ''' + ... integer :: a, b, c, d + ... real :: p, q, r, s + ... ''' + >>> p = SymPyExpression() + >>> p.convert_to_expr(src2, 'f') + >>> p.convert_to_c() + ['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0'] + + An example of Assignment: + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src3 = ''' + ... integer :: a, b, c, d, e + ... d = a + b - c + ... e = b * d + c * e / a + ... ''' + >>> p = SymPyExpression(src3, 'f') + >>> p.convert_to_python() + ['a = 0', 'b = 0', 'c = 0', 'd = 0', 'e = 0', 'd = a + b - c', 'e = b*d + c*e/a'] + + An example of function definition: + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src = ''' + ... integer function f(a,b) + ... integer, intent(in) :: a, b + ... integer :: r + ... end function + ... ''' + >>> a = SymPyExpression(src, 'f') + >>> a.convert_to_python() + ['def f(a, b):\\n f = 0\\n r = 0\\n return f'] + + """ + + def __init__(self, source_code = None, mode = None): + """Constructor for SymPyExpression class""" + super().__init__() + if not(mode or source_code): + self._expr = [] + elif mode: + if source_code: + if mode.lower() == 'f': + if lfortran: + self._expr = src_to_sympy(source_code) + else: + raise ImportError("LFortran is not installed, cannot parse Fortran code") + elif mode.lower() == 'c': + if cin: + self._expr = parse_c(source_code) + else: + raise ImportError("Clang is not installed, cannot parse C code") + else: + raise NotImplementedError( + 'Parser for specified language is not implemented' + ) + else: + raise ValueError('Source code not present') + else: + raise ValueError('Please specify a mode for conversion') + + def convert_to_expr(self, src_code, mode): + """Converts the given source code to SymPy Expressions + + Attributes + ========== + + src_code : String + the source code or filename of the source code that is to be + converted + + mode: String + the mode to determine which parser is to be used according to + the language of the source code + f or F for Fortran + c or C for C/C++ + + Examples + ======== + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src3 = ''' + ... integer function f(a,b) result(r) + ... integer, intent(in) :: a, b + ... integer :: x + ... r = a + b -x + ... end function + ... ''' + >>> p = SymPyExpression() + >>> p.convert_to_expr(src3, 'f') + >>> p.return_expr() + [FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock( + Declaration(Variable(r, type=integer, value=0)), + Declaration(Variable(x, type=integer, value=0)), + Assignment(Variable(r), a + b - x), + Return(Variable(r)) + ))] + + + + + """ + if mode.lower() == 'f': + if lfortran: + self._expr = src_to_sympy(src_code) + else: + raise ImportError("LFortran is not installed, cannot parse Fortran code") + elif mode.lower() == 'c': + if cin: + self._expr = parse_c(src_code) + else: + raise ImportError("Clang is not installed, cannot parse C code") + else: + raise NotImplementedError( + "Parser for specified language has not been implemented" + ) + + def convert_to_python(self): + """Returns a list with Python code for the SymPy expressions + + Examples + ======== + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src2 = ''' + ... integer :: a, b, c, d + ... real :: p, q, r, s + ... c = a/b + ... d = c/a + ... s = p/q + ... r = q/p + ... ''' + >>> p = SymPyExpression(src2, 'f') + >>> p.convert_to_python() + ['a = 0', 'b = 0', 'c = 0', 'd = 0', 'p = 0.0', 'q = 0.0', 'r = 0.0', 's = 0.0', 'c = a/b', 'd = c/a', 's = p/q', 'r = q/p'] + + """ + self._pycode = [] + for iter in self._expr: + self._pycode.append(pycode(iter)) + return self._pycode + + def convert_to_c(self): + """Returns a list with the c source code for the SymPy expressions + + + Examples + ======== + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src2 = ''' + ... integer :: a, b, c, d + ... real :: p, q, r, s + ... c = a/b + ... d = c/a + ... s = p/q + ... r = q/p + ... ''' + >>> p = SymPyExpression() + >>> p.convert_to_expr(src2, 'f') + >>> p.convert_to_c() + ['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0', 'c = a/b;', 'd = c/a;', 's = p/q;', 'r = q/p;'] + + """ + self._ccode = [] + for iter in self._expr: + self._ccode.append(ccode(iter)) + return self._ccode + + def convert_to_fortran(self): + """Returns a list with the fortran source code for the SymPy expressions + + Examples + ======== + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src2 = ''' + ... integer :: a, b, c, d + ... real :: p, q, r, s + ... c = a/b + ... d = c/a + ... s = p/q + ... r = q/p + ... ''' + >>> p = SymPyExpression(src2, 'f') + >>> p.convert_to_fortran() + [' integer*4 a', ' integer*4 b', ' integer*4 c', ' integer*4 d', ' real*8 p', ' real*8 q', ' real*8 r', ' real*8 s', ' c = a/b', ' d = c/a', ' s = p/q', ' r = q/p'] + + """ + self._fcode = [] + for iter in self._expr: + self._fcode.append(fcode(iter)) + return self._fcode + + def return_expr(self): + """Returns the expression list + + Examples + ======== + + >>> from sympy.parsing.sym_expr import SymPyExpression + >>> src3 = ''' + ... integer function f(a,b) + ... integer, intent(in) :: a, b + ... integer :: r + ... r = a+b + ... f = r + ... end function + ... ''' + >>> p = SymPyExpression() + >>> p.convert_to_expr(src3, 'f') + >>> p.return_expr() + [FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock( + Declaration(Variable(f, type=integer, value=0)), + Declaration(Variable(r, type=integer, value=0)), + Assignment(Variable(f), Variable(r)), + Return(Variable(f)) + ))] + + """ + return self._expr diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/sympy_parser.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/sympy_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..9cfda9ce0f73ffa3773031c48b9e9c245f69fe0b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/parsing/sympy_parser.py @@ -0,0 +1,1270 @@ +"""Transform a string with Python-like source code into SymPy expression. """ +from __future__ import annotations +from tokenize import (generate_tokens, untokenize, TokenError, + NUMBER, STRING, NAME, OP, ENDMARKER, ERRORTOKEN, NEWLINE) + +from keyword import iskeyword + +import ast +import unicodedata +from io import StringIO +import builtins +import types +from typing import Any, Callable +from functools import reduce +from sympy.assumptions.ask import AssumptionKeys +from sympy.core.basic import Basic +from sympy.core import Symbol +from sympy.core.function import Function +from sympy.utilities.misc import func_name +from sympy.functions.elementary.miscellaneous import Max, Min + + +null = '' + +TOKEN = tuple[int, str] +DICT = dict[str, Any] +TRANS = Callable[[list[TOKEN], DICT, DICT], list[TOKEN]] + +def _token_splittable(token_name: str) -> bool: + """ + Predicate for whether a token name can be split into multiple tokens. + + A token is splittable if it does not contain an underscore character and + it is not the name of a Greek letter. This is used to implicitly convert + expressions like 'xyz' into 'x*y*z'. + """ + if '_' in token_name: + return False + try: + return not unicodedata.lookup('GREEK SMALL LETTER ' + token_name) + except KeyError: + return len(token_name) > 1 + + +def _token_callable(token: TOKEN, local_dict: DICT, global_dict: DICT, nextToken=None): + """ + Predicate for whether a token name represents a callable function. + + Essentially wraps ``callable``, but looks up the token name in the + locals and globals. + """ + func = local_dict.get(token[1]) + if not func: + func = global_dict.get(token[1]) + return callable(func) and not isinstance(func, Symbol) + + +def _add_factorial_tokens(name: str, result: list[TOKEN]) -> list[TOKEN]: + if result == [] or result[-1][1] == '(': + raise TokenError() + + beginning = [(NAME, name), (OP, '(')] + end = [(OP, ')')] + + diff = 0 + length = len(result) + + for index, token in enumerate(result[::-1]): + toknum, tokval = token + i = length - index - 1 + + if tokval == ')': + diff += 1 + elif tokval == '(': + diff -= 1 + + if diff == 0: + if i - 1 >= 0 and result[i - 1][0] == NAME: + return result[:i - 1] + beginning + result[i - 1:] + end + else: + return result[:i] + beginning + result[i:] + end + + return result + + +class ParenthesisGroup(list[TOKEN]): + """List of tokens representing an expression in parentheses.""" + pass + + +class AppliedFunction: + """ + A group of tokens representing a function and its arguments. + + `exponent` is for handling the shorthand sin^2, ln^2, etc. + """ + def __init__(self, function: TOKEN, args: ParenthesisGroup, exponent=None): + if exponent is None: + exponent = [] + self.function = function + self.args = args + self.exponent = exponent + self.items = ['function', 'args', 'exponent'] + + def expand(self) -> list[TOKEN]: + """Return a list of tokens representing the function""" + return [self.function, *self.args] + + def __getitem__(self, index): + return getattr(self, self.items[index]) + + def __repr__(self): + return "AppliedFunction(%s, %s, %s)" % (self.function, self.args, + self.exponent) + + +def _flatten(result: list[TOKEN | AppliedFunction]): + result2: list[TOKEN] = [] + for tok in result: + if isinstance(tok, AppliedFunction): + result2.extend(tok.expand()) + else: + result2.append(tok) + return result2 + + +def _group_parentheses(recursor: TRANS): + def _inner(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """Group tokens between parentheses with ParenthesisGroup. + + Also processes those tokens recursively. + + """ + result: list[TOKEN | ParenthesisGroup] = [] + stacks: list[ParenthesisGroup] = [] + stacklevel = 0 + for token in tokens: + if token[0] == OP: + if token[1] == '(': + stacks.append(ParenthesisGroup([])) + stacklevel += 1 + elif token[1] == ')': + stacks[-1].append(token) + stack = stacks.pop() + + if len(stacks) > 0: + # We don't recurse here since the upper-level stack + # would reprocess these tokens + stacks[-1].extend(stack) + else: + # Recurse here to handle nested parentheses + # Strip off the outer parentheses to avoid an infinite loop + inner = stack[1:-1] + inner = recursor(inner, + local_dict, + global_dict) + parenGroup = [stack[0]] + inner + [stack[-1]] + result.append(ParenthesisGroup(parenGroup)) + stacklevel -= 1 + continue + if stacklevel: + stacks[-1].append(token) + else: + result.append(token) + if stacklevel: + raise TokenError("Mismatched parentheses") + return result + return _inner + + +def _apply_functions(tokens: list[TOKEN | ParenthesisGroup], local_dict: DICT, global_dict: DICT): + """Convert a NAME token + ParenthesisGroup into an AppliedFunction. + + Note that ParenthesisGroups, if not applied to any function, are + converted back into lists of tokens. + + """ + result: list[TOKEN | AppliedFunction] = [] + symbol = None + for tok in tokens: + if isinstance(tok, ParenthesisGroup): + if symbol and _token_callable(symbol, local_dict, global_dict): + result[-1] = AppliedFunction(symbol, tok) + symbol = None + else: + result.extend(tok) + elif tok[0] == NAME: + symbol = tok + result.append(tok) + else: + symbol = None + result.append(tok) + return result + + +def _implicit_multiplication(tokens: list[TOKEN | AppliedFunction], local_dict: DICT, global_dict: DICT): + """Implicitly adds '*' tokens. + + Cases: + + - Two AppliedFunctions next to each other ("sin(x)cos(x)") + + - AppliedFunction next to an open parenthesis ("sin x (cos x + 1)") + + - A close parenthesis next to an AppliedFunction ("(x+2)sin x")\ + + - A close parenthesis next to an open parenthesis ("(x+2)(x+3)") + + - AppliedFunction next to an implicitly applied function ("sin(x)cos x") + + """ + result: list[TOKEN | AppliedFunction] = [] + skip = False + for tok, nextTok in zip(tokens, tokens[1:]): + result.append(tok) + if skip: + skip = False + continue + if tok[0] == OP and tok[1] == '.' and nextTok[0] == NAME: + # Dotted name. Do not do implicit multiplication + skip = True + continue + if isinstance(tok, AppliedFunction): + if isinstance(nextTok, AppliedFunction): + result.append((OP, '*')) + elif nextTok == (OP, '('): + # Applied function followed by an open parenthesis + if tok.function[1] == "Function": + tok.function = (tok.function[0], 'Symbol') + result.append((OP, '*')) + elif nextTok[0] == NAME: + # Applied function followed by implicitly applied function + result.append((OP, '*')) + else: + if tok == (OP, ')'): + if isinstance(nextTok, AppliedFunction): + # Close parenthesis followed by an applied function + result.append((OP, '*')) + elif nextTok[0] == NAME: + # Close parenthesis followed by an implicitly applied function + result.append((OP, '*')) + elif nextTok == (OP, '('): + # Close parenthesis followed by an open parenthesis + result.append((OP, '*')) + elif tok[0] == NAME and not _token_callable(tok, local_dict, global_dict): + if isinstance(nextTok, AppliedFunction) or \ + (nextTok[0] == NAME and _token_callable(nextTok, local_dict, global_dict)): + # Constant followed by (implicitly applied) function + result.append((OP, '*')) + elif nextTok == (OP, '('): + # Constant followed by parenthesis + result.append((OP, '*')) + elif nextTok[0] == NAME: + # Constant followed by constant + result.append((OP, '*')) + if tokens: + result.append(tokens[-1]) + return result + + +def _implicit_application(tokens: list[TOKEN | AppliedFunction], local_dict: DICT, global_dict: DICT): + """Adds parentheses as needed after functions.""" + result: list[TOKEN | AppliedFunction] = [] + appendParen = 0 # number of closing parentheses to add + skip = 0 # number of tokens to delay before adding a ')' (to + # capture **, ^, etc.) + exponentSkip = False # skipping tokens before inserting parentheses to + # work with function exponentiation + for tok, nextTok in zip(tokens, tokens[1:]): + result.append(tok) + if (tok[0] == NAME and nextTok[0] not in [OP, ENDMARKER, NEWLINE]): + if _token_callable(tok, local_dict, global_dict, nextTok): # type: ignore + result.append((OP, '(')) + appendParen += 1 + # name followed by exponent - function exponentiation + elif (tok[0] == NAME and nextTok[0] == OP and nextTok[1] == '**'): + if _token_callable(tok, local_dict, global_dict): # type: ignore + exponentSkip = True + elif exponentSkip: + # if the last token added was an applied function (i.e. the + # power of the function exponent) OR a multiplication (as + # implicit multiplication would have added an extraneous + # multiplication) + if (isinstance(tok, AppliedFunction) + or (tok[0] == OP and tok[1] == '*')): + # don't add anything if the next token is a multiplication + # or if there's already a parenthesis (if parenthesis, still + # stop skipping tokens) + if not (nextTok[0] == OP and nextTok[1] == '*'): + if not(nextTok[0] == OP and nextTok[1] == '('): + result.append((OP, '(')) + appendParen += 1 + exponentSkip = False + elif appendParen: + if nextTok[0] == OP and nextTok[1] in ('^', '**', '*'): + skip = 1 + continue + if skip: + skip -= 1 + continue + result.append((OP, ')')) + appendParen -= 1 + + if tokens: + result.append(tokens[-1]) + + if appendParen: + result.extend([(OP, ')')] * appendParen) + return result + + +def function_exponentiation(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """Allows functions to be exponentiated, e.g. ``cos**2(x)``. + + Examples + ======== + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, function_exponentiation) + >>> transformations = standard_transformations + (function_exponentiation,) + >>> parse_expr('sin**4(x)', transformations=transformations) + sin(x)**4 + """ + result: list[TOKEN] = [] + exponent: list[TOKEN] = [] + consuming_exponent = False + level = 0 + for tok, nextTok in zip(tokens, tokens[1:]): + if tok[0] == NAME and nextTok[0] == OP and nextTok[1] == '**': + if _token_callable(tok, local_dict, global_dict): + consuming_exponent = True + elif consuming_exponent: + if tok[0] == NAME and tok[1] == 'Function': + tok = (NAME, 'Symbol') + exponent.append(tok) + + # only want to stop after hitting ) + if tok[0] == nextTok[0] == OP and tok[1] == ')' and nextTok[1] == '(': + consuming_exponent = False + # if implicit multiplication was used, we may have )*( instead + if tok[0] == nextTok[0] == OP and tok[1] == '*' and nextTok[1] == '(': + consuming_exponent = False + del exponent[-1] + continue + elif exponent and not consuming_exponent: + if tok[0] == OP: + if tok[1] == '(': + level += 1 + elif tok[1] == ')': + level -= 1 + if level == 0: + result.append(tok) + result.extend(exponent) + exponent = [] + continue + result.append(tok) + if tokens: + result.append(tokens[-1]) + if exponent: + result.extend(exponent) + return result + + +def split_symbols_custom(predicate: Callable[[str], bool]): + """Creates a transformation that splits symbol names. + + ``predicate`` should return True if the symbol name is to be split. + + For instance, to retain the default behavior but avoid splitting certain + symbol names, a predicate like this would work: + + + >>> from sympy.parsing.sympy_parser import (parse_expr, _token_splittable, + ... standard_transformations, implicit_multiplication, + ... split_symbols_custom) + >>> def can_split(symbol): + ... if symbol not in ('list', 'of', 'unsplittable', 'names'): + ... return _token_splittable(symbol) + ... return False + ... + >>> transformation = split_symbols_custom(can_split) + >>> parse_expr('unsplittable', transformations=standard_transformations + + ... (transformation, implicit_multiplication)) + unsplittable + """ + def _split_symbols(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + result: list[TOKEN] = [] + split = False + split_previous=False + + for tok in tokens: + if split_previous: + # throw out closing parenthesis of Symbol that was split + split_previous=False + continue + split_previous=False + + if tok[0] == NAME and tok[1] in ['Symbol', 'Function']: + split = True + + elif split and tok[0] == NAME: + symbol = tok[1][1:-1] + + if predicate(symbol): + tok_type = result[-2][1] # Symbol or Function + del result[-2:] # Get rid of the call to Symbol + + i = 0 + while i < len(symbol): + char = symbol[i] + if char in local_dict or char in global_dict: + result.append((NAME, "%s" % char)) + elif char.isdigit(): + chars = [char] + for i in range(i + 1, len(symbol)): + if not symbol[i].isdigit(): + i -= 1 + break + chars.append(symbol[i]) + char = ''.join(chars) + result.extend([(NAME, 'Number'), (OP, '('), + (NAME, "'%s'" % char), (OP, ')')]) + else: + use = tok_type if i == len(symbol) else 'Symbol' + result.extend([(NAME, use), (OP, '('), + (NAME, "'%s'" % char), (OP, ')')]) + i += 1 + + # Set split_previous=True so will skip + # the closing parenthesis of the original Symbol + split = False + split_previous = True + continue + + else: + split = False + + result.append(tok) + + return result + + return _split_symbols + + +#: Splits symbol names for implicit multiplication. +#: +#: Intended to let expressions like ``xyz`` be parsed as ``x*y*z``. Does not +#: split Greek character names, so ``theta`` will *not* become +#: ``t*h*e*t*a``. Generally this should be used with +#: ``implicit_multiplication``. +split_symbols = split_symbols_custom(_token_splittable) + + +def implicit_multiplication(tokens: list[TOKEN], local_dict: DICT, + global_dict: DICT) -> list[TOKEN]: + """Makes the multiplication operator optional in most cases. + + Use this before :func:`implicit_application`, otherwise expressions like + ``sin 2x`` will be parsed as ``x * sin(2)`` rather than ``sin(2*x)``. + + Examples + ======== + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, implicit_multiplication) + >>> transformations = standard_transformations + (implicit_multiplication,) + >>> parse_expr('3 x y', transformations=transformations) + 3*x*y + """ + # These are interdependent steps, so we don't expose them separately + res1 = _group_parentheses(implicit_multiplication)(tokens, local_dict, global_dict) + res2 = _apply_functions(res1, local_dict, global_dict) + res3 = _implicit_multiplication(res2, local_dict, global_dict) + result = _flatten(res3) + return result + + +def implicit_application(tokens: list[TOKEN], local_dict: DICT, + global_dict: DICT) -> list[TOKEN]: + """Makes parentheses optional in some cases for function calls. + + Use this after :func:`implicit_multiplication`, otherwise expressions + like ``sin 2x`` will be parsed as ``x * sin(2)`` rather than + ``sin(2*x)``. + + Examples + ======== + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, implicit_application) + >>> transformations = standard_transformations + (implicit_application,) + >>> parse_expr('cot z + csc z', transformations=transformations) + cot(z) + csc(z) + """ + res1 = _group_parentheses(implicit_application)(tokens, local_dict, global_dict) + res2 = _apply_functions(res1, local_dict, global_dict) + res3 = _implicit_application(res2, local_dict, global_dict) + result = _flatten(res3) + return result + + +def implicit_multiplication_application(result: list[TOKEN], local_dict: DICT, + global_dict: DICT) -> list[TOKEN]: + """Allows a slightly relaxed syntax. + + - Parentheses for single-argument method calls are optional. + + - Multiplication is implicit. + + - Symbol names can be split (i.e. spaces are not needed between + symbols). + + - Functions can be exponentiated. + + Examples + ======== + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, implicit_multiplication_application) + >>> parse_expr("10sin**2 x**2 + 3xyz + tan theta", + ... transformations=(standard_transformations + + ... (implicit_multiplication_application,))) + 3*x*y*z + 10*sin(x**2)**2 + tan(theta) + + """ + for step in (split_symbols, implicit_multiplication, + implicit_application, function_exponentiation): + result = step(result, local_dict, global_dict) + + return result + + +def auto_symbol(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """Inserts calls to ``Symbol``/``Function`` for undefined variables.""" + result: list[TOKEN] = [] + prevTok = (-1, '') + + tokens.append((-1, '')) # so zip traverses all tokens + for tok, nextTok in zip(tokens, tokens[1:]): + tokNum, tokVal = tok + nextTokNum, nextTokVal = nextTok + if tokNum == NAME: + name = tokVal + + if (name in ['True', 'False', 'None'] + or iskeyword(name) + # Don't convert attribute access + or (prevTok[0] == OP and prevTok[1] == '.') + # Don't convert keyword arguments + or (prevTok[0] == OP and prevTok[1] in ('(', ',') + and nextTokNum == OP and nextTokVal == '=') + # the name has already been defined + or name in local_dict and local_dict[name] is not null): + result.append((NAME, name)) + continue + elif name in local_dict: + local_dict.setdefault(null, set()).add(name) + if nextTokVal == '(': + local_dict[name] = Function(name) + else: + local_dict[name] = Symbol(name) + result.append((NAME, name)) + continue + elif name in global_dict: + obj = global_dict[name] + if isinstance(obj, (AssumptionKeys, Basic, type)) or callable(obj): + result.append((NAME, name)) + continue + + result.extend([ + (NAME, 'Symbol' if nextTokVal != '(' else 'Function'), + (OP, '('), + (NAME, repr(str(name))), + (OP, ')'), + ]) + else: + result.append((tokNum, tokVal)) + + prevTok = (tokNum, tokVal) + + return result + + +def lambda_notation(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """Substitutes "lambda" with its SymPy equivalent Lambda(). + However, the conversion does not take place if only "lambda" + is passed because that is a syntax error. + + """ + result: list[TOKEN] = [] + flag = False + toknum, tokval = tokens[0] + tokLen = len(tokens) + + if toknum == NAME and tokval == 'lambda': + if tokLen == 2 or tokLen == 3 and tokens[1][0] == NEWLINE: + # In Python 3.6.7+, inputs without a newline get NEWLINE added to + # the tokens + result.extend(tokens) + elif tokLen > 2: + result.extend([ + (NAME, 'Lambda'), + (OP, '('), + (OP, '('), + (OP, ')'), + (OP, ')'), + ]) + for tokNum, tokVal in tokens[1:]: + if tokNum == OP and tokVal == ':': + tokVal = ',' + flag = True + if not flag and tokNum == OP and tokVal in ('*', '**'): + raise TokenError("Starred arguments in lambda not supported") + if flag: + result.insert(-1, (tokNum, tokVal)) + else: + result.insert(-2, (tokNum, tokVal)) + else: + result.extend(tokens) + + return result + + +def factorial_notation(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """Allows standard notation for factorial.""" + result: list[TOKEN] = [] + nfactorial = 0 + for toknum, tokval in tokens: + if toknum == OP and tokval == "!": + # In Python 3.12 "!" are OP instead of ERRORTOKEN + nfactorial += 1 + elif toknum == ERRORTOKEN: + op = tokval + if op == '!': + nfactorial += 1 + else: + nfactorial = 0 + result.append((OP, op)) + else: + if nfactorial == 1: + result = _add_factorial_tokens('factorial', result) + elif nfactorial == 2: + result = _add_factorial_tokens('factorial2', result) + elif nfactorial > 2: + raise TokenError + nfactorial = 0 + result.append((toknum, tokval)) + return result + + +def convert_xor(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """Treats XOR, ``^``, as exponentiation, ``**``.""" + result: list[TOKEN] = [] + for toknum, tokval in tokens: + if toknum == OP: + if tokval == '^': + result.append((OP, '**')) + else: + result.append((toknum, tokval)) + else: + result.append((toknum, tokval)) + + return result + + +def repeated_decimals(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """ + Allows 0.2[1] notation to represent the repeated decimal 0.2111... (19/90) + + Run this before auto_number. + + """ + result: list[TOKEN] = [] + + def is_digit(s): + return all(i in '0123456789_' for i in s) + + # num will running match any DECIMAL [ INTEGER ] + num: list[TOKEN] = [] + for toknum, tokval in tokens: + if toknum == NUMBER: + if (not num and '.' in tokval and 'e' not in tokval.lower() and + 'j' not in tokval.lower()): + num.append((toknum, tokval)) + elif is_digit(tokval) and (len(num) == 2 or + len(num) == 3 and is_digit(num[-1][1])): + num.append((toknum, tokval)) + else: + num = [] + elif toknum == OP: + if tokval == '[' and len(num) == 1: + num.append((OP, tokval)) + elif tokval == ']' and len(num) >= 3: + num.append((OP, tokval)) + elif tokval == '.' and not num: + # handle .[1] + num.append((NUMBER, '0.')) + else: + num = [] + else: + num = [] + + result.append((toknum, tokval)) + + if num and num[-1][1] == ']': + # pre.post[repetend] = a + b/c + d/e where a = pre, b/c = post, + # and d/e = repetend + result = result[:-len(num)] + pre, post = num[0][1].split('.') + repetend = num[2][1] + if len(num) == 5: + repetend += num[3][1] + + pre = pre.replace('_', '') + post = post.replace('_', '') + repetend = repetend.replace('_', '') + + zeros = '0'*len(post) + post, repetends = [w.lstrip('0') for w in [post, repetend]] + # or else interpreted as octal + + a = pre or '0' + b, c = post or '0', '1' + zeros + d, e = repetends, ('9'*len(repetend)) + zeros + + seq = [ + (OP, '('), + (NAME, 'Integer'), + (OP, '('), + (NUMBER, a), + (OP, ')'), + (OP, '+'), + (NAME, 'Rational'), + (OP, '('), + (NUMBER, b), + (OP, ','), + (NUMBER, c), + (OP, ')'), + (OP, '+'), + (NAME, 'Rational'), + (OP, '('), + (NUMBER, d), + (OP, ','), + (NUMBER, e), + (OP, ')'), + (OP, ')'), + ] + result.extend(seq) + num = [] + + return result + + +def auto_number(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """ + Converts numeric literals to use SymPy equivalents. + + Complex numbers use ``I``, integer literals use ``Integer``, and float + literals use ``Float``. + + """ + result: list[TOKEN] = [] + + for toknum, tokval in tokens: + if toknum == NUMBER: + number = tokval + postfix = [] + + if number.endswith(('j', 'J')): + number = number[:-1] + postfix = [(OP, '*'), (NAME, 'I')] + + if '.' in number or (('e' in number or 'E' in number) and + not (number.startswith(('0x', '0X')))): + seq = [(NAME, 'Float'), (OP, '('), + (NUMBER, repr(str(number))), (OP, ')')] + else: + seq = [(NAME, 'Integer'), (OP, '('), ( + NUMBER, number), (OP, ')')] + + result.extend(seq + postfix) + else: + result.append((toknum, tokval)) + + return result + + +def rationalize(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """Converts floats into ``Rational``. Run AFTER ``auto_number``.""" + result: list[TOKEN] = [] + passed_float = False + for toknum, tokval in tokens: + if toknum == NAME: + if tokval == 'Float': + passed_float = True + tokval = 'Rational' + result.append((toknum, tokval)) + elif passed_float == True and toknum == NUMBER: + passed_float = False + result.append((STRING, tokval)) + else: + result.append((toknum, tokval)) + + return result + + +def _transform_equals_sign(tokens: list[TOKEN], local_dict: DICT, global_dict: DICT): + """Transforms the equals sign ``=`` to instances of Eq. + + This is a helper function for ``convert_equals_signs``. + Works with expressions containing one equals sign and no + nesting. Expressions like ``(1=2)=False`` will not work with this + and should be used with ``convert_equals_signs``. + + Examples: 1=2 to Eq(1,2) + 1*2=x to Eq(1*2, x) + + This does not deal with function arguments yet. + + """ + result: list[TOKEN] = [] + if (OP, "=") in tokens: + result.append((NAME, "Eq")) + result.append((OP, "(")) + for token in tokens: + if token == (OP, "="): + result.append((OP, ",")) + continue + result.append(token) + result.append((OP, ")")) + else: + result = tokens + return result + + +def convert_equals_signs(tokens: list[TOKEN], local_dict: DICT, + global_dict: DICT) -> list[TOKEN]: + """ Transforms all the equals signs ``=`` to instances of Eq. + + Parses the equals signs in the expression and replaces them with + appropriate Eq instances. Also works with nested equals signs. + + Does not yet play well with function arguments. + For example, the expression ``(x=y)`` is ambiguous and can be interpreted + as x being an argument to a function and ``convert_equals_signs`` will not + work for this. + + See also + ======== + convert_equality_operators + + Examples + ======== + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, convert_equals_signs) + >>> parse_expr("1*2=x", transformations=( + ... standard_transformations + (convert_equals_signs,))) + Eq(2, x) + >>> parse_expr("(1*2=x)=False", transformations=( + ... standard_transformations + (convert_equals_signs,))) + Eq(Eq(2, x), False) + + """ + res1 = _group_parentheses(convert_equals_signs)(tokens, local_dict, global_dict) + res2 = _apply_functions(res1, local_dict, global_dict) + res3 = _transform_equals_sign(res2, local_dict, global_dict) + result = _flatten(res3) + return result + + +#: Standard transformations for :func:`parse_expr`. +#: Inserts calls to :class:`~.Symbol`, :class:`~.Integer`, and other SymPy +#: datatypes and allows the use of standard factorial notation (e.g. ``x!``). +standard_transformations: tuple[TRANS, ...] \ + = (lambda_notation, auto_symbol, repeated_decimals, auto_number, + factorial_notation) + + +def stringify_expr(s: str, local_dict: DICT, global_dict: DICT, + transformations: tuple[TRANS, ...]) -> str: + """ + Converts the string ``s`` to Python code, in ``local_dict`` + + Generally, ``parse_expr`` should be used. + """ + + tokens = [] + input_code = StringIO(s.strip()) + for toknum, tokval, _, _, _ in generate_tokens(input_code.readline): + tokens.append((toknum, tokval)) + + for transform in transformations: + tokens = transform(tokens, local_dict, global_dict) + + return untokenize(tokens) + + +def eval_expr(code, local_dict: DICT, global_dict: DICT): + """ + Evaluate Python code generated by ``stringify_expr``. + + Generally, ``parse_expr`` should be used. + """ + expr = eval( + code, global_dict, local_dict) # take local objects in preference + return expr + + +def parse_expr(s: str, local_dict: DICT | None = None, + transformations: tuple[TRANS, ...] | str \ + = standard_transformations, + global_dict: DICT | None = None, evaluate=True): + """Converts the string ``s`` to a SymPy expression, in ``local_dict``. + + .. warning:: + Note that this function uses ``eval``, and thus shouldn't be used on + unsanitized input. + + Parameters + ========== + + s : str + The string to parse. + + local_dict : dict, optional + A dictionary of local variables to use when parsing. + + global_dict : dict, optional + A dictionary of global variables. By default, this is initialized + with ``from sympy import *``; provide this parameter to override + this behavior (for instance, to parse ``"Q & S"``). + + transformations : tuple or str + A tuple of transformation functions used to modify the tokens of the + parsed expression before evaluation. The default transformations + convert numeric literals into their SymPy equivalents, convert + undefined variables into SymPy symbols, and allow the use of standard + mathematical factorial notation (e.g. ``x!``). Selection via + string is available (see below). + + evaluate : bool, optional + When False, the order of the arguments will remain as they were in the + string and automatic simplification that would normally occur is + suppressed. (see examples) + + Examples + ======== + + >>> from sympy.parsing.sympy_parser import parse_expr + >>> parse_expr("1/2") + 1/2 + >>> type(_) + + >>> from sympy.parsing.sympy_parser import standard_transformations,\\ + ... implicit_multiplication_application + >>> transformations = (standard_transformations + + ... (implicit_multiplication_application,)) + >>> parse_expr("2x", transformations=transformations) + 2*x + + When evaluate=False, some automatic simplifications will not occur: + + >>> parse_expr("2**3"), parse_expr("2**3", evaluate=False) + (8, 2**3) + + In addition the order of the arguments will not be made canonical. + This feature allows one to tell exactly how the expression was entered: + + >>> a = parse_expr('1 + x', evaluate=False) + >>> b = parse_expr('x + 1', evaluate=False) + >>> a == b + False + >>> a.args + (1, x) + >>> b.args + (x, 1) + + Note, however, that when these expressions are printed they will + appear the same: + + >>> assert str(a) == str(b) + + As a convenience, transformations can be seen by printing ``transformations``: + + >>> from sympy.parsing.sympy_parser import transformations + + >>> print(transformations) + 0: lambda_notation + 1: auto_symbol + 2: repeated_decimals + 3: auto_number + 4: factorial_notation + 5: implicit_multiplication_application + 6: convert_xor + 7: implicit_application + 8: implicit_multiplication + 9: convert_equals_signs + 10: function_exponentiation + 11: rationalize + + The ``T`` object provides a way to select these transformations: + + >>> from sympy.parsing.sympy_parser import T + + If you print it, you will see the same list as shown above. + + >>> str(T) == str(transformations) + True + + Standard slicing will return a tuple of transformations: + + >>> T[:5] == standard_transformations + True + + So ``T`` can be used to specify the parsing transformations: + + >>> parse_expr("2x", transformations=T[:5]) + Traceback (most recent call last): + ... + SyntaxError: invalid syntax + >>> parse_expr("2x", transformations=T[:6]) + 2*x + >>> parse_expr('.3', transformations=T[3, 11]) + 3/10 + >>> parse_expr('.3x', transformations=T[:]) + 3*x/10 + + As a further convenience, strings 'implicit' and 'all' can be used + to select 0-5 and all the transformations, respectively. + + >>> parse_expr('.3x', transformations='all') + 3*x/10 + + See Also + ======== + + stringify_expr, eval_expr, standard_transformations, + implicit_multiplication_application + + """ + + if local_dict is None: + local_dict = {} + elif not isinstance(local_dict, dict): + raise TypeError('expecting local_dict to be a dict') + elif null in local_dict: + raise ValueError('cannot use "" in local_dict') + + if global_dict is None: + global_dict = {} + exec('from sympy import *', global_dict) + + builtins_dict = vars(builtins) + for name, obj in builtins_dict.items(): + if isinstance(obj, types.BuiltinFunctionType): + global_dict[name] = obj + global_dict['max'] = Max + global_dict['min'] = Min + + elif not isinstance(global_dict, dict): + raise TypeError('expecting global_dict to be a dict') + + transformations = transformations or () + if isinstance(transformations, str): + if transformations == 'all': + _transformations = T[:] + elif transformations == 'implicit': + _transformations = T[:6] + else: + raise ValueError('unknown transformation group name') + else: + _transformations = transformations + + code = stringify_expr(s, local_dict, global_dict, _transformations) + + if not evaluate: + code = compile(evaluateFalse(code), '', 'eval') # type: ignore + + try: + rv = eval_expr(code, local_dict, global_dict) + # restore neutral definitions for names + for i in local_dict.pop(null, ()): + local_dict[i] = null + return rv + except Exception as e: + # restore neutral definitions for names + for i in local_dict.pop(null, ()): + local_dict[i] = null + raise e from ValueError(f"Error from parse_expr with transformed code: {code!r}") + + +def evaluateFalse(s: str): + """ + Replaces operators with the SymPy equivalent and sets evaluate=False. + """ + node = ast.parse(s) + transformed_node = EvaluateFalseTransformer().visit(node) + # node is a Module, we want an Expression + transformed_node = ast.Expression(transformed_node.body[0].value) + + return ast.fix_missing_locations(transformed_node) + + +class EvaluateFalseTransformer(ast.NodeTransformer): + operators = { + ast.Add: 'Add', + ast.Mult: 'Mul', + ast.Pow: 'Pow', + ast.Sub: 'Add', + ast.Div: 'Mul', + ast.BitOr: 'Or', + ast.BitAnd: 'And', + ast.BitXor: 'Not', + } + functions = ( + 'Abs', 'im', 're', 'sign', 'arg', 'conjugate', + 'acos', 'acot', 'acsc', 'asec', 'asin', 'atan', + 'acosh', 'acoth', 'acsch', 'asech', 'asinh', 'atanh', + 'cos', 'cot', 'csc', 'sec', 'sin', 'tan', + 'cosh', 'coth', 'csch', 'sech', 'sinh', 'tanh', + 'exp', 'ln', 'log', 'sqrt', 'cbrt', + ) + + relational_operators = { + ast.NotEq: 'Ne', + ast.Lt: 'Lt', + ast.LtE: 'Le', + ast.Gt: 'Gt', + ast.GtE: 'Ge', + ast.Eq: 'Eq' + } + def visit_Compare(self, node): + def reducer(acc, op_right): + result, left = acc + op, right = op_right + if op.__class__ not in self.relational_operators: + raise ValueError("Only equation or inequality operators are supported") + new = ast.Call( + func=ast.Name( + id=self.relational_operators[op.__class__], ctx=ast.Load() + ), + args=[self.visit(left), self.visit(right)], + keywords=[ast.keyword(arg="evaluate", value=ast.Constant(value=False))], + ) + return result + [new], right + + args, _ = reduce( + reducer, zip(node.ops, node.comparators), ([], node.left) + ) + if len(args) == 1: + return args[0] + return ast.Call( + func=ast.Name(id=self.operators[ast.BitAnd], ctx=ast.Load()), + args=args, + keywords=[ast.keyword(arg="evaluate", value=ast.Constant(value=False))], + ) + + def flatten(self, args, func): + result = [] + for arg in args: + if isinstance(arg, ast.Call): + arg_func = arg.func + if isinstance(arg_func, ast.Call): + arg_func = arg_func.func + if arg_func.id == func: + result.extend(self.flatten(arg.args, func)) + else: + result.append(arg) + else: + result.append(arg) + return result + + def visit_BinOp(self, node): + if node.op.__class__ in self.operators: + sympy_class = self.operators[node.op.__class__] + right = self.visit(node.right) + left = self.visit(node.left) + + rev = False + if isinstance(node.op, ast.Sub): + right = ast.Call( + func=ast.Name(id='Mul', ctx=ast.Load()), + args=[ast.UnaryOp(op=ast.USub(), operand=ast.Constant(1)), right], + keywords=[ast.keyword(arg='evaluate', value=ast.Constant(value=False))] + ) + elif isinstance(node.op, ast.Div): + if isinstance(node.left, ast.UnaryOp): + left, right = right, left + rev = True + left = ast.Call( + func=ast.Name(id='Pow', ctx=ast.Load()), + args=[left, ast.UnaryOp(op=ast.USub(), operand=ast.Constant(1))], + keywords=[ast.keyword(arg='evaluate', value=ast.Constant(value=False))] + ) + else: + right = ast.Call( + func=ast.Name(id='Pow', ctx=ast.Load()), + args=[right, ast.UnaryOp(op=ast.USub(), operand=ast.Constant(1))], + keywords=[ast.keyword(arg='evaluate', value=ast.Constant(value=False))] + ) + + if rev: # undo reversal + left, right = right, left + new_node = ast.Call( + func=ast.Name(id=sympy_class, ctx=ast.Load()), + args=[left, right], + keywords=[ast.keyword(arg='evaluate', value=ast.Constant(value=False))] + ) + + if sympy_class in ('Add', 'Mul'): + # Denest Add or Mul as appropriate + new_node.args = self.flatten(new_node.args, sympy_class) + + return new_node + return node + + def visit_Call(self, node): + new_node = self.generic_visit(node) + if isinstance(node.func, ast.Name) and node.func.id in self.functions: + new_node.keywords.append(ast.keyword(arg='evaluate', value=ast.Constant(value=False))) + return new_node + + +_transformation = { # items can be added but never re-ordered +0: lambda_notation, +1: auto_symbol, +2: repeated_decimals, +3: auto_number, +4: factorial_notation, +5: implicit_multiplication_application, +6: convert_xor, +7: implicit_application, +8: implicit_multiplication, +9: convert_equals_signs, +10: function_exponentiation, +11: rationalize} + +transformations = '\n'.join('%s: %s' % (i, func_name(f)) for i, f in _transformation.items()) + + +class _T(): + """class to retrieve transformations from a given slice + + EXAMPLES + ======== + + >>> from sympy.parsing.sympy_parser import T, standard_transformations + >>> assert T[:5] == standard_transformations + """ + def __init__(self): + self.N = len(_transformation) + + def __str__(self): + return transformations + + def __getitem__(self, t): + if not type(t) is tuple: + t = (t,) + i = [] + for ti in t: + if type(ti) is int: + i.append(range(self.N)[ti]) + elif type(ti) is slice: + i.extend(range(*ti.indices(self.N))) + else: + raise TypeError('unexpected slice arg') + return tuple([_transformation[_] for _ in i]) + +T = _T() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..60989896ae8b3f69efc7d2350add8f6f19d85669 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__init__.py @@ -0,0 +1,12 @@ +""" +A module that helps solving problems in physics. +""" + +from . import units +from .matrices import mgamma, msigma, minkowski_tensor, mdft + +__all__ = [ + 'units', + + 'mgamma', 'msigma', 'minkowski_tensor', 'mdft', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..781429110cab760f8990961c6536e7267a2a371a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__init__.py @@ -0,0 +1,10 @@ +__all__ = ['Beam', + 'Truss', + 'Cable', + 'Arch' + ] + +from .beam import Beam +from .truss import Truss +from .cable import Cable +from .arch import Arch diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/arch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/arch.py new file mode 100644 index 0000000000000000000000000000000000000000..31e2b41e841638f6a8002da1a7c843a9f5b35555 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/arch.py @@ -0,0 +1,1025 @@ +""" +This module can be used to solve probelsm related to 2D parabolic arches +""" +from sympy.core.sympify import sympify +from sympy.core.symbol import Symbol,symbols +from sympy import diff, sqrt, cos , sin, atan, rad, Min +from sympy.core.relational import Eq +from sympy.solvers.solvers import solve +from sympy.functions import Piecewise +from sympy.plotting import plot +from sympy import limit +from sympy.utilities.decorator import doctest_depends_on +from sympy.external.importtools import import_module + +numpy = import_module('numpy', import_kwargs={'fromlist':['arange']}) + +class Arch: + """ + This class is used to solve problems related to a three hinged arch(determinate) structure.\n + An arch is a curved vertical structure spanning an open space underneath it.\n + Arches can be used to reduce the bending moments in long-span structures.\n + + Arches are used in structural engineering(over windows, door and even bridges)\n + because they can support a very large mass placed on top of them. + + Example + ======== + >>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(10,0),crown_x=5,crown_y=5) + >>> a.get_shape_eqn + 5 - (x - 5)**2/5 + + >>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(10,1),crown_x=6) + >>> a.get_shape_eqn + 9/5 - (x - 6)**2/20 + """ + def __init__(self,left_support,right_support,**kwargs): + self._shape_eqn = None + self._left_support = (sympify(left_support[0]),sympify(left_support[1])) + self._right_support = (sympify(right_support[0]),sympify(right_support[1])) + self._crown_x = None + self._crown_y = None + if 'crown_x' in kwargs: + self._crown_x = sympify(kwargs['crown_x']) + if 'crown_y' in kwargs: + self._crown_y = sympify(kwargs['crown_y']) + self._shape_eqn = self.get_shape_eqn + self._conc_loads = {} + self._distributed_loads = {} + self._loads = {'concentrated': self._conc_loads, 'distributed':self._distributed_loads} + self._loads_applied = {} + self._supports = {'left':'hinge', 'right':'hinge'} + self._member = None + self._member_force = None + self._reaction_force = {Symbol('R_A_x'):0, Symbol('R_A_y'):0, Symbol('R_B_x'):0, Symbol('R_B_y'):0} + self._points_disc_x = set() + self._points_disc_y = set() + self._moment_x = {} + self._moment_y = {} + self._load_x = {} + self._load_y = {} + self._moment_x_func = Piecewise((0,True)) + self._moment_y_func = Piecewise((0,True)) + self._load_x_func = Piecewise((0,True)) + self._load_y_func = Piecewise((0,True)) + self._bending_moment = None + self._shear_force = None + self._axial_force = None + # self._crown = (sympify(crown[0]),sympify(crown[1])) + + @property + def get_shape_eqn(self): + "returns the equation of the shape of arch developed" + if self._shape_eqn: + return self._shape_eqn + + x,y,c = symbols('x y c') + a = Symbol('a',positive=False) + if self._crown_x and self._crown_y: + x0 = self._crown_x + y0 = self._crown_y + parabola_eqn = a*(x-x0)**2 + y0 - y + eq1 = parabola_eqn.subs({x:self._left_support[0], y:self._left_support[1]}) + solution = solve((eq1),(a)) + parabola_eqn = solution[0]*(x-x0)**2 + y0 + if(parabola_eqn.subs({x:self._right_support[0]}) != self._right_support[1]): + raise ValueError("provided coordinates of crown and supports are not consistent with parabolic arch") + + elif self._crown_x: + x0 = self._crown_x + parabola_eqn = a*(x-x0)**2 + c - y + eq1 = parabola_eqn.subs({x:self._left_support[0], y:self._left_support[1]}) + eq2 = parabola_eqn.subs({x:self._right_support[0], y:self._right_support[1]}) + solution = solve((eq1,eq2),(a,c)) + if len(solution) <2 or solution[a] == 0: + raise ValueError("parabolic arch cannot be constructed with the provided coordinates, try providing crown_y") + parabola_eqn = solution[a]*(x-x0)**2+ solution[c] + self._crown_y = solution[c] + + else: + raise KeyError("please provide crown_x to construct arch") + + return parabola_eqn + + @property + def get_loads(self): + """ + return the position of the applied load and angle (for concentrated loads) + """ + return self._loads + + @property + def supports(self): + """ + Returns the type of support + """ + return self._supports + + @property + def left_support(self): + """ + Returns the position of the left support. + """ + return self._left_support + + @property + def right_support(self): + """ + Returns the position of the right support. + """ + return self._right_support + + @property + def reaction_force(self): + """ + return the reaction forces generated + """ + return self._reaction_force + + def apply_load(self,order,label,start,mag,end=None,angle=None): + """ + This method adds load to the Arch. + + Parameters + ========== + + order : Integer + Order of the applied load. + + - For point/concentrated loads, order = -1 + - For distributed load, order = 0 + + label : String or Symbol + The label of the load + - should not use 'A' or 'B' as it is used for supports. + + start : Float + + - For concentrated/point loads, start is the x coordinate + - For distributed loads, start is the starting position of distributed load + + mag : Sympifyable + Magnitude of the applied load. Must be positive + + end : Float + Required for distributed loads + + - For concentrated/point load , end is None(may not be given) + - For distributed loads, end is the end position of distributed load + + angle: Sympifyable + The angle in degrees, the load vector makes with the horizontal + in the counter-clockwise direction. + + Examples + ======== + For applying distributed load + + >>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(10,0),crown_x=5,crown_y=5) + >>> a.apply_load(0,'C',start=3,end=5,mag=-10) + + For applying point/concentrated_loads + + >>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(10,0),crown_x=5,crown_y=5) + >>> a.apply_load(-1,'C',start=2,mag=15,angle=45) + + """ + y = Symbol('y') + x = Symbol('x') + x0 = Symbol('x0') + # y0 = Symbol('y0') + order= sympify(order) + mag = sympify(mag) + angle = sympify(angle) + + if label in self._loads_applied: + raise ValueError("load with the given label already exists") + + if label in ['A','B']: + raise ValueError("cannot use the given label, reserved for supports") + + if order == 0: + if end is None or end>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(10,0),crown_x=5,crown_y=5) + >>> a.apply_load(0,'C',start=3,end=5,mag=-10) + >>> a.remove_load('C') + removed load C: {'start': 3, 'end': 5, 'f_y': -10} + """ + y = Symbol('y') + x = Symbol('x') + x0 = Symbol('x0') + + if label in self._distributed_loads : + + self._loads_applied.pop(label) + start = self._distributed_loads[label]['start'] + end = self._distributed_loads[label]['end'] + mag = self._distributed_loads[label]['f_y'] + self._points_disc_y.remove(start) + self._load_y[start] -= mag*(Min(x,end)-start) + self._moment_y[start] += mag*(Min(x,end)-start)*(x0-(start+(Min(x,end)))/2) + val = self._distributed_loads.pop(label) + print(f"removed load {label}: {val}") + + elif label in self._conc_loads : + + self._loads_applied.pop(label) + start = self._conc_loads[label]['x'] + self._points_disc_x.remove(start) + self._points_disc_y.remove(start) + self._moment_y[start] += self._conc_loads[label]['f_y']*(x0-start) + self._moment_x[start] -= self._conc_loads[label]['f_x']*(y-self._conc_loads[label]['y']) + self._load_x[start] -= self._conc_loads[label]['f_x'] + self._load_y[start] -= self._conc_loads[label]['f_y'] + val = self._conc_loads.pop(label) + print(f"removed load {label}: {val}") + + else : + raise ValueError("label not found") + + def change_support_position(self, left_support=None, right_support=None): + """ + Change position of supports. + If not provided , defaults to the old value. + Parameters + ========== + + left_support: tuple (x, y) + x: float + x-coordinate value of the left_support + + y: float + y-coordinate value of the left_support + + right_support: tuple (x, y) + x: float + x-coordinate value of the right_support + + y: float + y-coordinate value of the right_support + """ + if left_support is not None: + self._left_support = (left_support[0],left_support[1]) + + if right_support is not None: + self._right_support = (right_support[0],right_support[1]) + + self._shape_eqn = None + self._shape_eqn = self.get_shape_eqn + + def change_crown_position(self,crown_x=None,crown_y=None): + """ + Change the position of the crown/hinge of the arch + + Parameters + ========== + + crown_x: Float + The x coordinate of the position of the hinge + - if not provided, defaults to old value + + crown_y: Float + The y coordinate of the position of the hinge + - if not provided defaults to None + """ + self._crown_x = crown_x + self._crown_y = crown_y + self._shape_eqn = None + self._shape_eqn = self.get_shape_eqn + + def change_support_type(self,left_support=None,right_support=None): + """ + Add the type for support at each end. + Can use roller or hinge support at each end. + + Parameters + ========== + + left_support, right_support : string + Type of support at respective end + + - For roller support , left_support/right_support = "roller" + - For hinged support, left_support/right_support = "hinge" + - defaults to hinge if value not provided + + Examples + ======== + + For applying roller support at right end + + >>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(10,0),crown_x=5,crown_y=5) + >>> a.change_support_type(right_support="roller") + + """ + support_types = ['roller','hinge'] + if left_support: + if left_support not in support_types: + raise ValueError("supports must only be roller or hinge") + + self._supports['left'] = left_support + + if right_support: + if right_support not in support_types: + raise ValueError("supports must only be roller or hinge") + + self._supports['right'] = right_support + + def add_member(self,y): + """ + This method adds a member/rod at a particular height y. + A rod is used for stability of the structure in case of a roller support. + """ + if y>self._crown_y or y>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(10,0),crown_x=5,crown_y=5) + >>> a.apply_load(0,'C',start=3,end=5,mag=-10) + >>> a.solve() + >>> a.reaction_force + {R_A_x: 8, R_A_y: 12, R_B_x: -8, R_B_y: 8} + + >>> from sympy import Symbol + >>> t = Symbol('t') + >>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(16,0),crown_x=8,crown_y=5) + >>> a.apply_load(0,'C',start=3,end=5,mag=t) + >>> a.solve() + >>> a.reaction_force + {R_A_x: -4*t/5, R_A_y: -3*t/2, R_B_x: 4*t/5, R_B_y: -t/2} + + >>> a.bending_moment_at(4) + -5*t/2 + """ + y = Symbol('y') + x = Symbol('x') + x0 = Symbol('x0') + + discontinuity_points_x = sorted(self._points_disc_x) + discontinuity_points_y = sorted(self._points_disc_y) + + self._moment_x_func = Piecewise((0,True)) + self._moment_y_func = Piecewise((0,True)) + + self._load_x_func = Piecewise((0,True)) + self._load_y_func = Piecewise((0,True)) + + accumulated_x_moment = 0 + accumulated_y_moment = 0 + + accumulated_x_load = 0 + accumulated_y_load = 0 + + for point in discontinuity_points_x: + cond = (x >= point) + accumulated_x_load += self._load_x[point] + accumulated_x_moment += self._moment_x[point] + self._load_x_func = Piecewise((accumulated_x_load,cond),(self._load_x_func,True)) + self._moment_x_func = Piecewise((accumulated_x_moment,cond),(self._moment_x_func,True)) + + for point in discontinuity_points_y: + cond = (x >= point) + accumulated_y_moment += self._moment_y[point] + accumulated_y_load += self._load_y[point] + self._load_y_func = Piecewise((accumulated_y_load,cond),(self._load_y_func,True)) + self._moment_y_func = Piecewise((accumulated_y_moment,cond),(self._moment_y_func,True)) + + moment_A = self._moment_y_func.subs(x,self._right_support[0]).subs(x0,self._left_support[0]) +\ + self._moment_x_func.subs(x,self._right_support[0]).subs(y,self._left_support[1]) + + moment_hinge_left = self._moment_y_func.subs(x,self._crown_x).subs(x0,self._crown_x) +\ + self._moment_x_func.subs(x,self._crown_x).subs(y,self._crown_y) + + moment_hinge_right = self._moment_y_func.subs(x,self._right_support[0]).subs(x0,self._crown_x)- \ + self._moment_y_func.subs(x,self._crown_x).subs(x0,self._crown_x) +\ + self._moment_x_func.subs(x,self._right_support[0]).subs(y,self._crown_y) -\ + self._moment_x_func.subs(x,self._crown_x).subs(y,self._crown_y) + + net_x = self._load_x_func.subs(x,self._right_support[0]) + net_y = self._load_y_func.subs(x,self._right_support[0]) + + if (self._supports['left']=='roller' or self._supports['right']=='roller') and not self._member: + print("member must be added if any of the supports is roller") + return + + R_A_x, R_A_y, R_B_x, R_B_y, T = symbols('R_A_x R_A_y R_B_x R_B_y T') + + if self._supports['left'] == 'roller' and self._supports['right'] == 'roller': + + if self._member[2]>=max(self._left_support[1],self._right_support[1]): + + if net_x!=0: + raise ValueError("net force in x direction not possible under the specified conditions") + + else: + eq1 = Eq(R_A_x ,0) + eq2 = Eq(R_B_x, 0) + eq3 = Eq(R_A_y + R_B_y + net_y,0) + + eq4 = Eq(R_B_y*(self._right_support[0]-self._left_support[0])-\ + R_B_x*(self._right_support[1]-self._left_support[1])+moment_A,0) + + eq5 = Eq(moment_hinge_right + R_B_y*(self._right_support[0]-self._crown_x) +\ + T*(self._member[2]-self._crown_y),0) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + + elif self._member[2]>=self._left_support[1]: + eq1 = Eq(R_A_x ,0) + eq2 = Eq(R_B_x, 0) + eq3 = Eq(R_A_y + R_B_y + net_y,0) + eq4 = Eq(R_B_y*(self._right_support[0]-self._left_support[0])-\ + T*(self._member[2]-self._left_support[1])+moment_A,0) + eq5 = Eq(T+net_x,0) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + + elif self._member[2]>=self._right_support[1]: + eq1 = Eq(R_A_x ,0) + eq2 = Eq(R_B_x, 0) + eq3 = Eq(R_A_y + R_B_y + net_y,0) + eq4 = Eq(R_B_y*(self._right_support[0]-self._left_support[0])+\ + T*(self._member[2]-self._left_support[1])+moment_A,0) + eq5 = Eq(T-net_x,0) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + + elif self._supports['left'] == 'roller': + if self._member[2]>=max(self._left_support[1], self._right_support[1]): + eq1 = Eq(R_A_x ,0) + eq2 = Eq(R_B_x+net_x,0) + eq3 = Eq(R_A_y + R_B_y + net_y,0) + eq4 = Eq(R_B_y*(self._right_support[0]-self._left_support[0])-\ + R_B_x*(self._right_support[1]-self._left_support[1])+moment_A,0) + eq5 = Eq(moment_hinge_left + R_A_y*(self._left_support[0]-self._crown_x) -\ + T*(self._member[2]-self._crown_y),0) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + + elif self._member[2]>=self._left_support[1]: + eq1 = Eq(R_A_x ,0) + eq2 = Eq(R_B_x+ T +net_x,0) + eq3 = Eq(R_A_y + R_B_y + net_y,0) + eq4 = Eq(R_B_y*(self._right_support[0]-self._left_support[0])-\ + R_B_x*(self._right_support[1]-self._left_support[1])-\ + T*(self._member[2]-self._left_support[0])+moment_A,0) + eq5 = Eq(moment_hinge_left + R_A_y*(self._left_support[0]-self._crown_x)-\ + T*(self._member[2]-self._crown_y),0) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + + elif self._member[2]>=self._right_support[0]: + eq1 = Eq(R_A_x,0) + eq2 = Eq(R_B_x- T +net_x,0) + eq3 = Eq(R_A_y + R_B_y + net_y,0) + eq4 = Eq(moment_hinge_left+R_A_y*(self._left_support[0]-self._crown_x),0) + eq5 = Eq(moment_A+R_B_y*(self._right_support[0]-self._left_support[0])-\ + R_B_x*(self._right_support[1]-self._left_support[1])+\ + T*(self._member[2]-self._left_support[1]),0) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + + elif self._supports['right'] == 'roller': + if self._member[2]>=max(self._left_support[1], self._right_support[1]): + eq1 = Eq(R_B_x,0) + eq2 = Eq(R_A_x+net_x,0) + eq3 = Eq(R_A_y+R_B_y+net_y,0) + eq4 = Eq(moment_hinge_right+R_B_y*(self._right_support[0]-self._crown_x)+\ + T*(self._member[2]-self._crown_y),0) + eq5 = Eq(moment_A+R_B_y*(self._right_support[0]-self._left_support[0]),0) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + + elif self._member[2]>=self._left_support[1]: + eq1 = Eq(R_B_x,0) + eq2 = Eq(R_A_x+T+net_x,0) + eq3 = Eq(R_A_y+R_B_y+net_y,0) + eq4 = Eq(moment_hinge_right+R_B_y*(self._right_support[0]-self._crown_x),0) + eq5 = Eq(moment_A-T*(self._member[2]-self._left_support[1])+\ + R_B_y*(self._right_support[0]-self._left_support[0]),0) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + + elif self._member[2]>=self._right_support[1]: + eq1 = Eq(R_B_x,0) + eq2 = Eq(R_A_x-T+net_x,0) + eq3 = Eq(R_A_y+R_B_y+net_y,0) + eq4 = Eq(moment_hinge_right+R_B_y*(self._right_support[0]-self._crown_x)+\ + T*(self._member[2]-self._crown_y),0) + eq5 = Eq(moment_A+T*(self._member[2]-self._left_support[1])+\ + R_B_y*(self._right_support[0]-self._left_support[0])) + solution = solve((eq1,eq2,eq3,eq4,eq5),(R_A_x,R_A_y,R_B_x,R_B_y,T)) + else: + eq1 = Eq(R_A_x + R_B_x + net_x,0) + eq2 = Eq(R_A_y + R_B_y + net_y,0) + eq3 = Eq(R_B_y*(self._right_support[0]-self._left_support[0])-\ + R_B_x*(self._right_support[1]-self._left_support[1])+moment_A,0) + eq4 = Eq(moment_hinge_right + R_B_y*(self._right_support[0]-self._crown_x) -\ + R_B_x*(self._right_support[1]-self._crown_y),0) + solution = solve((eq1,eq2,eq3,eq4),(R_A_x,R_A_y,R_B_x,R_B_y)) + + for symb in self._reaction_force: + self._reaction_force[symb] = solution[symb] + + self._bending_moment = - (self._moment_x_func.subs(x,x0) + self._moment_y_func.subs(x,x0) -\ + solution[R_A_y]*(x0-self._left_support[0]) +\ + solution[R_A_x]*(self._shape_eqn.subs({x:x0})-self._left_support[1])) + + angle = atan(diff(self._shape_eqn,x)) + + fx = (self._load_x_func+solution[R_A_x]) + fy = (self._load_y_func+solution[R_A_y]) + + axial_force = fx*cos(angle) + fy*sin(angle) + shear_force = -fx*sin(angle) + fy*cos(angle) + + self._axial_force = axial_force + self._shear_force = shear_force + + @doctest_depends_on(modules=('numpy',)) + def draw(self): + """ + This method returns a plot object containing the diagram of the specified arch along with the supports + and forces applied to the structure. + + Examples + ======== + + >>> from sympy import Symbol + >>> t = Symbol('t') + >>> from sympy.physics.continuum_mechanics.arch import Arch + >>> a = Arch((0,0),(40,0),crown_x=20,crown_y=12) + >>> a.apply_load(-1,'C',8,150,angle=270) + >>> a.apply_load(0,'D',start=20,end=40,mag=-4) + >>> a.apply_load(-1,'E',10,t,angle=300) + >>> p = a.draw() + >>> p # doctest: +ELLIPSIS + Plot object containing: + [0]: cartesian line: 11.325 - 3*(x - 20)**2/100 for x over (0.0, 40.0) + [1]: cartesian line: 12 - 3*(x - 20)**2/100 for x over (0.0, 40.0) + ... + >>> p.show() + + """ + x = Symbol('x') + markers = [] + annotations = self._draw_loads() + rectangles = [] + supports = self._draw_supports() + markers+=supports + + xmax = self._right_support[0] + xmin = self._left_support[0] + ymin = min(self._left_support[1],self._right_support[1]) + ymax = self._crown_y + + lim = max(xmax*1.1-xmin*0.8+1, ymax*1.1-ymin*0.8+1) + + rectangles = self._draw_rectangles() + + filler = self._draw_filler() + rectangles+=filler + + if self._member is not None: + if(self._member[2]>=self._right_support[1]): + markers.append( + { + 'args':[[self._member[1]+0.005*lim],[self._member[2]]], + 'marker':'o', + 'markersize': 4, + 'color': 'white', + 'markerfacecolor':'none' + } + ) + + if(self._member[2]>=self._left_support[1]): + markers.append( + { + 'args':[[self._member[0]-0.005*lim],[self._member[2]]], + 'marker':'o', + 'markersize': 4, + 'color': 'white', + 'markerfacecolor':'none' + } + ) + + + + markers.append({ + 'args':[[self._crown_x],[self._crown_y-0.005*lim]], + 'marker':'o', + 'markersize': 5, + 'color':'white', + 'markerfacecolor':'none', + }) + + if lim==xmax*1.1-xmin*0.8+1: + + sing_plot = plot(self._shape_eqn-0.015*lim, + self._shape_eqn, + (x, self._left_support[0], self._right_support[0]), + markers=markers, + show=False, + annotations=annotations, + rectangles = rectangles, + xlim=(xmin-0.05*lim, xmax*1.1), + ylim=(xmin-0.05*lim, xmax*1.1), + axis=False, + line_color='brown') + + else: + sing_plot = plot(self._shape_eqn-0.015*lim, + self._shape_eqn, + (x, self._left_support[0], self._right_support[0]), + markers=markers, + show=False, + annotations=annotations, + rectangles = rectangles, + xlim=(ymin-0.05*lim, ymax*1.1), + ylim=(ymin-0.05*lim, ymax*1.1), + axis=False, + line_color='brown') + + return sing_plot + + + def _draw_supports(self): + support_markers = [] + + xmax = self._right_support[0] + xmin = self._left_support[0] + ymin = min(self._left_support[1],self._right_support[1]) + ymax = self._crown_y + + if abs(1.1*xmax-0.8*xmin)>abs(1.1*ymax-0.8*ymin): + max_diff = 1.1*xmax-0.8*xmin + else: + max_diff = 1.1*ymax-0.8*ymin + + if self._supports['left']=='roller': + support_markers.append( + { + 'args':[ + [self._left_support[0]], + [self._left_support[1]-0.02*max_diff] + ], + 'marker':'o', + 'markersize':11, + 'color':'black', + 'markerfacecolor':'none' + } + ) + else: + support_markers.append( + { + 'args':[ + [self._left_support[0]], + [self._left_support[1]-0.007*max_diff] + ], + 'marker':6, + 'markersize':15, + 'color':'black', + 'markerfacecolor':'none' + } + ) + + if self._supports['right']=='roller': + support_markers.append( + { + 'args':[ + [self._right_support[0]], + [self._right_support[1]-0.02*max_diff] + ], + 'marker':'o', + 'markersize':11, + 'color':'black', + 'markerfacecolor':'none' + } + ) + else: + support_markers.append( + { + 'args':[ + [self._right_support[0]], + [self._right_support[1]-0.007*max_diff] + ], + 'marker':6, + 'markersize':15, + 'color':'black', + 'markerfacecolor':'none' + } + ) + + support_markers.append( + { + 'args':[ + [self._right_support[0]], + [self._right_support[1]-0.036*max_diff] + ], + 'marker':'_', + 'markersize':15, + 'color':'black', + 'markerfacecolor':'none' + } + ) + + support_markers.append( + { + 'args':[ + [self._left_support[0]], + [self._left_support[1]-0.036*max_diff] + ], + 'marker':'_', + 'markersize':15, + 'color':'black', + 'markerfacecolor':'none' + } + ) + + return support_markers + + def _draw_rectangles(self): + member = [] + + xmax = self._right_support[0] + xmin = self._left_support[0] + ymin = min(self._left_support[1],self._right_support[1]) + ymax = self._crown_y + + if abs(1.1*xmax-0.8*xmin)>abs(1.1*ymax-0.8*ymin): + max_diff = 1.1*xmax-0.8*xmin + else: + max_diff = 1.1*ymax-0.8*ymin + + if self._member is not None: + if self._member[2]>= max(self._left_support[1],self._right_support[1]): + member.append( + { + 'xy':(self._member[0],self._member[2]-0.005*max_diff), + 'width':self._member[1]-self._member[0], + 'height': 0.01*max_diff, + 'angle': 0, + 'color':'brown', + } + ) + + elif self._member[2]>=self._left_support[1]: + member.append( + { + 'xy':(self._member[0],self._member[2]-0.005*max_diff), + 'width':self._right_support[0]-self._member[0], + 'height': 0.01*max_diff, + 'angle': 0, + 'color':'brown', + } + ) + + else: + member.append( + { + 'xy':(self._member[1],self._member[2]-0.005*max_diff), + 'width':abs(self._left_support[0]-self._member[1]), + 'height': 0.01*max_diff, + 'angle': 180, + 'color':'brown', + } + ) + + if self._distributed_loads: + for loads in self._distributed_loads: + + start = self._distributed_loads[loads]['start'] + end = self._distributed_loads[loads]['end'] + + member.append( + { + 'xy':(start,self._crown_y+max_diff*0.15), + 'width': (end-start), + 'height': max_diff*0.01, + 'color': 'orange' + } + ) + + + return member + + def _draw_loads(self): + load_annotations = [] + + xmax = self._right_support[0] + xmin = self._left_support[0] + ymin = min(self._left_support[1],self._right_support[1]) + ymax = self._crown_y + + if abs(1.1*xmax-0.8*xmin)>abs(1.1*ymax-0.8*ymin): + max_diff = 1.1*xmax-0.8*xmin + else: + max_diff = 1.1*ymax-0.8*ymin + + for load in self._conc_loads: + x = self._conc_loads[load]['x'] + y = self._conc_loads[load]['y'] + angle = self._conc_loads[load]['angle'] + mag = self._conc_loads[load]['mag'] + load_annotations.append( + { + 'text':'', + 'xy':( + x+cos(rad(angle))*max_diff*0.08, + y+sin(rad(angle))*max_diff*0.08 + ), + 'xytext':(x,y), + 'fontsize':10, + 'fontweight': 'bold', + 'arrowprops':{'width':1.5, 'headlength':5, 'headwidth':5, 'facecolor':'blue','edgecolor':'blue'} + } + ) + load_annotations.append( + { + 'text':f'{load}: {mag} N', + 'fontsize':10, + 'fontweight': 'bold', + 'xy': (x+cos(rad(angle))*max_diff*0.12,y+sin(rad(angle))*max_diff*0.12) + } + ) + + for load in self._distributed_loads: + start = self._distributed_loads[load]['start'] + end = self._distributed_loads[load]['end'] + mag = self._distributed_loads[load]['f_y'] + x_points = numpy.arange(start,end,(end-start)/(max_diff*0.25)) + x_points = numpy.append(x_points,end) + for point in x_points: + if(mag<0): + load_annotations.append( + { + 'text':'', + 'xy':(point,self._crown_y+max_diff*0.05), + 'xytext': (point,self._crown_y+max_diff*0.15), + 'arrowprops':{'width':1.5, 'headlength':5, 'headwidth':5, 'facecolor':'orange','edgecolor':'orange'} + } + ) + else: + load_annotations.append( + { + 'text':'', + 'xy':(point,self._crown_y+max_diff*0.2), + 'xytext': (point,self._crown_y+max_diff*0.15), + 'arrowprops':{'width':1.5, 'headlength':5, 'headwidth':5, 'facecolor':'orange','edgecolor':'orange'} + } + ) + if(mag<0): + load_annotations.append( + { + 'text':f'{load}: {abs(mag)} N/m', + 'fontsize':10, + 'fontweight': 'bold', + 'xy':((start+end)/2,self._crown_y+max_diff*0.175) + } + ) + else: + load_annotations.append( + { + 'text':f'{load}: {abs(mag)} N/m', + 'fontsize':10, + 'fontweight': 'bold', + 'xy':((start+end)/2,self._crown_y+max_diff*0.125) + } + ) + return load_annotations + + def _draw_filler(self): + x = Symbol('x') + filler = [] + xmax = self._right_support[0] + xmin = self._left_support[0] + ymin = min(self._left_support[1],self._right_support[1]) + ymax = self._crown_y + + if abs(1.1*xmax-0.8*xmin)>abs(1.1*ymax-0.8*ymin): + max_diff = 1.1*xmax-0.8*xmin + else: + max_diff = 1.1*ymax-0.8*ymin + + x_points = numpy.arange(self._left_support[0],self._right_support[0],(self._right_support[0]-self._left_support[0])/(max_diff*max_diff)) + + for point in x_points: + filler.append( + { + 'xy':(point,self._shape_eqn.subs(x,point)-max_diff*0.015), + 'width': (self._right_support[0]-self._left_support[0])/(max_diff*max_diff), + 'height': max_diff*0.015, + 'color': 'brown' + } + ) + + return filler diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/beam.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/beam.py new file mode 100644 index 0000000000000000000000000000000000000000..dfdfc6d3594da6de44c7c42def3e3f5539cb988e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/beam.py @@ -0,0 +1,3903 @@ +""" +This module can be used to solve 2D beam bending problems with +singularity functions in mechanics. +""" + +from sympy.core import S, Symbol, diff, symbols +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.function import (Derivative, Function) +from sympy.core.mul import Mul +from sympy.core.relational import Eq +from sympy.core.sympify import sympify +from sympy.solvers import linsolve +from sympy.solvers.ode.ode import dsolve +from sympy.solvers.solvers import solve +from sympy.printing import sstr +from sympy.functions import SingularityFunction, Piecewise, factorial +from sympy.integrals import integrate +from sympy.series import limit +from sympy.plotting import plot, PlotGrid +from sympy.geometry.entity import GeometryEntity +from sympy.external import import_module +from sympy.sets.sets import Interval +from sympy.utilities.lambdify import lambdify +from sympy.utilities.decorator import doctest_depends_on +from sympy.utilities.iterables import iterable +import warnings + + +__doctest_requires__ = { + ('Beam.draw', + 'Beam.plot_bending_moment', + 'Beam.plot_deflection', + 'Beam.plot_ild_moment', + 'Beam.plot_ild_shear', + 'Beam.plot_shear_force', + 'Beam.plot_shear_stress', + 'Beam.plot_slope'): ['matplotlib'], +} + + +numpy = import_module('numpy', import_kwargs={'fromlist':['arange']}) + + +class Beam: + """ + A Beam is a structural element that is capable of withstanding load + primarily by resisting against bending. Beams are characterized by + their cross sectional profile(Second moment of area), their length + and their material. + + .. note:: + A consistent sign convention must be used while solving a beam + bending problem; the results will + automatically follow the chosen sign convention. However, the + chosen sign convention must respect the rule that, on the positive + side of beam's axis (in respect to current section), a loading force + giving positive shear yields a negative moment, as below (the + curved arrow shows the positive moment and rotation): + + .. image:: allowed-sign-conventions.png + + Examples + ======== + There is a beam of length 4 meters. A constant distributed load of 6 N/m + is applied from half of the beam till the end. There are two simple supports + below the beam, one at the starting point and another at the ending point + of the beam. The deflection of the beam at the end is restricted. + + Using the sign convention of downwards forces being positive. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols, Piecewise + >>> E, I = symbols('E, I') + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(4, E, I) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(6, 2, 0) + >>> b.apply_load(R2, 4, -1) + >>> b.bc_deflection = [(0, 0), (4, 0)] + >>> b.boundary_conditions + {'bending_moment': [], 'deflection': [(0, 0), (4, 0)], 'shear_force': [], 'slope': []} + >>> b.load + R1*SingularityFunction(x, 0, -1) + R2*SingularityFunction(x, 4, -1) + 6*SingularityFunction(x, 2, 0) + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.load + -3*SingularityFunction(x, 0, -1) + 6*SingularityFunction(x, 2, 0) - 9*SingularityFunction(x, 4, -1) + >>> b.shear_force() + 3*SingularityFunction(x, 0, 0) - 6*SingularityFunction(x, 2, 1) + 9*SingularityFunction(x, 4, 0) + >>> b.bending_moment() + 3*SingularityFunction(x, 0, 1) - 3*SingularityFunction(x, 2, 2) + 9*SingularityFunction(x, 4, 1) + >>> b.slope() + (-3*SingularityFunction(x, 0, 2)/2 + SingularityFunction(x, 2, 3) - 9*SingularityFunction(x, 4, 2)/2 + 7)/(E*I) + >>> b.deflection() + (7*x - SingularityFunction(x, 0, 3)/2 + SingularityFunction(x, 2, 4)/4 - 3*SingularityFunction(x, 4, 3)/2)/(E*I) + >>> b.deflection().rewrite(Piecewise) + (7*x - Piecewise((x**3, x >= 0), (0, True))/2 + - 3*Piecewise(((x - 4)**3, x >= 4), (0, True))/2 + + Piecewise(((x - 2)**4, x >= 2), (0, True))/4)/(E*I) + + Calculate the support reactions for a fully symbolic beam of length L. + There are two simple supports below the beam, one at the starting point + and another at the ending point of the beam. The deflection of the beam + at the end is restricted. The beam is loaded with: + + * a downward point load P1 applied at L/4 + * an upward point load P2 applied at L/8 + * a counterclockwise moment M1 applied at L/2 + * a clockwise moment M2 applied at 3*L/4 + * a distributed constant load q1, applied downward, starting from L/2 + up to 3*L/4 + * a distributed constant load q2, applied upward, starting from 3*L/4 + up to L + + No assumptions are needed for symbolic loads. However, defining a positive + length will help the algorithm to compute the solution. + + >>> E, I = symbols('E, I') + >>> L = symbols("L", positive=True) + >>> P1, P2, M1, M2, q1, q2 = symbols("P1, P2, M1, M2, q1, q2") + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(L, E, I) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(R2, L, -1) + >>> b.apply_load(P1, L/4, -1) + >>> b.apply_load(-P2, L/8, -1) + >>> b.apply_load(M1, L/2, -2) + >>> b.apply_load(-M2, 3*L/4, -2) + >>> b.apply_load(q1, L/2, 0, 3*L/4) + >>> b.apply_load(-q2, 3*L/4, 0, L) + >>> b.bc_deflection = [(0, 0), (L, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> print(b.reaction_loads[R1]) + (-3*L**2*q1 + L**2*q2 - 24*L*P1 + 28*L*P2 - 32*M1 + 32*M2)/(32*L) + >>> print(b.reaction_loads[R2]) + (-5*L**2*q1 + 7*L**2*q2 - 8*L*P1 + 4*L*P2 + 32*M1 - 32*M2)/(32*L) + """ + + def __init__(self, length, elastic_modulus, second_moment, area=Symbol('A'), variable=Symbol('x'), base_char='C', ild_variable=Symbol('a')): + """Initializes the class. + + Parameters + ========== + + length : Sympifyable + A Symbol or value representing the Beam's length. + + elastic_modulus : Sympifyable + A SymPy expression representing the Beam's Modulus of Elasticity. + It is a measure of the stiffness of the Beam material. It can + also be a continuous function of position along the beam. + + second_moment : Sympifyable or Geometry object + Describes the cross-section of the beam via a SymPy expression + representing the Beam's second moment of area. It is a geometrical + property of an area which reflects how its points are distributed + with respect to its neutral axis. It can also be a continuous + function of position along the beam. Alternatively ``second_moment`` + can be a shape object such as a ``Polygon`` from the geometry module + representing the shape of the cross-section of the beam. In such cases, + it is assumed that the x-axis of the shape object is aligned with the + bending axis of the beam. The second moment of area will be computed + from the shape object internally. + + area : Symbol/float + Represents the cross-section area of beam + + variable : Symbol, optional + A Symbol object that will be used as the variable along the beam + while representing the load, shear, moment, slope and deflection + curve. By default, it is set to ``Symbol('x')``. + + base_char : String, optional + A String that will be used as base character to generate sequential + symbols for integration constants in cases where boundary conditions + are not sufficient to solve them. + + ild_variable : Symbol, optional + A Symbol object that will be used as the variable specifying the + location of the moving load in ILD calculations. By default, it + is set to ``Symbol('a')``. + """ + self.length = length + self.elastic_modulus = elastic_modulus + if isinstance(second_moment, GeometryEntity): + self.cross_section = second_moment + else: + self.cross_section = None + self.second_moment = second_moment + self.variable = variable + self.ild_variable = ild_variable + self._base_char = base_char + self._boundary_conditions = {'deflection': [], 'slope': [], 'bending_moment': [], 'shear_force': []} + self._load = 0 + self.area = area + self._applied_supports = [] + self._applied_rotation_hinges = [] + self._applied_sliding_hinges = [] + self._rotation_hinge_symbols = [] + self._sliding_hinge_symbols = [] + self._support_as_loads = [] + self._applied_loads = [] + self._reaction_loads = {} + self._ild_reactions = {} + self._ild_shear = 0 + self._ild_moment = 0 + # _original_load is a copy of _load equations with unsubstituted reaction + # forces. It is used for calculating reaction forces in case of I.L.D. + self._original_load = 0 + self._joined_beam = False + + def __str__(self): + shape_description = self._cross_section if self._cross_section else self._second_moment + str_sol = 'Beam({}, {}, {})'.format(sstr(self._length), sstr(self._elastic_modulus), sstr(shape_description)) + return str_sol + + @property + def reaction_loads(self): + """ Returns the reaction forces in a dictionary.""" + return self._reaction_loads + + @property + def rotation_jumps(self): + """ + Returns the value for the rotation jumps in rotation hinges in a dictionary. + The rotation jump is the rotation (in radian) in a rotation hinge. This can + be seen as a jump in the slope plot. + """ + return self._rotation_jumps + + @property + def deflection_jumps(self): + """ + Returns the deflection jumps in sliding hinges in a dictionary. + The deflection jump is the deflection (in meters) in a sliding hinge. + This can be seen as a jump in the deflection plot. + """ + return self._deflection_jumps + + @property + def ild_shear(self): + """ Returns the I.L.D. shear equation.""" + return self._ild_shear + + @property + def ild_reactions(self): + """ Returns the I.L.D. reaction forces in a dictionary.""" + return self._ild_reactions + + @property + def ild_rotation_jumps(self): + """ + Returns the I.L.D. rotation jumps in rotation hinges in a dictionary. + The rotation jump is the rotation (in radian) in a rotation hinge. This can + be seen as a jump in the slope plot. + """ + return self._ild_rotations_jumps + + @property + def ild_deflection_jumps(self): + """ + Returns the I.L.D. deflection jumps in sliding hinges in a dictionary. + The deflection jump is the deflection (in meters) in a sliding hinge. + This can be seen as a jump in the deflection plot. + """ + return self._ild_deflection_jumps + + @property + def ild_moment(self): + """ Returns the I.L.D. moment equation.""" + return self._ild_moment + + @property + def length(self): + """Length of the Beam.""" + return self._length + + @length.setter + def length(self, l): + self._length = sympify(l) + + @property + def area(self): + """Cross-sectional area of the Beam. """ + return self._area + + @area.setter + def area(self, a): + self._area = sympify(a) + + @property + def variable(self): + """ + A symbol that can be used as a variable along the length of the beam + while representing load distribution, shear force curve, bending + moment, slope curve and the deflection curve. By default, it is set + to ``Symbol('x')``, but this property is mutable. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I, A = symbols('E, I, A') + >>> x, y, z = symbols('x, y, z') + >>> b = Beam(4, E, I) + >>> b.variable + x + >>> b.variable = y + >>> b.variable + y + >>> b = Beam(4, E, I, A, z) + >>> b.variable + z + """ + return self._variable + + @variable.setter + def variable(self, v): + if isinstance(v, Symbol): + self._variable = v + else: + raise TypeError("""The variable should be a Symbol object.""") + + @property + def elastic_modulus(self): + """Young's Modulus of the Beam. """ + return self._elastic_modulus + + @elastic_modulus.setter + def elastic_modulus(self, e): + self._elastic_modulus = sympify(e) + + @property + def second_moment(self): + """Second moment of area of the Beam. """ + return self._second_moment + + @second_moment.setter + def second_moment(self, i): + self._cross_section = None + if isinstance(i, GeometryEntity): + raise ValueError("To update cross-section geometry use `cross_section` attribute") + else: + self._second_moment = sympify(i) + + @property + def cross_section(self): + """Cross-section of the beam""" + return self._cross_section + + @cross_section.setter + def cross_section(self, s): + if s: + self._second_moment = s.second_moment_of_area()[0] + self._cross_section = s + + @property + def boundary_conditions(self): + """ + Returns a dictionary of boundary conditions applied on the beam. + The dictionary has three keywords namely moment, slope and deflection. + The value of each keyword is a list of tuple, where each tuple + contains location and value of a boundary condition in the format + (location, value). + + Examples + ======== + There is a beam of length 4 meters. The bending moment at 0 should be 4 + and at 4 it should be 0. The slope of the beam should be 1 at 0. The + deflection should be 2 at 0. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> b = Beam(4, E, I) + >>> b.bc_deflection = [(0, 2)] + >>> b.bc_slope = [(0, 1)] + >>> b.boundary_conditions + {'bending_moment': [], 'deflection': [(0, 2)], 'shear_force': [], 'slope': [(0, 1)]} + + Here the deflection of the beam should be ``2`` at ``0``. + Similarly, the slope of the beam should be ``1`` at ``0``. + """ + return self._boundary_conditions + + @property + def bc_shear_force(self): + return self._boundary_conditions['shear_force'] + + @bc_shear_force.setter + def bc_shear_force(self, sf_bcs): + self._boundary_conditions['shear_force'] = sf_bcs + + @property + def bc_bending_moment(self): + return self._boundary_conditions['bending_moment'] + + @bc_bending_moment.setter + def bc_bending_moment(self, bm_bcs): + self._boundary_conditions['bending_moment'] = bm_bcs + + @property + def bc_slope(self): + return self._boundary_conditions['slope'] + + @bc_slope.setter + def bc_slope(self, s_bcs): + self._boundary_conditions['slope'] = s_bcs + + @property + def bc_deflection(self): + return self._boundary_conditions['deflection'] + + @bc_deflection.setter + def bc_deflection(self, d_bcs): + self._boundary_conditions['deflection'] = d_bcs + + def join(self, beam, via="fixed"): + """ + This method joins two beams to make a new composite beam system. + Passed Beam class instance is attached to the right end of calling + object. This method can be used to form beams having Discontinuous + values of Elastic modulus or Second moment. + + Parameters + ========== + beam : Beam class object + The Beam object which would be connected to the right of calling + object. + via : String + States the way two Beam object would get connected + - For axially fixed Beams, via="fixed" + - For Beams connected via rotation hinge, via="hinge" + + Examples + ======== + There is a cantilever beam of length 4 meters. For first 2 meters + its moment of inertia is `1.5*I` and `I` for the other end. + A pointload of magnitude 4 N is applied from the top at its free end. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> R1, R2 = symbols('R1, R2') + >>> b1 = Beam(2, E, 1.5*I) + >>> b2 = Beam(2, E, I) + >>> b = b1.join(b2, "fixed") + >>> b.apply_load(20, 4, -1) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(R2, 0, -2) + >>> b.bc_slope = [(0, 0)] + >>> b.bc_deflection = [(0, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.load + 80*SingularityFunction(x, 0, -2) - 20*SingularityFunction(x, 0, -1) + 20*SingularityFunction(x, 4, -1) + >>> b.slope() + (-((-80*SingularityFunction(x, 0, 1) + 10*SingularityFunction(x, 0, 2) - 10*SingularityFunction(x, 4, 2))/I + 120/I)/E + 80.0/(E*I))*SingularityFunction(x, 2, 0) + - 0.666666666666667*(-80*SingularityFunction(x, 0, 1) + 10*SingularityFunction(x, 0, 2) - 10*SingularityFunction(x, 4, 2))*SingularityFunction(x, 0, 0)/(E*I) + + 0.666666666666667*(-80*SingularityFunction(x, 0, 1) + 10*SingularityFunction(x, 0, 2) - 10*SingularityFunction(x, 4, 2))*SingularityFunction(x, 2, 0)/(E*I) + """ + x = self.variable + E = self.elastic_modulus + new_length = self.length + beam.length + if self.elastic_modulus != beam.elastic_modulus: + raise NotImplementedError('Joining beams with different Elastic modulus is not implemented.') + + if self.second_moment != beam.second_moment: + new_second_moment = Piecewise((self.second_moment, x<=self.length), + (beam.second_moment, x<=new_length)) + else: + new_second_moment = self.second_moment + + if via == "fixed": + new_beam = Beam(new_length, E, new_second_moment, x) + new_beam._joined_beam = True + return new_beam + + if via == "hinge": + new_beam = Beam(new_length, E, new_second_moment, x) + new_beam._joined_beam = True + new_beam.apply_rotation_hinge(self.length) + return new_beam + + def apply_support(self, loc, type="fixed"): + """ + This method applies support to a particular beam object and returns + the symbol of the unknown reaction load(s). + + Parameters + ========== + loc : Sympifyable + Location of point at which support is applied. + type : String + Determines type of Beam support applied. To apply support structure + with + - zero degree of freedom, type = "fixed" + - one degree of freedom, type = "pin" + - two degrees of freedom, type = "roller" + + Returns + ======= + Symbol or tuple of Symbol + The unknown reaction load as a symbol. + - Symbol(reaction_force) if type = "pin" or "roller" + - Symbol(reaction_force), Symbol(reaction_moment) if type = "fixed" + + Examples + ======== + There is a beam of length 20 meters. A moment of magnitude 100 Nm is + applied in the clockwise direction at the end of the beam. A pointload + of magnitude 8 N is applied from the top of the beam at a distance of 10 meters. + There is one fixed support at the start of the beam and a roller at the end. + + Using the sign convention of upward forces and clockwise moment + being positive. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> b = Beam(20, E, I) + >>> p0, m0 = b.apply_support(0, 'fixed') + >>> p1 = b.apply_support(20, 'roller') + >>> b.apply_load(-8, 10, -1) + >>> b.apply_load(100, 20, -2) + >>> b.solve_for_reaction_loads(p0, m0, p1) + >>> b.reaction_loads + {M_0: 20, R_0: -2, R_20: 10} + >>> b.reaction_loads[p0] + -2 + >>> b.load + 20*SingularityFunction(x, 0, -2) - 2*SingularityFunction(x, 0, -1) + - 8*SingularityFunction(x, 10, -1) + 100*SingularityFunction(x, 20, -2) + + 10*SingularityFunction(x, 20, -1) + """ + loc = sympify(loc) + + self._applied_supports.append((loc, type)) + if type in ("pin", "roller"): + reaction_load = Symbol('R_'+str(loc)) + self.apply_load(reaction_load, loc, -1) + self.bc_deflection.append((loc, 0)) + else: + reaction_load = Symbol('R_'+str(loc)) + reaction_moment = Symbol('M_'+str(loc)) + self.apply_load(reaction_load, loc, -1) + self.apply_load(reaction_moment, loc, -2) + self.bc_deflection.append((loc, 0)) + self.bc_slope.append((loc, 0)) + self._support_as_loads.append((reaction_moment, loc, -2, None)) + + self._support_as_loads.append((reaction_load, loc, -1, None)) + + if type in ("pin", "roller"): + return reaction_load + else: + return reaction_load, reaction_moment + + def _get_I(self, loc): + """ + Helper function that returns the Second moment (I) at a location in the beam. + """ + I = self.second_moment + if not isinstance(I, Piecewise): + return I + else: + for i in range(len(I.args)): + if loc <= I.args[i][1].args[1]: + return I.args[i][0] + + def apply_rotation_hinge(self, loc): + """ + This method applies a rotation hinge at a single location on the beam. + + Parameters + ---------- + loc : Sympifyable + Location of point at which hinge is applied. + + Returns + ======= + Symbol + The unknown rotation jump multiplied by the elastic modulus and second moment as a symbol. + + Examples + ======== + There is a beam of length 15 meters. Pin supports are placed at distances + of 0 and 10 meters. There is a fixed support at the end. There are two rotation hinges + in the structure, one at 5 meters and one at 10 meters. A pointload of magnitude + 10 kN is applied on the hinge at 5 meters. A distributed load of 5 kN works on + the structure from 10 meters to the end. + + Using the sign convention of upward forces and clockwise moment + being positive. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import Symbol + >>> E = Symbol('E') + >>> I = Symbol('I') + >>> b = Beam(15, E, I) + >>> r0 = b.apply_support(0, type='pin') + >>> r10 = b.apply_support(10, type='pin') + >>> r15, m15 = b.apply_support(15, type='fixed') + >>> p5 = b.apply_rotation_hinge(5) + >>> p12 = b.apply_rotation_hinge(12) + >>> b.apply_load(-10, 5, -1) + >>> b.apply_load(-5, 10, 0, 15) + >>> b.solve_for_reaction_loads(r0, r10, r15, m15) + >>> b.reaction_loads + {M_15: -75/2, R_0: 0, R_10: 40, R_15: -5} + >>> b.rotation_jumps + {P_12: -1875/(16*E*I), P_5: 9625/(24*E*I)} + >>> b.rotation_jumps[p12] + -1875/(16*E*I) + >>> b.bending_moment() + -9625*SingularityFunction(x, 5, -1)/24 + 10*SingularityFunction(x, 5, 1) + - 40*SingularityFunction(x, 10, 1) + 5*SingularityFunction(x, 10, 2)/2 + + 1875*SingularityFunction(x, 12, -1)/16 + 75*SingularityFunction(x, 15, 0)/2 + + 5*SingularityFunction(x, 15, 1) - 5*SingularityFunction(x, 15, 2)/2 + """ + loc = sympify(loc) + E = self.elastic_modulus + I = self._get_I(loc) + + rotation_jump = Symbol('P_'+str(loc)) + self._applied_rotation_hinges.append(loc) + self._rotation_hinge_symbols.append(rotation_jump) + self.apply_load(E * I * rotation_jump, loc, -3) + self.bc_bending_moment.append((loc, 0)) + return rotation_jump + + def apply_sliding_hinge(self, loc): + """ + This method applies a sliding hinge at a single location on the beam. + + Parameters + ---------- + loc : Sympifyable + Location of point at which hinge is applied. + + Returns + ======= + Symbol + The unknown deflection jump multiplied by the elastic modulus and second moment as a symbol. + + Examples + ======== + There is a beam of length 13 meters. A fixed support is placed at the beginning. + There is a pin support at the end. There is a sliding hinge at a location of 8 meters. + A pointload of magnitude 10 kN is applied on the hinge at 5 meters. + + Using the sign convention of upward forces and clockwise moment + being positive. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> b = Beam(13, 20, 20) + >>> r0, m0 = b.apply_support(0, type="fixed") + >>> s8 = b.apply_sliding_hinge(8) + >>> r13 = b.apply_support(13, type="pin") + >>> b.apply_load(-10, 5, -1) + >>> b.solve_for_reaction_loads(r0, m0, r13) + >>> b.reaction_loads + {M_0: -50, R_0: 10, R_13: 0} + >>> b.deflection_jumps + {W_8: 85/24} + >>> b.deflection_jumps[s8] + 85/24 + >>> b.bending_moment() + 50*SingularityFunction(x, 0, 0) - 10*SingularityFunction(x, 0, 1) + + 10*SingularityFunction(x, 5, 1) - 4250*SingularityFunction(x, 8, -2)/3 + >>> b.deflection() + -SingularityFunction(x, 0, 2)/16 + SingularityFunction(x, 0, 3)/240 + - SingularityFunction(x, 5, 3)/240 + 85*SingularityFunction(x, 8, 0)/24 + """ + loc = sympify(loc) + E = self.elastic_modulus + I = self._get_I(loc) + + deflection_jump = Symbol('W_' + str(loc)) + self._applied_sliding_hinges.append(loc) + self._sliding_hinge_symbols.append(deflection_jump) + self.apply_load(E * I * deflection_jump, loc, -4) + self.bc_shear_force.append((loc, 0)) + return deflection_jump + + def apply_load(self, value, start, order, end=None): + """ + This method adds up the loads given to a particular beam object. + + Parameters + ========== + value : Sympifyable + The value inserted should have the units [Force/(Distance**(n+1)] + where n is the order of applied load. + Units for applied loads: + + - For moments, unit = kN*m + - For point loads, unit = kN + - For constant distributed load, unit = kN/m + - For ramp loads, unit = kN/m/m + - For parabolic ramp loads, unit = kN/m/m/m + - ... so on. + + start : Sympifyable + The starting point of the applied load. For point moments and + point forces this is the location of application. + order : Integer + The order of the applied load. + + - For moments, order = -2 + - For point loads, order =-1 + - For constant distributed load, order = 0 + - For ramp loads, order = 1 + - For parabolic ramp loads, order = 2 + - ... so on. + + end : Sympifyable, optional + An optional argument that can be used if the load has an end point + within the length of the beam. + + Examples + ======== + There is a beam of length 4 meters. A moment of magnitude 3 Nm is + applied in the clockwise direction at the starting point of the beam. + A point load of magnitude 4 N is applied from the top of the beam at + 2 meters from the starting point and a parabolic ramp load of magnitude + 2 N/m is applied below the beam starting from 2 meters to 3 meters + away from the starting point of the beam. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> b = Beam(4, E, I) + >>> b.apply_load(-3, 0, -2) + >>> b.apply_load(4, 2, -1) + >>> b.apply_load(-2, 2, 2, end=3) + >>> b.load + -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) - 2*SingularityFunction(x, 2, 2) + 2*SingularityFunction(x, 3, 0) + 4*SingularityFunction(x, 3, 1) + 2*SingularityFunction(x, 3, 2) + + """ + x = self.variable + value = sympify(value) + start = sympify(start) + order = sympify(order) + + self._applied_loads.append((value, start, order, end)) + self._load += value*SingularityFunction(x, start, order) + self._original_load += value*SingularityFunction(x, start, order) + + if end: + # load has an end point within the length of the beam. + self._handle_end(x, value, start, order, end, type="apply") + + def remove_load(self, value, start, order, end=None): + """ + This method removes a particular load present on the beam object. + Returns a ValueError if the load passed as an argument is not + present on the beam. + + Parameters + ========== + value : Sympifyable + The magnitude of an applied load. + start : Sympifyable + The starting point of the applied load. For point moments and + point forces this is the location of application. + order : Integer + The order of the applied load. + - For moments, order= -2 + - For point loads, order=-1 + - For constant distributed load, order=0 + - For ramp loads, order=1 + - For parabolic ramp loads, order=2 + - ... so on. + end : Sympifyable, optional + An optional argument that can be used if the load has an end point + within the length of the beam. + + Examples + ======== + There is a beam of length 4 meters. A moment of magnitude 3 Nm is + applied in the clockwise direction at the starting point of the beam. + A pointload of magnitude 4 N is applied from the top of the beam at + 2 meters from the starting point and a parabolic ramp load of magnitude + 2 N/m is applied below the beam starting from 2 meters to 3 meters + away from the starting point of the beam. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> b = Beam(4, E, I) + >>> b.apply_load(-3, 0, -2) + >>> b.apply_load(4, 2, -1) + >>> b.apply_load(-2, 2, 2, end=3) + >>> b.load + -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) - 2*SingularityFunction(x, 2, 2) + 2*SingularityFunction(x, 3, 0) + 4*SingularityFunction(x, 3, 1) + 2*SingularityFunction(x, 3, 2) + >>> b.remove_load(-2, 2, 2, end = 3) + >>> b.load + -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) + """ + x = self.variable + value = sympify(value) + start = sympify(start) + order = sympify(order) + + if (value, start, order, end) in self._applied_loads: + self._load -= value*SingularityFunction(x, start, order) + self._original_load -= value*SingularityFunction(x, start, order) + self._applied_loads.remove((value, start, order, end)) + else: + msg = "No such load distribution exists on the beam object." + raise ValueError(msg) + + if end: + # load has an end point within the length of the beam. + self._handle_end(x, value, start, order, end, type="remove") + + def _handle_end(self, x, value, start, order, end, type): + """ + This functions handles the optional `end` value in the + `apply_load` and `remove_load` functions. When the value + of end is not NULL, this function will be executed. + """ + if order.is_negative: + msg = ("If 'end' is provided the 'order' of the load cannot " + "be negative, i.e. 'end' is only valid for distributed " + "loads.") + raise ValueError(msg) + # NOTE : A Taylor series can be used to define the summation of + # singularity functions that subtract from the load past the end + # point such that it evaluates to zero past 'end'. + f = value*x**order + + if type == "apply": + # iterating for "apply_load" method + for i in range(0, order + 1): + self._load -= (f.diff(x, i).subs(x, end - start) * + SingularityFunction(x, end, i)/factorial(i)) + self._original_load -= (f.diff(x, i).subs(x, end - start) * + SingularityFunction(x, end, i)/factorial(i)) + elif type == "remove": + # iterating for "remove_load" method + for i in range(0, order + 1): + self._load += (f.diff(x, i).subs(x, end - start) * + SingularityFunction(x, end, i)/factorial(i)) + self._original_load += (f.diff(x, i).subs(x, end - start) * + SingularityFunction(x, end, i)/factorial(i)) + + + @property + def load(self): + """ + Returns a Singularity Function expression which represents + the load distribution curve of the Beam object. + + Examples + ======== + There is a beam of length 4 meters. A moment of magnitude 3 Nm is + applied in the clockwise direction at the starting point of the beam. + A point load of magnitude 4 N is applied from the top of the beam at + 2 meters from the starting point and a parabolic ramp load of magnitude + 2 N/m is applied below the beam starting from 3 meters away from the + starting point of the beam. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> b = Beam(4, E, I) + >>> b.apply_load(-3, 0, -2) + >>> b.apply_load(4, 2, -1) + >>> b.apply_load(-2, 3, 2) + >>> b.load + -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) - 2*SingularityFunction(x, 3, 2) + """ + return self._load + + @property + def applied_loads(self): + """ + Returns a list of all loads applied on the beam object. + Each load in the list is a tuple of form (value, start, order, end). + + Examples + ======== + There is a beam of length 4 meters. A moment of magnitude 3 Nm is + applied in the clockwise direction at the starting point of the beam. + A pointload of magnitude 4 N is applied from the top of the beam at + 2 meters from the starting point. Another pointload of magnitude 5 N + is applied at same position. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> b = Beam(4, E, I) + >>> b.apply_load(-3, 0, -2) + >>> b.apply_load(4, 2, -1) + >>> b.apply_load(5, 2, -1) + >>> b.load + -3*SingularityFunction(x, 0, -2) + 9*SingularityFunction(x, 2, -1) + >>> b.applied_loads + [(-3, 0, -2, None), (4, 2, -1, None), (5, 2, -1, None)] + """ + return self._applied_loads + + def solve_for_reaction_loads(self, *reactions): + """ + Solves for the reaction forces. + + Examples + ======== + There is a beam of length 30 meters. A moment of magnitude 120 Nm is + applied in the clockwise direction at the end of the beam. A pointload + of magnitude 8 N is applied from the top of the beam at the starting + point. There are two simple supports below the beam. One at the end + and another one at a distance of 10 meters from the start. The + deflection is restricted at both the supports. + + Using the sign convention of upward forces and clockwise moment + being positive. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(30, E, I) + >>> b.apply_load(-8, 0, -1) + >>> b.apply_load(R1, 10, -1) # Reaction force at x = 10 + >>> b.apply_load(R2, 30, -1) # Reaction force at x = 30 + >>> b.apply_load(120, 30, -2) + >>> b.bc_deflection = [(10, 0), (30, 0)] + >>> b.load + R1*SingularityFunction(x, 10, -1) + R2*SingularityFunction(x, 30, -1) + - 8*SingularityFunction(x, 0, -1) + 120*SingularityFunction(x, 30, -2) + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.reaction_loads + {R1: 6, R2: 2} + >>> b.load + -8*SingularityFunction(x, 0, -1) + 6*SingularityFunction(x, 10, -1) + + 120*SingularityFunction(x, 30, -2) + 2*SingularityFunction(x, 30, -1) + """ + + x = self.variable + l = self.length + C3 = Symbol('C3') + C4 = Symbol('C4') + rotation_jumps = tuple(self._rotation_hinge_symbols) + deflection_jumps = tuple(self._sliding_hinge_symbols) + + shear_curve = limit(self.shear_force(), x, l) + moment_curve = limit(self.bending_moment(), x, l) + + shear_force_eqs = [] + bending_moment_eqs = [] + slope_eqs = [] + deflection_eqs = [] + + for position, value in self._boundary_conditions['shear_force']: + eqs = self.shear_force().subs(x, position) - value + new_eqs = sum(arg for arg in eqs.args if not any(num.is_infinite for num in arg.args)) + shear_force_eqs.append(new_eqs) + + for position, value in self._boundary_conditions['bending_moment']: + eqs = self.bending_moment().subs(x, position) - value + new_eqs = sum(arg for arg in eqs.args if not any(num.is_infinite for num in arg.args)) + bending_moment_eqs.append(new_eqs) + + slope_curve = integrate(self.bending_moment(), x) + C3 + for position, value in self._boundary_conditions['slope']: + eqs = slope_curve.subs(x, position) - value + slope_eqs.append(eqs) + + deflection_curve = integrate(slope_curve, x) + C4 + for position, value in self._boundary_conditions['deflection']: + eqs = deflection_curve.subs(x, position) - value + deflection_eqs.append(eqs) + + solution = list((linsolve([shear_curve, moment_curve] + shear_force_eqs + bending_moment_eqs + slope_eqs + + deflection_eqs, (C3, C4) + reactions + rotation_jumps + deflection_jumps).args)[0]) + reaction_index = 2+len(reactions) + rotation_index = reaction_index + len(rotation_jumps) + reaction_solution = solution[2:reaction_index] + rotation_solution = solution[reaction_index:rotation_index] + deflection_solution = solution[rotation_index:] + + self._reaction_loads = dict(zip(reactions, reaction_solution)) + self._rotation_jumps = dict(zip(rotation_jumps, rotation_solution)) + self._deflection_jumps = dict(zip(deflection_jumps, deflection_solution)) + self._load = self._load.subs(self._reaction_loads) + self._load = self._load.subs(self._rotation_jumps) + self._load = self._load.subs(self._deflection_jumps) + + def shear_force(self): + """ + Returns a Singularity Function expression which represents + the shear force curve of the Beam object. + + Examples + ======== + There is a beam of length 30 meters. A moment of magnitude 120 Nm is + applied in the clockwise direction at the end of the beam. A pointload + of magnitude 8 N is applied from the top of the beam at the starting + point. There are two simple supports below the beam. One at the end + and another one at a distance of 10 meters from the start. The + deflection is restricted at both the supports. + + Using the sign convention of upward forces and clockwise moment + being positive. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(30, E, I) + >>> b.apply_load(-8, 0, -1) + >>> b.apply_load(R1, 10, -1) + >>> b.apply_load(R2, 30, -1) + >>> b.apply_load(120, 30, -2) + >>> b.bc_deflection = [(10, 0), (30, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.shear_force() + 8*SingularityFunction(x, 0, 0) - 6*SingularityFunction(x, 10, 0) - 120*SingularityFunction(x, 30, -1) - 2*SingularityFunction(x, 30, 0) + """ + x = self.variable + return -integrate(self.load, x) + + def max_shear_force(self): + """Returns maximum Shear force and its coordinate + in the Beam object.""" + shear_curve = self.shear_force() + x = self.variable + + terms = shear_curve.args + singularity = [] # Points at which shear function changes + for term in terms: + if isinstance(term, Mul): + term = term.args[-1] # SingularityFunction in the term + singularity.append(term.args[1]) + singularity = list(set(singularity)) + singularity.sort() + + intervals = [] # List of Intervals with discrete value of shear force + shear_values = [] # List of values of shear force in each interval + for i, s in enumerate(singularity): + if s == 0: + continue + try: + shear_slope = Piecewise((float("nan"), x<=singularity[i-1]),(self._load.rewrite(Piecewise), x>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(30, E, I) + >>> b.apply_load(-8, 0, -1) + >>> b.apply_load(R1, 10, -1) + >>> b.apply_load(R2, 30, -1) + >>> b.apply_load(120, 30, -2) + >>> b.bc_deflection = [(10, 0), (30, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.bending_moment() + 8*SingularityFunction(x, 0, 1) - 6*SingularityFunction(x, 10, 1) - 120*SingularityFunction(x, 30, 0) - 2*SingularityFunction(x, 30, 1) + """ + x = self.variable + return integrate(self.shear_force(), x) + + def max_bmoment(self): + """Returns maximum Shear force and its coordinate + in the Beam object.""" + bending_curve = self.bending_moment() + x = self.variable + + terms = bending_curve.args + singularity = [] # Points at which bending moment changes + for term in terms: + if isinstance(term, Mul): + term = term.args[-1] # SingularityFunction in the term + singularity.append(term.args[1]) + singularity = list(set(singularity)) + singularity.sort() + + intervals = [] # List of Intervals with discrete value of bending moment + moment_values = [] # List of values of bending moment in each interval + for i, s in enumerate(singularity): + if s == 0: + continue + try: + moment_slope = Piecewise( + (float("nan"), x <= singularity[i - 1]), + (self.shear_force().rewrite(Piecewise), x < s), + (float("nan"), True)) + points = solve(moment_slope, x) + val = [] + for point in points: + val.append(abs(bending_curve.subs(x, point))) + points.extend([singularity[i-1], s]) + val += [abs(limit(bending_curve, x, singularity[i-1], '+')), abs(limit(bending_curve, x, s, '-'))] + max_moment = max(val) + moment_values.append(max_moment) + intervals.append(points[val.index(max_moment)]) + + # If bending moment in a particular Interval has zero or constant + # slope, then above block gives NotImplementedError as solve + # can't represent Interval solutions. + except NotImplementedError: + initial_moment = limit(bending_curve, x, singularity[i-1], '+') + final_moment = limit(bending_curve, x, s, '-') + # If bending_curve has a constant slope(it is a line). + if bending_curve.subs(x, (singularity[i-1] + s)/2) == (initial_moment + final_moment)/2 and initial_moment != final_moment: + moment_values.extend([initial_moment, final_moment]) + intervals.extend([singularity[i-1], s]) + else: # bending_curve has same value in whole Interval + moment_values.append(final_moment) + intervals.append(Interval(singularity[i-1], s)) + + moment_values = list(map(abs, moment_values)) + maximum_moment = max(moment_values) + point = intervals[moment_values.index(maximum_moment)] + return (point, maximum_moment) + + def point_cflexure(self): + """ + Returns a Set of point(s) with zero bending moment and + where bending moment curve of the beam object changes + its sign from negative to positive or vice versa. + + Examples + ======== + There is is 10 meter long overhanging beam. There are + two simple supports below the beam. One at the start + and another one at a distance of 6 meters from the start. + Point loads of magnitude 10KN and 20KN are applied at + 2 meters and 4 meters from start respectively. A Uniformly + distribute load of magnitude of magnitude 3KN/m is also + applied on top starting from 6 meters away from starting + point till end. + Using the sign convention of upward forces and clockwise moment + being positive. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> b = Beam(10, E, I) + >>> b.apply_load(-4, 0, -1) + >>> b.apply_load(-46, 6, -1) + >>> b.apply_load(10, 2, -1) + >>> b.apply_load(20, 4, -1) + >>> b.apply_load(3, 6, 0) + >>> b.point_cflexure() + [10/3] + """ + #Removes the singularity functions of order < 0 from the bending moment equation used in this method + non_singular_bending_moment = sum(arg for arg in self.bending_moment().args if not arg.args[1].args[2] < 0) + + # To restrict the range within length of the Beam + moment_curve = Piecewise((float("nan"), self.variable<=0), + (non_singular_bending_moment, self.variable>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(30, E, I) + >>> b.apply_load(-8, 0, -1) + >>> b.apply_load(R1, 10, -1) + >>> b.apply_load(R2, 30, -1) + >>> b.apply_load(120, 30, -2) + >>> b.bc_deflection = [(10, 0), (30, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.slope() + (-4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) + + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) + 4000/3)/(E*I) + """ + x = self.variable + E = self.elastic_modulus + I = self.second_moment + + if not self._boundary_conditions['slope']: + return diff(self.deflection(), x) + if isinstance(I, Piecewise) and self._joined_beam: + args = I.args + slope = 0 + prev_slope = 0 + prev_end = 0 + for i in range(len(args)): + if i != 0: + prev_end = args[i-1][1].args[1] + slope_value = -S.One/E*integrate(self.bending_moment()/args[i][0], (x, prev_end, x)) + if i != len(args) - 1: + slope += (prev_slope + slope_value)*SingularityFunction(x, prev_end, 0) - \ + (prev_slope + slope_value)*SingularityFunction(x, args[i][1].args[1], 0) + else: + slope += (prev_slope + slope_value)*SingularityFunction(x, prev_end, 0) + prev_slope = slope_value.subs(x, args[i][1].args[1]) + return slope + + C3 = Symbol('C3') + slope_curve = -integrate(S.One/(E*I)*self.bending_moment(), x) + C3 + + bc_eqs = [] + for position, value in self._boundary_conditions['slope']: + eqs = slope_curve.subs(x, position) - value + bc_eqs.append(eqs) + constants = list(linsolve(bc_eqs, C3)) + slope_curve = slope_curve.subs({C3: constants[0][0]}) + return slope_curve + + def deflection(self): + """ + Returns a Singularity Function expression which represents + the elastic curve or deflection of the Beam object. + + Examples + ======== + There is a beam of length 30 meters. A moment of magnitude 120 Nm is + applied in the clockwise direction at the end of the beam. A pointload + of magnitude 8 N is applied from the top of the beam at the starting + point. There are two simple supports below the beam. One at the end + and another one at a distance of 10 meters from the start. The + deflection is restricted at both the supports. + + Using the sign convention of upward forces and clockwise moment + being positive. + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> E, I = symbols('E, I') + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(30, E, I) + >>> b.apply_load(-8, 0, -1) + >>> b.apply_load(R1, 10, -1) + >>> b.apply_load(R2, 30, -1) + >>> b.apply_load(120, 30, -2) + >>> b.bc_deflection = [(10, 0), (30, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.deflection() + (4000*x/3 - 4*SingularityFunction(x, 0, 3)/3 + SingularityFunction(x, 10, 3) + + 60*SingularityFunction(x, 30, 2) + SingularityFunction(x, 30, 3)/3 - 12000)/(E*I) + """ + x = self.variable + E = self.elastic_modulus + I = self.second_moment + if not self._boundary_conditions['deflection'] and not self._boundary_conditions['slope']: + if isinstance(I, Piecewise) and self._joined_beam: + args = I.args + prev_slope = 0 + prev_def = 0 + prev_end = 0 + deflection = 0 + for i in range(len(args)): + if i != 0: + prev_end = args[i-1][1].args[1] + slope_value = -S.One/E*integrate(self.bending_moment()/args[i][0], (x, prev_end, x)) + recent_segment_slope = prev_slope + slope_value + deflection_value = integrate(recent_segment_slope, (x, prev_end, x)) + if i != len(args) - 1: + deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) \ + - (prev_def + deflection_value)*SingularityFunction(x, args[i][1].args[1], 0) + else: + deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) + prev_slope = slope_value.subs(x, args[i][1].args[1]) + prev_def = deflection_value.subs(x, args[i][1].args[1]) + return deflection + base_char = self._base_char + constants = symbols(base_char + '3:5') + return S.One/(E*I)*integrate(-integrate(self.bending_moment(), x), x) + constants[0]*x + constants[1] + elif not self._boundary_conditions['deflection']: + base_char = self._base_char + constant = symbols(base_char + '4') + return integrate(self.slope(), x) + constant + elif not self._boundary_conditions['slope'] and self._boundary_conditions['deflection']: + if isinstance(I, Piecewise) and self._joined_beam: + args = I.args + prev_slope = 0 + prev_def = 0 + prev_end = 0 + deflection = 0 + for i in range(len(args)): + if i != 0: + prev_end = args[i-1][1].args[1] + slope_value = -S.One/E*integrate(self.bending_moment()/args[i][0], (x, prev_end, x)) + recent_segment_slope = prev_slope + slope_value + deflection_value = integrate(recent_segment_slope, (x, prev_end, x)) + if i != len(args) - 1: + deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) \ + - (prev_def + deflection_value)*SingularityFunction(x, args[i][1].args[1], 0) + else: + deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) + prev_slope = slope_value.subs(x, args[i][1].args[1]) + prev_def = deflection_value.subs(x, args[i][1].args[1]) + return deflection + base_char = self._base_char + C3, C4 = symbols(base_char + '3:5') # Integration constants + slope_curve = -integrate(self.bending_moment(), x) + C3 + deflection_curve = integrate(slope_curve, x) + C4 + bc_eqs = [] + for position, value in self._boundary_conditions['deflection']: + eqs = deflection_curve.subs(x, position) - value + bc_eqs.append(eqs) + constants = list(linsolve(bc_eqs, (C3, C4))) + deflection_curve = deflection_curve.subs({C3: constants[0][0], C4: constants[0][1]}) + return S.One/(E*I)*deflection_curve + + if isinstance(I, Piecewise) and self._joined_beam: + args = I.args + prev_slope = 0 + prev_def = 0 + prev_end = 0 + deflection = 0 + for i in range(len(args)): + if i != 0: + prev_end = args[i-1][1].args[1] + slope_value = S.One/E*integrate(self.bending_moment()/args[i][0], (x, prev_end, x)) + recent_segment_slope = prev_slope + slope_value + deflection_value = integrate(recent_segment_slope, (x, prev_end, x)) + if i != len(args) - 1: + deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) \ + - (prev_def + deflection_value)*SingularityFunction(x, args[i][1].args[1], 0) + else: + deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) + prev_slope = slope_value.subs(x, args[i][1].args[1]) + prev_def = deflection_value.subs(x, args[i][1].args[1]) + return deflection + + C4 = Symbol('C4') + deflection_curve = integrate(self.slope(), x) + C4 + + bc_eqs = [] + for position, value in self._boundary_conditions['deflection']: + eqs = deflection_curve.subs(x, position) - value + bc_eqs.append(eqs) + + constants = list(linsolve(bc_eqs, C4)) + deflection_curve = deflection_curve.subs({C4: constants[0][0]}) + return deflection_curve + + def max_deflection(self): + """ + Returns point of max deflection and its corresponding deflection value + in a Beam object. + """ + + # To restrict the range within length of the Beam + slope_curve = Piecewise((float("nan"), self.variable<=0), + (self.slope(), self.variable>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(8, 200*(10**9), 400*(10**-6), 2) + >>> b.apply_load(5000, 2, -1) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(R2, 8, -1) + >>> b.apply_load(10000, 4, 0, end=8) + >>> b.bc_deflection = [(0, 0), (8, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.plot_shear_stress() + Plot object containing: + [0]: cartesian line: 6875*SingularityFunction(x, 0, 0) - 2500*SingularityFunction(x, 2, 0) + - 5000*SingularityFunction(x, 4, 1) + 15625*SingularityFunction(x, 8, 0) + + 5000*SingularityFunction(x, 8, 1) for x over (0.0, 8.0) + """ + + shear_stress = self.shear_stress() + x = self.variable + length = self.length + + if subs is None: + subs = {} + for sym in shear_stress.atoms(Symbol): + if sym != x and sym not in subs: + raise ValueError('value of %s was not passed.' %sym) + + if length in subs: + length = subs[length] + + # Returns Plot of Shear Stress + return plot (shear_stress.subs(subs), (x, 0, length), + title='Shear Stress', xlabel=r'$\mathrm{x}$', ylabel=r'$\tau$', + line_color='r') + + + def plot_shear_force(self, subs=None): + """ + + Returns a plot for Shear force present in the Beam object. + + Parameters + ========== + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + There is a beam of length 8 meters. A constant distributed load of 10 KN/m + is applied from half of the beam till the end. There are two simple supports + below the beam, one at the starting point and another at the ending point + of the beam. A pointload of magnitude 5 KN is also applied from top of the + beam, at a distance of 4 meters from the starting point. + Take E = 200 GPa and I = 400*(10**-6) meter**4. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(8, 200*(10**9), 400*(10**-6)) + >>> b.apply_load(5000, 2, -1) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(R2, 8, -1) + >>> b.apply_load(10000, 4, 0, end=8) + >>> b.bc_deflection = [(0, 0), (8, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.plot_shear_force() + Plot object containing: + [0]: cartesian line: 13750*SingularityFunction(x, 0, 0) - 5000*SingularityFunction(x, 2, 0) + - 10000*SingularityFunction(x, 4, 1) + 31250*SingularityFunction(x, 8, 0) + + 10000*SingularityFunction(x, 8, 1) for x over (0.0, 8.0) + """ + shear_force = self.shear_force() + if subs is None: + subs = {} + for sym in shear_force.atoms(Symbol): + if sym == self.variable: + continue + if sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + return plot(shear_force.subs(subs), (self.variable, 0, length), title='Shear Force', + xlabel=r'$\mathrm{x}$', ylabel=r'$\mathrm{V}$', line_color='g') + + def plot_bending_moment(self, subs=None): + """ + + Returns a plot for Bending moment present in the Beam object. + + Parameters + ========== + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + There is a beam of length 8 meters. A constant distributed load of 10 KN/m + is applied from half of the beam till the end. There are two simple supports + below the beam, one at the starting point and another at the ending point + of the beam. A pointload of magnitude 5 KN is also applied from top of the + beam, at a distance of 4 meters from the starting point. + Take E = 200 GPa and I = 400*(10**-6) meter**4. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(8, 200*(10**9), 400*(10**-6)) + >>> b.apply_load(5000, 2, -1) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(R2, 8, -1) + >>> b.apply_load(10000, 4, 0, end=8) + >>> b.bc_deflection = [(0, 0), (8, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.plot_bending_moment() + Plot object containing: + [0]: cartesian line: 13750*SingularityFunction(x, 0, 1) - 5000*SingularityFunction(x, 2, 1) + - 5000*SingularityFunction(x, 4, 2) + 31250*SingularityFunction(x, 8, 1) + + 5000*SingularityFunction(x, 8, 2) for x over (0.0, 8.0) + """ + bending_moment = self.bending_moment() + if subs is None: + subs = {} + for sym in bending_moment.atoms(Symbol): + if sym == self.variable: + continue + if sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + return plot(bending_moment.subs(subs), (self.variable, 0, length), title='Bending Moment', + xlabel=r'$\mathrm{x}$', ylabel=r'$\mathrm{M}$', line_color='b') + + def plot_slope(self, subs=None): + """ + + Returns a plot for slope of deflection curve of the Beam object. + + Parameters + ========== + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + There is a beam of length 8 meters. A constant distributed load of 10 KN/m + is applied from half of the beam till the end. There are two simple supports + below the beam, one at the starting point and another at the ending point + of the beam. A pointload of magnitude 5 KN is also applied from top of the + beam, at a distance of 4 meters from the starting point. + Take E = 200 GPa and I = 400*(10**-6) meter**4. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(8, 200*(10**9), 400*(10**-6)) + >>> b.apply_load(5000, 2, -1) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(R2, 8, -1) + >>> b.apply_load(10000, 4, 0, end=8) + >>> b.bc_deflection = [(0, 0), (8, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.plot_slope() + Plot object containing: + [0]: cartesian line: -8.59375e-5*SingularityFunction(x, 0, 2) + 3.125e-5*SingularityFunction(x, 2, 2) + + 2.08333333333333e-5*SingularityFunction(x, 4, 3) - 0.0001953125*SingularityFunction(x, 8, 2) + - 2.08333333333333e-5*SingularityFunction(x, 8, 3) + 0.00138541666666667 for x over (0.0, 8.0) + """ + slope = self.slope() + if subs is None: + subs = {} + for sym in slope.atoms(Symbol): + if sym == self.variable: + continue + if sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + return plot(slope.subs(subs), (self.variable, 0, length), title='Slope', + xlabel=r'$\mathrm{x}$', ylabel=r'$\theta$', line_color='m') + + def plot_deflection(self, subs=None): + """ + + Returns a plot for deflection curve of the Beam object. + + Parameters + ========== + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + There is a beam of length 8 meters. A constant distributed load of 10 KN/m + is applied from half of the beam till the end. There are two simple supports + below the beam, one at the starting point and another at the ending point + of the beam. A pointload of magnitude 5 KN is also applied from top of the + beam, at a distance of 4 meters from the starting point. + Take E = 200 GPa and I = 400*(10**-6) meter**4. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(8, 200*(10**9), 400*(10**-6)) + >>> b.apply_load(5000, 2, -1) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(R2, 8, -1) + >>> b.apply_load(10000, 4, 0, end=8) + >>> b.bc_deflection = [(0, 0), (8, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> b.plot_deflection() + Plot object containing: + [0]: cartesian line: 0.00138541666666667*x - 2.86458333333333e-5*SingularityFunction(x, 0, 3) + + 1.04166666666667e-5*SingularityFunction(x, 2, 3) + 5.20833333333333e-6*SingularityFunction(x, 4, 4) + - 6.51041666666667e-5*SingularityFunction(x, 8, 3) - 5.20833333333333e-6*SingularityFunction(x, 8, 4) + for x over (0.0, 8.0) + """ + deflection = self.deflection() + if subs is None: + subs = {} + for sym in deflection.atoms(Symbol): + if sym == self.variable: + continue + if sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + return plot(deflection.subs(subs), (self.variable, 0, length), + title='Deflection', xlabel=r'$\mathrm{x}$', ylabel=r'$\delta$', + line_color='r') + + + def plot_loading_results(self, subs=None): + """ + Returns a subplot of Shear Force, Bending Moment, + Slope and Deflection of the Beam object. + + Parameters + ========== + + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + + There is a beam of length 8 meters. A constant distributed load of 10 KN/m + is applied from half of the beam till the end. There are two simple supports + below the beam, one at the starting point and another at the ending point + of the beam. A pointload of magnitude 5 KN is also applied from top of the + beam, at a distance of 4 meters from the starting point. + Take E = 200 GPa and I = 400*(10**-6) meter**4. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> R1, R2 = symbols('R1, R2') + >>> b = Beam(8, 200*(10**9), 400*(10**-6)) + >>> b.apply_load(5000, 2, -1) + >>> b.apply_load(R1, 0, -1) + >>> b.apply_load(R2, 8, -1) + >>> b.apply_load(10000, 4, 0, end=8) + >>> b.bc_deflection = [(0, 0), (8, 0)] + >>> b.solve_for_reaction_loads(R1, R2) + >>> axes = b.plot_loading_results() + """ + length = self.length + variable = self.variable + if subs is None: + subs = {} + for sym in self.deflection().atoms(Symbol): + if sym == self.variable: + continue + if sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if length in subs: + length = subs[length] + ax1 = plot(self.shear_force().subs(subs), (variable, 0, length), + title="Shear Force", xlabel=r'$\mathrm{x}$', ylabel=r'$\mathrm{V}$', + line_color='g', show=False) + ax2 = plot(self.bending_moment().subs(subs), (variable, 0, length), + title="Bending Moment", xlabel=r'$\mathrm{x}$', ylabel=r'$\mathrm{M}$', + line_color='b', show=False) + ax3 = plot(self.slope().subs(subs), (variable, 0, length), + title="Slope", xlabel=r'$\mathrm{x}$', ylabel=r'$\theta$', + line_color='m', show=False) + ax4 = plot(self.deflection().subs(subs), (variable, 0, length), + title="Deflection", xlabel=r'$\mathrm{x}$', ylabel=r'$\delta$', + line_color='r', show=False) + + return PlotGrid(4, 1, ax1, ax2, ax3, ax4) + + def _solve_for_ild_equations(self, value): + """ + + Helper function for I.L.D. It takes the unsubstituted + copy of the load equation and uses it to calculate shear force and bending + moment equations. + """ + x = self.variable + a = self.ild_variable + load = self._load + value * SingularityFunction(x, a, -1) + shear_force = -integrate(load, x) + bending_moment = integrate(shear_force, x) + + return shear_force, bending_moment + + def solve_for_ild_reactions(self, value, *reactions): + """ + + Determines the Influence Line Diagram equations for reaction + forces under the effect of a moving load. + + Parameters + ========== + value : Integer + Magnitude of moving load + reactions : + The reaction forces applied on the beam. + + Warning + ======= + This method creates equations that can give incorrect results when + substituting a = 0 or a = l, with l the length of the beam. + + Examples + ======== + + There is a beam of length 10 meters. There are two simple supports + below the beam, one at the starting point and another at the ending + point of the beam. Calculate the I.L.D. equations for reaction forces + under the effect of a moving load of magnitude 1kN. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> E, I = symbols('E, I') + >>> R_0, R_10 = symbols('R_0, R_10') + >>> b = Beam(10, E, I) + >>> p0 = b.apply_support(0, 'pin') + >>> p10 = b.apply_support(10, 'roller') + >>> b.solve_for_ild_reactions(1,R_0,R_10) + >>> b.ild_reactions + {R_0: -SingularityFunction(a, 0, 0) + SingularityFunction(a, 0, 1)/10 - SingularityFunction(a, 10, 1)/10, + R_10: -SingularityFunction(a, 0, 1)/10 + SingularityFunction(a, 10, 0) + SingularityFunction(a, 10, 1)/10} + + """ + shear_force, bending_moment = self._solve_for_ild_equations(value) + x = self.variable + l = self.length + a = self.ild_variable + + rotation_jumps = tuple(self._rotation_hinge_symbols) + deflection_jumps = tuple(self._sliding_hinge_symbols) + + C3 = Symbol('C3') + C4 = Symbol('C4') + + shear_curve = limit(shear_force, x, l) - value*(SingularityFunction(a, 0, 0) - SingularityFunction(a, l, 0)) + moment_curve = (limit(bending_moment, x, l) - value * (l * SingularityFunction(a, 0, 0) + - SingularityFunction(a, 0, 1) + + SingularityFunction(a, l, 1))) + + shear_force_eqs = [] + bending_moment_eqs = [] + slope_eqs = [] + deflection_eqs = [] + + for position, val in self._boundary_conditions['shear_force']: + eqs = self.shear_force().subs(x, position) - val + eqs_without_inf = sum(arg for arg in eqs.args if not any(num.is_infinite for num in arg.args)) + shear_sinc = value * (SingularityFunction(- a, - position, 0) - SingularityFunction(-a, 0, 0)) + eqs_with_shear_sinc = eqs_without_inf - shear_sinc + shear_force_eqs.append(eqs_with_shear_sinc) + + for position, val in self._boundary_conditions['bending_moment']: + eqs = self.bending_moment().subs(x, position) - val + eqs_without_inf = sum(arg for arg in eqs.args if not any(num.is_infinite for num in arg.args)) + moment_sinc = value * (position * SingularityFunction(a, 0, 0) + - SingularityFunction(a, 0, 1) + SingularityFunction(a, position, 1)) + eqs_with_moment_sinc = eqs_without_inf - moment_sinc + bending_moment_eqs.append(eqs_with_moment_sinc) + + slope_curve = integrate(bending_moment, x) + C3 + for position, val in self._boundary_conditions['slope']: + eqs = slope_curve.subs(x, position) - val + value * (SingularityFunction(-a, 0, 1) + position * SingularityFunction(-a, 0, 0))**2 / 2 + slope_eqs.append(eqs) + + deflection_curve = integrate(slope_curve, x) + C4 + for position, val in self._boundary_conditions['deflection']: + eqs = deflection_curve.subs(x, position) - val + value * (SingularityFunction(-a, 0, 1) + position * SingularityFunction(-a, 0, 0)) ** 3 / 6 + deflection_eqs.append(eqs) + + solution = list((linsolve([shear_curve, moment_curve] + shear_force_eqs + bending_moment_eqs + slope_eqs + + deflection_eqs, (C3, C4) + reactions + rotation_jumps + deflection_jumps).args)[0]) + + reaction_index = 2 + len(reactions) + rotation_index = reaction_index + len(rotation_jumps) + reaction_solution = solution[2:reaction_index] + rotation_solution = solution[reaction_index:rotation_index] + deflection_solution = solution[rotation_index:] + + self._ild_reactions = dict(zip(reactions, reaction_solution)) + self._ild_rotations_jumps = dict(zip(rotation_jumps, rotation_solution)) + self._ild_deflection_jumps = dict(zip(deflection_jumps, deflection_solution)) + + def plot_ild_reactions(self, subs=None): + """ + + Plots the Influence Line Diagram of Reaction Forces + under the effect of a moving load. This function + should be called after calling solve_for_ild_reactions(). + + Parameters + ========== + + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Warning + ======= + The values for a = 0 and a = l, with l the length of the beam, in + the plot can be incorrect. + + Examples + ======== + + There is a beam of length 10 meters. A point load of magnitude 5KN + is also applied from top of the beam, at a distance of 4 meters + from the starting point. There are two simple supports below the + beam, located at the starting point and at a distance of 7 meters + from the starting point. Plot the I.L.D. equations for reactions + at both support points under the effect of a moving load + of magnitude 1kN. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> E, I = symbols('E, I') + >>> R_0, R_7 = symbols('R_0, R_7') + >>> b = Beam(10, E, I) + >>> p0 = b.apply_support(0, 'roller') + >>> p7 = b.apply_support(7, 'roller') + >>> b.apply_load(5,4,-1) + >>> b.solve_for_ild_reactions(1,R_0,R_7) + >>> b.ild_reactions + {R_0: -SingularityFunction(a, 0, 0) + SingularityFunction(a, 0, 1)/7 + - 3*SingularityFunction(a, 10, 0)/7 - SingularityFunction(a, 10, 1)/7 - 15/7, + R_7: -SingularityFunction(a, 0, 1)/7 + 10*SingularityFunction(a, 10, 0)/7 + SingularityFunction(a, 10, 1)/7 - 20/7} + >>> b.plot_ild_reactions() + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: -SingularityFunction(a, 0, 0) + SingularityFunction(a, 0, 1)/7 + - 3*SingularityFunction(a, 10, 0)/7 - SingularityFunction(a, 10, 1)/7 - 15/7 for a over (0.0, 10.0) + Plot[1]:Plot object containing: + [0]: cartesian line: -SingularityFunction(a, 0, 1)/7 + 10*SingularityFunction(a, 10, 0)/7 + + SingularityFunction(a, 10, 1)/7 - 20/7 for a over (0.0, 10.0) + + """ + if not self._ild_reactions: + raise ValueError("I.L.D. reaction equations not found. Please use solve_for_ild_reactions() to generate the I.L.D. reaction equations.") + + a = self.ild_variable + ildplots = [] + + if subs is None: + subs = {} + + for reaction in self._ild_reactions: + for sym in self._ild_reactions[reaction].atoms(Symbol): + if sym != a and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + + for sym in self._length.atoms(Symbol): + if sym != a and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + + for reaction in self._ild_reactions: + ildplots.append(plot(self._ild_reactions[reaction].subs(subs), + (a, 0, self._length.subs(subs)), title='I.L.D. for Reactions', + xlabel=a, ylabel=reaction, line_color='blue', show=False)) + + return PlotGrid(len(ildplots), 1, *ildplots) + + def solve_for_ild_shear(self, distance, value, *reactions): + """ + + Determines the Influence Line Diagram equations for shear at a + specified point under the effect of a moving load. + + Parameters + ========== + distance : Integer + Distance of the point from the start of the beam + for which equations are to be determined + value : Integer + Magnitude of moving load + reactions : + The reaction forces applied on the beam. + + Warning + ======= + This method creates equations that can give incorrect results when + substituting a = 0 or a = l, with l the length of the beam. + + Examples + ======== + + There is a beam of length 12 meters. There are two simple supports + below the beam, one at the starting point and another at a distance + of 8 meters. Calculate the I.L.D. equations for Shear at a distance + of 4 meters under the effect of a moving load of magnitude 1kN. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> E, I = symbols('E, I') + >>> R_0, R_8 = symbols('R_0, R_8') + >>> b = Beam(12, E, I) + >>> p0 = b.apply_support(0, 'roller') + >>> p8 = b.apply_support(8, 'roller') + >>> b.solve_for_ild_reactions(1, R_0, R_8) + >>> b.solve_for_ild_shear(4, 1, R_0, R_8) + >>> b.ild_shear + -(-SingularityFunction(a, 0, 0) + SingularityFunction(a, 12, 0) + 2)*SingularityFunction(a, 4, 0) + - SingularityFunction(-a, 0, 0) - SingularityFunction(a, 0, 0) + SingularityFunction(a, 0, 1)/8 + + SingularityFunction(a, 12, 0)/2 - SingularityFunction(a, 12, 1)/8 + 1 + + """ + + x = self.variable + l = self.length + a = self.ild_variable + + shear_force, _ = self._solve_for_ild_equations(value) + + shear_curve1 = value - limit(shear_force, x, distance) + shear_curve2 = (limit(shear_force, x, l) - limit(shear_force, x, distance)) - value + + for reaction in reactions: + shear_curve1 = shear_curve1.subs(reaction,self._ild_reactions[reaction]) + shear_curve2 = shear_curve2.subs(reaction,self._ild_reactions[reaction]) + + shear_eq = (shear_curve1 - (shear_curve1 - shear_curve2) * SingularityFunction(a, distance, 0) + - value * SingularityFunction(-a, 0, 0) + value * SingularityFunction(a, l, 0)) + + self._ild_shear = shear_eq + + def plot_ild_shear(self,subs=None): + """ + + Plots the Influence Line Diagram for Shear under the effect + of a moving load. This function should be called after + calling solve_for_ild_shear(). + + Parameters + ========== + + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Warning + ======= + The values for a = 0 and a = l, with l the length of the beam, in + the plot can be incorrect. + + Examples + ======== + + There is a beam of length 12 meters. There are two simple supports + below the beam, one at the starting point and another at a distance + of 8 meters. Plot the I.L.D. for Shear at a distance + of 4 meters under the effect of a moving load of magnitude 1kN. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> E, I = symbols('E, I') + >>> R_0, R_8 = symbols('R_0, R_8') + >>> b = Beam(12, E, I) + >>> p0 = b.apply_support(0, 'roller') + >>> p8 = b.apply_support(8, 'roller') + >>> b.solve_for_ild_reactions(1, R_0, R_8) + >>> b.solve_for_ild_shear(4, 1, R_0, R_8) + >>> b.ild_shear + -(-SingularityFunction(a, 0, 0) + SingularityFunction(a, 12, 0) + 2)*SingularityFunction(a, 4, 0) + - SingularityFunction(-a, 0, 0) - SingularityFunction(a, 0, 0) + SingularityFunction(a, 0, 1)/8 + + SingularityFunction(a, 12, 0)/2 - SingularityFunction(a, 12, 1)/8 + 1 + >>> b.plot_ild_shear() + Plot object containing: + [0]: cartesian line: -(-SingularityFunction(a, 0, 0) + SingularityFunction(a, 12, 0) + 2)*SingularityFunction(a, 4, 0) + - SingularityFunction(-a, 0, 0) - SingularityFunction(a, 0, 0) + SingularityFunction(a, 0, 1)/8 + + SingularityFunction(a, 12, 0)/2 - SingularityFunction(a, 12, 1)/8 + 1 for a over (0.0, 12.0) + + """ + + if not self._ild_shear: + raise ValueError("I.L.D. shear equation not found. Please use solve_for_ild_shear() to generate the I.L.D. shear equations.") + + l = self._length + a = self.ild_variable + + if subs is None: + subs = {} + + for sym in self._ild_shear.atoms(Symbol): + if sym != a and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + + for sym in self._length.atoms(Symbol): + if sym != a and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + + return plot(self._ild_shear.subs(subs), (a, 0, l), title='I.L.D. for Shear', + xlabel=r'$\mathrm{a}$', ylabel=r'$\mathrm{V}$', line_color='blue',show=True) + + def solve_for_ild_moment(self, distance, value, *reactions): + """ + + Determines the Influence Line Diagram equations for moment at a + specified point under the effect of a moving load. + + Parameters + ========== + distance : Integer + Distance of the point from the start of the beam + for which equations are to be determined + value : Integer + Magnitude of moving load + reactions : + The reaction forces applied on the beam. + + Warning + ======= + This method creates equations that can give incorrect results when + substituting a = 0 or a = l, with l the length of the beam. + + Examples + ======== + + There is a beam of length 12 meters. There are two simple supports + below the beam, one at the starting point and another at a distance + of 8 meters. Calculate the I.L.D. equations for Moment at a distance + of 4 meters under the effect of a moving load of magnitude 1kN. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> E, I = symbols('E, I') + >>> R_0, R_8 = symbols('R_0, R_8') + >>> b = Beam(12, E, I) + >>> p0 = b.apply_support(0, 'roller') + >>> p8 = b.apply_support(8, 'roller') + >>> b.solve_for_ild_reactions(1, R_0, R_8) + >>> b.solve_for_ild_moment(4, 1, R_0, R_8) + >>> b.ild_moment + -(4*SingularityFunction(a, 0, 0) - SingularityFunction(a, 0, 1) + SingularityFunction(a, 4, 1))*SingularityFunction(a, 4, 0) + - SingularityFunction(a, 0, 1)/2 + SingularityFunction(a, 4, 1) - 2*SingularityFunction(a, 12, 0) + - SingularityFunction(a, 12, 1)/2 + + """ + + x = self.variable + l = self.length + a = self.ild_variable + + _, moment = self._solve_for_ild_equations(value) + + moment_curve1 = value*(distance * SingularityFunction(a, 0, 0) - SingularityFunction(a, 0, 1) + + SingularityFunction(a, distance, 1)) - limit(moment, x, distance) + moment_curve2 = (limit(moment, x, l)-limit(moment, x, distance) + - value * (l * SingularityFunction(a, 0, 0) - SingularityFunction(a, 0, 1) + + SingularityFunction(a, l, 1))) + + for reaction in reactions: + moment_curve1 = moment_curve1.subs(reaction, self._ild_reactions[reaction]) + moment_curve2 = moment_curve2.subs(reaction, self._ild_reactions[reaction]) + + moment_eq = moment_curve1 - (moment_curve1 - moment_curve2) * SingularityFunction(a, distance, 0) + + self._ild_moment = moment_eq + + def plot_ild_moment(self,subs=None): + """ + + Plots the Influence Line Diagram for Moment under the effect + of a moving load. This function should be called after + calling solve_for_ild_moment(). + + Parameters + ========== + + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Warning + ======= + The values for a = 0 and a = l, with l the length of the beam, in + the plot can be incorrect. + + Examples + ======== + + There is a beam of length 12 meters. There are two simple supports + below the beam, one at the starting point and another at a distance + of 8 meters. Plot the I.L.D. for Moment at a distance + of 4 meters under the effect of a moving load of magnitude 1kN. + + Using the sign convention of downwards forces being positive. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> E, I = symbols('E, I') + >>> R_0, R_8 = symbols('R_0, R_8') + >>> b = Beam(12, E, I) + >>> p0 = b.apply_support(0, 'roller') + >>> p8 = b.apply_support(8, 'roller') + >>> b.solve_for_ild_reactions(1, R_0, R_8) + >>> b.solve_for_ild_moment(4, 1, R_0, R_8) + >>> b.ild_moment + -(4*SingularityFunction(a, 0, 0) - SingularityFunction(a, 0, 1) + SingularityFunction(a, 4, 1))*SingularityFunction(a, 4, 0) + - SingularityFunction(a, 0, 1)/2 + SingularityFunction(a, 4, 1) - 2*SingularityFunction(a, 12, 0) + - SingularityFunction(a, 12, 1)/2 + >>> b.plot_ild_moment() + Plot object containing: + [0]: cartesian line: -(4*SingularityFunction(a, 0, 0) - SingularityFunction(a, 0, 1) + + SingularityFunction(a, 4, 1))*SingularityFunction(a, 4, 0) - SingularityFunction(a, 0, 1)/2 + + SingularityFunction(a, 4, 1) - 2*SingularityFunction(a, 12, 0) - SingularityFunction(a, 12, 1)/2 for a over (0.0, 12.0) + + """ + + if not self._ild_moment: + raise ValueError("I.L.D. moment equation not found. Please use solve_for_ild_moment() to generate the I.L.D. moment equations.") + + a = self.ild_variable + + if subs is None: + subs = {} + + for sym in self._ild_moment.atoms(Symbol): + if sym != a and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + + for sym in self._length.atoms(Symbol): + if sym != a and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + return plot(self._ild_moment.subs(subs), (a, 0, self._length), title='I.L.D. for Moment', + xlabel=r'$\mathrm{a}$', ylabel=r'$\mathrm{M}$', line_color='blue', show=True) + + @doctest_depends_on(modules=('numpy',)) + def draw(self, pictorial=True): + """ + Returns a plot object representing the beam diagram of the beam. + In particular, the diagram might include: + + * the beam. + * vertical black arrows represent point loads and support reaction + forces (the latter if they have been added with the ``apply_load`` + method). + * circular arrows represent moments. + * shaded areas represent distributed loads. + * the support, if ``apply_support`` has been executed. + * if a composite beam has been created with the ``join`` method and + a hinge has been specified, it will be shown with a white disc. + + The diagram shows positive loads on the upper side of the beam, + and negative loads on the lower side. If two or more distributed + loads acts along the same direction over the same region, the + function will add them up together. + + .. note:: + The user must be careful while entering load values. + The draw function assumes a sign convention which is used + for plotting loads. + Given a right handed coordinate system with XYZ coordinates, + the beam's length is assumed to be along the positive X axis. + The draw function recognizes positive loads(with n>-2) as loads + acting along negative Y direction and positive moments acting + along positive Z direction. + + Parameters + ========== + + pictorial: Boolean (default=True) + Setting ``pictorial=True`` would simply create a pictorial (scaled) + view of the beam diagram. On the other hand, ``pictorial=False`` + would create a beam diagram with the exact dimensions on the plot. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam + >>> from sympy import symbols + >>> P1, P2, M = symbols('P1, P2, M') + >>> E, I = symbols('E, I') + >>> b = Beam(50, 20, 30) + >>> b.apply_load(-10, 2, -1) + >>> b.apply_load(15, 26, -1) + >>> b.apply_load(P1, 10, -1) + >>> b.apply_load(-P2, 40, -1) + >>> b.apply_load(90, 5, 0, 23) + >>> b.apply_load(10, 30, 1, 50) + >>> b.apply_load(M, 15, -2) + >>> b.apply_load(-M, 30, -2) + >>> p50 = b.apply_support(50, "pin") + >>> p0, m0 = b.apply_support(0, "fixed") + >>> p20 = b.apply_support(20, "roller") + >>> p = b.draw() # doctest: +SKIP + >>> p # doctest: +ELLIPSIS,+SKIP + Plot object containing: + [0]: cartesian line: 25*SingularityFunction(x, 5, 0) - 25*SingularityFunction(x, 23, 0) + + SingularityFunction(x, 30, 1) - 20*SingularityFunction(x, 50, 0) + - SingularityFunction(x, 50, 1) + 5 for x over (0.0, 50.0) + [1]: cartesian line: 5 for x over (0.0, 50.0) + ... + >>> p.show() # doctest: +SKIP + + """ + if not numpy: + raise ImportError("To use this function numpy module is required") + + loads = list(set(self.applied_loads) - set(self._support_as_loads)) + if (not pictorial) and any((len(l[0].free_symbols) > 0) and (l[2] >= 0) for l in loads): + raise ValueError("`pictorial=False` requires numerical " + "distributed loads. Instead, symbolic loads were found. " + "Cannot continue.") + + x = self.variable + + # checking whether length is an expression in terms of any Symbol. + if isinstance(self.length, Expr): + l = list(self.length.atoms(Symbol)) + # assigning every Symbol a default value of 10 + l = dict.fromkeys(l, 10) + length = self.length.subs(l) + else: + l = {} + length = self.length + height = length/10 + + rectangles = [] + rectangles.append({'xy':(0, 0), 'width':length, 'height': height, 'facecolor':"brown"}) + annotations, markers, load_eq,load_eq1, fill = self._draw_load(pictorial, length, l) + support_markers, support_rectangles = self._draw_supports(length, l) + + rectangles += support_rectangles + markers += support_markers + + for loc in self._applied_rotation_hinges: + ratio = loc / self.length + x_pos = float(ratio) * length + markers += [{'args':[[x_pos], [height / 2]], 'marker':'o', 'markersize':6, 'color':"white"}] + + for loc in self._applied_sliding_hinges: + ratio = loc / self.length + x_pos = float(ratio) * length + markers += [{'args': [[x_pos], [height / 2]], 'marker':'|', 'markersize':12, 'color':"white"}] + + ylim = (-length, 1.25*length) + if fill: + # when distributed loads are presents, they might get clipped out + # in the figure by the ylim settings. + # It might be necessary to compute new limits. + _min = min(min(fill["y2"]), min(r["xy"][1] for r in rectangles)) + _max = max(max(fill["y1"]), max(r["xy"][1] for r in rectangles)) + if (_min < ylim[0]) or (_max > ylim[1]): + offset = abs(_max - _min) * 0.1 + ylim = (_min - offset, _max + offset) + + sing_plot = plot(height + load_eq, height + load_eq1, (x, 0, length), + xlim=(-height, length + height), ylim=ylim, + annotations=annotations, markers=markers, rectangles=rectangles, + line_color='brown', fill=fill, axis=False, show=False) + + return sing_plot + + + def _is_load_negative(self, load): + """Try to determine if a load is negative or positive, using + expansion and doit if necessary. + + Returns + ======= + True: if the load is negative + False: if the load is positive + None: if it is indeterminate + + """ + rv = load.is_negative + if load.is_Atom or rv is not None: + return rv + return load.doit().expand().is_negative + + def _draw_load(self, pictorial, length, l): + loads = list(set(self.applied_loads) - set(self._support_as_loads)) + height = length/10 + x = self.variable + + annotations = [] + markers = [] + load_args = [] + scaled_load = 0 + load_args1 = [] + scaled_load1 = 0 + load_eq = S.Zero # For positive valued higher order loads + load_eq1 = S.Zero # For negative valued higher order loads + fill = None + + # schematic view should use the class convention as much as possible. + # However, users can add expressions as symbolic loads, for example + # P1 - P2: is this load positive or negative? We can't say. + # On these occasions it is better to inform users about the + # indeterminate state of those loads. + warning_head = "Please, note that this schematic view might not be " \ + "in agreement with the sign convention used by the Beam class " \ + "for load-related computations, because it was not possible " \ + "to determine the sign (hence, the direction) of the " \ + "following loads:\n" + warning_body = "" + + for load in loads: + # check if the position of load is in terms of the beam length. + if l: + pos = load[1].subs(l) + else: + pos = load[1] + + # point loads + if load[2] == -1: + iln = self._is_load_negative(load[0]) + if iln is None: + warning_body += "* Point load %s located at %s\n" % (load[0], load[1]) + if iln: + annotations.append({'text':'', 'xy':(pos, 0), 'xytext':(pos, height - 4*height), 'arrowprops':{'width': 1.5, 'headlength': 5, 'headwidth': 5, 'facecolor': 'black'}}) + else: + annotations.append({'text':'', 'xy':(pos, height), 'xytext':(pos, height*4), 'arrowprops':{"width": 1.5, "headlength": 4, "headwidth": 4, "facecolor": 'black'}}) + # moment loads + elif load[2] == -2: + iln = self._is_load_negative(load[0]) + if iln is None: + warning_body += "* Moment %s located at %s\n" % (load[0], load[1]) + if self._is_load_negative(load[0]): + markers.append({'args':[[pos], [height/2]], 'marker': r'$\circlearrowright$', 'markersize':15}) + else: + markers.append({'args':[[pos], [height/2]], 'marker': r'$\circlearrowleft$', 'markersize':15}) + # higher order loads + elif load[2] >= 0: + # `fill` will be assigned only when higher order loads are present + value, start, order, end = load + + iln = self._is_load_negative(value) + if iln is None: + warning_body += "* Distributed load %s from %s to %s\n" % (value, start, end) + + # Positive loads have their separate equations + if not iln: + # if pictorial is True we remake the load equation again with + # some constant magnitude values. + if pictorial: + # remake the load equation again with some constant + # magnitude values. + value = 10**(1-order) if order > 0 else length/2 + scaled_load += value*SingularityFunction(x, start, order) + if end: + f2 = value*x**order if order >= 0 else length/2*x**order + for i in range(0, order + 1): + scaled_load -= (f2.diff(x, i).subs(x, end - start)* + SingularityFunction(x, end, i)/factorial(i)) + + if isinstance(scaled_load, Add): + load_args = scaled_load.args + else: + # when the load equation consists of only a single term + load_args = (scaled_load,) + load_eq = Add(*[i.subs(l) for i in load_args]) + + # For loads with negative value + else: + if pictorial: + # remake the load equation again with some constant + # magnitude values. + value = 10**(1-order) if order > 0 else length/2 + scaled_load1 += abs(value)*SingularityFunction(x, start, order) + if end: + f2 = abs(value)*x**order if order >= 0 else length/2*x**order + for i in range(0, order + 1): + scaled_load1 -= (f2.diff(x, i).subs(x, end - start)* + SingularityFunction(x, end, i)/factorial(i)) + + if isinstance(scaled_load1, Add): + load_args1 = scaled_load1.args + else: + # when the load equation consists of only a single term + load_args1 = (scaled_load1,) + load_eq1 = [i.subs(l) for i in load_args1] + load_eq1 = -Add(*load_eq1) - height + + if len(warning_body) > 0: + warnings.warn(warning_head + warning_body) + + xx = numpy.arange(0, float(length), 0.001) + yy1 = lambdify([x], height + load_eq.rewrite(Piecewise))(xx) + yy2 = lambdify([x], height + load_eq1.rewrite(Piecewise))(xx) + if not isinstance(yy1, numpy.ndarray): + yy1 *= numpy.ones_like(xx) + if not isinstance(yy2, numpy.ndarray): + yy2 *= numpy.ones_like(xx) + fill = {'x': xx, 'y1': yy1, 'y2': yy2, + 'color':'darkkhaki', "zorder": -1} + return annotations, markers, load_eq, load_eq1, fill + + + def _draw_supports(self, length, l): + height = float(length/10) + + support_markers = [] + support_rectangles = [] + for support in self._applied_supports: + if l: + pos = support[0].subs(l) + else: + pos = support[0] + + if support[1] == "pin": + support_markers.append({'args':[pos, [0]], 'marker':6, 'markersize':13, 'color':"black"}) + + elif support[1] == "roller": + support_markers.append({'args':[pos, [-height/2.5]], 'marker':'o', 'markersize':11, 'color':"black"}) + + elif support[1] == "fixed": + if pos == 0: + support_rectangles.append({'xy':(0, -3*height), 'width':-length/20, 'height':6*height + height, 'fill':False, 'hatch':'/////'}) + else: + support_rectangles.append({'xy':(length, -3*height), 'width':length/20, 'height': 6*height + height, 'fill':False, 'hatch':'/////'}) + + return support_markers, support_rectangles + + +class Beam3D(Beam): + """ + This class handles loads applied in any direction of a 3D space along + with unequal values of Second moment along different axes. + + .. note:: + A consistent sign convention must be used while solving a beam + bending problem; the results will + automatically follow the chosen sign convention. + This class assumes that any kind of distributed load/moment is + applied through out the span of a beam. + + Examples + ======== + There is a beam of l meters long. A constant distributed load of magnitude q + is applied along y-axis from start till the end of beam. A constant distributed + moment of magnitude m is also applied along z-axis from start till the end of beam. + Beam is fixed at both of its end. So, deflection of the beam at the both ends + is restricted. + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols, simplify, collect, factor + >>> l, E, G, I, A = symbols('l, E, G, I, A') + >>> b = Beam3D(l, E, G, I, A) + >>> x, q, m = symbols('x, q, m') + >>> b.apply_load(q, 0, 0, dir="y") + >>> b.apply_moment_load(m, 0, -1, dir="z") + >>> b.shear_force() + [0, -q*x, 0] + >>> b.bending_moment() + [0, 0, -m*x + q*x**2/2] + >>> b.bc_slope = [(0, [0, 0, 0]), (l, [0, 0, 0])] + >>> b.bc_deflection = [(0, [0, 0, 0]), (l, [0, 0, 0])] + >>> b.solve_slope_deflection() + >>> factor(b.slope()) + [0, 0, x*(-l + x)*(-A*G*l**3*q + 2*A*G*l**2*q*x - 12*E*I*l*q + - 72*E*I*m + 24*E*I*q*x)/(12*E*I*(A*G*l**2 + 12*E*I))] + >>> dx, dy, dz = b.deflection() + >>> dy = collect(simplify(dy), x) + >>> dx == dz == 0 + True + >>> dy == (x*(12*E*I*l*(A*G*l**2*q - 2*A*G*l*m + 12*E*I*q) + ... + x*(A*G*l*(3*l*(A*G*l**2*q - 2*A*G*l*m + 12*E*I*q) + x*(-2*A*G*l**2*q + 4*A*G*l*m - 24*E*I*q)) + ... + A*G*(A*G*l**2 + 12*E*I)*(-2*l**2*q + 6*l*m - 4*m*x + q*x**2) + ... - 12*E*I*q*(A*G*l**2 + 12*E*I)))/(24*A*E*G*I*(A*G*l**2 + 12*E*I))) + True + + References + ========== + + .. [1] https://homes.civil.aau.dk/jc/FemteSemester/Beams3D.pdf + + """ + + def __init__(self, length, elastic_modulus, shear_modulus, second_moment, + area, variable=Symbol('x')): + """Initializes the class. + + Parameters + ========== + length : Sympifyable + A Symbol or value representing the Beam's length. + elastic_modulus : Sympifyable + A SymPy expression representing the Beam's Modulus of Elasticity. + It is a measure of the stiffness of the Beam material. + shear_modulus : Sympifyable + A SymPy expression representing the Beam's Modulus of rigidity. + It is a measure of rigidity of the Beam material. + second_moment : Sympifyable or list + A list of two elements having SymPy expression representing the + Beam's Second moment of area. First value represent Second moment + across y-axis and second across z-axis. + Single SymPy expression can be passed if both values are same + area : Sympifyable + A SymPy expression representing the Beam's cross-sectional area + in a plane perpendicular to length of the Beam. + variable : Symbol, optional + A Symbol object that will be used as the variable along the beam + while representing the load, shear, moment, slope and deflection + curve. By default, it is set to ``Symbol('x')``. + """ + super().__init__(length, elastic_modulus, second_moment, variable) + self.shear_modulus = shear_modulus + self.area = area + self._load_vector = [0, 0, 0] + self._moment_load_vector = [0, 0, 0] + self._torsion_moment = {} + self._load_Singularity = [0, 0, 0] + self._slope = [0, 0, 0] + self._deflection = [0, 0, 0] + self._angular_deflection = 0 + + @property + def shear_modulus(self): + """Young's Modulus of the Beam. """ + return self._shear_modulus + + @shear_modulus.setter + def shear_modulus(self, e): + self._shear_modulus = sympify(e) + + @property + def second_moment(self): + """Second moment of area of the Beam. """ + return self._second_moment + + @second_moment.setter + def second_moment(self, i): + if isinstance(i, list): + i = [sympify(x) for x in i] + self._second_moment = i + else: + self._second_moment = sympify(i) + + @property + def area(self): + """Cross-sectional area of the Beam. """ + return self._area + + @area.setter + def area(self, a): + self._area = sympify(a) + + @property + def load_vector(self): + """ + Returns a three element list representing the load vector. + """ + return self._load_vector + + @property + def moment_load_vector(self): + """ + Returns a three element list representing moment loads on Beam. + """ + return self._moment_load_vector + + @property + def boundary_conditions(self): + """ + Returns a dictionary of boundary conditions applied on the beam. + The dictionary has two keywords namely slope and deflection. + The value of each keyword is a list of tuple, where each tuple + contains location and value of a boundary condition in the format + (location, value). Further each value is a list corresponding to + slope or deflection(s) values along three axes at that location. + + Examples + ======== + There is a beam of length 4 meters. The slope at 0 should be 4 along + the x-axis and 0 along others. At the other end of beam, deflection + along all the three axes should be zero. + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(30, E, G, I, A, x) + >>> b.bc_slope = [(0, (4, 0, 0))] + >>> b.bc_deflection = [(4, [0, 0, 0])] + >>> b.boundary_conditions + {'bending_moment': [], 'deflection': [(4, [0, 0, 0])], 'shear_force': [], 'slope': [(0, (4, 0, 0))]} + + Here the deflection of the beam should be ``0`` along all the three axes at ``4``. + Similarly, the slope of the beam should be ``4`` along x-axis and ``0`` + along y and z axis at ``0``. + """ + return self._boundary_conditions + + def polar_moment(self): + """ + Returns the polar moment of area of the beam + about the X axis with respect to the centroid. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A = symbols('l, E, G, I, A') + >>> b = Beam3D(l, E, G, I, A) + >>> b.polar_moment() + 2*I + >>> I1 = [9, 15] + >>> b = Beam3D(l, E, G, I1, A) + >>> b.polar_moment() + 24 + """ + if not iterable(self.second_moment): + return 2*self.second_moment + return sum(self.second_moment) + + def apply_load(self, value, start, order, dir="y"): + """ + This method adds up the force load to a particular beam object. + + Parameters + ========== + value : Sympifyable + The magnitude of an applied load. + dir : String + Axis along which load is applied. + order : Integer + The order of the applied load. + - For point loads, order=-1 + - For constant distributed load, order=0 + - For ramp loads, order=1 + - For parabolic ramp loads, order=2 + - ... so on. + """ + x = self.variable + value = sympify(value) + start = sympify(start) + order = sympify(order) + + if dir == "x": + if not order == -1: + self._load_vector[0] += value + self._load_Singularity[0] += value*SingularityFunction(x, start, order) + + elif dir == "y": + if not order == -1: + self._load_vector[1] += value + self._load_Singularity[1] += value*SingularityFunction(x, start, order) + + else: + if not order == -1: + self._load_vector[2] += value + self._load_Singularity[2] += value*SingularityFunction(x, start, order) + + def apply_moment_load(self, value, start, order, dir="y"): + """ + This method adds up the moment loads to a particular beam object. + + Parameters + ========== + value : Sympifyable + The magnitude of an applied moment. + dir : String + Axis along which moment is applied. + order : Integer + The order of the applied load. + - For point moments, order=-2 + - For constant distributed moment, order=-1 + - For ramp moments, order=0 + - For parabolic ramp moments, order=1 + - ... so on. + """ + x = self.variable + value = sympify(value) + start = sympify(start) + order = sympify(order) + + if dir == "x": + if not order == -2: + self._moment_load_vector[0] += value + else: + if start in list(self._torsion_moment): + self._torsion_moment[start] += value + else: + self._torsion_moment[start] = value + self._load_Singularity[0] += value*SingularityFunction(x, start, order) + elif dir == "y": + if not order == -2: + self._moment_load_vector[1] += value + self._load_Singularity[0] += value*SingularityFunction(x, start, order) + else: + if not order == -2: + self._moment_load_vector[2] += value + self._load_Singularity[0] += value*SingularityFunction(x, start, order) + + def apply_support(self, loc, type="fixed"): + if type in ("pin", "roller"): + reaction_load = Symbol('R_'+str(loc)) + self._reaction_loads[reaction_load] = reaction_load + self.bc_deflection.append((loc, [0, 0, 0])) + else: + reaction_load = Symbol('R_'+str(loc)) + reaction_moment = Symbol('M_'+str(loc)) + self._reaction_loads[reaction_load] = [reaction_load, reaction_moment] + self.bc_deflection.append((loc, [0, 0, 0])) + self.bc_slope.append((loc, [0, 0, 0])) + + def solve_for_reaction_loads(self, *reaction): + """ + Solves for the reaction forces. + + Examples + ======== + There is a beam of length 30 meters. It it supported by rollers at + of its end. A constant distributed load of magnitude 8 N is applied + from start till its end along y-axis. Another linear load having + slope equal to 9 is applied along z-axis. + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(30, E, G, I, A, x) + >>> b.apply_load(8, start=0, order=0, dir="y") + >>> b.apply_load(9*x, start=0, order=0, dir="z") + >>> b.bc_deflection = [(0, [0, 0, 0]), (30, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="y") + >>> b.apply_load(R2, start=30, order=-1, dir="y") + >>> b.apply_load(R3, start=0, order=-1, dir="z") + >>> b.apply_load(R4, start=30, order=-1, dir="z") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.reaction_loads + {R1: -120, R2: -120, R3: -1350, R4: -2700} + """ + x = self.variable + l = self.length + q = self._load_Singularity + shear_curves = [integrate(load, x) for load in q] + moment_curves = [integrate(shear, x) for shear in shear_curves] + for i in range(3): + react = [r for r in reaction if (shear_curves[i].has(r) or moment_curves[i].has(r))] + if len(react) == 0: + continue + shear_curve = limit(shear_curves[i], x, l) + moment_curve = limit(moment_curves[i], x, l) + sol = list((linsolve([shear_curve, moment_curve], react).args)[0]) + sol_dict = dict(zip(react, sol)) + reaction_loads = self._reaction_loads + # Check if any of the evaluated reaction exists in another direction + # and if it exists then it should have same value. + for key in sol_dict: + if key in reaction_loads and sol_dict[key] != reaction_loads[key]: + raise ValueError("Ambiguous solution for %s in different directions." % key) + self._reaction_loads.update(sol_dict) + + def shear_force(self): + """ + Returns a list of three expressions which represents the shear force + curve of the Beam object along all three axes. + """ + x = self.variable + q = self._load_vector + return [integrate(-q[0], x), integrate(-q[1], x), integrate(-q[2], x)] + + def axial_force(self): + """ + Returns expression of Axial shear force present inside the Beam object. + """ + return self.shear_force()[0] + + def shear_stress(self): + """ + Returns a list of three expressions which represents the shear stress + curve of the Beam object along all three axes. + """ + return [self.shear_force()[0]/self._area, self.shear_force()[1]/self._area, self.shear_force()[2]/self._area] + + def axial_stress(self): + """ + Returns expression of Axial stress present inside the Beam object. + """ + return self.axial_force()/self._area + + def bending_moment(self): + """ + Returns a list of three expressions which represents the bending moment + curve of the Beam object along all three axes. + """ + x = self.variable + m = self._moment_load_vector + shear = self.shear_force() + + return [integrate(-m[0], x), integrate(-m[1] + shear[2], x), + integrate(-m[2] - shear[1], x) ] + + def torsional_moment(self): + """ + Returns expression of Torsional moment present inside the Beam object. + """ + return self.bending_moment()[0] + + def solve_for_torsion(self): + """ + Solves for the angular deflection due to the torsional effects of + moments being applied in the x-direction i.e. out of or into the beam. + + Here, a positive torque means the direction of the torque is positive + i.e. out of the beam along the beam-axis. Likewise, a negative torque + signifies a torque into the beam cross-section. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, E, G, I, A, x) + >>> b.apply_moment_load(4, 4, -2, dir='x') + >>> b.apply_moment_load(4, 8, -2, dir='x') + >>> b.apply_moment_load(4, 8, -2, dir='x') + >>> b.solve_for_torsion() + >>> b.angular_deflection().subs(x, 3) + 18/(G*I) + """ + x = self.variable + sum_moments = 0 + for point in list(self._torsion_moment): + sum_moments += self._torsion_moment[point] + list(self._torsion_moment).sort() + pointsList = list(self._torsion_moment) + torque_diagram = Piecewise((sum_moments, x<=pointsList[0]), (0, x>=pointsList[0])) + for i in range(len(pointsList))[1:]: + sum_moments -= self._torsion_moment[pointsList[i-1]] + torque_diagram += Piecewise((0, x<=pointsList[i-1]), (sum_moments, x<=pointsList[i]), (0, x>=pointsList[i])) + integrated_torque_diagram = integrate(torque_diagram) + self._angular_deflection = integrated_torque_diagram/(self.shear_modulus*self.polar_moment()) + + def solve_slope_deflection(self): + x = self.variable + l = self.length + E = self.elastic_modulus + G = self.shear_modulus + I = self.second_moment + if isinstance(I, list): + I_y, I_z = I[0], I[1] + else: + I_y = I_z = I + A = self._area + load = self._load_vector + moment = self._moment_load_vector + defl = Function('defl') + theta = Function('theta') + + # Finding deflection along x-axis(and corresponding slope value by differentiating it) + # Equation used: Derivative(E*A*Derivative(def_x(x), x), x) + load_x = 0 + eq = Derivative(E*A*Derivative(defl(x), x), x) + load[0] + def_x = dsolve(Eq(eq, 0), defl(x)).args[1] + # Solving constants originated from dsolve + C1 = Symbol('C1') + C2 = Symbol('C2') + constants = list((linsolve([def_x.subs(x, 0), def_x.subs(x, l)], C1, C2).args)[0]) + def_x = def_x.subs({C1:constants[0], C2:constants[1]}) + slope_x = def_x.diff(x) + self._deflection[0] = def_x + self._slope[0] = slope_x + + # Finding deflection along y-axis and slope across z-axis. System of equation involved: + # 1: Derivative(E*I_z*Derivative(theta_z(x), x), x) + G*A*(Derivative(defl_y(x), x) - theta_z(x)) + moment_z = 0 + # 2: Derivative(G*A*(Derivative(defl_y(x), x) - theta_z(x)), x) + load_y = 0 + C_i = Symbol('C_i') + # Substitute value of `G*A*(Derivative(defl_y(x), x) - theta_z(x))` from (2) in (1) + eq1 = Derivative(E*I_z*Derivative(theta(x), x), x) + (integrate(-load[1], x) + C_i) + moment[2] + slope_z = dsolve(Eq(eq1, 0)).args[1] + + # Solve for constants originated from using dsolve on eq1 + constants = list((linsolve([slope_z.subs(x, 0), slope_z.subs(x, l)], C1, C2).args)[0]) + slope_z = slope_z.subs({C1:constants[0], C2:constants[1]}) + + # Put value of slope obtained back in (2) to solve for `C_i` and find deflection across y-axis + eq2 = G*A*(Derivative(defl(x), x)) + load[1]*x - C_i - G*A*slope_z + def_y = dsolve(Eq(eq2, 0), defl(x)).args[1] + # Solve for constants originated from using dsolve on eq2 + constants = list((linsolve([def_y.subs(x, 0), def_y.subs(x, l)], C1, C_i).args)[0]) + self._deflection[1] = def_y.subs({C1:constants[0], C_i:constants[1]}) + self._slope[2] = slope_z.subs(C_i, constants[1]) + + # Finding deflection along z-axis and slope across y-axis. System of equation involved: + # 1: Derivative(E*I_y*Derivative(theta_y(x), x), x) - G*A*(Derivative(defl_z(x), x) + theta_y(x)) + moment_y = 0 + # 2: Derivative(G*A*(Derivative(defl_z(x), x) + theta_y(x)), x) + load_z = 0 + + # Substitute value of `G*A*(Derivative(defl_y(x), x) + theta_z(x))` from (2) in (1) + eq1 = Derivative(E*I_y*Derivative(theta(x), x), x) + (integrate(load[2], x) - C_i) + moment[1] + slope_y = dsolve(Eq(eq1, 0)).args[1] + # Solve for constants originated from using dsolve on eq1 + constants = list((linsolve([slope_y.subs(x, 0), slope_y.subs(x, l)], C1, C2).args)[0]) + slope_y = slope_y.subs({C1:constants[0], C2:constants[1]}) + + # Put value of slope obtained back in (2) to solve for `C_i` and find deflection across z-axis + eq2 = G*A*(Derivative(defl(x), x)) + load[2]*x - C_i + G*A*slope_y + def_z = dsolve(Eq(eq2,0)).args[1] + # Solve for constants originated from using dsolve on eq2 + constants = list((linsolve([def_z.subs(x, 0), def_z.subs(x, l)], C1, C_i).args)[0]) + self._deflection[2] = def_z.subs({C1:constants[0], C_i:constants[1]}) + self._slope[1] = slope_y.subs(C_i, constants[1]) + + def slope(self): + """ + Returns a three element list representing slope of deflection curve + along all the three axes. + """ + return self._slope + + def deflection(self): + """ + Returns a three element list representing deflection curve along all + the three axes. + """ + return self._deflection + + def angular_deflection(self): + """ + Returns a function in x depicting how the angular deflection, due to moments + in the x-axis on the beam, varies with x. + """ + return self._angular_deflection + + def _plot_shear_force(self, dir, subs=None): + + shear_force = self.shear_force() + + if dir == 'x': + dir_num = 0 + color = 'r' + + elif dir == 'y': + dir_num = 1 + color = 'g' + + elif dir == 'z': + dir_num = 2 + color = 'b' + + if subs is None: + subs = {} + + for sym in shear_force[dir_num].atoms(Symbol): + if sym != self.variable and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + + return plot(shear_force[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Shear Force along %c direction'%dir, + xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{V(%c)}$'%dir, line_color=color) + + def plot_shear_force(self, dir="all", subs=None): + + """ + + Returns a plot for Shear force along all three directions + present in the Beam object. + + Parameters + ========== + dir : string (default : "all") + Direction along which shear force plot is required. + If no direction is specified, all plots are displayed. + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + There is a beam of length 20 meters. It is supported by rollers + at both of its ends. A linear load having slope equal to 12 is applied + along y-axis. A constant distributed load of magnitude 15 N is + applied from start till its end along z-axis. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, E, G, I, A, x) + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.plot_shear_force() + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: 0 for x over (0.0, 20.0) + Plot[1]:Plot object containing: + [0]: cartesian line: -6*x**2 for x over (0.0, 20.0) + Plot[2]:Plot object containing: + [0]: cartesian line: -15*x for x over (0.0, 20.0) + + """ + + dir = dir.lower() + # For shear force along x direction + if dir == "x": + Px = self._plot_shear_force('x', subs) + return Px.show() + # For shear force along y direction + elif dir == "y": + Py = self._plot_shear_force('y', subs) + return Py.show() + # For shear force along z direction + elif dir == "z": + Pz = self._plot_shear_force('z', subs) + return Pz.show() + # For shear force along all direction + else: + Px = self._plot_shear_force('x', subs) + Py = self._plot_shear_force('y', subs) + Pz = self._plot_shear_force('z', subs) + return PlotGrid(3, 1, Px, Py, Pz) + + def _plot_bending_moment(self, dir, subs=None): + + bending_moment = self.bending_moment() + + if dir == 'x': + dir_num = 0 + color = 'g' + + elif dir == 'y': + dir_num = 1 + color = 'c' + + elif dir == 'z': + dir_num = 2 + color = 'm' + + if subs is None: + subs = {} + + for sym in bending_moment[dir_num].atoms(Symbol): + if sym != self.variable and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + + return plot(bending_moment[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Bending Moment along %c direction'%dir, + xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{M(%c)}$'%dir, line_color=color) + + def plot_bending_moment(self, dir="all", subs=None): + + """ + + Returns a plot for bending moment along all three directions + present in the Beam object. + + Parameters + ========== + dir : string (default : "all") + Direction along which bending moment plot is required. + If no direction is specified, all plots are displayed. + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + There is a beam of length 20 meters. It is supported by rollers + at both of its ends. A linear load having slope equal to 12 is applied + along y-axis. A constant distributed load of magnitude 15 N is + applied from start till its end along z-axis. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, E, G, I, A, x) + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.plot_bending_moment() + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: 0 for x over (0.0, 20.0) + Plot[1]:Plot object containing: + [0]: cartesian line: -15*x**2/2 for x over (0.0, 20.0) + Plot[2]:Plot object containing: + [0]: cartesian line: 2*x**3 for x over (0.0, 20.0) + + """ + + dir = dir.lower() + # For bending moment along x direction + if dir == "x": + Px = self._plot_bending_moment('x', subs) + return Px.show() + # For bending moment along y direction + elif dir == "y": + Py = self._plot_bending_moment('y', subs) + return Py.show() + # For bending moment along z direction + elif dir == "z": + Pz = self._plot_bending_moment('z', subs) + return Pz.show() + # For bending moment along all direction + else: + Px = self._plot_bending_moment('x', subs) + Py = self._plot_bending_moment('y', subs) + Pz = self._plot_bending_moment('z', subs) + return PlotGrid(3, 1, Px, Py, Pz) + + def _plot_slope(self, dir, subs=None): + + slope = self.slope() + + if dir == 'x': + dir_num = 0 + color = 'b' + + elif dir == 'y': + dir_num = 1 + color = 'm' + + elif dir == 'z': + dir_num = 2 + color = 'g' + + if subs is None: + subs = {} + + for sym in slope[dir_num].atoms(Symbol): + if sym != self.variable and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + + + return plot(slope[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Slope along %c direction'%dir, + xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{\theta(%c)}$'%dir, line_color=color) + + def plot_slope(self, dir="all", subs=None): + + """ + + Returns a plot for Slope along all three directions + present in the Beam object. + + Parameters + ========== + dir : string (default : "all") + Direction along which Slope plot is required. + If no direction is specified, all plots are displayed. + subs : dictionary + Python dictionary containing Symbols as keys and their + corresponding values. + + Examples + ======== + There is a beam of length 20 meters. It is supported by rollers + at both of its ends. A linear load having slope equal to 12 is applied + along y-axis. A constant distributed load of magnitude 15 N is + applied from start till its end along z-axis. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, 40, 21, 100, 25, x) + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.solve_slope_deflection() + >>> b.plot_slope() + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: 0 for x over (0.0, 20.0) + Plot[1]:Plot object containing: + [0]: cartesian line: -x**3/1600 + 3*x**2/160 - x/8 for x over (0.0, 20.0) + Plot[2]:Plot object containing: + [0]: cartesian line: x**4/8000 - 19*x**2/172 + 52*x/43 for x over (0.0, 20.0) + + """ + + dir = dir.lower() + # For Slope along x direction + if dir == "x": + Px = self._plot_slope('x', subs) + return Px.show() + # For Slope along y direction + elif dir == "y": + Py = self._plot_slope('y', subs) + return Py.show() + # For Slope along z direction + elif dir == "z": + Pz = self._plot_slope('z', subs) + return Pz.show() + # For Slope along all direction + else: + Px = self._plot_slope('x', subs) + Py = self._plot_slope('y', subs) + Pz = self._plot_slope('z', subs) + return PlotGrid(3, 1, Px, Py, Pz) + + def _plot_deflection(self, dir, subs=None): + + deflection = self.deflection() + + if dir == 'x': + dir_num = 0 + color = 'm' + + elif dir == 'y': + dir_num = 1 + color = 'r' + + elif dir == 'z': + dir_num = 2 + color = 'c' + + if subs is None: + subs = {} + + for sym in deflection[dir_num].atoms(Symbol): + if sym != self.variable and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + + return plot(deflection[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Deflection along %c direction'%dir, + xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{\delta(%c)}$'%dir, line_color=color) + + def plot_deflection(self, dir="all", subs=None): + + """ + + Returns a plot for Deflection along all three directions + present in the Beam object. + + Parameters + ========== + dir : string (default : "all") + Direction along which deflection plot is required. + If no direction is specified, all plots are displayed. + subs : dictionary + Python dictionary containing Symbols as keys and their + corresponding values. + + Examples + ======== + There is a beam of length 20 meters. It is supported by rollers + at both of its ends. A linear load having slope equal to 12 is applied + along y-axis. A constant distributed load of magnitude 15 N is + applied from start till its end along z-axis. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, 40, 21, 100, 25, x) + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.solve_slope_deflection() + >>> b.plot_deflection() + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: 0 for x over (0.0, 20.0) + Plot[1]:Plot object containing: + [0]: cartesian line: x**5/40000 - 4013*x**3/90300 + 26*x**2/43 + 1520*x/903 for x over (0.0, 20.0) + Plot[2]:Plot object containing: + [0]: cartesian line: x**4/6400 - x**3/160 + 27*x**2/560 + 2*x/7 for x over (0.0, 20.0) + + + """ + + dir = dir.lower() + # For deflection along x direction + if dir == "x": + Px = self._plot_deflection('x', subs) + return Px.show() + # For deflection along y direction + elif dir == "y": + Py = self._plot_deflection('y', subs) + return Py.show() + # For deflection along z direction + elif dir == "z": + Pz = self._plot_deflection('z', subs) + return Pz.show() + # For deflection along all direction + else: + Px = self._plot_deflection('x', subs) + Py = self._plot_deflection('y', subs) + Pz = self._plot_deflection('z', subs) + return PlotGrid(3, 1, Px, Py, Pz) + + def plot_loading_results(self, dir='x', subs=None): + + """ + + Returns a subplot of Shear Force, Bending Moment, + Slope and Deflection of the Beam object along the direction specified. + + Parameters + ========== + + dir : string (default : "x") + Direction along which plots are required. + If no direction is specified, plots along x-axis are displayed. + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + There is a beam of length 20 meters. It is supported by rollers + at both of its ends. A linear load having slope equal to 12 is applied + along y-axis. A constant distributed load of magnitude 15 N is + applied from start till its end along z-axis. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, E, G, I, A, x) + >>> subs = {E:40, G:21, I:100, A:25} + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.solve_slope_deflection() + >>> b.plot_loading_results('y',subs) + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: -6*x**2 for x over (0.0, 20.0) + Plot[1]:Plot object containing: + [0]: cartesian line: -15*x**2/2 for x over (0.0, 20.0) + Plot[2]:Plot object containing: + [0]: cartesian line: -x**3/1600 + 3*x**2/160 - x/8 for x over (0.0, 20.0) + Plot[3]:Plot object containing: + [0]: cartesian line: x**5/40000 - 4013*x**3/90300 + 26*x**2/43 + 1520*x/903 for x over (0.0, 20.0) + + """ + + dir = dir.lower() + if subs is None: + subs = {} + + ax1 = self._plot_shear_force(dir, subs) + ax2 = self._plot_bending_moment(dir, subs) + ax3 = self._plot_slope(dir, subs) + ax4 = self._plot_deflection(dir, subs) + + return PlotGrid(4, 1, ax1, ax2, ax3, ax4) + + def _plot_shear_stress(self, dir, subs=None): + + shear_stress = self.shear_stress() + + if dir == 'x': + dir_num = 0 + color = 'r' + + elif dir == 'y': + dir_num = 1 + color = 'g' + + elif dir == 'z': + dir_num = 2 + color = 'b' + + if subs is None: + subs = {} + + for sym in shear_stress[dir_num].atoms(Symbol): + if sym != self.variable and sym not in subs: + raise ValueError('Value of %s was not passed.' %sym) + if self.length in subs: + length = subs[self.length] + else: + length = self.length + + return plot(shear_stress[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Shear stress along %c direction'%dir, + xlabel=r'$\mathrm{X}$', ylabel=r'$\tau(%c)$'%dir, line_color=color) + + def plot_shear_stress(self, dir="all", subs=None): + + """ + + Returns a plot for Shear Stress along all three directions + present in the Beam object. + + Parameters + ========== + dir : string (default : "all") + Direction along which shear stress plot is required. + If no direction is specified, all plots are displayed. + subs : dictionary + Python dictionary containing Symbols as key and their + corresponding values. + + Examples + ======== + There is a beam of length 20 meters and area of cross section 2 square + meters. It is supported by rollers at both of its ends. A linear load having + slope equal to 12 is applied along y-axis. A constant distributed load + of magnitude 15 N is applied from start till its end along z-axis. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, E, G, I, 2, x) + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.plot_shear_stress() + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: 0 for x over (0.0, 20.0) + Plot[1]:Plot object containing: + [0]: cartesian line: -3*x**2 for x over (0.0, 20.0) + Plot[2]:Plot object containing: + [0]: cartesian line: -15*x/2 for x over (0.0, 20.0) + + """ + + dir = dir.lower() + # For shear stress along x direction + if dir == "x": + Px = self._plot_shear_stress('x', subs) + return Px.show() + # For shear stress along y direction + elif dir == "y": + Py = self._plot_shear_stress('y', subs) + return Py.show() + # For shear stress along z direction + elif dir == "z": + Pz = self._plot_shear_stress('z', subs) + return Pz.show() + # For shear stress along all direction + else: + Px = self._plot_shear_stress('x', subs) + Py = self._plot_shear_stress('y', subs) + Pz = self._plot_shear_stress('z', subs) + return PlotGrid(3, 1, Px, Py, Pz) + + def _max_shear_force(self, dir): + """ + Helper function for max_shear_force(). + """ + + dir = dir.lower() + + if dir == 'x': + dir_num = 0 + + elif dir == 'y': + dir_num = 1 + + elif dir == 'z': + dir_num = 2 + + if not self.shear_force()[dir_num]: + return (0,0) + # To restrict the range within length of the Beam + load_curve = Piecewise((float("nan"), self.variable<=0), + (self._load_vector[dir_num], self.variable>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, 40, 21, 100, 25, x) + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.max_shear_force() + [(0, 0), (20, 2400), (20, 300)] + """ + + max_shear = [] + max_shear.append(self._max_shear_force('x')) + max_shear.append(self._max_shear_force('y')) + max_shear.append(self._max_shear_force('z')) + return max_shear + + def _max_bending_moment(self, dir): + """ + Helper function for max_bending_moment(). + """ + + dir = dir.lower() + + if dir == 'x': + dir_num = 0 + + elif dir == 'y': + dir_num = 1 + + elif dir == 'z': + dir_num = 2 + + if not self.bending_moment()[dir_num]: + return (0,0) + # To restrict the range within length of the Beam + shear_curve = Piecewise((float("nan"), self.variable<=0), + (self.shear_force()[dir_num], self.variable>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, 40, 21, 100, 25, x) + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.max_bending_moment() + [(0, 0), (20, 3000), (20, 16000)] + """ + + max_bmoment = [] + max_bmoment.append(self._max_bending_moment('x')) + max_bmoment.append(self._max_bending_moment('y')) + max_bmoment.append(self._max_bending_moment('z')) + return max_bmoment + + max_bmoment = max_bending_moment + + def _max_deflection(self, dir): + """ + Helper function for max_Deflection() + """ + + dir = dir.lower() + + if dir == 'x': + dir_num = 0 + + elif dir == 'y': + dir_num = 1 + + elif dir == 'z': + dir_num = 2 + + if not self.deflection()[dir_num]: + return (0,0) + # To restrict the range within length of the Beam + slope_curve = Piecewise((float("nan"), self.variable<=0), + (self.slope()[dir_num], self.variable>> from sympy.physics.continuum_mechanics.beam import Beam3D + >>> from sympy import symbols + >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') + >>> b = Beam3D(20, 40, 21, 100, 25, x) + >>> b.apply_load(15, start=0, order=0, dir="z") + >>> b.apply_load(12*x, start=0, order=0, dir="y") + >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + >>> b.apply_load(R1, start=0, order=-1, dir="z") + >>> b.apply_load(R2, start=20, order=-1, dir="z") + >>> b.apply_load(R3, start=0, order=-1, dir="y") + >>> b.apply_load(R4, start=20, order=-1, dir="y") + >>> b.solve_for_reaction_loads(R1, R2, R3, R4) + >>> b.solve_slope_deflection() + >>> b.max_deflection() + [(0, 0), (10, 495/14), (-10 + 10*sqrt(10793)/43, (10 - 10*sqrt(10793)/43)**3/160 - 20/7 + (10 - 10*sqrt(10793)/43)**4/6400 + 20*sqrt(10793)/301 + 27*(10 - 10*sqrt(10793)/43)**2/560)] + """ + + max_def = [] + max_def.append(self._max_deflection('x')) + max_def.append(self._max_deflection('y')) + max_def.append(self._max_deflection('z')) + return max_def diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/cable.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/cable.py new file mode 100644 index 0000000000000000000000000000000000000000..e38c6601b0a12cad83bc7e87597e79937f4667a4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/cable.py @@ -0,0 +1,815 @@ +""" +This module can be used to solve problems related +to 2D Cables. +""" + +from sympy.core.sympify import sympify +from sympy.core.symbol import Symbol,symbols +from sympy import sin, cos, pi, atan, diff, Piecewise, solve, rad +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.solvers.solveset import linsolve +from sympy.matrices import Matrix +from sympy.plotting import plot + +class Cable: + """ + Cables are structures in engineering that support + the applied transverse loads through the tensile + resistance developed in its members. + + Cables are widely used in suspension bridges, tension + leg offshore platforms, transmission lines, and find + use in several other engineering applications. + + Examples + ======== + A cable is supported at (0, 10) and (10, 10). Two point loads + acting vertically downwards act on the cable, one with magnitude 3 kN + and acting 2 meters from the left support and 3 meters below it, while + the other with magnitude 2 kN is 6 meters from the left support and + 6 meters below it. + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(('A', 0, 10), ('B', 10, 10)) + >>> c.apply_load(-1, ('P', 2, 7, 3, 270)) + >>> c.apply_load(-1, ('Q', 6, 4, 2, 270)) + >>> c.loads + {'distributed': {}, 'point_load': {'P': [3, 270], 'Q': [2, 270]}} + >>> c.loads_position + {'P': [2, 7], 'Q': [6, 4]} + """ + def __init__(self, support_1, support_2): + """ + Initializes the class. + + Parameters + ========== + + support_1 and support_2 are tuples of the form + (label, x, y), where + + label : String or symbol + The label of the support + + x : Sympifyable + The x coordinate of the position of the support + + y : Sympifyable + The y coordinate of the position of the support + """ + self._left_support = [] + self._right_support = [] + self._supports = {} + self._support_labels = [] + self._loads = {"distributed": {}, "point_load": {}} + self._loads_position = {} + self._length = 0 + self._reaction_loads = {} + self._tension = {} + self._lowest_x_global = sympify(0) + self._lowest_y_global = sympify(0) + self._cable_eqn = None + self._tension_func = None + if support_1[0] == support_2[0]: + raise ValueError("Supports can not have the same label") + + elif support_1[1] == support_2[1]: + raise ValueError("Supports can not be at the same location") + + x1 = sympify(support_1[1]) + y1 = sympify(support_1[2]) + self._supports[support_1[0]] = [x1, y1] + + x2 = sympify(support_2[1]) + y2 = sympify(support_2[2]) + self._supports[support_2[0]] = [x2, y2] + + if support_1[1] < support_2[1]: + self._left_support.append(x1) + self._left_support.append(y1) + self._right_support.append(x2) + self._right_support.append(y2) + self._support_labels.append(support_1[0]) + self._support_labels.append(support_2[0]) + + else: + self._left_support.append(x2) + self._left_support.append(y2) + self._right_support.append(x1) + self._right_support.append(y1) + self._support_labels.append(support_2[0]) + self._support_labels.append(support_1[0]) + + for i in self._support_labels: + self._reaction_loads[Symbol("R_"+ i +"_x")] = 0 + self._reaction_loads[Symbol("R_"+ i +"_y")] = 0 + + @property + def supports(self): + """ + Returns the supports of the cable along with their + positions. + """ + return self._supports + + @property + def left_support(self): + """ + Returns the position of the left support. + """ + return self._left_support + + @property + def right_support(self): + """ + Returns the position of the right support. + """ + return self._right_support + + @property + def loads(self): + """ + Returns the magnitude and direction of the loads + acting on the cable. + """ + return self._loads + + @property + def loads_position(self): + """ + Returns the position of the point loads acting on the + cable. + """ + return self._loads_position + + @property + def length(self): + """ + Returns the length of the cable. + """ + return self._length + + @property + def reaction_loads(self): + """ + Returns the reaction forces at the supports, which are + initialized to 0. + """ + return self._reaction_loads + + @property + def tension(self): + """ + Returns the tension developed in the cable due to the loads + applied. + """ + return self._tension + + def tension_at(self, x): + """ + Returns the tension at a given value of x developed due to + distributed load. + """ + if 'distributed' not in self._tension.keys(): + raise ValueError("No distributed load added or solve method not called") + + if x > self._right_support[0] or x < self._left_support[0]: + raise ValueError("The value of x should be between the two supports") + + A = self._tension['distributed'] + X = Symbol('X') + + return A.subs({X:(x-self._lowest_x_global)}) + + def apply_length(self, length): + """ + This method specifies the length of the cable + + Parameters + ========== + + length : Sympifyable + The length of the cable + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(('A', 0, 10), ('B', 10, 10)) + >>> c.apply_length(20) + >>> c.length + 20 + """ + dist = ((self._left_support[0] - self._right_support[0])**2 + - (self._left_support[1] - self._right_support[1])**2)**(1/2) + + if length < dist: + raise ValueError("length should not be less than the distance between the supports") + + self._length = length + + def change_support(self, label, new_support): + """ + This method changes the mentioned support with a new support. + + Parameters + ========== + label: String or symbol + The label of the support to be changed + + new_support: Tuple of the form (new_label, x, y) + new_label: String or symbol + The label of the new support + + x: Sympifyable + The x-coordinate of the position of the new support. + + y: Sympifyable + The y-coordinate of the position of the new support. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(('A', 0, 10), ('B', 10, 10)) + >>> c.supports + {'A': [0, 10], 'B': [10, 10]} + >>> c.change_support('B', ('C', 5, 6)) + >>> c.supports + {'A': [0, 10], 'C': [5, 6]} + """ + if label not in self._supports: + raise ValueError("No support exists with the given label") + + i = self._support_labels.index(label) + rem_label = self._support_labels[(i+1)%2] + x1 = self._supports[rem_label][0] + y1 = self._supports[rem_label][1] + + x = sympify(new_support[1]) + y = sympify(new_support[2]) + + for l in self._loads_position: + if l[0] >= max(x, x1) or l[0] <= min(x, x1): + raise ValueError("The change in support will throw an existing load out of range") + + self._supports.pop(label) + self._left_support.clear() + self._right_support.clear() + self._reaction_loads.clear() + self._support_labels.remove(label) + + self._supports[new_support[0]] = [x, y] + + if x1 < x: + self._left_support.append(x1) + self._left_support.append(y1) + self._right_support.append(x) + self._right_support.append(y) + self._support_labels.append(new_support[0]) + + else: + self._left_support.append(x) + self._left_support.append(y) + self._right_support.append(x1) + self._right_support.append(y1) + self._support_labels.insert(0, new_support[0]) + + for i in self._support_labels: + self._reaction_loads[Symbol("R_"+ i +"_x")] = 0 + self._reaction_loads[Symbol("R_"+ i +"_y")] = 0 + + def apply_load(self, order, load): + """ + This method adds load to the cable. + + Parameters + ========== + + order : Integer + The order of the applied load. + + - For point loads, order = -1 + - For distributed load, order = 0 + + load : tuple + + * For point loads, load is of the form (label, x, y, magnitude, direction), where: + + label : String or symbol + The label of the load + + x : Sympifyable + The x coordinate of the position of the load + + y : Sympifyable + The y coordinate of the position of the load + + magnitude : Sympifyable + The magnitude of the load. It must always be positive + + direction : Sympifyable + The angle, in degrees, that the load vector makes with the horizontal + in the counter-clockwise direction. It takes the values 0 to 360, + inclusive. + + + * For uniformly distributed load, load is of the form (label, magnitude) + + label : String or symbol + The label of the load + + magnitude : Sympifyable + The magnitude of the load. It must always be positive + + Examples + ======== + + For a point load of magnitude 12 units inclined at 30 degrees with the horizontal: + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(('A', 0, 10), ('B', 10, 10)) + >>> c.apply_load(-1, ('Z', 5, 5, 12, 30)) + >>> c.loads + {'distributed': {}, 'point_load': {'Z': [12, 30]}} + >>> c.loads_position + {'Z': [5, 5]} + + + For a uniformly distributed load of magnitude 9 units: + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(('A', 0, 10), ('B', 10, 10)) + >>> c.apply_load(0, ('X', 9)) + >>> c.loads + {'distributed': {'X': 9}, 'point_load': {}} + """ + if order == -1: + if len(self._loads["distributed"]) != 0: + raise ValueError("Distributed load already exists") + + label = load[0] + if label in self._loads["point_load"]: + raise ValueError("Label already exists") + + x = sympify(load[1]) + y = sympify(load[2]) + + if x > self._right_support[0] or x < self._left_support[0]: + raise ValueError("The load should be positioned between the supports") + + magnitude = sympify(load[3]) + direction = sympify(load[4]) + + self._loads["point_load"][label] = [magnitude, direction] + self._loads_position[label] = [x, y] + + elif order == 0: + if len(self._loads_position) != 0: + raise ValueError("Point load(s) already exist") + + label = load[0] + if label in self._loads["distributed"]: + raise ValueError("Label already exists") + + magnitude = sympify(load[1]) + + self._loads["distributed"][label] = magnitude + + else: + raise ValueError("Order should be either -1 or 0") + + def remove_loads(self, *args): + """ + This methods removes the specified loads. + + Parameters + ========== + This input takes multiple label(s) as input + label(s): String or symbol + The label(s) of the loads to be removed. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(('A', 0, 10), ('B', 10, 10)) + >>> c.apply_load(-1, ('Z', 5, 5, 12, 30)) + >>> c.loads + {'distributed': {}, 'point_load': {'Z': [12, 30]}} + >>> c.remove_loads('Z') + >>> c.loads + {'distributed': {}, 'point_load': {}} + """ + for i in args: + if len(self._loads_position) == 0: + if i not in self._loads['distributed']: + raise ValueError("Error removing load " + i + ": no such load exists") + + else: + self._loads['disrtibuted'].pop(i) + + else: + if i not in self._loads['point_load']: + raise ValueError("Error removing load " + i + ": no such load exists") + + else: + self._loads['point_load'].pop(i) + self._loads_position.pop(i) + + def solve(self, *args): + """ + This method solves for the reaction forces at the supports, the tension developed in + the cable, and updates the length of the cable. + + Parameters + ========== + This method requires no input when solving for point loads + For distributed load, the x and y coordinates of the lowest point of the cable are + required as + + x: Sympifyable + The x coordinate of the lowest point + + y: Sympifyable + The y coordinate of the lowest point + + Examples + ======== + For point loads, + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(("A", 0, 10), ("B", 10, 10)) + >>> c.apply_load(-1, ('Z', 2, 7.26, 3, 270)) + >>> c.apply_load(-1, ('X', 4, 6, 8, 270)) + >>> c.solve() + >>> c.tension + {A_Z: 8.91403453669861, X_B: 19*sqrt(13)/10, Z_X: 4.79150773600774} + >>> c.reaction_loads + {R_A_x: -5.25547445255474, R_A_y: 7.2, R_B_x: 5.25547445255474, R_B_y: 3.8} + >>> c.length + 5.7560958484519 + 2*sqrt(13) + + For distributed load, + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c=Cable(("A", 0, 40),("B", 100, 20)) + >>> c.apply_load(0, ("X", 850)) + >>> c.solve(58.58) + >>> c.tension + {'distributed': 36465.0*sqrt(0.00054335718671383*X**2 + 1)} + >>> c.tension_at(0) + 61717.4130533677 + >>> c.reaction_loads + {R_A_x: 36465.0, R_A_y: -49793.0, R_B_x: 44399.9537590861, R_B_y: 42868.2071025955} + """ + + if len(self._loads_position) != 0: + sorted_position = sorted(self._loads_position.items(), key = lambda item : item[1][0]) + + sorted_position.append(self._support_labels[1]) + sorted_position.insert(0, self._support_labels[0]) + + self._tension.clear() + moment_sum_from_left_support = 0 + moment_sum_from_right_support = 0 + F_x = 0 + F_y = 0 + self._length = 0 + tension_func = [] + x = symbols('x') + for i in range(1, len(sorted_position)-1): + if i == 1: + self._length+=sqrt((self._left_support[0] - self._loads_position[sorted_position[i][0]][0])**2 + (self._left_support[1] - self._loads_position[sorted_position[i][0]][1])**2) + + else: + self._length+=sqrt((self._loads_position[sorted_position[i-1][0]][0] - self._loads_position[sorted_position[i][0]][0])**2 + (self._loads_position[sorted_position[i-1][0]][1] - self._loads_position[sorted_position[i][0]][1])**2) + + if i == len(sorted_position)-2: + self._length+=sqrt((self._right_support[0] - self._loads_position[sorted_position[i][0]][0])**2 + (self._right_support[1] - self._loads_position[sorted_position[i][0]][1])**2) + + moment_sum_from_left_support += self._loads['point_load'][sorted_position[i][0]][0] * cos(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) * abs(self._left_support[1] - self._loads_position[sorted_position[i][0]][1]) + moment_sum_from_left_support += self._loads['point_load'][sorted_position[i][0]][0] * sin(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) * abs(self._left_support[0] - self._loads_position[sorted_position[i][0]][0]) + + F_x += self._loads['point_load'][sorted_position[i][0]][0] * cos(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) + F_y += self._loads['point_load'][sorted_position[i][0]][0] * sin(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) + + label = Symbol(sorted_position[i][0]+"_"+sorted_position[i+1][0]) + y2 = self._loads_position[sorted_position[i][0]][1] + x2 = self._loads_position[sorted_position[i][0]][0] + y1 = 0 + x1 = 0 + + if i == len(sorted_position)-2: + x1 = self._right_support[0] + y1 = self._right_support[1] + + else: + x1 = self._loads_position[sorted_position[i+1][0]][0] + y1 = self._loads_position[sorted_position[i+1][0]][1] + + angle_with_horizontal = atan((y1 - y2)/(x1 - x2)) + + tension = -(moment_sum_from_left_support)/(abs(self._left_support[1] - self._loads_position[sorted_position[i][0]][1])*cos(angle_with_horizontal) + abs(self._left_support[0] - self._loads_position[sorted_position[i][0]][0])*sin(angle_with_horizontal)) + self._tension[label] = tension + tension_func.append((tension, x<=x1)) + moment_sum_from_right_support += self._loads['point_load'][sorted_position[i][0]][0] * cos(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) * abs(self._right_support[1] - self._loads_position[sorted_position[i][0]][1]) + moment_sum_from_right_support += self._loads['point_load'][sorted_position[i][0]][0] * sin(pi * self._loads['point_load'][sorted_position[i][0]][1] / 180) * abs(self._right_support[0] - self._loads_position[sorted_position[i][0]][0]) + + label = Symbol(sorted_position[0][0]+"_"+sorted_position[1][0]) + y2 = self._loads_position[sorted_position[1][0]][1] + x2 = self._loads_position[sorted_position[1][0]][0] + x1 = self._left_support[0] + y1 = self._left_support[1] + + angle_with_horizontal = -atan((y2 - y1)/(x2 - x1)) + tension = -(moment_sum_from_right_support)/(abs(self._right_support[1] - self._loads_position[sorted_position[1][0]][1])*cos(angle_with_horizontal) + abs(self._right_support[0] - self._loads_position[sorted_position[1][0]][0])*sin(angle_with_horizontal)) + self._tension[label] = tension + + tension_func.insert(0,(tension, x<=x2)) + self._tension_func = Piecewise(*tension_func) + angle_with_horizontal = pi/2 - angle_with_horizontal + label = self._support_labels[0] + self._reaction_loads[Symbol("R_"+label+"_x")] = -sin(angle_with_horizontal) * tension + F_x += -sin(angle_with_horizontal) * tension + self._reaction_loads[Symbol("R_"+label+"_y")] = cos(angle_with_horizontal) * tension + F_y += cos(angle_with_horizontal) * tension + + label = self._support_labels[1] + self._reaction_loads[Symbol("R_"+label+"_x")] = -F_x + self._reaction_loads[Symbol("R_"+label+"_y")] = -F_y + + elif len(self._loads['distributed']) != 0 : + + if len(args) == 0: + raise ValueError("Provide the lowest point of the cable") + + lowest_x = sympify(args[0]) + self._lowest_x_global = lowest_x + + a = Symbol('a', positive=True) + c = Symbol('c') + # augmented matrix form of linsolve + + M = Matrix( + [[(self._left_support[0]-lowest_x)**2, 1, self._left_support[1]], + [(self._right_support[0]-lowest_x)**2, 1, self._right_support[1]], + ]) + + coefficient_solution = list(linsolve(M, (a, c))) + if len(coefficient_solution) ==0 or coefficient_solution[0][0]== 0: + raise ValueError("The lowest point is inconsistent with the supports") + + A = coefficient_solution[0][0] + C = coefficient_solution[0][1] + coefficient_solution[0][0]*lowest_x**2 + B = -2*coefficient_solution[0][0]*lowest_x + self._lowest_y_global = coefficient_solution[0][1] + lowest_y = self._lowest_y_global + + # y = A*x**2 + B*x + C + # shifting origin to lowest point + X = Symbol('X') + Y = Symbol('Y') + Y = A*(X + lowest_x)**2 + B*(X + lowest_x) + C - lowest_y + + temp_list = list(self._loads['distributed'].values()) + applied_force = temp_list[0] + + horizontal_force_constant = (applied_force * (self._right_support[0] - lowest_x)**2) / (2 * (self._right_support[1] - lowest_y)) + + self._tension.clear() + tangent_slope_to_curve = diff(Y, X) + self._tension['distributed'] = horizontal_force_constant / (cos(atan(tangent_slope_to_curve))) + + label = self._support_labels[0] + self._reaction_loads[Symbol("R_"+label+"_x")] = self.tension_at(self._left_support[0]) * cos(atan(tangent_slope_to_curve.subs(X, self._left_support[0] - lowest_x))) + self._reaction_loads[Symbol("R_"+label+"_y")] = self.tension_at(self._left_support[0]) * sin(atan(tangent_slope_to_curve.subs(X, self._left_support[0] - lowest_x))) + + label = self._support_labels[1] + self._reaction_loads[Symbol("R_"+label+"_x")] = self.tension_at(self._left_support[0]) * cos(atan(tangent_slope_to_curve.subs(X, self._right_support[0] - lowest_x))) + self._reaction_loads[Symbol("R_"+label+"_y")] = self.tension_at(self._left_support[0]) * sin(atan(tangent_slope_to_curve.subs(X, self._right_support[0] - lowest_x))) + + def draw(self): + """ + This method is used to obtain a plot for the specified cable with its supports, + shape and loads. + + Examples + ======== + + For point loads, + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(("A", 0, 10), ("B", 10, 10)) + >>> c.apply_load(-1, ('Z', 2, 7.26, 3, 270)) + >>> c.apply_load(-1, ('X', 4, 6, 8, 270)) + >>> c.solve() + >>> p = c.draw() + >>> p # doctest: +ELLIPSIS + Plot object containing: + [0]: cartesian line: Piecewise((10 - 1.37*x, x <= 2), (8.52 - 0.63*x, x <= 4), (2*x/3 + 10/3, x <= 10)) for x over (0.0, 10.0) + ... + >>> p.show() + + For uniformly distributed loads, + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c=Cable(("A", 0, 40),("B", 100, 20)) + >>> c.apply_load(0, ("X", 850)) + >>> c.solve(58.58) + >>> p = c.draw() + >>> p # doctest: +ELLIPSIS + Plot object containing: + [0]: cartesian line: 0.0116550116550117*(x - 58.58)**2 + 0.00447086247086247 for x over (0.0, 100.0) + [1]: cartesian line: -7.49552913752915 for x over (0.0, 100.0) + ... + >>> p.show() + """ + x = Symbol("x") + annotations = [] + support_rectangles = self._draw_supports() + + xy_min = min(self._left_support[0],self._lowest_y_global) + xy_max = max(self._right_support[0], max(self._right_support[1],self._left_support[1])) + max_diff = xy_max - xy_min + if len(self._loads_position) != 0: + self._cable_eqn = self._draw_cable(-1) + annotations += self._draw_loads(-1) + + elif len(self._loads['distributed']) != 0 : + self._cable_eqn = self._draw_cable(0) + annotations += self._draw_loads(0) + + if not self._cable_eqn: + raise ValueError("solve method not called and/or values provided for loads and supports not adequate") + + cab_plot = plot(*self._cable_eqn,(x,self._left_support[0],self._right_support[0]), + xlim=(xy_min-0.5*max_diff,xy_max+0.5*max_diff), + ylim=(xy_min-0.5*max_diff,xy_max+0.5*max_diff), + rectangles=support_rectangles,show= False,annotations=annotations, axis=False) + + return cab_plot + + def _draw_supports(self): + member_rectangles = [] + xy_min = min(self._left_support[0],self._lowest_y_global) + xy_max = max(self._right_support[0], max(self._right_support[1],self._left_support[1])) + max_diff = xy_max - xy_min + + supp_width = 0.075*max_diff + + member_rectangles.append( + { + 'xy': (self._left_support[0]-supp_width,self._left_support[1]), + 'width': supp_width, + 'height':supp_width, + 'color':'brown', + 'fill': False + } + ) + + member_rectangles.append( + { + 'xy': (self._right_support[0],self._right_support[1]), + 'width': supp_width, + 'height':supp_width, + 'color':'brown', + 'fill': False + } + ) + + return member_rectangles + + def _draw_cable(self,order): + xy_min = min(self._left_support[0],self._lowest_y_global) + xy_max = max(self._right_support[0], max(self._right_support[1],self._left_support[1])) + max_diff = xy_max - xy_min + if order == -1 : + x,y = symbols('x y') + line_func = [] + sorted_position = sorted(self._loads_position.items(), key = lambda item : item[1][0]) + + for i in range(len(sorted_position)): + if(i==0): + y = ((sorted_position[i][1][1] - self._left_support[1])*(x-self._left_support[0]))/(sorted_position[i][1][0]- self._left_support[0]) + self._left_support[1] + else: + y = ((sorted_position[i][1][1] - sorted_position[i-1][1][1] )*(x-sorted_position[i-1][1][0]))/(sorted_position[i][1][0]- sorted_position[i-1][1][0]) + sorted_position[i-1][1][1] + line_func.append((y,x<=sorted_position[i][1][0])) + + y = ((sorted_position[len(sorted_position)-1][1][1] - self._right_support[1])*(x-self._right_support[0]))/(sorted_position[i][1][0]- self._right_support[0]) + self._right_support[1] + line_func.append((y,x<=self._right_support[0])) + return [Piecewise(*line_func)] + + elif order == 0: + x0 = self._lowest_x_global + diff_force_height = max_diff*0.075 + + a,c,x,y = symbols('a c x y') + parabola_eqn = a*(x-x0)**2 + c - y + + points = [(self._left_support[0],self._left_support[1]),(self._right_support[0],self._right_support[1])] + equations = [] + for px, py in points: + equations.append(parabola_eqn.subs({x: px, y: py})) + solution = solve(equations, (a, c)) + parabola_eqn = solution[a]*(x-x0)**2 + solution[c] + return [parabola_eqn, self._lowest_y_global - diff_force_height] + + def _draw_loads(self,order): + xy_min = min(self._left_support[0],self._lowest_y_global) + xy_max = max(self._right_support[0], max(self._right_support[1],self._left_support[1])) + max_diff = xy_max - xy_min + if(order==-1): + arrow_length = max_diff*0.1 + force_arrows = [] + for key in self._loads['point_load']: + force_arrows.append( + { + 'text': '', + 'xy':(self._loads_position[key][0]+arrow_length*cos(rad(self._loads['point_load'][key][1])),\ + self._loads_position[key][1] + arrow_length*sin(rad(self._loads['point_load'][key][1]))), + 'xytext': (self._loads_position[key][0],self._loads_position[key][1]), + 'arrowprops': {'width': 1, 'headlength':3, 'headwidth':3 , 'facecolor': 'black', } + } + ) + mag = self._loads['point_load'][key][0] + force_arrows.append( + { + 'text':f'{mag}N', + 'xy': (self._loads_position[key][0]+arrow_length*1.6*cos(rad(self._loads['point_load'][key][1])),\ + self._loads_position[key][1] + arrow_length*1.6*sin(rad(self._loads['point_load'][key][1]))), + } + ) + return force_arrows + + elif (order == 0): + x = symbols('x') + force_arrows = [] + x_val = [self._left_support[0] + ((self._right_support[0]-self._left_support[0])/10)*i for i in range(1,10)] + for i in x_val: + force_arrows.append( + { + 'text':'', + 'xytext':( + i, + self._cable_eqn[0].subs(x,i) + ), + 'xy':( + i, + self._cable_eqn[1].subs(x,i) + ), + 'arrowprops':{'width':1, 'headlength':3.5, 'headwidth':3.5, 'facecolor':'black'} + } + ) + mag = 0 + for key in self._loads['distributed']: + mag += self._loads['distributed'][key] + + force_arrows.append( + { + 'text':f'{mag} N/m', + 'xy':((self._left_support[0]+self._right_support[0])/2,self._lowest_y_global - max_diff*0.15) + } + ) + return force_arrows + + def plot_tension(self): + """ + Returns the diagram/plot of the tension generated in the cable at various points. + + Examples + ======== + + For point loads, + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c = Cable(("A", 0, 10), ("B", 10, 10)) + >>> c.apply_load(-1, ('Z', 2, 7.26, 3, 270)) + >>> c.apply_load(-1, ('X', 4, 6, 8, 270)) + >>> c.solve() + >>> p = c.plot_tension() + >>> p + Plot object containing: + [0]: cartesian line: Piecewise((8.91403453669861, x <= 2), (4.79150773600774, x <= 4), (19*sqrt(13)/10, x <= 10)) for x over (0.0, 10.0) + >>> p.show() + + For uniformly distributed loads, + + >>> from sympy.physics.continuum_mechanics.cable import Cable + >>> c=Cable(("A", 0, 40),("B", 100, 20)) + >>> c.apply_load(0, ("X", 850)) + >>> c.solve(58.58) + >>> p = c.plot_tension() + >>> p + Plot object containing: + [0]: cartesian line: 36465.0*sqrt(0.00054335718671383*X**2 + 1) for X over (0.0, 100.0) + >>> p.show() + + """ + if len(self._loads_position) != 0: + x = symbols('x') + tension_plot = plot(self._tension_func, (x,self._left_support[0],self._right_support[0]), show=False) + else: + X = symbols('X') + tension_plot = plot(self._tension['distributed'], (X,self._left_support[0],self._right_support[0]), show=False) + return tension_plot diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/truss.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/truss.py new file mode 100644 index 0000000000000000000000000000000000000000..f7fd0ea3f5e18574f21e2f656477c7af987d8eb6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/truss.py @@ -0,0 +1,1108 @@ +""" +This module can be used to solve problems related +to 2D Trusses. +""" + + +from cmath import atan, inf +from sympy.core.add import Add +from sympy.core.evalf import INF +from sympy.core.mul import Mul +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy import Matrix, pi +from sympy.external.importtools import import_module +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import zeros +import math +from sympy.physics.units.quantities import Quantity +from sympy.plotting import plot +from sympy.utilities.decorator import doctest_depends_on +from sympy import sin, cos + + +__doctest_requires__ = {('Truss.draw'): ['matplotlib']} + + +numpy = import_module('numpy', import_kwargs={'fromlist':['arange']}) + + +class Truss: + """ + A Truss is an assembly of members such as beams, + connected by nodes, that create a rigid structure. + In engineering, a truss is a structure that + consists of two-force members only. + + Trusses are extremely important in engineering applications + and can be seen in numerous real-world applications like bridges. + + Examples + ======== + + There is a Truss consisting of four nodes and five + members connecting the nodes. A force P acts + downward on the node D and there also exist pinned + and roller joints on the nodes A and B respectively. + + .. image:: truss_example.png + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(("node_1", 0, 0), ("node_2", 6, 0), ("node_3", 2, 2), ("node_4", 2, 0)) + >>> t.add_member(("member_1", "node_1", "node_4"), ("member_2", "node_2", "node_4"), ("member_3", "node_1", "node_3")) + >>> t.add_member(("member_4", "node_2", "node_3"), ("member_5", "node_3", "node_4")) + >>> t.apply_load(("node_4", 10, 270)) + >>> t.apply_support(("node_1", "pinned"), ("node_2", "roller")) + """ + + def __init__(self): + """ + Initializes the class + """ + self._nodes = [] + self._members = {} + self._loads = {} + self._supports = {} + self._node_labels = [] + self._node_positions = [] + self._node_position_x = [] + self._node_position_y = [] + self._nodes_occupied = {} + self._member_lengths = {} + self._reaction_loads = {} + self._internal_forces = {} + self._node_coordinates = {} + + @property + def nodes(self): + """ + Returns the nodes of the truss along with their positions. + """ + return self._nodes + + @property + def node_labels(self): + """ + Returns the node labels of the truss. + """ + return self._node_labels + + @property + def node_positions(self): + """ + Returns the positions of the nodes of the truss. + """ + return self._node_positions + + @property + def members(self): + """ + Returns the members of the truss along with the start and end points. + """ + return self._members + + @property + def member_lengths(self): + """ + Returns the length of each member of the truss. + """ + return self._member_lengths + + @property + def supports(self): + """ + Returns the nodes with provided supports along with the kind of support provided i.e. + pinned or roller. + """ + return self._supports + + @property + def loads(self): + """ + Returns the loads acting on the truss. + """ + return self._loads + + @property + def reaction_loads(self): + """ + Returns the reaction forces for all supports which are all initialized to 0. + """ + return self._reaction_loads + + @property + def internal_forces(self): + """ + Returns the internal forces for all members which are all initialized to 0. + """ + return self._internal_forces + + def add_node(self, *args): + """ + This method adds a node to the truss along with its name/label and its location. + Multiple nodes can be added at the same time. + + Parameters + ========== + The input(s) for this method are tuples of the form (label, x, y). + + label: String or a Symbol + The label for a node. It is the only way to identify a particular node. + + x: Sympifyable + The x-coordinate of the position of the node. + + y: Sympifyable + The y-coordinate of the position of the node. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(('A', 0, 0)) + >>> t.nodes + [('A', 0, 0)] + >>> t.add_node(('B', 3, 0), ('C', 4, 1)) + >>> t.nodes + [('A', 0, 0), ('B', 3, 0), ('C', 4, 1)] + """ + + for i in args: + label = i[0] + x = i[1] + x = sympify(x) + y=i[2] + y = sympify(y) + if label in self._node_coordinates: + raise ValueError("Node needs to have a unique label") + + elif [x, y] in self._node_coordinates.values(): + raise ValueError("A node already exists at the given position") + + else : + self._nodes.append((label, x, y)) + self._node_labels.append(label) + self._node_positions.append((x, y)) + self._node_position_x.append(x) + self._node_position_y.append(y) + self._node_coordinates[label] = [x, y] + + + + def remove_node(self, *args): + """ + This method removes a node from the truss. + Multiple nodes can be removed at the same time. + + Parameters + ========== + The input(s) for this method are the labels of the nodes to be removed. + + label: String or Symbol + The label of the node to be removed. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0), ('C', 5, 0)) + >>> t.nodes + [('A', 0, 0), ('B', 3, 0), ('C', 5, 0)] + >>> t.remove_node('A', 'C') + >>> t.nodes + [('B', 3, 0)] + """ + for label in args: + for i in range(len(self.nodes)): + if self._node_labels[i] == label: + x = self._node_position_x[i] + y = self._node_position_y[i] + + if label not in self._node_coordinates: + raise ValueError("No such node exists in the truss") + + else: + members_duplicate = self._members.copy() + for member in members_duplicate: + if label == self._members[member][0] or label == self._members[member][1]: + raise ValueError("The given node already has member attached to it") + self._nodes.remove((label, x, y)) + self._node_labels.remove(label) + self._node_positions.remove((x, y)) + self._node_position_x.remove(x) + self._node_position_y.remove(y) + if label in self._loads: + self._loads.pop(label) + if label in self._supports: + self._supports.pop(label) + self._node_coordinates.pop(label) + + + + def add_member(self, *args): + """ + This method adds a member between any two nodes in the given truss. + + Parameters + ========== + The input(s) of the method are tuple(s) of the form (label, start, end). + + label: String or Symbol + The label for a member. It is the only way to identify a particular member. + + start: String or Symbol + The label of the starting point/node of the member. + + end: String or Symbol + The label of the ending point/node of the member. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0), ('C', 2, 2)) + >>> t.add_member(('AB', 'A', 'B'), ('BC', 'B', 'C')) + >>> t.members + {'AB': ['A', 'B'], 'BC': ['B', 'C']} + """ + for i in args: + label = i[0] + start = i[1] + end = i[2] + + if start not in self._node_coordinates or end not in self._node_coordinates or start==end: + raise ValueError("The start and end points of the member must be unique nodes") + + elif label in self._members: + raise ValueError("A member with the same label already exists for the truss") + + elif self._nodes_occupied.get((start, end)): + raise ValueError("A member already exists between the two nodes") + + else: + self._members[label] = [start, end] + self._member_lengths[label] = sqrt((self._node_coordinates[end][0]-self._node_coordinates[start][0])**2 + (self._node_coordinates[end][1]-self._node_coordinates[start][1])**2) + self._nodes_occupied[start, end] = True + self._nodes_occupied[end, start] = True + self._internal_forces[label] = 0 + + def remove_member(self, *args): + """ + This method removes members from the given truss. + + Parameters + ========== + labels: String or Symbol + The label for the member to be removed. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0), ('C', 2, 2)) + >>> t.add_member(('AB', 'A', 'B'), ('AC', 'A', 'C'), ('BC', 'B', 'C')) + >>> t.members + {'AB': ['A', 'B'], 'AC': ['A', 'C'], 'BC': ['B', 'C']} + >>> t.remove_member('AC', 'BC') + >>> t.members + {'AB': ['A', 'B']} + """ + for label in args: + if label not in self._members: + raise ValueError("No such member exists in the Truss") + + else: + self._nodes_occupied.pop((self._members[label][0], self._members[label][1])) + self._nodes_occupied.pop((self._members[label][1], self._members[label][0])) + self._members.pop(label) + self._member_lengths.pop(label) + self._internal_forces.pop(label) + + def change_node_label(self, *args): + """ + This method changes the label(s) of the specified node(s). + + Parameters + ========== + The input(s) of this method are tuple(s) of the form (label, new_label). + + label: String or Symbol + The label of the node for which the label has + to be changed. + + new_label: String or Symbol + The new label of the node. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0)) + >>> t.nodes + [('A', 0, 0), ('B', 3, 0)] + >>> t.change_node_label(('A', 'C'), ('B', 'D')) + >>> t.nodes + [('C', 0, 0), ('D', 3, 0)] + """ + for i in args: + label = i[0] + new_label = i[1] + if label not in self._node_coordinates: + raise ValueError("No such node exists for the Truss") + elif new_label in self._node_coordinates: + raise ValueError("A node with the given label already exists") + else: + for node in self._nodes: + if node[0] == label: + self._nodes[self._nodes.index((label, node[1], node[2]))] = (new_label, node[1], node[2]) + self._node_labels[self._node_labels.index(node[0])] = new_label + self._node_coordinates[new_label] = self._node_coordinates[label] + self._node_coordinates.pop(label) + if node[0] in self._supports: + self._supports[new_label] = self._supports[node[0]] + self._supports.pop(node[0]) + if new_label in self._supports: + if self._supports[new_label] == 'pinned': + if 'R_'+str(label)+'_x' in self._reaction_loads and 'R_'+str(label)+'_y' in self._reaction_loads: + self._reaction_loads['R_'+str(new_label)+'_x'] = self._reaction_loads['R_'+str(label)+'_x'] + self._reaction_loads['R_'+str(new_label)+'_y'] = self._reaction_loads['R_'+str(label)+'_y'] + self._reaction_loads.pop('R_'+str(label)+'_x') + self._reaction_loads.pop('R_'+str(label)+'_y') + self._loads[new_label] = self._loads[label] + for load in self._loads[new_label]: + if load[1] == 90: + load[0] -= Symbol('R_'+str(label)+'_y') + if load[0] == 0: + self._loads[label].remove(load) + break + for load in self._loads[new_label]: + if load[1] == 0: + load[0] -= Symbol('R_'+str(label)+'_x') + if load[0] == 0: + self._loads[label].remove(load) + break + self.apply_load(new_label, Symbol('R_'+str(new_label)+'_x'), 0) + self.apply_load(new_label, Symbol('R_'+str(new_label)+'_y'), 90) + self._loads.pop(label) + elif self._supports[new_label] == 'roller': + self._loads[new_label] = self._loads[label] + for load in self._loads[label]: + if load[1] == 90: + load[0] -= Symbol('R_'+str(label)+'_y') + if load[0] == 0: + self._loads[label].remove(load) + break + self.apply_load(new_label, Symbol('R_'+str(new_label)+'_y'), 90) + self._loads.pop(label) + else: + if label in self._loads: + self._loads[new_label] = self._loads[label] + self._loads.pop(label) + for member in self._members: + if self._members[member][0] == node[0]: + self._members[member][0] = new_label + self._nodes_occupied[(new_label, self._members[member][1])] = True + self._nodes_occupied[(self._members[member][1], new_label)] = True + self._nodes_occupied.pop((label, self._members[member][1])) + self._nodes_occupied.pop((self._members[member][1], label)) + elif self._members[member][1] == node[0]: + self._members[member][1] = new_label + self._nodes_occupied[(self._members[member][0], new_label)] = True + self._nodes_occupied[(new_label, self._members[member][0])] = True + self._nodes_occupied.pop((self._members[member][0], label)) + self._nodes_occupied.pop((label, self._members[member][0])) + + def change_member_label(self, *args): + """ + This method changes the label(s) of the specified member(s). + + Parameters + ========== + The input(s) of this method are tuple(s) of the form (label, new_label) + + label: String or Symbol + The label of the member for which the label has + to be changed. + + new_label: String or Symbol + The new label of the member. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0), ('D', 5, 0)) + >>> t.nodes + [('A', 0, 0), ('B', 3, 0), ('D', 5, 0)] + >>> t.change_node_label(('A', 'C')) + >>> t.nodes + [('C', 0, 0), ('B', 3, 0), ('D', 5, 0)] + >>> t.add_member(('BC', 'B', 'C'), ('BD', 'B', 'D')) + >>> t.members + {'BC': ['B', 'C'], 'BD': ['B', 'D']} + >>> t.change_member_label(('BC', 'BC_new'), ('BD', 'BD_new')) + >>> t.members + {'BC_new': ['B', 'C'], 'BD_new': ['B', 'D']} + """ + for i in args: + label = i[0] + new_label = i[1] + if label not in self._members: + raise ValueError("No such member exists for the Truss") + else: + members_duplicate = list(self._members).copy() + for member in members_duplicate: + if member == label: + self._members[new_label] = [self._members[member][0], self._members[member][1]] + self._members.pop(label) + self._member_lengths[new_label] = self._member_lengths[label] + self._member_lengths.pop(label) + self._internal_forces[new_label] = self._internal_forces[label] + self._internal_forces.pop(label) + + def apply_load(self, *args): + """ + This method applies external load(s) at the specified node(s). + + Parameters + ========== + The input(s) of the method are tuple(s) of the form (location, magnitude, direction). + + location: String or Symbol + Label of the Node at which load is applied. + + magnitude: Sympifyable + Magnitude of the load applied. It must always be positive and any changes in + the direction of the load are not reflected here. + + direction: Sympifyable + The angle, in degrees, that the load vector makes with the horizontal + in the counter-clockwise direction. It takes the values 0 to 360, + inclusive. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> from sympy import symbols + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0)) + >>> P = symbols('P') + >>> t.apply_load(('A', P, 90), ('A', P/2, 45), ('A', P/4, 90)) + >>> t.loads + {'A': [[P, 90], [P/2, 45], [P/4, 90]]} + """ + for i in args: + location = i[0] + magnitude = i[1] + direction = i[2] + magnitude = sympify(magnitude) + direction = sympify(direction) + + if location not in self._node_coordinates: + raise ValueError("Load must be applied at a known node") + + else: + if location in self._loads: + self._loads[location].append([magnitude, direction]) + else: + self._loads[location] = [[magnitude, direction]] + + def remove_load(self, *args): + """ + This method removes already + present external load(s) at specified node(s). + + Parameters + ========== + The input(s) of this method are tuple(s) of the form (location, magnitude, direction). + + location: String or Symbol + Label of the Node at which load is applied and is to be removed. + + magnitude: Sympifyable + Magnitude of the load applied. + + direction: Sympifyable + The angle, in degrees, that the load vector makes with the horizontal + in the counter-clockwise direction. It takes the values 0 to 360, + inclusive. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> from sympy import symbols + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0)) + >>> P = symbols('P') + >>> t.apply_load(('A', P, 90), ('A', P/2, 45), ('A', P/4, 90)) + >>> t.loads + {'A': [[P, 90], [P/2, 45], [P/4, 90]]} + >>> t.remove_load(('A', P/4, 90), ('A', P/2, 45)) + >>> t.loads + {'A': [[P, 90]]} + """ + for i in args: + location = i[0] + magnitude = i[1] + direction = i[2] + magnitude = sympify(magnitude) + direction = sympify(direction) + + if location not in self._node_coordinates: + raise ValueError("Load must be removed from a known node") + + else: + if [magnitude, direction] not in self._loads[location]: + raise ValueError("No load of this magnitude and direction has been applied at this node") + else: + self._loads[location].remove([magnitude, direction]) + if self._loads[location] == []: + self._loads.pop(location) + + def apply_support(self, *args): + """ + This method adds a pinned or roller support at specified node(s). + + Parameters + ========== + The input(s) of this method are of the form (location, type). + + location: String or Symbol + Label of the Node at which support is added. + + type: String + Type of the support being provided at the node. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0)) + >>> t.apply_support(('A', 'pinned'), ('B', 'roller')) + >>> t.supports + {'A': 'pinned', 'B': 'roller'} + """ + for i in args: + location = i[0] + type = i[1] + if location not in self._node_coordinates: + raise ValueError("Support must be added on a known node") + + else: + if location not in self._supports: + if type == 'pinned': + self.apply_load((location, Symbol('R_'+str(location)+'_x'), 0)) + self.apply_load((location, Symbol('R_'+str(location)+'_y'), 90)) + elif type == 'roller': + self.apply_load((location, Symbol('R_'+str(location)+'_y'), 90)) + elif self._supports[location] == 'pinned': + if type == 'roller': + self.remove_load((location, Symbol('R_'+str(location)+'_x'), 0)) + elif self._supports[location] == 'roller': + if type == 'pinned': + self.apply_load((location, Symbol('R_'+str(location)+'_x'), 0)) + self._supports[location] = type + + def remove_support(self, *args): + """ + This method removes support from specified node(s.) + + Parameters + ========== + + locations: String or Symbol + Label of the Node(s) at which support is to be removed. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(('A', 0, 0), ('B', 3, 0)) + >>> t.apply_support(('A', 'pinned'), ('B', 'roller')) + >>> t.supports + {'A': 'pinned', 'B': 'roller'} + >>> t.remove_support('A','B') + >>> t.supports + {} + """ + for location in args: + + if location not in self._node_coordinates: + raise ValueError("No such node exists in the Truss") + + elif location not in self._supports: + raise ValueError("No support has been added to the given node") + + else: + if self._supports[location] == 'pinned': + self.remove_load((location, Symbol('R_'+str(location)+'_x'), 0)) + self.remove_load((location, Symbol('R_'+str(location)+'_y'), 90)) + elif self._supports[location] == 'roller': + self.remove_load((location, Symbol('R_'+str(location)+'_y'), 90)) + self._supports.pop(location) + + def solve(self): + """ + This method solves for all reaction forces of all supports and all internal forces + of all the members in the truss, provided the Truss is solvable. + + A Truss is solvable if the following condition is met, + + 2n >= r + m + + Where n is the number of nodes, r is the number of reaction forces, where each pinned + support has 2 reaction forces and each roller has 1, and m is the number of members. + + The given condition is derived from the fact that a system of equations is solvable + only when the number of variables is lesser than or equal to the number of equations. + Equilibrium Equations in x and y directions give two equations per node giving 2n number + equations. However, the truss needs to be stable as well and may be unstable if 2n > r + m. + The number of variables is simply the sum of the number of reaction forces and member + forces. + + .. note:: + The sign convention for the internal forces present in a member revolves around whether each + force is compressive or tensile. While forming equations for each node, internal force due + to a member on the node is assumed to be away from the node i.e. each force is assumed to + be compressive by default. Hence, a positive value for an internal force implies the + presence of compressive force in the member and a negative value implies a tensile force. + + Examples + ======== + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> t = Truss() + >>> t.add_node(("node_1", 0, 0), ("node_2", 6, 0), ("node_3", 2, 2), ("node_4", 2, 0)) + >>> t.add_member(("member_1", "node_1", "node_4"), ("member_2", "node_2", "node_4"), ("member_3", "node_1", "node_3")) + >>> t.add_member(("member_4", "node_2", "node_3"), ("member_5", "node_3", "node_4")) + >>> t.apply_load(("node_4", 10, 270)) + >>> t.apply_support(("node_1", "pinned"), ("node_2", "roller")) + >>> t.solve() + >>> t.reaction_loads + {'R_node_1_x': 0, 'R_node_1_y': 20/3, 'R_node_2_y': 10/3} + >>> t.internal_forces + {'member_1': 20/3, 'member_2': 20/3, 'member_3': -20*sqrt(2)/3, 'member_4': -10*sqrt(5)/3, 'member_5': 10} + """ + count_reaction_loads = 0 + for node in self._nodes: + if node[0] in self._supports: + if self._supports[node[0]]=='pinned': + count_reaction_loads += 2 + elif self._supports[node[0]]=='roller': + count_reaction_loads += 1 + if 2*len(self._nodes) != len(self._members) + count_reaction_loads: + raise ValueError("The given truss cannot be solved") + coefficients_matrix = [[0 for i in range(2*len(self._nodes))] for j in range(2*len(self._nodes))] + load_matrix = zeros(2*len(self.nodes), 1) + load_matrix_row = 0 + for node in self._nodes: + if node[0] in self._loads: + for load in self._loads[node[0]]: + if load[0]!=Symbol('R_'+str(node[0])+'_x') and load[0]!=Symbol('R_'+str(node[0])+'_y'): + load_matrix[load_matrix_row] -= load[0]*cos(pi*load[1]/180) + load_matrix[load_matrix_row + 1] -= load[0]*sin(pi*load[1]/180) + load_matrix_row += 2 + cols = 0 + row = 0 + for node in self._nodes: + if node[0] in self._supports: + if self._supports[node[0]]=='pinned': + coefficients_matrix[row][cols] += 1 + coefficients_matrix[row+1][cols+1] += 1 + cols += 2 + elif self._supports[node[0]]=='roller': + coefficients_matrix[row+1][cols] += 1 + cols += 1 + row += 2 + for member in self._members: + start = self._members[member][0] + end = self._members[member][1] + length = sqrt((self._node_coordinates[start][0]-self._node_coordinates[end][0])**2 + (self._node_coordinates[start][1]-self._node_coordinates[end][1])**2) + start_index = self._node_labels.index(start) + end_index = self._node_labels.index(end) + horizontal_component_start = (self._node_coordinates[end][0]-self._node_coordinates[start][0])/length + vertical_component_start = (self._node_coordinates[end][1]-self._node_coordinates[start][1])/length + horizontal_component_end = (self._node_coordinates[start][0]-self._node_coordinates[end][0])/length + vertical_component_end = (self._node_coordinates[start][1]-self._node_coordinates[end][1])/length + coefficients_matrix[start_index*2][cols] += horizontal_component_start + coefficients_matrix[start_index*2+1][cols] += vertical_component_start + coefficients_matrix[end_index*2][cols] += horizontal_component_end + coefficients_matrix[end_index*2+1][cols] += vertical_component_end + cols += 1 + forces_matrix = (Matrix(coefficients_matrix)**-1)*load_matrix + self._reaction_loads = {} + i = 0 + min_load = inf + for node in self._nodes: + if node[0] in self._loads: + for load in self._loads[node[0]]: + if type(load[0]) not in [Symbol, Mul, Add]: + min_load = min(min_load, load[0]) + for j in range(len(forces_matrix)): + if type(forces_matrix[j]) not in [Symbol, Mul, Add]: + if abs(forces_matrix[j]/min_load) <1E-10: + forces_matrix[j] = 0 + for node in self._nodes: + if node[0] in self._supports: + if self._supports[node[0]]=='pinned': + self._reaction_loads['R_'+str(node[0])+'_x'] = forces_matrix[i] + self._reaction_loads['R_'+str(node[0])+'_y'] = forces_matrix[i+1] + i += 2 + elif self._supports[node[0]]=='roller': + self._reaction_loads['R_'+str(node[0])+'_y'] = forces_matrix[i] + i += 1 + for member in self._members: + self._internal_forces[member] = forces_matrix[i] + i += 1 + return + + @doctest_depends_on(modules=('numpy',)) + def draw(self, subs_dict=None): + """ + Returns a plot object of the Truss with all its nodes, members, + supports and loads. + + .. note:: + The user must be careful while entering load values in their + directions. The draw function assumes a sign convention that + is used for plotting loads. + + Given a right-handed coordinate system with XYZ coordinates, + the supports are assumed to be such that the reaction forces of a + pinned support is in the +X and +Y direction while those of a + roller support is in the +Y direction. For the load, the range + of angles, one can input goes all the way to 360 degrees which, in the + the plot is the angle that the load vector makes with the positive x-axis in the anticlockwise direction. + + For example, for a 90-degree angle, the load will be a vertically + directed along +Y while a 270-degree angle denotes a vertical + load as well but along -Y. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.physics.continuum_mechanics.truss import Truss + >>> import math + >>> t = Truss() + >>> t.add_node(("A", -4, 0), ("B", 0, 0), ("C", 4, 0), ("D", 8, 0)) + >>> t.add_node(("E", 6, 2/math.sqrt(3))) + >>> t.add_node(("F", 2, 2*math.sqrt(3))) + >>> t.add_node(("G", -2, 2/math.sqrt(3))) + >>> t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D")) + >>> t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F")) + >>> t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E")) + >>> t.add_member(("FE","F","E"), ("DE","D","E")) + >>> t.apply_support(("A","pinned"), ("D","roller")) + >>> t.apply_load(("G", 3, 90), ("E", 3, 90), ("F", 2, 90)) + >>> p = t.draw() + >>> p # doctest: +ELLIPSIS + Plot object containing: + [0]: cartesian line: 1 for x over (1.0, 1.0) + ... + >>> p.show() + """ + if not numpy: + raise ImportError("To use this function numpy module is required") + + x = Symbol('x') + + markers = [] + annotations = [] + rectangles = [] + + node_markers = self._draw_nodes(subs_dict) + markers += node_markers + + member_rectangles = self._draw_members() + rectangles += member_rectangles + + support_markers = self._draw_supports() + markers += support_markers + + load_annotations = self._draw_loads() + annotations += load_annotations + + xmax = -INF + xmin = INF + ymax = -INF + ymin = INF + + for node in self._node_coordinates: + xmax = max(xmax, self._node_coordinates[node][0]) + xmin = min(xmin, self._node_coordinates[node][0]) + ymax = max(ymax, self._node_coordinates[node][1]) + ymin = min(ymin, self._node_coordinates[node][1]) + + lim = max(xmax*1.1-xmin*0.8+1, ymax*1.1-ymin*0.8+1) + + if lim==xmax*1.1-xmin*0.8+1: + sing_plot = plot(1, (x, 1, 1), markers=markers, show=False, annotations=annotations, xlim=(xmin-0.05*lim, xmax*1.1), ylim=(xmin-0.05*lim, xmax*1.1), axis=False, rectangles=rectangles) + + else: + sing_plot = plot(1, (x, 1, 1), markers=markers, show=False, annotations=annotations, xlim=(ymin-0.05*lim, ymax*1.1), ylim=(ymin-0.05*lim, ymax*1.1), axis=False, rectangles=rectangles) + + return sing_plot + + + def _draw_nodes(self, subs_dict): + node_markers = [] + + for node in self._node_coordinates: + if (type(self._node_coordinates[node][0]) in (Symbol, Quantity)): + if self._node_coordinates[node][0] in subs_dict: + self._node_coordinates[node][0] = subs_dict[self._node_coordinates[node][0]] + else: + raise ValueError("provided substituted dictionary is not adequate") + elif (type(self._node_coordinates[node][0]) == Mul): + objects = self._node_coordinates[node][0].as_coeff_Mul() + for object in objects: + if type(object) in (Symbol, Quantity): + if subs_dict==None or object not in subs_dict: + raise ValueError("provided substituted dictionary is not adequate") + else: + self._node_coordinates[node][0] /= object + self._node_coordinates[node][0] *= subs_dict[object] + + if (type(self._node_coordinates[node][1]) in (Symbol, Quantity)): + if self._node_coordinates[node][1] in subs_dict: + self._node_coordinates[node][1] = subs_dict[self._node_coordinates[node][1]] + else: + raise ValueError("provided substituted dictionary is not adequate") + elif (type(self._node_coordinates[node][1]) == Mul): + objects = self._node_coordinates[node][1].as_coeff_Mul() + for object in objects: + if type(object) in (Symbol, Quantity): + if subs_dict==None or object not in subs_dict: + raise ValueError("provided substituted dictionary is not adequate") + else: + self._node_coordinates[node][1] /= object + self._node_coordinates[node][1] *= subs_dict[object] + + for node in self._node_coordinates: + node_markers.append( + { + 'args':[[self._node_coordinates[node][0]], [self._node_coordinates[node][1]]], + 'marker':'o', + 'markersize':5, + 'color':'black' + } + ) + return node_markers + + def _draw_members(self): + + member_rectangles = [] + + xmax = -INF + xmin = INF + ymax = -INF + ymin = INF + + for node in self._node_coordinates: + xmax = max(xmax, self._node_coordinates[node][0]) + xmin = min(xmin, self._node_coordinates[node][0]) + ymax = max(ymax, self._node_coordinates[node][1]) + ymin = min(ymin, self._node_coordinates[node][1]) + + if abs(1.1*xmax-0.8*xmin)>abs(1.1*ymax-0.8*ymin): + max_diff = 1.1*xmax-0.8*xmin + else: + max_diff = 1.1*ymax-0.8*ymin + + for member in self._members: + x1 = self._node_coordinates[self._members[member][0]][0] + y1 = self._node_coordinates[self._members[member][0]][1] + x2 = self._node_coordinates[self._members[member][1]][0] + y2 = self._node_coordinates[self._members[member][1]][1] + if x2!=x1 and y2!=y1: + if x2>x1: + member_rectangles.append( + { + 'xy':(x1-0.005*max_diff*cos(pi/4+atan((y2-y1)/(x2-x1)))/2, y1-0.005*max_diff*sin(pi/4+atan((y2-y1)/(x2-x1)))/2), + 'width':sqrt((x1-x2)**2+(y1-y2)**2)+0.005*max_diff/math.sqrt(2), + 'height':0.005*max_diff, + 'angle':180*atan((y2-y1)/(x2-x1))/pi, + 'color':'brown' + } + ) + else: + member_rectangles.append( + { + 'xy':(x2-0.005*max_diff*cos(pi/4+atan((y2-y1)/(x2-x1)))/2, y2-0.005*max_diff*sin(pi/4+atan((y2-y1)/(x2-x1)))/2), + 'width':sqrt((x1-x2)**2+(y1-y2)**2)+0.005*max_diff/math.sqrt(2), + 'height':0.005*max_diff, + 'angle':180*atan((y2-y1)/(x2-x1))/pi, + 'color':'brown' + } + ) + elif y2==y1: + if x2>x1: + member_rectangles.append( + { + 'xy':(x1-0.005*max_diff/2, y1-0.005*max_diff/2), + 'width':sqrt((x1-x2)**2+(y1-y2)**2), + 'height':0.005*max_diff, + 'angle':90*(1-math.copysign(1, x2-x1)), + 'color':'brown' + } + ) + else: + member_rectangles.append( + { + 'xy':(x1-0.005*max_diff/2, y1-0.005*max_diff/2), + 'width':sqrt((x1-x2)**2+(y1-y2)**2), + 'height':-0.005*max_diff, + 'angle':90*(1-math.copysign(1, x2-x1)), + 'color':'brown' + } + ) + else: + if y1abs(1.1*ymax-0.8*ymin): + max_diff = 1.1*xmax-0.8*xmin + else: + max_diff = 1.1*ymax-0.8*ymin + + for node in self._supports: + if self._supports[node]=='pinned': + support_markers.append( + { + 'args':[ + [self._node_coordinates[node][0]], + [self._node_coordinates[node][1]] + ], + 'marker':6, + 'markersize':15, + 'color':'black', + 'markerfacecolor':'none' + } + ) + support_markers.append( + { + 'args':[ + [self._node_coordinates[node][0]], + [self._node_coordinates[node][1]-0.035*max_diff] + ], + 'marker':'_', + 'markersize':14, + 'color':'black' + } + ) + + elif self._supports[node]=='roller': + support_markers.append( + { + 'args':[ + [self._node_coordinates[node][0]], + [self._node_coordinates[node][1]-0.02*max_diff] + ], + 'marker':'o', + 'markersize':11, + 'color':'black', + 'markerfacecolor':'none' + } + ) + support_markers.append( + { + 'args':[ + [self._node_coordinates[node][0]], + [self._node_coordinates[node][1]-0.0375*max_diff] + ], + 'marker':'_', + 'markersize':14, + 'color':'black' + } + ) + return support_markers + + def _draw_loads(self): + load_annotations = [] + + xmax = -INF + xmin = INF + ymax = -INF + ymin = INF + + for node in self._node_coordinates: + xmax = max(xmax, self._node_coordinates[node][0]) + xmin = min(xmin, self._node_coordinates[node][0]) + ymax = max(ymax, self._node_coordinates[node][1]) + ymin = min(ymin, self._node_coordinates[node][1]) + + if abs(1.1*xmax-0.8*xmin)>abs(1.1*ymax-0.8*ymin): + max_diff = 1.1*xmax-0.8*xmin+5 + else: + max_diff = 1.1*ymax-0.8*ymin+5 + + for node in self._loads: + for load in self._loads[node]: + if load[0] in [Symbol('R_'+str(node)+'_x'), Symbol('R_'+str(node)+'_y')]: + continue + x = self._node_coordinates[node][0] + y = self._node_coordinates[node][1] + load_annotations.append( + { + 'text':'', + 'xy':( + x-math.cos(pi*load[1]/180)*(max_diff/100), + y-math.sin(pi*load[1]/180)*(max_diff/100) + ), + 'xytext':( + x-(max_diff/100+abs(xmax-xmin)+abs(ymax-ymin))*math.cos(pi*load[1]/180)/20, + y-(max_diff/100+abs(xmax-xmin)+abs(ymax-ymin))*math.sin(pi*load[1]/180)/20 + ), + 'arrowprops':{'width':1.5, 'headlength':5, 'headwidth':5, 'facecolor':'black'} + } + ) + return load_annotations diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c4d74895f2e68cb918f00fd7065ca048b32ef06d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__init__.py @@ -0,0 +1,17 @@ +from .lti import (TransferFunction, PIDController, Series, MIMOSeries, Parallel, MIMOParallel, + Feedback, MIMOFeedback, TransferFunctionMatrix, StateSpace, gbt, bilinear, forward_diff, + backward_diff, phase_margin, gain_margin) +from .control_plots import (pole_zero_numerical_data, pole_zero_plot, step_response_numerical_data, + step_response_plot, impulse_response_numerical_data, impulse_response_plot, ramp_response_numerical_data, + ramp_response_plot, bode_magnitude_numerical_data, bode_phase_numerical_data, bode_magnitude_plot, + bode_phase_plot, bode_plot, nyquist_plot_expr, nyquist_plot, nichols_plot_expr, nichols_plot) + +__all__ = ['TransferFunction', 'PIDController', 'Series', 'MIMOSeries', 'Parallel', + 'MIMOParallel', 'Feedback', 'MIMOFeedback', 'TransferFunctionMatrix', 'StateSpace', + 'gbt', 'bilinear', 'forward_diff', 'backward_diff', 'phase_margin', 'gain_margin', + 'pole_zero_numerical_data', 'pole_zero_plot', 'step_response_numerical_data', + 'step_response_plot', 'impulse_response_numerical_data', 'impulse_response_plot', + 'ramp_response_numerical_data', 'ramp_response_plot', + 'bode_magnitude_numerical_data', 'bode_phase_numerical_data', + 'bode_magnitude_plot', 'bode_phase_plot', 'bode_plot', 'nyquist_plot_expr', 'nyquist_plot', + 'nichols_plot_expr', 'nichols_plot'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/control_plots.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/control_plots.py new file mode 100644 index 0000000000000000000000000000000000000000..1a83d3b833a064905619a4d6ba2a74e52ef72afa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/control_plots.py @@ -0,0 +1,1135 @@ +from sympy.core.numbers import I, pi +from sympy.functions.elementary.exponential import (exp, log) +from sympy.polys.partfrac import apart +from sympy.core.symbol import Dummy +from sympy.external import import_module +from sympy.functions import arg, Abs +from sympy.integrals.laplace import _fast_inverse_laplace +from sympy.physics.control.lti import SISOLinearTimeInvariant +from sympy.plotting.series import LineOver1DRangeSeries +from sympy.plotting.plot import plot_parametric +from sympy.polys.domains import ZZ, QQ +from sympy.polys.polytools import Poly +from sympy.printing.latex import latex +from sympy.geometry.polygon import deg + +__all__ = ['pole_zero_numerical_data', 'pole_zero_plot', + 'step_response_numerical_data', 'step_response_plot', + 'impulse_response_numerical_data', 'impulse_response_plot', + 'ramp_response_numerical_data', 'ramp_response_plot', + 'bode_magnitude_numerical_data', 'bode_phase_numerical_data', + 'bode_magnitude_plot', 'bode_phase_plot', 'bode_plot', + 'nyquist_plot_expr', 'nyquist_plot', 'nichols_plot_expr', + 'nichols_plot'] + + +matplotlib = import_module( + 'matplotlib', import_kwargs={'fromlist': ['pyplot']}, + catch=(RuntimeError,)) + +if matplotlib: + plt = matplotlib.pyplot + + +def _check_system(system): + """Function to check whether the dynamical system passed for plots is + compatible or not.""" + if not isinstance(system, SISOLinearTimeInvariant): + raise NotImplementedError("Only SISO LTI systems are currently supported.") + sys = system.to_expr() + len_free_symbols = len(sys.free_symbols) + if len_free_symbols > 1: + raise ValueError("Extra degree of freedom found. Make sure" + " that there are no free symbols in the dynamical system other" + " than the variable of Laplace transform.") + if sys.has(exp): + # Should test that exp is not part of a constant, in which case + # no exception is required, compare exp(s) with s*exp(1) + raise NotImplementedError("Time delay terms are not supported.") + + +def _poly_roots(poly): + """Function to get the roots of a polynomial.""" + def _eval(l): + return [float(i) if i.is_real else complex(i) for i in l] + if poly.domain in (QQ, ZZ): + return _eval(poly.all_roots()) + # XXX: Use all_roots() for irrational coefficients when possible + # See https://github.com/sympy/sympy/issues/22943 + return _eval(poly.nroots()) + + +def pole_zero_numerical_data(system): + """ + Returns the numerical data of poles and zeros of the system. + It is internally used by ``pole_zero_plot`` to get the data + for plotting poles and zeros. Users can use this data to further + analyse the dynamics of the system or plot using a different + backend/plotting-module. + + Parameters + ========== + + system : SISOLinearTimeInvariant + The system for which the pole-zero data is to be computed. + + Returns + ======= + + tuple : (zeros, poles) + zeros = Zeros of the system as a list of Python float/complex. + poles = Poles of the system as a list of Python float/complex. + + Raises + ====== + + NotImplementedError + When a SISO LTI system is not passed. + + When time delay terms are present in the system. + + ValueError + When more than one free symbol is present in the system. + The only variable in the transfer function should be + the variable of the Laplace transform. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import pole_zero_numerical_data + >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) + >>> pole_zero_numerical_data(tf1) + ([-1j, 1j], [-2.0, -1.0, (-0.5-0.8660254037844386j), (-0.5+0.8660254037844386j)]) + + See Also + ======== + + pole_zero_plot + + """ + _check_system(system) + system = system.doit() # Get the equivalent TransferFunction object. + + num_poly = Poly(system.num, system.var) + den_poly = Poly(system.den, system.var) + + return _poly_roots(num_poly), _poly_roots(den_poly) + + +def pole_zero_plot(system, pole_color='blue', pole_markersize=10, + zero_color='orange', zero_markersize=7, grid=True, show_axes=True, + show=True, **kwargs): + r""" + Returns the Pole-Zero plot (also known as PZ Plot or PZ Map) of a system. + + A Pole-Zero plot is a graphical representation of a system's poles and + zeros. It is plotted on a complex plane, with circular markers representing + the system's zeros and 'x' shaped markers representing the system's poles. + + Parameters + ========== + + system : SISOLinearTimeInvariant type systems + The system for which the pole-zero plot is to be computed. + pole_color : str, tuple, optional + The color of the pole points on the plot. Default color + is blue. The color can be provided as a matplotlib color string, + or a 3-tuple of floats each in the 0-1 range. + pole_markersize : Number, optional + The size of the markers used to mark the poles in the plot. + Default pole markersize is 10. + zero_color : str, tuple, optional + The color of the zero points on the plot. Default color + is orange. The color can be provided as a matplotlib color string, + or a 3-tuple of floats each in the 0-1 range. + zero_markersize : Number, optional + The size of the markers used to mark the zeros in the plot. + Default zero markersize is 7. + grid : boolean, optional + If ``True``, the plot will have a grid. Defaults to True. + show_axes : boolean, optional + If ``True``, the coordinate axes will be shown. Defaults to False. + show : boolean, optional + If ``True``, the plot will be displayed otherwise + the equivalent matplotlib ``plot`` object will be returned. + Defaults to True. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import pole_zero_plot + >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) + >>> pole_zero_plot(tf1) # doctest: +SKIP + + See Also + ======== + + pole_zero_numerical_data + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Pole%E2%80%93zero_plot + + """ + zeros, poles = pole_zero_numerical_data(system) + + zero_real = [i.real for i in zeros] + zero_imag = [i.imag for i in zeros] + + pole_real = [i.real for i in poles] + pole_imag = [i.imag for i in poles] + + plt.plot(pole_real, pole_imag, 'x', mfc='none', + markersize=pole_markersize, color=pole_color) + plt.plot(zero_real, zero_imag, 'o', markersize=zero_markersize, + color=zero_color) + plt.xlabel('Real Axis') + plt.ylabel('Imaginary Axis') + plt.title(f'Poles and Zeros of ${latex(system)}$', pad=20) + + if grid: + plt.grid() + if show_axes: + plt.axhline(0, color='black') + plt.axvline(0, color='black') + if show: + plt.show() + return + + return plt + + +def step_response_numerical_data(system, prec=8, lower_limit=0, + upper_limit=10, **kwargs): + """ + Returns the numerical values of the points in the step response plot + of a SISO continuous-time system. By default, adaptive sampling + is used. If the user wants to instead get an uniformly + sampled response, then ``adaptive`` kwarg should be passed ``False`` + and ``n`` must be passed as additional kwargs. + Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries` + for more details. + + Parameters + ========== + + system : SISOLinearTimeInvariant + The system for which the unit step response data is to be computed. + prec : int, optional + The decimal point precision for the point coordinate values. + Defaults to 8. + lower_limit : Number, optional + The lower limit of the plot range. Defaults to 0. + upper_limit : Number, optional + The upper limit of the plot range. Defaults to 10. + kwargs : + Additional keyword arguments are passed to the underlying + :class:`sympy.plotting.series.LineOver1DRangeSeries` class. + + Returns + ======= + + tuple : (x, y) + x = Time-axis values of the points in the step response. NumPy array. + y = Amplitude-axis values of the points in the step response. NumPy array. + + Raises + ====== + + NotImplementedError + When a SISO LTI system is not passed. + + When time delay terms are present in the system. + + ValueError + When more than one free symbol is present in the system. + The only variable in the transfer function should be + the variable of the Laplace transform. + + When ``lower_limit`` parameter is less than 0. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import step_response_numerical_data + >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s) + >>> step_response_numerical_data(tf1) # doctest: +SKIP + ([0.0, 0.025413462339411542, 0.0484508722725343, ... , 9.670250533855183, 9.844291913708725, 10.0], + [0.0, 0.023844582399907256, 0.042894276802320226, ..., 6.828770759094287e-12, 6.456457160755703e-12]) + + See Also + ======== + + step_response_plot + + """ + if lower_limit < 0: + raise ValueError("Lower limit of time must be greater " + "than or equal to zero.") + _check_system(system) + _x = Dummy("x") + expr = system.to_expr()/(system.var) + expr = apart(expr, system.var, full=True) + _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec) + return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit), + **kwargs).get_points() + + +def step_response_plot(system, color='b', prec=8, lower_limit=0, + upper_limit=10, show_axes=False, grid=True, show=True, **kwargs): + r""" + Returns the unit step response of a continuous-time system. It is + the response of the system when the input signal is a step function. + + Parameters + ========== + + system : SISOLinearTimeInvariant type + The LTI SISO system for which the Step Response is to be computed. + color : str, tuple, optional + The color of the line. Default is Blue. + show : boolean, optional + If ``True``, the plot will be displayed otherwise + the equivalent matplotlib ``plot`` object will be returned. + Defaults to True. + lower_limit : Number, optional + The lower limit of the plot range. Defaults to 0. + upper_limit : Number, optional + The upper limit of the plot range. Defaults to 10. + prec : int, optional + The decimal point precision for the point coordinate values. + Defaults to 8. + show_axes : boolean, optional + If ``True``, the coordinate axes will be shown. Defaults to False. + grid : boolean, optional + If ``True``, the plot will have a grid. Defaults to True. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import step_response_plot + >>> tf1 = TransferFunction(8*s**2 + 18*s + 32, s**3 + 6*s**2 + 14*s + 24, s) + >>> step_response_plot(tf1) # doctest: +SKIP + + See Also + ======== + + impulse_response_plot, ramp_response_plot + + References + ========== + + .. [1] https://www.mathworks.com/help/control/ref/lti.step.html + + """ + x, y = step_response_numerical_data(system, prec=prec, + lower_limit=lower_limit, upper_limit=upper_limit, **kwargs) + plt.plot(x, y, color=color) + plt.xlabel('Time (s)') + plt.ylabel('Amplitude') + plt.title(f'Unit Step Response of ${latex(system)}$', pad=20) + + if grid: + plt.grid() + if show_axes: + plt.axhline(0, color='black') + plt.axvline(0, color='black') + if show: + plt.show() + return + + return plt + + +def impulse_response_numerical_data(system, prec=8, lower_limit=0, + upper_limit=10, **kwargs): + """ + Returns the numerical values of the points in the impulse response plot + of a SISO continuous-time system. By default, adaptive sampling + is used. If the user wants to instead get an uniformly + sampled response, then ``adaptive`` kwarg should be passed ``False`` + and ``n`` must be passed as additional kwargs. + Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries` + for more details. + + Parameters + ========== + + system : SISOLinearTimeInvariant + The system for which the impulse response data is to be computed. + prec : int, optional + The decimal point precision for the point coordinate values. + Defaults to 8. + lower_limit : Number, optional + The lower limit of the plot range. Defaults to 0. + upper_limit : Number, optional + The upper limit of the plot range. Defaults to 10. + kwargs : + Additional keyword arguments are passed to the underlying + :class:`sympy.plotting.series.LineOver1DRangeSeries` class. + + Returns + ======= + + tuple : (x, y) + x = Time-axis values of the points in the impulse response. NumPy array. + y = Amplitude-axis values of the points in the impulse response. NumPy array. + + Raises + ====== + + NotImplementedError + When a SISO LTI system is not passed. + + When time delay terms are present in the system. + + ValueError + When more than one free symbol is present in the system. + The only variable in the transfer function should be + the variable of the Laplace transform. + + When ``lower_limit`` parameter is less than 0. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import impulse_response_numerical_data + >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s) + >>> impulse_response_numerical_data(tf1) # doctest: +SKIP + ([0.0, 0.06616480200395854,... , 9.854500743565858, 10.0], + [0.9999999799999999, 0.7042848373025861,...,7.170748906965121e-13, -5.1901263495547205e-12]) + + See Also + ======== + + impulse_response_plot + + """ + if lower_limit < 0: + raise ValueError("Lower limit of time must be greater " + "than or equal to zero.") + _check_system(system) + _x = Dummy("x") + expr = system.to_expr() + expr = apart(expr, system.var, full=True) + _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec) + return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit), + **kwargs).get_points() + + +def impulse_response_plot(system, color='b', prec=8, lower_limit=0, + upper_limit=10, show_axes=False, grid=True, show=True, **kwargs): + r""" + Returns the unit impulse response (Input is the Dirac-Delta Function) of a + continuous-time system. + + Parameters + ========== + + system : SISOLinearTimeInvariant type + The LTI SISO system for which the Impulse Response is to be computed. + color : str, tuple, optional + The color of the line. Default is Blue. + show : boolean, optional + If ``True``, the plot will be displayed otherwise + the equivalent matplotlib ``plot`` object will be returned. + Defaults to True. + lower_limit : Number, optional + The lower limit of the plot range. Defaults to 0. + upper_limit : Number, optional + The upper limit of the plot range. Defaults to 10. + prec : int, optional + The decimal point precision for the point coordinate values. + Defaults to 8. + show_axes : boolean, optional + If ``True``, the coordinate axes will be shown. Defaults to False. + grid : boolean, optional + If ``True``, the plot will have a grid. Defaults to True. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import impulse_response_plot + >>> tf1 = TransferFunction(8*s**2 + 18*s + 32, s**3 + 6*s**2 + 14*s + 24, s) + >>> impulse_response_plot(tf1) # doctest: +SKIP + + See Also + ======== + + step_response_plot, ramp_response_plot + + References + ========== + + .. [1] https://www.mathworks.com/help/control/ref/dynamicsystem.impulse.html + + """ + x, y = impulse_response_numerical_data(system, prec=prec, + lower_limit=lower_limit, upper_limit=upper_limit, **kwargs) + plt.plot(x, y, color=color) + plt.xlabel('Time (s)') + plt.ylabel('Amplitude') + plt.title(f'Impulse Response of ${latex(system)}$', pad=20) + + if grid: + plt.grid() + if show_axes: + plt.axhline(0, color='black') + plt.axvline(0, color='black') + if show: + plt.show() + return + + return plt + + +def ramp_response_numerical_data(system, slope=1, prec=8, + lower_limit=0, upper_limit=10, **kwargs): + """ + Returns the numerical values of the points in the ramp response plot + of a SISO continuous-time system. By default, adaptive sampling + is used. If the user wants to instead get an uniformly + sampled response, then ``adaptive`` kwarg should be passed ``False`` + and ``n`` must be passed as additional kwargs. + Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries` + for more details. + + Parameters + ========== + + system : SISOLinearTimeInvariant + The system for which the ramp response data is to be computed. + slope : Number, optional + The slope of the input ramp function. Defaults to 1. + prec : int, optional + The decimal point precision for the point coordinate values. + Defaults to 8. + lower_limit : Number, optional + The lower limit of the plot range. Defaults to 0. + upper_limit : Number, optional + The upper limit of the plot range. Defaults to 10. + kwargs : + Additional keyword arguments are passed to the underlying + :class:`sympy.plotting.series.LineOver1DRangeSeries` class. + + Returns + ======= + + tuple : (x, y) + x = Time-axis values of the points in the ramp response plot. NumPy array. + y = Amplitude-axis values of the points in the ramp response plot. NumPy array. + + Raises + ====== + + NotImplementedError + When a SISO LTI system is not passed. + + When time delay terms are present in the system. + + ValueError + When more than one free symbol is present in the system. + The only variable in the transfer function should be + the variable of the Laplace transform. + + When ``lower_limit`` parameter is less than 0. + + When ``slope`` is negative. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import ramp_response_numerical_data + >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s) + >>> ramp_response_numerical_data(tf1) # doctest: +SKIP + (([0.0, 0.12166980856813935,..., 9.861246379582118, 10.0], + [1.4504508011325967e-09, 0.006046440489058766,..., 0.12499999999568202, 0.12499999999661349])) + + See Also + ======== + + ramp_response_plot + + """ + if slope < 0: + raise ValueError("Slope must be greater than or equal" + " to zero.") + if lower_limit < 0: + raise ValueError("Lower limit of time must be greater " + "than or equal to zero.") + _check_system(system) + _x = Dummy("x") + expr = (slope*system.to_expr())/((system.var)**2) + expr = apart(expr, system.var, full=True) + _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec) + return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit), + **kwargs).get_points() + + +def ramp_response_plot(system, slope=1, color='b', prec=8, lower_limit=0, + upper_limit=10, show_axes=False, grid=True, show=True, **kwargs): + r""" + Returns the ramp response of a continuous-time system. + + Ramp function is defined as the straight line + passing through origin ($f(x) = mx$). The slope of + the ramp function can be varied by the user and + the default value is 1. + + Parameters + ========== + + system : SISOLinearTimeInvariant type + The LTI SISO system for which the Ramp Response is to be computed. + slope : Number, optional + The slope of the input ramp function. Defaults to 1. + color : str, tuple, optional + The color of the line. Default is Blue. + show : boolean, optional + If ``True``, the plot will be displayed otherwise + the equivalent matplotlib ``plot`` object will be returned. + Defaults to True. + lower_limit : Number, optional + The lower limit of the plot range. Defaults to 0. + upper_limit : Number, optional + The upper limit of the plot range. Defaults to 10. + prec : int, optional + The decimal point precision for the point coordinate values. + Defaults to 8. + show_axes : boolean, optional + If ``True``, the coordinate axes will be shown. Defaults to False. + grid : boolean, optional + If ``True``, the plot will have a grid. Defaults to True. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import ramp_response_plot + >>> tf1 = TransferFunction(s, (s+4)*(s+8), s) + >>> ramp_response_plot(tf1, upper_limit=2) # doctest: +SKIP + + See Also + ======== + + step_response_plot, impulse_response_plot + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Ramp_function + + """ + x, y = ramp_response_numerical_data(system, slope=slope, prec=prec, + lower_limit=lower_limit, upper_limit=upper_limit, **kwargs) + plt.plot(x, y, color=color) + plt.xlabel('Time (s)') + plt.ylabel('Amplitude') + plt.title(f'Ramp Response of ${latex(system)}$ [Slope = {slope}]', pad=20) + + if grid: + plt.grid() + if show_axes: + plt.axhline(0, color='black') + plt.axvline(0, color='black') + if show: + plt.show() + return + + return plt + + +def bode_magnitude_numerical_data(system, initial_exp=-5, final_exp=5, freq_unit='rad/sec', **kwargs): + """ + Returns the numerical data of the Bode magnitude plot of the system. + It is internally used by ``bode_magnitude_plot`` to get the data + for plotting Bode magnitude plot. Users can use this data to further + analyse the dynamics of the system or plot using a different + backend/plotting-module. + + Parameters + ========== + + system : SISOLinearTimeInvariant + The system for which the data is to be computed. + initial_exp : Number, optional + The initial exponent of 10 of the semilog plot. Defaults to -5. + final_exp : Number, optional + The final exponent of 10 of the semilog plot. Defaults to 5. + freq_unit : string, optional + User can choose between ``'rad/sec'`` (radians/second) and ``'Hz'`` (Hertz) as frequency units. + + Returns + ======= + + tuple : (x, y) + x = x-axis values of the Bode magnitude plot. + y = y-axis values of the Bode magnitude plot. + + Raises + ====== + + NotImplementedError + When a SISO LTI system is not passed. + + When time delay terms are present in the system. + + ValueError + When more than one free symbol is present in the system. + The only variable in the transfer function should be + the variable of the Laplace transform. + + When incorrect frequency units are given as input. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import bode_magnitude_numerical_data + >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) + >>> bode_magnitude_numerical_data(tf1) # doctest: +SKIP + ([1e-05, 1.5148378120533502e-05,..., 68437.36188804005, 100000.0], + [-6.020599914256786, -6.0205999155219505,..., -193.4117304087953, -200.00000000260573]) + + See Also + ======== + + bode_magnitude_plot, bode_phase_numerical_data + + """ + _check_system(system) + expr = system.to_expr() + freq_units = ('rad/sec', 'Hz') + if freq_unit not in freq_units: + raise ValueError('Only "rad/sec" and "Hz" are accepted frequency units.') + + _w = Dummy("w", real=True) + if freq_unit == 'Hz': + repl = I*_w*2*pi + else: + repl = I*_w + w_expr = expr.subs({system.var: repl}) + + mag = 20*log(Abs(w_expr), 10) + + x, y = LineOver1DRangeSeries(mag, + (_w, 10**initial_exp, 10**final_exp), xscale='log', **kwargs).get_points() + + return x, y + + +def bode_magnitude_plot(system, initial_exp=-5, final_exp=5, + color='b', show_axes=False, grid=True, show=True, freq_unit='rad/sec', **kwargs): + r""" + Returns the Bode magnitude plot of a continuous-time system. + + See ``bode_plot`` for all the parameters. + """ + x, y = bode_magnitude_numerical_data(system, initial_exp=initial_exp, + final_exp=final_exp, freq_unit=freq_unit) + plt.plot(x, y, color=color, **kwargs) + plt.xscale('log') + + + plt.xlabel('Frequency (%s) [Log Scale]' % freq_unit) + plt.ylabel('Magnitude (dB)') + plt.title(f'Bode Plot (Magnitude) of ${latex(system)}$', pad=20) + + if grid: + plt.grid(True) + if show_axes: + plt.axhline(0, color='black') + plt.axvline(0, color='black') + if show: + plt.show() + return + + return plt + + +def bode_phase_numerical_data(system, initial_exp=-5, final_exp=5, freq_unit='rad/sec', phase_unit='rad', phase_unwrap = True, **kwargs): + """ + Returns the numerical data of the Bode phase plot of the system. + It is internally used by ``bode_phase_plot`` to get the data + for plotting Bode phase plot. Users can use this data to further + analyse the dynamics of the system or plot using a different + backend/plotting-module. + + Parameters + ========== + + system : SISOLinearTimeInvariant + The system for which the Bode phase plot data is to be computed. + initial_exp : Number, optional + The initial exponent of 10 of the semilog plot. Defaults to -5. + final_exp : Number, optional + The final exponent of 10 of the semilog plot. Defaults to 5. + freq_unit : string, optional + User can choose between ``'rad/sec'`` (radians/second) and '``'Hz'`` (Hertz) as frequency units. + phase_unit : string, optional + User can choose between ``'rad'`` (radians) and ``'deg'`` (degree) as phase units. + phase_unwrap : bool, optional + Set to ``True`` by default. + + Returns + ======= + + tuple : (x, y) + x = x-axis values of the Bode phase plot. + y = y-axis values of the Bode phase plot. + + Raises + ====== + + NotImplementedError + When a SISO LTI system is not passed. + + When time delay terms are present in the system. + + ValueError + When more than one free symbol is present in the system. + The only variable in the transfer function should be + the variable of the Laplace transform. + + When incorrect frequency or phase units are given as input. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import bode_phase_numerical_data + >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) + >>> bode_phase_numerical_data(tf1) # doctest: +SKIP + ([1e-05, 1.4472354033813751e-05, 2.035581932165858e-05,..., 47577.3248186011, 67884.09326036123, 100000.0], + [-2.5000000000291665e-05, -3.6180885085e-05, -5.08895483066e-05,...,-3.1415085799262523, -3.14155265358979]) + + See Also + ======== + + bode_magnitude_plot, bode_phase_numerical_data + + """ + _check_system(system) + expr = system.to_expr() + freq_units = ('rad/sec', 'Hz') + phase_units = ('rad', 'deg') + if freq_unit not in freq_units: + raise ValueError('Only "rad/sec" and "Hz" are accepted frequency units.') + if phase_unit not in phase_units: + raise ValueError('Only "rad" and "deg" are accepted phase units.') + + _w = Dummy("w", real=True) + if freq_unit == 'Hz': + repl = I*_w*2*pi + else: + repl = I*_w + w_expr = expr.subs({system.var: repl}) + + if phase_unit == 'deg': + phase = arg(w_expr)*180/pi + else: + phase = arg(w_expr) + + x, y = LineOver1DRangeSeries(phase, + (_w, 10**initial_exp, 10**final_exp), xscale='log', **kwargs).get_points() + + half = None + if phase_unwrap: + if(phase_unit == 'rad'): + half = pi + elif(phase_unit == 'deg'): + half = 180 + if half: + unit = 2*half + for i in range(1, len(y)): + diff = y[i] - y[i - 1] + if diff > half: # Jump from -half to half + y[i] = (y[i] - unit) + elif diff < -half: # Jump from half to -half + y[i] = (y[i] + unit) + + return x, y + + +def bode_phase_plot(system, initial_exp=-5, final_exp=5, + color='b', show_axes=False, grid=True, show=True, freq_unit='rad/sec', phase_unit='rad', phase_unwrap=True, **kwargs): + r""" + Returns the Bode phase plot of a continuous-time system. + + See ``bode_plot`` for all the parameters. + """ + x, y = bode_phase_numerical_data(system, initial_exp=initial_exp, + final_exp=final_exp, freq_unit=freq_unit, phase_unit=phase_unit, phase_unwrap=phase_unwrap) + plt.plot(x, y, color=color, **kwargs) + plt.xscale('log') + + plt.xlabel('Frequency (%s) [Log Scale]' % freq_unit) + plt.ylabel('Phase (%s)' % phase_unit) + plt.title(f'Bode Plot (Phase) of ${latex(system)}$', pad=20) + + if grid: + plt.grid(True) + if show_axes: + plt.axhline(0, color='black') + plt.axvline(0, color='black') + if show: + plt.show() + return + + return plt + + +def bode_plot(system, initial_exp=-5, final_exp=5, + grid=True, show_axes=False, show=True, freq_unit='rad/sec', phase_unit='rad', phase_unwrap=True, **kwargs): + r""" + Returns the Bode phase and magnitude plots of a continuous-time system. + + Parameters + ========== + + system : SISOLinearTimeInvariant type + The LTI SISO system for which the Bode Plot is to be computed. + initial_exp : Number, optional + The initial exponent of 10 of the semilog plot. Defaults to -5. + final_exp : Number, optional + The final exponent of 10 of the semilog plot. Defaults to 5. + show : boolean, optional + If ``True``, the plot will be displayed otherwise + the equivalent matplotlib ``plot`` object will be returned. + Defaults to True. + prec : int, optional + The decimal point precision for the point coordinate values. + Defaults to 8. + grid : boolean, optional + If ``True``, the plot will have a grid. Defaults to True. + show_axes : boolean, optional + If ``True``, the coordinate axes will be shown. Defaults to False. + freq_unit : string, optional + User can choose between ``'rad/sec'`` (radians/second) and ``'Hz'`` (Hertz) as frequency units. + phase_unit : string, optional + User can choose between ``'rad'`` (radians) and ``'deg'`` (degree) as phase units. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import bode_plot + >>> tf1 = TransferFunction(1*s**2 + 0.1*s + 7.5, 1*s**4 + 0.12*s**3 + 9*s**2, s) + >>> bode_plot(tf1, initial_exp=0.2, final_exp=0.7) # doctest: +SKIP + + See Also + ======== + + bode_magnitude_plot, bode_phase_plot + + """ + plt.subplot(211) + mag = bode_magnitude_plot(system, initial_exp=initial_exp, final_exp=final_exp, + show=False, grid=grid, show_axes=show_axes, + freq_unit=freq_unit, **kwargs) + mag.title(f'Bode Plot of ${latex(system)}$', pad=20) + mag.xlabel(None) + plt.subplot(212) + bode_phase_plot(system, initial_exp=initial_exp, final_exp=final_exp, + show=False, grid=grid, show_axes=show_axes, freq_unit=freq_unit, phase_unit=phase_unit, phase_unwrap=phase_unwrap, **kwargs).title(None) + + if show: + plt.show() + return + + return plt + + +def nyquist_plot_expr(system): + """Function to get the expression for Nyquist plot.""" + s = system.var + w = Dummy('w', real=True) + repl = I * w + expr = system.to_expr() + w_expr = expr.subs({s: repl}) + w_expr = w_expr.as_real_imag() + real_expr = w_expr[0] + imag_expr = w_expr[1] + return real_expr, imag_expr, w + + +def nichols_plot_expr(system): + """Function to get the expression for Nichols plot.""" + s = system.var + w = Dummy('w', real=True) + sys_expr = system.to_expr() + H_jw = sys_expr.subs(s, I*w) + mag_expr = Abs(H_jw) + mag_dB_expr = 20*log(mag_expr, 10) + phase_expr = arg(H_jw) + phase_deg_expr = deg(phase_expr) + return mag_dB_expr, phase_deg_expr, w + + +def nyquist_plot(system, initial_omega=0.01, final_omega=100, show=True, + color='b', **kwargs): + r""" + Generates the Nyquist plot for a continuous-time system. + + Parameters + ========== + + system : SISOLinearTimeInvariant + The LTI SISO system for which the Nyquist plot is to be generated. + initial_omega : float, optional + The starting frequency value. Defaults to 0.01. + final_omega : float, optional + The ending frequency value. Defaults to 100. + show : bool, optional + If True, the plot is displayed. Default is True. + color : str, optional + The color of the Nyquist plot. Default is 'b' (blue). + grid : bool, optional + If True, grid lines are displayed. Default is False. + **kwargs + Additional keyword arguments for customization. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import nyquist_plot + >>> tf1 = TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s) + >>> nyquist_plot(tf1) # doctest: +SKIP + + See Also + ======== + + nichols_plot, bode_plot + + """ + _check_system(system) + real_expr, imag_expr, w = nyquist_plot_expr(system) + w_values = [(w, initial_omega, final_omega)] + p = plot_parametric( + (real_expr, imag_expr), # The curve + (real_expr, -imag_expr), # Its mirror image + *w_values, + show=False, + line_color=color, + adaptive=True, + title=f'Nyquist Plot of ${latex(system)}$', + xlabel='Real Axis', + ylabel='Imaginary Axis', + size=(6, 5), + kwargs=kwargs) + if show: + p.show() + return + return p + + +def nichols_plot(system, initial_omega=0.01, final_omega=100, show=True, color='b', **kwargs): + r""" + Generates the Nichols plot for a LTI system. + + Parameters + ========== + + system : SISOLinearTimeInvariant + The LTI SISO system for which the Nyquist plot is to be generated. + initial_omega : float, optional + The starting frequency value. Defaults to 0.01. + final_omega : float, optional + The ending frequency value. Defaults to 100. + show : bool, optional + If True, the plot is displayed. Default is True. + color : str, optional + The color of the Nyquist plot. Default is 'b' (blue). + grid : bool, optional + If True, grid lines are displayed. Default is False. + **kwargs + Additional keyword arguments for customization. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy.physics.control.control_plots import nichols_plot + >>> tf1 = TransferFunction(1.5, s**2+14*s+40.02, s) + >>> nichols_plot(tf1) # doctest: +SKIP + + See Also + ======== + + nyquist_plot, bode_plot + + """ + _check_system(system) + magnitude_dB_expr, phase_deg_expr, w = nichols_plot_expr(system) + w_values = [(w, initial_omega, final_omega)] + p = plot_parametric( + (phase_deg_expr, magnitude_dB_expr), + *w_values, + show=False, + line_color=color, + title=f'Nichols Plot of ${latex(system)}$', + xlabel='Phase [deg]', + ylabel='Magnitude [dB]', + size=(6,5), + kwargs=kwargs) + if show: + p.show() + return + return p diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/lti.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/lti.py new file mode 100644 index 0000000000000000000000000000000000000000..480a1ec71d8c4dd07a51d67304a0b6e20a90691e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/lti.py @@ -0,0 +1,5001 @@ +from typing import Type +from sympy import Interval, numer, Rational, solveset +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.evalf import EvalfMixin +from sympy.core.expr import Expr +from sympy.core.function import expand +from sympy.core.logic import fuzzy_and +from sympy.core.mul import Mul +from sympy.core.numbers import I, pi, oo +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import Dummy, Symbol +from sympy.functions import Abs +from sympy.core.sympify import sympify, _sympify +from sympy.matrices import Matrix, ImmutableMatrix, ImmutableDenseMatrix, eye, ShapeError, zeros +from sympy.functions.elementary.exponential import (exp, log) +from sympy.matrices.expressions import MatMul, MatAdd +from sympy.polys import Poly, rootof +from sympy.polys.polyroots import roots +from sympy.polys.polytools import (cancel, degree) +from sympy.series import limit +from sympy.utilities.misc import filldedent +from sympy.solvers.ode.systems import linodesolve +from sympy.solvers.solveset import linsolve, linear_eq_to_matrix + +from mpmath.libmp.libmpf import prec_to_dps + +__all__ = ['TransferFunction', 'PIDController', 'Series', 'MIMOSeries', 'Parallel', 'MIMOParallel', + 'Feedback', 'MIMOFeedback', 'TransferFunctionMatrix', 'StateSpace', 'gbt', 'bilinear', 'forward_diff', 'backward_diff', + 'phase_margin', 'gain_margin'] + +def _roots(poly, var): + """ like roots, but works on higher-order polynomials. """ + r = roots(poly, var, multiple=True) + n = degree(poly) + if len(r) != n: + r = [rootof(poly, var, k) for k in range(n)] + return r + +def gbt(tf, sample_per, alpha): + r""" + Returns falling coefficients of H(z) from numerator and denominator. + + Explanation + =========== + + Where H(z) is the corresponding discretized transfer function, + discretized with the generalised bilinear transformation method. + H(z) is obtained from the continuous transfer function H(s) + by substituting $s(z) = \frac{z-1}{T(\alpha z + (1-\alpha))}$ into H(s), where T is the + sample period. + Coefficients are falling, i.e. $H(z) = \frac{az+b}{cz+d}$ is returned + as [a, b], [c, d]. + + Examples + ======== + + >>> from sympy.physics.control.lti import TransferFunction, gbt + >>> from sympy.abc import s, L, R, T + + >>> tf = TransferFunction(1, s*L + R, s) + >>> numZ, denZ = gbt(tf, T, 0.5) + >>> numZ + [T/(2*(L + R*T/2)), T/(2*(L + R*T/2))] + >>> denZ + [1, (-L + R*T/2)/(L + R*T/2)] + + >>> numZ, denZ = gbt(tf, T, 0) + >>> numZ + [T/L] + >>> denZ + [1, (-L + R*T)/L] + + >>> numZ, denZ = gbt(tf, T, 1) + >>> numZ + [T/(L + R*T), 0] + >>> denZ + [1, -L/(L + R*T)] + + >>> numZ, denZ = gbt(tf, T, 0.3) + >>> numZ + [3*T/(10*(L + 3*R*T/10)), 7*T/(10*(L + 3*R*T/10))] + >>> denZ + [1, (-L + 7*R*T/10)/(L + 3*R*T/10)] + + References + ========== + + .. [1] https://www.polyu.edu.hk/ama/profile/gfzhang/Research/ZCC09_IJC.pdf + """ + if not tf.is_SISO: + raise NotImplementedError("Not implemented for MIMO systems.") + + T = sample_per # and sample period T + s = tf.var + z = s # dummy discrete variable z + + np = tf.num.as_poly(s).all_coeffs() + dp = tf.den.as_poly(s).all_coeffs() + alpha = Rational(alpha).limit_denominator(1000) + + # The next line results from multiplying H(z) with z^N/z^N + N = max(len(np), len(dp)) - 1 + num = Add(*[ T**(N-i) * c * (z-1)**i * (alpha * z + 1 - alpha)**(N-i) for c, i in zip(np[::-1], range(len(np))) ]) + den = Add(*[ T**(N-i) * c * (z-1)**i * (alpha * z + 1 - alpha)**(N-i) for c, i in zip(dp[::-1], range(len(dp))) ]) + + num_coefs = num.as_poly(z).all_coeffs() + den_coefs = den.as_poly(z).all_coeffs() + + para = den_coefs[0] + num_coefs = [coef/para for coef in num_coefs] + den_coefs = [coef/para for coef in den_coefs] + + return num_coefs, den_coefs + +def bilinear(tf, sample_per): + r""" + Returns falling coefficients of H(z) from numerator and denominator. + + Explanation + =========== + + Where H(z) is the corresponding discretized transfer function, + discretized with the bilinear transform method. + H(z) is obtained from the continuous transfer function H(s) + by substituting $s(z) = \frac{2}{T}\frac{z-1}{z+1}$ into H(s), where T is the + sample period. + Coefficients are falling, i.e. $H(z) = \frac{az+b}{cz+d}$ is returned + as [a, b], [c, d]. + + Examples + ======== + + >>> from sympy.physics.control.lti import TransferFunction, bilinear + >>> from sympy.abc import s, L, R, T + + >>> tf = TransferFunction(1, s*L + R, s) + >>> numZ, denZ = bilinear(tf, T) + >>> numZ + [T/(2*(L + R*T/2)), T/(2*(L + R*T/2))] + >>> denZ + [1, (-L + R*T/2)/(L + R*T/2)] + """ + return gbt(tf, sample_per, S.Half) + +def forward_diff(tf, sample_per): + r""" + Returns falling coefficients of H(z) from numerator and denominator. + + Explanation + =========== + + Where H(z) is the corresponding discretized transfer function, + discretized with the forward difference transform method. + H(z) is obtained from the continuous transfer function H(s) + by substituting $s(z) = \frac{z-1}{T}$ into H(s), where T is the + sample period. + Coefficients are falling, i.e. $H(z) = \frac{az+b}{cz+d}$ is returned + as [a, b], [c, d]. + + Examples + ======== + + >>> from sympy.physics.control.lti import TransferFunction, forward_diff + >>> from sympy.abc import s, L, R, T + + >>> tf = TransferFunction(1, s*L + R, s) + >>> numZ, denZ = forward_diff(tf, T) + >>> numZ + [T/L] + >>> denZ + [1, (-L + R*T)/L] + """ + return gbt(tf, sample_per, S.Zero) + +def backward_diff(tf, sample_per): + r""" + Returns falling coefficients of H(z) from numerator and denominator. + + Explanation + =========== + + Where H(z) is the corresponding discretized transfer function, + discretized with the backward difference transform method. + H(z) is obtained from the continuous transfer function H(s) + by substituting $s(z) = \frac{z-1}{Tz}$ into H(s), where T is the + sample period. + Coefficients are falling, i.e. $H(z) = \frac{az+b}{cz+d}$ is returned + as [a, b], [c, d]. + + Examples + ======== + + >>> from sympy.physics.control.lti import TransferFunction, backward_diff + >>> from sympy.abc import s, L, R, T + + >>> tf = TransferFunction(1, s*L + R, s) + >>> numZ, denZ = backward_diff(tf, T) + >>> numZ + [T/(L + R*T), 0] + >>> denZ + [1, -L/(L + R*T)] + """ + return gbt(tf, sample_per, S.One) + +def phase_margin(system): + r""" + Returns the phase margin of a continuous time system. + Only applicable to Transfer Functions which can generate valid bode plots. + + Raises + ====== + + NotImplementedError + When time delay terms are present in the system. + + ValueError + When a SISO LTI system is not passed. + + When more than one free symbol is present in the system. + The only variable in the transfer function should be + the variable of the Laplace transform. + + Examples + ======== + + >>> from sympy.physics.control import TransferFunction, phase_margin + >>> from sympy.abc import s + + >>> tf = TransferFunction(1, s**3 + 2*s**2 + s, s) + >>> phase_margin(tf) + 180*(-pi + atan((-1 + (-2*18**(1/3)/(9 + sqrt(93))**(1/3) + 12**(1/3)*(9 + sqrt(93))**(1/3))**2/36)/(-12**(1/3)*(9 + sqrt(93))**(1/3)/3 + 2*18**(1/3)/(3*(9 + sqrt(93))**(1/3)))))/pi + 180 + >>> phase_margin(tf).n() + 21.3863897518751 + + >>> tf1 = TransferFunction(s**3, s**2 + 5*s, s) + >>> phase_margin(tf1) + -180 + 180*(atan(sqrt(2)*(-51/10 - sqrt(101)/10)*sqrt(1 + sqrt(101))/(2*(sqrt(101)/2 + 51/2))) + pi)/pi + >>> phase_margin(tf1).n() + -25.1783920627277 + + >>> tf2 = TransferFunction(1, s + 1, s) + >>> phase_margin(tf2) + -180 + + See Also + ======== + + gain_margin + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Phase_margin + + """ + from sympy.functions import arg + + if not isinstance(system, SISOLinearTimeInvariant): + raise ValueError("Margins are only applicable for SISO LTI systems.") + + _w = Dummy("w", real=True) + repl = I*_w + expr = system.to_expr() + len_free_symbols = len(expr.free_symbols) + if expr.has(exp): + raise NotImplementedError("Margins for systems with Time delay terms are not supported.") + elif len_free_symbols > 1: + raise ValueError("Extra degree of freedom found. Make sure" + " that there are no free symbols in the dynamical system other" + " than the variable of Laplace transform.") + + w_expr = expr.subs({system.var: repl}) + + mag = 20*log(Abs(w_expr), 10) + mag_sol = list(solveset(mag, _w, Interval(0, oo, left_open=True))) + + if (len(mag_sol) == 0): + pm = S(-180) + else: + wcp = mag_sol[0] + pm = ((arg(w_expr)*S(180)/pi).subs({_w:wcp}) + S(180)) % 360 + + if(pm >= 180): + pm = pm - 360 + + return pm + +def gain_margin(system): + r""" + Returns the gain margin of a continuous time system. + Only applicable to Transfer Functions which can generate valid bode plots. + + Raises + ====== + + NotImplementedError + When time delay terms are present in the system. + + ValueError + When a SISO LTI system is not passed. + + When more than one free symbol is present in the system. + The only variable in the transfer function should be + the variable of the Laplace transform. + + Examples + ======== + + >>> from sympy.physics.control import TransferFunction, gain_margin + >>> from sympy.abc import s + + >>> tf = TransferFunction(1, s**3 + 2*s**2 + s, s) + >>> gain_margin(tf) + 20*log(2)/log(10) + >>> gain_margin(tf).n() + 6.02059991327962 + + >>> tf1 = TransferFunction(s**3, s**2 + 5*s, s) + >>> gain_margin(tf1) + oo + + See Also + ======== + + phase_margin + + References + ========== + + https://en.wikipedia.org/wiki/Bode_plot + + """ + if not isinstance(system, SISOLinearTimeInvariant): + raise ValueError("Margins are only applicable for SISO LTI systems.") + + _w = Dummy("w", real=True) + repl = I*_w + expr = system.to_expr() + len_free_symbols = len(expr.free_symbols) + if expr.has(exp): + raise NotImplementedError("Margins for systems with Time delay terms are not supported.") + elif len_free_symbols > 1: + raise ValueError("Extra degree of freedom found. Make sure" + " that there are no free symbols in the dynamical system other" + " than the variable of Laplace transform.") + + w_expr = expr.subs({system.var: repl}) + + mag = 20*log(Abs(w_expr), 10) + phase = w_expr + phase_sol = list(solveset(numer(phase.as_real_imag()[1].cancel()),_w, Interval(0, oo, left_open = True))) + + if (len(phase_sol) == 0): + gm = oo + else: + wcg = phase_sol[0] + gm = -mag.subs({_w:wcg}) + + return gm + +class LinearTimeInvariant(Basic, EvalfMixin): + """A common class for all the Linear Time-Invariant Dynamical Systems.""" + + _clstype: Type + + # Users should not directly interact with this class. + def __new__(cls, *system, **kwargs): + if cls is LinearTimeInvariant: + raise NotImplementedError('The LTICommon class is not meant to be used directly.') + return super(LinearTimeInvariant, cls).__new__(cls, *system, **kwargs) + + @classmethod + def _check_args(cls, args): + if not args: + raise ValueError("At least 1 argument must be passed.") + if not all(isinstance(arg, cls._clstype) for arg in args): + raise TypeError(f"All arguments must be of type {cls._clstype}.") + var_set = {arg.var for arg in args} + if len(var_set) != 1: + raise ValueError(filldedent(f""" + All transfer functions should use the same complex variable + of the Laplace transform. {len(var_set)} different + values found.""")) + + @property + def is_SISO(self): + """Returns `True` if the passed LTI system is SISO else returns False.""" + return self._is_SISO + + +class SISOLinearTimeInvariant(LinearTimeInvariant): + """A common class for all the SISO Linear Time-Invariant Dynamical Systems.""" + # Users should not directly interact with this class. + + @property + def num_inputs(self): + """Return the number of inputs for SISOLinearTimeInvariant.""" + return 1 + + @property + def num_outputs(self): + """Return the number of outputs for SISOLinearTimeInvariant.""" + return 1 + + _is_SISO = True + + +class MIMOLinearTimeInvariant(LinearTimeInvariant): + """A common class for all the MIMO Linear Time-Invariant Dynamical Systems.""" + # Users should not directly interact with this class. + _is_SISO = False + + +SISOLinearTimeInvariant._clstype = SISOLinearTimeInvariant +MIMOLinearTimeInvariant._clstype = MIMOLinearTimeInvariant + + +def _check_other_SISO(func): + def wrapper(*args, **kwargs): + if not isinstance(args[-1], SISOLinearTimeInvariant): + return NotImplemented + else: + return func(*args, **kwargs) + return wrapper + + +def _check_other_MIMO(func): + def wrapper(*args, **kwargs): + if not isinstance(args[-1], MIMOLinearTimeInvariant): + return NotImplemented + else: + return func(*args, **kwargs) + return wrapper + + +class TransferFunction(SISOLinearTimeInvariant): + r""" + A class for representing LTI (Linear, time-invariant) systems that can be strictly described + by ratio of polynomials in the Laplace transform complex variable. The arguments + are ``num``, ``den``, and ``var``, where ``num`` and ``den`` are numerator and + denominator polynomials of the ``TransferFunction`` respectively, and the third argument is + a complex variable of the Laplace transform used by these polynomials of the transfer function. + ``num`` and ``den`` can be either polynomials or numbers, whereas ``var`` + has to be a :py:class:`~.Symbol`. + + Explanation + =========== + + Generally, a dynamical system representing a physical model can be described in terms of Linear + Ordinary Differential Equations like - + + $b_{m}y^{\left(m\right)}+b_{m-1}y^{\left(m-1\right)}+\dots+b_{1}y^{\left(1\right)}+b_{0}y= + a_{n}x^{\left(n\right)}+a_{n-1}x^{\left(n-1\right)}+\dots+a_{1}x^{\left(1\right)}+a_{0}x$ + + Here, $x$ is the input signal and $y$ is the output signal and superscript on both is the order of derivative + (not exponent). Derivative is taken with respect to the independent variable, $t$. Also, generally $m$ is greater + than $n$. + + It is not feasible to analyse the properties of such systems in their native form therefore, we use + mathematical tools like Laplace transform to get a better perspective. Taking the Laplace transform + of both the sides in the equation (at zero initial conditions), we get - + + $\mathcal{L}[b_{m}y^{\left(m\right)}+b_{m-1}y^{\left(m-1\right)}+\dots+b_{1}y^{\left(1\right)}+b_{0}y]= + \mathcal{L}[a_{n}x^{\left(n\right)}+a_{n-1}x^{\left(n-1\right)}+\dots+a_{1}x^{\left(1\right)}+a_{0}x]$ + + Using the linearity property of Laplace transform and also considering zero initial conditions + (i.e. $y(0^{-}) = 0$, $y'(0^{-}) = 0$ and so on), the equation + above gets translated to - + + $b_{m}\mathcal{L}[y^{\left(m\right)}]+\dots+b_{1}\mathcal{L}[y^{\left(1\right)}]+b_{0}\mathcal{L}[y]= + a_{n}\mathcal{L}[x^{\left(n\right)}]+\dots+a_{1}\mathcal{L}[x^{\left(1\right)}]+a_{0}\mathcal{L}[x]$ + + Now, applying Derivative property of Laplace transform, + + $b_{m}s^{m}\mathcal{L}[y]+\dots+b_{1}s\mathcal{L}[y]+b_{0}\mathcal{L}[y]= + a_{n}s^{n}\mathcal{L}[x]+\dots+a_{1}s\mathcal{L}[x]+a_{0}\mathcal{L}[x]$ + + Here, the superscript on $s$ is **exponent**. Note that the zero initial conditions assumption, mentioned above, is very important + and cannot be ignored otherwise the dynamical system cannot be considered time-independent and the simplified equation above + cannot be reached. + + Collecting $\mathcal{L}[y]$ and $\mathcal{L}[x]$ terms from both the sides and taking the ratio + $\frac{ \mathcal{L}\left\{y\right\} }{ \mathcal{L}\left\{x\right\} }$, we get the typical rational form of transfer + function. + + The numerator of the transfer function is, therefore, the Laplace transform of the output signal + (The signals are represented as functions of time) and similarly, the denominator + of the transfer function is the Laplace transform of the input signal. It is also a convention + to denote the input and output signal's Laplace transform with capital alphabets like shown below. + + $H(s) = \frac{Y(s)}{X(s)} = \frac{ \mathcal{L}\left\{y(t)\right\} }{ \mathcal{L}\left\{x(t)\right\} }$ + + $s$, also known as complex frequency, is a complex variable in the Laplace domain. It corresponds to the + equivalent variable $t$, in the time domain. Transfer functions are sometimes also referred to as the Laplace + transform of the system's impulse response. Transfer function, $H$, is represented as a rational + function in $s$ like, + + $H(s) =\ \frac{a_{n}s^{n}+a_{n-1}s^{n-1}+\dots+a_{1}s+a_{0}}{b_{m}s^{m}+b_{m-1}s^{m-1}+\dots+b_{1}s+b_{0}}$ + + Parameters + ========== + + num : Expr, Number + The numerator polynomial of the transfer function. + den : Expr, Number + The denominator polynomial of the transfer function. + var : Symbol + Complex variable of the Laplace transform used by the + polynomials of the transfer function. + + Raises + ====== + + TypeError + When ``var`` is not a Symbol or when ``num`` or ``den`` is not a + number or a polynomial. + ValueError + When ``den`` is zero. + + Examples + ======== + + >>> from sympy.abc import s, p, a + >>> from sympy.physics.control.lti import TransferFunction + >>> tf1 = TransferFunction(s + a, s**2 + s + 1, s) + >>> tf1 + TransferFunction(a + s, s**2 + s + 1, s) + >>> tf1.num + a + s + >>> tf1.den + s**2 + s + 1 + >>> tf1.var + s + >>> tf1.args + (a + s, s**2 + s + 1, s) + + Any complex variable can be used for ``var``. + + >>> tf2 = TransferFunction(a*p**3 - a*p**2 + s*p, p + a**2, p) + >>> tf2 + TransferFunction(a*p**3 - a*p**2 + p*s, a**2 + p, p) + >>> tf3 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) + >>> tf3 + TransferFunction((p - 1)*(p + 3), (p - 1)*(p + 5), p) + + To negate a transfer function the ``-`` operator can be prepended: + + >>> tf4 = TransferFunction(-a + s, p**2 + s, p) + >>> -tf4 + TransferFunction(a - s, p**2 + s, p) + >>> tf5 = TransferFunction(s**4 - 2*s**3 + 5*s + 4, s + 4, s) + >>> -tf5 + TransferFunction(-s**4 + 2*s**3 - 5*s - 4, s + 4, s) + + You can use a float or an integer (or other constants) as numerator and denominator: + + >>> tf6 = TransferFunction(1/2, 4, s) + >>> tf6.num + 0.500000000000000 + >>> tf6.den + 4 + >>> tf6.var + s + >>> tf6.args + (0.5, 4, s) + + You can take the integer power of a transfer function using the ``**`` operator: + + >>> tf7 = TransferFunction(s + a, s - a, s) + >>> tf7**3 + TransferFunction((a + s)**3, (-a + s)**3, s) + >>> tf7**0 + TransferFunction(1, 1, s) + >>> tf8 = TransferFunction(p + 4, p - 3, p) + >>> tf8**-1 + TransferFunction(p - 3, p + 4, p) + + Addition, subtraction, and multiplication of transfer functions can form + unevaluated ``Series`` or ``Parallel`` objects. + + >>> tf9 = TransferFunction(s + 1, s**2 + s + 1, s) + >>> tf10 = TransferFunction(s - p, s + 3, s) + >>> tf11 = TransferFunction(4*s**2 + 2*s - 4, s - 1, s) + >>> tf12 = TransferFunction(1 - s, s**2 + 4, s) + >>> tf9 + tf10 + Parallel(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-p + s, s + 3, s)) + >>> tf10 - tf11 + Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(-4*s**2 - 2*s + 4, s - 1, s)) + >>> tf9 * tf10 + Series(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-p + s, s + 3, s)) + >>> tf10 - (tf9 + tf12) + Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(-s - 1, s**2 + s + 1, s), TransferFunction(s - 1, s**2 + 4, s)) + >>> tf10 - (tf9 * tf12) + Parallel(TransferFunction(-p + s, s + 3, s), Series(TransferFunction(-1, 1, s), TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(1 - s, s**2 + 4, s))) + >>> tf11 * tf10 * tf9 + Series(TransferFunction(4*s**2 + 2*s - 4, s - 1, s), TransferFunction(-p + s, s + 3, s), TransferFunction(s + 1, s**2 + s + 1, s)) + >>> tf9 * tf11 + tf10 * tf12 + Parallel(Series(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(4*s**2 + 2*s - 4, s - 1, s)), Series(TransferFunction(-p + s, s + 3, s), TransferFunction(1 - s, s**2 + 4, s))) + >>> (tf9 + tf12) * (tf10 + tf11) + Series(Parallel(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(1 - s, s**2 + 4, s)), Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(4*s**2 + 2*s - 4, s - 1, s))) + + These unevaluated ``Series`` or ``Parallel`` objects can convert into the + resultant transfer function using ``.doit()`` method or by ``.rewrite(TransferFunction)``. + + >>> ((tf9 + tf10) * tf12).doit() + TransferFunction((1 - s)*((-p + s)*(s**2 + s + 1) + (s + 1)*(s + 3)), (s + 3)*(s**2 + 4)*(s**2 + s + 1), s) + >>> (tf9 * tf10 - tf11 * tf12).rewrite(TransferFunction) + TransferFunction(-(1 - s)*(s + 3)*(s**2 + s + 1)*(4*s**2 + 2*s - 4) + (-p + s)*(s - 1)*(s + 1)*(s**2 + 4), (s - 1)*(s + 3)*(s**2 + 4)*(s**2 + s + 1), s) + + See Also + ======== + + Feedback, Series, Parallel + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Transfer_function + .. [2] https://en.wikipedia.org/wiki/Laplace_transform + + """ + def __new__(cls, num, den, var): + num, den = _sympify(num), _sympify(den) + + if not isinstance(var, Symbol): + raise TypeError("Variable input must be a Symbol.") + + if den == 0: + raise ValueError("TransferFunction cannot have a zero denominator.") + + if (((isinstance(num, (Expr, TransferFunction, Series, Parallel)) and num.has(Symbol)) or num.is_number) and + ((isinstance(den, (Expr, TransferFunction, Series, Parallel)) and den.has(Symbol)) or den.is_number)): + cls.is_StateSpace_object = False + return super(TransferFunction, cls).__new__(cls, num, den, var) + + else: + raise TypeError("Unsupported type for numerator or denominator of TransferFunction.") + + @classmethod + def from_rational_expression(cls, expr, var=None): + r""" + Creates a new ``TransferFunction`` efficiently from a rational expression. + + Parameters + ========== + + expr : Expr, Number + The rational expression representing the ``TransferFunction``. + var : Symbol, optional + Complex variable of the Laplace transform used by the + polynomials of the transfer function. + + Raises + ====== + + ValueError + When ``expr`` is of type ``Number`` and optional parameter ``var`` + is not passed. + + When ``expr`` has more than one variables and an optional parameter + ``var`` is not passed. + ZeroDivisionError + When denominator of ``expr`` is zero or it has ``ComplexInfinity`` + in its numerator. + + Examples + ======== + + >>> from sympy.abc import s, p, a + >>> from sympy.physics.control.lti import TransferFunction + >>> expr1 = (s + 5)/(3*s**2 + 2*s + 1) + >>> tf1 = TransferFunction.from_rational_expression(expr1) + >>> tf1 + TransferFunction(s + 5, 3*s**2 + 2*s + 1, s) + >>> expr2 = (a*p**3 - a*p**2 + s*p)/(p + a**2) # Expr with more than one variables + >>> tf2 = TransferFunction.from_rational_expression(expr2, p) + >>> tf2 + TransferFunction(a*p**3 - a*p**2 + p*s, a**2 + p, p) + + In case of conflict between two or more variables in a expression, SymPy will + raise a ``ValueError``, if ``var`` is not passed by the user. + + >>> tf = TransferFunction.from_rational_expression((a + a*s)/(s**2 + s + 1)) + Traceback (most recent call last): + ... + ValueError: Conflicting values found for positional argument `var` ({a, s}). Specify it manually. + + This can be corrected by specifying the ``var`` parameter manually. + + >>> tf = TransferFunction.from_rational_expression((a + a*s)/(s**2 + s + 1), s) + >>> tf + TransferFunction(a*s + a, s**2 + s + 1, s) + + ``var`` also need to be specified when ``expr`` is a ``Number`` + + >>> tf3 = TransferFunction.from_rational_expression(10, s) + >>> tf3 + TransferFunction(10, 1, s) + + """ + expr = _sympify(expr) + if var is None: + _free_symbols = expr.free_symbols + _len_free_symbols = len(_free_symbols) + if _len_free_symbols == 1: + var = list(_free_symbols)[0] + elif _len_free_symbols == 0: + raise ValueError(filldedent(""" + Positional argument `var` not found in the + TransferFunction defined. Specify it manually.""")) + else: + raise ValueError(filldedent(""" + Conflicting values found for positional argument `var` ({}). + Specify it manually.""".format(_free_symbols))) + + _num, _den = expr.as_numer_denom() + if _den == 0 or _num.has(S.ComplexInfinity): + raise ZeroDivisionError("TransferFunction cannot have a zero denominator.") + return cls(_num, _den, var) + + @classmethod + def from_coeff_lists(cls, num_list, den_list, var): + r""" + Creates a new ``TransferFunction`` efficiently from a list of coefficients. + + Parameters + ========== + + num_list : Sequence + Sequence comprising of numerator coefficients. + den_list : Sequence + Sequence comprising of denominator coefficients. + var : Symbol + Complex variable of the Laplace transform used by the + polynomials of the transfer function. + + Raises + ====== + + ZeroDivisionError + When the constructed denominator is zero. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction + >>> num = [1, 0, 2] + >>> den = [3, 2, 2, 1] + >>> tf = TransferFunction.from_coeff_lists(num, den, s) + >>> tf + TransferFunction(s**2 + 2, 3*s**3 + 2*s**2 + 2*s + 1, s) + >>> #Create a Transfer Function with more than one variable + >>> tf1 = TransferFunction.from_coeff_lists([p, 1], [2*p, 0, 4], s) + >>> tf1 + TransferFunction(p*s + 1, 2*p*s**2 + 4, s) + + """ + num_list = num_list[::-1] + den_list = den_list[::-1] + num_var_powers = [var**i for i in range(len(num_list))] + den_var_powers = [var**i for i in range(len(den_list))] + + _num = sum(coeff * var_power for coeff, var_power in zip(num_list, num_var_powers)) + _den = sum(coeff * var_power for coeff, var_power in zip(den_list, den_var_powers)) + + if _den == 0: + raise ZeroDivisionError("TransferFunction cannot have a zero denominator.") + + return cls(_num, _den, var) + + @classmethod + def from_zpk(cls, zeros, poles, gain, var): + r""" + Creates a new ``TransferFunction`` from given zeros, poles and gain. + + Parameters + ========== + + zeros : Sequence + Sequence comprising of zeros of transfer function. + poles : Sequence + Sequence comprising of poles of transfer function. + gain : Number, Symbol, Expression + A scalar value specifying gain of the model. + var : Symbol + Complex variable of the Laplace transform used by the + polynomials of the transfer function. + + Examples + ======== + + >>> from sympy.abc import s, p, k + >>> from sympy.physics.control.lti import TransferFunction + >>> zeros = [1, 2, 3] + >>> poles = [6, 5, 4] + >>> gain = 7 + >>> tf = TransferFunction.from_zpk(zeros, poles, gain, s) + >>> tf + TransferFunction(7*(s - 3)*(s - 2)*(s - 1), (s - 6)*(s - 5)*(s - 4), s) + >>> #Create a Transfer Function with variable poles and zeros + >>> tf1 = TransferFunction.from_zpk([p, k], [p + k, p - k], 2, s) + >>> tf1 + TransferFunction(2*(-k + s)*(-p + s), (-k - p + s)*(k - p + s), s) + >>> #Complex poles or zeros are acceptable + >>> tf2 = TransferFunction.from_zpk([0], [1-1j, 1+1j, 2], -2, s) + >>> tf2 + TransferFunction(-2*s, (s - 2)*(s - 1.0 - 1.0*I)*(s - 1.0 + 1.0*I), s) + + """ + num_poly = 1 + den_poly = 1 + for zero in zeros: + num_poly *= var - zero + for pole in poles: + den_poly *= var - pole + + return cls(gain*num_poly, den_poly, var) + + @property + def num(self): + """ + Returns the numerator polynomial of the transfer function. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction + >>> G1 = TransferFunction(s**2 + p*s + 3, s - 4, s) + >>> G1.num + p*s + s**2 + 3 + >>> G2 = TransferFunction((p + 5)*(p - 3), (p - 3)*(p + 1), p) + >>> G2.num + (p - 3)*(p + 5) + + """ + return self.args[0] + + @property + def den(self): + """ + Returns the denominator polynomial of the transfer function. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction + >>> G1 = TransferFunction(s + 4, p**3 - 2*p + 4, s) + >>> G1.den + p**3 - 2*p + 4 + >>> G2 = TransferFunction(3, 4, s) + >>> G2.den + 4 + + """ + return self.args[1] + + @property + def var(self): + """ + Returns the complex variable of the Laplace transform used by the polynomials of + the transfer function. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction + >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) + >>> G1.var + p + >>> G2 = TransferFunction(0, s - 5, s) + >>> G2.var + s + + """ + return self.args[2] + + def _eval_subs(self, old, new): + arg_num = self.num.subs(old, new) + arg_den = self.den.subs(old, new) + argnew = TransferFunction(arg_num, arg_den, self.var) + return self if old == self.var else argnew + + def _eval_evalf(self, prec): + return TransferFunction( + self.num._eval_evalf(prec), + self.den._eval_evalf(prec), + self.var) + + def _eval_simplify(self, **kwargs): + tf = cancel(Mul(self.num, 1/self.den, evaluate=False), expand=False).as_numer_denom() + num_, den_ = tf[0], tf[1] + return TransferFunction(num_, den_, self.var) + + def _eval_rewrite_as_StateSpace(self, *args): + """ + Returns the equivalent space model of the transfer function model. + The state space model will be returned in the controllable canonical form. + + Unlike the space state to transfer function model conversion, the transfer function + to state space model conversion is not unique. There can be multiple state space + representations of a given transfer function model. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control import TransferFunction, StateSpace + >>> tf = TransferFunction(s**2 + 1, s**3 + 2*s + 10, s) + >>> tf.rewrite(StateSpace) + StateSpace(Matrix([ + [ 0, 1, 0], + [ 0, 0, 1], + [-10, -2, 0]]), Matrix([ + [0], + [0], + [1]]), Matrix([[1, 0, 1]]), Matrix([[0]])) + + """ + if not self.is_proper: + raise ValueError("Transfer Function must be proper.") + + num_poly = Poly(self.num, self.var) + den_poly = Poly(self.den, self.var) + n = den_poly.degree() + + num_coeffs = num_poly.all_coeffs() + den_coeffs = den_poly.all_coeffs() + diff = n - num_poly.degree() + num_coeffs = [0]*diff + num_coeffs + + a = den_coeffs[1:] + a_mat = Matrix([[(-1)*coefficient/den_coeffs[0] for coefficient in reversed(a)]]) + vert = zeros(n-1, 1) + mat = eye(n-1) + A = vert.row_join(mat) + A = A.col_join(a_mat) + + B = zeros(n, 1) + B[n-1] = 1 + + i = n + C = [] + while(i > 0): + C.append(num_coeffs[i] - den_coeffs[i]*num_coeffs[0]) + i -= 1 + C = Matrix([C]) + + D = Matrix([num_coeffs[0]]) + + return StateSpace(A, B, C, D) + + def expand(self): + """ + Returns the transfer function with numerator and denominator + in expanded form. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction + >>> G1 = TransferFunction((a - s)**2, (s**2 + a)**2, s) + >>> G1.expand() + TransferFunction(a**2 - 2*a*s + s**2, a**2 + 2*a*s**2 + s**4, s) + >>> G2 = TransferFunction((p + 3*b)*(p - b), (p - b)*(p + 2*b), p) + >>> G2.expand() + TransferFunction(-3*b**2 + 2*b*p + p**2, -2*b**2 + b*p + p**2, p) + + """ + return TransferFunction(expand(self.num), expand(self.den), self.var) + + def dc_gain(self): + """ + Computes the gain of the response as the frequency approaches zero. + + The DC gain is infinite for systems with pure integrators. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction + >>> tf1 = TransferFunction(s + 3, s**2 - 9, s) + >>> tf1.dc_gain() + -1/3 + >>> tf2 = TransferFunction(p**2, p - 3 + p**3, p) + >>> tf2.dc_gain() + 0 + >>> tf3 = TransferFunction(a*p**2 - b, s + b, s) + >>> tf3.dc_gain() + (a*p**2 - b)/b + >>> tf4 = TransferFunction(1, s, s) + >>> tf4.dc_gain() + oo + + """ + m = Mul(self.num, Pow(self.den, -1, evaluate=False), evaluate=False) + return limit(m, self.var, 0) + + def poles(self): + """ + Returns the poles of a transfer function. + + Examples + ======== + + >>> from sympy.abc import s, p, a + >>> from sympy.physics.control.lti import TransferFunction + >>> tf1 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) + >>> tf1.poles() + [-5, 1] + >>> tf2 = TransferFunction((1 - s)**2, (s**2 + 1)**2, s) + >>> tf2.poles() + [I, I, -I, -I] + >>> tf3 = TransferFunction(s**2, a*s + p, s) + >>> tf3.poles() + [-p/a] + + """ + return _roots(Poly(self.den, self.var), self.var) + + def zeros(self): + """ + Returns the zeros of a transfer function. + + Examples + ======== + + >>> from sympy.abc import s, p, a + >>> from sympy.physics.control.lti import TransferFunction + >>> tf1 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) + >>> tf1.zeros() + [-3, 1] + >>> tf2 = TransferFunction((1 - s)**2, (s**2 + 1)**2, s) + >>> tf2.zeros() + [1, 1] + >>> tf3 = TransferFunction(s**2, a*s + p, s) + >>> tf3.zeros() + [0, 0] + + """ + return _roots(Poly(self.num, self.var), self.var) + + def eval_frequency(self, other): + """ + Returns the system response at any point in the real or complex plane. + + Examples + ======== + + >>> from sympy.abc import s, p, a + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy import I + >>> tf1 = TransferFunction(1, s**2 + 2*s + 1, s) + >>> omega = 0.1 + >>> tf1.eval_frequency(I*omega) + 1/(0.99 + 0.2*I) + >>> tf2 = TransferFunction(s**2, a*s + p, s) + >>> tf2.eval_frequency(2) + 4/(2*a + p) + >>> tf2.eval_frequency(I*2) + -4/(2*I*a + p) + """ + arg_num = self.num.subs(self.var, other) + arg_den = self.den.subs(self.var, other) + argnew = TransferFunction(arg_num, arg_den, self.var).to_expr() + return argnew.expand() + + def is_stable(self): + """ + Returns True if the transfer function is asymptotically stable; else False. + + This would not check the marginal or conditional stability of the system. + + Examples + ======== + + >>> from sympy.abc import s, p, a + >>> from sympy import symbols + >>> from sympy.physics.control.lti import TransferFunction + >>> q, r = symbols('q, r', negative=True) + >>> tf1 = TransferFunction((1 - s)**2, (s + 1)**2, s) + >>> tf1.is_stable() + True + >>> tf2 = TransferFunction((1 - p)**2, (s**2 + 1)**2, s) + >>> tf2.is_stable() + False + >>> tf3 = TransferFunction(4, q*s - r, s) + >>> tf3.is_stable() + False + >>> tf4 = TransferFunction(p + 1, a*p - s**2, p) + >>> tf4.is_stable() is None # Not enough info about the symbols to determine stability + True + + """ + return fuzzy_and(pole.as_real_imag()[0].is_negative for pole in self.poles()) + + def __add__(self, other): + if hasattr(other, "is_StateSpace_object") and other.is_StateSpace_object: + return Parallel(self, other) + elif isinstance(other, (TransferFunction, Series, Feedback)): + if not self.var == other.var: + raise ValueError(filldedent(""" + All the transfer functions should use the same complex variable + of the Laplace transform.""")) + return Parallel(self, other) + elif isinstance(other, Parallel): + if not self.var == other.var: + raise ValueError(filldedent(""" + All the transfer functions should use the same complex variable + of the Laplace transform.""")) + arg_list = list(other.args) + return Parallel(self, *arg_list) + else: + raise ValueError("TransferFunction cannot be added with {}.". + format(type(other))) + + def __radd__(self, other): + return self + other + + def __sub__(self, other): + if hasattr(other, "is_StateSpace_object") and other.is_StateSpace_object: + return Parallel(self, -other) + elif isinstance(other, (TransferFunction, Series)): + if not self.var == other.var: + raise ValueError(filldedent(""" + All the transfer functions should use the same complex variable + of the Laplace transform.""")) + return Parallel(self, -other) + elif isinstance(other, Parallel): + if not self.var == other.var: + raise ValueError(filldedent(""" + All the transfer functions should use the same complex variable + of the Laplace transform.""")) + arg_list = [-i for i in list(other.args)] + return Parallel(self, *arg_list) + else: + raise ValueError("{} cannot be subtracted from a TransferFunction." + .format(type(other))) + + def __rsub__(self, other): + return -self + other + + def __mul__(self, other): + if hasattr(other, "is_StateSpace_object") and other.is_StateSpace_object: + return Series(self, other) + elif isinstance(other, (TransferFunction, Parallel, Feedback)): + if not self.var == other.var: + raise ValueError(filldedent(""" + All the transfer functions should use the same complex variable + of the Laplace transform.""")) + return Series(self, other) + elif isinstance(other, Series): + if not self.var == other.var: + raise ValueError(filldedent(""" + All the transfer functions should use the same complex variable + of the Laplace transform.""")) + arg_list = list(other.args) + return Series(self, *arg_list) + else: + raise ValueError("TransferFunction cannot be multiplied with {}." + .format(type(other))) + + __rmul__ = __mul__ + + def __truediv__(self, other): + if isinstance(other, TransferFunction): + if not self.var == other.var: + raise ValueError(filldedent(""" + All the transfer functions should use the same complex variable + of the Laplace transform.""")) + return Series(self, TransferFunction(other.den, other.num, self.var)) + elif (isinstance(other, Parallel) and len(other.args + ) == 2 and isinstance(other.args[0], TransferFunction) + and isinstance(other.args[1], (Series, TransferFunction))): + + if not self.var == other.var: + raise ValueError(filldedent(""" + Both TransferFunction and Parallel should use the + same complex variable of the Laplace transform.""")) + if other.args[1] == self: + # plant and controller with unit feedback. + return Feedback(self, other.args[0]) + other_arg_list = list(other.args[1].args) if isinstance( + other.args[1], Series) else other.args[1] + if other_arg_list == other.args[1]: + return Feedback(self, other_arg_list) + elif self in other_arg_list: + other_arg_list.remove(self) + else: + return Feedback(self, Series(*other_arg_list)) + + if len(other_arg_list) == 1: + return Feedback(self, *other_arg_list) + else: + return Feedback(self, Series(*other_arg_list)) + else: + raise ValueError("TransferFunction cannot be divided by {}.". + format(type(other))) + + __rtruediv__ = __truediv__ + + def __pow__(self, p): + p = sympify(p) + if not p.is_Integer: + raise ValueError("Exponent must be an integer.") + if p is S.Zero: + return TransferFunction(1, 1, self.var) + elif p > 0: + num_, den_ = self.num**p, self.den**p + else: + p = abs(p) + num_, den_ = self.den**p, self.num**p + + return TransferFunction(num_, den_, self.var) + + def __neg__(self): + return TransferFunction(-self.num, self.den, self.var) + + @property + def is_proper(self): + """ + Returns True if degree of the numerator polynomial is less than + or equal to degree of the denominator polynomial, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction + >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) + >>> tf1.is_proper + False + >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*p + 2, p) + >>> tf2.is_proper + True + + """ + return degree(self.num, self.var) <= degree(self.den, self.var) + + @property + def is_strictly_proper(self): + """ + Returns True if degree of the numerator polynomial is strictly less + than degree of the denominator polynomial, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf1.is_strictly_proper + False + >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) + >>> tf2.is_strictly_proper + True + + """ + return degree(self.num, self.var) < degree(self.den, self.var) + + @property + def is_biproper(self): + """ + Returns True if degree of the numerator polynomial is equal to + degree of the denominator polynomial, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf1.is_biproper + True + >>> tf2 = TransferFunction(p**2, p + a, p) + >>> tf2.is_biproper + False + + """ + return degree(self.num, self.var) == degree(self.den, self.var) + + def to_expr(self): + """ + Converts a ``TransferFunction`` object to SymPy Expr. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction + >>> from sympy import Expr + >>> tf1 = TransferFunction(s, a*s**2 + 1, s) + >>> tf1.to_expr() + s/(a*s**2 + 1) + >>> isinstance(_, Expr) + True + >>> tf2 = TransferFunction(1, (p + 3*b)*(b - p), p) + >>> tf2.to_expr() + 1/((b - p)*(3*b + p)) + >>> tf3 = TransferFunction((s - 2)*(s - 3), (s - 1)*(s - 2)*(s - 3), s) + >>> tf3.to_expr() + ((s - 3)*(s - 2))/(((s - 3)*(s - 2)*(s - 1))) + + """ + + if self.num != 1: + return Mul(self.num, Pow(self.den, -1, evaluate=False), evaluate=False) + else: + return Pow(self.den, -1, evaluate=False) + + +class PIDController(TransferFunction): + r""" + A class for representing PID (Proportional-Integral-Derivative) + controllers in control systems. The PIDController class is a subclass + of TransferFunction, representing the controller's transfer function + in the Laplace domain. The arguments are ``kp``, ``ki``, ``kd``, + ``tf``, and ``var``, where ``kp``, ``ki``, and ``kd`` are the + proportional, integral, and derivative gains respectively.``tf`` + is the derivative filter time constant, which can be used to + filter out the noise and ``var`` is the complex variable used in + the transfer function. + + Parameters + ========== + + kp : Expr, Number + Proportional gain. Defaults to ``Symbol('kp')`` if not specified. + ki : Expr, Number + Integral gain. Defaults to ``Symbol('ki')`` if not specified. + kd : Expr, Number + Derivative gain. Defaults to ``Symbol('kd')`` if not specified. + tf : Expr, Number + Derivative filter time constant. Defaults to ``0`` if not specified. + var : Symbol + The complex frequency variable. Defaults to ``s`` if not specified. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.control.lti import PIDController + >>> kp, ki, kd = symbols('kp ki kd') + >>> p1 = PIDController(kp, ki, kd) + >>> print(p1) + PIDController(kp, ki, kd, 0, s) + >>> p1.doit() + TransferFunction(kd*s**2 + ki + kp*s, s, s) + >>> p1.kp + kp + >>> p1.ki + ki + >>> p1.kd + kd + >>> p1.tf + 0 + >>> p1.var + s + >>> p1.to_expr() + (kd*s**2 + ki + kp*s)/s + + See Also + ======== + + TransferFunction + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/PID_controller + .. [2] https://in.mathworks.com/help/control/ug/proportional-integral-derivative-pid-controllers.html + + """ + def __new__(cls, kp=Symbol('kp'), ki=Symbol('ki'), kd=Symbol('kd'), tf=0, var=Symbol('s')): + kp, ki, kd, tf = _sympify(kp), _sympify(ki), _sympify(kd), _sympify(tf) + num = kp*tf*var**2 + kp*var + ki*tf*var + ki + kd*var**2 + den = tf*var**2 + var + obj = TransferFunction.__new__(cls, num, den, var) + obj._kp, obj._ki, obj._kd, obj._tf = kp, ki, kd, tf + return obj + + def __repr__(self): + return f"PIDController({self.kp}, {self.ki}, {self.kd}, {self.tf}, {self.var})" + + __str__ = __repr__ + + @property + def kp(self): + """ + Returns the Proportional gain (kp) of the PIDController. + """ + return self._kp + + @property + def ki(self): + """ + Returns the Integral gain (ki) of the PIDController. + """ + return self._ki + + @property + def kd(self): + """ + Returns the Derivative gain (kd) of the PIDController. + """ + return self._kd + + @property + def tf(self): + """ + Returns the Derivative filter time constant (tf) of the PIDController. + """ + return self._tf + + def doit(self): + """ + Convert the PIDController into TransferFunction. + """ + return TransferFunction(self.num, self.den, self.var) + + +def _flatten_args(args, _cls): + temp_args = [] + for arg in args: + if isinstance(arg, _cls): + temp_args.extend(arg.args) + else: + temp_args.append(arg) + return tuple(temp_args) + + +def _dummify_args(_arg, var): + dummy_dict = {} + dummy_arg_list = [] + + for arg in _arg: + _s = Dummy() + dummy_dict[_s] = var + dummy_arg = arg.subs({var: _s}) + dummy_arg_list.append(dummy_arg) + + return dummy_arg_list, dummy_dict + + +class Series(SISOLinearTimeInvariant): + r""" + A class for representing a series configuration of SISO systems. + + Parameters + ========== + + args : SISOLinearTimeInvariant + SISO systems in a series configuration. + evaluate : Boolean, Keyword + When passed ``True``, returns the equivalent + ``Series(*args).doit()``. Set to ``False`` by default. + + Raises + ====== + + ValueError + When no argument is passed. + + ``var`` attribute is not same for every system. + TypeError + Any of the passed ``*args`` has unsupported type + + A combination of SISO and MIMO systems is + passed. There should be homogeneity in the + type of systems passed, SISO in this case. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy import Matrix + >>> from sympy.physics.control.lti import TransferFunction, Series, Parallel, StateSpace + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) + >>> tf3 = TransferFunction(p**2, p + s, s) + >>> S1 = Series(tf1, tf2) + >>> S1 + Series(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)) + >>> S1.var + s + >>> S2 = Series(tf2, Parallel(tf3, -tf1)) + >>> S2 + Series(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), Parallel(TransferFunction(p**2, p + s, s), TransferFunction(-a*p**2 - b*s, -p + s, s))) + >>> S2.var + s + >>> S3 = Series(Parallel(tf1, tf2), Parallel(tf2, tf3)) + >>> S3 + Series(Parallel(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)), Parallel(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), TransferFunction(p**2, p + s, s))) + >>> S3.var + s + + You can get the resultant transfer function by using ``.doit()`` method: + + >>> S3 = Series(tf1, tf2, -tf3) + >>> S3.doit() + TransferFunction(-p**2*(s**3 - 2)*(a*p**2 + b*s), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) + >>> S4 = Series(tf2, Parallel(tf1, -tf3)) + >>> S4.doit() + TransferFunction((s**3 - 2)*(-p**2*(-p + s) + (p + s)*(a*p**2 + b*s)), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) + + You can also connect StateSpace which results in SISO + + >>> A1 = Matrix([[-1]]) + >>> B1 = Matrix([[1]]) + >>> C1 = Matrix([[-1]]) + >>> D1 = Matrix([1]) + >>> A2 = Matrix([[0]]) + >>> B2 = Matrix([[1]]) + >>> C2 = Matrix([[1]]) + >>> D2 = Matrix([[0]]) + >>> ss1 = StateSpace(A1, B1, C1, D1) + >>> ss2 = StateSpace(A2, B2, C2, D2) + >>> S5 = Series(ss1, ss2) + >>> S5 + Series(StateSpace(Matrix([[-1]]), Matrix([[1]]), Matrix([[-1]]), Matrix([[1]])), StateSpace(Matrix([[0]]), Matrix([[1]]), Matrix([[1]]), Matrix([[0]]))) + >>> S5.doit() + StateSpace(Matrix([ + [-1, 0], + [-1, 0]]), Matrix([ + [1], + [1]]), Matrix([[0, 1]]), Matrix([[0]])) + + Notes + ===== + + All the transfer functions should use the same complex variable + ``var`` of the Laplace transform. + + See Also + ======== + + MIMOSeries, Parallel, TransferFunction, Feedback + + """ + def __new__(cls, *args, evaluate=False): + + args = _flatten_args(args, Series) + # For StateSpace series connection + if args and any(isinstance(arg, StateSpace) or (hasattr(arg, 'is_StateSpace_object') + and arg.is_StateSpace_object)for arg in args): + # Check for SISO + if (args[0].num_inputs == 1) and (args[-1].num_outputs == 1): + # Check the interconnection + for i in range(1, len(args)): + if args[i].num_inputs != args[i-1].num_outputs: + raise ValueError(filldedent("""Systems with incompatible inputs and outputs + cannot be connected in Series.""")) + cls._is_series_StateSpace = True + else: + raise ValueError("To use Series connection for MIMO systems use MIMOSeries instead.") + else: + cls._is_series_StateSpace = False + cls._check_args(args) + + obj = super().__new__(cls, *args) + + return obj.doit() if evaluate else obj + + def __repr__(self): + systems_repr = ', '.join(repr(system) for system in self.args) + return f"Series({systems_repr})" + + __str__ = __repr__ + + @property + def var(self): + """ + Returns the complex variable used by all the transfer functions. + + Examples + ======== + + >>> from sympy.abc import p + >>> from sympy.physics.control.lti import TransferFunction, Series, Parallel + >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) + >>> G2 = TransferFunction(p, 4 - p, p) + >>> G3 = TransferFunction(0, p**4 - 1, p) + >>> Series(G1, G2).var + p + >>> Series(-G3, Parallel(G1, G2)).var + p + + """ + return self.args[0].var + + def doit(self, **hints): + """ + Returns the resultant transfer function or StateSpace obtained after evaluating + the series interconnection. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Series + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) + >>> Series(tf2, tf1).doit() + TransferFunction((s**3 - 2)*(a*p**2 + b*s), (-p + s)*(s**4 + 5*s + 6), s) + >>> Series(-tf1, -tf2).doit() + TransferFunction((2 - s**3)*(-a*p**2 - b*s), (-p + s)*(s**4 + 5*s + 6), s) + + Notes + ===== + + If a series connection contains only TransferFunction components, the equivalent system returned + will be a TransferFunction. However, if a StateSpace object is used in any of the arguments, + the output will be a StateSpace object. + + """ + # Check if the system is a StateSpace + if self._is_series_StateSpace: + # Return the equivalent StateSpace model + res = self.args[0] + if not isinstance(res, StateSpace): + res = res.doit().rewrite(StateSpace) + for arg in self.args[1:]: + if not isinstance(arg, StateSpace): + arg = arg.doit().rewrite(StateSpace) + else: + arg = arg.doit() + arg = arg.doit() + res = arg * res + return res + + _num_arg = (arg.doit().num for arg in self.args) + _den_arg = (arg.doit().den for arg in self.args) + res_num = Mul(*_num_arg, evaluate=True) + res_den = Mul(*_den_arg, evaluate=True) + return TransferFunction(res_num, res_den, self.var) + + def _eval_rewrite_as_TransferFunction(self, *args, **kwargs): + if self._is_series_StateSpace: + return self.doit().rewrite(TransferFunction)[0][0] + return self.doit() + + @_check_other_SISO + def __add__(self, other): + + if isinstance(other, Parallel): + arg_list = list(other.args) + return Parallel(self, *arg_list) + + return Parallel(self, other) + + __radd__ = __add__ + + @_check_other_SISO + def __sub__(self, other): + return self + (-other) + + def __rsub__(self, other): + return -self + other + + @_check_other_SISO + def __mul__(self, other): + + arg_list = list(self.args) + return Series(*arg_list, other) + + def __truediv__(self, other): + if isinstance(other, TransferFunction): + return Series(*self.args, TransferFunction(other.den, other.num, other.var)) + elif isinstance(other, Series): + tf_self = self.rewrite(TransferFunction) + tf_other = other.rewrite(TransferFunction) + return tf_self / tf_other + elif (isinstance(other, Parallel) and len(other.args) == 2 + and isinstance(other.args[0], TransferFunction) and isinstance(other.args[1], Series)): + + if not self.var == other.var: + raise ValueError(filldedent(""" + All the transfer functions should use the same complex variable + of the Laplace transform.""")) + self_arg_list = set(self.args) + other_arg_list = set(other.args[1].args) + res = list(self_arg_list ^ other_arg_list) + if len(res) == 0: + return Feedback(self, other.args[0]) + elif len(res) == 1: + return Feedback(self, *res) + else: + return Feedback(self, Series(*res)) + else: + raise ValueError("This transfer function expression is invalid.") + + def __neg__(self): + return Series(TransferFunction(-1, 1, self.var), self) + + def to_expr(self): + """Returns the equivalent ``Expr`` object.""" + return Mul(*(arg.to_expr() for arg in self.args), evaluate=False) + + @property + def is_proper(self): + """ + Returns True if degree of the numerator polynomial of the resultant transfer + function is less than or equal to degree of the denominator polynomial of + the same, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Series + >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) + >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*s + 2, s) + >>> tf3 = TransferFunction(s, s**2 + s + 1, s) + >>> S1 = Series(-tf2, tf1) + >>> S1.is_proper + False + >>> S2 = Series(tf1, tf2, tf3) + >>> S2.is_proper + True + + """ + return self.doit().is_proper + + @property + def is_strictly_proper(self): + """ + Returns True if degree of the numerator polynomial of the resultant transfer + function is strictly less than degree of the denominator polynomial of + the same, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Series + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(s**3 - 2, s**2 + 5*s + 6, s) + >>> tf3 = TransferFunction(1, s**2 + s + 1, s) + >>> S1 = Series(tf1, tf2) + >>> S1.is_strictly_proper + False + >>> S2 = Series(tf1, tf2, tf3) + >>> S2.is_strictly_proper + True + + """ + return self.doit().is_strictly_proper + + @property + def is_biproper(self): + r""" + Returns True if degree of the numerator polynomial of the resultant transfer + function is equal to degree of the denominator polynomial of + the same, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Series + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(p, s**2, s) + >>> tf3 = TransferFunction(s**2, 1, s) + >>> S1 = Series(tf1, -tf2) + >>> S1.is_biproper + False + >>> S2 = Series(tf2, tf3) + >>> S2.is_biproper + True + + """ + return self.doit().is_biproper + + @property + def is_StateSpace_object(self): + return self._is_series_StateSpace + +def _mat_mul_compatible(*args): + """To check whether shapes are compatible for matrix mul.""" + return all(args[i].num_outputs == args[i+1].num_inputs for i in range(len(args)-1)) + + +class MIMOSeries(MIMOLinearTimeInvariant): + r""" + A class for representing a series configuration of MIMO systems. + + Parameters + ========== + + args : MIMOLinearTimeInvariant + MIMO systems in a series configuration. + evaluate : Boolean, Keyword + When passed ``True``, returns the equivalent + ``MIMOSeries(*args).doit()``. Set to ``False`` by default. + + Raises + ====== + + ValueError + When no argument is passed. + + ``var`` attribute is not same for every system. + + ``num_outputs`` of the MIMO system is not equal to the + ``num_inputs`` of its adjacent MIMO system. (Matrix + multiplication constraint, basically) + TypeError + Any of the passed ``*args`` has unsupported type + + A combination of SISO and MIMO systems is + passed. There should be homogeneity in the + type of systems passed, MIMO in this case. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import MIMOSeries, TransferFunctionMatrix, StateSpace + >>> from sympy import Matrix, pprint + >>> mat_a = Matrix([[5*s], [5]]) # 2 Outputs 1 Input + >>> mat_b = Matrix([[5, 1/(6*s**2)]]) # 1 Output 2 Inputs + >>> mat_c = Matrix([[1, s], [5/s, 1]]) # 2 Outputs 2 Inputs + >>> tfm_a = TransferFunctionMatrix.from_Matrix(mat_a, s) + >>> tfm_b = TransferFunctionMatrix.from_Matrix(mat_b, s) + >>> tfm_c = TransferFunctionMatrix.from_Matrix(mat_c, s) + >>> MIMOSeries(tfm_c, tfm_b, tfm_a) + MIMOSeries(TransferFunctionMatrix(((TransferFunction(1, 1, s), TransferFunction(s, 1, s)), (TransferFunction(5, s, s), TransferFunction(1, 1, s)))), TransferFunctionMatrix(((TransferFunction(5, 1, s), TransferFunction(1, 6*s**2, s)),)), TransferFunctionMatrix(((TransferFunction(5*s, 1, s),), (TransferFunction(5, 1, s),)))) + >>> pprint(_, use_unicode=False) # For Better Visualization + [5*s] [1 s] + [---] [5 1 ] [- -] + [ 1 ] [- ----] [1 1] + [ ] *[1 2] *[ ] + [ 5 ] [ 6*s ]{t} [5 1] + [ - ] [- -] + [ 1 ]{t} [s 1]{t} + >>> MIMOSeries(tfm_c, tfm_b, tfm_a).doit() + TransferFunctionMatrix(((TransferFunction(150*s**4 + 25*s, 6*s**3, s), TransferFunction(150*s**4 + 5*s, 6*s**2, s)), (TransferFunction(150*s**3 + 25, 6*s**3, s), TransferFunction(150*s**3 + 5, 6*s**2, s)))) + >>> pprint(_, use_unicode=False) # (2 Inputs -A-> 2 Outputs) -> (2 Inputs -B-> 1 Output) -> (1 Input -C-> 2 Outputs) is equivalent to (2 Inputs -Series Equivalent-> 2 Outputs). + [ 4 4 ] + [150*s + 25*s 150*s + 5*s] + [------------- ------------] + [ 3 2 ] + [ 6*s 6*s ] + [ ] + [ 3 3 ] + [ 150*s + 25 150*s + 5 ] + [ ----------- ---------- ] + [ 3 2 ] + [ 6*s 6*s ]{t} + >>> a1 = Matrix([[4, 1], [2, -3]]) + >>> b1 = Matrix([[5, 2], [-3, -3]]) + >>> c1 = Matrix([[2, -4], [0, 1]]) + >>> d1 = Matrix([[3, 2], [1, -1]]) + >>> a2 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) + >>> b2 = Matrix([[1, 4], [-3, -3], [-2, 1]]) + >>> c2 = Matrix([[4, 2, -3], [1, 4, 3]]) + >>> d2 = Matrix([[-2, 4], [0, 1]]) + >>> ss1 = StateSpace(a1, b1, c1, d1) #2 inputs, 2 outputs + >>> ss2 = StateSpace(a2, b2, c2, d2) #2 inputs, 2 outputs + >>> S1 = MIMOSeries(ss1, ss2) #(2 inputs, 2 outputs) -> (2 inputs, 2 outputs) + >>> S1 + MIMOSeries(StateSpace(Matrix([ + [4, 1], + [2, -3]]), Matrix([ + [ 5, 2], + [-3, -3]]), Matrix([ + [2, -4], + [0, 1]]), Matrix([ + [3, 2], + [1, -1]])), StateSpace(Matrix([ + [-3, 4, 2], + [-1, -3, 0], + [ 2, 5, 3]]), Matrix([ + [ 1, 4], + [-3, -3], + [-2, 1]]), Matrix([ + [4, 2, -3], + [1, 4, 3]]), Matrix([ + [-2, 4], + [ 0, 1]]))) + >>> S1.doit() + StateSpace(Matrix([ + [ 4, 1, 0, 0, 0], + [ 2, -3, 0, 0, 0], + [ 2, 0, -3, 4, 2], + [-6, 9, -1, -3, 0], + [-4, 9, 2, 5, 3]]), Matrix([ + [ 5, 2], + [ -3, -3], + [ 7, -2], + [-12, -3], + [ -5, -5]]), Matrix([ + [-4, 12, 4, 2, -3], + [ 0, 1, 1, 4, 3]]), Matrix([ + [-2, -8], + [ 1, -1]])) + + Notes + ===== + + All the transfer function matrices should use the same complex variable ``var`` of the Laplace transform. + + ``MIMOSeries(A, B)`` is not equivalent to ``A*B``. It is always in the reverse order, that is ``B*A``. + + See Also + ======== + + Series, MIMOParallel + + """ + def __new__(cls, *args, evaluate=False): + + if args and any(isinstance(arg, StateSpace) or (hasattr(arg, 'is_StateSpace_object') + and arg.is_StateSpace_object) for arg in args): + # Check compatibility + for i in range(1, len(args)): + if args[i].num_inputs != args[i - 1].num_outputs: + raise ValueError(filldedent("""Systems with incompatible inputs and outputs + cannot be connected in MIMOSeries.""")) + obj = super().__new__(cls, *args) + cls._is_series_StateSpace = True + else: + cls._check_args(args) + cls._is_series_StateSpace = False + + if _mat_mul_compatible(*args): + obj = super().__new__(cls, *args) + + else: + raise ValueError(filldedent(""" + Number of input signals do not match the number + of output signals of adjacent systems for some args.""")) + + return obj.doit() if evaluate else obj + + @property + def var(self): + """ + Returns the complex variable used by all the transfer functions. + + Examples + ======== + + >>> from sympy.abc import p + >>> from sympy.physics.control.lti import TransferFunction, MIMOSeries, TransferFunctionMatrix + >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) + >>> G2 = TransferFunction(p, 4 - p, p) + >>> G3 = TransferFunction(0, p**4 - 1, p) + >>> tfm_1 = TransferFunctionMatrix([[G1, G2, G3]]) + >>> tfm_2 = TransferFunctionMatrix([[G1], [G2], [G3]]) + >>> MIMOSeries(tfm_2, tfm_1).var + p + + """ + return self.args[0].var + + @property + def num_inputs(self): + """Returns the number of input signals of the series system.""" + return self.args[0].num_inputs + + @property + def num_outputs(self): + """Returns the number of output signals of the series system.""" + return self.args[-1].num_outputs + + @property + def shape(self): + """Returns the shape of the equivalent MIMO system.""" + return self.num_outputs, self.num_inputs + + @property + def is_StateSpace_object(self): + return self._is_series_StateSpace + + def doit(self, cancel=False, **kwargs): + """ + Returns the resultant obtained after evaluating the MIMO systems arranged + in a series configuration. For TransferFunction systems it returns a TransferFunctionMatrix + and for StateSpace systems it returns the resultant StateSpace system. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, MIMOSeries, TransferFunctionMatrix + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) + >>> tfm1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf2]]) + >>> tfm2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf1]]) + >>> MIMOSeries(tfm2, tfm1).doit() + TransferFunctionMatrix(((TransferFunction(2*(-p + s)*(s**3 - 2)*(a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)**2*(s**4 + 5*s + 6)**2, s), TransferFunction((-p + s)**2*(s**3 - 2)*(a*p**2 + b*s) + (-p + s)*(a*p**2 + b*s)**2*(s**4 + 5*s + 6), (-p + s)**3*(s**4 + 5*s + 6), s)), (TransferFunction((-p + s)*(s**3 - 2)**2*(s**4 + 5*s + 6) + (s**3 - 2)*(a*p**2 + b*s)*(s**4 + 5*s + 6)**2, (-p + s)*(s**4 + 5*s + 6)**3, s), TransferFunction(2*(s**3 - 2)*(a*p**2 + b*s), (-p + s)*(s**4 + 5*s + 6), s)))) + + """ + if self._is_series_StateSpace: + # Return the equivalent StateSpace model + res = self.args[0] + if not isinstance(res, StateSpace): + res = res.doit().rewrite(StateSpace) + for arg in self.args[1:]: + if not isinstance(arg, StateSpace): + arg = arg.doit().rewrite(StateSpace) + else: + arg = arg.doit() + res = arg * res + return res + + _arg = (arg.doit()._expr_mat for arg in reversed(self.args)) + + if cancel: + res = MatMul(*_arg, evaluate=True) + return TransferFunctionMatrix.from_Matrix(res, self.var) + + _dummy_args, _dummy_dict = _dummify_args(_arg, self.var) + res = MatMul(*_dummy_args, evaluate=True) + temp_tfm = TransferFunctionMatrix.from_Matrix(res, self.var) + return temp_tfm.subs(_dummy_dict) + + def _eval_rewrite_as_TransferFunctionMatrix(self, *args, **kwargs): + if self._is_series_StateSpace: + return self.doit().rewrite(TransferFunction) + return self.doit() + + @_check_other_MIMO + def __add__(self, other): + + if isinstance(other, MIMOParallel): + arg_list = list(other.args) + return MIMOParallel(self, *arg_list) + + return MIMOParallel(self, other) + + __radd__ = __add__ + + @_check_other_MIMO + def __sub__(self, other): + return self + (-other) + + def __rsub__(self, other): + return -self + other + + @_check_other_MIMO + def __mul__(self, other): + + if isinstance(other, MIMOSeries): + self_arg_list = list(self.args) + other_arg_list = list(other.args) + return MIMOSeries(*other_arg_list, *self_arg_list) # A*B = MIMOSeries(B, A) + + arg_list = list(self.args) + return MIMOSeries(other, *arg_list) + + def __neg__(self): + arg_list = list(self.args) + arg_list[0] = -arg_list[0] + return MIMOSeries(*arg_list) + + +class Parallel(SISOLinearTimeInvariant): + r""" + A class for representing a parallel configuration of SISO systems. + + Parameters + ========== + + args : SISOLinearTimeInvariant + SISO systems in a parallel arrangement. + evaluate : Boolean, Keyword + When passed ``True``, returns the equivalent + ``Parallel(*args).doit()``. Set to ``False`` by default. + + Raises + ====== + + ValueError + When no argument is passed. + + ``var`` attribute is not same for every system. + TypeError + Any of the passed ``*args`` has unsupported type + + A combination of SISO and MIMO systems is + passed. There should be homogeneity in the + type of systems passed. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Parallel, Series, StateSpace + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) + >>> tf3 = TransferFunction(p**2, p + s, s) + >>> P1 = Parallel(tf1, tf2) + >>> P1 + Parallel(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)) + >>> P1.var + s + >>> P2 = Parallel(tf2, Series(tf3, -tf1)) + >>> P2 + Parallel(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), Series(TransferFunction(p**2, p + s, s), TransferFunction(-a*p**2 - b*s, -p + s, s))) + >>> P2.var + s + >>> P3 = Parallel(Series(tf1, tf2), Series(tf2, tf3)) + >>> P3 + Parallel(Series(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)), Series(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), TransferFunction(p**2, p + s, s))) + >>> P3.var + s + + You can get the resultant transfer function by using ``.doit()`` method: + + >>> Parallel(tf1, tf2, -tf3).doit() + TransferFunction(-p**2*(-p + s)*(s**4 + 5*s + 6) + (-p + s)*(p + s)*(s**3 - 2) + (p + s)*(a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) + >>> Parallel(tf2, Series(tf1, -tf3)).doit() + TransferFunction(-p**2*(a*p**2 + b*s)*(s**4 + 5*s + 6) + (-p + s)*(p + s)*(s**3 - 2), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) + + Parallel can be used to connect SISO ``StateSpace`` systems together. + + >>> A1 = Matrix([[-1]]) + >>> B1 = Matrix([[1]]) + >>> C1 = Matrix([[-1]]) + >>> D1 = Matrix([1]) + >>> A2 = Matrix([[0]]) + >>> B2 = Matrix([[1]]) + >>> C2 = Matrix([[1]]) + >>> D2 = Matrix([[0]]) + >>> ss1 = StateSpace(A1, B1, C1, D1) + >>> ss2 = StateSpace(A2, B2, C2, D2) + >>> P4 = Parallel(ss1, ss2) + >>> P4 + Parallel(StateSpace(Matrix([[-1]]), Matrix([[1]]), Matrix([[-1]]), Matrix([[1]])), StateSpace(Matrix([[0]]), Matrix([[1]]), Matrix([[1]]), Matrix([[0]]))) + + ``doit()`` can be used to find ``StateSpace`` equivalent for the system containing ``StateSpace`` objects. + + >>> P4.doit() + StateSpace(Matrix([ + [-1, 0], + [ 0, 0]]), Matrix([ + [1], + [1]]), Matrix([[-1, 1]]), Matrix([[1]])) + >>> P4.rewrite(TransferFunction) + TransferFunction(s*(s + 1) + 1, s*(s + 1), s) + + Notes + ===== + + All the transfer functions should use the same complex variable + ``var`` of the Laplace transform. + + See Also + ======== + + Series, TransferFunction, Feedback + + """ + + def __new__(cls, *args, evaluate=False): + + args = _flatten_args(args, Parallel) + # For StateSpace parallel connection + if args and any(isinstance(arg, StateSpace) or (hasattr(arg, 'is_StateSpace_object') + and arg.is_StateSpace_object) for arg in args): + # Check for SISO + if all(arg.is_SISO for arg in args): + cls._is_parallel_StateSpace = True + else: + raise ValueError("To use Parallel connection for MIMO systems use MIMOParallel instead.") + else: + cls._is_parallel_StateSpace = False + cls._check_args(args) + obj = super().__new__(cls, *args) + + return obj.doit() if evaluate else obj + + def __repr__(self): + systems_repr = ', '.join(repr(system) for system in self.args) + return f"Parallel({systems_repr})" + + __str__ = __repr__ + + @property + def var(self): + """ + Returns the complex variable used by all the transfer functions. + + Examples + ======== + + >>> from sympy.abc import p + >>> from sympy.physics.control.lti import TransferFunction, Parallel, Series + >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) + >>> G2 = TransferFunction(p, 4 - p, p) + >>> G3 = TransferFunction(0, p**4 - 1, p) + >>> Parallel(G1, G2).var + p + >>> Parallel(-G3, Series(G1, G2)).var + p + + """ + return self.args[0].var + + def doit(self, **hints): + """ + Returns the resultant transfer function or state space obtained by + parallel connection of transfer functions or state space objects. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Parallel + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) + >>> Parallel(tf2, tf1).doit() + TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s) + >>> Parallel(-tf1, -tf2).doit() + TransferFunction((2 - s**3)*(-p + s) + (-a*p**2 - b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s) + + """ + if self._is_parallel_StateSpace: + # Return the equivalent StateSpace model + res = self.args[0].doit() + if not isinstance(res, StateSpace): + res = res.rewrite(StateSpace) + for arg in self.args[1:]: + if not isinstance(arg, StateSpace): + arg = arg.doit().rewrite(StateSpace) + res += arg + return res + + _arg = (arg.doit().to_expr() for arg in self.args) + res = Add(*_arg).as_numer_denom() + return TransferFunction(*res, self.var) + + def _eval_rewrite_as_TransferFunction(self, *args, **kwargs): + if self._is_parallel_StateSpace: + return self.doit().rewrite(TransferFunction)[0][0] + return self.doit() + + @_check_other_SISO + def __add__(self, other): + + self_arg_list = list(self.args) + return Parallel(*self_arg_list, other) + + __radd__ = __add__ + + @_check_other_SISO + def __sub__(self, other): + return self + (-other) + + def __rsub__(self, other): + return -self + other + + @_check_other_SISO + def __mul__(self, other): + + if isinstance(other, Series): + arg_list = list(other.args) + return Series(self, *arg_list) + + return Series(self, other) + + def __neg__(self): + return Series(TransferFunction(-1, 1, self.var), self) + + def to_expr(self): + """Returns the equivalent ``Expr`` object.""" + return Add(*(arg.to_expr() for arg in self.args), evaluate=False) + + @property + def is_proper(self): + """ + Returns True if degree of the numerator polynomial of the resultant transfer + function is less than or equal to degree of the denominator polynomial of + the same, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Parallel + >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) + >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*s + 2, s) + >>> tf3 = TransferFunction(s, s**2 + s + 1, s) + >>> P1 = Parallel(-tf2, tf1) + >>> P1.is_proper + False + >>> P2 = Parallel(tf2, tf3) + >>> P2.is_proper + True + + """ + return self.doit().is_proper + + @property + def is_strictly_proper(self): + """ + Returns True if degree of the numerator polynomial of the resultant transfer + function is strictly less than degree of the denominator polynomial of + the same, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Parallel + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) + >>> tf3 = TransferFunction(s, s**2 + s + 1, s) + >>> P1 = Parallel(tf1, tf2) + >>> P1.is_strictly_proper + False + >>> P2 = Parallel(tf2, tf3) + >>> P2.is_strictly_proper + True + + """ + return self.doit().is_strictly_proper + + @property + def is_biproper(self): + """ + Returns True if degree of the numerator polynomial of the resultant transfer + function is equal to degree of the denominator polynomial of + the same, else False. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, Parallel + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(p**2, p + s, s) + >>> tf3 = TransferFunction(s, s**2 + s + 1, s) + >>> P1 = Parallel(tf1, -tf2) + >>> P1.is_biproper + True + >>> P2 = Parallel(tf2, tf3) + >>> P2.is_biproper + False + + """ + return self.doit().is_biproper + + @property + def is_StateSpace_object(self): + return self._is_parallel_StateSpace + + +class MIMOParallel(MIMOLinearTimeInvariant): + r""" + A class for representing a parallel configuration of MIMO systems. + + Parameters + ========== + + args : MIMOLinearTimeInvariant + MIMO Systems in a parallel arrangement. + evaluate : Boolean, Keyword + When passed ``True``, returns the equivalent + ``MIMOParallel(*args).doit()``. Set to ``False`` by default. + + Raises + ====== + + ValueError + When no argument is passed. + + ``var`` attribute is not same for every system. + + All MIMO systems passed do not have same shape. + TypeError + Any of the passed ``*args`` has unsupported type + + A combination of SISO and MIMO systems is + passed. There should be homogeneity in the + type of systems passed, MIMO in this case. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunctionMatrix, MIMOParallel, StateSpace + >>> from sympy import Matrix, pprint + >>> expr_1 = 1/s + >>> expr_2 = s/(s**2-1) + >>> expr_3 = (2 + s)/(s**2 - 1) + >>> expr_4 = 5 + >>> tfm_a = TransferFunctionMatrix.from_Matrix(Matrix([[expr_1, expr_2], [expr_3, expr_4]]), s) + >>> tfm_b = TransferFunctionMatrix.from_Matrix(Matrix([[expr_2, expr_1], [expr_4, expr_3]]), s) + >>> tfm_c = TransferFunctionMatrix.from_Matrix(Matrix([[expr_3, expr_4], [expr_1, expr_2]]), s) + >>> MIMOParallel(tfm_a, tfm_b, tfm_c) + MIMOParallel(TransferFunctionMatrix(((TransferFunction(1, s, s), TransferFunction(s, s**2 - 1, s)), (TransferFunction(s + 2, s**2 - 1, s), TransferFunction(5, 1, s)))), TransferFunctionMatrix(((TransferFunction(s, s**2 - 1, s), TransferFunction(1, s, s)), (TransferFunction(5, 1, s), TransferFunction(s + 2, s**2 - 1, s)))), TransferFunctionMatrix(((TransferFunction(s + 2, s**2 - 1, s), TransferFunction(5, 1, s)), (TransferFunction(1, s, s), TransferFunction(s, s**2 - 1, s))))) + >>> pprint(_, use_unicode=False) # For Better Visualization + [ 1 s ] [ s 1 ] [s + 2 5 ] + [ - ------] [------ - ] [------ - ] + [ s 2 ] [ 2 s ] [ 2 1 ] + [ s - 1] [s - 1 ] [s - 1 ] + [ ] + [ ] + [ ] + [s + 2 5 ] [ 5 s + 2 ] [ 1 s ] + [------ - ] [ - ------] [ - ------] + [ 2 1 ] [ 1 2 ] [ s 2 ] + [s - 1 ]{t} [ s - 1]{t} [ s - 1]{t} + >>> MIMOParallel(tfm_a, tfm_b, tfm_c).doit() + TransferFunctionMatrix(((TransferFunction(s**2 + s*(2*s + 2) - 1, s*(s**2 - 1), s), TransferFunction(2*s**2 + 5*s*(s**2 - 1) - 1, s*(s**2 - 1), s)), (TransferFunction(s**2 + s*(s + 2) + 5*s*(s**2 - 1) - 1, s*(s**2 - 1), s), TransferFunction(5*s**2 + 2*s - 3, s**2 - 1, s)))) + >>> pprint(_, use_unicode=False) + [ 2 2 / 2 \ ] + [ s + s*(2*s + 2) - 1 2*s + 5*s*\s - 1/ - 1] + [ -------------------- -----------------------] + [ / 2 \ / 2 \ ] + [ s*\s - 1/ s*\s - 1/ ] + [ ] + [ 2 / 2 \ 2 ] + [s + s*(s + 2) + 5*s*\s - 1/ - 1 5*s + 2*s - 3 ] + [--------------------------------- -------------- ] + [ / 2 \ 2 ] + [ s*\s - 1/ s - 1 ]{t} + + ``MIMOParallel`` can also be used to connect MIMO ``StateSpace`` systems. + + >>> A1 = Matrix([[4, 1], [2, -3]]) + >>> B1 = Matrix([[5, 2], [-3, -3]]) + >>> C1 = Matrix([[2, -4], [0, 1]]) + >>> D1 = Matrix([[3, 2], [1, -1]]) + >>> A2 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) + >>> B2 = Matrix([[1, 4], [-3, -3], [-2, 1]]) + >>> C2 = Matrix([[4, 2, -3], [1, 4, 3]]) + >>> D2 = Matrix([[-2, 4], [0, 1]]) + >>> ss1 = StateSpace(A1, B1, C1, D1) + >>> ss2 = StateSpace(A2, B2, C2, D2) + >>> p1 = MIMOParallel(ss1, ss2) + >>> p1 + MIMOParallel(StateSpace(Matrix([ + [4, 1], + [2, -3]]), Matrix([ + [ 5, 2], + [-3, -3]]), Matrix([ + [2, -4], + [0, 1]]), Matrix([ + [3, 2], + [1, -1]])), StateSpace(Matrix([ + [-3, 4, 2], + [-1, -3, 0], + [ 2, 5, 3]]), Matrix([ + [ 1, 4], + [-3, -3], + [-2, 1]]), Matrix([ + [4, 2, -3], + [1, 4, 3]]), Matrix([ + [-2, 4], + [ 0, 1]]))) + + ``doit()`` can be used to find ``StateSpace`` equivalent for the system containing ``StateSpace`` objects. + + >>> p1.doit() + StateSpace(Matrix([ + [4, 1, 0, 0, 0], + [2, -3, 0, 0, 0], + [0, 0, -3, 4, 2], + [0, 0, -1, -3, 0], + [0, 0, 2, 5, 3]]), Matrix([ + [ 5, 2], + [-3, -3], + [ 1, 4], + [-3, -3], + [-2, 1]]), Matrix([ + [2, -4, 4, 2, -3], + [0, 1, 1, 4, 3]]), Matrix([ + [1, 6], + [1, 0]])) + + Notes + ===== + + All the transfer function matrices should use the same complex variable + ``var`` of the Laplace transform. + + See Also + ======== + + Parallel, MIMOSeries + + """ + + def __new__(cls, *args, evaluate=False): + + args = _flatten_args(args, MIMOParallel) + + # For StateSpace Parallel connection + if args and any(isinstance(arg, StateSpace) or (hasattr(arg, 'is_StateSpace_object') + and arg.is_StateSpace_object) for arg in args): + if any(arg.num_inputs != args[0].num_inputs or arg.num_outputs != args[0].num_outputs + for arg in args[1:]): + raise ShapeError("Systems with incompatible inputs and outputs cannot be " + "connected in MIMOParallel.") + cls._is_parallel_StateSpace = True + else: + cls._check_args(args) + if any(arg.shape != args[0].shape for arg in args): + raise TypeError("Shape of all the args is not equal.") + cls._is_parallel_StateSpace = False + obj = super().__new__(cls, *args) + + return obj.doit() if evaluate else obj + + @property + def var(self): + """ + Returns the complex variable used by all the systems. + + Examples + ======== + + >>> from sympy.abc import p + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOParallel + >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) + >>> G2 = TransferFunction(p, 4 - p, p) + >>> G3 = TransferFunction(0, p**4 - 1, p) + >>> G4 = TransferFunction(p**2, p**2 - 1, p) + >>> tfm_a = TransferFunctionMatrix([[G1, G2], [G3, G4]]) + >>> tfm_b = TransferFunctionMatrix([[G2, G1], [G4, G3]]) + >>> MIMOParallel(tfm_a, tfm_b).var + p + + """ + return self.args[0].var + + @property + def num_inputs(self): + """Returns the number of input signals of the parallel system.""" + return self.args[0].num_inputs + + @property + def num_outputs(self): + """Returns the number of output signals of the parallel system.""" + return self.args[0].num_outputs + + @property + def shape(self): + """Returns the shape of the equivalent MIMO system.""" + return self.num_outputs, self.num_inputs + + @property + def is_StateSpace_object(self): + return self._is_parallel_StateSpace + + def doit(self, **hints): + """ + Returns the resultant transfer function matrix or StateSpace obtained after evaluating + the MIMO systems arranged in a parallel configuration. + + Examples + ======== + + >>> from sympy.abc import s, p, a, b + >>> from sympy.physics.control.lti import TransferFunction, MIMOParallel, TransferFunctionMatrix + >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) + >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) + >>> tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) + >>> tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) + >>> MIMOParallel(tfm_1, tfm_2).doit() + TransferFunctionMatrix(((TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s), TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s)), (TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s), TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s)))) + + """ + if self._is_parallel_StateSpace: + # Return the equivalent StateSpace model. + res = self.args[0] + if not isinstance(res, StateSpace): + res = res.doit().rewrite(StateSpace) + for arg in self.args[1:]: + if not isinstance(arg, StateSpace): + arg = arg.doit().rewrite(StateSpace) + else: + arg = arg.doit() + res += arg + return res + _arg = (arg.doit()._expr_mat for arg in self.args) + res = MatAdd(*_arg, evaluate=True) + return TransferFunctionMatrix.from_Matrix(res, self.var) + + def _eval_rewrite_as_TransferFunctionMatrix(self, *args, **kwargs): + if self._is_parallel_StateSpace: + return self.doit().rewrite(TransferFunction) + return self.doit() + + @_check_other_MIMO + def __add__(self, other): + + self_arg_list = list(self.args) + return MIMOParallel(*self_arg_list, other) + + __radd__ = __add__ + + @_check_other_MIMO + def __sub__(self, other): + return self + (-other) + + def __rsub__(self, other): + return -self + other + + @_check_other_MIMO + def __mul__(self, other): + + if isinstance(other, MIMOSeries): + arg_list = list(other.args) + return MIMOSeries(*arg_list, self) + + return MIMOSeries(other, self) + + def __neg__(self): + arg_list = [-arg for arg in list(self.args)] + return MIMOParallel(*arg_list) + + +class Feedback(SISOLinearTimeInvariant): + r""" + A class for representing closed-loop feedback interconnection between two + SISO input/output systems. + + The first argument, ``sys1``, is the feedforward part of the closed-loop + system or in simple words, the dynamical model representing the process + to be controlled. The second argument, ``sys2``, is the feedback system + and controls the fed back signal to ``sys1``. Both ``sys1`` and ``sys2`` + can either be ``Series``, ``StateSpace`` or ``TransferFunction`` objects. + + Parameters + ========== + + sys1 : Series, StateSpace, TransferFunction + The feedforward path system. + sys2 : Series, StateSpace, TransferFunction, optional + The feedback path system (often a feedback controller). + It is the model sitting on the feedback path. + + If not specified explicitly, the sys2 is + assumed to be unit (1.0) transfer function. + sign : int, optional + The sign of feedback. Can either be ``1`` + (for positive feedback) or ``-1`` (for negative feedback). + Default value is `-1`. + + Raises + ====== + + ValueError + When ``sys1`` and ``sys2`` are not using the + same complex variable of the Laplace transform. + + When a combination of ``sys1`` and ``sys2`` yields + zero denominator. + + TypeError + When either ``sys1`` or ``sys2`` is not a ``Series``, ``StateSpace`` or + ``TransferFunction`` object. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import StateSpace, TransferFunction, Feedback + >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) + >>> controller = TransferFunction(5*s - 10, s + 7, s) + >>> F1 = Feedback(plant, controller) + >>> F1 + Feedback(TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s), TransferFunction(5*s - 10, s + 7, s), -1) + >>> F1.var + s + >>> F1.args + (TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s), TransferFunction(5*s - 10, s + 7, s), -1) + + You can get the feedforward and feedback path systems by using ``.sys1`` and ``.sys2`` respectively. + + >>> F1.sys1 + TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) + >>> F1.sys2 + TransferFunction(5*s - 10, s + 7, s) + + You can get the resultant closed loop transfer function obtained by negative feedback + interconnection using ``.doit()`` method. + + >>> F1.doit() + TransferFunction((s + 7)*(s**2 - 4*s + 2)*(3*s**2 + 7*s - 3), ((s + 7)*(s**2 - 4*s + 2) + (5*s - 10)*(3*s**2 + 7*s - 3))*(s**2 - 4*s + 2), s) + >>> G = TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s) + >>> C = TransferFunction(5*s + 10, s + 10, s) + >>> F2 = Feedback(G*C, TransferFunction(1, 1, s)) + >>> F2.doit() + TransferFunction((s + 10)*(5*s + 10)*(s**2 + 2*s + 3)*(2*s**2 + 5*s + 1), (s + 10)*((s + 10)*(s**2 + 2*s + 3) + (5*s + 10)*(2*s**2 + 5*s + 1))*(s**2 + 2*s + 3), s) + + To negate a ``Feedback`` object, the ``-`` operator can be prepended: + + >>> -F1 + Feedback(TransferFunction(-3*s**2 - 7*s + 3, s**2 - 4*s + 2, s), TransferFunction(10 - 5*s, s + 7, s), -1) + >>> -F2 + Feedback(Series(TransferFunction(-1, 1, s), TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s), TransferFunction(5*s + 10, s + 10, s)), TransferFunction(-1, 1, s), -1) + + ``Feedback`` can also be used to connect SISO ``StateSpace`` systems together. + + >>> A1 = Matrix([[-1]]) + >>> B1 = Matrix([[1]]) + >>> C1 = Matrix([[-1]]) + >>> D1 = Matrix([1]) + >>> A2 = Matrix([[0]]) + >>> B2 = Matrix([[1]]) + >>> C2 = Matrix([[1]]) + >>> D2 = Matrix([[0]]) + >>> ss1 = StateSpace(A1, B1, C1, D1) + >>> ss2 = StateSpace(A2, B2, C2, D2) + >>> F3 = Feedback(ss1, ss2) + >>> F3 + Feedback(StateSpace(Matrix([[-1]]), Matrix([[1]]), Matrix([[-1]]), Matrix([[1]])), StateSpace(Matrix([[0]]), Matrix([[1]]), Matrix([[1]]), Matrix([[0]])), -1) + + ``doit()`` can be used to find ``StateSpace`` equivalent for the system containing ``StateSpace`` objects. + + >>> F3.doit() + StateSpace(Matrix([ + [-1, -1], + [-1, -1]]), Matrix([ + [1], + [1]]), Matrix([[-1, -1]]), Matrix([[1]])) + + We can also find the equivalent ``TransferFunction`` by using ``rewrite(TransferFunction)`` method. + + >>> F3.rewrite(TransferFunction) + TransferFunction(s, s + 2, s) + + See Also + ======== + + MIMOFeedback, Series, Parallel + + """ + def __new__(cls, sys1, sys2=None, sign=-1): + if not sys2: + sys2 = TransferFunction(1, 1, sys1.var) + + if not isinstance(sys1, (TransferFunction, Series, StateSpace, Feedback)): + raise TypeError("Unsupported type for `sys1` in Feedback.") + + if not isinstance(sys2, (TransferFunction, Series, StateSpace, Feedback)): + raise TypeError("Unsupported type for `sys2` in Feedback.") + + if not (sys1.num_inputs == sys1.num_outputs == sys2.num_inputs == + sys2.num_outputs == 1): + raise ValueError("""To use Feedback connection for MIMO systems + use MIMOFeedback instead.""") + + if sign not in [-1, 1]: + raise ValueError(filldedent(""" + Unsupported type for feedback. `sign` arg should + either be 1 (positive feedback loop) or -1 + (negative feedback loop).""")) + + if sys1.is_StateSpace_object or sys2.is_StateSpace_object: + cls.is_StateSpace_object = True + else: + if Mul(sys1.to_expr(), sys2.to_expr()).simplify() == sign: + raise ValueError("The equivalent system will have zero denominator.") + if sys1.var != sys2.var: + raise ValueError(filldedent("""Both `sys1` and `sys2` should be using the + same complex variable.""")) + cls.is_StateSpace_object = False + + return super(SISOLinearTimeInvariant, cls).__new__(cls, sys1, sys2, _sympify(sign)) + + def __repr__(self): + return f"Feedback({self.sys1}, {self.sys2}, {self.sign})" + + __str__ = __repr__ + + @property + def sys1(self): + """ + Returns the feedforward system of the feedback interconnection. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction, Feedback + >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) + >>> controller = TransferFunction(5*s - 10, s + 7, s) + >>> F1 = Feedback(plant, controller) + >>> F1.sys1 + TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) + >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) + >>> C = TransferFunction(5*p + 10, p + 10, p) + >>> P = TransferFunction(1 - s, p + 2, p) + >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) + >>> F2.sys1 + TransferFunction(1, 1, p) + + """ + return self.args[0] + + @property + def sys2(self): + """ + Returns the feedback controller of the feedback interconnection. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction, Feedback + >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) + >>> controller = TransferFunction(5*s - 10, s + 7, s) + >>> F1 = Feedback(plant, controller) + >>> F1.sys2 + TransferFunction(5*s - 10, s + 7, s) + >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) + >>> C = TransferFunction(5*p + 10, p + 10, p) + >>> P = TransferFunction(1 - s, p + 2, p) + >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) + >>> F2.sys2 + Series(TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p), TransferFunction(5*p + 10, p + 10, p), TransferFunction(1 - s, p + 2, p)) + + """ + return self.args[1] + + @property + def var(self): + """ + Returns the complex variable of the Laplace transform used by all + the transfer functions involved in the feedback interconnection. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction, Feedback + >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) + >>> controller = TransferFunction(5*s - 10, s + 7, s) + >>> F1 = Feedback(plant, controller) + >>> F1.var + s + >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) + >>> C = TransferFunction(5*p + 10, p + 10, p) + >>> P = TransferFunction(1 - s, p + 2, p) + >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) + >>> F2.var + p + + """ + return self.sys1.var + + @property + def sign(self): + """ + Returns the type of MIMO Feedback model. ``1`` + for Positive and ``-1`` for Negative. + """ + return self.args[2] + + @property + def num(self): + """ + Returns the numerator of the closed loop feedback system. + """ + return self.sys1 + + @property + def den(self): + """ + Returns the denominator of the closed loop feedback model. + """ + unit = TransferFunction(1, 1, self.var) + arg_list = list(self.sys1.args) if isinstance(self.sys1, Series) else [self.sys1] + if self.sign == 1: + return Parallel(unit, -Series(self.sys2, *arg_list)) + return Parallel(unit, Series(self.sys2, *arg_list)) + + @property + def sensitivity(self): + """ + Returns the sensitivity function of the feedback loop. + + Sensitivity of a Feedback system is the ratio + of change in the open loop gain to the change in + the closed loop gain. + + .. note:: + This method would not return the complementary + sensitivity function. + + Examples + ======== + + >>> from sympy.abc import p + >>> from sympy.physics.control.lti import TransferFunction, Feedback + >>> C = TransferFunction(5*p + 10, p + 10, p) + >>> P = TransferFunction(1 - p, p + 2, p) + >>> F_1 = Feedback(P, C) + >>> F_1.sensitivity + 1/((1 - p)*(5*p + 10)/((p + 2)*(p + 10)) + 1) + + """ + + return 1/(1 - self.sign*self.sys1.to_expr()*self.sys2.to_expr()) + + def doit(self, cancel=False, expand=False, **hints): + """ + Returns the resultant transfer function or state space obtained by + feedback connection of transfer functions or state space objects. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy import Matrix + >>> from sympy.physics.control.lti import TransferFunction, Feedback, StateSpace + >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) + >>> controller = TransferFunction(5*s - 10, s + 7, s) + >>> F1 = Feedback(plant, controller) + >>> F1.doit() + TransferFunction((s + 7)*(s**2 - 4*s + 2)*(3*s**2 + 7*s - 3), ((s + 7)*(s**2 - 4*s + 2) + (5*s - 10)*(3*s**2 + 7*s - 3))*(s**2 - 4*s + 2), s) + >>> G = TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s) + >>> F2 = Feedback(G, TransferFunction(1, 1, s)) + >>> F2.doit() + TransferFunction((s**2 + 2*s + 3)*(2*s**2 + 5*s + 1), (s**2 + 2*s + 3)*(3*s**2 + 7*s + 4), s) + + Use kwarg ``expand=True`` to expand the resultant transfer function. + Use ``cancel=True`` to cancel out the common terms in numerator and + denominator. + + >>> F2.doit(cancel=True, expand=True) + TransferFunction(2*s**2 + 5*s + 1, 3*s**2 + 7*s + 4, s) + >>> F2.doit(expand=True) + TransferFunction(2*s**4 + 9*s**3 + 17*s**2 + 17*s + 3, 3*s**4 + 13*s**3 + 27*s**2 + 29*s + 12, s) + + If the connection contain any ``StateSpace`` object then ``doit()`` + will return the equivalent ``StateSpace`` object. + + >>> A1 = Matrix([[-1.5, -2], [1, 0]]) + >>> B1 = Matrix([0.5, 0]) + >>> C1 = Matrix([[0, 1]]) + >>> A2 = Matrix([[0, 1], [-5, -2]]) + >>> B2 = Matrix([0, 3]) + >>> C2 = Matrix([[0, 1]]) + >>> ss1 = StateSpace(A1, B1, C1) + >>> ss2 = StateSpace(A2, B2, C2) + >>> F3 = Feedback(ss1, ss2) + >>> F3.doit() + StateSpace(Matrix([ + [-1.5, -2, 0, -0.5], + [ 1, 0, 0, 0], + [ 0, 0, 0, 1], + [ 0, 3, -5, -2]]), Matrix([ + [0.5], + [ 0], + [ 0], + [ 0]]), Matrix([[0, 1, 0, 0]]), Matrix([[0]])) + + """ + if self.is_StateSpace_object: + sys1_ss = self.sys1.doit().rewrite(StateSpace) + sys2_ss = self.sys2.doit().rewrite(StateSpace) + A1, B1, C1, D1 = sys1_ss.A, sys1_ss.B, sys1_ss.C, sys1_ss.D + A2, B2, C2, D2 = sys2_ss.A, sys2_ss.B, sys2_ss.C, sys2_ss.D + + # Create identity matrices + I_inputs = eye(self.num_inputs) + I_outputs = eye(self.num_outputs) + + # Compute F and its inverse + F = I_inputs - self.sign * D2 * D1 + E = F.inv() + + # Compute intermediate matrices + E_D2 = E * D2 + E_C2 = E * C2 + T1 = I_outputs + self.sign * D1 * E_D2 + T2 = I_inputs + self.sign * E_D2 * D1 + A = Matrix.vstack( + Matrix.hstack(A1 + self.sign * B1 * E_D2 * C1, self.sign * B1 * E_C2), + Matrix.hstack(B2 * T1 * C1, A2 + self.sign * B2 * D1 * E_C2) + ) + B = Matrix.vstack(B1 * T2, B2 * D1 * T2) + C = Matrix.hstack(T1 * C1, self.sign * D1 * E_C2) + D = D1 * T2 + return StateSpace(A, B, C, D) + + arg_list = list(self.sys1.args) if isinstance(self.sys1, Series) else [self.sys1] + # F_n and F_d are resultant TFs of num and den of Feedback. + F_n, unit = self.sys1.doit(), TransferFunction(1, 1, self.sys1.var) + if self.sign == -1: + F_d = Parallel(unit, Series(self.sys2, *arg_list)).doit() + else: + F_d = Parallel(unit, -Series(self.sys2, *arg_list)).doit() + + _resultant_tf = TransferFunction(F_n.num * F_d.den, F_n.den * F_d.num, F_n.var) + + if cancel: + _resultant_tf = _resultant_tf.simplify() + + if expand: + _resultant_tf = _resultant_tf.expand() + + return _resultant_tf + + def _eval_rewrite_as_TransferFunction(self, num, den, sign, **kwargs): + if self.is_StateSpace_object: + return self.doit().rewrite(TransferFunction)[0][0] + return self.doit() + + def to_expr(self): + """ + Converts a ``Feedback`` object to SymPy Expr. + + Examples + ======== + + >>> from sympy.abc import s, a, b + >>> from sympy.physics.control.lti import TransferFunction, Feedback + >>> from sympy import Expr + >>> tf1 = TransferFunction(a+s, 1, s) + >>> tf2 = TransferFunction(b+s, 1, s) + >>> fd1 = Feedback(tf1, tf2) + >>> fd1.to_expr() + (a + s)/((a + s)*(b + s) + 1) + >>> isinstance(_, Expr) + True + """ + + return self.doit().to_expr() + + def __neg__(self): + return Feedback(-self.sys1, -self.sys2, self.sign) + + +def _is_invertible(a, b, sign): + """ + Checks whether a given pair of MIMO + systems passed is invertible or not. + """ + _mat = eye(a.num_outputs) - sign*(a.doit()._expr_mat)*(b.doit()._expr_mat) + _det = _mat.det() + + return _det != 0 + + +class MIMOFeedback(MIMOLinearTimeInvariant): + r""" + A class for representing closed-loop feedback interconnection between two + MIMO input/output systems. + + Parameters + ========== + + sys1 : MIMOSeries, TransferFunctionMatrix, StateSpace + The MIMO system placed on the feedforward path. + sys2 : MIMOSeries, TransferFunctionMatrix, StateSpace + The system placed on the feedback path + (often a feedback controller). + sign : int, optional + The sign of feedback. Can either be ``1`` + (for positive feedback) or ``-1`` (for negative feedback). + Default value is `-1`. + + Raises + ====== + + ValueError + When ``sys1`` and ``sys2`` are not using the + same complex variable of the Laplace transform. + + Forward path model should have an equal number of inputs/outputs + to the feedback path outputs/inputs. + + When product of ``sys1`` and ``sys2`` is not a square matrix. + + When the equivalent MIMO system is not invertible. + + TypeError + When either ``sys1`` or ``sys2`` is not a ``MIMOSeries``, + ``TransferFunctionMatrix`` or a ``StateSpace`` object. + + Examples + ======== + + >>> from sympy import Matrix, pprint + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import StateSpace, TransferFunctionMatrix, MIMOFeedback + >>> plant_mat = Matrix([[1, 1/s], [0, 1]]) + >>> controller_mat = Matrix([[10, 0], [0, 10]]) # Constant Gain + >>> plant = TransferFunctionMatrix.from_Matrix(plant_mat, s) + >>> controller = TransferFunctionMatrix.from_Matrix(controller_mat, s) + >>> feedback = MIMOFeedback(plant, controller) # Negative Feedback (default) + >>> pprint(feedback, use_unicode=False) + / [1 1] [10 0 ] \-1 [1 1] + | [- -] [-- - ] | [- -] + | [1 s] [1 1 ] | [1 s] + |I + [ ] *[ ] | * [ ] + | [0 1] [0 10] | [0 1] + | [- -] [- --] | [- -] + \ [1 1]{t} [1 1 ]{t}/ [1 1]{t} + + To get the equivalent system matrix, use either ``doit`` or ``rewrite`` method. + + >>> pprint(feedback.doit(), use_unicode=False) + [1 1 ] + [-- -----] + [11 121*s] + [ ] + [0 1 ] + [- -- ] + [1 11 ]{t} + + To negate the ``MIMOFeedback`` object, use ``-`` operator. + + >>> neg_feedback = -feedback + >>> pprint(neg_feedback.doit(), use_unicode=False) + [-1 -1 ] + [--- -----] + [11 121*s] + [ ] + [ 0 -1 ] + [ - --- ] + [ 1 11 ]{t} + + ``MIMOFeedback`` can also be used to connect MIMO ``StateSpace`` systems. + + >>> A1 = Matrix([[4, 1], [2, -3]]) + >>> B1 = Matrix([[5, 2], [-3, -3]]) + >>> C1 = Matrix([[2, -4], [0, 1]]) + >>> D1 = Matrix([[3, 2], [1, -1]]) + >>> A2 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) + >>> B2 = Matrix([[1, 4], [-3, -3], [-2, 1]]) + >>> C2 = Matrix([[4, 2, -3], [1, 4, 3]]) + >>> D2 = Matrix([[-2, 4], [0, 1]]) + >>> ss1 = StateSpace(A1, B1, C1, D1) + >>> ss2 = StateSpace(A2, B2, C2, D2) + >>> F1 = MIMOFeedback(ss1, ss2) + >>> F1 + MIMOFeedback(StateSpace(Matrix([ + [4, 1], + [2, -3]]), Matrix([ + [ 5, 2], + [-3, -3]]), Matrix([ + [2, -4], + [0, 1]]), Matrix([ + [3, 2], + [1, -1]])), StateSpace(Matrix([ + [-3, 4, 2], + [-1, -3, 0], + [ 2, 5, 3]]), Matrix([ + [ 1, 4], + [-3, -3], + [-2, 1]]), Matrix([ + [4, 2, -3], + [1, 4, 3]]), Matrix([ + [-2, 4], + [ 0, 1]])), -1) + + ``doit()`` can be used to find ``StateSpace`` equivalent for the system containing ``StateSpace`` objects. + + >>> F1.doit() + StateSpace(Matrix([ + [ 3, -3/4, -15/4, -37/2, -15], + [ 7/2, -39/8, 9/8, 39/4, 9], + [ 3, -41/4, -45/4, -51/2, -19], + [-9/2, 129/8, 73/8, 171/4, 36], + [-3/2, 47/8, 31/8, 85/4, 18]]), Matrix([ + [-1/4, 19/4], + [ 3/8, -21/8], + [ 1/4, 29/4], + [ 3/8, -93/8], + [ 5/8, -35/8]]), Matrix([ + [ 1, -15/4, -7/4, -21/2, -9], + [1/2, -13/8, -13/8, -19/4, -3]]), Matrix([ + [-1/4, 11/4], + [ 1/8, 9/8]])) + + See Also + ======== + + Feedback, MIMOSeries, MIMOParallel + + """ + def __new__(cls, sys1, sys2, sign=-1): + if not isinstance(sys1, (TransferFunctionMatrix, MIMOSeries, StateSpace)): + raise TypeError("Unsupported type for `sys1` in MIMO Feedback.") + + if not isinstance(sys2, (TransferFunctionMatrix, MIMOSeries, StateSpace)): + raise TypeError("Unsupported type for `sys2` in MIMO Feedback.") + + if sys1.num_inputs != sys2.num_outputs or \ + sys1.num_outputs != sys2.num_inputs: + raise ValueError(filldedent(""" + Product of `sys1` and `sys2` must + yield a square matrix.""")) + + if sign not in (-1, 1): + raise ValueError(filldedent(""" + Unsupported type for feedback. `sign` arg should + either be 1 (positive feedback loop) or -1 + (negative feedback loop).""")) + + if sys1.is_StateSpace_object or sys2.is_StateSpace_object: + cls.is_StateSpace_object = True + else: + if not _is_invertible(sys1, sys2, sign): + raise ValueError("Non-Invertible system inputted.") + cls.is_StateSpace_object = False + + if not cls.is_StateSpace_object and sys1.var != sys2.var: + raise ValueError(filldedent(""" + Both `sys1` and `sys2` should be using the + same complex variable.""")) + + return super().__new__(cls, sys1, sys2, _sympify(sign)) + + @property + def sys1(self): + r""" + Returns the system placed on the feedforward path of the MIMO feedback interconnection. + + Examples + ======== + + >>> from sympy import pprint + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback + >>> tf1 = TransferFunction(s**2 + s + 1, s**2 - s + 1, s) + >>> tf2 = TransferFunction(1, s, s) + >>> tf3 = TransferFunction(1, 1, s) + >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) + >>> sys2 = TransferFunctionMatrix([[tf3, tf3], [tf3, tf2]]) + >>> F_1 = MIMOFeedback(sys1, sys2, 1) + >>> F_1.sys1 + TransferFunctionMatrix(((TransferFunction(s**2 + s + 1, s**2 - s + 1, s), TransferFunction(1, s, s)), (TransferFunction(1, s, s), TransferFunction(s**2 + s + 1, s**2 - s + 1, s)))) + >>> pprint(_, use_unicode=False) + [ 2 ] + [s + s + 1 1 ] + [---------- - ] + [ 2 s ] + [s - s + 1 ] + [ ] + [ 2 ] + [ 1 s + s + 1] + [ - ----------] + [ s 2 ] + [ s - s + 1]{t} + + """ + return self.args[0] + + @property + def sys2(self): + r""" + Returns the feedback controller of the MIMO feedback interconnection. + + Examples + ======== + + >>> from sympy import pprint + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback + >>> tf1 = TransferFunction(s**2, s**3 - s + 1, s) + >>> tf2 = TransferFunction(1, s, s) + >>> tf3 = TransferFunction(1, 1, s) + >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) + >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) + >>> F_1 = MIMOFeedback(sys1, sys2) + >>> F_1.sys2 + TransferFunctionMatrix(((TransferFunction(s**2, s**3 - s + 1, s), TransferFunction(1, 1, s)), (TransferFunction(1, 1, s), TransferFunction(1, s, s)))) + >>> pprint(_, use_unicode=False) + [ 2 ] + [ s 1] + [---------- -] + [ 3 1] + [s - s + 1 ] + [ ] + [ 1 1] + [ - -] + [ 1 s]{t} + + """ + return self.args[1] + + @property + def var(self): + r""" + Returns the complex variable of the Laplace transform used by all + the transfer functions involved in the MIMO feedback loop. + + Examples + ======== + + >>> from sympy.abc import p + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback + >>> tf1 = TransferFunction(p, 1 - p, p) + >>> tf2 = TransferFunction(1, p, p) + >>> tf3 = TransferFunction(1, 1, p) + >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) + >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) + >>> F_1 = MIMOFeedback(sys1, sys2, 1) # Positive feedback + >>> F_1.var + p + + """ + return self.sys1.var + + @property + def sign(self): + r""" + Returns the type of feedback interconnection of two models. ``1`` + for Positive and ``-1`` for Negative. + """ + return self.args[2] + + @property + def sensitivity(self): + r""" + Returns the sensitivity function matrix of the feedback loop. + + Sensitivity of a closed-loop system is the ratio of change + in the open loop gain to the change in the closed loop gain. + + .. note:: + This method would not return the complementary + sensitivity function. + + Examples + ======== + + >>> from sympy import pprint + >>> from sympy.abc import p + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback + >>> tf1 = TransferFunction(p, 1 - p, p) + >>> tf2 = TransferFunction(1, p, p) + >>> tf3 = TransferFunction(1, 1, p) + >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) + >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) + >>> F_1 = MIMOFeedback(sys1, sys2, 1) # Positive feedback + >>> F_2 = MIMOFeedback(sys1, sys2) # Negative feedback + >>> pprint(F_1.sensitivity, use_unicode=False) + [ 4 3 2 5 4 2 ] + [- p + 3*p - 4*p + 3*p - 1 p - 2*p + 3*p - 3*p + 1 ] + [---------------------------- -----------------------------] + [ 4 3 2 5 4 3 2 ] + [ p + 3*p - 8*p + 8*p - 3 p + 3*p - 8*p + 8*p - 3*p] + [ ] + [ 4 3 2 3 2 ] + [ p - p - p + p 3*p - 6*p + 4*p - 1 ] + [ -------------------------- -------------------------- ] + [ 4 3 2 4 3 2 ] + [ p + 3*p - 8*p + 8*p - 3 p + 3*p - 8*p + 8*p - 3 ] + >>> pprint(F_2.sensitivity, use_unicode=False) + [ 4 3 2 5 4 2 ] + [p - 3*p + 2*p + p - 1 p - 2*p + 3*p - 3*p + 1] + [------------------------ --------------------------] + [ 4 3 5 4 2 ] + [ p - 3*p + 2*p - 1 p - 3*p + 2*p - p ] + [ ] + [ 4 3 2 4 3 ] + [ p - p - p + p 2*p - 3*p + 2*p - 1 ] + [ ------------------- --------------------- ] + [ 4 3 4 3 ] + [ p - 3*p + 2*p - 1 p - 3*p + 2*p - 1 ] + + """ + _sys1_mat = self.sys1.doit()._expr_mat + _sys2_mat = self.sys2.doit()._expr_mat + + return (eye(self.sys1.num_inputs) - \ + self.sign*_sys1_mat*_sys2_mat).inv() + + @property + def num_inputs(self): + """Returns the number of inputs of the system.""" + return self.sys1.num_inputs + + @property + def num_outputs(self): + """Returns the number of outputs of the system.""" + return self.sys1.num_outputs + + def doit(self, cancel=True, expand=False, **hints): + r""" + Returns the resultant transfer function matrix obtained by the + feedback interconnection. + + Examples + ======== + + >>> from sympy import pprint + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback + >>> tf1 = TransferFunction(s, 1 - s, s) + >>> tf2 = TransferFunction(1, s, s) + >>> tf3 = TransferFunction(5, 1, s) + >>> tf4 = TransferFunction(s - 1, s, s) + >>> tf5 = TransferFunction(0, 1, s) + >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) + >>> sys2 = TransferFunctionMatrix([[tf3, tf5], [tf5, tf5]]) + >>> F_1 = MIMOFeedback(sys1, sys2, 1) + >>> pprint(F_1, use_unicode=False) + / [ s 1 ] [5 0] \-1 [ s 1 ] + | [----- - ] [- -] | [----- - ] + | [1 - s s ] [1 1] | [1 - s s ] + |I - [ ] *[ ] | * [ ] + | [ 5 s - 1] [0 0] | [ 5 s - 1] + | [ - -----] [- -] | [ - -----] + \ [ 1 s ]{t} [1 1]{t}/ [ 1 s ]{t} + >>> pprint(F_1.doit(), use_unicode=False) + [ -s s - 1 ] + [------- ----------- ] + [6*s - 1 s*(6*s - 1) ] + [ ] + [5*s - 5 (s - 1)*(6*s + 24)] + [------- ------------------] + [6*s - 1 s*(6*s - 1) ]{t} + + If the user wants the resultant ``TransferFunctionMatrix`` object without + canceling the common factors then the ``cancel`` kwarg should be passed ``False``. + + >>> pprint(F_1.doit(cancel=False), use_unicode=False) + [ s*(s - 1) s - 1 ] + [ ----------------- ----------- ] + [ (1 - s)*(6*s - 1) s*(6*s - 1) ] + [ ] + [s*(25*s - 25) + 5*(1 - s)*(6*s - 1) s*(s - 1)*(6*s - 1) + s*(25*s - 25)] + [----------------------------------- -----------------------------------] + [ (1 - s)*(6*s - 1) 2 ] + [ s *(6*s - 1) ]{t} + + If the user wants the expanded form of the resultant transfer function matrix, + the ``expand`` kwarg should be passed as ``True``. + + >>> pprint(F_1.doit(expand=True), use_unicode=False) + [ -s s - 1 ] + [------- -------- ] + [6*s - 1 2 ] + [ 6*s - s ] + [ ] + [ 2 ] + [5*s - 5 6*s + 18*s - 24] + [------- ----------------] + [6*s - 1 2 ] + [ 6*s - s ]{t} + + """ + if self.is_StateSpace_object: + sys1_ss = self.sys1.doit().rewrite(StateSpace) + sys2_ss = self.sys2.doit().rewrite(StateSpace) + A1, B1, C1, D1 = sys1_ss.A, sys1_ss.B, sys1_ss.C, sys1_ss.D + A2, B2, C2, D2 = sys2_ss.A, sys2_ss.B, sys2_ss.C, sys2_ss.D + + # Create identity matrices + I_inputs = eye(self.num_inputs) + I_outputs = eye(self.num_outputs) + + # Compute F and its inverse + F = I_inputs - self.sign * D2 * D1 + E = F.inv() + + # Compute intermediate matrices + E_D2 = E * D2 + E_C2 = E * C2 + T1 = I_outputs + self.sign * D1 * E_D2 + T2 = I_inputs + self.sign * E_D2 * D1 + A = Matrix.vstack( + Matrix.hstack(A1 + self.sign * B1 * E_D2 * C1, self.sign * B1 * E_C2), + Matrix.hstack(B2 * T1 * C1, A2 + self.sign * B2 * D1 * E_C2) + ) + B = Matrix.vstack(B1 * T2, B2 * D1 * T2) + C = Matrix.hstack(T1 * C1, self.sign * D1 * E_C2) + D = D1 * T2 + return StateSpace(A, B, C, D) + + _mat = self.sensitivity * self.sys1.doit()._expr_mat + + _resultant_tfm = _to_TFM(_mat, self.var) + + if cancel: + _resultant_tfm = _resultant_tfm.simplify() + + if expand: + _resultant_tfm = _resultant_tfm.expand() + + return _resultant_tfm + + def _eval_rewrite_as_TransferFunctionMatrix(self, sys1, sys2, sign, **kwargs): + return self.doit() + + def __neg__(self): + return MIMOFeedback(-self.sys1, -self.sys2, self.sign) + + +def _to_TFM(mat, var): + """Private method to convert ImmutableMatrix to TransferFunctionMatrix efficiently""" + to_tf = lambda expr: TransferFunction.from_rational_expression(expr, var) + arg = [[to_tf(expr) for expr in row] for row in mat.tolist()] + return TransferFunctionMatrix(arg) + + +class TransferFunctionMatrix(MIMOLinearTimeInvariant): + r""" + A class for representing the MIMO (multiple-input and multiple-output) + generalization of the SISO (single-input and single-output) transfer function. + + It is a matrix of transfer functions (``TransferFunction``, SISO-``Series`` or SISO-``Parallel``). + There is only one argument, ``arg`` which is also the compulsory argument. + ``arg`` is expected to be strictly of the type list of lists + which holds the transfer functions or reducible to transfer functions. + + Parameters + ========== + + arg : Nested ``List`` (strictly). + Users are expected to input a nested list of ``TransferFunction``, ``Series`` + and/or ``Parallel`` objects. + + Examples + ======== + + .. note:: + ``pprint()`` can be used for better visualization of ``TransferFunctionMatrix`` objects. + + >>> from sympy.abc import s, p, a + >>> from sympy import pprint + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, Series, Parallel + >>> tf_1 = TransferFunction(s + a, s**2 + s + 1, s) + >>> tf_2 = TransferFunction(p**4 - 3*p + 2, s + p, s) + >>> tf_3 = TransferFunction(3, s + 2, s) + >>> tf_4 = TransferFunction(-a + p, 9*s - 9, s) + >>> tfm_1 = TransferFunctionMatrix([[tf_1], [tf_2], [tf_3]]) + >>> tfm_1 + TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(3, s + 2, s),))) + >>> tfm_1.var + s + >>> tfm_1.num_inputs + 1 + >>> tfm_1.num_outputs + 3 + >>> tfm_1.shape + (3, 1) + >>> tfm_1.args + (((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(3, s + 2, s),)),) + >>> tfm_2 = TransferFunctionMatrix([[tf_1, -tf_3], [tf_2, -tf_1], [tf_3, -tf_2]]) + >>> tfm_2 + TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(p**4 - 3*p + 2, p + s, s), TransferFunction(-a - s, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)))) + >>> pprint(tfm_2, use_unicode=False) # pretty-printing for better visualization + [ a + s -3 ] + [ ---------- ----- ] + [ 2 s + 2 ] + [ s + s + 1 ] + [ ] + [ 4 ] + [p - 3*p + 2 -a - s ] + [------------ ---------- ] + [ p + s 2 ] + [ s + s + 1 ] + [ ] + [ 4 ] + [ 3 - p + 3*p - 2] + [ ----- --------------] + [ s + 2 p + s ]{t} + + TransferFunctionMatrix can be transposed, if user wants to switch the input and output transfer functions + + >>> tfm_2.transpose() + TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(p**4 - 3*p + 2, p + s, s), TransferFunction(3, s + 2, s)), (TransferFunction(-3, s + 2, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)))) + >>> pprint(_, use_unicode=False) + [ 4 ] + [ a + s p - 3*p + 2 3 ] + [---------- ------------ ----- ] + [ 2 p + s s + 2 ] + [s + s + 1 ] + [ ] + [ 4 ] + [ -3 -a - s - p + 3*p - 2] + [ ----- ---------- --------------] + [ s + 2 2 p + s ] + [ s + s + 1 ]{t} + + >>> tf_5 = TransferFunction(5, s, s) + >>> tf_6 = TransferFunction(5*s, (2 + s**2), s) + >>> tf_7 = TransferFunction(5, (s*(2 + s**2)), s) + >>> tf_8 = TransferFunction(5, 1, s) + >>> tfm_3 = TransferFunctionMatrix([[tf_5, tf_6], [tf_7, tf_8]]) + >>> tfm_3 + TransferFunctionMatrix(((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)), (TransferFunction(5, s*(s**2 + 2), s), TransferFunction(5, 1, s)))) + >>> pprint(tfm_3, use_unicode=False) + [ 5 5*s ] + [ - ------] + [ s 2 ] + [ s + 2] + [ ] + [ 5 5 ] + [---------- - ] + [ / 2 \ 1 ] + [s*\s + 2/ ]{t} + >>> tfm_3.var + s + >>> tfm_3.shape + (2, 2) + >>> tfm_3.num_outputs + 2 + >>> tfm_3.num_inputs + 2 + >>> tfm_3.args + (((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)), (TransferFunction(5, s*(s**2 + 2), s), TransferFunction(5, 1, s))),) + + To access the ``TransferFunction`` at any index in the ``TransferFunctionMatrix``, use the index notation. + + >>> tfm_3[1, 0] # gives the TransferFunction present at 2nd Row and 1st Col. Similar to that in Matrix classes + TransferFunction(5, s*(s**2 + 2), s) + >>> tfm_3[0, 0] # gives the TransferFunction present at 1st Row and 1st Col. + TransferFunction(5, s, s) + >>> tfm_3[:, 0] # gives the first column + TransferFunctionMatrix(((TransferFunction(5, s, s),), (TransferFunction(5, s*(s**2 + 2), s),))) + >>> pprint(_, use_unicode=False) + [ 5 ] + [ - ] + [ s ] + [ ] + [ 5 ] + [----------] + [ / 2 \] + [s*\s + 2/]{t} + >>> tfm_3[0, :] # gives the first row + TransferFunctionMatrix(((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)),)) + >>> pprint(_, use_unicode=False) + [5 5*s ] + [- ------] + [s 2 ] + [ s + 2]{t} + + To negate a transfer function matrix, ``-`` operator can be prepended: + + >>> tfm_4 = TransferFunctionMatrix([[tf_2], [-tf_1], [tf_3]]) + >>> -tfm_4 + TransferFunctionMatrix(((TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(-3, s + 2, s),))) + >>> tfm_5 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, -tf_1]]) + >>> -tfm_5 + TransferFunctionMatrix(((TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)), (TransferFunction(-3, s + 2, s), TransferFunction(a + s, s**2 + s + 1, s)))) + + ``subs()`` returns the ``TransferFunctionMatrix`` object with the value substituted in the expression. This will not + mutate your original ``TransferFunctionMatrix``. + + >>> tfm_2.subs(p, 2) # substituting p everywhere in tfm_2 with 2. + TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(12, s + 2, s), TransferFunction(-a - s, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-12, s + 2, s)))) + >>> pprint(_, use_unicode=False) + [ a + s -3 ] + [---------- ----- ] + [ 2 s + 2 ] + [s + s + 1 ] + [ ] + [ 12 -a - s ] + [ ----- ----------] + [ s + 2 2 ] + [ s + s + 1] + [ ] + [ 3 -12 ] + [ ----- ----- ] + [ s + 2 s + 2 ]{t} + >>> pprint(tfm_2, use_unicode=False) # State of tfm_2 is unchanged after substitution + [ a + s -3 ] + [ ---------- ----- ] + [ 2 s + 2 ] + [ s + s + 1 ] + [ ] + [ 4 ] + [p - 3*p + 2 -a - s ] + [------------ ---------- ] + [ p + s 2 ] + [ s + s + 1 ] + [ ] + [ 4 ] + [ 3 - p + 3*p - 2] + [ ----- --------------] + [ s + 2 p + s ]{t} + + ``subs()`` also supports multiple substitutions. + + >>> tfm_2.subs({p: 2, a: 1}) # substituting p with 2 and a with 1 + TransferFunctionMatrix(((TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(12, s + 2, s), TransferFunction(-s - 1, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-12, s + 2, s)))) + >>> pprint(_, use_unicode=False) + [ s + 1 -3 ] + [---------- ----- ] + [ 2 s + 2 ] + [s + s + 1 ] + [ ] + [ 12 -s - 1 ] + [ ----- ----------] + [ s + 2 2 ] + [ s + s + 1] + [ ] + [ 3 -12 ] + [ ----- ----- ] + [ s + 2 s + 2 ]{t} + + Users can reduce the ``Series`` and ``Parallel`` elements of the matrix to ``TransferFunction`` by using + ``doit()``. + + >>> tfm_6 = TransferFunctionMatrix([[Series(tf_3, tf_4), Parallel(tf_3, tf_4)]]) + >>> tfm_6 + TransferFunctionMatrix(((Series(TransferFunction(3, s + 2, s), TransferFunction(-a + p, 9*s - 9, s)), Parallel(TransferFunction(3, s + 2, s), TransferFunction(-a + p, 9*s - 9, s))),)) + >>> pprint(tfm_6, use_unicode=False) + [-a + p 3 -a + p 3 ] + [-------*----- ------- + -----] + [9*s - 9 s + 2 9*s - 9 s + 2]{t} + >>> tfm_6.doit() + TransferFunctionMatrix(((TransferFunction(-3*a + 3*p, (s + 2)*(9*s - 9), s), TransferFunction(27*s + (-a + p)*(s + 2) - 27, (s + 2)*(9*s - 9), s)),)) + >>> pprint(_, use_unicode=False) + [ -3*a + 3*p 27*s + (-a + p)*(s + 2) - 27] + [----------------- ----------------------------] + [(s + 2)*(9*s - 9) (s + 2)*(9*s - 9) ]{t} + >>> tf_9 = TransferFunction(1, s, s) + >>> tf_10 = TransferFunction(1, s**2, s) + >>> tfm_7 = TransferFunctionMatrix([[Series(tf_9, tf_10), tf_9], [tf_10, Parallel(tf_9, tf_10)]]) + >>> tfm_7 + TransferFunctionMatrix(((Series(TransferFunction(1, s, s), TransferFunction(1, s**2, s)), TransferFunction(1, s, s)), (TransferFunction(1, s**2, s), Parallel(TransferFunction(1, s, s), TransferFunction(1, s**2, s))))) + >>> pprint(tfm_7, use_unicode=False) + [ 1 1 ] + [---- - ] + [ 2 s ] + [s*s ] + [ ] + [ 1 1 1] + [ -- -- + -] + [ 2 2 s] + [ s s ]{t} + >>> tfm_7.doit() + TransferFunctionMatrix(((TransferFunction(1, s**3, s), TransferFunction(1, s, s)), (TransferFunction(1, s**2, s), TransferFunction(s**2 + s, s**3, s)))) + >>> pprint(_, use_unicode=False) + [1 1 ] + [-- - ] + [ 3 s ] + [s ] + [ ] + [ 2 ] + [1 s + s] + [-- ------] + [ 2 3 ] + [s s ]{t} + + Addition, subtraction, and multiplication of transfer function matrices can form + unevaluated ``Series`` or ``Parallel`` objects. + + - For addition and subtraction: + All the transfer function matrices must have the same shape. + + - For multiplication (C = A * B): + The number of inputs of the first transfer function matrix (A) must be equal to the + number of outputs of the second transfer function matrix (B). + + Also, use pretty-printing (``pprint``) to analyse better. + + >>> tfm_8 = TransferFunctionMatrix([[tf_3], [tf_2], [-tf_1]]) + >>> tfm_9 = TransferFunctionMatrix([[-tf_3]]) + >>> tfm_10 = TransferFunctionMatrix([[tf_1], [tf_2], [tf_4]]) + >>> tfm_11 = TransferFunctionMatrix([[tf_4], [-tf_1]]) + >>> tfm_12 = TransferFunctionMatrix([[tf_4, -tf_1, tf_3], [-tf_2, -tf_4, -tf_3]]) + >>> tfm_8 + tfm_10 + MIMOParallel(TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a + p, 9*s - 9, s),)))) + >>> pprint(_, use_unicode=False) + [ 3 ] [ a + s ] + [ ----- ] [ ---------- ] + [ s + 2 ] [ 2 ] + [ ] [ s + s + 1 ] + [ 4 ] [ ] + [p - 3*p + 2] [ 4 ] + [------------] + [p - 3*p + 2] + [ p + s ] [------------] + [ ] [ p + s ] + [ -a - s ] [ ] + [ ---------- ] [ -a + p ] + [ 2 ] [ ------- ] + [ s + s + 1 ]{t} [ 9*s - 9 ]{t} + >>> -tfm_10 - tfm_8 + MIMOParallel(TransferFunctionMatrix(((TransferFunction(-a - s, s**2 + s + 1, s),), (TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a - p, 9*s - 9, s),))), TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),), (TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a + s, s**2 + s + 1, s),)))) + >>> pprint(_, use_unicode=False) + [ -a - s ] [ -3 ] + [ ---------- ] [ ----- ] + [ 2 ] [ s + 2 ] + [ s + s + 1 ] [ ] + [ ] [ 4 ] + [ 4 ] [- p + 3*p - 2] + [- p + 3*p - 2] + [--------------] + [--------------] [ p + s ] + [ p + s ] [ ] + [ ] [ a + s ] + [ a - p ] [ ---------- ] + [ ------- ] [ 2 ] + [ 9*s - 9 ]{t} [ s + s + 1 ]{t} + >>> tfm_12 * tfm_8 + MIMOSeries(TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(-a + p, 9*s - 9, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(3, s + 2, s)), (TransferFunction(-p**4 + 3*p - 2, p + s, s), TransferFunction(a - p, 9*s - 9, s), TransferFunction(-3, s + 2, s))))) + >>> pprint(_, use_unicode=False) + [ 3 ] + [ ----- ] + [ -a + p -a - s 3 ] [ s + 2 ] + [ ------- ---------- -----] [ ] + [ 9*s - 9 2 s + 2] [ 4 ] + [ s + s + 1 ] [p - 3*p + 2] + [ ] *[------------] + [ 4 ] [ p + s ] + [- p + 3*p - 2 a - p -3 ] [ ] + [-------------- ------- -----] [ -a - s ] + [ p + s 9*s - 9 s + 2]{t} [ ---------- ] + [ 2 ] + [ s + s + 1 ]{t} + >>> tfm_12 * tfm_8 * tfm_9 + MIMOSeries(TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),),)), TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(-a + p, 9*s - 9, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(3, s + 2, s)), (TransferFunction(-p**4 + 3*p - 2, p + s, s), TransferFunction(a - p, 9*s - 9, s), TransferFunction(-3, s + 2, s))))) + >>> pprint(_, use_unicode=False) + [ 3 ] + [ ----- ] + [ -a + p -a - s 3 ] [ s + 2 ] + [ ------- ---------- -----] [ ] + [ 9*s - 9 2 s + 2] [ 4 ] + [ s + s + 1 ] [p - 3*p + 2] [ -3 ] + [ ] *[------------] *[-----] + [ 4 ] [ p + s ] [s + 2]{t} + [- p + 3*p - 2 a - p -3 ] [ ] + [-------------- ------- -----] [ -a - s ] + [ p + s 9*s - 9 s + 2]{t} [ ---------- ] + [ 2 ] + [ s + s + 1 ]{t} + >>> tfm_10 + tfm_8*tfm_9 + MIMOParallel(TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a + p, 9*s - 9, s),))), MIMOSeries(TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),),)), TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))))) + >>> pprint(_, use_unicode=False) + [ a + s ] [ 3 ] + [ ---------- ] [ ----- ] + [ 2 ] [ s + 2 ] + [ s + s + 1 ] [ ] + [ ] [ 4 ] + [ 4 ] [p - 3*p + 2] [ -3 ] + [p - 3*p + 2] + [------------] *[-----] + [------------] [ p + s ] [s + 2]{t} + [ p + s ] [ ] + [ ] [ -a - s ] + [ -a + p ] [ ---------- ] + [ ------- ] [ 2 ] + [ 9*s - 9 ]{t} [ s + s + 1 ]{t} + + These unevaluated ``Series`` or ``Parallel`` objects can convert into the + resultant transfer function matrix using ``.doit()`` method or by + ``.rewrite(TransferFunctionMatrix)``. + + >>> (-tfm_8 + tfm_10 + tfm_8*tfm_9).doit() + TransferFunctionMatrix(((TransferFunction((a + s)*(s + 2)**3 - 3*(s + 2)**2*(s**2 + s + 1) - 9*(s + 2)*(s**2 + s + 1), (s + 2)**3*(s**2 + s + 1), s),), (TransferFunction((p + s)*(-3*p**4 + 9*p - 6), (p + s)**2*(s + 2), s),), (TransferFunction((-a + p)*(s + 2)*(s**2 + s + 1)**2 + (a + s)*(s + 2)*(9*s - 9)*(s**2 + s + 1) + (3*a + 3*s)*(9*s - 9)*(s**2 + s + 1), (s + 2)*(9*s - 9)*(s**2 + s + 1)**2, s),))) + >>> (-tfm_12 * -tfm_8 * -tfm_9).rewrite(TransferFunctionMatrix) + TransferFunctionMatrix(((TransferFunction(3*(-3*a + 3*p)*(p + s)*(s + 2)*(s**2 + s + 1)**2 + 3*(-3*a - 3*s)*(p + s)*(s + 2)*(9*s - 9)*(s**2 + s + 1) + 3*(a + s)*(s + 2)**2*(9*s - 9)*(-p**4 + 3*p - 2)*(s**2 + s + 1), (p + s)*(s + 2)**3*(9*s - 9)*(s**2 + s + 1)**2, s),), (TransferFunction(3*(-a + p)*(p + s)*(s + 2)**2*(-p**4 + 3*p - 2)*(s**2 + s + 1) + 3*(3*a + 3*s)*(p + s)**2*(s + 2)*(9*s - 9) + 3*(p + s)*(s + 2)*(9*s - 9)*(-3*p**4 + 9*p - 6)*(s**2 + s + 1), (p + s)**2*(s + 2)**3*(9*s - 9)*(s**2 + s + 1), s),))) + + See Also + ======== + + TransferFunction, MIMOSeries, MIMOParallel, Feedback + + """ + def __new__(cls, arg): + + expr_mat_arg = [] + try: + var = arg[0][0].var + except TypeError: + raise ValueError(filldedent(""" + `arg` param in TransferFunctionMatrix should + strictly be a nested list containing TransferFunction + objects.""")) + for row in arg: + temp = [] + for element in row: + if not isinstance(element, SISOLinearTimeInvariant): + raise TypeError(filldedent(""" + Each element is expected to be of + type `SISOLinearTimeInvariant`.""")) + + if var != element.var: + raise ValueError(filldedent(""" + Conflicting value(s) found for `var`. All TransferFunction + instances in TransferFunctionMatrix should use the same + complex variable in Laplace domain.""")) + + temp.append(element.to_expr()) + expr_mat_arg.append(temp) + + if isinstance(arg, (tuple, list, Tuple)): + # Making nested Tuple (sympy.core.containers.Tuple) from nested list or nested Python tuple + arg = Tuple(*(Tuple(*r, sympify=False) for r in arg), sympify=False) + + obj = super(TransferFunctionMatrix, cls).__new__(cls, arg) + obj._expr_mat = ImmutableMatrix(expr_mat_arg) + obj.is_StateSpace_object = False + return obj + + @classmethod + def from_Matrix(cls, matrix, var): + """ + Creates a new ``TransferFunctionMatrix`` efficiently from a SymPy Matrix of ``Expr`` objects. + + Parameters + ========== + + matrix : ``ImmutableMatrix`` having ``Expr``/``Number`` elements. + var : Symbol + Complex variable of the Laplace transform which will be used by the + all the ``TransferFunction`` objects in the ``TransferFunctionMatrix``. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunctionMatrix + >>> from sympy import Matrix, pprint + >>> M = Matrix([[s, 1/s], [1/(s+1), s]]) + >>> M_tf = TransferFunctionMatrix.from_Matrix(M, s) + >>> pprint(M_tf, use_unicode=False) + [ s 1] + [ - -] + [ 1 s] + [ ] + [ 1 s] + [----- -] + [s + 1 1]{t} + >>> M_tf.elem_poles() + [[[], [0]], [[-1], []]] + >>> M_tf.elem_zeros() + [[[0], []], [[], [0]]] + + """ + return _to_TFM(matrix, var) + + @property + def var(self): + """ + Returns the complex variable used by all the transfer functions or + ``Series``/``Parallel`` objects in a transfer function matrix. + + Examples + ======== + + >>> from sympy.abc import p, s + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, Series, Parallel + >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) + >>> G2 = TransferFunction(p, 4 - p, p) + >>> G3 = TransferFunction(0, p**4 - 1, p) + >>> G4 = TransferFunction(s + 1, s**2 + s + 1, s) + >>> S1 = Series(G1, G2) + >>> S2 = Series(-G3, Parallel(G2, -G1)) + >>> tfm1 = TransferFunctionMatrix([[G1], [G2], [G3]]) + >>> tfm1.var + p + >>> tfm2 = TransferFunctionMatrix([[-S1, -S2], [S1, S2]]) + >>> tfm2.var + p + >>> tfm3 = TransferFunctionMatrix([[G4]]) + >>> tfm3.var + s + + """ + return self.args[0][0][0].var + + @property + def num_inputs(self): + """ + Returns the number of inputs of the system. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix + >>> G1 = TransferFunction(s + 3, s**2 - 3, s) + >>> G2 = TransferFunction(4, s**2, s) + >>> G3 = TransferFunction(p**2 + s**2, p - 3, s) + >>> tfm_1 = TransferFunctionMatrix([[G2, -G1, G3], [-G2, -G1, -G3]]) + >>> tfm_1.num_inputs + 3 + + See Also + ======== + + num_outputs + + """ + return self._expr_mat.shape[1] + + @property + def num_outputs(self): + """ + Returns the number of outputs of the system. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunctionMatrix + >>> from sympy import Matrix + >>> M_1 = Matrix([[s], [1/s]]) + >>> TFM = TransferFunctionMatrix.from_Matrix(M_1, s) + >>> print(TFM) + TransferFunctionMatrix(((TransferFunction(s, 1, s),), (TransferFunction(1, s, s),))) + >>> TFM.num_outputs + 2 + + See Also + ======== + + num_inputs + + """ + return self._expr_mat.shape[0] + + @property + def shape(self): + """ + Returns the shape of the transfer function matrix, that is, ``(# of outputs, # of inputs)``. + + Examples + ======== + + >>> from sympy.abc import s, p + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix + >>> tf1 = TransferFunction(p**2 - 1, s**4 + s**3 - p, p) + >>> tf2 = TransferFunction(1 - p, p**2 - 3*p + 7, p) + >>> tf3 = TransferFunction(3, 4, p) + >>> tfm1 = TransferFunctionMatrix([[tf1, -tf2]]) + >>> tfm1.shape + (1, 2) + >>> tfm2 = TransferFunctionMatrix([[-tf2, tf3], [tf1, -tf1]]) + >>> tfm2.shape + (2, 2) + + """ + return self._expr_mat.shape + + def __neg__(self): + neg = -self._expr_mat + return _to_TFM(neg, self.var) + + @_check_other_MIMO + def __add__(self, other): + + if not isinstance(other, MIMOParallel): + return MIMOParallel(self, other) + other_arg_list = list(other.args) + return MIMOParallel(self, *other_arg_list) + + @_check_other_MIMO + def __sub__(self, other): + return self + (-other) + + @_check_other_MIMO + def __mul__(self, other): + + if not isinstance(other, MIMOSeries): + return MIMOSeries(other, self) + other_arg_list = list(other.args) + return MIMOSeries(*other_arg_list, self) + + def __getitem__(self, key): + trunc = self._expr_mat.__getitem__(key) + if isinstance(trunc, ImmutableMatrix): + return _to_TFM(trunc, self.var) + return TransferFunction.from_rational_expression(trunc, self.var) + + def transpose(self): + """Returns the transpose of the ``TransferFunctionMatrix`` (switched input and output layers).""" + transposed_mat = self._expr_mat.transpose() + return _to_TFM(transposed_mat, self.var) + + def elem_poles(self): + """ + Returns the poles of each element of the ``TransferFunctionMatrix``. + + .. note:: + Actual poles of a MIMO system are NOT the poles of individual elements. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix + >>> tf_1 = TransferFunction(3, (s + 1), s) + >>> tf_2 = TransferFunction(s + 6, (s + 1)*(s + 2), s) + >>> tf_3 = TransferFunction(s + 3, s**2 + 3*s + 2, s) + >>> tf_4 = TransferFunction(s + 2, s**2 + 5*s - 10, s) + >>> tfm_1 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, tf_4]]) + >>> tfm_1 + TransferFunctionMatrix(((TransferFunction(3, s + 1, s), TransferFunction(s + 6, (s + 1)*(s + 2), s)), (TransferFunction(s + 3, s**2 + 3*s + 2, s), TransferFunction(s + 2, s**2 + 5*s - 10, s)))) + >>> tfm_1.elem_poles() + [[[-1], [-2, -1]], [[-2, -1], [-5/2 + sqrt(65)/2, -sqrt(65)/2 - 5/2]]] + + See Also + ======== + + elem_zeros + + """ + return [[element.poles() for element in row] for row in self.doit().args[0]] + + def elem_zeros(self): + """ + Returns the zeros of each element of the ``TransferFunctionMatrix``. + + .. note:: + Actual zeros of a MIMO system are NOT the zeros of individual elements. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix + >>> tf_1 = TransferFunction(3, (s + 1), s) + >>> tf_2 = TransferFunction(s + 6, (s + 1)*(s + 2), s) + >>> tf_3 = TransferFunction(s + 3, s**2 + 3*s + 2, s) + >>> tf_4 = TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s) + >>> tfm_1 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, tf_4]]) + >>> tfm_1 + TransferFunctionMatrix(((TransferFunction(3, s + 1, s), TransferFunction(s + 6, (s + 1)*(s + 2), s)), (TransferFunction(s + 3, s**2 + 3*s + 2, s), TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s)))) + >>> tfm_1.elem_zeros() + [[[], [-6]], [[-3], [4, 5]]] + + See Also + ======== + + elem_poles + + """ + return [[element.zeros() for element in row] for row in self.doit().args[0]] + + def eval_frequency(self, other): + """ + Evaluates system response of each transfer function in the ``TransferFunctionMatrix`` at any point in the real or complex plane. + + Examples + ======== + + >>> from sympy.abc import s + >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix + >>> from sympy import I + >>> tf_1 = TransferFunction(3, (s + 1), s) + >>> tf_2 = TransferFunction(s + 6, (s + 1)*(s + 2), s) + >>> tf_3 = TransferFunction(s + 3, s**2 + 3*s + 2, s) + >>> tf_4 = TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s) + >>> tfm_1 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, tf_4]]) + >>> tfm_1 + TransferFunctionMatrix(((TransferFunction(3, s + 1, s), TransferFunction(s + 6, (s + 1)*(s + 2), s)), (TransferFunction(s + 3, s**2 + 3*s + 2, s), TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s)))) + >>> tfm_1.eval_frequency(2) + Matrix([ + [ 1, 2/3], + [5/12, 3/2]]) + >>> tfm_1.eval_frequency(I*2) + Matrix([ + [ 3/5 - 6*I/5, -I], + [3/20 - 11*I/20, -101/74 + 23*I/74]]) + """ + mat = self._expr_mat.subs(self.var, other) + return mat.expand() + + def _flat(self): + """Returns flattened list of args in TransferFunctionMatrix""" + return [elem for tup in self.args[0] for elem in tup] + + def _eval_evalf(self, prec): + """Calls evalf() on each transfer function in the transfer function matrix""" + dps = prec_to_dps(prec) + mat = self._expr_mat.applyfunc(lambda a: a.evalf(n=dps)) + return _to_TFM(mat, self.var) + + def _eval_simplify(self, **kwargs): + """Simplifies the transfer function matrix""" + simp_mat = self._expr_mat.applyfunc(lambda a: cancel(a, expand=False)) + return _to_TFM(simp_mat, self.var) + + def expand(self, **hints): + """Expands the transfer function matrix""" + expand_mat = self._expr_mat.expand(**hints) + return _to_TFM(expand_mat, self.var) + +class StateSpace(LinearTimeInvariant): + r""" + State space model (ssm) of a linear, time invariant control system. + + Represents the standard state-space model with A, B, C, D as state-space matrices. + This makes the linear control system: + + (1) x'(t) = A * x(t) + B * u(t); x in R^n , u in R^k + (2) y(t) = C * x(t) + D * u(t); y in R^m + + where u(t) is any input signal, y(t) the corresponding output, and x(t) the system's state. + + Parameters + ========== + + A : Matrix + The State matrix of the state space model. + B : Matrix + The Input-to-State matrix of the state space model. + C : Matrix + The State-to-Output matrix of the state space model. + D : Matrix + The Feedthrough matrix of the state space model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + + The easiest way to create a StateSpaceModel is via four matrices: + + >>> A = Matrix([[1, 2], [1, 0]]) + >>> B = Matrix([1, 1]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([0]) + >>> StateSpace(A, B, C, D) + StateSpace(Matrix([ + [1, 2], + [1, 0]]), Matrix([ + [1], + [1]]), Matrix([[0, 1]]), Matrix([[0]])) + + One can use less matrices. The rest will be filled with a minimum of zeros: + + >>> StateSpace(A, B) + StateSpace(Matrix([ + [1, 2], + [1, 0]]), Matrix([ + [1], + [1]]), Matrix([[0, 0]]), Matrix([[0]])) + + See Also + ======== + + TransferFunction, TransferFunctionMatrix + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/State-space_representation + .. [2] https://in.mathworks.com/help/control/ref/ss.html + + """ + def __new__(cls, A=None, B=None, C=None, D=None): + if A is None: + A = zeros(1) + if B is None: + B = zeros(A.rows, 1) + if C is None: + C = zeros(1, A.cols) + if D is None: + D = zeros(C.rows, B.cols) + + A = _sympify(A) + B = _sympify(B) + C = _sympify(C) + D = _sympify(D) + + if (isinstance(A, ImmutableDenseMatrix) and isinstance(B, ImmutableDenseMatrix) and + isinstance(C, ImmutableDenseMatrix) and isinstance(D, ImmutableDenseMatrix)): + # Check State Matrix is square + if A.rows != A.cols: + raise ShapeError("Matrix A must be a square matrix.") + + # Check State and Input matrices have same rows + if A.rows != B.rows: + raise ShapeError("Matrices A and B must have the same number of rows.") + + # Check Output and Feedthrough matrices have same rows + if C.rows != D.rows: + raise ShapeError("Matrices C and D must have the same number of rows.") + + # Check State and Output matrices have same columns + if A.cols != C.cols: + raise ShapeError("Matrices A and C must have the same number of columns.") + + # Check Input and Feedthrough matrices have same columns + if B.cols != D.cols: + raise ShapeError("Matrices B and D must have the same number of columns.") + + obj = super(StateSpace, cls).__new__(cls, A, B, C, D) + obj._A = A + obj._B = B + obj._C = C + obj._D = D + + # Determine if the system is SISO or MIMO + num_outputs = D.rows + num_inputs = D.cols + if num_inputs == 1 and num_outputs == 1: + obj._is_SISO = True + obj._clstype = SISOLinearTimeInvariant + else: + obj._is_SISO = False + obj._clstype = MIMOLinearTimeInvariant + obj.is_StateSpace_object = True + return obj + + else: + raise TypeError("A, B, C and D inputs must all be sympy Matrices.") + + @property + def state_matrix(self): + """ + Returns the state matrix of the model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[1, 2], [1, 0]]) + >>> B = Matrix([1, 1]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.state_matrix + Matrix([ + [1, 2], + [1, 0]]) + + """ + return self._A + + @property + def input_matrix(self): + """ + Returns the input matrix of the model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[1, 2], [1, 0]]) + >>> B = Matrix([1, 1]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.input_matrix + Matrix([ + [1], + [1]]) + + """ + return self._B + + @property + def output_matrix(self): + """ + Returns the output matrix of the model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[1, 2], [1, 0]]) + >>> B = Matrix([1, 1]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.output_matrix + Matrix([[0, 1]]) + + """ + return self._C + + @property + def feedforward_matrix(self): + """ + Returns the feedforward matrix of the model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[1, 2], [1, 0]]) + >>> B = Matrix([1, 1]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.feedforward_matrix + Matrix([[0]]) + + """ + return self._D + + A = state_matrix + B = input_matrix + C = output_matrix + D = feedforward_matrix + + @property + def num_states(self): + """ + Returns the number of states of the model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[1, 2], [1, 0]]) + >>> B = Matrix([1, 1]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.num_states + 2 + + """ + return self._A.rows + + @property + def num_inputs(self): + """ + Returns the number of inputs of the model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[1, 2], [1, 0]]) + >>> B = Matrix([1, 1]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.num_inputs + 1 + + """ + return self._D.cols + + @property + def num_outputs(self): + """ + Returns the number of outputs of the model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[1, 2], [1, 0]]) + >>> B = Matrix([1, 1]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.num_outputs + 1 + + """ + return self._D.rows + + + @property + def shape(self): + """Returns the shape of the equivalent StateSpace system.""" + return self.num_outputs, self.num_inputs + + def dsolve(self, initial_conditions=None, input_vector=None, var=Symbol('t')): + r""" + Returns `y(t)` or output of StateSpace given by the solution of equations: + x'(t) = A * x(t) + B * u(t) + y(t) = C * x(t) + D * u(t) + + Parameters + ============ + + initial_conditions : Matrix + The initial conditions of `x` state vector. If not provided, it defaults to a zero vector. + input_vector : Matrix + The input vector for state space. If not provided, it defaults to a zero vector. + var : Symbol + The symbol representing time. If not provided, it defaults to `t`. + + Examples + ========== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-2, 0], [1, -1]]) + >>> B = Matrix([[1], [0]]) + >>> C = Matrix([[2, 1]]) + >>> ip = Matrix([5]) + >>> i = Matrix([0, 0]) + >>> ss = StateSpace(A, B, C) + >>> ss.dsolve(input_vector=ip, initial_conditions=i).simplify() + Matrix([[15/2 - 5*exp(-t) - 5*exp(-2*t)/2]]) + + If no input is provided it defaults to solving the system with zero initial conditions and zero input. + + >>> ss.dsolve() + Matrix([[0]]) + + References + ========== + .. [1] https://web.mit.edu/2.14/www/Handouts/StateSpaceResponse.pdf + .. [2] https://docs.sympy.org/latest/modules/solvers/ode.html#sympy.solvers.ode.systems.linodesolve + + """ + + if not isinstance(var, Symbol): + raise ValueError("Variable for representing time must be a Symbol.") + if not initial_conditions: + initial_conditions = zeros(self._A.shape[0], 1) + elif initial_conditions.shape != (self._A.shape[0], 1): + raise ShapeError("Initial condition vector should have the same number of " + "rows as the state matrix.") + if not input_vector: + input_vector = zeros(self._B.shape[1], 1) + elif input_vector.shape != (self._B.shape[1], 1): + raise ShapeError("Input vector should have the same number of " + "columns as the input matrix.") + sol = linodesolve(A=self._A, t=var, b=self._B*input_vector, type='type2', doit=True) + mat1 = Matrix(sol) + mat2 = mat1.replace(var, 0) + free1 = self._A.free_symbols | self._B.free_symbols | input_vector.free_symbols + free2 = mat2.free_symbols + # Get all the free symbols form the matrix + dummy_symbols = list(free2-free1) + # Convert the matrix to a Coefficient matrix + r1, r2 = linear_eq_to_matrix(mat2, dummy_symbols) + s = linsolve((r1, initial_conditions+r2)) + res_tuple = next(iter(s)) + for ind, v in enumerate(res_tuple): + mat1 = mat1.replace(dummy_symbols[ind], v) + res = self._C*mat1 + self._D*input_vector + return res + + def _eval_evalf(self, prec): + """ + Returns state space model where numerical expressions are evaluated into floating point numbers. + """ + dps = prec_to_dps(prec) + return StateSpace( + self._A.evalf(n = dps), + self._B.evalf(n = dps), + self._C.evalf(n = dps), + self._D.evalf(n = dps)) + + def _eval_rewrite_as_TransferFunction(self, *args): + """ + Returns the equivalent Transfer Function of the state space model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import TransferFunction, StateSpace + >>> A = Matrix([[-5, -1], [3, -1]]) + >>> B = Matrix([2, 5]) + >>> C = Matrix([[1, 2]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.rewrite(TransferFunction) + [[TransferFunction(12*s + 59, s**2 + 6*s + 8, s)]] + + """ + s = Symbol('s') + n = self._A.shape[0] + I = eye(n) + G = self._C*(s*I - self._A).solve(self._B) + self._D + G = G.simplify() + to_tf = lambda expr: TransferFunction.from_rational_expression(expr, s) + tf_mat = [[to_tf(expr) for expr in sublist] for sublist in G.tolist()] + return tf_mat + + def __add__(self, other): + """ + Add two State Space systems (parallel connection). + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A1 = Matrix([[1]]) + >>> B1 = Matrix([[2]]) + >>> C1 = Matrix([[-1]]) + >>> D1 = Matrix([[-2]]) + >>> A2 = Matrix([[-1]]) + >>> B2 = Matrix([[-2]]) + >>> C2 = Matrix([[1]]) + >>> D2 = Matrix([[2]]) + >>> ss1 = StateSpace(A1, B1, C1, D1) + >>> ss2 = StateSpace(A2, B2, C2, D2) + >>> ss1 + ss2 + StateSpace(Matrix([ + [1, 0], + [0, -1]]), Matrix([ + [ 2], + [-2]]), Matrix([[-1, 1]]), Matrix([[0]])) + + """ + # Check for scalars + if isinstance(other, (int, float, complex, Symbol)): + A = self._A + B = self._B + C = self._C + D = self._D.applyfunc(lambda element: element + other) + + else: + # Check nature of system + if not isinstance(other, StateSpace): + raise ValueError("Addition is only supported for 2 State Space models.") + # Check dimensions of system + elif ((self.num_inputs != other.num_inputs) or (self.num_outputs != other.num_outputs)): + raise ShapeError("Systems with incompatible inputs and outputs cannot be added.") + + m1 = (self._A).row_join(zeros(self._A.shape[0], other._A.shape[-1])) + m2 = zeros(other._A.shape[0], self._A.shape[-1]).row_join(other._A) + + A = m1.col_join(m2) + B = self._B.col_join(other._B) + C = self._C.row_join(other._C) + D = self._D + other._D + + return StateSpace(A, B, C, D) + + def __radd__(self, other): + """ + Right add two State Space systems. + + Examples + ======== + + >>> from sympy.physics.control import StateSpace + >>> s = StateSpace() + >>> 5 + s + StateSpace(Matrix([[0]]), Matrix([[0]]), Matrix([[0]]), Matrix([[5]])) + + """ + return self + other + + def __sub__(self, other): + """ + Subtract two State Space systems. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A1 = Matrix([[1]]) + >>> B1 = Matrix([[2]]) + >>> C1 = Matrix([[-1]]) + >>> D1 = Matrix([[-2]]) + >>> A2 = Matrix([[-1]]) + >>> B2 = Matrix([[-2]]) + >>> C2 = Matrix([[1]]) + >>> D2 = Matrix([[2]]) + >>> ss1 = StateSpace(A1, B1, C1, D1) + >>> ss2 = StateSpace(A2, B2, C2, D2) + >>> ss1 - ss2 + StateSpace(Matrix([ + [1, 0], + [0, -1]]), Matrix([ + [ 2], + [-2]]), Matrix([[-1, -1]]), Matrix([[-4]])) + + """ + return self + (-other) + + def __rsub__(self, other): + """ + Right subtract two tate Space systems. + + Examples + ======== + + >>> from sympy.physics.control import StateSpace + >>> s = StateSpace() + >>> 5 - s + StateSpace(Matrix([[0]]), Matrix([[0]]), Matrix([[0]]), Matrix([[5]])) + + """ + return other + (-self) + + def __neg__(self): + """ + Returns the negation of the state space model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-5, -1], [3, -1]]) + >>> B = Matrix([2, 5]) + >>> C = Matrix([[1, 2]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> -ss + StateSpace(Matrix([ + [-5, -1], + [ 3, -1]]), Matrix([ + [2], + [5]]), Matrix([[-1, -2]]), Matrix([[0]])) + + """ + return StateSpace(self._A, self._B, -self._C, -self._D) + + def __mul__(self, other): + """ + Multiplication of two State Space systems (serial connection). + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-5, -1], [3, -1]]) + >>> B = Matrix([2, 5]) + >>> C = Matrix([[1, 2]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> ss*5 + StateSpace(Matrix([ + [-5, -1], + [ 3, -1]]), Matrix([ + [2], + [5]]), Matrix([[5, 10]]), Matrix([[0]])) + + """ + # Check for scalars + if isinstance(other, (int, float, complex, Symbol)): + A = self._A + B = self._B + C = self._C.applyfunc(lambda element: element*other) + D = self._D.applyfunc(lambda element: element*other) + + else: + # Check nature of system + if not isinstance(other, StateSpace): + raise ValueError("Multiplication is only supported for 2 State Space models.") + # Check dimensions of system + elif self.num_inputs != other.num_outputs: + raise ShapeError("Systems with incompatible inputs and outputs cannot be multiplied.") + + m1 = (other._A).row_join(zeros(other._A.shape[0], self._A.shape[1])) + m2 = (self._B * other._C).row_join(self._A) + + A = m1.col_join(m2) + B = (other._B).col_join(self._B * other._D) + C = (self._D * other._C).row_join(self._C) + D = self._D * other._D + + return StateSpace(A, B, C, D) + + def __rmul__(self, other): + """ + Right multiply two tate Space systems. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-5, -1], [3, -1]]) + >>> B = Matrix([2, 5]) + >>> C = Matrix([[1, 2]]) + >>> D = Matrix([0]) + >>> ss = StateSpace(A, B, C, D) + >>> 5*ss + StateSpace(Matrix([ + [-5, -1], + [ 3, -1]]), Matrix([ + [10], + [25]]), Matrix([[1, 2]]), Matrix([[0]])) + + """ + if isinstance(other, (int, float, complex, Symbol)): + A = self._A + C = self._C + B = self._B.applyfunc(lambda element: element*other) + D = self._D.applyfunc(lambda element: element*other) + return StateSpace(A, B, C, D) + else: + return self*other + + def __repr__(self): + A_str = self._A.__repr__() + B_str = self._B.__repr__() + C_str = self._C.__repr__() + D_str = self._D.__repr__() + + return f"StateSpace(\n{A_str},\n\n{B_str},\n\n{C_str},\n\n{D_str})" + + + def append(self, other): + """ + Returns the first model appended with the second model. The order is preserved. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A1 = Matrix([[1]]) + >>> B1 = Matrix([[2]]) + >>> C1 = Matrix([[-1]]) + >>> D1 = Matrix([[-2]]) + >>> A2 = Matrix([[-1]]) + >>> B2 = Matrix([[-2]]) + >>> C2 = Matrix([[1]]) + >>> D2 = Matrix([[2]]) + >>> ss1 = StateSpace(A1, B1, C1, D1) + >>> ss2 = StateSpace(A2, B2, C2, D2) + >>> ss1.append(ss2) + StateSpace(Matrix([ + [1, 0], + [0, -1]]), Matrix([ + [2, 0], + [0, -2]]), Matrix([ + [-1, 0], + [ 0, 1]]), Matrix([ + [-2, 0], + [ 0, 2]])) + + """ + n = self.num_states + other.num_states + m = self.num_inputs + other.num_inputs + p = self.num_outputs + other.num_outputs + + A = zeros(n, n) + B = zeros(n, m) + C = zeros(p, n) + D = zeros(p, m) + + A[:self.num_states, :self.num_states] = self._A + A[self.num_states:, self.num_states:] = other._A + B[:self.num_states, :self.num_inputs] = self._B + B[self.num_states:, self.num_inputs:] = other._B + C[:self.num_outputs, :self.num_states] = self._C + C[self.num_outputs:, self.num_states:] = other._C + D[:self.num_outputs, :self.num_inputs] = self._D + D[self.num_outputs:, self.num_inputs:] = other._D + return StateSpace(A, B, C, D) + + def observability_matrix(self): + """ + Returns the observability matrix of the state space model: + [C, C * A^1, C * A^2, .. , C * A^(n-1)]; A in R^(n x n), C in R^(m x k) + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-1.5, -2], [1, 0]]) + >>> B = Matrix([0.5, 0]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([1]) + >>> ss = StateSpace(A, B, C, D) + >>> ob = ss.observability_matrix() + >>> ob + Matrix([ + [0, 1], + [1, 0]]) + + References + ========== + .. [1] https://in.mathworks.com/help/control/ref/statespacemodel.obsv.html + + """ + n = self.num_states + ob = self._C + for i in range(1,n): + ob = ob.col_join(self._C * self._A**i) + + return ob + + def observable_subspace(self): + """ + Returns the observable subspace of the state space model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-1.5, -2], [1, 0]]) + >>> B = Matrix([0.5, 0]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([1]) + >>> ss = StateSpace(A, B, C, D) + >>> ob_subspace = ss.observable_subspace() + >>> ob_subspace + [Matrix([ + [0], + [1]]), Matrix([ + [1], + [0]])] + + """ + return self.observability_matrix().columnspace() + + def is_observable(self): + """ + Returns if the state space model is observable. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-1.5, -2], [1, 0]]) + >>> B = Matrix([0.5, 0]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([1]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.is_observable() + True + + """ + return self.observability_matrix().rank() == self.num_states + + def controllability_matrix(self): + """ + Returns the controllability matrix of the system: + [B, A * B, A^2 * B, .. , A^(n-1) * B]; A in R^(n x n), B in R^(n x m) + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-1.5, -2], [1, 0]]) + >>> B = Matrix([0.5, 0]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([1]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.controllability_matrix() + Matrix([ + [0.5, -0.75], + [ 0, 0.5]]) + + References + ========== + .. [1] https://in.mathworks.com/help/control/ref/statespacemodel.ctrb.html + + """ + co = self._B + n = self._A.shape[0] + for i in range(1, n): + co = co.row_join(((self._A)**i) * self._B) + + return co + + def controllable_subspace(self): + """ + Returns the controllable subspace of the state space model. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-1.5, -2], [1, 0]]) + >>> B = Matrix([0.5, 0]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([1]) + >>> ss = StateSpace(A, B, C, D) + >>> co_subspace = ss.controllable_subspace() + >>> co_subspace + [Matrix([ + [0.5], + [ 0]]), Matrix([ + [-0.75], + [ 0.5]])] + + """ + return self.controllability_matrix().columnspace() + + def is_controllable(self): + """ + Returns if the state space model is controllable. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.physics.control import StateSpace + >>> A = Matrix([[-1.5, -2], [1, 0]]) + >>> B = Matrix([0.5, 0]) + >>> C = Matrix([[0, 1]]) + >>> D = Matrix([1]) + >>> ss = StateSpace(A, B, C, D) + >>> ss.is_controllable() + True + + """ + return self.controllability_matrix().rank() == self.num_states diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/gamma_matrices.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/gamma_matrices.py new file mode 100644 index 0000000000000000000000000000000000000000..40c3d0754438902f304d01c2df354dd09f9ea257 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/gamma_matrices.py @@ -0,0 +1,716 @@ +""" + Module to handle gamma matrices expressed as tensor objects. + + Examples + ======== + + >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, LorentzIndex + >>> from sympy.tensor.tensor import tensor_indices + >>> i = tensor_indices('i', LorentzIndex) + >>> G(i) + GammaMatrix(i) + + Note that there is already an instance of GammaMatrixHead in four dimensions: + GammaMatrix, which is simply declare as + + >>> from sympy.physics.hep.gamma_matrices import GammaMatrix + >>> from sympy.tensor.tensor import tensor_indices + >>> i = tensor_indices('i', LorentzIndex) + >>> GammaMatrix(i) + GammaMatrix(i) + + To access the metric tensor + + >>> LorentzIndex.metric + metric(LorentzIndex,LorentzIndex) + +""" +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.matrices.dense import eye +from sympy.matrices.expressions.trace import trace +from sympy.tensor.tensor import TensorIndexType, TensorIndex,\ + TensMul, TensAdd, tensor_mul, Tensor, TensorHead, TensorSymmetry + + +# DiracSpinorIndex = TensorIndexType('DiracSpinorIndex', dim=4, dummy_name="S") + + +LorentzIndex = TensorIndexType('LorentzIndex', dim=4, dummy_name="L") + + +GammaMatrix = TensorHead("GammaMatrix", [LorentzIndex], + TensorSymmetry.no_symmetry(1), comm=None) + + +def extract_type_tens(expression, component): + """ + Extract from a ``TensExpr`` all tensors with `component`. + + Returns two tensor expressions: + + * the first contains all ``Tensor`` of having `component`. + * the second contains all remaining. + + + """ + if isinstance(expression, Tensor): + sp = [expression] + elif isinstance(expression, TensMul): + sp = expression.args + else: + raise ValueError('wrong type') + + # Collect all gamma matrices of the same dimension + new_expr = S.One + residual_expr = S.One + for i in sp: + if isinstance(i, Tensor) and i.component == component: + new_expr *= i + else: + residual_expr *= i + return new_expr, residual_expr + + +def simplify_gamma_expression(expression): + extracted_expr, residual_expr = extract_type_tens(expression, GammaMatrix) + res_expr = _simplify_single_line(extracted_expr) + return res_expr * residual_expr + + +def simplify_gpgp(ex, sort=True): + """ + simplify products ``G(i)*p(-i)*G(j)*p(-j) -> p(i)*p(-i)`` + + Examples + ======== + + >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, \ + LorentzIndex, simplify_gpgp + >>> from sympy.tensor.tensor import tensor_indices, tensor_heads + >>> p, q = tensor_heads('p, q', [LorentzIndex]) + >>> i0,i1,i2,i3,i4,i5 = tensor_indices('i0:6', LorentzIndex) + >>> ps = p(i0)*G(-i0) + >>> qs = q(i0)*G(-i0) + >>> simplify_gpgp(ps*qs*qs) + GammaMatrix(-L_0)*p(L_0)*q(L_1)*q(-L_1) + """ + def _simplify_gpgp(ex): + components = ex.components + a = [] + comp_map = [] + for i, comp in enumerate(components): + comp_map.extend([i]*comp.rank) + dum = [(i[0], i[1], comp_map[i[0]], comp_map[i[1]]) for i in ex.dum] + for i in range(len(components)): + if components[i] != GammaMatrix: + continue + for dx in dum: + if dx[2] == i: + p_pos1 = dx[3] + elif dx[3] == i: + p_pos1 = dx[2] + else: + continue + comp1 = components[p_pos1] + if comp1.comm == 0 and comp1.rank == 1: + a.append((i, p_pos1)) + if not a: + return ex + elim = set() + tv = [] + hit = True + coeff = S.One + ta = None + while hit: + hit = False + for i, ai in enumerate(a[:-1]): + if ai[0] in elim: + continue + if ai[0] != a[i + 1][0] - 1: + continue + if components[ai[1]] != components[a[i + 1][1]]: + continue + elim.add(ai[0]) + elim.add(ai[1]) + elim.add(a[i + 1][0]) + elim.add(a[i + 1][1]) + if not ta: + ta = ex.split() + mu = TensorIndex('mu', LorentzIndex) + hit = True + if i == 0: + coeff = ex.coeff + tx = components[ai[1]](mu)*components[ai[1]](-mu) + if len(a) == 2: + tx *= 4 # eye(4) + tv.append(tx) + break + + if tv: + a = [x for j, x in enumerate(ta) if j not in elim] + a.extend(tv) + t = tensor_mul(*a)*coeff + # t = t.replace(lambda x: x.is_Matrix, lambda x: 1) + return t + else: + return ex + + if sort: + ex = ex.sorted_components() + # this would be better off with pattern matching + while 1: + t = _simplify_gpgp(ex) + if t != ex: + ex = t + else: + return t + + +def gamma_trace(t): + """ + trace of a single line of gamma matrices + + Examples + ======== + + >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, \ + gamma_trace, LorentzIndex + >>> from sympy.tensor.tensor import tensor_indices, tensor_heads + >>> p, q = tensor_heads('p, q', [LorentzIndex]) + >>> i0,i1,i2,i3,i4,i5 = tensor_indices('i0:6', LorentzIndex) + >>> ps = p(i0)*G(-i0) + >>> qs = q(i0)*G(-i0) + >>> gamma_trace(G(i0)*G(i1)) + 4*metric(i0, i1) + >>> gamma_trace(ps*ps) - 4*p(i0)*p(-i0) + 0 + >>> gamma_trace(ps*qs + ps*ps) - 4*p(i0)*p(-i0) - 4*p(i0)*q(-i0) + 0 + + """ + if isinstance(t, TensAdd): + res = TensAdd(*[gamma_trace(x) for x in t.args]) + return res + t = _simplify_single_line(t) + res = _trace_single_line(t) + return res + + +def _simplify_single_line(expression): + """ + Simplify single-line product of gamma matrices. + + Examples + ======== + + >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, \ + LorentzIndex, _simplify_single_line + >>> from sympy.tensor.tensor import tensor_indices, TensorHead + >>> p = TensorHead('p', [LorentzIndex]) + >>> i0,i1 = tensor_indices('i0:2', LorentzIndex) + >>> _simplify_single_line(G(i0)*G(i1)*p(-i1)*G(-i0)) + 2*G(i0)*p(-i0) + 0 + + """ + t1, t2 = extract_type_tens(expression, GammaMatrix) + if t1 != 1: + t1 = kahane_simplify(t1) + res = t1*t2 + return res + + +def _trace_single_line(t): + """ + Evaluate the trace of a single gamma matrix line inside a ``TensExpr``. + + Notes + ===== + + If there are ``DiracSpinorIndex.auto_left`` and ``DiracSpinorIndex.auto_right`` + indices trace over them; otherwise traces are not implied (explain) + + + Examples + ======== + + >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, \ + LorentzIndex, _trace_single_line + >>> from sympy.tensor.tensor import tensor_indices, TensorHead + >>> p = TensorHead('p', [LorentzIndex]) + >>> i0,i1,i2,i3,i4,i5 = tensor_indices('i0:6', LorentzIndex) + >>> _trace_single_line(G(i0)*G(i1)) + 4*metric(i0, i1) + >>> _trace_single_line(G(i0)*p(-i0)*G(i1)*p(-i1)) - 4*p(i0)*p(-i0) + 0 + + """ + def _trace_single_line1(t): + t = t.sorted_components() + components = t.components + ncomps = len(components) + g = LorentzIndex.metric + # gamma matirices are in a[i:j] + hit = 0 + for i in range(ncomps): + if components[i] == GammaMatrix: + hit = 1 + break + + for j in range(i + hit, ncomps): + if components[j] != GammaMatrix: + break + else: + j = ncomps + numG = j - i + if numG == 0: + tcoeff = t.coeff + return t.nocoeff if tcoeff else t + if numG % 2 == 1: + return TensMul.from_data(S.Zero, [], [], []) + elif numG > 4: + # find the open matrix indices and connect them: + a = t.split() + ind1 = a[i].get_indices()[0] + ind2 = a[i + 1].get_indices()[0] + aa = a[:i] + a[i + 2:] + t1 = tensor_mul(*aa)*g(ind1, ind2) + t1 = t1.contract_metric(g) + args = [t1] + sign = 1 + for k in range(i + 2, j): + sign = -sign + ind2 = a[k].get_indices()[0] + aa = a[:i] + a[i + 1:k] + a[k + 1:] + t2 = sign*tensor_mul(*aa)*g(ind1, ind2) + t2 = t2.contract_metric(g) + t2 = simplify_gpgp(t2, False) + args.append(t2) + t3 = TensAdd(*args) + t3 = _trace_single_line(t3) + return t3 + else: + a = t.split() + t1 = _gamma_trace1(*a[i:j]) + a2 = a[:i] + a[j:] + t2 = tensor_mul(*a2) + t3 = t1*t2 + if not t3: + return t3 + t3 = t3.contract_metric(g) + return t3 + + t = t.expand() + if isinstance(t, TensAdd): + a = [_trace_single_line1(x)*x.coeff for x in t.args] + return TensAdd(*a) + elif isinstance(t, (Tensor, TensMul)): + r = t.coeff*_trace_single_line1(t) + return r + else: + return trace(t) + + +def _gamma_trace1(*a): + gctr = 4 # FIXME specific for d=4 + g = LorentzIndex.metric + if not a: + return gctr + n = len(a) + if n%2 == 1: + #return TensMul.from_data(S.Zero, [], [], []) + return S.Zero + if n == 2: + ind0 = a[0].get_indices()[0] + ind1 = a[1].get_indices()[0] + return gctr*g(ind0, ind1) + if n == 4: + ind0 = a[0].get_indices()[0] + ind1 = a[1].get_indices()[0] + ind2 = a[2].get_indices()[0] + ind3 = a[3].get_indices()[0] + + return gctr*(g(ind0, ind1)*g(ind2, ind3) - \ + g(ind0, ind2)*g(ind1, ind3) + g(ind0, ind3)*g(ind1, ind2)) + + +def kahane_simplify(expression): + r""" + This function cancels contracted elements in a product of four + dimensional gamma matrices, resulting in an expression equal to the given + one, without the contracted gamma matrices. + + Parameters + ========== + + `expression` the tensor expression containing the gamma matrices to simplify. + + Notes + ===== + + If spinor indices are given, the matrices must be given in + the order given in the product. + + Algorithm + ========= + + The idea behind the algorithm is to use some well-known identities, + i.e., for contractions enclosing an even number of `\gamma` matrices + + `\gamma^\mu \gamma_{a_1} \cdots \gamma_{a_{2N}} \gamma_\mu = 2 (\gamma_{a_{2N}} \gamma_{a_1} \cdots \gamma_{a_{2N-1}} + \gamma_{a_{2N-1}} \cdots \gamma_{a_1} \gamma_{a_{2N}} )` + + for an odd number of `\gamma` matrices + + `\gamma^\mu \gamma_{a_1} \cdots \gamma_{a_{2N+1}} \gamma_\mu = -2 \gamma_{a_{2N+1}} \gamma_{a_{2N}} \cdots \gamma_{a_{1}}` + + Instead of repeatedly applying these identities to cancel out all contracted indices, + it is possible to recognize the links that would result from such an operation, + the problem is thus reduced to a simple rearrangement of free gamma matrices. + + Examples + ======== + + When using, always remember that the original expression coefficient + has to be handled separately + + >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, LorentzIndex + >>> from sympy.physics.hep.gamma_matrices import kahane_simplify + >>> from sympy.tensor.tensor import tensor_indices + >>> i0, i1, i2 = tensor_indices('i0:3', LorentzIndex) + >>> ta = G(i0)*G(-i0) + >>> kahane_simplify(ta) + Matrix([ + [4, 0, 0, 0], + [0, 4, 0, 0], + [0, 0, 4, 0], + [0, 0, 0, 4]]) + >>> tb = G(i0)*G(i1)*G(-i0) + >>> kahane_simplify(tb) + -2*GammaMatrix(i1) + >>> t = G(i0)*G(-i0) + >>> kahane_simplify(t) + Matrix([ + [4, 0, 0, 0], + [0, 4, 0, 0], + [0, 0, 4, 0], + [0, 0, 0, 4]]) + >>> t = G(i0)*G(-i0) + >>> kahane_simplify(t) + Matrix([ + [4, 0, 0, 0], + [0, 4, 0, 0], + [0, 0, 4, 0], + [0, 0, 0, 4]]) + + If there are no contractions, the same expression is returned + + >>> tc = G(i0)*G(i1) + >>> kahane_simplify(tc) + GammaMatrix(i0)*GammaMatrix(i1) + + References + ========== + + [1] Algorithm for Reducing Contracted Products of gamma Matrices, + Joseph Kahane, Journal of Mathematical Physics, Vol. 9, No. 10, October 1968. + """ + + if isinstance(expression, Mul): + return expression + if isinstance(expression, TensAdd): + return TensAdd(*[kahane_simplify(arg) for arg in expression.args]) + + if isinstance(expression, Tensor): + return expression + + assert isinstance(expression, TensMul) + + gammas = expression.args + + for gamma in gammas: + assert gamma.component == GammaMatrix + + free = expression.free + # spinor_free = [_ for _ in expression.free_in_args if _[1] != 0] + + # if len(spinor_free) == 2: + # spinor_free.sort(key=lambda x: x[2]) + # assert spinor_free[0][1] == 1 and spinor_free[-1][1] == 2 + # assert spinor_free[0][2] == 0 + # elif spinor_free: + # raise ValueError('spinor indices do not match') + + dum = [] + for dum_pair in expression.dum: + if expression.index_types[dum_pair[0]] == LorentzIndex: + dum.append((dum_pair[0], dum_pair[1])) + + dum = sorted(dum) + + if len(dum) == 0: # or GammaMatrixHead: + # no contractions in `expression`, just return it. + return expression + + # find the `first_dum_pos`, i.e. the position of the first contracted + # gamma matrix, Kahane's algorithm as described in his paper requires the + # gamma matrix expression to start with a contracted gamma matrix, this is + # a workaround which ignores possible initial free indices, and re-adds + # them later. + + first_dum_pos = min(map(min, dum)) + + # for p1, p2, a1, a2 in expression.dum_in_args: + # if p1 != 0 or p2 != 0: + # # only Lorentz indices, skip Dirac indices: + # continue + # first_dum_pos = min(p1, p2) + # break + + total_number = len(free) + len(dum)*2 + number_of_contractions = len(dum) + + free_pos = [None]*total_number + for i in free: + free_pos[i[1]] = i[0] + + # `index_is_free` is a list of booleans, to identify index position + # and whether that index is free or dummy. + index_is_free = [False]*total_number + + for i, indx in enumerate(free): + index_is_free[indx[1]] = True + + # `links` is a dictionary containing the graph described in Kahane's paper, + # to every key correspond one or two values, representing the linked indices. + # All values in `links` are integers, negative numbers are used in the case + # where it is necessary to insert gamma matrices between free indices, in + # order to make Kahane's algorithm work (see paper). + links = {i: [] for i in range(first_dum_pos, total_number)} + + # `cum_sign` is a step variable to mark the sign of every index, see paper. + cum_sign = -1 + # `cum_sign_list` keeps storage for all `cum_sign` (every index). + cum_sign_list = [None]*total_number + block_free_count = 0 + + # multiply `resulting_coeff` by the coefficient parameter, the rest + # of the algorithm ignores a scalar coefficient. + resulting_coeff = S.One + + # initialize a list of lists of indices. The outer list will contain all + # additive tensor expressions, while the inner list will contain the + # free indices (rearranged according to the algorithm). + resulting_indices = [[]] + + # start to count the `connected_components`, which together with the number + # of contractions, determines a -1 or +1 factor to be multiplied. + connected_components = 1 + + # First loop: here we fill `cum_sign_list`, and draw the links + # among consecutive indices (they are stored in `links`). Links among + # non-consecutive indices will be drawn later. + for i, is_free in enumerate(index_is_free): + # if `expression` starts with free indices, they are ignored here; + # they are later added as they are to the beginning of all + # `resulting_indices` list of lists of indices. + if i < first_dum_pos: + continue + + if is_free: + block_free_count += 1 + # if previous index was free as well, draw an arch in `links`. + if block_free_count > 1: + links[i - 1].append(i) + links[i].append(i - 1) + else: + # Change the sign of the index (`cum_sign`) if the number of free + # indices preceding it is even. + cum_sign *= 1 if (block_free_count % 2) else -1 + if block_free_count == 0 and i != first_dum_pos: + # check if there are two consecutive dummy indices: + # in this case create virtual indices with negative position, + # these "virtual" indices represent the insertion of two + # gamma^0 matrices to separate consecutive dummy indices, as + # Kahane's algorithm requires dummy indices to be separated by + # free indices. The product of two gamma^0 matrices is unity, + # so the new expression being examined is the same as the + # original one. + if cum_sign == -1: + links[-1-i] = [-1-i+1] + links[-1-i+1] = [-1-i] + if (i - cum_sign) in links: + if i != first_dum_pos: + links[i].append(i - cum_sign) + if block_free_count != 0: + if i - cum_sign < len(index_is_free): + if index_is_free[i - cum_sign]: + links[i - cum_sign].append(i) + block_free_count = 0 + + cum_sign_list[i] = cum_sign + + # The previous loop has only created links between consecutive free indices, + # it is necessary to properly create links among dummy (contracted) indices, + # according to the rules described in Kahane's paper. There is only one exception + # to Kahane's rules: the negative indices, which handle the case of some + # consecutive free indices (Kahane's paper just describes dummy indices + # separated by free indices, hinting that free indices can be added without + # altering the expression result). + for i in dum: + # get the positions of the two contracted indices: + pos1 = i[0] + pos2 = i[1] + + # create Kahane's upper links, i.e. the upper arcs between dummy + # (i.e. contracted) indices: + links[pos1].append(pos2) + links[pos2].append(pos1) + + # create Kahane's lower links, this corresponds to the arcs below + # the line described in the paper: + + # first we move `pos1` and `pos2` according to the sign of the indices: + linkpos1 = pos1 + cum_sign_list[pos1] + linkpos2 = pos2 + cum_sign_list[pos2] + + # otherwise, perform some checks before creating the lower arcs: + + # make sure we are not exceeding the total number of indices: + if linkpos1 >= total_number: + continue + if linkpos2 >= total_number: + continue + + # make sure we are not below the first dummy index in `expression`: + if linkpos1 < first_dum_pos: + continue + if linkpos2 < first_dum_pos: + continue + + # check if the previous loop created "virtual" indices between dummy + # indices, in such a case relink `linkpos1` and `linkpos2`: + if (-1-linkpos1) in links: + linkpos1 = -1-linkpos1 + if (-1-linkpos2) in links: + linkpos2 = -1-linkpos2 + + # move only if not next to free index: + if linkpos1 >= 0 and not index_is_free[linkpos1]: + linkpos1 = pos1 + + if linkpos2 >=0 and not index_is_free[linkpos2]: + linkpos2 = pos2 + + # create the lower arcs: + if linkpos2 not in links[linkpos1]: + links[linkpos1].append(linkpos2) + if linkpos1 not in links[linkpos2]: + links[linkpos2].append(linkpos1) + + # This loop starts from the `first_dum_pos` index (first dummy index) + # walks through the graph deleting the visited indices from `links`, + # it adds a gamma matrix for every free index in encounters, while it + # completely ignores dummy indices and virtual indices. + pointer = first_dum_pos + previous_pointer = 0 + while True: + if pointer in links: + next_ones = links.pop(pointer) + else: + break + + if previous_pointer in next_ones: + next_ones.remove(previous_pointer) + + previous_pointer = pointer + + if next_ones: + pointer = next_ones[0] + else: + break + + if pointer == previous_pointer: + break + if pointer >=0 and free_pos[pointer] is not None: + for ri in resulting_indices: + ri.append(free_pos[pointer]) + + # The following loop removes the remaining connected components in `links`. + # If there are free indices inside a connected component, it gives a + # contribution to the resulting expression given by the factor + # `gamma_a gamma_b ... gamma_z + gamma_z ... gamma_b gamma_a`, in Kahanes's + # paper represented as {gamma_a, gamma_b, ... , gamma_z}, + # virtual indices are ignored. The variable `connected_components` is + # increased by one for every connected component this loop encounters. + + # If the connected component has virtual and dummy indices only + # (no free indices), it contributes to `resulting_indices` by a factor of two. + # The multiplication by two is a result of the + # factor {gamma^0, gamma^0} = 2 I, as it appears in Kahane's paper. + # Note: curly brackets are meant as in the paper, as a generalized + # multi-element anticommutator! + + while links: + connected_components += 1 + pointer = min(links.keys()) + previous_pointer = pointer + # the inner loop erases the visited indices from `links`, and it adds + # all free indices to `prepend_indices` list, virtual indices are + # ignored. + prepend_indices = [] + while True: + if pointer in links: + next_ones = links.pop(pointer) + else: + break + + if previous_pointer in next_ones: + if len(next_ones) > 1: + next_ones.remove(previous_pointer) + + previous_pointer = pointer + + if next_ones: + pointer = next_ones[0] + + if pointer >= first_dum_pos and free_pos[pointer] is not None: + prepend_indices.insert(0, free_pos[pointer]) + # if `prepend_indices` is void, it means there are no free indices + # in the loop (and it can be shown that there must be a virtual index), + # loops of virtual indices only contribute by a factor of two: + if len(prepend_indices) == 0: + resulting_coeff *= 2 + # otherwise, add the free indices in `prepend_indices` to + # the `resulting_indices`: + else: + expr1 = prepend_indices + expr2 = list(reversed(prepend_indices)) + resulting_indices = [expri + ri for ri in resulting_indices for expri in (expr1, expr2)] + + # sign correction, as described in Kahane's paper: + resulting_coeff *= -1 if (number_of_contractions - connected_components + 1) % 2 else 1 + # power of two factor, as described in Kahane's paper: + resulting_coeff *= 2**(number_of_contractions) + + # If `first_dum_pos` is not zero, it means that there are trailing free gamma + # matrices in front of `expression`, so multiply by them: + resulting_indices = [ free_pos[0:first_dum_pos] + ri for ri in resulting_indices ] + + resulting_expr = S.Zero + for i in resulting_indices: + temp_expr = S.One + for j in i: + temp_expr *= GammaMatrix(j) + resulting_expr += temp_expr + + t = resulting_coeff * resulting_expr + t1 = None + if isinstance(t, TensAdd): + t1 = t.args[0] + elif isinstance(t, TensMul): + t1 = t + if t1: + pass + else: + t = eye(4)*t + return t diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hydrogen.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hydrogen.py new file mode 100644 index 0000000000000000000000000000000000000000..a3bac274c66a2cf97d4238d9e3951e39df820931 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hydrogen.py @@ -0,0 +1,265 @@ +from sympy.core.numbers import Float +from sympy.core.singleton import S +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.polynomials import assoc_laguerre +from sympy.functions.special.spherical_harmonics import Ynm + + +def R_nl(n, l, r, Z=1): + """ + Returns the Hydrogen radial wavefunction R_{nl}. + + Parameters + ========== + + n : integer + Principal Quantum Number which is + an integer with possible values as 1, 2, 3, 4,... + l : integer + ``l`` is the Angular Momentum Quantum Number with + values ranging from 0 to ``n-1``. + r : + Radial coordinate. + Z : + Atomic number (1 for Hydrogen, 2 for Helium, ...) + + Everything is in Hartree atomic units. + + Examples + ======== + + >>> from sympy.physics.hydrogen import R_nl + >>> from sympy.abc import r, Z + >>> R_nl(1, 0, r, Z) + 2*sqrt(Z**3)*exp(-Z*r) + >>> R_nl(2, 0, r, Z) + sqrt(2)*(-Z*r + 2)*sqrt(Z**3)*exp(-Z*r/2)/4 + >>> R_nl(2, 1, r, Z) + sqrt(6)*Z*r*sqrt(Z**3)*exp(-Z*r/2)/12 + + For Hydrogen atom, you can just use the default value of Z=1: + + >>> R_nl(1, 0, r) + 2*exp(-r) + >>> R_nl(2, 0, r) + sqrt(2)*(2 - r)*exp(-r/2)/4 + >>> R_nl(3, 0, r) + 2*sqrt(3)*(2*r**2/9 - 2*r + 3)*exp(-r/3)/27 + + For Silver atom, you would use Z=47: + + >>> R_nl(1, 0, r, Z=47) + 94*sqrt(47)*exp(-47*r) + >>> R_nl(2, 0, r, Z=47) + 47*sqrt(94)*(2 - 47*r)*exp(-47*r/2)/4 + >>> R_nl(3, 0, r, Z=47) + 94*sqrt(141)*(4418*r**2/9 - 94*r + 3)*exp(-47*r/3)/27 + + The normalization of the radial wavefunction is: + + >>> from sympy import integrate, oo + >>> integrate(R_nl(1, 0, r)**2 * r**2, (r, 0, oo)) + 1 + >>> integrate(R_nl(2, 0, r)**2 * r**2, (r, 0, oo)) + 1 + >>> integrate(R_nl(2, 1, r)**2 * r**2, (r, 0, oo)) + 1 + + It holds for any atomic number: + + >>> integrate(R_nl(1, 0, r, Z=2)**2 * r**2, (r, 0, oo)) + 1 + >>> integrate(R_nl(2, 0, r, Z=3)**2 * r**2, (r, 0, oo)) + 1 + >>> integrate(R_nl(2, 1, r, Z=4)**2 * r**2, (r, 0, oo)) + 1 + + """ + # sympify arguments + n, l, r, Z = map(S, [n, l, r, Z]) + # radial quantum number + n_r = n - l - 1 + # rescaled "r" + a = 1/Z # Bohr radius + r0 = 2 * r / (n * a) + # normalization coefficient + C = sqrt((S(2)/(n*a))**3 * factorial(n_r) / (2*n*factorial(n + l))) + # This is an equivalent normalization coefficient, that can be found in + # some books. Both coefficients seem to be the same fast: + # C = S(2)/n**2 * sqrt(1/a**3 * factorial(n_r) / (factorial(n+l))) + return C * r0**l * assoc_laguerre(n_r, 2*l + 1, r0).expand() * exp(-r0/2) + + +def Psi_nlm(n, l, m, r, phi, theta, Z=1): + """ + Returns the Hydrogen wave function psi_{nlm}. It's the product of + the radial wavefunction R_{nl} and the spherical harmonic Y_{l}^{m}. + + Parameters + ========== + + n : integer + Principal Quantum Number which is + an integer with possible values as 1, 2, 3, 4,... + l : integer + ``l`` is the Angular Momentum Quantum Number with + values ranging from 0 to ``n-1``. + m : integer + ``m`` is the Magnetic Quantum Number with values + ranging from ``-l`` to ``l``. + r : + radial coordinate + phi : + azimuthal angle + theta : + polar angle + Z : + atomic number (1 for Hydrogen, 2 for Helium, ...) + + Everything is in Hartree atomic units. + + Examples + ======== + + >>> from sympy.physics.hydrogen import Psi_nlm + >>> from sympy import Symbol + >>> r=Symbol("r", positive=True) + >>> phi=Symbol("phi", real=True) + >>> theta=Symbol("theta", real=True) + >>> Z=Symbol("Z", positive=True, integer=True, nonzero=True) + >>> Psi_nlm(1,0,0,r,phi,theta,Z) + Z**(3/2)*exp(-Z*r)/sqrt(pi) + >>> Psi_nlm(2,1,1,r,phi,theta,Z) + -Z**(5/2)*r*exp(I*phi)*exp(-Z*r/2)*sin(theta)/(8*sqrt(pi)) + + Integrating the absolute square of a hydrogen wavefunction psi_{nlm} + over the whole space leads 1. + + The normalization of the hydrogen wavefunctions Psi_nlm is: + + >>> from sympy import integrate, conjugate, pi, oo, sin + >>> wf=Psi_nlm(2,1,1,r,phi,theta,Z) + >>> abs_sqrd=wf*conjugate(wf) + >>> jacobi=r**2*sin(theta) + >>> integrate(abs_sqrd*jacobi, (r,0,oo), (phi,0,2*pi), (theta,0,pi)) + 1 + """ + + # sympify arguments + n, l, m, r, phi, theta, Z = map(S, [n, l, m, r, phi, theta, Z]) + # check if values for n,l,m make physically sense + if n.is_integer and n < 1: + raise ValueError("'n' must be positive integer") + if l.is_integer and not (n > l): + raise ValueError("'n' must be greater than 'l'") + if m.is_integer and not (abs(m) <= l): + raise ValueError("|'m'| must be less or equal 'l'") + # return the hydrogen wave function + return R_nl(n, l, r, Z)*Ynm(l, m, theta, phi).expand(func=True) + + +def E_nl(n, Z=1): + """ + Returns the energy of the state (n, l) in Hartree atomic units. + + The energy does not depend on "l". + + Parameters + ========== + + n : integer + Principal Quantum Number which is + an integer with possible values as 1, 2, 3, 4,... + Z : + Atomic number (1 for Hydrogen, 2 for Helium, ...) + + Examples + ======== + + >>> from sympy.physics.hydrogen import E_nl + >>> from sympy.abc import n, Z + >>> E_nl(n, Z) + -Z**2/(2*n**2) + >>> E_nl(1) + -1/2 + >>> E_nl(2) + -1/8 + >>> E_nl(3) + -1/18 + >>> E_nl(3, 47) + -2209/18 + + """ + n, Z = S(n), S(Z) + if n.is_integer and (n < 1): + raise ValueError("'n' must be positive integer") + return -Z**2/(2*n**2) + + +def E_nl_dirac(n, l, spin_up=True, Z=1, c=Float("137.035999037")): + """ + Returns the relativistic energy of the state (n, l, spin) in Hartree atomic + units. + + The energy is calculated from the Dirac equation. The rest mass energy is + *not* included. + + Parameters + ========== + + n : integer + Principal Quantum Number which is + an integer with possible values as 1, 2, 3, 4,... + l : integer + ``l`` is the Angular Momentum Quantum Number with + values ranging from 0 to ``n-1``. + spin_up : + True if the electron spin is up (default), otherwise down + Z : + Atomic number (1 for Hydrogen, 2 for Helium, ...) + c : + Speed of light in atomic units. Default value is 137.035999037, + taken from https://arxiv.org/abs/1012.3627 + + Examples + ======== + + >>> from sympy.physics.hydrogen import E_nl_dirac + >>> E_nl_dirac(1, 0) + -0.500006656595360 + + >>> E_nl_dirac(2, 0) + -0.125002080189006 + >>> E_nl_dirac(2, 1) + -0.125000416028342 + >>> E_nl_dirac(2, 1, False) + -0.125002080189006 + + >>> E_nl_dirac(3, 0) + -0.0555562951740285 + >>> E_nl_dirac(3, 1) + -0.0555558020932949 + >>> E_nl_dirac(3, 1, False) + -0.0555562951740285 + >>> E_nl_dirac(3, 2) + -0.0555556377366884 + >>> E_nl_dirac(3, 2, False) + -0.0555558020932949 + + """ + n, l, Z, c = map(S, [n, l, Z, c]) + if not (l >= 0): + raise ValueError("'l' must be positive or zero") + if not (n > l): + raise ValueError("'n' must be greater than 'l'") + if (l == 0 and spin_up is False): + raise ValueError("Spin must be up for l==0.") + # skappa is sign*kappa, where sign contains the correct sign + if spin_up: + skappa = -l - 1 + else: + skappa = -l + beta = sqrt(skappa**2 - Z**2/c**2) + return c**2/sqrt(1 + Z**2/(n + skappa + beta)**2/c**2) - c**2 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/matrices.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/matrices.py new file mode 100644 index 0000000000000000000000000000000000000000..d91466220d63956053b91bd76b948ee677e7c191 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/matrices.py @@ -0,0 +1,176 @@ +"""Known matrices related to physics""" + +from sympy.core.numbers import I +from sympy.matrices.dense import MutableDenseMatrix as Matrix +from sympy.utilities.decorator import deprecated + + +def msigma(i): + r"""Returns a Pauli matrix `\sigma_i` with `i=1,2,3`. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Pauli_matrices + + Examples + ======== + + >>> from sympy.physics.matrices import msigma + >>> msigma(1) + Matrix([ + [0, 1], + [1, 0]]) + """ + if i == 1: + mat = ( + (0, 1), + (1, 0) + ) + elif i == 2: + mat = ( + (0, -I), + (I, 0) + ) + elif i == 3: + mat = ( + (1, 0), + (0, -1) + ) + else: + raise IndexError("Invalid Pauli index") + return Matrix(mat) + + +def pat_matrix(m, dx, dy, dz): + """Returns the Parallel Axis Theorem matrix to translate the inertia + matrix a distance of `(dx, dy, dz)` for a body of mass m. + + Examples + ======== + + To translate a body having a mass of 2 units a distance of 1 unit along + the `x`-axis we get: + + >>> from sympy.physics.matrices import pat_matrix + >>> pat_matrix(2, 1, 0, 0) + Matrix([ + [0, 0, 0], + [0, 2, 0], + [0, 0, 2]]) + + """ + dxdy = -dx*dy + dydz = -dy*dz + dzdx = -dz*dx + dxdx = dx**2 + dydy = dy**2 + dzdz = dz**2 + mat = ((dydy + dzdz, dxdy, dzdx), + (dxdy, dxdx + dzdz, dydz), + (dzdx, dydz, dydy + dxdx)) + return m*Matrix(mat) + + +def mgamma(mu, lower=False): + r"""Returns a Dirac gamma matrix `\gamma^\mu` in the standard + (Dirac) representation. + + Explanation + =========== + + If you want `\gamma_\mu`, use ``gamma(mu, True)``. + + We use a convention: + + `\gamma^5 = i \cdot \gamma^0 \cdot \gamma^1 \cdot \gamma^2 \cdot \gamma^3` + + `\gamma_5 = i \cdot \gamma_0 \cdot \gamma_1 \cdot \gamma_2 \cdot \gamma_3 = - \gamma^5` + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gamma_matrices + + Examples + ======== + + >>> from sympy.physics.matrices import mgamma + >>> mgamma(1) + Matrix([ + [ 0, 0, 0, 1], + [ 0, 0, 1, 0], + [ 0, -1, 0, 0], + [-1, 0, 0, 0]]) + """ + if mu not in (0, 1, 2, 3, 5): + raise IndexError("Invalid Dirac index") + if mu == 0: + mat = ( + (1, 0, 0, 0), + (0, 1, 0, 0), + (0, 0, -1, 0), + (0, 0, 0, -1) + ) + elif mu == 1: + mat = ( + (0, 0, 0, 1), + (0, 0, 1, 0), + (0, -1, 0, 0), + (-1, 0, 0, 0) + ) + elif mu == 2: + mat = ( + (0, 0, 0, -I), + (0, 0, I, 0), + (0, I, 0, 0), + (-I, 0, 0, 0) + ) + elif mu == 3: + mat = ( + (0, 0, 1, 0), + (0, 0, 0, -1), + (-1, 0, 0, 0), + (0, 1, 0, 0) + ) + elif mu == 5: + mat = ( + (0, 0, 1, 0), + (0, 0, 0, 1), + (1, 0, 0, 0), + (0, 1, 0, 0) + ) + m = Matrix(mat) + if lower: + if mu in (1, 2, 3, 5): + m = -m + return m + +#Minkowski tensor using the convention (+,-,-,-) used in the Quantum Field +#Theory +minkowski_tensor = Matrix( ( + (1, 0, 0, 0), + (0, -1, 0, 0), + (0, 0, -1, 0), + (0, 0, 0, -1) +)) + + +@deprecated( + """ + The sympy.physics.matrices.mdft method is deprecated. Use + sympy.DFT(n).as_explicit() instead. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-physics-mdft", +) +def mdft(n): + r""" + .. deprecated:: 1.9 + + Use DFT from sympy.matrices.expressions.fourier instead. + + To get identical behavior to ``mdft(n)``, use ``DFT(n).as_explicit()``. + """ + from sympy.matrices.expressions.fourier import DFT + return DFT(n).as_mutable() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/body.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/body.py new file mode 100644 index 0000000000000000000000000000000000000000..efc367158bbf51e7d9929318ac9286ba5c3fb3ac --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/body.py @@ -0,0 +1,710 @@ +from sympy import Symbol +from sympy.physics.vector import Point, Vector, ReferenceFrame, Dyadic +from sympy.physics.mechanics import RigidBody, Particle, Inertia +from sympy.physics.mechanics.body_base import BodyBase +from sympy.utilities.exceptions import sympy_deprecation_warning + +__all__ = ['Body'] + + +# XXX: We use type:ignore because the classes RigidBody and Particle have +# inconsistent parallel axis methods that take different numbers of arguments. +class Body(RigidBody, Particle): # type: ignore + """ + Body is a common representation of either a RigidBody or a Particle SymPy + object depending on what is passed in during initialization. If a mass is + passed in and central_inertia is left as None, the Particle object is + created. Otherwise a RigidBody object will be created. + + .. deprecated:: 1.13 + The Body class is deprecated. Its functionality is captured by + :class:`~.RigidBody` and :class:`~.Particle`. + + Explanation + =========== + + The attributes that Body possesses will be the same as a Particle instance + or a Rigid Body instance depending on which was created. Additional + attributes are listed below. + + Attributes + ========== + + name : string + The body's name + masscenter : Point + The point which represents the center of mass of the rigid body + frame : ReferenceFrame + The reference frame which the body is fixed in + mass : Sympifyable + The body's mass + inertia : (Dyadic, Point) + The body's inertia around its center of mass. This attribute is specific + to the rigid body form of Body and is left undefined for the Particle + form + loads : iterable + This list contains information on the different loads acting on the + Body. Forces are listed as a (point, vector) tuple and torques are + listed as (reference frame, vector) tuples. + + Parameters + ========== + + name : String + Defines the name of the body. It is used as the base for defining + body specific properties. + masscenter : Point, optional + A point that represents the center of mass of the body or particle. + If no point is given, a point is generated. + mass : Sympifyable, optional + A Sympifyable object which represents the mass of the body. If no + mass is passed, one is generated. + frame : ReferenceFrame, optional + The ReferenceFrame that represents the reference frame of the body. + If no frame is given, a frame is generated. + central_inertia : Dyadic, optional + Central inertia dyadic of the body. If none is passed while creating + RigidBody, a default inertia is generated. + + Examples + ======== + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + + Default behaviour. This results in the creation of a RigidBody object for + which the mass, mass center, frame and inertia attributes are given default + values. :: + + >>> from sympy.physics.mechanics import Body + >>> with ignore_warnings(DeprecationWarning): + ... body = Body('name_of_body') + + This next example demonstrates the code required to specify all of the + values of the Body object. Note this will also create a RigidBody version of + the Body object. :: + + >>> from sympy import Symbol + >>> from sympy.physics.mechanics import ReferenceFrame, Point, inertia + >>> from sympy.physics.mechanics import Body + >>> mass = Symbol('mass') + >>> masscenter = Point('masscenter') + >>> frame = ReferenceFrame('frame') + >>> ixx = Symbol('ixx') + >>> body_inertia = inertia(frame, ixx, 0, 0) + >>> with ignore_warnings(DeprecationWarning): + ... body = Body('name_of_body', masscenter, mass, frame, body_inertia) + + The minimal code required to create a Particle version of the Body object + involves simply passing in a name and a mass. :: + + >>> from sympy import Symbol + >>> from sympy.physics.mechanics import Body + >>> mass = Symbol('mass') + >>> with ignore_warnings(DeprecationWarning): + ... body = Body('name_of_body', mass=mass) + + The Particle version of the Body object can also receive a masscenter point + and a reference frame, just not an inertia. + """ + + def __init__(self, name, masscenter=None, mass=None, frame=None, + central_inertia=None): + sympy_deprecation_warning( + """ + Support for the Body class has been removed, as its functionality is + fully captured by RigidBody and Particle. + """, + deprecated_since_version="1.13", + active_deprecations_target="deprecated-mechanics-body-class" + ) + + self._loads = [] + + if frame is None: + frame = ReferenceFrame(name + '_frame') + + if masscenter is None: + masscenter = Point(name + '_masscenter') + + if central_inertia is None and mass is None: + ixx = Symbol(name + '_ixx') + iyy = Symbol(name + '_iyy') + izz = Symbol(name + '_izz') + izx = Symbol(name + '_izx') + ixy = Symbol(name + '_ixy') + iyz = Symbol(name + '_iyz') + _inertia = Inertia.from_inertia_scalars(masscenter, frame, ixx, iyy, + izz, ixy, iyz, izx) + else: + _inertia = (central_inertia, masscenter) + + if mass is None: + _mass = Symbol(name + '_mass') + else: + _mass = mass + + masscenter.set_vel(frame, 0) + + # If user passes masscenter and mass then a particle is created + # otherwise a rigidbody. As a result a body may or may not have inertia. + # Note: BodyBase.__init__ is used to prevent problems with super() calls in + # Particle and RigidBody arising due to multiple inheritance. + if central_inertia is None and mass is not None: + BodyBase.__init__(self, name, masscenter, _mass) + self.frame = frame + self._central_inertia = Dyadic(0) + else: + BodyBase.__init__(self, name, masscenter, _mass) + self.frame = frame + self.inertia = _inertia + + def __repr__(self): + if self.is_rigidbody: + return RigidBody.__repr__(self) + return Particle.__repr__(self) + + @property + def loads(self): + return self._loads + + @property + def x(self): + """The basis Vector for the Body, in the x direction.""" + return self.frame.x + + @property + def y(self): + """The basis Vector for the Body, in the y direction.""" + return self.frame.y + + @property + def z(self): + """The basis Vector for the Body, in the z direction.""" + return self.frame.z + + @property + def inertia(self): + """The body's inertia about a point; stored as (Dyadic, Point).""" + if self.is_rigidbody: + return RigidBody.inertia.fget(self) + return (self.central_inertia, self.masscenter) + + @inertia.setter + def inertia(self, I): + RigidBody.inertia.fset(self, I) + + @property + def is_rigidbody(self): + if hasattr(self, '_inertia'): + return True + return False + + def kinetic_energy(self, frame): + """Kinetic energy of the body. + + Parameters + ========== + + frame : ReferenceFrame or Body + The Body's angular velocity and the velocity of it's mass + center are typically defined with respect to an inertial frame but + any relevant frame in which the velocities are known can be supplied. + + Examples + ======== + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy.physics.mechanics import Body, ReferenceFrame, Point + >>> from sympy import symbols + >>> m, v, r, omega = symbols('m v r omega') + >>> N = ReferenceFrame('N') + >>> O = Point('O') + >>> with ignore_warnings(DeprecationWarning): + ... P = Body('P', masscenter=O, mass=m) + >>> P.masscenter.set_vel(N, v * N.y) + >>> P.kinetic_energy(N) + m*v**2/2 + + >>> N = ReferenceFrame('N') + >>> b = ReferenceFrame('b') + >>> b.set_ang_vel(N, omega * b.x) + >>> P = Point('P') + >>> P.set_vel(N, v * N.x) + >>> with ignore_warnings(DeprecationWarning): + ... B = Body('B', masscenter=P, frame=b) + >>> B.kinetic_energy(N) + B_ixx*omega**2/2 + B_mass*v**2/2 + + See Also + ======== + + sympy.physics.mechanics : Particle, RigidBody + + """ + if isinstance(frame, Body): + frame = Body.frame + if self.is_rigidbody: + return RigidBody(self.name, self.masscenter, self.frame, self.mass, + (self.central_inertia, self.masscenter)).kinetic_energy(frame) + return Particle(self.name, self.masscenter, self.mass).kinetic_energy(frame) + + def apply_force(self, force, point=None, reaction_body=None, reaction_point=None): + """Add force to the body(s). + + Explanation + =========== + + Applies the force on self or equal and opposite forces on + self and other body if both are given on the desired point on the bodies. + The force applied on other body is taken opposite of self, i.e, -force. + + Parameters + ========== + + force: Vector + The force to be applied. + point: Point, optional + The point on self on which force is applied. + By default self's masscenter. + reaction_body: Body, optional + Second body on which equal and opposite force + is to be applied. + reaction_point : Point, optional + The point on other body on which equal and opposite + force is applied. By default masscenter of other body. + + Example + ======= + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy import symbols + >>> from sympy.physics.mechanics import Body, Point, dynamicsymbols + >>> m, g = symbols('m g') + >>> with ignore_warnings(DeprecationWarning): + ... B = Body('B') + >>> force1 = m*g*B.z + >>> B.apply_force(force1) #Applying force on B's masscenter + >>> B.loads + [(B_masscenter, g*m*B_frame.z)] + + We can also remove some part of force from any point on the body by + adding the opposite force to the body on that point. + + >>> f1, f2 = dynamicsymbols('f1 f2') + >>> P = Point('P') #Considering point P on body B + >>> B.apply_force(f1*B.x + f2*B.y, P) + >>> B.loads + [(B_masscenter, g*m*B_frame.z), (P, f1(t)*B_frame.x + f2(t)*B_frame.y)] + + Let's remove f1 from point P on body B. + + >>> B.apply_force(-f1*B.x, P) + >>> B.loads + [(B_masscenter, g*m*B_frame.z), (P, f2(t)*B_frame.y)] + + To further demonstrate the use of ``apply_force`` attribute, + consider two bodies connected through a spring. + + >>> from sympy.physics.mechanics import Body, dynamicsymbols + >>> with ignore_warnings(DeprecationWarning): + ... N = Body('N') #Newtonion Frame + >>> x = dynamicsymbols('x') + >>> with ignore_warnings(DeprecationWarning): + ... B1 = Body('B1') + ... B2 = Body('B2') + >>> spring_force = x*N.x + + Now let's apply equal and opposite spring force to the bodies. + + >>> P1 = Point('P1') + >>> P2 = Point('P2') + >>> B1.apply_force(spring_force, point=P1, reaction_body=B2, reaction_point=P2) + + We can check the loads(forces) applied to bodies now. + + >>> B1.loads + [(P1, x(t)*N_frame.x)] + >>> B2.loads + [(P2, - x(t)*N_frame.x)] + + Notes + ===== + + If a new force is applied to a body on a point which already has some + force applied on it, then the new force is added to the already applied + force on that point. + + """ + + if not isinstance(point, Point): + if point is None: + point = self.masscenter # masscenter + else: + raise TypeError("Force must be applied to a point on the body.") + if not isinstance(force, Vector): + raise TypeError("Force must be a vector.") + + if reaction_body is not None: + reaction_body.apply_force(-force, point=reaction_point) + + for load in self._loads: + if point in load: + force += load[1] + self._loads.remove(load) + break + + self._loads.append((point, force)) + + def apply_torque(self, torque, reaction_body=None): + """Add torque to the body(s). + + Explanation + =========== + + Applies the torque on self or equal and opposite torques on + self and other body if both are given. + The torque applied on other body is taken opposite of self, + i.e, -torque. + + Parameters + ========== + + torque: Vector + The torque to be applied. + reaction_body: Body, optional + Second body on which equal and opposite torque + is to be applied. + + Example + ======= + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy import symbols + >>> from sympy.physics.mechanics import Body, dynamicsymbols + >>> t = symbols('t') + >>> with ignore_warnings(DeprecationWarning): + ... B = Body('B') + >>> torque1 = t*B.z + >>> B.apply_torque(torque1) + >>> B.loads + [(B_frame, t*B_frame.z)] + + We can also remove some part of torque from the body by + adding the opposite torque to the body. + + >>> t1, t2 = dynamicsymbols('t1 t2') + >>> B.apply_torque(t1*B.x + t2*B.y) + >>> B.loads + [(B_frame, t1(t)*B_frame.x + t2(t)*B_frame.y + t*B_frame.z)] + + Let's remove t1 from Body B. + + >>> B.apply_torque(-t1*B.x) + >>> B.loads + [(B_frame, t2(t)*B_frame.y + t*B_frame.z)] + + To further demonstrate the use, let us consider two bodies such that + a torque `T` is acting on one body, and `-T` on the other. + + >>> from sympy.physics.mechanics import Body, dynamicsymbols + >>> with ignore_warnings(DeprecationWarning): + ... N = Body('N') #Newtonion frame + ... B1 = Body('B1') + ... B2 = Body('B2') + >>> v = dynamicsymbols('v') + >>> T = v*N.y #Torque + + Now let's apply equal and opposite torque to the bodies. + + >>> B1.apply_torque(T, B2) + + We can check the loads (torques) applied to bodies now. + + >>> B1.loads + [(B1_frame, v(t)*N_frame.y)] + >>> B2.loads + [(B2_frame, - v(t)*N_frame.y)] + + Notes + ===== + + If a new torque is applied on body which already has some torque applied on it, + then the new torque is added to the previous torque about the body's frame. + + """ + + if not isinstance(torque, Vector): + raise TypeError("A Vector must be supplied to add torque.") + + if reaction_body is not None: + reaction_body.apply_torque(-torque) + + for load in self._loads: + if self.frame in load: + torque += load[1] + self._loads.remove(load) + break + self._loads.append((self.frame, torque)) + + def clear_loads(self): + """ + Clears the Body's loads list. + + Example + ======= + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy.physics.mechanics import Body + >>> with ignore_warnings(DeprecationWarning): + ... B = Body('B') + >>> force = B.x + B.y + >>> B.apply_force(force) + >>> B.loads + [(B_masscenter, B_frame.x + B_frame.y)] + >>> B.clear_loads() + >>> B.loads + [] + + """ + + self._loads = [] + + def remove_load(self, about=None): + """ + Remove load about a point or frame. + + Parameters + ========== + + about : Point or ReferenceFrame, optional + The point about which force is applied, + and is to be removed. + If about is None, then the torque about + self's frame is removed. + + Example + ======= + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy.physics.mechanics import Body, Point + >>> with ignore_warnings(DeprecationWarning): + ... B = Body('B') + >>> P = Point('P') + >>> f1 = B.x + >>> f2 = B.y + >>> B.apply_force(f1) + >>> B.apply_force(f2, P) + >>> B.loads + [(B_masscenter, B_frame.x), (P, B_frame.y)] + + >>> B.remove_load(P) + >>> B.loads + [(B_masscenter, B_frame.x)] + + """ + + if about is not None: + if not isinstance(about, Point): + raise TypeError('Load is applied about Point or ReferenceFrame.') + else: + about = self.frame + + for load in self._loads: + if about in load: + self._loads.remove(load) + break + + def masscenter_vel(self, body): + """ + Returns the velocity of the mass center with respect to the provided + rigid body or reference frame. + + Parameters + ========== + + body: Body or ReferenceFrame + The rigid body or reference frame to calculate the velocity in. + + Example + ======= + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy.physics.mechanics import Body + >>> with ignore_warnings(DeprecationWarning): + ... A = Body('A') + ... B = Body('B') + >>> A.masscenter.set_vel(B.frame, 5*B.frame.x) + >>> A.masscenter_vel(B) + 5*B_frame.x + >>> A.masscenter_vel(B.frame) + 5*B_frame.x + + """ + + if isinstance(body, ReferenceFrame): + frame=body + elif isinstance(body, Body): + frame = body.frame + return self.masscenter.vel(frame) + + def ang_vel_in(self, body): + """ + Returns this body's angular velocity with respect to the provided + rigid body or reference frame. + + Parameters + ========== + + body: Body or ReferenceFrame + The rigid body or reference frame to calculate the angular velocity in. + + Example + ======= + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy.physics.mechanics import Body, ReferenceFrame + >>> with ignore_warnings(DeprecationWarning): + ... A = Body('A') + >>> N = ReferenceFrame('N') + >>> with ignore_warnings(DeprecationWarning): + ... B = Body('B', frame=N) + >>> A.frame.set_ang_vel(N, 5*N.x) + >>> A.ang_vel_in(B) + 5*N.x + >>> A.ang_vel_in(N) + 5*N.x + + """ + + if isinstance(body, ReferenceFrame): + frame=body + elif isinstance(body, Body): + frame = body.frame + return self.frame.ang_vel_in(frame) + + def dcm(self, body): + """ + Returns the direction cosine matrix of this body relative to the + provided rigid body or reference frame. + + Parameters + ========== + + body: Body or ReferenceFrame + The rigid body or reference frame to calculate the dcm. + + Example + ======= + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy.physics.mechanics import Body + >>> with ignore_warnings(DeprecationWarning): + ... A = Body('A') + ... B = Body('B') + >>> A.frame.orient_axis(B.frame, B.frame.x, 5) + >>> A.dcm(B) + Matrix([ + [1, 0, 0], + [0, cos(5), sin(5)], + [0, -sin(5), cos(5)]]) + >>> A.dcm(B.frame) + Matrix([ + [1, 0, 0], + [0, cos(5), sin(5)], + [0, -sin(5), cos(5)]]) + + """ + + if isinstance(body, ReferenceFrame): + frame=body + elif isinstance(body, Body): + frame = body.frame + return self.frame.dcm(frame) + + def parallel_axis(self, point, frame=None): + """Returns the inertia dyadic of the body with respect to another + point. + + Parameters + ========== + + point : sympy.physics.vector.Point + The point to express the inertia dyadic about. + frame : sympy.physics.vector.ReferenceFrame + The reference frame used to construct the dyadic. + + Returns + ======= + + inertia : sympy.physics.vector.Dyadic + The inertia dyadic of the rigid body expressed about the provided + point. + + Example + ======= + + As Body has been deprecated, the following examples are for illustrative + purposes only. The functionality of Body is fully captured by + :class:`~.RigidBody` and :class:`~.Particle`. To ignore the deprecation + warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> from sympy.physics.mechanics import Body + >>> with ignore_warnings(DeprecationWarning): + ... A = Body('A') + >>> P = A.masscenter.locatenew('point', 3 * A.x + 5 * A.y) + >>> A.parallel_axis(P).to_matrix(A.frame) + Matrix([ + [A_ixx + 25*A_mass, A_ixy - 15*A_mass, A_izx], + [A_ixy - 15*A_mass, A_iyy + 9*A_mass, A_iyz], + [ A_izx, A_iyz, A_izz + 34*A_mass]]) + + """ + if self.is_rigidbody: + return RigidBody.parallel_axis(self, point, frame) + return Particle.parallel_axis(self, point, frame) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/body_base.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/body_base.py new file mode 100644 index 0000000000000000000000000000000000000000..d2546faf685f579d2aea10ed7f139a4beced7dd0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/body_base.py @@ -0,0 +1,94 @@ +from abc import ABC, abstractmethod +from sympy import Symbol, sympify +from sympy.physics.vector import Point + +__all__ = ['BodyBase'] + + +class BodyBase(ABC): + """Abstract class for body type objects.""" + def __init__(self, name, masscenter=None, mass=None): + # Note: If frame=None, no auto-generated frame is created, because a + # Particle does not need to have a frame by default. + if not isinstance(name, str): + raise TypeError('Supply a valid name.') + self._name = name + if mass is None: + mass = Symbol(f'{name}_mass') + if masscenter is None: + masscenter = Point(f'{name}_masscenter') + self.mass = mass + self.masscenter = masscenter + self.potential_energy = 0 + self.points = [] + + def __str__(self): + return self.name + + def __repr__(self): + return (f'{self.__class__.__name__}({repr(self.name)}, masscenter=' + f'{repr(self.masscenter)}, mass={repr(self.mass)})') + + @property + def name(self): + """The name of the body.""" + return self._name + + @property + def masscenter(self): + """The body's center of mass.""" + return self._masscenter + + @masscenter.setter + def masscenter(self, point): + if not isinstance(point, Point): + raise TypeError("The body's center of mass must be a Point object.") + self._masscenter = point + + @property + def mass(self): + """The body's mass.""" + return self._mass + + @mass.setter + def mass(self, mass): + self._mass = sympify(mass) + + @property + def potential_energy(self): + """The potential energy of the body. + + Examples + ======== + + >>> from sympy.physics.mechanics import Particle, Point + >>> from sympy import symbols + >>> m, g, h = symbols('m g h') + >>> O = Point('O') + >>> P = Particle('P', O, m) + >>> P.potential_energy = m * g * h + >>> P.potential_energy + g*h*m + + """ + return self._potential_energy + + @potential_energy.setter + def potential_energy(self, scalar): + self._potential_energy = sympify(scalar) + + @abstractmethod + def kinetic_energy(self, frame): + pass + + @abstractmethod + def linear_momentum(self, frame): + pass + + @abstractmethod + def angular_momentum(self, point, frame): + pass + + @abstractmethod + def parallel_axis(self, point, frame): + pass diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/jointsmethod.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/jointsmethod.py new file mode 100644 index 0000000000000000000000000000000000000000..df7bd56360072feb57a65e5f78c2d116f0d4842d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/jointsmethod.py @@ -0,0 +1,318 @@ +from sympy.physics.mechanics import (Body, Lagrangian, KanesMethod, LagrangesMethod, + RigidBody, Particle) +from sympy.physics.mechanics.body_base import BodyBase +from sympy.physics.mechanics.method import _Methods +from sympy import Matrix +from sympy.utilities.exceptions import sympy_deprecation_warning + +__all__ = ['JointsMethod'] + + +class JointsMethod(_Methods): + """Method for formulating the equations of motion using a set of interconnected bodies with joints. + + .. deprecated:: 1.13 + The JointsMethod class is deprecated. Its functionality has been + replaced by the new :class:`~.System` class. + + Parameters + ========== + + newtonion : Body or ReferenceFrame + The newtonion(inertial) frame. + *joints : Joint + The joints in the system + + Attributes + ========== + + q, u : iterable + Iterable of the generalized coordinates and speeds + bodies : iterable + Iterable of Body objects in the system. + loads : iterable + Iterable of (Point, vector) or (ReferenceFrame, vector) tuples + describing the forces on the system. + mass_matrix : Matrix, shape(n, n) + The system's mass matrix + forcing : Matrix, shape(n, 1) + The system's forcing vector + mass_matrix_full : Matrix, shape(2*n, 2*n) + The "mass matrix" for the u's and q's + forcing_full : Matrix, shape(2*n, 1) + The "forcing vector" for the u's and q's + method : KanesMethod or Lagrange's method + Method's object. + kdes : iterable + Iterable of kde in they system. + + Examples + ======== + + As Body and JointsMethod have been deprecated, the following examples are + for illustrative purposes only. The functionality of Body is fully captured + by :class:`~.RigidBody` and :class:`~.Particle` and the functionality of + JointsMethod is fully captured by :class:`~.System`. To ignore the + deprecation warning we can use the ignore_warnings context manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + + This is a simple example for a one degree of freedom translational + spring-mass-damper. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import Body, JointsMethod, PrismaticJoint + >>> from sympy.physics.vector import dynamicsymbols + >>> c, k = symbols('c k') + >>> x, v = dynamicsymbols('x v') + >>> with ignore_warnings(DeprecationWarning): + ... wall = Body('W') + ... body = Body('B') + >>> J = PrismaticJoint('J', wall, body, coordinates=x, speeds=v) + >>> wall.apply_force(c*v*wall.x, reaction_body=body) + >>> wall.apply_force(k*x*wall.x, reaction_body=body) + >>> with ignore_warnings(DeprecationWarning): + ... method = JointsMethod(wall, J) + >>> method.form_eoms() + Matrix([[-B_mass*Derivative(v(t), t) - c*v(t) - k*x(t)]]) + >>> M = method.mass_matrix_full + >>> F = method.forcing_full + >>> rhs = M.LUsolve(F) + >>> rhs + Matrix([ + [ v(t)], + [(-c*v(t) - k*x(t))/B_mass]]) + + Notes + ===== + + ``JointsMethod`` currently only works with systems that do not have any + configuration or motion constraints. + + """ + + def __init__(self, newtonion, *joints): + sympy_deprecation_warning( + """ + The JointsMethod class is deprecated. + Its functionality has been replaced by the new System class. + """, + deprecated_since_version="1.13", + active_deprecations_target="deprecated-mechanics-jointsmethod" + ) + if isinstance(newtonion, BodyBase): + self.frame = newtonion.frame + else: + self.frame = newtonion + + self._joints = joints + self._bodies = self._generate_bodylist() + self._loads = self._generate_loadlist() + self._q = self._generate_q() + self._u = self._generate_u() + self._kdes = self._generate_kdes() + + self._method = None + + @property + def bodies(self): + """List of bodies in they system.""" + return self._bodies + + @property + def loads(self): + """List of loads on the system.""" + return self._loads + + @property + def q(self): + """List of the generalized coordinates.""" + return self._q + + @property + def u(self): + """List of the generalized speeds.""" + return self._u + + @property + def kdes(self): + """List of the generalized coordinates.""" + return self._kdes + + @property + def forcing_full(self): + """The "forcing vector" for the u's and q's.""" + return self.method.forcing_full + + @property + def mass_matrix_full(self): + """The "mass matrix" for the u's and q's.""" + return self.method.mass_matrix_full + + @property + def mass_matrix(self): + """The system's mass matrix.""" + return self.method.mass_matrix + + @property + def forcing(self): + """The system's forcing vector.""" + return self.method.forcing + + @property + def method(self): + """Object of method used to form equations of systems.""" + return self._method + + def _generate_bodylist(self): + bodies = [] + for joint in self._joints: + if joint.child not in bodies: + bodies.append(joint.child) + if joint.parent not in bodies: + bodies.append(joint.parent) + return bodies + + def _generate_loadlist(self): + load_list = [] + for body in self.bodies: + if isinstance(body, Body): + load_list.extend(body.loads) + return load_list + + def _generate_q(self): + q_ind = [] + for joint in self._joints: + for coordinate in joint.coordinates: + if coordinate in q_ind: + raise ValueError('Coordinates of joints should be unique.') + q_ind.append(coordinate) + return Matrix(q_ind) + + def _generate_u(self): + u_ind = [] + for joint in self._joints: + for speed in joint.speeds: + if speed in u_ind: + raise ValueError('Speeds of joints should be unique.') + u_ind.append(speed) + return Matrix(u_ind) + + def _generate_kdes(self): + kd_ind = Matrix(1, 0, []).T + for joint in self._joints: + kd_ind = kd_ind.col_join(joint.kdes) + return kd_ind + + def _convert_bodies(self): + # Convert `Body` to `Particle` and `RigidBody` + bodylist = [] + for body in self.bodies: + if not isinstance(body, Body): + bodylist.append(body) + continue + if body.is_rigidbody: + rb = RigidBody(body.name, body.masscenter, body.frame, body.mass, + (body.central_inertia, body.masscenter)) + rb.potential_energy = body.potential_energy + bodylist.append(rb) + else: + part = Particle(body.name, body.masscenter, body.mass) + part.potential_energy = body.potential_energy + bodylist.append(part) + return bodylist + + def form_eoms(self, method=KanesMethod): + """Method to form system's equation of motions. + + Parameters + ========== + + method : Class + Class name of method. + + Returns + ======== + + Matrix + Vector of equations of motions. + + Examples + ======== + + As Body and JointsMethod have been deprecated, the following examples + are for illustrative purposes only. The functionality of Body is fully + captured by :class:`~.RigidBody` and :class:`~.Particle` and the + functionality of JointsMethod is fully captured by :class:`~.System`. To + ignore the deprecation warning we can use the ignore_warnings context + manager. + + >>> from sympy.utilities.exceptions import ignore_warnings + + This is a simple example for a one degree of freedom translational + spring-mass-damper. + + >>> from sympy import S, symbols + >>> from sympy.physics.mechanics import LagrangesMethod, dynamicsymbols, Body + >>> from sympy.physics.mechanics import PrismaticJoint, JointsMethod + >>> q = dynamicsymbols('q') + >>> qd = dynamicsymbols('q', 1) + >>> m, k, b = symbols('m k b') + >>> with ignore_warnings(DeprecationWarning): + ... wall = Body('W') + ... part = Body('P', mass=m) + >>> part.potential_energy = k * q**2 / S(2) + >>> J = PrismaticJoint('J', wall, part, coordinates=q, speeds=qd) + >>> wall.apply_force(b * qd * wall.x, reaction_body=part) + >>> with ignore_warnings(DeprecationWarning): + ... method = JointsMethod(wall, J) + >>> method.form_eoms(LagrangesMethod) + Matrix([[b*Derivative(q(t), t) + k*q(t) + m*Derivative(q(t), (t, 2))]]) + + We can also solve for the states using the 'rhs' method. + + >>> method.rhs() + Matrix([ + [ Derivative(q(t), t)], + [(-b*Derivative(q(t), t) - k*q(t))/m]]) + + """ + + bodylist = self._convert_bodies() + if issubclass(method, LagrangesMethod): #LagrangesMethod or similar + L = Lagrangian(self.frame, *bodylist) + self._method = method(L, self.q, self.loads, bodylist, self.frame) + else: #KanesMethod or similar + self._method = method(self.frame, q_ind=self.q, u_ind=self.u, kd_eqs=self.kdes, + forcelist=self.loads, bodies=bodylist) + soln = self.method._form_eoms() + return soln + + def rhs(self, inv_method=None): + """Returns equations that can be solved numerically. + + Parameters + ========== + + inv_method : str + The specific sympy inverse matrix calculation method to use. For a + list of valid methods, see + :meth:`~sympy.matrices.matrixbase.MatrixBase.inv` + + Returns + ======== + + Matrix + Numerically solvable equations. + + See Also + ======== + + sympy.physics.mechanics.kane.KanesMethod.rhs: + KanesMethod's rhs function. + sympy.physics.mechanics.lagrange.LagrangesMethod.rhs: + LagrangesMethod's rhs function. + + """ + + return self.method.rhs(inv_method=inv_method) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/particle.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/particle.py new file mode 100644 index 0000000000000000000000000000000000000000..5d49d4f811b8d1c7fff16c71991f5e01da6ded02 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/particle.py @@ -0,0 +1,209 @@ +from sympy import S +from sympy.physics.vector import cross, dot +from sympy.physics.mechanics.body_base import BodyBase +from sympy.physics.mechanics.inertia import inertia_of_point_mass +from sympy.utilities.exceptions import sympy_deprecation_warning + +__all__ = ['Particle'] + + +class Particle(BodyBase): + """A particle. + + Explanation + =========== + + Particles have a non-zero mass and lack spatial extension; they take up no + space. + + Values need to be supplied on initialization, but can be changed later. + + Parameters + ========== + + name : str + Name of particle + point : Point + A physics/mechanics Point which represents the position, velocity, and + acceleration of this Particle + mass : Sympifyable + A SymPy expression representing the Particle's mass + potential_energy : Sympifyable + The potential energy of the Particle. + + Examples + ======== + + >>> from sympy.physics.mechanics import Particle, Point + >>> from sympy import Symbol + >>> po = Point('po') + >>> m = Symbol('m') + >>> pa = Particle('pa', po, m) + >>> # Or you could change these later + >>> pa.mass = m + >>> pa.point = po + + """ + point = BodyBase.masscenter + + def __init__(self, name, point=None, mass=None): + super().__init__(name, point, mass) + + def linear_momentum(self, frame): + """Linear momentum of the particle. + + Explanation + =========== + + The linear momentum L, of a particle P, with respect to frame N is + given by: + + L = m * v + + where m is the mass of the particle, and v is the velocity of the + particle in the frame N. + + Parameters + ========== + + frame : ReferenceFrame + The frame in which linear momentum is desired. + + Examples + ======== + + >>> from sympy.physics.mechanics import Particle, Point, ReferenceFrame + >>> from sympy.physics.mechanics import dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> m, v = dynamicsymbols('m v') + >>> N = ReferenceFrame('N') + >>> P = Point('P') + >>> A = Particle('A', P, m) + >>> P.set_vel(N, v * N.x) + >>> A.linear_momentum(N) + m*v*N.x + + """ + + return self.mass * self.point.vel(frame) + + def angular_momentum(self, point, frame): + """Angular momentum of the particle about the point. + + Explanation + =========== + + The angular momentum H, about some point O of a particle, P, is given + by: + + ``H = cross(r, m * v)`` + + where r is the position vector from point O to the particle P, m is + the mass of the particle, and v is the velocity of the particle in + the inertial frame, N. + + Parameters + ========== + + point : Point + The point about which angular momentum of the particle is desired. + + frame : ReferenceFrame + The frame in which angular momentum is desired. + + Examples + ======== + + >>> from sympy.physics.mechanics import Particle, Point, ReferenceFrame + >>> from sympy.physics.mechanics import dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> m, v, r = dynamicsymbols('m v r') + >>> N = ReferenceFrame('N') + >>> O = Point('O') + >>> A = O.locatenew('A', r * N.x) + >>> P = Particle('P', A, m) + >>> P.point.set_vel(N, v * N.y) + >>> P.angular_momentum(O, N) + m*r*v*N.z + + """ + + return cross(self.point.pos_from(point), + self.mass * self.point.vel(frame)) + + def kinetic_energy(self, frame): + """Kinetic energy of the particle. + + Explanation + =========== + + The kinetic energy, T, of a particle, P, is given by: + + ``T = 1/2 (dot(m * v, v))`` + + where m is the mass of particle P, and v is the velocity of the + particle in the supplied ReferenceFrame. + + Parameters + ========== + + frame : ReferenceFrame + The Particle's velocity is typically defined with respect to + an inertial frame but any relevant frame in which the velocity is + known can be supplied. + + Examples + ======== + + >>> from sympy.physics.mechanics import Particle, Point, ReferenceFrame + >>> from sympy import symbols + >>> m, v, r = symbols('m v r') + >>> N = ReferenceFrame('N') + >>> O = Point('O') + >>> P = Particle('P', O, m) + >>> P.point.set_vel(N, v * N.y) + >>> P.kinetic_energy(N) + m*v**2/2 + + """ + + return S.Half * self.mass * dot(self.point.vel(frame), + self.point.vel(frame)) + + def set_potential_energy(self, scalar): + sympy_deprecation_warning( + """ +The sympy.physics.mechanics.Particle.set_potential_energy() +method is deprecated. Instead use + + P.potential_energy = scalar + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-set-potential-energy", + ) + self.potential_energy = scalar + + def parallel_axis(self, point, frame): + """Returns an inertia dyadic of the particle with respect to another + point and frame. + + Parameters + ========== + + point : sympy.physics.vector.Point + The point to express the inertia dyadic about. + frame : sympy.physics.vector.ReferenceFrame + The reference frame used to construct the dyadic. + + Returns + ======= + + inertia : sympy.physics.vector.Dyadic + The inertia dyadic of the particle expressed about the provided + point and frame. + + """ + return inertia_of_point_mass(self.mass, self.point.pos_from(point), + frame) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/rigidbody.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/rigidbody.py new file mode 100644 index 0000000000000000000000000000000000000000..7cc61ff468f7f26d98209a48ca59ffa12a570490 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/rigidbody.py @@ -0,0 +1,314 @@ +from sympy import Symbol, S +from sympy.physics.vector import ReferenceFrame, Dyadic, Point, dot +from sympy.physics.mechanics.body_base import BodyBase +from sympy.physics.mechanics.inertia import inertia_of_point_mass, Inertia +from sympy.utilities.exceptions import sympy_deprecation_warning + +__all__ = ['RigidBody'] + + +class RigidBody(BodyBase): + """An idealized rigid body. + + Explanation + =========== + + This is essentially a container which holds the various components which + describe a rigid body: a name, mass, center of mass, reference frame, and + inertia. + + All of these need to be supplied on creation, but can be changed + afterwards. + + Attributes + ========== + + name : string + The body's name. + masscenter : Point + The point which represents the center of mass of the rigid body. + frame : ReferenceFrame + The ReferenceFrame which the rigid body is fixed in. + mass : Sympifyable + The body's mass. + inertia : (Dyadic, Point) + The body's inertia about a point; stored in a tuple as shown above. + potential_energy : Sympifyable + The potential energy of the RigidBody. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.mechanics import ReferenceFrame, Point, RigidBody + >>> from sympy.physics.mechanics import outer + >>> m = Symbol('m') + >>> A = ReferenceFrame('A') + >>> P = Point('P') + >>> I = outer (A.x, A.x) + >>> inertia_tuple = (I, P) + >>> B = RigidBody('B', P, A, m, inertia_tuple) + >>> # Or you could change them afterwards + >>> m2 = Symbol('m2') + >>> B.mass = m2 + + """ + + def __init__(self, name, masscenter=None, frame=None, mass=None, + inertia=None): + super().__init__(name, masscenter, mass) + if frame is None: + frame = ReferenceFrame(f'{name}_frame') + self.frame = frame + if inertia is None: + ixx = Symbol(f'{name}_ixx') + iyy = Symbol(f'{name}_iyy') + izz = Symbol(f'{name}_izz') + izx = Symbol(f'{name}_izx') + ixy = Symbol(f'{name}_ixy') + iyz = Symbol(f'{name}_iyz') + inertia = Inertia.from_inertia_scalars(self.masscenter, self.frame, + ixx, iyy, izz, ixy, iyz, izx) + self.inertia = inertia + + def __repr__(self): + return (f'{self.__class__.__name__}({repr(self.name)}, masscenter=' + f'{repr(self.masscenter)}, frame={repr(self.frame)}, mass=' + f'{repr(self.mass)}, inertia={repr(self.inertia)})') + + @property + def frame(self): + """The ReferenceFrame fixed to the body.""" + return self._frame + + @frame.setter + def frame(self, F): + if not isinstance(F, ReferenceFrame): + raise TypeError("RigidBody frame must be a ReferenceFrame object.") + self._frame = F + + @property + def x(self): + """The basis Vector for the body, in the x direction. """ + return self.frame.x + + @property + def y(self): + """The basis Vector for the body, in the y direction. """ + return self.frame.y + + @property + def z(self): + """The basis Vector for the body, in the z direction. """ + return self.frame.z + + @property + def inertia(self): + """The body's inertia about a point; stored as (Dyadic, Point).""" + return self._inertia + + @inertia.setter + def inertia(self, I): + # check if I is of the form (Dyadic, Point) + if len(I) != 2 or not isinstance(I[0], Dyadic) or not isinstance(I[1], Point): + raise TypeError("RigidBody inertia must be a tuple of the form (Dyadic, Point).") + + self._inertia = Inertia(I[0], I[1]) + # have I S/O, want I S/S* + # I S/O = I S/S* + I S*/O; I S/S* = I S/O - I S*/O + # I_S/S* = I_S/O - I_S*/O + I_Ss_O = inertia_of_point_mass(self.mass, + self.masscenter.pos_from(I[1]), + self.frame) + self._central_inertia = I[0] - I_Ss_O + + @property + def central_inertia(self): + """The body's central inertia dyadic.""" + return self._central_inertia + + @central_inertia.setter + def central_inertia(self, I): + if not isinstance(I, Dyadic): + raise TypeError("RigidBody inertia must be a Dyadic object.") + self.inertia = Inertia(I, self.masscenter) + + def linear_momentum(self, frame): + """ Linear momentum of the rigid body. + + Explanation + =========== + + The linear momentum L, of a rigid body B, with respect to frame N is + given by: + + ``L = m * v`` + + where m is the mass of the rigid body, and v is the velocity of the mass + center of B in the frame N. + + Parameters + ========== + + frame : ReferenceFrame + The frame in which linear momentum is desired. + + Examples + ======== + + >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer + >>> from sympy.physics.mechanics import RigidBody, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> m, v = dynamicsymbols('m v') + >>> N = ReferenceFrame('N') + >>> P = Point('P') + >>> P.set_vel(N, v * N.x) + >>> I = outer (N.x, N.x) + >>> Inertia_tuple = (I, P) + >>> B = RigidBody('B', P, N, m, Inertia_tuple) + >>> B.linear_momentum(N) + m*v*N.x + + """ + + return self.mass * self.masscenter.vel(frame) + + def angular_momentum(self, point, frame): + """Returns the angular momentum of the rigid body about a point in the + given frame. + + Explanation + =========== + + The angular momentum H of a rigid body B about some point O in a frame N + is given by: + + ``H = dot(I, w) + cross(r, m * v)`` + + where I and m are the central inertia dyadic and mass of rigid body B, w + is the angular velocity of body B in the frame N, r is the position + vector from point O to the mass center of B, and v is the velocity of + the mass center in the frame N. + + Parameters + ========== + + point : Point + The point about which angular momentum is desired. + frame : ReferenceFrame + The frame in which angular momentum is desired. + + Examples + ======== + + >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer + >>> from sympy.physics.mechanics import RigidBody, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> m, v, r, omega = dynamicsymbols('m v r omega') + >>> N = ReferenceFrame('N') + >>> b = ReferenceFrame('b') + >>> b.set_ang_vel(N, omega * b.x) + >>> P = Point('P') + >>> P.set_vel(N, 1 * N.x) + >>> I = outer(b.x, b.x) + >>> B = RigidBody('B', P, b, m, (I, P)) + >>> B.angular_momentum(P, N) + omega*b.x + + """ + I = self.central_inertia + w = self.frame.ang_vel_in(frame) + m = self.mass + r = self.masscenter.pos_from(point) + v = self.masscenter.vel(frame) + + return I.dot(w) + r.cross(m * v) + + def kinetic_energy(self, frame): + """Kinetic energy of the rigid body. + + Explanation + =========== + + The kinetic energy, T, of a rigid body, B, is given by: + + ``T = 1/2 * (dot(dot(I, w), w) + dot(m * v, v))`` + + where I and m are the central inertia dyadic and mass of rigid body B + respectively, w is the body's angular velocity, and v is the velocity of + the body's mass center in the supplied ReferenceFrame. + + Parameters + ========== + + frame : ReferenceFrame + The RigidBody's angular velocity and the velocity of it's mass + center are typically defined with respect to an inertial frame but + any relevant frame in which the velocities are known can be + supplied. + + Examples + ======== + + >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer + >>> from sympy.physics.mechanics import RigidBody + >>> from sympy import symbols + >>> m, v, r, omega = symbols('m v r omega') + >>> N = ReferenceFrame('N') + >>> b = ReferenceFrame('b') + >>> b.set_ang_vel(N, omega * b.x) + >>> P = Point('P') + >>> P.set_vel(N, v * N.x) + >>> I = outer (b.x, b.x) + >>> inertia_tuple = (I, P) + >>> B = RigidBody('B', P, b, m, inertia_tuple) + >>> B.kinetic_energy(N) + m*v**2/2 + omega**2/2 + + """ + + rotational_KE = S.Half * dot( + self.frame.ang_vel_in(frame), + dot(self.central_inertia, self.frame.ang_vel_in(frame))) + translational_KE = S.Half * self.mass * dot(self.masscenter.vel(frame), + self.masscenter.vel(frame)) + return rotational_KE + translational_KE + + def set_potential_energy(self, scalar): + sympy_deprecation_warning( + """ +The sympy.physics.mechanics.RigidBody.set_potential_energy() +method is deprecated. Instead use + + B.potential_energy = scalar + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-set-potential-energy", + ) + self.potential_energy = scalar + + def parallel_axis(self, point, frame=None): + """Returns the inertia dyadic of the body with respect to another point. + + Parameters + ========== + + point : sympy.physics.vector.Point + The point to express the inertia dyadic about. + frame : sympy.physics.vector.ReferenceFrame + The reference frame used to construct the dyadic. + + Returns + ======= + + inertia : sympy.physics.vector.Dyadic + The inertia dyadic of the rigid body expressed about the provided + point. + + """ + if frame is None: + frame = self.frame + return self.central_inertia + inertia_of_point_mass( + self.mass, self.masscenter.pos_from(point), frame) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/paulialgebra.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/paulialgebra.py new file mode 100644 index 0000000000000000000000000000000000000000..300957354ff34907035aa1d1a48b00276230a1e5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/paulialgebra.py @@ -0,0 +1,231 @@ +""" +This module implements Pauli algebra by subclassing Symbol. Only algebraic +properties of Pauli matrices are used (we do not use the Matrix class). + +See the documentation to the class Pauli for examples. + +References +========== + +.. [1] https://en.wikipedia.org/wiki/Pauli_matrices +""" + +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.numbers import I +from sympy.core.power import Pow +from sympy.core.symbol import Symbol +from sympy.physics.quantum import TensorProduct + +__all__ = ['evaluate_pauli_product'] + + +def delta(i, j): + """ + Returns 1 if ``i == j``, else 0. + + This is used in the multiplication of Pauli matrices. + + Examples + ======== + + >>> from sympy.physics.paulialgebra import delta + >>> delta(1, 1) + 1 + >>> delta(2, 3) + 0 + """ + if i == j: + return 1 + else: + return 0 + + +def epsilon(i, j, k): + """ + Return 1 if i,j,k is equal to (1,2,3), (2,3,1), or (3,1,2); + -1 if ``i``,``j``,``k`` is equal to (1,3,2), (3,2,1), or (2,1,3); + else return 0. + + This is used in the multiplication of Pauli matrices. + + Examples + ======== + + >>> from sympy.physics.paulialgebra import epsilon + >>> epsilon(1, 2, 3) + 1 + >>> epsilon(1, 3, 2) + -1 + """ + if (i, j, k) in ((1, 2, 3), (2, 3, 1), (3, 1, 2)): + return 1 + elif (i, j, k) in ((1, 3, 2), (3, 2, 1), (2, 1, 3)): + return -1 + else: + return 0 + + +class Pauli(Symbol): + """ + The class representing algebraic properties of Pauli matrices. + + Explanation + =========== + + The symbol used to display the Pauli matrices can be changed with an + optional parameter ``label="sigma"``. Pauli matrices with different + ``label`` attributes cannot multiply together. + + If the left multiplication of symbol or number with Pauli matrix is needed, + please use parentheses to separate Pauli and symbolic multiplication + (for example: 2*I*(Pauli(3)*Pauli(2))). + + Another variant is to use evaluate_pauli_product function to evaluate + the product of Pauli matrices and other symbols (with commutative + multiply rules). + + See Also + ======== + + evaluate_pauli_product + + Examples + ======== + + >>> from sympy.physics.paulialgebra import Pauli + >>> Pauli(1) + sigma1 + >>> Pauli(1)*Pauli(2) + I*sigma3 + >>> Pauli(1)*Pauli(1) + 1 + >>> Pauli(3)**4 + 1 + >>> Pauli(1)*Pauli(2)*Pauli(3) + I + + >>> from sympy.physics.paulialgebra import Pauli + >>> Pauli(1, label="tau") + tau1 + >>> Pauli(1)*Pauli(2, label="tau") + sigma1*tau2 + >>> Pauli(1, label="tau")*Pauli(2, label="tau") + I*tau3 + + >>> from sympy import I + >>> I*(Pauli(2)*Pauli(3)) + -sigma1 + + >>> from sympy.physics.paulialgebra import evaluate_pauli_product + >>> f = I*Pauli(2)*Pauli(3) + >>> f + I*sigma2*sigma3 + >>> evaluate_pauli_product(f) + -sigma1 + """ + + __slots__ = ("i", "label") + + def __new__(cls, i, label="sigma"): + if i not in [1, 2, 3]: + raise IndexError("Invalid Pauli index") + obj = Symbol.__new__(cls, "%s%d" %(label,i), commutative=False, hermitian=True) + obj.i = i + obj.label = label + return obj + + def __getnewargs_ex__(self): + return (self.i, self.label), {} + + def _hashable_content(self): + return (self.i, self.label) + + # FIXME don't work for -I*Pauli(2)*Pauli(3) + def __mul__(self, other): + if isinstance(other, Pauli): + j = self.i + k = other.i + jlab = self.label + klab = other.label + + if jlab == klab: + return delta(j, k) \ + + I*epsilon(j, k, 1)*Pauli(1,jlab) \ + + I*epsilon(j, k, 2)*Pauli(2,jlab) \ + + I*epsilon(j, k, 3)*Pauli(3,jlab) + return super().__mul__(other) + + def _eval_power(b, e): + if e.is_Integer and e.is_positive: + return super().__pow__(int(e) % 2) + + +def evaluate_pauli_product(arg): + '''Help function to evaluate Pauli matrices product + with symbolic objects. + + Parameters + ========== + + arg: symbolic expression that contains Paulimatrices + + Examples + ======== + + >>> from sympy.physics.paulialgebra import Pauli, evaluate_pauli_product + >>> from sympy import I + >>> evaluate_pauli_product(I*Pauli(1)*Pauli(2)) + -sigma3 + + >>> from sympy.abc import x + >>> evaluate_pauli_product(x**2*Pauli(2)*Pauli(1)) + -I*x**2*sigma3 + ''' + start = arg + end = arg + + if isinstance(arg, Pow) and isinstance(arg.args[0], Pauli): + if arg.args[1].is_odd: + return arg.args[0] + else: + return 1 + + if isinstance(arg, Add): + return Add(*[evaluate_pauli_product(part) for part in arg.args]) + + if isinstance(arg, TensorProduct): + return TensorProduct(*[evaluate_pauli_product(part) for part in arg.args]) + + elif not(isinstance(arg, Mul)): + return arg + + while not start == end or start == arg and end == arg: + start = end + + tmp = start.as_coeff_mul() + sigma_product = 1 + com_product = 1 + keeper = 1 + + for el in tmp[1]: + if isinstance(el, Pauli): + sigma_product *= el + elif not el.is_commutative: + if isinstance(el, Pow) and isinstance(el.args[0], Pauli): + if el.args[1].is_odd: + sigma_product *= el.args[0] + elif isinstance(el, TensorProduct): + keeper = keeper*sigma_product*\ + TensorProduct( + *[evaluate_pauli_product(part) for part in el.args] + ) + sigma_product = 1 + else: + keeper = keeper*sigma_product*el + sigma_product = 1 + else: + com_product *= el + end = tmp[0]*keeper*sigma_product*com_product + if end == arg: break + return end diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/pring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/pring.py new file mode 100644 index 0000000000000000000000000000000000000000..325f4ff98a8c9fc428b4e332153af533f4d199ca --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/pring.py @@ -0,0 +1,94 @@ +from sympy.core.numbers import (I, pi) +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.quantum.constants import hbar + + +def wavefunction(n, x): + """ + Returns the wavefunction for particle on ring. + + Parameters + ========== + + n : The quantum number. + Here ``n`` can be positive as well as negative + which can be used to describe the direction of motion of particle. + x : + The angle. + + Examples + ======== + + >>> from sympy.physics.pring import wavefunction + >>> from sympy import Symbol, integrate, pi + >>> x=Symbol("x") + >>> wavefunction(1, x) + sqrt(2)*exp(I*x)/(2*sqrt(pi)) + >>> wavefunction(2, x) + sqrt(2)*exp(2*I*x)/(2*sqrt(pi)) + >>> wavefunction(3, x) + sqrt(2)*exp(3*I*x)/(2*sqrt(pi)) + + The normalization of the wavefunction is: + + >>> integrate(wavefunction(2, x)*wavefunction(-2, x), (x, 0, 2*pi)) + 1 + >>> integrate(wavefunction(4, x)*wavefunction(-4, x), (x, 0, 2*pi)) + 1 + + References + ========== + + .. [1] Atkins, Peter W.; Friedman, Ronald (2005). Molecular Quantum + Mechanics (4th ed.). Pages 71-73. + + """ + # sympify arguments + n, x = S(n), S(x) + return exp(n * I * x) / sqrt(2 * pi) + + +def energy(n, m, r): + """ + Returns the energy of the state corresponding to quantum number ``n``. + + E=(n**2 * (hcross)**2) / (2 * m * r**2) + + Parameters + ========== + + n : + The quantum number. + m : + Mass of the particle. + r : + Radius of circle. + + Examples + ======== + + >>> from sympy.physics.pring import energy + >>> from sympy import Symbol + >>> m=Symbol("m") + >>> r=Symbol("r") + >>> energy(1, m, r) + hbar**2/(2*m*r**2) + >>> energy(2, m, r) + 2*hbar**2/(m*r**2) + >>> energy(-2, 2.0, 3.0) + 0.111111111111111*hbar**2 + + References + ========== + + .. [1] Atkins, Peter W.; Friedman, Ronald (2005). Molecular Quantum + Mechanics (4th ed.). Pages 71-73. + + """ + n, m, r = S(n), S(m), S(r) + if n.is_integer: + return (n**2 * hbar**2) / (2 * m * r**2) + else: + raise ValueError("'n' must be integer") diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/qho_1d.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/qho_1d.py new file mode 100644 index 0000000000000000000000000000000000000000..f418e0e954656923fbfa64cea2145581ddf65aea --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/qho_1d.py @@ -0,0 +1,88 @@ +from sympy.core import S, pi, Rational +from sympy.functions import hermite, sqrt, exp, factorial, Abs +from sympy.physics.quantum.constants import hbar + + +def psi_n(n, x, m, omega): + """ + Returns the wavefunction psi_{n} for the One-dimensional harmonic oscillator. + + Parameters + ========== + + n : + the "nodal" quantum number. Corresponds to the number of nodes in the + wavefunction. ``n >= 0`` + x : + x coordinate. + m : + Mass of the particle. + omega : + Angular frequency of the oscillator. + + Examples + ======== + + >>> from sympy.physics.qho_1d import psi_n + >>> from sympy.abc import m, x, omega + >>> psi_n(0, x, m, omega) + (m*omega)**(1/4)*exp(-m*omega*x**2/(2*hbar))/(hbar**(1/4)*pi**(1/4)) + + """ + + # sympify arguments + n, x, m, omega = map(S, [n, x, m, omega]) + nu = m * omega / hbar + # normalization coefficient + C = (nu/pi)**Rational(1, 4) * sqrt(1/(2**n*factorial(n))) + + return C * exp(-nu* x**2 /2) * hermite(n, sqrt(nu)*x) + + +def E_n(n, omega): + """ + Returns the Energy of the One-dimensional harmonic oscillator. + + Parameters + ========== + + n : + The "nodal" quantum number. + omega : + The harmonic oscillator angular frequency. + + Notes + ===== + + The unit of the returned value matches the unit of hw, since the energy is + calculated as: + + E_n = hbar * omega*(n + 1/2) + + Examples + ======== + + >>> from sympy.physics.qho_1d import E_n + >>> from sympy.abc import x, omega + >>> E_n(x, omega) + hbar*omega*(x + 1/2) + """ + + return hbar * omega * (n + S.Half) + + +def coherent_state(n, alpha): + """ + Returns for the coherent states of 1D harmonic oscillator. + See https://en.wikipedia.org/wiki/Coherent_states + + Parameters + ========== + + n : + The "nodal" quantum number. + alpha : + The eigen value of annihilation operator. + """ + + return exp(- Abs(alpha)**2/2)*(alpha**n)/sqrt(factorial(n)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/secondquant.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/secondquant.py new file mode 100644 index 0000000000000000000000000000000000000000..189e8e8b50c785759b03f19f28285f7988cfca75 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/secondquant.py @@ -0,0 +1,3125 @@ +""" +Second quantization operators and states for bosons. + +This follow the formulation of Fetter and Welecka, "Quantum Theory +of Many-Particle Systems." +""" +from collections import defaultdict + +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import Function +from sympy.core.mul import Mul +from sympy.core.numbers import I +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Dummy, Symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.complexes import conjugate +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.matrices.dense import zeros +from sympy.printing.str import StrPrinter +from sympy.utilities.iterables import has_dups + +__all__ = [ + 'Dagger', + 'KroneckerDelta', + 'BosonicOperator', + 'AnnihilateBoson', + 'CreateBoson', + 'AnnihilateFermion', + 'CreateFermion', + 'FockState', + 'FockStateBra', + 'FockStateKet', + 'FockStateBosonKet', + 'FockStateBosonBra', + 'FockStateFermionKet', + 'FockStateFermionBra', + 'BBra', + 'BKet', + 'FBra', + 'FKet', + 'F', + 'Fd', + 'B', + 'Bd', + 'apply_operators', + 'InnerProduct', + 'BosonicBasis', + 'VarBosonicBasis', + 'FixedBosonicBasis', + 'Commutator', + 'matrix_rep', + 'contraction', + 'wicks', + 'NO', + 'evaluate_deltas', + 'AntiSymmetricTensor', + 'substitute_dummies', + 'PermutationOperator', + 'simplify_index_permutations', +] + + +class SecondQuantizationError(Exception): + pass + + +class AppliesOnlyToSymbolicIndex(SecondQuantizationError): + pass + + +class ContractionAppliesOnlyToFermions(SecondQuantizationError): + pass + + +class ViolationOfPauliPrinciple(SecondQuantizationError): + pass + + +class SubstitutionOfAmbigousOperatorFailed(SecondQuantizationError): + pass + + +class WicksTheoremDoesNotApply(SecondQuantizationError): + pass + + +class Dagger(Expr): + """ + Hermitian conjugate of creation/annihilation operators. + + Examples + ======== + + >>> from sympy import I + >>> from sympy.physics.secondquant import Dagger, B, Bd + >>> Dagger(2*I) + -2*I + >>> Dagger(B(0)) + CreateBoson(0) + >>> Dagger(Bd(0)) + AnnihilateBoson(0) + + """ + + def __new__(cls, arg): + arg = sympify(arg) + r = cls.eval(arg) + if isinstance(r, Basic): + return r + obj = Basic.__new__(cls, arg) + return obj + + @classmethod + def eval(cls, arg): + """ + Evaluates the Dagger instance. + + Examples + ======== + + >>> from sympy import I + >>> from sympy.physics.secondquant import Dagger, B, Bd + >>> Dagger(2*I) + -2*I + >>> Dagger(B(0)) + CreateBoson(0) + >>> Dagger(Bd(0)) + AnnihilateBoson(0) + + The eval() method is called automatically. + + """ + dagger = getattr(arg, '_dagger_', None) + if dagger is not None: + return dagger() + if isinstance(arg, Symbol) and arg.is_commutative: + return conjugate(arg) + if isinstance(arg, Basic): + if arg.is_Add: + return Add(*tuple(map(Dagger, arg.args))) + if arg.is_Mul: + return Mul(*tuple(map(Dagger, reversed(arg.args)))) + if arg.is_Number: + return arg + if arg.is_Pow: + return Pow(Dagger(arg.args[0]), arg.args[1]) + if arg == I: + return -arg + if isinstance(arg, Function): + if all(a.is_commutative for a in arg.args): + return arg.func(*[Dagger(a) for a in arg.args]) + else: + return None + + def _dagger_(self): + return self.args[0] + + +class TensorSymbol(Expr): + + is_commutative = True + + +class AntiSymmetricTensor(TensorSymbol): + """Stores upper and lower indices in separate Tuple's. + + Each group of indices is assumed to be antisymmetric. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import AntiSymmetricTensor + >>> i, j = symbols('i j', below_fermi=True) + >>> a, b = symbols('a b', above_fermi=True) + >>> AntiSymmetricTensor('v', (a, i), (b, j)) + AntiSymmetricTensor(v, (a, i), (b, j)) + >>> AntiSymmetricTensor('v', (i, a), (b, j)) + -AntiSymmetricTensor(v, (a, i), (b, j)) + + As you can see, the indices are automatically sorted to a canonical form. + + """ + + def __new__(cls, symbol, upper, lower): + + try: + upper, signu = _sort_anticommuting_fermions( + upper, key=_sqkey_index) + lower, signl = _sort_anticommuting_fermions( + lower, key=_sqkey_index) + + except ViolationOfPauliPrinciple: + return S.Zero + + symbol = sympify(symbol) + upper = Tuple(*upper) + lower = Tuple(*lower) + + if (signu + signl) % 2: + return -TensorSymbol.__new__(cls, symbol, upper, lower) + else: + + return TensorSymbol.__new__(cls, symbol, upper, lower) + + def _latex(self, printer): + return "{%s^{%s}_{%s}}" % ( + self.symbol, + "".join([ printer._print(i) for i in self.args[1]]), + "".join([ printer._print(i) for i in self.args[2]]) + ) + + @property + def symbol(self): + """ + Returns the symbol of the tensor. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import AntiSymmetricTensor + >>> i, j = symbols('i,j', below_fermi=True) + >>> a, b = symbols('a,b', above_fermi=True) + >>> AntiSymmetricTensor('v', (a, i), (b, j)) + AntiSymmetricTensor(v, (a, i), (b, j)) + >>> AntiSymmetricTensor('v', (a, i), (b, j)).symbol + v + + """ + return self.args[0] + + @property + def upper(self): + """ + Returns the upper indices. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import AntiSymmetricTensor + >>> i, j = symbols('i,j', below_fermi=True) + >>> a, b = symbols('a,b', above_fermi=True) + >>> AntiSymmetricTensor('v', (a, i), (b, j)) + AntiSymmetricTensor(v, (a, i), (b, j)) + >>> AntiSymmetricTensor('v', (a, i), (b, j)).upper + (a, i) + + + """ + return self.args[1] + + @property + def lower(self): + """ + Returns the lower indices. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import AntiSymmetricTensor + >>> i, j = symbols('i,j', below_fermi=True) + >>> a, b = symbols('a,b', above_fermi=True) + >>> AntiSymmetricTensor('v', (a, i), (b, j)) + AntiSymmetricTensor(v, (a, i), (b, j)) + >>> AntiSymmetricTensor('v', (a, i), (b, j)).lower + (b, j) + + """ + return self.args[2] + + def __str__(self): + return "%s(%s,%s)" % self.args + + +class SqOperator(Expr): + """ + Base class for Second Quantization operators. + """ + + op_symbol = 'sq' + + is_commutative = False + + def __new__(cls, k): + obj = Basic.__new__(cls, sympify(k)) + return obj + + @property + def state(self): + """ + Returns the state index related to this operator. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F, Fd, B, Bd + >>> p = Symbol('p') + >>> F(p).state + p + >>> Fd(p).state + p + >>> B(p).state + p + >>> Bd(p).state + p + + """ + return self.args[0] + + @property + def is_symbolic(self): + """ + Returns True if the state is a symbol (as opposed to a number). + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> p = Symbol('p') + >>> F(p).is_symbolic + True + >>> F(1).is_symbolic + False + + """ + if self.state.is_Integer: + return False + else: + return True + + def __repr__(self): + return NotImplemented + + def __str__(self): + return "%s(%r)" % (self.op_symbol, self.state) + + def apply_operator(self, state): + """ + Applies an operator to itself. + """ + raise NotImplementedError('implement apply_operator in a subclass') + + +class BosonicOperator(SqOperator): + pass + + +class Annihilator(SqOperator): + pass + + +class Creator(SqOperator): + pass + + +class AnnihilateBoson(BosonicOperator, Annihilator): + """ + Bosonic annihilation operator. + + Examples + ======== + + >>> from sympy.physics.secondquant import B + >>> from sympy.abc import x + >>> B(x) + AnnihilateBoson(x) + """ + + op_symbol = 'b' + + def _dagger_(self): + return CreateBoson(self.state) + + def apply_operator(self, state): + """ + Apply state to self if self is not symbolic and state is a FockStateKet, else + multiply self by state. + + Examples + ======== + + >>> from sympy.physics.secondquant import B, BKet + >>> from sympy.abc import x, y, n + >>> B(x).apply_operator(y) + y*AnnihilateBoson(x) + >>> B(0).apply_operator(BKet((n,))) + sqrt(n)*FockStateBosonKet((n - 1,)) + + """ + if not self.is_symbolic and isinstance(state, FockStateKet): + element = self.state + amp = sqrt(state[element]) + return amp*state.down(element) + else: + return Mul(self, state) + + def __repr__(self): + return "AnnihilateBoson(%s)" % self.state + + def _latex(self, printer): + if self.state is S.Zero: + return "b_{0}" + else: + return "b_{%s}" % printer._print(self.state) + +class CreateBoson(BosonicOperator, Creator): + """ + Bosonic creation operator. + """ + + op_symbol = 'b+' + + def _dagger_(self): + return AnnihilateBoson(self.state) + + def apply_operator(self, state): + """ + Apply state to self if self is not symbolic and state is a FockStateKet, else + multiply self by state. + + Examples + ======== + + >>> from sympy.physics.secondquant import B, Dagger, BKet + >>> from sympy.abc import x, y, n + >>> Dagger(B(x)).apply_operator(y) + y*CreateBoson(x) + >>> B(0).apply_operator(BKet((n,))) + sqrt(n)*FockStateBosonKet((n - 1,)) + """ + if not self.is_symbolic and isinstance(state, FockStateKet): + element = self.state + amp = sqrt(state[element] + 1) + return amp*state.up(element) + else: + return Mul(self, state) + + def __repr__(self): + return "CreateBoson(%s)" % self.state + + def _latex(self, printer): + if self.state is S.Zero: + return "{b^\\dagger_{0}}" + else: + return "{b^\\dagger_{%s}}" % printer._print(self.state) + +B = AnnihilateBoson +Bd = CreateBoson + + +class FermionicOperator(SqOperator): + + @property + def is_restricted(self): + """ + Is this FermionicOperator restricted with respect to fermi level? + + Returns + ======= + + 1 : restricted to orbits above fermi + 0 : no restriction + -1 : restricted to orbits below fermi + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F, Fd + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> F(a).is_restricted + 1 + >>> Fd(a).is_restricted + 1 + >>> F(i).is_restricted + -1 + >>> Fd(i).is_restricted + -1 + >>> F(p).is_restricted + 0 + >>> Fd(p).is_restricted + 0 + + """ + ass = self.args[0].assumptions0 + if ass.get("below_fermi"): + return -1 + if ass.get("above_fermi"): + return 1 + return 0 + + @property + def is_above_fermi(self): + """ + Does the index of this FermionicOperator allow values above fermi? + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> F(a).is_above_fermi + True + >>> F(i).is_above_fermi + False + >>> F(p).is_above_fermi + True + + Note + ==== + + The same applies to creation operators Fd + + """ + return not self.args[0].assumptions0.get("below_fermi") + + @property + def is_below_fermi(self): + """ + Does the index of this FermionicOperator allow values below fermi? + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> F(a).is_below_fermi + False + >>> F(i).is_below_fermi + True + >>> F(p).is_below_fermi + True + + The same applies to creation operators Fd + + """ + return not self.args[0].assumptions0.get("above_fermi") + + @property + def is_only_below_fermi(self): + """ + Is the index of this FermionicOperator restricted to values below fermi? + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> F(a).is_only_below_fermi + False + >>> F(i).is_only_below_fermi + True + >>> F(p).is_only_below_fermi + False + + The same applies to creation operators Fd + """ + return self.is_below_fermi and not self.is_above_fermi + + @property + def is_only_above_fermi(self): + """ + Is the index of this FermionicOperator restricted to values above fermi? + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> F(a).is_only_above_fermi + True + >>> F(i).is_only_above_fermi + False + >>> F(p).is_only_above_fermi + False + + The same applies to creation operators Fd + """ + return self.is_above_fermi and not self.is_below_fermi + + def _sortkey(self): + h = hash(self) + label = str(self.args[0]) + + if self.is_only_q_creator: + return 1, label, h + if self.is_only_q_annihilator: + return 4, label, h + if isinstance(self, Annihilator): + return 3, label, h + if isinstance(self, Creator): + return 2, label, h + + +class AnnihilateFermion(FermionicOperator, Annihilator): + """ + Fermionic annihilation operator. + """ + + op_symbol = 'f' + + def _dagger_(self): + return CreateFermion(self.state) + + def apply_operator(self, state): + """ + Apply state to self if self is not symbolic and state is a FockStateKet, else + multiply self by state. + + Examples + ======== + + >>> from sympy.physics.secondquant import B, Dagger, BKet + >>> from sympy.abc import x, y, n + >>> Dagger(B(x)).apply_operator(y) + y*CreateBoson(x) + >>> B(0).apply_operator(BKet((n,))) + sqrt(n)*FockStateBosonKet((n - 1,)) + """ + if isinstance(state, FockStateFermionKet): + element = self.state + return state.down(element) + + elif isinstance(state, Mul): + c_part, nc_part = state.args_cnc() + if isinstance(nc_part[0], FockStateFermionKet): + element = self.state + return Mul(*(c_part + [nc_part[0].down(element)] + nc_part[1:])) + else: + return Mul(self, state) + + else: + return Mul(self, state) + + @property + def is_q_creator(self): + """ + Can we create a quasi-particle? (create hole or create particle) + If so, would that be above or below the fermi surface? + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> F(a).is_q_creator + 0 + >>> F(i).is_q_creator + -1 + >>> F(p).is_q_creator + -1 + + """ + if self.is_below_fermi: + return -1 + return 0 + + @property + def is_q_annihilator(self): + """ + Can we destroy a quasi-particle? (annihilate hole or annihilate particle) + If so, would that be above or below the fermi surface? + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> a = Symbol('a', above_fermi=1) + >>> i = Symbol('i', below_fermi=1) + >>> p = Symbol('p') + + >>> F(a).is_q_annihilator + 1 + >>> F(i).is_q_annihilator + 0 + >>> F(p).is_q_annihilator + 1 + + """ + if self.is_above_fermi: + return 1 + return 0 + + @property + def is_only_q_creator(self): + """ + Always create a quasi-particle? (create hole or create particle) + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> F(a).is_only_q_creator + False + >>> F(i).is_only_q_creator + True + >>> F(p).is_only_q_creator + False + + """ + return self.is_only_below_fermi + + @property + def is_only_q_annihilator(self): + """ + Always destroy a quasi-particle? (annihilate hole or annihilate particle) + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import F + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> F(a).is_only_q_annihilator + True + >>> F(i).is_only_q_annihilator + False + >>> F(p).is_only_q_annihilator + False + + """ + return self.is_only_above_fermi + + def __repr__(self): + return "AnnihilateFermion(%s)" % self.state + + def _latex(self, printer): + if self.state is S.Zero: + return "a_{0}" + else: + return "a_{%s}" % printer._print(self.state) + + +class CreateFermion(FermionicOperator, Creator): + """ + Fermionic creation operator. + """ + + op_symbol = 'f+' + + def _dagger_(self): + return AnnihilateFermion(self.state) + + def apply_operator(self, state): + """ + Apply state to self if self is not symbolic and state is a FockStateKet, else + multiply self by state. + + Examples + ======== + + >>> from sympy.physics.secondquant import B, Dagger, BKet + >>> from sympy.abc import x, y, n + >>> Dagger(B(x)).apply_operator(y) + y*CreateBoson(x) + >>> B(0).apply_operator(BKet((n,))) + sqrt(n)*FockStateBosonKet((n - 1,)) + """ + if isinstance(state, FockStateFermionKet): + element = self.state + return state.up(element) + + elif isinstance(state, Mul): + c_part, nc_part = state.args_cnc() + if isinstance(nc_part[0], FockStateFermionKet): + element = self.state + return Mul(*(c_part + [nc_part[0].up(element)] + nc_part[1:])) + + return Mul(self, state) + + @property + def is_q_creator(self): + """ + Can we create a quasi-particle? (create hole or create particle) + If so, would that be above or below the fermi surface? + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import Fd + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> Fd(a).is_q_creator + 1 + >>> Fd(i).is_q_creator + 0 + >>> Fd(p).is_q_creator + 1 + + """ + if self.is_above_fermi: + return 1 + return 0 + + @property + def is_q_annihilator(self): + """ + Can we destroy a quasi-particle? (annihilate hole or annihilate particle) + If so, would that be above or below the fermi surface? + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import Fd + >>> a = Symbol('a', above_fermi=1) + >>> i = Symbol('i', below_fermi=1) + >>> p = Symbol('p') + + >>> Fd(a).is_q_annihilator + 0 + >>> Fd(i).is_q_annihilator + -1 + >>> Fd(p).is_q_annihilator + -1 + + """ + if self.is_below_fermi: + return -1 + return 0 + + @property + def is_only_q_creator(self): + """ + Always create a quasi-particle? (create hole or create particle) + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import Fd + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> Fd(a).is_only_q_creator + True + >>> Fd(i).is_only_q_creator + False + >>> Fd(p).is_only_q_creator + False + + """ + return self.is_only_above_fermi + + @property + def is_only_q_annihilator(self): + """ + Always destroy a quasi-particle? (annihilate hole or annihilate particle) + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import Fd + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> Fd(a).is_only_q_annihilator + False + >>> Fd(i).is_only_q_annihilator + True + >>> Fd(p).is_only_q_annihilator + False + + """ + return self.is_only_below_fermi + + def __repr__(self): + return "CreateFermion(%s)" % self.state + + def _latex(self, printer): + if self.state is S.Zero: + return "{a^\\dagger_{0}}" + else: + return "{a^\\dagger_{%s}}" % printer._print(self.state) + +Fd = CreateFermion +F = AnnihilateFermion + + +class FockState(Expr): + """ + Many particle Fock state with a sequence of occupation numbers. + + Anywhere you can have a FockState, you can also have S.Zero. + All code must check for this! + + Base class to represent FockStates. + """ + is_commutative = False + + def __new__(cls, occupations): + """ + occupations is a list with two possible meanings: + + - For bosons it is a list of occupation numbers. + Element i is the number of particles in state i. + + - For fermions it is a list of occupied orbits. + Element 0 is the state that was occupied first, element i + is the i'th occupied state. + """ + occupations = list(map(sympify, occupations)) + obj = Basic.__new__(cls, Tuple(*occupations)) + return obj + + def __getitem__(self, i): + i = int(i) + return self.args[0][i] + + def __repr__(self): + return ("FockState(%r)") % (self.args) + + def __str__(self): + return "%s%r%s" % (getattr(self, 'lbracket', ""), self._labels(), getattr(self, 'rbracket', "")) + + def _labels(self): + return self.args[0] + + def __len__(self): + return len(self.args[0]) + + def _latex(self, printer): + return "%s%s%s" % (getattr(self, 'lbracket_latex', ""), printer._print(self._labels()), getattr(self, 'rbracket_latex', "")) + + +class BosonState(FockState): + """ + Base class for FockStateBoson(Ket/Bra). + """ + + def up(self, i): + """ + Performs the action of a creation operator. + + Examples + ======== + + >>> from sympy.physics.secondquant import BBra + >>> b = BBra([1, 2]) + >>> b + FockStateBosonBra((1, 2)) + >>> b.up(1) + FockStateBosonBra((1, 3)) + """ + i = int(i) + new_occs = list(self.args[0]) + new_occs[i] = new_occs[i] + S.One + return self.__class__(new_occs) + + def down(self, i): + """ + Performs the action of an annihilation operator. + + Examples + ======== + + >>> from sympy.physics.secondquant import BBra + >>> b = BBra([1, 2]) + >>> b + FockStateBosonBra((1, 2)) + >>> b.down(1) + FockStateBosonBra((1, 1)) + """ + i = int(i) + new_occs = list(self.args[0]) + if new_occs[i] == S.Zero: + return S.Zero + else: + new_occs[i] = new_occs[i] - S.One + return self.__class__(new_occs) + + +class FermionState(FockState): + """ + Base class for FockStateFermion(Ket/Bra). + """ + + fermi_level = 0 + + def __new__(cls, occupations, fermi_level=0): + occupations = list(map(sympify, occupations)) + if len(occupations) > 1: + try: + (occupations, sign) = _sort_anticommuting_fermions( + occupations, key=_sqkey_index) + except ViolationOfPauliPrinciple: + return S.Zero + else: + sign = 0 + + cls.fermi_level = fermi_level + + if cls._count_holes(occupations) > fermi_level: + return S.Zero + + if sign % 2: + return S.NegativeOne*FockState.__new__(cls, occupations) + else: + return FockState.__new__(cls, occupations) + + def up(self, i): + """ + Performs the action of a creation operator. + + Explanation + =========== + + If below fermi we try to remove a hole, + if above fermi we try to create a particle. + + If general index p we return ``Kronecker(p,i)*self`` + where ``i`` is a new symbol with restriction above or below. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import FKet + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + >>> FKet([]).up(a) + FockStateFermionKet((a,)) + + A creator acting on vacuum below fermi vanishes + + >>> FKet([]).up(i) + 0 + + + """ + present = i in self.args[0] + + if self._only_above_fermi(i): + if present: + return S.Zero + else: + return self._add_orbit(i) + elif self._only_below_fermi(i): + if present: + return self._remove_orbit(i) + else: + return S.Zero + else: + if present: + hole = Dummy("i", below_fermi=True) + return KroneckerDelta(i, hole)*self._remove_orbit(i) + else: + particle = Dummy("a", above_fermi=True) + return KroneckerDelta(i, particle)*self._add_orbit(i) + + def down(self, i): + """ + Performs the action of an annihilation operator. + + Explanation + =========== + + If below fermi we try to create a hole, + If above fermi we try to remove a particle. + + If general index p we return ``Kronecker(p,i)*self`` + where ``i`` is a new symbol with restriction above or below. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.secondquant import FKet + >>> a = Symbol('a', above_fermi=True) + >>> i = Symbol('i', below_fermi=True) + >>> p = Symbol('p') + + An annihilator acting on vacuum above fermi vanishes + + >>> FKet([]).down(a) + 0 + + Also below fermi, it vanishes, unless we specify a fermi level > 0 + + >>> FKet([]).down(i) + 0 + >>> FKet([],4).down(i) + FockStateFermionKet((i,)) + + """ + present = i in self.args[0] + + if self._only_above_fermi(i): + if present: + return self._remove_orbit(i) + else: + return S.Zero + + elif self._only_below_fermi(i): + if present: + return S.Zero + else: + return self._add_orbit(i) + else: + if present: + hole = Dummy("i", below_fermi=True) + return KroneckerDelta(i, hole)*self._add_orbit(i) + else: + particle = Dummy("a", above_fermi=True) + return KroneckerDelta(i, particle)*self._remove_orbit(i) + + @classmethod + def _only_below_fermi(cls, i): + """ + Tests if given orbit is only below fermi surface. + + If nothing can be concluded we return a conservative False. + """ + if i.is_number: + return i <= cls.fermi_level + if i.assumptions0.get('below_fermi'): + return True + return False + + @classmethod + def _only_above_fermi(cls, i): + """ + Tests if given orbit is only above fermi surface. + + If fermi level has not been set we return True. + If nothing can be concluded we return a conservative False. + """ + if i.is_number: + return i > cls.fermi_level + if i.assumptions0.get('above_fermi'): + return True + return not cls.fermi_level + + def _remove_orbit(self, i): + """ + Removes particle/fills hole in orbit i. No input tests performed here. + """ + new_occs = list(self.args[0]) + pos = new_occs.index(i) + del new_occs[pos] + if (pos) % 2: + return S.NegativeOne*self.__class__(new_occs, self.fermi_level) + else: + return self.__class__(new_occs, self.fermi_level) + + def _add_orbit(self, i): + """ + Adds particle/creates hole in orbit i. No input tests performed here. + """ + return self.__class__((i,) + self.args[0], self.fermi_level) + + @classmethod + def _count_holes(cls, occupations): + """ + Returns the number of identified hole states in occupations list. + """ + return len([i for i in occupations if cls._only_below_fermi(i)]) + + def _negate_holes(self, occupations): + """ + Returns the occupations list where states below the fermi level have negative labels. + + For symbolic state labels, no sign is included. + """ + return tuple([-i if self._only_below_fermi(i) and i.is_number else i for i in occupations]) + + def __repr__(self): + if self.fermi_level: + return "FockStateKet(%r, fermi_level=%s)" % (self.args[0], self.fermi_level) + else: + return "FockStateKet(%r)" % (self.args[0],) + + def _labels(self): + return self._negate_holes(self.args[0]) + + +class FockStateKet(FockState): + """ + Representation of a ket. + """ + lbracket = '|' + rbracket = '>' + lbracket_latex = r'\left|' + rbracket_latex = r'\right\rangle' + + +class FockStateBra(FockState): + """ + Representation of a bra. + """ + lbracket = '<' + rbracket = '|' + lbracket_latex = r'\left\langle' + rbracket_latex = r'\right|' + + def __mul__(self, other): + if isinstance(other, FockStateKet): + return InnerProduct(self, other) + else: + return Expr.__mul__(self, other) + + +class FockStateBosonKet(BosonState, FockStateKet): + """ + Many particle Fock state with a sequence of occupation numbers. + + Occupation numbers can be any integer >= 0. + + Examples + ======== + + >>> from sympy.physics.secondquant import BKet + >>> BKet([1, 2]) + FockStateBosonKet((1, 2)) + """ + def _dagger_(self): + return FockStateBosonBra(*self.args) + + +class FockStateBosonBra(BosonState, FockStateBra): + """ + Describes a collection of BosonBra particles. + + Examples + ======== + + >>> from sympy.physics.secondquant import BBra + >>> BBra([1, 2]) + FockStateBosonBra((1, 2)) + """ + def _dagger_(self): + return FockStateBosonKet(*self.args) + + +class FockStateFermionKet(FermionState, FockStateKet): + """ + Many-particle Fock state with a sequence of occupied orbits. + + Explanation + =========== + + Each state can only have one particle, so we choose to store a list of + occupied orbits rather than a tuple with occupation numbers (zeros and ones). + + states below fermi level are holes, and are represented by negative labels + in the occupation list. + + For symbolic state labels, the fermi_level caps the number of allowed hole- + states. + + Examples + ======== + + >>> from sympy.physics.secondquant import FKet + >>> FKet([1, 2]) + FockStateFermionKet((1, 2)) + """ + def _dagger_(self): + return FockStateFermionBra(*self.args) + + +class FockStateFermionBra(FermionState, FockStateBra): + """ + See Also + ======== + + FockStateFermionKet + + Examples + ======== + + >>> from sympy.physics.secondquant import FBra + >>> FBra([1, 2]) + FockStateFermionBra((1, 2)) + """ + def _dagger_(self): + return FockStateFermionKet(*self.args) + +BBra = FockStateBosonBra +BKet = FockStateBosonKet +FBra = FockStateFermionBra +FKet = FockStateFermionKet + + +def _apply_Mul(m): + """ + Take a Mul instance with operators and apply them to states. + + Explanation + =========== + + This method applies all operators with integer state labels + to the actual states. For symbolic state labels, nothing is done. + When inner products of FockStates are encountered (like ), + they are converted to instances of InnerProduct. + + This does not currently work on double inner products like, + . + + If the argument is not a Mul, it is simply returned as is. + """ + if not isinstance(m, Mul): + return m + c_part, nc_part = m.args_cnc() + n_nc = len(nc_part) + if n_nc in (0, 1): + return m + else: + last = nc_part[-1] + next_to_last = nc_part[-2] + if isinstance(last, FockStateKet): + if isinstance(next_to_last, SqOperator): + if next_to_last.is_symbolic: + return m + else: + result = next_to_last.apply_operator(last) + if result == 0: + return S.Zero + else: + return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) + elif isinstance(next_to_last, Pow): + if isinstance(next_to_last.base, SqOperator) and \ + next_to_last.exp.is_Integer: + if next_to_last.base.is_symbolic: + return m + else: + result = last + for i in range(next_to_last.exp): + result = next_to_last.base.apply_operator(result) + if result == 0: + break + if result == 0: + return S.Zero + else: + return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) + else: + return m + elif isinstance(next_to_last, FockStateBra): + result = InnerProduct(next_to_last, last) + if result == 0: + return S.Zero + else: + return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) + else: + return m + else: + return m + + +def apply_operators(e): + """ + Take a SymPy expression with operators and states and apply the operators. + + Examples + ======== + + >>> from sympy.physics.secondquant import apply_operators + >>> from sympy import sympify + >>> apply_operators(sympify(3)+4) + 7 + """ + e = e.expand() + muls = e.atoms(Mul) + subs_list = [(m, _apply_Mul(m)) for m in iter(muls)] + return e.subs(subs_list) + + +class InnerProduct(Basic): + """ + An unevaluated inner product between a bra and ket. + + Explanation + =========== + + Currently this class just reduces things to a product of + Kronecker Deltas. In the future, we could introduce abstract + states like ``|a>`` and ``|b>``, and leave the inner product unevaluated as + ````. + + """ + is_commutative = True + + def __new__(cls, bra, ket): + if not isinstance(bra, FockStateBra): + raise TypeError("must be a bra") + if not isinstance(ket, FockStateKet): + raise TypeError("must be a ket") + return cls.eval(bra, ket) + + @classmethod + def eval(cls, bra, ket): + result = S.One + for i, j in zip(bra.args[0], ket.args[0]): + result *= KroneckerDelta(i, j) + if result == 0: + break + return result + + @property + def bra(self): + """Returns the bra part of the state""" + return self.args[0] + + @property + def ket(self): + """Returns the ket part of the state""" + return self.args[1] + + def __repr__(self): + sbra = repr(self.bra) + sket = repr(self.ket) + return "%s|%s" % (sbra[:-1], sket[1:]) + + def __str__(self): + return self.__repr__() + + +def matrix_rep(op, basis): + """ + Find the representation of an operator in a basis. + + Examples + ======== + + >>> from sympy.physics.secondquant import VarBosonicBasis, B, matrix_rep + >>> b = VarBosonicBasis(5) + >>> o = B(0) + >>> matrix_rep(o, b) + Matrix([ + [0, 1, 0, 0, 0], + [0, 0, sqrt(2), 0, 0], + [0, 0, 0, sqrt(3), 0], + [0, 0, 0, 0, 2], + [0, 0, 0, 0, 0]]) + """ + a = zeros(len(basis)) + for i in range(len(basis)): + for j in range(len(basis)): + a[i, j] = apply_operators(Dagger(basis[i])*op*basis[j]) + return a + + +class BosonicBasis: + """ + Base class for a basis set of bosonic Fock states. + """ + pass + + +class VarBosonicBasis: + """ + A single state, variable particle number basis set. + + Examples + ======== + + >>> from sympy.physics.secondquant import VarBosonicBasis + >>> b = VarBosonicBasis(5) + >>> b + [FockState((0,)), FockState((1,)), FockState((2,)), + FockState((3,)), FockState((4,))] + """ + + def __init__(self, n_max): + self.n_max = n_max + self._build_states() + + def _build_states(self): + self.basis = [] + for i in range(self.n_max): + self.basis.append(FockStateBosonKet([i])) + self.n_basis = len(self.basis) + + def index(self, state): + """ + Returns the index of state in basis. + + Examples + ======== + + >>> from sympy.physics.secondquant import VarBosonicBasis + >>> b = VarBosonicBasis(3) + >>> state = b.state(1) + >>> b + [FockState((0,)), FockState((1,)), FockState((2,))] + >>> state + FockStateBosonKet((1,)) + >>> b.index(state) + 1 + """ + return self.basis.index(state) + + def state(self, i): + """ + The state of a single basis. + + Examples + ======== + + >>> from sympy.physics.secondquant import VarBosonicBasis + >>> b = VarBosonicBasis(5) + >>> b.state(3) + FockStateBosonKet((3,)) + """ + return self.basis[i] + + def __getitem__(self, i): + return self.state(i) + + def __len__(self): + return len(self.basis) + + def __repr__(self): + return repr(self.basis) + + +class FixedBosonicBasis(BosonicBasis): + """ + Fixed particle number basis set. + + Examples + ======== + + >>> from sympy.physics.secondquant import FixedBosonicBasis + >>> b = FixedBosonicBasis(2, 2) + >>> state = b.state(1) + >>> b + [FockState((2, 0)), FockState((1, 1)), FockState((0, 2))] + >>> state + FockStateBosonKet((1, 1)) + >>> b.index(state) + 1 + """ + def __init__(self, n_particles, n_levels): + self.n_particles = n_particles + self.n_levels = n_levels + self._build_particle_locations() + self._build_states() + + def _build_particle_locations(self): + tup = ["i%i" % i for i in range(self.n_particles)] + first_loop = "for i0 in range(%i)" % self.n_levels + other_loops = '' + for cur, prev in zip(tup[1:], tup): + temp = "for %s in range(%s + 1) " % (cur, prev) + other_loops = other_loops + temp + tup_string = "(%s)" % ", ".join(tup) + list_comp = "[%s %s %s]" % (tup_string, first_loop, other_loops) + result = eval(list_comp) + if self.n_particles == 1: + result = [(item,) for item in result] + self.particle_locations = result + + def _build_states(self): + self.basis = [] + for tuple_of_indices in self.particle_locations: + occ_numbers = self.n_levels*[0] + for level in tuple_of_indices: + occ_numbers[level] += 1 + self.basis.append(FockStateBosonKet(occ_numbers)) + self.n_basis = len(self.basis) + + def index(self, state): + """Returns the index of state in basis. + + Examples + ======== + + >>> from sympy.physics.secondquant import FixedBosonicBasis + >>> b = FixedBosonicBasis(2, 3) + >>> b.index(b.state(3)) + 3 + """ + return self.basis.index(state) + + def state(self, i): + """Returns the state that lies at index i of the basis + + Examples + ======== + + >>> from sympy.physics.secondquant import FixedBosonicBasis + >>> b = FixedBosonicBasis(2, 3) + >>> b.state(3) + FockStateBosonKet((1, 0, 1)) + """ + return self.basis[i] + + def __getitem__(self, i): + return self.state(i) + + def __len__(self): + return len(self.basis) + + def __repr__(self): + return repr(self.basis) + + +class Commutator(Function): + """ + The Commutator: [A, B] = A*B - B*A + + The arguments are ordered according to .__cmp__() + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import Commutator + >>> A, B = symbols('A,B', commutative=False) + >>> Commutator(B, A) + -Commutator(A, B) + + Evaluate the commutator with .doit() + + >>> comm = Commutator(A,B); comm + Commutator(A, B) + >>> comm.doit() + A*B - B*A + + + For two second quantization operators the commutator is evaluated + immediately: + + >>> from sympy.physics.secondquant import Fd, F + >>> a = symbols('a', above_fermi=True) + >>> i = symbols('i', below_fermi=True) + >>> p,q = symbols('p,q') + + >>> Commutator(Fd(a),Fd(i)) + 2*NO(CreateFermion(a)*CreateFermion(i)) + + But for more complicated expressions, the evaluation is triggered by + a call to .doit() + + >>> comm = Commutator(Fd(p)*Fd(q),F(i)); comm + Commutator(CreateFermion(p)*CreateFermion(q), AnnihilateFermion(i)) + >>> comm.doit(wicks=True) + -KroneckerDelta(i, p)*CreateFermion(q) + + KroneckerDelta(i, q)*CreateFermion(p) + + """ + + is_commutative = False + + @classmethod + def eval(cls, a, b): + """ + The Commutator [A,B] is on canonical form if A < B. + + Examples + ======== + + >>> from sympy.physics.secondquant import Commutator, F, Fd + >>> from sympy.abc import x + >>> c1 = Commutator(F(x), Fd(x)) + >>> c2 = Commutator(Fd(x), F(x)) + >>> Commutator.eval(c1, c2) + 0 + """ + if not (a and b): + return S.Zero + if a == b: + return S.Zero + if a.is_commutative or b.is_commutative: + return S.Zero + + # + # [A+B,C] -> [A,C] + [B,C] + # + a = a.expand() + if isinstance(a, Add): + return Add(*[cls(term, b) for term in a.args]) + b = b.expand() + if isinstance(b, Add): + return Add(*[cls(a, term) for term in b.args]) + + # + # [xA,yB] -> xy*[A,B] + # + ca, nca = a.args_cnc() + cb, ncb = b.args_cnc() + c_part = list(ca) + list(cb) + if c_part: + return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb))) + + # + # single second quantization operators + # + if isinstance(a, BosonicOperator) and isinstance(b, BosonicOperator): + if isinstance(b, CreateBoson) and isinstance(a, AnnihilateBoson): + return KroneckerDelta(a.state, b.state) + if isinstance(a, CreateBoson) and isinstance(b, AnnihilateBoson): + return S.NegativeOne*KroneckerDelta(a.state, b.state) + else: + return S.Zero + if isinstance(a, FermionicOperator) and isinstance(b, FermionicOperator): + return wicks(a*b) - wicks(b*a) + + # + # Canonical ordering of arguments + # + if a.sort_key() > b.sort_key(): + return S.NegativeOne*cls(b, a) + + def doit(self, **hints): + """ + Enables the computation of complex expressions. + + Examples + ======== + + >>> from sympy.physics.secondquant import Commutator, F, Fd + >>> from sympy import symbols + >>> i, j = symbols('i,j', below_fermi=True) + >>> a, b = symbols('a,b', above_fermi=True) + >>> c = Commutator(Fd(a)*F(i),Fd(b)*F(j)) + >>> c.doit(wicks=True) + 0 + """ + a = self.args[0] + b = self.args[1] + + if hints.get("wicks"): + a = a.doit(**hints) + b = b.doit(**hints) + try: + return wicks(a*b) - wicks(b*a) + except ContractionAppliesOnlyToFermions: + pass + except WicksTheoremDoesNotApply: + pass + + return (a*b - b*a).doit(**hints) + + def __repr__(self): + return "Commutator(%s,%s)" % (self.args[0], self.args[1]) + + def __str__(self): + return "[%s,%s]" % (self.args[0], self.args[1]) + + def _latex(self, printer): + return "\\left[%s,%s\\right]" % tuple([ + printer._print(arg) for arg in self.args]) + + +class NO(Expr): + """ + This Object is used to represent normal ordering brackets. + + i.e. {abcd} sometimes written :abcd: + + Explanation + =========== + + Applying the function NO(arg) to an argument means that all operators in + the argument will be assumed to anticommute, and have vanishing + contractions. This allows an immediate reordering to canonical form + upon object creation. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import NO, F, Fd + >>> p,q = symbols('p,q') + >>> NO(Fd(p)*F(q)) + NO(CreateFermion(p)*AnnihilateFermion(q)) + >>> NO(F(q)*Fd(p)) + -NO(CreateFermion(p)*AnnihilateFermion(q)) + + + Note + ==== + + If you want to generate a normal ordered equivalent of an expression, you + should use the function wicks(). This class only indicates that all + operators inside the brackets anticommute, and have vanishing contractions. + Nothing more, nothing less. + + """ + is_commutative = False + + def __new__(cls, arg): + """ + Use anticommutation to get canonical form of operators. + + Explanation + =========== + + Employ associativity of normal ordered product: {ab{cd}} = {abcd} + but note that {ab}{cd} /= {abcd}. + + We also employ distributivity: {ab + cd} = {ab} + {cd}. + + Canonical form also implies expand() {ab(c+d)} = {abc} + {abd}. + + """ + + # {ab + cd} = {ab} + {cd} + arg = sympify(arg) + arg = arg.expand() + if arg.is_Add: + return Add(*[ cls(term) for term in arg.args]) + + if arg.is_Mul: + + # take coefficient outside of normal ordering brackets + c_part, seq = arg.args_cnc() + if c_part: + coeff = Mul(*c_part) + if not seq: + return coeff + else: + coeff = S.One + + # {ab{cd}} = {abcd} + newseq = [] + foundit = False + for fac in seq: + if isinstance(fac, NO): + newseq.extend(fac.args) + foundit = True + else: + newseq.append(fac) + if foundit: + return coeff*cls(Mul(*newseq)) + + # We assume that the user don't mix B and F operators + if isinstance(seq[0], BosonicOperator): + raise NotImplementedError + + try: + newseq, sign = _sort_anticommuting_fermions(seq) + except ViolationOfPauliPrinciple: + return S.Zero + + if sign % 2: + return (S.NegativeOne*coeff)*cls(Mul(*newseq)) + elif sign: + return coeff*cls(Mul(*newseq)) + else: + pass # since sign==0, no permutations was necessary + + # if we couldn't do anything with Mul object, we just + # mark it as normal ordered + if coeff != S.One: + return coeff*cls(Mul(*newseq)) + return Expr.__new__(cls, Mul(*newseq)) + + if isinstance(arg, NO): + return arg + + # if object was not Mul or Add, normal ordering does not apply + return arg + + @property + def has_q_creators(self): + """ + Return 0 if the leftmost argument of the first argument is a not a + q_creator, else 1 if it is above fermi or -1 if it is below fermi. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import NO, F, Fd + + >>> a = symbols('a', above_fermi=True) + >>> i = symbols('i', below_fermi=True) + >>> NO(Fd(a)*Fd(i)).has_q_creators + 1 + >>> NO(F(i)*F(a)).has_q_creators + -1 + >>> NO(Fd(i)*F(a)).has_q_creators #doctest: +SKIP + 0 + + """ + return self.args[0].args[0].is_q_creator + + @property + def has_q_annihilators(self): + """ + Return 0 if the rightmost argument of the first argument is a not a + q_annihilator, else 1 if it is above fermi or -1 if it is below fermi. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import NO, F, Fd + + >>> a = symbols('a', above_fermi=True) + >>> i = symbols('i', below_fermi=True) + >>> NO(Fd(a)*Fd(i)).has_q_annihilators + -1 + >>> NO(F(i)*F(a)).has_q_annihilators + 1 + >>> NO(Fd(a)*F(i)).has_q_annihilators + 0 + + """ + return self.args[0].args[-1].is_q_annihilator + + def doit(self, **hints): + """ + Either removes the brackets or enables complex computations + in its arguments. + + Examples + ======== + + >>> from sympy.physics.secondquant import NO, Fd, F + >>> from textwrap import fill + >>> from sympy import symbols, Dummy + >>> p,q = symbols('p,q', cls=Dummy) + >>> print(fill(str(NO(Fd(p)*F(q)).doit()))) + KroneckerDelta(_a, _p)*KroneckerDelta(_a, + _q)*CreateFermion(_a)*AnnihilateFermion(_a) + KroneckerDelta(_a, + _p)*KroneckerDelta(_i, _q)*CreateFermion(_a)*AnnihilateFermion(_i) - + KroneckerDelta(_a, _q)*KroneckerDelta(_i, + _p)*AnnihilateFermion(_a)*CreateFermion(_i) - KroneckerDelta(_i, + _p)*KroneckerDelta(_i, _q)*AnnihilateFermion(_i)*CreateFermion(_i) + """ + if hints.get("remove_brackets", True): + return self._remove_brackets() + else: + return self.__new__(type(self), self.args[0].doit(**hints)) + + def _remove_brackets(self): + """ + Returns the sorted string without normal order brackets. + + The returned string have the property that no nonzero + contractions exist. + """ + + # check if any creator is also an annihilator + subslist = [] + for i in self.iter_q_creators(): + if self[i].is_q_annihilator: + assume = self[i].state.assumptions0 + + # only operators with a dummy index can be split in two terms + if isinstance(self[i].state, Dummy): + + # create indices with fermi restriction + assume.pop("above_fermi", None) + assume["below_fermi"] = True + below = Dummy('i', **assume) + assume.pop("below_fermi", None) + assume["above_fermi"] = True + above = Dummy('a', **assume) + + cls = type(self[i]) + split = ( + self[i].__new__(cls, below) + * KroneckerDelta(below, self[i].state) + + self[i].__new__(cls, above) + * KroneckerDelta(above, self[i].state) + ) + subslist.append((self[i], split)) + else: + raise SubstitutionOfAmbigousOperatorFailed(self[i]) + if subslist: + result = NO(self.subs(subslist)) + if isinstance(result, Add): + return Add(*[term.doit() for term in result.args]) + else: + return self.args[0] + + def _expand_operators(self): + """ + Returns a sum of NO objects that contain no ambiguous q-operators. + + Explanation + =========== + + If an index q has range both above and below fermi, the operator F(q) + is ambiguous in the sense that it can be both a q-creator and a q-annihilator. + If q is dummy, it is assumed to be a summation variable and this method + rewrites it into a sum of NO terms with unambiguous operators: + + {Fd(p)*F(q)} = {Fd(a)*F(b)} + {Fd(a)*F(i)} + {Fd(j)*F(b)} -{F(i)*Fd(j)} + + where a,b are above and i,j are below fermi level. + """ + return NO(self._remove_brackets) + + def __getitem__(self, i): + if isinstance(i, slice): + indices = i.indices(len(self)) + return [self.args[0].args[i] for i in range(*indices)] + else: + return self.args[0].args[i] + + def __len__(self): + return len(self.args[0].args) + + def iter_q_annihilators(self): + """ + Iterates over the annihilation operators. + + Examples + ======== + + >>> from sympy import symbols + >>> i, j = symbols('i j', below_fermi=True) + >>> a, b = symbols('a b', above_fermi=True) + >>> from sympy.physics.secondquant import NO, F, Fd + >>> no = NO(Fd(a)*F(i)*F(b)*Fd(j)) + + >>> no.iter_q_creators() + + >>> list(no.iter_q_creators()) + [0, 1] + >>> list(no.iter_q_annihilators()) + [3, 2] + + """ + ops = self.args[0].args + iter = range(len(ops) - 1, -1, -1) + for i in iter: + if ops[i].is_q_annihilator: + yield i + else: + break + + def iter_q_creators(self): + """ + Iterates over the creation operators. + + Examples + ======== + + >>> from sympy import symbols + >>> i, j = symbols('i j', below_fermi=True) + >>> a, b = symbols('a b', above_fermi=True) + >>> from sympy.physics.secondquant import NO, F, Fd + >>> no = NO(Fd(a)*F(i)*F(b)*Fd(j)) + + >>> no.iter_q_creators() + + >>> list(no.iter_q_creators()) + [0, 1] + >>> list(no.iter_q_annihilators()) + [3, 2] + + """ + + ops = self.args[0].args + iter = range(0, len(ops)) + for i in iter: + if ops[i].is_q_creator: + yield i + else: + break + + def get_subNO(self, i): + """ + Returns a NO() without FermionicOperator at index i. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import F, NO + >>> p, q, r = symbols('p,q,r') + + >>> NO(F(p)*F(q)*F(r)).get_subNO(1) + NO(AnnihilateFermion(p)*AnnihilateFermion(r)) + + """ + arg0 = self.args[0] # it's a Mul by definition of how it's created + mul = arg0._new_rawargs(*(arg0.args[:i] + arg0.args[i + 1:])) + return NO(mul) + + def _latex(self, printer): + return "\\left\\{%s\\right\\}" % printer._print(self.args[0]) + + def __repr__(self): + return "NO(%s)" % self.args[0] + + def __str__(self): + return ":%s:" % self.args[0] + + +def contraction(a, b): + """ + Calculates contraction of Fermionic operators a and b. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.secondquant import F, Fd, contraction + >>> p, q = symbols('p,q') + >>> a, b = symbols('a,b', above_fermi=True) + >>> i, j = symbols('i,j', below_fermi=True) + + A contraction is non-zero only if a quasi-creator is to the right of a + quasi-annihilator: + + >>> contraction(F(a),Fd(b)) + KroneckerDelta(a, b) + >>> contraction(Fd(i),F(j)) + KroneckerDelta(i, j) + + For general indices a non-zero result restricts the indices to below/above + the fermi surface: + + >>> contraction(Fd(p),F(q)) + KroneckerDelta(_i, q)*KroneckerDelta(p, q) + >>> contraction(F(p),Fd(q)) + KroneckerDelta(_a, q)*KroneckerDelta(p, q) + + Two creators or two annihilators always vanishes: + + >>> contraction(F(p),F(q)) + 0 + >>> contraction(Fd(p),Fd(q)) + 0 + + """ + if isinstance(b, FermionicOperator) and isinstance(a, FermionicOperator): + if isinstance(a, AnnihilateFermion) and isinstance(b, CreateFermion): + if b.state.assumptions0.get("below_fermi"): + return S.Zero + if a.state.assumptions0.get("below_fermi"): + return S.Zero + if b.state.assumptions0.get("above_fermi"): + return KroneckerDelta(a.state, b.state) + if a.state.assumptions0.get("above_fermi"): + return KroneckerDelta(a.state, b.state) + + return (KroneckerDelta(a.state, b.state)* + KroneckerDelta(b.state, Dummy('a', above_fermi=True))) + if isinstance(b, AnnihilateFermion) and isinstance(a, CreateFermion): + if b.state.assumptions0.get("above_fermi"): + return S.Zero + if a.state.assumptions0.get("above_fermi"): + return S.Zero + if b.state.assumptions0.get("below_fermi"): + return KroneckerDelta(a.state, b.state) + if a.state.assumptions0.get("below_fermi"): + return KroneckerDelta(a.state, b.state) + + return (KroneckerDelta(a.state, b.state)* + KroneckerDelta(b.state, Dummy('i', below_fermi=True))) + + # vanish if 2xAnnihilator or 2xCreator + return S.Zero + + else: + #not fermion operators + t = ( isinstance(i, FermionicOperator) for i in (a, b) ) + raise ContractionAppliesOnlyToFermions(*t) + + +def _sqkey_operator(sq_operator): + """Generates key for canonical sorting of SQ operators.""" + return sq_operator._sortkey() + +def _sqkey_index(index): + """Key for sorting of indices. + + particle < hole < general + + FIXME: This is a bottle-neck, can we do it faster? + """ + h = hash(index) + label = str(index) + if isinstance(index, Dummy): + if index.assumptions0.get('above_fermi'): + return (20, label, h) + elif index.assumptions0.get('below_fermi'): + return (21, label, h) + else: + return (22, label, h) + + if index.assumptions0.get('above_fermi'): + return (10, label, h) + elif index.assumptions0.get('below_fermi'): + return (11, label, h) + else: + return (12, label, h) + + + +def _sort_anticommuting_fermions(string1, key=_sqkey_operator): + """Sort fermionic operators to canonical order, assuming all pairs anticommute. + + Explanation + =========== + + Uses a bidirectional bubble sort. Items in string1 are not referenced + so in principle they may be any comparable objects. The sorting depends on the + operators '>' and '=='. + + If the Pauli principle is violated, an exception is raised. + + Returns + ======= + + tuple (sorted_str, sign) + + sorted_str: list containing the sorted operators + sign: int telling how many times the sign should be changed + (if sign==0 the string was already sorted) + """ + + verified = False + sign = 0 + rng = list(range(len(string1) - 1)) + rev = list(range(len(string1) - 3, -1, -1)) + + keys = list(map(key, string1)) + key_val = dict(list(zip(keys, string1))) + + while not verified: + verified = True + for i in rng: + left = keys[i] + right = keys[i + 1] + if left == right: + raise ViolationOfPauliPrinciple([left, right]) + if left > right: + verified = False + keys[i:i + 2] = [right, left] + sign = sign + 1 + if verified: + break + for i in rev: + left = keys[i] + right = keys[i + 1] + if left == right: + raise ViolationOfPauliPrinciple([left, right]) + if left > right: + verified = False + keys[i:i + 2] = [right, left] + sign = sign + 1 + string1 = [ key_val[k] for k in keys ] + return (string1, sign) + + +def evaluate_deltas(e): + """ + We evaluate KroneckerDelta symbols in the expression assuming Einstein summation. + + Explanation + =========== + + If one index is repeated it is summed over and in effect substituted with + the other one. If both indices are repeated we substitute according to what + is the preferred index. this is determined by + KroneckerDelta.preferred_index and KroneckerDelta.killable_index. + + In case there are no possible substitutions or if a substitution would + imply a loss of information, nothing is done. + + In case an index appears in more than one KroneckerDelta, the resulting + substitution depends on the order of the factors. Since the ordering is platform + dependent, the literal expression resulting from this function may be hard to + predict. + + Examples + ======== + + We assume the following: + + >>> from sympy import symbols, Function, Dummy, KroneckerDelta + >>> from sympy.physics.secondquant import evaluate_deltas + >>> i,j = symbols('i j', below_fermi=True, cls=Dummy) + >>> a,b = symbols('a b', above_fermi=True, cls=Dummy) + >>> p,q = symbols('p q', cls=Dummy) + >>> f = Function('f') + >>> t = Function('t') + + The order of preference for these indices according to KroneckerDelta is + (a, b, i, j, p, q). + + Trivial cases: + + >>> evaluate_deltas(KroneckerDelta(i,j)*f(i)) # d_ij f(i) -> f(j) + f(_j) + >>> evaluate_deltas(KroneckerDelta(i,j)*f(j)) # d_ij f(j) -> f(i) + f(_i) + >>> evaluate_deltas(KroneckerDelta(i,p)*f(p)) # d_ip f(p) -> f(i) + f(_i) + >>> evaluate_deltas(KroneckerDelta(q,p)*f(p)) # d_qp f(p) -> f(q) + f(_q) + >>> evaluate_deltas(KroneckerDelta(q,p)*f(q)) # d_qp f(q) -> f(p) + f(_p) + + More interesting cases: + + >>> evaluate_deltas(KroneckerDelta(i,p)*t(a,i)*f(p,q)) + f(_i, _q)*t(_a, _i) + >>> evaluate_deltas(KroneckerDelta(a,p)*t(a,i)*f(p,q)) + f(_a, _q)*t(_a, _i) + >>> evaluate_deltas(KroneckerDelta(p,q)*f(p,q)) + f(_p, _p) + + Finally, here are some cases where nothing is done, because that would + imply a loss of information: + + >>> evaluate_deltas(KroneckerDelta(i,p)*f(q)) + f(_q)*KroneckerDelta(_i, _p) + >>> evaluate_deltas(KroneckerDelta(i,p)*f(i)) + f(_i)*KroneckerDelta(_i, _p) + """ + + # We treat Deltas only in mul objects + # for general function objects we don't evaluate KroneckerDeltas in arguments, + # but here we hard code exceptions to this rule + accepted_functions = ( + Add, + ) + if isinstance(e, accepted_functions): + return e.func(*[evaluate_deltas(arg) for arg in e.args]) + + elif isinstance(e, Mul): + # find all occurrences of delta function and count each index present in + # expression. + deltas = [] + indices = {} + for i in e.args: + for s in i.free_symbols: + if s in indices: + indices[s] += 1 + else: + indices[s] = 0 # geek counting simplifies logic below + if isinstance(i, KroneckerDelta): + deltas.append(i) + + for d in deltas: + # If we do something, and there are more deltas, we should recurse + # to treat the resulting expression properly + if d.killable_index.is_Symbol and indices[d.killable_index]: + e = e.subs(d.killable_index, d.preferred_index) + if len(deltas) > 1: + return evaluate_deltas(e) + elif (d.preferred_index.is_Symbol and indices[d.preferred_index] + and d.indices_contain_equal_information): + e = e.subs(d.preferred_index, d.killable_index) + if len(deltas) > 1: + return evaluate_deltas(e) + else: + pass + + return e + # nothing to do, maybe we hit a Symbol or a number + else: + return e + + +def substitute_dummies(expr, new_indices=False, pretty_indices={}): + """ + Collect terms by substitution of dummy variables. + + Explanation + =========== + + This routine allows simplification of Add expressions containing terms + which differ only due to dummy variables. + + The idea is to substitute all dummy variables consistently depending on + the structure of the term. For each term, we obtain a sequence of all + dummy variables, where the order is determined by the index range, what + factors the index belongs to and its position in each factor. See + _get_ordered_dummies() for more information about the sorting of dummies. + The index sequence is then substituted consistently in each term. + + Examples + ======== + + >>> from sympy import symbols, Function, Dummy + >>> from sympy.physics.secondquant import substitute_dummies + >>> a,b,c,d = symbols('a b c d', above_fermi=True, cls=Dummy) + >>> i,j = symbols('i j', below_fermi=True, cls=Dummy) + >>> f = Function('f') + + >>> expr = f(a,b) + f(c,d); expr + f(_a, _b) + f(_c, _d) + + Since a, b, c and d are equivalent summation indices, the expression can be + simplified to a single term (for which the dummy indices are still summed over) + + >>> substitute_dummies(expr) + 2*f(_a, _b) + + + Controlling output: + + By default the dummy symbols that are already present in the expression + will be reused in a different permutation. However, if new_indices=True, + new dummies will be generated and inserted. The keyword 'pretty_indices' + can be used to control this generation of new symbols. + + By default the new dummies will be generated on the form i_1, i_2, a_1, + etc. If you supply a dictionary with key:value pairs in the form: + + { index_group: string_of_letters } + + The letters will be used as labels for the new dummy symbols. The + index_groups must be one of 'above', 'below' or 'general'. + + >>> expr = f(a,b,i,j) + >>> my_dummies = { 'above':'st', 'below':'uv' } + >>> substitute_dummies(expr, new_indices=True, pretty_indices=my_dummies) + f(_s, _t, _u, _v) + + If we run out of letters, or if there is no keyword for some index_group + the default dummy generator will be used as a fallback: + + >>> p,q = symbols('p q', cls=Dummy) # general indices + >>> expr = f(p,q) + >>> substitute_dummies(expr, new_indices=True, pretty_indices=my_dummies) + f(_p_0, _p_1) + + """ + + # setup the replacing dummies + if new_indices: + letters_above = pretty_indices.get('above', "") + letters_below = pretty_indices.get('below', "") + letters_general = pretty_indices.get('general', "") + len_above = len(letters_above) + len_below = len(letters_below) + len_general = len(letters_general) + + def _i(number): + try: + return letters_below[number] + except IndexError: + return 'i_' + str(number - len_below) + + def _a(number): + try: + return letters_above[number] + except IndexError: + return 'a_' + str(number - len_above) + + def _p(number): + try: + return letters_general[number] + except IndexError: + return 'p_' + str(number - len_general) + + aboves = [] + belows = [] + generals = [] + + dummies = expr.atoms(Dummy) + if not new_indices: + dummies = sorted(dummies, key=default_sort_key) + + # generate lists with the dummies we will insert + a = i = p = 0 + for d in dummies: + assum = d.assumptions0 + + if assum.get("above_fermi"): + if new_indices: + sym = _a(a) + a += 1 + l1 = aboves + elif assum.get("below_fermi"): + if new_indices: + sym = _i(i) + i += 1 + l1 = belows + else: + if new_indices: + sym = _p(p) + p += 1 + l1 = generals + + if new_indices: + l1.append(Dummy(sym, **assum)) + else: + l1.append(d) + + expr = expr.expand() + terms = Add.make_args(expr) + new_terms = [] + for term in terms: + i = iter(belows) + a = iter(aboves) + p = iter(generals) + ordered = _get_ordered_dummies(term) + subsdict = {} + for d in ordered: + if d.assumptions0.get('below_fermi'): + subsdict[d] = next(i) + elif d.assumptions0.get('above_fermi'): + subsdict[d] = next(a) + else: + subsdict[d] = next(p) + subslist = [] + final_subs = [] + for k, v in subsdict.items(): + if k == v: + continue + if v in subsdict: + # We check if the sequence of substitutions end quickly. In + # that case, we can avoid temporary symbols if we ensure the + # correct substitution order. + if subsdict[v] in subsdict: + # (x, y) -> (y, x), we need a temporary variable + x = Dummy('x') + subslist.append((k, x)) + final_subs.append((x, v)) + else: + # (x, y) -> (y, a), x->y must be done last + # but before temporary variables are resolved + final_subs.insert(0, (k, v)) + else: + subslist.append((k, v)) + subslist.extend(final_subs) + new_terms.append(term.subs(subslist)) + return Add(*new_terms) + + +class KeyPrinter(StrPrinter): + """Printer for which only equal objects are equal in print""" + def _print_Dummy(self, expr): + return "(%s_%i)" % (expr.name, expr.dummy_index) + + +def __kprint(expr): + p = KeyPrinter() + return p.doprint(expr) + + +def _get_ordered_dummies(mul, verbose=False): + """Returns all dummies in the mul sorted in canonical order. + + Explanation + =========== + + The purpose of the canonical ordering is that dummies can be substituted + consistently across terms with the result that equivalent terms can be + simplified. + + It is not possible to determine if two terms are equivalent based solely on + the dummy order. However, a consistent substitution guided by the ordered + dummies should lead to trivially (non-)equivalent terms, thereby revealing + the equivalence. This also means that if two terms have identical sequences of + dummies, the (non-)equivalence should already be apparent. + + Strategy + -------- + + The canonical order is given by an arbitrary sorting rule. A sort key + is determined for each dummy as a tuple that depends on all factors where + the index is present. The dummies are thereby sorted according to the + contraction structure of the term, instead of sorting based solely on the + dummy symbol itself. + + After all dummies in the term has been assigned a key, we check for identical + keys, i.e. unorderable dummies. If any are found, we call a specialized + method, _determine_ambiguous(), that will determine a unique order based + on recursive calls to _get_ordered_dummies(). + + Key description + --------------- + + A high level description of the sort key: + + 1. Range of the dummy index + 2. Relation to external (non-dummy) indices + 3. Position of the index in the first factor + 4. Position of the index in the second factor + + The sort key is a tuple with the following components: + + 1. A single character indicating the range of the dummy (above, below + or general.) + 2. A list of strings with fully masked string representations of all + factors where the dummy is present. By masked, we mean that dummies + are represented by a symbol to indicate either below fermi, above or + general. No other information is displayed about the dummies at + this point. The list is sorted stringwise. + 3. An integer number indicating the position of the index, in the first + factor as sorted in 2. + 4. An integer number indicating the position of the index, in the second + factor as sorted in 2. + + If a factor is either of type AntiSymmetricTensor or SqOperator, the index + position in items 3 and 4 is indicated as 'upper' or 'lower' only. + (Creation operators are considered upper and annihilation operators lower.) + + If the masked factors are identical, the two factors cannot be ordered + unambiguously in item 2. In this case, items 3, 4 are left out. If several + indices are contracted between the unorderable factors, it will be handled by + _determine_ambiguous() + + + """ + # setup dicts to avoid repeated calculations in key() + args = Mul.make_args(mul) + fac_dum = { fac: fac.atoms(Dummy) for fac in args } + fac_repr = { fac: __kprint(fac) for fac in args } + all_dums = set().union(*fac_dum.values()) + mask = {} + for d in all_dums: + if d.assumptions0.get('below_fermi'): + mask[d] = '0' + elif d.assumptions0.get('above_fermi'): + mask[d] = '1' + else: + mask[d] = '2' + dum_repr = {d: __kprint(d) for d in all_dums} + + def _key(d): + dumstruct = [ fac for fac in fac_dum if d in fac_dum[fac] ] + other_dums = set().union(*[fac_dum[fac] for fac in dumstruct]) + fac = dumstruct[-1] + if other_dums is fac_dum[fac]: + other_dums = fac_dum[fac].copy() + other_dums.remove(d) + masked_facs = [ fac_repr[fac] for fac in dumstruct ] + for d2 in other_dums: + masked_facs = [ fac.replace(dum_repr[d2], mask[d2]) + for fac in masked_facs ] + all_masked = [ fac.replace(dum_repr[d], mask[d]) + for fac in masked_facs ] + masked_facs = dict(list(zip(dumstruct, masked_facs))) + + # dummies for which the ordering cannot be determined + if has_dups(all_masked): + all_masked.sort() + return mask[d], tuple(all_masked) # positions are ambiguous + + # sort factors according to fully masked strings + keydict = dict(list(zip(dumstruct, all_masked))) + dumstruct.sort(key=lambda x: keydict[x]) + all_masked.sort() + + pos_val = [] + for fac in dumstruct: + if isinstance(fac, AntiSymmetricTensor): + if d in fac.upper: + pos_val.append('u') + if d in fac.lower: + pos_val.append('l') + elif isinstance(fac, Creator): + pos_val.append('u') + elif isinstance(fac, Annihilator): + pos_val.append('l') + elif isinstance(fac, NO): + ops = [ op for op in fac if op.has(d) ] + for op in ops: + if isinstance(op, Creator): + pos_val.append('u') + else: + pos_val.append('l') + else: + # fallback to position in string representation + facpos = -1 + while 1: + facpos = masked_facs[fac].find(dum_repr[d], facpos + 1) + if facpos == -1: + break + pos_val.append(facpos) + return (mask[d], tuple(all_masked), pos_val[0], pos_val[-1]) + dumkey = dict(list(zip(all_dums, list(map(_key, all_dums))))) + result = sorted(all_dums, key=lambda x: dumkey[x]) + if has_dups(iter(dumkey.values())): + # We have ambiguities + unordered = defaultdict(set) + for d, k in dumkey.items(): + unordered[k].add(d) + for k in [ k for k in unordered if len(unordered[k]) < 2 ]: + del unordered[k] + + unordered = [ unordered[k] for k in sorted(unordered) ] + result = _determine_ambiguous(mul, result, unordered) + return result + + +def _determine_ambiguous(term, ordered, ambiguous_groups): + # We encountered a term for which the dummy substitution is ambiguous. + # This happens for terms with 2 or more contractions between factors that + # cannot be uniquely ordered independent of summation indices. For + # example: + # + # Sum(p, q) v^{p, .}_{q, .}v^{q, .}_{p, .} + # + # Assuming that the indices represented by . are dummies with the + # same range, the factors cannot be ordered, and there is no + # way to determine a consistent ordering of p and q. + # + # The strategy employed here, is to relabel all unambiguous dummies with + # non-dummy symbols and call _get_ordered_dummies again. This procedure is + # applied to the entire term so there is a possibility that + # _determine_ambiguous() is called again from a deeper recursion level. + + # break recursion if there are no ordered dummies + all_ambiguous = set() + for dummies in ambiguous_groups: + all_ambiguous |= dummies + all_ordered = set(ordered) - all_ambiguous + if not all_ordered: + # FIXME: If we arrive here, there are no ordered dummies. A method to + # handle this needs to be implemented. In order to return something + # useful nevertheless, we choose arbitrarily the first dummy and + # determine the rest from this one. This method is dependent on the + # actual dummy labels which violates an assumption for the + # canonicalization procedure. A better implementation is needed. + group = [ d for d in ordered if d in ambiguous_groups[0] ] + d = group[0] + all_ordered.add(d) + ambiguous_groups[0].remove(d) + + stored_counter = _symbol_factory._counter + subslist = [] + for d in [ d for d in ordered if d in all_ordered ]: + nondum = _symbol_factory._next() + subslist.append((d, nondum)) + newterm = term.subs(subslist) + neworder = _get_ordered_dummies(newterm) + _symbol_factory._set_counter(stored_counter) + + # update ordered list with new information + for group in ambiguous_groups: + ordered_group = [ d for d in neworder if d in group ] + ordered_group.reverse() + result = [] + for d in ordered: + if d in group: + result.append(ordered_group.pop()) + else: + result.append(d) + ordered = result + return ordered + + +class _SymbolFactory: + def __init__(self, label): + self._counterVar = 0 + self._label = label + + def _set_counter(self, value): + """ + Sets counter to value. + """ + self._counterVar = value + + @property + def _counter(self): + """ + What counter is currently at. + """ + return self._counterVar + + def _next(self): + """ + Generates the next symbols and increments counter by 1. + """ + s = Symbol("%s%i" % (self._label, self._counterVar)) + self._counterVar += 1 + return s +_symbol_factory = _SymbolFactory('_]"]_') # most certainly a unique label + + +@cacheit +def _get_contractions(string1, keep_only_fully_contracted=False): + """ + Returns Add-object with contracted terms. + + Uses recursion to find all contractions. -- Internal helper function -- + + Will find nonzero contractions in string1 between indices given in + leftrange and rightrange. + + """ + + # Should we store current level of contraction? + if keep_only_fully_contracted and string1: + result = [] + else: + result = [NO(Mul(*string1))] + + for i in range(len(string1) - 1): + for j in range(i + 1, len(string1)): + + c = contraction(string1[i], string1[j]) + + if c: + sign = (j - i + 1) % 2 + if sign: + coeff = S.NegativeOne*c + else: + coeff = c + + # + # Call next level of recursion + # ============================ + # + # We now need to find more contractions among operators + # + # oplist = string1[:i]+ string1[i+1:j] + string1[j+1:] + # + # To prevent overcounting, we don't allow contractions + # we have already encountered. i.e. contractions between + # string1[:i] <---> string1[i+1:j] + # and string1[:i] <---> string1[j+1:]. + # + # This leaves the case: + oplist = string1[i + 1:j] + string1[j + 1:] + + if oplist: + + result.append(coeff*NO( + Mul(*string1[:i])*_get_contractions( oplist, + keep_only_fully_contracted=keep_only_fully_contracted))) + + else: + result.append(coeff*NO( Mul(*string1[:i]))) + + if keep_only_fully_contracted: + break # next iteration over i leaves leftmost operator string1[0] uncontracted + + return Add(*result) + + +def wicks(e, **kw_args): + """ + Returns the normal ordered equivalent of an expression using Wicks Theorem. + + Examples + ======== + + >>> from sympy import symbols, Dummy + >>> from sympy.physics.secondquant import wicks, F, Fd + >>> p, q, r = symbols('p,q,r') + >>> wicks(Fd(p)*F(q)) + KroneckerDelta(_i, q)*KroneckerDelta(p, q) + NO(CreateFermion(p)*AnnihilateFermion(q)) + + By default, the expression is expanded: + + >>> wicks(F(p)*(F(q)+F(r))) + NO(AnnihilateFermion(p)*AnnihilateFermion(q)) + NO(AnnihilateFermion(p)*AnnihilateFermion(r)) + + With the keyword 'keep_only_fully_contracted=True', only fully contracted + terms are returned. + + By request, the result can be simplified in the following order: + -- KroneckerDelta functions are evaluated + -- Dummy variables are substituted consistently across terms + + >>> p, q, r = symbols('p q r', cls=Dummy) + >>> wicks(Fd(p)*(F(q)+F(r)), keep_only_fully_contracted=True) + KroneckerDelta(_i, _q)*KroneckerDelta(_p, _q) + KroneckerDelta(_i, _r)*KroneckerDelta(_p, _r) + + """ + + if not e: + return S.Zero + + opts = { + 'simplify_kronecker_deltas': False, + 'expand': True, + 'simplify_dummies': False, + 'keep_only_fully_contracted': False + } + opts.update(kw_args) + + # check if we are already normally ordered + if isinstance(e, NO): + if opts['keep_only_fully_contracted']: + return S.Zero + else: + return e + elif isinstance(e, FermionicOperator): + if opts['keep_only_fully_contracted']: + return S.Zero + else: + return e + + # break up any NO-objects, and evaluate commutators + e = e.doit(wicks=True) + + # make sure we have only one term to consider + e = e.expand() + if isinstance(e, Add): + if opts['simplify_dummies']: + return substitute_dummies(Add(*[ wicks(term, **kw_args) for term in e.args])) + else: + return Add(*[ wicks(term, **kw_args) for term in e.args]) + + # For Mul-objects we can actually do something + if isinstance(e, Mul): + + # we don't want to mess around with commuting part of Mul + # so we factorize it out before starting recursion + c_part = [] + string1 = [] + for factor in e.args: + if factor.is_commutative: + c_part.append(factor) + else: + string1.append(factor) + n = len(string1) + + # catch trivial cases + if n == 0: + result = e + elif n == 1: + if opts['keep_only_fully_contracted']: + return S.Zero + else: + result = e + + else: # non-trivial + + if isinstance(string1[0], BosonicOperator): + raise NotImplementedError + + string1 = tuple(string1) + + # recursion over higher order contractions + result = _get_contractions(string1, + keep_only_fully_contracted=opts['keep_only_fully_contracted'] ) + result = Mul(*c_part)*result + + if opts['expand']: + result = result.expand() + if opts['simplify_kronecker_deltas']: + result = evaluate_deltas(result) + + return result + + # there was nothing to do + return e + + +class PermutationOperator(Expr): + """ + Represents the index permutation operator P(ij). + + P(ij)*f(i)*g(j) = f(i)*g(j) - f(j)*g(i) + """ + is_commutative = True + + def __new__(cls, i, j): + i, j = sorted(map(sympify, (i, j)), key=default_sort_key) + obj = Basic.__new__(cls, i, j) + return obj + + def get_permuted(self, expr): + """ + Returns -expr with permuted indices. + + Explanation + =========== + + >>> from sympy import symbols, Function + >>> from sympy.physics.secondquant import PermutationOperator + >>> p,q = symbols('p,q') + >>> f = Function('f') + >>> PermutationOperator(p,q).get_permuted(f(p,q)) + -f(q, p) + + """ + i = self.args[0] + j = self.args[1] + if expr.has(i) and expr.has(j): + tmp = Dummy() + expr = expr.subs(i, tmp) + expr = expr.subs(j, i) + expr = expr.subs(tmp, j) + return S.NegativeOne*expr + else: + return expr + + def _latex(self, printer): + return "P(%s%s)" % tuple(printer._print(i) for i in self.args) + + +def simplify_index_permutations(expr, permutation_operators): + """ + Performs simplification by introducing PermutationOperators where appropriate. + + Explanation + =========== + + Schematically: + [abij] - [abji] - [baij] + [baji] -> P(ab)*P(ij)*[abij] + + permutation_operators is a list of PermutationOperators to consider. + + If permutation_operators=[P(ab),P(ij)] we will try to introduce the + permutation operators P(ij) and P(ab) in the expression. If there are other + possible simplifications, we ignore them. + + >>> from sympy import symbols, Function + >>> from sympy.physics.secondquant import simplify_index_permutations + >>> from sympy.physics.secondquant import PermutationOperator + >>> p,q,r,s = symbols('p,q,r,s') + >>> f = Function('f') + >>> g = Function('g') + + >>> expr = f(p)*g(q) - f(q)*g(p); expr + f(p)*g(q) - f(q)*g(p) + >>> simplify_index_permutations(expr,[PermutationOperator(p,q)]) + f(p)*g(q)*PermutationOperator(p, q) + + >>> PermutList = [PermutationOperator(p,q),PermutationOperator(r,s)] + >>> expr = f(p,r)*g(q,s) - f(q,r)*g(p,s) + f(q,s)*g(p,r) - f(p,s)*g(q,r) + >>> simplify_index_permutations(expr,PermutList) + f(p, r)*g(q, s)*PermutationOperator(p, q)*PermutationOperator(r, s) + + """ + + def _get_indices(expr, ind): + """ + Collects indices recursively in predictable order. + """ + result = [] + for arg in expr.args: + if arg in ind: + result.append(arg) + else: + if arg.args: + result.extend(_get_indices(arg, ind)) + return result + + def _choose_one_to_keep(a, b, ind): + # we keep the one where indices in ind are in order ind[0] < ind[1] + return min(a, b, key=lambda x: default_sort_key(_get_indices(x, ind))) + + expr = expr.expand() + if isinstance(expr, Add): + terms = set(expr.args) + + for P in permutation_operators: + new_terms = set() + on_hold = set() + while terms: + term = terms.pop() + permuted = P.get_permuted(term) + if permuted in terms | on_hold: + try: + terms.remove(permuted) + except KeyError: + on_hold.remove(permuted) + keep = _choose_one_to_keep(term, permuted, P.args) + new_terms.add(P*keep) + else: + + # Some terms must get a second chance because the permuted + # term may already have canonical dummy ordering. Then + # substitute_dummies() does nothing. However, the other + # term, if it exists, will be able to match with us. + permuted1 = permuted + permuted = substitute_dummies(permuted) + if permuted1 == permuted: + on_hold.add(term) + elif permuted in terms | on_hold: + try: + terms.remove(permuted) + except KeyError: + on_hold.remove(permuted) + keep = _choose_one_to_keep(term, permuted, P.args) + new_terms.add(P*keep) + else: + new_terms.add(term) + terms = new_terms | on_hold + return Add(*terms) + return expr diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/sho.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/sho.py new file mode 100644 index 0000000000000000000000000000000000000000..c55b31b3fa9fca4fa33a9f8e91c90c2174fe81a5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/sho.py @@ -0,0 +1,95 @@ +from sympy.core import S, pi, Rational +from sympy.functions import assoc_laguerre, sqrt, exp, factorial, factorial2 + + +def R_nl(n, l, nu, r): + """ + Returns the radial wavefunction R_{nl} for a 3d isotropic harmonic + oscillator. + + Parameters + ========== + + n : + The "nodal" quantum number. Corresponds to the number of nodes in + the wavefunction. ``n >= 0`` + l : + The quantum number for orbital angular momentum. + nu : + mass-scaled frequency: nu = m*omega/(2*hbar) where `m` is the mass + and `omega` the frequency of the oscillator. + (in atomic units ``nu == omega/2``) + r : + Radial coordinate. + + Examples + ======== + + >>> from sympy.physics.sho import R_nl + >>> from sympy.abc import r, nu, l + >>> R_nl(0, 0, 1, r) + 2*2**(3/4)*exp(-r**2)/pi**(1/4) + >>> R_nl(1, 0, 1, r) + 4*2**(1/4)*sqrt(3)*(3/2 - 2*r**2)*exp(-r**2)/(3*pi**(1/4)) + + l, nu and r may be symbolic: + + >>> R_nl(0, 0, nu, r) + 2*2**(3/4)*sqrt(nu**(3/2))*exp(-nu*r**2)/pi**(1/4) + >>> R_nl(0, l, 1, r) + r**l*sqrt(2**(l + 3/2)*2**(l + 2)/factorial2(2*l + 1))*exp(-r**2)/pi**(1/4) + + The normalization of the radial wavefunction is: + + >>> from sympy import Integral, oo + >>> Integral(R_nl(0, 0, 1, r)**2*r**2, (r, 0, oo)).n() + 1.00000000000000 + >>> Integral(R_nl(1, 0, 1, r)**2*r**2, (r, 0, oo)).n() + 1.00000000000000 + >>> Integral(R_nl(1, 1, 1, r)**2*r**2, (r, 0, oo)).n() + 1.00000000000000 + + """ + n, l, nu, r = map(S, [n, l, nu, r]) + + # formula uses n >= 1 (instead of nodal n >= 0) + n = n + 1 + C = sqrt( + ((2*nu)**(l + Rational(3, 2))*2**(n + l + 1)*factorial(n - 1))/ + (sqrt(pi)*(factorial2(2*n + 2*l - 1))) + ) + return C*r**(l)*exp(-nu*r**2)*assoc_laguerre(n - 1, l + S.Half, 2*nu*r**2) + + +def E_nl(n, l, hw): + """ + Returns the Energy of an isotropic harmonic oscillator. + + Parameters + ========== + + n : + The "nodal" quantum number. + l : + The orbital angular momentum. + hw : + The harmonic oscillator parameter. + + Notes + ===== + + The unit of the returned value matches the unit of hw, since the energy is + calculated as: + + E_nl = (2*n + l + 3/2)*hw + + Examples + ======== + + >>> from sympy.physics.sho import E_nl + >>> from sympy import symbols + >>> x, y, z = symbols('x, y, z') + >>> E_nl(x, y, z) + z*(2*x + y + 3/2) + """ + return (2*n + l + Rational(3, 2))*hw diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_clebsch_gordan.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_clebsch_gordan.py new file mode 100644 index 0000000000000000000000000000000000000000..e4313e3e412d6d1883efaf693c13e0f967daf9da --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_clebsch_gordan.py @@ -0,0 +1,223 @@ +from sympy.core.numbers import (I, pi, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.functions.special.spherical_harmonics import Ynm +from sympy.matrices.dense import Matrix +from sympy.physics.wigner import (clebsch_gordan, wigner_9j, wigner_6j, gaunt, + real_gaunt, racah, dot_rot_grad_Ynm, wigner_3j, wigner_d_small, wigner_d) +from sympy.testing.pytest import raises, skip + +# for test cases, refer : https://en.wikipedia.org/wiki/Table_of_Clebsch%E2%80%93Gordan_coefficients + +def test_clebsch_gordan_docs(): + assert clebsch_gordan(Rational(3, 2), S.Half, 2, Rational(3, 2), S.Half, 2) == 1 + assert clebsch_gordan(Rational(3, 2), S.Half, 1, Rational(3, 2), Rational(-1, 2), 1) == sqrt(3)/2 + assert clebsch_gordan(Rational(3, 2), S.Half, 1, Rational(-1, 2), S.Half, 0) == -sqrt(2)/2 + + +def test_clebsch_gordan(): + # Argument order: (j_1, j_2, j, m_1, m_2, m) + + h = S.One + k = S.Half + l = Rational(3, 2) + i = Rational(-1, 2) + n = Rational(7, 2) + p = Rational(5, 2) + assert clebsch_gordan(k, k, 1, k, k, 1) == 1 + assert clebsch_gordan(k, k, 1, k, k, 0) == 0 + assert clebsch_gordan(k, k, 1, i, i, -1) == 1 + assert clebsch_gordan(k, k, 1, k, i, 0) == sqrt(2)/2 + assert clebsch_gordan(k, k, 0, k, i, 0) == sqrt(2)/2 + assert clebsch_gordan(k, k, 1, i, k, 0) == sqrt(2)/2 + assert clebsch_gordan(k, k, 0, i, k, 0) == -sqrt(2)/2 + assert clebsch_gordan(h, k, l, 1, k, l) == 1 + assert clebsch_gordan(h, k, l, 1, i, k) == 1/sqrt(3) + assert clebsch_gordan(h, k, k, 1, i, k) == sqrt(2)/sqrt(3) + assert clebsch_gordan(h, k, k, 0, k, k) == -1/sqrt(3) + assert clebsch_gordan(h, k, l, 0, k, k) == sqrt(2)/sqrt(3) + assert clebsch_gordan(h, h, S(2), 1, 1, S(2)) == 1 + assert clebsch_gordan(h, h, S(2), 1, 0, 1) == 1/sqrt(2) + assert clebsch_gordan(h, h, S(2), 0, 1, 1) == 1/sqrt(2) + assert clebsch_gordan(h, h, 1, 1, 0, 1) == 1/sqrt(2) + assert clebsch_gordan(h, h, 1, 0, 1, 1) == -1/sqrt(2) + assert clebsch_gordan(l, l, S(3), l, l, S(3)) == 1 + assert clebsch_gordan(l, l, S(2), l, k, S(2)) == 1/sqrt(2) + assert clebsch_gordan(l, l, S(3), l, k, S(2)) == 1/sqrt(2) + assert clebsch_gordan(S(2), S(2), S(4), S(2), S(2), S(4)) == 1 + assert clebsch_gordan(S(2), S(2), S(3), S(2), 1, S(3)) == 1/sqrt(2) + assert clebsch_gordan(S(2), S(2), S(3), 1, 1, S(2)) == 0 + assert clebsch_gordan(p, h, n, p, 1, n) == 1 + assert clebsch_gordan(p, h, p, p, 0, p) == sqrt(5)/sqrt(7) + assert clebsch_gordan(p, h, l, k, 1, l) == 1/sqrt(15) + + +def test_clebsch_gordan_numpy(): + try: + import numpy as np + except ImportError: + skip("numpy not installed") + assert clebsch_gordan(*np.zeros(6).astype(np.int64)) == 1 + assert wigner_3j(2, np.float64(6.0), 4.0, 0, 0, 0) == sqrt(715)/143 + assert wigner_3j(0, 0.5, 0.5, 0, 0.5, -0.5) == sqrt(2)/2 + raises(ValueError, lambda: wigner_3j(2.1, 6, 4, 0, 0, 0)) + + +def test_wigner(): + try: + import numpy as np + except ImportError: + skip("numpy not installed") + def tn(a, b): + return (a - b).n(64) < S('1e-64') + assert tn(wigner_9j(1, 1, 1, 1, 1, 1, 1, 1, 0, prec=64), Rational(1, 18)) + assert wigner_9j(3, 3, 2, 3, 3, 2, 3, 3, 2) == 3221*sqrt( + 70)/(246960*sqrt(105)) - 365/(3528*sqrt(70)*sqrt(105)) + assert wigner_6j(5, 5, 5, 5, 5, 5) == Rational(1, 52) + assert tn(wigner_6j(8, 8, 8, 8, 8, 8, prec=64), Rational(-12219, 965770)) + assert wigner_6j(1, 1, 1, 1.0, np.float64(1.0), 1) == Rational(1, 6) + assert wigner_6j(3.0, np.float32(3), 3.0, 3, 3, 3) == Rational(-1, 14) + # regression test for #8747 + half = S.Half + assert wigner_9j(0, 0, 0, 0, half, half, 0, half, half) == half + assert (wigner_9j(3, 5, 4, + 7 * half, 5 * half, 4, + 9 * half, 9 * half, 0) + == -sqrt(Rational(361, 205821000))) + assert (wigner_9j(1, 4, 3, + 5 * half, 4, 5 * half, + 5 * half, 2, 7 * half) + == -sqrt(Rational(3971, 373403520))) + assert (wigner_9j(4, 9 * half, 5 * half, + 2, 4, 4, + 5, 7 * half, 7 * half) + == -sqrt(Rational(3481, 5042614500))) + assert (wigner_9j(5, 5, 5.0, + np.float64(5.0), 5, 5, + 5, 5, 5) + == 0) + assert (wigner_9j(1.0, 2.0, 3.0, + 3, 2, 1, + 2, 1, 3) + == -4*sqrt(70)/11025) + + +def test_gaunt(): + def tn(a, b): + return (a - b).n(64) < S('1e-64') + assert gaunt(1, 0, 1, 1, 0, -1) == -1/(2*sqrt(pi)) + assert isinstance(gaunt(1, 1, 0, -1, 1, 0).args[0], Rational) + assert isinstance(gaunt(0, 1, 1, 0, -1, 1).args[0], Rational) + + assert tn(gaunt( + 10, 10, 12, 9, 3, -12, prec=64), (Rational(-98, 62031)) * sqrt(6279)/sqrt(pi)) + def gaunt_ref(l1, l2, l3, m1, m2, m3): + return ( + sqrt((2 * l1 + 1) * (2 * l2 + 1) * (2 * l3 + 1) / (4 * pi)) * + wigner_3j(l1, l2, l3, 0, 0, 0) * + wigner_3j(l1, l2, l3, m1, m2, m3) + ) + threshold = 1e-10 + l_max = 3 + l3_max = 24 + for l1 in range(l_max + 1): + for l2 in range(l_max + 1): + for l3 in range(l3_max + 1): + for m1 in range(-l1, l1 + 1): + for m2 in range(-l2, l2 + 1): + for m3 in range(-l3, l3 + 1): + args = l1, l2, l3, m1, m2, m3 + g = gaunt(*args) + g0 = gaunt_ref(*args) + assert abs(g - g0) < threshold + if m1 + m2 + m3 != 0: + assert abs(g) < threshold + if (l1 + l2 + l3) % 2: + assert abs(g) < threshold + assert gaunt(1, 1, 0, 0, 2, -2) is S.Zero + + +def test_realgaunt(): + # All non-zero values corresponding to l values from 0 to 2 + for l in range(3): + for m in range(-l, l+1): + assert real_gaunt(0, l, l, 0, m, m) == 1/(2*sqrt(pi)) + assert real_gaunt(1, 1, 2, 0, 0, 0) == sqrt(5)/(5*sqrt(pi)) + assert real_gaunt(1, 1, 2, 1, 1, 0) == -sqrt(5)/(10*sqrt(pi)) + assert real_gaunt(2, 2, 2, 0, 0, 0) == sqrt(5)/(7*sqrt(pi)) + assert real_gaunt(2, 2, 2, 0, 2, 2) == -sqrt(5)/(7*sqrt(pi)) + assert real_gaunt(2, 2, 2, -2, -2, 0) == -sqrt(5)/(7*sqrt(pi)) + assert real_gaunt(1, 1, 2, -1, 0, -1) == sqrt(15)/(10*sqrt(pi)) + assert real_gaunt(1, 1, 2, 0, 1, 1) == sqrt(15)/(10*sqrt(pi)) + assert real_gaunt(1, 1, 2, 1, 1, 2) == sqrt(15)/(10*sqrt(pi)) + assert real_gaunt(1, 1, 2, -1, 1, -2) == sqrt(15)/(10*sqrt(pi)) + assert real_gaunt(1, 1, 2, -1, -1, 2) == -sqrt(15)/(10*sqrt(pi)) + assert real_gaunt(2, 2, 2, 0, 1, 1) == sqrt(5)/(14*sqrt(pi)) + assert real_gaunt(2, 2, 2, 1, 1, 2) == sqrt(15)/(14*sqrt(pi)) + assert real_gaunt(2, 2, 2, -1, -1, 2) == -sqrt(15)/(14*sqrt(pi)) + + assert real_gaunt(-2, -2, -2, -2, -2, 0) is S.Zero # m test + assert real_gaunt(-2, 1, 0, 1, 1, 1) is S.Zero # l test + assert real_gaunt(-2, -1, -2, -1, -1, 0) is S.Zero # m and l test + assert real_gaunt(-2, -2, -2, -2, -2, -2) is S.Zero # m and k test + assert real_gaunt(-2, -1, -2, -1, -1, -1) is S.Zero # m, l and k test + + x = symbols('x', integer=True) + v = [0]*6 + for i in range(len(v)): + v[i] = x # non literal ints fail + raises(ValueError, lambda: real_gaunt(*v)) + v[i] = 0 + + +def test_racah(): + assert racah(3,3,3,3,3,3) == Rational(-1,14) + assert racah(2,2,2,2,2,2) == Rational(-3,70) + assert racah(7,8,7,1,7,7, prec=4).is_Float + assert racah(5.5,7.5,9.5,6.5,8,9) == -719*sqrt(598)/1158924 + assert abs(racah(5.5,7.5,9.5,6.5,8,9, prec=4) - (-0.01517)) < S('1e-4') + + +def test_dot_rota_grad_SH(): + theta, phi = symbols("theta phi") + assert dot_rot_grad_Ynm(1, 1, 1, 1, 1, 0) != \ + sqrt(30)*Ynm(2, 2, 1, 0)/(10*sqrt(pi)) + assert dot_rot_grad_Ynm(1, 1, 1, 1, 1, 0).doit() == \ + sqrt(30)*Ynm(2, 2, 1, 0)/(10*sqrt(pi)) + assert dot_rot_grad_Ynm(1, 5, 1, 1, 1, 2) != \ + 0 + assert dot_rot_grad_Ynm(1, 5, 1, 1, 1, 2).doit() == \ + 0 + assert dot_rot_grad_Ynm(3, 3, 3, 3, theta, phi).doit() == \ + 15*sqrt(3003)*Ynm(6, 6, theta, phi)/(143*sqrt(pi)) + assert dot_rot_grad_Ynm(3, 3, 1, 1, theta, phi).doit() == \ + sqrt(3)*Ynm(4, 4, theta, phi)/sqrt(pi) + assert dot_rot_grad_Ynm(3, 2, 2, 0, theta, phi).doit() == \ + 3*sqrt(55)*Ynm(5, 2, theta, phi)/(11*sqrt(pi)) + assert dot_rot_grad_Ynm(3, 2, 3, 2, theta, phi).doit().expand() == \ + -sqrt(70)*Ynm(4, 4, theta, phi)/(11*sqrt(pi)) + \ + 45*sqrt(182)*Ynm(6, 4, theta, phi)/(143*sqrt(pi)) + + +def test_wigner_d(): + half = S(1)/2 + assert wigner_d_small(half, 0) == Matrix([[1, 0], [0, 1]]) + assert wigner_d_small(half, pi/2) == Matrix([[1, 1], [-1, 1]])/sqrt(2) + assert wigner_d_small(half, pi) == Matrix([[0, 1], [-1, 0]]) + + alpha, beta, gamma = symbols("alpha, beta, gamma", real=True) + D = wigner_d(half, alpha, beta, gamma) + assert D[0, 0] == exp(I*alpha/2)*exp(I*gamma/2)*cos(beta/2) + assert D[0, 1] == exp(I*alpha/2)*exp(-I*gamma/2)*sin(beta/2) + assert D[1, 0] == -exp(-I*alpha/2)*exp(I*gamma/2)*sin(beta/2) + assert D[1, 1] == exp(-I*alpha/2)*exp(-I*gamma/2)*cos(beta/2) + + # Test Y_{n mi}(g*x)=\sum_{mj}D^n_{mi mj}*Y_{n mj}(x) + theta, phi = symbols("theta phi", real=True) + v = Matrix([Ynm(1, mj, theta, phi) for mj in range(1, -2, -1)]) + w = wigner_d(1, -pi/2, pi/2, -pi/2)@v.subs({theta: pi/4, phi: pi}) + w_ = v.subs({theta: pi/2, phi: pi/4}) + assert w.expand(func=True).as_real_imag() == w_.expand(func=True).as_real_imag() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_hydrogen.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_hydrogen.py new file mode 100644 index 0000000000000000000000000000000000000000..eb11744dd8e731f24fcd6f6be2a92ada4fffc554 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_hydrogen.py @@ -0,0 +1,126 @@ +from sympy.core.numbers import (I, Rational, oo, pi) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.integrals.integrals import integrate +from sympy.simplify.simplify import simplify +from sympy.physics.hydrogen import R_nl, E_nl, E_nl_dirac, Psi_nlm +from sympy.testing.pytest import raises + +n, r, Z = symbols('n r Z') + + +def feq(a, b, max_relative_error=1e-12, max_absolute_error=1e-12): + a = float(a) + b = float(b) + # if the numbers are close enough (absolutely), then they are equal + if abs(a - b) < max_absolute_error: + return True + # if not, they can still be equal if their relative error is small + if abs(b) > abs(a): + relative_error = abs((a - b)/b) + else: + relative_error = abs((a - b)/a) + return relative_error <= max_relative_error + + +def test_wavefunction(): + a = 1/Z + R = { + (1, 0): 2*sqrt(1/a**3) * exp(-r/a), + (2, 0): sqrt(1/(2*a**3)) * exp(-r/(2*a)) * (1 - r/(2*a)), + (2, 1): S.Half * sqrt(1/(6*a**3)) * exp(-r/(2*a)) * r/a, + (3, 0): Rational(2, 3) * sqrt(1/(3*a**3)) * exp(-r/(3*a)) * + (1 - 2*r/(3*a) + Rational(2, 27) * (r/a)**2), + (3, 1): Rational(4, 27) * sqrt(2/(3*a**3)) * exp(-r/(3*a)) * + (1 - r/(6*a)) * r/a, + (3, 2): Rational(2, 81) * sqrt(2/(15*a**3)) * exp(-r/(3*a)) * (r/a)**2, + (4, 0): Rational(1, 4) * sqrt(1/a**3) * exp(-r/(4*a)) * + (1 - 3*r/(4*a) + Rational(1, 8) * (r/a)**2 - Rational(1, 192) * (r/a)**3), + (4, 1): Rational(1, 16) * sqrt(5/(3*a**3)) * exp(-r/(4*a)) * + (1 - r/(4*a) + Rational(1, 80) * (r/a)**2) * (r/a), + (4, 2): Rational(1, 64) * sqrt(1/(5*a**3)) * exp(-r/(4*a)) * + (1 - r/(12*a)) * (r/a)**2, + (4, 3): Rational(1, 768) * sqrt(1/(35*a**3)) * exp(-r/(4*a)) * (r/a)**3, + } + for n, l in R: + assert simplify(R_nl(n, l, r, Z) - R[(n, l)]) == 0 + + +def test_norm(): + # Maximum "n" which is tested: + n_max = 2 # it works, but is slow, for n_max > 2 + for n in range(n_max + 1): + for l in range(n): + assert integrate(R_nl(n, l, r)**2 * r**2, (r, 0, oo)) == 1 + +def test_psi_nlm(): + r=S('r') + phi=S('phi') + theta=S('theta') + assert (Psi_nlm(1, 0, 0, r, phi, theta) == exp(-r) / sqrt(pi)) + assert (Psi_nlm(2, 1, -1, r, phi, theta)) == S.Half * exp(-r / (2)) * r \ + * (sin(theta) * exp(-I * phi) / (4 * sqrt(pi))) + assert (Psi_nlm(3, 2, 1, r, phi, theta, 2) == -sqrt(2) * sin(theta) \ + * exp(I * phi) * cos(theta) / (4 * sqrt(pi)) * S(2) / 81 \ + * sqrt(2 * 2 ** 3) * exp(-2 * r / (3)) * (r * 2) ** 2) + +def test_hydrogen_energies(): + assert E_nl(n, Z) == -Z**2/(2*n**2) + assert E_nl(n) == -1/(2*n**2) + + assert E_nl(1, 47) == -S(47)**2/(2*1**2) + assert E_nl(2, 47) == -S(47)**2/(2*2**2) + + assert E_nl(1) == -S.One/(2*1**2) + assert E_nl(2) == -S.One/(2*2**2) + assert E_nl(3) == -S.One/(2*3**2) + assert E_nl(4) == -S.One/(2*4**2) + assert E_nl(100) == -S.One/(2*100**2) + + raises(ValueError, lambda: E_nl(0)) + + +def test_hydrogen_energies_relat(): + # First test exact formulas for small "c" so that we get nice expressions: + assert E_nl_dirac(2, 0, Z=1, c=1) == 1/sqrt(2) - 1 + assert simplify(E_nl_dirac(2, 0, Z=1, c=2) - ( (8*sqrt(3) + 16) + / sqrt(16*sqrt(3) + 32) - 4)) == 0 + assert simplify(E_nl_dirac(2, 0, Z=1, c=3) - ( (54*sqrt(2) + 81) + / sqrt(108*sqrt(2) + 162) - 9)) == 0 + + # Now test for almost the correct speed of light, without floating point + # numbers: + assert simplify(E_nl_dirac(2, 0, Z=1, c=137) - ( (352275361 + 10285412 * + sqrt(1173)) / sqrt(704550722 + 20570824 * sqrt(1173)) - 18769)) == 0 + assert simplify(E_nl_dirac(2, 0, Z=82, c=137) - ( (352275361 + 2571353 * + sqrt(12045)) / sqrt(704550722 + 5142706*sqrt(12045)) - 18769)) == 0 + + # Test using exact speed of light, and compare against the nonrelativistic + # energies: + for n in range(1, 5): + for l in range(n): + assert feq(E_nl_dirac(n, l), E_nl(n), 1e-5, 1e-5) + if l > 0: + assert feq(E_nl_dirac(n, l, False), E_nl(n), 1e-5, 1e-5) + + Z = 2 + for n in range(1, 5): + for l in range(n): + assert feq(E_nl_dirac(n, l, Z=Z), E_nl(n, Z), 1e-4, 1e-4) + if l > 0: + assert feq(E_nl_dirac(n, l, False, Z), E_nl(n, Z), 1e-4, 1e-4) + + Z = 3 + for n in range(1, 5): + for l in range(n): + assert feq(E_nl_dirac(n, l, Z=Z), E_nl(n, Z), 1e-3, 1e-3) + if l > 0: + assert feq(E_nl_dirac(n, l, False, Z), E_nl(n, Z), 1e-3, 1e-3) + + # Test the exceptions: + raises(ValueError, lambda: E_nl_dirac(0, 0)) + raises(ValueError, lambda: E_nl_dirac(1, -1)) + raises(ValueError, lambda: E_nl_dirac(1, 0, False)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_paulialgebra.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_paulialgebra.py new file mode 100644 index 0000000000000000000000000000000000000000..f773470a1802f2864b79f56d38be1de030ff86dc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_paulialgebra.py @@ -0,0 +1,57 @@ +from sympy.core.numbers import I +from sympy.core.symbol import symbols +from sympy.physics.paulialgebra import Pauli +from sympy.testing.pytest import XFAIL +from sympy.physics.quantum import TensorProduct + +sigma1 = Pauli(1) +sigma2 = Pauli(2) +sigma3 = Pauli(3) + +tau1 = symbols("tau1", commutative = False) + + +def test_Pauli(): + + assert sigma1 == sigma1 + assert sigma1 != sigma2 + + assert sigma1*sigma2 == I*sigma3 + assert sigma3*sigma1 == I*sigma2 + assert sigma2*sigma3 == I*sigma1 + + assert sigma1*sigma1 == 1 + assert sigma2*sigma2 == 1 + assert sigma3*sigma3 == 1 + + assert sigma1**0 == 1 + assert sigma1**1 == sigma1 + assert sigma1**2 == 1 + assert sigma1**3 == sigma1 + assert sigma1**4 == 1 + + assert sigma3**2 == 1 + + assert sigma1*2*sigma1 == 2 + + +def test_evaluate_pauli_product(): + from sympy.physics.paulialgebra import evaluate_pauli_product + + assert evaluate_pauli_product(I*sigma2*sigma3) == -sigma1 + + # Check issue 6471 + assert evaluate_pauli_product(-I*4*sigma1*sigma2) == 4*sigma3 + + assert evaluate_pauli_product( + 1 + I*sigma1*sigma2*sigma1*sigma2 + \ + I*sigma1*sigma2*tau1*sigma1*sigma3 + \ + ((tau1**2).subs(tau1, I*sigma1)) + \ + sigma3*((tau1**2).subs(tau1, I*sigma1)) + \ + TensorProduct(I*sigma1*sigma2*sigma1*sigma2, 1) + ) == 1 -I + I*sigma3*tau1*sigma2 - 1 - sigma3 - I*TensorProduct(1,1) + + +@XFAIL +def test_Pauli_should_work(): + assert sigma1*sigma3*sigma1 == -sigma3 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_physics_matrices.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_physics_matrices.py new file mode 100644 index 0000000000000000000000000000000000000000..14fa47668d0760826e0354c8cafae787a24256eb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_physics_matrices.py @@ -0,0 +1,84 @@ +from sympy.physics.matrices import msigma, mgamma, minkowski_tensor, pat_matrix, mdft +from sympy.core.numbers import (I, Rational) +from sympy.core.singleton import S +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import (Matrix, eye, zeros) +from sympy.testing.pytest import warns_deprecated_sympy + + +def test_parallel_axis_theorem(): + # This tests the parallel axis theorem matrix by comparing to test + # matrices. + + # First case, 1 in all directions. + mat1 = Matrix(((2, -1, -1), (-1, 2, -1), (-1, -1, 2))) + assert pat_matrix(1, 1, 1, 1) == mat1 + assert pat_matrix(2, 1, 1, 1) == 2*mat1 + + # Second case, 1 in x, 0 in all others + mat2 = Matrix(((0, 0, 0), (0, 1, 0), (0, 0, 1))) + assert pat_matrix(1, 1, 0, 0) == mat2 + assert pat_matrix(2, 1, 0, 0) == 2*mat2 + + # Third case, 1 in y, 0 in all others + mat3 = Matrix(((1, 0, 0), (0, 0, 0), (0, 0, 1))) + assert pat_matrix(1, 0, 1, 0) == mat3 + assert pat_matrix(2, 0, 1, 0) == 2*mat3 + + # Fourth case, 1 in z, 0 in all others + mat4 = Matrix(((1, 0, 0), (0, 1, 0), (0, 0, 0))) + assert pat_matrix(1, 0, 0, 1) == mat4 + assert pat_matrix(2, 0, 0, 1) == 2*mat4 + + +def test_Pauli(): + #this and the following test are testing both Pauli and Dirac matrices + #and also that the general Matrix class works correctly in a real world + #situation + sigma1 = msigma(1) + sigma2 = msigma(2) + sigma3 = msigma(3) + + assert sigma1 == sigma1 + assert sigma1 != sigma2 + + # sigma*I -> I*sigma (see #354) + assert sigma1*sigma2 == sigma3*I + assert sigma3*sigma1 == sigma2*I + assert sigma2*sigma3 == sigma1*I + + assert sigma1*sigma1 == eye(2) + assert sigma2*sigma2 == eye(2) + assert sigma3*sigma3 == eye(2) + + assert sigma1*2*sigma1 == 2*eye(2) + assert sigma1*sigma3*sigma1 == -sigma3 + + +def test_Dirac(): + gamma0 = mgamma(0) + gamma1 = mgamma(1) + gamma2 = mgamma(2) + gamma3 = mgamma(3) + gamma5 = mgamma(5) + + # gamma*I -> I*gamma (see #354) + assert gamma5 == gamma0 * gamma1 * gamma2 * gamma3 * I + assert gamma1 * gamma2 + gamma2 * gamma1 == zeros(4) + assert gamma0 * gamma0 == eye(4) * minkowski_tensor[0, 0] + assert gamma2 * gamma2 != eye(4) * minkowski_tensor[0, 0] + assert gamma2 * gamma2 == eye(4) * minkowski_tensor[2, 2] + + assert mgamma(5, True) == \ + mgamma(0, True)*mgamma(1, True)*mgamma(2, True)*mgamma(3, True)*I + +def test_mdft(): + with warns_deprecated_sympy(): + assert mdft(1) == Matrix([[1]]) + with warns_deprecated_sympy(): + assert mdft(2) == 1/sqrt(2)*Matrix([[1,1],[1,-1]]) + with warns_deprecated_sympy(): + assert mdft(4) == Matrix([[S.Half, S.Half, S.Half, S.Half], + [S.Half, -I/2, Rational(-1,2), I/2], + [S.Half, Rational(-1,2), S.Half, Rational(-1,2)], + [S.Half, I/2, Rational(-1,2), -I/2]]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_pring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_pring.py new file mode 100644 index 0000000000000000000000000000000000000000..ed7398eac4a8bb1cd4af810825caf3fcefb5f18f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_pring.py @@ -0,0 +1,41 @@ +from sympy.physics.pring import wavefunction, energy +from sympy.core.numbers import (I, pi) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.integrals.integrals import integrate +from sympy.simplify.simplify import simplify +from sympy.abc import m, x, r +from sympy.physics.quantum.constants import hbar + + +def test_wavefunction(): + Psi = { + 0: (1/sqrt(2 * pi)), + 1: (1/sqrt(2 * pi)) * exp(I * x), + 2: (1/sqrt(2 * pi)) * exp(2 * I * x), + 3: (1/sqrt(2 * pi)) * exp(3 * I * x) + } + for n in Psi: + assert simplify(wavefunction(n, x) - Psi[n]) == 0 + + +def test_norm(n=1): + # Maximum "n" which is tested: + for i in range(n + 1): + assert integrate( + wavefunction(i, x) * wavefunction(-i, x), (x, 0, 2 * pi)) == 1 + + +def test_orthogonality(n=1): + # Maximum "n" which is tested: + for i in range(n + 1): + for j in range(i+1, n+1): + assert integrate( + wavefunction(i, x) * wavefunction(j, x), (x, 0, 2 * pi)) == 0 + + +def test_energy(n=1): + # Maximum "n" which is tested: + for i in range(n+1): + assert simplify( + energy(i, m, r) - ((i**2 * hbar**2) / (2 * m * r**2))) == 0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_qho_1d.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_qho_1d.py new file mode 100644 index 0000000000000000000000000000000000000000..34e52c9e3a721496fc61f7d2b31414db15caa7a8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_qho_1d.py @@ -0,0 +1,50 @@ +from sympy.core.numbers import (Rational, oo, pi) +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.integrals.integrals import integrate +from sympy.simplify.simplify import simplify +from sympy.abc import omega, m, x +from sympy.physics.qho_1d import psi_n, E_n, coherent_state +from sympy.physics.quantum.constants import hbar + +nu = m * omega / hbar + + +def test_wavefunction(): + Psi = { + 0: (nu/pi)**Rational(1, 4) * exp(-nu * x**2 /2), + 1: (nu/pi)**Rational(1, 4) * sqrt(2*nu) * x * exp(-nu * x**2 /2), + 2: (nu/pi)**Rational(1, 4) * (2 * nu * x**2 - 1)/sqrt(2) * exp(-nu * x**2 /2), + 3: (nu/pi)**Rational(1, 4) * sqrt(nu/3) * (2 * nu * x**3 - 3 * x) * exp(-nu * x**2 /2) + } + for n in Psi: + assert simplify(psi_n(n, x, m, omega) - Psi[n]) == 0 + + +def test_norm(n=1): + # Maximum "n" which is tested: + for i in range(n + 1): + assert integrate(psi_n(i, x, 1, 1)**2, (x, -oo, oo)) == 1 + + +def test_orthogonality(n=1): + # Maximum "n" which is tested: + for i in range(n + 1): + for j in range(i + 1, n + 1): + assert integrate( + psi_n(i, x, 1, 1)*psi_n(j, x, 1, 1), (x, -oo, oo)) == 0 + + +def test_energies(n=1): + # Maximum "n" which is tested: + for i in range(n + 1): + assert E_n(i, omega) == hbar * omega * (i + S.Half) + +def test_coherent_state(n=10): + # Maximum "n" which is tested: + # test whether coherent state is the eigenstate of annihilation operator + alpha = Symbol("alpha") + for i in range(n + 1): + assert simplify(sqrt(n + 1) * coherent_state(n + 1, alpha)) == simplify(alpha * coherent_state(n, alpha)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_secondquant.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_secondquant.py new file mode 100644 index 0000000000000000000000000000000000000000..e7f60fab05497aead65ad748460802c9c29740ce --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_secondquant.py @@ -0,0 +1,1301 @@ +from sympy.functions.elementary.complexes import conjugate +from sympy.functions.elementary.exponential import exp +from sympy.physics.secondquant import ( + Dagger, Bd, VarBosonicBasis, BBra, B, BKet, FixedBosonicBasis, + matrix_rep, apply_operators, InnerProduct, Commutator, KroneckerDelta, + AnnihilateBoson, CreateBoson, BosonicOperator, + F, Fd, FKet, BosonState, CreateFermion, AnnihilateFermion, + evaluate_deltas, AntiSymmetricTensor, contraction, NO, wicks, + PermutationOperator, simplify_index_permutations, + _sort_anticommuting_fermions, _get_ordered_dummies, + substitute_dummies, FockStateBosonKet, + ContractionAppliesOnlyToFermions +) + +from sympy.concrete.summations import Sum +from sympy.core.function import (Function, expand) +from sympy.core.numbers import (I, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.printing.repr import srepr +from sympy.simplify.simplify import simplify + +from sympy.testing.pytest import slow, raises +from sympy.printing.latex import latex + + +def test_PermutationOperator(): + p, q, r, s = symbols('p,q,r,s') + f, g, h, i = map(Function, 'fghi') + P = PermutationOperator + assert P(p, q).get_permuted(f(p)*g(q)) == -f(q)*g(p) + assert P(p, q).get_permuted(f(p, q)) == -f(q, p) + assert P(p, q).get_permuted(f(p)) == f(p) + expr = (f(p)*g(q)*h(r)*i(s) + - f(q)*g(p)*h(r)*i(s) + - f(p)*g(q)*h(s)*i(r) + + f(q)*g(p)*h(s)*i(r)) + perms = [P(p, q), P(r, s)] + assert (simplify_index_permutations(expr, perms) == + P(p, q)*P(r, s)*f(p)*g(q)*h(r)*i(s)) + assert latex(P(p, q)) == 'P(pq)' + + p1, p2 = symbols('p1,p2') + assert latex(P(p1,p2) == 'P(p_{1}p_{2})') + +def test_index_permutations_with_dummies(): + a, b, c, d = symbols('a b c d') + p, q, r, s = symbols('p q r s', cls=Dummy) + f, g = map(Function, 'fg') + P = PermutationOperator + + # No dummy substitution necessary + expr = f(a, b, p, q) - f(b, a, p, q) + assert simplify_index_permutations( + expr, [P(a, b)]) == P(a, b)*f(a, b, p, q) + + # Cases where dummy substitution is needed + expected = P(a, b)*substitute_dummies(f(a, b, p, q)) + + expr = f(a, b, p, q) - f(b, a, q, p) + result = simplify_index_permutations(expr, [P(a, b)]) + assert expected == substitute_dummies(result) + + expr = f(a, b, q, p) - f(b, a, p, q) + result = simplify_index_permutations(expr, [P(a, b)]) + assert expected == substitute_dummies(result) + + # A case where nothing can be done + expr = f(a, b, q, p) - g(b, a, p, q) + result = simplify_index_permutations(expr, [P(a, b)]) + assert expr == result + + +def test_dagger(): + i, j, n, m = symbols('i,j,n,m') + assert Dagger(1) == 1 + assert Dagger(1.0) == 1.0 + assert Dagger(2*I) == -2*I + assert Dagger(S.Half*I/3.0) == I*Rational(-1, 2)/3.0 + assert Dagger(BKet([n])) == BBra([n]) + assert Dagger(B(0)) == Bd(0) + assert Dagger(Bd(0)) == B(0) + assert Dagger(B(n)) == Bd(n) + assert Dagger(Bd(n)) == B(n) + assert Dagger(B(0) + B(1)) == Bd(0) + Bd(1) + assert Dagger(n*m) == Dagger(n)*Dagger(m) # n, m commute + assert Dagger(B(n)*B(m)) == Bd(m)*Bd(n) + assert Dagger(B(n)**10) == Dagger(B(n))**10 + assert Dagger('a') == Dagger(Symbol('a')) + assert Dagger(Dagger('a')) == Symbol('a') + assert Dagger(exp(2 * I)) == exp(-2 * I) + assert Dagger(i) == conjugate(i) + + +def test_operator(): + i, j = symbols('i,j') + o = BosonicOperator(i) + assert o.state == i + assert o.is_symbolic + o = BosonicOperator(1) + assert o.state == 1 + assert not o.is_symbolic + + +def test_create(): + i, j, n, m, p1 = symbols('i,j,n,m,p1') + o = Bd(i) + assert latex(o) == "{b^\\dagger_{i}}" + assert latex(Bd(p1)) == "{b^\\dagger_{p_{1}}}" + assert isinstance(o, CreateBoson) + o = o.subs(i, j) + assert o.atoms(Symbol) == {j} + o = Bd(0) + assert o.apply_operator(BKet([n])) == sqrt(n + 1)*BKet([n + 1]) + o = Bd(n) + assert o.apply_operator(BKet([n])) == o*BKet([n]) + + +def test_annihilate(): + i, j, n, m, p1 = symbols('i,j,n,m,p1') + o = B(i) + assert latex(o) == "b_{i}" + assert latex(B(p1)) == "b_{p_{1}}" + assert isinstance(o, AnnihilateBoson) + o = o.subs(i, j) + assert o.atoms(Symbol) == {j} + o = B(0) + assert o.apply_operator(BKet([n])) == sqrt(n)*BKet([n - 1]) + o = B(n) + assert o.apply_operator(BKet([n])) == o*BKet([n]) + + +def test_basic_state(): + i, j, n, m = symbols('i,j,n,m') + s = BosonState([0, 1, 2, 3, 4]) + assert len(s) == 5 + assert s.args[0] == tuple(range(5)) + assert s.up(0) == BosonState([1, 1, 2, 3, 4]) + assert s.down(4) == BosonState([0, 1, 2, 3, 3]) + for i in range(5): + assert s.up(i).down(i) == s + assert s.down(0) == 0 + for i in range(5): + assert s[i] == i + s = BosonState([n, m]) + assert s.down(0) == BosonState([n - 1, m]) + assert s.up(0) == BosonState([n + 1, m]) + + +def test_basic_apply(): + n = symbols("n") + e = B(0)*BKet([n]) + assert apply_operators(e) == sqrt(n)*BKet([n - 1]) + e = Bd(0)*BKet([n]) + assert apply_operators(e) == sqrt(n + 1)*BKet([n + 1]) + + +def test_complex_apply(): + n, m = symbols("n,m") + o = Bd(0)*B(0)*Bd(1)*B(0) + e = apply_operators(o*BKet([n, m])) + answer = sqrt(n)*sqrt(m + 1)*(-1 + n)*BKet([-1 + n, 1 + m]) + assert expand(e) == expand(answer) + + +def test_number_operator(): + n = symbols("n") + o = Bd(0)*B(0) + e = apply_operators(o*BKet([n])) + assert e == n*BKet([n]) + + +def test_inner_product(): + i, j, k, l = symbols('i,j,k,l') + s1 = BBra([0]) + s2 = BKet([1]) + assert InnerProduct(s1, Dagger(s1)) == 1 + assert InnerProduct(s1, s2) == 0 + s1 = BBra([i, j]) + s2 = BKet([k, l]) + r = InnerProduct(s1, s2) + assert r == KroneckerDelta(i, k)*KroneckerDelta(j, l) + + +def test_symbolic_matrix_elements(): + n, m = symbols('n,m') + s1 = BBra([n]) + s2 = BKet([m]) + o = B(0) + e = apply_operators(s1*o*s2) + assert e == sqrt(m)*KroneckerDelta(n, m - 1) + + +def test_matrix_elements(): + b = VarBosonicBasis(5) + o = B(0) + m = matrix_rep(o, b) + for i in range(4): + assert m[i, i + 1] == sqrt(i + 1) + o = Bd(0) + m = matrix_rep(o, b) + for i in range(4): + assert m[i + 1, i] == sqrt(i + 1) + + +def test_fixed_bosonic_basis(): + b = FixedBosonicBasis(2, 2) + # assert b == [FockState((2, 0)), FockState((1, 1)), FockState((0, 2))] + state = b.state(1) + assert state == FockStateBosonKet((1, 1)) + assert b.index(state) == 1 + assert b.state(1) == b[1] + assert len(b) == 3 + assert str(b) == '[FockState((2, 0)), FockState((1, 1)), FockState((0, 2))]' + assert repr(b) == '[FockState((2, 0)), FockState((1, 1)), FockState((0, 2))]' + assert srepr(b) == '[FockState((2, 0)), FockState((1, 1)), FockState((0, 2))]' + + +@slow +def test_sho(): + n, m = symbols('n,m') + h_n = Bd(n)*B(n)*(n + S.Half) + H = Sum(h_n, (n, 0, 5)) + o = H.doit(deep=False) + b = FixedBosonicBasis(2, 6) + m = matrix_rep(o, b) + # We need to double check these energy values to make sure that they + # are correct and have the proper degeneracies! + diag = [1, 2, 3, 3, 4, 5, 4, 5, 6, 7, 5, 6, 7, 8, 9, 6, 7, 8, 9, 10, 11] + for i in range(len(diag)): + assert diag[i] == m[i, i] + + +def test_commutation(): + n, m = symbols("n,m", above_fermi=True) + c = Commutator(B(0), Bd(0)) + assert c == 1 + c = Commutator(Bd(0), B(0)) + assert c == -1 + c = Commutator(B(n), Bd(0)) + assert c == KroneckerDelta(n, 0) + c = Commutator(B(0), B(0)) + assert c == 0 + c = Commutator(B(0), Bd(0)) + e = simplify(apply_operators(c*BKet([n]))) + assert e == BKet([n]) + c = Commutator(B(0), B(1)) + e = simplify(apply_operators(c*BKet([n, m]))) + assert e == 0 + + c = Commutator(F(m), Fd(m)) + assert c == +1 - 2*NO(Fd(m)*F(m)) + c = Commutator(Fd(m), F(m)) + assert c.expand() == -1 + 2*NO(Fd(m)*F(m)) + + C = Commutator + X, Y, Z = symbols('X,Y,Z', commutative=False) + assert C(C(X, Y), Z) != 0 + assert C(C(X, Z), Y) != 0 + assert C(Y, C(X, Z)) != 0 + + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) + p, q, r, s = symbols('p,q,r,s') + D = KroneckerDelta + + assert C(Fd(a), F(i)) == -2*NO(F(i)*Fd(a)) + assert C(Fd(j), NO(Fd(a)*F(i))).doit(wicks=True) == -D(j, i)*Fd(a) + assert C(Fd(a)*F(i), Fd(b)*F(j)).doit(wicks=True) == 0 + + c1 = Commutator(F(a), Fd(a)) + assert Commutator.eval(c1, c1) == 0 + c = Commutator(Fd(a)*F(i),Fd(b)*F(j)) + assert latex(c) == r'\left[{a^\dagger_{a}} a_{i},{a^\dagger_{b}} a_{j}\right]' + assert repr(c) == 'Commutator(CreateFermion(a)*AnnihilateFermion(i),CreateFermion(b)*AnnihilateFermion(j))' + assert str(c) == '[CreateFermion(a)*AnnihilateFermion(i),CreateFermion(b)*AnnihilateFermion(j)]' + + +def test_create_f(): + i, j, n, m = symbols('i,j,n,m') + o = Fd(i) + assert isinstance(o, CreateFermion) + o = o.subs(i, j) + assert o.atoms(Symbol) == {j} + o = Fd(1) + assert o.apply_operator(FKet([n])) == FKet([1, n]) + assert o.apply_operator(FKet([n])) == -FKet([n, 1]) + o = Fd(n) + assert o.apply_operator(FKet([])) == FKet([n]) + + vacuum = FKet([], fermi_level=4) + assert vacuum == FKet([], fermi_level=4) + + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) + p, q, r, s = symbols('p,q,r,s') + p1 = symbols("p1") + + assert Fd(i).apply_operator(FKet([i, j, k], 4)) == FKet([j, k], 4) + assert Fd(a).apply_operator(FKet([i, b, k], 4)) == FKet([a, i, b, k], 4) + + assert Dagger(B(p)).apply_operator(q) == q*CreateBoson(p) + assert repr(Fd(p)) == 'CreateFermion(p)' + assert srepr(Fd(p)) == "CreateFermion(Symbol('p'))" + assert latex(Fd(p)) == r'{a^\dagger_{p}}' + assert latex(Fd(p1)) == r'{a^\dagger_{p_{1}}}' + assert latex(FKet([a,i], 1)) == r"\left|\left( a, \ i\right)\right\rangle" + assert latex(FKet([j,i,b,a], 2)) == r"\left|\left( a, \ b, \ i, \ j\right)\right\rangle" + + +def test_annihilate_f(): + i, j, n, m = symbols('i,j,n,m') + o = F(i) + assert isinstance(o, AnnihilateFermion) + o = o.subs(i, j) + assert o.atoms(Symbol) == {j} + o = F(1) + assert o.apply_operator(FKet([1, n])) == FKet([n]) + assert o.apply_operator(FKet([n, 1])) == -FKet([n]) + o = F(n) + assert o.apply_operator(FKet([n])) == FKet([]) + + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) + p, q, r, s = symbols('p,q,r,s') + p1 = symbols('p1') + + assert F(i).apply_operator(FKet([i, j, k], 4)) == 0 + assert F(a).apply_operator(FKet([i, b, k], 4)) == 0 + assert F(l).apply_operator(FKet([i, j, k], 3)) == 0 + assert F(l).apply_operator(FKet([i, j, k], 4)) == FKet([l, i, j, k], 4) + assert str(F(p)) == 'f(p)' + assert repr(F(p)) == 'AnnihilateFermion(p)' + assert srepr(F(p)) == "AnnihilateFermion(Symbol('p'))" + assert latex(F(p)) == 'a_{p}' + assert latex(F(p1)) == 'a_{p_{1}}' + + +def test_create_b(): + i, j, n, m = symbols('i,j,n,m') + o = Bd(i) + assert isinstance(o, CreateBoson) + o = o.subs(i, j) + assert o.atoms(Symbol) == {j} + o = Bd(0) + assert o.apply_operator(BKet([n])) == sqrt(n + 1)*BKet([n + 1]) + o = Bd(n) + assert o.apply_operator(BKet([n])) == o*BKet([n]) + + +def test_annihilate_b(): + i, j, n, m = symbols('i,j,n,m') + o = B(i) + assert isinstance(o, AnnihilateBoson) + o = o.subs(i, j) + assert o.atoms(Symbol) == {j} + o = B(0) + + +def test_wicks(): + p, q, r, s = symbols('p,q,r,s', above_fermi=True) + + # Testing for particles only + + str = F(p)*Fd(q) + assert wicks(str) == NO(F(p)*Fd(q)) + KroneckerDelta(p, q) + str = Fd(p)*F(q) + assert wicks(str) == NO(Fd(p)*F(q)) + + str = F(p)*Fd(q)*F(r)*Fd(s) + nstr = wicks(str) + fasit = NO( + KroneckerDelta(p, q)*KroneckerDelta(r, s) + + KroneckerDelta(p, q)*AnnihilateFermion(r)*CreateFermion(s) + + KroneckerDelta(r, s)*AnnihilateFermion(p)*CreateFermion(q) + - KroneckerDelta(p, s)*AnnihilateFermion(r)*CreateFermion(q) + - AnnihilateFermion(p)*AnnihilateFermion(r)*CreateFermion(q)*CreateFermion(s)) + assert nstr == fasit + + assert (p*q*nstr).expand() == wicks(p*q*str) + assert (nstr*p*q*2).expand() == wicks(str*p*q*2) + + # Testing CC equations particles and holes + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) + p, q, r, s = symbols('p q r s', cls=Dummy) + + assert (wicks(F(a)*NO(F(i)*F(j))*Fd(b)) == + NO(F(a)*F(i)*F(j)*Fd(b)) + + KroneckerDelta(a, b)*NO(F(i)*F(j))) + assert (wicks(F(a)*NO(F(i)*F(j)*F(k))*Fd(b)) == + NO(F(a)*F(i)*F(j)*F(k)*Fd(b)) - + KroneckerDelta(a, b)*NO(F(i)*F(j)*F(k))) + + expr = wicks(Fd(i)*NO(Fd(j)*F(k))*F(l)) + assert (expr == + -KroneckerDelta(i, k)*NO(Fd(j)*F(l)) - + KroneckerDelta(j, l)*NO(Fd(i)*F(k)) - + KroneckerDelta(i, k)*KroneckerDelta(j, l) + + KroneckerDelta(i, l)*NO(Fd(j)*F(k)) + + NO(Fd(i)*Fd(j)*F(k)*F(l))) + expr = wicks(F(a)*NO(F(b)*Fd(c))*Fd(d)) + assert (expr == + -KroneckerDelta(a, c)*NO(F(b)*Fd(d)) - + KroneckerDelta(b, d)*NO(F(a)*Fd(c)) - + KroneckerDelta(a, c)*KroneckerDelta(b, d) + + KroneckerDelta(a, d)*NO(F(b)*Fd(c)) + + NO(F(a)*F(b)*Fd(c)*Fd(d))) + + +def test_NO(): + i, j, k, l = symbols('i j k l', below_fermi=True) + a, b, c, d = symbols('a b c d', above_fermi=True) + p, q, r, s = symbols('p q r s', cls=Dummy) + + assert (NO(Fd(p)*F(q) + Fd(a)*F(b)) == + NO(Fd(p)*F(q)) + NO(Fd(a)*F(b))) + assert (NO(Fd(i)*NO(F(j)*Fd(a))) == + NO(Fd(i)*F(j)*Fd(a))) + assert NO(1) == 1 + assert NO(i) == i + assert (NO(Fd(a)*Fd(b)*(F(c) + F(d))) == + NO(Fd(a)*Fd(b)*F(c)) + + NO(Fd(a)*Fd(b)*F(d))) + + assert NO(Fd(a)*F(b))._remove_brackets() == Fd(a)*F(b) + assert NO(F(j)*Fd(i))._remove_brackets() == F(j)*Fd(i) + + assert (NO(Fd(p)*F(q)).subs(Fd(p), Fd(a) + Fd(i)) == + NO(Fd(a)*F(q)) + NO(Fd(i)*F(q))) + assert (NO(Fd(p)*F(q)).subs(F(q), F(a) + F(i)) == + NO(Fd(p)*F(a)) + NO(Fd(p)*F(i))) + + expr = NO(Fd(p)*F(q))._remove_brackets() + assert wicks(expr) == NO(expr) + + assert NO(Fd(a)*F(b)) == - NO(F(b)*Fd(a)) + + no = NO(Fd(a)*F(i)*F(b)*Fd(j)) + l1 = list(no.iter_q_creators()) + assert l1 == [0, 1] + l2 = list(no.iter_q_annihilators()) + assert l2 == [3, 2] + no = NO(Fd(a)*Fd(i)) + assert no.has_q_creators == 1 + assert no.has_q_annihilators == -1 + assert str(no) == ':CreateFermion(a)*CreateFermion(i):' + assert repr(no) == 'NO(CreateFermion(a)*CreateFermion(i))' + assert latex(no) == r'\left\{{a^\dagger_{a}} {a^\dagger_{i}}\right\}' + raises(NotImplementedError, lambda: NO(Bd(p)*F(q))) + + +def test_sorting(): + i, j = symbols('i,j', below_fermi=True) + a, b = symbols('a,b', above_fermi=True) + p, q = symbols('p,q') + + # p, q + assert _sort_anticommuting_fermions([Fd(p), F(q)]) == ([Fd(p), F(q)], 0) + assert _sort_anticommuting_fermions([F(p), Fd(q)]) == ([Fd(q), F(p)], 1) + + # i, p + assert _sort_anticommuting_fermions([F(p), Fd(i)]) == ([F(p), Fd(i)], 0) + assert _sort_anticommuting_fermions([Fd(i), F(p)]) == ([F(p), Fd(i)], 1) + assert _sort_anticommuting_fermions([Fd(p), Fd(i)]) == ([Fd(p), Fd(i)], 0) + assert _sort_anticommuting_fermions([Fd(i), Fd(p)]) == ([Fd(p), Fd(i)], 1) + assert _sort_anticommuting_fermions([F(p), F(i)]) == ([F(i), F(p)], 1) + assert _sort_anticommuting_fermions([F(i), F(p)]) == ([F(i), F(p)], 0) + assert _sort_anticommuting_fermions([Fd(p), F(i)]) == ([F(i), Fd(p)], 1) + assert _sort_anticommuting_fermions([F(i), Fd(p)]) == ([F(i), Fd(p)], 0) + + # a, p + assert _sort_anticommuting_fermions([F(p), Fd(a)]) == ([Fd(a), F(p)], 1) + assert _sort_anticommuting_fermions([Fd(a), F(p)]) == ([Fd(a), F(p)], 0) + assert _sort_anticommuting_fermions([Fd(p), Fd(a)]) == ([Fd(a), Fd(p)], 1) + assert _sort_anticommuting_fermions([Fd(a), Fd(p)]) == ([Fd(a), Fd(p)], 0) + assert _sort_anticommuting_fermions([F(p), F(a)]) == ([F(p), F(a)], 0) + assert _sort_anticommuting_fermions([F(a), F(p)]) == ([F(p), F(a)], 1) + assert _sort_anticommuting_fermions([Fd(p), F(a)]) == ([Fd(p), F(a)], 0) + assert _sort_anticommuting_fermions([F(a), Fd(p)]) == ([Fd(p), F(a)], 1) + + # i, a + assert _sort_anticommuting_fermions([F(i), Fd(j)]) == ([F(i), Fd(j)], 0) + assert _sort_anticommuting_fermions([Fd(j), F(i)]) == ([F(i), Fd(j)], 1) + assert _sort_anticommuting_fermions([Fd(a), Fd(i)]) == ([Fd(a), Fd(i)], 0) + assert _sort_anticommuting_fermions([Fd(i), Fd(a)]) == ([Fd(a), Fd(i)], 1) + assert _sort_anticommuting_fermions([F(a), F(i)]) == ([F(i), F(a)], 1) + assert _sort_anticommuting_fermions([F(i), F(a)]) == ([F(i), F(a)], 0) + + +def test_contraction(): + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) + p, q, r, s = symbols('p,q,r,s') + assert contraction(Fd(i), F(j)) == KroneckerDelta(i, j) + assert contraction(F(a), Fd(b)) == KroneckerDelta(a, b) + assert contraction(F(a), Fd(i)) == 0 + assert contraction(Fd(a), F(i)) == 0 + assert contraction(F(i), Fd(a)) == 0 + assert contraction(Fd(i), F(a)) == 0 + assert contraction(Fd(i), F(p)) == KroneckerDelta(i, p) + restr = evaluate_deltas(contraction(Fd(p), F(q))) + assert restr.is_only_below_fermi + restr = evaluate_deltas(contraction(F(p), Fd(q))) + assert restr.is_only_above_fermi + raises(ContractionAppliesOnlyToFermions, lambda: contraction(B(a), Fd(b))) + + +def test_evaluate_deltas(): + i, j, k = symbols('i,j,k') + + r = KroneckerDelta(i, j) * KroneckerDelta(j, k) + assert evaluate_deltas(r) == KroneckerDelta(i, k) + + r = KroneckerDelta(i, 0) * KroneckerDelta(j, k) + assert evaluate_deltas(r) == KroneckerDelta(i, 0) * KroneckerDelta(j, k) + + r = KroneckerDelta(1, j) * KroneckerDelta(j, k) + assert evaluate_deltas(r) == KroneckerDelta(1, k) + + r = KroneckerDelta(j, 2) * KroneckerDelta(k, j) + assert evaluate_deltas(r) == KroneckerDelta(2, k) + + r = KroneckerDelta(i, 0) * KroneckerDelta(i, j) * KroneckerDelta(j, 1) + assert evaluate_deltas(r) == 0 + + r = (KroneckerDelta(0, i) * KroneckerDelta(0, j) + * KroneckerDelta(1, j) * KroneckerDelta(1, j)) + assert evaluate_deltas(r) == 0 + + +def test_Tensors(): + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) + p, q, r, s = symbols('p q r s') + + AT = AntiSymmetricTensor + assert AT('t', (a, b), (i, j)) == -AT('t', (b, a), (i, j)) + assert AT('t', (a, b), (i, j)) == AT('t', (b, a), (j, i)) + assert AT('t', (a, b), (i, j)) == -AT('t', (a, b), (j, i)) + assert AT('t', (a, a), (i, j)) == 0 + assert AT('t', (a, b), (i, i)) == 0 + assert AT('t', (a, b, c), (i, j)) == -AT('t', (b, a, c), (i, j)) + assert AT('t', (a, b, c), (i, j, k)) == AT('t', (b, a, c), (i, k, j)) + + tabij = AT('t', (a, b), (i, j)) + assert tabij.has(a) + assert tabij.has(b) + assert tabij.has(i) + assert tabij.has(j) + assert tabij.subs(b, c) == AT('t', (a, c), (i, j)) + assert (2*tabij).subs(i, c) == 2*AT('t', (a, b), (c, j)) + assert tabij.symbol == Symbol('t') + assert latex(tabij) == '{t^{ab}_{ij}}' + assert str(tabij) == 't((_a, _b),(_i, _j))' + + assert AT('t', (a, a), (i, j)).subs(a, b) == AT('t', (b, b), (i, j)) + assert AT('t', (a, i), (a, j)).subs(a, b) == AT('t', (b, i), (b, j)) + + a1, a2, a3, a4 = symbols('alpha1:5') + u_alpha1234 = AntiSymmetricTensor("u", (a1, a2), (a3, a4)) + + assert latex(u_alpha1234) == r'{u^{\alpha_{1}\alpha_{2}}_{\alpha_{3}\alpha_{4}}}' + assert str(u_alpha1234) == 'u((alpha1, alpha2),(alpha3, alpha4))' + + +def test_fully_contracted(): + i, j, k, l = symbols('i j k l', below_fermi=True) + a, b, c, d = symbols('a b c d', above_fermi=True) + p, q, r, s = symbols('p q r s', cls=Dummy) + + Fock = (AntiSymmetricTensor('f', (p,), (q,))* + NO(Fd(p)*F(q))) + V = (AntiSymmetricTensor('v', (p, q), (r, s))* + NO(Fd(p)*Fd(q)*F(s)*F(r)))/4 + + Fai = wicks(NO(Fd(i)*F(a))*Fock, + keep_only_fully_contracted=True, + simplify_kronecker_deltas=True) + assert Fai == AntiSymmetricTensor('f', (a,), (i,)) + Vabij = wicks(NO(Fd(i)*Fd(j)*F(b)*F(a))*V, + keep_only_fully_contracted=True, + simplify_kronecker_deltas=True) + assert Vabij == AntiSymmetricTensor('v', (a, b), (i, j)) + + +def test_substitute_dummies_without_dummies(): + i, j = symbols('i,j') + assert substitute_dummies(att(i, j) + 2) == att(i, j) + 2 + assert substitute_dummies(att(i, j) + 1) == att(i, j) + 1 + + +def test_substitute_dummies_NO_operator(): + i, j = symbols('i j', cls=Dummy) + assert substitute_dummies(att(i, j)*NO(Fd(i)*F(j)) + - att(j, i)*NO(Fd(j)*F(i))) == 0 + + +def test_substitute_dummies_SQ_operator(): + i, j = symbols('i j', cls=Dummy) + assert substitute_dummies(att(i, j)*Fd(i)*F(j) + - att(j, i)*Fd(j)*F(i)) == 0 + + +def test_substitute_dummies_new_indices(): + i, j = symbols('i j', below_fermi=True, cls=Dummy) + a, b = symbols('a b', above_fermi=True, cls=Dummy) + p, q = symbols('p q', cls=Dummy) + f = Function('f') + assert substitute_dummies(f(i, a, p) - f(j, b, q), new_indices=True) == 0 + + +def test_substitute_dummies_substitution_order(): + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + f = Function('f') + from sympy.utilities.iterables import variations + for permut in variations([i, j, k, l], 4): + assert substitute_dummies(f(*permut) - f(i, j, k, l)) == 0 + + +def test_dummy_order_inner_outer_lines_VT1T1T1(): + ii = symbols('i', below_fermi=True) + aa = symbols('a', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) + + v = Function('v') + t = Function('t') + dums = _get_ordered_dummies + + # Coupled-Cluster T1 terms with V*T1*T1*T1 + # t^{a}_{k} t^{c}_{i} t^{d}_{l} v^{lk}_{dc} + exprs = [ + # permut v and t <=> swapping internal lines, equivalent + # irrespective of symmetries in v + v(k, l, c, d)*t(c, ii)*t(d, l)*t(aa, k), + v(l, k, c, d)*t(c, ii)*t(d, k)*t(aa, l), + v(k, l, d, c)*t(d, ii)*t(c, l)*t(aa, k), + v(l, k, d, c)*t(d, ii)*t(c, k)*t(aa, l), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_dummy_order_inner_outer_lines_VT1T1T1T1(): + ii, jj = symbols('i j', below_fermi=True) + aa, bb = symbols('a b', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) + + v = Function('v') + t = Function('t') + dums = _get_ordered_dummies + + # Coupled-Cluster T2 terms with V*T1*T1*T1*T1 + exprs = [ + # permut t <=> swapping external lines, not equivalent + # except if v has certain symmetries. + v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(k, l, c, d)*t(c, jj)*t(d, ii)*t(aa, k)*t(bb, l), + v(k, l, c, d)*t(c, ii)*t(d, jj)*t(bb, k)*t(aa, l), + v(k, l, c, d)*t(c, jj)*t(d, ii)*t(bb, k)*t(aa, l), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + exprs = [ + # permut v <=> swapping external lines, not equivalent + # except if v has certain symmetries. + # + # Note that in contrast to above, these permutations have identical + # dummy order. That is because the proximity to external indices + # has higher influence on the canonical dummy ordering than the + # position of a dummy on the factors. In fact, the terms here are + # similar in structure as the result of the dummy substitutions above. + v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(l, k, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(k, l, d, c)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(l, k, d, c)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) == dums(permut) + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + exprs = [ + # permut t and v <=> swapping internal lines, equivalent. + # Canonical dummy order is different, and a consistent + # substitution reveals the equivalence. + v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(k, l, d, c)*t(c, jj)*t(d, ii)*t(aa, k)*t(bb, l), + v(l, k, c, d)*t(c, ii)*t(d, jj)*t(bb, k)*t(aa, l), + v(l, k, d, c)*t(c, jj)*t(d, ii)*t(bb, k)*t(aa, l), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_get_subNO(): + p, q, r = symbols('p,q,r') + assert NO(F(p)*F(q)*F(r)).get_subNO(1) == NO(F(p)*F(r)) + assert NO(F(p)*F(q)*F(r)).get_subNO(0) == NO(F(q)*F(r)) + assert NO(F(p)*F(q)*F(r)).get_subNO(2) == NO(F(p)*F(q)) + + +def test_equivalent_internal_lines_VT1T1(): + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) + + v = Function('v') + t = Function('t') + dums = _get_ordered_dummies + + exprs = [ # permute v. Different dummy order. Not equivalent. + v(i, j, a, b)*t(a, i)*t(b, j), + v(j, i, a, b)*t(a, i)*t(b, j), + v(i, j, b, a)*t(a, i)*t(b, j), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + + exprs = [ # permute v. Different dummy order. Equivalent + v(i, j, a, b)*t(a, i)*t(b, j), + v(j, i, b, a)*t(a, i)*t(b, j), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + exprs = [ # permute t. Same dummy order, not equivalent. + v(i, j, a, b)*t(a, i)*t(b, j), + v(i, j, a, b)*t(b, i)*t(a, j), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) == dums(permut) + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + + exprs = [ # permute v and t. Different dummy order, equivalent + v(i, j, a, b)*t(a, i)*t(b, j), + v(j, i, a, b)*t(a, j)*t(b, i), + v(i, j, b, a)*t(b, i)*t(a, j), + v(j, i, b, a)*t(b, j)*t(a, i), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_equivalent_internal_lines_VT2conjT2(): + # this diagram requires special handling in TCE + i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) + a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) + + from sympy.utilities.iterables import variations + + v = Function('v') + t = Function('t') + dums = _get_ordered_dummies + + # v(abcd)t(abij)t(ijcd) + template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(i, j, p3, p4) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert dums(base) != dums(expr) + assert substitute_dummies(expr) == substitute_dummies(base) + template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(j, i, p3, p4) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert dums(base) != dums(expr) + assert substitute_dummies(expr) == substitute_dummies(base) + + # v(abcd)t(abij)t(jicd) + template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(j, i, p3, p4) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert dums(base) != dums(expr) + assert substitute_dummies(expr) == substitute_dummies(base) + template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(i, j, p3, p4) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert dums(base) != dums(expr) + assert substitute_dummies(expr) == substitute_dummies(base) + + +def test_equivalent_internal_lines_VT2conjT2_ambiguous_order(): + # These diagrams invokes _determine_ambiguous() because the + # dummies can not be ordered unambiguously by the key alone + i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) + a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) + + from sympy.utilities.iterables import variations + + v = Function('v') + t = Function('t') + dums = _get_ordered_dummies + + # v(abcd)t(abij)t(cdij) + template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(p3, p4, i, j) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert dums(base) != dums(expr) + assert substitute_dummies(expr) == substitute_dummies(base) + template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(p3, p4, i, j) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert dums(base) != dums(expr) + assert substitute_dummies(expr) == substitute_dummies(base) + + +def test_equivalent_internal_lines_VT2(): + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) + + v = Function('v') + t = Function('t') + dums = _get_ordered_dummies + exprs = [ + # permute v. Same dummy order, not equivalent. + # + # This test show that the dummy order may not be sensitive to all + # index permutations. The following expressions have identical + # structure as the resulting terms from of the dummy substitutions + # in the test above. Here, all expressions have the same dummy + # order, so they cannot be simplified by means of dummy + # substitution. In order to simplify further, it is necessary to + # exploit symmetries in the objects, for instance if t or v is + # antisymmetric. + v(i, j, a, b)*t(a, b, i, j), + v(j, i, a, b)*t(a, b, i, j), + v(i, j, b, a)*t(a, b, i, j), + v(j, i, b, a)*t(a, b, i, j), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) == dums(permut) + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + + exprs = [ + # permute t. + v(i, j, a, b)*t(a, b, i, j), + v(i, j, a, b)*t(b, a, i, j), + v(i, j, a, b)*t(a, b, j, i), + v(i, j, a, b)*t(b, a, j, i), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + + exprs = [ # permute v and t. Relabelling of dummies should be equivalent. + v(i, j, a, b)*t(a, b, i, j), + v(j, i, a, b)*t(a, b, j, i), + v(i, j, b, a)*t(b, a, i, j), + v(j, i, b, a)*t(b, a, j, i), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_internal_external_VT2T2(): + ii, jj = symbols('i j', below_fermi=True) + aa, bb = symbols('a b', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) + + v = Function('v') + t = Function('t') + dums = _get_ordered_dummies + + exprs = [ + v(k, l, c, d)*t(aa, c, ii, k)*t(bb, d, jj, l), + v(l, k, c, d)*t(aa, c, ii, l)*t(bb, d, jj, k), + v(k, l, d, c)*t(aa, d, ii, k)*t(bb, c, jj, l), + v(l, k, d, c)*t(aa, d, ii, l)*t(bb, c, jj, k), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + exprs = [ + v(k, l, c, d)*t(aa, c, ii, k)*t(d, bb, jj, l), + v(l, k, c, d)*t(aa, c, ii, l)*t(d, bb, jj, k), + v(k, l, d, c)*t(aa, d, ii, k)*t(c, bb, jj, l), + v(l, k, d, c)*t(aa, d, ii, l)*t(c, bb, jj, k), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + exprs = [ + v(k, l, c, d)*t(c, aa, ii, k)*t(bb, d, jj, l), + v(l, k, c, d)*t(c, aa, ii, l)*t(bb, d, jj, k), + v(k, l, d, c)*t(d, aa, ii, k)*t(bb, c, jj, l), + v(l, k, d, c)*t(d, aa, ii, l)*t(bb, c, jj, k), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_internal_external_pqrs(): + ii, jj = symbols('i j') + aa, bb = symbols('a b') + k, l = symbols('k l', cls=Dummy) + c, d = symbols('c d', cls=Dummy) + + v = Function('v') + t = Function('t') + dums = _get_ordered_dummies + + exprs = [ + v(k, l, c, d)*t(aa, c, ii, k)*t(bb, d, jj, l), + v(l, k, c, d)*t(aa, c, ii, l)*t(bb, d, jj, k), + v(k, l, d, c)*t(aa, d, ii, k)*t(bb, c, jj, l), + v(l, k, d, c)*t(aa, d, ii, l)*t(bb, c, jj, k), + ] + for permut in exprs[1:]: + assert dums(exprs[0]) != dums(permut) + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_dummy_order_well_defined(): + aa, bb = symbols('a b', above_fermi=True) + k, l, m = symbols('k l m', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) + p, q = symbols('p q', cls=Dummy) + + A = Function('A') + B = Function('B') + C = Function('C') + dums = _get_ordered_dummies + + # We go through all key components in the order of increasing priority, + # and consider only fully orderable expressions. Non-orderable expressions + # are tested elsewhere. + + # pos in first factor determines sort order + assert dums(A(k, l)*B(l, k)) == [k, l] + assert dums(A(l, k)*B(l, k)) == [l, k] + assert dums(A(k, l)*B(k, l)) == [k, l] + assert dums(A(l, k)*B(k, l)) == [l, k] + + # factors involving the index + assert dums(A(k, l)*B(l, m)*C(k, m)) == [l, k, m] + assert dums(A(k, l)*B(l, m)*C(m, k)) == [l, k, m] + assert dums(A(l, k)*B(l, m)*C(k, m)) == [l, k, m] + assert dums(A(l, k)*B(l, m)*C(m, k)) == [l, k, m] + assert dums(A(k, l)*B(m, l)*C(k, m)) == [l, k, m] + assert dums(A(k, l)*B(m, l)*C(m, k)) == [l, k, m] + assert dums(A(l, k)*B(m, l)*C(k, m)) == [l, k, m] + assert dums(A(l, k)*B(m, l)*C(m, k)) == [l, k, m] + + # same, but with factor order determined by non-dummies + assert dums(A(k, aa, l)*A(l, bb, m)*A(bb, k, m)) == [l, k, m] + assert dums(A(k, aa, l)*A(l, bb, m)*A(bb, m, k)) == [l, k, m] + assert dums(A(k, aa, l)*A(m, bb, l)*A(bb, k, m)) == [l, k, m] + assert dums(A(k, aa, l)*A(m, bb, l)*A(bb, m, k)) == [l, k, m] + assert dums(A(l, aa, k)*A(l, bb, m)*A(bb, k, m)) == [l, k, m] + assert dums(A(l, aa, k)*A(l, bb, m)*A(bb, m, k)) == [l, k, m] + assert dums(A(l, aa, k)*A(m, bb, l)*A(bb, k, m)) == [l, k, m] + assert dums(A(l, aa, k)*A(m, bb, l)*A(bb, m, k)) == [l, k, m] + + # index range + assert dums(A(p, c, k)*B(p, c, k)) == [k, c, p] + assert dums(A(p, k, c)*B(p, c, k)) == [k, c, p] + assert dums(A(c, k, p)*B(p, c, k)) == [k, c, p] + assert dums(A(c, p, k)*B(p, c, k)) == [k, c, p] + assert dums(A(k, c, p)*B(p, c, k)) == [k, c, p] + assert dums(A(k, p, c)*B(p, c, k)) == [k, c, p] + assert dums(B(p, c, k)*A(p, c, k)) == [k, c, p] + assert dums(B(p, k, c)*A(p, c, k)) == [k, c, p] + assert dums(B(c, k, p)*A(p, c, k)) == [k, c, p] + assert dums(B(c, p, k)*A(p, c, k)) == [k, c, p] + assert dums(B(k, c, p)*A(p, c, k)) == [k, c, p] + assert dums(B(k, p, c)*A(p, c, k)) == [k, c, p] + + +def test_dummy_order_ambiguous(): + aa, bb = symbols('a b', above_fermi=True) + i, j, k, l, m = symbols('i j k l m', below_fermi=True, cls=Dummy) + a, b, c, d, e = symbols('a b c d e', above_fermi=True, cls=Dummy) + p, q = symbols('p q', cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + p5, p6, p7, p8 = symbols('p5 p6 p7 p8', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) + h5, h6, h7, h8 = symbols('h5 h6 h7 h8', below_fermi=True, cls=Dummy) + + A = Function('A') + B = Function('B') + + from sympy.utilities.iterables import variations + + # A*A*A*A*B -- ordering of p5 and p4 is used to figure out the rest + template = A(p1, p2)*A(p4, p1)*A(p2, p3)*A(p3, p5)*B(p5, p4) + permutator = variations([a, b, c, d, e], 5) + base = template.subs(zip([p1, p2, p3, p4, p5], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4, p5], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + + # A*A*A*A*A -- an arbitrary index is assigned and the rest are figured out + template = A(p1, p2)*A(p4, p1)*A(p2, p3)*A(p3, p5)*A(p5, p4) + permutator = variations([a, b, c, d, e], 5) + base = template.subs(zip([p1, p2, p3, p4, p5], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4, p5], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + + # A*A*A -- ordering of p5 and p4 is used to figure out the rest + template = A(p1, p2, p4, p1)*A(p2, p3, p3, p5)*A(p5, p4) + permutator = variations([a, b, c, d, e], 5) + base = template.subs(zip([p1, p2, p3, p4, p5], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4, p5], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + + +def atv(*args): + return AntiSymmetricTensor('v', args[:2], args[2:] ) + + +def att(*args): + if len(args) == 4: + return AntiSymmetricTensor('t', args[:2], args[2:] ) + elif len(args) == 2: + return AntiSymmetricTensor('t', (args[0],), (args[1],)) + + +def test_dummy_order_inner_outer_lines_VT1T1T1_AT(): + ii = symbols('i', below_fermi=True) + aa = symbols('a', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) + + # Coupled-Cluster T1 terms with V*T1*T1*T1 + # t^{a}_{k} t^{c}_{i} t^{d}_{l} v^{lk}_{dc} + exprs = [ + # permut v and t <=> swapping internal lines, equivalent + # irrespective of symmetries in v + atv(k, l, c, d)*att(c, ii)*att(d, l)*att(aa, k), + atv(l, k, c, d)*att(c, ii)*att(d, k)*att(aa, l), + atv(k, l, d, c)*att(d, ii)*att(c, l)*att(aa, k), + atv(l, k, d, c)*att(d, ii)*att(c, k)*att(aa, l), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_dummy_order_inner_outer_lines_VT1T1T1T1_AT(): + ii, jj = symbols('i j', below_fermi=True) + aa, bb = symbols('a b', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) + + # Coupled-Cluster T2 terms with V*T1*T1*T1*T1 + # non-equivalent substitutions (change of sign) + exprs = [ + # permut t <=> swapping external lines + atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(aa, k)*att(bb, l), + atv(k, l, c, d)*att(c, jj)*att(d, ii)*att(aa, k)*att(bb, l), + atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(bb, k)*att(aa, l), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == -substitute_dummies(permut) + + # equivalent substitutions + exprs = [ + atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(aa, k)*att(bb, l), + # permut t <=> swapping external lines + atv(k, l, c, d)*att(c, jj)*att(d, ii)*att(bb, k)*att(aa, l), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_equivalent_internal_lines_VT1T1_AT(): + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) + + exprs = [ # permute v. Different dummy order. Not equivalent. + atv(i, j, a, b)*att(a, i)*att(b, j), + atv(j, i, a, b)*att(a, i)*att(b, j), + atv(i, j, b, a)*att(a, i)*att(b, j), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + + exprs = [ # permute v. Different dummy order. Equivalent + atv(i, j, a, b)*att(a, i)*att(b, j), + atv(j, i, b, a)*att(a, i)*att(b, j), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + exprs = [ # permute t. Same dummy order, not equivalent. + atv(i, j, a, b)*att(a, i)*att(b, j), + atv(i, j, a, b)*att(b, i)*att(a, j), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + + exprs = [ # permute v and t. Different dummy order, equivalent + atv(i, j, a, b)*att(a, i)*att(b, j), + atv(j, i, a, b)*att(a, j)*att(b, i), + atv(i, j, b, a)*att(b, i)*att(a, j), + atv(j, i, b, a)*att(b, j)*att(a, i), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_equivalent_internal_lines_VT2conjT2_AT(): + # this diagram requires special handling in TCE + i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) + a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) + + from sympy.utilities.iterables import variations + + # atv(abcd)att(abij)att(ijcd) + template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(i, j, p3, p4) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(j, i, p3, p4) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + + # atv(abcd)att(abij)att(jicd) + template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(j, i, p3, p4) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(i, j, p3, p4) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + + +def test_equivalent_internal_lines_VT2conjT2_ambiguous_order_AT(): + # These diagrams invokes _determine_ambiguous() because the + # dummies can not be ordered unambiguously by the key alone + i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) + a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) + + from sympy.utilities.iterables import variations + + # atv(abcd)att(abij)att(cdij) + template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(p3, p4, i, j) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(p3, p4, i, j) + permutator = variations([a, b, c, d], 4) + base = template.subs(zip([p1, p2, p3, p4], next(permutator))) + for permut in permutator: + subslist = zip([p1, p2, p3, p4], permut) + expr = template.subs(subslist) + assert substitute_dummies(expr) == substitute_dummies(base) + + +def test_equivalent_internal_lines_VT2_AT(): + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) + + exprs = [ + # permute v. Same dummy order, not equivalent. + atv(i, j, a, b)*att(a, b, i, j), + atv(j, i, a, b)*att(a, b, i, j), + atv(i, j, b, a)*att(a, b, i, j), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + + exprs = [ + # permute t. + atv(i, j, a, b)*att(a, b, i, j), + atv(i, j, a, b)*att(b, a, i, j), + atv(i, j, a, b)*att(a, b, j, i), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) != substitute_dummies(permut) + + exprs = [ # permute v and t. Relabelling of dummies should be equivalent. + atv(i, j, a, b)*att(a, b, i, j), + atv(j, i, a, b)*att(a, b, j, i), + atv(i, j, b, a)*att(b, a, i, j), + atv(j, i, b, a)*att(b, a, j, i), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_internal_external_VT2T2_AT(): + ii, jj = symbols('i j', below_fermi=True) + aa, bb = symbols('a b', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) + + exprs = [ + atv(k, l, c, d)*att(aa, c, ii, k)*att(bb, d, jj, l), + atv(l, k, c, d)*att(aa, c, ii, l)*att(bb, d, jj, k), + atv(k, l, d, c)*att(aa, d, ii, k)*att(bb, c, jj, l), + atv(l, k, d, c)*att(aa, d, ii, l)*att(bb, c, jj, k), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + exprs = [ + atv(k, l, c, d)*att(aa, c, ii, k)*att(d, bb, jj, l), + atv(l, k, c, d)*att(aa, c, ii, l)*att(d, bb, jj, k), + atv(k, l, d, c)*att(aa, d, ii, k)*att(c, bb, jj, l), + atv(l, k, d, c)*att(aa, d, ii, l)*att(c, bb, jj, k), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + exprs = [ + atv(k, l, c, d)*att(c, aa, ii, k)*att(bb, d, jj, l), + atv(l, k, c, d)*att(c, aa, ii, l)*att(bb, d, jj, k), + atv(k, l, d, c)*att(d, aa, ii, k)*att(bb, c, jj, l), + atv(l, k, d, c)*att(d, aa, ii, l)*att(bb, c, jj, k), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_internal_external_pqrs_AT(): + ii, jj = symbols('i j') + aa, bb = symbols('a b') + k, l = symbols('k l', cls=Dummy) + c, d = symbols('c d', cls=Dummy) + + exprs = [ + atv(k, l, c, d)*att(aa, c, ii, k)*att(bb, d, jj, l), + atv(l, k, c, d)*att(aa, c, ii, l)*att(bb, d, jj, k), + atv(k, l, d, c)*att(aa, d, ii, k)*att(bb, c, jj, l), + atv(l, k, d, c)*att(aa, d, ii, l)*att(bb, c, jj, k), + ] + for permut in exprs[1:]: + assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + + +def test_issue_19661(): + a = Symbol('0') + assert latex(Commutator(Bd(a)**2, B(a)) + ) == '- \\left[b_{0},{b^\\dagger_{0}}^{2}\\right]' + + +def test_canonical_ordering_AntiSymmetricTensor(): + v = symbols("v") + + c, d = symbols(('c','d'), above_fermi=True, + cls=Dummy) + k, l = symbols(('k','l'), below_fermi=True, + cls=Dummy) + + # formerly, the left gave either the left or the right + assert AntiSymmetricTensor(v, (k, l), (d, c) + ) == -AntiSymmetricTensor(v, (l, k), (d, c)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_sho.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_sho.py new file mode 100644 index 0000000000000000000000000000000000000000..7248838b4bb9ad280fd4211bbe208063b65adcf5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/test_sho.py @@ -0,0 +1,21 @@ +from sympy.core import symbols, Rational, Function, diff +from sympy.physics.sho import R_nl, E_nl +from sympy.simplify.simplify import simplify + + +def test_sho_R_nl(): + omega, r = symbols('omega r') + l = symbols('l', integer=True) + u = Function('u') + + # check that it obeys the Schrodinger equation + for n in range(5): + schreq = ( -diff(u(r), r, 2)/2 + ((l*(l + 1))/(2*r**2) + + omega**2*r**2/2 - E_nl(n, l, omega))*u(r) ) + result = schreq.subs(u(r), r*R_nl(n, l, omega/2, r)) + assert simplify(result.doit()) == 0 + + +def test_energy(): + n, l, hw = symbols('n l hw') + assert simplify(E_nl(n, l, hw) - (2*n + l + Rational(3, 2))*hw) == 0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bf17c7f3051b03d9c0fc794d9d79885c94cc878e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__init__.py @@ -0,0 +1,453 @@ +# isort:skip_file +""" +Dimensional analysis and unit systems. + +This module defines dimension/unit systems and physical quantities. It is +based on a group-theoretical construction where dimensions are represented as +vectors (coefficients being the exponents), and units are defined as a dimension +to which we added a scale. + +Quantities are built from a factor and a unit, and are the basic objects that +one will use when doing computations. + +All objects except systems and prefixes can be used in SymPy expressions. +Note that as part of a CAS, various objects do not combine automatically +under operations. + +Details about the implementation can be found in the documentation, and we +will not repeat all the explanations we gave there concerning our approach. +Ideas about future developments can be found on the `Github wiki +`_, and you should consult +this page if you are willing to help. + +Useful functions: + +- ``find_unit``: easily lookup pre-defined units. +- ``convert_to(expr, newunit)``: converts an expression into the same + expression expressed in another unit. + +""" + +from .dimensions import Dimension, DimensionSystem +from .unitsystem import UnitSystem +from .util import convert_to +from .quantities import Quantity + +from .definitions.dimension_definitions import ( + amount_of_substance, acceleration, action, area, + capacitance, charge, conductance, current, energy, + force, frequency, impedance, inductance, length, + luminous_intensity, magnetic_density, + magnetic_flux, mass, momentum, power, pressure, temperature, time, + velocity, voltage, volume +) + +Unit = Quantity + +speed = velocity +luminosity = luminous_intensity +magnetic_flux_density = magnetic_density +amount = amount_of_substance + +from .prefixes import ( + # 10-power based: + yotta, + zetta, + exa, + peta, + tera, + giga, + mega, + kilo, + hecto, + deca, + deci, + centi, + milli, + micro, + nano, + pico, + femto, + atto, + zepto, + yocto, + # 2-power based: + kibi, + mebi, + gibi, + tebi, + pebi, + exbi, +) + +from .definitions import ( + percent, percents, + permille, + rad, radian, radians, + deg, degree, degrees, + sr, steradian, steradians, + mil, angular_mil, angular_mils, + m, meter, meters, + kg, kilogram, kilograms, + s, second, seconds, + A, ampere, amperes, + K, kelvin, kelvins, + mol, mole, moles, + cd, candela, candelas, + g, gram, grams, + mg, milligram, milligrams, + ug, microgram, micrograms, + t, tonne, metric_ton, + newton, newtons, N, + joule, joules, J, + watt, watts, W, + pascal, pascals, Pa, pa, + hertz, hz, Hz, + coulomb, coulombs, C, + volt, volts, v, V, + ohm, ohms, + siemens, S, mho, mhos, + farad, farads, F, + henry, henrys, H, + tesla, teslas, T, + weber, webers, Wb, wb, + optical_power, dioptre, D, + lux, lx, + katal, kat, + gray, Gy, + becquerel, Bq, + km, kilometer, kilometers, + dm, decimeter, decimeters, + cm, centimeter, centimeters, + mm, millimeter, millimeters, + um, micrometer, micrometers, micron, microns, + nm, nanometer, nanometers, + pm, picometer, picometers, + ft, foot, feet, + inch, inches, + yd, yard, yards, + mi, mile, miles, + nmi, nautical_mile, nautical_miles, + angstrom, angstroms, + ha, hectare, + l, L, liter, liters, + dl, dL, deciliter, deciliters, + cl, cL, centiliter, centiliters, + ml, mL, milliliter, milliliters, + ms, millisecond, milliseconds, + us, microsecond, microseconds, + ns, nanosecond, nanoseconds, + ps, picosecond, picoseconds, + minute, minutes, + h, hour, hours, + day, days, + anomalistic_year, anomalistic_years, + sidereal_year, sidereal_years, + tropical_year, tropical_years, + common_year, common_years, + julian_year, julian_years, + draconic_year, draconic_years, + gaussian_year, gaussian_years, + full_moon_cycle, full_moon_cycles, + year, years, + G, gravitational_constant, + c, speed_of_light, + elementary_charge, + hbar, + planck, + eV, electronvolt, electronvolts, + avogadro_number, + avogadro, avogadro_constant, + boltzmann, boltzmann_constant, + stefan, stefan_boltzmann_constant, + R, molar_gas_constant, + faraday_constant, + josephson_constant, + von_klitzing_constant, + Da, dalton, amu, amus, atomic_mass_unit, atomic_mass_constant, + me, electron_rest_mass, + gee, gees, acceleration_due_to_gravity, + u0, magnetic_constant, vacuum_permeability, + e0, electric_constant, vacuum_permittivity, + Z0, vacuum_impedance, + coulomb_constant, electric_force_constant, + atmosphere, atmospheres, atm, + kPa, + bar, bars, + pound, pounds, + psi, + dHg0, + mmHg, torr, + mmu, mmus, milli_mass_unit, + quart, quarts, + ly, lightyear, lightyears, + au, astronomical_unit, astronomical_units, + planck_mass, + planck_time, + planck_temperature, + planck_length, + planck_charge, + planck_area, + planck_volume, + planck_momentum, + planck_energy, + planck_force, + planck_power, + planck_density, + planck_energy_density, + planck_intensity, + planck_angular_frequency, + planck_pressure, + planck_current, + planck_voltage, + planck_impedance, + planck_acceleration, + bit, bits, + byte, + kibibyte, kibibytes, + mebibyte, mebibytes, + gibibyte, gibibytes, + tebibyte, tebibytes, + pebibyte, pebibytes, + exbibyte, exbibytes, +) + +from .systems import ( + mks, mksa, si +) + + +def find_unit(quantity, unit_system="SI"): + """ + Return a list of matching units or dimension names. + + - If ``quantity`` is a string -- units/dimensions containing the string + `quantity`. + - If ``quantity`` is a unit or dimension -- units having matching base + units or dimensions. + + Examples + ======== + + >>> from sympy.physics import units as u + >>> u.find_unit('charge') + ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge'] + >>> u.find_unit(u.charge) + ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge'] + >>> u.find_unit("ampere") + ['ampere', 'amperes'] + >>> u.find_unit('angstrom') + ['angstrom', 'angstroms'] + >>> u.find_unit('volt') + ['volt', 'volts', 'electronvolt', 'electronvolts', 'planck_voltage'] + >>> u.find_unit(u.inch**3)[:9] + ['L', 'l', 'cL', 'cl', 'dL', 'dl', 'mL', 'ml', 'liter'] + """ + unit_system = UnitSystem.get_unit_system(unit_system) + + import sympy.physics.units as u + rv = [] + if isinstance(quantity, str): + rv = [i for i in dir(u) if quantity in i and isinstance(getattr(u, i), Quantity)] + dim = getattr(u, quantity) + if isinstance(dim, Dimension): + rv.extend(find_unit(dim)) + else: + for i in sorted(dir(u)): + other = getattr(u, i) + if not isinstance(other, Quantity): + continue + if isinstance(quantity, Quantity): + if quantity.dimension == other.dimension: + rv.append(str(i)) + elif isinstance(quantity, Dimension): + if other.dimension == quantity: + rv.append(str(i)) + elif other.dimension == Dimension(unit_system.get_dimensional_expr(quantity)): + rv.append(str(i)) + return sorted(set(rv), key=lambda x: (len(x), x)) + +# NOTE: the old units module had additional variables: +# 'density', 'illuminance', 'resistance'. +# They were not dimensions, but units (old Unit class). + +__all__ = [ + 'Dimension', 'DimensionSystem', + 'UnitSystem', + 'convert_to', + 'Quantity', + + 'amount_of_substance', 'acceleration', 'action', 'area', + 'capacitance', 'charge', 'conductance', 'current', 'energy', + 'force', 'frequency', 'impedance', 'inductance', 'length', + 'luminous_intensity', 'magnetic_density', + 'magnetic_flux', 'mass', 'momentum', 'power', 'pressure', 'temperature', 'time', + 'velocity', 'voltage', 'volume', + + 'Unit', + + 'speed', + 'luminosity', + 'magnetic_flux_density', + 'amount', + + 'yotta', + 'zetta', + 'exa', + 'peta', + 'tera', + 'giga', + 'mega', + 'kilo', + 'hecto', + 'deca', + 'deci', + 'centi', + 'milli', + 'micro', + 'nano', + 'pico', + 'femto', + 'atto', + 'zepto', + 'yocto', + + 'kibi', + 'mebi', + 'gibi', + 'tebi', + 'pebi', + 'exbi', + + 'percent', 'percents', + 'permille', + 'rad', 'radian', 'radians', + 'deg', 'degree', 'degrees', + 'sr', 'steradian', 'steradians', + 'mil', 'angular_mil', 'angular_mils', + 'm', 'meter', 'meters', + 'kg', 'kilogram', 'kilograms', + 's', 'second', 'seconds', + 'A', 'ampere', 'amperes', + 'K', 'kelvin', 'kelvins', + 'mol', 'mole', 'moles', + 'cd', 'candela', 'candelas', + 'g', 'gram', 'grams', + 'mg', 'milligram', 'milligrams', + 'ug', 'microgram', 'micrograms', + 't', 'tonne', 'metric_ton', + 'newton', 'newtons', 'N', + 'joule', 'joules', 'J', + 'watt', 'watts', 'W', + 'pascal', 'pascals', 'Pa', 'pa', + 'hertz', 'hz', 'Hz', + 'coulomb', 'coulombs', 'C', + 'volt', 'volts', 'v', 'V', + 'ohm', 'ohms', + 'siemens', 'S', 'mho', 'mhos', + 'farad', 'farads', 'F', + 'henry', 'henrys', 'H', + 'tesla', 'teslas', 'T', + 'weber', 'webers', 'Wb', 'wb', + 'optical_power', 'dioptre', 'D', + 'lux', 'lx', + 'katal', 'kat', + 'gray', 'Gy', + 'becquerel', 'Bq', + 'km', 'kilometer', 'kilometers', + 'dm', 'decimeter', 'decimeters', + 'cm', 'centimeter', 'centimeters', + 'mm', 'millimeter', 'millimeters', + 'um', 'micrometer', 'micrometers', 'micron', 'microns', + 'nm', 'nanometer', 'nanometers', + 'pm', 'picometer', 'picometers', + 'ft', 'foot', 'feet', + 'inch', 'inches', + 'yd', 'yard', 'yards', + 'mi', 'mile', 'miles', + 'nmi', 'nautical_mile', 'nautical_miles', + 'angstrom', 'angstroms', + 'ha', 'hectare', + 'l', 'L', 'liter', 'liters', + 'dl', 'dL', 'deciliter', 'deciliters', + 'cl', 'cL', 'centiliter', 'centiliters', + 'ml', 'mL', 'milliliter', 'milliliters', + 'ms', 'millisecond', 'milliseconds', + 'us', 'microsecond', 'microseconds', + 'ns', 'nanosecond', 'nanoseconds', + 'ps', 'picosecond', 'picoseconds', + 'minute', 'minutes', + 'h', 'hour', 'hours', + 'day', 'days', + 'anomalistic_year', 'anomalistic_years', + 'sidereal_year', 'sidereal_years', + 'tropical_year', 'tropical_years', + 'common_year', 'common_years', + 'julian_year', 'julian_years', + 'draconic_year', 'draconic_years', + 'gaussian_year', 'gaussian_years', + 'full_moon_cycle', 'full_moon_cycles', + 'year', 'years', + 'G', 'gravitational_constant', + 'c', 'speed_of_light', + 'elementary_charge', + 'hbar', + 'planck', + 'eV', 'electronvolt', 'electronvolts', + 'avogadro_number', + 'avogadro', 'avogadro_constant', + 'boltzmann', 'boltzmann_constant', + 'stefan', 'stefan_boltzmann_constant', + 'R', 'molar_gas_constant', + 'faraday_constant', + 'josephson_constant', + 'von_klitzing_constant', + 'Da', 'dalton', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant', + 'me', 'electron_rest_mass', + 'gee', 'gees', 'acceleration_due_to_gravity', + 'u0', 'magnetic_constant', 'vacuum_permeability', + 'e0', 'electric_constant', 'vacuum_permittivity', + 'Z0', 'vacuum_impedance', + 'coulomb_constant', 'electric_force_constant', + 'atmosphere', 'atmospheres', 'atm', + 'kPa', + 'bar', 'bars', + 'pound', 'pounds', + 'psi', + 'dHg0', + 'mmHg', 'torr', + 'mmu', 'mmus', 'milli_mass_unit', + 'quart', 'quarts', + 'ly', 'lightyear', 'lightyears', + 'au', 'astronomical_unit', 'astronomical_units', + 'planck_mass', + 'planck_time', + 'planck_temperature', + 'planck_length', + 'planck_charge', + 'planck_area', + 'planck_volume', + 'planck_momentum', + 'planck_energy', + 'planck_force', + 'planck_power', + 'planck_density', + 'planck_energy_density', + 'planck_intensity', + 'planck_angular_frequency', + 'planck_pressure', + 'planck_current', + 'planck_voltage', + 'planck_impedance', + 'planck_acceleration', + 'bit', 'bits', + 'byte', + 'kibibyte', 'kibibytes', + 'mebibyte', 'mebibytes', + 'gibibyte', 'gibibytes', + 'tebibyte', 'tebibytes', + 'pebibyte', 'pebibytes', + 'exbibyte', 'exbibytes', + + 'mks', 'mksa', 'si', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/dimensions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/dimensions.py new file mode 100644 index 0000000000000000000000000000000000000000..de42912edca025a6cb53d457fd3e03d8fa30931e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/dimensions.py @@ -0,0 +1,590 @@ +""" +Definition of physical dimensions. + +Unit systems will be constructed on top of these dimensions. + +Most of the examples in the doc use MKS system and are presented from the +computer point of view: from a human point, adding length to time is not legal +in MKS but it is in natural system; for a computer in natural system there is +no time dimension (but a velocity dimension instead) - in the basis - so the +question of adding time to length has no meaning. +""" + +from __future__ import annotations + +import collections +from functools import reduce + +from sympy.core.basic import Basic +from sympy.core.containers import (Dict, Tuple) +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.matrices.dense import Matrix +from sympy.functions.elementary.trigonometric import TrigonometricFunction +from sympy.core.expr import Expr +from sympy.core.power import Pow + + +class _QuantityMapper: + + _quantity_scale_factors_global: dict[Expr, Expr] = {} + _quantity_dimensional_equivalence_map_global: dict[Expr, Expr] = {} + _quantity_dimension_global: dict[Expr, Expr] = {} + + def __init__(self, *args, **kwargs): + self._quantity_dimension_map = {} + self._quantity_scale_factors = {} + + def set_quantity_dimension(self, quantity, dimension): + """ + Set the dimension for the quantity in a unit system. + + If this relation is valid in every unit system, use + ``quantity.set_global_dimension(dimension)`` instead. + """ + from sympy.physics.units import Quantity + dimension = sympify(dimension) + if not isinstance(dimension, Dimension): + if dimension == 1: + dimension = Dimension(1) + else: + raise ValueError("expected dimension or 1") + elif isinstance(dimension, Quantity): + dimension = self.get_quantity_dimension(dimension) + self._quantity_dimension_map[quantity] = dimension + + def set_quantity_scale_factor(self, quantity, scale_factor): + """ + Set the scale factor of a quantity relative to another quantity. + + It should be used only once per quantity to just one other quantity, + the algorithm will then be able to compute the scale factors to all + other quantities. + + In case the scale factor is valid in every unit system, please use + ``quantity.set_global_relative_scale_factor(scale_factor)`` instead. + """ + from sympy.physics.units import Quantity + from sympy.physics.units.prefixes import Prefix + scale_factor = sympify(scale_factor) + # replace all prefixes by their ratio to canonical units: + scale_factor = scale_factor.replace( + lambda x: isinstance(x, Prefix), + lambda x: x.scale_factor + ) + # replace all quantities by their ratio to canonical units: + scale_factor = scale_factor.replace( + lambda x: isinstance(x, Quantity), + lambda x: self.get_quantity_scale_factor(x) + ) + self._quantity_scale_factors[quantity] = scale_factor + + def get_quantity_dimension(self, unit): + from sympy.physics.units import Quantity + # First look-up the local dimension map, then the global one: + if unit in self._quantity_dimension_map: + return self._quantity_dimension_map[unit] + if unit in self._quantity_dimension_global: + return self._quantity_dimension_global[unit] + if unit in self._quantity_dimensional_equivalence_map_global: + dep_unit = self._quantity_dimensional_equivalence_map_global[unit] + if isinstance(dep_unit, Quantity): + return self.get_quantity_dimension(dep_unit) + else: + return Dimension(self.get_dimensional_expr(dep_unit)) + if isinstance(unit, Quantity): + return Dimension(unit.name) + else: + return Dimension(1) + + def get_quantity_scale_factor(self, unit): + if unit in self._quantity_scale_factors: + return self._quantity_scale_factors[unit] + if unit in self._quantity_scale_factors_global: + mul_factor, other_unit = self._quantity_scale_factors_global[unit] + return mul_factor*self.get_quantity_scale_factor(other_unit) + return S.One + + +class Dimension(Expr): + """ + This class represent the dimension of a physical quantities. + + The ``Dimension`` constructor takes as parameters a name and an optional + symbol. + + For example, in classical mechanics we know that time is different from + temperature and dimensions make this difference (but they do not provide + any measure of these quantities. + + >>> from sympy.physics.units import Dimension + >>> length = Dimension('length') + >>> length + Dimension(length) + >>> time = Dimension('time') + >>> time + Dimension(time) + + Dimensions can be composed using multiplication, division and + exponentiation (by a number) to give new dimensions. Addition and + subtraction is defined only when the two objects are the same dimension. + + >>> velocity = length / time + >>> velocity + Dimension(length/time) + + It is possible to use a dimension system object to get the dimensionsal + dependencies of a dimension, for example the dimension system used by the + SI units convention can be used: + + >>> from sympy.physics.units.systems.si import dimsys_SI + >>> dimsys_SI.get_dimensional_dependencies(velocity) + {Dimension(length, L): 1, Dimension(time, T): -1} + >>> length + length + Dimension(length) + >>> l2 = length**2 + >>> l2 + Dimension(length**2) + >>> dimsys_SI.get_dimensional_dependencies(l2) + {Dimension(length, L): 2} + + """ + + _op_priority = 13.0 + + # XXX: This doesn't seem to be used anywhere... + _dimensional_dependencies = {} # type: ignore + + is_commutative = True + is_number = False + # make sqrt(M**2) --> M + is_positive = True + is_real = True + + def __new__(cls, name, symbol=None): + + if isinstance(name, str): + name = Symbol(name) + else: + name = sympify(name) + + if not isinstance(name, Expr): + raise TypeError("Dimension name needs to be a valid math expression") + + if isinstance(symbol, str): + symbol = Symbol(symbol) + elif symbol is not None: + assert isinstance(symbol, Symbol) + + obj = Expr.__new__(cls, name) + + obj._name = name + obj._symbol = symbol + return obj + + @property + def name(self): + return self._name + + @property + def symbol(self): + return self._symbol + + def __str__(self): + """ + Display the string representation of the dimension. + """ + if self.symbol is None: + return "Dimension(%s)" % (self.name) + else: + return "Dimension(%s, %s)" % (self.name, self.symbol) + + def __repr__(self): + return self.__str__() + + def __neg__(self): + return self + + def __add__(self, other): + from sympy.physics.units.quantities import Quantity + other = sympify(other) + if isinstance(other, Basic): + if other.has(Quantity): + raise TypeError("cannot sum dimension and quantity") + if isinstance(other, Dimension) and self == other: + return self + return super().__add__(other) + return self + + def __radd__(self, other): + return self.__add__(other) + + def __sub__(self, other): + # there is no notion of ordering (or magnitude) among dimension, + # subtraction is equivalent to addition when the operation is legal + return self + other + + def __rsub__(self, other): + # there is no notion of ordering (or magnitude) among dimension, + # subtraction is equivalent to addition when the operation is legal + return self + other + + def __pow__(self, other): + return self._eval_power(other) + + def _eval_power(self, other): + other = sympify(other) + return Dimension(self.name**other) + + def __mul__(self, other): + from sympy.physics.units.quantities import Quantity + if isinstance(other, Basic): + if other.has(Quantity): + raise TypeError("cannot sum dimension and quantity") + if isinstance(other, Dimension): + return Dimension(self.name*other.name) + if not other.free_symbols: # other.is_number cannot be used + return self + return super().__mul__(other) + return self + + def __rmul__(self, other): + return self.__mul__(other) + + def __truediv__(self, other): + return self*Pow(other, -1) + + def __rtruediv__(self, other): + return other * pow(self, -1) + + @classmethod + def _from_dimensional_dependencies(cls, dependencies): + return reduce(lambda x, y: x * y, ( + d**e for d, e in dependencies.items() + ), 1) + + def has_integer_powers(self, dim_sys): + """ + Check if the dimension object has only integer powers. + + All the dimension powers should be integers, but rational powers may + appear in intermediate steps. This method may be used to check that the + final result is well-defined. + """ + + return all(dpow.is_Integer for dpow in dim_sys.get_dimensional_dependencies(self).values()) + + +# Create dimensions according to the base units in MKSA. +# For other unit systems, they can be derived by transforming the base +# dimensional dependency dictionary. + + +class DimensionSystem(Basic, _QuantityMapper): + r""" + DimensionSystem represents a coherent set of dimensions. + + The constructor takes three parameters: + + - base dimensions; + - derived dimensions: these are defined in terms of the base dimensions + (for example velocity is defined from the division of length by time); + - dependency of dimensions: how the derived dimensions depend + on the base dimensions. + + Optionally either the ``derived_dims`` or the ``dimensional_dependencies`` + may be omitted. + """ + + def __new__(cls, base_dims, derived_dims=(), dimensional_dependencies={}): + dimensional_dependencies = dict(dimensional_dependencies) + + def parse_dim(dim): + if isinstance(dim, str): + dim = Dimension(Symbol(dim)) + elif isinstance(dim, Dimension): + pass + elif isinstance(dim, Symbol): + dim = Dimension(dim) + else: + raise TypeError("%s wrong type" % dim) + return dim + + base_dims = [parse_dim(i) for i in base_dims] + derived_dims = [parse_dim(i) for i in derived_dims] + + for dim in base_dims: + if (dim in dimensional_dependencies + and (len(dimensional_dependencies[dim]) != 1 or + dimensional_dependencies[dim].get(dim, None) != 1)): + raise IndexError("Repeated value in base dimensions") + dimensional_dependencies[dim] = Dict({dim: 1}) + + def parse_dim_name(dim): + if isinstance(dim, Dimension): + return dim + elif isinstance(dim, str): + return Dimension(Symbol(dim)) + elif isinstance(dim, Symbol): + return Dimension(dim) + else: + raise TypeError("unrecognized type %s for %s" % (type(dim), dim)) + + for dim in dimensional_dependencies.keys(): + dim = parse_dim(dim) + if (dim not in derived_dims) and (dim not in base_dims): + derived_dims.append(dim) + + def parse_dict(d): + return Dict({parse_dim_name(i): j for i, j in d.items()}) + + # Make sure everything is a SymPy type: + dimensional_dependencies = {parse_dim_name(i): parse_dict(j) for i, j in + dimensional_dependencies.items()} + + for dim in derived_dims: + if dim in base_dims: + raise ValueError("Dimension %s both in base and derived" % dim) + if dim not in dimensional_dependencies: + # TODO: should this raise a warning? + dimensional_dependencies[dim] = Dict({dim: 1}) + + base_dims.sort(key=default_sort_key) + derived_dims.sort(key=default_sort_key) + + base_dims = Tuple(*base_dims) + derived_dims = Tuple(*derived_dims) + dimensional_dependencies = Dict({i: Dict(j) for i, j in dimensional_dependencies.items()}) + obj = Basic.__new__(cls, base_dims, derived_dims, dimensional_dependencies) + return obj + + @property + def base_dims(self): + return self.args[0] + + @property + def derived_dims(self): + return self.args[1] + + @property + def dimensional_dependencies(self): + return self.args[2] + + def _get_dimensional_dependencies_for_name(self, dimension): + if isinstance(dimension, str): + dimension = Dimension(Symbol(dimension)) + elif not isinstance(dimension, Dimension): + dimension = Dimension(dimension) + + if dimension.name.is_Symbol: + # Dimensions not included in the dependencies are considered + # as base dimensions: + return dict(self.dimensional_dependencies.get(dimension, {dimension: 1})) + + if dimension.name.is_number or dimension.name.is_NumberSymbol: + return {} + + get_for_name = self._get_dimensional_dependencies_for_name + + if dimension.name.is_Mul: + ret = collections.defaultdict(int) + dicts = [get_for_name(i) for i in dimension.name.args] + for d in dicts: + for k, v in d.items(): + ret[k] += v + return {k: v for (k, v) in ret.items() if v != 0} + + if dimension.name.is_Add: + dicts = [get_for_name(i) for i in dimension.name.args] + if all(d == dicts[0] for d in dicts[1:]): + return dicts[0] + raise TypeError("Only equivalent dimensions can be added or subtracted.") + + if dimension.name.is_Pow: + dim_base = get_for_name(dimension.name.base) + dim_exp = get_for_name(dimension.name.exp) + if dim_exp == {} or dimension.name.exp.is_Symbol: + return {k: v * dimension.name.exp for (k, v) in dim_base.items()} + else: + raise TypeError("The exponent for the power operator must be a Symbol or dimensionless.") + + if dimension.name.is_Function: + args = (Dimension._from_dimensional_dependencies( + get_for_name(arg)) for arg in dimension.name.args) + result = dimension.name.func(*args) + + dicts = [get_for_name(i) for i in dimension.name.args] + + if isinstance(result, Dimension): + return self.get_dimensional_dependencies(result) + elif result.func == dimension.name.func: + if isinstance(dimension.name, TrigonometricFunction): + if dicts[0] in ({}, {Dimension('angle'): 1}): + return {} + else: + raise TypeError("The input argument for the function {} must be dimensionless or have dimensions of angle.".format(dimension.func)) + else: + if all(item == {} for item in dicts): + return {} + else: + raise TypeError("The input arguments for the function {} must be dimensionless.".format(dimension.func)) + else: + return get_for_name(result) + + raise TypeError("Type {} not implemented for get_dimensional_dependencies".format(type(dimension.name))) + + def get_dimensional_dependencies(self, name, mark_dimensionless=False): + dimdep = self._get_dimensional_dependencies_for_name(name) + if mark_dimensionless and dimdep == {}: + return {Dimension(1): 1} + return dict(dimdep.items()) + + def equivalent_dims(self, dim1, dim2): + deps1 = self.get_dimensional_dependencies(dim1) + deps2 = self.get_dimensional_dependencies(dim2) + return deps1 == deps2 + + def extend(self, new_base_dims, new_derived_dims=(), new_dim_deps=None): + deps = dict(self.dimensional_dependencies) + if new_dim_deps: + deps.update(new_dim_deps) + + new_dim_sys = DimensionSystem( + tuple(self.base_dims) + tuple(new_base_dims), + tuple(self.derived_dims) + tuple(new_derived_dims), + deps + ) + new_dim_sys._quantity_dimension_map.update(self._quantity_dimension_map) + new_dim_sys._quantity_scale_factors.update(self._quantity_scale_factors) + return new_dim_sys + + def is_dimensionless(self, dimension): + """ + Check if the dimension object really has a dimension. + + A dimension should have at least one component with non-zero power. + """ + if dimension.name == 1: + return True + return self.get_dimensional_dependencies(dimension) == {} + + @property + def list_can_dims(self): + """ + Useless method, kept for compatibility with previous versions. + + DO NOT USE. + + List all canonical dimension names. + """ + dimset = set() + for i in self.base_dims: + dimset.update(set(self.get_dimensional_dependencies(i).keys())) + return tuple(sorted(dimset, key=str)) + + @property + def inv_can_transf_matrix(self): + """ + Useless method, kept for compatibility with previous versions. + + DO NOT USE. + + Compute the inverse transformation matrix from the base to the + canonical dimension basis. + + It corresponds to the matrix where columns are the vector of base + dimensions in canonical basis. + + This matrix will almost never be used because dimensions are always + defined with respect to the canonical basis, so no work has to be done + to get them in this basis. Nonetheless if this matrix is not square + (or not invertible) it means that we have chosen a bad basis. + """ + matrix = reduce(lambda x, y: x.row_join(y), + [self.dim_can_vector(d) for d in self.base_dims]) + return matrix + + @property + def can_transf_matrix(self): + """ + Useless method, kept for compatibility with previous versions. + + DO NOT USE. + + Return the canonical transformation matrix from the canonical to the + base dimension basis. + + It is the inverse of the matrix computed with inv_can_transf_matrix(). + """ + + #TODO: the inversion will fail if the system is inconsistent, for + # example if the matrix is not a square + return reduce(lambda x, y: x.row_join(y), + [self.dim_can_vector(d) for d in sorted(self.base_dims, key=str)] + ).inv() + + def dim_can_vector(self, dim): + """ + Useless method, kept for compatibility with previous versions. + + DO NOT USE. + + Dimensional representation in terms of the canonical base dimensions. + """ + + vec = [] + for d in self.list_can_dims: + vec.append(self.get_dimensional_dependencies(dim).get(d, 0)) + return Matrix(vec) + + def dim_vector(self, dim): + """ + Useless method, kept for compatibility with previous versions. + + DO NOT USE. + + + Vector representation in terms of the base dimensions. + """ + return self.can_transf_matrix * Matrix(self.dim_can_vector(dim)) + + def print_dim_base(self, dim): + """ + Give the string expression of a dimension in term of the basis symbols. + """ + dims = self.dim_vector(dim) + symbols = [i.symbol if i.symbol is not None else i.name for i in self.base_dims] + res = S.One + for (s, p) in zip(symbols, dims): + res *= s**p + return res + + @property + def dim(self): + """ + Useless method, kept for compatibility with previous versions. + + DO NOT USE. + + Give the dimension of the system. + + That is return the number of dimensions forming the basis. + """ + return len(self.base_dims) + + @property + def is_consistent(self): + """ + Useless method, kept for compatibility with previous versions. + + DO NOT USE. + + Check if the system is well defined. + """ + + # not enough or too many base dimensions compared to independent + # dimensions + # in vector language: the set of vectors do not form a basis + return self.inv_can_transf_matrix.is_square diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/prefixes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/prefixes.py new file mode 100644 index 0000000000000000000000000000000000000000..44fd7cb9efe4b1d6307810af6b9cd140817126f9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/prefixes.py @@ -0,0 +1,219 @@ +""" +Module defining unit prefixe class and some constants. + +Constant dict for SI and binary prefixes are defined as PREFIXES and +BIN_PREFIXES. +""" +from sympy.core.expr import Expr +from sympy.core.sympify import sympify +from sympy.core.singleton import S + +class Prefix(Expr): + """ + This class represent prefixes, with their name, symbol and factor. + + Prefixes are used to create derived units from a given unit. They should + always be encapsulated into units. + + The factor is constructed from a base (default is 10) to some power, and + it gives the total multiple or fraction. For example the kilometer km + is constructed from the meter (factor 1) and the kilo (10 to the power 3, + i.e. 1000). The base can be changed to allow e.g. binary prefixes. + + A prefix multiplied by something will always return the product of this + other object times the factor, except if the other object: + + - is a prefix and they can be combined into a new prefix; + - defines multiplication with prefixes (which is the case for the Unit + class). + """ + _op_priority = 13.0 + is_commutative = True + + def __new__(cls, name, abbrev, exponent, base=sympify(10), latex_repr=None): + + name = sympify(name) + abbrev = sympify(abbrev) + exponent = sympify(exponent) + base = sympify(base) + + obj = Expr.__new__(cls, name, abbrev, exponent, base) + obj._name = name + obj._abbrev = abbrev + obj._scale_factor = base**exponent + obj._exponent = exponent + obj._base = base + obj._latex_repr = latex_repr + return obj + + @property + def name(self): + return self._name + + @property + def abbrev(self): + return self._abbrev + + @property + def scale_factor(self): + return self._scale_factor + + def _latex(self, printer): + if self._latex_repr is None: + return r'\text{%s}' % self._abbrev + return self._latex_repr + + @property + def base(self): + return self._base + + def __str__(self): + return str(self._abbrev) + + def __repr__(self): + if self.base == 10: + return "Prefix(%r, %r, %r)" % ( + str(self.name), str(self.abbrev), self._exponent) + else: + return "Prefix(%r, %r, %r, %r)" % ( + str(self.name), str(self.abbrev), self._exponent, self.base) + + def __mul__(self, other): + from sympy.physics.units import Quantity + if not isinstance(other, (Quantity, Prefix)): + return super().__mul__(other) + + fact = self.scale_factor * other.scale_factor + + if isinstance(other, Prefix): + if fact == 1: + return S.One + # simplify prefix + for p in PREFIXES: + if PREFIXES[p].scale_factor == fact: + return PREFIXES[p] + return fact + + return self.scale_factor * other + + def __truediv__(self, other): + if not hasattr(other, "scale_factor"): + return super().__truediv__(other) + + fact = self.scale_factor / other.scale_factor + + if fact == 1: + return S.One + elif isinstance(other, Prefix): + for p in PREFIXES: + if PREFIXES[p].scale_factor == fact: + return PREFIXES[p] + return fact + + return self.scale_factor / other + + def __rtruediv__(self, other): + if other == 1: + for p in PREFIXES: + if PREFIXES[p].scale_factor == 1 / self.scale_factor: + return PREFIXES[p] + return other / self.scale_factor + + +def prefix_unit(unit, prefixes): + """ + Return a list of all units formed by unit and the given prefixes. + + You can use the predefined PREFIXES or BIN_PREFIXES, but you can also + pass as argument a subdict of them if you do not want all prefixed units. + + >>> from sympy.physics.units.prefixes import (PREFIXES, + ... prefix_unit) + >>> from sympy.physics.units import m + >>> pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]} + >>> prefix_unit(m, pref) # doctest: +SKIP + [millimeter, centimeter, decimeter] + """ + + from sympy.physics.units.quantities import Quantity + from sympy.physics.units import UnitSystem + + prefixed_units = [] + + for prefix in prefixes.values(): + quantity = Quantity( + "%s%s" % (prefix.name, unit.name), + abbrev=("%s%s" % (prefix.abbrev, unit.abbrev)), + is_prefixed=True, + ) + UnitSystem._quantity_dimensional_equivalence_map_global[quantity] = unit + UnitSystem._quantity_scale_factors_global[quantity] = (prefix.scale_factor, unit) + prefixed_units.append(quantity) + + return prefixed_units + + +yotta = Prefix('yotta', 'Y', 24) +zetta = Prefix('zetta', 'Z', 21) +exa = Prefix('exa', 'E', 18) +peta = Prefix('peta', 'P', 15) +tera = Prefix('tera', 'T', 12) +giga = Prefix('giga', 'G', 9) +mega = Prefix('mega', 'M', 6) +kilo = Prefix('kilo', 'k', 3) +hecto = Prefix('hecto', 'h', 2) +deca = Prefix('deca', 'da', 1) +deci = Prefix('deci', 'd', -1) +centi = Prefix('centi', 'c', -2) +milli = Prefix('milli', 'm', -3) +micro = Prefix('micro', 'mu', -6, latex_repr=r"\mu") +nano = Prefix('nano', 'n', -9) +pico = Prefix('pico', 'p', -12) +femto = Prefix('femto', 'f', -15) +atto = Prefix('atto', 'a', -18) +zepto = Prefix('zepto', 'z', -21) +yocto = Prefix('yocto', 'y', -24) + + +# https://physics.nist.gov/cuu/Units/prefixes.html +PREFIXES = { + 'Y': yotta, + 'Z': zetta, + 'E': exa, + 'P': peta, + 'T': tera, + 'G': giga, + 'M': mega, + 'k': kilo, + 'h': hecto, + 'da': deca, + 'd': deci, + 'c': centi, + 'm': milli, + 'mu': micro, + 'n': nano, + 'p': pico, + 'f': femto, + 'a': atto, + 'z': zepto, + 'y': yocto, +} + + +kibi = Prefix('kibi', 'Y', 10, 2) +mebi = Prefix('mebi', 'Y', 20, 2) +gibi = Prefix('gibi', 'Y', 30, 2) +tebi = Prefix('tebi', 'Y', 40, 2) +pebi = Prefix('pebi', 'Y', 50, 2) +exbi = Prefix('exbi', 'Y', 60, 2) + + +# https://physics.nist.gov/cuu/Units/binary.html +BIN_PREFIXES = { + 'Ki': kibi, + 'Mi': mebi, + 'Gi': gibi, + 'Ti': tebi, + 'Pi': pebi, + 'Ei': exbi, +} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/quantities.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/quantities.py new file mode 100644 index 0000000000000000000000000000000000000000..cc19e72aea83b5bd8ae7cf2f63dd49388a3815ee --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/quantities.py @@ -0,0 +1,152 @@ +""" +Physical quantities. +""" + +from sympy.core.expr import AtomicExpr +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.physics.units.dimensions import _QuantityMapper +from sympy.physics.units.prefixes import Prefix + + +class Quantity(AtomicExpr): + """ + Physical quantity: can be a unit of measure, a constant or a generic quantity. + """ + + is_commutative = True + is_real = True + is_number = False + is_nonzero = True + is_physical_constant = False + _diff_wrt = True + + def __new__(cls, name, abbrev=None, + latex_repr=None, pretty_unicode_repr=None, + pretty_ascii_repr=None, mathml_presentation_repr=None, + is_prefixed=False, + **assumptions): + + if not isinstance(name, Symbol): + name = Symbol(name) + + if abbrev is None: + abbrev = name + elif isinstance(abbrev, str): + abbrev = Symbol(abbrev) + + # HACK: These are here purely for type checking. They actually get assigned below. + cls._is_prefixed = is_prefixed + + obj = AtomicExpr.__new__(cls, name, abbrev) + obj._name = name + obj._abbrev = abbrev + obj._latex_repr = latex_repr + obj._unicode_repr = pretty_unicode_repr + obj._ascii_repr = pretty_ascii_repr + obj._mathml_repr = mathml_presentation_repr + obj._is_prefixed = is_prefixed + return obj + + def set_global_dimension(self, dimension): + _QuantityMapper._quantity_dimension_global[self] = dimension + + def set_global_relative_scale_factor(self, scale_factor, reference_quantity): + """ + Setting a scale factor that is valid across all unit system. + """ + from sympy.physics.units import UnitSystem + scale_factor = sympify(scale_factor) + if isinstance(scale_factor, Prefix): + self._is_prefixed = True + # replace all prefixes by their ratio to canonical units: + scale_factor = scale_factor.replace( + lambda x: isinstance(x, Prefix), + lambda x: x.scale_factor + ) + scale_factor = sympify(scale_factor) + UnitSystem._quantity_scale_factors_global[self] = (scale_factor, reference_quantity) + UnitSystem._quantity_dimensional_equivalence_map_global[self] = reference_quantity + + @property + def name(self): + return self._name + + @property + def dimension(self): + from sympy.physics.units import UnitSystem + unit_system = UnitSystem.get_default_unit_system() + return unit_system.get_quantity_dimension(self) + + @property + def abbrev(self): + """ + Symbol representing the unit name. + + Prepend the abbreviation with the prefix symbol if it is defines. + """ + return self._abbrev + + @property + def scale_factor(self): + """ + Overall magnitude of the quantity as compared to the canonical units. + """ + from sympy.physics.units import UnitSystem + unit_system = UnitSystem.get_default_unit_system() + return unit_system.get_quantity_scale_factor(self) + + def _eval_is_positive(self): + return True + + def _eval_is_constant(self): + return True + + def _eval_Abs(self): + return self + + def _eval_subs(self, old, new): + if isinstance(new, Quantity) and self != old: + return self + + def _latex(self, printer): + if self._latex_repr: + return self._latex_repr + else: + return r'\text{{{}}}'.format(self.args[1] \ + if len(self.args) >= 2 else self.args[0]) + + def convert_to(self, other, unit_system="SI"): + """ + Convert the quantity to another quantity of same dimensions. + + Examples + ======== + + >>> from sympy.physics.units import speed_of_light, meter, second + >>> speed_of_light + speed_of_light + >>> speed_of_light.convert_to(meter/second) + 299792458*meter/second + + >>> from sympy.physics.units import liter + >>> liter.convert_to(meter**3) + meter**3/1000 + """ + from .util import convert_to + return convert_to(self, other, unit_system) + + @property + def free_symbols(self): + """Return free symbols from quantity.""" + return set() + + @property + def is_prefixed(self): + """Whether or not the quantity is prefixed. Eg. `kilogram` is prefixed, but `gram` is not.""" + return self._is_prefixed + +class PhysicalConstant(Quantity): + """Represents a physical constant, eg. `speed_of_light` or `avogadro_constant`.""" + + is_physical_constant = True diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/unitsystem.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/unitsystem.py new file mode 100644 index 0000000000000000000000000000000000000000..795f8026e9df7236fdb2abf882043a843797219d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/unitsystem.py @@ -0,0 +1,204 @@ +""" +Unit system for physical quantities; include definition of constants. +""" +from __future__ import annotations + +from sympy.core.add import Add +from sympy.core.function import (Derivative, Function) +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.physics.units.dimensions import _QuantityMapper +from sympy.physics.units.quantities import Quantity + +from .dimensions import Dimension + + +class UnitSystem(_QuantityMapper): + """ + UnitSystem represents a coherent set of units. + + A unit system is basically a dimension system with notions of scales. Many + of the methods are defined in the same way. + + It is much better if all base units have a symbol. + """ + + _unit_systems: dict[str, UnitSystem] = {} + + def __init__(self, base_units, units=(), name="", descr="", dimension_system=None, derived_units: dict[Dimension, Quantity]={}): + + UnitSystem._unit_systems[name] = self + + self.name = name + self.descr = descr + + self._base_units = base_units + self._dimension_system = dimension_system + self._units = tuple(set(base_units) | set(units)) + self._base_units = tuple(base_units) + self._derived_units = derived_units + + super().__init__() + + def __str__(self): + """ + Return the name of the system. + + If it does not exist, then it makes a list of symbols (or names) of + the base dimensions. + """ + + if self.name != "": + return self.name + else: + return "UnitSystem((%s))" % ", ".join( + str(d) for d in self._base_units) + + def __repr__(self): + return '' % repr(self._base_units) + + def extend(self, base, units=(), name="", description="", dimension_system=None, derived_units: dict[Dimension, Quantity]={}): + """Extend the current system into a new one. + + Take the base and normal units of the current system to merge + them to the base and normal units given in argument. + If not provided, name and description are overridden by empty strings. + """ + + base = self._base_units + tuple(base) + units = self._units + tuple(units) + + return UnitSystem(base, units, name, description, dimension_system, {**self._derived_units, **derived_units}) + + def get_dimension_system(self): + return self._dimension_system + + def get_quantity_dimension(self, unit): + qdm = self.get_dimension_system()._quantity_dimension_map + if unit in qdm: + return qdm[unit] + return super().get_quantity_dimension(unit) + + def get_quantity_scale_factor(self, unit): + qsfm = self.get_dimension_system()._quantity_scale_factors + if unit in qsfm: + return qsfm[unit] + return super().get_quantity_scale_factor(unit) + + @staticmethod + def get_unit_system(unit_system): + if isinstance(unit_system, UnitSystem): + return unit_system + + if unit_system not in UnitSystem._unit_systems: + raise ValueError( + "Unit system is not supported. Currently" + "supported unit systems are {}".format( + ", ".join(sorted(UnitSystem._unit_systems)) + ) + ) + + return UnitSystem._unit_systems[unit_system] + + @staticmethod + def get_default_unit_system(): + return UnitSystem._unit_systems["SI"] + + @property + def dim(self): + """ + Give the dimension of the system. + + That is return the number of units forming the basis. + """ + return len(self._base_units) + + @property + def is_consistent(self): + """ + Check if the underlying dimension system is consistent. + """ + # test is performed in DimensionSystem + return self.get_dimension_system().is_consistent + + @property + def derived_units(self) -> dict[Dimension, Quantity]: + return self._derived_units + + def get_dimensional_expr(self, expr): + from sympy.physics.units import Quantity + if isinstance(expr, Mul): + return Mul(*[self.get_dimensional_expr(i) for i in expr.args]) + elif isinstance(expr, Pow): + return self.get_dimensional_expr(expr.base) ** expr.exp + elif isinstance(expr, Add): + return self.get_dimensional_expr(expr.args[0]) + elif isinstance(expr, Derivative): + dim = self.get_dimensional_expr(expr.expr) + for independent, count in expr.variable_count: + dim /= self.get_dimensional_expr(independent)**count + return dim + elif isinstance(expr, Function): + args = [self.get_dimensional_expr(arg) for arg in expr.args] + if all(i == 1 for i in args): + return S.One + return expr.func(*args) + elif isinstance(expr, Quantity): + return self.get_quantity_dimension(expr).name + return S.One + + def _collect_factor_and_dimension(self, expr): + """ + Return tuple with scale factor expression and dimension expression. + """ + from sympy.physics.units import Quantity + if isinstance(expr, Quantity): + return expr.scale_factor, expr.dimension + elif isinstance(expr, Mul): + factor = 1 + dimension = Dimension(1) + for arg in expr.args: + arg_factor, arg_dim = self._collect_factor_and_dimension(arg) + factor *= arg_factor + dimension *= arg_dim + return factor, dimension + elif isinstance(expr, Pow): + factor, dim = self._collect_factor_and_dimension(expr.base) + exp_factor, exp_dim = self._collect_factor_and_dimension(expr.exp) + if self.get_dimension_system().is_dimensionless(exp_dim): + exp_dim = 1 + return factor ** exp_factor, dim ** (exp_factor * exp_dim) + elif isinstance(expr, Add): + factor, dim = self._collect_factor_and_dimension(expr.args[0]) + for addend in expr.args[1:]: + addend_factor, addend_dim = \ + self._collect_factor_and_dimension(addend) + if not self.get_dimension_system().equivalent_dims(dim, addend_dim): + raise ValueError( + 'Dimension of "{}" is {}, ' + 'but it should be {}'.format( + addend, addend_dim, dim)) + factor += addend_factor + return factor, dim + elif isinstance(expr, Derivative): + factor, dim = self._collect_factor_and_dimension(expr.args[0]) + for independent, count in expr.variable_count: + ifactor, idim = self._collect_factor_and_dimension(independent) + factor /= ifactor**count + dim /= idim**count + return factor, dim + elif isinstance(expr, Function): + fds = [self._collect_factor_and_dimension(arg) for arg in expr.args] + dims = [Dimension(1) if self.get_dimension_system().is_dimensionless(d[1]) else d[1] for d in fds] + return (expr.func(*(f[0] for f in fds)), *dims) + elif isinstance(expr, Dimension): + return S.One, expr + else: + return expr, Dimension(1) + + def get_units_non_prefixed(self) -> set[Quantity]: + """ + Return the units of the system that do not have a prefix. + """ + return set(filter(lambda u: not u.is_prefixed and not u.is_physical_constant, self._units)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/util.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/util.py new file mode 100644 index 0000000000000000000000000000000000000000..ccd6300acdb1a3c60b74076d4700e7f699ca46f5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/util.py @@ -0,0 +1,265 @@ +""" +Several methods to simplify expressions involving unit objects. +""" +from functools import reduce +from collections.abc import Iterable +from typing import Optional + +from sympy import default_sort_key +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.sorting import ordered +from sympy.core.sympify import sympify +from sympy.core.function import Function +from sympy.matrices.exceptions import NonInvertibleMatrixError +from sympy.physics.units.dimensions import Dimension, DimensionSystem +from sympy.physics.units.prefixes import Prefix +from sympy.physics.units.quantities import Quantity +from sympy.physics.units.unitsystem import UnitSystem +from sympy.utilities.iterables import sift + + +def _get_conversion_matrix_for_expr(expr, target_units, unit_system): + from sympy.matrices.dense import Matrix + + dimension_system = unit_system.get_dimension_system() + + expr_dim = Dimension(unit_system.get_dimensional_expr(expr)) + dim_dependencies = dimension_system.get_dimensional_dependencies(expr_dim, mark_dimensionless=True) + target_dims = [Dimension(unit_system.get_dimensional_expr(x)) for x in target_units] + canon_dim_units = [i for x in target_dims for i in dimension_system.get_dimensional_dependencies(x, mark_dimensionless=True)] + canon_expr_units = set(dim_dependencies) + + if not canon_expr_units.issubset(set(canon_dim_units)): + return None + + seen = set() + canon_dim_units = [i for i in canon_dim_units if not (i in seen or seen.add(i))] + + camat = Matrix([[dimension_system.get_dimensional_dependencies(i, mark_dimensionless=True).get(j, 0) for i in target_dims] for j in canon_dim_units]) + exprmat = Matrix([dim_dependencies.get(k, 0) for k in canon_dim_units]) + + try: + res_exponents = camat.solve(exprmat) + except NonInvertibleMatrixError: + return None + + return res_exponents + + +def convert_to(expr, target_units, unit_system="SI"): + """ + Convert ``expr`` to the same expression with all of its units and quantities + represented as factors of ``target_units``, whenever the dimension is compatible. + + ``target_units`` may be a single unit/quantity, or a collection of + units/quantities. + + Examples + ======== + + >>> from sympy.physics.units import speed_of_light, meter, gram, second, day + >>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant + >>> from sympy.physics.units import kilometer, centimeter + >>> from sympy.physics.units import gravitational_constant, hbar + >>> from sympy.physics.units import convert_to + >>> convert_to(mile, kilometer) + 25146*kilometer/15625 + >>> convert_to(mile, kilometer).n() + 1.609344*kilometer + >>> convert_to(speed_of_light, meter/second) + 299792458*meter/second + >>> convert_to(day, second) + 86400*second + >>> 3*newton + 3*newton + >>> convert_to(3*newton, kilogram*meter/second**2) + 3*kilogram*meter/second**2 + >>> convert_to(atomic_mass_constant, gram) + 1.660539060e-24*gram + + Conversion to multiple units: + + >>> convert_to(speed_of_light, [meter, second]) + 299792458*meter/second + >>> convert_to(3*newton, [centimeter, gram, second]) + 300000*centimeter*gram/second**2 + + Conversion to Planck units: + + >>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n() + 7.62963087839509e-20*hbar**0.5*speed_of_light**0.5/gravitational_constant**0.5 + + """ + from sympy.physics.units import UnitSystem + unit_system = UnitSystem.get_unit_system(unit_system) + + if not isinstance(target_units, (Iterable, Tuple)): + target_units = [target_units] + + def handle_Adds(expr): + return Add.fromiter(convert_to(i, target_units, unit_system) + for i in expr.args) + + if isinstance(expr, Add): + return handle_Adds(expr) + elif isinstance(expr, Pow) and isinstance(expr.base, Add): + return handle_Adds(expr.base) ** expr.exp + + expr = sympify(expr) + target_units = sympify(target_units) + + if isinstance(expr, Function): + expr = expr.together() + + if not isinstance(expr, Quantity) and expr.has(Quantity): + expr = expr.replace(lambda x: isinstance(x, Quantity), + lambda x: x.convert_to(target_units, unit_system)) + + def get_total_scale_factor(expr): + if isinstance(expr, Mul): + return reduce(lambda x, y: x * y, + [get_total_scale_factor(i) for i in expr.args]) + elif isinstance(expr, Pow): + return get_total_scale_factor(expr.base) ** expr.exp + elif isinstance(expr, Quantity): + return unit_system.get_quantity_scale_factor(expr) + return expr + + depmat = _get_conversion_matrix_for_expr(expr, target_units, unit_system) + if depmat is None: + return expr + + expr_scale_factor = get_total_scale_factor(expr) + return expr_scale_factor * Mul.fromiter( + (1/get_total_scale_factor(u)*u)**p for u, p in + zip(target_units, depmat)) + + +def quantity_simplify(expr, across_dimensions: bool=False, unit_system=None): + """Return an equivalent expression in which prefixes are replaced + with numerical values and all units of a given dimension are the + unified in a canonical manner by default. `across_dimensions` allows + for units of different dimensions to be simplified together. + + `unit_system` must be specified if `across_dimensions` is True. + + Examples + ======== + + >>> from sympy.physics.units.util import quantity_simplify + >>> from sympy.physics.units.prefixes import kilo + >>> from sympy.physics.units import foot, inch, joule, coulomb + >>> quantity_simplify(kilo*foot*inch) + 250*foot**2/3 + >>> quantity_simplify(foot - 6*inch) + foot/2 + >>> quantity_simplify(5*joule/coulomb, across_dimensions=True, unit_system="SI") + 5*volt + """ + + if expr.is_Atom or not expr.has(Prefix, Quantity): + return expr + + # replace all prefixes with numerical values + p = expr.atoms(Prefix) + expr = expr.xreplace({p: p.scale_factor for p in p}) + + # replace all quantities of given dimension with a canonical + # quantity, chosen from those in the expression + d = sift(expr.atoms(Quantity), lambda i: i.dimension) + for k in d: + if len(d[k]) == 1: + continue + v = list(ordered(d[k])) + ref = v[0]/v[0].scale_factor + expr = expr.xreplace({vi: ref*vi.scale_factor for vi in v[1:]}) + + if across_dimensions: + # combine quantities of different dimensions into a single + # quantity that is equivalent to the original expression + + if unit_system is None: + raise ValueError("unit_system must be specified if across_dimensions is True") + + unit_system = UnitSystem.get_unit_system(unit_system) + dimension_system: DimensionSystem = unit_system.get_dimension_system() + dim_expr = unit_system.get_dimensional_expr(expr) + dim_deps = dimension_system.get_dimensional_dependencies(dim_expr, mark_dimensionless=True) + + target_dimension: Optional[Dimension] = None + for ds_dim, ds_dim_deps in dimension_system.dimensional_dependencies.items(): + if ds_dim_deps == dim_deps: + target_dimension = ds_dim + break + + if target_dimension is None: + # if we can't find a target dimension, we can't do anything. unsure how to handle this case. + return expr + + target_unit = unit_system.derived_units.get(target_dimension) + if target_unit: + expr = convert_to(expr, target_unit, unit_system) + + return expr + + +def check_dimensions(expr, unit_system="SI"): + """Return expr if units in addends have the same + base dimensions, else raise a ValueError.""" + # the case of adding a number to a dimensional quantity + # is ignored for the sake of SymPy core routines, so this + # function will raise an error now if such an addend is + # found. + # Also, when doing substitutions, multiplicative constants + # might be introduced, so remove those now + + from sympy.physics.units import UnitSystem + unit_system = UnitSystem.get_unit_system(unit_system) + + def addDict(dict1, dict2): + """Merge dictionaries by adding values of common keys and + removing keys with value of 0.""" + dict3 = {**dict1, **dict2} + for key, value in dict3.items(): + if key in dict1 and key in dict2: + dict3[key] = value + dict1[key] + return {key:val for key, val in dict3.items() if val != 0} + + adds = expr.atoms(Add) + DIM_OF = unit_system.get_dimension_system().get_dimensional_dependencies + for a in adds: + deset = set() + for ai in a.args: + if ai.is_number: + deset.add(()) + continue + dims = [] + skip = False + dimdict = {} + for i in Mul.make_args(ai): + if i.has(Quantity): + i = Dimension(unit_system.get_dimensional_expr(i)) + if i.has(Dimension): + dimdict = addDict(dimdict, DIM_OF(i)) + elif i.free_symbols: + skip = True + break + dims.extend(dimdict.items()) + if not skip: + deset.add(tuple(sorted(dims, key=default_sort_key))) + if len(deset) > 1: + raise ValueError( + "addends have incompatible dimensions: {}".format(deset)) + + # clear multiplicative constants on Dimensions which may be + # left after substitution + reps = {} + for m in expr.atoms(Mul): + if any(isinstance(i, Dimension) for i in m.args): + reps[m] = m.func(*[ + i for i in m.args if not i.is_number]) + + return expr.xreplace(reps) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e714852064c0b940ebda2e5fe7a08faf13f07ed0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__init__.py @@ -0,0 +1,36 @@ +__all__ = [ + 'CoordinateSym', 'ReferenceFrame', + + 'Dyadic', + + 'Vector', + + 'Point', + + 'cross', 'dot', 'express', 'time_derivative', 'outer', + 'kinematic_equations', 'get_motion_params', 'partial_velocity', + 'dynamicsymbols', + + 'vprint', 'vsstrrepr', 'vsprint', 'vpprint', 'vlatex', 'init_vprinting', + + 'curl', 'divergence', 'gradient', 'is_conservative', 'is_solenoidal', + 'scalar_potential', 'scalar_potential_difference', + +] +from .frame import CoordinateSym, ReferenceFrame + +from .dyadic import Dyadic + +from .vector import Vector + +from .point import Point + +from .functions import (cross, dot, express, time_derivative, outer, + kinematic_equations, get_motion_params, partial_velocity, + dynamicsymbols) + +from .printing import (vprint, vsstrrepr, vsprint, vpprint, vlatex, + init_vprinting) + +from .fieldfunctions import (curl, divergence, gradient, is_conservative, + is_solenoidal, scalar_potential, scalar_potential_difference) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/dyadic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/dyadic.py new file mode 100644 index 0000000000000000000000000000000000000000..0adacab2c2be5a287f59b6944206a07398a5fb9d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/dyadic.py @@ -0,0 +1,545 @@ +from sympy import sympify, Add, ImmutableMatrix as Matrix +from sympy.core.evalf import EvalfMixin +from sympy.printing.defaults import Printable + +from mpmath.libmp.libmpf import prec_to_dps + + +__all__ = ['Dyadic'] + + +class Dyadic(Printable, EvalfMixin): + """A Dyadic object. + + See: + https://en.wikipedia.org/wiki/Dyadic_tensor + Kane, T., Levinson, D. Dynamics Theory and Applications. 1985 McGraw-Hill + + A more powerful way to represent a rigid body's inertia. While it is more + complex, by choosing Dyadic components to be in body fixed basis vectors, + the resulting matrix is equivalent to the inertia tensor. + + """ + + is_number = False + + def __init__(self, inlist): + """ + Just like Vector's init, you should not call this unless creating a + zero dyadic. + + zd = Dyadic(0) + + Stores a Dyadic as a list of lists; the inner list has the measure + number and the two unit vectors; the outerlist holds each unique + unit vector pair. + + """ + + self.args = [] + if inlist == 0: + inlist = [] + while len(inlist) != 0: + added = 0 + for i, v in enumerate(self.args): + if ((str(inlist[0][1]) == str(self.args[i][1])) and + (str(inlist[0][2]) == str(self.args[i][2]))): + self.args[i] = (self.args[i][0] + inlist[0][0], + inlist[0][1], inlist[0][2]) + inlist.remove(inlist[0]) + added = 1 + break + if added != 1: + self.args.append(inlist[0]) + inlist.remove(inlist[0]) + i = 0 + # This code is to remove empty parts from the list + while i < len(self.args): + if ((self.args[i][0] == 0) | (self.args[i][1] == 0) | + (self.args[i][2] == 0)): + self.args.remove(self.args[i]) + i -= 1 + i += 1 + + @property + def func(self): + """Returns the class Dyadic. """ + return Dyadic + + def __add__(self, other): + """The add operator for Dyadic. """ + other = _check_dyadic(other) + return Dyadic(self.args + other.args) + + __radd__ = __add__ + + def __mul__(self, other): + """Multiplies the Dyadic by a sympifyable expression. + + Parameters + ========== + + other : Sympafiable + The scalar to multiply this Dyadic with + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, outer + >>> N = ReferenceFrame('N') + >>> d = outer(N.x, N.x) + >>> 5 * d + 5*(N.x|N.x) + + """ + newlist = list(self.args) + other = sympify(other) + for i in range(len(newlist)): + newlist[i] = (other * newlist[i][0], newlist[i][1], + newlist[i][2]) + return Dyadic(newlist) + + __rmul__ = __mul__ + + def dot(self, other): + """The inner product operator for a Dyadic and a Dyadic or Vector. + + Parameters + ========== + + other : Dyadic or Vector + The other Dyadic or Vector to take the inner product with + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, outer + >>> N = ReferenceFrame('N') + >>> D1 = outer(N.x, N.y) + >>> D2 = outer(N.y, N.y) + >>> D1.dot(D2) + (N.x|N.y) + >>> D1.dot(N.y) + N.x + + """ + from sympy.physics.vector.vector import Vector, _check_vector + if isinstance(other, Dyadic): + other = _check_dyadic(other) + ol = Dyadic(0) + for v in self.args: + for v2 in other.args: + ol += v[0] * v2[0] * (v[2].dot(v2[1])) * (v[1].outer(v2[2])) + else: + other = _check_vector(other) + ol = Vector(0) + for v in self.args: + ol += v[0] * v[1] * (v[2].dot(other)) + return ol + + # NOTE : supports non-advertised Dyadic & Dyadic, Dyadic & Vector notation + __and__ = dot + + def __truediv__(self, other): + """Divides the Dyadic by a sympifyable expression. """ + return self.__mul__(1 / other) + + def __eq__(self, other): + """Tests for equality. + + Is currently weak; needs stronger comparison testing + + """ + + if other == 0: + other = Dyadic(0) + other = _check_dyadic(other) + if (self.args == []) and (other.args == []): + return True + elif (self.args == []) or (other.args == []): + return False + return set(self.args) == set(other.args) + + def __ne__(self, other): + return not self == other + + def __neg__(self): + return self * -1 + + def _latex(self, printer): + ar = self.args # just to shorten things + if len(ar) == 0: + return str(0) + ol = [] # output list, to be concatenated to a string + for v in ar: + # if the coef of the dyadic is 1, we skip the 1 + if v[0] == 1: + ol.append(' + ' + printer._print(v[1]) + r"\otimes " + + printer._print(v[2])) + # if the coef of the dyadic is -1, we skip the 1 + elif v[0] == -1: + ol.append(' - ' + + printer._print(v[1]) + + r"\otimes " + + printer._print(v[2])) + # If the coefficient of the dyadic is not 1 or -1, + # we might wrap it in parentheses, for readability. + elif v[0] != 0: + arg_str = printer._print(v[0]) + if isinstance(v[0], Add): + arg_str = '(%s)' % arg_str + if arg_str.startswith('-'): + arg_str = arg_str[1:] + str_start = ' - ' + else: + str_start = ' + ' + ol.append(str_start + arg_str + printer._print(v[1]) + + r"\otimes " + printer._print(v[2])) + outstr = ''.join(ol) + if outstr.startswith(' + '): + outstr = outstr[3:] + elif outstr.startswith(' '): + outstr = outstr[1:] + return outstr + + def _pretty(self, printer): + e = self + + class Fake: + baseline = 0 + + def render(self, *args, **kwargs): + ar = e.args # just to shorten things + mpp = printer + if len(ar) == 0: + return str(0) + bar = "\N{CIRCLED TIMES}" if printer._use_unicode else "|" + ol = [] # output list, to be concatenated to a string + for v in ar: + # if the coef of the dyadic is 1, we skip the 1 + if v[0] == 1: + ol.extend([" + ", + mpp.doprint(v[1]), + bar, + mpp.doprint(v[2])]) + + # if the coef of the dyadic is -1, we skip the 1 + elif v[0] == -1: + ol.extend([" - ", + mpp.doprint(v[1]), + bar, + mpp.doprint(v[2])]) + + # If the coefficient of the dyadic is not 1 or -1, + # we might wrap it in parentheses, for readability. + elif v[0] != 0: + if isinstance(v[0], Add): + arg_str = mpp._print( + v[0]).parens()[0] + else: + arg_str = mpp.doprint(v[0]) + if arg_str.startswith("-"): + arg_str = arg_str[1:] + str_start = " - " + else: + str_start = " + " + ol.extend([str_start, arg_str, " ", + mpp.doprint(v[1]), + bar, + mpp.doprint(v[2])]) + + outstr = "".join(ol) + if outstr.startswith(" + "): + outstr = outstr[3:] + elif outstr.startswith(" "): + outstr = outstr[1:] + return outstr + return Fake() + + def __rsub__(self, other): + return (-1 * self) + other + + def _sympystr(self, printer): + """Printing method. """ + ar = self.args # just to shorten things + if len(ar) == 0: + return printer._print(0) + ol = [] # output list, to be concatenated to a string + for v in ar: + # if the coef of the dyadic is 1, we skip the 1 + if v[0] == 1: + ol.append(' + (' + printer._print(v[1]) + '|' + + printer._print(v[2]) + ')') + # if the coef of the dyadic is -1, we skip the 1 + elif v[0] == -1: + ol.append(' - (' + printer._print(v[1]) + '|' + + printer._print(v[2]) + ')') + # If the coefficient of the dyadic is not 1 or -1, + # we might wrap it in parentheses, for readability. + elif v[0] != 0: + arg_str = printer._print(v[0]) + if isinstance(v[0], Add): + arg_str = "(%s)" % arg_str + if arg_str[0] == '-': + arg_str = arg_str[1:] + str_start = ' - ' + else: + str_start = ' + ' + ol.append(str_start + arg_str + '*(' + + printer._print(v[1]) + + '|' + printer._print(v[2]) + ')') + outstr = ''.join(ol) + if outstr.startswith(' + '): + outstr = outstr[3:] + elif outstr.startswith(' '): + outstr = outstr[1:] + return outstr + + def __sub__(self, other): + """The subtraction operator. """ + return self.__add__(other * -1) + + def cross(self, other): + """Returns the dyadic resulting from the dyadic vector cross product: + Dyadic x Vector. + + Parameters + ========== + other : Vector + Vector to cross with. + + Examples + ======== + >>> from sympy.physics.vector import ReferenceFrame, outer, cross + >>> N = ReferenceFrame('N') + >>> d = outer(N.x, N.x) + >>> cross(d, N.y) + (N.x|N.z) + + """ + from sympy.physics.vector.vector import _check_vector + other = _check_vector(other) + ol = Dyadic(0) + for v in self.args: + ol += v[0] * (v[1].outer((v[2].cross(other)))) + return ol + + # NOTE : supports non-advertised Dyadic ^ Vector notation + __xor__ = cross + + def express(self, frame1, frame2=None): + """Expresses this Dyadic in alternate frame(s) + + The first frame is the list side expression, the second frame is the + right side; if Dyadic is in form A.x|B.y, you can express it in two + different frames. If no second frame is given, the Dyadic is + expressed in only one frame. + + Calls the global express function + + Parameters + ========== + + frame1 : ReferenceFrame + The frame to express the left side of the Dyadic in + frame2 : ReferenceFrame + If provided, the frame to express the right side of the Dyadic in + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> N = ReferenceFrame('N') + >>> q = dynamicsymbols('q') + >>> B = N.orientnew('B', 'Axis', [q, N.z]) + >>> d = outer(N.x, N.x) + >>> d.express(B, N) + cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x) + + """ + from sympy.physics.vector.functions import express + return express(self, frame1, frame2) + + def to_matrix(self, reference_frame, second_reference_frame=None): + """Returns the matrix form of the dyadic with respect to one or two + reference frames. + + Parameters + ---------- + reference_frame : ReferenceFrame + The reference frame that the rows and columns of the matrix + correspond to. If a second reference frame is provided, this + only corresponds to the rows of the matrix. + second_reference_frame : ReferenceFrame, optional, default=None + The reference frame that the columns of the matrix correspond + to. + + Returns + ------- + matrix : ImmutableMatrix, shape(3,3) + The matrix that gives the 2D tensor form. + + Examples + ======== + + >>> from sympy import symbols, trigsimp + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy.physics.mechanics import inertia + >>> Ixx, Iyy, Izz, Ixy, Iyz, Ixz = symbols('Ixx, Iyy, Izz, Ixy, Iyz, Ixz') + >>> N = ReferenceFrame('N') + >>> inertia_dyadic = inertia(N, Ixx, Iyy, Izz, Ixy, Iyz, Ixz) + >>> inertia_dyadic.to_matrix(N) + Matrix([ + [Ixx, Ixy, Ixz], + [Ixy, Iyy, Iyz], + [Ixz, Iyz, Izz]]) + >>> beta = symbols('beta') + >>> A = N.orientnew('A', 'Axis', (beta, N.x)) + >>> trigsimp(inertia_dyadic.to_matrix(A)) + Matrix([ + [ Ixx, Ixy*cos(beta) + Ixz*sin(beta), -Ixy*sin(beta) + Ixz*cos(beta)], + [ Ixy*cos(beta) + Ixz*sin(beta), Iyy*cos(2*beta)/2 + Iyy/2 + Iyz*sin(2*beta) - Izz*cos(2*beta)/2 + Izz/2, -Iyy*sin(2*beta)/2 + Iyz*cos(2*beta) + Izz*sin(2*beta)/2], + [-Ixy*sin(beta) + Ixz*cos(beta), -Iyy*sin(2*beta)/2 + Iyz*cos(2*beta) + Izz*sin(2*beta)/2, -Iyy*cos(2*beta)/2 + Iyy/2 - Iyz*sin(2*beta) + Izz*cos(2*beta)/2 + Izz/2]]) + + """ + + if second_reference_frame is None: + second_reference_frame = reference_frame + + return Matrix([i.dot(self).dot(j) for i in reference_frame for j in + second_reference_frame]).reshape(3, 3) + + def doit(self, **hints): + """Calls .doit() on each term in the Dyadic""" + return sum([Dyadic([(v[0].doit(**hints), v[1], v[2])]) + for v in self.args], Dyadic(0)) + + def dt(self, frame): + """Take the time derivative of this Dyadic in a frame. + + This function calls the global time_derivative method + + Parameters + ========== + + frame : ReferenceFrame + The frame to take the time derivative in + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> N = ReferenceFrame('N') + >>> q = dynamicsymbols('q') + >>> B = N.orientnew('B', 'Axis', [q, N.z]) + >>> d = outer(N.x, N.x) + >>> d.dt(B) + - q'*(N.y|N.x) - q'*(N.x|N.y) + + """ + from sympy.physics.vector.functions import time_derivative + return time_derivative(self, frame) + + def simplify(self): + """Returns a simplified Dyadic.""" + out = Dyadic(0) + for v in self.args: + out += Dyadic([(v[0].simplify(), v[1], v[2])]) + return out + + def subs(self, *args, **kwargs): + """Substitution on the Dyadic. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy import Symbol + >>> N = ReferenceFrame('N') + >>> s = Symbol('s') + >>> a = s*(N.x|N.x) + >>> a.subs({s: 2}) + 2*(N.x|N.x) + + """ + + return sum([Dyadic([(v[0].subs(*args, **kwargs), v[1], v[2])]) + for v in self.args], Dyadic(0)) + + def applyfunc(self, f): + """Apply a function to each component of a Dyadic.""" + if not callable(f): + raise TypeError("`f` must be callable.") + + out = Dyadic(0) + for a, b, c in self.args: + out += f(a) * (b.outer(c)) + return out + + def _eval_evalf(self, prec): + if not self.args: + return self + new_args = [] + dps = prec_to_dps(prec) + for inlist in self.args: + new_inlist = list(inlist) + new_inlist[0] = inlist[0].evalf(n=dps) + new_args.append(tuple(new_inlist)) + return Dyadic(new_args) + + def xreplace(self, rule): + """ + Replace occurrences of objects within the measure numbers of the + Dyadic. + + Parameters + ========== + + rule : dict-like + Expresses a replacement rule. + + Returns + ======= + + Dyadic + Result of the replacement. + + Examples + ======== + + >>> from sympy import symbols, pi + >>> from sympy.physics.vector import ReferenceFrame, outer + >>> N = ReferenceFrame('N') + >>> D = outer(N.x, N.x) + >>> x, y, z = symbols('x y z') + >>> ((1 + x*y) * D).xreplace({x: pi}) + (pi*y + 1)*(N.x|N.x) + >>> ((1 + x*y) * D).xreplace({x: pi, y: 2}) + (1 + 2*pi)*(N.x|N.x) + + Replacements occur only if an entire node in the expression tree is + matched: + + >>> ((x*y + z) * D).xreplace({x*y: pi}) + (z + pi)*(N.x|N.x) + >>> ((x*y*z) * D).xreplace({x*y: pi}) + x*y*z*(N.x|N.x) + + """ + + new_args = [] + for inlist in self.args: + new_inlist = list(inlist) + new_inlist[0] = new_inlist[0].xreplace(rule) + new_args.append(tuple(new_inlist)) + return Dyadic(new_args) + + +def _check_dyadic(other): + if not isinstance(other, Dyadic): + raise TypeError('A Dyadic must be supplied') + return other diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/fieldfunctions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/fieldfunctions.py new file mode 100644 index 0000000000000000000000000000000000000000..50dd74ff9e5cb4fdf469a0ea5d72d812c8f03f15 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/fieldfunctions.py @@ -0,0 +1,313 @@ +from sympy.core.function import diff +from sympy.core.singleton import S +from sympy.integrals.integrals import integrate +from sympy.physics.vector import Vector, express +from sympy.physics.vector.frame import _check_frame +from sympy.physics.vector.vector import _check_vector + + +__all__ = ['curl', 'divergence', 'gradient', 'is_conservative', + 'is_solenoidal', 'scalar_potential', + 'scalar_potential_difference'] + + +def curl(vect, frame): + """ + Returns the curl of a vector field computed wrt the coordinate + symbols of the given frame. + + Parameters + ========== + + vect : Vector + The vector operand + + frame : ReferenceFrame + The reference frame to calculate the curl in + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy.physics.vector import curl + >>> R = ReferenceFrame('R') + >>> v1 = R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z + >>> curl(v1, R) + 0 + >>> v2 = R[0]*R[1]*R[2]*R.x + >>> curl(v2, R) + R_x*R_y*R.y - R_x*R_z*R.z + + """ + + _check_vector(vect) + if vect == 0: + return Vector(0) + vect = express(vect, frame, variables=True) + # A mechanical approach to avoid looping overheads + vectx = vect.dot(frame.x) + vecty = vect.dot(frame.y) + vectz = vect.dot(frame.z) + outvec = Vector(0) + outvec += (diff(vectz, frame[1]) - diff(vecty, frame[2])) * frame.x + outvec += (diff(vectx, frame[2]) - diff(vectz, frame[0])) * frame.y + outvec += (diff(vecty, frame[0]) - diff(vectx, frame[1])) * frame.z + return outvec + + +def divergence(vect, frame): + """ + Returns the divergence of a vector field computed wrt the coordinate + symbols of the given frame. + + Parameters + ========== + + vect : Vector + The vector operand + + frame : ReferenceFrame + The reference frame to calculate the divergence in + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy.physics.vector import divergence + >>> R = ReferenceFrame('R') + >>> v1 = R[0]*R[1]*R[2] * (R.x+R.y+R.z) + >>> divergence(v1, R) + R_x*R_y + R_x*R_z + R_y*R_z + >>> v2 = 2*R[1]*R[2]*R.y + >>> divergence(v2, R) + 2*R_z + + """ + + _check_vector(vect) + if vect == 0: + return S.Zero + vect = express(vect, frame, variables=True) + vectx = vect.dot(frame.x) + vecty = vect.dot(frame.y) + vectz = vect.dot(frame.z) + out = S.Zero + out += diff(vectx, frame[0]) + out += diff(vecty, frame[1]) + out += diff(vectz, frame[2]) + return out + + +def gradient(scalar, frame): + """ + Returns the vector gradient of a scalar field computed wrt the + coordinate symbols of the given frame. + + Parameters + ========== + + scalar : sympifiable + The scalar field to take the gradient of + + frame : ReferenceFrame + The frame to calculate the gradient in + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy.physics.vector import gradient + >>> R = ReferenceFrame('R') + >>> s1 = R[0]*R[1]*R[2] + >>> gradient(s1, R) + R_y*R_z*R.x + R_x*R_z*R.y + R_x*R_y*R.z + >>> s2 = 5*R[0]**2*R[2] + >>> gradient(s2, R) + 10*R_x*R_z*R.x + 5*R_x**2*R.z + + """ + + _check_frame(frame) + outvec = Vector(0) + scalar = express(scalar, frame, variables=True) + for i, x in enumerate(frame): + outvec += diff(scalar, frame[i]) * x # noqa: PLR1736 + return outvec + + +def is_conservative(field): + """ + Checks if a field is conservative. + + Parameters + ========== + + field : Vector + The field to check for conservative property + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy.physics.vector import is_conservative + >>> R = ReferenceFrame('R') + >>> is_conservative(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) + True + >>> is_conservative(R[2] * R.y) + False + + """ + + # Field is conservative irrespective of frame + # Take the first frame in the result of the separate method of Vector + if field == Vector(0): + return True + frame = list(field.separate())[0] + return curl(field, frame).simplify() == Vector(0) + + +def is_solenoidal(field): + """ + Checks if a field is solenoidal. + + Parameters + ========== + + field : Vector + The field to check for solenoidal property + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy.physics.vector import is_solenoidal + >>> R = ReferenceFrame('R') + >>> is_solenoidal(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) + True + >>> is_solenoidal(R[1] * R.y) + False + + """ + + # Field is solenoidal irrespective of frame + # Take the first frame in the result of the separate method in Vector + if field == Vector(0): + return True + frame = list(field.separate())[0] + return divergence(field, frame).simplify() is S.Zero + + +def scalar_potential(field, frame): + """ + Returns the scalar potential function of a field in a given frame + (without the added integration constant). + + Parameters + ========== + + field : Vector + The vector field whose scalar potential function is to be + calculated + + frame : ReferenceFrame + The frame to do the calculation in + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy.physics.vector import scalar_potential, gradient + >>> R = ReferenceFrame('R') + >>> scalar_potential(R.z, R) == R[2] + True + >>> scalar_field = 2*R[0]**2*R[1]*R[2] + >>> grad_field = gradient(scalar_field, R) + >>> scalar_potential(grad_field, R) + 2*R_x**2*R_y*R_z + + """ + + # Check whether field is conservative + if not is_conservative(field): + raise ValueError("Field is not conservative") + if field == Vector(0): + return S.Zero + # Express the field exntirely in frame + # Substitute coordinate variables also + _check_frame(frame) + field = express(field, frame, variables=True) + # Make a list of dimensions of the frame + dimensions = list(frame) + # Calculate scalar potential function + temp_function = integrate(field.dot(dimensions[0]), frame[0]) + for i, dim in enumerate(dimensions[1:]): + partial_diff = diff(temp_function, frame[i + 1]) + partial_diff = field.dot(dim) - partial_diff + temp_function += integrate(partial_diff, frame[i + 1]) + return temp_function + + +def scalar_potential_difference(field, frame, point1, point2, origin): + """ + Returns the scalar potential difference between two points in a + certain frame, wrt a given field. + + If a scalar field is provided, its values at the two points are + considered. If a conservative vector field is provided, the values + of its scalar potential function at the two points are used. + + Returns (potential at position 2) - (potential at position 1) + + Parameters + ========== + + field : Vector/sympyfiable + The field to calculate wrt + + frame : ReferenceFrame + The frame to do the calculations in + + point1 : Point + The initial Point in given frame + + position2 : Point + The second Point in the given frame + + origin : Point + The Point to use as reference point for position vector + calculation + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, Point + >>> from sympy.physics.vector import scalar_potential_difference + >>> R = ReferenceFrame('R') + >>> O = Point('O') + >>> P = O.locatenew('P', R[0]*R.x + R[1]*R.y + R[2]*R.z) + >>> vectfield = 4*R[0]*R[1]*R.x + 2*R[0]**2*R.y + >>> scalar_potential_difference(vectfield, R, O, P, O) + 2*R_x**2*R_y + >>> Q = O.locatenew('O', 3*R.x + R.y + 2*R.z) + >>> scalar_potential_difference(vectfield, R, P, Q, O) + -2*R_x**2*R_y + 18 + + """ + + _check_frame(frame) + if isinstance(field, Vector): + # Get the scalar potential function + scalar_fn = scalar_potential(field, frame) + else: + # Field is a scalar + scalar_fn = field + # Express positions in required frame + position1 = express(point1.pos_from(origin), frame, variables=True) + position2 = express(point2.pos_from(origin), frame, variables=True) + # Get the two positions as substitution dicts for coordinate variables + subs_dict1 = {} + subs_dict2 = {} + for i, x in enumerate(frame): + subs_dict1[frame[i]] = x.dot(position1) + subs_dict2[frame[i]] = x.dot(position2) + return scalar_fn.subs(subs_dict2) - scalar_fn.subs(subs_dict1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/frame.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/frame.py new file mode 100644 index 0000000000000000000000000000000000000000..4aa28fe3717696b6fd8196e652b6b1aa0daf5609 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/frame.py @@ -0,0 +1,1575 @@ +from sympy import (diff, expand, sin, cos, sympify, eye, zeros, + ImmutableMatrix as Matrix, MatrixBase) +from sympy.core.symbol import Symbol +from sympy.simplify.trigsimp import trigsimp +from sympy.physics.vector.vector import Vector, _check_vector +from sympy.utilities.misc import translate + +from warnings import warn + +__all__ = ['CoordinateSym', 'ReferenceFrame'] + + +class CoordinateSym(Symbol): + """ + A coordinate symbol/base scalar associated wrt a Reference Frame. + + Ideally, users should not instantiate this class. Instances of + this class must only be accessed through the corresponding frame + as 'frame[index]'. + + CoordinateSyms having the same frame and index parameters are equal + (even though they may be instantiated separately). + + Parameters + ========== + + name : string + The display name of the CoordinateSym + + frame : ReferenceFrame + The reference frame this base scalar belongs to + + index : 0, 1 or 2 + The index of the dimension denoted by this coordinate variable + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, CoordinateSym + >>> A = ReferenceFrame('A') + >>> A[1] + A_y + >>> type(A[0]) + + >>> a_y = CoordinateSym('a_y', A, 1) + >>> a_y == A[1] + True + + """ + + def __new__(cls, name, frame, index): + # We can't use the cached Symbol.__new__ because this class depends on + # frame and index, which are not passed to Symbol.__xnew__. + assumptions = {} + super()._sanitize(assumptions, cls) + obj = super().__xnew__(cls, name, **assumptions) + _check_frame(frame) + if index not in range(0, 3): + raise ValueError("Invalid index specified") + obj._id = (frame, index) + return obj + + def __getnewargs_ex__(self): + return (self.name, *self._id), {} + + @property + def frame(self): + return self._id[0] + + def __eq__(self, other): + # Check if the other object is a CoordinateSym of the same frame and + # same index + if isinstance(other, CoordinateSym): + if other._id == self._id: + return True + return False + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return (self._id[0].__hash__(), self._id[1]).__hash__() + + +class ReferenceFrame: + """A reference frame in classical mechanics. + + ReferenceFrame is a class used to represent a reference frame in classical + mechanics. It has a standard basis of three unit vectors in the frame's + x, y, and z directions. + + It also can have a rotation relative to a parent frame; this rotation is + defined by a direction cosine matrix relating this frame's basis vectors to + the parent frame's basis vectors. It can also have an angular velocity + vector, defined in another frame. + + """ + _count = 0 + + def __init__(self, name, indices=None, latexs=None, variables=None): + """ReferenceFrame initialization method. + + A ReferenceFrame has a set of orthonormal basis vectors, along with + orientations relative to other ReferenceFrames and angular velocities + relative to other ReferenceFrames. + + Parameters + ========== + + indices : tuple of str + Enables the reference frame's basis unit vectors to be accessed by + Python's square bracket indexing notation using the provided three + indice strings and alters the printing of the unit vectors to + reflect this choice. + latexs : tuple of str + Alters the LaTeX printing of the reference frame's basis unit + vectors to the provided three valid LaTeX strings. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, vlatex + >>> N = ReferenceFrame('N') + >>> N.x + N.x + >>> O = ReferenceFrame('O', indices=('1', '2', '3')) + >>> O.x + O['1'] + >>> O['1'] + O['1'] + >>> P = ReferenceFrame('P', latexs=('A1', 'A2', 'A3')) + >>> vlatex(P.x) + 'A1' + + ``symbols()`` can be used to create multiple Reference Frames in one + step, for example: + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy import symbols + >>> A, B, C = symbols('A B C', cls=ReferenceFrame) + >>> D, E = symbols('D E', cls=ReferenceFrame, indices=('1', '2', '3')) + >>> A[0] + A_x + >>> D.x + D['1'] + >>> E.y + E['2'] + >>> type(A) == type(D) + True + + Unit dyads for the ReferenceFrame can be accessed through the attributes ``xx``, ``xy``, etc. For example: + + >>> from sympy.physics.vector import ReferenceFrame + >>> N = ReferenceFrame('N') + >>> N.yz + (N.y|N.z) + >>> N.zx + (N.z|N.x) + >>> P = ReferenceFrame('P', indices=['1', '2', '3']) + >>> P.xx + (P['1']|P['1']) + >>> P.zy + (P['3']|P['2']) + + Unit dyadic is also accessible via the ``u`` attribute: + + >>> from sympy.physics.vector import ReferenceFrame + >>> N = ReferenceFrame('N') + >>> N.u + (N.x|N.x) + (N.y|N.y) + (N.z|N.z) + >>> P = ReferenceFrame('P', indices=['1', '2', '3']) + >>> P.u + (P['1']|P['1']) + (P['2']|P['2']) + (P['3']|P['3']) + + """ + + if not isinstance(name, str): + raise TypeError('Need to supply a valid name') + # The if statements below are for custom printing of basis-vectors for + # each frame. + # First case, when custom indices are supplied + if indices is not None: + if not isinstance(indices, (tuple, list)): + raise TypeError('Supply the indices as a list') + if len(indices) != 3: + raise ValueError('Supply 3 indices') + for i in indices: + if not isinstance(i, str): + raise TypeError('Indices must be strings') + self.str_vecs = [(name + '[\'' + indices[0] + '\']'), + (name + '[\'' + indices[1] + '\']'), + (name + '[\'' + indices[2] + '\']')] + self.pretty_vecs = [(name.lower() + "_" + indices[0]), + (name.lower() + "_" + indices[1]), + (name.lower() + "_" + indices[2])] + self.latex_vecs = [(r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), + indices[0])), + (r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), + indices[1])), + (r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), + indices[2]))] + self.indices = indices + # Second case, when no custom indices are supplied + else: + self.str_vecs = [(name + '.x'), (name + '.y'), (name + '.z')] + self.pretty_vecs = [name.lower() + "_x", + name.lower() + "_y", + name.lower() + "_z"] + self.latex_vecs = [(r"\mathbf{\hat{%s}_x}" % name.lower()), + (r"\mathbf{\hat{%s}_y}" % name.lower()), + (r"\mathbf{\hat{%s}_z}" % name.lower())] + self.indices = ['x', 'y', 'z'] + # Different step, for custom latex basis vectors + if latexs is not None: + if not isinstance(latexs, (tuple, list)): + raise TypeError('Supply the indices as a list') + if len(latexs) != 3: + raise ValueError('Supply 3 indices') + for i in latexs: + if not isinstance(i, str): + raise TypeError('Latex entries must be strings') + self.latex_vecs = latexs + self.name = name + self._var_dict = {} + # The _dcm_dict dictionary will only store the dcms of adjacent + # parent-child relationships. The _dcm_cache dictionary will store + # calculated dcm along with all content of _dcm_dict for faster + # retrieval of dcms. + self._dcm_dict = {} + self._dcm_cache = {} + self._ang_vel_dict = {} + self._ang_acc_dict = {} + self._dlist = [self._dcm_dict, self._ang_vel_dict, self._ang_acc_dict] + self._cur = 0 + self._x = Vector([(Matrix([1, 0, 0]), self)]) + self._y = Vector([(Matrix([0, 1, 0]), self)]) + self._z = Vector([(Matrix([0, 0, 1]), self)]) + # Associate coordinate symbols wrt this frame + if variables is not None: + if not isinstance(variables, (tuple, list)): + raise TypeError('Supply the variable names as a list/tuple') + if len(variables) != 3: + raise ValueError('Supply 3 variable names') + for i in variables: + if not isinstance(i, str): + raise TypeError('Variable names must be strings') + else: + variables = [name + '_x', name + '_y', name + '_z'] + self.varlist = (CoordinateSym(variables[0], self, 0), + CoordinateSym(variables[1], self, 1), + CoordinateSym(variables[2], self, 2)) + ReferenceFrame._count += 1 + self.index = ReferenceFrame._count + + def __getitem__(self, ind): + """ + Returns basis vector for the provided index, if the index is a string. + + If the index is a number, returns the coordinate variable correspon- + -ding to that index. + """ + if not isinstance(ind, str): + if ind < 3: + return self.varlist[ind] + else: + raise ValueError("Invalid index provided") + if self.indices[0] == ind: + return self.x + if self.indices[1] == ind: + return self.y + if self.indices[2] == ind: + return self.z + else: + raise ValueError('Not a defined index') + + def __iter__(self): + return iter([self.x, self.y, self.z]) + + def __str__(self): + """Returns the name of the frame. """ + return self.name + + __repr__ = __str__ + + def _dict_list(self, other, num): + """Returns an inclusive list of reference frames that connect this + reference frame to the provided reference frame. + + Parameters + ========== + other : ReferenceFrame + The other reference frame to look for a connecting relationship to. + num : integer + ``0``, ``1``, and ``2`` will look for orientation, angular + velocity, and angular acceleration relationships between the two + frames, respectively. + + Returns + ======= + list + Inclusive list of reference frames that connect this reference + frame to the other reference frame. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> A = ReferenceFrame('A') + >>> B = ReferenceFrame('B') + >>> C = ReferenceFrame('C') + >>> D = ReferenceFrame('D') + >>> B.orient_axis(A, A.x, 1.0) + >>> C.orient_axis(B, B.x, 1.0) + >>> D.orient_axis(C, C.x, 1.0) + >>> D._dict_list(A, 0) + [D, C, B, A] + + Raises + ====== + + ValueError + When no path is found between the two reference frames or ``num`` + is an incorrect value. + + """ + + connect_type = {0: 'orientation', + 1: 'angular velocity', + 2: 'angular acceleration'} + + if num not in connect_type.keys(): + raise ValueError('Valid values for num are 0, 1, or 2.') + + possible_connecting_paths = [[self]] + oldlist = [[]] + while possible_connecting_paths != oldlist: + oldlist = possible_connecting_paths.copy() + for frame_list in possible_connecting_paths: + frames_adjacent_to_last = frame_list[-1]._dlist[num].keys() + for adjacent_frame in frames_adjacent_to_last: + if adjacent_frame not in frame_list: + connecting_path = frame_list + [adjacent_frame] + if connecting_path not in possible_connecting_paths: + possible_connecting_paths.append(connecting_path) + + for connecting_path in oldlist: + if connecting_path[-1] != other: + possible_connecting_paths.remove(connecting_path) + possible_connecting_paths.sort(key=len) + + if len(possible_connecting_paths) != 0: + return possible_connecting_paths[0] # selects the shortest path + + msg = 'No connecting {} path found between {} and {}.' + raise ValueError(msg.format(connect_type[num], self.name, other.name)) + + def _w_diff_dcm(self, otherframe): + """Angular velocity from time differentiating the DCM. """ + from sympy.physics.vector.functions import dynamicsymbols + dcm2diff = otherframe.dcm(self) + diffed = dcm2diff.diff(dynamicsymbols._t) + angvelmat = diffed * dcm2diff.T + w1 = trigsimp(expand(angvelmat[7]), recursive=True) + w2 = trigsimp(expand(angvelmat[2]), recursive=True) + w3 = trigsimp(expand(angvelmat[3]), recursive=True) + return Vector([(Matrix([w1, w2, w3]), otherframe)]) + + def variable_map(self, otherframe): + """ + Returns a dictionary which expresses the coordinate variables + of this frame in terms of the variables of otherframe. + + If Vector.simp is True, returns a simplified version of the mapped + values. Else, returns them without simplification. + + Simplification of the expressions may take time. + + Parameters + ========== + + otherframe : ReferenceFrame + The other frame to map the variables to + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols + >>> A = ReferenceFrame('A') + >>> q = dynamicsymbols('q') + >>> B = A.orientnew('B', 'Axis', [q, A.z]) + >>> A.variable_map(B) + {A_x: B_x*cos(q(t)) - B_y*sin(q(t)), A_y: B_x*sin(q(t)) + B_y*cos(q(t)), A_z: B_z} + + """ + + _check_frame(otherframe) + if (otherframe, Vector.simp) in self._var_dict: + return self._var_dict[(otherframe, Vector.simp)] + else: + vars_matrix = self.dcm(otherframe) * Matrix(otherframe.varlist) + mapping = {} + for i, x in enumerate(self): + if Vector.simp: + mapping[self.varlist[i]] = trigsimp(vars_matrix[i], + method='fu') + else: + mapping[self.varlist[i]] = vars_matrix[i] + self._var_dict[(otherframe, Vector.simp)] = mapping + return mapping + + def ang_acc_in(self, otherframe): + """Returns the angular acceleration Vector of the ReferenceFrame. + + Effectively returns the Vector: + + ``N_alpha_B`` + + which represent the angular acceleration of B in N, where B is self, + and N is otherframe. + + Parameters + ========== + + otherframe : ReferenceFrame + The ReferenceFrame which the angular acceleration is returned in. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> V = 10 * N.x + >>> A.set_ang_acc(N, V) + >>> A.ang_acc_in(N) + 10*N.x + + """ + + _check_frame(otherframe) + if otherframe in self._ang_acc_dict: + return self._ang_acc_dict[otherframe] + else: + return self.ang_vel_in(otherframe).dt(otherframe) + + def ang_vel_in(self, otherframe): + """Returns the angular velocity Vector of the ReferenceFrame. + + Effectively returns the Vector: + + ^N omega ^B + + which represent the angular velocity of B in N, where B is self, and + N is otherframe. + + Parameters + ========== + + otherframe : ReferenceFrame + The ReferenceFrame which the angular velocity is returned in. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> V = 10 * N.x + >>> A.set_ang_vel(N, V) + >>> A.ang_vel_in(N) + 10*N.x + + """ + + _check_frame(otherframe) + flist = self._dict_list(otherframe, 1) + outvec = Vector(0) + for i in range(len(flist) - 1): + outvec += flist[i]._ang_vel_dict[flist[i + 1]] + return outvec + + def dcm(self, otherframe): + r"""Returns the direction cosine matrix of this reference frame + relative to the provided reference frame. + + The returned matrix can be used to express the orthogonal unit vectors + of this frame in terms of the orthogonal unit vectors of + ``otherframe``. + + Parameters + ========== + + otherframe : ReferenceFrame + The reference frame which the direction cosine matrix of this frame + is formed relative to. + + Examples + ======== + + The following example rotates the reference frame A relative to N by a + simple rotation and then calculates the direction cosine matrix of N + relative to A. + + >>> from sympy import symbols, sin, cos + >>> from sympy.physics.vector import ReferenceFrame + >>> q1 = symbols('q1') + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> A.orient_axis(N, q1, N.x) + >>> N.dcm(A) + Matrix([ + [1, 0, 0], + [0, cos(q1), -sin(q1)], + [0, sin(q1), cos(q1)]]) + + The second row of the above direction cosine matrix represents the + ``N.y`` unit vector in N expressed in A. Like so: + + >>> Ny = 0*A.x + cos(q1)*A.y - sin(q1)*A.z + + Thus, expressing ``N.y`` in A should return the same result: + + >>> N.y.express(A) + cos(q1)*A.y - sin(q1)*A.z + + Notes + ===== + + It is important to know what form of the direction cosine matrix is + returned. If ``B.dcm(A)`` is called, it means the "direction cosine + matrix of B rotated relative to A". This is the matrix + :math:`{}^B\mathbf{C}^A` shown in the following relationship: + + .. math:: + + \begin{bmatrix} + \hat{\mathbf{b}}_1 \\ + \hat{\mathbf{b}}_2 \\ + \hat{\mathbf{b}}_3 + \end{bmatrix} + = + {}^B\mathbf{C}^A + \begin{bmatrix} + \hat{\mathbf{a}}_1 \\ + \hat{\mathbf{a}}_2 \\ + \hat{\mathbf{a}}_3 + \end{bmatrix}. + + :math:`{}^B\mathbf{C}^A` is the matrix that expresses the B unit + vectors in terms of the A unit vectors. + + """ + + _check_frame(otherframe) + # Check if the dcm wrt that frame has already been calculated + if otherframe in self._dcm_cache: + return self._dcm_cache[otherframe] + flist = self._dict_list(otherframe, 0) + outdcm = eye(3) + for i in range(len(flist) - 1): + outdcm = outdcm * flist[i]._dcm_dict[flist[i + 1]] + # After calculation, store the dcm in dcm cache for faster future + # retrieval + self._dcm_cache[otherframe] = outdcm + otherframe._dcm_cache[self] = outdcm.T + return outdcm + + def _dcm(self, parent, parent_orient): + # If parent.oreint(self) is already defined,then + # update the _dcm_dict of parent while over write + # all content of self._dcm_dict and self._dcm_cache + # with new dcm relation. + # Else update _dcm_cache and _dcm_dict of both + # self and parent. + frames = self._dcm_cache.keys() + dcm_dict_del = [] + dcm_cache_del = [] + if parent in frames: + for frame in frames: + if frame in self._dcm_dict: + dcm_dict_del += [frame] + dcm_cache_del += [frame] + # Reset the _dcm_cache of this frame, and remove it from the + # _dcm_caches of the frames it is linked to. Also remove it from + # the _dcm_dict of its parent + for frame in dcm_dict_del: + del frame._dcm_dict[self] + for frame in dcm_cache_del: + del frame._dcm_cache[self] + # Reset the _dcm_dict + self._dcm_dict = self._dlist[0] = {} + # Reset the _dcm_cache + self._dcm_cache = {} + + else: + # Check for loops and raise warning accordingly. + visited = [] + queue = list(frames) + cont = True # Flag to control queue loop. + while queue and cont: + node = queue.pop(0) + if node not in visited: + visited.append(node) + neighbors = node._dcm_dict.keys() + for neighbor in neighbors: + if neighbor == parent: + warn('Loops are defined among the orientation of ' + 'frames. This is likely not desired and may ' + 'cause errors in your calculations.') + cont = False + break + queue.append(neighbor) + + # Add the dcm relationship to _dcm_dict + self._dcm_dict.update({parent: parent_orient.T}) + parent._dcm_dict.update({self: parent_orient}) + # Update the dcm cache + self._dcm_cache.update({parent: parent_orient.T}) + parent._dcm_cache.update({self: parent_orient}) + + def orient_axis(self, parent, axis, angle): + """Sets the orientation of this reference frame with respect to a + parent reference frame by rotating through an angle about an axis fixed + in the parent reference frame. + + Parameters + ========== + + parent : ReferenceFrame + Reference frame that this reference frame will be rotated relative + to. + axis : Vector + Vector fixed in the parent frame about about which this frame is + rotated. It need not be a unit vector and the rotation follows the + right hand rule. + angle : sympifiable + Angle in radians by which it the frame is to be rotated. + + Warns + ====== + + UserWarning + If the orientation creates a kinematic loop. + + Examples + ======== + + Setup variables for the examples: + + >>> from sympy import symbols + >>> from sympy.physics.vector import ReferenceFrame + >>> q1 = symbols('q1') + >>> N = ReferenceFrame('N') + >>> B = ReferenceFrame('B') + >>> B.orient_axis(N, N.x, q1) + + The ``orient_axis()`` method generates a direction cosine matrix and + its transpose which defines the orientation of B relative to N and vice + versa. Once orient is called, ``dcm()`` outputs the appropriate + direction cosine matrix: + + >>> B.dcm(N) + Matrix([ + [1, 0, 0], + [0, cos(q1), sin(q1)], + [0, -sin(q1), cos(q1)]]) + >>> N.dcm(B) + Matrix([ + [1, 0, 0], + [0, cos(q1), -sin(q1)], + [0, sin(q1), cos(q1)]]) + + The following two lines show that the sense of the rotation can be + defined by negating the vector direction or the angle. Both lines + produce the same result. + + >>> B.orient_axis(N, -N.x, q1) + >>> B.orient_axis(N, N.x, -q1) + + """ + + from sympy.physics.vector.functions import dynamicsymbols + _check_frame(parent) + + if not isinstance(axis, Vector) and isinstance(angle, Vector): + axis, angle = angle, axis + + axis = _check_vector(axis) + theta = sympify(angle) + + if not axis.dt(parent) == 0: + raise ValueError('Axis cannot be time-varying.') + unit_axis = axis.express(parent).normalize() + unit_col = unit_axis.args[0][0] + parent_orient_axis = ( + (eye(3) - unit_col * unit_col.T) * cos(theta) + + Matrix([[0, -unit_col[2], unit_col[1]], + [unit_col[2], 0, -unit_col[0]], + [-unit_col[1], unit_col[0], 0]]) * + sin(theta) + unit_col * unit_col.T) + + self._dcm(parent, parent_orient_axis) + + thetad = (theta).diff(dynamicsymbols._t) + wvec = thetad*axis.express(parent).normalize() + self._ang_vel_dict.update({parent: wvec}) + parent._ang_vel_dict.update({self: -wvec}) + self._var_dict = {} + + def orient_explicit(self, parent, dcm): + """Sets the orientation of this reference frame relative to another (parent) reference frame + using a direction cosine matrix that describes the rotation from the parent to the child. + + Parameters + ========== + + parent : ReferenceFrame + Reference frame that this reference frame will be rotated relative + to. + dcm : Matrix, shape(3, 3) + Direction cosine matrix that specifies the relative rotation + between the two reference frames. + + Warns + ====== + + UserWarning + If the orientation creates a kinematic loop. + + Examples + ======== + + Setup variables for the examples: + + >>> from sympy import symbols, Matrix, sin, cos + >>> from sympy.physics.vector import ReferenceFrame + >>> q1 = symbols('q1') + >>> A = ReferenceFrame('A') + >>> B = ReferenceFrame('B') + >>> N = ReferenceFrame('N') + + A simple rotation of ``A`` relative to ``N`` about ``N.x`` is defined + by the following direction cosine matrix: + + >>> dcm = Matrix([[1, 0, 0], + ... [0, cos(q1), -sin(q1)], + ... [0, sin(q1), cos(q1)]]) + >>> A.orient_explicit(N, dcm) + >>> A.dcm(N) + Matrix([ + [1, 0, 0], + [0, cos(q1), sin(q1)], + [0, -sin(q1), cos(q1)]]) + + This is equivalent to using ``orient_axis()``: + + >>> B.orient_axis(N, N.x, q1) + >>> B.dcm(N) + Matrix([ + [1, 0, 0], + [0, cos(q1), sin(q1)], + [0, -sin(q1), cos(q1)]]) + + **Note carefully that** ``N.dcm(B)`` **(the transpose) would be passed + into** ``orient_explicit()`` **for** ``A.dcm(N)`` **to match** + ``B.dcm(N)``: + + >>> A.orient_explicit(N, N.dcm(B)) + >>> A.dcm(N) + Matrix([ + [1, 0, 0], + [0, cos(q1), sin(q1)], + [0, -sin(q1), cos(q1)]]) + + """ + _check_frame(parent) + # amounts must be a Matrix type object + # (e.g. sympy.matrices.dense.MutableDenseMatrix). + if not isinstance(dcm, MatrixBase): + raise TypeError("Amounts must be a SymPy Matrix type object.") + + self.orient_dcm(parent, dcm.T) + + def orient_dcm(self, parent, dcm): + """Sets the orientation of this reference frame relative to another (parent) reference frame + using a direction cosine matrix that describes the rotation from the child to the parent. + + Parameters + ========== + + parent : ReferenceFrame + Reference frame that this reference frame will be rotated relative + to. + dcm : Matrix, shape(3, 3) + Direction cosine matrix that specifies the relative rotation + between the two reference frames. + + Warns + ====== + + UserWarning + If the orientation creates a kinematic loop. + + Examples + ======== + + Setup variables for the examples: + + >>> from sympy import symbols, Matrix, sin, cos + >>> from sympy.physics.vector import ReferenceFrame + >>> q1 = symbols('q1') + >>> A = ReferenceFrame('A') + >>> B = ReferenceFrame('B') + >>> N = ReferenceFrame('N') + + A simple rotation of ``A`` relative to ``N`` about ``N.x`` is defined + by the following direction cosine matrix: + + >>> dcm = Matrix([[1, 0, 0], + ... [0, cos(q1), sin(q1)], + ... [0, -sin(q1), cos(q1)]]) + >>> A.orient_dcm(N, dcm) + >>> A.dcm(N) + Matrix([ + [1, 0, 0], + [0, cos(q1), sin(q1)], + [0, -sin(q1), cos(q1)]]) + + This is equivalent to using ``orient_axis()``: + + >>> B.orient_axis(N, N.x, q1) + >>> B.dcm(N) + Matrix([ + [1, 0, 0], + [0, cos(q1), sin(q1)], + [0, -sin(q1), cos(q1)]]) + + """ + + _check_frame(parent) + # amounts must be a Matrix type object + # (e.g. sympy.matrices.dense.MutableDenseMatrix). + if not isinstance(dcm, MatrixBase): + raise TypeError("Amounts must be a SymPy Matrix type object.") + + self._dcm(parent, dcm.T) + + wvec = self._w_diff_dcm(parent) + self._ang_vel_dict.update({parent: wvec}) + parent._ang_vel_dict.update({self: -wvec}) + self._var_dict = {} + + def _rot(self, axis, angle): + """DCM for simple axis 1,2,or 3 rotations.""" + if axis == 1: + return Matrix([[1, 0, 0], + [0, cos(angle), -sin(angle)], + [0, sin(angle), cos(angle)]]) + elif axis == 2: + return Matrix([[cos(angle), 0, sin(angle)], + [0, 1, 0], + [-sin(angle), 0, cos(angle)]]) + elif axis == 3: + return Matrix([[cos(angle), -sin(angle), 0], + [sin(angle), cos(angle), 0], + [0, 0, 1]]) + + def _parse_consecutive_rotations(self, angles, rotation_order): + """Helper for orient_body_fixed and orient_space_fixed. + + Parameters + ========== + angles : 3-tuple of sympifiable + Three angles in radians used for the successive rotations. + rotation_order : 3 character string or 3 digit integer + Order of the rotations. The order can be specified by the strings + ``'XZX'``, ``'131'``, or the integer ``131``. There are 12 unique + valid rotation orders. + + Returns + ======= + + amounts : list + List of sympifiables corresponding to the rotation angles. + rot_order : list + List of integers corresponding to the axis of rotation. + rot_matrices : list + List of DCM around the given axis with corresponding magnitude. + + """ + amounts = list(angles) + for i, v in enumerate(amounts): + if not isinstance(v, Vector): + amounts[i] = sympify(v) + + approved_orders = ('123', '231', '312', '132', '213', '321', '121', + '131', '212', '232', '313', '323', '') + # make sure XYZ => 123 + rot_order = translate(str(rotation_order), 'XYZxyz', '123123') + if rot_order not in approved_orders: + raise TypeError('The rotation order is not a valid order.') + + rot_order = [int(r) for r in rot_order] + if not (len(amounts) == 3 & len(rot_order) == 3): + raise TypeError('Body orientation takes 3 values & 3 orders') + rot_matrices = [self._rot(order, amount) + for (order, amount) in zip(rot_order, amounts)] + return amounts, rot_order, rot_matrices + + def orient_body_fixed(self, parent, angles, rotation_order): + """Rotates this reference frame relative to the parent reference frame + by right hand rotating through three successive body fixed simple axis + rotations. Each subsequent axis of rotation is about the "body fixed" + unit vectors of a new intermediate reference frame. This type of + rotation is also referred to rotating through the `Euler and Tait-Bryan + Angles`_. + + .. _Euler and Tait-Bryan Angles: https://en.wikipedia.org/wiki/Euler_angles + + The computed angular velocity in this method is by default expressed in + the child's frame, so it is most preferable to use ``u1 * child.x + u2 * + child.y + u3 * child.z`` as generalized speeds. + + Parameters + ========== + + parent : ReferenceFrame + Reference frame that this reference frame will be rotated relative + to. + angles : 3-tuple of sympifiable + Three angles in radians used for the successive rotations. + rotation_order : 3 character string or 3 digit integer + Order of the rotations about each intermediate reference frames' + unit vectors. The Euler rotation about the X, Z', X'' axes can be + specified by the strings ``'XZX'``, ``'131'``, or the integer + ``131``. There are 12 unique valid rotation orders (6 Euler and 6 + Tait-Bryan): zxz, xyx, yzy, zyz, xzx, yxy, xyz, yzx, zxy, xzy, zyx, + and yxz. + + Warns + ====== + + UserWarning + If the orientation creates a kinematic loop. + + Examples + ======== + + Setup variables for the examples: + + >>> from sympy import symbols + >>> from sympy.physics.vector import ReferenceFrame + >>> q1, q2, q3 = symbols('q1, q2, q3') + >>> N = ReferenceFrame('N') + >>> B = ReferenceFrame('B') + >>> B1 = ReferenceFrame('B1') + >>> B2 = ReferenceFrame('B2') + >>> B3 = ReferenceFrame('B3') + + For example, a classic Euler Angle rotation can be done by: + + >>> B.orient_body_fixed(N, (q1, q2, q3), 'XYX') + >>> B.dcm(N) + Matrix([ + [ cos(q2), sin(q1)*sin(q2), -sin(q2)*cos(q1)], + [sin(q2)*sin(q3), -sin(q1)*sin(q3)*cos(q2) + cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q3)*cos(q1)*cos(q2)], + [sin(q2)*cos(q3), -sin(q1)*cos(q2)*cos(q3) - sin(q3)*cos(q1), -sin(q1)*sin(q3) + cos(q1)*cos(q2)*cos(q3)]]) + + This rotates reference frame B relative to reference frame N through + ``q1`` about ``N.x``, then rotates B again through ``q2`` about + ``B.y``, and finally through ``q3`` about ``B.x``. It is equivalent to + three successive ``orient_axis()`` calls: + + >>> B1.orient_axis(N, N.x, q1) + >>> B2.orient_axis(B1, B1.y, q2) + >>> B3.orient_axis(B2, B2.x, q3) + >>> B3.dcm(N) + Matrix([ + [ cos(q2), sin(q1)*sin(q2), -sin(q2)*cos(q1)], + [sin(q2)*sin(q3), -sin(q1)*sin(q3)*cos(q2) + cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q3)*cos(q1)*cos(q2)], + [sin(q2)*cos(q3), -sin(q1)*cos(q2)*cos(q3) - sin(q3)*cos(q1), -sin(q1)*sin(q3) + cos(q1)*cos(q2)*cos(q3)]]) + + Acceptable rotation orders are of length 3, expressed in as a string + ``'XYZ'`` or ``'123'`` or integer ``123``. Rotations about an axis + twice in a row are prohibited. + + >>> B.orient_body_fixed(N, (q1, q2, 0), 'ZXZ') + >>> B.orient_body_fixed(N, (q1, q2, 0), '121') + >>> B.orient_body_fixed(N, (q1, q2, q3), 123) + + """ + from sympy.physics.vector.functions import dynamicsymbols + + _check_frame(parent) + + amounts, rot_order, rot_matrices = self._parse_consecutive_rotations( + angles, rotation_order) + self._dcm(parent, rot_matrices[0] * rot_matrices[1] * rot_matrices[2]) + + rot_vecs = [zeros(3, 1) for _ in range(3)] + for i, order in enumerate(rot_order): + rot_vecs[i][order - 1] = amounts[i].diff(dynamicsymbols._t) + u1, u2, u3 = rot_vecs[2] + rot_matrices[2].T * ( + rot_vecs[1] + rot_matrices[1].T * rot_vecs[0]) + wvec = u1 * self.x + u2 * self.y + u3 * self.z # There is a double - + self._ang_vel_dict.update({parent: wvec}) + parent._ang_vel_dict.update({self: -wvec}) + self._var_dict = {} + + def orient_space_fixed(self, parent, angles, rotation_order): + """Rotates this reference frame relative to the parent reference frame + by right hand rotating through three successive space fixed simple axis + rotations. Each subsequent axis of rotation is about the "space fixed" + unit vectors of the parent reference frame. + + The computed angular velocity in this method is by default expressed in + the child's frame, so it is most preferable to use ``u1 * child.x + u2 * + child.y + u3 * child.z`` as generalized speeds. + + Parameters + ========== + parent : ReferenceFrame + Reference frame that this reference frame will be rotated relative + to. + angles : 3-tuple of sympifiable + Three angles in radians used for the successive rotations. + rotation_order : 3 character string or 3 digit integer + Order of the rotations about the parent reference frame's unit + vectors. The order can be specified by the strings ``'XZX'``, + ``'131'``, or the integer ``131``. There are 12 unique valid + rotation orders. + + Warns + ====== + + UserWarning + If the orientation creates a kinematic loop. + + Examples + ======== + + Setup variables for the examples: + + >>> from sympy import symbols + >>> from sympy.physics.vector import ReferenceFrame + >>> q1, q2, q3 = symbols('q1, q2, q3') + >>> N = ReferenceFrame('N') + >>> B = ReferenceFrame('B') + >>> B1 = ReferenceFrame('B1') + >>> B2 = ReferenceFrame('B2') + >>> B3 = ReferenceFrame('B3') + + >>> B.orient_space_fixed(N, (q1, q2, q3), '312') + >>> B.dcm(N) + Matrix([ + [ sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q2), sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1)], + [-sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2), sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3)], + [ sin(q3)*cos(q2), -sin(q2), cos(q2)*cos(q3)]]) + + is equivalent to: + + >>> B1.orient_axis(N, N.z, q1) + >>> B2.orient_axis(B1, N.x, q2) + >>> B3.orient_axis(B2, N.y, q3) + >>> B3.dcm(N).simplify() + Matrix([ + [ sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q2), sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1)], + [-sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2), sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3)], + [ sin(q3)*cos(q2), -sin(q2), cos(q2)*cos(q3)]]) + + It is worth noting that space-fixed and body-fixed rotations are + related by the order of the rotations, i.e. the reverse order of body + fixed will give space fixed and vice versa. + + >>> B.orient_space_fixed(N, (q1, q2, q3), '231') + >>> B.dcm(N) + Matrix([ + [cos(q1)*cos(q2), sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3), -sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)], + [ -sin(q2), cos(q2)*cos(q3), sin(q3)*cos(q2)], + [sin(q1)*cos(q2), sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1), sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3)]]) + + >>> B.orient_body_fixed(N, (q3, q2, q1), '132') + >>> B.dcm(N) + Matrix([ + [cos(q1)*cos(q2), sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3), -sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)], + [ -sin(q2), cos(q2)*cos(q3), sin(q3)*cos(q2)], + [sin(q1)*cos(q2), sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1), sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3)]]) + + """ + from sympy.physics.vector.functions import dynamicsymbols + + _check_frame(parent) + + amounts, rot_order, rot_matrices = self._parse_consecutive_rotations( + angles, rotation_order) + self._dcm(parent, rot_matrices[2] * rot_matrices[1] * rot_matrices[0]) + + rot_vecs = [zeros(3, 1) for _ in range(3)] + for i, order in enumerate(rot_order): + rot_vecs[i][order - 1] = amounts[i].diff(dynamicsymbols._t) + u1, u2, u3 = rot_vecs[0] + rot_matrices[0].T * ( + rot_vecs[1] + rot_matrices[1].T * rot_vecs[2]) + wvec = u1 * self.x + u2 * self.y + u3 * self.z # There is a double - + self._ang_vel_dict.update({parent: wvec}) + parent._ang_vel_dict.update({self: -wvec}) + self._var_dict = {} + + def orient_quaternion(self, parent, numbers): + """Sets the orientation of this reference frame relative to a parent + reference frame via an orientation quaternion. An orientation + quaternion is defined as a finite rotation a unit vector, ``(lambda_x, + lambda_y, lambda_z)``, by an angle ``theta``. The orientation + quaternion is described by four parameters: + + - ``q0 = cos(theta/2)`` + - ``q1 = lambda_x*sin(theta/2)`` + - ``q2 = lambda_y*sin(theta/2)`` + - ``q3 = lambda_z*sin(theta/2)`` + + See `Quaternions and Spatial Rotation + `_ on + Wikipedia for more information. + + Parameters + ========== + parent : ReferenceFrame + Reference frame that this reference frame will be rotated relative + to. + numbers : 4-tuple of sympifiable + The four quaternion scalar numbers as defined above: ``q0``, + ``q1``, ``q2``, ``q3``. + + Warns + ====== + + UserWarning + If the orientation creates a kinematic loop. + + Examples + ======== + + Setup variables for the examples: + + >>> from sympy import symbols + >>> from sympy.physics.vector import ReferenceFrame + >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') + >>> N = ReferenceFrame('N') + >>> B = ReferenceFrame('B') + + Set the orientation: + + >>> B.orient_quaternion(N, (q0, q1, q2, q3)) + >>> B.dcm(N) + Matrix([ + [q0**2 + q1**2 - q2**2 - q3**2, 2*q0*q3 + 2*q1*q2, -2*q0*q2 + 2*q1*q3], + [ -2*q0*q3 + 2*q1*q2, q0**2 - q1**2 + q2**2 - q3**2, 2*q0*q1 + 2*q2*q3], + [ 2*q0*q2 + 2*q1*q3, -2*q0*q1 + 2*q2*q3, q0**2 - q1**2 - q2**2 + q3**2]]) + + """ + + from sympy.physics.vector.functions import dynamicsymbols + _check_frame(parent) + + numbers = list(numbers) + for i, v in enumerate(numbers): + if not isinstance(v, Vector): + numbers[i] = sympify(v) + + if not (isinstance(numbers, (list, tuple)) & (len(numbers) == 4)): + raise TypeError('Amounts are a list or tuple of length 4') + q0, q1, q2, q3 = numbers + parent_orient_quaternion = ( + Matrix([[q0**2 + q1**2 - q2**2 - q3**2, + 2 * (q1 * q2 - q0 * q3), + 2 * (q0 * q2 + q1 * q3)], + [2 * (q1 * q2 + q0 * q3), + q0**2 - q1**2 + q2**2 - q3**2, + 2 * (q2 * q3 - q0 * q1)], + [2 * (q1 * q3 - q0 * q2), + 2 * (q0 * q1 + q2 * q3), + q0**2 - q1**2 - q2**2 + q3**2]])) + + self._dcm(parent, parent_orient_quaternion) + + t = dynamicsymbols._t + q0, q1, q2, q3 = numbers + q0d = diff(q0, t) + q1d = diff(q1, t) + q2d = diff(q2, t) + q3d = diff(q3, t) + w1 = 2 * (q1d * q0 + q2d * q3 - q3d * q2 - q0d * q1) + w2 = 2 * (q2d * q0 + q3d * q1 - q1d * q3 - q0d * q2) + w3 = 2 * (q3d * q0 + q1d * q2 - q2d * q1 - q0d * q3) + wvec = Vector([(Matrix([w1, w2, w3]), self)]) + + self._ang_vel_dict.update({parent: wvec}) + parent._ang_vel_dict.update({self: -wvec}) + self._var_dict = {} + + def orient(self, parent, rot_type, amounts, rot_order=''): + """Sets the orientation of this reference frame relative to another + (parent) reference frame. + + .. note:: It is now recommended to use the ``.orient_axis, + .orient_body_fixed, .orient_space_fixed, .orient_quaternion`` + methods for the different rotation types. + + Parameters + ========== + + parent : ReferenceFrame + Reference frame that this reference frame will be rotated relative + to. + rot_type : str + The method used to generate the direction cosine matrix. Supported + methods are: + + - ``'Axis'``: simple rotations about a single common axis + - ``'DCM'``: for setting the direction cosine matrix directly + - ``'Body'``: three successive rotations about new intermediate + axes, also called "Euler and Tait-Bryan angles" + - ``'Space'``: three successive rotations about the parent + frames' unit vectors + - ``'Quaternion'``: rotations defined by four parameters which + result in a singularity free direction cosine matrix + + amounts : + Expressions defining the rotation angles or direction cosine + matrix. These must match the ``rot_type``. See examples below for + details. The input types are: + + - ``'Axis'``: 2-tuple (expr/sym/func, Vector) + - ``'DCM'``: Matrix, shape(3,3) + - ``'Body'``: 3-tuple of expressions, symbols, or functions + - ``'Space'``: 3-tuple of expressions, symbols, or functions + - ``'Quaternion'``: 4-tuple of expressions, symbols, or + functions + + rot_order : str or int, optional + If applicable, the order of the successive of rotations. The string + ``'123'`` and integer ``123`` are equivalent, for example. Required + for ``'Body'`` and ``'Space'``. + + Warns + ====== + + UserWarning + If the orientation creates a kinematic loop. + + """ + + _check_frame(parent) + + approved_orders = ('123', '231', '312', '132', '213', '321', '121', + '131', '212', '232', '313', '323', '') + rot_order = translate(str(rot_order), 'XYZxyz', '123123') + rot_type = rot_type.upper() + + if rot_order not in approved_orders: + raise TypeError('The supplied order is not an approved type') + + if rot_type == 'AXIS': + self.orient_axis(parent, amounts[1], amounts[0]) + + elif rot_type == 'DCM': + self.orient_explicit(parent, amounts) + + elif rot_type == 'BODY': + self.orient_body_fixed(parent, amounts, rot_order) + + elif rot_type == 'SPACE': + self.orient_space_fixed(parent, amounts, rot_order) + + elif rot_type == 'QUATERNION': + self.orient_quaternion(parent, amounts) + + else: + raise NotImplementedError('That is not an implemented rotation') + + def orientnew(self, newname, rot_type, amounts, rot_order='', + variables=None, indices=None, latexs=None): + r"""Returns a new reference frame oriented with respect to this + reference frame. + + See ``ReferenceFrame.orient()`` for detailed examples of how to orient + reference frames. + + Parameters + ========== + + newname : str + Name for the new reference frame. + rot_type : str + The method used to generate the direction cosine matrix. Supported + methods are: + + - ``'Axis'``: simple rotations about a single common axis + - ``'DCM'``: for setting the direction cosine matrix directly + - ``'Body'``: three successive rotations about new intermediate + axes, also called "Euler and Tait-Bryan angles" + - ``'Space'``: three successive rotations about the parent + frames' unit vectors + - ``'Quaternion'``: rotations defined by four parameters which + result in a singularity free direction cosine matrix + + amounts : + Expressions defining the rotation angles or direction cosine + matrix. These must match the ``rot_type``. See examples below for + details. The input types are: + + - ``'Axis'``: 2-tuple (expr/sym/func, Vector) + - ``'DCM'``: Matrix, shape(3,3) + - ``'Body'``: 3-tuple of expressions, symbols, or functions + - ``'Space'``: 3-tuple of expressions, symbols, or functions + - ``'Quaternion'``: 4-tuple of expressions, symbols, or + functions + + rot_order : str or int, optional + If applicable, the order of the successive of rotations. The string + ``'123'`` and integer ``123`` are equivalent, for example. Required + for ``'Body'`` and ``'Space'``. + indices : tuple of str + Enables the reference frame's basis unit vectors to be accessed by + Python's square bracket indexing notation using the provided three + indice strings and alters the printing of the unit vectors to + reflect this choice. + latexs : tuple of str + Alters the LaTeX printing of the reference frame's basis unit + vectors to the provided three valid LaTeX strings. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.vector import ReferenceFrame, vlatex + >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') + >>> N = ReferenceFrame('N') + + Create a new reference frame A rotated relative to N through a simple + rotation. + + >>> A = N.orientnew('A', 'Axis', (q0, N.x)) + + Create a new reference frame B rotated relative to N through body-fixed + rotations. + + >>> B = N.orientnew('B', 'Body', (q1, q2, q3), '123') + + Create a new reference frame C rotated relative to N through a simple + rotation with unique indices and LaTeX printing. + + >>> C = N.orientnew('C', 'Axis', (q0, N.x), indices=('1', '2', '3'), + ... latexs=(r'\hat{\mathbf{c}}_1',r'\hat{\mathbf{c}}_2', + ... r'\hat{\mathbf{c}}_3')) + >>> C['1'] + C['1'] + >>> print(vlatex(C['1'])) + \hat{\mathbf{c}}_1 + + """ + + newframe = self.__class__(newname, variables=variables, + indices=indices, latexs=latexs) + + approved_orders = ('123', '231', '312', '132', '213', '321', '121', + '131', '212', '232', '313', '323', '') + rot_order = translate(str(rot_order), 'XYZxyz', '123123') + rot_type = rot_type.upper() + + if rot_order not in approved_orders: + raise TypeError('The supplied order is not an approved type') + + if rot_type == 'AXIS': + newframe.orient_axis(self, amounts[1], amounts[0]) + + elif rot_type == 'DCM': + newframe.orient_explicit(self, amounts) + + elif rot_type == 'BODY': + newframe.orient_body_fixed(self, amounts, rot_order) + + elif rot_type == 'SPACE': + newframe.orient_space_fixed(self, amounts, rot_order) + + elif rot_type == 'QUATERNION': + newframe.orient_quaternion(self, amounts) + + else: + raise NotImplementedError('That is not an implemented rotation') + return newframe + + def set_ang_acc(self, otherframe, value): + """Define the angular acceleration Vector in a ReferenceFrame. + + Defines the angular acceleration of this ReferenceFrame, in another. + Angular acceleration can be defined with respect to multiple different + ReferenceFrames. Care must be taken to not create loops which are + inconsistent. + + Parameters + ========== + + otherframe : ReferenceFrame + A ReferenceFrame to define the angular acceleration in + value : Vector + The Vector representing angular acceleration + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> V = 10 * N.x + >>> A.set_ang_acc(N, V) + >>> A.ang_acc_in(N) + 10*N.x + + """ + + if value == 0: + value = Vector(0) + value = _check_vector(value) + _check_frame(otherframe) + self._ang_acc_dict.update({otherframe: value}) + otherframe._ang_acc_dict.update({self: -value}) + + def set_ang_vel(self, otherframe, value): + """Define the angular velocity vector in a ReferenceFrame. + + Defines the angular velocity of this ReferenceFrame, in another. + Angular velocity can be defined with respect to multiple different + ReferenceFrames. Care must be taken to not create loops which are + inconsistent. + + Parameters + ========== + + otherframe : ReferenceFrame + A ReferenceFrame to define the angular velocity in + value : Vector + The Vector representing angular velocity + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> V = 10 * N.x + >>> A.set_ang_vel(N, V) + >>> A.ang_vel_in(N) + 10*N.x + + """ + + if value == 0: + value = Vector(0) + value = _check_vector(value) + _check_frame(otherframe) + self._ang_vel_dict.update({otherframe: value}) + otherframe._ang_vel_dict.update({self: -value}) + + @property + def x(self): + """The basis Vector for the ReferenceFrame, in the x direction. """ + return self._x + + @property + def y(self): + """The basis Vector for the ReferenceFrame, in the y direction. """ + return self._y + + @property + def z(self): + """The basis Vector for the ReferenceFrame, in the z direction. """ + return self._z + + @property + def xx(self): + """Unit dyad of basis Vectors x and x for the ReferenceFrame.""" + return Vector.outer(self.x, self.x) + + @property + def xy(self): + """Unit dyad of basis Vectors x and y for the ReferenceFrame.""" + return Vector.outer(self.x, self.y) + + @property + def xz(self): + """Unit dyad of basis Vectors x and z for the ReferenceFrame.""" + return Vector.outer(self.x, self.z) + + @property + def yx(self): + """Unit dyad of basis Vectors y and x for the ReferenceFrame.""" + return Vector.outer(self.y, self.x) + + @property + def yy(self): + """Unit dyad of basis Vectors y and y for the ReferenceFrame.""" + return Vector.outer(self.y, self.y) + + @property + def yz(self): + """Unit dyad of basis Vectors y and z for the ReferenceFrame.""" + return Vector.outer(self.y, self.z) + + @property + def zx(self): + """Unit dyad of basis Vectors z and x for the ReferenceFrame.""" + return Vector.outer(self.z, self.x) + + @property + def zy(self): + """Unit dyad of basis Vectors z and y for the ReferenceFrame.""" + return Vector.outer(self.z, self.y) + + @property + def zz(self): + """Unit dyad of basis Vectors z and z for the ReferenceFrame.""" + return Vector.outer(self.z, self.z) + + @property + def u(self): + """Unit dyadic for the ReferenceFrame.""" + return self.xx + self.yy + self.zz + + def partial_velocity(self, frame, *gen_speeds): + """Returns the partial angular velocities of this frame in the given + frame with respect to one or more provided generalized speeds. + + Parameters + ========== + frame : ReferenceFrame + The frame with which the angular velocity is defined in. + gen_speeds : functions of time + The generalized speeds. + + Returns + ======= + partial_velocities : tuple of Vector + The partial angular velocity vectors corresponding to the provided + generalized speeds. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> u1, u2 = dynamicsymbols('u1, u2') + >>> A.set_ang_vel(N, u1 * A.x + u2 * N.y) + >>> A.partial_velocity(N, u1) + A.x + >>> A.partial_velocity(N, u1, u2) + (A.x, N.y) + + """ + + from sympy.physics.vector.functions import partial_velocity + + vel = self.ang_vel_in(frame) + partials = partial_velocity([vel], gen_speeds, frame)[0] + + if len(partials) == 1: + return partials[0] + else: + return tuple(partials) + + +def _check_frame(other): + from .vector import VectorTypeError + if not isinstance(other, ReferenceFrame): + raise VectorTypeError(other, ReferenceFrame('A')) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/functions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/functions.py new file mode 100644 index 0000000000000000000000000000000000000000..6775b4b23bb376992d6a9e7651ba73a951c84287 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/functions.py @@ -0,0 +1,650 @@ +from functools import reduce + +from sympy import (sympify, diff, sin, cos, Matrix, symbols, + Function, S, Symbol, linear_eq_to_matrix) +from sympy.integrals.integrals import integrate +from sympy.simplify.trigsimp import trigsimp +from .vector import Vector, _check_vector +from .frame import CoordinateSym, _check_frame +from .dyadic import Dyadic +from .printing import vprint, vsprint, vpprint, vlatex, init_vprinting +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import translate + +__all__ = ['cross', 'dot', 'express', 'time_derivative', 'outer', + 'kinematic_equations', 'get_motion_params', 'partial_velocity', + 'dynamicsymbols', 'vprint', 'vsprint', 'vpprint', 'vlatex', + 'init_vprinting'] + + +def cross(vec1, vec2): + """Cross product convenience wrapper for Vector.cross(): \n""" + if not isinstance(vec1, (Vector, Dyadic)): + raise TypeError('Cross product is between two vectors') + return vec1 ^ vec2 + + +cross.__doc__ += Vector.cross.__doc__ # type: ignore + + +def dot(vec1, vec2): + """Dot product convenience wrapper for Vector.dot(): \n""" + if not isinstance(vec1, (Vector, Dyadic)): + raise TypeError('Dot product is between two vectors') + return vec1 & vec2 + + +dot.__doc__ += Vector.dot.__doc__ # type: ignore + + +def express(expr, frame, frame2=None, variables=False): + """ + Global function for 'express' functionality. + + Re-expresses a Vector, scalar(sympyfiable) or Dyadic in given frame. + + Refer to the local methods of Vector and Dyadic for details. + If 'variables' is True, then the coordinate variables (CoordinateSym + instances) of other frames present in the vector/scalar field or + dyadic expression are also substituted in terms of the base scalars of + this frame. + + Parameters + ========== + + expr : Vector/Dyadic/scalar(sympyfiable) + The expression to re-express in ReferenceFrame 'frame' + + frame: ReferenceFrame + The reference frame to express expr in + + frame2 : ReferenceFrame + The other frame required for re-expression(only for Dyadic expr) + + variables : boolean + Specifies whether to substitute the coordinate variables present + in expr, in terms of those of frame + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> N = ReferenceFrame('N') + >>> q = dynamicsymbols('q') + >>> B = N.orientnew('B', 'Axis', [q, N.z]) + >>> d = outer(N.x, N.x) + >>> from sympy.physics.vector import express + >>> express(d, B, N) + cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x) + >>> express(B.x, N) + cos(q)*N.x + sin(q)*N.y + >>> express(N[0], B, variables=True) + B_x*cos(q) - B_y*sin(q) + + """ + + _check_frame(frame) + + if expr == 0: + return expr + + if isinstance(expr, Vector): + # Given expr is a Vector + if variables: + # If variables attribute is True, substitute the coordinate + # variables in the Vector + frame_list = [x[-1] for x in expr.args] + subs_dict = {} + for f in frame_list: + subs_dict.update(f.variable_map(frame)) + expr = expr.subs(subs_dict) + # Re-express in this frame + outvec = Vector([]) + for v in expr.args: + if v[1] != frame: + temp = frame.dcm(v[1]) * v[0] + if Vector.simp: + temp = temp.applyfunc(lambda x: + trigsimp(x, method='fu')) + outvec += Vector([(temp, frame)]) + else: + outvec += Vector([v]) + return outvec + + if isinstance(expr, Dyadic): + if frame2 is None: + frame2 = frame + _check_frame(frame2) + ol = Dyadic(0) + for v in expr.args: + ol += express(v[0], frame, variables=variables) * \ + (express(v[1], frame, variables=variables) | + express(v[2], frame2, variables=variables)) + return ol + + else: + if variables: + # Given expr is a scalar field + frame_set = set() + expr = sympify(expr) + # Substitute all the coordinate variables + for x in expr.free_symbols: + if isinstance(x, CoordinateSym) and x.frame != frame: + frame_set.add(x.frame) + subs_dict = {} + for f in frame_set: + subs_dict.update(f.variable_map(frame)) + return expr.subs(subs_dict) + return expr + + +def time_derivative(expr, frame, order=1): + """ + Calculate the time derivative of a vector/scalar field function + or dyadic expression in given frame. + + References + ========== + + https://en.wikipedia.org/wiki/Rotating_reference_frame#Time_derivatives_in_the_two_frames + + Parameters + ========== + + expr : Vector/Dyadic/sympifyable + The expression whose time derivative is to be calculated + + frame : ReferenceFrame + The reference frame to calculate the time derivative in + + order : integer + The order of the derivative to be calculated + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> from sympy import Symbol + >>> q1 = Symbol('q1') + >>> u1 = dynamicsymbols('u1') + >>> N = ReferenceFrame('N') + >>> A = N.orientnew('A', 'Axis', [q1, N.x]) + >>> v = u1 * N.x + >>> A.set_ang_vel(N, 10*A.x) + >>> from sympy.physics.vector import time_derivative + >>> time_derivative(v, N) + u1'*N.x + >>> time_derivative(u1*A[0], N) + N_x*u1' + >>> B = N.orientnew('B', 'Axis', [u1, N.z]) + >>> from sympy.physics.vector import outer + >>> d = outer(N.x, N.x) + >>> time_derivative(d, B) + - u1'*(N.y|N.x) - u1'*(N.x|N.y) + + """ + + t = dynamicsymbols._t + _check_frame(frame) + + if order == 0: + return expr + if order % 1 != 0 or order < 0: + raise ValueError("Unsupported value of order entered") + + if isinstance(expr, Vector): + outlist = [] + for v in expr.args: + if v[1] == frame: + outlist += [(express(v[0], frame, variables=True).diff(t), + frame)] + else: + outlist += (time_derivative(Vector([v]), v[1]) + + (v[1].ang_vel_in(frame) ^ Vector([v]))).args + outvec = Vector(outlist) + return time_derivative(outvec, frame, order - 1) + + if isinstance(expr, Dyadic): + ol = Dyadic(0) + for v in expr.args: + ol += (v[0].diff(t) * (v[1] | v[2])) + ol += (v[0] * (time_derivative(v[1], frame) | v[2])) + ol += (v[0] * (v[1] | time_derivative(v[2], frame))) + return time_derivative(ol, frame, order - 1) + + else: + return diff(express(expr, frame, variables=True), t, order) + + +def outer(vec1, vec2): + """Outer product convenience wrapper for Vector.outer():\n""" + if not isinstance(vec1, Vector): + raise TypeError('Outer product is between two Vectors') + return vec1.outer(vec2) + + +outer.__doc__ += Vector.outer.__doc__ # type: ignore + + +def kinematic_equations(speeds, coords, rot_type, rot_order=''): + """Gives equations relating the qdot's to u's for a rotation type. + + Supply rotation type and order as in orient. Speeds are assumed to be + body-fixed; if we are defining the orientation of B in A using by rot_type, + the angular velocity of B in A is assumed to be in the form: speed[0]*B.x + + speed[1]*B.y + speed[2]*B.z + + Parameters + ========== + + speeds : list of length 3 + The body fixed angular velocity measure numbers. + coords : list of length 3 or 4 + The coordinates used to define the orientation of the two frames. + rot_type : str + The type of rotation used to create the equations. Body, Space, or + Quaternion only + rot_order : str or int + If applicable, the order of a series of rotations. + + Examples + ======== + + >>> from sympy.physics.vector import dynamicsymbols + >>> from sympy.physics.vector import kinematic_equations, vprint + >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') + >>> q1, q2, q3 = dynamicsymbols('q1 q2 q3') + >>> vprint(kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', '313'), + ... order=None) + [-(u1*sin(q3) + u2*cos(q3))/sin(q2) + q1', -u1*cos(q3) + u2*sin(q3) + q2', (u1*sin(q3) + u2*cos(q3))*cos(q2)/sin(q2) - u3 + q3'] + + """ + + # Code below is checking and sanitizing input + approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', + '212', '232', '313', '323', '1', '2', '3', '') + # make sure XYZ => 123 and rot_type is in lower case + rot_order = translate(str(rot_order), 'XYZxyz', '123123') + rot_type = rot_type.lower() + + if not isinstance(speeds, (list, tuple)): + raise TypeError('Need to supply speeds in a list') + if len(speeds) != 3: + raise TypeError('Need to supply 3 body-fixed speeds') + if not isinstance(coords, (list, tuple)): + raise TypeError('Need to supply coordinates in a list') + if rot_type in ['body', 'space']: + if rot_order not in approved_orders: + raise ValueError('Not an acceptable rotation order') + if len(coords) != 3: + raise ValueError('Need 3 coordinates for body or space') + # Actual hard-coded kinematic differential equations + w1, w2, w3 = speeds + if w1 == w2 == w3 == 0: + return [S.Zero]*3 + q1, q2, q3 = coords + q1d, q2d, q3d = [diff(i, dynamicsymbols._t) for i in coords] + s1, s2, s3 = [sin(q1), sin(q2), sin(q3)] + c1, c2, c3 = [cos(q1), cos(q2), cos(q3)] + if rot_type == 'body': + if rot_order == '123': + return [q1d - (w1 * c3 - w2 * s3) / c2, q2d - w1 * s3 - w2 * + c3, q3d - (-w1 * c3 + w2 * s3) * s2 / c2 - w3] + if rot_order == '231': + return [q1d - (w2 * c3 - w3 * s3) / c2, q2d - w2 * s3 - w3 * + c3, q3d - w1 - (- w2 * c3 + w3 * s3) * s2 / c2] + if rot_order == '312': + return [q1d - (-w1 * s3 + w3 * c3) / c2, q2d - w1 * c3 - w3 * + s3, q3d - (w1 * s3 - w3 * c3) * s2 / c2 - w2] + if rot_order == '132': + return [q1d - (w1 * c3 + w3 * s3) / c2, q2d + w1 * s3 - w3 * + c3, q3d - (w1 * c3 + w3 * s3) * s2 / c2 - w2] + if rot_order == '213': + return [q1d - (w1 * s3 + w2 * c3) / c2, q2d - w1 * c3 + w2 * + s3, q3d - (w1 * s3 + w2 * c3) * s2 / c2 - w3] + if rot_order == '321': + return [q1d - (w2 * s3 + w3 * c3) / c2, q2d - w2 * c3 + w3 * + s3, q3d - w1 - (w2 * s3 + w3 * c3) * s2 / c2] + if rot_order == '121': + return [q1d - (w2 * s3 + w3 * c3) / s2, q2d - w2 * c3 + w3 * + s3, q3d - w1 + (w2 * s3 + w3 * c3) * c2 / s2] + if rot_order == '131': + return [q1d - (-w2 * c3 + w3 * s3) / s2, q2d - w2 * s3 - w3 * + c3, q3d - w1 - (w2 * c3 - w3 * s3) * c2 / s2] + if rot_order == '212': + return [q1d - (w1 * s3 - w3 * c3) / s2, q2d - w1 * c3 - w3 * + s3, q3d - (-w1 * s3 + w3 * c3) * c2 / s2 - w2] + if rot_order == '232': + return [q1d - (w1 * c3 + w3 * s3) / s2, q2d + w1 * s3 - w3 * + c3, q3d + (w1 * c3 + w3 * s3) * c2 / s2 - w2] + if rot_order == '313': + return [q1d - (w1 * s3 + w2 * c3) / s2, q2d - w1 * c3 + w2 * + s3, q3d + (w1 * s3 + w2 * c3) * c2 / s2 - w3] + if rot_order == '323': + return [q1d - (-w1 * c3 + w2 * s3) / s2, q2d - w1 * s3 - w2 * + c3, q3d - (w1 * c3 - w2 * s3) * c2 / s2 - w3] + if rot_type == 'space': + if rot_order == '123': + return [q1d - w1 - (w2 * s1 + w3 * c1) * s2 / c2, q2d - w2 * + c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / c2] + if rot_order == '231': + return [q1d - (w1 * c1 + w3 * s1) * s2 / c2 - w2, q2d + w1 * + s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / c2] + if rot_order == '312': + return [q1d - (w1 * s1 + w2 * c1) * s2 / c2 - w3, q2d - w1 * + c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / c2] + if rot_order == '132': + return [q1d - w1 - (-w2 * c1 + w3 * s1) * s2 / c2, q2d - w2 * + s1 - w3 * c1, q3d - (w2 * c1 - w3 * s1) / c2] + if rot_order == '213': + return [q1d - (w1 * s1 - w3 * c1) * s2 / c2 - w2, q2d - w1 * + c1 - w3 * s1, q3d - (-w1 * s1 + w3 * c1) / c2] + if rot_order == '321': + return [q1d - (-w1 * c1 + w2 * s1) * s2 / c2 - w3, q2d - w1 * + s1 - w2 * c1, q3d - (w1 * c1 - w2 * s1) / c2] + if rot_order == '121': + return [q1d - w1 + (w2 * s1 + w3 * c1) * c2 / s2, q2d - w2 * + c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / s2] + if rot_order == '131': + return [q1d - w1 - (w2 * c1 - w3 * s1) * c2 / s2, q2d - w2 * + s1 - w3 * c1, q3d - (-w2 * c1 + w3 * s1) / s2] + if rot_order == '212': + return [q1d - (-w1 * s1 + w3 * c1) * c2 / s2 - w2, q2d - w1 * + c1 - w3 * s1, q3d - (w1 * s1 - w3 * c1) / s2] + if rot_order == '232': + return [q1d + (w1 * c1 + w3 * s1) * c2 / s2 - w2, q2d + w1 * + s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / s2] + if rot_order == '313': + return [q1d + (w1 * s1 + w2 * c1) * c2 / s2 - w3, q2d - w1 * + c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / s2] + if rot_order == '323': + return [q1d - (w1 * c1 - w2 * s1) * c2 / s2 - w3, q2d - w1 * + s1 - w2 * c1, q3d - (-w1 * c1 + w2 * s1) / s2] + elif rot_type == 'quaternion': + if rot_order != '': + raise ValueError('Cannot have rotation order for quaternion') + if len(coords) != 4: + raise ValueError('Need 4 coordinates for quaternion') + # Actual hard-coded kinematic differential equations + e0, e1, e2, e3 = coords + w = Matrix(speeds + [0]) + E = Matrix([[e0, -e3, e2, e1], + [e3, e0, -e1, e2], + [-e2, e1, e0, e3], + [-e1, -e2, -e3, e0]]) + edots = Matrix([diff(i, dynamicsymbols._t) for i in [e1, e2, e3, e0]]) + return list(edots.T - 0.5 * w.T * E.T) + else: + raise ValueError('Not an approved rotation type for this function') + + +def get_motion_params(frame, **kwargs): + """ + Returns the three motion parameters - (acceleration, velocity, and + position) as vectorial functions of time in the given frame. + + If a higher order differential function is provided, the lower order + functions are used as boundary conditions. For example, given the + acceleration, the velocity and position parameters are taken as + boundary conditions. + + The values of time at which the boundary conditions are specified + are taken from timevalue1(for position boundary condition) and + timevalue2(for velocity boundary condition). + + If any of the boundary conditions are not provided, they are taken + to be zero by default (zero vectors, in case of vectorial inputs). If + the boundary conditions are also functions of time, they are converted + to constants by substituting the time values in the dynamicsymbols._t + time Symbol. + + This function can also be used for calculating rotational motion + parameters. Have a look at the Parameters and Examples for more clarity. + + Parameters + ========== + + frame : ReferenceFrame + The frame to express the motion parameters in + + acceleration : Vector + Acceleration of the object/frame as a function of time + + velocity : Vector + Velocity as function of time or as boundary condition + of velocity at time = timevalue1 + + position : Vector + Velocity as function of time or as boundary condition + of velocity at time = timevalue1 + + timevalue1 : sympyfiable + Value of time for position boundary condition + + timevalue2 : sympyfiable + Value of time for velocity boundary condition + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, get_motion_params, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> from sympy import symbols + >>> R = ReferenceFrame('R') + >>> v1, v2, v3 = dynamicsymbols('v1 v2 v3') + >>> v = v1*R.x + v2*R.y + v3*R.z + >>> get_motion_params(R, position = v) + (v1''*R.x + v2''*R.y + v3''*R.z, v1'*R.x + v2'*R.y + v3'*R.z, v1*R.x + v2*R.y + v3*R.z) + >>> a, b, c = symbols('a b c') + >>> v = a*R.x + b*R.y + c*R.z + >>> get_motion_params(R, velocity = v) + (0, a*R.x + b*R.y + c*R.z, a*t*R.x + b*t*R.y + c*t*R.z) + >>> parameters = get_motion_params(R, acceleration = v) + >>> parameters[1] + a*t*R.x + b*t*R.y + c*t*R.z + >>> parameters[2] + a*t**2/2*R.x + b*t**2/2*R.y + c*t**2/2*R.z + + """ + + def _process_vector_differential(vectdiff, condition, variable, ordinate, + frame): + """ + Helper function for get_motion methods. Finds derivative of vectdiff + wrt variable, and its integral using the specified boundary condition + at value of variable = ordinate. + Returns a tuple of - (derivative, function and integral) wrt vectdiff + + """ + + # Make sure boundary condition is independent of 'variable' + if condition != 0: + condition = express(condition, frame, variables=True) + # Special case of vectdiff == 0 + if vectdiff == Vector(0): + return (0, 0, condition) + # Express vectdiff completely in condition's frame to give vectdiff1 + vectdiff1 = express(vectdiff, frame) + # Find derivative of vectdiff + vectdiff2 = time_derivative(vectdiff, frame) + # Integrate and use boundary condition + vectdiff0 = Vector(0) + lims = (variable, ordinate, variable) + for dim in frame: + function1 = vectdiff1.dot(dim) + abscissa = dim.dot(condition).subs({variable: ordinate}) + # Indefinite integral of 'function1' wrt 'variable', using + # the given initial condition (ordinate, abscissa). + vectdiff0 += (integrate(function1, lims) + abscissa) * dim + # Return tuple + return (vectdiff2, vectdiff, vectdiff0) + + _check_frame(frame) + # Decide mode of operation based on user's input + if 'acceleration' in kwargs: + mode = 2 + elif 'velocity' in kwargs: + mode = 1 + else: + mode = 0 + # All the possible parameters in kwargs + # Not all are required for every case + # If not specified, set to default values(may or may not be used in + # calculations) + conditions = ['acceleration', 'velocity', 'position', + 'timevalue', 'timevalue1', 'timevalue2'] + for i, x in enumerate(conditions): + if x not in kwargs: + if i < 3: + kwargs[x] = Vector(0) + else: + kwargs[x] = S.Zero + elif i < 3: + _check_vector(kwargs[x]) + else: + kwargs[x] = sympify(kwargs[x]) + if mode == 2: + vel = _process_vector_differential(kwargs['acceleration'], + kwargs['velocity'], + dynamicsymbols._t, + kwargs['timevalue2'], frame)[2] + pos = _process_vector_differential(vel, kwargs['position'], + dynamicsymbols._t, + kwargs['timevalue1'], frame)[2] + return (kwargs['acceleration'], vel, pos) + elif mode == 1: + return _process_vector_differential(kwargs['velocity'], + kwargs['position'], + dynamicsymbols._t, + kwargs['timevalue1'], frame) + else: + vel = time_derivative(kwargs['position'], frame) + acc = time_derivative(vel, frame) + return (acc, vel, kwargs['position']) + + +def partial_velocity(vel_vecs, gen_speeds, frame): + """Returns a list of partial velocities with respect to the provided + generalized speeds in the given reference frame for each of the supplied + velocity vectors. + + The output is a list of lists. The outer list has a number of elements + equal to the number of supplied velocity vectors. The inner lists are, for + each velocity vector, the partial derivatives of that velocity vector with + respect to the generalized speeds supplied. + + Parameters + ========== + + vel_vecs : iterable + An iterable of velocity vectors (angular or linear). + gen_speeds : iterable + An iterable of generalized speeds. + frame : ReferenceFrame + The reference frame that the partial derivatives are going to be taken + in. + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame + >>> from sympy.physics.vector import dynamicsymbols + >>> from sympy.physics.vector import partial_velocity + >>> u = dynamicsymbols('u') + >>> N = ReferenceFrame('N') + >>> P = Point('P') + >>> P.set_vel(N, u * N.x) + >>> vel_vecs = [P.vel(N)] + >>> gen_speeds = [u] + >>> partial_velocity(vel_vecs, gen_speeds, N) + [[N.x]] + + """ + + if not iterable(vel_vecs): + raise TypeError('Velocity vectors must be contained in an iterable.') + + if not iterable(gen_speeds): + raise TypeError('Generalized speeds must be contained in an iterable') + + vec_partials = [] + gen_speeds = list(gen_speeds) + for vel in vel_vecs: + partials = [Vector(0) for _ in gen_speeds] + for components, ref in vel.args: + mat, _ = linear_eq_to_matrix(components, gen_speeds) + for i in range(len(gen_speeds)): + for dim, direction in enumerate(ref): + if mat[dim, i] != 0: + partials[i] += direction * mat[dim, i] + + vec_partials.append(partials) + + return vec_partials + + +def dynamicsymbols(names, level=0, **assumptions): + """Uses symbols and Function for functions of time. + + Creates a SymPy UndefinedFunction, which is then initialized as a function + of a variable, the default being Symbol('t'). + + Parameters + ========== + + names : str + Names of the dynamic symbols you want to create; works the same way as + inputs to symbols + level : int + Level of differentiation of the returned function; d/dt once of t, + twice of t, etc. + assumptions : + - real(bool) : This is used to set the dynamicsymbol as real, + by default is False. + - positive(bool) : This is used to set the dynamicsymbol as positive, + by default is False. + - commutative(bool) : This is used to set the commutative property of + a dynamicsymbol, by default is True. + - integer(bool) : This is used to set the dynamicsymbol as integer, + by default is False. + + Examples + ======== + + >>> from sympy.physics.vector import dynamicsymbols + >>> from sympy import diff, Symbol + >>> q1 = dynamicsymbols('q1') + >>> q1 + q1(t) + >>> q2 = dynamicsymbols('q2', real=True) + >>> q2.is_real + True + >>> q3 = dynamicsymbols('q3', positive=True) + >>> q3.is_positive + True + >>> q4, q5 = dynamicsymbols('q4,q5', commutative=False) + >>> bool(q4*q5 != q5*q4) + True + >>> q6 = dynamicsymbols('q6', integer=True) + >>> q6.is_integer + True + >>> diff(q1, Symbol('t')) + Derivative(q1(t), t) + + """ + esses = symbols(names, cls=Function, **assumptions) + t = dynamicsymbols._t + if iterable(esses): + esses = [reduce(diff, [t] * level, e(t)) for e in esses] + return esses + else: + return reduce(diff, [t] * level, esses(t)) + + +dynamicsymbols._t = Symbol('t') # type: ignore +dynamicsymbols._str = '\'' # type: ignore diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/point.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/point.py new file mode 100644 index 0000000000000000000000000000000000000000..2841f9d465883b6fa6e1b5dc8bc0c107f18b65f7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/point.py @@ -0,0 +1,635 @@ +from .vector import Vector, _check_vector +from .frame import _check_frame +from warnings import warn +from sympy.utilities.misc import filldedent + +__all__ = ['Point'] + + +class Point: + """This object represents a point in a dynamic system. + + It stores the: position, velocity, and acceleration of a point. + The position is a vector defined as the vector distance from a parent + point to this point. + + Parameters + ========== + + name : string + The display name of the Point + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> N = ReferenceFrame('N') + >>> O = Point('O') + >>> P = Point('P') + >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') + >>> O.set_vel(N, u1 * N.x + u2 * N.y + u3 * N.z) + >>> O.acc(N) + u1'*N.x + u2'*N.y + u3'*N.z + + ``symbols()`` can be used to create multiple Points in a single step, for + example: + + >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> from sympy import symbols + >>> N = ReferenceFrame('N') + >>> u1, u2 = dynamicsymbols('u1 u2') + >>> A, B = symbols('A B', cls=Point) + >>> type(A) + + >>> A.set_vel(N, u1 * N.x + u2 * N.y) + >>> B.set_vel(N, u2 * N.x + u1 * N.y) + >>> A.acc(N) - B.acc(N) + (u1' - u2')*N.x + (-u1' + u2')*N.y + + """ + + def __init__(self, name): + """Initialization of a Point object. """ + self.name = name + self._pos_dict = {} + self._vel_dict = {} + self._acc_dict = {} + self._pdlist = [self._pos_dict, self._vel_dict, self._acc_dict] + + def __str__(self): + return self.name + + __repr__ = __str__ + + def _check_point(self, other): + if not isinstance(other, Point): + raise TypeError('A Point must be supplied') + + def _pdict_list(self, other, num): + """Returns a list of points that gives the shortest path with respect + to position, velocity, or acceleration from this point to the provided + point. + + Parameters + ========== + other : Point + A point that may be related to this point by position, velocity, or + acceleration. + num : integer + 0 for searching the position tree, 1 for searching the velocity + tree, and 2 for searching the acceleration tree. + + Returns + ======= + list of Points + A sequence of points from self to other. + + Notes + ===== + + It is not clear if num = 1 or num = 2 actually works because the keys + to ``_vel_dict`` and ``_acc_dict`` are :class:`ReferenceFrame` objects + which do not have the ``_pdlist`` attribute. + + """ + outlist = [[self]] + oldlist = [[]] + while outlist != oldlist: + oldlist = outlist.copy() + for v in outlist: + templist = v[-1]._pdlist[num].keys() + for v2 in templist: + if not v.__contains__(v2): + littletemplist = v + [v2] + if not outlist.__contains__(littletemplist): + outlist.append(littletemplist) + for v in oldlist: + if v[-1] != other: + outlist.remove(v) + outlist.sort(key=len) + if len(outlist) != 0: + return outlist[0] + raise ValueError('No Connecting Path found between ' + other.name + + ' and ' + self.name) + + def a1pt_theory(self, otherpoint, outframe, interframe): + """Sets the acceleration of this point with the 1-point theory. + + The 1-point theory for point acceleration looks like this: + + ^N a^P = ^B a^P + ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B + x r^OP) + 2 ^N omega^B x ^B v^P + + where O is a point fixed in B, P is a point moving in B, and B is + rotating in frame N. + + Parameters + ========== + + otherpoint : Point + The first point of the 1-point theory (O) + outframe : ReferenceFrame + The frame we want this point's acceleration defined in (N) + fixedframe : ReferenceFrame + The intermediate frame in this calculation (B) + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame + >>> from sympy.physics.vector import dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> q = dynamicsymbols('q') + >>> q2 = dynamicsymbols('q2') + >>> qd = dynamicsymbols('q', 1) + >>> q2d = dynamicsymbols('q2', 1) + >>> N = ReferenceFrame('N') + >>> B = ReferenceFrame('B') + >>> B.set_ang_vel(N, 5 * B.y) + >>> O = Point('O') + >>> P = O.locatenew('P', q * B.x + q2 * B.y) + >>> P.set_vel(B, qd * B.x + q2d * B.y) + >>> O.set_vel(N, 0) + >>> P.a1pt_theory(O, N, B) + (-25*q + q'')*B.x + q2''*B.y - 10*q'*B.z + + """ + + _check_frame(outframe) + _check_frame(interframe) + self._check_point(otherpoint) + dist = self.pos_from(otherpoint) + v = self.vel(interframe) + a1 = otherpoint.acc(outframe) + a2 = self.acc(interframe) + omega = interframe.ang_vel_in(outframe) + alpha = interframe.ang_acc_in(outframe) + self.set_acc(outframe, a2 + 2 * (omega.cross(v)) + a1 + + (alpha.cross(dist)) + (omega.cross(omega.cross(dist)))) + return self.acc(outframe) + + def a2pt_theory(self, otherpoint, outframe, fixedframe): + """Sets the acceleration of this point with the 2-point theory. + + The 2-point theory for point acceleration looks like this: + + ^N a^P = ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B x r^OP) + + where O and P are both points fixed in frame B, which is rotating in + frame N. + + Parameters + ========== + + otherpoint : Point + The first point of the 2-point theory (O) + outframe : ReferenceFrame + The frame we want this point's acceleration defined in (N) + fixedframe : ReferenceFrame + The frame in which both points are fixed (B) + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> q = dynamicsymbols('q') + >>> qd = dynamicsymbols('q', 1) + >>> N = ReferenceFrame('N') + >>> B = N.orientnew('B', 'Axis', [q, N.z]) + >>> O = Point('O') + >>> P = O.locatenew('P', 10 * B.x) + >>> O.set_vel(N, 5 * N.x) + >>> P.a2pt_theory(O, N, B) + - 10*q'**2*B.x + 10*q''*B.y + + """ + + _check_frame(outframe) + _check_frame(fixedframe) + self._check_point(otherpoint) + dist = self.pos_from(otherpoint) + a = otherpoint.acc(outframe) + omega = fixedframe.ang_vel_in(outframe) + alpha = fixedframe.ang_acc_in(outframe) + self.set_acc(outframe, a + (alpha.cross(dist)) + + (omega.cross(omega.cross(dist)))) + return self.acc(outframe) + + def acc(self, frame): + """The acceleration Vector of this Point in a ReferenceFrame. + + Parameters + ========== + + frame : ReferenceFrame + The frame in which the returned acceleration vector will be defined + in. + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame + >>> N = ReferenceFrame('N') + >>> p1 = Point('p1') + >>> p1.set_acc(N, 10 * N.x) + >>> p1.acc(N) + 10*N.x + + """ + + _check_frame(frame) + if not (frame in self._acc_dict): + if self.vel(frame) != 0: + return (self._vel_dict[frame]).dt(frame) + else: + return Vector(0) + return self._acc_dict[frame] + + def locatenew(self, name, value): + """Creates a new point with a position defined from this point. + + Parameters + ========== + + name : str + The name for the new point + value : Vector + The position of the new point relative to this point + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, Point + >>> N = ReferenceFrame('N') + >>> P1 = Point('P1') + >>> P2 = P1.locatenew('P2', 10 * N.x) + + """ + + if not isinstance(name, str): + raise TypeError('Must supply a valid name') + if value == 0: + value = Vector(0) + value = _check_vector(value) + p = Point(name) + p.set_pos(self, value) + self.set_pos(p, -value) + return p + + def pos_from(self, otherpoint): + """Returns a Vector distance between this Point and the other Point. + + Parameters + ========== + + otherpoint : Point + The otherpoint we are locating this one relative to + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame + >>> N = ReferenceFrame('N') + >>> p1 = Point('p1') + >>> p2 = Point('p2') + >>> p1.set_pos(p2, 10 * N.x) + >>> p1.pos_from(p2) + 10*N.x + + """ + + outvec = Vector(0) + plist = self._pdict_list(otherpoint, 0) + for i in range(len(plist) - 1): + outvec += plist[i]._pos_dict[plist[i + 1]] + return outvec + + def set_acc(self, frame, value): + """Used to set the acceleration of this Point in a ReferenceFrame. + + Parameters + ========== + + frame : ReferenceFrame + The frame in which this point's acceleration is defined + value : Vector + The vector value of this point's acceleration in the frame + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame + >>> N = ReferenceFrame('N') + >>> p1 = Point('p1') + >>> p1.set_acc(N, 10 * N.x) + >>> p1.acc(N) + 10*N.x + + """ + + if value == 0: + value = Vector(0) + value = _check_vector(value) + _check_frame(frame) + self._acc_dict.update({frame: value}) + + def set_pos(self, otherpoint, value): + """Used to set the position of this point w.r.t. another point. + + Parameters + ========== + + otherpoint : Point + The other point which this point's location is defined relative to + value : Vector + The vector which defines the location of this point + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame + >>> N = ReferenceFrame('N') + >>> p1 = Point('p1') + >>> p2 = Point('p2') + >>> p1.set_pos(p2, 10 * N.x) + >>> p1.pos_from(p2) + 10*N.x + + """ + + if value == 0: + value = Vector(0) + value = _check_vector(value) + self._check_point(otherpoint) + self._pos_dict.update({otherpoint: value}) + otherpoint._pos_dict.update({self: -value}) + + def set_vel(self, frame, value): + """Sets the velocity Vector of this Point in a ReferenceFrame. + + Parameters + ========== + + frame : ReferenceFrame + The frame in which this point's velocity is defined + value : Vector + The vector value of this point's velocity in the frame + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame + >>> N = ReferenceFrame('N') + >>> p1 = Point('p1') + >>> p1.set_vel(N, 10 * N.x) + >>> p1.vel(N) + 10*N.x + + """ + + if value == 0: + value = Vector(0) + value = _check_vector(value) + _check_frame(frame) + self._vel_dict.update({frame: value}) + + def v1pt_theory(self, otherpoint, outframe, interframe): + """Sets the velocity of this point with the 1-point theory. + + The 1-point theory for point velocity looks like this: + + ^N v^P = ^B v^P + ^N v^O + ^N omega^B x r^OP + + where O is a point fixed in B, P is a point moving in B, and B is + rotating in frame N. + + Parameters + ========== + + otherpoint : Point + The first point of the 1-point theory (O) + outframe : ReferenceFrame + The frame we want this point's velocity defined in (N) + interframe : ReferenceFrame + The intermediate frame in this calculation (B) + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame + >>> from sympy.physics.vector import dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> q = dynamicsymbols('q') + >>> q2 = dynamicsymbols('q2') + >>> qd = dynamicsymbols('q', 1) + >>> q2d = dynamicsymbols('q2', 1) + >>> N = ReferenceFrame('N') + >>> B = ReferenceFrame('B') + >>> B.set_ang_vel(N, 5 * B.y) + >>> O = Point('O') + >>> P = O.locatenew('P', q * B.x + q2 * B.y) + >>> P.set_vel(B, qd * B.x + q2d * B.y) + >>> O.set_vel(N, 0) + >>> P.v1pt_theory(O, N, B) + q'*B.x + q2'*B.y - 5*q*B.z + + """ + + _check_frame(outframe) + _check_frame(interframe) + self._check_point(otherpoint) + dist = self.pos_from(otherpoint) + v1 = self.vel(interframe) + v2 = otherpoint.vel(outframe) + omega = interframe.ang_vel_in(outframe) + self.set_vel(outframe, v1 + v2 + (omega.cross(dist))) + return self.vel(outframe) + + def v2pt_theory(self, otherpoint, outframe, fixedframe): + """Sets the velocity of this point with the 2-point theory. + + The 2-point theory for point velocity looks like this: + + ^N v^P = ^N v^O + ^N omega^B x r^OP + + where O and P are both points fixed in frame B, which is rotating in + frame N. + + Parameters + ========== + + otherpoint : Point + The first point of the 2-point theory (O) + outframe : ReferenceFrame + The frame we want this point's velocity defined in (N) + fixedframe : ReferenceFrame + The frame in which both points are fixed (B) + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> q = dynamicsymbols('q') + >>> qd = dynamicsymbols('q', 1) + >>> N = ReferenceFrame('N') + >>> B = N.orientnew('B', 'Axis', [q, N.z]) + >>> O = Point('O') + >>> P = O.locatenew('P', 10 * B.x) + >>> O.set_vel(N, 5 * N.x) + >>> P.v2pt_theory(O, N, B) + 5*N.x + 10*q'*B.y + + """ + + _check_frame(outframe) + _check_frame(fixedframe) + self._check_point(otherpoint) + dist = self.pos_from(otherpoint) + v = otherpoint.vel(outframe) + omega = fixedframe.ang_vel_in(outframe) + self.set_vel(outframe, v + (omega.cross(dist))) + return self.vel(outframe) + + def vel(self, frame): + """The velocity Vector of this Point in the ReferenceFrame. + + Parameters + ========== + + frame : ReferenceFrame + The frame in which the returned velocity vector will be defined in + + Examples + ======== + + >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols + >>> N = ReferenceFrame('N') + >>> p1 = Point('p1') + >>> p1.set_vel(N, 10 * N.x) + >>> p1.vel(N) + 10*N.x + + Velocities will be automatically calculated if possible, otherwise a + ``ValueError`` will be returned. If it is possible to calculate + multiple different velocities from the relative points, the points + defined most directly relative to this point will be used. In the case + of inconsistent relative positions of points, incorrect velocities may + be returned. It is up to the user to define prior relative positions + and velocities of points in a self-consistent way. + + >>> p = Point('p') + >>> q = dynamicsymbols('q') + >>> p.set_vel(N, 10 * N.x) + >>> p2 = Point('p2') + >>> p2.set_pos(p, q*N.x) + >>> p2.vel(N) + (Derivative(q(t), t) + 10)*N.x + + """ + + _check_frame(frame) + if not (frame in self._vel_dict): + valid_neighbor_found = False + is_cyclic = False + visited = [] + queue = [self] + candidate_neighbor = [] + while queue: # BFS to find nearest point + node = queue.pop(0) + if node not in visited: + visited.append(node) + for neighbor, neighbor_pos in node._pos_dict.items(): + if neighbor in visited: + continue + try: + # Checks if pos vector is valid + neighbor_pos.express(frame) + except ValueError: + continue + if neighbor in queue: + is_cyclic = True + try: + # Checks if point has its vel defined in req frame + neighbor_velocity = neighbor._vel_dict[frame] + except KeyError: + queue.append(neighbor) + continue + candidate_neighbor.append(neighbor) + if not valid_neighbor_found: + self.set_vel(frame, self.pos_from(neighbor).dt(frame) + neighbor_velocity) + valid_neighbor_found = True + if is_cyclic: + warn(filldedent(""" + Kinematic loops are defined among the positions of points. This + is likely not desired and may cause errors in your calculations. + """)) + if len(candidate_neighbor) > 1: + warn(filldedent(f""" + Velocity of {self.name} automatically calculated based on point + {candidate_neighbor[0].name} but it is also possible from + points(s): {str(candidate_neighbor[1:])}. Velocities from these + points are not necessarily the same. This may cause errors in + your calculations.""")) + if valid_neighbor_found: + return self._vel_dict[frame] + else: + raise ValueError(filldedent(f""" + Velocity of point {self.name} has not been defined in + ReferenceFrame {frame.name}.""")) + + return self._vel_dict[frame] + + def partial_velocity(self, frame, *gen_speeds): + """Returns the partial velocities of the linear velocity vector of this + point in the given frame with respect to one or more provided + generalized speeds. + + Parameters + ========== + frame : ReferenceFrame + The frame with which the velocity is defined in. + gen_speeds : functions of time + The generalized speeds. + + Returns + ======= + partial_velocities : tuple of Vector + The partial velocity vectors corresponding to the provided + generalized speeds. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, Point + >>> from sympy.physics.vector import dynamicsymbols + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> p = Point('p') + >>> u1, u2 = dynamicsymbols('u1, u2') + >>> p.set_vel(N, u1 * N.x + u2 * A.y) + >>> p.partial_velocity(N, u1) + N.x + >>> p.partial_velocity(N, u1, u2) + (N.x, A.y) + + """ + + from sympy.physics.vector.functions import partial_velocity + + vel = self.vel(frame) + partials = partial_velocity([vel], gen_speeds, frame)[0] + + if len(partials) == 1: + return partials[0] + else: + return tuple(partials) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/printing.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/printing.py new file mode 100644 index 0000000000000000000000000000000000000000..2b589f673329e1e598b9b568fba6c07b8abe67bc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/printing.py @@ -0,0 +1,371 @@ +from sympy.core.function import Derivative +from sympy.core.function import UndefinedFunction, AppliedUndef +from sympy.core.symbol import Symbol +from sympy.interactive.printing import init_printing +from sympy.printing.latex import LatexPrinter +from sympy.printing.pretty.pretty import PrettyPrinter +from sympy.printing.pretty.pretty_symbology import center_accent +from sympy.printing.str import StrPrinter +from sympy.printing.precedence import PRECEDENCE + +__all__ = ['vprint', 'vsstrrepr', 'vsprint', 'vpprint', 'vlatex', + 'init_vprinting'] + + +class VectorStrPrinter(StrPrinter): + """String Printer for vector expressions. """ + + def _print_Derivative(self, e): + from sympy.physics.vector.functions import dynamicsymbols + t = dynamicsymbols._t + if (bool(sum(i == t for i in e.variables)) & + isinstance(type(e.args[0]), UndefinedFunction)): + ol = str(e.args[0].func) + for i, v in enumerate(e.variables): + ol += dynamicsymbols._str + return ol + else: + return StrPrinter().doprint(e) + + def _print_Function(self, e): + from sympy.physics.vector.functions import dynamicsymbols + t = dynamicsymbols._t + if isinstance(type(e), UndefinedFunction): + return StrPrinter().doprint(e).replace("(%s)" % t, '') + return e.func.__name__ + "(%s)" % self.stringify(e.args, ", ") + + +class VectorStrReprPrinter(VectorStrPrinter): + """String repr printer for vector expressions.""" + def _print_str(self, s): + return repr(s) + + +class VectorLatexPrinter(LatexPrinter): + """Latex Printer for vector expressions. """ + + def _print_Function(self, expr, exp=None): + from sympy.physics.vector.functions import dynamicsymbols + func = expr.func.__name__ + t = dynamicsymbols._t + + if (hasattr(self, '_print_' + func) and not + isinstance(type(expr), UndefinedFunction)): + return getattr(self, '_print_' + func)(expr, exp) + elif isinstance(type(expr), UndefinedFunction) and (expr.args == (t,)): + # treat this function like a symbol + expr = Symbol(func) + if exp is not None: + # copied from LatexPrinter._helper_print_standard_power, which + # we can't call because we only have exp as a string. + base = self.parenthesize(expr, PRECEDENCE['Pow']) + base = self.parenthesize_super(base) + return r"%s^{%s}" % (base, exp) + else: + return super()._print(expr) + else: + return super()._print_Function(expr, exp) + + def _print_Derivative(self, der_expr): + from sympy.physics.vector.functions import dynamicsymbols + # make sure it is in the right form + der_expr = der_expr.doit() + if not isinstance(der_expr, Derivative): + return r"\left(%s\right)" % self.doprint(der_expr) + + # check if expr is a dynamicsymbol + t = dynamicsymbols._t + expr = der_expr.expr + red = expr.atoms(AppliedUndef) + syms = der_expr.variables + test1 = not all(True for i in red if i.free_symbols == {t}) + test2 = not all(t == i for i in syms) + if test1 or test2: + return super()._print_Derivative(der_expr) + + # done checking + dots = len(syms) + base = self._print_Function(expr) + base_split = base.split('_', 1) + base = base_split[0] + if dots == 1: + base = r"\dot{%s}" % base + elif dots == 2: + base = r"\ddot{%s}" % base + elif dots == 3: + base = r"\dddot{%s}" % base + elif dots == 4: + base = r"\ddddot{%s}" % base + else: # Fallback to standard printing + return super()._print_Derivative(der_expr) + if len(base_split) != 1: + base += '_' + base_split[1] + return base + + +class VectorPrettyPrinter(PrettyPrinter): + """Pretty Printer for vectorialexpressions. """ + + def _print_Derivative(self, deriv): + from sympy.physics.vector.functions import dynamicsymbols + # XXX use U('PARTIAL DIFFERENTIAL') here ? + t = dynamicsymbols._t + dot_i = 0 + syms = list(reversed(deriv.variables)) + + while len(syms) > 0: + if syms[-1] == t: + syms.pop() + dot_i += 1 + else: + return super()._print_Derivative(deriv) + + if not (isinstance(type(deriv.expr), UndefinedFunction) and + (deriv.expr.args == (t,))): + return super()._print_Derivative(deriv) + else: + pform = self._print_Function(deriv.expr) + + # the following condition would happen with some sort of non-standard + # dynamic symbol I guess, so we'll just print the SymPy way + if len(pform.picture) > 1: + return super()._print_Derivative(deriv) + + # There are only special symbols up to fourth-order derivatives + if dot_i >= 5: + return super()._print_Derivative(deriv) + + # Deal with special symbols + dots = {0: "", + 1: "\N{COMBINING DOT ABOVE}", + 2: "\N{COMBINING DIAERESIS}", + 3: "\N{COMBINING THREE DOTS ABOVE}", + 4: "\N{COMBINING FOUR DOTS ABOVE}"} + + d = pform.__dict__ + # if unicode is false then calculate number of apostrophes needed and + # add to output + if not self._use_unicode: + apostrophes = "" + for i in range(0, dot_i): + apostrophes += "'" + d['picture'][0] += apostrophes + "(t)" + else: + d['picture'] = [center_accent(d['picture'][0], dots[dot_i])] + return pform + + def _print_Function(self, e): + from sympy.physics.vector.functions import dynamicsymbols + t = dynamicsymbols._t + # XXX works only for applied functions + func = e.func + args = e.args + func_name = func.__name__ + pform = self._print_Symbol(Symbol(func_name)) + # If this function is an Undefined function of t, it is probably a + # dynamic symbol, so we'll skip the (t). The rest of the code is + # identical to the normal PrettyPrinter code + if not (isinstance(func, UndefinedFunction) and (args == (t,))): + return super()._print_Function(e) + return pform + + +def vprint(expr, **settings): + r"""Function for printing of expressions generated in the + sympy.physics vector package. + + Extends SymPy's StrPrinter, takes the same setting accepted by SymPy's + :func:`~.sstr`, and is equivalent to ``print(sstr(foo))``. + + Parameters + ========== + + expr : valid SymPy object + SymPy expression to print. + settings : args + Same as the settings accepted by SymPy's sstr(). + + Examples + ======== + + >>> from sympy.physics.vector import vprint, dynamicsymbols + >>> u1 = dynamicsymbols('u1') + >>> print(u1) + u1(t) + >>> vprint(u1) + u1 + + """ + + outstr = vsprint(expr, **settings) + + import builtins + if (outstr != 'None'): + builtins._ = outstr + print(outstr) + + +def vsstrrepr(expr, **settings): + """Function for displaying expression representation's with vector + printing enabled. + + Parameters + ========== + + expr : valid SymPy object + SymPy expression to print. + settings : args + Same as the settings accepted by SymPy's sstrrepr(). + + """ + p = VectorStrReprPrinter(settings) + return p.doprint(expr) + + +def vsprint(expr, **settings): + r"""Function for displaying expressions generated in the + sympy.physics vector package. + + Returns the output of vprint() as a string. + + Parameters + ========== + + expr : valid SymPy object + SymPy expression to print + settings : args + Same as the settings accepted by SymPy's sstr(). + + Examples + ======== + + >>> from sympy.physics.vector import vsprint, dynamicsymbols + >>> u1, u2 = dynamicsymbols('u1 u2') + >>> u2d = dynamicsymbols('u2', level=1) + >>> print("%s = %s" % (u1, u2 + u2d)) + u1(t) = u2(t) + Derivative(u2(t), t) + >>> print("%s = %s" % (vsprint(u1), vsprint(u2 + u2d))) + u1 = u2 + u2' + + """ + + string_printer = VectorStrPrinter(settings) + return string_printer.doprint(expr) + + +def vpprint(expr, **settings): + r"""Function for pretty printing of expressions generated in the + sympy.physics vector package. + + Mainly used for expressions not inside a vector; the output of running + scripts and generating equations of motion. Takes the same options as + SymPy's :func:`~.pretty_print`; see that function for more information. + + Parameters + ========== + + expr : valid SymPy object + SymPy expression to pretty print + settings : args + Same as those accepted by SymPy's pretty_print. + + + """ + + pp = VectorPrettyPrinter(settings) + + # Note that this is copied from sympy.printing.pretty.pretty_print: + + # XXX: this is an ugly hack, but at least it works + use_unicode = pp._settings['use_unicode'] + from sympy.printing.pretty.pretty_symbology import pretty_use_unicode + uflag = pretty_use_unicode(use_unicode) + + try: + return pp.doprint(expr) + finally: + pretty_use_unicode(uflag) + + +def vlatex(expr, **settings): + r"""Function for printing latex representation of sympy.physics.vector + objects. + + For latex representation of Vectors, Dyadics, and dynamicsymbols. Takes the + same options as SymPy's :func:`~.latex`; see that function for more + information; + + Parameters + ========== + + expr : valid SymPy object + SymPy expression to represent in LaTeX form + settings : args + Same as latex() + + Examples + ======== + + >>> from sympy.physics.vector import vlatex, ReferenceFrame, dynamicsymbols + >>> N = ReferenceFrame('N') + >>> q1, q2 = dynamicsymbols('q1 q2') + >>> q1d, q2d = dynamicsymbols('q1 q2', 1) + >>> q1dd, q2dd = dynamicsymbols('q1 q2', 2) + >>> vlatex(N.x + N.y) + '\\mathbf{\\hat{n}_x} + \\mathbf{\\hat{n}_y}' + >>> vlatex(q1 + q2) + 'q_{1} + q_{2}' + >>> vlatex(q1d) + '\\dot{q}_{1}' + >>> vlatex(q1 * q2d) + 'q_{1} \\dot{q}_{2}' + >>> vlatex(q1dd * q1 / q1d) + '\\frac{q_{1} \\ddot{q}_{1}}{\\dot{q}_{1}}' + + """ + latex_printer = VectorLatexPrinter(settings) + + return latex_printer.doprint(expr) + + +def init_vprinting(**kwargs): + """Initializes time derivative printing for all SymPy objects, i.e. any + functions of time will be displayed in a more compact notation. The main + benefit of this is for printing of time derivatives; instead of + displaying as ``Derivative(f(t),t)``, it will display ``f'``. This is + only actually needed for when derivatives are present and are not in a + physics.vector.Vector or physics.vector.Dyadic object. This function is a + light wrapper to :func:`~.init_printing`. Any keyword + arguments for it are valid here. + + {0} + + Examples + ======== + + >>> from sympy import Function, symbols + >>> t, x = symbols('t, x') + >>> omega = Function('omega') + >>> omega(x).diff() + Derivative(omega(x), x) + >>> omega(t).diff() + Derivative(omega(t), t) + + Now use the string printer: + + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> omega(x).diff() + Derivative(omega(x), x) + >>> omega(t).diff() + omega' + + """ + kwargs['str_printer'] = vsstrrepr + kwargs['pretty_printer'] = vpprint + kwargs['latex_printer'] = vlatex + init_printing(**kwargs) + + +params = init_printing.__doc__.split('Examples\n ========')[0] # type: ignore +init_vprinting.__doc__ = init_vprinting.__doc__.format(params) # type: ignore diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/vector.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/vector.py new file mode 100644 index 0000000000000000000000000000000000000000..96510c7c55470e0605276a924ce9777f226acd8e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/vector.py @@ -0,0 +1,806 @@ +from sympy import (S, sympify, expand, sqrt, Add, zeros, acos, + ImmutableMatrix as Matrix, simplify) +from sympy.simplify.trigsimp import trigsimp +from sympy.printing.defaults import Printable +from sympy.utilities.misc import filldedent +from sympy.core.evalf import EvalfMixin + +from mpmath.libmp.libmpf import prec_to_dps + + +__all__ = ['Vector'] + + +class Vector(Printable, EvalfMixin): + """The class used to define vectors. + + It along with ReferenceFrame are the building blocks of describing a + classical mechanics system in PyDy and sympy.physics.vector. + + Attributes + ========== + + simp : Boolean + Let certain methods use trigsimp on their outputs + + """ + + simp = False + is_number = False + + def __init__(self, inlist): + """This is the constructor for the Vector class. You should not be + calling this, it should only be used by other functions. You should be + treating Vectors like you would with if you were doing the math by + hand, and getting the first 3 from the standard basis vectors from a + ReferenceFrame. + + The only exception is to create a zero vector: + zv = Vector(0) + + """ + + self.args = [] + if inlist == 0: + inlist = [] + if isinstance(inlist, dict): + d = inlist + else: + d = {} + for inp in inlist: + if inp[1] in d: + d[inp[1]] += inp[0] + else: + d[inp[1]] = inp[0] + + for k, v in d.items(): + if v != Matrix([0, 0, 0]): + self.args.append((v, k)) + + @property + def func(self): + """Returns the class Vector. """ + return Vector + + def __hash__(self): + return hash(tuple(self.args)) + + def __add__(self, other): + """The add operator for Vector. """ + if other == 0: + return self + other = _check_vector(other) + return Vector(self.args + other.args) + + def dot(self, other): + """Dot product of two vectors. + + Returns a scalar, the dot product of the two Vectors + + Parameters + ========== + + other : Vector + The Vector which we are dotting with + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, dot + >>> from sympy import symbols + >>> q1 = symbols('q1') + >>> N = ReferenceFrame('N') + >>> dot(N.x, N.x) + 1 + >>> dot(N.x, N.y) + 0 + >>> A = N.orientnew('A', 'Axis', [q1, N.x]) + >>> dot(N.y, A.y) + cos(q1) + + """ + + from sympy.physics.vector.dyadic import Dyadic, _check_dyadic + if isinstance(other, Dyadic): + other = _check_dyadic(other) + ol = Vector(0) + for v in other.args: + ol += v[0] * v[2] * (v[1].dot(self)) + return ol + other = _check_vector(other) + out = S.Zero + for v1 in self.args: + for v2 in other.args: + out += ((v2[0].T) * (v2[1].dcm(v1[1])) * (v1[0]))[0] + if Vector.simp: + return trigsimp(out, recursive=True) + else: + return out + + def __truediv__(self, other): + """This uses mul and inputs self and 1 divided by other. """ + return self.__mul__(S.One / other) + + def __eq__(self, other): + """Tests for equality. + + It is very import to note that this is only as good as the SymPy + equality test; False does not always mean they are not equivalent + Vectors. + If other is 0, and self is empty, returns True. + If other is 0 and self is not empty, returns False. + If none of the above, only accepts other as a Vector. + + """ + + if other == 0: + other = Vector(0) + try: + other = _check_vector(other) + except TypeError: + return False + if (self.args == []) and (other.args == []): + return True + elif (self.args == []) or (other.args == []): + return False + + frame = self.args[0][1] + for v in frame: + if expand((self - other).dot(v)) != 0: + return False + return True + + def __mul__(self, other): + """Multiplies the Vector by a sympifyable expression. + + Parameters + ========== + + other : Sympifyable + The scalar to multiply this Vector with + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy import Symbol + >>> N = ReferenceFrame('N') + >>> b = Symbol('b') + >>> V = 10 * b * N.x + >>> print(V) + 10*b*N.x + + """ + + newlist = list(self.args) + other = sympify(other) + for i in range(len(newlist)): + newlist[i] = (other * newlist[i][0], newlist[i][1]) + return Vector(newlist) + + def __neg__(self): + return self * -1 + + def outer(self, other): + """Outer product between two Vectors. + + A rank increasing operation, which returns a Dyadic from two Vectors + + Parameters + ========== + + other : Vector + The Vector to take the outer product with + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, outer + >>> N = ReferenceFrame('N') + >>> outer(N.x, N.x) + (N.x|N.x) + + """ + + from sympy.physics.vector.dyadic import Dyadic + other = _check_vector(other) + ol = Dyadic(0) + for v in self.args: + for v2 in other.args: + # it looks this way because if we are in the same frame and + # use the enumerate function on the same frame in a nested + # fashion, then bad things happen + ol += Dyadic([(v[0][0] * v2[0][0], v[1].x, v2[1].x)]) + ol += Dyadic([(v[0][0] * v2[0][1], v[1].x, v2[1].y)]) + ol += Dyadic([(v[0][0] * v2[0][2], v[1].x, v2[1].z)]) + ol += Dyadic([(v[0][1] * v2[0][0], v[1].y, v2[1].x)]) + ol += Dyadic([(v[0][1] * v2[0][1], v[1].y, v2[1].y)]) + ol += Dyadic([(v[0][1] * v2[0][2], v[1].y, v2[1].z)]) + ol += Dyadic([(v[0][2] * v2[0][0], v[1].z, v2[1].x)]) + ol += Dyadic([(v[0][2] * v2[0][1], v[1].z, v2[1].y)]) + ol += Dyadic([(v[0][2] * v2[0][2], v[1].z, v2[1].z)]) + return ol + + def _latex(self, printer): + """Latex Printing method. """ + + ar = self.args # just to shorten things + if len(ar) == 0: + return str(0) + ol = [] # output list, to be concatenated to a string + for v in ar: + for j in 0, 1, 2: + # if the coef of the basis vector is 1, we skip the 1 + if v[0][j] == 1: + ol.append(' + ' + v[1].latex_vecs[j]) + # if the coef of the basis vector is -1, we skip the 1 + elif v[0][j] == -1: + ol.append(' - ' + v[1].latex_vecs[j]) + elif v[0][j] != 0: + # If the coefficient of the basis vector is not 1 or -1; + # also, we might wrap it in parentheses, for readability. + arg_str = printer._print(v[0][j]) + if isinstance(v[0][j], Add): + arg_str = "(%s)" % arg_str + if arg_str[0] == '-': + arg_str = arg_str[1:] + str_start = ' - ' + else: + str_start = ' + ' + ol.append(str_start + arg_str + v[1].latex_vecs[j]) + outstr = ''.join(ol) + if outstr.startswith(' + '): + outstr = outstr[3:] + elif outstr.startswith(' '): + outstr = outstr[1:] + return outstr + + def _pretty(self, printer): + """Pretty Printing method. """ + from sympy.printing.pretty.stringpict import prettyForm + + terms = [] + + def juxtapose(a, b): + pa = printer._print(a) + pb = printer._print(b) + if a.is_Add: + pa = prettyForm(*pa.parens()) + return printer._print_seq([pa, pb], delimiter=' ') + + for M, N in self.args: + for i in range(3): + if M[i] == 0: + continue + elif M[i] == 1: + terms.append(prettyForm(N.pretty_vecs[i])) + elif M[i] == -1: + terms.append(prettyForm("-1") * prettyForm(N.pretty_vecs[i])) + else: + terms.append(juxtapose(M[i], N.pretty_vecs[i])) + + if terms: + pretty_result = prettyForm.__add__(*terms) + else: + pretty_result = prettyForm("0") + + return pretty_result + + def __rsub__(self, other): + return (-1 * self) + other + + def _sympystr(self, printer, order=True): + """Printing method. """ + if not order or len(self.args) == 1: + ar = list(self.args) + elif len(self.args) == 0: + return printer._print(0) + else: + d = {v[1]: v[0] for v in self.args} + keys = sorted(d.keys(), key=lambda x: x.index) + ar = [] + for key in keys: + ar.append((d[key], key)) + ol = [] # output list, to be concatenated to a string + for v in ar: + for j in 0, 1, 2: + # if the coef of the basis vector is 1, we skip the 1 + if v[0][j] == 1: + ol.append(' + ' + v[1].str_vecs[j]) + # if the coef of the basis vector is -1, we skip the 1 + elif v[0][j] == -1: + ol.append(' - ' + v[1].str_vecs[j]) + elif v[0][j] != 0: + # If the coefficient of the basis vector is not 1 or -1; + # also, we might wrap it in parentheses, for readability. + arg_str = printer._print(v[0][j]) + if isinstance(v[0][j], Add): + arg_str = "(%s)" % arg_str + if arg_str[0] == '-': + arg_str = arg_str[1:] + str_start = ' - ' + else: + str_start = ' + ' + ol.append(str_start + arg_str + '*' + v[1].str_vecs[j]) + outstr = ''.join(ol) + if outstr.startswith(' + '): + outstr = outstr[3:] + elif outstr.startswith(' '): + outstr = outstr[1:] + return outstr + + def __sub__(self, other): + """The subtraction operator. """ + return self.__add__(other * -1) + + def cross(self, other): + """The cross product operator for two Vectors. + + Returns a Vector, expressed in the same ReferenceFrames as self. + + Parameters + ========== + + other : Vector + The Vector which we are crossing with + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.vector import ReferenceFrame, cross + >>> q1 = symbols('q1') + >>> N = ReferenceFrame('N') + >>> cross(N.x, N.y) + N.z + >>> A = ReferenceFrame('A') + >>> A.orient_axis(N, q1, N.x) + >>> cross(A.x, N.y) + N.z + >>> cross(N.y, A.x) + - sin(q1)*A.y - cos(q1)*A.z + + """ + + from sympy.physics.vector.dyadic import Dyadic, _check_dyadic + if isinstance(other, Dyadic): + other = _check_dyadic(other) + ol = Dyadic(0) + for i, v in enumerate(other.args): + ol += v[0] * ((self.cross(v[1])).outer(v[2])) + return ol + other = _check_vector(other) + if other.args == []: + return Vector(0) + + def _det(mat): + """This is needed as a little method for to find the determinant + of a list in python; needs to work for a 3x3 list. + SymPy's Matrix will not take in Vector, so need a custom function. + You should not be calling this. + + """ + + return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) + + mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * + mat[2][2]) + mat[0][2] * (mat[1][0] * mat[2][1] - + mat[1][1] * mat[2][0])) + + outlist = [] + ar = other.args # For brevity + for v in ar: + tempx = v[1].x + tempy = v[1].y + tempz = v[1].z + tempm = ([[tempx, tempy, tempz], + [self.dot(tempx), self.dot(tempy), self.dot(tempz)], + [Vector([v]).dot(tempx), Vector([v]).dot(tempy), + Vector([v]).dot(tempz)]]) + outlist += _det(tempm).args + return Vector(outlist) + + __radd__ = __add__ + __rmul__ = __mul__ + + def separate(self): + """ + The constituents of this vector in different reference frames, + as per its definition. + + Returns a dict mapping each ReferenceFrame to the corresponding + constituent Vector. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> R1 = ReferenceFrame('R1') + >>> R2 = ReferenceFrame('R2') + >>> v = R1.x + R2.x + >>> v.separate() == {R1: R1.x, R2: R2.x} + True + + """ + + components = {} + for x in self.args: + components[x[1]] = Vector([x]) + return components + + def __and__(self, other): + return self.dot(other) + __and__.__doc__ = dot.__doc__ + __rand__ = __and__ + + def __xor__(self, other): + return self.cross(other) + __xor__.__doc__ = cross.__doc__ + + def __or__(self, other): + return self.outer(other) + __or__.__doc__ = outer.__doc__ + + def diff(self, var, frame, var_in_dcm=True): + """Returns the partial derivative of the vector with respect to a + variable in the provided reference frame. + + Parameters + ========== + var : Symbol + What the partial derivative is taken with respect to. + frame : ReferenceFrame + The reference frame that the partial derivative is taken in. + var_in_dcm : boolean + If true, the differentiation algorithm assumes that the variable + may be present in any of the direction cosine matrices that relate + the frame to the frames of any component of the vector. But if it + is known that the variable is not present in the direction cosine + matrices, false can be set to skip full reexpression in the desired + frame. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.physics.vector import dynamicsymbols, ReferenceFrame + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> t = Symbol('t') + >>> q1 = dynamicsymbols('q1') + >>> N = ReferenceFrame('N') + >>> A = N.orientnew('A', 'Axis', [q1, N.y]) + >>> A.x.diff(t, N) + - sin(q1)*q1'*N.x - cos(q1)*q1'*N.z + >>> A.x.diff(t, N).express(A).simplify() + - q1'*A.z + >>> B = ReferenceFrame('B') + >>> u1, u2 = dynamicsymbols('u1, u2') + >>> v = u1 * A.x + u2 * B.y + >>> v.diff(u2, N, var_in_dcm=False) + B.y + + """ + + from sympy.physics.vector.frame import _check_frame + + _check_frame(frame) + var = sympify(var) + + inlist = [] + + for vector_component in self.args: + measure_number = vector_component[0] + component_frame = vector_component[1] + if component_frame == frame: + inlist += [(measure_number.diff(var), frame)] + else: + # If the direction cosine matrix relating the component frame + # with the derivative frame does not contain the variable. + if not var_in_dcm or (frame.dcm(component_frame).diff(var) == + zeros(3, 3)): + inlist += [(measure_number.diff(var), component_frame)] + else: # else express in the frame + reexp_vec_comp = Vector([vector_component]).express(frame) + deriv = reexp_vec_comp.args[0][0].diff(var) + inlist += Vector([(deriv, frame)]).args + + return Vector(inlist) + + def express(self, otherframe, variables=False): + """ + Returns a Vector equivalent to this one, expressed in otherframe. + Uses the global express method. + + Parameters + ========== + + otherframe : ReferenceFrame + The frame for this Vector to be described in + + variables : boolean + If True, the coordinate symbols(if present) in this Vector + are re-expressed in terms otherframe + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols + >>> from sympy.physics.vector import init_vprinting + >>> init_vprinting(pretty_print=False) + >>> q1 = dynamicsymbols('q1') + >>> N = ReferenceFrame('N') + >>> A = N.orientnew('A', 'Axis', [q1, N.y]) + >>> A.x.express(N) + cos(q1)*N.x - sin(q1)*N.z + + """ + from sympy.physics.vector import express + return express(self, otherframe, variables=variables) + + def to_matrix(self, reference_frame): + """Returns the matrix form of the vector with respect to the given + frame. + + Parameters + ---------- + reference_frame : ReferenceFrame + The reference frame that the rows of the matrix correspond to. + + Returns + ------- + matrix : ImmutableMatrix, shape(3,1) + The matrix that gives the 1D vector. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.vector import ReferenceFrame + >>> a, b, c = symbols('a, b, c') + >>> N = ReferenceFrame('N') + >>> vector = a * N.x + b * N.y + c * N.z + >>> vector.to_matrix(N) + Matrix([ + [a], + [b], + [c]]) + >>> beta = symbols('beta') + >>> A = N.orientnew('A', 'Axis', (beta, N.x)) + >>> vector.to_matrix(A) + Matrix([ + [ a], + [ b*cos(beta) + c*sin(beta)], + [-b*sin(beta) + c*cos(beta)]]) + + """ + + return Matrix([self.dot(unit_vec) for unit_vec in + reference_frame]).reshape(3, 1) + + def doit(self, **hints): + """Calls .doit() on each term in the Vector""" + d = {} + for v in self.args: + d[v[1]] = v[0].applyfunc(lambda x: x.doit(**hints)) + return Vector(d) + + def dt(self, otherframe): + """ + Returns a Vector which is the time derivative of + the self Vector, taken in frame otherframe. + + Calls the global time_derivative method + + Parameters + ========== + + otherframe : ReferenceFrame + The frame to calculate the time derivative in + + """ + from sympy.physics.vector import time_derivative + return time_derivative(self, otherframe) + + def simplify(self): + """Returns a simplified Vector.""" + d = {} + for v in self.args: + d[v[1]] = simplify(v[0]) + return Vector(d) + + def subs(self, *args, **kwargs): + """Substitution on the Vector. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> from sympy import Symbol + >>> N = ReferenceFrame('N') + >>> s = Symbol('s') + >>> a = N.x * s + >>> a.subs({s: 2}) + 2*N.x + + """ + + d = {} + for v in self.args: + d[v[1]] = v[0].subs(*args, **kwargs) + return Vector(d) + + def magnitude(self): + """Returns the magnitude (Euclidean norm) of self. + + Warnings + ======== + + Python ignores the leading negative sign so that might + give wrong results. + ``-A.x.magnitude()`` would be treated as ``-(A.x.magnitude())``, + instead of ``(-A.x).magnitude()``. + + """ + return sqrt(self.dot(self)) + + def normalize(self): + """Returns a Vector of magnitude 1, codirectional with self.""" + return Vector(self.args + []) / self.magnitude() + + def applyfunc(self, f): + """Apply a function to each component of a vector.""" + if not callable(f): + raise TypeError("`f` must be callable.") + + d = {} + for v in self.args: + d[v[1]] = v[0].applyfunc(f) + return Vector(d) + + def angle_between(self, vec): + """ + Returns the smallest angle between Vector 'vec' and self. + + Parameter + ========= + + vec : Vector + The Vector between which angle is needed. + + Examples + ======== + + >>> from sympy.physics.vector import ReferenceFrame + >>> A = ReferenceFrame("A") + >>> v1 = A.x + >>> v2 = A.y + >>> v1.angle_between(v2) + pi/2 + + >>> v3 = A.x + A.y + A.z + >>> v1.angle_between(v3) + acos(sqrt(3)/3) + + Warnings + ======== + + Python ignores the leading negative sign so that might give wrong + results. ``-A.x.angle_between()`` would be treated as + ``-(A.x.angle_between())``, instead of ``(-A.x).angle_between()``. + + """ + + vec1 = self.normalize() + vec2 = vec.normalize() + angle = acos(vec1.dot(vec2)) + return angle + + def free_symbols(self, reference_frame): + """Returns the free symbols in the measure numbers of the vector + expressed in the given reference frame. + + Parameters + ========== + reference_frame : ReferenceFrame + The frame with respect to which the free symbols of the given + vector is to be determined. + + Returns + ======= + set of Symbol + set of symbols present in the measure numbers of + ``reference_frame``. + + """ + + return self.to_matrix(reference_frame).free_symbols + + def free_dynamicsymbols(self, reference_frame): + """Returns the free dynamic symbols (functions of time ``t``) in the + measure numbers of the vector expressed in the given reference frame. + + Parameters + ========== + reference_frame : ReferenceFrame + The frame with respect to which the free dynamic symbols of the + given vector is to be determined. + + Returns + ======= + set + Set of functions of time ``t``, e.g. + ``Function('f')(me.dynamicsymbols._t)``. + + """ + # TODO : Circular dependency if imported at top. Should move + # find_dynamicsymbols into physics.vector.functions. + from sympy.physics.mechanics.functions import find_dynamicsymbols + + return find_dynamicsymbols(self, reference_frame=reference_frame) + + def _eval_evalf(self, prec): + if not self.args: + return self + new_args = [] + dps = prec_to_dps(prec) + for mat, frame in self.args: + new_args.append([mat.evalf(n=dps), frame]) + return Vector(new_args) + + def xreplace(self, rule): + """Replace occurrences of objects within the measure numbers of the + vector. + + Parameters + ========== + + rule : dict-like + Expresses a replacement rule. + + Returns + ======= + + Vector + Result of the replacement. + + Examples + ======== + + >>> from sympy import symbols, pi + >>> from sympy.physics.vector import ReferenceFrame + >>> A = ReferenceFrame('A') + >>> x, y, z = symbols('x y z') + >>> ((1 + x*y) * A.x).xreplace({x: pi}) + (pi*y + 1)*A.x + >>> ((1 + x*y) * A.x).xreplace({x: pi, y: 2}) + (1 + 2*pi)*A.x + + Replacements occur only if an entire node in the expression tree is + matched: + + >>> ((x*y + z) * A.x).xreplace({x*y: pi}) + (z + pi)*A.x + >>> ((x*y*z) * A.x).xreplace({x*y: pi}) + x*y*z*A.x + + """ + + new_args = [] + for mat, frame in self.args: + mat = mat.xreplace(rule) + new_args.append([mat, frame]) + return Vector(new_args) + + +class VectorTypeError(TypeError): + + def __init__(self, other, want): + msg = filldedent("Expected an instance of %s, but received object " + "'%s' of %s." % (type(want), other, type(other))) + super().__init__(msg) + + +def _check_vector(other): + if not isinstance(other, Vector): + raise TypeError('A Vector must be supplied') + return other diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/wigner.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/wigner.py new file mode 100644 index 0000000000000000000000000000000000000000..e08f3fb4a480439fd2bb1f8ff8c305bf69d7abae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/wigner.py @@ -0,0 +1,1213 @@ +# -*- coding: utf-8 -*- +r""" +Wigner, Clebsch-Gordan, Racah, and Gaunt coefficients + +Collection of functions for calculating Wigner 3j, 6j, 9j, +Clebsch-Gordan, Racah as well as Gaunt coefficients exactly, all +evaluating to a rational number times the square root of a rational +number [Rasch03]_. + +Please see the description of the individual functions for further +details and examples. + +References +========== + +.. [Regge58] 'Symmetry Properties of Clebsch-Gordan Coefficients', + T. Regge, Nuovo Cimento, Volume 10, pp. 544 (1958) +.. [Regge59] 'Symmetry Properties of Racah Coefficients', + T. Regge, Nuovo Cimento, Volume 11, pp. 116 (1959) +.. [Edmonds74] A. R. Edmonds. Angular momentum in quantum mechanics. + Investigations in physics, 4.; Investigations in physics, no. 4. + Princeton, N.J., Princeton University Press, 1957. +.. [Rasch03] J. Rasch and A. C. H. Yu, 'Efficient Storage Scheme for + Pre-calculated Wigner 3j, 6j and Gaunt Coefficients', SIAM + J. Sci. Comput. Volume 25, Issue 4, pp. 1416-1428 (2003) +.. [Liberatodebrito82] 'FORTRAN program for the integral of three + spherical harmonics', A. Liberato de Brito, + Comput. Phys. Commun., Volume 25, pp. 81-85 (1982) +.. [Homeier96] 'Some Properties of the Coupling Coefficients of Real + Spherical Harmonics and Their Relation to Gaunt Coefficients', + H. H. H. Homeier and E. O. Steinborn J. Mol. Struct., Volume 368, + pp. 31-37 (1996) + +Credits and Copyright +===================== + +This code was taken from Sage with the permission of all authors: + +https://groups.google.com/forum/#!topic/sage-devel/M4NZdu-7O38 + +Authors +======= + +- Jens Rasch (2009-03-24): initial version for Sage + +- Jens Rasch (2009-05-31): updated to sage-4.0 + +- Oscar Gerardo Lazo Arjona (2017-06-18): added Wigner D matrices + +- Phil Adam LeMaitre (2022-09-19): added real Gaunt coefficient + +Copyright (C) 2008 Jens Rasch + +""" +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.numbers import int_valued +from sympy.core.function import Function +from sympy.core.numbers import (Float, I, Integer, pi, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import (binomial, factorial) +from sympy.functions.elementary.complexes import re +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.functions.special.spherical_harmonics import Ynm +from sympy.matrices.dense import zeros +from sympy.matrices.immutable import ImmutableMatrix +from sympy.utilities.misc import as_int + +# This list of precomputed factorials is needed to massively +# accelerate future calculations of the various coefficients +_Factlist = [1] + + +def _calc_factlist(nn): + r""" + Function calculates a list of precomputed factorials in order to + massively accelerate future calculations of the various + coefficients. + + Parameters + ========== + + nn : integer + Highest factorial to be computed. + + Returns + ======= + + list of integers : + The list of precomputed factorials. + + Examples + ======== + + Calculate list of factorials:: + + sage: from sage.functions.wigner import _calc_factlist + sage: _calc_factlist(10) + [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] + """ + if nn >= len(_Factlist): + for ii in range(len(_Factlist), int(nn + 1)): + _Factlist.append(_Factlist[ii - 1] * ii) + return _Factlist[:int(nn) + 1] + + +def _int_or_halfint(value): + """return Python int unless value is half-int (then return float)""" + if isinstance(value, int): + return value + elif type(value) is float: + if value.is_integer(): + return int(value) # an int + if (2*value).is_integer(): + return value # a float + elif isinstance(value, Rational): + if value.q == 2: + return value.p/value.q # a float + elif value.q == 1: + return value.p # an int + elif isinstance(value, Float): + return _int_or_halfint(float(value)) + raise ValueError("expecting integer or half-integer, got %s" % value) + + +def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3): + r""" + Calculate the Wigner 3j symbol `\operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3)`. + + Parameters + ========== + + j_1, j_2, j_3, m_1, m_2, m_3 : + Integer or half integer. + + Returns + ======= + + Rational number times the square root of a rational number. + + Examples + ======== + + >>> from sympy.physics.wigner import wigner_3j + >>> wigner_3j(2, 6, 4, 0, 0, 0) + sqrt(715)/143 + >>> wigner_3j(2, 6, 4, 0, 0, 1) + 0 + + It is an error to have arguments that are not integer or half + integer values:: + + sage: wigner_3j(2.1, 6, 4, 0, 0, 0) + Traceback (most recent call last): + ... + ValueError: j values must be integer or half integer + sage: wigner_3j(2, 6, 4, 1, 0, -1.1) + Traceback (most recent call last): + ... + ValueError: m values must be integer or half integer + + Notes + ===== + + The Wigner 3j symbol obeys the following symmetry rules: + + - invariant under any permutation of the columns (with the + exception of a sign change where `J:=j_1+j_2+j_3`): + + .. math:: + + \begin{aligned} + \operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3) + &=\operatorname{Wigner3j}(j_3,j_1,j_2,m_3,m_1,m_2) \\ + &=\operatorname{Wigner3j}(j_2,j_3,j_1,m_2,m_3,m_1) \\ + &=(-1)^J \operatorname{Wigner3j}(j_3,j_2,j_1,m_3,m_2,m_1) \\ + &=(-1)^J \operatorname{Wigner3j}(j_1,j_3,j_2,m_1,m_3,m_2) \\ + &=(-1)^J \operatorname{Wigner3j}(j_2,j_1,j_3,m_2,m_1,m_3) + \end{aligned} + + - invariant under space inflection, i.e. + + .. math:: + + \operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3) + =(-1)^J \operatorname{Wigner3j}(j_1,j_2,j_3,-m_1,-m_2,-m_3) + + - symmetric with respect to the 72 additional symmetries based on + the work by [Regge58]_ + + - zero for `j_1`, `j_2`, `j_3` not fulfilling triangle relation + + - zero for `m_1 + m_2 + m_3 \neq 0` + + - zero for violating any one of the conditions + `m_1 \in \{-|j_1|, \ldots, |j_1|\}`, + `m_2 \in \{-|j_2|, \ldots, |j_2|\}`, + `m_3 \in \{-|j_3|, \ldots, |j_3|\}` + + Algorithm + ========= + + This function uses the algorithm of [Edmonds74]_ to calculate the + value of the 3j symbol exactly. Note that the formula contains + alternating sums over large factorials and is therefore unsuitable + for finite precision arithmetic and only useful for a computer + algebra system [Rasch03]_. + + Authors + ======= + + - Jens Rasch (2009-03-24): initial version + """ + + j_1, j_2, j_3, m_1, m_2, m_3 = \ + map(_int_or_halfint, map(sympify, + [j_1, j_2, j_3, m_1, m_2, m_3])) + + if m_1 + m_2 + m_3 != 0: + return S.Zero + a1 = j_1 + j_2 - j_3 + if a1 < 0: + return S.Zero + a2 = j_1 - j_2 + j_3 + if a2 < 0: + return S.Zero + a3 = -j_1 + j_2 + j_3 + if a3 < 0: + return S.Zero + if (abs(m_1) > j_1) or (abs(m_2) > j_2) or (abs(m_3) > j_3): + return S.Zero + if not (int_valued(j_1 - m_1) and \ + int_valued(j_2 - m_2) and \ + int_valued(j_3 - m_3)): + return S.Zero + + maxfact = max(j_1 + j_2 + j_3 + 1, j_1 + abs(m_1), j_2 + abs(m_2), + j_3 + abs(m_3)) + _calc_factlist(int(maxfact)) + + argsqrt = Integer(_Factlist[int(j_1 + j_2 - j_3)] * + _Factlist[int(j_1 - j_2 + j_3)] * + _Factlist[int(-j_1 + j_2 + j_3)] * + _Factlist[int(j_1 - m_1)] * + _Factlist[int(j_1 + m_1)] * + _Factlist[int(j_2 - m_2)] * + _Factlist[int(j_2 + m_2)] * + _Factlist[int(j_3 - m_3)] * + _Factlist[int(j_3 + m_3)]) / \ + _Factlist[int(j_1 + j_2 + j_3 + 1)] + + ressqrt = sqrt(argsqrt) + if ressqrt.is_complex or ressqrt.is_infinite: + ressqrt = ressqrt.as_real_imag()[0] + + imin = max(-j_3 + j_1 + m_2, -j_3 + j_2 - m_1, 0) + imax = min(j_2 + m_2, j_1 - m_1, j_1 + j_2 - j_3) + sumres = 0 + for ii in range(int(imin), int(imax) + 1): + den = _Factlist[ii] * \ + _Factlist[int(ii + j_3 - j_1 - m_2)] * \ + _Factlist[int(j_2 + m_2 - ii)] * \ + _Factlist[int(j_1 - ii - m_1)] * \ + _Factlist[int(ii + j_3 - j_2 + m_1)] * \ + _Factlist[int(j_1 + j_2 - j_3 - ii)] + sumres = sumres + Integer((-1) ** ii) / den + + prefid = Integer((-1) ** int(j_1 - j_2 - m_3)) + res = ressqrt * sumres * prefid + return res + + +def clebsch_gordan(j_1, j_2, j_3, m_1, m_2, m_3): + r""" + Calculates the Clebsch-Gordan coefficient. + `\left\langle j_1 m_1 \; j_2 m_2 | j_3 m_3 \right\rangle`. + + The reference for this function is [Edmonds74]_. + + Parameters + ========== + + j_1, j_2, j_3, m_1, m_2, m_3 : + Integer or half integer. + + Returns + ======= + + Rational number times the square root of a rational number. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.physics.wigner import clebsch_gordan + >>> clebsch_gordan(S(3)/2, S(1)/2, 2, S(3)/2, S(1)/2, 2) + 1 + >>> clebsch_gordan(S(3)/2, S(1)/2, 1, S(3)/2, -S(1)/2, 1) + sqrt(3)/2 + >>> clebsch_gordan(S(3)/2, S(1)/2, 1, -S(1)/2, S(1)/2, 0) + -sqrt(2)/2 + + Notes + ===== + + The Clebsch-Gordan coefficient will be evaluated via its relation + to Wigner 3j symbols: + + .. math:: + + \left\langle j_1 m_1 \; j_2 m_2 | j_3 m_3 \right\rangle + =(-1)^{j_1-j_2+m_3} \sqrt{2j_3+1} + \operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,-m_3) + + See also the documentation on Wigner 3j symbols which exhibit much + higher symmetry relations than the Clebsch-Gordan coefficient. + + Authors + ======= + + - Jens Rasch (2009-03-24): initial version + """ + j_1 = sympify(j_1) + j_2 = sympify(j_2) + j_3 = sympify(j_3) + m_1 = sympify(m_1) + m_2 = sympify(m_2) + m_3 = sympify(m_3) + + w = wigner_3j(j_1, j_2, j_3, m_1, m_2, -m_3) + + return (-1) ** (j_1 - j_2 + m_3) * sqrt(2 * j_3 + 1) * w + + +def _big_delta_coeff(aa, bb, cc, prec=None): + r""" + Calculates the Delta coefficient of the 3 angular momenta for + Racah symbols. Also checks that the differences are of integer + value. + + Parameters + ========== + + aa : + First angular momentum, integer or half integer. + bb : + Second angular momentum, integer or half integer. + cc : + Third angular momentum, integer or half integer. + prec : + Precision of the ``sqrt()`` calculation. + + Returns + ======= + + double : Value of the Delta coefficient. + + Examples + ======== + + sage: from sage.functions.wigner import _big_delta_coeff + sage: _big_delta_coeff(1,1,1) + 1/2*sqrt(1/6) + """ + + # the triangle test will only pass if a) all 3 values are ints or + # b) 1 is an int and the other two are half-ints + if not int_valued(aa + bb - cc): + raise ValueError("j values must be integer or half integer and fulfill the triangle relation") + if not int_valued(aa + cc - bb): + raise ValueError("j values must be integer or half integer and fulfill the triangle relation") + if not int_valued(bb + cc - aa): + raise ValueError("j values must be integer or half integer and fulfill the triangle relation") + if (aa + bb - cc) < 0: + return S.Zero + if (aa + cc - bb) < 0: + return S.Zero + if (bb + cc - aa) < 0: + return S.Zero + + maxfact = max(aa + bb - cc, aa + cc - bb, bb + cc - aa, aa + bb + cc + 1) + _calc_factlist(maxfact) + + argsqrt = Integer(_Factlist[int(aa + bb - cc)] * + _Factlist[int(aa + cc - bb)] * + _Factlist[int(bb + cc - aa)]) / \ + Integer(_Factlist[int(aa + bb + cc + 1)]) + + ressqrt = sqrt(argsqrt) + if prec: + ressqrt = ressqrt.evalf(prec).as_real_imag()[0] + return ressqrt + + +def racah(aa, bb, cc, dd, ee, ff, prec=None): + r""" + Calculate the Racah symbol `W(a,b,c,d;e,f)`. + + Parameters + ========== + + a, ..., f : + Integer or half integer. + prec : + Precision, default: ``None``. Providing a precision can + drastically speed up the calculation. + + Returns + ======= + + Rational number times the square root of a rational number + (if ``prec=None``), or real number if a precision is given. + + Examples + ======== + + >>> from sympy.physics.wigner import racah + >>> racah(3,3,3,3,3,3) + -1/14 + + Notes + ===== + + The Racah symbol is related to the Wigner 6j symbol: + + .. math:: + + \operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6) + =(-1)^{j_1+j_2+j_4+j_5} W(j_1,j_2,j_5,j_4,j_3,j_6) + + Please see the 6j symbol for its much richer symmetries and for + additional properties. + + Algorithm + ========= + + This function uses the algorithm of [Edmonds74]_ to calculate the + value of the 6j symbol exactly. Note that the formula contains + alternating sums over large factorials and is therefore unsuitable + for finite precision arithmetic and only useful for a computer + algebra system [Rasch03]_. + + Authors + ======= + + - Jens Rasch (2009-03-24): initial version + """ + prefac = _big_delta_coeff(aa, bb, ee, prec) * \ + _big_delta_coeff(cc, dd, ee, prec) * \ + _big_delta_coeff(aa, cc, ff, prec) * \ + _big_delta_coeff(bb, dd, ff, prec) + if prefac == 0: + return S.Zero + imin = max(aa + bb + ee, cc + dd + ee, aa + cc + ff, bb + dd + ff) + imax = min(aa + bb + cc + dd, aa + dd + ee + ff, bb + cc + ee + ff) + + maxfact = max(imax + 1, aa + bb + cc + dd, aa + dd + ee + ff, + bb + cc + ee + ff) + _calc_factlist(maxfact) + + sumres = 0 + for kk in range(int(imin), int(imax) + 1): + den = _Factlist[int(kk - aa - bb - ee)] * \ + _Factlist[int(kk - cc - dd - ee)] * \ + _Factlist[int(kk - aa - cc - ff)] * \ + _Factlist[int(kk - bb - dd - ff)] * \ + _Factlist[int(aa + bb + cc + dd - kk)] * \ + _Factlist[int(aa + dd + ee + ff - kk)] * \ + _Factlist[int(bb + cc + ee + ff - kk)] + sumres = sumres + Integer((-1) ** kk * _Factlist[kk + 1]) / den + + res = prefac * sumres * (-1) ** int(aa + bb + cc + dd) + return res + + +def wigner_6j(j_1, j_2, j_3, j_4, j_5, j_6, prec=None): + r""" + Calculate the Wigner 6j symbol `\operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6)`. + + Parameters + ========== + + j_1, ..., j_6 : + Integer or half integer. + prec : + Precision, default: ``None``. Providing a precision can + drastically speed up the calculation. + + Returns + ======= + + Rational number times the square root of a rational number + (if ``prec=None``), or real number if a precision is given. + + Examples + ======== + + >>> from sympy.physics.wigner import wigner_6j + >>> wigner_6j(3,3,3,3,3,3) + -1/14 + >>> wigner_6j(5,5,5,5,5,5) + 1/52 + + It is an error to have arguments that are not integer or half + integer values or do not fulfill the triangle relation:: + + sage: wigner_6j(2.5,2.5,2.5,2.5,2.5,2.5) + Traceback (most recent call last): + ... + ValueError: j values must be integer or half integer and fulfill the triangle relation + sage: wigner_6j(0.5,0.5,1.1,0.5,0.5,1.1) + Traceback (most recent call last): + ... + ValueError: j values must be integer or half integer and fulfill the triangle relation + + Notes + ===== + + The Wigner 6j symbol is related to the Racah symbol but exhibits + more symmetries as detailed below. + + .. math:: + + \operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6) + =(-1)^{j_1+j_2+j_4+j_5} W(j_1,j_2,j_5,j_4,j_3,j_6) + + The Wigner 6j symbol obeys the following symmetry rules: + + - Wigner 6j symbols are left invariant under any permutation of + the columns: + + .. math:: + + \begin{aligned} + \operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6) + &=\operatorname{Wigner6j}(j_3,j_1,j_2,j_6,j_4,j_5) \\ + &=\operatorname{Wigner6j}(j_2,j_3,j_1,j_5,j_6,j_4) \\ + &=\operatorname{Wigner6j}(j_3,j_2,j_1,j_6,j_5,j_4) \\ + &=\operatorname{Wigner6j}(j_1,j_3,j_2,j_4,j_6,j_5) \\ + &=\operatorname{Wigner6j}(j_2,j_1,j_3,j_5,j_4,j_6) + \end{aligned} + + - They are invariant under the exchange of the upper and lower + arguments in each of any two columns, i.e. + + .. math:: + + \begin{aligned} + \operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6) + &=\operatorname{Wigner6j}(j_1,j_5,j_6,j_4,j_2,j_3)\\ + &=\operatorname{Wigner6j}(j_4,j_2,j_6,j_1,j_5,j_3)\\ + &=\operatorname{Wigner6j}(j_4,j_5,j_3,j_1,j_2,j_6) + \end{aligned} + + - additional 6 symmetries [Regge59]_ giving rise to 144 symmetries + in total + + - only non-zero if any triple of `j`'s fulfill a triangle relation + + Algorithm + ========= + + This function uses the algorithm of [Edmonds74]_ to calculate the + value of the 6j symbol exactly. Note that the formula contains + alternating sums over large factorials and is therefore unsuitable + for finite precision arithmetic and only useful for a computer + algebra system [Rasch03]_. + + """ + j_1, j_2, j_3, j_4, j_5, j_6 = map(sympify, \ + [j_1, j_2, j_3, j_4, j_5, j_6]) + res = (-1) ** int(j_1 + j_2 + j_4 + j_5) * \ + racah(j_1, j_2, j_5, j_4, j_3, j_6, prec) + return res + + +def wigner_9j(j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9, prec=None): + r""" + Calculate the Wigner 9j symbol + `\operatorname{Wigner9j}(j_1,j_2,j_3,j_4,j_5,j_6,j_7,j_8,j_9)`. + + Parameters + ========== + + j_1, ..., j_9 : + Integer or half integer. + prec : precision, default + ``None``. Providing a precision can + drastically speed up the calculation. + + Returns + ======= + + Rational number times the square root of a rational number + (if ``prec=None``), or real number if a precision is given. + + Examples + ======== + + >>> from sympy.physics.wigner import wigner_9j + >>> wigner_9j(1,1,1, 1,1,1, 1,1,0, prec=64) + 0.05555555555555555555555555555555555555555555555555555555555555555 + + >>> wigner_9j(1/2,1/2,0, 1/2,3/2,1, 0,1,1, prec=64) + 0.1666666666666666666666666666666666666666666666666666666666666667 + + It is an error to have arguments that are not integer or half + integer values or do not fulfill the triangle relation:: + + sage: wigner_9j(0.5,0.5,0.5, 0.5,0.5,0.5, 0.5,0.5,0.5,prec=64) + Traceback (most recent call last): + ... + ValueError: j values must be integer or half integer and fulfill the triangle relation + sage: wigner_9j(1,1,1, 0.5,1,1.5, 0.5,1,2.5,prec=64) + Traceback (most recent call last): + ... + ValueError: j values must be integer or half integer and fulfill the triangle relation + + Algorithm + ========= + + This function uses the algorithm of [Edmonds74]_ to calculate the + value of the 3j symbol exactly. Note that the formula contains + alternating sums over large factorials and is therefore unsuitable + for finite precision arithmetic and only useful for a computer + algebra system [Rasch03]_. + """ + j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9 = map(sympify, \ + [j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9]) + imax = int(min(j_1 + j_9, j_2 + j_6, j_4 + j_8) * 2) + imin = imax % 2 + sumres = 0 + for kk in range(imin, int(imax) + 1, 2): + sumres = sumres + (kk + 1) * \ + racah(j_1, j_2, j_9, j_6, j_3, kk / 2, prec) * \ + racah(j_4, j_6, j_8, j_2, j_5, kk / 2, prec) * \ + racah(j_1, j_4, j_9, j_8, j_7, kk / 2, prec) + return sumres + + +def gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec=None): + r""" + Calculate the Gaunt coefficient. + + Explanation + =========== + + The Gaunt coefficient is defined as the integral over three + spherical harmonics: + + .. math:: + + \begin{aligned} + \operatorname{Gaunt}(l_1,l_2,l_3,m_1,m_2,m_3) + &=\int Y_{l_1,m_1}(\Omega) + Y_{l_2,m_2}(\Omega) Y_{l_3,m_3}(\Omega) \,d\Omega \\ + &=\sqrt{\frac{(2l_1+1)(2l_2+1)(2l_3+1)}{4\pi}} + \operatorname{Wigner3j}(l_1,l_2,l_3,0,0,0) + \operatorname{Wigner3j}(l_1,l_2,l_3,m_1,m_2,m_3) + \end{aligned} + + Parameters + ========== + + l_1, l_2, l_3, m_1, m_2, m_3 : + Integer. + prec - precision, default: ``None``. + Providing a precision can + drastically speed up the calculation. + + Returns + ======= + + Rational number times the square root of a rational number + (if ``prec=None``), or real number if a precision is given. + + Examples + ======== + + >>> from sympy.physics.wigner import gaunt + >>> gaunt(1,0,1,1,0,-1) + -1/(2*sqrt(pi)) + >>> gaunt(1000,1000,1200,9,3,-12).n(64) + 0.006895004219221134484332976156744208248842039317638217822322799675 + + It is an error to use non-integer values for `l` and `m`:: + + sage: gaunt(1.2,0,1.2,0,0,0) + Traceback (most recent call last): + ... + ValueError: l values must be integer + sage: gaunt(1,0,1,1.1,0,-1.1) + Traceback (most recent call last): + ... + ValueError: m values must be integer + + Notes + ===== + + The Gaunt coefficient obeys the following symmetry rules: + + - invariant under any permutation of the columns + + .. math:: + \begin{aligned} + Y(l_1,l_2,l_3,m_1,m_2,m_3) + &=Y(l_3,l_1,l_2,m_3,m_1,m_2) \\ + &=Y(l_2,l_3,l_1,m_2,m_3,m_1) \\ + &=Y(l_3,l_2,l_1,m_3,m_2,m_1) \\ + &=Y(l_1,l_3,l_2,m_1,m_3,m_2) \\ + &=Y(l_2,l_1,l_3,m_2,m_1,m_3) + \end{aligned} + + - invariant under space inflection, i.e. + + .. math:: + Y(l_1,l_2,l_3,m_1,m_2,m_3) + =Y(l_1,l_2,l_3,-m_1,-m_2,-m_3) + + - symmetric with respect to the 72 Regge symmetries as inherited + for the `3j` symbols [Regge58]_ + + - zero for `l_1`, `l_2`, `l_3` not fulfilling triangle relation + + - zero for violating any one of the conditions: `l_1 \ge |m_1|`, + `l_2 \ge |m_2|`, `l_3 \ge |m_3|` + + - non-zero only for an even sum of the `l_i`, i.e. + `L = l_1 + l_2 + l_3 = 2n` for `n` in `\mathbb{N}` + + Algorithms + ========== + + This function uses the algorithm of [Liberatodebrito82]_ to + calculate the value of the Gaunt coefficient exactly. Note that + the formula contains alternating sums over large factorials and is + therefore unsuitable for finite precision arithmetic and only + useful for a computer algebra system [Rasch03]_. + + Authors + ======= + + Jens Rasch (2009-03-24): initial version for Sage. + """ + l_1, l_2, l_3, m_1, m_2, m_3 = [ + as_int(i) for i in (l_1, l_2, l_3, m_1, m_2, m_3)] + + if l_1 + l_2 - l_3 < 0: + return S.Zero + if l_1 - l_2 + l_3 < 0: + return S.Zero + if -l_1 + l_2 + l_3 < 0: + return S.Zero + if (m_1 + m_2 + m_3) != 0: + return S.Zero + if (abs(m_1) > l_1) or (abs(m_2) > l_2) or (abs(m_3) > l_3): + return S.Zero + bigL, remL = divmod(l_1 + l_2 + l_3, 2) + if remL % 2: + return S.Zero + + imin = max(-l_3 + l_1 + m_2, -l_3 + l_2 - m_1, 0) + imax = min(l_2 + m_2, l_1 - m_1, l_1 + l_2 - l_3) + + _calc_factlist(max(l_1 + l_2 + l_3 + 1, imax + 1)) + + ressqrt = sqrt((2 * l_1 + 1) * (2 * l_2 + 1) * (2 * l_3 + 1) * \ + _Factlist[l_1 - m_1] * _Factlist[l_1 + m_1] * _Factlist[l_2 - m_2] * \ + _Factlist[l_2 + m_2] * _Factlist[l_3 - m_3] * _Factlist[l_3 + m_3] / \ + (4*pi)) + + prefac = Integer(_Factlist[bigL] * _Factlist[l_2 - l_1 + l_3] * + _Factlist[l_1 - l_2 + l_3] * _Factlist[l_1 + l_2 - l_3])/ \ + _Factlist[2 * bigL + 1]/ \ + (_Factlist[bigL - l_1] * + _Factlist[bigL - l_2] * _Factlist[bigL - l_3]) + + sumres = 0 + for ii in range(int(imin), int(imax) + 1): + den = _Factlist[ii] * _Factlist[ii + l_3 - l_1 - m_2] * \ + _Factlist[l_2 + m_2 - ii] * _Factlist[l_1 - ii - m_1] * \ + _Factlist[ii + l_3 - l_2 + m_1] * _Factlist[l_1 + l_2 - l_3 - ii] + sumres = sumres + Integer((-1) ** ii) / den + + res = ressqrt * prefac * sumres * Integer((-1) ** (bigL + l_3 + m_1 - m_2)) + if prec is not None: + res = res.n(prec) + return res + + +def real_gaunt(l_1, l_2, l_3, mu_1, mu_2, mu_3, prec=None): + r""" + Calculate the real Gaunt coefficient. + + Explanation + =========== + + The real Gaunt coefficient is defined as the integral over three + real spherical harmonics: + + .. math:: + \begin{aligned} + \operatorname{RealGaunt}(l_1,l_2,l_3,\mu_1,\mu_2,\mu_3) + &=\int Z^{\mu_1}_{l_1}(\Omega) + Z^{\mu_2}_{l_2}(\Omega) Z^{\mu_3}_{l_3}(\Omega) \,d\Omega \\ + \end{aligned} + + Alternatively, it can be defined in terms of the standard Gaunt + coefficient by relating the real spherical harmonics to the standard + spherical harmonics via a unitary transformation `U`, i.e. + `Z^{\mu}_{l}(\Omega)=\sum_{m'}U^{\mu}_{m'}Y^{m'}_{l}(\Omega)` [Homeier96]_. + The real Gaunt coefficient is then defined as + + .. math:: + \begin{aligned} + \operatorname{RealGaunt}(l_1,l_2,l_3,\mu_1,\mu_2,\mu_3) + &=\int Z^{\mu_1}_{l_1}(\Omega) + Z^{\mu_2}_{l_2}(\Omega) Z^{\mu_3}_{l_3}(\Omega) \,d\Omega \\ + &=\sum_{m'_1 m'_2 m'_3} U^{\mu_1}_{m'_1}U^{\mu_2}_{m'_2}U^{\mu_3}_{m'_3} + \operatorname{Gaunt}(l_1,l_2,l_3,m'_1,m'_2,m'_3) + \end{aligned} + + The unitary matrix `U` has components + + .. math:: + \begin{aligned} + U^\mu_{m} = \delta_{|\mu||m|}*(\delta_{m0}\delta_{\mu 0} + \frac{1}{\sqrt{2}}\big[\Theta(\mu)\big(\delta_{m\mu}+(-1)^{m}\delta_{m-\mu}\big) + +i \Theta(-\mu)\big((-1)^{m}\delta_{m\mu}-\delta_{m-\mu}\big)\big]) + \end{aligned} + + + where `\delta_{ij}` is the Kronecker delta symbol and `\Theta` is a step + function defined as + + .. math:: + \begin{aligned} + \Theta(x) = \begin{cases} 1 \,\text{for}\, x > 0 \\ 0 \,\text{for}\, x \leq 0 \end{cases} + \end{aligned} + + Parameters + ========== + + l_1, l_2, l_3, mu_1, mu_2, mu_3 : + Integer degree and order + + prec - precision, default: ``None``. + Providing a precision can + drastically speed up the calculation. + + Returns + ======= + + Rational number times the square root of a rational number. + + Examples + ======== + >>> from sympy.physics.wigner import real_gaunt + >>> real_gaunt(1,1,2,-1,1,-2) + sqrt(15)/(10*sqrt(pi)) + >>> real_gaunt(10,10,20,-9,-9,0,prec=64) + -0.00002480019791932209313156167176797577821140084216297395518482071448 + + It is an error to use non-integer values for `l` and `\mu`:: + real_gaunt(2.8,0.5,1.3,0,0,0) + Traceback (most recent call last): + ... + ValueError: l values must be integer + + real_gaunt(2,2,4,0.7,1,-3.4) + Traceback (most recent call last): + ... + ValueError: mu values must be integer + + Notes + ===== + + The real Gaunt coefficient inherits from the standard Gaunt coefficient, + the invariance under any permutation of the pairs `(l_i, \mu_i)` and the + requirement that the sum of the `l_i` be even to yield a non-zero value. + It also obeys the following symmetry rules: + + - zero for `l_1`, `l_2`, `l_3` not fulfilling the condition + `l_1 \in \{l_{\text{max}}, l_{\text{max}}-2, \ldots, l_{\text{min}}\}`, + where `l_{\text{max}} = l_2+l_3`, + + .. math:: + \begin{aligned} + l_{\text{min}} = \begin{cases} \kappa(l_2, l_3, \mu_2, \mu_3) & \text{if}\, + \kappa(l_2, l_3, \mu_2, \mu_3) + l_{\text{max}}\, \text{is even} \\ + \kappa(l_2, l_3, \mu_2, \mu_3)+1 & \text{if}\, \kappa(l_2, l_3, \mu_2, \mu_3) + + l_{\text{max}}\, \text{is odd}\end{cases} + \end{aligned} + + and `\kappa(l_2, l_3, \mu_2, \mu_3) = \max{\big(|l_2-l_3|, \min{\big(|\mu_2+\mu_3|, + |\mu_2-\mu_3|\big)}\big)}` + + - zero for an odd number of negative `\mu_i` + + Algorithms + ========== + + This function uses the algorithms of [Homeier96]_ and [Rasch03]_ to + calculate the value of the real Gaunt coefficient exactly. Note that + the formula used in [Rasch03]_ contains alternating sums over large + factorials and is therefore unsuitable for finite precision arithmetic + and only useful for a computer algebra system [Rasch03]_. However, this + function can in principle use any algorithm that computes the Gaunt + coefficient, so it is suitable for finite precision arithmetic in so far + as the algorithm which computes the Gaunt coefficient is. + """ + l_1, l_2, l_3, mu_1, mu_2, mu_3 = [ + as_int(i) for i in (l_1, l_2, l_3, mu_1, mu_2, mu_3)] + + # check for quick exits + if sum(1 for i in (mu_1, mu_2, mu_3) if i < 0) % 2: + return S.Zero # odd number of negative m + if (l_1 + l_2 + l_3) % 2: + return S.Zero # sum of l is odd + lmax = l_2 + l_3 + lmin = max(abs(l_2 - l_3), min(abs(mu_2 + mu_3), abs(mu_2 - mu_3))) + if (lmin + lmax) % 2: + lmin += 1 + if lmin not in range(lmax, lmin - 2, -2): + return S.Zero + + kron_del = lambda i, j: 1 if i == j else 0 + s = lambda e: -1 if e % 2 else 1 # (-1)**e to give +/-1, avoiding float when e<0 + + t = lambda x: 1 if x > 0 else 0 + A = lambda mu, m: t(-mu) * (s(m) * kron_del(m, mu) - kron_del(m, -mu)) + B = lambda mu, m: t(mu) * (kron_del(m, mu) + s(m) * kron_del(m, -mu)) + U = lambda mu, m: kron_del(abs(mu), abs(m)) * (kron_del(mu, 0) * kron_del(m, 0) + (B(mu, m) + I * A(mu, m))/sqrt(2)) + + ugnt = 0 + for m1 in range(-l_1, l_1+1): + U1 = U(mu_1, m1) + for m2 in range(-l_2, l_2+1): + U2 = U(mu_2, m2) + U3 = U(mu_3,-m1-m2) + ugnt = ugnt + re(U1*U2*U3)*gaunt(l_1, l_2, l_3, m1, m2, -m1 - m2, prec=prec) + + return ugnt + + +class Wigner3j(Function): + + def doit(self, **hints): + if all(obj.is_number for obj in self.args): + return wigner_3j(*self.args) + else: + return self + +def dot_rot_grad_Ynm(j, p, l, m, theta, phi): + r""" + Returns dot product of rotational gradients of spherical harmonics. + + Explanation + =========== + + This function returns the right hand side of the following expression: + + .. math :: + \vec{R}Y{_j^{p}} \cdot \vec{R}Y{_l^{m}} = (-1)^{m+p} + \sum\limits_{k=|l-j|}^{l+j}Y{_k^{m+p}} * \alpha_{l,m,j,p,k} * + \frac{1}{2} (k^2-j^2-l^2+k-j-l) + + + Arguments + ========= + + j, p, l, m .... indices in spherical harmonics (expressions or integers) + theta, phi .... angle arguments in spherical harmonics + + Example + ======= + + >>> from sympy import symbols + >>> from sympy.physics.wigner import dot_rot_grad_Ynm + >>> theta, phi = symbols("theta phi") + >>> dot_rot_grad_Ynm(3, 2, 2, 0, theta, phi).doit() + 3*sqrt(55)*Ynm(5, 2, theta, phi)/(11*sqrt(pi)) + + """ + j = sympify(j) + p = sympify(p) + l = sympify(l) + m = sympify(m) + theta = sympify(theta) + phi = sympify(phi) + k = Dummy("k") + + def alpha(l,m,j,p,k): + return sqrt((2*l+1)*(2*j+1)*(2*k+1)/(4*pi)) * \ + Wigner3j(j, l, k, S.Zero, S.Zero, S.Zero) * \ + Wigner3j(j, l, k, p, m, -m-p) + + return (S.NegativeOne)**(m+p) * Sum(Ynm(k, m+p, theta, phi) * alpha(l,m,j,p,k) / 2 \ + *(k**2-j**2-l**2+k-j-l), (k, abs(l-j), l+j)) + + +def wigner_d_small(J, beta): + """Return the small Wigner d matrix for angular momentum J. + + Explanation + =========== + + J : An integer, half-integer, or SymPy symbol for the total angular + momentum of the angular momentum space being rotated. + beta : A real number representing the Euler angle of rotation about + the so-called line of nodes. See [Edmonds74]_. + + Returns + ======= + + A matrix representing the corresponding Euler angle rotation( in the basis + of eigenvectors of `J_z`). + + .. math :: + \\mathcal{d}_{\\beta} = \\exp\\big( \\frac{i\\beta}{\\hbar} J_y\\big) + + such that + + .. math :: + d^{(J)}_{m',m}(\\beta) = \\mathtt{wigner\\_d\\_small(J,beta)[J-mprime,J-m]} + + The components are calculated using the general form [Edmonds74]_, + equation 4.1.15. + + Examples + ======== + + >>> from sympy import Integer, symbols, pi, pprint + >>> from sympy.physics.wigner import wigner_d_small + >>> half = 1/Integer(2) + >>> beta = symbols("beta", real=True) + >>> pprint(wigner_d_small(half, beta), use_unicode=True) + ⎡ ⎛β⎞ ⎛β⎞⎤ + ⎢cos⎜─⎟ sin⎜─⎟⎥ + ⎢ ⎝2⎠ ⎝2⎠⎥ + ⎢ ⎥ + ⎢ ⎛β⎞ ⎛β⎞⎥ + ⎢-sin⎜─⎟ cos⎜─⎟⎥ + ⎣ ⎝2⎠ ⎝2⎠⎦ + + >>> pprint(wigner_d_small(2*half, beta), use_unicode=True) + ⎡ 2⎛β⎞ ⎛β⎞ ⎛β⎞ 2⎛β⎞ ⎤ + ⎢ cos ⎜─⎟ √2⋅sin⎜─⎟⋅cos⎜─⎟ sin ⎜─⎟ ⎥ + ⎢ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎥ + ⎢ ⎥ + ⎢ ⎛β⎞ ⎛β⎞ 2⎛β⎞ 2⎛β⎞ ⎛β⎞ ⎛β⎞⎥ + ⎢-√2⋅sin⎜─⎟⋅cos⎜─⎟ - sin ⎜─⎟ + cos ⎜─⎟ √2⋅sin⎜─⎟⋅cos⎜─⎟⎥ + ⎢ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠⎥ + ⎢ ⎥ + ⎢ 2⎛β⎞ ⎛β⎞ ⎛β⎞ 2⎛β⎞ ⎥ + ⎢ sin ⎜─⎟ -√2⋅sin⎜─⎟⋅cos⎜─⎟ cos ⎜─⎟ ⎥ + ⎣ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎦ + + From table 4 in [Edmonds74]_ + + >>> pprint(wigner_d_small(half, beta).subs({beta:pi/2}), use_unicode=True) + ⎡ √2 √2⎤ + ⎢ ── ──⎥ + ⎢ 2 2 ⎥ + ⎢ ⎥ + ⎢-√2 √2⎥ + ⎢──── ──⎥ + ⎣ 2 2 ⎦ + + >>> pprint(wigner_d_small(2*half, beta).subs({beta:pi/2}), + ... use_unicode=True) + ⎡ √2 ⎤ + ⎢1/2 ── 1/2⎥ + ⎢ 2 ⎥ + ⎢ ⎥ + ⎢-√2 √2 ⎥ + ⎢──── 0 ── ⎥ + ⎢ 2 2 ⎥ + ⎢ ⎥ + ⎢ -√2 ⎥ + ⎢1/2 ──── 1/2⎥ + ⎣ 2 ⎦ + + >>> pprint(wigner_d_small(3*half, beta).subs({beta:pi/2}), + ... use_unicode=True) + ⎡ √2 √6 √6 √2⎤ + ⎢ ── ── ── ──⎥ + ⎢ 4 4 4 4 ⎥ + ⎢ ⎥ + ⎢-√6 -√2 √2 √6⎥ + ⎢──── ──── ── ──⎥ + ⎢ 4 4 4 4 ⎥ + ⎢ ⎥ + ⎢ √6 -√2 -√2 √6⎥ + ⎢ ── ──── ──── ──⎥ + ⎢ 4 4 4 4 ⎥ + ⎢ ⎥ + ⎢-√2 √6 -√6 √2⎥ + ⎢──── ── ──── ──⎥ + ⎣ 4 4 4 4 ⎦ + + >>> pprint(wigner_d_small(4*half, beta).subs({beta:pi/2}), + ... use_unicode=True) + ⎡ √6 ⎤ + ⎢1/4 1/2 ── 1/2 1/4⎥ + ⎢ 4 ⎥ + ⎢ ⎥ + ⎢-1/2 -1/2 0 1/2 1/2⎥ + ⎢ ⎥ + ⎢ √6 √6 ⎥ + ⎢ ── 0 -1/2 0 ── ⎥ + ⎢ 4 4 ⎥ + ⎢ ⎥ + ⎢-1/2 1/2 0 -1/2 1/2⎥ + ⎢ ⎥ + ⎢ √6 ⎥ + ⎢1/4 -1/2 ── -1/2 1/4⎥ + ⎣ 4 ⎦ + + """ + M = [J-i for i in range(2*J+1)] + d = zeros(2*J+1) + + # Mi corresponds to Edmonds' $m'$, and Mj to $m$. + for i, Mi in enumerate(M): + for j, Mj in enumerate(M): + + # We get the maximum and minimum value of sigma. + sigmamax = min([J-Mi, J-Mj]) + sigmamin = max([0, -Mi-Mj]) + + dij = sqrt(factorial(J+Mi)*factorial(J-Mi) / + factorial(J+Mj)/factorial(J-Mj)) + terms = [(-1)**(J-Mi-s) * + binomial(J+Mj, J-Mi-s) * + binomial(J-Mj, s) * + cos(beta/2)**(2*s+Mi+Mj) * + sin(beta/2)**(2*J-2*s-Mj-Mi) + for s in range(sigmamin, sigmamax+1)] + + d[i, j] = dij*Add(*terms) + + return ImmutableMatrix(d) + + +def wigner_d(J, alpha, beta, gamma): + """Return the Wigner D matrix for angular momentum J. + + Explanation + =========== + + J : + An integer, half-integer, or SymPy symbol for the total angular + momentum of the angular momentum space being rotated. + alpha, beta, gamma - Real numbers representing the Euler. + Angles of rotation about the so-called figure axis, line of nodes, + and vertical. See [Edmonds74]_, however note that the symbols alpha + and gamma are swapped in this implementation. + + Returns + ======= + + A matrix representing the corresponding Euler angle rotation (in the basis + of eigenvectors of `J_z`). + + .. math :: + \\mathcal{D}_{\\alpha \\beta \\gamma} = + \\exp\\big( \\frac{i\\alpha}{\\hbar} J_z\\big) + \\exp\\big( \\frac{i\\beta}{\\hbar} J_y\\big) + \\exp\\big( \\frac{i\\gamma}{\\hbar} J_z\\big) + + such that + + .. math :: + \\mathcal{D}^{(J)}_{m',m}(\\alpha, \\beta, \\gamma) = + \\mathtt{wigner_d(J, alpha, beta, gamma)[J-mprime,J-m]} + + The components are calculated using the general form [Edmonds74]_, + equation 4.1.12, however note that the angles alpha and gamma are swapped + in this implementation. + + Examples + ======== + + The simplest possible example: + + >>> from sympy.physics.wigner import wigner_d + >>> from sympy import Integer, symbols, pprint + >>> half = 1/Integer(2) + >>> alpha, beta, gamma = symbols("alpha, beta, gamma", real=True) + >>> pprint(wigner_d(half, alpha, beta, gamma), use_unicode=True) + ⎡ ⅈ⋅α ⅈ⋅γ ⅈ⋅α -ⅈ⋅γ ⎤ + ⎢ ─── ─── ─── ───── ⎥ + ⎢ 2 2 ⎛β⎞ 2 2 ⎛β⎞ ⎥ + ⎢ ℯ ⋅ℯ ⋅cos⎜─⎟ ℯ ⋅ℯ ⋅sin⎜─⎟ ⎥ + ⎢ ⎝2⎠ ⎝2⎠ ⎥ + ⎢ ⎥ + ⎢ -ⅈ⋅α ⅈ⋅γ -ⅈ⋅α -ⅈ⋅γ ⎥ + ⎢ ───── ─── ───── ───── ⎥ + ⎢ 2 2 ⎛β⎞ 2 2 ⎛β⎞⎥ + ⎢-ℯ ⋅ℯ ⋅sin⎜─⎟ ℯ ⋅ℯ ⋅cos⎜─⎟⎥ + ⎣ ⎝2⎠ ⎝2⎠⎦ + + """ + d = wigner_d_small(J, beta) + M = [J-i for i in range(2*J+1)] + # Mi corresponds to Edmonds' $m'$, and Mj to $m$. + D = [[exp(I*Mi*alpha)*d[i, j]*exp(I*Mj*gamma) + for j, Mj in enumerate(M)] for i, Mi in enumerate(M)] + return ImmutableMatrix(D) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..074bcf93b7375eb3dc96d16b5450b539074d8f7d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/__init__.py @@ -0,0 +1,22 @@ +from .plot import plot_backends +from .plot_implicit import plot_implicit +from .textplot import textplot +from .pygletplot import PygletPlot +from .plot import PlotGrid +from .plot import (plot, plot_parametric, plot3d, plot3d_parametric_surface, + plot3d_parametric_line, plot_contour) + +__all__ = [ + 'plot_backends', + + 'plot_implicit', + + 'textplot', + + 'PygletPlot', + + 'PlotGrid', + + 'plot', 'plot_parametric', 'plot3d', 'plot3d_parametric_surface', + 'plot3d_parametric_line', 'plot_contour' +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/experimental_lambdify.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/experimental_lambdify.py new file mode 100644 index 0000000000000000000000000000000000000000..ae17e7adf45f2933ccd71514917199c85d14549e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/experimental_lambdify.py @@ -0,0 +1,641 @@ +""" rewrite of lambdify - This stuff is not stable at all. + +It is for internal use in the new plotting module. +It may (will! see the Q'n'A in the source) be rewritten. + +It's completely self contained. Especially it does not use lambdarepr. + +It does not aim to replace the current lambdify. Most importantly it will never +ever support anything else than SymPy expressions (no Matrices, dictionaries +and so on). +""" + + +import re +from sympy.core.numbers import (I, NumberSymbol, oo, zoo) +from sympy.core.symbol import Symbol +from sympy.utilities.iterables import numbered_symbols + +# We parse the expression string into a tree that identifies functions. Then +# we translate the names of the functions and we translate also some strings +# that are not names of functions (all this according to translation +# dictionaries). +# If the translation goes to another module (like numpy) the +# module is imported and 'func' is translated to 'module.func'. +# If a function can not be translated, the inner nodes of that part of the +# tree are not translated. So if we have Integral(sqrt(x)), sqrt is not +# translated to np.sqrt and the Integral does not crash. +# A namespace for all this is generated by crawling the (func, args) tree of +# the expression. The creation of this namespace involves many ugly +# workarounds. +# The namespace consists of all the names needed for the SymPy expression and +# all the name of modules used for translation. Those modules are imported only +# as a name (import numpy as np) in order to keep the namespace small and +# manageable. + +# Please, if there is a bug, do not try to fix it here! Rewrite this by using +# the method proposed in the last Q'n'A below. That way the new function will +# work just as well, be just as simple, but it wont need any new workarounds. +# If you insist on fixing it here, look at the workarounds in the function +# sympy_expression_namespace and in lambdify. + +# Q: Why are you not using Python abstract syntax tree? +# A: Because it is more complicated and not much more powerful in this case. + +# Q: What if I have Symbol('sin') or g=Function('f')? +# A: You will break the algorithm. We should use srepr to defend against this? +# The problem with Symbol('sin') is that it will be printed as 'sin'. The +# parser will distinguish it from the function 'sin' because functions are +# detected thanks to the opening parenthesis, but the lambda expression won't +# understand the difference if we have also the sin function. +# The solution (complicated) is to use srepr and maybe ast. +# The problem with the g=Function('f') is that it will be printed as 'f' but in +# the global namespace we have only 'g'. But as the same printer is used in the +# constructor of the namespace there will be no problem. + +# Q: What if some of the printers are not printing as expected? +# A: The algorithm wont work. You must use srepr for those cases. But even +# srepr may not print well. All problems with printers should be considered +# bugs. + +# Q: What about _imp_ functions? +# A: Those are taken care for by evalf. A special case treatment will work +# faster but it's not worth the code complexity. + +# Q: Will ast fix all possible problems? +# A: No. You will always have to use some printer. Even srepr may not work in +# some cases. But if the printer does not work, that should be considered a +# bug. + +# Q: Is there same way to fix all possible problems? +# A: Probably by constructing our strings ourself by traversing the (func, +# args) tree and creating the namespace at the same time. That actually sounds +# good. + +from sympy.external import import_module +import warnings + +#TODO debugging output + + +class vectorized_lambdify: + """ Return a sufficiently smart, vectorized and lambdified function. + + Returns only reals. + + Explanation + =========== + + This function uses experimental_lambdify to created a lambdified + expression ready to be used with numpy. Many of the functions in SymPy + are not implemented in numpy so in some cases we resort to Python cmath or + even to evalf. + + The following translations are tried: + only numpy complex + - on errors raised by SymPy trying to work with ndarray: + only Python cmath and then vectorize complex128 + + When using Python cmath there is no need for evalf or float/complex + because Python cmath calls those. + + This function never tries to mix numpy directly with evalf because numpy + does not understand SymPy Float. If this is needed one can use the + float_wrap_evalf/complex_wrap_evalf options of experimental_lambdify or + better one can be explicit about the dtypes that numpy works with. + Check numpy bug http://projects.scipy.org/numpy/ticket/1013 to know what + types of errors to expect. + """ + def __init__(self, args, expr): + self.args = args + self.expr = expr + self.np = import_module('numpy') + + self.lambda_func_1 = experimental_lambdify( + args, expr, use_np=True) + self.vector_func_1 = self.lambda_func_1 + + self.lambda_func_2 = experimental_lambdify( + args, expr, use_python_cmath=True) + self.vector_func_2 = self.np.vectorize( + self.lambda_func_2, otypes=[complex]) + + self.vector_func = self.vector_func_1 + self.failure = False + + def __call__(self, *args): + np = self.np + + try: + temp_args = (np.array(a, dtype=complex) for a in args) + results = self.vector_func(*temp_args) + results = np.ma.masked_where( + np.abs(results.imag) > 1e-7 * np.abs(results), + results.real, copy=False) + return results + except ValueError: + if self.failure: + raise + + self.failure = True + self.vector_func = self.vector_func_2 + warnings.warn( + 'The evaluation of the expression is problematic. ' + 'We are trying a failback method that may still work. ' + 'Please report this as a bug.') + return self.__call__(*args) + + +class lambdify: + """Returns the lambdified function. + + Explanation + =========== + + This function uses experimental_lambdify to create a lambdified + expression. It uses cmath to lambdify the expression. If the function + is not implemented in Python cmath, Python cmath calls evalf on those + functions. + """ + + def __init__(self, args, expr): + self.args = args + self.expr = expr + self.lambda_func_1 = experimental_lambdify( + args, expr, use_python_cmath=True, use_evalf=True) + self.lambda_func_2 = experimental_lambdify( + args, expr, use_python_math=True, use_evalf=True) + self.lambda_func_3 = experimental_lambdify( + args, expr, use_evalf=True, complex_wrap_evalf=True) + self.lambda_func = self.lambda_func_1 + self.failure = False + + def __call__(self, args): + try: + #The result can be sympy.Float. Hence wrap it with complex type. + result = complex(self.lambda_func(args)) + if abs(result.imag) > 1e-7 * abs(result): + return None + return result.real + except (ZeroDivisionError, OverflowError): + return None + except TypeError as e: + if self.failure: + raise e + + if self.lambda_func == self.lambda_func_1: + self.lambda_func = self.lambda_func_2 + return self.__call__(args) + + self.failure = True + self.lambda_func = self.lambda_func_3 + warnings.warn( + 'The evaluation of the expression is problematic. ' + 'We are trying a failback method that may still work. ' + 'Please report this as a bug.', stacklevel=2) + return self.__call__(args) + + +def experimental_lambdify(*args, **kwargs): + l = Lambdifier(*args, **kwargs) + return l + + +class Lambdifier: + def __init__(self, args, expr, print_lambda=False, use_evalf=False, + float_wrap_evalf=False, complex_wrap_evalf=False, + use_np=False, use_python_math=False, use_python_cmath=False, + use_interval=False): + + self.print_lambda = print_lambda + self.use_evalf = use_evalf + self.float_wrap_evalf = float_wrap_evalf + self.complex_wrap_evalf = complex_wrap_evalf + self.use_np = use_np + self.use_python_math = use_python_math + self.use_python_cmath = use_python_cmath + self.use_interval = use_interval + + # Constructing the argument string + # - check + if not all(isinstance(a, Symbol) for a in args): + raise ValueError('The arguments must be Symbols.') + # - use numbered symbols + syms = numbered_symbols(exclude=expr.free_symbols) + newargs = [next(syms) for _ in args] + expr = expr.xreplace(dict(zip(args, newargs))) + argstr = ', '.join([str(a) for a in newargs]) + del syms, newargs, args + + # Constructing the translation dictionaries and making the translation + self.dict_str = self.get_dict_str() + self.dict_fun = self.get_dict_fun() + exprstr = str(expr) + newexpr = self.tree2str_translate(self.str2tree(exprstr)) + + # Constructing the namespaces + namespace = {} + namespace.update(self.sympy_atoms_namespace(expr)) + namespace.update(self.sympy_expression_namespace(expr)) + # XXX Workaround + # Ugly workaround because Pow(a,Half) prints as sqrt(a) + # and sympy_expression_namespace can not catch it. + from sympy.functions.elementary.miscellaneous import sqrt + namespace.update({'sqrt': sqrt}) + namespace.update({'Eq': lambda x, y: x == y}) + namespace.update({'Ne': lambda x, y: x != y}) + # End workaround. + if use_python_math: + namespace.update({'math': __import__('math')}) + if use_python_cmath: + namespace.update({'cmath': __import__('cmath')}) + if use_np: + try: + namespace.update({'np': __import__('numpy')}) + except ImportError: + raise ImportError( + 'experimental_lambdify failed to import numpy.') + if use_interval: + namespace.update({'imath': __import__( + 'sympy.plotting.intervalmath', fromlist=['intervalmath'])}) + namespace.update({'math': __import__('math')}) + + # Construct the lambda + if self.print_lambda: + print(newexpr) + eval_str = 'lambda %s : ( %s )' % (argstr, newexpr) + self.eval_str = eval_str + exec("MYNEWLAMBDA = %s" % eval_str, namespace) + self.lambda_func = namespace['MYNEWLAMBDA'] + + def __call__(self, *args, **kwargs): + return self.lambda_func(*args, **kwargs) + + + ############################################################################## + # Dicts for translating from SymPy to other modules + ############################################################################## + ### + # builtins + ### + # Functions with different names in builtins + builtin_functions_different = { + 'Min': 'min', + 'Max': 'max', + 'Abs': 'abs', + } + + # Strings that should be translated + builtin_not_functions = { + 'I': '1j', +# 'oo': '1e400', + } + + ### + # numpy + ### + + # Functions that are the same in numpy + numpy_functions_same = [ + 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'exp', 'log', + 'sqrt', 'floor', 'conjugate', 'sign', + ] + + # Functions with different names in numpy + numpy_functions_different = { + "acos": "arccos", + "acosh": "arccosh", + "arg": "angle", + "asin": "arcsin", + "asinh": "arcsinh", + "atan": "arctan", + "atan2": "arctan2", + "atanh": "arctanh", + "ceiling": "ceil", + "im": "imag", + "ln": "log", + "Max": "amax", + "Min": "amin", + "re": "real", + "Abs": "abs", + } + + # Strings that should be translated + numpy_not_functions = { + 'pi': 'np.pi', + 'oo': 'np.inf', + 'E': 'np.e', + } + + ### + # Python math + ### + + # Functions that are the same in math + math_functions_same = [ + 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', + 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', + 'exp', 'log', 'erf', 'sqrt', 'floor', 'factorial', 'gamma', + ] + + # Functions with different names in math + math_functions_different = { + 'ceiling': 'ceil', + 'ln': 'log', + 'loggamma': 'lgamma' + } + + # Strings that should be translated + math_not_functions = { + 'pi': 'math.pi', + 'E': 'math.e', + } + + ### + # Python cmath + ### + + # Functions that are the same in cmath + cmath_functions_same = [ + 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', + 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', + 'exp', 'log', 'sqrt', + ] + + # Functions with different names in cmath + cmath_functions_different = { + 'ln': 'log', + 'arg': 'phase', + } + + # Strings that should be translated + cmath_not_functions = { + 'pi': 'cmath.pi', + 'E': 'cmath.e', + } + + ### + # intervalmath + ### + + interval_not_functions = { + 'pi': 'math.pi', + 'E': 'math.e' + } + + interval_functions_same = [ + 'sin', 'cos', 'exp', 'tan', 'atan', 'log', + 'sqrt', 'cosh', 'sinh', 'tanh', 'floor', + 'acos', 'asin', 'acosh', 'asinh', 'atanh', + 'Abs', 'And', 'Or' + ] + + interval_functions_different = { + 'Min': 'imin', + 'Max': 'imax', + 'ceiling': 'ceil', + + } + + ### + # mpmath, etc + ### + #TODO + + ### + # Create the final ordered tuples of dictionaries + ### + + # For strings + def get_dict_str(self): + dict_str = dict(self.builtin_not_functions) + if self.use_np: + dict_str.update(self.numpy_not_functions) + if self.use_python_math: + dict_str.update(self.math_not_functions) + if self.use_python_cmath: + dict_str.update(self.cmath_not_functions) + if self.use_interval: + dict_str.update(self.interval_not_functions) + return dict_str + + # For functions + def get_dict_fun(self): + dict_fun = dict(self.builtin_functions_different) + if self.use_np: + for s in self.numpy_functions_same: + dict_fun[s] = 'np.' + s + for k, v in self.numpy_functions_different.items(): + dict_fun[k] = 'np.' + v + if self.use_python_math: + for s in self.math_functions_same: + dict_fun[s] = 'math.' + s + for k, v in self.math_functions_different.items(): + dict_fun[k] = 'math.' + v + if self.use_python_cmath: + for s in self.cmath_functions_same: + dict_fun[s] = 'cmath.' + s + for k, v in self.cmath_functions_different.items(): + dict_fun[k] = 'cmath.' + v + if self.use_interval: + for s in self.interval_functions_same: + dict_fun[s] = 'imath.' + s + for k, v in self.interval_functions_different.items(): + dict_fun[k] = 'imath.' + v + return dict_fun + + ############################################################################## + # The translator functions, tree parsers, etc. + ############################################################################## + + def str2tree(self, exprstr): + """Converts an expression string to a tree. + + Explanation + =========== + + Functions are represented by ('func_name(', tree_of_arguments). + Other expressions are (head_string, mid_tree, tail_str). + Expressions that do not contain functions are directly returned. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy import Integral, sin + >>> from sympy.plotting.experimental_lambdify import Lambdifier + >>> str2tree = Lambdifier([x], x).str2tree + + >>> str2tree(str(Integral(x, (x, 1, y)))) + ('', ('Integral(', 'x, (x, 1, y)'), ')') + >>> str2tree(str(x+y)) + 'x + y' + >>> str2tree(str(x+y*sin(z)+1)) + ('x + y*', ('sin(', 'z'), ') + 1') + >>> str2tree('sin(y*(y + 1.1) + (sin(y)))') + ('', ('sin(', ('y*(y + 1.1) + (', ('sin(', 'y'), '))')), ')') + """ + #matches the first 'function_name(' + first_par = re.search(r'(\w+\()', exprstr) + if first_par is None: + return exprstr + else: + start = first_par.start() + end = first_par.end() + head = exprstr[:start] + func = exprstr[start:end] + tail = exprstr[end:] + count = 0 + for i, c in enumerate(tail): + if c == '(': + count += 1 + elif c == ')': + count -= 1 + if count == -1: + break + func_tail = self.str2tree(tail[:i]) + tail = self.str2tree(tail[i:]) + return (head, (func, func_tail), tail) + + @classmethod + def tree2str(cls, tree): + """Converts a tree to string without translations. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy import sin + >>> from sympy.plotting.experimental_lambdify import Lambdifier + >>> str2tree = Lambdifier([x], x).str2tree + >>> tree2str = Lambdifier([x], x).tree2str + + >>> tree2str(str2tree(str(x+y*sin(z)+1))) + 'x + y*sin(z) + 1' + """ + if isinstance(tree, str): + return tree + else: + return ''.join(map(cls.tree2str, tree)) + + def tree2str_translate(self, tree): + """Converts a tree to string with translations. + + Explanation + =========== + + Function names are translated by translate_func. + Other strings are translated by translate_str. + """ + if isinstance(tree, str): + return self.translate_str(tree) + elif isinstance(tree, tuple) and len(tree) == 2: + return self.translate_func(tree[0][:-1], tree[1]) + else: + return ''.join([self.tree2str_translate(t) for t in tree]) + + def translate_str(self, estr): + """Translate substrings of estr using in order the dictionaries in + dict_tuple_str.""" + for pattern, repl in self.dict_str.items(): + estr = re.sub(pattern, repl, estr) + return estr + + def translate_func(self, func_name, argtree): + """Translate function names and the tree of arguments. + + Explanation + =========== + + If the function name is not in the dictionaries of dict_tuple_fun then the + function is surrounded by a float((...).evalf()). + + The use of float is necessary as np.(sympy.Float(..)) raises an + error.""" + if func_name in self.dict_fun: + new_name = self.dict_fun[func_name] + argstr = self.tree2str_translate(argtree) + return new_name + '(' + argstr + elif func_name in ['Eq', 'Ne']: + op = {'Eq': '==', 'Ne': '!='} + return "(lambda x, y: x {} y)({}".format(op[func_name], self.tree2str_translate(argtree)) + else: + template = '(%s(%s)).evalf(' if self.use_evalf else '%s(%s' + if self.float_wrap_evalf: + template = 'float(%s)' % template + elif self.complex_wrap_evalf: + template = 'complex(%s)' % template + + # Wrapping should only happen on the outermost expression, which + # is the only thing we know will be a number. + float_wrap_evalf = self.float_wrap_evalf + complex_wrap_evalf = self.complex_wrap_evalf + self.float_wrap_evalf = False + self.complex_wrap_evalf = False + ret = template % (func_name, self.tree2str_translate(argtree)) + self.float_wrap_evalf = float_wrap_evalf + self.complex_wrap_evalf = complex_wrap_evalf + return ret + + ############################################################################## + # The namespace constructors + ############################################################################## + + @classmethod + def sympy_expression_namespace(cls, expr): + """Traverses the (func, args) tree of an expression and creates a SymPy + namespace. All other modules are imported only as a module name. That way + the namespace is not polluted and rests quite small. It probably causes much + more variable lookups and so it takes more time, but there are no tests on + that for the moment.""" + if expr is None: + return {} + else: + funcname = str(expr.func) + # XXX Workaround + # Here we add an ugly workaround because str(func(x)) + # is not always the same as str(func). Eg + # >>> str(Integral(x)) + # "Integral(x)" + # >>> str(Integral) + # "" + # >>> str(sqrt(x)) + # "sqrt(x)" + # >>> str(sqrt) + # "" + # >>> str(sin(x)) + # "sin(x)" + # >>> str(sin) + # "sin" + # Either one of those can be used but not all at the same time. + # The code considers the sin example as the right one. + regexlist = [ + r'$', + # the example Integral + r'$', # the example sqrt + ] + for r in regexlist: + m = re.match(r, funcname) + if m is not None: + funcname = m.groups()[0] + # End of the workaround + # XXX debug: print funcname + args_dict = {} + for a in expr.args: + if (isinstance(a, (Symbol, NumberSymbol)) or a in [I, zoo, oo]): + continue + else: + args_dict.update(cls.sympy_expression_namespace(a)) + args_dict.update({funcname: expr.func}) + return args_dict + + @staticmethod + def sympy_atoms_namespace(expr): + """For no real reason this function is separated from + sympy_expression_namespace. It can be moved to it.""" + atoms = expr.atoms(Symbol, NumberSymbol, I, zoo, oo) + d = {} + for a in atoms: + # XXX debug: print 'atom:' + str(a) + d[str(a)] = a + return d diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plot.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plot.py new file mode 100644 index 0000000000000000000000000000000000000000..50029392a1ac70491f93f28c4d443da15e7fc31e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plot.py @@ -0,0 +1,1234 @@ +"""Plotting module for SymPy. + +A plot is represented by the ``Plot`` class that contains a reference to the +backend and a list of the data series to be plotted. The data series are +instances of classes meant to simplify getting points and meshes from SymPy +expressions. ``plot_backends`` is a dictionary with all the backends. + +This module gives only the essential. For all the fancy stuff use directly +the backend. You can get the backend wrapper for every plot from the +``_backend`` attribute. Moreover the data series classes have various useful +methods like ``get_points``, ``get_meshes``, etc, that may +be useful if you wish to use another plotting library. + +Especially if you need publication ready graphs and this module is not enough +for you - just get the ``_backend`` attribute and add whatever you want +directly to it. In the case of matplotlib (the common way to graph data in +python) just copy ``_backend.fig`` which is the figure and ``_backend.ax`` +which is the axis and work on them as you would on any other matplotlib object. + +Simplicity of code takes much greater importance than performance. Do not use it +if you care at all about performance. A new backend instance is initialized +every time you call ``show()`` and the old one is left to the garbage collector. +""" + +from sympy.concrete.summations import Sum +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import Function, AppliedUndef +from sympy.core.symbol import (Dummy, Symbol, Wild) +from sympy.external import import_module +from sympy.functions import sign +from sympy.plotting.backends.base_backend import Plot +from sympy.plotting.backends.matplotlibbackend import MatplotlibBackend +from sympy.plotting.backends.textbackend import TextBackend +from sympy.plotting.series import ( + LineOver1DRangeSeries, Parametric2DLineSeries, Parametric3DLineSeries, + ParametricSurfaceSeries, SurfaceOver2DRangeSeries, ContourSeries) +from sympy.plotting.utils import _check_arguments, _plot_sympify +from sympy.tensor.indexed import Indexed +# to maintain back-compatibility +from sympy.plotting.plotgrid import PlotGrid # noqa: F401 +from sympy.plotting.series import BaseSeries # noqa: F401 +from sympy.plotting.series import Line2DBaseSeries # noqa: F401 +from sympy.plotting.series import Line3DBaseSeries # noqa: F401 +from sympy.plotting.series import SurfaceBaseSeries # noqa: F401 +from sympy.plotting.series import List2DSeries # noqa: F401 +from sympy.plotting.series import GenericDataSeries # noqa: F401 +from sympy.plotting.series import centers_of_faces # noqa: F401 +from sympy.plotting.series import centers_of_segments # noqa: F401 +from sympy.plotting.series import flat # noqa: F401 +from sympy.plotting.backends.base_backend import unset_show # noqa: F401 +from sympy.plotting.backends.matplotlibbackend import _matplotlib_list # noqa: F401 +from sympy.plotting.textplot import textplot # noqa: F401 + + +__doctest_requires__ = { + ('plot3d', + 'plot3d_parametric_line', + 'plot3d_parametric_surface', + 'plot_parametric'): ['matplotlib'], + # XXX: The plot doctest possibly should not require matplotlib. It fails at + # plot(x**2, (x, -5, 5)) which should be fine for text backend. + ('plot',): ['matplotlib'], +} + + +def _process_summations(sum_bound, *args): + """Substitute oo (infinity) in the lower/upper bounds of a summation with + some integer number. + + Parameters + ========== + + sum_bound : int + oo will be substituted with this integer number. + *args : list/tuple + pre-processed arguments of the form (expr, range, ...) + + Notes + ===== + Let's consider the following summation: ``Sum(1 / x**2, (x, 1, oo))``. + The current implementation of lambdify (SymPy 1.12 at the time of + writing this) will create something of this form: + ``sum(1 / x**2 for x in range(1, INF))`` + The problem is that ``type(INF)`` is float, while ``range`` requires + integers: the evaluation fails. + Instead of modifying ``lambdify`` (which requires a deep knowledge), just + replace it with some integer number. + """ + def new_bound(t, bound): + if (not t.is_number) or t.is_finite: + return t + if sign(t) >= 0: + return bound + return -bound + + args = list(args) + expr = args[0] + + # select summations whose lower/upper bound is infinity + w = Wild("w", properties=[ + lambda t: isinstance(t, Sum), + lambda t: any((not a[1].is_finite) or (not a[2].is_finite) for i, a in enumerate(t.args) if i > 0) + ]) + + for t in list(expr.find(w)): + sums_args = list(t.args) + for i, a in enumerate(sums_args): + if i > 0: + sums_args[i] = (a[0], new_bound(a[1], sum_bound), + new_bound(a[2], sum_bound)) + s = Sum(*sums_args) + expr = expr.subs(t, s) + args[0] = expr + return args + + +def _build_line_series(*args, **kwargs): + """Loop over the provided arguments and create the necessary line series. + """ + series = [] + sum_bound = int(kwargs.get("sum_bound", 1000)) + for arg in args: + expr, r, label, rendering_kw = arg + kw = kwargs.copy() + if rendering_kw is not None: + kw["rendering_kw"] = rendering_kw + # TODO: _process_piecewise check goes here + if not callable(expr): + arg = _process_summations(sum_bound, *arg) + series.append(LineOver1DRangeSeries(*arg[:-1], **kw)) + return series + + +def _create_series(series_type, plot_expr, **kwargs): + """Extract the rendering_kw dictionary from the provided arguments and + create an appropriate data series. + """ + series = [] + for args in plot_expr: + kw = kwargs.copy() + if args[-1] is not None: + kw["rendering_kw"] = args[-1] + series.append(series_type(*args[:-1], **kw)) + return series + + +def _set_labels(series, labels, rendering_kw): + """Apply the `label` and `rendering_kw` keyword arguments to the series. + """ + if not isinstance(labels, (list, tuple)): + labels = [labels] + if len(labels) > 0: + if len(labels) == 1 and len(series) > 1: + # if one label is provided and multiple series are being plotted, + # set the same label to all data series. It maintains + # back-compatibility + labels *= len(series) + if len(series) != len(labels): + raise ValueError("The number of labels must be equal to the " + "number of expressions being plotted.\nReceived " + f"{len(series)} expressions and {len(labels)} labels") + + for s, l in zip(series, labels): + s.label = l + + if rendering_kw: + if isinstance(rendering_kw, dict): + rendering_kw = [rendering_kw] + if len(rendering_kw) == 1: + rendering_kw *= len(series) + elif len(series) != len(rendering_kw): + raise ValueError("The number of rendering dictionaries must be " + "equal to the number of expressions being plotted.\nReceived " + f"{len(series)} expressions and {len(labels)} labels") + for s, r in zip(series, rendering_kw): + s.rendering_kw = r + + +def plot_factory(*args, **kwargs): + backend = kwargs.pop("backend", "default") + if isinstance(backend, str): + if backend == "default": + matplotlib = import_module('matplotlib', + min_module_version='1.1.0', catch=(RuntimeError,)) + if matplotlib: + return MatplotlibBackend(*args, **kwargs) + return TextBackend(*args, **kwargs) + return plot_backends[backend](*args, **kwargs) + elif (type(backend) == type) and issubclass(backend, Plot): + return backend(*args, **kwargs) + else: + raise TypeError("backend must be either a string or a subclass of ``Plot``.") + + +plot_backends = { + 'matplotlib': MatplotlibBackend, + 'text': TextBackend, +} + + +####New API for plotting module #### + +# TODO: Add color arrays for plots. +# TODO: Add more plotting options for 3d plots. +# TODO: Adaptive sampling for 3D plots. + +def plot(*args, show=True, **kwargs): + """Plots a function of a single variable as a curve. + + Parameters + ========== + + args : + The first argument is the expression representing the function + of single variable to be plotted. + + The last argument is a 3-tuple denoting the range of the free + variable. e.g. ``(x, 0, 5)`` + + Typical usage examples are in the following: + + - Plotting a single expression with a single range. + ``plot(expr, range, **kwargs)`` + - Plotting a single expression with the default range (-10, 10). + ``plot(expr, **kwargs)`` + - Plotting multiple expressions with a single range. + ``plot(expr1, expr2, ..., range, **kwargs)`` + - Plotting multiple expressions with multiple ranges. + ``plot((expr1, range1), (expr2, range2), ..., **kwargs)`` + + It is best practice to specify range explicitly because default + range may change in the future if a more advanced default range + detection algorithm is implemented. + + show : bool, optional + The default value is set to ``True``. Set show to ``False`` and + the function will not display the plot. The returned instance of + the ``Plot`` class can then be used to save or display the plot + by calling the ``save()`` and ``show()`` methods respectively. + + line_color : string, or float, or function, optional + Specifies the color for the plot. + See ``Plot`` to see how to set color for the plots. + Note that by setting ``line_color``, it would be applied simultaneously + to all the series. + + title : str, optional + Title of the plot. It is set to the latex representation of + the expression, if the plot has only one expression. + + label : str, optional + The label of the expression in the plot. It will be used when + called with ``legend``. Default is the name of the expression. + e.g. ``sin(x)`` + + xlabel : str or expression, optional + Label for the x-axis. + + ylabel : str or expression, optional + Label for the y-axis. + + xscale : 'linear' or 'log', optional + Sets the scaling of the x-axis. + + yscale : 'linear' or 'log', optional + Sets the scaling of the y-axis. + + axis_center : (float, float), optional + Tuple of two floats denoting the coordinates of the center or + {'center', 'auto'} + + xlim : (float, float), optional + Denotes the x-axis limits, ``(min, max)```. + + ylim : (float, float), optional + Denotes the y-axis limits, ``(min, max)```. + + annotations : list, optional + A list of dictionaries specifying the type of annotation + required. The keys in the dictionary should be equivalent + to the arguments of the :external:mod:`matplotlib`'s + :external:meth:`~matplotlib.axes.Axes.annotate` method. + + markers : list, optional + A list of dictionaries specifying the type the markers required. + The keys in the dictionary should be equivalent to the arguments + of the :external:mod:`matplotlib`'s :external:func:`~matplotlib.pyplot.plot()` function + along with the marker related keyworded arguments. + + rectangles : list, optional + A list of dictionaries specifying the dimensions of the + rectangles to be plotted. The keys in the dictionary should be + equivalent to the arguments of the :external:mod:`matplotlib`'s + :external:class:`~matplotlib.patches.Rectangle` class. + + fill : dict, optional + A dictionary specifying the type of color filling required in + the plot. The keys in the dictionary should be equivalent to the + arguments of the :external:mod:`matplotlib`'s + :external:meth:`~matplotlib.axes.Axes.fill_between` method. + + adaptive : bool, optional + The default value for the ``adaptive`` parameter is now ``False``. + To enable adaptive sampling, set ``adaptive=True`` and specify ``n`` if uniform sampling is required. + + The plotting uses an adaptive algorithm which samples + recursively to accurately plot. The adaptive algorithm uses a + random point near the midpoint of two points that has to be + further sampled. Hence the same plots can appear slightly + different. + + depth : int, optional + Recursion depth of the adaptive algorithm. A depth of value + `n` samples a maximum of `2^{n}` points. + + If the ``adaptive`` flag is set to ``False``, this will be + ignored. + + n : int, optional + Used when the ``adaptive`` is set to ``False``. The function + is uniformly sampled at ``n`` number of points. If the ``adaptive`` + flag is set to ``True``, this will be ignored. + This keyword argument replaces ``nb_of_points``, which should be + considered deprecated. + + size : (float, float), optional + A tuple in the form (width, height) in inches to specify the size of + the overall figure. The default value is set to ``None``, meaning + the size will be set by the default backend. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.plotting import plot + >>> x = symbols('x') + + Single Plot + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot(x**2, (x, -5, 5)) + Plot object containing: + [0]: cartesian line: x**2 for x over (-5.0, 5.0) + + Multiple plots with single range. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot(x, x**2, x**3, (x, -5, 5)) + Plot object containing: + [0]: cartesian line: x for x over (-5.0, 5.0) + [1]: cartesian line: x**2 for x over (-5.0, 5.0) + [2]: cartesian line: x**3 for x over (-5.0, 5.0) + + Multiple plots with different ranges. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot((x**2, (x, -6, 6)), (x, (x, -5, 5))) + Plot object containing: + [0]: cartesian line: x**2 for x over (-6.0, 6.0) + [1]: cartesian line: x for x over (-5.0, 5.0) + + No adaptive sampling by default. If adaptive sampling is required, set ``adaptive=True``. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot(x**2, adaptive=True, n=400) + Plot object containing: + [0]: cartesian line: x**2 for x over (-10.0, 10.0) + + See Also + ======== + + Plot, LineOver1DRangeSeries + + """ + args = _plot_sympify(args) + plot_expr = _check_arguments(args, 1, 1, **kwargs) + params = kwargs.get("params", None) + free = set() + for p in plot_expr: + if not isinstance(p[1][0], str): + free |= {p[1][0]} + else: + free |= {Symbol(p[1][0])} + if params: + free = free.difference(params.keys()) + x = free.pop() if free else Symbol("x") + kwargs.setdefault('xlabel', x) + kwargs.setdefault('ylabel', Function('f')(x)) + + labels = kwargs.pop("label", []) + rendering_kw = kwargs.pop("rendering_kw", None) + series = _build_line_series(*plot_expr, **kwargs) + _set_labels(series, labels, rendering_kw) + + plots = plot_factory(*series, **kwargs) + if show: + plots.show() + return plots + + +def plot_parametric(*args, show=True, **kwargs): + """ + Plots a 2D parametric curve. + + Parameters + ========== + + args + Common specifications are: + + - Plotting a single parametric curve with a range + ``plot_parametric((expr_x, expr_y), range)`` + - Plotting multiple parametric curves with the same range + ``plot_parametric((expr_x, expr_y), ..., range)`` + - Plotting multiple parametric curves with different ranges + ``plot_parametric((expr_x, expr_y, range), ...)`` + + ``expr_x`` is the expression representing $x$ component of the + parametric function. + + ``expr_y`` is the expression representing $y$ component of the + parametric function. + + ``range`` is a 3-tuple denoting the parameter symbol, start and + stop. For example, ``(u, 0, 5)``. + + If the range is not specified, then a default range of (-10, 10) + is used. + + However, if the arguments are specified as + ``(expr_x, expr_y, range), ...``, you must specify the ranges + for each expressions manually. + + Default range may change in the future if a more advanced + algorithm is implemented. + + adaptive : bool, optional + Specifies whether to use the adaptive sampling or not. + + The default value is set to ``True``. Set adaptive to ``False`` + and specify ``n`` if uniform sampling is required. + + depth : int, optional + The recursion depth of the adaptive algorithm. A depth of + value $n$ samples a maximum of $2^n$ points. + + n : int, optional + Used when the ``adaptive`` flag is set to ``False``. Specifies the + number of the points used for the uniform sampling. + This keyword argument replaces ``nb_of_points``, which should be + considered deprecated. + + line_color : string, or float, or function, optional + Specifies the color for the plot. + See ``Plot`` to see how to set color for the plots. + Note that by setting ``line_color``, it would be applied simultaneously + to all the series. + + label : str, optional + The label of the expression in the plot. It will be used when + called with ``legend``. Default is the name of the expression. + e.g. ``sin(x)`` + + xlabel : str, optional + Label for the x-axis. + + ylabel : str, optional + Label for the y-axis. + + xscale : 'linear' or 'log', optional + Sets the scaling of the x-axis. + + yscale : 'linear' or 'log', optional + Sets the scaling of the y-axis. + + axis_center : (float, float), optional + Tuple of two floats denoting the coordinates of the center or + {'center', 'auto'} + + xlim : (float, float), optional + Denotes the x-axis limits, ``(min, max)```. + + ylim : (float, float), optional + Denotes the y-axis limits, ``(min, max)```. + + size : (float, float), optional + A tuple in the form (width, height) in inches to specify the size of + the overall figure. The default value is set to ``None``, meaning + the size will be set by the default backend. + + Examples + ======== + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import plot_parametric, symbols, cos, sin + >>> u = symbols('u') + + A parametric plot with a single expression: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot_parametric((cos(u), sin(u)), (u, -5, 5)) + Plot object containing: + [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-5.0, 5.0) + + A parametric plot with multiple expressions with the same range: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot_parametric((cos(u), sin(u)), (u, cos(u)), (u, -10, 10)) + Plot object containing: + [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-10.0, 10.0) + [1]: parametric cartesian line: (u, cos(u)) for u over (-10.0, 10.0) + + A parametric plot with multiple expressions with different ranges + for each curve: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot_parametric((cos(u), sin(u), (u, -5, 5)), + ... (cos(u), u, (u, -5, 5))) + Plot object containing: + [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-5.0, 5.0) + [1]: parametric cartesian line: (cos(u), u) for u over (-5.0, 5.0) + + Notes + ===== + + The plotting uses an adaptive algorithm which samples recursively to + accurately plot the curve. The adaptive algorithm uses a random point + near the midpoint of two points that has to be further sampled. + Hence, repeating the same plot command can give slightly different + results because of the random sampling. + + If there are multiple plots, then the same optional arguments are + applied to all the plots drawn in the same canvas. If you want to + set these options separately, you can index the returned ``Plot`` + object and set it. + + For example, when you specify ``line_color`` once, it would be + applied simultaneously to both series. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import pi + >>> expr1 = (u, cos(2*pi*u)/2 + 1/2) + >>> expr2 = (u, sin(2*pi*u)/2 + 1/2) + >>> p = plot_parametric(expr1, expr2, (u, 0, 1), line_color='blue') + + If you want to specify the line color for the specific series, you + should index each item and apply the property manually. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p[0].line_color = 'red' + >>> p.show() + + See Also + ======== + + Plot, Parametric2DLineSeries + """ + args = _plot_sympify(args) + plot_expr = _check_arguments(args, 2, 1, **kwargs) + + labels = kwargs.pop("label", []) + rendering_kw = kwargs.pop("rendering_kw", None) + series = _create_series(Parametric2DLineSeries, plot_expr, **kwargs) + _set_labels(series, labels, rendering_kw) + + plots = plot_factory(*series, **kwargs) + if show: + plots.show() + return plots + + +def plot3d_parametric_line(*args, show=True, **kwargs): + """ + Plots a 3D parametric line plot. + + Usage + ===== + + Single plot: + + ``plot3d_parametric_line(expr_x, expr_y, expr_z, range, **kwargs)`` + + If the range is not specified, then a default range of (-10, 10) is used. + + Multiple plots. + + ``plot3d_parametric_line((expr_x, expr_y, expr_z, range), ..., **kwargs)`` + + Ranges have to be specified for every expression. + + Default range may change in the future if a more advanced default range + detection algorithm is implemented. + + Arguments + ========= + + expr_x : Expression representing the function along x. + + expr_y : Expression representing the function along y. + + expr_z : Expression representing the function along z. + + range : (:class:`~.Symbol`, float, float) + A 3-tuple denoting the range of the parameter variable, e.g., (u, 0, 5). + + Keyword Arguments + ================= + + Arguments for ``Parametric3DLineSeries`` class. + + n : int + The range is uniformly sampled at ``n`` number of points. + This keyword argument replaces ``nb_of_points``, which should be + considered deprecated. + + Aesthetics: + + line_color : string, or float, or function, optional + Specifies the color for the plot. + See ``Plot`` to see how to set color for the plots. + Note that by setting ``line_color``, it would be applied simultaneously + to all the series. + + label : str + The label to the plot. It will be used when called with ``legend=True`` + to denote the function with the given label in the plot. + + If there are multiple plots, then the same series arguments are applied to + all the plots. If you want to set these options separately, you can index + the returned ``Plot`` object and set it. + + Arguments for ``Plot`` class. + + title : str + Title of the plot. + + size : (float, float), optional + A tuple in the form (width, height) in inches to specify the size of + the overall figure. The default value is set to ``None``, meaning + the size will be set by the default backend. + + Examples + ======== + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import symbols, cos, sin + >>> from sympy.plotting import plot3d_parametric_line + >>> u = symbols('u') + + Single plot. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot3d_parametric_line(cos(u), sin(u), u, (u, -5, 5)) + Plot object containing: + [0]: 3D parametric cartesian line: (cos(u), sin(u), u) for u over (-5.0, 5.0) + + + Multiple plots. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot3d_parametric_line((cos(u), sin(u), u, (u, -5, 5)), + ... (sin(u), u**2, u, (u, -5, 5))) + Plot object containing: + [0]: 3D parametric cartesian line: (cos(u), sin(u), u) for u over (-5.0, 5.0) + [1]: 3D parametric cartesian line: (sin(u), u**2, u) for u over (-5.0, 5.0) + + + See Also + ======== + + Plot, Parametric3DLineSeries + + """ + args = _plot_sympify(args) + plot_expr = _check_arguments(args, 3, 1, **kwargs) + kwargs.setdefault("xlabel", "x") + kwargs.setdefault("ylabel", "y") + kwargs.setdefault("zlabel", "z") + + labels = kwargs.pop("label", []) + rendering_kw = kwargs.pop("rendering_kw", None) + series = _create_series(Parametric3DLineSeries, plot_expr, **kwargs) + _set_labels(series, labels, rendering_kw) + + plots = plot_factory(*series, **kwargs) + if show: + plots.show() + return plots + + +def _plot3d_plot_contour_helper(Series, *args, **kwargs): + """plot3d and plot_contour are structurally identical. Let's reduce + code repetition. + """ + # NOTE: if this import would be at the top-module level, it would trigger + # SymPy's optional-dependencies tests to fail. + from sympy.vector import BaseScalar + + args = _plot_sympify(args) + plot_expr = _check_arguments(args, 1, 2, **kwargs) + + free_x = set() + free_y = set() + _types = (Symbol, BaseScalar, Indexed, AppliedUndef) + for p in plot_expr: + free_x |= {p[1][0]} if isinstance(p[1][0], _types) else {Symbol(p[1][0])} + free_y |= {p[2][0]} if isinstance(p[2][0], _types) else {Symbol(p[2][0])} + x = free_x.pop() if free_x else Symbol("x") + y = free_y.pop() if free_y else Symbol("y") + kwargs.setdefault("xlabel", x) + kwargs.setdefault("ylabel", y) + kwargs.setdefault("zlabel", Function('f')(x, y)) + + # if a polar discretization is requested and automatic labelling has ben + # applied, hide the labels on the x-y axis. + if kwargs.get("is_polar", False): + if callable(kwargs["xlabel"]): + kwargs["xlabel"] = "" + if callable(kwargs["ylabel"]): + kwargs["ylabel"] = "" + + labels = kwargs.pop("label", []) + rendering_kw = kwargs.pop("rendering_kw", None) + series = _create_series(Series, plot_expr, **kwargs) + _set_labels(series, labels, rendering_kw) + plots = plot_factory(*series, **kwargs) + if kwargs.get("show", True): + plots.show() + return plots + + +def plot3d(*args, show=True, **kwargs): + """ + Plots a 3D surface plot. + + Usage + ===== + + Single plot + + ``plot3d(expr, range_x, range_y, **kwargs)`` + + If the ranges are not specified, then a default range of (-10, 10) is used. + + Multiple plot with the same range. + + ``plot3d(expr1, expr2, range_x, range_y, **kwargs)`` + + If the ranges are not specified, then a default range of (-10, 10) is used. + + Multiple plots with different ranges. + + ``plot3d((expr1, range_x, range_y), (expr2, range_x, range_y), ..., **kwargs)`` + + Ranges have to be specified for every expression. + + Default range may change in the future if a more advanced default range + detection algorithm is implemented. + + Arguments + ========= + + expr : Expression representing the function along x. + + range_x : (:class:`~.Symbol`, float, float) + A 3-tuple denoting the range of the x variable, e.g. (x, 0, 5). + + range_y : (:class:`~.Symbol`, float, float) + A 3-tuple denoting the range of the y variable, e.g. (y, 0, 5). + + Keyword Arguments + ================= + + Arguments for ``SurfaceOver2DRangeSeries`` class: + + n1 : int + The x range is sampled uniformly at ``n1`` of points. + This keyword argument replaces ``nb_of_points_x``, which should be + considered deprecated. + + n2 : int + The y range is sampled uniformly at ``n2`` of points. + This keyword argument replaces ``nb_of_points_y``, which should be + considered deprecated. + + Aesthetics: + + surface_color : Function which returns a float + Specifies the color for the surface of the plot. + See :class:`~.Plot` for more details. + + If there are multiple plots, then the same series arguments are applied to + all the plots. If you want to set these options separately, you can index + the returned ``Plot`` object and set it. + + Arguments for ``Plot`` class: + + title : str + Title of the plot. + + size : (float, float), optional + A tuple in the form (width, height) in inches to specify the size of the + overall figure. The default value is set to ``None``, meaning the size will + be set by the default backend. + + Examples + ======== + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.plotting import plot3d + >>> x, y = symbols('x y') + + Single plot + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot3d(x*y, (x, -5, 5), (y, -5, 5)) + Plot object containing: + [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) + + + Multiple plots with same range + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot3d(x*y, -x*y, (x, -5, 5), (y, -5, 5)) + Plot object containing: + [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) + [1]: cartesian surface: -x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) + + + Multiple plots with different ranges. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot3d((x**2 + y**2, (x, -5, 5), (y, -5, 5)), + ... (x*y, (x, -3, 3), (y, -3, 3))) + Plot object containing: + [0]: cartesian surface: x**2 + y**2 for x over (-5.0, 5.0) and y over (-5.0, 5.0) + [1]: cartesian surface: x*y for x over (-3.0, 3.0) and y over (-3.0, 3.0) + + + See Also + ======== + + Plot, SurfaceOver2DRangeSeries + + """ + kwargs.setdefault("show", show) + return _plot3d_plot_contour_helper( + SurfaceOver2DRangeSeries, *args, **kwargs) + + +def plot3d_parametric_surface(*args, show=True, **kwargs): + """ + Plots a 3D parametric surface plot. + + Explanation + =========== + + Single plot. + + ``plot3d_parametric_surface(expr_x, expr_y, expr_z, range_u, range_v, **kwargs)`` + + If the ranges is not specified, then a default range of (-10, 10) is used. + + Multiple plots. + + ``plot3d_parametric_surface((expr_x, expr_y, expr_z, range_u, range_v), ..., **kwargs)`` + + Ranges have to be specified for every expression. + + Default range may change in the future if a more advanced default range + detection algorithm is implemented. + + Arguments + ========= + + expr_x : Expression representing the function along ``x``. + + expr_y : Expression representing the function along ``y``. + + expr_z : Expression representing the function along ``z``. + + range_u : (:class:`~.Symbol`, float, float) + A 3-tuple denoting the range of the u variable, e.g. (u, 0, 5). + + range_v : (:class:`~.Symbol`, float, float) + A 3-tuple denoting the range of the v variable, e.g. (v, 0, 5). + + Keyword Arguments + ================= + + Arguments for ``ParametricSurfaceSeries`` class: + + n1 : int + The ``u`` range is sampled uniformly at ``n1`` of points. + This keyword argument replaces ``nb_of_points_u``, which should be + considered deprecated. + + n2 : int + The ``v`` range is sampled uniformly at ``n2`` of points. + This keyword argument replaces ``nb_of_points_v``, which should be + considered deprecated. + + Aesthetics: + + surface_color : Function which returns a float + Specifies the color for the surface of the plot. See + :class:`~Plot` for more details. + + If there are multiple plots, then the same series arguments are applied for + all the plots. If you want to set these options separately, you can index + the returned ``Plot`` object and set it. + + + Arguments for ``Plot`` class: + + title : str + Title of the plot. + + size : (float, float), optional + A tuple in the form (width, height) in inches to specify the size of the + overall figure. The default value is set to ``None``, meaning the size will + be set by the default backend. + + Examples + ======== + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import symbols, cos, sin + >>> from sympy.plotting import plot3d_parametric_surface + >>> u, v = symbols('u v') + + Single plot. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> plot3d_parametric_surface(cos(u + v), sin(u - v), u - v, + ... (u, -5, 5), (v, -5, 5)) + Plot object containing: + [0]: parametric cartesian surface: (cos(u + v), sin(u - v), u - v) for u over (-5.0, 5.0) and v over (-5.0, 5.0) + + + See Also + ======== + + Plot, ParametricSurfaceSeries + + """ + + args = _plot_sympify(args) + plot_expr = _check_arguments(args, 3, 2, **kwargs) + kwargs.setdefault("xlabel", "x") + kwargs.setdefault("ylabel", "y") + kwargs.setdefault("zlabel", "z") + + labels = kwargs.pop("label", []) + rendering_kw = kwargs.pop("rendering_kw", None) + series = _create_series(ParametricSurfaceSeries, plot_expr, **kwargs) + _set_labels(series, labels, rendering_kw) + + plots = plot_factory(*series, **kwargs) + if show: + plots.show() + return plots + +def plot_contour(*args, show=True, **kwargs): + """ + Draws contour plot of a function + + Usage + ===== + + Single plot + + ``plot_contour(expr, range_x, range_y, **kwargs)`` + + If the ranges are not specified, then a default range of (-10, 10) is used. + + Multiple plot with the same range. + + ``plot_contour(expr1, expr2, range_x, range_y, **kwargs)`` + + If the ranges are not specified, then a default range of (-10, 10) is used. + + Multiple plots with different ranges. + + ``plot_contour((expr1, range_x, range_y), (expr2, range_x, range_y), ..., **kwargs)`` + + Ranges have to be specified for every expression. + + Default range may change in the future if a more advanced default range + detection algorithm is implemented. + + Arguments + ========= + + expr : Expression representing the function along x. + + range_x : (:class:`Symbol`, float, float) + A 3-tuple denoting the range of the x variable, e.g. (x, 0, 5). + + range_y : (:class:`Symbol`, float, float) + A 3-tuple denoting the range of the y variable, e.g. (y, 0, 5). + + Keyword Arguments + ================= + + Arguments for ``ContourSeries`` class: + + n1 : int + The x range is sampled uniformly at ``n1`` of points. + This keyword argument replaces ``nb_of_points_x``, which should be + considered deprecated. + + n2 : int + The y range is sampled uniformly at ``n2`` of points. + This keyword argument replaces ``nb_of_points_y``, which should be + considered deprecated. + + Aesthetics: + + surface_color : Function which returns a float + Specifies the color for the surface of the plot. See + :class:`sympy.plotting.Plot` for more details. + + If there are multiple plots, then the same series arguments are applied to + all the plots. If you want to set these options separately, you can index + the returned ``Plot`` object and set it. + + Arguments for ``Plot`` class: + + title : str + Title of the plot. + + size : (float, float), optional + A tuple in the form (width, height) in inches to specify the size of + the overall figure. The default value is set to ``None``, meaning + the size will be set by the default backend. + + See Also + ======== + + Plot, ContourSeries + + """ + kwargs.setdefault("show", show) + return _plot3d_plot_contour_helper(ContourSeries, *args, **kwargs) + + +def check_arguments(args, expr_len, nb_of_free_symbols): + """ + Checks the arguments and converts into tuples of the + form (exprs, ranges). + + Examples + ======== + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import cos, sin, symbols + >>> from sympy.plotting.plot import check_arguments + >>> x = symbols('x') + >>> check_arguments([cos(x), sin(x)], 2, 1) + [(cos(x), sin(x), (x, -10, 10))] + + >>> check_arguments([x, x**2], 1, 1) + [(x, (x, -10, 10)), (x**2, (x, -10, 10))] + """ + if not args: + return [] + if expr_len > 1 and isinstance(args[0], Expr): + # Multiple expressions same range. + # The arguments are tuples when the expression length is + # greater than 1. + if len(args) < expr_len: + raise ValueError("len(args) should not be less than expr_len") + for i in range(len(args)): + if isinstance(args[i], Tuple): + break + else: + i = len(args) + 1 + + exprs = Tuple(*args[:i]) + free_symbols = list(set().union(*[e.free_symbols for e in exprs])) + if len(args) == expr_len + nb_of_free_symbols: + #Ranges given + plots = [exprs + Tuple(*args[expr_len:])] + else: + default_range = Tuple(-10, 10) + ranges = [] + for symbol in free_symbols: + ranges.append(Tuple(symbol) + default_range) + + for i in range(len(free_symbols) - nb_of_free_symbols): + ranges.append(Tuple(Dummy()) + default_range) + plots = [exprs + Tuple(*ranges)] + return plots + + if isinstance(args[0], Expr) or (isinstance(args[0], Tuple) and + len(args[0]) == expr_len and + expr_len != 3): + # Cannot handle expressions with number of expression = 3. It is + # not possible to differentiate between expressions and ranges. + #Series of plots with same range + for i in range(len(args)): + if isinstance(args[i], Tuple) and len(args[i]) != expr_len: + break + if not isinstance(args[i], Tuple): + args[i] = Tuple(args[i]) + else: + i = len(args) + 1 + + exprs = args[:i] + assert all(isinstance(e, Expr) for expr in exprs for e in expr) + free_symbols = list(set().union(*[e.free_symbols for expr in exprs + for e in expr])) + + if len(free_symbols) > nb_of_free_symbols: + raise ValueError("The number of free_symbols in the expression " + "is greater than %d" % nb_of_free_symbols) + if len(args) == i + nb_of_free_symbols and isinstance(args[i], Tuple): + ranges = Tuple(*list(args[ + i:i + nb_of_free_symbols])) + plots = [expr + ranges for expr in exprs] + return plots + else: + # Use default ranges. + default_range = Tuple(-10, 10) + ranges = [] + for symbol in free_symbols: + ranges.append(Tuple(symbol) + default_range) + + for i in range(nb_of_free_symbols - len(free_symbols)): + ranges.append(Tuple(Dummy()) + default_range) + ranges = Tuple(*ranges) + plots = [expr + ranges for expr in exprs] + return plots + + elif isinstance(args[0], Tuple) and len(args[0]) == expr_len + nb_of_free_symbols: + # Multiple plots with different ranges. + for arg in args: + for i in range(expr_len): + if not isinstance(arg[i], Expr): + raise ValueError("Expected an expression, given %s" % + str(arg[i])) + for i in range(nb_of_free_symbols): + if not len(arg[i + expr_len]) == 3: + raise ValueError("The ranges should be a tuple of " + "length 3, got %s" % str(arg[i + expr_len])) + return args diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plot_implicit.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plot_implicit.py new file mode 100644 index 0000000000000000000000000000000000000000..5dceaf0699a2e6d3ff0bc30f415721918724cad5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plot_implicit.py @@ -0,0 +1,233 @@ +"""Implicit plotting module for SymPy. + +Explanation +=========== + +The module implements a data series called ImplicitSeries which is used by +``Plot`` class to plot implicit plots for different backends. The module, +by default, implements plotting using interval arithmetic. It switches to a +fall back algorithm if the expression cannot be plotted using interval arithmetic. +It is also possible to specify to use the fall back algorithm for all plots. + +Boolean combinations of expressions cannot be plotted by the fall back +algorithm. + +See Also +======== + +sympy.plotting.plot + +References +========== + +.. [1] Jeffrey Allen Tupper. Reliable Two-Dimensional Graphing Methods for +Mathematical Formulae with Two Free Variables. + +.. [2] Jeffrey Allen Tupper. Graphing Equations with Generalized Interval +Arithmetic. Master's thesis. University of Toronto, 1996 + +""" + + +from sympy.core.containers import Tuple +from sympy.core.symbol import (Dummy, Symbol) +from sympy.polys.polyutils import _sort_gens +from sympy.plotting.series import ImplicitSeries, _set_discretization_points +from sympy.plotting.plot import plot_factory +from sympy.utilities.decorator import doctest_depends_on +from sympy.utilities.iterables import flatten + + +__doctest_requires__ = {'plot_implicit': ['matplotlib']} + + +@doctest_depends_on(modules=('matplotlib',)) +def plot_implicit(expr, x_var=None, y_var=None, adaptive=True, depth=0, + n=300, line_color="blue", show=True, **kwargs): + """A plot function to plot implicit equations / inequalities. + + Arguments + ========= + + - expr : The equation / inequality that is to be plotted. + - x_var (optional) : symbol to plot on x-axis or tuple giving symbol + and range as ``(symbol, xmin, xmax)`` + - y_var (optional) : symbol to plot on y-axis or tuple giving symbol + and range as ``(symbol, ymin, ymax)`` + + If neither ``x_var`` nor ``y_var`` are given then the free symbols in the + expression will be assigned in the order they are sorted. + + The following keyword arguments can also be used: + + - ``adaptive`` Boolean. The default value is set to True. It has to be + set to False if you want to use a mesh grid. + + - ``depth`` integer. The depth of recursion for adaptive mesh grid. + Default value is 0. Takes value in the range (0, 4). + + - ``n`` integer. The number of points if adaptive mesh grid is not + used. Default value is 300. This keyword argument replaces ``points``, + which should be considered deprecated. + + - ``show`` Boolean. Default value is True. If set to False, the plot will + not be shown. See ``Plot`` for further information. + + - ``title`` string. The title for the plot. + + - ``xlabel`` string. The label for the x-axis + + - ``ylabel`` string. The label for the y-axis + + Aesthetics options: + + - ``line_color``: float or string. Specifies the color for the plot. + See ``Plot`` to see how to set color for the plots. + Default value is "Blue" + + plot_implicit, by default, uses interval arithmetic to plot functions. If + the expression cannot be plotted using interval arithmetic, it defaults to + a generating a contour using a mesh grid of fixed number of points. By + setting adaptive to False, you can force plot_implicit to use the mesh + grid. The mesh grid method can be effective when adaptive plotting using + interval arithmetic, fails to plot with small line width. + + Examples + ======== + + Plot expressions: + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import plot_implicit, symbols, Eq, And + >>> x, y = symbols('x y') + + Without any ranges for the symbols in the expression: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p1 = plot_implicit(Eq(x**2 + y**2, 5)) + + With the range for the symbols: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p2 = plot_implicit( + ... Eq(x**2 + y**2, 3), (x, -3, 3), (y, -3, 3)) + + With depth of recursion as argument: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p3 = plot_implicit( + ... Eq(x**2 + y**2, 5), (x, -4, 4), (y, -4, 4), depth = 2) + + Using mesh grid and not using adaptive meshing: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p4 = plot_implicit( + ... Eq(x**2 + y**2, 5), (x, -5, 5), (y, -2, 2), + ... adaptive=False) + + Using mesh grid without using adaptive meshing with number of points + specified: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p5 = plot_implicit( + ... Eq(x**2 + y**2, 5), (x, -5, 5), (y, -2, 2), + ... adaptive=False, n=400) + + Plotting regions: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p6 = plot_implicit(y > x**2) + + Plotting Using boolean conjunctions: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p7 = plot_implicit(And(y > x, y > -x)) + + When plotting an expression with a single variable (y - 1, for example), + specify the x or the y variable explicitly: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> p8 = plot_implicit(y - 1, y_var=y) + >>> p9 = plot_implicit(x - 1, x_var=x) + """ + + xyvar = [i for i in (x_var, y_var) if i is not None] + free_symbols = expr.free_symbols + range_symbols = Tuple(*flatten(xyvar)).free_symbols + undeclared = free_symbols - range_symbols + if len(free_symbols & range_symbols) > 2: + raise NotImplementedError("Implicit plotting is not implemented for " + "more than 2 variables") + + #Create default ranges if the range is not provided. + default_range = Tuple(-5, 5) + def _range_tuple(s): + if isinstance(s, Symbol): + return Tuple(s) + default_range + if len(s) == 3: + return Tuple(*s) + raise ValueError('symbol or `(symbol, min, max)` expected but got %s' % s) + + if len(xyvar) == 0: + xyvar = list(_sort_gens(free_symbols)) + var_start_end_x = _range_tuple(xyvar[0]) + x = var_start_end_x[0] + if len(xyvar) != 2: + if x in undeclared or not undeclared: + xyvar.append(Dummy('f(%s)' % x.name)) + else: + xyvar.append(undeclared.pop()) + var_start_end_y = _range_tuple(xyvar[1]) + + kwargs = _set_discretization_points(kwargs, ImplicitSeries) + series_argument = ImplicitSeries( + expr, var_start_end_x, var_start_end_y, + adaptive=adaptive, depth=depth, + n=n, line_color=line_color) + + #set the x and y limits + kwargs['xlim'] = tuple(float(x) for x in var_start_end_x[1:]) + kwargs['ylim'] = tuple(float(y) for y in var_start_end_y[1:]) + # set the x and y labels + kwargs.setdefault('xlabel', var_start_end_x[0]) + kwargs.setdefault('ylabel', var_start_end_y[0]) + p = plot_factory(series_argument, **kwargs) + if show: + p.show() + return p diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plotgrid.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plotgrid.py new file mode 100644 index 0000000000000000000000000000000000000000..8ff811c591e762275df1a0e3a221d05920d1804e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/plotgrid.py @@ -0,0 +1,188 @@ + +from sympy.external import import_module +import sympy.plotting.backends.base_backend as base_backend + + +# N.B. +# When changing the minimum module version for matplotlib, please change +# the same in the `SymPyDocTestFinder`` in `sympy/testing/runtests.py` + + +__doctest_requires__ = { + ("PlotGrid",): ["matplotlib"], +} + + +class PlotGrid: + """This class helps to plot subplots from already created SymPy plots + in a single figure. + + Examples + ======== + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> from sympy import symbols + >>> from sympy.plotting import plot, plot3d, PlotGrid + >>> x, y = symbols('x, y') + >>> p1 = plot(x, x**2, x**3, (x, -5, 5)) + >>> p2 = plot((x**2, (x, -6, 6)), (x, (x, -5, 5))) + >>> p3 = plot(x**3, (x, -5, 5)) + >>> p4 = plot3d(x*y, (x, -5, 5), (y, -5, 5)) + + Plotting vertically in a single line: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> PlotGrid(2, 1, p1, p2) + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: x for x over (-5.0, 5.0) + [1]: cartesian line: x**2 for x over (-5.0, 5.0) + [2]: cartesian line: x**3 for x over (-5.0, 5.0) + Plot[1]:Plot object containing: + [0]: cartesian line: x**2 for x over (-6.0, 6.0) + [1]: cartesian line: x for x over (-5.0, 5.0) + + Plotting horizontally in a single line: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> PlotGrid(1, 3, p2, p3, p4) + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: x**2 for x over (-6.0, 6.0) + [1]: cartesian line: x for x over (-5.0, 5.0) + Plot[1]:Plot object containing: + [0]: cartesian line: x**3 for x over (-5.0, 5.0) + Plot[2]:Plot object containing: + [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) + + Plotting in a grid form: + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> PlotGrid(2, 2, p1, p2, p3, p4) + PlotGrid object containing: + Plot[0]:Plot object containing: + [0]: cartesian line: x for x over (-5.0, 5.0) + [1]: cartesian line: x**2 for x over (-5.0, 5.0) + [2]: cartesian line: x**3 for x over (-5.0, 5.0) + Plot[1]:Plot object containing: + [0]: cartesian line: x**2 for x over (-6.0, 6.0) + [1]: cartesian line: x for x over (-5.0, 5.0) + Plot[2]:Plot object containing: + [0]: cartesian line: x**3 for x over (-5.0, 5.0) + Plot[3]:Plot object containing: + [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) + + """ + def __init__(self, nrows, ncolumns, *args, show=True, size=None, **kwargs): + """ + Parameters + ========== + + nrows : + The number of rows that should be in the grid of the + required subplot. + ncolumns : + The number of columns that should be in the grid + of the required subplot. + + nrows and ncolumns together define the required grid. + + Arguments + ========= + + A list of predefined plot objects entered in a row-wise sequence + i.e. plot objects which are to be in the top row of the required + grid are written first, then the second row objects and so on + + Keyword arguments + ================= + + show : Boolean + The default value is set to ``True``. Set show to ``False`` and + the function will not display the subplot. The returned instance + of the ``PlotGrid`` class can then be used to save or display the + plot by calling the ``save()`` and ``show()`` methods + respectively. + size : (float, float), optional + A tuple in the form (width, height) in inches to specify the size of + the overall figure. The default value is set to ``None``, meaning + the size will be set by the default backend. + """ + self.matplotlib = import_module('matplotlib', + import_kwargs={'fromlist': ['pyplot', 'cm', 'collections']}, + min_module_version='1.1.0', catch=(RuntimeError,)) + self.nrows = nrows + self.ncolumns = ncolumns + self._series = [] + self._fig = None + self.args = args + for arg in args: + self._series.append(arg._series) + self.size = size + if show and self.matplotlib: + self.show() + + def _create_figure(self): + gs = self.matplotlib.gridspec.GridSpec(self.nrows, self.ncolumns) + mapping = {} + c = 0 + for i in range(self.nrows): + for j in range(self.ncolumns): + if c < len(self.args): + mapping[gs[i, j]] = self.args[c] + c += 1 + + kw = {} if not self.size else {"figsize": self.size} + self._fig = self.matplotlib.pyplot.figure(**kw) + for spec, p in mapping.items(): + kw = ({"projection": "3d"} if (len(p._series) > 0 and + p._series[0].is_3D) else {}) + cur_ax = self._fig.add_subplot(spec, **kw) + p._plotgrid_fig = self._fig + p._plotgrid_ax = cur_ax + p.process_series() + + @property + def fig(self): + if not self._fig: + self._create_figure() + return self._fig + + @property + def _backend(self): + return self + + def close(self): + self.matplotlib.pyplot.close(self.fig) + + def show(self): + if base_backend._show: + self.fig.tight_layout() + self.matplotlib.pyplot.show() + else: + self.close() + + def save(self, path): + self.fig.savefig(path) + + def __str__(self): + plot_strs = [('Plot[%d]:' % i) + str(plot) + for i, plot in enumerate(self.args)] + + return 'PlotGrid object containing:\n' + '\n'.join(plot_strs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/series.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/series.py new file mode 100644 index 0000000000000000000000000000000000000000..ddd64116277668389fb8defc8289543667d2c9e8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/series.py @@ -0,0 +1,2591 @@ +### The base class for all series +from collections.abc import Callable +from sympy.calculus.util import continuous_domain +from sympy.concrete import Sum, Product +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import arity +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Symbol +from sympy.functions import atan2, zeta, frac, ceiling, floor, im +from sympy.core.relational import (Equality, GreaterThan, + LessThan, Relational, Ne) +from sympy.core.sympify import sympify +from sympy.external import import_module +from sympy.logic.boolalg import BooleanFunction +from sympy.plotting.utils import _get_free_symbols, extract_solution +from sympy.printing.latex import latex +from sympy.printing.pycode import PythonCodePrinter +from sympy.printing.precedence import precedence +from sympy.sets.sets import Set, Interval, Union +from sympy.simplify.simplify import nsimplify +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.lambdify import lambdify +from .intervalmath import interval +import warnings + + +class IntervalMathPrinter(PythonCodePrinter): + """A printer to be used inside `plot_implicit` when `adaptive=True`, + in which case the interval arithmetic module is going to be used, which + requires the following edits. + """ + def _print_And(self, expr): + PREC = precedence(expr) + return " & ".join(self.parenthesize(a, PREC) + for a in sorted(expr.args, key=default_sort_key)) + + def _print_Or(self, expr): + PREC = precedence(expr) + return " | ".join(self.parenthesize(a, PREC) + for a in sorted(expr.args, key=default_sort_key)) + + +def _uniform_eval(f1, f2, *args, modules=None, + force_real_eval=False, has_sum=False): + """ + Note: this is an experimental function, as such it is prone to changes. + Please, do not use it in your code. + """ + np = import_module('numpy') + + def wrapper_func(func, *args): + try: + return complex(func(*args)) + except (ZeroDivisionError, OverflowError): + return complex(np.nan, np.nan) + + # NOTE: np.vectorize is much slower than numpy vectorized operations. + # However, this modules must be able to evaluate functions also with + # mpmath or sympy. + wrapper_func = np.vectorize(wrapper_func, otypes=[complex]) + + def _eval_with_sympy(err=None): + if f2 is None: + msg = "Impossible to evaluate the provided numerical function" + if err is None: + msg += "." + else: + msg += "because the following exception was raised:\n" + "{}: {}".format(type(err).__name__, err) + raise RuntimeError(msg) + if err: + warnings.warn( + "The evaluation with %s failed.\n" % ( + "NumPy/SciPy" if not modules else modules) + + "{}: {}\n".format(type(err).__name__, err) + + "Trying to evaluate the expression with Sympy, but it might " + "be a slow operation." + ) + return wrapper_func(f2, *args) + + if modules == "sympy": + return _eval_with_sympy() + + try: + return wrapper_func(f1, *args) + except Exception as err: + return _eval_with_sympy(err) + + +def _adaptive_eval(f, x): + """Evaluate f(x) with an adaptive algorithm. Post-process the result. + If a symbolic expression is evaluated with SymPy, it might returns + another symbolic expression, containing additions, ... + Force evaluation to a float. + + Parameters + ========== + f : callable + x : float + """ + np = import_module('numpy') + + y = f(x) + if isinstance(y, Expr) and (not y.is_Number): + y = y.evalf() + y = complex(y) + if y.imag > 1e-08: + return np.nan + return y.real + + +def _get_wrapper_for_expr(ret): + wrapper = "%s" + if ret == "real": + wrapper = "re(%s)" + elif ret == "imag": + wrapper = "im(%s)" + elif ret == "abs": + wrapper = "abs(%s)" + elif ret == "arg": + wrapper = "arg(%s)" + return wrapper + + +class BaseSeries: + """Base class for the data objects containing stuff to be plotted. + + Notes + ===== + + The backend should check if it supports the data series that is given. + (e.g. TextBackend supports only LineOver1DRangeSeries). + It is the backend responsibility to know how to use the class of + data series that is given. + + Some data series classes are grouped (using a class attribute like is_2Dline) + according to the api they present (based only on convention). The backend is + not obliged to use that api (e.g. LineOver1DRangeSeries belongs to the + is_2Dline group and presents the get_points method, but the + TextBackend does not use the get_points method). + + BaseSeries + """ + + # Some flags follow. The rationale for using flags instead of checking base + # classes is that setting multiple flags is simpler than multiple + # inheritance. + + is_2Dline = False + # Some of the backends expect: + # - get_points returning 1D np.arrays list_x, list_y + # - get_color_array returning 1D np.array (done in Line2DBaseSeries) + # with the colors calculated at the points from get_points + + is_3Dline = False + # Some of the backends expect: + # - get_points returning 1D np.arrays list_x, list_y, list_y + # - get_color_array returning 1D np.array (done in Line2DBaseSeries) + # with the colors calculated at the points from get_points + + is_3Dsurface = False + # Some of the backends expect: + # - get_meshes returning mesh_x, mesh_y, mesh_z (2D np.arrays) + # - get_points an alias for get_meshes + + is_contour = False + # Some of the backends expect: + # - get_meshes returning mesh_x, mesh_y, mesh_z (2D np.arrays) + # - get_points an alias for get_meshes + + is_implicit = False + # Some of the backends expect: + # - get_meshes returning mesh_x (1D array), mesh_y(1D array, + # mesh_z (2D np.arrays) + # - get_points an alias for get_meshes + # Different from is_contour as the colormap in backend will be + # different + + is_interactive = False + # An interactive series can update its data. + + is_parametric = False + # The calculation of aesthetics expects: + # - get_parameter_points returning one or two np.arrays (1D or 2D) + # used for calculation aesthetics + + is_generic = False + # Represent generic user-provided numerical data + + is_vector = False + is_2Dvector = False + is_3Dvector = False + # Represents a 2D or 3D vector data series + + _N = 100 + # default number of discretization points for uniform sampling. Each + # subclass can set its number. + + def __init__(self, *args, **kwargs): + kwargs = _set_discretization_points(kwargs.copy(), type(self)) + # discretize the domain using only integer numbers + self.only_integers = kwargs.get("only_integers", False) + # represents the evaluation modules to be used by lambdify + self.modules = kwargs.get("modules", None) + # plot functions might create data series that might not be useful to + # be shown on the legend, for example wireframe lines on 3D plots. + self.show_in_legend = kwargs.get("show_in_legend", True) + # line and surface series can show data with a colormap, hence a + # colorbar is essential to understand the data. However, sometime it + # is useful to hide it on series-by-series base. The following keyword + # controls whether the series should show a colorbar or not. + self.colorbar = kwargs.get("colorbar", True) + # Some series might use a colormap as default coloring. Setting this + # attribute to False will inform the backends to use solid color. + self.use_cm = kwargs.get("use_cm", False) + # If True, the backend will attempt to render it on a polar-projection + # axis, or using a polar discretization if a 3D plot is requested + self.is_polar = kwargs.get("is_polar", kwargs.get("polar", False)) + # If True, the rendering will use points, not lines. + self.is_point = kwargs.get("is_point", kwargs.get("point", False)) + # some backend is able to render latex, other needs standard text + self._label = self._latex_label = "" + + self._ranges = [] + self._n = [ + int(kwargs.get("n1", self._N)), + int(kwargs.get("n2", self._N)), + int(kwargs.get("n3", self._N)) + ] + self._scales = [ + kwargs.get("xscale", "linear"), + kwargs.get("yscale", "linear"), + kwargs.get("zscale", "linear") + ] + + # enable interactive widget plots + self._params = kwargs.get("params", {}) + if not isinstance(self._params, dict): + raise TypeError("`params` must be a dictionary mapping symbols " + "to numeric values.") + if len(self._params) > 0: + self.is_interactive = True + + # contains keyword arguments that will be passed to the rendering + # function of the chosen plotting library + self.rendering_kw = kwargs.get("rendering_kw", {}) + + # numerical transformation functions to be applied to the output data: + # x, y, z (coordinates), p (parameter on parametric plots) + self._tx = kwargs.get("tx", None) + self._ty = kwargs.get("ty", None) + self._tz = kwargs.get("tz", None) + self._tp = kwargs.get("tp", None) + if not all(callable(t) or (t is None) for t in + [self._tx, self._ty, self._tz, self._tp]): + raise TypeError("`tx`, `ty`, `tz`, `tp` must be functions.") + + # list of numerical functions representing the expressions to evaluate + self._functions = [] + # signature for the numerical functions + self._signature = [] + # some expressions don't like to be evaluated over complex data. + # if that's the case, set this to True + self._force_real_eval = kwargs.get("force_real_eval", None) + # this attribute will eventually contain a dictionary with the + # discretized ranges + self._discretized_domain = None + # whether the series contains any interactive range, which is a range + # where the minimum and maximum values can be changed with an + # interactive widget + self._interactive_ranges = False + # NOTE: consider a generic summation, for example: + # s = Sum(cos(pi * x), (x, 1, y)) + # This gets lambdified to something: + # sum(cos(pi*x) for x in range(1, y+1)) + # Hence, y needs to be an integer, otherwise it raises: + # TypeError: 'complex' object cannot be interpreted as an integer + # This list will contains symbols that are upper bound to summations + # or products + self._needs_to_be_int = [] + # a color function will be responsible to set the line/surface color + # according to some logic. Each data series will et an appropriate + # default value. + self.color_func = None + # NOTE: color_func usually receives numerical functions that are going + # to be evaluated over the coordinates of the computed points (or the + # discretized meshes). + # However, if an expression is given to color_func, then it will be + # lambdified with symbols in self._signature, and it will be evaluated + # with the same data used to evaluate the plotted expression. + self._eval_color_func_with_signature = False + + def _block_lambda_functions(self, *exprs): + """Some data series can be used to plot numerical functions, others + cannot. Execute this method inside the `__init__` to prevent the + processing of numerical functions. + """ + if any(callable(e) for e in exprs): + raise TypeError(type(self).__name__ + " requires a symbolic " + "expression.") + + def _check_fs(self): + """ Checks if there are enough parameters and free symbols. + """ + exprs, ranges = self.expr, self.ranges + params, label = self.params, self.label + exprs = exprs if hasattr(exprs, "__iter__") else [exprs] + if any(callable(e) for e in exprs): + return + + # from the expression's free symbols, remove the ones used in + # the parameters and the ranges + fs = _get_free_symbols(exprs) + fs = fs.difference(params.keys()) + if ranges is not None: + fs = fs.difference([r[0] for r in ranges]) + + if len(fs) > 0: + raise ValueError( + "Incompatible expression and parameters.\n" + + "Expression: {}\n".format( + (exprs, ranges, label) if ranges is not None else (exprs, label)) + + "params: {}\n".format(params) + + "Specify what these symbols represent: {}\n".format(fs) + + "Are they ranges or parameters?" + ) + + # verify that all symbols are known (they either represent plotting + # ranges or parameters) + range_symbols = [r[0] for r in ranges] + for r in ranges: + fs = set().union(*[e.free_symbols for e in r[1:]]) + if any(t in fs for t in range_symbols): + # ranges can't depend on each other, for example this are + # not allowed: + # (x, 0, y), (y, 0, 3) + # (x, 0, y), (y, x + 2, 3) + raise ValueError("Range symbols can't be included into " + "minimum and maximum of a range. " + "Received range: %s" % str(r)) + if len(fs) > 0: + self._interactive_ranges = True + remaining_fs = fs.difference(params.keys()) + if len(remaining_fs) > 0: + raise ValueError( + "Unknown symbols found in plotting range: %s. " % (r,) + + "Are the following parameters? %s" % remaining_fs) + + def _create_lambda_func(self): + """Create the lambda functions to be used by the uniform meshing + strategy. + + Notes + ===== + The old sympy.plotting used experimental_lambdify. It created one + lambda function each time an evaluation was requested. If that failed, + it went on to create a different lambda function and evaluated it, + and so on. + + This new module changes strategy: it creates right away the default + lambda function as well as the backup one. The reason is that the + series could be interactive, hence the numerical function will be + evaluated multiple times. So, let's create the functions just once. + + This approach works fine for the majority of cases, in which the + symbolic expression is relatively short, hence the lambdification + is fast. If the expression is very long, this approach takes twice + the time to create the lambda functions. Be aware of that! + """ + exprs = self.expr if hasattr(self.expr, "__iter__") else [self.expr] + if not any(callable(e) for e in exprs): + fs = _get_free_symbols(exprs) + self._signature = sorted(fs, key=lambda t: t.name) + + # Generate a list of lambda functions, two for each expression: + # 1. the default one. + # 2. the backup one, in case of failures with the default one. + self._functions = [] + for e in exprs: + # TODO: set cse=True once this issue is solved: + # https://github.com/sympy/sympy/issues/24246 + self._functions.append([ + lambdify(self._signature, e, modules=self.modules), + lambdify(self._signature, e, modules="sympy", dummify=True), + ]) + else: + self._signature = sorted([r[0] for r in self.ranges], key=lambda t: t.name) + self._functions = [(e, None) for e in exprs] + + # deal with symbolic color_func + if isinstance(self.color_func, Expr): + self.color_func = lambdify(self._signature, self.color_func) + self._eval_color_func_with_signature = True + + def _update_range_value(self, t): + """If the value of a plotting range is a symbolic expression, + substitute the parameters in order to get a numerical value. + """ + if not self._interactive_ranges: + return complex(t) + return complex(t.subs(self.params)) + + def _create_discretized_domain(self): + """Discretize the ranges for uniform meshing strategy. + """ + # NOTE: the goal is to create a dictionary stored in + # self._discretized_domain, mapping symbols to a numpy array + # representing the discretization + discr_symbols = [] + discretizations = [] + + # create a 1D discretization + for i, r in enumerate(self.ranges): + discr_symbols.append(r[0]) + c_start = self._update_range_value(r[1]) + c_end = self._update_range_value(r[2]) + start = c_start.real if c_start.imag == c_end.imag == 0 else c_start + end = c_end.real if c_start.imag == c_end.imag == 0 else c_end + needs_integer_discr = self.only_integers or (r[0] in self._needs_to_be_int) + d = BaseSeries._discretize(start, end, self.n[i], + scale=self.scales[i], + only_integers=needs_integer_discr) + + if ((not self._force_real_eval) and (not needs_integer_discr) and + (d.dtype != "complex")): + d = d + 1j * c_start.imag + + if needs_integer_discr: + d = d.astype(int) + + discretizations.append(d) + + # create 2D or 3D + self._create_discretized_domain_helper(discr_symbols, discretizations) + + def _create_discretized_domain_helper(self, discr_symbols, discretizations): + """Create 2D or 3D discretized grids. + + Subclasses should override this method in order to implement a + different behaviour. + """ + np = import_module('numpy') + + # discretization suitable for 2D line plots, 3D surface plots, + # contours plots, vector plots + # NOTE: why indexing='ij'? Because it produces consistent results with + # np.mgrid. This is important as Mayavi requires this indexing + # to correctly compute 3D streamlines. While VTK is able to compute + # streamlines regardless of the indexing, with indexing='xy' it + # produces "strange" results with "voids" into the + # discretization volume. indexing='ij' solves the problem. + # Also note that matplotlib 2D streamlines requires indexing='xy'. + indexing = "xy" + if self.is_3Dvector or (self.is_3Dsurface and self.is_implicit): + indexing = "ij" + meshes = np.meshgrid(*discretizations, indexing=indexing) + self._discretized_domain = dict(zip(discr_symbols, meshes)) + + def _evaluate(self, cast_to_real=True): + """Evaluation of the symbolic expression (or expressions) with the + uniform meshing strategy, based on current values of the parameters. + """ + np = import_module('numpy') + + # create lambda functions + if not self._functions: + self._create_lambda_func() + # create (or update) the discretized domain + if (not self._discretized_domain) or self._interactive_ranges: + self._create_discretized_domain() + # ensure that discretized domains are returned with the proper order + discr = [self._discretized_domain[s[0]] for s in self.ranges] + + args = self._aggregate_args() + + results = [] + for f in self._functions: + r = _uniform_eval(*f, *args) + # the evaluation might produce an int/float. Need this correction. + r = self._correct_shape(np.array(r), discr[0]) + # sometime the evaluation is performed over arrays of type object. + # hence, `result` might be of type object, which don't work well + # with numpy real and imag functions. + r = r.astype(complex) + results.append(r) + + if cast_to_real: + discr = [np.real(d.astype(complex)) for d in discr] + return [*discr, *results] + + def _aggregate_args(self): + """Create a list of arguments to be passed to the lambda function, + sorted according to self._signature. + """ + args = [] + for s in self._signature: + if s in self._params.keys(): + args.append( + int(self._params[s]) if s in self._needs_to_be_int else + self._params[s] if self._force_real_eval + else complex(self._params[s])) + else: + args.append(self._discretized_domain[s]) + return args + + @property + def expr(self): + """Return the expression (or expressions) of the series.""" + return self._expr + + @expr.setter + def expr(self, e): + """Set the expression (or expressions) of the series.""" + is_iter = hasattr(e, "__iter__") + is_callable = callable(e) if not is_iter else any(callable(t) for t in e) + if is_callable: + self._expr = e + else: + self._expr = sympify(e) if not is_iter else Tuple(*e) + + # look for the upper bound of summations and products + s = set() + for e in self._expr.atoms(Sum, Product): + for a in e.args[1:]: + if isinstance(a[-1], Symbol): + s.add(a[-1]) + self._needs_to_be_int = list(s) + + # list of sympy functions that when lambdified, the corresponding + # numpy functions don't like complex-type arguments + pf = [ceiling, floor, atan2, frac, zeta] + if self._force_real_eval is not True: + check_res = [self._expr.has(f) for f in pf] + self._force_real_eval = any(check_res) + if self._force_real_eval and ((self.modules is None) or + (isinstance(self.modules, str) and "numpy" in self.modules)): + funcs = [f for f, c in zip(pf, check_res) if c] + warnings.warn("NumPy is unable to evaluate with complex " + "numbers some of the functions included in this " + "symbolic expression: %s. " % funcs + + "Hence, the evaluation will use real numbers. " + "If you believe the resulting plot is incorrect, " + "change the evaluation module by setting the " + "`modules` keyword argument.") + if self._functions: + # update lambda functions + self._create_lambda_func() + + @property + def is_3D(self): + flags3D = [self.is_3Dline, self.is_3Dsurface, self.is_3Dvector] + return any(flags3D) + + @property + def is_line(self): + flagslines = [self.is_2Dline, self.is_3Dline] + return any(flagslines) + + def _line_surface_color(self, prop, val): + """This method enables back-compatibility with old sympy.plotting""" + # NOTE: color_func is set inside the init method of the series. + # If line_color/surface_color is not a callable, then color_func will + # be set to None. + setattr(self, prop, val) + if callable(val) or isinstance(val, Expr): + self.color_func = val + setattr(self, prop, None) + elif val is not None: + self.color_func = None + + @property + def line_color(self): + return self._line_color + + @line_color.setter + def line_color(self, val): + self._line_surface_color("_line_color", val) + + @property + def n(self): + """Returns a list [n1, n2, n3] of numbers of discratization points. + """ + return self._n + + @n.setter + def n(self, v): + """Set the numbers of discretization points. ``v`` must be an int or + a list. + + Let ``s`` be a series. Then: + + * to set the number of discretization points along the x direction (or + first parameter): ``s.n = 10`` + * to set the number of discretization points along the x and y + directions (or first and second parameters): ``s.n = [10, 15]`` + * to set the number of discretization points along the x, y and z + directions: ``s.n = [10, 15, 20]`` + + The following is highly unreccomended, because it prevents + the execution of necessary code in order to keep updated data: + ``s.n[1] = 15`` + """ + if not hasattr(v, "__iter__"): + self._n[0] = v + else: + self._n[:len(v)] = v + if self._discretized_domain: + # update the discretized domain + self._create_discretized_domain() + + @property + def params(self): + """Get or set the current parameters dictionary. + + Parameters + ========== + + p : dict + + * key: symbol associated to the parameter + * val: the numeric value + """ + return self._params + + @params.setter + def params(self, p): + self._params = p + + def _post_init(self): + exprs = self.expr if hasattr(self.expr, "__iter__") else [self.expr] + if any(callable(e) for e in exprs) and self.params: + raise TypeError("`params` was provided, hence an interactive plot " + "is expected. However, interactive plots do not support " + "user-provided numerical functions.") + + # if the expressions is a lambda function and no label has been + # provided, then its better to do the following in order to avoid + # surprises on the backend + if any(callable(e) for e in exprs): + if self._label == str(self.expr): + self.label = "" + + self._check_fs() + + if hasattr(self, "adaptive") and self.adaptive and self.params: + warnings.warn("`params` was provided, hence an interactive plot " + "is expected. However, interactive plots do not support " + "adaptive evaluation. Automatically switched to " + "adaptive=False.") + self.adaptive = False + + @property + def scales(self): + return self._scales + + @scales.setter + def scales(self, v): + if isinstance(v, str): + self._scales[0] = v + else: + self._scales[:len(v)] = v + + @property + def surface_color(self): + return self._surface_color + + @surface_color.setter + def surface_color(self, val): + self._line_surface_color("_surface_color", val) + + @property + def rendering_kw(self): + return self._rendering_kw + + @rendering_kw.setter + def rendering_kw(self, kwargs): + if isinstance(kwargs, dict): + self._rendering_kw = kwargs + else: + self._rendering_kw = {} + if kwargs is not None: + warnings.warn( + "`rendering_kw` must be a dictionary, instead an " + "object of type %s was received. " % type(kwargs) + + "Automatically setting `rendering_kw` to an empty " + "dictionary") + + @staticmethod + def _discretize(start, end, N, scale="linear", only_integers=False): + """Discretize a 1D domain. + + Returns + ======= + + domain : np.ndarray with dtype=float or complex + The domain's dtype will be float or complex (depending on the + type of start/end) even if only_integers=True. It is left for + the downstream code to perform further casting, if necessary. + """ + np = import_module('numpy') + + if only_integers is True: + start, end = int(start), int(end) + N = end - start + 1 + + if scale == "linear": + return np.linspace(start, end, N) + return np.geomspace(start, end, N) + + @staticmethod + def _correct_shape(a, b): + """Convert ``a`` to a np.ndarray of the same shape of ``b``. + + Parameters + ========== + + a : int, float, complex, np.ndarray + Usually, this is the result of a numerical evaluation of a + symbolic expression. Even if a discretized domain was used to + evaluate the function, the result can be a scalar (int, float, + complex). Think for example to ``expr = Float(2)`` and + ``f = lambdify(x, expr)``. No matter the shape of the numerical + array representing x, the result of the evaluation will be + a single value. + + b : np.ndarray + It represents the correct shape that ``a`` should have. + + Returns + ======= + new_a : np.ndarray + An array with the correct shape. + """ + np = import_module('numpy') + + if not isinstance(a, np.ndarray): + a = np.array(a) + if a.shape != b.shape: + if a.shape == (): + a = a * np.ones_like(b) + else: + a = a.reshape(b.shape) + return a + + def eval_color_func(self, *args): + """Evaluate the color function. + + Parameters + ========== + + args : tuple + Arguments to be passed to the coloring function. Can be coordinates + or parameters or both. + + Notes + ===== + + The backend will request the data series to generate the numerical + data. Depending on the data series, either the data series itself or + the backend will eventually execute this function to generate the + appropriate coloring value. + """ + np = import_module('numpy') + if self.color_func is None: + # NOTE: with the line_color and surface_color attributes + # (back-compatibility with the old sympy.plotting module) it is + # possible to create a plot with a callable line_color (or + # surface_color). For example: + # p = plot(sin(x), line_color=lambda x, y: -y) + # This creates a ColoredLineOver1DRangeSeries with line_color=None + # and color_func=lambda x, y: -y, which effectively is a + # parametric series. Later we could change it to a string value: + # p[0].line_color = "red" + # However, this sets ine_color="red" and color_func=None, but the + # series is still ColoredLineOver1DRangeSeries (a parametric + # series), which will render using a color_func... + warnings.warn("This is likely not the result you were " + "looking for. Please, re-execute the plot command, this time " + "with the appropriate an appropriate value to line_color " + "or surface_color.") + return np.ones_like(args[0]) + + if self._eval_color_func_with_signature: + args = self._aggregate_args() + color = self.color_func(*args) + _re, _im = np.real(color), np.imag(color) + _re[np.invert(np.isclose(_im, np.zeros_like(_im)))] = np.nan + return _re + + nargs = arity(self.color_func) + if nargs == 1: + if self.is_2Dline and self.is_parametric: + if len(args) == 2: + # ColoredLineOver1DRangeSeries + return self._correct_shape(self.color_func(args[0]), args[0]) + # Parametric2DLineSeries + return self._correct_shape(self.color_func(args[2]), args[2]) + elif self.is_3Dline and self.is_parametric: + return self._correct_shape(self.color_func(args[3]), args[3]) + elif self.is_3Dsurface and self.is_parametric: + return self._correct_shape(self.color_func(args[3]), args[3]) + return self._correct_shape(self.color_func(args[0]), args[0]) + elif nargs == 2: + if self.is_3Dsurface and self.is_parametric: + return self._correct_shape(self.color_func(*args[3:]), args[3]) + return self._correct_shape(self.color_func(*args[:2]), args[0]) + return self._correct_shape(self.color_func(*args[:nargs]), args[0]) + + def get_data(self): + """Compute and returns the numerical data. + + The number of parameters returned by this method depends on the + specific instance. If ``s`` is the series, make sure to read + ``help(s.get_data)`` to understand what it returns. + """ + raise NotImplementedError + + def _get_wrapped_label(self, label, wrapper): + """Given a latex representation of an expression, wrap it inside + some characters. Matplotlib needs "$%s%$", K3D-Jupyter needs "%s". + """ + return wrapper % label + + def get_label(self, use_latex=False, wrapper="$%s$"): + """Return the label to be used to display the expression. + + Parameters + ========== + use_latex : bool + If False, the string representation of the expression is returned. + If True, the latex representation is returned. + wrapper : str + The backend might need the latex representation to be wrapped by + some characters. Default to ``"$%s$"``. + + Returns + ======= + label : str + """ + if use_latex is False: + return self._label + if self._label == str(self.expr): + # when the backend requests a latex label and user didn't provide + # any label + return self._get_wrapped_label(self._latex_label, wrapper) + return self._latex_label + + @property + def label(self): + return self.get_label() + + @label.setter + def label(self, val): + """Set the labels associated to this series.""" + # NOTE: the init method of any series requires a label. If the user do + # not provide it, the preprocessing function will set label=None, which + # informs the series to initialize two attributes: + # _label contains the string representation of the expression. + # _latex_label contains the latex representation of the expression. + self._label = self._latex_label = val + + @property + def ranges(self): + return self._ranges + + @ranges.setter + def ranges(self, val): + new_vals = [] + for v in val: + if v is not None: + new_vals.append(tuple([sympify(t) for t in v])) + self._ranges = new_vals + + def _apply_transform(self, *args): + """Apply transformations to the results of numerical evaluation. + + Parameters + ========== + args : tuple + Results of numerical evaluation. + + Returns + ======= + transformed_args : tuple + Tuple containing the transformed results. + """ + t = lambda x, transform: x if transform is None else transform(x) + x, y, z = None, None, None + if len(args) == 2: + x, y = args + return t(x, self._tx), t(y, self._ty) + elif (len(args) == 3) and isinstance(self, Parametric2DLineSeries): + x, y, u = args + return (t(x, self._tx), t(y, self._ty), t(u, self._tp)) + elif len(args) == 3: + x, y, z = args + return t(x, self._tx), t(y, self._ty), t(z, self._tz) + elif (len(args) == 4) and isinstance(self, Parametric3DLineSeries): + x, y, z, u = args + return (t(x, self._tx), t(y, self._ty), t(z, self._tz), t(u, self._tp)) + elif len(args) == 4: # 2D vector plot + x, y, u, v = args + return ( + t(x, self._tx), t(y, self._ty), + t(u, self._tx), t(v, self._ty) + ) + elif (len(args) == 5) and isinstance(self, ParametricSurfaceSeries): + x, y, z, u, v = args + return (t(x, self._tx), t(y, self._ty), t(z, self._tz), u, v) + elif (len(args) == 6) and self.is_3Dvector: # 3D vector plot + x, y, z, u, v, w = args + return ( + t(x, self._tx), t(y, self._ty), t(z, self._tz), + t(u, self._tx), t(v, self._ty), t(w, self._tz) + ) + elif len(args) == 6: # complex plot + x, y, _abs, _arg, img, colors = args + return ( + x, y, t(_abs, self._tz), _arg, img, colors) + return args + + def _str_helper(self, s): + pre, post = "", "" + if self.is_interactive: + pre = "interactive " + post = " and parameters " + str(tuple(self.params.keys())) + return pre + s + post + + +def _detect_poles_numerical_helper(x, y, eps=0.01, expr=None, symb=None, symbolic=False): + """Compute the steepness of each segment. If it's greater than a + threshold, set the right-point y-value non NaN and record the + corresponding x-location for further processing. + + Returns + ======= + x : np.ndarray + Unchanged x-data. + yy : np.ndarray + Modified y-data with NaN values. + """ + np = import_module('numpy') + + yy = y.copy() + threshold = np.pi / 2 - eps + for i in range(len(x) - 1): + dx = x[i + 1] - x[i] + dy = abs(y[i + 1] - y[i]) + angle = np.arctan(dy / dx) + if abs(angle) >= threshold: + yy[i + 1] = np.nan + + return x, yy + +def _detect_poles_symbolic_helper(expr, symb, start, end): + """Attempts to compute symbolic discontinuities. + + Returns + ======= + pole : list + List of symbolic poles, possibly empty. + """ + poles = [] + interval = Interval(nsimplify(start), nsimplify(end)) + res = continuous_domain(expr, symb, interval) + res = res.simplify() + if res == interval: + pass + elif (isinstance(res, Union) and + all(isinstance(t, Interval) for t in res.args)): + poles = [] + for s in res.args: + if s.left_open: + poles.append(s.left) + if s.right_open: + poles.append(s.right) + poles = list(set(poles)) + else: + raise ValueError( + f"Could not parse the following object: {res} .\n" + "Please, submit this as a bug. Consider also to set " + "`detect_poles=True`." + ) + return poles + + +### 2D lines +class Line2DBaseSeries(BaseSeries): + """A base class for 2D lines. + + - adding the label, steps and only_integers options + - making is_2Dline true + - defining get_segments and get_color_array + """ + + is_2Dline = True + _dim = 2 + _N = 1000 + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.steps = kwargs.get("steps", False) + self.is_point = kwargs.get("is_point", kwargs.get("point", False)) + self.is_filled = kwargs.get("is_filled", kwargs.get("fill", True)) + self.adaptive = kwargs.get("adaptive", False) + self.depth = kwargs.get('depth', 12) + self.use_cm = kwargs.get("use_cm", False) + self.color_func = kwargs.get("color_func", None) + self.line_color = kwargs.get("line_color", None) + self.detect_poles = kwargs.get("detect_poles", False) + self.eps = kwargs.get("eps", 0.01) + self.is_polar = kwargs.get("is_polar", kwargs.get("polar", False)) + self.unwrap = kwargs.get("unwrap", False) + # when detect_poles="symbolic", stores the location of poles so that + # they can be appropriately rendered + self.poles_locations = [] + exclude = kwargs.get("exclude", []) + if isinstance(exclude, Set): + exclude = list(extract_solution(exclude, n=100)) + if not hasattr(exclude, "__iter__"): + exclude = [exclude] + exclude = [float(e) for e in exclude] + self.exclude = sorted(exclude) + + def get_data(self): + """Return coordinates for plotting the line. + + Returns + ======= + + x: np.ndarray + x-coordinates + + y: np.ndarray + y-coordinates + + z: np.ndarray (optional) + z-coordinates in case of Parametric3DLineSeries, + Parametric3DLineInteractiveSeries + + param : np.ndarray (optional) + The parameter in case of Parametric2DLineSeries, + Parametric3DLineSeries or AbsArgLineSeries (and their + corresponding interactive series). + """ + np = import_module('numpy') + points = self._get_data_helper() + + if (isinstance(self, LineOver1DRangeSeries) and + (self.detect_poles == "symbolic")): + poles = _detect_poles_symbolic_helper( + self.expr.subs(self.params), *self.ranges[0]) + poles = np.array([float(t) for t in poles]) + t = lambda x, transform: x if transform is None else transform(x) + self.poles_locations = t(np.array(poles), self._tx) + + # postprocessing + points = self._apply_transform(*points) + + if self.is_2Dline and self.detect_poles: + if len(points) == 2: + x, y = points + x, y = _detect_poles_numerical_helper( + x, y, self.eps) + points = (x, y) + else: + x, y, p = points + x, y = _detect_poles_numerical_helper(x, y, self.eps) + points = (x, y, p) + + if self.unwrap: + kw = {} + if self.unwrap is not True: + kw = self.unwrap + if self.is_2Dline: + if len(points) == 2: + x, y = points + y = np.unwrap(y, **kw) + points = (x, y) + else: + x, y, p = points + y = np.unwrap(y, **kw) + points = (x, y, p) + + if self.steps is True: + if self.is_2Dline: + x, y = points[0], points[1] + x = np.array((x, x)).T.flatten()[1:] + y = np.array((y, y)).T.flatten()[:-1] + if self.is_parametric: + points = (x, y, points[2]) + else: + points = (x, y) + elif self.is_3Dline: + x = np.repeat(points[0], 3)[2:] + y = np.repeat(points[1], 3)[:-2] + z = np.repeat(points[2], 3)[1:-1] + if len(points) > 3: + points = (x, y, z, points[3]) + else: + points = (x, y, z) + + if len(self.exclude) > 0: + points = self._insert_exclusions(points) + return points + + def get_segments(self): + sympy_deprecation_warning( + """ + The Line2DBaseSeries.get_segments() method is deprecated. + + Instead, use the MatplotlibBackend.get_segments() method, or use + The get_points() or get_data() methods. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-get-segments") + + np = import_module('numpy') + points = type(self).get_data(self) + points = np.ma.array(points).T.reshape(-1, 1, self._dim) + return np.ma.concatenate([points[:-1], points[1:]], axis=1) + + def _insert_exclusions(self, points): + """Add NaN to each of the exclusion point. Practically, this adds a + NaN to the exclusion point, plus two other nearby points evaluated with + the numerical functions associated to this data series. + These nearby points are important when the number of discretization + points is low, or the scale is logarithm. + + NOTE: it would be easier to just add exclusion points to the + discretized domain before evaluation, then after evaluation add NaN + to the exclusion points. But that's only work with adaptive=False. + The following approach work even with adaptive=True. + """ + np = import_module("numpy") + points = list(points) + n = len(points) + # index of the x-coordinate (for 2d plots) or parameter (for 2d/3d + # parametric plots) + k = n - 1 + if n == 2: + k = 0 + # indices of the other coordinates + j_indeces = sorted(set(range(n)).difference([k])) + # TODO: for now, I assume that numpy functions are going to succeed + funcs = [f[0] for f in self._functions] + + for e in self.exclude: + res = points[k] - e >= 0 + # if res contains both True and False, ie, if e is found + if any(res) and any(~res): + idx = np.nanargmax(res) + # select the previous point with respect to e + idx -= 1 + # TODO: what if points[k][idx]==e or points[k][idx+1]==e? + + if idx > 0 and idx < len(points[k]) - 1: + delta_prev = abs(e - points[k][idx]) + delta_post = abs(e - points[k][idx + 1]) + delta = min(delta_prev, delta_post) / 100 + prev = e - delta + post = e + delta + + # add points to the x-coord or the parameter + points[k] = np.concatenate( + (points[k][:idx], [prev, e, post], points[k][idx+1:])) + + # add points to the other coordinates + c = 0 + for j in j_indeces: + values = funcs[c](np.array([prev, post])) + c += 1 + points[j] = np.concatenate( + (points[j][:idx], [values[0], np.nan, values[1]], points[j][idx+1:])) + return points + + @property + def var(self): + return None if not self.ranges else self.ranges[0][0] + + @property + def start(self): + if not self.ranges: + return None + try: + return self._cast(self.ranges[0][1]) + except TypeError: + return self.ranges[0][1] + + @property + def end(self): + if not self.ranges: + return None + try: + return self._cast(self.ranges[0][2]) + except TypeError: + return self.ranges[0][2] + + @property + def xscale(self): + return self._scales[0] + + @xscale.setter + def xscale(self, v): + self.scales = v + + def get_color_array(self): + np = import_module('numpy') + c = self.line_color + if hasattr(c, '__call__'): + f = np.vectorize(c) + nargs = arity(c) + if nargs == 1 and self.is_parametric: + x = self.get_parameter_points() + return f(centers_of_segments(x)) + else: + variables = list(map(centers_of_segments, self.get_points())) + if nargs == 1: + return f(variables[0]) + elif nargs == 2: + return f(*variables[:2]) + else: # only if the line is 3D (otherwise raises an error) + return f(*variables) + else: + return c*np.ones(self.nb_of_points) + + +class List2DSeries(Line2DBaseSeries): + """Representation for a line consisting of list of points.""" + + def __init__(self, list_x, list_y, label="", **kwargs): + super().__init__(**kwargs) + np = import_module('numpy') + if len(list_x) != len(list_y): + raise ValueError( + "The two lists of coordinates must have the same " + "number of elements.\n" + "Received: len(list_x) = {} ".format(len(list_x)) + + "and len(list_y) = {}".format(len(list_y)) + ) + self._block_lambda_functions(list_x, list_y) + check = lambda l: [isinstance(t, Expr) and (not t.is_number) for t in l] + if any(check(list_x) + check(list_y)) or self.params: + if not self.params: + raise ValueError("Some or all elements of the provided lists " + "are symbolic expressions, but the ``params`` dictionary " + "was not provided: those elements can't be evaluated.") + self.list_x = Tuple(*list_x) + self.list_y = Tuple(*list_y) + else: + self.list_x = np.array(list_x, dtype=np.float64) + self.list_y = np.array(list_y, dtype=np.float64) + + self._expr = (self.list_x, self.list_y) + if not any(isinstance(t, np.ndarray) for t in [self.list_x, self.list_y]): + self._check_fs() + self.is_polar = kwargs.get("is_polar", kwargs.get("polar", False)) + self.label = label + self.rendering_kw = kwargs.get("rendering_kw", {}) + if self.use_cm and self.color_func: + self.is_parametric = True + if isinstance(self.color_func, Expr): + raise TypeError( + "%s don't support symbolic " % self.__class__.__name__ + + "expression for `color_func`.") + + def __str__(self): + return "2D list plot" + + def _get_data_helper(self): + """Returns coordinates that needs to be postprocessed.""" + lx, ly = self.list_x, self.list_y + + if not self.is_interactive: + return self._eval_color_func_and_return(lx, ly) + + np = import_module('numpy') + lx = np.array([t.evalf(subs=self.params) for t in lx], dtype=float) + ly = np.array([t.evalf(subs=self.params) for t in ly], dtype=float) + return self._eval_color_func_and_return(lx, ly) + + def _eval_color_func_and_return(self, *data): + if self.use_cm and callable(self.color_func): + return [*data, self.eval_color_func(*data)] + return data + + +class LineOver1DRangeSeries(Line2DBaseSeries): + """Representation for a line consisting of a SymPy expression over a range.""" + + def __init__(self, expr, var_start_end, label="", **kwargs): + super().__init__(**kwargs) + self.expr = expr if callable(expr) else sympify(expr) + self._label = str(self.expr) if label is None else label + self._latex_label = latex(self.expr) if label is None else label + self.ranges = [var_start_end] + self._cast = complex + # for complex-related data series, this determines what data to return + # on the y-axis + self._return = kwargs.get("return", None) + self._post_init() + + if not self._interactive_ranges: + # NOTE: the following check is only possible when the minimum and + # maximum values of a plotting range are numeric + start, end = [complex(t) for t in self.ranges[0][1:]] + if im(start) != im(end): + raise ValueError( + "%s requires the imaginary " % self.__class__.__name__ + + "part of the start and end values of the range " + "to be the same.") + + if self.adaptive and self._return: + warnings.warn("The adaptive algorithm is unable to deal with " + "complex numbers. Automatically switching to uniform meshing.") + self.adaptive = False + + @property + def nb_of_points(self): + return self.n[0] + + @nb_of_points.setter + def nb_of_points(self, v): + self.n = v + + def __str__(self): + def f(t): + if isinstance(t, complex): + if t.imag != 0: + return t + return t.real + return t + pre = "interactive " if self.is_interactive else "" + post = "" + if self.is_interactive: + post = " and parameters " + str(tuple(self.params.keys())) + wrapper = _get_wrapper_for_expr(self._return) + return pre + "cartesian line: %s for %s over %s" % ( + wrapper % self.expr, + str(self.var), + str((f(self.start), f(self.end))), + ) + post + + def get_points(self): + """Return lists of coordinates for plotting. Depending on the + ``adaptive`` option, this function will either use an adaptive algorithm + or it will uniformly sample the expression over the provided range. + + This function is available for back-compatibility purposes. Consider + using ``get_data()`` instead. + + Returns + ======= + x : list + List of x-coordinates + + y : list + List of y-coordinates + """ + return self._get_data_helper() + + def _adaptive_sampling(self): + try: + if callable(self.expr): + f = self.expr + else: + f = lambdify([self.var], self.expr, self.modules) + x, y = self._adaptive_sampling_helper(f) + except Exception as err: + warnings.warn( + "The evaluation with %s failed.\n" % ( + "NumPy/SciPy" if not self.modules else self.modules) + + "{}: {}\n".format(type(err).__name__, err) + + "Trying to evaluate the expression with Sympy, but it might " + "be a slow operation." + ) + f = lambdify([self.var], self.expr, "sympy") + x, y = self._adaptive_sampling_helper(f) + return x, y + + def _adaptive_sampling_helper(self, f): + """The adaptive sampling is done by recursively checking if three + points are almost collinear. If they are not collinear, then more + points are added between those points. + + References + ========== + + .. [1] Adaptive polygonal approximation of parametric curves, + Luiz Henrique de Figueiredo. + """ + np = import_module('numpy') + + x_coords = [] + y_coords = [] + def sample(p, q, depth): + """ Samples recursively if three points are almost collinear. + For depth < 6, points are added irrespective of whether they + satisfy the collinearity condition or not. The maximum depth + allowed is 12. + """ + # Randomly sample to avoid aliasing. + random = 0.45 + np.random.rand() * 0.1 + if self.xscale == 'log': + xnew = 10**(np.log10(p[0]) + random * (np.log10(q[0]) - + np.log10(p[0]))) + else: + xnew = p[0] + random * (q[0] - p[0]) + ynew = _adaptive_eval(f, xnew) + new_point = np.array([xnew, ynew]) + + # Maximum depth + if depth > self.depth: + x_coords.append(q[0]) + y_coords.append(q[1]) + + # Sample to depth of 6 (whether the line is flat or not) + # without using linspace (to avoid aliasing). + elif depth < 6: + sample(p, new_point, depth + 1) + sample(new_point, q, depth + 1) + + # Sample ten points if complex values are encountered + # at both ends. If there is a real value in between, then + # sample those points further. + elif p[1] is None and q[1] is None: + if self.xscale == 'log': + xarray = np.logspace(p[0], q[0], 10) + else: + xarray = np.linspace(p[0], q[0], 10) + yarray = list(map(f, xarray)) + if not all(y is None for y in yarray): + for i in range(len(yarray) - 1): + if not (yarray[i] is None and yarray[i + 1] is None): + sample([xarray[i], yarray[i]], + [xarray[i + 1], yarray[i + 1]], depth + 1) + + # Sample further if one of the end points in None (i.e. a + # complex value) or the three points are not almost collinear. + elif (p[1] is None or q[1] is None or new_point[1] is None + or not flat(p, new_point, q)): + sample(p, new_point, depth + 1) + sample(new_point, q, depth + 1) + else: + x_coords.append(q[0]) + y_coords.append(q[1]) + + f_start = _adaptive_eval(f, self.start.real) + f_end = _adaptive_eval(f, self.end.real) + x_coords.append(self.start.real) + y_coords.append(f_start) + sample(np.array([self.start.real, f_start]), + np.array([self.end.real, f_end]), 0) + + return (x_coords, y_coords) + + def _uniform_sampling(self): + np = import_module('numpy') + + x, result = self._evaluate() + _re, _im = np.real(result), np.imag(result) + _re = self._correct_shape(_re, x) + _im = self._correct_shape(_im, x) + return x, _re, _im + + def _get_data_helper(self): + """Returns coordinates that needs to be postprocessed. + """ + np = import_module('numpy') + if self.adaptive and (not self.only_integers): + x, y = self._adaptive_sampling() + return [np.array(t) for t in [x, y]] + + x, _re, _im = self._uniform_sampling() + + if self._return is None: + # The evaluation could produce complex numbers. Set real elements + # to NaN where there are non-zero imaginary elements + _re[np.invert(np.isclose(_im, np.zeros_like(_im)))] = np.nan + elif self._return == "real": + pass + elif self._return == "imag": + _re = _im + elif self._return == "abs": + _re = np.sqrt(_re**2 + _im**2) + elif self._return == "arg": + _re = np.arctan2(_im, _re) + else: + raise ValueError("`_return` not recognized. " + "Received: %s" % self._return) + + return x, _re + + +class ParametricLineBaseSeries(Line2DBaseSeries): + is_parametric = True + + def _set_parametric_line_label(self, label): + """Logic to set the correct label to be shown on the plot. + If `use_cm=True` there will be a colorbar, so we show the parameter. + If `use_cm=False`, there might be a legend, so we show the expressions. + + Parameters + ========== + label : str + label passed in by the pre-processor or the user + """ + self._label = str(self.var) if label is None else label + self._latex_label = latex(self.var) if label is None else label + if (self.use_cm is False) and (self._label == str(self.var)): + self._label = str(self.expr) + self._latex_label = latex(self.expr) + # if the expressions is a lambda function and use_cm=False and no label + # has been provided, then its better to do the following in order to + # avoid surprises on the backend + if any(callable(e) for e in self.expr) and (not self.use_cm): + if self._label == str(self.expr): + self._label = "" + + def get_label(self, use_latex=False, wrapper="$%s$"): + # parametric lines returns the representation of the parameter to be + # shown on the colorbar if `use_cm=True`, otherwise it returns the + # representation of the expression to be placed on the legend. + if self.use_cm: + if str(self.var) == self._label: + if use_latex: + return self._get_wrapped_label(latex(self.var), wrapper) + return str(self.var) + # here the user has provided a custom label + return self._label + if use_latex: + if self._label != str(self.expr): + return self._latex_label + return self._get_wrapped_label(self._latex_label, wrapper) + return self._label + + def _get_data_helper(self): + """Returns coordinates that needs to be postprocessed. + Depending on the `adaptive` option, this function will either use an + adaptive algorithm or it will uniformly sample the expression over the + provided range. + """ + if self.adaptive: + np = import_module("numpy") + coords = self._adaptive_sampling() + coords = [np.array(t) for t in coords] + else: + coords = self._uniform_sampling() + + if self.is_2Dline and self.is_polar: + # when plot_polar is executed with polar_axis=True + np = import_module('numpy') + x, y, _ = coords + r = np.sqrt(x**2 + y**2) + t = np.arctan2(y, x) + coords = [t, r, coords[-1]] + + if callable(self.color_func): + coords = list(coords) + coords[-1] = self.eval_color_func(*coords) + + return coords + + def _uniform_sampling(self): + """Returns coordinates that needs to be postprocessed.""" + np = import_module('numpy') + + results = self._evaluate() + for i, r in enumerate(results): + _re, _im = np.real(r), np.imag(r) + _re[np.invert(np.isclose(_im, np.zeros_like(_im)))] = np.nan + results[i] = _re + + return [*results[1:], results[0]] + + def get_parameter_points(self): + return self.get_data()[-1] + + def get_points(self): + """ Return lists of coordinates for plotting. Depending on the + ``adaptive`` option, this function will either use an adaptive algorithm + or it will uniformly sample the expression over the provided range. + + This function is available for back-compatibility purposes. Consider + using ``get_data()`` instead. + + Returns + ======= + x : list + List of x-coordinates + y : list + List of y-coordinates + z : list + List of z-coordinates, only for 3D parametric line plot. + """ + return self._get_data_helper()[:-1] + + @property + def nb_of_points(self): + return self.n[0] + + @nb_of_points.setter + def nb_of_points(self, v): + self.n = v + + +class Parametric2DLineSeries(ParametricLineBaseSeries): + """Representation for a line consisting of two parametric SymPy expressions + over a range.""" + + is_2Dline = True + + def __init__(self, expr_x, expr_y, var_start_end, label="", **kwargs): + super().__init__(**kwargs) + self.expr_x = expr_x if callable(expr_x) else sympify(expr_x) + self.expr_y = expr_y if callable(expr_y) else sympify(expr_y) + self.expr = (self.expr_x, self.expr_y) + self.ranges = [var_start_end] + self._cast = float + self.use_cm = kwargs.get("use_cm", True) + self._set_parametric_line_label(label) + self._post_init() + + def __str__(self): + return self._str_helper( + "parametric cartesian line: (%s, %s) for %s over %s" % ( + str(self.expr_x), + str(self.expr_y), + str(self.var), + str((self.start, self.end)) + )) + + def _adaptive_sampling(self): + try: + if callable(self.expr_x) and callable(self.expr_y): + f_x = self.expr_x + f_y = self.expr_y + else: + f_x = lambdify([self.var], self.expr_x) + f_y = lambdify([self.var], self.expr_y) + x, y, p = self._adaptive_sampling_helper(f_x, f_y) + except Exception as err: + warnings.warn( + "The evaluation with %s failed.\n" % ( + "NumPy/SciPy" if not self.modules else self.modules) + + "{}: {}\n".format(type(err).__name__, err) + + "Trying to evaluate the expression with Sympy, but it might " + "be a slow operation." + ) + f_x = lambdify([self.var], self.expr_x, "sympy") + f_y = lambdify([self.var], self.expr_y, "sympy") + x, y, p = self._adaptive_sampling_helper(f_x, f_y) + return x, y, p + + def _adaptive_sampling_helper(self, f_x, f_y): + """The adaptive sampling is done by recursively checking if three + points are almost collinear. If they are not collinear, then more + points are added between those points. + + References + ========== + + .. [1] Adaptive polygonal approximation of parametric curves, + Luiz Henrique de Figueiredo. + """ + x_coords = [] + y_coords = [] + param = [] + + def sample(param_p, param_q, p, q, depth): + """ Samples recursively if three points are almost collinear. + For depth < 6, points are added irrespective of whether they + satisfy the collinearity condition or not. The maximum depth + allowed is 12. + """ + # Randomly sample to avoid aliasing. + np = import_module('numpy') + random = 0.45 + np.random.rand() * 0.1 + param_new = param_p + random * (param_q - param_p) + xnew = _adaptive_eval(f_x, param_new) + ynew = _adaptive_eval(f_y, param_new) + new_point = np.array([xnew, ynew]) + + # Maximum depth + if depth > self.depth: + x_coords.append(q[0]) + y_coords.append(q[1]) + param.append(param_p) + + # Sample irrespective of whether the line is flat till the + # depth of 6. We are not using linspace to avoid aliasing. + elif depth < 6: + sample(param_p, param_new, p, new_point, depth + 1) + sample(param_new, param_q, new_point, q, depth + 1) + + # Sample ten points if complex values are encountered + # at both ends. If there is a real value in between, then + # sample those points further. + elif ((p[0] is None and q[1] is None) or + (p[1] is None and q[1] is None)): + param_array = np.linspace(param_p, param_q, 10) + x_array = [_adaptive_eval(f_x, t) for t in param_array] + y_array = [_adaptive_eval(f_y, t) for t in param_array] + if not all(x is None and y is None + for x, y in zip(x_array, y_array)): + for i in range(len(y_array) - 1): + if ((x_array[i] is not None and y_array[i] is not None) or + (x_array[i + 1] is not None and y_array[i + 1] is not None)): + point_a = [x_array[i], y_array[i]] + point_b = [x_array[i + 1], y_array[i + 1]] + sample(param_array[i], param_array[i], point_a, + point_b, depth + 1) + + # Sample further if one of the end points in None (i.e. a complex + # value) or the three points are not almost collinear. + elif (p[0] is None or p[1] is None + or q[1] is None or q[0] is None + or not flat(p, new_point, q)): + sample(param_p, param_new, p, new_point, depth + 1) + sample(param_new, param_q, new_point, q, depth + 1) + else: + x_coords.append(q[0]) + y_coords.append(q[1]) + param.append(param_p) + + f_start_x = _adaptive_eval(f_x, self.start) + f_start_y = _adaptive_eval(f_y, self.start) + start = [f_start_x, f_start_y] + f_end_x = _adaptive_eval(f_x, self.end) + f_end_y = _adaptive_eval(f_y, self.end) + end = [f_end_x, f_end_y] + x_coords.append(f_start_x) + y_coords.append(f_start_y) + param.append(self.start) + sample(self.start, self.end, start, end, 0) + + return x_coords, y_coords, param + + +### 3D lines +class Line3DBaseSeries(Line2DBaseSeries): + """A base class for 3D lines. + + Most of the stuff is derived from Line2DBaseSeries.""" + + is_2Dline = False + is_3Dline = True + _dim = 3 + + def __init__(self): + super().__init__() + + +class Parametric3DLineSeries(ParametricLineBaseSeries): + """Representation for a 3D line consisting of three parametric SymPy + expressions and a range.""" + + is_2Dline = False + is_3Dline = True + + def __init__(self, expr_x, expr_y, expr_z, var_start_end, label="", **kwargs): + super().__init__(**kwargs) + self.expr_x = expr_x if callable(expr_x) else sympify(expr_x) + self.expr_y = expr_y if callable(expr_y) else sympify(expr_y) + self.expr_z = expr_z if callable(expr_z) else sympify(expr_z) + self.expr = (self.expr_x, self.expr_y, self.expr_z) + self.ranges = [var_start_end] + self._cast = float + self.adaptive = False + self.use_cm = kwargs.get("use_cm", True) + self._set_parametric_line_label(label) + self._post_init() + # TODO: remove this + self._xlim = None + self._ylim = None + self._zlim = None + + def __str__(self): + return self._str_helper( + "3D parametric cartesian line: (%s, %s, %s) for %s over %s" % ( + str(self.expr_x), + str(self.expr_y), + str(self.expr_z), + str(self.var), + str((self.start, self.end)) + )) + + def get_data(self): + # TODO: remove this + np = import_module("numpy") + x, y, z, p = super().get_data() + self._xlim = (np.amin(x), np.amax(x)) + self._ylim = (np.amin(y), np.amax(y)) + self._zlim = (np.amin(z), np.amax(z)) + return x, y, z, p + + +### Surfaces +class SurfaceBaseSeries(BaseSeries): + """A base class for 3D surfaces.""" + + is_3Dsurface = True + + def __init__(self, *args, **kwargs): + super().__init__(**kwargs) + self.use_cm = kwargs.get("use_cm", False) + # NOTE: why should SurfaceOver2DRangeSeries support is polar? + # After all, the same result can be achieve with + # ParametricSurfaceSeries. For example: + # sin(r) for (r, 0, 2 * pi) and (theta, 0, pi/2) can be parameterized + # as (r * cos(theta), r * sin(theta), sin(t)) for (r, 0, 2 * pi) and + # (theta, 0, pi/2). + # Because it is faster to evaluate (important for interactive plots). + self.is_polar = kwargs.get("is_polar", kwargs.get("polar", False)) + self.surface_color = kwargs.get("surface_color", None) + self.color_func = kwargs.get("color_func", lambda x, y, z: z) + if callable(self.surface_color): + self.color_func = self.surface_color + self.surface_color = None + + def _set_surface_label(self, label): + exprs = self.expr + self._label = str(exprs) if label is None else label + self._latex_label = latex(exprs) if label is None else label + # if the expressions is a lambda function and no label + # has been provided, then its better to do the following to avoid + # surprises on the backend + is_lambda = (callable(exprs) if not hasattr(exprs, "__iter__") + else any(callable(e) for e in exprs)) + if is_lambda and (self._label == str(exprs)): + self._label = "" + self._latex_label = "" + + def get_color_array(self): + np = import_module('numpy') + c = self.surface_color + if isinstance(c, Callable): + f = np.vectorize(c) + nargs = arity(c) + if self.is_parametric: + variables = list(map(centers_of_faces, self.get_parameter_meshes())) + if nargs == 1: + return f(variables[0]) + elif nargs == 2: + return f(*variables) + variables = list(map(centers_of_faces, self.get_meshes())) + if nargs == 1: + return f(variables[0]) + elif nargs == 2: + return f(*variables[:2]) + else: + return f(*variables) + else: + if isinstance(self, SurfaceOver2DRangeSeries): + return c*np.ones(min(self.nb_of_points_x, self.nb_of_points_y)) + else: + return c*np.ones(min(self.nb_of_points_u, self.nb_of_points_v)) + + +class SurfaceOver2DRangeSeries(SurfaceBaseSeries): + """Representation for a 3D surface consisting of a SymPy expression and 2D + range.""" + + def __init__(self, expr, var_start_end_x, var_start_end_y, label="", **kwargs): + super().__init__(**kwargs) + self.expr = expr if callable(expr) else sympify(expr) + self.ranges = [var_start_end_x, var_start_end_y] + self._set_surface_label(label) + self._post_init() + # TODO: remove this + self._xlim = (self.start_x, self.end_x) + self._ylim = (self.start_y, self.end_y) + + @property + def var_x(self): + return self.ranges[0][0] + + @property + def var_y(self): + return self.ranges[1][0] + + @property + def start_x(self): + try: + return float(self.ranges[0][1]) + except TypeError: + return self.ranges[0][1] + + @property + def end_x(self): + try: + return float(self.ranges[0][2]) + except TypeError: + return self.ranges[0][2] + + @property + def start_y(self): + try: + return float(self.ranges[1][1]) + except TypeError: + return self.ranges[1][1] + + @property + def end_y(self): + try: + return float(self.ranges[1][2]) + except TypeError: + return self.ranges[1][2] + + @property + def nb_of_points_x(self): + return self.n[0] + + @nb_of_points_x.setter + def nb_of_points_x(self, v): + n = self.n + self.n = [v, n[1:]] + + @property + def nb_of_points_y(self): + return self.n[1] + + @nb_of_points_y.setter + def nb_of_points_y(self, v): + n = self.n + self.n = [n[0], v, n[2]] + + def __str__(self): + series_type = "cartesian surface" if self.is_3Dsurface else "contour" + return self._str_helper( + series_type + ": %s for" " %s over %s and %s over %s" % ( + str(self.expr), + str(self.var_x), str((self.start_x, self.end_x)), + str(self.var_y), str((self.start_y, self.end_y)), + )) + + def get_meshes(self): + """Return the x,y,z coordinates for plotting the surface. + This function is available for back-compatibility purposes. Consider + using ``get_data()`` instead. + """ + return self.get_data() + + def get_data(self): + """Return arrays of coordinates for plotting. + + Returns + ======= + mesh_x : np.ndarray + Discretized x-domain. + mesh_y : np.ndarray + Discretized y-domain. + mesh_z : np.ndarray + Results of the evaluation. + """ + np = import_module('numpy') + + results = self._evaluate() + # mask out complex values + for i, r in enumerate(results): + _re, _im = np.real(r), np.imag(r) + _re[np.invert(np.isclose(_im, np.zeros_like(_im)))] = np.nan + results[i] = _re + + x, y, z = results + if self.is_polar and self.is_3Dsurface: + r = x.copy() + x = r * np.cos(y) + y = r * np.sin(y) + + # TODO: remove this + self._zlim = (np.amin(z), np.amax(z)) + + return self._apply_transform(x, y, z) + + +class ParametricSurfaceSeries(SurfaceBaseSeries): + """Representation for a 3D surface consisting of three parametric SymPy + expressions and a range.""" + + is_parametric = True + + def __init__(self, expr_x, expr_y, expr_z, + var_start_end_u, var_start_end_v, label="", **kwargs): + super().__init__(**kwargs) + self.expr_x = expr_x if callable(expr_x) else sympify(expr_x) + self.expr_y = expr_y if callable(expr_y) else sympify(expr_y) + self.expr_z = expr_z if callable(expr_z) else sympify(expr_z) + self.expr = (self.expr_x, self.expr_y, self.expr_z) + self.ranges = [var_start_end_u, var_start_end_v] + self.color_func = kwargs.get("color_func", lambda x, y, z, u, v: z) + self._set_surface_label(label) + self._post_init() + + @property + def var_u(self): + return self.ranges[0][0] + + @property + def var_v(self): + return self.ranges[1][0] + + @property + def start_u(self): + try: + return float(self.ranges[0][1]) + except TypeError: + return self.ranges[0][1] + + @property + def end_u(self): + try: + return float(self.ranges[0][2]) + except TypeError: + return self.ranges[0][2] + + @property + def start_v(self): + try: + return float(self.ranges[1][1]) + except TypeError: + return self.ranges[1][1] + + @property + def end_v(self): + try: + return float(self.ranges[1][2]) + except TypeError: + return self.ranges[1][2] + + @property + def nb_of_points_u(self): + return self.n[0] + + @nb_of_points_u.setter + def nb_of_points_u(self, v): + n = self.n + self.n = [v, n[1:]] + + @property + def nb_of_points_v(self): + return self.n[1] + + @nb_of_points_v.setter + def nb_of_points_v(self, v): + n = self.n + self.n = [n[0], v, n[2]] + + def __str__(self): + return self._str_helper( + "parametric cartesian surface: (%s, %s, %s) for" + " %s over %s and %s over %s" % ( + str(self.expr_x), str(self.expr_y), str(self.expr_z), + str(self.var_u), str((self.start_u, self.end_u)), + str(self.var_v), str((self.start_v, self.end_v)), + )) + + def get_parameter_meshes(self): + return self.get_data()[3:] + + def get_meshes(self): + """Return the x,y,z coordinates for plotting the surface. + This function is available for back-compatibility purposes. Consider + using ``get_data()`` instead. + """ + return self.get_data()[:3] + + def get_data(self): + """Return arrays of coordinates for plotting. + + Returns + ======= + x : np.ndarray [n2 x n1] + x-coordinates. + y : np.ndarray [n2 x n1] + y-coordinates. + z : np.ndarray [n2 x n1] + z-coordinates. + mesh_u : np.ndarray [n2 x n1] + Discretized u range. + mesh_v : np.ndarray [n2 x n1] + Discretized v range. + """ + np = import_module('numpy') + + results = self._evaluate() + # mask out complex values + for i, r in enumerate(results): + _re, _im = np.real(r), np.imag(r) + _re[np.invert(np.isclose(_im, np.zeros_like(_im)))] = np.nan + results[i] = _re + + # TODO: remove this + x, y, z = results[2:] + self._xlim = (np.amin(x), np.amax(x)) + self._ylim = (np.amin(y), np.amax(y)) + self._zlim = (np.amin(z), np.amax(z)) + + return self._apply_transform(*results[2:], *results[:2]) + + +### Contours +class ContourSeries(SurfaceOver2DRangeSeries): + """Representation for a contour plot.""" + + is_3Dsurface = False + is_contour = True + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.is_filled = kwargs.get("is_filled", kwargs.get("fill", True)) + self.show_clabels = kwargs.get("clabels", True) + + # NOTE: contour plots are used by plot_contour, plot_vector and + # plot_complex_vector. By implementing contour_kw we are able to + # quickly target the contour plot. + self.rendering_kw = kwargs.get("contour_kw", + kwargs.get("rendering_kw", {})) + + +class GenericDataSeries(BaseSeries): + """Represents generic numerical data. + + Notes + ===== + This class serves the purpose of back-compatibility with the "markers, + annotations, fill, rectangles" keyword arguments that represent + user-provided numerical data. In particular, it solves the problem of + combining together two or more plot-objects with the ``extend`` or + ``append`` methods: user-provided numerical data is also taken into + consideration because it is stored in this series class. + + Also note that the current implementation is far from optimal, as each + keyword argument is stored into an attribute in the ``Plot`` class, which + requires a hard-coded if-statement in the ``MatplotlibBackend`` class. + The implementation suggests that it is ok to add attributes and + if-statements to provide more and more functionalities for user-provided + numerical data (e.g. adding horizontal lines, or vertical lines, or bar + plots, etc). However, in doing so one would reinvent the wheel: plotting + libraries (like Matplotlib) already implements the necessary API. + + Instead of adding more keyword arguments and attributes, users interested + in adding custom numerical data to a plot should retrieve the figure + created by this plotting module. For example, this code: + + .. plot:: + :context: close-figs + :include-source: True + + from sympy import Symbol, plot, cos + x = Symbol("x") + p = plot(cos(x), markers=[{"args": [[0, 1, 2], [0, 1, -1], "*"]}]) + + Becomes: + + .. plot:: + :context: close-figs + :include-source: True + + p = plot(cos(x), backend="matplotlib") + fig, ax = p._backend.fig, p._backend.ax + ax.plot([0, 1, 2], [0, 1, -1], "*") + fig + + Which is far better in terms of readability. Also, it gives access to the + full plotting library capabilities, without the need to reinvent the wheel. + """ + is_generic = True + + def __init__(self, tp, *args, **kwargs): + self.type = tp + self.args = args + self.rendering_kw = kwargs + + def get_data(self): + return self.args + + +class ImplicitSeries(BaseSeries): + """Representation for 2D Implicit plot.""" + + is_implicit = True + use_cm = False + _N = 100 + + def __init__(self, expr, var_start_end_x, var_start_end_y, label="", **kwargs): + super().__init__(**kwargs) + self.adaptive = kwargs.get("adaptive", False) + self.expr = expr + self._label = str(expr) if label is None else label + self._latex_label = latex(expr) if label is None else label + self.ranges = [var_start_end_x, var_start_end_y] + self.var_x, self.start_x, self.end_x = self.ranges[0] + self.var_y, self.start_y, self.end_y = self.ranges[1] + self._color = kwargs.get("color", kwargs.get("line_color", None)) + + if self.is_interactive and self.adaptive: + raise NotImplementedError("Interactive plot with `adaptive=True` " + "is not supported.") + + # Check whether the depth is greater than 4 or less than 0. + depth = kwargs.get("depth", 0) + if depth > 4: + depth = 4 + elif depth < 0: + depth = 0 + self.depth = 4 + depth + self._post_init() + + @property + def expr(self): + if self.adaptive: + return self._adaptive_expr + return self._non_adaptive_expr + + @expr.setter + def expr(self, expr): + self._block_lambda_functions(expr) + # these are needed for adaptive evaluation + expr, has_equality = self._has_equality(sympify(expr)) + self._adaptive_expr = expr + self.has_equality = has_equality + self._label = str(expr) + self._latex_label = latex(expr) + + if isinstance(expr, (BooleanFunction, Ne)) and (not self.adaptive): + self.adaptive = True + msg = "contains Boolean functions. " + if isinstance(expr, Ne): + msg = "is an unequality. " + warnings.warn( + "The provided expression " + msg + + "In order to plot the expression, the algorithm " + + "automatically switched to an adaptive sampling." + ) + + if isinstance(expr, BooleanFunction): + self._non_adaptive_expr = None + self._is_equality = False + else: + # these are needed for uniform meshing evaluation + expr, is_equality = self._preprocess_meshgrid_expression(expr, self.adaptive) + self._non_adaptive_expr = expr + self._is_equality = is_equality + + @property + def line_color(self): + return self._color + + @line_color.setter + def line_color(self, v): + self._color = v + + color = line_color + + def _has_equality(self, expr): + # Represents whether the expression contains an Equality, GreaterThan + # or LessThan + has_equality = False + + def arg_expand(bool_expr): + """Recursively expands the arguments of an Boolean Function""" + for arg in bool_expr.args: + if isinstance(arg, BooleanFunction): + arg_expand(arg) + elif isinstance(arg, Relational): + arg_list.append(arg) + + arg_list = [] + if isinstance(expr, BooleanFunction): + arg_expand(expr) + # Check whether there is an equality in the expression provided. + if any(isinstance(e, (Equality, GreaterThan, LessThan)) for e in arg_list): + has_equality = True + elif not isinstance(expr, Relational): + expr = Equality(expr, 0) + has_equality = True + elif isinstance(expr, (Equality, GreaterThan, LessThan)): + has_equality = True + + return expr, has_equality + + def __str__(self): + f = lambda t: float(t) if len(t.free_symbols) == 0 else t + + return self._str_helper( + "Implicit expression: %s for %s over %s and %s over %s") % ( + str(self._adaptive_expr), + str(self.var_x), + str((f(self.start_x), f(self.end_x))), + str(self.var_y), + str((f(self.start_y), f(self.end_y))), + ) + + def get_data(self): + """Returns numerical data. + + Returns + ======= + + If the series is evaluated with the `adaptive=True` it returns: + + interval_list : list + List of bounding rectangular intervals to be postprocessed and + eventually used with Matplotlib's ``fill`` command. + dummy : str + A string containing ``"fill"``. + + Otherwise, it returns 2D numpy arrays to be used with Matplotlib's + ``contour`` or ``contourf`` commands: + + x_array : np.ndarray + y_array : np.ndarray + z_array : np.ndarray + plot_type : str + A string specifying which plot command to use, ``"contour"`` + or ``"contourf"``. + """ + if self.adaptive: + data = self._adaptive_eval() + if data is not None: + return data + + return self._get_meshes_grid() + + def _adaptive_eval(self): + """ + References + ========== + + .. [1] Jeffrey Allen Tupper. Reliable Two-Dimensional Graphing Methods for + Mathematical Formulae with Two Free Variables. + + .. [2] Jeffrey Allen Tupper. Graphing Equations with Generalized Interval + Arithmetic. Master's thesis. University of Toronto, 1996 + """ + import sympy.plotting.intervalmath.lib_interval as li + + user_functions = {} + printer = IntervalMathPrinter({ + 'fully_qualified_modules': False, 'inline': True, + 'allow_unknown_functions': True, + 'user_functions': user_functions}) + + keys = [t for t in dir(li) if ("__" not in t) and (t not in ["import_module", "interval"])] + vals = [getattr(li, k) for k in keys] + d = dict(zip(keys, vals)) + func = lambdify((self.var_x, self.var_y), self.expr, modules=[d], printer=printer) + data = None + + try: + data = self._get_raster_interval(func) + except NameError as err: + warnings.warn( + "Adaptive meshing could not be applied to the" + " expression, as some functions are not yet implemented" + " in the interval math module:\n\n" + "NameError: %s\n\n" % err + + "Proceeding with uniform meshing." + ) + self.adaptive = False + except TypeError: + warnings.warn( + "Adaptive meshing could not be applied to the" + " expression. Using uniform meshing.") + self.adaptive = False + + return data + + def _get_raster_interval(self, func): + """Uses interval math to adaptively mesh and obtain the plot""" + np = import_module('numpy') + + k = self.depth + interval_list = [] + sx, sy = [float(t) for t in [self.start_x, self.start_y]] + ex, ey = [float(t) for t in [self.end_x, self.end_y]] + # Create initial 32 divisions + xsample = np.linspace(sx, ex, 33) + ysample = np.linspace(sy, ey, 33) + + # Add a small jitter so that there are no false positives for equality. + # Ex: y==x becomes True for x interval(1, 2) and y interval(1, 2) + # which will draw a rectangle. + jitterx = ( + (np.random.rand(len(xsample)) * 2 - 1) + * (ex - sx) + / 2 ** 20 + ) + jittery = ( + (np.random.rand(len(ysample)) * 2 - 1) + * (ey - sy) + / 2 ** 20 + ) + xsample += jitterx + ysample += jittery + + xinter = [interval(x1, x2) for x1, x2 in zip(xsample[:-1], xsample[1:])] + yinter = [interval(y1, y2) for y1, y2 in zip(ysample[:-1], ysample[1:])] + interval_list = [[x, y] for x in xinter for y in yinter] + plot_list = [] + + # recursive call refinepixels which subdivides the intervals which are + # neither True nor False according to the expression. + def refine_pixels(interval_list): + """Evaluates the intervals and subdivides the interval if the + expression is partially satisfied.""" + temp_interval_list = [] + plot_list = [] + for intervals in interval_list: + + # Convert the array indices to x and y values + intervalx = intervals[0] + intervaly = intervals[1] + func_eval = func(intervalx, intervaly) + # The expression is valid in the interval. Change the contour + # array values to 1. + if func_eval[1] is False or func_eval[0] is False: + pass + elif func_eval == (True, True): + plot_list.append([intervalx, intervaly]) + elif func_eval[1] is None or func_eval[0] is None: + # Subdivide + avgx = intervalx.mid + avgy = intervaly.mid + a = interval(intervalx.start, avgx) + b = interval(avgx, intervalx.end) + c = interval(intervaly.start, avgy) + d = interval(avgy, intervaly.end) + temp_interval_list.append([a, c]) + temp_interval_list.append([a, d]) + temp_interval_list.append([b, c]) + temp_interval_list.append([b, d]) + return temp_interval_list, plot_list + + while k >= 0 and len(interval_list): + interval_list, plot_list_temp = refine_pixels(interval_list) + plot_list.extend(plot_list_temp) + k = k - 1 + # Check whether the expression represents an equality + # If it represents an equality, then none of the intervals + # would have satisfied the expression due to floating point + # differences. Add all the undecided values to the plot. + if self.has_equality: + for intervals in interval_list: + intervalx = intervals[0] + intervaly = intervals[1] + func_eval = func(intervalx, intervaly) + if func_eval[1] and func_eval[0] is not False: + plot_list.append([intervalx, intervaly]) + return plot_list, "fill" + + def _get_meshes_grid(self): + """Generates the mesh for generating a contour. + + In the case of equality, ``contour`` function of matplotlib can + be used. In other cases, matplotlib's ``contourf`` is used. + """ + np = import_module('numpy') + + xarray, yarray, z_grid = self._evaluate() + _re, _im = np.real(z_grid), np.imag(z_grid) + _re[np.invert(np.isclose(_im, np.zeros_like(_im)))] = np.nan + if self._is_equality: + return xarray, yarray, _re, 'contour' + return xarray, yarray, _re, 'contourf' + + @staticmethod + def _preprocess_meshgrid_expression(expr, adaptive): + """If the expression is a Relational, rewrite it as a single + expression. + + Returns + ======= + + expr : Expr + The rewritten expression + + equality : Boolean + Whether the original expression was an Equality or not. + """ + equality = False + if isinstance(expr, Equality): + expr = expr.lhs - expr.rhs + equality = True + elif isinstance(expr, Relational): + expr = expr.gts - expr.lts + elif not adaptive: + raise NotImplementedError( + "The expression is not supported for " + "plotting in uniform meshed plot." + ) + return expr, equality + + def get_label(self, use_latex=False, wrapper="$%s$"): + """Return the label to be used to display the expression. + + Parameters + ========== + use_latex : bool + If False, the string representation of the expression is returned. + If True, the latex representation is returned. + wrapper : str + The backend might need the latex representation to be wrapped by + some characters. Default to ``"$%s$"``. + + Returns + ======= + label : str + """ + if use_latex is False: + return self._label + if self._label == str(self._adaptive_expr): + return self._get_wrapped_label(self._latex_label, wrapper) + return self._latex_label + + +############################################################################## +# Finding the centers of line segments or mesh faces +############################################################################## + +def centers_of_segments(array): + np = import_module('numpy') + return np.mean(np.vstack((array[:-1], array[1:])), 0) + + +def centers_of_faces(array): + np = import_module('numpy') + return np.mean(np.dstack((array[:-1, :-1], + array[1:, :-1], + array[:-1, 1:], + array[:-1, :-1], + )), 2) + + +def flat(x, y, z, eps=1e-3): + """Checks whether three points are almost collinear""" + np = import_module('numpy') + # Workaround plotting piecewise (#8577) + vector_a = (x - y).astype(float) + vector_b = (z - y).astype(float) + dot_product = np.dot(vector_a, vector_b) + vector_a_norm = np.linalg.norm(vector_a) + vector_b_norm = np.linalg.norm(vector_b) + cos_theta = dot_product / (vector_a_norm * vector_b_norm) + return abs(cos_theta + 1) < eps + + +def _set_discretization_points(kwargs, pt): + """Allow the use of the keyword arguments ``n, n1, n2`` to + specify the number of discretization points in one and two + directions, while keeping back-compatibility with older keyword arguments + like, ``nb_of_points, nb_of_points_*, points``. + + Parameters + ========== + + kwargs : dict + Dictionary of keyword arguments passed into a plotting function. + pt : type + The type of the series, which indicates the kind of plot we are + trying to create. + """ + replace_old_keywords = { + "nb_of_points": "n", + "nb_of_points_x": "n1", + "nb_of_points_y": "n2", + "nb_of_points_u": "n1", + "nb_of_points_v": "n2", + "points": "n" + } + for k, v in replace_old_keywords.items(): + if k in kwargs.keys(): + kwargs[v] = kwargs.pop(k) + + if pt in [LineOver1DRangeSeries, Parametric2DLineSeries, + Parametric3DLineSeries]: + if "n" in kwargs.keys(): + kwargs["n1"] = kwargs["n"] + if hasattr(kwargs["n"], "__iter__") and (len(kwargs["n"]) > 0): + kwargs["n1"] = kwargs["n"][0] + elif pt in [SurfaceOver2DRangeSeries, ContourSeries, + ParametricSurfaceSeries, ImplicitSeries]: + if "n" in kwargs.keys(): + if hasattr(kwargs["n"], "__iter__") and (len(kwargs["n"]) > 1): + kwargs["n1"] = kwargs["n"][0] + kwargs["n2"] = kwargs["n"][1] + else: + kwargs["n1"] = kwargs["n2"] = kwargs["n"] + return kwargs diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/textplot.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/textplot.py new file mode 100644 index 0000000000000000000000000000000000000000..5f1f2b639d6c387a6a36cf89fe36bc7717c92b2b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/textplot.py @@ -0,0 +1,168 @@ +from sympy.core.numbers import Float +from sympy.core.symbol import Dummy +from sympy.utilities.lambdify import lambdify + +import math + + +def is_valid(x): + """Check if a floating point number is valid""" + if x is None: + return False + if isinstance(x, complex): + return False + return not math.isinf(x) and not math.isnan(x) + + +def rescale(y, W, H, mi, ma): + """Rescale the given array `y` to fit into the integer values + between `0` and `H-1` for the values between ``mi`` and ``ma``. + """ + y_new = [] + + norm = ma - mi + offset = (ma + mi) / 2 + + for x in range(W): + if is_valid(y[x]): + normalized = (y[x] - offset) / norm + if not is_valid(normalized): + y_new.append(None) + else: + rescaled = Float((normalized*H + H/2) * (H-1)/H).round() + rescaled = int(rescaled) + y_new.append(rescaled) + else: + y_new.append(None) + return y_new + + +def linspace(start, stop, num): + return [start + (stop - start) * x / (num-1) for x in range(num)] + + +def textplot_str(expr, a, b, W=55, H=21): + """Generator for the lines of the plot""" + free = expr.free_symbols + if len(free) > 1: + raise ValueError( + "The expression must have a single variable. (Got {})" + .format(free)) + x = free.pop() if free else Dummy() + f = lambdify([x], expr) + if isinstance(a, complex): + if a.imag == 0: + a = a.real + if isinstance(b, complex): + if b.imag == 0: + b = b.real + a = float(a) + b = float(b) + + # Calculate function values + x = linspace(a, b, W) + y = [] + for val in x: + try: + y.append(f(val)) + # Not sure what exceptions to catch here or why... + except (ValueError, TypeError, ZeroDivisionError): + y.append(None) + + # Normalize height to screen space + y_valid = list(filter(is_valid, y)) + if y_valid: + ma = max(y_valid) + mi = min(y_valid) + if ma == mi: + if ma: + mi, ma = sorted([0, 2*ma]) + else: + mi, ma = -1, 1 + else: + mi, ma = -1, 1 + y_range = ma - mi + precision = math.floor(math.log10(y_range)) - 1 + precision *= -1 + mi = round(mi, precision) + ma = round(ma, precision) + y = rescale(y, W, H, mi, ma) + + y_bins = linspace(mi, ma, H) + + # Draw plot + margin = 7 + for h in range(H - 1, -1, -1): + s = [' '] * W + for i in range(W): + if y[i] == h: + if (i == 0 or y[i - 1] == h - 1) and (i == W - 1 or y[i + 1] == h + 1): + s[i] = '/' + elif (i == 0 or y[i - 1] == h + 1) and (i == W - 1 or y[i + 1] == h - 1): + s[i] = '\\' + else: + s[i] = '.' + + if h == 0: + for i in range(W): + s[i] = '_' + + # Print y values + if h in (0, H//2, H - 1): + prefix = ("%g" % y_bins[h]).rjust(margin)[:margin] + else: + prefix = " "*margin + s = "".join(s) + if h == H//2: + s = s.replace(" ", "-") + yield prefix + " |" + s + + # Print x values + bottom = " " * (margin + 2) + bottom += ("%g" % x[0]).ljust(W//2) + if W % 2 == 1: + bottom += ("%g" % x[W//2]).ljust(W//2) + else: + bottom += ("%g" % x[W//2]).ljust(W//2-1) + bottom += "%g" % x[-1] + yield bottom + + +def textplot(expr, a, b, W=55, H=21): + r""" + Print a crude ASCII art plot of the SymPy expression 'expr' (which + should contain a single symbol, e.g. x or something else) over the + interval [a, b]. + + Examples + ======== + + >>> from sympy import Symbol, sin + >>> from sympy.plotting import textplot + >>> t = Symbol('t') + >>> textplot(sin(t)*t, 0, 15) + 14 | ... + | . + | . + | . + | . + | ... + | / . . + | / + | / . + | . . . + 1.5 |----.......-------------------------------------------- + |.... \ . . + | \ / . + | .. / . + | \ / . + | .... + | . + | . . + | + | . . + -11 |_______________________________________________________ + 0 7.5 15 + """ + for line in textplot_str(expr, a, b, W, H): + print(line) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/utils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..3213dea09b5a98e96094e7dffbd9b992c7d2b87e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/plotting/utils.py @@ -0,0 +1,323 @@ +from sympy.core.containers import Tuple +from sympy.core.basic import Basic +from sympy.core.expr import Expr +from sympy.core.function import AppliedUndef +from sympy.core.relational import Relational +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.logic.boolalg import BooleanFunction +from sympy.sets.fancysets import ImageSet +from sympy.sets.sets import FiniteSet +from sympy.tensor.indexed import Indexed + + +def _get_free_symbols(exprs): + """Returns the free symbols of a symbolic expression. + + If the expression contains any of these elements, assume that they are + the "free symbols" of the expression: + + * indexed objects + * applied undefined function (useful for sympy.physics.mechanics module) + """ + if not isinstance(exprs, (list, tuple, set)): + exprs = [exprs] + if all(callable(e) for e in exprs): + return set() + + free = set().union(*[e.atoms(Indexed) for e in exprs]) + free = free.union(*[e.atoms(AppliedUndef) for e in exprs]) + return free or set().union(*[e.free_symbols for e in exprs]) + + +def extract_solution(set_sol, n=10): + """Extract numerical solutions from a set solution (computed by solveset, + linsolve, nonlinsolve). Often, it is not trivial do get something useful + out of them. + + Parameters + ========== + + n : int, optional + In order to replace ImageSet with FiniteSet, an iterator is created + for each ImageSet contained in `set_sol`, starting from 0 up to `n`. + Default value: 10. + """ + images = set_sol.find(ImageSet) + for im in images: + it = iter(im) + s = FiniteSet(*[next(it) for n in range(0, n)]) + set_sol = set_sol.subs(im, s) + return set_sol + + +def _plot_sympify(args): + """This function recursively loop over the arguments passed to the plot + functions: the sympify function will be applied to all arguments except + those of type string/dict. + + Generally, users can provide the following arguments to a plot function: + + expr, range1 [tuple, opt], ..., label [str, opt], rendering_kw [dict, opt] + + `expr, range1, ...` can be sympified, whereas `label, rendering_kw` can't. + In particular, whenever a special character like $, {, }, ... is used in + the `label`, sympify will raise an error. + """ + if isinstance(args, Expr): + return args + + args = list(args) + for i, a in enumerate(args): + if isinstance(a, (list, tuple)): + args[i] = Tuple(*_plot_sympify(a), sympify=False) + elif not (isinstance(a, (str, dict)) or callable(a) + # NOTE: check if it is a vector from sympy.physics.vector module + # without importing the module (because it slows down SymPy's + # import process and triggers SymPy's optional-dependencies + # tests to fail). + or ((a.__class__.__name__ == "Vector") and not isinstance(a, Basic)) + ): + args[i] = sympify(a) + return args + + +def _create_ranges(exprs, ranges, npar, label="", params=None): + """This function does two things: + + 1. Check if the number of free symbols is in agreement with the type of + plot chosen. For example, plot() requires 1 free symbol; + plot3d() requires 2 free symbols. + 2. Sometime users create plots without providing ranges for the variables. + Here we create the necessary ranges. + + Parameters + ========== + + exprs : iterable + The expressions from which to extract the free symbols + ranges : iterable + The limiting ranges provided by the user + npar : int + The number of free symbols required by the plot functions. + For example, + npar=1 for plot, npar=2 for plot3d, ... + params : dict + A dictionary mapping symbols to parameters for interactive plot. + """ + get_default_range = lambda symbol: Tuple(symbol, -10, 10) + + free_symbols = _get_free_symbols(exprs) + if params is not None: + free_symbols = free_symbols.difference(params.keys()) + + if len(free_symbols) > npar: + raise ValueError( + "Too many free symbols.\n" + + "Expected {} free symbols.\n".format(npar) + + "Received {}: {}".format(len(free_symbols), free_symbols) + ) + + if len(ranges) > npar: + raise ValueError( + "Too many ranges. Received %s, expected %s" % (len(ranges), npar)) + + # free symbols in the ranges provided by the user + rfs = set().union([r[0] for r in ranges]) + if len(rfs) != len(ranges): + raise ValueError("Multiple ranges with the same symbol") + + if len(ranges) < npar: + symbols = free_symbols.difference(rfs) + if symbols != set(): + # add a range for each missing free symbols + for s in symbols: + ranges.append(get_default_range(s)) + # if there is still room, fill them with dummys + for i in range(npar - len(ranges)): + ranges.append(get_default_range(Dummy())) + + if len(free_symbols) == npar: + # there could be times when this condition is not met, for example + # plotting the function f(x, y) = x (which is a plane); in this case, + # free_symbols = {x} whereas rfs = {x, y} (or x and Dummy) + rfs = set().union([r[0] for r in ranges]) + if len(free_symbols.difference(rfs)) > 0: + raise ValueError( + "Incompatible free symbols of the expressions with " + "the ranges.\n" + + "Free symbols in the expressions: {}\n".format(free_symbols) + + "Free symbols in the ranges: {}".format(rfs) + ) + return ranges + + +def _is_range(r): + """A range is defined as (symbol, start, end). start and end should + be numbers. + """ + # TODO: prange check goes here + return ( + isinstance(r, Tuple) + and (len(r) == 3) + and (not isinstance(r.args[1], str)) and r.args[1].is_number + and (not isinstance(r.args[2], str)) and r.args[2].is_number + ) + + +def _unpack_args(*args): + """Given a list/tuple of arguments previously processed by _plot_sympify() + and/or _check_arguments(), separates and returns its components: + expressions, ranges, label and rendering keywords. + + Examples + ======== + + >>> from sympy import cos, sin, symbols + >>> from sympy.plotting.utils import _plot_sympify, _unpack_args + >>> x, y = symbols('x, y') + >>> args = (sin(x), (x, -10, 10), "f1") + >>> args = _plot_sympify(args) + >>> _unpack_args(*args) + ([sin(x)], [(x, -10, 10)], 'f1', None) + + >>> args = (sin(x**2 + y**2), (x, -2, 2), (y, -3, 3), "f2") + >>> args = _plot_sympify(args) + >>> _unpack_args(*args) + ([sin(x**2 + y**2)], [(x, -2, 2), (y, -3, 3)], 'f2', None) + + >>> args = (sin(x + y), cos(x - y), x + y, (x, -2, 2), (y, -3, 3), "f3") + >>> args = _plot_sympify(args) + >>> _unpack_args(*args) + ([sin(x + y), cos(x - y), x + y], [(x, -2, 2), (y, -3, 3)], 'f3', None) + """ + ranges = [t for t in args if _is_range(t)] + labels = [t for t in args if isinstance(t, str)] + label = None if not labels else labels[0] + rendering_kw = [t for t in args if isinstance(t, dict)] + rendering_kw = None if not rendering_kw else rendering_kw[0] + # NOTE: why None? because args might have been preprocessed by + # _check_arguments, so None might represent the rendering_kw + results = [not (_is_range(a) or isinstance(a, (str, dict)) or (a is None)) for a in args] + exprs = [a for a, b in zip(args, results) if b] + return exprs, ranges, label, rendering_kw + + +def _check_arguments(args, nexpr, npar, **kwargs): + """Checks the arguments and converts into tuples of the + form (exprs, ranges, label, rendering_kw). + + Parameters + ========== + + args + The arguments provided to the plot functions + nexpr + The number of sub-expression forming an expression to be plotted. + For example: + nexpr=1 for plot. + nexpr=2 for plot_parametric: a curve is represented by a tuple of two + elements. + nexpr=1 for plot3d. + nexpr=3 for plot3d_parametric_line: a curve is represented by a tuple + of three elements. + npar + The number of free symbols required by the plot functions. For example, + npar=1 for plot, npar=2 for plot3d, ... + **kwargs : + keyword arguments passed to the plotting function. It will be used to + verify if ``params`` has ben provided. + + Examples + ======== + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import cos, sin, symbols + >>> from sympy.plotting.plot import _check_arguments + >>> x = symbols('x') + >>> _check_arguments([cos(x), sin(x)], 2, 1) + [(cos(x), sin(x), (x, -10, 10), None, None)] + + >>> _check_arguments([cos(x), sin(x), "test"], 2, 1) + [(cos(x), sin(x), (x, -10, 10), 'test', None)] + + >>> _check_arguments([cos(x), sin(x), "test", {"a": 0, "b": 1}], 2, 1) + [(cos(x), sin(x), (x, -10, 10), 'test', {'a': 0, 'b': 1})] + + >>> _check_arguments([x, x**2], 1, 1) + [(x, (x, -10, 10), None, None), (x**2, (x, -10, 10), None, None)] + """ + if not args: + return [] + output = [] + params = kwargs.get("params", None) + + if all(isinstance(a, (Expr, Relational, BooleanFunction)) for a in args[:nexpr]): + # In this case, with a single plot command, we are plotting either: + # 1. one expression + # 2. multiple expressions over the same range + + exprs, ranges, label, rendering_kw = _unpack_args(*args) + free_symbols = set().union(*[e.free_symbols for e in exprs]) + ranges = _create_ranges(exprs, ranges, npar, label, params) + + if nexpr > 1: + # in case of plot_parametric or plot3d_parametric_line, there will + # be 2 or 3 expressions defining a curve. Group them together. + if len(exprs) == nexpr: + exprs = (tuple(exprs),) + for expr in exprs: + # need this if-else to deal with both plot/plot3d and + # plot_parametric/plot3d_parametric_line + is_expr = isinstance(expr, (Expr, Relational, BooleanFunction)) + e = (expr,) if is_expr else expr + output.append((*e, *ranges, label, rendering_kw)) + + else: + # In this case, we are plotting multiple expressions, each one with its + # range. Each "expression" to be plotted has the following form: + # (expr, range, label) where label is optional + + _, ranges, labels, rendering_kw = _unpack_args(*args) + labels = [labels] if labels else [] + + # number of expressions + n = (len(ranges) + len(labels) + + (len(rendering_kw) if rendering_kw is not None else 0)) + new_args = args[:-n] if n > 0 else args + + # at this point, new_args might just be [expr]. But I need it to be + # [[expr]] in order to be able to loop over + # [expr, range [opt], label [opt]] + if not isinstance(new_args[0], (list, tuple, Tuple)): + new_args = [new_args] + + # Each arg has the form (expr1, expr2, ..., range1 [optional], ..., + # label [optional], rendering_kw [optional]) + for arg in new_args: + # look for "local" range and label. If there is not, use "global". + l = [a for a in arg if isinstance(a, str)] + if not l: + l = labels + r = [a for a in arg if _is_range(a)] + if not r: + r = ranges.copy() + rend_kw = [a for a in arg if isinstance(a, dict)] + rend_kw = rendering_kw if len(rend_kw) == 0 else rend_kw[0] + + # NOTE: arg = arg[:nexpr] may raise an exception if lambda + # functions are used. Execute the following instead: + arg = [arg[i] for i in range(nexpr)] + free_symbols = set() + if all(not callable(a) for a in arg): + free_symbols = free_symbols.union(*[a.free_symbols for a in arg]) + if len(r) != npar: + r = _create_ranges(arg, r, npar, "", params) + + label = None if not l else l[0] + output.append((*arg, *r, label, rend_kw)) + return output diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8055ed12d213de3ebc7a1f17100607fb1e3b89b8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__init__.py @@ -0,0 +1,130 @@ +"""Polynomial manipulation algorithms and algebraic objects. """ + +__all__ = [ + 'Poly', 'PurePoly', 'poly_from_expr', 'parallel_poly_from_expr', 'degree', + 'total_degree', 'degree_list', 'LC', 'LM', 'LT', 'pdiv', 'prem', 'pquo', + 'pexquo', 'div', 'rem', 'quo', 'exquo', 'half_gcdex', 'gcdex', 'invert', + 'subresultants', 'resultant', 'discriminant', 'cofactors', 'gcd_list', + 'gcd', 'lcm_list', 'lcm', 'terms_gcd', 'trunc', 'monic', 'content', + 'primitive', 'compose', 'decompose', 'sturm', 'gff_list', 'gff', + 'sqf_norm', 'sqf_part', 'sqf_list', 'sqf', 'factor_list', 'factor', + 'intervals', 'refine_root', 'count_roots', 'all_roots', 'real_roots', + 'nroots', 'ground_roots', 'nth_power_roots_poly', 'cancel', 'reduced', + 'groebner', 'is_zero_dimensional', 'GroebnerBasis', 'poly', + + 'symmetrize', 'horner', 'interpolate', 'rational_interpolate', 'viete', + + 'together', + + 'BasePolynomialError', 'ExactQuotientFailed', 'PolynomialDivisionFailed', + 'OperationNotSupported', 'HeuristicGCDFailed', 'HomomorphismFailed', + 'IsomorphismFailed', 'ExtraneousFactors', 'EvaluationFailed', + 'RefinementFailed', 'CoercionFailed', 'NotInvertible', 'NotReversible', + 'NotAlgebraic', 'DomainError', 'PolynomialError', 'UnificationFailed', + 'GeneratorsError', 'GeneratorsNeeded', 'ComputationFailed', + 'UnivariatePolynomialError', 'MultivariatePolynomialError', + 'PolificationFailed', 'OptionError', 'FlagError', + + 'minpoly', 'minimal_polynomial', 'primitive_element', 'field_isomorphism', + 'to_number_field', 'isolate', 'round_two', 'prime_decomp', + 'prime_valuation', 'galois_group', + + 'itermonomials', 'Monomial', + + 'lex', 'grlex', 'grevlex', 'ilex', 'igrlex', 'igrevlex', + + 'CRootOf', 'rootof', 'RootOf', 'ComplexRootOf', 'RootSum', + + 'roots', + + 'Domain', 'FiniteField', 'IntegerRing', 'RationalField', 'RealField', + 'ComplexField', 'PythonFiniteField', 'GMPYFiniteField', + 'PythonIntegerRing', 'GMPYIntegerRing', 'PythonRational', + 'GMPYRationalField', 'AlgebraicField', 'PolynomialRing', 'FractionField', + 'ExpressionDomain', 'FF_python', 'FF_gmpy', 'ZZ_python', 'ZZ_gmpy', + 'QQ_python', 'QQ_gmpy', 'GF', 'FF', 'ZZ', 'QQ', 'ZZ_I', 'QQ_I', 'RR', + 'CC', 'EX', 'EXRAW', + + 'construct_domain', + + 'swinnerton_dyer_poly', 'cyclotomic_poly', 'symmetric_poly', + 'random_poly', 'interpolating_poly', + + 'jacobi_poly', 'chebyshevt_poly', 'chebyshevu_poly', 'hermite_poly', + 'hermite_prob_poly', 'legendre_poly', 'laguerre_poly', + + 'bernoulli_poly', 'bernoulli_c_poly', 'genocchi_poly', 'euler_poly', + 'andre_poly', + + 'apart', 'apart_list', 'assemble_partfrac_list', + + 'Options', + + 'ring', 'xring', 'vring', 'sring', + + 'field', 'xfield', 'vfield', 'sfield' +] + +from .polytools import (Poly, PurePoly, poly_from_expr, + parallel_poly_from_expr, degree, total_degree, degree_list, LC, LM, + LT, pdiv, prem, pquo, pexquo, div, rem, quo, exquo, half_gcdex, gcdex, + invert, subresultants, resultant, discriminant, cofactors, gcd_list, + gcd, lcm_list, lcm, terms_gcd, trunc, monic, content, primitive, + compose, decompose, sturm, gff_list, gff, sqf_norm, sqf_part, + sqf_list, sqf, factor_list, factor, intervals, refine_root, + count_roots, all_roots, real_roots, nroots, ground_roots, + nth_power_roots_poly, cancel, reduced, groebner, is_zero_dimensional, + GroebnerBasis, poly) + +from .polyfuncs import (symmetrize, horner, interpolate, + rational_interpolate, viete) + +from .rationaltools import together + +from .polyerrors import (BasePolynomialError, ExactQuotientFailed, + PolynomialDivisionFailed, OperationNotSupported, HeuristicGCDFailed, + HomomorphismFailed, IsomorphismFailed, ExtraneousFactors, + EvaluationFailed, RefinementFailed, CoercionFailed, NotInvertible, + NotReversible, NotAlgebraic, DomainError, PolynomialError, + UnificationFailed, GeneratorsError, GeneratorsNeeded, + ComputationFailed, UnivariatePolynomialError, + MultivariatePolynomialError, PolificationFailed, OptionError, + FlagError) + +from .numberfields import (minpoly, minimal_polynomial, primitive_element, + field_isomorphism, to_number_field, isolate, round_two, prime_decomp, + prime_valuation, galois_group) + +from .monomials import itermonomials, Monomial + +from .orderings import lex, grlex, grevlex, ilex, igrlex, igrevlex + +from .rootoftools import CRootOf, rootof, RootOf, ComplexRootOf, RootSum + +from .polyroots import roots + +from .domains import (Domain, FiniteField, IntegerRing, RationalField, + RealField, ComplexField, PythonFiniteField, GMPYFiniteField, + PythonIntegerRing, GMPYIntegerRing, PythonRational, GMPYRationalField, + AlgebraicField, PolynomialRing, FractionField, ExpressionDomain, + FF_python, FF_gmpy, ZZ_python, ZZ_gmpy, QQ_python, QQ_gmpy, GF, FF, + ZZ, QQ, ZZ_I, QQ_I, RR, CC, EX, EXRAW) + +from .constructor import construct_domain + +from .specialpolys import (swinnerton_dyer_poly, cyclotomic_poly, + symmetric_poly, random_poly, interpolating_poly) + +from .orthopolys import (jacobi_poly, chebyshevt_poly, chebyshevu_poly, + hermite_poly, hermite_prob_poly, legendre_poly, laguerre_poly) + +from .appellseqs import (bernoulli_poly, bernoulli_c_poly, genocchi_poly, + euler_poly, andre_poly) + +from .partfrac import apart, apart_list, assemble_partfrac_list + +from .polyoptions import Options + +from .rings import ring, xring, vring, sring + +from .fields import field, xfield, vfield, sfield diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/appellseqs.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/appellseqs.py new file mode 100644 index 0000000000000000000000000000000000000000..ac10fe3d1f1e60ccdf46cdae4eb5b8a969500a3e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/appellseqs.py @@ -0,0 +1,269 @@ +r""" +Efficient functions for generating Appell sequences. + +An Appell sequence is a zero-indexed sequence of polynomials `p_i(x)` +satisfying `p_{i+1}'(x)=(i+1)p_i(x)` for all `i`. This definition leads +to the following iterative algorithm: + +.. math :: p_0(x) = c_0,\ p_i(x) = i \int_0^x p_{i-1}(t)\,dt + c_i + +The constant coefficients `c_i` are usually determined from the +just-evaluated integral and `i`. + +Appell sequences satisfy the following identity from umbral calculus: + +.. math :: p_n(x+y) = \sum_{k=0}^n \binom{n}{k} p_k(x) y^{n-k} + +References +========== + +.. [1] https://en.wikipedia.org/wiki/Appell_sequence +.. [2] Peter Luschny, "An introduction to the Bernoulli function", + https://arxiv.org/abs/2009.06743 +""" +from sympy.polys.densearith import dup_mul_ground, dup_sub_ground, dup_quo_ground +from sympy.polys.densetools import dup_eval, dup_integrate +from sympy.polys.domains import ZZ, QQ +from sympy.polys.polytools import named_poly +from sympy.utilities import public + +def dup_bernoulli(n, K): + """Low-level implementation of Bernoulli polynomials.""" + if n < 1: + return [K.one] + p = [K.one, K(-1,2)] + for i in range(2, n+1): + p = dup_integrate(dup_mul_ground(p, K(i), K), 1, K) + if i % 2 == 0: + p = dup_sub_ground(p, dup_eval(p, K(1,2), K) * K(1<<(i-1), (1<>> from sympy import summation + >>> from sympy.abc import x + >>> from sympy.polys import bernoulli_poly + >>> bernoulli_poly(5, x) + x**5 - 5*x**4/2 + 5*x**3/3 - x/6 + + >>> def psum(p, a, b): + ... return (bernoulli_poly(p+1,b+1) - bernoulli_poly(p+1,a)) / (p+1) + >>> psum(4, -6, 27) + 3144337 + >>> summation(x**4, (x, -6, 27)) + 3144337 + + >>> psum(1, 1, x).factor() + x*(x + 1)/2 + >>> psum(2, 1, x).factor() + x*(x + 1)*(2*x + 1)/6 + >>> psum(3, 1, x).factor() + x**2*(x + 1)**2/4 + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + + See Also + ======== + + sympy.functions.combinatorial.numbers.bernoulli + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Bernoulli_polynomials + """ + return named_poly(n, dup_bernoulli, QQ, "Bernoulli polynomial", (x,), polys) + +def dup_bernoulli_c(n, K): + """Low-level implementation of central Bernoulli polynomials.""" + p = [K.one] + for i in range(1, n+1): + p = dup_integrate(dup_mul_ground(p, K(i), K), 1, K) + if i % 2 == 0: + p = dup_sub_ground(p, dup_eval(p, K.one, K) * K((1<<(i-1))-1, (1<>> from sympy import bernoulli, euler, genocchi + >>> from sympy.abc import x + >>> from sympy.polys import andre_poly + >>> andre_poly(9, x) + x**9 - 36*x**7 + 630*x**5 - 5124*x**3 + 12465*x + + >>> [andre_poly(n, 0) for n in range(11)] + [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0, -50521] + >>> [euler(n) for n in range(11)] + [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0, -50521] + >>> [andre_poly(n-1, 1) * n / (4**n - 2**n) for n in range(1, 11)] + [1/2, 1/6, 0, -1/30, 0, 1/42, 0, -1/30, 0, 5/66] + >>> [bernoulli(n) for n in range(1, 11)] + [1/2, 1/6, 0, -1/30, 0, 1/42, 0, -1/30, 0, 5/66] + >>> [-andre_poly(n-1, -1) * n / (-2)**(n-1) for n in range(1, 11)] + [-1, -1, 0, 1, 0, -3, 0, 17, 0, -155] + >>> [genocchi(n) for n in range(1, 11)] + [-1, -1, 0, 1, 0, -3, 0, 17, 0, -155] + + >>> [abs(andre_poly(n, n%2)) for n in range(11)] + [1, 1, 1, 2, 5, 16, 61, 272, 1385, 7936, 50521] + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + + See Also + ======== + + sympy.functions.combinatorial.numbers.andre + + References + ========== + + .. [1] Peter Luschny, "An introduction to the Bernoulli function", + https://arxiv.org/abs/2009.06743 + """ + return named_poly(n, dup_andre, ZZ, "Andre polynomial", (x,), polys) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/compatibility.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/compatibility.py new file mode 100644 index 0000000000000000000000000000000000000000..eb239d282a738d1e5611a2249d313ff1d3b7671c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/compatibility.py @@ -0,0 +1,1152 @@ +"""Compatibility interface between dense and sparse polys. """ + +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from sympy.core.expr import Expr + from sympy.polys.domains.domain import Domain + from sympy.polys.orderings import MonomialOrder + from sympy.polys.rings import PolyElement + +from sympy.polys.densearith import dup_add_term +from sympy.polys.densearith import dmp_add_term +from sympy.polys.densearith import dup_sub_term +from sympy.polys.densearith import dmp_sub_term +from sympy.polys.densearith import dup_mul_term +from sympy.polys.densearith import dmp_mul_term +from sympy.polys.densearith import dup_add_ground +from sympy.polys.densearith import dmp_add_ground +from sympy.polys.densearith import dup_sub_ground +from sympy.polys.densearith import dmp_sub_ground +from sympy.polys.densearith import dup_mul_ground +from sympy.polys.densearith import dmp_mul_ground +from sympy.polys.densearith import dup_quo_ground +from sympy.polys.densearith import dmp_quo_ground +from sympy.polys.densearith import dup_exquo_ground +from sympy.polys.densearith import dmp_exquo_ground +from sympy.polys.densearith import dup_lshift +from sympy.polys.densearith import dup_rshift +from sympy.polys.densearith import dup_abs +from sympy.polys.densearith import dmp_abs +from sympy.polys.densearith import dup_neg +from sympy.polys.densearith import dmp_neg +from sympy.polys.densearith import dup_add +from sympy.polys.densearith import dmp_add +from sympy.polys.densearith import dup_sub +from sympy.polys.densearith import dmp_sub +from sympy.polys.densearith import dup_add_mul +from sympy.polys.densearith import dmp_add_mul +from sympy.polys.densearith import dup_sub_mul +from sympy.polys.densearith import dmp_sub_mul +from sympy.polys.densearith import dup_mul +from sympy.polys.densearith import dmp_mul +from sympy.polys.densearith import dup_sqr +from sympy.polys.densearith import dmp_sqr +from sympy.polys.densearith import dup_pow +from sympy.polys.densearith import dmp_pow +from sympy.polys.densearith import dup_pdiv +from sympy.polys.densearith import dup_prem +from sympy.polys.densearith import dup_pquo +from sympy.polys.densearith import dup_pexquo +from sympy.polys.densearith import dmp_pdiv +from sympy.polys.densearith import dmp_prem +from sympy.polys.densearith import dmp_pquo +from sympy.polys.densearith import dmp_pexquo +from sympy.polys.densearith import dup_rr_div +from sympy.polys.densearith import dmp_rr_div +from sympy.polys.densearith import dup_ff_div +from sympy.polys.densearith import dmp_ff_div +from sympy.polys.densearith import dup_div +from sympy.polys.densearith import dup_rem +from sympy.polys.densearith import dup_quo +from sympy.polys.densearith import dup_exquo +from sympy.polys.densearith import dmp_div +from sympy.polys.densearith import dmp_rem +from sympy.polys.densearith import dmp_quo +from sympy.polys.densearith import dmp_exquo +from sympy.polys.densearith import dup_max_norm +from sympy.polys.densearith import dmp_max_norm +from sympy.polys.densearith import dup_l1_norm +from sympy.polys.densearith import dmp_l1_norm +from sympy.polys.densearith import dup_l2_norm_squared +from sympy.polys.densearith import dmp_l2_norm_squared +from sympy.polys.densearith import dup_expand +from sympy.polys.densearith import dmp_expand +from sympy.polys.densebasic import dup_LC +from sympy.polys.densebasic import dmp_LC +from sympy.polys.densebasic import dup_TC +from sympy.polys.densebasic import dmp_TC +from sympy.polys.densebasic import dmp_ground_LC +from sympy.polys.densebasic import dmp_ground_TC +from sympy.polys.densebasic import dup_degree +from sympy.polys.densebasic import dmp_degree +from sympy.polys.densebasic import dmp_degree_in +from sympy.polys.densebasic import dmp_to_dict +from sympy.polys.densetools import dup_integrate +from sympy.polys.densetools import dmp_integrate +from sympy.polys.densetools import dmp_integrate_in +from sympy.polys.densetools import dup_diff +from sympy.polys.densetools import dmp_diff +from sympy.polys.densetools import dmp_diff_in +from sympy.polys.densetools import dup_eval +from sympy.polys.densetools import dmp_eval +from sympy.polys.densetools import dmp_eval_in +from sympy.polys.densetools import dmp_eval_tail +from sympy.polys.densetools import dmp_diff_eval_in +from sympy.polys.densetools import dup_trunc +from sympy.polys.densetools import dmp_trunc +from sympy.polys.densetools import dmp_ground_trunc +from sympy.polys.densetools import dup_monic +from sympy.polys.densetools import dmp_ground_monic +from sympy.polys.densetools import dup_content +from sympy.polys.densetools import dmp_ground_content +from sympy.polys.densetools import dup_primitive +from sympy.polys.densetools import dmp_ground_primitive +from sympy.polys.densetools import dup_extract +from sympy.polys.densetools import dmp_ground_extract +from sympy.polys.densetools import dup_real_imag +from sympy.polys.densetools import dup_mirror +from sympy.polys.densetools import dup_scale +from sympy.polys.densetools import dup_shift +from sympy.polys.densetools import dmp_shift +from sympy.polys.densetools import dup_transform +from sympy.polys.densetools import dup_compose +from sympy.polys.densetools import dmp_compose +from sympy.polys.densetools import dup_decompose +from sympy.polys.densetools import dmp_lift +from sympy.polys.densetools import dup_sign_variations +from sympy.polys.densetools import dup_clear_denoms +from sympy.polys.densetools import dmp_clear_denoms +from sympy.polys.densetools import dup_revert +from sympy.polys.euclidtools import dup_half_gcdex +from sympy.polys.euclidtools import dmp_half_gcdex +from sympy.polys.euclidtools import dup_gcdex +from sympy.polys.euclidtools import dmp_gcdex +from sympy.polys.euclidtools import dup_invert +from sympy.polys.euclidtools import dmp_invert +from sympy.polys.euclidtools import dup_euclidean_prs +from sympy.polys.euclidtools import dmp_euclidean_prs +from sympy.polys.euclidtools import dup_primitive_prs +from sympy.polys.euclidtools import dmp_primitive_prs +from sympy.polys.euclidtools import dup_inner_subresultants +from sympy.polys.euclidtools import dup_subresultants +from sympy.polys.euclidtools import dup_prs_resultant +from sympy.polys.euclidtools import dup_resultant +from sympy.polys.euclidtools import dmp_inner_subresultants +from sympy.polys.euclidtools import dmp_subresultants +from sympy.polys.euclidtools import dmp_prs_resultant +from sympy.polys.euclidtools import dmp_zz_modular_resultant +from sympy.polys.euclidtools import dmp_zz_collins_resultant +from sympy.polys.euclidtools import dmp_qq_collins_resultant +from sympy.polys.euclidtools import dmp_resultant +from sympy.polys.euclidtools import dup_discriminant +from sympy.polys.euclidtools import dmp_discriminant +from sympy.polys.euclidtools import dup_rr_prs_gcd +from sympy.polys.euclidtools import dup_ff_prs_gcd +from sympy.polys.euclidtools import dmp_rr_prs_gcd +from sympy.polys.euclidtools import dmp_ff_prs_gcd +from sympy.polys.euclidtools import dup_zz_heu_gcd +from sympy.polys.euclidtools import dmp_zz_heu_gcd +from sympy.polys.euclidtools import dup_qq_heu_gcd +from sympy.polys.euclidtools import dmp_qq_heu_gcd +from sympy.polys.euclidtools import dup_inner_gcd +from sympy.polys.euclidtools import dmp_inner_gcd +from sympy.polys.euclidtools import dup_gcd +from sympy.polys.euclidtools import dmp_gcd +from sympy.polys.euclidtools import dup_rr_lcm +from sympy.polys.euclidtools import dup_ff_lcm +from sympy.polys.euclidtools import dup_lcm +from sympy.polys.euclidtools import dmp_rr_lcm +from sympy.polys.euclidtools import dmp_ff_lcm +from sympy.polys.euclidtools import dmp_lcm +from sympy.polys.euclidtools import dmp_content +from sympy.polys.euclidtools import dmp_primitive +from sympy.polys.euclidtools import dup_cancel +from sympy.polys.euclidtools import dmp_cancel +from sympy.polys.factortools import dup_trial_division +from sympy.polys.factortools import dmp_trial_division +from sympy.polys.factortools import dup_zz_mignotte_bound +from sympy.polys.factortools import dmp_zz_mignotte_bound +from sympy.polys.factortools import dup_zz_hensel_step +from sympy.polys.factortools import dup_zz_hensel_lift +from sympy.polys.factortools import dup_zz_zassenhaus +from sympy.polys.factortools import dup_zz_irreducible_p +from sympy.polys.factortools import dup_cyclotomic_p +from sympy.polys.factortools import dup_zz_cyclotomic_poly +from sympy.polys.factortools import dup_zz_cyclotomic_factor +from sympy.polys.factortools import dup_zz_factor_sqf +from sympy.polys.factortools import dup_zz_factor +from sympy.polys.factortools import dmp_zz_wang_non_divisors +from sympy.polys.factortools import dmp_zz_wang_lead_coeffs +from sympy.polys.factortools import dup_zz_diophantine +from sympy.polys.factortools import dmp_zz_diophantine +from sympy.polys.factortools import dmp_zz_wang_hensel_lifting +from sympy.polys.factortools import dmp_zz_wang +from sympy.polys.factortools import dmp_zz_factor +from sympy.polys.factortools import dup_qq_i_factor +from sympy.polys.factortools import dup_zz_i_factor +from sympy.polys.factortools import dmp_qq_i_factor +from sympy.polys.factortools import dmp_zz_i_factor +from sympy.polys.factortools import dup_ext_factor +from sympy.polys.factortools import dmp_ext_factor +from sympy.polys.factortools import dup_gf_factor +from sympy.polys.factortools import dmp_gf_factor +from sympy.polys.factortools import dup_factor_list +from sympy.polys.factortools import dup_factor_list_include +from sympy.polys.factortools import dmp_factor_list +from sympy.polys.factortools import dmp_factor_list_include +from sympy.polys.factortools import dup_irreducible_p +from sympy.polys.factortools import dmp_irreducible_p +from sympy.polys.rootisolation import dup_sturm +from sympy.polys.rootisolation import dup_root_upper_bound +from sympy.polys.rootisolation import dup_root_lower_bound +from sympy.polys.rootisolation import dup_step_refine_real_root +from sympy.polys.rootisolation import dup_inner_refine_real_root +from sympy.polys.rootisolation import dup_outer_refine_real_root +from sympy.polys.rootisolation import dup_refine_real_root +from sympy.polys.rootisolation import dup_inner_isolate_real_roots +from sympy.polys.rootisolation import dup_inner_isolate_positive_roots +from sympy.polys.rootisolation import dup_inner_isolate_negative_roots +from sympy.polys.rootisolation import dup_isolate_real_roots_sqf +from sympy.polys.rootisolation import dup_isolate_real_roots +from sympy.polys.rootisolation import dup_isolate_real_roots_list +from sympy.polys.rootisolation import dup_count_real_roots +from sympy.polys.rootisolation import dup_count_complex_roots +from sympy.polys.rootisolation import dup_isolate_complex_roots_sqf +from sympy.polys.rootisolation import dup_isolate_all_roots_sqf +from sympy.polys.rootisolation import dup_isolate_all_roots + +from sympy.polys.sqfreetools import ( + dup_sqf_p, dmp_sqf_p, dmp_norm, dup_sqf_norm, dmp_sqf_norm, + dup_gf_sqf_part, dmp_gf_sqf_part, dup_sqf_part, dmp_sqf_part, + dup_gf_sqf_list, dmp_gf_sqf_list, dup_sqf_list, dup_sqf_list_include, + dmp_sqf_list, dmp_sqf_list_include, dup_gff_list, dmp_gff_list) + +from sympy.polys.galoistools import ( + gf_degree, gf_LC, gf_TC, gf_strip, gf_from_dict, + gf_to_dict, gf_from_int_poly, gf_to_int_poly, gf_neg, gf_add_ground, gf_sub_ground, + gf_mul_ground, gf_quo_ground, gf_add, gf_sub, gf_mul, gf_sqr, gf_add_mul, gf_sub_mul, + gf_expand, gf_div, gf_rem, gf_quo, gf_exquo, gf_lshift, gf_rshift, gf_pow, gf_pow_mod, + gf_gcd, gf_lcm, gf_cofactors, gf_gcdex, gf_monic, gf_diff, gf_eval, gf_multi_eval, + gf_compose, gf_compose_mod, gf_trace_map, gf_random, gf_irreducible, gf_irred_p_ben_or, + gf_irred_p_rabin, gf_irreducible_p, gf_sqf_p, gf_sqf_part, gf_Qmatrix, + gf_berlekamp, gf_ddf_zassenhaus, gf_edf_zassenhaus, gf_ddf_shoup, gf_edf_shoup, + gf_zassenhaus, gf_shoup, gf_factor_sqf, gf_factor) + +from sympy.utilities import public + +@public +class IPolys: + + gens: tuple[PolyElement, ...] + symbols: tuple[Expr, ...] + ngens: int + domain: Domain + order: MonomialOrder + + def drop(self, gen): + pass + + def clone(self, symbols=None, domain=None, order=None): + pass + + def to_ground(self): + pass + + def ground_new(self, element): + pass + + def domain_new(self, element): + pass + + def from_dict(self, d): + pass + + def wrap(self, element): + from sympy.polys.rings import PolyElement + if isinstance(element, PolyElement): + if element.ring == self: + return element + else: + raise NotImplementedError("domain conversions") + else: + return self.ground_new(element) + + def to_dense(self, element): + return self.wrap(element).to_dense() + + def from_dense(self, element): + return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain)) + + def dup_add_term(self, f, c, i): + return self.from_dense(dup_add_term(self.to_dense(f), c, i, self.domain)) + def dmp_add_term(self, f, c, i): + return self.from_dense(dmp_add_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) + def dup_sub_term(self, f, c, i): + return self.from_dense(dup_sub_term(self.to_dense(f), c, i, self.domain)) + def dmp_sub_term(self, f, c, i): + return self.from_dense(dmp_sub_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) + def dup_mul_term(self, f, c, i): + return self.from_dense(dup_mul_term(self.to_dense(f), c, i, self.domain)) + def dmp_mul_term(self, f, c, i): + return self.from_dense(dmp_mul_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) + + def dup_add_ground(self, f, c): + return self.from_dense(dup_add_ground(self.to_dense(f), c, self.domain)) + def dmp_add_ground(self, f, c): + return self.from_dense(dmp_add_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + def dup_sub_ground(self, f, c): + return self.from_dense(dup_sub_ground(self.to_dense(f), c, self.domain)) + def dmp_sub_ground(self, f, c): + return self.from_dense(dmp_sub_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + def dup_mul_ground(self, f, c): + return self.from_dense(dup_mul_ground(self.to_dense(f), c, self.domain)) + def dmp_mul_ground(self, f, c): + return self.from_dense(dmp_mul_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + def dup_quo_ground(self, f, c): + return self.from_dense(dup_quo_ground(self.to_dense(f), c, self.domain)) + def dmp_quo_ground(self, f, c): + return self.from_dense(dmp_quo_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + def dup_exquo_ground(self, f, c): + return self.from_dense(dup_exquo_ground(self.to_dense(f), c, self.domain)) + def dmp_exquo_ground(self, f, c): + return self.from_dense(dmp_exquo_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + + def dup_lshift(self, f, n): + return self.from_dense(dup_lshift(self.to_dense(f), n, self.domain)) + def dup_rshift(self, f, n): + return self.from_dense(dup_rshift(self.to_dense(f), n, self.domain)) + + def dup_abs(self, f): + return self.from_dense(dup_abs(self.to_dense(f), self.domain)) + def dmp_abs(self, f): + return self.from_dense(dmp_abs(self.to_dense(f), self.ngens-1, self.domain)) + + def dup_neg(self, f): + return self.from_dense(dup_neg(self.to_dense(f), self.domain)) + def dmp_neg(self, f): + return self.from_dense(dmp_neg(self.to_dense(f), self.ngens-1, self.domain)) + + def dup_add(self, f, g): + return self.from_dense(dup_add(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_add(self, f, g): + return self.from_dense(dmp_add(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_sub(self, f, g): + return self.from_dense(dup_sub(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_sub(self, f, g): + return self.from_dense(dmp_sub(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_add_mul(self, f, g, h): + return self.from_dense(dup_add_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.domain)) + def dmp_add_mul(self, f, g, h): + return self.from_dense(dmp_add_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.ngens-1, self.domain)) + def dup_sub_mul(self, f, g, h): + return self.from_dense(dup_sub_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.domain)) + def dmp_sub_mul(self, f, g, h): + return self.from_dense(dmp_sub_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.ngens-1, self.domain)) + + def dup_mul(self, f, g): + return self.from_dense(dup_mul(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_mul(self, f, g): + return self.from_dense(dmp_mul(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_sqr(self, f): + return self.from_dense(dup_sqr(self.to_dense(f), self.domain)) + def dmp_sqr(self, f): + return self.from_dense(dmp_sqr(self.to_dense(f), self.ngens-1, self.domain)) + def dup_pow(self, f, n): + return self.from_dense(dup_pow(self.to_dense(f), n, self.domain)) + def dmp_pow(self, f, n): + return self.from_dense(dmp_pow(self.to_dense(f), n, self.ngens-1, self.domain)) + + def dup_pdiv(self, f, g): + q, r = dup_pdiv(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dup_prem(self, f, g): + return self.from_dense(dup_prem(self.to_dense(f), self.to_dense(g), self.domain)) + def dup_pquo(self, f, g): + return self.from_dense(dup_pquo(self.to_dense(f), self.to_dense(g), self.domain)) + def dup_pexquo(self, f, g): + return self.from_dense(dup_pexquo(self.to_dense(f), self.to_dense(g), self.domain)) + + def dmp_pdiv(self, f, g): + q, r = dmp_pdiv(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dmp_prem(self, f, g): + return self.from_dense(dmp_prem(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + def dmp_pquo(self, f, g): + return self.from_dense(dmp_pquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + def dmp_pexquo(self, f, g): + return self.from_dense(dmp_pexquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_rr_div(self, f, g): + q, r = dup_rr_div(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dmp_rr_div(self, f, g): + q, r = dmp_rr_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dup_ff_div(self, f, g): + q, r = dup_ff_div(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dmp_ff_div(self, f, g): + q, r = dmp_ff_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(q), self.from_dense(r)) + + def dup_div(self, f, g): + q, r = dup_div(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dup_rem(self, f, g): + return self.from_dense(dup_rem(self.to_dense(f), self.to_dense(g), self.domain)) + def dup_quo(self, f, g): + return self.from_dense(dup_quo(self.to_dense(f), self.to_dense(g), self.domain)) + def dup_exquo(self, f, g): + return self.from_dense(dup_exquo(self.to_dense(f), self.to_dense(g), self.domain)) + + def dmp_div(self, f, g): + q, r = dmp_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dmp_rem(self, f, g): + return self.from_dense(dmp_rem(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + def dmp_quo(self, f, g): + return self.from_dense(dmp_quo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + def dmp_exquo(self, f, g): + return self.from_dense(dmp_exquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_max_norm(self, f): + return dup_max_norm(self.to_dense(f), self.domain) + def dmp_max_norm(self, f): + return dmp_max_norm(self.to_dense(f), self.ngens-1, self.domain) + + def dup_l1_norm(self, f): + return dup_l1_norm(self.to_dense(f), self.domain) + def dmp_l1_norm(self, f): + return dmp_l1_norm(self.to_dense(f), self.ngens-1, self.domain) + + def dup_l2_norm_squared(self, f): + return dup_l2_norm_squared(self.to_dense(f), self.domain) + def dmp_l2_norm_squared(self, f): + return dmp_l2_norm_squared(self.to_dense(f), self.ngens-1, self.domain) + + def dup_expand(self, polys): + return self.from_dense(dup_expand(list(map(self.to_dense, polys)), self.domain)) + def dmp_expand(self, polys): + return self.from_dense(dmp_expand(list(map(self.to_dense, polys)), self.ngens-1, self.domain)) + + def dup_LC(self, f): + return dup_LC(self.to_dense(f), self.domain) + def dmp_LC(self, f): + LC = dmp_LC(self.to_dense(f), self.domain) + if isinstance(LC, list): + return self[1:].from_dense(LC) + else: + return LC + def dup_TC(self, f): + return dup_TC(self.to_dense(f), self.domain) + def dmp_TC(self, f): + TC = dmp_TC(self.to_dense(f), self.domain) + if isinstance(TC, list): + return self[1:].from_dense(TC) + else: + return TC + + def dmp_ground_LC(self, f): + return dmp_ground_LC(self.to_dense(f), self.ngens-1, self.domain) + def dmp_ground_TC(self, f): + return dmp_ground_TC(self.to_dense(f), self.ngens-1, self.domain) + + def dup_degree(self, f): + return dup_degree(self.to_dense(f)) + def dmp_degree(self, f): + return dmp_degree(self.to_dense(f), self.ngens-1) + def dmp_degree_in(self, f, j): + return dmp_degree_in(self.to_dense(f), j, self.ngens-1) + def dup_integrate(self, f, m): + return self.from_dense(dup_integrate(self.to_dense(f), m, self.domain)) + def dmp_integrate(self, f, m): + return self.from_dense(dmp_integrate(self.to_dense(f), m, self.ngens-1, self.domain)) + + def dup_diff(self, f, m): + return self.from_dense(dup_diff(self.to_dense(f), m, self.domain)) + def dmp_diff(self, f, m): + return self.from_dense(dmp_diff(self.to_dense(f), m, self.ngens-1, self.domain)) + + def dmp_diff_in(self, f, m, j): + return self.from_dense(dmp_diff_in(self.to_dense(f), m, j, self.ngens-1, self.domain)) + def dmp_integrate_in(self, f, m, j): + return self.from_dense(dmp_integrate_in(self.to_dense(f), m, j, self.ngens-1, self.domain)) + + def dup_eval(self, f, a): + return dup_eval(self.to_dense(f), a, self.domain) + def dmp_eval(self, f, a): + result = dmp_eval(self.to_dense(f), a, self.ngens-1, self.domain) + return self[1:].from_dense(result) + + def dmp_eval_in(self, f, a, j): + result = dmp_eval_in(self.to_dense(f), a, j, self.ngens-1, self.domain) + return self.drop(j).from_dense(result) + def dmp_diff_eval_in(self, f, m, a, j): + result = dmp_diff_eval_in(self.to_dense(f), m, a, j, self.ngens-1, self.domain) + return self.drop(j).from_dense(result) + + def dmp_eval_tail(self, f, A): + result = dmp_eval_tail(self.to_dense(f), A, self.ngens-1, self.domain) + if isinstance(result, list): + return self[:-len(A)].from_dense(result) + else: + return result + + def dup_trunc(self, f, p): + return self.from_dense(dup_trunc(self.to_dense(f), p, self.domain)) + def dmp_trunc(self, f, g): + return self.from_dense(dmp_trunc(self.to_dense(f), self[1:].to_dense(g), self.ngens-1, self.domain)) + def dmp_ground_trunc(self, f, p): + return self.from_dense(dmp_ground_trunc(self.to_dense(f), p, self.ngens-1, self.domain)) + + def dup_monic(self, f): + return self.from_dense(dup_monic(self.to_dense(f), self.domain)) + def dmp_ground_monic(self, f): + return self.from_dense(dmp_ground_monic(self.to_dense(f), self.ngens-1, self.domain)) + + def dup_extract(self, f, g): + c, F, G = dup_extract(self.to_dense(f), self.to_dense(g), self.domain) + return (c, self.from_dense(F), self.from_dense(G)) + def dmp_ground_extract(self, f, g): + c, F, G = dmp_ground_extract(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (c, self.from_dense(F), self.from_dense(G)) + + def dup_real_imag(self, f): + p, q = dup_real_imag(self.wrap(f).drop(1).to_dense(), self.domain) + return (self.from_dense(p), self.from_dense(q)) + + def dup_mirror(self, f): + return self.from_dense(dup_mirror(self.to_dense(f), self.domain)) + def dup_scale(self, f, a): + return self.from_dense(dup_scale(self.to_dense(f), a, self.domain)) + def dup_shift(self, f, a): + return self.from_dense(dup_shift(self.to_dense(f), a, self.domain)) + def dmp_shift(self, f, a): + return self.from_dense(dmp_shift(self.to_dense(f), a, self.ngens-1, self.domain)) + def dup_transform(self, f, p, q): + return self.from_dense(dup_transform(self.to_dense(f), self.to_dense(p), self.to_dense(q), self.domain)) + + def dup_compose(self, f, g): + return self.from_dense(dup_compose(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_compose(self, f, g): + return self.from_dense(dmp_compose(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_decompose(self, f): + components = dup_decompose(self.to_dense(f), self.domain) + return list(map(self.from_dense, components)) + + def dmp_lift(self, f): + result = dmp_lift(self.to_dense(f), self.ngens-1, self.domain) + return self.to_ground().from_dense(result) + + def dup_sign_variations(self, f): + return dup_sign_variations(self.to_dense(f), self.domain) + + def dup_clear_denoms(self, f, convert=False): + c, F = dup_clear_denoms(self.to_dense(f), self.domain, convert=convert) + if convert: + ring = self.clone(domain=self.domain.get_ring()) + else: + ring = self + return (c, ring.from_dense(F)) + def dmp_clear_denoms(self, f, convert=False): + c, F = dmp_clear_denoms(self.to_dense(f), self.ngens-1, self.domain, convert=convert) + if convert: + ring = self.clone(domain=self.domain.get_ring()) + else: + ring = self + return (c, ring.from_dense(F)) + + def dup_revert(self, f, n): + return self.from_dense(dup_revert(self.to_dense(f), n, self.domain)) + + def dup_half_gcdex(self, f, g): + s, h = dup_half_gcdex(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(s), self.from_dense(h)) + def dmp_half_gcdex(self, f, g): + s, h = dmp_half_gcdex(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(s), self.from_dense(h)) + def dup_gcdex(self, f, g): + s, t, h = dup_gcdex(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(s), self.from_dense(t), self.from_dense(h)) + def dmp_gcdex(self, f, g): + s, t, h = dmp_gcdex(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(s), self.from_dense(t), self.from_dense(h)) + + def dup_invert(self, f, g): + return self.from_dense(dup_invert(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_invert(self, f, g): + return self.from_dense(dmp_invert(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_euclidean_prs(self, f, g): + prs = dup_euclidean_prs(self.to_dense(f), self.to_dense(g), self.domain) + return list(map(self.from_dense, prs)) + def dmp_euclidean_prs(self, f, g): + prs = dmp_euclidean_prs(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return list(map(self.from_dense, prs)) + def dup_primitive_prs(self, f, g): + prs = dup_primitive_prs(self.to_dense(f), self.to_dense(g), self.domain) + return list(map(self.from_dense, prs)) + def dmp_primitive_prs(self, f, g): + prs = dmp_primitive_prs(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return list(map(self.from_dense, prs)) + + def dup_inner_subresultants(self, f, g): + prs, sres = dup_inner_subresultants(self.to_dense(f), self.to_dense(g), self.domain) + return (list(map(self.from_dense, prs)), sres) + def dmp_inner_subresultants(self, f, g): + prs, sres = dmp_inner_subresultants(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (list(map(self.from_dense, prs)), sres) + + def dup_subresultants(self, f, g): + prs = dup_subresultants(self.to_dense(f), self.to_dense(g), self.domain) + return list(map(self.from_dense, prs)) + def dmp_subresultants(self, f, g): + prs = dmp_subresultants(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return list(map(self.from_dense, prs)) + + def dup_prs_resultant(self, f, g): + res, prs = dup_prs_resultant(self.to_dense(f), self.to_dense(g), self.domain) + return (res, list(map(self.from_dense, prs))) + def dmp_prs_resultant(self, f, g): + res, prs = dmp_prs_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self[1:].from_dense(res), list(map(self.from_dense, prs))) + + def dmp_zz_modular_resultant(self, f, g, p): + res = dmp_zz_modular_resultant(self.to_dense(f), self.to_dense(g), self.domain_new(p), self.ngens-1, self.domain) + return self[1:].from_dense(res) + def dmp_zz_collins_resultant(self, f, g): + res = dmp_zz_collins_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self[1:].from_dense(res) + def dmp_qq_collins_resultant(self, f, g): + res = dmp_qq_collins_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self[1:].from_dense(res) + + def dup_resultant(self, f, g): #, includePRS=False): + return dup_resultant(self.to_dense(f), self.to_dense(g), self.domain) #, includePRS=includePRS) + def dmp_resultant(self, f, g): #, includePRS=False): + res = dmp_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) #, includePRS=includePRS) + if isinstance(res, list): + return self[1:].from_dense(res) + else: + return res + + def dup_discriminant(self, f): + return dup_discriminant(self.to_dense(f), self.domain) + def dmp_discriminant(self, f): + disc = dmp_discriminant(self.to_dense(f), self.ngens-1, self.domain) + if isinstance(disc, list): + return self[1:].from_dense(disc) + else: + return disc + + def dup_rr_prs_gcd(self, f, g): + H, F, G = dup_rr_prs_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_ff_prs_gcd(self, f, g): + H, F, G = dup_ff_prs_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_rr_prs_gcd(self, f, g): + H, F, G = dmp_rr_prs_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_ff_prs_gcd(self, f, g): + H, F, G = dmp_ff_prs_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_zz_heu_gcd(self, f, g): + H, F, G = dup_zz_heu_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_zz_heu_gcd(self, f, g): + H, F, G = dmp_zz_heu_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_qq_heu_gcd(self, f, g): + H, F, G = dup_qq_heu_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_qq_heu_gcd(self, f, g): + H, F, G = dmp_qq_heu_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_inner_gcd(self, f, g): + H, F, G = dup_inner_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_inner_gcd(self, f, g): + H, F, G = dmp_inner_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_gcd(self, f, g): + H = dup_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return self.from_dense(H) + def dmp_gcd(self, f, g): + H = dmp_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self.from_dense(H) + def dup_rr_lcm(self, f, g): + H = dup_rr_lcm(self.to_dense(f), self.to_dense(g), self.domain) + return self.from_dense(H) + def dup_ff_lcm(self, f, g): + H = dup_ff_lcm(self.to_dense(f), self.to_dense(g), self.domain) + return self.from_dense(H) + def dup_lcm(self, f, g): + H = dup_lcm(self.to_dense(f), self.to_dense(g), self.domain) + return self.from_dense(H) + def dmp_rr_lcm(self, f, g): + H = dmp_rr_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self.from_dense(H) + def dmp_ff_lcm(self, f, g): + H = dmp_ff_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self.from_dense(H) + def dmp_lcm(self, f, g): + H = dmp_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self.from_dense(H) + + def dup_content(self, f): + cont = dup_content(self.to_dense(f), self.domain) + return cont + def dup_primitive(self, f): + cont, prim = dup_primitive(self.to_dense(f), self.domain) + return cont, self.from_dense(prim) + + def dmp_content(self, f): + cont = dmp_content(self.to_dense(f), self.ngens-1, self.domain) + if isinstance(cont, list): + return self[1:].from_dense(cont) + else: + return cont + def dmp_primitive(self, f): + cont, prim = dmp_primitive(self.to_dense(f), self.ngens-1, self.domain) + if isinstance(cont, list): + return (self[1:].from_dense(cont), self.from_dense(prim)) + else: + return (cont, self.from_dense(prim)) + + def dmp_ground_content(self, f): + cont = dmp_ground_content(self.to_dense(f), self.ngens-1, self.domain) + return cont + def dmp_ground_primitive(self, f): + cont, prim = dmp_ground_primitive(self.to_dense(f), self.ngens-1, self.domain) + return (cont, self.from_dense(prim)) + + def dup_cancel(self, f, g, include=True): + result = dup_cancel(self.to_dense(f), self.to_dense(g), self.domain, include=include) + if not include: + cf, cg, F, G = result + return (cf, cg, self.from_dense(F), self.from_dense(G)) + else: + F, G = result + return (self.from_dense(F), self.from_dense(G)) + def dmp_cancel(self, f, g, include=True): + result = dmp_cancel(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain, include=include) + if not include: + cf, cg, F, G = result + return (cf, cg, self.from_dense(F), self.from_dense(G)) + else: + F, G = result + return (self.from_dense(F), self.from_dense(G)) + + def dup_trial_division(self, f, factors): + factors = dup_trial_division(self.to_dense(f), list(map(self.to_dense, factors)), self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + def dmp_trial_division(self, f, factors): + factors = dmp_trial_division(self.to_dense(f), list(map(self.to_dense, factors)), self.ngens-1, self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_zz_mignotte_bound(self, f): + return dup_zz_mignotte_bound(self.to_dense(f), self.domain) + def dmp_zz_mignotte_bound(self, f): + return dmp_zz_mignotte_bound(self.to_dense(f), self.ngens-1, self.domain) + + def dup_zz_hensel_step(self, m, f, g, h, s, t): + D = self.to_dense + G, H, S, T = dup_zz_hensel_step(m, D(f), D(g), D(h), D(s), D(t), self.domain) + return (self.from_dense(G), self.from_dense(H), self.from_dense(S), self.from_dense(T)) + def dup_zz_hensel_lift(self, p, f, f_list, l): + D = self.to_dense + polys = dup_zz_hensel_lift(p, D(f), list(map(D, f_list)), l, self.domain) + return list(map(self.from_dense, polys)) + + def dup_zz_zassenhaus(self, f): + factors = dup_zz_zassenhaus(self.to_dense(f), self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_zz_irreducible_p(self, f): + return dup_zz_irreducible_p(self.to_dense(f), self.domain) + def dup_cyclotomic_p(self, f, irreducible=False): + return dup_cyclotomic_p(self.to_dense(f), self.domain, irreducible=irreducible) + def dup_zz_cyclotomic_poly(self, n): + F = dup_zz_cyclotomic_poly(n, self.domain) + return self.from_dense(F) + def dup_zz_cyclotomic_factor(self, f): + result = dup_zz_cyclotomic_factor(self.to_dense(f), self.domain) + if result is None: + return result + else: + return list(map(self.from_dense, result)) + + # E: List[ZZ], cs: ZZ, ct: ZZ + def dmp_zz_wang_non_divisors(self, E, cs, ct): + return dmp_zz_wang_non_divisors(E, cs, ct, self.domain) + + # f: Poly, T: List[(Poly, int)], ct: ZZ, A: List[ZZ] + #def dmp_zz_wang_test_points(f, T, ct, A): + # dmp_zz_wang_test_points(self.to_dense(f), T, ct, A, self.ngens-1, self.domain) + + # f: Poly, T: List[(Poly, int)], cs: ZZ, E: List[ZZ], H: List[Poly], A: List[ZZ] + def dmp_zz_wang_lead_coeffs(self, f, T, cs, E, H, A): + mv = self[1:] + T = [ (mv.to_dense(t), k) for t, k in T ] + uv = self[:1] + H = list(map(uv.to_dense, H)) + f, HH, CC = dmp_zz_wang_lead_coeffs(self.to_dense(f), T, cs, E, H, A, self.ngens-1, self.domain) + return self.from_dense(f), list(map(uv.from_dense, HH)), list(map(mv.from_dense, CC)) + + # f: List[Poly], m: int, p: ZZ + def dup_zz_diophantine(self, F, m, p): + result = dup_zz_diophantine(list(map(self.to_dense, F)), m, p, self.domain) + return list(map(self.from_dense, result)) + + # f: List[Poly], c: List[Poly], A: List[ZZ], d: int, p: ZZ + def dmp_zz_diophantine(self, F, c, A, d, p): + result = dmp_zz_diophantine(list(map(self.to_dense, F)), self.to_dense(c), A, d, p, self.ngens-1, self.domain) + return list(map(self.from_dense, result)) + + # f: Poly, H: List[Poly], LC: List[Poly], A: List[ZZ], p: ZZ + def dmp_zz_wang_hensel_lifting(self, f, H, LC, A, p): + uv = self[:1] + mv = self[1:] + H = list(map(uv.to_dense, H)) + LC = list(map(mv.to_dense, LC)) + result = dmp_zz_wang_hensel_lifting(self.to_dense(f), H, LC, A, p, self.ngens-1, self.domain) + return list(map(self.from_dense, result)) + + def dmp_zz_wang(self, f, mod=None, seed=None): + factors = dmp_zz_wang(self.to_dense(f), self.ngens-1, self.domain, mod=mod, seed=seed) + return [ self.from_dense(g) for g in factors ] + + def dup_zz_factor_sqf(self, f): + coeff, factors = dup_zz_factor_sqf(self.to_dense(f), self.domain) + return (coeff, [ self.from_dense(g) for g in factors ]) + + def dup_zz_factor(self, f): + coeff, factors = dup_zz_factor(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_zz_factor(self, f): + coeff, factors = dmp_zz_factor(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_qq_i_factor(self, f): + coeff, factors = dup_qq_i_factor(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_qq_i_factor(self, f): + coeff, factors = dmp_qq_i_factor(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_zz_i_factor(self, f): + coeff, factors = dup_zz_i_factor(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_zz_i_factor(self, f): + coeff, factors = dmp_zz_i_factor(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_ext_factor(self, f): + coeff, factors = dup_ext_factor(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_ext_factor(self, f): + coeff, factors = dmp_ext_factor(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_gf_factor(self, f): + coeff, factors = dup_gf_factor(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_gf_factor(self, f): + coeff, factors = dmp_gf_factor(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_factor_list(self, f): + coeff, factors = dup_factor_list(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dup_factor_list_include(self, f): + factors = dup_factor_list_include(self.to_dense(f), self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dmp_factor_list(self, f): + coeff, factors = dmp_factor_list(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_factor_list_include(self, f): + factors = dmp_factor_list_include(self.to_dense(f), self.ngens-1, self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_irreducible_p(self, f): + return dup_irreducible_p(self.to_dense(f), self.domain) + def dmp_irreducible_p(self, f): + return dmp_irreducible_p(self.to_dense(f), self.ngens-1, self.domain) + + def dup_sturm(self, f): + seq = dup_sturm(self.to_dense(f), self.domain) + return list(map(self.from_dense, seq)) + + def dup_sqf_p(self, f): + return dup_sqf_p(self.to_dense(f), self.domain) + def dmp_sqf_p(self, f): + return dmp_sqf_p(self.to_dense(f), self.ngens-1, self.domain) + + def dmp_norm(self, f): + n = dmp_norm(self.to_dense(f), self.ngens-1, self.domain) + return self.to_ground().from_dense(n) + + def dup_sqf_norm(self, f): + s, F, R = dup_sqf_norm(self.to_dense(f), self.domain) + return (s, self.from_dense(F), self.to_ground().from_dense(R)) + def dmp_sqf_norm(self, f): + s, F, R = dmp_sqf_norm(self.to_dense(f), self.ngens-1, self.domain) + return (s, self.from_dense(F), self.to_ground().from_dense(R)) + + def dup_gf_sqf_part(self, f): + return self.from_dense(dup_gf_sqf_part(self.to_dense(f), self.domain)) + def dmp_gf_sqf_part(self, f): + return self.from_dense(dmp_gf_sqf_part(self.to_dense(f), self.domain)) + def dup_sqf_part(self, f): + return self.from_dense(dup_sqf_part(self.to_dense(f), self.domain)) + def dmp_sqf_part(self, f): + return self.from_dense(dmp_sqf_part(self.to_dense(f), self.ngens-1, self.domain)) + + def dup_gf_sqf_list(self, f, all=False): + coeff, factors = dup_gf_sqf_list(self.to_dense(f), self.domain, all=all) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_gf_sqf_list(self, f, all=False): + coeff, factors = dmp_gf_sqf_list(self.to_dense(f), self.ngens-1, self.domain, all=all) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_sqf_list(self, f, all=False): + coeff, factors = dup_sqf_list(self.to_dense(f), self.domain, all=all) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dup_sqf_list_include(self, f, all=False): + factors = dup_sqf_list_include(self.to_dense(f), self.domain, all=all) + return [ (self.from_dense(g), k) for g, k in factors ] + def dmp_sqf_list(self, f, all=False): + coeff, factors = dmp_sqf_list(self.to_dense(f), self.ngens-1, self.domain, all=all) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_sqf_list_include(self, f, all=False): + factors = dmp_sqf_list_include(self.to_dense(f), self.ngens-1, self.domain, all=all) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_gff_list(self, f): + factors = dup_gff_list(self.to_dense(f), self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + def dmp_gff_list(self, f): + factors = dmp_gff_list(self.to_dense(f), self.ngens-1, self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_root_upper_bound(self, f): + return dup_root_upper_bound(self.to_dense(f), self.domain) + def dup_root_lower_bound(self, f): + return dup_root_lower_bound(self.to_dense(f), self.domain) + + def dup_step_refine_real_root(self, f, M, fast=False): + return dup_step_refine_real_root(self.to_dense(f), M, self.domain, fast=fast) + def dup_inner_refine_real_root(self, f, M, eps=None, steps=None, disjoint=None, fast=False, mobius=False): + return dup_inner_refine_real_root(self.to_dense(f), M, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast, mobius=mobius) + def dup_outer_refine_real_root(self, f, s, t, eps=None, steps=None, disjoint=None, fast=False): + return dup_outer_refine_real_root(self.to_dense(f), s, t, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast) + def dup_refine_real_root(self, f, s, t, eps=None, steps=None, disjoint=None, fast=False): + return dup_refine_real_root(self.to_dense(f), s, t, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast) + def dup_inner_isolate_real_roots(self, f, eps=None, fast=False): + return dup_inner_isolate_real_roots(self.to_dense(f), self.domain, eps=eps, fast=fast) + def dup_inner_isolate_positive_roots(self, f, eps=None, inf=None, sup=None, fast=False, mobius=False): + return dup_inner_isolate_positive_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, mobius=mobius) + def dup_inner_isolate_negative_roots(self, f, inf=None, sup=None, eps=None, fast=False, mobius=False): + return dup_inner_isolate_negative_roots(self.to_dense(f), self.domain, inf=inf, sup=sup, eps=eps, fast=fast, mobius=mobius) + def dup_isolate_real_roots_sqf(self, f, eps=None, inf=None, sup=None, fast=False, blackbox=False): + return dup_isolate_real_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox) + def dup_isolate_real_roots(self, f, eps=None, inf=None, sup=None, basis=False, fast=False): + return dup_isolate_real_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, basis=basis, fast=fast) + def dup_isolate_real_roots_list(self, polys, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): + return dup_isolate_real_roots_list(list(map(self.to_dense, polys)), self.domain, eps=eps, inf=inf, sup=sup, strict=strict, basis=basis, fast=fast) + def dup_count_real_roots(self, f, inf=None, sup=None): + return dup_count_real_roots(self.to_dense(f), self.domain, inf=inf, sup=sup) + def dup_count_complex_roots(self, f, inf=None, sup=None, exclude=None): + return dup_count_complex_roots(self.to_dense(f), self.domain, inf=inf, sup=sup, exclude=exclude) + def dup_isolate_complex_roots_sqf(self, f, eps=None, inf=None, sup=None, blackbox=False): + return dup_isolate_complex_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, blackbox=blackbox) + def dup_isolate_all_roots_sqf(self, f, eps=None, inf=None, sup=None, fast=False, blackbox=False): + return dup_isolate_all_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox) + def dup_isolate_all_roots(self, f, eps=None, inf=None, sup=None, fast=False): + return dup_isolate_all_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast) + + def fateman_poly_F_1(self): + from sympy.polys.specialpolys import dmp_fateman_poly_F_1 + return tuple(map(self.from_dense, dmp_fateman_poly_F_1(self.ngens-1, self.domain))) + def fateman_poly_F_2(self): + from sympy.polys.specialpolys import dmp_fateman_poly_F_2 + return tuple(map(self.from_dense, dmp_fateman_poly_F_2(self.ngens-1, self.domain))) + def fateman_poly_F_3(self): + from sympy.polys.specialpolys import dmp_fateman_poly_F_3 + return tuple(map(self.from_dense, dmp_fateman_poly_F_3(self.ngens-1, self.domain))) + + def to_gf_dense(self, element): + return gf_strip([ self.domain.dom.convert(c, self.domain) for c in self.wrap(element).to_dense() ]) + + def from_gf_dense(self, element): + return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain.dom)) + + def gf_degree(self, f): + return gf_degree(self.to_gf_dense(f)) + + def gf_LC(self, f): + return gf_LC(self.to_gf_dense(f), self.domain.dom) + def gf_TC(self, f): + return gf_TC(self.to_gf_dense(f), self.domain.dom) + + def gf_strip(self, f): + return self.from_gf_dense(gf_strip(self.to_gf_dense(f))) + def gf_trunc(self, f): + return self.from_gf_dense(gf_strip(self.to_gf_dense(f), self.domain.mod)) + def gf_normal(self, f): + return self.from_gf_dense(gf_strip(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_from_dict(self, f): + return self.from_gf_dense(gf_from_dict(f, self.domain.mod, self.domain.dom)) + def gf_to_dict(self, f, symmetric=True): + return gf_to_dict(self.to_gf_dense(f), self.domain.mod, symmetric=symmetric) + + def gf_from_int_poly(self, f): + return self.from_gf_dense(gf_from_int_poly(f, self.domain.mod)) + def gf_to_int_poly(self, f, symmetric=True): + return gf_to_int_poly(self.to_gf_dense(f), self.domain.mod, symmetric=symmetric) + + def gf_neg(self, f): + return self.from_gf_dense(gf_neg(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_add_ground(self, f, a): + return self.from_gf_dense(gf_add_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) + def gf_sub_ground(self, f, a): + return self.from_gf_dense(gf_sub_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) + def gf_mul_ground(self, f, a): + return self.from_gf_dense(gf_mul_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) + def gf_quo_ground(self, f, a): + return self.from_gf_dense(gf_quo_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) + + def gf_add(self, f, g): + return self.from_gf_dense(gf_add(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_sub(self, f, g): + return self.from_gf_dense(gf_sub(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_mul(self, f, g): + return self.from_gf_dense(gf_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_sqr(self, f): + return self.from_gf_dense(gf_sqr(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_add_mul(self, f, g, h): + return self.from_gf_dense(gf_add_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.to_gf_dense(h), self.domain.mod, self.domain.dom)) + def gf_sub_mul(self, f, g, h): + return self.from_gf_dense(gf_sub_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.to_gf_dense(h), self.domain.mod, self.domain.dom)) + + def gf_expand(self, F): + return self.from_gf_dense(gf_expand(list(map(self.to_gf_dense, F)), self.domain.mod, self.domain.dom)) + + def gf_div(self, f, g): + q, r = gf_div(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom) + return self.from_gf_dense(q), self.from_gf_dense(r) + def gf_rem(self, f, g): + return self.from_gf_dense(gf_rem(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_quo(self, f, g): + return self.from_gf_dense(gf_quo(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_exquo(self, f, g): + return self.from_gf_dense(gf_exquo(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + + def gf_lshift(self, f, n): + return self.from_gf_dense(gf_lshift(self.to_gf_dense(f), n, self.domain.dom)) + def gf_rshift(self, f, n): + return self.from_gf_dense(gf_rshift(self.to_gf_dense(f), n, self.domain.dom)) + + def gf_pow(self, f, n): + return self.from_gf_dense(gf_pow(self.to_gf_dense(f), n, self.domain.mod, self.domain.dom)) + def gf_pow_mod(self, f, n, g): + return self.from_gf_dense(gf_pow_mod(self.to_gf_dense(f), n, self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + + def gf_cofactors(self, f, g): + h, cff, cfg = gf_cofactors(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom) + return self.from_gf_dense(h), self.from_gf_dense(cff), self.from_gf_dense(cfg) + def gf_gcd(self, f, g): + return self.from_gf_dense(gf_gcd(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_lcm(self, f, g): + return self.from_gf_dense(gf_lcm(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_gcdex(self, f, g): + return self.from_gf_dense(gf_gcdex(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + + def gf_monic(self, f): + return self.from_gf_dense(gf_monic(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + def gf_diff(self, f): + return self.from_gf_dense(gf_diff(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_eval(self, f, a): + return gf_eval(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom) + def gf_multi_eval(self, f, A): + return gf_multi_eval(self.to_gf_dense(f), A, self.domain.mod, self.domain.dom) + + def gf_compose(self, f, g): + return self.from_gf_dense(gf_compose(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_compose_mod(self, g, h, f): + return self.from_gf_dense(gf_compose_mod(self.to_gf_dense(g), self.to_gf_dense(h), self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_trace_map(self, a, b, c, n, f): + a = self.to_gf_dense(a) + b = self.to_gf_dense(b) + c = self.to_gf_dense(c) + f = self.to_gf_dense(f) + U, V = gf_trace_map(a, b, c, n, f, self.domain.mod, self.domain.dom) + return self.from_gf_dense(U), self.from_gf_dense(V) + + def gf_random(self, n): + return self.from_gf_dense(gf_random(n, self.domain.mod, self.domain.dom)) + def gf_irreducible(self, n): + return self.from_gf_dense(gf_irreducible(n, self.domain.mod, self.domain.dom)) + + def gf_irred_p_ben_or(self, f): + return gf_irred_p_ben_or(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + def gf_irred_p_rabin(self, f): + return gf_irred_p_rabin(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + def gf_irreducible_p(self, f): + return gf_irreducible_p(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + def gf_sqf_p(self, f): + return gf_sqf_p(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + + def gf_sqf_part(self, f): + return self.from_gf_dense(gf_sqf_part(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + def gf_sqf_list(self, f, all=False): + coeff, factors = gf_sqf_part(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return coeff, [ (self.from_gf_dense(g), k) for g, k in factors ] + + def gf_Qmatrix(self, f): + return gf_Qmatrix(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + def gf_berlekamp(self, f): + factors = gf_berlekamp(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + + def gf_ddf_zassenhaus(self, f): + factors = gf_ddf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ (self.from_gf_dense(g), k) for g, k in factors ] + def gf_edf_zassenhaus(self, f, n): + factors = gf_edf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + + def gf_ddf_shoup(self, f): + factors = gf_ddf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ (self.from_gf_dense(g), k) for g, k in factors ] + def gf_edf_shoup(self, f, n): + factors = gf_edf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + + def gf_zassenhaus(self, f): + factors = gf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + def gf_shoup(self, f): + factors = gf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + + def gf_factor_sqf(self, f, method=None): + coeff, factors = gf_factor_sqf(self.to_gf_dense(f), self.domain.mod, self.domain.dom, method=method) + return coeff, [ self.from_gf_dense(g) for g in factors ] + def gf_factor(self, f): + coeff, factors = gf_factor(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return coeff, [ (self.from_gf_dense(g), k) for g, k in factors ] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/constructor.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/constructor.py new file mode 100644 index 0000000000000000000000000000000000000000..49ce4782b987419ee8b736974f8755301380bdda --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/constructor.py @@ -0,0 +1,387 @@ +"""Tools for constructing domains for expressions. """ +from math import prod + +from sympy.core import sympify +from sympy.core.evalf import pure_complex +from sympy.core.sorting import ordered +from sympy.polys.domains import ZZ, QQ, ZZ_I, QQ_I, EX +from sympy.polys.domains.complexfield import ComplexField +from sympy.polys.domains.realfield import RealField +from sympy.polys.polyoptions import build_options +from sympy.polys.polyutils import parallel_dict_from_basic +from sympy.utilities import public + + +def _construct_simple(coeffs, opt): + """Handle simple domains, e.g.: ZZ, QQ, RR and algebraic domains. """ + rationals = floats = complexes = algebraics = False + float_numbers = [] + + if opt.extension is True: + is_algebraic = lambda coeff: coeff.is_number and coeff.is_algebraic + else: + is_algebraic = lambda coeff: False + + for coeff in coeffs: + if coeff.is_Rational: + if not coeff.is_Integer: + rationals = True + elif coeff.is_Float: + if algebraics: + # there are both reals and algebraics -> EX + return False + else: + floats = True + float_numbers.append(coeff) + else: + is_complex = pure_complex(coeff) + if is_complex: + complexes = True + x, y = is_complex + if x.is_Rational and y.is_Rational: + if not (x.is_Integer and y.is_Integer): + rationals = True + continue + else: + floats = True + if x.is_Float: + float_numbers.append(x) + if y.is_Float: + float_numbers.append(y) + elif is_algebraic(coeff): + if floats: + # there are both algebraics and reals -> EX + return False + algebraics = True + else: + # this is a composite domain, e.g. ZZ[X], EX + return None + + # Use the maximum precision of all coefficients for the RR or CC + # precision + max_prec = max(c._prec for c in float_numbers) if float_numbers else 53 + + if algebraics: + domain, result = _construct_algebraic(coeffs, opt) + else: + if floats and complexes: + domain = ComplexField(prec=max_prec) + elif floats: + domain = RealField(prec=max_prec) + elif rationals or opt.field: + domain = QQ_I if complexes else QQ + else: + domain = ZZ_I if complexes else ZZ + + result = [domain.from_sympy(coeff) for coeff in coeffs] + + return domain, result + + +def _construct_algebraic(coeffs, opt): + """We know that coefficients are algebraic so construct the extension. """ + from sympy.polys.numberfields import primitive_element + + exts = set() + + def build_trees(args): + trees = [] + for a in args: + if a.is_Rational: + tree = ('Q', QQ.from_sympy(a)) + elif a.is_Add: + tree = ('+', build_trees(a.args)) + elif a.is_Mul: + tree = ('*', build_trees(a.args)) + else: + tree = ('e', a) + exts.add(a) + trees.append(tree) + return trees + + trees = build_trees(coeffs) + exts = list(ordered(exts)) + + g, span, H = primitive_element(exts, ex=True, polys=True) + root = sum(s*ext for s, ext in zip(span, exts)) + + domain, g = QQ.algebraic_field((g, root)), g.rep.to_list() + + exts_dom = [domain.dtype.from_list(h, g, QQ) for h in H] + exts_map = dict(zip(exts, exts_dom)) + + def convert_tree(tree): + op, args = tree + if op == 'Q': + return domain.dtype.from_list([args], g, QQ) + elif op == '+': + return sum((convert_tree(a) for a in args), domain.zero) + elif op == '*': + return prod(convert_tree(a) for a in args) + elif op == 'e': + return exts_map[args] + else: + raise RuntimeError + + result = [convert_tree(tree) for tree in trees] + + return domain, result + + +def _construct_composite(coeffs, opt): + """Handle composite domains, e.g.: ZZ[X], QQ[X], ZZ(X), QQ(X). """ + numers, denoms = [], [] + + for coeff in coeffs: + numer, denom = coeff.as_numer_denom() + + numers.append(numer) + denoms.append(denom) + + polys, gens = parallel_dict_from_basic(numers + denoms) # XXX: sorting + if not gens: + return None + + if opt.composite is None: + if any(gen.is_number and gen.is_algebraic for gen in gens): + return None # generators are number-like so lets better use EX + + all_symbols = set() + + for gen in gens: + symbols = gen.free_symbols + + if all_symbols & symbols: + return None # there could be algebraic relations between generators + else: + all_symbols |= symbols + + n = len(gens) + k = len(polys)//2 + + numers = polys[:k] + denoms = polys[k:] + + if opt.field: + fractions = True + else: + fractions, zeros = False, (0,)*n + + for denom in denoms: + if len(denom) > 1 or zeros not in denom: + fractions = True + break + + coeffs = set() + + if not fractions: + for numer, denom in zip(numers, denoms): + denom = denom[zeros] + + for monom, coeff in numer.items(): + coeff /= denom + coeffs.add(coeff) + numer[monom] = coeff + else: + for numer, denom in zip(numers, denoms): + coeffs.update(list(numer.values())) + coeffs.update(list(denom.values())) + + rationals = floats = complexes = False + float_numbers = [] + + for coeff in coeffs: + if coeff.is_Rational: + if not coeff.is_Integer: + rationals = True + elif coeff.is_Float: + floats = True + float_numbers.append(coeff) + else: + is_complex = pure_complex(coeff) + if is_complex is not None: + complexes = True + x, y = is_complex + if x.is_Rational and y.is_Rational: + if not (x.is_Integer and y.is_Integer): + rationals = True + else: + floats = True + if x.is_Float: + float_numbers.append(x) + if y.is_Float: + float_numbers.append(y) + + max_prec = max(c._prec for c in float_numbers) if float_numbers else 53 + + if floats and complexes: + ground = ComplexField(prec=max_prec) + elif floats: + ground = RealField(prec=max_prec) + elif complexes: + if rationals: + ground = QQ_I + else: + ground = ZZ_I + elif rationals: + ground = QQ + else: + ground = ZZ + + result = [] + + if not fractions: + domain = ground.poly_ring(*gens) + + for numer in numers: + for monom, coeff in numer.items(): + numer[monom] = ground.from_sympy(coeff) + + result.append(domain(numer)) + else: + domain = ground.frac_field(*gens) + + for numer, denom in zip(numers, denoms): + for monom, coeff in numer.items(): + numer[monom] = ground.from_sympy(coeff) + + for monom, coeff in denom.items(): + denom[monom] = ground.from_sympy(coeff) + + result.append(domain((numer, denom))) + + return domain, result + + +def _construct_expression(coeffs, opt): + """The last resort case, i.e. use the expression domain. """ + domain, result = EX, [] + + for coeff in coeffs: + result.append(domain.from_sympy(coeff)) + + return domain, result + + +@public +def construct_domain(obj, **args): + """Construct a minimal domain for a list of expressions. + + Explanation + =========== + + Given a list of normal SymPy expressions (of type :py:class:`~.Expr`) + ``construct_domain`` will find a minimal :py:class:`~.Domain` that can + represent those expressions. The expressions will be converted to elements + of the domain and both the domain and the domain elements are returned. + + Parameters + ========== + + obj: list or dict + The expressions to build a domain for. + + **args: keyword arguments + Options that affect the choice of domain. + + Returns + ======= + + (K, elements): Domain and list of domain elements + The domain K that can represent the expressions and the list or dict + of domain elements representing the same expressions as elements of K. + + Examples + ======== + + Given a list of :py:class:`~.Integer` ``construct_domain`` will return the + domain :ref:`ZZ` and a list of integers as elements of :ref:`ZZ`. + + >>> from sympy import construct_domain, S + >>> expressions = [S(2), S(3), S(4)] + >>> K, elements = construct_domain(expressions) + >>> K + ZZ + >>> elements + [2, 3, 4] + >>> type(elements[0]) # doctest: +SKIP + + >>> type(expressions[0]) + + + If there are any :py:class:`~.Rational` then :ref:`QQ` is returned + instead. + + >>> construct_domain([S(1)/2, S(3)/4]) + (QQ, [1/2, 3/4]) + + If there are symbols then a polynomial ring :ref:`K[x]` is returned. + + >>> from sympy import symbols + >>> x, y = symbols('x, y') + >>> construct_domain([2*x + 1, S(3)/4]) + (QQ[x], [2*x + 1, 3/4]) + >>> construct_domain([2*x + 1, y]) + (ZZ[x,y], [2*x + 1, y]) + + If any symbols appear with negative powers then a rational function field + :ref:`K(x)` will be returned. + + >>> construct_domain([y/x, x/(1 - y)]) + (ZZ(x,y), [y/x, -x/(y - 1)]) + + Irrational algebraic numbers will result in the :ref:`EX` domain by + default. The keyword argument ``extension=True`` leads to the construction + of an algebraic number field :ref:`QQ(a)`. + + >>> from sympy import sqrt + >>> construct_domain([sqrt(2)]) + (EX, [EX(sqrt(2))]) + >>> construct_domain([sqrt(2)], extension=True) # doctest: +SKIP + (QQ, [ANP([1, 0], [1, 0, -2], QQ)]) + + See also + ======== + + Domain + Expr + """ + opt = build_options(args) + + if hasattr(obj, '__iter__'): + if isinstance(obj, dict): + if not obj: + monoms, coeffs = [], [] + else: + monoms, coeffs = list(zip(*list(obj.items()))) + else: + coeffs = obj + else: + coeffs = [obj] + + coeffs = list(map(sympify, coeffs)) + result = _construct_simple(coeffs, opt) + + if result is not None: + if result is not False: + domain, coeffs = result + else: + domain, coeffs = _construct_expression(coeffs, opt) + else: + if opt.composite is False: + result = None + else: + result = _construct_composite(coeffs, opt) + + if result is not None: + domain, coeffs = result + else: + domain, coeffs = _construct_expression(coeffs, opt) + + if hasattr(obj, '__iter__'): + if isinstance(obj, dict): + return domain, dict(list(zip(monoms, coeffs))) + else: + return domain, coeffs + else: + return domain, coeffs[0] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densearith.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densearith.py new file mode 100644 index 0000000000000000000000000000000000000000..1088691ca3fb020e9074c1c7c017c1baaba637c8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densearith.py @@ -0,0 +1,1875 @@ +"""Arithmetics for dense recursive polynomials in ``K[x]`` or ``K[X]``. """ + + +from sympy.polys.densebasic import ( + dup_slice, + dup_LC, dmp_LC, + dup_degree, dmp_degree, + dup_strip, dmp_strip, + dmp_zero_p, dmp_zero, + dmp_one_p, dmp_one, + dmp_ground, dmp_zeros) +from sympy.polys.polyerrors import (ExactQuotientFailed, PolynomialDivisionFailed) + +def dup_add_term(f, c, i, K): + """ + Add ``c*x**i`` to ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_add_term(x**2 - 1, ZZ(2), 4) + 2*x**4 + x**2 - 1 + + """ + if not c: + return f + + n = len(f) + m = n - i - 1 + + if i == n - 1: + return dup_strip([f[0] + c] + f[1:]) + else: + if i >= n: + return [c] + [K.zero]*(i - n) + f + else: + return f[:m] + [f[m] + c] + f[m + 1:] + + +def dmp_add_term(f, c, i, u, K): + """ + Add ``c(x_2..x_u)*x_0**i`` to ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_add_term(x*y + 1, 2, 2) + 2*x**2 + x*y + 1 + + """ + if not u: + return dup_add_term(f, c, i, K) + + v = u - 1 + + if dmp_zero_p(c, v): + return f + + n = len(f) + m = n - i - 1 + + if i == n - 1: + return dmp_strip([dmp_add(f[0], c, v, K)] + f[1:], u) + else: + if i >= n: + return [c] + dmp_zeros(i - n, v, K) + f + else: + return f[:m] + [dmp_add(f[m], c, v, K)] + f[m + 1:] + + +def dup_sub_term(f, c, i, K): + """ + Subtract ``c*x**i`` from ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_sub_term(2*x**4 + x**2 - 1, ZZ(2), 4) + x**2 - 1 + + """ + if not c: + return f + + n = len(f) + m = n - i - 1 + + if i == n - 1: + return dup_strip([f[0] - c] + f[1:]) + else: + if i >= n: + return [-c] + [K.zero]*(i - n) + f + else: + return f[:m] + [f[m] - c] + f[m + 1:] + + +def dmp_sub_term(f, c, i, u, K): + """ + Subtract ``c(x_2..x_u)*x_0**i`` from ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_sub_term(2*x**2 + x*y + 1, 2, 2) + x*y + 1 + + """ + if not u: + return dup_add_term(f, -c, i, K) + + v = u - 1 + + if dmp_zero_p(c, v): + return f + + n = len(f) + m = n - i - 1 + + if i == n - 1: + return dmp_strip([dmp_sub(f[0], c, v, K)] + f[1:], u) + else: + if i >= n: + return [dmp_neg(c, v, K)] + dmp_zeros(i - n, v, K) + f + else: + return f[:m] + [dmp_sub(f[m], c, v, K)] + f[m + 1:] + + +def dup_mul_term(f, c, i, K): + """ + Multiply ``f`` by ``c*x**i`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_mul_term(x**2 - 1, ZZ(3), 2) + 3*x**4 - 3*x**2 + + """ + if not c or not f: + return [] + else: + return [ cf * c for cf in f ] + [K.zero]*i + + +def dmp_mul_term(f, c, i, u, K): + """ + Multiply ``f`` by ``c(x_2..x_u)*x_0**i`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_mul_term(x**2*y + x, 3*y, 2) + 3*x**4*y**2 + 3*x**3*y + + """ + if not u: + return dup_mul_term(f, c, i, K) + + v = u - 1 + + if dmp_zero_p(f, u): + return f + if dmp_zero_p(c, v): + return dmp_zero(u) + else: + return [ dmp_mul(cf, c, v, K) for cf in f ] + dmp_zeros(i, v, K) + + +def dup_add_ground(f, c, K): + """ + Add an element of the ground domain to ``f``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_add_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) + x**3 + 2*x**2 + 3*x + 8 + + """ + return dup_add_term(f, c, 0, K) + + +def dmp_add_ground(f, c, u, K): + """ + Add an element of the ground domain to ``f``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_add_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) + x**3 + 2*x**2 + 3*x + 8 + + """ + return dmp_add_term(f, dmp_ground(c, u - 1), 0, u, K) + + +def dup_sub_ground(f, c, K): + """ + Subtract an element of the ground domain from ``f``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_sub_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) + x**3 + 2*x**2 + 3*x + + """ + return dup_sub_term(f, c, 0, K) + + +def dmp_sub_ground(f, c, u, K): + """ + Subtract an element of the ground domain from ``f``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_sub_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) + x**3 + 2*x**2 + 3*x + + """ + return dmp_sub_term(f, dmp_ground(c, u - 1), 0, u, K) + + +def dup_mul_ground(f, c, K): + """ + Multiply ``f`` by a constant value in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_mul_ground(x**2 + 2*x - 1, ZZ(3)) + 3*x**2 + 6*x - 3 + + """ + if not c or not f: + return [] + else: + return [ cf * c for cf in f ] + + +def dmp_mul_ground(f, c, u, K): + """ + Multiply ``f`` by a constant value in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_mul_ground(2*x + 2*y, ZZ(3)) + 6*x + 6*y + + """ + if not u: + return dup_mul_ground(f, c, K) + + v = u - 1 + + return [ dmp_mul_ground(cf, c, v, K) for cf in f ] + + +def dup_quo_ground(f, c, K): + """ + Quotient by a constant in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x = ring("x", ZZ) + >>> R.dup_quo_ground(3*x**2 + 2, ZZ(2)) + x**2 + 1 + + >>> R, x = ring("x", QQ) + >>> R.dup_quo_ground(3*x**2 + 2, QQ(2)) + 3/2*x**2 + 1 + + """ + if not c: + raise ZeroDivisionError('polynomial division') + if not f: + return f + + if K.is_Field: + return [ K.quo(cf, c) for cf in f ] + else: + return [ cf // c for cf in f ] + + +def dmp_quo_ground(f, c, u, K): + """ + Quotient by a constant in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x,y = ring("x,y", ZZ) + >>> R.dmp_quo_ground(2*x**2*y + 3*x, ZZ(2)) + x**2*y + x + + >>> R, x,y = ring("x,y", QQ) + >>> R.dmp_quo_ground(2*x**2*y + 3*x, QQ(2)) + x**2*y + 3/2*x + + """ + if not u: + return dup_quo_ground(f, c, K) + + v = u - 1 + + return [ dmp_quo_ground(cf, c, v, K) for cf in f ] + + +def dup_exquo_ground(f, c, K): + """ + Exact quotient by a constant in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> R.dup_exquo_ground(x**2 + 2, QQ(2)) + 1/2*x**2 + 1 + + """ + if not c: + raise ZeroDivisionError('polynomial division') + if not f: + return f + + return [ K.exquo(cf, c) for cf in f ] + + +def dmp_exquo_ground(f, c, u, K): + """ + Exact quotient by a constant in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) + + >>> R.dmp_exquo_ground(x**2*y + 2*x, QQ(2)) + 1/2*x**2*y + x + + """ + if not u: + return dup_exquo_ground(f, c, K) + + v = u - 1 + + return [ dmp_exquo_ground(cf, c, v, K) for cf in f ] + + +def dup_lshift(f, n, K): + """ + Efficiently multiply ``f`` by ``x**n`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_lshift(x**2 + 1, 2) + x**4 + x**2 + + """ + if not f: + return f + else: + return f + [K.zero]*n + + +def dup_rshift(f, n, K): + """ + Efficiently divide ``f`` by ``x**n`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_rshift(x**4 + x**2, 2) + x**2 + 1 + >>> R.dup_rshift(x**4 + x**2 + 2, 2) + x**2 + 1 + + """ + return f[:-n] + + +def dup_abs(f, K): + """ + Make all coefficients positive in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_abs(x**2 - 1) + x**2 + 1 + + """ + return [ K.abs(coeff) for coeff in f ] + + +def dmp_abs(f, u, K): + """ + Make all coefficients positive in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_abs(x**2*y - x) + x**2*y + x + + """ + if not u: + return dup_abs(f, K) + + v = u - 1 + + return [ dmp_abs(cf, v, K) for cf in f ] + + +def dup_neg(f, K): + """ + Negate a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_neg(x**2 - 1) + -x**2 + 1 + + """ + return [ -coeff for coeff in f ] + + +def dmp_neg(f, u, K): + """ + Negate a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_neg(x**2*y - x) + -x**2*y + x + + """ + if not u: + return dup_neg(f, K) + + v = u - 1 + + return [ dmp_neg(cf, v, K) for cf in f ] + + +def dup_add(f, g, K): + """ + Add dense polynomials in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_add(x**2 - 1, x - 2) + x**2 + x - 3 + + """ + if not f: + return g + if not g: + return f + + df = dup_degree(f) + dg = dup_degree(g) + + if df == dg: + return dup_strip([ a + b for a, b in zip(f, g) ]) + else: + k = abs(df - dg) + + if df > dg: + h, f = f[:k], f[k:] + else: + h, g = g[:k], g[k:] + + return h + [ a + b for a, b in zip(f, g) ] + + +def dmp_add(f, g, u, K): + """ + Add dense polynomials in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_add(x**2 + y, x**2*y + x) + x**2*y + x**2 + x + y + + """ + if not u: + return dup_add(f, g, K) + + df = dmp_degree(f, u) + + if df < 0: + return g + + dg = dmp_degree(g, u) + + if dg < 0: + return f + + v = u - 1 + + if df == dg: + return dmp_strip([ dmp_add(a, b, v, K) for a, b in zip(f, g) ], u) + else: + k = abs(df - dg) + + if df > dg: + h, f = f[:k], f[k:] + else: + h, g = g[:k], g[k:] + + return h + [ dmp_add(a, b, v, K) for a, b in zip(f, g) ] + + +def dup_sub(f, g, K): + """ + Subtract dense polynomials in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_sub(x**2 - 1, x - 2) + x**2 - x + 1 + + """ + if not f: + return dup_neg(g, K) + if not g: + return f + + df = dup_degree(f) + dg = dup_degree(g) + + if df == dg: + return dup_strip([ a - b for a, b in zip(f, g) ]) + else: + k = abs(df - dg) + + if df > dg: + h, f = f[:k], f[k:] + else: + h, g = dup_neg(g[:k], K), g[k:] + + return h + [ a - b for a, b in zip(f, g) ] + + +def dmp_sub(f, g, u, K): + """ + Subtract dense polynomials in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_sub(x**2 + y, x**2*y + x) + -x**2*y + x**2 - x + y + + """ + if not u: + return dup_sub(f, g, K) + + df = dmp_degree(f, u) + + if df < 0: + return dmp_neg(g, u, K) + + dg = dmp_degree(g, u) + + if dg < 0: + return f + + v = u - 1 + + if df == dg: + return dmp_strip([ dmp_sub(a, b, v, K) for a, b in zip(f, g) ], u) + else: + k = abs(df - dg) + + if df > dg: + h, f = f[:k], f[k:] + else: + h, g = dmp_neg(g[:k], u, K), g[k:] + + return h + [ dmp_sub(a, b, v, K) for a, b in zip(f, g) ] + + +def dup_add_mul(f, g, h, K): + """ + Returns ``f + g*h`` where ``f, g, h`` are in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_add_mul(x**2 - 1, x - 2, x + 2) + 2*x**2 - 5 + + """ + return dup_add(f, dup_mul(g, h, K), K) + + +def dmp_add_mul(f, g, h, u, K): + """ + Returns ``f + g*h`` where ``f, g, h`` are in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_add_mul(x**2 + y, x, x + 2) + 2*x**2 + 2*x + y + + """ + return dmp_add(f, dmp_mul(g, h, u, K), u, K) + + +def dup_sub_mul(f, g, h, K): + """ + Returns ``f - g*h`` where ``f, g, h`` are in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_sub_mul(x**2 - 1, x - 2, x + 2) + 3 + + """ + return dup_sub(f, dup_mul(g, h, K), K) + + +def dmp_sub_mul(f, g, h, u, K): + """ + Returns ``f - g*h`` where ``f, g, h`` are in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_sub_mul(x**2 + y, x, x + 2) + -2*x + y + + """ + return dmp_sub(f, dmp_mul(g, h, u, K), u, K) + + +def dup_mul(f, g, K): + """ + Multiply dense polynomials in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_mul(x - 2, x + 2) + x**2 - 4 + + """ + if f == g: + return dup_sqr(f, K) + + if not (f and g): + return [] + + df = dup_degree(f) + dg = dup_degree(g) + + n = max(df, dg) + 1 + + if n < 100 or not K.is_Exact: + h = [] + + for i in range(0, df + dg + 1): + coeff = K.zero + + for j in range(max(0, i - dg), min(df, i) + 1): + coeff += f[j]*g[i - j] + + h.append(coeff) + + return dup_strip(h) + else: + # Use Karatsuba's algorithm (divide and conquer), see e.g.: + # Joris van der Hoeven, Relax But Don't Be Too Lazy, + # J. Symbolic Computation, 11 (2002), section 3.1.1. + n2 = n//2 + + fl, gl = dup_slice(f, 0, n2, K), dup_slice(g, 0, n2, K) + + fh = dup_rshift(dup_slice(f, n2, n, K), n2, K) + gh = dup_rshift(dup_slice(g, n2, n, K), n2, K) + + lo, hi = dup_mul(fl, gl, K), dup_mul(fh, gh, K) + + mid = dup_mul(dup_add(fl, fh, K), dup_add(gl, gh, K), K) + mid = dup_sub(mid, dup_add(lo, hi, K), K) + + return dup_add(dup_add(lo, dup_lshift(mid, n2, K), K), + dup_lshift(hi, 2*n2, K), K) + + +def dmp_mul(f, g, u, K): + """ + Multiply dense polynomials in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_mul(x*y + 1, x) + x**2*y + x + + """ + if not u: + return dup_mul(f, g, K) + + if f == g: + return dmp_sqr(f, u, K) + + df = dmp_degree(f, u) + + if df < 0: + return f + + dg = dmp_degree(g, u) + + if dg < 0: + return g + + h, v = [], u - 1 + + for i in range(0, df + dg + 1): + coeff = dmp_zero(v) + + for j in range(max(0, i - dg), min(df, i) + 1): + coeff = dmp_add(coeff, dmp_mul(f[j], g[i - j], v, K), v, K) + + h.append(coeff) + + return dmp_strip(h, u) + + +def dup_sqr(f, K): + """ + Square dense polynomials in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_sqr(x**2 + 1) + x**4 + 2*x**2 + 1 + + """ + df, h = len(f) - 1, [] + + for i in range(0, 2*df + 1): + c = K.zero + + jmin = max(0, i - df) + jmax = min(i, df) + + n = jmax - jmin + 1 + + jmax = jmin + n // 2 - 1 + + for j in range(jmin, jmax + 1): + c += f[j]*f[i - j] + + c += c + + if n & 1: + elem = f[jmax + 1] + c += elem**2 + + h.append(c) + + return dup_strip(h) + + +def dmp_sqr(f, u, K): + """ + Square dense polynomials in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_sqr(x**2 + x*y + y**2) + x**4 + 2*x**3*y + 3*x**2*y**2 + 2*x*y**3 + y**4 + + """ + if not u: + return dup_sqr(f, K) + + df = dmp_degree(f, u) + + if df < 0: + return f + + h, v = [], u - 1 + + for i in range(0, 2*df + 1): + c = dmp_zero(v) + + jmin = max(0, i - df) + jmax = min(i, df) + + n = jmax - jmin + 1 + + jmax = jmin + n // 2 - 1 + + for j in range(jmin, jmax + 1): + c = dmp_add(c, dmp_mul(f[j], f[i - j], v, K), v, K) + + c = dmp_mul_ground(c, K(2), v, K) + + if n & 1: + elem = dmp_sqr(f[jmax + 1], v, K) + c = dmp_add(c, elem, v, K) + + h.append(c) + + return dmp_strip(h, u) + + +def dup_pow(f, n, K): + """ + Raise ``f`` to the ``n``-th power in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_pow(x - 2, 3) + x**3 - 6*x**2 + 12*x - 8 + + """ + if not n: + return [K.one] + if n < 0: + raise ValueError("Cannot raise polynomial to a negative power") + if n == 1 or not f or f == [K.one]: + return f + + g = [K.one] + + while True: + n, m = n//2, n + + if m % 2: + g = dup_mul(g, f, K) + + if not n: + break + + f = dup_sqr(f, K) + + return g + + +def dmp_pow(f, n, u, K): + """ + Raise ``f`` to the ``n``-th power in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_pow(x*y + 1, 3) + x**3*y**3 + 3*x**2*y**2 + 3*x*y + 1 + + """ + if not u: + return dup_pow(f, n, K) + + if not n: + return dmp_one(u, K) + if n < 0: + raise ValueError("Cannot raise polynomial to a negative power") + if n == 1 or dmp_zero_p(f, u) or dmp_one_p(f, u, K): + return f + + g = dmp_one(u, K) + + while True: + n, m = n//2, n + + if m & 1: + g = dmp_mul(g, f, u, K) + + if not n: + break + + f = dmp_sqr(f, u, K) + + return g + + +def dup_pdiv(f, g, K): + """ + Polynomial pseudo-division in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_pdiv(x**2 + 1, 2*x - 4) + (2*x + 4, 20) + + """ + df = dup_degree(f) + dg = dup_degree(g) + + q, r, dr = [], f, df + + if not g: + raise ZeroDivisionError("polynomial division") + elif df < dg: + return q, r + + N = df - dg + 1 + lc_g = dup_LC(g, K) + + while True: + lc_r = dup_LC(r, K) + j, N = dr - dg, N - 1 + + Q = dup_mul_ground(q, lc_g, K) + q = dup_add_term(Q, lc_r, j, K) + + R = dup_mul_ground(r, lc_g, K) + G = dup_mul_term(g, lc_r, j, K) + r = dup_sub(R, G, K) + + _dr, dr = dr, dup_degree(r) + + if dr < dg: + break + elif not (dr < _dr): + raise PolynomialDivisionFailed(f, g, K) + + c = lc_g**N + + q = dup_mul_ground(q, c, K) + r = dup_mul_ground(r, c, K) + + return q, r + + +def dup_prem(f, g, K): + """ + Polynomial pseudo-remainder in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_prem(x**2 + 1, 2*x - 4) + 20 + + """ + df = dup_degree(f) + dg = dup_degree(g) + + r, dr = f, df + + if not g: + raise ZeroDivisionError("polynomial division") + elif df < dg: + return r + + N = df - dg + 1 + lc_g = dup_LC(g, K) + + while True: + lc_r = dup_LC(r, K) + j, N = dr - dg, N - 1 + + R = dup_mul_ground(r, lc_g, K) + G = dup_mul_term(g, lc_r, j, K) + r = dup_sub(R, G, K) + + _dr, dr = dr, dup_degree(r) + + if dr < dg: + break + elif not (dr < _dr): + raise PolynomialDivisionFailed(f, g, K) + + return dup_mul_ground(r, lc_g**N, K) + + +def dup_pquo(f, g, K): + """ + Polynomial exact pseudo-quotient in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_pquo(x**2 - 1, 2*x - 2) + 2*x + 2 + + >>> R.dup_pquo(x**2 + 1, 2*x - 4) + 2*x + 4 + + """ + return dup_pdiv(f, g, K)[0] + + +def dup_pexquo(f, g, K): + """ + Polynomial pseudo-quotient in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_pexquo(x**2 - 1, 2*x - 2) + 2*x + 2 + + >>> R.dup_pexquo(x**2 + 1, 2*x - 4) + Traceback (most recent call last): + ... + ExactQuotientFailed: [2, -4] does not divide [1, 0, 1] + + """ + q, r = dup_pdiv(f, g, K) + + if not r: + return q + else: + raise ExactQuotientFailed(f, g) + + +def dmp_pdiv(f, g, u, K): + """ + Polynomial pseudo-division in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_pdiv(x**2 + x*y, 2*x + 2) + (2*x + 2*y - 2, -4*y + 4) + + """ + if not u: + return dup_pdiv(f, g, K) + + df = dmp_degree(f, u) + dg = dmp_degree(g, u) + + if dg < 0: + raise ZeroDivisionError("polynomial division") + + q, r, dr = dmp_zero(u), f, df + + if df < dg: + return q, r + + N = df - dg + 1 + lc_g = dmp_LC(g, K) + + while True: + lc_r = dmp_LC(r, K) + j, N = dr - dg, N - 1 + + Q = dmp_mul_term(q, lc_g, 0, u, K) + q = dmp_add_term(Q, lc_r, j, u, K) + + R = dmp_mul_term(r, lc_g, 0, u, K) + G = dmp_mul_term(g, lc_r, j, u, K) + r = dmp_sub(R, G, u, K) + + _dr, dr = dr, dmp_degree(r, u) + + if dr < dg: + break + elif not (dr < _dr): + raise PolynomialDivisionFailed(f, g, K) + + c = dmp_pow(lc_g, N, u - 1, K) + + q = dmp_mul_term(q, c, 0, u, K) + r = dmp_mul_term(r, c, 0, u, K) + + return q, r + + +def dmp_prem(f, g, u, K): + """ + Polynomial pseudo-remainder in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_prem(x**2 + x*y, 2*x + 2) + -4*y + 4 + + """ + if not u: + return dup_prem(f, g, K) + + df = dmp_degree(f, u) + dg = dmp_degree(g, u) + + if dg < 0: + raise ZeroDivisionError("polynomial division") + + r, dr = f, df + + if df < dg: + return r + + N = df - dg + 1 + lc_g = dmp_LC(g, K) + + while True: + lc_r = dmp_LC(r, K) + j, N = dr - dg, N - 1 + + R = dmp_mul_term(r, lc_g, 0, u, K) + G = dmp_mul_term(g, lc_r, j, u, K) + r = dmp_sub(R, G, u, K) + + _dr, dr = dr, dmp_degree(r, u) + + if dr < dg: + break + elif not (dr < _dr): + raise PolynomialDivisionFailed(f, g, K) + + c = dmp_pow(lc_g, N, u - 1, K) + + return dmp_mul_term(r, c, 0, u, K) + + +def dmp_pquo(f, g, u, K): + """ + Polynomial exact pseudo-quotient in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x**2 + x*y + >>> g = 2*x + 2*y + >>> h = 2*x + 2 + + >>> R.dmp_pquo(f, g) + 2*x + + >>> R.dmp_pquo(f, h) + 2*x + 2*y - 2 + + """ + return dmp_pdiv(f, g, u, K)[0] + + +def dmp_pexquo(f, g, u, K): + """ + Polynomial pseudo-quotient in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x**2 + x*y + >>> g = 2*x + 2*y + >>> h = 2*x + 2 + + >>> R.dmp_pexquo(f, g) + 2*x + + >>> R.dmp_pexquo(f, h) + Traceback (most recent call last): + ... + ExactQuotientFailed: [[2], [2]] does not divide [[1], [1, 0], []] + + """ + q, r = dmp_pdiv(f, g, u, K) + + if dmp_zero_p(r, u): + return q + else: + raise ExactQuotientFailed(f, g) + + +def dup_rr_div(f, g, K): + """ + Univariate division with remainder over a ring. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_rr_div(x**2 + 1, 2*x - 4) + (0, x**2 + 1) + + """ + df = dup_degree(f) + dg = dup_degree(g) + + q, r, dr = [], f, df + + if not g: + raise ZeroDivisionError("polynomial division") + elif df < dg: + return q, r + + lc_g = dup_LC(g, K) + + while True: + lc_r = dup_LC(r, K) + + if lc_r % lc_g: + break + + c = K.exquo(lc_r, lc_g) + j = dr - dg + + q = dup_add_term(q, c, j, K) + h = dup_mul_term(g, c, j, K) + r = dup_sub(r, h, K) + + _dr, dr = dr, dup_degree(r) + + if dr < dg: + break + elif not (dr < _dr): + raise PolynomialDivisionFailed(f, g, K) + + return q, r + + +def dmp_rr_div(f, g, u, K): + """ + Multivariate division with remainder over a ring. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_rr_div(x**2 + x*y, 2*x + 2) + (0, x**2 + x*y) + + """ + if not u: + return dup_rr_div(f, g, K) + + df = dmp_degree(f, u) + dg = dmp_degree(g, u) + + if dg < 0: + raise ZeroDivisionError("polynomial division") + + q, r, dr = dmp_zero(u), f, df + + if df < dg: + return q, r + + lc_g, v = dmp_LC(g, K), u - 1 + + while True: + lc_r = dmp_LC(r, K) + c, R = dmp_rr_div(lc_r, lc_g, v, K) + + if not dmp_zero_p(R, v): + break + + j = dr - dg + + q = dmp_add_term(q, c, j, u, K) + h = dmp_mul_term(g, c, j, u, K) + r = dmp_sub(r, h, u, K) + + _dr, dr = dr, dmp_degree(r, u) + + if dr < dg: + break + elif not (dr < _dr): + raise PolynomialDivisionFailed(f, g, K) + + return q, r + + +def dup_ff_div(f, g, K): + """ + Polynomial division with remainder over a field. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> R.dup_ff_div(x**2 + 1, 2*x - 4) + (1/2*x + 1, 5) + + """ + df = dup_degree(f) + dg = dup_degree(g) + + q, r, dr = [], f, df + + if not g: + raise ZeroDivisionError("polynomial division") + elif df < dg: + return q, r + + lc_g = dup_LC(g, K) + + while True: + lc_r = dup_LC(r, K) + + c = K.exquo(lc_r, lc_g) + j = dr - dg + + q = dup_add_term(q, c, j, K) + h = dup_mul_term(g, c, j, K) + r = dup_sub(r, h, K) + + _dr, dr = dr, dup_degree(r) + + if dr < dg: + break + elif dr == _dr and not K.is_Exact: + # remove leading term created by rounding error + r = dup_strip(r[1:]) + dr = dup_degree(r) + if dr < dg: + break + elif not (dr < _dr): + raise PolynomialDivisionFailed(f, g, K) + + return q, r + + +def dmp_ff_div(f, g, u, K): + """ + Polynomial division with remainder over a field. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) + + >>> R.dmp_ff_div(x**2 + x*y, 2*x + 2) + (1/2*x + 1/2*y - 1/2, -y + 1) + + """ + if not u: + return dup_ff_div(f, g, K) + + df = dmp_degree(f, u) + dg = dmp_degree(g, u) + + if dg < 0: + raise ZeroDivisionError("polynomial division") + + q, r, dr = dmp_zero(u), f, df + + if df < dg: + return q, r + + lc_g, v = dmp_LC(g, K), u - 1 + + while True: + lc_r = dmp_LC(r, K) + c, R = dmp_ff_div(lc_r, lc_g, v, K) + + if not dmp_zero_p(R, v): + break + + j = dr - dg + + q = dmp_add_term(q, c, j, u, K) + h = dmp_mul_term(g, c, j, u, K) + r = dmp_sub(r, h, u, K) + + _dr, dr = dr, dmp_degree(r, u) + + if dr < dg: + break + elif not (dr < _dr): + raise PolynomialDivisionFailed(f, g, K) + + return q, r + + +def dup_div(f, g, K): + """ + Polynomial division with remainder in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x = ring("x", ZZ) + >>> R.dup_div(x**2 + 1, 2*x - 4) + (0, x**2 + 1) + + >>> R, x = ring("x", QQ) + >>> R.dup_div(x**2 + 1, 2*x - 4) + (1/2*x + 1, 5) + + """ + if K.is_Field: + return dup_ff_div(f, g, K) + else: + return dup_rr_div(f, g, K) + + +def dup_rem(f, g, K): + """ + Returns polynomial remainder in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x = ring("x", ZZ) + >>> R.dup_rem(x**2 + 1, 2*x - 4) + x**2 + 1 + + >>> R, x = ring("x", QQ) + >>> R.dup_rem(x**2 + 1, 2*x - 4) + 5 + + """ + return dup_div(f, g, K)[1] + + +def dup_quo(f, g, K): + """ + Returns exact polynomial quotient in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x = ring("x", ZZ) + >>> R.dup_quo(x**2 + 1, 2*x - 4) + 0 + + >>> R, x = ring("x", QQ) + >>> R.dup_quo(x**2 + 1, 2*x - 4) + 1/2*x + 1 + + """ + return dup_div(f, g, K)[0] + + +def dup_exquo(f, g, K): + """ + Returns polynomial quotient in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_exquo(x**2 - 1, x - 1) + x + 1 + + >>> R.dup_exquo(x**2 + 1, 2*x - 4) + Traceback (most recent call last): + ... + ExactQuotientFailed: [2, -4] does not divide [1, 0, 1] + + """ + q, r = dup_div(f, g, K) + + if not r: + return q + else: + raise ExactQuotientFailed(f, g) + + +def dmp_div(f, g, u, K): + """ + Polynomial division with remainder in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x,y = ring("x,y", ZZ) + >>> R.dmp_div(x**2 + x*y, 2*x + 2) + (0, x**2 + x*y) + + >>> R, x,y = ring("x,y", QQ) + >>> R.dmp_div(x**2 + x*y, 2*x + 2) + (1/2*x + 1/2*y - 1/2, -y + 1) + + """ + if K.is_Field: + return dmp_ff_div(f, g, u, K) + else: + return dmp_rr_div(f, g, u, K) + + +def dmp_rem(f, g, u, K): + """ + Returns polynomial remainder in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x,y = ring("x,y", ZZ) + >>> R.dmp_rem(x**2 + x*y, 2*x + 2) + x**2 + x*y + + >>> R, x,y = ring("x,y", QQ) + >>> R.dmp_rem(x**2 + x*y, 2*x + 2) + -y + 1 + + """ + return dmp_div(f, g, u, K)[1] + + +def dmp_quo(f, g, u, K): + """ + Returns exact polynomial quotient in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x,y = ring("x,y", ZZ) + >>> R.dmp_quo(x**2 + x*y, 2*x + 2) + 0 + + >>> R, x,y = ring("x,y", QQ) + >>> R.dmp_quo(x**2 + x*y, 2*x + 2) + 1/2*x + 1/2*y - 1/2 + + """ + return dmp_div(f, g, u, K)[0] + + +def dmp_exquo(f, g, u, K): + """ + Returns polynomial quotient in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x**2 + x*y + >>> g = x + y + >>> h = 2*x + 2 + + >>> R.dmp_exquo(f, g) + x + + >>> R.dmp_exquo(f, h) + Traceback (most recent call last): + ... + ExactQuotientFailed: [[2], [2]] does not divide [[1], [1, 0], []] + + """ + q, r = dmp_div(f, g, u, K) + + if dmp_zero_p(r, u): + return q + else: + raise ExactQuotientFailed(f, g) + + +def dup_max_norm(f, K): + """ + Returns maximum norm of a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_max_norm(-x**2 + 2*x - 3) + 3 + + """ + if not f: + return K.zero + else: + return max(dup_abs(f, K)) + + +def dmp_max_norm(f, u, K): + """ + Returns maximum norm of a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_max_norm(2*x*y - x - 3) + 3 + + """ + if not u: + return dup_max_norm(f, K) + + v = u - 1 + + return max(dmp_max_norm(c, v, K) for c in f) + + +def dup_l1_norm(f, K): + """ + Returns l1 norm of a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_l1_norm(2*x**3 - 3*x**2 + 1) + 6 + + """ + if not f: + return K.zero + else: + return sum(dup_abs(f, K)) + + +def dmp_l1_norm(f, u, K): + """ + Returns l1 norm of a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_l1_norm(2*x*y - x - 3) + 6 + + """ + if not u: + return dup_l1_norm(f, K) + + v = u - 1 + + return sum(dmp_l1_norm(c, v, K) for c in f) + + +def dup_l2_norm_squared(f, K): + """ + Returns squared l2 norm of a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_l2_norm_squared(2*x**3 - 3*x**2 + 1) + 14 + + """ + return sum([coeff**2 for coeff in f], K.zero) + + +def dmp_l2_norm_squared(f, u, K): + """ + Returns squared l2 norm of a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_l2_norm_squared(2*x*y - x - 3) + 14 + + """ + if not u: + return dup_l2_norm_squared(f, K) + + v = u - 1 + + return sum(dmp_l2_norm_squared(c, v, K) for c in f) + + +def dup_expand(polys, K): + """ + Multiply together several polynomials in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_expand([x**2 - 1, x, 2]) + 2*x**3 - 2*x + + """ + if not polys: + return [K.one] + + f = polys[0] + + for g in polys[1:]: + f = dup_mul(f, g, K) + + return f + + +def dmp_expand(polys, u, K): + """ + Multiply together several polynomials in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_expand([x**2 + y**2, x + 1]) + x**3 + x**2 + x*y**2 + y**2 + + """ + if not polys: + return dmp_one(u, K) + + f = polys[0] + + for g in polys[1:]: + f = dmp_mul(f, g, u, K) + + return f diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densebasic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densebasic.py new file mode 100644 index 0000000000000000000000000000000000000000..b3a8a9497302b1af5bca20de100b7ae41e96b439 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densebasic.py @@ -0,0 +1,1887 @@ +"""Basic tools for dense recursive polynomials in ``K[x]`` or ``K[X]``. """ + + +from sympy.core import igcd +from sympy.polys.monomials import monomial_min, monomial_div +from sympy.polys.orderings import monomial_key + +import random + + +ninf = float('-inf') + + +def poly_LC(f, K): + """ + Return leading coefficient of ``f``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import poly_LC + + >>> poly_LC([], ZZ) + 0 + >>> poly_LC([ZZ(1), ZZ(2), ZZ(3)], ZZ) + 1 + + """ + if not f: + return K.zero + else: + return f[0] + + +def poly_TC(f, K): + """ + Return trailing coefficient of ``f``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import poly_TC + + >>> poly_TC([], ZZ) + 0 + >>> poly_TC([ZZ(1), ZZ(2), ZZ(3)], ZZ) + 3 + + """ + if not f: + return K.zero + else: + return f[-1] + +dup_LC = dmp_LC = poly_LC +dup_TC = dmp_TC = poly_TC + + +def dmp_ground_LC(f, u, K): + """ + Return the ground leading coefficient. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_ground_LC + + >>> f = ZZ.map([[[1], [2, 3]]]) + + >>> dmp_ground_LC(f, 2, ZZ) + 1 + + """ + while u: + f = dmp_LC(f, K) + u -= 1 + + return dup_LC(f, K) + + +def dmp_ground_TC(f, u, K): + """ + Return the ground trailing coefficient. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_ground_TC + + >>> f = ZZ.map([[[1], [2, 3]]]) + + >>> dmp_ground_TC(f, 2, ZZ) + 3 + + """ + while u: + f = dmp_TC(f, K) + u -= 1 + + return dup_TC(f, K) + + +def dmp_true_LT(f, u, K): + """ + Return the leading term ``c * x_1**n_1 ... x_k**n_k``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_true_LT + + >>> f = ZZ.map([[4], [2, 0], [3, 0, 0]]) + + >>> dmp_true_LT(f, 1, ZZ) + ((2, 0), 4) + + """ + monom = [] + + while u: + monom.append(len(f) - 1) + f, u = f[0], u - 1 + + if not f: + monom.append(0) + else: + monom.append(len(f) - 1) + + return tuple(monom), dup_LC(f, K) + + +def dup_degree(f): + """ + Return the leading degree of ``f`` in ``K[x]``. + + Note that the degree of 0 is negative infinity (``float('-inf')``). + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_degree + + >>> f = ZZ.map([1, 2, 0, 3]) + + >>> dup_degree(f) + 3 + + """ + if not f: + return ninf + return len(f) - 1 + + +def dmp_degree(f, u): + """ + Return the leading degree of ``f`` in ``x_0`` in ``K[X]``. + + Note that the degree of 0 is negative infinity (``float('-inf')``). + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_degree + + >>> dmp_degree([[[]]], 2) + -inf + + >>> f = ZZ.map([[2], [1, 2, 3]]) + + >>> dmp_degree(f, 1) + 1 + + """ + if dmp_zero_p(f, u): + return ninf + else: + return len(f) - 1 + + +def _rec_degree_in(g, v, i, j): + """Recursive helper function for :func:`dmp_degree_in`.""" + if i == j: + return dmp_degree(g, v) + + v, i = v - 1, i + 1 + + return max(_rec_degree_in(c, v, i, j) for c in g) + + +def dmp_degree_in(f, j, u): + """ + Return the leading degree of ``f`` in ``x_j`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_degree_in + + >>> f = ZZ.map([[2], [1, 2, 3]]) + + >>> dmp_degree_in(f, 0, 1) + 1 + >>> dmp_degree_in(f, 1, 1) + 2 + + """ + if not j: + return dmp_degree(f, u) + if j < 0 or j > u: + raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) + + return _rec_degree_in(f, u, 0, j) + + +def _rec_degree_list(g, v, i, degs): + """Recursive helper for :func:`dmp_degree_list`.""" + degs[i] = max(degs[i], dmp_degree(g, v)) + + if v > 0: + v, i = v - 1, i + 1 + + for c in g: + _rec_degree_list(c, v, i, degs) + + +def dmp_degree_list(f, u): + """ + Return a list of degrees of ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_degree_list + + >>> f = ZZ.map([[1], [1, 2, 3]]) + + >>> dmp_degree_list(f, 1) + (1, 2) + + """ + degs = [ninf]*(u + 1) + _rec_degree_list(f, u, 0, degs) + return tuple(degs) + + +def dup_strip(f): + """ + Remove leading zeros from ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.densebasic import dup_strip + + >>> dup_strip([0, 0, 1, 2, 3, 0]) + [1, 2, 3, 0] + + """ + if not f or f[0]: + return f + + i = 0 + + for cf in f: + if cf: + break + else: + i += 1 + + return f[i:] + + +def dmp_strip(f, u): + """ + Remove leading zeros from ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.densebasic import dmp_strip + + >>> dmp_strip([[], [0, 1, 2], [1]], 1) + [[0, 1, 2], [1]] + + """ + if not u: + return dup_strip(f) + + if dmp_zero_p(f, u): + return f + + i, v = 0, u - 1 + + for c in f: + if not dmp_zero_p(c, v): + break + else: + i += 1 + + if i == len(f): + return dmp_zero(u) + else: + return f[i:] + + +def _rec_validate(f, g, i, K): + """Recursive helper for :func:`dmp_validate`.""" + if not isinstance(g, list): + if K is not None and not K.of_type(g): + raise TypeError("%s in %s in not of type %s" % (g, f, K.dtype)) + + return {i - 1} + elif not g: + return {i} + else: + levels = set() + + for c in g: + levels |= _rec_validate(f, c, i + 1, K) + + return levels + + +def _rec_strip(g, v): + """Recursive helper for :func:`_rec_strip`.""" + if not v: + return dup_strip(g) + + w = v - 1 + + return dmp_strip([ _rec_strip(c, w) for c in g ], v) + + +def dmp_validate(f, K=None): + """ + Return the number of levels in ``f`` and recursively strip it. + + Examples + ======== + + >>> from sympy.polys.densebasic import dmp_validate + + >>> dmp_validate([[], [0, 1, 2], [1]]) + ([[1, 2], [1]], 1) + + >>> dmp_validate([[1], 1]) + Traceback (most recent call last): + ... + ValueError: invalid data structure for a multivariate polynomial + + """ + levels = _rec_validate(f, f, 0, K) + + u = levels.pop() + + if not levels: + return _rec_strip(f, u), u + else: + raise ValueError( + "invalid data structure for a multivariate polynomial") + + +def dup_reverse(f): + """ + Compute ``x**n * f(1/x)``, i.e.: reverse ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_reverse + + >>> f = ZZ.map([1, 2, 3, 0]) + + >>> dup_reverse(f) + [3, 2, 1] + + """ + return dup_strip(list(reversed(f))) + + +def dup_copy(f): + """ + Create a new copy of a polynomial ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_copy + + >>> f = ZZ.map([1, 2, 3, 0]) + + >>> dup_copy([1, 2, 3, 0]) + [1, 2, 3, 0] + + """ + return list(f) + + +def dmp_copy(f, u): + """ + Create a new copy of a polynomial ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_copy + + >>> f = ZZ.map([[1], [1, 2]]) + + >>> dmp_copy(f, 1) + [[1], [1, 2]] + + """ + if not u: + return list(f) + + v = u - 1 + + return [ dmp_copy(c, v) for c in f ] + + +def dup_to_tuple(f): + """ + Convert `f` into a tuple. + + This is needed for hashing. This is similar to dup_copy(). + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_copy + + >>> f = ZZ.map([1, 2, 3, 0]) + + >>> dup_copy([1, 2, 3, 0]) + [1, 2, 3, 0] + + """ + return tuple(f) + + +def dmp_to_tuple(f, u): + """ + Convert `f` into a nested tuple of tuples. + + This is needed for hashing. This is similar to dmp_copy(). + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_to_tuple + + >>> f = ZZ.map([[1], [1, 2]]) + + >>> dmp_to_tuple(f, 1) + ((1,), (1, 2)) + + """ + if not u: + return tuple(f) + v = u - 1 + + return tuple(dmp_to_tuple(c, v) for c in f) + + +def dup_normal(f, K): + """ + Normalize univariate polynomial in the given domain. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_normal + + >>> dup_normal([0, 1, 2, 3], ZZ) + [1, 2, 3] + + """ + return dup_strip([ K.normal(c) for c in f ]) + + +def dmp_normal(f, u, K): + """ + Normalize a multivariate polynomial in the given domain. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_normal + + >>> dmp_normal([[], [0, 1, 2]], 1, ZZ) + [[1, 2]] + + """ + if not u: + return dup_normal(f, K) + + v = u - 1 + + return dmp_strip([ dmp_normal(c, v, K) for c in f ], u) + + +def dup_convert(f, K0, K1): + """ + Convert the ground domain of ``f`` from ``K0`` to ``K1``. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_convert + + >>> R, x = ring("x", ZZ) + + >>> dup_convert([R(1), R(2)], R.to_domain(), ZZ) + [1, 2] + >>> dup_convert([ZZ(1), ZZ(2)], ZZ, R.to_domain()) + [1, 2] + + """ + if K0 is not None and K0 == K1: + return f + else: + return dup_strip([ K1.convert(c, K0) for c in f ]) + + +def dmp_convert(f, u, K0, K1): + """ + Convert the ground domain of ``f`` from ``K0`` to ``K1``. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_convert + + >>> R, x = ring("x", ZZ) + + >>> dmp_convert([[R(1)], [R(2)]], 1, R.to_domain(), ZZ) + [[1], [2]] + >>> dmp_convert([[ZZ(1)], [ZZ(2)]], 1, ZZ, R.to_domain()) + [[1], [2]] + + """ + if not u: + return dup_convert(f, K0, K1) + if K0 is not None and K0 == K1: + return f + + v = u - 1 + + return dmp_strip([ dmp_convert(c, v, K0, K1) for c in f ], u) + + +def dup_from_sympy(f, K): + """ + Convert the ground domain of ``f`` from SymPy to ``K``. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_from_sympy + + >>> dup_from_sympy([S(1), S(2)], ZZ) == [ZZ(1), ZZ(2)] + True + + """ + return dup_strip([ K.from_sympy(c) for c in f ]) + + +def dmp_from_sympy(f, u, K): + """ + Convert the ground domain of ``f`` from SymPy to ``K``. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_from_sympy + + >>> dmp_from_sympy([[S(1)], [S(2)]], 1, ZZ) == [[ZZ(1)], [ZZ(2)]] + True + + """ + if not u: + return dup_from_sympy(f, K) + + v = u - 1 + + return dmp_strip([ dmp_from_sympy(c, v, K) for c in f ], u) + + +def dup_nth(f, n, K): + """ + Return the ``n``-th coefficient of ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_nth + + >>> f = ZZ.map([1, 2, 3]) + + >>> dup_nth(f, 0, ZZ) + 3 + >>> dup_nth(f, 4, ZZ) + 0 + + """ + if n < 0: + raise IndexError("'n' must be non-negative, got %i" % n) + elif n >= len(f): + return K.zero + else: + return f[dup_degree(f) - n] + + +def dmp_nth(f, n, u, K): + """ + Return the ``n``-th coefficient of ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_nth + + >>> f = ZZ.map([[1], [2], [3]]) + + >>> dmp_nth(f, 0, 1, ZZ) + [3] + >>> dmp_nth(f, 4, 1, ZZ) + [] + + """ + if n < 0: + raise IndexError("'n' must be non-negative, got %i" % n) + elif n >= len(f): + return dmp_zero(u - 1) + else: + return f[dmp_degree(f, u) - n] + + +def dmp_ground_nth(f, N, u, K): + """ + Return the ground ``n``-th coefficient of ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_ground_nth + + >>> f = ZZ.map([[1], [2, 3]]) + + >>> dmp_ground_nth(f, (0, 1), 1, ZZ) + 2 + + """ + v = u + + for n in N: + if n < 0: + raise IndexError("`n` must be non-negative, got %i" % n) + elif n >= len(f): + return K.zero + else: + d = dmp_degree(f, v) + if d == ninf: + d = -1 + f, v = f[d - n], v - 1 + + return f + + +def dmp_zero_p(f, u): + """ + Return ``True`` if ``f`` is zero in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.densebasic import dmp_zero_p + + >>> dmp_zero_p([[[[[]]]]], 4) + True + >>> dmp_zero_p([[[[[1]]]]], 4) + False + + """ + while u: + if len(f) != 1: + return False + + f = f[0] + u -= 1 + + return not f + + +def dmp_zero(u): + """ + Return a multivariate zero. + + Examples + ======== + + >>> from sympy.polys.densebasic import dmp_zero + + >>> dmp_zero(4) + [[[[[]]]]] + + """ + r = [] + + for i in range(u): + r = [r] + + return r + + +def dmp_one_p(f, u, K): + """ + Return ``True`` if ``f`` is one in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_one_p + + >>> dmp_one_p([[[ZZ(1)]]], 2, ZZ) + True + + """ + return dmp_ground_p(f, K.one, u) + + +def dmp_one(u, K): + """ + Return a multivariate one over ``K``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_one + + >>> dmp_one(2, ZZ) + [[[1]]] + + """ + return dmp_ground(K.one, u) + + +def dmp_ground_p(f, c, u): + """ + Return True if ``f`` is constant in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.densebasic import dmp_ground_p + + >>> dmp_ground_p([[[3]]], 3, 2) + True + >>> dmp_ground_p([[[4]]], None, 2) + True + + """ + if c is not None and not c: + return dmp_zero_p(f, u) + + while u: + if len(f) != 1: + return False + f = f[0] + u -= 1 + + if c is None: + return len(f) <= 1 + else: + return f == [c] + + +def dmp_ground(c, u): + """ + Return a multivariate constant. + + Examples + ======== + + >>> from sympy.polys.densebasic import dmp_ground + + >>> dmp_ground(3, 5) + [[[[[[3]]]]]] + >>> dmp_ground(1, -1) + 1 + + """ + if not c: + return dmp_zero(u) + + for i in range(u + 1): + c = [c] + + return c + + +def dmp_zeros(n, u, K): + """ + Return a list of multivariate zeros. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_zeros + + >>> dmp_zeros(3, 2, ZZ) + [[[[]]], [[[]]], [[[]]]] + >>> dmp_zeros(3, -1, ZZ) + [0, 0, 0] + + """ + if not n: + return [] + + if u < 0: + return [K.zero]*n + else: + return [ dmp_zero(u) for i in range(n) ] + + +def dmp_grounds(c, n, u): + """ + Return a list of multivariate constants. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_grounds + + >>> dmp_grounds(ZZ(4), 3, 2) + [[[[4]]], [[[4]]], [[[4]]]] + >>> dmp_grounds(ZZ(4), 3, -1) + [4, 4, 4] + + """ + if not n: + return [] + + if u < 0: + return [c]*n + else: + return [ dmp_ground(c, u) for i in range(n) ] + + +def dmp_negative_p(f, u, K): + """ + Return ``True`` if ``LC(f)`` is negative. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_negative_p + + >>> dmp_negative_p([[ZZ(1)], [-ZZ(1)]], 1, ZZ) + False + >>> dmp_negative_p([[-ZZ(1)], [ZZ(1)]], 1, ZZ) + True + + """ + return K.is_negative(dmp_ground_LC(f, u, K)) + + +def dmp_positive_p(f, u, K): + """ + Return ``True`` if ``LC(f)`` is positive. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_positive_p + + >>> dmp_positive_p([[ZZ(1)], [-ZZ(1)]], 1, ZZ) + True + >>> dmp_positive_p([[-ZZ(1)], [ZZ(1)]], 1, ZZ) + False + + """ + return K.is_positive(dmp_ground_LC(f, u, K)) + + +def dup_from_dict(f, K): + """ + Create a ``K[x]`` polynomial from a ``dict``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_from_dict + + >>> dup_from_dict({(0,): ZZ(7), (2,): ZZ(5), (4,): ZZ(1)}, ZZ) + [1, 0, 5, 0, 7] + >>> dup_from_dict({}, ZZ) + [] + + """ + if not f: + return [] + + n, h = max(f.keys()), [] + + if isinstance(n, int): + for k in range(n, -1, -1): + h.append(f.get(k, K.zero)) + else: + (n,) = n + + for k in range(n, -1, -1): + h.append(f.get((k,), K.zero)) + + return dup_strip(h) + + +def dup_from_raw_dict(f, K): + """ + Create a ``K[x]`` polynomial from a raw ``dict``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_from_raw_dict + + >>> dup_from_raw_dict({0: ZZ(7), 2: ZZ(5), 4: ZZ(1)}, ZZ) + [1, 0, 5, 0, 7] + + """ + if not f: + return [] + + n, h = max(f.keys()), [] + + for k in range(n, -1, -1): + h.append(f.get(k, K.zero)) + + return dup_strip(h) + + +def dmp_from_dict(f, u, K): + """ + Create a ``K[X]`` polynomial from a ``dict``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_from_dict + + >>> dmp_from_dict({(0, 0): ZZ(3), (0, 1): ZZ(2), (2, 1): ZZ(1)}, 1, ZZ) + [[1, 0], [], [2, 3]] + >>> dmp_from_dict({}, 0, ZZ) + [] + + """ + if not u: + return dup_from_dict(f, K) + if not f: + return dmp_zero(u) + + coeffs = {} + + for monom, coeff in f.items(): + head, tail = monom[0], monom[1:] + + if head in coeffs: + coeffs[head][tail] = coeff + else: + coeffs[head] = { tail: coeff } + + n, v, h = max(coeffs.keys()), u - 1, [] + + for k in range(n, -1, -1): + coeff = coeffs.get(k) + + if coeff is not None: + h.append(dmp_from_dict(coeff, v, K)) + else: + h.append(dmp_zero(v)) + + return dmp_strip(h, u) + + +def dup_to_dict(f, K=None, zero=False): + """ + Convert ``K[x]`` polynomial to a ``dict``. + + Examples + ======== + + >>> from sympy.polys.densebasic import dup_to_dict + + >>> dup_to_dict([1, 0, 5, 0, 7]) + {(0,): 7, (2,): 5, (4,): 1} + >>> dup_to_dict([]) + {} + + """ + if not f and zero: + return {(0,): K.zero} + + n, result = len(f) - 1, {} + + for k in range(0, n + 1): + if f[n - k]: + result[(k,)] = f[n - k] + + return result + + +def dup_to_raw_dict(f, K=None, zero=False): + """ + Convert a ``K[x]`` polynomial to a raw ``dict``. + + Examples + ======== + + >>> from sympy.polys.densebasic import dup_to_raw_dict + + >>> dup_to_raw_dict([1, 0, 5, 0, 7]) + {0: 7, 2: 5, 4: 1} + + """ + if not f and zero: + return {0: K.zero} + + n, result = len(f) - 1, {} + + for k in range(0, n + 1): + if f[n - k]: + result[k] = f[n - k] + + return result + + +def dmp_to_dict(f, u, K=None, zero=False): + """ + Convert a ``K[X]`` polynomial to a ``dict````. + + Examples + ======== + + >>> from sympy.polys.densebasic import dmp_to_dict + + >>> dmp_to_dict([[1, 0], [], [2, 3]], 1) + {(0, 0): 3, (0, 1): 2, (2, 1): 1} + >>> dmp_to_dict([], 0) + {} + + """ + if not u: + return dup_to_dict(f, K, zero=zero) + + if dmp_zero_p(f, u) and zero: + return {(0,)*(u + 1): K.zero} + + n, v, result = dmp_degree(f, u), u - 1, {} + + if n == ninf: + n = -1 + + for k in range(0, n + 1): + h = dmp_to_dict(f[n - k], v) + + for exp, coeff in h.items(): + result[(k,) + exp] = coeff + + return result + + +def dmp_swap(f, i, j, u, K): + """ + Transform ``K[..x_i..x_j..]`` to ``K[..x_j..x_i..]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_swap + + >>> f = ZZ.map([[[2], [1, 0]], []]) + + >>> dmp_swap(f, 0, 1, 2, ZZ) + [[[2], []], [[1, 0], []]] + >>> dmp_swap(f, 1, 2, 2, ZZ) + [[[1], [2, 0]], [[]]] + >>> dmp_swap(f, 0, 2, 2, ZZ) + [[[1, 0]], [[2, 0], []]] + + """ + if i < 0 or j < 0 or i > u or j > u: + raise IndexError("0 <= i < j <= %s expected" % u) + elif i == j: + return f + + F, H = dmp_to_dict(f, u), {} + + for exp, coeff in F.items(): + H[exp[:i] + (exp[j],) + + exp[i + 1:j] + + (exp[i],) + exp[j + 1:]] = coeff + + return dmp_from_dict(H, u, K) + + +def dmp_permute(f, P, u, K): + """ + Return a polynomial in ``K[x_{P(1)},..,x_{P(n)}]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_permute + + >>> f = ZZ.map([[[2], [1, 0]], []]) + + >>> dmp_permute(f, [1, 0, 2], 2, ZZ) + [[[2], []], [[1, 0], []]] + >>> dmp_permute(f, [1, 2, 0], 2, ZZ) + [[[1], []], [[2, 0], []]] + + """ + F, H = dmp_to_dict(f, u), {} + + for exp, coeff in F.items(): + new_exp = [0]*len(exp) + + for e, p in zip(exp, P): + new_exp[p] = e + + H[tuple(new_exp)] = coeff + + return dmp_from_dict(H, u, K) + + +def dmp_nest(f, l, K): + """ + Return a multivariate value nested ``l``-levels. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_nest + + >>> dmp_nest([[ZZ(1)]], 2, ZZ) + [[[[1]]]] + + """ + if not isinstance(f, list): + return dmp_ground(f, l) + + for i in range(l): + f = [f] + + return f + + +def dmp_raise(f, l, u, K): + """ + Return a multivariate polynomial raised ``l``-levels. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_raise + + >>> f = ZZ.map([[], [1, 2]]) + + >>> dmp_raise(f, 2, 1, ZZ) + [[[[]]], [[[1]], [[2]]]] + + """ + if not l: + return f + + if not u: + if not f: + return dmp_zero(l) + + k = l - 1 + + return [ dmp_ground(c, k) for c in f ] + + v = u - 1 + + return [ dmp_raise(c, l, v, K) for c in f ] + + +def dup_deflate(f, K): + """ + Map ``x**m`` to ``y`` in a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_deflate + + >>> f = ZZ.map([1, 0, 0, 1, 0, 0, 1]) + + >>> dup_deflate(f, ZZ) + (3, [1, 1, 1]) + + """ + if dup_degree(f) <= 0: + return 1, f + + g = 0 + + for i in range(len(f)): + if not f[-i - 1]: + continue + + g = igcd(g, i) + + if g == 1: + return 1, f + + return g, f[::g] + + +def dmp_deflate(f, u, K): + """ + Map ``x_i**m_i`` to ``y_i`` in a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_deflate + + >>> f = ZZ.map([[1, 0, 0, 2], [], [3, 0, 0, 4]]) + + >>> dmp_deflate(f, 1, ZZ) + ((2, 3), [[1, 2], [3, 4]]) + + """ + if dmp_zero_p(f, u): + return (1,)*(u + 1), f + + F = dmp_to_dict(f, u) + B = [0]*(u + 1) + + for M in F.keys(): + for i, m in enumerate(M): + B[i] = igcd(B[i], m) + + for i, b in enumerate(B): + if not b: + B[i] = 1 + + B = tuple(B) + + if all(b == 1 for b in B): + return B, f + + H = {} + + for A, coeff in F.items(): + N = [ a // b for a, b in zip(A, B) ] + H[tuple(N)] = coeff + + return B, dmp_from_dict(H, u, K) + + +def dup_multi_deflate(polys, K): + """ + Map ``x**m`` to ``y`` in a set of polynomials in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_multi_deflate + + >>> f = ZZ.map([1, 0, 2, 0, 3]) + >>> g = ZZ.map([4, 0, 0]) + + >>> dup_multi_deflate((f, g), ZZ) + (2, ([1, 2, 3], [4, 0])) + + """ + G = 0 + + for p in polys: + if dup_degree(p) <= 0: + return 1, polys + + g = 0 + + for i in range(len(p)): + if not p[-i - 1]: + continue + + g = igcd(g, i) + + if g == 1: + return 1, polys + + G = igcd(G, g) + + return G, tuple([ p[::G] for p in polys ]) + + +def dmp_multi_deflate(polys, u, K): + """ + Map ``x_i**m_i`` to ``y_i`` in a set of polynomials in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_multi_deflate + + >>> f = ZZ.map([[1, 0, 0, 2], [], [3, 0, 0, 4]]) + >>> g = ZZ.map([[1, 0, 2], [], [3, 0, 4]]) + + >>> dmp_multi_deflate((f, g), 1, ZZ) + ((2, 1), ([[1, 0, 0, 2], [3, 0, 0, 4]], [[1, 0, 2], [3, 0, 4]])) + + """ + if not u: + M, H = dup_multi_deflate(polys, K) + return (M,), H + + F, B = [], [0]*(u + 1) + + for p in polys: + f = dmp_to_dict(p, u) + + if not dmp_zero_p(p, u): + for M in f.keys(): + for i, m in enumerate(M): + B[i] = igcd(B[i], m) + + F.append(f) + + for i, b in enumerate(B): + if not b: + B[i] = 1 + + B = tuple(B) + + if all(b == 1 for b in B): + return B, polys + + H = [] + + for f in F: + h = {} + + for A, coeff in f.items(): + N = [ a // b for a, b in zip(A, B) ] + h[tuple(N)] = coeff + + H.append(dmp_from_dict(h, u, K)) + + return B, tuple(H) + + +def dup_inflate(f, m, K): + """ + Map ``y`` to ``x**m`` in a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_inflate + + >>> f = ZZ.map([1, 1, 1]) + + >>> dup_inflate(f, 3, ZZ) + [1, 0, 0, 1, 0, 0, 1] + + """ + if m <= 0: + raise IndexError("'m' must be positive, got %s" % m) + if m == 1 or not f: + return f + + result = [f[0]] + + for coeff in f[1:]: + result.extend([K.zero]*(m - 1)) + result.append(coeff) + + return result + + +def _rec_inflate(g, M, v, i, K): + """Recursive helper for :func:`dmp_inflate`.""" + if not v: + return dup_inflate(g, M[i], K) + if M[i] <= 0: + raise IndexError("all M[i] must be positive, got %s" % M[i]) + + w, j = v - 1, i + 1 + + g = [ _rec_inflate(c, M, w, j, K) for c in g ] + + result = [g[0]] + + for coeff in g[1:]: + for _ in range(1, M[i]): + result.append(dmp_zero(w)) + + result.append(coeff) + + return result + + +def dmp_inflate(f, M, u, K): + """ + Map ``y_i`` to ``x_i**k_i`` in a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_inflate + + >>> f = ZZ.map([[1, 2], [3, 4]]) + + >>> dmp_inflate(f, (2, 3), 1, ZZ) + [[1, 0, 0, 2], [], [3, 0, 0, 4]] + + """ + if not u: + return dup_inflate(f, M[0], K) + + if all(m == 1 for m in M): + return f + else: + return _rec_inflate(f, M, u, 0, K) + + +def dmp_exclude(f, u, K): + """ + Exclude useless levels from ``f``. + + Return the levels excluded, the new excluded ``f``, and the new ``u``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_exclude + + >>> f = ZZ.map([[[1]], [[1], [2]]]) + + >>> dmp_exclude(f, 2, ZZ) + ([2], [[1], [1, 2]], 1) + + """ + if not u or dmp_ground_p(f, None, u): + return [], f, u + + J, F = [], dmp_to_dict(f, u) + + for j in range(0, u + 1): + for monom in F.keys(): + if monom[j]: + break + else: + J.append(j) + + if not J: + return [], f, u + + f = {} + + for monom, coeff in F.items(): + monom = list(monom) + + for j in reversed(J): + del monom[j] + + f[tuple(monom)] = coeff + + u -= len(J) + + return J, dmp_from_dict(f, u, K), u + + +def dmp_include(f, J, u, K): + """ + Include useless levels in ``f``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_include + + >>> f = ZZ.map([[1], [1, 2]]) + + >>> dmp_include(f, [2], 1, ZZ) + [[[1]], [[1], [2]]] + + """ + if not J: + return f + + F, f = dmp_to_dict(f, u), {} + + for monom, coeff in F.items(): + monom = list(monom) + + for j in J: + monom.insert(j, 0) + + f[tuple(monom)] = coeff + + u += len(J) + + return dmp_from_dict(f, u, K) + + +def dmp_inject(f, u, K, front=False): + """ + Convert ``f`` from ``K[X][Y]`` to ``K[X,Y]``. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_inject + + >>> R, x,y = ring("x,y", ZZ) + + >>> dmp_inject([R(1), x + 2], 0, R.to_domain()) + ([[[1]], [[1], [2]]], 2) + >>> dmp_inject([R(1), x + 2], 0, R.to_domain(), front=True) + ([[[1]], [[1, 2]]], 2) + + """ + f, h = dmp_to_dict(f, u), {} + + v = K.ngens - 1 + + for f_monom, g in f.items(): + g = g.to_dict() + + for g_monom, c in g.items(): + if front: + h[g_monom + f_monom] = c + else: + h[f_monom + g_monom] = c + + w = u + v + 1 + + return dmp_from_dict(h, w, K.dom), w + + +def dmp_eject(f, u, K, front=False): + """ + Convert ``f`` from ``K[X,Y]`` to ``K[X][Y]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_eject + + >>> dmp_eject([[[1]], [[1], [2]]], 2, ZZ['x', 'y']) + [1, x + 2] + + """ + f, h = dmp_to_dict(f, u), {} + + n = K.ngens + v = u - K.ngens + 1 + + for monom, c in f.items(): + if front: + g_monom, f_monom = monom[:n], monom[n:] + else: + g_monom, f_monom = monom[-n:], monom[:-n] + + if f_monom in h: + h[f_monom][g_monom] = c + else: + h[f_monom] = {g_monom: c} + + for monom, c in h.items(): + h[monom] = K(c) + + return dmp_from_dict(h, v - 1, K) + + +def dup_terms_gcd(f, K): + """ + Remove GCD of terms from ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_terms_gcd + + >>> f = ZZ.map([1, 0, 1, 0, 0]) + + >>> dup_terms_gcd(f, ZZ) + (2, [1, 0, 1]) + + """ + if dup_TC(f, K) or not f: + return 0, f + + i = 0 + + for c in reversed(f): + if not c: + i += 1 + else: + break + + return i, f[:-i] + + +def dmp_terms_gcd(f, u, K): + """ + Remove GCD of terms from ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_terms_gcd + + >>> f = ZZ.map([[1, 0], [1, 0, 0], [], []]) + + >>> dmp_terms_gcd(f, 1, ZZ) + ((2, 1), [[1], [1, 0]]) + + """ + if dmp_ground_TC(f, u, K) or dmp_zero_p(f, u): + return (0,)*(u + 1), f + + F = dmp_to_dict(f, u) + G = monomial_min(*list(F.keys())) + + if all(g == 0 for g in G): + return G, f + + f = {} + + for monom, coeff in F.items(): + f[monomial_div(monom, G)] = coeff + + return G, dmp_from_dict(f, u, K) + + +def _rec_list_terms(g, v, monom): + """Recursive helper for :func:`dmp_list_terms`.""" + d, terms = dmp_degree(g, v), [] + + if not v: + for i, c in enumerate(g): + if not c: + continue + + terms.append((monom + (d - i,), c)) + else: + w = v - 1 + + for i, c in enumerate(g): + terms.extend(_rec_list_terms(c, w, monom + (d - i,))) + + return terms + + +def dmp_list_terms(f, u, K, order=None): + """ + List all non-zero terms from ``f`` in the given order ``order``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_list_terms + + >>> f = ZZ.map([[1, 1], [2, 3]]) + + >>> dmp_list_terms(f, 1, ZZ) + [((1, 1), 1), ((1, 0), 1), ((0, 1), 2), ((0, 0), 3)] + >>> dmp_list_terms(f, 1, ZZ, order='grevlex') + [((1, 1), 1), ((1, 0), 1), ((0, 1), 2), ((0, 0), 3)] + + """ + def sort(terms, O): + return sorted(terms, key=lambda term: O(term[0]), reverse=True) + + terms = _rec_list_terms(f, u, ()) + + if not terms: + return [((0,)*(u + 1), K.zero)] + + if order is None: + return terms + else: + return sort(terms, monomial_key(order)) + + +def dup_apply_pairs(f, g, h, args, K): + """ + Apply ``h`` to pairs of coefficients of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_apply_pairs + + >>> h = lambda x, y, z: 2*x + y - z + + >>> dup_apply_pairs([1, 2, 3], [3, 2, 1], h, (1,), ZZ) + [4, 5, 6] + + """ + n, m = len(f), len(g) + + if n != m: + if n > m: + g = [K.zero]*(n - m) + g + else: + f = [K.zero]*(m - n) + f + + result = [] + + for a, b in zip(f, g): + result.append(h(a, b, *args)) + + return dup_strip(result) + + +def dmp_apply_pairs(f, g, h, args, u, K): + """ + Apply ``h`` to pairs of coefficients of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dmp_apply_pairs + + >>> h = lambda x, y, z: 2*x + y - z + + >>> dmp_apply_pairs([[1], [2, 3]], [[3], [2, 1]], h, (1,), 1, ZZ) + [[4], [5, 6]] + + """ + if not u: + return dup_apply_pairs(f, g, h, args, K) + + n, m, v = len(f), len(g), u - 1 + + if n != m: + if n > m: + g = dmp_zeros(n - m, v, K) + g + else: + f = dmp_zeros(m - n, v, K) + f + + result = [] + + for a, b in zip(f, g): + result.append(dmp_apply_pairs(a, b, h, args, v, K)) + + return dmp_strip(result, u) + + +def dup_slice(f, m, n, K): + """Take a continuous subsequence of terms of ``f`` in ``K[x]``. """ + k = len(f) + + if k >= m: + M = k - m + else: + M = 0 + if k >= n: + N = k - n + else: + N = 0 + + f = f[N:M] + + while f and f[0] == K.zero: + f.pop(0) + + if not f: + return [] + else: + return f + [K.zero]*m + + +def dmp_slice(f, m, n, u, K): + """Take a continuous subsequence of terms of ``f`` in ``K[X]``. """ + return dmp_slice_in(f, m, n, 0, u, K) + + +def dmp_slice_in(f, m, n, j, u, K): + """Take a continuous subsequence of terms of ``f`` in ``x_j`` in ``K[X]``. """ + if j < 0 or j > u: + raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) + + if not u: + return dup_slice(f, m, n, K) + + f, g = dmp_to_dict(f, u), {} + + for monom, coeff in f.items(): + k = monom[j] + + if k < m or k >= n: + monom = monom[:j] + (0,) + monom[j + 1:] + + if monom in g: + g[monom] += coeff + else: + g[monom] = coeff + + return dmp_from_dict(g, u, K) + + +def dup_random(n, a, b, K): + """ + Return a polynomial of degree ``n`` with coefficients in ``[a, b]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.densebasic import dup_random + + >>> dup_random(3, -10, 10, ZZ) #doctest: +SKIP + [-2, -8, 9, -4] + + """ + f = [ K.convert(random.randint(a, b)) for _ in range(0, n + 1) ] + + while not f[0]: + f[0] = K.convert(random.randint(a, b)) + + return f diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densetools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densetools.py new file mode 100644 index 0000000000000000000000000000000000000000..122bf778a4843847be6db17708887416ba458f49 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/densetools.py @@ -0,0 +1,1438 @@ +"""Advanced tools for dense recursive polynomials in ``K[x]`` or ``K[X]``. """ + + +from sympy.polys.densearith import ( + dup_add_term, dmp_add_term, + dup_lshift, + dup_add, dmp_add, + dup_sub, dmp_sub, + dup_mul, dmp_mul, + dup_sqr, + dup_div, + dup_rem, dmp_rem, + dup_mul_ground, dmp_mul_ground, + dup_quo_ground, dmp_quo_ground, + dup_exquo_ground, dmp_exquo_ground, +) +from sympy.polys.densebasic import ( + dup_strip, dmp_strip, + dup_convert, dmp_convert, + dup_degree, dmp_degree, + dmp_to_dict, + dmp_from_dict, + dup_LC, dmp_LC, dmp_ground_LC, + dup_TC, dmp_TC, + dmp_zero, dmp_ground, + dmp_zero_p, + dup_to_raw_dict, dup_from_raw_dict, + dmp_zeros, + dmp_include, +) +from sympy.polys.polyerrors import ( + MultivariatePolynomialError, + DomainError +) + +from math import ceil as _ceil, log2 as _log2 + + +def dup_integrate(f, m, K): + """ + Computes the indefinite integral of ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> R.dup_integrate(x**2 + 2*x, 1) + 1/3*x**3 + x**2 + >>> R.dup_integrate(x**2 + 2*x, 2) + 1/12*x**4 + 1/3*x**3 + + """ + if m <= 0 or not f: + return f + + g = [K.zero]*m + + for i, c in enumerate(reversed(f)): + n = i + 1 + + for j in range(1, m): + n *= i + j + 1 + + g.insert(0, K.exquo(c, K(n))) + + return g + + +def dmp_integrate(f, m, u, K): + """ + Computes the indefinite integral of ``f`` in ``x_0`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) + + >>> R.dmp_integrate(x + 2*y, 1) + 1/2*x**2 + 2*x*y + >>> R.dmp_integrate(x + 2*y, 2) + 1/6*x**3 + x**2*y + + """ + if not u: + return dup_integrate(f, m, K) + + if m <= 0 or dmp_zero_p(f, u): + return f + + g, v = dmp_zeros(m, u - 1, K), u - 1 + + for i, c in enumerate(reversed(f)): + n = i + 1 + + for j in range(1, m): + n *= i + j + 1 + + g.insert(0, dmp_quo_ground(c, K(n), v, K)) + + return g + + +def _rec_integrate_in(g, m, v, i, j, K): + """Recursive helper for :func:`dmp_integrate_in`.""" + if i == j: + return dmp_integrate(g, m, v, K) + + w, i = v - 1, i + 1 + + return dmp_strip([ _rec_integrate_in(c, m, w, i, j, K) for c in g ], v) + + +def dmp_integrate_in(f, m, j, u, K): + """ + Computes the indefinite integral of ``f`` in ``x_j`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) + + >>> R.dmp_integrate_in(x + 2*y, 1, 0) + 1/2*x**2 + 2*x*y + >>> R.dmp_integrate_in(x + 2*y, 1, 1) + x*y + y**2 + + """ + if j < 0 or j > u: + raise IndexError("0 <= j <= u expected, got u = %d, j = %d" % (u, j)) + + return _rec_integrate_in(f, m, u, 0, j, K) + + +def dup_diff(f, m, K): + """ + ``m``-th order derivative of a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_diff(x**3 + 2*x**2 + 3*x + 4, 1) + 3*x**2 + 4*x + 3 + >>> R.dup_diff(x**3 + 2*x**2 + 3*x + 4, 2) + 6*x + 4 + + """ + if m <= 0: + return f + + n = dup_degree(f) + + if n < m: + return [] + + deriv = [] + + if m == 1: + for coeff in f[:-m]: + deriv.append(K(n)*coeff) + n -= 1 + else: + for coeff in f[:-m]: + k = n + + for i in range(n - 1, n - m, -1): + k *= i + + deriv.append(K(k)*coeff) + n -= 1 + + return dup_strip(deriv) + + +def dmp_diff(f, m, u, K): + """ + ``m``-th order derivative in ``x_0`` of a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 + + >>> R.dmp_diff(f, 1) + y**2 + 2*y + 3 + >>> R.dmp_diff(f, 2) + 0 + + """ + if not u: + return dup_diff(f, m, K) + if m <= 0: + return f + + n = dmp_degree(f, u) + + if n < m: + return dmp_zero(u) + + deriv, v = [], u - 1 + + if m == 1: + for coeff in f[:-m]: + deriv.append(dmp_mul_ground(coeff, K(n), v, K)) + n -= 1 + else: + for coeff in f[:-m]: + k = n + + for i in range(n - 1, n - m, -1): + k *= i + + deriv.append(dmp_mul_ground(coeff, K(k), v, K)) + n -= 1 + + return dmp_strip(deriv, u) + + +def _rec_diff_in(g, m, v, i, j, K): + """Recursive helper for :func:`dmp_diff_in`.""" + if i == j: + return dmp_diff(g, m, v, K) + + w, i = v - 1, i + 1 + + return dmp_strip([ _rec_diff_in(c, m, w, i, j, K) for c in g ], v) + + +def dmp_diff_in(f, m, j, u, K): + """ + ``m``-th order derivative in ``x_j`` of a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 + + >>> R.dmp_diff_in(f, 1, 0) + y**2 + 2*y + 3 + >>> R.dmp_diff_in(f, 1, 1) + 2*x*y + 2*x + 4*y + 3 + + """ + if j < 0 or j > u: + raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) + + return _rec_diff_in(f, m, u, 0, j, K) + + +def dup_eval(f, a, K): + """ + Evaluate a polynomial at ``x = a`` in ``K[x]`` using Horner scheme. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_eval(x**2 + 2*x + 3, 2) + 11 + + """ + if not a: + return K.convert(dup_TC(f, K)) + + result = K.zero + + for c in f: + result *= a + result += c + + return result + + +def dmp_eval(f, a, u, K): + """ + Evaluate a polynomial at ``x_0 = a`` in ``K[X]`` using the Horner scheme. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_eval(2*x*y + 3*x + y + 2, 2) + 5*y + 8 + + """ + if not u: + return dup_eval(f, a, K) + + if not a: + return dmp_TC(f, K) + + result, v = dmp_LC(f, K), u - 1 + + for coeff in f[1:]: + result = dmp_mul_ground(result, a, v, K) + result = dmp_add(result, coeff, v, K) + + return result + + +def _rec_eval_in(g, a, v, i, j, K): + """Recursive helper for :func:`dmp_eval_in`.""" + if i == j: + return dmp_eval(g, a, v, K) + + v, i = v - 1, i + 1 + + return dmp_strip([ _rec_eval_in(c, a, v, i, j, K) for c in g ], v) + + +def dmp_eval_in(f, a, j, u, K): + """ + Evaluate a polynomial at ``x_j = a`` in ``K[X]`` using the Horner scheme. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = 2*x*y + 3*x + y + 2 + + >>> R.dmp_eval_in(f, 2, 0) + 5*y + 8 + >>> R.dmp_eval_in(f, 2, 1) + 7*x + 4 + + """ + if j < 0 or j > u: + raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) + + return _rec_eval_in(f, a, u, 0, j, K) + + +def _rec_eval_tail(g, i, A, u, K): + """Recursive helper for :func:`dmp_eval_tail`.""" + if i == u: + return dup_eval(g, A[-1], K) + else: + h = [ _rec_eval_tail(c, i + 1, A, u, K) for c in g ] + + if i < u - len(A) + 1: + return h + else: + return dup_eval(h, A[-u + i - 1], K) + + +def dmp_eval_tail(f, A, u, K): + """ + Evaluate a polynomial at ``x_j = a_j, ...`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = 2*x*y + 3*x + y + 2 + + >>> R.dmp_eval_tail(f, [2]) + 7*x + 4 + >>> R.dmp_eval_tail(f, [2, 2]) + 18 + + """ + if not A: + return f + + if dmp_zero_p(f, u): + return dmp_zero(u - len(A)) + + e = _rec_eval_tail(f, 0, A, u, K) + + if u == len(A) - 1: + return e + else: + return dmp_strip(e, u - len(A)) + + +def _rec_diff_eval(g, m, a, v, i, j, K): + """Recursive helper for :func:`dmp_diff_eval`.""" + if i == j: + return dmp_eval(dmp_diff(g, m, v, K), a, v, K) + + v, i = v - 1, i + 1 + + return dmp_strip([ _rec_diff_eval(c, m, a, v, i, j, K) for c in g ], v) + + +def dmp_diff_eval_in(f, m, a, j, u, K): + """ + Differentiate and evaluate a polynomial in ``x_j`` at ``a`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 + + >>> R.dmp_diff_eval_in(f, 1, 2, 0) + y**2 + 2*y + 3 + >>> R.dmp_diff_eval_in(f, 1, 2, 1) + 6*x + 11 + + """ + if j > u: + raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) + if not j: + return dmp_eval(dmp_diff(f, m, u, K), a, u, K) + + return _rec_diff_eval(f, m, a, u, 0, j, K) + + +def dup_trunc(f, p, K): + """ + Reduce a ``K[x]`` polynomial modulo a constant ``p`` in ``K``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_trunc(2*x**3 + 3*x**2 + 5*x + 7, ZZ(3)) + -x**3 - x + 1 + + """ + if K.is_ZZ: + g = [] + + for c in f: + c = c % p + + if c > p // 2: + g.append(c - p) + else: + g.append(c) + elif K.is_FiniteField: + # XXX: python-flint's nmod does not support % + pi = int(p) + g = [ K(int(c) % pi) for c in f ] + else: + g = [ c % p for c in f ] + + return dup_strip(g) + + +def dmp_trunc(f, p, u, K): + """ + Reduce a ``K[X]`` polynomial modulo a polynomial ``p`` in ``K[Y]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 + >>> g = (y - 1).drop(x) + + >>> R.dmp_trunc(f, g) + 11*x**2 + 11*x + 5 + + """ + return dmp_strip([ dmp_rem(c, p, u - 1, K) for c in f ], u) + + +def dmp_ground_trunc(f, p, u, K): + """ + Reduce a ``K[X]`` polynomial modulo a constant ``p`` in ``K``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 + + >>> R.dmp_ground_trunc(f, ZZ(3)) + -x**2 - x*y - y + + """ + if not u: + return dup_trunc(f, p, K) + + v = u - 1 + + return dmp_strip([ dmp_ground_trunc(c, p, v, K) for c in f ], u) + + +def dup_monic(f, K): + """ + Divide all coefficients by ``LC(f)`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x = ring("x", ZZ) + >>> R.dup_monic(3*x**2 + 6*x + 9) + x**2 + 2*x + 3 + + >>> R, x = ring("x", QQ) + >>> R.dup_monic(3*x**2 + 4*x + 2) + x**2 + 4/3*x + 2/3 + + """ + if not f: + return f + + lc = dup_LC(f, K) + + if K.is_one(lc): + return f + else: + return dup_exquo_ground(f, lc, K) + + +def dmp_ground_monic(f, u, K): + """ + Divide all coefficients by ``LC(f)`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x,y = ring("x,y", ZZ) + >>> f = 3*x**2*y + 6*x**2 + 3*x*y + 9*y + 3 + + >>> R.dmp_ground_monic(f) + x**2*y + 2*x**2 + x*y + 3*y + 1 + + >>> R, x,y = ring("x,y", QQ) + >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 + + >>> R.dmp_ground_monic(f) + x**2*y + 8/3*x**2 + 5/3*x*y + 2*x + 2/3*y + 1 + + """ + if not u: + return dup_monic(f, K) + + if dmp_zero_p(f, u): + return f + + lc = dmp_ground_LC(f, u, K) + + if K.is_one(lc): + return f + else: + return dmp_exquo_ground(f, lc, u, K) + + +def dup_content(f, K): + """ + Compute the GCD of coefficients of ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x = ring("x", ZZ) + >>> f = 6*x**2 + 8*x + 12 + + >>> R.dup_content(f) + 2 + + >>> R, x = ring("x", QQ) + >>> f = 6*x**2 + 8*x + 12 + + >>> R.dup_content(f) + 2 + + """ + from sympy.polys.domains import QQ + + if not f: + return K.zero + + cont = K.zero + + if K == QQ: + for c in f: + cont = K.gcd(cont, c) + else: + for c in f: + cont = K.gcd(cont, c) + + if K.is_one(cont): + break + + return cont + + +def dmp_ground_content(f, u, K): + """ + Compute the GCD of coefficients of ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x,y = ring("x,y", ZZ) + >>> f = 2*x*y + 6*x + 4*y + 12 + + >>> R.dmp_ground_content(f) + 2 + + >>> R, x,y = ring("x,y", QQ) + >>> f = 2*x*y + 6*x + 4*y + 12 + + >>> R.dmp_ground_content(f) + 2 + + """ + from sympy.polys.domains import QQ + + if not u: + return dup_content(f, K) + + if dmp_zero_p(f, u): + return K.zero + + cont, v = K.zero, u - 1 + + if K == QQ: + for c in f: + cont = K.gcd(cont, dmp_ground_content(c, v, K)) + else: + for c in f: + cont = K.gcd(cont, dmp_ground_content(c, v, K)) + + if K.is_one(cont): + break + + return cont + + +def dup_primitive(f, K): + """ + Compute content and the primitive form of ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x = ring("x", ZZ) + >>> f = 6*x**2 + 8*x + 12 + + >>> R.dup_primitive(f) + (2, 3*x**2 + 4*x + 6) + + >>> R, x = ring("x", QQ) + >>> f = 6*x**2 + 8*x + 12 + + >>> R.dup_primitive(f) + (2, 3*x**2 + 4*x + 6) + + """ + if not f: + return K.zero, f + + cont = dup_content(f, K) + + if K.is_one(cont): + return cont, f + else: + return cont, dup_quo_ground(f, cont, K) + + +def dmp_ground_primitive(f, u, K): + """ + Compute content and the primitive form of ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x,y = ring("x,y", ZZ) + >>> f = 2*x*y + 6*x + 4*y + 12 + + >>> R.dmp_ground_primitive(f) + (2, x*y + 3*x + 2*y + 6) + + >>> R, x,y = ring("x,y", QQ) + >>> f = 2*x*y + 6*x + 4*y + 12 + + >>> R.dmp_ground_primitive(f) + (2, x*y + 3*x + 2*y + 6) + + """ + if not u: + return dup_primitive(f, K) + + if dmp_zero_p(f, u): + return K.zero, f + + cont = dmp_ground_content(f, u, K) + + if K.is_one(cont): + return cont, f + else: + return cont, dmp_quo_ground(f, cont, u, K) + + +def dup_extract(f, g, K): + """ + Extract common content from a pair of polynomials in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_extract(6*x**2 + 12*x + 18, 4*x**2 + 8*x + 12) + (2, 3*x**2 + 6*x + 9, 2*x**2 + 4*x + 6) + + """ + fc = dup_content(f, K) + gc = dup_content(g, K) + + gcd = K.gcd(fc, gc) + + if not K.is_one(gcd): + f = dup_quo_ground(f, gcd, K) + g = dup_quo_ground(g, gcd, K) + + return gcd, f, g + + +def dmp_ground_extract(f, g, u, K): + """ + Extract common content from a pair of polynomials in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_ground_extract(6*x*y + 12*x + 18, 4*x*y + 8*x + 12) + (2, 3*x*y + 6*x + 9, 2*x*y + 4*x + 6) + + """ + fc = dmp_ground_content(f, u, K) + gc = dmp_ground_content(g, u, K) + + gcd = K.gcd(fc, gc) + + if not K.is_one(gcd): + f = dmp_quo_ground(f, gcd, u, K) + g = dmp_quo_ground(g, gcd, u, K) + + return gcd, f, g + + +def dup_real_imag(f, K): + """ + Find ``f1`` and ``f2``, such that ``f(x+I*y) = f1(x,y) + f2(x,y)*I``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dup_real_imag(x**3 + x**2 + x + 1) + (x**3 + x**2 - 3*x*y**2 + x - y**2 + 1, 3*x**2*y + 2*x*y - y**3 + y) + + >>> from sympy.abc import x, y, z + >>> from sympy import I + >>> (z**3 + z**2 + z + 1).subs(z, x+I*y).expand().collect(I) + x**3 + x**2 - 3*x*y**2 + x - y**2 + I*(3*x**2*y + 2*x*y - y**3 + y) + 1 + + """ + if not K.is_ZZ and not K.is_QQ: + raise DomainError("computing real and imaginary parts is not supported over %s" % K) + + f1 = dmp_zero(1) + f2 = dmp_zero(1) + + if not f: + return f1, f2 + + g = [[[K.one, K.zero]], [[K.one], []]] + h = dmp_ground(f[0], 2) + + for c in f[1:]: + h = dmp_mul(h, g, 2, K) + h = dmp_add_term(h, dmp_ground(c, 1), 0, 2, K) + + H = dup_to_raw_dict(h) + + for k, h in H.items(): + m = k % 4 + + if not m: + f1 = dmp_add(f1, h, 1, K) + elif m == 1: + f2 = dmp_add(f2, h, 1, K) + elif m == 2: + f1 = dmp_sub(f1, h, 1, K) + else: + f2 = dmp_sub(f2, h, 1, K) + + return f1, f2 + + +def dup_mirror(f, K): + """ + Evaluate efficiently the composition ``f(-x)`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_mirror(x**3 + 2*x**2 - 4*x + 2) + -x**3 + 2*x**2 + 4*x + 2 + + """ + f = list(f) + + for i in range(len(f) - 2, -1, -2): + f[i] = -f[i] + + return f + + +def dup_scale(f, a, K): + """ + Evaluate efficiently composition ``f(a*x)`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_scale(x**2 - 2*x + 1, ZZ(2)) + 4*x**2 - 4*x + 1 + + """ + f, n, b = list(f), len(f) - 1, a + + for i in range(n - 1, -1, -1): + f[i], b = b*f[i], b*a + + return f + + +def dup_shift(f, a, K): + """ + Evaluate efficiently Taylor shift ``f(x + a)`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_shift(x**2 - 2*x + 1, ZZ(2)) + x**2 + 2*x + 1 + + """ + f, n = list(f), len(f) - 1 + + for i in range(n, 0, -1): + for j in range(0, i): + f[j + 1] += a*f[j] + + return f + + +def dmp_shift(f, a, u, K): + """ + Evaluate efficiently Taylor shift ``f(X + A)`` in ``K[X]``. + + Examples + ======== + + >>> from sympy import symbols, ring, ZZ + >>> x, y = symbols('x y') + >>> R, _, _ = ring([x, y], ZZ) + + >>> p = x**2*y + 2*x*y + 3*x + 4*y + 5 + + >>> R.dmp_shift(R(p), [ZZ(1), ZZ(2)]) + x**2*y + 2*x**2 + 4*x*y + 11*x + 7*y + 22 + + >>> p.subs({x: x + 1, y: y + 2}).expand() + x**2*y + 2*x**2 + 4*x*y + 11*x + 7*y + 22 + """ + if not u: + return dup_shift(f, a[0], K) + + if dmp_zero_p(f, u): + return f + + a0, a1 = a[0], a[1:] + + if any(a1): + f = [ dmp_shift(c, a1, u-1, K) for c in f ] + else: + f = list(f) + + if a0: + n = len(f) - 1 + + for i in range(n, 0, -1): + for j in range(0, i): + afj = dmp_mul_ground(f[j], a0, u-1, K) + f[j + 1] = dmp_add(f[j + 1], afj, u-1, K) + + return dmp_strip(f, u) + + +def dup_transform(f, p, q, K): + """ + Evaluate functional transformation ``q**n * f(p/q)`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_transform(x**2 - 2*x + 1, x**2 + 1, x - 1) + x**4 - 2*x**3 + 5*x**2 - 4*x + 4 + + """ + if not f: + return [] + + n = len(f) - 1 + h, Q = [f[0]], [[K.one]] + + for i in range(0, n): + Q.append(dup_mul(Q[-1], q, K)) + + for c, q in zip(f[1:], Q[1:]): + h = dup_mul(h, p, K) + q = dup_mul_ground(q, c, K) + h = dup_add(h, q, K) + + return h + + +def dup_compose(f, g, K): + """ + Evaluate functional composition ``f(g)`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_compose(x**2 + x, x - 1) + x**2 - x + + """ + if len(g) <= 1: + return dup_strip([dup_eval(f, dup_LC(g, K), K)]) + + if not f: + return [] + + h = [f[0]] + + for c in f[1:]: + h = dup_mul(h, g, K) + h = dup_add_term(h, c, 0, K) + + return h + + +def dmp_compose(f, g, u, K): + """ + Evaluate functional composition ``f(g)`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_compose(x*y + 2*x + y, y) + y**2 + 3*y + + """ + if not u: + return dup_compose(f, g, K) + + if dmp_zero_p(f, u): + return f + + h = [f[0]] + + for c in f[1:]: + h = dmp_mul(h, g, u, K) + h = dmp_add_term(h, c, 0, u, K) + + return h + + +def _dup_right_decompose(f, s, K): + """Helper function for :func:`_dup_decompose`.""" + n = len(f) - 1 + lc = dup_LC(f, K) + + f = dup_to_raw_dict(f) + g = { s: K.one } + + r = n // s + + for i in range(1, s): + coeff = K.zero + + for j in range(0, i): + if not n + j - i in f: + continue + + if not s - j in g: + continue + + fc, gc = f[n + j - i], g[s - j] + coeff += (i - r*j)*fc*gc + + g[s - i] = K.quo(coeff, i*r*lc) + + return dup_from_raw_dict(g, K) + + +def _dup_left_decompose(f, h, K): + """Helper function for :func:`_dup_decompose`.""" + g, i = {}, 0 + + while f: + q, r = dup_div(f, h, K) + + if dup_degree(r) > 0: + return None + else: + g[i] = dup_LC(r, K) + f, i = q, i + 1 + + return dup_from_raw_dict(g, K) + + +def _dup_decompose(f, K): + """Helper function for :func:`dup_decompose`.""" + df = len(f) - 1 + + for s in range(2, df): + if df % s != 0: + continue + + h = _dup_right_decompose(f, s, K) + + if h is not None: + g = _dup_left_decompose(f, h, K) + + if g is not None: + return g, h + + return None + + +def dup_decompose(f, K): + """ + Computes functional decomposition of ``f`` in ``K[x]``. + + Given a univariate polynomial ``f`` with coefficients in a field of + characteristic zero, returns list ``[f_1, f_2, ..., f_n]``, where:: + + f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n)) + + and ``f_2, ..., f_n`` are monic and homogeneous polynomials of at + least second degree. + + Unlike factorization, complete functional decompositions of + polynomials are not unique, consider examples: + + 1. ``f o g = f(x + b) o (g - b)`` + 2. ``x**n o x**m = x**m o x**n`` + 3. ``T_n o T_m = T_m o T_n`` + + where ``T_n`` and ``T_m`` are Chebyshev polynomials. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_decompose(x**4 - 2*x**3 + x**2) + [x**2, x**2 - x] + + References + ========== + + .. [1] [Kozen89]_ + + """ + F = [] + + while True: + result = _dup_decompose(f, K) + + if result is not None: + f, h = result + F = [h] + F + else: + break + + return [f] + F + + +def dmp_alg_inject(f, u, K): + """ + Convert polynomial from ``K(a)[X]`` to ``K[a,X]``. + + Examples + ======== + + >>> from sympy.polys.densetools import dmp_alg_inject + >>> from sympy import QQ, sqrt + + >>> K = QQ.algebraic_field(sqrt(2)) + + >>> p = [K.from_sympy(sqrt(2)), K.zero, K.one] + >>> P, lev, dom = dmp_alg_inject(p, 0, K) + >>> P + [[1, 0, 0], [1]] + >>> lev + 1 + >>> dom + QQ + + """ + if K.is_GaussianRing or K.is_GaussianField: + return _dmp_alg_inject_gaussian(f, u, K) + elif K.is_Algebraic: + return _dmp_alg_inject_alg(f, u, K) + else: + raise DomainError('computation can be done only in an algebraic domain') + + +def _dmp_alg_inject_gaussian(f, u, K): + """Helper function for :func:`dmp_alg_inject`.""" + f, h = dmp_to_dict(f, u), {} + + for f_monom, g in f.items(): + x, y = g.x, g.y + if x: + h[(0,) + f_monom] = x + if y: + h[(1,) + f_monom] = y + + F = dmp_from_dict(h, u + 1, K.dom) + + return F, u + 1, K.dom + + +def _dmp_alg_inject_alg(f, u, K): + """Helper function for :func:`dmp_alg_inject`.""" + f, h = dmp_to_dict(f, u), {} + + for f_monom, g in f.items(): + for g_monom, c in g.to_dict().items(): + h[g_monom + f_monom] = c + + F = dmp_from_dict(h, u + 1, K.dom) + + return F, u + 1, K.dom + + +def dmp_lift(f, u, K): + """ + Convert algebraic coefficients to integers in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> from sympy import I + + >>> K = QQ.algebraic_field(I) + >>> R, x = ring("x", K) + + >>> f = x**2 + K([QQ(1), QQ(0)])*x + K([QQ(2), QQ(0)]) + + >>> R.dmp_lift(f) + x**4 + x**2 + 4*x + 4 + + """ + # Circular import. Probably dmp_lift should be moved to euclidtools + from .euclidtools import dmp_resultant + + F, v, K2 = dmp_alg_inject(f, u, K) + + p_a = K.mod.to_list() + P_A = dmp_include(p_a, list(range(1, v + 1)), 0, K2) + + return dmp_resultant(F, P_A, v, K2) + + +def dup_sign_variations(f, K): + """ + Compute the number of sign variations of ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_sign_variations(x**4 - x**2 - x + 1) + 2 + + """ + def is_negative_sympy(a): + if not a: + # XXX: requires zero equivalence testing in the domain + return False + else: + # XXX: This is inefficient. It should not be necessary to use a + # symbolic expression here at least for algebraic fields. If the + # domain elements can be numerically evaluated to real values with + # precision then this should work. We first need to rule out zero + # elements though. + return bool(K.to_sympy(a) < 0) + + # XXX: There should be a way to check for real numeric domains and + # Domain.is_negative should be fixed to handle all real numeric domains. + # It should not be necessary to special case all these different domains + # in this otherwise generic function. + if K.is_ZZ or K.is_QQ or K.is_RR: + is_negative = K.is_negative + elif K.is_AlgebraicField and K.ext.is_comparable: + is_negative = is_negative_sympy + elif ((K.is_PolynomialRing or K.is_FractionField) and len(K.symbols) == 1 and + (K.dom.is_ZZ or K.dom.is_QQ or K.is_AlgebraicField) and + K.symbols[0].is_transcendental and K.symbols[0].is_comparable): + # We can handle a polynomial ring like QQ[E] if there is a single + # transcendental generator because then zero equivalence is assured. + is_negative = is_negative_sympy + else: + raise DomainError("sign variation counting not supported over %s" % K) + + prev, k = K.zero, 0 + + for coeff in f: + if is_negative(coeff*prev): + k += 1 + + if coeff: + prev = coeff + + return k + + +def dup_clear_denoms(f, K0, K1=None, convert=False): + """ + Clear denominators, i.e. transform ``K_0`` to ``K_1``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = QQ(1,2)*x + QQ(1,3) + + >>> R.dup_clear_denoms(f, convert=False) + (6, 3*x + 2) + >>> R.dup_clear_denoms(f, convert=True) + (6, 3*x + 2) + + """ + if K1 is None: + if K0.has_assoc_Ring: + K1 = K0.get_ring() + else: + K1 = K0 + + common = K1.one + + for c in f: + common = K1.lcm(common, K0.denom(c)) + + if K1.is_one(common): + if not convert: + return common, f + else: + return common, dup_convert(f, K0, K1) + + # Use quo rather than exquo to handle inexact domains by discarding the + # remainder. + f = [K0.numer(c)*K1.quo(common, K0.denom(c)) for c in f] + + if not convert: + return common, dup_convert(f, K1, K0) + else: + return common, f + + +def _rec_clear_denoms(g, v, K0, K1): + """Recursive helper for :func:`dmp_clear_denoms`.""" + common = K1.one + + if not v: + for c in g: + common = K1.lcm(common, K0.denom(c)) + else: + w = v - 1 + + for c in g: + common = K1.lcm(common, _rec_clear_denoms(c, w, K0, K1)) + + return common + + +def dmp_clear_denoms(f, u, K0, K1=None, convert=False): + """ + Clear denominators, i.e. transform ``K_0`` to ``K_1``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) + + >>> f = QQ(1,2)*x + QQ(1,3)*y + 1 + + >>> R.dmp_clear_denoms(f, convert=False) + (6, 3*x + 2*y + 6) + >>> R.dmp_clear_denoms(f, convert=True) + (6, 3*x + 2*y + 6) + + """ + if not u: + return dup_clear_denoms(f, K0, K1, convert=convert) + + if K1 is None: + if K0.has_assoc_Ring: + K1 = K0.get_ring() + else: + K1 = K0 + + common = _rec_clear_denoms(f, u, K0, K1) + + if not K1.is_one(common): + f = dmp_mul_ground(f, common, u, K0) + + if not convert: + return common, f + else: + return common, dmp_convert(f, u, K0, K1) + + +def dup_revert(f, n, K): + """ + Compute ``f**(-1)`` mod ``x**n`` using Newton iteration. + + This function computes first ``2**n`` terms of a polynomial that + is a result of inversion of a polynomial modulo ``x**n``. This is + useful to efficiently compute series expansion of ``1/f``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = -QQ(1,720)*x**6 + QQ(1,24)*x**4 - QQ(1,2)*x**2 + 1 + + >>> R.dup_revert(f, 8) + 61/720*x**6 + 5/24*x**4 + 1/2*x**2 + 1 + + """ + g = [K.revert(dup_TC(f, K))] + h = [K.one, K.zero, K.zero] + + N = int(_ceil(_log2(n))) + + for i in range(1, N + 1): + a = dup_mul_ground(g, K(2), K) + b = dup_mul(f, dup_sqr(g, K), K) + g = dup_rem(dup_sub(a, b, K), h, K) + h = dup_lshift(h, dup_degree(h), K) + + return g + + +def dmp_revert(f, g, u, K): + """ + Compute ``f**(-1)`` mod ``x**n`` using Newton iteration. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) + + """ + if not u: + return dup_revert(f, g, K) + else: + raise MultivariatePolynomialError(f, g) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/dispersion.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/dispersion.py new file mode 100644 index 0000000000000000000000000000000000000000..699277d221f24b9bff42c55c3bb34fe5783ae7a1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/dispersion.py @@ -0,0 +1,212 @@ +from sympy.core import S +from sympy.polys import Poly + + +def dispersionset(p, q=None, *gens, **args): + r"""Compute the *dispersion set* of two polynomials. + + For two polynomials `f(x)` and `g(x)` with `\deg f > 0` + and `\deg g > 0` the dispersion set `\operatorname{J}(f, g)` is defined as: + + .. math:: + \operatorname{J}(f, g) + & := \{a \in \mathbb{N}_0 | \gcd(f(x), g(x+a)) \neq 1\} \\ + & = \{a \in \mathbb{N}_0 | \deg \gcd(f(x), g(x+a)) \geq 1\} + + For a single polynomial one defines `\operatorname{J}(f) := \operatorname{J}(f, f)`. + + Examples + ======== + + >>> from sympy import poly + >>> from sympy.polys.dispersion import dispersion, dispersionset + >>> from sympy.abc import x + + Dispersion set and dispersion of a simple polynomial: + + >>> fp = poly((x - 3)*(x + 3), x) + >>> sorted(dispersionset(fp)) + [0, 6] + >>> dispersion(fp) + 6 + + Note that the definition of the dispersion is not symmetric: + + >>> fp = poly(x**4 - 3*x**2 + 1, x) + >>> gp = fp.shift(-3) + >>> sorted(dispersionset(fp, gp)) + [2, 3, 4] + >>> dispersion(fp, gp) + 4 + >>> sorted(dispersionset(gp, fp)) + [] + >>> dispersion(gp, fp) + -oo + + Computing the dispersion also works over field extensions: + + >>> from sympy import sqrt + >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') + >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') + >>> sorted(dispersionset(fp, gp)) + [2] + >>> sorted(dispersionset(gp, fp)) + [1, 4] + + We can even perform the computations for polynomials + having symbolic coefficients: + + >>> from sympy.abc import a + >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) + >>> sorted(dispersionset(fp)) + [0, 1] + + See Also + ======== + + dispersion + + References + ========== + + .. [1] [ManWright94]_ + .. [2] [Koepf98]_ + .. [3] [Abramov71]_ + .. [4] [Man93]_ + """ + # Check for valid input + same = False if q is not None else True + if same: + q = p + + p = Poly(p, *gens, **args) + q = Poly(q, *gens, **args) + + if not p.is_univariate or not q.is_univariate: + raise ValueError("Polynomials need to be univariate") + + # The generator + if not p.gen == q.gen: + raise ValueError("Polynomials must have the same generator") + gen = p.gen + + # We define the dispersion of constant polynomials to be zero + if p.degree() < 1 or q.degree() < 1: + return {0} + + # Factor p and q over the rationals + fp = p.factor_list() + fq = q.factor_list() if not same else fp + + # Iterate over all pairs of factors + J = set() + for s, unused in fp[1]: + for t, unused in fq[1]: + m = s.degree() + n = t.degree() + if n != m: + continue + an = s.LC() + bn = t.LC() + if not (an - bn).is_zero: + continue + # Note that the roles of `s` and `t` below are switched + # w.r.t. the original paper. This is for consistency + # with the description in the book of W. Koepf. + anm1 = s.coeff_monomial(gen**(m-1)) + bnm1 = t.coeff_monomial(gen**(n-1)) + alpha = (anm1 - bnm1) / S(n*bn) + if not alpha.is_integer: + continue + if alpha < 0 or alpha in J: + continue + if n > 1 and not (s - t.shift(alpha)).is_zero: + continue + J.add(alpha) + + return J + + +def dispersion(p, q=None, *gens, **args): + r"""Compute the *dispersion* of polynomials. + + For two polynomials `f(x)` and `g(x)` with `\deg f > 0` + and `\deg g > 0` the dispersion `\operatorname{dis}(f, g)` is defined as: + + .. math:: + \operatorname{dis}(f, g) + & := \max\{ J(f,g) \cup \{0\} \} \\ + & = \max\{ \{a \in \mathbb{N} | \gcd(f(x), g(x+a)) \neq 1\} \cup \{0\} \} + + and for a single polynomial `\operatorname{dis}(f) := \operatorname{dis}(f, f)`. + Note that we make the definition `\max\{\} := -\infty`. + + Examples + ======== + + >>> from sympy import poly + >>> from sympy.polys.dispersion import dispersion, dispersionset + >>> from sympy.abc import x + + Dispersion set and dispersion of a simple polynomial: + + >>> fp = poly((x - 3)*(x + 3), x) + >>> sorted(dispersionset(fp)) + [0, 6] + >>> dispersion(fp) + 6 + + Note that the definition of the dispersion is not symmetric: + + >>> fp = poly(x**4 - 3*x**2 + 1, x) + >>> gp = fp.shift(-3) + >>> sorted(dispersionset(fp, gp)) + [2, 3, 4] + >>> dispersion(fp, gp) + 4 + >>> sorted(dispersionset(gp, fp)) + [] + >>> dispersion(gp, fp) + -oo + + The maximum of an empty set is defined to be `-\infty` + as seen in this example. + + Computing the dispersion also works over field extensions: + + >>> from sympy import sqrt + >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') + >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') + >>> sorted(dispersionset(fp, gp)) + [2] + >>> sorted(dispersionset(gp, fp)) + [1, 4] + + We can even perform the computations for polynomials + having symbolic coefficients: + + >>> from sympy.abc import a + >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) + >>> sorted(dispersionset(fp)) + [0, 1] + + See Also + ======== + + dispersionset + + References + ========== + + .. [1] [ManWright94]_ + .. [2] [Koepf98]_ + .. [3] [Abramov71]_ + .. [4] [Man93]_ + """ + J = dispersionset(p, q, *gens, **args) + if not J: + # Definition for maximum of empty set + j = S.NegativeInfinity + else: + j = max(J) + return j diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/distributedmodules.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/distributedmodules.py new file mode 100644 index 0000000000000000000000000000000000000000..df4581e58951a9c29b9e5b085311f5e6cb00f381 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/distributedmodules.py @@ -0,0 +1,739 @@ +r""" +Sparse distributed elements of free modules over multivariate (generalized) +polynomial rings. + +This code and its data structures are very much like the distributed +polynomials, except that the first "exponent" of the monomial is +a module generator index. That is, the multi-exponent ``(i, e_1, ..., e_n)`` +represents the "monomial" `x_1^{e_1} \cdots x_n^{e_n} f_i` of the free module +`F` generated by `f_1, \ldots, f_r` over (a localization of) the ring +`K[x_1, \ldots, x_n]`. A module element is simply stored as a list of terms +ordered by the monomial order. Here a term is a pair of a multi-exponent and a +coefficient. In general, this coefficient should never be zero (since it can +then be omitted). The zero module element is stored as an empty list. + +The main routines are ``sdm_nf_mora`` and ``sdm_groebner`` which can be used +to compute, respectively, weak normal forms and standard bases. They work with +arbitrary (not necessarily global) monomial orders. + +In general, product orders have to be used to construct valid monomial orders +for modules. However, ``lex`` can be used as-is. + +Note that the "level" (number of variables, i.e. parameter u+1 in +distributedpolys.py) is never needed in this code. + +The main reference for this file is [SCA], +"A Singular Introduction to Commutative Algebra". +""" + + +from itertools import permutations + +from sympy.polys.monomials import ( + monomial_mul, monomial_lcm, monomial_div, monomial_deg +) + +from sympy.polys.polytools import Poly +from sympy.polys.polyutils import parallel_dict_from_expr +from sympy.core.singleton import S +from sympy.core.sympify import sympify + +# Additional monomial tools. + + +def sdm_monomial_mul(M, X): + """ + Multiply tuple ``X`` representing a monomial of `K[X]` into the tuple + ``M`` representing a monomial of `F`. + + Examples + ======== + + Multiplying `xy^3` into `x f_1` yields `x^2 y^3 f_1`: + + >>> from sympy.polys.distributedmodules import sdm_monomial_mul + >>> sdm_monomial_mul((1, 1, 0), (1, 3)) + (1, 2, 3) + """ + return (M[0],) + monomial_mul(X, M[1:]) + + +def sdm_monomial_deg(M): + """ + Return the total degree of ``M``. + + Examples + ======== + + For example, the total degree of `x^2 y f_5` is 3: + + >>> from sympy.polys.distributedmodules import sdm_monomial_deg + >>> sdm_monomial_deg((5, 2, 1)) + 3 + """ + return monomial_deg(M[1:]) + + +def sdm_monomial_lcm(A, B): + r""" + Return the "least common multiple" of ``A`` and ``B``. + + IF `A = M e_j` and `B = N e_j`, where `M` and `N` are polynomial monomials, + this returns `\lcm(M, N) e_j`. Note that ``A`` and ``B`` involve distinct + monomials. + + Otherwise the result is undefined. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_monomial_lcm + >>> sdm_monomial_lcm((1, 2, 3), (1, 0, 5)) + (1, 2, 5) + """ + return (A[0],) + monomial_lcm(A[1:], B[1:]) + + +def sdm_monomial_divides(A, B): + """ + Does there exist a (polynomial) monomial X such that XA = B? + + Examples + ======== + + Positive examples: + + In the following examples, the monomial is given in terms of x, y and the + generator(s), f_1, f_2 etc. The tuple form of that monomial is used in + the call to sdm_monomial_divides. + Note: the generator appears last in the expression but first in the tuple + and other factors appear in the same order that they appear in the monomial + expression. + + `A = f_1` divides `B = f_1` + + >>> from sympy.polys.distributedmodules import sdm_monomial_divides + >>> sdm_monomial_divides((1, 0, 0), (1, 0, 0)) + True + + `A = f_1` divides `B = x^2 y f_1` + + >>> sdm_monomial_divides((1, 0, 0), (1, 2, 1)) + True + + `A = xy f_5` divides `B = x^2 y f_5` + + >>> sdm_monomial_divides((5, 1, 1), (5, 2, 1)) + True + + Negative examples: + + `A = f_1` does not divide `B = f_2` + + >>> sdm_monomial_divides((1, 0, 0), (2, 0, 0)) + False + + `A = x f_1` does not divide `B = f_1` + + >>> sdm_monomial_divides((1, 1, 0), (1, 0, 0)) + False + + `A = xy^2 f_5` does not divide `B = y f_5` + + >>> sdm_monomial_divides((5, 1, 2), (5, 0, 1)) + False + """ + return A[0] == B[0] and all(a <= b for a, b in zip(A[1:], B[1:])) + + +# The actual distributed modules code. + +def sdm_LC(f, K): + """Returns the leading coefficient of ``f``. """ + if not f: + return K.zero + else: + return f[0][1] + + +def sdm_to_dict(f): + """Make a dictionary from a distributed polynomial. """ + return dict(f) + + +def sdm_from_dict(d, O): + """ + Create an sdm from a dictionary. + + Here ``O`` is the monomial order to use. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_from_dict + >>> from sympy.polys import QQ, lex + >>> dic = {(1, 1, 0): QQ(1), (1, 0, 0): QQ(2), (0, 1, 0): QQ(0)} + >>> sdm_from_dict(dic, lex) + [((1, 1, 0), 1), ((1, 0, 0), 2)] + """ + return sdm_strip(sdm_sort(list(d.items()), O)) + + +def sdm_sort(f, O): + """Sort terms in ``f`` using the given monomial order ``O``. """ + return sorted(f, key=lambda term: O(term[0]), reverse=True) + + +def sdm_strip(f): + """Remove terms with zero coefficients from ``f`` in ``K[X]``. """ + return [ (monom, coeff) for monom, coeff in f if coeff ] + + +def sdm_add(f, g, O, K): + """ + Add two module elements ``f``, ``g``. + + Addition is done over the ground field ``K``, monomials are ordered + according to ``O``. + + Examples + ======== + + All examples use lexicographic order. + + `(xy f_1) + (f_2) = f_2 + xy f_1` + + >>> from sympy.polys.distributedmodules import sdm_add + >>> from sympy.polys import lex, QQ + >>> sdm_add([((1, 1, 1), QQ(1))], [((2, 0, 0), QQ(1))], lex, QQ) + [((2, 0, 0), 1), ((1, 1, 1), 1)] + + `(xy f_1) + (-xy f_1)` = 0` + + >>> sdm_add([((1, 1, 1), QQ(1))], [((1, 1, 1), QQ(-1))], lex, QQ) + [] + + `(f_1) + (2f_1) = 3f_1` + + >>> sdm_add([((1, 0, 0), QQ(1))], [((1, 0, 0), QQ(2))], lex, QQ) + [((1, 0, 0), 3)] + + `(yf_1) + (xf_1) = xf_1 + yf_1` + + >>> sdm_add([((1, 0, 1), QQ(1))], [((1, 1, 0), QQ(1))], lex, QQ) + [((1, 1, 0), 1), ((1, 0, 1), 1)] + """ + h = dict(f) + + for monom, c in g: + if monom in h: + coeff = h[monom] + c + + if not coeff: + del h[monom] + else: + h[monom] = coeff + else: + h[monom] = c + + return sdm_from_dict(h, O) + + +def sdm_LM(f): + r""" + Returns the leading monomial of ``f``. + + Only valid if `f \ne 0`. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_LM, sdm_from_dict + >>> from sympy.polys import QQ, lex + >>> dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(1), (4, 0, 1): QQ(1)} + >>> sdm_LM(sdm_from_dict(dic, lex)) + (4, 0, 1) + """ + return f[0][0] + + +def sdm_LT(f): + r""" + Returns the leading term of ``f``. + + Only valid if `f \ne 0`. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_LT, sdm_from_dict + >>> from sympy.polys import QQ, lex + >>> dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(2), (4, 0, 1): QQ(3)} + >>> sdm_LT(sdm_from_dict(dic, lex)) + ((4, 0, 1), 3) + """ + return f[0] + + +def sdm_mul_term(f, term, O, K): + """ + Multiply a distributed module element ``f`` by a (polynomial) term ``term``. + + Multiplication of coefficients is done over the ground field ``K``, and + monomials are ordered according to ``O``. + + Examples + ======== + + `0 f_1 = 0` + + >>> from sympy.polys.distributedmodules import sdm_mul_term + >>> from sympy.polys import lex, QQ + >>> sdm_mul_term([((1, 0, 0), QQ(1))], ((0, 0), QQ(0)), lex, QQ) + [] + + `x 0 = 0` + + >>> sdm_mul_term([], ((1, 0), QQ(1)), lex, QQ) + [] + + `(x) (f_1) = xf_1` + + >>> sdm_mul_term([((1, 0, 0), QQ(1))], ((1, 0), QQ(1)), lex, QQ) + [((1, 1, 0), 1)] + + `(2xy) (3x f_1 + 4y f_2) = 8xy^2 f_2 + 6x^2y f_1` + + >>> f = [((2, 0, 1), QQ(4)), ((1, 1, 0), QQ(3))] + >>> sdm_mul_term(f, ((1, 1), QQ(2)), lex, QQ) + [((2, 1, 2), 8), ((1, 2, 1), 6)] + """ + X, c = term + + if not f or not c: + return [] + else: + if K.is_one(c): + return [ (sdm_monomial_mul(f_M, X), f_c) for f_M, f_c in f ] + else: + return [ (sdm_monomial_mul(f_M, X), f_c * c) for f_M, f_c in f ] + + +def sdm_zero(): + """Return the zero module element.""" + return [] + + +def sdm_deg(f): + """ + Degree of ``f``. + + This is the maximum of the degrees of all its monomials. + Invalid if ``f`` is zero. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_deg + >>> sdm_deg([((1, 2, 3), 1), ((10, 0, 1), 1), ((2, 3, 4), 4)]) + 7 + """ + return max(sdm_monomial_deg(M[0]) for M in f) + + +# Conversion + +def sdm_from_vector(vec, O, K, **opts): + """ + Create an sdm from an iterable of expressions. + + Coefficients are created in the ground field ``K``, and terms are ordered + according to monomial order ``O``. Named arguments are passed on to the + polys conversion code and can be used to specify for example generators. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_from_vector + >>> from sympy.abc import x, y, z + >>> from sympy.polys import QQ, lex + >>> sdm_from_vector([x**2+y**2, 2*z], lex, QQ) + [((1, 0, 0, 1), 2), ((0, 2, 0, 0), 1), ((0, 0, 2, 0), 1)] + """ + dics, gens = parallel_dict_from_expr(sympify(vec), **opts) + dic = {} + for i, d in enumerate(dics): + for k, v in d.items(): + dic[(i,) + k] = K.convert(v) + return sdm_from_dict(dic, O) + + +def sdm_to_vector(f, gens, K, n=None): + """ + Convert sdm ``f`` into a list of polynomial expressions. + + The generators for the polynomial ring are specified via ``gens``. The rank + of the module is guessed, or passed via ``n``. The ground field is assumed + to be ``K``. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_to_vector + >>> from sympy.abc import x, y, z + >>> from sympy.polys import QQ + >>> f = [((1, 0, 0, 1), QQ(2)), ((0, 2, 0, 0), QQ(1)), ((0, 0, 2, 0), QQ(1))] + >>> sdm_to_vector(f, [x, y, z], QQ) + [x**2 + y**2, 2*z] + """ + dic = sdm_to_dict(f) + dics = {} + for k, v in dic.items(): + dics.setdefault(k[0], []).append((k[1:], v)) + n = n or len(dics) + res = [] + for k in range(n): + if k in dics: + res.append(Poly(dict(dics[k]), gens=gens, domain=K).as_expr()) + else: + res.append(S.Zero) + return res + +# Algorithms. + + +def sdm_spoly(f, g, O, K, phantom=None): + """ + Compute the generalized s-polynomial of ``f`` and ``g``. + + The ground field is assumed to be ``K``, and monomials ordered according to + ``O``. + + This is invalid if either of ``f`` or ``g`` is zero. + + If the leading terms of `f` and `g` involve different basis elements of + `F`, their s-poly is defined to be zero. Otherwise it is a certain linear + combination of `f` and `g` in which the leading terms cancel. + See [SCA, defn 2.3.6] for details. + + If ``phantom`` is not ``None``, it should be a pair of module elements on + which to perform the same operation(s) as on ``f`` and ``g``. The in this + case both results are returned. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_spoly + >>> from sympy.polys import QQ, lex + >>> f = [((2, 1, 1), QQ(1)), ((1, 0, 1), QQ(1))] + >>> g = [((2, 3, 0), QQ(1))] + >>> h = [((1, 2, 3), QQ(1))] + >>> sdm_spoly(f, h, lex, QQ) + [] + >>> sdm_spoly(f, g, lex, QQ) + [((1, 2, 1), 1)] + """ + if not f or not g: + return sdm_zero() + LM1 = sdm_LM(f) + LM2 = sdm_LM(g) + if LM1[0] != LM2[0]: + return sdm_zero() + LM1 = LM1[1:] + LM2 = LM2[1:] + lcm = monomial_lcm(LM1, LM2) + m1 = monomial_div(lcm, LM1) + m2 = monomial_div(lcm, LM2) + c = K.quo(-sdm_LC(f, K), sdm_LC(g, K)) + r1 = sdm_add(sdm_mul_term(f, (m1, K.one), O, K), + sdm_mul_term(g, (m2, c), O, K), O, K) + if phantom is None: + return r1 + r2 = sdm_add(sdm_mul_term(phantom[0], (m1, K.one), O, K), + sdm_mul_term(phantom[1], (m2, c), O, K), O, K) + return r1, r2 + + +def sdm_ecart(f): + """ + Compute the ecart of ``f``. + + This is defined to be the difference of the total degree of `f` and the + total degree of the leading monomial of `f` [SCA, defn 2.3.7]. + + Invalid if f is zero. + + Examples + ======== + + >>> from sympy.polys.distributedmodules import sdm_ecart + >>> sdm_ecart([((1, 2, 3), 1), ((1, 0, 1), 1)]) + 0 + >>> sdm_ecart([((2, 2, 1), 1), ((1, 5, 1), 1)]) + 3 + """ + return sdm_deg(f) - sdm_monomial_deg(sdm_LM(f)) + + +def sdm_nf_mora(f, G, O, K, phantom=None): + r""" + Compute a weak normal form of ``f`` with respect to ``G`` and order ``O``. + + The ground field is assumed to be ``K``, and monomials ordered according to + ``O``. + + Weak normal forms are defined in [SCA, defn 2.3.3]. They are not unique. + This function deterministically computes a weak normal form, depending on + the order of `G`. + + The most important property of a weak normal form is the following: if + `R` is the ring associated with the monomial ordering (if the ordering is + global, we just have `R = K[x_1, \ldots, x_n]`, otherwise it is a certain + localization thereof), `I` any ideal of `R` and `G` a standard basis for + `I`, then for any `f \in R`, we have `f \in I` if and only if + `NF(f | G) = 0`. + + This is the generalized Mora algorithm for computing weak normal forms with + respect to arbitrary monomial orders [SCA, algorithm 2.3.9]. + + If ``phantom`` is not ``None``, it should be a pair of "phantom" arguments + on which to perform the same computations as on ``f``, ``G``, both results + are then returned. + """ + from itertools import repeat + h = f + T = list(G) + if phantom is not None: + # "phantom" variables with suffix p + hp = phantom[0] + Tp = list(phantom[1]) + phantom = True + else: + Tp = repeat([]) + phantom = False + while h: + # TODO better data structure!!! + Th = [(g, sdm_ecart(g), gp) for g, gp in zip(T, Tp) + if sdm_monomial_divides(sdm_LM(g), sdm_LM(h))] + if not Th: + break + g, _, gp = min(Th, key=lambda x: x[1]) + if sdm_ecart(g) > sdm_ecart(h): + T.append(h) + if phantom: + Tp.append(hp) + if phantom: + h, hp = sdm_spoly(h, g, O, K, phantom=(hp, gp)) + else: + h = sdm_spoly(h, g, O, K) + if phantom: + return h, hp + return h + + +def sdm_nf_buchberger(f, G, O, K, phantom=None): + r""" + Compute a weak normal form of ``f`` with respect to ``G`` and order ``O``. + + The ground field is assumed to be ``K``, and monomials ordered according to + ``O``. + + This is the standard Buchberger algorithm for computing weak normal forms with + respect to *global* monomial orders [SCA, algorithm 1.6.10]. + + If ``phantom`` is not ``None``, it should be a pair of "phantom" arguments + on which to perform the same computations as on ``f``, ``G``, both results + are then returned. + """ + from itertools import repeat + h = f + T = list(G) + if phantom is not None: + # "phantom" variables with suffix p + hp = phantom[0] + Tp = list(phantom[1]) + phantom = True + else: + Tp = repeat([]) + phantom = False + while h: + try: + g, gp = next((g, gp) for g, gp in zip(T, Tp) + if sdm_monomial_divides(sdm_LM(g), sdm_LM(h))) + except StopIteration: + break + if phantom: + h, hp = sdm_spoly(h, g, O, K, phantom=(hp, gp)) + else: + h = sdm_spoly(h, g, O, K) + if phantom: + return h, hp + return h + + +def sdm_nf_buchberger_reduced(f, G, O, K): + r""" + Compute a reduced normal form of ``f`` with respect to ``G`` and order ``O``. + + The ground field is assumed to be ``K``, and monomials ordered according to + ``O``. + + In contrast to weak normal forms, reduced normal forms *are* unique, but + their computation is more expensive. + + This is the standard Buchberger algorithm for computing reduced normal forms + with respect to *global* monomial orders [SCA, algorithm 1.6.11]. + + The ``pantom`` option is not supported, so this normal form cannot be used + as a normal form for the "extended" groebner algorithm. + """ + h = sdm_zero() + g = f + while g: + g = sdm_nf_buchberger(g, G, O, K) + if g: + h = sdm_add(h, [sdm_LT(g)], O, K) + g = g[1:] + return h + + +def sdm_groebner(G, NF, O, K, extended=False): + """ + Compute a minimal standard basis of ``G`` with respect to order ``O``. + + The algorithm uses a normal form ``NF``, for example ``sdm_nf_mora``. + The ground field is assumed to be ``K``, and monomials ordered according + to ``O``. + + Let `N` denote the submodule generated by elements of `G`. A standard + basis for `N` is a subset `S` of `N`, such that `in(S) = in(N)`, where for + any subset `X` of `F`, `in(X)` denotes the submodule generated by the + initial forms of elements of `X`. [SCA, defn 2.3.2] + + A standard basis is called minimal if no subset of it is a standard basis. + + One may show that standard bases are always generating sets. + + Minimal standard bases are not unique. This algorithm computes a + deterministic result, depending on the particular order of `G`. + + If ``extended=True``, also compute the transition matrix from the initial + generators to the groebner basis. That is, return a list of coefficient + vectors, expressing the elements of the groebner basis in terms of the + elements of ``G``. + + This functions implements the "sugar" strategy, see + + Giovini et al: "One sugar cube, please" OR Selection strategies in + Buchberger algorithm. + """ + + # The critical pair set. + # A critical pair is stored as (i, j, s, t) where (i, j) defines the pair + # (by indexing S), s is the sugar of the pair, and t is the lcm of their + # leading monomials. + P = [] + + # The eventual standard basis. + S = [] + Sugars = [] + + def Ssugar(i, j): + """Compute the sugar of the S-poly corresponding to (i, j).""" + LMi = sdm_LM(S[i]) + LMj = sdm_LM(S[j]) + return max(Sugars[i] - sdm_monomial_deg(LMi), + Sugars[j] - sdm_monomial_deg(LMj)) \ + + sdm_monomial_deg(sdm_monomial_lcm(LMi, LMj)) + + ourkey = lambda p: (p[2], O(p[3]), p[1]) + + def update(f, sugar, P): + """Add f with sugar ``sugar`` to S, update P.""" + if not f: + return P + k = len(S) + S.append(f) + Sugars.append(sugar) + + LMf = sdm_LM(f) + + def removethis(pair): + i, j, s, t = pair + if LMf[0] != t[0]: + return False + tik = sdm_monomial_lcm(LMf, sdm_LM(S[i])) + tjk = sdm_monomial_lcm(LMf, sdm_LM(S[j])) + return tik != t and tjk != t and sdm_monomial_divides(tik, t) and \ + sdm_monomial_divides(tjk, t) + # apply the chain criterion + P = [p for p in P if not removethis(p)] + + # new-pair set + N = [(i, k, Ssugar(i, k), sdm_monomial_lcm(LMf, sdm_LM(S[i]))) + for i in range(k) if LMf[0] == sdm_LM(S[i])[0]] + # TODO apply the product criterion? + N.sort(key=ourkey) + remove = set() + for i, p in enumerate(N): + for j in range(i + 1, len(N)): + if sdm_monomial_divides(p[3], N[j][3]): + remove.add(j) + + # TODO mergesort? + P.extend(reversed([p for i, p in enumerate(N) if i not in remove])) + P.sort(key=ourkey, reverse=True) + # NOTE reverse-sort, because we want to pop from the end + return P + + # Figure out the number of generators in the ground ring. + try: + # NOTE: we look for the first non-zero vector, take its first monomial + # the number of generators in the ring is one less than the length + # (since the zeroth entry is for the module generators) + numgens = len(next(x[0] for x in G if x)[0]) - 1 + except StopIteration: + # No non-zero elements in G ... + if extended: + return [], [] + return [] + + # This list will store expressions of the elements of S in terms of the + # initial generators + coefficients = [] + + # First add all the elements of G to S + for i, f in enumerate(G): + P = update(f, sdm_deg(f), P) + if extended and f: + coefficients.append(sdm_from_dict({(i,) + (0,)*numgens: K(1)}, O)) + + # Now carry out the buchberger algorithm. + while P: + i, j, s, t = P.pop() + f, g = S[i], S[j] + if extended: + sp, coeff = sdm_spoly(f, g, O, K, + phantom=(coefficients[i], coefficients[j])) + h, hcoeff = NF(sp, S, O, K, phantom=(coeff, coefficients)) + if h: + coefficients.append(hcoeff) + else: + h = NF(sdm_spoly(f, g, O, K), S, O, K) + P = update(h, Ssugar(i, j), P) + + # Finally interreduce the standard basis. + # (TODO again, better data structures) + S = {(tuple(f), i) for i, f in enumerate(S)} + for (a, ai), (b, bi) in permutations(S, 2): + A = sdm_LM(a) + B = sdm_LM(b) + if sdm_monomial_divides(A, B) and (b, bi) in S and (a, ai) in S: + S.remove((b, bi)) + + L = sorted(((list(f), i) for f, i in S), key=lambda p: O(sdm_LM(p[0])), + reverse=True) + res = [x[0] for x in L] + if extended: + return res, [coefficients[i] for _, i in L] + return res diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domainmatrix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domainmatrix.py new file mode 100644 index 0000000000000000000000000000000000000000..c0ccaaa4cb96e0c49da58d8e9128c1b6fa551ade --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domainmatrix.py @@ -0,0 +1,12 @@ +""" +Stub module to expose DomainMatrix which has now moved to +sympy.polys.matrices package. It should now be imported as: + + >>> from sympy.polys.matrices import DomainMatrix + +This module might be removed in future. +""" + +from sympy.polys.matrices.domainmatrix import DomainMatrix + +__all__ = ['DomainMatrix'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/euclidtools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/euclidtools.py new file mode 100644 index 0000000000000000000000000000000000000000..768a44a94930f05e701e9f27a8b0f570a3312314 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/euclidtools.py @@ -0,0 +1,1912 @@ +"""Euclidean algorithms, GCDs, LCMs and polynomial remainder sequences. """ + + +from sympy.polys.densearith import ( + dup_sub_mul, + dup_neg, dmp_neg, + dmp_add, + dmp_sub, + dup_mul, dmp_mul, + dmp_pow, + dup_div, dmp_div, + dup_rem, + dup_quo, dmp_quo, + dup_prem, dmp_prem, + dup_mul_ground, dmp_mul_ground, + dmp_mul_term, + dup_quo_ground, dmp_quo_ground, + dup_max_norm, dmp_max_norm) +from sympy.polys.densebasic import ( + dup_strip, dmp_raise, + dmp_zero, dmp_one, dmp_ground, + dmp_one_p, dmp_zero_p, + dmp_zeros, + dup_degree, dmp_degree, dmp_degree_in, + dup_LC, dmp_LC, dmp_ground_LC, + dmp_multi_deflate, dmp_inflate, + dup_convert, dmp_convert, + dmp_apply_pairs) +from sympy.polys.densetools import ( + dup_clear_denoms, dmp_clear_denoms, + dup_diff, dmp_diff, + dup_eval, dmp_eval, dmp_eval_in, + dup_trunc, dmp_ground_trunc, + dup_monic, dmp_ground_monic, + dup_primitive, dmp_ground_primitive, + dup_extract, dmp_ground_extract) +from sympy.polys.galoistools import ( + gf_int, gf_crt) +from sympy.polys.polyconfig import query +from sympy.polys.polyerrors import ( + MultivariatePolynomialError, + HeuristicGCDFailed, + HomomorphismFailed, + NotInvertible, + DomainError) + + + + +def dup_half_gcdex(f, g, K): + """ + Half extended Euclidean algorithm in `F[x]`. + + Returns ``(s, h)`` such that ``h = gcd(f, g)`` and ``s*f = h (mod g)``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 + >>> g = x**3 + x**2 - 4*x - 4 + + >>> R.dup_half_gcdex(f, g) + (-1/5*x + 3/5, x + 1) + + """ + if not K.is_Field: + raise DomainError("Cannot compute half extended GCD over %s" % K) + + a, b = [K.one], [] + + while g: + q, r = dup_div(f, g, K) + f, g = g, r + a, b = b, dup_sub_mul(a, q, b, K) + + a = dup_quo_ground(a, dup_LC(f, K), K) + f = dup_monic(f, K) + + return a, f + + +def dmp_half_gcdex(f, g, u, K): + """ + Half extended Euclidean algorithm in `F[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + """ + if not u: + return dup_half_gcdex(f, g, K) + else: + raise MultivariatePolynomialError(f, g) + + +def dup_gcdex(f, g, K): + """ + Extended Euclidean algorithm in `F[x]`. + + Returns ``(s, t, h)`` such that ``h = gcd(f, g)`` and ``s*f + t*g = h``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 + >>> g = x**3 + x**2 - 4*x - 4 + + >>> R.dup_gcdex(f, g) + (-1/5*x + 3/5, 1/5*x**2 - 6/5*x + 2, x + 1) + + """ + s, h = dup_half_gcdex(f, g, K) + + F = dup_sub_mul(h, s, f, K) + t = dup_quo(F, g, K) + + return s, t, h + + +def dmp_gcdex(f, g, u, K): + """ + Extended Euclidean algorithm in `F[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + """ + if not u: + return dup_gcdex(f, g, K) + else: + raise MultivariatePolynomialError(f, g) + + +def dup_invert(f, g, K): + """ + Compute multiplicative inverse of `f` modulo `g` in `F[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = x**2 - 1 + >>> g = 2*x - 1 + >>> h = x - 1 + + >>> R.dup_invert(f, g) + -4/3 + + >>> R.dup_invert(f, h) + Traceback (most recent call last): + ... + NotInvertible: zero divisor + + """ + s, h = dup_half_gcdex(f, g, K) + + if h == [K.one]: + return dup_rem(s, g, K) + else: + raise NotInvertible("zero divisor") + + +def dmp_invert(f, g, u, K): + """ + Compute multiplicative inverse of `f` modulo `g` in `F[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + """ + if not u: + return dup_invert(f, g, K) + else: + raise MultivariatePolynomialError(f, g) + + +def dup_euclidean_prs(f, g, K): + """ + Euclidean polynomial remainder sequence (PRS) in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + >>> g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + + >>> prs = R.dup_euclidean_prs(f, g) + + >>> prs[0] + x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + >>> prs[1] + 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + >>> prs[2] + -5/9*x**4 + 1/9*x**2 - 1/3 + >>> prs[3] + -117/25*x**2 - 9*x + 441/25 + >>> prs[4] + 233150/19773*x - 102500/6591 + >>> prs[5] + -1288744821/543589225 + + """ + prs = [f, g] + h = dup_rem(f, g, K) + + while h: + prs.append(h) + f, g = g, h + h = dup_rem(f, g, K) + + return prs + + +def dmp_euclidean_prs(f, g, u, K): + """ + Euclidean polynomial remainder sequence (PRS) in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + """ + if not u: + return dup_euclidean_prs(f, g, K) + else: + raise MultivariatePolynomialError(f, g) + + +def dup_primitive_prs(f, g, K): + """ + Primitive polynomial remainder sequence (PRS) in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + >>> g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + + >>> prs = R.dup_primitive_prs(f, g) + + >>> prs[0] + x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + >>> prs[1] + 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + >>> prs[2] + -5*x**4 + x**2 - 3 + >>> prs[3] + 13*x**2 + 25*x - 49 + >>> prs[4] + 4663*x - 6150 + >>> prs[5] + 1 + + """ + prs = [f, g] + _, h = dup_primitive(dup_prem(f, g, K), K) + + while h: + prs.append(h) + f, g = g, h + _, h = dup_primitive(dup_prem(f, g, K), K) + + return prs + + +def dmp_primitive_prs(f, g, u, K): + """ + Primitive polynomial remainder sequence (PRS) in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + """ + if not u: + return dup_primitive_prs(f, g, K) + else: + raise MultivariatePolynomialError(f, g) + + +def dup_inner_subresultants(f, g, K): + """ + Subresultant PRS algorithm in `K[x]`. + + Computes the subresultant polynomial remainder sequence (PRS) + and the non-zero scalar subresultants of `f` and `g`. + By [1] Thm. 3, these are the constants '-c' (- to optimize + computation of sign). + The first subdeterminant is set to 1 by convention to match + the polynomial and the scalar subdeterminants. + If 'deg(f) < deg(g)', the subresultants of '(g,f)' are computed. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_inner_subresultants(x**2 + 1, x**2 - 1) + ([x**2 + 1, x**2 - 1, -2], [1, 1, 4]) + + References + ========== + + .. [1] W.S. Brown, The Subresultant PRS Algorithm. + ACM Transaction of Mathematical Software 4 (1978) 237-249 + + """ + n = dup_degree(f) + m = dup_degree(g) + + if n < m: + f, g = g, f + n, m = m, n + + if not f: + return [], [] + + if not g: + return [f], [K.one] + + R = [f, g] + d = n - m + + b = (-K.one)**(d + 1) + + h = dup_prem(f, g, K) + h = dup_mul_ground(h, b, K) + + lc = dup_LC(g, K) + c = lc**d + + # Conventional first scalar subdeterminant is 1 + S = [K.one, c] + c = -c + + while h: + k = dup_degree(h) + R.append(h) + + f, g, m, d = g, h, k, m - k + + b = -lc * c**d + + h = dup_prem(f, g, K) + h = dup_quo_ground(h, b, K) + + lc = dup_LC(g, K) + + if d > 1: # abnormal case + q = c**(d - 1) + c = K.quo((-lc)**d, q) + else: + c = -lc + + S.append(-c) + + return R, S + + +def dup_subresultants(f, g, K): + """ + Computes subresultant PRS of two polynomials in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_subresultants(x**2 + 1, x**2 - 1) + [x**2 + 1, x**2 - 1, -2] + + """ + return dup_inner_subresultants(f, g, K)[0] + + +def dup_prs_resultant(f, g, K): + """ + Resultant algorithm in `K[x]` using subresultant PRS. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_prs_resultant(x**2 + 1, x**2 - 1) + (4, [x**2 + 1, x**2 - 1, -2]) + + """ + if not f or not g: + return (K.zero, []) + + R, S = dup_inner_subresultants(f, g, K) + + if dup_degree(R[-1]) > 0: + return (K.zero, R) + + return S[-1], R + + +def dup_resultant(f, g, K, includePRS=False): + """ + Computes resultant of two polynomials in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_resultant(x**2 + 1, x**2 - 1) + 4 + + """ + if includePRS: + return dup_prs_resultant(f, g, K) + return dup_prs_resultant(f, g, K)[0] + + +def dmp_inner_subresultants(f, g, u, K): + """ + Subresultant PRS algorithm in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = 3*x**2*y - y**3 - 4 + >>> g = x**2 + x*y**3 - 9 + + >>> a = 3*x*y**4 + y**3 - 27*y + 4 + >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 + + >>> prs = [f, g, a, b] + >>> sres = [[1], [1], [3, 0, 0, 0, 0], [-3, 0, 0, -12, 1, 0, -54, 8, 729, -216, 16]] + + >>> R.dmp_inner_subresultants(f, g) == (prs, sres) + True + + """ + if not u: + return dup_inner_subresultants(f, g, K) + + n = dmp_degree(f, u) + m = dmp_degree(g, u) + + if n < m: + f, g = g, f + n, m = m, n + + if dmp_zero_p(f, u): + return [], [] + + v = u - 1 + if dmp_zero_p(g, u): + return [f], [dmp_ground(K.one, v)] + + R = [f, g] + d = n - m + + b = dmp_pow(dmp_ground(-K.one, v), d + 1, v, K) + + h = dmp_prem(f, g, u, K) + h = dmp_mul_term(h, b, 0, u, K) + + lc = dmp_LC(g, K) + c = dmp_pow(lc, d, v, K) + + S = [dmp_ground(K.one, v), c] + c = dmp_neg(c, v, K) + + while not dmp_zero_p(h, u): + k = dmp_degree(h, u) + R.append(h) + + f, g, m, d = g, h, k, m - k + + b = dmp_mul(dmp_neg(lc, v, K), + dmp_pow(c, d, v, K), v, K) + + h = dmp_prem(f, g, u, K) + h = [ dmp_quo(ch, b, v, K) for ch in h ] + + lc = dmp_LC(g, K) + + if d > 1: + p = dmp_pow(dmp_neg(lc, v, K), d, v, K) + q = dmp_pow(c, d - 1, v, K) + c = dmp_quo(p, q, v, K) + else: + c = dmp_neg(lc, v, K) + + S.append(dmp_neg(c, v, K)) + + return R, S + + +def dmp_subresultants(f, g, u, K): + """ + Computes subresultant PRS of two polynomials in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = 3*x**2*y - y**3 - 4 + >>> g = x**2 + x*y**3 - 9 + + >>> a = 3*x*y**4 + y**3 - 27*y + 4 + >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 + + >>> R.dmp_subresultants(f, g) == [f, g, a, b] + True + + """ + return dmp_inner_subresultants(f, g, u, K)[0] + + +def dmp_prs_resultant(f, g, u, K): + """ + Resultant algorithm in `K[X]` using subresultant PRS. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = 3*x**2*y - y**3 - 4 + >>> g = x**2 + x*y**3 - 9 + + >>> a = 3*x*y**4 + y**3 - 27*y + 4 + >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 + + >>> res, prs = R.dmp_prs_resultant(f, g) + + >>> res == b # resultant has n-1 variables + False + >>> res == b.drop(x) + True + >>> prs == [f, g, a, b] + True + + """ + if not u: + return dup_prs_resultant(f, g, K) + + if dmp_zero_p(f, u) or dmp_zero_p(g, u): + return (dmp_zero(u - 1), []) + + R, S = dmp_inner_subresultants(f, g, u, K) + + if dmp_degree(R[-1], u) > 0: + return (dmp_zero(u - 1), R) + + return S[-1], R + + +def dmp_zz_modular_resultant(f, g, p, u, K): + """ + Compute resultant of `f` and `g` modulo a prime `p`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x + y + 2 + >>> g = 2*x*y + x + 3 + + >>> R.dmp_zz_modular_resultant(f, g, 5) + -2*y**2 + 1 + + """ + if not u: + return gf_int(dup_prs_resultant(f, g, K)[0] % p, p) + + v = u - 1 + + n = dmp_degree(f, u) + m = dmp_degree(g, u) + + N = dmp_degree_in(f, 1, u) + M = dmp_degree_in(g, 1, u) + + B = n*M + m*N + + D, a = [K.one], -K.one + r = dmp_zero(v) + + while dup_degree(D) <= B: + while True: + a += K.one + + if a == p: + raise HomomorphismFailed('no luck') + + F = dmp_eval_in(f, gf_int(a, p), 1, u, K) + + if dmp_degree(F, v) == n: + G = dmp_eval_in(g, gf_int(a, p), 1, u, K) + + if dmp_degree(G, v) == m: + break + + R = dmp_zz_modular_resultant(F, G, p, v, K) + e = dmp_eval(r, a, v, K) + + if not v: + R = dup_strip([R]) + e = dup_strip([e]) + else: + R = [R] + e = [e] + + d = K.invert(dup_eval(D, a, K), p) + d = dup_mul_ground(D, d, K) + d = dmp_raise(d, v, 0, K) + + c = dmp_mul(d, dmp_sub(R, e, v, K), v, K) + r = dmp_add(r, c, v, K) + + r = dmp_ground_trunc(r, p, v, K) + + D = dup_mul(D, [K.one, -a], K) + D = dup_trunc(D, p, K) + + return r + + +def _collins_crt(r, R, P, p, K): + """Wrapper of CRT for Collins's resultant algorithm. """ + return gf_int(gf_crt([r, R], [P, p], K), P*p) + + +def dmp_zz_collins_resultant(f, g, u, K): + """ + Collins's modular resultant algorithm in `Z[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x + y + 2 + >>> g = 2*x*y + x + 3 + + >>> R.dmp_zz_collins_resultant(f, g) + -2*y**2 - 5*y + 1 + + """ + + n = dmp_degree(f, u) + m = dmp_degree(g, u) + + if n < 0 or m < 0: + return dmp_zero(u - 1) + + A = dmp_max_norm(f, u, K) + B = dmp_max_norm(g, u, K) + + a = dmp_ground_LC(f, u, K) + b = dmp_ground_LC(g, u, K) + + v = u - 1 + + B = K(2)*K.factorial(K(n + m))*A**m*B**n + r, p, P = dmp_zero(v), K.one, K.one + + from sympy.ntheory import nextprime + + while P <= B: + p = K(nextprime(p)) + + while not (a % p) or not (b % p): + p = K(nextprime(p)) + + F = dmp_ground_trunc(f, p, u, K) + G = dmp_ground_trunc(g, p, u, K) + + try: + R = dmp_zz_modular_resultant(F, G, p, u, K) + except HomomorphismFailed: + continue + + if K.is_one(P): + r = R + else: + r = dmp_apply_pairs(r, R, _collins_crt, (P, p, K), v, K) + + P *= p + + return r + + +def dmp_qq_collins_resultant(f, g, u, K0): + """ + Collins's modular resultant algorithm in `Q[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) + + >>> f = QQ(1,2)*x + y + QQ(2,3) + >>> g = 2*x*y + x + 3 + + >>> R.dmp_qq_collins_resultant(f, g) + -2*y**2 - 7/3*y + 5/6 + + """ + n = dmp_degree(f, u) + m = dmp_degree(g, u) + + if n < 0 or m < 0: + return dmp_zero(u - 1) + + K1 = K0.get_ring() + + cf, f = dmp_clear_denoms(f, u, K0, K1) + cg, g = dmp_clear_denoms(g, u, K0, K1) + + f = dmp_convert(f, u, K0, K1) + g = dmp_convert(g, u, K0, K1) + + r = dmp_zz_collins_resultant(f, g, u, K1) + r = dmp_convert(r, u - 1, K1, K0) + + c = K0.convert(cf**m * cg**n, K1) + + return dmp_quo_ground(r, c, u - 1, K0) + + +def dmp_resultant(f, g, u, K, includePRS=False): + """ + Computes resultant of two polynomials in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = 3*x**2*y - y**3 - 4 + >>> g = x**2 + x*y**3 - 9 + + >>> R.dmp_resultant(f, g) + -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 + + """ + if not u: + return dup_resultant(f, g, K, includePRS=includePRS) + + if includePRS: + return dmp_prs_resultant(f, g, u, K) + + if K.is_Field: + if K.is_QQ and query('USE_COLLINS_RESULTANT'): + return dmp_qq_collins_resultant(f, g, u, K) + else: + if K.is_ZZ and query('USE_COLLINS_RESULTANT'): + return dmp_zz_collins_resultant(f, g, u, K) + + return dmp_prs_resultant(f, g, u, K)[0] + + +def dup_discriminant(f, K): + """ + Computes discriminant of a polynomial in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_discriminant(x**2 + 2*x + 3) + -8 + + """ + d = dup_degree(f) + + if d <= 0: + return K.zero + else: + s = (-1)**((d*(d - 1)) // 2) + c = dup_LC(f, K) + + r = dup_resultant(f, dup_diff(f, 1, K), K) + + return K.quo(r, c*K(s)) + + +def dmp_discriminant(f, u, K): + """ + Computes discriminant of a polynomial in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y,z,t = ring("x,y,z,t", ZZ) + + >>> R.dmp_discriminant(x**2*y + x*z + t) + -4*y*t + z**2 + + """ + if not u: + return dup_discriminant(f, K) + + d, v = dmp_degree(f, u), u - 1 + + if d <= 0: + return dmp_zero(v) + else: + s = (-1)**((d*(d - 1)) // 2) + c = dmp_LC(f, K) + + r = dmp_resultant(f, dmp_diff(f, 1, u, K), u, K) + c = dmp_mul_ground(c, K(s), v, K) + + return dmp_quo(r, c, v, K) + + +def _dup_rr_trivial_gcd(f, g, K): + """Handle trivial cases in GCD algorithm over a ring. """ + if not (f or g): + return [], [], [] + elif not f: + if K.is_nonnegative(dup_LC(g, K)): + return g, [], [K.one] + else: + return dup_neg(g, K), [], [-K.one] + elif not g: + if K.is_nonnegative(dup_LC(f, K)): + return f, [K.one], [] + else: + return dup_neg(f, K), [-K.one], [] + + return None + + +def _dup_ff_trivial_gcd(f, g, K): + """Handle trivial cases in GCD algorithm over a field. """ + if not (f or g): + return [], [], [] + elif not f: + return dup_monic(g, K), [], [dup_LC(g, K)] + elif not g: + return dup_monic(f, K), [dup_LC(f, K)], [] + else: + return None + + +def _dmp_rr_trivial_gcd(f, g, u, K): + """Handle trivial cases in GCD algorithm over a ring. """ + zero_f = dmp_zero_p(f, u) + zero_g = dmp_zero_p(g, u) + if_contain_one = dmp_one_p(f, u, K) or dmp_one_p(g, u, K) + + if zero_f and zero_g: + return tuple(dmp_zeros(3, u, K)) + elif zero_f: + if K.is_nonnegative(dmp_ground_LC(g, u, K)): + return g, dmp_zero(u), dmp_one(u, K) + else: + return dmp_neg(g, u, K), dmp_zero(u), dmp_ground(-K.one, u) + elif zero_g: + if K.is_nonnegative(dmp_ground_LC(f, u, K)): + return f, dmp_one(u, K), dmp_zero(u) + else: + return dmp_neg(f, u, K), dmp_ground(-K.one, u), dmp_zero(u) + elif if_contain_one: + return dmp_one(u, K), f, g + elif query('USE_SIMPLIFY_GCD'): + return _dmp_simplify_gcd(f, g, u, K) + else: + return None + + +def _dmp_ff_trivial_gcd(f, g, u, K): + """Handle trivial cases in GCD algorithm over a field. """ + zero_f = dmp_zero_p(f, u) + zero_g = dmp_zero_p(g, u) + + if zero_f and zero_g: + return tuple(dmp_zeros(3, u, K)) + elif zero_f: + return (dmp_ground_monic(g, u, K), + dmp_zero(u), + dmp_ground(dmp_ground_LC(g, u, K), u)) + elif zero_g: + return (dmp_ground_monic(f, u, K), + dmp_ground(dmp_ground_LC(f, u, K), u), + dmp_zero(u)) + elif query('USE_SIMPLIFY_GCD'): + return _dmp_simplify_gcd(f, g, u, K) + else: + return None + + +def _dmp_simplify_gcd(f, g, u, K): + """Try to eliminate `x_0` from GCD computation in `K[X]`. """ + df = dmp_degree(f, u) + dg = dmp_degree(g, u) + + if df > 0 and dg > 0: + return None + + if not (df or dg): + F = dmp_LC(f, K) + G = dmp_LC(g, K) + else: + if not df: + F = dmp_LC(f, K) + G = dmp_content(g, u, K) + else: + F = dmp_content(f, u, K) + G = dmp_LC(g, K) + + v = u - 1 + h = dmp_gcd(F, G, v, K) + + cff = [ dmp_quo(cf, h, v, K) for cf in f ] + cfg = [ dmp_quo(cg, h, v, K) for cg in g ] + + return [h], cff, cfg + + +def dup_rr_prs_gcd(f, g, K): + """ + Computes polynomial GCD using subresultants over a ring. + + Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, + and ``cfg = quo(g, h)``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_rr_prs_gcd(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) + + """ + result = _dup_rr_trivial_gcd(f, g, K) + + if result is not None: + return result + + fc, F = dup_primitive(f, K) + gc, G = dup_primitive(g, K) + + c = K.gcd(fc, gc) + + h = dup_subresultants(F, G, K)[-1] + _, h = dup_primitive(h, K) + + c *= K.canonical_unit(dup_LC(h, K)) + + h = dup_mul_ground(h, c, K) + + cff = dup_quo(f, h, K) + cfg = dup_quo(g, h, K) + + return h, cff, cfg + + +def dup_ff_prs_gcd(f, g, K): + """ + Computes polynomial GCD using subresultants over a field. + + Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, + and ``cfg = quo(g, h)``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> R.dup_ff_prs_gcd(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) + + """ + result = _dup_ff_trivial_gcd(f, g, K) + + if result is not None: + return result + + h = dup_subresultants(f, g, K)[-1] + h = dup_monic(h, K) + + cff = dup_quo(f, h, K) + cfg = dup_quo(g, h, K) + + return h, cff, cfg + + +def dmp_rr_prs_gcd(f, g, u, K): + """ + Computes polynomial GCD using subresultants over a ring. + + Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, + and ``cfg = quo(g, h)``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) + + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y + + >>> R.dmp_rr_prs_gcd(f, g) + (x + y, x + y, x) + + """ + if not u: + return dup_rr_prs_gcd(f, g, K) + + result = _dmp_rr_trivial_gcd(f, g, u, K) + + if result is not None: + return result + + fc, F = dmp_primitive(f, u, K) + gc, G = dmp_primitive(g, u, K) + + h = dmp_subresultants(F, G, u, K)[-1] + c, _, _ = dmp_rr_prs_gcd(fc, gc, u - 1, K) + + _, h = dmp_primitive(h, u, K) + h = dmp_mul_term(h, c, 0, u, K) + + unit = K.canonical_unit(dmp_ground_LC(h, u, K)) + + if unit != K.one: + h = dmp_mul_ground(h, unit, u, K) + + cff = dmp_quo(f, h, u, K) + cfg = dmp_quo(g, h, u, K) + + return h, cff, cfg + + +def dmp_ff_prs_gcd(f, g, u, K): + """ + Computes polynomial GCD using subresultants over a field. + + Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, + and ``cfg = quo(g, h)``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y, = ring("x,y", QQ) + + >>> f = QQ(1,2)*x**2 + x*y + QQ(1,2)*y**2 + >>> g = x**2 + x*y + + >>> R.dmp_ff_prs_gcd(f, g) + (x + y, 1/2*x + 1/2*y, x) + + """ + if not u: + return dup_ff_prs_gcd(f, g, K) + + result = _dmp_ff_trivial_gcd(f, g, u, K) + + if result is not None: + return result + + fc, F = dmp_primitive(f, u, K) + gc, G = dmp_primitive(g, u, K) + + h = dmp_subresultants(F, G, u, K)[-1] + c, _, _ = dmp_ff_prs_gcd(fc, gc, u - 1, K) + + _, h = dmp_primitive(h, u, K) + h = dmp_mul_term(h, c, 0, u, K) + h = dmp_ground_monic(h, u, K) + + cff = dmp_quo(f, h, u, K) + cfg = dmp_quo(g, h, u, K) + + return h, cff, cfg + +HEU_GCD_MAX = 6 + + +def _dup_zz_gcd_interpolate(h, x, K): + """Interpolate polynomial GCD from integer GCD. """ + f = [] + + while h: + g = h % x + + if g > x // 2: + g -= x + + f.insert(0, g) + h = (h - g) // x + + return f + + +def dup_zz_heu_gcd(f, g, K): + """ + Heuristic polynomial GCD in `Z[x]`. + + Given univariate polynomials `f` and `g` in `Z[x]`, returns + their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` + such that:: + + h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) + + The algorithm is purely heuristic which means it may fail to compute + the GCD. This will be signaled by raising an exception. In this case + you will need to switch to another GCD method. + + The algorithm computes the polynomial GCD by evaluating polynomials + f and g at certain points and computing (fast) integer GCD of those + evaluations. The polynomial GCD is recovered from the integer image + by interpolation. The final step is to verify if the result is the + correct GCD. This gives cofactors as a side effect. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_zz_heu_gcd(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) + + References + ========== + + .. [1] [Liao95]_ + + """ + result = _dup_rr_trivial_gcd(f, g, K) + + if result is not None: + return result + + df = dup_degree(f) + dg = dup_degree(g) + + gcd, f, g = dup_extract(f, g, K) + + if df == 0 or dg == 0: + return [gcd], f, g + + f_norm = dup_max_norm(f, K) + g_norm = dup_max_norm(g, K) + + B = K(2*min(f_norm, g_norm) + 29) + + x = max(min(B, 99*K.sqrt(B)), + 2*min(f_norm // abs(dup_LC(f, K)), + g_norm // abs(dup_LC(g, K))) + 4) + + for i in range(0, HEU_GCD_MAX): + ff = dup_eval(f, x, K) + gg = dup_eval(g, x, K) + + if ff and gg: + h = K.gcd(ff, gg) + + cff = ff // h + cfg = gg // h + + h = _dup_zz_gcd_interpolate(h, x, K) + h = dup_primitive(h, K)[1] + + cff_, r = dup_div(f, h, K) + + if not r: + cfg_, r = dup_div(g, h, K) + + if not r: + h = dup_mul_ground(h, gcd, K) + return h, cff_, cfg_ + + cff = _dup_zz_gcd_interpolate(cff, x, K) + + h, r = dup_div(f, cff, K) + + if not r: + cfg_, r = dup_div(g, h, K) + + if not r: + h = dup_mul_ground(h, gcd, K) + return h, cff, cfg_ + + cfg = _dup_zz_gcd_interpolate(cfg, x, K) + + h, r = dup_div(g, cfg, K) + + if not r: + cff_, r = dup_div(f, h, K) + + if not r: + h = dup_mul_ground(h, gcd, K) + return h, cff_, cfg + + x = 73794*x * K.sqrt(K.sqrt(x)) // 27011 + + raise HeuristicGCDFailed('no luck') + + +def _dmp_zz_gcd_interpolate(h, x, v, K): + """Interpolate polynomial GCD from integer GCD. """ + f = [] + + while not dmp_zero_p(h, v): + g = dmp_ground_trunc(h, x, v, K) + f.insert(0, g) + + h = dmp_sub(h, g, v, K) + h = dmp_quo_ground(h, x, v, K) + + if K.is_negative(dmp_ground_LC(f, v + 1, K)): + return dmp_neg(f, v + 1, K) + else: + return f + + +def dmp_zz_heu_gcd(f, g, u, K): + """ + Heuristic polynomial GCD in `Z[X]`. + + Given univariate polynomials `f` and `g` in `Z[X]`, returns + their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` + such that:: + + h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) + + The algorithm is purely heuristic which means it may fail to compute + the GCD. This will be signaled by raising an exception. In this case + you will need to switch to another GCD method. + + The algorithm computes the polynomial GCD by evaluating polynomials + f and g at certain points and computing (fast) integer GCD of those + evaluations. The polynomial GCD is recovered from the integer image + by interpolation. The evaluation process reduces f and g variable by + variable into a large integer. The final step is to verify if the + interpolated polynomial is the correct GCD. This gives cofactors of + the input polynomials as a side effect. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) + + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y + + >>> R.dmp_zz_heu_gcd(f, g) + (x + y, x + y, x) + + References + ========== + + .. [1] [Liao95]_ + + """ + if not u: + return dup_zz_heu_gcd(f, g, K) + + result = _dmp_rr_trivial_gcd(f, g, u, K) + + if result is not None: + return result + + gcd, f, g = dmp_ground_extract(f, g, u, K) + + f_norm = dmp_max_norm(f, u, K) + g_norm = dmp_max_norm(g, u, K) + + B = K(2*min(f_norm, g_norm) + 29) + + x = max(min(B, 99*K.sqrt(B)), + 2*min(f_norm // abs(dmp_ground_LC(f, u, K)), + g_norm // abs(dmp_ground_LC(g, u, K))) + 4) + + for i in range(0, HEU_GCD_MAX): + ff = dmp_eval(f, x, u, K) + gg = dmp_eval(g, x, u, K) + + v = u - 1 + + if not (dmp_zero_p(ff, v) or dmp_zero_p(gg, v)): + h, cff, cfg = dmp_zz_heu_gcd(ff, gg, v, K) + + h = _dmp_zz_gcd_interpolate(h, x, v, K) + h = dmp_ground_primitive(h, u, K)[1] + + cff_, r = dmp_div(f, h, u, K) + + if dmp_zero_p(r, u): + cfg_, r = dmp_div(g, h, u, K) + + if dmp_zero_p(r, u): + h = dmp_mul_ground(h, gcd, u, K) + return h, cff_, cfg_ + + cff = _dmp_zz_gcd_interpolate(cff, x, v, K) + + h, r = dmp_div(f, cff, u, K) + + if dmp_zero_p(r, u): + cfg_, r = dmp_div(g, h, u, K) + + if dmp_zero_p(r, u): + h = dmp_mul_ground(h, gcd, u, K) + return h, cff, cfg_ + + cfg = _dmp_zz_gcd_interpolate(cfg, x, v, K) + + h, r = dmp_div(g, cfg, u, K) + + if dmp_zero_p(r, u): + cff_, r = dmp_div(f, h, u, K) + + if dmp_zero_p(r, u): + h = dmp_mul_ground(h, gcd, u, K) + return h, cff_, cfg + + x = 73794*x * K.sqrt(K.sqrt(x)) // 27011 + + raise HeuristicGCDFailed('no luck') + + +def dup_qq_heu_gcd(f, g, K0): + """ + Heuristic polynomial GCD in `Q[x]`. + + Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, + ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = QQ(1,2)*x**2 + QQ(7,4)*x + QQ(3,2) + >>> g = QQ(1,2)*x**2 + x + + >>> R.dup_qq_heu_gcd(f, g) + (x + 2, 1/2*x + 3/4, 1/2*x) + + """ + result = _dup_ff_trivial_gcd(f, g, K0) + + if result is not None: + return result + + K1 = K0.get_ring() + + cf, f = dup_clear_denoms(f, K0, K1) + cg, g = dup_clear_denoms(g, K0, K1) + + f = dup_convert(f, K0, K1) + g = dup_convert(g, K0, K1) + + h, cff, cfg = dup_zz_heu_gcd(f, g, K1) + + h = dup_convert(h, K1, K0) + + c = dup_LC(h, K0) + h = dup_monic(h, K0) + + cff = dup_convert(cff, K1, K0) + cfg = dup_convert(cfg, K1, K0) + + cff = dup_mul_ground(cff, K0.quo(c, cf), K0) + cfg = dup_mul_ground(cfg, K0.quo(c, cg), K0) + + return h, cff, cfg + + +def dmp_qq_heu_gcd(f, g, u, K0): + """ + Heuristic polynomial GCD in `Q[X]`. + + Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, + ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y, = ring("x,y", QQ) + + >>> f = QQ(1,4)*x**2 + x*y + y**2 + >>> g = QQ(1,2)*x**2 + x*y + + >>> R.dmp_qq_heu_gcd(f, g) + (x + 2*y, 1/4*x + 1/2*y, 1/2*x) + + """ + result = _dmp_ff_trivial_gcd(f, g, u, K0) + + if result is not None: + return result + + K1 = K0.get_ring() + + cf, f = dmp_clear_denoms(f, u, K0, K1) + cg, g = dmp_clear_denoms(g, u, K0, K1) + + f = dmp_convert(f, u, K0, K1) + g = dmp_convert(g, u, K0, K1) + + h, cff, cfg = dmp_zz_heu_gcd(f, g, u, K1) + + h = dmp_convert(h, u, K1, K0) + + c = dmp_ground_LC(h, u, K0) + h = dmp_ground_monic(h, u, K0) + + cff = dmp_convert(cff, u, K1, K0) + cfg = dmp_convert(cfg, u, K1, K0) + + cff = dmp_mul_ground(cff, K0.quo(c, cf), u, K0) + cfg = dmp_mul_ground(cfg, K0.quo(c, cg), u, K0) + + return h, cff, cfg + + +def dup_inner_gcd(f, g, K): + """ + Computes polynomial GCD and cofactors of `f` and `g` in `K[x]`. + + Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, + ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_inner_gcd(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) + + """ + # XXX: This used to check for K.is_Exact but leads to awkward results when + # the domain is something like RR[z] e.g.: + # + # >>> g, p, q = Poly(1, x).cancel(Poly(51.05*x*y - 1.0, x)) + # >>> g + # 1.0 + # >>> p + # Poly(17592186044421.0, x, domain='RR[y]') + # >>> q + # Poly(898081097567692.0*y*x - 17592186044421.0, x, domain='RR[y]')) + # + # Maybe it would be better to flatten into multivariate polynomials first. + if K.is_RR or K.is_CC: + try: + exact = K.get_exact() + except DomainError: + return [K.one], f, g + + f = dup_convert(f, K, exact) + g = dup_convert(g, K, exact) + + h, cff, cfg = dup_inner_gcd(f, g, exact) + + h = dup_convert(h, exact, K) + cff = dup_convert(cff, exact, K) + cfg = dup_convert(cfg, exact, K) + + return h, cff, cfg + elif K.is_Field: + if K.is_QQ and query('USE_HEU_GCD'): + try: + return dup_qq_heu_gcd(f, g, K) + except HeuristicGCDFailed: + pass + + return dup_ff_prs_gcd(f, g, K) + else: + if K.is_ZZ and query('USE_HEU_GCD'): + try: + return dup_zz_heu_gcd(f, g, K) + except HeuristicGCDFailed: + pass + + return dup_rr_prs_gcd(f, g, K) + + +def _dmp_inner_gcd(f, g, u, K): + """Helper function for `dmp_inner_gcd()`. """ + if not K.is_Exact: + try: + exact = K.get_exact() + except DomainError: + return dmp_one(u, K), f, g + + f = dmp_convert(f, u, K, exact) + g = dmp_convert(g, u, K, exact) + + h, cff, cfg = _dmp_inner_gcd(f, g, u, exact) + + h = dmp_convert(h, u, exact, K) + cff = dmp_convert(cff, u, exact, K) + cfg = dmp_convert(cfg, u, exact, K) + + return h, cff, cfg + elif K.is_Field: + if K.is_QQ and query('USE_HEU_GCD'): + try: + return dmp_qq_heu_gcd(f, g, u, K) + except HeuristicGCDFailed: + pass + + return dmp_ff_prs_gcd(f, g, u, K) + else: + if K.is_ZZ and query('USE_HEU_GCD'): + try: + return dmp_zz_heu_gcd(f, g, u, K) + except HeuristicGCDFailed: + pass + + return dmp_rr_prs_gcd(f, g, u, K) + + +def dmp_inner_gcd(f, g, u, K): + """ + Computes polynomial GCD and cofactors of `f` and `g` in `K[X]`. + + Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, + ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) + + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y + + >>> R.dmp_inner_gcd(f, g) + (x + y, x + y, x) + + """ + if not u: + return dup_inner_gcd(f, g, K) + + J, (f, g) = dmp_multi_deflate((f, g), u, K) + h, cff, cfg = _dmp_inner_gcd(f, g, u, K) + + return (dmp_inflate(h, J, u, K), + dmp_inflate(cff, J, u, K), + dmp_inflate(cfg, J, u, K)) + + +def dup_gcd(f, g, K): + """ + Computes polynomial GCD of `f` and `g` in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_gcd(x**2 - 1, x**2 - 3*x + 2) + x - 1 + + """ + return dup_inner_gcd(f, g, K)[0] + + +def dmp_gcd(f, g, u, K): + """ + Computes polynomial GCD of `f` and `g` in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) + + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y + + >>> R.dmp_gcd(f, g) + x + y + + """ + return dmp_inner_gcd(f, g, u, K)[0] + + +def dup_rr_lcm(f, g, K): + """ + Computes polynomial LCM over a ring in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_rr_lcm(x**2 - 1, x**2 - 3*x + 2) + x**3 - 2*x**2 - x + 2 + + """ + if not f or not g: + return dmp_zero(0) + + fc, f = dup_primitive(f, K) + gc, g = dup_primitive(g, K) + + c = K.lcm(fc, gc) + + h = dup_quo(dup_mul(f, g, K), + dup_gcd(f, g, K), K) + + u = K.canonical_unit(dup_LC(h, K)) + + return dup_mul_ground(h, c*u, K) + + +def dup_ff_lcm(f, g, K): + """ + Computes polynomial LCM over a field in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = QQ(1,2)*x**2 + QQ(7,4)*x + QQ(3,2) + >>> g = QQ(1,2)*x**2 + x + + >>> R.dup_ff_lcm(f, g) + x**3 + 7/2*x**2 + 3*x + + """ + h = dup_quo(dup_mul(f, g, K), + dup_gcd(f, g, K), K) + + return dup_monic(h, K) + + +def dup_lcm(f, g, K): + """ + Computes polynomial LCM of `f` and `g` in `K[x]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_lcm(x**2 - 1, x**2 - 3*x + 2) + x**3 - 2*x**2 - x + 2 + + """ + if K.is_Field: + return dup_ff_lcm(f, g, K) + else: + return dup_rr_lcm(f, g, K) + + +def dmp_rr_lcm(f, g, u, K): + """ + Computes polynomial LCM over a ring in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) + + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y + + >>> R.dmp_rr_lcm(f, g) + x**3 + 2*x**2*y + x*y**2 + + """ + fc, f = dmp_ground_primitive(f, u, K) + gc, g = dmp_ground_primitive(g, u, K) + + c = K.lcm(fc, gc) + + h = dmp_quo(dmp_mul(f, g, u, K), + dmp_gcd(f, g, u, K), u, K) + + return dmp_mul_ground(h, c, u, K) + + +def dmp_ff_lcm(f, g, u, K): + """ + Computes polynomial LCM over a field in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x,y, = ring("x,y", QQ) + + >>> f = QQ(1,4)*x**2 + x*y + y**2 + >>> g = QQ(1,2)*x**2 + x*y + + >>> R.dmp_ff_lcm(f, g) + x**3 + 4*x**2*y + 4*x*y**2 + + """ + h = dmp_quo(dmp_mul(f, g, u, K), + dmp_gcd(f, g, u, K), u, K) + + return dmp_ground_monic(h, u, K) + + +def dmp_lcm(f, g, u, K): + """ + Computes polynomial LCM of `f` and `g` in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) + + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y + + >>> R.dmp_lcm(f, g) + x**3 + 2*x**2*y + x*y**2 + + """ + if not u: + return dup_lcm(f, g, K) + + if K.is_Field: + return dmp_ff_lcm(f, g, u, K) + else: + return dmp_rr_lcm(f, g, u, K) + + +def dmp_content(f, u, K): + """ + Returns GCD of multivariate coefficients. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) + + >>> R.dmp_content(2*x*y + 6*x + 4*y + 12) + 2*y + 6 + + """ + cont, v = dmp_LC(f, K), u - 1 + + if dmp_zero_p(f, u): + return cont + + for c in f[1:]: + cont = dmp_gcd(cont, c, v, K) + + if dmp_one_p(cont, v, K): + break + + if K.is_negative(dmp_ground_LC(cont, v, K)): + return dmp_neg(cont, v, K) + else: + return cont + + +def dmp_primitive(f, u, K): + """ + Returns multivariate content and a primitive polynomial. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) + + >>> R.dmp_primitive(2*x*y + 6*x + 4*y + 12) + (2*y + 6, x + 2) + + """ + cont, v = dmp_content(f, u, K), u - 1 + + if dmp_zero_p(f, u) or dmp_one_p(cont, v, K): + return cont, f + else: + return cont, [ dmp_quo(c, cont, v, K) for c in f ] + + +def dup_cancel(f, g, K, include=True): + """ + Cancel common factors in a rational function `f/g`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_cancel(2*x**2 - 2, x**2 - 2*x + 1) + (2*x + 2, x - 1) + + """ + return dmp_cancel(f, g, 0, K, include=include) + + +def dmp_cancel(f, g, u, K, include=True): + """ + Cancel common factors in a rational function `f/g`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_cancel(2*x**2 - 2, x**2 - 2*x + 1) + (2*x + 2, x - 1) + + """ + K0 = None + + if K.is_Field and K.has_assoc_Ring: + K0, K = K, K.get_ring() + + cq, f = dmp_clear_denoms(f, u, K0, K, convert=True) + cp, g = dmp_clear_denoms(g, u, K0, K, convert=True) + else: + cp, cq = K.one, K.one + + _, p, q = dmp_inner_gcd(f, g, u, K) + + if K0 is not None: + _, cp, cq = K.cofactors(cp, cq) + + p = dmp_convert(p, u, K, K0) + q = dmp_convert(q, u, K, K0) + + K = K0 + + p_neg = K.is_negative(dmp_ground_LC(p, u, K)) + q_neg = K.is_negative(dmp_ground_LC(q, u, K)) + + if p_neg and q_neg: + p, q = dmp_neg(p, u, K), dmp_neg(q, u, K) + elif p_neg: + cp, p = -cp, dmp_neg(p, u, K) + elif q_neg: + cp, q = -cp, dmp_neg(q, u, K) + + if not include: + return cp, cq, p, q + + p = dmp_mul_ground(p, cp, u, K) + q = dmp_mul_ground(q, cq, u, K) + + return p, q diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/factortools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/factortools.py new file mode 100644 index 0000000000000000000000000000000000000000..021a6b06cb8802748deef6c69448ebc50503269b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/factortools.py @@ -0,0 +1,1648 @@ +"""Polynomial factorization routines in characteristic zero. """ + +from sympy.external.gmpy import GROUND_TYPES + +from sympy.core.random import _randint + +from sympy.polys.galoistools import ( + gf_from_int_poly, gf_to_int_poly, + gf_lshift, gf_add_mul, gf_mul, + gf_div, gf_rem, + gf_gcdex, + gf_sqf_p, + gf_factor_sqf, gf_factor) + +from sympy.polys.densebasic import ( + dup_LC, dmp_LC, dmp_ground_LC, + dup_TC, + dup_convert, dmp_convert, + dup_degree, dmp_degree, + dmp_degree_in, dmp_degree_list, + dmp_from_dict, + dmp_zero_p, + dmp_one, + dmp_nest, dmp_raise, + dup_strip, + dmp_ground, + dup_inflate, + dmp_exclude, dmp_include, + dmp_inject, dmp_eject, + dup_terms_gcd, dmp_terms_gcd) + +from sympy.polys.densearith import ( + dup_neg, dmp_neg, + dup_add, dmp_add, + dup_sub, dmp_sub, + dup_mul, dmp_mul, + dup_sqr, + dmp_pow, + dup_div, dmp_div, + dup_quo, dmp_quo, + dmp_expand, + dmp_add_mul, + dup_sub_mul, dmp_sub_mul, + dup_lshift, + dup_max_norm, dmp_max_norm, + dup_l1_norm, + dup_mul_ground, dmp_mul_ground, + dup_quo_ground, dmp_quo_ground) + +from sympy.polys.densetools import ( + dup_clear_denoms, dmp_clear_denoms, + dup_trunc, dmp_ground_trunc, + dup_content, + dup_monic, dmp_ground_monic, + dup_primitive, dmp_ground_primitive, + dmp_eval_tail, + dmp_eval_in, dmp_diff_eval_in, + dup_shift, dmp_shift, dup_mirror) + +from sympy.polys.euclidtools import ( + dmp_primitive, + dup_inner_gcd, dmp_inner_gcd) + +from sympy.polys.sqfreetools import ( + dup_sqf_p, + dup_sqf_norm, dmp_sqf_norm, + dup_sqf_part, dmp_sqf_part, + _dup_check_degrees, _dmp_check_degrees, + ) + +from sympy.polys.polyutils import _sort_factors +from sympy.polys.polyconfig import query + +from sympy.polys.polyerrors import ( + ExtraneousFactors, DomainError, CoercionFailed, EvaluationFailed) + +from sympy.utilities import subsets + +from math import ceil as _ceil, log as _log, log2 as _log2 + + +if GROUND_TYPES == 'flint': + from flint import fmpz_poly +else: + fmpz_poly = None + + +def dup_trial_division(f, factors, K): + """ + Determine multiplicities of factors for a univariate polynomial + using trial division. + + An error will be raised if any factor does not divide ``f``. + """ + result = [] + + for factor in factors: + k = 0 + + while True: + q, r = dup_div(f, factor, K) + + if not r: + f, k = q, k + 1 + else: + break + + if k == 0: + raise RuntimeError("trial division failed") + + result.append((factor, k)) + + return _sort_factors(result) + + +def dmp_trial_division(f, factors, u, K): + """ + Determine multiplicities of factors for a multivariate polynomial + using trial division. + + An error will be raised if any factor does not divide ``f``. + """ + result = [] + + for factor in factors: + k = 0 + + while True: + q, r = dmp_div(f, factor, u, K) + + if dmp_zero_p(r, u): + f, k = q, k + 1 + else: + break + + if k == 0: + raise RuntimeError("trial division failed") + + result.append((factor, k)) + + return _sort_factors(result) + + +def dup_zz_mignotte_bound(f, K): + """ + The Knuth-Cohen variant of Mignotte bound for + univariate polynomials in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> f = x**3 + 14*x**2 + 56*x + 64 + >>> R.dup_zz_mignotte_bound(f) + 152 + + By checking ``factor(f)`` we can see that max coeff is 8 + + Also consider a case that ``f`` is irreducible for example + ``f = 2*x**2 + 3*x + 4``. To avoid a bug for these cases, we return the + bound plus the max coefficient of ``f`` + + >>> f = 2*x**2 + 3*x + 4 + >>> R.dup_zz_mignotte_bound(f) + 6 + + Lastly, to see the difference between the new and the old Mignotte bound + consider the irreducible polynomial: + + >>> f = 87*x**7 + 4*x**6 + 80*x**5 + 17*x**4 + 9*x**3 + 12*x**2 + 49*x + 26 + >>> R.dup_zz_mignotte_bound(f) + 744 + + The new Mignotte bound is 744 whereas the old one (SymPy 1.5.1) is 1937664. + + + References + ========== + + ..[1] [Abbott13]_ + + """ + from sympy.functions.combinatorial.factorials import binomial + d = dup_degree(f) + delta = _ceil(d / 2) + delta2 = _ceil(delta / 2) + + # euclidean-norm + eucl_norm = K.sqrt( sum( cf**2 for cf in f ) ) + + # biggest values of binomial coefficients (p. 538 of reference) + t1 = binomial(delta - 1, delta2) + t2 = binomial(delta - 1, delta2 - 1) + + lc = K.abs(dup_LC(f, K)) # leading coefficient + bound = t1 * eucl_norm + t2 * lc # (p. 538 of reference) + bound += dup_max_norm(f, K) # add max coeff for irreducible polys + bound = _ceil(bound / 2) * 2 # round up to even integer + + return bound + +def dmp_zz_mignotte_bound(f, u, K): + """Mignotte bound for multivariate polynomials in `K[X]`. """ + a = dmp_max_norm(f, u, K) + b = abs(dmp_ground_LC(f, u, K)) + n = sum(dmp_degree_list(f, u)) + + return K.sqrt(K(n + 1))*2**n*a*b + + +def dup_zz_hensel_step(m, f, g, h, s, t, K): + """ + One step in Hensel lifting in `Z[x]`. + + Given positive integer `m` and `Z[x]` polynomials `f`, `g`, `h`, `s` + and `t` such that:: + + f = g*h (mod m) + s*g + t*h = 1 (mod m) + + lc(f) is not a zero divisor (mod m) + lc(h) = 1 + + deg(f) = deg(g) + deg(h) + deg(s) < deg(h) + deg(t) < deg(g) + + returns polynomials `G`, `H`, `S` and `T`, such that:: + + f = G*H (mod m**2) + S*G + T*H = 1 (mod m**2) + + References + ========== + + .. [1] [Gathen99]_ + + """ + M = m**2 + + e = dup_sub_mul(f, g, h, K) + e = dup_trunc(e, M, K) + + q, r = dup_div(dup_mul(s, e, K), h, K) + + q = dup_trunc(q, M, K) + r = dup_trunc(r, M, K) + + u = dup_add(dup_mul(t, e, K), dup_mul(q, g, K), K) + G = dup_trunc(dup_add(g, u, K), M, K) + H = dup_trunc(dup_add(h, r, K), M, K) + + u = dup_add(dup_mul(s, G, K), dup_mul(t, H, K), K) + b = dup_trunc(dup_sub(u, [K.one], K), M, K) + + c, d = dup_div(dup_mul(s, b, K), H, K) + + c = dup_trunc(c, M, K) + d = dup_trunc(d, M, K) + + u = dup_add(dup_mul(t, b, K), dup_mul(c, G, K), K) + S = dup_trunc(dup_sub(s, d, K), M, K) + T = dup_trunc(dup_sub(t, u, K), M, K) + + return G, H, S, T + + +def dup_zz_hensel_lift(p, f, f_list, l, K): + r""" + Multifactor Hensel lifting in `Z[x]`. + + Given a prime `p`, polynomial `f` over `Z[x]` such that `lc(f)` + is a unit modulo `p`, monic pair-wise coprime polynomials `f_i` + over `Z[x]` satisfying:: + + f = lc(f) f_1 ... f_r (mod p) + + and a positive integer `l`, returns a list of monic polynomials + `F_1,\ F_2,\ \dots,\ F_r` satisfying:: + + f = lc(f) F_1 ... F_r (mod p**l) + + F_i = f_i (mod p), i = 1..r + + References + ========== + + .. [1] [Gathen99]_ + + """ + r = len(f_list) + lc = dup_LC(f, K) + + if r == 1: + F = dup_mul_ground(f, K.gcdex(lc, p**l)[0], K) + return [ dup_trunc(F, p**l, K) ] + + m = p + k = r // 2 + d = int(_ceil(_log2(l))) + + g = gf_from_int_poly([lc], p) + + for f_i in f_list[:k]: + g = gf_mul(g, gf_from_int_poly(f_i, p), p, K) + + h = gf_from_int_poly(f_list[k], p) + + for f_i in f_list[k + 1:]: + h = gf_mul(h, gf_from_int_poly(f_i, p), p, K) + + s, t, _ = gf_gcdex(g, h, p, K) + + g = gf_to_int_poly(g, p) + h = gf_to_int_poly(h, p) + s = gf_to_int_poly(s, p) + t = gf_to_int_poly(t, p) + + for _ in range(1, d + 1): + (g, h, s, t), m = dup_zz_hensel_step(m, f, g, h, s, t, K), m**2 + + return dup_zz_hensel_lift(p, g, f_list[:k], l, K) \ + + dup_zz_hensel_lift(p, h, f_list[k:], l, K) + +def _test_pl(fc, q, pl): + if q > pl // 2: + q = q - pl + if not q: + return True + return fc % q == 0 + +def dup_zz_zassenhaus(f, K): + """Factor primitive square-free polynomials in `Z[x]`. """ + n = dup_degree(f) + + if n == 1: + return [f] + + from sympy.ntheory import isprime + + fc = f[-1] + A = dup_max_norm(f, K) + b = dup_LC(f, K) + B = int(abs(K.sqrt(K(n + 1))*2**n*A*b)) + C = int((n + 1)**(2*n)*A**(2*n - 1)) + gamma = int(_ceil(2*_log2(C))) + bound = int(2*gamma*_log(gamma)) + a = [] + # choose a prime number `p` such that `f` be square free in Z_p + # if there are many factors in Z_p, choose among a few different `p` + # the one with fewer factors + for px in range(3, bound + 1): + if not isprime(px) or b % px == 0: + continue + + px = K.convert(px) + + F = gf_from_int_poly(f, px) + + if not gf_sqf_p(F, px, K): + continue + fsqfx = gf_factor_sqf(F, px, K)[1] + a.append((px, fsqfx)) + if len(fsqfx) < 15 or len(a) > 4: + break + p, fsqf = min(a, key=lambda x: len(x[1])) + + l = int(_ceil(_log(2*B + 1, p))) + + modular = [gf_to_int_poly(ff, p) for ff in fsqf] + + g = dup_zz_hensel_lift(p, f, modular, l, K) + + sorted_T = range(len(g)) + T = set(sorted_T) + factors, s = [], 1 + pl = p**l + + while 2*s <= len(T): + for S in subsets(sorted_T, s): + # lift the constant coefficient of the product `G` of the factors + # in the subset `S`; if it is does not divide `fc`, `G` does + # not divide the input polynomial + + if b == 1: + q = 1 + for i in S: + q = q*g[i][-1] + q = q % pl + if not _test_pl(fc, q, pl): + continue + else: + G = [b] + for i in S: + G = dup_mul(G, g[i], K) + G = dup_trunc(G, pl, K) + G = dup_primitive(G, K)[1] + q = G[-1] + if q and fc % q != 0: + continue + + H = [b] + S = set(S) + T_S = T - S + + if b == 1: + G = [b] + for i in S: + G = dup_mul(G, g[i], K) + G = dup_trunc(G, pl, K) + + for i in T_S: + H = dup_mul(H, g[i], K) + + H = dup_trunc(H, pl, K) + + G_norm = dup_l1_norm(G, K) + H_norm = dup_l1_norm(H, K) + + if G_norm*H_norm <= B: + T = T_S + sorted_T = [i for i in sorted_T if i not in S] + + G = dup_primitive(G, K)[1] + f = dup_primitive(H, K)[1] + + factors.append(G) + b = dup_LC(f, K) + + break + else: + s += 1 + + return factors + [f] + + +def dup_zz_irreducible_p(f, K): + """Test irreducibility using Eisenstein's criterion. """ + lc = dup_LC(f, K) + tc = dup_TC(f, K) + + e_fc = dup_content(f[1:], K) + + if e_fc: + from sympy.ntheory import factorint + e_ff = factorint(int(e_fc)) + + for p in e_ff.keys(): + if (lc % p) and (tc % p**2): + return True + + +def dup_cyclotomic_p(f, K, irreducible=False): + """ + Efficiently test if ``f`` is a cyclotomic polynomial. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 + >>> R.dup_cyclotomic_p(f) + False + + >>> g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 + >>> R.dup_cyclotomic_p(g) + True + + References + ========== + + Bradford, Russell J., and James H. Davenport. "Effective tests for + cyclotomic polynomials." In International Symposium on Symbolic and + Algebraic Computation, pp. 244-251. Springer, Berlin, Heidelberg, 1988. + + """ + if K.is_QQ: + try: + K0, K = K, K.get_ring() + f = dup_convert(f, K0, K) + except CoercionFailed: + return False + elif not K.is_ZZ: + return False + + lc = dup_LC(f, K) + tc = dup_TC(f, K) + + if lc != 1 or (tc != -1 and tc != 1): + return False + + if not irreducible: + coeff, factors = dup_factor_list(f, K) + + if coeff != K.one or factors != [(f, 1)]: + return False + + n = dup_degree(f) + g, h = [], [] + + for i in range(n, -1, -2): + g.insert(0, f[i]) + + for i in range(n - 1, -1, -2): + h.insert(0, f[i]) + + g = dup_sqr(dup_strip(g), K) + h = dup_sqr(dup_strip(h), K) + + F = dup_sub(g, dup_lshift(h, 1, K), K) + + if K.is_negative(dup_LC(F, K)): + F = dup_neg(F, K) + + if F == f: + return True + + g = dup_mirror(f, K) + + if K.is_negative(dup_LC(g, K)): + g = dup_neg(g, K) + + if F == g and dup_cyclotomic_p(g, K): + return True + + G = dup_sqf_part(F, K) + + if dup_sqr(G, K) == F and dup_cyclotomic_p(G, K): + return True + + return False + + +def dup_zz_cyclotomic_poly(n, K): + """Efficiently generate n-th cyclotomic polynomial. """ + from sympy.ntheory import factorint + h = [K.one, -K.one] + + for p, k in factorint(n).items(): + h = dup_quo(dup_inflate(h, p, K), h, K) + h = dup_inflate(h, p**(k - 1), K) + + return h + + +def _dup_cyclotomic_decompose(n, K): + from sympy.ntheory import factorint + + H = [[K.one, -K.one]] + + for p, k in factorint(n).items(): + Q = [ dup_quo(dup_inflate(h, p, K), h, K) for h in H ] + H.extend(Q) + + for i in range(1, k): + Q = [ dup_inflate(q, p, K) for q in Q ] + H.extend(Q) + + return H + + +def dup_zz_cyclotomic_factor(f, K): + """ + Efficiently factor polynomials `x**n - 1` and `x**n + 1` in `Z[x]`. + + Given a univariate polynomial `f` in `Z[x]` returns a list of factors + of `f`, provided that `f` is in the form `x**n - 1` or `x**n + 1` for + `n >= 1`. Otherwise returns None. + + Factorization is performed using cyclotomic decomposition of `f`, + which makes this method much faster that any other direct factorization + approach (e.g. Zassenhaus's). + + References + ========== + + .. [1] [Weisstein09]_ + + """ + lc_f, tc_f = dup_LC(f, K), dup_TC(f, K) + + if dup_degree(f) <= 0: + return None + + if lc_f != 1 or tc_f not in [-1, 1]: + return None + + if any(bool(cf) for cf in f[1:-1]): + return None + + n = dup_degree(f) + F = _dup_cyclotomic_decompose(n, K) + + if not K.is_one(tc_f): + return F + else: + H = [] + + for h in _dup_cyclotomic_decompose(2*n, K): + if h not in F: + H.append(h) + + return H + + +def dup_zz_factor_sqf(f, K): + """Factor square-free (non-primitive) polynomials in `Z[x]`. """ + cont, g = dup_primitive(f, K) + + n = dup_degree(g) + + if dup_LC(g, K) < 0: + cont, g = -cont, dup_neg(g, K) + + if n <= 0: + return cont, [] + elif n == 1: + return cont, [g] + + if query('USE_IRREDUCIBLE_IN_FACTOR'): + if dup_zz_irreducible_p(g, K): + return cont, [g] + + factors = None + + if query('USE_CYCLOTOMIC_FACTOR'): + factors = dup_zz_cyclotomic_factor(g, K) + + if factors is None: + factors = dup_zz_zassenhaus(g, K) + + return cont, _sort_factors(factors, multiple=False) + + +def dup_zz_factor(f, K): + """ + Factor (non square-free) polynomials in `Z[x]`. + + Given a univariate polynomial `f` in `Z[x]` computes its complete + factorization `f_1, ..., f_n` into irreducibles over integers:: + + f = content(f) f_1**k_1 ... f_n**k_n + + The factorization is computed by reducing the input polynomial + into a primitive square-free polynomial and factoring it using + Zassenhaus algorithm. Trial division is used to recover the + multiplicities of factors. + + The result is returned as a tuple consisting of:: + + (content(f), [(f_1, k_1), ..., (f_n, k_n)) + + Examples + ======== + + Consider the polynomial `f = 2*x**4 - 2`:: + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_zz_factor(2*x**4 - 2) + (2, [(x - 1, 1), (x + 1, 1), (x**2 + 1, 1)]) + + In result we got the following factorization:: + + f = 2 (x - 1) (x + 1) (x**2 + 1) + + Note that this is a complete factorization over integers, + however over Gaussian integers we can factor the last term. + + By default, polynomials `x**n - 1` and `x**n + 1` are factored + using cyclotomic decomposition to speedup computations. To + disable this behaviour set cyclotomic=False. + + References + ========== + + .. [1] [Gathen99]_ + + """ + if GROUND_TYPES == 'flint': + f_flint = fmpz_poly(f[::-1]) + cont, factors = f_flint.factor() + factors = [(fac.coeffs()[::-1], exp) for fac, exp in factors] + return cont, _sort_factors(factors) + + cont, g = dup_primitive(f, K) + + n = dup_degree(g) + + if dup_LC(g, K) < 0: + cont, g = -cont, dup_neg(g, K) + + if n <= 0: + return cont, [] + elif n == 1: + return cont, [(g, 1)] + + if query('USE_IRREDUCIBLE_IN_FACTOR'): + if dup_zz_irreducible_p(g, K): + return cont, [(g, 1)] + + g = dup_sqf_part(g, K) + H = None + + if query('USE_CYCLOTOMIC_FACTOR'): + H = dup_zz_cyclotomic_factor(g, K) + + if H is None: + H = dup_zz_zassenhaus(g, K) + + factors = dup_trial_division(f, H, K) + + _dup_check_degrees(f, factors) + + return cont, factors + + +def dmp_zz_wang_non_divisors(E, cs, ct, K): + """Wang/EEZ: Compute a set of valid divisors. """ + result = [ cs*ct ] + + for q in E: + q = abs(q) + + for r in reversed(result): + while r != 1: + r = K.gcd(r, q) + q = q // r + + if K.is_one(q): + return None + + result.append(q) + + return result[1:] + + +def dmp_zz_wang_test_points(f, T, ct, A, u, K): + """Wang/EEZ: Test evaluation points for suitability. """ + if not dmp_eval_tail(dmp_LC(f, K), A, u - 1, K): + raise EvaluationFailed('no luck') + + g = dmp_eval_tail(f, A, u, K) + + if not dup_sqf_p(g, K): + raise EvaluationFailed('no luck') + + c, h = dup_primitive(g, K) + + if K.is_negative(dup_LC(h, K)): + c, h = -c, dup_neg(h, K) + + v = u - 1 + + E = [ dmp_eval_tail(t, A, v, K) for t, _ in T ] + D = dmp_zz_wang_non_divisors(E, c, ct, K) + + if D is not None: + return c, h, E + else: + raise EvaluationFailed('no luck') + + +def dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K): + """Wang/EEZ: Compute correct leading coefficients. """ + C, J, v = [], [0]*len(E), u - 1 + + for h in H: + c = dmp_one(v, K) + d = dup_LC(h, K)*cs + + for i in reversed(range(len(E))): + k, e, (t, _) = 0, E[i], T[i] + + while not (d % e): + d, k = d//e, k + 1 + + if k != 0: + c, J[i] = dmp_mul(c, dmp_pow(t, k, v, K), v, K), 1 + + C.append(c) + + if not all(J): + raise ExtraneousFactors # pragma: no cover + + CC, HH = [], [] + + for c, h in zip(C, H): + d = dmp_eval_tail(c, A, v, K) + lc = dup_LC(h, K) + + if K.is_one(cs): + cc = lc//d + else: + g = K.gcd(lc, d) + d, cc = d//g, lc//g + h, cs = dup_mul_ground(h, d, K), cs//d + + c = dmp_mul_ground(c, cc, v, K) + + CC.append(c) + HH.append(h) + + if K.is_one(cs): + return f, HH, CC + + CCC, HHH = [], [] + + for c, h in zip(CC, HH): + CCC.append(dmp_mul_ground(c, cs, v, K)) + HHH.append(dmp_mul_ground(h, cs, 0, K)) + + f = dmp_mul_ground(f, cs**(len(H) - 1), u, K) + + return f, HHH, CCC + + +def dup_zz_diophantine(F, m, p, K): + """Wang/EEZ: Solve univariate Diophantine equations. """ + if len(F) == 2: + a, b = F + + f = gf_from_int_poly(a, p) + g = gf_from_int_poly(b, p) + + s, t, G = gf_gcdex(g, f, p, K) + + s = gf_lshift(s, m, K) + t = gf_lshift(t, m, K) + + q, s = gf_div(s, f, p, K) + + t = gf_add_mul(t, q, g, p, K) + + s = gf_to_int_poly(s, p) + t = gf_to_int_poly(t, p) + + result = [s, t] + else: + G = [F[-1]] + + for f in reversed(F[1:-1]): + G.insert(0, dup_mul(f, G[0], K)) + + S, T = [], [[1]] + + for f, g in zip(F, G): + t, s = dmp_zz_diophantine([g, f], T[-1], [], 0, p, 1, K) + T.append(t) + S.append(s) + + result, S = [], S + [T[-1]] + + for s, f in zip(S, F): + s = gf_from_int_poly(s, p) + f = gf_from_int_poly(f, p) + + r = gf_rem(gf_lshift(s, m, K), f, p, K) + s = gf_to_int_poly(r, p) + + result.append(s) + + return result + + +def dmp_zz_diophantine(F, c, A, d, p, u, K): + """Wang/EEZ: Solve multivariate Diophantine equations. """ + if not A: + S = [ [] for _ in F ] + n = dup_degree(c) + + for i, coeff in enumerate(c): + if not coeff: + continue + + T = dup_zz_diophantine(F, n - i, p, K) + + for j, (s, t) in enumerate(zip(S, T)): + t = dup_mul_ground(t, coeff, K) + S[j] = dup_trunc(dup_add(s, t, K), p, K) + else: + n = len(A) + e = dmp_expand(F, u, K) + + a, A = A[-1], A[:-1] + B, G = [], [] + + for f in F: + B.append(dmp_quo(e, f, u, K)) + G.append(dmp_eval_in(f, a, n, u, K)) + + C = dmp_eval_in(c, a, n, u, K) + + v = u - 1 + + S = dmp_zz_diophantine(G, C, A, d, p, v, K) + S = [ dmp_raise(s, 1, v, K) for s in S ] + + for s, b in zip(S, B): + c = dmp_sub_mul(c, s, b, u, K) + + c = dmp_ground_trunc(c, p, u, K) + + m = dmp_nest([K.one, -a], n, K) + M = dmp_one(n, K) + + for k in range(0, d): + if dmp_zero_p(c, u): + break + + M = dmp_mul(M, m, u, K) + C = dmp_diff_eval_in(c, k + 1, a, n, u, K) + + if not dmp_zero_p(C, v): + C = dmp_quo_ground(C, K.factorial(K(k) + 1), v, K) + T = dmp_zz_diophantine(G, C, A, d, p, v, K) + + for i, t in enumerate(T): + T[i] = dmp_mul(dmp_raise(t, 1, v, K), M, u, K) + + for i, (s, t) in enumerate(zip(S, T)): + S[i] = dmp_add(s, t, u, K) + + for t, b in zip(T, B): + c = dmp_sub_mul(c, t, b, u, K) + + c = dmp_ground_trunc(c, p, u, K) + + S = [ dmp_ground_trunc(s, p, u, K) for s in S ] + + return S + + +def dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K): + """Wang/EEZ: Parallel Hensel lifting algorithm. """ + S, n, v = [f], len(A), u - 1 + + H = list(H) + + for i, a in enumerate(reversed(A[1:])): + s = dmp_eval_in(S[0], a, n - i, u - i, K) + S.insert(0, dmp_ground_trunc(s, p, v - i, K)) + + d = max(dmp_degree_list(f, u)[1:]) + + for j, s, a in zip(range(2, n + 2), S, A): + G, w = list(H), j - 1 + + I, J = A[:j - 2], A[j - 1:] + + for i, (h, lc) in enumerate(zip(H, LC)): + lc = dmp_ground_trunc(dmp_eval_tail(lc, J, v, K), p, w - 1, K) + H[i] = [lc] + dmp_raise(h[1:], 1, w - 1, K) + + m = dmp_nest([K.one, -a], w, K) + M = dmp_one(w, K) + + c = dmp_sub(s, dmp_expand(H, w, K), w, K) + + dj = dmp_degree_in(s, w, w) + + for k in range(0, dj): + if dmp_zero_p(c, w): + break + + M = dmp_mul(M, m, w, K) + C = dmp_diff_eval_in(c, k + 1, a, w, w, K) + + if not dmp_zero_p(C, w - 1): + C = dmp_quo_ground(C, K.factorial(K(k) + 1), w - 1, K) + T = dmp_zz_diophantine(G, C, I, d, p, w - 1, K) + + for i, (h, t) in enumerate(zip(H, T)): + h = dmp_add_mul(h, dmp_raise(t, 1, w - 1, K), M, w, K) + H[i] = dmp_ground_trunc(h, p, w, K) + + h = dmp_sub(s, dmp_expand(H, w, K), w, K) + c = dmp_ground_trunc(h, p, w, K) + + if dmp_expand(H, u, K) != f: + raise ExtraneousFactors # pragma: no cover + else: + return H + + +def dmp_zz_wang(f, u, K, mod=None, seed=None): + r""" + Factor primitive square-free polynomials in `Z[X]`. + + Given a multivariate polynomial `f` in `Z[x_1,...,x_n]`, which is + primitive and square-free in `x_1`, computes factorization of `f` into + irreducibles over integers. + + The procedure is based on Wang's Enhanced Extended Zassenhaus + algorithm. The algorithm works by viewing `f` as a univariate polynomial + in `Z[x_2,...,x_n][x_1]`, for which an evaluation mapping is computed:: + + x_2 -> a_2, ..., x_n -> a_n + + where `a_i`, for `i = 2, \dots, n`, are carefully chosen integers. The + mapping is used to transform `f` into a univariate polynomial in `Z[x_1]`, + which can be factored efficiently using Zassenhaus algorithm. The last + step is to lift univariate factors to obtain true multivariate + factors. For this purpose a parallel Hensel lifting procedure is used. + + The parameter ``seed`` is passed to _randint and can be used to seed randint + (when an integer) or (for testing purposes) can be a sequence of numbers. + + References + ========== + + .. [1] [Wang78]_ + .. [2] [Geddes92]_ + + """ + from sympy.ntheory import nextprime + + randint = _randint(seed) + + ct, T = dmp_zz_factor(dmp_LC(f, K), u - 1, K) + + b = dmp_zz_mignotte_bound(f, u, K) + p = K(nextprime(b)) + + if mod is None: + if u == 1: + mod = 2 + else: + mod = 1 + + history, configs, A, r = set(), [], [K.zero]*u, None + + try: + cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K) + + _, H = dup_zz_factor_sqf(s, K) + + r = len(H) + + if r == 1: + return [f] + + configs = [(s, cs, E, H, A)] + except EvaluationFailed: + pass + + eez_num_configs = query('EEZ_NUMBER_OF_CONFIGS') + eez_num_tries = query('EEZ_NUMBER_OF_TRIES') + eez_mod_step = query('EEZ_MODULUS_STEP') + + while len(configs) < eez_num_configs: + for _ in range(eez_num_tries): + A = [ K(randint(-mod, mod)) for _ in range(u) ] + + if tuple(A) not in history: + history.add(tuple(A)) + else: + continue + + try: + cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K) + except EvaluationFailed: + continue + + _, H = dup_zz_factor_sqf(s, K) + + rr = len(H) + + if r is not None: + if rr != r: # pragma: no cover + if rr < r: + configs, r = [], rr + else: + continue + else: + r = rr + + if r == 1: + return [f] + + configs.append((s, cs, E, H, A)) + + if len(configs) == eez_num_configs: + break + else: + mod += eez_mod_step + + s_norm, s_arg, i = None, 0, 0 + + for s, _, _, _, _ in configs: + _s_norm = dup_max_norm(s, K) + + if s_norm is not None: + if _s_norm < s_norm: + s_norm = _s_norm + s_arg = i + else: + s_norm = _s_norm + + i += 1 + + _, cs, E, H, A = configs[s_arg] + orig_f = f + + try: + f, H, LC = dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K) + factors = dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K) + except ExtraneousFactors: # pragma: no cover + if query('EEZ_RESTART_IF_NEEDED'): + return dmp_zz_wang(orig_f, u, K, mod + 1) + else: + raise ExtraneousFactors( + "we need to restart algorithm with better parameters") + + result = [] + + for f in factors: + _, f = dmp_ground_primitive(f, u, K) + + if K.is_negative(dmp_ground_LC(f, u, K)): + f = dmp_neg(f, u, K) + + result.append(f) + + return result + + +def dmp_zz_factor(f, u, K): + r""" + Factor (non square-free) polynomials in `Z[X]`. + + Given a multivariate polynomial `f` in `Z[x]` computes its complete + factorization `f_1, \dots, f_n` into irreducibles over integers:: + + f = content(f) f_1**k_1 ... f_n**k_n + + The factorization is computed by reducing the input polynomial + into a primitive square-free polynomial and factoring it using + Enhanced Extended Zassenhaus (EEZ) algorithm. Trial division + is used to recover the multiplicities of factors. + + The result is returned as a tuple consisting of:: + + (content(f), [(f_1, k_1), ..., (f_n, k_n)) + + Consider polynomial `f = 2*(x**2 - y**2)`:: + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_zz_factor(2*x**2 - 2*y**2) + (2, [(x - y, 1), (x + y, 1)]) + + In result we got the following factorization:: + + f = 2 (x - y) (x + y) + + References + ========== + + .. [1] [Gathen99]_ + + """ + if not u: + return dup_zz_factor(f, K) + + if dmp_zero_p(f, u): + return K.zero, [] + + cont, g = dmp_ground_primitive(f, u, K) + + if dmp_ground_LC(g, u, K) < 0: + cont, g = -cont, dmp_neg(g, u, K) + + if all(d <= 0 for d in dmp_degree_list(g, u)): + return cont, [] + + G, g = dmp_primitive(g, u, K) + + factors = [] + + if dmp_degree(g, u) > 0: + g = dmp_sqf_part(g, u, K) + H = dmp_zz_wang(g, u, K) + factors = dmp_trial_division(f, H, u, K) + + for g, k in dmp_zz_factor(G, u - 1, K)[1]: + factors.insert(0, ([g], k)) + + _dmp_check_degrees(f, u, factors) + + return cont, _sort_factors(factors) + + +def dup_qq_i_factor(f, K0): + """Factor univariate polynomials into irreducibles in `QQ_I[x]`. """ + # Factor in QQ + K1 = K0.as_AlgebraicField() + f = dup_convert(f, K0, K1) + coeff, factors = dup_factor_list(f, K1) + factors = [(dup_convert(fac, K1, K0), i) for fac, i in factors] + coeff = K0.convert(coeff, K1) + return coeff, factors + + +def dup_zz_i_factor(f, K0): + """Factor univariate polynomials into irreducibles in `ZZ_I[x]`. """ + # First factor in QQ_I + K1 = K0.get_field() + f = dup_convert(f, K0, K1) + coeff, factors = dup_qq_i_factor(f, K1) + + new_factors = [] + for fac, i in factors: + # Extract content + fac_denom, fac_num = dup_clear_denoms(fac, K1) + fac_num_ZZ_I = dup_convert(fac_num, K1, K0) + content, fac_prim = dmp_ground_primitive(fac_num_ZZ_I, 0, K0) + + coeff = (coeff * content ** i) // fac_denom ** i + new_factors.append((fac_prim, i)) + + factors = new_factors + coeff = K0.convert(coeff, K1) + return coeff, factors + + +def dmp_qq_i_factor(f, u, K0): + """Factor multivariate polynomials into irreducibles in `QQ_I[X]`. """ + # Factor in QQ + K1 = K0.as_AlgebraicField() + f = dmp_convert(f, u, K0, K1) + coeff, factors = dmp_factor_list(f, u, K1) + factors = [(dmp_convert(fac, u, K1, K0), i) for fac, i in factors] + coeff = K0.convert(coeff, K1) + return coeff, factors + + +def dmp_zz_i_factor(f, u, K0): + """Factor multivariate polynomials into irreducibles in `ZZ_I[X]`. """ + # First factor in QQ_I + K1 = K0.get_field() + f = dmp_convert(f, u, K0, K1) + coeff, factors = dmp_qq_i_factor(f, u, K1) + + new_factors = [] + for fac, i in factors: + # Extract content + fac_denom, fac_num = dmp_clear_denoms(fac, u, K1) + fac_num_ZZ_I = dmp_convert(fac_num, u, K1, K0) + content, fac_prim = dmp_ground_primitive(fac_num_ZZ_I, u, K0) + + coeff = (coeff * content ** i) // fac_denom ** i + new_factors.append((fac_prim, i)) + + factors = new_factors + coeff = K0.convert(coeff, K1) + return coeff, factors + + +def dup_ext_factor(f, K): + r"""Factor univariate polynomials over algebraic number fields. + + The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`). + + Examples + ======== + + First define the algebraic number field `K = \mathbb{Q}(\sqrt{2})`: + + >>> from sympy import QQ, sqrt + >>> from sympy.polys.factortools import dup_ext_factor + >>> K = QQ.algebraic_field(sqrt(2)) + + We can now factorise the polynomial `x^2 - 2` over `K`: + + >>> p = [K(1), K(0), K(-2)] # x^2 - 2 + >>> p1 = [K(1), -K.unit] # x - sqrt(2) + >>> p2 = [K(1), +K.unit] # x + sqrt(2) + >>> dup_ext_factor(p, K) == (K.one, [(p1, 1), (p2, 1)]) + True + + Usually this would be done at a higher level: + + >>> from sympy import factor + >>> from sympy.abc import x + >>> factor(x**2 - 2, extension=sqrt(2)) + (x - sqrt(2))*(x + sqrt(2)) + + Explanation + =========== + + Uses Trager's algorithm. In particular this function is algorithm + ``alg_factor`` from [Trager76]_. + + If `f` is a polynomial in `k(a)[x]` then its norm `g(x)` is a polynomial in + `k[x]`. If `g(x)` is square-free and has irreducible factors `g_1(x)`, + `g_2(x)`, `\cdots` then the irreducible factors of `f` in `k(a)[x]` are + given by `f_i(x) = \gcd(f(x), g_i(x))` where the GCD is computed in + `k(a)[x]`. + + The first step in Trager's algorithm is to find an integer shift `s` so + that `f(x-sa)` has square-free norm. Then the norm is factorized in `k[x]` + and the GCD of (shifted) `f` with each factor gives the shifted factors of + `f`. At the end the shift is undone to recover the unshifted factors of `f` + in `k(a)[x]`. + + The algorithm reduces the problem of factorization in `k(a)[x]` to + factorization in `k[x]` with the main additional steps being to compute the + norm (a resultant calculation in `k[x,y]`) and some polynomial GCDs in + `k(a)[x]`. + + In practice in SymPy the base field `k` will be the rationals :ref:`QQ` and + this function factorizes a polynomial with coefficients in an algebraic + number field like `\mathbb{Q}(\sqrt{2})`. + + See Also + ======== + + dmp_ext_factor: + Analogous function for multivariate polynomials over ``k(a)``. + dup_sqf_norm: + Subroutine ``sqfr_norm`` also from [Trager76]_. + sympy.polys.polytools.factor: + The high-level function that ultimately uses this function as needed. + """ + n, lc = dup_degree(f), dup_LC(f, K) + + f = dup_monic(f, K) + + if n <= 0: + return lc, [] + if n == 1: + return lc, [(f, 1)] + + f, F = dup_sqf_part(f, K), f + s, g, r = dup_sqf_norm(f, K) + + factors = dup_factor_list_include(r, K.dom) + + if len(factors) == 1: + return lc, [(f, n//dup_degree(f))] + + H = s*K.unit + + for i, (factor, _) in enumerate(factors): + h = dup_convert(factor, K.dom, K) + h, _, g = dup_inner_gcd(h, g, K) + h = dup_shift(h, H, K) + factors[i] = h + + factors = dup_trial_division(F, factors, K) + + _dup_check_degrees(F, factors) + + return lc, factors + + +def dmp_ext_factor(f, u, K): + r"""Factor multivariate polynomials over algebraic number fields. + + The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`). + + Examples + ======== + + First define the algebraic number field `K = \mathbb{Q}(\sqrt{2})`: + + >>> from sympy import QQ, sqrt + >>> from sympy.polys.factortools import dmp_ext_factor + >>> K = QQ.algebraic_field(sqrt(2)) + + We can now factorise the polynomial `x^2 y^2 - 2` over `K`: + + >>> p = [[K(1),K(0),K(0)], [], [K(-2)]] # x**2*y**2 - 2 + >>> p1 = [[K(1),K(0)], [-K.unit]] # x*y - sqrt(2) + >>> p2 = [[K(1),K(0)], [+K.unit]] # x*y + sqrt(2) + >>> dmp_ext_factor(p, 1, K) == (K.one, [(p1, 1), (p2, 1)]) + True + + Usually this would be done at a higher level: + + >>> from sympy import factor + >>> from sympy.abc import x, y + >>> factor(x**2*y**2 - 2, extension=sqrt(2)) + (x*y - sqrt(2))*(x*y + sqrt(2)) + + Explanation + =========== + + This is Trager's algorithm for multivariate polynomials. In particular this + function is algorithm ``alg_factor`` from [Trager76]_. + + See :func:`dup_ext_factor` for explanation. + + See Also + ======== + + dup_ext_factor: + Analogous function for univariate polynomials over ``k(a)``. + dmp_sqf_norm: + Multivariate version of subroutine ``sqfr_norm`` also from [Trager76]_. + sympy.polys.polytools.factor: + The high-level function that ultimately uses this function as needed. + """ + if not u: + return dup_ext_factor(f, K) + + lc = dmp_ground_LC(f, u, K) + f = dmp_ground_monic(f, u, K) + + if all(d <= 0 for d in dmp_degree_list(f, u)): + return lc, [] + + f, F = dmp_sqf_part(f, u, K), f + s, g, r = dmp_sqf_norm(f, u, K) + + factors = dmp_factor_list_include(r, u, K.dom) + + if len(factors) == 1: + factors = [f] + else: + for i, (factor, _) in enumerate(factors): + h = dmp_convert(factor, u, K.dom, K) + h, _, g = dmp_inner_gcd(h, g, u, K) + a = [si*K.unit for si in s] + h = dmp_shift(h, a, u, K) + factors[i] = h + + result = dmp_trial_division(F, factors, u, K) + + _dmp_check_degrees(F, u, result) + + return lc, result + + +def dup_gf_factor(f, K): + """Factor univariate polynomials over finite fields. """ + f = dup_convert(f, K, K.dom) + + coeff, factors = gf_factor(f, K.mod, K.dom) + + for i, (f, k) in enumerate(factors): + factors[i] = (dup_convert(f, K.dom, K), k) + + return K.convert(coeff, K.dom), factors + + +def dmp_gf_factor(f, u, K): + """Factor multivariate polynomials over finite fields. """ + raise NotImplementedError('multivariate polynomials over finite fields') + + +def dup_factor_list(f, K0): + """Factor univariate polynomials into irreducibles in `K[x]`. """ + j, f = dup_terms_gcd(f, K0) + cont, f = dup_primitive(f, K0) + + if K0.is_FiniteField: + coeff, factors = dup_gf_factor(f, K0) + elif K0.is_Algebraic: + coeff, factors = dup_ext_factor(f, K0) + elif K0.is_GaussianRing: + coeff, factors = dup_zz_i_factor(f, K0) + elif K0.is_GaussianField: + coeff, factors = dup_qq_i_factor(f, K0) + else: + if not K0.is_Exact: + K0_inexact, K0 = K0, K0.get_exact() + f = dup_convert(f, K0_inexact, K0) + else: + K0_inexact = None + + if K0.is_Field: + K = K0.get_ring() + + denom, f = dup_clear_denoms(f, K0, K) + f = dup_convert(f, K0, K) + else: + K = K0 + + if K.is_ZZ: + coeff, factors = dup_zz_factor(f, K) + elif K.is_Poly: + f, u = dmp_inject(f, 0, K) + + coeff, factors = dmp_factor_list(f, u, K.dom) + + for i, (f, k) in enumerate(factors): + factors[i] = (dmp_eject(f, u, K), k) + + coeff = K.convert(coeff, K.dom) + else: # pragma: no cover + raise DomainError('factorization not supported over %s' % K0) + + if K0.is_Field: + for i, (f, k) in enumerate(factors): + factors[i] = (dup_convert(f, K, K0), k) + + coeff = K0.convert(coeff, K) + coeff = K0.quo(coeff, denom) + + if K0_inexact: + for i, (f, k) in enumerate(factors): + max_norm = dup_max_norm(f, K0) + f = dup_quo_ground(f, max_norm, K0) + f = dup_convert(f, K0, K0_inexact) + factors[i] = (f, k) + coeff = K0.mul(coeff, K0.pow(max_norm, k)) + + coeff = K0_inexact.convert(coeff, K0) + K0 = K0_inexact + + if j: + factors.insert(0, ([K0.one, K0.zero], j)) + + return coeff*cont, _sort_factors(factors) + + +def dup_factor_list_include(f, K): + """Factor univariate polynomials into irreducibles in `K[x]`. """ + coeff, factors = dup_factor_list(f, K) + + if not factors: + return [(dup_strip([coeff]), 1)] + else: + g = dup_mul_ground(factors[0][0], coeff, K) + return [(g, factors[0][1])] + factors[1:] + + +def dmp_factor_list(f, u, K0): + """Factor multivariate polynomials into irreducibles in `K[X]`. """ + if not u: + return dup_factor_list(f, K0) + + J, f = dmp_terms_gcd(f, u, K0) + cont, f = dmp_ground_primitive(f, u, K0) + + if K0.is_FiniteField: # pragma: no cover + coeff, factors = dmp_gf_factor(f, u, K0) + elif K0.is_Algebraic: + coeff, factors = dmp_ext_factor(f, u, K0) + elif K0.is_GaussianRing: + coeff, factors = dmp_zz_i_factor(f, u, K0) + elif K0.is_GaussianField: + coeff, factors = dmp_qq_i_factor(f, u, K0) + else: + if not K0.is_Exact: + K0_inexact, K0 = K0, K0.get_exact() + f = dmp_convert(f, u, K0_inexact, K0) + else: + K0_inexact = None + + if K0.is_Field: + K = K0.get_ring() + + denom, f = dmp_clear_denoms(f, u, K0, K) + f = dmp_convert(f, u, K0, K) + else: + K = K0 + + if K.is_ZZ: + levels, f, v = dmp_exclude(f, u, K) + coeff, factors = dmp_zz_factor(f, v, K) + + for i, (f, k) in enumerate(factors): + factors[i] = (dmp_include(f, levels, v, K), k) + elif K.is_Poly: + f, v = dmp_inject(f, u, K) + + coeff, factors = dmp_factor_list(f, v, K.dom) + + for i, (f, k) in enumerate(factors): + factors[i] = (dmp_eject(f, v, K), k) + + coeff = K.convert(coeff, K.dom) + else: # pragma: no cover + raise DomainError('factorization not supported over %s' % K0) + + if K0.is_Field: + for i, (f, k) in enumerate(factors): + factors[i] = (dmp_convert(f, u, K, K0), k) + + coeff = K0.convert(coeff, K) + coeff = K0.quo(coeff, denom) + + if K0_inexact: + for i, (f, k) in enumerate(factors): + max_norm = dmp_max_norm(f, u, K0) + f = dmp_quo_ground(f, max_norm, u, K0) + f = dmp_convert(f, u, K0, K0_inexact) + factors[i] = (f, k) + coeff = K0.mul(coeff, K0.pow(max_norm, k)) + + coeff = K0_inexact.convert(coeff, K0) + K0 = K0_inexact + + for i, j in enumerate(reversed(J)): + if not j: + continue + + term = {(0,)*(u - i) + (1,) + (0,)*i: K0.one} + factors.insert(0, (dmp_from_dict(term, u, K0), j)) + + return coeff*cont, _sort_factors(factors) + + +def dmp_factor_list_include(f, u, K): + """Factor multivariate polynomials into irreducibles in `K[X]`. """ + if not u: + return dup_factor_list_include(f, K) + + coeff, factors = dmp_factor_list(f, u, K) + + if not factors: + return [(dmp_ground(coeff, u), 1)] + else: + g = dmp_mul_ground(factors[0][0], coeff, u, K) + return [(g, factors[0][1])] + factors[1:] + + +def dup_irreducible_p(f, K): + """ + Returns ``True`` if a univariate polynomial ``f`` has no factors + over its domain. + """ + return dmp_irreducible_p(f, 0, K) + + +def dmp_irreducible_p(f, u, K): + """ + Returns ``True`` if a multivariate polynomial ``f`` has no factors + over its domain. + """ + _, factors = dmp_factor_list(f, u, K) + + if not factors: + return True + elif len(factors) > 1: + return False + else: + _, k = factors[0] + return k == 1 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/fglmtools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/fglmtools.py new file mode 100644 index 0000000000000000000000000000000000000000..d68fe5bc2a40741e39b89163d393f7b57e6b1c49 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/fglmtools.py @@ -0,0 +1,153 @@ +"""Implementation of matrix FGLM Groebner basis conversion algorithm. """ + + +from sympy.polys.monomials import monomial_mul, monomial_div + +def matrix_fglm(F, ring, O_to): + """ + Converts the reduced Groebner basis ``F`` of a zero-dimensional + ideal w.r.t. ``O_from`` to a reduced Groebner basis + w.r.t. ``O_to``. + + References + ========== + + .. [1] J.C. Faugere, P. Gianni, D. Lazard, T. Mora (1994). Efficient + Computation of Zero-dimensional Groebner Bases by Change of + Ordering + """ + domain = ring.domain + ngens = ring.ngens + + ring_to = ring.clone(order=O_to) + + old_basis = _basis(F, ring) + M = _representing_matrices(old_basis, F, ring) + + # V contains the normalforms (wrt O_from) of S + S = [ring.zero_monom] + V = [[domain.one] + [domain.zero] * (len(old_basis) - 1)] + G = [] + + L = [(i, 0) for i in range(ngens)] # (i, j) corresponds to x_i * S[j] + L.sort(key=lambda k_l: O_to(_incr_k(S[k_l[1]], k_l[0])), reverse=True) + t = L.pop() + + P = _identity_matrix(len(old_basis), domain) + + while True: + s = len(S) + v = _matrix_mul(M[t[0]], V[t[1]]) + _lambda = _matrix_mul(P, v) + + if all(_lambda[i] == domain.zero for i in range(s, len(old_basis))): + # there is a linear combination of v by V + lt = ring.term_new(_incr_k(S[t[1]], t[0]), domain.one) + rest = ring.from_dict({S[i]: _lambda[i] for i in range(s)}) + + g = (lt - rest).set_ring(ring_to) + if g: + G.append(g) + else: + # v is linearly independent from V + P = _update(s, _lambda, P) + S.append(_incr_k(S[t[1]], t[0])) + V.append(v) + + L.extend([(i, s) for i in range(ngens)]) + L = list(set(L)) + L.sort(key=lambda k_l: O_to(_incr_k(S[k_l[1]], k_l[0])), reverse=True) + + L = [(k, l) for (k, l) in L if all(monomial_div(_incr_k(S[l], k), g.LM) is None for g in G)] + + if not L: + G = [ g.monic() for g in G ] + return sorted(G, key=lambda g: O_to(g.LM), reverse=True) + + t = L.pop() + + +def _incr_k(m, k): + return tuple(list(m[:k]) + [m[k] + 1] + list(m[k + 1:])) + + +def _identity_matrix(n, domain): + M = [[domain.zero]*n for _ in range(n)] + + for i in range(n): + M[i][i] = domain.one + + return M + + +def _matrix_mul(M, v): + return [sum(row[i] * v[i] for i in range(len(v))) for row in M] + + +def _update(s, _lambda, P): + """ + Update ``P`` such that for the updated `P'` `P' v = e_{s}`. + """ + k = min(j for j in range(s, len(_lambda)) if _lambda[j] != 0) + + for r in range(len(_lambda)): + if r != k: + P[r] = [P[r][j] - (P[k][j] * _lambda[r]) / _lambda[k] for j in range(len(P[r]))] + + P[k] = [P[k][j] / _lambda[k] for j in range(len(P[k]))] + P[k], P[s] = P[s], P[k] + + return P + + +def _representing_matrices(basis, G, ring): + r""" + Compute the matrices corresponding to the linear maps `m \mapsto + x_i m` for all variables `x_i`. + """ + domain = ring.domain + u = ring.ngens-1 + + def var(i): + return tuple([0] * i + [1] + [0] * (u - i)) + + def representing_matrix(m): + M = [[domain.zero] * len(basis) for _ in range(len(basis))] + + for i, v in enumerate(basis): + r = ring.term_new(monomial_mul(m, v), domain.one).rem(G) + + for monom, coeff in r.terms(): + j = basis.index(monom) + M[j][i] = coeff + + return M + + return [representing_matrix(var(i)) for i in range(u + 1)] + + +def _basis(G, ring): + r""" + Computes a list of monomials which are not divisible by the leading + monomials wrt to ``O`` of ``G``. These monomials are a basis of + `K[X_1, \ldots, X_n]/(G)`. + """ + order = ring.order + + leading_monomials = [g.LM for g in G] + candidates = [ring.zero_monom] + basis = [] + + while candidates: + t = candidates.pop() + basis.append(t) + + new_candidates = [_incr_k(t, k) for k in range(ring.ngens) + if all(monomial_div(_incr_k(t, k), lmg) is None + for lmg in leading_monomials)] + candidates.extend(new_candidates) + candidates.sort(key=order, reverse=True) + + basis = list(set(basis)) + + return sorted(basis, key=order) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/fields.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/fields.py new file mode 100644 index 0000000000000000000000000000000000000000..ee844df55690af0b140132249990b335d926b6d4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/fields.py @@ -0,0 +1,639 @@ +"""Sparse rational function fields. """ + +from __future__ import annotations +from functools import reduce + +from operator import add, mul, lt, le, gt, ge + +from sympy.core.expr import Expr +from sympy.core.mod import Mod +from sympy.core.numbers import Exp1 +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import CantSympify, sympify +from sympy.functions.elementary.exponential import ExpBase +from sympy.polys.domains.domain import Domain +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.domains.fractionfield import FractionField +from sympy.polys.domains.polynomialring import PolynomialRing +from sympy.polys.constructor import construct_domain +from sympy.polys.orderings import lex, MonomialOrder +from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.polyoptions import build_options +from sympy.polys.polyutils import _parallel_dict_from_expr +from sympy.polys.rings import PolyRing, PolyElement +from sympy.printing.defaults import DefaultPrinting +from sympy.utilities import public +from sympy.utilities.iterables import is_sequence +from sympy.utilities.magic import pollute + +@public +def field(symbols, domain, order=lex): + """Construct new rational function field returning (field, x1, ..., xn). """ + _field = FracField(symbols, domain, order) + return (_field,) + _field.gens + +@public +def xfield(symbols, domain, order=lex): + """Construct new rational function field returning (field, (x1, ..., xn)). """ + _field = FracField(symbols, domain, order) + return (_field, _field.gens) + +@public +def vfield(symbols, domain, order=lex): + """Construct new rational function field and inject generators into global namespace. """ + _field = FracField(symbols, domain, order) + pollute([ sym.name for sym in _field.symbols ], _field.gens) + return _field + +@public +def sfield(exprs, *symbols, **options): + """Construct a field deriving generators and domain + from options and input expressions. + + Parameters + ========== + + exprs : py:class:`~.Expr` or sequence of :py:class:`~.Expr` (sympifiable) + + symbols : sequence of :py:class:`~.Symbol`/:py:class:`~.Expr` + + options : keyword arguments understood by :py:class:`~.Options` + + Examples + ======== + + >>> from sympy import exp, log, symbols, sfield + + >>> x = symbols("x") + >>> K, f = sfield((x*log(x) + 4*x**2)*exp(1/x + log(x)/3)/x**2) + >>> K + Rational function field in x, exp(1/x), log(x), x**(1/3) over ZZ with lex order + >>> f + (4*x**2*(exp(1/x)) + x*(exp(1/x))*(log(x)))/((x**(1/3))**5) + """ + single = False + if not is_sequence(exprs): + exprs, single = [exprs], True + + exprs = list(map(sympify, exprs)) + opt = build_options(symbols, options) + numdens = [] + for expr in exprs: + numdens.extend(expr.as_numer_denom()) + reps, opt = _parallel_dict_from_expr(numdens, opt) + + if opt.domain is None: + # NOTE: this is inefficient because construct_domain() automatically + # performs conversion to the target domain. It shouldn't do this. + coeffs = sum([list(rep.values()) for rep in reps], []) + opt.domain, _ = construct_domain(coeffs, opt=opt) + + _field = FracField(opt.gens, opt.domain, opt.order) + fracs = [] + for i in range(0, len(reps), 2): + fracs.append(_field(tuple(reps[i:i+2]))) + + if single: + return (_field, fracs[0]) + else: + return (_field, fracs) + + +class FracField(DefaultPrinting): + """Multivariate distributed rational function field. """ + + ring: PolyRing + gens: tuple[FracElement, ...] + symbols: tuple[Expr, ...] + ngens: int + domain: Domain + order: MonomialOrder + + def __new__(cls, symbols, domain, order=lex): + ring = PolyRing(symbols, domain, order) + symbols = ring.symbols + ngens = ring.ngens + domain = ring.domain + order = ring.order + + _hash_tuple = (cls.__name__, symbols, ngens, domain, order) + + obj = object.__new__(cls) + obj._hash_tuple = _hash_tuple + obj._hash = hash(_hash_tuple) + obj.ring = ring + obj.symbols = symbols + obj.ngens = ngens + obj.domain = domain + obj.order = order + + obj.dtype = FracElement(obj, ring.zero).raw_new + + obj.zero = obj.dtype(ring.zero) + obj.one = obj.dtype(ring.one) + + obj.gens = obj._gens() + + for symbol, generator in zip(obj.symbols, obj.gens): + if isinstance(symbol, Symbol): + name = symbol.name + + if not hasattr(obj, name): + setattr(obj, name, generator) + + return obj + + def _gens(self): + """Return a list of polynomial generators. """ + return tuple([ self.dtype(gen) for gen in self.ring.gens ]) + + def __getnewargs__(self): + return (self.symbols, self.domain, self.order) + + def __hash__(self): + return self._hash + + def index(self, gen): + if self.is_element(gen): + return self.ring.index(gen.to_poly()) + else: + raise ValueError("expected a %s, got %s instead" % (self.dtype,gen)) + + def __eq__(self, other): + return isinstance(other, FracField) and \ + (self.symbols, self.ngens, self.domain, self.order) == \ + (other.symbols, other.ngens, other.domain, other.order) + + def __ne__(self, other): + return not self == other + + def is_element(self, element): + """True if ``element`` is an element of this field. False otherwise. """ + return isinstance(element, FracElement) and element.field == self + + def raw_new(self, numer, denom=None): + return self.dtype(numer, denom) + + def new(self, numer, denom=None): + if denom is None: denom = self.ring.one + numer, denom = numer.cancel(denom) + return self.raw_new(numer, denom) + + def domain_new(self, element): + return self.domain.convert(element) + + def ground_new(self, element): + try: + return self.new(self.ring.ground_new(element)) + except CoercionFailed: + domain = self.domain + + if not domain.is_Field and domain.has_assoc_Field: + ring = self.ring + ground_field = domain.get_field() + element = ground_field.convert(element) + numer = ring.ground_new(ground_field.numer(element)) + denom = ring.ground_new(ground_field.denom(element)) + return self.raw_new(numer, denom) + else: + raise + + def field_new(self, element): + if isinstance(element, FracElement): + if self == element.field: + return element + + if isinstance(self.domain, FractionField) and \ + self.domain.field == element.field: + return self.ground_new(element) + elif isinstance(self.domain, PolynomialRing) and \ + self.domain.ring.to_field() == element.field: + return self.ground_new(element) + else: + raise NotImplementedError("conversion") + elif isinstance(element, PolyElement): + denom, numer = element.clear_denoms() + + if isinstance(self.domain, PolynomialRing) and \ + numer.ring == self.domain.ring: + numer = self.ring.ground_new(numer) + elif isinstance(self.domain, FractionField) and \ + numer.ring == self.domain.field.to_ring(): + numer = self.ring.ground_new(numer) + else: + numer = numer.set_ring(self.ring) + + denom = self.ring.ground_new(denom) + return self.raw_new(numer, denom) + elif isinstance(element, tuple) and len(element) == 2: + numer, denom = list(map(self.ring.ring_new, element)) + return self.new(numer, denom) + elif isinstance(element, str): + raise NotImplementedError("parsing") + elif isinstance(element, Expr): + return self.from_expr(element) + else: + return self.ground_new(element) + + __call__ = field_new + + def _rebuild_expr(self, expr, mapping): + domain = self.domain + powers = tuple((gen, gen.as_base_exp()) for gen in mapping.keys() + if gen.is_Pow or isinstance(gen, ExpBase)) + + def _rebuild(expr): + generator = mapping.get(expr) + + if generator is not None: + return generator + elif expr.is_Add: + return reduce(add, list(map(_rebuild, expr.args))) + elif expr.is_Mul: + return reduce(mul, list(map(_rebuild, expr.args))) + elif expr.is_Pow or isinstance(expr, (ExpBase, Exp1)): + b, e = expr.as_base_exp() + # look for bg**eg whose integer power may be b**e + for gen, (bg, eg) in powers: + if bg == b and Mod(e, eg) == 0: + return mapping.get(gen)**int(e/eg) + if e.is_Integer and e is not S.One: + return _rebuild(b)**int(e) + elif mapping.get(1/expr) is not None: + return 1/mapping.get(1/expr) + + try: + return domain.convert(expr) + except CoercionFailed: + if not domain.is_Field and domain.has_assoc_Field: + return domain.get_field().convert(expr) + else: + raise + + return _rebuild(expr) + + def from_expr(self, expr): + mapping = dict(list(zip(self.symbols, self.gens))) + + try: + frac = self._rebuild_expr(sympify(expr), mapping) + except CoercionFailed: + raise ValueError("expected an expression convertible to a rational function in %s, got %s" % (self, expr)) + else: + return self.field_new(frac) + + def to_domain(self): + return FractionField(self) + + def to_ring(self): + return PolyRing(self.symbols, self.domain, self.order) + +class FracElement(DomainElement, DefaultPrinting, CantSympify): + """Element of multivariate distributed rational function field. """ + + def __init__(self, field, numer, denom=None): + if denom is None: + denom = field.ring.one + elif not denom: + raise ZeroDivisionError("zero denominator") + + self.field = field + self.numer = numer + self.denom = denom + + def raw_new(f, numer, denom=None): + return f.__class__(f.field, numer, denom) + + def new(f, numer, denom): + return f.raw_new(*numer.cancel(denom)) + + def to_poly(f): + if f.denom != 1: + raise ValueError("f.denom should be 1") + return f.numer + + def parent(self): + return self.field.to_domain() + + def __getnewargs__(self): + return (self.field, self.numer, self.denom) + + _hash = None + + def __hash__(self): + _hash = self._hash + if _hash is None: + self._hash = _hash = hash((self.field, self.numer, self.denom)) + return _hash + + def copy(self): + return self.raw_new(self.numer.copy(), self.denom.copy()) + + def set_field(self, new_field): + if self.field == new_field: + return self + else: + new_ring = new_field.ring + numer = self.numer.set_ring(new_ring) + denom = self.denom.set_ring(new_ring) + return new_field.new(numer, denom) + + def as_expr(self, *symbols): + return self.numer.as_expr(*symbols)/self.denom.as_expr(*symbols) + + def __eq__(f, g): + if isinstance(g, FracElement) and f.field == g.field: + return f.numer == g.numer and f.denom == g.denom + else: + return f.numer == g and f.denom == f.field.ring.one + + def __ne__(f, g): + return not f == g + + def __bool__(f): + return bool(f.numer) + + def sort_key(self): + return (self.denom.sort_key(), self.numer.sort_key()) + + def _cmp(f1, f2, op): + if f1.field.is_element(f2): + return op(f1.sort_key(), f2.sort_key()) + else: + return NotImplemented + + def __lt__(f1, f2): + return f1._cmp(f2, lt) + def __le__(f1, f2): + return f1._cmp(f2, le) + def __gt__(f1, f2): + return f1._cmp(f2, gt) + def __ge__(f1, f2): + return f1._cmp(f2, ge) + + def __pos__(f): + """Negate all coefficients in ``f``. """ + return f.raw_new(f.numer, f.denom) + + def __neg__(f): + """Negate all coefficients in ``f``. """ + return f.raw_new(-f.numer, f.denom) + + def _extract_ground(self, element): + domain = self.field.domain + + try: + element = domain.convert(element) + except CoercionFailed: + if not domain.is_Field and domain.has_assoc_Field: + ground_field = domain.get_field() + + try: + element = ground_field.convert(element) + except CoercionFailed: + pass + else: + return -1, ground_field.numer(element), ground_field.denom(element) + + return 0, None, None + else: + return 1, element, None + + def __add__(f, g): + """Add rational functions ``f`` and ``g``. """ + field = f.field + + if not g: + return f + elif not f: + return g + elif field.is_element(g): + if f.denom == g.denom: + return f.new(f.numer + g.numer, f.denom) + else: + return f.new(f.numer*g.denom + f.denom*g.numer, f.denom*g.denom) + elif field.ring.is_element(g): + return f.new(f.numer + f.denom*g, f.denom) + else: + if isinstance(g, FracElement): + if isinstance(field.domain, FractionField) and field.domain.field == g.field: + pass + elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: + return g.__radd__(f) + else: + return NotImplemented + elif isinstance(g, PolyElement): + if isinstance(field.domain, PolynomialRing) and field.domain.ring == g.ring: + pass + else: + return g.__radd__(f) + + return f.__radd__(g) + + def __radd__(f, c): + if f.field.ring.is_element(c): + return f.new(f.numer + f.denom*c, f.denom) + + op, g_numer, g_denom = f._extract_ground(c) + + if op == 1: + return f.new(f.numer + f.denom*g_numer, f.denom) + elif not op: + return NotImplemented + else: + return f.new(f.numer*g_denom + f.denom*g_numer, f.denom*g_denom) + + def __sub__(f, g): + """Subtract rational functions ``f`` and ``g``. """ + field = f.field + + if not g: + return f + elif not f: + return -g + elif field.is_element(g): + if f.denom == g.denom: + return f.new(f.numer - g.numer, f.denom) + else: + return f.new(f.numer*g.denom - f.denom*g.numer, f.denom*g.denom) + elif field.ring.is_element(g): + return f.new(f.numer - f.denom*g, f.denom) + else: + if isinstance(g, FracElement): + if isinstance(field.domain, FractionField) and field.domain.field == g.field: + pass + elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: + return g.__rsub__(f) + else: + return NotImplemented + elif isinstance(g, PolyElement): + if isinstance(field.domain, PolynomialRing) and field.domain.ring == g.ring: + pass + else: + return g.__rsub__(f) + + op, g_numer, g_denom = f._extract_ground(g) + + if op == 1: + return f.new(f.numer - f.denom*g_numer, f.denom) + elif not op: + return NotImplemented + else: + return f.new(f.numer*g_denom - f.denom*g_numer, f.denom*g_denom) + + def __rsub__(f, c): + if f.field.ring.is_element(c): + return f.new(-f.numer + f.denom*c, f.denom) + + op, g_numer, g_denom = f._extract_ground(c) + + if op == 1: + return f.new(-f.numer + f.denom*g_numer, f.denom) + elif not op: + return NotImplemented + else: + return f.new(-f.numer*g_denom + f.denom*g_numer, f.denom*g_denom) + + def __mul__(f, g): + """Multiply rational functions ``f`` and ``g``. """ + field = f.field + + if not f or not g: + return field.zero + elif field.is_element(g): + return f.new(f.numer*g.numer, f.denom*g.denom) + elif field.ring.is_element(g): + return f.new(f.numer*g, f.denom) + else: + if isinstance(g, FracElement): + if isinstance(field.domain, FractionField) and field.domain.field == g.field: + pass + elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: + return g.__rmul__(f) + else: + return NotImplemented + elif isinstance(g, PolyElement): + if isinstance(field.domain, PolynomialRing) and field.domain.ring == g.ring: + pass + else: + return g.__rmul__(f) + + return f.__rmul__(g) + + def __rmul__(f, c): + if f.field.ring.is_element(c): + return f.new(f.numer*c, f.denom) + + op, g_numer, g_denom = f._extract_ground(c) + + if op == 1: + return f.new(f.numer*g_numer, f.denom) + elif not op: + return NotImplemented + else: + return f.new(f.numer*g_numer, f.denom*g_denom) + + def __truediv__(f, g): + """Computes quotient of fractions ``f`` and ``g``. """ + field = f.field + + if not g: + raise ZeroDivisionError + elif field.is_element(g): + return f.new(f.numer*g.denom, f.denom*g.numer) + elif field.ring.is_element(g): + return f.new(f.numer, f.denom*g) + else: + if isinstance(g, FracElement): + if isinstance(field.domain, FractionField) and field.domain.field == g.field: + pass + elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: + return g.__rtruediv__(f) + else: + return NotImplemented + elif isinstance(g, PolyElement): + if isinstance(field.domain, PolynomialRing) and field.domain.ring == g.ring: + pass + else: + return g.__rtruediv__(f) + + op, g_numer, g_denom = f._extract_ground(g) + + if op == 1: + return f.new(f.numer, f.denom*g_numer) + elif not op: + return NotImplemented + else: + return f.new(f.numer*g_denom, f.denom*g_numer) + + def __rtruediv__(f, c): + if not f: + raise ZeroDivisionError + elif f.field.ring.is_element(c): + return f.new(f.denom*c, f.numer) + + op, g_numer, g_denom = f._extract_ground(c) + + if op == 1: + return f.new(f.denom*g_numer, f.numer) + elif not op: + return NotImplemented + else: + return f.new(f.denom*g_numer, f.numer*g_denom) + + def __pow__(f, n): + """Raise ``f`` to a non-negative power ``n``. """ + if n >= 0: + return f.raw_new(f.numer**n, f.denom**n) + elif not f: + raise ZeroDivisionError + else: + return f.raw_new(f.denom**-n, f.numer**-n) + + def diff(f, x): + """Computes partial derivative in ``x``. + + Examples + ======== + + >>> from sympy.polys.fields import field + >>> from sympy.polys.domains import ZZ + + >>> _, x, y, z = field("x,y,z", ZZ) + >>> ((x**2 + y)/(z + 1)).diff(x) + 2*x/(z + 1) + + """ + x = x.to_poly() + return f.new(f.numer.diff(x)*f.denom - f.numer*f.denom.diff(x), f.denom**2) + + def __call__(f, *values): + if 0 < len(values) <= f.field.ngens: + return f.evaluate(list(zip(f.field.gens, values))) + else: + raise ValueError("expected at least 1 and at most %s values, got %s" % (f.field.ngens, len(values))) + + def evaluate(f, x, a=None): + if isinstance(x, list) and a is None: + x = [ (X.to_poly(), a) for X, a in x ] + numer, denom = f.numer.evaluate(x), f.denom.evaluate(x) + else: + x = x.to_poly() + numer, denom = f.numer.evaluate(x, a), f.denom.evaluate(x, a) + + field = numer.ring.to_field() + return field.new(numer, denom) + + def subs(f, x, a=None): + if isinstance(x, list) and a is None: + x = [ (X.to_poly(), a) for X, a in x ] + numer, denom = f.numer.subs(x), f.denom.subs(x) + else: + x = x.to_poly() + numer, denom = f.numer.subs(x, a), f.denom.subs(x, a) + + return f.new(numer, denom) + + def compose(f, x, a=None): + raise NotImplementedError diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/galoistools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/galoistools.py new file mode 100644 index 0000000000000000000000000000000000000000..b09f85057eced59b8054c6007f2b291a35a2fafb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/galoistools.py @@ -0,0 +1,2532 @@ +"""Dense univariate polynomials with coefficients in Galois fields. """ + +from math import ceil as _ceil, sqrt as _sqrt, prod + +from sympy.core.random import uniform, _randint +from sympy.external.gmpy import SYMPY_INTS, MPZ, invert +from sympy.polys.polyconfig import query +from sympy.polys.polyerrors import ExactQuotientFailed +from sympy.polys.polyutils import _sort_factors + + +def gf_crt(U, M, K=None): + """ + Chinese Remainder Theorem. + + Given a set of integer residues ``u_0,...,u_n`` and a set of + co-prime integer moduli ``m_0,...,m_n``, returns an integer + ``u``, such that ``u = u_i mod m_i`` for ``i = ``0,...,n``. + + Examples + ======== + + Consider a set of residues ``U = [49, 76, 65]`` + and a set of moduli ``M = [99, 97, 95]``. Then we have:: + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_crt + + >>> gf_crt([49, 76, 65], [99, 97, 95], ZZ) + 639985 + + This is the correct result because:: + + >>> [639985 % m for m in [99, 97, 95]] + [49, 76, 65] + + Note: this is a low-level routine with no error checking. + + See Also + ======== + + sympy.ntheory.modular.crt : a higher level crt routine + sympy.ntheory.modular.solve_congruence + + """ + p = prod(M, start=K.one) + v = K.zero + + for u, m in zip(U, M): + e = p // m + s, _, _ = K.gcdex(e, m) + v += e*(u*s % m) + + return v % p + + +def gf_crt1(M, K): + """ + First part of the Chinese Remainder Theorem. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2 + >>> U = [49, 76, 65] + >>> M = [99, 97, 95] + + The following two codes have the same result. + + >>> gf_crt(U, M, ZZ) + 639985 + + >>> p, E, S = gf_crt1(M, ZZ) + >>> gf_crt2(U, M, p, E, S, ZZ) + 639985 + + However, it is faster when we want to fix ``M`` and + compute for multiple U, i.e. the following cases: + + >>> p, E, S = gf_crt1(M, ZZ) + >>> Us = [[49, 76, 65], [23, 42, 67]] + >>> for U in Us: + ... print(gf_crt2(U, M, p, E, S, ZZ)) + 639985 + 236237 + + See Also + ======== + + sympy.ntheory.modular.crt1 : a higher level crt routine + sympy.polys.galoistools.gf_crt + sympy.polys.galoistools.gf_crt2 + + """ + E, S = [], [] + p = prod(M, start=K.one) + + for m in M: + E.append(p // m) + S.append(K.gcdex(E[-1], m)[0] % m) + + return p, E, S + + +def gf_crt2(U, M, p, E, S, K): + """ + Second part of the Chinese Remainder Theorem. + + See ``gf_crt1`` for usage. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_crt2 + + >>> U = [49, 76, 65] + >>> M = [99, 97, 95] + >>> p = 912285 + >>> E = [9215, 9405, 9603] + >>> S = [62, 24, 12] + + >>> gf_crt2(U, M, p, E, S, ZZ) + 639985 + + See Also + ======== + + sympy.ntheory.modular.crt2 : a higher level crt routine + sympy.polys.galoistools.gf_crt + sympy.polys.galoistools.gf_crt1 + + """ + v = K.zero + + for u, m, e, s in zip(U, M, E, S): + v += e*(u*s % m) + + return v % p + + +def gf_int(a, p): + """ + Coerce ``a mod p`` to an integer in the range ``[-p/2, p/2]``. + + Examples + ======== + + >>> from sympy.polys.galoistools import gf_int + + >>> gf_int(2, 7) + 2 + >>> gf_int(5, 7) + -2 + + """ + if a <= p // 2: + return a + else: + return a - p + + +def gf_degree(f): + """ + Return the leading degree of ``f``. + + Examples + ======== + + >>> from sympy.polys.galoistools import gf_degree + + >>> gf_degree([1, 1, 2, 0]) + 3 + >>> gf_degree([]) + -1 + + """ + return len(f) - 1 + + +def gf_LC(f, K): + """ + Return the leading coefficient of ``f``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_LC + + >>> gf_LC([3, 0, 1], ZZ) + 3 + + """ + if not f: + return K.zero + else: + return f[0] + + +def gf_TC(f, K): + """ + Return the trailing coefficient of ``f``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_TC + + >>> gf_TC([3, 0, 1], ZZ) + 1 + + """ + if not f: + return K.zero + else: + return f[-1] + + +def gf_strip(f): + """ + Remove leading zeros from ``f``. + + + Examples + ======== + + >>> from sympy.polys.galoistools import gf_strip + + >>> gf_strip([0, 0, 0, 3, 0, 1]) + [3, 0, 1] + + """ + if not f or f[0]: + return f + + k = 0 + + for coeff in f: + if coeff: + break + else: + k += 1 + + return f[k:] + + +def gf_trunc(f, p): + """ + Reduce all coefficients modulo ``p``. + + Examples + ======== + + >>> from sympy.polys.galoistools import gf_trunc + + >>> gf_trunc([7, -2, 3], 5) + [2, 3, 3] + + """ + return gf_strip([ a % p for a in f ]) + + +def gf_normal(f, p, K): + """ + Normalize all coefficients in ``K``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_normal + + >>> gf_normal([5, 10, 21, -3], 5, ZZ) + [1, 2] + + """ + return gf_trunc(list(map(K, f)), p) + + +def gf_from_dict(f, p, K): + """ + Create a ``GF(p)[x]`` polynomial from a dict. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_from_dict + + >>> gf_from_dict({10: ZZ(4), 4: ZZ(33), 0: ZZ(-1)}, 5, ZZ) + [4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4] + + """ + n, h = max(f.keys()), [] + + if isinstance(n, SYMPY_INTS): + for k in range(n, -1, -1): + h.append(f.get(k, K.zero) % p) + else: + (n,) = n + + for k in range(n, -1, -1): + h.append(f.get((k,), K.zero) % p) + + return gf_trunc(h, p) + + +def gf_to_dict(f, p, symmetric=True): + """ + Convert a ``GF(p)[x]`` polynomial to a dict. + + Examples + ======== + + >>> from sympy.polys.galoistools import gf_to_dict + + >>> gf_to_dict([4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4], 5) + {0: -1, 4: -2, 10: -1} + >>> gf_to_dict([4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4], 5, symmetric=False) + {0: 4, 4: 3, 10: 4} + + """ + n, result = gf_degree(f), {} + + for k in range(0, n + 1): + if symmetric: + a = gf_int(f[n - k], p) + else: + a = f[n - k] + + if a: + result[k] = a + + return result + + +def gf_from_int_poly(f, p): + """ + Create a ``GF(p)[x]`` polynomial from ``Z[x]``. + + Examples + ======== + + >>> from sympy.polys.galoistools import gf_from_int_poly + + >>> gf_from_int_poly([7, -2, 3], 5) + [2, 3, 3] + + """ + return gf_trunc(f, p) + + +def gf_to_int_poly(f, p, symmetric=True): + """ + Convert a ``GF(p)[x]`` polynomial to ``Z[x]``. + + + Examples + ======== + + >>> from sympy.polys.galoistools import gf_to_int_poly + + >>> gf_to_int_poly([2, 3, 3], 5) + [2, -2, -2] + >>> gf_to_int_poly([2, 3, 3], 5, symmetric=False) + [2, 3, 3] + + """ + if symmetric: + return [ gf_int(c, p) for c in f ] + else: + return f + + +def gf_neg(f, p, K): + """ + Negate a polynomial in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_neg + + >>> gf_neg([3, 2, 1, 0], 5, ZZ) + [2, 3, 4, 0] + + """ + return [ -coeff % p for coeff in f ] + + +def gf_add_ground(f, a, p, K): + """ + Compute ``f + a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_add_ground + + >>> gf_add_ground([3, 2, 4], 2, 5, ZZ) + [3, 2, 1] + + """ + if not f: + a = a % p + else: + a = (f[-1] + a) % p + + if len(f) > 1: + return f[:-1] + [a] + + if not a: + return [] + else: + return [a] + + +def gf_sub_ground(f, a, p, K): + """ + Compute ``f - a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_sub_ground + + >>> gf_sub_ground([3, 2, 4], 2, 5, ZZ) + [3, 2, 2] + + """ + if not f: + a = -a % p + else: + a = (f[-1] - a) % p + + if len(f) > 1: + return f[:-1] + [a] + + if not a: + return [] + else: + return [a] + + +def gf_mul_ground(f, a, p, K): + """ + Compute ``f * a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_mul_ground + + >>> gf_mul_ground([3, 2, 4], 2, 5, ZZ) + [1, 4, 3] + + """ + if not a: + return [] + else: + return [ (a*b) % p for b in f ] + + +def gf_quo_ground(f, a, p, K): + """ + Compute ``f/a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_quo_ground + + >>> gf_quo_ground(ZZ.map([3, 2, 4]), ZZ(2), 5, ZZ) + [4, 1, 2] + + """ + return gf_mul_ground(f, K.invert(a, p), p, K) + + +def gf_add(f, g, p, K): + """ + Add polynomials in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_add + + >>> gf_add([3, 2, 4], [2, 2, 2], 5, ZZ) + [4, 1] + + """ + if not f: + return g + if not g: + return f + + df = gf_degree(f) + dg = gf_degree(g) + + if df == dg: + return gf_strip([ (a + b) % p for a, b in zip(f, g) ]) + else: + k = abs(df - dg) + + if df > dg: + h, f = f[:k], f[k:] + else: + h, g = g[:k], g[k:] + + return h + [ (a + b) % p for a, b in zip(f, g) ] + + +def gf_sub(f, g, p, K): + """ + Subtract polynomials in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_sub + + >>> gf_sub([3, 2, 4], [2, 2, 2], 5, ZZ) + [1, 0, 2] + + """ + if not g: + return f + if not f: + return gf_neg(g, p, K) + + df = gf_degree(f) + dg = gf_degree(g) + + if df == dg: + return gf_strip([ (a - b) % p for a, b in zip(f, g) ]) + else: + k = abs(df - dg) + + if df > dg: + h, f = f[:k], f[k:] + else: + h, g = gf_neg(g[:k], p, K), g[k:] + + return h + [ (a - b) % p for a, b in zip(f, g) ] + + +def gf_mul(f, g, p, K): + """ + Multiply polynomials in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_mul + + >>> gf_mul([3, 2, 4], [2, 2, 2], 5, ZZ) + [1, 0, 3, 2, 3] + + """ + df = gf_degree(f) + dg = gf_degree(g) + + dh = df + dg + h = [0]*(dh + 1) + + for i in range(0, dh + 1): + coeff = K.zero + + for j in range(max(0, i - dg), min(i, df) + 1): + coeff += f[j]*g[i - j] + + h[i] = coeff % p + + return gf_strip(h) + + +def gf_sqr(f, p, K): + """ + Square polynomials in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_sqr + + >>> gf_sqr([3, 2, 4], 5, ZZ) + [4, 2, 3, 1, 1] + + """ + df = gf_degree(f) + + dh = 2*df + h = [0]*(dh + 1) + + for i in range(0, dh + 1): + coeff = K.zero + + jmin = max(0, i - df) + jmax = min(i, df) + + n = jmax - jmin + 1 + + jmax = jmin + n // 2 - 1 + + for j in range(jmin, jmax + 1): + coeff += f[j]*f[i - j] + + coeff += coeff + + if n & 1: + elem = f[jmax + 1] + coeff += elem**2 + + h[i] = coeff % p + + return gf_strip(h) + + +def gf_add_mul(f, g, h, p, K): + """ + Returns ``f + g*h`` where ``f``, ``g``, ``h`` in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_add_mul + >>> gf_add_mul([3, 2, 4], [2, 2, 2], [1, 4], 5, ZZ) + [2, 3, 2, 2] + """ + return gf_add(f, gf_mul(g, h, p, K), p, K) + + +def gf_sub_mul(f, g, h, p, K): + """ + Compute ``f - g*h`` where ``f``, ``g``, ``h`` in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_sub_mul + + >>> gf_sub_mul([3, 2, 4], [2, 2, 2], [1, 4], 5, ZZ) + [3, 3, 2, 1] + + """ + return gf_sub(f, gf_mul(g, h, p, K), p, K) + + +def gf_expand(F, p, K): + """ + Expand results of :func:`~.factor` in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_expand + + >>> gf_expand([([3, 2, 4], 1), ([2, 2], 2), ([3, 1], 3)], 5, ZZ) + [4, 3, 0, 3, 0, 1, 4, 1] + + """ + if isinstance(F, tuple): + lc, F = F + else: + lc = K.one + + g = [lc] + + for f, k in F: + f = gf_pow(f, k, p, K) + g = gf_mul(g, f, p, K) + + return g + + +def gf_div(f, g, p, K): + """ + Division with remainder in ``GF(p)[x]``. + + Given univariate polynomials ``f`` and ``g`` with coefficients in a + finite field with ``p`` elements, returns polynomials ``q`` and ``r`` + (quotient and remainder) such that ``f = q*g + r``. + + Consider polynomials ``x**3 + x + 1`` and ``x**2 + x`` in GF(2):: + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_div, gf_add_mul + + >>> gf_div(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) + ([1, 1], [1]) + + As result we obtained quotient ``x + 1`` and remainder ``1``, thus:: + + >>> gf_add_mul(ZZ.map([1]), ZZ.map([1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) + [1, 0, 1, 1] + + References + ========== + + .. [1] [Monagan93]_ + .. [2] [Gathen99]_ + + """ + df = gf_degree(f) + dg = gf_degree(g) + + if not g: + raise ZeroDivisionError("polynomial division") + elif df < dg: + return [], f + + inv = K.invert(g[0], p) + + h, dq, dr = list(f), df - dg, dg - 1 + + for i in range(0, df + 1): + coeff = h[i] + + for j in range(max(0, dg - i), min(df - i, dr) + 1): + coeff -= h[i + j - dg] * g[dg - j] + + if i <= dq: + coeff *= inv + + h[i] = coeff % p + + return h[:dq + 1], gf_strip(h[dq + 1:]) + + +def gf_rem(f, g, p, K): + """ + Compute polynomial remainder in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_rem + + >>> gf_rem(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) + [1] + + """ + return gf_div(f, g, p, K)[1] + + +def gf_quo(f, g, p, K): + """ + Compute exact quotient in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_quo + + >>> gf_quo(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) + [1, 1] + >>> gf_quo(ZZ.map([1, 0, 3, 2, 3]), ZZ.map([2, 2, 2]), 5, ZZ) + [3, 2, 4] + + """ + df = gf_degree(f) + dg = gf_degree(g) + + if not g: + raise ZeroDivisionError("polynomial division") + elif df < dg: + return [] + + inv = K.invert(g[0], p) + + h, dq, dr = f[:], df - dg, dg - 1 + + for i in range(0, dq + 1): + coeff = h[i] + + for j in range(max(0, dg - i), min(df - i, dr) + 1): + coeff -= h[i + j - dg] * g[dg - j] + + h[i] = (coeff * inv) % p + + return h[:dq + 1] + + +def gf_exquo(f, g, p, K): + """ + Compute polynomial quotient in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_exquo + + >>> gf_exquo(ZZ.map([1, 0, 3, 2, 3]), ZZ.map([2, 2, 2]), 5, ZZ) + [3, 2, 4] + + >>> gf_exquo(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) + Traceback (most recent call last): + ... + ExactQuotientFailed: [1, 1, 0] does not divide [1, 0, 1, 1] + + """ + q, r = gf_div(f, g, p, K) + + if not r: + return q + else: + raise ExactQuotientFailed(f, g) + + +def gf_lshift(f, n, K): + """ + Efficiently multiply ``f`` by ``x**n``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_lshift + + >>> gf_lshift([3, 2, 4], 4, ZZ) + [3, 2, 4, 0, 0, 0, 0] + + """ + if not f: + return f + else: + return f + [K.zero]*n + + +def gf_rshift(f, n, K): + """ + Efficiently divide ``f`` by ``x**n``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_rshift + + >>> gf_rshift([1, 2, 3, 4, 0], 3, ZZ) + ([1, 2], [3, 4, 0]) + + """ + if not n: + return f, [] + else: + return f[:-n], f[-n:] + + +def gf_pow(f, n, p, K): + """ + Compute ``f**n`` in ``GF(p)[x]`` using repeated squaring. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_pow + + >>> gf_pow([3, 2, 4], 3, 5, ZZ) + [2, 4, 4, 2, 2, 1, 4] + + """ + if not n: + return [K.one] + elif n == 1: + return f + elif n == 2: + return gf_sqr(f, p, K) + + h = [K.one] + + while True: + if n & 1: + h = gf_mul(h, f, p, K) + n -= 1 + + n >>= 1 + + if not n: + break + + f = gf_sqr(f, p, K) + + return h + +def gf_frobenius_monomial_base(g, p, K): + """ + return the list of ``x**(i*p) mod g in Z_p`` for ``i = 0, .., n - 1`` + where ``n = gf_degree(g)`` + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_frobenius_monomial_base + >>> g = ZZ.map([1, 0, 2, 1]) + >>> gf_frobenius_monomial_base(g, 5, ZZ) + [[1], [4, 4, 2], [1, 2]] + + """ + n = gf_degree(g) + if n == 0: + return [] + b = [0]*n + b[0] = [1] + if p < n: + for i in range(1, n): + mon = gf_lshift(b[i - 1], p, K) + b[i] = gf_rem(mon, g, p, K) + elif n > 1: + b[1] = gf_pow_mod([K.one, K.zero], p, g, p, K) + for i in range(2, n): + b[i] = gf_mul(b[i - 1], b[1], p, K) + b[i] = gf_rem(b[i], g, p, K) + + return b + +def gf_frobenius_map(f, g, b, p, K): + """ + compute gf_pow_mod(f, p, g, p, K) using the Frobenius map + + Parameters + ========== + + f, g : polynomials in ``GF(p)[x]`` + b : frobenius monomial base + p : prime number + K : domain + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_frobenius_monomial_base, gf_frobenius_map + >>> f = ZZ.map([2, 1, 0, 1]) + >>> g = ZZ.map([1, 0, 2, 1]) + >>> p = 5 + >>> b = gf_frobenius_monomial_base(g, p, ZZ) + >>> r = gf_frobenius_map(f, g, b, p, ZZ) + >>> gf_frobenius_map(f, g, b, p, ZZ) + [4, 0, 3] + """ + m = gf_degree(g) + if gf_degree(f) >= m: + f = gf_rem(f, g, p, K) + if not f: + return [] + n = gf_degree(f) + sf = [f[-1]] + for i in range(1, n + 1): + v = gf_mul_ground(b[i], f[n - i], p, K) + sf = gf_add(sf, v, p, K) + return sf + +def _gf_pow_pnm1d2(f, n, g, b, p, K): + """ + utility function for ``gf_edf_zassenhaus`` + Compute ``f**((p**n - 1) // 2)`` in ``GF(p)[x]/(g)`` + ``f**((p**n - 1) // 2) = (f*f**p*...*f**(p**n - 1))**((p - 1) // 2)`` + """ + f = gf_rem(f, g, p, K) + h = f + r = f + for i in range(1, n): + h = gf_frobenius_map(h, g, b, p, K) + r = gf_mul(r, h, p, K) + r = gf_rem(r, g, p, K) + + res = gf_pow_mod(r, (p - 1)//2, g, p, K) + return res + +def gf_pow_mod(f, n, g, p, K): + """ + Compute ``f**n`` in ``GF(p)[x]/(g)`` using repeated squaring. + + Given polynomials ``f`` and ``g`` in ``GF(p)[x]`` and a non-negative + integer ``n``, efficiently computes ``f**n (mod g)`` i.e. the remainder + of ``f**n`` from division by ``g``, using the repeated squaring algorithm. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_pow_mod + + >>> gf_pow_mod(ZZ.map([3, 2, 4]), 3, ZZ.map([1, 1]), 5, ZZ) + [] + + References + ========== + + .. [1] [Gathen99]_ + + """ + if not n: + return [K.one] + elif n == 1: + return gf_rem(f, g, p, K) + elif n == 2: + return gf_rem(gf_sqr(f, p, K), g, p, K) + + h = [K.one] + + while True: + if n & 1: + h = gf_mul(h, f, p, K) + h = gf_rem(h, g, p, K) + n -= 1 + + n >>= 1 + + if not n: + break + + f = gf_sqr(f, p, K) + f = gf_rem(f, g, p, K) + + return h + + +def gf_gcd(f, g, p, K): + """ + Euclidean Algorithm in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_gcd + + >>> gf_gcd(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) + [1, 3] + + """ + while g: + f, g = g, gf_rem(f, g, p, K) + + return gf_monic(f, p, K)[1] + + +def gf_lcm(f, g, p, K): + """ + Compute polynomial LCM in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_lcm + + >>> gf_lcm(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) + [1, 2, 0, 4] + + """ + if not f or not g: + return [] + + h = gf_quo(gf_mul(f, g, p, K), + gf_gcd(f, g, p, K), p, K) + + return gf_monic(h, p, K)[1] + + +def gf_cofactors(f, g, p, K): + """ + Compute polynomial GCD and cofactors in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_cofactors + + >>> gf_cofactors(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) + ([1, 3], [3, 3], [2, 1]) + + """ + if not f and not g: + return ([], [], []) + + h = gf_gcd(f, g, p, K) + + return (h, gf_quo(f, h, p, K), + gf_quo(g, h, p, K)) + + +def gf_gcdex(f, g, p, K): + """ + Extended Euclidean Algorithm in ``GF(p)[x]``. + + Given polynomials ``f`` and ``g`` in ``GF(p)[x]``, computes polynomials + ``s``, ``t`` and ``h``, such that ``h = gcd(f, g)`` and ``s*f + t*g = h``. + The typical application of EEA is solving polynomial diophantine equations. + + Consider polynomials ``f = (x + 7) (x + 1)``, ``g = (x + 7) (x**2 + 1)`` + in ``GF(11)[x]``. Application of Extended Euclidean Algorithm gives:: + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_gcdex, gf_mul, gf_add + + >>> s, t, g = gf_gcdex(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) + >>> s, t, g + ([5, 6], [6], [1, 7]) + + As result we obtained polynomials ``s = 5*x + 6`` and ``t = 6``, and + additionally ``gcd(f, g) = x + 7``. This is correct because:: + + >>> S = gf_mul(s, ZZ.map([1, 8, 7]), 11, ZZ) + >>> T = gf_mul(t, ZZ.map([1, 7, 1, 7]), 11, ZZ) + + >>> gf_add(S, T, 11, ZZ) == [1, 7] + True + + References + ========== + + .. [1] [Gathen99]_ + + """ + if not (f or g): + return [K.one], [], [] + + p0, r0 = gf_monic(f, p, K) + p1, r1 = gf_monic(g, p, K) + + if not f: + return [], [K.invert(p1, p)], r1 + if not g: + return [K.invert(p0, p)], [], r0 + + s0, s1 = [K.invert(p0, p)], [] + t0, t1 = [], [K.invert(p1, p)] + + while True: + Q, R = gf_div(r0, r1, p, K) + + if not R: + break + + (lc, r1), r0 = gf_monic(R, p, K), r1 + + inv = K.invert(lc, p) + + s = gf_sub_mul(s0, s1, Q, p, K) + t = gf_sub_mul(t0, t1, Q, p, K) + + s1, s0 = gf_mul_ground(s, inv, p, K), s1 + t1, t0 = gf_mul_ground(t, inv, p, K), t1 + + return s1, t1, r1 + + +def gf_monic(f, p, K): + """ + Compute LC and a monic polynomial in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_monic + + >>> gf_monic(ZZ.map([3, 2, 4]), 5, ZZ) + (3, [1, 4, 3]) + + """ + if not f: + return K.zero, [] + else: + lc = f[0] + + if K.is_one(lc): + return lc, list(f) + else: + return lc, gf_quo_ground(f, lc, p, K) + + +def gf_diff(f, p, K): + """ + Differentiate polynomial in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_diff + + >>> gf_diff([3, 2, 4], 5, ZZ) + [1, 2] + + """ + df = gf_degree(f) + + h, n = [K.zero]*df, df + + for coeff in f[:-1]: + coeff *= K(n) + coeff %= p + + if coeff: + h[df - n] = coeff + + n -= 1 + + return gf_strip(h) + + +def gf_eval(f, a, p, K): + """ + Evaluate ``f(a)`` in ``GF(p)`` using Horner scheme. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_eval + + >>> gf_eval([3, 2, 4], 2, 5, ZZ) + 0 + + """ + result = K.zero + + for c in f: + result *= a + result += c + result %= p + + return result + + +def gf_multi_eval(f, A, p, K): + """ + Evaluate ``f(a)`` for ``a`` in ``[a_1, ..., a_n]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_multi_eval + + >>> gf_multi_eval([3, 2, 4], [0, 1, 2, 3, 4], 5, ZZ) + [4, 4, 0, 2, 0] + + """ + return [ gf_eval(f, a, p, K) for a in A ] + + +def gf_compose(f, g, p, K): + """ + Compute polynomial composition ``f(g)`` in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_compose + + >>> gf_compose([3, 2, 4], [2, 2, 2], 5, ZZ) + [2, 4, 0, 3, 0] + + """ + if len(g) <= 1: + return gf_strip([gf_eval(f, gf_LC(g, K), p, K)]) + + if not f: + return [] + + h = [f[0]] + + for c in f[1:]: + h = gf_mul(h, g, p, K) + h = gf_add_ground(h, c, p, K) + + return h + + +def gf_compose_mod(g, h, f, p, K): + """ + Compute polynomial composition ``g(h)`` in ``GF(p)[x]/(f)``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_compose_mod + + >>> gf_compose_mod(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 2]), ZZ.map([4, 3]), 5, ZZ) + [4] + + """ + if not g: + return [] + + comp = [g[0]] + + for a in g[1:]: + comp = gf_mul(comp, h, p, K) + comp = gf_add_ground(comp, a, p, K) + comp = gf_rem(comp, f, p, K) + + return comp + + +def gf_trace_map(a, b, c, n, f, p, K): + """ + Compute polynomial trace map in ``GF(p)[x]/(f)``. + + Given a polynomial ``f`` in ``GF(p)[x]``, polynomials ``a``, ``b``, + ``c`` in the quotient ring ``GF(p)[x]/(f)`` such that ``b = c**t + (mod f)`` for some positive power ``t`` of ``p``, and a positive + integer ``n``, returns a mapping:: + + a -> a**t**n, a + a**t + a**t**2 + ... + a**t**n (mod f) + + In factorization context, ``b = x**p mod f`` and ``c = x mod f``. + This way we can efficiently compute trace polynomials in equal + degree factorization routine, much faster than with other methods, + like iterated Frobenius algorithm, for large degrees. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_trace_map + + >>> gf_trace_map([1, 2], [4, 4], [1, 1], 4, [3, 2, 4], 5, ZZ) + ([1, 3], [1, 3]) + + References + ========== + + .. [1] [Gathen92]_ + + """ + u = gf_compose_mod(a, b, f, p, K) + v = b + + if n & 1: + U = gf_add(a, u, p, K) + V = b + else: + U = a + V = c + + n >>= 1 + + while n: + u = gf_add(u, gf_compose_mod(u, v, f, p, K), p, K) + v = gf_compose_mod(v, v, f, p, K) + + if n & 1: + U = gf_add(U, gf_compose_mod(u, V, f, p, K), p, K) + V = gf_compose_mod(v, V, f, p, K) + + n >>= 1 + + return gf_compose_mod(a, V, f, p, K), U + +def _gf_trace_map(f, n, g, b, p, K): + """ + utility for ``gf_edf_shoup`` + """ + f = gf_rem(f, g, p, K) + h = f + r = f + for i in range(1, n): + h = gf_frobenius_map(h, g, b, p, K) + r = gf_add(r, h, p, K) + r = gf_rem(r, g, p, K) + return r + + +def gf_random(n, p, K): + """ + Generate a random polynomial in ``GF(p)[x]`` of degree ``n``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_random + >>> gf_random(10, 5, ZZ) #doctest: +SKIP + [1, 2, 3, 2, 1, 1, 1, 2, 0, 4, 2] + + """ + pi = int(p) + return [K.one] + [ K(int(uniform(0, pi))) for i in range(0, n) ] + + +def gf_irreducible(n, p, K): + """ + Generate random irreducible polynomial of degree ``n`` in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_irreducible + >>> gf_irreducible(10, 5, ZZ) #doctest: +SKIP + [1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4] + + """ + while True: + f = gf_random(n, p, K) + if gf_irreducible_p(f, p, K): + return f + + +def gf_irred_p_ben_or(f, p, K): + """ + Ben-Or's polynomial irreducibility test over finite fields. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_irred_p_ben_or + + >>> gf_irred_p_ben_or(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) + True + >>> gf_irred_p_ben_or(ZZ.map([3, 2, 4]), 5, ZZ) + False + + """ + n = gf_degree(f) + + if n <= 1: + return True + + _, f = gf_monic(f, p, K) + if n < 5: + H = h = gf_pow_mod([K.one, K.zero], p, f, p, K) + + for i in range(0, n//2): + g = gf_sub(h, [K.one, K.zero], p, K) + + if gf_gcd(f, g, p, K) == [K.one]: + h = gf_compose_mod(h, H, f, p, K) + else: + return False + else: + b = gf_frobenius_monomial_base(f, p, K) + H = h = gf_frobenius_map([K.one, K.zero], f, b, p, K) + for i in range(0, n//2): + g = gf_sub(h, [K.one, K.zero], p, K) + if gf_gcd(f, g, p, K) == [K.one]: + h = gf_frobenius_map(h, f, b, p, K) + else: + return False + + return True + + +def gf_irred_p_rabin(f, p, K): + """ + Rabin's polynomial irreducibility test over finite fields. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_irred_p_rabin + + >>> gf_irred_p_rabin(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) + True + >>> gf_irred_p_rabin(ZZ.map([3, 2, 4]), 5, ZZ) + False + + """ + n = gf_degree(f) + + if n <= 1: + return True + + _, f = gf_monic(f, p, K) + + x = [K.one, K.zero] + + from sympy.ntheory import factorint + + indices = { n//d for d in factorint(n) } + + b = gf_frobenius_monomial_base(f, p, K) + h = b[1] + + for i in range(1, n): + if i in indices: + g = gf_sub(h, x, p, K) + + if gf_gcd(f, g, p, K) != [K.one]: + return False + + h = gf_frobenius_map(h, f, b, p, K) + + return h == x + +_irred_methods = { + 'ben-or': gf_irred_p_ben_or, + 'rabin': gf_irred_p_rabin, +} + + +def gf_irreducible_p(f, p, K): + """ + Test irreducibility of a polynomial ``f`` in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_irreducible_p + + >>> gf_irreducible_p(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) + True + >>> gf_irreducible_p(ZZ.map([3, 2, 4]), 5, ZZ) + False + + """ + method = query('GF_IRRED_METHOD') + + if method is not None: + irred = _irred_methods[method](f, p, K) + else: + irred = gf_irred_p_rabin(f, p, K) + + return irred + + +def gf_sqf_p(f, p, K): + """ + Return ``True`` if ``f`` is square-free in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_sqf_p + + >>> gf_sqf_p(ZZ.map([3, 2, 4]), 5, ZZ) + True + >>> gf_sqf_p(ZZ.map([2, 4, 4, 2, 2, 1, 4]), 5, ZZ) + False + + """ + _, f = gf_monic(f, p, K) + + if not f: + return True + else: + return gf_gcd(f, gf_diff(f, p, K), p, K) == [K.one] + + +def gf_sqf_part(f, p, K): + """ + Return square-free part of a ``GF(p)[x]`` polynomial. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_sqf_part + + >>> gf_sqf_part(ZZ.map([1, 1, 3, 0, 1, 0, 2, 2, 1]), 5, ZZ) + [1, 4, 3] + + """ + _, sqf = gf_sqf_list(f, p, K) + + g = [K.one] + + for f, _ in sqf: + g = gf_mul(g, f, p, K) + + return g + + +def gf_sqf_list(f, p, K, all=False): + """ + Return the square-free decomposition of a ``GF(p)[x]`` polynomial. + + Given a polynomial ``f`` in ``GF(p)[x]``, returns the leading coefficient + of ``f`` and a square-free decomposition ``f_1**e_1 f_2**e_2 ... f_k**e_k`` + such that all ``f_i`` are monic polynomials and ``(f_i, f_j)`` for ``i != j`` + are co-prime and ``e_1 ... e_k`` are given in increasing order. All trivial + terms (i.e. ``f_i = 1``) are not included in the output. + + Consider polynomial ``f = x**11 + 1`` over ``GF(11)[x]``:: + + >>> from sympy.polys.domains import ZZ + + >>> from sympy.polys.galoistools import ( + ... gf_from_dict, gf_diff, gf_sqf_list, gf_pow, + ... ) + ... # doctest: +NORMALIZE_WHITESPACE + + >>> f = gf_from_dict({11: ZZ(1), 0: ZZ(1)}, 11, ZZ) + + Note that ``f'(x) = 0``:: + + >>> gf_diff(f, 11, ZZ) + [] + + This phenomenon does not happen in characteristic zero. However we can + still compute square-free decomposition of ``f`` using ``gf_sqf()``:: + + >>> gf_sqf_list(f, 11, ZZ) + (1, [([1, 1], 11)]) + + We obtained factorization ``f = (x + 1)**11``. This is correct because:: + + >>> gf_pow([1, 1], 11, 11, ZZ) == f + True + + References + ========== + + .. [1] [Geddes92]_ + + """ + n, sqf, factors, r = 1, False, [], int(p) + + lc, f = gf_monic(f, p, K) + + if gf_degree(f) < 1: + return lc, [] + + while True: + F = gf_diff(f, p, K) + + if F != []: + g = gf_gcd(f, F, p, K) + h = gf_quo(f, g, p, K) + + i = 1 + + while h != [K.one]: + G = gf_gcd(g, h, p, K) + H = gf_quo(h, G, p, K) + + if gf_degree(H) > 0: + factors.append((H, i*n)) + + g, h, i = gf_quo(g, G, p, K), G, i + 1 + + if g == [K.one]: + sqf = True + else: + f = g + + if not sqf: + d = gf_degree(f) // r + + for i in range(0, d + 1): + f[i] = f[i*r] + + f, n = f[:d + 1], n*r + else: + break + + if all: + raise ValueError("'all=True' is not supported yet") + + return lc, factors + + +def gf_Qmatrix(f, p, K): + """ + Calculate Berlekamp's ``Q`` matrix. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_Qmatrix + + >>> gf_Qmatrix([3, 2, 4], 5, ZZ) + [[1, 0], + [3, 4]] + + >>> gf_Qmatrix([1, 0, 0, 0, 1], 5, ZZ) + [[1, 0, 0, 0], + [0, 4, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 4]] + + """ + n, r = gf_degree(f), int(p) + + q = [K.one] + [K.zero]*(n - 1) + Q = [list(q)] + [[]]*(n - 1) + + for i in range(1, (n - 1)*r + 1): + qq, c = [(-q[-1]*f[-1]) % p], q[-1] + + for j in range(1, n): + qq.append((q[j - 1] - c*f[-j - 1]) % p) + + if not (i % r): + Q[i//r] = list(qq) + + q = qq + + return Q + + +def gf_Qbasis(Q, p, K): + """ + Compute a basis of the kernel of ``Q``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_Qmatrix, gf_Qbasis + + >>> gf_Qbasis(gf_Qmatrix([1, 0, 0, 0, 1], 5, ZZ), 5, ZZ) + [[1, 0, 0, 0], [0, 0, 1, 0]] + + >>> gf_Qbasis(gf_Qmatrix([3, 2, 4], 5, ZZ), 5, ZZ) + [[1, 0]] + + """ + Q, n = [ list(q) for q in Q ], len(Q) + + for k in range(0, n): + Q[k][k] = (Q[k][k] - K.one) % p + + for k in range(0, n): + for i in range(k, n): + if Q[k][i]: + break + else: + continue + + inv = K.invert(Q[k][i], p) + + for j in range(0, n): + Q[j][i] = (Q[j][i]*inv) % p + + for j in range(0, n): + t = Q[j][k] + Q[j][k] = Q[j][i] + Q[j][i] = t + + for i in range(0, n): + if i != k: + q = Q[k][i] + + for j in range(0, n): + Q[j][i] = (Q[j][i] - Q[j][k]*q) % p + + for i in range(0, n): + for j in range(0, n): + if i == j: + Q[i][j] = (K.one - Q[i][j]) % p + else: + Q[i][j] = (-Q[i][j]) % p + + basis = [] + + for q in Q: + if any(q): + basis.append(q) + + return basis + + +def gf_berlekamp(f, p, K): + """ + Factor a square-free ``f`` in ``GF(p)[x]`` for small ``p``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_berlekamp + + >>> gf_berlekamp([1, 0, 0, 0, 1], 5, ZZ) + [[1, 0, 2], [1, 0, 3]] + + """ + Q = gf_Qmatrix(f, p, K) + V = gf_Qbasis(Q, p, K) + + for i, v in enumerate(V): + V[i] = gf_strip(list(reversed(v))) + + factors = [f] + + for k in range(1, len(V)): + for f in list(factors): + s = K.zero + + while s < p: + g = gf_sub_ground(V[k], s, p, K) + h = gf_gcd(f, g, p, K) + + if h != [K.one] and h != f: + factors.remove(f) + + f = gf_quo(f, h, p, K) + factors.extend([f, h]) + + if len(factors) == len(V): + return _sort_factors(factors, multiple=False) + + s += K.one + + return _sort_factors(factors, multiple=False) + + +def gf_ddf_zassenhaus(f, p, K): + """ + Cantor-Zassenhaus: Deterministic Distinct Degree Factorization + + Given a monic square-free polynomial ``f`` in ``GF(p)[x]``, computes + partial distinct degree factorization ``f_1 ... f_d`` of ``f`` where + ``deg(f_i) != deg(f_j)`` for ``i != j``. The result is returned as a + list of pairs ``(f_i, e_i)`` where ``deg(f_i) > 0`` and ``e_i > 0`` + is an argument to the equal degree factorization routine. + + Consider the polynomial ``x**15 - 1`` in ``GF(11)[x]``:: + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_from_dict + + >>> f = gf_from_dict({15: ZZ(1), 0: ZZ(-1)}, 11, ZZ) + + Distinct degree factorization gives:: + + >>> from sympy.polys.galoistools import gf_ddf_zassenhaus + + >>> gf_ddf_zassenhaus(f, 11, ZZ) + [([1, 0, 0, 0, 0, 10], 1), ([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2)] + + which means ``x**15 - 1 = (x**5 - 1) (x**10 + x**5 + 1)``. To obtain + factorization into irreducibles, use equal degree factorization + procedure (EDF) with each of the factors. + + References + ========== + + .. [1] [Gathen99]_ + .. [2] [Geddes92]_ + + """ + i, g, factors = 1, [K.one, K.zero], [] + + b = gf_frobenius_monomial_base(f, p, K) + while 2*i <= gf_degree(f): + g = gf_frobenius_map(g, f, b, p, K) + h = gf_gcd(f, gf_sub(g, [K.one, K.zero], p, K), p, K) + + if h != [K.one]: + factors.append((h, i)) + + f = gf_quo(f, h, p, K) + g = gf_rem(g, f, p, K) + b = gf_frobenius_monomial_base(f, p, K) + + i += 1 + + if f != [K.one]: + return factors + [(f, gf_degree(f))] + else: + return factors + + +def gf_edf_zassenhaus(f, n, p, K): + """ + Cantor-Zassenhaus: Probabilistic Equal Degree Factorization + + Given a monic square-free polynomial ``f`` in ``GF(p)[x]`` and + an integer ``n``, such that ``n`` divides ``deg(f)``, returns all + irreducible factors ``f_1,...,f_d`` of ``f``, each of degree ``n``. + EDF procedure gives complete factorization over Galois fields. + + Consider the square-free polynomial ``f = x**3 + x**2 + x + 1`` in + ``GF(5)[x]``. Let's compute its irreducible factors of degree one:: + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_edf_zassenhaus + + >>> gf_edf_zassenhaus([1,1,1,1], 1, 5, ZZ) + [[1, 1], [1, 2], [1, 3]] + + Notes + ===== + + The case p == 2 is handled by Cohen's Algorithm 3.4.8. The case p odd is + as in Geddes Algorithm 8.9 (or Cohen's Algorithm 3.4.6). + + References + ========== + + .. [1] [Gathen99]_ + .. [2] [Geddes92]_ Algorithm 8.9 + .. [3] [Cohen93]_ Algorithm 3.4.8 + + """ + factors = [f] + + if gf_degree(f) <= n: + return factors + + N = gf_degree(f) // n + if p != 2: + b = gf_frobenius_monomial_base(f, p, K) + + t = [K.one, K.zero] + while len(factors) < N: + if p == 2: + h = r = t + + for i in range(n - 1): + r = gf_pow_mod(r, 2, f, p, K) + h = gf_add(h, r, p, K) + + g = gf_gcd(f, h, p, K) + t += [K.zero, K.zero] + else: + r = gf_random(2 * n - 1, p, K) + h = _gf_pow_pnm1d2(r, n, f, b, p, K) + g = gf_gcd(f, gf_sub_ground(h, K.one, p, K), p, K) + + if g != [K.one] and g != f: + factors = gf_edf_zassenhaus(g, n, p, K) \ + + gf_edf_zassenhaus(gf_quo(f, g, p, K), n, p, K) + + return _sort_factors(factors, multiple=False) + + +def gf_ddf_shoup(f, p, K): + """ + Kaltofen-Shoup: Deterministic Distinct Degree Factorization + + Given a monic square-free polynomial ``f`` in ``GF(p)[x]``, computes + partial distinct degree factorization ``f_1,...,f_d`` of ``f`` where + ``deg(f_i) != deg(f_j)`` for ``i != j``. The result is returned as a + list of pairs ``(f_i, e_i)`` where ``deg(f_i) > 0`` and ``e_i > 0`` + is an argument to the equal degree factorization routine. + + This algorithm is an improved version of Zassenhaus algorithm for + large ``deg(f)`` and modulus ``p`` (especially for ``deg(f) ~ lg(p)``). + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_ddf_shoup, gf_from_dict + + >>> f = gf_from_dict({6: ZZ(1), 5: ZZ(-1), 4: ZZ(1), 3: ZZ(1), 1: ZZ(-1)}, 3, ZZ) + + >>> gf_ddf_shoup(f, 3, ZZ) + [([1, 1, 0], 1), ([1, 1, 0, 1, 2], 2)] + + References + ========== + + .. [1] [Kaltofen98]_ + .. [2] [Shoup95]_ + .. [3] [Gathen92]_ + + """ + n = gf_degree(f) + k = int(_ceil(_sqrt(n//2))) + b = gf_frobenius_monomial_base(f, p, K) + h = gf_frobenius_map([K.one, K.zero], f, b, p, K) + # U[i] = x**(p**i) + U = [[K.one, K.zero], h] + [K.zero]*(k - 1) + + for i in range(2, k + 1): + U[i] = gf_frobenius_map(U[i-1], f, b, p, K) + + h, U = U[k], U[:k] + # V[i] = x**(p**(k*(i+1))) + V = [h] + [K.zero]*(k - 1) + + for i in range(1, k): + V[i] = gf_compose_mod(V[i - 1], h, f, p, K) + + factors = [] + + for i, v in enumerate(V): + h, j = [K.one], k - 1 + + for u in U: + g = gf_sub(v, u, p, K) + h = gf_mul(h, g, p, K) + h = gf_rem(h, f, p, K) + + g = gf_gcd(f, h, p, K) + f = gf_quo(f, g, p, K) + + for u in reversed(U): + h = gf_sub(v, u, p, K) + F = gf_gcd(g, h, p, K) + + if F != [K.one]: + factors.append((F, k*(i + 1) - j)) + + g, j = gf_quo(g, F, p, K), j - 1 + + if f != [K.one]: + factors.append((f, gf_degree(f))) + + return factors + +def gf_edf_shoup(f, n, p, K): + """ + Gathen-Shoup: Probabilistic Equal Degree Factorization + + Given a monic square-free polynomial ``f`` in ``GF(p)[x]`` and integer + ``n`` such that ``n`` divides ``deg(f)``, returns all irreducible factors + ``f_1,...,f_d`` of ``f``, each of degree ``n``. This is a complete + factorization over Galois fields. + + This algorithm is an improved version of Zassenhaus algorithm for + large ``deg(f)`` and modulus ``p`` (especially for ``deg(f) ~ lg(p)``). + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_edf_shoup + + >>> gf_edf_shoup(ZZ.map([1, 2837, 2277]), 1, 2917, ZZ) + [[1, 852], [1, 1985]] + + References + ========== + + .. [1] [Shoup91]_ + .. [2] [Gathen92]_ + + """ + N, q = gf_degree(f), int(p) + + if not N: + return [] + if N <= n: + return [f] + + factors, x = [f], [K.one, K.zero] + + r = gf_random(N - 1, p, K) + + if p == 2: + h = gf_pow_mod(x, q, f, p, K) + H = gf_trace_map(r, h, x, n - 1, f, p, K)[1] + h1 = gf_gcd(f, H, p, K) + h2 = gf_quo(f, h1, p, K) + + factors = gf_edf_shoup(h1, n, p, K) \ + + gf_edf_shoup(h2, n, p, K) + else: + b = gf_frobenius_monomial_base(f, p, K) + H = _gf_trace_map(r, n, f, b, p, K) + h = gf_pow_mod(H, (q - 1)//2, f, p, K) + + h1 = gf_gcd(f, h, p, K) + h2 = gf_gcd(f, gf_sub_ground(h, K.one, p, K), p, K) + h3 = gf_quo(f, gf_mul(h1, h2, p, K), p, K) + + factors = gf_edf_shoup(h1, n, p, K) \ + + gf_edf_shoup(h2, n, p, K) \ + + gf_edf_shoup(h3, n, p, K) + + return _sort_factors(factors, multiple=False) + + +def gf_zassenhaus(f, p, K): + """ + Factor a square-free ``f`` in ``GF(p)[x]`` for medium ``p``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_zassenhaus + + >>> gf_zassenhaus(ZZ.map([1, 4, 3]), 5, ZZ) + [[1, 1], [1, 3]] + + """ + factors = [] + + for factor, n in gf_ddf_zassenhaus(f, p, K): + factors += gf_edf_zassenhaus(factor, n, p, K) + + return _sort_factors(factors, multiple=False) + + +def gf_shoup(f, p, K): + """ + Factor a square-free ``f`` in ``GF(p)[x]`` for large ``p``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_shoup + + >>> gf_shoup(ZZ.map([1, 4, 3]), 5, ZZ) + [[1, 1], [1, 3]] + + """ + factors = [] + + for factor, n in gf_ddf_shoup(f, p, K): + factors += gf_edf_shoup(factor, n, p, K) + + return _sort_factors(factors, multiple=False) + +_factor_methods = { + 'berlekamp': gf_berlekamp, # ``p`` : small + 'zassenhaus': gf_zassenhaus, # ``p`` : medium + 'shoup': gf_shoup, # ``p`` : large +} + + +def gf_factor_sqf(f, p, K, method=None): + """ + Factor a square-free polynomial ``f`` in ``GF(p)[x]``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_factor_sqf + + >>> gf_factor_sqf(ZZ.map([3, 2, 4]), 5, ZZ) + (3, [[1, 1], [1, 3]]) + + """ + lc, f = gf_monic(f, p, K) + + if gf_degree(f) < 1: + return lc, [] + + method = method or query('GF_FACTOR_METHOD') + + if method is not None: + factors = _factor_methods[method](f, p, K) + else: + factors = gf_zassenhaus(f, p, K) + + return lc, factors + + +def gf_factor(f, p, K): + """ + Factor (non square-free) polynomials in ``GF(p)[x]``. + + Given a possibly non square-free polynomial ``f`` in ``GF(p)[x]``, + returns its complete factorization into irreducibles:: + + f_1(x)**e_1 f_2(x)**e_2 ... f_d(x)**e_d + + where each ``f_i`` is a monic polynomial and ``gcd(f_i, f_j) == 1``, + for ``i != j``. The result is given as a tuple consisting of the + leading coefficient of ``f`` and a list of factors of ``f`` with + their multiplicities. + + The algorithm proceeds by first computing square-free decomposition + of ``f`` and then iteratively factoring each of square-free factors. + + Consider a non square-free polynomial ``f = (7*x + 1) (x + 2)**2`` in + ``GF(11)[x]``. We obtain its factorization into irreducibles as follows:: + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.galoistools import gf_factor + + >>> gf_factor(ZZ.map([5, 2, 7, 2]), 11, ZZ) + (5, [([1, 2], 1), ([1, 8], 2)]) + + We arrived with factorization ``f = 5 (x + 2) (x + 8)**2``. We did not + recover the exact form of the input polynomial because we requested to + get monic factors of ``f`` and its leading coefficient separately. + + Square-free factors of ``f`` can be factored into irreducibles over + ``GF(p)`` using three very different methods: + + Berlekamp + efficient for very small values of ``p`` (usually ``p < 25``) + Cantor-Zassenhaus + efficient on average input and with "typical" ``p`` + Shoup-Kaltofen-Gathen + efficient with very large inputs and modulus + + If you want to use a specific factorization method, instead of the default + one, set ``GF_FACTOR_METHOD`` with one of ``berlekamp``, ``zassenhaus`` or + ``shoup`` values. + + References + ========== + + .. [1] [Gathen99]_ + + """ + lc, f = gf_monic(f, p, K) + + if gf_degree(f) < 1: + return lc, [] + + factors = [] + + for g, n in gf_sqf_list(f, p, K)[1]: + for h in gf_factor_sqf(g, p, K)[1]: + factors.append((h, n)) + + return lc, _sort_factors(factors) + + +def gf_value(f, a): + """ + Value of polynomial 'f' at 'a' in field R. + + Examples + ======== + + >>> from sympy.polys.galoistools import gf_value + + >>> gf_value([1, 7, 2, 4], 11) + 2204 + + """ + result = 0 + for c in f: + result *= a + result += c + return result + + +def linear_congruence(a, b, m): + """ + Returns the values of x satisfying a*x congruent b mod(m) + + Here m is positive integer and a, b are natural numbers. + This function returns only those values of x which are distinct mod(m). + + Examples + ======== + + >>> from sympy.polys.galoistools import linear_congruence + + >>> linear_congruence(3, 12, 15) + [4, 9, 14] + + There are 3 solutions distinct mod(15) since gcd(a, m) = gcd(3, 15) = 3. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Linear_congruence_theorem + + """ + from sympy.polys.polytools import gcdex + if a % m == 0: + if b % m == 0: + return list(range(m)) + else: + return [] + r, _, g = gcdex(a, m) + if b % g != 0: + return [] + return [(r * b // g + t * m // g) % m for t in range(g)] + + +def _raise_mod_power(x, s, p, f): + """ + Used in gf_csolve to generate solutions of f(x) cong 0 mod(p**(s + 1)) + from the solutions of f(x) cong 0 mod(p**s). + + Examples + ======== + + >>> from sympy.polys.galoistools import _raise_mod_power + >>> from sympy.polys.galoistools import csolve_prime + + These is the solutions of f(x) = x**2 + x + 7 cong 0 mod(3) + + >>> f = [1, 1, 7] + >>> csolve_prime(f, 3) + [1] + >>> [ i for i in range(3) if not (i**2 + i + 7) % 3] + [1] + + The solutions of f(x) cong 0 mod(9) are constructed from the + values returned from _raise_mod_power: + + >>> x, s, p = 1, 1, 3 + >>> V = _raise_mod_power(x, s, p, f) + >>> [x + v * p**s for v in V] + [1, 4, 7] + + And these are confirmed with the following: + + >>> [ i for i in range(3**2) if not (i**2 + i + 7) % 3**2] + [1, 4, 7] + + """ + from sympy.polys.domains import ZZ + f_f = gf_diff(f, p, ZZ) + alpha = gf_value(f_f, x) + beta = - gf_value(f, x) // p**s + return linear_congruence(alpha, beta, p) + + +def _csolve_prime_las_vegas(f, p, seed=None): + r""" Solutions of `f(x) \equiv 0 \pmod{p}`, `f(0) \not\equiv 0 \pmod{p}`. + + Explanation + =========== + + This algorithm is classified as the Las Vegas method. + That is, it always returns the correct answer and solves the problem + fast in many cases, but if it is unlucky, it does not answer forever. + + Suppose the polynomial f is not a zero polynomial. Assume further + that it is of degree at most p-1 and `f(0)\not\equiv 0 \pmod{p}`. + These assumptions are not an essential part of the algorithm, + only that it is more convenient for the function calling this + function to resolve them. + + Note that `x^{p-1} - 1 \equiv \prod_{a=1}^{p-1}(x - a) \pmod{p}`. + Thus, the greatest common divisor with f is `\prod_{s \in S}(x - s)`, + with S being the set of solutions to f. Furthermore, + when a is randomly determined, `(x+a)^{(p-1)/2}-1` is + a polynomial with (p-1)/2 randomly chosen solutions. + The greatest common divisor of f may be a nontrivial factor of f. + + When p is large and the degree of f is small, + it is faster than naive solution methods. + + Parameters + ========== + + f : polynomial + p : prime number + + Returns + ======= + + list[int] + a list of solutions, sorted in ascending order + by integers in the range [1, p). The same value + does not exist in the list even if there is + a multiple solution. If no solution exists, returns []. + + Examples + ======== + + >>> from sympy.polys.galoistools import _csolve_prime_las_vegas + >>> _csolve_prime_las_vegas([1, 4, 3], 7) # x^2 + 4x + 3 = 0 (mod 7) + [4, 6] + >>> _csolve_prime_las_vegas([5, 7, 1, 9], 11) # 5x^3 + 7x^2 + x + 9 = 0 (mod 11) + [1, 5, 8] + + References + ========== + + .. [1] R. Crandall and C. Pomerance "Prime Numbers", 2nd Ed., Algorithm 2.3.10 + + """ + from sympy.polys.domains import ZZ + from sympy.ntheory import sqrt_mod + randint = _randint(seed) + root = set() + g = gf_pow_mod([1, 0], p - 1, f, p, ZZ) + g = gf_sub_ground(g, 1, p, ZZ) + # We want to calculate gcd(x**(p-1) - 1, f(x)) + factors = [gf_gcd(f, g, p, ZZ)] + while factors: + f = factors.pop() + # If the degree is small, solve directly + if len(f) <= 1: + continue + if len(f) == 2: + root.add(-invert(f[0], p) * f[1] % p) + continue + if len(f) == 3: + inv = invert(f[0], p) + b = f[1] * inv % p + b = (b + p * (b % 2)) // 2 + root.update((r - b) % p for r in + sqrt_mod(b**2 - f[2] * inv, p, all_roots=True)) + continue + while True: + # Determine `a` randomly and + # compute gcd((x+a)**((p-1)//2)-1, f(x)) + a = randint(0, p - 1) + g = gf_pow_mod([1, a], (p - 1) // 2, f, p, ZZ) + g = gf_sub_ground(g, 1, p, ZZ) + g = gf_gcd(f, g, p, ZZ) + if 1 < len(g) < len(f): + factors.append(g) + factors.append(gf_div(f, g, p, ZZ)[0]) + break + return sorted(root) + + +def csolve_prime(f, p, e=1): + r""" Solutions of `f(x) \equiv 0 \pmod{p^e}`. + + Parameters + ========== + + f : polynomial + p : prime number + e : positive integer + + Returns + ======= + + list[int] + a list of solutions, sorted in ascending order + by integers in the range [1, p**e). The same value + does not exist in the list even if there is + a multiple solution. If no solution exists, returns []. + + Examples + ======== + + >>> from sympy.polys.galoistools import csolve_prime + >>> csolve_prime([1, 1, 7], 3, 1) + [1] + >>> csolve_prime([1, 1, 7], 3, 2) + [1, 4, 7] + + Solutions [7, 4, 1] (mod 3**2) are generated by ``_raise_mod_power()`` + from solution [1] (mod 3). + """ + from sympy.polys.domains import ZZ + g = [MPZ(int(c)) for c in f] + # Convert to polynomial of degree at most p-1 + for i in range(len(g) - p): + g[i + p - 1] += g[i] + g[i] = 0 + g = gf_trunc(g, p) + # Checks whether g(x) is divisible by x + k = 0 + while k < len(g) and g[len(g) - k - 1] == 0: + k += 1 + if k: + g = g[:-k] + root_zero = [0] + else: + root_zero = [] + if g == []: + X1 = list(range(p)) + elif len(g)**2 < p: + # The conditions under which `_csolve_prime_las_vegas` is faster than + # a naive solution are worth considering. + X1 = root_zero + _csolve_prime_las_vegas(g, p) + else: + X1 = root_zero + [i for i in range(p) if gf_eval(g, i, p, ZZ) == 0] + if e == 1: + return X1 + X = [] + S = list(zip(X1, [1]*len(X1))) + while S: + x, s = S.pop() + if s == e: + X.append(x) + else: + s1 = s + 1 + ps = p**s + S.extend([(x + v*ps, s1) for v in _raise_mod_power(x, s, p, f)]) + return sorted(X) + + +def gf_csolve(f, n): + """ + To solve f(x) congruent 0 mod(n). + + n is divided into canonical factors and f(x) cong 0 mod(p**e) will be + solved for each factor. Applying the Chinese Remainder Theorem to the + results returns the final answers. + + Examples + ======== + + Solve [1, 1, 7] congruent 0 mod(189): + + >>> from sympy.polys.galoistools import gf_csolve + >>> gf_csolve([1, 1, 7], 189) + [13, 49, 76, 112, 139, 175] + + See Also + ======== + + sympy.ntheory.residue_ntheory.polynomial_congruence : a higher level solving routine + + References + ========== + + .. [1] 'An introduction to the Theory of Numbers' 5th Edition by Ivan Niven, + Zuckerman and Montgomery. + + """ + from sympy.polys.domains import ZZ + from sympy.ntheory import factorint + P = factorint(n) + X = [csolve_prime(f, p, e) for p, e in P.items()] + pools = list(map(tuple, X)) + perms = [[]] + for pool in pools: + perms = [x + [y] for x in perms for y in pool] + dist_factors = [pow(p, e) for p, e in P.items()] + return sorted([gf_crt(per, dist_factors, ZZ) for per in perms]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/groebnertools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/groebnertools.py new file mode 100644 index 0000000000000000000000000000000000000000..fc5c2f228ab4f4182e4c8fff68d974aa25c9d531 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/groebnertools.py @@ -0,0 +1,862 @@ +"""Groebner bases algorithms. """ + + +from sympy.core.symbol import Dummy +from sympy.polys.monomials import monomial_mul, monomial_lcm, monomial_divides, term_div +from sympy.polys.orderings import lex +from sympy.polys.polyerrors import DomainError +from sympy.polys.polyconfig import query + +def groebner(seq, ring, method=None): + """ + Computes Groebner basis for a set of polynomials in `K[X]`. + + Wrapper around the (default) improved Buchberger and the other algorithms + for computing Groebner bases. The choice of algorithm can be changed via + ``method`` argument or :func:`sympy.polys.polyconfig.setup`, where + ``method`` can be either ``buchberger`` or ``f5b``. + + """ + if method is None: + method = query('groebner') + + _groebner_methods = { + 'buchberger': _buchberger, + 'f5b': _f5b, + } + + try: + _groebner = _groebner_methods[method] + except KeyError: + raise ValueError("'%s' is not a valid Groebner bases algorithm (valid are 'buchberger' and 'f5b')" % method) + + domain, orig = ring.domain, None + + if not domain.is_Field or not domain.has_assoc_Field: + try: + orig, ring = ring, ring.clone(domain=domain.get_field()) + except DomainError: + raise DomainError("Cannot compute a Groebner basis over %s" % domain) + else: + seq = [ s.set_ring(ring) for s in seq ] + + G = _groebner(seq, ring) + + if orig is not None: + G = [ g.clear_denoms()[1].set_ring(orig) for g in G ] + + return G + +def _buchberger(f, ring): + """ + Computes Groebner basis for a set of polynomials in `K[X]`. + + Given a set of multivariate polynomials `F`, finds another + set `G`, such that Ideal `F = Ideal G` and `G` is a reduced + Groebner basis. + + The resulting basis is unique and has monic generators if the + ground domains is a field. Otherwise the result is non-unique + but Groebner bases over e.g. integers can be computed (if the + input polynomials are monic). + + Groebner bases can be used to choose specific generators for a + polynomial ideal. Because these bases are unique you can check + for ideal equality by comparing the Groebner bases. To see if + one polynomial lies in an ideal, divide by the elements in the + base and see if the remainder vanishes. + + They can also be used to solve systems of polynomial equations + as, by choosing lexicographic ordering, you can eliminate one + variable at a time, provided that the ideal is zero-dimensional + (finite number of solutions). + + Notes + ===== + + Algorithm used: an improved version of Buchberger's algorithm + as presented in T. Becker, V. Weispfenning, Groebner Bases: A + Computational Approach to Commutative Algebra, Springer, 1993, + page 232. + + References + ========== + + .. [1] [Bose03]_ + .. [2] [Giovini91]_ + .. [3] [Ajwa95]_ + .. [4] [Cox97]_ + + """ + order = ring.order + + monomial_mul = ring.monomial_mul + monomial_div = ring.monomial_div + monomial_lcm = ring.monomial_lcm + + def select(P): + # normal selection strategy + # select the pair with minimum LCM(LM(f), LM(g)) + pr = min(P, key=lambda pair: order(monomial_lcm(f[pair[0]].LM, f[pair[1]].LM))) + return pr + + def normal(g, J): + h = g.rem([ f[j] for j in J ]) + + if not h: + return None + else: + h = h.monic() + + if h not in I: + I[h] = len(f) + f.append(h) + + return h.LM, I[h] + + def update(G, B, ih): + # update G using the set of critical pairs B and h + # [BW] page 230 + h = f[ih] + mh = h.LM + + # filter new pairs (h, g), g in G + C = G.copy() + D = set() + + while C: + # select a pair (h, g) by popping an element from C + ig = C.pop() + g = f[ig] + mg = g.LM + LCMhg = monomial_lcm(mh, mg) + + def lcm_divides(ip): + # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g)) + m = monomial_lcm(mh, f[ip].LM) + return monomial_div(LCMhg, m) + + # HT(h) and HT(g) disjoint: mh*mg == LCMhg + if monomial_mul(mh, mg) == LCMhg or ( + not any(lcm_divides(ipx) for ipx in C) and + not any(lcm_divides(pr[1]) for pr in D)): + D.add((ih, ig)) + + E = set() + + while D: + # select h, g from D (h the same as above) + ih, ig = D.pop() + mg = f[ig].LM + LCMhg = monomial_lcm(mh, mg) + + if not monomial_mul(mh, mg) == LCMhg: + E.add((ih, ig)) + + # filter old pairs + B_new = set() + + while B: + # select g1, g2 from B (-> CP) + ig1, ig2 = B.pop() + mg1 = f[ig1].LM + mg2 = f[ig2].LM + LCM12 = monomial_lcm(mg1, mg2) + + # if HT(h) does not divide lcm(HT(g1), HT(g2)) + if not monomial_div(LCM12, mh) or \ + monomial_lcm(mg1, mh) == LCM12 or \ + monomial_lcm(mg2, mh) == LCM12: + B_new.add((ig1, ig2)) + + B_new |= E + + # filter polynomials + G_new = set() + + while G: + ig = G.pop() + mg = f[ig].LM + + if not monomial_div(mg, mh): + G_new.add(ig) + + G_new.add(ih) + + return G_new, B_new + # end of update ################################ + + if not f: + return [] + + # replace f with a reduced list of initial polynomials; see [BW] page 203 + f1 = f[:] + + while True: + f = f1[:] + f1 = [] + + for i in range(len(f)): + p = f[i] + r = p.rem(f[:i]) + + if r: + f1.append(r.monic()) + + if f == f1: + break + + I = {} # ip = I[p]; p = f[ip] + F = set() # set of indices of polynomials + G = set() # set of indices of intermediate would-be Groebner basis + CP = set() # set of pairs of indices of critical pairs + + for i, h in enumerate(f): + I[h] = i + F.add(i) + + ##################################### + # algorithm GROEBNERNEWS2 in [BW] page 232 + + while F: + # select p with minimum monomial according to the monomial ordering + h = min([f[x] for x in F], key=lambda f: order(f.LM)) + ih = I[h] + F.remove(ih) + G, CP = update(G, CP, ih) + + # count the number of critical pairs which reduce to zero + reductions_to_zero = 0 + + while CP: + ig1, ig2 = select(CP) + CP.remove((ig1, ig2)) + + h = spoly(f[ig1], f[ig2], ring) + # ordering divisors is on average more efficient [Cox] page 111 + G1 = sorted(G, key=lambda g: order(f[g].LM)) + ht = normal(h, G1) + + if ht: + G, CP = update(G, CP, ht[1]) + else: + reductions_to_zero += 1 + + ###################################### + # now G is a Groebner basis; reduce it + Gr = set() + + for ig in G: + ht = normal(f[ig], G - {ig}) + + if ht: + Gr.add(ht[1]) + + Gr = [f[ig] for ig in Gr] + + # order according to the monomial ordering + Gr = sorted(Gr, key=lambda f: order(f.LM), reverse=True) + + return Gr + +def spoly(p1, p2, ring): + """ + Compute LCM(LM(p1), LM(p2))/LM(p1)*p1 - LCM(LM(p1), LM(p2))/LM(p2)*p2 + This is the S-poly provided p1 and p2 are monic + """ + LM1 = p1.LM + LM2 = p2.LM + LCM12 = ring.monomial_lcm(LM1, LM2) + m1 = ring.monomial_div(LCM12, LM1) + m2 = ring.monomial_div(LCM12, LM2) + s1 = p1.mul_monom(m1) + s2 = p2.mul_monom(m2) + s = s1 - s2 + return s + +# F5B + +# convenience functions + + +def Sign(f): + return f[0] + + +def Polyn(f): + return f[1] + + +def Num(f): + return f[2] + + +def sig(monomial, index): + return (monomial, index) + + +def lbp(signature, polynomial, number): + return (signature, polynomial, number) + +# signature functions + + +def sig_cmp(u, v, order): + """ + Compare two signatures by extending the term order to K[X]^n. + + u < v iff + - the index of v is greater than the index of u + or + - the index of v is equal to the index of u and u[0] < v[0] w.r.t. order + + u > v otherwise + """ + if u[1] > v[1]: + return -1 + if u[1] == v[1]: + #if u[0] == v[0]: + # return 0 + if order(u[0]) < order(v[0]): + return -1 + return 1 + + +def sig_key(s, order): + """ + Key for comparing two signatures. + + s = (m, k), t = (n, l) + + s < t iff [k > l] or [k == l and m < n] + s > t otherwise + """ + return (-s[1], order(s[0])) + + +def sig_mult(s, m): + """ + Multiply a signature by a monomial. + + The product of a signature (m, i) and a monomial n is defined as + (m * t, i). + """ + return sig(monomial_mul(s[0], m), s[1]) + +# labeled polynomial functions + + +def lbp_sub(f, g): + """ + Subtract labeled polynomial g from f. + + The signature and number of the difference of f and g are signature + and number of the maximum of f and g, w.r.t. lbp_cmp. + """ + if sig_cmp(Sign(f), Sign(g), Polyn(f).ring.order) < 0: + max_poly = g + else: + max_poly = f + + ret = Polyn(f) - Polyn(g) + + return lbp(Sign(max_poly), ret, Num(max_poly)) + + +def lbp_mul_term(f, cx): + """ + Multiply a labeled polynomial with a term. + + The product of a labeled polynomial (s, p, k) by a monomial is + defined as (m * s, m * p, k). + """ + return lbp(sig_mult(Sign(f), cx[0]), Polyn(f).mul_term(cx), Num(f)) + + +def lbp_cmp(f, g): + """ + Compare two labeled polynomials. + + f < g iff + - Sign(f) < Sign(g) + or + - Sign(f) == Sign(g) and Num(f) > Num(g) + + f > g otherwise + """ + if sig_cmp(Sign(f), Sign(g), Polyn(f).ring.order) == -1: + return -1 + if Sign(f) == Sign(g): + if Num(f) > Num(g): + return -1 + #if Num(f) == Num(g): + # return 0 + return 1 + + +def lbp_key(f): + """ + Key for comparing two labeled polynomials. + """ + return (sig_key(Sign(f), Polyn(f).ring.order), -Num(f)) + +# algorithm and helper functions + + +def critical_pair(f, g, ring): + """ + Compute the critical pair corresponding to two labeled polynomials. + + A critical pair is a tuple (um, f, vm, g), where um and vm are + terms such that um * f - vm * g is the S-polynomial of f and g (so, + wlog assume um * f > vm * g). + For performance sake, a critical pair is represented as a tuple + (Sign(um * f), um, f, Sign(vm * g), vm, g), since um * f creates + a new, relatively expensive object in memory, whereas Sign(um * + f) and um are lightweight and f (in the tuple) is a reference to + an already existing object in memory. + """ + domain = ring.domain + + ltf = Polyn(f).LT + ltg = Polyn(g).LT + lt = (monomial_lcm(ltf[0], ltg[0]), domain.one) + + um = term_div(lt, ltf, domain) + vm = term_div(lt, ltg, domain) + + # The full information is not needed (now), so only the product + # with the leading term is considered: + fr = lbp_mul_term(lbp(Sign(f), Polyn(f).leading_term(), Num(f)), um) + gr = lbp_mul_term(lbp(Sign(g), Polyn(g).leading_term(), Num(g)), vm) + + # return in proper order, such that the S-polynomial is just + # u_first * f_first - u_second * f_second: + if lbp_cmp(fr, gr) == -1: + return (Sign(gr), vm, g, Sign(fr), um, f) + else: + return (Sign(fr), um, f, Sign(gr), vm, g) + + +def cp_cmp(c, d): + """ + Compare two critical pairs c and d. + + c < d iff + - lbp(c[0], _, Num(c[2]) < lbp(d[0], _, Num(d[2])) (this + corresponds to um_c * f_c and um_d * f_d) + or + - lbp(c[0], _, Num(c[2]) >< lbp(d[0], _, Num(d[2])) and + lbp(c[3], _, Num(c[5])) < lbp(d[3], _, Num(d[5])) (this + corresponds to vm_c * g_c and vm_d * g_d) + + c > d otherwise + """ + zero = Polyn(c[2]).ring.zero + + c0 = lbp(c[0], zero, Num(c[2])) + d0 = lbp(d[0], zero, Num(d[2])) + + r = lbp_cmp(c0, d0) + + if r == -1: + return -1 + if r == 0: + c1 = lbp(c[3], zero, Num(c[5])) + d1 = lbp(d[3], zero, Num(d[5])) + + r = lbp_cmp(c1, d1) + + if r == -1: + return -1 + #if r == 0: + # return 0 + return 1 + + +def cp_key(c, ring): + """ + Key for comparing critical pairs. + """ + return (lbp_key(lbp(c[0], ring.zero, Num(c[2]))), lbp_key(lbp(c[3], ring.zero, Num(c[5])))) + + +def s_poly(cp): + """ + Compute the S-polynomial of a critical pair. + + The S-polynomial of a critical pair cp is cp[1] * cp[2] - cp[4] * cp[5]. + """ + return lbp_sub(lbp_mul_term(cp[2], cp[1]), lbp_mul_term(cp[5], cp[4])) + + +def is_rewritable_or_comparable(sign, num, B): + """ + Check if a labeled polynomial is redundant by checking if its + signature and number imply rewritability or comparability. + + (sign, num) is comparable if there exists a labeled polynomial + h in B, such that sign[1] (the index) is less than Sign(h)[1] + and sign[0] is divisible by the leading monomial of h. + + (sign, num) is rewritable if there exists a labeled polynomial + h in B, such thatsign[1] is equal to Sign(h)[1], num < Num(h) + and sign[0] is divisible by Sign(h)[0]. + """ + for h in B: + # comparable + if sign[1] < Sign(h)[1]: + if monomial_divides(Polyn(h).LM, sign[0]): + return True + + # rewritable + if sign[1] == Sign(h)[1]: + if num < Num(h): + if monomial_divides(Sign(h)[0], sign[0]): + return True + return False + + +def f5_reduce(f, B): + """ + F5-reduce a labeled polynomial f by B. + + Continuously searches for non-zero labeled polynomial h in B, such + that the leading term lt_h of h divides the leading term lt_f of + f and Sign(lt_h * h) < Sign(f). If such a labeled polynomial h is + found, f gets replaced by f - lt_f / lt_h * h. If no such h can be + found or f is 0, f is no further F5-reducible and f gets returned. + + A polynomial that is reducible in the usual sense need not be + F5-reducible, e.g.: + + >>> from sympy.polys.groebnertools import lbp, sig, f5_reduce, Polyn + >>> from sympy.polys import ring, QQ, lex + + >>> R, x,y,z = ring("x,y,z", QQ, lex) + + >>> f = lbp(sig((1, 1, 1), 4), x, 3) + >>> g = lbp(sig((0, 0, 0), 2), x, 2) + + >>> Polyn(f).rem([Polyn(g)]) + 0 + >>> f5_reduce(f, [g]) + (((1, 1, 1), 4), x, 3) + + """ + order = Polyn(f).ring.order + domain = Polyn(f).ring.domain + + if not Polyn(f): + return f + + while True: + g = f + + for h in B: + if Polyn(h): + if monomial_divides(Polyn(h).LM, Polyn(f).LM): + t = term_div(Polyn(f).LT, Polyn(h).LT, domain) + if sig_cmp(sig_mult(Sign(h), t[0]), Sign(f), order) < 0: + # The following check need not be done and is in general slower than without. + #if not is_rewritable_or_comparable(Sign(gp), Num(gp), B): + hp = lbp_mul_term(h, t) + f = lbp_sub(f, hp) + break + + if g == f or not Polyn(f): + return f + + +def _f5b(F, ring): + """ + Computes a reduced Groebner basis for the ideal generated by F. + + f5b is an implementation of the F5B algorithm by Yao Sun and + Dingkang Wang. Similarly to Buchberger's algorithm, the algorithm + proceeds by computing critical pairs, computing the S-polynomial, + reducing it and adjoining the reduced S-polynomial if it is not 0. + + Unlike Buchberger's algorithm, each polynomial contains additional + information, namely a signature and a number. The signature + specifies the path of computation (i.e. from which polynomial in + the original basis was it derived and how), the number says when + the polynomial was added to the basis. With this information it + is (often) possible to decide if an S-polynomial will reduce to + 0 and can be discarded. + + Optimizations include: Reducing the generators before computing + a Groebner basis, removing redundant critical pairs when a new + polynomial enters the basis and sorting the critical pairs and + the current basis. + + Once a Groebner basis has been found, it gets reduced. + + References + ========== + + .. [1] Yao Sun, Dingkang Wang: "A New Proof for the Correctness of F5 + (F5-Like) Algorithm", https://arxiv.org/abs/1004.0084 (specifically + v4) + + .. [2] Thomas Becker, Volker Weispfenning, Groebner bases: A computational + approach to commutative algebra, 1993, p. 203, 216 + """ + order = ring.order + + # reduce polynomials (like in Mario Pernici's implementation) (Becker, Weispfenning, p. 203) + B = F + while True: + F = B + B = [] + + for i in range(len(F)): + p = F[i] + r = p.rem(F[:i]) + + if r: + B.append(r) + + if F == B: + break + + # basis + B = [lbp(sig(ring.zero_monom, i + 1), F[i], i + 1) for i in range(len(F))] + B.sort(key=lambda f: order(Polyn(f).LM), reverse=True) + + # critical pairs + CP = [critical_pair(B[i], B[j], ring) for i in range(len(B)) for j in range(i + 1, len(B))] + CP.sort(key=lambda cp: cp_key(cp, ring), reverse=True) + + k = len(B) + + reductions_to_zero = 0 + + while len(CP): + cp = CP.pop() + + # discard redundant critical pairs: + if is_rewritable_or_comparable(cp[0], Num(cp[2]), B): + continue + if is_rewritable_or_comparable(cp[3], Num(cp[5]), B): + continue + + s = s_poly(cp) + + p = f5_reduce(s, B) + + p = lbp(Sign(p), Polyn(p).monic(), k + 1) + + if Polyn(p): + # remove old critical pairs, that become redundant when adding p: + indices = [] + for i, cp in enumerate(CP): + if is_rewritable_or_comparable(cp[0], Num(cp[2]), [p]): + indices.append(i) + elif is_rewritable_or_comparable(cp[3], Num(cp[5]), [p]): + indices.append(i) + + for i in reversed(indices): + del CP[i] + + # only add new critical pairs that are not made redundant by p: + for g in B: + if Polyn(g): + cp = critical_pair(p, g, ring) + if is_rewritable_or_comparable(cp[0], Num(cp[2]), [p]): + continue + elif is_rewritable_or_comparable(cp[3], Num(cp[5]), [p]): + continue + + CP.append(cp) + + # sort (other sorting methods/selection strategies were not as successful) + CP.sort(key=lambda cp: cp_key(cp, ring), reverse=True) + + # insert p into B: + m = Polyn(p).LM + if order(m) <= order(Polyn(B[-1]).LM): + B.append(p) + else: + for i, q in enumerate(B): + if order(m) > order(Polyn(q).LM): + B.insert(i, p) + break + + k += 1 + + #print(len(B), len(CP), "%d critical pairs removed" % len(indices)) + else: + reductions_to_zero += 1 + + # reduce Groebner basis: + H = [Polyn(g).monic() for g in B] + H = red_groebner(H, ring) + + return sorted(H, key=lambda f: order(f.LM), reverse=True) + + +def red_groebner(G, ring): + """ + Compute reduced Groebner basis, from BeckerWeispfenning93, p. 216 + + Selects a subset of generators, that already generate the ideal + and computes a reduced Groebner basis for them. + """ + def reduction(P): + """ + The actual reduction algorithm. + """ + Q = [] + for i, p in enumerate(P): + h = p.rem(P[:i] + P[i + 1:]) + if h: + Q.append(h) + + return [p.monic() for p in Q] + + F = G + H = [] + + while F: + f0 = F.pop() + + if not any(monomial_divides(f.LM, f0.LM) for f in F + H): + H.append(f0) + + # Becker, Weispfenning, p. 217: H is Groebner basis of the ideal generated by G. + return reduction(H) + + +def is_groebner(G, ring): + """ + Check if G is a Groebner basis. + """ + for i in range(len(G)): + for j in range(i + 1, len(G)): + s = spoly(G[i], G[j], ring) + s = s.rem(G) + if s: + return False + + return True + + +def is_minimal(G, ring): + """ + Checks if G is a minimal Groebner basis. + """ + order = ring.order + domain = ring.domain + + G.sort(key=lambda g: order(g.LM)) + + for i, g in enumerate(G): + if g.LC != domain.one: + return False + + for h in G[:i] + G[i + 1:]: + if monomial_divides(h.LM, g.LM): + return False + + return True + + +def is_reduced(G, ring): + """ + Checks if G is a reduced Groebner basis. + """ + order = ring.order + domain = ring.domain + + G.sort(key=lambda g: order(g.LM)) + + for i, g in enumerate(G): + if g.LC != domain.one: + return False + + for term in g.terms(): + for h in G[:i] + G[i + 1:]: + if monomial_divides(h.LM, term[0]): + return False + + return True + +def groebner_lcm(f, g): + """ + Computes LCM of two polynomials using Groebner bases. + + The LCM is computed as the unique generator of the intersection + of the two ideals generated by `f` and `g`. The approach is to + compute a Groebner basis with respect to lexicographic ordering + of `t*f` and `(1 - t)*g`, where `t` is an unrelated variable and + then filtering out the solution that does not contain `t`. + + References + ========== + + .. [1] [Cox97]_ + + """ + if f.ring != g.ring: + raise ValueError("Values should be equal") + + ring = f.ring + domain = ring.domain + + if not f or not g: + return ring.zero + + if len(f) <= 1 and len(g) <= 1: + monom = monomial_lcm(f.LM, g.LM) + coeff = domain.lcm(f.LC, g.LC) + return ring.term_new(monom, coeff) + + fc, f = f.primitive() + gc, g = g.primitive() + + lcm = domain.lcm(fc, gc) + + f_terms = [ ((1,) + monom, coeff) for monom, coeff in f.terms() ] + g_terms = [ ((0,) + monom, coeff) for monom, coeff in g.terms() ] \ + + [ ((1,) + monom,-coeff) for monom, coeff in g.terms() ] + + t = Dummy("t") + t_ring = ring.clone(symbols=(t,) + ring.symbols, order=lex) + + F = t_ring.from_terms(f_terms) + G = t_ring.from_terms(g_terms) + + basis = groebner([F, G], t_ring) + + def is_independent(h, j): + return not any(monom[j] for monom in h.monoms()) + + H = [ h for h in basis if is_independent(h, 0) ] + + h_terms = [ (monom[1:], coeff*lcm) for monom, coeff in H[0].terms() ] + h = ring.from_terms(h_terms) + + return h + +def groebner_gcd(f, g): + """Computes GCD of two polynomials using Groebner bases. """ + if f.ring != g.ring: + raise ValueError("Values should be equal") + domain = f.ring.domain + + if not domain.is_Field: + fc, f = f.primitive() + gc, g = g.primitive() + gcd = domain.gcd(fc, gc) + + H = (f*g).quo([groebner_lcm(f, g)]) + + if len(H) != 1: + raise ValueError("Length should be 1") + h = H[0] + + if not domain.is_Field: + return gcd*h + else: + return h.monic() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/heuristicgcd.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/heuristicgcd.py new file mode 100644 index 0000000000000000000000000000000000000000..ea9eeac952e88552d729f0bd3073dee21b6ab68b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/heuristicgcd.py @@ -0,0 +1,149 @@ +"""Heuristic polynomial GCD algorithm (HEUGCD). """ + +from .polyerrors import HeuristicGCDFailed + +HEU_GCD_MAX = 6 + +def heugcd(f, g): + """ + Heuristic polynomial GCD in ``Z[X]``. + + Given univariate polynomials ``f`` and ``g`` in ``Z[X]``, returns + their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` + such that:: + + h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) + + The algorithm is purely heuristic which means it may fail to compute + the GCD. This will be signaled by raising an exception. In this case + you will need to switch to another GCD method. + + The algorithm computes the polynomial GCD by evaluating polynomials + ``f`` and ``g`` at certain points and computing (fast) integer GCD + of those evaluations. The polynomial GCD is recovered from the integer + image by interpolation. The evaluation process reduces f and g variable + by variable into a large integer. The final step is to verify if the + interpolated polynomial is the correct GCD. This gives cofactors of + the input polynomials as a side effect. + + Examples + ======== + + >>> from sympy.polys.heuristicgcd import heugcd + >>> from sympy.polys import ring, ZZ + + >>> R, x,y, = ring("x,y", ZZ) + + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y + + >>> h, cff, cfg = heugcd(f, g) + >>> h, cff, cfg + (x + y, x + y, x) + + >>> cff*h == f + True + >>> cfg*h == g + True + + References + ========== + + .. [1] [Liao95]_ + + """ + assert f.ring == g.ring and f.ring.domain.is_ZZ + + ring = f.ring + x0 = ring.gens[0] + domain = ring.domain + + gcd, f, g = f.extract_ground(g) + + f_norm = f.max_norm() + g_norm = g.max_norm() + + B = domain(2*min(f_norm, g_norm) + 29) + + x = max(min(B, 99*domain.sqrt(B)), + 2*min(f_norm // abs(f.LC), + g_norm // abs(g.LC)) + 4) + + for i in range(0, HEU_GCD_MAX): + ff = f.evaluate(x0, x) + gg = g.evaluate(x0, x) + + if ff and gg: + if ring.ngens == 1: + h, cff, cfg = domain.cofactors(ff, gg) + else: + h, cff, cfg = heugcd(ff, gg) + + h = _gcd_interpolate(h, x, ring) + h = h.primitive()[1] + + cff_, r = f.div(h) + + if not r: + cfg_, r = g.div(h) + + if not r: + h = h.mul_ground(gcd) + return h, cff_, cfg_ + + cff = _gcd_interpolate(cff, x, ring) + + h, r = f.div(cff) + + if not r: + cfg_, r = g.div(h) + + if not r: + h = h.mul_ground(gcd) + return h, cff, cfg_ + + cfg = _gcd_interpolate(cfg, x, ring) + + h, r = g.div(cfg) + + if not r: + cff_, r = f.div(h) + + if not r: + h = h.mul_ground(gcd) + return h, cff_, cfg + + x = 73794*x * domain.sqrt(domain.sqrt(x)) // 27011 + + raise HeuristicGCDFailed('no luck') + +def _gcd_interpolate(h, x, ring): + """Interpolate polynomial GCD from integer GCD. """ + f, i = ring.zero, 0 + + # TODO: don't expose poly repr implementation details + if ring.ngens == 1: + while h: + g = h % x + if g > x // 2: g -= x + h = (h - g) // x + + # f += X**i*g + if g: + f[(i,)] = g + i += 1 + else: + while h: + g = h.trunc_ground(x) + h = (h - g).quo_ground(x) + + # f += X**i*g + if g: + for monom, coeff in g.iterterms(): + f[(i,) + monom] = coeff + i += 1 + + if f.LC < 0: + return -f + else: + return f diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/modulargcd.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/modulargcd.py new file mode 100644 index 0000000000000000000000000000000000000000..6f0012316c499cfde85f56c5c37a3475f4175a4e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/modulargcd.py @@ -0,0 +1,2278 @@ +from sympy.core.symbol import Dummy +from sympy.ntheory import nextprime +from sympy.ntheory.modular import crt +from sympy.polys.domains import PolynomialRing +from sympy.polys.galoistools import ( + gf_gcd, gf_from_dict, gf_gcdex, gf_div, gf_lcm) +from sympy.polys.polyerrors import ModularGCDFailed + +from mpmath import sqrt +import random + + +def _trivial_gcd(f, g): + """ + Compute the GCD of two polynomials in trivial cases, i.e. when one + or both polynomials are zero. + """ + ring = f.ring + + if not (f or g): + return ring.zero, ring.zero, ring.zero + elif not f: + if g.LC < ring.domain.zero: + return -g, ring.zero, -ring.one + else: + return g, ring.zero, ring.one + elif not g: + if f.LC < ring.domain.zero: + return -f, -ring.one, ring.zero + else: + return f, ring.one, ring.zero + return None + + +def _gf_gcd(fp, gp, p): + r""" + Compute the GCD of two univariate polynomials in `\mathbb{Z}_p[x]`. + """ + dom = fp.ring.domain + + while gp: + rem = fp + deg = gp.degree() + lcinv = dom.invert(gp.LC, p) + + while True: + degrem = rem.degree() + if degrem < deg: + break + rem = (rem - gp.mul_monom((degrem - deg,)).mul_ground(lcinv * rem.LC)).trunc_ground(p) + + fp = gp + gp = rem + + return fp.mul_ground(dom.invert(fp.LC, p)).trunc_ground(p) + + +def _degree_bound_univariate(f, g): + r""" + Compute an upper bound for the degree of the GCD of two univariate + integer polynomials `f` and `g`. + + The function chooses a suitable prime `p` and computes the GCD of + `f` and `g` in `\mathbb{Z}_p[x]`. The choice of `p` guarantees that + the degree in `\mathbb{Z}_p[x]` is greater than or equal to the degree + in `\mathbb{Z}[x]`. + + Parameters + ========== + + f : PolyElement + univariate integer polynomial + g : PolyElement + univariate integer polynomial + + """ + gamma = f.ring.domain.gcd(f.LC, g.LC) + p = 1 + + p = nextprime(p) + while gamma % p == 0: + p = nextprime(p) + + fp = f.trunc_ground(p) + gp = g.trunc_ground(p) + hp = _gf_gcd(fp, gp, p) + deghp = hp.degree() + return deghp + + +def _chinese_remainder_reconstruction_univariate(hp, hq, p, q): + r""" + Construct a polynomial `h_{pq}` in `\mathbb{Z}_{p q}[x]` such that + + .. math :: + + h_{pq} = h_p \; \mathrm{mod} \, p + + h_{pq} = h_q \; \mathrm{mod} \, q + + for relatively prime integers `p` and `q` and polynomials + `h_p` and `h_q` in `\mathbb{Z}_p[x]` and `\mathbb{Z}_q[x]` + respectively. + + The coefficients of the polynomial `h_{pq}` are computed with the + Chinese Remainder Theorem. The symmetric representation in + `\mathbb{Z}_p[x]`, `\mathbb{Z}_q[x]` and `\mathbb{Z}_{p q}[x]` is used. + It is assumed that `h_p` and `h_q` have the same degree. + + Parameters + ========== + + hp : PolyElement + univariate integer polynomial with coefficients in `\mathbb{Z}_p` + hq : PolyElement + univariate integer polynomial with coefficients in `\mathbb{Z}_q` + p : Integer + modulus of `h_p`, relatively prime to `q` + q : Integer + modulus of `h_q`, relatively prime to `p` + + Examples + ======== + + >>> from sympy.polys.modulargcd import _chinese_remainder_reconstruction_univariate + >>> from sympy.polys import ring, ZZ + + >>> R, x = ring("x", ZZ) + >>> p = 3 + >>> q = 5 + + >>> hp = -x**3 - 1 + >>> hq = 2*x**3 - 2*x**2 + x + + >>> hpq = _chinese_remainder_reconstruction_univariate(hp, hq, p, q) + >>> hpq + 2*x**3 + 3*x**2 + 6*x + 5 + + >>> hpq.trunc_ground(p) == hp + True + >>> hpq.trunc_ground(q) == hq + True + + """ + n = hp.degree() + x = hp.ring.gens[0] + hpq = hp.ring.zero + + for i in range(n+1): + hpq[(i,)] = crt([p, q], [hp.coeff(x**i), hq.coeff(x**i)], symmetric=True)[0] + + hpq.strip_zero() + return hpq + + +def modgcd_univariate(f, g): + r""" + Computes the GCD of two polynomials in `\mathbb{Z}[x]` using a modular + algorithm. + + The algorithm computes the GCD of two univariate integer polynomials + `f` and `g` by computing the GCD in `\mathbb{Z}_p[x]` for suitable + primes `p` and then reconstructing the coefficients with the Chinese + Remainder Theorem. Trial division is only made for candidates which + are very likely the desired GCD. + + Parameters + ========== + + f : PolyElement + univariate integer polynomial + g : PolyElement + univariate integer polynomial + + Returns + ======= + + h : PolyElement + GCD of the polynomials `f` and `g` + cff : PolyElement + cofactor of `f`, i.e. `\frac{f}{h}` + cfg : PolyElement + cofactor of `g`, i.e. `\frac{g}{h}` + + Examples + ======== + + >>> from sympy.polys.modulargcd import modgcd_univariate + >>> from sympy.polys import ring, ZZ + + >>> R, x = ring("x", ZZ) + + >>> f = x**5 - 1 + >>> g = x - 1 + + >>> h, cff, cfg = modgcd_univariate(f, g) + >>> h, cff, cfg + (x - 1, x**4 + x**3 + x**2 + x + 1, 1) + + >>> cff * h == f + True + >>> cfg * h == g + True + + >>> f = 6*x**2 - 6 + >>> g = 2*x**2 + 4*x + 2 + + >>> h, cff, cfg = modgcd_univariate(f, g) + >>> h, cff, cfg + (2*x + 2, 3*x - 3, x + 1) + + >>> cff * h == f + True + >>> cfg * h == g + True + + References + ========== + + 1. [Monagan00]_ + + """ + assert f.ring == g.ring and f.ring.domain.is_ZZ + + result = _trivial_gcd(f, g) + if result is not None: + return result + + ring = f.ring + + cf, f = f.primitive() + cg, g = g.primitive() + ch = ring.domain.gcd(cf, cg) + + bound = _degree_bound_univariate(f, g) + if bound == 0: + return ring(ch), f.mul_ground(cf // ch), g.mul_ground(cg // ch) + + gamma = ring.domain.gcd(f.LC, g.LC) + m = 1 + p = 1 + + while True: + p = nextprime(p) + while gamma % p == 0: + p = nextprime(p) + + fp = f.trunc_ground(p) + gp = g.trunc_ground(p) + hp = _gf_gcd(fp, gp, p) + deghp = hp.degree() + + if deghp > bound: + continue + elif deghp < bound: + m = 1 + bound = deghp + continue + + hp = hp.mul_ground(gamma).trunc_ground(p) + if m == 1: + m = p + hlastm = hp + continue + + hm = _chinese_remainder_reconstruction_univariate(hp, hlastm, p, m) + m *= p + + if not hm == hlastm: + hlastm = hm + continue + + h = hm.quo_ground(hm.content()) + fquo, frem = f.div(h) + gquo, grem = g.div(h) + if not frem and not grem: + if h.LC < 0: + ch = -ch + h = h.mul_ground(ch) + cff = fquo.mul_ground(cf // ch) + cfg = gquo.mul_ground(cg // ch) + return h, cff, cfg + + +def _primitive(f, p): + r""" + Compute the content and the primitive part of a polynomial in + `\mathbb{Z}_p[x_0, \ldots, x_{k-2}, y] \cong \mathbb{Z}_p[y][x_0, \ldots, x_{k-2}]`. + + Parameters + ========== + + f : PolyElement + integer polynomial in `\mathbb{Z}_p[x0, \ldots, x{k-2}, y]` + p : Integer + modulus of `f` + + Returns + ======= + + contf : PolyElement + integer polynomial in `\mathbb{Z}_p[y]`, content of `f` + ppf : PolyElement + primitive part of `f`, i.e. `\frac{f}{contf}` + + Examples + ======== + + >>> from sympy.polys.modulargcd import _primitive + >>> from sympy.polys import ring, ZZ + + >>> R, x, y = ring("x, y", ZZ) + >>> p = 3 + + >>> f = x**2*y**2 + x**2*y - y**2 - y + >>> _primitive(f, p) + (y**2 + y, x**2 - 1) + + >>> R, x, y, z = ring("x, y, z", ZZ) + + >>> f = x*y*z - y**2*z**2 + >>> _primitive(f, p) + (z, x*y - y**2*z) + + """ + ring = f.ring + dom = ring.domain + k = ring.ngens + + coeffs = {} + for monom, coeff in f.iterterms(): + if monom[:-1] not in coeffs: + coeffs[monom[:-1]] = {} + coeffs[monom[:-1]][monom[-1]] = coeff + + cont = [] + for coeff in iter(coeffs.values()): + cont = gf_gcd(cont, gf_from_dict(coeff, p, dom), p, dom) + + yring = ring.clone(symbols=ring.symbols[k-1]) + contf = yring.from_dense(cont).trunc_ground(p) + + return contf, f.quo(contf.set_ring(ring)) + + +def _deg(f): + r""" + Compute the degree of a multivariate polynomial + `f \in K[x_0, \ldots, x_{k-2}, y] \cong K[y][x_0, \ldots, x_{k-2}]`. + + Parameters + ========== + + f : PolyElement + polynomial in `K[x_0, \ldots, x_{k-2}, y]` + + Returns + ======= + + degf : Integer tuple + degree of `f` in `x_0, \ldots, x_{k-2}` + + Examples + ======== + + >>> from sympy.polys.modulargcd import _deg + >>> from sympy.polys import ring, ZZ + + >>> R, x, y = ring("x, y", ZZ) + + >>> f = x**2*y**2 + x**2*y - 1 + >>> _deg(f) + (2,) + + >>> R, x, y, z = ring("x, y, z", ZZ) + + >>> f = x**2*y**2 + x**2*y - 1 + >>> _deg(f) + (2, 2) + + >>> f = x*y*z - y**2*z**2 + >>> _deg(f) + (1, 1) + + """ + k = f.ring.ngens + degf = (0,) * (k-1) + for monom in f.itermonoms(): + if monom[:-1] > degf: + degf = monom[:-1] + return degf + + +def _LC(f): + r""" + Compute the leading coefficient of a multivariate polynomial + `f \in K[x_0, \ldots, x_{k-2}, y] \cong K[y][x_0, \ldots, x_{k-2}]`. + + Parameters + ========== + + f : PolyElement + polynomial in `K[x_0, \ldots, x_{k-2}, y]` + + Returns + ======= + + lcf : PolyElement + polynomial in `K[y]`, leading coefficient of `f` + + Examples + ======== + + >>> from sympy.polys.modulargcd import _LC + >>> from sympy.polys import ring, ZZ + + >>> R, x, y = ring("x, y", ZZ) + + >>> f = x**2*y**2 + x**2*y - 1 + >>> _LC(f) + y**2 + y + + >>> R, x, y, z = ring("x, y, z", ZZ) + + >>> f = x**2*y**2 + x**2*y - 1 + >>> _LC(f) + 1 + + >>> f = x*y*z - y**2*z**2 + >>> _LC(f) + z + + """ + ring = f.ring + k = ring.ngens + yring = ring.clone(symbols=ring.symbols[k-1]) + y = yring.gens[0] + degf = _deg(f) + + lcf = yring.zero + for monom, coeff in f.iterterms(): + if monom[:-1] == degf: + lcf += coeff*y**monom[-1] + return lcf + + +def _swap(f, i): + """ + Make the variable `x_i` the leading one in a multivariate polynomial `f`. + """ + ring = f.ring + fswap = ring.zero + for monom, coeff in f.iterterms(): + monomswap = (monom[i],) + monom[:i] + monom[i+1:] + fswap[monomswap] = coeff + return fswap + + +def _degree_bound_bivariate(f, g): + r""" + Compute upper degree bounds for the GCD of two bivariate + integer polynomials `f` and `g`. + + The GCD is viewed as a polynomial in `\mathbb{Z}[y][x]` and the + function returns an upper bound for its degree and one for the degree + of its content. This is done by choosing a suitable prime `p` and + computing the GCD of the contents of `f \; \mathrm{mod} \, p` and + `g \; \mathrm{mod} \, p`. The choice of `p` guarantees that the degree + of the content in `\mathbb{Z}_p[y]` is greater than or equal to the + degree in `\mathbb{Z}[y]`. To obtain the degree bound in the variable + `x`, the polynomials are evaluated at `y = a` for a suitable + `a \in \mathbb{Z}_p` and then their GCD in `\mathbb{Z}_p[x]` is + computed. If no such `a` exists, i.e. the degree in `\mathbb{Z}_p[x]` + is always smaller than the one in `\mathbb{Z}[y][x]`, then the bound is + set to the minimum of the degrees of `f` and `g` in `x`. + + Parameters + ========== + + f : PolyElement + bivariate integer polynomial + g : PolyElement + bivariate integer polynomial + + Returns + ======= + + xbound : Integer + upper bound for the degree of the GCD of the polynomials `f` and + `g` in the variable `x` + ycontbound : Integer + upper bound for the degree of the content of the GCD of the + polynomials `f` and `g` in the variable `y` + + References + ========== + + 1. [Monagan00]_ + + """ + ring = f.ring + + gamma1 = ring.domain.gcd(f.LC, g.LC) + gamma2 = ring.domain.gcd(_swap(f, 1).LC, _swap(g, 1).LC) + badprimes = gamma1 * gamma2 + p = 1 + + p = nextprime(p) + while badprimes % p == 0: + p = nextprime(p) + + fp = f.trunc_ground(p) + gp = g.trunc_ground(p) + contfp, fp = _primitive(fp, p) + contgp, gp = _primitive(gp, p) + conthp = _gf_gcd(contfp, contgp, p) # polynomial in Z_p[y] + ycontbound = conthp.degree() + + # polynomial in Z_p[y] + delta = _gf_gcd(_LC(fp), _LC(gp), p) + + for a in range(p): + if not delta.evaluate(0, a) % p: + continue + fpa = fp.evaluate(1, a).trunc_ground(p) + gpa = gp.evaluate(1, a).trunc_ground(p) + hpa = _gf_gcd(fpa, gpa, p) + xbound = hpa.degree() + return xbound, ycontbound + + return min(fp.degree(), gp.degree()), ycontbound + + +def _chinese_remainder_reconstruction_multivariate(hp, hq, p, q): + r""" + Construct a polynomial `h_{pq}` in + `\mathbb{Z}_{p q}[x_0, \ldots, x_{k-1}]` such that + + .. math :: + + h_{pq} = h_p \; \mathrm{mod} \, p + + h_{pq} = h_q \; \mathrm{mod} \, q + + for relatively prime integers `p` and `q` and polynomials + `h_p` and `h_q` in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` and + `\mathbb{Z}_q[x_0, \ldots, x_{k-1}]` respectively. + + The coefficients of the polynomial `h_{pq}` are computed with the + Chinese Remainder Theorem. The symmetric representation in + `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`, + `\mathbb{Z}_q[x_0, \ldots, x_{k-1}]` and + `\mathbb{Z}_{p q}[x_0, \ldots, x_{k-1}]` is used. + + Parameters + ========== + + hp : PolyElement + multivariate integer polynomial with coefficients in `\mathbb{Z}_p` + hq : PolyElement + multivariate integer polynomial with coefficients in `\mathbb{Z}_q` + p : Integer + modulus of `h_p`, relatively prime to `q` + q : Integer + modulus of `h_q`, relatively prime to `p` + + Examples + ======== + + >>> from sympy.polys.modulargcd import _chinese_remainder_reconstruction_multivariate + >>> from sympy.polys import ring, ZZ + + >>> R, x, y = ring("x, y", ZZ) + >>> p = 3 + >>> q = 5 + + >>> hp = x**3*y - x**2 - 1 + >>> hq = -x**3*y - 2*x*y**2 + 2 + + >>> hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q) + >>> hpq + 4*x**3*y + 5*x**2 + 3*x*y**2 + 2 + + >>> hpq.trunc_ground(p) == hp + True + >>> hpq.trunc_ground(q) == hq + True + + >>> R, x, y, z = ring("x, y, z", ZZ) + >>> p = 6 + >>> q = 5 + + >>> hp = 3*x**4 - y**3*z + z + >>> hq = -2*x**4 + z + + >>> hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q) + >>> hpq + 3*x**4 + 5*y**3*z + z + + >>> hpq.trunc_ground(p) == hp + True + >>> hpq.trunc_ground(q) == hq + True + + """ + hpmonoms = set(hp.monoms()) + hqmonoms = set(hq.monoms()) + monoms = hpmonoms.intersection(hqmonoms) + hpmonoms.difference_update(monoms) + hqmonoms.difference_update(monoms) + + domain = hp.ring.domain + zero = domain.zero + + hpq = hp.ring.zero + + if isinstance(hp.ring.domain, PolynomialRing): + crt_ = _chinese_remainder_reconstruction_multivariate + else: + def crt_(cp, cq, p, q): + return domain(crt([p, q], [cp, cq], symmetric=True)[0]) + + for monom in monoms: + hpq[monom] = crt_(hp[monom], hq[monom], p, q) + for monom in hpmonoms: + hpq[monom] = crt_(hp[monom], zero, p, q) + for monom in hqmonoms: + hpq[monom] = crt_(zero, hq[monom], p, q) + + return hpq + + +def _interpolate_multivariate(evalpoints, hpeval, ring, i, p, ground=False): + r""" + Reconstruct a polynomial `h_p` in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` + from a list of evaluation points in `\mathbb{Z}_p` and a list of + polynomials in + `\mathbb{Z}_p[x_0, \ldots, x_{i-1}, x_{i+1}, \ldots, x_{k-1}]`, which + are the images of `h_p` evaluated in the variable `x_i`. + + It is also possible to reconstruct a parameter of the ground domain, + i.e. if `h_p` is a polynomial over `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`. + In this case, one has to set ``ground=True``. + + Parameters + ========== + + evalpoints : list of Integer objects + list of evaluation points in `\mathbb{Z}_p` + hpeval : list of PolyElement objects + list of polynomials in (resp. over) + `\mathbb{Z}_p[x_0, \ldots, x_{i-1}, x_{i+1}, \ldots, x_{k-1}]`, + images of `h_p` evaluated in the variable `x_i` + ring : PolyRing + `h_p` will be an element of this ring + i : Integer + index of the variable which has to be reconstructed + p : Integer + prime number, modulus of `h_p` + ground : Boolean + indicates whether `x_i` is in the ground domain, default is + ``False`` + + Returns + ======= + + hp : PolyElement + interpolated polynomial in (resp. over) + `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` + + """ + hp = ring.zero + + if ground: + domain = ring.domain.domain + y = ring.domain.gens[i] + else: + domain = ring.domain + y = ring.gens[i] + + for a, hpa in zip(evalpoints, hpeval): + numer = ring.one + denom = domain.one + for b in evalpoints: + if b == a: + continue + + numer *= y - b + denom *= a - b + + denom = domain.invert(denom, p) + coeff = numer.mul_ground(denom) + hp += hpa.set_ring(ring) * coeff + + return hp.trunc_ground(p) + + +def modgcd_bivariate(f, g): + r""" + Computes the GCD of two polynomials in `\mathbb{Z}[x, y]` using a + modular algorithm. + + The algorithm computes the GCD of two bivariate integer polynomials + `f` and `g` by calculating the GCD in `\mathbb{Z}_p[x, y]` for + suitable primes `p` and then reconstructing the coefficients with the + Chinese Remainder Theorem. To compute the bivariate GCD over + `\mathbb{Z}_p`, the polynomials `f \; \mathrm{mod} \, p` and + `g \; \mathrm{mod} \, p` are evaluated at `y = a` for certain + `a \in \mathbb{Z}_p` and then their univariate GCD in `\mathbb{Z}_p[x]` + is computed. Interpolating those yields the bivariate GCD in + `\mathbb{Z}_p[x, y]`. To verify the result in `\mathbb{Z}[x, y]`, trial + division is done, but only for candidates which are very likely the + desired GCD. + + Parameters + ========== + + f : PolyElement + bivariate integer polynomial + g : PolyElement + bivariate integer polynomial + + Returns + ======= + + h : PolyElement + GCD of the polynomials `f` and `g` + cff : PolyElement + cofactor of `f`, i.e. `\frac{f}{h}` + cfg : PolyElement + cofactor of `g`, i.e. `\frac{g}{h}` + + Examples + ======== + + >>> from sympy.polys.modulargcd import modgcd_bivariate + >>> from sympy.polys import ring, ZZ + + >>> R, x, y = ring("x, y", ZZ) + + >>> f = x**2 - y**2 + >>> g = x**2 + 2*x*y + y**2 + + >>> h, cff, cfg = modgcd_bivariate(f, g) + >>> h, cff, cfg + (x + y, x - y, x + y) + + >>> cff * h == f + True + >>> cfg * h == g + True + + >>> f = x**2*y - x**2 - 4*y + 4 + >>> g = x + 2 + + >>> h, cff, cfg = modgcd_bivariate(f, g) + >>> h, cff, cfg + (x + 2, x*y - x - 2*y + 2, 1) + + >>> cff * h == f + True + >>> cfg * h == g + True + + References + ========== + + 1. [Monagan00]_ + + """ + assert f.ring == g.ring and f.ring.domain.is_ZZ + + result = _trivial_gcd(f, g) + if result is not None: + return result + + ring = f.ring + + cf, f = f.primitive() + cg, g = g.primitive() + ch = ring.domain.gcd(cf, cg) + + xbound, ycontbound = _degree_bound_bivariate(f, g) + if xbound == ycontbound == 0: + return ring(ch), f.mul_ground(cf // ch), g.mul_ground(cg // ch) + + fswap = _swap(f, 1) + gswap = _swap(g, 1) + degyf = fswap.degree() + degyg = gswap.degree() + + ybound, xcontbound = _degree_bound_bivariate(fswap, gswap) + if ybound == xcontbound == 0: + return ring(ch), f.mul_ground(cf // ch), g.mul_ground(cg // ch) + + # TODO: to improve performance, choose the main variable here + + gamma1 = ring.domain.gcd(f.LC, g.LC) + gamma2 = ring.domain.gcd(fswap.LC, gswap.LC) + badprimes = gamma1 * gamma2 + m = 1 + p = 1 + + while True: + p = nextprime(p) + while badprimes % p == 0: + p = nextprime(p) + + fp = f.trunc_ground(p) + gp = g.trunc_ground(p) + contfp, fp = _primitive(fp, p) + contgp, gp = _primitive(gp, p) + conthp = _gf_gcd(contfp, contgp, p) # monic polynomial in Z_p[y] + degconthp = conthp.degree() + + if degconthp > ycontbound: + continue + elif degconthp < ycontbound: + m = 1 + ycontbound = degconthp + continue + + # polynomial in Z_p[y] + delta = _gf_gcd(_LC(fp), _LC(gp), p) + + degcontfp = contfp.degree() + degcontgp = contgp.degree() + degdelta = delta.degree() + + N = min(degyf - degcontfp, degyg - degcontgp, + ybound - ycontbound + degdelta) + 1 + + if p < N: + continue + + n = 0 + evalpoints = [] + hpeval = [] + unlucky = False + + for a in range(p): + deltaa = delta.evaluate(0, a) + if not deltaa % p: + continue + + fpa = fp.evaluate(1, a).trunc_ground(p) + gpa = gp.evaluate(1, a).trunc_ground(p) + hpa = _gf_gcd(fpa, gpa, p) # monic polynomial in Z_p[x] + deghpa = hpa.degree() + + if deghpa > xbound: + continue + elif deghpa < xbound: + m = 1 + xbound = deghpa + unlucky = True + break + + hpa = hpa.mul_ground(deltaa).trunc_ground(p) + evalpoints.append(a) + hpeval.append(hpa) + n += 1 + + if n == N: + break + + if unlucky: + continue + if n < N: + continue + + hp = _interpolate_multivariate(evalpoints, hpeval, ring, 1, p) + + hp = _primitive(hp, p)[1] + hp = hp * conthp.set_ring(ring) + degyhp = hp.degree(1) + + if degyhp > ybound: + continue + if degyhp < ybound: + m = 1 + ybound = degyhp + continue + + hp = hp.mul_ground(gamma1).trunc_ground(p) + if m == 1: + m = p + hlastm = hp + continue + + hm = _chinese_remainder_reconstruction_multivariate(hp, hlastm, p, m) + m *= p + + if not hm == hlastm: + hlastm = hm + continue + + h = hm.quo_ground(hm.content()) + fquo, frem = f.div(h) + gquo, grem = g.div(h) + if not frem and not grem: + if h.LC < 0: + ch = -ch + h = h.mul_ground(ch) + cff = fquo.mul_ground(cf // ch) + cfg = gquo.mul_ground(cg // ch) + return h, cff, cfg + + +def _modgcd_multivariate_p(f, g, p, degbound, contbound): + r""" + Compute the GCD of two polynomials in + `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`. + + The algorithm reduces the problem step by step by evaluating the + polynomials `f` and `g` at `x_{k-1} = a` for suitable + `a \in \mathbb{Z}_p` and then calls itself recursively to compute the GCD + in `\mathbb{Z}_p[x_0, \ldots, x_{k-2}]`. If these recursive calls are + successful for enough evaluation points, the GCD in `k` variables is + interpolated, otherwise the algorithm returns ``None``. Every time a GCD + or a content is computed, their degrees are compared with the bounds. If + a degree greater then the bound is encountered, then the current call + returns ``None`` and a new evaluation point has to be chosen. If at some + point the degree is smaller, the correspondent bound is updated and the + algorithm fails. + + Parameters + ========== + + f : PolyElement + multivariate integer polynomial with coefficients in `\mathbb{Z}_p` + g : PolyElement + multivariate integer polynomial with coefficients in `\mathbb{Z}_p` + p : Integer + prime number, modulus of `f` and `g` + degbound : list of Integer objects + ``degbound[i]`` is an upper bound for the degree of the GCD of `f` + and `g` in the variable `x_i` + contbound : list of Integer objects + ``contbound[i]`` is an upper bound for the degree of the content of + the GCD in `\mathbb{Z}_p[x_i][x_0, \ldots, x_{i-1}]`, + ``contbound[0]`` is not used can therefore be chosen + arbitrarily. + + Returns + ======= + + h : PolyElement + GCD of the polynomials `f` and `g` or ``None`` + + References + ========== + + 1. [Monagan00]_ + 2. [Brown71]_ + + """ + ring = f.ring + k = ring.ngens + + if k == 1: + h = _gf_gcd(f, g, p).trunc_ground(p) + degh = h.degree() + + if degh > degbound[0]: + return None + if degh < degbound[0]: + degbound[0] = degh + raise ModularGCDFailed + + return h + + degyf = f.degree(k-1) + degyg = g.degree(k-1) + + contf, f = _primitive(f, p) + contg, g = _primitive(g, p) + + conth = _gf_gcd(contf, contg, p) # polynomial in Z_p[y] + + degcontf = contf.degree() + degcontg = contg.degree() + degconth = conth.degree() + + if degconth > contbound[k-1]: + return None + if degconth < contbound[k-1]: + contbound[k-1] = degconth + raise ModularGCDFailed + + lcf = _LC(f) + lcg = _LC(g) + + delta = _gf_gcd(lcf, lcg, p) # polynomial in Z_p[y] + + evaltest = delta + + for i in range(k-1): + evaltest *= _gf_gcd(_LC(_swap(f, i)), _LC(_swap(g, i)), p) + + degdelta = delta.degree() + + N = min(degyf - degcontf, degyg - degcontg, + degbound[k-1] - contbound[k-1] + degdelta) + 1 + + if p < N: + return None + + n = 0 + d = 0 + evalpoints = [] + heval = [] + points = list(range(p)) + + while points: + a = random.sample(points, 1)[0] + points.remove(a) + + if not evaltest.evaluate(0, a) % p: + continue + + deltaa = delta.evaluate(0, a) % p + + fa = f.evaluate(k-1, a).trunc_ground(p) + ga = g.evaluate(k-1, a).trunc_ground(p) + + # polynomials in Z_p[x_0, ..., x_{k-2}] + ha = _modgcd_multivariate_p(fa, ga, p, degbound, contbound) + + if ha is None: + d += 1 + if d > n: + return None + continue + + if ha.is_ground: + h = conth.set_ring(ring).trunc_ground(p) + return h + + ha = ha.mul_ground(deltaa).trunc_ground(p) + + evalpoints.append(a) + heval.append(ha) + n += 1 + + if n == N: + h = _interpolate_multivariate(evalpoints, heval, ring, k-1, p) + + h = _primitive(h, p)[1] * conth.set_ring(ring) + degyh = h.degree(k-1) + + if degyh > degbound[k-1]: + return None + if degyh < degbound[k-1]: + degbound[k-1] = degyh + raise ModularGCDFailed + + return h + + return None + + +def modgcd_multivariate(f, g): + r""" + Compute the GCD of two polynomials in `\mathbb{Z}[x_0, \ldots, x_{k-1}]` + using a modular algorithm. + + The algorithm computes the GCD of two multivariate integer polynomials + `f` and `g` by calculating the GCD in + `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` for suitable primes `p` and then + reconstructing the coefficients with the Chinese Remainder Theorem. To + compute the multivariate GCD over `\mathbb{Z}_p` the recursive + subroutine :func:`_modgcd_multivariate_p` is used. To verify the result in + `\mathbb{Z}[x_0, \ldots, x_{k-1}]`, trial division is done, but only for + candidates which are very likely the desired GCD. + + Parameters + ========== + + f : PolyElement + multivariate integer polynomial + g : PolyElement + multivariate integer polynomial + + Returns + ======= + + h : PolyElement + GCD of the polynomials `f` and `g` + cff : PolyElement + cofactor of `f`, i.e. `\frac{f}{h}` + cfg : PolyElement + cofactor of `g`, i.e. `\frac{g}{h}` + + Examples + ======== + + >>> from sympy.polys.modulargcd import modgcd_multivariate + >>> from sympy.polys import ring, ZZ + + >>> R, x, y = ring("x, y", ZZ) + + >>> f = x**2 - y**2 + >>> g = x**2 + 2*x*y + y**2 + + >>> h, cff, cfg = modgcd_multivariate(f, g) + >>> h, cff, cfg + (x + y, x - y, x + y) + + >>> cff * h == f + True + >>> cfg * h == g + True + + >>> R, x, y, z = ring("x, y, z", ZZ) + + >>> f = x*z**2 - y*z**2 + >>> g = x**2*z + z + + >>> h, cff, cfg = modgcd_multivariate(f, g) + >>> h, cff, cfg + (z, x*z - y*z, x**2 + 1) + + >>> cff * h == f + True + >>> cfg * h == g + True + + References + ========== + + 1. [Monagan00]_ + 2. [Brown71]_ + + See also + ======== + + _modgcd_multivariate_p + + """ + assert f.ring == g.ring and f.ring.domain.is_ZZ + + result = _trivial_gcd(f, g) + if result is not None: + return result + + ring = f.ring + k = ring.ngens + + # divide out integer content + cf, f = f.primitive() + cg, g = g.primitive() + ch = ring.domain.gcd(cf, cg) + + gamma = ring.domain.gcd(f.LC, g.LC) + + badprimes = ring.domain.one + for i in range(k): + badprimes *= ring.domain.gcd(_swap(f, i).LC, _swap(g, i).LC) + + degbound = [min(fdeg, gdeg) for fdeg, gdeg in zip(f.degrees(), g.degrees())] + contbound = list(degbound) + + m = 1 + p = 1 + + while True: + p = nextprime(p) + while badprimes % p == 0: + p = nextprime(p) + + fp = f.trunc_ground(p) + gp = g.trunc_ground(p) + + try: + # monic GCD of fp, gp in Z_p[x_0, ..., x_{k-2}, y] + hp = _modgcd_multivariate_p(fp, gp, p, degbound, contbound) + except ModularGCDFailed: + m = 1 + continue + + if hp is None: + continue + + hp = hp.mul_ground(gamma).trunc_ground(p) + if m == 1: + m = p + hlastm = hp + continue + + hm = _chinese_remainder_reconstruction_multivariate(hp, hlastm, p, m) + m *= p + + if not hm == hlastm: + hlastm = hm + continue + + h = hm.primitive()[1] + fquo, frem = f.div(h) + gquo, grem = g.div(h) + if not frem and not grem: + if h.LC < 0: + ch = -ch + h = h.mul_ground(ch) + cff = fquo.mul_ground(cf // ch) + cfg = gquo.mul_ground(cg // ch) + return h, cff, cfg + + +def _gf_div(f, g, p): + r""" + Compute `\frac f g` modulo `p` for two univariate polynomials over + `\mathbb Z_p`. + """ + ring = f.ring + densequo, denserem = gf_div(f.to_dense(), g.to_dense(), p, ring.domain) + return ring.from_dense(densequo), ring.from_dense(denserem) + + +def _rational_function_reconstruction(c, p, m): + r""" + Reconstruct a rational function `\frac a b` in `\mathbb Z_p(t)` from + + .. math:: + + c = \frac a b \; \mathrm{mod} \, m, + + where `c` and `m` are polynomials in `\mathbb Z_p[t]` and `m` has + positive degree. + + The algorithm is based on the Euclidean Algorithm. In general, `m` is + not irreducible, so it is possible that `b` is not invertible modulo + `m`. In that case ``None`` is returned. + + Parameters + ========== + + c : PolyElement + univariate polynomial in `\mathbb Z[t]` + p : Integer + prime number + m : PolyElement + modulus, not necessarily irreducible + + Returns + ======= + + frac : FracElement + either `\frac a b` in `\mathbb Z(t)` or ``None`` + + References + ========== + + 1. [Hoeij04]_ + + """ + ring = c.ring + domain = ring.domain + M = m.degree() + N = M // 2 + D = M - N - 1 + + r0, s0 = m, ring.zero + r1, s1 = c, ring.one + + while r1.degree() > N: + quo = _gf_div(r0, r1, p)[0] + r0, r1 = r1, (r0 - quo*r1).trunc_ground(p) + s0, s1 = s1, (s0 - quo*s1).trunc_ground(p) + + a, b = r1, s1 + if b.degree() > D or _gf_gcd(b, m, p) != 1: + return None + + lc = b.LC + if lc != 1: + lcinv = domain.invert(lc, p) + a = a.mul_ground(lcinv).trunc_ground(p) + b = b.mul_ground(lcinv).trunc_ground(p) + + field = ring.to_field() + + return field(a) / field(b) + + +def _rational_reconstruction_func_coeffs(hm, p, m, ring, k): + r""" + Reconstruct every coefficient `c_h` of a polynomial `h` in + `\mathbb Z_p(t_k)[t_1, \ldots, t_{k-1}][x, z]` from the corresponding + coefficient `c_{h_m}` of a polynomial `h_m` in + `\mathbb Z_p[t_1, \ldots, t_k][x, z] \cong \mathbb Z_p[t_k][t_1, \ldots, t_{k-1}][x, z]` + such that + + .. math:: + + c_{h_m} = c_h \; \mathrm{mod} \, m, + + where `m \in \mathbb Z_p[t]`. + + The reconstruction is based on the Euclidean Algorithm. In general, `m` + is not irreducible, so it is possible that this fails for some + coefficient. In that case ``None`` is returned. + + Parameters + ========== + + hm : PolyElement + polynomial in `\mathbb Z[t_1, \ldots, t_k][x, z]` + p : Integer + prime number, modulus of `\mathbb Z_p` + m : PolyElement + modulus, polynomial in `\mathbb Z[t]`, not necessarily irreducible + ring : PolyRing + `\mathbb Z(t_k)[t_1, \ldots, t_{k-1}][x, z]`, `h` will be an + element of this ring + k : Integer + index of the parameter `t_k` which will be reconstructed + + Returns + ======= + + h : PolyElement + reconstructed polynomial in + `\mathbb Z(t_k)[t_1, \ldots, t_{k-1}][x, z]` or ``None`` + + See also + ======== + + _rational_function_reconstruction + + """ + h = ring.zero + + for monom, coeff in hm.iterterms(): + if k == 0: + coeffh = _rational_function_reconstruction(coeff, p, m) + + if not coeffh: + return None + + else: + coeffh = ring.domain.zero + for mon, c in coeff.drop_to_ground(k).iterterms(): + ch = _rational_function_reconstruction(c, p, m) + + if not ch: + return None + + coeffh[mon] = ch + + h[monom] = coeffh + + return h + + +def _gf_gcdex(f, g, p): + r""" + Extended Euclidean Algorithm for two univariate polynomials over + `\mathbb Z_p`. + + Returns polynomials `s, t` and `h`, such that `h` is the GCD of `f` and + `g` and `sf + tg = h \; \mathrm{mod} \, p`. + + """ + ring = f.ring + s, t, h = gf_gcdex(f.to_dense(), g.to_dense(), p, ring.domain) + return ring.from_dense(s), ring.from_dense(t), ring.from_dense(h) + + +def _trunc(f, minpoly, p): + r""" + Compute the reduced representation of a polynomial `f` in + `\mathbb Z_p[z] / (\check m_{\alpha}(z))[x]` + + Parameters + ========== + + f : PolyElement + polynomial in `\mathbb Z[x, z]` + minpoly : PolyElement + polynomial `\check m_{\alpha} \in \mathbb Z[z]`, not necessarily + irreducible + p : Integer + prime number, modulus of `\mathbb Z_p` + + Returns + ======= + + ftrunc : PolyElement + polynomial in `\mathbb Z[x, z]`, reduced modulo + `\check m_{\alpha}(z)` and `p` + + """ + ring = f.ring + minpoly = minpoly.set_ring(ring) + p_ = ring.ground_new(p) + + return f.trunc_ground(p).rem([minpoly, p_]).trunc_ground(p) + + +def _euclidean_algorithm(f, g, minpoly, p): + r""" + Compute the monic GCD of two univariate polynomials in + `\mathbb{Z}_p[z]/(\check m_{\alpha}(z))[x]` with the Euclidean + Algorithm. + + In general, `\check m_{\alpha}(z)` is not irreducible, so it is possible + that some leading coefficient is not invertible modulo + `\check m_{\alpha}(z)`. In that case ``None`` is returned. + + Parameters + ========== + + f, g : PolyElement + polynomials in `\mathbb Z[x, z]` + minpoly : PolyElement + polynomial in `\mathbb Z[z]`, not necessarily irreducible + p : Integer + prime number, modulus of `\mathbb Z_p` + + Returns + ======= + + h : PolyElement + GCD of `f` and `g` in `\mathbb Z[z, x]` or ``None``, coefficients + are in `\left[ -\frac{p-1} 2, \frac{p-1} 2 \right]` + + """ + ring = f.ring + + f = _trunc(f, minpoly, p) + g = _trunc(g, minpoly, p) + + while g: + rem = f + deg = g.degree(0) # degree in x + lcinv, _, gcd = _gf_gcdex(ring.dmp_LC(g), minpoly, p) + + if not gcd == 1: + return None + + while True: + degrem = rem.degree(0) # degree in x + if degrem < deg: + break + quo = (lcinv * ring.dmp_LC(rem)).set_ring(ring) + rem = _trunc(rem - g.mul_monom((degrem - deg, 0))*quo, minpoly, p) + + f = g + g = rem + + lcfinv = _gf_gcdex(ring.dmp_LC(f), minpoly, p)[0].set_ring(ring) + + return _trunc(f * lcfinv, minpoly, p) + + +def _trial_division(f, h, minpoly, p=None): + r""" + Check if `h` divides `f` in + `\mathbb K[t_1, \ldots, t_k][z]/(m_{\alpha}(z))`, where `\mathbb K` is + either `\mathbb Q` or `\mathbb Z_p`. + + This algorithm is based on pseudo division and does not use any + fractions. By default `\mathbb K` is `\mathbb Q`, if a prime number `p` + is given, `\mathbb Z_p` is chosen instead. + + Parameters + ========== + + f, h : PolyElement + polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]` + minpoly : PolyElement + polynomial `m_{\alpha}(z)` in `\mathbb Z[t_1, \ldots, t_k][z]` + p : Integer or None + if `p` is given, `\mathbb K` is set to `\mathbb Z_p` instead of + `\mathbb Q`, default is ``None`` + + Returns + ======= + + rem : PolyElement + remainder of `\frac f h` + + References + ========== + + .. [1] [Hoeij02]_ + + """ + ring = f.ring + + zxring = ring.clone(symbols=(ring.symbols[1], ring.symbols[0])) + + minpoly = minpoly.set_ring(ring) + + rem = f + + degrem = rem.degree() + degh = h.degree() + degm = minpoly.degree(1) + + lch = _LC(h).set_ring(ring) + lcm = minpoly.LC + + while rem and degrem >= degh: + # polynomial in Z[t_1, ..., t_k][z] + lcrem = _LC(rem).set_ring(ring) + rem = rem*lch - h.mul_monom((degrem - degh, 0))*lcrem + if p: + rem = rem.trunc_ground(p) + degrem = rem.degree(1) + + while rem and degrem >= degm: + # polynomial in Z[t_1, ..., t_k][x] + lcrem = _LC(rem.set_ring(zxring)).set_ring(ring) + rem = rem.mul_ground(lcm) - minpoly.mul_monom((0, degrem - degm))*lcrem + if p: + rem = rem.trunc_ground(p) + degrem = rem.degree(1) + + degrem = rem.degree() + + return rem + + +def _evaluate_ground(f, i, a): + r""" + Evaluate a polynomial `f` at `a` in the `i`-th variable of the ground + domain. + """ + ring = f.ring.clone(domain=f.ring.domain.ring.drop(i)) + fa = ring.zero + + for monom, coeff in f.iterterms(): + fa[monom] = coeff.evaluate(i, a) + + return fa + + +def _func_field_modgcd_p(f, g, minpoly, p): + r""" + Compute the GCD of two polynomials `f` and `g` in + `\mathbb Z_p(t_1, \ldots, t_k)[z]/(\check m_\alpha(z))[x]`. + + The algorithm reduces the problem step by step by evaluating the + polynomials `f` and `g` at `t_k = a` for suitable `a \in \mathbb Z_p` + and then calls itself recursively to compute the GCD in + `\mathbb Z_p(t_1, \ldots, t_{k-1})[z]/(\check m_\alpha(z))[x]`. If these + recursive calls are successful, the GCD over `k` variables is + interpolated, otherwise the algorithm returns ``None``. After + interpolation, Rational Function Reconstruction is used to obtain the + correct coefficients. If this fails, a new evaluation point has to be + chosen, otherwise the desired polynomial is obtained by clearing + denominators. The result is verified with a fraction free trial + division. + + Parameters + ========== + + f, g : PolyElement + polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]` + minpoly : PolyElement + polynomial in `\mathbb Z[t_1, \ldots, t_k][z]`, not necessarily + irreducible + p : Integer + prime number, modulus of `\mathbb Z_p` + + Returns + ======= + + h : PolyElement + primitive associate in `\mathbb Z[t_1, \ldots, t_k][x, z]` of the + GCD of the polynomials `f` and `g` or ``None``, coefficients are + in `\left[ -\frac{p-1} 2, \frac{p-1} 2 \right]` + + References + ========== + + 1. [Hoeij04]_ + + """ + ring = f.ring + domain = ring.domain # Z[t_1, ..., t_k] + + if isinstance(domain, PolynomialRing): + k = domain.ngens + else: + return _euclidean_algorithm(f, g, minpoly, p) + + if k == 1: + qdomain = domain.ring.to_field() + else: + qdomain = domain.ring.drop_to_ground(k - 1) + qdomain = qdomain.clone(domain=qdomain.domain.ring.to_field()) + + qring = ring.clone(domain=qdomain) # = Z(t_k)[t_1, ..., t_{k-1}][x, z] + + n = 1 + d = 1 + + # polynomial in Z_p[t_1, ..., t_k][z] + gamma = ring.dmp_LC(f) * ring.dmp_LC(g) + # polynomial in Z_p[t_1, ..., t_k] + delta = minpoly.LC + + evalpoints = [] + heval = [] + LMlist = [] + points = list(range(p)) + + while points: + a = random.sample(points, 1)[0] + points.remove(a) + + if k == 1: + test = delta.evaluate(k-1, a) % p == 0 + else: + test = delta.evaluate(k-1, a).trunc_ground(p) == 0 + + if test: + continue + + gammaa = _evaluate_ground(gamma, k-1, a) + minpolya = _evaluate_ground(minpoly, k-1, a) + + if gammaa.rem([minpolya, gammaa.ring(p)]) == 0: + continue + + fa = _evaluate_ground(f, k-1, a) + ga = _evaluate_ground(g, k-1, a) + + # polynomial in Z_p[x, t_1, ..., t_{k-1}, z]/(minpoly) + ha = _func_field_modgcd_p(fa, ga, minpolya, p) + + if ha is None: + d += 1 + if d > n: + return None + continue + + if ha == 1: + return ha + + LM = [ha.degree()] + [0]*(k-1) + if k > 1: + for monom, coeff in ha.iterterms(): + if monom[0] == LM[0] and coeff.LM > tuple(LM[1:]): + LM[1:] = coeff.LM + + evalpoints_a = [a] + heval_a = [ha] + if k == 1: + m = qring.domain.get_ring().one + else: + m = qring.domain.domain.get_ring().one + + t = m.ring.gens[0] + + for b, hb, LMhb in zip(evalpoints, heval, LMlist): + if LMhb == LM: + evalpoints_a.append(b) + heval_a.append(hb) + m *= (t - b) + + m = m.trunc_ground(p) + evalpoints.append(a) + heval.append(ha) + LMlist.append(LM) + n += 1 + + # polynomial in Z_p[t_1, ..., t_k][x, z] + h = _interpolate_multivariate(evalpoints_a, heval_a, ring, k-1, p, ground=True) + + # polynomial in Z_p(t_k)[t_1, ..., t_{k-1}][x, z] + h = _rational_reconstruction_func_coeffs(h, p, m, qring, k-1) + + if h is None: + continue + + if k == 1: + dom = qring.domain.field + den = dom.ring.one + + for coeff in h.itercoeffs(): + den = dom.ring.from_dense(gf_lcm(den.to_dense(), coeff.denom.to_dense(), + p, dom.domain)) + + else: + dom = qring.domain.domain.field + den = dom.ring.one + + for coeff in h.itercoeffs(): + for c in coeff.itercoeffs(): + den = dom.ring.from_dense(gf_lcm(den.to_dense(), c.denom.to_dense(), + p, dom.domain)) + + den = qring.domain_new(den.trunc_ground(p)) + h = ring(h.mul_ground(den).as_expr()).trunc_ground(p) + + if not _trial_division(f, h, minpoly, p) and not _trial_division(g, h, minpoly, p): + return h + + return None + + +def _integer_rational_reconstruction(c, m, domain): + r""" + Reconstruct a rational number `\frac a b` from + + .. math:: + + c = \frac a b \; \mathrm{mod} \, m, + + where `c` and `m` are integers. + + The algorithm is based on the Euclidean Algorithm. In general, `m` is + not a prime number, so it is possible that `b` is not invertible modulo + `m`. In that case ``None`` is returned. + + Parameters + ========== + + c : Integer + `c = \frac a b \; \mathrm{mod} \, m` + m : Integer + modulus, not necessarily prime + domain : IntegerRing + `a, b, c` are elements of ``domain`` + + Returns + ======= + + frac : Rational + either `\frac a b` in `\mathbb Q` or ``None`` + + References + ========== + + 1. [Wang81]_ + + """ + if c < 0: + c += m + + r0, s0 = m, domain.zero + r1, s1 = c, domain.one + + bound = sqrt(m / 2) # still correct if replaced by ZZ.sqrt(m // 2) ? + + while int(r1) >= bound: + quo = r0 // r1 + r0, r1 = r1, r0 - quo*r1 + s0, s1 = s1, s0 - quo*s1 + + if abs(int(s1)) >= bound: + return None + + if s1 < 0: + a, b = -r1, -s1 + elif s1 > 0: + a, b = r1, s1 + else: + return None + + field = domain.get_field() + + return field(a) / field(b) + + +def _rational_reconstruction_int_coeffs(hm, m, ring): + r""" + Reconstruct every rational coefficient `c_h` of a polynomial `h` in + `\mathbb Q[t_1, \ldots, t_k][x, z]` from the corresponding integer + coefficient `c_{h_m}` of a polynomial `h_m` in + `\mathbb Z[t_1, \ldots, t_k][x, z]` such that + + .. math:: + + c_{h_m} = c_h \; \mathrm{mod} \, m, + + where `m \in \mathbb Z`. + + The reconstruction is based on the Euclidean Algorithm. In general, + `m` is not a prime number, so it is possible that this fails for some + coefficient. In that case ``None`` is returned. + + Parameters + ========== + + hm : PolyElement + polynomial in `\mathbb Z[t_1, \ldots, t_k][x, z]` + m : Integer + modulus, not necessarily prime + ring : PolyRing + `\mathbb Q[t_1, \ldots, t_k][x, z]`, `h` will be an element of this + ring + + Returns + ======= + + h : PolyElement + reconstructed polynomial in `\mathbb Q[t_1, \ldots, t_k][x, z]` or + ``None`` + + See also + ======== + + _integer_rational_reconstruction + + """ + h = ring.zero + + if isinstance(ring.domain, PolynomialRing): + reconstruction = _rational_reconstruction_int_coeffs + domain = ring.domain.ring + else: + reconstruction = _integer_rational_reconstruction + domain = hm.ring.domain + + for monom, coeff in hm.iterterms(): + coeffh = reconstruction(coeff, m, domain) + + if not coeffh: + return None + + h[monom] = coeffh + + return h + + +def _func_field_modgcd_m(f, g, minpoly): + r""" + Compute the GCD of two polynomials in + `\mathbb Q(t_1, \ldots, t_k)[z]/(m_{\alpha}(z))[x]` using a modular + algorithm. + + The algorithm computes the GCD of two polynomials `f` and `g` by + calculating the GCD in + `\mathbb Z_p(t_1, \ldots, t_k)[z] / (\check m_{\alpha}(z))[x]` for + suitable primes `p` and the primitive associate `\check m_{\alpha}(z)` + of `m_{\alpha}(z)`. Then the coefficients are reconstructed with the + Chinese Remainder Theorem and Rational Reconstruction. To compute the + GCD over `\mathbb Z_p(t_1, \ldots, t_k)[z] / (\check m_{\alpha})[x]`, + the recursive subroutine ``_func_field_modgcd_p`` is used. To verify the + result in `\mathbb Q(t_1, \ldots, t_k)[z] / (m_{\alpha}(z))[x]`, a + fraction free trial division is used. + + Parameters + ========== + + f, g : PolyElement + polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]` + minpoly : PolyElement + irreducible polynomial in `\mathbb Z[t_1, \ldots, t_k][z]` + + Returns + ======= + + h : PolyElement + the primitive associate in `\mathbb Z[t_1, \ldots, t_k][x, z]` of + the GCD of `f` and `g` + + Examples + ======== + + >>> from sympy.polys.modulargcd import _func_field_modgcd_m + >>> from sympy.polys import ring, ZZ + + >>> R, x, z = ring('x, z', ZZ) + >>> minpoly = (z**2 - 2).drop(0) + + >>> f = x**2 + 2*x*z + 2 + >>> g = x + z + >>> _func_field_modgcd_m(f, g, minpoly) + x + z + + >>> D, t = ring('t', ZZ) + >>> R, x, z = ring('x, z', D) + >>> minpoly = (z**2-3).drop(0) + + >>> f = x**2 + (t + 1)*x*z + 3*t + >>> g = x*z + 3*t + >>> _func_field_modgcd_m(f, g, minpoly) + x + t*z + + References + ========== + + 1. [Hoeij04]_ + + See also + ======== + + _func_field_modgcd_p + + """ + ring = f.ring + domain = ring.domain + + if isinstance(domain, PolynomialRing): + k = domain.ngens + QQdomain = domain.ring.clone(domain=domain.domain.get_field()) + QQring = ring.clone(domain=QQdomain) + else: + k = 0 + QQring = ring.clone(domain=ring.domain.get_field()) + + cf, f = f.primitive() + cg, g = g.primitive() + + # polynomial in Z[t_1, ..., t_k][z] + gamma = ring.dmp_LC(f) * ring.dmp_LC(g) + # polynomial in Z[t_1, ..., t_k] + delta = minpoly.LC + + p = 1 + primes = [] + hplist = [] + LMlist = [] + + while True: + p = nextprime(p) + + if gamma.trunc_ground(p) == 0: + continue + + if k == 0: + test = (delta % p == 0) + else: + test = (delta.trunc_ground(p) == 0) + + if test: + continue + + fp = f.trunc_ground(p) + gp = g.trunc_ground(p) + minpolyp = minpoly.trunc_ground(p) + + hp = _func_field_modgcd_p(fp, gp, minpolyp, p) + + if hp is None: + continue + + if hp == 1: + return ring.one + + LM = [hp.degree()] + [0]*k + if k > 0: + for monom, coeff in hp.iterterms(): + if monom[0] == LM[0] and coeff.LM > tuple(LM[1:]): + LM[1:] = coeff.LM + + hm = hp + m = p + + for q, hq, LMhq in zip(primes, hplist, LMlist): + if LMhq == LM: + hm = _chinese_remainder_reconstruction_multivariate(hq, hm, q, m) + m *= q + + primes.append(p) + hplist.append(hp) + LMlist.append(LM) + + hm = _rational_reconstruction_int_coeffs(hm, m, QQring) + + if hm is None: + continue + + if k == 0: + h = hm.clear_denoms()[1] + else: + den = domain.domain.one + for coeff in hm.itercoeffs(): + den = domain.domain.lcm(den, coeff.clear_denoms()[0]) + h = hm.mul_ground(den) + + # convert back to Z[t_1, ..., t_k][x, z] from Q[t_1, ..., t_k][x, z] + h = h.set_ring(ring) + h = h.primitive()[1] + + if not (_trial_division(f.mul_ground(cf), h, minpoly) or + _trial_division(g.mul_ground(cg), h, minpoly)): + return h + + +def _to_ZZ_poly(f, ring): + r""" + Compute an associate of a polynomial + `f \in \mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` in + `\mathbb Z[x_1, \ldots, x_{n-1}][z] / (\check m_{\alpha}(z))[x_0]`, + where `\check m_{\alpha}(z) \in \mathbb Z[z]` is the primitive associate + of the minimal polynomial `m_{\alpha}(z)` of `\alpha` over + `\mathbb Q`. + + Parameters + ========== + + f : PolyElement + polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` + ring : PolyRing + `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]` + + Returns + ======= + + f_ : PolyElement + associate of `f` in + `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]` + + """ + f_ = ring.zero + + if isinstance(ring.domain, PolynomialRing): + domain = ring.domain.domain + else: + domain = ring.domain + + den = domain.one + + for coeff in f.itercoeffs(): + for c in coeff.to_list(): + if c: + den = domain.lcm(den, c.denominator) + + for monom, coeff in f.iterterms(): + coeff = coeff.to_list() + m = ring.domain.one + if isinstance(ring.domain, PolynomialRing): + m = m.mul_monom(monom[1:]) + n = len(coeff) + + for i in range(n): + if coeff[i]: + c = domain.convert(coeff[i] * den) * m + + if (monom[0], n-i-1) not in f_: + f_[(monom[0], n-i-1)] = c + else: + f_[(monom[0], n-i-1)] += c + + return f_ + + +def _to_ANP_poly(f, ring): + r""" + Convert a polynomial + `f \in \mathbb Z[x_1, \ldots, x_{n-1}][z]/(\check m_{\alpha}(z))[x_0]` + to a polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]`, + where `\check m_{\alpha}(z) \in \mathbb Z[z]` is the primitive associate + of the minimal polynomial `m_{\alpha}(z)` of `\alpha` over + `\mathbb Q`. + + Parameters + ========== + + f : PolyElement + polynomial in `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]` + ring : PolyRing + `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` + + Returns + ======= + + f_ : PolyElement + polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` + + """ + domain = ring.domain + f_ = ring.zero + + if isinstance(f.ring.domain, PolynomialRing): + for monom, coeff in f.iterterms(): + for mon, coef in coeff.iterterms(): + m = (monom[0],) + mon + c = domain([domain.domain(coef)] + [0]*monom[1]) + + if m not in f_: + f_[m] = c + else: + f_[m] += c + + else: + for monom, coeff in f.iterterms(): + m = (monom[0],) + c = domain([domain.domain(coeff)] + [0]*monom[1]) + + if m not in f_: + f_[m] = c + else: + f_[m] += c + + return f_ + + +def _minpoly_from_dense(minpoly, ring): + r""" + Change representation of the minimal polynomial from ``DMP`` to + ``PolyElement`` for a given ring. + """ + minpoly_ = ring.zero + + for monom, coeff in minpoly.terms(): + minpoly_[monom] = ring.domain(coeff) + + return minpoly_ + + +def _primitive_in_x0(f): + r""" + Compute the content in `x_0` and the primitive part of a polynomial `f` + in + `\mathbb Q(\alpha)[x_0, x_1, \ldots, x_{n-1}] \cong \mathbb Q(\alpha)[x_1, \ldots, x_{n-1}][x_0]`. + """ + fring = f.ring + ring = fring.drop_to_ground(*range(1, fring.ngens)) + dom = ring.domain.ring + f_ = ring(f.as_expr()) + cont = dom.zero + + for coeff in f_.itercoeffs(): + cont = func_field_modgcd(cont, coeff)[0] + if cont == dom.one: + return cont, f + + return cont, f.quo(cont.set_ring(fring)) + + +# TODO: add support for algebraic function fields +def func_field_modgcd(f, g): + r""" + Compute the GCD of two polynomials `f` and `g` in + `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` using a modular algorithm. + + The algorithm first computes the primitive associate + `\check m_{\alpha}(z)` of the minimal polynomial `m_{\alpha}` in + `\mathbb{Z}[z]` and the primitive associates of `f` and `g` in + `\mathbb{Z}[x_1, \ldots, x_{n-1}][z]/(\check m_{\alpha})[x_0]`. Then it + computes the GCD in + `\mathbb Q(x_1, \ldots, x_{n-1})[z]/(m_{\alpha}(z))[x_0]`. + This is done by calculating the GCD in + `\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]` for + suitable primes `p` and then reconstructing the coefficients with the + Chinese Remainder Theorem and Rational Reconstruction. The GCD over + `\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]` is + computed with a recursive subroutine, which evaluates the polynomials at + `x_{n-1} = a` for suitable evaluation points `a \in \mathbb Z_p` and + then calls itself recursively until the ground domain does no longer + contain any parameters. For + `\mathbb{Z}_p[z]/(\check m_{\alpha}(z))[x_0]` the Euclidean Algorithm is + used. The results of those recursive calls are then interpolated and + Rational Function Reconstruction is used to obtain the correct + coefficients. The results, both in + `\mathbb Q(x_1, \ldots, x_{n-1})[z]/(m_{\alpha}(z))[x_0]` and + `\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]`, are + verified by a fraction free trial division. + + Apart from the above GCD computation some GCDs in + `\mathbb Q(\alpha)[x_1, \ldots, x_{n-1}]` have to be calculated, + because treating the polynomials as univariate ones can result in + a spurious content of the GCD. For this ``func_field_modgcd`` is + called recursively. + + Parameters + ========== + + f, g : PolyElement + polynomials in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` + + Returns + ======= + + h : PolyElement + monic GCD of the polynomials `f` and `g` + cff : PolyElement + cofactor of `f`, i.e. `\frac f h` + cfg : PolyElement + cofactor of `g`, i.e. `\frac g h` + + Examples + ======== + + >>> from sympy.polys.modulargcd import func_field_modgcd + >>> from sympy.polys import AlgebraicField, QQ, ring + >>> from sympy import sqrt + + >>> A = AlgebraicField(QQ, sqrt(2)) + >>> R, x = ring('x', A) + + >>> f = x**2 - 2 + >>> g = x + sqrt(2) + + >>> h, cff, cfg = func_field_modgcd(f, g) + + >>> h == x + sqrt(2) + True + >>> cff * h == f + True + >>> cfg * h == g + True + + >>> R, x, y = ring('x, y', A) + + >>> f = x**2 + 2*sqrt(2)*x*y + 2*y**2 + >>> g = x + sqrt(2)*y + + >>> h, cff, cfg = func_field_modgcd(f, g) + + >>> h == x + sqrt(2)*y + True + >>> cff * h == f + True + >>> cfg * h == g + True + + >>> f = x + sqrt(2)*y + >>> g = x + y + + >>> h, cff, cfg = func_field_modgcd(f, g) + + >>> h == R.one + True + >>> cff * h == f + True + >>> cfg * h == g + True + + References + ========== + + 1. [Hoeij04]_ + + """ + ring = f.ring + domain = ring.domain + n = ring.ngens + + assert ring == g.ring and domain.is_Algebraic + + result = _trivial_gcd(f, g) + if result is not None: + return result + + z = Dummy('z') + + ZZring = ring.clone(symbols=ring.symbols + (z,), domain=domain.domain.get_ring()) + + if n == 1: + f_ = _to_ZZ_poly(f, ZZring) + g_ = _to_ZZ_poly(g, ZZring) + minpoly = ZZring.drop(0).from_dense(domain.mod.to_list()) + + h = _func_field_modgcd_m(f_, g_, minpoly) + h = _to_ANP_poly(h, ring) + + else: + # contx0f in Q(a)[x_1, ..., x_{n-1}], f in Q(a)[x_0, ..., x_{n-1}] + contx0f, f = _primitive_in_x0(f) + contx0g, g = _primitive_in_x0(g) + contx0h = func_field_modgcd(contx0f, contx0g)[0] + + ZZring_ = ZZring.drop_to_ground(*range(1, n)) + + f_ = _to_ZZ_poly(f, ZZring_) + g_ = _to_ZZ_poly(g, ZZring_) + minpoly = _minpoly_from_dense(domain.mod, ZZring_.drop(0)) + + h = _func_field_modgcd_m(f_, g_, minpoly) + h = _to_ANP_poly(h, ring) + + contx0h_, h = _primitive_in_x0(h) + h *= contx0h.set_ring(ring) + f *= contx0f.set_ring(ring) + g *= contx0g.set_ring(ring) + + h = h.quo_ground(h.LC) + + return h, f.quo(h), g.quo(h) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/monomials.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/monomials.py new file mode 100644 index 0000000000000000000000000000000000000000..43a17223861f656b8a4a51fb4c0c934635ed4623 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/monomials.py @@ -0,0 +1,628 @@ +"""Tools and arithmetics for monomials of distributed polynomials. """ + + +from itertools import combinations_with_replacement, product +from textwrap import dedent + +from sympy.core.cache import cacheit +from sympy.core import Mul, S, Tuple, sympify +from sympy.polys.polyerrors import ExactQuotientFailed +from sympy.polys.polyutils import PicklableWithSlots, dict_from_expr +from sympy.utilities import public +from sympy.utilities.iterables import is_sequence, iterable + +@public +def itermonomials(variables, max_degrees, min_degrees=None): + r""" + ``max_degrees`` and ``min_degrees`` are either both integers or both lists. + Unless otherwise specified, ``min_degrees`` is either ``0`` or + ``[0, ..., 0]``. + + A generator of all monomials ``monom`` is returned, such that + either + ``min_degree <= total_degree(monom) <= max_degree``, + or + ``min_degrees[i] <= degree_list(monom)[i] <= max_degrees[i]``, + for all ``i``. + + Case I. ``max_degrees`` and ``min_degrees`` are both integers + ============================================================= + + Given a set of variables $V$ and a min_degree $N$ and a max_degree $M$ + generate a set of monomials of degree less than or equal to $N$ and greater + than or equal to $M$. The total number of monomials in commutative + variables is huge and is given by the following formula if $M = 0$: + + .. math:: + \frac{(\#V + N)!}{\#V! N!} + + For example if we would like to generate a dense polynomial of + a total degree $N = 50$ and $M = 0$, which is the worst case, in 5 + variables, assuming that exponents and all of coefficients are 32-bit long + and stored in an array we would need almost 80 GiB of memory! Fortunately + most polynomials, that we will encounter, are sparse. + + Consider monomials in commutative variables $x$ and $y$ + and non-commutative variables $a$ and $b$:: + + >>> from sympy import symbols + >>> from sympy.polys.monomials import itermonomials + >>> from sympy.polys.orderings import monomial_key + >>> from sympy.abc import x, y + + >>> sorted(itermonomials([x, y], 2), key=monomial_key('grlex', [y, x])) + [1, x, y, x**2, x*y, y**2] + + >>> sorted(itermonomials([x, y], 3), key=monomial_key('grlex', [y, x])) + [1, x, y, x**2, x*y, y**2, x**3, x**2*y, x*y**2, y**3] + + >>> a, b = symbols('a, b', commutative=False) + >>> set(itermonomials([a, b, x], 2)) + {1, a, a**2, b, b**2, x, x**2, a*b, b*a, x*a, x*b} + + >>> sorted(itermonomials([x, y], 2, 1), key=monomial_key('grlex', [y, x])) + [x, y, x**2, x*y, y**2] + + Case II. ``max_degrees`` and ``min_degrees`` are both lists + =========================================================== + + If ``max_degrees = [d_1, ..., d_n]`` and + ``min_degrees = [e_1, ..., e_n]``, the number of monomials generated + is: + + .. math:: + (d_1 - e_1 + 1) (d_2 - e_2 + 1) \cdots (d_n - e_n + 1) + + Let us generate all monomials ``monom`` in variables $x$ and $y$ + such that ``[1, 2][i] <= degree_list(monom)[i] <= [2, 4][i]``, + ``i = 0, 1`` :: + + >>> from sympy import symbols + >>> from sympy.polys.monomials import itermonomials + >>> from sympy.polys.orderings import monomial_key + >>> from sympy.abc import x, y + + >>> sorted(itermonomials([x, y], [2, 4], [1, 2]), reverse=True, key=monomial_key('lex', [x, y])) + [x**2*y**4, x**2*y**3, x**2*y**2, x*y**4, x*y**3, x*y**2] + """ + if is_sequence(max_degrees): + n = len(variables) + if len(max_degrees) != n: + raise ValueError('Argument sizes do not match') + if min_degrees is None: + min_degrees = [0]*n + elif not is_sequence(min_degrees): + raise ValueError('min_degrees is not a list') + else: + if len(min_degrees) != n: + raise ValueError('Argument sizes do not match') + if any(i < 0 for i in min_degrees): + raise ValueError("min_degrees cannot contain negative numbers") + if any(min_degrees[i] > max_degrees[i] for i in range(n)): + raise ValueError('min_degrees[i] must be <= max_degrees[i] for all i') + power_lists = [] + for var, min_d, max_d in zip(variables, min_degrees, max_degrees): + power_lists.append([var**i for i in range(min_d, max_d + 1)]) + for powers in product(*power_lists): + yield Mul(*powers) + else: + max_degree = max_degrees + if max_degree < 0: + raise ValueError("max_degrees cannot be negative") + if min_degrees is None: + min_degree = 0 + else: + if min_degrees < 0: + raise ValueError("min_degrees cannot be negative") + min_degree = min_degrees + if min_degree > max_degree: + return + if not variables or max_degree == 0: + yield S.One + return + # Force to list in case of passed tuple or other incompatible collection + variables = list(variables) + [S.One] + if all(variable.is_commutative for variable in variables): + it = combinations_with_replacement(variables, max_degree) + else: + it = product(variables, repeat=max_degree) + monomials_set = set() + d = max_degree - min_degree + for item in it: + count = 0 + for variable in item: + if variable == 1: + count += 1 + if d < count: + break + else: + monomials_set.add(Mul(*item)) + yield from monomials_set + +def monomial_count(V, N): + r""" + Computes the number of monomials. + + The number of monomials is given by the following formula: + + .. math:: + + \frac{(\#V + N)!}{\#V! N!} + + where `N` is a total degree and `V` is a set of variables. + + Examples + ======== + + >>> from sympy.polys.monomials import itermonomials, monomial_count + >>> from sympy.polys.orderings import monomial_key + >>> from sympy.abc import x, y + + >>> monomial_count(2, 2) + 6 + + >>> M = list(itermonomials([x, y], 2)) + + >>> sorted(M, key=monomial_key('grlex', [y, x])) + [1, x, y, x**2, x*y, y**2] + >>> len(M) + 6 + + """ + from sympy.functions.combinatorial.factorials import factorial + return factorial(V + N) / factorial(V) / factorial(N) + +def monomial_mul(A, B): + """ + Multiplication of tuples representing monomials. + + Examples + ======== + + Lets multiply `x**3*y**4*z` with `x*y**2`:: + + >>> from sympy.polys.monomials import monomial_mul + + >>> monomial_mul((3, 4, 1), (1, 2, 0)) + (4, 6, 1) + + which gives `x**4*y**5*z`. + + """ + return tuple([ a + b for a, b in zip(A, B) ]) + +def monomial_div(A, B): + """ + Division of tuples representing monomials. + + Examples + ======== + + Lets divide `x**3*y**4*z` by `x*y**2`:: + + >>> from sympy.polys.monomials import monomial_div + + >>> monomial_div((3, 4, 1), (1, 2, 0)) + (2, 2, 1) + + which gives `x**2*y**2*z`. However:: + + >>> monomial_div((3, 4, 1), (1, 2, 2)) is None + True + + `x*y**2*z**2` does not divide `x**3*y**4*z`. + + """ + C = monomial_ldiv(A, B) + + if all(c >= 0 for c in C): + return tuple(C) + else: + return None + +def monomial_ldiv(A, B): + """ + Division of tuples representing monomials. + + Examples + ======== + + Lets divide `x**3*y**4*z` by `x*y**2`:: + + >>> from sympy.polys.monomials import monomial_ldiv + + >>> monomial_ldiv((3, 4, 1), (1, 2, 0)) + (2, 2, 1) + + which gives `x**2*y**2*z`. + + >>> monomial_ldiv((3, 4, 1), (1, 2, 2)) + (2, 2, -1) + + which gives `x**2*y**2*z**-1`. + + """ + return tuple([ a - b for a, b in zip(A, B) ]) + +def monomial_pow(A, n): + """Return the n-th pow of the monomial. """ + return tuple([ a*n for a in A ]) + +def monomial_gcd(A, B): + """ + Greatest common divisor of tuples representing monomials. + + Examples + ======== + + Lets compute GCD of `x*y**4*z` and `x**3*y**2`:: + + >>> from sympy.polys.monomials import monomial_gcd + + >>> monomial_gcd((1, 4, 1), (3, 2, 0)) + (1, 2, 0) + + which gives `x*y**2`. + + """ + return tuple([ min(a, b) for a, b in zip(A, B) ]) + +def monomial_lcm(A, B): + """ + Least common multiple of tuples representing monomials. + + Examples + ======== + + Lets compute LCM of `x*y**4*z` and `x**3*y**2`:: + + >>> from sympy.polys.monomials import monomial_lcm + + >>> monomial_lcm((1, 4, 1), (3, 2, 0)) + (3, 4, 1) + + which gives `x**3*y**4*z`. + + """ + return tuple([ max(a, b) for a, b in zip(A, B) ]) + +def monomial_divides(A, B): + """ + Does there exist a monomial X such that XA == B? + + Examples + ======== + + >>> from sympy.polys.monomials import monomial_divides + >>> monomial_divides((1, 2), (3, 4)) + True + >>> monomial_divides((1, 2), (0, 2)) + False + """ + return all(a <= b for a, b in zip(A, B)) + +def monomial_max(*monoms): + """ + Returns maximal degree for each variable in a set of monomials. + + Examples + ======== + + Consider monomials `x**3*y**4*z**5`, `y**5*z` and `x**6*y**3*z**9`. + We wish to find out what is the maximal degree for each of `x`, `y` + and `z` variables:: + + >>> from sympy.polys.monomials import monomial_max + + >>> monomial_max((3,4,5), (0,5,1), (6,3,9)) + (6, 5, 9) + + """ + M = list(monoms[0]) + + for N in monoms[1:]: + for i, n in enumerate(N): + M[i] = max(M[i], n) + + return tuple(M) + +def monomial_min(*monoms): + """ + Returns minimal degree for each variable in a set of monomials. + + Examples + ======== + + Consider monomials `x**3*y**4*z**5`, `y**5*z` and `x**6*y**3*z**9`. + We wish to find out what is the minimal degree for each of `x`, `y` + and `z` variables:: + + >>> from sympy.polys.monomials import monomial_min + + >>> monomial_min((3,4,5), (0,5,1), (6,3,9)) + (0, 3, 1) + + """ + M = list(monoms[0]) + + for N in monoms[1:]: + for i, n in enumerate(N): + M[i] = min(M[i], n) + + return tuple(M) + +def monomial_deg(M): + """ + Returns the total degree of a monomial. + + Examples + ======== + + The total degree of `xy^2` is 3: + + >>> from sympy.polys.monomials import monomial_deg + >>> monomial_deg((1, 2)) + 3 + """ + return sum(M) + +def term_div(a, b, domain): + """Division of two terms in over a ring/field. """ + a_lm, a_lc = a + b_lm, b_lc = b + + monom = monomial_div(a_lm, b_lm) + + if domain.is_Field: + if monom is not None: + return monom, domain.quo(a_lc, b_lc) + else: + return None + else: + if not (monom is None or a_lc % b_lc): + return monom, domain.quo(a_lc, b_lc) + else: + return None + +class MonomialOps: + """Code generator of fast monomial arithmetic functions. """ + + @cacheit + def __new__(cls, ngens): + obj = super().__new__(cls) + obj.ngens = ngens + return obj + + def __getnewargs__(self): + return (self.ngens,) + + def _build(self, code, name): + ns = {} + exec(code, ns) + return ns[name] + + def _vars(self, name): + return [ "%s%s" % (name, i) for i in range(self.ngens) ] + + @cacheit + def mul(self): + name = "monomial_mul" + template = dedent("""\ + def %(name)s(A, B): + (%(A)s,) = A + (%(B)s,) = B + return (%(AB)s,) + """) + A = self._vars("a") + B = self._vars("b") + AB = [ "%s + %s" % (a, b) for a, b in zip(A, B) ] + code = template % {"name": name, "A": ", ".join(A), "B": ", ".join(B), "AB": ", ".join(AB)} + return self._build(code, name) + + @cacheit + def pow(self): + name = "monomial_pow" + template = dedent("""\ + def %(name)s(A, k): + (%(A)s,) = A + return (%(Ak)s,) + """) + A = self._vars("a") + Ak = [ "%s*k" % a for a in A ] + code = template % {"name": name, "A": ", ".join(A), "Ak": ", ".join(Ak)} + return self._build(code, name) + + @cacheit + def mulpow(self): + name = "monomial_mulpow" + template = dedent("""\ + def %(name)s(A, B, k): + (%(A)s,) = A + (%(B)s,) = B + return (%(ABk)s,) + """) + A = self._vars("a") + B = self._vars("b") + ABk = [ "%s + %s*k" % (a, b) for a, b in zip(A, B) ] + code = template % {"name": name, "A": ", ".join(A), "B": ", ".join(B), "ABk": ", ".join(ABk)} + return self._build(code, name) + + @cacheit + def ldiv(self): + name = "monomial_ldiv" + template = dedent("""\ + def %(name)s(A, B): + (%(A)s,) = A + (%(B)s,) = B + return (%(AB)s,) + """) + A = self._vars("a") + B = self._vars("b") + AB = [ "%s - %s" % (a, b) for a, b in zip(A, B) ] + code = template % {"name": name, "A": ", ".join(A), "B": ", ".join(B), "AB": ", ".join(AB)} + return self._build(code, name) + + @cacheit + def div(self): + name = "monomial_div" + template = dedent("""\ + def %(name)s(A, B): + (%(A)s,) = A + (%(B)s,) = B + %(RAB)s + return (%(R)s,) + """) + A = self._vars("a") + B = self._vars("b") + RAB = [ "r%(i)s = a%(i)s - b%(i)s\n if r%(i)s < 0: return None" % {"i": i} for i in range(self.ngens) ] + R = self._vars("r") + code = template % {"name": name, "A": ", ".join(A), "B": ", ".join(B), "RAB": "\n ".join(RAB), "R": ", ".join(R)} + return self._build(code, name) + + @cacheit + def lcm(self): + name = "monomial_lcm" + template = dedent("""\ + def %(name)s(A, B): + (%(A)s,) = A + (%(B)s,) = B + return (%(AB)s,) + """) + A = self._vars("a") + B = self._vars("b") + AB = [ "%s if %s >= %s else %s" % (a, a, b, b) for a, b in zip(A, B) ] + code = template % {"name": name, "A": ", ".join(A), "B": ", ".join(B), "AB": ", ".join(AB)} + return self._build(code, name) + + @cacheit + def gcd(self): + name = "monomial_gcd" + template = dedent("""\ + def %(name)s(A, B): + (%(A)s,) = A + (%(B)s,) = B + return (%(AB)s,) + """) + A = self._vars("a") + B = self._vars("b") + AB = [ "%s if %s <= %s else %s" % (a, a, b, b) for a, b in zip(A, B) ] + code = template % {"name": name, "A": ", ".join(A), "B": ", ".join(B), "AB": ", ".join(AB)} + return self._build(code, name) + +@public +class Monomial(PicklableWithSlots): + """Class representing a monomial, i.e. a product of powers. """ + + __slots__ = ('exponents', 'gens') + + def __init__(self, monom, gens=None): + if not iterable(monom): + rep, gens = dict_from_expr(sympify(monom), gens=gens) + if len(rep) == 1 and list(rep.values())[0] == 1: + monom = list(rep.keys())[0] + else: + raise ValueError("Expected a monomial got {}".format(monom)) + + self.exponents = tuple(map(int, monom)) + self.gens = gens + + def rebuild(self, exponents, gens=None): + return self.__class__(exponents, gens or self.gens) + + def __len__(self): + return len(self.exponents) + + def __iter__(self): + return iter(self.exponents) + + def __getitem__(self, item): + return self.exponents[item] + + def __hash__(self): + return hash((self.__class__.__name__, self.exponents, self.gens)) + + def __str__(self): + if self.gens: + return "*".join([ "%s**%s" % (gen, exp) for gen, exp in zip(self.gens, self.exponents) ]) + else: + return "%s(%s)" % (self.__class__.__name__, self.exponents) + + def as_expr(self, *gens): + """Convert a monomial instance to a SymPy expression. """ + gens = gens or self.gens + + if not gens: + raise ValueError( + "Cannot convert %s to an expression without generators" % self) + + return Mul(*[ gen**exp for gen, exp in zip(gens, self.exponents) ]) + + def __eq__(self, other): + if isinstance(other, Monomial): + exponents = other.exponents + elif isinstance(other, (tuple, Tuple)): + exponents = other + else: + return False + + return self.exponents == exponents + + def __ne__(self, other): + return not self == other + + def __mul__(self, other): + if isinstance(other, Monomial): + exponents = other.exponents + elif isinstance(other, (tuple, Tuple)): + exponents = other + else: + raise NotImplementedError + + return self.rebuild(monomial_mul(self.exponents, exponents)) + + def __truediv__(self, other): + if isinstance(other, Monomial): + exponents = other.exponents + elif isinstance(other, (tuple, Tuple)): + exponents = other + else: + raise NotImplementedError + + result = monomial_div(self.exponents, exponents) + + if result is not None: + return self.rebuild(result) + else: + raise ExactQuotientFailed(self, Monomial(other)) + + __floordiv__ = __truediv__ + + def __pow__(self, other): + n = int(other) + if n < 0: + raise ValueError("a non-negative integer expected, got %s" % other) + return self.rebuild(monomial_pow(self.exponents, n)) + + def gcd(self, other): + """Greatest common divisor of monomials. """ + if isinstance(other, Monomial): + exponents = other.exponents + elif isinstance(other, (tuple, Tuple)): + exponents = other + else: + raise TypeError( + "an instance of Monomial class expected, got %s" % other) + + return self.rebuild(monomial_gcd(self.exponents, exponents)) + + def lcm(self, other): + """Least common multiple of monomials. """ + if isinstance(other, Monomial): + exponents = other.exponents + elif isinstance(other, (tuple, Tuple)): + exponents = other + else: + raise TypeError( + "an instance of Monomial class expected, got %s" % other) + + return self.rebuild(monomial_lcm(self.exponents, exponents)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/multivariate_resultants.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/multivariate_resultants.py new file mode 100644 index 0000000000000000000000000000000000000000..b6c967a8b981e25e8e26745804a658ff7b90e9af --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/multivariate_resultants.py @@ -0,0 +1,473 @@ +""" +This module contains functions for two multivariate resultants. These +are: + +- Dixon's resultant. +- Macaulay's resultant. + +Multivariate resultants are used to identify whether a multivariate +system has common roots. That is when the resultant is equal to zero. +""" +from math import prod + +from sympy.core.mul import Mul +from sympy.matrices.dense import (Matrix, diag) +from sympy.polys.polytools import (Poly, degree_list, rem) +from sympy.simplify.simplify import simplify +from sympy.tensor.indexed import IndexedBase +from sympy.polys.monomials import itermonomials, monomial_deg +from sympy.polys.orderings import monomial_key +from sympy.polys.polytools import poly_from_expr, total_degree +from sympy.functions.combinatorial.factorials import binomial +from itertools import combinations_with_replacement +from sympy.utilities.exceptions import sympy_deprecation_warning + +class DixonResultant(): + """ + A class for retrieving the Dixon's resultant of a multivariate + system. + + Examples + ======== + + >>> from sympy import symbols + + >>> from sympy.polys.multivariate_resultants import DixonResultant + >>> x, y = symbols('x, y') + + >>> p = x + y + >>> q = x ** 2 + y ** 3 + >>> h = x ** 2 + y + + >>> dixon = DixonResultant(variables=[x, y], polynomials=[p, q, h]) + >>> poly = dixon.get_dixon_polynomial() + >>> matrix = dixon.get_dixon_matrix(polynomial=poly) + >>> matrix + Matrix([ + [ 0, 0, -1, 0, -1], + [ 0, -1, 0, -1, 0], + [-1, 0, 1, 0, 0], + [ 0, -1, 0, 0, 1], + [-1, 0, 0, 1, 0]]) + >>> matrix.det() + 0 + + See Also + ======== + + Notebook in examples: sympy/example/notebooks. + + References + ========== + + .. [1] [Kapur1994]_ + .. [2] [Palancz08]_ + + """ + + def __init__(self, polynomials, variables): + """ + A class that takes two lists, a list of polynomials and list of + variables. Returns the Dixon matrix of the multivariate system. + + Parameters + ---------- + polynomials : list of polynomials + A list of m n-degree polynomials + variables: list + A list of all n variables + """ + self.polynomials = polynomials + self.variables = variables + + self.n = len(self.variables) + self.m = len(self.polynomials) + + a = IndexedBase("alpha") + # A list of n alpha variables (the replacing variables) + self.dummy_variables = [a[i] for i in range(self.n)] + + # A list of the d_max of each variable. + self._max_degrees = [max(degree_list(poly)[i] for poly in self.polynomials) + for i in range(self.n)] + + @property + def max_degrees(self): + sympy_deprecation_warning( + """ + The max_degrees property of DixonResultant is deprecated. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-dixonresultant-properties", + ) + return self._max_degrees + + def get_dixon_polynomial(self): + r""" + Returns + ======= + + dixon_polynomial: polynomial + Dixon's polynomial is calculated as: + + delta = Delta(A) / ((x_1 - a_1) ... (x_n - a_n)) where, + + A = |p_1(x_1,... x_n), ..., p_n(x_1,... x_n)| + |p_1(a_1,... x_n), ..., p_n(a_1,... x_n)| + |... , ..., ...| + |p_1(a_1,... a_n), ..., p_n(a_1,... a_n)| + """ + if self.m != (self.n + 1): + raise ValueError('Method invalid for given combination.') + + # First row + rows = [self.polynomials] + + temp = list(self.variables) + + for idx in range(self.n): + temp[idx] = self.dummy_variables[idx] + substitution = dict(zip(self.variables, temp)) + rows.append([f.subs(substitution) for f in self.polynomials]) + + A = Matrix(rows) + + terms = zip(self.variables, self.dummy_variables) + product_of_differences = Mul(*[a - b for a, b in terms]) + dixon_polynomial = (A.det() / product_of_differences).factor() + + return poly_from_expr(dixon_polynomial, self.dummy_variables)[0] + + def get_upper_degree(self): + sympy_deprecation_warning( + """ + The get_upper_degree() method of DixonResultant is deprecated. Use + get_max_degrees() instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-dixonresultant-properties" + ) + list_of_products = [self.variables[i] ** self._max_degrees[i] + for i in range(self.n)] + product = prod(list_of_products) + product = Poly(product).monoms() + + return monomial_deg(*product) + + def get_max_degrees(self, polynomial): + r""" + Returns a list of the maximum degree of each variable appearing + in the coefficients of the Dixon polynomial. The coefficients are + viewed as polys in $x_1, x_2, \dots, x_n$. + """ + deg_lists = [degree_list(Poly(poly, self.variables)) + for poly in polynomial.coeffs()] + + max_degrees = [max(degs) for degs in zip(*deg_lists)] + + return max_degrees + + def get_dixon_matrix(self, polynomial): + r""" + Construct the Dixon matrix from the coefficients of polynomial + \alpha. Each coefficient is viewed as a polynomial of x_1, ..., + x_n. + """ + + max_degrees = self.get_max_degrees(polynomial) + + # list of column headers of the Dixon matrix. + monomials = itermonomials(self.variables, max_degrees) + monomials = sorted(monomials, reverse=True, + key=monomial_key('lex', self.variables)) + + dixon_matrix = Matrix([[Poly(c, *self.variables).coeff_monomial(m) + for m in monomials] + for c in polynomial.coeffs()]) + + # remove columns if needed + if dixon_matrix.shape[0] != dixon_matrix.shape[1]: + keep = [column for column in range(dixon_matrix.shape[-1]) + if any(element != 0 for element + in dixon_matrix[:, column])] + + dixon_matrix = dixon_matrix[:, keep] + + return dixon_matrix + + def KSY_precondition(self, matrix): + """ + Test for the validity of the Kapur-Saxena-Yang precondition. + + The precondition requires that the column corresponding to the + monomial 1 = x_1 ^ 0 * x_2 ^ 0 * ... * x_n ^ 0 is not a linear + combination of the remaining ones. In SymPy notation this is + the last column. For the precondition to hold the last non-zero + row of the rref matrix should be of the form [0, 0, ..., 1]. + """ + if matrix.is_zero_matrix: + return False + + m, n = matrix.shape + + # simplify the matrix and keep only its non-zero rows + matrix = simplify(matrix.rref()[0]) + rows = [i for i in range(m) if any(matrix[i, j] != 0 for j in range(n))] + matrix = matrix[rows,:] + + condition = Matrix([[0]*(n-1) + [1]]) + + if matrix[-1,:] == condition: + return True + else: + return False + + def delete_zero_rows_and_columns(self, matrix): + """Remove the zero rows and columns of the matrix.""" + rows = [ + i for i in range(matrix.rows) if not matrix.row(i).is_zero_matrix] + cols = [ + j for j in range(matrix.cols) if not matrix.col(j).is_zero_matrix] + + return matrix[rows, cols] + + def product_leading_entries(self, matrix): + """Calculate the product of the leading entries of the matrix.""" + res = 1 + for row in range(matrix.rows): + for el in matrix.row(row): + if el != 0: + res = res * el + break + return res + + def get_KSY_Dixon_resultant(self, matrix): + """Calculate the Kapur-Saxena-Yang approach to the Dixon Resultant.""" + matrix = self.delete_zero_rows_and_columns(matrix) + _, U, _ = matrix.LUdecomposition() + matrix = self.delete_zero_rows_and_columns(simplify(U)) + + return self.product_leading_entries(matrix) + +class MacaulayResultant(): + """ + A class for calculating the Macaulay resultant. Note that the + polynomials must be homogenized and their coefficients must be + given as symbols. + + Examples + ======== + + >>> from sympy import symbols + + >>> from sympy.polys.multivariate_resultants import MacaulayResultant + >>> x, y, z = symbols('x, y, z') + + >>> a_0, a_1, a_2 = symbols('a_0, a_1, a_2') + >>> b_0, b_1, b_2 = symbols('b_0, b_1, b_2') + >>> c_0, c_1, c_2,c_3, c_4 = symbols('c_0, c_1, c_2, c_3, c_4') + + >>> f = a_0 * y - a_1 * x + a_2 * z + >>> g = b_1 * x ** 2 + b_0 * y ** 2 - b_2 * z ** 2 + >>> h = c_0 * y * z ** 2 - c_1 * x ** 3 + c_2 * x ** 2 * z - c_3 * x * z ** 2 + c_4 * z ** 3 + + >>> mac = MacaulayResultant(polynomials=[f, g, h], variables=[x, y, z]) + >>> mac.monomial_set + [x**4, x**3*y, x**3*z, x**2*y**2, x**2*y*z, x**2*z**2, x*y**3, + x*y**2*z, x*y*z**2, x*z**3, y**4, y**3*z, y**2*z**2, y*z**3, z**4] + >>> matrix = mac.get_matrix() + >>> submatrix = mac.get_submatrix(matrix) + >>> submatrix + Matrix([ + [-a_1, a_0, a_2, 0], + [ 0, -a_1, 0, 0], + [ 0, 0, -a_1, 0], + [ 0, 0, 0, -a_1]]) + + See Also + ======== + + Notebook in examples: sympy/example/notebooks. + + References + ========== + + .. [1] [Bruce97]_ + .. [2] [Stiller96]_ + + """ + def __init__(self, polynomials, variables): + """ + Parameters + ========== + + variables: list + A list of all n variables + polynomials : list of SymPy polynomials + A list of m n-degree polynomials + """ + self.polynomials = polynomials + self.variables = variables + self.n = len(variables) + + # A list of the d_max of each polynomial. + self.degrees = [total_degree(poly, *self.variables) for poly + in self.polynomials] + + self.degree_m = self._get_degree_m() + self.monomials_size = self.get_size() + + # The set T of all possible monomials of degree degree_m + self.monomial_set = self.get_monomials_of_certain_degree(self.degree_m) + + def _get_degree_m(self): + r""" + Returns + ======= + + degree_m: int + The degree_m is calculated as 1 + \sum_1 ^ n (d_i - 1), + where d_i is the degree of the i polynomial + """ + return 1 + sum(d - 1 for d in self.degrees) + + def get_size(self): + r""" + Returns + ======= + + size: int + The size of set T. Set T is the set of all possible + monomials of the n variables for degree equal to the + degree_m + """ + return binomial(self.degree_m + self.n - 1, self.n - 1) + + def get_monomials_of_certain_degree(self, degree): + """ + Returns + ======= + + monomials: list + A list of monomials of a certain degree. + """ + monomials = [Mul(*monomial) for monomial + in combinations_with_replacement(self.variables, + degree)] + + return sorted(monomials, reverse=True, + key=monomial_key('lex', self.variables)) + + def get_row_coefficients(self): + """ + Returns + ======= + + row_coefficients: list + The row coefficients of Macaulay's matrix + """ + row_coefficients = [] + divisible = [] + for i in range(self.n): + if i == 0: + degree = self.degree_m - self.degrees[i] + monomial = self.get_monomials_of_certain_degree(degree) + row_coefficients.append(monomial) + else: + divisible.append(self.variables[i - 1] ** + self.degrees[i - 1]) + degree = self.degree_m - self.degrees[i] + poss_rows = self.get_monomials_of_certain_degree(degree) + for div in divisible: + for p in poss_rows: + if rem(p, div) == 0: + poss_rows = [item for item in poss_rows + if item != p] + row_coefficients.append(poss_rows) + return row_coefficients + + def get_matrix(self): + """ + Returns + ======= + + macaulay_matrix: Matrix + The Macaulay numerator matrix + """ + rows = [] + row_coefficients = self.get_row_coefficients() + for i in range(self.n): + for multiplier in row_coefficients[i]: + coefficients = [] + poly = Poly(self.polynomials[i] * multiplier, + *self.variables) + + for mono in self.monomial_set: + coefficients.append(poly.coeff_monomial(mono)) + rows.append(coefficients) + + macaulay_matrix = Matrix(rows) + return macaulay_matrix + + def get_reduced_nonreduced(self): + r""" + Returns + ======= + + reduced: list + A list of the reduced monomials + non_reduced: list + A list of the monomials that are not reduced + + Definition + ========== + + A polynomial is said to be reduced in x_i, if its degree (the + maximum degree of its monomials) in x_i is less than d_i. A + polynomial that is reduced in all variables but one is said + simply to be reduced. + """ + divisible = [] + for m in self.monomial_set: + temp = [] + for i, v in enumerate(self.variables): + temp.append(bool(total_degree(m, v) >= self.degrees[i])) + divisible.append(temp) + reduced = [i for i, r in enumerate(divisible) + if sum(r) < self.n - 1] + non_reduced = [i for i, r in enumerate(divisible) + if sum(r) >= self.n -1] + + return reduced, non_reduced + + def get_submatrix(self, matrix): + r""" + Returns + ======= + + macaulay_submatrix: Matrix + The Macaulay denominator matrix. Columns that are non reduced are kept. + The row which contains one of the a_{i}s is dropped. a_{i}s + are the coefficients of x_i ^ {d_i}. + """ + reduced, non_reduced = self.get_reduced_nonreduced() + + # if reduced == [], then det(matrix) should be 1 + if reduced == []: + return diag([1]) + + # reduced != [] + reduction_set = [v ** self.degrees[i] for i, v + in enumerate(self.variables)] + + ais = [self.polynomials[i].coeff(reduction_set[i]) + for i in range(self.n)] + + reduced_matrix = matrix[:, reduced] + keep = [] + for row in range(reduced_matrix.rows): + check = [ai in reduced_matrix[row, :] for ai in ais] + if True not in check: + keep.append(row) + + return matrix[keep, non_reduced] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/orderings.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/orderings.py new file mode 100644 index 0000000000000000000000000000000000000000..b6ed575d5103440e1e8ebda4c53c4149d3badf11 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/orderings.py @@ -0,0 +1,286 @@ +"""Definitions of monomial orderings. """ + +from __future__ import annotations + +__all__ = ["lex", "grlex", "grevlex", "ilex", "igrlex", "igrevlex"] + +from sympy.core import Symbol +from sympy.utilities.iterables import iterable + +class MonomialOrder: + """Base class for monomial orderings. """ + + alias: str | None = None + is_global: bool | None = None + is_default = False + + def __repr__(self): + return self.__class__.__name__ + "()" + + def __str__(self): + return self.alias + + def __call__(self, monomial): + raise NotImplementedError + + def __eq__(self, other): + return self.__class__ == other.__class__ + + def __hash__(self): + return hash(self.__class__) + + def __ne__(self, other): + return not (self == other) + +class LexOrder(MonomialOrder): + """Lexicographic order of monomials. """ + + alias = 'lex' + is_global = True + is_default = True + + def __call__(self, monomial): + return monomial + +class GradedLexOrder(MonomialOrder): + """Graded lexicographic order of monomials. """ + + alias = 'grlex' + is_global = True + + def __call__(self, monomial): + return (sum(monomial), monomial) + +class ReversedGradedLexOrder(MonomialOrder): + """Reversed graded lexicographic order of monomials. """ + + alias = 'grevlex' + is_global = True + + def __call__(self, monomial): + return (sum(monomial), tuple(reversed([-m for m in monomial]))) + +class ProductOrder(MonomialOrder): + """ + A product order built from other monomial orders. + + Given (not necessarily total) orders O1, O2, ..., On, their product order + P is defined as M1 > M2 iff there exists i such that O1(M1) = O2(M2), + ..., Oi(M1) = Oi(M2), O{i+1}(M1) > O{i+1}(M2). + + Product orders are typically built from monomial orders on different sets + of variables. + + ProductOrder is constructed by passing a list of pairs + [(O1, L1), (O2, L2), ...] where Oi are MonomialOrders and Li are callables. + Upon comparison, the Li are passed the total monomial, and should filter + out the part of the monomial to pass to Oi. + + Examples + ======== + + We can use a lexicographic order on x_1, x_2 and also on + y_1, y_2, y_3, and their product on {x_i, y_i} as follows: + + >>> from sympy.polys.orderings import lex, grlex, ProductOrder + >>> P = ProductOrder( + ... (lex, lambda m: m[:2]), # lex order on x_1 and x_2 of monomial + ... (grlex, lambda m: m[2:]) # grlex on y_1, y_2, y_3 + ... ) + >>> P((2, 1, 1, 0, 0)) > P((1, 10, 0, 2, 0)) + True + + Here the exponent `2` of `x_1` in the first monomial + (`x_1^2 x_2 y_1`) is bigger than the exponent `1` of `x_1` in the + second monomial (`x_1 x_2^10 y_2^2`), so the first monomial is greater + in the product ordering. + + >>> P((2, 1, 1, 0, 0)) < P((2, 1, 0, 2, 0)) + True + + Here the exponents of `x_1` and `x_2` agree, so the grlex order on + `y_1, y_2, y_3` is used to decide the ordering. In this case the monomial + `y_2^2` is ordered larger than `y_1`, since for the grlex order the degree + of the monomial is most important. + """ + + def __init__(self, *args): + self.args = args + + def __call__(self, monomial): + return tuple(O(lamda(monomial)) for (O, lamda) in self.args) + + def __repr__(self): + contents = [repr(x[0]) for x in self.args] + return self.__class__.__name__ + '(' + ", ".join(contents) + ')' + + def __str__(self): + contents = [str(x[0]) for x in self.args] + return self.__class__.__name__ + '(' + ", ".join(contents) + ')' + + def __eq__(self, other): + if not isinstance(other, ProductOrder): + return False + return self.args == other.args + + def __hash__(self): + return hash((self.__class__, self.args)) + + @property + def is_global(self): + if all(o.is_global is True for o, _ in self.args): + return True + if all(o.is_global is False for o, _ in self.args): + return False + return None + +class InverseOrder(MonomialOrder): + """ + The "inverse" of another monomial order. + + If O is any monomial order, we can construct another monomial order iO + such that `A >_{iO} B` if and only if `B >_O A`. This is useful for + constructing local orders. + + Note that many algorithms only work with *global* orders. + + For example, in the inverse lexicographic order on a single variable `x`, + high powers of `x` count as small: + + >>> from sympy.polys.orderings import lex, InverseOrder + >>> ilex = InverseOrder(lex) + >>> ilex((5,)) < ilex((0,)) + True + """ + + def __init__(self, O): + self.O = O + + def __str__(self): + return "i" + str(self.O) + + def __call__(self, monomial): + def inv(l): + if iterable(l): + return tuple(inv(x) for x in l) + return -l + return inv(self.O(monomial)) + + @property + def is_global(self): + if self.O.is_global is True: + return False + if self.O.is_global is False: + return True + return None + + def __eq__(self, other): + return isinstance(other, InverseOrder) and other.O == self.O + + def __hash__(self): + return hash((self.__class__, self.O)) + +lex = LexOrder() +grlex = GradedLexOrder() +grevlex = ReversedGradedLexOrder() +ilex = InverseOrder(lex) +igrlex = InverseOrder(grlex) +igrevlex = InverseOrder(grevlex) + +_monomial_key = { + 'lex': lex, + 'grlex': grlex, + 'grevlex': grevlex, + 'ilex': ilex, + 'igrlex': igrlex, + 'igrevlex': igrevlex +} + +def monomial_key(order=None, gens=None): + """ + Return a function defining admissible order on monomials. + + The result of a call to :func:`monomial_key` is a function which should + be used as a key to :func:`sorted` built-in function, to provide order + in a set of monomials of the same length. + + Currently supported monomial orderings are: + + 1. lex - lexicographic order (default) + 2. grlex - graded lexicographic order + 3. grevlex - reversed graded lexicographic order + 4. ilex, igrlex, igrevlex - the corresponding inverse orders + + If the ``order`` input argument is not a string but has ``__call__`` + attribute, then it will pass through with an assumption that the + callable object defines an admissible order on monomials. + + If the ``gens`` input argument contains a list of generators, the + resulting key function can be used to sort SymPy ``Expr`` objects. + + """ + if order is None: + order = lex + + if isinstance(order, Symbol): + order = str(order) + + if isinstance(order, str): + try: + order = _monomial_key[order] + except KeyError: + raise ValueError("supported monomial orderings are 'lex', 'grlex' and 'grevlex', got %r" % order) + if hasattr(order, '__call__'): + if gens is not None: + def _order(expr): + return order(expr.as_poly(*gens).degree_list()) + return _order + return order + else: + raise ValueError("monomial ordering specification must be a string or a callable, got %s" % order) + +class _ItemGetter: + """Helper class to return a subsequence of values.""" + + def __init__(self, seq): + self.seq = tuple(seq) + + def __call__(self, m): + return tuple(m[idx] for idx in self.seq) + + def __eq__(self, other): + if not isinstance(other, _ItemGetter): + return False + return self.seq == other.seq + +def build_product_order(arg, gens): + """ + Build a monomial order on ``gens``. + + ``arg`` should be a tuple of iterables. The first element of each iterable + should be a string or monomial order (will be passed to monomial_key), + the others should be subsets of the generators. This function will build + the corresponding product order. + + For example, build a product of two grlex orders: + + >>> from sympy.polys.orderings import build_product_order + >>> from sympy.abc import x, y, z, t + + >>> O = build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) + >>> O((1, 2, 3, 4)) + ((3, (1, 2)), (7, (3, 4))) + + """ + gens2idx = {} + for i, g in enumerate(gens): + gens2idx[g] = i + order = [] + for expr in arg: + name = expr[0] + var = expr[1:] + + def makelambda(var): + return _ItemGetter(gens2idx[g] for g in var) + order.append((monomial_key(name), makelambda(var))) + return ProductOrder(*order) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/orthopolys.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/orthopolys.py new file mode 100644 index 0000000000000000000000000000000000000000..ee82457703a2be172951ee38e3cd67f221a438a0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/orthopolys.py @@ -0,0 +1,343 @@ +"""Efficient functions for generating orthogonal polynomials.""" +from sympy.core.symbol import Dummy +from sympy.polys.densearith import (dup_mul, dup_mul_ground, + dup_lshift, dup_sub, dup_add, dup_sub_term, dup_sub_ground, dup_sqr) +from sympy.polys.domains import ZZ, QQ +from sympy.polys.polytools import named_poly +from sympy.utilities import public + +def dup_jacobi(n, a, b, K): + """Low-level implementation of Jacobi polynomials.""" + if n < 1: + return [K.one] + m2, m1 = [K.one], [(a+b)/K(2) + K.one, (a-b)/K(2)] + for i in range(2, n+1): + den = K(i)*(a + b + i)*(a + b + K(2)*i - K(2)) + f0 = (a + b + K(2)*i - K.one) * (a*a - b*b) / (K(2)*den) + f1 = (a + b + K(2)*i - K.one) * (a + b + K(2)*i - K(2)) * (a + b + K(2)*i) / (K(2)*den) + f2 = (a + i - K.one)*(b + i - K.one)*(a + b + K(2)*i) / den + p0 = dup_mul_ground(m1, f0, K) + p1 = dup_mul_ground(dup_lshift(m1, 1, K), f1, K) + p2 = dup_mul_ground(m2, f2, K) + m2, m1 = m1, dup_sub(dup_add(p0, p1, K), p2, K) + return m1 + +@public +def jacobi_poly(n, a, b, x=None, polys=False): + r"""Generates the Jacobi polynomial `P_n^{(a,b)}(x)`. + + Parameters + ========== + + n : int + Degree of the polynomial. + a + Lower limit of minimal domain for the list of coefficients. + b + Upper limit of minimal domain for the list of coefficients. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + return named_poly(n, dup_jacobi, None, "Jacobi polynomial", (x, a, b), polys) + +def dup_gegenbauer(n, a, K): + """Low-level implementation of Gegenbauer polynomials.""" + if n < 1: + return [K.one] + m2, m1 = [K.one], [K(2)*a, K.zero] + for i in range(2, n+1): + p1 = dup_mul_ground(dup_lshift(m1, 1, K), K(2)*(a-K.one)/K(i) + K(2), K) + p2 = dup_mul_ground(m2, K(2)*(a-K.one)/K(i) + K.one, K) + m2, m1 = m1, dup_sub(p1, p2, K) + return m1 + +def gegenbauer_poly(n, a, x=None, polys=False): + r"""Generates the Gegenbauer polynomial `C_n^{(a)}(x)`. + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + a + Decides minimal domain for the list of coefficients. + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + return named_poly(n, dup_gegenbauer, None, "Gegenbauer polynomial", (x, a), polys) + +def dup_chebyshevt(n, K): + """Low-level implementation of Chebyshev polynomials of the first kind.""" + if n < 1: + return [K.one] + # When n is small, it is faster to directly calculate the recurrence relation. + if n < 64: # The threshold serves as a heuristic + return _dup_chebyshevt_rec(n, K) + return _dup_chebyshevt_prod(n, K) + +def _dup_chebyshevt_rec(n, K): + r""" Chebyshev polynomials of the first kind using recurrence. + + Explanation + =========== + + Chebyshev polynomials of the first kind are defined by the recurrence + relation: + + .. math:: + T_0(x) &= 1\\ + T_1(x) &= x\\ + T_n(x) &= 2xT_{n-1}(x) - T_{n-2}(x) + + This function calculates the Chebyshev polynomial of the first kind using + the above recurrence relation. + + Parameters + ========== + + n : int + n is a nonnegative integer. + K : domain + + """ + m2, m1 = [K.one], [K.one, K.zero] + for _ in range(n - 1): + m2, m1 = m1, dup_sub(dup_mul_ground(dup_lshift(m1, 1, K), K(2), K), m2, K) + return m1 + +def _dup_chebyshevt_prod(n, K): + r""" Chebyshev polynomials of the first kind using recursive products. + + Explanation + =========== + + Computes Chebyshev polynomials of the first kind using + + .. math:: + T_{2n}(x) &= 2T_n^2(x) - 1\\ + T_{2n+1}(x) &= 2T_{n+1}(x)T_n(x) - x + + This is faster than ``_dup_chebyshevt_rec`` for large ``n``. + + Parameters + ========== + + n : int + n is a nonnegative integer. + K : domain + + """ + m2, m1 = [K.one, K.zero], [K(2), K.zero, -K.one] + for i in bin(n)[3:]: + c = dup_sub_term(dup_mul_ground(dup_mul(m1, m2, K), K(2), K), K.one, 1, K) + if i == '1': + m2, m1 = c, dup_sub_ground(dup_mul_ground(dup_sqr(m1, K), K(2), K), K.one, K) + else: + m2, m1 = dup_sub_ground(dup_mul_ground(dup_sqr(m2, K), K(2), K), K.one, K), c + return m2 + +def dup_chebyshevu(n, K): + """Low-level implementation of Chebyshev polynomials of the second kind.""" + if n < 1: + return [K.one] + m2, m1 = [K.one], [K(2), K.zero] + for i in range(2, n+1): + m2, m1 = m1, dup_sub(dup_mul_ground(dup_lshift(m1, 1, K), K(2), K), m2, K) + return m1 + +@public +def chebyshevt_poly(n, x=None, polys=False): + r"""Generates the Chebyshev polynomial of the first kind `T_n(x)`. + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + return named_poly(n, dup_chebyshevt, ZZ, + "Chebyshev polynomial of the first kind", (x,), polys) + +@public +def chebyshevu_poly(n, x=None, polys=False): + r"""Generates the Chebyshev polynomial of the second kind `U_n(x)`. + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + return named_poly(n, dup_chebyshevu, ZZ, + "Chebyshev polynomial of the second kind", (x,), polys) + +def dup_hermite(n, K): + """Low-level implementation of Hermite polynomials.""" + if n < 1: + return [K.one] + m2, m1 = [K.one], [K(2), K.zero] + for i in range(2, n+1): + a = dup_lshift(m1, 1, K) + b = dup_mul_ground(m2, K(i-1), K) + m2, m1 = m1, dup_mul_ground(dup_sub(a, b, K), K(2), K) + return m1 + +def dup_hermite_prob(n, K): + """Low-level implementation of probabilist's Hermite polynomials.""" + if n < 1: + return [K.one] + m2, m1 = [K.one], [K.one, K.zero] + for i in range(2, n+1): + a = dup_lshift(m1, 1, K) + b = dup_mul_ground(m2, K(i-1), K) + m2, m1 = m1, dup_sub(a, b, K) + return m1 + +@public +def hermite_poly(n, x=None, polys=False): + r"""Generates the Hermite polynomial `H_n(x)`. + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + return named_poly(n, dup_hermite, ZZ, "Hermite polynomial", (x,), polys) + +@public +def hermite_prob_poly(n, x=None, polys=False): + r"""Generates the probabilist's Hermite polynomial `He_n(x)`. + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + return named_poly(n, dup_hermite_prob, ZZ, + "probabilist's Hermite polynomial", (x,), polys) + +def dup_legendre(n, K): + """Low-level implementation of Legendre polynomials.""" + if n < 1: + return [K.one] + m2, m1 = [K.one], [K.one, K.zero] + for i in range(2, n+1): + a = dup_mul_ground(dup_lshift(m1, 1, K), K(2*i-1, i), K) + b = dup_mul_ground(m2, K(i-1, i), K) + m2, m1 = m1, dup_sub(a, b, K) + return m1 + +@public +def legendre_poly(n, x=None, polys=False): + r"""Generates the Legendre polynomial `P_n(x)`. + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + return named_poly(n, dup_legendre, QQ, "Legendre polynomial", (x,), polys) + +def dup_laguerre(n, alpha, K): + """Low-level implementation of Laguerre polynomials.""" + m2, m1 = [K.zero], [K.one] + for i in range(1, n+1): + a = dup_mul(m1, [-K.one/K(i), (alpha-K.one)/K(i) + K(2)], K) + b = dup_mul_ground(m2, (alpha-K.one)/K(i) + K.one, K) + m2, m1 = m1, dup_sub(a, b, K) + return m1 + +@public +def laguerre_poly(n, x=None, alpha=0, polys=False): + r"""Generates the Laguerre polynomial `L_n^{(\alpha)}(x)`. + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + alpha : optional + Decides minimal domain for the list of coefficients. + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + return named_poly(n, dup_laguerre, None, "Laguerre polynomial", (x, alpha), polys) + +def dup_spherical_bessel_fn(n, K): + """Low-level implementation of fn(n, x).""" + if n < 1: + return [K.one, K.zero] + m2, m1 = [K.one], [K.one, K.zero] + for i in range(2, n+1): + m2, m1 = m1, dup_sub(dup_mul_ground(dup_lshift(m1, 1, K), K(2*i-1), K), m2, K) + return dup_lshift(m1, 1, K) + +def dup_spherical_bessel_fn_minus(n, K): + """Low-level implementation of fn(-n, x).""" + m2, m1 = [K.one, K.zero], [K.zero] + for i in range(2, n+1): + m2, m1 = m1, dup_sub(dup_mul_ground(dup_lshift(m1, 1, K), K(3-2*i), K), m2, K) + return m1 + +def spherical_bessel_fn(n, x=None, polys=False): + """ + Coefficients for the spherical Bessel functions. + + These are only needed in the jn() function. + + The coefficients are calculated from: + + fn(0, z) = 1/z + fn(1, z) = 1/z**2 + fn(n-1, z) + fn(n+1, z) == (2*n+1)/z * fn(n, z) + + Parameters + ========== + + n : int + Degree of the polynomial. + x : optional + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + + Examples + ======== + + >>> from sympy.polys.orthopolys import spherical_bessel_fn as fn + >>> from sympy import Symbol + >>> z = Symbol("z") + >>> fn(1, z) + z**(-2) + >>> fn(2, z) + -1/z + 3/z**3 + >>> fn(3, z) + -6/z**2 + 15/z**4 + >>> fn(4, z) + 1/z - 45/z**3 + 105/z**5 + + """ + if x is None: + x = Dummy("x") + f = dup_spherical_bessel_fn_minus if n < 0 else dup_spherical_bessel_fn + return named_poly(abs(n), f, ZZ, "", (QQ(1)/x,), polys) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/partfrac.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/partfrac.py new file mode 100644 index 0000000000000000000000000000000000000000..dedc1bf0fba42128e869303ed9b12c598640a36c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/partfrac.py @@ -0,0 +1,496 @@ +"""Algorithms for partial fraction decomposition of rational functions. """ + + +from sympy.core import S, Add, sympify, Function, Lambda, Dummy +from sympy.core.traversal import preorder_traversal +from sympy.polys import Poly, RootSum, cancel, factor +from sympy.polys.polyerrors import PolynomialError +from sympy.polys.polyoptions import allowed_flags, set_defaults +from sympy.polys.polytools import parallel_poly_from_expr +from sympy.utilities import numbered_symbols, take, xthreaded, public + + +@xthreaded +@public +def apart(f, x=None, full=False, **options): + """ + Compute partial fraction decomposition of a rational function. + + Given a rational function ``f``, computes the partial fraction + decomposition of ``f``. Two algorithms are available: One is based on the + undetermined coefficients method, the other is Bronstein's full partial + fraction decomposition algorithm. + + The undetermined coefficients method (selected by ``full=False``) uses + polynomial factorization (and therefore accepts the same options as + factor) for the denominator. Per default it works over the rational + numbers, therefore decomposition of denominators with non-rational roots + (e.g. irrational, complex roots) is not supported by default (see options + of factor). + + Bronstein's algorithm can be selected by using ``full=True`` and allows a + decomposition of denominators with non-rational roots. A human-readable + result can be obtained via ``doit()`` (see examples below). + + Examples + ======== + + >>> from sympy.polys.partfrac import apart + >>> from sympy.abc import x, y + + By default, using the undetermined coefficients method: + + >>> apart(y/(x + 2)/(x + 1), x) + -y/(x + 2) + y/(x + 1) + + The undetermined coefficients method does not provide a result when the + denominators roots are not rational: + + >>> apart(y/(x**2 + x + 1), x) + y/(x**2 + x + 1) + + You can choose Bronstein's algorithm by setting ``full=True``: + + >>> apart(y/(x**2 + x + 1), x, full=True) + RootSum(_w**2 + _w + 1, Lambda(_a, (-2*_a*y/3 - y/3)/(-_a + x))) + + Calling ``doit()`` yields a human-readable result: + + >>> apart(y/(x**2 + x + 1), x, full=True).doit() + (-y/3 - 2*y*(-1/2 - sqrt(3)*I/2)/3)/(x + 1/2 + sqrt(3)*I/2) + (-y/3 - + 2*y*(-1/2 + sqrt(3)*I/2)/3)/(x + 1/2 - sqrt(3)*I/2) + + + See Also + ======== + + apart_list, assemble_partfrac_list + """ + allowed_flags(options, []) + + f = sympify(f) + + if f.is_Atom: + return f + else: + P, Q = f.as_numer_denom() + + _options = options.copy() + options = set_defaults(options, extension=True) + try: + (P, Q), opt = parallel_poly_from_expr((P, Q), x, **options) + except PolynomialError as msg: + if f.is_commutative: + raise PolynomialError(msg) + # non-commutative + if f.is_Mul: + c, nc = f.args_cnc(split_1=False) + nc = f.func(*nc) + if c: + c = apart(f.func._from_args(c), x=x, full=full, **_options) + return c*nc + else: + return nc + elif f.is_Add: + c = [] + nc = [] + for i in f.args: + if i.is_commutative: + c.append(i) + else: + try: + nc.append(apart(i, x=x, full=full, **_options)) + except NotImplementedError: + nc.append(i) + return apart(f.func(*c), x=x, full=full, **_options) + f.func(*nc) + else: + reps = [] + pot = preorder_traversal(f) + next(pot) + for e in pot: + try: + reps.append((e, apart(e, x=x, full=full, **_options))) + pot.skip() # this was handled successfully + except NotImplementedError: + pass + return f.xreplace(dict(reps)) + + if P.is_multivariate: + fc = f.cancel() + if fc != f: + return apart(fc, x=x, full=full, **_options) + + raise NotImplementedError( + "multivariate partial fraction decomposition") + + common, P, Q = P.cancel(Q) + + poly, P = P.div(Q, auto=True) + P, Q = P.rat_clear_denoms(Q) + + if Q.degree() <= 1: + partial = P/Q + else: + if not full: + partial = apart_undetermined_coeffs(P, Q) + else: + partial = apart_full_decomposition(P, Q) + + terms = S.Zero + + for term in Add.make_args(partial): + if term.has(RootSum): + terms += term + else: + terms += factor(term) + + return common*(poly.as_expr() + terms) + + +def apart_undetermined_coeffs(P, Q): + """Partial fractions via method of undetermined coefficients. """ + X = numbered_symbols(cls=Dummy) + partial, symbols = [], [] + + _, factors = Q.factor_list() + + for f, k in factors: + n, q = f.degree(), Q + + for i in range(1, k + 1): + coeffs, q = take(X, n), q.quo(f) + partial.append((coeffs, q, f, i)) + symbols.extend(coeffs) + + dom = Q.get_domain().inject(*symbols) + F = Poly(0, Q.gen, domain=dom) + + for i, (coeffs, q, f, k) in enumerate(partial): + h = Poly(coeffs, Q.gen, domain=dom) + partial[i] = (h, f, k) + q = q.set_domain(dom) + F += h*q + + system, result = [], S.Zero + + for (k,), coeff in F.terms(): + system.append(coeff - P.nth(k)) + + from sympy.solvers import solve + solution = solve(system, symbols) + + for h, f, k in partial: + h = h.as_expr().subs(solution) + result += h/f.as_expr()**k + + return result + + +def apart_full_decomposition(P, Q): + """ + Bronstein's full partial fraction decomposition algorithm. + + Given a univariate rational function ``f``, performing only GCD + operations over the algebraic closure of the initial ground domain + of definition, compute full partial fraction decomposition with + fractions having linear denominators. + + Note that no factorization of the initial denominator of ``f`` is + performed. The final decomposition is formed in terms of a sum of + :class:`RootSum` instances. + + References + ========== + + .. [1] [Bronstein93]_ + + """ + return assemble_partfrac_list(apart_list(P/Q, P.gens[0])) + + +@public +def apart_list(f, x=None, dummies=None, **options): + """ + Compute partial fraction decomposition of a rational function + and return the result in structured form. + + Given a rational function ``f`` compute the partial fraction decomposition + of ``f``. Only Bronstein's full partial fraction decomposition algorithm + is supported by this method. The return value is highly structured and + perfectly suited for further algorithmic treatment rather than being + human-readable. The function returns a tuple holding three elements: + + * The first item is the common coefficient, free of the variable `x` used + for decomposition. (It is an element of the base field `K`.) + + * The second item is the polynomial part of the decomposition. This can be + the zero polynomial. (It is an element of `K[x]`.) + + * The third part itself is a list of quadruples. Each quadruple + has the following elements in this order: + + - The (not necessarily irreducible) polynomial `D` whose roots `w_i` appear + in the linear denominator of a bunch of related fraction terms. (This item + can also be a list of explicit roots. However, at the moment ``apart_list`` + never returns a result this way, but the related ``assemble_partfrac_list`` + function accepts this format as input.) + + - The numerator of the fraction, written as a function of the root `w` + + - The linear denominator of the fraction *excluding its power exponent*, + written as a function of the root `w`. + + - The power to which the denominator has to be raised. + + On can always rebuild a plain expression by using the function ``assemble_partfrac_list``. + + Examples + ======== + + A first example: + + >>> from sympy.polys.partfrac import apart_list, assemble_partfrac_list + >>> from sympy.abc import x, t + + >>> f = (2*x**3 - 2*x) / (x**2 - 2*x + 1) + >>> pfd = apart_list(f) + >>> pfd + (1, + Poly(2*x + 4, x, domain='ZZ'), + [(Poly(_w - 1, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + 2*x + 4 + 4/(x - 1) + + Second example: + + >>> f = (-2*x - 2*x**2) / (3*x**2 - 6*x) + >>> pfd = apart_list(f) + >>> pfd + (-1, + Poly(2/3, x, domain='QQ'), + [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 2), Lambda(_a, -_a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + -2/3 - 2/(x - 2) + + Another example, showing symbolic parameters: + + >>> pfd = apart_list(t/(x**2 + x + t), x) + >>> pfd + (1, + Poly(0, x, domain='ZZ[t]'), + [(Poly(_w**2 + _w + t, _w, domain='ZZ[t]'), + Lambda(_a, -2*_a*t/(4*t - 1) - t/(4*t - 1)), + Lambda(_a, -_a + x), + 1)]) + + >>> assemble_partfrac_list(pfd) + RootSum(_w**2 + _w + t, Lambda(_a, (-2*_a*t/(4*t - 1) - t/(4*t - 1))/(-_a + x))) + + This example is taken from Bronstein's original paper: + + >>> f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) + >>> pfd = apart_list(f) + >>> pfd + (1, + Poly(0, x, domain='ZZ'), + [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1), + (Poly(_w**2 - 1, _w, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2), + (Poly(_w + 1, _w, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2) + + See also + ======== + + apart, assemble_partfrac_list + + References + ========== + + .. [1] [Bronstein93]_ + + """ + allowed_flags(options, []) + + f = sympify(f) + + if f.is_Atom: + return f + else: + P, Q = f.as_numer_denom() + + options = set_defaults(options, extension=True) + (P, Q), opt = parallel_poly_from_expr((P, Q), x, **options) + + if P.is_multivariate: + raise NotImplementedError( + "multivariate partial fraction decomposition") + + common, P, Q = P.cancel(Q) + + poly, P = P.div(Q, auto=True) + P, Q = P.rat_clear_denoms(Q) + + polypart = poly + + if dummies is None: + def dummies(name): + d = Dummy(name) + while True: + yield d + + dummies = dummies("w") + + rationalpart = apart_list_full_decomposition(P, Q, dummies) + + return (common, polypart, rationalpart) + + +def apart_list_full_decomposition(P, Q, dummygen): + """ + Bronstein's full partial fraction decomposition algorithm. + + Given a univariate rational function ``f``, performing only GCD + operations over the algebraic closure of the initial ground domain + of definition, compute full partial fraction decomposition with + fractions having linear denominators. + + Note that no factorization of the initial denominator of ``f`` is + performed. The final decomposition is formed in terms of a sum of + :class:`RootSum` instances. + + References + ========== + + .. [1] [Bronstein93]_ + + """ + P_orig, Q_orig, x, U = P, Q, P.gen, [] + + u = Function('u')(x) + a = Dummy('a') + + partial = [] + + for d, n in Q.sqf_list_include(all=True): + b = d.as_expr() + U += [ u.diff(x, n - 1) ] + + h = cancel(P_orig/Q_orig.quo(d**n)) / u**n + + H, subs = [h], [] + + for j in range(1, n): + H += [ H[-1].diff(x) / j ] + + for j in range(1, n + 1): + subs += [ (U[j - 1], b.diff(x, j) / j) ] + + for j in range(0, n): + P, Q = cancel(H[j]).as_numer_denom() + + for i in range(0, j + 1): + P = P.subs(*subs[j - i]) + + Q = Q.subs(*subs[0]) + + P = Poly(P, x) + Q = Poly(Q, x) + + G = P.gcd(d) + D = d.quo(G) + + B, g = Q.half_gcdex(D) + b = (P * B.quo(g)).rem(D) + + Dw = D.subs(x, next(dummygen)) + numer = Lambda(a, b.as_expr().subs(x, a)) + denom = Lambda(a, (x - a)) + exponent = n-j + + partial.append((Dw, numer, denom, exponent)) + + return partial + + +@public +def assemble_partfrac_list(partial_list): + r"""Reassemble a full partial fraction decomposition + from a structured result obtained by the function ``apart_list``. + + Examples + ======== + + This example is taken from Bronstein's original paper: + + >>> from sympy.polys.partfrac import apart_list, assemble_partfrac_list + >>> from sympy.abc import x + + >>> f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) + >>> pfd = apart_list(f) + >>> pfd + (1, + Poly(0, x, domain='ZZ'), + [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1), + (Poly(_w**2 - 1, _w, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2), + (Poly(_w + 1, _w, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2) + + If we happen to know some roots we can provide them easily inside the structure: + + >>> pfd = apart_list(2/(x**2-2)) + >>> pfd + (1, + Poly(0, x, domain='ZZ'), + [(Poly(_w**2 - 2, _w, domain='ZZ'), + Lambda(_a, _a/2), + Lambda(_a, -_a + x), + 1)]) + + >>> pfda = assemble_partfrac_list(pfd) + >>> pfda + RootSum(_w**2 - 2, Lambda(_a, _a/(-_a + x)))/2 + + >>> pfda.doit() + -sqrt(2)/(2*(x + sqrt(2))) + sqrt(2)/(2*(x - sqrt(2))) + + >>> from sympy import Dummy, Poly, Lambda, sqrt + >>> a = Dummy("a") + >>> pfd = (1, Poly(0, x, domain='ZZ'), [([sqrt(2),-sqrt(2)], Lambda(a, a/2), Lambda(a, -a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + -sqrt(2)/(2*(x + sqrt(2))) + sqrt(2)/(2*(x - sqrt(2))) + + See Also + ======== + + apart, apart_list + """ + # Common factor + common = partial_list[0] + + # Polynomial part + polypart = partial_list[1] + pfd = polypart.as_expr() + + # Rational parts + for r, nf, df, ex in partial_list[2]: + if isinstance(r, Poly): + # Assemble in case the roots are given implicitly by a polynomials + an, nu = nf.variables, nf.expr + ad, de = df.variables, df.expr + # Hack to make dummies equal because Lambda created new Dummies + de = de.subs(ad[0], an[0]) + func = Lambda(tuple(an), nu/de**ex) + pfd += RootSum(r, func, auto=False, quadratic=False) + else: + # Assemble in case the roots are given explicitly by a list of algebraic numbers + for root in r: + pfd += nf(root)/df(root)**ex + + return common*pfd diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyclasses.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyclasses.py new file mode 100644 index 0000000000000000000000000000000000000000..1cc0e0f368ab07d64837e057b841ea991d9de223 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyclasses.py @@ -0,0 +1,3186 @@ +"""OO layer for several polynomial representations. """ + +from __future__ import annotations + +from sympy.external.gmpy import GROUND_TYPES + +from sympy.utilities.exceptions import sympy_deprecation_warning + +from sympy.core.numbers import oo +from sympy.core.sympify import CantSympify +from sympy.polys.polyutils import PicklableWithSlots, _sort_factors +from sympy.polys.domains import Domain, ZZ, QQ + +from sympy.polys.polyerrors import ( + CoercionFailed, + ExactQuotientFailed, + DomainError, + NotInvertible, +) + +from sympy.polys.densebasic import ( + ninf, + dmp_validate, + dup_normal, dmp_normal, + dup_convert, dmp_convert, + dmp_from_sympy, + dup_strip, + dmp_degree_in, + dmp_degree_list, + dmp_negative_p, + dmp_ground_LC, + dmp_ground_TC, + dmp_ground_nth, + dmp_one, dmp_ground, + dmp_zero, dmp_zero_p, dmp_one_p, dmp_ground_p, + dup_from_dict, dmp_from_dict, + dmp_to_dict, + dmp_deflate, + dmp_inject, dmp_eject, + dmp_terms_gcd, + dmp_list_terms, dmp_exclude, + dup_slice, dmp_slice_in, dmp_permute, + dmp_to_tuple,) + +from sympy.polys.densearith import ( + dmp_add_ground, + dmp_sub_ground, + dmp_mul_ground, + dmp_quo_ground, + dmp_exquo_ground, + dmp_abs, + dmp_neg, + dmp_add, + dmp_sub, + dmp_mul, + dmp_sqr, + dmp_pow, + dmp_pdiv, + dmp_prem, + dmp_pquo, + dmp_pexquo, + dmp_div, + dmp_rem, + dmp_quo, + dmp_exquo, + dmp_add_mul, dmp_sub_mul, + dmp_max_norm, + dmp_l1_norm, + dmp_l2_norm_squared) + +from sympy.polys.densetools import ( + dmp_clear_denoms, + dmp_integrate_in, + dmp_diff_in, + dmp_eval_in, + dup_revert, + dmp_ground_trunc, + dmp_ground_content, + dmp_ground_primitive, + dmp_ground_monic, + dmp_compose, + dup_decompose, + dup_shift, + dmp_shift, + dup_transform, + dmp_lift) + +from sympy.polys.euclidtools import ( + dup_half_gcdex, dup_gcdex, dup_invert, + dmp_subresultants, + dmp_resultant, + dmp_discriminant, + dmp_inner_gcd, + dmp_gcd, + dmp_lcm, + dmp_cancel) + +from sympy.polys.sqfreetools import ( + dup_gff_list, + dmp_norm, + dmp_sqf_p, + dmp_sqf_norm, + dmp_sqf_part, + dmp_sqf_list, dmp_sqf_list_include) + +from sympy.polys.factortools import ( + dup_cyclotomic_p, dmp_irreducible_p, + dmp_factor_list, dmp_factor_list_include) + +from sympy.polys.rootisolation import ( + dup_isolate_real_roots_sqf, + dup_isolate_real_roots, + dup_isolate_all_roots_sqf, + dup_isolate_all_roots, + dup_refine_real_root, + dup_count_real_roots, + dup_count_complex_roots, + dup_sturm, + dup_cauchy_upper_bound, + dup_cauchy_lower_bound, + dup_mignotte_sep_bound_squared) + +from sympy.polys.polyerrors import ( + UnificationFailed, + PolynomialError) + + +if GROUND_TYPES == 'flint': + import flint + def _supported_flint_domain(D): + return D.is_ZZ or D.is_QQ or D.is_FF and D._is_flint +else: + flint = None + def _supported_flint_domain(D): + return False + + +class DMP(CantSympify): + """Dense Multivariate Polynomials over `K`. """ + + __slots__ = () + + lev: int + dom: Domain + + def __new__(cls, rep, dom, lev=None): + + if lev is None: + rep, lev = dmp_validate(rep) + elif not isinstance(rep, list): + raise CoercionFailed("expected list, got %s" % type(rep)) + + return cls.new(rep, dom, lev) + + @classmethod + def new(cls, rep, dom, lev): + # It would be too slow to call _validate_args always at runtime. + # Ideally this checking would be handled by a static type checker. + # + #cls._validate_args(rep, dom, lev) + if flint is not None: + if lev == 0 and _supported_flint_domain(dom): + return DUP_Flint._new(rep, dom, lev) + + return DMP_Python._new(rep, dom, lev) + + @property + def rep(f): + """Get the representation of ``f``. """ + + sympy_deprecation_warning(""" + Accessing the ``DMP.rep`` attribute is deprecated. The internal + representation of ``DMP`` instances can now be ``DUP_Flint`` when the + ground types are ``flint``. In this case the ``DMP`` instance does not + have a ``rep`` attribute. Use ``DMP.to_list()`` instead. Using + ``DMP.to_list()`` also works in previous versions of SymPy. + """, + deprecated_since_version="1.13", + active_deprecations_target="dmp-rep", + ) + + return f.to_list() + + def to_best(f): + """Convert to DUP_Flint if possible. + + This method should be used when the domain or level is changed and it + potentially becomes possible to convert from DMP_Python to DUP_Flint. + """ + if flint is not None: + if isinstance(f, DMP_Python) and f.lev == 0 and _supported_flint_domain(f.dom): + return DUP_Flint.new(f._rep, f.dom, f.lev) + + return f + + @classmethod + def _validate_args(cls, rep, dom, lev): + assert isinstance(dom, Domain) + assert isinstance(lev, int) and lev >= 0 + + def validate_rep(rep, lev): + assert isinstance(rep, list) + if lev == 0: + assert all(dom.of_type(c) for c in rep) + else: + for r in rep: + validate_rep(r, lev - 1) + + validate_rep(rep, lev) + + @classmethod + def from_dict(cls, rep, lev, dom): + rep = dmp_from_dict(rep, lev, dom) + return cls.new(rep, dom, lev) + + @classmethod + def from_list(cls, rep, lev, dom): + """Create an instance of ``cls`` given a list of native coefficients. """ + return cls.new(dmp_convert(rep, lev, None, dom), dom, lev) + + @classmethod + def from_sympy_list(cls, rep, lev, dom): + """Create an instance of ``cls`` given a list of SymPy coefficients. """ + return cls.new(dmp_from_sympy(rep, lev, dom), dom, lev) + + @classmethod + def from_monoms_coeffs(cls, monoms, coeffs, lev, dom): + return cls(dict(list(zip(monoms, coeffs))), dom, lev) + + def convert(f, dom): + """Convert ``f`` to a ``DMP`` over the new domain. """ + if f.dom == dom: + return f + elif f.lev or flint is None: + return f._convert(dom) + elif isinstance(f, DUP_Flint): + if _supported_flint_domain(dom): + return f._convert(dom) + else: + return f.to_DMP_Python()._convert(dom) + elif isinstance(f, DMP_Python): + if _supported_flint_domain(dom): + return f._convert(dom).to_DUP_Flint() + else: + return f._convert(dom) + else: + raise RuntimeError("unreachable code") + + def _convert(f, dom): + raise NotImplementedError + + @classmethod + def zero(cls, lev, dom): + return DMP(dmp_zero(lev), dom, lev) + + @classmethod + def one(cls, lev, dom): + return DMP(dmp_one(lev, dom), dom, lev) + + def _one(f): + raise NotImplementedError + + def __repr__(f): + return "%s(%s, %s)" % (f.__class__.__name__, f.to_list(), f.dom) + + def __hash__(f): + return hash((f.__class__.__name__, f.to_tuple(), f.lev, f.dom)) + + def __getnewargs__(self): + return self.to_list(), self.dom, self.lev + + def ground_new(f, coeff): + """Construct a new ground instance of ``f``. """ + raise NotImplementedError + + def unify_DMP(f, g): + """Unify and return ``DMP`` instances of ``f`` and ``g``. """ + if not isinstance(g, DMP) or f.lev != g.lev: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + if f.dom != g.dom: + dom = f.dom.unify(g.dom) + f = f.convert(dom) + g = g.convert(dom) + + return f, g + + def to_dict(f, zero=False): + """Convert ``f`` to a dict representation with native coefficients. """ + return dmp_to_dict(f.to_list(), f.lev, f.dom, zero=zero) + + def to_sympy_dict(f, zero=False): + """Convert ``f`` to a dict representation with SymPy coefficients. """ + rep = f.to_dict(zero=zero) + + for k, v in rep.items(): + rep[k] = f.dom.to_sympy(v) + + return rep + + def to_sympy_list(f): + """Convert ``f`` to a list representation with SymPy coefficients. """ + def sympify_nested_list(rep): + out = [] + for val in rep: + if isinstance(val, list): + out.append(sympify_nested_list(val)) + else: + out.append(f.dom.to_sympy(val)) + return out + + return sympify_nested_list(f.to_list()) + + def to_list(f): + """Convert ``f`` to a list representation with native coefficients. """ + raise NotImplementedError + + def to_tuple(f): + """ + Convert ``f`` to a tuple representation with native coefficients. + + This is needed for hashing. + """ + raise NotImplementedError + + def to_ring(f): + """Make the ground domain a ring. """ + return f.convert(f.dom.get_ring()) + + def to_field(f): + """Make the ground domain a field. """ + return f.convert(f.dom.get_field()) + + def to_exact(f): + """Make the ground domain exact. """ + return f.convert(f.dom.get_exact()) + + def slice(f, m, n, j=0): + """Take a continuous subsequence of terms of ``f``. """ + if not f.lev and not j: + return f._slice(m, n) + else: + return f._slice_lev(m, n, j) + + def _slice(f, m, n): + raise NotImplementedError + + def _slice_lev(f, m, n, j): + raise NotImplementedError + + def coeffs(f, order=None): + """Returns all non-zero coefficients from ``f`` in lex order. """ + return [ c for _, c in f.terms(order=order) ] + + def monoms(f, order=None): + """Returns all non-zero monomials from ``f`` in lex order. """ + return [ m for m, _ in f.terms(order=order) ] + + def terms(f, order=None): + """Returns all non-zero terms from ``f`` in lex order. """ + if f.is_zero: + zero_monom = (0,)*(f.lev + 1) + return [(zero_monom, f.dom.zero)] + else: + return f._terms(order=order) + + def _terms(f, order=None): + raise NotImplementedError + + def all_coeffs(f): + """Returns all coefficients from ``f``. """ + if f.lev: + raise PolynomialError('multivariate polynomials not supported') + + if not f: + return [f.dom.zero] + else: + return list(f.to_list()) + + def all_monoms(f): + """Returns all monomials from ``f``. """ + if f.lev: + raise PolynomialError('multivariate polynomials not supported') + + n = f.degree() + + if n < 0: + return [(0,)] + else: + return [ (n - i,) for i, c in enumerate(f.to_list()) ] + + def all_terms(f): + """Returns all terms from a ``f``. """ + if f.lev: + raise PolynomialError('multivariate polynomials not supported') + + n = f.degree() + + if n < 0: + return [((0,), f.dom.zero)] + else: + return [ ((n - i,), c) for i, c in enumerate(f.to_list()) ] + + def lift(f): + """Convert algebraic coefficients to rationals. """ + return f._lift().to_best() + + def _lift(f): + raise NotImplementedError + + def deflate(f): + """Reduce degree of `f` by mapping `x_i^m` to `y_i`. """ + raise NotImplementedError + + def inject(f, front=False): + """Inject ground domain generators into ``f``. """ + raise NotImplementedError + + def eject(f, dom, front=False): + """Eject selected generators into the ground domain. """ + raise NotImplementedError + + def exclude(f): + r""" + Remove useless generators from ``f``. + + Returns the removed generators and the new excluded ``f``. + + Examples + ======== + + >>> from sympy.polys.polyclasses import DMP + >>> from sympy.polys.domains import ZZ + + >>> DMP([[[ZZ(1)]], [[ZZ(1)], [ZZ(2)]]], ZZ).exclude() + ([2], DMP_Python([[1], [1, 2]], ZZ)) + + """ + J, F = f._exclude() + return J, F.to_best() + + def _exclude(f): + raise NotImplementedError + + def permute(f, P): + r""" + Returns a polynomial in `K[x_{P(1)}, ..., x_{P(n)}]`. + + Examples + ======== + + >>> from sympy.polys.polyclasses import DMP + >>> from sympy.polys.domains import ZZ + + >>> DMP([[[ZZ(2)], [ZZ(1), ZZ(0)]], [[]]], ZZ).permute([1, 0, 2]) + DMP_Python([[[2], []], [[1, 0], []]], ZZ) + + >>> DMP([[[ZZ(2)], [ZZ(1), ZZ(0)]], [[]]], ZZ).permute([1, 2, 0]) + DMP_Python([[[1], []], [[2, 0], []]], ZZ) + + """ + return f._permute(P) + + def _permute(f, P): + raise NotImplementedError + + def terms_gcd(f): + """Remove GCD of terms from the polynomial ``f``. """ + raise NotImplementedError + + def abs(f): + """Make all coefficients in ``f`` positive. """ + raise NotImplementedError + + def neg(f): + """Negate all coefficients in ``f``. """ + raise NotImplementedError + + def add_ground(f, c): + """Add an element of the ground domain to ``f``. """ + return f._add_ground(f.dom.convert(c)) + + def sub_ground(f, c): + """Subtract an element of the ground domain from ``f``. """ + return f._sub_ground(f.dom.convert(c)) + + def mul_ground(f, c): + """Multiply ``f`` by a an element of the ground domain. """ + return f._mul_ground(f.dom.convert(c)) + + def quo_ground(f, c): + """Quotient of ``f`` by a an element of the ground domain. """ + return f._quo_ground(f.dom.convert(c)) + + def exquo_ground(f, c): + """Exact quotient of ``f`` by a an element of the ground domain. """ + return f._exquo_ground(f.dom.convert(c)) + + def add(f, g): + """Add two multivariate polynomials ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._add(G) + + def sub(f, g): + """Subtract two multivariate polynomials ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._sub(G) + + def mul(f, g): + """Multiply two multivariate polynomials ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._mul(G) + + def sqr(f): + """Square a multivariate polynomial ``f``. """ + return f._sqr() + + def pow(f, n): + """Raise ``f`` to a non-negative power ``n``. """ + if not isinstance(n, int): + raise TypeError("``int`` expected, got %s" % type(n)) + return f._pow(n) + + def pdiv(f, g): + """Polynomial pseudo-division of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._pdiv(G) + + def prem(f, g): + """Polynomial pseudo-remainder of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._prem(G) + + def pquo(f, g): + """Polynomial pseudo-quotient of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._pquo(G) + + def pexquo(f, g): + """Polynomial exact pseudo-quotient of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._pexquo(G) + + def div(f, g): + """Polynomial division with remainder of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._div(G) + + def rem(f, g): + """Computes polynomial remainder of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._rem(G) + + def quo(f, g): + """Computes polynomial quotient of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._quo(G) + + def exquo(f, g): + """Computes polynomial exact quotient of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._exquo(G) + + def _add_ground(f, c): + raise NotImplementedError + + def _sub_ground(f, c): + raise NotImplementedError + + def _mul_ground(f, c): + raise NotImplementedError + + def _quo_ground(f, c): + raise NotImplementedError + + def _exquo_ground(f, c): + raise NotImplementedError + + def _add(f, g): + raise NotImplementedError + + def _sub(f, g): + raise NotImplementedError + + def _mul(f, g): + raise NotImplementedError + + def _sqr(f): + raise NotImplementedError + + def _pow(f, n): + raise NotImplementedError + + def _pdiv(f, g): + raise NotImplementedError + + def _prem(f, g): + raise NotImplementedError + + def _pquo(f, g): + raise NotImplementedError + + def _pexquo(f, g): + raise NotImplementedError + + def _div(f, g): + raise NotImplementedError + + def _rem(f, g): + raise NotImplementedError + + def _quo(f, g): + raise NotImplementedError + + def _exquo(f, g): + raise NotImplementedError + + def degree(f, j=0): + """Returns the leading degree of ``f`` in ``x_j``. """ + if not isinstance(j, int): + raise TypeError("``int`` expected, got %s" % type(j)) + + return f._degree(j) + + def _degree(f, j): + raise NotImplementedError + + def degree_list(f): + """Returns a list of degrees of ``f``. """ + raise NotImplementedError + + def total_degree(f): + """Returns the total degree of ``f``. """ + raise NotImplementedError + + def homogenize(f, s): + """Return homogeneous polynomial of ``f``""" + td = f.total_degree() + result = {} + new_symbol = (s == len(f.terms()[0][0])) + for term in f.terms(): + d = sum(term[0]) + if d < td: + i = td - d + else: + i = 0 + if new_symbol: + result[term[0] + (i,)] = term[1] + else: + l = list(term[0]) + l[s] += i + result[tuple(l)] = term[1] + return DMP.from_dict(result, f.lev + int(new_symbol), f.dom) + + def homogeneous_order(f): + """Returns the homogeneous order of ``f``. """ + if f.is_zero: + return -oo + + monoms = f.monoms() + tdeg = sum(monoms[0]) + + for monom in monoms: + _tdeg = sum(monom) + + if _tdeg != tdeg: + return None + + return tdeg + + def LC(f): + """Returns the leading coefficient of ``f``. """ + raise NotImplementedError + + def TC(f): + """Returns the trailing coefficient of ``f``. """ + raise NotImplementedError + + def nth(f, *N): + """Returns the ``n``-th coefficient of ``f``. """ + if all(isinstance(n, int) for n in N): + return f._nth(N) + else: + raise TypeError("a sequence of integers expected") + + def _nth(f, N): + raise NotImplementedError + + def max_norm(f): + """Returns maximum norm of ``f``. """ + raise NotImplementedError + + def l1_norm(f): + """Returns l1 norm of ``f``. """ + raise NotImplementedError + + def l2_norm_squared(f): + """Return squared l2 norm of ``f``. """ + raise NotImplementedError + + def clear_denoms(f): + """Clear denominators, but keep the ground domain. """ + raise NotImplementedError + + def integrate(f, m=1, j=0): + """Computes the ``m``-th order indefinite integral of ``f`` in ``x_j``. """ + if not isinstance(m, int): + raise TypeError("``int`` expected, got %s" % type(m)) + + if not isinstance(j, int): + raise TypeError("``int`` expected, got %s" % type(j)) + + return f._integrate(m, j) + + def _integrate(f, m, j): + raise NotImplementedError + + def diff(f, m=1, j=0): + """Computes the ``m``-th order derivative of ``f`` in ``x_j``. """ + if not isinstance(m, int): + raise TypeError("``int`` expected, got %s" % type(m)) + + if not isinstance(j, int): + raise TypeError("``int`` expected, got %s" % type(j)) + + return f._diff(m, j) + + def _diff(f, m, j): + raise NotImplementedError + + def eval(f, a, j=0): + """Evaluates ``f`` at the given point ``a`` in ``x_j``. """ + if not isinstance(j, int): + raise TypeError("``int`` expected, got %s" % type(j)) + elif not (0 <= j <= f.lev): + raise ValueError("invalid variable index %s" % j) + + if f.lev: + return f._eval_lev(a, j) + else: + return f._eval(a) + + def _eval(f, a): + raise NotImplementedError + + def _eval_lev(f, a, j): + raise NotImplementedError + + def half_gcdex(f, g): + """Half extended Euclidean algorithm, if univariate. """ + F, G = f.unify_DMP(g) + + if F.lev: + raise ValueError('univariate polynomial expected') + + return F._half_gcdex(G) + + def _half_gcdex(f, g): + raise NotImplementedError + + def gcdex(f, g): + """Extended Euclidean algorithm, if univariate. """ + F, G = f.unify_DMP(g) + + if F.lev: + raise ValueError('univariate polynomial expected') + + if not F.dom.is_Field: + raise DomainError('ground domain must be a field') + + return F._gcdex(G) + + def _gcdex(f, g): + raise NotImplementedError + + def invert(f, g): + """Invert ``f`` modulo ``g``, if possible. """ + F, G = f.unify_DMP(g) + + if F.lev: + raise ValueError('univariate polynomial expected') + + return F._invert(G) + + def _invert(f, g): + raise NotImplementedError + + def revert(f, n): + """Compute ``f**(-1)`` mod ``x**n``. """ + if f.lev: + raise ValueError('univariate polynomial expected') + + return f._revert(n) + + def _revert(f, n): + raise NotImplementedError + + def subresultants(f, g): + """Computes subresultant PRS sequence of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._subresultants(G) + + def _subresultants(f, g): + raise NotImplementedError + + def resultant(f, g, includePRS=False): + """Computes resultant of ``f`` and ``g`` via PRS. """ + F, G = f.unify_DMP(g) + if includePRS: + return F._resultant_includePRS(G) + else: + return F._resultant(G) + + def _resultant(f, g, includePRS=False): + raise NotImplementedError + + def discriminant(f): + """Computes discriminant of ``f``. """ + raise NotImplementedError + + def cofactors(f, g): + """Returns GCD of ``f`` and ``g`` and their cofactors. """ + F, G = f.unify_DMP(g) + return F._cofactors(G) + + def _cofactors(f, g): + raise NotImplementedError + + def gcd(f, g): + """Returns polynomial GCD of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._gcd(G) + + def _gcd(f, g): + raise NotImplementedError + + def lcm(f, g): + """Returns polynomial LCM of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._lcm(G) + + def _lcm(f, g): + raise NotImplementedError + + def cancel(f, g, include=True): + """Cancel common factors in a rational function ``f/g``. """ + F, G = f.unify_DMP(g) + + if include: + return F._cancel_include(G) + else: + return F._cancel(G) + + def _cancel(f, g): + raise NotImplementedError + + def _cancel_include(f, g): + raise NotImplementedError + + def trunc(f, p): + """Reduce ``f`` modulo a constant ``p``. """ + return f._trunc(f.dom.convert(p)) + + def _trunc(f, p): + raise NotImplementedError + + def monic(f): + """Divides all coefficients by ``LC(f)``. """ + raise NotImplementedError + + def content(f): + """Returns GCD of polynomial coefficients. """ + raise NotImplementedError + + def primitive(f): + """Returns content and a primitive form of ``f``. """ + raise NotImplementedError + + def compose(f, g): + """Computes functional composition of ``f`` and ``g``. """ + F, G = f.unify_DMP(g) + return F._compose(G) + + def _compose(f, g): + raise NotImplementedError + + def decompose(f): + """Computes functional decomposition of ``f``. """ + if f.lev: + raise ValueError('univariate polynomial expected') + + return f._decompose() + + def _decompose(f): + raise NotImplementedError + + def shift(f, a): + """Efficiently compute Taylor shift ``f(x + a)``. """ + if f.lev: + raise ValueError('univariate polynomial expected') + + return f._shift(f.dom.convert(a)) + + def shift_list(f, a): + """Efficiently compute Taylor shift ``f(X + A)``. """ + a = [f.dom.convert(ai) for ai in a] + return f._shift_list(a) + + def _shift(f, a): + raise NotImplementedError + + def transform(f, p, q): + """Evaluate functional transformation ``q**n * f(p/q)``.""" + if f.lev: + raise ValueError('univariate polynomial expected') + + P, Q = p.unify_DMP(q) + F, P = f.unify_DMP(P) + F, Q = F.unify_DMP(Q) + + return F._transform(P, Q) + + def _transform(f, p, q): + raise NotImplementedError + + def sturm(f): + """Computes the Sturm sequence of ``f``. """ + if f.lev: + raise ValueError('univariate polynomial expected') + + return f._sturm() + + def _sturm(f): + raise NotImplementedError + + def cauchy_upper_bound(f): + """Computes the Cauchy upper bound on the roots of ``f``. """ + if f.lev: + raise ValueError('univariate polynomial expected') + + return f._cauchy_upper_bound() + + def _cauchy_upper_bound(f): + raise NotImplementedError + + def cauchy_lower_bound(f): + """Computes the Cauchy lower bound on the nonzero roots of ``f``. """ + if f.lev: + raise ValueError('univariate polynomial expected') + + return f._cauchy_lower_bound() + + def _cauchy_lower_bound(f): + raise NotImplementedError + + def mignotte_sep_bound_squared(f): + """Computes the squared Mignotte bound on root separations of ``f``. """ + if f.lev: + raise ValueError('univariate polynomial expected') + + return f._mignotte_sep_bound_squared() + + def _mignotte_sep_bound_squared(f): + raise NotImplementedError + + def gff_list(f): + """Computes greatest factorial factorization of ``f``. """ + if f.lev: + raise ValueError('univariate polynomial expected') + + return f._gff_list() + + def _gff_list(f): + raise NotImplementedError + + def norm(f): + """Computes ``Norm(f)``.""" + raise NotImplementedError + + def sqf_norm(f): + """Computes square-free norm of ``f``. """ + raise NotImplementedError + + def sqf_part(f): + """Computes square-free part of ``f``. """ + raise NotImplementedError + + def sqf_list(f, all=False): + """Returns a list of square-free factors of ``f``. """ + raise NotImplementedError + + def sqf_list_include(f, all=False): + """Returns a list of square-free factors of ``f``. """ + raise NotImplementedError + + def factor_list(f): + """Returns a list of irreducible factors of ``f``. """ + raise NotImplementedError + + def factor_list_include(f): + """Returns a list of irreducible factors of ``f``. """ + raise NotImplementedError + + def intervals(f, all=False, eps=None, inf=None, sup=None, fast=False, sqf=False): + """Compute isolating intervals for roots of ``f``. """ + if f.lev: + raise PolynomialError("Cannot isolate roots of a multivariate polynomial") + + if all and sqf: + return f._isolate_all_roots_sqf(eps=eps, inf=inf, sup=sup, fast=fast) + elif all and not sqf: + return f._isolate_all_roots(eps=eps, inf=inf, sup=sup, fast=fast) + elif not all and sqf: + return f._isolate_real_roots_sqf(eps=eps, inf=inf, sup=sup, fast=fast) + else: + return f._isolate_real_roots(eps=eps, inf=inf, sup=sup, fast=fast) + + def _isolate_all_roots(f, eps, inf, sup, fast): + raise NotImplementedError + + def _isolate_all_roots_sqf(f, eps, inf, sup, fast): + raise NotImplementedError + + def _isolate_real_roots(f, eps, inf, sup, fast): + raise NotImplementedError + + def _isolate_real_roots_sqf(f, eps, inf, sup, fast): + raise NotImplementedError + + def refine_root(f, s, t, eps=None, steps=None, fast=False): + """ + Refine an isolating interval to the given precision. + + ``eps`` should be a rational number. + + """ + if f.lev: + raise PolynomialError( + "Cannot refine a root of a multivariate polynomial") + + return f._refine_real_root(s, t, eps=eps, steps=steps, fast=fast) + + def _refine_real_root(f, s, t, eps, steps, fast): + raise NotImplementedError + + def count_real_roots(f, inf=None, sup=None): + """Return the number of real roots of ``f`` in ``[inf, sup]``. """ + raise NotImplementedError + + def count_complex_roots(f, inf=None, sup=None): + """Return the number of complex roots of ``f`` in ``[inf, sup]``. """ + raise NotImplementedError + + @property + def is_zero(f): + """Returns ``True`` if ``f`` is a zero polynomial. """ + raise NotImplementedError + + @property + def is_one(f): + """Returns ``True`` if ``f`` is a unit polynomial. """ + raise NotImplementedError + + @property + def is_ground(f): + """Returns ``True`` if ``f`` is an element of the ground domain. """ + raise NotImplementedError + + @property + def is_sqf(f): + """Returns ``True`` if ``f`` is a square-free polynomial. """ + raise NotImplementedError + + @property + def is_monic(f): + """Returns ``True`` if the leading coefficient of ``f`` is one. """ + raise NotImplementedError + + @property + def is_primitive(f): + """Returns ``True`` if the GCD of the coefficients of ``f`` is one. """ + raise NotImplementedError + + @property + def is_linear(f): + """Returns ``True`` if ``f`` is linear in all its variables. """ + raise NotImplementedError + + @property + def is_quadratic(f): + """Returns ``True`` if ``f`` is quadratic in all its variables. """ + raise NotImplementedError + + @property + def is_monomial(f): + """Returns ``True`` if ``f`` is zero or has only one term. """ + raise NotImplementedError + + @property + def is_homogeneous(f): + """Returns ``True`` if ``f`` is a homogeneous polynomial. """ + raise NotImplementedError + + @property + def is_irreducible(f): + """Returns ``True`` if ``f`` has no factors over its domain. """ + raise NotImplementedError + + @property + def is_cyclotomic(f): + """Returns ``True`` if ``f`` is a cyclotomic polynomial. """ + raise NotImplementedError + + def __abs__(f): + return f.abs() + + def __neg__(f): + return f.neg() + + def __add__(f, g): + if isinstance(g, DMP): + return f.add(g) + else: + try: + return f.add_ground(g) + except CoercionFailed: + return NotImplemented + + def __radd__(f, g): + return f.__add__(g) + + def __sub__(f, g): + if isinstance(g, DMP): + return f.sub(g) + else: + try: + return f.sub_ground(g) + except CoercionFailed: + return NotImplemented + + def __rsub__(f, g): + return (-f).__add__(g) + + def __mul__(f, g): + if isinstance(g, DMP): + return f.mul(g) + else: + try: + return f.mul_ground(g) + except CoercionFailed: + return NotImplemented + + def __rmul__(f, g): + return f.__mul__(g) + + def __truediv__(f, g): + if isinstance(g, DMP): + return f.exquo(g) + else: + try: + return f.mul_ground(g) + except CoercionFailed: + return NotImplemented + + def __rtruediv__(f, g): + if isinstance(g, DMP): + return g.exquo(f) + else: + try: + return f._one().mul_ground(g).exquo(f) + except CoercionFailed: + return NotImplemented + + def __pow__(f, n): + return f.pow(n) + + def __divmod__(f, g): + return f.div(g) + + def __mod__(f, g): + return f.rem(g) + + def __floordiv__(f, g): + if isinstance(g, DMP): + return f.quo(g) + else: + try: + return f.quo_ground(g) + except TypeError: + return NotImplemented + + def __eq__(f, g): + if f is g: + return True + if not isinstance(g, DMP): + return NotImplemented + try: + F, G = f.unify_DMP(g) + except UnificationFailed: + return False + else: + return F._strict_eq(G) + + def _strict_eq(f, g): + raise NotImplementedError + + def eq(f, g, strict=False): + if not strict: + return f == g + else: + return f._strict_eq(g) + + def ne(f, g, strict=False): + return not f.eq(g, strict=strict) + + def __lt__(f, g): + F, G = f.unify_DMP(g) + return F.to_list() < G.to_list() + + def __le__(f, g): + F, G = f.unify_DMP(g) + return F.to_list() <= G.to_list() + + def __gt__(f, g): + F, G = f.unify_DMP(g) + return F.to_list() > G.to_list() + + def __ge__(f, g): + F, G = f.unify_DMP(g) + return F.to_list() >= G.to_list() + + def __bool__(f): + return not f.is_zero + + +class DMP_Python(DMP): + """Dense Multivariate Polynomials over `K`. """ + + __slots__ = ('_rep', 'dom', 'lev') + + @classmethod + def _new(cls, rep, dom, lev): + obj = object.__new__(cls) + obj._rep = rep + obj.lev = lev + obj.dom = dom + return obj + + def _strict_eq(f, g): + if type(f) != type(g): + return False + return f.lev == g.lev and f.dom == g.dom and f._rep == g._rep + + def per(f, rep): + """Create a DMP out of the given representation. """ + return f._new(rep, f.dom, f.lev) + + def ground_new(f, coeff): + """Construct a new ground instance of ``f``. """ + return f._new(dmp_ground(coeff, f.lev), f.dom, f.lev) + + def _one(f): + return f.one(f.lev, f.dom) + + def unify(f, g): + """Unify representations of two multivariate polynomials. """ + # XXX: This function is not really used any more since there is + # unify_DMP now. + if not isinstance(g, DMP) or f.lev != g.lev: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + if f.dom == g.dom: + return f.lev, f.dom, f.per, f._rep, g._rep + else: + lev, dom = f.lev, f.dom.unify(g.dom) + + F = dmp_convert(f._rep, lev, f.dom, dom) + G = dmp_convert(g._rep, lev, g.dom, dom) + + def per(rep): + return f._new(rep, dom, lev) + + return lev, dom, per, F, G + + def to_DUP_Flint(f): + """Convert ``f`` to a Flint representation. """ + return DUP_Flint._new(f._rep, f.dom, f.lev) + + def to_list(f): + """Convert ``f`` to a list representation with native coefficients. """ + return list(f._rep) + + def to_tuple(f): + """Convert ``f`` to a tuple representation with native coefficients. """ + return dmp_to_tuple(f._rep, f.lev) + + def _convert(f, dom): + """Convert the ground domain of ``f``. """ + return f._new(dmp_convert(f._rep, f.lev, f.dom, dom), dom, f.lev) + + def _slice(f, m, n): + """Take a continuous subsequence of terms of ``f``. """ + rep = dup_slice(f._rep, m, n, f.dom) + return f._new(rep, f.dom, f.lev) + + def _slice_lev(f, m, n, j): + """Take a continuous subsequence of terms of ``f``. """ + rep = dmp_slice_in(f._rep, m, n, j, f.lev, f.dom) + return f._new(rep, f.dom, f.lev) + + def _terms(f, order=None): + """Returns all non-zero terms from ``f`` in lex order. """ + return dmp_list_terms(f._rep, f.lev, f.dom, order=order) + + def _lift(f): + """Convert algebraic coefficients to rationals. """ + r = dmp_lift(f._rep, f.lev, f.dom) + return f._new(r, f.dom.dom, f.lev) + + def deflate(f): + """Reduce degree of `f` by mapping `x_i^m` to `y_i`. """ + J, F = dmp_deflate(f._rep, f.lev, f.dom) + return J, f.per(F) + + def inject(f, front=False): + """Inject ground domain generators into ``f``. """ + F, lev = dmp_inject(f._rep, f.lev, f.dom, front=front) + # XXX: domain and level changed here + return f._new(F, f.dom.dom, lev) + + def eject(f, dom, front=False): + """Eject selected generators into the ground domain. """ + F = dmp_eject(f._rep, f.lev, dom, front=front) + # XXX: domain and level changed here + return f._new(F, dom, f.lev - len(dom.symbols)) + + def _exclude(f): + """Remove useless generators from ``f``. """ + J, F, u = dmp_exclude(f._rep, f.lev, f.dom) + # XXX: level changed here + return J, f._new(F, f.dom, u) + + def _permute(f, P): + """Returns a polynomial in `K[x_{P(1)}, ..., x_{P(n)}]`. """ + return f.per(dmp_permute(f._rep, P, f.lev, f.dom)) + + def terms_gcd(f): + """Remove GCD of terms from the polynomial ``f``. """ + J, F = dmp_terms_gcd(f._rep, f.lev, f.dom) + return J, f.per(F) + + def _add_ground(f, c): + """Add an element of the ground domain to ``f``. """ + return f.per(dmp_add_ground(f._rep, c, f.lev, f.dom)) + + def _sub_ground(f, c): + """Subtract an element of the ground domain from ``f``. """ + return f.per(dmp_sub_ground(f._rep, c, f.lev, f.dom)) + + def _mul_ground(f, c): + """Multiply ``f`` by a an element of the ground domain. """ + return f.per(dmp_mul_ground(f._rep, c, f.lev, f.dom)) + + def _quo_ground(f, c): + """Quotient of ``f`` by a an element of the ground domain. """ + return f.per(dmp_quo_ground(f._rep, c, f.lev, f.dom)) + + def _exquo_ground(f, c): + """Exact quotient of ``f`` by a an element of the ground domain. """ + return f.per(dmp_exquo_ground(f._rep, c, f.lev, f.dom)) + + def abs(f): + """Make all coefficients in ``f`` positive. """ + return f.per(dmp_abs(f._rep, f.lev, f.dom)) + + def neg(f): + """Negate all coefficients in ``f``. """ + return f.per(dmp_neg(f._rep, f.lev, f.dom)) + + def _add(f, g): + """Add two multivariate polynomials ``f`` and ``g``. """ + return f.per(dmp_add(f._rep, g._rep, f.lev, f.dom)) + + def _sub(f, g): + """Subtract two multivariate polynomials ``f`` and ``g``. """ + return f.per(dmp_sub(f._rep, g._rep, f.lev, f.dom)) + + def _mul(f, g): + """Multiply two multivariate polynomials ``f`` and ``g``. """ + return f.per(dmp_mul(f._rep, g._rep, f.lev, f.dom)) + + def sqr(f): + """Square a multivariate polynomial ``f``. """ + return f.per(dmp_sqr(f._rep, f.lev, f.dom)) + + def _pow(f, n): + """Raise ``f`` to a non-negative power ``n``. """ + return f.per(dmp_pow(f._rep, n, f.lev, f.dom)) + + def _pdiv(f, g): + """Polynomial pseudo-division of ``f`` and ``g``. """ + q, r = dmp_pdiv(f._rep, g._rep, f.lev, f.dom) + return f.per(q), f.per(r) + + def _prem(f, g): + """Polynomial pseudo-remainder of ``f`` and ``g``. """ + return f.per(dmp_prem(f._rep, g._rep, f.lev, f.dom)) + + def _pquo(f, g): + """Polynomial pseudo-quotient of ``f`` and ``g``. """ + return f.per(dmp_pquo(f._rep, g._rep, f.lev, f.dom)) + + def _pexquo(f, g): + """Polynomial exact pseudo-quotient of ``f`` and ``g``. """ + return f.per(dmp_pexquo(f._rep, g._rep, f.lev, f.dom)) + + def _div(f, g): + """Polynomial division with remainder of ``f`` and ``g``. """ + q, r = dmp_div(f._rep, g._rep, f.lev, f.dom) + return f.per(q), f.per(r) + + def _rem(f, g): + """Computes polynomial remainder of ``f`` and ``g``. """ + return f.per(dmp_rem(f._rep, g._rep, f.lev, f.dom)) + + def _quo(f, g): + """Computes polynomial quotient of ``f`` and ``g``. """ + return f.per(dmp_quo(f._rep, g._rep, f.lev, f.dom)) + + def _exquo(f, g): + """Computes polynomial exact quotient of ``f`` and ``g``. """ + return f.per(dmp_exquo(f._rep, g._rep, f.lev, f.dom)) + + def _degree(f, j=0): + """Returns the leading degree of ``f`` in ``x_j``. """ + return dmp_degree_in(f._rep, j, f.lev) + + def degree_list(f): + """Returns a list of degrees of ``f``. """ + return dmp_degree_list(f._rep, f.lev) + + def total_degree(f): + """Returns the total degree of ``f``. """ + return max(sum(m) for m in f.monoms()) + + def LC(f): + """Returns the leading coefficient of ``f``. """ + return dmp_ground_LC(f._rep, f.lev, f.dom) + + def TC(f): + """Returns the trailing coefficient of ``f``. """ + return dmp_ground_TC(f._rep, f.lev, f.dom) + + def _nth(f, N): + """Returns the ``n``-th coefficient of ``f``. """ + return dmp_ground_nth(f._rep, N, f.lev, f.dom) + + def max_norm(f): + """Returns maximum norm of ``f``. """ + return dmp_max_norm(f._rep, f.lev, f.dom) + + def l1_norm(f): + """Returns l1 norm of ``f``. """ + return dmp_l1_norm(f._rep, f.lev, f.dom) + + def l2_norm_squared(f): + """Return squared l2 norm of ``f``. """ + return dmp_l2_norm_squared(f._rep, f.lev, f.dom) + + def clear_denoms(f): + """Clear denominators, but keep the ground domain. """ + coeff, F = dmp_clear_denoms(f._rep, f.lev, f.dom) + return coeff, f.per(F) + + def _integrate(f, m=1, j=0): + """Computes the ``m``-th order indefinite integral of ``f`` in ``x_j``. """ + return f.per(dmp_integrate_in(f._rep, m, j, f.lev, f.dom)) + + def _diff(f, m=1, j=0): + """Computes the ``m``-th order derivative of ``f`` in ``x_j``. """ + return f.per(dmp_diff_in(f._rep, m, j, f.lev, f.dom)) + + def _eval(f, a): + return dmp_eval_in(f._rep, f.dom.convert(a), 0, f.lev, f.dom) + + def _eval_lev(f, a, j): + rep = dmp_eval_in(f._rep, f.dom.convert(a), j, f.lev, f.dom) + return f.new(rep, f.dom, f.lev - 1) + + def _half_gcdex(f, g): + """Half extended Euclidean algorithm, if univariate. """ + s, h = dup_half_gcdex(f._rep, g._rep, f.dom) + return f.per(s), f.per(h) + + def _gcdex(f, g): + """Extended Euclidean algorithm, if univariate. """ + s, t, h = dup_gcdex(f._rep, g._rep, f.dom) + return f.per(s), f.per(t), f.per(h) + + def _invert(f, g): + """Invert ``f`` modulo ``g``, if possible. """ + s = dup_invert(f._rep, g._rep, f.dom) + return f.per(s) + + def _revert(f, n): + """Compute ``f**(-1)`` mod ``x**n``. """ + return f.per(dup_revert(f._rep, n, f.dom)) + + def _subresultants(f, g): + """Computes subresultant PRS sequence of ``f`` and ``g``. """ + R = dmp_subresultants(f._rep, g._rep, f.lev, f.dom) + return list(map(f.per, R)) + + def _resultant_includePRS(f, g): + """Computes resultant of ``f`` and ``g`` via PRS. """ + res, R = dmp_resultant(f._rep, g._rep, f.lev, f.dom, includePRS=True) + if f.lev: + res = f.new(res, f.dom, f.lev - 1) + return res, list(map(f.per, R)) + + def _resultant(f, g): + res = dmp_resultant(f._rep, g._rep, f.lev, f.dom) + if f.lev: + res = f.new(res, f.dom, f.lev - 1) + return res + + def discriminant(f): + """Computes discriminant of ``f``. """ + res = dmp_discriminant(f._rep, f.lev, f.dom) + if f.lev: + res = f.new(res, f.dom, f.lev - 1) + return res + + def _cofactors(f, g): + """Returns GCD of ``f`` and ``g`` and their cofactors. """ + h, cff, cfg = dmp_inner_gcd(f._rep, g._rep, f.lev, f.dom) + return f.per(h), f.per(cff), f.per(cfg) + + def _gcd(f, g): + """Returns polynomial GCD of ``f`` and ``g``. """ + return f.per(dmp_gcd(f._rep, g._rep, f.lev, f.dom)) + + def _lcm(f, g): + """Returns polynomial LCM of ``f`` and ``g``. """ + return f.per(dmp_lcm(f._rep, g._rep, f.lev, f.dom)) + + def _cancel(f, g): + """Cancel common factors in a rational function ``f/g``. """ + cF, cG, F, G = dmp_cancel(f._rep, g._rep, f.lev, f.dom, include=False) + return cF, cG, f.per(F), f.per(G) + + def _cancel_include(f, g): + """Cancel common factors in a rational function ``f/g``. """ + F, G = dmp_cancel(f._rep, g._rep, f.lev, f.dom, include=True) + return f.per(F), f.per(G) + + def _trunc(f, p): + """Reduce ``f`` modulo a constant ``p``. """ + return f.per(dmp_ground_trunc(f._rep, p, f.lev, f.dom)) + + def monic(f): + """Divides all coefficients by ``LC(f)``. """ + return f.per(dmp_ground_monic(f._rep, f.lev, f.dom)) + + def content(f): + """Returns GCD of polynomial coefficients. """ + return dmp_ground_content(f._rep, f.lev, f.dom) + + def primitive(f): + """Returns content and a primitive form of ``f``. """ + cont, F = dmp_ground_primitive(f._rep, f.lev, f.dom) + return cont, f.per(F) + + def _compose(f, g): + """Computes functional composition of ``f`` and ``g``. """ + return f.per(dmp_compose(f._rep, g._rep, f.lev, f.dom)) + + def _decompose(f): + """Computes functional decomposition of ``f``. """ + return list(map(f.per, dup_decompose(f._rep, f.dom))) + + def _shift(f, a): + """Efficiently compute Taylor shift ``f(x + a)``. """ + return f.per(dup_shift(f._rep, a, f.dom)) + + def _shift_list(f, a): + """Efficiently compute Taylor shift ``f(X + A)``. """ + return f.per(dmp_shift(f._rep, a, f.lev, f.dom)) + + def _transform(f, p, q): + """Evaluate functional transformation ``q**n * f(p/q)``.""" + return f.per(dup_transform(f._rep, p._rep, q._rep, f.dom)) + + def _sturm(f): + """Computes the Sturm sequence of ``f``. """ + return list(map(f.per, dup_sturm(f._rep, f.dom))) + + def _cauchy_upper_bound(f): + """Computes the Cauchy upper bound on the roots of ``f``. """ + return dup_cauchy_upper_bound(f._rep, f.dom) + + def _cauchy_lower_bound(f): + """Computes the Cauchy lower bound on the nonzero roots of ``f``. """ + return dup_cauchy_lower_bound(f._rep, f.dom) + + def _mignotte_sep_bound_squared(f): + """Computes the squared Mignotte bound on root separations of ``f``. """ + return dup_mignotte_sep_bound_squared(f._rep, f.dom) + + def _gff_list(f): + """Computes greatest factorial factorization of ``f``. """ + return [ (f.per(g), k) for g, k in dup_gff_list(f._rep, f.dom) ] + + def norm(f): + """Computes ``Norm(f)``.""" + r = dmp_norm(f._rep, f.lev, f.dom) + return f.new(r, f.dom.dom, f.lev) + + def sqf_norm(f): + """Computes square-free norm of ``f``. """ + s, g, r = dmp_sqf_norm(f._rep, f.lev, f.dom) + return s, f.per(g), f.new(r, f.dom.dom, f.lev) + + def sqf_part(f): + """Computes square-free part of ``f``. """ + return f.per(dmp_sqf_part(f._rep, f.lev, f.dom)) + + def sqf_list(f, all=False): + """Returns a list of square-free factors of ``f``. """ + coeff, factors = dmp_sqf_list(f._rep, f.lev, f.dom, all) + return coeff, [ (f.per(g), k) for g, k in factors ] + + def sqf_list_include(f, all=False): + """Returns a list of square-free factors of ``f``. """ + factors = dmp_sqf_list_include(f._rep, f.lev, f.dom, all) + return [ (f.per(g), k) for g, k in factors ] + + def factor_list(f): + """Returns a list of irreducible factors of ``f``. """ + coeff, factors = dmp_factor_list(f._rep, f.lev, f.dom) + return coeff, [ (f.per(g), k) for g, k in factors ] + + def factor_list_include(f): + """Returns a list of irreducible factors of ``f``. """ + factors = dmp_factor_list_include(f._rep, f.lev, f.dom) + return [ (f.per(g), k) for g, k in factors ] + + def _isolate_real_roots(f, eps, inf, sup, fast): + return dup_isolate_real_roots(f._rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) + + def _isolate_real_roots_sqf(f, eps, inf, sup, fast): + return dup_isolate_real_roots_sqf(f._rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) + + def _isolate_all_roots(f, eps, inf, sup, fast): + return dup_isolate_all_roots(f._rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) + + def _isolate_all_roots_sqf(f, eps, inf, sup, fast): + return dup_isolate_all_roots_sqf(f._rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) + + def _refine_real_root(f, s, t, eps, steps, fast): + return dup_refine_real_root(f._rep, s, t, f.dom, eps=eps, steps=steps, fast=fast) + + def count_real_roots(f, inf=None, sup=None): + """Return the number of real roots of ``f`` in ``[inf, sup]``. """ + return dup_count_real_roots(f._rep, f.dom, inf=inf, sup=sup) + + def count_complex_roots(f, inf=None, sup=None): + """Return the number of complex roots of ``f`` in ``[inf, sup]``. """ + return dup_count_complex_roots(f._rep, f.dom, inf=inf, sup=sup) + + @property + def is_zero(f): + """Returns ``True`` if ``f`` is a zero polynomial. """ + return dmp_zero_p(f._rep, f.lev) + + @property + def is_one(f): + """Returns ``True`` if ``f`` is a unit polynomial. """ + return dmp_one_p(f._rep, f.lev, f.dom) + + @property + def is_ground(f): + """Returns ``True`` if ``f`` is an element of the ground domain. """ + return dmp_ground_p(f._rep, None, f.lev) + + @property + def is_sqf(f): + """Returns ``True`` if ``f`` is a square-free polynomial. """ + return dmp_sqf_p(f._rep, f.lev, f.dom) + + @property + def is_monic(f): + """Returns ``True`` if the leading coefficient of ``f`` is one. """ + return f.dom.is_one(dmp_ground_LC(f._rep, f.lev, f.dom)) + + @property + def is_primitive(f): + """Returns ``True`` if the GCD of the coefficients of ``f`` is one. """ + return f.dom.is_one(dmp_ground_content(f._rep, f.lev, f.dom)) + + @property + def is_linear(f): + """Returns ``True`` if ``f`` is linear in all its variables. """ + return all(sum(monom) <= 1 for monom in dmp_to_dict(f._rep, f.lev, f.dom).keys()) + + @property + def is_quadratic(f): + """Returns ``True`` if ``f`` is quadratic in all its variables. """ + return all(sum(monom) <= 2 for monom in dmp_to_dict(f._rep, f.lev, f.dom).keys()) + + @property + def is_monomial(f): + """Returns ``True`` if ``f`` is zero or has only one term. """ + return len(f.to_dict()) <= 1 + + @property + def is_homogeneous(f): + """Returns ``True`` if ``f`` is a homogeneous polynomial. """ + return f.homogeneous_order() is not None + + @property + def is_irreducible(f): + """Returns ``True`` if ``f`` has no factors over its domain. """ + return dmp_irreducible_p(f._rep, f.lev, f.dom) + + @property + def is_cyclotomic(f): + """Returns ``True`` if ``f`` is a cyclotomic polynomial. """ + if not f.lev: + return dup_cyclotomic_p(f._rep, f.dom) + else: + return False + + +class DUP_Flint(DMP): + """Dense Multivariate Polynomials over `K`. """ + + lev = 0 + + __slots__ = ('_rep', 'dom', '_cls') + + def __reduce__(self): + return self.__class__, (self.to_list(), self.dom, self.lev) + + @classmethod + def _new(cls, rep, dom, lev): + rep = cls._flint_poly(rep[::-1], dom, lev) + return cls.from_rep(rep, dom) + + def to_list(f): + """Convert ``f`` to a list representation with native coefficients. """ + return f._rep.coeffs()[::-1] + + @classmethod + def _flint_poly(cls, rep, dom, lev): + assert _supported_flint_domain(dom) + assert lev == 0 + flint_cls = cls._get_flint_poly_cls(dom) + return flint_cls(rep) + + @classmethod + def _get_flint_poly_cls(cls, dom): + if dom.is_ZZ: + return flint.fmpz_poly + elif dom.is_QQ: + return flint.fmpq_poly + elif dom.is_FF: + return dom._poly_ctx + else: + raise RuntimeError("Domain %s is not supported with flint" % dom) + + @classmethod + def from_rep(cls, rep, dom): + """Create a DMP from the given representation. """ + + if dom.is_ZZ: + assert isinstance(rep, flint.fmpz_poly) + _cls = flint.fmpz_poly + elif dom.is_QQ: + assert isinstance(rep, flint.fmpq_poly) + _cls = flint.fmpq_poly + elif dom.is_FF: + assert isinstance(rep, (flint.nmod_poly, flint.fmpz_mod_poly)) + c = dom.characteristic() + __cls = type(rep) + _cls = lambda e: __cls(e, c) + else: + raise RuntimeError("Domain %s is not supported with flint" % dom) + + obj = object.__new__(cls) + obj.dom = dom + obj._rep = rep + obj._cls = _cls + + return obj + + def _strict_eq(f, g): + if type(f) != type(g): + return False + return f.dom == g.dom and f._rep == g._rep + + def ground_new(f, coeff): + """Construct a new ground instance of ``f``. """ + return f.from_rep(f._cls([coeff]), f.dom) + + def _one(f): + return f.ground_new(f.dom.one) + + def unify(f, g): + """Unify representations of two polynomials. """ + raise RuntimeError + + def to_DMP_Python(f): + """Convert ``f`` to a Python native representation. """ + return DMP_Python._new(f.to_list(), f.dom, f.lev) + + def to_tuple(f): + """Convert ``f`` to a tuple representation with native coefficients. """ + return tuple(f.to_list()) + + def _convert(f, dom): + """Convert the ground domain of ``f``. """ + if dom == QQ and f.dom == ZZ: + return f.from_rep(flint.fmpq_poly(f._rep), dom) + elif _supported_flint_domain(dom) and _supported_flint_domain(f.dom): + # XXX: python-flint should provide a faster way to do this. + return f.to_DMP_Python()._convert(dom).to_DUP_Flint() + else: + raise RuntimeError(f"DUP_Flint: Cannot convert {f.dom} to {dom}") + + def _slice(f, m, n): + """Take a continuous subsequence of terms of ``f``. """ + coeffs = f._rep.coeffs()[m:n] + return f.from_rep(f._cls(coeffs), f.dom) + + def _slice_lev(f, m, n, j): + """Take a continuous subsequence of terms of ``f``. """ + # Only makes sense for multivariate polynomials + raise NotImplementedError + + def _terms(f, order=None): + """Returns all non-zero terms from ``f`` in lex order. """ + if order is None or order.alias == 'lex': + terms = [ ((n,), c) for n, c in enumerate(f._rep.coeffs()) if c ] + return terms[::-1] + else: + # XXX: InverseOrder (ilex) comes here. We could handle that case + # efficiently by reversing the coefficients but it is not clear + # how to test if the order is InverseOrder. + # + # Otherwise why would the order ever be different for univariate + # polynomials? + return f.to_DMP_Python()._terms(order=order) + + def _lift(f): + """Convert algebraic coefficients to rationals. """ + # This is for algebraic number fields which DUP_Flint does not support + raise NotImplementedError + + def deflate(f): + """Reduce degree of `f` by mapping `x_i^m` to `y_i`. """ + # XXX: Check because otherwise this segfaults with python-flint: + # + # >>> flint.fmpz_poly([]).deflation() + # Exception (fmpz_poly_deflate). Division by zero. + # Aborted (core dumped + # + if f.is_zero: + return (1,), f + g, n = f._rep.deflation() + return (n,), f.from_rep(g, f.dom) + + def inject(f, front=False): + """Inject ground domain generators into ``f``. """ + # Ground domain would need to be a poly ring + raise NotImplementedError + + def eject(f, dom, front=False): + """Eject selected generators into the ground domain. """ + # Only makes sense for multivariate polynomials + raise NotImplementedError + + def _exclude(f): + """Remove useless generators from ``f``. """ + # Only makes sense for multivariate polynomials + raise NotImplementedError + + def _permute(f, P): + """Returns a polynomial in `K[x_{P(1)}, ..., x_{P(n)}]`. """ + # Only makes sense for multivariate polynomials + raise NotImplementedError + + def terms_gcd(f): + """Remove GCD of terms from the polynomial ``f``. """ + # XXX: python-flint should have primitive, content, etc methods. + J, F = f.to_DMP_Python().terms_gcd() + return J, F.to_DUP_Flint() + + def _add_ground(f, c): + """Add an element of the ground domain to ``f``. """ + return f.from_rep(f._rep + c, f.dom) + + def _sub_ground(f, c): + """Subtract an element of the ground domain from ``f``. """ + return f.from_rep(f._rep - c, f.dom) + + def _mul_ground(f, c): + """Multiply ``f`` by a an element of the ground domain. """ + return f.from_rep(f._rep * c, f.dom) + + def _quo_ground(f, c): + """Quotient of ``f`` by a an element of the ground domain. """ + return f.from_rep(f._rep // c, f.dom) + + def _exquo_ground(f, c): + """Exact quotient of ``f`` by an element of the ground domain. """ + q, r = divmod(f._rep, c) + if r: + raise ExactQuotientFailed(f, c) + return f.from_rep(q, f.dom) + + def abs(f): + """Make all coefficients in ``f`` positive. """ + return f.to_DMP_Python().abs().to_DUP_Flint() + + def neg(f): + """Negate all coefficients in ``f``. """ + return f.from_rep(-f._rep, f.dom) + + def _add(f, g): + """Add two multivariate polynomials ``f`` and ``g``. """ + return f.from_rep(f._rep + g._rep, f.dom) + + def _sub(f, g): + """Subtract two multivariate polynomials ``f`` and ``g``. """ + return f.from_rep(f._rep - g._rep, f.dom) + + def _mul(f, g): + """Multiply two multivariate polynomials ``f`` and ``g``. """ + return f.from_rep(f._rep * g._rep, f.dom) + + def sqr(f): + """Square a multivariate polynomial ``f``. """ + return f.from_rep(f._rep ** 2, f.dom) + + def _pow(f, n): + """Raise ``f`` to a non-negative power ``n``. """ + return f.from_rep(f._rep ** n, f.dom) + + def _pdiv(f, g): + """Polynomial pseudo-division of ``f`` and ``g``. """ + d = f.degree() - g.degree() + 1 + q, r = divmod(g.LC()**d * f._rep, g._rep) + return f.from_rep(q, f.dom), f.from_rep(r, f.dom) + + def _prem(f, g): + """Polynomial pseudo-remainder of ``f`` and ``g``. """ + d = f.degree() - g.degree() + 1 + q = (g.LC()**d * f._rep) % g._rep + return f.from_rep(q, f.dom) + + def _pquo(f, g): + """Polynomial pseudo-quotient of ``f`` and ``g``. """ + d = f.degree() - g.degree() + 1 + r = (g.LC()**d * f._rep) // g._rep + return f.from_rep(r, f.dom) + + def _pexquo(f, g): + """Polynomial exact pseudo-quotient of ``f`` and ``g``. """ + d = f.degree() - g.degree() + 1 + q, r = divmod(g.LC()**d * f._rep, g._rep) + if r: + raise ExactQuotientFailed(f, g) + return f.from_rep(q, f.dom) + + def _div(f, g): + """Polynomial division with remainder of ``f`` and ``g``. """ + if f.dom.is_Field: + q, r = divmod(f._rep, g._rep) + return f.from_rep(q, f.dom), f.from_rep(r, f.dom) + else: + # XXX: python-flint defines division in ZZ[x] differently + q, r = f.to_DMP_Python()._div(g.to_DMP_Python()) + return q.to_DUP_Flint(), r.to_DUP_Flint() + + def _rem(f, g): + """Computes polynomial remainder of ``f`` and ``g``. """ + return f.from_rep(f._rep % g._rep, f.dom) + + def _quo(f, g): + """Computes polynomial quotient of ``f`` and ``g``. """ + return f.from_rep(f._rep // g._rep, f.dom) + + def _exquo(f, g): + """Computes polynomial exact quotient of ``f`` and ``g``. """ + q, r = f._div(g) + if r: + raise ExactQuotientFailed(f, g) + return q + + def _degree(f, j=0): + """Returns the leading degree of ``f`` in ``x_j``. """ + d = f._rep.degree() + if d == -1: + d = ninf + return d + + def degree_list(f): + """Returns a list of degrees of ``f``. """ + return ( f._degree() ,) + + def total_degree(f): + """Returns the total degree of ``f``. """ + return f._degree() + + def LC(f): + """Returns the leading coefficient of ``f``. """ + return f._rep[f._rep.degree()] + + def TC(f): + """Returns the trailing coefficient of ``f``. """ + return f._rep[0] + + def _nth(f, N): + """Returns the ``n``-th coefficient of ``f``. """ + [n] = N + return f._rep[n] + + def max_norm(f): + """Returns maximum norm of ``f``. """ + return f.to_DMP_Python().max_norm() + + def l1_norm(f): + """Returns l1 norm of ``f``. """ + return f.to_DMP_Python().l1_norm() + + def l2_norm_squared(f): + """Return squared l2 norm of ``f``. """ + return f.to_DMP_Python().l2_norm_squared() + + def clear_denoms(f): + """Clear denominators, but keep the ground domain. """ + R = f.dom + if R.is_QQ: + denom = f._rep.denom() + numer = f.from_rep(f._cls(f._rep.numer()), f.dom) + return denom, numer + elif R.is_ZZ or R.is_FiniteField: + return R.one, f + else: + raise NotImplementedError + + def _integrate(f, m=1, j=0): + """Computes the ``m``-th order indefinite integral of ``f`` in ``x_j``. """ + assert j == 0 + if f.dom.is_Field: + rep = f._rep + for i in range(m): + rep = rep.integral() + return f.from_rep(rep, f.dom) + else: + return f.to_DMP_Python()._integrate(m=m, j=j).to_DUP_Flint() + + def _diff(f, m=1, j=0): + """Computes the ``m``-th order derivative of ``f``. """ + assert j == 0 + rep = f._rep + for i in range(m): + rep = rep.derivative() + return f.from_rep(rep, f.dom) + + def _eval(f, a): + # XXX: This method is called with many different input types. Ideally + # we could use e.g. fmpz_poly.__call__ here but more thought needs to + # go into which types this is supposed to be called with and what types + # it should return. + return f.to_DMP_Python()._eval(a) + + def _eval_lev(f, a, j): + # Only makes sense for multivariate polynomials + raise NotImplementedError + + def _half_gcdex(f, g): + """Half extended Euclidean algorithm. """ + s, h = f.to_DMP_Python()._half_gcdex(g.to_DMP_Python()) + return s.to_DUP_Flint(), h.to_DUP_Flint() + + def _gcdex(f, g): + """Extended Euclidean algorithm. """ + h, s, t = f._rep.xgcd(g._rep) + return f.from_rep(s, f.dom), f.from_rep(t, f.dom), f.from_rep(h, f.dom) + + def _invert(f, g): + """Invert ``f`` modulo ``g``, if possible. """ + R = f.dom + if R.is_Field: + gcd, F_inv, _ = f._rep.xgcd(g._rep) + # XXX: Should be gcd != 1 but nmod_poly does not compare equal to + # other types. + if gcd != 0*gcd + 1: + raise NotInvertible("zero divisor") + return f.from_rep(F_inv, R) + else: + # fmpz_poly does not have xgcd or invert and this is not well + # defined in general. + return f.to_DMP_Python()._invert(g.to_DMP_Python()).to_DUP_Flint() + + def _revert(f, n): + """Compute ``f**(-1)`` mod ``x**n``. """ + # XXX: Use fmpz_series etc for reversion? + # Maybe python-flint should provide revert for fmpz_poly... + return f.to_DMP_Python()._revert(n).to_DUP_Flint() + + def _subresultants(f, g): + """Computes subresultant PRS sequence of ``f`` and ``g``. """ + # XXX: Maybe _fmpz_poly_pseudo_rem_cohen could be used... + R = f.to_DMP_Python()._subresultants(g.to_DMP_Python()) + return [ g.to_DUP_Flint() for g in R ] + + def _resultant_includePRS(f, g): + """Computes resultant of ``f`` and ``g`` via PRS. """ + # XXX: Maybe _fmpz_poly_pseudo_rem_cohen could be used... + res, R = f.to_DMP_Python()._resultant_includePRS(g.to_DMP_Python()) + return res, [ g.to_DUP_Flint() for g in R ] + + def _resultant(f, g): + """Computes resultant of ``f`` and ``g``. """ + # XXX: Use fmpz_mpoly etc when possible... + return f.to_DMP_Python()._resultant(g.to_DMP_Python()) + + def discriminant(f): + """Computes discriminant of ``f``. """ + # XXX: Use fmpz_mpoly etc when possible... + return f.to_DMP_Python().discriminant() + + def _cofactors(f, g): + """Returns GCD of ``f`` and ``g`` and their cofactors. """ + h = f.gcd(g) + return h, f.exquo(h), g.exquo(h) + + def _gcd(f, g): + """Returns polynomial GCD of ``f`` and ``g``. """ + return f.from_rep(f._rep.gcd(g._rep), f.dom) + + def _lcm(f, g): + """Returns polynomial LCM of ``f`` and ``g``. """ + # XXX: python-flint should have a lcm method + if not (f and g): + return f.ground_new(f.dom.zero) + + l = f._mul(g)._exquo(f._gcd(g)) + + if l.dom.is_Field: + l = l.monic() + elif l.LC() < 0: + l = l.neg() + + return l + + def _cancel(f, g): + """Cancel common factors in a rational function ``f/g``. """ + assert f.dom == g.dom + R = f.dom + + # Think carefully about how to handle denominators and coefficient + # canonicalisation if more domains are permitted... + assert R.is_ZZ or R.is_QQ or R.is_FiniteField + + if R.is_FiniteField: + h = f._gcd(g) + F, G = f.exquo(h), g.exquo(h) + return R.one, R.one, F, G + + if R.is_QQ: + cG, F = f.clear_denoms() + cF, G = g.clear_denoms() + else: + cG, F = R.one, f + cF, G = R.one, g + + cH = cF.gcd(cG) + cF, cG = cF // cH, cG // cH + + H = F._gcd(G) + F, G = F.exquo(H), G.exquo(H) + + f_neg = F.LC() < 0 + g_neg = G.LC() < 0 + + if f_neg and g_neg: + F, G = F.neg(), G.neg() + elif f_neg: + cF, F = -cF, F.neg() + elif g_neg: + cF, G = -cF, G.neg() + + return cF, cG, F, G + + def _cancel_include(f, g): + """Cancel common factors in a rational function ``f/g``. """ + cF, cG, F, G = f._cancel(g) + return F._mul_ground(cF), G._mul_ground(cG) + + def _trunc(f, p): + """Reduce ``f`` modulo a constant ``p``. """ + return f.to_DMP_Python()._trunc(p).to_DUP_Flint() + + def monic(f): + """Divides all coefficients by ``LC(f)``. """ + # XXX: python-flint should add monic + return f._exquo_ground(f.LC()) + + def content(f): + """Returns GCD of polynomial coefficients. """ + # XXX: python-flint should have a content method + return f.to_DMP_Python().content() + + def primitive(f): + """Returns content and a primitive form of ``f``. """ + cont = f.content() + if f.is_zero: + return f.dom.zero, f + prim = f._exquo_ground(cont) + return cont, prim + + def _compose(f, g): + """Computes functional composition of ``f`` and ``g``. """ + return f.from_rep(f._rep(g._rep), f.dom) + + def _decompose(f): + """Computes functional decomposition of ``f``. """ + return [ g.to_DUP_Flint() for g in f.to_DMP_Python()._decompose() ] + + def _shift(f, a): + """Efficiently compute Taylor shift ``f(x + a)``. """ + x_plus_a = f._cls([a, f.dom.one]) + return f.from_rep(f._rep(x_plus_a), f.dom) + + def _transform(f, p, q): + """Evaluate functional transformation ``q**n * f(p/q)``.""" + F, P, Q = f.to_DMP_Python(), p.to_DMP_Python(), q.to_DMP_Python() + return F.transform(P, Q).to_DUP_Flint() + + def _sturm(f): + """Computes the Sturm sequence of ``f``. """ + return [ g.to_DUP_Flint() for g in f.to_DMP_Python()._sturm() ] + + def _cauchy_upper_bound(f): + """Computes the Cauchy upper bound on the roots of ``f``. """ + return f.to_DMP_Python()._cauchy_upper_bound() + + def _cauchy_lower_bound(f): + """Computes the Cauchy lower bound on the nonzero roots of ``f``. """ + return f.to_DMP_Python()._cauchy_lower_bound() + + def _mignotte_sep_bound_squared(f): + """Computes the squared Mignotte bound on root separations of ``f``. """ + return f.to_DMP_Python()._mignotte_sep_bound_squared() + + def _gff_list(f): + """Computes greatest factorial factorization of ``f``. """ + F = f.to_DMP_Python() + return [ (g.to_DUP_Flint(), k) for g, k in F.gff_list() ] + + def norm(f): + """Computes ``Norm(f)``.""" + # This is for algebraic number fields which DUP_Flint does not support + raise NotImplementedError + + def sqf_norm(f): + """Computes square-free norm of ``f``. """ + # This is for algebraic number fields which DUP_Flint does not support + raise NotImplementedError + + def sqf_part(f): + """Computes square-free part of ``f``. """ + return f._exquo(f._gcd(f._diff())) + + def sqf_list(f, all=False): + """Returns a list of square-free factors of ``f``. """ + # XXX: python-flint should provide square free factorisation. + coeff, factors = f.to_DMP_Python().sqf_list(all=all) + return coeff, [ (g.to_DUP_Flint(), k) for g, k in factors ] + + def sqf_list_include(f, all=False): + """Returns a list of square-free factors of ``f``. """ + factors = f.to_DMP_Python().sqf_list_include(all=all) + return [ (g.to_DUP_Flint(), k) for g, k in factors ] + + def factor_list(f): + """Returns a list of irreducible factors of ``f``. """ + + if f.dom.is_ZZ or f.dom.is_FF: + # python-flint matches polys here + coeff, factors = f._rep.factor() + factors = [ (f.from_rep(g, f.dom), k) for g, k in factors ] + + elif f.dom.is_QQ: + # python-flint returns monic factors over QQ whereas polys returns + # denominator free factors. + coeff, factors = f._rep.factor() + factors_monic = [ (f.from_rep(g, f.dom), k) for g, k in factors ] + + # Absorb the denominators into coeff + factors = [] + for g, k in factors_monic: + d, g = g.clear_denoms() + coeff /= d**k + factors.append((g, k)) + + else: + # Check carefully when adding more domains here... + raise RuntimeError("Domain %s is not supported with flint" % f.dom) + + # We need to match the way that polys orders the factors + factors = f._sort_factors(factors) + + return coeff, factors + + def factor_list_include(f): + """Returns a list of irreducible factors of ``f``. """ + # XXX: factor_list_include seems to be broken in general: + # + # >>> Poly(2*(x - 1)**3, x).factor_list_include() + # [(Poly(2*x - 2, x, domain='ZZ'), 3)] + # + # Let's not try to implement it here. + factors = f.to_DMP_Python().factor_list_include() + return [ (g.to_DUP_Flint(), k) for g, k in factors ] + + def _sort_factors(f, factors): + """Sort a list of factors to canonical order. """ + # Convert the factors to lists and use _sort_factors from polys + factors = [ (g.to_list(), k) for g, k in factors ] + factors = _sort_factors(factors, multiple=True) + to_dup_flint = lambda g: f.from_rep(f._cls(g[::-1]), f.dom) + return [ (to_dup_flint(g), k) for g, k in factors ] + + def _isolate_real_roots(f, eps, inf, sup, fast): + return f.to_DMP_Python()._isolate_real_roots(eps, inf, sup, fast) + + def _isolate_real_roots_sqf(f, eps, inf, sup, fast): + return f.to_DMP_Python()._isolate_real_roots_sqf(eps, inf, sup, fast) + + def _isolate_all_roots(f, eps, inf, sup, fast): + # fmpz_poly and fmpq_poly have a complex_roots method that could be + # used here. It probably makes more sense to add analogous methods in + # python-flint though. + return f.to_DMP_Python()._isolate_all_roots(eps, inf, sup, fast) + + def _isolate_all_roots_sqf(f, eps, inf, sup, fast): + return f.to_DMP_Python()._isolate_all_roots_sqf(eps, inf, sup, fast) + + def _refine_real_root(f, s, t, eps, steps, fast): + return f.to_DMP_Python()._refine_real_root(s, t, eps, steps, fast) + + def count_real_roots(f, inf=None, sup=None): + """Return the number of real roots of ``f`` in ``[inf, sup]``. """ + return f.to_DMP_Python().count_real_roots(inf=inf, sup=sup) + + def count_complex_roots(f, inf=None, sup=None): + """Return the number of complex roots of ``f`` in ``[inf, sup]``. """ + return f.to_DMP_Python().count_complex_roots(inf=inf, sup=sup) + + @property + def is_zero(f): + """Returns ``True`` if ``f`` is a zero polynomial. """ + return not f._rep + + @property + def is_one(f): + """Returns ``True`` if ``f`` is a unit polynomial. """ + return f._rep == f.dom.one + + @property + def is_ground(f): + """Returns ``True`` if ``f`` is an element of the ground domain. """ + return f._rep.degree() <= 0 + + @property + def is_linear(f): + """Returns ``True`` if ``f`` is linear in all its variables. """ + return f._rep.degree() <= 1 + + @property + def is_quadratic(f): + """Returns ``True`` if ``f`` is quadratic in all its variables. """ + return f._rep.degree() <= 2 + + @property + def is_monomial(f): + """Returns ``True`` if ``f`` is zero or has only one term. """ + fr = f._rep + return fr.degree() < 0 or not any(fr[n] for n in range(fr.degree())) + + @property + def is_monic(f): + """Returns ``True`` if the leading coefficient of ``f`` is one. """ + return f.LC() == f.dom.one + + @property + def is_primitive(f): + """Returns ``True`` if the GCD of the coefficients of ``f`` is one. """ + return f.to_DMP_Python().is_primitive + + @property + def is_homogeneous(f): + """Returns ``True`` if ``f`` is a homogeneous polynomial. """ + return f.to_DMP_Python().is_homogeneous + + @property + def is_sqf(f): + """Returns ``True`` if ``f`` is a square-free polynomial. """ + g = f._rep.gcd(f._rep.derivative()) + return g.degree() <= 0 + + @property + def is_irreducible(f): + """Returns ``True`` if ``f`` has no factors over its domain. """ + _, factors = f._rep.factor() + if len(factors) == 0: + return True + elif len(factors) == 1: + return factors[0][1] == 1 + else: + return False + + @property + def is_cyclotomic(f): + """Returns ``True`` if ``f`` is a cyclotomic polynomial. """ + if f.dom.is_QQ: + try: + f = f.convert(ZZ) + except CoercionFailed: + return False + if f.dom.is_ZZ: + return bool(f._rep.is_cyclotomic()) + else: + # This is what dup_cyclotomic_p does... + return False + + +def init_normal_DMF(num, den, lev, dom): + return DMF(dmp_normal(num, lev, dom), + dmp_normal(den, lev, dom), dom, lev) + + +class DMF(PicklableWithSlots, CantSympify): + """Dense Multivariate Fractions over `K`. """ + + __slots__ = ('num', 'den', 'lev', 'dom') + + def __init__(self, rep, dom, lev=None): + num, den, lev = self._parse(rep, dom, lev) + num, den = dmp_cancel(num, den, lev, dom) + + self.num = num + self.den = den + self.lev = lev + self.dom = dom + + @classmethod + def new(cls, rep, dom, lev=None): + num, den, lev = cls._parse(rep, dom, lev) + + obj = object.__new__(cls) + + obj.num = num + obj.den = den + obj.lev = lev + obj.dom = dom + + return obj + + def ground_new(self, rep): + return self.new(rep, self.dom, self.lev) + + @classmethod + def _parse(cls, rep, dom, lev=None): + if isinstance(rep, tuple): + num, den = rep + + if lev is not None: + if isinstance(num, dict): + num = dmp_from_dict(num, lev, dom) + + if isinstance(den, dict): + den = dmp_from_dict(den, lev, dom) + else: + num, num_lev = dmp_validate(num) + den, den_lev = dmp_validate(den) + + if num_lev == den_lev: + lev = num_lev + else: + raise ValueError('inconsistent number of levels') + + if dmp_zero_p(den, lev): + raise ZeroDivisionError('fraction denominator') + + if dmp_zero_p(num, lev): + den = dmp_one(lev, dom) + else: + if dmp_negative_p(den, lev, dom): + num = dmp_neg(num, lev, dom) + den = dmp_neg(den, lev, dom) + else: + num = rep + + if lev is not None: + if isinstance(num, dict): + num = dmp_from_dict(num, lev, dom) + elif not isinstance(num, list): + num = dmp_ground(dom.convert(num), lev) + else: + num, lev = dmp_validate(num) + + den = dmp_one(lev, dom) + + return num, den, lev + + def __repr__(f): + return "%s((%s, %s), %s)" % (f.__class__.__name__, f.num, f.den, f.dom) + + def __hash__(f): + return hash((f.__class__.__name__, dmp_to_tuple(f.num, f.lev), + dmp_to_tuple(f.den, f.lev), f.lev, f.dom)) + + def poly_unify(f, g): + """Unify a multivariate fraction and a polynomial. """ + if not isinstance(g, DMP) or f.lev != g.lev: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + if f.dom == g.dom: + return (f.lev, f.dom, f.per, (f.num, f.den), g._rep) + else: + lev, dom = f.lev, f.dom.unify(g.dom) + + F = (dmp_convert(f.num, lev, f.dom, dom), + dmp_convert(f.den, lev, f.dom, dom)) + + G = dmp_convert(g._rep, lev, g.dom, dom) + + def per(num, den, cancel=True, kill=False, lev=lev): + if kill: + if not lev: + return num/den + else: + lev = lev - 1 + + if cancel: + num, den = dmp_cancel(num, den, lev, dom) + + return f.__class__.new((num, den), dom, lev) + + return lev, dom, per, F, G + + def frac_unify(f, g): + """Unify representations of two multivariate fractions. """ + if not isinstance(g, DMF) or f.lev != g.lev: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + if f.dom == g.dom: + return (f.lev, f.dom, f.per, (f.num, f.den), + (g.num, g.den)) + else: + lev, dom = f.lev, f.dom.unify(g.dom) + + F = (dmp_convert(f.num, lev, f.dom, dom), + dmp_convert(f.den, lev, f.dom, dom)) + + G = (dmp_convert(g.num, lev, g.dom, dom), + dmp_convert(g.den, lev, g.dom, dom)) + + def per(num, den, cancel=True, kill=False, lev=lev): + if kill: + if not lev: + return num/den + else: + lev = lev - 1 + + if cancel: + num, den = dmp_cancel(num, den, lev, dom) + + return f.__class__.new((num, den), dom, lev) + + return lev, dom, per, F, G + + def per(f, num, den, cancel=True, kill=False): + """Create a DMF out of the given representation. """ + lev, dom = f.lev, f.dom + + if kill: + if not lev: + return num/den + else: + lev -= 1 + + if cancel: + num, den = dmp_cancel(num, den, lev, dom) + + return f.__class__.new((num, den), dom, lev) + + def half_per(f, rep, kill=False): + """Create a DMP out of the given representation. """ + lev = f.lev + + if kill: + if not lev: + return rep + else: + lev -= 1 + + return DMP(rep, f.dom, lev) + + @classmethod + def zero(cls, lev, dom): + return cls.new(0, dom, lev) + + @classmethod + def one(cls, lev, dom): + return cls.new(1, dom, lev) + + def numer(f): + """Returns the numerator of ``f``. """ + return f.half_per(f.num) + + def denom(f): + """Returns the denominator of ``f``. """ + return f.half_per(f.den) + + def cancel(f): + """Remove common factors from ``f.num`` and ``f.den``. """ + return f.per(f.num, f.den) + + def neg(f): + """Negate all coefficients in ``f``. """ + return f.per(dmp_neg(f.num, f.lev, f.dom), f.den, cancel=False) + + def add_ground(f, c): + """Add an element of the ground domain to ``f``. """ + return f + f.ground_new(c) + + def add(f, g): + """Add two multivariate fractions ``f`` and ``g``. """ + if isinstance(g, DMP): + lev, dom, per, (F_num, F_den), G = f.poly_unify(g) + num, den = dmp_add_mul(F_num, F_den, G, lev, dom), F_den + else: + lev, dom, per, F, G = f.frac_unify(g) + (F_num, F_den), (G_num, G_den) = F, G + + num = dmp_add(dmp_mul(F_num, G_den, lev, dom), + dmp_mul(F_den, G_num, lev, dom), lev, dom) + den = dmp_mul(F_den, G_den, lev, dom) + + return per(num, den) + + def sub(f, g): + """Subtract two multivariate fractions ``f`` and ``g``. """ + if isinstance(g, DMP): + lev, dom, per, (F_num, F_den), G = f.poly_unify(g) + num, den = dmp_sub_mul(F_num, F_den, G, lev, dom), F_den + else: + lev, dom, per, F, G = f.frac_unify(g) + (F_num, F_den), (G_num, G_den) = F, G + + num = dmp_sub(dmp_mul(F_num, G_den, lev, dom), + dmp_mul(F_den, G_num, lev, dom), lev, dom) + den = dmp_mul(F_den, G_den, lev, dom) + + return per(num, den) + + def mul(f, g): + """Multiply two multivariate fractions ``f`` and ``g``. """ + if isinstance(g, DMP): + lev, dom, per, (F_num, F_den), G = f.poly_unify(g) + num, den = dmp_mul(F_num, G, lev, dom), F_den + else: + lev, dom, per, F, G = f.frac_unify(g) + (F_num, F_den), (G_num, G_den) = F, G + + num = dmp_mul(F_num, G_num, lev, dom) + den = dmp_mul(F_den, G_den, lev, dom) + + return per(num, den) + + def pow(f, n): + """Raise ``f`` to a non-negative power ``n``. """ + if isinstance(n, int): + num, den = f.num, f.den + if n < 0: + num, den, n = den, num, -n + return f.per(dmp_pow(num, n, f.lev, f.dom), + dmp_pow(den, n, f.lev, f.dom), cancel=False) + else: + raise TypeError("``int`` expected, got %s" % type(n)) + + def quo(f, g): + """Computes quotient of fractions ``f`` and ``g``. """ + if isinstance(g, DMP): + lev, dom, per, (F_num, F_den), G = f.poly_unify(g) + num, den = F_num, dmp_mul(F_den, G, lev, dom) + else: + lev, dom, per, F, G = f.frac_unify(g) + (F_num, F_den), (G_num, G_den) = F, G + + num = dmp_mul(F_num, G_den, lev, dom) + den = dmp_mul(F_den, G_num, lev, dom) + + return per(num, den) + + exquo = quo + + def invert(f, check=True): + """Computes inverse of a fraction ``f``. """ + return f.per(f.den, f.num, cancel=False) + + @property + def is_zero(f): + """Returns ``True`` if ``f`` is a zero fraction. """ + return dmp_zero_p(f.num, f.lev) + + @property + def is_one(f): + """Returns ``True`` if ``f`` is a unit fraction. """ + return dmp_one_p(f.num, f.lev, f.dom) and \ + dmp_one_p(f.den, f.lev, f.dom) + + def __neg__(f): + return f.neg() + + def __add__(f, g): + if isinstance(g, (DMP, DMF)): + return f.add(g) + elif g in f.dom: + return f.add_ground(f.dom.convert(g)) + + try: + return f.add(f.half_per(g)) + except (TypeError, CoercionFailed, NotImplementedError): + return NotImplemented + + def __radd__(f, g): + return f.__add__(g) + + def __sub__(f, g): + if isinstance(g, (DMP, DMF)): + return f.sub(g) + + try: + return f.sub(f.half_per(g)) + except (TypeError, CoercionFailed, NotImplementedError): + return NotImplemented + + def __rsub__(f, g): + return (-f).__add__(g) + + def __mul__(f, g): + if isinstance(g, (DMP, DMF)): + return f.mul(g) + + try: + return f.mul(f.half_per(g)) + except (TypeError, CoercionFailed, NotImplementedError): + return NotImplemented + + def __rmul__(f, g): + return f.__mul__(g) + + def __pow__(f, n): + return f.pow(n) + + def __truediv__(f, g): + if isinstance(g, (DMP, DMF)): + return f.quo(g) + + try: + return f.quo(f.half_per(g)) + except (TypeError, CoercionFailed, NotImplementedError): + return NotImplemented + + def __rtruediv__(self, g): + return self.invert(check=False)*g + + def __eq__(f, g): + try: + if isinstance(g, DMP): + _, _, _, (F_num, F_den), G = f.poly_unify(g) + + if f.lev == g.lev: + return dmp_one_p(F_den, f.lev, f.dom) and F_num == G + else: + _, _, _, F, G = f.frac_unify(g) + + if f.lev == g.lev: + return F == G + except UnificationFailed: + pass + + return False + + def __ne__(f, g): + try: + if isinstance(g, DMP): + _, _, _, (F_num, F_den), G = f.poly_unify(g) + + if f.lev == g.lev: + return not (dmp_one_p(F_den, f.lev, f.dom) and F_num == G) + else: + _, _, _, F, G = f.frac_unify(g) + + if f.lev == g.lev: + return F != G + except UnificationFailed: + pass + + return True + + def __lt__(f, g): + _, _, _, F, G = f.frac_unify(g) + return F < G + + def __le__(f, g): + _, _, _, F, G = f.frac_unify(g) + return F <= G + + def __gt__(f, g): + _, _, _, F, G = f.frac_unify(g) + return F > G + + def __ge__(f, g): + _, _, _, F, G = f.frac_unify(g) + return F >= G + + def __bool__(f): + return not dmp_zero_p(f.num, f.lev) + + +def init_normal_ANP(rep, mod, dom): + return ANP(dup_normal(rep, dom), + dup_normal(mod, dom), dom) + + +class ANP(CantSympify): + """Dense Algebraic Number Polynomials over a field. """ + + __slots__ = ('_rep', '_mod', 'dom') + + def __new__(cls, rep, mod, dom): + if isinstance(rep, DMP): + pass + elif type(rep) is dict: # don't use isinstance + rep = DMP(dup_from_dict(rep, dom), dom, 0) + else: + if isinstance(rep, list): + rep = [dom.convert(a) for a in rep] + else: + rep = [dom.convert(rep)] + rep = DMP(dup_strip(rep), dom, 0) + + if isinstance(mod, DMP): + pass + elif isinstance(mod, dict): + mod = DMP(dup_from_dict(mod, dom), dom, 0) + else: + mod = DMP(dup_strip(mod), dom, 0) + + return cls.new(rep, mod, dom) + + @classmethod + def new(cls, rep, mod, dom): + if not (rep.dom == mod.dom == dom): + raise RuntimeError("Inconsistent domain") + obj = super().__new__(cls) + obj._rep = rep + obj._mod = mod + obj.dom = dom + return obj + + # XXX: It should be possible to use __getnewargs__ rather than __reduce__ + # but it doesn't work for some reason. Probably this would be easier if + # python-flint supported pickling for polynomial types. + def __reduce__(self): + return ANP, (self.rep, self.mod, self.dom) + + @property + def rep(self): + return self._rep.to_list() + + @property + def mod(self): + return self.mod_to_list() + + def to_DMP(self): + return self._rep + + def mod_to_DMP(self): + return self._mod + + def per(f, rep): + return f.new(rep, f._mod, f.dom) + + def __repr__(f): + return "%s(%s, %s, %s)" % (f.__class__.__name__, f._rep.to_list(), f._mod.to_list(), f.dom) + + def __hash__(f): + return hash((f.__class__.__name__, f.to_tuple(), f._mod.to_tuple(), f.dom)) + + def convert(f, dom): + """Convert ``f`` to a ``ANP`` over a new domain. """ + if f.dom == dom: + return f + else: + return f.new(f._rep.convert(dom), f._mod.convert(dom), dom) + + def unify(f, g): + """Unify representations of two algebraic numbers. """ + + # XXX: This unify method is not used any more because unify_ANP is used + # instead. + + if not isinstance(g, ANP) or f.mod != g.mod: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + if f.dom == g.dom: + return f.dom, f.per, f.rep, g.rep, f.mod + else: + dom = f.dom.unify(g.dom) + + F = dup_convert(f.rep, f.dom, dom) + G = dup_convert(g.rep, g.dom, dom) + + if dom != f.dom and dom != g.dom: + mod = dup_convert(f.mod, f.dom, dom) + else: + if dom == f.dom: + mod = f.mod + else: + mod = g.mod + + per = lambda rep: ANP(rep, mod, dom) + + return dom, per, F, G, mod + + def unify_ANP(f, g): + """Unify and return ``DMP`` instances of ``f`` and ``g``. """ + if not isinstance(g, ANP) or f._mod != g._mod: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + # The domain is almost always QQ but there are some tests involving ZZ + if f.dom != g.dom: + dom = f.dom.unify(g.dom) + f = f.convert(dom) + g = g.convert(dom) + + return f._rep, g._rep, f._mod, f.dom + + @classmethod + def zero(cls, mod, dom): + return ANP(0, mod, dom) + + @classmethod + def one(cls, mod, dom): + return ANP(1, mod, dom) + + def to_dict(f): + """Convert ``f`` to a dict representation with native coefficients. """ + return f._rep.to_dict() + + def to_sympy_dict(f): + """Convert ``f`` to a dict representation with SymPy coefficients. """ + rep = dmp_to_dict(f.rep, 0, f.dom) + + for k, v in rep.items(): + rep[k] = f.dom.to_sympy(v) + + return rep + + def to_list(f): + """Convert ``f`` to a list representation with native coefficients. """ + return f._rep.to_list() + + def mod_to_list(f): + """Return ``f.mod`` as a list with native coefficients. """ + return f._mod.to_list() + + def to_sympy_list(f): + """Convert ``f`` to a list representation with SymPy coefficients. """ + return [ f.dom.to_sympy(c) for c in f.to_list() ] + + def to_tuple(f): + """ + Convert ``f`` to a tuple representation with native coefficients. + + This is needed for hashing. + """ + return f._rep.to_tuple() + + @classmethod + def from_list(cls, rep, mod, dom): + return ANP(dup_strip(list(map(dom.convert, rep))), mod, dom) + + def add_ground(f, c): + """Add an element of the ground domain to ``f``. """ + return f.per(f._rep.add_ground(c)) + + def sub_ground(f, c): + """Subtract an element of the ground domain from ``f``. """ + return f.per(f._rep.sub_ground(c)) + + def mul_ground(f, c): + """Multiply ``f`` by an element of the ground domain. """ + return f.per(f._rep.mul_ground(c)) + + def quo_ground(f, c): + """Quotient of ``f`` by an element of the ground domain. """ + return f.per(f._rep.quo_ground(c)) + + def neg(f): + return f.per(f._rep.neg()) + + def add(f, g): + F, G, mod, dom = f.unify_ANP(g) + return f.new(F.add(G), mod, dom) + + def sub(f, g): + F, G, mod, dom = f.unify_ANP(g) + return f.new(F.sub(G), mod, dom) + + def mul(f, g): + F, G, mod, dom = f.unify_ANP(g) + return f.new(F.mul(G).rem(mod), mod, dom) + + def pow(f, n): + """Raise ``f`` to a non-negative power ``n``. """ + if not isinstance(n, int): + raise TypeError("``int`` expected, got %s" % type(n)) + + mod = f._mod + F = f._rep + + if n < 0: + F, n = F.invert(mod), -n + + # XXX: Need a pow_mod method for DMP + return f.new(F.pow(n).rem(f._mod), mod, f.dom) + + def exquo(f, g): + F, G, mod, dom = f.unify_ANP(g) + return f.new(F.mul(G.invert(mod)).rem(mod), mod, dom) + + def div(f, g): + return f.exquo(g), f.zero(f._mod, f.dom) + + def quo(f, g): + return f.exquo(g) + + def rem(f, g): + F, G, mod, dom = f.unify_ANP(g) + s, h = F.half_gcdex(G) + + if h.is_one: + return f.zero(mod, dom) + else: + raise NotInvertible("zero divisor") + + def LC(f): + """Returns the leading coefficient of ``f``. """ + return f._rep.LC() + + def TC(f): + """Returns the trailing coefficient of ``f``. """ + return f._rep.TC() + + @property + def is_zero(f): + """Returns ``True`` if ``f`` is a zero algebraic number. """ + return f._rep.is_zero + + @property + def is_one(f): + """Returns ``True`` if ``f`` is a unit algebraic number. """ + return f._rep.is_one + + @property + def is_ground(f): + """Returns ``True`` if ``f`` is an element of the ground domain. """ + return f._rep.is_ground + + def __pos__(f): + return f + + def __neg__(f): + return f.neg() + + def __add__(f, g): + if isinstance(g, ANP): + return f.add(g) + try: + g = f.dom.convert(g) + except CoercionFailed: + return NotImplemented + else: + return f.add_ground(g) + + def __radd__(f, g): + return f.__add__(g) + + def __sub__(f, g): + if isinstance(g, ANP): + return f.sub(g) + try: + g = f.dom.convert(g) + except CoercionFailed: + return NotImplemented + else: + return f.sub_ground(g) + + def __rsub__(f, g): + return (-f).__add__(g) + + def __mul__(f, g): + if isinstance(g, ANP): + return f.mul(g) + try: + g = f.dom.convert(g) + except CoercionFailed: + return NotImplemented + else: + return f.mul_ground(g) + + def __rmul__(f, g): + return f.__mul__(g) + + def __pow__(f, n): + return f.pow(n) + + def __divmod__(f, g): + return f.div(g) + + def __mod__(f, g): + return f.rem(g) + + def __truediv__(f, g): + if isinstance(g, ANP): + return f.quo(g) + try: + g = f.dom.convert(g) + except CoercionFailed: + return NotImplemented + else: + return f.quo_ground(g) + + def __eq__(f, g): + try: + F, G, _, _ = f.unify_ANP(g) + except UnificationFailed: + return NotImplemented + return F == G + + def __ne__(f, g): + try: + F, G, _, _ = f.unify_ANP(g) + except UnificationFailed: + return NotImplemented + return F != G + + def __lt__(f, g): + F, G, _, _ = f.unify_ANP(g) + return F < G + + def __le__(f, g): + F, G, _, _ = f.unify_ANP(g) + return F <= G + + def __gt__(f, g): + F, G, _, _ = f.unify_ANP(g) + return F > G + + def __ge__(f, g): + F, G, _, _ = f.unify_ANP(g) + return F >= G + + def __bool__(f): + return bool(f._rep) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyconfig.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyconfig.py new file mode 100644 index 0000000000000000000000000000000000000000..75731f7ac4e4f8784ff8f999cc3537bfa3c6659a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyconfig.py @@ -0,0 +1,67 @@ +"""Configuration utilities for polynomial manipulation algorithms. """ + + +from contextlib import contextmanager + +_default_config = { + 'USE_COLLINS_RESULTANT': False, + 'USE_SIMPLIFY_GCD': True, + 'USE_HEU_GCD': True, + + 'USE_IRREDUCIBLE_IN_FACTOR': False, + 'USE_CYCLOTOMIC_FACTOR': True, + + 'EEZ_RESTART_IF_NEEDED': True, + 'EEZ_NUMBER_OF_CONFIGS': 3, + 'EEZ_NUMBER_OF_TRIES': 5, + 'EEZ_MODULUS_STEP': 2, + + 'GF_IRRED_METHOD': 'rabin', + 'GF_FACTOR_METHOD': 'zassenhaus', + + 'GROEBNER': 'buchberger', +} + +_current_config = {} + +@contextmanager +def using(**kwargs): + for k, v in kwargs.items(): + setup(k, v) + + yield + + for k in kwargs.keys(): + setup(k) + +def setup(key, value=None): + """Assign a value to (or reset) a configuration item. """ + key = key.upper() + + if value is not None: + _current_config[key] = value + else: + _current_config[key] = _default_config[key] + + +def query(key): + """Ask for a value of the given configuration item. """ + return _current_config.get(key.upper(), None) + + +def configure(): + """Initialized configuration of polys module. """ + from os import getenv + + for key, default in _default_config.items(): + value = getenv('SYMPY_' + key) + + if value is not None: + try: + _current_config[key] = eval(value) + except NameError: + _current_config[key] = value + else: + _current_config[key] = default + +configure() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyerrors.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyerrors.py new file mode 100644 index 0000000000000000000000000000000000000000..79385ffaf6746386f8f108c3e02992dcaf4a4f55 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyerrors.py @@ -0,0 +1,183 @@ +"""Definitions of common exceptions for `polys` module. """ + + +from sympy.utilities import public + +@public +class BasePolynomialError(Exception): + """Base class for polynomial related exceptions. """ + + def new(self, *args): + raise NotImplementedError("abstract base class") + +@public +class ExactQuotientFailed(BasePolynomialError): + + def __init__(self, f, g, dom=None): + self.f, self.g, self.dom = f, g, dom + + def __str__(self): # pragma: no cover + from sympy.printing.str import sstr + + if self.dom is None: + return "%s does not divide %s" % (sstr(self.g), sstr(self.f)) + else: + return "%s does not divide %s in %s" % (sstr(self.g), sstr(self.f), sstr(self.dom)) + + def new(self, f, g): + return self.__class__(f, g, self.dom) + +@public +class PolynomialDivisionFailed(BasePolynomialError): + + def __init__(self, f, g, domain): + self.f = f + self.g = g + self.domain = domain + + def __str__(self): + if self.domain.is_EX: + msg = "You may want to use a different simplification algorithm. Note " \ + "that in general it's not possible to guarantee to detect zero " \ + "in this domain." + elif not self.domain.is_Exact: + msg = "Your working precision or tolerance of computations may be set " \ + "improperly. Adjust those parameters of the coefficient domain " \ + "and try again." + else: + msg = "Zero detection is guaranteed in this coefficient domain. This " \ + "may indicate a bug in SymPy or the domain is user defined and " \ + "doesn't implement zero detection properly." + + return "couldn't reduce degree in a polynomial division algorithm when " \ + "dividing %s by %s. This can happen when it's not possible to " \ + "detect zero in the coefficient domain. The domain of computation " \ + "is %s. %s" % (self.f, self.g, self.domain, msg) + +@public +class OperationNotSupported(BasePolynomialError): + + def __init__(self, poly, func): + self.poly = poly + self.func = func + + def __str__(self): # pragma: no cover + return "`%s` operation not supported by %s representation" % (self.func, self.poly.rep.__class__.__name__) + +@public +class HeuristicGCDFailed(BasePolynomialError): + pass + +class ModularGCDFailed(BasePolynomialError): + pass + +@public +class HomomorphismFailed(BasePolynomialError): + pass + +@public +class IsomorphismFailed(BasePolynomialError): + pass + +@public +class ExtraneousFactors(BasePolynomialError): + pass + +@public +class EvaluationFailed(BasePolynomialError): + pass + +@public +class RefinementFailed(BasePolynomialError): + pass + +@public +class CoercionFailed(BasePolynomialError): + pass + +@public +class NotInvertible(BasePolynomialError): + pass + +@public +class NotReversible(BasePolynomialError): + pass + +@public +class NotAlgebraic(BasePolynomialError): + pass + +@public +class DomainError(BasePolynomialError): + pass + +@public +class PolynomialError(BasePolynomialError): + pass + +@public +class UnificationFailed(BasePolynomialError): + pass + +@public +class UnsolvableFactorError(BasePolynomialError): + """Raised if ``roots`` is called with strict=True and a polynomial + having a factor whose solutions are not expressible in radicals + is encountered.""" + +@public +class GeneratorsError(BasePolynomialError): + pass + +@public +class GeneratorsNeeded(GeneratorsError): + pass + +@public +class ComputationFailed(BasePolynomialError): + + def __init__(self, func, nargs, exc): + self.func = func + self.nargs = nargs + self.exc = exc + + def __str__(self): + return "%s(%s) failed without generators" % (self.func, ', '.join(map(str, self.exc.exprs[:self.nargs]))) + +@public +class UnivariatePolynomialError(PolynomialError): + pass + +@public +class MultivariatePolynomialError(PolynomialError): + pass + +@public +class PolificationFailed(PolynomialError): + + def __init__(self, opt, origs, exprs, seq=False): + if not seq: + self.orig = origs + self.expr = exprs + self.origs = [origs] + self.exprs = [exprs] + else: + self.origs = origs + self.exprs = exprs + + self.opt = opt + self.seq = seq + + def __str__(self): # pragma: no cover + if not self.seq: + return "Cannot construct a polynomial from %s" % str(self.orig) + else: + return "Cannot construct polynomials from %s" % ', '.join(map(str, self.origs)) + +@public +class OptionError(BasePolynomialError): + pass + +@public +class FlagError(OptionError): + pass diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyfuncs.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyfuncs.py new file mode 100644 index 0000000000000000000000000000000000000000..b412123f7383c68177a88df8817e921d96f6d5af --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyfuncs.py @@ -0,0 +1,321 @@ +"""High-level polynomials manipulation functions. """ + + +from sympy.core import S, Basic, symbols, Dummy +from sympy.polys.polyerrors import ( + PolificationFailed, ComputationFailed, + MultivariatePolynomialError, OptionError) +from sympy.polys.polyoptions import allowed_flags, build_options +from sympy.polys.polytools import poly_from_expr, Poly +from sympy.polys.specialpolys import ( + symmetric_poly, interpolating_poly) +from sympy.polys.rings import sring +from sympy.utilities import numbered_symbols, take, public + +@public +def symmetrize(F, *gens, **args): + r""" + Rewrite a polynomial in terms of elementary symmetric polynomials. + + A symmetric polynomial is a multivariate polynomial that remains invariant + under any variable permutation, i.e., if `f = f(x_1, x_2, \dots, x_n)`, + then `f = f(x_{i_1}, x_{i_2}, \dots, x_{i_n})`, where + `(i_1, i_2, \dots, i_n)` is a permutation of `(1, 2, \dots, n)` (an + element of the group `S_n`). + + Returns a tuple of symmetric polynomials ``(f1, f2, ..., fn)`` such that + ``f = f1 + f2 + ... + fn``. + + Examples + ======== + + >>> from sympy.polys.polyfuncs import symmetrize + >>> from sympy.abc import x, y + + >>> symmetrize(x**2 + y**2) + (-2*x*y + (x + y)**2, 0) + + >>> symmetrize(x**2 + y**2, formal=True) + (s1**2 - 2*s2, 0, [(s1, x + y), (s2, x*y)]) + + >>> symmetrize(x**2 - y**2) + (-2*x*y + (x + y)**2, -2*y**2) + + >>> symmetrize(x**2 - y**2, formal=True) + (s1**2 - 2*s2, -2*y**2, [(s1, x + y), (s2, x*y)]) + + """ + allowed_flags(args, ['formal', 'symbols']) + + iterable = True + + if not hasattr(F, '__iter__'): + iterable = False + F = [F] + + R, F = sring(F, *gens, **args) + gens = R.symbols + + opt = build_options(gens, args) + symbols = opt.symbols + symbols = [next(symbols) for i in range(len(gens))] + + result = [] + + for f in F: + p, r, m = f.symmetrize() + result.append((p.as_expr(*symbols), r.as_expr(*gens))) + + polys = [(s, g.as_expr()) for s, (_, g) in zip(symbols, m)] + + if not opt.formal: + for i, (sym, non_sym) in enumerate(result): + result[i] = (sym.subs(polys), non_sym) + + if not iterable: + result, = result + + if not opt.formal: + return result + else: + if iterable: + return result, polys + else: + return result + (polys,) + + +@public +def horner(f, *gens, **args): + """ + Rewrite a polynomial in Horner form. + + Among other applications, evaluation of a polynomial at a point is optimal + when it is applied using the Horner scheme ([1]). + + Examples + ======== + + >>> from sympy.polys.polyfuncs import horner + >>> from sympy.abc import x, y, a, b, c, d, e + + >>> horner(9*x**4 + 8*x**3 + 7*x**2 + 6*x + 5) + x*(x*(x*(9*x + 8) + 7) + 6) + 5 + + >>> horner(a*x**4 + b*x**3 + c*x**2 + d*x + e) + e + x*(d + x*(c + x*(a*x + b))) + + >>> f = 4*x**2*y**2 + 2*x**2*y + 2*x*y**2 + x*y + + >>> horner(f, wrt=x) + x*(x*y*(4*y + 2) + y*(2*y + 1)) + + >>> horner(f, wrt=y) + y*(x*y*(4*x + 2) + x*(2*x + 1)) + + References + ========== + [1] - https://en.wikipedia.org/wiki/Horner_scheme + + """ + allowed_flags(args, []) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + return exc.expr + + form, gen = S.Zero, F.gen + + if F.is_univariate: + for coeff in F.all_coeffs(): + form = form*gen + coeff + else: + F, gens = Poly(F, gen), gens[1:] + + for coeff in F.all_coeffs(): + form = form*gen + horner(coeff, *gens, **args) + + return form + + +@public +def interpolate(data, x): + """ + Construct an interpolating polynomial for the data points + evaluated at point x (which can be symbolic or numeric). + + Examples + ======== + + >>> from sympy.polys.polyfuncs import interpolate + >>> from sympy.abc import a, b, x + + A list is interpreted as though it were paired with a range starting + from 1: + + >>> interpolate([1, 4, 9, 16], x) + x**2 + + This can be made explicit by giving a list of coordinates: + + >>> interpolate([(1, 1), (2, 4), (3, 9)], x) + x**2 + + The (x, y) coordinates can also be given as keys and values of a + dictionary (and the points need not be equispaced): + + >>> interpolate([(-1, 2), (1, 2), (2, 5)], x) + x**2 + 1 + >>> interpolate({-1: 2, 1: 2, 2: 5}, x) + x**2 + 1 + + If the interpolation is going to be used only once then the + value of interest can be passed instead of passing a symbol: + + >>> interpolate([1, 4, 9], 5) + 25 + + Symbolic coordinates are also supported: + + >>> [(i,interpolate((a, b), i)) for i in range(1, 4)] + [(1, a), (2, b), (3, -a + 2*b)] + """ + n = len(data) + + if isinstance(data, dict): + if x in data: + return S(data[x]) + X, Y = list(zip(*data.items())) + else: + if isinstance(data[0], tuple): + X, Y = list(zip(*data)) + if x in X: + return S(Y[X.index(x)]) + else: + if x in range(1, n + 1): + return S(data[x - 1]) + Y = list(data) + X = list(range(1, n + 1)) + + try: + return interpolating_poly(n, x, X, Y).expand() + except ValueError: + d = Dummy() + return interpolating_poly(n, d, X, Y).expand().subs(d, x) + + +@public +def rational_interpolate(data, degnum, X=symbols('x')): + """ + Returns a rational interpolation, where the data points are element of + any integral domain. + + The first argument contains the data (as a list of coordinates). The + ``degnum`` argument is the degree in the numerator of the rational + function. Setting it too high will decrease the maximal degree in the + denominator for the same amount of data. + + Examples + ======== + + >>> from sympy.polys.polyfuncs import rational_interpolate + + >>> data = [(1, -210), (2, -35), (3, 105), (4, 231), (5, 350), (6, 465)] + >>> rational_interpolate(data, 2) + (105*x**2 - 525)/(x + 1) + + Values do not need to be integers: + + >>> from sympy import sympify + >>> x = [1, 2, 3, 4, 5, 6] + >>> y = sympify("[-1, 0, 2, 22/5, 7, 68/7]") + >>> rational_interpolate(zip(x, y), 2) + (3*x**2 - 7*x + 2)/(x + 1) + + The symbol for the variable can be changed if needed: + >>> from sympy import symbols + >>> z = symbols('z') + >>> rational_interpolate(data, 2, X=z) + (105*z**2 - 525)/(z + 1) + + References + ========== + + .. [1] Algorithm is adapted from: + http://axiom-wiki.newsynthesis.org/RationalInterpolation + + """ + from sympy.matrices.dense import ones + + xdata, ydata = list(zip(*data)) + + k = len(xdata) - degnum - 1 + if k < 0: + raise OptionError("Too few values for the required degree.") + c = ones(degnum + k + 1, degnum + k + 2) + for j in range(max(degnum, k)): + for i in range(degnum + k + 1): + c[i, j + 1] = c[i, j]*xdata[i] + for j in range(k + 1): + for i in range(degnum + k + 1): + c[i, degnum + k + 1 - j] = -c[i, k - j]*ydata[i] + r = c.nullspace()[0] + return (sum(r[i] * X**i for i in range(degnum + 1)) + / sum(r[i + degnum + 1] * X**i for i in range(k + 1))) + + +@public +def viete(f, roots=None, *gens, **args): + """ + Generate Viete's formulas for ``f``. + + Examples + ======== + + >>> from sympy.polys.polyfuncs import viete + >>> from sympy import symbols + + >>> x, a, b, c, r1, r2 = symbols('x,a:c,r1:3') + + >>> viete(a*x**2 + b*x + c, [r1, r2], x) + [(r1 + r2, -b/a), (r1*r2, c/a)] + + """ + allowed_flags(args, []) + + if isinstance(roots, Basic): + gens, roots = (roots,) + gens, None + + try: + f, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('viete', 1, exc) + + if f.is_multivariate: + raise MultivariatePolynomialError( + "multivariate polynomials are not allowed") + + n = f.degree() + + if n < 1: + raise ValueError( + "Cannot derive Viete's formulas for a constant polynomial") + + if roots is None: + roots = numbered_symbols('r', start=1) + + roots = take(roots, n) + + if n != len(roots): + raise ValueError("required %s roots, got %s" % (n, len(roots))) + + lc, coeffs = f.LC(), f.all_coeffs() + result, sign = [], -1 + + for i, coeff in enumerate(coeffs[1:]): + poly = symmetric_poly(i + 1, roots) + coeff = sign*(coeff/lc) + result.append((poly, coeff)) + sign = -sign + + return result diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polymatrix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polymatrix.py new file mode 100644 index 0000000000000000000000000000000000000000..fb2a58efc3ebfd85507ac2b0cfd31230e55ded66 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polymatrix.py @@ -0,0 +1,292 @@ +from sympy.core.expr import Expr +from sympy.core.symbol import Dummy +from sympy.core.sympify import _sympify + +from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.polytools import Poly, parallel_poly_from_expr +from sympy.polys.domains import QQ + +from sympy.polys.matrices import DomainMatrix +from sympy.polys.matrices.domainscalar import DomainScalar + + +class MutablePolyDenseMatrix: + """ + A mutable matrix of objects from poly module or to operate with them. + + Examples + ======== + + >>> from sympy.polys.polymatrix import PolyMatrix + >>> from sympy import Symbol, Poly + >>> x = Symbol('x') + >>> pm1 = PolyMatrix([[Poly(x**2, x), Poly(-x, x)], [Poly(x**3, x), Poly(-1 + x, x)]]) + >>> v1 = PolyMatrix([[1, 0], [-1, 0]], x) + >>> pm1*v1 + PolyMatrix([ + [ x**2 + x, 0], + [x**3 - x + 1, 0]], ring=QQ[x]) + + >>> pm1.ring + ZZ[x] + + >>> v1*pm1 + PolyMatrix([ + [ x**2, -x], + [-x**2, x]], ring=QQ[x]) + + >>> pm2 = PolyMatrix([[Poly(x**2, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(1, x, domain='QQ'), \ + Poly(x**3, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(-x**3, x, domain='QQ')]]) + >>> v2 = PolyMatrix([1, 0, 0, 0, 0, 0], x) + >>> v2.ring + QQ[x] + >>> pm2*v2 + PolyMatrix([[x**2]], ring=QQ[x]) + + """ + + def __new__(cls, *args, ring=None): + + if not args: + # PolyMatrix(ring=QQ[x]) + if ring is None: + raise TypeError("The ring needs to be specified for an empty PolyMatrix") + rows, cols, items, gens = 0, 0, [], () + elif isinstance(args[0], list): + elements, gens = args[0], args[1:] + if not elements: + # PolyMatrix([]) + rows, cols, items = 0, 0, [] + elif isinstance(elements[0], (list, tuple)): + # PolyMatrix([[1, 2]], x) + rows, cols = len(elements), len(elements[0]) + items = [e for row in elements for e in row] + else: + # PolyMatrix([1, 2], x) + rows, cols = len(elements), 1 + items = elements + elif [type(a) for a in args[:3]] == [int, int, list]: + # PolyMatrix(2, 2, [1, 2, 3, 4], x) + rows, cols, items, gens = args[0], args[1], args[2], args[3:] + elif [type(a) for a in args[:3]] == [int, int, type(lambda: 0)]: + # PolyMatrix(2, 2, lambda i, j: i+j, x) + rows, cols, func, gens = args[0], args[1], args[2], args[3:] + items = [func(i, j) for i in range(rows) for j in range(cols)] + else: + raise TypeError("Invalid arguments") + + # PolyMatrix([[1]], x, y) vs PolyMatrix([[1]], (x, y)) + if len(gens) == 1 and isinstance(gens[0], tuple): + gens = gens[0] + # gens is now a tuple (x, y) + + return cls.from_list(rows, cols, items, gens, ring) + + @classmethod + def from_list(cls, rows, cols, items, gens, ring): + + # items can be Expr, Poly, or a mix of Expr and Poly + items = [_sympify(item) for item in items] + if items and all(isinstance(item, Poly) for item in items): + polys = True + else: + polys = False + + # Identify the ring for the polys + if ring is not None: + # Parse a domain string like 'QQ[x]' + if isinstance(ring, str): + ring = Poly(0, Dummy(), domain=ring).domain + elif polys: + p = items[0] + for p2 in items[1:]: + p, _ = p.unify(p2) + ring = p.domain[p.gens] + else: + items, info = parallel_poly_from_expr(items, gens, field=True) + ring = info['domain'][info['gens']] + polys = True + + # Efficiently convert when all elements are Poly + if polys: + p_ring = Poly(0, ring.symbols, domain=ring.domain) + to_ring = ring.ring.from_list + convert_poly = lambda p: to_ring(p.unify(p_ring)[0].rep.to_list()) + elements = [convert_poly(p) for p in items] + else: + convert_expr = ring.from_sympy + elements = [convert_expr(e.as_expr()) for e in items] + + # Convert to domain elements and construct DomainMatrix + elements_lol = [[elements[i*cols + j] for j in range(cols)] for i in range(rows)] + dm = DomainMatrix(elements_lol, (rows, cols), ring) + return cls.from_dm(dm) + + @classmethod + def from_dm(cls, dm): + obj = super().__new__(cls) + dm = dm.to_sparse() + R = dm.domain + obj._dm = dm + obj.ring = R + obj.domain = R.domain + obj.gens = R.symbols + return obj + + def to_Matrix(self): + return self._dm.to_Matrix() + + @classmethod + def from_Matrix(cls, other, *gens, ring=None): + return cls(*other.shape, other.flat(), *gens, ring=ring) + + def set_gens(self, gens): + return self.from_Matrix(self.to_Matrix(), gens) + + def __repr__(self): + if self.rows * self.cols: + return 'Poly' + repr(self.to_Matrix())[:-1] + f', ring={self.ring})' + else: + return f'PolyMatrix({self.rows}, {self.cols}, [], ring={self.ring})' + + @property + def shape(self): + return self._dm.shape + + @property + def rows(self): + return self.shape[0] + + @property + def cols(self): + return self.shape[1] + + def __len__(self): + return self.rows * self.cols + + def __getitem__(self, key): + + def to_poly(v): + ground = self._dm.domain.domain + gens = self._dm.domain.symbols + return Poly(v.to_dict(), gens, domain=ground) + + dm = self._dm + + if isinstance(key, slice): + items = dm.flat()[key] + return [to_poly(item) for item in items] + elif isinstance(key, int): + i, j = divmod(key, self.cols) + e = dm[i,j] + return to_poly(e.element) + + i, j = key + if isinstance(i, int) and isinstance(j, int): + return to_poly(dm[i, j].element) + else: + return self.from_dm(dm[i, j]) + + def __eq__(self, other): + if not isinstance(self, type(other)): + return NotImplemented + return self._dm == other._dm + + def __add__(self, other): + if isinstance(other, type(self)): + return self.from_dm(self._dm + other._dm) + return NotImplemented + + def __sub__(self, other): + if isinstance(other, type(self)): + return self.from_dm(self._dm - other._dm) + return NotImplemented + + def __mul__(self, other): + if isinstance(other, type(self)): + return self.from_dm(self._dm * other._dm) + elif isinstance(other, int): + other = _sympify(other) + if isinstance(other, Expr): + Kx = self.ring + try: + other_ds = DomainScalar(Kx.from_sympy(other), Kx) + except (CoercionFailed, ValueError): + other_ds = DomainScalar.from_sympy(other) + return self.from_dm(self._dm * other_ds) + return NotImplemented + + def __rmul__(self, other): + if isinstance(other, int): + other = _sympify(other) + if isinstance(other, Expr): + other_ds = DomainScalar.from_sympy(other) + return self.from_dm(other_ds * self._dm) + return NotImplemented + + def __truediv__(self, other): + + if isinstance(other, Poly): + other = other.as_expr() + elif isinstance(other, int): + other = _sympify(other) + if not isinstance(other, Expr): + return NotImplemented + + other = self.domain.from_sympy(other) + inverse = self.ring.convert_from(1/other, self.domain) + inverse = DomainScalar(inverse, self.ring) + dm = self._dm * inverse + return self.from_dm(dm) + + def __neg__(self): + return self.from_dm(-self._dm) + + def transpose(self): + return self.from_dm(self._dm.transpose()) + + def row_join(self, other): + dm = DomainMatrix.hstack(self._dm, other._dm) + return self.from_dm(dm) + + def col_join(self, other): + dm = DomainMatrix.vstack(self._dm, other._dm) + return self.from_dm(dm) + + def applyfunc(self, func): + M = self.to_Matrix().applyfunc(func) + return self.from_Matrix(M, self.gens) + + @classmethod + def eye(cls, n, gens): + return cls.from_dm(DomainMatrix.eye(n, QQ[gens])) + + @classmethod + def zeros(cls, m, n, gens): + return cls.from_dm(DomainMatrix.zeros((m, n), QQ[gens])) + + def rref(self, simplify='ignore', normalize_last='ignore'): + # If this is K[x] then computes RREF in ground field K. + if not (self.domain.is_Field and all(p.is_ground for p in self)): + raise ValueError("PolyMatrix rref is only for ground field elements") + dm = self._dm + dm_ground = dm.convert_to(dm.domain.domain) + dm_rref, pivots = dm_ground.rref() + dm_rref = dm_rref.convert_to(dm.domain) + return self.from_dm(dm_rref), pivots + + def nullspace(self): + # If this is K[x] then computes nullspace in ground field K. + if not (self.domain.is_Field and all(p.is_ground for p in self)): + raise ValueError("PolyMatrix nullspace is only for ground field elements") + dm = self._dm + K, Kx = self.domain, self.ring + dm_null_rows = dm.convert_to(K).nullspace(divide_last=True).convert_to(Kx) + dm_null = dm_null_rows.transpose() + dm_basis = [dm_null[:,i] for i in range(dm_null.shape[1])] + return [self.from_dm(dmvec) for dmvec in dm_basis] + + def rank(self): + return self.cols - len(self.nullspace()) + +MutablePolyMatrix = PolyMatrix = MutablePolyDenseMatrix diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyoptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyoptions.py new file mode 100644 index 0000000000000000000000000000000000000000..7b9bd989c4d5676aab32e65c62996137b3e0b73e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyoptions.py @@ -0,0 +1,791 @@ +"""Options manager for :class:`~.Poly` and public API functions. """ + +from __future__ import annotations + +__all__ = ["Options"] + +from sympy.core.basic import Basic +from sympy.core.expr import Expr +from sympy.core.sympify import sympify +from sympy.polys.polyerrors import GeneratorsError, OptionError, FlagError +from sympy.utilities import numbered_symbols, topological_sort, public +from sympy.utilities.iterables import has_dups, is_sequence + +import sympy.polys + +import re + +class Option: + """Base class for all kinds of options. """ + + option: str | None = None + + is_Flag = False + + requires: list[str] = [] + excludes: list[str] = [] + + after: list[str] = [] + before: list[str] = [] + + @classmethod + def default(cls): + return None + + @classmethod + def preprocess(cls, option): + return None + + @classmethod + def postprocess(cls, options): + pass + + +class Flag(Option): + """Base class for all kinds of flags. """ + + is_Flag = True + + +class BooleanOption(Option): + """An option that must have a boolean value or equivalent assigned. """ + + @classmethod + def preprocess(cls, value): + if value in [True, False]: + return bool(value) + else: + raise OptionError("'%s' must have a boolean value assigned, got %s" % (cls.option, value)) + + +class OptionType(type): + """Base type for all options that does registers options. """ + + def __init__(cls, *args, **kwargs): + @property + def getter(self): + try: + return self[cls.option] + except KeyError: + return cls.default() + + setattr(Options, cls.option, getter) + Options.__options__[cls.option] = cls + + +@public +class Options(dict): + """ + Options manager for polynomial manipulation module. + + Examples + ======== + + >>> from sympy.polys.polyoptions import Options + >>> from sympy.polys.polyoptions import build_options + + >>> from sympy.abc import x, y, z + + >>> Options((x, y, z), {'domain': 'ZZ'}) + {'auto': False, 'domain': ZZ, 'gens': (x, y, z)} + + >>> build_options((x, y, z), {'domain': 'ZZ'}) + {'auto': False, 'domain': ZZ, 'gens': (x, y, z)} + + **Options** + + * Expand --- boolean option + * Gens --- option + * Wrt --- option + * Sort --- option + * Order --- option + * Field --- boolean option + * Greedy --- boolean option + * Domain --- option + * Split --- boolean option + * Gaussian --- boolean option + * Extension --- option + * Modulus --- option + * Symmetric --- boolean option + * Strict --- boolean option + + **Flags** + + * Auto --- boolean flag + * Frac --- boolean flag + * Formal --- boolean flag + * Polys --- boolean flag + * Include --- boolean flag + * All --- boolean flag + * Gen --- flag + * Series --- boolean flag + + """ + + __order__ = None + __options__: dict[str, type[Option]] = {} + + gens: tuple[Expr, ...] + domain: sympy.polys.domains.Domain + + def __init__(self, gens, args, flags=None, strict=False): + dict.__init__(self) + + if gens and args.get('gens', ()): + raise OptionError( + "both '*gens' and keyword argument 'gens' supplied") + elif gens: + args = dict(args) + args['gens'] = gens + + defaults = args.pop('defaults', {}) + + def preprocess_options(args): + for option, value in args.items(): + try: + cls = self.__options__[option] + except KeyError: + raise OptionError("'%s' is not a valid option" % option) + + if issubclass(cls, Flag): + if flags is None or option not in flags: + if strict: + raise OptionError("'%s' flag is not allowed in this context" % option) + + if value is not None: + self[option] = cls.preprocess(value) + + preprocess_options(args) + + for key in dict(defaults): + if key in self: + del defaults[key] + else: + for option in self.keys(): + cls = self.__options__[option] + + if key in cls.excludes: + del defaults[key] + break + + preprocess_options(defaults) + + for option in self.keys(): + cls = self.__options__[option] + + for require_option in cls.requires: + if self.get(require_option) is None: + raise OptionError("'%s' option is only allowed together with '%s'" % (option, require_option)) + + for exclude_option in cls.excludes: + if self.get(exclude_option) is not None: + raise OptionError("'%s' option is not allowed together with '%s'" % (option, exclude_option)) + + for option in self.__order__: + self.__options__[option].postprocess(self) + + @classmethod + def _init_dependencies_order(cls): + """Resolve the order of options' processing. """ + if cls.__order__ is None: + vertices, edges = [], set() + + for name, option in cls.__options__.items(): + vertices.append(name) + + edges.update((_name, name) for _name in option.after) + + edges.update((name, _name) for _name in option.before) + + try: + cls.__order__ = topological_sort((vertices, list(edges))) + except ValueError: + raise RuntimeError( + "cycle detected in sympy.polys options framework") + + def clone(self, updates={}): + """Clone ``self`` and update specified options. """ + obj = dict.__new__(self.__class__) + + for option, value in self.items(): + obj[option] = value + + for option, value in updates.items(): + obj[option] = value + + return obj + + def __setattr__(self, attr, value): + if attr in self.__options__: + self[attr] = value + else: + super().__setattr__(attr, value) + + @property + def args(self): + args = {} + + for option, value in self.items(): + if value is not None and option != 'gens': + cls = self.__options__[option] + + if not issubclass(cls, Flag): + args[option] = value + + return args + + @property + def options(self): + options = {} + + for option, cls in self.__options__.items(): + if not issubclass(cls, Flag): + options[option] = getattr(self, option) + + return options + + @property + def flags(self): + flags = {} + + for option, cls in self.__options__.items(): + if issubclass(cls, Flag): + flags[option] = getattr(self, option) + + return flags + + +class Expand(BooleanOption, metaclass=OptionType): + """``expand`` option to polynomial manipulation functions. """ + + option = 'expand' + + requires: list[str] = [] + excludes: list[str] = [] + + @classmethod + def default(cls): + return True + + +class Gens(Option, metaclass=OptionType): + """``gens`` option to polynomial manipulation functions. """ + + option = 'gens' + + requires: list[str] = [] + excludes: list[str] = [] + + @classmethod + def default(cls): + return () + + @classmethod + def preprocess(cls, gens): + if isinstance(gens, Basic): + gens = (gens,) + elif len(gens) == 1 and is_sequence(gens[0]): + gens = gens[0] + + if gens == (None,): + gens = () + elif has_dups(gens): + raise GeneratorsError("duplicated generators: %s" % str(gens)) + elif any(gen.is_commutative is False for gen in gens): + raise GeneratorsError("non-commutative generators: %s" % str(gens)) + + return tuple(gens) + + +class Wrt(Option, metaclass=OptionType): + """``wrt`` option to polynomial manipulation functions. """ + + option = 'wrt' + + requires: list[str] = [] + excludes: list[str] = [] + + _re_split = re.compile(r"\s*,\s*|\s+") + + @classmethod + def preprocess(cls, wrt): + if isinstance(wrt, Basic): + return [str(wrt)] + elif isinstance(wrt, str): + wrt = wrt.strip() + if wrt.endswith(','): + raise OptionError('Bad input: missing parameter.') + if not wrt: + return [] + return list(cls._re_split.split(wrt)) + elif hasattr(wrt, '__getitem__'): + return list(map(str, wrt)) + else: + raise OptionError("invalid argument for 'wrt' option") + + +class Sort(Option, metaclass=OptionType): + """``sort`` option to polynomial manipulation functions. """ + + option = 'sort' + + requires: list[str] = [] + excludes: list[str] = [] + + @classmethod + def default(cls): + return [] + + @classmethod + def preprocess(cls, sort): + if isinstance(sort, str): + return [ gen.strip() for gen in sort.split('>') ] + elif hasattr(sort, '__getitem__'): + return list(map(str, sort)) + else: + raise OptionError("invalid argument for 'sort' option") + + +class Order(Option, metaclass=OptionType): + """``order`` option to polynomial manipulation functions. """ + + option = 'order' + + requires: list[str] = [] + excludes: list[str] = [] + + @classmethod + def default(cls): + return sympy.polys.orderings.lex + + @classmethod + def preprocess(cls, order): + return sympy.polys.orderings.monomial_key(order) + + +class Field(BooleanOption, metaclass=OptionType): + """``field`` option to polynomial manipulation functions. """ + + option = 'field' + + requires: list[str] = [] + excludes = ['domain', 'split', 'gaussian'] + + +class Greedy(BooleanOption, metaclass=OptionType): + """``greedy`` option to polynomial manipulation functions. """ + + option = 'greedy' + + requires: list[str] = [] + excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', 'symmetric'] + + +class Composite(BooleanOption, metaclass=OptionType): + """``composite`` option to polynomial manipulation functions. """ + + option = 'composite' + + @classmethod + def default(cls): + return None + + requires: list[str] = [] + excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', 'symmetric'] + + +class Domain(Option, metaclass=OptionType): + """``domain`` option to polynomial manipulation functions. """ + + option = 'domain' + + requires: list[str] = [] + excludes = ['field', 'greedy', 'split', 'gaussian', 'extension'] + + after = ['gens'] + + _re_realfield = re.compile(r"^(R|RR)(_(\d+))?$") + _re_complexfield = re.compile(r"^(C|CC)(_(\d+))?$") + _re_finitefield = re.compile(r"^(FF|GF)\((\d+)\)$") + _re_polynomial = re.compile(r"^(Z|ZZ|Q|QQ|ZZ_I|QQ_I|R|RR|C|CC)\[(.+)\]$") + _re_fraction = re.compile(r"^(Z|ZZ|Q|QQ)\((.+)\)$") + _re_algebraic = re.compile(r"^(Q|QQ)\<(.+)\>$") + + @classmethod + def preprocess(cls, domain): + if isinstance(domain, sympy.polys.domains.Domain): + return domain + elif hasattr(domain, 'to_domain'): + return domain.to_domain() + elif isinstance(domain, str): + if domain in ['Z', 'ZZ']: + return sympy.polys.domains.ZZ + + if domain in ['Q', 'QQ']: + return sympy.polys.domains.QQ + + if domain == 'ZZ_I': + return sympy.polys.domains.ZZ_I + + if domain == 'QQ_I': + return sympy.polys.domains.QQ_I + + if domain == 'EX': + return sympy.polys.domains.EX + + r = cls._re_realfield.match(domain) + + if r is not None: + _, _, prec = r.groups() + + if prec is None: + return sympy.polys.domains.RR + else: + return sympy.polys.domains.RealField(int(prec)) + + r = cls._re_complexfield.match(domain) + + if r is not None: + _, _, prec = r.groups() + + if prec is None: + return sympy.polys.domains.CC + else: + return sympy.polys.domains.ComplexField(int(prec)) + + r = cls._re_finitefield.match(domain) + + if r is not None: + return sympy.polys.domains.FF(int(r.groups()[1])) + + r = cls._re_polynomial.match(domain) + + if r is not None: + ground, gens = r.groups() + + gens = list(map(sympify, gens.split(','))) + + if ground in ['Z', 'ZZ']: + return sympy.polys.domains.ZZ.poly_ring(*gens) + elif ground in ['Q', 'QQ']: + return sympy.polys.domains.QQ.poly_ring(*gens) + elif ground in ['R', 'RR']: + return sympy.polys.domains.RR.poly_ring(*gens) + elif ground == 'ZZ_I': + return sympy.polys.domains.ZZ_I.poly_ring(*gens) + elif ground == 'QQ_I': + return sympy.polys.domains.QQ_I.poly_ring(*gens) + else: + return sympy.polys.domains.CC.poly_ring(*gens) + + r = cls._re_fraction.match(domain) + + if r is not None: + ground, gens = r.groups() + + gens = list(map(sympify, gens.split(','))) + + if ground in ['Z', 'ZZ']: + return sympy.polys.domains.ZZ.frac_field(*gens) + else: + return sympy.polys.domains.QQ.frac_field(*gens) + + r = cls._re_algebraic.match(domain) + + if r is not None: + gens = list(map(sympify, r.groups()[1].split(','))) + return sympy.polys.domains.QQ.algebraic_field(*gens) + + raise OptionError('expected a valid domain specification, got %s' % domain) + + @classmethod + def postprocess(cls, options): + if 'gens' in options and 'domain' in options and options['domain'].is_Composite and \ + (set(options['domain'].symbols) & set(options['gens'])): + raise GeneratorsError( + "ground domain and generators interfere together") + elif ('gens' not in options or not options['gens']) and \ + 'domain' in options and options['domain'] == sympy.polys.domains.EX: + raise GeneratorsError("you have to provide generators because EX domain was requested") + + +class Split(BooleanOption, metaclass=OptionType): + """``split`` option to polynomial manipulation functions. """ + + option = 'split' + + requires: list[str] = [] + excludes = ['field', 'greedy', 'domain', 'gaussian', 'extension', + 'modulus', 'symmetric'] + + @classmethod + def postprocess(cls, options): + if 'split' in options: + raise NotImplementedError("'split' option is not implemented yet") + + +class Gaussian(BooleanOption, metaclass=OptionType): + """``gaussian`` option to polynomial manipulation functions. """ + + option = 'gaussian' + + requires: list[str] = [] + excludes = ['field', 'greedy', 'domain', 'split', 'extension', + 'modulus', 'symmetric'] + + @classmethod + def postprocess(cls, options): + if 'gaussian' in options and options['gaussian'] is True: + options['domain'] = sympy.polys.domains.QQ_I + Extension.postprocess(options) + + +class Extension(Option, metaclass=OptionType): + """``extension`` option to polynomial manipulation functions. """ + + option = 'extension' + + requires: list[str] = [] + excludes = ['greedy', 'domain', 'split', 'gaussian', 'modulus', + 'symmetric'] + + @classmethod + def preprocess(cls, extension): + if extension == 1: + return bool(extension) + elif extension == 0: + raise OptionError("'False' is an invalid argument for 'extension'") + else: + if not hasattr(extension, '__iter__'): + extension = {extension} + else: + if not extension: + extension = None + else: + extension = set(extension) + + return extension + + @classmethod + def postprocess(cls, options): + if 'extension' in options and options['extension'] is not True: + options['domain'] = sympy.polys.domains.QQ.algebraic_field( + *options['extension']) + + +class Modulus(Option, metaclass=OptionType): + """``modulus`` option to polynomial manipulation functions. """ + + option = 'modulus' + + requires: list[str] = [] + excludes = ['greedy', 'split', 'domain', 'gaussian', 'extension'] + + @classmethod + def preprocess(cls, modulus): + modulus = sympify(modulus) + + if modulus.is_Integer and modulus > 0: + return int(modulus) + else: + raise OptionError( + "'modulus' must a positive integer, got %s" % modulus) + + @classmethod + def postprocess(cls, options): + if 'modulus' in options: + modulus = options['modulus'] + symmetric = options.get('symmetric', True) + options['domain'] = sympy.polys.domains.FF(modulus, symmetric) + + +class Symmetric(BooleanOption, metaclass=OptionType): + """``symmetric`` option to polynomial manipulation functions. """ + + option = 'symmetric' + + requires = ['modulus'] + excludes = ['greedy', 'domain', 'split', 'gaussian', 'extension'] + + +class Strict(BooleanOption, metaclass=OptionType): + """``strict`` option to polynomial manipulation functions. """ + + option = 'strict' + + @classmethod + def default(cls): + return True + + +class Auto(BooleanOption, Flag, metaclass=OptionType): + """``auto`` flag to polynomial manipulation functions. """ + + option = 'auto' + + after = ['field', 'domain', 'extension', 'gaussian'] + + @classmethod + def default(cls): + return True + + @classmethod + def postprocess(cls, options): + if ('domain' in options or 'field' in options) and 'auto' not in options: + options['auto'] = False + + +class Frac(BooleanOption, Flag, metaclass=OptionType): + """``auto`` option to polynomial manipulation functions. """ + + option = 'frac' + + @classmethod + def default(cls): + return False + + +class Formal(BooleanOption, Flag, metaclass=OptionType): + """``formal`` flag to polynomial manipulation functions. """ + + option = 'formal' + + @classmethod + def default(cls): + return False + + +class Polys(BooleanOption, Flag, metaclass=OptionType): + """``polys`` flag to polynomial manipulation functions. """ + + option = 'polys' + + +class Include(BooleanOption, Flag, metaclass=OptionType): + """``include`` flag to polynomial manipulation functions. """ + + option = 'include' + + @classmethod + def default(cls): + return False + + +class All(BooleanOption, Flag, metaclass=OptionType): + """``all`` flag to polynomial manipulation functions. """ + + option = 'all' + + @classmethod + def default(cls): + return False + + +class Gen(Flag, metaclass=OptionType): + """``gen`` flag to polynomial manipulation functions. """ + + option = 'gen' + + @classmethod + def default(cls): + return 0 + + @classmethod + def preprocess(cls, gen): + if isinstance(gen, (Basic, int)): + return gen + else: + raise OptionError("invalid argument for 'gen' option") + + +class Series(BooleanOption, Flag, metaclass=OptionType): + """``series`` flag to polynomial manipulation functions. """ + + option = 'series' + + @classmethod + def default(cls): + return False + + +class Symbols(Flag, metaclass=OptionType): + """``symbols`` flag to polynomial manipulation functions. """ + + option = 'symbols' + + @classmethod + def default(cls): + return numbered_symbols('s', start=1) + + @classmethod + def preprocess(cls, symbols): + if hasattr(symbols, '__iter__'): + return iter(symbols) + else: + raise OptionError("expected an iterator or iterable container, got %s" % symbols) + + +class Method(Flag, metaclass=OptionType): + """``method`` flag to polynomial manipulation functions. """ + + option = 'method' + + @classmethod + def preprocess(cls, method): + if isinstance(method, str): + return method.lower() + else: + raise OptionError("expected a string, got %s" % method) + + +def build_options(gens, args=None): + """Construct options from keyword arguments or ... options. """ + if args is None: + gens, args = (), gens + + if len(args) != 1 or 'opt' not in args or gens: + return Options(gens, args) + else: + return args['opt'] + + +def allowed_flags(args, flags): + """ + Allow specified flags to be used in the given context. + + Examples + ======== + + >>> from sympy.polys.polyoptions import allowed_flags + >>> from sympy.polys.domains import ZZ + + >>> allowed_flags({'domain': ZZ}, []) + + >>> allowed_flags({'domain': ZZ, 'frac': True}, []) + Traceback (most recent call last): + ... + FlagError: 'frac' flag is not allowed in this context + + >>> allowed_flags({'domain': ZZ, 'frac': True}, ['frac']) + + """ + flags = set(flags) + + for arg in args.keys(): + try: + if Options.__options__[arg].is_Flag and arg not in flags: + raise FlagError( + "'%s' flag is not allowed in this context" % arg) + except KeyError: + raise OptionError("'%s' is not a valid option" % arg) + + +def set_defaults(options, **defaults): + """Update options with default values. """ + if 'defaults' not in options: + options = dict(options) + options['defaults'] = defaults + + return options + +Options._init_dependencies_order() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyquinticconst.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyquinticconst.py new file mode 100644 index 0000000000000000000000000000000000000000..3b17096fd2cf3b205c3b819eb11ffc2012ea125b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyquinticconst.py @@ -0,0 +1,187 @@ +""" +Solving solvable quintics - An implementation of DS Dummit's paper + +Paper : +https://www.ams.org/journals/mcom/1991-57-195/S0025-5718-1991-1079014-X/S0025-5718-1991-1079014-X.pdf + +Mathematica notebook: +http://www.emba.uvm.edu/~ddummit/quintics/quintics.nb + +""" + + +from sympy.core import Symbol +from sympy.core.evalf import N +from sympy.core.numbers import I, Rational +from sympy.functions import sqrt +from sympy.polys.polytools import Poly +from sympy.utilities import public + +x = Symbol('x') + +@public +class PolyQuintic: + """Special functions for solvable quintics""" + def __init__(self, poly): + _, _, self.p, self.q, self.r, self.s = poly.all_coeffs() + self.zeta1 = Rational(-1, 4) + (sqrt(5)/4) + I*sqrt((sqrt(5)/8) + Rational(5, 8)) + self.zeta2 = (-sqrt(5)/4) - Rational(1, 4) + I*sqrt((-sqrt(5)/8) + Rational(5, 8)) + self.zeta3 = (-sqrt(5)/4) - Rational(1, 4) - I*sqrt((-sqrt(5)/8) + Rational(5, 8)) + self.zeta4 = Rational(-1, 4) + (sqrt(5)/4) - I*sqrt((sqrt(5)/8) + Rational(5, 8)) + + @property + def f20(self): + p, q, r, s = self.p, self.q, self.r, self.s + f20 = q**8 - 13*p*q**6*r + p**5*q**2*r**2 + 65*p**2*q**4*r**2 - 4*p**6*r**3 - 128*p**3*q**2*r**3 + 17*q**4*r**3 + 48*p**4*r**4 - 16*p*q**2*r**4 - 192*p**2*r**5 + 256*r**6 - 4*p**5*q**3*s - 12*p**2*q**5*s + 18*p**6*q*r*s + 12*p**3*q**3*r*s - 124*q**5*r*s + 196*p**4*q*r**2*s + 590*p*q**3*r**2*s - 160*p**2*q*r**3*s - 1600*q*r**4*s - 27*p**7*s**2 - 150*p**4*q**2*s**2 - 125*p*q**4*s**2 - 99*p**5*r*s**2 - 725*p**2*q**2*r*s**2 + 1200*p**3*r**2*s**2 + 3250*q**2*r**2*s**2 - 2000*p*r**3*s**2 - 1250*p*q*r*s**3 + 3125*p**2*s**4 - 9375*r*s**4-(2*p*q**6 - 19*p**2*q**4*r + 51*p**3*q**2*r**2 - 3*q**4*r**2 - 32*p**4*r**3 - 76*p*q**2*r**3 + 256*p**2*r**4 - 512*r**5 + 31*p**3*q**3*s + 58*q**5*s - 117*p**4*q*r*s - 105*p*q**3*r*s - 260*p**2*q*r**2*s + 2400*q*r**3*s + 108*p**5*s**2 + 325*p**2*q**2*s**2 - 525*p**3*r*s**2 - 2750*q**2*r*s**2 + 500*p*r**2*s**2 - 625*p*q*s**3 + 3125*s**4)*x+(p**2*q**4 - 6*p**3*q**2*r - 8*q**4*r + 9*p**4*r**2 + 76*p*q**2*r**2 - 136*p**2*r**3 + 400*r**4 - 50*p*q**3*s + 90*p**2*q*r*s - 1400*q*r**2*s + 625*q**2*s**2 + 500*p*r*s**2)*x**2-(2*q**4 - 21*p*q**2*r + 40*p**2*r**2 - 160*r**3 + 15*p**2*q*s + 400*q*r*s - 125*p*s**2)*x**3+(2*p*q**2 - 6*p**2*r + 40*r**2 - 50*q*s)*x**4 + 8*r*x**5 + x**6 + return Poly(f20, x) + + @property + def b(self): + p, q, r, s = self.p, self.q, self.r, self.s + b = ( [], [0,0,0,0,0,0], [0,0,0,0,0,0], [0,0,0,0,0,0], [0,0,0,0,0,0],) + + b[1][5] = 100*p**7*q**7 + 2175*p**4*q**9 + 10500*p*q**11 - 1100*p**8*q**5*r - 27975*p**5*q**7*r - 152950*p**2*q**9*r + 4125*p**9*q**3*r**2 + 128875*p**6*q**5*r**2 + 830525*p**3*q**7*r**2 - 59450*q**9*r**2 - 5400*p**10*q*r**3 - 243800*p**7*q**3*r**3 - 2082650*p**4*q**5*r**3 + 333925*p*q**7*r**3 + 139200*p**8*q*r**4 + 2406000*p**5*q**3*r**4 + 122600*p**2*q**5*r**4 - 1254400*p**6*q*r**5 - 3776000*p**3*q**3*r**5 - 1832000*q**5*r**5 + 4736000*p**4*q*r**6 + 6720000*p*q**3*r**6 - 6400000*p**2*q*r**7 + 900*p**9*q**4*s + 37400*p**6*q**6*s + 281625*p**3*q**8*s + 435000*q**10*s - 6750*p**10*q**2*r*s - 322300*p**7*q**4*r*s - 2718575*p**4*q**6*r*s - 4214250*p*q**8*r*s + 16200*p**11*r**2*s + 859275*p**8*q**2*r**2*s + 8925475*p**5*q**4*r**2*s + 14427875*p**2*q**6*r**2*s - 453600*p**9*r**3*s - 10038400*p**6*q**2*r**3*s - 17397500*p**3*q**4*r**3*s + 11333125*q**6*r**3*s + 4451200*p**7*r**4*s + 15850000*p**4*q**2*r**4*s - 34000000*p*q**4*r**4*s - 17984000*p**5*r**5*s + 10000000*p**2*q**2*r**5*s + 25600000*p**3*r**6*s + 8000000*q**2*r**6*s - 6075*p**11*q*s**2 + 83250*p**8*q**3*s**2 + 1282500*p**5*q**5*s**2 + 2862500*p**2*q**7*s**2 - 724275*p**9*q*r*s**2 - 9807250*p**6*q**3*r*s**2 - 28374375*p**3*q**5*r*s**2 - 22212500*q**7*r*s**2 + 8982000*p**7*q*r**2*s**2 + 39600000*p**4*q**3*r**2*s**2 + 61746875*p*q**5*r**2*s**2 + 1010000*p**5*q*r**3*s**2 + 1000000*p**2*q**3*r**3*s**2 - 78000000*p**3*q*r**4*s**2 - 30000000*q**3*r**4*s**2 - 80000000*p*q*r**5*s**2 + 759375*p**10*s**3 + 9787500*p**7*q**2*s**3 + 39062500*p**4*q**4*s**3 + 52343750*p*q**6*s**3 - 12301875*p**8*r*s**3 - 98175000*p**5*q**2*r*s**3 - 225078125*p**2*q**4*r*s**3 + 54900000*p**6*r**2*s**3 + 310000000*p**3*q**2*r**2*s**3 + 7890625*q**4*r**2*s**3 - 51250000*p**4*r**3*s**3 + 420000000*p*q**2*r**3*s**3 - 110000000*p**2*r**4*s**3 + 200000000*r**5*s**3 - 2109375*p**6*q*s**4 + 21093750*p**3*q**3*s**4 + 89843750*q**5*s**4 - 182343750*p**4*q*r*s**4 - 733203125*p*q**3*r*s**4 + 196875000*p**2*q*r**2*s**4 - 1125000000*q*r**3*s**4 + 158203125*p**5*s**5 + 566406250*p**2*q**2*s**5 - 101562500*p**3*r*s**5 + 1669921875*q**2*r*s**5 - 1250000000*p*r**2*s**5 + 1220703125*p*q*s**6 - 6103515625*s**7 + + b[1][4] = -1000*p**5*q**7 - 7250*p**2*q**9 + 10800*p**6*q**5*r + 96900*p**3*q**7*r + 52500*q**9*r - 37400*p**7*q**3*r**2 - 470850*p**4*q**5*r**2 - 640600*p*q**7*r**2 + 39600*p**8*q*r**3 + 983600*p**5*q**3*r**3 + 2848100*p**2*q**5*r**3 - 814400*p**6*q*r**4 - 6076000*p**3*q**3*r**4 - 2308000*q**5*r**4 + 5024000*p**4*q*r**5 + 9680000*p*q**3*r**5 - 9600000*p**2*q*r**6 - 13800*p**7*q**4*s - 94650*p**4*q**6*s + 26500*p*q**8*s + 86400*p**8*q**2*r*s + 816500*p**5*q**4*r*s + 257500*p**2*q**6*r*s - 91800*p**9*r**2*s - 1853700*p**6*q**2*r**2*s - 630000*p**3*q**4*r**2*s + 8971250*q**6*r**2*s + 2071200*p**7*r**3*s + 7240000*p**4*q**2*r**3*s - 29375000*p*q**4*r**3*s - 14416000*p**5*r**4*s + 5200000*p**2*q**2*r**4*s + 30400000*p**3*r**5*s + 12000000*q**2*r**5*s - 64800*p**9*q*s**2 - 567000*p**6*q**3*s**2 - 1655000*p**3*q**5*s**2 - 6987500*q**7*s**2 - 337500*p**7*q*r*s**2 - 8462500*p**4*q**3*r*s**2 + 5812500*p*q**5*r*s**2 + 24930000*p**5*q*r**2*s**2 + 69125000*p**2*q**3*r**2*s**2 - 103500000*p**3*q*r**3*s**2 - 30000000*q**3*r**3*s**2 - 90000000*p*q*r**4*s**2 + 708750*p**8*s**3 + 5400000*p**5*q**2*s**3 - 8906250*p**2*q**4*s**3 - 18562500*p**6*r*s**3 + 625000*p**3*q**2*r*s**3 - 29687500*q**4*r*s**3 + 75000000*p**4*r**2*s**3 + 416250000*p*q**2*r**2*s**3 - 60000000*p**2*r**3*s**3 + 300000000*r**4*s**3 - 71718750*p**4*q*s**4 - 189062500*p*q**3*s**4 - 210937500*p**2*q*r*s**4 - 1187500000*q*r**2*s**4 + 187500000*p**3*s**5 + 800781250*q**2*s**5 + 390625000*p*r*s**5 + + b[1][3] = 500*p**6*q**5 + 6350*p**3*q**7 + 19800*q**9 - 3750*p**7*q**3*r - 65100*p**4*q**5*r - 264950*p*q**7*r + 6750*p**8*q*r**2 + 209050*p**5*q**3*r**2 + 1217250*p**2*q**5*r**2 - 219000*p**6*q*r**3 - 2510000*p**3*q**3*r**3 - 1098500*q**5*r**3 + 2068000*p**4*q*r**4 + 5060000*p*q**3*r**4 - 5200000*p**2*q*r**5 + 6750*p**8*q**2*s + 96350*p**5*q**4*s + 346000*p**2*q**6*s - 20250*p**9*r*s - 459900*p**6*q**2*r*s - 1828750*p**3*q**4*r*s + 2930000*q**6*r*s + 594000*p**7*r**2*s + 4301250*p**4*q**2*r**2*s - 10906250*p*q**4*r**2*s - 5252000*p**5*r**3*s + 1450000*p**2*q**2*r**3*s + 12800000*p**3*r**4*s + 6500000*q**2*r**4*s - 74250*p**7*q*s**2 - 1418750*p**4*q**3*s**2 - 5956250*p*q**5*s**2 + 4297500*p**5*q*r*s**2 + 29906250*p**2*q**3*r*s**2 - 31500000*p**3*q*r**2*s**2 - 12500000*q**3*r**2*s**2 - 35000000*p*q*r**3*s**2 - 1350000*p**6*s**3 - 6093750*p**3*q**2*s**3 - 17500000*q**4*s**3 + 7031250*p**4*r*s**3 + 127812500*p*q**2*r*s**3 - 18750000*p**2*r**2*s**3 + 162500000*r**3*s**3 - 107812500*p**2*q*s**4 - 460937500*q*r*s**4 + 214843750*p*s**5 + + b[1][2] = -1950*p**4*q**5 - 14100*p*q**7 + 14350*p**5*q**3*r + 125600*p**2*q**5*r - 27900*p**6*q*r**2 - 402250*p**3*q**3*r**2 - 288250*q**5*r**2 + 436000*p**4*q*r**3 + 1345000*p*q**3*r**3 - 1400000*p**2*q*r**4 - 9450*p**6*q**2*s + 1250*p**3*q**4*s + 465000*q**6*s + 49950*p**7*r*s + 302500*p**4*q**2*r*s - 1718750*p*q**4*r*s - 834000*p**5*r**2*s - 437500*p**2*q**2*r**2*s + 3100000*p**3*r**3*s + 1750000*q**2*r**3*s + 292500*p**5*q*s**2 + 1937500*p**2*q**3*s**2 - 3343750*p**3*q*r*s**2 - 1875000*q**3*r*s**2 - 8125000*p*q*r**2*s**2 + 1406250*p**4*s**3 + 12343750*p*q**2*s**3 - 5312500*p**2*r*s**3 + 43750000*r**2*s**3 - 74218750*q*s**4 + + b[1][1] = 300*p**5*q**3 + 2150*p**2*q**5 - 1350*p**6*q*r - 21500*p**3*q**3*r - 61500*q**5*r + 42000*p**4*q*r**2 + 290000*p*q**3*r**2 - 300000*p**2*q*r**3 + 4050*p**7*s + 45000*p**4*q**2*s + 125000*p*q**4*s - 108000*p**5*r*s - 643750*p**2*q**2*r*s + 700000*p**3*r**2*s + 375000*q**2*r**2*s + 93750*p**3*q*s**2 + 312500*q**3*s**2 - 1875000*p*q*r*s**2 + 1406250*p**2*s**3 + 9375000*r*s**3 + + b[1][0] = -1250*p**3*q**3 - 9000*q**5 + 4500*p**4*q*r + 46250*p*q**3*r - 50000*p**2*q*r**2 - 6750*p**5*s - 43750*p**2*q**2*s + 75000*p**3*r*s + 62500*q**2*r*s - 156250*p*q*s**2 + 1562500*s**3 + + b[2][5] = 200*p**6*q**11 - 250*p**3*q**13 - 10800*q**15 - 3900*p**7*q**9*r - 3325*p**4*q**11*r + 181800*p*q**13*r + 26950*p**8*q**7*r**2 + 69625*p**5*q**9*r**2 - 1214450*p**2*q**11*r**2 - 78725*p**9*q**5*r**3 - 368675*p**6*q**7*r**3 + 4166325*p**3*q**9*r**3 + 1131100*q**11*r**3 + 73400*p**10*q**3*r**4 + 661950*p**7*q**5*r**4 - 9151950*p**4*q**7*r**4 - 16633075*p*q**9*r**4 + 36000*p**11*q*r**5 + 135600*p**8*q**3*r**5 + 17321400*p**5*q**5*r**5 + 85338300*p**2*q**7*r**5 - 832000*p**9*q*r**6 - 21379200*p**6*q**3*r**6 - 176044000*p**3*q**5*r**6 - 1410000*q**7*r**6 + 6528000*p**7*q*r**7 + 129664000*p**4*q**3*r**7 + 47344000*p*q**5*r**7 - 21504000*p**5*q*r**8 - 115200000*p**2*q**3*r**8 + 25600000*p**3*q*r**9 + 64000000*q**3*r**9 + 15700*p**8*q**8*s + 120525*p**5*q**10*s + 113250*p**2*q**12*s - 196900*p**9*q**6*r*s - 1776925*p**6*q**8*r*s - 3062475*p**3*q**10*r*s - 4153500*q**12*r*s + 857925*p**10*q**4*r**2*s + 10562775*p**7*q**6*r**2*s + 34866250*p**4*q**8*r**2*s + 73486750*p*q**10*r**2*s - 1333800*p**11*q**2*r**3*s - 29212625*p**8*q**4*r**3*s - 168729675*p**5*q**6*r**3*s - 427230750*p**2*q**8*r**3*s + 108000*p**12*r**4*s + 30384200*p**9*q**2*r**4*s + 324535100*p**6*q**4*r**4*s + 952666750*p**3*q**6*r**4*s - 38076875*q**8*r**4*s - 4296000*p**10*r**5*s - 213606400*p**7*q**2*r**5*s - 842060000*p**4*q**4*r**5*s - 95285000*p*q**6*r**5*s + 61184000*p**8*r**6*s + 567520000*p**5*q**2*r**6*s + 547000000*p**2*q**4*r**6*s - 390912000*p**6*r**7*s - 812800000*p**3*q**2*r**7*s - 924000000*q**4*r**7*s + 1152000000*p**4*r**8*s + 800000000*p*q**2*r**8*s - 1280000000*p**2*r**9*s + 141750*p**10*q**5*s**2 - 31500*p**7*q**7*s**2 - 11325000*p**4*q**9*s**2 - 31687500*p*q**11*s**2 - 1293975*p**11*q**3*r*s**2 - 4803800*p**8*q**5*r*s**2 + 71398250*p**5*q**7*r*s**2 + 227625000*p**2*q**9*r*s**2 + 3256200*p**12*q*r**2*s**2 + 43870125*p**9*q**3*r**2*s**2 + 64581500*p**6*q**5*r**2*s**2 + 56090625*p**3*q**7*r**2*s**2 + 260218750*q**9*r**2*s**2 - 74610000*p**10*q*r**3*s**2 - 662186500*p**7*q**3*r**3*s**2 - 1987747500*p**4*q**5*r**3*s**2 - 811928125*p*q**7*r**3*s**2 + 471286000*p**8*q*r**4*s**2 + 2106040000*p**5*q**3*r**4*s**2 + 792687500*p**2*q**5*r**4*s**2 - 135120000*p**6*q*r**5*s**2 + 2479000000*p**3*q**3*r**5*s**2 + 5242250000*q**5*r**5*s**2 - 6400000000*p**4*q*r**6*s**2 - 8620000000*p*q**3*r**6*s**2 + 13280000000*p**2*q*r**7*s**2 + 1600000000*q*r**8*s**2 + 273375*p**12*q**2*s**3 - 13612500*p**9*q**4*s**3 - 177250000*p**6*q**6*s**3 - 511015625*p**3*q**8*s**3 - 320937500*q**10*s**3 - 2770200*p**13*r*s**3 + 12595500*p**10*q**2*r*s**3 + 543950000*p**7*q**4*r*s**3 + 1612281250*p**4*q**6*r*s**3 + 968125000*p*q**8*r*s**3 + 77031000*p**11*r**2*s**3 + 373218750*p**8*q**2*r**2*s**3 + 1839765625*p**5*q**4*r**2*s**3 + 1818515625*p**2*q**6*r**2*s**3 - 776745000*p**9*r**3*s**3 - 6861075000*p**6*q**2*r**3*s**3 - 20014531250*p**3*q**4*r**3*s**3 - 13747812500*q**6*r**3*s**3 + 3768000000*p**7*r**4*s**3 + 35365000000*p**4*q**2*r**4*s**3 + 34441875000*p*q**4*r**4*s**3 - 9628000000*p**5*r**5*s**3 - 63230000000*p**2*q**2*r**5*s**3 + 13600000000*p**3*r**6*s**3 - 15000000000*q**2*r**6*s**3 - 10400000000*p*r**7*s**3 - 45562500*p**11*q*s**4 - 525937500*p**8*q**3*s**4 - 1364218750*p**5*q**5*s**4 - 1382812500*p**2*q**7*s**4 + 572062500*p**9*q*r*s**4 + 2473515625*p**6*q**3*r*s**4 + 13192187500*p**3*q**5*r*s**4 + 12703125000*q**7*r*s**4 - 451406250*p**7*q*r**2*s**4 - 18153906250*p**4*q**3*r**2*s**4 - 36908203125*p*q**5*r**2*s**4 - 9069375000*p**5*q*r**3*s**4 + 79957812500*p**2*q**3*r**3*s**4 + 5512500000*p**3*q*r**4*s**4 + 50656250000*q**3*r**4*s**4 + 74750000000*p*q*r**5*s**4 + 56953125*p**10*s**5 + 1381640625*p**7*q**2*s**5 - 781250000*p**4*q**4*s**5 + 878906250*p*q**6*s**5 - 2655703125*p**8*r*s**5 - 3223046875*p**5*q**2*r*s**5 - 35117187500*p**2*q**4*r*s**5 + 26573437500*p**6*r**2*s**5 + 14785156250*p**3*q**2*r**2*s**5 - 52050781250*q**4*r**2*s**5 - 103062500000*p**4*r**3*s**5 - 281796875000*p*q**2*r**3*s**5 + 146875000000*p**2*r**4*s**5 - 37500000000*r**5*s**5 - 8789062500*p**6*q*s**6 - 3906250000*p**3*q**3*s**6 + 1464843750*q**5*s**6 + 102929687500*p**4*q*r*s**6 + 297119140625*p*q**3*r*s**6 - 217773437500*p**2*q*r**2*s**6 + 167968750000*q*r**3*s**6 + 10986328125*p**5*s**7 + 98876953125*p**2*q**2*s**7 - 188964843750*p**3*r*s**7 - 278320312500*q**2*r*s**7 + 517578125000*p*r**2*s**7 - 610351562500*p*q*s**8 + 762939453125*s**9 + + b[2][4] = -200*p**7*q**9 + 1850*p**4*q**11 + 21600*p*q**13 + 3200*p**8*q**7*r - 19200*p**5*q**9*r - 316350*p**2*q**11*r - 19050*p**9*q**5*r**2 + 37400*p**6*q**7*r**2 + 1759250*p**3*q**9*r**2 + 440100*q**11*r**2 + 48750*p**10*q**3*r**3 + 190200*p**7*q**5*r**3 - 4604200*p**4*q**7*r**3 - 6072800*p*q**9*r**3 - 43200*p**11*q*r**4 - 834500*p**8*q**3*r**4 + 4916000*p**5*q**5*r**4 + 27926850*p**2*q**7*r**4 + 969600*p**9*q*r**5 + 2467200*p**6*q**3*r**5 - 45393200*p**3*q**5*r**5 - 5399500*q**7*r**5 - 7283200*p**7*q*r**6 + 10536000*p**4*q**3*r**6 + 41656000*p*q**5*r**6 + 22784000*p**5*q*r**7 - 35200000*p**2*q**3*r**7 - 25600000*p**3*q*r**8 + 96000000*q**3*r**8 - 3000*p**9*q**6*s + 40400*p**6*q**8*s + 136550*p**3*q**10*s - 1647000*q**12*s + 40500*p**10*q**4*r*s - 173600*p**7*q**6*r*s - 126500*p**4*q**8*r*s + 23969250*p*q**10*r*s - 153900*p**11*q**2*r**2*s - 486150*p**8*q**4*r**2*s - 4115800*p**5*q**6*r**2*s - 112653250*p**2*q**8*r**2*s + 129600*p**12*r**3*s + 2683350*p**9*q**2*r**3*s + 10906650*p**6*q**4*r**3*s + 187289500*p**3*q**6*r**3*s + 44098750*q**8*r**3*s - 4384800*p**10*r**4*s - 35660800*p**7*q**2*r**4*s - 175420000*p**4*q**4*r**4*s - 426538750*p*q**6*r**4*s + 60857600*p**8*r**5*s + 349436000*p**5*q**2*r**5*s + 900600000*p**2*q**4*r**5*s - 429568000*p**6*r**6*s - 1511200000*p**3*q**2*r**6*s - 1286000000*q**4*r**6*s + 1472000000*p**4*r**7*s + 1440000000*p*q**2*r**7*s - 1920000000*p**2*r**8*s - 36450*p**11*q**3*s**2 - 188100*p**8*q**5*s**2 - 5504750*p**5*q**7*s**2 - 37968750*p**2*q**9*s**2 + 255150*p**12*q*r*s**2 + 2754000*p**9*q**3*r*s**2 + 49196500*p**6*q**5*r*s**2 + 323587500*p**3*q**7*r*s**2 - 83250000*q**9*r*s**2 - 465750*p**10*q*r**2*s**2 - 31881500*p**7*q**3*r**2*s**2 - 415585000*p**4*q**5*r**2*s**2 + 1054775000*p*q**7*r**2*s**2 - 96823500*p**8*q*r**3*s**2 - 701490000*p**5*q**3*r**3*s**2 - 2953531250*p**2*q**5*r**3*s**2 + 1454560000*p**6*q*r**4*s**2 + 7670500000*p**3*q**3*r**4*s**2 + 5661062500*q**5*r**4*s**2 - 7785000000*p**4*q*r**5*s**2 - 9450000000*p*q**3*r**5*s**2 + 14000000000*p**2*q*r**6*s**2 + 2400000000*q*r**7*s**2 - 437400*p**13*s**3 - 10145250*p**10*q**2*s**3 - 121912500*p**7*q**4*s**3 - 576531250*p**4*q**6*s**3 - 528593750*p*q**8*s**3 + 12939750*p**11*r*s**3 + 313368750*p**8*q**2*r*s**3 + 2171812500*p**5*q**4*r*s**3 + 2381718750*p**2*q**6*r*s**3 - 124638750*p**9*r**2*s**3 - 3001575000*p**6*q**2*r**2*s**3 - 12259375000*p**3*q**4*r**2*s**3 - 9985312500*q**6*r**2*s**3 + 384000000*p**7*r**3*s**3 + 13997500000*p**4*q**2*r**3*s**3 + 20749531250*p*q**4*r**3*s**3 - 553500000*p**5*r**4*s**3 - 41835000000*p**2*q**2*r**4*s**3 + 5420000000*p**3*r**5*s**3 - 16300000000*q**2*r**5*s**3 - 17600000000*p*r**6*s**3 - 7593750*p**9*q*s**4 + 289218750*p**6*q**3*s**4 + 3591406250*p**3*q**5*s**4 + 5992187500*q**7*s**4 + 658125000*p**7*q*r*s**4 - 269531250*p**4*q**3*r*s**4 - 15882812500*p*q**5*r*s**4 - 4785000000*p**5*q*r**2*s**4 + 54375781250*p**2*q**3*r**2*s**4 - 5668750000*p**3*q*r**3*s**4 + 35867187500*q**3*r**3*s**4 + 113875000000*p*q*r**4*s**4 - 544218750*p**8*s**5 - 5407031250*p**5*q**2*s**5 - 14277343750*p**2*q**4*s**5 + 5421093750*p**6*r*s**5 - 24941406250*p**3*q**2*r*s**5 - 25488281250*q**4*r*s**5 - 11500000000*p**4*r**2*s**5 - 231894531250*p*q**2*r**2*s**5 - 6250000000*p**2*r**3*s**5 - 43750000000*r**4*s**5 + 35449218750*p**4*q*s**6 + 137695312500*p*q**3*s**6 + 34667968750*p**2*q*r*s**6 + 202148437500*q*r**2*s**6 - 33691406250*p**3*s**7 - 214843750000*q**2*s**7 - 31738281250*p*r*s**7 + + b[2][3] = -800*p**5*q**9 - 5400*p**2*q**11 + 5800*p**6*q**7*r + 48750*p**3*q**9*r + 16200*q**11*r - 3000*p**7*q**5*r**2 - 108350*p**4*q**7*r**2 - 263250*p*q**9*r**2 - 60700*p**8*q**3*r**3 - 386250*p**5*q**5*r**3 + 253100*p**2*q**7*r**3 + 127800*p**9*q*r**4 + 2326700*p**6*q**3*r**4 + 6565550*p**3*q**5*r**4 - 705750*q**7*r**4 - 2903200*p**7*q*r**5 - 21218000*p**4*q**3*r**5 + 1057000*p*q**5*r**5 + 20368000*p**5*q*r**6 + 33000000*p**2*q**3*r**6 - 43200000*p**3*q*r**7 + 52000000*q**3*r**7 + 6200*p**7*q**6*s + 188250*p**4*q**8*s + 931500*p*q**10*s - 73800*p**8*q**4*r*s - 1466850*p**5*q**6*r*s - 6894000*p**2*q**8*r*s + 315900*p**9*q**2*r**2*s + 4547000*p**6*q**4*r**2*s + 20362500*p**3*q**6*r**2*s + 15018750*q**8*r**2*s - 653400*p**10*r**3*s - 13897550*p**7*q**2*r**3*s - 76757500*p**4*q**4*r**3*s - 124207500*p*q**6*r**3*s + 18567600*p**8*r**4*s + 175911000*p**5*q**2*r**4*s + 253787500*p**2*q**4*r**4*s - 183816000*p**6*r**5*s - 706900000*p**3*q**2*r**5*s - 665750000*q**4*r**5*s + 740000000*p**4*r**6*s + 890000000*p*q**2*r**6*s - 1040000000*p**2*r**7*s - 763000*p**6*q**5*s**2 - 12375000*p**3*q**7*s**2 - 40500000*q**9*s**2 + 364500*p**10*q*r*s**2 + 15537000*p**7*q**3*r*s**2 + 154392500*p**4*q**5*r*s**2 + 372206250*p*q**7*r*s**2 - 25481250*p**8*q*r**2*s**2 - 386300000*p**5*q**3*r**2*s**2 - 996343750*p**2*q**5*r**2*s**2 + 459872500*p**6*q*r**3*s**2 + 2943937500*p**3*q**3*r**3*s**2 + 2437781250*q**5*r**3*s**2 - 2883750000*p**4*q*r**4*s**2 - 4343750000*p*q**3*r**4*s**2 + 5495000000*p**2*q*r**5*s**2 + 1300000000*q*r**6*s**2 - 364500*p**11*s**3 - 13668750*p**8*q**2*s**3 - 113406250*p**5*q**4*s**3 - 159062500*p**2*q**6*s**3 + 13972500*p**9*r*s**3 + 61537500*p**6*q**2*r*s**3 - 1622656250*p**3*q**4*r*s**3 - 2720625000*q**6*r*s**3 - 201656250*p**7*r**2*s**3 + 1949687500*p**4*q**2*r**2*s**3 + 4979687500*p*q**4*r**2*s**3 + 497125000*p**5*r**3*s**3 - 11150625000*p**2*q**2*r**3*s**3 + 2982500000*p**3*r**4*s**3 - 6612500000*q**2*r**4*s**3 - 10450000000*p*r**5*s**3 + 126562500*p**7*q*s**4 + 1443750000*p**4*q**3*s**4 + 281250000*p*q**5*s**4 - 1648125000*p**5*q*r*s**4 + 11271093750*p**2*q**3*r*s**4 - 4785156250*p**3*q*r**2*s**4 + 8808593750*q**3*r**2*s**4 + 52390625000*p*q*r**3*s**4 - 611718750*p**6*s**5 - 13027343750*p**3*q**2*s**5 - 1464843750*q**4*s**5 + 6492187500*p**4*r*s**5 - 65351562500*p*q**2*r*s**5 - 13476562500*p**2*r**2*s**5 - 24218750000*r**3*s**5 + 41992187500*p**2*q*s**6 + 69824218750*q*r*s**6 - 34179687500*p*s**7 + + b[2][2] = -1000*p**6*q**7 - 5150*p**3*q**9 + 10800*q**11 + 11000*p**7*q**5*r + 66450*p**4*q**7*r - 127800*p*q**9*r - 41250*p**8*q**3*r**2 - 368400*p**5*q**5*r**2 + 204200*p**2*q**7*r**2 + 54000*p**9*q*r**3 + 1040950*p**6*q**3*r**3 + 2096500*p**3*q**5*r**3 + 200000*q**7*r**3 - 1140000*p**7*q*r**4 - 7691000*p**4*q**3*r**4 - 2281000*p*q**5*r**4 + 7296000*p**5*q*r**5 + 13300000*p**2*q**3*r**5 - 14400000*p**3*q*r**6 + 14000000*q**3*r**6 - 9000*p**8*q**4*s + 52100*p**5*q**6*s + 710250*p**2*q**8*s + 67500*p**9*q**2*r*s - 256100*p**6*q**4*r*s - 5753000*p**3*q**6*r*s + 292500*q**8*r*s - 162000*p**10*r**2*s - 1432350*p**7*q**2*r**2*s + 5410000*p**4*q**4*r**2*s - 7408750*p*q**6*r**2*s + 4401000*p**8*r**3*s + 24185000*p**5*q**2*r**3*s + 20781250*p**2*q**4*r**3*s - 43012000*p**6*r**4*s - 146300000*p**3*q**2*r**4*s - 165875000*q**4*r**4*s + 182000000*p**4*r**5*s + 250000000*p*q**2*r**5*s - 280000000*p**2*r**6*s + 60750*p**10*q*s**2 + 2414250*p**7*q**3*s**2 + 15770000*p**4*q**5*s**2 + 15825000*p*q**7*s**2 - 6021000*p**8*q*r*s**2 - 62252500*p**5*q**3*r*s**2 - 74718750*p**2*q**5*r*s**2 + 90888750*p**6*q*r**2*s**2 + 471312500*p**3*q**3*r**2*s**2 + 525875000*q**5*r**2*s**2 - 539375000*p**4*q*r**3*s**2 - 1030000000*p*q**3*r**3*s**2 + 1142500000*p**2*q*r**4*s**2 + 350000000*q*r**5*s**2 - 303750*p**9*s**3 - 35943750*p**6*q**2*s**3 - 331875000*p**3*q**4*s**3 - 505937500*q**6*s**3 + 8437500*p**7*r*s**3 + 530781250*p**4*q**2*r*s**3 + 1150312500*p*q**4*r*s**3 - 154500000*p**5*r**2*s**3 - 2059062500*p**2*q**2*r**2*s**3 + 1150000000*p**3*r**3*s**3 - 1343750000*q**2*r**3*s**3 - 2900000000*p*r**4*s**3 + 30937500*p**5*q*s**4 + 1166406250*p**2*q**3*s**4 - 1496875000*p**3*q*r*s**4 + 1296875000*q**3*r*s**4 + 10640625000*p*q*r**2*s**4 - 281250000*p**4*s**5 - 9746093750*p*q**2*s**5 + 1269531250*p**2*r*s**5 - 7421875000*r**2*s**5 + 15625000000*q*s**6 + + b[2][1] = -1600*p**4*q**7 - 10800*p*q**9 + 9800*p**5*q**5*r + 80550*p**2*q**7*r - 4600*p**6*q**3*r**2 - 112700*p**3*q**5*r**2 + 40500*q**7*r**2 - 34200*p**7*q*r**3 - 279500*p**4*q**3*r**3 - 665750*p*q**5*r**3 + 632000*p**5*q*r**4 + 3200000*p**2*q**3*r**4 - 2800000*p**3*q*r**5 + 3000000*q**3*r**5 - 18600*p**6*q**4*s - 51750*p**3*q**6*s + 405000*q**8*s + 21600*p**7*q**2*r*s - 122500*p**4*q**4*r*s - 2891250*p*q**6*r*s + 156600*p**8*r**2*s + 1569750*p**5*q**2*r**2*s + 6943750*p**2*q**4*r**2*s - 3774000*p**6*r**3*s - 27100000*p**3*q**2*r**3*s - 30187500*q**4*r**3*s + 28000000*p**4*r**4*s + 52500000*p*q**2*r**4*s - 60000000*p**2*r**5*s - 81000*p**8*q*s**2 - 240000*p**5*q**3*s**2 + 937500*p**2*q**5*s**2 + 3273750*p**6*q*r*s**2 + 30406250*p**3*q**3*r*s**2 + 55687500*q**5*r*s**2 - 42187500*p**4*q*r**2*s**2 - 112812500*p*q**3*r**2*s**2 + 152500000*p**2*q*r**3*s**2 + 75000000*q*r**4*s**2 - 4218750*p**4*q**2*s**3 + 15156250*p*q**4*s**3 + 5906250*p**5*r*s**3 - 206562500*p**2*q**2*r*s**3 + 107500000*p**3*r**2*s**3 - 159375000*q**2*r**2*s**3 - 612500000*p*r**3*s**3 + 135937500*p**3*q*s**4 + 46875000*q**3*s**4 + 1175781250*p*q*r*s**4 - 292968750*p**2*s**5 - 1367187500*r*s**5 + + b[2][0] = -800*p**5*q**5 - 5400*p**2*q**7 + 6000*p**6*q**3*r + 51700*p**3*q**5*r + 27000*q**7*r - 10800*p**7*q*r**2 - 163250*p**4*q**3*r**2 - 285750*p*q**5*r**2 + 192000*p**5*q*r**3 + 1000000*p**2*q**3*r**3 - 800000*p**3*q*r**4 + 500000*q**3*r**4 - 10800*p**7*q**2*s - 57500*p**4*q**4*s + 67500*p*q**6*s + 32400*p**8*r*s + 279000*p**5*q**2*r*s - 131250*p**2*q**4*r*s - 729000*p**6*r**2*s - 4100000*p**3*q**2*r**2*s - 5343750*q**4*r**2*s + 5000000*p**4*r**3*s + 10000000*p*q**2*r**3*s - 10000000*p**2*r**4*s + 641250*p**6*q*s**2 + 5812500*p**3*q**3*s**2 + 10125000*q**5*s**2 - 7031250*p**4*q*r*s**2 - 20625000*p*q**3*r*s**2 + 17500000*p**2*q*r**2*s**2 + 12500000*q*r**3*s**2 - 843750*p**5*s**3 - 19375000*p**2*q**2*s**3 + 30000000*p**3*r*s**3 - 20312500*q**2*r*s**3 - 112500000*p*r**2*s**3 + 183593750*p*q*s**4 - 292968750*s**5 + + b[3][5] = 500*p**11*q**6 + 9875*p**8*q**8 + 42625*p**5*q**10 - 35000*p**2*q**12 - 4500*p**12*q**4*r - 108375*p**9*q**6*r - 516750*p**6*q**8*r + 1110500*p**3*q**10*r + 2730000*q**12*r + 10125*p**13*q**2*r**2 + 358250*p**10*q**4*r**2 + 1908625*p**7*q**6*r**2 - 11744250*p**4*q**8*r**2 - 43383250*p*q**10*r**2 - 313875*p**11*q**2*r**3 - 2074875*p**8*q**4*r**3 + 52094750*p**5*q**6*r**3 + 264567500*p**2*q**8*r**3 + 796125*p**9*q**2*r**4 - 92486250*p**6*q**4*r**4 - 757957500*p**3*q**6*r**4 - 29354375*q**8*r**4 + 60970000*p**7*q**2*r**5 + 1112462500*p**4*q**4*r**5 + 571094375*p*q**6*r**5 - 685290000*p**5*q**2*r**6 - 2037800000*p**2*q**4*r**6 + 2279600000*p**3*q**2*r**7 + 849000000*q**4*r**7 - 1480000000*p*q**2*r**8 + 13500*p**13*q**3*s + 363000*p**10*q**5*s + 2861250*p**7*q**7*s + 8493750*p**4*q**9*s + 17031250*p*q**11*s - 60750*p**14*q*r*s - 2319750*p**11*q**3*r*s - 22674250*p**8*q**5*r*s - 74368750*p**5*q**7*r*s - 170578125*p**2*q**9*r*s + 2760750*p**12*q*r**2*s + 46719000*p**9*q**3*r**2*s + 163356375*p**6*q**5*r**2*s + 360295625*p**3*q**7*r**2*s - 195990625*q**9*r**2*s - 37341750*p**10*q*r**3*s - 194739375*p**7*q**3*r**3*s - 105463125*p**4*q**5*r**3*s - 415825000*p*q**7*r**3*s + 90180000*p**8*q*r**4*s - 990552500*p**5*q**3*r**4*s + 3519212500*p**2*q**5*r**4*s + 1112220000*p**6*q*r**5*s - 4508750000*p**3*q**3*r**5*s - 8159500000*q**5*r**5*s - 4356000000*p**4*q*r**6*s + 14615000000*p*q**3*r**6*s - 2160000000*p**2*q*r**7*s + 91125*p**15*s**2 + 3290625*p**12*q**2*s**2 + 35100000*p**9*q**4*s**2 + 175406250*p**6*q**6*s**2 + 629062500*p**3*q**8*s**2 + 910937500*q**10*s**2 - 5710500*p**13*r*s**2 - 100423125*p**10*q**2*r*s**2 - 604743750*p**7*q**4*r*s**2 - 2954843750*p**4*q**6*r*s**2 - 4587578125*p*q**8*r*s**2 + 116194500*p**11*r**2*s**2 + 1280716250*p**8*q**2*r**2*s**2 + 7401190625*p**5*q**4*r**2*s**2 + 11619937500*p**2*q**6*r**2*s**2 - 952173125*p**9*r**3*s**2 - 6519712500*p**6*q**2*r**3*s**2 - 10238593750*p**3*q**4*r**3*s**2 + 29984609375*q**6*r**3*s**2 + 2558300000*p**7*r**4*s**2 + 16225000000*p**4*q**2*r**4*s**2 - 64994140625*p*q**4*r**4*s**2 + 4202250000*p**5*r**5*s**2 + 46925000000*p**2*q**2*r**5*s**2 - 28950000000*p**3*r**6*s**2 - 1000000000*q**2*r**6*s**2 + 37000000000*p*r**7*s**2 - 48093750*p**11*q*s**3 - 673359375*p**8*q**3*s**3 - 2170312500*p**5*q**5*s**3 - 2466796875*p**2*q**7*s**3 + 647578125*p**9*q*r*s**3 + 597031250*p**6*q**3*r*s**3 - 7542578125*p**3*q**5*r*s**3 - 41125000000*q**7*r*s**3 - 2175828125*p**7*q*r**2*s**3 - 7101562500*p**4*q**3*r**2*s**3 + 100596875000*p*q**5*r**2*s**3 - 8984687500*p**5*q*r**3*s**3 - 120070312500*p**2*q**3*r**3*s**3 + 57343750000*p**3*q*r**4*s**3 + 9500000000*q**3*r**4*s**3 - 342875000000*p*q*r**5*s**3 + 400781250*p**10*s**4 + 8531250000*p**7*q**2*s**4 + 34033203125*p**4*q**4*s**4 + 42724609375*p*q**6*s**4 - 6289453125*p**8*r*s**4 - 24037109375*p**5*q**2*r*s**4 - 62626953125*p**2*q**4*r*s**4 + 17299218750*p**6*r**2*s**4 + 108357421875*p**3*q**2*r**2*s**4 - 55380859375*q**4*r**2*s**4 + 105648437500*p**4*r**3*s**4 + 1204228515625*p*q**2*r**3*s**4 - 365000000000*p**2*r**4*s**4 + 184375000000*r**5*s**4 - 32080078125*p**6*q*s**5 - 98144531250*p**3*q**3*s**5 + 93994140625*q**5*s**5 - 178955078125*p**4*q*r*s**5 - 1299804687500*p*q**3*r*s**5 + 332421875000*p**2*q*r**2*s**5 - 1195312500000*q*r**3*s**5 + 72021484375*p**5*s**6 + 323486328125*p**2*q**2*s**6 + 682373046875*p**3*r*s**6 + 2447509765625*q**2*r*s**6 - 3011474609375*p*r**2*s**6 + 3051757812500*p*q*s**7 - 7629394531250*s**8 + + b[3][4] = 1500*p**9*q**6 + 69625*p**6*q**8 + 590375*p**3*q**10 + 1035000*q**12 - 13500*p**10*q**4*r - 760625*p**7*q**6*r - 7904500*p**4*q**8*r - 18169250*p*q**10*r + 30375*p**11*q**2*r**2 + 2628625*p**8*q**4*r**2 + 37879000*p**5*q**6*r**2 + 121367500*p**2*q**8*r**2 - 2699250*p**9*q**2*r**3 - 76776875*p**6*q**4*r**3 - 403583125*p**3*q**6*r**3 - 78865625*q**8*r**3 + 60907500*p**7*q**2*r**4 + 735291250*p**4*q**4*r**4 + 781142500*p*q**6*r**4 - 558270000*p**5*q**2*r**5 - 2150725000*p**2*q**4*r**5 + 2015400000*p**3*q**2*r**6 + 1181000000*q**4*r**6 - 2220000000*p*q**2*r**7 + 40500*p**11*q**3*s + 1376500*p**8*q**5*s + 9953125*p**5*q**7*s + 9765625*p**2*q**9*s - 182250*p**12*q*r*s - 8859000*p**9*q**3*r*s - 82854500*p**6*q**5*r*s - 71511250*p**3*q**7*r*s + 273631250*q**9*r*s + 10233000*p**10*q*r**2*s + 179627500*p**7*q**3*r**2*s + 25164375*p**4*q**5*r**2*s - 2927290625*p*q**7*r**2*s - 171305000*p**8*q*r**3*s - 544768750*p**5*q**3*r**3*s + 7583437500*p**2*q**5*r**3*s + 1139860000*p**6*q*r**4*s - 6489375000*p**3*q**3*r**4*s - 9625375000*q**5*r**4*s - 1838000000*p**4*q*r**5*s + 19835000000*p*q**3*r**5*s - 3240000000*p**2*q*r**6*s + 273375*p**13*s**2 + 9753750*p**10*q**2*s**2 + 82575000*p**7*q**4*s**2 + 202265625*p**4*q**6*s**2 + 556093750*p*q**8*s**2 - 11552625*p**11*r*s**2 - 115813125*p**8*q**2*r*s**2 + 630590625*p**5*q**4*r*s**2 + 1347015625*p**2*q**6*r*s**2 + 157578750*p**9*r**2*s**2 - 689206250*p**6*q**2*r**2*s**2 - 4299609375*p**3*q**4*r**2*s**2 + 23896171875*q**6*r**2*s**2 - 1022437500*p**7*r**3*s**2 + 6648125000*p**4*q**2*r**3*s**2 - 52895312500*p*q**4*r**3*s**2 + 4401750000*p**5*r**4*s**2 + 26500000000*p**2*q**2*r**4*s**2 - 22125000000*p**3*r**5*s**2 - 1500000000*q**2*r**5*s**2 + 55500000000*p*r**6*s**2 - 137109375*p**9*q*s**3 - 1955937500*p**6*q**3*s**3 - 6790234375*p**3*q**5*s**3 - 16996093750*q**7*s**3 + 2146218750*p**7*q*r*s**3 + 6570312500*p**4*q**3*r*s**3 + 39918750000*p*q**5*r*s**3 - 7673281250*p**5*q*r**2*s**3 - 52000000000*p**2*q**3*r**2*s**3 + 50796875000*p**3*q*r**3*s**3 + 18750000000*q**3*r**3*s**3 - 399875000000*p*q*r**4*s**3 + 780468750*p**8*s**4 + 14455078125*p**5*q**2*s**4 + 10048828125*p**2*q**4*s**4 - 15113671875*p**6*r*s**4 + 39298828125*p**3*q**2*r*s**4 - 52138671875*q**4*r*s**4 + 45964843750*p**4*r**2*s**4 + 914414062500*p*q**2*r**2*s**4 + 1953125000*p**2*r**3*s**4 + 334375000000*r**4*s**4 - 149169921875*p**4*q*s**5 - 459716796875*p*q**3*s**5 - 325585937500*p**2*q*r*s**5 - 1462890625000*q*r**2*s**5 + 296630859375*p**3*s**6 + 1324462890625*q**2*s**6 + 307617187500*p*r*s**6 + + b[3][3] = -20750*p**7*q**6 - 290125*p**4*q**8 - 993000*p*q**10 + 146125*p**8*q**4*r + 2721500*p**5*q**6*r + 11833750*p**2*q**8*r - 237375*p**9*q**2*r**2 - 8167500*p**6*q**4*r**2 - 54605625*p**3*q**6*r**2 - 23802500*q**8*r**2 + 8927500*p**7*q**2*r**3 + 131184375*p**4*q**4*r**3 + 254695000*p*q**6*r**3 - 121561250*p**5*q**2*r**4 - 728003125*p**2*q**4*r**4 + 702550000*p**3*q**2*r**5 + 597312500*q**4*r**5 - 1202500000*p*q**2*r**6 - 194625*p**9*q**3*s - 1568875*p**6*q**5*s + 9685625*p**3*q**7*s + 74662500*q**9*s + 327375*p**10*q*r*s + 1280000*p**7*q**3*r*s - 123703750*p**4*q**5*r*s - 850121875*p*q**7*r*s - 7436250*p**8*q*r**2*s + 164820000*p**5*q**3*r**2*s + 2336659375*p**2*q**5*r**2*s + 32202500*p**6*q*r**3*s - 2429765625*p**3*q**3*r**3*s - 4318609375*q**5*r**3*s + 148000000*p**4*q*r**4*s + 9902812500*p*q**3*r**4*s - 1755000000*p**2*q*r**5*s + 1154250*p**11*s**2 + 36821250*p**8*q**2*s**2 + 372825000*p**5*q**4*s**2 + 1170921875*p**2*q**6*s**2 - 38913750*p**9*r*s**2 - 797071875*p**6*q**2*r*s**2 - 2848984375*p**3*q**4*r*s**2 + 7651406250*q**6*r*s**2 + 415068750*p**7*r**2*s**2 + 3151328125*p**4*q**2*r**2*s**2 - 17696875000*p*q**4*r**2*s**2 - 725968750*p**5*r**3*s**2 + 5295312500*p**2*q**2*r**3*s**2 - 8581250000*p**3*r**4*s**2 - 812500000*q**2*r**4*s**2 + 30062500000*p*r**5*s**2 - 110109375*p**7*q*s**3 - 1976562500*p**4*q**3*s**3 - 6329296875*p*q**5*s**3 + 2256328125*p**5*q*r*s**3 + 8554687500*p**2*q**3*r*s**3 + 12947265625*p**3*q*r**2*s**3 + 7984375000*q**3*r**2*s**3 - 167039062500*p*q*r**3*s**3 + 1181250000*p**6*s**4 + 17873046875*p**3*q**2*s**4 - 20449218750*q**4*s**4 - 16265625000*p**4*r*s**4 + 260869140625*p*q**2*r*s**4 + 21025390625*p**2*r**2*s**4 + 207617187500*r**3*s**4 - 207177734375*p**2*q*s**5 - 615478515625*q*r*s**5 + 301513671875*p*s**6 + + b[3][2] = 53125*p**5*q**6 + 425000*p**2*q**8 - 394375*p**6*q**4*r - 4301875*p**3*q**6*r - 3225000*q**8*r + 851250*p**7*q**2*r**2 + 16910625*p**4*q**4*r**2 + 44210000*p*q**6*r**2 - 20474375*p**5*q**2*r**3 - 147190625*p**2*q**4*r**3 + 163975000*p**3*q**2*r**4 + 156812500*q**4*r**4 - 323750000*p*q**2*r**5 - 99375*p**7*q**3*s - 6395000*p**4*q**5*s - 49243750*p*q**7*s - 1164375*p**8*q*r*s + 4465625*p**5*q**3*r*s + 205546875*p**2*q**5*r*s + 12163750*p**6*q*r**2*s - 315546875*p**3*q**3*r**2*s - 946453125*q**5*r**2*s - 23500000*p**4*q*r**3*s + 2313437500*p*q**3*r**3*s - 472500000*p**2*q*r**4*s + 1316250*p**9*s**2 + 22715625*p**6*q**2*s**2 + 206953125*p**3*q**4*s**2 + 1220000000*q**6*s**2 - 20953125*p**7*r*s**2 - 277656250*p**4*q**2*r*s**2 - 3317187500*p*q**4*r*s**2 + 293734375*p**5*r**2*s**2 + 1351562500*p**2*q**2*r**2*s**2 - 2278125000*p**3*r**3*s**2 - 218750000*q**2*r**3*s**2 + 8093750000*p*r**4*s**2 - 9609375*p**5*q*s**3 + 240234375*p**2*q**3*s**3 + 2310546875*p**3*q*r*s**3 + 1171875000*q**3*r*s**3 - 33460937500*p*q*r**2*s**3 + 2185546875*p**4*s**4 + 32578125000*p*q**2*s**4 - 8544921875*p**2*r*s**4 + 58398437500*r**2*s**4 - 114013671875*q*s**5 + + b[3][1] = -16250*p**6*q**4 - 191875*p**3*q**6 - 495000*q**8 + 73125*p**7*q**2*r + 1437500*p**4*q**4*r + 5866250*p*q**6*r - 2043125*p**5*q**2*r**2 - 17218750*p**2*q**4*r**2 + 19106250*p**3*q**2*r**3 + 34015625*q**4*r**3 - 69375000*p*q**2*r**4 - 219375*p**8*q*s - 2846250*p**5*q**3*s - 8021875*p**2*q**5*s + 3420000*p**6*q*r*s - 1640625*p**3*q**3*r*s - 152468750*q**5*r*s + 3062500*p**4*q*r**2*s + 381171875*p*q**3*r**2*s - 101250000*p**2*q*r**3*s + 2784375*p**7*s**2 + 43515625*p**4*q**2*s**2 + 115625000*p*q**4*s**2 - 48140625*p**5*r*s**2 - 307421875*p**2*q**2*r*s**2 - 25781250*p**3*r**2*s**2 - 46875000*q**2*r**2*s**2 + 1734375000*p*r**3*s**2 - 128906250*p**3*q*s**3 + 339843750*q**3*s**3 - 4583984375*p*q*r*s**3 + 2236328125*p**2*s**4 + 12255859375*r*s**4 + + b[3][0] = 31875*p**4*q**4 + 255000*p*q**6 - 82500*p**5*q**2*r - 1106250*p**2*q**4*r + 1653125*p**3*q**2*r**2 + 5187500*q**4*r**2 - 11562500*p*q**2*r**3 - 118125*p**6*q*s - 3593750*p**3*q**3*s - 23812500*q**5*s + 4656250*p**4*q*r*s + 67109375*p*q**3*r*s - 16875000*p**2*q*r**2*s - 984375*p**5*s**2 - 19531250*p**2*q**2*s**2 - 37890625*p**3*r*s**2 - 7812500*q**2*r*s**2 + 289062500*p*r**2*s**2 - 529296875*p*q*s**3 + 2343750000*s**4 + + b[4][5] = 600*p**10*q**10 + 13850*p**7*q**12 + 106150*p**4*q**14 + 270000*p*q**16 - 9300*p**11*q**8*r - 234075*p**8*q**10*r - 1942825*p**5*q**12*r - 5319900*p**2*q**14*r + 52050*p**12*q**6*r**2 + 1481025*p**9*q**8*r**2 + 13594450*p**6*q**10*r**2 + 40062750*p**3*q**12*r**2 - 3569400*q**14*r**2 - 122175*p**13*q**4*r**3 - 4260350*p**10*q**6*r**3 - 45052375*p**7*q**8*r**3 - 142634900*p**4*q**10*r**3 + 54186350*p*q**12*r**3 + 97200*p**14*q**2*r**4 + 5284225*p**11*q**4*r**4 + 70389525*p**8*q**6*r**4 + 232732850*p**5*q**8*r**4 - 318849400*p**2*q**10*r**4 - 2046000*p**12*q**2*r**5 - 43874125*p**9*q**4*r**5 - 107411850*p**6*q**6*r**5 + 948310700*p**3*q**8*r**5 - 34763575*q**10*r**5 + 5915600*p**10*q**2*r**6 - 115887800*p**7*q**4*r**6 - 1649542400*p**4*q**6*r**6 + 224468875*p*q**8*r**6 + 120252800*p**8*q**2*r**7 + 1779902000*p**5*q**4*r**7 - 288250000*p**2*q**6*r**7 - 915200000*p**6*q**2*r**8 - 1164000000*p**3*q**4*r**8 - 444200000*q**6*r**8 + 2502400000*p**4*q**2*r**9 + 1984000000*p*q**4*r**9 - 2880000000*p**2*q**2*r**10 + 20700*p**12*q**7*s + 551475*p**9*q**9*s + 5194875*p**6*q**11*s + 18985000*p**3*q**13*s + 16875000*q**15*s - 218700*p**13*q**5*r*s - 6606475*p**10*q**7*r*s - 69770850*p**7*q**9*r*s - 285325500*p**4*q**11*r*s - 292005000*p*q**13*r*s + 694575*p**14*q**3*r**2*s + 26187750*p**11*q**5*r**2*s + 328992825*p**8*q**7*r**2*s + 1573292400*p**5*q**9*r**2*s + 1930043875*p**2*q**11*r**2*s - 583200*p**15*q*r**3*s - 37263225*p**12*q**3*r**3*s - 638579425*p**9*q**5*r**3*s - 3920212225*p**6*q**7*r**3*s - 6327336875*p**3*q**9*r**3*s + 440969375*q**11*r**3*s + 13446000*p**13*q*r**4*s + 462330325*p**10*q**3*r**4*s + 4509088275*p**7*q**5*r**4*s + 11709795625*p**4*q**7*r**4*s - 3579565625*p*q**9*r**4*s - 85033600*p**11*q*r**5*s - 2136801600*p**8*q**3*r**5*s - 12221575800*p**5*q**5*r**5*s + 9431044375*p**2*q**7*r**5*s + 10643200*p**9*q*r**6*s + 4565594000*p**6*q**3*r**6*s - 1778590000*p**3*q**5*r**6*s + 4842175000*q**7*r**6*s + 712320000*p**7*q*r**7*s - 16182000000*p**4*q**3*r**7*s - 21918000000*p*q**5*r**7*s - 742400000*p**5*q*r**8*s + 31040000000*p**2*q**3*r**8*s + 1280000000*p**3*q*r**9*s + 4800000000*q**3*r**9*s + 230850*p**14*q**4*s**2 + 7373250*p**11*q**6*s**2 + 85045625*p**8*q**8*s**2 + 399140625*p**5*q**10*s**2 + 565031250*p**2*q**12*s**2 - 1257525*p**15*q**2*r*s**2 - 52728975*p**12*q**4*r*s**2 - 743466375*p**9*q**6*r*s**2 - 4144915000*p**6*q**8*r*s**2 - 7102690625*p**3*q**10*r*s**2 - 1389937500*q**12*r*s**2 + 874800*p**16*r**2*s**2 + 89851275*p**13*q**2*r**2*s**2 + 1897236775*p**10*q**4*r**2*s**2 + 14144163000*p**7*q**6*r**2*s**2 + 31942921875*p**4*q**8*r**2*s**2 + 13305118750*p*q**10*r**2*s**2 - 23004000*p**14*r**3*s**2 - 1450715475*p**11*q**2*r**3*s**2 - 19427105000*p**8*q**4*r**3*s**2 - 70634028750*p**5*q**6*r**3*s**2 - 47854218750*p**2*q**8*r**3*s**2 + 204710400*p**12*r**4*s**2 + 10875135000*p**9*q**2*r**4*s**2 + 83618806250*p**6*q**4*r**4*s**2 + 62744500000*p**3*q**6*r**4*s**2 - 19806718750*q**8*r**4*s**2 - 757094800*p**10*r**5*s**2 - 37718030000*p**7*q**2*r**5*s**2 - 22479500000*p**4*q**4*r**5*s**2 + 91556093750*p*q**6*r**5*s**2 + 2306320000*p**8*r**6*s**2 + 55539600000*p**5*q**2*r**6*s**2 - 112851250000*p**2*q**4*r**6*s**2 - 10720000000*p**6*r**7*s**2 - 64720000000*p**3*q**2*r**7*s**2 - 59925000000*q**4*r**7*s**2 + 28000000000*p**4*r**8*s**2 + 28000000000*p*q**2*r**8*s**2 - 24000000000*p**2*r**9*s**2 + 820125*p**16*q*s**3 + 36804375*p**13*q**3*s**3 + 552225000*p**10*q**5*s**3 + 3357593750*p**7*q**7*s**3 + 7146562500*p**4*q**9*s**3 + 3851562500*p*q**11*s**3 - 92400750*p**14*q*r*s**3 - 2350175625*p**11*q**3*r*s**3 - 19470640625*p**8*q**5*r*s**3 - 52820593750*p**5*q**7*r*s**3 - 45447734375*p**2*q**9*r*s**3 + 1824363000*p**12*q*r**2*s**3 + 31435234375*p**9*q**3*r**2*s**3 + 141717537500*p**6*q**5*r**2*s**3 + 228370781250*p**3*q**7*r**2*s**3 + 34610078125*q**9*r**2*s**3 - 17591825625*p**10*q*r**3*s**3 - 188927187500*p**7*q**3*r**3*s**3 - 502088984375*p**4*q**5*r**3*s**3 - 187849296875*p*q**7*r**3*s**3 + 75577750000*p**8*q*r**4*s**3 + 342800000000*p**5*q**3*r**4*s**3 + 295384296875*p**2*q**5*r**4*s**3 - 107681250000*p**6*q*r**5*s**3 + 53330000000*p**3*q**3*r**5*s**3 + 271586875000*q**5*r**5*s**3 - 26410000000*p**4*q*r**6*s**3 - 188200000000*p*q**3*r**6*s**3 + 92000000000*p**2*q*r**7*s**3 + 120000000000*q*r**8*s**3 + 47840625*p**15*s**4 + 1150453125*p**12*q**2*s**4 + 9229453125*p**9*q**4*s**4 + 24954687500*p**6*q**6*s**4 + 22978515625*p**3*q**8*s**4 + 1367187500*q**10*s**4 - 1193737500*p**13*r*s**4 - 20817843750*p**10*q**2*r*s**4 - 98640000000*p**7*q**4*r*s**4 - 225767187500*p**4*q**6*r*s**4 - 74707031250*p*q**8*r*s**4 + 13431318750*p**11*r**2*s**4 + 188709843750*p**8*q**2*r**2*s**4 + 875157656250*p**5*q**4*r**2*s**4 + 593812890625*p**2*q**6*r**2*s**4 - 69869296875*p**9*r**3*s**4 - 854811093750*p**6*q**2*r**3*s**4 - 1730658203125*p**3*q**4*r**3*s**4 - 570867187500*q**6*r**3*s**4 + 162075625000*p**7*r**4*s**4 + 1536375000000*p**4*q**2*r**4*s**4 + 765156250000*p*q**4*r**4*s**4 - 165988750000*p**5*r**5*s**4 - 728968750000*p**2*q**2*r**5*s**4 + 121500000000*p**3*r**6*s**4 - 1039375000000*q**2*r**6*s**4 - 100000000000*p*r**7*s**4 - 379687500*p**11*q*s**5 - 11607421875*p**8*q**3*s**5 - 20830078125*p**5*q**5*s**5 - 33691406250*p**2*q**7*s**5 - 41491406250*p**9*q*r*s**5 - 419054687500*p**6*q**3*r*s**5 - 129511718750*p**3*q**5*r*s**5 + 311767578125*q**7*r*s**5 + 620116015625*p**7*q*r**2*s**5 + 1154687500000*p**4*q**3*r**2*s**5 + 36455078125*p*q**5*r**2*s**5 - 2265953125000*p**5*q*r**3*s**5 - 1509521484375*p**2*q**3*r**3*s**5 + 2530468750000*p**3*q*r**4*s**5 + 3259765625000*q**3*r**4*s**5 + 93750000000*p*q*r**5*s**5 + 23730468750*p**10*s**6 + 243603515625*p**7*q**2*s**6 + 341552734375*p**4*q**4*s**6 - 12207031250*p*q**6*s**6 - 357099609375*p**8*r*s**6 - 298193359375*p**5*q**2*r*s**6 + 406738281250*p**2*q**4*r*s**6 + 1615683593750*p**6*r**2*s**6 + 558593750000*p**3*q**2*r**2*s**6 - 2811035156250*q**4*r**2*s**6 - 2960937500000*p**4*r**3*s**6 - 3802246093750*p*q**2*r**3*s**6 + 2347656250000*p**2*r**4*s**6 - 671875000000*r**5*s**6 - 651855468750*p**6*q*s**7 - 1458740234375*p**3*q**3*s**7 - 152587890625*q**5*s**7 + 1628417968750*p**4*q*r*s**7 + 3948974609375*p*q**3*r*s**7 - 916748046875*p**2*q*r**2*s**7 + 1611328125000*q*r**3*s**7 + 640869140625*p**5*s**8 + 1068115234375*p**2*q**2*s**8 - 2044677734375*p**3*r*s**8 - 3204345703125*q**2*r*s**8 + 1739501953125*p*r**2*s**8 + + b[4][4] = -600*p**11*q**8 - 14050*p**8*q**10 - 109100*p**5*q**12 - 280800*p**2*q**14 + 7200*p**12*q**6*r + 188700*p**9*q**8*r + 1621725*p**6*q**10*r + 4577075*p**3*q**12*r + 5400*q**14*r - 28350*p**13*q**4*r**2 - 910600*p**10*q**6*r**2 - 9237975*p**7*q**8*r**2 - 30718900*p**4*q**10*r**2 - 5575950*p*q**12*r**2 + 36450*p**14*q**2*r**3 + 1848125*p**11*q**4*r**3 + 25137775*p**8*q**6*r**3 + 109591450*p**5*q**8*r**3 + 70627650*p**2*q**10*r**3 - 1317150*p**12*q**2*r**4 - 32857100*p**9*q**4*r**4 - 219125575*p**6*q**6*r**4 - 327565875*p**3*q**8*r**4 - 13011875*q**10*r**4 + 16484150*p**10*q**2*r**5 + 222242250*p**7*q**4*r**5 + 642173750*p**4*q**6*r**5 + 101263750*p*q**8*r**5 - 79345000*p**8*q**2*r**6 - 433180000*p**5*q**4*r**6 - 93731250*p**2*q**6*r**6 - 74300000*p**6*q**2*r**7 - 1057900000*p**3*q**4*r**7 - 591175000*q**6*r**7 + 1891600000*p**4*q**2*r**8 + 2796000000*p*q**4*r**8 - 4320000000*p**2*q**2*r**9 - 16200*p**13*q**5*s - 359500*p**10*q**7*s - 2603825*p**7*q**9*s - 4590375*p**4*q**11*s + 12352500*p*q**13*s + 121500*p**14*q**3*r*s + 3227400*p**11*q**5*r*s + 27301725*p**8*q**7*r*s + 59480975*p**5*q**9*r*s - 137308875*p**2*q**11*r*s - 218700*p**15*q*r**2*s - 8903925*p**12*q**3*r**2*s - 100918225*p**9*q**5*r**2*s - 325291300*p**6*q**7*r**2*s + 365705000*p**3*q**9*r**2*s + 94342500*q**11*r**2*s + 7632900*p**13*q*r**3*s + 162995400*p**10*q**3*r**3*s + 974558975*p**7*q**5*r**3*s + 930991250*p**4*q**7*r**3*s - 495368750*p*q**9*r**3*s - 97344900*p**11*q*r**4*s - 1406739250*p**8*q**3*r**4*s - 5572526250*p**5*q**5*r**4*s - 1903987500*p**2*q**7*r**4*s + 678550000*p**9*q*r**5*s + 8176215000*p**6*q**3*r**5*s + 18082050000*p**3*q**5*r**5*s + 5435843750*q**7*r**5*s - 2979800000*p**7*q*r**6*s - 29163500000*p**4*q**3*r**6*s - 27417500000*p*q**5*r**6*s + 6282400000*p**5*q*r**7*s + 48690000000*p**2*q**3*r**7*s - 2880000000*p**3*q*r**8*s + 7200000000*q**3*r**8*s - 109350*p**15*q**2*s**2 - 2405700*p**12*q**4*s**2 - 16125250*p**9*q**6*s**2 - 4930000*p**6*q**8*s**2 + 201150000*p**3*q**10*s**2 - 243000000*q**12*s**2 + 328050*p**16*r*s**2 + 10552275*p**13*q**2*r*s**2 + 88019100*p**10*q**4*r*s**2 - 4208625*p**7*q**6*r*s**2 - 1920390625*p**4*q**8*r*s**2 + 1759537500*p*q**10*r*s**2 - 11955600*p**14*r**2*s**2 - 196375050*p**11*q**2*r**2*s**2 - 555196250*p**8*q**4*r**2*s**2 + 4213270000*p**5*q**6*r**2*s**2 - 157468750*p**2*q**8*r**2*s**2 + 162656100*p**12*r**3*s**2 + 1880870000*p**9*q**2*r**3*s**2 + 753684375*p**6*q**4*r**3*s**2 - 25423062500*p**3*q**6*r**3*s**2 - 14142031250*q**8*r**3*s**2 - 1251948750*p**10*r**4*s**2 - 12524475000*p**7*q**2*r**4*s**2 + 18067656250*p**4*q**4*r**4*s**2 + 60531875000*p*q**6*r**4*s**2 + 6827725000*p**8*r**5*s**2 + 57157000000*p**5*q**2*r**5*s**2 - 75844531250*p**2*q**4*r**5*s**2 - 24452500000*p**6*r**6*s**2 - 144950000000*p**3*q**2*r**6*s**2 - 82109375000*q**4*r**6*s**2 + 46950000000*p**4*r**7*s**2 + 60000000000*p*q**2*r**7*s**2 - 36000000000*p**2*r**8*s**2 + 1549125*p**14*q*s**3 + 51873750*p**11*q**3*s**3 + 599781250*p**8*q**5*s**3 + 2421156250*p**5*q**7*s**3 - 1693515625*p**2*q**9*s**3 - 104884875*p**12*q*r*s**3 - 1937437500*p**9*q**3*r*s**3 - 11461053125*p**6*q**5*r*s**3 + 10299375000*p**3*q**7*r*s**3 + 10551250000*q**9*r*s**3 + 1336263750*p**10*q*r**2*s**3 + 23737250000*p**7*q**3*r**2*s**3 + 57136718750*p**4*q**5*r**2*s**3 - 8288906250*p*q**7*r**2*s**3 - 10907218750*p**8*q*r**3*s**3 - 160615000000*p**5*q**3*r**3*s**3 - 111134687500*p**2*q**5*r**3*s**3 + 46743125000*p**6*q*r**4*s**3 + 570509375000*p**3*q**3*r**4*s**3 + 274839843750*q**5*r**4*s**3 - 73312500000*p**4*q*r**5*s**3 - 145437500000*p*q**3*r**5*s**3 + 8750000000*p**2*q*r**6*s**3 + 180000000000*q*r**7*s**3 + 15946875*p**13*s**4 + 1265625*p**10*q**2*s**4 - 3282343750*p**7*q**4*s**4 - 38241406250*p**4*q**6*s**4 - 40136718750*p*q**8*s**4 - 113146875*p**11*r*s**4 - 2302734375*p**8*q**2*r*s**4 + 68450156250*p**5*q**4*r*s**4 + 177376562500*p**2*q**6*r*s**4 + 3164062500*p**9*r**2*s**4 + 14392890625*p**6*q**2*r**2*s**4 - 543781250000*p**3*q**4*r**2*s**4 - 319769531250*q**6*r**2*s**4 - 21048281250*p**7*r**3*s**4 - 240687500000*p**4*q**2*r**3*s**4 - 228164062500*p*q**4*r**3*s**4 + 23062500000*p**5*r**4*s**4 + 300410156250*p**2*q**2*r**4*s**4 + 93437500000*p**3*r**5*s**4 - 1141015625000*q**2*r**5*s**4 - 187500000000*p*r**6*s**4 + 1761328125*p**9*q*s**5 - 3177734375*p**6*q**3*s**5 + 60019531250*p**3*q**5*s**5 + 108398437500*q**7*s**5 + 24106640625*p**7*q*r*s**5 + 429589843750*p**4*q**3*r*s**5 + 410371093750*p*q**5*r*s**5 - 23582031250*p**5*q*r**2*s**5 + 202441406250*p**2*q**3*r**2*s**5 - 383203125000*p**3*q*r**3*s**5 + 2232910156250*q**3*r**3*s**5 + 1500000000000*p*q*r**4*s**5 - 13710937500*p**8*s**6 - 202832031250*p**5*q**2*s**6 - 531738281250*p**2*q**4*s**6 + 73330078125*p**6*r*s**6 - 3906250000*p**3*q**2*r*s**6 - 1275878906250*q**4*r*s**6 - 121093750000*p**4*r**2*s**6 - 3308593750000*p*q**2*r**2*s**6 + 18066406250*p**2*r**3*s**6 - 244140625000*r**4*s**6 + 327148437500*p**4*q*s**7 + 1672363281250*p*q**3*s**7 + 446777343750*p**2*q*r*s**7 + 1232910156250*q*r**2*s**7 - 274658203125*p**3*s**8 - 1068115234375*q**2*s**8 - 61035156250*p*r*s**8 + + b[4][3] = 200*p**9*q**8 + 7550*p**6*q**10 + 78650*p**3*q**12 + 248400*q**14 - 4800*p**10*q**6*r - 164300*p**7*q**8*r - 1709575*p**4*q**10*r - 5566500*p*q**12*r + 31050*p**11*q**4*r**2 + 1116175*p**8*q**6*r**2 + 12674650*p**5*q**8*r**2 + 45333850*p**2*q**10*r**2 - 60750*p**12*q**2*r**3 - 2872725*p**9*q**4*r**3 - 40403050*p**6*q**6*r**3 - 173564375*p**3*q**8*r**3 - 11242250*q**10*r**3 + 2174100*p**10*q**2*r**4 + 54010000*p**7*q**4*r**4 + 331074875*p**4*q**6*r**4 + 114173750*p*q**8*r**4 - 24858500*p**8*q**2*r**5 - 300875000*p**5*q**4*r**5 - 319430625*p**2*q**6*r**5 + 69810000*p**6*q**2*r**6 - 23900000*p**3*q**4*r**6 - 294662500*q**6*r**6 + 524200000*p**4*q**2*r**7 + 1432000000*p*q**4*r**7 - 2340000000*p**2*q**2*r**8 + 5400*p**11*q**5*s + 310400*p**8*q**7*s + 3591725*p**5*q**9*s + 11556750*p**2*q**11*s - 105300*p**12*q**3*r*s - 4234650*p**9*q**5*r*s - 49928875*p**6*q**7*r*s - 174078125*p**3*q**9*r*s + 18000000*q**11*r*s + 364500*p**13*q*r**2*s + 15763050*p**10*q**3*r**2*s + 220187400*p**7*q**5*r**2*s + 929609375*p**4*q**7*r**2*s - 43653125*p*q**9*r**2*s - 13427100*p**11*q*r**3*s - 346066250*p**8*q**3*r**3*s - 2287673375*p**5*q**5*r**3*s - 1403903125*p**2*q**7*r**3*s + 184586000*p**9*q*r**4*s + 2983460000*p**6*q**3*r**4*s + 8725818750*p**3*q**5*r**4*s + 2527734375*q**7*r**4*s - 1284480000*p**7*q*r**5*s - 13138250000*p**4*q**3*r**5*s - 14001625000*p*q**5*r**5*s + 4224800000*p**5*q*r**6*s + 27460000000*p**2*q**3*r**6*s - 3760000000*p**3*q*r**7*s + 3900000000*q**3*r**7*s + 36450*p**13*q**2*s**2 + 2765475*p**10*q**4*s**2 + 34027625*p**7*q**6*s**2 + 97375000*p**4*q**8*s**2 - 88275000*p*q**10*s**2 - 546750*p**14*r*s**2 - 21961125*p**11*q**2*r*s**2 - 273059375*p**8*q**4*r*s**2 - 761562500*p**5*q**6*r*s**2 + 1869656250*p**2*q**8*r*s**2 + 20545650*p**12*r**2*s**2 + 473934375*p**9*q**2*r**2*s**2 + 1758053125*p**6*q**4*r**2*s**2 - 8743359375*p**3*q**6*r**2*s**2 - 4154375000*q**8*r**2*s**2 - 296559000*p**10*r**3*s**2 - 4065056250*p**7*q**2*r**3*s**2 - 186328125*p**4*q**4*r**3*s**2 + 19419453125*p*q**6*r**3*s**2 + 2326262500*p**8*r**4*s**2 + 21189375000*p**5*q**2*r**4*s**2 - 26301953125*p**2*q**4*r**4*s**2 - 10513250000*p**6*r**5*s**2 - 69937500000*p**3*q**2*r**5*s**2 - 42257812500*q**4*r**5*s**2 + 23375000000*p**4*r**6*s**2 + 40750000000*p*q**2*r**6*s**2 - 19500000000*p**2*r**7*s**2 + 4009500*p**12*q*s**3 + 36140625*p**9*q**3*s**3 - 335459375*p**6*q**5*s**3 - 2695312500*p**3*q**7*s**3 - 1486250000*q**9*s**3 + 102515625*p**10*q*r*s**3 + 4006812500*p**7*q**3*r*s**3 + 27589609375*p**4*q**5*r*s**3 + 20195312500*p*q**7*r*s**3 - 2792812500*p**8*q*r**2*s**3 - 44115156250*p**5*q**3*r**2*s**3 - 72609453125*p**2*q**5*r**2*s**3 + 18752500000*p**6*q*r**3*s**3 + 218140625000*p**3*q**3*r**3*s**3 + 109940234375*q**5*r**3*s**3 - 21893750000*p**4*q*r**4*s**3 - 65187500000*p*q**3*r**4*s**3 - 31000000000*p**2*q*r**5*s**3 + 97500000000*q*r**6*s**3 - 86568750*p**11*s**4 - 1955390625*p**8*q**2*s**4 - 8960781250*p**5*q**4*s**4 - 1357812500*p**2*q**6*s**4 + 1657968750*p**9*r*s**4 + 10467187500*p**6*q**2*r*s**4 - 55292968750*p**3*q**4*r*s**4 - 60683593750*q**6*r*s**4 - 11473593750*p**7*r**2*s**4 - 123281250000*p**4*q**2*r**2*s**4 - 164912109375*p*q**4*r**2*s**4 + 13150000000*p**5*r**3*s**4 + 190751953125*p**2*q**2*r**3*s**4 + 61875000000*p**3*r**4*s**4 - 467773437500*q**2*r**4*s**4 - 118750000000*p*r**5*s**4 + 7583203125*p**7*q*s**5 + 54638671875*p**4*q**3*s**5 + 39423828125*p*q**5*s**5 + 32392578125*p**5*q*r*s**5 + 278515625000*p**2*q**3*r*s**5 - 298339843750*p**3*q*r**2*s**5 + 560791015625*q**3*r**2*s**5 + 720703125000*p*q*r**3*s**5 - 19687500000*p**6*s**6 - 159667968750*p**3*q**2*s**6 - 72265625000*q**4*s**6 + 116699218750*p**4*r*s**6 - 924072265625*p*q**2*r*s**6 - 156005859375*p**2*r**2*s**6 - 112304687500*r**3*s**6 + 349121093750*p**2*q*s**7 + 396728515625*q*r*s**7 - 213623046875*p*s**8 + + b[4][2] = -600*p**10*q**6 - 18450*p**7*q**8 - 174000*p**4*q**10 - 518400*p*q**12 + 5400*p**11*q**4*r + 197550*p**8*q**6*r + 2147775*p**5*q**8*r + 7219800*p**2*q**10*r - 12150*p**12*q**2*r**2 - 662200*p**9*q**4*r**2 - 9274775*p**6*q**6*r**2 - 38330625*p**3*q**8*r**2 - 5508000*q**10*r**2 + 656550*p**10*q**2*r**3 + 16233750*p**7*q**4*r**3 + 97335875*p**4*q**6*r**3 + 58271250*p*q**8*r**3 - 9845500*p**8*q**2*r**4 - 119464375*p**5*q**4*r**4 - 194431875*p**2*q**6*r**4 + 49465000*p**6*q**2*r**5 + 166000000*p**3*q**4*r**5 - 80793750*q**6*r**5 + 54400000*p**4*q**2*r**6 + 377750000*p*q**4*r**6 - 630000000*p**2*q**2*r**7 - 16200*p**12*q**3*s - 459300*p**9*q**5*s - 4207225*p**6*q**7*s - 10827500*p**3*q**9*s + 13635000*q**11*s + 72900*p**13*q*r*s + 2877300*p**10*q**3*r*s + 33239700*p**7*q**5*r*s + 107080625*p**4*q**7*r*s - 114975000*p*q**9*r*s - 3601800*p**11*q*r**2*s - 75214375*p**8*q**3*r**2*s - 387073250*p**5*q**5*r**2*s + 55540625*p**2*q**7*r**2*s + 53793000*p**9*q*r**3*s + 687176875*p**6*q**3*r**3*s + 1670018750*p**3*q**5*r**3*s + 665234375*q**7*r**3*s - 391570000*p**7*q*r**4*s - 3420125000*p**4*q**3*r**4*s - 3609625000*p*q**5*r**4*s + 1365600000*p**5*q*r**5*s + 7236250000*p**2*q**3*r**5*s - 1220000000*p**3*q*r**6*s + 1050000000*q**3*r**6*s - 109350*p**14*s**2 - 3065850*p**11*q**2*s**2 - 26908125*p**8*q**4*s**2 - 44606875*p**5*q**6*s**2 + 269812500*p**2*q**8*s**2 + 5200200*p**12*r*s**2 + 81826875*p**9*q**2*r*s**2 + 155378125*p**6*q**4*r*s**2 - 1936203125*p**3*q**6*r*s**2 - 998437500*q**8*r*s**2 - 77145750*p**10*r**2*s**2 - 745528125*p**7*q**2*r**2*s**2 + 683437500*p**4*q**4*r**2*s**2 + 4083359375*p*q**6*r**2*s**2 + 593287500*p**8*r**3*s**2 + 4799375000*p**5*q**2*r**3*s**2 - 4167578125*p**2*q**4*r**3*s**2 - 2731125000*p**6*r**4*s**2 - 18668750000*p**3*q**2*r**4*s**2 - 10480468750*q**4*r**4*s**2 + 6200000000*p**4*r**5*s**2 + 11750000000*p*q**2*r**5*s**2 - 5250000000*p**2*r**6*s**2 + 26527500*p**10*q*s**3 + 526031250*p**7*q**3*s**3 + 3160703125*p**4*q**5*s**3 + 2650312500*p*q**7*s**3 - 448031250*p**8*q*r*s**3 - 6682968750*p**5*q**3*r*s**3 - 11642812500*p**2*q**5*r*s**3 + 2553203125*p**6*q*r**2*s**3 + 37234375000*p**3*q**3*r**2*s**3 + 21871484375*q**5*r**2*s**3 + 2803125000*p**4*q*r**3*s**3 - 10796875000*p*q**3*r**3*s**3 - 16656250000*p**2*q*r**4*s**3 + 26250000000*q*r**5*s**3 - 75937500*p**9*s**4 - 704062500*p**6*q**2*s**4 - 8363281250*p**3*q**4*s**4 - 10398437500*q**6*s**4 + 197578125*p**7*r*s**4 - 16441406250*p**4*q**2*r*s**4 - 24277343750*p*q**4*r*s**4 - 5716015625*p**5*r**2*s**4 + 31728515625*p**2*q**2*r**2*s**4 + 27031250000*p**3*r**3*s**4 - 92285156250*q**2*r**3*s**4 - 33593750000*p*r**4*s**4 + 10394531250*p**5*q*s**5 + 38037109375*p**2*q**3*s**5 - 48144531250*p**3*q*r*s**5 + 74462890625*q**3*r*s**5 + 121093750000*p*q*r**2*s**5 - 2197265625*p**4*s**6 - 92529296875*p*q**2*s**6 + 15380859375*p**2*r*s**6 - 31738281250*r**2*s**6 + 54931640625*q*s**7 + + b[4][1] = 200*p**8*q**6 + 2950*p**5*q**8 + 10800*p**2*q**10 - 1800*p**9*q**4*r - 49650*p**6*q**6*r - 403375*p**3*q**8*r - 999000*q**10*r + 4050*p**10*q**2*r**2 + 236625*p**7*q**4*r**2 + 3109500*p**4*q**6*r**2 + 11463750*p*q**8*r**2 - 331500*p**8*q**2*r**3 - 7818125*p**5*q**4*r**3 - 41411250*p**2*q**6*r**3 + 4782500*p**6*q**2*r**4 + 47475000*p**3*q**4*r**4 - 16728125*q**6*r**4 - 8700000*p**4*q**2*r**5 + 81750000*p*q**4*r**5 - 135000000*p**2*q**2*r**6 + 5400*p**10*q**3*s + 144200*p**7*q**5*s + 939375*p**4*q**7*s + 1012500*p*q**9*s - 24300*p**11*q*r*s - 1169250*p**8*q**3*r*s - 14027250*p**5*q**5*r*s - 44446875*p**2*q**7*r*s + 2011500*p**9*q*r**2*s + 49330625*p**6*q**3*r**2*s + 272009375*p**3*q**5*r**2*s + 104062500*q**7*r**2*s - 34660000*p**7*q*r**3*s - 455062500*p**4*q**3*r**3*s - 625906250*p*q**5*r**3*s + 210200000*p**5*q*r**4*s + 1298750000*p**2*q**3*r**4*s - 240000000*p**3*q*r**5*s + 225000000*q**3*r**5*s + 36450*p**12*s**2 + 1231875*p**9*q**2*s**2 + 10712500*p**6*q**4*s**2 + 21718750*p**3*q**6*s**2 + 16875000*q**8*s**2 - 2814750*p**10*r*s**2 - 67612500*p**7*q**2*r*s**2 - 345156250*p**4*q**4*r*s**2 - 283125000*p*q**6*r*s**2 + 51300000*p**8*r**2*s**2 + 734531250*p**5*q**2*r**2*s**2 + 1267187500*p**2*q**4*r**2*s**2 - 384312500*p**6*r**3*s**2 - 3912500000*p**3*q**2*r**3*s**2 - 1822265625*q**4*r**3*s**2 + 1112500000*p**4*r**4*s**2 + 2437500000*p*q**2*r**4*s**2 - 1125000000*p**2*r**5*s**2 - 72578125*p**5*q**3*s**3 - 189296875*p**2*q**5*s**3 + 127265625*p**6*q*r*s**3 + 1415625000*p**3*q**3*r*s**3 + 1229687500*q**5*r*s**3 + 1448437500*p**4*q*r**2*s**3 + 2218750000*p*q**3*r**2*s**3 - 4031250000*p**2*q*r**3*s**3 + 5625000000*q*r**4*s**3 - 132890625*p**7*s**4 - 529296875*p**4*q**2*s**4 - 175781250*p*q**4*s**4 - 401953125*p**5*r*s**4 - 4482421875*p**2*q**2*r*s**4 + 4140625000*p**3*r**2*s**4 - 10498046875*q**2*r**2*s**4 - 7031250000*p*r**3*s**4 + 1220703125*p**3*q*s**5 + 1953125000*q**3*s**5 + 14160156250*p*q*r*s**5 - 1708984375*p**2*s**6 - 3662109375*r*s**6 + + b[4][0] = -4600*p**6*q**6 - 67850*p**3*q**8 - 248400*q**10 + 38900*p**7*q**4*r + 679575*p**4*q**6*r + 2866500*p*q**8*r - 81900*p**8*q**2*r**2 - 2009750*p**5*q**4*r**2 - 10783750*p**2*q**6*r**2 + 1478750*p**6*q**2*r**3 + 14165625*p**3*q**4*r**3 - 2743750*q**6*r**3 - 5450000*p**4*q**2*r**4 + 12687500*p*q**4*r**4 - 22500000*p**2*q**2*r**5 - 101700*p**8*q**3*s - 1700975*p**5*q**5*s - 7061250*p**2*q**7*s + 423900*p**9*q*r*s + 9292375*p**6*q**3*r*s + 50438750*p**3*q**5*r*s + 20475000*q**7*r*s - 7852500*p**7*q*r**2*s - 87765625*p**4*q**3*r**2*s - 121609375*p*q**5*r**2*s + 47700000*p**5*q*r**3*s + 264687500*p**2*q**3*r**3*s - 65000000*p**3*q*r**4*s + 37500000*q**3*r**4*s - 534600*p**10*s**2 - 10344375*p**7*q**2*s**2 - 54859375*p**4*q**4*s**2 - 40312500*p*q**6*s**2 + 10158750*p**8*r*s**2 + 117778125*p**5*q**2*r*s**2 + 192421875*p**2*q**4*r*s**2 - 70593750*p**6*r**2*s**2 - 685312500*p**3*q**2*r**2*s**2 - 334375000*q**4*r**2*s**2 + 193750000*p**4*r**3*s**2 + 500000000*p*q**2*r**3*s**2 - 187500000*p**2*r**4*s**2 + 8437500*p**6*q*s**3 + 159218750*p**3*q**3*s**3 + 220625000*q**5*s**3 + 353828125*p**4*q*r*s**3 + 412500000*p*q**3*r*s**3 - 1023437500*p**2*q*r**2*s**3 + 937500000*q*r**3*s**3 - 206015625*p**5*s**4 - 701171875*p**2*q**2*s**4 + 998046875*p**3*r*s**4 - 1308593750*q**2*r*s**4 - 1367187500*p*r**2*s**4 + 1708984375*p*q*s**5 - 976562500*s**6 + + return b + + @property + def o(self): + p, q, r, s = self.p, self.q, self.r, self.s + o = [0]*6 + + o[5] = -1600*p**10*q**10 - 23600*p**7*q**12 - 86400*p**4*q**14 + 24800*p**11*q**8*r + 419200*p**8*q**10*r + 1850450*p**5*q**12*r + 896400*p**2*q**14*r - 138800*p**12*q**6*r**2 - 2921900*p**9*q**8*r**2 - 17295200*p**6*q**10*r**2 - 27127750*p**3*q**12*r**2 - 26076600*q**14*r**2 + 325800*p**13*q**4*r**3 + 9993850*p**10*q**6*r**3 + 88010500*p**7*q**8*r**3 + 274047650*p**4*q**10*r**3 + 410171400*p*q**12*r**3 - 259200*p**14*q**2*r**4 - 17147100*p**11*q**4*r**4 - 254289150*p**8*q**6*r**4 - 1318548225*p**5*q**8*r**4 - 2633598475*p**2*q**10*r**4 + 12636000*p**12*q**2*r**5 + 388911000*p**9*q**4*r**5 + 3269704725*p**6*q**6*r**5 + 8791192300*p**3*q**8*r**5 + 93560575*q**10*r**5 - 228361600*p**10*q**2*r**6 - 3951199200*p**7*q**4*r**6 - 16276981100*p**4*q**6*r**6 - 1597227000*p*q**8*r**6 + 1947899200*p**8*q**2*r**7 + 17037648000*p**5*q**4*r**7 + 8919740000*p**2*q**6*r**7 - 7672160000*p**6*q**2*r**8 - 15496000000*p**3*q**4*r**8 + 4224000000*q**6*r**8 + 9968000000*p**4*q**2*r**9 - 8640000000*p*q**4*r**9 + 4800000000*p**2*q**2*r**10 - 55200*p**12*q**7*s - 685600*p**9*q**9*s + 1028250*p**6*q**11*s + 37650000*p**3*q**13*s + 111375000*q**15*s + 583200*p**13*q**5*r*s + 9075600*p**10*q**7*r*s - 883150*p**7*q**9*r*s - 506830750*p**4*q**11*r*s - 1793137500*p*q**13*r*s - 1852200*p**14*q**3*r**2*s - 41435250*p**11*q**5*r**2*s - 80566700*p**8*q**7*r**2*s + 2485673600*p**5*q**9*r**2*s + 11442286125*p**2*q**11*r**2*s + 1555200*p**15*q*r**3*s + 80846100*p**12*q**3*r**3*s + 564906800*p**9*q**5*r**3*s - 4493012400*p**6*q**7*r**3*s - 35492391250*p**3*q**9*r**3*s - 789931875*q**11*r**3*s - 71766000*p**13*q*r**4*s - 1551149200*p**10*q**3*r**4*s - 1773437900*p**7*q**5*r**4*s + 51957593125*p**4*q**7*r**4*s + 14964765625*p*q**9*r**4*s + 1231569600*p**11*q*r**5*s + 12042977600*p**8*q**3*r**5*s - 27151011200*p**5*q**5*r**5*s - 88080610000*p**2*q**7*r**5*s - 9912995200*p**9*q*r**6*s - 29448104000*p**6*q**3*r**6*s + 144954840000*p**3*q**5*r**6*s - 44601300000*q**7*r**6*s + 35453760000*p**7*q*r**7*s - 63264000000*p**4*q**3*r**7*s + 60544000000*p*q**5*r**7*s - 30048000000*p**5*q*r**8*s + 37040000000*p**2*q**3*r**8*s - 60800000000*p**3*q*r**9*s - 48000000000*q**3*r**9*s - 615600*p**14*q**4*s**2 - 10524500*p**11*q**6*s**2 - 33831250*p**8*q**8*s**2 + 222806250*p**5*q**10*s**2 + 1099687500*p**2*q**12*s**2 + 3353400*p**15*q**2*r*s**2 + 74269350*p**12*q**4*r*s**2 + 276445750*p**9*q**6*r*s**2 - 2618600000*p**6*q**8*r*s**2 - 14473243750*p**3*q**10*r*s**2 + 1383750000*q**12*r*s**2 - 2332800*p**16*r**2*s**2 - 132750900*p**13*q**2*r**2*s**2 - 900775150*p**10*q**4*r**2*s**2 + 8249244500*p**7*q**6*r**2*s**2 + 59525796875*p**4*q**8*r**2*s**2 - 40292868750*p*q**10*r**2*s**2 + 128304000*p**14*r**3*s**2 + 3160232100*p**11*q**2*r**3*s**2 + 8329580000*p**8*q**4*r**3*s**2 - 45558458750*p**5*q**6*r**3*s**2 + 297252890625*p**2*q**8*r**3*s**2 - 2769854400*p**12*r**4*s**2 - 37065970000*p**9*q**2*r**4*s**2 - 90812546875*p**6*q**4*r**4*s**2 - 627902000000*p**3*q**6*r**4*s**2 + 181347421875*q**8*r**4*s**2 + 30946932800*p**10*r**5*s**2 + 249954680000*p**7*q**2*r**5*s**2 + 802954812500*p**4*q**4*r**5*s**2 - 80900000000*p*q**6*r**5*s**2 - 192137320000*p**8*r**6*s**2 - 932641600000*p**5*q**2*r**6*s**2 - 943242500000*p**2*q**4*r**6*s**2 + 658412000000*p**6*r**7*s**2 + 1930720000000*p**3*q**2*r**7*s**2 + 593800000000*q**4*r**7*s**2 - 1162800000000*p**4*r**8*s**2 - 280000000000*p*q**2*r**8*s**2 + 840000000000*p**2*r**9*s**2 - 2187000*p**16*q*s**3 - 47418750*p**13*q**3*s**3 - 180618750*p**10*q**5*s**3 + 2231250000*p**7*q**7*s**3 + 17857734375*p**4*q**9*s**3 + 29882812500*p*q**11*s**3 + 24664500*p**14*q*r*s**3 - 853368750*p**11*q**3*r*s**3 - 25939693750*p**8*q**5*r*s**3 - 177541562500*p**5*q**7*r*s**3 - 297978828125*p**2*q**9*r*s**3 - 153468000*p**12*q*r**2*s**3 + 30188125000*p**9*q**3*r**2*s**3 + 344049821875*p**6*q**5*r**2*s**3 + 534026875000*p**3*q**7*r**2*s**3 - 340726484375*q**9*r**2*s**3 - 9056190000*p**10*q*r**3*s**3 - 322314687500*p**7*q**3*r**3*s**3 - 769632109375*p**4*q**5*r**3*s**3 - 83276875000*p*q**7*r**3*s**3 + 164061000000*p**8*q*r**4*s**3 + 1381358750000*p**5*q**3*r**4*s**3 + 3088020000000*p**2*q**5*r**4*s**3 - 1267655000000*p**6*q*r**5*s**3 - 7642630000000*p**3*q**3*r**5*s**3 - 2759877500000*q**5*r**5*s**3 + 4597760000000*p**4*q*r**6*s**3 + 1846200000000*p*q**3*r**6*s**3 - 7006000000000*p**2*q*r**7*s**3 - 1200000000000*q*r**8*s**3 + 18225000*p**15*s**4 + 1328906250*p**12*q**2*s**4 + 24729140625*p**9*q**4*s**4 + 169467187500*p**6*q**6*s**4 + 413281250000*p**3*q**8*s**4 + 223828125000*q**10*s**4 + 710775000*p**13*r*s**4 - 18611015625*p**10*q**2*r*s**4 - 314344375000*p**7*q**4*r*s**4 - 828439843750*p**4*q**6*r*s**4 + 460937500000*p*q**8*r*s**4 - 25674975000*p**11*r**2*s**4 - 52223515625*p**8*q**2*r**2*s**4 - 387160000000*p**5*q**4*r**2*s**4 - 4733680078125*p**2*q**6*r**2*s**4 + 343911875000*p**9*r**3*s**4 + 3328658359375*p**6*q**2*r**3*s**4 + 16532406250000*p**3*q**4*r**3*s**4 + 5980613281250*q**6*r**3*s**4 - 2295497500000*p**7*r**4*s**4 - 14809820312500*p**4*q**2*r**4*s**4 - 6491406250000*p*q**4*r**4*s**4 + 7768470000000*p**5*r**5*s**4 + 34192562500000*p**2*q**2*r**5*s**4 - 11859000000000*p**3*r**6*s**4 + 10530000000000*q**2*r**6*s**4 + 6000000000000*p*r**7*s**4 + 11453906250*p**11*q*s**5 + 149765625000*p**8*q**3*s**5 + 545537109375*p**5*q**5*s**5 + 527343750000*p**2*q**7*s**5 - 371313281250*p**9*q*r*s**5 - 3461455078125*p**6*q**3*r*s**5 - 7920878906250*p**3*q**5*r*s**5 - 4747314453125*q**7*r*s**5 + 2417815625000*p**7*q*r**2*s**5 + 5465576171875*p**4*q**3*r**2*s**5 + 5937128906250*p*q**5*r**2*s**5 - 10661156250000*p**5*q*r**3*s**5 - 63574218750000*p**2*q**3*r**3*s**5 + 24059375000000*p**3*q*r**4*s**5 - 33023437500000*q**3*r**4*s**5 - 43125000000000*p*q*r**5*s**5 + 94394531250*p**10*s**6 + 1097167968750*p**7*q**2*s**6 + 2829833984375*p**4*q**4*s**6 - 1525878906250*p*q**6*s**6 + 2724609375*p**8*r*s**6 + 13998535156250*p**5*q**2*r*s**6 + 57094482421875*p**2*q**4*r*s**6 - 8512509765625*p**6*r**2*s**6 - 37941406250000*p**3*q**2*r**2*s**6 + 33191894531250*q**4*r**2*s**6 + 50534179687500*p**4*r**3*s**6 + 156656250000000*p*q**2*r**3*s**6 - 85023437500000*p**2*r**4*s**6 + 10125000000000*r**5*s**6 - 2717285156250*p**6*q*s**7 - 11352539062500*p**3*q**3*s**7 - 2593994140625*q**5*s**7 - 47154541015625*p**4*q*r*s**7 - 160644531250000*p*q**3*r*s**7 + 142500000000000*p**2*q*r**2*s**7 - 26757812500000*q*r**3*s**7 - 4364013671875*p**5*s**8 - 94604492187500*p**2*q**2*s**8 + 114379882812500*p**3*r*s**8 + 51116943359375*q**2*r*s**8 - 346435546875000*p*r**2*s**8 + 476837158203125*p*q*s**9 - 476837158203125*s**10 + + o[4] = 1600*p**11*q**8 + 20800*p**8*q**10 + 45100*p**5*q**12 - 151200*p**2*q**14 - 19200*p**12*q**6*r - 293200*p**9*q**8*r - 794600*p**6*q**10*r + 2634675*p**3*q**12*r + 2640600*q**14*r + 75600*p**13*q**4*r**2 + 1529100*p**10*q**6*r**2 + 6233350*p**7*q**8*r**2 - 12013350*p**4*q**10*r**2 - 29069550*p*q**12*r**2 - 97200*p**14*q**2*r**3 - 3562500*p**11*q**4*r**3 - 26984900*p**8*q**6*r**3 - 15900325*p**5*q**8*r**3 + 76267100*p**2*q**10*r**3 + 3272400*p**12*q**2*r**4 + 59486850*p**9*q**4*r**4 + 221270075*p**6*q**6*r**4 + 74065250*p**3*q**8*r**4 - 300564375*q**10*r**4 - 45569400*p**10*q**2*r**5 - 438666000*p**7*q**4*r**5 - 444821250*p**4*q**6*r**5 + 2448256250*p*q**8*r**5 + 290640000*p**8*q**2*r**6 + 855850000*p**5*q**4*r**6 - 5741875000*p**2*q**6*r**6 - 644000000*p**6*q**2*r**7 + 5574000000*p**3*q**4*r**7 + 4643000000*q**6*r**7 - 1696000000*p**4*q**2*r**8 - 12660000000*p*q**4*r**8 + 7200000000*p**2*q**2*r**9 + 43200*p**13*q**5*s + 572000*p**10*q**7*s - 59800*p**7*q**9*s - 24174625*p**4*q**11*s - 74587500*p*q**13*s - 324000*p**14*q**3*r*s - 5531400*p**11*q**5*r*s - 3712100*p**8*q**7*r*s + 293009275*p**5*q**9*r*s + 1115548875*p**2*q**11*r*s + 583200*p**15*q*r**2*s + 18343800*p**12*q**3*r**2*s + 77911100*p**9*q**5*r**2*s - 957488825*p**6*q**7*r**2*s - 5449661250*p**3*q**9*r**2*s + 960120000*q**11*r**2*s - 23684400*p**13*q*r**3*s - 373761900*p**10*q**3*r**3*s - 27944975*p**7*q**5*r**3*s + 10375740625*p**4*q**7*r**3*s - 4649093750*p*q**9*r**3*s + 395816400*p**11*q*r**4*s + 2910968000*p**8*q**3*r**4*s - 9126162500*p**5*q**5*r**4*s - 11696118750*p**2*q**7*r**4*s - 3028640000*p**9*q*r**5*s - 3251550000*p**6*q**3*r**5*s + 47914250000*p**3*q**5*r**5*s - 30255625000*q**7*r**5*s + 9304000000*p**7*q*r**6*s - 42970000000*p**4*q**3*r**6*s + 31475000000*p*q**5*r**6*s + 2176000000*p**5*q*r**7*s + 62100000000*p**2*q**3*r**7*s - 43200000000*p**3*q*r**8*s - 72000000000*q**3*r**8*s + 291600*p**15*q**2*s**2 + 2702700*p**12*q**4*s**2 - 38692250*p**9*q**6*s**2 - 538903125*p**6*q**8*s**2 - 1613112500*p**3*q**10*s**2 + 320625000*q**12*s**2 - 874800*p**16*r*s**2 - 14166900*p**13*q**2*r*s**2 + 193284900*p**10*q**4*r*s**2 + 3688520500*p**7*q**6*r*s**2 + 11613390625*p**4*q**8*r*s**2 - 15609881250*p*q**10*r*s**2 + 44031600*p**14*r**2*s**2 + 482345550*p**11*q**2*r**2*s**2 - 2020881875*p**8*q**4*r**2*s**2 - 7407026250*p**5*q**6*r**2*s**2 + 136175750000*p**2*q**8*r**2*s**2 - 1000884600*p**12*r**3*s**2 - 8888950000*p**9*q**2*r**3*s**2 - 30101703125*p**6*q**4*r**3*s**2 - 319761000000*p**3*q**6*r**3*s**2 + 51519218750*q**8*r**3*s**2 + 12622395000*p**10*r**4*s**2 + 97032450000*p**7*q**2*r**4*s**2 + 469929218750*p**4*q**4*r**4*s**2 + 291342187500*p*q**6*r**4*s**2 - 96382000000*p**8*r**5*s**2 - 598070000000*p**5*q**2*r**5*s**2 - 1165021875000*p**2*q**4*r**5*s**2 + 446500000000*p**6*r**6*s**2 + 1651500000000*p**3*q**2*r**6*s**2 + 789375000000*q**4*r**6*s**2 - 1152000000000*p**4*r**7*s**2 - 600000000000*p*q**2*r**7*s**2 + 1260000000000*p**2*r**8*s**2 - 24786000*p**14*q*s**3 - 660487500*p**11*q**3*s**3 - 5886356250*p**8*q**5*s**3 - 18137187500*p**5*q**7*s**3 - 5120546875*p**2*q**9*s**3 + 827658000*p**12*q*r*s**3 + 13343062500*p**9*q**3*r*s**3 + 39782068750*p**6*q**5*r*s**3 - 111288437500*p**3*q**7*r*s**3 - 15438750000*q**9*r*s**3 - 14540782500*p**10*q*r**2*s**3 - 135889750000*p**7*q**3*r**2*s**3 - 176892578125*p**4*q**5*r**2*s**3 - 934462656250*p*q**7*r**2*s**3 + 171669250000*p**8*q*r**3*s**3 + 1164538125000*p**5*q**3*r**3*s**3 + 3192346406250*p**2*q**5*r**3*s**3 - 1295476250000*p**6*q*r**4*s**3 - 6540712500000*p**3*q**3*r**4*s**3 - 2957828125000*q**5*r**4*s**3 + 5366750000000*p**4*q*r**5*s**3 + 3165000000000*p*q**3*r**5*s**3 - 8862500000000*p**2*q*r**6*s**3 - 1800000000000*q*r**7*s**3 + 236925000*p**13*s**4 + 8895234375*p**10*q**2*s**4 + 106180781250*p**7*q**4*s**4 + 474221875000*p**4*q**6*s**4 + 616210937500*p*q**8*s**4 - 6995868750*p**11*r*s**4 - 184190625000*p**8*q**2*r*s**4 - 1299254453125*p**5*q**4*r*s**4 - 2475458593750*p**2*q**6*r*s**4 + 63049218750*p**9*r**2*s**4 + 1646791484375*p**6*q**2*r**2*s**4 + 9086886718750*p**3*q**4*r**2*s**4 + 4673421875000*q**6*r**2*s**4 - 215665000000*p**7*r**3*s**4 - 7864589843750*p**4*q**2*r**3*s**4 - 5987890625000*p*q**4*r**3*s**4 + 594843750000*p**5*r**4*s**4 + 27791171875000*p**2*q**2*r**4*s**4 - 3881250000000*p**3*r**5*s**4 + 12203125000000*q**2*r**5*s**4 + 10312500000000*p*r**6*s**4 - 34720312500*p**9*q*s**5 - 545126953125*p**6*q**3*s**5 - 2176425781250*p**3*q**5*s**5 - 2792968750000*q**7*s**5 - 1395703125*p**7*q*r*s**5 - 1957568359375*p**4*q**3*r*s**5 + 5122636718750*p*q**5*r*s**5 + 858210937500*p**5*q*r**2*s**5 - 42050097656250*p**2*q**3*r**2*s**5 + 7088281250000*p**3*q*r**3*s**5 - 25974609375000*q**3*r**3*s**5 - 69296875000000*p*q*r**4*s**5 + 384697265625*p**8*s**6 + 6403320312500*p**5*q**2*s**6 + 16742675781250*p**2*q**4*s**6 - 3467080078125*p**6*r*s**6 + 11009765625000*p**3*q**2*r*s**6 + 16451660156250*q**4*r*s**6 + 6979003906250*p**4*r**2*s**6 + 145403320312500*p*q**2*r**2*s**6 + 4076171875000*p**2*r**3*s**6 + 22265625000000*r**4*s**6 - 21915283203125*p**4*q*s**7 - 86608886718750*p*q**3*s**7 - 22785644531250*p**2*q*r*s**7 - 103466796875000*q*r**2*s**7 + 18798828125000*p**3*s**8 + 106048583984375*q**2*s**8 + 17761230468750*p*r*s**8 + + o[3] = 2800*p**9*q**8 + 55700*p**6*q**10 + 363600*p**3*q**12 + 777600*q**14 - 27200*p**10*q**6*r - 700200*p**7*q**8*r - 5726550*p**4*q**10*r - 15066000*p*q**12*r + 74700*p**11*q**4*r**2 + 2859575*p**8*q**6*r**2 + 31175725*p**5*q**8*r**2 + 103147650*p**2*q**10*r**2 - 40500*p**12*q**2*r**3 - 4274400*p**9*q**4*r**3 - 76065825*p**6*q**6*r**3 - 365623750*p**3*q**8*r**3 - 132264000*q**10*r**3 + 2192400*p**10*q**2*r**4 + 92562500*p**7*q**4*r**4 + 799193875*p**4*q**6*r**4 + 1188193125*p*q**8*r**4 - 41231500*p**8*q**2*r**5 - 914210000*p**5*q**4*r**5 - 3318853125*p**2*q**6*r**5 + 398850000*p**6*q**2*r**6 + 3944000000*p**3*q**4*r**6 + 2211312500*q**6*r**6 - 1817000000*p**4*q**2*r**7 - 6720000000*p*q**4*r**7 + 3900000000*p**2*q**2*r**8 + 75600*p**11*q**5*s + 1823100*p**8*q**7*s + 14534150*p**5*q**9*s + 38265750*p**2*q**11*s - 394200*p**12*q**3*r*s - 11453850*p**9*q**5*r*s - 101213000*p**6*q**7*r*s - 223565625*p**3*q**9*r*s + 415125000*q**11*r*s + 243000*p**13*q*r**2*s + 13654575*p**10*q**3*r**2*s + 163811725*p**7*q**5*r**2*s + 173461250*p**4*q**7*r**2*s - 3008671875*p*q**9*r**2*s - 2016900*p**11*q*r**3*s - 86576250*p**8*q**3*r**3*s - 324146625*p**5*q**5*r**3*s + 3378506250*p**2*q**7*r**3*s - 89211000*p**9*q*r**4*s - 55207500*p**6*q**3*r**4*s + 1493950000*p**3*q**5*r**4*s - 12573609375*q**7*r**4*s + 1140100000*p**7*q*r**5*s + 42500000*p**4*q**3*r**5*s + 21511250000*p*q**5*r**5*s - 4058000000*p**5*q*r**6*s + 6725000000*p**2*q**3*r**6*s - 1400000000*p**3*q*r**7*s - 39000000000*q**3*r**7*s + 510300*p**13*q**2*s**2 + 4814775*p**10*q**4*s**2 - 70265125*p**7*q**6*s**2 - 1016484375*p**4*q**8*s**2 - 3221100000*p*q**10*s**2 - 364500*p**14*r*s**2 + 30314250*p**11*q**2*r*s**2 + 1106765625*p**8*q**4*r*s**2 + 10984203125*p**5*q**6*r*s**2 + 33905812500*p**2*q**8*r*s**2 - 37980900*p**12*r**2*s**2 - 2142905625*p**9*q**2*r**2*s**2 - 26896125000*p**6*q**4*r**2*s**2 - 95551328125*p**3*q**6*r**2*s**2 + 11320312500*q**8*r**2*s**2 + 1743781500*p**10*r**3*s**2 + 35432262500*p**7*q**2*r**3*s**2 + 177855859375*p**4*q**4*r**3*s**2 + 121260546875*p*q**6*r**3*s**2 - 25943162500*p**8*r**4*s**2 - 249165500000*p**5*q**2*r**4*s**2 - 461739453125*p**2*q**4*r**4*s**2 + 177823750000*p**6*r**5*s**2 + 726225000000*p**3*q**2*r**5*s**2 + 404195312500*q**4*r**5*s**2 - 565875000000*p**4*r**6*s**2 - 407500000000*p*q**2*r**6*s**2 + 682500000000*p**2*r**7*s**2 - 59140125*p**12*q*s**3 - 1290515625*p**9*q**3*s**3 - 8785071875*p**6*q**5*s**3 - 15588281250*p**3*q**7*s**3 + 17505000000*q**9*s**3 + 896062500*p**10*q*r*s**3 + 2589750000*p**7*q**3*r*s**3 - 82700156250*p**4*q**5*r*s**3 - 347683593750*p*q**7*r*s**3 + 17022656250*p**8*q*r**2*s**3 + 320923593750*p**5*q**3*r**2*s**3 + 1042116875000*p**2*q**5*r**2*s**3 - 353262812500*p**6*q*r**3*s**3 - 2212664062500*p**3*q**3*r**3*s**3 - 1252408984375*q**5*r**3*s**3 + 1967362500000*p**4*q*r**4*s**3 + 1583343750000*p*q**3*r**4*s**3 - 3560625000000*p**2*q*r**5*s**3 - 975000000000*q*r**6*s**3 + 462459375*p**11*s**4 + 14210859375*p**8*q**2*s**4 + 99521718750*p**5*q**4*s**4 + 114955468750*p**2*q**6*s**4 - 17720859375*p**9*r*s**4 - 100320703125*p**6*q**2*r*s**4 + 1021943359375*p**3*q**4*r*s**4 + 1193203125000*q**6*r*s**4 + 171371250000*p**7*r**2*s**4 - 1113390625000*p**4*q**2*r**2*s**4 - 1211474609375*p*q**4*r**2*s**4 - 274056250000*p**5*r**3*s**4 + 8285166015625*p**2*q**2*r**3*s**4 - 2079375000000*p**3*r**4*s**4 + 5137304687500*q**2*r**4*s**4 + 6187500000000*p*r**5*s**4 - 135675000000*p**7*q*s**5 - 1275244140625*p**4*q**3*s**5 - 28388671875*p*q**5*s**5 + 1015166015625*p**5*q*r*s**5 - 10584423828125*p**2*q**3*r*s**5 + 3559570312500*p**3*q*r**2*s**5 - 6929931640625*q**3*r**2*s**5 - 32304687500000*p*q*r**3*s**5 + 430576171875*p**6*s**6 + 9397949218750*p**3*q**2*s**6 + 575195312500*q**4*s**6 - 4086425781250*p**4*r*s**6 + 42183837890625*p*q**2*r*s**6 + 8156494140625*p**2*r**2*s**6 + 12612304687500*r**3*s**6 - 25513916015625*p**2*q*s**7 - 37017822265625*q*r*s**7 + 18981933593750*p*s**8 + + o[2] = 1600*p**10*q**6 + 9200*p**7*q**8 - 126000*p**4*q**10 - 777600*p*q**12 - 14400*p**11*q**4*r - 119300*p**8*q**6*r + 1203225*p**5*q**8*r + 9412200*p**2*q**10*r + 32400*p**12*q**2*r**2 + 417950*p**9*q**4*r**2 - 4543725*p**6*q**6*r**2 - 49008125*p**3*q**8*r**2 - 24192000*q**10*r**2 - 292050*p**10*q**2*r**3 + 8760000*p**7*q**4*r**3 + 137506625*p**4*q**6*r**3 + 225438750*p*q**8*r**3 - 4213250*p**8*q**2*r**4 - 173595625*p**5*q**4*r**4 - 653003125*p**2*q**6*r**4 + 82575000*p**6*q**2*r**5 + 838125000*p**3*q**4*r**5 + 578562500*q**6*r**5 - 421500000*p**4*q**2*r**6 - 1796250000*p*q**4*r**6 + 1050000000*p**2*q**2*r**7 + 43200*p**12*q**3*s + 807300*p**9*q**5*s + 5328225*p**6*q**7*s + 16946250*p**3*q**9*s + 29565000*q**11*s - 194400*p**13*q*r*s - 5505300*p**10*q**3*r*s - 49886700*p**7*q**5*r*s - 178821875*p**4*q**7*r*s - 222750000*p*q**9*r*s + 6814800*p**11*q*r**2*s + 120525625*p**8*q**3*r**2*s + 526694500*p**5*q**5*r**2*s + 84065625*p**2*q**7*r**2*s - 123670500*p**9*q*r**3*s - 1106731875*p**6*q**3*r**3*s - 669556250*p**3*q**5*r**3*s - 2869265625*q**7*r**3*s + 1004350000*p**7*q*r**4*s + 3384375000*p**4*q**3*r**4*s + 5665625000*p*q**5*r**4*s - 3411000000*p**5*q*r**5*s - 418750000*p**2*q**3*r**5*s + 1700000000*p**3*q*r**6*s - 10500000000*q**3*r**6*s + 291600*p**14*s**2 + 9829350*p**11*q**2*s**2 + 114151875*p**8*q**4*s**2 + 522169375*p**5*q**6*s**2 + 716906250*p**2*q**8*s**2 - 18625950*p**12*r*s**2 - 387703125*p**9*q**2*r*s**2 - 2056109375*p**6*q**4*r*s**2 - 760203125*p**3*q**6*r*s**2 + 3071250000*q**8*r*s**2 + 512419500*p**10*r**2*s**2 + 5859053125*p**7*q**2*r**2*s**2 + 12154062500*p**4*q**4*r**2*s**2 + 15931640625*p*q**6*r**2*s**2 - 6598393750*p**8*r**3*s**2 - 43549625000*p**5*q**2*r**3*s**2 - 82011328125*p**2*q**4*r**3*s**2 + 43538125000*p**6*r**4*s**2 + 160831250000*p**3*q**2*r**4*s**2 + 99070312500*q**4*r**4*s**2 - 141812500000*p**4*r**5*s**2 - 117500000000*p*q**2*r**5*s**2 + 183750000000*p**2*r**6*s**2 - 154608750*p**10*q*s**3 - 3309468750*p**7*q**3*s**3 - 20834140625*p**4*q**5*s**3 - 34731562500*p*q**7*s**3 + 5970375000*p**8*q*r*s**3 + 68533281250*p**5*q**3*r*s**3 + 142698281250*p**2*q**5*r*s**3 - 74509140625*p**6*q*r**2*s**3 - 389148437500*p**3*q**3*r**2*s**3 - 270937890625*q**5*r**2*s**3 + 366696875000*p**4*q*r**3*s**3 + 400031250000*p*q**3*r**3*s**3 - 735156250000*p**2*q*r**4*s**3 - 262500000000*q*r**5*s**3 + 371250000*p**9*s**4 + 21315000000*p**6*q**2*s**4 + 179515625000*p**3*q**4*s**4 + 238406250000*q**6*s**4 - 9071015625*p**7*r*s**4 - 268945312500*p**4*q**2*r*s**4 - 379785156250*p*q**4*r*s**4 + 140262890625*p**5*r**2*s**4 + 1486259765625*p**2*q**2*r**2*s**4 - 806484375000*p**3*r**3*s**4 + 1066210937500*q**2*r**3*s**4 + 1722656250000*p*r**4*s**4 - 125648437500*p**5*q*s**5 - 1236279296875*p**2*q**3*s**5 + 1267871093750*p**3*q*r*s**5 - 1044677734375*q**3*r*s**5 - 6630859375000*p*q*r**2*s**5 + 160888671875*p**4*s**6 + 6352294921875*p*q**2*s**6 - 708740234375*p**2*r*s**6 + 3901367187500*r**2*s**6 - 8050537109375*q*s**7 + + o[1] = 2800*p**8*q**6 + 41300*p**5*q**8 + 151200*p**2*q**10 - 25200*p**9*q**4*r - 542600*p**6*q**6*r - 3397875*p**3*q**8*r - 5751000*q**10*r + 56700*p**10*q**2*r**2 + 1972125*p**7*q**4*r**2 + 18624250*p**4*q**6*r**2 + 50253750*p*q**8*r**2 - 1701000*p**8*q**2*r**3 - 32630625*p**5*q**4*r**3 - 139868750*p**2*q**6*r**3 + 18162500*p**6*q**2*r**4 + 177125000*p**3*q**4*r**4 + 121734375*q**6*r**4 - 100500000*p**4*q**2*r**5 - 386250000*p*q**4*r**5 + 225000000*p**2*q**2*r**6 + 75600*p**10*q**3*s + 1708800*p**7*q**5*s + 12836875*p**4*q**7*s + 32062500*p*q**9*s - 340200*p**11*q*r*s - 10185750*p**8*q**3*r*s - 97502750*p**5*q**5*r*s - 301640625*p**2*q**7*r*s + 7168500*p**9*q*r**2*s + 135960625*p**6*q**3*r**2*s + 587471875*p**3*q**5*r**2*s - 384750000*q**7*r**2*s - 29325000*p**7*q*r**3*s - 320625000*p**4*q**3*r**3*s + 523437500*p*q**5*r**3*s - 42000000*p**5*q*r**4*s + 343750000*p**2*q**3*r**4*s + 150000000*p**3*q*r**5*s - 2250000000*q**3*r**5*s + 510300*p**12*s**2 + 12808125*p**9*q**2*s**2 + 107062500*p**6*q**4*s**2 + 270312500*p**3*q**6*s**2 - 168750000*q**8*s**2 - 2551500*p**10*r*s**2 - 5062500*p**7*q**2*r*s**2 + 712343750*p**4*q**4*r*s**2 + 4788281250*p*q**6*r*s**2 - 256837500*p**8*r**2*s**2 - 3574812500*p**5*q**2*r**2*s**2 - 14967968750*p**2*q**4*r**2*s**2 + 4040937500*p**6*r**3*s**2 + 26400000000*p**3*q**2*r**3*s**2 + 17083984375*q**4*r**3*s**2 - 21812500000*p**4*r**4*s**2 - 24375000000*p*q**2*r**4*s**2 + 39375000000*p**2*r**5*s**2 - 127265625*p**5*q**3*s**3 - 680234375*p**2*q**5*s**3 - 2048203125*p**6*q*r*s**3 - 18794531250*p**3*q**3*r*s**3 - 25050000000*q**5*r*s**3 + 26621875000*p**4*q*r**2*s**3 + 37007812500*p*q**3*r**2*s**3 - 105468750000*p**2*q*r**3*s**3 - 56250000000*q*r**4*s**3 + 1124296875*p**7*s**4 + 9251953125*p**4*q**2*s**4 - 8007812500*p*q**4*s**4 - 4004296875*p**5*r*s**4 + 179931640625*p**2*q**2*r*s**4 - 75703125000*p**3*r**2*s**4 + 133447265625*q**2*r**2*s**4 + 363281250000*p*r**3*s**4 - 91552734375*p**3*q*s**5 - 19531250000*q**3*s**5 - 751953125000*p*q*r*s**5 + 157958984375*p**2*s**6 + 748291015625*r*s**6 + + o[0] = -14400*p**6*q**6 - 212400*p**3*q**8 - 777600*q**10 + 92100*p**7*q**4*r + 1689675*p**4*q**6*r + 7371000*p*q**8*r - 122850*p**8*q**2*r**2 - 3735250*p**5*q**4*r**2 - 22432500*p**2*q**6*r**2 + 2298750*p**6*q**2*r**3 + 29390625*p**3*q**4*r**3 + 18000000*q**6*r**3 - 17750000*p**4*q**2*r**4 - 62812500*p*q**4*r**4 + 37500000*p**2*q**2*r**5 - 51300*p**8*q**3*s - 768025*p**5*q**5*s - 2801250*p**2*q**7*s - 275400*p**9*q*r*s - 5479875*p**6*q**3*r*s - 35538750*p**3*q**5*r*s - 68850000*q**7*r*s + 12757500*p**7*q*r**2*s + 133640625*p**4*q**3*r**2*s + 222609375*p*q**5*r**2*s - 108500000*p**5*q*r**3*s - 290312500*p**2*q**3*r**3*s + 275000000*p**3*q*r**4*s - 375000000*q**3*r**4*s + 1931850*p**10*s**2 + 40213125*p**7*q**2*s**2 + 253921875*p**4*q**4*s**2 + 464062500*p*q**6*s**2 - 71077500*p**8*r*s**2 - 818746875*p**5*q**2*r*s**2 - 1882265625*p**2*q**4*r*s**2 + 826031250*p**6*r**2*s**2 + 4369687500*p**3*q**2*r**2*s**2 + 3107812500*q**4*r**2*s**2 - 3943750000*p**4*r**3*s**2 - 5000000000*p*q**2*r**3*s**2 + 6562500000*p**2*r**4*s**2 - 295312500*p**6*q*s**3 - 2938906250*p**3*q**3*s**3 - 4848750000*q**5*s**3 + 3791484375*p**4*q*r*s**3 + 7556250000*p*q**3*r*s**3 - 11960937500*p**2*q*r**2*s**3 - 9375000000*q*r**3*s**3 + 1668515625*p**5*s**4 + 20447265625*p**2*q**2*s**4 - 21955078125*p**3*r*s**4 + 18984375000*q**2*r*s**4 + 67382812500*p*r**2*s**4 - 120849609375*p*q*s**5 + 157226562500*s**6 + + return o + + @property + def a(self): + p, q, r, s = self.p, self.q, self.r, self.s + a = [0]*6 + + a[5] = -100*p**7*q**7 - 2175*p**4*q**9 - 10500*p*q**11 + 1100*p**8*q**5*r + 27975*p**5*q**7*r + 152950*p**2*q**9*r - 4125*p**9*q**3*r**2 - 128875*p**6*q**5*r**2 - 830525*p**3*q**7*r**2 + 59450*q**9*r**2 + 5400*p**10*q*r**3 + 243800*p**7*q**3*r**3 + 2082650*p**4*q**5*r**3 - 333925*p*q**7*r**3 - 139200*p**8*q*r**4 - 2406000*p**5*q**3*r**4 - 122600*p**2*q**5*r**4 + 1254400*p**6*q*r**5 + 3776000*p**3*q**3*r**5 + 1832000*q**5*r**5 - 4736000*p**4*q*r**6 - 6720000*p*q**3*r**6 + 6400000*p**2*q*r**7 - 900*p**9*q**4*s - 37400*p**6*q**6*s - 281625*p**3*q**8*s - 435000*q**10*s + 6750*p**10*q**2*r*s + 322300*p**7*q**4*r*s + 2718575*p**4*q**6*r*s + 4214250*p*q**8*r*s - 16200*p**11*r**2*s - 859275*p**8*q**2*r**2*s - 8925475*p**5*q**4*r**2*s - 14427875*p**2*q**6*r**2*s + 453600*p**9*r**3*s + 10038400*p**6*q**2*r**3*s + 17397500*p**3*q**4*r**3*s - 11333125*q**6*r**3*s - 4451200*p**7*r**4*s - 15850000*p**4*q**2*r**4*s + 34000000*p*q**4*r**4*s + 17984000*p**5*r**5*s - 10000000*p**2*q**2*r**5*s - 25600000*p**3*r**6*s - 8000000*q**2*r**6*s + 6075*p**11*q*s**2 - 83250*p**8*q**3*s**2 - 1282500*p**5*q**5*s**2 - 2862500*p**2*q**7*s**2 + 724275*p**9*q*r*s**2 + 9807250*p**6*q**3*r*s**2 + 28374375*p**3*q**5*r*s**2 + 22212500*q**7*r*s**2 - 8982000*p**7*q*r**2*s**2 - 39600000*p**4*q**3*r**2*s**2 - 61746875*p*q**5*r**2*s**2 - 1010000*p**5*q*r**3*s**2 - 1000000*p**2*q**3*r**3*s**2 + 78000000*p**3*q*r**4*s**2 + 30000000*q**3*r**4*s**2 + 80000000*p*q*r**5*s**2 - 759375*p**10*s**3 - 9787500*p**7*q**2*s**3 - 39062500*p**4*q**4*s**3 - 52343750*p*q**6*s**3 + 12301875*p**8*r*s**3 + 98175000*p**5*q**2*r*s**3 + 225078125*p**2*q**4*r*s**3 - 54900000*p**6*r**2*s**3 - 310000000*p**3*q**2*r**2*s**3 - 7890625*q**4*r**2*s**3 + 51250000*p**4*r**3*s**3 - 420000000*p*q**2*r**3*s**3 + 110000000*p**2*r**4*s**3 - 200000000*r**5*s**3 + 2109375*p**6*q*s**4 - 21093750*p**3*q**3*s**4 - 89843750*q**5*s**4 + 182343750*p**4*q*r*s**4 + 733203125*p*q**3*r*s**4 - 196875000*p**2*q*r**2*s**4 + 1125000000*q*r**3*s**4 - 158203125*p**5*s**5 - 566406250*p**2*q**2*s**5 + 101562500*p**3*r*s**5 - 1669921875*q**2*r*s**5 + 1250000000*p*r**2*s**5 - 1220703125*p*q*s**6 + 6103515625*s**7 + + a[4] = 1000*p**5*q**7 + 7250*p**2*q**9 - 10800*p**6*q**5*r - 96900*p**3*q**7*r - 52500*q**9*r + 37400*p**7*q**3*r**2 + 470850*p**4*q**5*r**2 + 640600*p*q**7*r**2 - 39600*p**8*q*r**3 - 983600*p**5*q**3*r**3 - 2848100*p**2*q**5*r**3 + 814400*p**6*q*r**4 + 6076000*p**3*q**3*r**4 + 2308000*q**5*r**4 - 5024000*p**4*q*r**5 - 9680000*p*q**3*r**5 + 9600000*p**2*q*r**6 + 13800*p**7*q**4*s + 94650*p**4*q**6*s - 26500*p*q**8*s - 86400*p**8*q**2*r*s - 816500*p**5*q**4*r*s - 257500*p**2*q**6*r*s + 91800*p**9*r**2*s + 1853700*p**6*q**2*r**2*s + 630000*p**3*q**4*r**2*s - 8971250*q**6*r**2*s - 2071200*p**7*r**3*s - 7240000*p**4*q**2*r**3*s + 29375000*p*q**4*r**3*s + 14416000*p**5*r**4*s - 5200000*p**2*q**2*r**4*s - 30400000*p**3*r**5*s - 12000000*q**2*r**5*s + 64800*p**9*q*s**2 + 567000*p**6*q**3*s**2 + 1655000*p**3*q**5*s**2 + 6987500*q**7*s**2 + 337500*p**7*q*r*s**2 + 8462500*p**4*q**3*r*s**2 - 5812500*p*q**5*r*s**2 - 24930000*p**5*q*r**2*s**2 - 69125000*p**2*q**3*r**2*s**2 + 103500000*p**3*q*r**3*s**2 + 30000000*q**3*r**3*s**2 + 90000000*p*q*r**4*s**2 - 708750*p**8*s**3 - 5400000*p**5*q**2*s**3 + 8906250*p**2*q**4*s**3 + 18562500*p**6*r*s**3 - 625000*p**3*q**2*r*s**3 + 29687500*q**4*r*s**3 - 75000000*p**4*r**2*s**3 - 416250000*p*q**2*r**2*s**3 + 60000000*p**2*r**3*s**3 - 300000000*r**4*s**3 + 71718750*p**4*q*s**4 + 189062500*p*q**3*s**4 + 210937500*p**2*q*r*s**4 + 1187500000*q*r**2*s**4 - 187500000*p**3*s**5 - 800781250*q**2*s**5 - 390625000*p*r*s**5 + + a[3] = -500*p**6*q**5 - 6350*p**3*q**7 - 19800*q**9 + 3750*p**7*q**3*r + 65100*p**4*q**5*r + 264950*p*q**7*r - 6750*p**8*q*r**2 - 209050*p**5*q**3*r**2 - 1217250*p**2*q**5*r**2 + 219000*p**6*q*r**3 + 2510000*p**3*q**3*r**3 + 1098500*q**5*r**3 - 2068000*p**4*q*r**4 - 5060000*p*q**3*r**4 + 5200000*p**2*q*r**5 - 6750*p**8*q**2*s - 96350*p**5*q**4*s - 346000*p**2*q**6*s + 20250*p**9*r*s + 459900*p**6*q**2*r*s + 1828750*p**3*q**4*r*s - 2930000*q**6*r*s - 594000*p**7*r**2*s - 4301250*p**4*q**2*r**2*s + 10906250*p*q**4*r**2*s + 5252000*p**5*r**3*s - 1450000*p**2*q**2*r**3*s - 12800000*p**3*r**4*s - 6500000*q**2*r**4*s + 74250*p**7*q*s**2 + 1418750*p**4*q**3*s**2 + 5956250*p*q**5*s**2 - 4297500*p**5*q*r*s**2 - 29906250*p**2*q**3*r*s**2 + 31500000*p**3*q*r**2*s**2 + 12500000*q**3*r**2*s**2 + 35000000*p*q*r**3*s**2 + 1350000*p**6*s**3 + 6093750*p**3*q**2*s**3 + 17500000*q**4*s**3 - 7031250*p**4*r*s**3 - 127812500*p*q**2*r*s**3 + 18750000*p**2*r**2*s**3 - 162500000*r**3*s**3 + 107812500*p**2*q*s**4 + 460937500*q*r*s**4 - 214843750*p*s**5 + + a[2] = 1950*p**4*q**5 + 14100*p*q**7 - 14350*p**5*q**3*r - 125600*p**2*q**5*r + 27900*p**6*q*r**2 + 402250*p**3*q**3*r**2 + 288250*q**5*r**2 - 436000*p**4*q*r**3 - 1345000*p*q**3*r**3 + 1400000*p**2*q*r**4 + 9450*p**6*q**2*s - 1250*p**3*q**4*s - 465000*q**6*s - 49950*p**7*r*s - 302500*p**4*q**2*r*s + 1718750*p*q**4*r*s + 834000*p**5*r**2*s + 437500*p**2*q**2*r**2*s - 3100000*p**3*r**3*s - 1750000*q**2*r**3*s - 292500*p**5*q*s**2 - 1937500*p**2*q**3*s**2 + 3343750*p**3*q*r*s**2 + 1875000*q**3*r*s**2 + 8125000*p*q*r**2*s**2 - 1406250*p**4*s**3 - 12343750*p*q**2*s**3 + 5312500*p**2*r*s**3 - 43750000*r**2*s**3 + 74218750*q*s**4 + + a[1] = -300*p**5*q**3 - 2150*p**2*q**5 + 1350*p**6*q*r + 21500*p**3*q**3*r + 61500*q**5*r - 42000*p**4*q*r**2 - 290000*p*q**3*r**2 + 300000*p**2*q*r**3 - 4050*p**7*s - 45000*p**4*q**2*s - 125000*p*q**4*s + 108000*p**5*r*s + 643750*p**2*q**2*r*s - 700000*p**3*r**2*s - 375000*q**2*r**2*s - 93750*p**3*q*s**2 - 312500*q**3*s**2 + 1875000*p*q*r*s**2 - 1406250*p**2*s**3 - 9375000*r*s**3 + + a[0] = 1250*p**3*q**3 + 9000*q**5 - 4500*p**4*q*r - 46250*p*q**3*r + 50000*p**2*q*r**2 + 6750*p**5*s + 43750*p**2*q**2*s - 75000*p**3*r*s - 62500*q**2*r*s + 156250*p*q*s**2 - 1562500*s**3 + + return a + + @property + def c(self): + p, q, r, s = self.p, self.q, self.r, self.s + c = [0]*6 + + c[5] = -40*p**5*q**11 - 270*p**2*q**13 + 700*p**6*q**9*r + 5165*p**3*q**11*r + 540*q**13*r - 4230*p**7*q**7*r**2 - 31845*p**4*q**9*r**2 + 20880*p*q**11*r**2 + 9645*p**8*q**5*r**3 + 57615*p**5*q**7*r**3 - 358255*p**2*q**9*r**3 - 1880*p**9*q**3*r**4 + 114020*p**6*q**5*r**4 + 2012190*p**3*q**7*r**4 - 26855*q**9*r**4 - 14400*p**10*q*r**5 - 470400*p**7*q**3*r**5 - 5088640*p**4*q**5*r**5 + 920*p*q**7*r**5 + 332800*p**8*q*r**6 + 5797120*p**5*q**3*r**6 + 1608000*p**2*q**5*r**6 - 2611200*p**6*q*r**7 - 7424000*p**3*q**3*r**7 - 2323200*q**5*r**7 + 8601600*p**4*q*r**8 + 9472000*p*q**3*r**8 - 10240000*p**2*q*r**9 - 3060*p**7*q**8*s - 39085*p**4*q**10*s - 132300*p*q**12*s + 36580*p**8*q**6*r*s + 520185*p**5*q**8*r*s + 1969860*p**2*q**10*r*s - 144045*p**9*q**4*r**2*s - 2438425*p**6*q**6*r**2*s - 10809475*p**3*q**8*r**2*s + 518850*q**10*r**2*s + 182520*p**10*q**2*r**3*s + 4533930*p**7*q**4*r**3*s + 26196770*p**4*q**6*r**3*s - 4542325*p*q**8*r**3*s + 21600*p**11*r**4*s - 2208080*p**8*q**2*r**4*s - 24787960*p**5*q**4*r**4*s + 10813900*p**2*q**6*r**4*s - 499200*p**9*r**5*s + 3827840*p**6*q**2*r**5*s + 9596000*p**3*q**4*r**5*s + 22662000*q**6*r**5*s + 3916800*p**7*r**6*s - 29952000*p**4*q**2*r**6*s - 90800000*p*q**4*r**6*s - 12902400*p**5*r**7*s + 87040000*p**2*q**2*r**7*s + 15360000*p**3*r**8*s + 12800000*q**2*r**8*s - 38070*p**9*q**5*s**2 - 566700*p**6*q**7*s**2 - 2574375*p**3*q**9*s**2 - 1822500*q**11*s**2 + 292815*p**10*q**3*r*s**2 + 5170280*p**7*q**5*r*s**2 + 27918125*p**4*q**7*r*s**2 + 21997500*p*q**9*r*s**2 - 573480*p**11*q*r**2*s**2 - 14566350*p**8*q**3*r**2*s**2 - 104851575*p**5*q**5*r**2*s**2 - 96448750*p**2*q**7*r**2*s**2 + 11001240*p**9*q*r**3*s**2 + 147798600*p**6*q**3*r**3*s**2 + 158632750*p**3*q**5*r**3*s**2 - 78222500*q**7*r**3*s**2 - 62819200*p**7*q*r**4*s**2 - 136160000*p**4*q**3*r**4*s**2 + 317555000*p*q**5*r**4*s**2 + 160224000*p**5*q*r**5*s**2 - 267600000*p**2*q**3*r**5*s**2 - 153600000*p**3*q*r**6*s**2 - 120000000*q**3*r**6*s**2 - 32000000*p*q*r**7*s**2 - 127575*p**11*q**2*s**3 - 2148750*p**8*q**4*s**3 - 13652500*p**5*q**6*s**3 - 19531250*p**2*q**8*s**3 + 495720*p**12*r*s**3 + 11856375*p**9*q**2*r*s**3 + 107807500*p**6*q**4*r*s**3 + 222334375*p**3*q**6*r*s**3 + 105062500*q**8*r*s**3 - 11566800*p**10*r**2*s**3 - 216787500*p**7*q**2*r**2*s**3 - 633437500*p**4*q**4*r**2*s**3 - 504484375*p*q**6*r**2*s**3 + 90918000*p**8*r**3*s**3 + 567080000*p**5*q**2*r**3*s**3 + 692937500*p**2*q**4*r**3*s**3 - 326640000*p**6*r**4*s**3 - 339000000*p**3*q**2*r**4*s**3 + 369250000*q**4*r**4*s**3 + 560000000*p**4*r**5*s**3 + 508000000*p*q**2*r**5*s**3 - 480000000*p**2*r**6*s**3 + 320000000*r**7*s**3 - 455625*p**10*q*s**4 - 27562500*p**7*q**3*s**4 - 120593750*p**4*q**5*s**4 - 60312500*p*q**7*s**4 + 110615625*p**8*q*r*s**4 + 662984375*p**5*q**3*r*s**4 + 528515625*p**2*q**5*r*s**4 - 541687500*p**6*q*r**2*s**4 - 1262343750*p**3*q**3*r**2*s**4 - 466406250*q**5*r**2*s**4 + 633000000*p**4*q*r**3*s**4 - 1264375000*p*q**3*r**3*s**4 + 1085000000*p**2*q*r**4*s**4 - 2700000000*q*r**5*s**4 - 68343750*p**9*s**5 - 478828125*p**6*q**2*s**5 - 355468750*p**3*q**4*s**5 - 11718750*q**6*s**5 + 718031250*p**7*r*s**5 + 1658593750*p**4*q**2*r*s**5 + 2212890625*p*q**4*r*s**5 - 2855625000*p**5*r**2*s**5 - 4273437500*p**2*q**2*r**2*s**5 + 4537500000*p**3*r**3*s**5 + 8031250000*q**2*r**3*s**5 - 1750000000*p*r**4*s**5 + 1353515625*p**5*q*s**6 + 1562500000*p**2*q**3*s**6 - 3964843750*p**3*q*r*s**6 - 7226562500*q**3*r*s**6 + 1953125000*p*q*r**2*s**6 - 1757812500*p**4*s**7 - 3173828125*p*q**2*s**7 + 6445312500*p**2*r*s**7 - 3906250000*r**2*s**7 + 6103515625*q*s**8 + + c[4] = 40*p**6*q**9 + 110*p**3*q**11 - 1080*q**13 - 560*p**7*q**7*r - 1780*p**4*q**9*r + 17370*p*q**11*r + 2850*p**8*q**5*r**2 + 10520*p**5*q**7*r**2 - 115910*p**2*q**9*r**2 - 6090*p**9*q**3*r**3 - 25330*p**6*q**5*r**3 + 448740*p**3*q**7*r**3 + 128230*q**9*r**3 + 4320*p**10*q*r**4 + 16960*p**7*q**3*r**4 - 1143600*p**4*q**5*r**4 - 1410310*p*q**7*r**4 + 3840*p**8*q*r**5 + 1744480*p**5*q**3*r**5 + 5619520*p**2*q**5*r**5 - 1198080*p**6*q*r**6 - 10579200*p**3*q**3*r**6 - 2940800*q**5*r**6 + 8294400*p**4*q*r**7 + 13568000*p*q**3*r**7 - 15360000*p**2*q*r**8 + 840*p**8*q**6*s + 7580*p**5*q**8*s + 24420*p**2*q**10*s - 8100*p**9*q**4*r*s - 94100*p**6*q**6*r*s - 473000*p**3*q**8*r*s - 473400*q**10*r*s + 22680*p**10*q**2*r**2*s + 374370*p**7*q**4*r**2*s + 2888020*p**4*q**6*r**2*s + 5561050*p*q**8*r**2*s - 12960*p**11*r**3*s - 485820*p**8*q**2*r**3*s - 6723440*p**5*q**4*r**3*s - 23561400*p**2*q**6*r**3*s + 190080*p**9*r**4*s + 5894880*p**6*q**2*r**4*s + 50882000*p**3*q**4*r**4*s + 22411500*q**6*r**4*s - 258560*p**7*r**5*s - 46248000*p**4*q**2*r**5*s - 103800000*p*q**4*r**5*s - 3737600*p**5*r**6*s + 119680000*p**2*q**2*r**6*s + 10240000*p**3*r**7*s + 19200000*q**2*r**7*s + 7290*p**10*q**3*s**2 + 117360*p**7*q**5*s**2 + 691250*p**4*q**7*s**2 - 198750*p*q**9*s**2 - 36450*p**11*q*r*s**2 - 854550*p**8*q**3*r*s**2 - 7340700*p**5*q**5*r*s**2 - 2028750*p**2*q**7*r*s**2 + 995490*p**9*q*r**2*s**2 + 18896600*p**6*q**3*r**2*s**2 + 5026500*p**3*q**5*r**2*s**2 - 52272500*q**7*r**2*s**2 - 16636800*p**7*q*r**3*s**2 - 43200000*p**4*q**3*r**3*s**2 + 223426250*p*q**5*r**3*s**2 + 112068000*p**5*q*r**4*s**2 - 177000000*p**2*q**3*r**4*s**2 - 244000000*p**3*q*r**5*s**2 - 156000000*q**3*r**5*s**2 + 43740*p**12*s**3 + 1032750*p**9*q**2*s**3 + 8602500*p**6*q**4*s**3 + 15606250*p**3*q**6*s**3 + 39625000*q**8*s**3 - 1603800*p**10*r*s**3 - 26932500*p**7*q**2*r*s**3 - 19562500*p**4*q**4*r*s**3 - 152000000*p*q**6*r*s**3 + 25555500*p**8*r**2*s**3 + 16230000*p**5*q**2*r**2*s**3 + 42187500*p**2*q**4*r**2*s**3 - 165660000*p**6*r**3*s**3 + 373500000*p**3*q**2*r**3*s**3 + 332937500*q**4*r**3*s**3 + 465000000*p**4*r**4*s**3 + 586000000*p*q**2*r**4*s**3 - 592000000*p**2*r**5*s**3 + 480000000*r**6*s**3 - 1518750*p**8*q*s**4 - 62531250*p**5*q**3*s**4 + 7656250*p**2*q**5*s**4 + 184781250*p**6*q*r*s**4 - 15781250*p**3*q**3*r*s**4 - 135156250*q**5*r*s**4 - 1148250000*p**4*q*r**2*s**4 - 2121406250*p*q**3*r**2*s**4 + 1990000000*p**2*q*r**3*s**4 - 3150000000*q*r**4*s**4 - 2531250*p**7*s**5 + 660937500*p**4*q**2*s**5 + 1339843750*p*q**4*s**5 - 33750000*p**5*r*s**5 - 679687500*p**2*q**2*r*s**5 + 6250000*p**3*r**2*s**5 + 6195312500*q**2*r**2*s**5 + 1125000000*p*r**3*s**5 - 996093750*p**3*q*s**6 - 3125000000*q**3*s**6 - 3222656250*p*q*r*s**6 + 1171875000*p**2*s**7 + 976562500*r*s**7 + + c[3] = 80*p**4*q**9 + 540*p*q**11 - 600*p**5*q**7*r - 4770*p**2*q**9*r + 1230*p**6*q**5*r**2 + 20900*p**3*q**7*r**2 + 47250*q**9*r**2 - 710*p**7*q**3*r**3 - 84950*p**4*q**5*r**3 - 526310*p*q**7*r**3 + 720*p**8*q*r**4 + 216280*p**5*q**3*r**4 + 2068020*p**2*q**5*r**4 - 198080*p**6*q*r**5 - 3703200*p**3*q**3*r**5 - 1423600*q**5*r**5 + 2860800*p**4*q*r**6 + 7056000*p*q**3*r**6 - 8320000*p**2*q*r**7 - 2720*p**6*q**6*s - 46350*p**3*q**8*s - 178200*q**10*s + 25740*p**7*q**4*r*s + 489490*p**4*q**6*r*s + 2152350*p*q**8*r*s - 61560*p**8*q**2*r**2*s - 1568150*p**5*q**4*r**2*s - 9060500*p**2*q**6*r**2*s + 24840*p**9*r**3*s + 1692380*p**6*q**2*r**3*s + 18098250*p**3*q**4*r**3*s + 9387750*q**6*r**3*s - 382560*p**7*r**4*s - 16818000*p**4*q**2*r**4*s - 49325000*p*q**4*r**4*s + 1212800*p**5*r**5*s + 64840000*p**2*q**2*r**5*s - 320000*p**3*r**6*s + 10400000*q**2*r**6*s - 36450*p**8*q**3*s**2 - 588350*p**5*q**5*s**2 - 2156250*p**2*q**7*s**2 + 123930*p**9*q*r*s**2 + 2879700*p**6*q**3*r*s**2 + 12548000*p**3*q**5*r*s**2 - 14445000*q**7*r*s**2 - 3233250*p**7*q*r**2*s**2 - 28485000*p**4*q**3*r**2*s**2 + 72231250*p*q**5*r**2*s**2 + 32093000*p**5*q*r**3*s**2 - 61275000*p**2*q**3*r**3*s**2 - 107500000*p**3*q*r**4*s**2 - 78500000*q**3*r**4*s**2 + 22000000*p*q*r**5*s**2 - 72900*p**10*s**3 - 1215000*p**7*q**2*s**3 - 2937500*p**4*q**4*s**3 + 9156250*p*q**6*s**3 + 2612250*p**8*r*s**3 + 16560000*p**5*q**2*r*s**3 - 75468750*p**2*q**4*r*s**3 - 32737500*p**6*r**2*s**3 + 169062500*p**3*q**2*r**2*s**3 + 121718750*q**4*r**2*s**3 + 160250000*p**4*r**3*s**3 + 219750000*p*q**2*r**3*s**3 - 317000000*p**2*r**4*s**3 + 260000000*r**5*s**3 + 2531250*p**6*q*s**4 + 22500000*p**3*q**3*s**4 + 39843750*q**5*s**4 - 266343750*p**4*q*r*s**4 - 776406250*p*q**3*r*s**4 + 789062500*p**2*q*r**2*s**4 - 1368750000*q*r**3*s**4 + 67500000*p**5*s**5 + 441406250*p**2*q**2*s**5 - 311718750*p**3*r*s**5 + 1785156250*q**2*r*s**5 + 546875000*p*r**2*s**5 - 1269531250*p*q*s**6 + 488281250*s**7 + + c[2] = 120*p**5*q**7 + 810*p**2*q**9 - 1280*p**6*q**5*r - 9160*p**3*q**7*r + 3780*q**9*r + 4530*p**7*q**3*r**2 + 36640*p**4*q**5*r**2 - 45270*p*q**7*r**2 - 5400*p**8*q*r**3 - 60920*p**5*q**3*r**3 + 200050*p**2*q**5*r**3 + 31200*p**6*q*r**4 - 476000*p**3*q**3*r**4 - 378200*q**5*r**4 + 521600*p**4*q*r**5 + 1872000*p*q**3*r**5 - 2240000*p**2*q*r**6 + 1440*p**7*q**4*s + 15310*p**4*q**6*s + 59400*p*q**8*s - 9180*p**8*q**2*r*s - 115240*p**5*q**4*r*s - 589650*p**2*q**6*r*s + 16200*p**9*r**2*s + 316710*p**6*q**2*r**2*s + 2547750*p**3*q**4*r**2*s + 2178000*q**6*r**2*s - 259200*p**7*r**3*s - 4123000*p**4*q**2*r**3*s - 11700000*p*q**4*r**3*s + 937600*p**5*r**4*s + 16340000*p**2*q**2*r**4*s - 640000*p**3*r**5*s + 2800000*q**2*r**5*s - 2430*p**9*q*s**2 - 54450*p**6*q**3*s**2 - 285500*p**3*q**5*s**2 - 2767500*q**7*s**2 + 43200*p**7*q*r*s**2 - 916250*p**4*q**3*r*s**2 + 14482500*p*q**5*r*s**2 + 4806000*p**5*q*r**2*s**2 - 13212500*p**2*q**3*r**2*s**2 - 25400000*p**3*q*r**3*s**2 - 18750000*q**3*r**3*s**2 + 8000000*p*q*r**4*s**2 + 121500*p**8*s**3 + 2058750*p**5*q**2*s**3 - 6656250*p**2*q**4*s**3 - 6716250*p**6*r*s**3 + 24125000*p**3*q**2*r*s**3 + 23875000*q**4*r*s**3 + 43125000*p**4*r**2*s**3 + 45750000*p*q**2*r**2*s**3 - 87500000*p**2*r**3*s**3 + 70000000*r**4*s**3 - 44437500*p**4*q*s**4 - 107968750*p*q**3*s**4 + 159531250*p**2*q*r*s**4 - 284375000*q*r**2*s**4 + 7031250*p**3*s**5 + 265625000*q**2*s**5 + 31250000*p*r*s**5 + + c[1] = 160*p**3*q**7 + 1080*q**9 - 1080*p**4*q**5*r - 8730*p*q**7*r + 1510*p**5*q**3*r**2 + 20420*p**2*q**5*r**2 + 720*p**6*q*r**3 - 23200*p**3*q**3*r**3 - 79900*q**5*r**3 + 35200*p**4*q*r**4 + 404000*p*q**3*r**4 - 480000*p**2*q*r**5 + 960*p**5*q**4*s + 2850*p**2*q**6*s + 540*p**6*q**2*r*s + 63500*p**3*q**4*r*s + 319500*q**6*r*s - 7560*p**7*r**2*s - 253500*p**4*q**2*r**2*s - 1806250*p*q**4*r**2*s + 91200*p**5*r**3*s + 2600000*p**2*q**2*r**3*s - 80000*p**3*r**4*s + 600000*q**2*r**4*s - 4050*p**7*q*s**2 - 120000*p**4*q**3*s**2 - 273750*p*q**5*s**2 + 425250*p**5*q*r*s**2 + 2325000*p**2*q**3*r*s**2 - 5400000*p**3*q*r**2*s**2 - 2875000*q**3*r**2*s**2 + 1500000*p*q*r**3*s**2 - 303750*p**6*s**3 - 843750*p**3*q**2*s**3 - 812500*q**4*s**3 + 5062500*p**4*r*s**3 + 13312500*p*q**2*r*s**3 - 14500000*p**2*r**2*s**3 + 15000000*r**3*s**3 - 3750000*p**2*q*s**4 - 35937500*q*r*s**4 + 11718750*p*s**5 + + c[0] = 80*p**4*q**5 + 540*p*q**7 - 600*p**5*q**3*r - 4770*p**2*q**5*r + 1080*p**6*q*r**2 + 11200*p**3*q**3*r**2 - 12150*q**5*r**2 - 4800*p**4*q*r**3 + 64000*p*q**3*r**3 - 80000*p**2*q*r**4 + 1080*p**6*q**2*s + 13250*p**3*q**4*s + 54000*q**6*s - 3240*p**7*r*s - 56250*p**4*q**2*r*s - 337500*p*q**4*r*s + 43200*p**5*r**2*s + 560000*p**2*q**2*r**2*s - 80000*p**3*r**3*s + 100000*q**2*r**3*s + 6750*p**5*q*s**2 + 225000*p**2*q**3*s**2 - 900000*p**3*q*r*s**2 - 562500*q**3*r*s**2 + 500000*p*q*r**2*s**2 + 843750*p**4*s**3 + 1937500*p*q**2*s**3 - 3000000*p**2*r*s**3 + 2500000*r**2*s**3 - 5468750*q*s**4 + + return c + + @property + def F(self): + p, q, r, s = self.p, self.q, self.r, self.s + F = 4*p**6*q**6 + 59*p**3*q**8 + 216*q**10 - 36*p**7*q**4*r - 623*p**4*q**6*r - 2610*p*q**8*r + 81*p**8*q**2*r**2 + 2015*p**5*q**4*r**2 + 10825*p**2*q**6*r**2 - 1800*p**6*q**2*r**3 - 17500*p**3*q**4*r**3 + 625*q**6*r**3 + 10000*p**4*q**2*r**4 + 108*p**8*q**3*s + 1584*p**5*q**5*s + 5700*p**2*q**7*s - 486*p**9*q*r*s - 9720*p**6*q**3*r*s - 45050*p**3*q**5*r*s - 9000*q**7*r*s + 10800*p**7*q*r**2*s + 92500*p**4*q**3*r**2*s + 32500*p*q**5*r**2*s - 60000*p**5*q*r**3*s - 50000*p**2*q**3*r**3*s + 729*p**10*s**2 + 12150*p**7*q**2*s**2 + 60000*p**4*q**4*s**2 + 93750*p*q**6*s**2 - 18225*p**8*r*s**2 - 175500*p**5*q**2*r*s**2 - 478125*p**2*q**4*r*s**2 + 135000*p**6*r**2*s**2 + 850000*p**3*q**2*r**2*s**2 + 15625*q**4*r**2*s**2 - 250000*p**4*r**3*s**2 + 225000*p**3*q**3*s**3 + 175000*q**5*s**3 - 1012500*p**4*q*r*s**3 - 1187500*p*q**3*r*s**3 + 1250000*p**2*q*r**2*s**3 + 928125*p**5*s**4 + 1875000*p**2*q**2*s**4 - 2812500*p**3*r*s**4 - 390625*q**2*r*s**4 - 9765625*s**6 + return F + + def l0(self, theta): + F = self.F + a = self.a + l0 = Poly(a, x).eval(theta)/F + return l0 + + def T(self, theta, d): + F = self.F + T = [0]*5 + b = self.b + # Note that the order of sublists of the b's has been reversed compared to the paper + T[1] = -Poly(b[1], x).eval(theta)/(2*F) + T[2] = Poly(b[2], x).eval(theta)/(2*d*F) + T[3] = Poly(b[3], x).eval(theta)/(2*F) + T[4] = Poly(b[4], x).eval(theta)/(2*d*F) + return T + + def order(self, theta, d): + F = self.F + o = self.o + order = Poly(o, x).eval(theta)/(d*F) + return N(order) + + def uv(self, theta, d): + c = self.c + u = self.q*Rational(-25, 2) + v = Poly(c, x).eval(theta)/(2*d*self.F) + return N(u), N(v) + + @property + def zeta(self): + return [self.zeta1, self.zeta2, self.zeta3, self.zeta4] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyroots.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyroots.py new file mode 100644 index 0000000000000000000000000000000000000000..4def1312eb5b94a13e511d2d4f9b15f1d51fd63f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyroots.py @@ -0,0 +1,1227 @@ +"""Algorithms for computing symbolic roots of polynomials. """ + + +import math +from functools import reduce + +from sympy.core import S, I, pi +from sympy.core.exprtools import factor_terms +from sympy.core.function import _mexpand +from sympy.core.logic import fuzzy_not +from sympy.core.mul import expand_2arg, Mul +from sympy.core.intfunc import igcd +from sympy.core.numbers import Rational, comp +from sympy.core.power import Pow +from sympy.core.relational import Eq +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy, Symbol, symbols +from sympy.core.sympify import sympify +from sympy.functions import exp, im, cos, acos, Piecewise +from sympy.functions.elementary.miscellaneous import root, sqrt +from sympy.ntheory import divisors, isprime, nextprime +from sympy.polys.domains import EX +from sympy.polys.polyerrors import (PolynomialError, GeneratorsNeeded, + DomainError, UnsolvableFactorError) +from sympy.polys.polyquinticconst import PolyQuintic +from sympy.polys.polytools import Poly, cancel, factor, gcd_list, discriminant +from sympy.polys.rationaltools import together +from sympy.polys.specialpolys import cyclotomic_poly +from sympy.utilities import public +from sympy.utilities.misc import filldedent + + + +z = Symbol('z') # importing from abc cause O to be lost as clashing symbol + + +def roots_linear(f): + """Returns a list of roots of a linear polynomial.""" + r = -f.nth(0)/f.nth(1) + dom = f.get_domain() + + if not dom.is_Numerical: + if dom.is_Composite: + r = factor(r) + else: + from sympy.simplify.simplify import simplify + r = simplify(r) + + return [r] + + +def roots_quadratic(f): + """Returns a list of roots of a quadratic polynomial. If the domain is ZZ + then the roots will be sorted with negatives coming before positives. + The ordering will be the same for any numerical coefficients as long as + the assumptions tested are correct, otherwise the ordering will not be + sorted (but will be canonical). + """ + + a, b, c = f.all_coeffs() + dom = f.get_domain() + + def _sqrt(d): + # remove squares from square root since both will be represented + # in the results; a similar thing is happening in roots() but + # must be duplicated here because not all quadratics are binomials + co = [] + other = [] + for di in Mul.make_args(d): + if di.is_Pow and di.exp.is_Integer and di.exp % 2 == 0: + co.append(Pow(di.base, di.exp//2)) + else: + other.append(di) + if co: + d = Mul(*other) + co = Mul(*co) + return co*sqrt(d) + return sqrt(d) + + def _simplify(expr): + if dom.is_Composite: + return factor(expr) + else: + from sympy.simplify.simplify import simplify + return simplify(expr) + + if c is S.Zero: + r0, r1 = S.Zero, -b/a + + if not dom.is_Numerical: + r1 = _simplify(r1) + elif r1.is_negative: + r0, r1 = r1, r0 + elif b is S.Zero: + r = -c/a + if not dom.is_Numerical: + r = _simplify(r) + + R = _sqrt(r) + r0 = -R + r1 = R + else: + d = b**2 - 4*a*c + A = 2*a + B = -b/A + + if not dom.is_Numerical: + d = _simplify(d) + B = _simplify(B) + + D = factor_terms(_sqrt(d)/A) + r0 = B - D + r1 = B + D + if a.is_negative: + r0, r1 = r1, r0 + elif not dom.is_Numerical: + r0, r1 = [expand_2arg(i) for i in (r0, r1)] + + return [r0, r1] + + +def roots_cubic(f, trig=False): + """Returns a list of roots of a cubic polynomial. + + References + ========== + [1] https://en.wikipedia.org/wiki/Cubic_function, General formula for roots, + (accessed November 17, 2014). + """ + if trig: + a, b, c, d = f.all_coeffs() + p = (3*a*c - b**2)/(3*a**2) + q = (2*b**3 - 9*a*b*c + 27*a**2*d)/(27*a**3) + D = 18*a*b*c*d - 4*b**3*d + b**2*c**2 - 4*a*c**3 - 27*a**2*d**2 + if (D > 0) == True: + rv = [] + for k in range(3): + rv.append(2*sqrt(-p/3)*cos(acos(q/p*sqrt(-3/p)*Rational(3, 2))/3 - k*pi*Rational(2, 3))) + return [i - b/3/a for i in rv] + + # a*x**3 + b*x**2 + c*x + d -> x**3 + a*x**2 + b*x + c + _, a, b, c = f.monic().all_coeffs() + + if c is S.Zero: + x1, x2 = roots([1, a, b], multiple=True) + return [x1, S.Zero, x2] + + # x**3 + a*x**2 + b*x + c -> u**3 + p*u + q + p = b - a**2/3 + q = c - a*b/3 + 2*a**3/27 + + pon3 = p/3 + aon3 = a/3 + + u1 = None + if p is S.Zero: + if q is S.Zero: + return [-aon3]*3 + u1 = -root(q, 3) if q.is_positive else root(-q, 3) + elif q is S.Zero: + y1, y2 = roots([1, 0, p], multiple=True) + return [tmp - aon3 for tmp in [y1, S.Zero, y2]] + elif q.is_real and q.is_negative: + u1 = -root(-q/2 + sqrt(q**2/4 + pon3**3), 3) + + coeff = I*sqrt(3)/2 + if u1 is None: + u1 = S.One + u2 = Rational(-1, 2) + coeff + u3 = Rational(-1, 2) - coeff + b, c, d = a, b, c # a, b, c, d = S.One, a, b, c + D0 = b**2 - 3*c # b**2 - 3*a*c + D1 = 2*b**3 - 9*b*c + 27*d # 2*b**3 - 9*a*b*c + 27*a**2*d + C = root((D1 + sqrt(D1**2 - 4*D0**3))/2, 3) + return [-(b + uk*C + D0/C/uk)/3 for uk in [u1, u2, u3]] # -(b + uk*C + D0/C/uk)/3/a + + u2 = u1*(Rational(-1, 2) + coeff) + u3 = u1*(Rational(-1, 2) - coeff) + + if p is S.Zero: + return [u1 - aon3, u2 - aon3, u3 - aon3] + + soln = [ + -u1 + pon3/u1 - aon3, + -u2 + pon3/u2 - aon3, + -u3 + pon3/u3 - aon3 + ] + + return soln + +def _roots_quartic_euler(p, q, r, a): + """ + Descartes-Euler solution of the quartic equation + + Parameters + ========== + + p, q, r: coefficients of ``x**4 + p*x**2 + q*x + r`` + a: shift of the roots + + Notes + ===== + + This is a helper function for ``roots_quartic``. + + Look for solutions of the form :: + + ``x1 = sqrt(R) - sqrt(A + B*sqrt(R))`` + ``x2 = -sqrt(R) - sqrt(A - B*sqrt(R))`` + ``x3 = -sqrt(R) + sqrt(A - B*sqrt(R))`` + ``x4 = sqrt(R) + sqrt(A + B*sqrt(R))`` + + To satisfy the quartic equation one must have + ``p = -2*(R + A); q = -4*B*R; r = (R - A)**2 - B**2*R`` + so that ``R`` must satisfy the Descartes-Euler resolvent equation + ``64*R**3 + 32*p*R**2 + (4*p**2 - 16*r)*R - q**2 = 0`` + + If the resolvent does not have a rational solution, return None; + in that case it is likely that the Ferrari method gives a simpler + solution. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.polys.polyroots import _roots_quartic_euler + >>> p, q, r = -S(64)/5, -S(512)/125, -S(1024)/3125 + >>> _roots_quartic_euler(p, q, r, S(0))[0] + -sqrt(32*sqrt(5)/125 + 16/5) + 4*sqrt(5)/5 + """ + # solve the resolvent equation + x = Dummy('x') + eq = 64*x**3 + 32*p*x**2 + (4*p**2 - 16*r)*x - q**2 + xsols = list(roots(Poly(eq, x), cubics=False).keys()) + xsols = [sol for sol in xsols if sol.is_rational and sol.is_nonzero] + if not xsols: + return None + R = max(xsols) + c1 = sqrt(R) + B = -q*c1/(4*R) + A = -R - p/2 + c2 = sqrt(A + B) + c3 = sqrt(A - B) + return [c1 - c2 - a, -c1 - c3 - a, -c1 + c3 - a, c1 + c2 - a] + + +def roots_quartic(f): + r""" + Returns a list of roots of a quartic polynomial. + + There are many references for solving quartic expressions available [1-5]. + This reviewer has found that many of them require one to select from among + 2 or more possible sets of solutions and that some solutions work when one + is searching for real roots but do not work when searching for complex roots + (though this is not always stated clearly). The following routine has been + tested and found to be correct for 0, 2 or 4 complex roots. + + The quasisymmetric case solution [6] looks for quartics that have the form + `x**4 + A*x**3 + B*x**2 + C*x + D = 0` where `(C/A)**2 = D`. + + Although no general solution that is always applicable for all + coefficients is known to this reviewer, certain conditions are tested + to determine the simplest 4 expressions that can be returned: + + 1) `f = c + a*(a**2/8 - b/2) == 0` + 2) `g = d - a*(a*(3*a**2/256 - b/16) + c/4) = 0` + 3) if `f != 0` and `g != 0` and `p = -d + a*c/4 - b**2/12` then + a) `p == 0` + b) `p != 0` + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.polys.polyroots import roots_quartic + + >>> r = roots_quartic(Poly('x**4-6*x**3+17*x**2-26*x+20')) + + >>> # 4 complex roots: 1+-I*sqrt(3), 2+-I + >>> sorted(str(tmp.evalf(n=2)) for tmp in r) + ['1.0 + 1.7*I', '1.0 - 1.7*I', '2.0 + 1.0*I', '2.0 - 1.0*I'] + + References + ========== + + 1. http://mathforum.org/dr.math/faq/faq.cubic.equations.html + 2. https://en.wikipedia.org/wiki/Quartic_function#Summary_of_Ferrari.27s_method + 3. https://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html + 4. https://people.bath.ac.uk/masjhd/JHD-CA.pdf + 5. http://www.albmath.org/files/Math_5713.pdf + 6. https://web.archive.org/web/20171002081448/http://www.statemaster.com/encyclopedia/Quartic-equation + 7. https://eqworld.ipmnet.ru/en/solutions/ae/ae0108.pdf + """ + _, a, b, c, d = f.monic().all_coeffs() + + if not d: + return [S.Zero] + roots([1, a, b, c], multiple=True) + elif (c/a)**2 == d: + x, m = f.gen, c/a + + g = Poly(x**2 + a*x + b - 2*m, x) + + z1, z2 = roots_quadratic(g) + + h1 = Poly(x**2 - z1*x + m, x) + h2 = Poly(x**2 - z2*x + m, x) + + r1 = roots_quadratic(h1) + r2 = roots_quadratic(h2) + + return r1 + r2 + else: + a2 = a**2 + e = b - 3*a2/8 + f = _mexpand(c + a*(a2/8 - b/2)) + aon4 = a/4 + g = _mexpand(d - aon4*(a*(3*a2/64 - b/4) + c)) + + if f.is_zero: + y1, y2 = [sqrt(tmp) for tmp in + roots([1, e, g], multiple=True)] + return [tmp - aon4 for tmp in [-y1, -y2, y1, y2]] + if g.is_zero: + y = [S.Zero] + roots([1, 0, e, f], multiple=True) + return [tmp - aon4 for tmp in y] + else: + # Descartes-Euler method, see [7] + sols = _roots_quartic_euler(e, f, g, aon4) + if sols: + return sols + # Ferrari method, see [1, 2] + p = -e**2/12 - g + q = -e**3/108 + e*g/3 - f**2/8 + TH = Rational(1, 3) + + def _ans(y): + w = sqrt(e + 2*y) + arg1 = 3*e + 2*y + arg2 = 2*f/w + ans = [] + for s in [-1, 1]: + root = sqrt(-(arg1 + s*arg2)) + for t in [-1, 1]: + ans.append((s*w - t*root)/2 - aon4) + return ans + + # whether a Piecewise is returned or not + # depends on knowing p, so try to put + # in a simple form + p = _mexpand(p) + + + # p == 0 case + y1 = e*Rational(-5, 6) - q**TH + if p.is_zero: + return _ans(y1) + + # if p != 0 then u below is not 0 + root = sqrt(q**2/4 + p**3/27) + r = -q/2 + root # or -q/2 - root + u = r**TH # primary root of solve(x**3 - r, x) + y2 = e*Rational(-5, 6) + u - p/u/3 + if fuzzy_not(p.is_zero): + return _ans(y2) + + # sort it out once they know the values of the coefficients + return [Piecewise((a1, Eq(p, 0)), (a2, True)) + for a1, a2 in zip(_ans(y1), _ans(y2))] + + +def roots_binomial(f): + """Returns a list of roots of a binomial polynomial. If the domain is ZZ + then the roots will be sorted with negatives coming before positives. + The ordering will be the same for any numerical coefficients as long as + the assumptions tested are correct, otherwise the ordering will not be + sorted (but will be canonical). + """ + n = f.degree() + + a, b = f.nth(n), f.nth(0) + base = -cancel(b/a) + alpha = root(base, n) + + if alpha.is_number: + alpha = alpha.expand(complex=True) + + # define some parameters that will allow us to order the roots. + # If the domain is ZZ this is guaranteed to return roots sorted + # with reals before non-real roots and non-real sorted according + # to real part and imaginary part, e.g. -1, 1, -1 + I, 2 - I + neg = base.is_negative + even = n % 2 == 0 + if neg: + if even == True and (base + 1).is_positive: + big = True + else: + big = False + + # get the indices in the right order so the computed + # roots will be sorted when the domain is ZZ + ks = [] + imax = n//2 + if even: + ks.append(imax) + imax -= 1 + if not neg: + ks.append(0) + for i in range(imax, 0, -1): + if neg: + ks.extend([i, -i]) + else: + ks.extend([-i, i]) + if neg: + ks.append(0) + if big: + for i in range(0, len(ks), 2): + pair = ks[i: i + 2] + pair = list(reversed(pair)) + + # compute the roots + roots, d = [], 2*I*pi/n + for k in ks: + zeta = exp(k*d).expand(complex=True) + roots.append((alpha*zeta).expand(power_base=False)) + + return roots + + +def _inv_totient_estimate(m): + """ + Find ``(L, U)`` such that ``L <= phi^-1(m) <= U``. + + Examples + ======== + + >>> from sympy.polys.polyroots import _inv_totient_estimate + + >>> _inv_totient_estimate(192) + (192, 840) + >>> _inv_totient_estimate(400) + (400, 1750) + + """ + primes = [ d + 1 for d in divisors(m) if isprime(d + 1) ] + + a, b = 1, 1 + + for p in primes: + a *= p + b *= p - 1 + + L = m + U = int(math.ceil(m*(float(a)/b))) + + P = p = 2 + primes = [] + + while P <= U: + p = nextprime(p) + primes.append(p) + P *= p + + P //= p + b = 1 + + for p in primes[:-1]: + b *= p - 1 + + U = int(math.ceil(m*(float(P)/b))) + + return L, U + + +def roots_cyclotomic(f, factor=False): + """Compute roots of cyclotomic polynomials. """ + L, U = _inv_totient_estimate(f.degree()) + + for n in range(L, U + 1): + g = cyclotomic_poly(n, f.gen, polys=True) + + if f.expr == g.expr: + break + else: # pragma: no cover + raise RuntimeError("failed to find index of a cyclotomic polynomial") + + roots = [] + + if not factor: + # get the indices in the right order so the computed + # roots will be sorted + h = n//2 + ks = [i for i in range(1, n + 1) if igcd(i, n) == 1] + ks.sort(key=lambda x: (x, -1) if x <= h else (abs(x - n), 1)) + d = 2*I*pi/n + for k in reversed(ks): + roots.append(exp(k*d).expand(complex=True)) + else: + g = Poly(f, extension=root(-1, n)) + + for h, _ in ordered(g.factor_list()[1]): + roots.append(-h.TC()) + + return roots + + +def roots_quintic(f): + """ + Calculate exact roots of a solvable irreducible quintic with rational coefficients. + Return an empty list if the quintic is reducible or not solvable. + """ + result = [] + + coeff_5, coeff_4, p_, q_, r_, s_ = f.all_coeffs() + + if not all(coeff.is_Rational for coeff in (coeff_5, coeff_4, p_, q_, r_, s_)): + return result + + if coeff_5 != 1: + f = Poly(f / coeff_5) + _, coeff_4, p_, q_, r_, s_ = f.all_coeffs() + + # Cancel coeff_4 to form x^5 + px^3 + qx^2 + rx + s + if coeff_4: + p = p_ - 2*coeff_4*coeff_4/5 + q = q_ - 3*coeff_4*p_/5 + 4*coeff_4**3/25 + r = r_ - 2*coeff_4*q_/5 + 3*coeff_4**2*p_/25 - 3*coeff_4**4/125 + s = s_ - coeff_4*r_/5 + coeff_4**2*q_/25 - coeff_4**3*p_/125 + 4*coeff_4**5/3125 + x = f.gen + f = Poly(x**5 + p*x**3 + q*x**2 + r*x + s) + else: + p, q, r, s = p_, q_, r_, s_ + + quintic = PolyQuintic(f) + + # Eqn standardized. Algo for solving starts here + if not f.is_irreducible: + return result + f20 = quintic.f20 + # Check if f20 has linear factors over domain Z + if f20.is_irreducible: + return result + # Now, we know that f is solvable + for _factor in f20.factor_list()[1]: + if _factor[0].is_linear: + theta = _factor[0].root(0) + break + d = discriminant(f) + delta = sqrt(d) + # zeta = a fifth root of unity + zeta1, zeta2, zeta3, zeta4 = quintic.zeta + T = quintic.T(theta, d) + tol = S(1e-10) + alpha = T[1] + T[2]*delta + alpha_bar = T[1] - T[2]*delta + beta = T[3] + T[4]*delta + beta_bar = T[3] - T[4]*delta + + disc = alpha**2 - 4*beta + disc_bar = alpha_bar**2 - 4*beta_bar + + l0 = quintic.l0(theta) + Stwo = S(2) + l1 = _quintic_simplify((-alpha + sqrt(disc)) / Stwo) + l4 = _quintic_simplify((-alpha - sqrt(disc)) / Stwo) + + l2 = _quintic_simplify((-alpha_bar + sqrt(disc_bar)) / Stwo) + l3 = _quintic_simplify((-alpha_bar - sqrt(disc_bar)) / Stwo) + + order = quintic.order(theta, d) + test = (order*delta.n()) - ( (l1.n() - l4.n())*(l2.n() - l3.n()) ) + # Comparing floats + if not comp(test, 0, tol): + l2, l3 = l3, l2 + + # Now we have correct order of l's + R1 = l0 + l1*zeta1 + l2*zeta2 + l3*zeta3 + l4*zeta4 + R2 = l0 + l3*zeta1 + l1*zeta2 + l4*zeta3 + l2*zeta4 + R3 = l0 + l2*zeta1 + l4*zeta2 + l1*zeta3 + l3*zeta4 + R4 = l0 + l4*zeta1 + l3*zeta2 + l2*zeta3 + l1*zeta4 + + Res = [None, [None]*5, [None]*5, [None]*5, [None]*5] + Res_n = [None, [None]*5, [None]*5, [None]*5, [None]*5] + + # Simplifying improves performance a lot for exact expressions + R1 = _quintic_simplify(R1) + R2 = _quintic_simplify(R2) + R3 = _quintic_simplify(R3) + R4 = _quintic_simplify(R4) + + # hard-coded results for [factor(i) for i in _vsolve(x**5 - a - I*b, x)] + x0 = z**(S(1)/5) + x1 = sqrt(2) + x2 = sqrt(5) + x3 = sqrt(5 - x2) + x4 = I*x2 + x5 = x4 + I + x6 = I*x0/4 + x7 = x1*sqrt(x2 + 5) + sol = [x0, -x6*(x1*x3 - x5), x6*(x1*x3 + x5), -x6*(x4 + x7 - I), x6*(-x4 + x7 + I)] + + R1 = R1.as_real_imag() + R2 = R2.as_real_imag() + R3 = R3.as_real_imag() + R4 = R4.as_real_imag() + + for i, s in enumerate(sol): + Res[1][i] = _quintic_simplify(s.xreplace({z: R1[0] + I*R1[1]})) + Res[2][i] = _quintic_simplify(s.xreplace({z: R2[0] + I*R2[1]})) + Res[3][i] = _quintic_simplify(s.xreplace({z: R3[0] + I*R3[1]})) + Res[4][i] = _quintic_simplify(s.xreplace({z: R4[0] + I*R4[1]})) + + for i in range(1, 5): + for j in range(5): + Res_n[i][j] = Res[i][j].n() + Res[i][j] = _quintic_simplify(Res[i][j]) + r1 = Res[1][0] + r1_n = Res_n[1][0] + + for i in range(5): + if comp(im(r1_n*Res_n[4][i]), 0, tol): + r4 = Res[4][i] + break + + # Now we have various Res values. Each will be a list of five + # values. We have to pick one r value from those five for each Res + u, v = quintic.uv(theta, d) + testplus = (u + v*delta*sqrt(5)).n() + testminus = (u - v*delta*sqrt(5)).n() + + # Evaluated numbers suffixed with _n + # We will use evaluated numbers for calculation. Much faster. + r4_n = r4.n() + r2 = r3 = None + + for i in range(5): + r2temp_n = Res_n[2][i] + for j in range(5): + # Again storing away the exact number and using + # evaluated numbers in computations + r3temp_n = Res_n[3][j] + if (comp((r1_n*r2temp_n**2 + r4_n*r3temp_n**2 - testplus).n(), 0, tol) and + comp((r3temp_n*r1_n**2 + r2temp_n*r4_n**2 - testminus).n(), 0, tol)): + r2 = Res[2][i] + r3 = Res[3][j] + break + if r2 is not None: + break + else: + return [] # fall back to normal solve + + # Now, we have r's so we can get roots + x1 = (r1 + r2 + r3 + r4)/5 + x2 = (r1*zeta4 + r2*zeta3 + r3*zeta2 + r4*zeta1)/5 + x3 = (r1*zeta3 + r2*zeta1 + r3*zeta4 + r4*zeta2)/5 + x4 = (r1*zeta2 + r2*zeta4 + r3*zeta1 + r4*zeta3)/5 + x5 = (r1*zeta1 + r2*zeta2 + r3*zeta3 + r4*zeta4)/5 + result = [x1, x2, x3, x4, x5] + + # Now check if solutions are distinct + + saw = set() + for r in result: + r = r.n(2) + if r in saw: + # Roots were identical. Abort, return [] + # and fall back to usual solve + return [] + saw.add(r) + + # Restore to original equation where coeff_4 is nonzero + if coeff_4: + result = [x - coeff_4 / 5 for x in result] + return result + + +def _quintic_simplify(expr): + from sympy.simplify.simplify import powsimp + expr = powsimp(expr) + expr = cancel(expr) + return together(expr) + + +def _integer_basis(poly): + """Compute coefficient basis for a polynomial over integers. + + Returns the integer ``div`` such that substituting ``x = div*y`` + ``p(x) = m*q(y)`` where the coefficients of ``q`` are smaller + than those of ``p``. + + For example ``x**5 + 512*x + 1024 = 0`` + with ``div = 4`` becomes ``y**5 + 2*y + 1 = 0`` + + Returns the integer ``div`` or ``None`` if there is no possible scaling. + + Examples + ======== + + >>> from sympy.polys import Poly + >>> from sympy.abc import x + >>> from sympy.polys.polyroots import _integer_basis + >>> p = Poly(x**5 + 512*x + 1024, x, domain='ZZ') + >>> _integer_basis(p) + 4 + """ + monoms, coeffs = list(zip(*poly.terms())) + + monoms, = list(zip(*monoms)) + coeffs = list(map(abs, coeffs)) + + if coeffs[0] < coeffs[-1]: + coeffs = list(reversed(coeffs)) + n = monoms[0] + monoms = [n - i for i in reversed(monoms)] + else: + return None + + monoms = monoms[:-1] + coeffs = coeffs[:-1] + + # Special case for two-term polynominals + if len(monoms) == 1: + r = Pow(coeffs[0], S.One/monoms[0]) + if r.is_Integer: + return int(r) + else: + return None + + divs = reversed(divisors(gcd_list(coeffs))[1:]) + + try: + div = next(divs) + except StopIteration: + return None + + while True: + for monom, coeff in zip(monoms, coeffs): + if coeff % div**monom != 0: + try: + div = next(divs) + except StopIteration: + return None + else: + break + else: + return div + + +def preprocess_roots(poly): + """Try to get rid of symbolic coefficients from ``poly``. """ + coeff = S.One + + poly_func = poly.func + try: + _, poly = poly.clear_denoms(convert=True) + except DomainError: + return coeff, poly + + poly = poly.primitive()[1] + poly = poly.retract() + + # TODO: This is fragile. Figure out how to make this independent of construct_domain(). + if poly.get_domain().is_Poly and all(c.is_term for c in poly.rep.coeffs()): + poly = poly.inject() + + strips = list(zip(*poly.monoms())) + gens = list(poly.gens[1:]) + + base, strips = strips[0], strips[1:] + + for gen, strip in zip(list(gens), strips): + reverse = False + + if strip[0] < strip[-1]: + strip = reversed(strip) + reverse = True + + ratio = None + + for a, b in zip(base, strip): + if not a and not b: + continue + elif not a or not b: + break + elif b % a != 0: + break + else: + _ratio = b // a + + if ratio is None: + ratio = _ratio + elif ratio != _ratio: + break + else: + if reverse: + ratio = -ratio + + poly = poly.eval(gen, 1) + coeff *= gen**(-ratio) + gens.remove(gen) + + if gens: + poly = poly.eject(*gens) + + if poly.is_univariate and poly.get_domain().is_ZZ: + basis = _integer_basis(poly) + + if basis is not None: + n = poly.degree() + + def func(k, coeff): + return coeff//basis**(n - k[0]) + + poly = poly.termwise(func) + coeff *= basis + + if not isinstance(poly, poly_func): + poly = poly_func(poly) + return coeff, poly + + +@public +def roots(f, *gens, + auto=True, + cubics=True, + trig=False, + quartics=True, + quintics=False, + multiple=False, + filter=None, + predicate=None, + strict=False, + **flags): + """ + Computes symbolic roots of a univariate polynomial. + + Given a univariate polynomial f with symbolic coefficients (or + a list of the polynomial's coefficients), returns a dictionary + with its roots and their multiplicities. + + Only roots expressible via radicals will be returned. To get + a complete set of roots use RootOf class or numerical methods + instead. By default cubic and quartic formulas are used in + the algorithm. To disable them because of unreadable output + set ``cubics=False`` or ``quartics=False`` respectively. If cubic + roots are real but are expressed in terms of complex numbers + (casus irreducibilis [1]) the ``trig`` flag can be set to True to + have the solutions returned in terms of cosine and inverse cosine + functions. + + To get roots from a specific domain set the ``filter`` flag with + one of the following specifiers: Z, Q, R, I, C. By default all + roots are returned (this is equivalent to setting ``filter='C'``). + + By default a dictionary is returned giving a compact result in + case of multiple roots. However to get a list containing all + those roots set the ``multiple`` flag to True; the list will + have identical roots appearing next to each other in the result. + (For a given Poly, the all_roots method will give the roots in + sorted numerical order.) + + If the ``strict`` flag is True, ``UnsolvableFactorError`` will be + raised if the roots found are known to be incomplete (because + some roots are not expressible in radicals). + + Examples + ======== + + >>> from sympy import Poly, roots, degree + >>> from sympy.abc import x, y + + >>> roots(x**2 - 1, x) + {-1: 1, 1: 1} + + >>> p = Poly(x**2-1, x) + >>> roots(p) + {-1: 1, 1: 1} + + >>> p = Poly(x**2-y, x, y) + + >>> roots(Poly(p, x)) + {-sqrt(y): 1, sqrt(y): 1} + + >>> roots(x**2 - y, x) + {-sqrt(y): 1, sqrt(y): 1} + + >>> roots([1, 0, -1]) + {-1: 1, 1: 1} + + ``roots`` will only return roots expressible in radicals. If + the given polynomial has some or all of its roots inexpressible in + radicals, the result of ``roots`` will be incomplete or empty + respectively. + + Example where result is incomplete: + + >>> roots((x-1)*(x**5-x+1), x) + {1: 1} + + In this case, the polynomial has an unsolvable quintic factor + whose roots cannot be expressed by radicals. The polynomial has a + rational root (due to the factor `(x-1)`), which is returned since + ``roots`` always finds all rational roots. + + Example where result is empty: + + >>> roots(x**7-3*x**2+1, x) + {} + + Here, the polynomial has no roots expressible in radicals, so + ``roots`` returns an empty dictionary. + + The result produced by ``roots`` is complete if and only if the + sum of the multiplicity of each root is equal to the degree of + the polynomial. If strict=True, UnsolvableFactorError will be + raised if the result is incomplete. + + The result can be be checked for completeness as follows: + + >>> f = x**3-2*x**2+1 + >>> sum(roots(f, x).values()) == degree(f, x) + True + >>> f = (x-1)*(x**5-x+1) + >>> sum(roots(f, x).values()) == degree(f, x) + False + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Cubic_equation#Trigonometric_and_hyperbolic_solutions + + """ + from sympy.polys.polytools import to_rational_coeffs + flags = dict(flags) + + if isinstance(f, list): + if gens: + raise ValueError('redundant generators given') + + x = Dummy('x') + + poly, i = {}, len(f) - 1 + + for coeff in f: + poly[i], i = sympify(coeff), i - 1 + + f = Poly(poly, x, field=True) + else: + try: + F = Poly(f, *gens, **flags) + if not isinstance(f, Poly) and not F.gen.is_Symbol: + raise PolynomialError("generator must be a Symbol") + f = F + except GeneratorsNeeded: + if multiple: + return [] + else: + return {} + else: + n = f.degree() + if f.length() == 2 and n > 2: + # check for foo**n in constant if dep is c*gen**m + con, dep = f.as_expr().as_independent(*f.gens) + fcon = -(-con).factor() + if fcon != con: + con = fcon + bases = [] + for i in Mul.make_args(con): + if i.is_Pow: + b, e = i.as_base_exp() + if e.is_Integer and b.is_Add: + bases.append((b, Dummy(positive=True))) + if bases: + rv = roots(Poly((dep + con).xreplace(dict(bases)), + *f.gens), *F.gens, + auto=auto, + cubics=cubics, + trig=trig, + quartics=quartics, + quintics=quintics, + multiple=multiple, + filter=filter, + predicate=predicate, + **flags) + return {factor_terms(k.xreplace( + {v: k for k, v in bases}) + ): v for k, v in rv.items()} + + if f.is_multivariate: + raise PolynomialError('multivariate polynomials are not supported') + + def _update_dict(result, zeros, currentroot, k): + if currentroot == S.Zero: + if S.Zero in zeros: + zeros[S.Zero] += k + else: + zeros[S.Zero] = k + if currentroot in result: + result[currentroot] += k + else: + result[currentroot] = k + + def _try_decompose(f): + """Find roots using functional decomposition. """ + factors, roots = f.decompose(), [] + + for currentroot in _try_heuristics(factors[0]): + roots.append(currentroot) + + for currentfactor in factors[1:]: + previous, roots = list(roots), [] + + for currentroot in previous: + g = currentfactor - Poly(currentroot, f.gen) + + for currentroot in _try_heuristics(g): + roots.append(currentroot) + + return roots + + def _try_heuristics(f): + """Find roots using formulas and some tricks. """ + if f.is_ground: + return [] + if f.is_monomial: + return [S.Zero]*f.degree() + + if f.length() == 2: + if f.degree() == 1: + return list(map(cancel, roots_linear(f))) + else: + return roots_binomial(f) + + result = [] + + for i in [-1, 1]: + if not f.eval(i): + f = f.quo(Poly(f.gen - i, f.gen)) + result.append(i) + break + + n = f.degree() + + if n == 1: + result += list(map(cancel, roots_linear(f))) + elif n == 2: + result += list(map(cancel, roots_quadratic(f))) + elif f.is_cyclotomic: + result += roots_cyclotomic(f) + elif n == 3 and cubics: + result += roots_cubic(f, trig=trig) + elif n == 4 and quartics: + result += roots_quartic(f) + elif n == 5 and quintics: + result += roots_quintic(f) + + return result + + # Convert the generators to symbols + dumgens = symbols('x:%d' % len(f.gens), cls=Dummy) + f = f.per(f.rep, dumgens) + + (k,), f = f.terms_gcd() + + if not k: + zeros = {} + else: + zeros = {S.Zero: k} + + coeff, f = preprocess_roots(f) + + if auto and f.get_domain().is_Ring: + f = f.to_field() + + # Use EX instead of ZZ_I or QQ_I + if f.get_domain().is_QQ_I: + f = f.per(f.rep.convert(EX)) + + rescale_x = None + translate_x = None + + result = {} + + if not f.is_ground: + dom = f.get_domain() + if not dom.is_Exact and dom.is_Numerical: + for r in f.nroots(): + _update_dict(result, zeros, r, 1) + elif f.degree() == 1: + _update_dict(result, zeros, roots_linear(f)[0], 1) + elif f.length() == 2: + roots_fun = roots_quadratic if f.degree() == 2 else roots_binomial + for r in roots_fun(f): + _update_dict(result, zeros, r, 1) + else: + _, factors = Poly(f.as_expr()).factor_list() + if len(factors) == 1 and f.degree() == 2: + for r in roots_quadratic(f): + _update_dict(result, zeros, r, 1) + else: + if len(factors) == 1 and factors[0][1] == 1: + if f.get_domain().is_EX: + res = to_rational_coeffs(f) + if res: + if res[0] is None: + translate_x, f = res[2:] + else: + rescale_x, f = res[1], res[-1] + result = roots(f) + if not result: + for currentroot in _try_decompose(f): + _update_dict(result, zeros, currentroot, 1) + else: + for r in _try_heuristics(f): + _update_dict(result, zeros, r, 1) + else: + for currentroot in _try_decompose(f): + _update_dict(result, zeros, currentroot, 1) + else: + for currentfactor, k in factors: + for r in _try_heuristics(Poly(currentfactor, f.gen, field=True)): + _update_dict(result, zeros, r, k) + + if coeff is not S.One: + _result, result, = result, {} + + for currentroot, k in _result.items(): + result[coeff*currentroot] = k + + if filter not in [None, 'C']: + handlers = { + 'Z': lambda r: r.is_Integer, + 'Q': lambda r: r.is_Rational, + 'R': lambda r: all(a.is_real for a in r.as_numer_denom()), + 'I': lambda r: r.is_imaginary, + } + + try: + query = handlers[filter] + except KeyError: + raise ValueError("Invalid filter: %s" % filter) + + for zero in dict(result).keys(): + if not query(zero): + del result[zero] + + if predicate is not None: + for zero in dict(result).keys(): + if not predicate(zero): + del result[zero] + if rescale_x: + result1 = {} + for k, v in result.items(): + result1[k*rescale_x] = v + result = result1 + if translate_x: + result1 = {} + for k, v in result.items(): + result1[k + translate_x] = v + result = result1 + + # adding zero roots after non-trivial roots have been translated + result.update(zeros) + + if strict and sum(result.values()) < f.degree(): + raise UnsolvableFactorError(filldedent(''' + Strict mode: some factors cannot be solved in radicals, so + a complete list of solutions cannot be returned. Call + roots with strict=False to get solutions expressible in + radicals (if there are any). + ''')) + + if not multiple: + return result + else: + zeros = [] + + for zero in ordered(result): + zeros.extend([zero]*result[zero]) + + return zeros + + +def root_factors(f, *gens, filter=None, **args): + """ + Returns all factors of a univariate polynomial. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.polys.polyroots import root_factors + + >>> root_factors(x**2 - y, x) + [x - sqrt(y), x + sqrt(y)] + + """ + args = dict(args) + + F = Poly(f, *gens, **args) + + if not F.is_Poly: + return [f] + + if F.is_multivariate: + raise ValueError('multivariate polynomials are not supported') + + x = F.gens[0] + + zeros = roots(F, filter=filter) + + if not zeros: + factors = [F] + else: + factors, N = [], 0 + + for r, n in ordered(zeros.items()): + factors, N = factors + [Poly(x - r, x)]*n, N + n + + if N < F.degree(): + G = reduce(lambda p, q: p*q, factors) + factors.append(F.quo(G)) + + if not isinstance(f, Poly): + factors = [ f.as_expr() for f in factors ] + + return factors diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polytools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polytools.py new file mode 100644 index 0000000000000000000000000000000000000000..11b9dd3435f8dc68ea3b0578df9fccfb07dd0f4c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polytools.py @@ -0,0 +1,7960 @@ +"""User-friendly public interface to polynomial functions. """ + +from __future__ import annotations + +from functools import wraps, reduce +from operator import mul +from typing import Optional +from collections import Counter, defaultdict + +from sympy.core import ( + S, Expr, Add, Tuple +) +from sympy.core.basic import Basic +from sympy.core.decorators import _sympifyit +from sympy.core.exprtools import Factors, factor_nc, factor_terms +from sympy.core.evalf import ( + pure_complex, evalf, fastlog, _evalf_with_bounded_error, quad_to_mpmath) +from sympy.core.function import Derivative +from sympy.core.mul import Mul, _keep_coeff +from sympy.core.intfunc import ilcm +from sympy.core.numbers import I, Integer, equal_valued +from sympy.core.relational import Relational, Equality +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy, Symbol +from sympy.core.sympify import sympify, _sympify +from sympy.core.traversal import preorder_traversal, bottom_up +from sympy.logic.boolalg import BooleanAtom +from sympy.polys import polyoptions as options +from sympy.polys.constructor import construct_domain +from sympy.polys.domains import FF, QQ, ZZ +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.fglmtools import matrix_fglm +from sympy.polys.groebnertools import groebner as _groebner +from sympy.polys.monomials import Monomial +from sympy.polys.orderings import monomial_key +from sympy.polys.polyclasses import DMP, DMF, ANP +from sympy.polys.polyerrors import ( + OperationNotSupported, DomainError, + CoercionFailed, UnificationFailed, + GeneratorsNeeded, PolynomialError, + MultivariatePolynomialError, + ExactQuotientFailed, + PolificationFailed, + ComputationFailed, + GeneratorsError, +) +from sympy.polys.polyutils import ( + basic_from_dict, + _sort_gens, + _unify_gens, + _dict_reorder, + _dict_from_expr, + _parallel_dict_from_expr, +) +from sympy.polys.rationaltools import together +from sympy.polys.rootisolation import dup_isolate_real_roots_list +from sympy.utilities import group, public, filldedent +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import iterable, sift + +# Required to avoid errors +import sympy.polys + +import mpmath +from mpmath.libmp.libhyper import NoConvergence + + + +def _polifyit(func): + @wraps(func) + def wrapper(f, g): + g = _sympify(g) + if isinstance(g, Poly): + return func(f, g) + elif isinstance(g, Integer): + g = f.from_expr(g, *f.gens, domain=f.domain) + return func(f, g) + elif isinstance(g, Expr): + try: + g = f.from_expr(g, *f.gens) + except PolynomialError: + if g.is_Matrix: + return NotImplemented + expr_method = getattr(f.as_expr(), func.__name__) + result = expr_method(g) + if result is not NotImplemented: + sympy_deprecation_warning( + """ + Mixing Poly with non-polynomial expressions in binary + operations is deprecated. Either explicitly convert + the non-Poly operand to a Poly with as_poly() or + convert the Poly to an Expr with as_expr(). + """, + deprecated_since_version="1.6", + active_deprecations_target="deprecated-poly-nonpoly-binary-operations", + ) + return result + else: + return func(f, g) + else: + return NotImplemented + return wrapper + + + +@public +class Poly(Basic): + """ + Generic class for representing and operating on polynomial expressions. + + See :ref:`polys-docs` for general documentation. + + Poly is a subclass of Basic rather than Expr but instances can be + converted to Expr with the :py:meth:`~.Poly.as_expr` method. + + .. deprecated:: 1.6 + + Combining Poly with non-Poly objects in binary operations is + deprecated. Explicitly convert both objects to either Poly or Expr + first. See :ref:`deprecated-poly-nonpoly-binary-operations`. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + Create a univariate polynomial: + + >>> Poly(x*(x**2 + x - 1)**2) + Poly(x**5 + 2*x**4 - x**3 - 2*x**2 + x, x, domain='ZZ') + + Create a univariate polynomial with specific domain: + + >>> from sympy import sqrt + >>> Poly(x**2 + 2*x + sqrt(3), domain='R') + Poly(1.0*x**2 + 2.0*x + 1.73205080756888, x, domain='RR') + + Create a multivariate polynomial: + + >>> Poly(y*x**2 + x*y + 1) + Poly(x**2*y + x*y + 1, x, y, domain='ZZ') + + Create a univariate polynomial, where y is a constant: + + >>> Poly(y*x**2 + x*y + 1,x) + Poly(y*x**2 + y*x + 1, x, domain='ZZ[y]') + + You can evaluate the above polynomial as a function of y: + + >>> Poly(y*x**2 + x*y + 1,x).eval(2) + 6*y + 1 + + See Also + ======== + + sympy.core.expr.Expr + + """ + + __slots__ = ('rep', 'gens') + + is_commutative = True + is_Poly = True + _op_priority = 10.001 + + rep: DMP + gens: tuple[Expr, ...] + + def __new__(cls, rep, *gens, **args) -> Poly: + """Create a new polynomial instance out of something useful. """ + opt = options.build_options(gens, args) + + if 'order' in opt: + raise NotImplementedError("'order' keyword is not implemented yet") + + if isinstance(rep, (DMP, DMF, ANP, DomainElement)): + return cls._from_domain_element(rep, opt) + elif iterable(rep, exclude=str): + if isinstance(rep, dict): + return cls._from_dict(rep, opt) + else: + return cls._from_list(list(rep), opt) + else: + rep = sympify(rep, evaluate=type(rep) is not str) # type: ignore + + if rep.is_Poly: + return cls._from_poly(rep, opt) + else: + return cls._from_expr(rep, opt) + + # Poly does not pass its args to Basic.__new__ to be stored in _args so we + # have to emulate them here with an args property that derives from rep + # and gens which are instance attributes. This also means we need to + # define _hashable_content. The _hashable_content is rep and gens but args + # uses expr instead of rep (expr is the Basic version of rep). Passing + # expr in args means that Basic methods like subs should work. Using rep + # otherwise means that Poly can remain more efficient than Basic by + # avoiding creating a Basic instance just to be hashable. + + @classmethod + def new(cls, rep, *gens): + """Construct :class:`Poly` instance from raw representation. """ + if not isinstance(rep, DMP): + raise PolynomialError( + "invalid polynomial representation: %s" % rep) + elif rep.lev != len(gens) - 1: + raise PolynomialError("invalid arguments: %s, %s" % (rep, gens)) + + obj = Basic.__new__(cls) + obj.rep = rep + obj.gens = gens + + return obj + + @property + def expr(self): + return basic_from_dict(self.rep.to_sympy_dict(), *self.gens) + + @property + def args(self): + return (self.expr,) + self.gens + + def _hashable_content(self): + return (self.rep,) + self.gens + + @classmethod + def from_dict(cls, rep, *gens, **args): + """Construct a polynomial from a ``dict``. """ + opt = options.build_options(gens, args) + return cls._from_dict(rep, opt) + + @classmethod + def from_list(cls, rep, *gens, **args): + """Construct a polynomial from a ``list``. """ + opt = options.build_options(gens, args) + return cls._from_list(rep, opt) + + @classmethod + def from_poly(cls, rep, *gens, **args): + """Construct a polynomial from a polynomial. """ + opt = options.build_options(gens, args) + return cls._from_poly(rep, opt) + + @classmethod + def from_expr(cls, rep, *gens, **args): + """Construct a polynomial from an expression. """ + opt = options.build_options(gens, args) + return cls._from_expr(rep, opt) + + @classmethod + def _from_dict(cls, rep, opt): + """Construct a polynomial from a ``dict``. """ + gens = opt.gens + + if not gens: + raise GeneratorsNeeded( + "Cannot initialize from 'dict' without generators") + + level = len(gens) - 1 + domain = opt.domain + + if domain is None: + domain, rep = construct_domain(rep, opt=opt) + else: + for monom, coeff in rep.items(): + rep[monom] = domain.convert(coeff) + + return cls.new(DMP.from_dict(rep, level, domain), *gens) + + @classmethod + def _from_list(cls, rep, opt): + """Construct a polynomial from a ``list``. """ + gens = opt.gens + + if not gens: + raise GeneratorsNeeded( + "Cannot initialize from 'list' without generators") + elif len(gens) != 1: + raise MultivariatePolynomialError( + "'list' representation not supported") + + level = len(gens) - 1 + domain = opt.domain + + if domain is None: + domain, rep = construct_domain(rep, opt=opt) + else: + rep = list(map(domain.convert, rep)) + + return cls.new(DMP.from_list(rep, level, domain), *gens) + + @classmethod + def _from_poly(cls, rep, opt): + """Construct a polynomial from a polynomial. """ + if cls != rep.__class__: + rep = cls.new(rep.rep, *rep.gens) + + gens = opt.gens + field = opt.field + domain = opt.domain + + if gens and rep.gens != gens: + if set(rep.gens) != set(gens): + return cls._from_expr(rep.as_expr(), opt) + else: + rep = rep.reorder(*gens) + + if 'domain' in opt and domain: + rep = rep.set_domain(domain) + elif field is True: + rep = rep.to_field() + + return rep + + @classmethod + def _from_expr(cls, rep, opt): + """Construct a polynomial from an expression. """ + rep, opt = _dict_from_expr(rep, opt) + return cls._from_dict(rep, opt) + + @classmethod + def _from_domain_element(cls, rep, opt): + gens = opt.gens + domain = opt.domain + + level = len(gens) - 1 + rep = [domain.convert(rep)] + + return cls.new(DMP.from_list(rep, level, domain), *gens) + + def __hash__(self): + return super().__hash__() + + @property + def free_symbols(self): + """ + Free symbols of a polynomial expression. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y, z + + >>> Poly(x**2 + 1).free_symbols + {x} + >>> Poly(x**2 + y).free_symbols + {x, y} + >>> Poly(x**2 + y, x).free_symbols + {x, y} + >>> Poly(x**2 + y, x, z).free_symbols + {x, y} + + """ + symbols = set() + gens = self.gens + for i in range(len(gens)): + for monom in self.monoms(): + if monom[i]: + symbols |= gens[i].free_symbols + break + + return symbols | self.free_symbols_in_domain + + @property + def free_symbols_in_domain(self): + """ + Free symbols of the domain of ``self``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + 1).free_symbols_in_domain + set() + >>> Poly(x**2 + y).free_symbols_in_domain + set() + >>> Poly(x**2 + y, x).free_symbols_in_domain + {y} + + """ + domain, symbols = self.rep.dom, set() + + if domain.is_Composite: + for gen in domain.symbols: + symbols |= gen.free_symbols + elif domain.is_EX: + for coeff in self.coeffs(): + symbols |= coeff.free_symbols + + return symbols + + @property + def gen(self): + """ + Return the principal generator. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).gen + x + + """ + return self.gens[0] + + @property + def domain(self): + """Get the ground domain of a :py:class:`~.Poly` + + Returns + ======= + + :py:class:`~.Domain`: + Ground domain of the :py:class:`~.Poly`. + + Examples + ======== + + >>> from sympy import Poly, Symbol + >>> x = Symbol('x') + >>> p = Poly(x**2 + x) + >>> p + Poly(x**2 + x, x, domain='ZZ') + >>> p.domain + ZZ + """ + return self.get_domain() + + @property + def zero(self): + """Return zero polynomial with ``self``'s properties. """ + return self.new(self.rep.zero(self.rep.lev, self.rep.dom), *self.gens) + + @property + def one(self): + """Return one polynomial with ``self``'s properties. """ + return self.new(self.rep.one(self.rep.lev, self.rep.dom), *self.gens) + + def unify(f, g): + """ + Make ``f`` and ``g`` belong to the same domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f, g = Poly(x/2 + 1), Poly(2*x + 1) + + >>> f + Poly(1/2*x + 1, x, domain='QQ') + >>> g + Poly(2*x + 1, x, domain='ZZ') + + >>> F, G = f.unify(g) + + >>> F + Poly(1/2*x + 1, x, domain='QQ') + >>> G + Poly(2*x + 1, x, domain='QQ') + + """ + _, per, F, G = f._unify(g) + return per(F), per(G) + + def _unify(f, g): + g = sympify(g) + + if not g.is_Poly: + try: + g_coeff = f.rep.dom.from_sympy(g) + except CoercionFailed: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + else: + return f.rep.dom, f.per, f.rep, f.rep.ground_new(g_coeff) + + if isinstance(f.rep, DMP) and isinstance(g.rep, DMP): + gens = _unify_gens(f.gens, g.gens) + + dom, lev = f.rep.dom.unify(g.rep.dom, gens), len(gens) - 1 + + if f.gens != gens: + f_monoms, f_coeffs = _dict_reorder( + f.rep.to_dict(), f.gens, gens) + + if f.rep.dom != dom: + f_coeffs = [dom.convert(c, f.rep.dom) for c in f_coeffs] + + F = DMP.from_dict(dict(list(zip(f_monoms, f_coeffs))), lev, dom) + else: + F = f.rep.convert(dom) + + if g.gens != gens: + g_monoms, g_coeffs = _dict_reorder( + g.rep.to_dict(), g.gens, gens) + + if g.rep.dom != dom: + g_coeffs = [dom.convert(c, g.rep.dom) for c in g_coeffs] + + G = DMP.from_dict(dict(list(zip(g_monoms, g_coeffs))), lev, dom) + else: + G = g.rep.convert(dom) + else: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + cls = f.__class__ + + def per(rep, dom=dom, gens=gens, remove=None): + if remove is not None: + gens = gens[:remove] + gens[remove + 1:] + + if not gens: + return dom.to_sympy(rep) + + return cls.new(rep, *gens) + + return dom, per, F, G + + def per(f, rep, gens=None, remove=None): + """ + Create a Poly out of the given representation. + + Examples + ======== + + >>> from sympy import Poly, ZZ + >>> from sympy.abc import x, y + + >>> from sympy.polys.polyclasses import DMP + + >>> a = Poly(x**2 + 1) + + >>> a.per(DMP([ZZ(1), ZZ(1)], ZZ), gens=[y]) + Poly(y + 1, y, domain='ZZ') + + """ + if gens is None: + gens = f.gens + + if remove is not None: + gens = gens[:remove] + gens[remove + 1:] + + if not gens: + return f.rep.dom.to_sympy(rep) + + return f.__class__.new(rep, *gens) + + def set_domain(f, domain): + """Set the ground domain of ``f``. """ + opt = options.build_options(f.gens, {'domain': domain}) + return f.per(f.rep.convert(opt.domain)) + + def get_domain(f): + """Get the ground domain of ``f``. """ + return f.rep.dom + + def set_modulus(f, modulus): + """ + Set the modulus of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(5*x**2 + 2*x - 1, x).set_modulus(2) + Poly(x**2 + 1, x, modulus=2) + + """ + modulus = options.Modulus.preprocess(modulus) + return f.set_domain(FF(modulus)) + + def get_modulus(f): + """ + Get the modulus of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, modulus=2).get_modulus() + 2 + + """ + domain = f.get_domain() + + if domain.is_FiniteField: + return Integer(domain.characteristic()) + else: + raise PolynomialError("not a polynomial over a Galois field") + + def _eval_subs(f, old, new): + """Internal implementation of :func:`subs`. """ + if old in f.gens: + if new.is_number: + return f.eval(old, new) + else: + try: + return f.replace(old, new) + except PolynomialError: + pass + + return f.as_expr().subs(old, new) + + def exclude(f): + """ + Remove unnecessary generators from ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import a, b, c, d, x + + >>> Poly(a + x, a, b, c, d, x).exclude() + Poly(a + x, a, x, domain='ZZ') + + """ + J, new = f.rep.exclude() + gens = [gen for j, gen in enumerate(f.gens) if j not in J] + + return f.per(new, gens=gens) + + def replace(f, x, y=None, **_ignore): + # XXX this does not match Basic's signature + """ + Replace ``x`` with ``y`` in generators list. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + 1, x).replace(x, y) + Poly(y**2 + 1, y, domain='ZZ') + + """ + if y is None: + if f.is_univariate: + x, y = f.gen, x + else: + raise PolynomialError( + "syntax supported only in univariate case") + + if x == y or x not in f.gens: + return f + + if x in f.gens and y not in f.gens: + dom = f.get_domain() + + if not dom.is_Composite or y not in dom.symbols: + gens = list(f.gens) + gens[gens.index(x)] = y + return f.per(f.rep, gens=gens) + + raise PolynomialError("Cannot replace %s with %s in %s" % (x, y, f)) + + def match(f, *args, **kwargs): + """Match expression from Poly. See Basic.match()""" + return f.as_expr().match(*args, **kwargs) + + def reorder(f, *gens, **args): + """ + Efficiently apply new order of generators. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + x*y**2, x, y).reorder(y, x) + Poly(y**2*x + x**2, y, x, domain='ZZ') + + """ + opt = options.Options((), args) + + if not gens: + gens = _sort_gens(f.gens, opt=opt) + elif set(f.gens) != set(gens): + raise PolynomialError( + "generators list can differ only up to order of elements") + + rep = dict(list(zip(*_dict_reorder(f.rep.to_dict(), f.gens, gens)))) + + return f.per(DMP.from_dict(rep, len(gens) - 1, f.rep.dom), gens=gens) + + def ltrim(f, gen): + """ + Remove dummy generators from ``f`` that are to the left of + specified ``gen`` in the generators as ordered. When ``gen`` + is an integer, it refers to the generator located at that + position within the tuple of generators of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y, z + + >>> Poly(y**2 + y*z**2, x, y, z).ltrim(y) + Poly(y**2 + y*z**2, y, z, domain='ZZ') + >>> Poly(z, x, y, z).ltrim(-1) + Poly(z, z, domain='ZZ') + + """ + rep = f.as_dict(native=True) + j = f._gen_to_level(gen) + + terms = {} + + for monom, coeff in rep.items(): + + if any(monom[:j]): + # some generator is used in the portion to be trimmed + raise PolynomialError("Cannot left trim %s" % f) + + terms[monom[j:]] = coeff + + gens = f.gens[j:] + + return f.new(DMP.from_dict(terms, len(gens) - 1, f.rep.dom), *gens) + + def has_only_gens(f, *gens): + """ + Return ``True`` if ``Poly(f, *gens)`` retains ground domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y, z + + >>> Poly(x*y + 1, x, y, z).has_only_gens(x, y) + True + >>> Poly(x*y + z, x, y, z).has_only_gens(x, y) + False + + """ + indices = set() + + for gen in gens: + try: + index = f.gens.index(gen) + except ValueError: + raise GeneratorsError( + "%s doesn't have %s as generator" % (f, gen)) + else: + indices.add(index) + + for monom in f.monoms(): + for i, elt in enumerate(monom): + if i not in indices and elt: + return False + + return True + + def to_ring(f): + """ + Make the ground domain a ring. + + Examples + ======== + + >>> from sympy import Poly, QQ + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, domain=QQ).to_ring() + Poly(x**2 + 1, x, domain='ZZ') + + """ + if hasattr(f.rep, 'to_ring'): + result = f.rep.to_ring() + else: # pragma: no cover + raise OperationNotSupported(f, 'to_ring') + + return f.per(result) + + def to_field(f): + """ + Make the ground domain a field. + + Examples + ======== + + >>> from sympy import Poly, ZZ + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x, domain=ZZ).to_field() + Poly(x**2 + 1, x, domain='QQ') + + """ + if hasattr(f.rep, 'to_field'): + result = f.rep.to_field() + else: # pragma: no cover + raise OperationNotSupported(f, 'to_field') + + return f.per(result) + + def to_exact(f): + """ + Make the ground domain exact. + + Examples + ======== + + >>> from sympy import Poly, RR + >>> from sympy.abc import x + + >>> Poly(x**2 + 1.0, x, domain=RR).to_exact() + Poly(x**2 + 1, x, domain='QQ') + + """ + if hasattr(f.rep, 'to_exact'): + result = f.rep.to_exact() + else: # pragma: no cover + raise OperationNotSupported(f, 'to_exact') + + return f.per(result) + + def retract(f, field=None): + """ + Recalculate the ground domain of a polynomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = Poly(x**2 + 1, x, domain='QQ[y]') + >>> f + Poly(x**2 + 1, x, domain='QQ[y]') + + >>> f.retract() + Poly(x**2 + 1, x, domain='ZZ') + >>> f.retract(field=True) + Poly(x**2 + 1, x, domain='QQ') + + """ + dom, rep = construct_domain(f.as_dict(zero=True), + field=field, composite=f.domain.is_Composite or None) + return f.from_dict(rep, f.gens, domain=dom) + + def slice(f, x, m, n=None): + """Take a continuous subsequence of terms of ``f``. """ + if n is None: + j, m, n = 0, x, m + else: + j = f._gen_to_level(x) + + m, n = int(m), int(n) + + if hasattr(f.rep, 'slice'): + result = f.rep.slice(m, n, j) + else: # pragma: no cover + raise OperationNotSupported(f, 'slice') + + return f.per(result) + + def coeffs(f, order=None): + """ + Returns all non-zero coefficients from ``f`` in lex order. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**3 + 2*x + 3, x).coeffs() + [1, 2, 3] + + See Also + ======== + all_coeffs + coeff_monomial + nth + + """ + return [f.rep.dom.to_sympy(c) for c in f.rep.coeffs(order=order)] + + def monoms(f, order=None): + """ + Returns all non-zero monomials from ``f`` in lex order. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + 2*x*y**2 + x*y + 3*y, x, y).monoms() + [(2, 0), (1, 2), (1, 1), (0, 1)] + + See Also + ======== + all_monoms + + """ + return f.rep.monoms(order=order) + + def terms(f, order=None): + """ + Returns all non-zero terms from ``f`` in lex order. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + 2*x*y**2 + x*y + 3*y, x, y).terms() + [((2, 0), 1), ((1, 2), 2), ((1, 1), 1), ((0, 1), 3)] + + See Also + ======== + all_terms + + """ + return [(m, f.rep.dom.to_sympy(c)) for m, c in f.rep.terms(order=order)] + + def all_coeffs(f): + """ + Returns all coefficients from a univariate polynomial ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**3 + 2*x - 1, x).all_coeffs() + [1, 0, 2, -1] + + """ + return [f.rep.dom.to_sympy(c) for c in f.rep.all_coeffs()] + + def all_monoms(f): + """ + Returns all monomials from a univariate polynomial ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**3 + 2*x - 1, x).all_monoms() + [(3,), (2,), (1,), (0,)] + + See Also + ======== + all_terms + + """ + return f.rep.all_monoms() + + def all_terms(f): + """ + Returns all terms from a univariate polynomial ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**3 + 2*x - 1, x).all_terms() + [((3,), 1), ((2,), 0), ((1,), 2), ((0,), -1)] + + """ + return [(m, f.rep.dom.to_sympy(c)) for m, c in f.rep.all_terms()] + + def termwise(f, func, *gens, **args): + """ + Apply a function to all terms of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> def func(k, coeff): + ... k = k[0] + ... return coeff//10**(2-k) + + >>> Poly(x**2 + 20*x + 400).termwise(func) + Poly(x**2 + 2*x + 4, x, domain='ZZ') + + """ + terms = {} + + for monom, coeff in f.terms(): + result = func(monom, coeff) + + if isinstance(result, tuple): + monom, coeff = result + else: + coeff = result + + if coeff: + if monom not in terms: + terms[monom] = coeff + else: + raise PolynomialError( + "%s monomial was generated twice" % monom) + + return f.from_dict(terms, *(gens or f.gens), **args) + + def length(f): + """ + Returns the number of non-zero terms in ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 2*x - 1).length() + 3 + + """ + return len(f.as_dict()) + + def as_dict(f, native=False, zero=False): + """ + Switch to a ``dict`` representation. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + 2*x*y**2 - y, x, y).as_dict() + {(0, 1): -1, (1, 2): 2, (2, 0): 1} + + """ + if native: + return f.rep.to_dict(zero=zero) + else: + return f.rep.to_sympy_dict(zero=zero) + + def as_list(f, native=False): + """Switch to a ``list`` representation. """ + if native: + return f.rep.to_list() + else: + return f.rep.to_sympy_list() + + def as_expr(f, *gens): + """ + Convert a Poly instance to an Expr instance. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> f = Poly(x**2 + 2*x*y**2 - y, x, y) + + >>> f.as_expr() + x**2 + 2*x*y**2 - y + >>> f.as_expr({x: 5}) + 10*y**2 - y + 25 + >>> f.as_expr(5, 6) + 379 + + """ + if not gens: + return f.expr + + if len(gens) == 1 and isinstance(gens[0], dict): + mapping = gens[0] + gens = list(f.gens) + + for gen, value in mapping.items(): + try: + index = gens.index(gen) + except ValueError: + raise GeneratorsError( + "%s doesn't have %s as generator" % (f, gen)) + else: + gens[index] = value + + return basic_from_dict(f.rep.to_sympy_dict(), *gens) + + def as_poly(self, *gens, **args): + """Converts ``self`` to a polynomial or returns ``None``. + + >>> from sympy import sin + >>> from sympy.abc import x, y + + >>> print((x**2 + x*y).as_poly()) + Poly(x**2 + x*y, x, y, domain='ZZ') + + >>> print((x**2 + x*y).as_poly(x, y)) + Poly(x**2 + x*y, x, y, domain='ZZ') + + >>> print((x**2 + sin(y)).as_poly(x, y)) + None + + """ + try: + poly = Poly(self, *gens, **args) + + if not poly.is_Poly: + return None + else: + return poly + except PolynomialError: + return None + + def lift(f): + """ + Convert algebraic coefficients to rationals. + + Examples + ======== + + >>> from sympy import Poly, I + >>> from sympy.abc import x + + >>> Poly(x**2 + I*x + 1, x, extension=I).lift() + Poly(x**4 + 3*x**2 + 1, x, domain='QQ') + + """ + if hasattr(f.rep, 'lift'): + result = f.rep.lift() + else: # pragma: no cover + raise OperationNotSupported(f, 'lift') + + return f.per(result) + + def deflate(f): + """ + Reduce degree of ``f`` by mapping ``x_i**m`` to ``y_i``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**6*y**2 + x**3 + 1, x, y).deflate() + ((3, 2), Poly(x**2*y + x + 1, x, y, domain='ZZ')) + + """ + if hasattr(f.rep, 'deflate'): + J, result = f.rep.deflate() + else: # pragma: no cover + raise OperationNotSupported(f, 'deflate') + + return J, f.per(result) + + def inject(f, front=False): + """ + Inject ground domain generators into ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> f = Poly(x**2*y + x*y**3 + x*y + 1, x) + + >>> f.inject() + Poly(x**2*y + x*y**3 + x*y + 1, x, y, domain='ZZ') + >>> f.inject(front=True) + Poly(y**3*x + y*x**2 + y*x + 1, y, x, domain='ZZ') + + """ + dom = f.rep.dom + + if dom.is_Numerical: + return f + elif not dom.is_Poly: + raise DomainError("Cannot inject generators over %s" % dom) + + if hasattr(f.rep, 'inject'): + result = f.rep.inject(front=front) + else: # pragma: no cover + raise OperationNotSupported(f, 'inject') + + if front: + gens = dom.symbols + f.gens + else: + gens = f.gens + dom.symbols + + return f.new(result, *gens) + + def eject(f, *gens): + """ + Eject selected generators into the ground domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> f = Poly(x**2*y + x*y**3 + x*y + 1, x, y) + + >>> f.eject(x) + Poly(x*y**3 + (x**2 + x)*y + 1, y, domain='ZZ[x]') + >>> f.eject(y) + Poly(y*x**2 + (y**3 + y)*x + 1, x, domain='ZZ[y]') + + """ + dom = f.rep.dom + + if not dom.is_Numerical: + raise DomainError("Cannot eject generators over %s" % dom) + + k = len(gens) + + if f.gens[:k] == gens: + _gens, front = f.gens[k:], True + elif f.gens[-k:] == gens: + _gens, front = f.gens[:-k], False + else: + raise NotImplementedError( + "can only eject front or back generators") + + dom = dom.inject(*gens) + + if hasattr(f.rep, 'eject'): + result = f.rep.eject(dom, front=front) + else: # pragma: no cover + raise OperationNotSupported(f, 'eject') + + return f.new(result, *_gens) + + def terms_gcd(f): + """ + Remove GCD of terms from the polynomial ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**6*y**2 + x**3*y, x, y).terms_gcd() + ((3, 1), Poly(x**3*y + 1, x, y, domain='ZZ')) + + """ + if hasattr(f.rep, 'terms_gcd'): + J, result = f.rep.terms_gcd() + else: # pragma: no cover + raise OperationNotSupported(f, 'terms_gcd') + + return J, f.per(result) + + def add_ground(f, coeff): + """ + Add an element of the ground domain to ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x + 1).add_ground(2) + Poly(x + 3, x, domain='ZZ') + + """ + if hasattr(f.rep, 'add_ground'): + result = f.rep.add_ground(coeff) + else: # pragma: no cover + raise OperationNotSupported(f, 'add_ground') + + return f.per(result) + + def sub_ground(f, coeff): + """ + Subtract an element of the ground domain from ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x + 1).sub_ground(2) + Poly(x - 1, x, domain='ZZ') + + """ + if hasattr(f.rep, 'sub_ground'): + result = f.rep.sub_ground(coeff) + else: # pragma: no cover + raise OperationNotSupported(f, 'sub_ground') + + return f.per(result) + + def mul_ground(f, coeff): + """ + Multiply ``f`` by a an element of the ground domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x + 1).mul_ground(2) + Poly(2*x + 2, x, domain='ZZ') + + """ + if hasattr(f.rep, 'mul_ground'): + result = f.rep.mul_ground(coeff) + else: # pragma: no cover + raise OperationNotSupported(f, 'mul_ground') + + return f.per(result) + + def quo_ground(f, coeff): + """ + Quotient of ``f`` by a an element of the ground domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(2*x + 4).quo_ground(2) + Poly(x + 2, x, domain='ZZ') + + >>> Poly(2*x + 3).quo_ground(2) + Poly(x + 1, x, domain='ZZ') + + """ + if hasattr(f.rep, 'quo_ground'): + result = f.rep.quo_ground(coeff) + else: # pragma: no cover + raise OperationNotSupported(f, 'quo_ground') + + return f.per(result) + + def exquo_ground(f, coeff): + """ + Exact quotient of ``f`` by a an element of the ground domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(2*x + 4).exquo_ground(2) + Poly(x + 2, x, domain='ZZ') + + >>> Poly(2*x + 3).exquo_ground(2) + Traceback (most recent call last): + ... + ExactQuotientFailed: 2 does not divide 3 in ZZ + + """ + if hasattr(f.rep, 'exquo_ground'): + result = f.rep.exquo_ground(coeff) + else: # pragma: no cover + raise OperationNotSupported(f, 'exquo_ground') + + return f.per(result) + + def abs(f): + """ + Make all coefficients in ``f`` positive. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 1, x).abs() + Poly(x**2 + 1, x, domain='ZZ') + + """ + if hasattr(f.rep, 'abs'): + result = f.rep.abs() + else: # pragma: no cover + raise OperationNotSupported(f, 'abs') + + return f.per(result) + + def neg(f): + """ + Negate all coefficients in ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 1, x).neg() + Poly(-x**2 + 1, x, domain='ZZ') + + >>> -Poly(x**2 - 1, x) + Poly(-x**2 + 1, x, domain='ZZ') + + """ + if hasattr(f.rep, 'neg'): + result = f.rep.neg() + else: # pragma: no cover + raise OperationNotSupported(f, 'neg') + + return f.per(result) + + def add(f, g): + """ + Add two polynomials ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).add(Poly(x - 2, x)) + Poly(x**2 + x - 1, x, domain='ZZ') + + >>> Poly(x**2 + 1, x) + Poly(x - 2, x) + Poly(x**2 + x - 1, x, domain='ZZ') + + """ + g = sympify(g) + + if not g.is_Poly: + return f.add_ground(g) + + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'add'): + result = F.add(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'add') + + return per(result) + + def sub(f, g): + """ + Subtract two polynomials ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).sub(Poly(x - 2, x)) + Poly(x**2 - x + 3, x, domain='ZZ') + + >>> Poly(x**2 + 1, x) - Poly(x - 2, x) + Poly(x**2 - x + 3, x, domain='ZZ') + + """ + g = sympify(g) + + if not g.is_Poly: + return f.sub_ground(g) + + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'sub'): + result = F.sub(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'sub') + + return per(result) + + def mul(f, g): + """ + Multiply two polynomials ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).mul(Poly(x - 2, x)) + Poly(x**3 - 2*x**2 + x - 2, x, domain='ZZ') + + >>> Poly(x**2 + 1, x)*Poly(x - 2, x) + Poly(x**3 - 2*x**2 + x - 2, x, domain='ZZ') + + """ + g = sympify(g) + + if not g.is_Poly: + return f.mul_ground(g) + + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'mul'): + result = F.mul(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'mul') + + return per(result) + + def sqr(f): + """ + Square a polynomial ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x - 2, x).sqr() + Poly(x**2 - 4*x + 4, x, domain='ZZ') + + >>> Poly(x - 2, x)**2 + Poly(x**2 - 4*x + 4, x, domain='ZZ') + + """ + if hasattr(f.rep, 'sqr'): + result = f.rep.sqr() + else: # pragma: no cover + raise OperationNotSupported(f, 'sqr') + + return f.per(result) + + def pow(f, n): + """ + Raise ``f`` to a non-negative power ``n``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x - 2, x).pow(3) + Poly(x**3 - 6*x**2 + 12*x - 8, x, domain='ZZ') + + >>> Poly(x - 2, x)**3 + Poly(x**3 - 6*x**2 + 12*x - 8, x, domain='ZZ') + + """ + n = int(n) + + if hasattr(f.rep, 'pow'): + result = f.rep.pow(n) + else: # pragma: no cover + raise OperationNotSupported(f, 'pow') + + return f.per(result) + + def pdiv(f, g): + """ + Polynomial pseudo-division of ``f`` by ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).pdiv(Poly(2*x - 4, x)) + (Poly(2*x + 4, x, domain='ZZ'), Poly(20, x, domain='ZZ')) + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'pdiv'): + q, r = F.pdiv(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'pdiv') + + return per(q), per(r) + + def prem(f, g): + """ + Polynomial pseudo-remainder of ``f`` by ``g``. + + Caveat: The function prem(f, g, x) can be safely used to compute + in Z[x] _only_ subresultant polynomial remainder sequences (prs's). + + To safely compute Euclidean and Sturmian prs's in Z[x] + employ anyone of the corresponding functions found in + the module sympy.polys.subresultants_qq_zz. The functions + in the module with suffix _pg compute prs's in Z[x] employing + rem(f, g, x), whereas the functions with suffix _amv + compute prs's in Z[x] employing rem_z(f, g, x). + + The function rem_z(f, g, x) differs from prem(f, g, x) in that + to compute the remainder polynomials in Z[x] it premultiplies + the divident times the absolute value of the leading coefficient + of the divisor raised to the power degree(f, x) - degree(g, x) + 1. + + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).prem(Poly(2*x - 4, x)) + Poly(20, x, domain='ZZ') + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'prem'): + result = F.prem(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'prem') + + return per(result) + + def pquo(f, g): + """ + Polynomial pseudo-quotient of ``f`` by ``g``. + + See the Caveat note in the function prem(f, g). + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).pquo(Poly(2*x - 4, x)) + Poly(2*x + 4, x, domain='ZZ') + + >>> Poly(x**2 - 1, x).pquo(Poly(2*x - 2, x)) + Poly(2*x + 2, x, domain='ZZ') + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'pquo'): + result = F.pquo(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'pquo') + + return per(result) + + def pexquo(f, g): + """ + Polynomial exact pseudo-quotient of ``f`` by ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 1, x).pexquo(Poly(2*x - 2, x)) + Poly(2*x + 2, x, domain='ZZ') + + >>> Poly(x**2 + 1, x).pexquo(Poly(2*x - 4, x)) + Traceback (most recent call last): + ... + ExactQuotientFailed: 2*x - 4 does not divide x**2 + 1 + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'pexquo'): + try: + result = F.pexquo(G) + except ExactQuotientFailed as exc: + raise exc.new(f.as_expr(), g.as_expr()) + else: # pragma: no cover + raise OperationNotSupported(f, 'pexquo') + + return per(result) + + def div(f, g, auto=True): + """ + Polynomial division with remainder of ``f`` by ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).div(Poly(2*x - 4, x)) + (Poly(1/2*x + 1, x, domain='QQ'), Poly(5, x, domain='QQ')) + + >>> Poly(x**2 + 1, x).div(Poly(2*x - 4, x), auto=False) + (Poly(0, x, domain='ZZ'), Poly(x**2 + 1, x, domain='ZZ')) + + """ + dom, per, F, G = f._unify(g) + retract = False + + if auto and dom.is_Ring and not dom.is_Field: + F, G = F.to_field(), G.to_field() + retract = True + + if hasattr(f.rep, 'div'): + q, r = F.div(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'div') + + if retract: + try: + Q, R = q.to_ring(), r.to_ring() + except CoercionFailed: + pass + else: + q, r = Q, R + + return per(q), per(r) + + def rem(f, g, auto=True): + """ + Computes the polynomial remainder of ``f`` by ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).rem(Poly(2*x - 4, x)) + Poly(5, x, domain='ZZ') + + >>> Poly(x**2 + 1, x).rem(Poly(2*x - 4, x), auto=False) + Poly(x**2 + 1, x, domain='ZZ') + + """ + dom, per, F, G = f._unify(g) + retract = False + + if auto and dom.is_Ring and not dom.is_Field: + F, G = F.to_field(), G.to_field() + retract = True + + if hasattr(f.rep, 'rem'): + r = F.rem(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'rem') + + if retract: + try: + r = r.to_ring() + except CoercionFailed: + pass + + return per(r) + + def quo(f, g, auto=True): + """ + Computes polynomial quotient of ``f`` by ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).quo(Poly(2*x - 4, x)) + Poly(1/2*x + 1, x, domain='QQ') + + >>> Poly(x**2 - 1, x).quo(Poly(x - 1, x)) + Poly(x + 1, x, domain='ZZ') + + """ + dom, per, F, G = f._unify(g) + retract = False + + if auto and dom.is_Ring and not dom.is_Field: + F, G = F.to_field(), G.to_field() + retract = True + + if hasattr(f.rep, 'quo'): + q = F.quo(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'quo') + + if retract: + try: + q = q.to_ring() + except CoercionFailed: + pass + + return per(q) + + def exquo(f, g, auto=True): + """ + Computes polynomial exact quotient of ``f`` by ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 1, x).exquo(Poly(x - 1, x)) + Poly(x + 1, x, domain='ZZ') + + >>> Poly(x**2 + 1, x).exquo(Poly(2*x - 4, x)) + Traceback (most recent call last): + ... + ExactQuotientFailed: 2*x - 4 does not divide x**2 + 1 + + """ + dom, per, F, G = f._unify(g) + retract = False + + if auto and dom.is_Ring and not dom.is_Field: + F, G = F.to_field(), G.to_field() + retract = True + + if hasattr(f.rep, 'exquo'): + try: + q = F.exquo(G) + except ExactQuotientFailed as exc: + raise exc.new(f.as_expr(), g.as_expr()) + else: # pragma: no cover + raise OperationNotSupported(f, 'exquo') + + if retract: + try: + q = q.to_ring() + except CoercionFailed: + pass + + return per(q) + + def _gen_to_level(f, gen): + """Returns level associated with the given generator. """ + if isinstance(gen, int): + length = len(f.gens) + + if -length <= gen < length: + if gen < 0: + return length + gen + else: + return gen + else: + raise PolynomialError("-%s <= gen < %s expected, got %s" % + (length, length, gen)) + else: + try: + return f.gens.index(sympify(gen)) + except ValueError: + raise PolynomialError( + "a valid generator expected, got %s" % gen) + + def degree(f, gen=0): + """ + Returns degree of ``f`` in ``x_j``. + + The degree of 0 is negative infinity. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + y*x + 1, x, y).degree() + 2 + >>> Poly(x**2 + y*x + y, x, y).degree(y) + 1 + >>> Poly(0, x).degree() + -oo + + """ + j = f._gen_to_level(gen) + + if hasattr(f.rep, 'degree'): + d = f.rep.degree(j) + if d < 0: + d = S.NegativeInfinity + return d + else: # pragma: no cover + raise OperationNotSupported(f, 'degree') + + def degree_list(f): + """ + Returns a list of degrees of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + y*x + 1, x, y).degree_list() + (2, 1) + + """ + if hasattr(f.rep, 'degree_list'): + return f.rep.degree_list() + else: # pragma: no cover + raise OperationNotSupported(f, 'degree_list') + + def total_degree(f): + """ + Returns the total degree of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + y*x + 1, x, y).total_degree() + 2 + >>> Poly(x + y**5, x, y).total_degree() + 5 + + """ + if hasattr(f.rep, 'total_degree'): + return f.rep.total_degree() + else: # pragma: no cover + raise OperationNotSupported(f, 'total_degree') + + def homogenize(f, s): + """ + Returns the homogeneous polynomial of ``f``. + + A homogeneous polynomial is a polynomial whose all monomials with + non-zero coefficients have the same total degree. If you only + want to check if a polynomial is homogeneous, then use + :func:`Poly.is_homogeneous`. If you want not only to check if a + polynomial is homogeneous but also compute its homogeneous order, + then use :func:`Poly.homogeneous_order`. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y, z + + >>> f = Poly(x**5 + 2*x**2*y**2 + 9*x*y**3) + >>> f.homogenize(z) + Poly(x**5 + 2*x**2*y**2*z + 9*x*y**3*z, x, y, z, domain='ZZ') + + """ + if not isinstance(s, Symbol): + raise TypeError("``Symbol`` expected, got %s" % type(s)) + if s in f.gens: + i = f.gens.index(s) + gens = f.gens + else: + i = len(f.gens) + gens = f.gens + (s,) + if hasattr(f.rep, 'homogenize'): + return f.per(f.rep.homogenize(i), gens=gens) + raise OperationNotSupported(f, 'homogeneous_order') + + def homogeneous_order(f): + """ + Returns the homogeneous order of ``f``. + + A homogeneous polynomial is a polynomial whose all monomials with + non-zero coefficients have the same total degree. This degree is + the homogeneous order of ``f``. If you only want to check if a + polynomial is homogeneous, then use :func:`Poly.is_homogeneous`. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> f = Poly(x**5 + 2*x**3*y**2 + 9*x*y**4) + >>> f.homogeneous_order() + 5 + + """ + if hasattr(f.rep, 'homogeneous_order'): + return f.rep.homogeneous_order() + else: # pragma: no cover + raise OperationNotSupported(f, 'homogeneous_order') + + def LC(f, order=None): + """ + Returns the leading coefficient of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(4*x**3 + 2*x**2 + 3*x, x).LC() + 4 + + """ + if order is not None: + return f.coeffs(order)[0] + + if hasattr(f.rep, 'LC'): + result = f.rep.LC() + else: # pragma: no cover + raise OperationNotSupported(f, 'LC') + + return f.rep.dom.to_sympy(result) + + def TC(f): + """ + Returns the trailing coefficient of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**3 + 2*x**2 + 3*x, x).TC() + 0 + + """ + if hasattr(f.rep, 'TC'): + result = f.rep.TC() + else: # pragma: no cover + raise OperationNotSupported(f, 'TC') + + return f.rep.dom.to_sympy(result) + + def EC(f, order=None): + """ + Returns the last non-zero coefficient of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**3 + 2*x**2 + 3*x, x).EC() + 3 + + """ + if hasattr(f.rep, 'coeffs'): + return f.coeffs(order)[-1] + else: # pragma: no cover + raise OperationNotSupported(f, 'EC') + + def coeff_monomial(f, monom): + """ + Returns the coefficient of ``monom`` in ``f`` if there, else None. + + Examples + ======== + + >>> from sympy import Poly, exp + >>> from sympy.abc import x, y + + >>> p = Poly(24*x*y*exp(8) + 23*x, x, y) + + >>> p.coeff_monomial(x) + 23 + >>> p.coeff_monomial(y) + 0 + >>> p.coeff_monomial(x*y) + 24*exp(8) + + Note that ``Expr.coeff()`` behaves differently, collecting terms + if possible; the Poly must be converted to an Expr to use that + method, however: + + >>> p.as_expr().coeff(x) + 24*y*exp(8) + 23 + >>> p.as_expr().coeff(y) + 24*x*exp(8) + >>> p.as_expr().coeff(x*y) + 24*exp(8) + + See Also + ======== + nth: more efficient query using exponents of the monomial's generators + + """ + return f.nth(*Monomial(monom, f.gens).exponents) + + def nth(f, *N): + """ + Returns the ``n``-th coefficient of ``f`` where ``N`` are the + exponents of the generators in the term of interest. + + Examples + ======== + + >>> from sympy import Poly, sqrt + >>> from sympy.abc import x, y + + >>> Poly(x**3 + 2*x**2 + 3*x, x).nth(2) + 2 + >>> Poly(x**3 + 2*x*y**2 + y**2, x, y).nth(1, 2) + 2 + >>> Poly(4*sqrt(x)*y) + Poly(4*y*(sqrt(x)), y, sqrt(x), domain='ZZ') + >>> _.nth(1, 1) + 4 + + See Also + ======== + coeff_monomial + + """ + if hasattr(f.rep, 'nth'): + if len(N) != len(f.gens): + raise ValueError('exponent of each generator must be specified') + result = f.rep.nth(*list(map(int, N))) + else: # pragma: no cover + raise OperationNotSupported(f, 'nth') + + return f.rep.dom.to_sympy(result) + + def coeff(f, x, n=1, right=False): + # the semantics of coeff_monomial and Expr.coeff are different; + # if someone is working with a Poly, they should be aware of the + # differences and chose the method best suited for the query. + # Alternatively, a pure-polys method could be written here but + # at this time the ``right`` keyword would be ignored because Poly + # doesn't work with non-commutatives. + raise NotImplementedError( + 'Either convert to Expr with `as_expr` method ' + 'to use Expr\'s coeff method or else use the ' + '`coeff_monomial` method of Polys.') + + def LM(f, order=None): + """ + Returns the leading monomial of ``f``. + + The Leading monomial signifies the monomial having + the highest power of the principal generator in the + expression f. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(4*x**2 + 2*x*y**2 + x*y + 3*y, x, y).LM() + x**2*y**0 + + """ + return Monomial(f.monoms(order)[0], f.gens) + + def EM(f, order=None): + """ + Returns the last non-zero monomial of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(4*x**2 + 2*x*y**2 + x*y + 3*y, x, y).EM() + x**0*y**1 + + """ + return Monomial(f.monoms(order)[-1], f.gens) + + def LT(f, order=None): + """ + Returns the leading term of ``f``. + + The Leading term signifies the term having + the highest power of the principal generator in the + expression f along with its coefficient. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(4*x**2 + 2*x*y**2 + x*y + 3*y, x, y).LT() + (x**2*y**0, 4) + + """ + monom, coeff = f.terms(order)[0] + return Monomial(monom, f.gens), coeff + + def ET(f, order=None): + """ + Returns the last non-zero term of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(4*x**2 + 2*x*y**2 + x*y + 3*y, x, y).ET() + (x**0*y**1, 3) + + """ + monom, coeff = f.terms(order)[-1] + return Monomial(monom, f.gens), coeff + + def max_norm(f): + """ + Returns maximum norm of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(-x**2 + 2*x - 3, x).max_norm() + 3 + + """ + if hasattr(f.rep, 'max_norm'): + result = f.rep.max_norm() + else: # pragma: no cover + raise OperationNotSupported(f, 'max_norm') + + return f.rep.dom.to_sympy(result) + + def l1_norm(f): + """ + Returns l1 norm of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(-x**2 + 2*x - 3, x).l1_norm() + 6 + + """ + if hasattr(f.rep, 'l1_norm'): + result = f.rep.l1_norm() + else: # pragma: no cover + raise OperationNotSupported(f, 'l1_norm') + + return f.rep.dom.to_sympy(result) + + def clear_denoms(self, convert=False): + """ + Clear denominators, but keep the ground domain. + + Examples + ======== + + >>> from sympy import Poly, S, QQ + >>> from sympy.abc import x + + >>> f = Poly(x/2 + S(1)/3, x, domain=QQ) + + >>> f.clear_denoms() + (6, Poly(3*x + 2, x, domain='QQ')) + >>> f.clear_denoms(convert=True) + (6, Poly(3*x + 2, x, domain='ZZ')) + + """ + f = self + + if not f.rep.dom.is_Field: + return S.One, f + + dom = f.get_domain() + if dom.has_assoc_Ring: + dom = f.rep.dom.get_ring() + + if hasattr(f.rep, 'clear_denoms'): + coeff, result = f.rep.clear_denoms() + else: # pragma: no cover + raise OperationNotSupported(f, 'clear_denoms') + + coeff, f = dom.to_sympy(coeff), f.per(result) + + if not convert or not dom.has_assoc_Ring: + return coeff, f + else: + return coeff, f.to_ring() + + def rat_clear_denoms(self, g): + """ + Clear denominators in a rational function ``f/g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> f = Poly(x**2/y + 1, x) + >>> g = Poly(x**3 + y, x) + + >>> p, q = f.rat_clear_denoms(g) + + >>> p + Poly(x**2 + y, x, domain='ZZ[y]') + >>> q + Poly(y*x**3 + y**2, x, domain='ZZ[y]') + + """ + f = self + + dom, per, f, g = f._unify(g) + + f = per(f) + g = per(g) + + if not (dom.is_Field and dom.has_assoc_Ring): + return f, g + + a, f = f.clear_denoms(convert=True) + b, g = g.clear_denoms(convert=True) + + f = f.mul_ground(b) + g = g.mul_ground(a) + + return f, g + + def integrate(self, *specs, **args): + """ + Computes indefinite integral of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + 2*x + 1, x).integrate() + Poly(1/3*x**3 + x**2 + x, x, domain='QQ') + + >>> Poly(x*y**2 + x, x, y).integrate((0, 1), (1, 0)) + Poly(1/2*x**2*y**2 + 1/2*x**2, x, y, domain='QQ') + + """ + f = self + + if args.get('auto', True) and f.rep.dom.is_Ring: + f = f.to_field() + + if hasattr(f.rep, 'integrate'): + if not specs: + return f.per(f.rep.integrate(m=1)) + + rep = f.rep + + for spec in specs: + if isinstance(spec, tuple): + gen, m = spec + else: + gen, m = spec, 1 + + rep = rep.integrate(int(m), f._gen_to_level(gen)) + + return f.per(rep) + else: # pragma: no cover + raise OperationNotSupported(f, 'integrate') + + def diff(f, *specs, **kwargs): + """ + Computes partial derivative of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + 2*x + 1, x).diff() + Poly(2*x + 2, x, domain='ZZ') + + >>> Poly(x*y**2 + x, x, y).diff((0, 0), (1, 1)) + Poly(2*x*y, x, y, domain='ZZ') + + """ + if not kwargs.get('evaluate', True): + return Derivative(f, *specs, **kwargs) + + if hasattr(f.rep, 'diff'): + if not specs: + return f.per(f.rep.diff(m=1)) + + rep = f.rep + + for spec in specs: + if isinstance(spec, tuple): + gen, m = spec + else: + gen, m = spec, 1 + + rep = rep.diff(int(m), f._gen_to_level(gen)) + + return f.per(rep) + else: # pragma: no cover + raise OperationNotSupported(f, 'diff') + + _eval_derivative = diff + + def eval(self, x, a=None, auto=True): + """ + Evaluate ``f`` at ``a`` in the given variable. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y, z + + >>> Poly(x**2 + 2*x + 3, x).eval(2) + 11 + + >>> Poly(2*x*y + 3*x + y + 2, x, y).eval(x, 2) + Poly(5*y + 8, y, domain='ZZ') + + >>> f = Poly(2*x*y + 3*x + y + 2*z, x, y, z) + + >>> f.eval({x: 2}) + Poly(5*y + 2*z + 6, y, z, domain='ZZ') + >>> f.eval({x: 2, y: 5}) + Poly(2*z + 31, z, domain='ZZ') + >>> f.eval({x: 2, y: 5, z: 7}) + 45 + + >>> f.eval((2, 5)) + Poly(2*z + 31, z, domain='ZZ') + >>> f(2, 5) + Poly(2*z + 31, z, domain='ZZ') + + """ + f = self + + if a is None: + if isinstance(x, dict): + mapping = x + + for gen, value in mapping.items(): + f = f.eval(gen, value) + + return f + elif isinstance(x, (tuple, list)): + values = x + + if len(values) > len(f.gens): + raise ValueError("too many values provided") + + for gen, value in zip(f.gens, values): + f = f.eval(gen, value) + + return f + else: + j, a = 0, x + else: + j = f._gen_to_level(x) + + if not hasattr(f.rep, 'eval'): # pragma: no cover + raise OperationNotSupported(f, 'eval') + + try: + result = f.rep.eval(a, j) + except CoercionFailed: + if not auto: + raise DomainError("Cannot evaluate at %s in %s" % (a, f.rep.dom)) + else: + a_domain, [a] = construct_domain([a]) + new_domain = f.get_domain().unify_with_symbols(a_domain, f.gens) + + f = f.set_domain(new_domain) + a = new_domain.convert(a, a_domain) + + result = f.rep.eval(a, j) + + return f.per(result, remove=j) + + def __call__(f, *values): + """ + Evaluate ``f`` at the give values. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y, z + + >>> f = Poly(2*x*y + 3*x + y + 2*z, x, y, z) + + >>> f(2) + Poly(5*y + 2*z + 6, y, z, domain='ZZ') + >>> f(2, 5) + Poly(2*z + 31, z, domain='ZZ') + >>> f(2, 5, 7) + 45 + + """ + return f.eval(values) + + def half_gcdex(f, g, auto=True): + """ + Half extended Euclidean algorithm of ``f`` and ``g``. + + Returns ``(s, h)`` such that ``h = gcd(f, g)`` and ``s*f = h (mod g)``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 + >>> g = x**3 + x**2 - 4*x - 4 + + >>> Poly(f).half_gcdex(Poly(g)) + (Poly(-1/5*x + 3/5, x, domain='QQ'), Poly(x + 1, x, domain='QQ')) + + """ + dom, per, F, G = f._unify(g) + + if auto and dom.is_Ring: + F, G = F.to_field(), G.to_field() + + if hasattr(f.rep, 'half_gcdex'): + s, h = F.half_gcdex(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'half_gcdex') + + return per(s), per(h) + + def gcdex(f, g, auto=True): + """ + Extended Euclidean algorithm of ``f`` and ``g``. + + Returns ``(s, t, h)`` such that ``h = gcd(f, g)`` and ``s*f + t*g = h``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 + >>> g = x**3 + x**2 - 4*x - 4 + + >>> Poly(f).gcdex(Poly(g)) + (Poly(-1/5*x + 3/5, x, domain='QQ'), + Poly(1/5*x**2 - 6/5*x + 2, x, domain='QQ'), + Poly(x + 1, x, domain='QQ')) + + """ + dom, per, F, G = f._unify(g) + + if auto and dom.is_Ring: + F, G = F.to_field(), G.to_field() + + if hasattr(f.rep, 'gcdex'): + s, t, h = F.gcdex(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'gcdex') + + return per(s), per(t), per(h) + + def invert(f, g, auto=True): + """ + Invert ``f`` modulo ``g`` when possible. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 1, x).invert(Poly(2*x - 1, x)) + Poly(-4/3, x, domain='QQ') + + >>> Poly(x**2 - 1, x).invert(Poly(x - 1, x)) + Traceback (most recent call last): + ... + NotInvertible: zero divisor + + """ + dom, per, F, G = f._unify(g) + + if auto and dom.is_Ring: + F, G = F.to_field(), G.to_field() + + if hasattr(f.rep, 'invert'): + result = F.invert(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'invert') + + return per(result) + + def revert(f, n): + """ + Compute ``f**(-1)`` mod ``x**n``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(1, x).revert(2) + Poly(1, x, domain='ZZ') + + >>> Poly(1 + x, x).revert(1) + Poly(1, x, domain='ZZ') + + >>> Poly(x**2 - 2, x).revert(2) + Traceback (most recent call last): + ... + NotReversible: only units are reversible in a ring + + >>> Poly(1/x, x).revert(1) + Traceback (most recent call last): + ... + PolynomialError: 1/x contains an element of the generators set + + """ + if hasattr(f.rep, 'revert'): + result = f.rep.revert(int(n)) + else: # pragma: no cover + raise OperationNotSupported(f, 'revert') + + return f.per(result) + + def subresultants(f, g): + """ + Computes the subresultant PRS of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 1, x).subresultants(Poly(x**2 - 1, x)) + [Poly(x**2 + 1, x, domain='ZZ'), + Poly(x**2 - 1, x, domain='ZZ'), + Poly(-2, x, domain='ZZ')] + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'subresultants'): + result = F.subresultants(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'subresultants') + + return list(map(per, result)) + + def resultant(f, g, includePRS=False): + """ + Computes the resultant of ``f`` and ``g`` via PRS. + + If includePRS=True, it includes the subresultant PRS in the result. + Because the PRS is used to calculate the resultant, this is more + efficient than calling :func:`subresultants` separately. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = Poly(x**2 + 1, x) + + >>> f.resultant(Poly(x**2 - 1, x)) + 4 + >>> f.resultant(Poly(x**2 - 1, x), includePRS=True) + (4, [Poly(x**2 + 1, x, domain='ZZ'), Poly(x**2 - 1, x, domain='ZZ'), + Poly(-2, x, domain='ZZ')]) + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'resultant'): + if includePRS: + result, R = F.resultant(G, includePRS=includePRS) + else: + result = F.resultant(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'resultant') + + if includePRS: + return (per(result, remove=0), list(map(per, R))) + return per(result, remove=0) + + def discriminant(f): + """ + Computes the discriminant of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + 2*x + 3, x).discriminant() + -8 + + """ + if hasattr(f.rep, 'discriminant'): + result = f.rep.discriminant() + else: # pragma: no cover + raise OperationNotSupported(f, 'discriminant') + + return f.per(result, remove=0) + + def dispersionset(f, g=None): + r"""Compute the *dispersion set* of two polynomials. + + For two polynomials `f(x)` and `g(x)` with `\deg f > 0` + and `\deg g > 0` the dispersion set `\operatorname{J}(f, g)` is defined as: + + .. math:: + \operatorname{J}(f, g) + & := \{a \in \mathbb{N}_0 | \gcd(f(x), g(x+a)) \neq 1\} \\ + & = \{a \in \mathbb{N}_0 | \deg \gcd(f(x), g(x+a)) \geq 1\} + + For a single polynomial one defines `\operatorname{J}(f) := \operatorname{J}(f, f)`. + + Examples + ======== + + >>> from sympy import poly + >>> from sympy.polys.dispersion import dispersion, dispersionset + >>> from sympy.abc import x + + Dispersion set and dispersion of a simple polynomial: + + >>> fp = poly((x - 3)*(x + 3), x) + >>> sorted(dispersionset(fp)) + [0, 6] + >>> dispersion(fp) + 6 + + Note that the definition of the dispersion is not symmetric: + + >>> fp = poly(x**4 - 3*x**2 + 1, x) + >>> gp = fp.shift(-3) + >>> sorted(dispersionset(fp, gp)) + [2, 3, 4] + >>> dispersion(fp, gp) + 4 + >>> sorted(dispersionset(gp, fp)) + [] + >>> dispersion(gp, fp) + -oo + + Computing the dispersion also works over field extensions: + + >>> from sympy import sqrt + >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') + >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') + >>> sorted(dispersionset(fp, gp)) + [2] + >>> sorted(dispersionset(gp, fp)) + [1, 4] + + We can even perform the computations for polynomials + having symbolic coefficients: + + >>> from sympy.abc import a + >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) + >>> sorted(dispersionset(fp)) + [0, 1] + + See Also + ======== + + dispersion + + References + ========== + + 1. [ManWright94]_ + 2. [Koepf98]_ + 3. [Abramov71]_ + 4. [Man93]_ + """ + from sympy.polys.dispersion import dispersionset + return dispersionset(f, g) + + def dispersion(f, g=None): + r"""Compute the *dispersion* of polynomials. + + For two polynomials `f(x)` and `g(x)` with `\deg f > 0` + and `\deg g > 0` the dispersion `\operatorname{dis}(f, g)` is defined as: + + .. math:: + \operatorname{dis}(f, g) + & := \max\{ J(f,g) \cup \{0\} \} \\ + & = \max\{ \{a \in \mathbb{N} | \gcd(f(x), g(x+a)) \neq 1\} \cup \{0\} \} + + and for a single polynomial `\operatorname{dis}(f) := \operatorname{dis}(f, f)`. + + Examples + ======== + + >>> from sympy import poly + >>> from sympy.polys.dispersion import dispersion, dispersionset + >>> from sympy.abc import x + + Dispersion set and dispersion of a simple polynomial: + + >>> fp = poly((x - 3)*(x + 3), x) + >>> sorted(dispersionset(fp)) + [0, 6] + >>> dispersion(fp) + 6 + + Note that the definition of the dispersion is not symmetric: + + >>> fp = poly(x**4 - 3*x**2 + 1, x) + >>> gp = fp.shift(-3) + >>> sorted(dispersionset(fp, gp)) + [2, 3, 4] + >>> dispersion(fp, gp) + 4 + >>> sorted(dispersionset(gp, fp)) + [] + >>> dispersion(gp, fp) + -oo + + Computing the dispersion also works over field extensions: + + >>> from sympy import sqrt + >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') + >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') + >>> sorted(dispersionset(fp, gp)) + [2] + >>> sorted(dispersionset(gp, fp)) + [1, 4] + + We can even perform the computations for polynomials + having symbolic coefficients: + + >>> from sympy.abc import a + >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) + >>> sorted(dispersionset(fp)) + [0, 1] + + See Also + ======== + + dispersionset + + References + ========== + + 1. [ManWright94]_ + 2. [Koepf98]_ + 3. [Abramov71]_ + 4. [Man93]_ + """ + from sympy.polys.dispersion import dispersion + return dispersion(f, g) + + def cofactors(f, g): + """ + Returns the GCD of ``f`` and ``g`` and their cofactors. + + Returns polynomials ``(h, cff, cfg)`` such that ``h = gcd(f, g)``, and + ``cff = quo(f, h)`` and ``cfg = quo(g, h)`` are, so called, cofactors + of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 1, x).cofactors(Poly(x**2 - 3*x + 2, x)) + (Poly(x - 1, x, domain='ZZ'), + Poly(x + 1, x, domain='ZZ'), + Poly(x - 2, x, domain='ZZ')) + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'cofactors'): + h, cff, cfg = F.cofactors(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'cofactors') + + return per(h), per(cff), per(cfg) + + def gcd(f, g): + """ + Returns the polynomial GCD of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 1, x).gcd(Poly(x**2 - 3*x + 2, x)) + Poly(x - 1, x, domain='ZZ') + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'gcd'): + result = F.gcd(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'gcd') + + return per(result) + + def lcm(f, g): + """ + Returns polynomial LCM of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 1, x).lcm(Poly(x**2 - 3*x + 2, x)) + Poly(x**3 - 2*x**2 - x + 2, x, domain='ZZ') + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'lcm'): + result = F.lcm(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'lcm') + + return per(result) + + def trunc(f, p): + """ + Reduce ``f`` modulo a constant ``p``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(2*x**3 + 3*x**2 + 5*x + 7, x).trunc(3) + Poly(-x**3 - x + 1, x, domain='ZZ') + + """ + p = f.rep.dom.convert(p) + + if hasattr(f.rep, 'trunc'): + result = f.rep.trunc(p) + else: # pragma: no cover + raise OperationNotSupported(f, 'trunc') + + return f.per(result) + + def monic(self, auto=True): + """ + Divides all coefficients by ``LC(f)``. + + Examples + ======== + + >>> from sympy import Poly, ZZ + >>> from sympy.abc import x + + >>> Poly(3*x**2 + 6*x + 9, x, domain=ZZ).monic() + Poly(x**2 + 2*x + 3, x, domain='QQ') + + >>> Poly(3*x**2 + 4*x + 2, x, domain=ZZ).monic() + Poly(x**2 + 4/3*x + 2/3, x, domain='QQ') + + """ + f = self + + if auto and f.rep.dom.is_Ring: + f = f.to_field() + + if hasattr(f.rep, 'monic'): + result = f.rep.monic() + else: # pragma: no cover + raise OperationNotSupported(f, 'monic') + + return f.per(result) + + def content(f): + """ + Returns the GCD of polynomial coefficients. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(6*x**2 + 8*x + 12, x).content() + 2 + + """ + if hasattr(f.rep, 'content'): + result = f.rep.content() + else: # pragma: no cover + raise OperationNotSupported(f, 'content') + + return f.rep.dom.to_sympy(result) + + def primitive(f): + """ + Returns the content and a primitive form of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(2*x**2 + 8*x + 12, x).primitive() + (2, Poly(x**2 + 4*x + 6, x, domain='ZZ')) + + """ + if hasattr(f.rep, 'primitive'): + cont, result = f.rep.primitive() + else: # pragma: no cover + raise OperationNotSupported(f, 'primitive') + + return f.rep.dom.to_sympy(cont), f.per(result) + + def compose(f, g): + """ + Computes the functional composition of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + x, x).compose(Poly(x - 1, x)) + Poly(x**2 - x, x, domain='ZZ') + + """ + _, per, F, G = f._unify(g) + + if hasattr(f.rep, 'compose'): + result = F.compose(G) + else: # pragma: no cover + raise OperationNotSupported(f, 'compose') + + return per(result) + + def decompose(f): + """ + Computes a functional decomposition of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**4 + 2*x**3 - x - 1, x, domain='ZZ').decompose() + [Poly(x**2 - x - 1, x, domain='ZZ'), Poly(x**2 + x, x, domain='ZZ')] + + """ + if hasattr(f.rep, 'decompose'): + result = f.rep.decompose() + else: # pragma: no cover + raise OperationNotSupported(f, 'decompose') + + return list(map(f.per, result)) + + def shift(f, a): + """ + Efficiently compute Taylor shift ``f(x + a)``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 2*x + 1, x).shift(2) + Poly(x**2 + 2*x + 1, x, domain='ZZ') + + See Also + ======== + + shift_list: Analogous method for multivariate polynomials. + """ + return f.per(f.rep.shift(a)) + + def shift_list(f, a): + """ + Efficiently compute Taylor shift ``f(X + A)``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x*y, [x,y]).shift_list([1, 2]) == Poly((x+1)*(y+2), [x,y]) + True + + See Also + ======== + + shift: Analogous method for univariate polynomials. + """ + return f.per(f.rep.shift_list(a)) + + def transform(f, p, q): + """ + Efficiently evaluate the functional transformation ``q**n * f(p/q)``. + + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 2*x + 1, x).transform(Poly(x + 1, x), Poly(x - 1, x)) + Poly(4, x, domain='ZZ') + + """ + P, Q = p.unify(q) + F, P = f.unify(P) + F, Q = F.unify(Q) + + if hasattr(F.rep, 'transform'): + result = F.rep.transform(P.rep, Q.rep) + else: # pragma: no cover + raise OperationNotSupported(F, 'transform') + + return F.per(result) + + def sturm(self, auto=True): + """ + Computes the Sturm sequence of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**3 - 2*x**2 + x - 3, x).sturm() + [Poly(x**3 - 2*x**2 + x - 3, x, domain='QQ'), + Poly(3*x**2 - 4*x + 1, x, domain='QQ'), + Poly(2/9*x + 25/9, x, domain='QQ'), + Poly(-2079/4, x, domain='QQ')] + + """ + f = self + + if auto and f.rep.dom.is_Ring: + f = f.to_field() + + if hasattr(f.rep, 'sturm'): + result = f.rep.sturm() + else: # pragma: no cover + raise OperationNotSupported(f, 'sturm') + + return list(map(f.per, result)) + + def gff_list(f): + """ + Computes greatest factorial factorization of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = x**5 + 2*x**4 - x**3 - 2*x**2 + + >>> Poly(f).gff_list() + [(Poly(x, x, domain='ZZ'), 1), (Poly(x + 2, x, domain='ZZ'), 4)] + + """ + if hasattr(f.rep, 'gff_list'): + result = f.rep.gff_list() + else: # pragma: no cover + raise OperationNotSupported(f, 'gff_list') + + return [(f.per(g), k) for g, k in result] + + def norm(f): + """ + Computes the product, ``Norm(f)``, of the conjugates of + a polynomial ``f`` defined over a number field ``K``. + + Examples + ======== + + >>> from sympy import Poly, sqrt + >>> from sympy.abc import x + + >>> a, b = sqrt(2), sqrt(3) + + A polynomial over a quadratic extension. + Two conjugates x - a and x + a. + + >>> f = Poly(x - a, x, extension=a) + >>> f.norm() + Poly(x**2 - 2, x, domain='QQ') + + A polynomial over a quartic extension. + Four conjugates x - a, x - a, x + a and x + a. + + >>> f = Poly(x - a, x, extension=(a, b)) + >>> f.norm() + Poly(x**4 - 4*x**2 + 4, x, domain='QQ') + + """ + if hasattr(f.rep, 'norm'): + r = f.rep.norm() + else: # pragma: no cover + raise OperationNotSupported(f, 'norm') + + return f.per(r) + + def sqf_norm(f): + """ + Computes square-free norm of ``f``. + + Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and + ``r(x) = Norm(g(x))`` is a square-free polynomial over ``K``, + where ``a`` is the algebraic extension of the ground domain. + + Examples + ======== + + >>> from sympy import Poly, sqrt + >>> from sympy.abc import x + + >>> s, f, r = Poly(x**2 + 1, x, extension=[sqrt(3)]).sqf_norm() + + >>> s + [1] + >>> f + Poly(x**2 - 2*sqrt(3)*x + 4, x, domain='QQ') + >>> r + Poly(x**4 - 4*x**2 + 16, x, domain='QQ') + + """ + if hasattr(f.rep, 'sqf_norm'): + s, g, r = f.rep.sqf_norm() + else: # pragma: no cover + raise OperationNotSupported(f, 'sqf_norm') + + return s, f.per(g), f.per(r) + + def sqf_part(f): + """ + Computes square-free part of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**3 - 3*x - 2, x).sqf_part() + Poly(x**2 - x - 2, x, domain='ZZ') + + """ + if hasattr(f.rep, 'sqf_part'): + result = f.rep.sqf_part() + else: # pragma: no cover + raise OperationNotSupported(f, 'sqf_part') + + return f.per(result) + + def sqf_list(f, all=False): + """ + Returns a list of square-free factors of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 + + >>> Poly(f).sqf_list() + (2, [(Poly(x + 1, x, domain='ZZ'), 2), + (Poly(x + 2, x, domain='ZZ'), 3)]) + + >>> Poly(f).sqf_list(all=True) + (2, [(Poly(1, x, domain='ZZ'), 1), + (Poly(x + 1, x, domain='ZZ'), 2), + (Poly(x + 2, x, domain='ZZ'), 3)]) + + """ + if hasattr(f.rep, 'sqf_list'): + coeff, factors = f.rep.sqf_list(all) + else: # pragma: no cover + raise OperationNotSupported(f, 'sqf_list') + + return f.rep.dom.to_sympy(coeff), [(f.per(g), k) for g, k in factors] + + def sqf_list_include(f, all=False): + """ + Returns a list of square-free factors of ``f``. + + Examples + ======== + + >>> from sympy import Poly, expand + >>> from sympy.abc import x + + >>> f = expand(2*(x + 1)**3*x**4) + >>> f + 2*x**7 + 6*x**6 + 6*x**5 + 2*x**4 + + >>> Poly(f).sqf_list_include() + [(Poly(2, x, domain='ZZ'), 1), + (Poly(x + 1, x, domain='ZZ'), 3), + (Poly(x, x, domain='ZZ'), 4)] + + >>> Poly(f).sqf_list_include(all=True) + [(Poly(2, x, domain='ZZ'), 1), + (Poly(1, x, domain='ZZ'), 2), + (Poly(x + 1, x, domain='ZZ'), 3), + (Poly(x, x, domain='ZZ'), 4)] + + """ + if hasattr(f.rep, 'sqf_list_include'): + factors = f.rep.sqf_list_include(all) + else: # pragma: no cover + raise OperationNotSupported(f, 'sqf_list_include') + + return [(f.per(g), k) for g, k in factors] + + def factor_list(f) -> tuple[Expr, list[tuple[Poly, int]]]: + """ + Returns a list of irreducible factors of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> f = 2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y + + >>> Poly(f).factor_list() + (2, [(Poly(x + y, x, y, domain='ZZ'), 1), + (Poly(x**2 + 1, x, y, domain='ZZ'), 2)]) + + """ + if hasattr(f.rep, 'factor_list'): + try: + coeff, factors = f.rep.factor_list() + except DomainError: + if f.degree() == 0: + return f.as_expr(), [] + else: + return S.One, [(f, 1)] + else: # pragma: no cover + raise OperationNotSupported(f, 'factor_list') + + return f.rep.dom.to_sympy(coeff), [(f.per(g), k) for g, k in factors] + + def factor_list_include(f): + """ + Returns a list of irreducible factors of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> f = 2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y + + >>> Poly(f).factor_list_include() + [(Poly(2*x + 2*y, x, y, domain='ZZ'), 1), + (Poly(x**2 + 1, x, y, domain='ZZ'), 2)] + + """ + if hasattr(f.rep, 'factor_list_include'): + try: + factors = f.rep.factor_list_include() + except DomainError: + return [(f, 1)] + else: # pragma: no cover + raise OperationNotSupported(f, 'factor_list_include') + + return [(f.per(g), k) for g, k in factors] + + def intervals(f, all=False, eps=None, inf=None, sup=None, fast=False, sqf=False): + """ + Compute isolating intervals for roots of ``f``. + + For real roots the Vincent-Akritas-Strzebonski (VAS) continued fractions method is used. + + References + ========== + .. [#] Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative Study of Two Real Root + Isolation Methods . Nonlinear Analysis: Modelling and Control, Vol. 10, No. 4, 297-304, 2005. + .. [#] Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. Vigklas: Improving the + Performance of the Continued Fractions Method Using new Bounds of Positive Roots. Nonlinear + Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 3, x).intervals() + [((-2, -1), 1), ((1, 2), 1)] + >>> Poly(x**2 - 3, x).intervals(eps=1e-2) + [((-26/15, -19/11), 1), ((19/11, 26/15), 1)] + + """ + if eps is not None: + eps = QQ.convert(eps) + + if eps <= 0: + raise ValueError("'eps' must be a positive rational") + + if inf is not None: + inf = QQ.convert(inf) + if sup is not None: + sup = QQ.convert(sup) + + if hasattr(f.rep, 'intervals'): + result = f.rep.intervals( + all=all, eps=eps, inf=inf, sup=sup, fast=fast, sqf=sqf) + else: # pragma: no cover + raise OperationNotSupported(f, 'intervals') + + if sqf: + def _real(interval): + s, t = interval + return (QQ.to_sympy(s), QQ.to_sympy(t)) + + if not all: + return list(map(_real, result)) + + def _complex(rectangle): + (u, v), (s, t) = rectangle + return (QQ.to_sympy(u) + I*QQ.to_sympy(v), + QQ.to_sympy(s) + I*QQ.to_sympy(t)) + + real_part, complex_part = result + + return list(map(_real, real_part)), list(map(_complex, complex_part)) + else: + def _real(interval): + (s, t), k = interval + return ((QQ.to_sympy(s), QQ.to_sympy(t)), k) + + if not all: + return list(map(_real, result)) + + def _complex(rectangle): + ((u, v), (s, t)), k = rectangle + return ((QQ.to_sympy(u) + I*QQ.to_sympy(v), + QQ.to_sympy(s) + I*QQ.to_sympy(t)), k) + + real_part, complex_part = result + + return list(map(_real, real_part)), list(map(_complex, complex_part)) + + def refine_root(f, s, t, eps=None, steps=None, fast=False, check_sqf=False): + """ + Refine an isolating interval of a root to the given precision. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 3, x).refine_root(1, 2, eps=1e-2) + (19/11, 26/15) + + """ + if check_sqf and not f.is_sqf: + raise PolynomialError("only square-free polynomials supported") + + s, t = QQ.convert(s), QQ.convert(t) + + if eps is not None: + eps = QQ.convert(eps) + + if eps <= 0: + raise ValueError("'eps' must be a positive rational") + + if steps is not None: + steps = int(steps) + elif eps is None: + steps = 1 + + if hasattr(f.rep, 'refine_root'): + S, T = f.rep.refine_root(s, t, eps=eps, steps=steps, fast=fast) + else: # pragma: no cover + raise OperationNotSupported(f, 'refine_root') + + return QQ.to_sympy(S), QQ.to_sympy(T) + + def count_roots(f, inf=None, sup=None): + """ + Return the number of roots of ``f`` in ``[inf, sup]`` interval. + + Examples + ======== + + >>> from sympy import Poly, I + >>> from sympy.abc import x + + >>> Poly(x**4 - 4, x).count_roots(-3, 3) + 2 + >>> Poly(x**4 - 4, x).count_roots(0, 1 + 3*I) + 1 + + """ + inf_real, sup_real = True, True + + if inf is not None: + inf = sympify(inf) + + if inf is S.NegativeInfinity: + inf = None + else: + re, im = inf.as_real_imag() + + if not im: + inf = QQ.convert(inf) + else: + inf, inf_real = list(map(QQ.convert, (re, im))), False + + if sup is not None: + sup = sympify(sup) + + if sup is S.Infinity: + sup = None + else: + re, im = sup.as_real_imag() + + if not im: + sup = QQ.convert(sup) + else: + sup, sup_real = list(map(QQ.convert, (re, im))), False + + if inf_real and sup_real: + if hasattr(f.rep, 'count_real_roots'): + count = f.rep.count_real_roots(inf=inf, sup=sup) + else: # pragma: no cover + raise OperationNotSupported(f, 'count_real_roots') + else: + if inf_real and inf is not None: + inf = (inf, QQ.zero) + + if sup_real and sup is not None: + sup = (sup, QQ.zero) + + if hasattr(f.rep, 'count_complex_roots'): + count = f.rep.count_complex_roots(inf=inf, sup=sup) + else: # pragma: no cover + raise OperationNotSupported(f, 'count_complex_roots') + + return Integer(count) + + def root(f, index, radicals=True): + """ + Get an indexed root of a polynomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = Poly(2*x**3 - 7*x**2 + 4*x + 4) + + >>> f.root(0) + -1/2 + >>> f.root(1) + 2 + >>> f.root(2) + 2 + >>> f.root(3) + Traceback (most recent call last): + ... + IndexError: root index out of [-3, 2] range, got 3 + + >>> Poly(x**5 + x + 1).root(0) + CRootOf(x**3 - x**2 + 1, 0) + + """ + return sympy.polys.rootoftools.rootof(f, index, radicals=radicals) + + def real_roots(f, multiple=True, radicals=True): + """ + Return a list of real roots with multiplicities. + + See :func:`real_roots` for more explanation. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(2*x**3 - 7*x**2 + 4*x + 4).real_roots() + [-1/2, 2, 2] + >>> Poly(x**3 + x + 1).real_roots() + [CRootOf(x**3 + x + 1, 0)] + """ + reals = sympy.polys.rootoftools.CRootOf.real_roots(f, radicals=radicals) + + if multiple: + return reals + else: + return group(reals, multiple=False) + + def all_roots(f, multiple=True, radicals=True): + """ + Return a list of real and complex roots with multiplicities. + + See :func:`all_roots` for more explanation. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(2*x**3 - 7*x**2 + 4*x + 4).all_roots() + [-1/2, 2, 2] + >>> Poly(x**3 + x + 1).all_roots() + [CRootOf(x**3 + x + 1, 0), + CRootOf(x**3 + x + 1, 1), + CRootOf(x**3 + x + 1, 2)] + + """ + roots = sympy.polys.rootoftools.CRootOf.all_roots(f, radicals=radicals) + + if multiple: + return roots + else: + return group(roots, multiple=False) + + def nroots(f, n=15, maxsteps=50, cleanup=True): + """ + Compute numerical approximations of roots of ``f``. + + Parameters + ========== + + n ... the number of digits to calculate + maxsteps ... the maximum number of iterations to do + + If the accuracy `n` cannot be reached in `maxsteps`, it will raise an + exception. You need to rerun with higher maxsteps. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 3).nroots(n=15) + [-1.73205080756888, 1.73205080756888] + >>> Poly(x**2 - 3).nroots(n=30) + [-1.73205080756887729352744634151, 1.73205080756887729352744634151] + + """ + if f.is_multivariate: + raise MultivariatePolynomialError( + "Cannot compute numerical roots of %s" % f) + + if f.degree() <= 0: + return [] + + # For integer and rational coefficients, convert them to integers only + # (for accuracy). Otherwise just try to convert the coefficients to + # mpmath.mpc and raise an exception if the conversion fails. + if f.rep.dom is ZZ: + coeffs = [int(coeff) for coeff in f.all_coeffs()] + elif f.rep.dom is QQ: + denoms = [coeff.q for coeff in f.all_coeffs()] + fac = ilcm(*denoms) + coeffs = [int(coeff*fac) for coeff in f.all_coeffs()] + else: + coeffs = [coeff.evalf(n=n).as_real_imag() + for coeff in f.all_coeffs()] + with mpmath.workdps(n): + try: + coeffs = [mpmath.mpc(*coeff) for coeff in coeffs] + except TypeError: + raise DomainError("Numerical domain expected, got %s" % \ + f.rep.dom) + + dps = mpmath.mp.dps + mpmath.mp.dps = n + + from sympy.functions.elementary.complexes import sign + try: + # We need to add extra precision to guard against losing accuracy. + # 10 times the degree of the polynomial seems to work well. + roots = mpmath.polyroots(coeffs, maxsteps=maxsteps, + cleanup=cleanup, error=False, extraprec=f.degree()*10) + + # Mpmath puts real roots first, then complex ones (as does all_roots) + # so we make sure this convention holds here, too. + roots = list(map(sympify, + sorted(roots, key=lambda r: (1 if r.imag else 0, r.real, abs(r.imag), sign(r.imag))))) + except NoConvergence: + try: + # If roots did not converge try again with more extra precision. + roots = mpmath.polyroots(coeffs, maxsteps=maxsteps, + cleanup=cleanup, error=False, extraprec=f.degree()*15) + roots = list(map(sympify, + sorted(roots, key=lambda r: (1 if r.imag else 0, r.real, abs(r.imag), sign(r.imag))))) + except NoConvergence: + raise NoConvergence( + 'convergence to root failed; try n < %s or maxsteps > %s' % ( + n, maxsteps)) + finally: + mpmath.mp.dps = dps + + return roots + + def ground_roots(f): + """ + Compute roots of ``f`` by factorization in the ground domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**6 - 4*x**4 + 4*x**3 - x**2).ground_roots() + {0: 2, 1: 2} + + """ + if f.is_multivariate: + raise MultivariatePolynomialError( + "Cannot compute ground roots of %s" % f) + + roots = {} + + for factor, k in f.factor_list()[1]: + if factor.is_linear: + a, b = factor.all_coeffs() + roots[-b/a] = k + + return roots + + def nth_power_roots_poly(f, n): + """ + Construct a polynomial with n-th powers of roots of ``f``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = Poly(x**4 - x**2 + 1) + + >>> f.nth_power_roots_poly(2) + Poly(x**4 - 2*x**3 + 3*x**2 - 2*x + 1, x, domain='ZZ') + >>> f.nth_power_roots_poly(3) + Poly(x**4 + 2*x**2 + 1, x, domain='ZZ') + >>> f.nth_power_roots_poly(4) + Poly(x**4 + 2*x**3 + 3*x**2 + 2*x + 1, x, domain='ZZ') + >>> f.nth_power_roots_poly(12) + Poly(x**4 - 4*x**3 + 6*x**2 - 4*x + 1, x, domain='ZZ') + + """ + if f.is_multivariate: + raise MultivariatePolynomialError( + "must be a univariate polynomial") + + N = sympify(n) + + if N.is_Integer and N >= 1: + n = int(N) + else: + raise ValueError("'n' must an integer and n >= 1, got %s" % n) + + x = f.gen + t = Dummy('t') + + r = f.resultant(f.__class__.from_expr(x**n - t, x, t)) + + return r.replace(t, x) + + def which_real_roots(f, candidates): + """ + Find roots of a square-free polynomial ``f`` from ``candidates``. + + Explanation + =========== + + If ``f`` is a square-free polynomial and ``candidates`` is a superset + of the roots of ``f``, then ``f.which_real_roots(candidates)`` returns a + list containing exactly the set of roots of ``f``. The domain must be + :ref:`ZZ`, :ref:`QQ`, or :ref:`QQ(a)` and``f`` must be univariate and + square-free. + + The list ``candidates`` must be a superset of the real roots of ``f`` + and ``f.which_real_roots(candidates)`` returns the set of real roots + of ``f``. The output preserves the order of the order of ``candidates``. + + Examples + ======== + + >>> from sympy import Poly, sqrt + >>> from sympy.abc import x + + >>> f = Poly(x**4 - 1) + >>> f.which_real_roots([-1, 1, 0, -2, 2]) + [-1, 1] + >>> f.which_real_roots([-1, 1, 1, 1, 1]) + [-1, 1] + + This method is useful as lifting to rational coefficients + produced extraneous roots, which we can filter out with + this method. + + >>> f = Poly(sqrt(2)*x**3 + x**2 - 1, x, extension=True) + >>> f.lift() + Poly(-2*x**6 + x**4 - 2*x**2 + 1, x, domain='QQ') + >>> f.lift().real_roots() + [-sqrt(2)/2, sqrt(2)/2] + >>> f.which_real_roots(f.lift().real_roots()) + [sqrt(2)/2] + + This procedure is already done internally when calling + `.real_roots()` on a polynomial with algebraic coefficients. + + >>> f.real_roots() + [sqrt(2)/2] + + See Also + ======== + + same_root + which_all_roots + """ + if f.is_multivariate: + raise MultivariatePolynomialError( + "Must be a univariate polynomial") + + dom = f.get_domain() + + if not (dom.is_ZZ or dom.is_QQ or dom.is_AlgebraicField): + raise NotImplementedError( + "root counting not supported over %s" % dom) + + return f._which_roots(candidates, f.count_roots()) + + def which_all_roots(f, candidates): + """ + Find roots of a square-free polynomial ``f`` from ``candidates``. + + Explanation + =========== + + If ``f`` is a square-free polynomial and ``candidates`` is a superset + of the roots of ``f``, then ``f.which_all_roots(candidates)`` returns a + list containing exactly the set of roots of ``f``. The polynomial``f`` + must be univariate and square-free. + + The list ``candidates`` must be a superset of the complex roots of + ``f`` and ``f.which_all_roots(candidates)`` returns exactly the + set of all complex roots of ``f``. The output preserves the order of + the order of ``candidates``. + + Examples + ======== + + >>> from sympy import Poly, I + >>> from sympy.abc import x + + >>> f = Poly(x**4 - 1) + >>> f.which_all_roots([-1, 1, -I, I, 0]) + [-1, 1, -I, I] + >>> f.which_all_roots([-1, 1, -I, I, I, I]) + [-1, 1, -I, I] + + This method is useful as lifting to rational coefficients + produced extraneous roots, which we can filter out with + this method. + + >>> f = Poly(x**2 + I*x - 1, x, extension=True) + >>> f.lift() + Poly(x**4 - x**2 + 1, x, domain='ZZ') + >>> f.lift().all_roots() + [CRootOf(x**4 - x**2 + 1, 0), + CRootOf(x**4 - x**2 + 1, 1), + CRootOf(x**4 - x**2 + 1, 2), + CRootOf(x**4 - x**2 + 1, 3)] + >>> f.which_all_roots(f.lift().all_roots()) + [CRootOf(x**4 - x**2 + 1, 0), CRootOf(x**4 - x**2 + 1, 2)] + + This procedure is already done internally when calling + `.all_roots()` on a polynomial with algebraic coefficients, + or polynomials with Gaussian domains. + + >>> f.all_roots() + [CRootOf(x**4 - x**2 + 1, 0), CRootOf(x**4 - x**2 + 1, 2)] + + See Also + ======== + + same_root + which_real_roots + """ + if f.is_multivariate: + raise MultivariatePolynomialError( + "Must be a univariate polynomial") + + return f._which_roots(candidates, f.degree()) + + def _which_roots(f, candidates, num_roots): + prec = 10 + # using Counter bc its like an ordered set + root_counts = Counter(candidates) + + while len(root_counts) > num_roots: + for r in list(root_counts.keys()): + # If f(r) != 0 then f(r).evalf() gives a float/complex with precision. + f_r = f(r).evalf(prec, maxn=2*prec) + if abs(f_r)._prec >= 2: + root_counts.pop(r) + + prec *= 2 + + return list(root_counts.keys()) + + def same_root(f, a, b): + """ + Decide whether two roots of this polynomial are equal. + + Examples + ======== + + >>> from sympy import Poly, cyclotomic_poly, exp, I, pi + >>> f = Poly(cyclotomic_poly(5)) + >>> r0 = exp(2*I*pi/5) + >>> indices = [i for i, r in enumerate(f.all_roots()) if f.same_root(r, r0)] + >>> print(indices) + [3] + + Raises + ====== + + DomainError + If the domain of the polynomial is not :ref:`ZZ`, :ref:`QQ`, + :ref:`RR`, or :ref:`CC`. + MultivariatePolynomialError + If the polynomial is not univariate. + PolynomialError + If the polynomial is of degree < 2. + + See Also + ======== + + which_real_roots + which_all_roots + """ + if f.is_multivariate: + raise MultivariatePolynomialError( + "Must be a univariate polynomial") + + dom_delta_sq = f.rep.mignotte_sep_bound_squared() + delta_sq = f.domain.get_field().to_sympy(dom_delta_sq) + # We have delta_sq = delta**2, where delta is a lower bound on the + # minimum separation between any two roots of this polynomial. + # Let eps = delta/3, and define eps_sq = eps**2 = delta**2/9. + eps_sq = delta_sq / 9 + + r, _, _, _ = evalf(1/eps_sq, 1, {}) + n = fastlog(r) + # Then 2^n > 1/eps**2. + m = (n // 2) + (n % 2) + # Then 2^(-m) < eps. + ev = lambda x: quad_to_mpmath(_evalf_with_bounded_error(x, m=m)) + + # Then for any complex numbers a, b we will have + # |a - ev(a)| < eps and |b - ev(b)| < eps. + # So if |ev(a) - ev(b)|**2 < eps**2, then + # |ev(a) - ev(b)| < eps, hence |a - b| < 3*eps = delta. + A, B = ev(a), ev(b) + return (A.real - B.real)**2 + (A.imag - B.imag)**2 < eps_sq + + def cancel(f, g, include=False): + """ + Cancel common factors in a rational function ``f/g``. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(2*x**2 - 2, x).cancel(Poly(x**2 - 2*x + 1, x)) + (1, Poly(2*x + 2, x, domain='ZZ'), Poly(x - 1, x, domain='ZZ')) + + >>> Poly(2*x**2 - 2, x).cancel(Poly(x**2 - 2*x + 1, x), include=True) + (Poly(2*x + 2, x, domain='ZZ'), Poly(x - 1, x, domain='ZZ')) + + """ + dom, per, F, G = f._unify(g) + + if hasattr(F, 'cancel'): + result = F.cancel(G, include=include) + else: # pragma: no cover + raise OperationNotSupported(f, 'cancel') + + if not include: + if dom.has_assoc_Ring: + dom = dom.get_ring() + + cp, cq, p, q = result + + cp = dom.to_sympy(cp) + cq = dom.to_sympy(cq) + + return cp/cq, per(p), per(q) + else: + return tuple(map(per, result)) + + def make_monic_over_integers_by_scaling_roots(f): + """ + Turn any univariate polynomial over :ref:`QQ` or :ref:`ZZ` into a monic + polynomial over :ref:`ZZ`, by scaling the roots as necessary. + + Explanation + =========== + + This operation can be performed whether or not *f* is irreducible; when + it is, this can be understood as determining an algebraic integer + generating the same field as a root of *f*. + + Examples + ======== + + >>> from sympy import Poly, S + >>> from sympy.abc import x + >>> f = Poly(x**2/2 + S(1)/4 * x + S(1)/8, x, domain='QQ') + >>> f.make_monic_over_integers_by_scaling_roots() + (Poly(x**2 + 2*x + 4, x, domain='ZZ'), 4) + + Returns + ======= + + Pair ``(g, c)`` + g is the polynomial + + c is the integer by which the roots had to be scaled + + """ + if not f.is_univariate or f.domain not in [ZZ, QQ]: + raise ValueError('Polynomial must be univariate over ZZ or QQ.') + if f.is_monic and f.domain == ZZ: + return f, ZZ.one + else: + fm = f.monic() + c, _ = fm.clear_denoms() + return fm.transform(Poly(fm.gen), c).to_ring(), c + + def galois_group(f, by_name=False, max_tries=30, randomize=False): + """ + Compute the Galois group of this polynomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + >>> f = Poly(x**4 - 2) + >>> G, _ = f.galois_group(by_name=True) + >>> print(G) + S4TransitiveSubgroups.D4 + + See Also + ======== + + sympy.polys.numberfields.galoisgroups.galois_group + + """ + from sympy.polys.numberfields.galoisgroups import ( + _galois_group_degree_3, _galois_group_degree_4_lookup, + _galois_group_degree_5_lookup_ext_factor, + _galois_group_degree_6_lookup, + ) + if (not f.is_univariate + or not f.is_irreducible + or f.domain not in [ZZ, QQ] + ): + raise ValueError('Polynomial must be irreducible and univariate over ZZ or QQ.') + gg = { + 3: _galois_group_degree_3, + 4: _galois_group_degree_4_lookup, + 5: _galois_group_degree_5_lookup_ext_factor, + 6: _galois_group_degree_6_lookup, + } + max_supported = max(gg.keys()) + n = f.degree() + if n > max_supported: + raise ValueError(f"Only polynomials up to degree {max_supported} are supported.") + elif n < 1: + raise ValueError("Constant polynomial has no Galois group.") + elif n == 1: + from sympy.combinatorics.galois import S1TransitiveSubgroups + name, alt = S1TransitiveSubgroups.S1, True + elif n == 2: + from sympy.combinatorics.galois import S2TransitiveSubgroups + name, alt = S2TransitiveSubgroups.S2, False + else: + g, _ = f.make_monic_over_integers_by_scaling_roots() + name, alt = gg[n](g, max_tries=max_tries, randomize=randomize) + G = name if by_name else name.get_perm_group() + return G, alt + + @property + def is_zero(f): + """ + Returns ``True`` if ``f`` is a zero polynomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(0, x).is_zero + True + >>> Poly(1, x).is_zero + False + + """ + return f.rep.is_zero + + @property + def is_one(f): + """ + Returns ``True`` if ``f`` is a unit polynomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(0, x).is_one + False + >>> Poly(1, x).is_one + True + + """ + return f.rep.is_one + + @property + def is_sqf(f): + """ + Returns ``True`` if ``f`` is a square-free polynomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 - 2*x + 1, x).is_sqf + False + >>> Poly(x**2 - 1, x).is_sqf + True + + """ + return f.rep.is_sqf + + @property + def is_monic(f): + """ + Returns ``True`` if the leading coefficient of ``f`` is one. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x + 2, x).is_monic + True + >>> Poly(2*x + 2, x).is_monic + False + + """ + return f.rep.is_monic + + @property + def is_primitive(f): + """ + Returns ``True`` if GCD of the coefficients of ``f`` is one. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(2*x**2 + 6*x + 12, x).is_primitive + False + >>> Poly(x**2 + 3*x + 6, x).is_primitive + True + + """ + return f.rep.is_primitive + + @property + def is_ground(f): + """ + Returns ``True`` if ``f`` is an element of the ground domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x, x).is_ground + False + >>> Poly(2, x).is_ground + True + >>> Poly(y, x).is_ground + True + + """ + return f.rep.is_ground + + @property + def is_linear(f): + """ + Returns ``True`` if ``f`` is linear in all its variables. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x + y + 2, x, y).is_linear + True + >>> Poly(x*y + 2, x, y).is_linear + False + + """ + return f.rep.is_linear + + @property + def is_quadratic(f): + """ + Returns ``True`` if ``f`` is quadratic in all its variables. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x*y + 2, x, y).is_quadratic + True + >>> Poly(x*y**2 + 2, x, y).is_quadratic + False + + """ + return f.rep.is_quadratic + + @property + def is_monomial(f): + """ + Returns ``True`` if ``f`` is zero or has only one term. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(3*x**2, x).is_monomial + True + >>> Poly(3*x**2 + 1, x).is_monomial + False + + """ + return f.rep.is_monomial + + @property + def is_homogeneous(f): + """ + Returns ``True`` if ``f`` is a homogeneous polynomial. + + A homogeneous polynomial is a polynomial whose all monomials with + non-zero coefficients have the same total degree. If you want not + only to check if a polynomial is homogeneous but also compute its + homogeneous order, then use :func:`Poly.homogeneous_order`. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + x*y, x, y).is_homogeneous + True + >>> Poly(x**3 + x*y, x, y).is_homogeneous + False + + """ + return f.rep.is_homogeneous + + @property + def is_irreducible(f): + """ + Returns ``True`` if ``f`` has no factors over its domain. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> Poly(x**2 + x + 1, x, modulus=2).is_irreducible + True + >>> Poly(x**2 + 1, x, modulus=2).is_irreducible + False + + """ + return f.rep.is_irreducible + + @property + def is_univariate(f): + """ + Returns ``True`` if ``f`` is a univariate polynomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + x + 1, x).is_univariate + True + >>> Poly(x*y**2 + x*y + 1, x, y).is_univariate + False + >>> Poly(x*y**2 + x*y + 1, x).is_univariate + True + >>> Poly(x**2 + x + 1, x, y).is_univariate + False + + """ + return len(f.gens) == 1 + + @property + def is_multivariate(f): + """ + Returns ``True`` if ``f`` is a multivariate polynomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x, y + + >>> Poly(x**2 + x + 1, x).is_multivariate + False + >>> Poly(x*y**2 + x*y + 1, x, y).is_multivariate + True + >>> Poly(x*y**2 + x*y + 1, x).is_multivariate + False + >>> Poly(x**2 + x + 1, x, y).is_multivariate + True + + """ + return len(f.gens) != 1 + + @property + def is_cyclotomic(f): + """ + Returns ``True`` if ``f`` is a cyclotomic polnomial. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.abc import x + + >>> f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 + + >>> Poly(f).is_cyclotomic + False + + >>> g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 + + >>> Poly(g).is_cyclotomic + True + + """ + return f.rep.is_cyclotomic + + def __abs__(f): + return f.abs() + + def __neg__(f): + return f.neg() + + @_polifyit + def __add__(f, g): + return f.add(g) + + @_polifyit + def __radd__(f, g): + return g.add(f) + + @_polifyit + def __sub__(f, g): + return f.sub(g) + + @_polifyit + def __rsub__(f, g): + return g.sub(f) + + @_polifyit + def __mul__(f, g): + return f.mul(g) + + @_polifyit + def __rmul__(f, g): + return g.mul(f) + + @_sympifyit('n', NotImplemented) + def __pow__(f, n): + if n.is_Integer and n >= 0: + return f.pow(n) + else: + return NotImplemented + + @_polifyit + def __divmod__(f, g): + return f.div(g) + + @_polifyit + def __rdivmod__(f, g): + return g.div(f) + + @_polifyit + def __mod__(f, g): + return f.rem(g) + + @_polifyit + def __rmod__(f, g): + return g.rem(f) + + @_polifyit + def __floordiv__(f, g): + return f.quo(g) + + @_polifyit + def __rfloordiv__(f, g): + return g.quo(f) + + @_sympifyit('g', NotImplemented) + def __truediv__(f, g): + return f.as_expr()/g.as_expr() + + @_sympifyit('g', NotImplemented) + def __rtruediv__(f, g): + return g.as_expr()/f.as_expr() + + @_sympifyit('other', NotImplemented) + def __eq__(self, other): + f, g = self, other + + if not g.is_Poly: + try: + g = f.__class__(g, f.gens, domain=f.get_domain()) + except (PolynomialError, DomainError, CoercionFailed): + return False + + if f.gens != g.gens: + return False + + if f.rep.dom != g.rep.dom: + return False + + return f.rep == g.rep + + @_sympifyit('g', NotImplemented) + def __ne__(f, g): + return not f == g + + def __bool__(f): + return not f.is_zero + + def eq(f, g, strict=False): + if not strict: + return f == g + else: + return f._strict_eq(sympify(g)) + + def ne(f, g, strict=False): + return not f.eq(g, strict=strict) + + def _strict_eq(f, g): + return isinstance(g, f.__class__) and f.gens == g.gens and f.rep.eq(g.rep, strict=True) + + +@public +class PurePoly(Poly): + """Class for representing pure polynomials. """ + + def _hashable_content(self): + """Allow SymPy to hash Poly instances. """ + return (self.rep,) + + def __hash__(self): + return super().__hash__() + + @property + def free_symbols(self): + """ + Free symbols of a polynomial. + + Examples + ======== + + >>> from sympy import PurePoly + >>> from sympy.abc import x, y + + >>> PurePoly(x**2 + 1).free_symbols + set() + >>> PurePoly(x**2 + y).free_symbols + set() + >>> PurePoly(x**2 + y, x).free_symbols + {y} + + """ + return self.free_symbols_in_domain + + @_sympifyit('other', NotImplemented) + def __eq__(self, other): + f, g = self, other + + if not g.is_Poly: + try: + g = f.__class__(g, f.gens, domain=f.get_domain()) + except (PolynomialError, DomainError, CoercionFailed): + return False + + if len(f.gens) != len(g.gens): + return False + + if f.rep.dom != g.rep.dom: + try: + dom = f.rep.dom.unify(g.rep.dom, f.gens) + except UnificationFailed: + return False + + f = f.set_domain(dom) + g = g.set_domain(dom) + + return f.rep == g.rep + + def _strict_eq(f, g): + return isinstance(g, f.__class__) and f.rep.eq(g.rep, strict=True) + + def _unify(f, g): + g = sympify(g) + + if not g.is_Poly: + try: + return f.rep.dom, f.per, f.rep, f.rep.per(f.rep.dom.from_sympy(g)) + except CoercionFailed: + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + if len(f.gens) != len(g.gens): + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + if not (isinstance(f.rep, DMP) and isinstance(g.rep, DMP)): + raise UnificationFailed("Cannot unify %s with %s" % (f, g)) + + cls = f.__class__ + gens = f.gens + + dom = f.rep.dom.unify(g.rep.dom, gens) + + F = f.rep.convert(dom) + G = g.rep.convert(dom) + + def per(rep, dom=dom, gens=gens, remove=None): + if remove is not None: + gens = gens[:remove] + gens[remove + 1:] + + if not gens: + return dom.to_sympy(rep) + + return cls.new(rep, *gens) + + return dom, per, F, G + + +@public +def poly_from_expr(expr, *gens, **args): + """Construct a polynomial from an expression. """ + opt = options.build_options(gens, args) + return _poly_from_expr(expr, opt) + + +def _poly_from_expr(expr, opt): + """Construct a polynomial from an expression. """ + orig, expr = expr, sympify(expr) + + if not isinstance(expr, Basic): + raise PolificationFailed(opt, orig, expr) + elif expr.is_Poly: + poly = expr.__class__._from_poly(expr, opt) + + opt.gens = poly.gens + opt.domain = poly.domain + + if opt.polys is None: + opt.polys = True + + return poly, opt + elif opt.expand: + expr = expr.expand() + + rep, opt = _dict_from_expr(expr, opt) + if not opt.gens: + raise PolificationFailed(opt, orig, expr) + + monoms, coeffs = list(zip(*list(rep.items()))) + domain = opt.domain + + if domain is None: + opt.domain, coeffs = construct_domain(coeffs, opt=opt) + else: + coeffs = list(map(domain.from_sympy, coeffs)) + + rep = dict(list(zip(monoms, coeffs))) + poly = Poly._from_dict(rep, opt) + + if opt.polys is None: + opt.polys = False + + return poly, opt + + +@public +def parallel_poly_from_expr(exprs, *gens, **args): + """Construct polynomials from expressions. """ + opt = options.build_options(gens, args) + return _parallel_poly_from_expr(exprs, opt) + + +def _parallel_poly_from_expr(exprs, opt): + """Construct polynomials from expressions. """ + if len(exprs) == 2: + f, g = exprs + + if isinstance(f, Poly) and isinstance(g, Poly): + f = f.__class__._from_poly(f, opt) + g = g.__class__._from_poly(g, opt) + + f, g = f.unify(g) + + opt.gens = f.gens + opt.domain = f.domain + + if opt.polys is None: + opt.polys = True + + return [f, g], opt + + origs, exprs = list(exprs), [] + _exprs, _polys = [], [] + + failed = False + + for i, expr in enumerate(origs): + expr = sympify(expr) + + if isinstance(expr, Basic): + if expr.is_Poly: + _polys.append(i) + else: + _exprs.append(i) + + if opt.expand: + expr = expr.expand() + else: + failed = True + + exprs.append(expr) + + if failed: + raise PolificationFailed(opt, origs, exprs, True) + + if _polys: + # XXX: this is a temporary solution + for i in _polys: + exprs[i] = exprs[i].as_expr() + + reps, opt = _parallel_dict_from_expr(exprs, opt) + if not opt.gens: + raise PolificationFailed(opt, origs, exprs, True) + + from sympy.functions.elementary.piecewise import Piecewise + for k in opt.gens: + if isinstance(k, Piecewise): + raise PolynomialError("Piecewise generators do not make sense") + + coeffs_list, lengths = [], [] + + all_monoms = [] + all_coeffs = [] + + for rep in reps: + monoms, coeffs = list(zip(*list(rep.items()))) + + coeffs_list.extend(coeffs) + all_monoms.append(monoms) + + lengths.append(len(coeffs)) + + domain = opt.domain + + if domain is None: + opt.domain, coeffs_list = construct_domain(coeffs_list, opt=opt) + else: + coeffs_list = list(map(domain.from_sympy, coeffs_list)) + + for k in lengths: + all_coeffs.append(coeffs_list[:k]) + coeffs_list = coeffs_list[k:] + + polys = [] + + for monoms, coeffs in zip(all_monoms, all_coeffs): + rep = dict(list(zip(monoms, coeffs))) + poly = Poly._from_dict(rep, opt) + polys.append(poly) + + if opt.polys is None: + opt.polys = bool(_polys) + + return polys, opt + + +def _update_args(args, key, value): + """Add a new ``(key, value)`` pair to arguments ``dict``. """ + args = dict(args) + + if key not in args: + args[key] = value + + return args + + +@public +def degree(f, gen=0): + """ + Return the degree of ``f`` in the given variable. + + The degree of 0 is negative infinity. + + Examples + ======== + + >>> from sympy import degree + >>> from sympy.abc import x, y + + >>> degree(x**2 + y*x + 1, gen=x) + 2 + >>> degree(x**2 + y*x + 1, gen=y) + 1 + >>> degree(0, x) + -oo + + See also + ======== + + sympy.polys.polytools.Poly.total_degree + degree_list + """ + + f = sympify(f, strict=True) + gen_is_Num = sympify(gen, strict=True).is_Number + if f.is_Poly: + p = f + isNum = p.as_expr().is_Number + else: + isNum = f.is_Number + if not isNum: + if gen_is_Num: + p, _ = poly_from_expr(f) + else: + p, _ = poly_from_expr(f, gen) + + if isNum: + return S.Zero if f else S.NegativeInfinity + + if not gen_is_Num: + if f.is_Poly and gen not in p.gens: + # try recast without explicit gens + p, _ = poly_from_expr(f.as_expr()) + if gen not in p.gens: + return S.Zero + elif not f.is_Poly and len(f.free_symbols) > 1: + raise TypeError(filldedent(''' + A symbolic generator of interest is required for a multivariate + expression like func = %s, e.g. degree(func, gen = %s) instead of + degree(func, gen = %s). + ''' % (f, next(ordered(f.free_symbols)), gen))) + result = p.degree(gen) + return Integer(result) if isinstance(result, int) else S.NegativeInfinity + + +@public +def total_degree(f, *gens): + """ + Return the total_degree of ``f`` in the given variables. + + Examples + ======== + >>> from sympy import total_degree, Poly + >>> from sympy.abc import x, y + + >>> total_degree(1) + 0 + >>> total_degree(x + x*y) + 2 + >>> total_degree(x + x*y, x) + 1 + + If the expression is a Poly and no variables are given + then the generators of the Poly will be used: + + >>> p = Poly(x + x*y, y) + >>> total_degree(p) + 1 + + To deal with the underlying expression of the Poly, convert + it to an Expr: + + >>> total_degree(p.as_expr()) + 2 + + This is done automatically if any variables are given: + + >>> total_degree(p, x) + 1 + + See also + ======== + degree + """ + + p = sympify(f) + if p.is_Poly: + p = p.as_expr() + if p.is_Number: + rv = 0 + else: + if f.is_Poly: + gens = gens or f.gens + rv = Poly(p, gens).total_degree() + + return Integer(rv) + + +@public +def degree_list(f, *gens, **args): + """ + Return a list of degrees of ``f`` in all variables. + + Examples + ======== + + >>> from sympy import degree_list + >>> from sympy.abc import x, y + + >>> degree_list(x**2 + y*x + 1) + (2, 1) + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('degree_list', 1, exc) + + degrees = F.degree_list() + + return tuple(map(Integer, degrees)) + + +@public +def LC(f, *gens, **args): + """ + Return the leading coefficient of ``f``. + + Examples + ======== + + >>> from sympy import LC + >>> from sympy.abc import x, y + + >>> LC(4*x**2 + 2*x*y**2 + x*y + 3*y) + 4 + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('LC', 1, exc) + + return F.LC(order=opt.order) + + +@public +def LM(f, *gens, **args): + """ + Return the leading monomial of ``f``. + + Examples + ======== + + >>> from sympy import LM + >>> from sympy.abc import x, y + + >>> LM(4*x**2 + 2*x*y**2 + x*y + 3*y) + x**2 + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('LM', 1, exc) + + monom = F.LM(order=opt.order) + return monom.as_expr() + + +@public +def LT(f, *gens, **args): + """ + Return the leading term of ``f``. + + Examples + ======== + + >>> from sympy import LT + >>> from sympy.abc import x, y + + >>> LT(4*x**2 + 2*x*y**2 + x*y + 3*y) + 4*x**2 + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('LT', 1, exc) + + monom, coeff = F.LT(order=opt.order) + return coeff*monom.as_expr() + + +@public +def pdiv(f, g, *gens, **args): + """ + Compute polynomial pseudo-division of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import pdiv + >>> from sympy.abc import x + + >>> pdiv(x**2 + 1, 2*x - 4) + (2*x + 4, 20) + + """ + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('pdiv', 2, exc) + + q, r = F.pdiv(G) + + if not opt.polys: + return q.as_expr(), r.as_expr() + else: + return q, r + + +@public +def prem(f, g, *gens, **args): + """ + Compute polynomial pseudo-remainder of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import prem + >>> from sympy.abc import x + + >>> prem(x**2 + 1, 2*x - 4) + 20 + + """ + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('prem', 2, exc) + + r = F.prem(G) + + if not opt.polys: + return r.as_expr() + else: + return r + + +@public +def pquo(f, g, *gens, **args): + """ + Compute polynomial pseudo-quotient of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import pquo + >>> from sympy.abc import x + + >>> pquo(x**2 + 1, 2*x - 4) + 2*x + 4 + >>> pquo(x**2 - 1, 2*x - 1) + 2*x + 1 + + """ + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('pquo', 2, exc) + + try: + q = F.pquo(G) + except ExactQuotientFailed: + raise ExactQuotientFailed(f, g) + + if not opt.polys: + return q.as_expr() + else: + return q + + +@public +def pexquo(f, g, *gens, **args): + """ + Compute polynomial exact pseudo-quotient of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import pexquo + >>> from sympy.abc import x + + >>> pexquo(x**2 - 1, 2*x - 2) + 2*x + 2 + + >>> pexquo(x**2 + 1, 2*x - 4) + Traceback (most recent call last): + ... + ExactQuotientFailed: 2*x - 4 does not divide x**2 + 1 + + """ + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('pexquo', 2, exc) + + q = F.pexquo(G) + + if not opt.polys: + return q.as_expr() + else: + return q + + +@public +def div(f, g, *gens, **args): + """ + Compute polynomial division of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import div, ZZ, QQ + >>> from sympy.abc import x + + >>> div(x**2 + 1, 2*x - 4, domain=ZZ) + (0, x**2 + 1) + >>> div(x**2 + 1, 2*x - 4, domain=QQ) + (x/2 + 1, 5) + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('div', 2, exc) + + q, r = F.div(G, auto=opt.auto) + + if not opt.polys: + return q.as_expr(), r.as_expr() + else: + return q, r + + +@public +def rem(f, g, *gens, **args): + """ + Compute polynomial remainder of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import rem, ZZ, QQ + >>> from sympy.abc import x + + >>> rem(x**2 + 1, 2*x - 4, domain=ZZ) + x**2 + 1 + >>> rem(x**2 + 1, 2*x - 4, domain=QQ) + 5 + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('rem', 2, exc) + + r = F.rem(G, auto=opt.auto) + + if not opt.polys: + return r.as_expr() + else: + return r + + +@public +def quo(f, g, *gens, **args): + """ + Compute polynomial quotient of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import quo + >>> from sympy.abc import x + + >>> quo(x**2 + 1, 2*x - 4) + x/2 + 1 + >>> quo(x**2 - 1, x - 1) + x + 1 + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('quo', 2, exc) + + q = F.quo(G, auto=opt.auto) + + if not opt.polys: + return q.as_expr() + else: + return q + + +@public +def exquo(f, g, *gens, **args): + """ + Compute polynomial exact quotient of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import exquo + >>> from sympy.abc import x + + >>> exquo(x**2 - 1, x - 1) + x + 1 + + >>> exquo(x**2 + 1, 2*x - 4) + Traceback (most recent call last): + ... + ExactQuotientFailed: 2*x - 4 does not divide x**2 + 1 + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('exquo', 2, exc) + + q = F.exquo(G, auto=opt.auto) + + if not opt.polys: + return q.as_expr() + else: + return q + + +@public +def half_gcdex(f, g, *gens, **args): + """ + Half extended Euclidean algorithm of ``f`` and ``g``. + + Returns ``(s, h)`` such that ``h = gcd(f, g)`` and ``s*f = h (mod g)``. + + Examples + ======== + + >>> from sympy import half_gcdex + >>> from sympy.abc import x + + >>> half_gcdex(x**4 - 2*x**3 - 6*x**2 + 12*x + 15, x**3 + x**2 - 4*x - 4) + (3/5 - x/5, x + 1) + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + domain, (a, b) = construct_domain(exc.exprs) + + try: + s, h = domain.half_gcdex(a, b) + except NotImplementedError: + raise ComputationFailed('half_gcdex', 2, exc) + else: + return domain.to_sympy(s), domain.to_sympy(h) + + s, h = F.half_gcdex(G, auto=opt.auto) + + if not opt.polys: + return s.as_expr(), h.as_expr() + else: + return s, h + + +@public +def gcdex(f, g, *gens, **args): + """ + Extended Euclidean algorithm of ``f`` and ``g``. + + Returns ``(s, t, h)`` such that ``h = gcd(f, g)`` and ``s*f + t*g = h``. + + Examples + ======== + + >>> from sympy import gcdex + >>> from sympy.abc import x + + >>> gcdex(x**4 - 2*x**3 - 6*x**2 + 12*x + 15, x**3 + x**2 - 4*x - 4) + (3/5 - x/5, x**2/5 - 6*x/5 + 2, x + 1) + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + domain, (a, b) = construct_domain(exc.exprs) + + try: + s, t, h = domain.gcdex(a, b) + except NotImplementedError: + raise ComputationFailed('gcdex', 2, exc) + else: + return domain.to_sympy(s), domain.to_sympy(t), domain.to_sympy(h) + + s, t, h = F.gcdex(G, auto=opt.auto) + + if not opt.polys: + return s.as_expr(), t.as_expr(), h.as_expr() + else: + return s, t, h + + +@public +def invert(f, g, *gens, **args): + """ + Invert ``f`` modulo ``g`` when possible. + + Examples + ======== + + >>> from sympy import invert, S, mod_inverse + >>> from sympy.abc import x + + >>> invert(x**2 - 1, 2*x - 1) + -4/3 + + >>> invert(x**2 - 1, x - 1) + Traceback (most recent call last): + ... + NotInvertible: zero divisor + + For more efficient inversion of Rationals, + use the :obj:`sympy.core.intfunc.mod_inverse` function: + + >>> mod_inverse(3, 5) + 2 + >>> (S(2)/5).invert(S(7)/3) + 5/2 + + See Also + ======== + sympy.core.intfunc.mod_inverse + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + domain, (a, b) = construct_domain(exc.exprs) + + try: + return domain.to_sympy(domain.invert(a, b)) + except NotImplementedError: + raise ComputationFailed('invert', 2, exc) + + h = F.invert(G, auto=opt.auto) + + if not opt.polys: + return h.as_expr() + else: + return h + + +@public +def subresultants(f, g, *gens, **args): + """ + Compute subresultant PRS of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import subresultants + >>> from sympy.abc import x + + >>> subresultants(x**2 + 1, x**2 - 1) + [x**2 + 1, x**2 - 1, -2] + + """ + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('subresultants', 2, exc) + + result = F.subresultants(G) + + if not opt.polys: + return [r.as_expr() for r in result] + else: + return result + + +@public +def resultant(f, g, *gens, includePRS=False, **args): + """ + Compute resultant of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import resultant + >>> from sympy.abc import x + + >>> resultant(x**2 + 1, x**2 - 1) + 4 + + """ + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('resultant', 2, exc) + + if includePRS: + result, R = F.resultant(G, includePRS=includePRS) + else: + result = F.resultant(G) + + if not opt.polys: + if includePRS: + return result.as_expr(), [r.as_expr() for r in R] + return result.as_expr() + else: + if includePRS: + return result, R + return result + + +@public +def discriminant(f, *gens, **args): + """ + Compute discriminant of ``f``. + + Examples + ======== + + >>> from sympy import discriminant + >>> from sympy.abc import x + + >>> discriminant(x**2 + 2*x + 3) + -8 + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('discriminant', 1, exc) + + result = F.discriminant() + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def cofactors(f, g, *gens, **args): + """ + Compute GCD and cofactors of ``f`` and ``g``. + + Returns polynomials ``(h, cff, cfg)`` such that ``h = gcd(f, g)``, and + ``cff = quo(f, h)`` and ``cfg = quo(g, h)`` are, so called, cofactors + of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import cofactors + >>> from sympy.abc import x + + >>> cofactors(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) + + """ + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + domain, (a, b) = construct_domain(exc.exprs) + + try: + h, cff, cfg = domain.cofactors(a, b) + except NotImplementedError: + raise ComputationFailed('cofactors', 2, exc) + else: + return domain.to_sympy(h), domain.to_sympy(cff), domain.to_sympy(cfg) + + h, cff, cfg = F.cofactors(G) + + if not opt.polys: + return h.as_expr(), cff.as_expr(), cfg.as_expr() + else: + return h, cff, cfg + + +@public +def gcd_list(seq, *gens, **args): + """ + Compute GCD of a list of polynomials. + + Examples + ======== + + >>> from sympy import gcd_list + >>> from sympy.abc import x + + >>> gcd_list([x**3 - 1, x**2 - 1, x**2 - 3*x + 2]) + x - 1 + + """ + seq = sympify(seq) + + def try_non_polynomial_gcd(seq): + if not gens and not args: + domain, numbers = construct_domain(seq) + + if not numbers: + return domain.zero + elif domain.is_Numerical: + result, numbers = numbers[0], numbers[1:] + + for number in numbers: + result = domain.gcd(result, number) + + if domain.is_one(result): + break + + return domain.to_sympy(result) + + return None + + result = try_non_polynomial_gcd(seq) + + if result is not None: + return result + + options.allowed_flags(args, ['polys']) + + try: + polys, opt = parallel_poly_from_expr(seq, *gens, **args) + + # gcd for domain Q[irrational] (purely algebraic irrational) + if len(seq) > 1 and all(elt.is_algebraic and elt.is_irrational for elt in seq): + a = seq[-1] + lst = [ (a/elt).ratsimp() for elt in seq[:-1] ] + if all(frc.is_rational for frc in lst): + lc = 1 + for frc in lst: + lc = lcm(lc, frc.as_numer_denom()[0]) + # abs ensures that the gcd is always non-negative + return abs(a/lc) + + except PolificationFailed as exc: + result = try_non_polynomial_gcd(exc.exprs) + + if result is not None: + return result + else: + raise ComputationFailed('gcd_list', len(seq), exc) + + if not polys: + if not opt.polys: + return S.Zero + else: + return Poly(0, opt=opt) + + result, polys = polys[0], polys[1:] + + for poly in polys: + result = result.gcd(poly) + + if result.is_one: + break + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def gcd(f, g=None, *gens, **args): + """ + Compute GCD of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import gcd + >>> from sympy.abc import x + + >>> gcd(x**2 - 1, x**2 - 3*x + 2) + x - 1 + + """ + if hasattr(f, '__iter__'): + if g is not None: + gens = (g,) + gens + + return gcd_list(f, *gens, **args) + elif g is None: + raise TypeError("gcd() takes 2 arguments or a sequence of arguments") + + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + + # gcd for domain Q[irrational] (purely algebraic irrational) + a, b = map(sympify, (f, g)) + if a.is_algebraic and a.is_irrational and b.is_algebraic and b.is_irrational: + frc = (a/b).ratsimp() + if frc.is_rational: + # abs ensures that the returned gcd is always non-negative + return abs(a/frc.as_numer_denom()[0]) + + except PolificationFailed as exc: + domain, (a, b) = construct_domain(exc.exprs) + + try: + return domain.to_sympy(domain.gcd(a, b)) + except NotImplementedError: + raise ComputationFailed('gcd', 2, exc) + + result = F.gcd(G) + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def lcm_list(seq, *gens, **args): + """ + Compute LCM of a list of polynomials. + + Examples + ======== + + >>> from sympy import lcm_list + >>> from sympy.abc import x + + >>> lcm_list([x**3 - 1, x**2 - 1, x**2 - 3*x + 2]) + x**5 - x**4 - 2*x**3 - x**2 + x + 2 + + """ + seq = sympify(seq) + + def try_non_polynomial_lcm(seq) -> Optional[Expr]: + if not gens and not args: + domain, numbers = construct_domain(seq) + + if not numbers: + return domain.to_sympy(domain.one) + elif domain.is_Numerical: + result, numbers = numbers[0], numbers[1:] + + for number in numbers: + result = domain.lcm(result, number) + + return domain.to_sympy(result) + + return None + + result = try_non_polynomial_lcm(seq) + + if result is not None: + return result + + options.allowed_flags(args, ['polys']) + + try: + polys, opt = parallel_poly_from_expr(seq, *gens, **args) + + # lcm for domain Q[irrational] (purely algebraic irrational) + if len(seq) > 1 and all(elt.is_algebraic and elt.is_irrational for elt in seq): + a = seq[-1] + lst = [ (a/elt).ratsimp() for elt in seq[:-1] ] + if all(frc.is_rational for frc in lst): + lc = 1 + for frc in lst: + lc = lcm(lc, frc.as_numer_denom()[1]) + return a*lc + + except PolificationFailed as exc: + result = try_non_polynomial_lcm(exc.exprs) + + if result is not None: + return result + else: + raise ComputationFailed('lcm_list', len(seq), exc) + + if not polys: + if not opt.polys: + return S.One + else: + return Poly(1, opt=opt) + + result, polys = polys[0], polys[1:] + + for poly in polys: + result = result.lcm(poly) + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def lcm(f, g=None, *gens, **args): + """ + Compute LCM of ``f`` and ``g``. + + Examples + ======== + + >>> from sympy import lcm + >>> from sympy.abc import x + + >>> lcm(x**2 - 1, x**2 - 3*x + 2) + x**3 - 2*x**2 - x + 2 + + """ + if hasattr(f, '__iter__'): + if g is not None: + gens = (g,) + gens + + return lcm_list(f, *gens, **args) + elif g is None: + raise TypeError("lcm() takes 2 arguments or a sequence of arguments") + + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + + # lcm for domain Q[irrational] (purely algebraic irrational) + a, b = map(sympify, (f, g)) + if a.is_algebraic and a.is_irrational and b.is_algebraic and b.is_irrational: + frc = (a/b).ratsimp() + if frc.is_rational: + return a*frc.as_numer_denom()[1] + + except PolificationFailed as exc: + domain, (a, b) = construct_domain(exc.exprs) + + try: + return domain.to_sympy(domain.lcm(a, b)) + except NotImplementedError: + raise ComputationFailed('lcm', 2, exc) + + result = F.lcm(G) + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def terms_gcd(f, *gens, **args): + """ + Remove GCD of terms from ``f``. + + If the ``deep`` flag is True, then the arguments of ``f`` will have + terms_gcd applied to them. + + If a fraction is factored out of ``f`` and ``f`` is an Add, then + an unevaluated Mul will be returned so that automatic simplification + does not redistribute it. The hint ``clear``, when set to False, can be + used to prevent such factoring when all coefficients are not fractions. + + Examples + ======== + + >>> from sympy import terms_gcd, cos + >>> from sympy.abc import x, y + >>> terms_gcd(x**6*y**2 + x**3*y, x, y) + x**3*y*(x**3*y + 1) + + The default action of polys routines is to expand the expression + given to them. terms_gcd follows this behavior: + + >>> terms_gcd((3+3*x)*(x+x*y)) + 3*x*(x*y + x + y + 1) + + If this is not desired then the hint ``expand`` can be set to False. + In this case the expression will be treated as though it were comprised + of one or more terms: + + >>> terms_gcd((3+3*x)*(x+x*y), expand=False) + (3*x + 3)*(x*y + x) + + In order to traverse factors of a Mul or the arguments of other + functions, the ``deep`` hint can be used: + + >>> terms_gcd((3 + 3*x)*(x + x*y), expand=False, deep=True) + 3*x*(x + 1)*(y + 1) + >>> terms_gcd(cos(x + x*y), deep=True) + cos(x*(y + 1)) + + Rationals are factored out by default: + + >>> terms_gcd(x + y/2) + (2*x + y)/2 + + Only the y-term had a coefficient that was a fraction; if one + does not want to factor out the 1/2 in cases like this, the + flag ``clear`` can be set to False: + + >>> terms_gcd(x + y/2, clear=False) + x + y/2 + >>> terms_gcd(x*y/2 + y**2, clear=False) + y*(x/2 + y) + + The ``clear`` flag is ignored if all coefficients are fractions: + + >>> terms_gcd(x/3 + y/2, clear=False) + (2*x + 3*y)/6 + + See Also + ======== + sympy.core.exprtools.gcd_terms, sympy.core.exprtools.factor_terms + + """ + + orig = sympify(f) + + if isinstance(f, Equality): + return Equality(*(terms_gcd(s, *gens, **args) for s in [f.lhs, f.rhs])) + elif isinstance(f, Relational): + raise TypeError("Inequalities cannot be used with terms_gcd. Found: %s" %(f,)) + + if not isinstance(f, Expr) or f.is_Atom: + return orig + + if args.get('deep', False): + new = f.func(*[terms_gcd(a, *gens, **args) for a in f.args]) + args.pop('deep') + args['expand'] = False + return terms_gcd(new, *gens, **args) + + clear = args.pop('clear', True) + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + return exc.expr + + J, f = F.terms_gcd() + + if opt.domain.is_Ring: + if opt.domain.is_Field: + denom, f = f.clear_denoms(convert=True) + + coeff, f = f.primitive() + + if opt.domain.is_Field: + coeff /= denom + else: + coeff = S.One + + term = Mul(*[x**j for x, j in zip(f.gens, J)]) + if equal_valued(coeff, 1): + coeff = S.One + if term == 1: + return orig + + if clear: + return _keep_coeff(coeff, term*f.as_expr()) + # base the clearing on the form of the original expression, not + # the (perhaps) Mul that we have now + coeff, f = _keep_coeff(coeff, f.as_expr(), clear=False).as_coeff_Mul() + return _keep_coeff(coeff, term*f, clear=False) + + +@public +def trunc(f, p, *gens, **args): + """ + Reduce ``f`` modulo a constant ``p``. + + Examples + ======== + + >>> from sympy import trunc + >>> from sympy.abc import x + + >>> trunc(2*x**3 + 3*x**2 + 5*x + 7, 3) + -x**3 - x + 1 + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('trunc', 1, exc) + + result = F.trunc(sympify(p)) + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def monic(f, *gens, **args): + """ + Divide all coefficients of ``f`` by ``LC(f)``. + + Examples + ======== + + >>> from sympy import monic + >>> from sympy.abc import x + + >>> monic(3*x**2 + 4*x + 2) + x**2 + 4*x/3 + 2/3 + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('monic', 1, exc) + + result = F.monic(auto=opt.auto) + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def content(f, *gens, **args): + """ + Compute GCD of coefficients of ``f``. + + Examples + ======== + + >>> from sympy import content + >>> from sympy.abc import x + + >>> content(6*x**2 + 8*x + 12) + 2 + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('content', 1, exc) + + return F.content() + + +@public +def primitive(f, *gens, **args): + """ + Compute content and the primitive form of ``f``. + + Examples + ======== + + >>> from sympy.polys.polytools import primitive + >>> from sympy.abc import x + + >>> primitive(6*x**2 + 8*x + 12) + (2, 3*x**2 + 4*x + 6) + + >>> eq = (2 + 2*x)*x + 2 + + Expansion is performed by default: + + >>> primitive(eq) + (2, x**2 + x + 1) + + Set ``expand`` to False to shut this off. Note that the + extraction will not be recursive; use the as_content_primitive method + for recursive, non-destructive Rational extraction. + + >>> primitive(eq, expand=False) + (1, x*(2*x + 2) + 2) + + >>> eq.as_content_primitive() + (2, x*(x + 1) + 1) + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('primitive', 1, exc) + + cont, result = F.primitive() + if not opt.polys: + return cont, result.as_expr() + else: + return cont, result + + +@public +def compose(f, g, *gens, **args): + """ + Compute functional composition ``f(g)``. + + Examples + ======== + + >>> from sympy import compose + >>> from sympy.abc import x + + >>> compose(x**2 + x, x - 1) + x**2 - x + + """ + options.allowed_flags(args, ['polys']) + + try: + (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('compose', 2, exc) + + result = F.compose(G) + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def decompose(f, *gens, **args): + """ + Compute functional decomposition of ``f``. + + Examples + ======== + + >>> from sympy import decompose + >>> from sympy.abc import x + + >>> decompose(x**4 + 2*x**3 - x - 1) + [x**2 - x - 1, x**2 + x] + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('decompose', 1, exc) + + result = F.decompose() + + if not opt.polys: + return [r.as_expr() for r in result] + else: + return result + + +@public +def sturm(f, *gens, **args): + """ + Compute Sturm sequence of ``f``. + + Examples + ======== + + >>> from sympy import sturm + >>> from sympy.abc import x + + >>> sturm(x**3 - 2*x**2 + x - 3) + [x**3 - 2*x**2 + x - 3, 3*x**2 - 4*x + 1, 2*x/9 + 25/9, -2079/4] + + """ + options.allowed_flags(args, ['auto', 'polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('sturm', 1, exc) + + result = F.sturm(auto=opt.auto) + + if not opt.polys: + return [r.as_expr() for r in result] + else: + return result + + +@public +def gff_list(f, *gens, **args): + """ + Compute a list of greatest factorial factors of ``f``. + + Note that the input to ff() and rf() should be Poly instances to use the + definitions here. + + Examples + ======== + + >>> from sympy import gff_list, ff, Poly + >>> from sympy.abc import x + + >>> f = Poly(x**5 + 2*x**4 - x**3 - 2*x**2, x) + + >>> gff_list(f) + [(Poly(x, x, domain='ZZ'), 1), (Poly(x + 2, x, domain='ZZ'), 4)] + + >>> (ff(Poly(x), 1)*ff(Poly(x + 2), 4)) == f + True + + >>> f = Poly(x**12 + 6*x**11 - 11*x**10 - 56*x**9 + 220*x**8 + 208*x**7 - \ + 1401*x**6 + 1090*x**5 + 2715*x**4 - 6720*x**3 - 1092*x**2 + 5040*x, x) + + >>> gff_list(f) + [(Poly(x**3 + 7, x, domain='ZZ'), 2), (Poly(x**2 + 5*x, x, domain='ZZ'), 3)] + + >>> ff(Poly(x**3 + 7, x), 2)*ff(Poly(x**2 + 5*x, x), 3) == f + True + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('gff_list', 1, exc) + + factors = F.gff_list() + + if not opt.polys: + return [(g.as_expr(), k) for g, k in factors] + else: + return factors + + +@public +def gff(f, *gens, **args): + """Compute greatest factorial factorization of ``f``. """ + raise NotImplementedError('symbolic falling factorial') + + +@public +def sqf_norm(f, *gens, **args): + """ + Compute square-free norm of ``f``. + + Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and + ``r(x) = Norm(g(x))`` is a square-free polynomial over ``K``, + where ``a`` is the algebraic extension of the ground domain. + + Examples + ======== + + >>> from sympy import sqf_norm, sqrt + >>> from sympy.abc import x + + >>> sqf_norm(x**2 + 1, extension=[sqrt(3)]) + ([1], x**2 - 2*sqrt(3)*x + 4, x**4 - 4*x**2 + 16) + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('sqf_norm', 1, exc) + + s, g, r = F.sqf_norm() + + s_expr = [Integer(si) for si in s] + + if not opt.polys: + return s_expr, g.as_expr(), r.as_expr() + else: + return s_expr, g, r + + +@public +def sqf_part(f, *gens, **args): + """ + Compute square-free part of ``f``. + + Examples + ======== + + >>> from sympy import sqf_part + >>> from sympy.abc import x + + >>> sqf_part(x**3 - 3*x - 2) + x**2 - x - 2 + + """ + options.allowed_flags(args, ['polys']) + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('sqf_part', 1, exc) + + result = F.sqf_part() + + if not opt.polys: + return result.as_expr() + else: + return result + + +def _poly_sort_key(poly): + """Sort a list of polys.""" + rep = poly.rep.to_list() + return (len(rep), len(poly.gens), str(poly.domain), rep) + + +def _sorted_factors(factors, method): + """Sort a list of ``(expr, exp)`` pairs. """ + if method == 'sqf': + def key(obj): + poly, exp = obj + rep = poly.rep.to_list() + return (exp, len(rep), len(poly.gens), str(poly.domain), rep) + else: + def key(obj): + poly, exp = obj + rep = poly.rep.to_list() + return (len(rep), len(poly.gens), exp, str(poly.domain), rep) + + return sorted(factors, key=key) + + +def _factors_product(factors): + """Multiply a list of ``(expr, exp)`` pairs. """ + return Mul(*[f.as_expr()**k for f, k in factors]) + + +def _symbolic_factor_list(expr, opt, method): + """Helper function for :func:`_symbolic_factor`. """ + coeff, factors = S.One, [] + + args = [i._eval_factor() if hasattr(i, '_eval_factor') else i + for i in Mul.make_args(expr)] + for arg in args: + if arg.is_Number or (isinstance(arg, Expr) and pure_complex(arg)): + coeff *= arg + continue + elif arg.is_Pow and arg.base != S.Exp1: + base, exp = arg.args + if base.is_Number and exp.is_Number: + coeff *= arg + continue + if base.is_Number: + factors.append((base, exp)) + continue + else: + base, exp = arg, S.One + + try: + poly, _ = _poly_from_expr(base, opt) + except PolificationFailed as exc: + factors.append((exc.expr, exp)) + else: + func = getattr(poly, method + '_list') + + _coeff, _factors = func() + if _coeff is not S.One: + if exp.is_Integer: + coeff *= _coeff**exp + elif _coeff.is_positive: + factors.append((_coeff, exp)) + else: + _factors.append((_coeff, S.One)) + + if exp is S.One: + factors.extend(_factors) + elif exp.is_integer: + factors.extend([(f, k*exp) for f, k in _factors]) + else: + other = [] + + for f, k in _factors: + if f.as_expr().is_positive: + factors.append((f, k*exp)) + else: + other.append((f, k)) + + factors.append((_factors_product(other), exp)) + if method == 'sqf': + factors = [(reduce(mul, (f for f, _ in factors if _ == k)), k) + for k in {i for _, i in factors}] + #collect duplicates + rv = defaultdict(int) + for k, v in factors: + rv[k] += v + return coeff, list(rv.items()) + + +def _symbolic_factor(expr, opt, method): + """Helper function for :func:`_factor`. """ + if isinstance(expr, Expr): + if hasattr(expr,'_eval_factor'): + return expr._eval_factor() + coeff, factors = _symbolic_factor_list(together(expr, fraction=opt['fraction']), opt, method) + return _keep_coeff(coeff, _factors_product(factors)) + elif hasattr(expr, 'args'): + return expr.func(*[_symbolic_factor(arg, opt, method) for arg in expr.args]) + elif hasattr(expr, '__iter__'): + return expr.__class__([_symbolic_factor(arg, opt, method) for arg in expr]) + else: + return expr + + +def _generic_factor_list(expr, gens, args, method): + """Helper function for :func:`sqf_list` and :func:`factor_list`. """ + options.allowed_flags(args, ['frac', 'polys']) + opt = options.build_options(gens, args) + + expr = sympify(expr) + + if isinstance(expr, (Expr, Poly)): + if isinstance(expr, Poly): + numer, denom = expr, 1 + else: + numer, denom = together(expr).as_numer_denom() + + cp, fp = _symbolic_factor_list(numer, opt, method) + cq, fq = _symbolic_factor_list(denom, opt, method) + + if fq and not opt.frac: + raise PolynomialError("a polynomial expected, got %s" % expr) + + _opt = opt.clone({"expand": True}) + + for factors in (fp, fq): + for i, (f, k) in enumerate(factors): + if not f.is_Poly: + f, _ = _poly_from_expr(f, _opt) + factors[i] = (f, k) + + fp = _sorted_factors(fp, method) + fq = _sorted_factors(fq, method) + + if not opt.polys: + fp = [(f.as_expr(), k) for f, k in fp] + fq = [(f.as_expr(), k) for f, k in fq] + + coeff = cp/cq + + if not opt.frac: + return coeff, fp + else: + return coeff, fp, fq + else: + raise PolynomialError("a polynomial expected, got %s" % expr) + + +def _generic_factor(expr, gens, args, method): + """Helper function for :func:`sqf` and :func:`factor`. """ + fraction = args.pop('fraction', True) + options.allowed_flags(args, []) + opt = options.build_options(gens, args) + opt['fraction'] = fraction + return _symbolic_factor(sympify(expr), opt, method) + + +def to_rational_coeffs(f): + """ + try to transform a polynomial to have rational coefficients + + try to find a transformation ``x = alpha*y`` + + ``f(x) = lc*alpha**n * g(y)`` where ``g`` is a polynomial with + rational coefficients, ``lc`` the leading coefficient. + + If this fails, try ``x = y + beta`` + ``f(x) = g(y)`` + + Returns ``None`` if ``g`` not found; + ``(lc, alpha, None, g)`` in case of rescaling + ``(None, None, beta, g)`` in case of translation + + Notes + ===== + + Currently it transforms only polynomials without roots larger than 2. + + Examples + ======== + + >>> from sympy import sqrt, Poly, simplify + >>> from sympy.polys.polytools import to_rational_coeffs + >>> from sympy.abc import x + >>> p = Poly(((x**2-1)*(x-2)).subs({x:x*(1 + sqrt(2))}), x, domain='EX') + >>> lc, r, _, g = to_rational_coeffs(p) + >>> lc, r + (7 + 5*sqrt(2), 2 - 2*sqrt(2)) + >>> g + Poly(x**3 + x**2 - 1/4*x - 1/4, x, domain='QQ') + >>> r1 = simplify(1/r) + >>> Poly(lc*r**3*(g.as_expr()).subs({x:x*r1}), x, domain='EX') == p + True + + """ + from sympy.simplify.simplify import simplify + + def _try_rescale(f, f1=None): + """ + try rescaling ``x -> alpha*x`` to convert f to a polynomial + with rational coefficients. + Returns ``alpha, f``; if the rescaling is successful, + ``alpha`` is the rescaling factor, and ``f`` is the rescaled + polynomial; else ``alpha`` is ``None``. + """ + if not len(f.gens) == 1 or not (f.gens[0]).is_Atom: + return None, f + n = f.degree() + lc = f.LC() + f1 = f1 or f1.monic() + coeffs = f1.all_coeffs()[1:] + coeffs = [simplify(coeffx) for coeffx in coeffs] + if len(coeffs) > 1 and coeffs[-2]: + rescale1_x = simplify(coeffs[-2]/coeffs[-1]) + coeffs1 = [] + for i in range(len(coeffs)): + coeffx = simplify(coeffs[i]*rescale1_x**(i + 1)) + if not coeffx.is_rational: + break + coeffs1.append(coeffx) + else: + rescale_x = simplify(1/rescale1_x) + x = f.gens[0] + v = [x**n] + for i in range(1, n + 1): + v.append(coeffs1[i - 1]*x**(n - i)) + f = Add(*v) + f = Poly(f) + return lc, rescale_x, f + return None + + def _try_translate(f, f1=None): + """ + try translating ``x -> x + alpha`` to convert f to a polynomial + with rational coefficients. + Returns ``alpha, f``; if the translating is successful, + ``alpha`` is the translating factor, and ``f`` is the shifted + polynomial; else ``alpha`` is ``None``. + """ + if not len(f.gens) == 1 or not (f.gens[0]).is_Atom: + return None, f + n = f.degree() + f1 = f1 or f1.monic() + coeffs = f1.all_coeffs()[1:] + c = simplify(coeffs[0]) + if c.is_Add and not c.is_rational: + rat, nonrat = sift(c.args, + lambda z: z.is_rational is True, binary=True) + alpha = -c.func(*nonrat)/n + f2 = f1.shift(alpha) + return alpha, f2 + return None + + def _has_square_roots(p): + """ + Return True if ``f`` is a sum with square roots but no other root + """ + coeffs = p.coeffs() + has_sq = False + for y in coeffs: + for x in Add.make_args(y): + f = Factors(x).factors + r = [wx.q for b, wx in f.items() if + b.is_number and wx.is_Rational and wx.q >= 2] + if not r: + continue + if min(r) == 2: + has_sq = True + if max(r) > 2: + return False + return has_sq + + if f.get_domain().is_EX and _has_square_roots(f): + f1 = f.monic() + r = _try_rescale(f, f1) + if r: + return r[0], r[1], None, r[2] + else: + r = _try_translate(f, f1) + if r: + return None, None, r[0], r[1] + return None + + +def _torational_factor_list(p, x): + """ + helper function to factor polynomial using to_rational_coeffs + + Examples + ======== + + >>> from sympy.polys.polytools import _torational_factor_list + >>> from sympy.abc import x + >>> from sympy import sqrt, expand, Mul + >>> p = expand(((x**2-1)*(x-2)).subs({x:x*(1 + sqrt(2))})) + >>> factors = _torational_factor_list(p, x); factors + (-2, [(-x*(1 + sqrt(2))/2 + 1, 1), (-x*(1 + sqrt(2)) - 1, 1), (-x*(1 + sqrt(2)) + 1, 1)]) + >>> expand(factors[0]*Mul(*[z[0] for z in factors[1]])) == p + True + >>> p = expand(((x**2-1)*(x-2)).subs({x:x + sqrt(2)})) + >>> factors = _torational_factor_list(p, x); factors + (1, [(x - 2 + sqrt(2), 1), (x - 1 + sqrt(2), 1), (x + 1 + sqrt(2), 1)]) + >>> expand(factors[0]*Mul(*[z[0] for z in factors[1]])) == p + True + + """ + from sympy.simplify.simplify import simplify + p1 = Poly(p, x, domain='EX') + n = p1.degree() + res = to_rational_coeffs(p1) + if not res: + return None + lc, r, t, g = res + factors = factor_list(g.as_expr()) + if lc: + c = simplify(factors[0]*lc*r**n) + r1 = simplify(1/r) + a = [] + for z in factors[1:][0]: + a.append((simplify(z[0].subs({x: x*r1})), z[1])) + else: + c = factors[0] + a = [] + for z in factors[1:][0]: + a.append((z[0].subs({x: x - t}), z[1])) + return (c, a) + + +@public +def sqf_list(f, *gens, **args): + """ + Compute a list of square-free factors of ``f``. + + Examples + ======== + + >>> from sympy import sqf_list + >>> from sympy.abc import x + + >>> sqf_list(2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16) + (2, [(x + 1, 2), (x + 2, 3)]) + + """ + return _generic_factor_list(f, gens, args, method='sqf') + + +@public +def sqf(f, *gens, **args): + """ + Compute square-free factorization of ``f``. + + Examples + ======== + + >>> from sympy import sqf + >>> from sympy.abc import x + + >>> sqf(2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16) + 2*(x + 1)**2*(x + 2)**3 + + """ + return _generic_factor(f, gens, args, method='sqf') + + +@public +def factor_list(f, *gens, **args): + """ + Compute a list of irreducible factors of ``f``. + + Examples + ======== + + >>> from sympy import factor_list + >>> from sympy.abc import x, y + + >>> factor_list(2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y) + (2, [(x + y, 1), (x**2 + 1, 2)]) + + """ + return _generic_factor_list(f, gens, args, method='factor') + + +@public +def factor(f, *gens, deep=False, **args): + """ + Compute the factorization of expression, ``f``, into irreducibles. (To + factor an integer into primes, use ``factorint``.) + + There two modes implemented: symbolic and formal. If ``f`` is not an + instance of :class:`Poly` and generators are not specified, then the + former mode is used. Otherwise, the formal mode is used. + + In symbolic mode, :func:`factor` will traverse the expression tree and + factor its components without any prior expansion, unless an instance + of :class:`~.Add` is encountered (in this case formal factorization is + used). This way :func:`factor` can handle large or symbolic exponents. + + By default, the factorization is computed over the rationals. To factor + over other domain, e.g. an algebraic or finite field, use appropriate + options: ``extension``, ``modulus`` or ``domain``. + + Examples + ======== + + >>> from sympy import factor, sqrt, exp + >>> from sympy.abc import x, y + + >>> factor(2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y) + 2*(x + y)*(x**2 + 1)**2 + + >>> factor(x**2 + 1) + x**2 + 1 + >>> factor(x**2 + 1, modulus=2) + (x + 1)**2 + >>> factor(x**2 + 1, gaussian=True) + (x - I)*(x + I) + + >>> factor(x**2 - 2, extension=sqrt(2)) + (x - sqrt(2))*(x + sqrt(2)) + + >>> factor((x**2 - 1)/(x**2 + 4*x + 4)) + (x - 1)*(x + 1)/(x + 2)**2 + >>> factor((x**2 + 4*x + 4)**10000000*(x**2 + 1)) + (x + 2)**20000000*(x**2 + 1) + + By default, factor deals with an expression as a whole: + + >>> eq = 2**(x**2 + 2*x + 1) + >>> factor(eq) + 2**(x**2 + 2*x + 1) + + If the ``deep`` flag is True then subexpressions will + be factored: + + >>> factor(eq, deep=True) + 2**((x + 1)**2) + + If the ``fraction`` flag is False then rational expressions + will not be combined. By default it is True. + + >>> factor(5*x + 3*exp(2 - 7*x), deep=True) + (5*x*exp(7*x) + 3*exp(2))*exp(-7*x) + >>> factor(5*x + 3*exp(2 - 7*x), deep=True, fraction=False) + 5*x + 3*exp(2)*exp(-7*x) + + See Also + ======== + sympy.ntheory.factor_.factorint + + """ + f = sympify(f) + if deep: + def _try_factor(expr): + """ + Factor, but avoid changing the expression when unable to. + """ + fac = factor(expr, *gens, **args) + if fac.is_Mul or fac.is_Pow: + return fac + return expr + + f = bottom_up(f, _try_factor) + # clean up any subexpressions that may have been expanded + # while factoring out a larger expression + partials = {} + muladd = f.atoms(Mul, Add) + for p in muladd: + fac = factor(p, *gens, **args) + if (fac.is_Mul or fac.is_Pow) and fac != p: + partials[p] = fac + return f.xreplace(partials) + + try: + return _generic_factor(f, gens, args, method='factor') + except PolynomialError: + if not f.is_commutative: + return factor_nc(f) + else: + raise + + +@public +def intervals(F, all=False, eps=None, inf=None, sup=None, strict=False, fast=False, sqf=False): + """ + Compute isolating intervals for roots of ``f``. + + Examples + ======== + + >>> from sympy import intervals + >>> from sympy.abc import x + + >>> intervals(x**2 - 3) + [((-2, -1), 1), ((1, 2), 1)] + >>> intervals(x**2 - 3, eps=1e-2) + [((-26/15, -19/11), 1), ((19/11, 26/15), 1)] + + """ + if not hasattr(F, '__iter__'): + try: + F = Poly(F) + except GeneratorsNeeded: + return [] + + return F.intervals(all=all, eps=eps, inf=inf, sup=sup, fast=fast, sqf=sqf) + else: + polys, opt = parallel_poly_from_expr(F, domain='QQ') + + if len(opt.gens) > 1: + raise MultivariatePolynomialError + + for i, poly in enumerate(polys): + polys[i] = poly.rep.to_list() + + if eps is not None: + eps = opt.domain.convert(eps) + + if eps <= 0: + raise ValueError("'eps' must be a positive rational") + + if inf is not None: + inf = opt.domain.convert(inf) + if sup is not None: + sup = opt.domain.convert(sup) + + intervals = dup_isolate_real_roots_list(polys, opt.domain, + eps=eps, inf=inf, sup=sup, strict=strict, fast=fast) + + result = [] + + for (s, t), indices in intervals: + s, t = opt.domain.to_sympy(s), opt.domain.to_sympy(t) + result.append(((s, t), indices)) + + return result + + +@public +def refine_root(f, s, t, eps=None, steps=None, fast=False, check_sqf=False): + """ + Refine an isolating interval of a root to the given precision. + + Examples + ======== + + >>> from sympy import refine_root + >>> from sympy.abc import x + + >>> refine_root(x**2 - 3, 1, 2, eps=1e-2) + (19/11, 26/15) + + """ + try: + F = Poly(f) + if not isinstance(f, Poly) and not F.gen.is_Symbol: + # root of sin(x) + 1 is -1 but when someone + # passes an Expr instead of Poly they may not expect + # that the generator will be sin(x), not x + raise PolynomialError("generator must be a Symbol") + except GeneratorsNeeded: + raise PolynomialError( + "Cannot refine a root of %s, not a polynomial" % f) + + return F.refine_root(s, t, eps=eps, steps=steps, fast=fast, check_sqf=check_sqf) + + +@public +def count_roots(f, inf=None, sup=None): + """ + Return the number of roots of ``f`` in ``[inf, sup]`` interval. + + If one of ``inf`` or ``sup`` is complex, it will return the number of roots + in the complex rectangle with corners at ``inf`` and ``sup``. + + Examples + ======== + + >>> from sympy import count_roots, I + >>> from sympy.abc import x + + >>> count_roots(x**4 - 4, -3, 3) + 2 + >>> count_roots(x**4 - 4, 0, 1 + 3*I) + 1 + + """ + try: + F = Poly(f, greedy=False) + if not isinstance(f, Poly) and not F.gen.is_Symbol: + # root of sin(x) + 1 is -1 but when someone + # passes an Expr instead of Poly they may not expect + # that the generator will be sin(x), not x + raise PolynomialError("generator must be a Symbol") + except GeneratorsNeeded: + raise PolynomialError("Cannot count roots of %s, not a polynomial" % f) + + return F.count_roots(inf=inf, sup=sup) + + +@public +def all_roots(f, multiple=True, radicals=True, extension=False): + """ + Returns the real and complex roots of ``f`` with multiplicities. + + Explanation + =========== + + Finds all real and complex roots of a univariate polynomial with rational + coefficients of any degree exactly. The roots are represented in the form + given by :func:`~.rootof`. This is equivalent to using :func:`~.rootof` to + find each of the indexed roots. + + Examples + ======== + + >>> from sympy import all_roots + >>> from sympy.abc import x, y + + >>> print(all_roots(x**3 + 1)) + [-1, 1/2 - sqrt(3)*I/2, 1/2 + sqrt(3)*I/2] + + Simple radical formulae are used in some cases but the cubic and quartic + formulae are avoided. Instead most non-rational roots will be represented + as :class:`~.ComplexRootOf`: + + >>> print(all_roots(x**3 + x + 1)) + [CRootOf(x**3 + x + 1, 0), CRootOf(x**3 + x + 1, 1), CRootOf(x**3 + x + 1, 2)] + + All roots of any polynomial with rational coefficients of any degree can be + represented using :py:class:`~.ComplexRootOf`. The use of + :py:class:`~.ComplexRootOf` bypasses limitations on the availability of + radical formulae for quintic and higher degree polynomials _[1]: + + >>> p = x**5 - x - 1 + >>> for r in all_roots(p): print(r) + CRootOf(x**5 - x - 1, 0) + CRootOf(x**5 - x - 1, 1) + CRootOf(x**5 - x - 1, 2) + CRootOf(x**5 - x - 1, 3) + CRootOf(x**5 - x - 1, 4) + >>> [r.evalf(3) for r in all_roots(p)] + [1.17, -0.765 - 0.352*I, -0.765 + 0.352*I, 0.181 - 1.08*I, 0.181 + 1.08*I] + + Irrational algebraic coefficients are handled by :func:`all_roots` + if `extension=True` is set. + + >>> from sympy import sqrt, expand + >>> p = expand((x - sqrt(2))*(x - sqrt(3))) + >>> print(p) + x**2 - sqrt(3)*x - sqrt(2)*x + sqrt(6) + >>> all_roots(p) + Traceback (most recent call last): + ... + NotImplementedError: sorted roots not supported over EX + >>> all_roots(p, extension=True) + [sqrt(2), sqrt(3)] + + Algebraic coefficients can be complex as well. + + >>> from sympy import I + >>> all_roots(x**2 - I, extension=True) + [-sqrt(2)/2 - sqrt(2)*I/2, sqrt(2)/2 + sqrt(2)*I/2] + >>> all_roots(x**2 - sqrt(2)*I, extension=True) + [-2**(3/4)/2 - 2**(3/4)*I/2, 2**(3/4)/2 + 2**(3/4)*I/2] + + Transcendental coefficients cannot currently be handled by + :func:`all_roots`. In the case of algebraic or transcendental coefficients + :func:`~.ground_roots` might be able to find some roots by factorisation: + + >>> from sympy import ground_roots + >>> ground_roots(p, x, extension=True) + {sqrt(2): 1, sqrt(3): 1} + + If the coefficients are numeric then :func:`~.nroots` can be used to find + all roots approximately: + + >>> from sympy import nroots + >>> nroots(p, 5) + [1.4142, 1.732] + + If the coefficients are symbolic then :func:`sympy.polys.polyroots.roots` + or :func:`~.ground_roots` should be used instead: + + >>> from sympy import roots, ground_roots + >>> p = x**2 - 3*x*y + 2*y**2 + >>> roots(p, x) + {y: 1, 2*y: 1} + >>> ground_roots(p, x) + {y: 1, 2*y: 1} + + Parameters + ========== + + f : :class:`~.Expr` or :class:`~.Poly` + A univariate polynomial with rational (or ``Float``) coefficients. + multiple : ``bool`` (default ``True``). + Whether to return a ``list`` of roots or a list of root/multiplicity + pairs. + radicals : ``bool`` (default ``True``) + Use simple radical formulae rather than :py:class:`~.ComplexRootOf` for + some irrational roots. + extension: ``bool`` (default ``False``) + Whether to construct an algebraic extension domain before computing + the roots. Setting to ``True`` is necessary for finding roots of a + polynomial with (irrational) algebraic coefficients but can be slow. + + Returns + ======= + + A list of :class:`~.Expr` (usually :class:`~.ComplexRootOf`) representing + the roots is returned with each root repeated according to its multiplicity + as a root of ``f``. The roots are always uniquely ordered with real roots + coming before complex roots. The real roots are in increasing order. + Complex roots are ordered by increasing real part and then increasing + imaginary part. + + If ``multiple=False`` is passed then a list of root/multiplicity pairs is + returned instead. + + If ``radicals=False`` is passed then all roots will be represented as + either rational numbers or :class:`~.ComplexRootOf`. + + See also + ======== + + Poly.all_roots: + The underlying :class:`Poly` method used by :func:`~.all_roots`. + rootof: + Compute a single numbered root of a univariate polynomial. + real_roots: + Compute all the real roots using :func:`~.rootof`. + ground_roots: + Compute some roots in the ground domain by factorisation. + nroots: + Compute all roots using approximate numerical techniques. + sympy.polys.polyroots.roots: + Compute symbolic expressions for roots using radical formulae. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Abel%E2%80%93Ruffini_theorem + """ + try: + if isinstance(f, Poly): + if extension and not f.domain.is_AlgebraicField: + F = Poly(f.expr, extension=True) + else: + F = f + else: + if extension: + F = Poly(f, extension=True) + else: + F = Poly(f, greedy=False) + + if not isinstance(f, Poly) and not F.gen.is_Symbol: + # root of sin(x) + 1 is -1 but when someone + # passes an Expr instead of Poly they may not expect + # that the generator will be sin(x), not x + raise PolynomialError("generator must be a Symbol") + except GeneratorsNeeded: + raise PolynomialError( + "Cannot compute real roots of %s, not a polynomial" % f) + + return F.all_roots(multiple=multiple, radicals=radicals) + + +@public +def real_roots(f, multiple=True, radicals=True, extension=False): + """ + Returns the real roots of ``f`` with multiplicities. + + Explanation + =========== + + Finds all real roots of a univariate polynomial with rational coefficients + of any degree exactly. The roots are represented in the form given by + :func:`~.rootof`. This is equivalent to using :func:`~.rootof` or + :func:`~.all_roots` and filtering out only the real roots. However if only + the real roots are needed then :func:`real_roots` is more efficient than + :func:`~.all_roots` because it computes only the real roots and avoids + costly complex root isolation routines. + + Examples + ======== + + >>> from sympy import real_roots + >>> from sympy.abc import x, y + + >>> real_roots(2*x**3 - 7*x**2 + 4*x + 4) + [-1/2, 2, 2] + >>> real_roots(2*x**3 - 7*x**2 + 4*x + 4, multiple=False) + [(-1/2, 1), (2, 2)] + + Real roots of any polynomial with rational coefficients of any degree can + be represented using :py:class:`~.ComplexRootOf`: + + >>> p = x**9 + 2*x + 2 + >>> print(real_roots(p)) + [CRootOf(x**9 + 2*x + 2, 0)] + >>> [r.evalf(3) for r in real_roots(p)] + [-0.865] + + All rational roots will be returned as rational numbers. Roots of some + simple factors will be expressed using radical or other formulae (unless + ``radicals=False`` is passed). All other roots will be expressed as + :class:`~.ComplexRootOf`. + + >>> p = (x + 7)*(x**2 - 2)*(x**3 + x + 1) + >>> print(real_roots(p)) + [-7, -sqrt(2), CRootOf(x**3 + x + 1, 0), sqrt(2)] + >>> print(real_roots(p, radicals=False)) + [-7, CRootOf(x**2 - 2, 0), CRootOf(x**3 + x + 1, 0), CRootOf(x**2 - 2, 1)] + + All returned root expressions will numerically evaluate to real numbers + with no imaginary part. This is in contrast to the expressions generated by + the cubic or quartic formulae as used by :func:`~.roots` which suffer from + casus irreducibilis [1]_: + + >>> from sympy import roots + >>> p = 2*x**3 - 9*x**2 - 6*x + 3 + >>> [r.evalf(5) for r in roots(p, multiple=True)] + [5.0365 - 0.e-11*I, 0.33984 + 0.e-13*I, -0.87636 + 0.e-10*I] + >>> [r.evalf(5) for r in real_roots(p, x)] + [-0.87636, 0.33984, 5.0365] + >>> [r.is_real for r in roots(p, multiple=True)] + [None, None, None] + >>> [r.is_real for r in real_roots(p)] + [True, True, True] + + Using :func:`real_roots` is equivalent to using :func:`~.all_roots` (or + :func:`~.rootof`) and filtering out only the real roots: + + >>> from sympy import all_roots + >>> r = [r for r in all_roots(p) if r.is_real] + >>> real_roots(p) == r + True + + If only the real roots are wanted then using :func:`real_roots` is faster + than using :func:`~.all_roots`. Using :func:`real_roots` avoids complex root + isolation which can be a lot slower than real root isolation especially for + polynomials of high degree which typically have many more complex roots + than real roots. + + Irrational algebraic coefficients are handled by :func:`real_roots` + if `extension=True` is set. + + >>> from sympy import sqrt, expand + >>> p = expand((x - sqrt(2))*(x - sqrt(3))) + >>> print(p) + x**2 - sqrt(3)*x - sqrt(2)*x + sqrt(6) + >>> real_roots(p) + Traceback (most recent call last): + ... + NotImplementedError: sorted roots not supported over EX + >>> real_roots(p, extension=True) + [sqrt(2), sqrt(3)] + + Transcendental coefficients cannot currently be handled by + :func:`real_roots`. In the case of algebraic or transcendental coefficients + :func:`~.ground_roots` might be able to find some roots by factorisation: + + >>> from sympy import ground_roots + >>> ground_roots(p, x, extension=True) + {sqrt(2): 1, sqrt(3): 1} + + If the coefficients are numeric then :func:`~.nroots` can be used to find + all roots approximately: + + >>> from sympy import nroots + >>> nroots(p, 5) + [1.4142, 1.732] + + If the coefficients are symbolic then :func:`sympy.polys.polyroots.roots` + or :func:`~.ground_roots` should be used instead. + + >>> from sympy import roots, ground_roots + >>> p = x**2 - 3*x*y + 2*y**2 + >>> roots(p, x) + {y: 1, 2*y: 1} + >>> ground_roots(p, x) + {y: 1, 2*y: 1} + + Parameters + ========== + + f : :class:`~.Expr` or :class:`~.Poly` + A univariate polynomial with rational (or ``Float``) coefficients. + multiple : ``bool`` (default ``True``). + Whether to return a ``list`` of roots or a list of root/multiplicity + pairs. + radicals : ``bool`` (default ``True``) + Use simple radical formulae rather than :py:class:`~.ComplexRootOf` for + some irrational roots. + extension: ``bool`` (default ``False``) + Whether to construct an algebraic extension domain before computing + the roots. Setting to ``True`` is necessary for finding roots of a + polynomial with (irrational) algebraic coefficients but can be slow. + + Returns + ======= + + A list of :class:`~.Expr` (usually :class:`~.ComplexRootOf`) representing + the real roots is returned. The roots are arranged in increasing order and + are repeated according to their multiplicities as roots of ``f``. + + If ``multiple=False`` is passed then a list of root/multiplicity pairs is + returned instead. + + If ``radicals=False`` is passed then all roots will be represented as + either rational numbers or :class:`~.ComplexRootOf`. + + See also + ======== + + Poly.real_roots: + The underlying :class:`Poly` method used by :func:`real_roots`. + rootof: + Compute a single numbered root of a univariate polynomial. + all_roots: + Compute all real and non-real roots using :func:`~.rootof`. + ground_roots: + Compute some roots in the ground domain by factorisation. + nroots: + Compute all roots using approximate numerical techniques. + sympy.polys.polyroots.roots: + Compute symbolic expressions for roots using radical formulae. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Casus_irreducibilis + """ + try: + if isinstance(f, Poly): + if extension and not f.domain.is_AlgebraicField: + F = Poly(f.expr, extension=True) + else: + F = f + else: + if extension: + F = Poly(f, extension=True) + else: + F = Poly(f, greedy=False) + + if not isinstance(f, Poly) and not F.gen.is_Symbol: + # root of sin(x) + 1 is -1 but when someone + # passes an Expr instead of Poly they may not expect + # that the generator will be sin(x), not x + raise PolynomialError("generator must be a Symbol") + except GeneratorsNeeded: + raise PolynomialError( + "Cannot compute real roots of %s, not a polynomial" % f) + + return F.real_roots(multiple=multiple, radicals=radicals) + + +@public +def nroots(f, n=15, maxsteps=50, cleanup=True): + """ + Compute numerical approximations of roots of ``f``. + + Examples + ======== + + >>> from sympy import nroots + >>> from sympy.abc import x + + >>> nroots(x**2 - 3, n=15) + [-1.73205080756888, 1.73205080756888] + >>> nroots(x**2 - 3, n=30) + [-1.73205080756887729352744634151, 1.73205080756887729352744634151] + + """ + try: + F = Poly(f, greedy=False) + if not isinstance(f, Poly) and not F.gen.is_Symbol: + # root of sin(x) + 1 is -1 but when someone + # passes an Expr instead of Poly they may not expect + # that the generator will be sin(x), not x + raise PolynomialError("generator must be a Symbol") + except GeneratorsNeeded: + raise PolynomialError( + "Cannot compute numerical roots of %s, not a polynomial" % f) + + return F.nroots(n=n, maxsteps=maxsteps, cleanup=cleanup) + + +@public +def ground_roots(f, *gens, **args): + """ + Compute roots of ``f`` by factorization in the ground domain. + + Examples + ======== + + >>> from sympy import ground_roots + >>> from sympy.abc import x + + >>> ground_roots(x**6 - 4*x**4 + 4*x**3 - x**2) + {0: 2, 1: 2} + + """ + options.allowed_flags(args, []) + + try: + F, opt = poly_from_expr(f, *gens, **args) + if not isinstance(f, Poly) and not F.gen.is_Symbol: + # root of sin(x) + 1 is -1 but when someone + # passes an Expr instead of Poly they may not expect + # that the generator will be sin(x), not x + raise PolynomialError("generator must be a Symbol") + except PolificationFailed as exc: + raise ComputationFailed('ground_roots', 1, exc) + + return F.ground_roots() + + +@public +def nth_power_roots_poly(f, n, *gens, **args): + """ + Construct a polynomial with n-th powers of roots of ``f``. + + Examples + ======== + + >>> from sympy import nth_power_roots_poly, factor, roots + >>> from sympy.abc import x + + >>> f = x**4 - x**2 + 1 + >>> g = factor(nth_power_roots_poly(f, 2)) + + >>> g + (x**2 - x + 1)**2 + + >>> R_f = [ (r**2).expand() for r in roots(f) ] + >>> R_g = roots(g).keys() + + >>> set(R_f) == set(R_g) + True + + """ + options.allowed_flags(args, []) + + try: + F, opt = poly_from_expr(f, *gens, **args) + if not isinstance(f, Poly) and not F.gen.is_Symbol: + # root of sin(x) + 1 is -1 but when someone + # passes an Expr instead of Poly they may not expect + # that the generator will be sin(x), not x + raise PolynomialError("generator must be a Symbol") + except PolificationFailed as exc: + raise ComputationFailed('nth_power_roots_poly', 1, exc) + + result = F.nth_power_roots_poly(n) + + if not opt.polys: + return result.as_expr() + else: + return result + + +@public +def cancel(f, *gens, _signsimp=True, **args): + """ + Cancel common factors in a rational function ``f``. + + Examples + ======== + + >>> from sympy import cancel, sqrt, Symbol, together + >>> from sympy.abc import x + >>> A = Symbol('A', commutative=False) + + >>> cancel((2*x**2 - 2)/(x**2 - 2*x + 1)) + (2*x + 2)/(x - 1) + >>> cancel((sqrt(3) + sqrt(15)*A)/(sqrt(2) + sqrt(10)*A)) + sqrt(6)/2 + + Note: due to automatic distribution of Rationals, a sum divided by an integer + will appear as a sum. To recover a rational form use `together` on the result: + + >>> cancel(x/2 + 1) + x/2 + 1 + >>> together(_) + (x + 2)/2 + """ + from sympy.simplify.simplify import signsimp + from sympy.polys.rings import sring + options.allowed_flags(args, ['polys']) + + f = sympify(f) + if _signsimp: + f = signsimp(f) + opt = {} + if 'polys' in args: + opt['polys'] = args['polys'] + + if not isinstance(f, Tuple): + if f.is_Number or isinstance(f, Relational) or not isinstance(f, Expr): + return f + f = factor_terms(f, radical=True) + p, q = f.as_numer_denom() + + elif len(f) == 2: + p, q = f + if isinstance(p, Poly) and isinstance(q, Poly): + opt['gens'] = p.gens + opt['domain'] = p.domain + opt['polys'] = opt.get('polys', True) + p, q = p.as_expr(), q.as_expr() + else: + raise ValueError('unexpected argument: %s' % f) + + from sympy.functions.elementary.piecewise import Piecewise + try: + if f.has(Piecewise): + raise PolynomialError() + R, (F, G) = sring((p, q), *gens, **args) + if not R.ngens: + if not isinstance(f, Tuple): + return f.expand() + else: + return S.One, p, q + except PolynomialError as msg: + if f.is_commutative and not f.has(Piecewise): + raise PolynomialError(msg) + # Handling of noncommutative and/or piecewise expressions + if f.is_Add or f.is_Mul: + c, nc = sift(f.args, lambda x: + x.is_commutative is True and not x.has(Piecewise), + binary=True) + nc = [cancel(i) for i in nc] + return f.func(cancel(f.func(*c)), *nc) + else: + reps = [] + pot = preorder_traversal(f) + next(pot) + for e in pot: + if isinstance(e, BooleanAtom) or not isinstance(e, Expr): + continue + try: + reps.append((e, cancel(e))) + pot.skip() # this was handled successfully + except NotImplementedError: + pass + return f.xreplace(dict(reps)) + + c, (P, Q) = 1, F.cancel(G) + if opt.get('polys', False) and 'gens' not in opt: + opt['gens'] = R.symbols + + if not isinstance(f, Tuple): + return c*(P.as_expr()/Q.as_expr()) + else: + P, Q = P.as_expr(), Q.as_expr() + if not opt.get('polys', False): + return c, P, Q + else: + return c, Poly(P, *gens, **opt), Poly(Q, *gens, **opt) + + +@public +def reduced(f, G, *gens, **args): + """ + Reduces a polynomial ``f`` modulo a set of polynomials ``G``. + + Given a polynomial ``f`` and a set of polynomials ``G = (g_1, ..., g_n)``, + computes a set of quotients ``q = (q_1, ..., q_n)`` and the remainder ``r`` + such that ``f = q_1*g_1 + ... + q_n*g_n + r``, where ``r`` vanishes or ``r`` + is a completely reduced polynomial with respect to ``G``. + + Examples + ======== + + >>> from sympy import reduced + >>> from sympy.abc import x, y + + >>> reduced(2*x**4 + y**2 - x**2 + y**3, [x**3 - x, y**3 - y]) + ([2*x, 1], x**2 + y**2 + y) + + """ + options.allowed_flags(args, ['polys', 'auto']) + + try: + polys, opt = parallel_poly_from_expr([f] + list(G), *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('reduced', 0, exc) + + domain = opt.domain + retract = False + + if opt.auto and domain.is_Ring and not domain.is_Field: + opt = opt.clone({"domain": domain.get_field()}) + retract = True + + from sympy.polys.rings import xring + _ring, _ = xring(opt.gens, opt.domain, opt.order) + + for i, poly in enumerate(polys): + poly = poly.set_domain(opt.domain).rep.to_dict() + polys[i] = _ring.from_dict(poly) + + Q, r = polys[0].div(polys[1:]) + + Q = [Poly._from_dict(dict(q), opt) for q in Q] + r = Poly._from_dict(dict(r), opt) + + if retract: + try: + _Q, _r = [q.to_ring() for q in Q], r.to_ring() + except CoercionFailed: + pass + else: + Q, r = _Q, _r + + if not opt.polys: + return [q.as_expr() for q in Q], r.as_expr() + else: + return Q, r + + +@public +def groebner(F, *gens, **args): + """ + Computes the reduced Groebner basis for a set of polynomials. + + Use the ``order`` argument to set the monomial ordering that will be + used to compute the basis. Allowed orders are ``lex``, ``grlex`` and + ``grevlex``. If no order is specified, it defaults to ``lex``. + + For more information on Groebner bases, see the references and the docstring + of :func:`~.solve_poly_system`. + + Examples + ======== + + Example taken from [1]. + + >>> from sympy import groebner + >>> from sympy.abc import x, y + + >>> F = [x*y - 2*y, 2*y**2 - x**2] + + >>> groebner(F, x, y, order='lex') + GroebnerBasis([x**2 - 2*y**2, x*y - 2*y, y**3 - 2*y], x, y, + domain='ZZ', order='lex') + >>> groebner(F, x, y, order='grlex') + GroebnerBasis([y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y], x, y, + domain='ZZ', order='grlex') + >>> groebner(F, x, y, order='grevlex') + GroebnerBasis([y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y], x, y, + domain='ZZ', order='grevlex') + + By default, an improved implementation of the Buchberger algorithm is + used. Optionally, an implementation of the F5B algorithm can be used. The + algorithm can be set using the ``method`` flag or with the + :func:`sympy.polys.polyconfig.setup` function. + + >>> F = [x**2 - x - 1, (2*x - 1) * y - (x**10 - (1 - x)**10)] + + >>> groebner(F, x, y, method='buchberger') + GroebnerBasis([x**2 - x - 1, y - 55], x, y, domain='ZZ', order='lex') + >>> groebner(F, x, y, method='f5b') + GroebnerBasis([x**2 - x - 1, y - 55], x, y, domain='ZZ', order='lex') + + References + ========== + + 1. [Buchberger01]_ + 2. [Cox97]_ + + """ + return GroebnerBasis(F, *gens, **args) + + +@public +def is_zero_dimensional(F, *gens, **args): + """ + Checks if the ideal generated by a Groebner basis is zero-dimensional. + + The algorithm checks if the set of monomials not divisible by the + leading monomial of any element of ``F`` is bounded. + + References + ========== + + David A. Cox, John B. Little, Donal O'Shea. Ideals, Varieties and + Algorithms, 3rd edition, p. 230 + + """ + return GroebnerBasis(F, *gens, **args).is_zero_dimensional + + +@public +class GroebnerBasis(Basic): + """Represents a reduced Groebner basis. """ + + def __new__(cls, F, *gens, **args): + """Compute a reduced Groebner basis for a system of polynomials. """ + options.allowed_flags(args, ['polys', 'method']) + + try: + polys, opt = parallel_poly_from_expr(F, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('groebner', len(F), exc) + + from sympy.polys.rings import PolyRing + ring = PolyRing(opt.gens, opt.domain, opt.order) + + polys = [ring.from_dict(poly.rep.to_dict()) for poly in polys if poly] + + G = _groebner(polys, ring, method=opt.method) + G = [Poly._from_dict(g, opt) for g in G] + + return cls._new(G, opt) + + @classmethod + def _new(cls, basis, options): + obj = Basic.__new__(cls) + + obj._basis = tuple(basis) + obj._options = options + + return obj + + @property + def args(self): + basis = (p.as_expr() for p in self._basis) + return (Tuple(*basis), Tuple(*self._options.gens)) + + @property + def exprs(self): + return [poly.as_expr() for poly in self._basis] + + @property + def polys(self): + return list(self._basis) + + @property + def gens(self): + return self._options.gens + + @property + def domain(self): + return self._options.domain + + @property + def order(self): + return self._options.order + + def __len__(self): + return len(self._basis) + + def __iter__(self): + if self._options.polys: + return iter(self.polys) + else: + return iter(self.exprs) + + def __getitem__(self, item): + if self._options.polys: + basis = self.polys + else: + basis = self.exprs + + return basis[item] + + def __hash__(self): + return hash((self._basis, tuple(self._options.items()))) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self._basis == other._basis and self._options == other._options + elif iterable(other): + return self.polys == list(other) or self.exprs == list(other) + else: + return False + + def __ne__(self, other): + return not self == other + + @property + def is_zero_dimensional(self): + """ + Checks if the ideal generated by a Groebner basis is zero-dimensional. + + The algorithm checks if the set of monomials not divisible by the + leading monomial of any element of ``F`` is bounded. + + References + ========== + + David A. Cox, John B. Little, Donal O'Shea. Ideals, Varieties and + Algorithms, 3rd edition, p. 230 + + """ + def single_var(monomial): + return sum(map(bool, monomial)) == 1 + + exponents = Monomial([0]*len(self.gens)) + order = self._options.order + + for poly in self.polys: + monomial = poly.LM(order=order) + + if single_var(monomial): + exponents *= monomial + + # If any element of the exponents vector is zero, then there's + # a variable for which there's no degree bound and the ideal + # generated by this Groebner basis isn't zero-dimensional. + return all(exponents) + + def fglm(self, order): + """ + Convert a Groebner basis from one ordering to another. + + The FGLM algorithm converts reduced Groebner bases of zero-dimensional + ideals from one ordering to another. This method is often used when it + is infeasible to compute a Groebner basis with respect to a particular + ordering directly. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import groebner + + >>> F = [x**2 - 3*y - x + 1, y**2 - 2*x + y - 1] + >>> G = groebner(F, x, y, order='grlex') + + >>> list(G.fglm('lex')) + [2*x - y**2 - y + 1, y**4 + 2*y**3 - 3*y**2 - 16*y + 7] + >>> list(groebner(F, x, y, order='lex')) + [2*x - y**2 - y + 1, y**4 + 2*y**3 - 3*y**2 - 16*y + 7] + + References + ========== + + .. [1] J.C. Faugere, P. Gianni, D. Lazard, T. Mora (1994). Efficient + Computation of Zero-dimensional Groebner Bases by Change of + Ordering + + """ + opt = self._options + + src_order = opt.order + dst_order = monomial_key(order) + + if src_order == dst_order: + return self + + if not self.is_zero_dimensional: + raise NotImplementedError("Cannot convert Groebner bases of ideals with positive dimension") + + polys = list(self._basis) + domain = opt.domain + + opt = opt.clone({ + "domain": domain.get_field(), + "order": dst_order, + }) + + from sympy.polys.rings import xring + _ring, _ = xring(opt.gens, opt.domain, src_order) + + for i, poly in enumerate(polys): + poly = poly.set_domain(opt.domain).rep.to_dict() + polys[i] = _ring.from_dict(poly) + + G = matrix_fglm(polys, _ring, dst_order) + G = [Poly._from_dict(dict(g), opt) for g in G] + + if not domain.is_Field: + G = [g.clear_denoms(convert=True)[1] for g in G] + opt.domain = domain + + return self._new(G, opt) + + def reduce(self, expr, auto=True): + """ + Reduces a polynomial modulo a Groebner basis. + + Given a polynomial ``f`` and a set of polynomials ``G = (g_1, ..., g_n)``, + computes a set of quotients ``q = (q_1, ..., q_n)`` and the remainder ``r`` + such that ``f = q_1*f_1 + ... + q_n*f_n + r``, where ``r`` vanishes or ``r`` + is a completely reduced polynomial with respect to ``G``. + + Examples + ======== + + >>> from sympy import groebner, expand, Poly + >>> from sympy.abc import x, y + + >>> f = 2*x**4 - x**2 + y**3 + y**2 + >>> G = groebner([x**3 - x, y**3 - y]) + + >>> G.reduce(f) + ([2*x, 1], x**2 + y**2 + y) + >>> Q, r = _ + + >>> expand(sum(q*g for q, g in zip(Q, G)) + r) + 2*x**4 - x**2 + y**3 + y**2 + >>> _ == f + True + + # Using Poly input + >>> f_poly = Poly(f, x, y) + >>> G = groebner([Poly(x**3 - x), Poly(y**3 - y)]) + + >>> G.reduce(f_poly) + ([Poly(2*x, x, y, domain='ZZ'), Poly(1, x, y, domain='ZZ')], Poly(x**2 + y**2 + y, x, y, domain='ZZ')) + + """ + if isinstance(expr, Poly): + + if expr.gens != self._options.gens: + raise ValueError("Polynomial generators don't match Groebner basis generators") + poly = expr.set_domain(self._options.domain) + else: + + poly = Poly._from_expr(expr, self._options) + + polys = [poly] + list(self._basis) + + opt = self._options + domain = opt.domain + + retract = False + + if auto and domain.is_Ring and not domain.is_Field: + opt = opt.clone({"domain": domain.get_field()}) + retract = True + + from sympy.polys.rings import xring + _ring, _ = xring(opt.gens, opt.domain, opt.order) + + for i, poly in enumerate(polys): + poly = poly.set_domain(opt.domain).rep.to_dict() + polys[i] = _ring.from_dict(poly) + + Q, r = polys[0].div(polys[1:]) + + Q = [Poly._from_dict(dict(q), opt) for q in Q] + r = Poly._from_dict(dict(r), opt) + + if retract: + try: + _Q, _r = [q.to_ring() for q in Q], r.to_ring() + except CoercionFailed: + pass + else: + Q, r = _Q, _r + + if not opt.polys: + return [q.as_expr() for q in Q], r.as_expr() + else: + return Q, r + + def contains(self, poly): + """ + Check if ``poly`` belongs the ideal generated by ``self``. + + Examples + ======== + + >>> from sympy import groebner + >>> from sympy.abc import x, y + + >>> f = 2*x**3 + y**3 + 3*y + >>> G = groebner([x**2 + y**2 - 1, x*y - 2]) + + >>> G.contains(f) + True + >>> G.contains(f + 1) + False + + """ + return self.reduce(poly)[1] == 0 + + +@public +def poly(expr, *gens, **args): + """ + Efficiently transform an expression into a polynomial. + + Examples + ======== + + >>> from sympy import poly + >>> from sympy.abc import x + + >>> poly(x*(x**2 + x - 1)**2) + Poly(x**5 + 2*x**4 - x**3 - 2*x**2 + x, x, domain='ZZ') + + """ + options.allowed_flags(args, []) + + def _poly(expr, opt): + terms, poly_terms = [], [] + + for term in Add.make_args(expr): + factors, poly_factors = [], [] + + for factor in Mul.make_args(term): + if factor.is_Add: + poly_factors.append(_poly(factor, opt)) + elif factor.is_Pow and factor.base.is_Add and \ + factor.exp.is_Integer and factor.exp >= 0: + poly_factors.append( + _poly(factor.base, opt).pow(factor.exp)) + else: + factors.append(factor) + + if not poly_factors: + terms.append(term) + else: + product = poly_factors[0] + + for factor in poly_factors[1:]: + product = product.mul(factor) + + if factors: + factor = Mul(*factors) + + if factor.is_Number: + product *= factor + else: + product = product.mul(Poly._from_expr(factor, opt)) + + poly_terms.append(product) + + if not poly_terms: + result = Poly._from_expr(expr, opt) + else: + result = poly_terms[0] + + for term in poly_terms[1:]: + result = result.add(term) + + if terms: + term = Add(*terms) + + if term.is_Number: + result += term + else: + result = result.add(Poly._from_expr(term, opt)) + + return result.reorder(*opt.get('gens', ()), **args) + + expr = sympify(expr) + + if expr.is_Poly: + return Poly(expr, *gens, **args) + + if 'expand' not in args: + args['expand'] = False + + opt = options.build_options(gens, args) + + return _poly(expr, opt) + + +def named_poly(n, f, K, name, x, polys): + r"""Common interface to the low-level polynomial generating functions + in orthopolys and appellseqs. + + Parameters + ========== + + n : int + Index of the polynomial, which may or may not equal its degree. + f : callable + Low-level generating function to use. + K : Domain or None + Domain in which to perform the computations. If None, use the smallest + field containing the rationals and the extra parameters of x (see below). + name : str + Name of an arbitrary individual polynomial in the sequence generated + by f, only used in the error message for invalid n. + x : seq + The first element of this argument is the main variable of all + polynomials in this sequence. Any further elements are extra + parameters required by f. + polys : bool, optional + If True, return a Poly, otherwise (default) return an expression. + """ + if n < 0: + raise ValueError("Cannot generate %s of index %s" % (name, n)) + head, tail = x[0], x[1:] + if K is None: + K, tail = construct_domain(tail, field=True) + poly = DMP(f(int(n), *tail, K), K) + if head is None: + poly = PurePoly.new(poly, Dummy('x')) + else: + poly = Poly.new(poly, head) + return poly if polys else poly.as_expr() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyutils.py new file mode 100644 index 0000000000000000000000000000000000000000..6a2019d3b195891d84ce8e0b368f6bdc5f45d4b3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/polyutils.py @@ -0,0 +1,584 @@ +"""Useful utilities for higher level polynomial classes. """ + +from __future__ import annotations + +from sympy.external.gmpy import GROUND_TYPES + +from sympy.core import (S, Add, Mul, Pow, Eq, Expr, + expand_mul, expand_multinomial) +from sympy.core.exprtools import decompose_power, decompose_power_rat +from sympy.core.numbers import _illegal +from sympy.polys.polyerrors import PolynomialError, GeneratorsError +from sympy.polys.polyoptions import build_options + +import re + + +_gens_order = { + 'a': 301, 'b': 302, 'c': 303, 'd': 304, + 'e': 305, 'f': 306, 'g': 307, 'h': 308, + 'i': 309, 'j': 310, 'k': 311, 'l': 312, + 'm': 313, 'n': 314, 'o': 315, 'p': 216, + 'q': 217, 'r': 218, 's': 219, 't': 220, + 'u': 221, 'v': 222, 'w': 223, 'x': 124, + 'y': 125, 'z': 126, +} + +_max_order = 1000 +_re_gen = re.compile(r"^(.*?)(\d*)$", re.MULTILINE) + + +def _nsort(roots, separated=False): + """Sort the numerical roots putting the real roots first, then sorting + according to real and imaginary parts. If ``separated`` is True, then + the real and imaginary roots will be returned in two lists, respectively. + + This routine tries to avoid issue 6137 by separating the roots into real + and imaginary parts before evaluation. In addition, the sorting will raise + an error if any computation cannot be done with precision. + """ + if not all(r.is_number for r in roots): + raise NotImplementedError + if not len(roots): + return [] if not separated else ([], []) + # see issue 6137: + # get the real part of the evaluated real and imaginary parts of each root + key = [[i.n(2).as_real_imag()[0] for i in r.as_real_imag()] for r in roots] + # make sure the parts were computed with precision + if len(roots) > 1 and any(i._prec == 1 for k in key for i in k): + raise NotImplementedError("could not compute root with precision") + # insert a key to indicate if the root has an imaginary part + key = [(1 if i else 0, r, i) for r, i in key] + key = sorted(zip(key, roots)) + # return the real and imaginary roots separately if desired + if separated: + r = [] + i = [] + for (im, _, _), v in key: + if im: + i.append(v) + else: + r.append(v) + return r, i + _, roots = zip(*key) + return list(roots) + + +def _sort_gens(gens, **args): + """Sort generators in a reasonably intelligent way. """ + opt = build_options(args) + + gens_order, wrt = {}, None + + if opt is not None: + gens_order, wrt = {}, opt.wrt + + for i, gen in enumerate(opt.sort): + gens_order[gen] = i + 1 + + def order_key(gen): + gen = str(gen) + + if wrt is not None: + try: + return (-len(wrt) + wrt.index(gen), gen, 0) + except ValueError: + pass + + name, index = _re_gen.match(gen).groups() + + if index: + index = int(index) + else: + index = 0 + + try: + return ( gens_order[name], name, index) + except KeyError: + pass + + try: + return (_gens_order[name], name, index) + except KeyError: + pass + + return (_max_order, name, index) + + try: + gens = sorted(gens, key=order_key) + except TypeError: # pragma: no cover + pass + + return tuple(gens) + + +def _unify_gens(f_gens, g_gens): + """Unify generators in a reasonably intelligent way. """ + f_gens = list(f_gens) + g_gens = list(g_gens) + + if f_gens == g_gens: + return tuple(f_gens) + + gens, common, k = [], [], 0 + + for gen in f_gens: + if gen in g_gens: + common.append(gen) + + for i, gen in enumerate(g_gens): + if gen in common: + g_gens[i], k = common[k], k + 1 + + for gen in common: + i = f_gens.index(gen) + + gens.extend(f_gens[:i]) + f_gens = f_gens[i + 1:] + + i = g_gens.index(gen) + + gens.extend(g_gens[:i]) + g_gens = g_gens[i + 1:] + + gens.append(gen) + + gens.extend(f_gens) + gens.extend(g_gens) + + return tuple(gens) + + +def _analyze_gens(gens): + """Support for passing generators as `*gens` and `[gens]`. """ + if len(gens) == 1 and hasattr(gens[0], '__iter__'): + return tuple(gens[0]) + else: + return tuple(gens) + + +def _sort_factors(factors, **args): + """Sort low-level factors in increasing 'complexity' order. """ + + # XXX: GF(p) does not support comparisons so we need a key function to sort + # the factors if python-flint is being used. A better solution might be to + # add a sort key method to each domain. + def order_key(factor): + if isinstance(factor, _GF_types): + return int(factor) + elif isinstance(factor, list): + return [order_key(f) for f in factor] + else: + return factor + + def order_if_multiple_key(factor): + (f, n) = factor + return (len(f), n, order_key(f)) + + def order_no_multiple_key(f): + return (len(f), order_key(f)) + + if args.get('multiple', True): + return sorted(factors, key=order_if_multiple_key) + else: + return sorted(factors, key=order_no_multiple_key) + + +illegal_types = [type(obj) for obj in _illegal] +finf = [float(i) for i in _illegal[1:3]] + + +def _not_a_coeff(expr): + """Do not treat NaN and infinities as valid polynomial coefficients. """ + if type(expr) in illegal_types or expr in finf: + return True + if isinstance(expr, float) and float(expr) != expr: + return True # nan + return # could be + + +def _parallel_dict_from_expr_if_gens(exprs, opt): + """Transform expressions into a multinomial form given generators. """ + k, indices = len(opt.gens), {} + + for i, g in enumerate(opt.gens): + indices[g] = i + + polys = [] + + for expr in exprs: + poly = {} + + if expr.is_Equality: + expr = expr.lhs - expr.rhs + + for term in Add.make_args(expr): + coeff, monom = [], [0]*k + + for factor in Mul.make_args(term): + if not _not_a_coeff(factor) and factor.is_Number: + coeff.append(factor) + else: + try: + if opt.series is False: + base, exp = decompose_power(factor) + + if exp < 0: + exp, base = -exp, Pow(base, -S.One) + else: + base, exp = decompose_power_rat(factor) + + monom[indices[base]] = exp + except KeyError: + if not factor.has_free(*opt.gens): + coeff.append(factor) + else: + raise PolynomialError("%s contains an element of " + "the set of generators." % factor) + + monom = tuple(monom) + + if monom in poly: + poly[monom] += Mul(*coeff) + else: + poly[monom] = Mul(*coeff) + + polys.append(poly) + + return polys, opt.gens + + +def _parallel_dict_from_expr_no_gens(exprs, opt): + """Transform expressions into a multinomial form and figure out generators. """ + if opt.domain is not None: + def _is_coeff(factor): + return factor in opt.domain + elif opt.extension is True: + def _is_coeff(factor): + return factor.is_algebraic + elif opt.greedy is not False: + def _is_coeff(factor): + return factor is S.ImaginaryUnit + else: + def _is_coeff(factor): + return factor.is_number + + gens, reprs = set(), [] + + for expr in exprs: + terms = [] + + if expr.is_Equality: + expr = expr.lhs - expr.rhs + + for term in Add.make_args(expr): + coeff, elements = [], {} + + for factor in Mul.make_args(term): + if not _not_a_coeff(factor) and (factor.is_Number or _is_coeff(factor)): + coeff.append(factor) + else: + if opt.series is False: + base, exp = decompose_power(factor) + + if exp < 0: + exp, base = -exp, Pow(base, -S.One) + else: + base, exp = decompose_power_rat(factor) + + elements[base] = elements.setdefault(base, 0) + exp + gens.add(base) + + terms.append((coeff, elements)) + + reprs.append(terms) + + gens = _sort_gens(gens, opt=opt) + k, indices = len(gens), {} + + for i, g in enumerate(gens): + indices[g] = i + + polys = [] + + for terms in reprs: + poly = {} + + for coeff, term in terms: + monom = [0]*k + + for base, exp in term.items(): + monom[indices[base]] = exp + + monom = tuple(monom) + + if monom in poly: + poly[monom] += Mul(*coeff) + else: + poly[monom] = Mul(*coeff) + + polys.append(poly) + + return polys, tuple(gens) + + +def _dict_from_expr_if_gens(expr, opt): + """Transform an expression into a multinomial form given generators. """ + (poly,), gens = _parallel_dict_from_expr_if_gens((expr,), opt) + return poly, gens + + +def _dict_from_expr_no_gens(expr, opt): + """Transform an expression into a multinomial form and figure out generators. """ + (poly,), gens = _parallel_dict_from_expr_no_gens((expr,), opt) + return poly, gens + + +def parallel_dict_from_expr(exprs, **args): + """Transform expressions into a multinomial form. """ + reps, opt = _parallel_dict_from_expr(exprs, build_options(args)) + return reps, opt.gens + + +def _parallel_dict_from_expr(exprs, opt): + """Transform expressions into a multinomial form. """ + if opt.expand is not False: + exprs = [ expr.expand() for expr in exprs ] + + if any(expr.is_commutative is False for expr in exprs): + raise PolynomialError('non-commutative expressions are not supported') + + if opt.gens: + reps, gens = _parallel_dict_from_expr_if_gens(exprs, opt) + else: + reps, gens = _parallel_dict_from_expr_no_gens(exprs, opt) + + return reps, opt.clone({'gens': gens}) + + +def dict_from_expr(expr, **args): + """Transform an expression into a multinomial form. """ + rep, opt = _dict_from_expr(expr, build_options(args)) + return rep, opt.gens + + +def _dict_from_expr(expr, opt): + """Transform an expression into a multinomial form. """ + if expr.is_commutative is False: + raise PolynomialError('non-commutative expressions are not supported') + + def _is_expandable_pow(expr): + return (expr.is_Pow and expr.exp.is_positive and expr.exp.is_Integer + and expr.base.is_Add) + + if opt.expand is not False: + if not isinstance(expr, (Expr, Eq)): + raise PolynomialError('expression must be of type Expr') + expr = expr.expand() + # TODO: Integrate this into expand() itself + while any(_is_expandable_pow(i) or i.is_Mul and + any(_is_expandable_pow(j) for j in i.args) for i in + Add.make_args(expr)): + + expr = expand_multinomial(expr) + while any(i.is_Mul and any(j.is_Add for j in i.args) for i in Add.make_args(expr)): + expr = expand_mul(expr) + + if opt.gens: + rep, gens = _dict_from_expr_if_gens(expr, opt) + else: + rep, gens = _dict_from_expr_no_gens(expr, opt) + + return rep, opt.clone({'gens': gens}) + + +def expr_from_dict(rep, *gens): + """Convert a multinomial form into an expression. """ + result = [] + + for monom, coeff in rep.items(): + term = [coeff] + for g, m in zip(gens, monom): + if m: + term.append(Pow(g, m)) + + result.append(Mul(*term)) + + return Add(*result) + +parallel_dict_from_basic = parallel_dict_from_expr +dict_from_basic = dict_from_expr +basic_from_dict = expr_from_dict + + +def _dict_reorder(rep, gens, new_gens): + """Reorder levels using dict representation. """ + gens = list(gens) + + monoms = rep.keys() + coeffs = rep.values() + + new_monoms = [ [] for _ in range(len(rep)) ] + used_indices = set() + + for gen in new_gens: + try: + j = gens.index(gen) + used_indices.add(j) + + for M, new_M in zip(monoms, new_monoms): + new_M.append(M[j]) + except ValueError: + for new_M in new_monoms: + new_M.append(0) + + for i, _ in enumerate(gens): + if i not in used_indices: + for monom in monoms: + if monom[i]: + raise GeneratorsError("unable to drop generators") + + return map(tuple, new_monoms), coeffs + + +class PicklableWithSlots: + """ + Mixin class that allows to pickle objects with ``__slots__``. + + Examples + ======== + + First define a class that mixes :class:`PicklableWithSlots` in:: + + >>> from sympy.polys.polyutils import PicklableWithSlots + >>> class Some(PicklableWithSlots): + ... __slots__ = ('foo', 'bar') + ... + ... def __init__(self, foo, bar): + ... self.foo = foo + ... self.bar = bar + + To make :mod:`pickle` happy in doctest we have to use these hacks:: + + >>> import builtins + >>> builtins.Some = Some + >>> from sympy.polys import polyutils + >>> polyutils.Some = Some + + Next lets see if we can create an instance, pickle it and unpickle:: + + >>> some = Some('abc', 10) + >>> some.foo, some.bar + ('abc', 10) + + >>> from pickle import dumps, loads + >>> some2 = loads(dumps(some)) + + >>> some2.foo, some2.bar + ('abc', 10) + + """ + + __slots__ = () + + def __getstate__(self, cls=None): + if cls is None: + # This is the case for the instance that gets pickled + cls = self.__class__ + + d = {} + + # Get all data that should be stored from super classes + for c in cls.__bases__: + # XXX: Python 3.11 defines object.__getstate__ and it does not + # accept any arguments so we need to make sure not to call it with + # an argument here. To be compatible with Python < 3.11 we need to + # be careful not to assume that c or object has a __getstate__ + # method though. + getstate = getattr(c, "__getstate__", None) + objstate = getattr(object, "__getstate__", None) + if getstate is not None and getstate is not objstate: + d.update(getstate(self, c)) + + # Get all information that should be stored from cls and return the dict + for name in cls.__slots__: + if hasattr(self, name): + d[name] = getattr(self, name) + + return d + + def __setstate__(self, d): + # All values that were pickled are now assigned to a fresh instance + for name, value in d.items(): + setattr(self, name, value) + + +class IntegerPowerable: + r""" + Mixin class for classes that define a `__mul__` method, and want to be + raised to integer powers in the natural way that follows. Implements + powering via binary expansion, for efficiency. + + By default, only integer powers $\geq 2$ are supported. To support the + first, zeroth, or negative powers, override the corresponding methods, + `_first_power`, `_zeroth_power`, `_negative_power`, below. + """ + + def __pow__(self, e, modulo=None): + if e < 2: + try: + if e == 1: + return self._first_power() + elif e == 0: + return self._zeroth_power() + else: + return self._negative_power(e, modulo=modulo) + except NotImplementedError: + return NotImplemented + else: + bits = [int(d) for d in reversed(bin(e)[2:])] + n = len(bits) + p = self + first = True + for i in range(n): + if bits[i]: + if first: + r = p + first = False + else: + r *= p + if modulo is not None: + r %= modulo + if i < n - 1: + p *= p + if modulo is not None: + p %= modulo + return r + + def _negative_power(self, e, modulo=None): + """ + Compute inverse of self, then raise that to the abs(e) power. + For example, if the class has an `inv()` method, + return self.inv() ** abs(e) % modulo + """ + raise NotImplementedError + + def _zeroth_power(self): + """Return unity element of algebraic struct to which self belongs.""" + raise NotImplementedError + + def _first_power(self): + """Return a copy of self.""" + raise NotImplementedError + + +_GF_types: tuple[type, ...] + + +if GROUND_TYPES == 'flint': + import flint + _GF_types = (flint.nmod, flint.fmpz_mod) +else: + from sympy.polys.domains.modularinteger import ModularInteger + flint = None + _GF_types = (ModularInteger,) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/puiseux.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/puiseux.py new file mode 100644 index 0000000000000000000000000000000000000000..446dc9c1a5e0d873cdf23da37d2c2430ba0bac6e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/puiseux.py @@ -0,0 +1,795 @@ +""" +Puiseux rings. These are used by the ring_series module to represented +truncated Puiseux series. Elements of a Puiseux ring are like polynomials +except that the exponents can be negative or rational rather than just +non-negative integers. +""" + +# Previously the ring_series module used PolyElement to represent Puiseux +# series. This is problematic because it means that PolyElement has to support +# negative and non-integer exponents which most polynomial representations do +# not support. This module provides an implementation of a ring for Puiseux +# series that can be used by ring_series without breaking the basic invariants +# of polynomial rings. +# +# Ideally there would be more of a proper series type that can keep track of +# not just the leading terms of a truncated series but also the precision +# of the series. For now the rings here are just introduced to keep the +# interface that ring_series was using before. + +from __future__ import annotations + +from sympy.polys.domains import QQ +from sympy.polys.rings import PolyRing, PolyElement +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.external.gmpy import gcd, lcm + + +from typing import TYPE_CHECKING + + +if TYPE_CHECKING: + from typing import Any, Unpack + from sympy.core.expr import Expr + from sympy.polys.domains import Domain + from collections.abc import Iterable, Iterator + + +def puiseux_ring( + symbols: str | list[Expr], domain: Domain +) -> tuple[PuiseuxRing, Unpack[tuple[PuiseuxPoly, ...]]]: + """Construct a Puiseux ring. + + This function constructs a Puiseux ring with the given symbols and domain. + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x, y = puiseux_ring('x y', QQ) + >>> R + PuiseuxRing((x, y), QQ) + >>> p = 5*x**QQ(1,2) + 7/y + >>> p + 7*y**(-1) + 5*x**(1/2) + """ + ring = PuiseuxRing(symbols, domain) + return (ring,) + ring.gens # type: ignore + + +class PuiseuxRing: + """Ring of Puiseux polynomials. + + A Puiseux polynomial is a truncated Puiseux series. The exponents of the + monomials can be negative or rational numbers. This ring is used by the + ring_series module: + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> from sympy.polys.ring_series import rs_exp, rs_nth_root + >>> ring, x, y = puiseux_ring('x y', QQ) + >>> f = x**2 + y**3 + >>> f + y**3 + x**2 + >>> f.diff(x) + 2*x + >>> rs_exp(x, x, 5) + 1 + x + 1/2*x**2 + 1/6*x**3 + 1/24*x**4 + + Importantly the Puiseux ring can represent truncated series with negative + and fractional exponents: + + >>> f = 1/x + 1/y**2 + >>> f + x**(-1) + y**(-2) + >>> f.diff(x) + -1*x**(-2) + + >>> rs_nth_root(8*x + x**2 + x**3, 3, x, 5) + 2*x**(1/3) + 1/12*x**(4/3) + 23/288*x**(7/3) + -139/20736*x**(10/3) + + See Also + ======== + + sympy.polys.ring_series.rs_series + PuiseuxPoly + """ + def __init__(self, symbols: str | list[Expr], domain: Domain): + + poly_ring = PolyRing(symbols, domain) + + domain = poly_ring.domain + ngens = poly_ring.ngens + + self.poly_ring = poly_ring + self.domain = domain + + self.symbols = poly_ring.symbols + self.gens = tuple([self.from_poly(g) for g in poly_ring.gens]) + self.ngens = ngens + + self.zero = self.from_poly(poly_ring.zero) + self.one = self.from_poly(poly_ring.one) + + self.zero_monom = poly_ring.zero_monom # type: ignore + self.monomial_mul = poly_ring.monomial_mul # type: ignore + + def __repr__(self) -> str: + return f"PuiseuxRing({self.symbols}, {self.domain})" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, PuiseuxRing): + return NotImplemented + return self.symbols == other.symbols and self.domain == other.domain + + def from_poly(self, poly: PolyElement) -> PuiseuxPoly: + """Create a Puiseux polynomial from a polynomial. + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.puiseux import puiseux_ring + >>> R1, x1 = ring('x', QQ) + >>> R2, x2 = puiseux_ring('x', QQ) + >>> R2.from_poly(x1**2) + x**2 + """ + return PuiseuxPoly(poly, self) + + def from_dict(self, terms: dict[tuple[int, ...], Any]) -> PuiseuxPoly: + """Create a Puiseux polynomial from a dictionary of terms. + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x = puiseux_ring('x', QQ) + >>> R.from_dict({(QQ(1,2),): QQ(3)}) + 3*x**(1/2) + """ + return PuiseuxPoly.from_dict(terms, self) + + def from_int(self, n: int) -> PuiseuxPoly: + """Create a Puiseux polynomial from an integer. + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x = puiseux_ring('x', QQ) + >>> R.from_int(3) + 3 + """ + return self.from_poly(self.poly_ring(n)) + + def domain_new(self, arg: Any) -> Any: + """Create a new element of the domain. + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x = puiseux_ring('x', QQ) + >>> R.domain_new(3) + 3 + >>> QQ.of_type(_) + True + """ + return self.poly_ring.domain_new(arg) + + def ground_new(self, arg: Any) -> PuiseuxPoly: + """Create a new element from a ground element. + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring, PuiseuxPoly + >>> R, x = puiseux_ring('x', QQ) + >>> R.ground_new(3) + 3 + >>> isinstance(_, PuiseuxPoly) + True + """ + return self.from_poly(self.poly_ring.ground_new(arg)) + + def __call__(self, arg: Any) -> PuiseuxPoly: + """Coerce an element into the ring. + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x = puiseux_ring('x', QQ) + >>> R(3) + 3 + >>> R({(QQ(1,2),): QQ(3)}) + 3*x**(1/2) + """ + if isinstance(arg, dict): + return self.from_dict(arg) + else: + return self.from_poly(self.poly_ring(arg)) + + def index(self, x: PuiseuxPoly) -> int: + """Return the index of a generator. + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x, y = puiseux_ring('x y', QQ) + >>> R.index(x) + 0 + >>> R.index(y) + 1 + """ + return self.gens.index(x) + + +def _div_poly_monom(poly: PolyElement, monom: Iterable[int]) -> PolyElement: + ring = poly.ring + div = ring.monomial_div + return ring.from_dict({div(m, monom): c for m, c in poly.terms()}) + + +def _mul_poly_monom(poly: PolyElement, monom: Iterable[int]) -> PolyElement: + ring = poly.ring + mul = ring.monomial_mul + return ring.from_dict({mul(m, monom): c for m, c in poly.terms()}) + + +def _div_monom(monom: Iterable[int], div: Iterable[int]) -> tuple[int, ...]: + return tuple(mi - di for mi, di in zip(monom, div)) + + +class PuiseuxPoly: + """Puiseux polynomial. Represents a truncated Puiseux series. + + See the :class:`PuiseuxRing` class for more information. + + >>> from sympy import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x, y = puiseux_ring('x, y', QQ) + >>> p = 5*x**2 + 7*y**3 + >>> p + 7*y**3 + 5*x**2 + + The internal representation of a Puiseux polynomial wraps a normal + polynomial. To support negative powers the polynomial is considered to be + divided by a monomial. + + >>> p2 = 1/x + 1/y**2 + >>> p2.monom # x*y**2 + (1, 2) + >>> p2.poly + x + y**2 + >>> (y**2 + x) / (x*y**2) == p2 + True + + To support fractional powers the polynomial is considered to be a function + of ``x**(1/nx), y**(1/ny), ...``. The representation keeps track of a + monomial and a list of exponent denominators so that the polynomial can be + used to represent both negative and fractional powers. + + >>> p3 = x**QQ(1,2) + y**QQ(2,3) + >>> p3.ns + (2, 3) + >>> p3.poly + x + y**2 + + See Also + ======== + + sympy.polys.puiseux.PuiseuxRing + sympy.polys.rings.PolyElement + """ + + ring: PuiseuxRing + poly: PolyElement + monom: tuple[int, ...] | None + ns: tuple[int, ...] | None + + def __new__(cls, poly: PolyElement, ring: PuiseuxRing) -> PuiseuxPoly: + return cls._new(ring, poly, None, None) + + @classmethod + def _new( + cls, + ring: PuiseuxRing, + poly: PolyElement, + monom: tuple[int, ...] | None, + ns: tuple[int, ...] | None, + ) -> PuiseuxPoly: + poly, monom, ns = cls._normalize(poly, monom, ns) + return cls._new_raw(ring, poly, monom, ns) + + @classmethod + def _new_raw( + cls, + ring: PuiseuxRing, + poly: PolyElement, + monom: tuple[int, ...] | None, + ns: tuple[int, ...] | None, + ) -> PuiseuxPoly: + obj = object.__new__(cls) + obj.ring = ring + obj.poly = poly + obj.monom = monom + obj.ns = ns + return obj + + def __eq__(self, other: Any) -> bool: + if isinstance(other, PuiseuxPoly): + return ( + self.poly == other.poly + and self.monom == other.monom + and self.ns == other.ns + ) + elif self.monom is None and self.ns is None: + return self.poly.__eq__(other) + else: + return NotImplemented + + @classmethod + def _normalize( + cls, + poly: PolyElement, + monom: tuple[int, ...] | None, + ns: tuple[int, ...] | None, + ) -> tuple[PolyElement, tuple[int, ...] | None, tuple[int, ...] | None]: + if monom is None and ns is None: + return poly, None, None + + if monom is not None: + degs = [max(d, 0) for d in poly.tail_degrees()] + if all(di >= mi for di, mi in zip(degs, monom)): + poly = _div_poly_monom(poly, monom) + monom = None + elif any(degs): + poly = _div_poly_monom(poly, degs) + monom = _div_monom(monom, degs) + + if ns is not None: + factors_d, [poly_d] = poly.deflate() + degrees = poly.degrees() + monom_d = monom if monom is not None else [0] * len(degrees) + ns_new = [] + monom_new = [] + inflations = [] + for fi, ni, di, mi in zip(factors_d, ns, degrees, monom_d): + if di == 0: + g = gcd(ni, mi) + else: + g = gcd(fi, ni, mi) + ns_new.append(ni // g) + monom_new.append(mi // g) + inflations.append(fi // g) + + if any(infl > 1 for infl in inflations): + poly_d = poly_d.inflate(inflations) + + poly = poly_d + + if monom is not None: + monom = tuple(monom_new) + + if all(n == 1 for n in ns_new): + ns = None + else: + ns = tuple(ns_new) + + return poly, monom, ns + + @classmethod + def _monom_fromint( + cls, + monom: tuple[int, ...], + dmonom: tuple[int, ...] | None, + ns: tuple[int, ...] | None, + ) -> tuple[Any, ...]: + if dmonom is not None and ns is not None: + return tuple(QQ(mi - di, ni) for mi, di, ni in zip(monom, dmonom, ns)) + elif dmonom is not None: + return tuple(QQ(mi - di) for mi, di in zip(monom, dmonom)) + elif ns is not None: + return tuple(QQ(mi, ni) for mi, ni in zip(monom, ns)) + else: + return tuple(QQ(mi) for mi in monom) + + @classmethod + def _monom_toint( + cls, + monom: tuple[Any, ...], + dmonom: tuple[int, ...] | None, + ns: tuple[int, ...] | None, + ) -> tuple[int, ...]: + if dmonom is not None and ns is not None: + return tuple( + int((mi * ni).numerator + di) for mi, di, ni in zip(monom, dmonom, ns) + ) + elif dmonom is not None: + return tuple(int(mi.numerator + di) for mi, di in zip(monom, dmonom)) + elif ns is not None: + return tuple(int((mi * ni).numerator) for mi, ni in zip(monom, ns)) + else: + return tuple(int(mi.numerator) for mi in monom) + + def itermonoms(self) -> Iterator[tuple[Any, ...]]: + """Iterate over the monomials of a Puiseux polynomial. + + >>> from sympy import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x, y = puiseux_ring('x, y', QQ) + >>> p = 5*x**2 + 7*y**3 + >>> list(p.itermonoms()) + [(2, 0), (0, 3)] + >>> p[(2, 0)] + 5 + """ + monom, ns = self.monom, self.ns + for m in self.poly.itermonoms(): + yield self._monom_fromint(m, monom, ns) + + def monoms(self) -> list[tuple[Any, ...]]: + """Return a list of the monomials of a Puiseux polynomial.""" + return list(self.itermonoms()) + + def __iter__(self) -> Iterator[tuple[tuple[Any, ...], Any]]: + return self.itermonoms() + + def __getitem__(self, monom: tuple[int, ...]) -> Any: + monom = self._monom_toint(monom, self.monom, self.ns) + return self.poly[monom] + + def __len__(self) -> int: + return len(self.poly) + + def iterterms(self) -> Iterator[tuple[tuple[Any, ...], Any]]: + """Iterate over the terms of a Puiseux polynomial. + + >>> from sympy import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x, y = puiseux_ring('x, y', QQ) + >>> p = 5*x**2 + 7*y**3 + >>> list(p.iterterms()) + [((2, 0), 5), ((0, 3), 7)] + """ + monom, ns = self.monom, self.ns + for m, coeff in self.poly.iterterms(): + mq = self._monom_fromint(m, monom, ns) + yield mq, coeff + + def terms(self) -> list[tuple[tuple[Any, ...], Any]]: + """Return a list of the terms of a Puiseux polynomial.""" + return list(self.iterterms()) + + @property + def is_term(self) -> bool: + """Return True if the Puiseux polynomial is a single term.""" + return self.poly.is_term + + def to_dict(self) -> dict[tuple[int, ...], Any]: + """Return a dictionary representation of a Puiseux polynomial.""" + return dict(self.iterterms()) + + @classmethod + def from_dict( + cls, terms: dict[tuple[Any, ...], Any], ring: PuiseuxRing + ) -> PuiseuxPoly: + """Create a Puiseux polynomial from a dictionary of terms. + + >>> from sympy import QQ + >>> from sympy.polys.puiseux import puiseux_ring, PuiseuxPoly + >>> R, x = puiseux_ring('x', QQ) + >>> PuiseuxPoly.from_dict({(QQ(1,2),): QQ(3)}, R) + 3*x**(1/2) + >>> R.from_dict({(QQ(1,2),): QQ(3)}) + 3*x**(1/2) + """ + ns = [1] * ring.ngens + mon = [0] * ring.ngens + for mo in terms: + ns = [lcm(n, m.denominator) for n, m in zip(ns, mo)] + mon = [min(m, n) for m, n in zip(mo, mon)] + + if not any(mon): + monom = None + else: + monom = tuple(-int((m * n).numerator) for m, n in zip(mon, ns)) + + if all(n == 1 for n in ns): + ns_final = None + else: + ns_final = tuple(ns) + + terms_p = {cls._monom_toint(m, monom, ns_final): coeff for m, coeff in terms.items()} + + poly = ring.poly_ring.from_dict(terms_p) + + return cls._new(ring, poly, monom, ns_final) + + def as_expr(self) -> Expr: + """Convert a Puiseux polynomial to :class:`~sympy.core.expr.Expr`. + + >>> from sympy import QQ, Expr + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x = puiseux_ring('x', QQ) + >>> p = 5*x**2 + 7*x**3 + >>> p.as_expr() + 7*x**3 + 5*x**2 + >>> isinstance(_, Expr) + True + """ + ring = self.ring + dom = ring.domain + symbols = ring.symbols + terms = [] + for monom, coeff in self.iterterms(): + coeff_expr = dom.to_sympy(coeff) + monoms_expr = [] + for i, m in enumerate(monom): + monoms_expr.append(symbols[i] ** m) + terms.append(Mul(coeff_expr, *monoms_expr)) + return Add(*terms) + + def __repr__(self) -> str: + + def format_power(base: str, exp: int) -> str: + if exp == 1: + return base + elif exp >= 0 and int(exp) == exp: + return f"{base}**{exp}" + else: + return f"{base}**({exp})" + + ring = self.ring + dom = ring.domain + + syms = [str(s) for s in ring.symbols] + terms_str = [] + for monom, coeff in sorted(self.terms()): + monom_str = "*".join(format_power(s, e) for s, e in zip(syms, monom) if e) + if coeff == dom.one: + if monom_str: + terms_str.append(monom_str) + else: + terms_str.append("1") + elif not monom_str: + terms_str.append(str(coeff)) + else: + terms_str.append(f"{coeff}*{monom_str}") + + return " + ".join(terms_str) + + def _unify( + self, other: PuiseuxPoly + ) -> tuple[ + PolyElement, PolyElement, tuple[int, ...] | None, tuple[int, ...] | None + ]: + """Bring two Puiseux polynomials to a common monom and ns.""" + poly1, monom1, ns1 = self.poly, self.monom, self.ns + poly2, monom2, ns2 = other.poly, other.monom, other.ns + + if monom1 == monom2 and ns1 == ns2: + return poly1, poly2, monom1, ns1 + + if ns1 == ns2: + ns = ns1 + elif ns1 is not None and ns2 is not None: + ns = tuple(lcm(n1, n2) for n1, n2 in zip(ns1, ns2)) + f1 = [n // n1 for n, n1 in zip(ns, ns1)] + f2 = [n // n2 for n, n2 in zip(ns, ns2)] + poly1 = poly1.inflate(f1) + poly2 = poly2.inflate(f2) + if monom1 is not None: + monom1 = tuple(m * f for m, f in zip(monom1, f1)) + if monom2 is not None: + monom2 = tuple(m * f for m, f in zip(monom2, f2)) + elif ns2 is not None: + ns = ns2 + poly1 = poly1.inflate(ns) + if monom1 is not None: + monom1 = tuple(m * n for m, n in zip(monom1, ns)) + elif ns1 is not None: + ns = ns1 + poly2 = poly2.inflate(ns) + if monom2 is not None: + monom2 = tuple(m * n for m, n in zip(monom2, ns)) + else: + assert False + + if monom1 == monom2: + monom = monom1 + elif monom1 is not None and monom2 is not None: + monom = tuple(max(m1, m2) for m1, m2 in zip(monom1, monom2)) + poly1 = _mul_poly_monom(poly1, _div_monom(monom, monom1)) + poly2 = _mul_poly_monom(poly2, _div_monom(monom, monom2)) + elif monom2 is not None: + monom = monom2 + poly1 = _mul_poly_monom(poly1, monom2) + elif monom1 is not None: + monom = monom1 + poly2 = _mul_poly_monom(poly2, monom1) + else: + assert False + + return poly1, poly2, monom, ns + + def __pos__(self) -> PuiseuxPoly: + return self + + def __neg__(self) -> PuiseuxPoly: + return self._new_raw(self.ring, -self.poly, self.monom, self.ns) + + def __add__(self, other: Any) -> PuiseuxPoly: + if isinstance(other, PuiseuxPoly): + if self.ring != other.ring: + raise ValueError("Cannot add Puiseux polynomials from different rings") + return self._add(other) + domain = self.ring.domain + if isinstance(other, int): + return self._add_ground(domain.convert_from(QQ(other), QQ)) + elif domain.of_type(other): + return self._add_ground(other) + else: + return NotImplemented + + def __radd__(self, other: Any) -> PuiseuxPoly: + domain = self.ring.domain + if isinstance(other, int): + return self._add_ground(domain.convert_from(QQ(other), QQ)) + elif domain.of_type(other): + return self._add_ground(other) + else: + return NotImplemented + + def __sub__(self, other: Any) -> PuiseuxPoly: + if isinstance(other, PuiseuxPoly): + if self.ring != other.ring: + raise ValueError( + "Cannot subtract Puiseux polynomials from different rings" + ) + return self._sub(other) + domain = self.ring.domain + if isinstance(other, int): + return self._sub_ground(domain.convert_from(QQ(other), QQ)) + elif domain.of_type(other): + return self._sub_ground(other) + else: + return NotImplemented + + def __rsub__(self, other: Any) -> PuiseuxPoly: + domain = self.ring.domain + if isinstance(other, int): + return self._rsub_ground(domain.convert_from(QQ(other), QQ)) + elif domain.of_type(other): + return self._rsub_ground(other) + else: + return NotImplemented + + def __mul__(self, other: Any) -> PuiseuxPoly: + if isinstance(other, PuiseuxPoly): + if self.ring != other.ring: + raise ValueError( + "Cannot multiply Puiseux polynomials from different rings" + ) + return self._mul(other) + domain = self.ring.domain + if isinstance(other, int): + return self._mul_ground(domain.convert_from(QQ(other), QQ)) + elif domain.of_type(other): + return self._mul_ground(other) + else: + return NotImplemented + + def __rmul__(self, other: Any) -> PuiseuxPoly: + domain = self.ring.domain + if isinstance(other, int): + return self._mul_ground(domain.convert_from(QQ(other), QQ)) + elif domain.of_type(other): + return self._mul_ground(other) + else: + return NotImplemented + + def __pow__(self, other: Any) -> PuiseuxPoly: + if isinstance(other, int): + if other >= 0: + return self._pow_pint(other) + else: + return self._pow_nint(-other) + elif QQ.of_type(other): + return self._pow_rational(other) + else: + return NotImplemented + + def __truediv__(self, other: Any) -> PuiseuxPoly: + if isinstance(other, PuiseuxPoly): + if self.ring != other.ring: + raise ValueError( + "Cannot divide Puiseux polynomials from different rings" + ) + return self._mul(other._inv()) + domain = self.ring.domain + if isinstance(other, int): + return self._mul_ground(domain.convert_from(QQ(1, other), QQ)) + elif domain.of_type(other): + return self._div_ground(other) + else: + return NotImplemented + + def __rtruediv__(self, other: Any) -> PuiseuxPoly: + if isinstance(other, int): + return self._inv()._mul_ground(self.ring.domain.convert_from(QQ(other), QQ)) + elif self.ring.domain.of_type(other): + return self._inv()._mul_ground(other) + else: + return NotImplemented + + def _add(self, other: PuiseuxPoly) -> PuiseuxPoly: + poly1, poly2, monom, ns = self._unify(other) + return self._new(self.ring, poly1 + poly2, monom, ns) + + def _add_ground(self, ground: Any) -> PuiseuxPoly: + return self._add(self.ring.ground_new(ground)) + + def _sub(self, other: PuiseuxPoly) -> PuiseuxPoly: + poly1, poly2, monom, ns = self._unify(other) + return self._new(self.ring, poly1 - poly2, monom, ns) + + def _sub_ground(self, ground: Any) -> PuiseuxPoly: + return self._sub(self.ring.ground_new(ground)) + + def _rsub_ground(self, ground: Any) -> PuiseuxPoly: + return self.ring.ground_new(ground)._sub(self) + + def _mul(self, other: PuiseuxPoly) -> PuiseuxPoly: + poly1, poly2, monom, ns = self._unify(other) + if monom is not None: + monom = tuple(2 * e for e in monom) + return self._new(self.ring, poly1 * poly2, monom, ns) + + def _mul_ground(self, ground: Any) -> PuiseuxPoly: + return self._new_raw(self.ring, self.poly * ground, self.monom, self.ns) + + def _div_ground(self, ground: Any) -> PuiseuxPoly: + return self._new_raw(self.ring, self.poly / ground, self.monom, self.ns) + + def _pow_pint(self, n: int) -> PuiseuxPoly: + assert n >= 0 + monom = self.monom + if monom is not None: + monom = tuple(m * n for m in monom) + return self._new(self.ring, self.poly**n, monom, self.ns) + + def _pow_nint(self, n: int) -> PuiseuxPoly: + return self._inv()._pow_pint(n) + + def _pow_rational(self, n: Any) -> PuiseuxPoly: + if not self.is_term: + raise ValueError("Only monomials can be raised to a rational power") + [(monom, coeff)] = self.terms() + domain = self.ring.domain + if not domain.is_one(coeff): + raise ValueError("Only monomials can be raised to a rational power") + monom = tuple(m * n for m in monom) + return self.ring.from_dict({monom: domain.one}) + + def _inv(self) -> PuiseuxPoly: + if not self.is_term: + raise ValueError("Only terms can be inverted") + [(monom, coeff)] = self.terms() + domain = self.ring.domain + if not domain.is_Field and not domain.is_one(coeff): + raise ValueError("Cannot invert non-unit coefficient") + monom = tuple(-m for m in monom) + coeff = 1 / coeff + return self.ring.from_dict({monom: coeff}) + + def diff(self, x: PuiseuxPoly) -> PuiseuxPoly: + """Differentiate a Puiseux polynomial with respect to a variable. + + >>> from sympy import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> R, x, y = puiseux_ring('x, y', QQ) + >>> p = 5*x**2 + 7*y**3 + >>> p.diff(x) + 10*x + >>> p.diff(y) + 21*y**2 + """ + ring = self.ring + i = ring.index(x) + g = {} + for expv, coeff in self.iterterms(): + n = expv[i] + if n: + e = list(expv) + e[i] -= 1 + g[tuple(e)] = coeff * n + return ring(g) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rationaltools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rationaltools.py new file mode 100644 index 0000000000000000000000000000000000000000..0ca513ff2d4af96baaaf1c82caf501750b1524da --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rationaltools.py @@ -0,0 +1,85 @@ +"""Tools for manipulation of rational expressions. """ + + +from sympy.core import Basic, Add, sympify +from sympy.core.exprtools import gcd_terms +from sympy.utilities import public +from sympy.utilities.iterables import iterable + + +@public +def together(expr, deep=False, fraction=True): + """ + Denest and combine rational expressions using symbolic methods. + + This function takes an expression or a container of expressions + and puts it (them) together by denesting and combining rational + subexpressions. No heroic measures are taken to minimize degree + of the resulting numerator and denominator. To obtain completely + reduced expression use :func:`~.cancel`. However, :func:`~.together` + can preserve as much as possible of the structure of the input + expression in the output (no expansion is performed). + + A wide variety of objects can be put together including lists, + tuples, sets, relational objects, integrals and others. It is + also possible to transform interior of function applications, + by setting ``deep`` flag to ``True``. + + By definition, :func:`~.together` is a complement to :func:`~.apart`, + so ``apart(together(expr))`` should return expr unchanged. Note + however, that :func:`~.together` uses only symbolic methods, so + it might be necessary to use :func:`~.cancel` to perform algebraic + simplification and minimize degree of the numerator and denominator. + + Examples + ======== + + >>> from sympy import together, exp + >>> from sympy.abc import x, y, z + + >>> together(1/x + 1/y) + (x + y)/(x*y) + >>> together(1/x + 1/y + 1/z) + (x*y + x*z + y*z)/(x*y*z) + + >>> together(1/(x*y) + 1/y**2) + (x + y)/(x*y**2) + + >>> together(1/(1 + 1/x) + 1/(1 + 1/y)) + (x*(y + 1) + y*(x + 1))/((x + 1)*(y + 1)) + + >>> together(exp(1/x + 1/y)) + exp(1/y + 1/x) + >>> together(exp(1/x + 1/y), deep=True) + exp((x + y)/(x*y)) + + >>> together(1/exp(x) + 1/(x*exp(x))) + (x + 1)*exp(-x)/x + + >>> together(1/exp(2*x) + 1/(x*exp(3*x))) + (x*exp(x) + 1)*exp(-3*x)/x + + """ + def _together(expr): + if isinstance(expr, Basic): + if expr.is_Atom or (expr.is_Function and not deep): + return expr + elif expr.is_Add: + return gcd_terms(list(map(_together, Add.make_args(expr))), fraction=fraction) + elif expr.is_Pow: + base = _together(expr.base) + + if deep: + exp = _together(expr.exp) + else: + exp = expr.exp + + return expr.func(base, exp) + else: + return expr.func(*[ _together(arg) for arg in expr.args ]) + elif iterable(expr): + return expr.__class__([ _together(ex) for ex in expr ]) + + return expr + + return _together(sympify(expr)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/ring_series.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/ring_series.py new file mode 100644 index 0000000000000000000000000000000000000000..b4333f0add9365991794d920a2699722900e8a5e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/ring_series.py @@ -0,0 +1,2127 @@ +"""Power series evaluation and manipulation using sparse Polynomials + +Implementing a new function +--------------------------- + +There are a few things to be kept in mind when adding a new function here:: + + - The implementation should work on all possible input domains/rings. + Special cases include the ``EX`` ring and a constant term in the series + to be expanded. There can be two types of constant terms in the series: + + + A constant value or symbol. + + A term of a multivariate series not involving the generator, with + respect to which the series is to expanded. + + Strictly speaking, a generator of a ring should not be considered a + constant. However, for series expansion both the cases need similar + treatment (as the user does not care about inner details), i.e, use an + addition formula to separate the constant part and the variable part (see + rs_sin for reference). + + - All the algorithms used here are primarily designed to work for Taylor + series (number of iterations in the algo equals the required order). + Hence, it becomes tricky to get the series of the right order if a + Puiseux series is input. Use rs_puiseux? in your function if your + algorithm is not designed to handle fractional powers. + +Extending rs_series +------------------- + +To make a function work with rs_series you need to do two things:: + + - Many sure it works with a constant term (as explained above). + - If the series contains constant terms, you might need to extend its ring. + You do so by adding the new terms to the rings as generators. + ``PolyRing.compose`` and ``PolyRing.add_gens`` are two functions that do + so and need to be called every time you expand a series containing a + constant term. + +Look at rs_sin and rs_series for further reference. + +""" + +from sympy.polys.domains import QQ, EX +from sympy.polys.rings import PolyElement, ring, sring +from sympy.polys.puiseux import PuiseuxPoly +from sympy.polys.polyerrors import DomainError +from sympy.polys.monomials import (monomial_min, monomial_mul, monomial_div, + monomial_ldiv) +from mpmath.libmp.libintmath import ifac +from sympy.core import PoleError, Function, Expr +from sympy.core.numbers import Rational +from sympy.core.intfunc import igcd +from sympy.functions import (sin, cos, tan, atan, exp, atanh, asinh, tanh, log, + ceiling, sinh, cosh) +from sympy.utilities.misc import as_int +from mpmath.libmp.libintmath import giant_steps +import math + + +def _invert_monoms(p1): + """ + Compute ``x**n * p1(1/x)`` for a univariate polynomial ``p1`` in ``x``. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import _invert_monoms + >>> R, x = ring('x', ZZ) + >>> p = x**2 + 2*x + 3 + >>> _invert_monoms(p) + 3*x**2 + 2*x + 1 + + See Also + ======== + + sympy.polys.densebasic.dup_reverse + """ + terms = list(p1.items()) + terms.sort() + deg = p1.degree() + R = p1.ring + p = R.zero + cv = p1.listcoeffs() + mv = p1.listmonoms() + for mvi, cvi in zip(mv, cv): + p[(deg - mvi[0],)] = cvi + return p + +def _giant_steps(target): + """Return a list of precision steps for the Newton's method""" + # We use ceil here because giant_steps cannot handle flint.fmpq + res = giant_steps(2, math.ceil(target)) + if res[0] != 2: + res = [2] + res + return res + +def rs_trunc(p1, x, prec): + """ + Truncate the series in the ``x`` variable with precision ``prec``, + that is, modulo ``O(x**prec)`` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_trunc + >>> R, x = ring('x', QQ) + >>> p = x**10 + x**5 + x + 1 + >>> rs_trunc(p, x, 12) + x**10 + x**5 + x + 1 + >>> rs_trunc(p, x, 10) + x**5 + x + 1 + """ + R = p1.ring + p = {} + i = R.gens.index(x) + for exp1 in p1: + if exp1[i] >= prec: + continue + p[exp1] = p1[exp1] + return R(p) + +def rs_is_puiseux(p, x): + """ + Test if ``p`` is Puiseux series in ``x``. + + Raise an exception if it has a negative power in ``x``. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> from sympy.polys.ring_series import rs_is_puiseux + >>> R, x = puiseux_ring('x', QQ) + >>> p = x**QQ(2,5) + x**QQ(2,3) + x + >>> rs_is_puiseux(p, x) + True + """ + index = p.ring.gens.index(x) + for k in p.itermonoms(): + if k[index] != int(k[index]): + return True + if k[index] < 0: + raise ValueError('The series is not regular in %s' % x) + return False + +def rs_puiseux(f, p, x, prec): + """ + Return the puiseux series for `f(p, x, prec)`. + + To be used when function ``f`` is implemented only for regular series. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> from sympy.polys.ring_series import rs_puiseux, rs_exp + >>> R, x = puiseux_ring('x', QQ) + >>> p = x**QQ(2,5) + x**QQ(2,3) + x + >>> rs_puiseux(rs_exp,p, x, 1) + 1 + x**(2/5) + x**(2/3) + 1/2*x**(4/5) + """ + index = p.ring.gens.index(x) + n = 1 + for k in p: + power = k[index] + if isinstance(power, Rational): + num, den = power.as_numer_denom() + n = int(n*den // igcd(n, den)) + elif power != int(power): + den = power.denominator + n = int(n*den // igcd(n, den)) + if n != 1: + p1 = pow_xin(p, index, n) + r = f(p1, x, prec*n) + n1 = QQ(1, n) + if isinstance(r, tuple): + r = tuple([pow_xin(rx, index, n1) for rx in r]) + else: + r = pow_xin(r, index, n1) + else: + r = f(p, x, prec) + return r + +def rs_puiseux2(f, p, q, x, prec): + """ + Return the puiseux series for `f(p, q, x, prec)`. + + To be used when function ``f`` is implemented only for regular series. + """ + index = p.ring.gens.index(x) + n = 1 + for k in p: + power = k[index] + if isinstance(power, Rational): + num, den = power.as_numer_denom() + n = n*den // igcd(n, den) + elif power != int(power): + den = power.denominator + n = n*den // igcd(n, den) + if n != 1: + p1 = pow_xin(p, index, n) + r = f(p1, q, x, prec*n) + n1 = QQ(1, n) + r = pow_xin(r, index, n1) + else: + r = f(p, q, x, prec) + return r + +def rs_mul(p1, p2, x, prec): + """ + Return the product of the given two series, modulo ``O(x**prec)``. + + ``x`` is the series variable or its position in the generators. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_mul + >>> R, x = ring('x', QQ) + >>> p1 = x**2 + 2*x + 1 + >>> p2 = x + 1 + >>> rs_mul(p1, p2, x, 3) + 3*x**2 + 3*x + 1 + """ + R = p1.ring + p = {} + if R.__class__ != p2.ring.__class__ or R != p2.ring: + raise ValueError('p1 and p2 must have the same ring') + iv = R.gens.index(x) + if not isinstance(p2, (PolyElement, PuiseuxPoly)): + raise ValueError('p2 must be a polynomial') + if R == p2.ring: + get = p.get + items2 = p2.terms() + items2.sort(key=lambda e: e[0][iv]) + if R.ngens == 1: + for exp1, v1 in p1.iterterms(): + for exp2, v2 in items2: + exp = exp1[0] + exp2[0] + if exp < prec: + exp = (exp, ) + p[exp] = get(exp, 0) + v1*v2 + else: + break + else: + monomial_mul = R.monomial_mul + for exp1, v1 in p1.iterterms(): + for exp2, v2 in items2: + if exp1[iv] + exp2[iv] < prec: + exp = monomial_mul(exp1, exp2) + p[exp] = get(exp, 0) + v1*v2 + else: + break + + return R(p) + +def rs_square(p1, x, prec): + """ + Square the series modulo ``O(x**prec)`` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_square + >>> R, x = ring('x', QQ) + >>> p = x**2 + 2*x + 1 + >>> rs_square(p, x, 3) + 6*x**2 + 4*x + 1 + """ + R = p1.ring + p = {} + iv = R.gens.index(x) + get = p.get + items = p1.terms() + items.sort(key=lambda e: e[0][iv]) + monomial_mul = R.monomial_mul + for i in range(len(items)): + exp1, v1 = items[i] + for j in range(i): + exp2, v2 = items[j] + if exp1[iv] + exp2[iv] < prec: + exp = monomial_mul(exp1, exp2) + p[exp] = get(exp, 0) + v1*v2 + else: + break + p = {m: 2*v for m, v in p.items()} + get = p.get + for expv, v in p1.iterterms(): + if 2*expv[iv] < prec: + e2 = monomial_mul(expv, expv) + p[e2] = get(e2, 0) + v**2 + return R(p) + +def rs_pow(p1, n, x, prec): + """ + Return ``p1**n`` modulo ``O(x**prec)`` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_pow + >>> R, x = ring('x', QQ) + >>> p = x + 1 + >>> rs_pow(p, 4, x, 3) + 6*x**2 + 4*x + 1 + """ + R = p1.ring + if isinstance(n, Rational): + np = int(n.p) + nq = int(n.q) + if nq != 1: + res = rs_nth_root(p1, nq, x, prec) + if np != 1: + res = rs_pow(res, np, x, prec) + else: + res = rs_pow(p1, np, x, prec) + return res + + n = as_int(n) + if n == 0: + if p1: + return R(1) + else: + raise ValueError('0**0 is undefined') + if n < 0: + p1 = rs_pow(p1, -n, x, prec) + return rs_series_inversion(p1, x, prec) + if n == 1: + return rs_trunc(p1, x, prec) + if n == 2: + return rs_square(p1, x, prec) + if n == 3: + p2 = rs_square(p1, x, prec) + return rs_mul(p1, p2, x, prec) + p = R(1) + while 1: + if n & 1: + p = rs_mul(p1, p, x, prec) + n -= 1 + if not n: + break + p1 = rs_square(p1, x, prec) + n = n // 2 + return p + +def rs_subs(p, rules, x, prec): + """ + Substitution with truncation according to the mapping in ``rules``. + + Return a series with precision ``prec`` in the generator ``x`` + + Note that substitutions are not done one after the other + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_subs + >>> R, x, y = ring('x, y', QQ) + >>> p = x**2 + y**2 + >>> rs_subs(p, {x: x+ y, y: x+ 2*y}, x, 3) + 2*x**2 + 6*x*y + 5*y**2 + >>> (x + y)**2 + (x + 2*y)**2 + 2*x**2 + 6*x*y + 5*y**2 + + which differs from + + >>> rs_subs(rs_subs(p, {x: x+ y}, x, 3), {y: x+ 2*y}, x, 3) + 5*x**2 + 12*x*y + 8*y**2 + + Parameters + ---------- + p : :class:`~.PolyElement` Input series. + rules : ``dict`` with substitution mappings. + x : :class:`~.PolyElement` in which the series truncation is to be done. + prec : :class:`~.Integer` order of the series after truncation. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_subs + >>> R, x, y = ring('x, y', QQ) + >>> rs_subs(x**2+y**2, {y: (x+y)**2}, x, 3) + 6*x**2*y**2 + x**2 + 4*x*y**3 + y**4 + """ + R = p.ring + ngens = R.ngens + d = R(0) + for i in range(ngens): + d[(i, 1)] = R.gens[i] + for var in rules: + d[(R.index(var), 1)] = rules[var] + p1 = R(0) + p_keys = sorted(p.keys()) + for expv in p_keys: + p2 = R(1) + for i in range(ngens): + power = expv[i] + if power == 0: + continue + if (i, power) not in d: + q, r = divmod(power, 2) + if r == 0 and (i, q) in d: + d[(i, power)] = rs_square(d[(i, q)], x, prec) + elif (i, power - 1) in d: + d[(i, power)] = rs_mul(d[(i, power - 1)], d[(i, 1)], + x, prec) + else: + d[(i, power)] = rs_pow(d[(i, 1)], power, x, prec) + p2 = rs_mul(p2, d[(i, power)], x, prec) + p1 += p2*p[expv] + return p1 + +def _has_constant_term(p, x): + """ + Check if ``p`` has a constant term in ``x`` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import _has_constant_term + >>> R, x = ring('x', QQ) + >>> p = x**2 + x + 1 + >>> _has_constant_term(p, x) + True + """ + R = p.ring + iv = R.gens.index(x) + zm = R.zero_monom + a = [0]*R.ngens + a[iv] = 1 + miv = tuple(a) + return any(monomial_min(expv, miv) == zm for expv in p) + +def _get_constant_term(p, x): + """Return constant term in p with respect to x + + Note that it is not simply `p[R.zero_monom]` as there might be multiple + generators in the ring R. We want the `x`-free term which can contain other + generators. + """ + R = p.ring + i = R.gens.index(x) + zm = R.zero_monom + a = [0]*R.ngens + a[i] = 1 + miv = tuple(a) + c = 0 + for expv in p: + if monomial_min(expv, miv) == zm: + c += R({expv: p[expv]}) + return c + +def _check_series_var(p, x, name): + index = p.ring.gens.index(x) + m = min(p, key=lambda k: k[index])[index] + if m < 0: + raise PoleError("Asymptotic expansion of %s around [oo] not " + "implemented." % name) + return index, m + +def _series_inversion1(p, x, prec): + """ + Univariate series inversion ``1/p`` modulo ``O(x**prec)``. + + The Newton method is used. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import _series_inversion1 + >>> R, x = ring('x', QQ) + >>> p = x + 1 + >>> _series_inversion1(p, x, 4) + -x**3 + x**2 - x + 1 + """ + if rs_is_puiseux(p, x): + return rs_puiseux(_series_inversion1, p, x, prec) + R = p.ring + zm = R.zero_monom + c = p[zm] + + # giant_steps does not seem to work with PythonRational numbers with 1 as + # denominator. This makes sure such a number is converted to integer. + if prec == int(prec): + prec = int(prec) + + if zm not in p: + raise ValueError("No constant term in series") + if _has_constant_term(p - c, x): + raise ValueError("p cannot contain a constant term depending on " + "parameters") + if not R.domain.is_unit(c): + raise ValueError(f"Constant term {c} must be a unit in {R.domain}") + + one = R(1) + if R.domain is EX: + one = 1 + if c != one: + p1 = R(1)/c + else: + p1 = R(1) + for precx in _giant_steps(prec): + t = 1 - rs_mul(p1, p, x, precx) + p1 = p1 + rs_mul(p1, t, x, precx) + return p1 + +def rs_series_inversion(p, x, prec): + """ + Multivariate series inversion ``1/p`` modulo ``O(x**prec)``. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_series_inversion + >>> R, x, y = ring('x, y', QQ) + >>> rs_series_inversion(1 + x*y**2, x, 4) + -x**3*y**6 + x**2*y**4 - x*y**2 + 1 + >>> rs_series_inversion(1 + x*y**2, y, 4) + -x*y**2 + 1 + >>> rs_series_inversion(x + x**2, x, 4) + x**3 - x**2 + x - 1 + x**(-1) + """ + R = p.ring + if p == R.zero: + raise ZeroDivisionError + zm = R.zero_monom + index = R.gens.index(x) + m = min(p, key=lambda k: k[index])[index] + if m: + p = mul_xin(p, index, -m) + prec = prec + m + if zm not in p: + raise NotImplementedError("No constant term in series") + + if _has_constant_term(p - p[zm], x): + raise NotImplementedError("p - p[0] must not have a constant term in " + "the series variables") + r = _series_inversion1(p, x, prec) + if m != 0: + r = mul_xin(r, index, -m) + return r + +def _coefficient_t(p, t): + r"""Coefficient of `x_i**j` in p, where ``t`` = (i, j)""" + i, j = t + R = p.ring + expv1 = [0]*R.ngens + expv1[i] = j + expv1 = tuple(expv1) + p1 = R(0) + for expv in p: + if expv[i] == j: + p1[monomial_div(expv, expv1)] = p[expv] + return p1 + +def rs_series_reversion(p, x, n, y): + r""" + Reversion of a series. + + ``p`` is a series with ``O(x**n)`` of the form $p = ax + f(x)$ + where $a$ is a number different from 0. + + $f(x) = \sum_{k=2}^{n-1} a_kx_k$ + + Parameters + ========== + + a_k : Can depend polynomially on other variables, not indicated. + x : Variable with name x. + y : Variable with name y. + + Returns + ======= + + Solve $p = y$, that is, given $ax + f(x) - y = 0$, + find the solution $x = r(y)$ up to $O(y^n)$. + + Algorithm + ========= + + If $r_i$ is the solution at order $i$, then: + $ar_i + f(r_i) - y = O\left(y^{i + 1}\right)$ + + and if $r_{i + 1}$ is the solution at order $i + 1$, then: + $ar_{i + 1} + f(r_{i + 1}) - y = O\left(y^{i + 2}\right)$ + + We have, $r_{i + 1} = r_i + e$, such that, + $ae + f(r_i) = O\left(y^{i + 2}\right)$ + or $e = -f(r_i)/a$ + + So we use the recursion relation: + $r_{i + 1} = r_i - f(r_i)/a$ + with the boundary condition: $r_1 = y$ + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_series_reversion, rs_trunc + >>> R, x, y, a, b = ring('x, y, a, b', QQ) + >>> p = x - x**2 - 2*b*x**2 + 2*a*b*x**2 + >>> p1 = rs_series_reversion(p, x, 3, y); p1 + -2*y**2*a*b + 2*y**2*b + y**2 + y + >>> rs_trunc(p.compose(x, p1), y, 3) + y + """ + if rs_is_puiseux(p, x): + raise NotImplementedError + R = p.ring + nx = R.gens.index(x) + y = R(y) + ny = R.gens.index(y) + if _has_constant_term(p, x): + raise ValueError("p must not contain a constant term in the series " + "variable") + a = _coefficient_t(p, (nx, 1)) + zm = R.zero_monom + assert zm in a and len(a) == 1 + a = a[zm] + r = y/a + for i in range(2, n): + sp = rs_subs(p, {x: r}, y, i + 1) + sp = _coefficient_t(sp, (ny, i))*y**i + r -= sp/a + return r + +def rs_series_from_list(p, c, x, prec, concur=1): + """ + Return a series `sum c[n]*p**n` modulo `O(x**prec)`. + + It reduces the number of multiplications by summing concurrently. + + `ax = [1, p, p**2, .., p**(J - 1)]` + `s = sum(c[i]*ax[i]` for i in `range(r, (r + 1)*J))*p**((K - 1)*J)` + with `K >= (n + 1)/J` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_series_from_list, rs_trunc + >>> R, x = ring('x', QQ) + >>> p = x**2 + x + 1 + >>> c = [1, 2, 3] + >>> rs_series_from_list(p, c, x, 4) + 6*x**3 + 11*x**2 + 8*x + 6 + >>> rs_trunc(1 + 2*p + 3*p**2, x, 4) + 6*x**3 + 11*x**2 + 8*x + 6 + >>> pc = R.from_list(list(reversed(c))) + >>> rs_trunc(pc.compose(x, p), x, 4) + 6*x**3 + 11*x**2 + 8*x + 6 + + See Also + ======== + + sympy.polys.rings.PolyRing.compose + + """ + R = p.ring + n = len(c) + if not concur: + q = R(1) + s = c[0]*q + for i in range(1, n): + q = rs_mul(q, p, x, prec) + s += c[i]*q + return s + J = int(math.sqrt(n) + 1) + K, r = divmod(n, J) + if r: + K += 1 + ax = [R(1)] + q = R(1) + if len(p) < 20: + for i in range(1, J): + q = rs_mul(q, p, x, prec) + ax.append(q) + else: + for i in range(1, J): + if i % 2 == 0: + q = rs_square(ax[i//2], x, prec) + else: + q = rs_mul(q, p, x, prec) + ax.append(q) + # optimize using rs_square + pj = rs_mul(ax[-1], p, x, prec) + b = R(1) + s = R(0) + for k in range(K - 1): + r = J*k + s1 = c[r] + for j in range(1, J): + s1 += c[r + j]*ax[j] + s1 = rs_mul(s1, b, x, prec) + s += s1 + b = rs_mul(b, pj, x, prec) + if not b: + break + k = K - 1 + r = J*k + if r < n: + s1 = c[r]*R(1) + for j in range(1, J): + if r + j >= n: + break + s1 += c[r + j]*ax[j] + s1 = rs_mul(s1, b, x, prec) + s += s1 + return s + +def rs_diff(p, x): + """ + Return partial derivative of ``p`` with respect to ``x``. + + Parameters + ========== + + x : :class:`~.PolyElement` with respect to which ``p`` is differentiated. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_diff + >>> R, x, y = ring('x, y', QQ) + >>> p = x + x**2*y**3 + >>> rs_diff(p, x) + 2*x*y**3 + 1 + """ + R = p.ring + n = R.gens.index(x) + p1 = {} + mn = [0]*R.ngens + mn[n] = 1 + mn = tuple(mn) + for expv in p: + if expv[n]: + e = monomial_ldiv(expv, mn) + p1[e] = R.domain_new(p[expv]*expv[n]) + return R(p1) + +def rs_integrate(p, x): + """ + Integrate ``p`` with respect to ``x``. + + Parameters + ========== + + x : :class:`~.PolyElement` with respect to which ``p`` is integrated. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_integrate + >>> R, x, y = ring('x, y', QQ) + >>> p = x + x**2*y**3 + >>> rs_integrate(p, x) + 1/3*x**3*y**3 + 1/2*x**2 + """ + R = p.ring + p1 = {} + n = R.gens.index(x) + mn = [0]*R.ngens + mn[n] = 1 + mn = tuple(mn) + + for expv in p: + e = monomial_mul(expv, mn) + p1[e] = R.domain_new(p[expv]/(expv[n] + 1)) + return R(p1) + +def rs_fun(p, f, *args): + r""" + Function of a multivariate series computed by substitution. + + The case with f method name is used to compute `rs\_tan` and `rs\_nth\_root` + of a multivariate series: + + `rs\_fun(p, tan, iv, prec)` + + tan series is first computed for a dummy variable _x, + i.e, `rs\_tan(\_x, iv, prec)`. Then we substitute _x with p to get the + desired series + + Parameters + ========== + + p : :class:`~.PolyElement` The multivariate series to be expanded. + f : `ring\_series` function to be applied on `p`. + args[-2] : :class:`~.PolyElement` with respect to which, the series is to be expanded. + args[-1] : Required order of the expanded series. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_fun, _tan1 + >>> R, x, y = ring('x, y', QQ) + >>> p = x + x*y + x**2*y + x**3*y**2 + >>> rs_fun(p, _tan1, x, 4) + 1/3*x**3*y**3 + 2*x**3*y**2 + x**3*y + 1/3*x**3 + x**2*y + x*y + x + """ + _R = p.ring + R1, _x = ring('_x', _R.domain) + h = int(args[-1]) + args1 = args[:-2] + (_x, h) + zm = _R.zero_monom + # separate the constant term of the series + # compute the univariate series f(_x, .., 'x', sum(nv)) + if zm in p: + x1 = _x + p[zm] + p1 = p - p[zm] + else: + x1 = _x + p1 = p + if isinstance(f, str): + q = getattr(x1, f)(*args1) + else: + q = f(x1, *args1) + a = sorted(q.items()) + c = [0]*h + for x in a: + c[x[0][0]] = x[1] + p1 = rs_series_from_list(p1, c, args[-2], args[-1]) + return p1 + +def mul_xin(p, i, n): + r""" + Return `p*x_i**n`. + + `x\_i` is the ith variable in ``p``. + """ + R = p.ring + q = {} + for k, v in p.terms(): + k1 = list(k) + k1[i] += n + q[tuple(k1)] = v + return R(q) + +def pow_xin(p, i, n): + """ + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> from sympy.polys.ring_series import pow_xin + >>> R, x, y = puiseux_ring('x, y', QQ) + >>> p = x**QQ(2,5) + x + x**QQ(2,3) + >>> index = p.ring.gens.index(x) + >>> pow_xin(p, index, 15) + x**6 + x**10 + x**15 + """ + R = p.ring + q = {} + for k, v in p.terms(): + k1 = list(k) + k1[i] *= n + q[tuple(k1)] = v + return R(q) + +def _nth_root1(p, n, x, prec): + """ + Univariate series expansion of the nth root of ``p``. + + The Newton method is used. + """ + if rs_is_puiseux(p, x): + return rs_puiseux2(_nth_root1, p, n, x, prec) + R = p.ring + zm = R.zero_monom + if zm not in p: + raise NotImplementedError('No constant term in series') + n = as_int(n) + assert p[zm] == 1 + p1 = R(1) + if p == 1: + return p + if n == 0: + return R(1) + if n == 1: + return p + if n < 0: + n = -n + sign = 1 + else: + sign = 0 + for precx in _giant_steps(prec): + tmp = rs_pow(p1, n + 1, x, precx) + tmp = rs_mul(tmp, p, x, precx) + p1 += p1/n - tmp/n + if sign: + return p1 + else: + return _series_inversion1(p1, x, prec) + +def rs_nth_root(p, n, x, prec): + """ + Multivariate series expansion of the nth root of ``p``. + + Parameters + ========== + + p : Expr + The polynomial to computer the root of. + n : integer + The order of the root to be computed. + x : :class:`~.PolyElement` + prec : integer + Order of the expanded series. + + Notes + ===== + + The result of this function is dependent on the ring over which the + polynomial has been defined. If the answer involves a root of a constant, + make sure that the polynomial is over a real field. It cannot yet handle + roots of symbols. + + Examples + ======== + + >>> from sympy.polys.domains import QQ, RR + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_nth_root + >>> R, x, y = ring('x, y', QQ) + >>> rs_nth_root(1 + x + x*y, -3, x, 3) + 2/9*x**2*y**2 + 4/9*x**2*y + 2/9*x**2 - 1/3*x*y - 1/3*x + 1 + >>> R, x, y = ring('x, y', RR) + >>> rs_nth_root(3 + x + x*y, 3, x, 2) + 0.160249952256379*x*y + 0.160249952256379*x + 1.44224957030741 + """ + if n == 0: + if p == 0: + raise ValueError('0**0 expression') + else: + return p.ring(1) + if n == 1: + return rs_trunc(p, x, prec) + R = p.ring + index = R.gens.index(x) + m = min(p, key=lambda k: k[index])[index] + p = mul_xin(p, index, -m) + prec -= m + + if _has_constant_term(p - 1, x): + zm = R.zero_monom + c = p[zm] + if isinstance(c, PolyElement): + try: + c_expr = c.as_expr() + const = R(c_expr**(QQ(1, n))) + except ValueError: + raise DomainError("The given series cannot be expanded in " + "this domain.") + else: + try: # RealElement doesn't support + const = R(c**Rational(1, n)) # exponentiation with mpq object + except ValueError: # as exponent + raise DomainError("The given series cannot be expanded in " + "this domain.") + res = rs_nth_root(p/c, n, x, prec)*const + else: + res = _nth_root1(p, n, x, prec) + if m: + m = QQ(m) / n + res = mul_xin(res, index, m) + return res + +def rs_log(p, x, prec): + """ + The Logarithm of ``p`` modulo ``O(x**prec)``. + + Notes + ===== + + Truncation of ``integral dx p**-1*d p/dx`` is used. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> from sympy.polys.ring_series import rs_log + >>> R, x = puiseux_ring('x', QQ) + >>> rs_log(1 + x, x, 8) + x + -1/2*x**2 + 1/3*x**3 + -1/4*x**4 + 1/5*x**5 + -1/6*x**6 + 1/7*x**7 + >>> rs_log(x**QQ(3, 2) + 1, x, 5) + x**(3/2) + -1/2*x**3 + 1/3*x**(9/2) + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_log, p, x, prec) + R = p.ring + if p == 1: + return R.zero + c = _get_constant_term(p, x) + if c: + const = 0 + if c == 1: + pass + try: + c_expr = c.as_expr() + const = R(log(c_expr)) + except ValueError: + R = R.add_gens([log(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + const = R(log(c_expr)) + + dlog = p.diff(x) + dlog = rs_mul(dlog, _series_inversion1(p, x, prec), x, prec - 1) + return rs_integrate(dlog, x) + const + else: + raise NotImplementedError + +def rs_LambertW(p, x, prec): + """ + Calculate the series expansion of the principal branch of the Lambert W + function. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_LambertW + >>> R, x, y = ring('x, y', QQ) + >>> rs_LambertW(x + x*y, x, 3) + -x**2*y**2 - 2*x**2*y - x**2 + x*y + x + + See Also + ======== + + LambertW + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_LambertW, p, x, prec) + R = p.ring + p1 = R(0) + if _has_constant_term(p, x): + raise NotImplementedError("Polynomial must not have constant term in " + "the series variables") + if x in R.gens: + for precx in _giant_steps(prec): + e = rs_exp(p1, x, precx) + p2 = rs_mul(e, p1, x, precx) - p + p3 = rs_mul(e, p1 + 1, x, precx) + p3 = rs_series_inversion(p3, x, precx) + tmp = rs_mul(p2, p3, x, precx) + p1 -= tmp + return p1 + else: + raise NotImplementedError + +def _exp1(p, x, prec): + r"""Helper function for `rs\_exp`. """ + R = p.ring + p1 = R(1) + for precx in _giant_steps(prec): + pt = p - rs_log(p1, x, precx) + tmp = rs_mul(pt, p1, x, precx) + p1 += tmp + return p1 + +def rs_exp(p, x, prec): + """ + Exponentiation of a series modulo ``O(x**prec)`` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_exp + >>> R, x = ring('x', QQ) + >>> rs_exp(x**2, x, 7) + 1/6*x**6 + 1/2*x**4 + x**2 + 1 + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_exp, p, x, prec) + R = p.ring + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + const = R(exp(c_expr)) + except ValueError: + R = R.add_gens([exp(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + const = R(exp(c_expr)) + + p1 = p - c + + # Makes use of SymPy functions to evaluate the values of the cos/sin + # of the constant term. + return const*rs_exp(p1, x, prec) + + if len(p) > 20: + return _exp1(p, x, prec) + one = R(1) + n = 1 + c = [] + for k in range(prec): + c.append(one/n) + k += 1 + n *= k + + r = rs_series_from_list(p, c, x, prec) + return r + +def _atan(p, iv, prec): + """ + Expansion using formula. + + Faster on very small and univariate series. + """ + R = p.ring + mo = R(-1) + c = [-mo] + p2 = rs_square(p, iv, prec) + for k in range(1, prec): + c.append(mo**k/(2*k + 1)) + s = rs_series_from_list(p2, c, iv, prec) + s = rs_mul(s, p, iv, prec) + return s + +def rs_atan(p, x, prec): + """ + The arctangent of a series + + Return the series expansion of the atan of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_atan + >>> R, x, y = ring('x, y', QQ) + >>> rs_atan(x + x*y, x, 4) + -1/3*x**3*y**3 - x**3*y**2 - x**3*y - 1/3*x**3 + x*y + x + + See Also + ======== + + atan + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_atan, p, x, prec) + R = p.ring + const = 0 + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + const = R(atan(c_expr)) + except ValueError: + R = R.add_gens([atan(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + const = R(atan(c_expr)) + + # Instead of using a closed form formula, we differentiate atan(p) to get + # `1/(1+p**2) * dp`, whose series expansion is much easier to calculate. + # Finally we integrate to get back atan + dp = p.diff(x) + p1 = rs_square(p, x, prec) + R(1) + p1 = rs_series_inversion(p1, x, prec - 1) + p1 = rs_mul(dp, p1, x, prec - 1) + return rs_integrate(p1, x) + const + +def rs_asin(p, x, prec): + """ + Arcsine of a series + + Return the series expansion of the asin of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_asin + >>> R, x, y = ring('x, y', QQ) + >>> rs_asin(x, x, 8) + 5/112*x**7 + 3/40*x**5 + 1/6*x**3 + x + + See Also + ======== + + asin + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_asin, p, x, prec) + if _has_constant_term(p, x): + raise NotImplementedError("Polynomial must not have constant term in " + "series variables") + R = p.ring + if x in R.gens: + # get a good value + if len(p) > 20: + dp = rs_diff(p, x) + p1 = 1 - rs_square(p, x, prec - 1) + p1 = rs_nth_root(p1, -2, x, prec - 1) + p1 = rs_mul(dp, p1, x, prec - 1) + return rs_integrate(p1, x) + one = R(1) + c = [0, one, 0] + for k in range(3, prec, 2): + c.append((k - 2)**2*c[-2]/(k*(k - 1))) + c.append(0) + return rs_series_from_list(p, c, x, prec) + + else: + raise NotImplementedError + +def _tan1(p, x, prec): + r""" + Helper function of :func:`rs_tan`. + + Return the series expansion of tan of a univariate series using Newton's + method. It takes advantage of the fact that series expansion of atan is + easier than that of tan. + + Consider `f(x) = y - \arctan(x)` + Let r be a root of f(x) found using Newton's method. + Then `f(r) = 0` + Or `y = \arctan(x)` where `x = \tan(y)` as required. + """ + R = p.ring + p1 = R(0) + for precx in _giant_steps(prec): + tmp = p - rs_atan(p1, x, precx) + tmp = rs_mul(tmp, 1 + rs_square(p1, x, precx), x, precx) + p1 += tmp + return p1 + +def rs_tan(p, x, prec): + """ + Tangent of a series. + + Return the series expansion of the tan of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_tan + >>> R, x, y = ring('x, y', QQ) + >>> rs_tan(x + x*y, x, 4) + 1/3*x**3*y**3 + x**3*y**2 + x**3*y + 1/3*x**3 + x*y + x + + See Also + ======== + + _tan1, tan + """ + if rs_is_puiseux(p, x): + r = rs_puiseux(rs_tan, p, x, prec) + return r + R = p.ring + const = 0 + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + const = R(tan(c_expr)) + except ValueError: + R = R.add_gens([tan(c_expr, )]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + const = R(tan(c_expr)) + + p1 = p - c + + # Makes use of SymPy functions to evaluate the values of the cos/sin + # of the constant term. + t2 = rs_tan(p1, x, prec) + t = rs_series_inversion(1 - const*t2, x, prec) + return rs_mul(const + t2, t, x, prec) + + if R.ngens == 1: + return _tan1(p, x, prec) + else: + return rs_fun(p, rs_tan, x, prec) + +def rs_cot(p, x, prec): + """ + Cotangent of a series + + Return the series expansion of the cot of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_cot + >>> R, x, y = ring('x, y', QQ) + >>> rs_cot(x, x, 6) + -2/945*x**5 - 1/45*x**3 - 1/3*x + x**(-1) + + See Also + ======== + + cot + """ + # It can not handle series like `p = x + x*y` where the coefficient of the + # linear term in the series variable is symbolic. + if rs_is_puiseux(p, x): + r = rs_puiseux(rs_cot, p, x, prec) + return r + i, m = _check_series_var(p, x, 'cot') + prec1 = int(prec + 2*m) + c, s = rs_cos_sin(p, x, prec1) + s = mul_xin(s, i, -m) + s = rs_series_inversion(s, x, prec1) + res = rs_mul(c, s, x, prec1) + res = mul_xin(res, i, -m) + res = rs_trunc(res, x, prec) + return res + +def rs_sin(p, x, prec): + """ + Sine of a series + + Return the series expansion of the sin of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> from sympy.polys.ring_series import rs_sin + >>> R, x, y = puiseux_ring('x, y', QQ) + >>> rs_sin(x + x*y, x, 4) + x + x*y + -1/6*x**3 + -1/2*x**3*y + -1/2*x**3*y**2 + -1/6*x**3*y**3 + >>> rs_sin(x**QQ(3, 2) + x*y**QQ(7, 5), x, 4) + x*y**(7/5) + x**(3/2) + -1/6*x**3*y**(21/5) + -1/2*x**(7/2)*y**(14/5) + + See Also + ======== + + sin + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_sin, p, x, prec) + R = x.ring + if not p: + return R(0) + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + t1, t2 = R(sin(c_expr)), R(cos(c_expr)) + except ValueError: + R = R.add_gens([sin(c_expr), cos(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + t1, t2 = R(sin(c_expr)), R(cos(c_expr)) + + p1 = p - c + + # Makes use of SymPy cos, sin functions to evaluate the values of the + # cos/sin of the constant term. + p_cos, p_sin = rs_cos_sin(p1, x, prec) + return p_sin*t2 + p_cos*t1 + + # Series is calculated in terms of tan as its evaluation is fast. + if len(p) > 20 and R.ngens == 1: + t = rs_tan(p/2, x, prec) + t2 = rs_square(t, x, prec) + p1 = rs_series_inversion(1 + t2, x, prec) + return rs_mul(p1, 2*t, x, prec) + one = R(1) + n = 1 + c = [0] + for k in range(2, prec + 2, 2): + c.append(one/n) + c.append(0) + n *= -k*(k + 1) + return rs_series_from_list(p, c, x, prec) + +def rs_cos(p, x, prec): + """ + Cosine of a series + + Return the series expansion of the cos of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.puiseux import puiseux_ring + >>> from sympy.polys.ring_series import rs_cos + >>> R, x, y = puiseux_ring('x, y', QQ) + >>> rs_cos(x + x*y, x, 4) + 1 + -1/2*x**2 + -1*x**2*y + -1/2*x**2*y**2 + >>> rs_cos(x + x*y, x, 4)/x**QQ(7, 5) + x**(-7/5) + -1/2*x**(3/5) + -1*x**(3/5)*y + -1/2*x**(3/5)*y**2 + + See Also + ======== + + cos + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_cos, p, x, prec) + R = p.ring + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + t1, t2 = R(sin(c_expr)), R(cos(c_expr)) + except ValueError: + R = R.add_gens([sin(c_expr), cos(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + t1, t2 = R(sin(c_expr)), R(cos(c_expr)) + + p1 = p - c + # Makes use of SymPy cos, sin functions to evaluate the values of the + # cos/sin of the constant term. + p_cos, p_sin = rs_cos_sin(p1, x, prec) + return p_cos*t2 - p_sin*t1 + + # Series is calculated in terms of tan as its evaluation is fast. + if len(p) > 20 and R.ngens == 1: + t = rs_tan(p/2, x, prec) + t2 = rs_square(t, x, prec) + p1 = rs_series_inversion(1+t2, x, prec) + return rs_mul(p1, 1 - t2, x, prec) + one = R(1) + n = 1 + c = [] + for k in range(2, prec + 2, 2): + c.append(one/n) + c.append(0) + n *= -k*(k - 1) + return rs_series_from_list(p, c, x, prec) + +def rs_cos_sin(p, x, prec): + """ + Cosine and sine of a series + + Return the series expansion of the cosine and sine of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_cos_sin + >>> R, x, y = ring('x, y', QQ) + >>> c, s = rs_cos_sin(x + x*y, x, 4) + >>> c + -1/2*x**2*y**2 - x**2*y - 1/2*x**2 + 1 + >>> s + -1/6*x**3*y**3 - 1/2*x**3*y**2 - 1/2*x**3*y - 1/6*x**3 + x*y + x + + See Also + ======== + + rs_cos, rs_sin + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_cos_sin, p, x, prec) + R = p.ring + if not p: + return R(0), R(0) + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + t1, t2 = R(sin(c_expr)), R(cos(c_expr)) + except ValueError: + R = R.add_gens([sin(c_expr), cos(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + t1, t2 = R(sin(c_expr)), R(cos(c_expr)) + + p1 = p - c + p_cos, p_sin = rs_cos_sin(p1, x, prec) + return p_cos*t2 - p_sin*t1, p_cos*t1 + p_sin*t2 + + if len(p) > 20 and R.ngens == 1: + t = rs_tan(p/2, x, prec) + t2 = rs_square(t, x, prec) + p1 = rs_series_inversion(1 + t2, x, prec) + return (rs_mul(p1, 1 - t2, x, prec), rs_mul(p1, 2*t, x, prec)) + + one = R(1) + coeffs = [] + cn, sn = 1, 1 + for k in range(2, prec+2, 2): + coeffs.extend([(one/cn, 0), (0, one/sn)]) + cn, sn = -cn*k*(k - 1), -sn*k*(k + 1) + + c, s = zip(*coeffs) + return (rs_series_from_list(p, c, x, prec), rs_series_from_list(p, s, x, prec)) + +def _atanh(p, x, prec): + """ + Expansion using formula + + Faster for very small and univariate series + """ + R = p.ring + one = R(1) + c = [one] + p2 = rs_square(p, x, prec) + for k in range(1, prec): + c.append(one/(2*k + 1)) + s = rs_series_from_list(p2, c, x, prec) + s = rs_mul(s, p, x, prec) + return s + +def rs_atanh(p, x, prec): + """ + Hyperbolic arctangent of a series + + Return the series expansion of the atanh of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_atanh + >>> R, x, y = ring('x, y', QQ) + >>> rs_atanh(x + x*y, x, 4) + 1/3*x**3*y**3 + x**3*y**2 + x**3*y + 1/3*x**3 + x*y + x + + See Also + ======== + + atanh + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_atanh, p, x, prec) + R = p.ring + const = 0 + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + const = R(atanh(c_expr)) + except ValueError: + raise DomainError("The given series cannot be expanded in " + "this domain.") + + # Instead of using a closed form formula, we differentiate atanh(p) to get + # `1/(1-p**2) * dp`, whose series expansion is much easier to calculate. + # Finally we integrate to get back atanh + dp = rs_diff(p, x) + p1 = - rs_square(p, x, prec) + 1 + p1 = rs_series_inversion(p1, x, prec - 1) + p1 = rs_mul(dp, p1, x, prec - 1) + return rs_integrate(p1, x) + const + +def rs_asinh(p, x, prec): + """ + Hyperbolic arcsine of a series + + Return the series expansion of the arcsinh of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_asinh + >>> R, x = ring('x', QQ) + >>> rs_asinh(x, x, 9) + -5/112*x**7 + 3/40*x**5 - 1/6*x**3 + x + + See Also + ======== + + asinh + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_asinh, p, x, prec) + R = p.ring + const = 0 + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + const = R(asinh(c_expr)) + except ValueError: + raise DomainError("The given series cannot be expanded in " + "this domain.") + + # Instead of using a closed form formula, we differentiate asinh(p) to get + # `1/sqrt(1+p**2) * dp`, whose series expansion is much easier to calculate. + # Finally we integrate to get back asinh + dp = rs_diff(p, x) + p_squared = rs_square(p, x, prec) + denom = p_squared + R(1) + p1 = rs_nth_root(denom, -2, x, prec - 1) + p1 = rs_mul(dp, p1, x, prec - 1) + return rs_integrate(p1, x) + const + +def rs_sinh(p, x, prec): + """ + Hyperbolic sine of a series + + Return the series expansion of the sinh of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_sinh + >>> R, x, y = ring('x, y', QQ) + >>> rs_sinh(x + x*y, x, 4) + 1/6*x**3*y**3 + 1/2*x**3*y**2 + 1/2*x**3*y + 1/6*x**3 + x*y + x + + See Also + ======== + + sinh + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_sinh, p, x, prec) + R = p.ring + if not p: + return R(0) + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + t1, t2 = R(sinh(c_expr)), R(cosh(c_expr)) + except ValueError: + R = R.add_gens([sinh(c_expr), cosh(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + t1, t2 = R(sinh(c_expr)), R(cosh(c_expr)) + + p1 = p - c + p_cosh, p_sinh = rs_cosh_sinh(p1, x, prec) + return p_sinh * t2 + p_cosh * t1 + + t = rs_exp(p, x, prec) + t1 = rs_series_inversion(t, x, prec) + return (t - t1)/2 + +def rs_cosh(p, x, prec): + """ + Hyperbolic cosine of a series + + Return the series expansion of the cosh of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_cosh + >>> R, x, y = ring('x, y', QQ) + >>> rs_cosh(x + x*y, x, 4) + 1/2*x**2*y**2 + x**2*y + 1/2*x**2 + 1 + + See Also + ======== + + cosh + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_cosh, p, x, prec) + R = p.ring + if not p: + return R(0) + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + t1, t2 = R(sinh(c_expr)), R(cosh(c_expr)) + except ValueError: + R = R.add_gens([sinh(c_expr), cosh(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + t1, t2 = R(sinh(c_expr)), R(cosh(c_expr)) + + p1 = p - c + p_cosh, p_sinh = rs_cosh_sinh(p1, x, prec) + return p_cosh * t2 + p_sinh * t1 + + t = rs_exp(p, x, prec) + t1 = rs_series_inversion(t, x, prec) + return (t + t1)/2 + +def rs_cosh_sinh(p, x, prec): + """ + Hyperbolic cosine and sine of a series + + Return the series expansion of the hyperbolic cosine and sine of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_cosh_sinh + >>> R, x, y = ring('x, y', QQ) + >>> c, s = rs_cosh_sinh(x + x*y, x, 4) + >>> c + 1/2*x**2*y**2 + x**2*y + 1/2*x**2 + 1 + >>> s + 1/6*x**3*y**3 + 1/2*x**3*y**2 + 1/2*x**3*y + 1/6*x**3 + x*y + x + + See Also + ======== + + rs_cosh, rs_sinh + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_cosh_sinh, p, x, prec) + R = p.ring + if not p: + return R(0), R(0) + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + t1, t2 = R(sinh(c_expr)), R(cosh(c_expr)) + except ValueError: + R = R.add_gens([sinh(c_expr), cosh(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + t1, t2 = R(sinh(c_expr)), R(cosh(c_expr)) + + p1 = p - c + p_cosh, p_sinh = rs_cosh_sinh(p1, x, prec) + return p_cosh * t2 + p_sinh * t1, p_sinh * t2 + p_cosh * t1 + + t = rs_exp(p, x, prec) + t1 = rs_series_inversion(t, x, prec) + return (t + t1)/2, (t - t1)/2 + + +def _tanh(p, x, prec): + r""" + Helper function of :func:`rs_tanh` + + Return the series expansion of tanh of a univariate series using Newton's + method. It takes advantage of the fact that series expansion of atanh is + easier than that of tanh. + + See Also + ======== + + _tanh + """ + R = p.ring + p1 = R(0) + for precx in _giant_steps(prec): + tmp = p - rs_atanh(p1, x, precx) + tmp = rs_mul(tmp, 1 - rs_square(p1, x, prec), x, precx) + p1 += tmp + return p1 + +def rs_tanh(p, x, prec): + """ + Hyperbolic tangent of a series + + Return the series expansion of the tanh of ``p``, about 0. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_tanh + >>> R, x, y = ring('x, y', QQ) + >>> rs_tanh(x + x*y, x, 4) + -1/3*x**3*y**3 - x**3*y**2 - x**3*y - 1/3*x**3 + x*y + x + + See Also + ======== + + tanh + """ + if rs_is_puiseux(p, x): + return rs_puiseux(rs_tanh, p, x, prec) + R = p.ring + const = 0 + c = _get_constant_term(p, x) + if c: + try: + c_expr = c.as_expr() + const = R(tanh(c_expr)) + except ValueError: + R = R.add_gens([tanh(c_expr)]) + p = p.set_ring(R) + x = x.set_ring(R) + c = c.set_ring(R) + const = R(tanh(c_expr)) + + p1 = p - c + t1 = rs_tanh(p1, x, prec) + t = rs_series_inversion(1 + const*t1, x, prec) + return rs_mul(const + t1, t, x, prec) + + if R.ngens == 1: + return _tanh(p, x, prec) + else: + return rs_fun(p, _tanh, x, prec) + +def rs_newton(p, x, prec): + """ + Compute the truncated Newton sum of the polynomial ``p`` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_newton + >>> R, x = ring('x', QQ) + >>> p = x**2 - 2 + >>> rs_newton(p, x, 5) + 8*x**4 + 4*x**2 + 2 + """ + deg = p.degree() + p1 = _invert_monoms(p) + p2 = rs_series_inversion(p1, x, prec) + p3 = rs_mul(p1.diff(x), p2, x, prec) + res = deg - p3*x + return res + +def rs_hadamard_exp(p1, inverse=False): + """ + Return ``sum f_i/i!*x**i`` from ``sum f_i*x**i``, + where ``x`` is the first variable. + + If ``inverse=True`` return ``sum f_i*i!*x**i`` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_hadamard_exp + >>> R, x = ring('x', QQ) + >>> p = 1 + x + x**2 + x**3 + >>> rs_hadamard_exp(p) + 1/6*x**3 + 1/2*x**2 + x + 1 + """ + R = p1.ring + if R.domain != QQ: + raise NotImplementedError + p = R.zero + if not inverse: + for exp1, v1 in p1.items(): + p[exp1] = v1/int(ifac(exp1[0])) + else: + for exp1, v1 in p1.items(): + p[exp1] = v1*int(ifac(exp1[0])) + return p + +def rs_compose_add(p1, p2): + """ + compute the composed sum ``prod(p2(x - beta) for beta root of p1)`` + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> from sympy.polys.ring_series import rs_compose_add + >>> R, x = ring('x', QQ) + >>> f = x**2 - 2 + >>> g = x**2 - 3 + >>> rs_compose_add(f, g) + x**4 - 10*x**2 + 1 + + References + ========== + + .. [1] A. Bostan, P. Flajolet, B. Salvy and E. Schost + "Fast Computation with Two Algebraic Numbers", + (2002) Research Report 4579, Institut + National de Recherche en Informatique et en Automatique + """ + R = p1.ring + x = R.gens[0] + prec = p1.degree()*p2.degree() + 1 + np1 = rs_newton(p1, x, prec) + np1e = rs_hadamard_exp(np1) + np2 = rs_newton(p2, x, prec) + np2e = rs_hadamard_exp(np2) + np3e = rs_mul(np1e, np2e, x, prec) + np3 = rs_hadamard_exp(np3e, True) + np3a = (np3[(0,)] - np3) / x + q = rs_integrate(np3a, x) + q = rs_exp(q, x, prec) + q = _invert_monoms(q) + q = q.primitive()[1] + dp = p1.degree()*p2.degree() - q.degree() + # `dp` is the multiplicity of the zeroes of the resultant; + # these zeroes are missed in this computation so they are put here. + # if p1 and p2 are monic irreducible polynomials, + # there are zeroes in the resultant + # if and only if p1 = p2 ; in fact in that case p1 and p2 have a + # root in common, so gcd(p1, p2) != 1; being p1 and p2 irreducible + # this means p1 = p2 + if dp: + q = q*x**dp + return q + + +_convert_func = { + 'sin': 'rs_sin', + 'cos': 'rs_cos', + 'exp': 'rs_exp', + 'tan': 'rs_tan', + 'log': 'rs_log', + 'atan': 'rs_atan', + 'sinh': 'rs_sinh', + 'cosh': 'rs_cosh', + 'tanh': 'rs_tanh' + } + +def rs_min_pow(expr, series_rs, a): + """Find the minimum power of `a` in the series expansion of expr""" + series = 0 + n = 2 + while series == 0: + series = _rs_series(expr, series_rs, a, n) + n *= 2 + R = series.ring + a = R(a) + i = R.gens.index(a) + return min(series, key=lambda t: t[i])[i] + + +def _rs_series(expr, series_rs, a, prec): + # TODO Use _parallel_dict_from_expr instead of sring as sring is + # inefficient. For details, read the todo in sring. + args = expr.args + R = series_rs.ring + + # expr does not contain any function to be expanded + if not any(arg.has(Function) for arg in args) and not expr.is_Function: + return series_rs + + if not expr.has(a): + return series_rs + + elif expr.is_Function: + arg = args[0] + if len(args) > 1: + raise NotImplementedError + R1, series = sring(arg, domain=QQ, expand=False, series=True) + series_inner = _rs_series(arg, series, a, prec) + + # Why do we need to compose these three rings? + # + # We want to use a simple domain (like ``QQ`` or ``RR``) but they don't + # support symbolic coefficients. We need a ring that for example lets + # us have `sin(1)` and `cos(1)` as coefficients if we are expanding + # `sin(x + 1)`. The ``EX`` domain allows all symbolic coefficients, but + # that makes it very complex and hence slow. + # + # To solve this problem, we add only those symbolic elements as + # generators to our ring, that we need. Here, series_inner might + # involve terms like `sin(4)`, `exp(a)`, etc, which are not there in + # R1 or R. Hence, we compose these three rings to create one that has + # the generators of all three. + R = R.compose(R1).compose(series_inner.ring) + series_inner = series_inner.set_ring(R) + series = eval(_convert_func[str(expr.func)])(series_inner, + R(a), prec) + return series + + elif expr.is_Mul: + n = len(args) + for arg in args: # XXX Looks redundant + if not arg.is_Number: + R1, _ = sring(arg, expand=False, series=True) + R = R.compose(R1) + min_pows = list(map(rs_min_pow, args, [R(arg) for arg in args], + [a]*len(args))) + sum_pows = sum(min_pows) + series = R(1) + + for i in range(n): + _series = _rs_series(args[i], R(args[i]), a, ceiling(prec + - sum_pows + min_pows[i])) + R = R.compose(_series.ring) + _series = _series.set_ring(R) + series = series.set_ring(R) + series *= _series + series = rs_trunc(series, R(a), prec) + return series + + elif expr.is_Add: + n = len(args) + series = R(0) + for i in range(n): + _series = _rs_series(args[i], R(args[i]), a, prec) + R = R.compose(_series.ring) + _series = _series.set_ring(R) + series = series.set_ring(R) + series += _series + return series + + elif expr.is_Pow: + R1, _ = sring(expr.base, domain=QQ, expand=False, series=True) + R = R.compose(R1) + series_inner = _rs_series(expr.base, R(expr.base), a, prec) + return rs_pow(series_inner, expr.exp, series_inner.ring(a), prec) + + # The `is_constant` method is buggy hence we check it at the end. + # See issue #9786 for details. + elif isinstance(expr, Expr) and expr.is_constant(): + return sring(expr, domain=QQ, expand=False, series=True)[1] + + else: + raise NotImplementedError + +def rs_series(expr, a, prec): + """Return the series expansion of an expression about 0. + + Parameters + ========== + + expr : :class:`~.Expr` + a : :class:`~.Symbol` with respect to which expr is to be expanded + prec : order of the series expansion + + Currently supports multivariate Taylor series expansion. This is much + faster that SymPy's series method as it uses sparse polynomial operations. + + It automatically creates the simplest ring required to represent the series + expansion through repeated calls to sring. + + Examples + ======== + + >>> from sympy.polys.ring_series import rs_series + >>> from sympy import sin, cos, exp, tan, symbols, QQ + >>> a, b, c = symbols('a, b, c') + >>> rs_series(sin(a) + exp(a), a, 5) + 1/24*a**4 + 1/2*a**2 + 2*a + 1 + >>> series = rs_series(tan(a + b)*cos(a + c), a, 2) + >>> series.as_expr() + -a*sin(c)*tan(b) + a*cos(c)*tan(b)**2 + a*cos(c) + cos(c)*tan(b) + >>> series = rs_series(exp(a**QQ(1,3) + a**QQ(2, 5)), a, 1) + >>> series.as_expr() + a**(11/15) + a**(4/5)/2 + a**(2/5) + a**(2/3)/2 + a**(1/3) + 1 + + """ + R, series = sring(expr, domain=QQ, expand=False, series=True) + if a not in R.symbols: + R = R.add_gens([a, ]) + series = series.set_ring(R) + series = _rs_series(expr, series, a, prec) + R = series.ring + gen = R(a) + prec_got = series.degree(gen) + 1 + + if prec_got >= prec: + return rs_trunc(series, gen, prec) + else: + # increase the requested number of terms to get the desired + # number keep increasing (up to 9) until the received order + # is different than the original order and then predict how + # many additional terms are needed + for more in range(1, 9): + p1 = _rs_series(expr, series, a, prec=prec + more) + gen = gen.set_ring(p1.ring) + new_prec = p1.degree(gen) + 1 + if new_prec != prec_got: + prec_do = ceiling(prec + (prec - prec_got)*more/(new_prec - + prec_got)) + p1 = _rs_series(expr, series, a, prec=prec_do) + while p1.degree(gen) + 1 < prec: + p1 = _rs_series(expr, series, a, prec=prec_do) + gen = gen.set_ring(p1.ring) + prec_do *= 2 + break + else: + break + else: + raise ValueError('Could not calculate %s terms for %s' + % (str(prec), expr)) + return rs_trunc(p1, gen, prec) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rings.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rings.py new file mode 100644 index 0000000000000000000000000000000000000000..9df84dcf1691ac9bcd4aa01a85ca34b7ffc53e5d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rings.py @@ -0,0 +1,3096 @@ +"""Sparse polynomial rings. """ + +from __future__ import annotations + +from operator import add, mul, lt, le, gt, ge +from functools import reduce +from types import GeneratorType + +from sympy.core.cache import cacheit +from sympy.core.expr import Expr +from sympy.core.intfunc import igcd +from sympy.core.symbol import Symbol, symbols as _symbols +from sympy.core.sympify import CantSympify, sympify +from sympy.ntheory.multinomial import multinomial_coefficients +from sympy.polys.compatibility import IPolys +from sympy.polys.constructor import construct_domain +from sympy.polys.densebasic import ninf, dmp_to_dict, dmp_from_dict +from sympy.polys.domains.domain import Domain +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.domains.polynomialring import PolynomialRing +from sympy.polys.heuristicgcd import heugcd +from sympy.polys.monomials import MonomialOps +from sympy.polys.orderings import lex, MonomialOrder +from sympy.polys.polyerrors import ( + CoercionFailed, GeneratorsError, + ExactQuotientFailed, MultivariatePolynomialError) +from sympy.polys.polyoptions import (Domain as DomainOpt, + Order as OrderOpt, build_options) +from sympy.polys.polyutils import (expr_from_dict, _dict_reorder, + _parallel_dict_from_expr) +from sympy.printing.defaults import DefaultPrinting +from sympy.utilities import public, subsets +from sympy.utilities.iterables import is_sequence +from sympy.utilities.magic import pollute + +@public +def ring(symbols, domain, order: MonomialOrder|str = lex): + """Construct a polynomial ring returning ``(ring, x_1, ..., x_n)``. + + Parameters + ========== + + symbols : str + Symbol/Expr or sequence of str, Symbol/Expr (non-empty) + domain : :class:`~.Domain` or coercible + order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex`` + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.orderings import lex + + >>> R, x, y, z = ring("x,y,z", ZZ, lex) + >>> R + Polynomial ring in x, y, z over ZZ with lex order + >>> x + y + z + x + y + z + >>> type(_) + + + """ + _ring = PolyRing(symbols, domain, order) + return (_ring,) + _ring.gens + +@public +def xring(symbols, domain, order=lex): + """Construct a polynomial ring returning ``(ring, (x_1, ..., x_n))``. + + Parameters + ========== + + symbols : str + Symbol/Expr or sequence of str, Symbol/Expr (non-empty) + domain : :class:`~.Domain` or coercible + order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex`` + + Examples + ======== + + >>> from sympy.polys.rings import xring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.orderings import lex + + >>> R, (x, y, z) = xring("x,y,z", ZZ, lex) + >>> R + Polynomial ring in x, y, z over ZZ with lex order + >>> x + y + z + x + y + z + >>> type(_) + + + """ + _ring = PolyRing(symbols, domain, order) + return (_ring, _ring.gens) + +@public +def vring(symbols, domain, order=lex): + """Construct a polynomial ring and inject ``x_1, ..., x_n`` into the global namespace. + + Parameters + ========== + + symbols : str + Symbol/Expr or sequence of str, Symbol/Expr (non-empty) + domain : :class:`~.Domain` or coercible + order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex`` + + Examples + ======== + + >>> from sympy.polys.rings import vring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.orderings import lex + + >>> vring("x,y,z", ZZ, lex) + Polynomial ring in x, y, z over ZZ with lex order + >>> x + y + z # noqa: + x + y + z + >>> type(_) + + + """ + _ring = PolyRing(symbols, domain, order) + pollute([ sym.name for sym in _ring.symbols ], _ring.gens) + return _ring + +@public +def sring(exprs, *symbols, **options): + """Construct a ring deriving generators and domain from options and input expressions. + + Parameters + ========== + + exprs : :class:`~.Expr` or sequence of :class:`~.Expr` (sympifiable) + symbols : sequence of :class:`~.Symbol`/:class:`~.Expr` + options : keyword arguments understood by :class:`~.Options` + + Examples + ======== + + >>> from sympy import sring, symbols + + >>> x, y, z = symbols("x,y,z") + >>> R, f = sring(x + 2*y + 3*z) + >>> R + Polynomial ring in x, y, z over ZZ with lex order + >>> f + x + 2*y + 3*z + >>> type(_) + + + """ + single = False + + if not is_sequence(exprs): + exprs, single = [exprs], True + + exprs = list(map(sympify, exprs)) + opt = build_options(symbols, options) + + # TODO: rewrite this so that it doesn't use expand() (see poly()). + reps, opt = _parallel_dict_from_expr(exprs, opt) + + if opt.domain is None: + coeffs = sum([ list(rep.values()) for rep in reps ], []) + + opt.domain, coeffs_dom = construct_domain(coeffs, opt=opt) + + coeff_map = dict(zip(coeffs, coeffs_dom)) + reps = [{m: coeff_map[c] for m, c in rep.items()} for rep in reps] + + _ring = PolyRing(opt.gens, opt.domain, opt.order) + polys = list(map(_ring.from_dict, reps)) + + if single: + return (_ring, polys[0]) + else: + return (_ring, polys) + +def _parse_symbols(symbols): + if isinstance(symbols, str): + return _symbols(symbols, seq=True) if symbols else () + elif isinstance(symbols, Expr): + return (symbols,) + elif is_sequence(symbols): + if all(isinstance(s, str) for s in symbols): + return _symbols(symbols) + elif all(isinstance(s, Expr) for s in symbols): + return symbols + + raise GeneratorsError("expected a string, Symbol or expression or a non-empty sequence of strings, Symbols or expressions") + + +class PolyRing(DefaultPrinting, IPolys): + """Multivariate distributed polynomial ring. """ + + gens: tuple[PolyElement, ...] + symbols: tuple[Expr, ...] + ngens: int + domain: Domain + order: MonomialOrder + + def __new__(cls, symbols, domain, order=lex): + symbols = tuple(_parse_symbols(symbols)) + ngens = len(symbols) + domain = DomainOpt.preprocess(domain) + order = OrderOpt.preprocess(order) + + _hash_tuple = (cls.__name__, symbols, ngens, domain, order) + + if domain.is_Composite and set(symbols) & set(domain.symbols): + raise GeneratorsError("polynomial ring and it's ground domain share generators") + + obj = object.__new__(cls) + obj._hash_tuple = _hash_tuple + obj._hash = hash(_hash_tuple) + obj.symbols = symbols + obj.ngens = ngens + obj.domain = domain + obj.order = order + + obj.dtype = PolyElement(obj, ()).new + + obj.zero_monom = (0,)*ngens + obj.gens = obj._gens() + obj._gens_set = set(obj.gens) + + obj._one = [(obj.zero_monom, domain.one)] + + if ngens: + # These expect monomials in at least one variable + codegen = MonomialOps(ngens) + obj.monomial_mul = codegen.mul() + obj.monomial_pow = codegen.pow() + obj.monomial_mulpow = codegen.mulpow() + obj.monomial_ldiv = codegen.ldiv() + obj.monomial_div = codegen.div() + obj.monomial_lcm = codegen.lcm() + obj.monomial_gcd = codegen.gcd() + else: + monunit = lambda a, b: () + obj.monomial_mul = monunit + obj.monomial_pow = monunit + obj.monomial_mulpow = lambda a, b, c: () + obj.monomial_ldiv = monunit + obj.monomial_div = monunit + obj.monomial_lcm = monunit + obj.monomial_gcd = monunit + + + if order is lex: + obj.leading_expv = max + else: + obj.leading_expv = lambda f: max(f, key=order) + + for symbol, generator in zip(obj.symbols, obj.gens): + if isinstance(symbol, Symbol): + name = symbol.name + + if not hasattr(obj, name): + setattr(obj, name, generator) + + return obj + + def _gens(self): + """Return a list of polynomial generators. """ + one = self.domain.one + _gens = [] + for i in range(self.ngens): + expv = self.monomial_basis(i) + poly = self.zero + poly[expv] = one + _gens.append(poly) + return tuple(_gens) + + def __getnewargs__(self): + return (self.symbols, self.domain, self.order) + + def __getstate__(self): + state = self.__dict__.copy() + del state["leading_expv"] + + for key in state: + if key.startswith("monomial_"): + del state[key] + + return state + + def __hash__(self): + return self._hash + + def __eq__(self, other): + return isinstance(other, PolyRing) and \ + (self.symbols, self.domain, self.ngens, self.order) == \ + (other.symbols, other.domain, other.ngens, other.order) + + def __ne__(self, other): + return not self == other + + def clone(self, symbols=None, domain=None, order=None): + # Need a hashable tuple for cacheit to work + if symbols is not None and isinstance(symbols, list): + symbols = tuple(symbols) + return self._clone(symbols, domain, order) + + @cacheit + def _clone(self, symbols, domain, order): + return self.__class__(symbols or self.symbols, domain or self.domain, order or self.order) + + def monomial_basis(self, i): + """Return the ith-basis element. """ + basis = [0]*self.ngens + basis[i] = 1 + return tuple(basis) + + @property + def zero(self): + return self.dtype([]) + + @property + def one(self): + return self.dtype(self._one) + + def is_element(self, element): + """True if ``element`` is an element of this ring. False otherwise. """ + return isinstance(element, PolyElement) and element.ring == self + + def domain_new(self, element, orig_domain=None): + return self.domain.convert(element, orig_domain) + + def ground_new(self, coeff): + return self.term_new(self.zero_monom, coeff) + + def term_new(self, monom, coeff): + coeff = self.domain_new(coeff) + poly = self.zero + if coeff: + poly[monom] = coeff + return poly + + def ring_new(self, element): + if isinstance(element, PolyElement): + if self == element.ring: + return element + elif isinstance(self.domain, PolynomialRing) and self.domain.ring == element.ring: + return self.ground_new(element) + else: + raise NotImplementedError("conversion") + elif isinstance(element, str): + raise NotImplementedError("parsing") + elif isinstance(element, dict): + return self.from_dict(element) + elif isinstance(element, list): + try: + return self.from_terms(element) + except ValueError: + return self.from_list(element) + elif isinstance(element, Expr): + return self.from_expr(element) + else: + return self.ground_new(element) + + __call__ = ring_new + + def from_dict(self, element, orig_domain=None): + domain_new = self.domain_new + poly = self.zero + + for monom, coeff in element.items(): + coeff = domain_new(coeff, orig_domain) + if coeff: + poly[monom] = coeff + + return poly + + def from_terms(self, element, orig_domain=None): + return self.from_dict(dict(element), orig_domain) + + def from_list(self, element): + return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain)) + + def _rebuild_expr(self, expr, mapping): + domain = self.domain + + def _rebuild(expr): + generator = mapping.get(expr) + + if generator is not None: + return generator + elif expr.is_Add: + return reduce(add, list(map(_rebuild, expr.args))) + elif expr.is_Mul: + return reduce(mul, list(map(_rebuild, expr.args))) + else: + # XXX: Use as_base_exp() to handle Pow(x, n) and also exp(n) + # XXX: E can be a generator e.g. sring([exp(2)]) -> ZZ[E] + base, exp = expr.as_base_exp() + if exp.is_Integer and exp > 1: + return _rebuild(base)**int(exp) + else: + return self.ground_new(domain.convert(expr)) + + return _rebuild(sympify(expr)) + + def from_expr(self, expr): + mapping = dict(list(zip(self.symbols, self.gens))) + + try: + poly = self._rebuild_expr(expr, mapping) + except CoercionFailed: + raise ValueError("expected an expression convertible to a polynomial in %s, got %s" % (self, expr)) + else: + return self.ring_new(poly) + + def index(self, gen): + """Compute index of ``gen`` in ``self.gens``. """ + if gen is None: + if self.ngens: + i = 0 + else: + i = -1 # indicate impossible choice + elif isinstance(gen, int): + i = gen + + if 0 <= i and i < self.ngens: + pass + elif -self.ngens <= i and i <= -1: + i = -i - 1 + else: + raise ValueError("invalid generator index: %s" % gen) + elif self.is_element(gen): + try: + i = self.gens.index(gen) + except ValueError: + raise ValueError("invalid generator: %s" % gen) + elif isinstance(gen, str): + try: + i = self.symbols.index(gen) + except ValueError: + raise ValueError("invalid generator: %s" % gen) + else: + raise ValueError("expected a polynomial generator, an integer, a string or None, got %s" % gen) + + return i + + def drop(self, *gens): + """Remove specified generators from this ring. """ + indices = set(map(self.index, gens)) + symbols = [ s for i, s in enumerate(self.symbols) if i not in indices ] + + if not symbols: + return self.domain + else: + return self.clone(symbols=symbols) + + def __getitem__(self, key): + symbols = self.symbols[key] + + if not symbols: + return self.domain + else: + return self.clone(symbols=symbols) + + def to_ground(self): + # TODO: should AlgebraicField be a Composite domain? + if self.domain.is_Composite or hasattr(self.domain, 'domain'): + return self.clone(domain=self.domain.domain) + else: + raise ValueError("%s is not a composite domain" % self.domain) + + def to_domain(self): + return PolynomialRing(self) + + def to_field(self): + from sympy.polys.fields import FracField + return FracField(self.symbols, self.domain, self.order) + + @property + def is_univariate(self): + return len(self.gens) == 1 + + @property + def is_multivariate(self): + return len(self.gens) > 1 + + def add(self, *objs): + """ + Add a sequence of polynomials or containers of polynomials. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> R, x = ring("x", ZZ) + >>> R.add([ x**2 + 2*i + 3 for i in range(4) ]) + 4*x**2 + 24 + >>> _.factor_list() + (4, [(x**2 + 6, 1)]) + + """ + p = self.zero + + for obj in objs: + if is_sequence(obj, include=GeneratorType): + p += self.add(*obj) + else: + p += obj + + return p + + def mul(self, *objs): + """ + Multiply a sequence of polynomials or containers of polynomials. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> R, x = ring("x", ZZ) + >>> R.mul([ x**2 + 2*i + 3 for i in range(4) ]) + x**8 + 24*x**6 + 206*x**4 + 744*x**2 + 945 + >>> _.factor_list() + (1, [(x**2 + 3, 1), (x**2 + 5, 1), (x**2 + 7, 1), (x**2 + 9, 1)]) + + """ + p = self.one + + for obj in objs: + if is_sequence(obj, include=GeneratorType): + p *= self.mul(*obj) + else: + p *= obj + + return p + + def drop_to_ground(self, *gens): + r""" + Remove specified generators from the ring and inject them into + its domain. + """ + indices = set(map(self.index, gens)) + symbols = [s for i, s in enumerate(self.symbols) if i not in indices] + gens = [gen for i, gen in enumerate(self.gens) if i not in indices] + + if not symbols: + return self + else: + return self.clone(symbols=symbols, domain=self.drop(*gens)) + + def compose(self, other): + """Add the generators of ``other`` to ``self``""" + if self != other: + syms = set(self.symbols).union(set(other.symbols)) + return self.clone(symbols=list(syms)) + else: + return self + + def add_gens(self, symbols): + """Add the elements of ``symbols`` as generators to ``self``""" + syms = set(self.symbols).union(set(symbols)) + return self.clone(symbols=list(syms)) + + def symmetric_poly(self, n): + """ + Return the elementary symmetric polynomial of degree *n* over + this ring's generators. + """ + if n < 0 or n > self.ngens: + raise ValueError("Cannot generate symmetric polynomial of order %s for %s" % (n, self.gens)) + elif not n: + return self.one + else: + poly = self.zero + for s in subsets(range(self.ngens), int(n)): + monom = tuple(int(i in s) for i in range(self.ngens)) + poly += self.term_new(monom, self.domain.one) + return poly + + +class PolyElement(DomainElement, DefaultPrinting, CantSympify, dict): + """Element of multivariate distributed polynomial ring. """ + + def __init__(self, ring, init): + super().__init__(init) + self.ring = ring + # This check would be too slow to run every time: + # self._check() + + def _check(self): + assert isinstance(self, PolyElement) + assert isinstance(self.ring, PolyRing) + dom = self.ring.domain + assert isinstance(dom, Domain) + for monom, coeff in self.items(): + assert dom.of_type(coeff) + assert len(monom) == self.ring.ngens + assert all(isinstance(exp, int) and exp >= 0 for exp in monom) + + def new(self, init): + return self.__class__(self.ring, init) + + def parent(self): + return self.ring.to_domain() + + def __getnewargs__(self): + return (self.ring, list(self.iterterms())) + + _hash = None + + def __hash__(self): + # XXX: This computes a hash of a dictionary, but currently we don't + # protect dictionary from being changed so any use site modifications + # will make hashing go wrong. Use this feature with caution until we + # figure out how to make a safe API without compromising speed of this + # low-level class. + _hash = self._hash + if _hash is None: + self._hash = _hash = hash((self.ring, frozenset(self.items()))) + return _hash + + def copy(self): + """Return a copy of polynomial self. + + Polynomials are mutable; if one is interested in preserving + a polynomial, and one plans to use inplace operations, one + can copy the polynomial. This method makes a shallow copy. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + + >>> R, x, y = ring('x, y', ZZ) + >>> p = (x + y)**2 + >>> p1 = p.copy() + >>> p2 = p + >>> p[R.zero_monom] = 3 + >>> p + x**2 + 2*x*y + y**2 + 3 + >>> p1 + x**2 + 2*x*y + y**2 + >>> p2 + x**2 + 2*x*y + y**2 + 3 + + """ + return self.new(self) + + def set_ring(self, new_ring): + if self.ring == new_ring: + return self + elif self.ring.symbols != new_ring.symbols: + terms = list(zip(*_dict_reorder(self, self.ring.symbols, new_ring.symbols))) + return new_ring.from_terms(terms, self.ring.domain) + else: + return new_ring.from_dict(self, self.ring.domain) + + def as_expr(self, *symbols): + if not symbols: + symbols = self.ring.symbols + elif len(symbols) != self.ring.ngens: + raise ValueError( + "Wrong number of symbols, expected %s got %s" % + (self.ring.ngens, len(symbols)) + ) + + return expr_from_dict(self.as_expr_dict(), *symbols) + + def as_expr_dict(self): + to_sympy = self.ring.domain.to_sympy + return {monom: to_sympy(coeff) for monom, coeff in self.iterterms()} + + def clear_denoms(self): + domain = self.ring.domain + + if not domain.is_Field or not domain.has_assoc_Ring: + return domain.one, self + + ground_ring = domain.get_ring() + common = ground_ring.one + lcm = ground_ring.lcm + denom = domain.denom + + for coeff in self.values(): + common = lcm(common, denom(coeff)) + + poly = self.new([ (k, v*common) for k, v in self.items() ]) + return common, poly + + def strip_zero(self): + """Eliminate monomials with zero coefficient. """ + for k, v in list(self.items()): + if not v: + del self[k] + + def __eq__(p1, p2): + """Equality test for polynomials. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + + >>> _, x, y = ring('x, y', ZZ) + >>> p1 = (x + y)**2 + (x - y)**2 + >>> p1 == 4*x*y + False + >>> p1 == 2*(x**2 + y**2) + True + + """ + if not p2: + return not p1 + elif p1.ring.is_element(p2): + return dict.__eq__(p1, p2) + elif len(p1) > 1: + return False + else: + return p1.get(p1.ring.zero_monom) == p2 + + def __ne__(p1, p2): + return not p1 == p2 + + def almosteq(p1, p2, tolerance=None): + """Approximate equality test for polynomials. """ + ring = p1.ring + + if ring.is_element(p2): + if set(p1.keys()) != set(p2.keys()): + return False + + almosteq = ring.domain.almosteq + + for k in p1.keys(): + if not almosteq(p1[k], p2[k], tolerance): + return False + return True + elif len(p1) > 1: + return False + else: + try: + p2 = ring.domain.convert(p2) + except CoercionFailed: + return False + else: + return ring.domain.almosteq(p1.const(), p2, tolerance) + + def sort_key(self): + return (len(self), self.terms()) + + def _cmp(p1, p2, op): + if p1.ring.is_element(p2): + return op(p1.sort_key(), p2.sort_key()) + else: + return NotImplemented + + def __lt__(p1, p2): + return p1._cmp(p2, lt) + def __le__(p1, p2): + return p1._cmp(p2, le) + def __gt__(p1, p2): + return p1._cmp(p2, gt) + def __ge__(p1, p2): + return p1._cmp(p2, ge) + + def _drop(self, gen): + ring = self.ring + i = ring.index(gen) + + if ring.ngens == 1: + return i, ring.domain + else: + symbols = list(ring.symbols) + del symbols[i] + return i, ring.clone(symbols=symbols) + + def drop(self, gen): + i, ring = self._drop(gen) + + if self.ring.ngens == 1: + if self.is_ground: + return self.coeff(1) + else: + raise ValueError("Cannot drop %s" % gen) + else: + poly = ring.zero + + for k, v in self.items(): + if k[i] == 0: + K = list(k) + del K[i] + poly[tuple(K)] = v + else: + raise ValueError("Cannot drop %s" % gen) + + return poly + + def _drop_to_ground(self, gen): + ring = self.ring + i = ring.index(gen) + + symbols = list(ring.symbols) + del symbols[i] + return i, ring.clone(symbols=symbols, domain=ring[i]) + + def drop_to_ground(self, gen): + if self.ring.ngens == 1: + raise ValueError("Cannot drop only generator to ground") + + i, ring = self._drop_to_ground(gen) + poly = ring.zero + gen = ring.domain.gens[0] + + for monom, coeff in self.iterterms(): + mon = monom[:i] + monom[i+1:] + if mon not in poly: + poly[mon] = (gen**monom[i]).mul_ground(coeff) + else: + poly[mon] += (gen**monom[i]).mul_ground(coeff) + + return poly + + def to_dense(self): + return dmp_from_dict(self, self.ring.ngens-1, self.ring.domain) + + def to_dict(self): + return dict(self) + + def str(self, printer, precedence, exp_pattern, mul_symbol): + if not self: + return printer._print(self.ring.domain.zero) + prec_mul = precedence["Mul"] + prec_atom = precedence["Atom"] + ring = self.ring + symbols = ring.symbols + ngens = ring.ngens + zm = ring.zero_monom + sexpvs = [] + for expv, coeff in self.terms(): + negative = ring.domain.is_negative(coeff) + sign = " - " if negative else " + " + sexpvs.append(sign) + if expv == zm: + scoeff = printer._print(coeff) + if negative and scoeff.startswith("-"): + scoeff = scoeff[1:] + else: + if negative: + coeff = -coeff + if coeff != self.ring.domain.one: + scoeff = printer.parenthesize(coeff, prec_mul, strict=True) + else: + scoeff = '' + sexpv = [] + for i in range(ngens): + exp = expv[i] + if not exp: + continue + symbol = printer.parenthesize(symbols[i], prec_atom, strict=True) + if exp != 1: + if exp != int(exp) or exp < 0: + sexp = printer.parenthesize(exp, prec_atom, strict=False) + else: + sexp = exp + sexpv.append(exp_pattern % (symbol, sexp)) + else: + sexpv.append('%s' % symbol) + if scoeff: + sexpv = [scoeff] + sexpv + sexpvs.append(mul_symbol.join(sexpv)) + if sexpvs[0] in [" + ", " - "]: + head = sexpvs.pop(0) + if head == " - ": + sexpvs.insert(0, "-") + return "".join(sexpvs) + + @property + def is_generator(self): + return self in self.ring._gens_set + + @property + def is_ground(self): + return not self or (len(self) == 1 and self.ring.zero_monom in self) + + @property + def is_monomial(self): + return not self or (len(self) == 1 and self.LC == 1) + + @property + def is_term(self): + return len(self) <= 1 + + @property + def is_negative(self): + return self.ring.domain.is_negative(self.LC) + + @property + def is_positive(self): + return self.ring.domain.is_positive(self.LC) + + @property + def is_nonnegative(self): + return self.ring.domain.is_nonnegative(self.LC) + + @property + def is_nonpositive(self): + return self.ring.domain.is_nonpositive(self.LC) + + @property + def is_zero(f): + return not f + + @property + def is_one(f): + return f == f.ring.one + + @property + def is_monic(f): + return f.ring.domain.is_one(f.LC) + + @property + def is_primitive(f): + return f.ring.domain.is_one(f.content()) + + @property + def is_linear(f): + return all(sum(monom) <= 1 for monom in f.itermonoms()) + + @property + def is_quadratic(f): + return all(sum(monom) <= 2 for monom in f.itermonoms()) + + @property + def is_squarefree(f): + if not f.ring.ngens: + return True + return f.ring.dmp_sqf_p(f) + + @property + def is_irreducible(f): + if not f.ring.ngens: + return True + return f.ring.dmp_irreducible_p(f) + + @property + def is_cyclotomic(f): + if f.ring.is_univariate: + return f.ring.dup_cyclotomic_p(f) + else: + raise MultivariatePolynomialError("cyclotomic polynomial") + + def __neg__(self): + return self.new([ (monom, -coeff) for monom, coeff in self.iterterms() ]) + + def __pos__(self): + return self + + def __add__(p1, p2): + """Add two polynomials. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + + >>> _, x, y = ring('x, y', ZZ) + >>> (x + y)**2 + (x - y)**2 + 2*x**2 + 2*y**2 + + """ + if not p2: + return p1.copy() + ring = p1.ring + if ring.is_element(p2): + p = p1.copy() + get = p.get + zero = ring.domain.zero + for k, v in p2.items(): + v = get(k, zero) + v + if v: + p[k] = v + else: + del p[k] + return p + elif isinstance(p2, PolyElement): + if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__radd__(p1) + else: + return NotImplemented + + try: + cp2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + p = p1.copy() + if not cp2: + return p + zm = ring.zero_monom + if zm not in p1.keys(): + p[zm] = cp2 + else: + if p2 == -p[zm]: + del p[zm] + else: + p[zm] += cp2 + return p + + def __radd__(p1, n): + p = p1.copy() + if not n: + return p + ring = p1.ring + try: + n = ring.domain_new(n) + except CoercionFailed: + return NotImplemented + else: + zm = ring.zero_monom + if zm not in p1.keys(): + p[zm] = n + else: + if n == -p[zm]: + del p[zm] + else: + p[zm] += n + return p + + def __sub__(p1, p2): + """Subtract polynomial p2 from p1. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + + >>> _, x, y = ring('x, y', ZZ) + >>> p1 = x + y**2 + >>> p2 = x*y + y**2 + >>> p1 - p2 + -x*y + x + + """ + if not p2: + return p1.copy() + ring = p1.ring + if ring.is_element(p2): + p = p1.copy() + get = p.get + zero = ring.domain.zero + for k, v in p2.items(): + v = get(k, zero) - v + if v: + p[k] = v + else: + del p[k] + return p + elif isinstance(p2, PolyElement): + if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__rsub__(p1) + else: + return NotImplemented + + try: + p2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + p = p1.copy() + zm = ring.zero_monom + if zm not in p1.keys(): + p[zm] = -p2 + else: + if p2 == p[zm]: + del p[zm] + else: + p[zm] -= p2 + return p + + def __rsub__(p1, n): + """n - p1 with n convertible to the coefficient domain. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y + >>> 4 - p + -x - y + 4 + + """ + ring = p1.ring + try: + n = ring.domain_new(n) + except CoercionFailed: + return NotImplemented + else: + p = ring.zero + for expv in p1: + p[expv] = -p1[expv] + p += n + # p._check() + return p + + def __mul__(p1, p2): + """Multiply two polynomials. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + + >>> _, x, y = ring('x, y', QQ) + >>> p1 = x + y + >>> p2 = x - y + >>> p1*p2 + x**2 - y**2 + + """ + ring = p1.ring + p = ring.zero + if not p1 or not p2: + return p + elif ring.is_element(p2): + get = p.get + zero = ring.domain.zero + monomial_mul = ring.monomial_mul + p2it = list(p2.items()) + for exp1, v1 in p1.items(): + for exp2, v2 in p2it: + exp = monomial_mul(exp1, exp2) + p[exp] = get(exp, zero) + v1*v2 + p.strip_zero() + # p._check() + return p + elif isinstance(p2, PolyElement): + if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__rmul__(p1) + else: + return NotImplemented + + try: + p2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + for exp1, v1 in p1.items(): + v = v1*p2 + if v: + p[exp1] = v + # p._check() + return p + + def __rmul__(p1, p2): + """p2 * p1 with p2 in the coefficient domain of p1. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y + >>> 4 * p + 4*x + 4*y + + """ + p = p1.ring.zero + if not p2: + return p + try: + p2 = p.ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + for exp1, v1 in p1.items(): + v = p2*v1 + if v: + p[exp1] = v + return p + + def __pow__(self, n): + """raise polynomial to power `n` + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y**2 + >>> p**3 + x**3 + 3*x**2*y**2 + 3*x*y**4 + y**6 + + """ + if not isinstance(n, int): + raise TypeError("exponent must be an integer, got %s" % n) + elif n < 0: + raise ValueError("exponent must be a non-negative integer, got %s" % n) + + ring = self.ring + + if not n: + if self: + return ring.one + else: + raise ValueError("0**0") + elif len(self) == 1: + monom, coeff = list(self.items())[0] + p = ring.zero + if coeff == ring.domain.one: + p[ring.monomial_pow(monom, n)] = coeff + else: + p[ring.monomial_pow(monom, n)] = coeff**n + # p._check() + return p + + # For ring series, we need negative and rational exponent support only + # with monomials. + n = int(n) + if n < 0: + raise ValueError("Negative exponent") + + elif n == 1: + return self.copy() + elif n == 2: + return self.square() + elif n == 3: + return self*self.square() + elif len(self) <= 5: # TODO: use an actual density measure + return self._pow_multinomial(n) + else: + return self._pow_generic(n) + + def _pow_generic(self, n): + p = self.ring.one + c = self + + while True: + if n & 1: + p = p*c + n -= 1 + if not n: + break + + c = c.square() + n = n // 2 + + return p + + def _pow_multinomial(self, n): + multinomials = multinomial_coefficients(len(self), n).items() + monomial_mulpow = self.ring.monomial_mulpow + zero_monom = self.ring.zero_monom + terms = self.items() + zero = self.ring.domain.zero + poly = self.ring.zero + + for multinomial, multinomial_coeff in multinomials: + product_monom = zero_monom + product_coeff = multinomial_coeff + + for exp, (monom, coeff) in zip(multinomial, terms): + if exp: + product_monom = monomial_mulpow(product_monom, monom, exp) + product_coeff *= coeff**exp + + monom = tuple(product_monom) + coeff = product_coeff + + coeff = poly.get(monom, zero) + coeff + + if coeff: + poly[monom] = coeff + elif monom in poly: + del poly[monom] + + return poly + + def square(self): + """square of a polynomial + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y**2 + >>> p.square() + x**2 + 2*x*y**2 + y**4 + + """ + ring = self.ring + p = ring.zero + get = p.get + keys = list(self.keys()) + zero = ring.domain.zero + monomial_mul = ring.monomial_mul + for i in range(len(keys)): + k1 = keys[i] + pk = self[k1] + for j in range(i): + k2 = keys[j] + exp = monomial_mul(k1, k2) + p[exp] = get(exp, zero) + pk*self[k2] + p = p.imul_num(2) + get = p.get + for k, v in self.items(): + k2 = monomial_mul(k, k) + p[k2] = get(k2, zero) + v**2 + p.strip_zero() + # p._check() + return p + + def __divmod__(p1, p2): + ring = p1.ring + + if not p2: + raise ZeroDivisionError("polynomial division") + elif ring.is_element(p2): + return p1.div(p2) + elif isinstance(p2, PolyElement): + if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__rdivmod__(p1) + else: + return NotImplemented + + try: + p2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + return (p1.quo_ground(p2), p1.rem_ground(p2)) + + def __rdivmod__(p1, p2): + ring = p1.ring + try: + p2 = ring.ground_new(p2) + except CoercionFailed: + return NotImplemented + else: + return p2.div(p1) + + def __mod__(p1, p2): + ring = p1.ring + + if not p2: + raise ZeroDivisionError("polynomial division") + elif ring.is_element(p2): + return p1.rem(p2) + elif isinstance(p2, PolyElement): + if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__rmod__(p1) + else: + return NotImplemented + + try: + p2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + return p1.rem_ground(p2) + + def __rmod__(p1, p2): + ring = p1.ring + try: + p2 = ring.ground_new(p2) + except CoercionFailed: + return NotImplemented + else: + return p2.rem(p1) + + def __floordiv__(p1, p2): + ring = p1.ring + + if not p2: + raise ZeroDivisionError("polynomial division") + elif ring.is_element(p2): + return p1.quo(p2) + elif isinstance(p2, PolyElement): + if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__rtruediv__(p1) + else: + return NotImplemented + + try: + p2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + return p1.quo_ground(p2) + + def __rfloordiv__(p1, p2): + ring = p1.ring + try: + p2 = ring.ground_new(p2) + except CoercionFailed: + return NotImplemented + else: + return p2.quo(p1) + + def __truediv__(p1, p2): + ring = p1.ring + + if not p2: + raise ZeroDivisionError("polynomial division") + elif ring.is_element(p2): + return p1.exquo(p2) + elif isinstance(p2, PolyElement): + if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__rtruediv__(p1) + else: + return NotImplemented + + try: + p2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + return p1.quo_ground(p2) + + def __rtruediv__(p1, p2): + ring = p1.ring + try: + p2 = ring.ground_new(p2) + except CoercionFailed: + return NotImplemented + else: + return p2.exquo(p1) + + def _term_div(self): + zm = self.ring.zero_monom + domain = self.ring.domain + domain_quo = domain.quo + monomial_div = self.ring.monomial_div + + if domain.is_Field: + def term_div(a_lm_a_lc, b_lm_b_lc): + a_lm, a_lc = a_lm_a_lc + b_lm, b_lc = b_lm_b_lc + if b_lm == zm: # apparently this is a very common case + monom = a_lm + else: + monom = monomial_div(a_lm, b_lm) + if monom is not None: + return monom, domain_quo(a_lc, b_lc) + else: + return None + else: + def term_div(a_lm_a_lc, b_lm_b_lc): + a_lm, a_lc = a_lm_a_lc + b_lm, b_lc = b_lm_b_lc + if b_lm == zm: # apparently this is a very common case + monom = a_lm + else: + monom = monomial_div(a_lm, b_lm) + if not (monom is None or a_lc % b_lc): + return monom, domain_quo(a_lc, b_lc) + else: + return None + + return term_div + + def div(self, fv): + """Division algorithm, see [CLO] p64. + + fv array of polynomials + return qv, r such that + self = sum(fv[i]*qv[i]) + r + + All polynomials are required not to be Laurent polynomials. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring('x, y', ZZ) + >>> f = x**3 + >>> f0 = x - y**2 + >>> f1 = x - y + >>> qv, r = f.div((f0, f1)) + >>> qv[0] + x**2 + x*y**2 + y**4 + >>> qv[1] + 0 + >>> r + y**6 + + """ + ring = self.ring + ret_single = False + if isinstance(fv, PolyElement): + ret_single = True + fv = [fv] + if not all(fv): + raise ZeroDivisionError("polynomial division") + if not self: + if ret_single: + return ring.zero, ring.zero + else: + return [], ring.zero + for f in fv: + if f.ring != ring: + raise ValueError('self and f must have the same ring') + s = len(fv) + qv = [ring.zero for i in range(s)] + p = self.copy() + r = ring.zero + term_div = self._term_div() + expvs = [fx.leading_expv() for fx in fv] + while p: + i = 0 + divoccurred = 0 + while i < s and divoccurred == 0: + expv = p.leading_expv() + term = term_div((expv, p[expv]), (expvs[i], fv[i][expvs[i]])) + if term is not None: + expv1, c = term + qv[i] = qv[i]._iadd_monom((expv1, c)) + p = p._iadd_poly_monom(fv[i], (expv1, -c)) + divoccurred = 1 + else: + i += 1 + if not divoccurred: + expv = p.leading_expv() + r = r._iadd_monom((expv, p[expv])) + del p[expv] + if expv == ring.zero_monom: + r += p + if ret_single: + if not qv: + return ring.zero, r + else: + return qv[0], r + else: + return qv, r + + def rem(self, G): + f = self + if isinstance(G, PolyElement): + G = [G] + if not all(G): + raise ZeroDivisionError("polynomial division") + ring = f.ring + domain = ring.domain + zero = domain.zero + monomial_mul = ring.monomial_mul + r = ring.zero + term_div = f._term_div() + ltf = f.LT + f = f.copy() + get = f.get + while f: + for g in G: + tq = term_div(ltf, g.LT) + if tq is not None: + m, c = tq + for mg, cg in g.iterterms(): + m1 = monomial_mul(mg, m) + c1 = get(m1, zero) - c*cg + if not c1: + del f[m1] + else: + f[m1] = c1 + ltm = f.leading_expv() + if ltm is not None: + ltf = ltm, f[ltm] + + break + else: + ltm, ltc = ltf + if ltm in r: + r[ltm] += ltc + else: + r[ltm] = ltc + del f[ltm] + ltm = f.leading_expv() + if ltm is not None: + ltf = ltm, f[ltm] + + return r + + def quo(f, G): + return f.div(G)[0] + + def exquo(f, G): + q, r = f.div(G) + + if not r: + return q + else: + raise ExactQuotientFailed(f, G) + + def _iadd_monom(self, mc): + """add to self the monomial coeff*x0**i0*x1**i1*... + unless self is a generator -- then just return the sum of the two. + + mc is a tuple, (monom, coeff), where monomial is (i0, i1, ...) + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring('x, y', ZZ) + >>> p = x**4 + 2*y + >>> m = (1, 2) + >>> p1 = p._iadd_monom((m, 5)) + >>> p1 + x**4 + 5*x*y**2 + 2*y + >>> p1 is p + True + >>> p = x + >>> p1 = p._iadd_monom((m, 5)) + >>> p1 + 5*x*y**2 + x + >>> p1 is p + False + + """ + if self in self.ring._gens_set: + cpself = self.copy() + else: + cpself = self + expv, coeff = mc + c = cpself.get(expv) + if c is None: + cpself[expv] = coeff + else: + c += coeff + if c: + cpself[expv] = c + else: + del cpself[expv] + return cpself + + def _iadd_poly_monom(self, p2, mc): + """add to self the product of (p)*(coeff*x0**i0*x1**i1*...) + unless self is a generator -- then just return the sum of the two. + + mc is a tuple, (monom, coeff), where monomial is (i0, i1, ...) + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y, z = ring('x, y, z', ZZ) + >>> p1 = x**4 + 2*y + >>> p2 = y + z + >>> m = (1, 2, 3) + >>> p1 = p1._iadd_poly_monom(p2, (m, 3)) + >>> p1 + x**4 + 3*x*y**3*z**3 + 3*x*y**2*z**4 + 2*y + + """ + p1 = self + if p1 in p1.ring._gens_set: + p1 = p1.copy() + (m, c) = mc + get = p1.get + zero = p1.ring.domain.zero + monomial_mul = p1.ring.monomial_mul + for k, v in p2.items(): + ka = monomial_mul(k, m) + coeff = get(ka, zero) + v*c + if coeff: + p1[ka] = coeff + else: + del p1[ka] + return p1 + + def degree(f, x=None): + """ + The leading degree in ``x`` or the main variable. + + Note that the degree of 0 is negative infinity (``float('-inf')``) + + """ + i = f.ring.index(x) + + if not f: + return ninf + elif i < 0: + return 0 + else: + return max(monom[i] for monom in f.itermonoms()) + + def degrees(f): + """ + A tuple containing leading degrees in all variables. + + Note that the degree of 0 is negative infinity (``float('-inf')``) + + """ + if not f: + return (ninf,)*f.ring.ngens + else: + return tuple(map(max, list(zip(*f.itermonoms())))) + + def tail_degree(f, x=None): + """ + The tail degree in ``x`` or the main variable. + + Note that the degree of 0 is negative infinity (``float('-inf')``) + + """ + i = f.ring.index(x) + + if not f: + return ninf + elif i < 0: + return 0 + else: + return min(monom[i] for monom in f.itermonoms()) + + def tail_degrees(f): + """ + A tuple containing tail degrees in all variables. + + Note that the degree of 0 is negative infinity (``float('-inf')``) + + """ + if not f: + return (ninf,)*f.ring.ngens + else: + return tuple(map(min, list(zip(*f.itermonoms())))) + + def leading_expv(self): + """Leading monomial tuple according to the monomial ordering. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y, z = ring('x, y, z', ZZ) + >>> p = x**4 + x**3*y + x**2*z**2 + z**7 + >>> p.leading_expv() + (4, 0, 0) + + """ + if self: + return self.ring.leading_expv(self) + else: + return None + + def _get_coeff(self, expv): + return self.get(expv, self.ring.domain.zero) + + def coeff(self, element): + """ + Returns the coefficient that stands next to the given monomial. + + Parameters + ========== + + element : PolyElement (with ``is_monomial = True``) or 1 + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y, z = ring("x,y,z", ZZ) + >>> f = 3*x**2*y - x*y*z + 7*z**3 + 23 + + >>> f.coeff(x**2*y) + 3 + >>> f.coeff(x*y) + 0 + >>> f.coeff(1) + 23 + + """ + if element == 1: + return self._get_coeff(self.ring.zero_monom) + elif self.ring.is_element(element): + terms = list(element.iterterms()) + if len(terms) == 1: + monom, coeff = terms[0] + if coeff == self.ring.domain.one: + return self._get_coeff(monom) + + raise ValueError("expected a monomial, got %s" % element) + + def const(self): + """Returns the constant coefficient. """ + return self._get_coeff(self.ring.zero_monom) + + @property + def LC(self): + return self._get_coeff(self.leading_expv()) + + @property + def LM(self): + expv = self.leading_expv() + if expv is None: + return self.ring.zero_monom + else: + return expv + + def leading_monom(self): + """ + Leading monomial as a polynomial element. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring('x, y', ZZ) + >>> (3*x*y + y**2).leading_monom() + x*y + + """ + p = self.ring.zero + expv = self.leading_expv() + if expv: + p[expv] = self.ring.domain.one + return p + + @property + def LT(self): + expv = self.leading_expv() + if expv is None: + return (self.ring.zero_monom, self.ring.domain.zero) + else: + return (expv, self._get_coeff(expv)) + + def leading_term(self): + """Leading term as a polynomial element. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring('x, y', ZZ) + >>> (3*x*y + y**2).leading_term() + 3*x*y + + """ + p = self.ring.zero + expv = self.leading_expv() + if expv is not None: + p[expv] = self[expv] + return p + + def _sorted(self, seq, order): + if order is None: + order = self.ring.order + else: + order = OrderOpt.preprocess(order) + + if order is lex: + return sorted(seq, key=lambda monom: monom[0], reverse=True) + else: + return sorted(seq, key=lambda monom: order(monom[0]), reverse=True) + + def coeffs(self, order=None): + """Ordered list of polynomial coefficients. + + Parameters + ========== + + order : :class:`~.MonomialOrder` or coercible, optional + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.orderings import lex, grlex + + >>> _, x, y = ring("x, y", ZZ, lex) + >>> f = x*y**7 + 2*x**2*y**3 + + >>> f.coeffs() + [2, 1] + >>> f.coeffs(grlex) + [1, 2] + + """ + return [ coeff for _, coeff in self.terms(order) ] + + def monoms(self, order=None): + """Ordered list of polynomial monomials. + + Parameters + ========== + + order : :class:`~.MonomialOrder` or coercible, optional + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.orderings import lex, grlex + + >>> _, x, y = ring("x, y", ZZ, lex) + >>> f = x*y**7 + 2*x**2*y**3 + + >>> f.monoms() + [(2, 3), (1, 7)] + >>> f.monoms(grlex) + [(1, 7), (2, 3)] + + """ + return [ monom for monom, _ in self.terms(order) ] + + def terms(self, order=None): + """Ordered list of polynomial terms. + + Parameters + ========== + + order : :class:`~.MonomialOrder` or coercible, optional + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.orderings import lex, grlex + + >>> _, x, y = ring("x, y", ZZ, lex) + >>> f = x*y**7 + 2*x**2*y**3 + + >>> f.terms() + [((2, 3), 2), ((1, 7), 1)] + >>> f.terms(grlex) + [((1, 7), 1), ((2, 3), 2)] + + """ + return self._sorted(list(self.items()), order) + + def itercoeffs(self): + """Iterator over coefficients of a polynomial. """ + return iter(self.values()) + + def itermonoms(self): + """Iterator over monomials of a polynomial. """ + return iter(self.keys()) + + def iterterms(self): + """Iterator over terms of a polynomial. """ + return iter(self.items()) + + def listcoeffs(self): + """Unordered list of polynomial coefficients. """ + return list(self.values()) + + def listmonoms(self): + """Unordered list of polynomial monomials. """ + return list(self.keys()) + + def listterms(self): + """Unordered list of polynomial terms. """ + return list(self.items()) + + def imul_num(p, c): + """multiply inplace the polynomial p by an element in the + coefficient ring, provided p is not one of the generators; + else multiply not inplace + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y**2 + >>> p1 = p.imul_num(3) + >>> p1 + 3*x + 3*y**2 + >>> p1 is p + True + >>> p = x + >>> p1 = p.imul_num(3) + >>> p1 + 3*x + >>> p1 is p + False + + """ + if p in p.ring._gens_set: + return p*c + if not c: + p.clear() + return + for exp in p: + p[exp] *= c + return p + + def content(f): + """Returns GCD of polynomial's coefficients. """ + domain = f.ring.domain + cont = domain.zero + gcd = domain.gcd + + for coeff in f.itercoeffs(): + cont = gcd(cont, coeff) + + return cont + + def primitive(f): + """Returns content and a primitive polynomial. """ + cont = f.content() + if cont == f.ring.domain.zero: + return (cont, f) + return cont, f.quo_ground(cont) + + def monic(f): + """Divides all coefficients by the leading coefficient. """ + if not f: + return f + else: + return f.quo_ground(f.LC) + + def mul_ground(f, x): + if not x: + return f.ring.zero + + terms = [ (monom, coeff*x) for monom, coeff in f.iterterms() ] + return f.new(terms) + + def mul_monom(f, monom): + monomial_mul = f.ring.monomial_mul + terms = [ (monomial_mul(f_monom, monom), f_coeff) for f_monom, f_coeff in f.items() ] + return f.new(terms) + + def mul_term(f, term): + monom, coeff = term + + if not f or not coeff: + return f.ring.zero + elif monom == f.ring.zero_monom: + return f.mul_ground(coeff) + + monomial_mul = f.ring.monomial_mul + terms = [ (monomial_mul(f_monom, monom), f_coeff*coeff) for f_monom, f_coeff in f.items() ] + return f.new(terms) + + def quo_ground(f, x): + domain = f.ring.domain + + if not x: + raise ZeroDivisionError('polynomial division') + if not f or x == domain.one: + return f + + if domain.is_Field: + quo = domain.quo + terms = [ (monom, quo(coeff, x)) for monom, coeff in f.iterterms() ] + else: + terms = [ (monom, coeff // x) for monom, coeff in f.iterterms() if not (coeff % x) ] + + return f.new(terms) + + def quo_term(f, term): + monom, coeff = term + + if not coeff: + raise ZeroDivisionError("polynomial division") + elif not f: + return f.ring.zero + elif monom == f.ring.zero_monom: + return f.quo_ground(coeff) + + term_div = f._term_div() + + terms = [ term_div(t, term) for t in f.iterterms() ] + return f.new([ t for t in terms if t is not None ]) + + def trunc_ground(f, p): + if f.ring.domain.is_ZZ: + terms = [] + + for monom, coeff in f.iterterms(): + coeff = coeff % p + + if coeff > p // 2: + coeff = coeff - p + + terms.append((monom, coeff)) + else: + terms = [ (monom, coeff % p) for monom, coeff in f.iterterms() ] + + poly = f.new(terms) + poly.strip_zero() + return poly + + rem_ground = trunc_ground + + def extract_ground(self, g): + f = self + fc = f.content() + gc = g.content() + + gcd = f.ring.domain.gcd(fc, gc) + + f = f.quo_ground(gcd) + g = g.quo_ground(gcd) + + return gcd, f, g + + def _norm(f, norm_func): + if not f: + return f.ring.domain.zero + else: + ground_abs = f.ring.domain.abs + return norm_func([ ground_abs(coeff) for coeff in f.itercoeffs() ]) + + def max_norm(f): + return f._norm(max) + + def l1_norm(f): + return f._norm(sum) + + def deflate(f, *G): + ring = f.ring + polys = [f] + list(G) + + J = [0]*ring.ngens + + for p in polys: + for monom in p.itermonoms(): + for i, m in enumerate(monom): + J[i] = igcd(J[i], m) + + for i, b in enumerate(J): + if not b: + J[i] = 1 + + J = tuple(J) + + if all(b == 1 for b in J): + return J, polys + + H = [] + + for p in polys: + h = ring.zero + + for I, coeff in p.iterterms(): + N = [ i // j for i, j in zip(I, J) ] + h[tuple(N)] = coeff + + H.append(h) + + return J, H + + def inflate(f, J): + poly = f.ring.zero + + for I, coeff in f.iterterms(): + N = [ i*j for i, j in zip(I, J) ] + poly[tuple(N)] = coeff + + return poly + + def lcm(self, g): + f = self + domain = f.ring.domain + + if not domain.is_Field: + fc, f = f.primitive() + gc, g = g.primitive() + c = domain.lcm(fc, gc) + + h = (f*g).quo(f.gcd(g)) + + if not domain.is_Field: + return h.mul_ground(c) + else: + return h.monic() + + def gcd(f, g): + return f.cofactors(g)[0] + + def cofactors(f, g): + if not f and not g: + zero = f.ring.zero + return zero, zero, zero + elif not f: + h, cff, cfg = f._gcd_zero(g) + return h, cff, cfg + elif not g: + h, cfg, cff = g._gcd_zero(f) + return h, cff, cfg + elif len(f) == 1: + h, cff, cfg = f._gcd_monom(g) + return h, cff, cfg + elif len(g) == 1: + h, cfg, cff = g._gcd_monom(f) + return h, cff, cfg + + J, (f, g) = f.deflate(g) + h, cff, cfg = f._gcd(g) + + return (h.inflate(J), cff.inflate(J), cfg.inflate(J)) + + def _gcd_zero(f, g): + one, zero = f.ring.one, f.ring.zero + if g.is_nonnegative: + return g, zero, one + else: + return -g, zero, -one + + def _gcd_monom(f, g): + ring = f.ring + ground_gcd = ring.domain.gcd + ground_quo = ring.domain.quo + monomial_gcd = ring.monomial_gcd + monomial_ldiv = ring.monomial_ldiv + mf, cf = list(f.iterterms())[0] + _mgcd, _cgcd = mf, cf + for mg, cg in g.iterterms(): + _mgcd = monomial_gcd(_mgcd, mg) + _cgcd = ground_gcd(_cgcd, cg) + h = f.new([(_mgcd, _cgcd)]) + cff = f.new([(monomial_ldiv(mf, _mgcd), ground_quo(cf, _cgcd))]) + cfg = f.new([(monomial_ldiv(mg, _mgcd), ground_quo(cg, _cgcd)) for mg, cg in g.iterterms()]) + return h, cff, cfg + + def _gcd(f, g): + ring = f.ring + + if ring.domain.is_QQ: + return f._gcd_QQ(g) + elif ring.domain.is_ZZ: + return f._gcd_ZZ(g) + else: # TODO: don't use dense representation (port PRS algorithms) + return ring.dmp_inner_gcd(f, g) + + def _gcd_ZZ(f, g): + return heugcd(f, g) + + def _gcd_QQ(self, g): + f = self + ring = f.ring + new_ring = ring.clone(domain=ring.domain.get_ring()) + + cf, f = f.clear_denoms() + cg, g = g.clear_denoms() + + f = f.set_ring(new_ring) + g = g.set_ring(new_ring) + + h, cff, cfg = f._gcd_ZZ(g) + + h = h.set_ring(ring) + c, h = h.LC, h.monic() + + cff = cff.set_ring(ring).mul_ground(ring.domain.quo(c, cf)) + cfg = cfg.set_ring(ring).mul_ground(ring.domain.quo(c, cg)) + + return h, cff, cfg + + def cancel(self, g): + """ + Cancel common factors in a rational function ``f/g``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> (2*x**2 - 2).cancel(x**2 - 2*x + 1) + (2*x + 2, x - 1) + + """ + f = self + ring = f.ring + + if not f: + return f, ring.one + + domain = ring.domain + + if not (domain.is_Field and domain.has_assoc_Ring): + _, p, q = f.cofactors(g) + else: + new_ring = ring.clone(domain=domain.get_ring()) + + cq, f = f.clear_denoms() + cp, g = g.clear_denoms() + + f = f.set_ring(new_ring) + g = g.set_ring(new_ring) + + _, p, q = f.cofactors(g) + _, cp, cq = new_ring.domain.cofactors(cp, cq) + + p = p.set_ring(ring) + q = q.set_ring(ring) + + p = p.mul_ground(cp) + q = q.mul_ground(cq) + + # Make canonical with respect to sign or quadrant in the case of ZZ_I + # or QQ_I. This ensures that the LC of the denominator is canonical by + # multiplying top and bottom by a unit of the ring. + u = q.canonical_unit() + if u == domain.one: + pass + elif u == -domain.one: + p, q = -p, -q + else: + p = p.mul_ground(u) + q = q.mul_ground(u) + + return p, q + + def canonical_unit(f): + domain = f.ring.domain + return domain.canonical_unit(f.LC) + + def diff(f, x): + """Computes partial derivative in ``x``. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring("x,y", ZZ) + >>> p = x + x**2*y**3 + >>> p.diff(x) + 2*x*y**3 + 1 + + """ + ring = f.ring + i = ring.index(x) + m = ring.monomial_basis(i) + g = ring.zero + for expv, coeff in f.iterterms(): + if expv[i]: + e = ring.monomial_ldiv(expv, m) + g[e] = ring.domain_new(coeff*expv[i]) + return g + + def __call__(f, *values): + if 0 < len(values) <= f.ring.ngens: + return f.evaluate(list(zip(f.ring.gens, values))) + else: + raise ValueError("expected at least 1 and at most %s values, got %s" % (f.ring.ngens, len(values))) + + def evaluate(self, x, a=None): + f = self + + if isinstance(x, list) and a is None: + (X, a), x = x[0], x[1:] + f = f.evaluate(X, a) + + if not x: + return f + else: + x = [ (Y.drop(X), a) for (Y, a) in x ] + return f.evaluate(x) + + ring = f.ring + i = ring.index(x) + a = ring.domain.convert(a) + + if ring.ngens == 1: + result = ring.domain.zero + + for (n,), coeff in f.iterterms(): + result += coeff*a**n + + return result + else: + poly = ring.drop(x).zero + + for monom, coeff in f.iterterms(): + n, monom = monom[i], monom[:i] + monom[i+1:] + coeff = coeff*a**n + + if monom in poly: + coeff = coeff + poly[monom] + + if coeff: + poly[monom] = coeff + else: + del poly[monom] + else: + if coeff: + poly[monom] = coeff + + return poly + + def subs(self, x, a=None): + f = self + + if isinstance(x, list) and a is None: + for X, a in x: + f = f.subs(X, a) + return f + + ring = f.ring + i = ring.index(x) + a = ring.domain.convert(a) + + if ring.ngens == 1: + result = ring.domain.zero + + for (n,), coeff in f.iterterms(): + result += coeff*a**n + + return ring.ground_new(result) + else: + poly = ring.zero + + for monom, coeff in f.iterterms(): + n, monom = monom[i], monom[:i] + (0,) + monom[i+1:] + coeff = coeff*a**n + + if monom in poly: + coeff = coeff + poly[monom] + + if coeff: + poly[monom] = coeff + else: + del poly[monom] + else: + if coeff: + poly[monom] = coeff + + return poly + + def symmetrize(self): + r""" + Rewrite *self* in terms of elementary symmetric polynomials. + + Explanation + =========== + + If this :py:class:`~.PolyElement` belongs to a ring of $n$ variables, + we can try to write it as a function of the elementary symmetric + polynomials on $n$ variables. We compute a symmetric part, and a + remainder for any part we were not able to symmetrize. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> R, x, y = ring("x,y", ZZ) + + >>> f = x**2 + y**2 + >>> f.symmetrize() + (x**2 - 2*y, 0, [(x, x + y), (y, x*y)]) + + >>> f = x**2 - y**2 + >>> f.symmetrize() + (x**2 - 2*y, -2*y**2, [(x, x + y), (y, x*y)]) + + Returns + ======= + + Triple ``(p, r, m)`` + ``p`` is a :py:class:`~.PolyElement` that represents our attempt + to express *self* as a function of elementary symmetric + polynomials. Each variable in ``p`` stands for one of the + elementary symmetric polynomials. The correspondence is given + by ``m``. + + ``r`` is the remainder. + + ``m`` is a list of pairs, giving the mapping from variables in + ``p`` to elementary symmetric polynomials. + + The triple satisfies the equation ``p.compose(m) + r == self``. + If the remainder ``r`` is zero, *self* is symmetric. If it is + nonzero, we were not able to represent *self* as symmetric. + + See Also + ======== + + sympy.polys.polyfuncs.symmetrize + + References + ========== + + .. [1] Lauer, E. Algorithms for symmetrical polynomials, Proc. 1976 + ACM Symp. on Symbolic and Algebraic Computing, NY 242-247. + https://dl.acm.org/doi/pdf/10.1145/800205.806342 + + """ + f = self.copy() + ring = f.ring + n = ring.ngens + + if not n: + return f, ring.zero, [] + + polys = [ring.symmetric_poly(i+1) for i in range(n)] + + poly_powers = {} + def get_poly_power(i, n): + if (i, n) not in poly_powers: + poly_powers[(i, n)] = polys[i]**n + return poly_powers[(i, n)] + + indices = list(range(n - 1)) + weights = list(range(n, 0, -1)) + + symmetric = ring.zero + + while f: + _height, _monom, _coeff = -1, None, None + + for i, (monom, coeff) in enumerate(f.terms()): + if all(monom[i] >= monom[i + 1] for i in indices): + height = max(n*m for n, m in zip(weights, monom)) + + if height > _height: + _height, _monom, _coeff = height, monom, coeff + + if _height != -1: + monom, coeff = _monom, _coeff + else: + break + + exponents = [] + for m1, m2 in zip(monom, monom[1:] + (0,)): + exponents.append(m1 - m2) + + symmetric += ring.term_new(tuple(exponents), coeff) + + product = coeff + for i, n in enumerate(exponents): + product *= get_poly_power(i, n) + f -= product + + mapping = list(zip(ring.gens, polys)) + + return symmetric, f, mapping + + def compose(f, x, a=None): + ring = f.ring + poly = ring.zero + gens_map = dict(zip(ring.gens, range(ring.ngens))) + + if a is not None: + replacements = [(x, a)] + else: + if isinstance(x, list): + replacements = list(x) + elif isinstance(x, dict): + replacements = sorted(x.items(), key=lambda k: gens_map[k[0]]) + else: + raise ValueError("expected a generator, value pair a sequence of such pairs") + + for k, (x, g) in enumerate(replacements): + replacements[k] = (gens_map[x], ring.ring_new(g)) + + for monom, coeff in f.iterterms(): + monom = list(monom) + subpoly = ring.one + + for i, g in replacements: + n, monom[i] = monom[i], 0 + if n: + subpoly *= g**n + + subpoly = subpoly.mul_term((tuple(monom), coeff)) + poly += subpoly + + return poly + + def coeff_wrt(self, x, deg): + """ + Coefficient of ``self`` with respect to ``x**deg``. + + Treating ``self`` as a univariate polynomial in ``x`` this finds the + coefficient of ``x**deg`` as a polynomial in the other generators. + + Parameters + ========== + + x : generator or generator index + The generator or generator index to compute the expression for. + deg : int + The degree of the monomial to compute the expression for. + + Returns + ======= + + :py:class:`~.PolyElement` + The coefficient of ``x**deg`` as a polynomial in the same ring. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x, y, z = ring("x, y, z", ZZ) + + >>> p = 2*x**4 + 3*y**4 + 10*z**2 + 10*x*z**2 + >>> deg = 2 + >>> p.coeff_wrt(2, deg) # Using the generator index + 10*x + 10 + >>> p.coeff_wrt(z, deg) # Using the generator + 10*x + 10 + >>> p.coeff(z**2) # shows the difference between coeff and coeff_wrt + 10 + + See Also + ======== + + coeff, coeffs + + """ + p = self + i = p.ring.index(x) + terms = [(m, c) for m, c in p.iterterms() if m[i] == deg] + + if not terms: + return p.ring.zero + + monoms, coeffs = zip(*terms) + monoms = [m[:i] + (0,) + m[i + 1:] for m in monoms] + return p.ring.from_dict(dict(zip(monoms, coeffs))) + + def prem(self, g, x=None): + """ + Pseudo-remainder of the polynomial ``self`` with respect to ``g``. + + The pseudo-quotient ``q`` and pseudo-remainder ``r`` with respect to + ``z`` when dividing ``f`` by ``g`` satisfy ``m*f = g*q + r``, + where ``deg(r,z) < deg(g,z)`` and + ``m = LC(g,z)**(deg(f,z) - deg(g,z)+1)``. + + See :meth:`pdiv` for explanation of pseudo-division. + + + Parameters + ========== + + g : :py:class:`~.PolyElement` + The polynomial to divide ``self`` by. + x : generator or generator index, optional + The main variable of the polynomials and default is first generator. + + Returns + ======= + + :py:class:`~.PolyElement` + The pseudo-remainder polynomial. + + Raises + ====== + + ZeroDivisionError : If ``g`` is the zero polynomial. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x, y = ring("x, y", ZZ) + + >>> f = x**2 + x*y + >>> g = 2*x + 2 + >>> f.prem(g) # first generator is chosen by default if it is not given + -4*y + 4 + >>> f.rem(g) # shows the difference between prem and rem + x**2 + x*y + >>> f.prem(g, y) # generator is given + 0 + >>> f.prem(g, 1) # generator index is given + 0 + + See Also + ======== + + pdiv, pquo, pexquo, sympy.polys.domains.ring.Ring.rem + + """ + f = self + x = f.ring.index(x) + df = f.degree(x) + dg = g.degree(x) + + if dg < 0: + raise ZeroDivisionError('polynomial division') + + r, dr = f, df + + if df < dg: + return r + + N = df - dg + 1 + + lc_g = g.coeff_wrt(x, dg) + + xp = f.ring.gens[x] + + while True: + + lc_r = r.coeff_wrt(x, dr) + j, N = dr - dg, N - 1 + + R = r * lc_g + G = g * lc_r * xp**j + r = R - G + + dr = r.degree(x) + + if dr < dg: + break + + c = lc_g ** N + + return r * c + + def pdiv(self, g, x=None): + """ + Computes the pseudo-division of the polynomial ``self`` with respect to ``g``. + + The pseudo-division algorithm is used to find the pseudo-quotient ``q`` + and pseudo-remainder ``r`` such that ``m*f = g*q + r``, where ``m`` + represents the multiplier and ``f`` is the dividend polynomial. + + The pseudo-quotient ``q`` and pseudo-remainder ``r`` are polynomials in + the variable ``x``, with the degree of ``r`` with respect to ``x`` + being strictly less than the degree of ``g`` with respect to ``x``. + + The multiplier ``m`` is defined as + ``LC(g, x) ^ (deg(f, x) - deg(g, x) + 1)``, + where ``LC(g, x)`` represents the leading coefficient of ``g``. + + It is important to note that in the context of the ``prem`` method, + multivariate polynomials in a ring, such as ``R[x,y,z]``, are treated + as univariate polynomials with coefficients that are polynomials, + such as ``R[x,y][z]``. When dividing ``f`` by ``g`` with respect to the + variable ``z``, the pseudo-quotient ``q`` and pseudo-remainder ``r`` + satisfy ``m*f = g*q + r``, where ``deg(r, z) < deg(g, z)`` + and ``m = LC(g, z)^(deg(f, z) - deg(g, z) + 1)``. + + In this function, the pseudo-remainder ``r`` can be obtained using the + ``prem`` method, the pseudo-quotient ``q`` can + be obtained using the ``pquo`` method, and + the function ``pdiv`` itself returns a tuple ``(q, r)``. + + + Parameters + ========== + + g : :py:class:`~.PolyElement` + The polynomial to divide ``self`` by. + x : generator or generator index, optional + The main variable of the polynomials and default is first generator. + + Returns + ======= + + :py:class:`~.PolyElement` + The pseudo-division polynomial (tuple of ``q`` and ``r``). + + Raises + ====== + + ZeroDivisionError : If ``g`` is the zero polynomial. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x, y = ring("x, y", ZZ) + + >>> f = x**2 + x*y + >>> g = 2*x + 2 + >>> f.pdiv(g) # first generator is chosen by default if it is not given + (2*x + 2*y - 2, -4*y + 4) + >>> f.div(g) # shows the difference between pdiv and div + (0, x**2 + x*y) + >>> f.pdiv(g, y) # generator is given + (2*x**3 + 2*x**2*y + 6*x**2 + 2*x*y + 8*x + 4, 0) + >>> f.pdiv(g, 1) # generator index is given + (2*x**3 + 2*x**2*y + 6*x**2 + 2*x*y + 8*x + 4, 0) + + See Also + ======== + + prem + Computes only the pseudo-remainder more efficiently than + `f.pdiv(g)[1]`. + pquo + Returns only the pseudo-quotient. + pexquo + Returns only an exact pseudo-quotient having no remainder. + div + Returns quotient and remainder of f and g polynomials. + + """ + f = self + x = f.ring.index(x) + + df = f.degree(x) + dg = g.degree(x) + + if dg < 0: + raise ZeroDivisionError("polynomial division") + + q, r, dr = x, f, df + + if df < dg: + return q, r + + N = df - dg + 1 + lc_g = g.coeff_wrt(x, dg) + + xp = f.ring.gens[x] + + while True: + + lc_r = r.coeff_wrt(x, dr) + j, N = dr - dg, N - 1 + + Q = q * lc_g + + q = Q + (lc_r)*xp**j + + R = r * lc_g + + G = g * lc_r * xp**j + + r = R - G + + dr = r.degree(x) + + if dr < dg: + break + + c = lc_g**N + + q = q * c + r = r * c + + return q, r + + def pquo(self, g, x=None): + """ + Polynomial pseudo-quotient in multivariate polynomial ring. + + Examples + ======== + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x**2 + x*y + >>> g = 2*x + 2*y + >>> h = 2*x + 2 + >>> f.pquo(g) + 2*x + >>> f.quo(g) # shows the difference between pquo and quo + 0 + >>> f.pquo(h) + 2*x + 2*y - 2 + >>> f.quo(h) # shows the difference between pquo and quo + 0 + + See Also + ======== + + prem, pdiv, pexquo, sympy.polys.domains.ring.Ring.quo + + """ + f = self + return f.pdiv(g, x)[0] + + def pexquo(self, g, x=None): + """ + Polynomial exact pseudo-quotient in multivariate polynomial ring. + + Examples + ======== + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x**2 + x*y + >>> g = 2*x + 2*y + >>> h = 2*x + 2 + >>> f.pexquo(g) + 2*x + >>> f.exquo(g) # shows the difference between pexquo and exquo + Traceback (most recent call last): + ... + ExactQuotientFailed: 2*x + 2*y does not divide x**2 + x*y + >>> f.pexquo(h) + Traceback (most recent call last): + ... + ExactQuotientFailed: 2*x + 2 does not divide x**2 + x*y + + See Also + ======== + + prem, pdiv, pquo, sympy.polys.domains.ring.Ring.exquo + + """ + f = self + q, r = f.pdiv(g, x) + + if r.is_zero: + return q + else: + raise ExactQuotientFailed(f, g) + + def subresultants(self, g, x=None): + """ + Computes the subresultant PRS of two polynomials ``self`` and ``g``. + + Parameters + ========== + + g : :py:class:`~.PolyElement` + The second polynomial. + x : generator or generator index + The variable with respect to which the subresultant sequence is computed. + + Returns + ======= + + R : list + Returns a list polynomials representing the subresultant PRS. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x, y = ring("x, y", ZZ) + + >>> f = x**2*y + x*y + >>> g = x + y + >>> f.subresultants(g) # first generator is chosen by default if not given + [x**2*y + x*y, x + y, y**3 - y**2] + >>> f.subresultants(g, 0) # generator index is given + [x**2*y + x*y, x + y, y**3 - y**2] + >>> f.subresultants(g, y) # generator is given + [x**2*y + x*y, x + y, x**3 + x**2] + + """ + f = self + x = f.ring.index(x) + n = f.degree(x) + m = g.degree(x) + + if n < m: + f, g = g, f + n, m = m, n + + if f == 0: + return [0, 0] + + if g == 0: + return [f, 1] + + R = [f, g] + + d = n - m + b = (-1) ** (d + 1) + + # Compute the pseudo-remainder for f and g + h = f.prem(g, x) + h = h * b + + # Compute the coefficient of g with respect to x**m + lc = g.coeff_wrt(x, m) + + c = lc ** d + + S = [1, c] + + c = -c + + while h: + k = h.degree(x) + + R.append(h) + f, g, m, d = g, h, k, m - k + + b = -lc * c ** d + h = f.prem(g, x) + h = h.exquo(b) + + lc = g.coeff_wrt(x, k) + + if d > 1: + p = (-lc) ** d + q = c ** (d - 1) + c = p.exquo(q) + else: + c = -lc + + S.append(-c) + + return R + + # TODO: following methods should point to polynomial + # representation independent algorithm implementations. + + def half_gcdex(f, g): + return f.ring.dmp_half_gcdex(f, g) + + def gcdex(f, g): + return f.ring.dmp_gcdex(f, g) + + def resultant(f, g): + return f.ring.dmp_resultant(f, g) + + def discriminant(f): + return f.ring.dmp_discriminant(f) + + def decompose(f): + if f.ring.is_univariate: + return f.ring.dup_decompose(f) + else: + raise MultivariatePolynomialError("polynomial decomposition") + + def shift(f, a): + if f.ring.is_univariate: + return f.ring.dup_shift(f, a) + else: + raise MultivariatePolynomialError("shift: use shift_list instead") + + def shift_list(f, a): + return f.ring.dmp_shift(f, a) + + def sturm(f): + if f.ring.is_univariate: + return f.ring.dup_sturm(f) + else: + raise MultivariatePolynomialError("sturm sequence") + + def gff_list(f): + return f.ring.dmp_gff_list(f) + + def norm(f): + return f.ring.dmp_norm(f) + + def sqf_norm(f): + return f.ring.dmp_sqf_norm(f) + + def sqf_part(f): + return f.ring.dmp_sqf_part(f) + + def sqf_list(f, all=False): + return f.ring.dmp_sqf_list(f, all=all) + + def factor_list(f): + return f.ring.dmp_factor_list(f) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rootisolation.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rootisolation.py new file mode 100644 index 0000000000000000000000000000000000000000..b2f8fd115e49ce8dcf4db8659a60c3361818b7bb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rootisolation.py @@ -0,0 +1,2190 @@ +"""Real and complex root isolation and refinement algorithms. """ + + +from sympy.polys.densearith import ( + dup_neg, dup_rshift, dup_rem, + dup_l2_norm_squared) +from sympy.polys.densebasic import ( + dup_LC, dup_TC, dup_degree, + dup_strip, dup_reverse, + dup_convert, + dup_terms_gcd) +from sympy.polys.densetools import ( + dup_clear_denoms, + dup_mirror, dup_scale, dup_shift, + dup_transform, + dup_diff, + dup_eval, dmp_eval_in, + dup_sign_variations, + dup_real_imag) +from sympy.polys.euclidtools import ( + dup_discriminant) +from sympy.polys.factortools import ( + dup_factor_list) +from sympy.polys.polyerrors import ( + RefinementFailed, + DomainError, + PolynomialError) +from sympy.polys.sqfreetools import ( + dup_sqf_part, dup_sqf_list) + + +def dup_sturm(f, K): + """ + Computes the Sturm sequence of ``f`` in ``F[x]``. + + Given a univariate, square-free polynomial ``f(x)`` returns the + associated Sturm sequence ``f_0(x), ..., f_n(x)`` defined by:: + + f_0(x), f_1(x) = f(x), f'(x) + f_n = -rem(f_{n-2}(x), f_{n-1}(x)) + + Examples + ======== + + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> R.dup_sturm(x**3 - 2*x**2 + x - 3) + [x**3 - 2*x**2 + x - 3, 3*x**2 - 4*x + 1, 2/9*x + 25/9, -2079/4] + + References + ========== + + .. [1] [Davenport88]_ + + """ + if not K.is_Field: + raise DomainError("Cannot compute Sturm sequence over %s" % K) + + f = dup_sqf_part(f, K) + + sturm = [f, dup_diff(f, 1, K)] + + while sturm[-1]: + s = dup_rem(sturm[-2], sturm[-1], K) + sturm.append(dup_neg(s, K)) + + return sturm[:-1] + +def dup_root_upper_bound(f, K): + """Compute the LMQ upper bound for the positive roots of `f`; + LMQ (Local Max Quadratic) was developed by Akritas-Strzebonski-Vigklas. + + References + ========== + .. [1] Alkiviadis G. Akritas: "Linear and Quadratic Complexity Bounds on the + Values of the Positive Roots of Polynomials" + Journal of Universal Computer Science, Vol. 15, No. 3, 523-537, 2009. + """ + n, P = len(f), [] + t = n * [K.one] + if dup_LC(f, K) < 0: + f = dup_neg(f, K) + f = list(reversed(f)) + + for i in range(0, n): + if f[i] >= 0: + continue + + a, QL = K.log(-f[i], 2), [] + + for j in range(i + 1, n): + + if f[j] <= 0: + continue + + q = t[j] + a - K.log(f[j], 2) + QL.append([q // (j - i), j]) + + if not QL: + continue + + q = min(QL) + + t[q[1]] = t[q[1]] + 1 + + P.append(q[0]) + + if not P: + return None + else: + return K.get_field()(2)**(max(P) + 1) + +def dup_root_lower_bound(f, K): + """Compute the LMQ lower bound for the positive roots of `f`; + LMQ (Local Max Quadratic) was developed by Akritas-Strzebonski-Vigklas. + + References + ========== + .. [1] Alkiviadis G. Akritas: "Linear and Quadratic Complexity Bounds on the + Values of the Positive Roots of Polynomials" + Journal of Universal Computer Science, Vol. 15, No. 3, 523-537, 2009. + """ + bound = dup_root_upper_bound(dup_reverse(f), K) + + if bound is not None: + return 1/bound + else: + return None + +def dup_cauchy_upper_bound(f, K): + """ + Compute the Cauchy upper bound on the absolute value of all roots of f, + real or complex. + + References + ========== + .. [1] https://en.wikipedia.org/wiki/Geometrical_properties_of_polynomial_roots#Lagrange's_and_Cauchy's_bounds + """ + n = dup_degree(f) + if n < 1: + raise PolynomialError('Polynomial has no roots.') + + if K.is_ZZ: + L = K.get_field() + f, K = dup_convert(f, K, L), L + elif not K.is_QQ or K.is_RR or K.is_CC: + # We need to compute absolute value, and we are not supporting cases + # where this would take us outside the domain (or its quotient field). + raise DomainError('Cauchy bound not supported over %s' % K) + else: + f = f[:] + + while K.is_zero(f[-1]): + f.pop() + if len(f) == 1: + # Monomial. All roots are zero. + return K.zero + + lc = f[0] + return K.one + max(abs(n / lc) for n in f[1:]) + +def dup_cauchy_lower_bound(f, K): + """Compute the Cauchy lower bound on the absolute value of all non-zero + roots of f, real or complex.""" + g = dup_reverse(f) + if len(g) < 2: + raise PolynomialError('Polynomial has no non-zero roots.') + if K.is_ZZ: + K = K.get_field() + b = dup_cauchy_upper_bound(g, K) + return K.one / b + +def dup_mignotte_sep_bound_squared(f, K): + """ + Return the square of the Mignotte lower bound on separation between + distinct roots of f. The square is returned so that the bound lies in + K or its quotient field. + + References + ========== + + .. [1] Mignotte, Maurice. "Some useful bounds." Computer algebra. + Springer, Vienna, 1982. 259-263. + https://people.dm.unipi.it/gianni/AC-EAG/Mignotte.pdf + """ + n = dup_degree(f) + if n < 2: + raise PolynomialError('Polynomials of degree < 2 have no distinct roots.') + + if K.is_ZZ: + L = K.get_field() + f, K = dup_convert(f, K, L), L + elif not K.is_QQ or K.is_RR or K.is_CC: + # We need to compute absolute value, and we are not supporting cases + # where this would take us outside the domain (or its quotient field). + raise DomainError('Mignotte bound not supported over %s' % K) + + D = dup_discriminant(f, K) + l2sq = dup_l2_norm_squared(f, K) + return K(3)*K.abs(D) / ( K(n)**(n+1) * l2sq**(n-1) ) + +def _mobius_from_interval(I, field): + """Convert an open interval to a Mobius transform. """ + s, t = I + + a, c = field.numer(s), field.denom(s) + b, d = field.numer(t), field.denom(t) + + return a, b, c, d + +def _mobius_to_interval(M, field): + """Convert a Mobius transform to an open interval. """ + a, b, c, d = M + + s, t = field(a, c), field(b, d) + + if s <= t: + return (s, t) + else: + return (t, s) + +def dup_step_refine_real_root(f, M, K, fast=False): + """One step of positive real root refinement algorithm. """ + a, b, c, d = M + + if a == b and c == d: + return f, (a, b, c, d) + + A = dup_root_lower_bound(f, K) + + if A is not None: + A = K(int(A)) + else: + A = K.zero + + if fast and A > 16: + f = dup_scale(f, A, K) + a, c, A = A*a, A*c, K.one + + if A >= K.one: + f = dup_shift(f, A, K) + b, d = A*a + b, A*c + d + + if not dup_eval(f, K.zero, K): + return f, (b, b, d, d) + + f, g = dup_shift(f, K.one, K), f + + a1, b1, c1, d1 = a, a + b, c, c + d + + if not dup_eval(f, K.zero, K): + return f, (b1, b1, d1, d1) + + k = dup_sign_variations(f, K) + + if k == 1: + a, b, c, d = a1, b1, c1, d1 + else: + f = dup_shift(dup_reverse(g), K.one, K) + + if not dup_eval(f, K.zero, K): + f = dup_rshift(f, 1, K) + + a, b, c, d = b, a + b, d, c + d + + return f, (a, b, c, d) + +def dup_inner_refine_real_root(f, M, K, eps=None, steps=None, disjoint=None, fast=False, mobius=False): + """Refine a positive root of `f` given a Mobius transform or an interval. """ + F = K.get_field() + + if len(M) == 2: + a, b, c, d = _mobius_from_interval(M, F) + else: + a, b, c, d = M + + while not c: + f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, + d), K, fast=fast) + + if eps is not None and steps is not None: + for i in range(0, steps): + if abs(F(a, c) - F(b, d)) >= eps: + f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + else: + break + else: + if eps is not None: + while abs(F(a, c) - F(b, d)) >= eps: + f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + + if steps is not None: + for i in range(0, steps): + f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + + if disjoint is not None: + while True: + u, v = _mobius_to_interval((a, b, c, d), F) + + if v <= disjoint or disjoint <= u: + break + else: + f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + + if not mobius: + return _mobius_to_interval((a, b, c, d), F) + else: + return f, (a, b, c, d) + +def dup_outer_refine_real_root(f, s, t, K, eps=None, steps=None, disjoint=None, fast=False): + """Refine a positive root of `f` given an interval `(s, t)`. """ + a, b, c, d = _mobius_from_interval((s, t), K.get_field()) + + f = dup_transform(f, dup_strip([a, b]), + dup_strip([c, d]), K) + + if dup_sign_variations(f, K) != 1: + raise RefinementFailed("there should be exactly one root in (%s, %s) interval" % (s, t)) + + return dup_inner_refine_real_root(f, (a, b, c, d), K, eps=eps, steps=steps, disjoint=disjoint, fast=fast) + +def dup_refine_real_root(f, s, t, K, eps=None, steps=None, disjoint=None, fast=False): + """Refine real root's approximating interval to the given precision. """ + if K.is_QQ: + (_, f), K = dup_clear_denoms(f, K, convert=True), K.get_ring() + elif not K.is_ZZ: + raise DomainError("real root refinement not supported over %s" % K) + + if s == t: + return (s, t) + + if s > t: + s, t = t, s + + negative = False + + if s < 0: + if t <= 0: + f, s, t, negative = dup_mirror(f, K), -t, -s, True + else: + raise ValueError("Cannot refine a real root in (%s, %s)" % (s, t)) + + if negative and disjoint is not None: + if disjoint < 0: + disjoint = -disjoint + else: + disjoint = None + + s, t = dup_outer_refine_real_root( + f, s, t, K, eps=eps, steps=steps, disjoint=disjoint, fast=fast) + + if negative: + return (-t, -s) + else: + return ( s, t) + +def dup_inner_isolate_real_roots(f, K, eps=None, fast=False): + """Internal function for isolation positive roots up to given precision. + + References + ========== + 1. Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative Study of Two Real Root + Isolation Methods . Nonlinear Analysis: Modelling and Control, Vol. 10, No. 4, 297-304, 2005. + 2. Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. Vigklas: Improving the + Performance of the Continued Fractions Method Using new Bounds of Positive Roots. Nonlinear + Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. + """ + a, b, c, d = K.one, K.zero, K.zero, K.one + + k = dup_sign_variations(f, K) + + if k == 0: + return [] + if k == 1: + roots = [dup_inner_refine_real_root( + f, (a, b, c, d), K, eps=eps, fast=fast, mobius=True)] + else: + roots, stack = [], [(a, b, c, d, f, k)] + + while stack: + a, b, c, d, f, k = stack.pop() + + A = dup_root_lower_bound(f, K) + + if A is not None: + A = K(int(A)) + else: + A = K.zero + + if fast and A > 16: + f = dup_scale(f, A, K) + a, c, A = A*a, A*c, K.one + + if A >= K.one: + f = dup_shift(f, A, K) + b, d = A*a + b, A*c + d + + if not dup_TC(f, K): + roots.append((f, (b, b, d, d))) + f = dup_rshift(f, 1, K) + + k = dup_sign_variations(f, K) + + if k == 0: + continue + if k == 1: + roots.append(dup_inner_refine_real_root( + f, (a, b, c, d), K, eps=eps, fast=fast, mobius=True)) + continue + + f1 = dup_shift(f, K.one, K) + + a1, b1, c1, d1, r = a, a + b, c, c + d, 0 + + if not dup_TC(f1, K): + roots.append((f1, (b1, b1, d1, d1))) + f1, r = dup_rshift(f1, 1, K), 1 + + k1 = dup_sign_variations(f1, K) + k2 = k - k1 - r + + a2, b2, c2, d2 = b, a + b, d, c + d + + if k2 > 1: + f2 = dup_shift(dup_reverse(f), K.one, K) + + if not dup_TC(f2, K): + f2 = dup_rshift(f2, 1, K) + + k2 = dup_sign_variations(f2, K) + else: + f2 = None + + if k1 < k2: + a1, a2, b1, b2 = a2, a1, b2, b1 + c1, c2, d1, d2 = c2, c1, d2, d1 + f1, f2, k1, k2 = f2, f1, k2, k1 + + if not k1: + continue + + if f1 is None: + f1 = dup_shift(dup_reverse(f), K.one, K) + + if not dup_TC(f1, K): + f1 = dup_rshift(f1, 1, K) + + if k1 == 1: + roots.append(dup_inner_refine_real_root( + f1, (a1, b1, c1, d1), K, eps=eps, fast=fast, mobius=True)) + else: + stack.append((a1, b1, c1, d1, f1, k1)) + + if not k2: + continue + + if f2 is None: + f2 = dup_shift(dup_reverse(f), K.one, K) + + if not dup_TC(f2, K): + f2 = dup_rshift(f2, 1, K) + + if k2 == 1: + roots.append(dup_inner_refine_real_root( + f2, (a2, b2, c2, d2), K, eps=eps, fast=fast, mobius=True)) + else: + stack.append((a2, b2, c2, d2, f2, k2)) + + return roots + +def _discard_if_outside_interval(f, M, inf, sup, K, negative, fast, mobius): + """Discard an isolating interval if outside ``(inf, sup)``. """ + F = K.get_field() + + while True: + u, v = _mobius_to_interval(M, F) + + if negative: + u, v = -v, -u + + if (inf is None or u >= inf) and (sup is None or v <= sup): + if not mobius: + return u, v + else: + return f, M + elif (sup is not None and u > sup) or (inf is not None and v < inf): + return None + else: + f, M = dup_step_refine_real_root(f, M, K, fast=fast) + +def dup_inner_isolate_positive_roots(f, K, eps=None, inf=None, sup=None, fast=False, mobius=False): + """Iteratively compute disjoint positive root isolation intervals. """ + if sup is not None and sup < 0: + return [] + + roots = dup_inner_isolate_real_roots(f, K, eps=eps, fast=fast) + + F, results = K.get_field(), [] + + if inf is not None or sup is not None: + for f, M in roots: + result = _discard_if_outside_interval(f, M, inf, sup, K, False, fast, mobius) + + if result is not None: + results.append(result) + elif not mobius: + results.extend(_mobius_to_interval(M, F) for _, M in roots) + else: + results = roots + + return results + +def dup_inner_isolate_negative_roots(f, K, inf=None, sup=None, eps=None, fast=False, mobius=False): + """Iteratively compute disjoint negative root isolation intervals. """ + if inf is not None and inf >= 0: + return [] + + roots = dup_inner_isolate_real_roots(dup_mirror(f, K), K, eps=eps, fast=fast) + + F, results = K.get_field(), [] + + if inf is not None or sup is not None: + for f, M in roots: + result = _discard_if_outside_interval(f, M, inf, sup, K, True, fast, mobius) + + if result is not None: + results.append(result) + elif not mobius: + for f, M in roots: + u, v = _mobius_to_interval(M, F) + results.append((-v, -u)) + else: + results = roots + + return results + +def _isolate_zero(f, K, inf, sup, basis=False, sqf=False): + """Handle special case of CF algorithm when ``f`` is homogeneous. """ + j, f = dup_terms_gcd(f, K) + + if j > 0: + F = K.get_field() + + if (inf is None or inf <= 0) and (sup is None or 0 <= sup): + if not sqf: + if not basis: + return [((F.zero, F.zero), j)], f + else: + return [((F.zero, F.zero), j, [K.one, K.zero])], f + else: + return [(F.zero, F.zero)], f + + return [], f + +def dup_isolate_real_roots_sqf(f, K, eps=None, inf=None, sup=None, fast=False, blackbox=False): + """Isolate real roots of a square-free polynomial using the Vincent-Akritas-Strzebonski (VAS) CF approach. + + References + ========== + .. [1] Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative + Study of Two Real Root Isolation Methods. Nonlinear Analysis: + Modelling and Control, Vol. 10, No. 4, 297-304, 2005. + .. [2] Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. + Vigklas: Improving the Performance of the Continued Fractions + Method Using New Bounds of Positive Roots. Nonlinear Analysis: + Modelling and Control, Vol. 13, No. 3, 265-279, 2008. + + """ + if K.is_QQ: + (_, f), K = dup_clear_denoms(f, K, convert=True), K.get_ring() + elif not K.is_ZZ: + raise DomainError("isolation of real roots not supported over %s" % K) + + if dup_degree(f) <= 0: + return [] + + I_zero, f = _isolate_zero(f, K, inf, sup, basis=False, sqf=True) + + I_neg = dup_inner_isolate_negative_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) + I_pos = dup_inner_isolate_positive_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) + + roots = sorted(I_neg + I_zero + I_pos) + + if not blackbox: + return roots + else: + return [ RealInterval((a, b), f, K) for (a, b) in roots ] + +def dup_isolate_real_roots(f, K, eps=None, inf=None, sup=None, basis=False, fast=False): + """Isolate real roots using Vincent-Akritas-Strzebonski (VAS) continued fractions approach. + + References + ========== + + .. [1] Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative + Study of Two Real Root Isolation Methods. Nonlinear Analysis: + Modelling and Control, Vol. 10, No. 4, 297-304, 2005. + .. [2] Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. + Vigklas: Improving the Performance of the Continued Fractions + Method Using New Bounds of Positive Roots. + Nonlinear Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. + + """ + if K.is_QQ: + (_, f), K = dup_clear_denoms(f, K, convert=True), K.get_ring() + elif not K.is_ZZ: + raise DomainError("isolation of real roots not supported over %s" % K) + + if dup_degree(f) <= 0: + return [] + + I_zero, f = _isolate_zero(f, K, inf, sup, basis=basis, sqf=False) + + _, factors = dup_sqf_list(f, K) + + if len(factors) == 1: + ((f, k),) = factors + + I_neg = dup_inner_isolate_negative_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) + I_pos = dup_inner_isolate_positive_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) + + I_neg = [ ((u, v), k) for u, v in I_neg ] + I_pos = [ ((u, v), k) for u, v in I_pos ] + else: + I_neg, I_pos = _real_isolate_and_disjoin(factors, K, + eps=eps, inf=inf, sup=sup, basis=basis, fast=fast) + + return sorted(I_neg + I_zero + I_pos) + +def dup_isolate_real_roots_list(polys, K, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): + """Isolate real roots of a list of polynomial using Vincent-Akritas-Strzebonski (VAS) CF approach. + + References + ========== + + .. [1] Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative + Study of Two Real Root Isolation Methods. Nonlinear Analysis: + Modelling and Control, Vol. 10, No. 4, 297-304, 2005. + .. [2] Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. + Vigklas: Improving the Performance of the Continued Fractions + Method Using New Bounds of Positive Roots. + Nonlinear Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. + + """ + if K.is_QQ: + K, F, polys = K.get_ring(), K, polys[:] + + for i, p in enumerate(polys): + polys[i] = dup_clear_denoms(p, F, K, convert=True)[1] + elif not K.is_ZZ: + raise DomainError("isolation of real roots not supported over %s" % K) + + zeros, factors_dict = False, {} + + if (inf is None or inf <= 0) and (sup is None or 0 <= sup): + zeros, zero_indices = True, {} + + for i, p in enumerate(polys): + j, p = dup_terms_gcd(p, K) + + if zeros and j > 0: + zero_indices[i] = j + + for f, k in dup_factor_list(p, K)[1]: + f = tuple(f) + + if f not in factors_dict: + factors_dict[f] = {i: k} + else: + factors_dict[f][i] = k + + factors_list = [(list(f), indices) for f, indices in factors_dict.items()] + I_neg, I_pos = _real_isolate_and_disjoin(factors_list, K, eps=eps, + inf=inf, sup=sup, strict=strict, basis=basis, fast=fast) + + F = K.get_field() + + if not zeros or not zero_indices: + I_zero = [] + else: + if not basis: + I_zero = [((F.zero, F.zero), zero_indices)] + else: + I_zero = [((F.zero, F.zero), zero_indices, [K.one, K.zero])] + + return sorted(I_neg + I_zero + I_pos) + +def _disjoint_p(M, N, strict=False): + """Check if Mobius transforms define disjoint intervals. """ + a1, b1, c1, d1 = M + a2, b2, c2, d2 = N + + a1d1, b1c1 = a1*d1, b1*c1 + a2d2, b2c2 = a2*d2, b2*c2 + + if a1d1 == b1c1 and a2d2 == b2c2: + return True + + if a1d1 > b1c1: + a1, c1, b1, d1 = b1, d1, a1, c1 + + if a2d2 > b2c2: + a2, c2, b2, d2 = b2, d2, a2, c2 + + if not strict: + return a2*d1 >= c2*b1 or b2*c1 <= d2*a1 + else: + return a2*d1 > c2*b1 or b2*c1 < d2*a1 + +def _real_isolate_and_disjoin(factors, K, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): + """Isolate real roots of a list of polynomials and disjoin intervals. """ + I_pos, I_neg = [], [] + + for i, (f, k) in enumerate(factors): + for F, M in dup_inner_isolate_positive_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast, mobius=True): + I_pos.append((F, M, k, f)) + + for G, N in dup_inner_isolate_negative_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast, mobius=True): + I_neg.append((G, N, k, f)) + + for i, (f, M, k, F) in enumerate(I_pos): + for j, (g, N, m, G) in enumerate(I_pos[i + 1:]): + while not _disjoint_p(M, N, strict=strict): + f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) + g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) + + I_pos[i + j + 1] = (g, N, m, G) + + I_pos[i] = (f, M, k, F) + + for i, (f, M, k, F) in enumerate(I_neg): + for j, (g, N, m, G) in enumerate(I_neg[i + 1:]): + while not _disjoint_p(M, N, strict=strict): + f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) + g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) + + I_neg[i + j + 1] = (g, N, m, G) + + I_neg[i] = (f, M, k, F) + + if strict: + for i, (f, M, k, F) in enumerate(I_neg): + if not M[0]: + while not M[0]: + f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) + + I_neg[i] = (f, M, k, F) + break + + for j, (g, N, m, G) in enumerate(I_pos): + if not N[0]: + while not N[0]: + g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) + + I_pos[j] = (g, N, m, G) + break + + field = K.get_field() + + I_neg = [ (_mobius_to_interval(M, field), k, f) for (_, M, k, f) in I_neg ] + I_pos = [ (_mobius_to_interval(M, field), k, f) for (_, M, k, f) in I_pos ] + + I_neg = [((-v, -u), k, f) for ((u, v), k, f) in I_neg] + + if not basis: + I_neg = [((u, v), k) for ((u, v), k, _) in I_neg] + I_pos = [((u, v), k) for ((u, v), k, _) in I_pos] + + return I_neg, I_pos + +def dup_count_real_roots(f, K, inf=None, sup=None): + """Returns the number of distinct real roots of ``f`` in ``[inf, sup]``. """ + if dup_degree(f) <= 0: + return 0 + + if not K.is_Field: + R, K = K, K.get_field() + f = dup_convert(f, R, K) + + sturm = dup_sturm(f, K) + + if inf is None: + signs_inf = dup_sign_variations([ dup_LC(s, K)*(-1)**dup_degree(s) for s in sturm ], K) + else: + signs_inf = dup_sign_variations([ dup_eval(s, inf, K) for s in sturm ], K) + + if sup is None: + signs_sup = dup_sign_variations([ dup_LC(s, K) for s in sturm ], K) + else: + signs_sup = dup_sign_variations([ dup_eval(s, sup, K) for s in sturm ], K) + + count = abs(signs_inf - signs_sup) + + if inf is not None and not dup_eval(f, inf, K): + count += 1 + + return count + +OO = 'OO' # Origin of (re, im) coordinate system + +Q1 = 'Q1' # Quadrant #1 (++): re > 0 and im > 0 +Q2 = 'Q2' # Quadrant #2 (-+): re < 0 and im > 0 +Q3 = 'Q3' # Quadrant #3 (--): re < 0 and im < 0 +Q4 = 'Q4' # Quadrant #4 (+-): re > 0 and im < 0 + +A1 = 'A1' # Axis #1 (+0): re > 0 and im = 0 +A2 = 'A2' # Axis #2 (0+): re = 0 and im > 0 +A3 = 'A3' # Axis #3 (-0): re < 0 and im = 0 +A4 = 'A4' # Axis #4 (0-): re = 0 and im < 0 + +_rules_simple = { + # Q --> Q (same) => no change + (Q1, Q1): 0, + (Q2, Q2): 0, + (Q3, Q3): 0, + (Q4, Q4): 0, + + # A -- CCW --> Q => +1/4 (CCW) + (A1, Q1): 1, + (A2, Q2): 1, + (A3, Q3): 1, + (A4, Q4): 1, + + # A -- CW --> Q => -1/4 (CCW) + (A1, Q4): 2, + (A2, Q1): 2, + (A3, Q2): 2, + (A4, Q3): 2, + + # Q -- CCW --> A => +1/4 (CCW) + (Q1, A2): 3, + (Q2, A3): 3, + (Q3, A4): 3, + (Q4, A1): 3, + + # Q -- CW --> A => -1/4 (CCW) + (Q1, A1): 4, + (Q2, A2): 4, + (Q3, A3): 4, + (Q4, A4): 4, + + # Q -- CCW --> Q => +1/2 (CCW) + (Q1, Q2): +5, + (Q2, Q3): +5, + (Q3, Q4): +5, + (Q4, Q1): +5, + + # Q -- CW --> Q => -1/2 (CW) + (Q1, Q4): -5, + (Q2, Q1): -5, + (Q3, Q2): -5, + (Q4, Q3): -5, +} + +_rules_ambiguous = { + # A -- CCW --> Q => { +1/4 (CCW), -9/4 (CW) } + (A1, OO, Q1): -1, + (A2, OO, Q2): -1, + (A3, OO, Q3): -1, + (A4, OO, Q4): -1, + + # A -- CW --> Q => { -1/4 (CCW), +7/4 (CW) } + (A1, OO, Q4): -2, + (A2, OO, Q1): -2, + (A3, OO, Q2): -2, + (A4, OO, Q3): -2, + + # Q -- CCW --> A => { +1/4 (CCW), -9/4 (CW) } + (Q1, OO, A2): -3, + (Q2, OO, A3): -3, + (Q3, OO, A4): -3, + (Q4, OO, A1): -3, + + # Q -- CW --> A => { -1/4 (CCW), +7/4 (CW) } + (Q1, OO, A1): -4, + (Q2, OO, A2): -4, + (Q3, OO, A3): -4, + (Q4, OO, A4): -4, + + # A -- OO --> A => { +1 (CCW), -1 (CW) } + (A1, A3): 7, + (A2, A4): 7, + (A3, A1): 7, + (A4, A2): 7, + + (A1, OO, A3): 7, + (A2, OO, A4): 7, + (A3, OO, A1): 7, + (A4, OO, A2): 7, + + # Q -- DIA --> Q => { +1 (CCW), -1 (CW) } + (Q1, Q3): 8, + (Q2, Q4): 8, + (Q3, Q1): 8, + (Q4, Q2): 8, + + (Q1, OO, Q3): 8, + (Q2, OO, Q4): 8, + (Q3, OO, Q1): 8, + (Q4, OO, Q2): 8, + + # A --- R ---> A => { +1/2 (CCW), -3/2 (CW) } + (A1, A2): 9, + (A2, A3): 9, + (A3, A4): 9, + (A4, A1): 9, + + (A1, OO, A2): 9, + (A2, OO, A3): 9, + (A3, OO, A4): 9, + (A4, OO, A1): 9, + + # A --- L ---> A => { +3/2 (CCW), -1/2 (CW) } + (A1, A4): 10, + (A2, A1): 10, + (A3, A2): 10, + (A4, A3): 10, + + (A1, OO, A4): 10, + (A2, OO, A1): 10, + (A3, OO, A2): 10, + (A4, OO, A3): 10, + + # Q --- 1 ---> A => { +3/4 (CCW), -5/4 (CW) } + (Q1, A3): 11, + (Q2, A4): 11, + (Q3, A1): 11, + (Q4, A2): 11, + + (Q1, OO, A3): 11, + (Q2, OO, A4): 11, + (Q3, OO, A1): 11, + (Q4, OO, A2): 11, + + # Q --- 2 ---> A => { +5/4 (CCW), -3/4 (CW) } + (Q1, A4): 12, + (Q2, A1): 12, + (Q3, A2): 12, + (Q4, A3): 12, + + (Q1, OO, A4): 12, + (Q2, OO, A1): 12, + (Q3, OO, A2): 12, + (Q4, OO, A3): 12, + + # A --- 1 ---> Q => { +5/4 (CCW), -3/4 (CW) } + (A1, Q3): 13, + (A2, Q4): 13, + (A3, Q1): 13, + (A4, Q2): 13, + + (A1, OO, Q3): 13, + (A2, OO, Q4): 13, + (A3, OO, Q1): 13, + (A4, OO, Q2): 13, + + # A --- 2 ---> Q => { +3/4 (CCW), -5/4 (CW) } + (A1, Q2): 14, + (A2, Q3): 14, + (A3, Q4): 14, + (A4, Q1): 14, + + (A1, OO, Q2): 14, + (A2, OO, Q3): 14, + (A3, OO, Q4): 14, + (A4, OO, Q1): 14, + + # Q --> OO --> Q => { +1/2 (CCW), -3/2 (CW) } + (Q1, OO, Q2): 15, + (Q2, OO, Q3): 15, + (Q3, OO, Q4): 15, + (Q4, OO, Q1): 15, + + # Q --> OO --> Q => { +3/2 (CCW), -1/2 (CW) } + (Q1, OO, Q4): 16, + (Q2, OO, Q1): 16, + (Q3, OO, Q2): 16, + (Q4, OO, Q3): 16, + + # A --> OO --> A => { +2 (CCW), 0 (CW) } + (A1, OO, A1): 17, + (A2, OO, A2): 17, + (A3, OO, A3): 17, + (A4, OO, A4): 17, + + # Q --> OO --> Q => { +2 (CCW), 0 (CW) } + (Q1, OO, Q1): 18, + (Q2, OO, Q2): 18, + (Q3, OO, Q3): 18, + (Q4, OO, Q4): 18, +} + +_values = { + 0: [( 0, 1)], + 1: [(+1, 4)], + 2: [(-1, 4)], + 3: [(+1, 4)], + 4: [(-1, 4)], + -1: [(+9, 4), (+1, 4)], + -2: [(+7, 4), (-1, 4)], + -3: [(+9, 4), (+1, 4)], + -4: [(+7, 4), (-1, 4)], + +5: [(+1, 2)], + -5: [(-1, 2)], + 7: [(+1, 1), (-1, 1)], + 8: [(+1, 1), (-1, 1)], + 9: [(+1, 2), (-3, 2)], + 10: [(+3, 2), (-1, 2)], + 11: [(+3, 4), (-5, 4)], + 12: [(+5, 4), (-3, 4)], + 13: [(+5, 4), (-3, 4)], + 14: [(+3, 4), (-5, 4)], + 15: [(+1, 2), (-3, 2)], + 16: [(+3, 2), (-1, 2)], + 17: [(+2, 1), ( 0, 1)], + 18: [(+2, 1), ( 0, 1)], +} + +def _classify_point(re, im): + """Return the half-axis (or origin) on which (re, im) point is located. """ + if not re and not im: + return OO + + if not re: + if im > 0: + return A2 + else: + return A4 + elif not im: + if re > 0: + return A1 + else: + return A3 + +def _intervals_to_quadrants(intervals, f1, f2, s, t, F): + """Generate a sequence of extended quadrants from a list of critical points. """ + if not intervals: + return [] + + Q = [] + + if not f1: + (a, b), _, _ = intervals[0] + + if a == b == s: + if len(intervals) == 1: + if dup_eval(f2, t, F) > 0: + return [OO, A2] + else: + return [OO, A4] + else: + (a, _), _, _ = intervals[1] + + if dup_eval(f2, (s + a)/2, F) > 0: + Q.extend([OO, A2]) + f2_sgn = +1 + else: + Q.extend([OO, A4]) + f2_sgn = -1 + + intervals = intervals[1:] + else: + if dup_eval(f2, s, F) > 0: + Q.append(A2) + f2_sgn = +1 + else: + Q.append(A4) + f2_sgn = -1 + + for (a, _), indices, _ in intervals: + Q.append(OO) + + if indices[1] % 2 == 1: + f2_sgn = -f2_sgn + + if a != t: + if f2_sgn > 0: + Q.append(A2) + else: + Q.append(A4) + + return Q + + if not f2: + (a, b), _, _ = intervals[0] + + if a == b == s: + if len(intervals) == 1: + if dup_eval(f1, t, F) > 0: + return [OO, A1] + else: + return [OO, A3] + else: + (a, _), _, _ = intervals[1] + + if dup_eval(f1, (s + a)/2, F) > 0: + Q.extend([OO, A1]) + f1_sgn = +1 + else: + Q.extend([OO, A3]) + f1_sgn = -1 + + intervals = intervals[1:] + else: + if dup_eval(f1, s, F) > 0: + Q.append(A1) + f1_sgn = +1 + else: + Q.append(A3) + f1_sgn = -1 + + for (a, _), indices, _ in intervals: + Q.append(OO) + + if indices[0] % 2 == 1: + f1_sgn = -f1_sgn + + if a != t: + if f1_sgn > 0: + Q.append(A1) + else: + Q.append(A3) + + return Q + + re = dup_eval(f1, s, F) + im = dup_eval(f2, s, F) + + if not re or not im: + Q.append(_classify_point(re, im)) + + if len(intervals) == 1: + re = dup_eval(f1, t, F) + im = dup_eval(f2, t, F) + else: + (a, _), _, _ = intervals[1] + + re = dup_eval(f1, (s + a)/2, F) + im = dup_eval(f2, (s + a)/2, F) + + intervals = intervals[1:] + + if re > 0: + f1_sgn = +1 + else: + f1_sgn = -1 + + if im > 0: + f2_sgn = +1 + else: + f2_sgn = -1 + + sgn = { + (+1, +1): Q1, + (-1, +1): Q2, + (-1, -1): Q3, + (+1, -1): Q4, + } + + Q.append(sgn[(f1_sgn, f2_sgn)]) + + for (a, b), indices, _ in intervals: + if a == b: + re = dup_eval(f1, a, F) + im = dup_eval(f2, a, F) + + cls = _classify_point(re, im) + + if cls is not None: + Q.append(cls) + + if 0 in indices: + if indices[0] % 2 == 1: + f1_sgn = -f1_sgn + + if 1 in indices: + if indices[1] % 2 == 1: + f2_sgn = -f2_sgn + + if not (a == b and b == t): + Q.append(sgn[(f1_sgn, f2_sgn)]) + + return Q + +def _traverse_quadrants(Q_L1, Q_L2, Q_L3, Q_L4, exclude=None): + """Transform sequences of quadrants to a sequence of rules. """ + if exclude is True: + edges = [1, 1, 0, 0] + + corners = { + (0, 1): 1, + (1, 2): 1, + (2, 3): 0, + (3, 0): 1, + } + else: + edges = [0, 0, 0, 0] + + corners = { + (0, 1): 0, + (1, 2): 0, + (2, 3): 0, + (3, 0): 0, + } + + if exclude is not None and exclude is not True: + exclude = set(exclude) + + for i, edge in enumerate(['S', 'E', 'N', 'W']): + if edge in exclude: + edges[i] = 1 + + for i, corner in enumerate(['SW', 'SE', 'NE', 'NW']): + if corner in exclude: + corners[((i - 1) % 4, i)] = 1 + + QQ, rules = [Q_L1, Q_L2, Q_L3, Q_L4], [] + + for i, Q in enumerate(QQ): + if not Q: + continue + + if Q[-1] == OO: + Q = Q[:-1] + + if Q[0] == OO: + j, Q = (i - 1) % 4, Q[1:] + qq = (QQ[j][-2], OO, Q[0]) + + if qq in _rules_ambiguous: + rules.append((_rules_ambiguous[qq], corners[(j, i)])) + else: + raise NotImplementedError("3 element rule (corner): " + str(qq)) + + q1, k = Q[0], 1 + + while k < len(Q): + q2, k = Q[k], k + 1 + + if q2 != OO: + qq = (q1, q2) + + if qq in _rules_simple: + rules.append((_rules_simple[qq], 0)) + elif qq in _rules_ambiguous: + rules.append((_rules_ambiguous[qq], edges[i])) + else: + raise NotImplementedError("2 element rule (inside): " + str(qq)) + else: + qq, k = (q1, q2, Q[k]), k + 1 + + if qq in _rules_ambiguous: + rules.append((_rules_ambiguous[qq], edges[i])) + else: + raise NotImplementedError("3 element rule (edge): " + str(qq)) + + q1 = qq[-1] + + return rules + +def _reverse_intervals(intervals): + """Reverse intervals for traversal from right to left and from top to bottom. """ + return [ ((b, a), indices, f) for (a, b), indices, f in reversed(intervals) ] + +def _winding_number(T, field): + """Compute the winding number of the input polynomial, i.e. the number of roots. """ + return int(sum(field(*_values[t][i]) for t, i in T) / field(2)) + +def dup_count_complex_roots(f, K, inf=None, sup=None, exclude=None): + """Count all roots in [u + v*I, s + t*I] rectangle using Collins-Krandick algorithm. """ + if not K.is_ZZ and not K.is_QQ: + raise DomainError("complex root counting is not supported over %s" % K) + + if K.is_ZZ: + R, F = K, K.get_field() + else: + R, F = K.get_ring(), K + + f = dup_convert(f, K, F) + + if inf is None or sup is None: + _, lc = dup_degree(f), abs(dup_LC(f, F)) + B = 2*max(F.quo(abs(c), lc) for c in f) + + if inf is None: + (u, v) = (-B, -B) + else: + (u, v) = inf + + if sup is None: + (s, t) = (+B, +B) + else: + (s, t) = sup + + f1, f2 = dup_real_imag(f, F) + + f1L1F = dmp_eval_in(f1, v, 1, 1, F) + f2L1F = dmp_eval_in(f2, v, 1, 1, F) + + _, f1L1R = dup_clear_denoms(f1L1F, F, R, convert=True) + _, f2L1R = dup_clear_denoms(f2L1F, F, R, convert=True) + + f1L2F = dmp_eval_in(f1, s, 0, 1, F) + f2L2F = dmp_eval_in(f2, s, 0, 1, F) + + _, f1L2R = dup_clear_denoms(f1L2F, F, R, convert=True) + _, f2L2R = dup_clear_denoms(f2L2F, F, R, convert=True) + + f1L3F = dmp_eval_in(f1, t, 1, 1, F) + f2L3F = dmp_eval_in(f2, t, 1, 1, F) + + _, f1L3R = dup_clear_denoms(f1L3F, F, R, convert=True) + _, f2L3R = dup_clear_denoms(f2L3F, F, R, convert=True) + + f1L4F = dmp_eval_in(f1, u, 0, 1, F) + f2L4F = dmp_eval_in(f2, u, 0, 1, F) + + _, f1L4R = dup_clear_denoms(f1L4F, F, R, convert=True) + _, f2L4R = dup_clear_denoms(f2L4F, F, R, convert=True) + + S_L1 = [f1L1R, f2L1R] + S_L2 = [f1L2R, f2L2R] + S_L3 = [f1L3R, f2L3R] + S_L4 = [f1L4R, f2L4R] + + I_L1 = dup_isolate_real_roots_list(S_L1, R, inf=u, sup=s, fast=True, basis=True, strict=True) + I_L2 = dup_isolate_real_roots_list(S_L2, R, inf=v, sup=t, fast=True, basis=True, strict=True) + I_L3 = dup_isolate_real_roots_list(S_L3, R, inf=u, sup=s, fast=True, basis=True, strict=True) + I_L4 = dup_isolate_real_roots_list(S_L4, R, inf=v, sup=t, fast=True, basis=True, strict=True) + + I_L3 = _reverse_intervals(I_L3) + I_L4 = _reverse_intervals(I_L4) + + Q_L1 = _intervals_to_quadrants(I_L1, f1L1F, f2L1F, u, s, F) + Q_L2 = _intervals_to_quadrants(I_L2, f1L2F, f2L2F, v, t, F) + Q_L3 = _intervals_to_quadrants(I_L3, f1L3F, f2L3F, s, u, F) + Q_L4 = _intervals_to_quadrants(I_L4, f1L4F, f2L4F, t, v, F) + + T = _traverse_quadrants(Q_L1, Q_L2, Q_L3, Q_L4, exclude=exclude) + + return _winding_number(T, F) + +def _vertical_bisection(N, a, b, I, Q, F1, F2, f1, f2, F): + """Vertical bisection step in Collins-Krandick root isolation algorithm. """ + (u, v), (s, t) = a, b + + I_L1, I_L2, I_L3, I_L4 = I + Q_L1, Q_L2, Q_L3, Q_L4 = Q + + f1L1F, f1L2F, f1L3F, f1L4F = F1 + f2L1F, f2L2F, f2L3F, f2L4F = F2 + + x = (u + s) / 2 + + f1V = dmp_eval_in(f1, x, 0, 1, F) + f2V = dmp_eval_in(f2, x, 0, 1, F) + + I_V = dup_isolate_real_roots_list([f1V, f2V], F, inf=v, sup=t, fast=True, strict=True, basis=True) + + I_L1_L, I_L1_R = [], [] + I_L2_L, I_L2_R = I_V, I_L2 + I_L3_L, I_L3_R = [], [] + I_L4_L, I_L4_R = I_L4, _reverse_intervals(I_V) + + for I in I_L1: + (a, b), indices, h = I + + if a == b: + if a == x: + I_L1_L.append(I) + I_L1_R.append(I) + elif a < x: + I_L1_L.append(I) + else: + I_L1_R.append(I) + else: + if b <= x: + I_L1_L.append(I) + elif a >= x: + I_L1_R.append(I) + else: + a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=x, fast=True) + + if b <= x: + I_L1_L.append(((a, b), indices, h)) + if a >= x: + I_L1_R.append(((a, b), indices, h)) + + for I in I_L3: + (b, a), indices, h = I + + if a == b: + if a == x: + I_L3_L.append(I) + I_L3_R.append(I) + elif a < x: + I_L3_L.append(I) + else: + I_L3_R.append(I) + else: + if b <= x: + I_L3_L.append(I) + elif a >= x: + I_L3_R.append(I) + else: + a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=x, fast=True) + + if b <= x: + I_L3_L.append(((b, a), indices, h)) + if a >= x: + I_L3_R.append(((b, a), indices, h)) + + Q_L1_L = _intervals_to_quadrants(I_L1_L, f1L1F, f2L1F, u, x, F) + Q_L2_L = _intervals_to_quadrants(I_L2_L, f1V, f2V, v, t, F) + Q_L3_L = _intervals_to_quadrants(I_L3_L, f1L3F, f2L3F, x, u, F) + Q_L4_L = Q_L4 + + Q_L1_R = _intervals_to_quadrants(I_L1_R, f1L1F, f2L1F, x, s, F) + Q_L2_R = Q_L2 + Q_L3_R = _intervals_to_quadrants(I_L3_R, f1L3F, f2L3F, s, x, F) + Q_L4_R = _intervals_to_quadrants(I_L4_R, f1V, f2V, t, v, F) + + T_L = _traverse_quadrants(Q_L1_L, Q_L2_L, Q_L3_L, Q_L4_L, exclude=True) + T_R = _traverse_quadrants(Q_L1_R, Q_L2_R, Q_L3_R, Q_L4_R, exclude=True) + + N_L = _winding_number(T_L, F) + N_R = _winding_number(T_R, F) + + I_L = (I_L1_L, I_L2_L, I_L3_L, I_L4_L) + Q_L = (Q_L1_L, Q_L2_L, Q_L3_L, Q_L4_L) + + I_R = (I_L1_R, I_L2_R, I_L3_R, I_L4_R) + Q_R = (Q_L1_R, Q_L2_R, Q_L3_R, Q_L4_R) + + F1_L = (f1L1F, f1V, f1L3F, f1L4F) + F2_L = (f2L1F, f2V, f2L3F, f2L4F) + + F1_R = (f1L1F, f1L2F, f1L3F, f1V) + F2_R = (f2L1F, f2L2F, f2L3F, f2V) + + a, b = (u, v), (x, t) + c, d = (x, v), (s, t) + + D_L = (N_L, a, b, I_L, Q_L, F1_L, F2_L) + D_R = (N_R, c, d, I_R, Q_R, F1_R, F2_R) + + return D_L, D_R + +def _horizontal_bisection(N, a, b, I, Q, F1, F2, f1, f2, F): + """Horizontal bisection step in Collins-Krandick root isolation algorithm. """ + (u, v), (s, t) = a, b + + I_L1, I_L2, I_L3, I_L4 = I + Q_L1, Q_L2, Q_L3, Q_L4 = Q + + f1L1F, f1L2F, f1L3F, f1L4F = F1 + f2L1F, f2L2F, f2L3F, f2L4F = F2 + + y = (v + t) / 2 + + f1H = dmp_eval_in(f1, y, 1, 1, F) + f2H = dmp_eval_in(f2, y, 1, 1, F) + + I_H = dup_isolate_real_roots_list([f1H, f2H], F, inf=u, sup=s, fast=True, strict=True, basis=True) + + I_L1_B, I_L1_U = I_L1, I_H + I_L2_B, I_L2_U = [], [] + I_L3_B, I_L3_U = _reverse_intervals(I_H), I_L3 + I_L4_B, I_L4_U = [], [] + + for I in I_L2: + (a, b), indices, h = I + + if a == b: + if a == y: + I_L2_B.append(I) + I_L2_U.append(I) + elif a < y: + I_L2_B.append(I) + else: + I_L2_U.append(I) + else: + if b <= y: + I_L2_B.append(I) + elif a >= y: + I_L2_U.append(I) + else: + a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=y, fast=True) + + if b <= y: + I_L2_B.append(((a, b), indices, h)) + if a >= y: + I_L2_U.append(((a, b), indices, h)) + + for I in I_L4: + (b, a), indices, h = I + + if a == b: + if a == y: + I_L4_B.append(I) + I_L4_U.append(I) + elif a < y: + I_L4_B.append(I) + else: + I_L4_U.append(I) + else: + if b <= y: + I_L4_B.append(I) + elif a >= y: + I_L4_U.append(I) + else: + a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=y, fast=True) + + if b <= y: + I_L4_B.append(((b, a), indices, h)) + if a >= y: + I_L4_U.append(((b, a), indices, h)) + + Q_L1_B = Q_L1 + Q_L2_B = _intervals_to_quadrants(I_L2_B, f1L2F, f2L2F, v, y, F) + Q_L3_B = _intervals_to_quadrants(I_L3_B, f1H, f2H, s, u, F) + Q_L4_B = _intervals_to_quadrants(I_L4_B, f1L4F, f2L4F, y, v, F) + + Q_L1_U = _intervals_to_quadrants(I_L1_U, f1H, f2H, u, s, F) + Q_L2_U = _intervals_to_quadrants(I_L2_U, f1L2F, f2L2F, y, t, F) + Q_L3_U = Q_L3 + Q_L4_U = _intervals_to_quadrants(I_L4_U, f1L4F, f2L4F, t, y, F) + + T_B = _traverse_quadrants(Q_L1_B, Q_L2_B, Q_L3_B, Q_L4_B, exclude=True) + T_U = _traverse_quadrants(Q_L1_U, Q_L2_U, Q_L3_U, Q_L4_U, exclude=True) + + N_B = _winding_number(T_B, F) + N_U = _winding_number(T_U, F) + + I_B = (I_L1_B, I_L2_B, I_L3_B, I_L4_B) + Q_B = (Q_L1_B, Q_L2_B, Q_L3_B, Q_L4_B) + + I_U = (I_L1_U, I_L2_U, I_L3_U, I_L4_U) + Q_U = (Q_L1_U, Q_L2_U, Q_L3_U, Q_L4_U) + + F1_B = (f1L1F, f1L2F, f1H, f1L4F) + F2_B = (f2L1F, f2L2F, f2H, f2L4F) + + F1_U = (f1H, f1L2F, f1L3F, f1L4F) + F2_U = (f2H, f2L2F, f2L3F, f2L4F) + + a, b = (u, v), (s, y) + c, d = (u, y), (s, t) + + D_B = (N_B, a, b, I_B, Q_B, F1_B, F2_B) + D_U = (N_U, c, d, I_U, Q_U, F1_U, F2_U) + + return D_B, D_U + +def _depth_first_select(rectangles): + """Find a rectangle of minimum area for bisection. """ + min_area, j = None, None + + for i, (_, (u, v), (s, t), _, _, _, _) in enumerate(rectangles): + area = (s - u)*(t - v) + + if min_area is None or area < min_area: + min_area, j = area, i + + return rectangles.pop(j) + +def _rectangle_small_p(a, b, eps): + """Return ``True`` if the given rectangle is small enough. """ + (u, v), (s, t) = a, b + + if eps is not None: + return s - u < eps and t - v < eps + else: + return True + +def dup_isolate_complex_roots_sqf(f, K, eps=None, inf=None, sup=None, blackbox=False): + """Isolate complex roots of a square-free polynomial using Collins-Krandick algorithm. """ + if not K.is_ZZ and not K.is_QQ: + raise DomainError("isolation of complex roots is not supported over %s" % K) + + if dup_degree(f) <= 0: + return [] + + if K.is_ZZ: + F = K.get_field() + else: + F = K + + f = dup_convert(f, K, F) + + lc = abs(dup_LC(f, F)) + B = 2*max(F.quo(abs(c), lc) for c in f) + + (u, v), (s, t) = (-B, F.zero), (B, B) + + if inf is not None: + u = inf + + if sup is not None: + s = sup + + if v < 0 or t <= v or s <= u: + raise ValueError("not a valid complex isolation rectangle") + + f1, f2 = dup_real_imag(f, F) + + f1L1 = dmp_eval_in(f1, v, 1, 1, F) + f2L1 = dmp_eval_in(f2, v, 1, 1, F) + + f1L2 = dmp_eval_in(f1, s, 0, 1, F) + f2L2 = dmp_eval_in(f2, s, 0, 1, F) + + f1L3 = dmp_eval_in(f1, t, 1, 1, F) + f2L3 = dmp_eval_in(f2, t, 1, 1, F) + + f1L4 = dmp_eval_in(f1, u, 0, 1, F) + f2L4 = dmp_eval_in(f2, u, 0, 1, F) + + S_L1 = [f1L1, f2L1] + S_L2 = [f1L2, f2L2] + S_L3 = [f1L3, f2L3] + S_L4 = [f1L4, f2L4] + + I_L1 = dup_isolate_real_roots_list(S_L1, F, inf=u, sup=s, fast=True, strict=True, basis=True) + I_L2 = dup_isolate_real_roots_list(S_L2, F, inf=v, sup=t, fast=True, strict=True, basis=True) + I_L3 = dup_isolate_real_roots_list(S_L3, F, inf=u, sup=s, fast=True, strict=True, basis=True) + I_L4 = dup_isolate_real_roots_list(S_L4, F, inf=v, sup=t, fast=True, strict=True, basis=True) + + I_L3 = _reverse_intervals(I_L3) + I_L4 = _reverse_intervals(I_L4) + + Q_L1 = _intervals_to_quadrants(I_L1, f1L1, f2L1, u, s, F) + Q_L2 = _intervals_to_quadrants(I_L2, f1L2, f2L2, v, t, F) + Q_L3 = _intervals_to_quadrants(I_L3, f1L3, f2L3, s, u, F) + Q_L4 = _intervals_to_quadrants(I_L4, f1L4, f2L4, t, v, F) + + T = _traverse_quadrants(Q_L1, Q_L2, Q_L3, Q_L4) + N = _winding_number(T, F) + + if not N: + return [] + + I = (I_L1, I_L2, I_L3, I_L4) + Q = (Q_L1, Q_L2, Q_L3, Q_L4) + + F1 = (f1L1, f1L2, f1L3, f1L4) + F2 = (f2L1, f2L2, f2L3, f2L4) + + rectangles, roots = [(N, (u, v), (s, t), I, Q, F1, F2)], [] + + while rectangles: + N, (u, v), (s, t), I, Q, F1, F2 = _depth_first_select(rectangles) + + if s - u > t - v: + D_L, D_R = _vertical_bisection(N, (u, v), (s, t), I, Q, F1, F2, f1, f2, F) + + N_L, a, b, I_L, Q_L, F1_L, F2_L = D_L + N_R, c, d, I_R, Q_R, F1_R, F2_R = D_R + + if N_L >= 1: + if N_L == 1 and _rectangle_small_p(a, b, eps): + roots.append(ComplexInterval(a, b, I_L, Q_L, F1_L, F2_L, f1, f2, F)) + else: + rectangles.append(D_L) + + if N_R >= 1: + if N_R == 1 and _rectangle_small_p(c, d, eps): + roots.append(ComplexInterval(c, d, I_R, Q_R, F1_R, F2_R, f1, f2, F)) + else: + rectangles.append(D_R) + else: + D_B, D_U = _horizontal_bisection(N, (u, v), (s, t), I, Q, F1, F2, f1, f2, F) + + N_B, a, b, I_B, Q_B, F1_B, F2_B = D_B + N_U, c, d, I_U, Q_U, F1_U, F2_U = D_U + + if N_B >= 1: + if N_B == 1 and _rectangle_small_p(a, b, eps): + roots.append(ComplexInterval( + a, b, I_B, Q_B, F1_B, F2_B, f1, f2, F)) + else: + rectangles.append(D_B) + + if N_U >= 1: + if N_U == 1 and _rectangle_small_p(c, d, eps): + roots.append(ComplexInterval( + c, d, I_U, Q_U, F1_U, F2_U, f1, f2, F)) + else: + rectangles.append(D_U) + + _roots, roots = sorted(roots, key=lambda r: (r.ax, r.ay)), [] + + for root in _roots: + roots.extend([root.conjugate(), root]) + + if blackbox: + return roots + else: + return [ r.as_tuple() for r in roots ] + +def dup_isolate_all_roots_sqf(f, K, eps=None, inf=None, sup=None, fast=False, blackbox=False): + """Isolate real and complex roots of a square-free polynomial ``f``. """ + return ( + dup_isolate_real_roots_sqf( f, K, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox), + dup_isolate_complex_roots_sqf(f, K, eps=eps, inf=inf, sup=sup, blackbox=blackbox)) + +def dup_isolate_all_roots(f, K, eps=None, inf=None, sup=None, fast=False): + """Isolate real and complex roots of a non-square-free polynomial ``f``. """ + if not K.is_ZZ and not K.is_QQ: + raise DomainError("isolation of real and complex roots is not supported over %s" % K) + + _, factors = dup_sqf_list(f, K) + + if len(factors) == 1: + ((f, k),) = factors + + real_part, complex_part = dup_isolate_all_roots_sqf( + f, K, eps=eps, inf=inf, sup=sup, fast=fast) + + real_part = [ ((a, b), k) for (a, b) in real_part ] + complex_part = [ ((a, b), k) for (a, b) in complex_part ] + + return real_part, complex_part + else: + raise NotImplementedError( "only trivial square-free polynomials are supported") + +class RealInterval: + """A fully qualified representation of a real isolation interval. """ + + def __init__(self, data, f, dom): + """Initialize new real interval with complete information. """ + if len(data) == 2: + s, t = data + + self.neg = False + + if s < 0: + if t <= 0: + f, s, t, self.neg = dup_mirror(f, dom), -t, -s, True + else: + raise ValueError("Cannot refine a real root in (%s, %s)" % (s, t)) + + a, b, c, d = _mobius_from_interval((s, t), dom.get_field()) + + f = dup_transform(f, dup_strip([a, b]), + dup_strip([c, d]), dom) + + self.mobius = a, b, c, d + else: + self.mobius = data[:-1] + self.neg = data[-1] + + self.f, self.dom = f, dom + + @property + def func(self): + return RealInterval + + @property + def args(self): + i = self + return (i.mobius + (i.neg,), i.f, i.dom) + + def __eq__(self, other): + if type(other) is not type(self): + return False + return self.args == other.args + + @property + def a(self): + """Return the position of the left end. """ + field = self.dom.get_field() + a, b, c, d = self.mobius + + if not self.neg: + if a*d < b*c: + return field(a, c) + return field(b, d) + else: + if a*d > b*c: + return -field(a, c) + return -field(b, d) + + @property + def b(self): + """Return the position of the right end. """ + was = self.neg + self.neg = not was + rv = -self.a + self.neg = was + return rv + + @property + def dx(self): + """Return width of the real isolating interval. """ + return self.b - self.a + + @property + def center(self): + """Return the center of the real isolating interval. """ + return (self.a + self.b)/2 + + @property + def max_denom(self): + """Return the largest denominator occurring in either endpoint. """ + return max(self.a.denominator, self.b.denominator) + + def as_tuple(self): + """Return tuple representation of real isolating interval. """ + return (self.a, self.b) + + def __repr__(self): + return "(%s, %s)" % (self.a, self.b) + + def __contains__(self, item): + """ + Say whether a complex number belongs to this real interval. + + Parameters + ========== + + item : pair (re, im) or number re + Either a pair giving the real and imaginary parts of the number, + or else a real number. + + """ + if isinstance(item, tuple): + re, im = item + else: + re, im = item, 0 + return im == 0 and self.a <= re <= self.b + + def is_disjoint(self, other): + """Return ``True`` if two isolation intervals are disjoint. """ + if isinstance(other, RealInterval): + return (self.b < other.a or other.b < self.a) + assert isinstance(other, ComplexInterval) + return (self.b < other.ax or other.bx < self.a + or other.ay*other.by > 0) + + def _inner_refine(self): + """Internal one step real root refinement procedure. """ + if self.mobius is None: + return self + + f, mobius = dup_inner_refine_real_root( + self.f, self.mobius, self.dom, steps=1, mobius=True) + + return RealInterval(mobius + (self.neg,), f, self.dom) + + def refine_disjoint(self, other): + """Refine an isolating interval until it is disjoint with another one. """ + expr = self + while not expr.is_disjoint(other): + expr, other = expr._inner_refine(), other._inner_refine() + + return expr, other + + def refine_size(self, dx): + """Refine an isolating interval until it is of sufficiently small size. """ + expr = self + while not (expr.dx < dx): + expr = expr._inner_refine() + + return expr + + def refine_step(self, steps=1): + """Perform several steps of real root refinement algorithm. """ + expr = self + for _ in range(steps): + expr = expr._inner_refine() + + return expr + + def refine(self): + """Perform one step of real root refinement algorithm. """ + return self._inner_refine() + + +class ComplexInterval: + """A fully qualified representation of a complex isolation interval. + The printed form is shown as (ax, bx) x (ay, by) where (ax, ay) + and (bx, by) are the coordinates of the southwest and northeast + corners of the interval's rectangle, respectively. + + Examples + ======== + + >>> from sympy import CRootOf, S + >>> from sympy.abc import x + >>> CRootOf.clear_cache() # for doctest reproducibility + >>> root = CRootOf(x**10 - 2*x + 3, 9) + >>> i = root._get_interval(); i + (3/64, 3/32) x (9/8, 75/64) + + The real part of the root lies within the range [0, 3/4] while + the imaginary part lies within the range [9/8, 3/2]: + + >>> root.n(3) + 0.0766 + 1.14*I + + The width of the ranges in the x and y directions on the complex + plane are: + + >>> i.dx, i.dy + (3/64, 3/64) + + The center of the range is + + >>> i.center + (9/128, 147/128) + + The northeast coordinate of the rectangle bounding the root in the + complex plane is given by attribute b and the x and y components + are accessed by bx and by: + + >>> i.b, i.bx, i.by + ((3/32, 75/64), 3/32, 75/64) + + The southwest coordinate is similarly given by i.a + + >>> i.a, i.ax, i.ay + ((3/64, 9/8), 3/64, 9/8) + + Although the interval prints to show only the real and imaginary + range of the root, all the information of the underlying root + is contained as properties of the interval. + + For example, an interval with a nonpositive imaginary range is + considered to be the conjugate. Since the y values of y are in the + range [0, 1/4] it is not the conjugate: + + >>> i.conj + False + + The conjugate's interval is + + >>> ic = i.conjugate(); ic + (3/64, 3/32) x (-75/64, -9/8) + + NOTE: the values printed still represent the x and y range + in which the root -- conjugate, in this case -- is located, + but the underlying a and b values of a root and its conjugate + are the same: + + >>> assert i.a == ic.a and i.b == ic.b + + What changes are the reported coordinates of the bounding rectangle: + + >>> (i.ax, i.ay), (i.bx, i.by) + ((3/64, 9/8), (3/32, 75/64)) + >>> (ic.ax, ic.ay), (ic.bx, ic.by) + ((3/64, -75/64), (3/32, -9/8)) + + The interval can be refined once: + + >>> i # for reference, this is the current interval + (3/64, 3/32) x (9/8, 75/64) + + >>> i.refine() + (3/64, 3/32) x (9/8, 147/128) + + Several refinement steps can be taken: + + >>> i.refine_step(2) # 2 steps + (9/128, 3/32) x (9/8, 147/128) + + It is also possible to refine to a given tolerance: + + >>> tol = min(i.dx, i.dy)/2 + >>> i.refine_size(tol) + (9/128, 21/256) x (9/8, 291/256) + + A disjoint interval is one whose bounding rectangle does not + overlap with another. An interval, necessarily, is not disjoint with + itself, but any interval is disjoint with a conjugate since the + conjugate rectangle will always be in the lower half of the complex + plane and the non-conjugate in the upper half: + + >>> i.is_disjoint(i), i.is_disjoint(i.conjugate()) + (False, True) + + The following interval j is not disjoint from i: + + >>> close = CRootOf(x**10 - 2*x + 300/S(101), 9) + >>> j = close._get_interval(); j + (75/1616, 75/808) x (225/202, 1875/1616) + >>> i.is_disjoint(j) + False + + The two can be made disjoint, however: + + >>> newi, newj = i.refine_disjoint(j) + >>> newi + (39/512, 159/2048) x (2325/2048, 4653/4096) + >>> newj + (3975/51712, 2025/25856) x (29325/25856, 117375/103424) + + Even though the real ranges overlap, the imaginary do not, so + the roots have been resolved as distinct. Intervals are disjoint + when either the real or imaginary component of the intervals is + distinct. In the case above, the real components have not been + resolved (so we do not know, yet, which root has the smaller real + part) but the imaginary part of ``close`` is larger than ``root``: + + >>> close.n(3) + 0.0771 + 1.13*I + >>> root.n(3) + 0.0766 + 1.14*I + """ + + def __init__(self, a, b, I, Q, F1, F2, f1, f2, dom, conj=False): + """Initialize new complex interval with complete information. """ + # a and b are the SW and NE corner of the bounding interval, + # (ax, ay) and (bx, by), respectively, for the NON-CONJUGATE + # root (the one with the positive imaginary part); when working + # with the conjugate, the a and b value are still non-negative + # but the ay, by are reversed and have oppositite sign + self.a, self.b = a, b + self.I, self.Q = I, Q + + self.f1, self.F1 = f1, F1 + self.f2, self.F2 = f2, F2 + + self.dom = dom + self.conj = conj + + @property + def func(self): + return ComplexInterval + + @property + def args(self): + i = self + return (i.a, i.b, i.I, i.Q, i.F1, i.F2, i.f1, i.f2, i.dom, i.conj) + + def __eq__(self, other): + if type(other) is not type(self): + return False + return self.args == other.args + + @property + def ax(self): + """Return ``x`` coordinate of south-western corner. """ + return self.a[0] + + @property + def ay(self): + """Return ``y`` coordinate of south-western corner. """ + if not self.conj: + return self.a[1] + else: + return -self.b[1] + + @property + def bx(self): + """Return ``x`` coordinate of north-eastern corner. """ + return self.b[0] + + @property + def by(self): + """Return ``y`` coordinate of north-eastern corner. """ + if not self.conj: + return self.b[1] + else: + return -self.a[1] + + @property + def dx(self): + """Return width of the complex isolating interval. """ + return self.b[0] - self.a[0] + + @property + def dy(self): + """Return height of the complex isolating interval. """ + return self.b[1] - self.a[1] + + @property + def center(self): + """Return the center of the complex isolating interval. """ + return ((self.ax + self.bx)/2, (self.ay + self.by)/2) + + @property + def max_denom(self): + """Return the largest denominator occurring in either endpoint. """ + return max(self.ax.denominator, self.bx.denominator, + self.ay.denominator, self.by.denominator) + + def as_tuple(self): + """Return tuple representation of the complex isolating + interval's SW and NE corners, respectively. """ + return ((self.ax, self.ay), (self.bx, self.by)) + + def __repr__(self): + return "(%s, %s) x (%s, %s)" % (self.ax, self.bx, self.ay, self.by) + + def conjugate(self): + """This complex interval really is located in lower half-plane. """ + return ComplexInterval(self.a, self.b, self.I, self.Q, + self.F1, self.F2, self.f1, self.f2, self.dom, conj=True) + + def __contains__(self, item): + """ + Say whether a complex number belongs to this complex rectangular + region. + + Parameters + ========== + + item : pair (re, im) or number re + Either a pair giving the real and imaginary parts of the number, + or else a real number. + + """ + if isinstance(item, tuple): + re, im = item + else: + re, im = item, 0 + return self.ax <= re <= self.bx and self.ay <= im <= self.by + + def is_disjoint(self, other): + """Return ``True`` if two isolation intervals are disjoint. """ + if isinstance(other, RealInterval): + return other.is_disjoint(self) + if self.conj != other.conj: # above and below real axis + return True + re_distinct = (self.bx < other.ax or other.bx < self.ax) + if re_distinct: + return True + im_distinct = (self.by < other.ay or other.by < self.ay) + return im_distinct + + def _inner_refine(self): + """Internal one step complex root refinement procedure. """ + (u, v), (s, t) = self.a, self.b + + I, Q = self.I, self.Q + + f1, F1 = self.f1, self.F1 + f2, F2 = self.f2, self.F2 + + dom = self.dom + + if s - u > t - v: + D_L, D_R = _vertical_bisection(1, (u, v), (s, t), I, Q, F1, F2, f1, f2, dom) + + if D_L[0] == 1: + _, a, b, I, Q, F1, F2 = D_L + else: + _, a, b, I, Q, F1, F2 = D_R + else: + D_B, D_U = _horizontal_bisection(1, (u, v), (s, t), I, Q, F1, F2, f1, f2, dom) + + if D_B[0] == 1: + _, a, b, I, Q, F1, F2 = D_B + else: + _, a, b, I, Q, F1, F2 = D_U + + return ComplexInterval(a, b, I, Q, F1, F2, f1, f2, dom, self.conj) + + def refine_disjoint(self, other): + """Refine an isolating interval until it is disjoint with another one. """ + expr = self + while not expr.is_disjoint(other): + expr, other = expr._inner_refine(), other._inner_refine() + + return expr, other + + def refine_size(self, dx, dy=None): + """Refine an isolating interval until it is of sufficiently small size. """ + if dy is None: + dy = dx + expr = self + while not (expr.dx < dx and expr.dy < dy): + expr = expr._inner_refine() + + return expr + + def refine_step(self, steps=1): + """Perform several steps of complex root refinement algorithm. """ + expr = self + for _ in range(steps): + expr = expr._inner_refine() + + return expr + + def refine(self): + """Perform one step of complex root refinement algorithm. """ + return self._inner_refine() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rootoftools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rootoftools.py new file mode 100644 index 0000000000000000000000000000000000000000..d68d8b008281c7e9b5aac618c6c76f74fa236d9e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/rootoftools.py @@ -0,0 +1,1298 @@ +"""Implementation of RootOf class and related tools. """ + + + +from sympy.core.basic import Basic +from sympy.core import (S, Expr, Integer, Float, I, oo, Add, Lambda, + symbols, sympify, Rational, Dummy) +from sympy.core.cache import cacheit +from sympy.core.relational import is_le +from sympy.core.sorting import ordered +from sympy.polys.domains import QQ +from sympy.polys.polyerrors import ( + MultivariatePolynomialError, + GeneratorsNeeded, + PolynomialError, + DomainError) +from sympy.polys.polyfuncs import symmetrize, viete +from sympy.polys.polyroots import ( + roots_linear, roots_quadratic, roots_binomial, + preprocess_roots, roots) +from sympy.polys.polytools import Poly, PurePoly, factor +from sympy.polys.rationaltools import together +from sympy.polys.rootisolation import ( + dup_isolate_complex_roots_sqf, + dup_isolate_real_roots_sqf) +from sympy.utilities import lambdify, public, sift, numbered_symbols + +from mpmath import mpf, mpc, findroot, workprec +from mpmath.libmp.libmpf import dps_to_prec, prec_to_dps +from sympy.multipledispatch import dispatch +from itertools import chain + + +__all__ = ['CRootOf'] + + + +class _pure_key_dict: + """A minimal dictionary that makes sure that the key is a + univariate PurePoly instance. + + Examples + ======== + + Only the following actions are guaranteed: + + >>> from sympy.polys.rootoftools import _pure_key_dict + >>> from sympy import PurePoly + >>> from sympy.abc import x, y + + 1) creation + + >>> P = _pure_key_dict() + + 2) assignment for a PurePoly or univariate polynomial + + >>> P[x] = 1 + >>> P[PurePoly(x - y, x)] = 2 + + 3) retrieval based on PurePoly key comparison (use this + instead of the get method) + + >>> P[y] + 1 + + 4) KeyError when trying to retrieve a nonexisting key + + >>> P[y + 1] + Traceback (most recent call last): + ... + KeyError: PurePoly(y + 1, y, domain='ZZ') + + 5) ability to query with ``in`` + + >>> x + 1 in P + False + + NOTE: this is a *not* a dictionary. It is a very basic object + for internal use that makes sure to always address its cache + via PurePoly instances. It does not, for example, implement + ``get`` or ``setdefault``. + """ + def __init__(self): + self._dict = {} + + def __getitem__(self, k): + if not isinstance(k, PurePoly): + if not (isinstance(k, Expr) and len(k.free_symbols) == 1): + raise KeyError + k = PurePoly(k, expand=False) + return self._dict[k] + + def __setitem__(self, k, v): + if not isinstance(k, PurePoly): + if not (isinstance(k, Expr) and len(k.free_symbols) == 1): + raise ValueError('expecting univariate expression') + k = PurePoly(k, expand=False) + self._dict[k] = v + + def __contains__(self, k): + try: + self[k] + return True + except KeyError: + return False + +_reals_cache = _pure_key_dict() +_complexes_cache = _pure_key_dict() + + +def _pure_factors(poly): + _, factors = poly.factor_list() + return [(PurePoly(f, expand=False), m) for f, m in factors] + + +def _imag_count_of_factor(f): + """Return the number of imaginary roots for irreducible + univariate polynomial ``f``. + """ + terms = [(i, j) for (i,), j in f.terms()] + if any(i % 2 for i, j in terms): + return 0 + # update signs + even = [(i, I**i*j) for i, j in terms] + even = Poly.from_dict(dict(even), Dummy('x')) + return int(even.count_roots(-oo, oo)) + + +@public +def rootof(f, x, index=None, radicals=True, expand=True): + """An indexed root of a univariate polynomial. + + Returns either a :obj:`ComplexRootOf` object or an explicit + expression involving radicals. + + Parameters + ========== + + f : Expr + Univariate polynomial. + x : Symbol, optional + Generator for ``f``. + index : int or Integer + radicals : bool + Return a radical expression if possible. + expand : bool + Expand ``f``. + """ + return CRootOf(f, x, index=index, radicals=radicals, expand=expand) + + +@public +class RootOf(Expr): + """Represents a root of a univariate polynomial. + + Base class for roots of different kinds of polynomials. + Only complex roots are currently supported. + """ + + __slots__ = ('poly',) + + def __new__(cls, f, x, index=None, radicals=True, expand=True): + """Construct a new ``CRootOf`` object for ``k``-th root of ``f``.""" + return rootof(f, x, index=index, radicals=radicals, expand=expand) + +@public +class ComplexRootOf(RootOf): + """Represents an indexed complex root of a polynomial. + + Roots of a univariate polynomial separated into disjoint + real or complex intervals and indexed in a fixed order: + + * real roots come first and are sorted in increasing order; + * complex roots come next and are sorted primarily by increasing + real part, secondarily by increasing imaginary part. + + Currently only rational coefficients are allowed. + Can be imported as ``CRootOf``. To avoid confusion, the + generator must be a Symbol. + + + Examples + ======== + + >>> from sympy import CRootOf, rootof + >>> from sympy.abc import x + + CRootOf is a way to reference a particular root of a + polynomial. If there is a rational root, it will be returned: + + >>> CRootOf.clear_cache() # for doctest reproducibility + >>> CRootOf(x**2 - 4, 0) + -2 + + Whether roots involving radicals are returned or not + depends on whether the ``radicals`` flag is true (which is + set to True with rootof): + + >>> CRootOf(x**2 - 3, 0) + CRootOf(x**2 - 3, 0) + >>> CRootOf(x**2 - 3, 0, radicals=True) + -sqrt(3) + >>> rootof(x**2 - 3, 0) + -sqrt(3) + + The following cannot be expressed in terms of radicals: + + >>> r = rootof(4*x**5 + 16*x**3 + 12*x**2 + 7, 0); r + CRootOf(4*x**5 + 16*x**3 + 12*x**2 + 7, 0) + + The root bounds can be seen, however, and they are used by the + evaluation methods to get numerical approximations for the root. + + >>> interval = r._get_interval(); interval + (-1, 0) + >>> r.evalf(2) + -0.98 + + The evalf method refines the width of the root bounds until it + guarantees that any decimal approximation within those bounds + will satisfy the desired precision. It then stores the refined + interval so subsequent requests at or below the requested + precision will not have to recompute the root bounds and will + return very quickly. + + Before evaluation above, the interval was + + >>> interval + (-1, 0) + + After evaluation it is now + + >>> r._get_interval() # doctest: +SKIP + (-165/169, -206/211) + + To reset all intervals for a given polynomial, the :meth:`_reset` method + can be called from any CRootOf instance of the polynomial: + + >>> r._reset() + >>> r._get_interval() + (-1, 0) + + The :meth:`eval_approx` method will also find the root to a given + precision but the interval is not modified unless the search + for the root fails to converge within the root bounds. And + the secant method is used to find the root. (The ``evalf`` + method uses bisection and will always update the interval.) + + >>> r.eval_approx(2) + -0.98 + + The interval needed to be slightly updated to find that root: + + >>> r._get_interval() + (-1, -1/2) + + The ``evalf_rational`` will compute a rational approximation + of the root to the desired accuracy or precision. + + >>> r.eval_rational(n=2) + -69629/71318 + + >>> t = CRootOf(x**3 + 10*x + 1, 1) + >>> t.eval_rational(1e-1) + 15/256 - 805*I/256 + >>> t.eval_rational(1e-1, 1e-4) + 3275/65536 - 414645*I/131072 + >>> t.eval_rational(1e-4, 1e-4) + 6545/131072 - 414645*I/131072 + >>> t.eval_rational(n=2) + 104755/2097152 - 6634255*I/2097152 + + Notes + ===== + + Although a PurePoly can be constructed from a non-symbol generator + RootOf instances of non-symbols are disallowed to avoid confusion + over what root is being represented. + + >>> from sympy import exp, PurePoly + >>> PurePoly(x) == PurePoly(exp(x)) + True + >>> CRootOf(x - 1, 0) + 1 + >>> CRootOf(exp(x) - 1, 0) # would correspond to x == 0 + Traceback (most recent call last): + ... + sympy.polys.polyerrors.PolynomialError: generator must be a Symbol + + See Also + ======== + + eval_approx + eval_rational + + """ + + __slots__ = ('index',) + is_complex = True + is_number = True + is_finite = True + is_algebraic = True + + def __new__(cls, f, x, index=None, radicals=False, expand=True): + """ Construct an indexed complex root of a polynomial. + + See ``rootof`` for the parameters. + + The default value of ``radicals`` is ``False`` to satisfy + ``eval(srepr(expr) == expr``. + """ + x = sympify(x) + + if index is None and x.is_Integer: + x, index = None, x + else: + index = sympify(index) + + if index is not None and index.is_Integer: + index = int(index) + else: + raise ValueError("expected an integer root index, got %s" % index) + + poly = PurePoly(f, x, greedy=False, expand=expand) + + if not poly.is_univariate: + raise PolynomialError("only univariate polynomials are allowed") + + if not poly.gen.is_Symbol: + # PurePoly(sin(x) + 1) == PurePoly(x + 1) but the roots of + # x for each are not the same: issue 8617 + raise PolynomialError("generator must be a Symbol") + + degree = poly.degree() + + if degree <= 0: + raise PolynomialError("Cannot construct CRootOf object for %s" % f) + + if index < -degree or index >= degree: + raise IndexError("root index out of [%d, %d] range, got %d" % + (-degree, degree - 1, index)) + elif index < 0: + index += degree + + dom = poly.get_domain() + + if not dom.is_Exact: + poly = poly.to_exact() + + roots = cls._roots_trivial(poly, radicals) + + if roots is not None: + return roots[index] + + coeff, poly = preprocess_roots(poly) + dom = poly.get_domain() + + if not dom.is_ZZ: + raise NotImplementedError("CRootOf is not supported over %s" % dom) + + root = cls._indexed_root(poly, index, lazy=True) + return coeff * cls._postprocess_root(root, radicals) + + @classmethod + def _new(cls, poly, index): + """Construct new ``CRootOf`` object from raw data. """ + obj = Expr.__new__(cls) + + obj.poly = PurePoly(poly) + obj.index = index + + try: + _reals_cache[obj.poly] = _reals_cache[poly] + _complexes_cache[obj.poly] = _complexes_cache[poly] + except KeyError: + pass + + return obj + + def _hashable_content(self): + return (self.poly, self.index) + + @property + def expr(self): + return self.poly.as_expr() + + @property + def args(self): + return (self.expr, Integer(self.index)) + + @property + def free_symbols(self): + # CRootOf currently only works with univariate expressions + # whose poly attribute should be a PurePoly with no free + # symbols + return set() + + def _eval_is_real(self): + """Return ``True`` if the root is real. """ + self._ensure_reals_init() + return self.index < len(_reals_cache[self.poly]) + + def _eval_is_imaginary(self): + """Return ``True`` if the root is imaginary. """ + self._ensure_reals_init() + if self.index >= len(_reals_cache[self.poly]): + ivl = self._get_interval() + return ivl.ax*ivl.bx <= 0 # all others are on one side or the other + return False # XXX is this necessary? + + @classmethod + def real_roots(cls, poly, radicals=True): + """Get real roots of a polynomial. """ + return cls._get_roots("_real_roots", poly, radicals) + + @classmethod + def all_roots(cls, poly, radicals=True): + """Get real and complex roots of a polynomial. """ + return cls._get_roots("_all_roots", poly, radicals) + + @classmethod + def _get_reals_sqf(cls, currentfactor, use_cache=True): + """Get real root isolating intervals for a square-free factor.""" + if use_cache and currentfactor in _reals_cache: + real_part = _reals_cache[currentfactor] + else: + _reals_cache[currentfactor] = real_part = \ + dup_isolate_real_roots_sqf( + currentfactor.rep.to_list(), currentfactor.rep.dom, blackbox=True) + + return real_part + + @classmethod + def _get_complexes_sqf(cls, currentfactor, use_cache=True): + """Get complex root isolating intervals for a square-free factor.""" + if use_cache and currentfactor in _complexes_cache: + complex_part = _complexes_cache[currentfactor] + else: + _complexes_cache[currentfactor] = complex_part = \ + dup_isolate_complex_roots_sqf( + currentfactor.rep.to_list(), currentfactor.rep.dom, blackbox=True) + return complex_part + + @classmethod + def _get_reals(cls, factors, use_cache=True): + """Compute real root isolating intervals for a list of factors. """ + reals = [] + + for currentfactor, k in factors: + try: + if not use_cache: + raise KeyError + r = _reals_cache[currentfactor] + reals.extend([(i, currentfactor, k) for i in r]) + except KeyError: + real_part = cls._get_reals_sqf(currentfactor, use_cache) + new = [(root, currentfactor, k) for root in real_part] + reals.extend(new) + + reals = cls._reals_sorted(reals) + return reals + + @classmethod + def _get_complexes(cls, factors, use_cache=True): + """Compute complex root isolating intervals for a list of factors. """ + complexes = [] + + for currentfactor, k in ordered(factors): + try: + if not use_cache: + raise KeyError + c = _complexes_cache[currentfactor] + complexes.extend([(i, currentfactor, k) for i in c]) + except KeyError: + complex_part = cls._get_complexes_sqf(currentfactor, use_cache) + new = [(root, currentfactor, k) for root in complex_part] + complexes.extend(new) + + complexes = cls._complexes_sorted(complexes) + return complexes + + @classmethod + def _reals_sorted(cls, reals): + """Make real isolating intervals disjoint and sort roots. """ + cache = {} + + for i, (u, f, k) in enumerate(reals): + for j, (v, g, m) in enumerate(reals[i + 1:]): + u, v = u.refine_disjoint(v) + reals[i + j + 1] = (v, g, m) + + reals[i] = (u, f, k) + + reals = sorted(reals, key=lambda r: r[0].a) + + for root, currentfactor, _ in reals: + if currentfactor in cache: + cache[currentfactor].append(root) + else: + cache[currentfactor] = [root] + + for currentfactor, root in cache.items(): + _reals_cache[currentfactor] = root + + return reals + + @classmethod + def _refine_imaginary(cls, complexes): + sifted = sift(complexes, lambda c: c[1]) + complexes = [] + for f in ordered(sifted): + nimag = _imag_count_of_factor(f) + if nimag == 0: + # refine until xbounds are neg or pos + for u, f, k in sifted[f]: + while u.ax*u.bx <= 0: + u = u._inner_refine() + complexes.append((u, f, k)) + else: + # refine until all but nimag xbounds are neg or pos + potential_imag = list(range(len(sifted[f]))) + while True: + assert len(potential_imag) > 1 + for i in list(potential_imag): + u, f, k = sifted[f][i] + if u.ax*u.bx > 0: + potential_imag.remove(i) + elif u.ax != u.bx: + u = u._inner_refine() + sifted[f][i] = u, f, k + if len(potential_imag) == nimag: + break + complexes.extend(sifted[f]) + return complexes + + @classmethod + def _refine_complexes(cls, complexes): + """return complexes such that no bounding rectangles of non-conjugate + roots would intersect. In addition, assure that neither ay nor by is + 0 to guarantee that non-real roots are distinct from real roots in + terms of the y-bounds. + """ + # get the intervals pairwise-disjoint. + # If rectangles were drawn around the coordinates of the bounding + # rectangles, no rectangles would intersect after this procedure. + for i, (u, f, k) in enumerate(complexes): + for j, (v, g, m) in enumerate(complexes[i + 1:]): + u, v = u.refine_disjoint(v) + complexes[i + j + 1] = (v, g, m) + + complexes[i] = (u, f, k) + + # refine until the x-bounds are unambiguously positive or negative + # for non-imaginary roots + complexes = cls._refine_imaginary(complexes) + + # make sure that all y bounds are off the real axis + # and on the same side of the axis + for i, (u, f, k) in enumerate(complexes): + while u.ay*u.by <= 0: + u = u.refine() + complexes[i] = u, f, k + return complexes + + @classmethod + def _complexes_sorted(cls, complexes): + """Make complex isolating intervals disjoint and sort roots. """ + complexes = cls._refine_complexes(complexes) + # XXX don't sort until you are sure that it is compatible + # with the indexing method but assert that the desired state + # is not broken + C, F = 0, 1 # location of ComplexInterval and factor + fs = {i[F] for i in complexes} + for i in range(1, len(complexes)): + if complexes[i][F] != complexes[i - 1][F]: + # if this fails the factors of a root were not + # contiguous because a discontinuity should only + # happen once + fs.remove(complexes[i - 1][F]) + for i, cmplx in enumerate(complexes): + # negative im part (conj=True) comes before + # positive im part (conj=False) + assert cmplx[C].conj is (i % 2 == 0) + + # update cache + cache = {} + # -- collate + for root, currentfactor, _ in complexes: + cache.setdefault(currentfactor, []).append(root) + # -- store + for currentfactor, root in cache.items(): + _complexes_cache[currentfactor] = root + + return complexes + + @classmethod + def _reals_index(cls, reals, index): + """ + Map initial real root index to an index in a factor where + the root belongs. + """ + i = 0 + + for j, (_, currentfactor, k) in enumerate(reals): + if index < i + k: + poly, index = currentfactor, 0 + + for _, currentfactor, _ in reals[:j]: + if currentfactor == poly: + index += 1 + + return poly, index + else: + i += k + + @classmethod + def _complexes_index(cls, complexes, index): + """ + Map initial complex root index to an index in a factor where + the root belongs. + """ + i = 0 + for j, (_, currentfactor, k) in enumerate(complexes): + if index < i + k: + poly, index = currentfactor, 0 + + for _, currentfactor, _ in complexes[:j]: + if currentfactor == poly: + index += 1 + + index += len(_reals_cache[poly]) + + return poly, index + else: + i += k + + @classmethod + def _count_roots(cls, roots): + """Count the number of real or complex roots with multiplicities.""" + return sum(k for _, _, k in roots) + + @classmethod + def _indexed_root(cls, poly, index, lazy=False): + """Get a root of a composite polynomial by index. """ + factors = _pure_factors(poly) + + # If the given poly is already irreducible, then the index does not + # need to be adjusted, and we can postpone the heavy lifting of + # computing and refining isolating intervals until that is needed. + # Note, however, that `_pure_factors()` extracts a negative leading + # coeff if present, so `factors[0][0]` may differ from `poly`, and + # is the "normalized" version of `poly` that we must return. + if lazy and len(factors) == 1 and factors[0][1] == 1: + return factors[0][0], index + + reals = cls._get_reals(factors) + reals_count = cls._count_roots(reals) + + if index < reals_count: + return cls._reals_index(reals, index) + else: + complexes = cls._get_complexes(factors) + return cls._complexes_index(complexes, index - reals_count) + + def _ensure_reals_init(self): + """Ensure that our poly has entries in the reals cache. """ + if self.poly not in _reals_cache: + self._indexed_root(self.poly, self.index) + + def _ensure_complexes_init(self): + """Ensure that our poly has entries in the complexes cache. """ + if self.poly not in _complexes_cache: + self._indexed_root(self.poly, self.index) + + @classmethod + def _real_roots(cls, poly): + """Get real roots of a composite polynomial. """ + factors = _pure_factors(poly) + + reals = cls._get_reals(factors) + reals_count = cls._count_roots(reals) + + roots = [] + + for index in range(0, reals_count): + roots.append(cls._reals_index(reals, index)) + + return roots + + def _reset(self): + """ + Reset all intervals + """ + self._all_roots(self.poly, use_cache=False) + + @classmethod + def _all_roots(cls, poly, use_cache=True): + """Get real and complex roots of a composite polynomial. """ + factors = _pure_factors(poly) + + reals = cls._get_reals(factors, use_cache=use_cache) + reals_count = cls._count_roots(reals) + + roots = [] + + for index in range(0, reals_count): + roots.append(cls._reals_index(reals, index)) + + complexes = cls._get_complexes(factors, use_cache=use_cache) + complexes_count = cls._count_roots(complexes) + + for index in range(0, complexes_count): + roots.append(cls._complexes_index(complexes, index)) + + return roots + + @classmethod + @cacheit + def _roots_trivial(cls, poly, radicals): + """Compute roots in linear, quadratic and binomial cases. """ + if poly.degree() == 1: + return roots_linear(poly) + + if not radicals: + return None + + if poly.degree() == 2: + return roots_quadratic(poly) + elif poly.length() == 2 and poly.TC(): + return roots_binomial(poly) + else: + return None + + @classmethod + def _preprocess_roots(cls, poly): + """Take heroic measures to make ``poly`` compatible with ``CRootOf``.""" + dom = poly.get_domain() + + if not dom.is_Exact: + poly = poly.to_exact() + + coeff, poly = preprocess_roots(poly) + dom = poly.get_domain() + + if not dom.is_ZZ: + raise NotImplementedError( + "sorted roots not supported over %s" % dom) + + return coeff, poly + + @classmethod + def _postprocess_root(cls, root, radicals): + """Return the root if it is trivial or a ``CRootOf`` object. """ + poly, index = root + roots = cls._roots_trivial(poly, radicals) + + if roots is not None: + return roots[index] + else: + return cls._new(poly, index) + + @classmethod + def _get_roots(cls, method, poly, radicals): + """Return postprocessed roots of specified kind. """ + if not poly.is_univariate: + raise PolynomialError("only univariate polynomials are allowed") + + dom = poly.get_domain() + + # get rid of gen and it's free symbol + d = Dummy() + poly = poly.subs(poly.gen, d) + x = symbols('x') + # see what others are left and select x or a numbered x + # that doesn't clash + free_names = {str(i) for i in poly.free_symbols} + for x in chain((symbols('x'),), numbered_symbols('x')): + if x.name not in free_names: + poly = poly.replace(d, x) + break + + if dom.is_QQ or dom.is_ZZ: + return cls._get_roots_qq(method, poly, radicals) + elif dom.is_AlgebraicField or dom.is_ZZ_I or dom.is_QQ_I: + return cls._get_roots_alg(method, poly, radicals) + else: + # XXX: not sure how to handle ZZ[x] which appears in some tests? + # this makes the tests pass alright but has to be a better way? + return cls._get_roots_qq(method, poly, radicals) + + + @classmethod + def _get_roots_qq(cls, method, poly, radicals): + """Return postprocessed roots of specified kind + for polynomials with rational coefficients. """ + coeff, poly = cls._preprocess_roots(poly) + roots = [] + + for root in getattr(cls, method)(poly): + roots.append(coeff*cls._postprocess_root(root, radicals)) + + return roots + + @classmethod + def _get_roots_alg(cls, method, poly, radicals): + """Return postprocessed roots of specified kind + for polynomials with algebraic coefficients. It assumes + the domain is already an algebraic field. First it + finds the roots using _get_roots_qq, then uses the + square-free factors to filter roots and get the correct + multiplicity. + """ + + # Existing QQ code can find and sort the roots + roots = cls._get_roots_qq(method, poly.lift(), radicals) + + subroots = {} + for f, m in poly.sqf_list()[1]: + if method == "_real_roots": + roots_filt = f.which_real_roots(roots) + elif method == "_all_roots": + roots_filt = f.which_all_roots(roots) + for r in roots_filt: + subroots[r] = m + + roots_seen = set() + roots_flat = [] + for r in roots: + if r in subroots and r not in roots_seen: + m = subroots[r] + roots_flat.extend([r] * m) + roots_seen.add(r) + + return roots_flat + + @classmethod + def clear_cache(cls): + """Reset cache for reals and complexes. + + The intervals used to approximate a root instance are updated + as needed. When a request is made to see the intervals, the + most current values are shown. `clear_cache` will reset all + CRootOf instances back to their original state. + + See Also + ======== + + _reset + """ + global _reals_cache, _complexes_cache + _reals_cache = _pure_key_dict() + _complexes_cache = _pure_key_dict() + + def _get_interval(self): + """Internal function for retrieving isolation interval from cache. """ + self._ensure_reals_init() + if self.is_real: + return _reals_cache[self.poly][self.index] + else: + reals_count = len(_reals_cache[self.poly]) + self._ensure_complexes_init() + return _complexes_cache[self.poly][self.index - reals_count] + + def _set_interval(self, interval): + """Internal function for updating isolation interval in cache. """ + self._ensure_reals_init() + if self.is_real: + _reals_cache[self.poly][self.index] = interval + else: + reals_count = len(_reals_cache[self.poly]) + self._ensure_complexes_init() + _complexes_cache[self.poly][self.index - reals_count] = interval + + def _eval_subs(self, old, new): + # don't allow subs to change anything + return self + + def _eval_conjugate(self): + if self.is_real: + return self + expr, i = self.args + return self.func(expr, i + (1 if self._get_interval().conj else -1)) + + def eval_approx(self, n, return_mpmath=False): + """Evaluate this complex root to the given precision. + + This uses secant method and root bounds are used to both + generate an initial guess and to check that the root + returned is valid. If ever the method converges outside the + root bounds, the bounds will be made smaller and updated. + """ + prec = dps_to_prec(n) + with workprec(prec): + g = self.poly.gen + if not g.is_Symbol: + d = Dummy('x') + if self.is_imaginary: + d *= I + func = lambdify(d, self.expr.subs(g, d)) + else: + expr = self.expr + if self.is_imaginary: + expr = self.expr.subs(g, I*g) + func = lambdify(g, expr) + + interval = self._get_interval() + while True: + if self.is_real: + a = mpf(str(interval.a)) + b = mpf(str(interval.b)) + if a == b: + root = a + break + x0 = mpf(str(interval.center)) + x1 = x0 + mpf(str(interval.dx))/4 + elif self.is_imaginary: + a = mpf(str(interval.ay)) + b = mpf(str(interval.by)) + if a == b: + root = mpc(mpf('0'), a) + break + x0 = mpf(str(interval.center[1])) + x1 = x0 + mpf(str(interval.dy))/4 + else: + ax = mpf(str(interval.ax)) + bx = mpf(str(interval.bx)) + ay = mpf(str(interval.ay)) + by = mpf(str(interval.by)) + if ax == bx and ay == by: + root = mpc(ax, ay) + break + x0 = mpc(*map(str, interval.center)) + x1 = x0 + mpc(*map(str, (interval.dx, interval.dy)))/4 + try: + # without a tolerance, this will return when (to within + # the given precision) x_i == x_{i-1} + root = findroot(func, (x0, x1)) + # If the (real or complex) root is not in the 'interval', + # then keep refining the interval. This happens if findroot + # accidentally finds a different root outside of this + # interval because our initial estimate 'x0' was not close + # enough. It is also possible that the secant method will + # get trapped by a max/min in the interval; the root + # verification by findroot will raise a ValueError in this + # case and the interval will then be tightened -- and + # eventually the root will be found. + # + # It is also possible that findroot will not have any + # successful iterations to process (in which case it + # will fail to initialize a variable that is tested + # after the iterations and raise an UnboundLocalError). + if self.is_real or self.is_imaginary: + if not bool(root.imag) == self.is_real and ( + a <= root <= b): + if self.is_imaginary: + root = mpc(mpf('0'), root.real) + break + elif (ax <= root.real <= bx and ay <= root.imag <= by): + break + except (UnboundLocalError, ValueError): + pass + interval = interval.refine() + + # update the interval so we at least (for this precision or + # less) don't have much work to do to recompute the root + self._set_interval(interval) + if return_mpmath: + return root + return (Float._new(root.real._mpf_, prec) + + I*Float._new(root.imag._mpf_, prec)) + + def _eval_evalf(self, prec, **kwargs): + """Evaluate this complex root to the given precision.""" + # all kwargs are ignored + return self.eval_rational(n=prec_to_dps(prec))._evalf(prec) + + def eval_rational(self, dx=None, dy=None, n=15): + """ + Return a Rational approximation of ``self`` that has real + and imaginary component approximations that are within ``dx`` + and ``dy`` of the true values, respectively. Alternatively, + ``n`` digits of precision can be specified. + + The interval is refined with bisection and is sure to + converge. The root bounds are updated when the refinement + is complete so recalculation at the same or lesser precision + will not have to repeat the refinement and should be much + faster. + + The following example first obtains Rational approximation to + 1e-8 accuracy for all roots of the 4-th order Legendre + polynomial. Since the roots are all less than 1, this will + ensure the decimal representation of the approximation will be + correct (including rounding) to 6 digits: + + >>> from sympy import legendre_poly, Symbol + >>> x = Symbol("x") + >>> p = legendre_poly(4, x, polys=True) + >>> r = p.real_roots()[-1] + >>> r.eval_rational(10**-8).n(6) + 0.861136 + + It is not necessary to a two-step calculation, however: the + decimal representation can be computed directly: + + >>> r.evalf(17) + 0.86113631159405258 + + """ + dy = dy or dx + if dx: + rtol = None + dx = dx if isinstance(dx, Rational) else Rational(str(dx)) + dy = dy if isinstance(dy, Rational) else Rational(str(dy)) + else: + # 5 binary (or 2 decimal) digits are needed to ensure that + # a given digit is correctly rounded + # prec_to_dps(dps_to_prec(n) + 5) - n <= 2 (tested for + # n in range(1000000) + rtol = S(10)**-(n + 2) # +2 for guard digits + interval = self._get_interval() + while True: + if self.is_real: + if rtol: + dx = abs(interval.center*rtol) + interval = interval.refine_size(dx=dx) + c = interval.center + real = Rational(c) + imag = S.Zero + if not rtol or interval.dx < abs(c*rtol): + break + elif self.is_imaginary: + if rtol: + dy = abs(interval.center[1]*rtol) + dx = 1 + interval = interval.refine_size(dx=dx, dy=dy) + c = interval.center[1] + imag = Rational(c) + real = S.Zero + if not rtol or interval.dy < abs(c*rtol): + break + else: + if rtol: + dx = abs(interval.center[0]*rtol) + dy = abs(interval.center[1]*rtol) + interval = interval.refine_size(dx, dy) + c = interval.center + real, imag = map(Rational, c) + if not rtol or ( + interval.dx < abs(c[0]*rtol) and + interval.dy < abs(c[1]*rtol)): + break + + # update the interval so we at least (for this precision or + # less) don't have much work to do to recompute the root + self._set_interval(interval) + return real + I*imag + + +CRootOf = ComplexRootOf + + +@dispatch(ComplexRootOf, ComplexRootOf) +def _eval_is_eq(lhs, rhs): # noqa:F811 + # if we use is_eq to check here, we get infinite recursion + return lhs == rhs + + +@dispatch(ComplexRootOf, Basic) # type:ignore +def _eval_is_eq(lhs, rhs): # noqa:F811 + # CRootOf represents a Root, so if rhs is that root, it should set + # the expression to zero *and* it should be in the interval of the + # CRootOf instance. It must also be a number that agrees with the + # is_real value of the CRootOf instance. + if not rhs.is_number: + return None + if not rhs.is_finite: + return False + z = lhs.expr.subs(lhs.expr.free_symbols.pop(), rhs).is_zero + if z is False: # all roots will make z True but we don't know + # whether this is the right root if z is True + return False + o = rhs.is_real, rhs.is_imaginary + s = lhs.is_real, lhs.is_imaginary + assert None not in s # this is part of initial refinement + if o != s and None not in o: + return False + re, im = rhs.as_real_imag() + if lhs.is_real: + if im: + return False + i = lhs._get_interval() + a, b = [Rational(str(_)) for _ in (i.a, i.b)] + return sympify(a <= rhs and rhs <= b) + i = lhs._get_interval() + r1, r2, i1, i2 = [Rational(str(j)) for j in ( + i.ax, i.bx, i.ay, i.by)] + return is_le(r1, re) and is_le(re,r2) and is_le(i1,im) and is_le(im,i2) + + +@public +class RootSum(Expr): + """Represents a sum of all roots of a univariate polynomial. """ + + __slots__ = ('poly', 'fun', 'auto') + + def __new__(cls, expr, func=None, x=None, auto=True, quadratic=False): + """Construct a new ``RootSum`` instance of roots of a polynomial.""" + coeff, poly = cls._transform(expr, x) + + if not poly.is_univariate: + raise MultivariatePolynomialError( + "only univariate polynomials are allowed") + + if func is None: + func = Lambda(poly.gen, poly.gen) + else: + is_func = getattr(func, 'is_Function', False) + + if is_func and 1 in func.nargs: + if not isinstance(func, Lambda): + func = Lambda(poly.gen, func(poly.gen)) + else: + raise ValueError( + "expected a univariate function, got %s" % func) + + var, expr = func.variables[0], func.expr + + if coeff is not S.One: + expr = expr.subs(var, coeff*var) + + deg = poly.degree() + + if not expr.has(var): + return deg*expr + + if expr.is_Add: + add_const, expr = expr.as_independent(var) + else: + add_const = S.Zero + + if expr.is_Mul: + mul_const, expr = expr.as_independent(var) + else: + mul_const = S.One + + func = Lambda(var, expr) + + rational = cls._is_func_rational(poly, func) + factors, terms = _pure_factors(poly), [] + + for poly, k in factors: + if poly.is_linear: + term = func(roots_linear(poly)[0]) + elif quadratic and poly.is_quadratic: + term = sum(map(func, roots_quadratic(poly))) + else: + if not rational or not auto: + term = cls._new(poly, func, auto) + else: + term = cls._rational_case(poly, func) + + terms.append(k*term) + + return mul_const*Add(*terms) + deg*add_const + + @classmethod + def _new(cls, poly, func, auto=True): + """Construct new raw ``RootSum`` instance. """ + obj = Expr.__new__(cls) + + obj.poly = poly + obj.fun = func + obj.auto = auto + + return obj + + @classmethod + def new(cls, poly, func, auto=True): + """Construct new ``RootSum`` instance. """ + if not func.expr.has(*func.variables): + return func.expr + + rational = cls._is_func_rational(poly, func) + + if not rational or not auto: + return cls._new(poly, func, auto) + else: + return cls._rational_case(poly, func) + + @classmethod + def _transform(cls, expr, x): + """Transform an expression to a polynomial. """ + poly = PurePoly(expr, x, greedy=False) + return preprocess_roots(poly) + + @classmethod + def _is_func_rational(cls, poly, func): + """Check if a lambda is a rational function. """ + var, expr = func.variables[0], func.expr + return expr.is_rational_function(var) + + @classmethod + def _rational_case(cls, poly, func): + """Handle the rational function case. """ + roots = symbols('r:%d' % poly.degree()) + var, expr = func.variables[0], func.expr + + f = sum(expr.subs(var, r) for r in roots) + p, q = together(f).as_numer_denom() + + domain = QQ[roots] + + p = p.expand() + q = q.expand() + + try: + p = Poly(p, domain=domain, expand=False) + except GeneratorsNeeded: + p, p_coeff = None, (p,) + else: + p_monom, p_coeff = zip(*p.terms()) + + try: + q = Poly(q, domain=domain, expand=False) + except GeneratorsNeeded: + q, q_coeff = None, (q,) + else: + q_monom, q_coeff = zip(*q.terms()) + + coeffs, mapping = symmetrize(p_coeff + q_coeff, formal=True) + formulas, values = viete(poly, roots), [] + + for (sym, _), (_, val) in zip(mapping, formulas): + values.append((sym, val)) + + for i, (coeff, _) in enumerate(coeffs): + coeffs[i] = coeff.subs(values) + + n = len(p_coeff) + + p_coeff = coeffs[:n] + q_coeff = coeffs[n:] + + if p is not None: + p = Poly(dict(zip(p_monom, p_coeff)), *p.gens).as_expr() + else: + (p,) = p_coeff + + if q is not None: + q = Poly(dict(zip(q_monom, q_coeff)), *q.gens).as_expr() + else: + (q,) = q_coeff + + return factor(p/q) + + def _hashable_content(self): + return (self.poly, self.fun) + + @property + def expr(self): + return self.poly.as_expr() + + @property + def args(self): + return (self.expr, self.fun, self.poly.gen) + + @property + def free_symbols(self): + return self.poly.free_symbols | self.fun.free_symbols + + @property + def is_commutative(self): + return True + + def doit(self, **hints): + if not hints.get('roots', True): + return self + + _roots = roots(self.poly, multiple=True) + + if len(_roots) < self.poly.degree(): + return self + else: + return Add(*[self.fun(r) for r in _roots]) + + def _eval_evalf(self, prec): + try: + _roots = self.poly.nroots(n=prec_to_dps(prec)) + except (DomainError, PolynomialError): + return self + else: + return Add(*[self.fun(r) for r in _roots]) + + def _eval_derivative(self, x): + var, expr = self.fun.args + func = Lambda(var, expr.diff(x)) + return self.new(self.poly, func, self.auto) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/solvers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/solvers.py new file mode 100644 index 0000000000000000000000000000000000000000..b333e81d975a8cd71e7eb683c2b943d8538f6ac5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/solvers.py @@ -0,0 +1,435 @@ +"""Low-level linear systems solver. """ + + +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import connected_components + +from sympy.core.sympify import sympify +from sympy.core.numbers import Integer, Rational +from sympy.matrices.dense import MutableDenseMatrix +from sympy.polys.domains import ZZ, QQ + +from sympy.polys.domains import EX +from sympy.polys.rings import sring +from sympy.polys.polyerrors import NotInvertible +from sympy.polys.domainmatrix import DomainMatrix + + +class PolyNonlinearError(Exception): + """Raised by solve_lin_sys for nonlinear equations""" + pass + + +class RawMatrix(MutableDenseMatrix): + """ + .. deprecated:: 1.9 + + This class fundamentally is broken by design. Use ``DomainMatrix`` if + you want a matrix over the polys domains or ``Matrix`` for a matrix + with ``Expr`` elements. The ``RawMatrix`` class will be removed/broken + in future in order to reestablish the invariant that the elements of a + Matrix should be of type ``Expr``. + + """ + _sympify = staticmethod(lambda x, *args, **kwargs: x) + + def __init__(self, *args, **kwargs): + sympy_deprecation_warning( + """ + The RawMatrix class is deprecated. Use either DomainMatrix or + Matrix instead. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-rawmatrix", + ) + + domain = ZZ + for i in range(self.rows): + for j in range(self.cols): + val = self[i,j] + if getattr(val, 'is_Poly', False): + K = val.domain[val.gens] + val_sympy = val.as_expr() + elif hasattr(val, 'parent'): + K = val.parent() + val_sympy = K.to_sympy(val) + elif isinstance(val, (int, Integer)): + K = ZZ + val_sympy = sympify(val) + elif isinstance(val, Rational): + K = QQ + val_sympy = val + else: + for K in ZZ, QQ: + if K.of_type(val): + val_sympy = K.to_sympy(val) + break + else: + raise TypeError + domain = domain.unify(K) + self[i,j] = val_sympy + self.ring = domain + + +def eqs_to_matrix(eqs_coeffs, eqs_rhs, gens, domain): + """Get matrix from linear equations in dict format. + + Explanation + =========== + + Get the matrix representation of a system of linear equations represented + as dicts with low-level DomainElement coefficients. This is an + *internal* function that is used by solve_lin_sys. + + Parameters + ========== + + eqs_coeffs: list[dict[Symbol, DomainElement]] + The left hand sides of the equations as dicts mapping from symbols to + coefficients where the coefficients are instances of + DomainElement. + eqs_rhs: list[DomainElements] + The right hand sides of the equations as instances of + DomainElement. + gens: list[Symbol] + The unknowns in the system of equations. + domain: Domain + The domain for coefficients of both lhs and rhs. + + Returns + ======= + + The augmented matrix representation of the system as a DomainMatrix. + + Examples + ======== + + >>> from sympy import symbols, ZZ + >>> from sympy.polys.solvers import eqs_to_matrix + >>> x, y = symbols('x, y') + >>> eqs_coeff = [{x:ZZ(1), y:ZZ(1)}, {x:ZZ(1), y:ZZ(-1)}] + >>> eqs_rhs = [ZZ(0), ZZ(-1)] + >>> eqs_to_matrix(eqs_coeff, eqs_rhs, [x, y], ZZ) + DomainMatrix([[1, 1, 0], [1, -1, 1]], (2, 3), ZZ) + + See also + ======== + + solve_lin_sys: Uses :func:`~eqs_to_matrix` internally + """ + sym2index = {x: n for n, x in enumerate(gens)} + nrows = len(eqs_coeffs) + ncols = len(gens) + 1 + rows = [[domain.zero] * ncols for _ in range(nrows)] + for row, eq_coeff, eq_rhs in zip(rows, eqs_coeffs, eqs_rhs): + for sym, coeff in eq_coeff.items(): + row[sym2index[sym]] = domain.convert(coeff) + row[-1] = -domain.convert(eq_rhs) + + return DomainMatrix(rows, (nrows, ncols), domain) + + +def sympy_eqs_to_ring(eqs, symbols): + """Convert a system of equations from Expr to a PolyRing + + Explanation + =========== + + High-level functions like ``solve`` expect Expr as inputs but can use + ``solve_lin_sys`` internally. This function converts equations from + ``Expr`` to the low-level poly types used by the ``solve_lin_sys`` + function. + + Parameters + ========== + + eqs: List of Expr + A list of equations as Expr instances + symbols: List of Symbol + A list of the symbols that are the unknowns in the system of + equations. + + Returns + ======= + + Tuple[List[PolyElement], Ring]: The equations as PolyElement instances + and the ring of polynomials within which each equation is represented. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.polys.solvers import sympy_eqs_to_ring + >>> a, x, y = symbols('a, x, y') + >>> eqs = [x-y, x+a*y] + >>> eqs_ring, ring = sympy_eqs_to_ring(eqs, [x, y]) + >>> eqs_ring + [x - y, x + a*y] + >>> type(eqs_ring[0]) + + >>> ring + ZZ(a)[x,y] + + With the equations in this form they can be passed to ``solve_lin_sys``: + + >>> from sympy.polys.solvers import solve_lin_sys + >>> solve_lin_sys(eqs_ring, ring) + {y: 0, x: 0} + """ + try: + K, eqs_K = sring(eqs, symbols, field=True, extension=True) + except NotInvertible: + # https://github.com/sympy/sympy/issues/18874 + K, eqs_K = sring(eqs, symbols, domain=EX) + return eqs_K, K.to_domain() + + +def solve_lin_sys(eqs, ring, _raw=True): + """Solve a system of linear equations from a PolynomialRing + + Explanation + =========== + + Solves a system of linear equations given as PolyElement instances of a + PolynomialRing. The basic arithmetic is carried out using instance of + DomainElement which is more efficient than :class:`~sympy.core.expr.Expr` + for the most common inputs. + + While this is a public function it is intended primarily for internal use + so its interface is not necessarily convenient. Users are suggested to use + the :func:`sympy.solvers.solveset.linsolve` function (which uses this + function internally) instead. + + Parameters + ========== + + eqs: list[PolyElement] + The linear equations to be solved as elements of a + PolynomialRing (assumed equal to zero). + ring: PolynomialRing + The polynomial ring from which eqs are drawn. The generators of this + ring are the unknowns to be solved for and the domain of the ring is + the domain of the coefficients of the system of equations. + _raw: bool + If *_raw* is False, the keys and values in the returned dictionary + will be of type Expr (and the unit of the field will be removed from + the keys) otherwise the low-level polys types will be returned, e.g. + PolyElement: PythonRational. + + Returns + ======= + + ``None`` if the system has no solution. + + dict[Symbol, Expr] if _raw=False + + dict[Symbol, DomainElement] if _raw=True. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.polys.solvers import solve_lin_sys, sympy_eqs_to_ring + >>> x, y = symbols('x, y') + >>> eqs = [x - y, x + y - 2] + >>> eqs_ring, ring = sympy_eqs_to_ring(eqs, [x, y]) + >>> solve_lin_sys(eqs_ring, ring) + {y: 1, x: 1} + + Passing ``_raw=False`` returns the same result except that the keys are + ``Expr`` rather than low-level poly types. + + >>> solve_lin_sys(eqs_ring, ring, _raw=False) + {x: 1, y: 1} + + See also + ======== + + sympy_eqs_to_ring: prepares the inputs to ``solve_lin_sys``. + linsolve: ``linsolve`` uses ``solve_lin_sys`` internally. + sympy.solvers.solvers.solve: ``solve`` uses ``solve_lin_sys`` internally. + """ + as_expr = not _raw + + assert ring.domain.is_Field + + eqs_dict = [dict(eq) for eq in eqs] + + one_monom = ring.one.monoms()[0] + zero = ring.domain.zero + + eqs_rhs = [] + eqs_coeffs = [] + for eq_dict in eqs_dict: + eq_rhs = eq_dict.pop(one_monom, zero) + eq_coeffs = {} + for monom, coeff in eq_dict.items(): + if sum(monom) != 1: + msg = "Nonlinear term encountered in solve_lin_sys" + raise PolyNonlinearError(msg) + eq_coeffs[ring.gens[monom.index(1)]] = coeff + if not eq_coeffs: + if not eq_rhs: + continue + else: + return None + eqs_rhs.append(eq_rhs) + eqs_coeffs.append(eq_coeffs) + + result = _solve_lin_sys(eqs_coeffs, eqs_rhs, ring) + + if result is not None and as_expr: + + def to_sympy(x): + as_expr = getattr(x, 'as_expr', None) + if as_expr: + return as_expr() + else: + return ring.domain.to_sympy(x) + + tresult = {to_sympy(sym): to_sympy(val) for sym, val in result.items()} + + # Remove 1.0x + result = {} + for k, v in tresult.items(): + if k.is_Mul: + c, s = k.as_coeff_Mul() + result[s] = v/c + else: + result[k] = v + + return result + + +def _solve_lin_sys(eqs_coeffs, eqs_rhs, ring): + """Solve a linear system from dict of PolynomialRing coefficients + + Explanation + =========== + + This is an **internal** function used by :func:`solve_lin_sys` after the + equations have been preprocessed. The role of this function is to split + the system into connected components and pass those to + :func:`_solve_lin_sys_component`. + + Examples + ======== + + Setup a system for $x-y=0$ and $x+y=2$ and solve: + + >>> from sympy import symbols, sring + >>> from sympy.polys.solvers import _solve_lin_sys + >>> x, y = symbols('x, y') + >>> R, (xr, yr) = sring([x, y], [x, y]) + >>> eqs = [{xr:R.one, yr:-R.one}, {xr:R.one, yr:R.one}] + >>> eqs_rhs = [R.zero, -2*R.one] + >>> _solve_lin_sys(eqs, eqs_rhs, R) + {y: 1, x: 1} + + See also + ======== + + solve_lin_sys: This function is used internally by :func:`solve_lin_sys`. + """ + V = ring.gens + E = [] + for eq_coeffs in eqs_coeffs: + syms = list(eq_coeffs) + E.extend(zip(syms[:-1], syms[1:])) + G = V, E + + components = connected_components(G) + + sym2comp = {} + for n, component in enumerate(components): + for sym in component: + sym2comp[sym] = n + + subsystems = [([], []) for _ in range(len(components))] + for eq_coeff, eq_rhs in zip(eqs_coeffs, eqs_rhs): + sym = next(iter(eq_coeff), None) + sub_coeff, sub_rhs = subsystems[sym2comp[sym]] + sub_coeff.append(eq_coeff) + sub_rhs.append(eq_rhs) + + sol = {} + for subsystem in subsystems: + subsol = _solve_lin_sys_component(subsystem[0], subsystem[1], ring) + if subsol is None: + return None + sol.update(subsol) + + return sol + + +def _solve_lin_sys_component(eqs_coeffs, eqs_rhs, ring): + """Solve a linear system from dict of PolynomialRing coefficients + + Explanation + =========== + + This is an **internal** function used by :func:`solve_lin_sys` after the + equations have been preprocessed. After :func:`_solve_lin_sys` splits the + system into connected components this function is called for each + component. The system of equations is solved using Gauss-Jordan + elimination with division followed by back-substitution. + + Examples + ======== + + Setup a system for $x-y=0$ and $x+y=2$ and solve: + + >>> from sympy import symbols, sring + >>> from sympy.polys.solvers import _solve_lin_sys_component + >>> x, y = symbols('x, y') + >>> R, (xr, yr) = sring([x, y], [x, y]) + >>> eqs = [{xr:R.one, yr:-R.one}, {xr:R.one, yr:R.one}] + >>> eqs_rhs = [R.zero, -2*R.one] + >>> _solve_lin_sys_component(eqs, eqs_rhs, R) + {y: 1, x: 1} + + See also + ======== + + solve_lin_sys: This function is used internally by :func:`solve_lin_sys`. + """ + + # transform from equations to matrix form + matrix = eqs_to_matrix(eqs_coeffs, eqs_rhs, ring.gens, ring.domain) + + # convert to a field for rref + if not matrix.domain.is_Field: + matrix = matrix.to_field() + + # solve by row-reduction + echelon, pivots = matrix.rref() + + # construct the returnable form of the solutions + keys = ring.gens + + if pivots and pivots[-1] == len(keys): + return None + + if len(pivots) == len(keys): + sol = [] + for s in [row[-1] for row in echelon.rep.to_ddm()]: + a = s + sol.append(a) + sols = dict(zip(keys, sol)) + else: + sols = {} + g = ring.gens + # Extract ground domain coefficients and convert to the ring: + if hasattr(ring, 'ring'): + convert = ring.ring.ground_new + else: + convert = ring.ground_new + echelon = echelon.rep.to_ddm() + vals_set = {v for row in echelon for v in row} + vals_map = {v: convert(v) for v in vals_set} + echelon = [[vals_map[eij] for eij in ei] for ei in echelon] + for i, p in enumerate(pivots): + v = echelon[i][-1] - sum(echelon[i][j]*g[j] for j in range(p+1, len(g)) if echelon[i][j]) + sols[keys[p]] = v + + return sols diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/specialpolys.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/specialpolys.py new file mode 100644 index 0000000000000000000000000000000000000000..3e85de8679cda3084f1c263a045f4d8f817bed98 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/specialpolys.py @@ -0,0 +1,340 @@ +"""Functions for generating interesting polynomials, e.g. for benchmarking. """ + + +from sympy.core import Add, Mul, Symbol, sympify, Dummy, symbols +from sympy.core.containers import Tuple +from sympy.core.singleton import S +from sympy.ntheory import nextprime +from sympy.polys.densearith import ( + dmp_add_term, dmp_neg, dmp_mul, dmp_sqr +) +from sympy.polys.densebasic import ( + dmp_zero, dmp_one, dmp_ground, + dup_from_raw_dict, dmp_raise, dup_random +) +from sympy.polys.domains import ZZ +from sympy.polys.factortools import dup_zz_cyclotomic_poly +from sympy.polys.polyclasses import DMP +from sympy.polys.polytools import Poly, PurePoly +from sympy.polys.polyutils import _analyze_gens +from sympy.utilities import subsets, public, filldedent + + +@public +def swinnerton_dyer_poly(n, x=None, polys=False): + """Generates n-th Swinnerton-Dyer polynomial in `x`. + + Parameters + ---------- + n : int + `n` decides the order of polynomial + x : optional + polys : bool, optional + ``polys=True`` returns an expression, otherwise + (default) returns an expression. + """ + if n <= 0: + raise ValueError( + "Cannot generate Swinnerton-Dyer polynomial of order %s" % n) + + if x is not None: + sympify(x) + else: + x = Dummy('x') + + if n > 3: + from sympy.functions.elementary.miscellaneous import sqrt + from .numberfields import minimal_polynomial + p = 2 + a = [sqrt(2)] + for i in range(2, n + 1): + p = nextprime(p) + a.append(sqrt(p)) + return minimal_polynomial(Add(*a), x, polys=polys) + + if n == 1: + ex = x**2 - 2 + elif n == 2: + ex = x**4 - 10*x**2 + 1 + elif n == 3: + ex = x**8 - 40*x**6 + 352*x**4 - 960*x**2 + 576 + + return PurePoly(ex, x) if polys else ex + + +@public +def cyclotomic_poly(n, x=None, polys=False): + """Generates cyclotomic polynomial of order `n` in `x`. + + Parameters + ---------- + n : int + `n` decides the order of polynomial + x : optional + polys : bool, optional + ``polys=True`` returns an expression, otherwise + (default) returns an expression. + """ + if n <= 0: + raise ValueError( + "Cannot generate cyclotomic polynomial of order %s" % n) + + poly = DMP(dup_zz_cyclotomic_poly(int(n), ZZ), ZZ) + + if x is not None: + poly = Poly.new(poly, x) + else: + poly = PurePoly.new(poly, Dummy('x')) + + return poly if polys else poly.as_expr() + + +@public +def symmetric_poly(n, *gens, polys=False): + """ + Generates symmetric polynomial of order `n`. + + Parameters + ========== + + polys: bool, optional (default: False) + Returns a Poly object when ``polys=True``, otherwise + (default) returns an expression. + """ + gens = _analyze_gens(gens) + + if n < 0 or n > len(gens) or not gens: + raise ValueError("Cannot generate symmetric polynomial of order %s for %s" % (n, gens)) + elif not n: + poly = S.One + else: + poly = Add(*[Mul(*s) for s in subsets(gens, int(n))]) + + return Poly(poly, *gens) if polys else poly + + +@public +def random_poly(x, n, inf, sup, domain=ZZ, polys=False): + """Generates a polynomial of degree ``n`` with coefficients in + ``[inf, sup]``. + + Parameters + ---------- + x + `x` is the independent term of polynomial + n : int + `n` decides the order of polynomial + inf + Lower limit of range in which coefficients lie + sup + Upper limit of range in which coefficients lie + domain : optional + Decides what ring the coefficients are supposed + to belong. Default is set to Integers. + polys : bool, optional + ``polys=True`` returns an expression, otherwise + (default) returns an expression. + """ + poly = Poly(dup_random(n, inf, sup, domain), x, domain=domain) + + return poly if polys else poly.as_expr() + + +@public +def interpolating_poly(n, x, X='x', Y='y'): + """Construct Lagrange interpolating polynomial for ``n`` + data points. If a sequence of values are given for ``X`` and ``Y`` + then the first ``n`` values will be used. + """ + ok = getattr(x, 'free_symbols', None) + + if isinstance(X, str): + X = symbols("%s:%s" % (X, n)) + elif ok and ok & Tuple(*X).free_symbols: + ok = False + + if isinstance(Y, str): + Y = symbols("%s:%s" % (Y, n)) + elif ok and ok & Tuple(*Y).free_symbols: + ok = False + + if not ok: + raise ValueError(filldedent(''' + Expecting symbol for x that does not appear in X or Y. + Use `interpolate(list(zip(X, Y)), x)` instead.''')) + + coeffs = [] + numert = Mul(*[x - X[i] for i in range(n)]) + + for i in range(n): + numer = numert/(x - X[i]) + denom = Mul(*[(X[i] - X[j]) for j in range(n) if i != j]) + coeffs.append(numer/denom) + + return Add(*[coeff*y for coeff, y in zip(coeffs, Y)]) + + +def fateman_poly_F_1(n): + """Fateman's GCD benchmark: trivial GCD """ + Y = [Symbol('y_' + str(i)) for i in range(n + 1)] + + y_0, y_1 = Y[0], Y[1] + + u = y_0 + Add(*Y[1:]) + v = y_0**2 + Add(*[y**2 for y in Y[1:]]) + + F = ((u + 1)*(u + 2)).as_poly(*Y) + G = ((v + 1)*(-3*y_1*y_0**2 + y_1**2 - 1)).as_poly(*Y) + + H = Poly(1, *Y) + + return F, G, H + + +def dmp_fateman_poly_F_1(n, K): + """Fateman's GCD benchmark: trivial GCD """ + u = [K(1), K(0)] + + for i in range(n): + u = [dmp_one(i, K), u] + + v = [K(1), K(0), K(0)] + + for i in range(0, n): + v = [dmp_one(i, K), dmp_zero(i), v] + + m = n - 1 + + U = dmp_add_term(u, dmp_ground(K(1), m), 0, n, K) + V = dmp_add_term(u, dmp_ground(K(2), m), 0, n, K) + + f = [[-K(3), K(0)], [], [K(1), K(0), -K(1)]] + + W = dmp_add_term(v, dmp_ground(K(1), m), 0, n, K) + Y = dmp_raise(f, m, 1, K) + + F = dmp_mul(U, V, n, K) + G = dmp_mul(W, Y, n, K) + + H = dmp_one(n, K) + + return F, G, H + + +def fateman_poly_F_2(n): + """Fateman's GCD benchmark: linearly dense quartic inputs """ + Y = [Symbol('y_' + str(i)) for i in range(n + 1)] + + y_0 = Y[0] + + u = Add(*Y[1:]) + + H = Poly((y_0 + u + 1)**2, *Y) + + F = Poly((y_0 - u - 2)**2, *Y) + G = Poly((y_0 + u + 2)**2, *Y) + + return H*F, H*G, H + + +def dmp_fateman_poly_F_2(n, K): + """Fateman's GCD benchmark: linearly dense quartic inputs """ + u = [K(1), K(0)] + + for i in range(n - 1): + u = [dmp_one(i, K), u] + + m = n - 1 + + v = dmp_add_term(u, dmp_ground(K(2), m - 1), 0, n, K) + + f = dmp_sqr([dmp_one(m, K), dmp_neg(v, m, K)], n, K) + g = dmp_sqr([dmp_one(m, K), v], n, K) + + v = dmp_add_term(u, dmp_one(m - 1, K), 0, n, K) + + h = dmp_sqr([dmp_one(m, K), v], n, K) + + return dmp_mul(f, h, n, K), dmp_mul(g, h, n, K), h + + +def fateman_poly_F_3(n): + """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ + Y = [Symbol('y_' + str(i)) for i in range(n + 1)] + + y_0 = Y[0] + + u = Add(*[y**(n + 1) for y in Y[1:]]) + + H = Poly((y_0**(n + 1) + u + 1)**2, *Y) + + F = Poly((y_0**(n + 1) - u - 2)**2, *Y) + G = Poly((y_0**(n + 1) + u + 2)**2, *Y) + + return H*F, H*G, H + + +def dmp_fateman_poly_F_3(n, K): + """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ + u = dup_from_raw_dict({n + 1: K.one}, K) + + for i in range(0, n - 1): + u = dmp_add_term([u], dmp_one(i, K), n + 1, i + 1, K) + + v = dmp_add_term(u, dmp_ground(K(2), n - 2), 0, n, K) + + f = dmp_sqr( + dmp_add_term([dmp_neg(v, n - 1, K)], dmp_one(n - 1, K), n + 1, n, K), n, K) + g = dmp_sqr(dmp_add_term([v], dmp_one(n - 1, K), n + 1, n, K), n, K) + + v = dmp_add_term(u, dmp_one(n - 2, K), 0, n - 1, K) + + h = dmp_sqr(dmp_add_term([v], dmp_one(n - 1, K), n + 1, n, K), n, K) + + return dmp_mul(f, h, n, K), dmp_mul(g, h, n, K), h + +# A few useful polynomials from Wang's paper ('78). + +from sympy.polys.rings import ring + +def _f_0(): + R, x, y, z = ring("x,y,z", ZZ) + return x**2*y*z**2 + 2*x**2*y*z + 3*x**2*y + 2*x**2 + 3*x + 4*y**2*z**2 + 5*y**2*z + 6*y**2 + y*z**2 + 2*y*z + y + 1 + +def _f_1(): + R, x, y, z = ring("x,y,z", ZZ) + return x**3*y*z + x**2*y**2*z**2 + x**2*y**2 + 20*x**2*y*z + 30*x**2*y + x**2*z**2 + 10*x**2*z + x*y**3*z + 30*x*y**2*z + 20*x*y**2 + x*y*z**3 + 10*x*y*z**2 + x*y*z + 610*x*y + 20*x*z**2 + 230*x*z + 300*x + y**2*z**2 + 10*y**2*z + 30*y*z**2 + 320*y*z + 200*y + 600*z + 6000 + +def _f_2(): + R, x, y, z = ring("x,y,z", ZZ) + return x**5*y**3 + x**5*y**2*z + x**5*y*z**2 + x**5*z**3 + x**3*y**2 + x**3*y*z + 90*x**3*y + 90*x**3*z + x**2*y**2*z - 11*x**2*y**2 + x**2*z**3 - 11*x**2*z**2 + y*z - 11*y + 90*z - 990 + +def _f_3(): + R, x, y, z = ring("x,y,z", ZZ) + return x**5*y**2 + x**4*z**4 + x**4 + x**3*y**3*z + x**3*z + x**2*y**4 + x**2*y**3*z**3 + x**2*y*z**5 + x**2*y*z + x*y**2*z**4 + x*y**2 + x*y*z**7 + x*y*z**3 + x*y*z**2 + y**2*z + y*z**4 + +def _f_4(): + R, x, y, z = ring("x,y,z", ZZ) + return -x**9*y**8*z - x**8*y**5*z**3 - x**7*y**12*z**2 - 5*x**7*y**8 - x**6*y**9*z**4 + x**6*y**7*z**3 + 3*x**6*y**7*z - 5*x**6*y**5*z**2 - x**6*y**4*z**3 + x**5*y**4*z**5 + 3*x**5*y**4*z**3 - x**5*y*z**5 + x**4*y**11*z**4 + 3*x**4*y**11*z**2 - x**4*y**8*z**4 + 5*x**4*y**7*z**2 + 15*x**4*y**7 - 5*x**4*y**4*z**2 + x**3*y**8*z**6 + 3*x**3*y**8*z**4 - x**3*y**5*z**6 + 5*x**3*y**4*z**4 + 15*x**3*y**4*z**2 + x**3*y**3*z**5 + 3*x**3*y**3*z**3 - 5*x**3*y*z**4 + x**2*z**7 + 3*x**2*z**5 + x*y**7*z**6 + 3*x*y**7*z**4 + 5*x*y**3*z**4 + 15*x*y**3*z**2 + y**4*z**8 + 3*y**4*z**6 + 5*z**6 + 15*z**4 + +def _f_5(): + R, x, y, z = ring("x,y,z", ZZ) + return -x**3 - 3*x**2*y + 3*x**2*z - 3*x*y**2 + 6*x*y*z - 3*x*z**2 - y**3 + 3*y**2*z - 3*y*z**2 + z**3 + +def _f_6(): + R, x, y, z, t = ring("x,y,z,t", ZZ) + return 2115*x**4*y + 45*x**3*z**3*t**2 - 45*x**3*t**2 - 423*x*y**4 - 47*x*y**3 + 141*x*y*z**3 + 94*x*y*z*t - 9*y**3*z**3*t**2 + 9*y**3*t**2 - y**2*z**3*t**2 + y**2*t**2 + 3*z**6*t**2 + 2*z**4*t**3 - 3*z**3*t**2 - 2*z*t**3 + +def _w_1(): + R, x, y, z = ring("x,y,z", ZZ) + return 4*x**6*y**4*z**2 + 4*x**6*y**3*z**3 - 4*x**6*y**2*z**4 - 4*x**6*y*z**5 + x**5*y**4*z**3 + 12*x**5*y**3*z - x**5*y**2*z**5 + 12*x**5*y**2*z**2 - 12*x**5*y*z**3 - 12*x**5*z**4 + 8*x**4*y**4 + 6*x**4*y**3*z**2 + 8*x**4*y**3*z - 4*x**4*y**2*z**4 + 4*x**4*y**2*z**3 - 8*x**4*y**2*z**2 - 4*x**4*y*z**5 - 2*x**4*y*z**4 - 8*x**4*y*z**3 + 2*x**3*y**4*z + x**3*y**3*z**3 - x**3*y**2*z**5 - 2*x**3*y**2*z**3 + 9*x**3*y**2*z - 12*x**3*y*z**3 + 12*x**3*y*z**2 - 12*x**3*z**4 + 3*x**3*z**3 + 6*x**2*y**3 - 6*x**2*y**2*z**2 + 8*x**2*y**2*z - 2*x**2*y*z**4 - 8*x**2*y*z**3 + 2*x**2*y*z**2 + 2*x*y**3*z - 2*x*y**2*z**3 - 3*x*y*z + 3*x*z**3 - 2*y**2 + 2*y*z**2 + +def _w_2(): + R, x, y = ring("x,y", ZZ) + return 24*x**8*y**3 + 48*x**8*y**2 + 24*x**7*y**5 - 72*x**7*y**2 + 25*x**6*y**4 + 2*x**6*y**3 + 4*x**6*y + 8*x**6 + x**5*y**6 + x**5*y**3 - 12*x**5 + x**4*y**5 - x**4*y**4 - 2*x**4*y**3 + 292*x**4*y**2 - x**3*y**6 + 3*x**3*y**3 - x**2*y**5 + 12*x**2*y**3 + 48*x**2 - 12*y**3 + +def f_polys(): + return _f_0(), _f_1(), _f_2(), _f_3(), _f_4(), _f_5(), _f_6() + +def w_polys(): + return _w_1(), _w_2() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/sqfreetools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/sqfreetools.py new file mode 100644 index 0000000000000000000000000000000000000000..b2bf434cab542a42c0f7d67058e1a3c01857335d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/sqfreetools.py @@ -0,0 +1,795 @@ +"""Square-free decomposition algorithms and related tools. """ + + +from sympy.polys.densearith import ( + dup_neg, dmp_neg, + dup_sub, dmp_sub, + dup_mul, dmp_mul, + dup_quo, dmp_quo, + dup_mul_ground, dmp_mul_ground) +from sympy.polys.densebasic import ( + dup_strip, + dup_LC, dmp_ground_LC, + dmp_zero_p, + dmp_ground, + dup_degree, dmp_degree, dmp_degree_in, dmp_degree_list, + dmp_raise, dmp_inject, + dup_convert) +from sympy.polys.densetools import ( + dup_diff, dmp_diff, dmp_diff_in, + dup_shift, dmp_shift, + dup_monic, dmp_ground_monic, + dup_primitive, dmp_ground_primitive) +from sympy.polys.euclidtools import ( + dup_inner_gcd, dmp_inner_gcd, + dup_gcd, dmp_gcd, + dmp_resultant, dmp_primitive) +from sympy.polys.galoistools import ( + gf_sqf_list, gf_sqf_part) +from sympy.polys.polyerrors import ( + MultivariatePolynomialError, + DomainError) + + +def _dup_check_degrees(f, result): + """Sanity check the degrees of a computed factorization in K[x].""" + deg = sum(k * dup_degree(fac) for (fac, k) in result) + assert deg == dup_degree(f) + + +def _dmp_check_degrees(f, u, result): + """Sanity check the degrees of a computed factorization in K[X].""" + degs = [0] * (u + 1) + for fac, k in result: + degs_fac = dmp_degree_list(fac, u) + degs = [d1 + k * d2 for d1, d2 in zip(degs, degs_fac)] + assert tuple(degs) == dmp_degree_list(f, u) + + +def dup_sqf_p(f, K): + """ + Return ``True`` if ``f`` is a square-free polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_sqf_p(x**2 - 2*x + 1) + False + >>> R.dup_sqf_p(x**2 - 1) + True + + """ + if not f: + return True + else: + return not dup_degree(dup_gcd(f, dup_diff(f, 1, K), K)) + + +def dmp_sqf_p(f, u, K): + """ + Return ``True`` if ``f`` is a square-free polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_sqf_p(x**2 + 2*x*y + y**2) + False + >>> R.dmp_sqf_p(x**2 + y**2) + True + + """ + if dmp_zero_p(f, u): + return True + + for i in range(u+1): + + fp = dmp_diff_in(f, 1, i, u, K) + + if dmp_zero_p(fp, u): + continue + + gcd = dmp_gcd(f, fp, u, K) + + if dmp_degree_in(gcd, i, u) != 0: + return False + + return True + + +def dup_sqf_norm(f, K): + r""" + Find a shift of `f` in `K[x]` that has square-free norm. + + The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`). + + Returns `(s,g,r)`, such that `g(x)=f(x-sa)`, `r(x)=\text{Norm}(g(x))` and + `r` is a square-free polynomial over `k`. + + Examples + ======== + + We first create the algebraic number field `K=k(a)=\mathbb{Q}(\sqrt{3})` + and rings `K[x]` and `k[x]`: + + >>> from sympy.polys import ring, QQ + >>> from sympy import sqrt + + >>> K = QQ.algebraic_field(sqrt(3)) + >>> R, x = ring("x", K) + >>> _, X = ring("x", QQ) + + We can now find a square free norm for a shift of `f`: + + >>> f = x**2 - 1 + >>> s, g, r = R.dup_sqf_norm(f) + + The choice of shift `s` is arbitrary and the particular values returned for + `g` and `r` are determined by `s`. + + >>> s == 1 + True + >>> g == x**2 - 2*sqrt(3)*x + 2 + True + >>> r == X**4 - 8*X**2 + 4 + True + + The invariants are: + + >>> g == f.shift(-s*K.unit) + True + >>> g.norm() == r + True + >>> r.is_squarefree + True + + Explanation + =========== + + This is part of Trager's algorithm for factorizing polynomials over + algebraic number fields. In particular this function is algorithm + ``sqfr_norm`` from [Trager76]_. + + See Also + ======== + + dmp_sqf_norm: + Analogous function for multivariate polynomials over ``k(a)``. + dmp_norm: + Computes the norm of `f` directly without any shift. + dup_ext_factor: + Function implementing Trager's algorithm that uses this. + sympy.polys.polytools.sqf_norm: + High-level interface for using this function. + """ + if not K.is_Algebraic: + raise DomainError("ground domain must be algebraic") + + s, g = 0, dmp_raise(K.mod.to_list(), 1, 0, K.dom) + + while True: + h, _ = dmp_inject(f, 0, K, front=True) + r = dmp_resultant(g, h, 1, K.dom) + + if dup_sqf_p(r, K.dom): + break + else: + f, s = dup_shift(f, -K.unit, K), s + 1 + + return s, f, r + + +def _dmp_sqf_norm_shifts(f, u, K): + """Generate a sequence of candidate shifts for dmp_sqf_norm.""" + # + # We want to find a minimal shift if possible because shifting high degree + # variables can be expensive e.g. x**10 -> (x + 1)**10. We try a few easy + # cases first before the final infinite loop that is guaranteed to give + # only finitely many bad shifts (see Trager76 for proof of this in the + # univariate case). + # + + # First the trivial shift [0, 0, ...] + n = u + 1 + s0 = [0] * n + yield s0, f + + # Shift in multiples of the generator of the extension field K + a = K.unit + + # Variables of degree > 0 ordered by increasing degree + d = dmp_degree_list(f, u) + var_indices = [i for di, i in sorted(zip(d, range(u+1))) if di > 0] + + # Now try [1, 0, 0, ...], [0, 1, 0, ...] + for i in var_indices: + s1 = s0.copy() + s1[i] = 1 + a1 = [-a*s1i for s1i in s1] + f1 = dmp_shift(f, a1, u, K) + yield s1, f1 + + # Now try [1, 1, 1, ...], [2, 2, 2, ...] + j = 0 + while True: + j += 1 + sj = [j] * n + aj = [-a*j] * n + fj = dmp_shift(f, aj, u, K) + yield sj, fj + + +def dmp_sqf_norm(f, u, K): + r""" + Find a shift of ``f`` in ``K[X]`` that has square-free norm. + + The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`). + + Returns `(s,g,r)`, such that `g(x_1,x_2,\cdots)=f(x_1-s_1 a, x_2 - s_2 a, + \cdots)`, `r(x)=\text{Norm}(g(x))` and `r` is a square-free polynomial over + `k`. + + Examples + ======== + + We first create the algebraic number field `K=k(a)=\mathbb{Q}(i)` and rings + `K[x,y]` and `k[x,y]`: + + >>> from sympy.polys import ring, QQ + >>> from sympy import I + + >>> K = QQ.algebraic_field(I) + >>> R, x, y = ring("x,y", K) + >>> _, X, Y = ring("x,y", QQ) + + We can now find a square free norm for a shift of `f`: + + >>> f = x*y + y**2 + >>> s, g, r = R.dmp_sqf_norm(f) + + The choice of shifts ``s`` is arbitrary and the particular values returned + for ``g`` and ``r`` are determined by ``s``. + + >>> s + [0, 1] + >>> g == x*y - I*x + y**2 - 2*I*y - 1 + True + >>> r == X**2*Y**2 + X**2 + 2*X*Y**3 + 2*X*Y + Y**4 + 2*Y**2 + 1 + True + + The required invariants are: + + >>> g == f.shift_list([-si*K.unit for si in s]) + True + >>> g.norm() == r + True + >>> r.is_squarefree + True + + Explanation + =========== + + This is part of Trager's algorithm for factorizing polynomials over + algebraic number fields. In particular this function is a multivariate + generalization of algorithm ``sqfr_norm`` from [Trager76]_. + + See Also + ======== + + dup_sqf_norm: + Analogous function for univariate polynomials over ``k(a)``. + dmp_norm: + Computes the norm of `f` directly without any shift. + dmp_ext_factor: + Function implementing Trager's algorithm that uses this. + sympy.polys.polytools.sqf_norm: + High-level interface for using this function. + """ + if not u: + s, g, r = dup_sqf_norm(f, K) + return [s], g, r + + if not K.is_Algebraic: + raise DomainError("ground domain must be algebraic") + + g = dmp_raise(K.mod.to_list(), u + 1, 0, K.dom) + + for s, f in _dmp_sqf_norm_shifts(f, u, K): + + h, _ = dmp_inject(f, u, K, front=True) + r = dmp_resultant(g, h, u + 1, K.dom) + + if dmp_sqf_p(r, u, K.dom): + break + + return s, f, r + + +def dmp_norm(f, u, K): + r""" + Norm of ``f`` in ``K[X]``, often not square-free. + + The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`). + + Examples + ======== + + We first define the algebraic number field `K = k(a) = \mathbb{Q}(\sqrt{2})`: + + >>> from sympy import QQ, sqrt + >>> from sympy.polys.sqfreetools import dmp_norm + >>> k = QQ + >>> K = k.algebraic_field(sqrt(2)) + + We can now compute the norm of a polynomial `p` in `K[x,y]`: + + >>> p = [[K(1)], [K(1),K.unit]] # x + y + sqrt(2) + >>> N = [[k(1)], [k(2),k(0)], [k(1),k(0),k(-2)]] # x**2 + 2*x*y + y**2 - 2 + >>> dmp_norm(p, 1, K) == N + True + + In higher level functions that is: + + >>> from sympy import expand, roots, minpoly + >>> from sympy.abc import x, y + >>> from math import prod + >>> a = sqrt(2) + >>> e = (x + y + a) + >>> e.as_poly([x, y], extension=a).norm() + Poly(x**2 + 2*x*y + y**2 - 2, x, y, domain='QQ') + + This is equal to the product of the expressions `x + y + a_i` where the + `a_i` are the conjugates of `a`: + + >>> pa = minpoly(a) + >>> pa + _x**2 - 2 + >>> rs = roots(pa, multiple=True) + >>> rs + [sqrt(2), -sqrt(2)] + >>> n = prod(e.subs(a, r) for r in rs) + >>> n + (x + y - sqrt(2))*(x + y + sqrt(2)) + >>> expand(n) + x**2 + 2*x*y + y**2 - 2 + + Explanation + =========== + + Given an algebraic number field `K = k(a)` any element `b` of `K` can be + represented as polynomial function `b=g(a)` where `g` is in `k[x]`. If the + minimal polynomial of `a` over `k` is `p_a` then the roots `a_1`, `a_2`, + `\cdots` of `p_a(x)` are the conjugates of `a`. The norm of `b` is the + product `g(a1) \times g(a2) \times \cdots` and is an element of `k`. + + As in [Trager76]_ we extend this norm to multivariate polynomials over `K`. + If `b(x)` is a polynomial in `k(a)[X]` then we can think of `b` as being + alternately a function `g_X(a)` where `g_X` is an element of `k[X][y]` i.e. + a polynomial function with coefficients that are elements of `k[X]`. Then + the norm of `b` is the product `g_X(a1) \times g_X(a2) \times \cdots` and + will be an element of `k[X]`. + + See Also + ======== + + dmp_sqf_norm: + Compute a shift of `f` so that the `\text{Norm}(f)` is square-free. + sympy.polys.polytools.Poly.norm: + Higher-level function that calls this. + """ + if not K.is_Algebraic: + raise DomainError("ground domain must be algebraic") + + g = dmp_raise(K.mod.to_list(), u + 1, 0, K.dom) + h, _ = dmp_inject(f, u, K, front=True) + + return dmp_resultant(g, h, u + 1, K.dom) + + +def dup_gf_sqf_part(f, K): + """Compute square-free part of ``f`` in ``GF(p)[x]``. """ + f = dup_convert(f, K, K.dom) + g = gf_sqf_part(f, K.mod, K.dom) + return dup_convert(g, K.dom, K) + + +def dmp_gf_sqf_part(f, u, K): + """Compute square-free part of ``f`` in ``GF(p)[X]``. """ + raise NotImplementedError('multivariate polynomials over finite fields') + + +def dup_sqf_part(f, K): + """ + Returns square-free part of a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_sqf_part(x**3 - 3*x - 2) + x**2 - x - 2 + + See Also + ======== + + sympy.polys.polytools.Poly.sqf_part + """ + if K.is_FiniteField: + return dup_gf_sqf_part(f, K) + + if not f: + return f + + if K.is_negative(dup_LC(f, K)): + f = dup_neg(f, K) + + gcd = dup_gcd(f, dup_diff(f, 1, K), K) + sqf = dup_quo(f, gcd, K) + + if K.is_Field: + return dup_monic(sqf, K) + else: + return dup_primitive(sqf, K)[1] + + +def dmp_sqf_part(f, u, K): + """ + Returns square-free part of a polynomial in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> R.dmp_sqf_part(x**3 + 2*x**2*y + x*y**2) + x**2 + x*y + + """ + if not u: + return dup_sqf_part(f, K) + + if K.is_FiniteField: + return dmp_gf_sqf_part(f, u, K) + + if dmp_zero_p(f, u): + return f + + if K.is_negative(dmp_ground_LC(f, u, K)): + f = dmp_neg(f, u, K) + + gcd = f + for i in range(u+1): + gcd = dmp_gcd(gcd, dmp_diff_in(f, 1, i, u, K), u, K) + sqf = dmp_quo(f, gcd, u, K) + + if K.is_Field: + return dmp_ground_monic(sqf, u, K) + else: + return dmp_ground_primitive(sqf, u, K)[1] + + +def dup_gf_sqf_list(f, K, all=False): + """Compute square-free decomposition of ``f`` in ``GF(p)[x]``. """ + f_orig = f + + f = dup_convert(f, K, K.dom) + + coeff, factors = gf_sqf_list(f, K.mod, K.dom, all=all) + + for i, (f, k) in enumerate(factors): + factors[i] = (dup_convert(f, K.dom, K), k) + + _dup_check_degrees(f_orig, factors) + + return K.convert(coeff, K.dom), factors + + +def dmp_gf_sqf_list(f, u, K, all=False): + """Compute square-free decomposition of ``f`` in ``GF(p)[X]``. """ + raise NotImplementedError('multivariate polynomials over finite fields') + + +def dup_sqf_list(f, K, all=False): + """ + Return square-free decomposition of a polynomial in ``K[x]``. + + Uses Yun's algorithm from [Yun76]_. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 + + >>> R.dup_sqf_list(f) + (2, [(x + 1, 2), (x + 2, 3)]) + >>> R.dup_sqf_list(f, all=True) + (2, [(1, 1), (x + 1, 2), (x + 2, 3)]) + + See Also + ======== + + dmp_sqf_list: + Corresponding function for multivariate polynomials. + sympy.polys.polytools.sqf_list: + High-level function for square-free factorization of expressions. + sympy.polys.polytools.Poly.sqf_list: + Analogous method on :class:`~.Poly`. + + References + ========== + + [Yun76]_ + """ + if K.is_FiniteField: + return dup_gf_sqf_list(f, K, all=all) + + f_orig = f + + if K.is_Field: + coeff = dup_LC(f, K) + f = dup_monic(f, K) + else: + coeff, f = dup_primitive(f, K) + + if K.is_negative(dup_LC(f, K)): + f = dup_neg(f, K) + coeff = -coeff + + if dup_degree(f) <= 0: + return coeff, [] + + result, i = [], 1 + + h = dup_diff(f, 1, K) + g, p, q = dup_inner_gcd(f, h, K) + + while True: + d = dup_diff(p, 1, K) + h = dup_sub(q, d, K) + + if not h: + result.append((p, i)) + break + + g, p, q = dup_inner_gcd(p, h, K) + + if all or dup_degree(g) > 0: + result.append((g, i)) + + i += 1 + + _dup_check_degrees(f_orig, result) + + return coeff, result + + +def dup_sqf_list_include(f, K, all=False): + """ + Return square-free decomposition of a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 + + >>> R.dup_sqf_list_include(f) + [(2, 1), (x + 1, 2), (x + 2, 3)] + >>> R.dup_sqf_list_include(f, all=True) + [(2, 1), (x + 1, 2), (x + 2, 3)] + + """ + coeff, factors = dup_sqf_list(f, K, all=all) + + if factors and factors[0][1] == 1: + g = dup_mul_ground(factors[0][0], coeff, K) + return [(g, 1)] + factors[1:] + else: + g = dup_strip([coeff]) + return [(g, 1)] + factors + + +def dmp_sqf_list(f, u, K, all=False): + """ + Return square-free decomposition of a polynomial in `K[X]`. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x**5 + 2*x**4*y + x**3*y**2 + + >>> R.dmp_sqf_list(f) + (1, [(x + y, 2), (x, 3)]) + >>> R.dmp_sqf_list(f, all=True) + (1, [(1, 1), (x + y, 2), (x, 3)]) + + Explanation + =========== + + Uses Yun's algorithm for univariate polynomials from [Yun76]_ recursively. + The multivariate polynomial is treated as a univariate polynomial in its + leading variable. Then Yun's algorithm computes the square-free + factorization of the primitive and the content is factored recursively. + + It would be better to use a dedicated algorithm for multivariate + polynomials instead. + + See Also + ======== + + dup_sqf_list: + Corresponding function for univariate polynomials. + sympy.polys.polytools.sqf_list: + High-level function for square-free factorization of expressions. + sympy.polys.polytools.Poly.sqf_list: + Analogous method on :class:`~.Poly`. + """ + if not u: + return dup_sqf_list(f, K, all=all) + + if K.is_FiniteField: + return dmp_gf_sqf_list(f, u, K, all=all) + + f_orig = f + + if K.is_Field: + coeff = dmp_ground_LC(f, u, K) + f = dmp_ground_monic(f, u, K) + else: + coeff, f = dmp_ground_primitive(f, u, K) + + if K.is_negative(dmp_ground_LC(f, u, K)): + f = dmp_neg(f, u, K) + coeff = -coeff + + deg = dmp_degree(f, u) + if deg < 0: + return coeff, [] + + # Yun's algorithm requires the polynomial to be primitive as a univariate + # polynomial in its main variable. + content, f = dmp_primitive(f, u, K) + + result = {} + + if deg != 0: + + h = dmp_diff(f, 1, u, K) + g, p, q = dmp_inner_gcd(f, h, u, K) + + i = 1 + + while True: + d = dmp_diff(p, 1, u, K) + h = dmp_sub(q, d, u, K) + + if dmp_zero_p(h, u): + result[i] = p + break + + g, p, q = dmp_inner_gcd(p, h, u, K) + + if all or dmp_degree(g, u) > 0: + result[i] = g + + i += 1 + + coeff_content, result_content = dmp_sqf_list(content, u-1, K, all=all) + + coeff *= coeff_content + + # Combine factors of the content and primitive part that have the same + # multiplicity to produce a list in ascending order of multiplicity. + for fac, i in result_content: + fac = [fac] + if i in result: + result[i] = dmp_mul(result[i], fac, u, K) + else: + result[i] = fac + + result = [(result[i], i) for i in sorted(result)] + + _dmp_check_degrees(f_orig, u, result) + + return coeff, result + + +def dmp_sqf_list_include(f, u, K, all=False): + """ + Return square-free decomposition of a polynomial in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> f = x**5 + 2*x**4*y + x**3*y**2 + + >>> R.dmp_sqf_list_include(f) + [(1, 1), (x + y, 2), (x, 3)] + >>> R.dmp_sqf_list_include(f, all=True) + [(1, 1), (x + y, 2), (x, 3)] + + """ + if not u: + return dup_sqf_list_include(f, K, all=all) + + coeff, factors = dmp_sqf_list(f, u, K, all=all) + + if factors and factors[0][1] == 1: + g = dmp_mul_ground(factors[0][0], coeff, u, K) + return [(g, 1)] + factors[1:] + else: + g = dmp_ground(coeff, u) + return [(g, 1)] + factors + + +def dup_gff_list(f, K): + """ + Compute greatest factorial factorization of ``f`` in ``K[x]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) + + >>> R.dup_gff_list(x**5 + 2*x**4 - x**3 - 2*x**2) + [(x, 1), (x + 2, 4)] + + """ + if not f: + raise ValueError("greatest factorial factorization doesn't exist for a zero polynomial") + + f = dup_monic(f, K) + + if not dup_degree(f): + return [] + else: + g = dup_gcd(f, dup_shift(f, K.one, K), K) + H = dup_gff_list(g, K) + + for i, (h, k) in enumerate(H): + g = dup_mul(g, dup_shift(h, -K(k), K), K) + H[i] = (h, k + 1) + + f = dup_quo(f, g, K) + + if not dup_degree(f): + return H + else: + return [(f, 1)] + H + + +def dmp_gff_list(f, u, K): + """ + Compute greatest factorial factorization of ``f`` in ``K[X]``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + """ + if not u: + return dup_gff_list(f, K) + else: + raise MultivariatePolynomialError(f) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/subresultants_qq_zz.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/subresultants_qq_zz.py new file mode 100644 index 0000000000000000000000000000000000000000..9ce8d5c88d44022621d13d8e82956e676a7e75ae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/subresultants_qq_zz.py @@ -0,0 +1,2558 @@ +""" +This module contains functions for the computation +of Euclidean, (generalized) Sturmian, (modified) subresultant +polynomial remainder sequences (prs's) of two polynomials; +included are also three functions for the computation of the +resultant of two polynomials. + +Except for the function res_z(), which computes the resultant +of two polynomials, the pseudo-remainder function prem() +of sympy is _not_ used by any of the functions in the module. + +Instead of prem() we use the function + +rem_z(). + +Included is also the function quo_z(). + +An explanation of why we avoid prem() can be found in the +references stated in the docstring of rem_z(). + +1. Theoretical background: +========================== +Consider the polynomials f, g in Z[x] of degrees deg(f) = n and +deg(g) = m with n >= m. + +Definition 1: +============= +The sign sequence of a polynomial remainder sequence (prs) is the +sequence of signs of the leading coefficients of its polynomials. + +Sign sequences can be computed with the function: + +sign_seq(poly_seq, x) + +Definition 2: +============= +A polynomial remainder sequence (prs) is called complete if the +degree difference between any two consecutive polynomials is 1; +otherwise, it called incomplete. + +It is understood that f, g belong to the sequences mentioned in +the two definitions above. + +1A. Euclidean and subresultant prs's: +===================================== +The subresultant prs of f, g is a sequence of polynomials in Z[x] +analogous to the Euclidean prs, the sequence obtained by applying +on f, g Euclid's algorithm for polynomial greatest common divisors +(gcd) in Q[x]. + +The subresultant prs differs from the Euclidean prs in that the +coefficients of each polynomial in the former sequence are determinants +--- also referred to as subresultants --- of appropriately selected +sub-matrices of sylvester1(f, g, x), Sylvester's matrix of 1840 of +dimensions (n + m) * (n + m). + +Recall that the determinant of sylvester1(f, g, x) itself is +called the resultant of f, g and serves as a criterion of whether +the two polynomials have common roots or not. + +In SymPy the resultant is computed with the function +resultant(f, g, x). This function does _not_ evaluate the +determinant of sylvester(f, g, x, 1); instead, it returns +the last member of the subresultant prs of f, g, multiplied +(if needed) by an appropriate power of -1; see the caveat below. + +In this module we use three functions to compute the +resultant of f, g: +a) res(f, g, x) computes the resultant by evaluating +the determinant of sylvester(f, g, x, 1); +b) res_q(f, g, x) computes the resultant recursively, by +performing polynomial divisions in Q[x] with the function rem(); +c) res_z(f, g, x) computes the resultant recursively, by +performing polynomial divisions in Z[x] with the function prem(). + +Caveat: If Df = degree(f, x) and Dg = degree(g, x), then: + +resultant(f, g, x) = (-1)**(Df*Dg) * resultant(g, f, x). + +For complete prs's the sign sequence of the Euclidean prs of f, g +is identical to the sign sequence of the subresultant prs of f, g +and the coefficients of one sequence are easily computed from the +coefficients of the other. + +For incomplete prs's the polynomials in the subresultant prs, generally +differ in sign from those of the Euclidean prs, and --- unlike the +case of complete prs's --- it is not at all obvious how to compute +the coefficients of one sequence from the coefficients of the other. + +1B. Sturmian and modified subresultant prs's: +============================================= +For the same polynomials f, g in Z[x] mentioned above, their ``modified'' +subresultant prs is a sequence of polynomials similar to the Sturmian +prs, the sequence obtained by applying in Q[x] Sturm's algorithm on f, g. + +The two sequences differ in that the coefficients of each polynomial +in the modified subresultant prs are the determinants --- also referred +to as modified subresultants --- of appropriately selected sub-matrices +of sylvester2(f, g, x), Sylvester's matrix of 1853 of dimensions 2n x 2n. + +The determinant of sylvester2 itself is called the modified resultant +of f, g and it also can serve as a criterion of whether the two +polynomials have common roots or not. + +For complete prs's the sign sequence of the Sturmian prs of f, g is +identical to the sign sequence of the modified subresultant prs of +f, g and the coefficients of one sequence are easily computed from +the coefficients of the other. + +For incomplete prs's the polynomials in the modified subresultant prs, +generally differ in sign from those of the Sturmian prs, and --- unlike +the case of complete prs's --- it is not at all obvious how to compute +the coefficients of one sequence from the coefficients of the other. + +As Sylvester pointed out, the coefficients of the polynomial remainders +obtained as (modified) subresultants are the smallest possible without +introducing rationals and without computing (integer) greatest common +divisors. + +1C. On terminology: +=================== +Whence the terminology? Well generalized Sturmian prs's are +``modifications'' of Euclidean prs's; the hint came from the title +of the Pell-Gordon paper of 1917. + +In the literature one also encounters the name ``non signed'' and +``signed'' prs for Euclidean and Sturmian prs respectively. + +Likewise ``non signed'' and ``signed'' subresultant prs for +subresultant and modified subresultant prs respectively. + +2. Functions in the module: +=========================== +No function utilizes SymPy's function prem(). + +2A. Matrices: +============= +The functions sylvester(f, g, x, method=1) and +sylvester(f, g, x, method=2) compute either Sylvester matrix. +They can be used to compute (modified) subresultant prs's by +direct determinant evaluation. + +The function bezout(f, g, x, method='prs') provides a matrix of +smaller dimensions than either Sylvester matrix. It is the function +of choice for computing (modified) subresultant prs's by direct +determinant evaluation. + +sylvester(f, g, x, method=1) +sylvester(f, g, x, method=2) +bezout(f, g, x, method='prs') + +The following identity holds: + +bezout(f, g, x, method='prs') = +backward_eye(deg(f))*bezout(f, g, x, method='bz')*backward_eye(deg(f)) + +2B. Subresultant and modified subresultant prs's by +=================================================== +determinant evaluations: +======================= +We use the Sylvester matrices of 1840 and 1853 to +compute, respectively, subresultant and modified +subresultant polynomial remainder sequences. However, +for large matrices this approach takes a lot of time. + +Instead of utilizing the Sylvester matrices, we can +employ the Bezout matrix which is of smaller dimensions. + +subresultants_sylv(f, g, x) +modified_subresultants_sylv(f, g, x) +subresultants_bezout(f, g, x) +modified_subresultants_bezout(f, g, x) + +2C. Subresultant prs's by ONE determinant evaluation: +===================================================== +All three functions in this section evaluate one determinant +per remainder polynomial; this is the determinant of an +appropriately selected sub-matrix of sylvester1(f, g, x), +Sylvester's matrix of 1840. + +To compute the remainder polynomials the function +subresultants_rem(f, g, x) employs rem(f, g, x). +By contrast, the other two functions implement Van Vleck's ideas +of 1900 and compute the remainder polynomials by trinagularizing +sylvester2(f, g, x), Sylvester's matrix of 1853. + + +subresultants_rem(f, g, x) +subresultants_vv(f, g, x) +subresultants_vv_2(f, g, x). + +2E. Euclidean, Sturmian prs's in Q[x]: +====================================== +euclid_q(f, g, x) +sturm_q(f, g, x) + +2F. Euclidean, Sturmian and (modified) subresultant prs's P-G: +============================================================== +All functions in this section are based on the Pell-Gordon (P-G) +theorem of 1917. +Computations are done in Q[x], employing the function rem(f, g, x) +for the computation of the remainder polynomials. + +euclid_pg(f, g, x) +sturm pg(f, g, x) +subresultants_pg(f, g, x) +modified_subresultants_pg(f, g, x) + +2G. Euclidean, Sturmian and (modified) subresultant prs's A-M-V: +================================================================ +All functions in this section are based on the Akritas-Malaschonok- +Vigklas (A-M-V) theorem of 2015. +Computations are done in Z[x], employing the function rem_z(f, g, x) +for the computation of the remainder polynomials. + +euclid_amv(f, g, x) +sturm_amv(f, g, x) +subresultants_amv(f, g, x) +modified_subresultants_amv(f, g, x) + +2Ga. Exception: +=============== +subresultants_amv_q(f, g, x) + +This function employs rem(f, g, x) for the computation of +the remainder polynomials, despite the fact that it implements +the A-M-V Theorem. + +It is included in our module in order to show that theorems P-G +and A-M-V can be implemented utilizing either the function +rem(f, g, x) or the function rem_z(f, g, x). + +For clearly historical reasons --- since the Collins-Brown-Traub +coefficients-reduction factor beta_i was not available in 1917 --- +we have implemented the Pell-Gordon theorem with the function +rem(f, g, x) and the A-M-V Theorem with the function rem_z(f, g, x). + +2H. Resultants: +=============== +res(f, g, x) +res_q(f, g, x) +res_z(f, g, x) +""" + + +from sympy.concrete.summations import summation +from sympy.core.function import expand +from sympy.core.numbers import nan +from sympy.core.singleton import S +from sympy.core.symbol import Dummy as var +from sympy.functions.elementary.complexes import Abs, sign +from sympy.functions.elementary.integers import floor +from sympy.matrices.dense import eye, Matrix, zeros +from sympy.printing.pretty.pretty import pretty_print as pprint +from sympy.simplify.simplify import simplify +from sympy.polys.domains import QQ +from sympy.polys.polytools import degree, LC, Poly, pquo, quo, prem, rem +from sympy.polys.polyerrors import PolynomialError + + +def sylvester(f, g, x, method = 1): + ''' + The input polynomials f, g are in Z[x] or in Q[x]. Let m = degree(f, x), + n = degree(g, x) and mx = max(m, n). + + a. If method = 1 (default), computes sylvester1, Sylvester's matrix of 1840 + of dimension (m + n) x (m + n). The determinants of properly chosen + submatrices of this matrix (a.k.a. subresultants) can be + used to compute the coefficients of the Euclidean PRS of f, g. + + b. If method = 2, computes sylvester2, Sylvester's matrix of 1853 + of dimension (2*mx) x (2*mx). The determinants of properly chosen + submatrices of this matrix (a.k.a. ``modified'' subresultants) can be + used to compute the coefficients of the Sturmian PRS of f, g. + + Applications of these Matrices can be found in the references below. + Especially, for applications of sylvester2, see the first reference!! + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On a Theorem + by Van Vleck Regarding Sturm Sequences. Serdica Journal of Computing, + Vol. 7, No 4, 101-134, 2013. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences + and Modified Subresultant Polynomial Remainder Sequences.'' + Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. + + ''' + # obtain degrees of polys + m, n = degree( Poly(f, x), x), degree( Poly(g, x), x) + + # Special cases: + # A:: case m = n < 0 (i.e. both polys are 0) + if m == n and n < 0: + return Matrix([]) + + # B:: case m = n = 0 (i.e. both polys are constants) + if m == n and n == 0: + return Matrix([]) + + # C:: m == 0 and n < 0 or m < 0 and n == 0 + # (i.e. one poly is constant and the other is 0) + if m == 0 and n < 0: + return Matrix([]) + elif m < 0 and n == 0: + return Matrix([]) + + # D:: m >= 1 and n < 0 or m < 0 and n >=1 + # (i.e. one poly is of degree >=1 and the other is 0) + if m >= 1 and n < 0: + return Matrix([0]) + elif m < 0 and n >= 1: + return Matrix([0]) + + fp = Poly(f, x).all_coeffs() + gp = Poly(g, x).all_coeffs() + + # Sylvester's matrix of 1840 (default; a.k.a. sylvester1) + if method <= 1: + M = zeros(m + n) + k = 0 + for i in range(n): + j = k + for coeff in fp: + M[i, j] = coeff + j = j + 1 + k = k + 1 + k = 0 + for i in range(n, m + n): + j = k + for coeff in gp: + M[i, j] = coeff + j = j + 1 + k = k + 1 + return M + + # Sylvester's matrix of 1853 (a.k.a sylvester2) + else: + if len(fp) < len(gp): + h = [] + for i in range(len(gp) - len(fp)): + h.append(0) + fp[ : 0] = h + else: + h = [] + for i in range(len(fp) - len(gp)): + h.append(0) + gp[ : 0] = h + mx = max(m, n) + dim = 2*mx + M = zeros( dim ) + k = 0 + for i in range( mx ): + j = k + for coeff in fp: + M[2*i, j] = coeff + j = j + 1 + j = k + for coeff in gp: + M[2*i + 1, j] = coeff + j = j + 1 + k = k + 1 + return M + +def process_matrix_output(poly_seq, x): + """ + poly_seq is a polynomial remainder sequence computed either by + (modified_)subresultants_bezout or by (modified_)subresultants_sylv. + + This function removes from poly_seq all zero polynomials as well + as all those whose degree is equal to the degree of a preceding + polynomial in poly_seq, as we scan it from left to right. + + """ + L = poly_seq[:] # get a copy of the input sequence + d = degree(L[1], x) + i = 2 + while i < len(L): + d_i = degree(L[i], x) + if d_i < 0: # zero poly + L.remove(L[i]) + i = i - 1 + if d == d_i: # poly degree equals degree of previous poly + L.remove(L[i]) + i = i - 1 + if d_i >= 0: + d = d_i + i = i + 1 + + return L + +def subresultants_sylv(f, g, x): + """ + The input polynomials f, g are in Z[x] or in Q[x]. It is assumed + that deg(f) >= deg(g). + + Computes the subresultant polynomial remainder sequence (prs) + of f, g by evaluating determinants of appropriately selected + submatrices of sylvester(f, g, x, 1). The dimensions of the + latter are (deg(f) + deg(g)) x (deg(f) + deg(g)). + + Each coefficient is computed by evaluating the determinant of the + corresponding submatrix of sylvester(f, g, x, 1). + + If the subresultant prs is complete, then the output coincides + with the Euclidean sequence of the polynomials f, g. + + References: + =========== + 1. G.M.Diaz-Toca,L.Gonzalez-Vega: Various New Expressions for Subresultants + and Their Applications. Appl. Algebra in Engin., Communic. and Comp., + Vol. 15, 233-266, 2004. + + """ + + # make sure neither f nor g is 0 + if f == 0 or g == 0: + return [f, g] + + n = degF = degree(f, x) + m = degG = degree(g, x) + + # make sure proper degrees + if n == 0 and m == 0: + return [f, g] + if n < m: + n, m, degF, degG, f, g = m, n, degG, degF, g, f + if n > 0 and m == 0: + return [f, g] + + SR_L = [f, g] # subresultant list + + # form matrix sylvester(f, g, x, 1) + S = sylvester(f, g, x, 1) + + # pick appropriate submatrices of S + # and form subresultant polys + j = m - 1 + + while j > 0: + Sp = S[:, :] # copy of S + # delete last j rows of coeffs of g + for ind in range(m + n - j, m + n): + Sp.row_del(m + n - j) + # delete last j rows of coeffs of f + for ind in range(m - j, m): + Sp.row_del(m - j) + + # evaluate determinants and form coefficients list + coeff_L, k, l = [], Sp.rows, 0 + while l <= j: + coeff_L.append(Sp[:, 0:k].det()) + Sp.col_swap(k - 1, k + l) + l += 1 + + # form poly and append to SP_L + SR_L.append(Poly(coeff_L, x).as_expr()) + j -= 1 + + # j = 0 + SR_L.append(S.det()) + + return process_matrix_output(SR_L, x) + +def modified_subresultants_sylv(f, g, x): + """ + The input polynomials f, g are in Z[x] or in Q[x]. It is assumed + that deg(f) >= deg(g). + + Computes the modified subresultant polynomial remainder sequence (prs) + of f, g by evaluating determinants of appropriately selected + submatrices of sylvester(f, g, x, 2). The dimensions of the + latter are (2*deg(f)) x (2*deg(f)). + + Each coefficient is computed by evaluating the determinant of the + corresponding submatrix of sylvester(f, g, x, 2). + + If the modified subresultant prs is complete, then the output coincides + with the Sturmian sequence of the polynomials f, g. + + References: + =========== + 1. A. G. Akritas,G.I. Malaschonok and P.S. Vigklas: + Sturm Sequences and Modified Subresultant Polynomial Remainder + Sequences. Serdica Journal of Computing, Vol. 8, No 1, 29--46, 2014. + + """ + + # make sure neither f nor g is 0 + if f == 0 or g == 0: + return [f, g] + + n = degF = degree(f, x) + m = degG = degree(g, x) + + # make sure proper degrees + if n == 0 and m == 0: + return [f, g] + if n < m: + n, m, degF, degG, f, g = m, n, degG, degF, g, f + if n > 0 and m == 0: + return [f, g] + + SR_L = [f, g] # modified subresultant list + + # form matrix sylvester(f, g, x, 2) + S = sylvester(f, g, x, 2) + + # pick appropriate submatrices of S + # and form modified subresultant polys + j = m - 1 + + while j > 0: + # delete last 2*j rows of pairs of coeffs of f, g + Sp = S[0:2*n - 2*j, :] # copy of first 2*n - 2*j rows of S + + # evaluate determinants and form coefficients list + coeff_L, k, l = [], Sp.rows, 0 + while l <= j: + coeff_L.append(Sp[:, 0:k].det()) + Sp.col_swap(k - 1, k + l) + l += 1 + + # form poly and append to SP_L + SR_L.append(Poly(coeff_L, x).as_expr()) + j -= 1 + + # j = 0 + SR_L.append(S.det()) + + return process_matrix_output(SR_L, x) + +def res(f, g, x): + """ + The input polynomials f, g are in Z[x] or in Q[x]. + + The output is the resultant of f, g computed by evaluating + the determinant of the matrix sylvester(f, g, x, 1). + + References: + =========== + 1. J. S. Cohen: Computer Algebra and Symbolic Computation + - Mathematical Methods. A. K. Peters, 2003. + + """ + if f == 0 or g == 0: + raise PolynomialError("The resultant of %s and %s is not defined" % (f, g)) + else: + return sylvester(f, g, x, 1).det() + +def res_q(f, g, x): + """ + The input polynomials f, g are in Z[x] or in Q[x]. + + The output is the resultant of f, g computed recursively + by polynomial divisions in Q[x], using the function rem. + See Cohen's book p. 281. + + References: + =========== + 1. J. S. Cohen: Computer Algebra and Symbolic Computation + - Mathematical Methods. A. K. Peters, 2003. + """ + m = degree(f, x) + n = degree(g, x) + if m < n: + return (-1)**(m*n) * res_q(g, f, x) + elif n == 0: # g is a constant + return g**m + else: + r = rem(f, g, x) + if r == 0: + return 0 + else: + s = degree(r, x) + l = LC(g, x) + return (-1)**(m*n) * l**(m-s)*res_q(g, r, x) + +def res_z(f, g, x): + """ + The input polynomials f, g are in Z[x] or in Q[x]. + + The output is the resultant of f, g computed recursively + by polynomial divisions in Z[x], using the function prem(). + See Cohen's book p. 283. + + References: + =========== + 1. J. S. Cohen: Computer Algebra and Symbolic Computation + - Mathematical Methods. A. K. Peters, 2003. + """ + m = degree(f, x) + n = degree(g, x) + if m < n: + return (-1)**(m*n) * res_z(g, f, x) + elif n == 0: # g is a constant + return g**m + else: + r = prem(f, g, x) + if r == 0: + return 0 + else: + delta = m - n + 1 + w = (-1)**(m*n) * res_z(g, r, x) + s = degree(r, x) + l = LC(g, x) + k = delta * n - m + s + return quo(w, l**k, x) + +def sign_seq(poly_seq, x): + """ + Given a sequence of polynomials poly_seq, it returns + the sequence of signs of the leading coefficients of + the polynomials in poly_seq. + + """ + return [sign(LC(poly_seq[i], x)) for i in range(len(poly_seq))] + +def bezout(p, q, x, method='bz'): + """ + The input polynomials p, q are in Z[x] or in Q[x]. Let + mx = max(degree(p, x), degree(q, x)). + + The default option bezout(p, q, x, method='bz') returns Bezout's + symmetric matrix of p and q, of dimensions (mx) x (mx). The + determinant of this matrix is equal to the determinant of sylvester2, + Sylvester's matrix of 1853, whose dimensions are (2*mx) x (2*mx); + however the subresultants of these two matrices may differ. + + The other option, bezout(p, q, x, 'prs'), is of interest to us + in this module because it returns a matrix equivalent to sylvester2. + In this case all subresultants of the two matrices are identical. + + Both the subresultant polynomial remainder sequence (prs) and + the modified subresultant prs of p and q can be computed by + evaluating determinants of appropriately selected submatrices of + bezout(p, q, x, 'prs') --- one determinant per coefficient of the + remainder polynomials. + + The matrices bezout(p, q, x, 'bz') and bezout(p, q, x, 'prs') + are related by the formula + + bezout(p, q, x, 'prs') = + backward_eye(deg(p)) * bezout(p, q, x, 'bz') * backward_eye(deg(p)), + + where backward_eye() is the backward identity function. + + References + ========== + 1. G.M.Diaz-Toca,L.Gonzalez-Vega: Various New Expressions for Subresultants + and Their Applications. Appl. Algebra in Engin., Communic. and Comp., + Vol. 15, 233-266, 2004. + + """ + # obtain degrees of polys + m, n = degree( Poly(p, x), x), degree( Poly(q, x), x) + + # Special cases: + # A:: case m = n < 0 (i.e. both polys are 0) + if m == n and n < 0: + return Matrix([]) + + # B:: case m = n = 0 (i.e. both polys are constants) + if m == n and n == 0: + return Matrix([]) + + # C:: m == 0 and n < 0 or m < 0 and n == 0 + # (i.e. one poly is constant and the other is 0) + if m == 0 and n < 0: + return Matrix([]) + elif m < 0 and n == 0: + return Matrix([]) + + # D:: m >= 1 and n < 0 or m < 0 and n >=1 + # (i.e. one poly is of degree >=1 and the other is 0) + if m >= 1 and n < 0: + return Matrix([0]) + elif m < 0 and n >= 1: + return Matrix([0]) + + y = var('y') + + # expr is 0 when x = y + expr = p * q.subs({x:y}) - p.subs({x:y}) * q + + # hence expr is exactly divisible by x - y + poly = Poly( quo(expr, x-y), x, y) + + # form Bezout matrix and store them in B as indicated to get + # the LC coefficient of each poly either in the first position + # of each row (method='prs') or in the last (method='bz'). + mx = max(m, n) + B = zeros(mx) + for i in range(mx): + for j in range(mx): + if method == 'prs': + B[mx - 1 - i, mx - 1 - j] = poly.nth(i, j) + else: + B[i, j] = poly.nth(i, j) + return B + +def backward_eye(n): + ''' + Returns the backward identity matrix of dimensions n x n. + + Needed to "turn" the Bezout matrices + so that the leading coefficients are first. + See docstring of the function bezout(p, q, x, method='bz'). + ''' + M = eye(n) # identity matrix of order n + + for i in range(int(M.rows / 2)): + M.row_swap(0 + i, M.rows - 1 - i) + + return M + +def subresultants_bezout(p, q, x): + """ + The input polynomials p, q are in Z[x] or in Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the subresultant polynomial remainder sequence + of p, q by evaluating determinants of appropriately selected + submatrices of bezout(p, q, x, 'prs'). The dimensions of the + latter are deg(p) x deg(p). + + Each coefficient is computed by evaluating the determinant of the + corresponding submatrix of bezout(p, q, x, 'prs'). + + bezout(p, q, x, 'prs) is used instead of sylvester(p, q, x, 1), + Sylvester's matrix of 1840, because the dimensions of the latter + are (deg(p) + deg(q)) x (deg(p) + deg(q)). + + If the subresultant prs is complete, then the output coincides + with the Euclidean sequence of the polynomials p, q. + + References + ========== + 1. G.M.Diaz-Toca,L.Gonzalez-Vega: Various New Expressions for Subresultants + and Their Applications. Appl. Algebra in Engin., Communic. and Comp., + Vol. 15, 233-266, 2004. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + f, g = p, q + n = degF = degree(f, x) + m = degG = degree(g, x) + + # make sure proper degrees + if n == 0 and m == 0: + return [f, g] + if n < m: + n, m, degF, degG, f, g = m, n, degG, degF, g, f + if n > 0 and m == 0: + return [f, g] + + SR_L = [f, g] # subresultant list + F = LC(f, x)**(degF - degG) + + # form the bezout matrix + B = bezout(f, g, x, 'prs') + + # pick appropriate submatrices of B + # and form subresultant polys + if degF > degG: + j = 2 + if degF == degG: + j = 1 + while j <= degF: + M = B[0:j, :] + k, coeff_L = j - 1, [] + while k <= degF - 1: + coeff_L.append(M[:, 0:j].det()) + if k < degF - 1: + M.col_swap(j - 1, k + 1) + k = k + 1 + + # apply Theorem 2.1 in the paper by Toca & Vega 2004 + # to get correct signs + SR_L.append(int((-1)**(j*(j-1)/2)) * (Poly(coeff_L, x) / F).as_expr()) + j = j + 1 + + return process_matrix_output(SR_L, x) + +def modified_subresultants_bezout(p, q, x): + """ + The input polynomials p, q are in Z[x] or in Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the modified subresultant polynomial remainder sequence + of p, q by evaluating determinants of appropriately selected + submatrices of bezout(p, q, x, 'prs'). The dimensions of the + latter are deg(p) x deg(p). + + Each coefficient is computed by evaluating the determinant of the + corresponding submatrix of bezout(p, q, x, 'prs'). + + bezout(p, q, x, 'prs') is used instead of sylvester(p, q, x, 2), + Sylvester's matrix of 1853, because the dimensions of the latter + are 2*deg(p) x 2*deg(p). + + If the modified subresultant prs is complete, and LC( p ) > 0, the output + coincides with the (generalized) Sturm's sequence of the polynomials p, q. + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences + and Modified Subresultant Polynomial Remainder Sequences.'' + Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. + + 2. G.M.Diaz-Toca,L.Gonzalez-Vega: Various New Expressions for Subresultants + and Their Applications. Appl. Algebra in Engin., Communic. and Comp., + Vol. 15, 233-266, 2004. + + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + f, g = p, q + n = degF = degree(f, x) + m = degG = degree(g, x) + + # make sure proper degrees + if n == 0 and m == 0: + return [f, g] + if n < m: + n, m, degF, degG, f, g = m, n, degG, degF, g, f + if n > 0 and m == 0: + return [f, g] + + SR_L = [f, g] # subresultant list + + # form the bezout matrix + B = bezout(f, g, x, 'prs') + + # pick appropriate submatrices of B + # and form subresultant polys + if degF > degG: + j = 2 + if degF == degG: + j = 1 + while j <= degF: + M = B[0:j, :] + k, coeff_L = j - 1, [] + while k <= degF - 1: + coeff_L.append(M[:, 0:j].det()) + if k < degF - 1: + M.col_swap(j - 1, k + 1) + k = k + 1 + + ## Theorem 2.1 in the paper by Toca & Vega 2004 is _not needed_ + ## in this case since + ## the bezout matrix is equivalent to sylvester2 + SR_L.append(( Poly(coeff_L, x)).as_expr()) + j = j + 1 + + return process_matrix_output(SR_L, x) + +def sturm_pg(p, q, x, method=0): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the (generalized) Sturm sequence of p and q in Z[x] or Q[x]. + If q = diff(p, x, 1) it is the usual Sturm sequence. + + A. If method == 0, default, the remainder coefficients of the sequence + are (in absolute value) ``modified'' subresultants, which for non-monic + polynomials are greater than the coefficients of the corresponding + subresultants by the factor Abs(LC(p)**( deg(p)- deg(q))). + + B. If method == 1, the remainder coefficients of the sequence are (in + absolute value) subresultants, which for non-monic polynomials are + smaller than the coefficients of the corresponding ``modified'' + subresultants by the factor Abs(LC(p)**( deg(p)- deg(q))). + + If the Sturm sequence is complete, method=0 and LC( p ) > 0, the coefficients + of the polynomials in the sequence are ``modified'' subresultants. + That is, they are determinants of appropriately selected submatrices of + sylvester2, Sylvester's matrix of 1853. In this case the Sturm sequence + coincides with the ``modified'' subresultant prs, of the polynomials + p, q. + + If the Sturm sequence is incomplete and method=0 then the signs of the + coefficients of the polynomials in the sequence may differ from the signs + of the coefficients of the corresponding polynomials in the ``modified'' + subresultant prs; however, the absolute values are the same. + + To compute the coefficients, no determinant evaluation takes place. Instead, + polynomial divisions in Q[x] are performed, using the function rem(p, q, x); + the coefficients of the remainders computed this way become (``modified'') + subresultants with the help of the Pell-Gordon Theorem of 1917. + See also the function euclid_pg(p, q, x). + + References + ========== + 1. Pell A. J., R. L. Gordon. The Modified Remainders Obtained in Finding + the Highest Common Factor of Two Polynomials. Annals of MatheMatics, + Second Series, 18 (1917), No. 4, 188-193. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences + and Modified Subresultant Polynomial Remainder Sequences.'' + Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + # make sure proper degrees + d0 = degree(p, x) + d1 = degree(q, x) + if d0 == 0 and d1 == 0: + return [p, q] + if d1 > d0: + d0, d1 = d1, d0 + p, q = q, p + if d0 > 0 and d1 == 0: + return [p,q] + + # make sure LC(p) > 0 + flag = 0 + if LC(p,x) < 0: + flag = 1 + p = -p + q = -q + + # initialize + lcf = LC(p, x)**(d0 - d1) # lcf * subr = modified subr + a0, a1 = p, q # the input polys + sturm_seq = [a0, a1] # the output list + del0 = d0 - d1 # degree difference + rho1 = LC(a1, x) # leading coeff of a1 + exp_deg = d1 - 1 # expected degree of a2 + a2 = - rem(a0, a1, domain=QQ) # first remainder + rho2 = LC(a2,x) # leading coeff of a2 + d2 = degree(a2, x) # actual degree of a2 + deg_diff_new = exp_deg - d2 # expected - actual degree + del1 = d1 - d2 # degree difference + + # mul_fac is the factor by which a2 is multiplied to + # get integer coefficients + mul_fac_old = rho1**(del0 + del1 - deg_diff_new) + + # append accordingly + if method == 0: + sturm_seq.append( simplify(lcf * a2 * Abs(mul_fac_old))) + else: + sturm_seq.append( simplify( a2 * Abs(mul_fac_old))) + + # main loop + deg_diff_old = deg_diff_new + while d2 > 0: + a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees + del0 = del1 # update degree difference + exp_deg = d1 - 1 # new expected degree + a2 = - rem(a0, a1, domain=QQ) # new remainder + rho3 = LC(a2, x) # leading coeff of a2 + d2 = degree(a2, x) # actual degree of a2 + deg_diff_new = exp_deg - d2 # expected - actual degree + del1 = d1 - d2 # degree difference + + # take into consideration the power + # rho1**deg_diff_old that was "left out" + expo_old = deg_diff_old # rho1 raised to this power + expo_new = del0 + del1 - deg_diff_new # rho2 raised to this power + + # update variables and append + mul_fac_new = rho2**(expo_new) * rho1**(expo_old) * mul_fac_old + deg_diff_old, mul_fac_old = deg_diff_new, mul_fac_new + rho1, rho2 = rho2, rho3 + if method == 0: + sturm_seq.append( simplify(lcf * a2 * Abs(mul_fac_old))) + else: + sturm_seq.append( simplify( a2 * Abs(mul_fac_old))) + + if flag: # change the sign of the sequence + sturm_seq = [-i for i in sturm_seq] + + # gcd is of degree > 0 ? + m = len(sturm_seq) + if sturm_seq[m - 1] == nan or sturm_seq[m - 1] == 0: + sturm_seq.pop(m - 1) + + return sturm_seq + +def sturm_q(p, q, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the (generalized) Sturm sequence of p and q in Q[x]. + Polynomial divisions in Q[x] are performed, using the function rem(p, q, x). + + The coefficients of the polynomials in the Sturm sequence can be uniquely + determined from the corresponding coefficients of the polynomials found + either in: + + (a) the ``modified'' subresultant prs, (references 1, 2) + + or in + + (b) the subresultant prs (reference 3). + + References + ========== + 1. Pell A. J., R. L. Gordon. The Modified Remainders Obtained in Finding + the Highest Common Factor of Two Polynomials. Annals of MatheMatics, + Second Series, 18 (1917), No. 4, 188-193. + + 2 Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences + and Modified Subresultant Polynomial Remainder Sequences.'' + Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. + + 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result + on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + # make sure proper degrees + d0 = degree(p, x) + d1 = degree(q, x) + if d0 == 0 and d1 == 0: + return [p, q] + if d1 > d0: + d0, d1 = d1, d0 + p, q = q, p + if d0 > 0 and d1 == 0: + return [p,q] + + # make sure LC(p) > 0 + flag = 0 + if LC(p,x) < 0: + flag = 1 + p = -p + q = -q + + # initialize + a0, a1 = p, q # the input polys + sturm_seq = [a0, a1] # the output list + a2 = -rem(a0, a1, domain=QQ) # first remainder + d2 = degree(a2, x) # degree of a2 + sturm_seq.append( a2 ) + + # main loop + while d2 > 0: + a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees + a2 = -rem(a0, a1, domain=QQ) # new remainder + d2 = degree(a2, x) # actual degree of a2 + sturm_seq.append( a2 ) + + if flag: # change the sign of the sequence + sturm_seq = [-i for i in sturm_seq] + + # gcd is of degree > 0 ? + m = len(sturm_seq) + if sturm_seq[m - 1] == nan or sturm_seq[m - 1] == 0: + sturm_seq.pop(m - 1) + + return sturm_seq + +def sturm_amv(p, q, x, method=0): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the (generalized) Sturm sequence of p and q in Z[x] or Q[x]. + If q = diff(p, x, 1) it is the usual Sturm sequence. + + A. If method == 0, default, the remainder coefficients of the + sequence are (in absolute value) ``modified'' subresultants, which + for non-monic polynomials are greater than the coefficients of the + corresponding subresultants by the factor Abs(LC(p)**( deg(p)- deg(q))). + + B. If method == 1, the remainder coefficients of the sequence are (in + absolute value) subresultants, which for non-monic polynomials are + smaller than the coefficients of the corresponding ``modified'' + subresultants by the factor Abs( LC(p)**( deg(p)- deg(q)) ). + + If the Sturm sequence is complete, method=0 and LC( p ) > 0, then the + coefficients of the polynomials in the sequence are ``modified'' subresultants. + That is, they are determinants of appropriately selected submatrices of + sylvester2, Sylvester's matrix of 1853. In this case the Sturm sequence + coincides with the ``modified'' subresultant prs, of the polynomials + p, q. + + If the Sturm sequence is incomplete and method=0 then the signs of the + coefficients of the polynomials in the sequence may differ from the signs + of the coefficients of the corresponding polynomials in the ``modified'' + subresultant prs; however, the absolute values are the same. + + To compute the coefficients, no determinant evaluation takes place. + Instead, we first compute the euclidean sequence of p and q using + euclid_amv(p, q, x) and then: (a) change the signs of the remainders in the + Euclidean sequence according to the pattern "-, -, +, +, -, -, +, +,..." + (see Lemma 1 in the 1st reference or Theorem 3 in the 2nd reference) + and (b) if method=0, assuming deg(p) > deg(q), we multiply the remainder + coefficients of the Euclidean sequence times the factor + Abs( LC(p)**( deg(p)- deg(q)) ) to make them modified subresultants. + See also the function sturm_pg(p, q, x). + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result + on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On the Remainders + Obtained in Finding the Greatest Common Divisor of Two Polynomials.'' Serdica + Journal of Computing 9(2) (2015), 123-138. + + 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial + Remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' + Serdica Journal of Computing 10 (2016), No.3-4, 197-217. + + """ + # compute the euclidean sequence + prs = euclid_amv(p, q, x) + + # defensive + if prs == [] or len(prs) == 2: + return prs + + # the coefficients in prs are subresultants and hence are smaller + # than the corresponding subresultants by the factor + # Abs( LC(prs[0])**( deg(prs[0]) - deg(prs[1])) ); Theorem 2, 2nd reference. + lcf = Abs( LC(prs[0])**( degree(prs[0], x) - degree(prs[1], x) ) ) + + # the signs of the first two polys in the sequence stay the same + sturm_seq = [prs[0], prs[1]] + + # change the signs according to "-, -, +, +, -, -, +, +,..." + # and multiply times lcf if needed + flag = 0 + m = len(prs) + i = 2 + while i <= m-1: + if flag == 0: + sturm_seq.append( - prs[i] ) + i = i + 1 + if i == m: + break + sturm_seq.append( - prs[i] ) + i = i + 1 + flag = 1 + elif flag == 1: + sturm_seq.append( prs[i] ) + i = i + 1 + if i == m: + break + sturm_seq.append( prs[i] ) + i = i + 1 + flag = 0 + + # subresultants or modified subresultants? + if method == 0 and lcf > 1: + aux_seq = [sturm_seq[0], sturm_seq[1]] + for i in range(2, m): + aux_seq.append(simplify(sturm_seq[i] * lcf )) + sturm_seq = aux_seq + + return sturm_seq + +def euclid_pg(p, q, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the Euclidean sequence of p and q in Z[x] or Q[x]. + + If the Euclidean sequence is complete the coefficients of the polynomials + in the sequence are subresultants. That is, they are determinants of + appropriately selected submatrices of sylvester1, Sylvester's matrix of 1840. + In this case the Euclidean sequence coincides with the subresultant prs + of the polynomials p, q. + + If the Euclidean sequence is incomplete the signs of the coefficients of the + polynomials in the sequence may differ from the signs of the coefficients of + the corresponding polynomials in the subresultant prs; however, the absolute + values are the same. + + To compute the Euclidean sequence, no determinant evaluation takes place. + We first compute the (generalized) Sturm sequence of p and q using + sturm_pg(p, q, x, 1), in which case the coefficients are (in absolute value) + equal to subresultants. Then we change the signs of the remainders in the + Sturm sequence according to the pattern "-, -, +, +, -, -, +, +,..." ; + see Lemma 1 in the 1st reference or Theorem 3 in the 2nd reference as well as + the function sturm_pg(p, q, x). + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result + on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On the Remainders + Obtained in Finding the Greatest Common Divisor of Two Polynomials.'' Serdica + Journal of Computing 9(2) (2015), 123-138. + + 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial + Remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' + Serdica Journal of Computing 10 (2016), No.3-4, 197-217. + """ + # compute the sturmian sequence using the Pell-Gordon (or AMV) theorem + # with the coefficients in the prs being (in absolute value) subresultants + prs = sturm_pg(p, q, x, 1) ## any other method would do + + # defensive + if prs == [] or len(prs) == 2: + return prs + + # the signs of the first two polys in the sequence stay the same + euclid_seq = [prs[0], prs[1]] + + # change the signs according to "-, -, +, +, -, -, +, +,..." + flag = 0 + m = len(prs) + i = 2 + while i <= m-1: + if flag == 0: + euclid_seq.append(- prs[i] ) + i = i + 1 + if i == m: + break + euclid_seq.append(- prs[i] ) + i = i + 1 + flag = 1 + elif flag == 1: + euclid_seq.append(prs[i] ) + i = i + 1 + if i == m: + break + euclid_seq.append(prs[i] ) + i = i + 1 + flag = 0 + + return euclid_seq + +def euclid_q(p, q, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the Euclidean sequence of p and q in Q[x]. + Polynomial divisions in Q[x] are performed, using the function rem(p, q, x). + + The coefficients of the polynomials in the Euclidean sequence can be uniquely + determined from the corresponding coefficients of the polynomials found + either in: + + (a) the ``modified'' subresultant polynomial remainder sequence, + (references 1, 2) + + or in + + (b) the subresultant polynomial remainder sequence (references 3). + + References + ========== + 1. Pell A. J., R. L. Gordon. The Modified Remainders Obtained in Finding + the Highest Common Factor of Two Polynomials. Annals of MatheMatics, + Second Series, 18 (1917), No. 4, 188-193. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences + and Modified Subresultant Polynomial Remainder Sequences.'' + Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. + + 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result + on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + # make sure proper degrees + d0 = degree(p, x) + d1 = degree(q, x) + if d0 == 0 and d1 == 0: + return [p, q] + if d1 > d0: + d0, d1 = d1, d0 + p, q = q, p + if d0 > 0 and d1 == 0: + return [p,q] + + # make sure LC(p) > 0 + flag = 0 + if LC(p,x) < 0: + flag = 1 + p = -p + q = -q + + # initialize + a0, a1 = p, q # the input polys + euclid_seq = [a0, a1] # the output list + a2 = rem(a0, a1, domain=QQ) # first remainder + d2 = degree(a2, x) # degree of a2 + euclid_seq.append( a2 ) + + # main loop + while d2 > 0: + a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees + a2 = rem(a0, a1, domain=QQ) # new remainder + d2 = degree(a2, x) # actual degree of a2 + euclid_seq.append( a2 ) + + if flag: # change the sign of the sequence + euclid_seq = [-i for i in euclid_seq] + + # gcd is of degree > 0 ? + m = len(euclid_seq) + if euclid_seq[m - 1] == nan or euclid_seq[m - 1] == 0: + euclid_seq.pop(m - 1) + + return euclid_seq + +def euclid_amv(f, g, x): + """ + f, g are polynomials in Z[x] or Q[x]. It is assumed + that degree(f, x) >= degree(g, x). + + Computes the Euclidean sequence of p and q in Z[x] or Q[x]. + + If the Euclidean sequence is complete the coefficients of the polynomials + in the sequence are subresultants. That is, they are determinants of + appropriately selected submatrices of sylvester1, Sylvester's matrix of 1840. + In this case the Euclidean sequence coincides with the subresultant prs, + of the polynomials p, q. + + If the Euclidean sequence is incomplete the signs of the coefficients of the + polynomials in the sequence may differ from the signs of the coefficients of + the corresponding polynomials in the subresultant prs; however, the absolute + values are the same. + + To compute the coefficients, no determinant evaluation takes place. + Instead, polynomial divisions in Z[x] or Q[x] are performed, using + the function rem_z(f, g, x); the coefficients of the remainders + computed this way become subresultants with the help of the + Collins-Brown-Traub formula for coefficient reduction. + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result + on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial + remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' + Serdica Journal of Computing 10 (2016), No.3-4, 197-217. + + """ + # make sure neither f nor g is 0 + if f == 0 or g == 0: + return [f, g] + + # make sure proper degrees + d0 = degree(f, x) + d1 = degree(g, x) + if d0 == 0 and d1 == 0: + return [f, g] + if d1 > d0: + d0, d1 = d1, d0 + f, g = g, f + if d0 > 0 and d1 == 0: + return [f, g] + + # initialize + a0 = f + a1 = g + euclid_seq = [a0, a1] + deg_dif_p1, c = degree(a0, x) - degree(a1, x) + 1, -1 + + # compute the first polynomial of the prs + i = 1 + a2 = rem_z(a0, a1, x) / Abs( (-1)**deg_dif_p1 ) # first remainder + euclid_seq.append( a2 ) + d2 = degree(a2, x) # actual degree of a2 + + # main loop + while d2 >= 1: + a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees + i += 1 + sigma0 = -LC(a0) + c = (sigma0**(deg_dif_p1 - 1)) / (c**(deg_dif_p1 - 2)) + deg_dif_p1 = degree(a0, x) - d2 + 1 + a2 = rem_z(a0, a1, x) / Abs( (c**(deg_dif_p1 - 1)) * sigma0 ) + euclid_seq.append( a2 ) + d2 = degree(a2, x) # actual degree of a2 + + # gcd is of degree > 0 ? + m = len(euclid_seq) + if euclid_seq[m - 1] == nan or euclid_seq[m - 1] == 0: + euclid_seq.pop(m - 1) + + return euclid_seq + +def modified_subresultants_pg(p, q, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the ``modified'' subresultant prs of p and q in Z[x] or Q[x]; + the coefficients of the polynomials in the sequence are + ``modified'' subresultants. That is, they are determinants of appropriately + selected submatrices of sylvester2, Sylvester's matrix of 1853. + + To compute the coefficients, no determinant evaluation takes place. Instead, + polynomial divisions in Q[x] are performed, using the function rem(p, q, x); + the coefficients of the remainders computed this way become ``modified'' + subresultants with the help of the Pell-Gordon Theorem of 1917. + + If the ``modified'' subresultant prs is complete, and LC( p ) > 0, it coincides + with the (generalized) Sturm sequence of the polynomials p, q. + + References + ========== + 1. Pell A. J., R. L. Gordon. The Modified Remainders Obtained in Finding + the Highest Common Factor of Two Polynomials. Annals of MatheMatics, + Second Series, 18 (1917), No. 4, 188-193. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences + and Modified Subresultant Polynomial Remainder Sequences.'' + Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + # make sure proper degrees + d0 = degree(p,x) + d1 = degree(q,x) + if d0 == 0 and d1 == 0: + return [p, q] + if d1 > d0: + d0, d1 = d1, d0 + p, q = q, p + if d0 > 0 and d1 == 0: + return [p,q] + + # initialize + k = var('k') # index in summation formula + u_list = [] # of elements (-1)**u_i + subres_l = [p, q] # mod. subr. prs output list + a0, a1 = p, q # the input polys + del0 = d0 - d1 # degree difference + degdif = del0 # save it + rho_1 = LC(a0) # lead. coeff (a0) + + # Initialize Pell-Gordon variables + rho_list_minus_1 = sign( LC(a0, x)) # sign of LC(a0) + rho1 = LC(a1, x) # leading coeff of a1 + rho_list = [ sign(rho1)] # of signs + p_list = [del0] # of degree differences + u = summation(k, (k, 1, p_list[0])) # value of u + u_list.append(u) # of u values + v = sum(p_list) # v value + + # first remainder + exp_deg = d1 - 1 # expected degree of a2 + a2 = - rem(a0, a1, domain=QQ) # first remainder + rho2 = LC(a2, x) # leading coeff of a2 + d2 = degree(a2, x) # actual degree of a2 + deg_diff_new = exp_deg - d2 # expected - actual degree + del1 = d1 - d2 # degree difference + + # mul_fac is the factor by which a2 is multiplied to + # get integer coefficients + mul_fac_old = rho1**(del0 + del1 - deg_diff_new) + + # update Pell-Gordon variables + p_list.append(1 + deg_diff_new) # deg_diff_new is 0 for complete seq + + # apply Pell-Gordon formula (7) in second reference + num = 1 # numerator of fraction + for u in u_list: + num *= (-1)**u + num = num * (-1)**v + + # denominator depends on complete / incomplete seq + if deg_diff_new == 0: # complete seq + den = 1 + for k in range(len(rho_list)): + den *= rho_list[k]**(p_list[k] + p_list[k + 1]) + den = den * rho_list_minus_1 + else: # incomplete seq + den = 1 + for k in range(len(rho_list)-1): + den *= rho_list[k]**(p_list[k] + p_list[k + 1]) + den = den * rho_list_minus_1 + expo = (p_list[len(rho_list) - 1] + p_list[len(rho_list)] - deg_diff_new) + den = den * rho_list[len(rho_list) - 1]**expo + + # the sign of the determinant depends on sg(num / den) + if sign(num / den) > 0: + subres_l.append( simplify(rho_1**degdif*a2* Abs(mul_fac_old) ) ) + else: + subres_l.append(- simplify(rho_1**degdif*a2* Abs(mul_fac_old) ) ) + + # update Pell-Gordon variables + k = var('k') + rho_list.append( sign(rho2)) + u = summation(k, (k, 1, p_list[len(p_list) - 1])) + u_list.append(u) + v = sum(p_list) + deg_diff_old=deg_diff_new + + # main loop + while d2 > 0: + a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees + del0 = del1 # update degree difference + exp_deg = d1 - 1 # new expected degree + a2 = - rem(a0, a1, domain=QQ) # new remainder + rho3 = LC(a2, x) # leading coeff of a2 + d2 = degree(a2, x) # actual degree of a2 + deg_diff_new = exp_deg - d2 # expected - actual degree + del1 = d1 - d2 # degree difference + + # take into consideration the power + # rho1**deg_diff_old that was "left out" + expo_old = deg_diff_old # rho1 raised to this power + expo_new = del0 + del1 - deg_diff_new # rho2 raised to this power + + mul_fac_new = rho2**(expo_new) * rho1**(expo_old) * mul_fac_old + + # update variables + deg_diff_old, mul_fac_old = deg_diff_new, mul_fac_new + rho1, rho2 = rho2, rho3 + + # update Pell-Gordon variables + p_list.append(1 + deg_diff_new) # deg_diff_new is 0 for complete seq + + # apply Pell-Gordon formula (7) in second reference + num = 1 # numerator + for u in u_list: + num *= (-1)**u + num = num * (-1)**v + + # denominator depends on complete / incomplete seq + if deg_diff_new == 0: # complete seq + den = 1 + for k in range(len(rho_list)): + den *= rho_list[k]**(p_list[k] + p_list[k + 1]) + den = den * rho_list_minus_1 + else: # incomplete seq + den = 1 + for k in range(len(rho_list)-1): + den *= rho_list[k]**(p_list[k] + p_list[k + 1]) + den = den * rho_list_minus_1 + expo = (p_list[len(rho_list) - 1] + p_list[len(rho_list)] - deg_diff_new) + den = den * rho_list[len(rho_list) - 1]**expo + + # the sign of the determinant depends on sg(num / den) + if sign(num / den) > 0: + subres_l.append( simplify(rho_1**degdif*a2* Abs(mul_fac_old) ) ) + else: + subres_l.append(- simplify(rho_1**degdif*a2* Abs(mul_fac_old) ) ) + + # update Pell-Gordon variables + k = var('k') + rho_list.append( sign(rho2)) + u = summation(k, (k, 1, p_list[len(p_list) - 1])) + u_list.append(u) + v = sum(p_list) + + # gcd is of degree > 0 ? + m = len(subres_l) + if subres_l[m - 1] == nan or subres_l[m - 1] == 0: + subres_l.pop(m - 1) + + # LC( p ) < 0 + m = len(subres_l) # list may be shorter now due to deg(gcd ) > 0 + if LC( p ) < 0: + aux_seq = [subres_l[0], subres_l[1]] + for i in range(2, m): + aux_seq.append(simplify(subres_l[i] * (-1) )) + subres_l = aux_seq + + return subres_l + +def subresultants_pg(p, q, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the subresultant prs of p and q in Z[x] or Q[x], from + the modified subresultant prs of p and q. + + The coefficients of the polynomials in these two sequences differ only + in sign and the factor LC(p)**( deg(p)- deg(q)) as stated in + Theorem 2 of the reference. + + The coefficients of the polynomials in the output sequence are + subresultants. That is, they are determinants of appropriately + selected submatrices of sylvester1, Sylvester's matrix of 1840. + + If the subresultant prs is complete, then it coincides with the + Euclidean sequence of the polynomials p, q. + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: "On the Remainders + Obtained in Finding the Greatest Common Divisor of Two Polynomials." + Serdica Journal of Computing 9(2) (2015), 123-138. + + """ + # compute the modified subresultant prs + lst = modified_subresultants_pg(p,q,x) ## any other method would do + + # defensive + if lst == [] or len(lst) == 2: + return lst + + # the coefficients in lst are modified subresultants and, hence, are + # greater than those of the corresponding subresultants by the factor + # LC(lst[0])**( deg(lst[0]) - deg(lst[1])); see Theorem 2 in reference. + lcf = LC(lst[0])**( degree(lst[0], x) - degree(lst[1], x) ) + + # Initialize the subresultant prs list + subr_seq = [lst[0], lst[1]] + + # compute the degree sequences m_i and j_i of Theorem 2 in reference. + deg_seq = [degree(Poly(poly, x), x) for poly in lst] + deg = deg_seq[0] + deg_seq_s = deg_seq[1:-1] + m_seq = [m-1 for m in deg_seq_s] + j_seq = [deg - m for m in m_seq] + + # compute the AMV factors of Theorem 2 in reference. + fact = [(-1)**( j*(j-1)/S(2) ) for j in j_seq] + + # shortened list without the first two polys + lst_s = lst[2:] + + # poly lst_s[k] is multiplied times fact[k], divided by lcf + # and appended to the subresultant prs list + m = len(fact) + for k in range(m): + if sign(fact[k]) == -1: + subr_seq.append(-lst_s[k] / lcf) + else: + subr_seq.append(lst_s[k] / lcf) + + return subr_seq + +def subresultants_amv_q(p, q, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the subresultant prs of p and q in Q[x]; + the coefficients of the polynomials in the sequence are + subresultants. That is, they are determinants of appropriately + selected submatrices of sylvester1, Sylvester's matrix of 1840. + + To compute the coefficients, no determinant evaluation takes place. + Instead, polynomial divisions in Q[x] are performed, using the + function rem(p, q, x); the coefficients of the remainders + computed this way become subresultants with the help of the + Akritas-Malaschonok-Vigklas Theorem of 2015. + + If the subresultant prs is complete, then it coincides with the + Euclidean sequence of the polynomials p, q. + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result + on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial + remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' + Serdica Journal of Computing 10 (2016), No.3-4, 197-217. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + # make sure proper degrees + d0 = degree(p, x) + d1 = degree(q, x) + if d0 == 0 and d1 == 0: + return [p, q] + if d1 > d0: + d0, d1 = d1, d0 + p, q = q, p + if d0 > 0 and d1 == 0: + return [p, q] + + # initialize + i, s = 0, 0 # counters for remainders & odd elements + p_odd_index_sum = 0 # contains the sum of p_1, p_3, etc + subres_l = [p, q] # subresultant prs output list + a0, a1 = p, q # the input polys + sigma1 = LC(a1, x) # leading coeff of a1 + p0 = d0 - d1 # degree difference + if p0 % 2 == 1: + s += 1 + phi = floor( (s + 1) / 2 ) + mul_fac = 1 + d2 = d1 + + # main loop + while d2 > 0: + i += 1 + a2 = rem(a0, a1, domain= QQ) # new remainder + if i == 1: + sigma2 = LC(a2, x) + else: + sigma3 = LC(a2, x) + sigma1, sigma2 = sigma2, sigma3 + d2 = degree(a2, x) + p1 = d1 - d2 + psi = i + phi + p_odd_index_sum + + # new mul_fac + mul_fac = sigma1**(p0 + 1) * mul_fac + + ## compute the sign of the first fraction in formula (9) of the paper + # numerator + num = (-1)**psi + # denominator + den = sign(mul_fac) + + # the sign of the determinant depends on sign( num / den ) != 0 + if sign(num / den) > 0: + subres_l.append( simplify(expand(a2* Abs(mul_fac)))) + else: + subres_l.append(- simplify(expand(a2* Abs(mul_fac)))) + + ## bring into mul_fac the missing power of sigma if there was a degree gap + if p1 - 1 > 0: + mul_fac = mul_fac * sigma1**(p1 - 1) + + # update AMV variables + a0, a1, d0, d1 = a1, a2, d1, d2 + p0 = p1 + if p0 % 2 ==1: + s += 1 + phi = floor( (s + 1) / 2 ) + if i%2 == 1: + p_odd_index_sum += p0 # p_i has odd index + + # gcd is of degree > 0 ? + m = len(subres_l) + if subres_l[m - 1] == nan or subres_l[m - 1] == 0: + subres_l.pop(m - 1) + + return subres_l + +def compute_sign(base, expo): + ''' + base != 0 and expo >= 0 are integers; + + returns the sign of base**expo without + evaluating the power itself! + ''' + sb = sign(base) + if sb == 1: + return 1 + pe = expo % 2 + if pe == 0: + return -sb + else: + return sb + +def rem_z(p, q, x): + ''' + Intended mainly for p, q polynomials in Z[x] so that, + on dividing p by q, the remainder will also be in Z[x]. (However, + it also works fine for polynomials in Q[x].) It is assumed + that degree(p, x) >= degree(q, x). + + It premultiplies p by the _absolute_ value of the leading coefficient + of q, raised to the power deg(p) - deg(q) + 1 and then performs + polynomial division in Q[x], using the function rem(p, q, x). + + By contrast the function prem(p, q, x) does _not_ use the absolute + value of the leading coefficient of q. + This results not only in ``messing up the signs'' of the Euclidean and + Sturmian prs's as mentioned in the second reference, + but also in violation of the main results of the first and third + references --- Theorem 4 and Theorem 1 respectively. Theorems 4 and 1 + establish a one-to-one correspondence between the Euclidean and the + Sturmian prs of p, q, on one hand, and the subresultant prs of p, q, + on the other. + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On the Remainders + Obtained in Finding the Greatest Common Divisor of Two Polynomials.'' + Serdica Journal of Computing, 9(2) (2015), 123-138. + + 2. https://planetMath.org/sturmstheorem + + 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on + the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. + + ''' + if (p.as_poly().is_univariate and q.as_poly().is_univariate and + p.as_poly().gens == q.as_poly().gens): + delta = (degree(p, x) - degree(q, x) + 1) + return rem(Abs(LC(q, x))**delta * p, q, x) + else: + return prem(p, q, x) + +def quo_z(p, q, x): + """ + Intended mainly for p, q polynomials in Z[x] so that, + on dividing p by q, the quotient will also be in Z[x]. (However, + it also works fine for polynomials in Q[x].) It is assumed + that degree(p, x) >= degree(q, x). + + It premultiplies p by the _absolute_ value of the leading coefficient + of q, raised to the power deg(p) - deg(q) + 1 and then performs + polynomial division in Q[x], using the function quo(p, q, x). + + By contrast the function pquo(p, q, x) does _not_ use the absolute + value of the leading coefficient of q. + + See also function rem_z(p, q, x) for additional comments and references. + + """ + if (p.as_poly().is_univariate and q.as_poly().is_univariate and + p.as_poly().gens == q.as_poly().gens): + delta = (degree(p, x) - degree(q, x) + 1) + return quo(Abs(LC(q, x))**delta * p, q, x) + else: + return pquo(p, q, x) + +def subresultants_amv(f, g, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(f, x) >= degree(g, x). + + Computes the subresultant prs of p and q in Z[x] or Q[x]; + the coefficients of the polynomials in the sequence are + subresultants. That is, they are determinants of appropriately + selected submatrices of sylvester1, Sylvester's matrix of 1840. + + To compute the coefficients, no determinant evaluation takes place. + Instead, polynomial divisions in Z[x] or Q[x] are performed, using + the function rem_z(p, q, x); the coefficients of the remainders + computed this way become subresultants with the help of the + Akritas-Malaschonok-Vigklas Theorem of 2015 and the Collins-Brown- + Traub formula for coefficient reduction. + + If the subresultant prs is complete, then it coincides with the + Euclidean sequence of the polynomials p, q. + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result + on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial + remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' + Serdica Journal of Computing 10 (2016), No.3-4, 197-217. + + """ + # make sure neither f nor g is 0 + if f == 0 or g == 0: + return [f, g] + + # make sure proper degrees + d0 = degree(f, x) + d1 = degree(g, x) + if d0 == 0 and d1 == 0: + return [f, g] + if d1 > d0: + d0, d1 = d1, d0 + f, g = g, f + if d0 > 0 and d1 == 0: + return [f, g] + + # initialize + a0 = f + a1 = g + subres_l = [a0, a1] + deg_dif_p1, c = degree(a0, x) - degree(a1, x) + 1, -1 + + # initialize AMV variables + sigma1 = LC(a1, x) # leading coeff of a1 + i, s = 0, 0 # counters for remainders & odd elements + p_odd_index_sum = 0 # contains the sum of p_1, p_3, etc + p0 = deg_dif_p1 - 1 + if p0 % 2 == 1: + s += 1 + phi = floor( (s + 1) / 2 ) + + # compute the first polynomial of the prs + i += 1 + a2 = rem_z(a0, a1, x) / Abs( (-1)**deg_dif_p1 ) # first remainder + sigma2 = LC(a2, x) # leading coeff of a2 + d2 = degree(a2, x) # actual degree of a2 + p1 = d1 - d2 # degree difference + + # sgn_den is the factor, the denominator 1st fraction of (9), + # by which a2 is multiplied to get integer coefficients + sgn_den = compute_sign( sigma1, p0 + 1 ) + + ## compute sign of the 1st fraction in formula (9) of the paper + # numerator + psi = i + phi + p_odd_index_sum + num = (-1)**psi + # denominator + den = sgn_den + + # the sign of the determinant depends on sign(num / den) != 0 + if sign(num / den) > 0: + subres_l.append( a2 ) + else: + subres_l.append( -a2 ) + + # update AMV variable + if p1 % 2 == 1: + s += 1 + + # bring in the missing power of sigma if there was gap + if p1 - 1 > 0: + sgn_den = sgn_den * compute_sign( sigma1, p1 - 1 ) + + # main loop + while d2 >= 1: + phi = floor( (s + 1) / 2 ) + if i%2 == 1: + p_odd_index_sum += p1 # p_i has odd index + a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees + p0 = p1 # update degree difference + i += 1 + sigma0 = -LC(a0) + c = (sigma0**(deg_dif_p1 - 1)) / (c**(deg_dif_p1 - 2)) + deg_dif_p1 = degree(a0, x) - d2 + 1 + a2 = rem_z(a0, a1, x) / Abs( (c**(deg_dif_p1 - 1)) * sigma0 ) + sigma3 = LC(a2, x) # leading coeff of a2 + d2 = degree(a2, x) # actual degree of a2 + p1 = d1 - d2 # degree difference + psi = i + phi + p_odd_index_sum + + # update variables + sigma1, sigma2 = sigma2, sigma3 + + # new sgn_den + sgn_den = compute_sign( sigma1, p0 + 1 ) * sgn_den + + # compute the sign of the first fraction in formula (9) of the paper + # numerator + num = (-1)**psi + # denominator + den = sgn_den + + # the sign of the determinant depends on sign( num / den ) != 0 + if sign(num / den) > 0: + subres_l.append( a2 ) + else: + subres_l.append( -a2 ) + + # update AMV variable + if p1 % 2 ==1: + s += 1 + + # bring in the missing power of sigma if there was gap + if p1 - 1 > 0: + sgn_den = sgn_den * compute_sign( sigma1, p1 - 1 ) + + # gcd is of degree > 0 ? + m = len(subres_l) + if subres_l[m - 1] == nan or subres_l[m - 1] == 0: + subres_l.pop(m - 1) + + return subres_l + +def modified_subresultants_amv(p, q, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the modified subresultant prs of p and q in Z[x] or Q[x], + from the subresultant prs of p and q. + The coefficients of the polynomials in the two sequences differ only + in sign and the factor LC(p)**( deg(p)- deg(q)) as stated in + Theorem 2 of the reference. + + The coefficients of the polynomials in the output sequence are + modified subresultants. That is, they are determinants of appropriately + selected submatrices of sylvester2, Sylvester's matrix of 1853. + + If the modified subresultant prs is complete, and LC( p ) > 0, it coincides + with the (generalized) Sturm's sequence of the polynomials p, q. + + References + ========== + 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: "On the Remainders + Obtained in Finding the Greatest Common Divisor of Two Polynomials." + Serdica Journal of Computing, Serdica Journal of Computing, 9(2) (2015), 123-138. + + """ + # compute the subresultant prs + lst = subresultants_amv(p,q,x) ## any other method would do + + # defensive + if lst == [] or len(lst) == 2: + return lst + + # the coefficients in lst are subresultants and, hence, smaller than those + # of the corresponding modified subresultants by the factor + # LC(lst[0])**( deg(lst[0]) - deg(lst[1])); see Theorem 2. + lcf = LC(lst[0])**( degree(lst[0], x) - degree(lst[1], x) ) + + # Initialize the modified subresultant prs list + subr_seq = [lst[0], lst[1]] + + # compute the degree sequences m_i and j_i of Theorem 2 + deg_seq = [degree(Poly(poly, x), x) for poly in lst] + deg = deg_seq[0] + deg_seq_s = deg_seq[1:-1] + m_seq = [m-1 for m in deg_seq_s] + j_seq = [deg - m for m in m_seq] + + # compute the AMV factors of Theorem 2 + fact = [(-1)**( j*(j-1)/S(2) ) for j in j_seq] + + # shortened list without the first two polys + lst_s = lst[2:] + + # poly lst_s[k] is multiplied times fact[k] and times lcf + # and appended to the subresultant prs list + m = len(fact) + for k in range(m): + if sign(fact[k]) == -1: + subr_seq.append( simplify(-lst_s[k] * lcf) ) + else: + subr_seq.append( simplify(lst_s[k] * lcf) ) + + return subr_seq + +def correct_sign(deg_f, deg_g, s1, rdel, cdel): + """ + Used in various subresultant prs algorithms. + + Evaluates the determinant, (a.k.a. subresultant) of a properly selected + submatrix of s1, Sylvester's matrix of 1840, to get the correct sign + and value of the leading coefficient of a given polynomial remainder. + + deg_f, deg_g are the degrees of the original polynomials p, q for which the + matrix s1 = sylvester(p, q, x, 1) was constructed. + + rdel denotes the expected degree of the remainder; it is the number of + rows to be deleted from each group of rows in s1 as described in the + reference below. + + cdel denotes the expected degree minus the actual degree of the remainder; + it is the number of columns to be deleted --- starting with the last column + forming the square matrix --- from the matrix resulting after the row deletions. + + References + ========== + Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences + and Modified Subresultant Polynomial Remainder Sequences.'' + Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. + + """ + M = s1[:, :] # copy of matrix s1 + + # eliminate rdel rows from the first deg_g rows + for i in range(M.rows - deg_f - 1, M.rows - deg_f - rdel - 1, -1): + M.row_del(i) + + # eliminate rdel rows from the last deg_f rows + for i in range(M.rows - 1, M.rows - rdel - 1, -1): + M.row_del(i) + + # eliminate cdel columns + for i in range(cdel): + M.col_del(M.rows - 1) + + # define submatrix + Md = M[:, 0: M.rows] + + return Md.det() + +def subresultants_rem(p, q, x): + """ + p, q are polynomials in Z[x] or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the subresultant prs of p and q in Z[x] or Q[x]; + the coefficients of the polynomials in the sequence are + subresultants. That is, they are determinants of appropriately + selected submatrices of sylvester1, Sylvester's matrix of 1840. + + To compute the coefficients polynomial divisions in Q[x] are + performed, using the function rem(p, q, x). The coefficients + of the remainders computed this way become subresultants by evaluating + one subresultant per remainder --- that of the leading coefficient. + This way we obtain the correct sign and value of the leading coefficient + of the remainder and we easily ``force'' the rest of the coefficients + to become subresultants. + + If the subresultant prs is complete, then it coincides with the + Euclidean sequence of the polynomials p, q. + + References + ========== + 1. Akritas, A. G.:``Three New Methods for Computing Subresultant + Polynomial Remainder Sequences (PRS's).'' Serdica Journal of Computing 9(1) (2015), 1-26. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + # make sure proper degrees + f, g = p, q + n = deg_f = degree(f, x) + m = deg_g = degree(g, x) + if n == 0 and m == 0: + return [f, g] + if n < m: + n, m, deg_f, deg_g, f, g = m, n, deg_g, deg_f, g, f + if n > 0 and m == 0: + return [f, g] + + # initialize + s1 = sylvester(f, g, x, 1) + sr_list = [f, g] # subresultant list + + # main loop + while deg_g > 0: + r = rem(p, q, x) + d = degree(r, x) + if d < 0: + return sr_list + + # make coefficients subresultants evaluating ONE determinant + exp_deg = deg_g - 1 # expected degree + sign_value = correct_sign(n, m, s1, exp_deg, exp_deg - d) + r = simplify((r / LC(r, x)) * sign_value) + + # append poly with subresultant coeffs + sr_list.append(r) + + # update degrees and polys + deg_f, deg_g = deg_g, d + p, q = q, r + + # gcd is of degree > 0 ? + m = len(sr_list) + if sr_list[m - 1] == nan or sr_list[m - 1] == 0: + sr_list.pop(m - 1) + + return sr_list + +def pivot(M, i, j): + ''' + M is a matrix, and M[i, j] specifies the pivot element. + + All elements below M[i, j], in the j-th column, will + be zeroed, if they are not already 0, according to + Dodgson-Bareiss' integer preserving transformations. + + References + ========== + 1. Akritas, A. G.: ``A new method for computing polynomial greatest + common divisors and polynomial remainder sequences.'' + Numerische MatheMatik 52, 119-127, 1988. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On a Theorem + by Van Vleck Regarding Sturm Sequences.'' + Serdica Journal of Computing, 7, No 4, 101-134, 2013. + + ''' + ma = M[:, :] # copy of matrix M + rs = ma.rows # No. of rows + cs = ma.cols # No. of cols + for r in range(i+1, rs): + if ma[r, j] != 0: + for c in range(j + 1, cs): + ma[r, c] = ma[i, j] * ma[r, c] - ma[i, c] * ma[r, j] + ma[r, j] = 0 + return ma + +def rotate_r(L, k): + ''' + Rotates right by k. L is a row of a matrix or a list. + + ''' + ll = list(L) + if ll == []: + return [] + for i in range(k): + el = ll.pop(len(ll) - 1) + ll.insert(0, el) + return ll if isinstance(L, list) else Matrix([ll]) + +def rotate_l(L, k): + ''' + Rotates left by k. L is a row of a matrix or a list. + + ''' + ll = list(L) + if ll == []: + return [] + for i in range(k): + el = ll.pop(0) + ll.insert(len(ll) - 1, el) + return ll if isinstance(L, list) else Matrix([ll]) + +def row2poly(row, deg, x): + ''' + Converts the row of a matrix to a poly of degree deg and variable x. + Some entries at the beginning and/or at the end of the row may be zero. + + ''' + k = 0 + poly = [] + leng = len(row) + + # find the beginning of the poly ; i.e. the first + # non-zero element of the row + while row[k] == 0: + k = k + 1 + + # append the next deg + 1 elements to poly + for j in range( deg + 1): + if k + j <= leng: + poly.append(row[k + j]) + + return Poly(poly, x) + +def create_ma(deg_f, deg_g, row1, row2, col_num): + ''' + Creates a ``small'' matrix M to be triangularized. + + deg_f, deg_g are the degrees of the divident and of the + divisor polynomials respectively, deg_g > deg_f. + + The coefficients of the divident poly are the elements + in row2 and those of the divisor poly are the elements + in row1. + + col_num defines the number of columns of the matrix M. + + ''' + if deg_g - deg_f >= 1: + print('Reverse degrees') + return + + m = zeros(deg_f - deg_g + 2, col_num) + + for i in range(deg_f - deg_g + 1): + m[i, :] = rotate_r(row1, i) + m[deg_f - deg_g + 1, :] = row2 + + return m + +def find_degree(M, deg_f): + ''' + Finds the degree of the poly corresponding (after triangularization) + to the _last_ row of the ``small'' matrix M, created by create_ma(). + + deg_f is the degree of the divident poly. + If _last_ row is all 0's returns None. + + ''' + j = deg_f + for i in range(0, M.cols): + if M[M.rows - 1, i] == 0: + j = j - 1 + else: + return max(j, 0) + +def final_touches(s2, r, deg_g): + """ + s2 is sylvester2, r is the row pointer in s2, + deg_g is the degree of the poly last inserted in s2. + + After a gcd of degree > 0 has been found with Van Vleck's + method, and was inserted into s2, if its last term is not + in the last column of s2, then it is inserted as many + times as needed, rotated right by one each time, until + the condition is met. + + """ + R = s2.row(r-1) + + # find the first non zero term + for i in range(s2.cols): + if R[0,i] == 0: + continue + else: + break + + # missing rows until last term is in last column + mr = s2.cols - (i + deg_g + 1) + + # insert them by replacing the existing entries in the row + i = 0 + while mr != 0 and r + i < s2.rows : + s2[r + i, : ] = rotate_r(R, i + 1) + i += 1 + mr -= 1 + + return s2 + +def subresultants_vv(p, q, x, method = 0): + """ + p, q are polynomials in Z[x] (intended) or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the subresultant prs of p, q by triangularizing, + in Z[x] or in Q[x], all the smaller matrices encountered in the + process of triangularizing sylvester2, Sylvester's matrix of 1853; + see references 1 and 2 for Van Vleck's method. With each remainder, + sylvester2 gets updated and is prepared to be printed if requested. + + If sylvester2 has small dimensions and you want to see the final, + triangularized matrix use this version with method=1; otherwise, + use either this version with method=0 (default) or the faster version, + subresultants_vv_2(p, q, x), where sylvester2 is used implicitly. + + Sylvester's matrix sylvester1 is also used to compute one + subresultant per remainder; namely, that of the leading + coefficient, in order to obtain the correct sign and to + force the remainder coefficients to become subresultants. + + If the subresultant prs is complete, then it coincides with the + Euclidean sequence of the polynomials p, q. + + If the final, triangularized matrix s2 is printed, then: + (a) if deg(p) - deg(q) > 1 or deg( gcd(p, q) ) > 0, several + of the last rows in s2 will remain unprocessed; + (b) if deg(p) - deg(q) == 0, p will not appear in the final matrix. + + References + ========== + 1. Akritas, A. G.: ``A new method for computing polynomial greatest + common divisors and polynomial remainder sequences.'' + Numerische MatheMatik 52, 119-127, 1988. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On a Theorem + by Van Vleck Regarding Sturm Sequences.'' + Serdica Journal of Computing, 7, No 4, 101-134, 2013. + + 3. Akritas, A. G.:``Three New Methods for Computing Subresultant + Polynomial Remainder Sequences (PRS's).'' Serdica Journal of Computing 9(1) (2015), 1-26. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + # make sure proper degrees + f, g = p, q + n = deg_f = degree(f, x) + m = deg_g = degree(g, x) + if n == 0 and m == 0: + return [f, g] + if n < m: + n, m, deg_f, deg_g, f, g = m, n, deg_g, deg_f, g, f + if n > 0 and m == 0: + return [f, g] + + # initialize + s1 = sylvester(f, g, x, 1) + s2 = sylvester(f, g, x, 2) + sr_list = [f, g] + col_num = 2 * n # columns in s2 + + # make two rows (row0, row1) of poly coefficients + row0 = Poly(f, x, domain = QQ).all_coeffs() + leng0 = len(row0) + for i in range(col_num - leng0): + row0.append(0) + row0 = Matrix([row0]) + row1 = Poly(g,x, domain = QQ).all_coeffs() + leng1 = len(row1) + for i in range(col_num - leng1): + row1.append(0) + row1 = Matrix([row1]) + + # row pointer for deg_f - deg_g == 1; may be reset below + r = 2 + + # modify first rows of s2 matrix depending on poly degrees + if deg_f - deg_g > 1: + r = 1 + # replacing the existing entries in the rows of s2, + # insert row0 (deg_f - deg_g - 1) times, rotated each time + for i in range(deg_f - deg_g - 1): + s2[r + i, : ] = rotate_r(row0, i + 1) + r = r + deg_f - deg_g - 1 + # insert row1 (deg_f - deg_g) times, rotated each time + for i in range(deg_f - deg_g): + s2[r + i, : ] = rotate_r(row1, r + i) + r = r + deg_f - deg_g + + if deg_f - deg_g == 0: + r = 0 + + # main loop + while deg_g > 0: + # create a small matrix M, and triangularize it; + M = create_ma(deg_f, deg_g, row1, row0, col_num) + # will need only the first and last rows of M + for i in range(deg_f - deg_g + 1): + M1 = pivot(M, i, i) + M = M1[:, :] + + # treat last row of M as poly; find its degree + d = find_degree(M, deg_f) + if d is None: + break + exp_deg = deg_g - 1 + + # evaluate one determinant & make coefficients subresultants + sign_value = correct_sign(n, m, s1, exp_deg, exp_deg - d) + poly = row2poly(M[M.rows - 1, :], d, x) + temp2 = LC(poly, x) + poly = simplify((poly / temp2) * sign_value) + + # update s2 by inserting first row of M as needed + row0 = M[0, :] + for i in range(deg_g - d): + s2[r + i, :] = rotate_r(row0, r + i) + r = r + deg_g - d + + # update s2 by inserting last row of M as needed + row1 = rotate_l(M[M.rows - 1, :], deg_f - d) + row1 = (row1 / temp2) * sign_value + for i in range(deg_g - d): + s2[r + i, :] = rotate_r(row1, r + i) + r = r + deg_g - d + + # update degrees + deg_f, deg_g = deg_g, d + + # append poly with subresultant coeffs + sr_list.append(poly) + + # final touches to print the s2 matrix + if method != 0 and s2.rows > 2: + s2 = final_touches(s2, r, deg_g) + pprint(s2) + elif method != 0 and s2.rows == 2: + s2[1, :] = rotate_r(s2.row(1), 1) + pprint(s2) + + return sr_list + +def subresultants_vv_2(p, q, x): + """ + p, q are polynomials in Z[x] (intended) or Q[x]. It is assumed + that degree(p, x) >= degree(q, x). + + Computes the subresultant prs of p, q by triangularizing, + in Z[x] or in Q[x], all the smaller matrices encountered in the + process of triangularizing sylvester2, Sylvester's matrix of 1853; + see references 1 and 2 for Van Vleck's method. + + If the sylvester2 matrix has big dimensions use this version, + where sylvester2 is used implicitly. If you want to see the final, + triangularized matrix sylvester2, then use the first version, + subresultants_vv(p, q, x, 1). + + sylvester1, Sylvester's matrix of 1840, is also used to compute + one subresultant per remainder; namely, that of the leading + coefficient, in order to obtain the correct sign and to + ``force'' the remainder coefficients to become subresultants. + + If the subresultant prs is complete, then it coincides with the + Euclidean sequence of the polynomials p, q. + + References + ========== + 1. Akritas, A. G.: ``A new method for computing polynomial greatest + common divisors and polynomial remainder sequences.'' + Numerische MatheMatik 52, 119-127, 1988. + + 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On a Theorem + by Van Vleck Regarding Sturm Sequences.'' + Serdica Journal of Computing, 7, No 4, 101-134, 2013. + + 3. Akritas, A. G.:``Three New Methods for Computing Subresultant + Polynomial Remainder Sequences (PRS's).'' Serdica Journal of Computing 9(1) (2015), 1-26. + + """ + # make sure neither p nor q is 0 + if p == 0 or q == 0: + return [p, q] + + # make sure proper degrees + f, g = p, q + n = deg_f = degree(f, x) + m = deg_g = degree(g, x) + if n == 0 and m == 0: + return [f, g] + if n < m: + n, m, deg_f, deg_g, f, g = m, n, deg_g, deg_f, g, f + if n > 0 and m == 0: + return [f, g] + + # initialize + s1 = sylvester(f, g, x, 1) + sr_list = [f, g] # subresultant list + col_num = 2 * n # columns in sylvester2 + + # make two rows (row0, row1) of poly coefficients + row0 = Poly(f, x, domain = QQ).all_coeffs() + leng0 = len(row0) + for i in range(col_num - leng0): + row0.append(0) + row0 = Matrix([row0]) + row1 = Poly(g,x, domain = QQ).all_coeffs() + leng1 = len(row1) + for i in range(col_num - leng1): + row1.append(0) + row1 = Matrix([row1]) + + # main loop + while deg_g > 0: + # create a small matrix M, and triangularize it + M = create_ma(deg_f, deg_g, row1, row0, col_num) + for i in range(deg_f - deg_g + 1): + M1 = pivot(M, i, i) + M = M1[:, :] + + # treat last row of M as poly; find its degree + d = find_degree(M, deg_f) + if d is None: + return sr_list + exp_deg = deg_g - 1 + + # evaluate one determinant & make coefficients subresultants + sign_value = correct_sign(n, m, s1, exp_deg, exp_deg - d) + poly = row2poly(M[M.rows - 1, :], d, x) + poly = simplify((poly / LC(poly, x)) * sign_value) + + # append poly with subresultant coeffs + sr_list.append(poly) + + # update degrees and rows + deg_f, deg_g = deg_g, d + row0 = row1 + row1 = Poly(poly, x, domain = QQ).all_coeffs() + leng1 = len(row1) + for i in range(col_num - leng1): + row1.append(0) + row1 = Matrix([row1]) + + return sr_list diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..15dfaf70eb3777195b7c9a0930894bb2187bbb50 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/__init__.py @@ -0,0 +1,111 @@ +"""Printing subsystem""" + +from .pretty import pager_print, pretty, pretty_print, pprint, pprint_use_unicode, pprint_try_use_unicode + +from .latex import latex, print_latex, multiline_latex + +from .mathml import mathml, print_mathml + +from .python import python, print_python + +from .pycode import pycode + +from .codeprinter import print_ccode, print_fcode + +from .codeprinter import ccode, fcode, cxxcode, rust_code # noqa:F811 + +from .smtlib import smtlib_code + +from .glsl import glsl_code, print_glsl + +from .rcode import rcode, print_rcode + +from .jscode import jscode, print_jscode + +from .julia import julia_code + +from .mathematica import mathematica_code + +from .octave import octave_code + +from .gtk import print_gtk + +from .preview import preview + +from .repr import srepr + +from .tree import print_tree + +from .str import StrPrinter, sstr, sstrrepr + +from .tableform import TableForm + +from .dot import dotprint + +from .maple import maple_code, print_maple_code + +__all__ = [ + # sympy.printing.pretty + 'pager_print', 'pretty', 'pretty_print', 'pprint', 'pprint_use_unicode', + 'pprint_try_use_unicode', + + # sympy.printing.latex + 'latex', 'print_latex', 'multiline_latex', + + # sympy.printing.mathml + 'mathml', 'print_mathml', + + # sympy.printing.python + 'python', 'print_python', + + # sympy.printing.pycode + 'pycode', + + # sympy.printing.codeprinter + 'ccode', 'print_ccode', 'cxxcode', 'fcode', 'print_fcode', 'rust_code', + + # sympy.printing.smtlib + 'smtlib_code', + + # sympy.printing.glsl + 'glsl_code', 'print_glsl', + + # sympy.printing.rcode + 'rcode', 'print_rcode', + + # sympy.printing.jscode + 'jscode', 'print_jscode', + + # sympy.printing.julia + 'julia_code', + + # sympy.printing.mathematica + 'mathematica_code', + + # sympy.printing.octave + 'octave_code', + + # sympy.printing.gtk + 'print_gtk', + + # sympy.printing.preview + 'preview', + + # sympy.printing.repr + 'srepr', + + # sympy.printing.tree + 'print_tree', + + # sympy.printing.str + 'StrPrinter', 'sstr', 'sstrrepr', + + # sympy.printing.tableform + 'TableForm', + + # sympy.printing.dot + 'dotprint', + + # sympy.printing.maple + 'maple_code', 'print_maple_code', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/aesaracode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/aesaracode.py new file mode 100644 index 0000000000000000000000000000000000000000..1e31c6940a86bd25ef8805420b84c22c5e08bca9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/aesaracode.py @@ -0,0 +1,563 @@ +from __future__ import annotations +import math +from typing import Any + +from sympy.external import import_module +from sympy.printing.printer import Printer +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import is_sequence +import sympy +from functools import partial + + +aesara = import_module('aesara') + +if aesara: + aes = aesara.scalar + aet = aesara.tensor + from aesara.tensor import nlinalg + from aesara.tensor.elemwise import Elemwise + from aesara.tensor.elemwise import DimShuffle + + # `true_divide` replaced `true_div` in Aesara 2.8.11 (released 2023) to + # match NumPy + # XXX: Remove this when not needed to support older versions. + true_divide = getattr(aet, 'true_divide', None) + if true_divide is None: + true_divide = aet.true_div + + mapping = { + sympy.Add: aet.add, + sympy.Mul: aet.mul, + sympy.Abs: aet.abs, + sympy.sign: aet.sgn, + sympy.ceiling: aet.ceil, + sympy.floor: aet.floor, + sympy.log: aet.log, + sympy.exp: aet.exp, + sympy.sqrt: aet.sqrt, + sympy.cos: aet.cos, + sympy.acos: aet.arccos, + sympy.sin: aet.sin, + sympy.asin: aet.arcsin, + sympy.tan: aet.tan, + sympy.atan: aet.arctan, + sympy.atan2: aet.arctan2, + sympy.cosh: aet.cosh, + sympy.acosh: aet.arccosh, + sympy.sinh: aet.sinh, + sympy.asinh: aet.arcsinh, + sympy.tanh: aet.tanh, + sympy.atanh: aet.arctanh, + sympy.re: aet.real, + sympy.im: aet.imag, + sympy.arg: aet.angle, + sympy.erf: aet.erf, + sympy.gamma: aet.gamma, + sympy.loggamma: aet.gammaln, + sympy.Pow: aet.pow, + sympy.Eq: aet.eq, + sympy.StrictGreaterThan: aet.gt, + sympy.StrictLessThan: aet.lt, + sympy.LessThan: aet.le, + sympy.GreaterThan: aet.ge, + sympy.And: aet.bitwise_and, # bitwise + sympy.Or: aet.bitwise_or, # bitwise + sympy.Not: aet.invert, # bitwise + sympy.Xor: aet.bitwise_xor, # bitwise + sympy.Max: aet.maximum, # Sympy accept >2 inputs, Aesara only 2 + sympy.Min: aet.minimum, # Sympy accept >2 inputs, Aesara only 2 + sympy.conjugate: aet.conj, + sympy.core.numbers.ImaginaryUnit: lambda:aet.complex(0,1), + # Matrices + sympy.MatAdd: Elemwise(aes.add), + sympy.HadamardProduct: Elemwise(aes.mul), + sympy.Trace: nlinalg.trace, + sympy.Determinant : nlinalg.det, + sympy.Inverse: nlinalg.matrix_inverse, + sympy.Transpose: DimShuffle((False, False), [1, 0]), + } + + +class AesaraPrinter(Printer): + """ + .. deprecated:: 1.14. + The ``Aesara Code printing`` is deprecated.See its documentation for + more information. See :ref:`deprecated-aesaraprinter` for details. + + Code printer which creates Aesara symbolic expression graphs. + + Parameters + ========== + + cache : dict + Cache dictionary to use. If None (default) will use + the global cache. To create a printer which does not depend on or alter + global state pass an empty dictionary. Note: the dictionary is not + copied on initialization of the printer and will be updated in-place, + so using the same dict object when creating multiple printers or making + multiple calls to :func:`.aesara_code` or :func:`.aesara_function` means + the cache is shared between all these applications. + + Attributes + ========== + + cache : dict + A cache of Aesara variables which have been created for SymPy + symbol-like objects (e.g. :class:`sympy.core.symbol.Symbol` or + :class:`sympy.matrices.expressions.MatrixSymbol`). This is used to + ensure that all references to a given symbol in an expression (or + multiple expressions) are printed as the same Aesara variable, which is + created only once. Symbols are differentiated only by name and type. The + format of the cache's contents should be considered opaque to the user. + """ + printmethod = "_aesara" + + def __init__(self, *args, **kwargs): + self.cache = kwargs.pop('cache', {}) + super().__init__(*args, **kwargs) + + def _get_key(self, s, name=None, dtype=None, broadcastable=None): + """ Get the cache key for a SymPy object. + + Parameters + ========== + + s : sympy.core.basic.Basic + SymPy object to get key for. + + name : str + Name of object, if it does not have a ``name`` attribute. + """ + + if name is None: + name = s.name + + return (name, type(s), s.args, dtype, broadcastable) + + def _get_or_create(self, s, name=None, dtype=None, broadcastable=None): + """ + Get the Aesara variable for a SymPy symbol from the cache, or create it + if it does not exist. + """ + + # Defaults + if name is None: + name = s.name + if dtype is None: + dtype = 'floatX' + if broadcastable is None: + broadcastable = () + + key = self._get_key(s, name, dtype=dtype, broadcastable=broadcastable) + + if key in self.cache: + return self.cache[key] + + value = aet.tensor(name=name, dtype=dtype, shape=broadcastable) + self.cache[key] = value + return value + + def _print_Symbol(self, s, **kwargs): + dtype = kwargs.get('dtypes', {}).get(s) + bc = kwargs.get('broadcastables', {}).get(s) + return self._get_or_create(s, dtype=dtype, broadcastable=bc) + + def _print_AppliedUndef(self, s, **kwargs): + name = str(type(s)) + '_' + str(s.args[0]) + dtype = kwargs.get('dtypes', {}).get(s) + bc = kwargs.get('broadcastables', {}).get(s) + return self._get_or_create(s, name=name, dtype=dtype, broadcastable=bc) + + def _print_Basic(self, expr, **kwargs): + op = mapping[type(expr)] + children = [self._print(arg, **kwargs) for arg in expr.args] + return op(*children) + + def _print_Number(self, n, **kwargs): + # Integers already taken care of below, interpret as float + return float(n.evalf()) + + def _print_MatrixSymbol(self, X, **kwargs): + dtype = kwargs.get('dtypes', {}).get(X) + return self._get_or_create(X, dtype=dtype, broadcastable=(None, None)) + + def _print_DenseMatrix(self, X, **kwargs): + if not hasattr(aet, 'stacklists'): + raise NotImplementedError( + "Matrix translation not yet supported in this version of Aesara") + + return aet.stacklists([ + [self._print(arg, **kwargs) for arg in L] + for L in X.tolist() + ]) + + _print_ImmutableMatrix = _print_ImmutableDenseMatrix = _print_DenseMatrix + + def _print_MatMul(self, expr, **kwargs): + children = [self._print(arg, **kwargs) for arg in expr.args] + result = children[0] + for child in children[1:]: + result = aet.dot(result, child) + return result + + def _print_MatPow(self, expr, **kwargs): + children = [self._print(arg, **kwargs) for arg in expr.args] + result = 1 + if isinstance(children[1], int) and children[1] > 0: + for i in range(children[1]): + result = aet.dot(result, children[0]) + else: + raise NotImplementedError('''Only non-negative integer + powers of matrices can be handled by Aesara at the moment''') + return result + + def _print_MatrixSlice(self, expr, **kwargs): + parent = self._print(expr.parent, **kwargs) + rowslice = self._print(slice(*expr.rowslice), **kwargs) + colslice = self._print(slice(*expr.colslice), **kwargs) + return parent[rowslice, colslice] + + def _print_BlockMatrix(self, expr, **kwargs): + nrows, ncols = expr.blocks.shape + blocks = [[self._print(expr.blocks[r, c], **kwargs) + for c in range(ncols)] + for r in range(nrows)] + return aet.join(0, *[aet.join(1, *row) for row in blocks]) + + + def _print_slice(self, expr, **kwargs): + return slice(*[self._print(i, **kwargs) + if isinstance(i, sympy.Basic) else i + for i in (expr.start, expr.stop, expr.step)]) + + def _print_Pi(self, expr, **kwargs): + return math.pi + + def _print_Piecewise(self, expr, **kwargs): + import numpy as np + e, cond = expr.args[0].args # First condition and corresponding value + + # Print conditional expression and value for first condition + p_cond = self._print(cond, **kwargs) + p_e = self._print(e, **kwargs) + + # One condition only + if len(expr.args) == 1: + # Return value if condition else NaN + return aet.switch(p_cond, p_e, np.nan) + + # Return value_1 if condition_1 else evaluate remaining conditions + p_remaining = self._print(sympy.Piecewise(*expr.args[1:]), **kwargs) + return aet.switch(p_cond, p_e, p_remaining) + + def _print_Rational(self, expr, **kwargs): + return true_divide(self._print(expr.p, **kwargs), + self._print(expr.q, **kwargs)) + + def _print_Integer(self, expr, **kwargs): + return expr.p + + def _print_factorial(self, expr, **kwargs): + return self._print(sympy.gamma(expr.args[0] + 1), **kwargs) + + def _print_Derivative(self, deriv, **kwargs): + from aesara.gradient import Rop + + rv = self._print(deriv.expr, **kwargs) + for var in deriv.variables: + var = self._print(var, **kwargs) + rv = Rop(rv, var, aet.ones_like(var)) + return rv + + def emptyPrinter(self, expr): + return expr + + def doprint(self, expr, dtypes=None, broadcastables=None): + """ Convert a SymPy expression to a Aesara graph variable. + + The ``dtypes`` and ``broadcastables`` arguments are used to specify the + data type, dimension, and broadcasting behavior of the Aesara variables + corresponding to the free symbols in ``expr``. Each is a mapping from + SymPy symbols to the value of the corresponding argument to + ``aesara.tensor.var.TensorVariable``. + + See the corresponding `documentation page`__ for more information on + broadcasting in Aesara. + + + .. __: https://aesara.readthedocs.io/en/latest/reference/tensor/shapes.html#broadcasting + + Parameters + ========== + + expr : sympy.core.expr.Expr + SymPy expression to print. + + dtypes : dict + Mapping from SymPy symbols to Aesara datatypes to use when creating + new Aesara variables for those symbols. Corresponds to the ``dtype`` + argument to ``aesara.tensor.var.TensorVariable``. Defaults to ``'floatX'`` + for symbols not included in the mapping. + + broadcastables : dict + Mapping from SymPy symbols to the value of the ``broadcastable`` + argument to ``aesara.tensor.var.TensorVariable`` to use when creating Aesara + variables for those symbols. Defaults to the empty tuple for symbols + not included in the mapping (resulting in a scalar). + + Returns + ======= + + aesara.graph.basic.Variable + A variable corresponding to the expression's value in a Aesara + symbolic expression graph. + + """ + if dtypes is None: + dtypes = {} + if broadcastables is None: + broadcastables = {} + + return self._print(expr, dtypes=dtypes, broadcastables=broadcastables) + + +global_cache: dict[Any, Any] = {} + + +def aesara_code(expr, cache=None, **kwargs): + """ + Convert a SymPy expression into a Aesara graph variable. + + Parameters + ========== + + expr : sympy.core.expr.Expr + SymPy expression object to convert. + + cache : dict + Cached Aesara variables (see :class:`AesaraPrinter.cache + `). Defaults to the module-level global cache. + + dtypes : dict + Passed to :meth:`.AesaraPrinter.doprint`. + + broadcastables : dict + Passed to :meth:`.AesaraPrinter.doprint`. + + Returns + ======= + + aesara.graph.basic.Variable + A variable corresponding to the expression's value in a Aesara symbolic + expression graph. + + """ + sympy_deprecation_warning( + """ + The aesara_code function is deprecated. + """, + deprecated_since_version="1.14", + active_deprecations_target='deprecated-aesaraprinter', + ) + + if not aesara: + raise ImportError("aesara is required for aesara_code") + + if cache is None: + cache = global_cache + + return AesaraPrinter(cache=cache, settings={}).doprint(expr, **kwargs) + + +def dim_handling(inputs, dim=None, dims=None, broadcastables=None): + r""" + Get value of ``broadcastables`` argument to :func:`.aesara_code` from + keyword arguments to :func:`.aesara_function`. + + Included for backwards compatibility. + + Parameters + ========== + + inputs + Sequence of input symbols. + + dim : int + Common number of dimensions for all inputs. Overrides other arguments + if given. + + dims : dict + Mapping from input symbols to number of dimensions. Overrides + ``broadcastables`` argument if given. + + broadcastables : dict + Explicit value of ``broadcastables`` argument to + :meth:`.AesaraPrinter.doprint`. If not None function will return this value unchanged. + + Returns + ======= + dict + Dictionary mapping elements of ``inputs`` to their "broadcastable" + values (tuple of ``bool``\ s). + """ + if dim is not None: + return dict.fromkeys(inputs, (False,) * dim) + + if dims is not None: + maxdim = max(dims.values()) + return { + s: (False,) * d + (True,) * (maxdim - d) + for s, d in dims.items() + } + + if broadcastables is not None: + return broadcastables + + return {} + + +def aesara_function(inputs, outputs, scalar=False, *, + dim=None, dims=None, broadcastables=None, **kwargs): + """ + Create a Aesara function from SymPy expressions. + + The inputs and outputs are converted to Aesara variables using + :func:`.aesara_code` and then passed to ``aesara.function``. + + Parameters + ========== + + inputs + Sequence of symbols which constitute the inputs of the function. + + outputs + Sequence of expressions which constitute the outputs(s) of the + function. The free symbols of each expression must be a subset of + ``inputs``. + + scalar : bool + Convert 0-dimensional arrays in output to scalars. This will return a + Python wrapper function around the Aesara function object. + + cache : dict + Cached Aesara variables (see :class:`AesaraPrinter.cache + `). Defaults to the module-level global cache. + + dtypes : dict + Passed to :meth:`.AesaraPrinter.doprint`. + + broadcastables : dict + Passed to :meth:`.AesaraPrinter.doprint`. + + dims : dict + Alternative to ``broadcastables`` argument. Mapping from elements of + ``inputs`` to integers indicating the dimension of their associated + arrays/tensors. Overrides ``broadcastables`` argument if given. + + dim : int + Another alternative to the ``broadcastables`` argument. Common number of + dimensions to use for all arrays/tensors. + ``aesara_function([x, y], [...], dim=2)`` is equivalent to using + ``broadcastables={x: (False, False), y: (False, False)}``. + + Returns + ======= + callable + A callable object which takes values of ``inputs`` as positional + arguments and returns an output array for each of the expressions + in ``outputs``. If ``outputs`` is a single expression the function will + return a Numpy array, if it is a list of multiple expressions the + function will return a list of arrays. See description of the ``squeeze`` + argument above for the behavior when a single output is passed in a list. + The returned object will either be an instance of + ``aesara.compile.function.types.Function`` or a Python wrapper + function around one. In both cases, the returned value will have a + ``aesara_function`` attribute which points to the return value of + ``aesara.function``. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.printing.aesaracode import aesara_function + + A simple function with one input and one output: + + >>> f1 = aesara_function([x], [x**2 - 1], scalar=True) + >>> f1(3) + 8.0 + + A function with multiple inputs and one output: + + >>> f2 = aesara_function([x, y, z], [(x**z + y**z)**(1/z)], scalar=True) + >>> f2(3, 4, 2) + 5.0 + + A function with multiple inputs and multiple outputs: + + >>> f3 = aesara_function([x, y], [x**2 + y**2, x**2 - y**2], scalar=True) + >>> f3(2, 3) + [13.0, -5.0] + + See also + ======== + + dim_handling + + """ + sympy_deprecation_warning( + """ + The aesara_function function is deprecated. + """, + deprecated_since_version="1.14", + active_deprecations_target='deprecated-aesaraprinter', + ) + + if not aesara: + raise ImportError("Aesara is required for aesara_function") + + # Pop off non-aesara keyword args + cache = kwargs.pop('cache', {}) + dtypes = kwargs.pop('dtypes', {}) + + broadcastables = dim_handling( + inputs, dim=dim, dims=dims, broadcastables=broadcastables, + ) + + # Print inputs/outputs + code = partial(aesara_code, cache=cache, dtypes=dtypes, + broadcastables=broadcastables) + tinputs = list(map(code, inputs)) + toutputs = list(map(code, outputs)) + + #fix constant expressions as variables + toutputs = [output if isinstance(output, aesara.graph.basic.Variable) else aet.as_tensor_variable(output) for output in toutputs] + + if len(toutputs) == 1: + toutputs = toutputs[0] + + # Compile aesara func + func = aesara.function(tinputs, toutputs, **kwargs) + + is_0d = [len(o.variable.broadcastable) == 0 for o in func.outputs] + + # No wrapper required + if not scalar or not any(is_0d): + func.aesara_function = func + return func + + # Create wrapper to convert 0-dimensional outputs to scalars + def wrapper(*args): + out = func(*args) + # out can be array(1.0) or [array(1.0), array(2.0)] + + if is_sequence(out): + return [o[()] if is_0d[i] else o for i, o in enumerate(out)] + else: + return out[()] + + wrapper.__wrapped__ = func + wrapper.__doc__ = func.__doc__ + wrapper.aesara_function = func + return wrapper diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/c.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/c.py new file mode 100644 index 0000000000000000000000000000000000000000..34c4b8f021073aeee7672248838557b5fa85fbae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/c.py @@ -0,0 +1,747 @@ +""" +C code printer + +The C89CodePrinter & C99CodePrinter converts single SymPy expressions into +single C expressions, using the functions defined in math.h where possible. + +A complete code generator, which uses ccode extensively, can be found in +sympy.utilities.codegen. The codegen module can be used to generate complete +source code files that are compilable without further modifications. + + +""" + +from __future__ import annotations +from typing import Any + +from functools import wraps +from itertools import chain + +from sympy.core import S +from sympy.core.numbers import equal_valued, Float +from sympy.codegen.ast import ( + Assignment, Pointer, Variable, Declaration, Type, + real, complex_, integer, bool_, float32, float64, float80, + complex64, complex128, intc, value_const, pointer_const, + int8, int16, int32, int64, uint8, uint16, uint32, uint64, untyped, + none +) +from sympy.printing.codeprinter import CodePrinter, requires +from sympy.printing.precedence import precedence, PRECEDENCE +from sympy.sets.fancysets import Range + +# These are defined in the other file so we can avoid importing sympy.codegen +# from the top-level 'import sympy'. Export them here as well. +from sympy.printing.codeprinter import ccode, print_ccode # noqa:F401 + +# dictionary mapping SymPy function to (argument_conditions, C_function). +# Used in C89CodePrinter._print_Function(self) +known_functions_C89 = { + "Abs": [(lambda x: not x.is_integer, "fabs"), (lambda x: x.is_integer, "abs")], + "sin": "sin", + "cos": "cos", + "tan": "tan", + "asin": "asin", + "acos": "acos", + "atan": "atan", + "atan2": "atan2", + "exp": "exp", + "log": "log", + "log10": "log10", + "sinh": "sinh", + "cosh": "cosh", + "tanh": "tanh", + "floor": "floor", + "ceiling": "ceil", + "sqrt": "sqrt", # To enable automatic rewrites +} + +known_functions_C99 = dict(known_functions_C89, **{ + 'exp2': 'exp2', + 'expm1': 'expm1', + 'log2': 'log2', + 'log1p': 'log1p', + 'Cbrt': 'cbrt', + 'hypot': 'hypot', + 'fma': 'fma', + 'loggamma': 'lgamma', + 'erfc': 'erfc', + 'Max': 'fmax', + 'Min': 'fmin', + "asinh": "asinh", + "acosh": "acosh", + "atanh": "atanh", + "erf": "erf", + "gamma": "tgamma", +}) + +# These are the core reserved words in the C language. Taken from: +# https://en.cppreference.com/w/c/keyword + +reserved_words = [ + 'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', + 'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'int', + 'long', 'register', 'return', 'short', 'signed', 'sizeof', 'static', + 'struct', 'entry', # never standardized, we'll leave it here anyway + 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while' +] + +reserved_words_c99 = ['inline', 'restrict'] + +def get_math_macros(): + """ Returns a dictionary with math-related macros from math.h/cmath + + Note that these macros are not strictly required by the C/C++-standard. + For MSVC they are enabled by defining "_USE_MATH_DEFINES" (preferably + via a compilation flag). + + Returns + ======= + + Dictionary mapping SymPy expressions to strings (macro names) + + """ + from sympy.codegen.cfunctions import log2, Sqrt + from sympy.functions.elementary.exponential import log + from sympy.functions.elementary.miscellaneous import sqrt + + return { + S.Exp1: 'M_E', + log2(S.Exp1): 'M_LOG2E', + 1/log(2): 'M_LOG2E', + log(2): 'M_LN2', + log(10): 'M_LN10', + S.Pi: 'M_PI', + S.Pi/2: 'M_PI_2', + S.Pi/4: 'M_PI_4', + 1/S.Pi: 'M_1_PI', + 2/S.Pi: 'M_2_PI', + 2/sqrt(S.Pi): 'M_2_SQRTPI', + 2/Sqrt(S.Pi): 'M_2_SQRTPI', + sqrt(2): 'M_SQRT2', + Sqrt(2): 'M_SQRT2', + 1/sqrt(2): 'M_SQRT1_2', + 1/Sqrt(2): 'M_SQRT1_2' + } + + +def _as_macro_if_defined(meth): + """ Decorator for printer methods + + When a Printer's method is decorated using this decorator the expressions printed + will first be looked for in the attribute ``math_macros``, and if present it will + print the macro name in ``math_macros`` followed by a type suffix for the type + ``real``. e.g. printing ``sympy.pi`` would print ``M_PIl`` if real is mapped to float80. + + """ + @wraps(meth) + def _meth_wrapper(self, expr, **kwargs): + if expr in self.math_macros: + return '%s%s' % (self.math_macros[expr], self._get_math_macro_suffix(real)) + else: + return meth(self, expr, **kwargs) + + return _meth_wrapper + + +class C89CodePrinter(CodePrinter): + """A printer to convert Python expressions to strings of C code""" + printmethod = "_ccode" + language = "C" + standard = "C89" + reserved_words = set(reserved_words) + + _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{ + 'precision': 17, + 'user_functions': {}, + 'contract': True, + 'dereference': set(), + 'error_on_reserved': False, + }) + + type_aliases = { + real: float64, + complex_: complex128, + integer: intc + } + + type_mappings: dict[Type, Any] = { + real: 'double', + intc: 'int', + float32: 'float', + float64: 'double', + integer: 'int', + bool_: 'bool', + int8: 'int8_t', + int16: 'int16_t', + int32: 'int32_t', + int64: 'int64_t', + uint8: 'int8_t', + uint16: 'int16_t', + uint32: 'int32_t', + uint64: 'int64_t', + } + + type_headers = { + bool_: {'stdbool.h'}, + int8: {'stdint.h'}, + int16: {'stdint.h'}, + int32: {'stdint.h'}, + int64: {'stdint.h'}, + uint8: {'stdint.h'}, + uint16: {'stdint.h'}, + uint32: {'stdint.h'}, + uint64: {'stdint.h'}, + } + + # Macros needed to be defined when using a Type + type_macros: dict[Type, tuple[str, ...]] = {} + + type_func_suffixes = { + float32: 'f', + float64: '', + float80: 'l' + } + + type_literal_suffixes = { + float32: 'F', + float64: '', + float80: 'L' + } + + type_math_macro_suffixes = { + float80: 'l' + } + + math_macros = None + + _ns = '' # namespace, C++ uses 'std::' + # known_functions-dict to copy + _kf: dict[str, Any] = known_functions_C89 + + def __init__(self, settings=None): + settings = settings or {} + if self.math_macros is None: + self.math_macros = settings.pop('math_macros', get_math_macros()) + self.type_aliases = dict(chain(self.type_aliases.items(), + settings.pop('type_aliases', {}).items())) + self.type_mappings = dict(chain(self.type_mappings.items(), + settings.pop('type_mappings', {}).items())) + self.type_headers = dict(chain(self.type_headers.items(), + settings.pop('type_headers', {}).items())) + self.type_macros = dict(chain(self.type_macros.items(), + settings.pop('type_macros', {}).items())) + self.type_func_suffixes = dict(chain(self.type_func_suffixes.items(), + settings.pop('type_func_suffixes', {}).items())) + self.type_literal_suffixes = dict(chain(self.type_literal_suffixes.items(), + settings.pop('type_literal_suffixes', {}).items())) + self.type_math_macro_suffixes = dict(chain(self.type_math_macro_suffixes.items(), + settings.pop('type_math_macro_suffixes', {}).items())) + super().__init__(settings) + self.known_functions = dict(self._kf, **settings.get('user_functions', {})) + self._dereference = set(settings.get('dereference', [])) + self.headers = set() + self.libraries = set() + self.macros = set() + + def _rate_index_position(self, p): + return p*5 + + def _get_statement(self, codestring): + """ Get code string as a statement - i.e. ending with a semicolon. """ + return codestring if codestring.endswith(';') else codestring + ';' + + def _get_comment(self, text): + return "/* {} */".format(text) + + def _declare_number_const(self, name, value): + type_ = self.type_aliases[real] + var = Variable(name, type=type_, value=value.evalf(type_.decimal_dig), attrs={value_const}) + decl = Declaration(var) + return self._get_statement(self._print(decl)) + + def _format_code(self, lines): + return self.indent_code(lines) + + def _traverse_matrix_indices(self, mat): + rows, cols = mat.shape + return ((i, j) for i in range(rows) for j in range(cols)) + + @_as_macro_if_defined + def _print_Mul(self, expr, **kwargs): + return super()._print_Mul(expr, **kwargs) + + @_as_macro_if_defined + def _print_Pow(self, expr): + if "Pow" in self.known_functions: + return self._print_Function(expr) + PREC = precedence(expr) + suffix = self._get_func_suffix(real) + if equal_valued(expr.exp, -1): + return '%s/%s' % (self._print_Float(Float(1.0)), self.parenthesize(expr.base, PREC)) + elif equal_valued(expr.exp, 0.5): + return '%ssqrt%s(%s)' % (self._ns, suffix, self._print(expr.base)) + elif expr.exp == S.One/3 and self.standard != 'C89': + return '%scbrt%s(%s)' % (self._ns, suffix, self._print(expr.base)) + else: + return '%spow%s(%s, %s)' % (self._ns, suffix, self._print(expr.base), + self._print(expr.exp)) + + def _print_Mod(self, expr): + num, den = expr.args + if num.is_integer and den.is_integer: + PREC = precedence(expr) + snum, sden = [self.parenthesize(arg, PREC) for arg in expr.args] + # % is remainder (same sign as numerator), not modulo (same sign as + # denominator), in C. Hence, % only works as modulo if both numbers + # have the same sign + if (num.is_nonnegative and den.is_nonnegative or + num.is_nonpositive and den.is_nonpositive): + return f"{snum} % {sden}" + return f"(({snum} % {sden}) + {sden}) % {sden}" + # Not guaranteed integer + return self._print_math_func(expr, known='fmod') + + def _print_Rational(self, expr): + p, q = int(expr.p), int(expr.q) + suffix = self._get_literal_suffix(real) + return '%d.0%s/%d.0%s' % (p, suffix, q, suffix) + + def _print_Indexed(self, expr): + # calculate index for 1d array + offset = getattr(expr.base, 'offset', S.Zero) + strides = getattr(expr.base, 'strides', None) + indices = expr.indices + + if strides is None or isinstance(strides, str): + dims = expr.shape + shift = S.One + temp = () + if strides == 'C' or strides is None: + traversal = reversed(range(expr.rank)) + indices = indices[::-1] + elif strides == 'F': + traversal = range(expr.rank) + + for i in traversal: + temp += (shift,) + shift *= dims[i] + strides = temp + flat_index = sum(x[0]*x[1] for x in zip(indices, strides)) + offset + return "%s[%s]" % (self._print(expr.base.label), + self._print(flat_index)) + + @_as_macro_if_defined + def _print_NumberSymbol(self, expr): + return super()._print_NumberSymbol(expr) + + def _print_Infinity(self, expr): + return 'HUGE_VAL' + + def _print_NegativeInfinity(self, expr): + return '-HUGE_VAL' + + def _print_Piecewise(self, expr): + if expr.args[-1].cond != True: + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + lines = [] + if expr.has(Assignment): + for i, (e, c) in enumerate(expr.args): + if i == 0: + lines.append("if (%s) {" % self._print(c)) + elif i == len(expr.args) - 1 and c == True: + lines.append("else {") + else: + lines.append("else if (%s) {" % self._print(c)) + code0 = self._print(e) + lines.append(code0) + lines.append("}") + return "\n".join(lines) + else: + # The piecewise was used in an expression, need to do inline + # operators. This has the downside that inline operators will + # not work for statements that span multiple lines (Matrix or + # Indexed expressions). + ecpairs = ["((%s) ? (\n%s\n)\n" % (self._print(c), + self._print(e)) + for e, c in expr.args[:-1]] + last_line = ": (\n%s\n)" % self._print(expr.args[-1].expr) + return ": ".join(ecpairs) + last_line + " ".join([")"*len(ecpairs)]) + + def _print_ITE(self, expr): + from sympy.functions import Piecewise + return self._print(expr.rewrite(Piecewise, deep=False)) + + def _print_MatrixElement(self, expr): + return "{}[{}]".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"], + strict=True), expr.j + expr.i*expr.parent.shape[1]) + + def _print_Symbol(self, expr): + name = super()._print_Symbol(expr) + if expr in self._settings['dereference']: + return '(*{})'.format(name) + else: + return name + + def _print_Relational(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + op = expr.rel_op + return "{} {} {}".format(lhs_code, op, rhs_code) + + def _print_For(self, expr): + target = self._print(expr.target) + if isinstance(expr.iterable, Range): + start, stop, step = expr.iterable.args + else: + raise NotImplementedError("Only iterable currently supported is Range") + body = self._print(expr.body) + return ('for ({target} = {start}; {target} < {stop}; {target} += ' + '{step}) {{\n{body}\n}}').format(target=target, start=start, + stop=stop, step=step, body=body) + + def _print_sign(self, func): + return '((({0}) > 0) - (({0}) < 0))'.format(self._print(func.args[0])) + + def _print_Max(self, expr): + if "Max" in self.known_functions: + return self._print_Function(expr) + def inner_print_max(args): # The more natural abstraction of creating + if len(args) == 1: # and printing smaller Max objects is slow + return self._print(args[0]) # when there are many arguments. + half = len(args) // 2 + return "((%(a)s > %(b)s) ? %(a)s : %(b)s)" % { + 'a': inner_print_max(args[:half]), + 'b': inner_print_max(args[half:]) + } + return inner_print_max(expr.args) + + def _print_Min(self, expr): + if "Min" in self.known_functions: + return self._print_Function(expr) + def inner_print_min(args): # The more natural abstraction of creating + if len(args) == 1: # and printing smaller Min objects is slow + return self._print(args[0]) # when there are many arguments. + half = len(args) // 2 + return "((%(a)s < %(b)s) ? %(a)s : %(b)s)" % { + 'a': inner_print_min(args[:half]), + 'b': inner_print_min(args[half:]) + } + return inner_print_min(expr.args) + + def indent_code(self, code): + """Accepts a string of code or a list of code lines""" + + if isinstance(code, str): + code_lines = self.indent_code(code.splitlines(True)) + return ''.join(code_lines) + + tab = " " + inc_token = ('{', '(', '{\n', '(\n') + dec_token = ('}', ')') + + code = [line.lstrip(' \t') for line in code] + + increase = [int(any(map(line.endswith, inc_token))) for line in code] + decrease = [int(any(map(line.startswith, dec_token))) for line in code] + + pretty = [] + level = 0 + for n, line in enumerate(code): + if line in ('', '\n'): + pretty.append(line) + continue + level -= decrease[n] + pretty.append("%s%s" % (tab*level, line)) + level += increase[n] + return pretty + + def _get_func_suffix(self, type_): + return self.type_func_suffixes[self.type_aliases.get(type_, type_)] + + def _get_literal_suffix(self, type_): + return self.type_literal_suffixes[self.type_aliases.get(type_, type_)] + + def _get_math_macro_suffix(self, type_): + alias = self.type_aliases.get(type_, type_) + dflt = self.type_math_macro_suffixes.get(alias, '') + return self.type_math_macro_suffixes.get(type_, dflt) + + def _print_Tuple(self, expr): + return '{'+', '.join(self._print(e) for e in expr)+'}' + + _print_List = _print_Tuple + + def _print_Type(self, type_): + self.headers.update(self.type_headers.get(type_, set())) + self.macros.update(self.type_macros.get(type_, set())) + return self._print(self.type_mappings.get(type_, type_.name)) + + def _print_Declaration(self, decl): + from sympy.codegen.cnodes import restrict + var = decl.variable + val = var.value + if var.type == untyped: + raise ValueError("C does not support untyped variables") + + if isinstance(var, Pointer): + result = '{vc}{t} *{pc} {r}{s}'.format( + vc='const ' if value_const in var.attrs else '', + t=self._print(var.type), + pc=' const' if pointer_const in var.attrs else '', + r='restrict ' if restrict in var.attrs else '', + s=self._print(var.symbol) + ) + elif isinstance(var, Variable): + result = '{vc}{t} {s}'.format( + vc='const ' if value_const in var.attrs else '', + t=self._print(var.type), + s=self._print(var.symbol) + ) + else: + raise NotImplementedError("Unknown type of var: %s" % type(var)) + if val != None: # Must be "!= None", cannot be "is not None" + result += ' = %s' % self._print(val) + return result + + def _print_Float(self, flt): + type_ = self.type_aliases.get(real, real) + self.macros.update(self.type_macros.get(type_, set())) + suffix = self._get_literal_suffix(type_) + num = str(flt.evalf(type_.decimal_dig)) + if 'e' not in num and '.' not in num: + num += '.0' + num_parts = num.split('e') + num_parts[0] = num_parts[0].rstrip('0') + if num_parts[0].endswith('.'): + num_parts[0] += '0' + return 'e'.join(num_parts) + suffix + + @requires(headers={'stdbool.h'}) + def _print_BooleanTrue(self, expr): + return 'true' + + @requires(headers={'stdbool.h'}) + def _print_BooleanFalse(self, expr): + return 'false' + + def _print_Element(self, elem): + if elem.strides == None: # Must be "== None", cannot be "is None" + if elem.offset != None: # Must be "!= None", cannot be "is not None" + raise ValueError("Expected strides when offset is given") + idxs = ']['.join((self._print(arg) for arg in elem.indices)) + else: + global_idx = sum(i*s for i, s in zip(elem.indices, elem.strides)) + if elem.offset != None: # Must be "!= None", cannot be "is not None" + global_idx += elem.offset + idxs = self._print(global_idx) + + return "{symb}[{idxs}]".format( + symb=self._print(elem.symbol), + idxs=idxs + ) + + def _print_CodeBlock(self, expr): + """ Elements of code blocks printed as statements. """ + return '\n'.join([self._get_statement(self._print(i)) for i in expr.args]) + + def _print_While(self, expr): + return 'while ({condition}) {{\n{body}\n}}'.format(**expr.kwargs( + apply=lambda arg: self._print(arg))) + + def _print_Scope(self, expr): + return '{\n%s\n}' % self._print_CodeBlock(expr.body) + + @requires(headers={'stdio.h'}) + def _print_Print(self, expr): + if expr.file == none: + template = 'printf({fmt}, {pargs})' + else: + template = 'fprintf(%(out)s, {fmt}, {pargs})' % { + 'out': self._print(expr.file) + } + return template.format( + fmt="%s\n" if expr.format_string == none else self._print(expr.format_string), + pargs=', '.join((self._print(arg) for arg in expr.print_args)) + ) + + def _print_Stream(self, strm): + return strm.name + + def _print_FunctionPrototype(self, expr): + pars = ', '.join((self._print(Declaration(arg)) for arg in expr.parameters)) + return "%s %s(%s)" % ( + tuple((self._print(arg) for arg in (expr.return_type, expr.name))) + (pars,) + ) + + def _print_FunctionDefinition(self, expr): + return "%s%s" % (self._print_FunctionPrototype(expr), + self._print_Scope(expr)) + + def _print_Return(self, expr): + arg, = expr.args + return 'return %s' % self._print(arg) + + def _print_CommaOperator(self, expr): + return '(%s)' % ', '.join((self._print(arg) for arg in expr.args)) + + def _print_Label(self, expr): + if expr.body == none: + return '%s:' % str(expr.name) + if len(expr.body.args) == 1: + return '%s:\n%s' % (str(expr.name), self._print_CodeBlock(expr.body)) + return '%s:\n{\n%s\n}' % (str(expr.name), self._print_CodeBlock(expr.body)) + + def _print_goto(self, expr): + return 'goto %s' % expr.label.name + + def _print_PreIncrement(self, expr): + arg, = expr.args + return '++(%s)' % self._print(arg) + + def _print_PostIncrement(self, expr): + arg, = expr.args + return '(%s)++' % self._print(arg) + + def _print_PreDecrement(self, expr): + arg, = expr.args + return '--(%s)' % self._print(arg) + + def _print_PostDecrement(self, expr): + arg, = expr.args + return '(%s)--' % self._print(arg) + + def _print_struct(self, expr): + return "%(keyword)s %(name)s {\n%(lines)s}" % { + "keyword": expr.__class__.__name__, "name": expr.name, "lines": ';\n'.join( + [self._print(decl) for decl in expr.declarations] + ['']) + } + + def _print_BreakToken(self, _): + return 'break' + + def _print_ContinueToken(self, _): + return 'continue' + + _print_union = _print_struct + +class C99CodePrinter(C89CodePrinter): + standard = 'C99' + reserved_words = set(reserved_words + reserved_words_c99) + type_mappings=dict(chain(C89CodePrinter.type_mappings.items(), { + complex64: 'float complex', + complex128: 'double complex', + }.items())) + type_headers = dict(chain(C89CodePrinter.type_headers.items(), { + complex64: {'complex.h'}, + complex128: {'complex.h'} + }.items())) + + # known_functions-dict to copy + _kf: dict[str, Any] = known_functions_C99 + + # functions with versions with 'f' and 'l' suffixes: + _prec_funcs = ('fabs fmod remainder remquo fma fmax fmin fdim nan exp exp2' + ' expm1 log log10 log2 log1p pow sqrt cbrt hypot sin cos tan' + ' asin acos atan atan2 sinh cosh tanh asinh acosh atanh erf' + ' erfc tgamma lgamma ceil floor trunc round nearbyint rint' + ' frexp ldexp modf scalbn ilogb logb nextafter copysign').split() + + def _print_Infinity(self, expr): + return 'INFINITY' + + def _print_NegativeInfinity(self, expr): + return '-INFINITY' + + def _print_NaN(self, expr): + return 'NAN' + + # tgamma was already covered by 'known_functions' dict + + @requires(headers={'math.h'}, libraries={'m'}) + @_as_macro_if_defined + def _print_math_func(self, expr, nest=False, known=None): + if known is None: + known = self.known_functions[expr.__class__.__name__] + if not isinstance(known, str): + for cb, name in known: + if cb(*expr.args): + known = name + break + else: + raise ValueError("No matching printer") + try: + return known(self, *expr.args) + except TypeError: + suffix = self._get_func_suffix(real) if self._ns + known in self._prec_funcs else '' + + if nest: + args = self._print(expr.args[0]) + if len(expr.args) > 1: + paren_pile = '' + for curr_arg in expr.args[1:-1]: + paren_pile += ')' + args += ', {ns}{name}{suffix}({next}'.format( + ns=self._ns, + name=known, + suffix=suffix, + next = self._print(curr_arg) + ) + args += ', %s%s' % ( + self._print(expr.func(expr.args[-1])), + paren_pile + ) + else: + args = ', '.join((self._print(arg) for arg in expr.args)) + return '{ns}{name}{suffix}({args})'.format( + ns=self._ns, + name=known, + suffix=suffix, + args=args + ) + + def _print_Max(self, expr): + return self._print_math_func(expr, nest=True) + + def _print_Min(self, expr): + return self._print_math_func(expr, nest=True) + + def _get_loop_opening_ending(self, indices): + open_lines = [] + close_lines = [] + loopstart = "for (int %(var)s=%(start)s; %(var)s<%(end)s; %(var)s++){" # C99 + for i in indices: + # C arrays start at 0 and end at dimension-1 + open_lines.append(loopstart % { + 'var': self._print(i.label), + 'start': self._print(i.lower), + 'end': self._print(i.upper + 1)}) + close_lines.append("}") + return open_lines, close_lines + + +for k in ('Abs Sqrt exp exp2 expm1 log log10 log2 log1p Cbrt hypot fma' + ' loggamma sin cos tan asin acos atan atan2 sinh cosh tanh asinh acosh ' + 'atanh erf erfc loggamma gamma ceiling floor').split(): + setattr(C99CodePrinter, '_print_%s' % k, C99CodePrinter._print_math_func) + + +class C11CodePrinter(C99CodePrinter): + + @requires(headers={'stdalign.h'}) + def _print_alignof(self, expr): + arg, = expr.args + return 'alignof(%s)' % self._print(arg) + + +c_code_printers = { + 'c89': C89CodePrinter, + 'c99': C99CodePrinter, + 'c11': C11CodePrinter +} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/codeprinter.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/codeprinter.py new file mode 100644 index 0000000000000000000000000000000000000000..1faaa0f054cbd8ff438b90e914808f720d2da90a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/codeprinter.py @@ -0,0 +1,1039 @@ +from __future__ import annotations +from typing import Any + +from functools import wraps + +from sympy.core import Add, Mul, Pow, S, sympify, Float +from sympy.core.basic import Basic +from sympy.core.expr import Expr, UnevaluatedExpr +from sympy.core.function import Lambda +from sympy.core.mul import _keep_coeff +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Symbol +from sympy.functions.elementary.complexes import re +from sympy.printing.str import StrPrinter +from sympy.printing.precedence import precedence, PRECEDENCE + + +class requires: + """ Decorator for registering requirements on print methods. """ + def __init__(self, **kwargs): + self._req = kwargs + + def __call__(self, method): + def _method_wrapper(self_, *args, **kwargs): + for k, v in self._req.items(): + getattr(self_, k).update(v) + return method(self_, *args, **kwargs) + return wraps(method)(_method_wrapper) + + +class AssignmentError(Exception): + """ + Raised if an assignment variable for a loop is missing. + """ + pass + +class PrintMethodNotImplementedError(NotImplementedError): + """ + Raised if a _print_* method is missing in the Printer. + """ + pass + +def _convert_python_lists(arg): + if isinstance(arg, list): + from sympy.codegen.abstract_nodes import List + return List(*(_convert_python_lists(e) for e in arg)) + elif isinstance(arg, tuple): + return tuple(_convert_python_lists(e) for e in arg) + else: + return arg + + +class CodePrinter(StrPrinter): + """ + The base class for code-printing subclasses. + """ + + _operators = { + 'and': '&&', + 'or': '||', + 'not': '!', + } + + _default_settings: dict[str, Any] = { + 'order': None, + 'full_prec': 'auto', + 'error_on_reserved': False, + 'reserved_word_suffix': '_', + 'human': True, + 'inline': False, + 'allow_unknown_functions': False, + 'strict': None # True or False; None => True if human == True + } + + # Functions which are "simple" to rewrite to other functions that + # may be supported + # function_to_rewrite : (function_to_rewrite_to, iterable_with_other_functions_required) + _rewriteable_functions = { + 'cot': ('tan', []), + 'csc': ('sin', []), + 'sec': ('cos', []), + 'acot': ('atan', []), + 'acsc': ('asin', []), + 'asec': ('acos', []), + 'coth': ('exp', []), + 'csch': ('exp', []), + 'sech': ('exp', []), + 'acoth': ('log', []), + 'acsch': ('log', []), + 'asech': ('log', []), + 'catalan': ('gamma', []), + 'fibonacci': ('sqrt', []), + 'lucas': ('sqrt', []), + 'beta': ('gamma', []), + 'sinc': ('sin', ['Piecewise']), + 'Mod': ('floor', []), + 'factorial': ('gamma', []), + 'factorial2': ('gamma', ['Piecewise']), + 'subfactorial': ('uppergamma', []), + 'RisingFactorial': ('gamma', ['Piecewise']), + 'FallingFactorial': ('gamma', ['Piecewise']), + 'binomial': ('gamma', []), + 'frac': ('floor', []), + 'Max': ('Piecewise', []), + 'Min': ('Piecewise', []), + 'Heaviside': ('Piecewise', []), + 'erf2': ('erf', []), + 'erfc': ('erf', []), + 'Li': ('li', []), + 'Ei': ('li', []), + 'dirichlet_eta': ('zeta', []), + 'riemann_xi': ('zeta', ['gamma']), + 'SingularityFunction': ('Piecewise', []), + } + + def __init__(self, settings=None): + super().__init__(settings=settings) + if self._settings.get('strict', True) == None: + # for backwards compatibility, human=False need not to throw: + self._settings['strict'] = self._settings.get('human', True) == True + if not hasattr(self, 'reserved_words'): + self.reserved_words = set() + + def _handle_UnevaluatedExpr(self, expr): + return expr.replace(re, lambda arg: arg if isinstance( + arg, UnevaluatedExpr) and arg.args[0].is_real else re(arg)) + + def doprint(self, expr, assign_to=None): + """ + Print the expression as code. + + Parameters + ---------- + expr : Expression + The expression to be printed. + + assign_to : Symbol, string, MatrixSymbol, list of strings or Symbols (optional) + If provided, the printed code will set the expression to a variable or multiple variables + with the name or names given in ``assign_to``. + """ + from sympy.matrices.expressions.matexpr import MatrixSymbol + from sympy.codegen.ast import CodeBlock, Assignment + + def _handle_assign_to(expr, assign_to): + if assign_to is None: + return sympify(expr) + if isinstance(assign_to, (list, tuple)): + if len(expr) != len(assign_to): + raise ValueError('Failed to assign an expression of length {} to {} variables'.format(len(expr), len(assign_to))) + return CodeBlock(*[_handle_assign_to(lhs, rhs) for lhs, rhs in zip(expr, assign_to)]) + if isinstance(assign_to, str): + if expr.is_Matrix: + assign_to = MatrixSymbol(assign_to, *expr.shape) + else: + assign_to = Symbol(assign_to) + elif not isinstance(assign_to, Basic): + raise TypeError("{} cannot assign to object of type {}".format( + type(self).__name__, type(assign_to))) + return Assignment(assign_to, expr) + + expr = _convert_python_lists(expr) + expr = _handle_assign_to(expr, assign_to) + + # Remove re(...) nodes due to UnevaluatedExpr.is_real always is None: + expr = self._handle_UnevaluatedExpr(expr) + + # keep a set of expressions that are not strictly translatable to Code + # and number constants that must be declared and initialized + self._not_supported = set() + self._number_symbols = set() + + lines = self._print(expr).splitlines() + + # format the output + if self._settings["human"]: + frontlines = [] + if self._not_supported: + frontlines.append(self._get_comment( + "Not supported in {}:".format(self.language))) + for expr in sorted(self._not_supported, key=str): + frontlines.append(self._get_comment(type(expr).__name__)) + for name, value in sorted(self._number_symbols, key=str): + frontlines.append(self._declare_number_const(name, value)) + lines = frontlines + lines + lines = self._format_code(lines) + result = "\n".join(lines) + else: + lines = self._format_code(lines) + num_syms = {(k, self._print(v)) for k, v in self._number_symbols} + result = (num_syms, self._not_supported, "\n".join(lines)) + self._not_supported = set() + self._number_symbols = set() + return result + + def _doprint_loops(self, expr, assign_to=None): + # Here we print an expression that contains Indexed objects, they + # correspond to arrays in the generated code. The low-level implementation + # involves looping over array elements and possibly storing results in temporary + # variables or accumulate it in the assign_to object. + + if self._settings.get('contract', True): + from sympy.tensor import get_contraction_structure + # Setup loops over non-dummy indices -- all terms need these + indices = self._get_expression_indices(expr, assign_to) + # Setup loops over dummy indices -- each term needs separate treatment + dummies = get_contraction_structure(expr) + else: + indices = [] + dummies = {None: (expr,)} + openloop, closeloop = self._get_loop_opening_ending(indices) + + # terms with no summations first + if None in dummies: + text = StrPrinter.doprint(self, Add(*dummies[None])) + else: + # If all terms have summations we must initialize array to Zero + text = StrPrinter.doprint(self, 0) + + # skip redundant assignments (where lhs == rhs) + lhs_printed = self._print(assign_to) + lines = [] + if text != lhs_printed: + lines.extend(openloop) + if assign_to is not None: + text = self._get_statement("%s = %s" % (lhs_printed, text)) + lines.append(text) + lines.extend(closeloop) + + # then terms with summations + for d in dummies: + if isinstance(d, tuple): + indices = self._sort_optimized(d, expr) + openloop_d, closeloop_d = self._get_loop_opening_ending( + indices) + + for term in dummies[d]: + if term in dummies and not ([list(f.keys()) for f in dummies[term]] + == [[None] for f in dummies[term]]): + # If one factor in the term has it's own internal + # contractions, those must be computed first. + # (temporary variables?) + raise NotImplementedError( + "FIXME: no support for contractions in factor yet") + else: + + # We need the lhs expression as an accumulator for + # the loops, i.e + # + # for (int d=0; d < dim; d++){ + # lhs[] = lhs[] + term[][d] + # } ^.................. the accumulator + # + # We check if the expression already contains the + # lhs, and raise an exception if it does, as that + # syntax is currently undefined. FIXME: What would be + # a good interpretation? + if assign_to is None: + raise AssignmentError( + "need assignment variable for loops") + if term.has(assign_to): + raise ValueError("FIXME: lhs present in rhs,\ + this is undefined in CodePrinter") + + lines.extend(openloop) + lines.extend(openloop_d) + text = "%s = %s" % (lhs_printed, StrPrinter.doprint( + self, assign_to + term)) + lines.append(self._get_statement(text)) + lines.extend(closeloop_d) + lines.extend(closeloop) + + return "\n".join(lines) + + def _get_expression_indices(self, expr, assign_to): + from sympy.tensor import get_indices + rinds, junk = get_indices(expr) + linds, junk = get_indices(assign_to) + + # support broadcast of scalar + if linds and not rinds: + rinds = linds + if rinds != linds: + raise ValueError("lhs indices must match non-dummy" + " rhs indices in %s" % expr) + + return self._sort_optimized(rinds, assign_to) + + def _sort_optimized(self, indices, expr): + + from sympy.tensor.indexed import Indexed + + if not indices: + return [] + + # determine optimized loop order by giving a score to each index + # the index with the highest score are put in the innermost loop. + score_table = {} + for i in indices: + score_table[i] = 0 + + arrays = expr.atoms(Indexed) + for arr in arrays: + for p, ind in enumerate(arr.indices): + try: + score_table[ind] += self._rate_index_position(p) + except KeyError: + pass + + return sorted(indices, key=lambda x: score_table[x]) + + def _rate_index_position(self, p): + """function to calculate score based on position among indices + + This method is used to sort loops in an optimized order, see + CodePrinter._sort_optimized() + """ + raise NotImplementedError("This function must be implemented by " + "subclass of CodePrinter.") + + def _get_statement(self, codestring): + """Formats a codestring with the proper line ending.""" + raise NotImplementedError("This function must be implemented by " + "subclass of CodePrinter.") + + def _get_comment(self, text): + """Formats a text string as a comment.""" + raise NotImplementedError("This function must be implemented by " + "subclass of CodePrinter.") + + def _declare_number_const(self, name, value): + """Declare a numeric constant at the top of a function""" + raise NotImplementedError("This function must be implemented by " + "subclass of CodePrinter.") + + def _format_code(self, lines): + """Take in a list of lines of code, and format them accordingly. + + This may include indenting, wrapping long lines, etc...""" + raise NotImplementedError("This function must be implemented by " + "subclass of CodePrinter.") + + def _get_loop_opening_ending(self, indices): + """Returns a tuple (open_lines, close_lines) containing lists + of codelines""" + raise NotImplementedError("This function must be implemented by " + "subclass of CodePrinter.") + + def _print_Dummy(self, expr): + if expr.name.startswith('Dummy_'): + return '_' + expr.name + else: + return '%s_%d' % (expr.name, expr.dummy_index) + + def _print_Idx(self, expr): + return self._print(expr.label) + + def _print_CodeBlock(self, expr): + return '\n'.join([self._print(i) for i in expr.args]) + + def _print_String(self, string): + return str(string) + + def _print_QuotedString(self, arg): + return '"%s"' % arg.text + + def _print_Comment(self, string): + return self._get_comment(str(string)) + + def _print_Assignment(self, expr): + from sympy.codegen.ast import Assignment + from sympy.functions.elementary.piecewise import Piecewise + from sympy.matrices.expressions.matexpr import MatrixSymbol + from sympy.tensor.indexed import IndexedBase + lhs = expr.lhs + rhs = expr.rhs + # We special case assignments that take multiple lines + if isinstance(expr.rhs, Piecewise): + # Here we modify Piecewise so each expression is now + # an Assignment, and then continue on the print. + expressions = [] + conditions = [] + for (e, c) in rhs.args: + expressions.append(Assignment(lhs, e)) + conditions.append(c) + temp = Piecewise(*zip(expressions, conditions)) + return self._print(temp) + elif isinstance(lhs, MatrixSymbol): + # Here we form an Assignment for each element in the array, + # printing each one. + lines = [] + for (i, j) in self._traverse_matrix_indices(lhs): + temp = Assignment(lhs[i, j], rhs[i, j]) + code0 = self._print(temp) + lines.append(code0) + return "\n".join(lines) + elif self._settings.get("contract", False) and (lhs.has(IndexedBase) or + rhs.has(IndexedBase)): + # Here we check if there is looping to be done, and if so + # print the required loops. + return self._doprint_loops(rhs, lhs) + else: + lhs_code = self._print(lhs) + rhs_code = self._print(rhs) + return self._get_statement("%s = %s" % (lhs_code, rhs_code)) + + def _print_AugmentedAssignment(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + return self._get_statement("{} {} {}".format( + *(self._print(arg) for arg in [lhs_code, expr.op, rhs_code]))) + + def _print_FunctionCall(self, expr): + return '%s(%s)' % ( + expr.name, + ', '.join((self._print(arg) for arg in expr.function_args))) + + def _print_Variable(self, expr): + return self._print(expr.symbol) + + def _print_Symbol(self, expr): + name = super()._print_Symbol(expr) + + if name in self.reserved_words: + if self._settings['error_on_reserved']: + msg = ('This expression includes the symbol "{}" which is a ' + 'reserved keyword in this language.') + raise ValueError(msg.format(name)) + return name + self._settings['reserved_word_suffix'] + else: + return name + + def _can_print(self, name): + """ Check if function ``name`` is either a known function or has its own + printing method. Used to check if rewriting is possible.""" + return name in self.known_functions or getattr(self, '_print_{}'.format(name), False) + + def _print_Function(self, expr): + if expr.func.__name__ in self.known_functions: + cond_func = self.known_functions[expr.func.__name__] + if isinstance(cond_func, str): + return "%s(%s)" % (cond_func, self.stringify(expr.args, ", ")) + else: + for cond, func in cond_func: + if cond(*expr.args): + break + if func is not None: + try: + return func(*[self.parenthesize(item, 0) for item in expr.args]) + except TypeError: + return "%s(%s)" % (func, self.stringify(expr.args, ", ")) + elif hasattr(expr, '_imp_') and isinstance(expr._imp_, Lambda): + # inlined function + return self._print(expr._imp_(*expr.args)) + elif expr.func.__name__ in self._rewriteable_functions: + # Simple rewrite to supported function possible + target_f, required_fs = self._rewriteable_functions[expr.func.__name__] + if self._can_print(target_f) and all(self._can_print(f) for f in required_fs): + return '(' + self._print(expr.rewrite(target_f)) + ')' + + if expr.is_Function and self._settings.get('allow_unknown_functions', False): + return '%s(%s)' % (self._print(expr.func), ', '.join(map(self._print, expr.args))) + else: + return self._print_not_supported(expr) + + _print_Expr = _print_Function + + def _print_Derivative(self, expr): + obj, *wrt_order_pairs = expr.args + for func_arg in obj.args: + if not func_arg.is_Symbol: + raise ValueError("%s._print_Derivative(...) only supports functions with symbols as arguments." % + self.__class__.__name__) + meth_name = '_print_Derivative_%s' % obj.func.__name__ + pmeth = getattr(self, meth_name, None) + if pmeth is None: + if self._settings.get('strict', False): + raise PrintMethodNotImplementedError( + f"Unsupported by {type(self)}: {type(expr)}" + + f"\nPrinter has no method: {meth_name}" + + "\nSet the printer option 'strict' to False in order to generate partially printed code." + ) + return self._print_not_supported(expr) + orders = dict(wrt_order_pairs) + seq_orders = [orders[arg] for arg in obj.args] + return pmeth(obj.args, seq_orders) + + # Don't inherit the str-printer method for Heaviside to the code printers + _print_Heaviside = None + + def _print_NumberSymbol(self, expr): + if self._settings.get("inline", False): + return self._print(Float(expr.evalf(self._settings["precision"]))) + else: + # A Number symbol that is not implemented here or with _printmethod + # is registered and evaluated + self._number_symbols.add((expr, + Float(expr.evalf(self._settings["precision"])))) + return str(expr) + + def _print_Catalan(self, expr): + return self._print_NumberSymbol(expr) + def _print_EulerGamma(self, expr): + return self._print_NumberSymbol(expr) + def _print_GoldenRatio(self, expr): + return self._print_NumberSymbol(expr) + def _print_TribonacciConstant(self, expr): + return self._print_NumberSymbol(expr) + def _print_Exp1(self, expr): + return self._print_NumberSymbol(expr) + def _print_Pi(self, expr): + return self._print_NumberSymbol(expr) + + def _print_And(self, expr): + PREC = precedence(expr) + return (" %s " % self._operators['and']).join(self.parenthesize(a, PREC) + for a in sorted(expr.args, key=default_sort_key)) + + def _print_Or(self, expr): + PREC = precedence(expr) + return (" %s " % self._operators['or']).join(self.parenthesize(a, PREC) + for a in sorted(expr.args, key=default_sort_key)) + + def _print_Xor(self, expr): + if self._operators.get('xor') is None: + return self._print(expr.to_nnf()) + PREC = precedence(expr) + return (" %s " % self._operators['xor']).join(self.parenthesize(a, PREC) + for a in expr.args) + + def _print_Equivalent(self, expr): + if self._operators.get('equivalent') is None: + return self._print(expr.to_nnf()) + PREC = precedence(expr) + return (" %s " % self._operators['equivalent']).join(self.parenthesize(a, PREC) + for a in expr.args) + + def _print_Not(self, expr): + PREC = precedence(expr) + return self._operators['not'] + self.parenthesize(expr.args[0], PREC) + + def _print_BooleanFunction(self, expr): + return self._print(expr.to_nnf()) + + def _print_isnan(self, arg): + return 'isnan(%s)' % self._print(*arg.args) + + def _print_isinf(self, arg): + return 'isinf(%s)' % self._print(*arg.args) + + def _print_Mul(self, expr): + + prec = precedence(expr) + + c, e = expr.as_coeff_Mul() + if c < 0: + expr = _keep_coeff(-c, e) + sign = "-" + else: + sign = "" + + a = [] # items in the numerator + b = [] # items that are in the denominator (if any) + + pow_paren = [] # Will collect all pow with more than one base element and exp = -1 + + if self.order not in ('old', 'none'): + args = expr.as_ordered_factors() + else: + # use make_args in case expr was something like -x -> x + args = Mul.make_args(expr) + + # Gather args for numerator/denominator + for item in args: + if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative: + if item.exp != -1: + b.append(Pow(item.base, -item.exp, evaluate=False)) + else: + if len(item.args[0].args) != 1 and isinstance(item.base, Mul): # To avoid situations like #14160 + pow_paren.append(item) + b.append(Pow(item.base, -item.exp)) + else: + a.append(item) + + a = a or [S.One] + + if len(a) == 1 and sign == "-": + # Unary minus does not have a SymPy class, and hence there's no + # precedence weight associated with it, Python's unary minus has + # an operator precedence between multiplication and exponentiation, + # so we use this to compute a weight. + a_str = [self.parenthesize(a[0], 0.5*(PRECEDENCE["Pow"]+PRECEDENCE["Mul"]))] + else: + a_str = [self.parenthesize(x, prec) for x in a] + b_str = [self.parenthesize(x, prec) for x in b] + + # To parenthesize Pow with exp = -1 and having more than one Symbol + for item in pow_paren: + if item.base in b: + b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] + + if not b: + return sign + '*'.join(a_str) + elif len(b) == 1: + return sign + '*'.join(a_str) + "/" + b_str[0] + else: + return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str) + + def _print_not_supported(self, expr): + if self._settings.get('strict', False): + raise PrintMethodNotImplementedError( + f"Unsupported by {type(self)}: {type(expr)}" + + "\nSet the printer option 'strict' to False in order to generate partially printed code." + ) + try: + self._not_supported.add(expr) + except TypeError: + # not hashable + pass + return self.emptyPrinter(expr) + + # The following can not be simply translated into C or Fortran + _print_Basic = _print_not_supported + _print_ComplexInfinity = _print_not_supported + _print_ExprCondPair = _print_not_supported + _print_GeometryEntity = _print_not_supported + _print_Infinity = _print_not_supported + _print_Integral = _print_not_supported + _print_Interval = _print_not_supported + _print_AccumulationBounds = _print_not_supported + _print_Limit = _print_not_supported + _print_MatrixBase = _print_not_supported + _print_DeferredVector = _print_not_supported + _print_NaN = _print_not_supported + _print_NegativeInfinity = _print_not_supported + _print_Order = _print_not_supported + _print_RootOf = _print_not_supported + _print_RootsOf = _print_not_supported + _print_RootSum = _print_not_supported + _print_Uniform = _print_not_supported + _print_Unit = _print_not_supported + _print_Wild = _print_not_supported + _print_WildFunction = _print_not_supported + _print_Relational = _print_not_supported + + +# Code printer functions. These are included in this file so that they can be +# imported in the top-level __init__.py without importing the sympy.codegen +# module. + +def ccode(expr, assign_to=None, standard='c99', **settings): + """Converts an expr to a string of c code + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used as the name of the variable to which + the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of + line-wrapping, or for expressions that generate multi-line statements. + standard : str, optional + String specifying the standard. If your compiler supports a more modern + standard you may set this to 'c99' to allow the printer to use more math + functions. [default='c89']. + precision : integer, optional + The precision for numbers such as pi [default=17]. + user_functions : dict, optional + A dictionary where the keys are string representations of either + ``FunctionClass`` or ``UndefinedFunction`` instances and the values + are their desired C string representations. Alternatively, the + dictionary value can be a list of tuples i.e. [(argument_test, + cfunction_string)] or [(argument_test, cfunction_formater)]. See below + for examples. + dereference : iterable, optional + An iterable of symbols that should be dereferenced in the printed code + expression. These would be values passed by address to the function. + For example, if ``dereference=[a]``, the resulting code would print + ``(*a)`` instead of ``a``. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + + Examples + ======== + + >>> from sympy import ccode, symbols, Rational, sin, ceiling, Abs, Function + >>> x, tau = symbols("x, tau") + >>> expr = (2*tau)**Rational(7, 2) + >>> ccode(expr) + '8*M_SQRT2*pow(tau, 7.0/2.0)' + >>> ccode(expr, math_macros={}) + '8*sqrt(2)*pow(tau, 7.0/2.0)' + >>> ccode(sin(x), assign_to="s") + 's = sin(x);' + >>> from sympy.codegen.ast import real, float80 + >>> ccode(expr, type_aliases={real: float80}) + '8*M_SQRT2l*powl(tau, 7.0L/2.0L)' + + Simple custom printing can be defined for certain types by passing a + dictionary of {"type" : "function"} to the ``user_functions`` kwarg. + Alternatively, the dictionary value can be a list of tuples i.e. + [(argument_test, cfunction_string)]. + + >>> custom_functions = { + ... "ceiling": "CEIL", + ... "Abs": [(lambda x: not x.is_integer, "fabs"), + ... (lambda x: x.is_integer, "ABS")], + ... "func": "f" + ... } + >>> func = Function('func') + >>> ccode(func(Abs(x) + ceiling(x)), standard='C89', user_functions=custom_functions) + 'f(fabs(x) + CEIL(x))' + + or if the C-function takes a subset of the original arguments: + + >>> ccode(2**x + 3**x, standard='C99', user_functions={'Pow': [ + ... (lambda b, e: b == 2, lambda b, e: 'exp2(%s)' % e), + ... (lambda b, e: b != 2, 'pow')]}) + 'exp2(x) + pow(3, x)' + + ``Piecewise`` expressions are converted into conditionals. If an + ``assign_to`` variable is provided an if statement is created, otherwise + the ternary operator is used. Note that if the ``Piecewise`` lacks a + default term, represented by ``(expr, True)`` then an error will be thrown. + This is to prevent generating an expression that may not evaluate to + anything. + + >>> from sympy import Piecewise + >>> expr = Piecewise((x + 1, x > 0), (x, True)) + >>> print(ccode(expr, tau, standard='C89')) + if (x > 0) { + tau = x + 1; + } + else { + tau = x; + } + + Support for loops is provided through ``Indexed`` types. With + ``contract=True`` these expressions will be turned into loops, whereas + ``contract=False`` will just print the assignment expression that should be + looped over: + + >>> from sympy import Eq, IndexedBase, Idx + >>> len_y = 5 + >>> y = IndexedBase('y', shape=(len_y,)) + >>> t = IndexedBase('t', shape=(len_y,)) + >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) + >>> i = Idx('i', len_y-1) + >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) + >>> ccode(e.rhs, assign_to=e.lhs, contract=False, standard='C89') + 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' + + Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions + must be provided to ``assign_to``. Note that any expression that can be + generated normally can also exist inside a Matrix: + + >>> from sympy import Matrix, MatrixSymbol + >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) + >>> A = MatrixSymbol('A', 3, 1) + >>> print(ccode(mat, A, standard='C89')) + A[0] = pow(x, 2); + if (x > 0) { + A[1] = x + 1; + } + else { + A[1] = x; + } + A[2] = sin(x); + """ + from sympy.printing.c import c_code_printers + return c_code_printers[standard.lower()](settings).doprint(expr, assign_to) + +def print_ccode(expr, **settings): + """Prints C representation of the given expression.""" + print(ccode(expr, **settings)) + +def fcode(expr, assign_to=None, **settings): + """Converts an expr to a string of fortran code + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used as the name of the variable to which + the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of + line-wrapping, or for expressions that generate multi-line statements. + precision : integer, optional + DEPRECATED. Use type_mappings instead. The precision for numbers such + as pi [default=17]. + user_functions : dict, optional + A dictionary where keys are ``FunctionClass`` instances and values are + their string representations. Alternatively, the dictionary value can + be a list of tuples i.e. [(argument_test, cfunction_string)]. See below + for examples. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + source_format : optional + The source format can be either 'fixed' or 'free'. [default='fixed'] + standard : integer, optional + The Fortran standard to be followed. This is specified as an integer. + Acceptable standards are 66, 77, 90, 95, 2003, and 2008. Default is 77. + Note that currently the only distinction internally is between + standards before 95, and those 95 and after. This may change later as + more features are added. + name_mangling : bool, optional + If True, then the variables that would become identical in + case-insensitive Fortran are mangled by appending different number + of ``_`` at the end. If False, SymPy Will not interfere with naming of + variables. [default=True] + + Examples + ======== + + >>> from sympy import fcode, symbols, Rational, sin, ceiling, floor + >>> x, tau = symbols("x, tau") + >>> fcode((2*tau)**Rational(7, 2)) + ' 8*sqrt(2.0d0)*tau**(7.0d0/2.0d0)' + >>> fcode(sin(x), assign_to="s") + ' s = sin(x)' + + Custom printing can be defined for certain types by passing a dictionary of + "type" : "function" to the ``user_functions`` kwarg. Alternatively, the + dictionary value can be a list of tuples i.e. [(argument_test, + cfunction_string)]. + + >>> custom_functions = { + ... "ceiling": "CEIL", + ... "floor": [(lambda x: not x.is_integer, "FLOOR1"), + ... (lambda x: x.is_integer, "FLOOR2")] + ... } + >>> fcode(floor(x) + ceiling(x), user_functions=custom_functions) + ' CEIL(x) + FLOOR1(x)' + + ``Piecewise`` expressions are converted into conditionals. If an + ``assign_to`` variable is provided an if statement is created, otherwise + the ternary operator is used. Note that if the ``Piecewise`` lacks a + default term, represented by ``(expr, True)`` then an error will be thrown. + This is to prevent generating an expression that may not evaluate to + anything. + + >>> from sympy import Piecewise + >>> expr = Piecewise((x + 1, x > 0), (x, True)) + >>> print(fcode(expr, tau)) + if (x > 0) then + tau = x + 1 + else + tau = x + end if + + Support for loops is provided through ``Indexed`` types. With + ``contract=True`` these expressions will be turned into loops, whereas + ``contract=False`` will just print the assignment expression that should be + looped over: + + >>> from sympy import Eq, IndexedBase, Idx + >>> len_y = 5 + >>> y = IndexedBase('y', shape=(len_y,)) + >>> t = IndexedBase('t', shape=(len_y,)) + >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) + >>> i = Idx('i', len_y-1) + >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) + >>> fcode(e.rhs, assign_to=e.lhs, contract=False) + ' Dy(i) = (y(i + 1) - y(i))/(t(i + 1) - t(i))' + + Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions + must be provided to ``assign_to``. Note that any expression that can be + generated normally can also exist inside a Matrix: + + >>> from sympy import Matrix, MatrixSymbol + >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) + >>> A = MatrixSymbol('A', 3, 1) + >>> print(fcode(mat, A)) + A(1, 1) = x**2 + if (x > 0) then + A(2, 1) = x + 1 + else + A(2, 1) = x + end if + A(3, 1) = sin(x) + """ + from sympy.printing.fortran import FCodePrinter + return FCodePrinter(settings).doprint(expr, assign_to) + + +def print_fcode(expr, **settings): + """Prints the Fortran representation of the given expression. + + See fcode for the meaning of the optional arguments. + """ + print(fcode(expr, **settings)) + +def cxxcode(expr, assign_to=None, standard='c++11', **settings): + """ C++ equivalent of :func:`~.ccode`. """ + from sympy.printing.cxx import cxx_code_printers + return cxx_code_printers[standard.lower()](settings).doprint(expr, assign_to) + + +def rust_code(expr, assign_to=None, **settings): + """Converts an expr to a string of Rust code + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used as the name of the variable to which + the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of + line-wrapping, or for expressions that generate multi-line statements. + precision : integer, optional + The precision for numbers such as pi [default=15]. + user_functions : dict, optional + A dictionary where the keys are string representations of either + ``FunctionClass`` or ``UndefinedFunction`` instances and the values + are their desired C string representations. Alternatively, the + dictionary value can be a list of tuples i.e. [(argument_test, + cfunction_string)]. See below for examples. + dereference : iterable, optional + An iterable of symbols that should be dereferenced in the printed code + expression. These would be values passed by address to the function. + For example, if ``dereference=[a]``, the resulting code would print + ``(*a)`` instead of ``a``. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + + Examples + ======== + + >>> from sympy import rust_code, symbols, Rational, sin, ceiling, Abs, Function + >>> x, tau = symbols("x, tau") + >>> rust_code((2*tau)**Rational(7, 2)) + '8.0*1.4142135623731*tau.powf(7_f64/2.0)' + >>> rust_code(sin(x), assign_to="s") + 's = x.sin();' + + Simple custom printing can be defined for certain types by passing a + dictionary of {"type" : "function"} to the ``user_functions`` kwarg. + Alternatively, the dictionary value can be a list of tuples i.e. + [(argument_test, cfunction_string)]. + + >>> custom_functions = { + ... "ceiling": "CEIL", + ... "Abs": [(lambda x: not x.is_integer, "fabs", 4), + ... (lambda x: x.is_integer, "ABS", 4)], + ... "func": "f" + ... } + >>> func = Function('func') + >>> rust_code(func(Abs(x) + ceiling(x)), user_functions=custom_functions) + '(fabs(x) + x.ceil()).f()' + + ``Piecewise`` expressions are converted into conditionals. If an + ``assign_to`` variable is provided an if statement is created, otherwise + the ternary operator is used. Note that if the ``Piecewise`` lacks a + default term, represented by ``(expr, True)`` then an error will be thrown. + This is to prevent generating an expression that may not evaluate to + anything. + + >>> from sympy import Piecewise + >>> expr = Piecewise((x + 1, x > 0), (x, True)) + >>> print(rust_code(expr, tau)) + tau = if (x > 0.0) { + x + 1 + } else { + x + }; + + Support for loops is provided through ``Indexed`` types. With + ``contract=True`` these expressions will be turned into loops, whereas + ``contract=False`` will just print the assignment expression that should be + looped over: + + >>> from sympy import Eq, IndexedBase, Idx + >>> len_y = 5 + >>> y = IndexedBase('y', shape=(len_y,)) + >>> t = IndexedBase('t', shape=(len_y,)) + >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) + >>> i = Idx('i', len_y-1) + >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) + >>> rust_code(e.rhs, assign_to=e.lhs, contract=False) + 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' + + Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions + must be provided to ``assign_to``. Note that any expression that can be + generated normally can also exist inside a Matrix: + + >>> from sympy import Matrix, MatrixSymbol + >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) + >>> A = MatrixSymbol('A', 3, 1) + >>> print(rust_code(mat, A)) + A = [x.powi(2), if (x > 0.0) { + x + 1 + } else { + x + }, x.sin()]; + """ + from sympy.printing.rust import RustCodePrinter + printer = RustCodePrinter(settings) + expr = printer._rewrite_known_functions(expr) + if isinstance(expr, Expr): + for src_func, dst_func in printer.function_overrides.values(): + expr = expr.replace(src_func, dst_func) + return printer.doprint(expr, assign_to) + + +def print_rust_code(expr, **settings): + """Prints Rust representation of the given expression.""" + print(rust_code(expr, **settings)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/conventions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/conventions.py new file mode 100644 index 0000000000000000000000000000000000000000..4f5545ae38511e0bb0366da5c9fb4e59156095c8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/conventions.py @@ -0,0 +1,88 @@ +""" +A few practical conventions common to all printers. +""" + +import re + +from collections.abc import Iterable +from sympy.core.function import Derivative + +_name_with_digits_p = re.compile(r'^([^\W\d_]+)(\d+)$', re.UNICODE) + + +def split_super_sub(text): + """Split a symbol name into a name, superscripts and subscripts + + The first part of the symbol name is considered to be its actual + 'name', followed by super- and subscripts. Each superscript is + preceded with a "^" character or by "__". Each subscript is preceded + by a "_" character. The three return values are the actual name, a + list with superscripts and a list with subscripts. + + Examples + ======== + + >>> from sympy.printing.conventions import split_super_sub + >>> split_super_sub('a_x^1') + ('a', ['1'], ['x']) + >>> split_super_sub('var_sub1__sup_sub2') + ('var', ['sup'], ['sub1', 'sub2']) + + """ + if not text: + return text, [], [] + + pos = 0 + name = None + supers = [] + subs = [] + while pos < len(text): + start = pos + 1 + if text[pos:pos + 2] == "__": + start += 1 + pos_hat = text.find("^", start) + if pos_hat < 0: + pos_hat = len(text) + pos_usc = text.find("_", start) + if pos_usc < 0: + pos_usc = len(text) + pos_next = min(pos_hat, pos_usc) + part = text[pos:pos_next] + pos = pos_next + if name is None: + name = part + elif part.startswith("^"): + supers.append(part[1:]) + elif part.startswith("__"): + supers.append(part[2:]) + elif part.startswith("_"): + subs.append(part[1:]) + else: + raise RuntimeError("This should never happen.") + + # Make a little exception when a name ends with digits, i.e. treat them + # as a subscript too. + m = _name_with_digits_p.match(name) + if m: + name, sub = m.groups() + subs.insert(0, sub) + + return name, supers, subs + + +def requires_partial(expr): + """Return whether a partial derivative symbol is required for printing + + This requires checking how many free variables there are, + filtering out the ones that are integers. Some expressions do not have + free variables. In that case, check its variable list explicitly to + get the context of the expression. + """ + + if isinstance(expr, Derivative): + return requires_partial(expr.expr) + + if not isinstance(expr.free_symbols, Iterable): + return len(set(expr.variables)) > 1 + + return sum(not s.is_integer for s in expr.free_symbols) > 1 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/cxx.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/cxx.py new file mode 100644 index 0000000000000000000000000000000000000000..0ed4f468b866e1b44aba6ae94a85c740dd324689 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/cxx.py @@ -0,0 +1,181 @@ +""" +C++ code printer +""" + +from itertools import chain +from sympy.codegen.ast import Type, none +from .codeprinter import requires +from .c import C89CodePrinter, C99CodePrinter + +# These are defined in the other file so we can avoid importing sympy.codegen +# from the top-level 'import sympy'. Export them here as well. +from sympy.printing.codeprinter import cxxcode # noqa:F401 + +# from https://en.cppreference.com/w/cpp/keyword +reserved = { + 'C++98': [ + 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'bool', 'break', + 'case', 'catch,', 'char', 'class', 'compl', 'const', 'const_cast', + 'continue', 'default', 'delete', 'do', 'double', 'dynamic_cast', + 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'float', + 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', + 'namespace', 'new', 'not', 'not_eq', 'operator', 'or', 'or_eq', + 'private', 'protected', 'public', 'register', 'reinterpret_cast', + 'return', 'short', 'signed', 'sizeof', 'static', 'static_cast', + 'struct', 'switch', 'template', 'this', 'throw', 'true', 'try', + 'typedef', 'typeid', 'typename', 'union', 'unsigned', 'using', + 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq' + ] +} + +reserved['C++11'] = reserved['C++98'][:] + [ + 'alignas', 'alignof', 'char16_t', 'char32_t', 'constexpr', 'decltype', + 'noexcept', 'nullptr', 'static_assert', 'thread_local' +] +reserved['C++17'] = reserved['C++11'][:] +reserved['C++17'].remove('register') +# TM TS: atomic_cancel, atomic_commit, atomic_noexcept, synchronized +# concepts TS: concept, requires +# module TS: import, module + + +_math_functions = { + 'C++98': { + 'Mod': 'fmod', + 'ceiling': 'ceil', + }, + 'C++11': { + 'gamma': 'tgamma', + }, + 'C++17': { + 'beta': 'beta', + 'Ei': 'expint', + 'zeta': 'riemann_zeta', + } +} + +# from https://en.cppreference.com/w/cpp/header/cmath +for k in ('Abs', 'exp', 'log', 'log10', 'sqrt', 'sin', 'cos', 'tan', # 'Pow' + 'asin', 'acos', 'atan', 'atan2', 'sinh', 'cosh', 'tanh', 'floor'): + _math_functions['C++98'][k] = k.lower() + + +for k in ('asinh', 'acosh', 'atanh', 'erf', 'erfc'): + _math_functions['C++11'][k] = k.lower() + + +def _attach_print_method(cls, sympy_name, func_name): + meth_name = '_print_%s' % sympy_name + if hasattr(cls, meth_name): + raise ValueError("Edit method (or subclass) instead of overwriting.") + def _print_method(self, expr): + return '{}{}({})'.format(self._ns, func_name, ', '.join(map(self._print, expr.args))) + _print_method.__doc__ = "Prints code for %s" % k + setattr(cls, meth_name, _print_method) + + +def _attach_print_methods(cls, cont): + for sympy_name, cxx_name in cont[cls.standard].items(): + _attach_print_method(cls, sympy_name, cxx_name) + + +class _CXXCodePrinterBase: + printmethod = "_cxxcode" + language = 'C++' + _ns = 'std::' # namespace + + def __init__(self, settings=None): + super().__init__(settings or {}) + + @requires(headers={'algorithm'}) + def _print_Max(self, expr): + from sympy.functions.elementary.miscellaneous import Max + if len(expr.args) == 1: + return self._print(expr.args[0]) + return "%smax(%s, %s)" % (self._ns, self._print(expr.args[0]), + self._print(Max(*expr.args[1:]))) + + @requires(headers={'algorithm'}) + def _print_Min(self, expr): + from sympy.functions.elementary.miscellaneous import Min + if len(expr.args) == 1: + return self._print(expr.args[0]) + return "%smin(%s, %s)" % (self._ns, self._print(expr.args[0]), + self._print(Min(*expr.args[1:]))) + + def _print_using(self, expr): + if expr.alias == none: + return 'using %s' % expr.type + else: + raise ValueError("C++98 does not support type aliases") + + def _print_Raise(self, rs): + arg, = rs.args + return 'throw %s' % self._print(arg) + + @requires(headers={'stdexcept'}) + def _print_RuntimeError_(self, re): + message, = re.args + return "%sruntime_error(%s)" % (self._ns, self._print(message)) + + +class CXX98CodePrinter(_CXXCodePrinterBase, C89CodePrinter): + standard = 'C++98' + reserved_words = set(reserved['C++98']) + + +# _attach_print_methods(CXX98CodePrinter, _math_functions) + + +class CXX11CodePrinter(_CXXCodePrinterBase, C99CodePrinter): + standard = 'C++11' + reserved_words = set(reserved['C++11']) + type_mappings = dict(chain( + CXX98CodePrinter.type_mappings.items(), + { + Type('int8'): ('int8_t', {'cstdint'}), + Type('int16'): ('int16_t', {'cstdint'}), + Type('int32'): ('int32_t', {'cstdint'}), + Type('int64'): ('int64_t', {'cstdint'}), + Type('uint8'): ('uint8_t', {'cstdint'}), + Type('uint16'): ('uint16_t', {'cstdint'}), + Type('uint32'): ('uint32_t', {'cstdint'}), + Type('uint64'): ('uint64_t', {'cstdint'}), + Type('complex64'): ('std::complex', {'complex'}), + Type('complex128'): ('std::complex', {'complex'}), + Type('bool'): ('bool', None), + }.items() + )) + + def _print_using(self, expr): + if expr.alias == none: + return super()._print_using(expr) + else: + return 'using %(alias)s = %(type)s' % expr.kwargs(apply=self._print) + +# _attach_print_methods(CXX11CodePrinter, _math_functions) + + +class CXX17CodePrinter(_CXXCodePrinterBase, C99CodePrinter): + standard = 'C++17' + reserved_words = set(reserved['C++17']) + + _kf = dict(C99CodePrinter._kf, **_math_functions['C++17']) + + def _print_beta(self, expr): + return self._print_math_func(expr) + + def _print_Ei(self, expr): + return self._print_math_func(expr) + + def _print_zeta(self, expr): + return self._print_math_func(expr) + + +# _attach_print_methods(CXX17CodePrinter, _math_functions) + +cxx_code_printers = { + 'c++98': CXX98CodePrinter, + 'c++11': CXX11CodePrinter, + 'c++17': CXX17CodePrinter +} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/defaults.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/defaults.py new file mode 100644 index 0000000000000000000000000000000000000000..77a88d353fed4bd70496456ddd03cc429a4ba5e7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/defaults.py @@ -0,0 +1,5 @@ +from sympy.core._print_helpers import Printable + +# alias for compatibility +Printable.__module__ = __name__ +DefaultPrinting = Printable diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/dot.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/dot.py new file mode 100644 index 0000000000000000000000000000000000000000..c968fee389c16108b757b8fcad531ac6fa4ddb2f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/dot.py @@ -0,0 +1,294 @@ +from sympy.core.basic import Basic +from sympy.core.expr import Expr +from sympy.core.symbol import Symbol +from sympy.core.numbers import Integer, Rational, Float +from sympy.printing.repr import srepr + +__all__ = ['dotprint'] + +default_styles = ( + (Basic, {'color': 'blue', 'shape': 'ellipse'}), + (Expr, {'color': 'black'}) +) + +slotClasses = (Symbol, Integer, Rational, Float) +def purestr(x, with_args=False): + """A string that follows ```obj = type(obj)(*obj.args)``` exactly. + + Parameters + ========== + + with_args : boolean, optional + If ``True``, there will be a second argument for the return + value, which is a tuple containing ``purestr`` applied to each + of the subnodes. + + If ``False``, there will not be a second argument for the + return. + + Default is ``False`` + + Examples + ======== + + >>> from sympy import Float, Symbol, MatrixSymbol + >>> from sympy import Integer # noqa: F401 + >>> from sympy.core.symbol import Str # noqa: F401 + >>> from sympy.printing.dot import purestr + + Applying ``purestr`` for basic symbolic object: + >>> code = purestr(Symbol('x')) + >>> code + "Symbol('x')" + >>> eval(code) == Symbol('x') + True + + For basic numeric object: + >>> purestr(Float(2)) + "Float('2.0', precision=53)" + + For matrix symbol: + >>> code = purestr(MatrixSymbol('x', 2, 2)) + >>> code + "MatrixSymbol(Str('x'), Integer(2), Integer(2))" + >>> eval(code) == MatrixSymbol('x', 2, 2) + True + + With ``with_args=True``: + >>> purestr(Float(2), with_args=True) + ("Float('2.0', precision=53)", ()) + >>> purestr(MatrixSymbol('x', 2, 2), with_args=True) + ("MatrixSymbol(Str('x'), Integer(2), Integer(2))", + ("Str('x')", 'Integer(2)', 'Integer(2)')) + """ + sargs = () + if not isinstance(x, Basic): + rv = str(x) + elif not x.args: + rv = srepr(x) + else: + args = x.args + sargs = tuple(map(purestr, args)) + rv = "%s(%s)"%(type(x).__name__, ', '.join(sargs)) + if with_args: + rv = rv, sargs + return rv + + +def styleof(expr, styles=default_styles): + """ Merge style dictionaries in order + + Examples + ======== + + >>> from sympy import Symbol, Basic, Expr, S + >>> from sympy.printing.dot import styleof + >>> styles = [(Basic, {'color': 'blue', 'shape': 'ellipse'}), + ... (Expr, {'color': 'black'})] + + >>> styleof(Basic(S(1)), styles) + {'color': 'blue', 'shape': 'ellipse'} + + >>> x = Symbol('x') + >>> styleof(x + 1, styles) # this is an Expr + {'color': 'black', 'shape': 'ellipse'} + """ + style = {} + for typ, sty in styles: + if isinstance(expr, typ): + style.update(sty) + return style + + +def attrprint(d, delimiter=', '): + """ Print a dictionary of attributes + + Examples + ======== + + >>> from sympy.printing.dot import attrprint + >>> print(attrprint({'color': 'blue', 'shape': 'ellipse'})) + "color"="blue", "shape"="ellipse" + """ + return delimiter.join('"%s"="%s"'%item for item in sorted(d.items())) + + +def dotnode(expr, styles=default_styles, labelfunc=str, pos=(), repeat=True): + """ String defining a node + + Examples + ======== + + >>> from sympy.printing.dot import dotnode + >>> from sympy.abc import x + >>> print(dotnode(x)) + "Symbol('x')_()" ["color"="black", "label"="x", "shape"="ellipse"]; + """ + style = styleof(expr, styles) + + if isinstance(expr, Basic) and not expr.is_Atom: + label = str(expr.__class__.__name__) + else: + label = labelfunc(expr) + style['label'] = label + expr_str = purestr(expr) + if repeat: + expr_str += '_%s' % str(pos) + return '"%s" [%s];' % (expr_str, attrprint(style)) + + +def dotedges(expr, atom=lambda x: not isinstance(x, Basic), pos=(), repeat=True): + """ List of strings for all expr->expr.arg pairs + + See the docstring of dotprint for explanations of the options. + + Examples + ======== + + >>> from sympy.printing.dot import dotedges + >>> from sympy.abc import x + >>> for e in dotedges(x+2): + ... print(e) + "Add(Integer(2), Symbol('x'))_()" -> "Integer(2)_(0,)"; + "Add(Integer(2), Symbol('x'))_()" -> "Symbol('x')_(1,)"; + """ + if atom(expr): + return [] + else: + expr_str, arg_strs = purestr(expr, with_args=True) + if repeat: + expr_str += '_%s' % str(pos) + arg_strs = ['%s_%s' % (a, str(pos + (i,))) + for i, a in enumerate(arg_strs)] + return ['"%s" -> "%s";' % (expr_str, a) for a in arg_strs] + +template = \ +"""digraph{ + +# Graph style +%(graphstyle)s + +######### +# Nodes # +######### + +%(nodes)s + +######### +# Edges # +######### + +%(edges)s +}""" + +_graphstyle = {'rankdir': 'TD', 'ordering': 'out'} + +def dotprint(expr, + styles=default_styles, atom=lambda x: not isinstance(x, Basic), + maxdepth=None, repeat=True, labelfunc=str, **kwargs): + """DOT description of a SymPy expression tree + + Parameters + ========== + + styles : list of lists composed of (Class, mapping), optional + Styles for different classes. + + The default is + + .. code-block:: python + + ( + (Basic, {'color': 'blue', 'shape': 'ellipse'}), + (Expr, {'color': 'black'}) + ) + + atom : function, optional + Function used to determine if an arg is an atom. + + A good choice is ``lambda x: not x.args``. + + The default is ``lambda x: not isinstance(x, Basic)``. + + maxdepth : integer, optional + The maximum depth. + + The default is ``None``, meaning no limit. + + repeat : boolean, optional + Whether to use different nodes for common subexpressions. + + The default is ``True``. + + For example, for ``x + x*y`` with ``repeat=True``, it will have + two nodes for ``x``; with ``repeat=False``, it will have one + node. + + .. warning:: + Even if a node appears twice in the same object like ``x`` in + ``Pow(x, x)``, it will still only appear once. + Hence, with ``repeat=False``, the number of arrows out of an + object might not equal the number of args it has. + + labelfunc : function, optional + A function to create a label for a given leaf node. + + The default is ``str``. + + Another good option is ``srepr``. + + For example with ``str``, the leaf nodes of ``x + 1`` are labeled, + ``x`` and ``1``. With ``srepr``, they are labeled ``Symbol('x')`` + and ``Integer(1)``. + + **kwargs : optional + Additional keyword arguments are included as styles for the graph. + + Examples + ======== + + >>> from sympy import dotprint + >>> from sympy.abc import x + >>> print(dotprint(x+2)) # doctest: +NORMALIZE_WHITESPACE + digraph{ + + # Graph style + "ordering"="out" + "rankdir"="TD" + + ######### + # Nodes # + ######### + + "Add(Integer(2), Symbol('x'))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; + "Integer(2)_(0,)" ["color"="black", "label"="2", "shape"="ellipse"]; + "Symbol('x')_(1,)" ["color"="black", "label"="x", "shape"="ellipse"]; + + ######### + # Edges # + ######### + + "Add(Integer(2), Symbol('x'))_()" -> "Integer(2)_(0,)"; + "Add(Integer(2), Symbol('x'))_()" -> "Symbol('x')_(1,)"; + } + + """ + # repeat works by adding a signature tuple to the end of each node for its + # position in the graph. For example, for expr = Add(x, Pow(x, 2)), the x in the + # Pow will have the tuple (1, 0), meaning it is expr.args[1].args[0]. + graphstyle = _graphstyle.copy() + graphstyle.update(kwargs) + + nodes = [] + edges = [] + def traverse(e, depth, pos=()): + nodes.append(dotnode(e, styles, labelfunc=labelfunc, pos=pos, repeat=repeat)) + if maxdepth and depth >= maxdepth: + return + edges.extend(dotedges(e, atom=atom, pos=pos, repeat=repeat)) + [traverse(arg, depth+1, pos + (i,)) for i, arg in enumerate(e.args) if not atom(arg)] + traverse(expr, 0) + + return template%{'graphstyle': attrprint(graphstyle, delimiter='\n'), + 'nodes': '\n'.join(nodes), + 'edges': '\n'.join(edges)} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/fortran.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/fortran.py new file mode 100644 index 0000000000000000000000000000000000000000..7cea812d72ddcd3ccb56c7258f74e6fe3b8d5211 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/fortran.py @@ -0,0 +1,779 @@ +""" +Fortran code printer + +The FCodePrinter converts single SymPy expressions into single Fortran +expressions, using the functions defined in the Fortran 77 standard where +possible. Some useful pointers to Fortran can be found on wikipedia: + +https://en.wikipedia.org/wiki/Fortran + +Most of the code below is based on the "Professional Programmer\'s Guide to +Fortran77" by Clive G. Page: + +https://www.star.le.ac.uk/~cgp/prof77.html + +Fortran is a case-insensitive language. This might cause trouble because +SymPy is case sensitive. So, fcode adds underscores to variable names when +it is necessary to make them different for Fortran. +""" + +from __future__ import annotations +from typing import Any + +from collections import defaultdict +from itertools import chain +import string + +from sympy.codegen.ast import ( + Assignment, Declaration, Pointer, value_const, + float32, float64, float80, complex64, complex128, int8, int16, int32, + int64, intc, real, integer, bool_, complex_, none, stderr, stdout +) +from sympy.codegen.fnodes import ( + allocatable, isign, dsign, cmplx, merge, literal_dp, elemental, pure, + intent_in, intent_out, intent_inout +) +from sympy.core import S, Add, N, Float, Symbol +from sympy.core.function import Function +from sympy.core.numbers import equal_valued +from sympy.core.relational import Eq +from sympy.sets import Range +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import precedence, PRECEDENCE +from sympy.printing.printer import printer_context + +# These are defined in the other file so we can avoid importing sympy.codegen +# from the top-level 'import sympy'. Export them here as well. +from sympy.printing.codeprinter import fcode, print_fcode # noqa:F401 + +known_functions = { + "sin": "sin", + "cos": "cos", + "tan": "tan", + "asin": "asin", + "acos": "acos", + "atan": "atan", + "atan2": "atan2", + "sinh": "sinh", + "cosh": "cosh", + "tanh": "tanh", + "log": "log", + "exp": "exp", + "erf": "erf", + "Abs": "abs", + "conjugate": "conjg", + "Max": "max", + "Min": "min", +} + + +class FCodePrinter(CodePrinter): + """A printer to convert SymPy expressions to strings of Fortran code""" + printmethod = "_fcode" + language = "Fortran" + + type_aliases = { + integer: int32, + real: float64, + complex_: complex128, + } + + type_mappings = { + intc: 'integer(c_int)', + float32: 'real*4', # real(kind(0.e0)) + float64: 'real*8', # real(kind(0.d0)) + float80: 'real*10', # real(kind(????)) + complex64: 'complex*8', + complex128: 'complex*16', + int8: 'integer*1', + int16: 'integer*2', + int32: 'integer*4', + int64: 'integer*8', + bool_: 'logical' + } + + type_modules = { + intc: {'iso_c_binding': 'c_int'} + } + + _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{ + 'precision': 17, + 'user_functions': {}, + 'source_format': 'fixed', + 'contract': True, + 'standard': 77, + 'name_mangling': True, + }) + + _operators = { + 'and': '.and.', + 'or': '.or.', + 'xor': '.neqv.', + 'equivalent': '.eqv.', + 'not': '.not. ', + } + + _relationals = { + '!=': '/=', + } + + def __init__(self, settings=None): + if not settings: + settings = {} + self.mangled_symbols = {} # Dict showing mapping of all words + self.used_name = [] + self.type_aliases = dict(chain(self.type_aliases.items(), + settings.pop('type_aliases', {}).items())) + self.type_mappings = dict(chain(self.type_mappings.items(), + settings.pop('type_mappings', {}).items())) + super().__init__(settings) + self.known_functions = dict(known_functions) + userfuncs = settings.get('user_functions', {}) + self.known_functions.update(userfuncs) + # leading columns depend on fixed or free format + standards = {66, 77, 90, 95, 2003, 2008} + if self._settings['standard'] not in standards: + raise ValueError("Unknown Fortran standard: %s" % self._settings[ + 'standard']) + self.module_uses = defaultdict(set) # e.g.: use iso_c_binding, only: c_int + + @property + def _lead(self): + if self._settings['source_format'] == 'fixed': + return {'code': " ", 'cont': " @ ", 'comment': "C "} + elif self._settings['source_format'] == 'free': + return {'code': "", 'cont': " ", 'comment': "! "} + else: + raise ValueError("Unknown source format: %s" % self._settings['source_format']) + + def _print_Symbol(self, expr): + if self._settings['name_mangling'] == True: + if expr not in self.mangled_symbols: + name = expr.name + while name.lower() in self.used_name: + name += '_' + self.used_name.append(name.lower()) + if name == expr.name: + self.mangled_symbols[expr] = expr + else: + self.mangled_symbols[expr] = Symbol(name) + + expr = expr.xreplace(self.mangled_symbols) + + name = super()._print_Symbol(expr) + return name + + def _rate_index_position(self, p): + return -p*5 + + def _get_statement(self, codestring): + return codestring + + def _get_comment(self, text): + return "! {}".format(text) + + def _declare_number_const(self, name, value): + return "parameter ({} = {})".format(name, self._print(value)) + + def _print_NumberSymbol(self, expr): + # A Number symbol that is not implemented here or with _printmethod + # is registered and evaluated + self._number_symbols.add((expr, Float(expr.evalf(self._settings['precision'])))) + return str(expr) + + def _format_code(self, lines): + return self._wrap_fortran(self.indent_code(lines)) + + def _traverse_matrix_indices(self, mat): + rows, cols = mat.shape + return ((i, j) for j in range(cols) for i in range(rows)) + + def _get_loop_opening_ending(self, indices): + open_lines = [] + close_lines = [] + for i in indices: + # fortran arrays start at 1 and end at dimension + var, start, stop = map(self._print, + [i.label, i.lower + 1, i.upper + 1]) + open_lines.append("do %s = %s, %s" % (var, start, stop)) + close_lines.append("end do") + return open_lines, close_lines + + def _print_sign(self, expr): + from sympy.functions.elementary.complexes import Abs + arg, = expr.args + if arg.is_integer: + new_expr = merge(0, isign(1, arg), Eq(arg, 0)) + elif (arg.is_complex or arg.is_infinite): + new_expr = merge(cmplx(literal_dp(0), literal_dp(0)), arg/Abs(arg), Eq(Abs(arg), literal_dp(0))) + else: + new_expr = merge(literal_dp(0), dsign(literal_dp(1), arg), Eq(arg, literal_dp(0))) + return self._print(new_expr) + + + def _print_Piecewise(self, expr): + if expr.args[-1].cond != True: + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + lines = [] + if expr.has(Assignment): + for i, (e, c) in enumerate(expr.args): + if i == 0: + lines.append("if (%s) then" % self._print(c)) + elif i == len(expr.args) - 1 and c == True: + lines.append("else") + else: + lines.append("else if (%s) then" % self._print(c)) + lines.append(self._print(e)) + lines.append("end if") + return "\n".join(lines) + elif self._settings["standard"] >= 95: + # Only supported in F95 and newer: + # The piecewise was used in an expression, need to do inline + # operators. This has the downside that inline operators will + # not work for statements that span multiple lines (Matrix or + # Indexed expressions). + pattern = "merge({T}, {F}, {COND})" + code = self._print(expr.args[-1].expr) + terms = list(expr.args[:-1]) + while terms: + e, c = terms.pop() + expr = self._print(e) + cond = self._print(c) + code = pattern.format(T=expr, F=code, COND=cond) + return code + else: + # `merge` is not supported prior to F95 + raise NotImplementedError("Using Piecewise as an expression using " + "inline operators is not supported in " + "standards earlier than Fortran95.") + + def _print_MatrixElement(self, expr): + return "{}({}, {})".format(self.parenthesize(expr.parent, + PRECEDENCE["Atom"], strict=True), expr.i + 1, expr.j + 1) + + def _print_Add(self, expr): + # purpose: print complex numbers nicely in Fortran. + # collect the purely real and purely imaginary parts: + pure_real = [] + pure_imaginary = [] + mixed = [] + for arg in expr.args: + if arg.is_number and arg.is_real: + pure_real.append(arg) + elif arg.is_number and arg.is_imaginary: + pure_imaginary.append(arg) + else: + mixed.append(arg) + if pure_imaginary: + if mixed: + PREC = precedence(expr) + term = Add(*mixed) + t = self._print(term) + if t.startswith('-'): + sign = "-" + t = t[1:] + else: + sign = "+" + if precedence(term) < PREC: + t = "(%s)" % t + + return "cmplx(%s,%s) %s %s" % ( + self._print(Add(*pure_real)), + self._print(-S.ImaginaryUnit*Add(*pure_imaginary)), + sign, t, + ) + else: + return "cmplx(%s,%s)" % ( + self._print(Add(*pure_real)), + self._print(-S.ImaginaryUnit*Add(*pure_imaginary)), + ) + else: + return CodePrinter._print_Add(self, expr) + + def _print_Function(self, expr): + # All constant function args are evaluated as floats + prec = self._settings['precision'] + args = [N(a, prec) for a in expr.args] + eval_expr = expr.func(*args) + if not isinstance(eval_expr, Function): + return self._print(eval_expr) + else: + return CodePrinter._print_Function(self, expr.func(*args)) + + def _print_Mod(self, expr): + # NOTE : Fortran has the functions mod() and modulo(). modulo() behaves + # the same wrt to the sign of the arguments as Python and SymPy's + # modulus computations (% and Mod()) but is not available in Fortran 66 + # or Fortran 77, thus we raise an error. + if self._settings['standard'] in [66, 77]: + msg = ("Python % operator and SymPy's Mod() function are not " + "supported by Fortran 66 or 77 standards.") + raise NotImplementedError(msg) + else: + x, y = expr.args + return " modulo({}, {})".format(self._print(x), self._print(y)) + + def _print_ImaginaryUnit(self, expr): + # purpose: print complex numbers nicely in Fortran. + return "cmplx(0,1)" + + def _print_int(self, expr): + return str(expr) + + def _print_Mul(self, expr): + # purpose: print complex numbers nicely in Fortran. + if expr.is_number and expr.is_imaginary: + return "cmplx(0,%s)" % ( + self._print(-S.ImaginaryUnit*expr) + ) + else: + return CodePrinter._print_Mul(self, expr) + + def _print_Pow(self, expr): + PREC = precedence(expr) + if equal_valued(expr.exp, -1): + return '%s/%s' % ( + self._print(literal_dp(1)), + self.parenthesize(expr.base, PREC) + ) + elif equal_valued(expr.exp, 0.5): + if expr.base.is_integer: + # Fortran intrinsic sqrt() does not accept integer argument + if expr.base.is_Number: + return 'sqrt(%s.0d0)' % self._print(expr.base) + else: + return 'sqrt(dble(%s))' % self._print(expr.base) + else: + return 'sqrt(%s)' % self._print(expr.base) + else: + return CodePrinter._print_Pow(self, expr) + + def _print_Rational(self, expr): + p, q = int(expr.p), int(expr.q) + return "%d.0d0/%d.0d0" % (p, q) + + def _print_Float(self, expr): + printed = CodePrinter._print_Float(self, expr) + e = printed.find('e') + if e > -1: + return "%sd%s" % (printed[:e], printed[e + 1:]) + return "%sd0" % printed + + def _print_Relational(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + op = expr.rel_op + op = op if op not in self._relationals else self._relationals[op] + return "{} {} {}".format(lhs_code, op, rhs_code) + + def _print_Indexed(self, expr): + inds = [ self._print(i) for i in expr.indices ] + return "%s(%s)" % (self._print(expr.base.label), ", ".join(inds)) + + def _print_AugmentedAssignment(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + return self._get_statement("{0} = {0} {1} {2}".format( + self._print(lhs_code), self._print(expr.binop), self._print(rhs_code))) + + def _print_sum_(self, sm): + params = self._print(sm.array) + if sm.dim != None: # Must use '!= None', cannot use 'is not None' + params += ', ' + self._print(sm.dim) + if sm.mask != None: # Must use '!= None', cannot use 'is not None' + params += ', mask=' + self._print(sm.mask) + return '%s(%s)' % (sm.__class__.__name__.rstrip('_'), params) + + def _print_product_(self, prod): + return self._print_sum_(prod) + + def _print_Do(self, do): + excl = ['concurrent'] + if do.step == 1: + excl.append('step') + step = '' + else: + step = ', {step}' + + return ( + 'do {concurrent}{counter} = {first}, {last}'+step+'\n' + '{body}\n' + 'end do\n' + ).format( + concurrent='concurrent ' if do.concurrent else '', + **do.kwargs(apply=lambda arg: self._print(arg), exclude=excl) + ) + + def _print_ImpliedDoLoop(self, idl): + step = '' if idl.step == 1 else ', {step}' + return ('({expr}, {counter} = {first}, {last}'+step+')').format( + **idl.kwargs(apply=lambda arg: self._print(arg)) + ) + + def _print_For(self, expr): + target = self._print(expr.target) + if isinstance(expr.iterable, Range): + start, stop, step = expr.iterable.args + else: + raise NotImplementedError("Only iterable currently supported is Range") + body = self._print(expr.body) + return ('do {target} = {start}, {stop}, {step}\n' + '{body}\n' + 'end do').format(target=target, start=start, stop=stop - 1, + step=step, body=body) + + def _print_Type(self, type_): + type_ = self.type_aliases.get(type_, type_) + type_str = self.type_mappings.get(type_, type_.name) + module_uses = self.type_modules.get(type_) + if module_uses: + for k, v in module_uses: + self.module_uses[k].add(v) + return type_str + + def _print_Element(self, elem): + return '{symbol}({idxs})'.format( + symbol=self._print(elem.symbol), + idxs=', '.join((self._print(arg) for arg in elem.indices)) + ) + + def _print_Extent(self, ext): + return str(ext) + + def _print_Declaration(self, expr): + var = expr.variable + val = var.value + dim = var.attr_params('dimension') + intents = [intent in var.attrs for intent in (intent_in, intent_out, intent_inout)] + if intents.count(True) == 0: + intent = '' + elif intents.count(True) == 1: + intent = ', intent(%s)' % ['in', 'out', 'inout'][intents.index(True)] + else: + raise ValueError("Multiple intents specified for %s" % self) + + if isinstance(var, Pointer): + raise NotImplementedError("Pointers are not available by default in Fortran.") + if self._settings["standard"] >= 90: + result = '{t}{vc}{dim}{intent}{alloc} :: {s}'.format( + t=self._print(var.type), + vc=', parameter' if value_const in var.attrs else '', + dim=', dimension(%s)' % ', '.join((self._print(arg) for arg in dim)) if dim else '', + intent=intent, + alloc=', allocatable' if allocatable in var.attrs else '', + s=self._print(var.symbol) + ) + if val != None: # Must be "!= None", cannot be "is not None" + result += ' = %s' % self._print(val) + else: + if value_const in var.attrs or val: + raise NotImplementedError("F77 init./parameter statem. req. multiple lines.") + result = ' '.join((self._print(arg) for arg in [var.type, var.symbol])) + + return result + + + def _print_Infinity(self, expr): + return '(huge(%s) + 1)' % self._print(literal_dp(0)) + + def _print_While(self, expr): + return 'do while ({condition})\n{body}\nend do'.format(**expr.kwargs( + apply=lambda arg: self._print(arg))) + + def _print_BooleanTrue(self, expr): + return '.true.' + + def _print_BooleanFalse(self, expr): + return '.false.' + + def _pad_leading_columns(self, lines): + result = [] + for line in lines: + if line.startswith('!'): + result.append(self._lead['comment'] + line[1:].lstrip()) + else: + result.append(self._lead['code'] + line) + return result + + def _wrap_fortran(self, lines): + """Wrap long Fortran lines + + Argument: + lines -- a list of lines (without \\n character) + + A comment line is split at white space. Code lines are split with a more + complex rule to give nice results. + """ + # routine to find split point in a code line + my_alnum = set("_+-." + string.digits + string.ascii_letters) + my_white = set(" \t()") + + def split_pos_code(line, endpos): + if len(line) <= endpos: + return len(line) + pos = endpos + split = lambda pos: \ + (line[pos] in my_alnum and line[pos - 1] not in my_alnum) or \ + (line[pos] not in my_alnum and line[pos - 1] in my_alnum) or \ + (line[pos] in my_white and line[pos - 1] not in my_white) or \ + (line[pos] not in my_white and line[pos - 1] in my_white) + while not split(pos): + pos -= 1 + if pos == 0: + return endpos + return pos + # split line by line and add the split lines to result + result = [] + if self._settings['source_format'] == 'free': + trailing = ' &' + else: + trailing = '' + for line in lines: + if line.startswith(self._lead['comment']): + # comment line + if len(line) > 72: + pos = line.rfind(" ", 6, 72) + if pos == -1: + pos = 72 + hunk = line[:pos] + line = line[pos:].lstrip() + result.append(hunk) + while line: + pos = line.rfind(" ", 0, 66) + if pos == -1 or len(line) < 66: + pos = 66 + hunk = line[:pos] + line = line[pos:].lstrip() + result.append("%s%s" % (self._lead['comment'], hunk)) + else: + result.append(line) + elif line.startswith(self._lead['code']): + # code line + pos = split_pos_code(line, 72) + hunk = line[:pos].rstrip() + line = line[pos:].lstrip() + if line: + hunk += trailing + result.append(hunk) + while line: + pos = split_pos_code(line, 65) + hunk = line[:pos].rstrip() + line = line[pos:].lstrip() + if line: + hunk += trailing + result.append("%s%s" % (self._lead['cont'], hunk)) + else: + result.append(line) + return result + + def indent_code(self, code): + """Accepts a string of code or a list of code lines""" + if isinstance(code, str): + code_lines = self.indent_code(code.splitlines(True)) + return ''.join(code_lines) + + free = self._settings['source_format'] == 'free' + code = [ line.lstrip(' \t') for line in code ] + + inc_keyword = ('do ', 'if(', 'if ', 'do\n', 'else', 'program', 'interface') + dec_keyword = ('end do', 'enddo', 'end if', 'endif', 'else', 'end program', 'end interface') + + increase = [ int(any(map(line.startswith, inc_keyword))) + for line in code ] + decrease = [ int(any(map(line.startswith, dec_keyword))) + for line in code ] + continuation = [ int(any(map(line.endswith, ['&', '&\n']))) + for line in code ] + + level = 0 + cont_padding = 0 + tabwidth = 3 + new_code = [] + for i, line in enumerate(code): + if line in ('', '\n'): + new_code.append(line) + continue + level -= decrease[i] + + if free: + padding = " "*(level*tabwidth + cont_padding) + else: + padding = " "*level*tabwidth + + line = "%s%s" % (padding, line) + if not free: + line = self._pad_leading_columns([line])[0] + + new_code.append(line) + + if continuation[i]: + cont_padding = 2*tabwidth + else: + cont_padding = 0 + level += increase[i] + + if not free: + return self._wrap_fortran(new_code) + return new_code + + def _print_GoTo(self, goto): + if goto.expr: # computed goto + return "go to ({labels}), {expr}".format( + labels=', '.join((self._print(arg) for arg in goto.labels)), + expr=self._print(goto.expr) + ) + else: + lbl, = goto.labels + return "go to %s" % self._print(lbl) + + def _print_Program(self, prog): + return ( + "program {name}\n" + "{body}\n" + "end program\n" + ).format(**prog.kwargs(apply=lambda arg: self._print(arg))) + + def _print_Module(self, mod): + return ( + "module {name}\n" + "{declarations}\n" + "\ncontains\n\n" + "{definitions}\n" + "end module\n" + ).format(**mod.kwargs(apply=lambda arg: self._print(arg))) + + def _print_Stream(self, strm): + if strm.name == 'stdout' and self._settings["standard"] >= 2003: + self.module_uses['iso_c_binding'].add('stdint=>input_unit') + return 'input_unit' + elif strm.name == 'stderr' and self._settings["standard"] >= 2003: + self.module_uses['iso_c_binding'].add('stdint=>error_unit') + return 'error_unit' + else: + if strm.name == 'stdout': + return '*' + else: + return strm.name + + def _print_Print(self, ps): + if ps.format_string == none: # Must be '!= None', cannot be 'is not None' + template = "print {fmt}, {iolist}" + fmt = '*' + else: + template = 'write(%(out)s, fmt="{fmt}", advance="no"), {iolist}' % { + 'out': {stderr: '0', stdout: '6'}.get(ps.file, '*') + } + fmt = self._print(ps.format_string) + return template.format(fmt=fmt, iolist=', '.join( + (self._print(arg) for arg in ps.print_args))) + + def _print_Return(self, rs): + arg, = rs.args + return "{result_name} = {arg}".format( + result_name=self._context.get('result_name', 'sympy_result'), + arg=self._print(arg) + ) + + def _print_FortranReturn(self, frs): + arg, = frs.args + if arg: + return 'return %s' % self._print(arg) + else: + return 'return' + + def _head(self, entity, fp, **kwargs): + bind_C_params = fp.attr_params('bind_C') + if bind_C_params is None: + bind = '' + else: + bind = ' bind(C, name="%s")' % bind_C_params[0] if bind_C_params else ' bind(C)' + result_name = self._settings.get('result_name', None) + return ( + "{entity}{name}({arg_names}){result}{bind}\n" + "{arg_declarations}" + ).format( + entity=entity, + name=self._print(fp.name), + arg_names=', '.join([self._print(arg.symbol) for arg in fp.parameters]), + result=(' result(%s)' % result_name) if result_name else '', + bind=bind, + arg_declarations='\n'.join((self._print(Declaration(arg)) for arg in fp.parameters)) + ) + + def _print_FunctionPrototype(self, fp): + entity = "{} function ".format(self._print(fp.return_type)) + return ( + "interface\n" + "{function_head}\n" + "end function\n" + "end interface" + ).format(function_head=self._head(entity, fp)) + + def _print_FunctionDefinition(self, fd): + if elemental in fd.attrs: + prefix = 'elemental ' + elif pure in fd.attrs: + prefix = 'pure ' + else: + prefix = '' + + entity = "{} function ".format(self._print(fd.return_type)) + with printer_context(self, result_name=fd.name): + return ( + "{prefix}{function_head}\n" + "{body}\n" + "end function\n" + ).format( + prefix=prefix, + function_head=self._head(entity, fd), + body=self._print(fd.body) + ) + + def _print_Subroutine(self, sub): + return ( + '{subroutine_head}\n' + '{body}\n' + 'end subroutine\n' + ).format( + subroutine_head=self._head('subroutine ', sub), + body=self._print(sub.body) + ) + + def _print_SubroutineCall(self, scall): + return 'call {name}({args})'.format( + name=self._print(scall.name), + args=', '.join((self._print(arg) for arg in scall.subroutine_args)) + ) + + def _print_use_rename(self, rnm): + return "%s => %s" % tuple((self._print(arg) for arg in rnm.args)) + + def _print_use(self, use): + result = 'use %s' % self._print(use.namespace) + if use.rename != None: # Must be '!= None', cannot be 'is not None' + result += ', ' + ', '.join([self._print(rnm) for rnm in use.rename]) + if use.only != None: # Must be '!= None', cannot be 'is not None' + result += ', only: ' + ', '.join([self._print(nly) for nly in use.only]) + return result + + def _print_BreakToken(self, _): + return 'exit' + + def _print_ContinueToken(self, _): + return 'cycle' + + def _print_ArrayConstructor(self, ac): + fmtstr = "[%s]" if self._settings["standard"] >= 2003 else '(/%s/)' + return fmtstr % ', '.join((self._print(arg) for arg in ac.elements)) + + def _print_ArrayElement(self, elem): + return '{symbol}({idxs})'.format( + symbol=self._print(elem.name), + idxs=', '.join((self._print(arg) for arg in elem.indices)) + ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/glsl.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/glsl.py new file mode 100644 index 0000000000000000000000000000000000000000..f98df8d46abec5f891b6bc9836a13ca69934275c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/glsl.py @@ -0,0 +1,548 @@ +from __future__ import annotations + +from sympy.core import Basic, S +from sympy.core.function import Lambda +from sympy.core.numbers import equal_valued +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import precedence +from functools import reduce + +known_functions = { + 'Abs': 'abs', + 'sin': 'sin', + 'cos': 'cos', + 'tan': 'tan', + 'acos': 'acos', + 'asin': 'asin', + 'atan': 'atan', + 'atan2': 'atan', + 'ceiling': 'ceil', + 'floor': 'floor', + 'sign': 'sign', + 'exp': 'exp', + 'log': 'log', + 'add': 'add', + 'sub': 'sub', + 'mul': 'mul', + 'pow': 'pow' +} + +class GLSLPrinter(CodePrinter): + """ + Rudimentary, generic GLSL printing tools. + + Additional settings: + 'use_operators': Boolean (should the printer use operators for +,-,*, or functions?) + """ + _not_supported: set[Basic] = set() + printmethod = "_glsl" + language = "GLSL" + + _default_settings = dict(CodePrinter._default_settings, **{ + 'use_operators': True, + 'zero': 0, + 'mat_nested': False, + 'mat_separator': ',\n', + 'mat_transpose': False, + 'array_type': 'float', + 'glsl_types': True, + + 'precision': 9, + 'user_functions': {}, + 'contract': True, + }) + + def __init__(self, settings={}): + CodePrinter.__init__(self, settings) + self.known_functions = dict(known_functions) + userfuncs = settings.get('user_functions', {}) + self.known_functions.update(userfuncs) + + def _rate_index_position(self, p): + return p*5 + + def _get_statement(self, codestring): + return "%s;" % codestring + + def _get_comment(self, text): + return "// {}".format(text) + + def _declare_number_const(self, name, value): + return "float {} = {};".format(name, value) + + def _format_code(self, lines): + return self.indent_code(lines) + + def indent_code(self, code): + """Accepts a string of code or a list of code lines""" + + if isinstance(code, str): + code_lines = self.indent_code(code.splitlines(True)) + return ''.join(code_lines) + + tab = " " + inc_token = ('{', '(', '{\n', '(\n') + dec_token = ('}', ')') + + code = [line.lstrip(' \t') for line in code] + + increase = [int(any(map(line.endswith, inc_token))) for line in code] + decrease = [int(any(map(line.startswith, dec_token))) for line in code] + + pretty = [] + level = 0 + for n, line in enumerate(code): + if line in ('', '\n'): + pretty.append(line) + continue + level -= decrease[n] + pretty.append("%s%s" % (tab*level, line)) + level += increase[n] + return pretty + + def _print_MatrixBase(self, mat): + mat_separator = self._settings['mat_separator'] + mat_transpose = self._settings['mat_transpose'] + column_vector = (mat.rows == 1) if mat_transpose else (mat.cols == 1) + A = mat.transpose() if mat_transpose != column_vector else mat + + glsl_types = self._settings['glsl_types'] + array_type = self._settings['array_type'] + array_size = A.cols*A.rows + array_constructor = "{}[{}]".format(array_type, array_size) + + if A.cols == 1: + return self._print(A[0]) + if A.rows <= 4 and A.cols <= 4 and glsl_types: + if A.rows == 1: + return "vec{}{}".format( + A.cols, A.table(self,rowstart='(',rowend=')') + ) + elif A.rows == A.cols: + return "mat{}({})".format( + A.rows, A.table(self,rowsep=', ', + rowstart='',rowend='') + ) + else: + return "mat{}x{}({})".format( + A.cols, A.rows, + A.table(self,rowsep=', ', + rowstart='',rowend='') + ) + elif S.One in A.shape: + return "{}({})".format( + array_constructor, + A.table(self,rowsep=mat_separator,rowstart='',rowend='') + ) + elif not self._settings['mat_nested']: + return "{}(\n{}\n) /* a {}x{} matrix */".format( + array_constructor, + A.table(self,rowsep=mat_separator,rowstart='',rowend=''), + A.rows, A.cols + ) + elif self._settings['mat_nested']: + return "{}[{}][{}](\n{}\n)".format( + array_type, A.rows, A.cols, + A.table(self,rowsep=mat_separator,rowstart='float[](',rowend=')') + ) + + def _print_SparseRepMatrix(self, mat): + # do not allow sparse matrices to be made dense + return self._print_not_supported(mat) + + def _traverse_matrix_indices(self, mat): + mat_transpose = self._settings['mat_transpose'] + if mat_transpose: + rows,cols = mat.shape + else: + cols,rows = mat.shape + return ((i, j) for i in range(cols) for j in range(rows)) + + def _print_MatrixElement(self, expr): + # print('begin _print_MatrixElement') + nest = self._settings['mat_nested'] + glsl_types = self._settings['glsl_types'] + mat_transpose = self._settings['mat_transpose'] + if mat_transpose: + cols,rows = expr.parent.shape + i,j = expr.j,expr.i + else: + rows,cols = expr.parent.shape + i,j = expr.i,expr.j + pnt = self._print(expr.parent) + if glsl_types and ((rows <= 4 and cols <=4) or nest): + return "{}[{}][{}]".format(pnt, i, j) + else: + return "{}[{}]".format(pnt, i + j*rows) + + def _print_list(self, expr): + l = ', '.join(self._print(item) for item in expr) + glsl_types = self._settings['glsl_types'] + array_type = self._settings['array_type'] + array_size = len(expr) + array_constructor = '{}[{}]'.format(array_type, array_size) + + if array_size <= 4 and glsl_types: + return 'vec{}({})'.format(array_size, l) + else: + return '{}({})'.format(array_constructor, l) + + _print_tuple = _print_list + _print_Tuple = _print_list + + def _get_loop_opening_ending(self, indices): + open_lines = [] + close_lines = [] + loopstart = "for (int %(varble)s=%(start)s; %(varble)s<%(end)s; %(varble)s++){" + for i in indices: + # GLSL arrays start at 0 and end at dimension-1 + open_lines.append(loopstart % { + 'varble': self._print(i.label), + 'start': self._print(i.lower), + 'end': self._print(i.upper + 1)}) + close_lines.append("}") + return open_lines, close_lines + + def _print_Function_with_args(self, func, func_args): + if func in self.known_functions: + cond_func = self.known_functions[func] + func = None + if isinstance(cond_func, str): + func = cond_func + else: + for cond, func in cond_func: + if cond(func_args): + break + if func is not None: + try: + return func(*[self.parenthesize(item, 0) for item in func_args]) + except TypeError: + return '{}({})'.format(func, self.stringify(func_args, ", ")) + elif isinstance(func, Lambda): + # inlined function + return self._print(func(*func_args)) + else: + return self._print_not_supported(func) + + def _print_Piecewise(self, expr): + from sympy.codegen.ast import Assignment + if expr.args[-1].cond != True: + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + lines = [] + if expr.has(Assignment): + for i, (e, c) in enumerate(expr.args): + if i == 0: + lines.append("if (%s) {" % self._print(c)) + elif i == len(expr.args) - 1 and c == True: + lines.append("else {") + else: + lines.append("else if (%s) {" % self._print(c)) + code0 = self._print(e) + lines.append(code0) + lines.append("}") + return "\n".join(lines) + else: + # The piecewise was used in an expression, need to do inline + # operators. This has the downside that inline operators will + # not work for statements that span multiple lines (Matrix or + # Indexed expressions). + ecpairs = ["((%s) ? (\n%s\n)\n" % (self._print(c), + self._print(e)) + for e, c in expr.args[:-1]] + last_line = ": (\n%s\n)" % self._print(expr.args[-1].expr) + return ": ".join(ecpairs) + last_line + " ".join([")"*len(ecpairs)]) + + def _print_Indexed(self, expr): + # calculate index for 1d array + dims = expr.shape + elem = S.Zero + offset = S.One + for i in reversed(range(expr.rank)): + elem += expr.indices[i]*offset + offset *= dims[i] + return "{}[{}]".format( + self._print(expr.base.label), + self._print(elem) + ) + + def _print_Pow(self, expr): + PREC = precedence(expr) + if equal_valued(expr.exp, -1): + return '1.0/%s' % (self.parenthesize(expr.base, PREC)) + elif equal_valued(expr.exp, 0.5): + return 'sqrt(%s)' % self._print(expr.base) + else: + try: + e = self._print(float(expr.exp)) + except TypeError: + e = self._print(expr.exp) + return self._print_Function_with_args('pow', ( + self._print(expr.base), + e + )) + + def _print_int(self, expr): + return str(float(expr)) + + def _print_Rational(self, expr): + return "{}.0/{}.0".format(expr.p, expr.q) + + def _print_Relational(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + op = expr.rel_op + return "{} {} {}".format(lhs_code, op, rhs_code) + + def _print_Add(self, expr, order=None): + if self._settings['use_operators']: + return CodePrinter._print_Add(self, expr, order=order) + + terms = expr.as_ordered_terms() + + def partition(p,l): + return reduce(lambda x, y: (x[0]+[y], x[1]) if p(y) else (x[0], x[1]+[y]), l, ([], [])) + def add(a,b): + return self._print_Function_with_args('add', (a, b)) + # return self.known_functions['add']+'(%s, %s)' % (a,b) + neg, pos = partition(lambda arg: arg.could_extract_minus_sign(), terms) + if pos: + s = pos = reduce(lambda a,b: add(a,b), (self._print(t) for t in pos)) + else: + s = pos = self._print(self._settings['zero']) + + if neg: + # sum the absolute values of the negative terms + neg = reduce(lambda a,b: add(a,b), (self._print(-n) for n in neg)) + # then subtract them from the positive terms + s = self._print_Function_with_args('sub', (pos,neg)) + # s = self.known_functions['sub']+'(%s, %s)' % (pos,neg) + return s + + def _print_Mul(self, expr, **kwargs): + if self._settings['use_operators']: + return CodePrinter._print_Mul(self, expr, **kwargs) + terms = expr.as_ordered_factors() + def mul(a,b): + # return self.known_functions['mul']+'(%s, %s)' % (a,b) + return self._print_Function_with_args('mul', (a,b)) + + s = reduce(lambda a,b: mul(a,b), (self._print(t) for t in terms)) + return s + +def glsl_code(expr,assign_to=None,**settings): + """Converts an expr to a string of GLSL code + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used for naming the variable or variables + to which the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol`` or ``Indexed`` type object. In cases where ``expr`` + would be printed as an array, a list of string or ``Symbol`` objects + can also be passed. + + This is helpful in case of line-wrapping, or for expressions that + generate multi-line statements. It can also be used to spread an array-like + expression into multiple assignments. + use_operators: bool, optional + If set to False, then *,/,+,- operators will be replaced with functions + mul, add, and sub, which must be implemented by the user, e.g. for + implementing non-standard rings or emulated quad/octal precision. + [default=True] + glsl_types: bool, optional + Set this argument to ``False`` in order to avoid using the ``vec`` and ``mat`` + types. The printer will instead use arrays (or nested arrays). + [default=True] + mat_nested: bool, optional + GLSL version 4.3 and above support nested arrays (arrays of arrays). Set this to ``True`` + to render matrices as nested arrays. + [default=False] + mat_separator: str, optional + By default, matrices are rendered with newlines using this separator, + making them easier to read, but less compact. By removing the newline + this option can be used to make them more vertically compact. + [default=',\n'] + mat_transpose: bool, optional + GLSL's matrix multiplication implementation assumes column-major indexing. + By default, this printer ignores that convention. Setting this option to + ``True`` transposes all matrix output. + [default=False] + array_type: str, optional + The GLSL array constructor type. + [default='float'] + precision : integer, optional + The precision for numbers such as pi [default=15]. + user_functions : dict, optional + A dictionary where keys are ``FunctionClass`` instances and values are + their string representations. Alternatively, the dictionary value can + be a list of tuples i.e. [(argument_test, js_function_string)]. See + below for examples. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + + Examples + ======== + + >>> from sympy import glsl_code, symbols, Rational, sin, ceiling, Abs + >>> x, tau = symbols("x, tau") + >>> glsl_code((2*tau)**Rational(7, 2)) + '8*sqrt(2)*pow(tau, 3.5)' + >>> glsl_code(sin(x), assign_to="float y") + 'float y = sin(x);' + + Various GLSL types are supported: + >>> from sympy import Matrix, glsl_code + >>> glsl_code(Matrix([1,2,3])) + 'vec3(1, 2, 3)' + + >>> glsl_code(Matrix([[1, 2],[3, 4]])) + 'mat2(1, 2, 3, 4)' + + Pass ``mat_transpose = True`` to switch to column-major indexing: + >>> glsl_code(Matrix([[1, 2],[3, 4]]), mat_transpose = True) + 'mat2(1, 3, 2, 4)' + + By default, larger matrices get collapsed into float arrays: + >>> print(glsl_code( Matrix([[1,2,3,4,5],[6,7,8,9,10]]) )) + float[10]( + 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 + ) /* a 2x5 matrix */ + + The type of array constructor used to print GLSL arrays can be controlled + via the ``array_type`` parameter: + >>> glsl_code(Matrix([1,2,3,4,5]), array_type='int') + 'int[5](1, 2, 3, 4, 5)' + + Passing a list of strings or ``symbols`` to the ``assign_to`` parameter will yield + a multi-line assignment for each item in an array-like expression: + >>> x_struct_members = symbols('x.a x.b x.c x.d') + >>> print(glsl_code(Matrix([1,2,3,4]), assign_to=x_struct_members)) + x.a = 1; + x.b = 2; + x.c = 3; + x.d = 4; + + This could be useful in cases where it's desirable to modify members of a + GLSL ``Struct``. It could also be used to spread items from an array-like + expression into various miscellaneous assignments: + >>> misc_assignments = ('x[0]', 'x[1]', 'float y', 'float z') + >>> print(glsl_code(Matrix([1,2,3,4]), assign_to=misc_assignments)) + x[0] = 1; + x[1] = 2; + float y = 3; + float z = 4; + + Passing ``mat_nested = True`` instead prints out nested float arrays, which are + supported in GLSL 4.3 and above. + >>> mat = Matrix([ + ... [ 0, 1, 2], + ... [ 3, 4, 5], + ... [ 6, 7, 8], + ... [ 9, 10, 11], + ... [12, 13, 14]]) + >>> print(glsl_code( mat, mat_nested = True )) + float[5][3]( + float[]( 0, 1, 2), + float[]( 3, 4, 5), + float[]( 6, 7, 8), + float[]( 9, 10, 11), + float[](12, 13, 14) + ) + + + + Custom printing can be defined for certain types by passing a dictionary of + "type" : "function" to the ``user_functions`` kwarg. Alternatively, the + dictionary value can be a list of tuples i.e. [(argument_test, + js_function_string)]. + + >>> custom_functions = { + ... "ceiling": "CEIL", + ... "Abs": [(lambda x: not x.is_integer, "fabs"), + ... (lambda x: x.is_integer, "ABS")] + ... } + >>> glsl_code(Abs(x) + ceiling(x), user_functions=custom_functions) + 'fabs(x) + CEIL(x)' + + If further control is needed, addition, subtraction, multiplication and + division operators can be replaced with ``add``, ``sub``, and ``mul`` + functions. This is done by passing ``use_operators = False``: + + >>> x,y,z = symbols('x,y,z') + >>> glsl_code(x*(y+z), use_operators = False) + 'mul(x, add(y, z))' + >>> glsl_code(x*(y+z*(x-y)**z), use_operators = False) + 'mul(x, add(y, mul(z, pow(sub(x, y), z))))' + + ``Piecewise`` expressions are converted into conditionals. If an + ``assign_to`` variable is provided an if statement is created, otherwise + the ternary operator is used. Note that if the ``Piecewise`` lacks a + default term, represented by ``(expr, True)`` then an error will be thrown. + This is to prevent generating an expression that may not evaluate to + anything. + + >>> from sympy import Piecewise + >>> expr = Piecewise((x + 1, x > 0), (x, True)) + >>> print(glsl_code(expr, tau)) + if (x > 0) { + tau = x + 1; + } + else { + tau = x; + } + + Support for loops is provided through ``Indexed`` types. With + ``contract=True`` these expressions will be turned into loops, whereas + ``contract=False`` will just print the assignment expression that should be + looped over: + + >>> from sympy import Eq, IndexedBase, Idx + >>> len_y = 5 + >>> y = IndexedBase('y', shape=(len_y,)) + >>> t = IndexedBase('t', shape=(len_y,)) + >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) + >>> i = Idx('i', len_y-1) + >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) + >>> glsl_code(e.rhs, assign_to=e.lhs, contract=False) + 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' + + >>> from sympy import Matrix, MatrixSymbol + >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) + >>> A = MatrixSymbol('A', 3, 1) + >>> print(glsl_code(mat, A)) + A[0][0] = pow(x, 2.0); + if (x > 0) { + A[1][0] = x + 1; + } + else { + A[1][0] = x; + } + A[2][0] = sin(x); + """ + return GLSLPrinter(settings).doprint(expr,assign_to) + +def print_glsl(expr, **settings): + """Prints the GLSL representation of the given expression. + + See GLSLPrinter init function for settings. + """ + print(glsl_code(expr, **settings)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/gtk.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/gtk.py new file mode 100644 index 0000000000000000000000000000000000000000..4123d7231c730bbde28e33f441470c28b21c78d0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/gtk.py @@ -0,0 +1,16 @@ +from sympy.printing.mathml import mathml +from sympy.utilities.mathml import c2p +import tempfile +import subprocess + + +def print_gtk(x, start_viewer=True): + """Print to Gtkmathview, a gtk widget capable of rendering MathML. + + Needs libgtkmathview-bin""" + with tempfile.NamedTemporaryFile('w') as file: + file.write(c2p(mathml(x), simple=True)) + file.flush() + + if start_viewer: + subprocess.check_call(('mathmlviewer', file.name)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/jscode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/jscode.py new file mode 100644 index 0000000000000000000000000000000000000000..753eb3291dd719ff53b06584de8ebe76c4471a3f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/jscode.py @@ -0,0 +1,332 @@ +""" +Javascript code printer + +The JavascriptCodePrinter converts single SymPy expressions into single +Javascript expressions, using the functions defined in the Javascript +Math object where possible. + +""" + +from __future__ import annotations +from typing import Any + +from sympy.core import S +from sympy.core.numbers import equal_valued +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import precedence, PRECEDENCE + + +# dictionary mapping SymPy function to (argument_conditions, Javascript_function). +# Used in JavascriptCodePrinter._print_Function(self) +known_functions = { + 'Abs': 'Math.abs', + 'acos': 'Math.acos', + 'acosh': 'Math.acosh', + 'asin': 'Math.asin', + 'asinh': 'Math.asinh', + 'atan': 'Math.atan', + 'atan2': 'Math.atan2', + 'atanh': 'Math.atanh', + 'ceiling': 'Math.ceil', + 'cos': 'Math.cos', + 'cosh': 'Math.cosh', + 'exp': 'Math.exp', + 'floor': 'Math.floor', + 'log': 'Math.log', + 'Max': 'Math.max', + 'Min': 'Math.min', + 'sign': 'Math.sign', + 'sin': 'Math.sin', + 'sinh': 'Math.sinh', + 'tan': 'Math.tan', + 'tanh': 'Math.tanh', +} + + +class JavascriptCodePrinter(CodePrinter): + """"A Printer to convert Python expressions to strings of JavaScript code + """ + printmethod = '_javascript' + language = 'JavaScript' + + _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{ + 'precision': 17, + 'user_functions': {}, + 'contract': True, + }) + + def __init__(self, settings={}): + CodePrinter.__init__(self, settings) + self.known_functions = dict(known_functions) + userfuncs = settings.get('user_functions', {}) + self.known_functions.update(userfuncs) + + def _rate_index_position(self, p): + return p*5 + + def _get_statement(self, codestring): + return "%s;" % codestring + + def _get_comment(self, text): + return "// {}".format(text) + + def _declare_number_const(self, name, value): + return "var {} = {};".format(name, value.evalf(self._settings['precision'])) + + def _format_code(self, lines): + return self.indent_code(lines) + + def _traverse_matrix_indices(self, mat): + rows, cols = mat.shape + return ((i, j) for i in range(rows) for j in range(cols)) + + def _get_loop_opening_ending(self, indices): + open_lines = [] + close_lines = [] + loopstart = "for (var %(varble)s=%(start)s; %(varble)s<%(end)s; %(varble)s++){" + for i in indices: + # Javascript arrays start at 0 and end at dimension-1 + open_lines.append(loopstart % { + 'varble': self._print(i.label), + 'start': self._print(i.lower), + 'end': self._print(i.upper + 1)}) + close_lines.append("}") + return open_lines, close_lines + + def _print_Pow(self, expr): + PREC = precedence(expr) + if equal_valued(expr.exp, -1): + return '1/%s' % (self.parenthesize(expr.base, PREC)) + elif equal_valued(expr.exp, 0.5): + return 'Math.sqrt(%s)' % self._print(expr.base) + elif expr.exp == S.One/3: + return 'Math.cbrt(%s)' % self._print(expr.base) + else: + return 'Math.pow(%s, %s)' % (self._print(expr.base), + self._print(expr.exp)) + + def _print_Rational(self, expr): + p, q = int(expr.p), int(expr.q) + return '%d/%d' % (p, q) + + def _print_Mod(self, expr): + num, den = expr.args + PREC = precedence(expr) + snum, sden = [self.parenthesize(arg, PREC) for arg in expr.args] + # % is remainder (same sign as numerator), not modulo (same sign as + # denominator), in js. Hence, % only works as modulo if both numbers + # have the same sign + if (num.is_nonnegative and den.is_nonnegative or + num.is_nonpositive and den.is_nonpositive): + return f"{snum} % {sden}" + return f"(({snum} % {sden}) + {sden}) % {sden}" + + def _print_Relational(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + op = expr.rel_op + return "{} {} {}".format(lhs_code, op, rhs_code) + + def _print_Indexed(self, expr): + # calculate index for 1d array + dims = expr.shape + elem = S.Zero + offset = S.One + for i in reversed(range(expr.rank)): + elem += expr.indices[i]*offset + offset *= dims[i] + return "%s[%s]" % (self._print(expr.base.label), self._print(elem)) + + def _print_Exp1(self, expr): + return "Math.E" + + def _print_Pi(self, expr): + return 'Math.PI' + + def _print_Infinity(self, expr): + return 'Number.POSITIVE_INFINITY' + + def _print_NegativeInfinity(self, expr): + return 'Number.NEGATIVE_INFINITY' + + def _print_Piecewise(self, expr): + from sympy.codegen.ast import Assignment + if expr.args[-1].cond != True: + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + lines = [] + if expr.has(Assignment): + for i, (e, c) in enumerate(expr.args): + if i == 0: + lines.append("if (%s) {" % self._print(c)) + elif i == len(expr.args) - 1 and c == True: + lines.append("else {") + else: + lines.append("else if (%s) {" % self._print(c)) + code0 = self._print(e) + lines.append(code0) + lines.append("}") + return "\n".join(lines) + else: + # The piecewise was used in an expression, need to do inline + # operators. This has the downside that inline operators will + # not work for statements that span multiple lines (Matrix or + # Indexed expressions). + ecpairs = ["((%s) ? (\n%s\n)\n" % (self._print(c), self._print(e)) + for e, c in expr.args[:-1]] + last_line = ": (\n%s\n)" % self._print(expr.args[-1].expr) + return ": ".join(ecpairs) + last_line + " ".join([")"*len(ecpairs)]) + + def _print_MatrixElement(self, expr): + return "{}[{}]".format(self.parenthesize(expr.parent, + PRECEDENCE["Atom"], strict=True), + expr.j + expr.i*expr.parent.shape[1]) + + def indent_code(self, code): + """Accepts a string of code or a list of code lines""" + + if isinstance(code, str): + code_lines = self.indent_code(code.splitlines(True)) + return ''.join(code_lines) + + tab = " " + inc_token = ('{', '(', '{\n', '(\n') + dec_token = ('}', ')') + + code = [ line.lstrip(' \t') for line in code ] + + increase = [ int(any(map(line.endswith, inc_token))) for line in code ] + decrease = [ int(any(map(line.startswith, dec_token))) + for line in code ] + + pretty = [] + level = 0 + for n, line in enumerate(code): + if line in ('', '\n'): + pretty.append(line) + continue + level -= decrease[n] + pretty.append("%s%s" % (tab*level, line)) + level += increase[n] + return pretty + + +def jscode(expr, assign_to=None, **settings): + """Converts an expr to a string of javascript code + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used as the name of the variable to which + the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of + line-wrapping, or for expressions that generate multi-line statements. + precision : integer, optional + The precision for numbers such as pi [default=15]. + user_functions : dict, optional + A dictionary where keys are ``FunctionClass`` instances and values are + their string representations. Alternatively, the dictionary value can + be a list of tuples i.e. [(argument_test, js_function_string)]. See + below for examples. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + + Examples + ======== + + >>> from sympy import jscode, symbols, Rational, sin, ceiling, Abs + >>> x, tau = symbols("x, tau") + >>> jscode((2*tau)**Rational(7, 2)) + '8*Math.sqrt(2)*Math.pow(tau, 7/2)' + >>> jscode(sin(x), assign_to="s") + 's = Math.sin(x);' + + Custom printing can be defined for certain types by passing a dictionary of + "type" : "function" to the ``user_functions`` kwarg. Alternatively, the + dictionary value can be a list of tuples i.e. [(argument_test, + js_function_string)]. + + >>> custom_functions = { + ... "ceiling": "CEIL", + ... "Abs": [(lambda x: not x.is_integer, "fabs"), + ... (lambda x: x.is_integer, "ABS")] + ... } + >>> jscode(Abs(x) + ceiling(x), user_functions=custom_functions) + 'fabs(x) + CEIL(x)' + + ``Piecewise`` expressions are converted into conditionals. If an + ``assign_to`` variable is provided an if statement is created, otherwise + the ternary operator is used. Note that if the ``Piecewise`` lacks a + default term, represented by ``(expr, True)`` then an error will be thrown. + This is to prevent generating an expression that may not evaluate to + anything. + + >>> from sympy import Piecewise + >>> expr = Piecewise((x + 1, x > 0), (x, True)) + >>> print(jscode(expr, tau)) + if (x > 0) { + tau = x + 1; + } + else { + tau = x; + } + + Support for loops is provided through ``Indexed`` types. With + ``contract=True`` these expressions will be turned into loops, whereas + ``contract=False`` will just print the assignment expression that should be + looped over: + + >>> from sympy import Eq, IndexedBase, Idx + >>> len_y = 5 + >>> y = IndexedBase('y', shape=(len_y,)) + >>> t = IndexedBase('t', shape=(len_y,)) + >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) + >>> i = Idx('i', len_y-1) + >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) + >>> jscode(e.rhs, assign_to=e.lhs, contract=False) + 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' + + Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions + must be provided to ``assign_to``. Note that any expression that can be + generated normally can also exist inside a Matrix: + + >>> from sympy import Matrix, MatrixSymbol + >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) + >>> A = MatrixSymbol('A', 3, 1) + >>> print(jscode(mat, A)) + A[0] = Math.pow(x, 2); + if (x > 0) { + A[1] = x + 1; + } + else { + A[1] = x; + } + A[2] = Math.sin(x); + """ + + return JavascriptCodePrinter(settings).doprint(expr, assign_to) + + +def print_jscode(expr, **settings): + """Prints the Javascript representation of the given expression. + + See jscode for the meaning of the optional arguments. + """ + print(jscode(expr, **settings)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/julia.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/julia.py new file mode 100644 index 0000000000000000000000000000000000000000..3ab815add4d87fe953f646409e3a7bb383b1bbc6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/julia.py @@ -0,0 +1,652 @@ +""" +Julia code printer + +The `JuliaCodePrinter` converts SymPy expressions into Julia expressions. + +A complete code generator, which uses `julia_code` extensively, can be found +in `sympy.utilities.codegen`. The `codegen` module can be used to generate +complete source code files. + +""" + +from __future__ import annotations +from typing import Any + +from sympy.core import Mul, Pow, S, Rational +from sympy.core.mul import _keep_coeff +from sympy.core.numbers import equal_valued +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import precedence, PRECEDENCE +from re import search + +# List of known functions. First, those that have the same name in +# SymPy and Julia. This is almost certainly incomplete! +known_fcns_src1 = ["sin", "cos", "tan", "cot", "sec", "csc", + "asin", "acos", "atan", "acot", "asec", "acsc", + "sinh", "cosh", "tanh", "coth", "sech", "csch", + "asinh", "acosh", "atanh", "acoth", "asech", "acsch", + "atan2", "sign", "floor", "log", "exp", + "cbrt", "sqrt", "erf", "erfc", "erfi", + "factorial", "gamma", "digamma", "trigamma", + "polygamma", "beta", + "airyai", "airyaiprime", "airybi", "airybiprime", + "besselj", "bessely", "besseli", "besselk", + "erfinv", "erfcinv"] +# These functions have different names ("SymPy": "Julia"), more +# generally a mapping to (argument_conditions, julia_function). +known_fcns_src2 = { + "Abs": "abs", + "ceiling": "ceil", + "conjugate": "conj", + "hankel1": "hankelh1", + "hankel2": "hankelh2", + "im": "imag", + "re": "real" +} + + +class JuliaCodePrinter(CodePrinter): + """ + A printer to convert expressions to strings of Julia code. + """ + printmethod = "_julia" + language = "Julia" + + _operators = { + 'and': '&&', + 'or': '||', + 'not': '!', + } + + _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{ + 'precision': 17, + 'user_functions': {}, + 'contract': True, + 'inline': True, + }) + # Note: contract is for expressing tensors as loops (if True), or just + # assignment (if False). FIXME: this should be looked a more carefully + # for Julia. + + def __init__(self, settings={}): + super().__init__(settings) + self.known_functions = dict(zip(known_fcns_src1, known_fcns_src1)) + self.known_functions.update(dict(known_fcns_src2)) + userfuncs = settings.get('user_functions', {}) + self.known_functions.update(userfuncs) + + + def _rate_index_position(self, p): + return p*5 + + + def _get_statement(self, codestring): + return "%s" % codestring + + + def _get_comment(self, text): + return "# {}".format(text) + + + def _declare_number_const(self, name, value): + return "const {} = {}".format(name, value) + + + def _format_code(self, lines): + return self.indent_code(lines) + + + def _traverse_matrix_indices(self, mat): + # Julia uses Fortran order (column-major) + rows, cols = mat.shape + return ((i, j) for j in range(cols) for i in range(rows)) + + + def _get_loop_opening_ending(self, indices): + open_lines = [] + close_lines = [] + for i in indices: + # Julia arrays start at 1 and end at dimension + var, start, stop = map(self._print, + [i.label, i.lower + 1, i.upper + 1]) + open_lines.append("for %s = %s:%s" % (var, start, stop)) + close_lines.append("end") + return open_lines, close_lines + + + def _print_Mul(self, expr): + # print complex numbers nicely in Julia + if (expr.is_number and expr.is_imaginary and + expr.as_coeff_Mul()[0].is_integer): + return "%sim" % self._print(-S.ImaginaryUnit*expr) + + # cribbed from str.py + prec = precedence(expr) + + c, e = expr.as_coeff_Mul() + if c < 0: + expr = _keep_coeff(-c, e) + sign = "-" + else: + sign = "" + + a = [] # items in the numerator + b = [] # items that are in the denominator (if any) + + pow_paren = [] # Will collect all pow with more than one base element and exp = -1 + + if self.order not in ('old', 'none'): + args = expr.as_ordered_factors() + else: + # use make_args in case expr was something like -x -> x + args = Mul.make_args(expr) + + # Gather args for numerator/denominator + for item in args: + if (item.is_commutative and item.is_Pow and item.exp.is_Rational + and item.exp.is_negative): + if item.exp != -1: + b.append(Pow(item.base, -item.exp, evaluate=False)) + else: + if len(item.args[0].args) != 1 and isinstance(item.base, Mul): # To avoid situations like #14160 + pow_paren.append(item) + b.append(Pow(item.base, -item.exp)) + elif item.is_Rational and item is not S.Infinity and item.p == 1: + # Save the Rational type in julia Unless the numerator is 1. + # For example: + # julia_code(Rational(3, 7)*x) --> (3 // 7) * x + # julia_code(x/3) --> x / 3 but not x * (1 // 3) + b.append(Rational(item.q)) + else: + a.append(item) + + a = a or [S.One] + + a_str = [self.parenthesize(x, prec) for x in a] + b_str = [self.parenthesize(x, prec) for x in b] + + # To parenthesize Pow with exp = -1 and having more than one Symbol + for item in pow_paren: + if item.base in b: + b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] + + # from here it differs from str.py to deal with "*" and ".*" + def multjoin(a, a_str): + # here we probably are assuming the constants will come first + r = a_str[0] + for i in range(1, len(a)): + mulsym = '*' if a[i-1].is_number else '.*' + r = "%s %s %s" % (r, mulsym, a_str[i]) + return r + + if not b: + return sign + multjoin(a, a_str) + elif len(b) == 1: + divsym = '/' if b[0].is_number else './' + return "%s %s %s" % (sign+multjoin(a, a_str), divsym, b_str[0]) + else: + divsym = '/' if all(bi.is_number for bi in b) else './' + return "%s %s (%s)" % (sign + multjoin(a, a_str), divsym, multjoin(b, b_str)) + + def _print_Relational(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + op = expr.rel_op + return "{} {} {}".format(lhs_code, op, rhs_code) + + def _print_Pow(self, expr): + powsymbol = '^' if all(x.is_number for x in expr.args) else '.^' + + PREC = precedence(expr) + + if equal_valued(expr.exp, 0.5): + return "sqrt(%s)" % self._print(expr.base) + + if expr.is_commutative: + if equal_valued(expr.exp, -0.5): + sym = '/' if expr.base.is_number else './' + return "1 %s sqrt(%s)" % (sym, self._print(expr.base)) + if equal_valued(expr.exp, -1): + sym = '/' if expr.base.is_number else './' + return "1 %s %s" % (sym, self.parenthesize(expr.base, PREC)) + + return '%s %s %s' % (self.parenthesize(expr.base, PREC), powsymbol, + self.parenthesize(expr.exp, PREC)) + + + def _print_MatPow(self, expr): + PREC = precedence(expr) + return '%s ^ %s' % (self.parenthesize(expr.base, PREC), + self.parenthesize(expr.exp, PREC)) + + + def _print_Pi(self, expr): + if self._settings["inline"]: + return "pi" + else: + return super()._print_NumberSymbol(expr) + + + def _print_ImaginaryUnit(self, expr): + return "im" + + + def _print_Exp1(self, expr): + if self._settings["inline"]: + return "e" + else: + return super()._print_NumberSymbol(expr) + + + def _print_EulerGamma(self, expr): + if self._settings["inline"]: + return "eulergamma" + else: + return super()._print_NumberSymbol(expr) + + + def _print_Catalan(self, expr): + if self._settings["inline"]: + return "catalan" + else: + return super()._print_NumberSymbol(expr) + + + def _print_GoldenRatio(self, expr): + if self._settings["inline"]: + return "golden" + else: + return super()._print_NumberSymbol(expr) + + + def _print_Assignment(self, expr): + from sympy.codegen.ast import Assignment + from sympy.functions.elementary.piecewise import Piecewise + from sympy.tensor.indexed import IndexedBase + # Copied from codeprinter, but remove special MatrixSymbol treatment + lhs = expr.lhs + rhs = expr.rhs + # We special case assignments that take multiple lines + if not self._settings["inline"] and isinstance(expr.rhs, Piecewise): + # Here we modify Piecewise so each expression is now + # an Assignment, and then continue on the print. + expressions = [] + conditions = [] + for (e, c) in rhs.args: + expressions.append(Assignment(lhs, e)) + conditions.append(c) + temp = Piecewise(*zip(expressions, conditions)) + return self._print(temp) + if self._settings["contract"] and (lhs.has(IndexedBase) or + rhs.has(IndexedBase)): + # Here we check if there is looping to be done, and if so + # print the required loops. + return self._doprint_loops(rhs, lhs) + else: + lhs_code = self._print(lhs) + rhs_code = self._print(rhs) + return self._get_statement("%s = %s" % (lhs_code, rhs_code)) + + + def _print_Infinity(self, expr): + return 'Inf' + + + def _print_NegativeInfinity(self, expr): + return '-Inf' + + + def _print_NaN(self, expr): + return 'NaN' + + + def _print_list(self, expr): + return 'Any[' + ', '.join(self._print(a) for a in expr) + ']' + + + def _print_tuple(self, expr): + if len(expr) == 1: + return "(%s,)" % self._print(expr[0]) + else: + return "(%s)" % self.stringify(expr, ", ") + _print_Tuple = _print_tuple + + + def _print_BooleanTrue(self, expr): + return "true" + + + def _print_BooleanFalse(self, expr): + return "false" + + + def _print_bool(self, expr): + return str(expr).lower() + + + # Could generate quadrature code for definite Integrals? + #_print_Integral = _print_not_supported + + + def _print_MatrixBase(self, A): + # Handle zero dimensions: + if S.Zero in A.shape: + return 'zeros(%s, %s)' % (A.rows, A.cols) + elif (A.rows, A.cols) == (1, 1): + return "[%s]" % A[0, 0] + elif A.rows == 1: + return "[%s]" % A.table(self, rowstart='', rowend='', colsep=' ') + elif A.cols == 1: + # note .table would unnecessarily equispace the rows + return "[%s]" % ", ".join([self._print(a) for a in A]) + return "[%s]" % A.table(self, rowstart='', rowend='', + rowsep=';\n', colsep=' ') + + + def _print_SparseRepMatrix(self, A): + from sympy.matrices import Matrix + L = A.col_list() + # make row vectors of the indices and entries + I = Matrix([k[0] + 1 for k in L]) + J = Matrix([k[1] + 1 for k in L]) + AIJ = Matrix([k[2] for k in L]) + return "sparse(%s, %s, %s, %s, %s)" % (self._print(I), self._print(J), + self._print(AIJ), A.rows, A.cols) + + + def _print_MatrixElement(self, expr): + return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \ + + '[%s,%s]' % (expr.i + 1, expr.j + 1) + + + def _print_MatrixSlice(self, expr): + def strslice(x, lim): + l = x[0] + 1 + h = x[1] + step = x[2] + lstr = self._print(l) + hstr = 'end' if h == lim else self._print(h) + if step == 1: + if l == 1 and h == lim: + return ':' + if l == h: + return lstr + else: + return lstr + ':' + hstr + else: + return ':'.join((lstr, self._print(step), hstr)) + return (self._print(expr.parent) + '[' + + strslice(expr.rowslice, expr.parent.shape[0]) + ',' + + strslice(expr.colslice, expr.parent.shape[1]) + ']') + + + def _print_Indexed(self, expr): + inds = [ self._print(i) for i in expr.indices ] + return "%s[%s]" % (self._print(expr.base.label), ",".join(inds)) + + def _print_Identity(self, expr): + return "eye(%s)" % self._print(expr.shape[0]) + + def _print_HadamardProduct(self, expr): + return ' .* '.join([self.parenthesize(arg, precedence(expr)) + for arg in expr.args]) + + def _print_HadamardPower(self, expr): + PREC = precedence(expr) + return '.**'.join([ + self.parenthesize(expr.base, PREC), + self.parenthesize(expr.exp, PREC) + ]) + + def _print_Rational(self, expr): + if expr.q == 1: + return str(expr.p) + return "%s // %s" % (expr.p, expr.q) + + # Note: as of 2022, Julia doesn't have spherical Bessel functions + def _print_jn(self, expr): + from sympy.functions import sqrt, besselj + x = expr.argument + expr2 = sqrt(S.Pi/(2*x))*besselj(expr.order + S.Half, x) + return self._print(expr2) + + + def _print_yn(self, expr): + from sympy.functions import sqrt, bessely + x = expr.argument + expr2 = sqrt(S.Pi/(2*x))*bessely(expr.order + S.Half, x) + return self._print(expr2) + + def _print_sinc(self, expr): + # Julia has the normalized sinc function + return "sinc({})".format(self._print(expr.args[0] / S.Pi)) + + def _print_Piecewise(self, expr): + if expr.args[-1].cond != True: + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + lines = [] + if self._settings["inline"]: + # Express each (cond, expr) pair in a nested Horner form: + # (condition) .* (expr) + (not cond) .* () + # Expressions that result in multiple statements won't work here. + ecpairs = ["({}) ? ({}) :".format + (self._print(c), self._print(e)) + for e, c in expr.args[:-1]] + elast = " (%s)" % self._print(expr.args[-1].expr) + pw = "\n".join(ecpairs) + elast + # Note: current need these outer brackets for 2*pw. Would be + # nicer to teach parenthesize() to do this for us when needed! + return "(" + pw + ")" + else: + for i, (e, c) in enumerate(expr.args): + if i == 0: + lines.append("if (%s)" % self._print(c)) + elif i == len(expr.args) - 1 and c == True: + lines.append("else") + else: + lines.append("elseif (%s)" % self._print(c)) + code0 = self._print(e) + lines.append(code0) + if i == len(expr.args) - 1: + lines.append("end") + return "\n".join(lines) + + def _print_MatMul(self, expr): + c, m = expr.as_coeff_mmul() + + sign = "" + if c.is_number: + re, im = c.as_real_imag() + if im.is_zero and re.is_negative: + expr = _keep_coeff(-c, m) + sign = "-" + elif re.is_zero and im.is_negative: + expr = _keep_coeff(-c, m) + sign = "-" + + return sign + ' * '.join( + (self.parenthesize(arg, precedence(expr)) for arg in expr.args) + ) + + + def indent_code(self, code): + """Accepts a string of code or a list of code lines""" + + # code mostly copied from ccode + if isinstance(code, str): + code_lines = self.indent_code(code.splitlines(True)) + return ''.join(code_lines) + + tab = " " + inc_regex = ('^function ', '^if ', '^elseif ', '^else$', '^for ') + dec_regex = ('^end$', '^elseif ', '^else$') + + # pre-strip left-space from the code + code = [ line.lstrip(' \t') for line in code ] + + increase = [ int(any(search(re, line) for re in inc_regex)) + for line in code ] + decrease = [ int(any(search(re, line) for re in dec_regex)) + for line in code ] + + pretty = [] + level = 0 + for n, line in enumerate(code): + if line in ('', '\n'): + pretty.append(line) + continue + level -= decrease[n] + pretty.append("%s%s" % (tab*level, line)) + level += increase[n] + return pretty + + +def julia_code(expr, assign_to=None, **settings): + r"""Converts `expr` to a string of Julia code. + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used as the name of the variable to which + the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for + expressions that generate multi-line statements. + precision : integer, optional + The precision for numbers such as pi [default=16]. + user_functions : dict, optional + A dictionary where keys are ``FunctionClass`` instances and values are + their string representations. Alternatively, the dictionary value can + be a list of tuples i.e. [(argument_test, cfunction_string)]. See + below for examples. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + inline: bool, optional + If True, we try to create single-statement code instead of multiple + statements. [default=True]. + + Examples + ======== + + >>> from sympy import julia_code, symbols, sin, pi + >>> x = symbols('x') + >>> julia_code(sin(x).series(x).removeO()) + 'x .^ 5 / 120 - x .^ 3 / 6 + x' + + >>> from sympy import Rational, ceiling + >>> x, y, tau = symbols("x, y, tau") + >>> julia_code((2*tau)**Rational(7, 2)) + '8 * sqrt(2) * tau .^ (7 // 2)' + + Note that element-wise (Hadamard) operations are used by default between + symbols. This is because its possible in Julia to write "vectorized" + code. It is harmless if the values are scalars. + + >>> julia_code(sin(pi*x*y), assign_to="s") + 's = sin(pi * x .* y)' + + If you need a matrix product "*" or matrix power "^", you can specify the + symbol as a ``MatrixSymbol``. + + >>> from sympy import Symbol, MatrixSymbol + >>> n = Symbol('n', integer=True, positive=True) + >>> A = MatrixSymbol('A', n, n) + >>> julia_code(3*pi*A**3) + '(3 * pi) * A ^ 3' + + This class uses several rules to decide which symbol to use a product. + Pure numbers use "*", Symbols use ".*" and MatrixSymbols use "*". + A HadamardProduct can be used to specify componentwise multiplication ".*" + of two MatrixSymbols. There is currently there is no easy way to specify + scalar symbols, so sometimes the code might have some minor cosmetic + issues. For example, suppose x and y are scalars and A is a Matrix, then + while a human programmer might write "(x^2*y)*A^3", we generate: + + >>> julia_code(x**2*y*A**3) + '(x .^ 2 .* y) * A ^ 3' + + Matrices are supported using Julia inline notation. When using + ``assign_to`` with matrices, the name can be specified either as a string + or as a ``MatrixSymbol``. The dimensions must align in the latter case. + + >>> from sympy import Matrix, MatrixSymbol + >>> mat = Matrix([[x**2, sin(x), ceiling(x)]]) + >>> julia_code(mat, assign_to='A') + 'A = [x .^ 2 sin(x) ceil(x)]' + + ``Piecewise`` expressions are implemented with logical masking by default. + Alternatively, you can pass "inline=False" to use if-else conditionals. + Note that if the ``Piecewise`` lacks a default term, represented by + ``(expr, True)`` then an error will be thrown. This is to prevent + generating an expression that may not evaluate to anything. + + >>> from sympy import Piecewise + >>> pw = Piecewise((x + 1, x > 0), (x, True)) + >>> julia_code(pw, assign_to=tau) + 'tau = ((x > 0) ? (x + 1) : (x))' + + Note that any expression that can be generated normally can also exist + inside a Matrix: + + >>> mat = Matrix([[x**2, pw, sin(x)]]) + >>> julia_code(mat, assign_to='A') + 'A = [x .^ 2 ((x > 0) ? (x + 1) : (x)) sin(x)]' + + Custom printing can be defined for certain types by passing a dictionary of + "type" : "function" to the ``user_functions`` kwarg. Alternatively, the + dictionary value can be a list of tuples i.e., [(argument_test, + cfunction_string)]. This can be used to call a custom Julia function. + + >>> from sympy import Function + >>> f = Function('f') + >>> g = Function('g') + >>> custom_functions = { + ... "f": "existing_julia_fcn", + ... "g": [(lambda x: x.is_Matrix, "my_mat_fcn"), + ... (lambda x: not x.is_Matrix, "my_fcn")] + ... } + >>> mat = Matrix([[1, x]]) + >>> julia_code(f(x) + g(x) + g(mat), user_functions=custom_functions) + 'existing_julia_fcn(x) + my_fcn(x) + my_mat_fcn([1 x])' + + Support for loops is provided through ``Indexed`` types. With + ``contract=True`` these expressions will be turned into loops, whereas + ``contract=False`` will just print the assignment expression that should be + looped over: + + >>> from sympy import Eq, IndexedBase, Idx + >>> len_y = 5 + >>> y = IndexedBase('y', shape=(len_y,)) + >>> t = IndexedBase('t', shape=(len_y,)) + >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) + >>> i = Idx('i', len_y-1) + >>> e = Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) + >>> julia_code(e.rhs, assign_to=e.lhs, contract=False) + 'Dy[i] = (y[i + 1] - y[i]) ./ (t[i + 1] - t[i])' + """ + return JuliaCodePrinter(settings).doprint(expr, assign_to) + + +def print_julia_code(expr, **settings): + """Prints the Julia representation of the given expression. + + See `julia_code` for the meaning of the optional arguments. + """ + print(julia_code(expr, **settings)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/lambdarepr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/lambdarepr.py new file mode 100644 index 0000000000000000000000000000000000000000..87fa0988d138d54d68ab8aef1bbc0f27b243b472 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/lambdarepr.py @@ -0,0 +1,251 @@ +from .pycode import ( + PythonCodePrinter, + MpmathPrinter, +) +from .numpy import NumPyPrinter # NumPyPrinter is imported for backward compatibility +from sympy.core.sorting import default_sort_key + + +__all__ = [ + 'PythonCodePrinter', + 'MpmathPrinter', # MpmathPrinter is published for backward compatibility + 'NumPyPrinter', + 'LambdaPrinter', + 'NumPyPrinter', + 'IntervalPrinter', + 'lambdarepr', +] + + +class LambdaPrinter(PythonCodePrinter): + """ + This printer converts expressions into strings that can be used by + lambdify. + """ + printmethod = "_lambdacode" + + + def _print_And(self, expr): + result = ['('] + for arg in sorted(expr.args, key=default_sort_key): + result.extend(['(', self._print(arg), ')']) + result.append(' and ') + result = result[:-1] + result.append(')') + return ''.join(result) + + def _print_Or(self, expr): + result = ['('] + for arg in sorted(expr.args, key=default_sort_key): + result.extend(['(', self._print(arg), ')']) + result.append(' or ') + result = result[:-1] + result.append(')') + return ''.join(result) + + def _print_Not(self, expr): + result = ['(', 'not (', self._print(expr.args[0]), '))'] + return ''.join(result) + + def _print_BooleanTrue(self, expr): + return "True" + + def _print_BooleanFalse(self, expr): + return "False" + + def _print_ITE(self, expr): + result = [ + '((', self._print(expr.args[1]), + ') if (', self._print(expr.args[0]), + ') else (', self._print(expr.args[2]), '))' + ] + return ''.join(result) + + def _print_NumberSymbol(self, expr): + return str(expr) + + def _print_Pow(self, expr, **kwargs): + # XXX Temporary workaround. Should Python math printer be + # isolated from PythonCodePrinter? + return super(PythonCodePrinter, self)._print_Pow(expr, **kwargs) + + +# numexpr works by altering the string passed to numexpr.evaluate +# rather than by populating a namespace. Thus a special printer... +class NumExprPrinter(LambdaPrinter): + # key, value pairs correspond to SymPy name and numexpr name + # functions not appearing in this dict will raise a TypeError + printmethod = "_numexprcode" + + _numexpr_functions = { + 'sin' : 'sin', + 'cos' : 'cos', + 'tan' : 'tan', + 'asin': 'arcsin', + 'acos': 'arccos', + 'atan': 'arctan', + 'atan2' : 'arctan2', + 'sinh' : 'sinh', + 'cosh' : 'cosh', + 'tanh' : 'tanh', + 'asinh': 'arcsinh', + 'acosh': 'arccosh', + 'atanh': 'arctanh', + 'ln' : 'log', + 'log': 'log', + 'exp': 'exp', + 'sqrt' : 'sqrt', + 'Abs' : 'abs', + 'conjugate' : 'conj', + 'im' : 'imag', + 're' : 'real', + 'where' : 'where', + 'complex' : 'complex', + 'contains' : 'contains', + } + + module = 'numexpr' + + def _print_ImaginaryUnit(self, expr): + return '1j' + + def _print_seq(self, seq, delimiter=', '): + # simplified _print_seq taken from pretty.py + s = [self._print(item) for item in seq] + if s: + return delimiter.join(s) + else: + return "" + + def _print_Function(self, e): + func_name = e.func.__name__ + + nstr = self._numexpr_functions.get(func_name, None) + if nstr is None: + # check for implemented_function + if hasattr(e, '_imp_'): + return "(%s)" % self._print(e._imp_(*e.args)) + else: + raise TypeError("numexpr does not support function '%s'" % + func_name) + return "%s(%s)" % (nstr, self._print_seq(e.args)) + + def _print_Piecewise(self, expr): + "Piecewise function printer" + exprs = [self._print(arg.expr) for arg in expr.args] + conds = [self._print(arg.cond) for arg in expr.args] + # If [default_value, True] is a (expr, cond) sequence in a Piecewise object + # it will behave the same as passing the 'default' kwarg to select() + # *as long as* it is the last element in expr.args. + # If this is not the case, it may be triggered prematurely. + ans = [] + parenthesis_count = 0 + is_last_cond_True = False + for cond, expr in zip(conds, exprs): + if cond == 'True': + ans.append(expr) + is_last_cond_True = True + break + else: + ans.append('where(%s, %s, ' % (cond, expr)) + parenthesis_count += 1 + if not is_last_cond_True: + # See https://github.com/pydata/numexpr/issues/298 + # + # simplest way to put a nan but raises + # 'RuntimeWarning: invalid value encountered in log' + # + # There are other ways to do this such as + # + # >>> import numexpr as ne + # >>> nan = float('nan') + # >>> ne.evaluate('where(x < 0, -1, nan)', {'x': [-1, 2, 3], 'nan':nan}) + # array([-1., nan, nan]) + # + # That needs to be handled in the lambdified function though rather + # than here in the printer. + ans.append('log(-1)') + return ''.join(ans) + ')' * parenthesis_count + + def _print_ITE(self, expr): + from sympy.functions.elementary.piecewise import Piecewise + return self._print(expr.rewrite(Piecewise)) + + def blacklisted(self, expr): + raise TypeError("numexpr cannot be used with %s" % + expr.__class__.__name__) + + # blacklist all Matrix printing + _print_SparseRepMatrix = \ + _print_MutableSparseMatrix = \ + _print_ImmutableSparseMatrix = \ + _print_Matrix = \ + _print_DenseMatrix = \ + _print_MutableDenseMatrix = \ + _print_ImmutableMatrix = \ + _print_ImmutableDenseMatrix = \ + blacklisted + # blacklist some Python expressions + _print_list = \ + _print_tuple = \ + _print_Tuple = \ + _print_dict = \ + _print_Dict = \ + blacklisted + + def _print_NumExprEvaluate(self, expr): + evaluate = self._module_format(self.module +".evaluate") + return "%s('%s', truediv=True)" % (evaluate, self._print(expr.expr)) + + def doprint(self, expr): + from sympy.codegen.ast import CodegenAST + from sympy.codegen.pynodes import NumExprEvaluate + if not isinstance(expr, CodegenAST): + expr = NumExprEvaluate(expr) + return super().doprint(expr) + + def _print_Return(self, expr): + from sympy.codegen.pynodes import NumExprEvaluate + r, = expr.args + if not isinstance(r, NumExprEvaluate): + expr = expr.func(NumExprEvaluate(r)) + return super()._print_Return(expr) + + def _print_Assignment(self, expr): + from sympy.codegen.pynodes import NumExprEvaluate + lhs, rhs, *args = expr.args + if not isinstance(rhs, NumExprEvaluate): + expr = expr.func(lhs, NumExprEvaluate(rhs), *args) + return super()._print_Assignment(expr) + + def _print_CodeBlock(self, expr): + from sympy.codegen.ast import CodegenAST + from sympy.codegen.pynodes import NumExprEvaluate + args = [ arg if isinstance(arg, CodegenAST) else NumExprEvaluate(arg) for arg in expr.args ] + return super()._print_CodeBlock(self, expr.func(*args)) + + +class IntervalPrinter(MpmathPrinter, LambdaPrinter): + """Use ``lambda`` printer but print numbers as ``mpi`` intervals. """ + + def _print_Integer(self, expr): + return "mpi('%s')" % super(PythonCodePrinter, self)._print_Integer(expr) + + def _print_Rational(self, expr): + return "mpi('%s')" % super(PythonCodePrinter, self)._print_Rational(expr) + + def _print_Half(self, expr): + return "mpi('%s')" % super(PythonCodePrinter, self)._print_Rational(expr) + + def _print_Pow(self, expr): + return super(MpmathPrinter, self)._print_Pow(expr, rational=True) + + +for k in NumExprPrinter._numexpr_functions: + setattr(NumExprPrinter, '_print_%s' % k, NumExprPrinter._print_Function) + +def lambdarepr(expr, **settings): + """ + Returns a string usable for lambdifying. + """ + return LambdaPrinter(settings).doprint(expr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/latex.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/latex.py new file mode 100644 index 0000000000000000000000000000000000000000..724df719d560e001deb175649a3769703bdf5ca5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/latex.py @@ -0,0 +1,3318 @@ +""" +A Printer which converts an expression into its LaTeX equivalent. +""" +from __future__ import annotations +from typing import Any, Callable, TYPE_CHECKING + +import itertools + +from sympy.core import Add, Float, Mod, Mul, Number, S, Symbol, Expr +from sympy.core.alphabets import greeks +from sympy.core.containers import Tuple +from sympy.core.function import Function, AppliedUndef, Derivative +from sympy.core.operations import AssocOp +from sympy.core.power import Pow +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import SympifyError +from sympy.logic.boolalg import true, BooleanTrue, BooleanFalse + + +# sympy.printing imports +from sympy.printing.precedence import precedence_traditional +from sympy.printing.printer import Printer, print_function +from sympy.printing.conventions import split_super_sub, requires_partial +from sympy.printing.precedence import precedence, PRECEDENCE + +from mpmath.libmp.libmpf import prec_to_dps, to_str as mlib_to_str + +from sympy.utilities.iterables import has_variety, sift + +import re + +if TYPE_CHECKING: + from sympy.tensor.array import NDimArray + from sympy.vector.basisdependent import BasisDependent + +# Hand-picked functions which can be used directly in both LaTeX and MathJax +# Complete list at +# https://docs.mathjax.org/en/latest/tex.html#supported-latex-commands +# This variable only contains those functions which SymPy uses. +accepted_latex_functions = ['arcsin', 'arccos', 'arctan', 'sin', 'cos', 'tan', + 'sinh', 'cosh', 'tanh', 'sqrt', 'ln', 'log', 'sec', + 'csc', 'cot', 'coth', 're', 'im', 'frac', 'root', + 'arg', + ] + +tex_greek_dictionary = { + 'Alpha': r'\mathrm{A}', + 'Beta': r'\mathrm{B}', + 'Gamma': r'\Gamma', + 'Delta': r'\Delta', + 'Epsilon': r'\mathrm{E}', + 'Zeta': r'\mathrm{Z}', + 'Eta': r'\mathrm{H}', + 'Theta': r'\Theta', + 'Iota': r'\mathrm{I}', + 'Kappa': r'\mathrm{K}', + 'Lambda': r'\Lambda', + 'Mu': r'\mathrm{M}', + 'Nu': r'\mathrm{N}', + 'Xi': r'\Xi', + 'omicron': 'o', + 'Omicron': r'\mathrm{O}', + 'Pi': r'\Pi', + 'Rho': r'\mathrm{P}', + 'Sigma': r'\Sigma', + 'Tau': r'\mathrm{T}', + 'Upsilon': r'\Upsilon', + 'Phi': r'\Phi', + 'Chi': r'\mathrm{X}', + 'Psi': r'\Psi', + 'Omega': r'\Omega', + 'lamda': r'\lambda', + 'Lamda': r'\Lambda', + 'khi': r'\chi', + 'Khi': r'\mathrm{X}', + 'varepsilon': r'\varepsilon', + 'varkappa': r'\varkappa', + 'varphi': r'\varphi', + 'varpi': r'\varpi', + 'varrho': r'\varrho', + 'varsigma': r'\varsigma', + 'vartheta': r'\vartheta', +} + +other_symbols = {'aleph', 'beth', 'daleth', 'gimel', 'ell', 'eth', 'hbar', + 'hslash', 'mho', 'wp'} + +# Variable name modifiers +modifier_dict: dict[str, Callable[[str], str]] = { + # Accents + 'mathring': lambda s: r'\mathring{'+s+r'}', + 'ddddot': lambda s: r'\ddddot{'+s+r'}', + 'dddot': lambda s: r'\dddot{'+s+r'}', + 'ddot': lambda s: r'\ddot{'+s+r'}', + 'dot': lambda s: r'\dot{'+s+r'}', + 'check': lambda s: r'\check{'+s+r'}', + 'breve': lambda s: r'\breve{'+s+r'}', + 'acute': lambda s: r'\acute{'+s+r'}', + 'grave': lambda s: r'\grave{'+s+r'}', + 'tilde': lambda s: r'\tilde{'+s+r'}', + 'hat': lambda s: r'\hat{'+s+r'}', + 'bar': lambda s: r'\bar{'+s+r'}', + 'vec': lambda s: r'\vec{'+s+r'}', + 'prime': lambda s: "{"+s+"}'", + 'prm': lambda s: "{"+s+"}'", + # Faces + 'bold': lambda s: r'\boldsymbol{'+s+r'}', + 'bm': lambda s: r'\boldsymbol{'+s+r'}', + 'cal': lambda s: r'\mathcal{'+s+r'}', + 'scr': lambda s: r'\mathscr{'+s+r'}', + 'frak': lambda s: r'\mathfrak{'+s+r'}', + # Brackets + 'norm': lambda s: r'\left\|{'+s+r'}\right\|', + 'avg': lambda s: r'\left\langle{'+s+r'}\right\rangle', + 'abs': lambda s: r'\left|{'+s+r'}\right|', + 'mag': lambda s: r'\left|{'+s+r'}\right|', +} + +greek_letters_set = frozenset(greeks) + +_between_two_numbers_p = ( + re.compile(r'[0-9][} ]*$'), # search + re.compile(r'(\d|\\frac{\d+}{\d+})'), # match +) + + +def latex_escape(s: str) -> str: + """ + Escape a string such that latex interprets it as plaintext. + + We cannot use verbatim easily with mathjax, so escaping is easier. + Rules from https://tex.stackexchange.com/a/34586/41112. + """ + s = s.replace('\\', r'\textbackslash') + for c in '&%$#_{}': + s = s.replace(c, '\\' + c) + s = s.replace('~', r'\textasciitilde') + s = s.replace('^', r'\textasciicircum') + return s + + +class LatexPrinter(Printer): + printmethod = "_latex" + + _default_settings: dict[str, Any] = { + "full_prec": False, + "fold_frac_powers": False, + "fold_func_brackets": False, + "fold_short_frac": None, + "inv_trig_style": "abbreviated", + "itex": False, + "ln_notation": False, + "long_frac_ratio": None, + "mat_delim": "[", + "mat_str": None, + "mode": "plain", + "mul_symbol": None, + "order": None, + "symbol_names": {}, + "root_notation": True, + "mat_symbol_style": "plain", + "imaginary_unit": "i", + "gothic_re_im": False, + "decimal_separator": "period", + "perm_cyclic": True, + "parenthesize_super": True, + "min": None, + "max": None, + "diff_operator": "d", + "adjoint_style": "dagger", + "disable_split_super_sub": False, + } + + def __init__(self, settings=None): + Printer.__init__(self, settings) + + if 'mode' in self._settings: + valid_modes = ['inline', 'plain', 'equation', + 'equation*'] + if self._settings['mode'] not in valid_modes: + raise ValueError("'mode' must be one of 'inline', 'plain', " + "'equation' or 'equation*'") + + if self._settings['fold_short_frac'] is None and \ + self._settings['mode'] == 'inline': + self._settings['fold_short_frac'] = True + + mul_symbol_table = { + None: r" ", + "ldot": r" \,.\, ", + "dot": r" \cdot ", + "times": r" \times " + } + try: + self._settings['mul_symbol_latex'] = \ + mul_symbol_table[self._settings['mul_symbol']] + except KeyError: + self._settings['mul_symbol_latex'] = \ + self._settings['mul_symbol'] + try: + self._settings['mul_symbol_latex_numbers'] = \ + mul_symbol_table[self._settings['mul_symbol'] or 'dot'] + except KeyError: + if (self._settings['mul_symbol'].strip() in + ['', ' ', '\\', '\\,', '\\:', '\\;', '\\quad']): + self._settings['mul_symbol_latex_numbers'] = \ + mul_symbol_table['dot'] + else: + self._settings['mul_symbol_latex_numbers'] = \ + self._settings['mul_symbol'] + + self._delim_dict = {'(': ')', '[': ']'} + + imaginary_unit_table = { + None: r"i", + "i": r"i", + "ri": r"\mathrm{i}", + "ti": r"\text{i}", + "j": r"j", + "rj": r"\mathrm{j}", + "tj": r"\text{j}", + } + imag_unit = self._settings['imaginary_unit'] + self._settings['imaginary_unit_latex'] = imaginary_unit_table.get(imag_unit, imag_unit) + + diff_operator_table = { + None: r"d", + "d": r"d", + "rd": r"\mathrm{d}", + "td": r"\text{d}", + } + diff_operator = self._settings['diff_operator'] + self._settings["diff_operator_latex"] = diff_operator_table.get(diff_operator, diff_operator) + + def _add_parens(self, s) -> str: + return r"\left({}\right)".format(s) + + # TODO: merge this with the above, which requires a lot of test changes + def _add_parens_lspace(self, s) -> str: + return r"\left( {}\right)".format(s) + + def parenthesize(self, item, level, is_neg=False, strict=False) -> str: + prec_val = precedence_traditional(item) + if is_neg and strict: + return self._add_parens(self._print(item)) + + if (prec_val < level) or ((not strict) and prec_val <= level): + return self._add_parens(self._print(item)) + else: + return self._print(item) + + def parenthesize_super(self, s): + """ + Protect superscripts in s + + If the parenthesize_super option is set, protect with parentheses, else + wrap in braces. + """ + if "^" in s: + if self._settings['parenthesize_super']: + return self._add_parens(s) + else: + return "{{{}}}".format(s) + return s + + def doprint(self, expr) -> str: + tex = Printer.doprint(self, expr) + + if self._settings['mode'] == 'plain': + return tex + elif self._settings['mode'] == 'inline': + return r"$%s$" % tex + elif self._settings['itex']: + return r"$$%s$$" % tex + else: + env_str = self._settings['mode'] + return r"\begin{%s}%s\end{%s}" % (env_str, tex, env_str) + + def _needs_brackets(self, expr) -> bool: + """ + Returns True if the expression needs to be wrapped in brackets when + printed, False otherwise. For example: a + b => True; a => False; + 10 => False; -10 => True. + """ + return not ((expr.is_Integer and expr.is_nonnegative) + or (expr.is_Atom and (expr is not S.NegativeOne + and expr.is_Rational is False))) + + def _needs_function_brackets(self, expr) -> bool: + """ + Returns True if the expression needs to be wrapped in brackets when + passed as an argument to a function, False otherwise. This is a more + liberal version of _needs_brackets, in that many expressions which need + to be wrapped in brackets when added/subtracted/raised to a power do + not need them when passed to a function. Such an example is a*b. + """ + if not self._needs_brackets(expr): + return False + else: + # Muls of the form a*b*c... can be folded + if expr.is_Mul and not self._mul_is_clean(expr): + return True + # Pows which don't need brackets can be folded + elif expr.is_Pow and not self._pow_is_clean(expr): + return True + # Add and Function always need brackets + elif expr.is_Add or expr.is_Function: + return True + else: + return False + + def _needs_mul_brackets(self, expr, first=False, last=False) -> bool: + """ + Returns True if the expression needs to be wrapped in brackets when + printed as part of a Mul, False otherwise. This is True for Add, + but also for some container objects that would not need brackets + when appearing last in a Mul, e.g. an Integral. ``last=True`` + specifies that this expr is the last to appear in a Mul. + ``first=True`` specifies that this expr is the first to appear in + a Mul. + """ + from sympy.concrete.products import Product + from sympy.concrete.summations import Sum + from sympy.integrals.integrals import Integral + + if expr.is_Mul: + if not first and expr.could_extract_minus_sign(): + return True + elif precedence_traditional(expr) < PRECEDENCE["Mul"]: + return True + elif expr.is_Relational: + return True + if expr.is_Piecewise: + return True + if any(expr.has(x) for x in (Mod,)): + return True + if (not last and + any(expr.has(x) for x in (Integral, Product, Sum))): + return True + + return False + + def _needs_add_brackets(self, expr) -> bool: + """ + Returns True if the expression needs to be wrapped in brackets when + printed as part of an Add, False otherwise. This is False for most + things. + """ + if expr.is_Relational: + return True + if any(expr.has(x) for x in (Mod,)): + return True + if expr.is_Add: + return True + return False + + def _mul_is_clean(self, expr) -> bool: + for arg in expr.args: + if arg.is_Function: + return False + return True + + def _pow_is_clean(self, expr) -> bool: + return not self._needs_brackets(expr.base) + + def _do_exponent(self, expr: str, exp): + if exp is not None: + return r"\left(%s\right)^{%s}" % (expr, exp) + else: + return expr + + def _print_Basic(self, expr): + name = self._deal_with_super_sub(expr.__class__.__name__) + if expr.args: + ls = [self._print(o) for o in expr.args] + s = r"\operatorname{{{}}}\left({}\right)" + return s.format(name, ", ".join(ls)) + else: + return r"\text{{{}}}".format(name) + + def _print_bool(self, e: bool | BooleanTrue | BooleanFalse): + return r"\text{%s}" % e + + _print_BooleanTrue = _print_bool + _print_BooleanFalse = _print_bool + + def _print_NoneType(self, e): + return r"\text{%s}" % e + + def _print_Add(self, expr, order=None): + terms = self._as_ordered_terms(expr, order=order) + + tex = "" + for i, term in enumerate(terms): + if i == 0: + pass + elif term.could_extract_minus_sign(): + tex += " - " + term = -term + else: + tex += " + " + term_tex = self._print(term) + if self._needs_add_brackets(term): + term_tex = r"\left(%s\right)" % term_tex + tex += term_tex + + return tex + + def _print_Cycle(self, expr): + from sympy.combinatorics.permutations import Permutation + if expr.size == 0: + return r"\left( \right)" + expr = Permutation(expr) + expr_perm = expr.cyclic_form + siz = expr.size + if expr.array_form[-1] == siz - 1: + expr_perm = expr_perm + [[siz - 1]] + term_tex = '' + for i in expr_perm: + term_tex += str(i).replace(',', r"\;") + term_tex = term_tex.replace('[', r"\left( ") + term_tex = term_tex.replace(']', r"\right)") + return term_tex + + def _print_Permutation(self, expr): + from sympy.combinatorics.permutations import Permutation + from sympy.utilities.exceptions import sympy_deprecation_warning + + perm_cyclic = Permutation.print_cyclic + if perm_cyclic is not None: + sympy_deprecation_warning( + f""" + Setting Permutation.print_cyclic is deprecated. Instead use + init_printing(perm_cyclic={perm_cyclic}). + """, + deprecated_since_version="1.6", + active_deprecations_target="deprecated-permutation-print_cyclic", + stacklevel=8, + ) + else: + perm_cyclic = self._settings.get("perm_cyclic", True) + + if perm_cyclic: + return self._print_Cycle(expr) + + if expr.size == 0: + return r"\left( \right)" + + lower = [self._print(arg) for arg in expr.array_form] + upper = [self._print(arg) for arg in range(len(lower))] + + row1 = " & ".join(upper) + row2 = " & ".join(lower) + mat = r" \\ ".join((row1, row2)) + return r"\begin{pmatrix} %s \end{pmatrix}" % mat + + + def _print_AppliedPermutation(self, expr): + perm, var = expr.args + return r"\sigma_{%s}(%s)" % (self._print(perm), self._print(var)) + + def _print_Float(self, expr): + # Based off of that in StrPrinter + dps = prec_to_dps(expr._prec) + strip = False if self._settings['full_prec'] else True + low = self._settings["min"] if "min" in self._settings else None + high = self._settings["max"] if "max" in self._settings else None + str_real = mlib_to_str(expr._mpf_, dps, strip_zeros=strip, min_fixed=low, max_fixed=high) + + # Must always have a mul symbol (as 2.5 10^{20} just looks odd) + # thus we use the number separator + separator = self._settings['mul_symbol_latex_numbers'] + + if 'e' in str_real: + (mant, exp) = str_real.split('e') + + if exp[0] == '+': + exp = exp[1:] + if self._settings['decimal_separator'] == 'comma': + mant = mant.replace('.','{,}') + + return r"%s%s10^{%s}" % (mant, separator, exp) + elif str_real == "+inf": + return r"\infty" + elif str_real == "-inf": + return r"- \infty" + else: + if self._settings['decimal_separator'] == 'comma': + str_real = str_real.replace('.','{,}') + return str_real + + def _print_Cross(self, expr): + vec1 = expr._expr1 + vec2 = expr._expr2 + return r"%s \times %s" % (self.parenthesize(vec1, PRECEDENCE['Mul']), + self.parenthesize(vec2, PRECEDENCE['Mul'])) + + def _print_Curl(self, expr): + vec = expr._expr + return r"\nabla\times %s" % self.parenthesize(vec, PRECEDENCE['Mul']) + + def _print_Divergence(self, expr): + vec = expr._expr + return r"\nabla\cdot %s" % self.parenthesize(vec, PRECEDENCE['Mul']) + + def _print_Dot(self, expr): + vec1 = expr._expr1 + vec2 = expr._expr2 + return r"%s \cdot %s" % (self.parenthesize(vec1, PRECEDENCE['Mul']), + self.parenthesize(vec2, PRECEDENCE['Mul'])) + + def _print_Gradient(self, expr): + func = expr._expr + return r"\nabla %s" % self.parenthesize(func, PRECEDENCE['Mul']) + + def _print_Laplacian(self, expr): + func = expr._expr + return r"\Delta %s" % self.parenthesize(func, PRECEDENCE['Mul']) + + def _print_Mul(self, expr: Expr): + from sympy.simplify import fraction + separator: str = self._settings['mul_symbol_latex'] + numbersep: str = self._settings['mul_symbol_latex_numbers'] + + def convert(expr) -> str: + if not expr.is_Mul: + return str(self._print(expr)) + else: + if self.order not in ('old', 'none'): + args = expr.as_ordered_factors() + else: + args = list(expr.args) + + # If there are quantities or prefixes, append them at the back. + units, nonunits = sift(args, lambda x: (hasattr(x, "_scale_factor") or hasattr(x, "is_physical_constant")) or + (isinstance(x, Pow) and + hasattr(x.base, "is_physical_constant")), binary=True) + prefixes, units = sift(units, lambda x: hasattr(x, "_scale_factor"), binary=True) + return convert_args(nonunits + prefixes + units) + + def convert_args(args) -> str: + _tex = last_term_tex = "" + + for i, term in enumerate(args): + term_tex = self._print(term) + if not (hasattr(term, "_scale_factor") or hasattr(term, "is_physical_constant")): + if self._needs_mul_brackets(term, first=(i == 0), + last=(i == len(args) - 1)): + term_tex = r"\left(%s\right)" % term_tex + + if _between_two_numbers_p[0].search(last_term_tex) and \ + _between_two_numbers_p[1].match(term_tex): + # between two numbers + _tex += numbersep + elif _tex: + _tex += separator + elif _tex: + _tex += separator + + _tex += term_tex + last_term_tex = term_tex + return _tex + + # Check for unevaluated Mul. In this case we need to make sure the + # identities are visible, multiple Rational factors are not combined + # etc so we display in a straight-forward form that fully preserves all + # args and their order. + # XXX: _print_Pow calls this routine with instances of Pow... + if isinstance(expr, Mul): + args = expr.args + if args[0] is S.One or any(isinstance(arg, Number) for arg in args[1:]): + return convert_args(args) + + include_parens = False + if expr.could_extract_minus_sign(): + expr = -expr + tex = "- " + if expr.is_Add: + tex += "(" + include_parens = True + else: + tex = "" + + numer, denom = fraction(expr, exact=True) + + if denom is S.One and Pow(1, -1, evaluate=False) not in expr.args: + # use the original expression here, since fraction() may have + # altered it when producing numer and denom + tex += convert(expr) + + else: + snumer = convert(numer) + sdenom = convert(denom) + ldenom = len(sdenom.split()) + ratio = self._settings['long_frac_ratio'] + if self._settings['fold_short_frac'] and ldenom <= 2 and \ + "^" not in sdenom: + # handle short fractions + if self._needs_mul_brackets(numer, last=False): + tex += r"\left(%s\right) / %s" % (snumer, sdenom) + else: + tex += r"%s / %s" % (snumer, sdenom) + elif ratio is not None and \ + len(snumer.split()) > ratio*ldenom: + # handle long fractions + if self._needs_mul_brackets(numer, last=True): + tex += r"\frac{1}{%s}%s\left(%s\right)" \ + % (sdenom, separator, snumer) + elif numer.is_Mul: + # split a long numerator + a = S.One + b = S.One + for x in numer.args: + if self._needs_mul_brackets(x, last=False) or \ + len(convert(a*x).split()) > ratio*ldenom or \ + (b.is_commutative is x.is_commutative is False): + b *= x + else: + a *= x + if self._needs_mul_brackets(b, last=True): + tex += r"\frac{%s}{%s}%s\left(%s\right)" \ + % (convert(a), sdenom, separator, convert(b)) + else: + tex += r"\frac{%s}{%s}%s%s" \ + % (convert(a), sdenom, separator, convert(b)) + else: + tex += r"\frac{1}{%s}%s%s" % (sdenom, separator, snumer) + else: + tex += r"\frac{%s}{%s}" % (snumer, sdenom) + + if include_parens: + tex += ")" + return tex + + def _print_AlgebraicNumber(self, expr): + if expr.is_aliased: + return self._print(expr.as_poly().as_expr()) + else: + return self._print(expr.as_expr()) + + def _print_PrimeIdeal(self, expr): + p = self._print(expr.p) + if expr.is_inert: + return rf'\left({p}\right)' + alpha = self._print(expr.alpha.as_expr()) + return rf'\left({p}, {alpha}\right)' + + def _print_Pow(self, expr: Pow): + # Treat x**Rational(1,n) as special case + if expr.exp.is_Rational: + p: int = expr.exp.p # type: ignore + q: int = expr.exp.q # type: ignore + if abs(p) == 1 and q != 1 and self._settings['root_notation']: + base = self._print(expr.base) + if q == 2: + tex = r"\sqrt{%s}" % base + elif self._settings['itex']: + tex = r"\root{%d}{%s}" % (q, base) + else: + tex = r"\sqrt[%d]{%s}" % (q, base) + if expr.exp.is_negative: + return r"\frac{1}{%s}" % tex + else: + return tex + elif self._settings['fold_frac_powers'] and q != 1: + base = self.parenthesize(expr.base, PRECEDENCE['Pow']) + # issue #12886: add parentheses for superscripts raised to powers + if expr.base.is_Symbol: + base = self.parenthesize_super(base) + if expr.base.is_Function: + return self._print(expr.base, exp="%s/%s" % (p, q)) + return r"%s^{%s/%s}" % (base, p, q) + elif expr.exp.is_negative and expr.base.is_commutative: + # special case for 1^(-x), issue 9216 + if expr.base == 1: + return r"%s^{%s}" % (expr.base, expr.exp) + # special case for (1/x)^(-y) and (-1/-x)^(-y), issue 20252 + if expr.base.is_Rational: + base_p: int = expr.base.p # type: ignore + base_q: int = expr.base.q # type: ignore + if base_p * base_q == abs(base_q): + if expr.exp == -1: + return r"\frac{1}{\frac{%s}{%s}}" % (base_p, base_q) + else: + return r"\frac{1}{(\frac{%s}{%s})^{%s}}" % (base_p, base_q, abs(expr.exp)) + # things like 1/x + return self._print_Mul(expr) + if expr.base.is_Function: + return self._print(expr.base, exp=self._print(expr.exp)) + tex = r"%s^{%s}" + return self._helper_print_standard_power(expr, tex) + + def _helper_print_standard_power(self, expr, template: str) -> str: + exp = self._print(expr.exp) + # issue #12886: add parentheses around superscripts raised + # to powers + base = self.parenthesize(expr.base, PRECEDENCE['Pow']) + if expr.base.is_Symbol: + base = self.parenthesize_super(base) + elif expr.base.is_Float: + base = r"{%s}" % base + elif (isinstance(expr.base, Derivative) + and base.startswith(r'\left(') + and re.match(r'\\left\(\\d?d?dot', base) + and base.endswith(r'\right)')): + # don't use parentheses around dotted derivative + base = base[6: -7] # remove outermost added parens + return template % (base, exp) + + def _print_UnevaluatedExpr(self, expr): + return self._print(expr.args[0]) + + def _print_Sum(self, expr): + if len(expr.limits) == 1: + tex = r"\sum_{%s=%s}^{%s} " % \ + tuple([self._print(i) for i in expr.limits[0]]) + else: + def _format_ineq(l): + return r"%s \leq %s \leq %s" % \ + tuple([self._print(s) for s in (l[1], l[0], l[2])]) + + tex = r"\sum_{\substack{%s}} " % \ + str.join('\\\\', [_format_ineq(l) for l in expr.limits]) + + if isinstance(expr.function, Add): + tex += r"\left(%s\right)" % self._print(expr.function) + else: + tex += self._print(expr.function) + + return tex + + def _print_Product(self, expr): + if len(expr.limits) == 1: + tex = r"\prod_{%s=%s}^{%s} " % \ + tuple([self._print(i) for i in expr.limits[0]]) + else: + def _format_ineq(l): + return r"%s \leq %s \leq %s" % \ + tuple([self._print(s) for s in (l[1], l[0], l[2])]) + + tex = r"\prod_{\substack{%s}} " % \ + str.join('\\\\', [_format_ineq(l) for l in expr.limits]) + + if isinstance(expr.function, Add): + tex += r"\left(%s\right)" % self._print(expr.function) + else: + tex += self._print(expr.function) + + return tex + + def _print_BasisDependent(self, expr: 'BasisDependent'): + from sympy.vector import Vector + + o1: list[str] = [] + if expr == expr.zero: + return expr.zero._latex_form + if isinstance(expr, Vector): + items = expr.separate().items() + else: + items = [(0, expr)] + + for system, vect in items: + inneritems = list(vect.components.items()) + inneritems.sort(key=lambda x: x[0].__str__()) + for k, v in inneritems: + if v == 1: + o1.append(' + ' + k._latex_form) + elif v == -1: + o1.append(' - ' + k._latex_form) + else: + arg_str = r'\left(' + self._print(v) + r'\right)' + o1.append(' + ' + arg_str + k._latex_form) + + outstr = (''.join(o1)) + if outstr[1] != '-': + outstr = outstr[3:] + else: + outstr = outstr[1:] + return outstr + + def _print_Indexed(self, expr): + tex_base = self._print(expr.base) + tex = '{'+tex_base+'}'+'_{%s}' % ','.join( + map(self._print, expr.indices)) + return tex + + def _print_IndexedBase(self, expr): + return self._print(expr.label) + + def _print_Idx(self, expr): + label = self._print(expr.label) + if expr.upper is not None: + upper = self._print(expr.upper) + if expr.lower is not None: + lower = self._print(expr.lower) + else: + lower = self._print(S.Zero) + interval = '{lower}\\mathrel{{..}}\\nobreak {upper}'.format( + lower = lower, upper = upper) + return '{{{label}}}_{{{interval}}}'.format( + label = label, interval = interval) + #if no bounds are defined this just prints the label + return label + + def _print_Derivative(self, expr): + if requires_partial(expr.expr): + diff_symbol = r'\partial' + else: + diff_symbol = self._settings["diff_operator_latex"] + + tex = "" + dim = 0 + for x, num in reversed(expr.variable_count): + dim += num + if num == 1: + tex += r"%s %s" % (diff_symbol, self._print(x)) + else: + tex += r"%s %s^{%s}" % (diff_symbol, + self.parenthesize_super(self._print(x)), + self._print(num)) + + if dim == 1: + tex = r"\frac{%s}{%s}" % (diff_symbol, tex) + else: + tex = r"\frac{%s^{%s}}{%s}" % (diff_symbol, self._print(dim), tex) + + if any(i.could_extract_minus_sign() for i in expr.args): + return r"%s %s" % (tex, self.parenthesize(expr.expr, + PRECEDENCE["Mul"], + is_neg=True, + strict=True)) + + return r"%s %s" % (tex, self.parenthesize(expr.expr, + PRECEDENCE["Mul"], + is_neg=False, + strict=True)) + + def _print_Subs(self, subs): + expr, old, new = subs.args + latex_expr = self._print(expr) + latex_old = (self._print(e) for e in old) + latex_new = (self._print(e) for e in new) + latex_subs = r'\\ '.join( + e[0] + '=' + e[1] for e in zip(latex_old, latex_new)) + return r'\left. %s \right|_{\substack{ %s }}' % (latex_expr, + latex_subs) + + def _print_Integral(self, expr): + tex, symbols = "", [] + diff_symbol = self._settings["diff_operator_latex"] + + # Only up to \iiiint exists + if len(expr.limits) <= 4 and all(len(lim) == 1 for lim in expr.limits): + # Use len(expr.limits)-1 so that syntax highlighters don't think + # \" is an escaped quote + tex = r"\i" + "i"*(len(expr.limits) - 1) + "nt" + symbols = [r"\, %s%s" % (diff_symbol, self._print(symbol[0])) + for symbol in expr.limits] + + else: + for lim in reversed(expr.limits): + symbol = lim[0] + tex += r"\int" + + if len(lim) > 1: + if self._settings['mode'] != 'inline' \ + and not self._settings['itex']: + tex += r"\limits" + + if len(lim) == 3: + tex += "_{%s}^{%s}" % (self._print(lim[1]), + self._print(lim[2])) + if len(lim) == 2: + tex += "^{%s}" % (self._print(lim[1])) + + symbols.insert(0, r"\, %s%s" % (diff_symbol, self._print(symbol))) + + return r"%s %s%s" % (tex, self.parenthesize(expr.function, + PRECEDENCE["Mul"], + is_neg=any(i.could_extract_minus_sign() for i in expr.args), + strict=True), + "".join(symbols)) + + def _print_Limit(self, expr): + e, z, z0, dir = expr.args + + tex = r"\lim_{%s \to " % self._print(z) + if str(dir) == '+-' or z0 in (S.Infinity, S.NegativeInfinity): + tex += r"%s}" % self._print(z0) + else: + tex += r"%s^%s}" % (self._print(z0), self._print(dir)) + + if isinstance(e, AssocOp): + return r"%s\left(%s\right)" % (tex, self._print(e)) + else: + return r"%s %s" % (tex, self._print(e)) + + def _hprint_Function(self, func: str) -> str: + r''' + Logic to decide how to render a function to latex + - if it is a recognized latex name, use the appropriate latex command + - if it is a single letter, excluding sub- and superscripts, just use that letter + - if it is a longer name, then put \operatorname{} around it and be + mindful of undercores in the name + ''' + func = self._deal_with_super_sub(func) + superscriptidx = func.find("^") + subscriptidx = func.find("_") + if func in accepted_latex_functions: + name = r"\%s" % func + elif len(func) == 1 or func.startswith('\\') or subscriptidx == 1 or superscriptidx == 1: + name = func + else: + if superscriptidx > 0 and subscriptidx > 0: + name = r"\operatorname{%s}%s" %( + func[:min(subscriptidx,superscriptidx)], + func[min(subscriptidx,superscriptidx):]) + elif superscriptidx > 0: + name = r"\operatorname{%s}%s" %( + func[:superscriptidx], + func[superscriptidx:]) + elif subscriptidx > 0: + name = r"\operatorname{%s}%s" %( + func[:subscriptidx], + func[subscriptidx:]) + else: + name = r"\operatorname{%s}" % func + return name + + def _print_Function(self, expr: Function, exp=None) -> str: + r''' + Render functions to LaTeX, handling functions that LaTeX knows about + e.g., sin, cos, ... by using the proper LaTeX command (\sin, \cos, ...). + For single-letter function names, render them as regular LaTeX math + symbols. For multi-letter function names that LaTeX does not know + about, (e.g., Li, sech) use \operatorname{} so that the function name + is rendered in Roman font and LaTeX handles spacing properly. + + expr is the expression involving the function + exp is an exponent + ''' + func = expr.func.__name__ + if hasattr(self, '_print_' + func) and \ + not isinstance(expr, AppliedUndef): + return getattr(self, '_print_' + func)(expr, exp) + else: + args = [str(self._print(arg)) for arg in expr.args] + # How inverse trig functions should be displayed, formats are: + # abbreviated: asin, full: arcsin, power: sin^-1 + inv_trig_style = self._settings['inv_trig_style'] + # If we are dealing with a power-style inverse trig function + inv_trig_power_case = False + # If it is applicable to fold the argument brackets + can_fold_brackets = self._settings['fold_func_brackets'] and \ + len(args) == 1 and \ + not self._needs_function_brackets(expr.args[0]) + + inv_trig_table = [ + "asin", "acos", "atan", + "acsc", "asec", "acot", + "asinh", "acosh", "atanh", + "acsch", "asech", "acoth", + ] + + # If the function is an inverse trig function, handle the style + if func in inv_trig_table: + if inv_trig_style == "abbreviated": + pass + elif inv_trig_style == "full": + func = ("ar" if func[-1] == "h" else "arc") + func[1:] + elif inv_trig_style == "power": + func = func[1:] + inv_trig_power_case = True + + # Can never fold brackets if we're raised to a power + if exp is not None: + can_fold_brackets = False + + if inv_trig_power_case: + if func in accepted_latex_functions: + name = r"\%s^{-1}" % func + else: + name = r"\operatorname{%s}^{-1}" % func + elif exp is not None: + func_tex = self._hprint_Function(func) + func_tex = self.parenthesize_super(func_tex) + name = r'%s^{%s}' % (func_tex, exp) + else: + name = self._hprint_Function(func) + + if can_fold_brackets: + if func in accepted_latex_functions: + # Wrap argument safely to avoid parse-time conflicts + # with the function name itself + name += r" {%s}" + else: + name += r"%s" + else: + name += r"{\left(%s \right)}" + + if inv_trig_power_case and exp is not None: + name += r"^{%s}" % exp + + return name % ",".join(args) + + def _print_UndefinedFunction(self, expr): + return self._hprint_Function(str(expr)) + + def _print_ElementwiseApplyFunction(self, expr): + return r"{%s}_{\circ}\left({%s}\right)" % ( + self._print(expr.function), + self._print(expr.expr), + ) + + @property + def _special_function_classes(self): + from sympy.functions.special.tensor_functions import KroneckerDelta + from sympy.functions.special.gamma_functions import gamma, lowergamma + from sympy.functions.special.beta_functions import beta + from sympy.functions.special.delta_functions import DiracDelta + from sympy.functions.special.error_functions import Chi + return {KroneckerDelta: r'\delta', + gamma: r'\Gamma', + lowergamma: r'\gamma', + beta: r'\operatorname{B}', + DiracDelta: r'\delta', + Chi: r'\operatorname{Chi}'} + + def _print_FunctionClass(self, expr): + for cls in self._special_function_classes: + if issubclass(expr, cls) and expr.__name__ == cls.__name__: + return self._special_function_classes[cls] + return self._hprint_Function(str(expr)) + + def _print_Lambda(self, expr): + symbols, expr = expr.args + + if len(symbols) == 1: + symbols = self._print(symbols[0]) + else: + symbols = self._print(tuple(symbols)) + + tex = r"\left( %s \mapsto %s \right)" % (symbols, self._print(expr)) + + return tex + + def _print_IdentityFunction(self, expr): + return r"\left( x \mapsto x \right)" + + def _hprint_variadic_function(self, expr, exp=None) -> str: + args = sorted(expr.args, key=default_sort_key) + texargs = [r"%s" % self._print(symbol) for symbol in args] + tex = r"\%s\left(%s\right)" % (str(expr.func).lower(), + ", ".join(texargs)) + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + _print_Min = _print_Max = _hprint_variadic_function + + def _print_floor(self, expr, exp=None): + tex = r"\left\lfloor{%s}\right\rfloor" % self._print(expr.args[0]) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + def _print_ceiling(self, expr, exp=None): + tex = r"\left\lceil{%s}\right\rceil" % self._print(expr.args[0]) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + def _print_log(self, expr, exp=None): + if not self._settings["ln_notation"]: + tex = r"\log{\left(%s \right)}" % self._print(expr.args[0]) + else: + tex = r"\ln{\left(%s \right)}" % self._print(expr.args[0]) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + def _print_Abs(self, expr, exp=None): + tex = r"\left|{%s}\right|" % self._print(expr.args[0]) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + def _print_re(self, expr, exp=None): + if self._settings['gothic_re_im']: + tex = r"\Re{%s}" % self.parenthesize(expr.args[0], PRECEDENCE['Atom']) + else: + tex = r"\operatorname{{re}}{{{}}}".format(self.parenthesize(expr.args[0], PRECEDENCE['Atom'])) + + return self._do_exponent(tex, exp) + + def _print_im(self, expr, exp=None): + if self._settings['gothic_re_im']: + tex = r"\Im{%s}" % self.parenthesize(expr.args[0], PRECEDENCE['Atom']) + else: + tex = r"\operatorname{{im}}{{{}}}".format(self.parenthesize(expr.args[0], PRECEDENCE['Atom'])) + + return self._do_exponent(tex, exp) + + def _print_Not(self, e): + from sympy.logic.boolalg import (Equivalent, Implies) + if isinstance(e.args[0], Equivalent): + return self._print_Equivalent(e.args[0], r"\not\Leftrightarrow") + if isinstance(e.args[0], Implies): + return self._print_Implies(e.args[0], r"\not\Rightarrow") + if (e.args[0].is_Boolean): + return r"\neg \left(%s\right)" % self._print(e.args[0]) + else: + return r"\neg %s" % self._print(e.args[0]) + + def _print_LogOp(self, args, char): + arg = args[0] + if arg.is_Boolean and not arg.is_Not: + tex = r"\left(%s\right)" % self._print(arg) + else: + tex = r"%s" % self._print(arg) + + for arg in args[1:]: + if arg.is_Boolean and not arg.is_Not: + tex += r" %s \left(%s\right)" % (char, self._print(arg)) + else: + tex += r" %s %s" % (char, self._print(arg)) + + return tex + + def _print_And(self, e): + args = sorted(e.args, key=default_sort_key) + return self._print_LogOp(args, r"\wedge") + + def _print_Or(self, e): + args = sorted(e.args, key=default_sort_key) + return self._print_LogOp(args, r"\vee") + + def _print_Xor(self, e): + args = sorted(e.args, key=default_sort_key) + return self._print_LogOp(args, r"\veebar") + + def _print_Implies(self, e, altchar=None): + return self._print_LogOp(e.args, altchar or r"\Rightarrow") + + def _print_Equivalent(self, e, altchar=None): + args = sorted(e.args, key=default_sort_key) + return self._print_LogOp(args, altchar or r"\Leftrightarrow") + + def _print_conjugate(self, expr, exp=None): + tex = r"\overline{%s}" % self._print(expr.args[0]) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + def _print_polar_lift(self, expr, exp=None): + func = r"\operatorname{polar\_lift}" + arg = r"{\left(%s \right)}" % self._print(expr.args[0]) + + if exp is not None: + return r"%s^{%s}%s" % (func, exp, arg) + else: + return r"%s%s" % (func, arg) + + def _print_ExpBase(self, expr, exp=None): + # TODO should exp_polar be printed differently? + # what about exp_polar(0), exp_polar(1)? + tex = r"e^{%s}" % self._print(expr.args[0]) + return self._do_exponent(tex, exp) + + def _print_Exp1(self, expr, exp=None): + return "e" + + def _print_elliptic_k(self, expr, exp=None): + tex = r"\left(%s\right)" % self._print(expr.args[0]) + if exp is not None: + return r"K^{%s}%s" % (exp, tex) + else: + return r"K%s" % tex + + def _print_elliptic_f(self, expr, exp=None): + tex = r"\left(%s\middle| %s\right)" % \ + (self._print(expr.args[0]), self._print(expr.args[1])) + if exp is not None: + return r"F^{%s}%s" % (exp, tex) + else: + return r"F%s" % tex + + def _print_elliptic_e(self, expr, exp=None): + if len(expr.args) == 2: + tex = r"\left(%s\middle| %s\right)" % \ + (self._print(expr.args[0]), self._print(expr.args[1])) + else: + tex = r"\left(%s\right)" % self._print(expr.args[0]) + if exp is not None: + return r"E^{%s}%s" % (exp, tex) + else: + return r"E%s" % tex + + def _print_elliptic_pi(self, expr, exp=None): + if len(expr.args) == 3: + tex = r"\left(%s; %s\middle| %s\right)" % \ + (self._print(expr.args[0]), self._print(expr.args[1]), + self._print(expr.args[2])) + else: + tex = r"\left(%s\middle| %s\right)" % \ + (self._print(expr.args[0]), self._print(expr.args[1])) + if exp is not None: + return r"\Pi^{%s}%s" % (exp, tex) + else: + return r"\Pi%s" % tex + + def _print_beta(self, expr, exp=None): + x = expr.args[0] + # Deal with unevaluated single argument beta + y = expr.args[0] if len(expr.args) == 1 else expr.args[1] + tex = rf"\left({x}, {y}\right)" + + if exp is not None: + return r"\operatorname{B}^{%s}%s" % (exp, tex) + else: + return r"\operatorname{B}%s" % tex + + def _print_betainc(self, expr, exp=None, operator='B'): + largs = [self._print(arg) for arg in expr.args] + tex = r"\left(%s, %s\right)" % (largs[0], largs[1]) + + if exp is not None: + return r"\operatorname{%s}_{(%s, %s)}^{%s}%s" % (operator, largs[2], largs[3], exp, tex) + else: + return r"\operatorname{%s}_{(%s, %s)}%s" % (operator, largs[2], largs[3], tex) + + def _print_betainc_regularized(self, expr, exp=None): + return self._print_betainc(expr, exp, operator='I') + + def _print_uppergamma(self, expr, exp=None): + tex = r"\left(%s, %s\right)" % (self._print(expr.args[0]), + self._print(expr.args[1])) + + if exp is not None: + return r"\Gamma^{%s}%s" % (exp, tex) + else: + return r"\Gamma%s" % tex + + def _print_lowergamma(self, expr, exp=None): + tex = r"\left(%s, %s\right)" % (self._print(expr.args[0]), + self._print(expr.args[1])) + + if exp is not None: + return r"\gamma^{%s}%s" % (exp, tex) + else: + return r"\gamma%s" % tex + + def _hprint_one_arg_func(self, expr, exp=None) -> str: + tex = r"\left(%s\right)" % self._print(expr.args[0]) + + if exp is not None: + return r"%s^{%s}%s" % (self._print(expr.func), exp, tex) + else: + return r"%s%s" % (self._print(expr.func), tex) + + _print_gamma = _hprint_one_arg_func + + def _print_Chi(self, expr, exp=None): + tex = r"\left(%s\right)" % self._print(expr.args[0]) + + if exp is not None: + return r"\operatorname{Chi}^{%s}%s" % (exp, tex) + else: + return r"\operatorname{Chi}%s" % tex + + def _print_expint(self, expr, exp=None): + tex = r"\left(%s\right)" % self._print(expr.args[1]) + nu = self._print(expr.args[0]) + + if exp is not None: + return r"\operatorname{E}_{%s}^{%s}%s" % (nu, exp, tex) + else: + return r"\operatorname{E}_{%s}%s" % (nu, tex) + + def _print_fresnels(self, expr, exp=None): + tex = r"\left(%s\right)" % self._print(expr.args[0]) + + if exp is not None: + return r"S^{%s}%s" % (exp, tex) + else: + return r"S%s" % tex + + def _print_fresnelc(self, expr, exp=None): + tex = r"\left(%s\right)" % self._print(expr.args[0]) + + if exp is not None: + return r"C^{%s}%s" % (exp, tex) + else: + return r"C%s" % tex + + def _print_subfactorial(self, expr, exp=None): + tex = r"!%s" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) + + if exp is not None: + return r"\left(%s\right)^{%s}" % (tex, exp) + else: + return tex + + def _print_factorial(self, expr, exp=None): + tex = r"%s!" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + def _print_factorial2(self, expr, exp=None): + tex = r"%s!!" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + def _print_binomial(self, expr, exp=None): + tex = r"{\binom{%s}{%s}}" % (self._print(expr.args[0]), + self._print(expr.args[1])) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + + def _print_RisingFactorial(self, expr, exp=None): + n, k = expr.args + base = r"%s" % self.parenthesize(n, PRECEDENCE['Func']) + + tex = r"{%s}^{\left(%s\right)}" % (base, self._print(k)) + + return self._do_exponent(tex, exp) + + def _print_FallingFactorial(self, expr, exp=None): + n, k = expr.args + sub = r"%s" % self.parenthesize(k, PRECEDENCE['Func']) + + tex = r"{\left(%s\right)}_{%s}" % (self._print(n), sub) + + return self._do_exponent(tex, exp) + + def _hprint_BesselBase(self, expr, exp, sym: str) -> str: + tex = r"%s" % (sym) + + need_exp = False + if exp is not None: + if tex.find('^') == -1: + tex = r"%s^{%s}" % (tex, exp) + else: + need_exp = True + + tex = r"%s_{%s}\left(%s\right)" % (tex, self._print(expr.order), + self._print(expr.argument)) + + if need_exp: + tex = self._do_exponent(tex, exp) + return tex + + def _hprint_vec(self, vec) -> str: + if not vec: + return "" + s = "" + for i in vec[:-1]: + s += "%s, " % self._print(i) + s += self._print(vec[-1]) + return s + + def _print_besselj(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'J') + + def _print_besseli(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'I') + + def _print_besselk(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'K') + + def _print_bessely(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'Y') + + def _print_yn(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'y') + + def _print_jn(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'j') + + def _print_hankel1(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'H^{(1)}') + + def _print_hankel2(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'H^{(2)}') + + def _print_hn1(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'h^{(1)}') + + def _print_hn2(self, expr, exp=None): + return self._hprint_BesselBase(expr, exp, 'h^{(2)}') + + def _hprint_airy(self, expr, exp=None, notation="") -> str: + tex = r"\left(%s\right)" % self._print(expr.args[0]) + + if exp is not None: + return r"%s^{%s}%s" % (notation, exp, tex) + else: + return r"%s%s" % (notation, tex) + + def _hprint_airy_prime(self, expr, exp=None, notation="") -> str: + tex = r"\left(%s\right)" % self._print(expr.args[0]) + + if exp is not None: + return r"{%s^\prime}^{%s}%s" % (notation, exp, tex) + else: + return r"%s^\prime%s" % (notation, tex) + + def _print_airyai(self, expr, exp=None): + return self._hprint_airy(expr, exp, 'Ai') + + def _print_airybi(self, expr, exp=None): + return self._hprint_airy(expr, exp, 'Bi') + + def _print_airyaiprime(self, expr, exp=None): + return self._hprint_airy_prime(expr, exp, 'Ai') + + def _print_airybiprime(self, expr, exp=None): + return self._hprint_airy_prime(expr, exp, 'Bi') + + def _print_hyper(self, expr, exp=None): + tex = r"{{}_{%s}F_{%s}\left(\begin{matrix} %s \\ %s \end{matrix}" \ + r"\middle| {%s} \right)}" % \ + (self._print(len(expr.ap)), self._print(len(expr.bq)), + self._hprint_vec(expr.ap), self._hprint_vec(expr.bq), + self._print(expr.argument)) + + if exp is not None: + tex = r"{%s}^{%s}" % (tex, exp) + return tex + + def _print_meijerg(self, expr, exp=None): + tex = r"{G_{%s, %s}^{%s, %s}\left(\begin{matrix} %s & %s \\" \ + r"%s & %s \end{matrix} \middle| {%s} \right)}" % \ + (self._print(len(expr.ap)), self._print(len(expr.bq)), + self._print(len(expr.bm)), self._print(len(expr.an)), + self._hprint_vec(expr.an), self._hprint_vec(expr.aother), + self._hprint_vec(expr.bm), self._hprint_vec(expr.bother), + self._print(expr.argument)) + + if exp is not None: + tex = r"{%s}^{%s}" % (tex, exp) + return tex + + def _print_dirichlet_eta(self, expr, exp=None): + tex = r"\left(%s\right)" % self._print(expr.args[0]) + if exp is not None: + return r"\eta^{%s}%s" % (exp, tex) + return r"\eta%s" % tex + + def _print_zeta(self, expr, exp=None): + if len(expr.args) == 2: + tex = r"\left(%s, %s\right)" % tuple(map(self._print, expr.args)) + else: + tex = r"\left(%s\right)" % self._print(expr.args[0]) + if exp is not None: + return r"\zeta^{%s}%s" % (exp, tex) + return r"\zeta%s" % tex + + def _print_stieltjes(self, expr, exp=None): + if len(expr.args) == 2: + tex = r"_{%s}\left(%s\right)" % tuple(map(self._print, expr.args)) + else: + tex = r"_{%s}" % self._print(expr.args[0]) + if exp is not None: + return r"\gamma%s^{%s}" % (tex, exp) + return r"\gamma%s" % tex + + def _print_lerchphi(self, expr, exp=None): + tex = r"\left(%s, %s, %s\right)" % tuple(map(self._print, expr.args)) + if exp is None: + return r"\Phi%s" % tex + return r"\Phi^{%s}%s" % (exp, tex) + + def _print_polylog(self, expr, exp=None): + s, z = map(self._print, expr.args) + tex = r"\left(%s\right)" % z + if exp is None: + return r"\operatorname{Li}_{%s}%s" % (s, tex) + return r"\operatorname{Li}_{%s}^{%s}%s" % (s, exp, tex) + + def _print_jacobi(self, expr, exp=None): + n, a, b, x = map(self._print, expr.args) + tex = r"P_{%s}^{\left(%s,%s\right)}\left(%s\right)" % (n, a, b, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_gegenbauer(self, expr, exp=None): + n, a, x = map(self._print, expr.args) + tex = r"C_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_chebyshevt(self, expr, exp=None): + n, x = map(self._print, expr.args) + tex = r"T_{%s}\left(%s\right)" % (n, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_chebyshevu(self, expr, exp=None): + n, x = map(self._print, expr.args) + tex = r"U_{%s}\left(%s\right)" % (n, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_legendre(self, expr, exp=None): + n, x = map(self._print, expr.args) + tex = r"P_{%s}\left(%s\right)" % (n, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_assoc_legendre(self, expr, exp=None): + n, a, x = map(self._print, expr.args) + tex = r"P_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_hermite(self, expr, exp=None): + n, x = map(self._print, expr.args) + tex = r"H_{%s}\left(%s\right)" % (n, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_laguerre(self, expr, exp=None): + n, x = map(self._print, expr.args) + tex = r"L_{%s}\left(%s\right)" % (n, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_assoc_laguerre(self, expr, exp=None): + n, a, x = map(self._print, expr.args) + tex = r"L_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_Ynm(self, expr, exp=None): + n, m, theta, phi = map(self._print, expr.args) + tex = r"Y_{%s}^{%s}\left(%s,%s\right)" % (n, m, theta, phi) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def _print_Znm(self, expr, exp=None): + n, m, theta, phi = map(self._print, expr.args) + tex = r"Z_{%s}^{%s}\left(%s,%s\right)" % (n, m, theta, phi) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (exp) + return tex + + def __print_mathieu_functions(self, character, args, prime=False, exp=None): + a, q, z = map(self._print, args) + sup = r"^{\prime}" if prime else "" + exp = "" if not exp else "^{%s}" % exp + return r"%s%s\left(%s, %s, %s\right)%s" % (character, sup, a, q, z, exp) + + def _print_mathieuc(self, expr, exp=None): + return self.__print_mathieu_functions("C", expr.args, exp=exp) + + def _print_mathieus(self, expr, exp=None): + return self.__print_mathieu_functions("S", expr.args, exp=exp) + + def _print_mathieucprime(self, expr, exp=None): + return self.__print_mathieu_functions("C", expr.args, prime=True, exp=exp) + + def _print_mathieusprime(self, expr, exp=None): + return self.__print_mathieu_functions("S", expr.args, prime=True, exp=exp) + + def _print_Rational(self, expr): + if expr.q != 1: + sign = "" + p = expr.p + if expr.p < 0: + sign = "- " + p = -p + if self._settings['fold_short_frac']: + return r"%s%d / %d" % (sign, p, expr.q) + return r"%s\frac{%d}{%d}" % (sign, p, expr.q) + else: + return self._print(expr.p) + + def _print_Order(self, expr): + s = self._print(expr.expr) + if expr.point and any(p != S.Zero for p in expr.point) or \ + len(expr.variables) > 1: + s += '; ' + if len(expr.variables) > 1: + s += self._print(expr.variables) + elif expr.variables: + s += self._print(expr.variables[0]) + s += r'\rightarrow ' + if len(expr.point) > 1: + s += self._print(expr.point) + else: + s += self._print(expr.point[0]) + return r"O\left(%s\right)" % s + + def _print_Symbol(self, expr: Symbol, style='plain'): + name: str = self._settings['symbol_names'].get(expr) + if name is not None: + return name + + return self._deal_with_super_sub(expr.name, style=style) + + _print_RandomSymbol = _print_Symbol + + def _split_super_sub(self, name: str) -> tuple[str, list[str], list[str]]: + if name is None or '{' in name: + return (name, [], []) + elif self._settings["disable_split_super_sub"]: + name, supers, subs = (name.replace('_', '\\_').replace('^', '\\^'), [], []) + else: + name, supers, subs = split_super_sub(name) + name = translate(name) + supers = [translate(sup) for sup in supers] + subs = [translate(sub) for sub in subs] + return (name, supers, subs) + + def _deal_with_super_sub(self, string: str, style='plain') -> str: + name, supers, subs = self._split_super_sub(string) + + # apply the style only to the name + if style == 'bold': + name = "\\mathbf{{{}}}".format(name) + + # glue all items together: + if supers: + name += "^{%s}" % " ".join(supers) + if subs: + name += "_{%s}" % " ".join(subs) + + return name + + def _print_Relational(self, expr): + if self._settings['itex']: + gt = r"\gt" + lt = r"\lt" + else: + gt = ">" + lt = "<" + + charmap = { + "==": "=", + ">": gt, + "<": lt, + ">=": r"\geq", + "<=": r"\leq", + "!=": r"\neq", + } + + return "%s %s %s" % (self._print(expr.lhs), + charmap[expr.rel_op], self._print(expr.rhs)) + + def _print_Piecewise(self, expr): + ecpairs = [r"%s & \text{for}\: %s" % (self._print(e), self._print(c)) + for e, c in expr.args[:-1]] + if expr.args[-1].cond == true: + ecpairs.append(r"%s & \text{otherwise}" % + self._print(expr.args[-1].expr)) + else: + ecpairs.append(r"%s & \text{for}\: %s" % + (self._print(expr.args[-1].expr), + self._print(expr.args[-1].cond))) + tex = r"\begin{cases} %s \end{cases}" + return tex % r" \\".join(ecpairs) + + def _print_matrix_contents(self, expr): + lines = [] + + for line in range(expr.rows): # horrible, should be 'rows' + lines.append(" & ".join([self._print(i) for i in expr[line, :]])) + + mat_str = self._settings['mat_str'] + if mat_str is None: + if self._settings['mode'] == 'inline': + mat_str = 'smallmatrix' + else: + if (expr.cols <= 10) is True: + mat_str = 'matrix' + else: + mat_str = 'array' + + out_str = r'\begin{%MATSTR%}%s\end{%MATSTR%}' + out_str = out_str.replace('%MATSTR%', mat_str) + if mat_str == 'array': + out_str = out_str.replace('%s', '{' + 'c'*expr.cols + '}%s') + return out_str % r"\\".join(lines) + + def _print_MatrixBase(self, expr): + out_str = self._print_matrix_contents(expr) + if self._settings['mat_delim']: + left_delim = self._settings['mat_delim'] + right_delim = self._delim_dict[left_delim] + out_str = r'\left' + left_delim + out_str + \ + r'\right' + right_delim + return out_str + + def _print_MatrixElement(self, expr): + matrix_part = self.parenthesize(expr.parent, PRECEDENCE['Atom'], strict=True) + index_part = f"{self._print(expr.i)},{self._print(expr.j)}" + return f"{{{matrix_part}}}_{{{index_part}}}" + + def _print_MatrixSlice(self, expr): + def latexslice(x, dim): + x = list(x) + if x[2] == 1: + del x[2] + if x[0] == 0: + x[0] = None + if x[1] == dim: + x[1] = None + return ':'.join(self._print(xi) if xi is not None else '' for xi in x) + return (self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) + r'\left[' + + latexslice(expr.rowslice, expr.parent.rows) + ', ' + + latexslice(expr.colslice, expr.parent.cols) + r'\right]') + + def _print_BlockMatrix(self, expr): + return self._print(expr.blocks) + + def _print_Transpose(self, expr): + mat = expr.arg + from sympy.matrices import MatrixSymbol, BlockMatrix + if (not isinstance(mat, MatrixSymbol) and + not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr): + return r"\left(%s\right)^{T}" % self._print(mat) + else: + s = self.parenthesize(mat, precedence_traditional(expr), True) + if '^' in s: + return r"\left(%s\right)^{T}" % s + else: + return "%s^{T}" % s + + def _print_Trace(self, expr): + mat = expr.arg + return r"\operatorname{tr}\left(%s \right)" % self._print(mat) + + def _print_Adjoint(self, expr): + style_to_latex = { + "dagger" : r"\dagger", + "star" : r"\ast", + "hermitian": r"\mathsf{H}" + } + adjoint_style = style_to_latex.get(self._settings["adjoint_style"], r"\dagger") + mat = expr.arg + from sympy.matrices import MatrixSymbol, BlockMatrix + if (not isinstance(mat, MatrixSymbol) and + not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr): + return r"\left(%s\right)^{%s}" % (self._print(mat), adjoint_style) + else: + s = self.parenthesize(mat, precedence_traditional(expr), True) + if '^' in s: + return r"\left(%s\right)^{%s}" % (s, adjoint_style) + else: + return r"%s^{%s}" % (s, adjoint_style) + + def _print_MatMul(self, expr): + from sympy import MatMul + + # Parenthesize nested MatMul but not other types of Mul objects: + parens = lambda x: self._print(x) if isinstance(x, Mul) and not isinstance(x, MatMul) else \ + self.parenthesize(x, precedence_traditional(expr), False) + + args = list(expr.args) + if expr.could_extract_minus_sign(): + if args[0] == -1: + args = args[1:] + else: + args[0] = -args[0] + return '- ' + ' '.join(map(parens, args)) + else: + return ' '.join(map(parens, args)) + + def _print_DotProduct(self, expr): + level = precedence_traditional(expr) + left, right = expr.args + return rf"{self.parenthesize(left, level)} \cdot {self.parenthesize(right, level)}" + + def _print_Determinant(self, expr): + mat = expr.arg + if mat.is_MatrixExpr: + from sympy.matrices.expressions.blockmatrix import BlockMatrix + if isinstance(mat, BlockMatrix): + return r"\left|{%s}\right|" % self._print_matrix_contents(mat.blocks) + return r"\left|{%s}\right|" % self._print(mat) + return r"\left|{%s}\right|" % self._print_matrix_contents(mat) + + + def _print_Mod(self, expr, exp=None): + if exp is not None: + return r'\left(%s \bmod %s\right)^{%s}' % \ + (self.parenthesize(expr.args[0], PRECEDENCE['Mul'], + strict=True), + self.parenthesize(expr.args[1], PRECEDENCE['Mul'], + strict=True), + exp) + return r'%s \bmod %s' % (self.parenthesize(expr.args[0], + PRECEDENCE['Mul'], + strict=True), + self.parenthesize(expr.args[1], + PRECEDENCE['Mul'], + strict=True)) + + def _print_HadamardProduct(self, expr): + args = expr.args + prec = PRECEDENCE['Pow'] + parens = self.parenthesize + + return r' \circ '.join( + (parens(arg, prec, strict=True) for arg in args)) + + def _print_HadamardPower(self, expr): + if precedence_traditional(expr.exp) < PRECEDENCE["Mul"]: + template = r"%s^{\circ \left({%s}\right)}" + else: + template = r"%s^{\circ {%s}}" + return self._helper_print_standard_power(expr, template) + + def _print_KroneckerProduct(self, expr): + args = expr.args + prec = PRECEDENCE['Pow'] + parens = self.parenthesize + + return r' \otimes '.join( + (parens(arg, prec, strict=True) for arg in args)) + + def _print_MatPow(self, expr): + base, exp = expr.base, expr.exp + from sympy.matrices import MatrixSymbol + if not isinstance(base, MatrixSymbol) and base.is_MatrixExpr: + return "\\left(%s\\right)^{%s}" % (self._print(base), + self._print(exp)) + else: + base_str = self._print(base) + if '^' in base_str: + return r"\left(%s\right)^{%s}" % (base_str, self._print(exp)) + else: + return "%s^{%s}" % (base_str, self._print(exp)) + + def _print_MatrixSymbol(self, expr): + return self._print_Symbol(expr, style=self._settings[ + 'mat_symbol_style']) + + def _print_ZeroMatrix(self, Z): + return "0" if self._settings[ + 'mat_symbol_style'] == 'plain' else r"\mathbf{0}" + + def _print_OneMatrix(self, O): + return "1" if self._settings[ + 'mat_symbol_style'] == 'plain' else r"\mathbf{1}" + + def _print_Identity(self, I): + return r"\mathbb{I}" if self._settings[ + 'mat_symbol_style'] == 'plain' else r"\mathbf{I}" + + def _print_PermutationMatrix(self, P): + perm_str = self._print(P.args[0]) + return "P_{%s}" % perm_str + + def _print_NDimArray(self, expr: NDimArray): + + if expr.rank() == 0: + return self._print(expr[()]) + + mat_str = self._settings['mat_str'] + if mat_str is None: + if self._settings['mode'] == 'inline': + mat_str = 'smallmatrix' + else: + if (expr.rank() == 0) or (expr.shape[-1] <= 10): + mat_str = 'matrix' + else: + mat_str = 'array' + block_str = r'\begin{%MATSTR%}%s\end{%MATSTR%}' + block_str = block_str.replace('%MATSTR%', mat_str) + if mat_str == 'array': + block_str = block_str.replace('%s', '{' + 'c'*expr.shape[0] + '}%s') + + if self._settings['mat_delim']: + left_delim: str = self._settings['mat_delim'] + right_delim = self._delim_dict[left_delim] + block_str = r'\left' + left_delim + block_str + \ + r'\right' + right_delim + + if expr.rank() == 0: + return block_str % "" + + level_str: list[list[str]] = [[] for i in range(expr.rank() + 1)] + shape_ranges = [list(range(i)) for i in expr.shape] + for outer_i in itertools.product(*shape_ranges): + level_str[-1].append(self._print(expr[outer_i])) + even = True + for back_outer_i in range(expr.rank()-1, -1, -1): + if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]: + break + if even: + level_str[back_outer_i].append( + r" & ".join(level_str[back_outer_i+1])) + else: + level_str[back_outer_i].append( + block_str % (r"\\".join(level_str[back_outer_i+1]))) + if len(level_str[back_outer_i+1]) == 1: + level_str[back_outer_i][-1] = r"\left[" + \ + level_str[back_outer_i][-1] + r"\right]" + even = not even + level_str[back_outer_i+1] = [] + + out_str = level_str[0][0] + + if expr.rank() % 2 == 1: + out_str = block_str % out_str + + return out_str + + def _printer_tensor_indices(self, name, indices, index_map: dict): + out_str = self._print(name) + last_valence = None + prev_map = None + for index in indices: + new_valence = index.is_up + if ((index in index_map) or prev_map) and \ + last_valence == new_valence: + out_str += "," + if last_valence != new_valence: + if last_valence is not None: + out_str += "}" + if index.is_up: + out_str += "{}^{" + else: + out_str += "{}_{" + out_str += self._print(index.args[0]) + if index in index_map: + out_str += "=" + out_str += self._print(index_map[index]) + prev_map = True + else: + prev_map = False + last_valence = new_valence + if last_valence is not None: + out_str += "}" + return out_str + + def _print_Tensor(self, expr): + name = expr.args[0].args[0] + indices = expr.get_indices() + return self._printer_tensor_indices(name, indices, {}) + + def _print_TensorElement(self, expr): + name = expr.expr.args[0].args[0] + indices = expr.expr.get_indices() + index_map = expr.index_map + return self._printer_tensor_indices(name, indices, index_map) + + def _print_TensMul(self, expr): + # prints expressions like "A(a)", "3*A(a)", "(1+x)*A(a)" + sign, args = expr._get_args_for_traditional_printer() + return sign + "".join( + [self.parenthesize(arg, precedence(expr)) for arg in args] + ) + + def _print_TensAdd(self, expr): + a = [] + args = expr.args + for x in args: + a.append(self.parenthesize(x, precedence(expr))) + a.sort() + s = ' + '.join(a) + s = s.replace('+ -', '- ') + return s + + def _print_TensorIndex(self, expr): + return "{}%s{%s}" % ( + "^" if expr.is_up else "_", + self._print(expr.args[0]) + ) + + def _print_PartialDerivative(self, expr): + if len(expr.variables) == 1: + return r"\frac{\partial}{\partial {%s}}{%s}" % ( + self._print(expr.variables[0]), + self.parenthesize(expr.expr, PRECEDENCE["Mul"], False) + ) + else: + return r"\frac{\partial^{%s}}{%s}{%s}" % ( + len(expr.variables), + " ".join([r"\partial {%s}" % self._print(i) for i in expr.variables]), + self.parenthesize(expr.expr, PRECEDENCE["Mul"], False) + ) + + def _print_ArraySymbol(self, expr): + return self._print(expr.name) + + def _print_ArrayElement(self, expr): + return "{{%s}_{%s}}" % ( + self.parenthesize(expr.name, PRECEDENCE["Func"], True), + ", ".join([f"{self._print(i)}" for i in expr.indices])) + + def _print_UniversalSet(self, expr): + return r"\mathbb{U}" + + def _print_frac(self, expr, exp=None): + if exp is None: + return r"\operatorname{frac}{\left(%s\right)}" % self._print(expr.args[0]) + else: + return r"\operatorname{frac}{\left(%s\right)}^{%s}" % ( + self._print(expr.args[0]), exp) + + def _print_tuple(self, expr): + if self._settings['decimal_separator'] == 'comma': + sep = ";" + elif self._settings['decimal_separator'] == 'period': + sep = "," + else: + raise ValueError('Unknown Decimal Separator') + + if len(expr) == 1: + # 1-tuple needs a trailing separator + return self._add_parens_lspace(self._print(expr[0]) + sep) + else: + return self._add_parens_lspace( + (sep + r" \ ").join([self._print(i) for i in expr])) + + def _print_TensorProduct(self, expr): + elements = [self._print(a) for a in expr.args] + return r' \otimes '.join(elements) + + def _print_WedgeProduct(self, expr): + elements = [self._print(a) for a in expr.args] + return r' \wedge '.join(elements) + + def _print_Tuple(self, expr): + return self._print_tuple(expr) + + def _print_list(self, expr): + if self._settings['decimal_separator'] == 'comma': + return r"\left[ %s\right]" % \ + r"; \ ".join([self._print(i) for i in expr]) + elif self._settings['decimal_separator'] == 'period': + return r"\left[ %s\right]" % \ + r", \ ".join([self._print(i) for i in expr]) + else: + raise ValueError('Unknown Decimal Separator') + + + def _print_dict(self, d): + keys = sorted(d.keys(), key=default_sort_key) + items = [] + + for key in keys: + val = d[key] + items.append("%s : %s" % (self._print(key), self._print(val))) + + return r"\left\{ %s\right\}" % r", \ ".join(items) + + def _print_Dict(self, expr): + return self._print_dict(expr) + + def _print_DiracDelta(self, expr, exp=None): + if len(expr.args) == 1 or expr.args[1] == 0: + tex = r"\delta\left(%s\right)" % self._print(expr.args[0]) + else: + tex = r"\delta^{\left( %s \right)}\left( %s \right)" % ( + self._print(expr.args[1]), self._print(expr.args[0])) + if exp: + tex = r"\left(%s\right)^{%s}" % (tex, exp) + return tex + + def _print_SingularityFunction(self, expr, exp=None): + shift = self._print(expr.args[0] - expr.args[1]) + power = self._print(expr.args[2]) + tex = r"{\left\langle %s \right\rangle}^{%s}" % (shift, power) + if exp is not None: + tex = r"{\left({\langle %s \rangle}^{%s}\right)}^{%s}" % (shift, power, exp) + return tex + + def _print_Heaviside(self, expr, exp=None): + pargs = ', '.join(self._print(arg) for arg in expr.pargs) + tex = r"\theta\left(%s\right)" % pargs + if exp: + tex = r"\left(%s\right)^{%s}" % (tex, exp) + return tex + + def _print_KroneckerDelta(self, expr, exp=None): + i = self._print(expr.args[0]) + j = self._print(expr.args[1]) + if expr.args[0].is_Atom and expr.args[1].is_Atom: + tex = r'\delta_{%s %s}' % (i, j) + else: + tex = r'\delta_{%s, %s}' % (i, j) + if exp is not None: + tex = r'\left(%s\right)^{%s}' % (tex, exp) + return tex + + def _print_LeviCivita(self, expr, exp=None): + indices = map(self._print, expr.args) + if all(x.is_Atom for x in expr.args): + tex = r'\varepsilon_{%s}' % " ".join(indices) + else: + tex = r'\varepsilon_{%s}' % ", ".join(indices) + if exp: + tex = r'\left(%s\right)^{%s}' % (tex, exp) + return tex + + def _print_RandomDomain(self, d): + if hasattr(d, 'as_boolean'): + return '\\text{Domain: }' + self._print(d.as_boolean()) + elif hasattr(d, 'set'): + return ('\\text{Domain: }' + self._print(d.symbols) + ' \\in ' + + self._print(d.set)) + elif hasattr(d, 'symbols'): + return '\\text{Domain on }' + self._print(d.symbols) + else: + return self._print(None) + + def _print_FiniteSet(self, s): + items = sorted(s.args, key=default_sort_key) + return self._print_set(items) + + def _print_set(self, s): + items = sorted(s, key=default_sort_key) + if self._settings['decimal_separator'] == 'comma': + items = "; ".join(map(self._print, items)) + elif self._settings['decimal_separator'] == 'period': + items = ", ".join(map(self._print, items)) + else: + raise ValueError('Unknown Decimal Separator') + return r"\left\{%s\right\}" % items + + + _print_frozenset = _print_set + + def _print_Range(self, s): + def _print_symbolic_range(): + # Symbolic Range that cannot be resolved + if s.args[0] == 0: + if s.args[2] == 1: + cont = self._print(s.args[1]) + else: + cont = ", ".join(self._print(arg) for arg in s.args) + else: + if s.args[2] == 1: + cont = ", ".join(self._print(arg) for arg in s.args[:2]) + else: + cont = ", ".join(self._print(arg) for arg in s.args) + + return(f"\\text{{Range}}\\left({cont}\\right)") + + dots = object() + + if s.start.is_infinite and s.stop.is_infinite: + if s.step.is_positive: + printset = dots, -1, 0, 1, dots + else: + printset = dots, 1, 0, -1, dots + elif s.start.is_infinite: + printset = dots, s[-1] - s.step, s[-1] + elif s.stop.is_infinite: + it = iter(s) + printset = next(it), next(it), dots + elif s.is_empty is not None: + if (s.size < 4) == True: + printset = tuple(s) + elif s.is_iterable: + it = iter(s) + printset = next(it), next(it), dots, s[-1] + else: + return _print_symbolic_range() + else: + return _print_symbolic_range() + return (r"\left\{" + + r", ".join(self._print(el) if el is not dots else r'\ldots' for el in printset) + + r"\right\}") + + def __print_number_polynomial(self, expr, letter, exp=None): + if len(expr.args) == 2: + if exp is not None: + return r"%s_{%s}^{%s}\left(%s\right)" % (letter, + self._print(expr.args[0]), exp, + self._print(expr.args[1])) + return r"%s_{%s}\left(%s\right)" % (letter, + self._print(expr.args[0]), self._print(expr.args[1])) + + tex = r"%s_{%s}" % (letter, self._print(expr.args[0])) + if exp is not None: + tex = r"%s^{%s}" % (tex, exp) + return tex + + def _print_bernoulli(self, expr, exp=None): + return self.__print_number_polynomial(expr, "B", exp) + + def _print_genocchi(self, expr, exp=None): + return self.__print_number_polynomial(expr, "G", exp) + + def _print_bell(self, expr, exp=None): + if len(expr.args) == 3: + tex1 = r"B_{%s, %s}" % (self._print(expr.args[0]), + self._print(expr.args[1])) + tex2 = r"\left(%s\right)" % r", ".join(self._print(el) for + el in expr.args[2]) + if exp is not None: + tex = r"%s^{%s}%s" % (tex1, exp, tex2) + else: + tex = tex1 + tex2 + return tex + return self.__print_number_polynomial(expr, "B", exp) + + def _print_fibonacci(self, expr, exp=None): + return self.__print_number_polynomial(expr, "F", exp) + + def _print_lucas(self, expr, exp=None): + tex = r"L_{%s}" % self._print(expr.args[0]) + if exp is not None: + tex = r"%s^{%s}" % (tex, exp) + return tex + + def _print_tribonacci(self, expr, exp=None): + return self.__print_number_polynomial(expr, "T", exp) + + def _print_mobius(self, expr, exp=None): + if exp is None: + return r'\mu\left(%s\right)' % self._print(expr.args[0]) + return r'\mu^{%s}\left(%s\right)' % (exp, self._print(expr.args[0])) + + def _print_SeqFormula(self, s): + dots = object() + if len(s.start.free_symbols) > 0 or len(s.stop.free_symbols) > 0: + return r"\left\{%s\right\}_{%s=%s}^{%s}" % ( + self._print(s.formula), + self._print(s.variables[0]), + self._print(s.start), + self._print(s.stop) + ) + if s.start is S.NegativeInfinity: + stop = s.stop + printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2), + s.coeff(stop - 1), s.coeff(stop)) + elif s.stop is S.Infinity or s.length > 4: + printset = s[:4] + printset.append(dots) + else: + printset = tuple(s) + + return (r"\left[" + + r", ".join(self._print(el) if el is not dots else r'\ldots' for el in printset) + + r"\right]") + + _print_SeqPer = _print_SeqFormula + _print_SeqAdd = _print_SeqFormula + _print_SeqMul = _print_SeqFormula + + def _print_Interval(self, i): + if i.start == i.end: + return r"\left\{%s\right\}" % self._print(i.start) + + else: + if i.left_open: + left = '(' + else: + left = '[' + + if i.right_open: + right = ')' + else: + right = ']' + + return r"\left%s%s, %s\right%s" % \ + (left, self._print(i.start), self._print(i.end), right) + + def _print_AccumulationBounds(self, i): + return r"\left\langle %s, %s\right\rangle" % \ + (self._print(i.min), self._print(i.max)) + + def _print_Union(self, u): + prec = precedence_traditional(u) + args_str = [self.parenthesize(i, prec) for i in u.args] + return r" \cup ".join(args_str) + + def _print_Complement(self, u): + prec = precedence_traditional(u) + args_str = [self.parenthesize(i, prec) for i in u.args] + return r" \setminus ".join(args_str) + + def _print_Intersection(self, u): + prec = precedence_traditional(u) + args_str = [self.parenthesize(i, prec) for i in u.args] + return r" \cap ".join(args_str) + + def _print_SymmetricDifference(self, u): + prec = precedence_traditional(u) + args_str = [self.parenthesize(i, prec) for i in u.args] + return r" \triangle ".join(args_str) + + def _print_ProductSet(self, p): + prec = precedence_traditional(p) + if len(p.sets) >= 1 and not has_variety(p.sets): + return self.parenthesize(p.sets[0], prec) + "^{%d}" % len(p.sets) + return r" \times ".join( + self.parenthesize(set, prec) for set in p.sets) + + def _print_EmptySet(self, e): + return r"\emptyset" + + def _print_Naturals(self, n): + return r"\mathbb{N}" + + def _print_Naturals0(self, n): + return r"\mathbb{N}_0" + + def _print_Integers(self, i): + return r"\mathbb{Z}" + + def _print_Rationals(self, i): + return r"\mathbb{Q}" + + def _print_Reals(self, i): + return r"\mathbb{R}" + + def _print_Complexes(self, i): + return r"\mathbb{C}" + + def _print_ImageSet(self, s): + expr = s.lamda.expr + sig = s.lamda.signature + xys = ((self._print(x), self._print(y)) for x, y in zip(sig, s.base_sets)) + xinys = r", ".join(r"%s \in %s" % xy for xy in xys) + return r"\left\{%s\; \middle|\; %s\right\}" % (self._print(expr), xinys) + + def _print_ConditionSet(self, s): + vars_print = ', '.join([self._print(var) for var in Tuple(s.sym)]) + if s.base_set is S.UniversalSet: + return r"\left\{%s\; \middle|\; %s \right\}" % \ + (vars_print, self._print(s.condition)) + + return r"\left\{%s\; \middle|\; %s \in %s \wedge %s \right\}" % ( + vars_print, + vars_print, + self._print(s.base_set), + self._print(s.condition)) + + def _print_PowerSet(self, expr): + arg_print = self._print(expr.args[0]) + return r"\mathcal{{P}}\left({}\right)".format(arg_print) + + def _print_ComplexRegion(self, s): + vars_print = ', '.join([self._print(var) for var in s.variables]) + return r"\left\{%s\; \middle|\; %s \in %s \right\}" % ( + self._print(s.expr), + vars_print, + self._print(s.sets)) + + def _print_Contains(self, e): + return r"%s \in %s" % tuple(self._print(a) for a in e.args) + + def _print_FourierSeries(self, s): + if s.an.formula is S.Zero and s.bn.formula is S.Zero: + return self._print(s.a0) + return self._print_Add(s.truncate()) + r' + \ldots' + + def _print_FormalPowerSeries(self, s): + return self._print_Add(s.infinite) + + def _print_FiniteField(self, expr): + return r"\mathbb{F}_{%s}" % expr.mod + + def _print_IntegerRing(self, expr): + return r"\mathbb{Z}" + + def _print_RationalField(self, expr): + return r"\mathbb{Q}" + + def _print_RealField(self, expr): + return r"\mathbb{R}" + + def _print_ComplexField(self, expr): + return r"\mathbb{C}" + + def _print_PolynomialRing(self, expr): + domain = self._print(expr.domain) + symbols = ", ".join(map(self._print, expr.symbols)) + return r"%s\left[%s\right]" % (domain, symbols) + + def _print_FractionField(self, expr): + domain = self._print(expr.domain) + symbols = ", ".join(map(self._print, expr.symbols)) + return r"%s\left(%s\right)" % (domain, symbols) + + def _print_PolynomialRingBase(self, expr): + domain = self._print(expr.domain) + symbols = ", ".join(map(self._print, expr.symbols)) + inv = "" + if not expr.is_Poly: + inv = r"S_<^{-1}" + return r"%s%s\left[%s\right]" % (inv, domain, symbols) + + def _print_Poly(self, poly): + cls = poly.__class__.__name__ + terms = [] + for monom, coeff in poly.terms(): + s_monom = '' + for i, exp in enumerate(monom): + if exp > 0: + if exp == 1: + s_monom += self._print(poly.gens[i]) + else: + s_monom += self._print(pow(poly.gens[i], exp)) + + if coeff.is_Add: + if s_monom: + s_coeff = r"\left(%s\right)" % self._print(coeff) + else: + s_coeff = self._print(coeff) + else: + if s_monom: + if coeff is S.One: + terms.extend(['+', s_monom]) + continue + + if coeff is S.NegativeOne: + terms.extend(['-', s_monom]) + continue + + s_coeff = self._print(coeff) + + if not s_monom: + s_term = s_coeff + else: + s_term = s_coeff + " " + s_monom + + if s_term.startswith('-'): + terms.extend(['-', s_term[1:]]) + else: + terms.extend(['+', s_term]) + + if terms[0] in ('-', '+'): + modifier = terms.pop(0) + + if modifier == '-': + terms[0] = '-' + terms[0] + + expr = ' '.join(terms) + gens = list(map(self._print, poly.gens)) + domain = "domain=%s" % self._print(poly.get_domain()) + + args = ", ".join([expr] + gens + [domain]) + if cls in accepted_latex_functions: + tex = r"\%s {\left(%s \right)}" % (cls, args) + else: + tex = r"\operatorname{%s}{\left( %s \right)}" % (cls, args) + + return tex + + def _print_ComplexRootOf(self, root): + cls = root.__class__.__name__ + if cls == "ComplexRootOf": + cls = "CRootOf" + expr = self._print(root.expr) + index = root.index + if cls in accepted_latex_functions: + return r"\%s {\left(%s, %d\right)}" % (cls, expr, index) + else: + return r"\operatorname{%s} {\left(%s, %d\right)}" % (cls, expr, + index) + + def _print_RootSum(self, expr): + cls = expr.__class__.__name__ + args = [self._print(expr.expr)] + + if expr.fun is not S.IdentityFunction: + args.append(self._print(expr.fun)) + + if cls in accepted_latex_functions: + return r"\%s {\left(%s\right)}" % (cls, ", ".join(args)) + else: + return r"\operatorname{%s} {\left(%s\right)}" % (cls, + ", ".join(args)) + + def _print_OrdinalOmega(self, expr): + return r"\omega" + + def _print_OmegaPower(self, expr): + exp, mul = expr.args + if mul != 1: + if exp != 1: + return r"{} \omega^{{{}}}".format(mul, exp) + else: + return r"{} \omega".format(mul) + else: + if exp != 1: + return r"\omega^{{{}}}".format(exp) + else: + return r"\omega" + + def _print_Ordinal(self, expr): + return " + ".join([self._print(arg) for arg in expr.args]) + + def _print_PolyElement(self, poly): + mul_symbol = self._settings['mul_symbol_latex'] + return poly.str(self, PRECEDENCE, "{%s}^{%d}", mul_symbol) + + def _print_FracElement(self, frac): + if frac.denom == 1: + return self._print(frac.numer) + else: + numer = self._print(frac.numer) + denom = self._print(frac.denom) + return r"\frac{%s}{%s}" % (numer, denom) + + def _print_euler(self, expr, exp=None): + m, x = (expr.args[0], None) if len(expr.args) == 1 else expr.args + tex = r"E_{%s}" % self._print(m) + if exp is not None: + tex = r"%s^{%s}" % (tex, exp) + if x is not None: + tex = r"%s\left(%s\right)" % (tex, self._print(x)) + return tex + + def _print_catalan(self, expr, exp=None): + tex = r"C_{%s}" % self._print(expr.args[0]) + if exp is not None: + tex = r"%s^{%s}" % (tex, exp) + return tex + + def _print_UnifiedTransform(self, expr, s, inverse=False): + return r"\mathcal{{{}}}{}_{{{}}}\left[{}\right]\left({}\right)".format(s, '^{-1}' if inverse else '', self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) + + def _print_MellinTransform(self, expr): + return self._print_UnifiedTransform(expr, 'M') + + def _print_InverseMellinTransform(self, expr): + return self._print_UnifiedTransform(expr, 'M', True) + + def _print_LaplaceTransform(self, expr): + return self._print_UnifiedTransform(expr, 'L') + + def _print_InverseLaplaceTransform(self, expr): + return self._print_UnifiedTransform(expr, 'L', True) + + def _print_FourierTransform(self, expr): + return self._print_UnifiedTransform(expr, 'F') + + def _print_InverseFourierTransform(self, expr): + return self._print_UnifiedTransform(expr, 'F', True) + + def _print_SineTransform(self, expr): + return self._print_UnifiedTransform(expr, 'SIN') + + def _print_InverseSineTransform(self, expr): + return self._print_UnifiedTransform(expr, 'SIN', True) + + def _print_CosineTransform(self, expr): + return self._print_UnifiedTransform(expr, 'COS') + + def _print_InverseCosineTransform(self, expr): + return self._print_UnifiedTransform(expr, 'COS', True) + + def _print_DMP(self, p): + try: + if p.ring is not None: + # TODO incorporate order + return self._print(p.ring.to_sympy(p)) + except SympifyError: + pass + return self._print(repr(p)) + + def _print_DMF(self, p): + return self._print_DMP(p) + + def _print_Object(self, object): + return self._print(Symbol(object.name)) + + def _print_LambertW(self, expr, exp=None): + arg0 = self._print(expr.args[0]) + exp = r"^{%s}" % (exp,) if exp is not None else "" + if len(expr.args) == 1: + result = r"W%s\left(%s\right)" % (exp, arg0) + else: + arg1 = self._print(expr.args[1]) + result = "W{0}_{{{1}}}\\left({2}\\right)".format(exp, arg1, arg0) + return result + + def _print_Expectation(self, expr): + return r"\operatorname{{E}}\left[{}\right]".format(self._print(expr.args[0])) + + def _print_Variance(self, expr): + return r"\operatorname{{Var}}\left({}\right)".format(self._print(expr.args[0])) + + def _print_Covariance(self, expr): + return r"\operatorname{{Cov}}\left({}\right)".format(", ".join(self._print(arg) for arg in expr.args)) + + def _print_Probability(self, expr): + return r"\operatorname{{P}}\left({}\right)".format(self._print(expr.args[0])) + + def _print_Morphism(self, morphism): + domain = self._print(morphism.domain) + codomain = self._print(morphism.codomain) + return "%s\\rightarrow %s" % (domain, codomain) + + def _print_TransferFunction(self, expr): + num, den = self._print(expr.num), self._print(expr.den) + return r"\frac{%s}{%s}" % (num, den) + + def _print_Series(self, expr): + args = list(expr.args) + parens = lambda x: self.parenthesize(x, precedence_traditional(expr), + False) + return ' '.join(map(parens, args)) + + def _print_MIMOSeries(self, expr): + from sympy.physics.control.lti import MIMOParallel + args = list(expr.args)[::-1] + parens = lambda x: self.parenthesize(x, precedence_traditional(expr), + False) if isinstance(x, MIMOParallel) else self._print(x) + return r"\cdot".join(map(parens, args)) + + def _print_Parallel(self, expr): + return ' + '.join(map(self._print, expr.args)) + + def _print_MIMOParallel(self, expr): + return ' + '.join(map(self._print, expr.args)) + + def _print_Feedback(self, expr): + from sympy.physics.control import TransferFunction, Series + + num, tf = expr.sys1, TransferFunction(1, 1, expr.var) + num_arg_list = list(num.args) if isinstance(num, Series) else [num] + den_arg_list = list(expr.sys2.args) if \ + isinstance(expr.sys2, Series) else [expr.sys2] + den_term_1 = tf + + if isinstance(num, Series) and isinstance(expr.sys2, Series): + den_term_2 = Series(*num_arg_list, *den_arg_list) + elif isinstance(num, Series) and isinstance(expr.sys2, TransferFunction): + if expr.sys2 == tf: + den_term_2 = Series(*num_arg_list) + else: + den_term_2 = tf, Series(*num_arg_list, expr.sys2) + elif isinstance(num, TransferFunction) and isinstance(expr.sys2, Series): + if num == tf: + den_term_2 = Series(*den_arg_list) + else: + den_term_2 = Series(num, *den_arg_list) + else: + if num == tf: + den_term_2 = Series(*den_arg_list) + elif expr.sys2 == tf: + den_term_2 = Series(*num_arg_list) + else: + den_term_2 = Series(*num_arg_list, *den_arg_list) + + numer = self._print(num) + denom_1 = self._print(den_term_1) + denom_2 = self._print(den_term_2) + _sign = "+" if expr.sign == -1 else "-" + + return r"\frac{%s}{%s %s %s}" % (numer, denom_1, _sign, denom_2) + + def _print_MIMOFeedback(self, expr): + from sympy.physics.control import MIMOSeries + inv_mat = self._print(MIMOSeries(expr.sys2, expr.sys1)) + sys1 = self._print(expr.sys1) + _sign = "+" if expr.sign == -1 else "-" + return r"\left(I_{\tau} %s %s\right)^{-1} \cdot %s" % (_sign, inv_mat, sys1) + + def _print_TransferFunctionMatrix(self, expr): + mat = self._print(expr._expr_mat) + return r"%s_\tau" % mat + + def _print_DFT(self, expr): + return r"\text{{{}}}_{{{}}}".format(expr.__class__.__name__, expr.n) + _print_IDFT = _print_DFT + + def _print_NamedMorphism(self, morphism): + pretty_name = self._print(Symbol(morphism.name)) + pretty_morphism = self._print_Morphism(morphism) + return "%s:%s" % (pretty_name, pretty_morphism) + + def _print_IdentityMorphism(self, morphism): + from sympy.categories import NamedMorphism + return self._print_NamedMorphism(NamedMorphism( + morphism.domain, morphism.codomain, "id")) + + def _print_CompositeMorphism(self, morphism): + # All components of the morphism have names and it is thus + # possible to build the name of the composite. + component_names_list = [self._print(Symbol(component.name)) for + component in morphism.components] + component_names_list.reverse() + component_names = "\\circ ".join(component_names_list) + ":" + + pretty_morphism = self._print_Morphism(morphism) + return component_names + pretty_morphism + + def _print_Category(self, morphism): + return r"\mathbf{{{}}}".format(self._print(Symbol(morphism.name))) + + def _print_Diagram(self, diagram): + if not diagram.premises: + # This is an empty diagram. + return self._print(S.EmptySet) + + latex_result = self._print(diagram.premises) + if diagram.conclusions: + latex_result += "\\Longrightarrow %s" % \ + self._print(diagram.conclusions) + + return latex_result + + def _print_DiagramGrid(self, grid): + latex_result = "\\begin{array}{%s}\n" % ("c" * grid.width) + + for i in range(grid.height): + for j in range(grid.width): + if grid[i, j]: + latex_result += latex(grid[i, j]) + latex_result += " " + if j != grid.width - 1: + latex_result += "& " + + if i != grid.height - 1: + latex_result += "\\\\" + latex_result += "\n" + + latex_result += "\\end{array}\n" + return latex_result + + def _print_FreeModule(self, M): + return '{{{}}}^{{{}}}'.format(self._print(M.ring), self._print(M.rank)) + + def _print_FreeModuleElement(self, m): + # Print as row vector for convenience, for now. + return r"\left[ {} \right]".format(",".join( + '{' + self._print(x) + '}' for x in m)) + + def _print_SubModule(self, m): + gens = [[self._print(m.ring.to_sympy(x)) for x in g] for g in m.gens] + curly = lambda o: r"{" + o + r"}" + square = lambda o: r"\left[ " + o + r" \right]" + gens_latex = ",".join(curly(square(",".join(curly(x) for x in g))) for g in gens) + return r"\left\langle {} \right\rangle".format(gens_latex) + + def _print_SubQuotientModule(self, m): + gens_latex = ",".join(["{" + self._print(g) + "}" for g in m.gens]) + return r"\left\langle {} \right\rangle".format(gens_latex) + + def _print_ModuleImplementedIdeal(self, m): + gens = [m.ring.to_sympy(x) for [x] in m._module.gens] + gens_latex = ",".join('{' + self._print(x) + '}' for x in gens) + return r"\left\langle {} \right\rangle".format(gens_latex) + + def _print_Quaternion(self, expr): + # TODO: This expression is potentially confusing, + # shall we print it as `Quaternion( ... )`? + s = [self.parenthesize(i, PRECEDENCE["Mul"], strict=True) + for i in expr.args] + a = [s[0]] + [i+" "+j for i, j in zip(s[1:], "ijk")] + return " + ".join(a) + + def _print_QuotientRing(self, R): + # TODO nicer fractions for few generators... + return r"\frac{{{}}}{{{}}}".format(self._print(R.ring), + self._print(R.base_ideal)) + + def _print_QuotientRingElement(self, x): + x_latex = self._print(x.ring.to_sympy(x)) + return r"{{{}}} + {{{}}}".format(x_latex, + self._print(x.ring.base_ideal)) + + def _print_QuotientModuleElement(self, m): + data = [m.module.ring.to_sympy(x) for x in m.data] + data_latex = r"\left[ {} \right]".format(",".join( + '{' + self._print(x) + '}' for x in data)) + return r"{{{}}} + {{{}}}".format(data_latex, + self._print(m.module.killed_module)) + + def _print_QuotientModule(self, M): + # TODO nicer fractions for few generators... + return r"\frac{{{}}}{{{}}}".format(self._print(M.base), + self._print(M.killed_module)) + + def _print_MatrixHomomorphism(self, h): + return r"{{{}}} : {{{}}} \to {{{}}}".format(self._print(h._sympy_matrix()), + self._print(h.domain), self._print(h.codomain)) + + def _print_Manifold(self, manifold): + name, supers, subs = self._split_super_sub(manifold.name.name) + + name = r'\text{%s}' % name + if supers: + name += "^{%s}" % " ".join(supers) + if subs: + name += "_{%s}" % " ".join(subs) + + return name + + def _print_Patch(self, patch): + return r'\text{%s}_{%s}' % (self._print(patch.name), self._print(patch.manifold)) + + def _print_CoordSystem(self, coordsys): + return r'\text{%s}^{\text{%s}}_{%s}' % ( + self._print(coordsys.name), self._print(coordsys.patch.name), self._print(coordsys.manifold) + ) + + def _print_CovarDerivativeOp(self, cvd): + return r'\mathbb{\nabla}_{%s}' % self._print(cvd._wrt) + + def _print_BaseScalarField(self, field): + string = field._coord_sys.symbols[field._index].name + return r'\mathbf{{{}}}'.format(self._print(Symbol(string))) + + def _print_BaseVectorField(self, field): + string = field._coord_sys.symbols[field._index].name + return r'\partial_{{{}}}'.format(self._print(Symbol(string))) + + def _print_Differential(self, diff): + field = diff._form_field + if hasattr(field, '_coord_sys'): + string = field._coord_sys.symbols[field._index].name + return r'\operatorname{{d}}{}'.format(self._print(Symbol(string))) + else: + string = self._print(field) + return r'\operatorname{{d}}\left({}\right)'.format(string) + + def _print_Tr(self, p): + # TODO: Handle indices + contents = self._print(p.args[0]) + return r'\operatorname{{tr}}\left({}\right)'.format(contents) + + def _print_totient(self, expr, exp=None): + if exp is not None: + return r'\left(\phi\left(%s\right)\right)^{%s}' % \ + (self._print(expr.args[0]), exp) + return r'\phi\left(%s\right)' % self._print(expr.args[0]) + + def _print_reduced_totient(self, expr, exp=None): + if exp is not None: + return r'\left(\lambda\left(%s\right)\right)^{%s}' % \ + (self._print(expr.args[0]), exp) + return r'\lambda\left(%s\right)' % self._print(expr.args[0]) + + def _print_divisor_sigma(self, expr, exp=None): + if len(expr.args) == 2: + tex = r"_%s\left(%s\right)" % tuple(map(self._print, + (expr.args[1], expr.args[0]))) + else: + tex = r"\left(%s\right)" % self._print(expr.args[0]) + if exp is not None: + return r"\sigma^{%s}%s" % (exp, tex) + return r"\sigma%s" % tex + + def _print_udivisor_sigma(self, expr, exp=None): + if len(expr.args) == 2: + tex = r"_%s\left(%s\right)" % tuple(map(self._print, + (expr.args[1], expr.args[0]))) + else: + tex = r"\left(%s\right)" % self._print(expr.args[0]) + if exp is not None: + return r"\sigma^*^{%s}%s" % (exp, tex) + return r"\sigma^*%s" % tex + + def _print_primenu(self, expr, exp=None): + if exp is not None: + return r'\left(\nu\left(%s\right)\right)^{%s}' % \ + (self._print(expr.args[0]), exp) + return r'\nu\left(%s\right)' % self._print(expr.args[0]) + + def _print_primeomega(self, expr, exp=None): + if exp is not None: + return r'\left(\Omega\left(%s\right)\right)^{%s}' % \ + (self._print(expr.args[0]), exp) + return r'\Omega\left(%s\right)' % self._print(expr.args[0]) + + def _print_Str(self, s): + return str(s.name) + + def _print_float(self, expr): + return self._print(Float(expr)) + + def _print_int(self, expr): + return str(expr) + + def _print_mpz(self, expr): + return str(expr) + + def _print_mpq(self, expr): + return str(expr) + + def _print_fmpz(self, expr): + return str(expr) + + def _print_fmpq(self, expr): + return str(expr) + + def _print_Predicate(self, expr): + return r"\operatorname{{Q}}_{{\text{{{}}}}}".format(latex_escape(str(expr.name))) + + def _print_AppliedPredicate(self, expr): + pred = expr.function + args = expr.arguments + pred_latex = self._print(pred) + args_latex = ', '.join([self._print(a) for a in args]) + return '%s(%s)' % (pred_latex, args_latex) + + def emptyPrinter(self, expr): + # default to just printing as monospace, like would normally be shown + s = super().emptyPrinter(expr) + + return r"\mathtt{\text{%s}}" % latex_escape(s) + + +def translate(s: str) -> str: + r''' + Check for a modifier ending the string. If present, convert the + modifier to latex and translate the rest recursively. + + Given a description of a Greek letter or other special character, + return the appropriate latex. + + Let everything else pass as given. + + >>> from sympy.printing.latex import translate + >>> translate('alphahatdotprime') + "{\\dot{\\hat{\\alpha}}}'" + ''' + # Process the rest + tex = tex_greek_dictionary.get(s) + if tex: + return tex + elif s.lower() in greek_letters_set: + return "\\" + s.lower() + elif s in other_symbols: + return "\\" + s + else: + # Process modifiers, if any, and recurse + for key in sorted(modifier_dict.keys(), key=len, reverse=True): + if s.lower().endswith(key) and len(s) > len(key): + return modifier_dict[key](translate(s[:-len(key)])) + return s + + + +@print_function(LatexPrinter) +def latex(expr, **settings): + r"""Convert the given expression to LaTeX string representation. + + Parameters + ========== + full_prec: boolean, optional + If set to True, a floating point number is printed with full precision. + fold_frac_powers : boolean, optional + Emit ``^{p/q}`` instead of ``^{\frac{p}{q}}`` for fractional powers. + fold_func_brackets : boolean, optional + Fold function brackets where applicable. + fold_short_frac : boolean, optional + Emit ``p / q`` instead of ``\frac{p}{q}`` when the denominator is + simple enough (at most two terms and no powers). The default value is + ``True`` for inline mode, ``False`` otherwise. + inv_trig_style : string, optional + How inverse trig functions should be displayed. Can be one of + ``'abbreviated'``, ``'full'``, or ``'power'``. Defaults to + ``'abbreviated'``. + itex : boolean, optional + Specifies if itex-specific syntax is used, including emitting + ``$$...$$``. + ln_notation : boolean, optional + If set to ``True``, ``\ln`` is used instead of default ``\log``. + long_frac_ratio : float or None, optional + The allowed ratio of the width of the numerator to the width of the + denominator before the printer breaks off long fractions. If ``None`` + (the default value), long fractions are not broken up. + mat_delim : string, optional + The delimiter to wrap around matrices. Can be one of ``'['``, ``'('``, + or the empty string ``''``. Defaults to ``'['``. + mat_str : string, optional + Which matrix environment string to emit. ``'smallmatrix'``, + ``'matrix'``, ``'array'``, etc. Defaults to ``'smallmatrix'`` for + inline mode, ``'matrix'`` for matrices of no more than 10 columns, and + ``'array'`` otherwise. + mode: string, optional + Specifies how the generated code will be delimited. ``mode`` can be one + of ``'plain'``, ``'inline'``, ``'equation'`` or ``'equation*'``. If + ``mode`` is set to ``'plain'``, then the resulting code will not be + delimited at all (this is the default). If ``mode`` is set to + ``'inline'`` then inline LaTeX ``$...$`` will be used. If ``mode`` is + set to ``'equation'`` or ``'equation*'``, the resulting code will be + enclosed in the ``equation`` or ``equation*`` environment (remember to + import ``amsmath`` for ``equation*``), unless the ``itex`` option is + set. In the latter case, the ``$$...$$`` syntax is used. + mul_symbol : string or None, optional + The symbol to use for multiplication. Can be one of ``None``, + ``'ldot'``, ``'dot'``, or ``'times'``. + order: string, optional + Any of the supported monomial orderings (currently ``'lex'``, + ``'grlex'``, or ``'grevlex'``), ``'old'``, and ``'none'``. This + parameter does nothing for `~.Mul` objects. Setting order to ``'old'`` + uses the compatibility ordering for ``~.Add`` defined in Printer. For + very large expressions, set the ``order`` keyword to ``'none'`` if + speed is a concern. + symbol_names : dictionary of strings mapped to symbols, optional + Dictionary of symbols and the custom strings they should be emitted as. + root_notation : boolean, optional + If set to ``False``, exponents of the form 1/n are printed in fractonal + form. Default is ``True``, to print exponent in root form. + mat_symbol_style : string, optional + Can be either ``'plain'`` (default) or ``'bold'``. If set to + ``'bold'``, a `~.MatrixSymbol` A will be printed as ``\mathbf{A}``, + otherwise as ``A``. + imaginary_unit : string, optional + String to use for the imaginary unit. Defined options are ``'i'`` + (default) and ``'j'``. Adding ``r`` or ``t`` in front gives ``\mathrm`` + or ``\text``, so ``'ri'`` leads to ``\mathrm{i}`` which gives + `\mathrm{i}`. + gothic_re_im : boolean, optional + If set to ``True``, `\Re` and `\Im` is used for ``re`` and ``im``, respectively. + The default is ``False`` leading to `\operatorname{re}` and `\operatorname{im}`. + decimal_separator : string, optional + Specifies what separator to use to separate the whole and fractional parts of a + floating point number as in `2.5` for the default, ``period`` or `2{,}5` + when ``comma`` is specified. Lists, sets, and tuple are printed with semicolon + separating the elements when ``comma`` is chosen. For example, [1; 2; 3] when + ``comma`` is chosen and [1,2,3] for when ``period`` is chosen. + parenthesize_super : boolean, optional + If set to ``False``, superscripted expressions will not be parenthesized when + powered. Default is ``True``, which parenthesizes the expression when powered. + min: Integer or None, optional + Sets the lower bound for the exponent to print floating point numbers in + fixed-point format. + max: Integer or None, optional + Sets the upper bound for the exponent to print floating point numbers in + fixed-point format. + diff_operator: string, optional + String to use for differential operator. Default is ``'d'``, to print in italic + form. ``'rd'``, ``'td'`` are shortcuts for ``\mathrm{d}`` and ``\text{d}``. + adjoint_style: string, optional + String to use for the adjoint symbol. Defined options are ``'dagger'`` + (default),``'star'``, and ``'hermitian'``. + + Notes + ===== + + Not using a print statement for printing, results in double backslashes for + latex commands since that's the way Python escapes backslashes in strings. + + >>> from sympy import latex, Rational + >>> from sympy.abc import tau + >>> latex((2*tau)**Rational(7,2)) + '8 \\sqrt{2} \\tau^{\\frac{7}{2}}' + >>> print(latex((2*tau)**Rational(7,2))) + 8 \sqrt{2} \tau^{\frac{7}{2}} + + Examples + ======== + + >>> from sympy import latex, pi, sin, asin, Integral, Matrix, Rational, log + >>> from sympy.abc import x, y, mu, r, tau + + Basic usage: + + >>> print(latex((2*tau)**Rational(7,2))) + 8 \sqrt{2} \tau^{\frac{7}{2}} + + ``mode`` and ``itex`` options: + + >>> print(latex((2*mu)**Rational(7,2), mode='plain')) + 8 \sqrt{2} \mu^{\frac{7}{2}} + >>> print(latex((2*tau)**Rational(7,2), mode='inline')) + $8 \sqrt{2} \tau^{7 / 2}$ + >>> print(latex((2*mu)**Rational(7,2), mode='equation*')) + \begin{equation*}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation*} + >>> print(latex((2*mu)**Rational(7,2), mode='equation')) + \begin{equation}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation} + >>> print(latex((2*mu)**Rational(7,2), mode='equation', itex=True)) + $$8 \sqrt{2} \mu^{\frac{7}{2}}$$ + >>> print(latex((2*mu)**Rational(7,2), mode='plain')) + 8 \sqrt{2} \mu^{\frac{7}{2}} + >>> print(latex((2*tau)**Rational(7,2), mode='inline')) + $8 \sqrt{2} \tau^{7 / 2}$ + >>> print(latex((2*mu)**Rational(7,2), mode='equation*')) + \begin{equation*}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation*} + >>> print(latex((2*mu)**Rational(7,2), mode='equation')) + \begin{equation}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation} + >>> print(latex((2*mu)**Rational(7,2), mode='equation', itex=True)) + $$8 \sqrt{2} \mu^{\frac{7}{2}}$$ + + Fraction options: + + >>> print(latex((2*tau)**Rational(7,2), fold_frac_powers=True)) + 8 \sqrt{2} \tau^{7/2} + >>> print(latex((2*tau)**sin(Rational(7,2)))) + \left(2 \tau\right)^{\sin{\left(\frac{7}{2} \right)}} + >>> print(latex((2*tau)**sin(Rational(7,2)), fold_func_brackets=True)) + \left(2 \tau\right)^{\sin {\frac{7}{2}}} + >>> print(latex(3*x**2/y)) + \frac{3 x^{2}}{y} + >>> print(latex(3*x**2/y, fold_short_frac=True)) + 3 x^{2} / y + >>> print(latex(Integral(r, r)/2/pi, long_frac_ratio=2)) + \frac{\int r\, dr}{2 \pi} + >>> print(latex(Integral(r, r)/2/pi, long_frac_ratio=0)) + \frac{1}{2 \pi} \int r\, dr + + Multiplication options: + + >>> print(latex((2*tau)**sin(Rational(7,2)), mul_symbol="times")) + \left(2 \times \tau\right)^{\sin{\left(\frac{7}{2} \right)}} + + Trig options: + + >>> print(latex(asin(Rational(7,2)))) + \operatorname{asin}{\left(\frac{7}{2} \right)} + >>> print(latex(asin(Rational(7,2)), inv_trig_style="full")) + \arcsin{\left(\frac{7}{2} \right)} + >>> print(latex(asin(Rational(7,2)), inv_trig_style="power")) + \sin^{-1}{\left(\frac{7}{2} \right)} + + Matrix options: + + >>> print(latex(Matrix(2, 1, [x, y]))) + \left[\begin{matrix}x\\y\end{matrix}\right] + >>> print(latex(Matrix(2, 1, [x, y]), mat_str = "array")) + \left[\begin{array}{c}x\\y\end{array}\right] + >>> print(latex(Matrix(2, 1, [x, y]), mat_delim="(")) + \left(\begin{matrix}x\\y\end{matrix}\right) + + Custom printing of symbols: + + >>> print(latex(x**2, symbol_names={x: 'x_i'})) + x_i^{2} + + Logarithms: + + >>> print(latex(log(10))) + \log{\left(10 \right)} + >>> print(latex(log(10), ln_notation=True)) + \ln{\left(10 \right)} + + ``latex()`` also supports the builtin container types :class:`list`, + :class:`tuple`, and :class:`dict`: + + >>> print(latex([2/x, y], mode='inline')) + $\left[ 2 / x, \ y\right]$ + + Unsupported types are rendered as monospaced plaintext: + + >>> print(latex(int)) + \mathtt{\text{}} + >>> print(latex("plain % text")) + \mathtt{\text{plain \% text}} + + See :ref:`printer_method_example` for an example of how to override + this behavior for your own types by implementing ``_latex``. + + .. versionchanged:: 1.7.0 + Unsupported types no longer have their ``str`` representation treated as valid latex. + + """ + return LatexPrinter(settings).doprint(expr) + + +def print_latex(expr, **settings): + """Prints LaTeX representation of the given expression. Takes the same + settings as ``latex()``.""" + + print(latex(expr, **settings)) + + +def multiline_latex(lhs, rhs, terms_per_line=1, environment="align*", use_dots=False, **settings): + r""" + This function generates a LaTeX equation with a multiline right-hand side + in an ``align*``, ``eqnarray`` or ``IEEEeqnarray`` environment. + + Parameters + ========== + + lhs : Expr + Left-hand side of equation + + rhs : Expr + Right-hand side of equation + + terms_per_line : integer, optional + Number of terms per line to print. Default is 1. + + environment : "string", optional + Which LaTeX wnvironment to use for the output. Options are "align*" + (default), "eqnarray", and "IEEEeqnarray". + + use_dots : boolean, optional + If ``True``, ``\\dots`` is added to the end of each line. Default is ``False``. + + Examples + ======== + + >>> from sympy import multiline_latex, symbols, sin, cos, exp, log, I + >>> x, y, alpha = symbols('x y alpha') + >>> expr = sin(alpha*y) + exp(I*alpha) - cos(log(y)) + >>> print(multiline_latex(x, expr)) + \begin{align*} + x = & e^{i \alpha} \\ + & + \sin{\left(\alpha y \right)} \\ + & - \cos{\left(\log{\left(y \right)} \right)} + \end{align*} + + Using at most two terms per line: + >>> print(multiline_latex(x, expr, 2)) + \begin{align*} + x = & e^{i \alpha} + \sin{\left(\alpha y \right)} \\ + & - \cos{\left(\log{\left(y \right)} \right)} + \end{align*} + + Using ``eqnarray`` and dots: + >>> print(multiline_latex(x, expr, terms_per_line=2, environment="eqnarray", use_dots=True)) + \begin{eqnarray} + x & = & e^{i \alpha} + \sin{\left(\alpha y \right)} \dots\nonumber\\ + & & - \cos{\left(\log{\left(y \right)} \right)} + \end{eqnarray} + + Using ``IEEEeqnarray``: + >>> print(multiline_latex(x, expr, environment="IEEEeqnarray")) + \begin{IEEEeqnarray}{rCl} + x & = & e^{i \alpha} \nonumber\\ + & & + \sin{\left(\alpha y \right)} \nonumber\\ + & & - \cos{\left(\log{\left(y \right)} \right)} + \end{IEEEeqnarray} + + Notes + ===== + + All optional parameters from ``latex`` can also be used. + + """ + + # Based on code from https://github.com/sympy/sympy/issues/3001 + l = LatexPrinter(**settings) + if environment == "eqnarray": + result = r'\begin{eqnarray}' + '\n' + first_term = '& = &' + nonumber = r'\nonumber' + end_term = '\n\\end{eqnarray}' + doubleet = True + elif environment == "IEEEeqnarray": + result = r'\begin{IEEEeqnarray}{rCl}' + '\n' + first_term = '& = &' + nonumber = r'\nonumber' + end_term = '\n\\end{IEEEeqnarray}' + doubleet = True + elif environment == "align*": + result = r'\begin{align*}' + '\n' + first_term = '= &' + nonumber = '' + end_term = '\n\\end{align*}' + doubleet = False + else: + raise ValueError("Unknown environment: {}".format(environment)) + dots = '' + if use_dots: + dots=r'\dots' + terms = rhs.as_ordered_terms() + n_terms = len(terms) + term_count = 1 + for i in range(n_terms): + term = terms[i] + term_start = '' + term_end = '' + sign = '+' + if term_count > terms_per_line: + if doubleet: + term_start = '& & ' + else: + term_start = '& ' + term_count = 1 + if term_count == terms_per_line: + # End of line + if i < n_terms-1: + # There are terms remaining + term_end = dots + nonumber + r'\\' + '\n' + else: + term_end = '' + + if term.as_ordered_factors()[0] == -1: + term = -1*term + sign = r'-' + if i == 0: # beginning + if sign == '+': + sign = '' + result += r'{:s} {:s}{:s} {:s} {:s}'.format(l.doprint(lhs), + first_term, sign, l.doprint(term), term_end) + else: + result += r'{:s}{:s} {:s} {:s}'.format(term_start, sign, + l.doprint(term), term_end) + term_count += 1 + result += end_term + return result diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/llvmjitcode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/llvmjitcode.py new file mode 100644 index 0000000000000000000000000000000000000000..0e657f3b854be62fb4b6b4be96f82579b718f6ca --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/llvmjitcode.py @@ -0,0 +1,490 @@ +''' +Use llvmlite to create executable functions from SymPy expressions + +This module requires llvmlite (https://github.com/numba/llvmlite). +''' + +import ctypes + +from sympy.external import import_module +from sympy.printing.printer import Printer +from sympy.core.singleton import S +from sympy.tensor.indexed import IndexedBase +from sympy.utilities.decorator import doctest_depends_on + +llvmlite = import_module('llvmlite') +if llvmlite: + ll = import_module('llvmlite.ir').ir + llvm = import_module('llvmlite.binding').binding + llvm.initialize() + llvm.initialize_native_target() + llvm.initialize_native_asmprinter() + + +__doctest_requires__ = {('llvm_callable'): ['llvmlite']} + + +class LLVMJitPrinter(Printer): + '''Convert expressions to LLVM IR''' + def __init__(self, module, builder, fn, *args, **kwargs): + self.func_arg_map = kwargs.pop("func_arg_map", {}) + if not llvmlite: + raise ImportError("llvmlite is required for LLVMJITPrinter") + super().__init__(*args, **kwargs) + self.fp_type = ll.DoubleType() + self.module = module + self.builder = builder + self.fn = fn + self.ext_fn = {} # keep track of wrappers to external functions + self.tmp_var = {} + + def _add_tmp_var(self, name, value): + self.tmp_var[name] = value + + def _print_Number(self, n): + return ll.Constant(self.fp_type, float(n)) + + def _print_Integer(self, expr): + return ll.Constant(self.fp_type, float(expr.p)) + + def _print_Symbol(self, s): + val = self.tmp_var.get(s) + if not val: + # look up parameter with name s + val = self.func_arg_map.get(s) + if not val: + raise LookupError("Symbol not found: %s" % s) + return val + + def _print_Pow(self, expr): + base0 = self._print(expr.base) + if expr.exp == S.NegativeOne: + return self.builder.fdiv(ll.Constant(self.fp_type, 1.0), base0) + if expr.exp == S.Half: + fn = self.ext_fn.get("sqrt") + if not fn: + fn_type = ll.FunctionType(self.fp_type, [self.fp_type]) + fn = ll.Function(self.module, fn_type, "sqrt") + self.ext_fn["sqrt"] = fn + return self.builder.call(fn, [base0], "sqrt") + if expr.exp == 2: + return self.builder.fmul(base0, base0) + + exp0 = self._print(expr.exp) + fn = self.ext_fn.get("pow") + if not fn: + fn_type = ll.FunctionType(self.fp_type, [self.fp_type, self.fp_type]) + fn = ll.Function(self.module, fn_type, "pow") + self.ext_fn["pow"] = fn + return self.builder.call(fn, [base0, exp0], "pow") + + def _print_Mul(self, expr): + nodes = [self._print(a) for a in expr.args] + e = nodes[0] + for node in nodes[1:]: + e = self.builder.fmul(e, node) + return e + + def _print_Add(self, expr): + nodes = [self._print(a) for a in expr.args] + e = nodes[0] + for node in nodes[1:]: + e = self.builder.fadd(e, node) + return e + + # TODO - assumes all called functions take one double precision argument. + # Should have a list of math library functions to validate this. + def _print_Function(self, expr): + name = expr.func.__name__ + e0 = self._print(expr.args[0]) + fn = self.ext_fn.get(name) + if not fn: + fn_type = ll.FunctionType(self.fp_type, [self.fp_type]) + fn = ll.Function(self.module, fn_type, name) + self.ext_fn[name] = fn + return self.builder.call(fn, [e0], name) + + def emptyPrinter(self, expr): + raise TypeError("Unsupported type for LLVM JIT conversion: %s" + % type(expr)) + + +# Used when parameters are passed by array. Often used in callbacks to +# handle a variable number of parameters. +class LLVMJitCallbackPrinter(LLVMJitPrinter): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def _print_Indexed(self, expr): + array, idx = self.func_arg_map[expr.base] + offset = int(expr.indices[0].evalf()) + array_ptr = self.builder.gep(array, [ll.Constant(ll.IntType(32), offset)]) + fp_array_ptr = self.builder.bitcast(array_ptr, ll.PointerType(self.fp_type)) + value = self.builder.load(fp_array_ptr) + return value + + def _print_Symbol(self, s): + val = self.tmp_var.get(s) + if val: + return val + + array, idx = self.func_arg_map.get(s, [None, 0]) + if not array: + raise LookupError("Symbol not found: %s" % s) + array_ptr = self.builder.gep(array, [ll.Constant(ll.IntType(32), idx)]) + fp_array_ptr = self.builder.bitcast(array_ptr, + ll.PointerType(self.fp_type)) + value = self.builder.load(fp_array_ptr) + return value + + +# ensure lifetime of the execution engine persists (else call to compiled +# function will seg fault) +exe_engines = [] + +# ensure names for generated functions are unique +link_names = set() +current_link_suffix = 0 + + +class LLVMJitCode: + def __init__(self, signature): + self.signature = signature + self.fp_type = ll.DoubleType() + self.module = ll.Module('mod1') + self.fn = None + self.llvm_arg_types = [] + self.llvm_ret_type = self.fp_type + self.param_dict = {} # map symbol name to LLVM function argument + self.link_name = '' + + def _from_ctype(self, ctype): + if ctype == ctypes.c_int: + return ll.IntType(32) + if ctype == ctypes.c_double: + return self.fp_type + if ctype == ctypes.POINTER(ctypes.c_double): + return ll.PointerType(self.fp_type) + if ctype == ctypes.c_void_p: + return ll.PointerType(ll.IntType(32)) + if ctype == ctypes.py_object: + return ll.PointerType(ll.IntType(32)) + + print("Unhandled ctype = %s" % str(ctype)) + + def _create_args(self, func_args): + """Create types for function arguments""" + self.llvm_ret_type = self._from_ctype(self.signature.ret_type) + self.llvm_arg_types = \ + [self._from_ctype(a) for a in self.signature.arg_ctypes] + + def _create_function_base(self): + """Create function with name and type signature""" + global current_link_suffix + default_link_name = 'jit_func' + current_link_suffix += 1 + self.link_name = default_link_name + str(current_link_suffix) + link_names.add(self.link_name) + + fn_type = ll.FunctionType(self.llvm_ret_type, self.llvm_arg_types) + self.fn = ll.Function(self.module, fn_type, name=self.link_name) + + def _create_param_dict(self, func_args): + """Mapping of symbolic values to function arguments""" + for i, a in enumerate(func_args): + self.fn.args[i].name = str(a) + self.param_dict[a] = self.fn.args[i] + + def _create_function(self, expr): + """Create function body and return LLVM IR""" + bb_entry = self.fn.append_basic_block('entry') + builder = ll.IRBuilder(bb_entry) + + lj = LLVMJitPrinter(self.module, builder, self.fn, + func_arg_map=self.param_dict) + + ret = self._convert_expr(lj, expr) + lj.builder.ret(self._wrap_return(lj, ret)) + + strmod = str(self.module) + return strmod + + def _wrap_return(self, lj, vals): + # Return a single double if there is one return value, + # else return a tuple of doubles. + + # Don't wrap return value in this case + if self.signature.ret_type == ctypes.c_double: + return vals[0] + + # Use this instead of a real PyObject* + void_ptr = ll.PointerType(ll.IntType(32)) + + # Create a wrapped double: PyObject* PyFloat_FromDouble(double v) + wrap_type = ll.FunctionType(void_ptr, [self.fp_type]) + wrap_fn = ll.Function(lj.module, wrap_type, "PyFloat_FromDouble") + + wrapped_vals = [lj.builder.call(wrap_fn, [v]) for v in vals] + if len(vals) == 1: + final_val = wrapped_vals[0] + else: + # Create a tuple: PyObject* PyTuple_Pack(Py_ssize_t n, ...) + + # This should be Py_ssize_t + tuple_arg_types = [ll.IntType(32)] + + tuple_arg_types.extend([void_ptr]*len(vals)) + tuple_type = ll.FunctionType(void_ptr, tuple_arg_types) + tuple_fn = ll.Function(lj.module, tuple_type, "PyTuple_Pack") + + tuple_args = [ll.Constant(ll.IntType(32), len(wrapped_vals))] + tuple_args.extend(wrapped_vals) + + final_val = lj.builder.call(tuple_fn, tuple_args) + + return final_val + + def _convert_expr(self, lj, expr): + try: + # Match CSE return data structure. + if len(expr) == 2: + tmp_exprs = expr[0] + final_exprs = expr[1] + if len(final_exprs) != 1 and self.signature.ret_type == ctypes.c_double: + raise NotImplementedError("Return of multiple expressions not supported for this callback") + for name, e in tmp_exprs: + val = lj._print(e) + lj._add_tmp_var(name, val) + except TypeError: + final_exprs = [expr] + + vals = [lj._print(e) for e in final_exprs] + + return vals + + def _compile_function(self, strmod): + llmod = llvm.parse_assembly(strmod) + + pmb = llvm.create_pass_manager_builder() + pmb.opt_level = 2 + pass_manager = llvm.create_module_pass_manager() + pmb.populate(pass_manager) + + pass_manager.run(llmod) + + target_machine = \ + llvm.Target.from_default_triple().create_target_machine() + exe_eng = llvm.create_mcjit_compiler(llmod, target_machine) + exe_eng.finalize_object() + exe_engines.append(exe_eng) + + if False: + print("Assembly") + print(target_machine.emit_assembly(llmod)) + + fptr = exe_eng.get_function_address(self.link_name) + + return fptr + + +class LLVMJitCodeCallback(LLVMJitCode): + def __init__(self, signature): + super().__init__(signature) + + def _create_param_dict(self, func_args): + for i, a in enumerate(func_args): + if isinstance(a, IndexedBase): + self.param_dict[a] = (self.fn.args[i], i) + self.fn.args[i].name = str(a) + else: + self.param_dict[a] = (self.fn.args[self.signature.input_arg], + i) + + def _create_function(self, expr): + """Create function body and return LLVM IR""" + bb_entry = self.fn.append_basic_block('entry') + builder = ll.IRBuilder(bb_entry) + + lj = LLVMJitCallbackPrinter(self.module, builder, self.fn, + func_arg_map=self.param_dict) + + ret = self._convert_expr(lj, expr) + + if self.signature.ret_arg: + output_fp_ptr = builder.bitcast(self.fn.args[self.signature.ret_arg], + ll.PointerType(self.fp_type)) + for i, val in enumerate(ret): + index = ll.Constant(ll.IntType(32), i) + output_array_ptr = builder.gep(output_fp_ptr, [index]) + builder.store(val, output_array_ptr) + builder.ret(ll.Constant(ll.IntType(32), 0)) # return success + else: + lj.builder.ret(self._wrap_return(lj, ret)) + + strmod = str(self.module) + return strmod + + +class CodeSignature: + def __init__(self, ret_type): + self.ret_type = ret_type + self.arg_ctypes = [] + + # Input argument array element index + self.input_arg = 0 + + # For the case output value is referenced through a parameter rather + # than the return value + self.ret_arg = None + + +def _llvm_jit_code(args, expr, signature, callback_type): + """Create a native code function from a SymPy expression""" + if callback_type is None: + jit = LLVMJitCode(signature) + else: + jit = LLVMJitCodeCallback(signature) + + jit._create_args(args) + jit._create_function_base() + jit._create_param_dict(args) + strmod = jit._create_function(expr) + if False: + print("LLVM IR") + print(strmod) + fptr = jit._compile_function(strmod) + return fptr + + +@doctest_depends_on(modules=('llvmlite', 'scipy')) +def llvm_callable(args, expr, callback_type=None): + '''Compile function from a SymPy expression + + Expressions are evaluated using double precision arithmetic. + Some single argument math functions (exp, sin, cos, etc.) are supported + in expressions. + + Parameters + ========== + + args : List of Symbol + Arguments to the generated function. Usually the free symbols in + the expression. Currently each one is assumed to convert to + a double precision scalar. + expr : Expr, or (Replacements, Expr) as returned from 'cse' + Expression to compile. + callback_type : string + Create function with signature appropriate to use as a callback. + Currently supported: + 'scipy.integrate' + 'scipy.integrate.test' + 'cubature' + + Returns + ======= + + Compiled function that can evaluate the expression. + + Examples + ======== + + >>> import sympy.printing.llvmjitcode as jit + >>> from sympy.abc import a + >>> e = a*a + a + 1 + >>> e1 = jit.llvm_callable([a], e) + >>> e.subs(a, 1.1) # Evaluate via substitution + 3.31000000000000 + >>> e1(1.1) # Evaluate using JIT-compiled code + 3.3100000000000005 + + + Callbacks for integration functions can be JIT compiled. + + >>> import sympy.printing.llvmjitcode as jit + >>> from sympy.abc import a + >>> from sympy import integrate + >>> from scipy.integrate import quad + >>> e = a*a + >>> e1 = jit.llvm_callable([a], e, callback_type='scipy.integrate') + >>> integrate(e, (a, 0.0, 2.0)) + 2.66666666666667 + >>> quad(e1, 0.0, 2.0)[0] + 2.66666666666667 + + The 'cubature' callback is for the Python wrapper around the + cubature package ( https://github.com/saullocastro/cubature ) + and ( http://ab-initio.mit.edu/wiki/index.php/Cubature ) + + There are two signatures for the SciPy integration callbacks. + The first ('scipy.integrate') is the function to be passed to the + integration routine, and will pass the signature checks. + The second ('scipy.integrate.test') is only useful for directly calling + the function using ctypes variables. It will not pass the signature checks + for scipy.integrate. + + The return value from the cse module can also be compiled. This + can improve the performance of the compiled function. If multiple + expressions are given to cse, the compiled function returns a tuple. + The 'cubature' callback handles multiple expressions (set `fdim` + to match in the integration call.) + + >>> import sympy.printing.llvmjitcode as jit + >>> from sympy import cse + >>> from sympy.abc import x,y + >>> e1 = x*x + y*y + >>> e2 = 4*(x*x + y*y) + 8.0 + >>> after_cse = cse([e1,e2]) + >>> after_cse + ([(x0, x**2), (x1, y**2)], [x0 + x1, 4*x0 + 4*x1 + 8.0]) + >>> j1 = jit.llvm_callable([x,y], after_cse) + >>> j1(1.0, 2.0) + (5.0, 28.0) + ''' + + if not llvmlite: + raise ImportError("llvmlite is required for llvmjitcode") + + signature = CodeSignature(ctypes.py_object) + + arg_ctypes = [] + if callback_type is None: + for _ in args: + arg_ctype = ctypes.c_double + arg_ctypes.append(arg_ctype) + elif callback_type in ('scipy.integrate', 'scipy.integrate.test'): + signature.ret_type = ctypes.c_double + arg_ctypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_double)] + arg_ctypes_formal = [ctypes.c_int, ctypes.c_double] + signature.input_arg = 1 + elif callback_type == 'cubature': + arg_ctypes = [ctypes.c_int, + ctypes.POINTER(ctypes.c_double), + ctypes.c_void_p, + ctypes.c_int, + ctypes.POINTER(ctypes.c_double) + ] + signature.ret_type = ctypes.c_int + signature.input_arg = 1 + signature.ret_arg = 4 + else: + raise ValueError("Unknown callback type: %s" % callback_type) + + signature.arg_ctypes = arg_ctypes + + fptr = _llvm_jit_code(args, expr, signature, callback_type) + + if callback_type and callback_type == 'scipy.integrate': + arg_ctypes = arg_ctypes_formal + + # PYFUNCTYPE holds the GIL which is needed to prevent a segfault when + # calling PyFloat_FromDouble on Python 3.10. Probably it is better to use + # ctypes.c_double when returning a float rather than using ctypes.py_object + # and returning a PyFloat from inside the jitted function (i.e. let ctypes + # handle the conversion from double to PyFloat). + if signature.ret_type == ctypes.py_object: + FUNCTYPE = ctypes.PYFUNCTYPE + else: + FUNCTYPE = ctypes.CFUNCTYPE + + cfunc = FUNCTYPE(signature.ret_type, *arg_ctypes)(fptr) + return cfunc diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/maple.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/maple.py new file mode 100644 index 0000000000000000000000000000000000000000..2c937cd262ab7f3ee5f32b3f4b5eb5633bc6bb3c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/maple.py @@ -0,0 +1,311 @@ +""" +Maple code printer + +The MapleCodePrinter converts single SymPy expressions into single +Maple expressions, using the functions defined in the Maple objects where possible. + + +FIXME: This module is still under actively developed. Some functions may be not completed. +""" + +from sympy.core import S +from sympy.core.numbers import Integer, IntegerConstant, equal_valued +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import precedence, PRECEDENCE + +import sympy + +_known_func_same_name = ( + 'sin', 'cos', 'tan', 'sec', 'csc', 'cot', 'sinh', 'cosh', 'tanh', 'sech', + 'csch', 'coth', 'exp', 'floor', 'factorial', 'bernoulli', 'euler', + 'fibonacci', 'gcd', 'lcm', 'conjugate', 'Ci', 'Chi', 'Ei', 'Li', 'Si', 'Shi', + 'erf', 'erfc', 'harmonic', 'LambertW', + 'sqrt', # For automatic rewrites +) + +known_functions = { + # SymPy -> Maple + 'Abs': 'abs', + 'log': 'ln', + 'asin': 'arcsin', + 'acos': 'arccos', + 'atan': 'arctan', + 'asec': 'arcsec', + 'acsc': 'arccsc', + 'acot': 'arccot', + 'asinh': 'arcsinh', + 'acosh': 'arccosh', + 'atanh': 'arctanh', + 'asech': 'arcsech', + 'acsch': 'arccsch', + 'acoth': 'arccoth', + 'ceiling': 'ceil', + 'Max' : 'max', + 'Min' : 'min', + + 'factorial2': 'doublefactorial', + 'RisingFactorial': 'pochhammer', + 'besseli': 'BesselI', + 'besselj': 'BesselJ', + 'besselk': 'BesselK', + 'bessely': 'BesselY', + 'hankelh1': 'HankelH1', + 'hankelh2': 'HankelH2', + 'airyai': 'AiryAi', + 'airybi': 'AiryBi', + 'appellf1': 'AppellF1', + 'fresnelc': 'FresnelC', + 'fresnels': 'FresnelS', + 'lerchphi' : 'LerchPhi', +} + +for _func in _known_func_same_name: + known_functions[_func] = _func + +number_symbols = { + # SymPy -> Maple + S.Pi: 'Pi', + S.Exp1: 'exp(1)', + S.Catalan: 'Catalan', + S.EulerGamma: 'gamma', + S.GoldenRatio: '(1/2 + (1/2)*sqrt(5))' +} + +spec_relational_ops = { + # SymPy -> Maple + '==': '=', + '!=': '<>' +} + +not_supported_symbol = [ + S.ComplexInfinity +] + +class MapleCodePrinter(CodePrinter): + """ + Printer which converts a SymPy expression into a maple code. + """ + printmethod = "_maple" + language = "maple" + + _operators = { + 'and': 'and', + 'or': 'or', + 'not': 'not ', + } + + _default_settings = dict(CodePrinter._default_settings, **{ + 'inline': True, + 'allow_unknown_functions': True, + }) + + def __init__(self, settings=None): + if settings is None: + settings = {} + super().__init__(settings) + self.known_functions = dict(known_functions) + userfuncs = settings.get('user_functions', {}) + self.known_functions.update(userfuncs) + + def _get_statement(self, codestring): + return "%s;" % codestring + + def _get_comment(self, text): + return "# {}".format(text) + + def _declare_number_const(self, name, value): + return "{} := {};".format(name, + value.evalf(self._settings['precision'])) + + def _format_code(self, lines): + return lines + + def _print_tuple(self, expr): + return self._print(list(expr)) + + def _print_Tuple(self, expr): + return self._print(list(expr)) + + def _print_Assignment(self, expr): + lhs = self._print(expr.lhs) + rhs = self._print(expr.rhs) + return "{lhs} := {rhs}".format(lhs=lhs, rhs=rhs) + + def _print_Pow(self, expr, **kwargs): + PREC = precedence(expr) + if equal_valued(expr.exp, -1): + return '1/%s' % (self.parenthesize(expr.base, PREC)) + elif equal_valued(expr.exp, 0.5): + return 'sqrt(%s)' % self._print(expr.base) + elif equal_valued(expr.exp, -0.5): + return '1/sqrt(%s)' % self._print(expr.base) + else: + return '{base}^{exp}'.format( + base=self.parenthesize(expr.base, PREC), + exp=self.parenthesize(expr.exp, PREC)) + + def _print_Piecewise(self, expr): + if (expr.args[-1].cond is not True) and (expr.args[-1].cond != S.BooleanTrue): + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + _coup_list = [ + ("{c}, {e}".format(c=self._print(c), + e=self._print(e)) if c is not True and c is not S.BooleanTrue else "{e}".format( + e=self._print(e))) + for e, c in expr.args] + _inbrace = ', '.join(_coup_list) + return 'piecewise({_inbrace})'.format(_inbrace=_inbrace) + + def _print_Rational(self, expr): + p, q = int(expr.p), int(expr.q) + return "{p}/{q}".format(p=str(p), q=str(q)) + + def _print_Relational(self, expr): + PREC=precedence(expr) + lhs_code = self.parenthesize(expr.lhs, PREC) + rhs_code = self.parenthesize(expr.rhs, PREC) + op = expr.rel_op + if op in spec_relational_ops: + op = spec_relational_ops[op] + return "{lhs} {rel_op} {rhs}".format(lhs=lhs_code, rel_op=op, rhs=rhs_code) + + def _print_NumberSymbol(self, expr): + return number_symbols[expr] + + def _print_NegativeInfinity(self, expr): + return '-infinity' + + def _print_Infinity(self, expr): + return 'infinity' + + def _print_BooleanTrue(self, expr): + return "true" + + def _print_BooleanFalse(self, expr): + return "false" + + def _print_bool(self, expr): + return 'true' if expr else 'false' + + def _print_NaN(self, expr): + return 'undefined' + + def _get_matrix(self, expr, sparse=False): + if S.Zero in expr.shape: + _strM = 'Matrix([], storage = {storage})'.format( + storage='sparse' if sparse else 'rectangular') + else: + _strM = 'Matrix({list}, storage = {storage})'.format( + list=self._print(expr.tolist()), + storage='sparse' if sparse else 'rectangular') + return _strM + + def _print_MatrixElement(self, expr): + return "{parent}[{i_maple}, {j_maple}]".format( + parent=self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True), + i_maple=self._print(expr.i + 1), + j_maple=self._print(expr.j + 1)) + + def _print_MatrixBase(self, expr): + return self._get_matrix(expr, sparse=False) + + def _print_SparseRepMatrix(self, expr): + return self._get_matrix(expr, sparse=True) + + def _print_Identity(self, expr): + if isinstance(expr.rows, (Integer, IntegerConstant)): + return self._print(sympy.SparseMatrix(expr)) + else: + return "Matrix({var_size}, shape = identity)".format(var_size=self._print(expr.rows)) + + def _print_MatMul(self, expr): + PREC=precedence(expr) + _fact_list = list(expr.args) + _const = None + if not isinstance(_fact_list[0], (sympy.MatrixBase, sympy.MatrixExpr, + sympy.MatrixSlice, sympy.MatrixSymbol)): + _const, _fact_list = _fact_list[0], _fact_list[1:] + + if _const is None or _const == 1: + return '.'.join(self.parenthesize(_m, PREC) for _m in _fact_list) + else: + return '{c}*{m}'.format(c=_const, m='.'.join(self.parenthesize(_m, PREC) for _m in _fact_list)) + + def _print_MatPow(self, expr): + # This function requires LinearAlgebra Function in Maple + return 'MatrixPower({A}, {n})'.format(A=self._print(expr.base), n=self._print(expr.exp)) + + def _print_HadamardProduct(self, expr): + PREC = precedence(expr) + _fact_list = list(expr.args) + return '*'.join(self.parenthesize(_m, PREC) for _m in _fact_list) + + def _print_Derivative(self, expr): + _f, (_var, _order) = expr.args + + if _order != 1: + _second_arg = '{var}${order}'.format(var=self._print(_var), + order=self._print(_order)) + else: + _second_arg = '{var}'.format(var=self._print(_var)) + return 'diff({func_expr}, {sec_arg})'.format(func_expr=self._print(_f), sec_arg=_second_arg) + + +def maple_code(expr, assign_to=None, **settings): + r"""Converts ``expr`` to a string of Maple code. + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used as the name of the variable to which + the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for + expressions that generate multi-line statements. + precision : integer, optional + The precision for numbers such as pi [default=16]. + user_functions : dict, optional + A dictionary where keys are ``FunctionClass`` instances and values are + their string representations. Alternatively, the dictionary value can + be a list of tuples i.e. [(argument_test, cfunction_string)]. See + below for examples. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + inline: bool, optional + If True, we try to create single-statement code instead of multiple + statements. [default=True]. + + """ + return MapleCodePrinter(settings).doprint(expr, assign_to) + + +def print_maple_code(expr, **settings): + """Prints the Maple representation of the given expression. + + See :func:`maple_code` for the meaning of the optional arguments. + + Examples + ======== + + >>> from sympy import print_maple_code, symbols + >>> x, y = symbols('x y') + >>> print_maple_code(x, assign_to=y) + y := x + """ + print(maple_code(expr, **settings)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/mathematica.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/mathematica.py new file mode 100644 index 0000000000000000000000000000000000000000..064925ec1a9a477d7509110c57311239bac9fcaf --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/mathematica.py @@ -0,0 +1,353 @@ +""" +Mathematica code printer +""" + +from __future__ import annotations +from typing import Any + +from sympy.core import Basic, Expr, Float +from sympy.core.sorting import default_sort_key + +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import precedence + +# Used in MCodePrinter._print_Function(self) +known_functions = { + "exp": [(lambda x: True, "Exp")], + "log": [(lambda x: True, "Log")], + "sin": [(lambda x: True, "Sin")], + "cos": [(lambda x: True, "Cos")], + "tan": [(lambda x: True, "Tan")], + "cot": [(lambda x: True, "Cot")], + "sec": [(lambda x: True, "Sec")], + "csc": [(lambda x: True, "Csc")], + "asin": [(lambda x: True, "ArcSin")], + "acos": [(lambda x: True, "ArcCos")], + "atan": [(lambda x: True, "ArcTan")], + "acot": [(lambda x: True, "ArcCot")], + "asec": [(lambda x: True, "ArcSec")], + "acsc": [(lambda x: True, "ArcCsc")], + "sinh": [(lambda x: True, "Sinh")], + "cosh": [(lambda x: True, "Cosh")], + "tanh": [(lambda x: True, "Tanh")], + "coth": [(lambda x: True, "Coth")], + "sech": [(lambda x: True, "Sech")], + "csch": [(lambda x: True, "Csch")], + "asinh": [(lambda x: True, "ArcSinh")], + "acosh": [(lambda x: True, "ArcCosh")], + "atanh": [(lambda x: True, "ArcTanh")], + "acoth": [(lambda x: True, "ArcCoth")], + "asech": [(lambda x: True, "ArcSech")], + "acsch": [(lambda x: True, "ArcCsch")], + "sinc": [(lambda x: True, "Sinc")], + "conjugate": [(lambda x: True, "Conjugate")], + "Max": [(lambda *x: True, "Max")], + "Min": [(lambda *x: True, "Min")], + "erf": [(lambda x: True, "Erf")], + "erf2": [(lambda *x: True, "Erf")], + "erfc": [(lambda x: True, "Erfc")], + "erfi": [(lambda x: True, "Erfi")], + "erfinv": [(lambda x: True, "InverseErf")], + "erfcinv": [(lambda x: True, "InverseErfc")], + "erf2inv": [(lambda *x: True, "InverseErf")], + "expint": [(lambda *x: True, "ExpIntegralE")], + "Ei": [(lambda x: True, "ExpIntegralEi")], + "fresnelc": [(lambda x: True, "FresnelC")], + "fresnels": [(lambda x: True, "FresnelS")], + "gamma": [(lambda x: True, "Gamma")], + "uppergamma": [(lambda *x: True, "Gamma")], + "polygamma": [(lambda *x: True, "PolyGamma")], + "loggamma": [(lambda x: True, "LogGamma")], + "beta": [(lambda *x: True, "Beta")], + "Ci": [(lambda x: True, "CosIntegral")], + "Si": [(lambda x: True, "SinIntegral")], + "Chi": [(lambda x: True, "CoshIntegral")], + "Shi": [(lambda x: True, "SinhIntegral")], + "li": [(lambda x: True, "LogIntegral")], + "factorial": [(lambda x: True, "Factorial")], + "factorial2": [(lambda x: True, "Factorial2")], + "subfactorial": [(lambda x: True, "Subfactorial")], + "catalan": [(lambda x: True, "CatalanNumber")], + "harmonic": [(lambda *x: True, "HarmonicNumber")], + "lucas": [(lambda x: True, "LucasL")], + "RisingFactorial": [(lambda *x: True, "Pochhammer")], + "FallingFactorial": [(lambda *x: True, "FactorialPower")], + "laguerre": [(lambda *x: True, "LaguerreL")], + "assoc_laguerre": [(lambda *x: True, "LaguerreL")], + "hermite": [(lambda *x: True, "HermiteH")], + "jacobi": [(lambda *x: True, "JacobiP")], + "gegenbauer": [(lambda *x: True, "GegenbauerC")], + "chebyshevt": [(lambda *x: True, "ChebyshevT")], + "chebyshevu": [(lambda *x: True, "ChebyshevU")], + "legendre": [(lambda *x: True, "LegendreP")], + "assoc_legendre": [(lambda *x: True, "LegendreP")], + "mathieuc": [(lambda *x: True, "MathieuC")], + "mathieus": [(lambda *x: True, "MathieuS")], + "mathieucprime": [(lambda *x: True, "MathieuCPrime")], + "mathieusprime": [(lambda *x: True, "MathieuSPrime")], + "stieltjes": [(lambda x: True, "StieltjesGamma")], + "elliptic_e": [(lambda *x: True, "EllipticE")], + "elliptic_f": [(lambda *x: True, "EllipticE")], + "elliptic_k": [(lambda x: True, "EllipticK")], + "elliptic_pi": [(lambda *x: True, "EllipticPi")], + "zeta": [(lambda *x: True, "Zeta")], + "dirichlet_eta": [(lambda x: True, "DirichletEta")], + "riemann_xi": [(lambda x: True, "RiemannXi")], + "besseli": [(lambda *x: True, "BesselI")], + "besselj": [(lambda *x: True, "BesselJ")], + "besselk": [(lambda *x: True, "BesselK")], + "bessely": [(lambda *x: True, "BesselY")], + "hankel1": [(lambda *x: True, "HankelH1")], + "hankel2": [(lambda *x: True, "HankelH2")], + "airyai": [(lambda x: True, "AiryAi")], + "airybi": [(lambda x: True, "AiryBi")], + "airyaiprime": [(lambda x: True, "AiryAiPrime")], + "airybiprime": [(lambda x: True, "AiryBiPrime")], + "polylog": [(lambda *x: True, "PolyLog")], + "lerchphi": [(lambda *x: True, "LerchPhi")], + "gcd": [(lambda *x: True, "GCD")], + "lcm": [(lambda *x: True, "LCM")], + "jn": [(lambda *x: True, "SphericalBesselJ")], + "yn": [(lambda *x: True, "SphericalBesselY")], + "hyper": [(lambda *x: True, "HypergeometricPFQ")], + "meijerg": [(lambda *x: True, "MeijerG")], + "appellf1": [(lambda *x: True, "AppellF1")], + "DiracDelta": [(lambda x: True, "DiracDelta")], + "Heaviside": [(lambda x: True, "HeavisideTheta")], + "KroneckerDelta": [(lambda *x: True, "KroneckerDelta")], + "sqrt": [(lambda x: True, "Sqrt")], # For automatic rewrites +} + + +class MCodePrinter(CodePrinter): + """A printer to convert Python expressions to + strings of the Wolfram's Mathematica code + """ + printmethod = "_mcode" + language = "Wolfram Language" + + _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{ + 'precision': 15, + 'user_functions': {}, + }) + + _number_symbols: set[tuple[Expr, Float]] = set() + _not_supported: set[Basic] = set() + + def __init__(self, settings={}): + """Register function mappings supplied by user""" + CodePrinter.__init__(self, settings) + self.known_functions = dict(known_functions) + userfuncs = settings.get('user_functions', {}).copy() + for k, v in userfuncs.items(): + if not isinstance(v, list): + userfuncs[k] = [(lambda *x: True, v)] + self.known_functions.update(userfuncs) + + def _format_code(self, lines): + return lines + + def _print_Pow(self, expr): + PREC = precedence(expr) + return '%s^%s' % (self.parenthesize(expr.base, PREC), + self.parenthesize(expr.exp, PREC)) + + def _print_Mul(self, expr): + PREC = precedence(expr) + c, nc = expr.args_cnc() + res = super()._print_Mul(expr.func(*c)) + if nc: + res += '*' + res += '**'.join(self.parenthesize(a, PREC) for a in nc) + return res + + def _print_Relational(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + op = expr.rel_op + return "{} {} {}".format(lhs_code, op, rhs_code) + + # Primitive numbers + def _print_Zero(self, expr): + return '0' + + def _print_One(self, expr): + return '1' + + def _print_NegativeOne(self, expr): + return '-1' + + def _print_Half(self, expr): + return '1/2' + + def _print_ImaginaryUnit(self, expr): + return 'I' + + + # Infinity and invalid numbers + def _print_Infinity(self, expr): + return 'Infinity' + + def _print_NegativeInfinity(self, expr): + return '-Infinity' + + def _print_ComplexInfinity(self, expr): + return 'ComplexInfinity' + + def _print_NaN(self, expr): + return 'Indeterminate' + + + # Mathematical constants + def _print_Exp1(self, expr): + return 'E' + + def _print_Pi(self, expr): + return 'Pi' + + def _print_GoldenRatio(self, expr): + return 'GoldenRatio' + + def _print_TribonacciConstant(self, expr): + expanded = expr.expand(func=True) + PREC = precedence(expr) + return self.parenthesize(expanded, PREC) + + def _print_EulerGamma(self, expr): + return 'EulerGamma' + + def _print_Catalan(self, expr): + return 'Catalan' + + + def _print_list(self, expr): + return '{' + ', '.join(self.doprint(a) for a in expr) + '}' + _print_tuple = _print_list + _print_Tuple = _print_list + + def _print_ImmutableDenseMatrix(self, expr): + return self.doprint(expr.tolist()) + + def _print_ImmutableSparseMatrix(self, expr): + + def print_rule(pos, val): + return '{} -> {}'.format( + self.doprint((pos[0]+1, pos[1]+1)), self.doprint(val)) + + def print_data(): + items = sorted(expr.todok().items(), key=default_sort_key) + return '{' + \ + ', '.join(print_rule(k, v) for k, v in items) + \ + '}' + + def print_dims(): + return self.doprint(expr.shape) + + return 'SparseArray[{}, {}]'.format(print_data(), print_dims()) + + def _print_ImmutableDenseNDimArray(self, expr): + return self.doprint(expr.tolist()) + + def _print_ImmutableSparseNDimArray(self, expr): + def print_string_list(string_list): + return '{' + ', '.join(a for a in string_list) + '}' + + def to_mathematica_index(*args): + """Helper function to change Python style indexing to + Pathematica indexing. + + Python indexing (0, 1 ... n-1) + -> Mathematica indexing (1, 2 ... n) + """ + return tuple(i + 1 for i in args) + + def print_rule(pos, val): + """Helper function to print a rule of Mathematica""" + return '{} -> {}'.format(self.doprint(pos), self.doprint(val)) + + def print_data(): + """Helper function to print data part of Mathematica + sparse array. + + It uses the fourth notation ``SparseArray[data,{d1,d2,...}]`` + from + https://reference.wolfram.com/language/ref/SparseArray.html + + ``data`` must be formatted with rule. + """ + return print_string_list( + [print_rule( + to_mathematica_index(*(expr._get_tuple_index(key))), + value) + for key, value in sorted(expr._sparse_array.items())] + ) + + def print_dims(): + """Helper function to print dimensions part of Mathematica + sparse array. + + It uses the fourth notation ``SparseArray[data,{d1,d2,...}]`` + from + https://reference.wolfram.com/language/ref/SparseArray.html + """ + return self.doprint(expr.shape) + + return 'SparseArray[{}, {}]'.format(print_data(), print_dims()) + + def _print_Function(self, expr): + if expr.func.__name__ in self.known_functions: + cond_mfunc = self.known_functions[expr.func.__name__] + for cond, mfunc in cond_mfunc: + if cond(*expr.args): + return "%s[%s]" % (mfunc, self.stringify(expr.args, ", ")) + elif expr.func.__name__ in self._rewriteable_functions: + # Simple rewrite to supported function possible + target_f, required_fs = self._rewriteable_functions[expr.func.__name__] + if self._can_print(target_f) and all(self._can_print(f) for f in required_fs): + return self._print(expr.rewrite(target_f)) + return expr.func.__name__ + "[%s]" % self.stringify(expr.args, ", ") + + _print_MinMaxBase = _print_Function + + def _print_LambertW(self, expr): + if len(expr.args) == 1: + return "ProductLog[{}]".format(self._print(expr.args[0])) + return "ProductLog[{}, {}]".format( + self._print(expr.args[1]), self._print(expr.args[0])) + + def _print_atan2(self, expr): + return "ArcTan[{}, {}]".format( + self._print(expr.args[1]), self._print(expr.args[0])) + + def _print_Integral(self, expr): + if len(expr.variables) == 1 and not expr.limits[0][1:]: + args = [expr.args[0], expr.variables[0]] + else: + args = expr.args + return "Hold[Integrate[" + ', '.join(self.doprint(a) for a in args) + "]]" + + def _print_Sum(self, expr): + return "Hold[Sum[" + ', '.join(self.doprint(a) for a in expr.args) + "]]" + + def _print_Derivative(self, expr): + dexpr = expr.expr + dvars = [i[0] if i[1] == 1 else i for i in expr.variable_count] + return "Hold[D[" + ', '.join(self.doprint(a) for a in [dexpr] + dvars) + "]]" + + + def _get_comment(self, text): + return "(* {} *)".format(text) + + +def mathematica_code(expr, **settings): + r"""Converts an expr to a string of the Wolfram Mathematica code + + Examples + ======== + + >>> from sympy import mathematica_code as mcode, symbols, sin + >>> x = symbols('x') + >>> mcode(sin(x).series(x).removeO()) + '(1/120)*x^5 - 1/6*x^3 + x' + """ + return MCodePrinter(settings).doprint(expr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/mathml.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/mathml.py new file mode 100644 index 0000000000000000000000000000000000000000..4dff74cd64b17036d3ff2a766253c9af850f088d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/mathml.py @@ -0,0 +1,2157 @@ +""" +A MathML printer. +""" + +from __future__ import annotations +from typing import Any + +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import sympify +from sympy.printing.conventions import split_super_sub, requires_partial +from sympy.printing.precedence import \ + precedence_traditional, PRECEDENCE, PRECEDENCE_TRADITIONAL +from sympy.printing.pretty.pretty_symbology import greek_unicode +from sympy.printing.printer import Printer, print_function + +from mpmath.libmp import prec_to_dps, repr_dps, to_str as mlib_to_str + + +class MathMLPrinterBase(Printer): + """Contains common code required for MathMLContentPrinter and + MathMLPresentationPrinter. + """ + + _default_settings: dict[str, Any] = { + "order": None, + "encoding": "utf-8", + "fold_frac_powers": False, + "fold_func_brackets": False, + "fold_short_frac": None, + "inv_trig_style": "abbreviated", + "ln_notation": False, + "long_frac_ratio": None, + "mat_delim": "[", + "mat_symbol_style": "plain", + "mul_symbol": None, + "root_notation": True, + "symbol_names": {}, + "mul_symbol_mathml_numbers": '·', + "disable_split_super_sub": False, + } + + def __init__(self, settings=None): + Printer.__init__(self, settings) + from xml.dom.minidom import Document, Text + + self.dom = Document() + + # Workaround to allow strings to remain unescaped + # Based on + # https://stackoverflow.com/questions/38015864/python-xml-dom-minidom-\ + # please-dont-escape-my-strings/38041194 + class RawText(Text): + def writexml(self, writer, indent='', addindent='', newl=''): + if self.data: + writer.write('{}{}{}'.format(indent, self.data, newl)) + + def createRawTextNode(data): + r = RawText() + r.data = data + r.ownerDocument = self.dom + return r + + self.dom.createTextNode = createRawTextNode + + def doprint(self, expr): + """ + Prints the expression as MathML. + """ + mathML = Printer._print(self, expr) + unistr = mathML.toxml() + xmlbstr = unistr.encode('ascii', 'xmlcharrefreplace') + res = xmlbstr.decode() + return res + + def _split_super_sub(self, name): + if self._settings["disable_split_super_sub"]: + return (name, [], []) + else: + return split_super_sub(name) + + +class MathMLContentPrinter(MathMLPrinterBase): + """Prints an expression to the Content MathML markup language. + + References: https://www.w3.org/TR/MathML2/chapter4.html + """ + printmethod = "_mathml_content" + + def mathml_tag(self, e): + """Returns the MathML tag for an expression.""" + translate = { + 'Add': 'plus', + 'Mul': 'times', + 'Derivative': 'diff', + 'Number': 'cn', + 'int': 'cn', + 'Pow': 'power', + 'Max': 'max', + 'Min': 'min', + 'Abs': 'abs', + 'And': 'and', + 'Or': 'or', + 'Xor': 'xor', + 'Not': 'not', + 'Implies': 'implies', + 'Symbol': 'ci', + 'MatrixSymbol': 'ci', + 'RandomSymbol': 'ci', + 'Integral': 'int', + 'Sum': 'sum', + 'sin': 'sin', + 'cos': 'cos', + 'tan': 'tan', + 'cot': 'cot', + 'csc': 'csc', + 'sec': 'sec', + 'sinh': 'sinh', + 'cosh': 'cosh', + 'tanh': 'tanh', + 'coth': 'coth', + 'csch': 'csch', + 'sech': 'sech', + 'asin': 'arcsin', + 'asinh': 'arcsinh', + 'acos': 'arccos', + 'acosh': 'arccosh', + 'atan': 'arctan', + 'atanh': 'arctanh', + 'atan2': 'arctan', + 'acot': 'arccot', + 'acoth': 'arccoth', + 'asec': 'arcsec', + 'asech': 'arcsech', + 'acsc': 'arccsc', + 'acsch': 'arccsch', + 'log': 'ln', + 'Equality': 'eq', + 'Unequality': 'neq', + 'GreaterThan': 'geq', + 'LessThan': 'leq', + 'StrictGreaterThan': 'gt', + 'StrictLessThan': 'lt', + 'Union': 'union', + 'Intersection': 'intersect', + } + + for cls in e.__class__.__mro__: + n = cls.__name__ + if n in translate: + return translate[n] + # Not found in the MRO set + n = e.__class__.__name__ + return n.lower() + + def _print_Mul(self, expr): + + if expr.could_extract_minus_sign(): + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('minus')) + x.appendChild(self._print_Mul(-expr)) + return x + + from sympy.simplify import fraction + numer, denom = fraction(expr) + + if denom is not S.One: + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('divide')) + x.appendChild(self._print(numer)) + x.appendChild(self._print(denom)) + return x + + coeff, terms = expr.as_coeff_mul() + if coeff is S.One and len(terms) == 1: + # XXX since the negative coefficient has been handled, I don't + # think a coeff of 1 can remain + return self._print(terms[0]) + + if self.order != 'old': + terms = Mul._from_args(terms).as_ordered_factors() + + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('times')) + if coeff != 1: + x.appendChild(self._print(coeff)) + for term in terms: + x.appendChild(self._print(term)) + return x + + def _print_Add(self, expr, order=None): + args = self._as_ordered_terms(expr, order=order) + lastProcessed = self._print(args[0]) + plusNodes = [] + for arg in args[1:]: + if arg.could_extract_minus_sign(): + # use minus + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('minus')) + x.appendChild(lastProcessed) + x.appendChild(self._print(-arg)) + # invert expression since this is now minused + lastProcessed = x + if arg == args[-1]: + plusNodes.append(lastProcessed) + else: + plusNodes.append(lastProcessed) + lastProcessed = self._print(arg) + if arg == args[-1]: + plusNodes.append(self._print(arg)) + if len(plusNodes) == 1: + return lastProcessed + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('plus')) + while plusNodes: + x.appendChild(plusNodes.pop(0)) + return x + + def _print_Piecewise(self, expr): + if expr.args[-1].cond != True: + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + root = self.dom.createElement('piecewise') + for i, (e, c) in enumerate(expr.args): + if i == len(expr.args) - 1 and c == True: + piece = self.dom.createElement('otherwise') + piece.appendChild(self._print(e)) + else: + piece = self.dom.createElement('piece') + piece.appendChild(self._print(e)) + piece.appendChild(self._print(c)) + root.appendChild(piece) + return root + + def _print_MatrixBase(self, m): + x = self.dom.createElement('matrix') + for i in range(m.rows): + x_r = self.dom.createElement('matrixrow') + for j in range(m.cols): + x_r.appendChild(self._print(m[i, j])) + x.appendChild(x_r) + return x + + def _print_Rational(self, e): + if e.q == 1: + # don't divide + x = self.dom.createElement('cn') + x.appendChild(self.dom.createTextNode(str(e.p))) + return x + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('divide')) + # numerator + xnum = self.dom.createElement('cn') + xnum.appendChild(self.dom.createTextNode(str(e.p))) + # denominator + xdenom = self.dom.createElement('cn') + xdenom.appendChild(self.dom.createTextNode(str(e.q))) + x.appendChild(xnum) + x.appendChild(xdenom) + return x + + def _print_Limit(self, e): + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement(self.mathml_tag(e))) + + x_1 = self.dom.createElement('bvar') + x_2 = self.dom.createElement('lowlimit') + x_1.appendChild(self._print(e.args[1])) + x_2.appendChild(self._print(e.args[2])) + + x.appendChild(x_1) + x.appendChild(x_2) + x.appendChild(self._print(e.args[0])) + return x + + def _print_ImaginaryUnit(self, e): + return self.dom.createElement('imaginaryi') + + def _print_EulerGamma(self, e): + return self.dom.createElement('eulergamma') + + def _print_GoldenRatio(self, e): + """We use unicode #x3c6 for Greek letter phi as defined here + https://www.w3.org/2003/entities/2007doc/isogrk1.html""" + x = self.dom.createElement('cn') + x.appendChild(self.dom.createTextNode("\N{GREEK SMALL LETTER PHI}")) + return x + + def _print_Exp1(self, e): + return self.dom.createElement('exponentiale') + + def _print_Pi(self, e): + return self.dom.createElement('pi') + + def _print_Infinity(self, e): + return self.dom.createElement('infinity') + + def _print_NaN(self, e): + return self.dom.createElement('notanumber') + + def _print_EmptySet(self, e): + return self.dom.createElement('emptyset') + + def _print_BooleanTrue(self, e): + return self.dom.createElement('true') + + def _print_BooleanFalse(self, e): + return self.dom.createElement('false') + + def _print_NegativeInfinity(self, e): + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('minus')) + x.appendChild(self.dom.createElement('infinity')) + return x + + def _print_Integral(self, e): + def lime_recur(limits): + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement(self.mathml_tag(e))) + bvar_elem = self.dom.createElement('bvar') + bvar_elem.appendChild(self._print(limits[0][0])) + x.appendChild(bvar_elem) + + if len(limits[0]) == 3: + low_elem = self.dom.createElement('lowlimit') + low_elem.appendChild(self._print(limits[0][1])) + x.appendChild(low_elem) + up_elem = self.dom.createElement('uplimit') + up_elem.appendChild(self._print(limits[0][2])) + x.appendChild(up_elem) + if len(limits[0]) == 2: + up_elem = self.dom.createElement('uplimit') + up_elem.appendChild(self._print(limits[0][1])) + x.appendChild(up_elem) + if len(limits) == 1: + x.appendChild(self._print(e.function)) + else: + x.appendChild(lime_recur(limits[1:])) + return x + + limits = list(e.limits) + limits.reverse() + return lime_recur(limits) + + def _print_Sum(self, e): + # Printer can be shared because Sum and Integral have the + # same internal representation. + return self._print_Integral(e) + + def _print_Symbol(self, sym): + ci = self.dom.createElement(self.mathml_tag(sym)) + + def join(items): + if len(items) > 1: + mrow = self.dom.createElement('mml:mrow') + for i, item in enumerate(items): + if i > 0: + mo = self.dom.createElement('mml:mo') + mo.appendChild(self.dom.createTextNode(" ")) + mrow.appendChild(mo) + mi = self.dom.createElement('mml:mi') + mi.appendChild(self.dom.createTextNode(item)) + mrow.appendChild(mi) + return mrow + else: + mi = self.dom.createElement('mml:mi') + mi.appendChild(self.dom.createTextNode(items[0])) + return mi + + # translate name, supers and subs to unicode characters + def translate(s): + if s in greek_unicode: + return greek_unicode.get(s) + else: + return s + + name, supers, subs = self._split_super_sub(sym.name) + name = translate(name) + supers = [translate(sup) for sup in supers] + subs = [translate(sub) for sub in subs] + + mname = self.dom.createElement('mml:mi') + mname.appendChild(self.dom.createTextNode(name)) + if not supers: + if not subs: + ci.appendChild(self.dom.createTextNode(name)) + else: + msub = self.dom.createElement('mml:msub') + msub.appendChild(mname) + msub.appendChild(join(subs)) + ci.appendChild(msub) + else: + if not subs: + msup = self.dom.createElement('mml:msup') + msup.appendChild(mname) + msup.appendChild(join(supers)) + ci.appendChild(msup) + else: + msubsup = self.dom.createElement('mml:msubsup') + msubsup.appendChild(mname) + msubsup.appendChild(join(subs)) + msubsup.appendChild(join(supers)) + ci.appendChild(msubsup) + return ci + + _print_MatrixSymbol = _print_Symbol + _print_RandomSymbol = _print_Symbol + + def _print_Pow(self, e): + # Here we use root instead of power if the exponent is the reciprocal + # of an integer + if (self._settings['root_notation'] and e.exp.is_Rational + and e.exp.p == 1): + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('root')) + if e.exp.q != 2: + xmldeg = self.dom.createElement('degree') + xmlcn = self.dom.createElement('cn') + xmlcn.appendChild(self.dom.createTextNode(str(e.exp.q))) + xmldeg.appendChild(xmlcn) + x.appendChild(xmldeg) + x.appendChild(self._print(e.base)) + return x + + x = self.dom.createElement('apply') + x_1 = self.dom.createElement(self.mathml_tag(e)) + x.appendChild(x_1) + x.appendChild(self._print(e.base)) + x.appendChild(self._print(e.exp)) + return x + + def _print_Number(self, e): + x = self.dom.createElement(self.mathml_tag(e)) + x.appendChild(self.dom.createTextNode(str(e))) + return x + + def _print_Float(self, e): + x = self.dom.createElement(self.mathml_tag(e)) + repr_e = mlib_to_str(e._mpf_, repr_dps(e._prec)) + x.appendChild(self.dom.createTextNode(repr_e)) + return x + + def _print_Derivative(self, e): + x = self.dom.createElement('apply') + diff_symbol = self.mathml_tag(e) + if requires_partial(e.expr): + diff_symbol = 'partialdiff' + x.appendChild(self.dom.createElement(diff_symbol)) + x_1 = self.dom.createElement('bvar') + + for sym, times in reversed(e.variable_count): + x_1.appendChild(self._print(sym)) + if times > 1: + degree = self.dom.createElement('degree') + degree.appendChild(self._print(sympify(times))) + x_1.appendChild(degree) + + x.appendChild(x_1) + x.appendChild(self._print(e.expr)) + return x + + def _print_Function(self, e): + x = self.dom.createElement("apply") + x.appendChild(self.dom.createElement(self.mathml_tag(e))) + for arg in e.args: + x.appendChild(self._print(arg)) + return x + + def _print_Basic(self, e): + x = self.dom.createElement(self.mathml_tag(e)) + for arg in e.args: + x.appendChild(self._print(arg)) + return x + + def _print_AssocOp(self, e): + x = self.dom.createElement('apply') + x_1 = self.dom.createElement(self.mathml_tag(e)) + x.appendChild(x_1) + for arg in e.args: + x.appendChild(self._print(arg)) + return x + + def _print_Relational(self, e): + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement(self.mathml_tag(e))) + x.appendChild(self._print(e.lhs)) + x.appendChild(self._print(e.rhs)) + return x + + def _print_list(self, seq): + """MathML reference for the element: + https://www.w3.org/TR/MathML2/chapter4.html#contm.list""" + dom_element = self.dom.createElement('list') + for item in seq: + dom_element.appendChild(self._print(item)) + return dom_element + + def _print_int(self, p): + dom_element = self.dom.createElement(self.mathml_tag(p)) + dom_element.appendChild(self.dom.createTextNode(str(p))) + return dom_element + + _print_Implies = _print_AssocOp + _print_Not = _print_AssocOp + _print_Xor = _print_AssocOp + + def _print_FiniteSet(self, e): + x = self.dom.createElement('set') + for arg in e.args: + x.appendChild(self._print(arg)) + return x + + def _print_Complement(self, e): + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('setdiff')) + for arg in e.args: + x.appendChild(self._print(arg)) + return x + + def _print_ProductSet(self, e): + x = self.dom.createElement('apply') + x.appendChild(self.dom.createElement('cartesianproduct')) + for arg in e.args: + x.appendChild(self._print(arg)) + return x + + def _print_Lambda(self, e): + # MathML reference for the lambda element: + # https://www.w3.org/TR/MathML2/chapter4.html#id.4.2.1.7 + x = self.dom.createElement(self.mathml_tag(e)) + for arg in e.signature: + x_1 = self.dom.createElement('bvar') + x_1.appendChild(self._print(arg)) + x.appendChild(x_1) + x.appendChild(self._print(e.expr)) + return x + + # XXX Symmetric difference is not supported for MathML content printers. + + +class MathMLPresentationPrinter(MathMLPrinterBase): + """Prints an expression to the Presentation MathML markup language. + + References: https://www.w3.org/TR/MathML2/chapter3.html + """ + printmethod = "_mathml_presentation" + + def mathml_tag(self, e): + """Returns the MathML tag for an expression.""" + translate = { + 'Number': 'mn', + 'Limit': '→', + 'Derivative': 'ⅆ', + 'int': 'mn', + 'Symbol': 'mi', + 'Integral': '∫', + 'Sum': '∑', + 'sin': 'sin', + 'cos': 'cos', + 'tan': 'tan', + 'cot': 'cot', + 'asin': 'arcsin', + 'asinh': 'arcsinh', + 'acos': 'arccos', + 'acosh': 'arccosh', + 'atan': 'arctan', + 'atanh': 'arctanh', + 'acot': 'arccot', + 'atan2': 'arctan', + 'Equality': '=', + 'Unequality': '≠', + 'GreaterThan': '≥', + 'LessThan': '≤', + 'StrictGreaterThan': '>', + 'StrictLessThan': '<', + 'lerchphi': 'Φ', + 'zeta': 'ζ', + 'dirichlet_eta': 'η', + 'elliptic_k': 'Κ', + 'lowergamma': 'γ', + 'uppergamma': 'Γ', + 'gamma': 'Γ', + 'totient': 'ϕ', + 'reduced_totient': 'λ', + 'primenu': 'ν', + 'primeomega': 'Ω', + 'fresnels': 'S', + 'fresnelc': 'C', + 'LambertW': 'W', + 'Heaviside': 'Θ', + 'BooleanTrue': 'True', + 'BooleanFalse': 'False', + 'NoneType': 'None', + 'mathieus': 'S', + 'mathieuc': 'C', + 'mathieusprime': 'S′', + 'mathieucprime': 'C′', + 'Lambda': 'lambda', + } + + def mul_symbol_selection(): + if (self._settings["mul_symbol"] is None or + self._settings["mul_symbol"] == 'None'): + return '⁢' + elif self._settings["mul_symbol"] == 'times': + return '×' + elif self._settings["mul_symbol"] == 'dot': + return '·' + elif self._settings["mul_symbol"] == 'ldot': + return '․' + elif not isinstance(self._settings["mul_symbol"], str): + raise TypeError + else: + return self._settings["mul_symbol"] + for cls in e.__class__.__mro__: + n = cls.__name__ + if n in translate: + return translate[n] + # Not found in the MRO set + if e.__class__.__name__ == "Mul": + return mul_symbol_selection() + n = e.__class__.__name__ + return n.lower() + + def _l_paren(self): + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('(')) + return mo + + def _r_paren(self): + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode(')')) + return mo + + def _l_brace(self): + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('{')) + return mo + + def _r_brace(self): + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('}')) + return mo + + def _comma(self): + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode(',')) + return mo + + def _bar(self): + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('|')) + return mo + + def _semicolon(self): + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode(';')) + return mo + + def _paren_comma_separated(self, *args): + mrow = self.dom.createElement('mrow') + mrow.appendChild(self._l_paren()) + for i, arg in enumerate(args): + if i: + mrow.appendChild(self._comma()) + mrow.appendChild(self._print(arg)) + mrow.appendChild(self._r_paren()) + return mrow + + def _paren_bar_separated(self, *args): + mrow = self.dom.createElement('mrow') + mrow.appendChild(self._l_paren()) + for i, arg in enumerate(args): + if i: + mrow.appendChild(self._bar()) + mrow.appendChild(self._print(arg)) + mrow.appendChild(self._r_paren()) + return mrow + + def parenthesize(self, item, level, strict=False): + prec_val = precedence_traditional(item) + if (prec_val < level) or ((not strict) and prec_val <= level): + mrow = self.dom.createElement('mrow') + mrow.appendChild(self._l_paren()) + mrow.appendChild(self._print(item)) + mrow.appendChild(self._r_paren()) + return mrow + return self._print(item) + + def _print_Mul(self, expr): + + def multiply(expr, mrow): + from sympy.simplify import fraction + numer, denom = fraction(expr) + if denom is not S.One: + frac = self.dom.createElement('mfrac') + if self._settings["fold_short_frac"] and len(str(expr)) < 7: + frac.setAttribute('bevelled', 'true') + xnum = self._print(numer) + xden = self._print(denom) + frac.appendChild(xnum) + frac.appendChild(xden) + mrow.appendChild(frac) + return mrow + + coeff, terms = expr.as_coeff_mul() + if coeff is S.One and len(terms) == 1: + mrow.appendChild(self._print(terms[0])) + return mrow + if self.order != 'old': + terms = Mul._from_args(terms).as_ordered_factors() + + if coeff != 1: + x = self._print(coeff) + y = self.dom.createElement('mo') + y.appendChild(self.dom.createTextNode(self.mathml_tag(expr))) + mrow.appendChild(x) + mrow.appendChild(y) + for term in terms: + mrow.appendChild(self.parenthesize(term, PRECEDENCE['Mul'])) + if not term == terms[-1]: + y = self.dom.createElement('mo') + y.appendChild(self.dom.createTextNode(self.mathml_tag(expr))) + mrow.appendChild(y) + return mrow + mrow = self.dom.createElement('mrow') + if expr.could_extract_minus_sign(): + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode('-')) + mrow.appendChild(x) + mrow = multiply(-expr, mrow) + else: + mrow = multiply(expr, mrow) + + return mrow + + def _print_Add(self, expr, order=None): + mrow = self.dom.createElement('mrow') + args = self._as_ordered_terms(expr, order=order) + mrow.appendChild(self._print(args[0])) + for arg in args[1:]: + if arg.could_extract_minus_sign(): + # use minus + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode('-')) + y = self._print(-arg) + # invert expression since this is now minused + else: + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode('+')) + y = self._print(arg) + mrow.appendChild(x) + mrow.appendChild(y) + + return mrow + + def _print_MatrixBase(self, m): + table = self.dom.createElement('mtable') + for i in range(m.rows): + x = self.dom.createElement('mtr') + for j in range(m.cols): + y = self.dom.createElement('mtd') + y.appendChild(self._print(m[i, j])) + x.appendChild(y) + table.appendChild(x) + mat_delim = self._settings["mat_delim"] + if mat_delim == '': + return table + left = self.dom.createElement('mo') + right = self.dom.createElement('mo') + if mat_delim == "[": + left.appendChild(self.dom.createTextNode("[")) + right.appendChild(self.dom.createTextNode("]")) + else: + left.appendChild(self.dom.createTextNode("(")) + right.appendChild(self.dom.createTextNode(")")) + mrow = self.dom.createElement('mrow') + mrow.appendChild(left) + mrow.appendChild(table) + mrow.appendChild(right) + return mrow + + def _get_printed_Rational(self, e, folded=None): + if e.p < 0: + p = -e.p + else: + p = e.p + x = self.dom.createElement('mfrac') + if folded or self._settings["fold_short_frac"]: + x.setAttribute('bevelled', 'true') + x.appendChild(self._print(p)) + x.appendChild(self._print(e.q)) + if e.p < 0: + mrow = self.dom.createElement('mrow') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('-')) + mrow.appendChild(mo) + mrow.appendChild(x) + return mrow + else: + return x + + def _print_Rational(self, e): + if e.q == 1: + # don't divide + return self._print(e.p) + + return self._get_printed_Rational(e, self._settings["fold_short_frac"]) + + def _print_Limit(self, e): + mrow = self.dom.createElement('mrow') + munder = self.dom.createElement('munder') + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode('lim')) + + x = self.dom.createElement('mrow') + x_1 = self._print(e.args[1]) + arrow = self.dom.createElement('mo') + arrow.appendChild(self.dom.createTextNode(self.mathml_tag(e))) + x_2 = self._print(e.args[2]) + x.appendChild(x_1) + x.appendChild(arrow) + x.appendChild(x_2) + + munder.appendChild(mi) + munder.appendChild(x) + mrow.appendChild(munder) + mrow.appendChild(self._print(e.args[0])) + + return mrow + + def _print_ImaginaryUnit(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('ⅈ')) + return x + + def _print_GoldenRatio(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('Φ')) + return x + + def _print_Exp1(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('ⅇ')) + return x + + def _print_Pi(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('π')) + return x + + def _print_Infinity(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('∞')) + return x + + def _print_NegativeInfinity(self, e): + mrow = self.dom.createElement('mrow') + y = self.dom.createElement('mo') + y.appendChild(self.dom.createTextNode('-')) + x = self._print_Infinity(e) + mrow.appendChild(y) + mrow.appendChild(x) + return mrow + + def _print_HBar(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('ℏ')) + return x + + def _print_EulerGamma(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('γ')) + return x + + def _print_TribonacciConstant(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('TribonacciConstant')) + return x + + def _print_Dagger(self, e): + msup = self.dom.createElement('msup') + msup.appendChild(self._print(e.args[0])) + msup.appendChild(self.dom.createTextNode('†')) + return msup + + def _print_Contains(self, e): + mrow = self.dom.createElement('mrow') + mrow.appendChild(self._print(e.args[0])) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('∈')) + mrow.appendChild(mo) + mrow.appendChild(self._print(e.args[1])) + return mrow + + def _print_HilbertSpace(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('ℋ')) + return x + + def _print_ComplexSpace(self, e): + msup = self.dom.createElement('msup') + msup.appendChild(self.dom.createTextNode('𝒞')) + msup.appendChild(self._print(e.args[0])) + return msup + + def _print_FockSpace(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('ℱ')) + return x + + + def _print_Integral(self, expr): + intsymbols = {1: "∫", 2: "∬", 3: "∭"} + + mrow = self.dom.createElement('mrow') + if len(expr.limits) <= 3 and all(len(lim) == 1 for lim in expr.limits): + # Only up to three-integral signs exists + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode(intsymbols[len(expr.limits)])) + mrow.appendChild(mo) + else: + # Either more than three or limits provided + for lim in reversed(expr.limits): + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode(intsymbols[1])) + if len(lim) == 1: + mrow.appendChild(mo) + if len(lim) == 2: + msup = self.dom.createElement('msup') + msup.appendChild(mo) + msup.appendChild(self._print(lim[1])) + mrow.appendChild(msup) + if len(lim) == 3: + msubsup = self.dom.createElement('msubsup') + msubsup.appendChild(mo) + msubsup.appendChild(self._print(lim[1])) + msubsup.appendChild(self._print(lim[2])) + mrow.appendChild(msubsup) + # print function + mrow.appendChild(self.parenthesize(expr.function, PRECEDENCE["Mul"], + strict=True)) + # print integration variables + for lim in reversed(expr.limits): + d = self.dom.createElement('mo') + d.appendChild(self.dom.createTextNode('ⅆ')) + mrow.appendChild(d) + mrow.appendChild(self._print(lim[0])) + return mrow + + def _print_Sum(self, e): + limits = list(e.limits) + subsup = self.dom.createElement('munderover') + low_elem = self._print(limits[0][1]) + up_elem = self._print(limits[0][2]) + summand = self.dom.createElement('mo') + summand.appendChild(self.dom.createTextNode(self.mathml_tag(e))) + + low = self.dom.createElement('mrow') + var = self._print(limits[0][0]) + equal = self.dom.createElement('mo') + equal.appendChild(self.dom.createTextNode('=')) + low.appendChild(var) + low.appendChild(equal) + low.appendChild(low_elem) + + subsup.appendChild(summand) + subsup.appendChild(low) + subsup.appendChild(up_elem) + + mrow = self.dom.createElement('mrow') + mrow.appendChild(subsup) + mrow.appendChild(self.parenthesize(e.function, precedence_traditional(e))) + return mrow + + def _print_Symbol(self, sym, style='plain'): + def join(items): + if len(items) > 1: + mrow = self.dom.createElement('mrow') + for i, item in enumerate(items): + if i > 0: + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode(" ")) + mrow.appendChild(mo) + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(item)) + mrow.appendChild(mi) + return mrow + else: + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(items[0])) + return mi + + # translate name, supers and subs to unicode characters + def translate(s): + if s in greek_unicode: + return greek_unicode.get(s) + else: + return s + + name, supers, subs = self._split_super_sub(sym.name) + name = translate(name) + supers = [translate(sup) for sup in supers] + subs = [translate(sub) for sub in subs] + + mname = self.dom.createElement('mi') + mname.appendChild(self.dom.createTextNode(name)) + if len(supers) == 0: + if len(subs) == 0: + x = mname + else: + x = self.dom.createElement('msub') + x.appendChild(mname) + x.appendChild(join(subs)) + else: + if len(subs) == 0: + x = self.dom.createElement('msup') + x.appendChild(mname) + x.appendChild(join(supers)) + else: + x = self.dom.createElement('msubsup') + x.appendChild(mname) + x.appendChild(join(subs)) + x.appendChild(join(supers)) + # Set bold font? + if style == 'bold': + x.setAttribute('mathvariant', 'bold') + return x + + def _print_MatrixSymbol(self, sym): + return self._print_Symbol(sym, + style=self._settings['mat_symbol_style']) + + _print_RandomSymbol = _print_Symbol + + def _print_conjugate(self, expr): + enc = self.dom.createElement('menclose') + enc.setAttribute('notation', 'top') + enc.appendChild(self._print(expr.args[0])) + return enc + + def _print_operator_after(self, op, expr): + row = self.dom.createElement('mrow') + row.appendChild(self.parenthesize(expr, PRECEDENCE["Func"])) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode(op)) + row.appendChild(mo) + return row + + def _print_factorial(self, expr): + return self._print_operator_after('!', expr.args[0]) + + def _print_factorial2(self, expr): + return self._print_operator_after('!!', expr.args[0]) + + def _print_binomial(self, expr): + frac = self.dom.createElement('mfrac') + frac.setAttribute('linethickness', '0') + frac.appendChild(self._print(expr.args[0])) + frac.appendChild(self._print(expr.args[1])) + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_paren()) + brac.appendChild(frac) + brac.appendChild(self._r_paren()) + return brac + + def _print_Pow(self, e): + # Here we use root instead of power if the exponent is the + # reciprocal of an integer + if (e.exp.is_Rational and abs(e.exp.p) == 1 and e.exp.q != 1 and + self._settings['root_notation']): + if e.exp.q == 2: + x = self.dom.createElement('msqrt') + x.appendChild(self._print(e.base)) + if e.exp.q != 2: + x = self.dom.createElement('mroot') + x.appendChild(self._print(e.base)) + x.appendChild(self._print(e.exp.q)) + if e.exp.p == -1: + frac = self.dom.createElement('mfrac') + frac.appendChild(self._print(1)) + frac.appendChild(x) + return frac + else: + return x + + if e.exp.is_Rational and e.exp.q != 1: + if e.exp.is_negative: + top = self.dom.createElement('mfrac') + top.appendChild(self._print(1)) + x = self.dom.createElement('msup') + x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow'])) + x.appendChild(self._get_printed_Rational(-e.exp, + self._settings['fold_frac_powers'])) + top.appendChild(x) + return top + else: + x = self.dom.createElement('msup') + x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow'])) + x.appendChild(self._get_printed_Rational(e.exp, + self._settings['fold_frac_powers'])) + return x + + if e.exp.is_negative: + top = self.dom.createElement('mfrac') + top.appendChild(self._print(1)) + if e.exp == -1: + top.appendChild(self._print(e.base)) + else: + x = self.dom.createElement('msup') + x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow'])) + x.appendChild(self._print(-e.exp)) + top.appendChild(x) + return top + + x = self.dom.createElement('msup') + x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow'])) + x.appendChild(self._print(e.exp)) + return x + + def _print_Number(self, e): + x = self.dom.createElement(self.mathml_tag(e)) + x.appendChild(self.dom.createTextNode(str(e))) + return x + + def _print_AccumulationBounds(self, i): + left = self.dom.createElement('mo') + left.appendChild(self.dom.createTextNode('\u27e8')) + right = self.dom.createElement('mo') + right.appendChild(self.dom.createTextNode('\u27e9')) + brac = self.dom.createElement('mrow') + brac.appendChild(left) + brac.appendChild(self._print(i.min)) + brac.appendChild(self._comma()) + brac.appendChild(self._print(i.max)) + brac.appendChild(right) + return brac + + def _print_Derivative(self, e): + + if requires_partial(e.expr): + d = '∂' + else: + d = self.mathml_tag(e) + + # Determine denominator + m = self.dom.createElement('mrow') + dim = 0 # Total diff dimension, for numerator + for sym, num in reversed(e.variable_count): + dim += num + if num >= 2: + x = self.dom.createElement('msup') + xx = self.dom.createElement('mo') + xx.appendChild(self.dom.createTextNode(d)) + x.appendChild(xx) + x.appendChild(self._print(num)) + else: + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode(d)) + m.appendChild(x) + y = self._print(sym) + m.appendChild(y) + + mnum = self.dom.createElement('mrow') + if dim >= 2: + x = self.dom.createElement('msup') + xx = self.dom.createElement('mo') + xx.appendChild(self.dom.createTextNode(d)) + x.appendChild(xx) + x.appendChild(self._print(dim)) + else: + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode(d)) + + mnum.appendChild(x) + mrow = self.dom.createElement('mrow') + frac = self.dom.createElement('mfrac') + frac.appendChild(mnum) + frac.appendChild(m) + mrow.appendChild(frac) + + # Print function + mrow.appendChild(self._print(e.expr)) + + return mrow + + def _print_Function(self, e): + x = self.dom.createElement('mi') + if self.mathml_tag(e) == 'log' and self._settings["ln_notation"]: + x.appendChild(self.dom.createTextNode('ln')) + else: + x.appendChild(self.dom.createTextNode(self.mathml_tag(e))) + mrow = self.dom.createElement('mrow') + mrow.appendChild(x) + mrow.appendChild(self._paren_comma_separated(*e.args)) + return mrow + + def _print_Float(self, expr): + # Based off of that in StrPrinter + dps = prec_to_dps(expr._prec) + str_real = mlib_to_str(expr._mpf_, dps, strip_zeros=True) + + # Must always have a mul symbol (as 2.5 10^{20} just looks odd) + # thus we use the number separator + separator = self._settings['mul_symbol_mathml_numbers'] + mrow = self.dom.createElement('mrow') + if 'e' in str_real: + (mant, exp) = str_real.split('e') + + if exp[0] == '+': + exp = exp[1:] + + mn = self.dom.createElement('mn') + mn.appendChild(self.dom.createTextNode(mant)) + mrow.appendChild(mn) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode(separator)) + mrow.appendChild(mo) + msup = self.dom.createElement('msup') + mn = self.dom.createElement('mn') + mn.appendChild(self.dom.createTextNode("10")) + msup.appendChild(mn) + mn = self.dom.createElement('mn') + mn.appendChild(self.dom.createTextNode(exp)) + msup.appendChild(mn) + mrow.appendChild(msup) + return mrow + elif str_real == "+inf": + return self._print_Infinity(None) + elif str_real == "-inf": + return self._print_NegativeInfinity(None) + else: + mn = self.dom.createElement('mn') + mn.appendChild(self.dom.createTextNode(str_real)) + return mn + + def _print_polylog(self, expr): + mrow = self.dom.createElement('mrow') + m = self.dom.createElement('msub') + + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode('Li')) + m.appendChild(mi) + m.appendChild(self._print(expr.args[0])) + mrow.appendChild(m) + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_paren()) + brac.appendChild(self._print(expr.args[1])) + brac.appendChild(self._r_paren()) + mrow.appendChild(brac) + return mrow + + def _print_Basic(self, e): + mrow = self.dom.createElement('mrow') + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(self.mathml_tag(e))) + mrow.appendChild(mi) + mrow.appendChild(self._paren_comma_separated(*e.args)) + return mrow + + def _print_Tuple(self, e): + return self._paren_comma_separated(*e.args) + + def _print_Interval(self, i): + right = self.dom.createElement('mo') + if i.right_open: + right.appendChild(self.dom.createTextNode(')')) + else: + right.appendChild(self.dom.createTextNode(']')) + left = self.dom.createElement('mo') + if i.left_open: + left.appendChild(self.dom.createTextNode('(')) + else: + left.appendChild(self.dom.createTextNode('[')) + mrow = self.dom.createElement('mrow') + mrow.appendChild(left) + mrow.appendChild(self._print(i.start)) + mrow.appendChild(self._comma()) + mrow.appendChild(self._print(i.end)) + mrow.appendChild(right) + return mrow + + def _print_Abs(self, expr, exp=None): + mrow = self.dom.createElement('mrow') + mrow.appendChild(self._bar()) + mrow.appendChild(self._print(expr.args[0])) + mrow.appendChild(self._bar()) + return mrow + + _print_Determinant = _print_Abs + + def _print_re_im(self, c, expr): + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_paren()) + brac.appendChild(self._print(expr)) + brac.appendChild(self._r_paren()) + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(c)) + mrow = self.dom.createElement('mrow') + mrow.appendChild(mi) + mrow.appendChild(brac) + return mrow + + def _print_re(self, expr, exp=None): + return self._print_re_im('\u211C', expr.args[0]) + + def _print_im(self, expr, exp=None): + return self._print_re_im('\u2111', expr.args[0]) + + def _print_AssocOp(self, e): + mrow = self.dom.createElement('mrow') + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(self.mathml_tag(e))) + mrow.appendChild(mi) + for arg in e.args: + mrow.appendChild(self._print(arg)) + return mrow + + def _print_SetOp(self, expr, symbol, prec): + mrow = self.dom.createElement('mrow') + mrow.appendChild(self.parenthesize(expr.args[0], prec)) + for arg in expr.args[1:]: + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode(symbol)) + y = self.parenthesize(arg, prec) + mrow.appendChild(x) + mrow.appendChild(y) + return mrow + + def _print_Union(self, expr): + prec = PRECEDENCE_TRADITIONAL['Union'] + return self._print_SetOp(expr, '∪', prec) + + def _print_Intersection(self, expr): + prec = PRECEDENCE_TRADITIONAL['Intersection'] + return self._print_SetOp(expr, '∩', prec) + + def _print_Complement(self, expr): + prec = PRECEDENCE_TRADITIONAL['Complement'] + return self._print_SetOp(expr, '∖', prec) + + def _print_SymmetricDifference(self, expr): + prec = PRECEDENCE_TRADITIONAL['SymmetricDifference'] + return self._print_SetOp(expr, '∆', prec) + + def _print_ProductSet(self, expr): + prec = PRECEDENCE_TRADITIONAL['ProductSet'] + return self._print_SetOp(expr, '×', prec) + + def _print_FiniteSet(self, s): + return self._print_set(s.args) + + def _print_set(self, s): + items = sorted(s, key=default_sort_key) + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_brace()) + for i, item in enumerate(items): + if i: + brac.appendChild(self._comma()) + brac.appendChild(self._print(item)) + brac.appendChild(self._r_brace()) + return brac + + _print_frozenset = _print_set + + def _print_LogOp(self, args, symbol): + mrow = self.dom.createElement('mrow') + if args[0].is_Boolean and not args[0].is_Not: + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_paren()) + brac.appendChild(self._print(args[0])) + brac.appendChild(self._r_paren()) + mrow.appendChild(brac) + else: + mrow.appendChild(self._print(args[0])) + for arg in args[1:]: + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode(symbol)) + if arg.is_Boolean and not arg.is_Not: + y = self.dom.createElement('mrow') + y.appendChild(self._l_paren()) + y.appendChild(self._print(arg)) + y.appendChild(self._r_paren()) + else: + y = self._print(arg) + mrow.appendChild(x) + mrow.appendChild(y) + return mrow + + def _print_BasisDependent(self, expr): + from sympy.vector import Vector + + if expr == expr.zero: + # Not clear if this is ever called + return self._print(expr.zero) + if isinstance(expr, Vector): + items = expr.separate().items() + else: + items = [(0, expr)] + + mrow = self.dom.createElement('mrow') + for system, vect in items: + inneritems = list(vect.components.items()) + inneritems.sort(key = lambda x:x[0].__str__()) + for i, (k, v) in enumerate(inneritems): + if v == 1: + if i: # No + for first item + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('+')) + mrow.appendChild(mo) + mrow.appendChild(self._print(k)) + elif v == -1: + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('-')) + mrow.appendChild(mo) + mrow.appendChild(self._print(k)) + else: + if i: # No + for first item + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('+')) + mrow.appendChild(mo) + mbrac = self.dom.createElement('mrow') + mbrac.appendChild(self._l_paren()) + mbrac.appendChild(self._print(v)) + mbrac.appendChild(self._r_paren()) + mrow.appendChild(mbrac) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('⁢')) + mrow.appendChild(mo) + mrow.appendChild(self._print(k)) + return mrow + + + def _print_And(self, expr): + args = sorted(expr.args, key=default_sort_key) + return self._print_LogOp(args, '∧') + + def _print_Or(self, expr): + args = sorted(expr.args, key=default_sort_key) + return self._print_LogOp(args, '∨') + + def _print_Xor(self, expr): + args = sorted(expr.args, key=default_sort_key) + return self._print_LogOp(args, '⊻') + + def _print_Implies(self, expr): + return self._print_LogOp(expr.args, '⇒') + + def _print_Equivalent(self, expr): + args = sorted(expr.args, key=default_sort_key) + return self._print_LogOp(args, '⇔') + + def _print_Not(self, e): + mrow = self.dom.createElement('mrow') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('¬')) + mrow.appendChild(mo) + if (e.args[0].is_Boolean): + x = self.dom.createElement('mrow') + x.appendChild(self._l_paren()) + x.appendChild(self._print(e.args[0])) + x.appendChild(self._r_paren()) + else: + x = self._print(e.args[0]) + mrow.appendChild(x) + return mrow + + def _print_bool(self, e): + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(self.mathml_tag(e))) + return mi + + _print_BooleanTrue = _print_bool + _print_BooleanFalse = _print_bool + + def _print_NoneType(self, e): + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(self.mathml_tag(e))) + return mi + + def _print_Range(self, s): + dots = "\u2026" + if s.start.is_infinite and s.stop.is_infinite: + if s.step.is_positive: + printset = dots, -1, 0, 1, dots + else: + printset = dots, 1, 0, -1, dots + elif s.start.is_infinite: + printset = dots, s[-1] - s.step, s[-1] + elif s.stop.is_infinite: + it = iter(s) + printset = next(it), next(it), dots + elif len(s) > 4: + it = iter(s) + printset = next(it), next(it), dots, s[-1] + else: + printset = tuple(s) + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_brace()) + for i, el in enumerate(printset): + if i: + brac.appendChild(self._comma()) + if el == dots: + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(dots)) + brac.appendChild(mi) + else: + brac.appendChild(self._print(el)) + brac.appendChild(self._r_brace()) + return brac + + def _hprint_variadic_function(self, expr): + args = sorted(expr.args, key=default_sort_key) + mrow = self.dom.createElement('mrow') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode((str(expr.func)).lower())) + mrow.appendChild(mo) + mrow.appendChild(self._paren_comma_separated(*args)) + return mrow + + _print_Min = _print_Max = _hprint_variadic_function + + def _print_exp(self, expr): + msup = self.dom.createElement('msup') + msup.appendChild(self._print_Exp1(None)) + msup.appendChild(self._print(expr.args[0])) + return msup + + def _print_Relational(self, e): + mrow = self.dom.createElement('mrow') + mrow.appendChild(self._print(e.lhs)) + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode(self.mathml_tag(e))) + mrow.appendChild(x) + mrow.appendChild(self._print(e.rhs)) + return mrow + + def _print_int(self, p): + dom_element = self.dom.createElement(self.mathml_tag(p)) + dom_element.appendChild(self.dom.createTextNode(str(p))) + return dom_element + + def _print_BaseScalar(self, e): + msub = self.dom.createElement('msub') + index, system = e._id + mi = self.dom.createElement('mi') + mi.setAttribute('mathvariant', 'bold') + mi.appendChild(self.dom.createTextNode(system._variable_names[index])) + msub.appendChild(mi) + mi = self.dom.createElement('mi') + mi.setAttribute('mathvariant', 'bold') + mi.appendChild(self.dom.createTextNode(system._name)) + msub.appendChild(mi) + return msub + + def _print_BaseVector(self, e): + msub = self.dom.createElement('msub') + index, system = e._id + mover = self.dom.createElement('mover') + mi = self.dom.createElement('mi') + mi.setAttribute('mathvariant', 'bold') + mi.appendChild(self.dom.createTextNode(system._vector_names[index])) + mover.appendChild(mi) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('^')) + mover.appendChild(mo) + msub.appendChild(mover) + mi = self.dom.createElement('mi') + mi.setAttribute('mathvariant', 'bold') + mi.appendChild(self.dom.createTextNode(system._name)) + msub.appendChild(mi) + return msub + + def _print_VectorZero(self, e): + mover = self.dom.createElement('mover') + mi = self.dom.createElement('mi') + mi.setAttribute('mathvariant', 'bold') + mi.appendChild(self.dom.createTextNode("0")) + mover.appendChild(mi) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('^')) + mover.appendChild(mo) + return mover + + def _print_Cross(self, expr): + mrow = self.dom.createElement('mrow') + vec1 = expr._expr1 + vec2 = expr._expr2 + mrow.appendChild(self.parenthesize(vec1, PRECEDENCE['Mul'])) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('×')) + mrow.appendChild(mo) + mrow.appendChild(self.parenthesize(vec2, PRECEDENCE['Mul'])) + return mrow + + def _print_Curl(self, expr): + mrow = self.dom.createElement('mrow') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('∇')) + mrow.appendChild(mo) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('×')) + mrow.appendChild(mo) + mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul'])) + return mrow + + def _print_Divergence(self, expr): + mrow = self.dom.createElement('mrow') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('∇')) + mrow.appendChild(mo) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('·')) + mrow.appendChild(mo) + mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul'])) + return mrow + + def _print_Dot(self, expr): + mrow = self.dom.createElement('mrow') + vec1 = expr._expr1 + vec2 = expr._expr2 + mrow.appendChild(self.parenthesize(vec1, PRECEDENCE['Mul'])) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('·')) + mrow.appendChild(mo) + mrow.appendChild(self.parenthesize(vec2, PRECEDENCE['Mul'])) + return mrow + + def _print_Gradient(self, expr): + mrow = self.dom.createElement('mrow') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('∇')) + mrow.appendChild(mo) + mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul'])) + return mrow + + def _print_Laplacian(self, expr): + mrow = self.dom.createElement('mrow') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('∆')) + mrow.appendChild(mo) + mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul'])) + return mrow + + def _print_Integers(self, e): + x = self.dom.createElement('mi') + x.setAttribute('mathvariant', 'normal') + x.appendChild(self.dom.createTextNode('ℤ')) + return x + + def _print_Complexes(self, e): + x = self.dom.createElement('mi') + x.setAttribute('mathvariant', 'normal') + x.appendChild(self.dom.createTextNode('ℂ')) + return x + + def _print_Reals(self, e): + x = self.dom.createElement('mi') + x.setAttribute('mathvariant', 'normal') + x.appendChild(self.dom.createTextNode('ℝ')) + return x + + def _print_Naturals(self, e): + x = self.dom.createElement('mi') + x.setAttribute('mathvariant', 'normal') + x.appendChild(self.dom.createTextNode('ℕ')) + return x + + def _print_Naturals0(self, e): + sub = self.dom.createElement('msub') + x = self.dom.createElement('mi') + x.setAttribute('mathvariant', 'normal') + x.appendChild(self.dom.createTextNode('ℕ')) + sub.appendChild(x) + sub.appendChild(self._print(S.Zero)) + return sub + + def _print_SingularityFunction(self, expr): + shift = expr.args[0] - expr.args[1] + power = expr.args[2] + left = self.dom.createElement('mo') + left.appendChild(self.dom.createTextNode('\u27e8')) + right = self.dom.createElement('mo') + right.appendChild(self.dom.createTextNode('\u27e9')) + brac = self.dom.createElement('mrow') + brac.appendChild(left) + brac.appendChild(self._print(shift)) + brac.appendChild(right) + sup = self.dom.createElement('msup') + sup.appendChild(brac) + sup.appendChild(self._print(power)) + return sup + + def _print_NaN(self, e): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('NaN')) + return x + + def _print_number_function(self, e, name): + # Print name_arg[0] for one argument or name_arg[0](arg[1]) + # for more than one argument + sub = self.dom.createElement('msub') + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode(name)) + sub.appendChild(mi) + sub.appendChild(self._print(e.args[0])) + if len(e.args) == 1: + return sub + mrow = self.dom.createElement('mrow') + mrow.appendChild(sub) + mrow.appendChild(self._paren_comma_separated(*e.args[1:])) + return mrow + + def _print_bernoulli(self, e): + return self._print_number_function(e, 'B') + + _print_bell = _print_bernoulli + + def _print_catalan(self, e): + return self._print_number_function(e, 'C') + + def _print_euler(self, e): + return self._print_number_function(e, 'E') + + def _print_fibonacci(self, e): + return self._print_number_function(e, 'F') + + def _print_lucas(self, e): + return self._print_number_function(e, 'L') + + def _print_stieltjes(self, e): + return self._print_number_function(e, 'γ') + + def _print_tribonacci(self, e): + return self._print_number_function(e, 'T') + + def _print_ComplexInfinity(self, e): + x = self.dom.createElement('mover') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('∞')) + x.appendChild(mo) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('~')) + x.appendChild(mo) + return x + + def _print_EmptySet(self, e): + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode('∅')) + return x + + def _print_UniversalSet(self, e): + x = self.dom.createElement('mo') + x.appendChild(self.dom.createTextNode('𝕌')) + return x + + def _print_Adjoint(self, expr): + from sympy.matrices import MatrixSymbol + mat = expr.arg + sup = self.dom.createElement('msup') + if not isinstance(mat, MatrixSymbol): + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_paren()) + brac.appendChild(self._print(mat)) + brac.appendChild(self._r_paren()) + sup.appendChild(brac) + else: + sup.appendChild(self._print(mat)) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('†')) + sup.appendChild(mo) + return sup + + def _print_Transpose(self, expr): + from sympy.matrices import MatrixSymbol + mat = expr.arg + sup = self.dom.createElement('msup') + if not isinstance(mat, MatrixSymbol): + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_paren()) + brac.appendChild(self._print(mat)) + brac.appendChild(self._r_paren()) + sup.appendChild(brac) + else: + sup.appendChild(self._print(mat)) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('T')) + sup.appendChild(mo) + return sup + + def _print_Inverse(self, expr): + from sympy.matrices import MatrixSymbol + mat = expr.arg + sup = self.dom.createElement('msup') + if not isinstance(mat, MatrixSymbol): + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_paren()) + brac.appendChild(self._print(mat)) + brac.appendChild(self._r_paren()) + sup.appendChild(brac) + else: + sup.appendChild(self._print(mat)) + sup.appendChild(self._print(-1)) + return sup + + def _print_MatMul(self, expr): + from sympy.matrices.expressions.matmul import MatMul + + x = self.dom.createElement('mrow') + args = expr.args + if isinstance(args[0], Mul): + args = args[0].as_ordered_factors() + list(args[1:]) + else: + args = list(args) + + if isinstance(expr, MatMul) and expr.could_extract_minus_sign(): + if args[0] == -1: + args = args[1:] + else: + args[0] = -args[0] + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('-')) + x.appendChild(mo) + + for arg in args[:-1]: + x.appendChild(self.parenthesize(arg, precedence_traditional(expr), + False)) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('⁢')) + x.appendChild(mo) + x.appendChild(self.parenthesize(args[-1], precedence_traditional(expr), + False)) + return x + + def _print_MatPow(self, expr): + from sympy.matrices import MatrixSymbol + base, exp = expr.base, expr.exp + sup = self.dom.createElement('msup') + if not isinstance(base, MatrixSymbol): + brac = self.dom.createElement('mrow') + brac.appendChild(self._l_paren()) + brac.appendChild(self._print(base)) + brac.appendChild(self._r_paren()) + sup.appendChild(brac) + else: + sup.appendChild(self._print(base)) + sup.appendChild(self._print(exp)) + return sup + + def _print_HadamardProduct(self, expr): + x = self.dom.createElement('mrow') + args = expr.args + for arg in args[:-1]: + x.appendChild( + self.parenthesize(arg, precedence_traditional(expr), False)) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('∘')) + x.appendChild(mo) + x.appendChild( + self.parenthesize(args[-1], precedence_traditional(expr), False)) + return x + + def _print_ZeroMatrix(self, Z): + x = self.dom.createElement('mn') + x.appendChild(self.dom.createTextNode('𝟘')) + return x + + def _print_OneMatrix(self, Z): + x = self.dom.createElement('mn') + x.appendChild(self.dom.createTextNode('𝟙')) + return x + + def _print_Identity(self, I): + x = self.dom.createElement('mi') + x.appendChild(self.dom.createTextNode('𝕀')) + return x + + def _print_floor(self, e): + left = self.dom.createElement('mo') + left.appendChild(self.dom.createTextNode('\u230A')) + right = self.dom.createElement('mo') + right.appendChild(self.dom.createTextNode('\u230B')) + mrow = self.dom.createElement('mrow') + mrow.appendChild(left) + mrow.appendChild(self._print(e.args[0])) + mrow.appendChild(right) + return mrow + + def _print_ceiling(self, e): + left = self.dom.createElement('mo') + left.appendChild(self.dom.createTextNode('\u2308')) + right = self.dom.createElement('mo') + right.appendChild(self.dom.createTextNode('\u2309')) + mrow = self.dom.createElement('mrow') + mrow.appendChild(left) + mrow.appendChild(self._print(e.args[0])) + mrow.appendChild(right) + return mrow + + def _print_Lambda(self, e): + mrow = self.dom.createElement('mrow') + symbols = e.args[0] + if len(symbols) == 1: + symbols = self._print(symbols[0]) + else: + symbols = self._print(symbols) + mrow.appendChild(self._l_paren()) + mrow.appendChild(symbols) + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('↦')) + mrow.appendChild(mo) + mrow.appendChild(self._print(e.args[1])) + mrow.appendChild(self._r_paren()) + return mrow + + def _print_tuple(self, e): + return self._paren_comma_separated(*e) + + def _print_IndexedBase(self, e): + return self._print(e.label) + + def _print_Indexed(self, e): + x = self.dom.createElement('msub') + x.appendChild(self._print(e.base)) + if len(e.indices) == 1: + x.appendChild(self._print(e.indices[0])) + return x + x.appendChild(self._print(e.indices)) + return x + + def _print_MatrixElement(self, e): + x = self.dom.createElement('msub') + x.appendChild(self.parenthesize(e.parent, PRECEDENCE["Atom"], strict = True)) + brac = self.dom.createElement('mrow') + for i, arg in enumerate(e.indices): + if i: + brac.appendChild(self._comma()) + brac.appendChild(self._print(arg)) + x.appendChild(brac) + return x + + def _print_elliptic_f(self, e): + x = self.dom.createElement('mrow') + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode('𝖥')) + x.appendChild(mi) + x.appendChild(self._paren_bar_separated(*e.args)) + return x + + def _print_elliptic_e(self, e): + x = self.dom.createElement('mrow') + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode('𝖤')) + x.appendChild(mi) + x.appendChild(self._paren_bar_separated(*e.args)) + return x + + def _print_elliptic_pi(self, e): + x = self.dom.createElement('mrow') + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode('𝛱')) + x.appendChild(mi) + y = self.dom.createElement('mrow') + y.appendChild(self._l_paren()) + if len(e.args) == 2: + n, m = e.args + y.appendChild(self._print(n)) + y.appendChild(self._bar()) + y.appendChild(self._print(m)) + else: + n, m, z = e.args + y.appendChild(self._print(n)) + y.appendChild(self._semicolon()) + y.appendChild(self._print(m)) + y.appendChild(self._bar()) + y.appendChild(self._print(z)) + y.appendChild(self._r_paren()) + x.appendChild(y) + return x + + def _print_Ei(self, e): + x = self.dom.createElement('mrow') + mi = self.dom.createElement('mi') + mi.appendChild(self.dom.createTextNode('Ei')) + x.appendChild(mi) + x.appendChild(self._print(e.args)) + return x + + def _print_expint(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msub') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('E')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + x.appendChild(y) + x.appendChild(self._print(e.args[1:])) + return x + + def _print_jacobi(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msubsup') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('P')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + y.appendChild(self._print(e.args[1:3])) + x.appendChild(y) + x.appendChild(self._print(e.args[3:])) + return x + + def _print_gegenbauer(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msubsup') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('C')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + y.appendChild(self._print(e.args[1:2])) + x.appendChild(y) + x.appendChild(self._print(e.args[2:])) + return x + + def _print_chebyshevt(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msub') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('T')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + x.appendChild(y) + x.appendChild(self._print(e.args[1:])) + return x + + def _print_chebyshevu(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msub') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('U')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + x.appendChild(y) + x.appendChild(self._print(e.args[1:])) + return x + + def _print_legendre(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msub') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('P')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + x.appendChild(y) + x.appendChild(self._print(e.args[1:])) + return x + + def _print_assoc_legendre(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msubsup') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('P')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + y.appendChild(self._print(e.args[1:2])) + x.appendChild(y) + x.appendChild(self._print(e.args[2:])) + return x + + def _print_laguerre(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msub') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('L')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + x.appendChild(y) + x.appendChild(self._print(e.args[1:])) + return x + + def _print_assoc_laguerre(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msubsup') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('L')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + y.appendChild(self._print(e.args[1:2])) + x.appendChild(y) + x.appendChild(self._print(e.args[2:])) + return x + + def _print_hermite(self, e): + x = self.dom.createElement('mrow') + y = self.dom.createElement('msub') + mo = self.dom.createElement('mo') + mo.appendChild(self.dom.createTextNode('H')) + y.appendChild(mo) + y.appendChild(self._print(e.args[0])) + x.appendChild(y) + x.appendChild(self._print(e.args[1:])) + return x + + +@print_function(MathMLPrinterBase) +def mathml(expr, printer='content', **settings): + """Returns the MathML representation of expr. If printer is presentation + then prints Presentation MathML else prints content MathML. + """ + if printer == 'presentation': + return MathMLPresentationPrinter(settings).doprint(expr) + else: + return MathMLContentPrinter(settings).doprint(expr) + + +def print_mathml(expr, printer='content', **settings): + """ + Prints a pretty representation of the MathML code for expr. If printer is + presentation then prints Presentation MathML else prints content MathML. + + Examples + ======== + + >>> ## + >>> from sympy import print_mathml + >>> from sympy.abc import x + >>> print_mathml(x+1) #doctest: +NORMALIZE_WHITESPACE + + + x + 1 + + >>> print_mathml(x+1, printer='presentation') + + x + + + 1 + + + """ + if printer == 'presentation': + s = MathMLPresentationPrinter(settings) + else: + s = MathMLContentPrinter(settings) + xml = s._print(sympify(expr)) + pretty_xml = xml.toprettyxml() + + print(pretty_xml) + + +# For backward compatibility +MathMLPrinter = MathMLContentPrinter diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/numpy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/numpy.py new file mode 100644 index 0000000000000000000000000000000000000000..1ff68454bb287bc0a1d2dfc1fe68fb05b3c22a74 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/numpy.py @@ -0,0 +1,541 @@ +from sympy.core import S +from sympy.core.function import Lambda +from sympy.core.power import Pow +from .pycode import PythonCodePrinter, _known_functions_math, _print_known_const, _print_known_func, _unpack_integral_limits, ArrayPrinter +from .codeprinter import CodePrinter + + +_not_in_numpy = 'erf erfc factorial gamma loggamma'.split() +_in_numpy = [(k, v) for k, v in _known_functions_math.items() if k not in _not_in_numpy] +_known_functions_numpy = dict(_in_numpy, **{ + 'acos': 'arccos', + 'acosh': 'arccosh', + 'asin': 'arcsin', + 'asinh': 'arcsinh', + 'atan': 'arctan', + 'atan2': 'arctan2', + 'atanh': 'arctanh', + 'exp2': 'exp2', + 'sign': 'sign', + 'logaddexp': 'logaddexp', + 'logaddexp2': 'logaddexp2', + 'isinf': 'isinf', + 'isnan': 'isnan', + +}) +_known_constants_numpy = { + 'Exp1': 'e', + 'Pi': 'pi', + 'EulerGamma': 'euler_gamma', + 'NaN': 'nan', + 'Infinity': 'inf', +} + +_numpy_known_functions = {k: 'numpy.' + v for k, v in _known_functions_numpy.items()} +_numpy_known_constants = {k: 'numpy.' + v for k, v in _known_constants_numpy.items()} + +class NumPyPrinter(ArrayPrinter, PythonCodePrinter): + """ + Numpy printer which handles vectorized piecewise functions, + logical operators, etc. + """ + + _module = 'numpy' + _kf = _numpy_known_functions + _kc = _numpy_known_constants + + def __init__(self, settings=None): + """ + `settings` is passed to CodePrinter.__init__() + `module` specifies the array module to use, currently 'NumPy', 'CuPy' + or 'JAX'. + """ + self.language = "Python with {}".format(self._module) + self.printmethod = "_{}code".format(self._module) + + self._kf = {**PythonCodePrinter._kf, **self._kf} + + super().__init__(settings=settings) + + + def _print_seq(self, seq): + "General sequence printer: converts to tuple" + # Print tuples here instead of lists because numba supports + # tuples in nopython mode. + delimiter=', ' + return '({},)'.format(delimiter.join(self._print(item) for item in seq)) + + def _print_NegativeInfinity(self, expr): + return '-' + self._print(S.Infinity) + + def _print_MatMul(self, expr): + "Matrix multiplication printer" + if expr.as_coeff_matrices()[0] is not S.One: + expr_list = expr.as_coeff_matrices()[1]+[(expr.as_coeff_matrices()[0])] + return '({})'.format(').dot('.join(self._print(i) for i in expr_list)) + return '({})'.format(').dot('.join(self._print(i) for i in expr.args)) + + def _print_MatPow(self, expr): + "Matrix power printer" + return '{}({}, {})'.format(self._module_format(self._module + '.linalg.matrix_power'), + self._print(expr.args[0]), self._print(expr.args[1])) + + def _print_Inverse(self, expr): + "Matrix inverse printer" + return '{}({})'.format(self._module_format(self._module + '.linalg.inv'), + self._print(expr.args[0])) + + def _print_DotProduct(self, expr): + # DotProduct allows any shape order, but numpy.dot does matrix + # multiplication, so we have to make sure it gets 1 x n by n x 1. + arg1, arg2 = expr.args + if arg1.shape[0] != 1: + arg1 = arg1.T + if arg2.shape[1] != 1: + arg2 = arg2.T + + return "%s(%s, %s)" % (self._module_format(self._module + '.dot'), + self._print(arg1), + self._print(arg2)) + + def _print_MatrixSolve(self, expr): + return "%s(%s, %s)" % (self._module_format(self._module + '.linalg.solve'), + self._print(expr.matrix), + self._print(expr.vector)) + + def _print_ZeroMatrix(self, expr): + return '{}({})'.format(self._module_format(self._module + '.zeros'), + self._print(expr.shape)) + + def _print_OneMatrix(self, expr): + return '{}({})'.format(self._module_format(self._module + '.ones'), + self._print(expr.shape)) + + def _print_FunctionMatrix(self, expr): + from sympy.abc import i, j + lamda = expr.lamda + if not isinstance(lamda, Lambda): + lamda = Lambda((i, j), lamda(i, j)) + return '{}(lambda {}: {}, {})'.format(self._module_format(self._module + '.fromfunction'), + ', '.join(self._print(arg) for arg in lamda.args[0]), + self._print(lamda.args[1]), self._print(expr.shape)) + + def _print_HadamardProduct(self, expr): + func = self._module_format(self._module + '.multiply') + return ''.join('{}({}, '.format(func, self._print(arg)) \ + for arg in expr.args[:-1]) + "{}{}".format(self._print(expr.args[-1]), + ')' * (len(expr.args) - 1)) + + def _print_KroneckerProduct(self, expr): + func = self._module_format(self._module + '.kron') + return ''.join('{}({}, '.format(func, self._print(arg)) \ + for arg in expr.args[:-1]) + "{}{}".format(self._print(expr.args[-1]), + ')' * (len(expr.args) - 1)) + + def _print_Adjoint(self, expr): + return '{}({}({}))'.format( + self._module_format(self._module + '.conjugate'), + self._module_format(self._module + '.transpose'), + self._print(expr.args[0])) + + def _print_DiagonalOf(self, expr): + vect = '{}({})'.format( + self._module_format(self._module + '.diag'), + self._print(expr.arg)) + return '{}({}, (-1, 1))'.format( + self._module_format(self._module + '.reshape'), vect) + + def _print_DiagMatrix(self, expr): + return '{}({})'.format(self._module_format(self._module + '.diagflat'), + self._print(expr.args[0])) + + def _print_DiagonalMatrix(self, expr): + return '{}({}, {}({}, {}))'.format(self._module_format(self._module + '.multiply'), + self._print(expr.arg), self._module_format(self._module + '.eye'), + self._print(expr.shape[0]), self._print(expr.shape[1])) + + def _print_Piecewise(self, expr): + "Piecewise function printer" + from sympy.logic.boolalg import ITE, simplify_logic + def print_cond(cond): + """ Problem having an ITE in the cond. """ + if cond.has(ITE): + return self._print(simplify_logic(cond)) + else: + return self._print(cond) + exprs = '[{}]'.format(','.join(self._print(arg.expr) for arg in expr.args)) + conds = '[{}]'.format(','.join(print_cond(arg.cond) for arg in expr.args)) + # If [default_value, True] is a (expr, cond) sequence in a Piecewise object + # it will behave the same as passing the 'default' kwarg to select() + # *as long as* it is the last element in expr.args. + # If this is not the case, it may be triggered prematurely. + return '{}({}, {}, default={})'.format( + self._module_format(self._module + '.select'), conds, exprs, + self._print(S.NaN)) + + def _print_Relational(self, expr): + "Relational printer for Equality and Unequality" + op = { + '==' :'equal', + '!=' :'not_equal', + '<' :'less', + '<=' :'less_equal', + '>' :'greater', + '>=' :'greater_equal', + } + if expr.rel_op in op: + lhs = self._print(expr.lhs) + rhs = self._print(expr.rhs) + return '{op}({lhs}, {rhs})'.format(op=self._module_format(self._module + '.'+op[expr.rel_op]), + lhs=lhs, rhs=rhs) + return super()._print_Relational(expr) + + def _print_And(self, expr): + "Logical And printer" + # We have to override LambdaPrinter because it uses Python 'and' keyword. + # If LambdaPrinter didn't define it, we could use StrPrinter's + # version of the function and add 'logical_and' to NUMPY_TRANSLATIONS. + return '{}.reduce(({}))'.format(self._module_format(self._module + '.logical_and'), ','.join(self._print(i) for i in expr.args)) + + def _print_Or(self, expr): + "Logical Or printer" + # We have to override LambdaPrinter because it uses Python 'or' keyword. + # If LambdaPrinter didn't define it, we could use StrPrinter's + # version of the function and add 'logical_or' to NUMPY_TRANSLATIONS. + return '{}.reduce(({}))'.format(self._module_format(self._module + '.logical_or'), ','.join(self._print(i) for i in expr.args)) + + def _print_Not(self, expr): + "Logical Not printer" + # We have to override LambdaPrinter because it uses Python 'not' keyword. + # If LambdaPrinter didn't define it, we would still have to define our + # own because StrPrinter doesn't define it. + return '{}({})'.format(self._module_format(self._module + '.logical_not'), ','.join(self._print(i) for i in expr.args)) + + def _print_Pow(self, expr, rational=False): + # XXX Workaround for negative integer power error + if expr.exp.is_integer and expr.exp.is_negative: + expr = Pow(expr.base, expr.exp.evalf(), evaluate=False) + return self._hprint_Pow(expr, rational=rational, sqrt=self._module + '.sqrt') + + def _helper_minimum_maximum(self, op: str, *args): + if len(args) == 0: + raise NotImplementedError(f"Need at least one argument for {op}") + elif len(args) == 1: + return self._print(args[0]) + _reduce = self._module_format('functools.reduce') + s_args = [self._print(arg) for arg in args] + return f"{_reduce}({op}, [{', '.join(s_args)}])" + + def _print_Min(self, expr): + return self._print_minimum(expr) + + def _print_amin(self, expr): + return '{}({}, axis={})'.format(self._module_format(self._module + '.amin'), self._print(expr.array), self._print(expr.axis)) + + def _print_minimum(self, expr): + op = self._module_format(self._module + '.minimum') + return self._helper_minimum_maximum(op, *expr.args) + + def _print_Max(self, expr): + return self._print_maximum(expr) + + def _print_amax(self, expr): + return '{}({}, axis={})'.format(self._module_format(self._module + '.amax'), self._print(expr.array), self._print(expr.axis)) + + def _print_maximum(self, expr): + op = self._module_format(self._module + '.maximum') + return self._helper_minimum_maximum(op, *expr.args) + + def _print_arg(self, expr): + return "%s(%s)" % (self._module_format(self._module + '.angle'), self._print(expr.args[0])) + + def _print_im(self, expr): + return "%s(%s)" % (self._module_format(self._module + '.imag'), self._print(expr.args[0])) + + def _print_Mod(self, expr): + return "%s(%s)" % (self._module_format(self._module + '.mod'), ', '.join( + (self._print(arg) for arg in expr.args))) + + def _print_re(self, expr): + return "%s(%s)" % (self._module_format(self._module + '.real'), self._print(expr.args[0])) + + def _print_sinc(self, expr): + return "%s(%s)" % (self._module_format(self._module + '.sinc'), self._print(expr.args[0]/S.Pi)) + + def _print_MatrixBase(self, expr): + if 0 in expr.shape: + func = self._module_format(f'{self._module}.{self._zeros}') + return f"{func}({self._print(expr.shape)})" + func = self.known_functions.get(expr.__class__.__name__, None) + if func is None: + func = self._module_format(f'{self._module}.array') + return "%s(%s)" % (func, self._print(expr.tolist())) + + def _print_Identity(self, expr): + shape = expr.shape + if all(dim.is_Integer for dim in shape): + return "%s(%s)" % (self._module_format(self._module + '.eye'), self._print(expr.shape[0])) + else: + raise NotImplementedError("Symbolic matrix dimensions are not yet supported for identity matrices") + + def _print_BlockMatrix(self, expr): + return '{}({})'.format(self._module_format(self._module + '.block'), + self._print(expr.args[0].tolist())) + + def _print_NDimArray(self, expr): + if expr.rank() == 0: + func = self._module_format(f'{self._module}.array') + return f"{func}({self._print(expr[()])})" + if 0 in expr.shape: + func = self._module_format(f'{self._module}.{self._zeros}') + return f"{func}({self._print(expr.shape)})" + func = self._module_format(f'{self._module}.array') + return f"{func}({self._print(expr.tolist())})" + + _add = "add" + _einsum = "einsum" + _transpose = "transpose" + _ones = "ones" + _zeros = "zeros" + + _print_lowergamma = CodePrinter._print_not_supported + _print_uppergamma = CodePrinter._print_not_supported + _print_fresnelc = CodePrinter._print_not_supported + _print_fresnels = CodePrinter._print_not_supported + +for func in _numpy_known_functions: + setattr(NumPyPrinter, f'_print_{func}', _print_known_func) + +for const in _numpy_known_constants: + setattr(NumPyPrinter, f'_print_{const}', _print_known_const) + + +_known_functions_scipy_special = { + 'Ei': 'expi', + 'erf': 'erf', + 'erfc': 'erfc', + 'besselj': 'jv', + 'bessely': 'yv', + 'besseli': 'iv', + 'besselk': 'kv', + 'cosm1': 'cosm1', + 'powm1': 'powm1', + 'factorial': 'factorial', + 'gamma': 'gamma', + 'loggamma': 'gammaln', + 'digamma': 'psi', + 'polygamma': 'polygamma', + 'RisingFactorial': 'poch', + 'jacobi': 'eval_jacobi', + 'gegenbauer': 'eval_gegenbauer', + 'chebyshevt': 'eval_chebyt', + 'chebyshevu': 'eval_chebyu', + 'legendre': 'eval_legendre', + 'hermite': 'eval_hermite', + 'laguerre': 'eval_laguerre', + 'assoc_laguerre': 'eval_genlaguerre', + 'beta': 'beta', + 'LambertW' : 'lambertw', +} + +_known_constants_scipy_constants = { + 'GoldenRatio': 'golden_ratio', + 'Pi': 'pi', +} +_scipy_known_functions = {k : "scipy.special." + v for k, v in _known_functions_scipy_special.items()} +_scipy_known_constants = {k : "scipy.constants." + v for k, v in _known_constants_scipy_constants.items()} + +class SciPyPrinter(NumPyPrinter): + + _kf = {**NumPyPrinter._kf, **_scipy_known_functions} + _kc = {**NumPyPrinter._kc, **_scipy_known_constants} + + def __init__(self, settings=None): + super().__init__(settings=settings) + self.language = "Python with SciPy and NumPy" + + def _print_SparseRepMatrix(self, expr): + i, j, data = [], [], [] + for (r, c), v in expr.todok().items(): + i.append(r) + j.append(c) + data.append(v) + + return "{name}(({data}, ({i}, {j})), shape={shape})".format( + name=self._module_format('scipy.sparse.coo_matrix'), + data=data, i=i, j=j, shape=expr.shape + ) + + _print_ImmutableSparseMatrix = _print_SparseRepMatrix + + # SciPy's lpmv has a different order of arguments from assoc_legendre + def _print_assoc_legendre(self, expr): + return "{0}({2}, {1}, {3})".format( + self._module_format('scipy.special.lpmv'), + self._print(expr.args[0]), + self._print(expr.args[1]), + self._print(expr.args[2])) + + def _print_lowergamma(self, expr): + return "{0}({2})*{1}({2}, {3})".format( + self._module_format('scipy.special.gamma'), + self._module_format('scipy.special.gammainc'), + self._print(expr.args[0]), + self._print(expr.args[1])) + + def _print_uppergamma(self, expr): + return "{0}({2})*{1}({2}, {3})".format( + self._module_format('scipy.special.gamma'), + self._module_format('scipy.special.gammaincc'), + self._print(expr.args[0]), + self._print(expr.args[1])) + + def _print_betainc(self, expr): + betainc = self._module_format('scipy.special.betainc') + beta = self._module_format('scipy.special.beta') + args = [self._print(arg) for arg in expr.args] + return f"({betainc}({args[0]}, {args[1]}, {args[3]}) - {betainc}({args[0]}, {args[1]}, {args[2]})) \ + * {beta}({args[0]}, {args[1]})" + + def _print_betainc_regularized(self, expr): + return "{0}({1}, {2}, {4}) - {0}({1}, {2}, {3})".format( + self._module_format('scipy.special.betainc'), + self._print(expr.args[0]), + self._print(expr.args[1]), + self._print(expr.args[2]), + self._print(expr.args[3])) + + def _print_fresnels(self, expr): + return "{}({})[0]".format( + self._module_format("scipy.special.fresnel"), + self._print(expr.args[0])) + + def _print_fresnelc(self, expr): + return "{}({})[1]".format( + self._module_format("scipy.special.fresnel"), + self._print(expr.args[0])) + + def _print_airyai(self, expr): + return "{}({})[0]".format( + self._module_format("scipy.special.airy"), + self._print(expr.args[0])) + + def _print_airyaiprime(self, expr): + return "{}({})[1]".format( + self._module_format("scipy.special.airy"), + self._print(expr.args[0])) + + def _print_airybi(self, expr): + return "{}({})[2]".format( + self._module_format("scipy.special.airy"), + self._print(expr.args[0])) + + def _print_airybiprime(self, expr): + return "{}({})[3]".format( + self._module_format("scipy.special.airy"), + self._print(expr.args[0])) + + def _print_bernoulli(self, expr): + # scipy's bernoulli is inconsistent with SymPy's so rewrite + return self._print(expr._eval_rewrite_as_zeta(*expr.args)) + + def _print_harmonic(self, expr): + return self._print(expr._eval_rewrite_as_zeta(*expr.args)) + + def _print_Integral(self, e): + integration_vars, limits = _unpack_integral_limits(e) + + if len(limits) == 1: + # nicer (but not necessary) to prefer quad over nquad for 1D case + module_str = self._module_format("scipy.integrate.quad") + limit_str = "%s, %s" % tuple(map(self._print, limits[0])) + else: + module_str = self._module_format("scipy.integrate.nquad") + limit_str = "({})".format(", ".join( + "(%s, %s)" % tuple(map(self._print, l)) for l in limits)) + + return "{}(lambda {}: {}, {})[0]".format( + module_str, + ", ".join(map(self._print, integration_vars)), + self._print(e.args[0]), + limit_str) + + def _print_Si(self, expr): + return "{}({})[0]".format( + self._module_format("scipy.special.sici"), + self._print(expr.args[0])) + + def _print_Ci(self, expr): + return "{}({})[1]".format( + self._module_format("scipy.special.sici"), + self._print(expr.args[0])) + +for func in _scipy_known_functions: + setattr(SciPyPrinter, f'_print_{func}', _print_known_func) + +for const in _scipy_known_constants: + setattr(SciPyPrinter, f'_print_{const}', _print_known_const) + + +_cupy_known_functions = {k : "cupy." + v for k, v in _known_functions_numpy.items()} +_cupy_known_constants = {k : "cupy." + v for k, v in _known_constants_numpy.items()} + +class CuPyPrinter(NumPyPrinter): + """ + CuPy printer which handles vectorized piecewise functions, + logical operators, etc. + """ + + _module = 'cupy' + _kf = _cupy_known_functions + _kc = _cupy_known_constants + + def __init__(self, settings=None): + super().__init__(settings=settings) + +for func in _cupy_known_functions: + setattr(CuPyPrinter, f'_print_{func}', _print_known_func) + +for const in _cupy_known_constants: + setattr(CuPyPrinter, f'_print_{const}', _print_known_const) + + +_jax_known_functions = {k: 'jax.numpy.' + v for k, v in _known_functions_numpy.items()} +_jax_known_constants = {k: 'jax.numpy.' + v for k, v in _known_constants_numpy.items()} + +class JaxPrinter(NumPyPrinter): + """ + JAX printer which handles vectorized piecewise functions, + logical operators, etc. + """ + _module = "jax.numpy" + + _kf = _jax_known_functions + _kc = _jax_known_constants + + def __init__(self, settings=None): + super().__init__(settings=settings) + self.printmethod = '_jaxcode' + + # These need specific override to allow for the lack of "jax.numpy.reduce" + def _print_And(self, expr): + "Logical And printer" + return "{}({}.asarray([{}]), axis=0)".format( + self._module_format(self._module + ".all"), + self._module_format(self._module), + ",".join(self._print(i) for i in expr.args), + ) + + def _print_Or(self, expr): + "Logical Or printer" + return "{}({}.asarray([{}]), axis=0)".format( + self._module_format(self._module + ".any"), + self._module_format(self._module), + ",".join(self._print(i) for i in expr.args), + ) + +for func in _jax_known_functions: + setattr(JaxPrinter, f'_print_{func}', _print_known_func) + +for const in _jax_known_constants: + setattr(JaxPrinter, f'_print_{const}', _print_known_const) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/octave.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/octave.py new file mode 100644 index 0000000000000000000000000000000000000000..2cf2d6a5754668d7a95ef5dc7b27b4864756a9e5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/octave.py @@ -0,0 +1,711 @@ +""" +Octave (and Matlab) code printer + +The `OctaveCodePrinter` converts SymPy expressions into Octave expressions. +It uses a subset of the Octave language for Matlab compatibility. + +A complete code generator, which uses `octave_code` extensively, can be found +in `sympy.utilities.codegen`. The `codegen` module can be used to generate +complete source code files. + +""" + +from __future__ import annotations +from typing import Any + +from sympy.core import Mul, Pow, S, Rational +from sympy.core.mul import _keep_coeff +from sympy.core.numbers import equal_valued +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import precedence, PRECEDENCE +from re import search + +# List of known functions. First, those that have the same name in +# SymPy and Octave. This is almost certainly incomplete! +known_fcns_src1 = ["sin", "cos", "tan", "cot", "sec", "csc", + "asin", "acos", "acot", "atan", "atan2", "asec", "acsc", + "sinh", "cosh", "tanh", "coth", "csch", "sech", + "asinh", "acosh", "atanh", "acoth", "asech", "acsch", + "erfc", "erfi", "erf", "erfinv", "erfcinv", + "besseli", "besselj", "besselk", "bessely", + "bernoulli", "beta", "euler", "exp", "factorial", "floor", + "fresnelc", "fresnels", "gamma", "harmonic", "log", + "polylog", "sign", "zeta", "legendre"] + +# These functions have different names ("SymPy": "Octave"), more +# generally a mapping to (argument_conditions, octave_function). +known_fcns_src2 = { + "Abs": "abs", + "arg": "angle", # arg/angle ok in Octave but only angle in Matlab + "binomial": "bincoeff", + "ceiling": "ceil", + "chebyshevu": "chebyshevU", + "chebyshevt": "chebyshevT", + "Chi": "coshint", + "Ci": "cosint", + "conjugate": "conj", + "DiracDelta": "dirac", + "Heaviside": "heaviside", + "im": "imag", + "laguerre": "laguerreL", + "LambertW": "lambertw", + "li": "logint", + "loggamma": "gammaln", + "Max": "max", + "Min": "min", + "Mod": "mod", + "polygamma": "psi", + "re": "real", + "RisingFactorial": "pochhammer", + "Shi": "sinhint", + "Si": "sinint", +} + + +class OctaveCodePrinter(CodePrinter): + """ + A printer to convert expressions to strings of Octave/Matlab code. + """ + printmethod = "_octave" + language = "Octave" + + _operators = { + 'and': '&', + 'or': '|', + 'not': '~', + } + + _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{ + 'precision': 17, + 'user_functions': {}, + 'contract': True, + 'inline': True, + }) + # Note: contract is for expressing tensors as loops (if True), or just + # assignment (if False). FIXME: this should be looked a more carefully + # for Octave. + + + def __init__(self, settings={}): + super().__init__(settings) + self.known_functions = dict(zip(known_fcns_src1, known_fcns_src1)) + self.known_functions.update(dict(known_fcns_src2)) + userfuncs = settings.get('user_functions', {}) + self.known_functions.update(userfuncs) + + + def _rate_index_position(self, p): + return p*5 + + + def _get_statement(self, codestring): + return "%s;" % codestring + + + def _get_comment(self, text): + return "% {}".format(text) + + + def _declare_number_const(self, name, value): + return "{} = {};".format(name, value) + + + def _format_code(self, lines): + return self.indent_code(lines) + + + def _traverse_matrix_indices(self, mat): + # Octave uses Fortran order (column-major) + rows, cols = mat.shape + return ((i, j) for j in range(cols) for i in range(rows)) + + + def _get_loop_opening_ending(self, indices): + open_lines = [] + close_lines = [] + for i in indices: + # Octave arrays start at 1 and end at dimension + var, start, stop = map(self._print, + [i.label, i.lower + 1, i.upper + 1]) + open_lines.append("for %s = %s:%s" % (var, start, stop)) + close_lines.append("end") + return open_lines, close_lines + + + def _print_Mul(self, expr): + # print complex numbers nicely in Octave + if (expr.is_number and expr.is_imaginary and + (S.ImaginaryUnit*expr).is_Integer): + return "%si" % self._print(-S.ImaginaryUnit*expr) + + # cribbed from str.py + prec = precedence(expr) + + c, e = expr.as_coeff_Mul() + if c < 0: + expr = _keep_coeff(-c, e) + sign = "-" + else: + sign = "" + + a = [] # items in the numerator + b = [] # items that are in the denominator (if any) + + pow_paren = [] # Will collect all pow with more than one base element and exp = -1 + + if self.order not in ('old', 'none'): + args = expr.as_ordered_factors() + else: + # use make_args in case expr was something like -x -> x + args = Mul.make_args(expr) + + # Gather args for numerator/denominator + for item in args: + if (item.is_commutative and item.is_Pow and item.exp.is_Rational + and item.exp.is_negative): + if item.exp != -1: + b.append(Pow(item.base, -item.exp, evaluate=False)) + else: + if len(item.args[0].args) != 1 and isinstance(item.base, Mul): # To avoid situations like #14160 + pow_paren.append(item) + b.append(Pow(item.base, -item.exp)) + elif item.is_Rational and item is not S.Infinity: + if item.p != 1: + a.append(Rational(item.p)) + if item.q != 1: + b.append(Rational(item.q)) + else: + a.append(item) + + a = a or [S.One] + + a_str = [self.parenthesize(x, prec) for x in a] + b_str = [self.parenthesize(x, prec) for x in b] + + # To parenthesize Pow with exp = -1 and having more than one Symbol + for item in pow_paren: + if item.base in b: + b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] + + # from here it differs from str.py to deal with "*" and ".*" + def multjoin(a, a_str): + # here we probably are assuming the constants will come first + r = a_str[0] + for i in range(1, len(a)): + mulsym = '*' if a[i-1].is_number else '.*' + r = r + mulsym + a_str[i] + return r + + if not b: + return sign + multjoin(a, a_str) + elif len(b) == 1: + divsym = '/' if b[0].is_number else './' + return sign + multjoin(a, a_str) + divsym + b_str[0] + else: + divsym = '/' if all(bi.is_number for bi in b) else './' + return (sign + multjoin(a, a_str) + + divsym + "(%s)" % multjoin(b, b_str)) + + def _print_Relational(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + op = expr.rel_op + return "{} {} {}".format(lhs_code, op, rhs_code) + + def _print_Pow(self, expr): + powsymbol = '^' if all(x.is_number for x in expr.args) else '.^' + + PREC = precedence(expr) + + if equal_valued(expr.exp, 0.5): + return "sqrt(%s)" % self._print(expr.base) + + if expr.is_commutative: + if equal_valued(expr.exp, -0.5): + sym = '/' if expr.base.is_number else './' + return "1" + sym + "sqrt(%s)" % self._print(expr.base) + if equal_valued(expr.exp, -1): + sym = '/' if expr.base.is_number else './' + return "1" + sym + "%s" % self.parenthesize(expr.base, PREC) + + return '%s%s%s' % (self.parenthesize(expr.base, PREC), powsymbol, + self.parenthesize(expr.exp, PREC)) + + + def _print_MatPow(self, expr): + PREC = precedence(expr) + return '%s^%s' % (self.parenthesize(expr.base, PREC), + self.parenthesize(expr.exp, PREC)) + + def _print_MatrixSolve(self, expr): + PREC = precedence(expr) + return "%s \\ %s" % (self.parenthesize(expr.matrix, PREC), + self.parenthesize(expr.vector, PREC)) + + def _print_Pi(self, expr): + return 'pi' + + + def _print_ImaginaryUnit(self, expr): + return "1i" + + + def _print_Exp1(self, expr): + return "exp(1)" + + + def _print_GoldenRatio(self, expr): + # FIXME: how to do better, e.g., for octave_code(2*GoldenRatio)? + #return self._print((1+sqrt(S(5)))/2) + return "(1+sqrt(5))/2" + + + def _print_Assignment(self, expr): + from sympy.codegen.ast import Assignment + from sympy.functions.elementary.piecewise import Piecewise + from sympy.tensor.indexed import IndexedBase + # Copied from codeprinter, but remove special MatrixSymbol treatment + lhs = expr.lhs + rhs = expr.rhs + # We special case assignments that take multiple lines + if not self._settings["inline"] and isinstance(expr.rhs, Piecewise): + # Here we modify Piecewise so each expression is now + # an Assignment, and then continue on the print. + expressions = [] + conditions = [] + for (e, c) in rhs.args: + expressions.append(Assignment(lhs, e)) + conditions.append(c) + temp = Piecewise(*zip(expressions, conditions)) + return self._print(temp) + if self._settings["contract"] and (lhs.has(IndexedBase) or + rhs.has(IndexedBase)): + # Here we check if there is looping to be done, and if so + # print the required loops. + return self._doprint_loops(rhs, lhs) + else: + lhs_code = self._print(lhs) + rhs_code = self._print(rhs) + return self._get_statement("%s = %s" % (lhs_code, rhs_code)) + + + def _print_Infinity(self, expr): + return 'inf' + + + def _print_NegativeInfinity(self, expr): + return '-inf' + + + def _print_NaN(self, expr): + return 'NaN' + + + def _print_list(self, expr): + return '{' + ', '.join(self._print(a) for a in expr) + '}' + _print_tuple = _print_list + _print_Tuple = _print_list + _print_List = _print_list + + + def _print_BooleanTrue(self, expr): + return "true" + + + def _print_BooleanFalse(self, expr): + return "false" + + + def _print_bool(self, expr): + return str(expr).lower() + + + # Could generate quadrature code for definite Integrals? + #_print_Integral = _print_not_supported + + + def _print_MatrixBase(self, A): + # Handle zero dimensions: + if (A.rows, A.cols) == (0, 0): + return '[]' + elif S.Zero in A.shape: + return 'zeros(%s, %s)' % (A.rows, A.cols) + elif (A.rows, A.cols) == (1, 1): + # Octave does not distinguish between scalars and 1x1 matrices + return self._print(A[0, 0]) + return "[%s]" % "; ".join(" ".join([self._print(a) for a in A[r, :]]) + for r in range(A.rows)) + + + def _print_SparseRepMatrix(self, A): + from sympy.matrices import Matrix + L = A.col_list() + # make row vectors of the indices and entries + I = Matrix([[k[0] + 1 for k in L]]) + J = Matrix([[k[1] + 1 for k in L]]) + AIJ = Matrix([[k[2] for k in L]]) + return "sparse(%s, %s, %s, %s, %s)" % (self._print(I), self._print(J), + self._print(AIJ), A.rows, A.cols) + + + def _print_MatrixElement(self, expr): + return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \ + + '(%s, %s)' % (expr.i + 1, expr.j + 1) + + + def _print_MatrixSlice(self, expr): + def strslice(x, lim): + l = x[0] + 1 + h = x[1] + step = x[2] + lstr = self._print(l) + hstr = 'end' if h == lim else self._print(h) + if step == 1: + if l == 1 and h == lim: + return ':' + if l == h: + return lstr + else: + return lstr + ':' + hstr + else: + return ':'.join((lstr, self._print(step), hstr)) + return (self._print(expr.parent) + '(' + + strslice(expr.rowslice, expr.parent.shape[0]) + ', ' + + strslice(expr.colslice, expr.parent.shape[1]) + ')') + + + def _print_Indexed(self, expr): + inds = [ self._print(i) for i in expr.indices ] + return "%s(%s)" % (self._print(expr.base.label), ", ".join(inds)) + + + def _print_KroneckerDelta(self, expr): + prec = PRECEDENCE["Pow"] + return "double(%s == %s)" % tuple(self.parenthesize(x, prec) + for x in expr.args) + + def _print_HadamardProduct(self, expr): + return '.*'.join([self.parenthesize(arg, precedence(expr)) + for arg in expr.args]) + + def _print_HadamardPower(self, expr): + PREC = precedence(expr) + return '.**'.join([ + self.parenthesize(expr.base, PREC), + self.parenthesize(expr.exp, PREC) + ]) + + def _print_Identity(self, expr): + shape = expr.shape + if len(shape) == 2 and shape[0] == shape[1]: + shape = [shape[0]] + s = ", ".join(self._print(n) for n in shape) + return "eye(" + s + ")" + + def _print_lowergamma(self, expr): + # Octave implements regularized incomplete gamma function + return "(gammainc({1}, {0}).*gamma({0}))".format( + self._print(expr.args[0]), self._print(expr.args[1])) + + + def _print_uppergamma(self, expr): + return "(gammainc({1}, {0}, 'upper').*gamma({0}))".format( + self._print(expr.args[0]), self._print(expr.args[1])) + + + def _print_sinc(self, expr): + #Note: Divide by pi because Octave implements normalized sinc function. + return "sinc(%s)" % self._print(expr.args[0]/S.Pi) + + + def _print_hankel1(self, expr): + return "besselh(%s, 1, %s)" % (self._print(expr.order), + self._print(expr.argument)) + + + def _print_hankel2(self, expr): + return "besselh(%s, 2, %s)" % (self._print(expr.order), + self._print(expr.argument)) + + + # Note: as of 2015, Octave doesn't have spherical Bessel functions + def _print_jn(self, expr): + from sympy.functions import sqrt, besselj + x = expr.argument + expr2 = sqrt(S.Pi/(2*x))*besselj(expr.order + S.Half, x) + return self._print(expr2) + + + def _print_yn(self, expr): + from sympy.functions import sqrt, bessely + x = expr.argument + expr2 = sqrt(S.Pi/(2*x))*bessely(expr.order + S.Half, x) + return self._print(expr2) + + + def _print_airyai(self, expr): + return "airy(0, %s)" % self._print(expr.args[0]) + + + def _print_airyaiprime(self, expr): + return "airy(1, %s)" % self._print(expr.args[0]) + + + def _print_airybi(self, expr): + return "airy(2, %s)" % self._print(expr.args[0]) + + + def _print_airybiprime(self, expr): + return "airy(3, %s)" % self._print(expr.args[0]) + + + def _print_expint(self, expr): + mu, x = expr.args + if mu != 1: + return self._print_not_supported(expr) + return "expint(%s)" % self._print(x) + + + def _one_or_two_reversed_args(self, expr): + assert len(expr.args) <= 2 + return '{name}({args})'.format( + name=self.known_functions[expr.__class__.__name__], + args=", ".join([self._print(x) for x in reversed(expr.args)]) + ) + + + _print_DiracDelta = _print_LambertW = _one_or_two_reversed_args + + + def _nested_binary_math_func(self, expr): + return '{name}({arg1}, {arg2})'.format( + name=self.known_functions[expr.__class__.__name__], + arg1=self._print(expr.args[0]), + arg2=self._print(expr.func(*expr.args[1:])) + ) + + _print_Max = _print_Min = _nested_binary_math_func + + + def _print_Piecewise(self, expr): + if expr.args[-1].cond != True: + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + lines = [] + if self._settings["inline"]: + # Express each (cond, expr) pair in a nested Horner form: + # (condition) .* (expr) + (not cond) .* () + # Expressions that result in multiple statements won't work here. + ecpairs = ["({0}).*({1}) + (~({0})).*(".format + (self._print(c), self._print(e)) + for e, c in expr.args[:-1]] + elast = "%s" % self._print(expr.args[-1].expr) + pw = " ...\n".join(ecpairs) + elast + ")"*len(ecpairs) + # Note: current need these outer brackets for 2*pw. Would be + # nicer to teach parenthesize() to do this for us when needed! + return "(" + pw + ")" + else: + for i, (e, c) in enumerate(expr.args): + if i == 0: + lines.append("if (%s)" % self._print(c)) + elif i == len(expr.args) - 1 and c == True: + lines.append("else") + else: + lines.append("elseif (%s)" % self._print(c)) + code0 = self._print(e) + lines.append(code0) + if i == len(expr.args) - 1: + lines.append("end") + return "\n".join(lines) + + + def _print_zeta(self, expr): + if len(expr.args) == 1: + return "zeta(%s)" % self._print(expr.args[0]) + else: + # Matlab two argument zeta is not equivalent to SymPy's + return self._print_not_supported(expr) + + + def indent_code(self, code): + """Accepts a string of code or a list of code lines""" + + # code mostly copied from ccode + if isinstance(code, str): + code_lines = self.indent_code(code.splitlines(True)) + return ''.join(code_lines) + + tab = " " + inc_regex = ('^function ', '^if ', '^elseif ', '^else$', '^for ') + dec_regex = ('^end$', '^elseif ', '^else$') + + # pre-strip left-space from the code + code = [ line.lstrip(' \t') for line in code ] + + increase = [ int(any(search(re, line) for re in inc_regex)) + for line in code ] + decrease = [ int(any(search(re, line) for re in dec_regex)) + for line in code ] + + pretty = [] + level = 0 + for n, line in enumerate(code): + if line in ('', '\n'): + pretty.append(line) + continue + level -= decrease[n] + pretty.append("%s%s" % (tab*level, line)) + level += increase[n] + return pretty + + +def octave_code(expr, assign_to=None, **settings): + r"""Converts `expr` to a string of Octave (or Matlab) code. + + The string uses a subset of the Octave language for Matlab compatibility. + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used as the name of the variable to which + the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for + expressions that generate multi-line statements. + precision : integer, optional + The precision for numbers such as pi [default=16]. + user_functions : dict, optional + A dictionary where keys are ``FunctionClass`` instances and values are + their string representations. Alternatively, the dictionary value can + be a list of tuples i.e. [(argument_test, cfunction_string)]. See + below for examples. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + inline: bool, optional + If True, we try to create single-statement code instead of multiple + statements. [default=True]. + + Examples + ======== + + >>> from sympy import octave_code, symbols, sin, pi + >>> x = symbols('x') + >>> octave_code(sin(x).series(x).removeO()) + 'x.^5/120 - x.^3/6 + x' + + >>> from sympy import Rational, ceiling + >>> x, y, tau = symbols("x, y, tau") + >>> octave_code((2*tau)**Rational(7, 2)) + '8*sqrt(2)*tau.^(7/2)' + + Note that element-wise (Hadamard) operations are used by default between + symbols. This is because its very common in Octave to write "vectorized" + code. It is harmless if the values are scalars. + + >>> octave_code(sin(pi*x*y), assign_to="s") + 's = sin(pi*x.*y);' + + If you need a matrix product "*" or matrix power "^", you can specify the + symbol as a ``MatrixSymbol``. + + >>> from sympy import Symbol, MatrixSymbol + >>> n = Symbol('n', integer=True, positive=True) + >>> A = MatrixSymbol('A', n, n) + >>> octave_code(3*pi*A**3) + '(3*pi)*A^3' + + This class uses several rules to decide which symbol to use a product. + Pure numbers use "*", Symbols use ".*" and MatrixSymbols use "*". + A HadamardProduct can be used to specify componentwise multiplication ".*" + of two MatrixSymbols. There is currently there is no easy way to specify + scalar symbols, so sometimes the code might have some minor cosmetic + issues. For example, suppose x and y are scalars and A is a Matrix, then + while a human programmer might write "(x^2*y)*A^3", we generate: + + >>> octave_code(x**2*y*A**3) + '(x.^2.*y)*A^3' + + Matrices are supported using Octave inline notation. When using + ``assign_to`` with matrices, the name can be specified either as a string + or as a ``MatrixSymbol``. The dimensions must align in the latter case. + + >>> from sympy import Matrix, MatrixSymbol + >>> mat = Matrix([[x**2, sin(x), ceiling(x)]]) + >>> octave_code(mat, assign_to='A') + 'A = [x.^2 sin(x) ceil(x)];' + + ``Piecewise`` expressions are implemented with logical masking by default. + Alternatively, you can pass "inline=False" to use if-else conditionals. + Note that if the ``Piecewise`` lacks a default term, represented by + ``(expr, True)`` then an error will be thrown. This is to prevent + generating an expression that may not evaluate to anything. + + >>> from sympy import Piecewise + >>> pw = Piecewise((x + 1, x > 0), (x, True)) + >>> octave_code(pw, assign_to=tau) + 'tau = ((x > 0).*(x + 1) + (~(x > 0)).*(x));' + + Note that any expression that can be generated normally can also exist + inside a Matrix: + + >>> mat = Matrix([[x**2, pw, sin(x)]]) + >>> octave_code(mat, assign_to='A') + 'A = [x.^2 ((x > 0).*(x + 1) + (~(x > 0)).*(x)) sin(x)];' + + Custom printing can be defined for certain types by passing a dictionary of + "type" : "function" to the ``user_functions`` kwarg. Alternatively, the + dictionary value can be a list of tuples i.e., [(argument_test, + cfunction_string)]. This can be used to call a custom Octave function. + + >>> from sympy import Function + >>> f = Function('f') + >>> g = Function('g') + >>> custom_functions = { + ... "f": "existing_octave_fcn", + ... "g": [(lambda x: x.is_Matrix, "my_mat_fcn"), + ... (lambda x: not x.is_Matrix, "my_fcn")] + ... } + >>> mat = Matrix([[1, x]]) + >>> octave_code(f(x) + g(x) + g(mat), user_functions=custom_functions) + 'existing_octave_fcn(x) + my_fcn(x) + my_mat_fcn([1 x])' + + Support for loops is provided through ``Indexed`` types. With + ``contract=True`` these expressions will be turned into loops, whereas + ``contract=False`` will just print the assignment expression that should be + looped over: + + >>> from sympy import Eq, IndexedBase, Idx + >>> len_y = 5 + >>> y = IndexedBase('y', shape=(len_y,)) + >>> t = IndexedBase('t', shape=(len_y,)) + >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) + >>> i = Idx('i', len_y-1) + >>> e = Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) + >>> octave_code(e.rhs, assign_to=e.lhs, contract=False) + 'Dy(i) = (y(i + 1) - y(i))./(t(i + 1) - t(i));' + """ + return OctaveCodePrinter(settings).doprint(expr, assign_to) + + +def print_octave_code(expr, **settings): + """Prints the Octave (or Matlab) representation of the given expression. + + See `octave_code` for the meaning of the optional arguments. + """ + print(octave_code(expr, **settings)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/precedence.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/precedence.py new file mode 100644 index 0000000000000000000000000000000000000000..d22d5746aeee51bddcf273d4575c30c3c27db71a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/precedence.py @@ -0,0 +1,180 @@ +"""A module providing information about the necessity of brackets""" + + +# Default precedence values for some basic types +PRECEDENCE = { + "Lambda": 1, + "Xor": 10, + "Or": 20, + "And": 30, + "Relational": 35, + "Add": 40, + "Mul": 50, + "Pow": 60, + "Func": 70, + "Not": 100, + "Atom": 1000, + "BitwiseOr": 36, + "BitwiseXor": 37, + "BitwiseAnd": 38 +} + +# A dictionary assigning precedence values to certain classes. These values are +# treated like they were inherited, so not every single class has to be named +# here. +# Do not use this with printers other than StrPrinter +PRECEDENCE_VALUES = { + "Equivalent": PRECEDENCE["Xor"], + "Xor": PRECEDENCE["Xor"], + "Implies": PRECEDENCE["Xor"], + "Or": PRECEDENCE["Or"], + "And": PRECEDENCE["And"], + "Add": PRECEDENCE["Add"], + "Pow": PRECEDENCE["Pow"], + "Relational": PRECEDENCE["Relational"], + "Sub": PRECEDENCE["Add"], + "Not": PRECEDENCE["Not"], + "Function" : PRECEDENCE["Func"], + "NegativeInfinity": PRECEDENCE["Add"], + "MatAdd": PRECEDENCE["Add"], + "MatPow": PRECEDENCE["Pow"], + "MatrixSolve": PRECEDENCE["Mul"], + "Mod": PRECEDENCE["Mul"], + "TensAdd": PRECEDENCE["Add"], + # As soon as `TensMul` is a subclass of `Mul`, remove this: + "TensMul": PRECEDENCE["Mul"], + "HadamardProduct": PRECEDENCE["Mul"], + "HadamardPower": PRECEDENCE["Pow"], + "KroneckerProduct": PRECEDENCE["Mul"], + "Equality": PRECEDENCE["Mul"], + "Unequality": PRECEDENCE["Mul"], +} + +# Sometimes it's not enough to assign a fixed precedence value to a +# class. Then a function can be inserted in this dictionary that takes +# an instance of this class as argument and returns the appropriate +# precedence value. + +# Precedence functions + + +def precedence_Mul(item): + from sympy.core.function import Function + if any(hasattr(arg, 'precedence') and isinstance(arg, Function) and + arg.precedence < PRECEDENCE["Mul"] for arg in item.args): + return PRECEDENCE["Mul"] + + if item.could_extract_minus_sign(): + return PRECEDENCE["Add"] + return PRECEDENCE["Mul"] + + +def precedence_Rational(item): + if item.p < 0: + return PRECEDENCE["Add"] + return PRECEDENCE["Mul"] + + +def precedence_Integer(item): + if item.p < 0: + return PRECEDENCE["Add"] + return PRECEDENCE["Atom"] + + +def precedence_Float(item): + if item < 0: + return PRECEDENCE["Add"] + return PRECEDENCE["Atom"] + + +def precedence_PolyElement(item): + if item.is_generator: + return PRECEDENCE["Atom"] + elif item.is_ground: + return precedence(item.coeff(1)) + elif item.is_term: + return PRECEDENCE["Mul"] + else: + return PRECEDENCE["Add"] + + +def precedence_FracElement(item): + if item.denom == 1: + return precedence_PolyElement(item.numer) + else: + return PRECEDENCE["Mul"] + + +def precedence_UnevaluatedExpr(item): + return precedence(item.args[0]) - 0.5 + + +PRECEDENCE_FUNCTIONS = { + "Integer": precedence_Integer, + "Mul": precedence_Mul, + "Rational": precedence_Rational, + "Float": precedence_Float, + "PolyElement": precedence_PolyElement, + "FracElement": precedence_FracElement, + "UnevaluatedExpr": precedence_UnevaluatedExpr, +} + + +def precedence(item): + """Returns the precedence of a given object. + + This is the precedence for StrPrinter. + """ + if hasattr(item, "precedence"): + return item.precedence + if not isinstance(item, type): + for i in type(item).mro(): + n = i.__name__ + if n in PRECEDENCE_FUNCTIONS: + return PRECEDENCE_FUNCTIONS[n](item) + elif n in PRECEDENCE_VALUES: + return PRECEDENCE_VALUES[n] + return PRECEDENCE["Atom"] + + +PRECEDENCE_TRADITIONAL = PRECEDENCE.copy() +PRECEDENCE_TRADITIONAL['Integral'] = PRECEDENCE["Mul"] +PRECEDENCE_TRADITIONAL['Sum'] = PRECEDENCE["Mul"] +PRECEDENCE_TRADITIONAL['Product'] = PRECEDENCE["Mul"] +PRECEDENCE_TRADITIONAL['Limit'] = PRECEDENCE["Mul"] +PRECEDENCE_TRADITIONAL['Derivative'] = PRECEDENCE["Mul"] +PRECEDENCE_TRADITIONAL['TensorProduct'] = PRECEDENCE["Mul"] +PRECEDENCE_TRADITIONAL['Transpose'] = PRECEDENCE["Pow"] +PRECEDENCE_TRADITIONAL['Adjoint'] = PRECEDENCE["Pow"] +PRECEDENCE_TRADITIONAL['Dot'] = PRECEDENCE["Mul"] - 1 +PRECEDENCE_TRADITIONAL['Cross'] = PRECEDENCE["Mul"] - 1 +PRECEDENCE_TRADITIONAL['Gradient'] = PRECEDENCE["Mul"] - 1 +PRECEDENCE_TRADITIONAL['Divergence'] = PRECEDENCE["Mul"] - 1 +PRECEDENCE_TRADITIONAL['Curl'] = PRECEDENCE["Mul"] - 1 +PRECEDENCE_TRADITIONAL['Laplacian'] = PRECEDENCE["Mul"] - 1 +PRECEDENCE_TRADITIONAL['Union'] = PRECEDENCE['Xor'] +PRECEDENCE_TRADITIONAL['Intersection'] = PRECEDENCE['Xor'] +PRECEDENCE_TRADITIONAL['Complement'] = PRECEDENCE['Xor'] +PRECEDENCE_TRADITIONAL['SymmetricDifference'] = PRECEDENCE['Xor'] +PRECEDENCE_TRADITIONAL['ProductSet'] = PRECEDENCE['Xor'] +PRECEDENCE_TRADITIONAL['DotProduct'] = PRECEDENCE_TRADITIONAL['Dot'] + + +def precedence_traditional(item): + """Returns the precedence of a given object according to the + traditional rules of mathematics. + + This is the precedence for the LaTeX and pretty printer. + """ + # Integral, Sum, Product, Limit have the precedence of Mul in LaTeX, + # the precedence of Atom for other printers: + from sympy.core.expr import UnevaluatedExpr + + if isinstance(item, UnevaluatedExpr): + return precedence_traditional(item.args[0]) + + n = item.__class__.__name__ + if n in PRECEDENCE_TRADITIONAL: + return PRECEDENCE_TRADITIONAL[n] + + return precedence(item) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/preview.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/preview.py new file mode 100644 index 0000000000000000000000000000000000000000..b04a344b5b4acc086eb84ff068bc1c6a8b55d811 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/preview.py @@ -0,0 +1,390 @@ +import os +from os.path import join +import shutil +import tempfile +from pathlib import Path + +try: + from subprocess import STDOUT, CalledProcessError, check_output +except ImportError: + pass + +from sympy.utilities.decorator import doctest_depends_on +from sympy.utilities.misc import debug +from .latex import latex + +__doctest_requires__ = {('preview',): ['pyglet']} + + +def _check_output_no_window(*args, **kwargs): + # Avoid showing a cmd.exe window when running this + # on Windows + if os.name == 'nt': + creation_flag = 0x08000000 # CREATE_NO_WINDOW + else: + creation_flag = 0 # Default value + return check_output(*args, creationflags=creation_flag, **kwargs) + + +def system_default_viewer(fname, fmt): + """ Open fname with the default system viewer. + + In practice, it is impossible for python to know when the system viewer is + done. For this reason, we ensure the passed file will not be deleted under + it, and this function does not attempt to block. + """ + # copy to a new temporary file that will not be deleted + with tempfile.NamedTemporaryFile(prefix='sympy-preview-', + suffix=os.path.splitext(fname)[1], + delete=False) as temp_f: + with open(fname, 'rb') as f: + shutil.copyfileobj(f, temp_f) + + import platform + if platform.system() == 'Darwin': + import subprocess + subprocess.call(('open', temp_f.name)) + elif platform.system() == 'Windows': + os.startfile(temp_f.name) + else: + import subprocess + subprocess.call(('xdg-open', temp_f.name)) + + +def pyglet_viewer(fname, fmt): + try: + from pyglet import window, image, gl + from pyglet.window import key + from pyglet.image.codecs import ImageDecodeException + except ImportError: + raise ImportError("pyglet is required for preview.\n visit https://pyglet.org/") + + try: + img = image.load(fname) + except ImageDecodeException: + raise ValueError("pyglet preview does not work for '{}' files.".format(fmt)) + + offset = 25 + + config = gl.Config(double_buffer=False) + win = window.Window( + width=img.width + 2*offset, + height=img.height + 2*offset, + caption="SymPy", + resizable=False, + config=config + ) + + win.set_vsync(False) + + try: + def on_close(): + win.has_exit = True + + win.on_close = on_close + + def on_key_press(symbol, modifiers): + if symbol in [key.Q, key.ESCAPE]: + on_close() + + win.on_key_press = on_key_press + + def on_expose(): + gl.glClearColor(1.0, 1.0, 1.0, 1.0) + gl.glClear(gl.GL_COLOR_BUFFER_BIT) + + img.blit( + (win.width - img.width) / 2, + (win.height - img.height) / 2 + ) + + win.on_expose = on_expose + + while not win.has_exit: + win.dispatch_events() + win.flip() + except KeyboardInterrupt: + pass + + win.close() + + +def _get_latex_main(expr, *, preamble=None, packages=(), extra_preamble=None, + euler=True, fontsize=None, **latex_settings): + """ + Generate string of a LaTeX document rendering ``expr``. + """ + if preamble is None: + actual_packages = packages + ("amsmath", "amsfonts") + if euler: + actual_packages += ("euler",) + package_includes = "\n" + "\n".join(["\\usepackage{%s}" % p + for p in actual_packages]) + if extra_preamble: + package_includes += extra_preamble + + if not fontsize: + fontsize = "12pt" + elif isinstance(fontsize, int): + fontsize = "{}pt".format(fontsize) + preamble = r"""\documentclass[varwidth,%s]{standalone} +%s + +\begin{document} +""" % (fontsize, package_includes) + else: + if packages or extra_preamble: + raise ValueError("The \"packages\" or \"extra_preamble\" keywords" + "must not be set if a " + "custom LaTeX preamble was specified") + + if isinstance(expr, str): + latex_string = expr + else: + latex_string = ('$\\displaystyle ' + + latex(expr, mode='plain', **latex_settings) + + '$') + + return preamble + '\n' + latex_string + '\n\n' + r"\end{document}" + + +@doctest_depends_on(exe=('latex', 'dvipng'), modules=('pyglet',), + disable_viewers=('evince', 'gimp', 'superior-dvi-viewer')) +def preview(expr, output='png', viewer=None, euler=True, packages=(), + filename=None, outputbuffer=None, preamble=None, dvioptions=None, + outputTexFile=None, extra_preamble=None, fontsize=None, + **latex_settings): + r""" + View expression or LaTeX markup in PNG, DVI, PostScript or PDF form. + + If the expr argument is an expression, it will be exported to LaTeX and + then compiled using the available TeX distribution. The first argument, + 'expr', may also be a LaTeX string. The function will then run the + appropriate viewer for the given output format or use the user defined + one. By default png output is generated. + + By default pretty Euler fonts are used for typesetting (they were used to + typeset the well known "Concrete Mathematics" book). For that to work, you + need the 'eulervm.sty' LaTeX style (in Debian/Ubuntu, install the + texlive-fonts-extra package). If you prefer default AMS fonts or your + system lacks 'eulervm' LaTeX package then unset the 'euler' keyword + argument. + + To use viewer auto-detection, lets say for 'png' output, issue + + >>> from sympy import symbols, preview, Symbol + >>> x, y = symbols("x,y") + + >>> preview(x + y, output='png') + + This will choose 'pyglet' by default. To select a different one, do + + >>> preview(x + y, output='png', viewer='gimp') + + The 'png' format is considered special. For all other formats the rules + are slightly different. As an example we will take 'dvi' output format. If + you would run + + >>> preview(x + y, output='dvi') + + then 'view' will look for available 'dvi' viewers on your system + (predefined in the function, so it will try evince, first, then kdvi and + xdvi). If nothing is found, it will fall back to using a system file + association (via ``open`` and ``xdg-open``). To always use your system file + association without searching for the above readers, use + + >>> from sympy.printing.preview import system_default_viewer + >>> preview(x + y, output='dvi', viewer=system_default_viewer) + + If this still does not find the viewer you want, it can be set explicitly. + + >>> preview(x + y, output='dvi', viewer='superior-dvi-viewer') + + This will skip auto-detection and will run user specified + 'superior-dvi-viewer'. If ``view`` fails to find it on your system it will + gracefully raise an exception. + + You may also enter ``'file'`` for the viewer argument. Doing so will cause + this function to return a file object in read-only mode, if ``filename`` + is unset. However, if it was set, then 'preview' writes the generated + file to this filename instead. + + There is also support for writing to a ``io.BytesIO`` like object, which + needs to be passed to the ``outputbuffer`` argument. + + >>> from io import BytesIO + >>> obj = BytesIO() + >>> preview(x + y, output='png', viewer='BytesIO', + ... outputbuffer=obj) + + The LaTeX preamble can be customized by setting the 'preamble' keyword + argument. This can be used, e.g., to set a different font size, use a + custom documentclass or import certain set of LaTeX packages. + + >>> preamble = "\\documentclass[10pt]{article}\n" \ + ... "\\usepackage{amsmath,amsfonts}\\begin{document}" + >>> preview(x + y, output='png', preamble=preamble) + + It is also possible to use the standard preamble and provide additional + information to the preamble using the ``extra_preamble`` keyword argument. + + >>> from sympy import sin + >>> extra_preamble = "\\renewcommand{\\sin}{\\cos}" + >>> preview(sin(x), output='png', extra_preamble=extra_preamble) + + If the value of 'output' is different from 'dvi' then command line + options can be set ('dvioptions' argument) for the execution of the + 'dvi'+output conversion tool. These options have to be in the form of a + list of strings (see ``subprocess.Popen``). + + Additional keyword args will be passed to the :func:`~sympy.printing.latex.latex` call, + e.g., the ``symbol_names`` flag. + + >>> phidd = Symbol('phidd') + >>> preview(phidd, symbol_names={phidd: r'\ddot{\varphi}'}) + + For post-processing the generated TeX File can be written to a file by + passing the desired filename to the 'outputTexFile' keyword + argument. To write the TeX code to a file named + ``"sample.tex"`` and run the default png viewer to display the resulting + bitmap, do + + >>> preview(x + y, outputTexFile="sample.tex") + + + """ + # pyglet is the default for png + if viewer is None and output == "png": + try: + import pyglet # noqa: F401 + except ImportError: + pass + else: + viewer = pyglet_viewer + + # look up a known application + if viewer is None: + # sorted in order from most pretty to most ugly + # very discussable, but indeed 'gv' looks awful :) + candidates = { + "dvi": [ "evince", "okular", "kdvi", "xdvi" ], + "ps": [ "evince", "okular", "gsview", "gv" ], + "pdf": [ "evince", "okular", "kpdf", "acroread", "xpdf", "gv" ], + } + + for candidate in candidates.get(output, []): + path = shutil.which(candidate) + if path is not None: + viewer = path + break + + # otherwise, use the system default for file association + if viewer is None: + viewer = system_default_viewer + + if viewer == "file": + if filename is None: + raise ValueError("filename has to be specified if viewer=\"file\"") + elif viewer == "BytesIO": + if outputbuffer is None: + raise ValueError("outputbuffer has to be a BytesIO " + "compatible object if viewer=\"BytesIO\"") + elif not callable(viewer) and not shutil.which(viewer): + raise OSError("Unrecognized viewer: %s" % viewer) + + latex_main = _get_latex_main(expr, preamble=preamble, packages=packages, + euler=euler, extra_preamble=extra_preamble, + fontsize=fontsize, **latex_settings) + + debug("Latex code:") + debug(latex_main) + with tempfile.TemporaryDirectory() as workdir: + Path(join(workdir, 'texput.tex')).write_text(latex_main, encoding='utf-8') + + if outputTexFile is not None: + shutil.copyfile(join(workdir, 'texput.tex'), outputTexFile) + + if not shutil.which('latex'): + raise RuntimeError("latex program is not installed") + + try: + _check_output_no_window( + ['latex', '-halt-on-error', '-interaction=nonstopmode', + 'texput.tex'], + cwd=workdir, + stderr=STDOUT) + except CalledProcessError as e: + raise RuntimeError( + "'latex' exited abnormally with the following output:\n%s" % + e.output) + + src = "texput.%s" % (output) + + if output != "dvi": + # in order of preference + commandnames = { + "ps": ["dvips"], + "pdf": ["dvipdfmx", "dvipdfm", "dvipdf"], + "png": ["dvipng"], + "svg": ["dvisvgm"], + } + try: + cmd_variants = commandnames[output] + except KeyError: + raise ValueError("Invalid output format: %s" % output) from None + + # find an appropriate command + for cmd_variant in cmd_variants: + cmd_path = shutil.which(cmd_variant) + if cmd_path: + cmd = [cmd_path] + break + else: + if len(cmd_variants) > 1: + raise RuntimeError("None of %s are installed" % ", ".join(cmd_variants)) + else: + raise RuntimeError("%s is not installed" % cmd_variants[0]) + + defaultoptions = { + "dvipng": ["-T", "tight", "-z", "9", "--truecolor"], + "dvisvgm": ["--no-fonts"], + } + + commandend = { + "dvips": ["-o", src, "texput.dvi"], + "dvipdf": ["texput.dvi", src], + "dvipdfm": ["-o", src, "texput.dvi"], + "dvipdfmx": ["-o", src, "texput.dvi"], + "dvipng": ["-o", src, "texput.dvi"], + "dvisvgm": ["-o", src, "texput.dvi"], + } + + if dvioptions is not None: + cmd.extend(dvioptions) + else: + cmd.extend(defaultoptions.get(cmd_variant, [])) + cmd.extend(commandend[cmd_variant]) + + try: + _check_output_no_window(cmd, cwd=workdir, stderr=STDOUT) + except CalledProcessError as e: + raise RuntimeError( + "'%s' exited abnormally with the following output:\n%s" % + (' '.join(cmd), e.output)) + + + if viewer == "file": + shutil.move(join(workdir, src), filename) + elif viewer == "BytesIO": + s = Path(join(workdir, src)).read_bytes() + outputbuffer.write(s) + elif callable(viewer): + viewer(join(workdir, src), fmt=output) + else: + try: + _check_output_no_window( + [viewer, src], cwd=workdir, stderr=STDOUT) + except CalledProcessError as e: + raise RuntimeError( + "'%s %s' exited abnormally with the following output:\n%s" % + (viewer, src, e.output)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/printer.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/printer.py new file mode 100644 index 0000000000000000000000000000000000000000..0c0a6970920cf0928ad330ed9a3ea4291107a29d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/printer.py @@ -0,0 +1,432 @@ +"""Printing subsystem driver + +SymPy's printing system works the following way: Any expression can be +passed to a designated Printer who then is responsible to return an +adequate representation of that expression. + +**The basic concept is the following:** + +1. Let the object print itself if it knows how. +2. Take the best fitting method defined in the printer. +3. As fall-back use the emptyPrinter method for the printer. + +Which Method is Responsible for Printing? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The whole printing process is started by calling ``.doprint(expr)`` on the printer +which you want to use. This method looks for an appropriate method which can +print the given expression in the given style that the printer defines. +While looking for the method, it follows these steps: + +1. **Let the object print itself if it knows how.** + + The printer looks for a specific method in every object. The name of that method + depends on the specific printer and is defined under ``Printer.printmethod``. + For example, StrPrinter calls ``_sympystr`` and LatexPrinter calls ``_latex``. + Look at the documentation of the printer that you want to use. + The name of the method is specified there. + + This was the original way of doing printing in sympy. Every class had + its own latex, mathml, str and repr methods, but it turned out that it + is hard to produce a high quality printer, if all the methods are spread + out that far. Therefore all printing code was combined into the different + printers, which works great for built-in SymPy objects, but not that + good for user defined classes where it is inconvenient to patch the + printers. + +2. **Take the best fitting method defined in the printer.** + + The printer loops through expr classes (class + its bases), and tries + to dispatch the work to ``_print_`` + + e.g., suppose we have the following class hierarchy:: + + Basic + | + Atom + | + Number + | + Rational + + then, for ``expr=Rational(...)``, the Printer will try + to call printer methods in the order as shown in the figure below:: + + p._print(expr) + | + |-- p._print_Rational(expr) + | + |-- p._print_Number(expr) + | + |-- p._print_Atom(expr) + | + `-- p._print_Basic(expr) + + if ``._print_Rational`` method exists in the printer, then it is called, + and the result is returned back. Otherwise, the printer tries to call + ``._print_Number`` and so on. + +3. **As a fall-back use the emptyPrinter method for the printer.** + + As fall-back ``self.emptyPrinter`` will be called with the expression. If + not defined in the Printer subclass this will be the same as ``str(expr)``. + +.. _printer_example: + +Example of Custom Printer +^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the example below, we have a printer which prints the derivative of a function +in a shorter form. + +.. code-block:: python + + from sympy.core.symbol import Symbol + from sympy.printing.latex import LatexPrinter, print_latex + from sympy.core.function import UndefinedFunction, Function + + + class MyLatexPrinter(LatexPrinter): + \"\"\"Print derivative of a function of symbols in a shorter form. + \"\"\" + def _print_Derivative(self, expr): + function, *vars = expr.args + if not isinstance(type(function), UndefinedFunction) or \\ + not all(isinstance(i, Symbol) for i in vars): + return super()._print_Derivative(expr) + + # If you want the printer to work correctly for nested + # expressions then use self._print() instead of str() or latex(). + # See the example of nested modulo below in the custom printing + # method section. + return "{}_{{{}}}".format( + self._print(Symbol(function.func.__name__)), + ''.join(self._print(i) for i in vars)) + + + def print_my_latex(expr): + \"\"\" Most of the printers define their own wrappers for print(). + These wrappers usually take printer settings. Our printer does not have + any settings. + \"\"\" + print(MyLatexPrinter().doprint(expr)) + + + y = Symbol("y") + x = Symbol("x") + f = Function("f") + expr = f(x, y).diff(x, y) + + # Print the expression using the normal latex printer and our custom + # printer. + print_latex(expr) + print_my_latex(expr) + +The output of the code above is:: + + \\frac{\\partial^{2}}{\\partial x\\partial y} f{\\left(x,y \\right)} + f_{xy} + +.. _printer_method_example: + +Example of Custom Printing Method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the example below, the latex printing of the modulo operator is modified. +This is done by overriding the method ``_latex`` of ``Mod``. + +>>> from sympy import Symbol, Mod, Integer, print_latex + +>>> # Always use printer._print() +>>> class ModOp(Mod): +... def _latex(self, printer): +... a, b = [printer._print(i) for i in self.args] +... return r"\\operatorname{Mod}{\\left(%s, %s\\right)}" % (a, b) + +Comparing the output of our custom operator to the builtin one: + +>>> x = Symbol('x') +>>> m = Symbol('m') +>>> print_latex(Mod(x, m)) +x \\bmod m +>>> print_latex(ModOp(x, m)) +\\operatorname{Mod}{\\left(x, m\\right)} + +Common mistakes +~~~~~~~~~~~~~~~ +It's important to always use ``self._print(obj)`` to print subcomponents of +an expression when customizing a printer. Mistakes include: + +1. Using ``self.doprint(obj)`` instead: + + >>> # This example does not work properly, as only the outermost call may use + >>> # doprint. + >>> class ModOpModeWrong(Mod): + ... def _latex(self, printer): + ... a, b = [printer.doprint(i) for i in self.args] + ... return r"\\operatorname{Mod}{\\left(%s, %s\\right)}" % (a, b) + + This fails when the ``mode`` argument is passed to the printer: + + >>> print_latex(ModOp(x, m), mode='inline') # ok + $\\operatorname{Mod}{\\left(x, m\\right)}$ + >>> print_latex(ModOpModeWrong(x, m), mode='inline') # bad + $\\operatorname{Mod}{\\left($x$, $m$\\right)}$ + +2. Using ``str(obj)`` instead: + + >>> class ModOpNestedWrong(Mod): + ... def _latex(self, printer): + ... a, b = [str(i) for i in self.args] + ... return r"\\operatorname{Mod}{\\left(%s, %s\\right)}" % (a, b) + + This fails on nested objects: + + >>> # Nested modulo. + >>> print_latex(ModOp(ModOp(x, m), Integer(7))) # ok + \\operatorname{Mod}{\\left(\\operatorname{Mod}{\\left(x, m\\right)}, 7\\right)} + >>> print_latex(ModOpNestedWrong(ModOpNestedWrong(x, m), Integer(7))) # bad + \\operatorname{Mod}{\\left(ModOpNestedWrong(x, m), 7\\right)} + +3. Using ``LatexPrinter()._print(obj)`` instead. + + >>> from sympy.printing.latex import LatexPrinter + >>> class ModOpSettingsWrong(Mod): + ... def _latex(self, printer): + ... a, b = [LatexPrinter()._print(i) for i in self.args] + ... return r"\\operatorname{Mod}{\\left(%s, %s\\right)}" % (a, b) + + This causes all the settings to be discarded in the subobjects. As an + example, the ``full_prec`` setting which shows floats to full precision is + ignored: + + >>> from sympy import Float + >>> print_latex(ModOp(Float(1) * x, m), full_prec=True) # ok + \\operatorname{Mod}{\\left(1.00000000000000 x, m\\right)} + >>> print_latex(ModOpSettingsWrong(Float(1) * x, m), full_prec=True) # bad + \\operatorname{Mod}{\\left(1.0 x, m\\right)} + +""" + +from __future__ import annotations +import sys +from typing import Any, Type +import inspect +from contextlib import contextmanager +from functools import cmp_to_key, update_wrapper + +from sympy.core.add import Add +from sympy.core.basic import Basic + +from sympy.core.function import AppliedUndef, UndefinedFunction, Function + + + +@contextmanager +def printer_context(printer, **kwargs): + original = printer._context.copy() + try: + printer._context.update(kwargs) + yield + finally: + printer._context = original + + +class Printer: + """ Generic printer + + Its job is to provide infrastructure for implementing new printers easily. + + If you want to define your custom Printer or your custom printing method + for your custom class then see the example above: printer_example_ . + """ + + _global_settings: dict[str, Any] = {} + + _default_settings: dict[str, Any] = {} + + # must be initialized to pass tests and cannot be set to '| None' to pass mypy + printmethod = None # type: str + + @classmethod + def _get_initial_settings(cls): + settings = cls._default_settings.copy() + for key, val in cls._global_settings.items(): + if key in cls._default_settings: + settings[key] = val + return settings + + def __init__(self, settings=None): + self._str = str + + self._settings = self._get_initial_settings() + self._context = {} # mutable during printing + + if settings is not None: + self._settings.update(settings) + + if len(self._settings) > len(self._default_settings): + for key in self._settings: + if key not in self._default_settings: + raise TypeError("Unknown setting '%s'." % key) + + # _print_level is the number of times self._print() was recursively + # called. See StrPrinter._print_Float() for an example of usage + self._print_level = 0 + + @classmethod + def set_global_settings(cls, **settings): + """Set system-wide printing settings. """ + for key, val in settings.items(): + if val is not None: + cls._global_settings[key] = val + + @property + def order(self): + if 'order' in self._settings: + return self._settings['order'] + else: + raise AttributeError("No order defined.") + + def doprint(self, expr): + """Returns printer's representation for expr (as a string)""" + return self._str(self._print(expr)) + + def _print(self, expr, **kwargs) -> str: + """Internal dispatcher + + Tries the following concepts to print an expression: + 1. Let the object print itself if it knows how. + 2. Take the best fitting method defined in the printer. + 3. As fall-back use the emptyPrinter method for the printer. + """ + self._print_level += 1 + try: + # If the printer defines a name for a printing method + # (Printer.printmethod) and the object knows for itself how it + # should be printed, use that method. + if self.printmethod and hasattr(expr, self.printmethod): + if not (isinstance(expr, type) and issubclass(expr, Basic)): + return getattr(expr, self.printmethod)(self, **kwargs) + + # See if the class of expr is known, or if one of its super + # classes is known, and use that print function + # Exception: ignore the subclasses of Undefined, so that, e.g., + # Function('gamma') does not get dispatched to _print_gamma + classes = type(expr).__mro__ + if AppliedUndef in classes: + classes = classes[classes.index(AppliedUndef):] + if UndefinedFunction in classes: + classes = classes[classes.index(UndefinedFunction):] + # Another exception: if someone subclasses a known function, e.g., + # gamma, and changes the name, then ignore _print_gamma + if Function in classes: + i = classes.index(Function) + classes = tuple(c for c in classes[:i] if \ + c.__name__ == classes[0].__name__ or \ + c.__name__.endswith("Base")) + classes[i:] + for cls in classes: + printmethodname = '_print_' + cls.__name__ + printmethod = getattr(self, printmethodname, None) + if printmethod is not None: + return printmethod(expr, **kwargs) + # Unknown object, fall back to the emptyPrinter. + return self.emptyPrinter(expr) + finally: + self._print_level -= 1 + + def emptyPrinter(self, expr): + return str(expr) + + def _as_ordered_terms(self, expr, order=None): + """A compatibility function for ordering terms in Add. """ + order = order or self.order + + if order == 'old': + return sorted(Add.make_args(expr), key=cmp_to_key(self._compare_pretty)) + elif order == 'none': + return list(expr.args) + else: + return expr.as_ordered_terms(order=order) + + def _compare_pretty(self, a, b): + """return -1, 0, 1 if a is canonically less, equal or + greater than b. This is used when 'order=old' is selected + for printing. This puts Order last, orders Rationals + according to value, puts terms in order wrt the power of + the last power appearing in a term. Ties are broken using + Basic.compare. + """ + from sympy.core.numbers import Rational + from sympy.core.symbol import Wild + from sympy.series.order import Order + if isinstance(a, Order) and not isinstance(b, Order): + return 1 + if not isinstance(a, Order) and isinstance(b, Order): + return -1 + + if isinstance(a, Rational) and isinstance(b, Rational): + l = a.p * b.q + r = b.p * a.q + return (l > r) - (l < r) + else: + p1, p2, p3 = Wild("p1"), Wild("p2"), Wild("p3") + r_a = a.match(p1 * p2**p3) + if r_a and p3 in r_a: + a3 = r_a[p3] + r_b = b.match(p1 * p2**p3) + if r_b and p3 in r_b: + b3 = r_b[p3] + c = Basic.compare(a3, b3) + if c != 0: + return c + + # break ties + return Basic.compare(a, b) + + +class _PrintFunction: + """ + Function wrapper to replace ``**settings`` in the signature with printer defaults + """ + def __init__(self, f, print_cls: Type[Printer]): + # find all the non-setting arguments + params = list(inspect.signature(f).parameters.values()) + assert params.pop(-1).kind == inspect.Parameter.VAR_KEYWORD + self.__other_params = params + + self.__print_cls = print_cls + update_wrapper(self, f) + + def __reduce__(self): + # Since this is used as a decorator, it replaces the original function. + # The default pickling will try to pickle self.__wrapped__ and fail + # because the wrapped function can't be retrieved by name. + return self.__wrapped__.__qualname__ + + def __call__(self, *args, **kwargs): + return self.__wrapped__(*args, **kwargs) + + @property + def __signature__(self) -> inspect.Signature: + settings = self.__print_cls._get_initial_settings() + return inspect.Signature( + parameters=self.__other_params + [ + inspect.Parameter(k, inspect.Parameter.KEYWORD_ONLY, default=v) + for k, v in settings.items() + ], + return_annotation=self.__wrapped__.__annotations__.get('return', inspect.Signature.empty) # type:ignore + ) + + +def print_function(print_cls): + """ A decorator to replace kwargs with the printer settings in __signature__ """ + def decorator(f): + if sys.version_info < (3, 9): + # We have to create a subclass so that `help` actually shows the docstring in older Python versions. + # IPython and Sphinx do not need this, only a raw Python console. + cls = type(f'{f.__qualname__}_PrintFunction', (_PrintFunction,), {"__doc__": f.__doc__}) + else: + cls = _PrintFunction + return cls(f, print_cls) + return decorator diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/pycode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/pycode.py new file mode 100644 index 0000000000000000000000000000000000000000..09bdc6788775d409c06bdaae0a43c54544894602 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/pycode.py @@ -0,0 +1,852 @@ +""" +Python code printers + +This module contains Python code printers for plain Python as well as NumPy & SciPy enabled code. +""" +from collections import defaultdict +from itertools import chain +from sympy.core import S +from sympy.core.mod import Mod +from .precedence import precedence +from .codeprinter import CodePrinter + +_kw = { + 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', + 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', + 'is', 'lambda', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', + 'with', 'yield', 'None', 'False', 'nonlocal', 'True' +} + +_known_functions = { + 'Abs': 'abs', + 'Min': 'min', + 'Max': 'max', +} +_known_functions_math = { + 'acos': 'acos', + 'acosh': 'acosh', + 'asin': 'asin', + 'asinh': 'asinh', + 'atan': 'atan', + 'atan2': 'atan2', + 'atanh': 'atanh', + 'ceiling': 'ceil', + 'cos': 'cos', + 'cosh': 'cosh', + 'erf': 'erf', + 'erfc': 'erfc', + 'exp': 'exp', + 'expm1': 'expm1', + 'factorial': 'factorial', + 'floor': 'floor', + 'gamma': 'gamma', + 'hypot': 'hypot', + 'isinf': 'isinf', + 'isnan': 'isnan', + 'loggamma': 'lgamma', + 'log': 'log', + 'ln': 'log', + 'log10': 'log10', + 'log1p': 'log1p', + 'log2': 'log2', + 'sin': 'sin', + 'sinh': 'sinh', + 'Sqrt': 'sqrt', + 'tan': 'tan', + 'tanh': 'tanh' +} # Not used from ``math``: [copysign isclose isfinite isinf ldexp frexp pow modf +# radians trunc fmod fsum gcd degrees fabs] +_known_constants_math = { + 'Exp1': 'e', + 'Pi': 'pi', + 'E': 'e', + 'Infinity': 'inf', + 'NaN': 'nan', + 'ComplexInfinity': 'nan' +} + +def _print_known_func(self, expr): + known = self.known_functions[expr.__class__.__name__] + return '{name}({args})'.format(name=self._module_format(known), + args=', '.join((self._print(arg) for arg in expr.args))) + + +def _print_known_const(self, expr): + known = self.known_constants[expr.__class__.__name__] + return self._module_format(known) + + +class AbstractPythonCodePrinter(CodePrinter): + printmethod = "_pythoncode" + language = "Python" + reserved_words = _kw + modules = None # initialized to a set in __init__ + tab = ' ' + _kf = dict(chain( + _known_functions.items(), + [(k, 'math.' + v) for k, v in _known_functions_math.items()] + )) + _kc = {k: 'math.'+v for k, v in _known_constants_math.items()} + _operators = {'and': 'and', 'or': 'or', 'not': 'not'} + _default_settings = dict( + CodePrinter._default_settings, + user_functions={}, + precision=17, + inline=True, + fully_qualified_modules=True, + contract=False, + standard='python3', + ) + + def __init__(self, settings=None): + super().__init__(settings) + + # Python standard handler + std = self._settings['standard'] + if std is None: + import sys + std = 'python{}'.format(sys.version_info.major) + if std != 'python3': + raise ValueError('Only Python 3 is supported.') + self.standard = std + + self.module_imports = defaultdict(set) + + # Known functions and constants handler + self.known_functions = dict(self._kf, **(settings or {}).get( + 'user_functions', {})) + self.known_constants = dict(self._kc, **(settings or {}).get( + 'user_constants', {})) + + def _declare_number_const(self, name, value): + return "%s = %s" % (name, value) + + def _module_format(self, fqn, register=True): + parts = fqn.split('.') + if register and len(parts) > 1: + self.module_imports['.'.join(parts[:-1])].add(parts[-1]) + + if self._settings['fully_qualified_modules']: + return fqn + else: + return fqn.split('(')[0].split('[')[0].split('.')[-1] + + def _format_code(self, lines): + return lines + + def _get_statement(self, codestring): + return "{}".format(codestring) + + def _get_comment(self, text): + return " # {}".format(text) + + def _expand_fold_binary_op(self, op, args): + """ + This method expands a fold on binary operations. + + ``functools.reduce`` is an example of a folded operation. + + For example, the expression + + `A + B + C + D` + + is folded into + + `((A + B) + C) + D` + """ + if len(args) == 1: + return self._print(args[0]) + else: + return "%s(%s, %s)" % ( + self._module_format(op), + self._expand_fold_binary_op(op, args[:-1]), + self._print(args[-1]), + ) + + def _expand_reduce_binary_op(self, op, args): + """ + This method expands a reduction on binary operations. + + Notice: this is NOT the same as ``functools.reduce``. + + For example, the expression + + `A + B + C + D` + + is reduced into: + + `(A + B) + (C + D)` + """ + if len(args) == 1: + return self._print(args[0]) + else: + N = len(args) + Nhalf = N // 2 + return "%s(%s, %s)" % ( + self._module_format(op), + self._expand_reduce_binary_op(args[:Nhalf]), + self._expand_reduce_binary_op(args[Nhalf:]), + ) + + def _print_NaN(self, expr): + return "float('nan')" + + def _print_Infinity(self, expr): + return "float('inf')" + + def _print_NegativeInfinity(self, expr): + return "float('-inf')" + + def _print_ComplexInfinity(self, expr): + return self._print_NaN(expr) + + def _print_Mod(self, expr): + PREC = precedence(expr) + return ('{} % {}'.format(*(self.parenthesize(x, PREC) for x in expr.args))) + + def _print_Piecewise(self, expr): + result = [] + i = 0 + for arg in expr.args: + e = arg.expr + c = arg.cond + if i == 0: + result.append('(') + result.append('(') + result.append(self._print(e)) + result.append(')') + result.append(' if ') + result.append(self._print(c)) + result.append(' else ') + i += 1 + result = result[:-1] + if result[-1] == 'True': + result = result[:-2] + result.append(')') + else: + result.append(' else None)') + return ''.join(result) + + def _print_Relational(self, expr): + "Relational printer for Equality and Unequality" + op = { + '==' :'equal', + '!=' :'not_equal', + '<' :'less', + '<=' :'less_equal', + '>' :'greater', + '>=' :'greater_equal', + } + if expr.rel_op in op: + lhs = self._print(expr.lhs) + rhs = self._print(expr.rhs) + return '({lhs} {op} {rhs})'.format(op=expr.rel_op, lhs=lhs, rhs=rhs) + return super()._print_Relational(expr) + + def _print_ITE(self, expr): + from sympy.functions.elementary.piecewise import Piecewise + return self._print(expr.rewrite(Piecewise)) + + def _print_Sum(self, expr): + loops = ( + 'for {i} in range({a}, {b}+1)'.format( + i=self._print(i), + a=self._print(a), + b=self._print(b)) + for i, a, b in expr.limits[::-1]) + return '(builtins.sum({function} {loops}))'.format( + function=self._print(expr.function), + loops=' '.join(loops)) + + def _print_ImaginaryUnit(self, expr): + return '1j' + + def _print_KroneckerDelta(self, expr): + a, b = expr.args + + return '(1 if {a} == {b} else 0)'.format( + a = self._print(a), + b = self._print(b) + ) + + def _print_MatrixBase(self, expr): + name = expr.__class__.__name__ + func = self.known_functions.get(name, name) + return "%s(%s)" % (func, self._print(expr.tolist())) + + _print_SparseRepMatrix = \ + _print_MutableSparseMatrix = \ + _print_ImmutableSparseMatrix = \ + _print_Matrix = \ + _print_DenseMatrix = \ + _print_MutableDenseMatrix = \ + _print_ImmutableMatrix = \ + _print_ImmutableDenseMatrix = \ + lambda self, expr: self._print_MatrixBase(expr) + + def _indent_codestring(self, codestring): + return '\n'.join([self.tab + line for line in codestring.split('\n')]) + + def _print_FunctionDefinition(self, fd): + body = '\n'.join((self._print(arg) for arg in fd.body)) + return "def {name}({parameters}):\n{body}".format( + name=self._print(fd.name), + parameters=', '.join([self._print(var.symbol) for var in fd.parameters]), + body=self._indent_codestring(body) + ) + + def _print_While(self, whl): + body = '\n'.join((self._print(arg) for arg in whl.body)) + return "while {cond}:\n{body}".format( + cond=self._print(whl.condition), + body=self._indent_codestring(body) + ) + + def _print_Declaration(self, decl): + return '%s = %s' % ( + self._print(decl.variable.symbol), + self._print(decl.variable.value) + ) + + def _print_BreakToken(self, bt): + return 'break' + + def _print_Return(self, ret): + arg, = ret.args + return 'return %s' % self._print(arg) + + def _print_Raise(self, rs): + arg, = rs.args + return 'raise %s' % self._print(arg) + + def _print_RuntimeError_(self, re): + message, = re.args + return "RuntimeError(%s)" % self._print(message) + + def _print_Print(self, prnt): + print_args = ', '.join((self._print(arg) for arg in prnt.print_args)) + from sympy.codegen.ast import none + if prnt.format_string != none: + print_args = '{} % ({}), end=""'.format( + self._print(prnt.format_string), + print_args + ) + if prnt.file != None: # Must be '!= None', cannot be 'is not None' + print_args += ', file=%s' % self._print(prnt.file) + return 'print(%s)' % print_args + + def _print_Stream(self, strm): + if str(strm.name) == 'stdout': + return self._module_format('sys.stdout') + elif str(strm.name) == 'stderr': + return self._module_format('sys.stderr') + else: + return self._print(strm.name) + + def _print_NoneToken(self, arg): + return 'None' + + def _hprint_Pow(self, expr, rational=False, sqrt='math.sqrt'): + """Printing helper function for ``Pow`` + + Notes + ===== + + This preprocesses the ``sqrt`` as math formatter and prints division + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.printing.pycode import PythonCodePrinter + >>> from sympy.abc import x + + Python code printer automatically looks up ``math.sqrt``. + + >>> printer = PythonCodePrinter() + >>> printer._hprint_Pow(sqrt(x), rational=True) + 'x**(1/2)' + >>> printer._hprint_Pow(sqrt(x), rational=False) + 'math.sqrt(x)' + >>> printer._hprint_Pow(1/sqrt(x), rational=True) + 'x**(-1/2)' + >>> printer._hprint_Pow(1/sqrt(x), rational=False) + '1/math.sqrt(x)' + >>> printer._hprint_Pow(1/x, rational=False) + '1/x' + >>> printer._hprint_Pow(1/x, rational=True) + 'x**(-1)' + + Using sqrt from numpy or mpmath + + >>> printer._hprint_Pow(sqrt(x), sqrt='numpy.sqrt') + 'numpy.sqrt(x)' + >>> printer._hprint_Pow(sqrt(x), sqrt='mpmath.sqrt') + 'mpmath.sqrt(x)' + + See Also + ======== + + sympy.printing.str.StrPrinter._print_Pow + """ + PREC = precedence(expr) + + if expr.exp == S.Half and not rational: + func = self._module_format(sqrt) + arg = self._print(expr.base) + return '{func}({arg})'.format(func=func, arg=arg) + + if expr.is_commutative and not rational: + if -expr.exp is S.Half: + func = self._module_format(sqrt) + num = self._print(S.One) + arg = self._print(expr.base) + return f"{num}/{func}({arg})" + if expr.exp is S.NegativeOne: + num = self._print(S.One) + arg = self.parenthesize(expr.base, PREC, strict=False) + return f"{num}/{arg}" + + + base_str = self.parenthesize(expr.base, PREC, strict=False) + exp_str = self.parenthesize(expr.exp, PREC, strict=False) + return "{}**{}".format(base_str, exp_str) + + +class ArrayPrinter: + + def _arrayify(self, indexed): + from sympy.tensor.array.expressions.from_indexed_to_array import convert_indexed_to_array + try: + return convert_indexed_to_array(indexed) + except Exception: + return indexed + + def _get_einsum_string(self, subranks, contraction_indices): + letters = self._get_letter_generator_for_einsum() + contraction_string = "" + counter = 0 + d = {j: min(i) for i in contraction_indices for j in i} + indices = [] + for rank_arg in subranks: + lindices = [] + for i in range(rank_arg): + if counter in d: + lindices.append(d[counter]) + else: + lindices.append(counter) + counter += 1 + indices.append(lindices) + mapping = {} + letters_free = [] + letters_dum = [] + for i in indices: + for j in i: + if j not in mapping: + l = next(letters) + mapping[j] = l + else: + l = mapping[j] + contraction_string += l + if j in d: + if l not in letters_dum: + letters_dum.append(l) + else: + letters_free.append(l) + contraction_string += "," + contraction_string = contraction_string[:-1] + return contraction_string, letters_free, letters_dum + + def _get_letter_generator_for_einsum(self): + for i in range(97, 123): + yield chr(i) + for i in range(65, 91): + yield chr(i) + raise ValueError("out of letters") + + def _print_ArrayTensorProduct(self, expr): + letters = self._get_letter_generator_for_einsum() + contraction_string = ",".join(["".join([next(letters) for j in range(i)]) for i in expr.subranks]) + return '%s("%s", %s)' % ( + self._module_format(self._module + "." + self._einsum), + contraction_string, + ", ".join([self._print(arg) for arg in expr.args]) + ) + + def _print_ArrayContraction(self, expr): + from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct + base = expr.expr + contraction_indices = expr.contraction_indices + + if isinstance(base, ArrayTensorProduct): + elems = ",".join(["%s" % (self._print(arg)) for arg in base.args]) + ranks = base.subranks + else: + elems = self._print(base) + ranks = [len(base.shape)] + + contraction_string, letters_free, letters_dum = self._get_einsum_string(ranks, contraction_indices) + + if not contraction_indices: + return self._print(base) + if isinstance(base, ArrayTensorProduct): + elems = ",".join(["%s" % (self._print(arg)) for arg in base.args]) + else: + elems = self._print(base) + return "%s(\"%s\", %s)" % ( + self._module_format(self._module + "." + self._einsum), + "{}->{}".format(contraction_string, "".join(sorted(letters_free))), + elems, + ) + + def _print_ArrayDiagonal(self, expr): + from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct + diagonal_indices = list(expr.diagonal_indices) + if isinstance(expr.expr, ArrayTensorProduct): + subranks = expr.expr.subranks + elems = expr.expr.args + else: + subranks = expr.subranks + elems = [expr.expr] + diagonal_string, letters_free, letters_dum = self._get_einsum_string(subranks, diagonal_indices) + elems = [self._print(i) for i in elems] + return '%s("%s", %s)' % ( + self._module_format(self._module + "." + self._einsum), + "{}->{}".format(diagonal_string, "".join(letters_free+letters_dum)), + ", ".join(elems) + ) + + def _print_PermuteDims(self, expr): + return "%s(%s, %s)" % ( + self._module_format(self._module + "." + self._transpose), + self._print(expr.expr), + self._print(expr.permutation.array_form), + ) + + def _print_ArrayAdd(self, expr): + return self._expand_fold_binary_op(self._module + "." + self._add, expr.args) + + def _print_OneArray(self, expr): + return "%s((%s,))" % ( + self._module_format(self._module+ "." + self._ones), + ','.join(map(self._print,expr.args)) + ) + + def _print_ZeroArray(self, expr): + return "%s((%s,))" % ( + self._module_format(self._module+ "." + self._zeros), + ','.join(map(self._print,expr.args)) + ) + + def _print_Assignment(self, expr): + #XXX: maybe this needs to happen at a higher level e.g. at _print or + #doprint? + lhs = self._print(self._arrayify(expr.lhs)) + rhs = self._print(self._arrayify(expr.rhs)) + return "%s = %s" % ( lhs, rhs ) + + def _print_IndexedBase(self, expr): + return self._print_ArraySymbol(expr) + + +class PythonCodePrinter(AbstractPythonCodePrinter): + + def _print_sign(self, e): + return '(0.0 if {e} == 0 else {f}(1, {e}))'.format( + f=self._module_format('math.copysign'), e=self._print(e.args[0])) + + def _print_Not(self, expr): + PREC = precedence(expr) + return self._operators['not'] + ' ' + self.parenthesize(expr.args[0], PREC) + + def _print_IndexedBase(self, expr): + return expr.name + + def _print_Indexed(self, expr): + base = expr.args[0] + index = expr.args[1:] + return "{}[{}]".format(str(base), ", ".join([self._print(ind) for ind in index])) + + def _print_Pow(self, expr, rational=False): + return self._hprint_Pow(expr, rational=rational) + + def _print_Rational(self, expr): + return '{}/{}'.format(expr.p, expr.q) + + def _print_Half(self, expr): + return self._print_Rational(expr) + + def _print_frac(self, expr): + return self._print_Mod(Mod(expr.args[0], 1)) + + def _print_Symbol(self, expr): + + name = super()._print_Symbol(expr) + + if name in self.reserved_words: + if self._settings['error_on_reserved']: + msg = ('This expression includes the symbol "{}" which is a ' + 'reserved keyword in this language.') + raise ValueError(msg.format(name)) + return name + self._settings['reserved_word_suffix'] + elif '{' in name: # Remove curly braces from subscripted variables + return name.replace('{', '').replace('}', '') + else: + return name + + _print_lowergamma = CodePrinter._print_not_supported + _print_uppergamma = CodePrinter._print_not_supported + _print_fresnelc = CodePrinter._print_not_supported + _print_fresnels = CodePrinter._print_not_supported + + +for k in PythonCodePrinter._kf: + setattr(PythonCodePrinter, '_print_%s' % k, _print_known_func) + +for k in _known_constants_math: + setattr(PythonCodePrinter, '_print_%s' % k, _print_known_const) + + +def pycode(expr, **settings): + """ Converts an expr to a string of Python code + + Parameters + ========== + + expr : Expr + A SymPy expression. + fully_qualified_modules : bool + Whether or not to write out full module names of functions + (``math.sin`` vs. ``sin``). default: ``True``. + standard : str or None, optional + Only 'python3' (default) is supported. + This parameter may be removed in the future. + + Examples + ======== + + >>> from sympy import pycode, tan, Symbol + >>> pycode(tan(Symbol('x')) + 1) + 'math.tan(x) + 1' + + """ + return PythonCodePrinter(settings).doprint(expr) + + +from itertools import chain +from sympy.printing.pycode import PythonCodePrinter + +_known_functions_cmath = { + 'exp': 'exp', + 'sqrt': 'sqrt', + 'log': 'log', + 'cos': 'cos', + 'sin': 'sin', + 'tan': 'tan', + 'acos': 'acos', + 'asin': 'asin', + 'atan': 'atan', + 'cosh': 'cosh', + 'sinh': 'sinh', + 'tanh': 'tanh', + 'acosh': 'acosh', + 'asinh': 'asinh', + 'atanh': 'atanh', +} + +_known_constants_cmath = { + 'Pi': 'pi', + 'E': 'e', + 'Infinity': 'inf', + 'NegativeInfinity': '-inf', +} + +class CmathPrinter(PythonCodePrinter): + """ Printer for Python's cmath module """ + printmethod = "_cmathcode" + language = "Python with cmath" + + _kf = dict(chain( + _known_functions_cmath.items() + )) + + _kc = {k: 'cmath.' + v for k, v in _known_constants_cmath.items()} + + def _print_Pow(self, expr, rational=False): + return self._hprint_Pow(expr, rational=rational, sqrt='cmath.sqrt') + + def _print_Float(self, e): + return '{func}({val})'.format(func=self._module_format('cmath.mpf'), val=self._print(e)) + + def _print_known_func(self, expr): + func_name = expr.func.__name__ + if func_name in self._kf: + return f"cmath.{self._kf[func_name]}({', '.join(map(self._print, expr.args))})" + return super()._print_Function(expr) + + def _print_known_const(self, expr): + return self._kc[expr.__class__.__name__] + + def _print_re(self, expr): + """Prints `re(z)` as `z.real`""" + return f"({self._print(expr.args[0])}).real" + + def _print_im(self, expr): + """Prints `im(z)` as `z.imag`""" + return f"({self._print(expr.args[0])}).imag" + + +for k in CmathPrinter._kf: + setattr(CmathPrinter, '_print_%s' % k, CmathPrinter._print_known_func) + +for k in _known_constants_cmath: + setattr(CmathPrinter, '_print_%s' % k, CmathPrinter._print_known_const) + + +_not_in_mpmath = 'log1p log2'.split() +_in_mpmath = [(k, v) for k, v in _known_functions_math.items() if k not in _not_in_mpmath] +_known_functions_mpmath = dict(_in_mpmath, **{ + 'beta': 'beta', + 'frac': 'frac', + 'fresnelc': 'fresnelc', + 'fresnels': 'fresnels', + 'sign': 'sign', + 'loggamma': 'loggamma', + 'hyper': 'hyper', + 'meijerg': 'meijerg', + 'besselj': 'besselj', + 'bessely': 'bessely', + 'besseli': 'besseli', + 'besselk': 'besselk', +}) +_known_constants_mpmath = { + 'Exp1': 'e', + 'Pi': 'pi', + 'GoldenRatio': 'phi', + 'EulerGamma': 'euler', + 'Catalan': 'catalan', + 'NaN': 'nan', + 'Infinity': 'inf', + 'NegativeInfinity': 'ninf' +} + + +def _unpack_integral_limits(integral_expr): + """ helper function for _print_Integral that + - accepts an Integral expression + - returns a tuple of + - a list variables of integration + - a list of tuples of the upper and lower limits of integration + """ + integration_vars = [] + limits = [] + for integration_range in integral_expr.limits: + if len(integration_range) == 3: + integration_var, lower_limit, upper_limit = integration_range + else: + raise NotImplementedError("Only definite integrals are supported") + integration_vars.append(integration_var) + limits.append((lower_limit, upper_limit)) + return integration_vars, limits + + +class MpmathPrinter(PythonCodePrinter): + """ + Lambda printer for mpmath which maintains precision for floats + """ + printmethod = "_mpmathcode" + + language = "Python with mpmath" + + _kf = dict(chain( + _known_functions.items(), + [(k, 'mpmath.' + v) for k, v in _known_functions_mpmath.items()] + )) + _kc = {k: 'mpmath.'+v for k, v in _known_constants_mpmath.items()} + + def _print_Float(self, e): + # XXX: This does not handle setting mpmath.mp.dps. It is assumed that + # the caller of the lambdified function will have set it to sufficient + # precision to match the Floats in the expression. + + # Remove 'mpz' if gmpy is installed. + args = str(tuple(map(int, e._mpf_))) + return '{func}({args})'.format(func=self._module_format('mpmath.mpf'), args=args) + + + def _print_Rational(self, e): + return "{func}({p})/{func}({q})".format( + func=self._module_format('mpmath.mpf'), + q=self._print(e.q), + p=self._print(e.p) + ) + + def _print_Half(self, e): + return self._print_Rational(e) + + def _print_uppergamma(self, e): + return "{}({}, {}, {})".format( + self._module_format('mpmath.gammainc'), + self._print(e.args[0]), + self._print(e.args[1]), + self._module_format('mpmath.inf')) + + def _print_lowergamma(self, e): + return "{}({}, 0, {})".format( + self._module_format('mpmath.gammainc'), + self._print(e.args[0]), + self._print(e.args[1])) + + def _print_log2(self, e): + return '{0}({1})/{0}(2)'.format( + self._module_format('mpmath.log'), self._print(e.args[0])) + + def _print_log1p(self, e): + return '{}({})'.format( + self._module_format('mpmath.log1p'), self._print(e.args[0])) + + def _print_Pow(self, expr, rational=False): + return self._hprint_Pow(expr, rational=rational, sqrt='mpmath.sqrt') + + def _print_Integral(self, e): + integration_vars, limits = _unpack_integral_limits(e) + + return "{}(lambda {}: {}, {})".format( + self._module_format("mpmath.quad"), + ", ".join(map(self._print, integration_vars)), + self._print(e.args[0]), + ", ".join("(%s, %s)" % tuple(map(self._print, l)) for l in limits)) + + + def _print_Derivative_zeta(self, args, seq_orders): + arg, = args + deriv_order, = seq_orders + return '{}({}, derivative={})'.format( + self._module_format('mpmath.zeta'), + self._print(arg), deriv_order + ) + + +for k in MpmathPrinter._kf: + setattr(MpmathPrinter, '_print_%s' % k, _print_known_func) + +for k in _known_constants_mpmath: + setattr(MpmathPrinter, '_print_%s' % k, _print_known_const) + + +class SymPyPrinter(AbstractPythonCodePrinter): + + language = "Python with SymPy" + + _default_settings = dict( + AbstractPythonCodePrinter._default_settings, + strict=False # any class name will per definition be what we target in SymPyPrinter. + ) + + def _print_Function(self, expr): + mod = expr.func.__module__ or '' + return '%s(%s)' % (self._module_format(mod + ('.' if mod else '') + expr.func.__name__), + ', '.join((self._print(arg) for arg in expr.args))) + + def _print_Pow(self, expr, rational=False): + return self._hprint_Pow(expr, rational=rational, sqrt='sympy.sqrt') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/python.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/python.py new file mode 100644 index 0000000000000000000000000000000000000000..2f6862574d99db90f289de65144c7122ed2d731a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/python.py @@ -0,0 +1,92 @@ +import keyword as kw +import sympy +from .repr import ReprPrinter +from .str import StrPrinter + +# A list of classes that should be printed using StrPrinter +STRPRINT = ("Add", "Infinity", "Integer", "Mul", "NegativeInfinity", "Pow") + + +class PythonPrinter(ReprPrinter, StrPrinter): + """A printer which converts an expression into its Python interpretation.""" + + def __init__(self, settings=None): + super().__init__(settings) + self.symbols = [] + self.functions = [] + + # Create print methods for classes that should use StrPrinter instead + # of ReprPrinter. + for name in STRPRINT: + f_name = "_print_%s" % name + f = getattr(StrPrinter, f_name) + setattr(PythonPrinter, f_name, f) + + def _print_Function(self, expr): + func = expr.func.__name__ + if not hasattr(sympy, func) and func not in self.functions: + self.functions.append(func) + return StrPrinter._print_Function(self, expr) + + # procedure (!) for defining symbols which have be defined in print_python() + def _print_Symbol(self, expr): + symbol = self._str(expr) + if symbol not in self.symbols: + self.symbols.append(symbol) + return StrPrinter._print_Symbol(self, expr) + + def _print_module(self, expr): + raise ValueError('Modules in the expression are unacceptable') + + +def python(expr, **settings): + """Return Python interpretation of passed expression + (can be passed to the exec() function without any modifications)""" + + printer = PythonPrinter(settings) + exprp = printer.doprint(expr) + + result = '' + # Returning found symbols and functions + renamings = {} + for symbolname in printer.symbols: + # Remove curly braces from subscripted variables + if '{' in symbolname: + newsymbolname = symbolname.replace('{', '').replace('}', '') + renamings[sympy.Symbol(symbolname)] = newsymbolname + else: + newsymbolname = symbolname + + # Escape symbol names that are reserved Python keywords + if kw.iskeyword(newsymbolname): + while True: + newsymbolname += "_" + if (newsymbolname not in printer.symbols and + newsymbolname not in printer.functions): + renamings[sympy.Symbol( + symbolname)] = sympy.Symbol(newsymbolname) + break + result += newsymbolname + ' = Symbol(\'' + symbolname + '\')\n' + + for functionname in printer.functions: + newfunctionname = functionname + # Escape function names that are reserved Python keywords + if kw.iskeyword(newfunctionname): + while True: + newfunctionname += "_" + if (newfunctionname not in printer.symbols and + newfunctionname not in printer.functions): + renamings[sympy.Function( + functionname)] = sympy.Function(newfunctionname) + break + result += newfunctionname + ' = Function(\'' + functionname + '\')\n' + + if renamings: + exprp = expr.subs(renamings) + result += 'e = ' + printer._str(exprp) + return result + + +def print_python(expr, **settings): + """Print output of python() function""" + print(python(expr, **settings)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/pytorch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/pytorch.py new file mode 100644 index 0000000000000000000000000000000000000000..0e8ff01856fa1dce7f8e786065a32bb74d987254 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/pytorch.py @@ -0,0 +1,297 @@ + +from sympy.printing.pycode import AbstractPythonCodePrinter, ArrayPrinter +from sympy.matrices.expressions import MatrixExpr +from sympy.core.mul import Mul +from sympy.printing.precedence import PRECEDENCE +from sympy.external import import_module +from sympy.codegen.cfunctions import Sqrt +from sympy import S +from sympy import Integer + +import sympy + +torch = import_module('torch') + + +class TorchPrinter(ArrayPrinter, AbstractPythonCodePrinter): + + printmethod = "_torchcode" + + mapping = { + sympy.Abs: "torch.abs", + sympy.sign: "torch.sign", + + # XXX May raise error for ints. + sympy.ceiling: "torch.ceil", + sympy.floor: "torch.floor", + sympy.log: "torch.log", + sympy.exp: "torch.exp", + Sqrt: "torch.sqrt", + sympy.cos: "torch.cos", + sympy.acos: "torch.acos", + sympy.sin: "torch.sin", + sympy.asin: "torch.asin", + sympy.tan: "torch.tan", + sympy.atan: "torch.atan", + sympy.atan2: "torch.atan2", + # XXX Also may give NaN for complex results. + sympy.cosh: "torch.cosh", + sympy.acosh: "torch.acosh", + sympy.sinh: "torch.sinh", + sympy.asinh: "torch.asinh", + sympy.tanh: "torch.tanh", + sympy.atanh: "torch.atanh", + sympy.Pow: "torch.pow", + + sympy.re: "torch.real", + sympy.im: "torch.imag", + sympy.arg: "torch.angle", + + # XXX May raise error for ints and complexes + sympy.erf: "torch.erf", + sympy.loggamma: "torch.lgamma", + + sympy.Eq: "torch.eq", + sympy.Ne: "torch.ne", + sympy.StrictGreaterThan: "torch.gt", + sympy.StrictLessThan: "torch.lt", + sympy.LessThan: "torch.le", + sympy.GreaterThan: "torch.ge", + + sympy.And: "torch.logical_and", + sympy.Or: "torch.logical_or", + sympy.Not: "torch.logical_not", + sympy.Max: "torch.max", + sympy.Min: "torch.min", + + # Matrices + sympy.MatAdd: "torch.add", + sympy.HadamardProduct: "torch.mul", + sympy.Trace: "torch.trace", + + # XXX May raise error for integer matrices. + sympy.Determinant: "torch.det", + } + + _default_settings = dict( + AbstractPythonCodePrinter._default_settings, + torch_version=None, + requires_grad=False, + dtype="torch.float64", + ) + + def __init__(self, settings=None): + super().__init__(settings) + + version = self._settings['torch_version'] + self.requires_grad = self._settings['requires_grad'] + self.dtype = self._settings['dtype'] + if version is None and torch: + version = torch.__version__ + self.torch_version = version + + def _print_Function(self, expr): + + op = self.mapping.get(type(expr), None) + if op is None: + return super()._print_Basic(expr) + children = [self._print(arg) for arg in expr.args] + if len(children) == 1: + return "%s(%s)" % ( + self._module_format(op), + children[0] + ) + else: + return self._expand_fold_binary_op(op, children) + + # mirrors the tensorflow version + _print_Expr = _print_Function + _print_Application = _print_Function + _print_MatrixExpr = _print_Function + _print_Relational = _print_Function + _print_Not = _print_Function + _print_And = _print_Function + _print_Or = _print_Function + _print_HadamardProduct = _print_Function + _print_Trace = _print_Function + _print_Determinant = _print_Function + + def _print_Inverse(self, expr): + return '{}({})'.format(self._module_format("torch.linalg.inv"), + self._print(expr.args[0])) + + def _print_Transpose(self, expr): + if expr.arg.is_Matrix and expr.arg.shape[0] == expr.arg.shape[1]: + # For square matrices, we can use the .t() method + return "{}({}).t()".format("torch.transpose", self._print(expr.arg)) + else: + # For non-square matrices or more general cases + # transpose first and second dimensions (typical matrix transpose) + return "{}.permute({})".format( + self._print(expr.arg), + ", ".join([str(i) for i in range(len(expr.arg.shape))])[::-1] + ) + + def _print_PermuteDims(self, expr): + return "%s.permute(%s)" % ( + self._print(expr.expr), + ", ".join(str(i) for i in expr.permutation.array_form) + ) + + def _print_Derivative(self, expr): + # this version handles multi-variable and mixed partial derivatives. The tensorflow version does not. + variables = expr.variables + expr_arg = expr.expr + + # Handle multi-variable or repeated derivatives + if len(variables) > 1 or ( + len(variables) == 1 and not isinstance(variables[0], tuple) and variables.count(variables[0]) > 1): + result = self._print(expr_arg) + var_groups = {} + + # Group variables by base symbol + for var in variables: + if isinstance(var, tuple): + base_var, order = var + var_groups[base_var] = var_groups.get(base_var, 0) + order + else: + var_groups[var] = var_groups.get(var, 0) + 1 + + # Apply gradients in sequence + for var, order in var_groups.items(): + for _ in range(order): + result = "torch.autograd.grad({}, {}, create_graph=True)[0]".format(result, self._print(var)) + return result + + # Handle single variable case + if len(variables) == 1: + variable = variables[0] + if isinstance(variable, tuple) and len(variable) == 2: + base_var, order = variable + if not isinstance(order, Integer): raise NotImplementedError("Only integer orders are supported") + result = self._print(expr_arg) + for _ in range(order): + result = "torch.autograd.grad({}, {}, create_graph=True)[0]".format(result, self._print(base_var)) + return result + return "torch.autograd.grad({}, {})[0]".format(self._print(expr_arg), self._print(variable)) + + return self._print(expr_arg) # Empty variables case + + def _print_Piecewise(self, expr): + from sympy import Piecewise + e, cond = expr.args[0].args + if len(expr.args) == 1: + return '{}({}, {}, {})'.format( + self._module_format("torch.where"), + self._print(cond), + self._print(e), + 0) + + return '{}({}, {}, {})'.format( + self._module_format("torch.where"), + self._print(cond), + self._print(e), + self._print(Piecewise(*expr.args[1:]))) + + def _print_Pow(self, expr): + # XXX May raise error for + # int**float or int**complex or float**complex + base, exp = expr.args + if expr.exp == S.Half: + return "{}({})".format( + self._module_format("torch.sqrt"), self._print(base)) + return "{}({}, {})".format( + self._module_format("torch.pow"), + self._print(base), self._print(exp)) + + def _print_MatMul(self, expr): + # Separate matrix and scalar arguments + mat_args = [arg for arg in expr.args if isinstance(arg, MatrixExpr)] + args = [arg for arg in expr.args if arg not in mat_args] + # Handle scalar multipliers if present + if args: + return "%s*%s" % ( + self.parenthesize(Mul.fromiter(args), PRECEDENCE["Mul"]), + self._expand_fold_binary_op("torch.matmul", mat_args) + ) + else: + return self._expand_fold_binary_op("torch.matmul", mat_args) + + def _print_MatPow(self, expr): + return self._expand_fold_binary_op("torch.mm", [expr.base]*expr.exp) + + def _print_MatrixBase(self, expr): + data = "[" + ", ".join(["[" + ", ".join([self._print(j) for j in i]) + "]" for i in expr.tolist()]) + "]" + params = [str(data)] + params.append(f"dtype={self.dtype}") + if self.requires_grad: + params.append("requires_grad=True") + + return "{}({})".format( + self._module_format("torch.tensor"), + ", ".join(params) + ) + + def _print_isnan(self, expr): + return f'torch.isnan({self._print(expr.args[0])})' + + def _print_isinf(self, expr): + return f'torch.isinf({self._print(expr.args[0])})' + + def _print_Identity(self, expr): + if all(dim.is_Integer for dim in expr.shape): + return "{}({})".format( + self._module_format("torch.eye"), + self._print(expr.shape[0]) + ) + else: + # For symbolic dimensions, fall back to a more general approach + return "{}({}, {})".format( + self._module_format("torch.eye"), + self._print(expr.shape[0]), + self._print(expr.shape[1]) + ) + + def _print_ZeroMatrix(self, expr): + return "{}({})".format( + self._module_format("torch.zeros"), + self._print(expr.shape) + ) + + def _print_OneMatrix(self, expr): + return "{}({})".format( + self._module_format("torch.ones"), + self._print(expr.shape) + ) + + def _print_conjugate(self, expr): + return f"{self._module_format('torch.conj')}({self._print(expr.args[0])})" + + def _print_ImaginaryUnit(self, expr): + return "1j" # uses the Python built-in 1j notation for the imaginary unit + + def _print_Heaviside(self, expr): + args = [self._print(expr.args[0]), "0.5"] + if len(expr.args) > 1: + args[1] = self._print(expr.args[1]) + return f"{self._module_format('torch.heaviside')}({args[0]}, {args[1]})" + + def _print_gamma(self, expr): + return f"{self._module_format('torch.special.gamma')}({self._print(expr.args[0])})" + + def _print_polygamma(self, expr): + if expr.args[0] == S.Zero: + return f"{self._module_format('torch.special.digamma')}({self._print(expr.args[1])})" + else: + raise NotImplementedError("PyTorch only supports digamma (0th order polygamma)") + + _module = "torch" + _einsum = "einsum" + _add = "add" + _transpose = "t" + _ones = "ones" + _zeros = "zeros" + +def torch_code(expr, requires_grad=False, dtype="torch.float64", **settings): + printer = TorchPrinter(settings={'requires_grad': requires_grad, 'dtype': dtype}) + return printer.doprint(expr, **settings) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/rcode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/rcode.py new file mode 100644 index 0000000000000000000000000000000000000000..3107e6e94d5c5acf0b2dc063e4a83af6970f6576 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/rcode.py @@ -0,0 +1,402 @@ +""" +R code printer + +The RCodePrinter converts single SymPy expressions into single R expressions, +using the functions defined in math.h where possible. + + + +""" + +from __future__ import annotations +from typing import Any + +from sympy.core.numbers import equal_valued +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import precedence, PRECEDENCE +from sympy.sets.fancysets import Range + +# dictionary mapping SymPy function to (argument_conditions, C_function). +# Used in RCodePrinter._print_Function(self) +known_functions = { + #"Abs": [(lambda x: not x.is_integer, "fabs")], + "Abs": "abs", + "sin": "sin", + "cos": "cos", + "tan": "tan", + "asin": "asin", + "acos": "acos", + "atan": "atan", + "atan2": "atan2", + "exp": "exp", + "log": "log", + "erf": "erf", + "sinh": "sinh", + "cosh": "cosh", + "tanh": "tanh", + "asinh": "asinh", + "acosh": "acosh", + "atanh": "atanh", + "floor": "floor", + "ceiling": "ceiling", + "sign": "sign", + "Max": "max", + "Min": "min", + "factorial": "factorial", + "gamma": "gamma", + "digamma": "digamma", + "trigamma": "trigamma", + "beta": "beta", + "sqrt": "sqrt", # To enable automatic rewrite +} + +# These are the core reserved words in the R language. Taken from: +# https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Reserved-words + +reserved_words = ['if', + 'else', + 'repeat', + 'while', + 'function', + 'for', + 'in', + 'next', + 'break', + 'TRUE', + 'FALSE', + 'NULL', + 'Inf', + 'NaN', + 'NA', + 'NA_integer_', + 'NA_real_', + 'NA_complex_', + 'NA_character_', + 'volatile'] + + +class RCodePrinter(CodePrinter): + """A printer to convert SymPy expressions to strings of R code""" + printmethod = "_rcode" + language = "R" + + _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{ + 'precision': 15, + 'user_functions': {}, + 'contract': True, + 'dereference': set(), + }) + _operators = { + 'and': '&', + 'or': '|', + 'not': '!', + } + + _relationals: dict[str, str] = {} + + def __init__(self, settings={}): + CodePrinter.__init__(self, settings) + self.known_functions = dict(known_functions) + userfuncs = settings.get('user_functions', {}) + self.known_functions.update(userfuncs) + self._dereference = set(settings.get('dereference', [])) + self.reserved_words = set(reserved_words) + + def _rate_index_position(self, p): + return p*5 + + def _get_statement(self, codestring): + return "%s;" % codestring + + def _get_comment(self, text): + return "// {}".format(text) + + def _declare_number_const(self, name, value): + return "{} = {};".format(name, value) + + def _format_code(self, lines): + return self.indent_code(lines) + + def _traverse_matrix_indices(self, mat): + rows, cols = mat.shape + return ((i, j) for i in range(rows) for j in range(cols)) + + def _get_loop_opening_ending(self, indices): + """Returns a tuple (open_lines, close_lines) containing lists of codelines + """ + open_lines = [] + close_lines = [] + loopstart = "for (%(var)s in %(start)s:%(end)s){" + for i in indices: + # R arrays start at 1 and end at dimension + open_lines.append(loopstart % { + 'var': self._print(i.label), + 'start': self._print(i.lower+1), + 'end': self._print(i.upper + 1)}) + close_lines.append("}") + return open_lines, close_lines + + def _print_Pow(self, expr): + if "Pow" in self.known_functions: + return self._print_Function(expr) + PREC = precedence(expr) + if equal_valued(expr.exp, -1): + return '1.0/%s' % (self.parenthesize(expr.base, PREC)) + elif equal_valued(expr.exp, 0.5): + return 'sqrt(%s)' % self._print(expr.base) + else: + return '%s^%s' % (self.parenthesize(expr.base, PREC), + self.parenthesize(expr.exp, PREC)) + + + def _print_Rational(self, expr): + p, q = int(expr.p), int(expr.q) + return '%d.0/%d.0' % (p, q) + + def _print_Indexed(self, expr): + inds = [ self._print(i) for i in expr.indices ] + return "%s[%s]" % (self._print(expr.base.label), ", ".join(inds)) + + def _print_Exp1(self, expr): + return "exp(1)" + + def _print_Pi(self, expr): + return 'pi' + + def _print_Infinity(self, expr): + return 'Inf' + + def _print_NegativeInfinity(self, expr): + return '-Inf' + + def _print_Assignment(self, expr): + from sympy.codegen.ast import Assignment + + from sympy.matrices.expressions.matexpr import MatrixSymbol + from sympy.tensor.indexed import IndexedBase + lhs = expr.lhs + rhs = expr.rhs + # We special case assignments that take multiple lines + #if isinstance(expr.rhs, Piecewise): + # from sympy.functions.elementary.piecewise import Piecewise + # # Here we modify Piecewise so each expression is now + # # an Assignment, and then continue on the print. + # expressions = [] + # conditions = [] + # for (e, c) in rhs.args: + # expressions.append(Assignment(lhs, e)) + # conditions.append(c) + # temp = Piecewise(*zip(expressions, conditions)) + # return self._print(temp) + #elif isinstance(lhs, MatrixSymbol): + if isinstance(lhs, MatrixSymbol): + # Here we form an Assignment for each element in the array, + # printing each one. + lines = [] + for (i, j) in self._traverse_matrix_indices(lhs): + temp = Assignment(lhs[i, j], rhs[i, j]) + code0 = self._print(temp) + lines.append(code0) + return "\n".join(lines) + elif self._settings["contract"] and (lhs.has(IndexedBase) or + rhs.has(IndexedBase)): + # Here we check if there is looping to be done, and if so + # print the required loops. + return self._doprint_loops(rhs, lhs) + else: + lhs_code = self._print(lhs) + rhs_code = self._print(rhs) + return self._get_statement("%s = %s" % (lhs_code, rhs_code)) + + def _print_Piecewise(self, expr): + # This method is called only for inline if constructs + # Top level piecewise is handled in doprint() + if expr.args[-1].cond == True: + last_line = "%s" % self._print(expr.args[-1].expr) + else: + last_line = "ifelse(%s,%s,NA)" % (self._print(expr.args[-1].cond), self._print(expr.args[-1].expr)) + code=last_line + for e, c in reversed(expr.args[:-1]): + code= "ifelse(%s,%s," % (self._print(c), self._print(e))+code+")" + return(code) + + def _print_ITE(self, expr): + from sympy.functions import Piecewise + return self._print(expr.rewrite(Piecewise)) + + def _print_MatrixElement(self, expr): + return "{}[{}]".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"], + strict=True), expr.j + expr.i*expr.parent.shape[1]) + + def _print_Symbol(self, expr): + name = super()._print_Symbol(expr) + if expr in self._dereference: + return '(*{})'.format(name) + else: + return name + + def _print_Relational(self, expr): + lhs_code = self._print(expr.lhs) + rhs_code = self._print(expr.rhs) + op = expr.rel_op + return "{} {} {}".format(lhs_code, op, rhs_code) + + def _print_AugmentedAssignment(self, expr): + lhs_code = self._print(expr.lhs) + op = expr.op + rhs_code = self._print(expr.rhs) + return "{} {} {};".format(lhs_code, op, rhs_code) + + def _print_For(self, expr): + target = self._print(expr.target) + if isinstance(expr.iterable, Range): + start, stop, step = expr.iterable.args + else: + raise NotImplementedError("Only iterable currently supported is Range") + body = self._print(expr.body) + return 'for({target} in seq(from={start}, to={stop}, by={step}){{\n{body}\n}}'.format(target=target, start=start, + stop=stop-1, step=step, body=body) + + + def indent_code(self, code): + """Accepts a string of code or a list of code lines""" + + if isinstance(code, str): + code_lines = self.indent_code(code.splitlines(True)) + return ''.join(code_lines) + + tab = " " + inc_token = ('{', '(', '{\n', '(\n') + dec_token = ('}', ')') + + code = [ line.lstrip(' \t') for line in code ] + + increase = [ int(any(map(line.endswith, inc_token))) for line in code ] + decrease = [ int(any(map(line.startswith, dec_token))) + for line in code ] + + pretty = [] + level = 0 + for n, line in enumerate(code): + if line in ('', '\n'): + pretty.append(line) + continue + level -= decrease[n] + pretty.append("%s%s" % (tab*level, line)) + level += increase[n] + return pretty + + +def rcode(expr, assign_to=None, **settings): + """Converts an expr to a string of r code + + Parameters + ========== + + expr : Expr + A SymPy expression to be converted. + assign_to : optional + When given, the argument is used as the name of the variable to which + the expression is assigned. Can be a string, ``Symbol``, + ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of + line-wrapping, or for expressions that generate multi-line statements. + precision : integer, optional + The precision for numbers such as pi [default=15]. + user_functions : dict, optional + A dictionary where the keys are string representations of either + ``FunctionClass`` or ``UndefinedFunction`` instances and the values + are their desired R string representations. Alternatively, the + dictionary value can be a list of tuples i.e. [(argument_test, + rfunction_string)] or [(argument_test, rfunction_formater)]. See below + for examples. + human : bool, optional + If True, the result is a single string that may contain some constant + declarations for the number symbols. If False, the same information is + returned in a tuple of (symbols_to_declare, not_supported_functions, + code_text). [default=True]. + contract: bool, optional + If True, ``Indexed`` instances are assumed to obey tensor contraction + rules and the corresponding nested loops over indices are generated. + Setting contract=False will not generate loops, instead the user is + responsible to provide values for the indices in the code. + [default=True]. + + Examples + ======== + + >>> from sympy import rcode, symbols, Rational, sin, ceiling, Abs, Function + >>> x, tau = symbols("x, tau") + >>> rcode((2*tau)**Rational(7, 2)) + '8*sqrt(2)*tau^(7.0/2.0)' + >>> rcode(sin(x), assign_to="s") + 's = sin(x);' + + Simple custom printing can be defined for certain types by passing a + dictionary of {"type" : "function"} to the ``user_functions`` kwarg. + Alternatively, the dictionary value can be a list of tuples i.e. + [(argument_test, cfunction_string)]. + + >>> custom_functions = { + ... "ceiling": "CEIL", + ... "Abs": [(lambda x: not x.is_integer, "fabs"), + ... (lambda x: x.is_integer, "ABS")], + ... "func": "f" + ... } + >>> func = Function('func') + >>> rcode(func(Abs(x) + ceiling(x)), user_functions=custom_functions) + 'f(fabs(x) + CEIL(x))' + + or if the R-function takes a subset of the original arguments: + + >>> rcode(2**x + 3**x, user_functions={'Pow': [ + ... (lambda b, e: b == 2, lambda b, e: 'exp2(%s)' % e), + ... (lambda b, e: b != 2, 'pow')]}) + 'exp2(x) + pow(3, x)' + + ``Piecewise`` expressions are converted into conditionals. If an + ``assign_to`` variable is provided an if statement is created, otherwise + the ternary operator is used. Note that if the ``Piecewise`` lacks a + default term, represented by ``(expr, True)`` then an error will be thrown. + This is to prevent generating an expression that may not evaluate to + anything. + + >>> from sympy import Piecewise + >>> expr = Piecewise((x + 1, x > 0), (x, True)) + >>> print(rcode(expr, assign_to=tau)) + tau = ifelse(x > 0,x + 1,x); + + Support for loops is provided through ``Indexed`` types. With + ``contract=True`` these expressions will be turned into loops, whereas + ``contract=False`` will just print the assignment expression that should be + looped over: + + >>> from sympy import Eq, IndexedBase, Idx + >>> len_y = 5 + >>> y = IndexedBase('y', shape=(len_y,)) + >>> t = IndexedBase('t', shape=(len_y,)) + >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) + >>> i = Idx('i', len_y-1) + >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) + >>> rcode(e.rhs, assign_to=e.lhs, contract=False) + 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' + + Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions + must be provided to ``assign_to``. Note that any expression that can be + generated normally can also exist inside a Matrix: + + >>> from sympy import Matrix, MatrixSymbol + >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) + >>> A = MatrixSymbol('A', 3, 1) + >>> print(rcode(mat, A)) + A[0] = x^2; + A[1] = ifelse(x > 0,x + 1,x); + A[2] = sin(x); + + """ + + return RCodePrinter(settings).doprint(expr, assign_to) + + +def print_rcode(expr, **settings): + """Prints R representation of the given expression.""" + print(rcode(expr, **settings)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/repr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/repr.py new file mode 100644 index 0000000000000000000000000000000000000000..0a4b756abbab77c3eb0fd77ee1f0bd97382c36fb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/repr.py @@ -0,0 +1,339 @@ +""" +A Printer for generating executable code. + +The most important function here is srepr that returns a string so that the +relation eval(srepr(expr))=expr holds in an appropriate environment. +""" + +from __future__ import annotations +from typing import Any + +from sympy.core.function import AppliedUndef +from sympy.core.mul import Mul +from mpmath.libmp import repr_dps, to_str as mlib_to_str + +from .printer import Printer, print_function + + +class ReprPrinter(Printer): + printmethod = "_sympyrepr" + + _default_settings: dict[str, Any] = { + "order": None, + "perm_cyclic" : True, + } + + def reprify(self, args, sep): + """ + Prints each item in `args` and joins them with `sep`. + """ + return sep.join([self.doprint(item) for item in args]) + + def emptyPrinter(self, expr): + """ + The fallback printer. + """ + if isinstance(expr, str): + return expr + elif hasattr(expr, "__srepr__"): + return expr.__srepr__() + elif hasattr(expr, "args") and hasattr(expr.args, "__iter__"): + l = [] + for o in expr.args: + l.append(self._print(o)) + return expr.__class__.__name__ + '(%s)' % ', '.join(l) + elif hasattr(expr, "__module__") and hasattr(expr, "__name__"): + return "<'%s.%s'>" % (expr.__module__, expr.__name__) + else: + return str(expr) + + def _print_Add(self, expr, order=None): + args = self._as_ordered_terms(expr, order=order) + args = map(self._print, args) + clsname = type(expr).__name__ + return clsname + "(%s)" % ", ".join(args) + + def _print_Cycle(self, expr): + return expr.__repr__() + + def _print_Permutation(self, expr): + from sympy.combinatorics.permutations import Permutation, Cycle + from sympy.utilities.exceptions import sympy_deprecation_warning + + perm_cyclic = Permutation.print_cyclic + if perm_cyclic is not None: + sympy_deprecation_warning( + f""" + Setting Permutation.print_cyclic is deprecated. Instead use + init_printing(perm_cyclic={perm_cyclic}). + """, + deprecated_since_version="1.6", + active_deprecations_target="deprecated-permutation-print_cyclic", + stacklevel=7, + ) + else: + perm_cyclic = self._settings.get("perm_cyclic", True) + + if perm_cyclic: + if not expr.size: + return 'Permutation()' + # before taking Cycle notation, see if the last element is + # a singleton and move it to the head of the string + s = Cycle(expr)(expr.size - 1).__repr__()[len('Cycle'):] + last = s.rfind('(') + if not last == 0 and ',' not in s[last:]: + s = s[last:] + s[:last] + return 'Permutation%s' %s + else: + s = expr.support() + if not s: + if expr.size < 5: + return 'Permutation(%s)' % str(expr.array_form) + return 'Permutation([], size=%s)' % expr.size + trim = str(expr.array_form[:s[-1] + 1]) + ', size=%s' % expr.size + use = full = str(expr.array_form) + if len(trim) < len(full): + use = trim + return 'Permutation(%s)' % use + + def _print_Function(self, expr): + r = self._print(expr.func) + r += '(%s)' % ', '.join([self._print(a) for a in expr.args]) + return r + + def _print_Heaviside(self, expr): + # Same as _print_Function but uses pargs to suppress default value for + # 2nd arg. + r = self._print(expr.func) + r += '(%s)' % ', '.join([self._print(a) for a in expr.pargs]) + return r + + def _print_FunctionClass(self, expr): + if issubclass(expr, AppliedUndef): + return 'Function(%r)' % (expr.__name__) + else: + return expr.__name__ + + def _print_Half(self, expr): + return 'Rational(1, 2)' + + def _print_RationalConstant(self, expr): + return str(expr) + + def _print_AtomicExpr(self, expr): + return str(expr) + + def _print_NumberSymbol(self, expr): + return str(expr) + + def _print_Integer(self, expr): + return 'Integer(%i)' % expr.p + + def _print_Complexes(self, expr): + return 'Complexes' + + def _print_Integers(self, expr): + return 'Integers' + + def _print_Naturals(self, expr): + return 'Naturals' + + def _print_Naturals0(self, expr): + return 'Naturals0' + + def _print_Rationals(self, expr): + return 'Rationals' + + def _print_Reals(self, expr): + return 'Reals' + + def _print_EmptySet(self, expr): + return 'EmptySet' + + def _print_UniversalSet(self, expr): + return 'UniversalSet' + + def _print_EmptySequence(self, expr): + return 'EmptySequence' + + def _print_list(self, expr): + return "[%s]" % self.reprify(expr, ", ") + + def _print_dict(self, expr): + sep = ", " + dict_kvs = ["%s: %s" % (self.doprint(key), self.doprint(value)) for key, value in expr.items()] + return "{%s}" % sep.join(dict_kvs) + + def _print_set(self, expr): + if not expr: + return "set()" + return "{%s}" % self.reprify(expr, ", ") + + def _print_MatrixBase(self, expr): + # special case for some empty matrices + if (expr.rows == 0) ^ (expr.cols == 0): + return '%s(%s, %s, %s)' % (expr.__class__.__name__, + self._print(expr.rows), + self._print(expr.cols), + self._print([])) + l = [] + for i in range(expr.rows): + l.append([]) + for j in range(expr.cols): + l[-1].append(expr[i, j]) + return '%s(%s)' % (expr.__class__.__name__, self._print(l)) + + def _print_BooleanTrue(self, expr): + return "true" + + def _print_BooleanFalse(self, expr): + return "false" + + def _print_NaN(self, expr): + return "nan" + + def _print_Mul(self, expr, order=None): + if self.order not in ('old', 'none'): + args = expr.as_ordered_factors() + else: + # use make_args in case expr was something like -x -> x + args = Mul.make_args(expr) + + args = map(self._print, args) + clsname = type(expr).__name__ + return clsname + "(%s)" % ", ".join(args) + + def _print_Rational(self, expr): + return 'Rational(%s, %s)' % (self._print(expr.p), self._print(expr.q)) + + def _print_PythonRational(self, expr): + return "%s(%d, %d)" % (expr.__class__.__name__, expr.p, expr.q) + + def _print_Fraction(self, expr): + return 'Fraction(%s, %s)' % (self._print(expr.numerator), self._print(expr.denominator)) + + def _print_Float(self, expr): + r = mlib_to_str(expr._mpf_, repr_dps(expr._prec)) + return "%s('%s', precision=%i)" % (expr.__class__.__name__, r, expr._prec) + + def _print_Sum2(self, expr): + return "Sum2(%s, (%s, %s, %s))" % (self._print(expr.f), self._print(expr.i), + self._print(expr.a), self._print(expr.b)) + + def _print_Str(self, s): + return "%s(%s)" % (s.__class__.__name__, self._print(s.name)) + + def _print_Symbol(self, expr): + d = expr._assumptions_orig + # print the dummy_index like it was an assumption + if expr.is_Dummy: + d = d.copy() + d['dummy_index'] = expr.dummy_index + + if d == {}: + return "%s(%s)" % (expr.__class__.__name__, self._print(expr.name)) + else: + attr = ['%s=%s' % (k, v) for k, v in d.items()] + return "%s(%s, %s)" % (expr.__class__.__name__, + self._print(expr.name), ', '.join(attr)) + + def _print_CoordinateSymbol(self, expr): + d = expr._assumptions.generator + + if d == {}: + return "%s(%s, %s)" % ( + expr.__class__.__name__, + self._print(expr.coord_sys), + self._print(expr.index) + ) + else: + attr = ['%s=%s' % (k, v) for k, v in d.items()] + return "%s(%s, %s, %s)" % ( + expr.__class__.__name__, + self._print(expr.coord_sys), + self._print(expr.index), + ', '.join(attr) + ) + + def _print_Predicate(self, expr): + return "Q.%s" % expr.name + + def _print_AppliedPredicate(self, expr): + # will be changed to just expr.args when args overriding is removed + args = expr._args + return "%s(%s)" % (expr.__class__.__name__, self.reprify(args, ", ")) + + def _print_str(self, expr): + return repr(expr) + + def _print_tuple(self, expr): + if len(expr) == 1: + return "(%s,)" % self._print(expr[0]) + else: + return "(%s)" % self.reprify(expr, ", ") + + def _print_WildFunction(self, expr): + return "%s('%s')" % (expr.__class__.__name__, expr.name) + + def _print_AlgebraicNumber(self, expr): + return "%s(%s, %s)" % (expr.__class__.__name__, + self._print(expr.root), self._print(expr.coeffs())) + + def _print_PolyRing(self, ring): + return "%s(%s, %s, %s)" % (ring.__class__.__name__, + self._print(ring.symbols), self._print(ring.domain), self._print(ring.order)) + + def _print_FracField(self, field): + return "%s(%s, %s, %s)" % (field.__class__.__name__, + self._print(field.symbols), self._print(field.domain), self._print(field.order)) + + def _print_PolyElement(self, poly): + terms = list(poly.terms()) + terms.sort(key=poly.ring.order, reverse=True) + return "%s(%s, %s)" % (poly.__class__.__name__, self._print(poly.ring), self._print(terms)) + + def _print_FracElement(self, frac): + numer_terms = list(frac.numer.terms()) + numer_terms.sort(key=frac.field.order, reverse=True) + denom_terms = list(frac.denom.terms()) + denom_terms.sort(key=frac.field.order, reverse=True) + numer = self._print(numer_terms) + denom = self._print(denom_terms) + return "%s(%s, %s, %s)" % (frac.__class__.__name__, self._print(frac.field), numer, denom) + + def _print_FractionField(self, domain): + cls = domain.__class__.__name__ + field = self._print(domain.field) + return "%s(%s)" % (cls, field) + + def _print_PolynomialRingBase(self, ring): + cls = ring.__class__.__name__ + dom = self._print(ring.domain) + gens = ', '.join(map(self._print, ring.gens)) + order = str(ring.order) + if order != ring.default_order: + orderstr = ", order=" + order + else: + orderstr = "" + return "%s(%s, %s%s)" % (cls, dom, gens, orderstr) + + def _print_DMP(self, p): + cls = p.__class__.__name__ + rep = self._print(p.to_list()) + dom = self._print(p.dom) + return "%s(%s, %s)" % (cls, rep, dom) + + def _print_MonogenicFiniteExtension(self, ext): + # The expanded tree shown by srepr(ext.modulus) + # is not practical. + return "FiniteExtension(%s)" % str(ext.modulus) + + def _print_ExtensionElement(self, f): + rep = self._print(f.rep) + ext = self._print(f.ext) + return "ExtElem(%s, %s)" % (rep, ext) + +@print_function(ReprPrinter) +def srepr(expr, **settings): + """return expr in repr form""" + return ReprPrinter(settings).doprint(expr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/rust.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/rust.py new file mode 100644 index 0000000000000000000000000000000000000000..5bfd481bec6b7350df281accfb9b7a598cf05baa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/rust.py @@ -0,0 +1,637 @@ +""" +Rust code printer + +The `RustCodePrinter` converts SymPy expressions into Rust expressions. + +A complete code generator, which uses `rust_code` extensively, can be found +in `sympy.utilities.codegen`. The `codegen` module can be used to generate +complete source code files. + +""" + +# Possible Improvement +# +# * make sure we follow Rust Style Guidelines_ +# * make use of pattern matching +# * better support for reference +# * generate generic code and use trait to make sure they have specific methods +# * use crates_ to get more math support +# - num_ +# + BigInt_, BigUint_ +# + Complex_ +# + Rational64_, Rational32_, BigRational_ +# +# .. _crates: https://crates.io/ +# .. _Guidelines: https://github.com/rust-lang/rust/tree/master/src/doc/style +# .. _num: http://rust-num.github.io/num/num/ +# .. _BigInt: http://rust-num.github.io/num/num/bigint/struct.BigInt.html +# .. _BigUint: http://rust-num.github.io/num/num/bigint/struct.BigUint.html +# .. _Complex: http://rust-num.github.io/num/num/complex/struct.Complex.html +# .. _Rational32: http://rust-num.github.io/num/num/rational/type.Rational32.html +# .. _Rational64: http://rust-num.github.io/num/num/rational/type.Rational64.html +# .. _BigRational: http://rust-num.github.io/num/num/rational/type.BigRational.html + +from __future__ import annotations +from functools import reduce +import operator +from typing import Any + +from sympy.codegen.ast import ( + float32, float64, int32, + real, integer, bool_ +) +from sympy.core import S, Rational, Float, Lambda +from sympy.core.expr import Expr +from sympy.core.numbers import equal_valued +from sympy.functions.elementary.integers import ceiling, floor +from sympy.printing.codeprinter import CodePrinter +from sympy.printing.precedence import PRECEDENCE + +# Rust's methods for integer and float can be found at here : +# +# * `Rust - Primitive Type f64 `_ +# * `Rust - Primitive Type i64 `_ +# +# Function Style : +# +# 1. args[0].func(args[1:]), method with arguments +# 2. args[0].func(), method without arguments +# 3. args[1].func(), method without arguments (e.g. (e, x) => x.exp()) +# 4. func(args), function with arguments + +# dictionary mapping SymPy function to (argument_conditions, Rust_function). +# Used in RustCodePrinter._print_Function(self) + +class float_floor(floor): + """ + Same as `sympy.floor`, but mimics the Rust behavior of returning a float rather than an integer + """ + def _eval_is_integer(self): + return False + +class float_ceiling(ceiling): + """ + Same as `sympy.ceiling`, but mimics the Rust behavior of returning a float rather than an integer + """ + def _eval_is_integer(self): + return False + + +function_overrides = { + "floor": (floor, float_floor), + "ceiling": (ceiling, float_ceiling), +} + +# f64 method in Rust +known_functions = { + # "": "is_nan", + # "": "is_infinite", + # "": "is_finite", + # "": "is_normal", + # "": "classify", + "float_floor": "floor", + "float_ceiling": "ceil", + # "": "round", + # "": "trunc", + # "": "fract", + "Abs": "abs", + # "": "signum", + # "": "is_sign_positive", + # "": "is_sign_negative", + # "": "mul_add", + "Pow": [(lambda base, exp: equal_valued(exp, -1), "recip", 2), # 1.0/x + (lambda base, exp: equal_valued(exp, 0.5), "sqrt", 2), # x ** 0.5 + (lambda base, exp: equal_valued(exp, -0.5), "sqrt().recip", 2), # 1/(x ** 0.5) + (lambda base, exp: exp == Rational(1, 3), "cbrt", 2), # x ** (1/3) + (lambda base, exp: equal_valued(base, 2), "exp2", 3), # 2 ** x + (lambda base, exp: exp.is_integer, "powi", 1), # x ** y, for i32 + (lambda base, exp: not exp.is_integer, "powf", 1)], # x ** y, for f64 + "exp": [(lambda exp: True, "exp", 2)], # e ** x + "log": "ln", + # "": "log", # number.log(base) + # "": "log2", + # "": "log10", + # "": "to_degrees", + # "": "to_radians", + "Max": "max", + "Min": "min", + # "": "hypot", # (x**2 + y**2) ** 0.5 + "sin": "sin", + "cos": "cos", + "tan": "tan", + "asin": "asin", + "acos": "acos", + "atan": "atan", + "atan2": "atan2", + # "": "sin_cos", + # "": "exp_m1", # e ** x - 1 + # "": "ln_1p", # ln(1 + x) + "sinh": "sinh", + "cosh": "cosh", + "tanh": "tanh", + "asinh": "asinh", + "acosh": "acosh", + "atanh": "atanh", + "sqrt": "sqrt", # To enable automatic rewrites +} + +# i64 method in Rust +# known_functions_i64 = { +# "": "min_value", +# "": "max_value", +# "": "from_str_radix", +# "": "count_ones", +# "": "count_zeros", +# "": "leading_zeros", +# "": "trainling_zeros", +# "": "rotate_left", +# "": "rotate_right", +# "": "swap_bytes", +# "": "from_be", +# "": "from_le", +# "": "to_be", # to big endian +# "": "to_le", # to little endian +# "": "checked_add", +# "": "checked_sub", +# "": "checked_mul", +# "": "checked_div", +# "": "checked_rem", +# "": "checked_neg", +# "": "checked_shl", +# "": "checked_shr", +# "": "checked_abs", +# "": "saturating_add", +# "": "saturating_sub", +# "": "saturating_mul", +# "": "wrapping_add", +# "": "wrapping_sub", +# "": "wrapping_mul", +# "": "wrapping_div", +# "": "wrapping_rem", +# "": "wrapping_neg", +# "": "wrapping_shl", +# "": "wrapping_shr", +# "": "wrapping_abs", +# "": "overflowing_add", +# "": "overflowing_sub", +# "": "overflowing_mul", +# "": "overflowing_div", +# "": "overflowing_rem", +# "": "overflowing_neg", +# "": "overflowing_shl", +# "": "overflowing_shr", +# "": "overflowing_abs", +# "Pow": "pow", +# "Abs": "abs", +# "sign": "signum", +# "": "is_positive", +# "": "is_negnative", +# } + +# These are the core reserved words in the Rust language. Taken from: +# https://doc.rust-lang.org/reference/keywords.html + +reserved_words = ['abstract', + 'as', + 'async', + 'await', + 'become', + 'box', + 'break', + 'const', + 'continue', + 'crate', + 'do', + 'dyn', + 'else', + 'enum', + 'extern', + 'false', + 'final', + 'fn', + 'for', + 'gen', + 'if', + 'impl', + 'in', + 'let', + 'loop', + 'macro', + 'match', + 'mod', + 'move', + 'mut', + 'override', + 'priv', + 'pub', + 'ref', + 'return', + 'Self', + 'self', + 'static', + 'struct', + 'super', + 'trait', + 'true', + 'try', + 'type', + 'typeof', + 'unsafe', + 'unsized', + 'use', + 'virtual', + 'where', + 'while', + 'yield'] + + +class TypeCast(Expr): + """ + The type casting operator of the Rust language. + """ + + def __init__(self, expr, type_) -> None: + super().__init__() + self.explicit = expr.is_integer and type_ is not integer + self._assumptions = expr._assumptions + if self.explicit: + setattr(self, 'precedence', PRECEDENCE["Func"] + 10) + + @property + def expr(self): + return self.args[0] + + @property + def type_(self): + return self.args[1] + + def sort_key(self, order=None): + return self.args[0].sort_key(order=order) + + +class RustCodePrinter(CodePrinter): + """A printer to convert SymPy expressions to strings of Rust code""" + printmethod = "_rust_code" + language = "Rust" + + type_aliases = { + integer: int32, + real: float64, + } + + type_mappings = { + int32: 'i32', + float32: 'f32', + float64: 'f64', + bool_: 'bool' + } + + _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{ + 'precision': 17, + 'user_functions': {}, + 'contract': True, + 'dereference': set(), + }) + + def __init__(self, settings={}): + CodePrinter.__init__(self, settings) + self.known_functions = dict(known_functions) + userfuncs = settings.get('user_functions', {}) + self.known_functions.update(userfuncs) + self._dereference = set(settings.get('dereference', [])) + self.reserved_words = set(reserved_words) + self.function_overrides = function_overrides + + def _rate_index_position(self, p): + return p*5 + + def _get_statement(self, codestring): + return "%s;" % codestring + + def _get_comment(self, text): + return "// %s" % text + + def _declare_number_const(self, name, value): + type_ = self.type_mappings[self.type_aliases[real]] + return "const %s: %s = %s;" % (name, type_, value) + + def _format_code(self, lines): + return self.indent_code(lines) + + def _traverse_matrix_indices(self, mat): + rows, cols = mat.shape + return ((i, j) for i in range(rows) for j in range(cols)) + + def _get_loop_opening_ending(self, indices): + open_lines = [] + close_lines = [] + loopstart = "for %(var)s in %(start)s..%(end)s {" + for i in indices: + # Rust arrays start at 0 and end at dimension-1 + open_lines.append(loopstart % { + 'var': self._print(i), + 'start': self._print(i.lower), + 'end': self._print(i.upper + 1)}) + close_lines.append("}") + return open_lines, close_lines + + def _print_caller_var(self, expr): + if len(expr.args) > 1: + # for something like `sin(x + y + z)`, + # make sure we can get '(x + y + z).sin()' + # instead of 'x + y + z.sin()' + return '(' + self._print(expr) + ')' + elif expr.is_number: + return self._print(expr, _type=True) + else: + return self._print(expr) + + def _print_Function(self, expr): + """ + basic function for printing `Function` + + Function Style : + + 1. args[0].func(args[1:]), method with arguments + 2. args[0].func(), method without arguments + 3. args[1].func(), method without arguments (e.g. (e, x) => x.exp()) + 4. func(args), function with arguments + """ + + if expr.func.__name__ in self.known_functions: + cond_func = self.known_functions[expr.func.__name__] + func = None + style = 1 + if isinstance(cond_func, str): + func = cond_func + else: + for cond, func, style in cond_func: + if cond(*expr.args): + break + if func is not None: + if style == 1: + ret = "%(var)s.%(method)s(%(args)s)" % { + 'var': self._print_caller_var(expr.args[0]), + 'method': func, + 'args': self.stringify(expr.args[1:], ", ") if len(expr.args) > 1 else '' + } + elif style == 2: + ret = "%(var)s.%(method)s()" % { + 'var': self._print_caller_var(expr.args[0]), + 'method': func, + } + elif style == 3: + ret = "%(var)s.%(method)s()" % { + 'var': self._print_caller_var(expr.args[1]), + 'method': func, + } + else: + ret = "%(func)s(%(args)s)" % { + 'func': func, + 'args': self.stringify(expr.args, ", "), + } + return ret + elif hasattr(expr, '_imp_') and isinstance(expr._imp_, Lambda): + # inlined function + return self._print(expr._imp_(*expr.args)) + else: + return self._print_not_supported(expr) + + def _print_Mul(self, expr): + contains_floats = any(arg.is_real and not arg.is_integer for arg in expr.args) + if contains_floats: + expr = reduce(operator.mul,(self._cast_to_float(arg) if arg != -1 else arg for arg in expr.args)) + + return super()._print_Mul(expr) + + def _print_Add(self, expr, order=None): + contains_floats = any(arg.is_real and not arg.is_integer for arg in expr.args) + if contains_floats: + expr = reduce(operator.add, (self._cast_to_float(arg) for arg in expr.args)) + + return super()._print_Add(expr, order) + + def _print_Pow(self, expr): + if expr.base.is_integer and not expr.exp.is_integer: + expr = type(expr)(Float(expr.base), expr.exp) + return self._print(expr) + return self._print_Function(expr) + + def _print_TypeCast(self, expr): + if not expr.explicit: + return self._print(expr.expr) + else: + return self._print(expr.expr) + ' as %s' % self.type_mappings[self.type_aliases[expr.type_]] + + def _print_Float(self, expr, _type=False): + ret = super()._print_Float(expr) + if _type: + return ret + '_%s' % self.type_mappings[self.type_aliases[real]] + else: + return ret + + def _print_Integer(self, expr, _type=False): + ret = super()._print_Integer(expr) + if _type: + return ret + '_%s' % self.type_mappings[self.type_aliases[integer]] + else: + return ret + + def _print_Rational(self, expr): + p, q = int(expr.p), int(expr.q) + float_suffix = self.type_mappings[self.type_aliases[real]] + return '%d_%s/%d.0' % (p, float_suffix, q) + + def _print_Relational(self, expr): + if (expr.lhs.is_integer and not expr.rhs.is_integer) or (expr.rhs.is_integer and not expr.lhs.is_integer): + lhs = self._cast_to_float(expr.lhs) + rhs = self._cast_to_float(expr.rhs) + else: + lhs = expr.lhs + rhs = expr.rhs + lhs_code = self._print(lhs) + rhs_code = self._print(rhs) + op = expr.rel_op + return "{} {} {}".format(lhs_code, op, rhs_code) + + def _print_Indexed(self, expr): + # calculate index for 1d array + dims = expr.shape + elem = S.Zero + offset = S.One + for i in reversed(range(expr.rank)): + elem += expr.indices[i]*offset + offset *= dims[i] + return "%s[%s]" % (self._print(expr.base.label), self._print(elem)) + + def _print_Idx(self, expr): + return expr.label.name + + def _print_Dummy(self, expr): + return expr.name + + def _print_Exp1(self, expr, _type=False): + return "E" + + def _print_Pi(self, expr, _type=False): + return 'PI' + + def _print_Infinity(self, expr, _type=False): + return 'INFINITY' + + def _print_NegativeInfinity(self, expr, _type=False): + return 'NEG_INFINITY' + + def _print_BooleanTrue(self, expr, _type=False): + return "true" + + def _print_BooleanFalse(self, expr, _type=False): + return "false" + + def _print_bool(self, expr, _type=False): + return str(expr).lower() + + def _print_NaN(self, expr, _type=False): + return "NAN" + + def _print_Piecewise(self, expr): + if expr.args[-1].cond != True: + # We need the last conditional to be a True, otherwise the resulting + # function may not return a result. + raise ValueError("All Piecewise expressions must contain an " + "(expr, True) statement to be used as a default " + "condition. Without one, the generated " + "expression may not evaluate to anything under " + "some condition.") + lines = [] + + for i, (e, c) in enumerate(expr.args): + if i == 0: + lines.append("if (%s) {" % self._print(c)) + elif i == len(expr.args) - 1 and c == True: + lines[-1] += " else {" + else: + lines[-1] += " else if (%s) {" % self._print(c) + code0 = self._print(e) + lines.append(code0) + lines.append("}") + + if self._settings['inline']: + return " ".join(lines) + else: + return "\n".join(lines) + + def _print_ITE(self, expr): + from sympy.functions import Piecewise + return self._print(expr.rewrite(Piecewise, deep=False)) + + def _print_MatrixBase(self, A): + if A.cols == 1: + return "[%s]" % ", ".join(self._print(a) for a in A) + else: + raise ValueError("Full Matrix Support in Rust need Crates (https://crates.io/keywords/matrix).") + + def _print_SparseRepMatrix(self, mat): + # do not allow sparse matrices to be made dense + return self._print_not_supported(mat) + + def _print_MatrixElement(self, expr): + return "%s[%s]" % (expr.parent, + expr.j + expr.i*expr.parent.shape[1]) + + def _print_Symbol(self, expr): + + name = super()._print_Symbol(expr) + + if expr in self._dereference: + return '(*%s)' % name + else: + return name + + def _print_Assignment(self, expr): + from sympy.tensor.indexed import IndexedBase + lhs = expr.lhs + rhs = expr.rhs + if self._settings["contract"] and (lhs.has(IndexedBase) or + rhs.has(IndexedBase)): + # Here we check if there is looping to be done, and if so + # print the required loops. + return self._doprint_loops(rhs, lhs) + else: + lhs_code = self._print(lhs) + rhs_code = self._print(rhs) + return self._get_statement("%s = %s" % (lhs_code, rhs_code)) + + def _print_sign(self, expr): + arg = self._print(expr.args[0]) + return "(if (%s == 0.0) { 0.0 } else { (%s).signum() })" % (arg, arg) + + def _cast_to_float(self, expr): + if not expr.is_number: + return TypeCast(expr, real) + elif expr.is_integer: + return Float(expr) + return expr + + def _can_print(self, name): + """ Check if function ``name`` is either a known function or has its own + printing method. Used to check if rewriting is possible.""" + + # since the whole point of function_overrides is to enable proper printing, + # we presume they all are printable + + return name in self.known_functions or name in function_overrides or getattr(self, '_print_{}'.format(name), False) + + def _collect_functions(self, expr): + functions = set() + if isinstance(expr, Expr): + if expr.is_Function: + functions.add(expr.func) + for arg in expr.args: + functions = functions.union(self._collect_functions(arg)) + return functions + + def _rewrite_known_functions(self, expr): + if not isinstance(expr, Expr): + return expr + + expression_functions = self._collect_functions(expr) + rewriteable_functions = { + name: (target_f, required_fs) + for name, (target_f, required_fs) in self._rewriteable_functions.items() + if self._can_print(target_f) + and all(self._can_print(f) for f in required_fs) + } + for func in expression_functions: + target_f, _ = rewriteable_functions.get(func.__name__, (None, None)) + if target_f: + expr = expr.rewrite(target_f) + return expr + + def indent_code(self, code): + """Accepts a string of code or a list of code lines""" + + if isinstance(code, str): + code_lines = self.indent_code(code.splitlines(True)) + return ''.join(code_lines) + + tab = " " + inc_token = ('{', '(', '{\n', '(\n') + dec_token = ('}', ')') + + code = [ line.lstrip(' \t') for line in code ] + + increase = [ int(any(map(line.endswith, inc_token))) for line in code ] + decrease = [ int(any(map(line.startswith, dec_token))) + for line in code ] + + pretty = [] + level = 0 + for n, line in enumerate(code): + if line in ('', '\n'): + pretty.append(line) + continue + level -= decrease[n] + pretty.append("%s%s" % (tab*level, line)) + level += increase[n] + return pretty diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/smtlib.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/smtlib.py new file mode 100644 index 0000000000000000000000000000000000000000..8fa015c6198cb32837eb3a0d7fe9d61352da25ad --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/smtlib.py @@ -0,0 +1,583 @@ +import typing + +import sympy +from sympy.core import Add, Mul +from sympy.core import Symbol, Expr, Float, Rational, Integer, Basic +from sympy.core.function import UndefinedFunction, Function +from sympy.core.relational import Relational, Unequality, Equality, LessThan, GreaterThan, StrictLessThan, StrictGreaterThan +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import exp, log, Pow +from sympy.functions.elementary.hyperbolic import sinh, cosh, tanh +from sympy.functions.elementary.miscellaneous import Min, Max +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import sin, cos, tan, asin, acos, atan, atan2 +from sympy.logic.boolalg import And, Or, Xor, Implies, Boolean +from sympy.logic.boolalg import BooleanTrue, BooleanFalse, BooleanFunction, Not, ITE +from sympy.printing.printer import Printer +from sympy.sets import Interval +from mpmath.libmp.libmpf import prec_to_dps, to_str as mlib_to_str +from sympy.assumptions.assume import AppliedPredicate +from sympy.assumptions.relation.binrel import AppliedBinaryRelation +from sympy.assumptions.ask import Q +from sympy.assumptions.relation.equality import StrictGreaterThanPredicate, StrictLessThanPredicate, GreaterThanPredicate, LessThanPredicate, EqualityPredicate + + +class SMTLibPrinter(Printer): + printmethod = "_smtlib" + + # based on dReal, an automated reasoning tool for solving problems that can be encoded as first-order logic formulas over the real numbers. + # dReal's special strength is in handling problems that involve a wide range of nonlinear real functions. + _default_settings: dict = { + 'precision': None, + 'known_types': { + bool: 'Bool', + int: 'Int', + float: 'Real' + }, + 'known_constants': { + # pi: 'MY_VARIABLE_PI_DECLARED_ELSEWHERE', + }, + 'known_functions': { + Add: '+', + Mul: '*', + + Equality: '=', + LessThan: '<=', + GreaterThan: '>=', + StrictLessThan: '<', + StrictGreaterThan: '>', + + EqualityPredicate(): '=', + LessThanPredicate(): '<=', + GreaterThanPredicate(): '>=', + StrictLessThanPredicate(): '<', + StrictGreaterThanPredicate(): '>', + + exp: 'exp', + log: 'log', + Abs: 'abs', + sin: 'sin', + cos: 'cos', + tan: 'tan', + asin: 'arcsin', + acos: 'arccos', + atan: 'arctan', + atan2: 'arctan2', + sinh: 'sinh', + cosh: 'cosh', + tanh: 'tanh', + Min: 'min', + Max: 'max', + Pow: 'pow', + + And: 'and', + Or: 'or', + Xor: 'xor', + Not: 'not', + ITE: 'ite', + Implies: '=>', + } + } + + symbol_table: dict + + def __init__(self, settings: typing.Optional[dict] = None, + symbol_table=None): + settings = settings or {} + self.symbol_table = symbol_table or {} + Printer.__init__(self, settings) + self._precision = self._settings['precision'] + self._known_types = dict(self._settings['known_types']) + self._known_constants = dict(self._settings['known_constants']) + self._known_functions = dict(self._settings['known_functions']) + + for _ in self._known_types.values(): assert self._is_legal_name(_) + for _ in self._known_constants.values(): assert self._is_legal_name(_) + # for _ in self._known_functions.values(): assert self._is_legal_name(_) # +, *, <, >, etc. + + def _is_legal_name(self, s: str): + if not s: return False + if s[0].isnumeric(): return False + return all(_.isalnum() or _ == '_' for _ in s) + + def _s_expr(self, op: str, args: typing.Union[list, tuple]) -> str: + args_str = ' '.join( + a if isinstance(a, str) + else self._print(a) + for a in args + ) + return f'({op} {args_str})' + + def _print_Function(self, e): + if e in self._known_functions: + op = self._known_functions[e] + elif type(e) in self._known_functions: + op = self._known_functions[type(e)] + elif type(type(e)) == UndefinedFunction: + op = e.name + elif isinstance(e, AppliedBinaryRelation) and e.function in self._known_functions: + op = self._known_functions[e.function] + return self._s_expr(op, e.arguments) + else: + op = self._known_functions[e] # throw KeyError + + return self._s_expr(op, e.args) + + def _print_Relational(self, e: Relational): + return self._print_Function(e) + + def _print_BooleanFunction(self, e: BooleanFunction): + return self._print_Function(e) + + def _print_Expr(self, e: Expr): + return self._print_Function(e) + + def _print_Unequality(self, e: Unequality): + if type(e) in self._known_functions: + return self._print_Relational(e) # default + else: + eq_op = self._known_functions[Equality] + not_op = self._known_functions[Not] + return self._s_expr(not_op, [self._s_expr(eq_op, e.args)]) + + def _print_Piecewise(self, e: Piecewise): + def _print_Piecewise_recursive(args: typing.Union[list, tuple]): + e, c = args[0] + if len(args) == 1: + assert (c is True) or isinstance(c, BooleanTrue) + return self._print(e) + else: + ite = self._known_functions[ITE] + return self._s_expr(ite, [ + c, e, _print_Piecewise_recursive(args[1:]) + ]) + + return _print_Piecewise_recursive(e.args) + + def _print_Interval(self, e: Interval): + if e.start.is_infinite and e.end.is_infinite: + return '' + elif e.start.is_infinite != e.end.is_infinite: + raise ValueError(f'One-sided intervals (`{e}`) are not supported in SMT.') + else: + return f'[{e.start}, {e.end}]' + + def _print_AppliedPredicate(self, e: AppliedPredicate): + if e.function == Q.positive: + rel = Q.gt(e.arguments[0],0) + elif e.function == Q.negative: + rel = Q.lt(e.arguments[0], 0) + elif e.function == Q.zero: + rel = Q.eq(e.arguments[0], 0) + elif e.function == Q.nonpositive: + rel = Q.le(e.arguments[0], 0) + elif e.function == Q.nonnegative: + rel = Q.ge(e.arguments[0], 0) + elif e.function == Q.nonzero: + rel = Q.ne(e.arguments[0], 0) + else: + raise ValueError(f"Predicate (`{e}`) is not handled.") + + return self._print_AppliedBinaryRelation(rel) + + def _print_AppliedBinaryRelation(self, e: AppliedPredicate): + if e.function == Q.ne: + return self._print_Unequality(Unequality(*e.arguments)) + else: + return self._print_Function(e) + + # todo: Sympy does not support quantifiers yet as of 2022, but quantifiers can be handy in SMT. + # For now, users can extend this class and build in their own quantifier support. + # See `test_quantifier_extensions()` in test_smtlib.py for an example of how this might look. + + # def _print_ForAll(self, e: ForAll): + # return self._s('forall', [ + # self._s('', [ + # self._s(sym.name, [self._type_name(sym), Interval(start, end)]) + # for sym, start, end in e.limits + # ]), + # e.function + # ]) + + def _print_BooleanTrue(self, x: BooleanTrue): + return 'true' + + def _print_BooleanFalse(self, x: BooleanFalse): + return 'false' + + def _print_Float(self, x: Float): + dps = prec_to_dps(x._prec) + str_real = mlib_to_str(x._mpf_, dps, strip_zeros=True, min_fixed=None, max_fixed=None) + + if 'e' in str_real: + (mant, exp) = str_real.split('e') + + if exp[0] == '+': + exp = exp[1:] + + mul = self._known_functions[Mul] + pow = self._known_functions[Pow] + + return r"(%s %s (%s 10 %s))" % (mul, mant, pow, exp) + elif str_real in ["+inf", "-inf"]: + raise ValueError("Infinite values are not supported in SMT.") + else: + return str_real + + def _print_float(self, x: float): + return self._print(Float(x)) + + def _print_Rational(self, x: Rational): + return self._s_expr('/', [x.p, x.q]) + + def _print_Integer(self, x: Integer): + assert x.q == 1 + return str(x.p) + + def _print_int(self, x: int): + return str(x) + + def _print_Symbol(self, x: Symbol): + assert self._is_legal_name(x.name) + return x.name + + def _print_NumberSymbol(self, x): + name = self._known_constants.get(x) + if name: + return name + else: + f = x.evalf(self._precision) if self._precision else x.evalf() + return self._print_Float(f) + + def _print_UndefinedFunction(self, x): + assert self._is_legal_name(x.name) + return x.name + + def _print_Exp1(self, x): + return ( + self._print_Function(exp(1, evaluate=False)) + if exp in self._known_functions else + self._print_NumberSymbol(x) + ) + + def emptyPrinter(self, expr): + raise NotImplementedError(f'Cannot convert `{repr(expr)}` of type `{type(expr)}` to SMT.') + + +def smtlib_code( + expr, + auto_assert=True, auto_declare=True, + precision=None, + symbol_table=None, + known_types=None, known_constants=None, known_functions=None, + prefix_expressions=None, suffix_expressions=None, + log_warn=None +): + r"""Converts ``expr`` to a string of smtlib code. + + Parameters + ========== + + expr : Expr | List[Expr] + A SymPy expression or system to be converted. + auto_assert : bool, optional + If false, do not modify expr and produce only the S-Expression equivalent of expr. + If true, assume expr is a system and assert each boolean element. + auto_declare : bool, optional + If false, do not produce declarations for the symbols used in expr. + If true, prepend all necessary declarations for variables used in expr based on symbol_table. + precision : integer, optional + The ``evalf(..)`` precision for numbers such as pi. + symbol_table : dict, optional + A dictionary where keys are ``Symbol`` or ``Function`` instances and values are their Python type i.e. ``bool``, ``int``, ``float``, or ``Callable[...]``. + If incomplete, an attempt will be made to infer types from ``expr``. + known_types: dict, optional + A dictionary where keys are ``bool``, ``int``, ``float`` etc. and values are their corresponding SMT type names. + If not given, a partial listing compatible with several solvers will be used. + known_functions : dict, optional + A dictionary where keys are ``Function``, ``Relational``, ``BooleanFunction``, or ``Expr`` instances and values are their SMT string representations. + If not given, a partial listing optimized for dReal solver (but compatible with others) will be used. + known_constants: dict, optional + A dictionary where keys are ``NumberSymbol`` instances and values are their SMT variable names. + When using this feature, extra caution must be taken to avoid naming collisions between user symbols and listed constants. + If not given, constants will be expanded inline i.e. ``3.14159`` instead of ``MY_SMT_VARIABLE_FOR_PI``. + prefix_expressions: list, optional + A list of lists of ``str`` and/or expressions to convert into SMTLib and prefix to the output. + suffix_expressions: list, optional + A list of lists of ``str`` and/or expressions to convert into SMTLib and postfix to the output. + log_warn: lambda function, optional + A function to record all warnings during potentially risky operations. + Soundness is a core value in SMT solving, so it is good to log all assumptions made. + + Examples + ======== + >>> from sympy import smtlib_code, symbols, sin, Eq + >>> x = symbols('x') + >>> smtlib_code(sin(x).series(x).removeO(), log_warn=print) + Could not infer type of `x`. Defaulting to float. + Non-Boolean expression `x**5/120 - x**3/6 + x` will not be asserted. Converting to SMTLib verbatim. + '(declare-const x Real)\n(+ x (* (/ -1 6) (pow x 3)) (* (/ 1 120) (pow x 5)))' + + >>> from sympy import Rational + >>> x, y, tau = symbols("x, y, tau") + >>> smtlib_code((2*tau)**Rational(7, 2), log_warn=print) + Could not infer type of `tau`. Defaulting to float. + Non-Boolean expression `8*sqrt(2)*tau**(7/2)` will not be asserted. Converting to SMTLib verbatim. + '(declare-const tau Real)\n(* 8 (pow 2 (/ 1 2)) (pow tau (/ 7 2)))' + + ``Piecewise`` expressions are implemented with ``ite`` expressions by default. + Note that if the ``Piecewise`` lacks a default term, represented by + ``(expr, True)`` then an error will be thrown. This is to prevent + generating an expression that may not evaluate to anything. + + >>> from sympy import Piecewise + >>> pw = Piecewise((x + 1, x > 0), (x, True)) + >>> smtlib_code(Eq(pw, 3), symbol_table={x: float}, log_warn=print) + '(declare-const x Real)\n(assert (= (ite (> x 0) (+ 1 x) x) 3))' + + Custom printing can be defined for certain types by passing a dictionary of + PythonType : "SMT Name" to the ``known_types``, ``known_constants``, and ``known_functions`` kwargs. + + >>> from typing import Callable + >>> from sympy import Function, Add + >>> f = Function('f') + >>> g = Function('g') + >>> smt_builtin_funcs = { # functions our SMT solver will understand + ... f: "existing_smtlib_fcn", + ... Add: "sum", + ... } + >>> user_def_funcs = { # functions defined by the user must have their types specified explicitly + ... g: Callable[[int], float], + ... } + >>> smtlib_code(f(x) + g(x), symbol_table=user_def_funcs, known_functions=smt_builtin_funcs, log_warn=print) + Non-Boolean expression `f(x) + g(x)` will not be asserted. Converting to SMTLib verbatim. + '(declare-const x Int)\n(declare-fun g (Int) Real)\n(sum (existing_smtlib_fcn x) (g x))' + """ + log_warn = log_warn or (lambda _: None) + + if not isinstance(expr, list): expr = [expr] + expr = [ + sympy.sympify(_, strict=True, evaluate=False, convert_xor=False) + for _ in expr + ] + + if not symbol_table: symbol_table = {} + symbol_table = _auto_infer_smtlib_types( + *expr, symbol_table=symbol_table + ) + # See [FALLBACK RULES] + # Need SMTLibPrinter to populate known_functions and known_constants first. + + settings = {} + if precision: settings['precision'] = precision + del precision + + if known_types: settings['known_types'] = known_types + del known_types + + if known_functions: settings['known_functions'] = known_functions + del known_functions + + if known_constants: settings['known_constants'] = known_constants + del known_constants + + if not prefix_expressions: prefix_expressions = [] + if not suffix_expressions: suffix_expressions = [] + + p = SMTLibPrinter(settings, symbol_table) + del symbol_table + + # [FALLBACK RULES] + for e in expr: + for sym in e.atoms(Symbol, Function): + if ( + sym.is_Symbol and + sym not in p._known_constants and + sym not in p.symbol_table + ): + log_warn(f"Could not infer type of `{sym}`. Defaulting to float.") + p.symbol_table[sym] = float + if ( + sym.is_Function and + type(sym) not in p._known_functions and + type(sym) not in p.symbol_table and + not sym.is_Piecewise + ): raise TypeError( + f"Unknown type of undefined function `{sym}`. " + f"Must be mapped to ``str`` in known_functions or mapped to ``Callable[..]`` in symbol_table." + ) + + declarations = [] + if auto_declare: + constants = {sym.name: sym for e in expr for sym in e.free_symbols + if sym not in p._known_constants} + functions = {fnc.name: fnc for e in expr for fnc in e.atoms(Function) + if type(fnc) not in p._known_functions and not fnc.is_Piecewise} + declarations = \ + [ + _auto_declare_smtlib(sym, p, log_warn) + for sym in constants.values() + ] + [ + _auto_declare_smtlib(fnc, p, log_warn) + for fnc in functions.values() + ] + declarations = [decl for decl in declarations if decl] + + if auto_assert: + expr = [_auto_assert_smtlib(e, p, log_warn) for e in expr] + + # return SMTLibPrinter().doprint(expr) + return '\n'.join([ + # ';; PREFIX EXPRESSIONS', + *[ + e if isinstance(e, str) else p.doprint(e) + for e in prefix_expressions + ], + + # ';; DECLARATIONS', + *sorted(e for e in declarations), + + # ';; EXPRESSIONS', + *[ + e if isinstance(e, str) else p.doprint(e) + for e in expr + ], + + # ';; SUFFIX EXPRESSIONS', + *[ + e if isinstance(e, str) else p.doprint(e) + for e in suffix_expressions + ], + ]) + + +def _auto_declare_smtlib(sym: typing.Union[Symbol, Function], p: SMTLibPrinter, log_warn: typing.Callable[[str], None]): + if sym.is_Symbol: + type_signature = p.symbol_table[sym] + assert isinstance(type_signature, type) + type_signature = p._known_types[type_signature] + return p._s_expr('declare-const', [sym, type_signature]) + + elif sym.is_Function: + type_signature = p.symbol_table[type(sym)] + assert callable(type_signature) + type_signature = [p._known_types[_] for _ in type_signature.__args__] + assert len(type_signature) > 0 + params_signature = f"({' '.join(type_signature[:-1])})" + return_signature = type_signature[-1] + return p._s_expr('declare-fun', [type(sym), params_signature, return_signature]) + + else: + log_warn(f"Non-Symbol/Function `{sym}` will not be declared.") + return None + + +def _auto_assert_smtlib(e: Expr, p: SMTLibPrinter, log_warn: typing.Callable[[str], None]): + if isinstance(e, Boolean) or ( + e in p.symbol_table and p.symbol_table[e] == bool + ) or ( + e.is_Function and + type(e) in p.symbol_table and + p.symbol_table[type(e)].__args__[-1] == bool + ): + return p._s_expr('assert', [e]) + else: + log_warn(f"Non-Boolean expression `{e}` will not be asserted. Converting to SMTLib verbatim.") + return e + + +def _auto_infer_smtlib_types( + *exprs: Basic, + symbol_table: typing.Optional[dict] = None +) -> dict: + # [TYPE INFERENCE RULES] + # X is alone in an expr => X is bool + # X in BooleanFunction.args => X is bool + # X matches to a bool param of a symbol_table function => X is bool + # X matches to an int param of a symbol_table function => X is int + # X.is_integer => X is int + # X == Y, where X is T => Y is T + + # [FALLBACK RULES] + # see _auto_declare_smtlib(..) + # X is not bool and X is not int and X is Symbol => X is float + # else (e.g. X is Function) => error. must be specified explicitly. + + _symbols = dict(symbol_table) if symbol_table else {} + + def safe_update(syms: set, inf): + for s in syms: + assert s.is_Symbol + if (old_type := _symbols.setdefault(s, inf)) != inf: + raise TypeError(f"Could not infer type of `{s}`. Apparently both `{old_type}` and `{inf}`?") + + # EXPLICIT TYPES + safe_update({ + e + for e in exprs + if e.is_Symbol + }, bool) + + safe_update({ + symbol + for e in exprs + for boolfunc in e.atoms(BooleanFunction) + for symbol in boolfunc.args + if symbol.is_Symbol + }, bool) + + safe_update({ + symbol + for e in exprs + for boolfunc in e.atoms(Function) + if type(boolfunc) in _symbols + for symbol, param in zip(boolfunc.args, _symbols[type(boolfunc)].__args__) + if symbol.is_Symbol and param == bool + }, bool) + + safe_update({ + symbol + for e in exprs + for intfunc in e.atoms(Function) + if type(intfunc) in _symbols + for symbol, param in zip(intfunc.args, _symbols[type(intfunc)].__args__) + if symbol.is_Symbol and param == int + }, int) + + safe_update({ + symbol + for e in exprs + for symbol in e.atoms(Symbol) + if symbol.is_integer + }, int) + + safe_update({ + symbol + for e in exprs + for symbol in e.atoms(Symbol) + if symbol.is_real and not symbol.is_integer + }, float) + + # EQUALITY RELATION RULE + rels_eq = [rel for expr in exprs for rel in expr.atoms(Equality)] + rels = [ + (rel.lhs, rel.rhs) for rel in rels_eq if rel.lhs.is_Symbol + ] + [ + (rel.rhs, rel.lhs) for rel in rels_eq if rel.rhs.is_Symbol + ] + for infer, reltd in rels: + inference = ( + _symbols[infer] if infer in _symbols else + _symbols[reltd] if reltd in _symbols else + + _symbols[type(reltd)].__args__[-1] + if reltd.is_Function and type(reltd) in _symbols else + + bool if reltd.is_Boolean else + int if reltd.is_integer or reltd.is_Integer else + float if reltd.is_real else + None + ) + if inference: safe_update({infer}, inference) + + return _symbols diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/str.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/str.py new file mode 100644 index 0000000000000000000000000000000000000000..9975776fbb73bec9c956fe359387fa8036995795 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/str.py @@ -0,0 +1,1021 @@ +""" +A Printer for generating readable representation of most SymPy classes. +""" + +from __future__ import annotations +from typing import Any + +from sympy.core import S, Rational, Pow, Basic, Mul, Number +from sympy.core.mul import _keep_coeff +from sympy.core.numbers import Integer +from sympy.core.relational import Relational +from sympy.core.sorting import default_sort_key +from sympy.utilities.iterables import sift +from .precedence import precedence, PRECEDENCE +from .printer import Printer, print_function + +from mpmath.libmp import prec_to_dps, to_str as mlib_to_str + + +class StrPrinter(Printer): + printmethod = "_sympystr" + _default_settings: dict[str, Any] = { + "order": None, + "full_prec": "auto", + "sympy_integers": False, + "abbrev": False, + "perm_cyclic": True, + "min": None, + "max": None, + "dps" : None + } + + _relationals: dict[str, str] = {} + + def parenthesize(self, item, level, strict=False): + if (precedence(item) < level) or ((not strict) and precedence(item) <= level): + return "(%s)" % self._print(item) + else: + return self._print(item) + + def stringify(self, args, sep, level=0): + return sep.join([self.parenthesize(item, level) for item in args]) + + def emptyPrinter(self, expr): + if isinstance(expr, str): + return expr + elif isinstance(expr, Basic): + return repr(expr) + else: + return str(expr) + + def _print_Add(self, expr, order=None): + terms = self._as_ordered_terms(expr, order=order) + + prec = precedence(expr) + l = [] + for term in terms: + t = self._print(term) + if t.startswith('-') and not term.is_Add: + sign = "-" + t = t[1:] + else: + sign = "+" + if precedence(term) < prec or term.is_Add: + l.extend([sign, "(%s)" % t]) + else: + l.extend([sign, t]) + sign = l.pop(0) + if sign == '+': + sign = "" + return sign + ' '.join(l) + + def _print_BooleanTrue(self, expr): + return "True" + + def _print_BooleanFalse(self, expr): + return "False" + + def _print_Not(self, expr): + return '~%s' %(self.parenthesize(expr.args[0],PRECEDENCE["Not"])) + + def _print_And(self, expr): + args = list(expr.args) + for j, i in enumerate(args): + if isinstance(i, Relational) and ( + i.canonical.rhs is S.NegativeInfinity): + args.insert(0, args.pop(j)) + return self.stringify(args, " & ", PRECEDENCE["BitwiseAnd"]) + + def _print_Or(self, expr): + return self.stringify(expr.args, " | ", PRECEDENCE["BitwiseOr"]) + + def _print_Xor(self, expr): + return self.stringify(expr.args, " ^ ", PRECEDENCE["BitwiseXor"]) + + def _print_AppliedPredicate(self, expr): + return '%s(%s)' % ( + self._print(expr.function), self.stringify(expr.arguments, ", ")) + + def _print_Basic(self, expr): + l = [self._print(o) for o in expr.args] + return expr.__class__.__name__ + "(%s)" % ", ".join(l) + + def _print_BlockMatrix(self, B): + if B.blocks.shape == (1, 1): + self._print(B.blocks[0, 0]) + return self._print(B.blocks) + + def _print_Catalan(self, expr): + return 'Catalan' + + def _print_ComplexInfinity(self, expr): + return 'zoo' + + def _print_ConditionSet(self, s): + args = tuple([self._print(i) for i in (s.sym, s.condition)]) + if s.base_set is S.UniversalSet: + return 'ConditionSet(%s, %s)' % args + args += (self._print(s.base_set),) + return 'ConditionSet(%s, %s, %s)' % args + + def _print_Derivative(self, expr): + dexpr = expr.expr + dvars = [i[0] if i[1] == 1 else i for i in expr.variable_count] + return 'Derivative(%s)' % ", ".join((self._print(arg) for arg in [dexpr] + dvars)) + + def _print_dict(self, d): + keys = sorted(d.keys(), key=default_sort_key) + items = [] + + for key in keys: + item = "%s: %s" % (self._print(key), self._print(d[key])) + items.append(item) + + return "{%s}" % ", ".join(items) + + def _print_Dict(self, expr): + return self._print_dict(expr) + + def _print_RandomDomain(self, d): + if hasattr(d, 'as_boolean'): + return 'Domain: ' + self._print(d.as_boolean()) + elif hasattr(d, 'set'): + return ('Domain: ' + self._print(d.symbols) + ' in ' + + self._print(d.set)) + else: + return 'Domain on ' + self._print(d.symbols) + + def _print_Dummy(self, expr): + return '_' + expr.name + + def _print_EulerGamma(self, expr): + return 'EulerGamma' + + def _print_Exp1(self, expr): + return 'E' + + def _print_ExprCondPair(self, expr): + return '(%s, %s)' % (self._print(expr.expr), self._print(expr.cond)) + + def _print_Function(self, expr): + return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ") + + def _print_GoldenRatio(self, expr): + return 'GoldenRatio' + + def _print_Heaviside(self, expr): + # Same as _print_Function but uses pargs to suppress default 1/2 for + # 2nd args + return expr.func.__name__ + "(%s)" % self.stringify(expr.pargs, ", ") + + def _print_TribonacciConstant(self, expr): + return 'TribonacciConstant' + + def _print_ImaginaryUnit(self, expr): + return 'I' + + def _print_Infinity(self, expr): + return 'oo' + + def _print_Integral(self, expr): + def _xab_tostr(xab): + if len(xab) == 1: + return self._print(xab[0]) + else: + return self._print((xab[0],) + tuple(xab[1:])) + L = ', '.join([_xab_tostr(l) for l in expr.limits]) + return 'Integral(%s, %s)' % (self._print(expr.function), L) + + def _print_Interval(self, i): + fin = 'Interval{m}({a}, {b})' + a, b, l, r = i.args + if a.is_infinite and b.is_infinite: + m = '' + elif a.is_infinite and not r: + m = '' + elif b.is_infinite and not l: + m = '' + elif not l and not r: + m = '' + elif l and r: + m = '.open' + elif l: + m = '.Lopen' + else: + m = '.Ropen' + return fin.format(**{'a': a, 'b': b, 'm': m}) + + def _print_AccumulationBounds(self, i): + return "AccumBounds(%s, %s)" % (self._print(i.min), + self._print(i.max)) + + def _print_Inverse(self, I): + return "%s**(-1)" % self.parenthesize(I.arg, PRECEDENCE["Pow"]) + + def _print_Lambda(self, obj): + expr = obj.expr + sig = obj.signature + if len(sig) == 1 and sig[0].is_symbol: + sig = sig[0] + return "Lambda(%s, %s)" % (self._print(sig), self._print(expr)) + + def _print_LatticeOp(self, expr): + args = sorted(expr.args, key=default_sort_key) + return expr.func.__name__ + "(%s)" % ", ".join(self._print(arg) for arg in args) + + def _print_Limit(self, expr): + e, z, z0, dir = expr.args + return "Limit(%s, %s, %s, dir='%s')" % tuple(map(self._print, (e, z, z0, dir))) + + + def _print_list(self, expr): + return "[%s]" % self.stringify(expr, ", ") + + def _print_List(self, expr): + return self._print_list(expr) + + def _print_MatrixBase(self, expr): + return expr._format_str(self) + + def _print_MatrixElement(self, expr): + return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \ + + '[%s, %s]' % (self._print(expr.i), self._print(expr.j)) + + def _print_MatrixSlice(self, expr): + def strslice(x, dim): + x = list(x) + if x[2] == 1: + del x[2] + if x[0] == 0: + x[0] = '' + if x[1] == dim: + x[1] = '' + return ':'.join((self._print(arg) for arg in x)) + return (self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) + '[' + + strslice(expr.rowslice, expr.parent.rows) + ', ' + + strslice(expr.colslice, expr.parent.cols) + ']') + + def _print_DeferredVector(self, expr): + return expr.name + + def _print_Mul(self, expr): + + prec = precedence(expr) + + # Check for unevaluated Mul. In this case we need to make sure the + # identities are visible, multiple Rational factors are not combined + # etc so we display in a straight-forward form that fully preserves all + # args and their order. + args = expr.args + if args[0] is S.One or any( + isinstance(a, Number) or + a.is_Pow and all(ai.is_Integer for ai in a.args) + for a in args[1:]): + d, n = sift(args, lambda x: + isinstance(x, Pow) and bool(x.exp.as_coeff_Mul()[0] < 0), + binary=True) + for i, di in enumerate(d): + if di.exp.is_Number: + e = -di.exp + else: + dargs = list(di.exp.args) + dargs[0] = -dargs[0] + e = Mul._from_args(dargs) + d[i] = Pow(di.base, e, evaluate=False) if e - 1 else di.base + + pre = [] + # don't parenthesize first factor if negative + if n and not n[0].is_Add and n[0].could_extract_minus_sign(): + pre = [self._print(n.pop(0))] + + nfactors = pre + [self.parenthesize(a, prec, strict=False) + for a in n] + if not nfactors: + nfactors = ['1'] + + # don't parenthesize first of denominator unless singleton + if len(d) > 1 and d[0].could_extract_minus_sign(): + pre = [self._print(d.pop(0))] + else: + pre = [] + dfactors = pre + [self.parenthesize(a, prec, strict=False) + for a in d] + + n = '*'.join(nfactors) + d = '*'.join(dfactors) + if len(dfactors) > 1: + return '%s/(%s)' % (n, d) + elif dfactors: + return '%s/%s' % (n, d) + return n + + c, e = expr.as_coeff_Mul() + if c < 0: + expr = _keep_coeff(-c, e) + sign = "-" + else: + sign = "" + + a = [] # items in the numerator + b = [] # items that are in the denominator (if any) + + pow_paren = [] # Will collect all pow with more than one base element and exp = -1 + + if self.order not in ('old', 'none'): + args = expr.as_ordered_factors() + else: + # use make_args in case expr was something like -x -> x + args = Mul.make_args(expr) + + # Gather args for numerator/denominator + def apow(i): + b, e = i.as_base_exp() + eargs = list(Mul.make_args(e)) + if eargs[0] is S.NegativeOne: + eargs = eargs[1:] + else: + eargs[0] = -eargs[0] + e = Mul._from_args(eargs) + if isinstance(i, Pow): + return i.func(b, e, evaluate=False) + return i.func(e, evaluate=False) + for item in args: + if (item.is_commutative and + isinstance(item, Pow) and + bool(item.exp.as_coeff_Mul()[0] < 0)): + if item.exp is not S.NegativeOne: + b.append(apow(item)) + else: + if (len(item.args[0].args) != 1 and + isinstance(item.base, (Mul, Pow))): + # To avoid situations like #14160 + pow_paren.append(item) + b.append(item.base) + elif item.is_Rational and item is not S.Infinity: + if item.p != 1: + a.append(Rational(item.p)) + if item.q != 1: + b.append(Rational(item.q)) + else: + a.append(item) + + a = a or [S.One] + + a_str = [self.parenthesize(x, prec, strict=False) for x in a] + b_str = [self.parenthesize(x, prec, strict=False) for x in b] + + # To parenthesize Pow with exp = -1 and having more than one Symbol + for item in pow_paren: + if item.base in b: + b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] + + if not b: + return sign + '*'.join(a_str) + elif len(b) == 1: + return sign + '*'.join(a_str) + "/" + b_str[0] + else: + return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str) + + def _print_MatMul(self, expr): + c, m = expr.as_coeff_mmul() + + sign = "" + if c.is_number: + re, im = c.as_real_imag() + if im.is_zero and re.is_negative: + expr = _keep_coeff(-c, m) + sign = "-" + elif re.is_zero and im.is_negative: + expr = _keep_coeff(-c, m) + sign = "-" + + return sign + '*'.join( + [self.parenthesize(arg, precedence(expr)) for arg in expr.args] + ) + + def _print_ElementwiseApplyFunction(self, expr): + return "{}.({})".format( + expr.function, + self._print(expr.expr), + ) + + def _print_NaN(self, expr): + return 'nan' + + def _print_NegativeInfinity(self, expr): + return '-oo' + + def _print_Order(self, expr): + if not expr.variables or all(p is S.Zero for p in expr.point): + if len(expr.variables) <= 1: + return 'O(%s)' % self._print(expr.expr) + else: + return 'O(%s)' % self.stringify((expr.expr,) + expr.variables, ', ', 0) + else: + return 'O(%s)' % self.stringify(expr.args, ', ', 0) + + def _print_Ordinal(self, expr): + return expr.__str__() + + def _print_Cycle(self, expr): + return expr.__str__() + + def _print_Permutation(self, expr): + from sympy.combinatorics.permutations import Permutation, Cycle + from sympy.utilities.exceptions import sympy_deprecation_warning + + perm_cyclic = Permutation.print_cyclic + if perm_cyclic is not None: + sympy_deprecation_warning( + f""" + Setting Permutation.print_cyclic is deprecated. Instead use + init_printing(perm_cyclic={perm_cyclic}). + """, + deprecated_since_version="1.6", + active_deprecations_target="deprecated-permutation-print_cyclic", + stacklevel=7, + ) + else: + perm_cyclic = self._settings.get("perm_cyclic", True) + + if perm_cyclic: + if not expr.size: + return '()' + # before taking Cycle notation, see if the last element is + # a singleton and move it to the head of the string + s = Cycle(expr)(expr.size - 1).__repr__()[len('Cycle'):] + last = s.rfind('(') + if not last == 0 and ',' not in s[last:]: + s = s[last:] + s[:last] + s = s.replace(',', '') + return s + else: + s = expr.support() + if not s: + if expr.size < 5: + return 'Permutation(%s)' % self._print(expr.array_form) + return 'Permutation([], size=%s)' % self._print(expr.size) + trim = self._print(expr.array_form[:s[-1] + 1]) + ', size=%s' % self._print(expr.size) + use = full = self._print(expr.array_form) + if len(trim) < len(full): + use = trim + return 'Permutation(%s)' % use + + def _print_Subs(self, obj): + expr, old, new = obj.args + if len(obj.point) == 1: + old = old[0] + new = new[0] + return "Subs(%s, %s, %s)" % ( + self._print(expr), self._print(old), self._print(new)) + + def _print_TensorIndex(self, expr): + return expr._print() + + def _print_TensorHead(self, expr): + return expr._print() + + def _print_Tensor(self, expr): + return expr._print() + + def _print_TensMul(self, expr): + # prints expressions like "A(a)", "3*A(a)", "(1+x)*A(a)" + sign, args = expr._get_args_for_traditional_printer() + return sign + "*".join( + [self.parenthesize(arg, precedence(expr)) for arg in args] + ) + + def _print_TensAdd(self, expr): + return expr._print() + + def _print_ArraySymbol(self, expr): + return self._print(expr.name) + + def _print_ArrayElement(self, expr): + return "%s[%s]" % ( + self.parenthesize(expr.name, PRECEDENCE["Func"], True), ", ".join([self._print(i) for i in expr.indices])) + + def _print_PermutationGroup(self, expr): + p = [' %s' % self._print(a) for a in expr.args] + return 'PermutationGroup([\n%s])' % ',\n'.join(p) + + def _print_Pi(self, expr): + return 'pi' + + def _print_PolyRing(self, ring): + return "Polynomial ring in %s over %s with %s order" % \ + (", ".join((self._print(rs) for rs in ring.symbols)), + self._print(ring.domain), self._print(ring.order)) + + def _print_FracField(self, field): + return "Rational function field in %s over %s with %s order" % \ + (", ".join((self._print(fs) for fs in field.symbols)), + self._print(field.domain), self._print(field.order)) + + def _print_FreeGroupElement(self, elm): + return elm.__str__() + + def _print_GaussianElement(self, poly): + return "(%s + %s*I)" % (poly.x, poly.y) + + def _print_PolyElement(self, poly): + return poly.str(self, PRECEDENCE, "%s**%s", "*") + + def _print_FracElement(self, frac): + if frac.denom == 1: + return self._print(frac.numer) + else: + numer = self.parenthesize(frac.numer, PRECEDENCE["Mul"], strict=True) + denom = self.parenthesize(frac.denom, PRECEDENCE["Atom"], strict=True) + return numer + "/" + denom + + def _print_Poly(self, expr): + ATOM_PREC = PRECEDENCE["Atom"] - 1 + terms, gens = [], [ self.parenthesize(s, ATOM_PREC) for s in expr.gens ] + + for monom, coeff in expr.terms(): + s_monom = [] + + for i, e in enumerate(monom): + if e > 0: + if e == 1: + s_monom.append(gens[i]) + else: + s_monom.append(gens[i] + "**%d" % e) + + s_monom = "*".join(s_monom) + + if coeff.is_Add: + if s_monom: + s_coeff = "(" + self._print(coeff) + ")" + else: + s_coeff = self._print(coeff) + else: + if s_monom: + if coeff is S.One: + terms.extend(['+', s_monom]) + continue + + if coeff is S.NegativeOne: + terms.extend(['-', s_monom]) + continue + + s_coeff = self._print(coeff) + + if not s_monom: + s_term = s_coeff + else: + s_term = s_coeff + "*" + s_monom + + if s_term.startswith('-'): + terms.extend(['-', s_term[1:]]) + else: + terms.extend(['+', s_term]) + + if terms[0] in ('-', '+'): + modifier = terms.pop(0) + + if modifier == '-': + terms[0] = '-' + terms[0] + + format = expr.__class__.__name__ + "(%s, %s" + + from sympy.polys.polyerrors import PolynomialError + + try: + format += ", modulus=%s" % expr.get_modulus() + except PolynomialError: + format += ", domain='%s'" % expr.get_domain() + + format += ")" + + for index, item in enumerate(gens): + if len(item) > 2 and (item[:1] == "(" and item[len(item) - 1:] == ")"): + gens[index] = item[1:len(item) - 1] + + return format % (' '.join(terms), ', '.join(gens)) + + def _print_UniversalSet(self, p): + return 'UniversalSet' + + def _print_AlgebraicNumber(self, expr): + if expr.is_aliased: + return self._print(expr.as_poly().as_expr()) + else: + return self._print(expr.as_expr()) + + def _print_Pow(self, expr, rational=False): + """Printing helper function for ``Pow`` + + Parameters + ========== + + rational : bool, optional + If ``True``, it will not attempt printing ``sqrt(x)`` or + ``x**S.Half`` as ``sqrt``, and will use ``x**(1/2)`` + instead. + + See examples for additional details + + Examples + ======== + + >>> from sympy import sqrt, StrPrinter + >>> from sympy.abc import x + + How ``rational`` keyword works with ``sqrt``: + + >>> printer = StrPrinter() + >>> printer._print_Pow(sqrt(x), rational=True) + 'x**(1/2)' + >>> printer._print_Pow(sqrt(x), rational=False) + 'sqrt(x)' + >>> printer._print_Pow(1/sqrt(x), rational=True) + 'x**(-1/2)' + >>> printer._print_Pow(1/sqrt(x), rational=False) + '1/sqrt(x)' + + Notes + ===== + + ``sqrt(x)`` is canonicalized as ``Pow(x, S.Half)`` in SymPy, + so there is no need of defining a separate printer for ``sqrt``. + Instead, it should be handled here as well. + """ + PREC = precedence(expr) + + if expr.exp is S.Half and not rational: + return "sqrt(%s)" % self._print(expr.base) + + if expr.is_commutative: + if -expr.exp is S.Half and not rational: + # Note: Don't test "expr.exp == -S.Half" here, because that will + # match -0.5, which we don't want. + return "%s/sqrt(%s)" % tuple((self._print(arg) for arg in (S.One, expr.base))) + if expr.exp is -S.One: + # Similarly to the S.Half case, don't test with "==" here. + return '%s/%s' % (self._print(S.One), + self.parenthesize(expr.base, PREC, strict=False)) + + e = self.parenthesize(expr.exp, PREC, strict=False) + if self.printmethod == '_sympyrepr' and expr.exp.is_Rational and expr.exp.q != 1: + # the parenthesized exp should be '(Rational(a, b))' so strip parens, + # but just check to be sure. + if e.startswith('(Rational'): + return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e[1:-1]) + return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e) + + def _print_UnevaluatedExpr(self, expr): + return self._print(expr.args[0]) + + def _print_MatPow(self, expr): + PREC = precedence(expr) + return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), + self.parenthesize(expr.exp, PREC, strict=False)) + + def _print_Integer(self, expr): + if self._settings.get("sympy_integers", False): + return "S(%s)" % (expr) + return str(expr.p) + + def _print_Integers(self, expr): + return 'Integers' + + def _print_Naturals(self, expr): + return 'Naturals' + + def _print_Naturals0(self, expr): + return 'Naturals0' + + def _print_Rationals(self, expr): + return 'Rationals' + + def _print_Reals(self, expr): + return 'Reals' + + def _print_Complexes(self, expr): + return 'Complexes' + + def _print_EmptySet(self, expr): + return 'EmptySet' + + def _print_EmptySequence(self, expr): + return 'EmptySequence' + + def _print_int(self, expr): + return str(expr) + + def _print_mpz(self, expr): + return str(expr) + + def _print_Rational(self, expr): + if expr.q == 1: + return str(expr.p) + else: + if self._settings.get("sympy_integers", False): + return "S(%s)/%s" % (expr.p, expr.q) + return "%s/%s" % (expr.p, expr.q) + + def _print_PythonRational(self, expr): + if expr.q == 1: + return str(expr.p) + else: + return "%d/%d" % (expr.p, expr.q) + + def _print_Fraction(self, expr): + if expr.denominator == 1: + return str(expr.numerator) + else: + return "%s/%s" % (expr.numerator, expr.denominator) + + def _print_mpq(self, expr): + if expr.denominator == 1: + return str(expr.numerator) + else: + return "%s/%s" % (expr.numerator, expr.denominator) + + def _print_Float(self, expr): + prec = expr._prec + dps = self._settings.get('dps', None) + if dps is None: + dps = 0 if prec < 5 else prec_to_dps(expr._prec) + if self._settings["full_prec"] is True: + strip = False + elif self._settings["full_prec"] is False: + strip = True + elif self._settings["full_prec"] == "auto": + strip = self._print_level > 1 + low = self._settings["min"] if "min" in self._settings else None + high = self._settings["max"] if "max" in self._settings else None + rv = mlib_to_str(expr._mpf_, dps, strip_zeros=strip, min_fixed=low, max_fixed=high) + if rv.startswith('-.0'): + rv = '-0.' + rv[3:] + elif rv.startswith('.0'): + rv = '0.' + rv[2:] + rv = rv.removeprefix('+') # e.g., +inf -> inf + return rv + + def _print_Relational(self, expr): + + charmap = { + "==": "Eq", + "!=": "Ne", + ":=": "Assignment", + '+=': "AddAugmentedAssignment", + "-=": "SubAugmentedAssignment", + "*=": "MulAugmentedAssignment", + "/=": "DivAugmentedAssignment", + "%=": "ModAugmentedAssignment", + } + + if expr.rel_op in charmap: + return '%s(%s, %s)' % (charmap[expr.rel_op], self._print(expr.lhs), + self._print(expr.rhs)) + + return '%s %s %s' % (self.parenthesize(expr.lhs, precedence(expr)), + self._relationals.get(expr.rel_op) or expr.rel_op, + self.parenthesize(expr.rhs, precedence(expr))) + + def _print_ComplexRootOf(self, expr): + return "CRootOf(%s, %d)" % (self._print_Add(expr.expr, order='lex'), + expr.index) + + def _print_RootSum(self, expr): + args = [self._print_Add(expr.expr, order='lex')] + + if expr.fun is not S.IdentityFunction: + args.append(self._print(expr.fun)) + + return "RootSum(%s)" % ", ".join(args) + + def _print_GroebnerBasis(self, basis): + cls = basis.__class__.__name__ + + exprs = [self._print_Add(arg, order=basis.order) for arg in basis.exprs] + exprs = "[%s]" % ", ".join(exprs) + + gens = [ self._print(gen) for gen in basis.gens ] + domain = "domain='%s'" % self._print(basis.domain) + order = "order='%s'" % self._print(basis.order) + + args = [exprs] + gens + [domain, order] + + return "%s(%s)" % (cls, ", ".join(args)) + + def _print_set(self, s): + items = sorted(s, key=default_sort_key) + + args = ', '.join(self._print(item) for item in items) + if not args: + return "set()" + return '{%s}' % args + + def _print_FiniteSet(self, s): + from sympy.sets.sets import FiniteSet + items = sorted(s, key=default_sort_key) + + args = ', '.join(self._print(item) for item in items) + if any(item.has(FiniteSet) for item in items): + return 'FiniteSet({})'.format(args) + return '{{{}}}'.format(args) + + def _print_Partition(self, s): + items = sorted(s, key=default_sort_key) + + args = ', '.join(self._print(arg) for arg in items) + return 'Partition({})'.format(args) + + def _print_frozenset(self, s): + if not s: + return "frozenset()" + return "frozenset(%s)" % self._print_set(s) + + def _print_Sum(self, expr): + def _xab_tostr(xab): + if len(xab) == 1: + return self._print(xab[0]) + else: + return self._print((xab[0],) + tuple(xab[1:])) + L = ', '.join([_xab_tostr(l) for l in expr.limits]) + return 'Sum(%s, %s)' % (self._print(expr.function), L) + + def _print_Symbol(self, expr): + return expr.name + _print_MatrixSymbol = _print_Symbol + _print_RandomSymbol = _print_Symbol + + def _print_Identity(self, expr): + return "I" + + def _print_ZeroMatrix(self, expr): + return "0" + + def _print_OneMatrix(self, expr): + return "1" + + def _print_Predicate(self, expr): + return "Q.%s" % expr.name + + def _print_str(self, expr): + return str(expr) + + def _print_tuple(self, expr): + if len(expr) == 1: + return "(%s,)" % self._print(expr[0]) + else: + return "(%s)" % self.stringify(expr, ", ") + + def _print_Tuple(self, expr): + return self._print_tuple(expr) + + def _print_Transpose(self, T): + return "%s.T" % self.parenthesize(T.arg, PRECEDENCE["Pow"]) + + def _print_Uniform(self, expr): + return "Uniform(%s, %s)" % (self._print(expr.a), self._print(expr.b)) + + def _print_Quantity(self, expr): + if self._settings.get("abbrev", False): + return "%s" % expr.abbrev + return "%s" % expr.name + + def _print_Quaternion(self, expr): + s = [self.parenthesize(i, PRECEDENCE["Mul"], strict=True) for i in expr.args] + a = [s[0]] + [i+"*"+j for i, j in zip(s[1:], "ijk")] + return " + ".join(a) + + def _print_Dimension(self, expr): + return str(expr) + + def _print_Wild(self, expr): + return expr.name + '_' + + def _print_WildFunction(self, expr): + return expr.name + '_' + + def _print_WildDot(self, expr): + return expr.name + + def _print_WildPlus(self, expr): + return expr.name + + def _print_WildStar(self, expr): + return expr.name + + def _print_Zero(self, expr): + if self._settings.get("sympy_integers", False): + return "S(0)" + return self._print_Integer(Integer(0)) + + def _print_DMP(self, p): + cls = p.__class__.__name__ + rep = self._print(p.to_list()) + dom = self._print(p.dom) + + return "%s(%s, %s)" % (cls, rep, dom) + + def _print_DMF(self, expr): + cls = expr.__class__.__name__ + num = self._print(expr.num) + den = self._print(expr.den) + dom = self._print(expr.dom) + + return "%s(%s, %s, %s)" % (cls, num, den, dom) + + def _print_Object(self, obj): + return 'Object("%s")' % obj.name + + def _print_IdentityMorphism(self, morphism): + return 'IdentityMorphism(%s)' % morphism.domain + + def _print_NamedMorphism(self, morphism): + return 'NamedMorphism(%s, %s, "%s")' % \ + (morphism.domain, morphism.codomain, morphism.name) + + def _print_Category(self, category): + return 'Category("%s")' % category.name + + def _print_Manifold(self, manifold): + return manifold.name.name + + def _print_Patch(self, patch): + return patch.name.name + + def _print_CoordSystem(self, coords): + return coords.name.name + + def _print_BaseScalarField(self, field): + return field._coord_sys.symbols[field._index].name + + def _print_BaseVectorField(self, field): + return 'e_%s' % field._coord_sys.symbols[field._index].name + + def _print_Differential(self, diff): + field = diff._form_field + if hasattr(field, '_coord_sys'): + return 'd%s' % field._coord_sys.symbols[field._index].name + else: + return 'd(%s)' % self._print(field) + + def _print_Tr(self, expr): + #TODO : Handle indices + return "%s(%s)" % ("Tr", self._print(expr.args[0])) + + def _print_Str(self, s): + return self._print(s.name) + + def _print_AppliedBinaryRelation(self, expr): + rel = expr.function + return '%s(%s, %s)' % (self._print(rel), + self._print(expr.lhs), + self._print(expr.rhs)) + + +@print_function(StrPrinter) +def sstr(expr, **settings): + """Returns the expression as a string. + + For large expressions where speed is a concern, use the setting + order='none'. If abbrev=True setting is used then units are printed in + abbreviated form. + + Examples + ======== + + >>> from sympy import symbols, Eq, sstr + >>> a, b = symbols('a b') + >>> sstr(Eq(a + b, 0)) + 'Eq(a + b, 0)' + """ + + p = StrPrinter(settings) + s = p.doprint(expr) + + return s + + +class StrReprPrinter(StrPrinter): + """(internal) -- see sstrrepr""" + + def _print_str(self, s): + return repr(s) + + def _print_Str(self, s): + # Str does not to be printed same as str here + return "%s(%s)" % (s.__class__.__name__, self._print(s.name)) + +@print_function(StrReprPrinter) +def sstrrepr(expr, **settings): + """return expr in mixed str/repr form + + i.e. strings are returned in repr form with quotes, and everything else + is returned in str form. + + This function could be useful for hooking into sys.displayhook + """ + + p = StrReprPrinter(settings) + s = p.doprint(expr) + + return s diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tableform.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tableform.py new file mode 100644 index 0000000000000000000000000000000000000000..4a84ef96ae92517a6ec01ca9db1a13e9afa67093 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tableform.py @@ -0,0 +1,366 @@ +from sympy.core.containers import Tuple +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import SympifyError + +from types import FunctionType + + +class TableForm: + r""" + Create a nice table representation of data. + + Examples + ======== + + >>> from sympy import TableForm + >>> t = TableForm([[5, 7], [4, 2], [10, 3]]) + >>> print(t) + 5 7 + 4 2 + 10 3 + + You can use the SymPy's printing system to produce tables in any + format (ascii, latex, html, ...). + + >>> print(t.as_latex()) + \begin{tabular}{l l} + $5$ & $7$ \\ + $4$ & $2$ \\ + $10$ & $3$ \\ + \end{tabular} + + """ + + def __init__(self, data, **kwarg): + """ + Creates a TableForm. + + Parameters: + + data ... + 2D data to be put into the table; data can be + given as a Matrix + + headings ... + gives the labels for rows and columns: + + Can be a single argument that applies to both + dimensions: + + - None ... no labels + - "automatic" ... labels are 1, 2, 3, ... + + Can be a list of labels for rows and columns: + The labels for each dimension can be given + as None, "automatic", or [l1, l2, ...] e.g. + ["automatic", None] will number the rows + + [default: None] + + alignments ... + alignment of the columns with: + + - "left" or "<" + - "center" or "^" + - "right" or ">" + + When given as a single value, the value is used for + all columns. The row headings (if given) will be + right justified unless an explicit alignment is + given for it and all other columns. + + [default: "left"] + + formats ... + a list of format strings or functions that accept + 3 arguments (entry, row number, col number) and + return a string for the table entry. (If a function + returns None then the _print method will be used.) + + wipe_zeros ... + Do not show zeros in the table. + + [default: True] + + pad ... + the string to use to indicate a missing value (e.g. + elements that are None or those that are missing + from the end of a row (i.e. any row that is shorter + than the rest is assumed to have missing values). + When None, nothing will be shown for values that + are missing from the end of a row; values that are + None, however, will be shown. + + [default: None] + + Examples + ======== + + >>> from sympy import TableForm, Symbol + >>> TableForm([[5, 7], [4, 2], [10, 3]]) + 5 7 + 4 2 + 10 3 + >>> TableForm([list('.'*i) for i in range(1, 4)], headings='automatic') + | 1 2 3 + --------- + 1 | . + 2 | . . + 3 | . . . + >>> TableForm([[Symbol('.'*(j if not i%2 else 1)) for i in range(3)] + ... for j in range(4)], alignments='rcl') + . + . . . + .. . .. + ... . ... + """ + from sympy.matrices.dense import Matrix + + # We only support 2D data. Check the consistency: + if isinstance(data, Matrix): + data = data.tolist() + _h = len(data) + + # fill out any short lines + pad = kwarg.get('pad', None) + ok_None = False + if pad is None: + pad = " " + ok_None = True + pad = Symbol(pad) + _w = max(len(line) for line in data) + for i, line in enumerate(data): + if len(line) != _w: + line.extend([pad]*(_w - len(line))) + for j, lj in enumerate(line): + if lj is None: + if not ok_None: + lj = pad + else: + try: + lj = S(lj) + except SympifyError: + lj = Symbol(str(lj)) + line[j] = lj + data[i] = line + _lines = Tuple(*[Tuple(*d) for d in data]) + + headings = kwarg.get("headings", [None, None]) + if headings == "automatic": + _headings = [range(1, _h + 1), range(1, _w + 1)] + else: + h1, h2 = headings + if h1 == "automatic": + h1 = range(1, _h + 1) + if h2 == "automatic": + h2 = range(1, _w + 1) + _headings = [h1, h2] + + allow = ('l', 'r', 'c') + alignments = kwarg.get("alignments", "l") + + def _std_align(a): + a = a.strip().lower() + if len(a) > 1: + return {'left': 'l', 'right': 'r', 'center': 'c'}.get(a, a) + else: + return {'<': 'l', '>': 'r', '^': 'c'}.get(a, a) + std_align = _std_align(alignments) + if std_align in allow: + _alignments = [std_align]*_w + else: + _alignments = [] + for a in alignments: + std_align = _std_align(a) + _alignments.append(std_align) + if std_align not in ('l', 'r', 'c'): + raise ValueError('alignment "%s" unrecognized' % + alignments) + if _headings[0] and len(_alignments) == _w + 1: + _head_align = _alignments[0] + _alignments = _alignments[1:] + else: + _head_align = 'r' + if len(_alignments) != _w: + raise ValueError( + 'wrong number of alignments: expected %s but got %s' % + (_w, len(_alignments))) + + _column_formats = kwarg.get("formats", [None]*_w) + + _wipe_zeros = kwarg.get("wipe_zeros", True) + + self._w = _w + self._h = _h + self._lines = _lines + self._headings = _headings + self._head_align = _head_align + self._alignments = _alignments + self._column_formats = _column_formats + self._wipe_zeros = _wipe_zeros + + def __repr__(self): + from .str import sstr + return sstr(self, order=None) + + def __str__(self): + from .str import sstr + return sstr(self, order=None) + + def as_matrix(self): + """Returns the data of the table in Matrix form. + + Examples + ======== + + >>> from sympy import TableForm + >>> t = TableForm([[5, 7], [4, 2], [10, 3]], headings='automatic') + >>> t + | 1 2 + -------- + 1 | 5 7 + 2 | 4 2 + 3 | 10 3 + >>> t.as_matrix() + Matrix([ + [ 5, 7], + [ 4, 2], + [10, 3]]) + """ + from sympy.matrices.dense import Matrix + return Matrix(self._lines) + + def as_str(self): + # XXX obsolete ? + return str(self) + + def as_latex(self): + from .latex import latex + return latex(self) + + def _sympystr(self, p): + """ + Returns the string representation of 'self'. + + Examples + ======== + + >>> from sympy import TableForm + >>> t = TableForm([[5, 7], [4, 2], [10, 3]]) + >>> s = t.as_str() + + """ + column_widths = [0] * self._w + lines = [] + for line in self._lines: + new_line = [] + for i in range(self._w): + # Format the item somehow if needed: + s = str(line[i]) + if self._wipe_zeros and (s == "0"): + s = " " + w = len(s) + if w > column_widths[i]: + column_widths[i] = w + new_line.append(s) + lines.append(new_line) + + # Check heading: + if self._headings[0]: + self._headings[0] = [str(x) for x in self._headings[0]] + _head_width = max(len(x) for x in self._headings[0]) + + if self._headings[1]: + new_line = [] + for i in range(self._w): + # Format the item somehow if needed: + s = str(self._headings[1][i]) + w = len(s) + if w > column_widths[i]: + column_widths[i] = w + new_line.append(s) + self._headings[1] = new_line + + format_str = [] + + def _align(align, w): + return '%%%s%ss' % ( + ("-" if align == "l" else ""), + str(w)) + format_str = [_align(align, w) for align, w in + zip(self._alignments, column_widths)] + if self._headings[0]: + format_str.insert(0, _align(self._head_align, _head_width)) + format_str.insert(1, '|') + format_str = ' '.join(format_str) + '\n' + + s = [] + if self._headings[1]: + d = self._headings[1] + if self._headings[0]: + d = [""] + d + first_line = format_str % tuple(d) + s.append(first_line) + s.append("-" * (len(first_line) - 1) + "\n") + for i, line in enumerate(lines): + d = [l if self._alignments[j] != 'c' else + l.center(column_widths[j]) for j, l in enumerate(line)] + if self._headings[0]: + l = self._headings[0][i] + l = (l if self._head_align != 'c' else + l.center(_head_width)) + d = [l] + d + s.append(format_str % tuple(d)) + return ''.join(s)[:-1] # don't include trailing newline + + def _latex(self, printer): + """ + Returns the string representation of 'self'. + """ + # Check heading: + if self._headings[1]: + new_line = [] + for i in range(self._w): + # Format the item somehow if needed: + new_line.append(str(self._headings[1][i])) + self._headings[1] = new_line + + alignments = [] + if self._headings[0]: + self._headings[0] = [str(x) for x in self._headings[0]] + alignments = [self._head_align] + alignments.extend(self._alignments) + + s = r"\begin{tabular}{" + " ".join(alignments) + "}\n" + + if self._headings[1]: + d = self._headings[1] + if self._headings[0]: + d = [""] + d + first_line = " & ".join(d) + r" \\" + "\n" + s += first_line + s += r"\hline" + "\n" + for i, line in enumerate(self._lines): + d = [] + for j, x in enumerate(line): + if self._wipe_zeros and (x in (0, "0")): + d.append(" ") + continue + f = self._column_formats[j] + if f: + if isinstance(f, FunctionType): + v = f(x, i, j) + if v is None: + v = printer._print(x) + else: + v = f % x + d.append(v) + else: + v = printer._print(x) + d.append("$%s$" % v) + if self._headings[0]: + d = [self._headings[0][i]] + d + s += " & ".join(d) + r" \\" + "\n" + s += r"\end{tabular}" + return s diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tensorflow.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tensorflow.py new file mode 100644 index 0000000000000000000000000000000000000000..78b0df62b611f336468769e4cee1695bc068eee9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tensorflow.py @@ -0,0 +1,224 @@ +import sympy.codegen +import sympy.codegen.cfunctions +from sympy.external.importtools import version_tuple +from collections.abc import Iterable + +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.codegen.cfunctions import Sqrt +from sympy.external import import_module +from sympy.printing.precedence import PRECEDENCE +from sympy.printing.pycode import AbstractPythonCodePrinter, ArrayPrinter +import sympy + +tensorflow = import_module('tensorflow') + +class TensorflowPrinter(ArrayPrinter, AbstractPythonCodePrinter): + """ + Tensorflow printer which handles vectorized piecewise functions, + logical operators, max/min, and relational operators. + """ + printmethod = "_tensorflowcode" + + mapping = { + sympy.Abs: "tensorflow.math.abs", + sympy.sign: "tensorflow.math.sign", + + # XXX May raise error for ints. + sympy.ceiling: "tensorflow.math.ceil", + sympy.floor: "tensorflow.math.floor", + sympy.log: "tensorflow.math.log", + sympy.exp: "tensorflow.math.exp", + Sqrt: "tensorflow.math.sqrt", + sympy.cos: "tensorflow.math.cos", + sympy.acos: "tensorflow.math.acos", + sympy.sin: "tensorflow.math.sin", + sympy.asin: "tensorflow.math.asin", + sympy.tan: "tensorflow.math.tan", + sympy.atan: "tensorflow.math.atan", + sympy.atan2: "tensorflow.math.atan2", + # XXX Also may give NaN for complex results. + sympy.cosh: "tensorflow.math.cosh", + sympy.acosh: "tensorflow.math.acosh", + sympy.sinh: "tensorflow.math.sinh", + sympy.asinh: "tensorflow.math.asinh", + sympy.tanh: "tensorflow.math.tanh", + sympy.atanh: "tensorflow.math.atanh", + + sympy.re: "tensorflow.math.real", + sympy.im: "tensorflow.math.imag", + sympy.arg: "tensorflow.math.angle", + + # XXX May raise error for ints and complexes + sympy.erf: "tensorflow.math.erf", + sympy.loggamma: "tensorflow.math.lgamma", + + sympy.Eq: "tensorflow.math.equal", + sympy.Ne: "tensorflow.math.not_equal", + sympy.StrictGreaterThan: "tensorflow.math.greater", + sympy.StrictLessThan: "tensorflow.math.less", + sympy.LessThan: "tensorflow.math.less_equal", + sympy.GreaterThan: "tensorflow.math.greater_equal", + + sympy.And: "tensorflow.math.logical_and", + sympy.Or: "tensorflow.math.logical_or", + sympy.Not: "tensorflow.math.logical_not", + sympy.Max: "tensorflow.math.maximum", + sympy.Min: "tensorflow.math.minimum", + + # Matrices + sympy.MatAdd: "tensorflow.math.add", + sympy.HadamardProduct: "tensorflow.math.multiply", + sympy.Trace: "tensorflow.linalg.trace", + + # XXX May raise error for integer matrices. + sympy.Determinant : "tensorflow.linalg.det", + } + + _default_settings = dict( + AbstractPythonCodePrinter._default_settings, + tensorflow_version=None + ) + + def __init__(self, settings=None): + super().__init__(settings) + + version = self._settings['tensorflow_version'] + if version is None and tensorflow: + version = tensorflow.__version__ + self.tensorflow_version = version + + def _print_Function(self, expr): + op = self.mapping.get(type(expr), None) + if op is None: + return super()._print_Basic(expr) + children = [self._print(arg) for arg in expr.args] + if len(children) == 1: + return "%s(%s)" % ( + self._module_format(op), + children[0] + ) + else: + return self._expand_fold_binary_op(op, children) + + _print_Expr = _print_Function + _print_Application = _print_Function + _print_MatrixExpr = _print_Function + # TODO: a better class structure would avoid this mess: + _print_Relational = _print_Function + _print_Not = _print_Function + _print_And = _print_Function + _print_Or = _print_Function + _print_HadamardProduct = _print_Function + _print_Trace = _print_Function + _print_Determinant = _print_Function + + def _print_Inverse(self, expr): + op = self._module_format('tensorflow.linalg.inv') + return "{}({})".format(op, self._print(expr.arg)) + + def _print_Transpose(self, expr): + version = self.tensorflow_version + if version and version_tuple(version) < version_tuple('1.14'): + op = self._module_format('tensorflow.matrix_transpose') + else: + op = self._module_format('tensorflow.linalg.matrix_transpose') + return "{}({})".format(op, self._print(expr.arg)) + + def _print_Derivative(self, expr): + variables = expr.variables + if any(isinstance(i, Iterable) for i in variables): + raise NotImplementedError("derivation by multiple variables is not supported") + def unfold(expr, args): + if not args: + return self._print(expr) + return "%s(%s, %s)[0]" % ( + self._module_format("tensorflow.gradients"), + unfold(expr, args[:-1]), + self._print(args[-1]), + ) + return unfold(expr.expr, variables) + + def _print_Piecewise(self, expr): + version = self.tensorflow_version + if version and version_tuple(version) < version_tuple('1.0'): + tensorflow_piecewise = "tensorflow.select" + else: + tensorflow_piecewise = "tensorflow.where" + + from sympy.functions.elementary.piecewise import Piecewise + e, cond = expr.args[0].args + if len(expr.args) == 1: + return '{}({}, {}, {})'.format( + self._module_format(tensorflow_piecewise), + self._print(cond), + self._print(e), + 0) + + return '{}({}, {}, {})'.format( + self._module_format(tensorflow_piecewise), + self._print(cond), + self._print(e), + self._print(Piecewise(*expr.args[1:]))) + + def _print_Pow(self, expr): + # XXX May raise error for + # int**float or int**complex or float**complex + base, exp = expr.args + if expr.exp == S.Half: + return "{}({})".format( + self._module_format("tensorflow.math.sqrt"), self._print(base)) + return "{}({}, {})".format( + self._module_format("tensorflow.math.pow"), + self._print(base), self._print(exp)) + + def _print_MatrixBase(self, expr): + tensorflow_f = "tensorflow.Variable" if expr.free_symbols else "tensorflow.constant" + data = "["+", ".join(["["+", ".join([self._print(j) for j in i])+"]" for i in expr.tolist()])+"]" + return "%s(%s)" % ( + self._module_format(tensorflow_f), + data, + ) + + def _print_MatMul(self, expr): + from sympy.matrices.expressions import MatrixExpr + mat_args = [arg for arg in expr.args if isinstance(arg, MatrixExpr)] + args = [arg for arg in expr.args if arg not in mat_args] + if args: + return "%s*%s" % ( + self.parenthesize(Mul.fromiter(args), PRECEDENCE["Mul"]), + self._expand_fold_binary_op( + "tensorflow.linalg.matmul", mat_args) + ) + else: + return self._expand_fold_binary_op( + "tensorflow.linalg.matmul", mat_args) + + def _print_MatPow(self, expr): + return self._expand_fold_binary_op( + "tensorflow.linalg.matmul", [expr.base]*expr.exp) + + def _print_CodeBlock(self, expr): + # TODO: is this necessary? + ret = [] + for subexpr in expr.args: + ret.append(self._print(subexpr)) + return "\n".join(ret) + + def _print_isnan(self, exp): + return f'tensorflow.math.is_nan({self._print(*exp.args)})' + + def _print_isinf(self, exp): + return f'tensorflow.math.is_inf({self._print(*exp.args)})' + + _module = "tensorflow" + _einsum = "linalg.einsum" + _add = "math.add" + _transpose = "transpose" + _ones = "ones" + _zeros = "zeros" + + +def tensorflow_code(expr, **settings): + printer = TensorflowPrinter(settings) + return printer.doprint(expr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/theanocode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/theanocode.py new file mode 100644 index 0000000000000000000000000000000000000000..dce908865d426dabede2b6749ad944e5a420e4cf --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/theanocode.py @@ -0,0 +1,571 @@ +""" +.. deprecated:: 1.8 + + ``sympy.printing.theanocode`` is deprecated. Theano has been renamed to + Aesara. Use ``sympy.printing.aesaracode`` instead. See + :ref:`theanocode-deprecated` for more information. + +""" +from __future__ import annotations +import math +from typing import Any + +from sympy.external import import_module +from sympy.printing.printer import Printer +from sympy.utilities.iterables import is_sequence +import sympy +from functools import partial + +from sympy.utilities.decorator import doctest_depends_on +from sympy.utilities.exceptions import sympy_deprecation_warning + + +__doctest_requires__ = {('theano_function',): ['theano']} + + +theano = import_module('theano') + + +if theano: + ts = theano.scalar + tt = theano.tensor + from theano.sandbox import linalg as tlinalg + + mapping = { + sympy.Add: tt.add, + sympy.Mul: tt.mul, + sympy.Abs: tt.abs_, + sympy.sign: tt.sgn, + sympy.ceiling: tt.ceil, + sympy.floor: tt.floor, + sympy.log: tt.log, + sympy.exp: tt.exp, + sympy.sqrt: tt.sqrt, + sympy.cos: tt.cos, + sympy.acos: tt.arccos, + sympy.sin: tt.sin, + sympy.asin: tt.arcsin, + sympy.tan: tt.tan, + sympy.atan: tt.arctan, + sympy.atan2: tt.arctan2, + sympy.cosh: tt.cosh, + sympy.acosh: tt.arccosh, + sympy.sinh: tt.sinh, + sympy.asinh: tt.arcsinh, + sympy.tanh: tt.tanh, + sympy.atanh: tt.arctanh, + sympy.re: tt.real, + sympy.im: tt.imag, + sympy.arg: tt.angle, + sympy.erf: tt.erf, + sympy.gamma: tt.gamma, + sympy.loggamma: tt.gammaln, + sympy.Pow: tt.pow, + sympy.Eq: tt.eq, + sympy.StrictGreaterThan: tt.gt, + sympy.StrictLessThan: tt.lt, + sympy.LessThan: tt.le, + sympy.GreaterThan: tt.ge, + sympy.And: tt.and_, + sympy.Or: tt.or_, + sympy.Max: tt.maximum, # SymPy accept >2 inputs, Theano only 2 + sympy.Min: tt.minimum, # SymPy accept >2 inputs, Theano only 2 + sympy.conjugate: tt.conj, + sympy.core.numbers.ImaginaryUnit: lambda:tt.complex(0,1), + # Matrices + sympy.MatAdd: tt.Elemwise(ts.add), + sympy.HadamardProduct: tt.Elemwise(ts.mul), + sympy.Trace: tlinalg.trace, + sympy.Determinant : tlinalg.det, + sympy.Inverse: tlinalg.matrix_inverse, + sympy.Transpose: tt.DimShuffle((False, False), [1, 0]), + } + + +class TheanoPrinter(Printer): + """ Code printer which creates Theano symbolic expression graphs. + + Parameters + ========== + + cache : dict + Cache dictionary to use. If None (default) will use + the global cache. To create a printer which does not depend on or alter + global state pass an empty dictionary. Note: the dictionary is not + copied on initialization of the printer and will be updated in-place, + so using the same dict object when creating multiple printers or making + multiple calls to :func:`.theano_code` or :func:`.theano_function` means + the cache is shared between all these applications. + + Attributes + ========== + + cache : dict + A cache of Theano variables which have been created for SymPy + symbol-like objects (e.g. :class:`sympy.core.symbol.Symbol` or + :class:`sympy.matrices.expressions.MatrixSymbol`). This is used to + ensure that all references to a given symbol in an expression (or + multiple expressions) are printed as the same Theano variable, which is + created only once. Symbols are differentiated only by name and type. The + format of the cache's contents should be considered opaque to the user. + """ + printmethod = "_theano" + + def __init__(self, *args, **kwargs): + self.cache = kwargs.pop('cache', {}) + super().__init__(*args, **kwargs) + + def _get_key(self, s, name=None, dtype=None, broadcastable=None): + """ Get the cache key for a SymPy object. + + Parameters + ========== + + s : sympy.core.basic.Basic + SymPy object to get key for. + + name : str + Name of object, if it does not have a ``name`` attribute. + """ + + if name is None: + name = s.name + + return (name, type(s), s.args, dtype, broadcastable) + + def _get_or_create(self, s, name=None, dtype=None, broadcastable=None): + """ + Get the Theano variable for a SymPy symbol from the cache, or create it + if it does not exist. + """ + + # Defaults + if name is None: + name = s.name + if dtype is None: + dtype = 'floatX' + if broadcastable is None: + broadcastable = () + + key = self._get_key(s, name, dtype=dtype, broadcastable=broadcastable) + + if key in self.cache: + return self.cache[key] + + value = tt.tensor(name=name, dtype=dtype, broadcastable=broadcastable) + self.cache[key] = value + return value + + def _print_Symbol(self, s, **kwargs): + dtype = kwargs.get('dtypes', {}).get(s) + bc = kwargs.get('broadcastables', {}).get(s) + return self._get_or_create(s, dtype=dtype, broadcastable=bc) + + def _print_AppliedUndef(self, s, **kwargs): + name = str(type(s)) + '_' + str(s.args[0]) + dtype = kwargs.get('dtypes', {}).get(s) + bc = kwargs.get('broadcastables', {}).get(s) + return self._get_or_create(s, name=name, dtype=dtype, broadcastable=bc) + + def _print_Basic(self, expr, **kwargs): + op = mapping[type(expr)] + children = [self._print(arg, **kwargs) for arg in expr.args] + return op(*children) + + def _print_Number(self, n, **kwargs): + # Integers already taken care of below, interpret as float + return float(n.evalf()) + + def _print_MatrixSymbol(self, X, **kwargs): + dtype = kwargs.get('dtypes', {}).get(X) + return self._get_or_create(X, dtype=dtype, broadcastable=(None, None)) + + def _print_DenseMatrix(self, X, **kwargs): + if not hasattr(tt, 'stacklists'): + raise NotImplementedError( + "Matrix translation not yet supported in this version of Theano") + + return tt.stacklists([ + [self._print(arg, **kwargs) for arg in L] + for L in X.tolist() + ]) + + _print_ImmutableMatrix = _print_ImmutableDenseMatrix = _print_DenseMatrix + + def _print_MatMul(self, expr, **kwargs): + children = [self._print(arg, **kwargs) for arg in expr.args] + result = children[0] + for child in children[1:]: + result = tt.dot(result, child) + return result + + def _print_MatPow(self, expr, **kwargs): + children = [self._print(arg, **kwargs) for arg in expr.args] + result = 1 + if isinstance(children[1], int) and children[1] > 0: + for i in range(children[1]): + result = tt.dot(result, children[0]) + else: + raise NotImplementedError('''Only non-negative integer + powers of matrices can be handled by Theano at the moment''') + return result + + def _print_MatrixSlice(self, expr, **kwargs): + parent = self._print(expr.parent, **kwargs) + rowslice = self._print(slice(*expr.rowslice), **kwargs) + colslice = self._print(slice(*expr.colslice), **kwargs) + return parent[rowslice, colslice] + + def _print_BlockMatrix(self, expr, **kwargs): + nrows, ncols = expr.blocks.shape + blocks = [[self._print(expr.blocks[r, c], **kwargs) + for c in range(ncols)] + for r in range(nrows)] + return tt.join(0, *[tt.join(1, *row) for row in blocks]) + + + def _print_slice(self, expr, **kwargs): + return slice(*[self._print(i, **kwargs) + if isinstance(i, sympy.Basic) else i + for i in (expr.start, expr.stop, expr.step)]) + + def _print_Pi(self, expr, **kwargs): + return math.pi + + def _print_Exp1(self, expr, **kwargs): + return ts.exp(1) + + def _print_Piecewise(self, expr, **kwargs): + import numpy as np + e, cond = expr.args[0].args # First condition and corresponding value + + # Print conditional expression and value for first condition + p_cond = self._print(cond, **kwargs) + p_e = self._print(e, **kwargs) + + # One condition only + if len(expr.args) == 1: + # Return value if condition else NaN + return tt.switch(p_cond, p_e, np.nan) + + # Return value_1 if condition_1 else evaluate remaining conditions + p_remaining = self._print(sympy.Piecewise(*expr.args[1:]), **kwargs) + return tt.switch(p_cond, p_e, p_remaining) + + def _print_Rational(self, expr, **kwargs): + return tt.true_div(self._print(expr.p, **kwargs), + self._print(expr.q, **kwargs)) + + def _print_Integer(self, expr, **kwargs): + return expr.p + + def _print_factorial(self, expr, **kwargs): + return self._print(sympy.gamma(expr.args[0] + 1), **kwargs) + + def _print_Derivative(self, deriv, **kwargs): + rv = self._print(deriv.expr, **kwargs) + for var in deriv.variables: + var = self._print(var, **kwargs) + rv = tt.Rop(rv, var, tt.ones_like(var)) + return rv + + def emptyPrinter(self, expr): + return expr + + def doprint(self, expr, dtypes=None, broadcastables=None): + """ Convert a SymPy expression to a Theano graph variable. + + The ``dtypes`` and ``broadcastables`` arguments are used to specify the + data type, dimension, and broadcasting behavior of the Theano variables + corresponding to the free symbols in ``expr``. Each is a mapping from + SymPy symbols to the value of the corresponding argument to + ``theano.tensor.Tensor``. + + See the corresponding `documentation page`__ for more information on + broadcasting in Theano. + + .. __: http://deeplearning.net/software/theano/tutorial/broadcasting.html + + Parameters + ========== + + expr : sympy.core.expr.Expr + SymPy expression to print. + + dtypes : dict + Mapping from SymPy symbols to Theano datatypes to use when creating + new Theano variables for those symbols. Corresponds to the ``dtype`` + argument to ``theano.tensor.Tensor``. Defaults to ``'floatX'`` + for symbols not included in the mapping. + + broadcastables : dict + Mapping from SymPy symbols to the value of the ``broadcastable`` + argument to ``theano.tensor.Tensor`` to use when creating Theano + variables for those symbols. Defaults to the empty tuple for symbols + not included in the mapping (resulting in a scalar). + + Returns + ======= + + theano.gof.graph.Variable + A variable corresponding to the expression's value in a Theano + symbolic expression graph. + + """ + if dtypes is None: + dtypes = {} + if broadcastables is None: + broadcastables = {} + + return self._print(expr, dtypes=dtypes, broadcastables=broadcastables) + + +global_cache: dict[Any, Any] = {} + + +def theano_code(expr, cache=None, **kwargs): + """ + Convert a SymPy expression into a Theano graph variable. + + .. deprecated:: 1.8 + + ``sympy.printing.theanocode`` is deprecated. Theano has been renamed to + Aesara. Use ``sympy.printing.aesaracode`` instead. See + :ref:`theanocode-deprecated` for more information. + + Parameters + ========== + + expr : sympy.core.expr.Expr + SymPy expression object to convert. + + cache : dict + Cached Theano variables (see :class:`TheanoPrinter.cache + `). Defaults to the module-level global cache. + + dtypes : dict + Passed to :meth:`.TheanoPrinter.doprint`. + + broadcastables : dict + Passed to :meth:`.TheanoPrinter.doprint`. + + Returns + ======= + + theano.gof.graph.Variable + A variable corresponding to the expression's value in a Theano symbolic + expression graph. + + """ + sympy_deprecation_warning( + """ + sympy.printing.theanocode is deprecated. Theano has been renamed to + Aesara. Use sympy.printing.aesaracode instead.""", + deprecated_since_version="1.8", + active_deprecations_target='theanocode-deprecated') + + if not theano: + raise ImportError("theano is required for theano_code") + + if cache is None: + cache = global_cache + + return TheanoPrinter(cache=cache, settings={}).doprint(expr, **kwargs) + + +def dim_handling(inputs, dim=None, dims=None, broadcastables=None): + r""" + Get value of ``broadcastables`` argument to :func:`.theano_code` from + keyword arguments to :func:`.theano_function`. + + Included for backwards compatibility. + + Parameters + ========== + + inputs + Sequence of input symbols. + + dim : int + Common number of dimensions for all inputs. Overrides other arguments + if given. + + dims : dict + Mapping from input symbols to number of dimensions. Overrides + ``broadcastables`` argument if given. + + broadcastables : dict + Explicit value of ``broadcastables`` argument to + :meth:`.TheanoPrinter.doprint`. If not None function will return this value unchanged. + + Returns + ======= + dict + Dictionary mapping elements of ``inputs`` to their "broadcastable" + values (tuple of ``bool``\ s). + """ + if dim is not None: + return dict.fromkeys(inputs, (False,) * dim) + + if dims is not None: + maxdim = max(dims.values()) + return { + s: (False,) * d + (True,) * (maxdim - d) + for s, d in dims.items() + } + + if broadcastables is not None: + return broadcastables + + return {} + + +@doctest_depends_on(modules=('theano',)) +def theano_function(inputs, outputs, scalar=False, *, + dim=None, dims=None, broadcastables=None, **kwargs): + """ + Create a Theano function from SymPy expressions. + + .. deprecated:: 1.8 + + ``sympy.printing.theanocode`` is deprecated. Theano has been renamed to + Aesara. Use ``sympy.printing.aesaracode`` instead. See + :ref:`theanocode-deprecated` for more information. + + The inputs and outputs are converted to Theano variables using + :func:`.theano_code` and then passed to ``theano.function``. + + Parameters + ========== + + inputs + Sequence of symbols which constitute the inputs of the function. + + outputs + Sequence of expressions which constitute the outputs(s) of the + function. The free symbols of each expression must be a subset of + ``inputs``. + + scalar : bool + Convert 0-dimensional arrays in output to scalars. This will return a + Python wrapper function around the Theano function object. + + cache : dict + Cached Theano variables (see :class:`TheanoPrinter.cache + `). Defaults to the module-level global cache. + + dtypes : dict + Passed to :meth:`.TheanoPrinter.doprint`. + + broadcastables : dict + Passed to :meth:`.TheanoPrinter.doprint`. + + dims : dict + Alternative to ``broadcastables`` argument. Mapping from elements of + ``inputs`` to integers indicating the dimension of their associated + arrays/tensors. Overrides ``broadcastables`` argument if given. + + dim : int + Another alternative to the ``broadcastables`` argument. Common number of + dimensions to use for all arrays/tensors. + ``theano_function([x, y], [...], dim=2)`` is equivalent to using + ``broadcastables={x: (False, False), y: (False, False)}``. + + Returns + ======= + callable + A callable object which takes values of ``inputs`` as positional + arguments and returns an output array for each of the expressions + in ``outputs``. If ``outputs`` is a single expression the function will + return a Numpy array, if it is a list of multiple expressions the + function will return a list of arrays. See description of the ``squeeze`` + argument above for the behavior when a single output is passed in a list. + The returned object will either be an instance of + ``theano.compile.function_module.Function`` or a Python wrapper + function around one. In both cases, the returned value will have a + ``theano_function`` attribute which points to the return value of + ``theano.function``. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.printing.theanocode import theano_function + + A simple function with one input and one output: + + >>> f1 = theano_function([x], [x**2 - 1], scalar=True) + >>> f1(3) + 8.0 + + A function with multiple inputs and one output: + + >>> f2 = theano_function([x, y, z], [(x**z + y**z)**(1/z)], scalar=True) + >>> f2(3, 4, 2) + 5.0 + + A function with multiple inputs and multiple outputs: + + >>> f3 = theano_function([x, y], [x**2 + y**2, x**2 - y**2], scalar=True) + >>> f3(2, 3) + [13.0, -5.0] + + See also + ======== + + dim_handling + + """ + sympy_deprecation_warning( + """ + sympy.printing.theanocode is deprecated. Theano has been renamed to Aesara. Use sympy.printing.aesaracode instead""", + deprecated_since_version="1.8", + active_deprecations_target='theanocode-deprecated') + + if not theano: + raise ImportError("theano is required for theano_function") + + # Pop off non-theano keyword args + cache = kwargs.pop('cache', {}) + dtypes = kwargs.pop('dtypes', {}) + + broadcastables = dim_handling( + inputs, dim=dim, dims=dims, broadcastables=broadcastables, + ) + + # Print inputs/outputs + code = partial(theano_code, cache=cache, dtypes=dtypes, + broadcastables=broadcastables) + tinputs = list(map(code, inputs)) + toutputs = list(map(code, outputs)) + + #fix constant expressions as variables + toutputs = [output if isinstance(output, theano.Variable) else tt.as_tensor_variable(output) for output in toutputs] + + if len(toutputs) == 1: + toutputs = toutputs[0] + + # Compile theano func + func = theano.function(tinputs, toutputs, **kwargs) + + is_0d = [len(o.variable.broadcastable) == 0 for o in func.outputs] + + # No wrapper required + if not scalar or not any(is_0d): + func.theano_function = func + return func + + # Create wrapper to convert 0-dimensional outputs to scalars + def wrapper(*args): + out = func(*args) + # out can be array(1.0) or [array(1.0), array(2.0)] + + if is_sequence(out): + return [o[()] if is_0d[i] else o for i, o in enumerate(out)] + else: + return out[()] + + wrapper.__wrapped__ = func + wrapper.__doc__ = func.__doc__ + wrapper.theano_function = func + return wrapper diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tree.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tree.py new file mode 100644 index 0000000000000000000000000000000000000000..82dac013419fbe93f63dcf5b90b3a529d72a32bc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/printing/tree.py @@ -0,0 +1,175 @@ +def pprint_nodes(subtrees): + """ + Prettyprints systems of nodes. + + Examples + ======== + + >>> from sympy.printing.tree import pprint_nodes + >>> print(pprint_nodes(["a", "b1\\nb2", "c"])) + +-a + +-b1 + | b2 + +-c + + """ + def indent(s, type=1): + x = s.split("\n") + r = "+-%s\n" % x[0] + for a in x[1:]: + if a == "": + continue + if type == 1: + r += "| %s\n" % a + else: + r += " %s\n" % a + return r + if not subtrees: + return "" + f = "" + for a in subtrees[:-1]: + f += indent(a) + f += indent(subtrees[-1], 2) + return f + + +def print_node(node, assumptions=True): + """ + Returns information about the "node". + + This includes class name, string representation and assumptions. + + Parameters + ========== + + assumptions : bool, optional + See the ``assumptions`` keyword in ``tree`` + """ + s = "%s: %s\n" % (node.__class__.__name__, str(node)) + + if assumptions: + d = node._assumptions + else: + d = None + + if d: + for a in sorted(d): + v = d[a] + if v is None: + continue + s += "%s: %s\n" % (a, v) + + return s + + +def tree(node, assumptions=True): + """ + Returns a tree representation of "node" as a string. + + It uses print_node() together with pprint_nodes() on node.args recursively. + + Parameters + ========== + + assumptions : bool, optional + The flag to decide whether to print out all the assumption data + (such as ``is_integer`, ``is_real``) associated with the + expression or not. + + Enabling the flag makes the result verbose, and the printed + result may not be deterministic because of the randomness used + in backtracing the assumptions. + + See Also + ======== + + print_tree + + """ + subtrees = [] + for arg in node.args: + subtrees.append(tree(arg, assumptions=assumptions)) + s = print_node(node, assumptions=assumptions) + pprint_nodes(subtrees) + return s + + +def print_tree(node, assumptions=True): + """ + Prints a tree representation of "node". + + Parameters + ========== + + assumptions : bool, optional + The flag to decide whether to print out all the assumption data + (such as ``is_integer`, ``is_real``) associated with the + expression or not. + + Enabling the flag makes the result verbose, and the printed + result may not be deterministic because of the randomness used + in backtracing the assumptions. + + Examples + ======== + + >>> from sympy.printing import print_tree + >>> from sympy import Symbol + >>> x = Symbol('x', odd=True) + >>> y = Symbol('y', even=True) + + Printing with full assumptions information: + + >>> print_tree(y**x) + Pow: y**x + +-Symbol: y + | algebraic: True + | commutative: True + | complex: True + | even: True + | extended_real: True + | finite: True + | hermitian: True + | imaginary: False + | infinite: False + | integer: True + | irrational: False + | noninteger: False + | odd: False + | rational: True + | real: True + | transcendental: False + +-Symbol: x + algebraic: True + commutative: True + complex: True + even: False + extended_nonzero: True + extended_real: True + finite: True + hermitian: True + imaginary: False + infinite: False + integer: True + irrational: False + noninteger: False + nonzero: True + odd: True + rational: True + real: True + transcendental: False + zero: False + + Hiding the assumptions: + + >>> print_tree(y**x, assumptions=False) + Pow: y**x + +-Symbol: y + +-Symbol: x + + See Also + ======== + + tree + + """ + print(tree(node, assumptions=assumptions)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3a84b7517819bb2fc9886274e09d955a74cabca1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__init__.py @@ -0,0 +1,8 @@ +""" +Sandbox module of SymPy. + +This module contains experimental code, use at your own risk! + +There is no warranty that this code will still be located here in future +versions of SymPy. +""" diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/indexed_integrals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/indexed_integrals.py new file mode 100644 index 0000000000000000000000000000000000000000..c0c17d141448b5a71cb814bff76a710a5bd43f88 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/indexed_integrals.py @@ -0,0 +1,72 @@ +from sympy.tensor import Indexed +from sympy.core.containers import Tuple +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.integrals.integrals import Integral + + +class IndexedIntegral(Integral): + """ + Experimental class to test integration by indexed variables. + + Usage is analogue to ``Integral``, it simply adds awareness of + integration over indices. + + Contraction of non-identical index symbols referring to the same + ``IndexedBase`` is not yet supported. + + Examples + ======== + + >>> from sympy.sandbox.indexed_integrals import IndexedIntegral + >>> from sympy import IndexedBase, symbols + >>> A = IndexedBase('A') + >>> i, j = symbols('i j', integer=True) + >>> ii = IndexedIntegral(A[i], A[i]) + >>> ii + Integral(_A[i], _A[i]) + >>> ii.doit() + A[i]**2/2 + + If the indices are different, indexed objects are considered to be + different variables: + + >>> i2 = IndexedIntegral(A[j], A[i]) + >>> i2 + Integral(A[j], _A[i]) + >>> i2.doit() + A[i]*A[j] + """ + + def __new__(cls, function, *limits, **assumptions): + repl, limits = IndexedIntegral._indexed_process_limits(limits) + function = sympify(function) + function = function.xreplace(repl) + obj = Integral.__new__(cls, function, *limits, **assumptions) + obj._indexed_repl = repl + obj._indexed_reverse_repl = {val: key for key, val in repl.items()} + return obj + + def doit(self): + res = super().doit() + return res.xreplace(self._indexed_reverse_repl) + + @staticmethod + def _indexed_process_limits(limits): + repl = {} + newlimits = [] + for i in limits: + if isinstance(i, (tuple, list, Tuple)): + v = i[0] + vrest = i[1:] + else: + v = i + vrest = () + if isinstance(v, Indexed): + if v not in repl: + r = Dummy(str(v)) + repl[v] = r + newlimits.append((r,)+vrest) + else: + newlimits.append(i) + return repl, newlimits diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..953653e21856b82bc0b708ccd922efb728a084ed --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/__init__.py @@ -0,0 +1,23 @@ +"""A module that handles series: find a limit, order the series etc. +""" +from .order import Order +from .limits import limit, Limit +from .gruntz import gruntz +from .series import series +from .approximants import approximants +from .residues import residue +from .sequences import SeqPer, SeqFormula, sequence, SeqAdd, SeqMul +from .fourier import fourier_series +from .formal import fps +from .limitseq import difference_delta, limit_seq + +from sympy.core.singleton import S +EmptySequence = S.EmptySequence + +O = Order + +__all__ = ['Order', 'O', 'limit', 'Limit', 'gruntz', 'series', 'approximants', + 'residue', 'EmptySequence', 'SeqPer', 'SeqFormula', 'sequence', + 'SeqAdd', 'SeqMul', 'fourier_series', 'fps', 'difference_delta', + 'limit_seq' + ] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/acceleration.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/acceleration.py new file mode 100644 index 0000000000000000000000000000000000000000..e2c7c1629a4b0d52e2aa33bd415886dfed515693 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/acceleration.py @@ -0,0 +1,101 @@ +""" +Convergence acceleration / extrapolation methods for series and +sequences. + +References: +Carl M. Bender & Steven A. Orszag, "Advanced Mathematical Methods for +Scientists and Engineers: Asymptotic Methods and Perturbation Theory", +Springer 1999. (Shanks transformation: pp. 368-375, Richardson +extrapolation: pp. 375-377.) +""" + +from sympy.core.numbers import Integer +from sympy.core.singleton import S +from sympy.functions.combinatorial.factorials import factorial + + +def richardson(A, k, n, N): + """ + Calculate an approximation for lim k->oo A(k) using Richardson + extrapolation with the terms A(n), A(n+1), ..., A(n+N+1). + Choosing N ~= 2*n often gives good results. + + Examples + ======== + + A simple example is to calculate exp(1) using the limit definition. + This limit converges slowly; n = 100 only produces two accurate + digits: + + >>> from sympy.abc import n + >>> e = (1 + 1/n)**n + >>> print(round(e.subs(n, 100).evalf(), 10)) + 2.7048138294 + + Richardson extrapolation with 11 appropriately chosen terms gives + a value that is accurate to the indicated precision: + + >>> from sympy import E + >>> from sympy.series.acceleration import richardson + >>> print(round(richardson(e, n, 10, 20).evalf(), 10)) + 2.7182818285 + >>> print(round(E.evalf(), 10)) + 2.7182818285 + + Another useful application is to speed up convergence of series. + Computing 100 terms of the zeta(2) series 1/k**2 yields only + two accurate digits: + + >>> from sympy.abc import k, n + >>> from sympy import Sum + >>> A = Sum(k**-2, (k, 1, n)) + >>> print(round(A.subs(n, 100).evalf(), 10)) + 1.6349839002 + + Richardson extrapolation performs much better: + + >>> from sympy import pi + >>> print(round(richardson(A, n, 10, 20).evalf(), 10)) + 1.6449340668 + >>> print(round(((pi**2)/6).evalf(), 10)) # Exact value + 1.6449340668 + + """ + s = S.Zero + for j in range(0, N + 1): + s += (A.subs(k, Integer(n + j)).doit() * (n + j)**N * + S.NegativeOne**(j + N) / (factorial(j) * factorial(N - j))) + return s + + +def shanks(A, k, n, m=1): + """ + Calculate an approximation for lim k->oo A(k) using the n-term Shanks + transformation S(A)(n). With m > 1, calculate the m-fold recursive + Shanks transformation S(S(...S(A)...))(n). + + The Shanks transformation is useful for summing Taylor series that + converge slowly near a pole or singularity, e.g. for log(2): + + >>> from sympy.abc import k, n + >>> from sympy import Sum, Integer + >>> from sympy.series.acceleration import shanks + >>> A = Sum(Integer(-1)**(k+1) / k, (k, 1, n)) + >>> print(round(A.subs(n, 100).doit().evalf(), 10)) + 0.6881721793 + >>> print(round(shanks(A, n, 25).evalf(), 10)) + 0.6931396564 + >>> print(round(shanks(A, n, 25, 5).evalf(), 10)) + 0.6931471806 + + The correct value is 0.6931471805599453094172321215. + """ + table = [A.subs(k, Integer(j)).doit() for j in range(n + m + 2)] + table2 = table.copy() + + for i in range(1, m + 1): + for j in range(i, n + m + 1): + x, y, z = table[j - 1], table[j], table[j + 1] + table2[j] = (z*x - y**2) / (z + x - 2*y) + table = table2.copy() + return table[n] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/approximants.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/approximants.py new file mode 100644 index 0000000000000000000000000000000000000000..3d54ce41bc7367606ae6260f8e9ac00149cedc0f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/approximants.py @@ -0,0 +1,103 @@ +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.polys.polytools import lcm +from sympy.utilities import public + +@public +def approximants(l, X=Symbol('x'), simplify=False): + """ + Return a generator for consecutive Pade approximants for a series. + It can also be used for computing the rational generating function of a + series when possible, since the last approximant returned by the generator + will be the generating function (if any). + + Explanation + =========== + + The input list can contain more complex expressions than integer or rational + numbers; symbols may also be involved in the computation. An example below + show how to compute the generating function of the whole Pascal triangle. + + The generator can be asked to apply the sympy.simplify function on each + generated term, which will make the computation slower; however it may be + useful when symbols are involved in the expressions. + + Examples + ======== + + >>> from sympy.series import approximants + >>> from sympy import lucas, fibonacci, symbols, binomial + >>> g = [lucas(k) for k in range(16)] + >>> [e for e in approximants(g)] + [2, -4/(x - 2), (5*x - 2)/(3*x - 1), (x - 2)/(x**2 + x - 1)] + + >>> h = [fibonacci(k) for k in range(16)] + >>> [e for e in approximants(h)] + [x, -x/(x - 1), (x**2 - x)/(2*x - 1), -x/(x**2 + x - 1)] + + >>> x, t = symbols("x,t") + >>> p=[sum(binomial(k,i)*x**i for i in range(k+1)) for k in range(16)] + >>> y = approximants(p, t) + >>> for k in range(3): print(next(y)) + 1 + (x + 1)/((-x - 1)*(t*(x + 1) + (x + 1)/(-x - 1))) + nan + + >>> y = approximants(p, t, simplify=True) + >>> for k in range(3): print(next(y)) + 1 + -1/(t*(x + 1) - 1) + nan + + See Also + ======== + + sympy.concrete.guess.guess_generating_function_rational + mpmath.pade + """ + from sympy.simplify import simplify as simp + from sympy.simplify.radsimp import denom + p1, q1 = [S.One], [S.Zero] + p2, q2 = [S.Zero], [S.One] + while len(l): + b = 0 + while l[b]==0: + b += 1 + if b == len(l): + return + m = [S.One/l[b]] + for k in range(b+1, len(l)): + s = 0 + for j in range(b, k): + s -= l[j+1] * m[b-j-1] + m.append(s/l[b]) + l = m + a, l[0] = l[0], 0 + p = [0] * max(len(p2), b+len(p1)) + q = [0] * max(len(q2), b+len(q1)) + for k in range(len(p2)): + p[k] = a*p2[k] + for k in range(b, b+len(p1)): + p[k] += p1[k-b] + for k in range(len(q2)): + q[k] = a*q2[k] + for k in range(b, b+len(q1)): + q[k] += q1[k-b] + while p[-1]==0: p.pop() + while q[-1]==0: q.pop() + p1, p2 = p2, p + q1, q2 = q2, q + + # yield result + c = 1 + for x in p: + c = lcm(c, denom(x)) + for x in q: + c = lcm(c, denom(x)) + out = ( sum(c*e*X**k for k, e in enumerate(p)) + / sum(c*e*X**k for k, e in enumerate(q)) ) + if simplify: + yield(simp(out)) + else: + yield out + return diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/aseries.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/aseries.py new file mode 100644 index 0000000000000000000000000000000000000000..dbbe0664e6d43a9329f37789c16c48143eda5413 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/aseries.py @@ -0,0 +1,10 @@ +from sympy.core.sympify import sympify + + +def aseries(expr, x=None, n=6, bound=0, hir=False): + """ + See the docstring of Expr.aseries() for complete details of this wrapper. + + """ + expr = sympify(expr) + return expr.aseries(x, n, bound, hir) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/formal.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/formal.py new file mode 100644 index 0000000000000000000000000000000000000000..ada591e03dd607daf8f8a5da1cf38cf283a3ed86 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/formal.py @@ -0,0 +1,1863 @@ +"""Formal Power Series""" + +from collections import defaultdict + +from sympy.core.numbers import (nan, oo, zoo) +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.function import Derivative, Function, expand +from sympy.core.mul import Mul +from sympy.core.numbers import Rational +from sympy.core.relational import Eq +from sympy.sets.sets import Interval +from sympy.core.singleton import S +from sympy.core.symbol import Wild, Dummy, symbols, Symbol +from sympy.core.sympify import sympify +from sympy.discrete.convolutions import convolution +from sympy.functions.combinatorial.factorials import binomial, factorial, rf +from sympy.functions.combinatorial.numbers import bell +from sympy.functions.elementary.integers import floor, frac, ceiling +from sympy.functions.elementary.miscellaneous import Min, Max +from sympy.functions.elementary.piecewise import Piecewise +from sympy.series.limits import Limit +from sympy.series.order import Order +from sympy.series.sequences import sequence +from sympy.series.series_class import SeriesBase +from sympy.utilities.iterables import iterable + + + +def rational_algorithm(f, x, k, order=4, full=False): + """ + Rational algorithm for computing + formula of coefficients of Formal Power Series + of a function. + + Explanation + =========== + + Applicable when f(x) or some derivative of f(x) + is a rational function in x. + + :func:`rational_algorithm` uses :func:`~.apart` function for partial fraction + decomposition. :func:`~.apart` by default uses 'undetermined coefficients + method'. By setting ``full=True``, 'Bronstein's algorithm' can be used + instead. + + Looks for derivative of a function up to 4'th order (by default). + This can be overridden using order option. + + Parameters + ========== + + x : Symbol + order : int, optional + Order of the derivative of ``f``, Default is 4. + full : bool + + Returns + ======= + + formula : Expr + ind : Expr + Independent terms. + order : int + full : bool + + Examples + ======== + + >>> from sympy import log, atan + >>> from sympy.series.formal import rational_algorithm as ra + >>> from sympy.abc import x, k + + >>> ra(1 / (1 - x), x, k) + (1, 0, 0) + >>> ra(log(1 + x), x, k) + (-1/((-1)**k*k), 0, 1) + + >>> ra(atan(x), x, k, full=True) + ((-I/(2*(-I)**k) + I/(2*I**k))/k, 0, 1) + + Notes + ===== + + By setting ``full=True``, range of admissible functions to be solved using + ``rational_algorithm`` can be increased. This option should be used + carefully as it can significantly slow down the computation as ``doit`` is + performed on the :class:`~.RootSum` object returned by the :func:`~.apart` + function. Use ``full=False`` whenever possible. + + See Also + ======== + + sympy.polys.partfrac.apart + + References + ========== + + .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf + .. [2] Power Series in Computer Algebra - Wolfram Koepf + + """ + from sympy.polys import RootSum, apart + from sympy.integrals import integrate + + diff = f + ds = [] # list of diff + + for i in range(order + 1): + if i: + diff = diff.diff(x) + + if diff.is_rational_function(x): + coeff, sep = S.Zero, S.Zero + + terms = apart(diff, x, full=full) + if terms.has(RootSum): + terms = terms.doit() + + for t in Add.make_args(terms): + num, den = t.as_numer_denom() + if not den.has(x): + sep += t + else: + if isinstance(den, Mul): + # m*(n*x - a)**j -> (n*x - a)**j + ind = den.as_independent(x) + den = ind[1] + num /= ind[0] + + # (n*x - a)**j -> (x - b) + den, j = den.as_base_exp() + a, xterm = den.as_coeff_add(x) + + # term -> m/x**n + if not a: + sep += t + continue + + xc = xterm[0].coeff(x) + a /= -xc + num /= xc**j + + ak = ((-1)**j * num * + binomial(j + k - 1, k).rewrite(factorial) / + a**(j + k)) + coeff += ak + + # Hacky, better way? + if coeff.is_zero: + return None + if (coeff.has(x) or coeff.has(zoo) or coeff.has(oo) or + coeff.has(nan)): + return None + + for j in range(i): + coeff = (coeff / (k + j + 1)) + sep = integrate(sep, x) + sep += (ds.pop() - sep).limit(x, 0) # constant of integration + return (coeff.subs(k, k - i), sep, i) + + else: + ds.append(diff) + + return None + + +def rational_independent(terms, x): + """ + Returns a list of all the rationally independent terms. + + Examples + ======== + + >>> from sympy import sin, cos + >>> from sympy.series.formal import rational_independent + >>> from sympy.abc import x + + >>> rational_independent([cos(x), sin(x)], x) + [cos(x), sin(x)] + >>> rational_independent([x**2, sin(x), x*sin(x), x**3], x) + [x**3 + x**2, x*sin(x) + sin(x)] + """ + if not terms: + return [] + + ind = terms[0:1] + + for t in terms[1:]: + n = t.as_independent(x)[1] + for i, term in enumerate(ind): + d = term.as_independent(x)[1] + q = (n / d).cancel() + if q.is_rational_function(x): + ind[i] += t + break + else: + ind.append(t) + return ind + + +def simpleDE(f, x, g, order=4): + r""" + Generates simple DE. + + Explanation + =========== + + DE is of the form + + .. math:: + f^k(x) + \sum\limits_{j=0}^{k-1} A_j f^j(x) = 0 + + where :math:`A_j` should be rational function in x. + + Generates DE's upto order 4 (default). DE's can also have free parameters. + + By increasing order, higher order DE's can be found. + + Yields a tuple of (DE, order). + """ + from sympy.solvers.solveset import linsolve + + a = symbols('a:%d' % (order)) + + def _makeDE(k): + eq = f.diff(x, k) + Add(*[a[i]*f.diff(x, i) for i in range(0, k)]) + DE = g(x).diff(x, k) + Add(*[a[i]*g(x).diff(x, i) for i in range(0, k)]) + return eq, DE + + found = False + for k in range(1, order + 1): + eq, DE = _makeDE(k) + eq = eq.expand() + terms = eq.as_ordered_terms() + ind = rational_independent(terms, x) + if found or len(ind) == k: + sol = dict(zip(a, (i for s in linsolve(ind, a[:k]) for i in s))) + if sol: + found = True + DE = DE.subs(sol) + DE = DE.as_numer_denom()[0] + DE = DE.factor().as_coeff_mul(Derivative)[1][0] + yield DE.collect(Derivative(g(x))), k + + +def exp_re(DE, r, k): + """Converts a DE with constant coefficients (explike) into a RE. + + Explanation + =========== + + Performs the substitution: + + .. math:: + f^j(x) \\to r(k + j) + + Normalises the terms so that lowest order of a term is always r(k). + + Examples + ======== + + >>> from sympy import Function, Derivative + >>> from sympy.series.formal import exp_re + >>> from sympy.abc import x, k + >>> f, r = Function('f'), Function('r') + + >>> exp_re(-f(x) + Derivative(f(x)), r, k) + -r(k) + r(k + 1) + >>> exp_re(Derivative(f(x), x) + Derivative(f(x), (x, 2)), r, k) + r(k) + r(k + 1) + + See Also + ======== + + sympy.series.formal.hyper_re + """ + RE = S.Zero + + g = DE.atoms(Function).pop() + + mini = None + for t in Add.make_args(DE): + coeff, d = t.as_independent(g) + if isinstance(d, Derivative): + j = d.derivative_count + else: + j = 0 + if mini is None or j < mini: + mini = j + RE += coeff * r(k + j) + if mini: + RE = RE.subs(k, k - mini) + return RE + + +def hyper_re(DE, r, k): + """ + Converts a DE into a RE. + + Explanation + =========== + + Performs the substitution: + + .. math:: + x^l f^j(x) \\to (k + 1 - l)_j . a_{k + j - l} + + Normalises the terms so that lowest order of a term is always r(k). + + Examples + ======== + + >>> from sympy import Function, Derivative + >>> from sympy.series.formal import hyper_re + >>> from sympy.abc import x, k + >>> f, r = Function('f'), Function('r') + + >>> hyper_re(-f(x) + Derivative(f(x)), r, k) + (k + 1)*r(k + 1) - r(k) + >>> hyper_re(-x*f(x) + Derivative(f(x), (x, 2)), r, k) + (k + 2)*(k + 3)*r(k + 3) - r(k) + + See Also + ======== + + sympy.series.formal.exp_re + """ + RE = S.Zero + + g = DE.atoms(Function).pop() + x = g.atoms(Symbol).pop() + + mini = None + for t in Add.make_args(DE.expand()): + coeff, d = t.as_independent(g) + c, v = coeff.as_independent(x) + l = v.as_coeff_exponent(x)[1] + if isinstance(d, Derivative): + j = d.derivative_count + else: + j = 0 + RE += c * rf(k + 1 - l, j) * r(k + j - l) + if mini is None or j - l < mini: + mini = j - l + + RE = RE.subs(k, k - mini) + + m = Wild('m') + return RE.collect(r(k + m)) + + +def _transformation_a(f, x, P, Q, k, m, shift): + f *= x**(-shift) + P = P.subs(k, k + shift) + Q = Q.subs(k, k + shift) + return f, P, Q, m + + +def _transformation_c(f, x, P, Q, k, m, scale): + f = f.subs(x, x**scale) + P = P.subs(k, k / scale) + Q = Q.subs(k, k / scale) + m *= scale + return f, P, Q, m + + +def _transformation_e(f, x, P, Q, k, m): + f = f.diff(x) + P = P.subs(k, k + 1) * (k + m + 1) + Q = Q.subs(k, k + 1) * (k + 1) + return f, P, Q, m + + +def _apply_shift(sol, shift): + return [(res, cond + shift) for res, cond in sol] + + +def _apply_scale(sol, scale): + return [(res, cond / scale) for res, cond in sol] + + +def _apply_integrate(sol, x, k): + return [(res / ((cond + 1)*(cond.as_coeff_Add()[1].coeff(k))), cond + 1) + for res, cond in sol] + + +def _compute_formula(f, x, P, Q, k, m, k_max): + """Computes the formula for f.""" + from sympy.polys import roots + + sol = [] + for i in range(k_max + 1, k_max + m + 1): + if (i < 0) == True: + continue + r = f.diff(x, i).limit(x, 0) / factorial(i) + if r.is_zero: + continue + + kterm = m*k + i + res = r + + p = P.subs(k, kterm) + q = Q.subs(k, kterm) + c1 = p.subs(k, 1/k).leadterm(k)[0] + c2 = q.subs(k, 1/k).leadterm(k)[0] + res *= (-c1 / c2)**k + + res *= Mul(*[rf(-r, k)**mul for r, mul in roots(p, k).items()]) + res /= Mul(*[rf(-r, k)**mul for r, mul in roots(q, k).items()]) + + sol.append((res, kterm)) + + return sol + + +def _rsolve_hypergeometric(f, x, P, Q, k, m): + """ + Recursive wrapper to rsolve_hypergeometric. + + Explanation + =========== + + Returns a Tuple of (formula, series independent terms, + maximum power of x in independent terms) if successful + otherwise ``None``. + + See :func:`rsolve_hypergeometric` for details. + """ + from sympy.polys import lcm, roots + from sympy.integrals import integrate + + # transformation - c + proots, qroots = roots(P, k), roots(Q, k) + all_roots = dict(proots) + all_roots.update(qroots) + scale = lcm([r.as_numer_denom()[1] for r, t in all_roots.items() + if r.is_rational]) + f, P, Q, m = _transformation_c(f, x, P, Q, k, m, scale) + + # transformation - a + qroots = roots(Q, k) + if qroots: + k_min = Min(*qroots.keys()) + else: + k_min = S.Zero + shift = k_min + m + f, P, Q, m = _transformation_a(f, x, P, Q, k, m, shift) + + l = (x*f).limit(x, 0) + if not isinstance(l, Limit) and l != 0: # Ideally should only be l != 0 + return None + + qroots = roots(Q, k) + if qroots: + k_max = Max(*qroots.keys()) + else: + k_max = S.Zero + + ind, mp = S.Zero, -oo + for i in range(k_max + m + 1): + r = f.diff(x, i).limit(x, 0) / factorial(i) + if r.is_finite is False: + old_f = f + f, P, Q, m = _transformation_a(f, x, P, Q, k, m, i) + f, P, Q, m = _transformation_e(f, x, P, Q, k, m) + sol, ind, mp = _rsolve_hypergeometric(f, x, P, Q, k, m) + sol = _apply_integrate(sol, x, k) + sol = _apply_shift(sol, i) + ind = integrate(ind, x) + ind += (old_f - ind).limit(x, 0) # constant of integration + mp += 1 + return sol, ind, mp + elif r: + ind += r*x**(i + shift) + pow_x = Rational((i + shift), scale) + if pow_x > mp: + mp = pow_x # maximum power of x + ind = ind.subs(x, x**(1/scale)) + + sol = _compute_formula(f, x, P, Q, k, m, k_max) + sol = _apply_shift(sol, shift) + sol = _apply_scale(sol, scale) + + return sol, ind, mp + + +def rsolve_hypergeometric(f, x, P, Q, k, m): + """ + Solves RE of hypergeometric type. + + Explanation + =========== + + Attempts to solve RE of the form + + Q(k)*a(k + m) - P(k)*a(k) + + Transformations that preserve Hypergeometric type: + + a. x**n*f(x): b(k + m) = R(k - n)*b(k) + b. f(A*x): b(k + m) = A**m*R(k)*b(k) + c. f(x**n): b(k + n*m) = R(k/n)*b(k) + d. f(x**(1/m)): b(k + 1) = R(k*m)*b(k) + e. f'(x): b(k + m) = ((k + m + 1)/(k + 1))*R(k + 1)*b(k) + + Some of these transformations have been used to solve the RE. + + Returns + ======= + + formula : Expr + ind : Expr + Independent terms. + order : int + + Examples + ======== + + >>> from sympy import exp, ln, S + >>> from sympy.series.formal import rsolve_hypergeometric as rh + >>> from sympy.abc import x, k + + >>> rh(exp(x), x, -S.One, (k + 1), k, 1) + (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1) + + >>> rh(ln(1 + x), x, k**2, k*(k + 1), k, 1) + (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1), + Eq(Mod(k, 1), 0)), (0, True)), x, 2) + + References + ========== + + .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf + .. [2] Power Series in Computer Algebra - Wolfram Koepf + """ + result = _rsolve_hypergeometric(f, x, P, Q, k, m) + + if result is None: + return None + + sol_list, ind, mp = result + + sol_dict = defaultdict(lambda: S.Zero) + for res, cond in sol_list: + j, mk = cond.as_coeff_Add() + c = mk.coeff(k) + + if j.is_integer is False: + res *= x**frac(j) + j = floor(j) + + res = res.subs(k, (k - j) / c) + cond = Eq(k % c, j % c) + sol_dict[cond] += res # Group together formula for same conditions + + sol = [(res, cond) for cond, res in sol_dict.items()] + sol.append((S.Zero, True)) + sol = Piecewise(*sol) + + if mp is -oo: + s = S.Zero + elif mp.is_integer is False: + s = ceiling(mp) + else: + s = mp + 1 + + # save all the terms of + # form 1/x**k in ind + if s < 0: + ind += sum(sequence(sol * x**k, (k, s, -1))) + s = S.Zero + + return (sol, ind, s) + + +def _solve_hyper_RE(f, x, RE, g, k): + """See docstring of :func:`rsolve_hypergeometric` for details.""" + terms = Add.make_args(RE) + + if len(terms) == 2: + gs = list(RE.atoms(Function)) + P, Q = map(RE.coeff, gs) + m = gs[1].args[0] - gs[0].args[0] + if m < 0: + P, Q = Q, P + m = abs(m) + return rsolve_hypergeometric(f, x, P, Q, k, m) + + +def _solve_explike_DE(f, x, DE, g, k): + """Solves DE with constant coefficients.""" + from sympy.solvers import rsolve + + for t in Add.make_args(DE): + coeff, d = t.as_independent(g) + if coeff.free_symbols: + return + + RE = exp_re(DE, g, k) + + init = {} + for i in range(len(Add.make_args(RE))): + if i: + f = f.diff(x) + init[g(k).subs(k, i)] = f.limit(x, 0) + + sol = rsolve(RE, g(k), init) + + if sol: + return (sol / factorial(k), S.Zero, S.Zero) + + +def _solve_simple(f, x, DE, g, k): + """Converts DE into RE and solves using :func:`rsolve`.""" + from sympy.solvers import rsolve + + RE = hyper_re(DE, g, k) + + init = {} + for i in range(len(Add.make_args(RE))): + if i: + f = f.diff(x) + init[g(k).subs(k, i)] = f.limit(x, 0) / factorial(i) + + sol = rsolve(RE, g(k), init) + + if sol: + return (sol, S.Zero, S.Zero) + + +def _transform_explike_DE(DE, g, x, order, syms): + """Converts DE with free parameters into DE with constant coefficients.""" + from sympy.solvers.solveset import linsolve + + eq = [] + highest_coeff = DE.coeff(Derivative(g(x), x, order)) + for i in range(order): + coeff = DE.coeff(Derivative(g(x), x, i)) + coeff = (coeff / highest_coeff).expand().collect(x) + eq.extend(Add.make_args(coeff)) + temp = [] + for e in eq: + if e.has(x): + break + elif e.has(Symbol): + temp.append(e) + else: + eq = temp + if eq: + sol = dict(zip(syms, (i for s in linsolve(eq, list(syms)) for i in s))) + if sol: + DE = DE.subs(sol) + DE = DE.factor().as_coeff_mul(Derivative)[1][0] + DE = DE.collect(Derivative(g(x))) + return DE + + +def _transform_DE_RE(DE, g, k, order, syms): + """Converts DE with free parameters into RE of hypergeometric type.""" + from sympy.solvers.solveset import linsolve + + RE = hyper_re(DE, g, k) + + eq = [RE.coeff(g(k + i)) for i in range(1, order)] + sol = dict(zip(syms, (i for s in linsolve(eq, list(syms)) for i in s))) + if sol: + m = Wild('m') + RE = RE.subs(sol) + RE = RE.factor().as_numer_denom()[0].collect(g(k + m)) + RE = RE.as_coeff_mul(g)[1][0] + for i in range(order): # smallest order should be g(k) + if RE.coeff(g(k + i)) and i: + RE = RE.subs(k, k - i) + break + return RE + + +def solve_de(f, x, DE, order, g, k): + """ + Solves the DE. + + Explanation + =========== + + Tries to solve DE by either converting into a RE containing two terms or + converting into a DE having constant coefficients. + + Returns + ======= + + formula : Expr + ind : Expr + Independent terms. + order : int + + Examples + ======== + + >>> from sympy import Derivative as D, Function + >>> from sympy import exp, ln + >>> from sympy.series.formal import solve_de + >>> from sympy.abc import x, k + >>> f = Function('f') + + >>> solve_de(exp(x), x, D(f(x), x) - f(x), 1, f, k) + (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1) + + >>> solve_de(ln(1 + x), x, (x + 1)*D(f(x), x, 2) + D(f(x)), 2, f, k) + (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1), + Eq(Mod(k, 1), 0)), (0, True)), x, 2) + """ + sol = None + syms = DE.free_symbols.difference({g, x}) + + if syms: + RE = _transform_DE_RE(DE, g, k, order, syms) + else: + RE = hyper_re(DE, g, k) + if not RE.free_symbols.difference({k}): + sol = _solve_hyper_RE(f, x, RE, g, k) + + if sol: + return sol + + if syms: + DE = _transform_explike_DE(DE, g, x, order, syms) + if not DE.free_symbols.difference({x}): + sol = _solve_explike_DE(f, x, DE, g, k) + + if sol: + return sol + + +def hyper_algorithm(f, x, k, order=4): + """ + Hypergeometric algorithm for computing Formal Power Series. + + Explanation + =========== + + Steps: + * Generates DE + * Convert the DE into RE + * Solves the RE + + Examples + ======== + + >>> from sympy import exp, ln + >>> from sympy.series.formal import hyper_algorithm + + >>> from sympy.abc import x, k + + >>> hyper_algorithm(exp(x), x, k) + (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1) + + >>> hyper_algorithm(ln(1 + x), x, k) + (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1), + Eq(Mod(k, 1), 0)), (0, True)), x, 2) + + See Also + ======== + + sympy.series.formal.simpleDE + sympy.series.formal.solve_de + """ + g = Function('g') + + des = [] # list of DE's + sol = None + for DE, i in simpleDE(f, x, g, order): + if DE is not None: + sol = solve_de(f, x, DE, i, g, k) + if sol: + return sol + if not DE.free_symbols.difference({x}): + des.append(DE) + + # If nothing works + # Try plain rsolve + for DE in des: + sol = _solve_simple(f, x, DE, g, k) + if sol: + return sol + + +def _compute_fps(f, x, x0, dir, hyper, order, rational, full): + """Recursive wrapper to compute fps. + + See :func:`compute_fps` for details. + """ + if x0 in [S.Infinity, S.NegativeInfinity]: + dir = S.One if x0 is S.Infinity else -S.One + temp = f.subs(x, 1/x) + result = _compute_fps(temp, x, 0, dir, hyper, order, rational, full) + if result is None: + return None + return (result[0], result[1].subs(x, 1/x), result[2].subs(x, 1/x)) + elif x0 or dir == -S.One: + if dir == -S.One: + rep = -x + x0 + rep2 = -x + rep2b = x0 + else: + rep = x + x0 + rep2 = x + rep2b = -x0 + temp = f.subs(x, rep) + result = _compute_fps(temp, x, 0, S.One, hyper, order, rational, full) + if result is None: + return None + return (result[0], result[1].subs(x, rep2 + rep2b), + result[2].subs(x, rep2 + rep2b)) + + if f.is_polynomial(x): + k = Dummy('k') + ak = sequence(Coeff(f, x, k), (k, 1, oo)) + xk = sequence(x**k, (k, 0, oo)) + ind = f.coeff(x, 0) + return ak, xk, ind + + # Break instances of Add + # this allows application of different + # algorithms on different terms increasing the + # range of admissible functions. + if isinstance(f, Add): + result = False + ak = sequence(S.Zero, (0, oo)) + ind, xk = S.Zero, None + for t in Add.make_args(f): + res = _compute_fps(t, x, 0, S.One, hyper, order, rational, full) + if res: + if not result: + result = True + xk = res[1] + if res[0].start > ak.start: + seq = ak + s, f = ak.start, res[0].start + else: + seq = res[0] + s, f = res[0].start, ak.start + save = Add(*[z[0]*z[1] for z in zip(seq[0:(f - s)], xk[s:f])]) + ak += res[0] + ind += res[2] + save + else: + ind += t + if result: + return ak, xk, ind + return None + + # The symbolic term - symb, if present, is being separated from the function + # Otherwise symb is being set to S.One + syms = f.free_symbols.difference({x}) + (f, symb) = expand(f).as_independent(*syms) + + result = None + + # from here on it's x0=0 and dir=1 handling + k = Dummy('k') + if rational: + result = rational_algorithm(f, x, k, order, full) + + if result is None and hyper: + result = hyper_algorithm(f, x, k, order) + + if result is None: + return None + + from sympy.simplify.powsimp import powsimp + if symb.is_zero: + symb = S.One + else: + symb = powsimp(symb) + ak = sequence(result[0], (k, result[2], oo)) + xk_formula = powsimp(x**k * symb) + xk = sequence(xk_formula, (k, 0, oo)) + ind = powsimp(result[1] * symb) + + return ak, xk, ind + + +def compute_fps(f, x, x0=0, dir=1, hyper=True, order=4, rational=True, + full=False): + """ + Computes the formula for Formal Power Series of a function. + + Explanation + =========== + + Tries to compute the formula by applying the following techniques + (in order): + + * rational_algorithm + * Hypergeometric algorithm + + Parameters + ========== + + x : Symbol + x0 : number, optional + Point to perform series expansion about. Default is 0. + dir : {1, -1, '+', '-'}, optional + If dir is 1 or '+' the series is calculated from the right and + for -1 or '-' the series is calculated from the left. For smooth + functions this flag will not alter the results. Default is 1. + hyper : {True, False}, optional + Set hyper to False to skip the hypergeometric algorithm. + By default it is set to False. + order : int, optional + Order of the derivative of ``f``, Default is 4. + rational : {True, False}, optional + Set rational to False to skip rational algorithm. By default it is set + to True. + full : {True, False}, optional + Set full to True to increase the range of rational algorithm. + See :func:`rational_algorithm` for details. By default it is set to + False. + + Returns + ======= + + ak : sequence + Sequence of coefficients. + xk : sequence + Sequence of powers of x. + ind : Expr + Independent terms. + mul : Pow + Common terms. + + See Also + ======== + + sympy.series.formal.rational_algorithm + sympy.series.formal.hyper_algorithm + """ + f = sympify(f) + x = sympify(x) + + if not f.has(x): + return None + + x0 = sympify(x0) + + if dir == '+': + dir = S.One + elif dir == '-': + dir = -S.One + elif dir not in [S.One, -S.One]: + raise ValueError("Dir must be '+' or '-'") + else: + dir = sympify(dir) + + return _compute_fps(f, x, x0, dir, hyper, order, rational, full) + + +class Coeff(Function): + """ + Coeff(p, x, n) represents the nth coefficient of the polynomial p in x + """ + @classmethod + def eval(cls, p, x, n): + if p.is_polynomial(x) and n.is_integer: + return p.coeff(x, n) + + +class FormalPowerSeries(SeriesBase): + """ + Represents Formal Power Series of a function. + + Explanation + =========== + + No computation is performed. This class should only to be used to represent + a series. No checks are performed. + + For computing a series use :func:`fps`. + + See Also + ======== + + sympy.series.formal.fps + """ + def __new__(cls, *args): + args = map(sympify, args) + return Expr.__new__(cls, *args) + + def __init__(self, *args): + ak = args[4][0] + k = ak.variables[0] + self.ak_seq = sequence(ak.formula, (k, 1, oo)) + self.fact_seq = sequence(factorial(k), (k, 1, oo)) + self.bell_coeff_seq = self.ak_seq * self.fact_seq + self.sign_seq = sequence((-1, 1), (k, 1, oo)) + + @property + def function(self): + return self.args[0] + + @property + def x(self): + return self.args[1] + + @property + def x0(self): + return self.args[2] + + @property + def dir(self): + return self.args[3] + + @property + def ak(self): + return self.args[4][0] + + @property + def xk(self): + return self.args[4][1] + + @property + def ind(self): + return self.args[4][2] + + @property + def interval(self): + return Interval(0, oo) + + @property + def start(self): + return self.interval.inf + + @property + def stop(self): + return self.interval.sup + + @property + def length(self): + return oo + + @property + def infinite(self): + """Returns an infinite representation of the series""" + from sympy.concrete import Sum + ak, xk = self.ak, self.xk + k = ak.variables[0] + inf_sum = Sum(ak.formula * xk.formula, (k, ak.start, ak.stop)) + + return self.ind + inf_sum + + def _get_pow_x(self, term): + """Returns the power of x in a term.""" + xterm, pow_x = term.as_independent(self.x)[1].as_base_exp() + if not xterm.has(self.x): + return S.Zero + return pow_x + + def polynomial(self, n=6): + """ + Truncated series as polynomial. + + Explanation + =========== + + Returns series expansion of ``f`` upto order ``O(x**n)`` + as a polynomial(without ``O`` term). + """ + terms = [] + sym = self.free_symbols + for i, t in enumerate(self): + xp = self._get_pow_x(t) + if xp.has(*sym): + xp = xp.as_coeff_add(*sym)[0] + if xp >= n: + break + elif xp.is_integer is True and i == n + 1: + break + elif t is not S.Zero: + terms.append(t) + + return Add(*terms) + + def truncate(self, n=6): + """ + Truncated series. + + Explanation + =========== + + Returns truncated series expansion of f upto + order ``O(x**n)``. + + If n is ``None``, returns an infinite iterator. + """ + if n is None: + return iter(self) + + x, x0 = self.x, self.x0 + pt_xk = self.xk.coeff(n) + if x0 is S.NegativeInfinity: + x0 = S.Infinity + + return self.polynomial(n) + Order(pt_xk, (x, x0)) + + def zero_coeff(self): + return self._eval_term(0) + + def _eval_term(self, pt): + try: + pt_xk = self.xk.coeff(pt) + pt_ak = self.ak.coeff(pt).simplify() # Simplify the coefficients + except IndexError: + term = S.Zero + else: + term = (pt_ak * pt_xk) + + if self.ind: + ind = S.Zero + sym = self.free_symbols + for t in Add.make_args(self.ind): + pow_x = self._get_pow_x(t) + if pow_x.has(*sym): + pow_x = pow_x.as_coeff_add(*sym)[0] + if pt == 0 and pow_x < 1: + ind += t + elif pow_x >= pt and pow_x < pt + 1: + ind += t + term += ind + + return term.collect(self.x) + + def _eval_subs(self, old, new): + x = self.x + if old.has(x): + return self + + def _eval_as_leading_term(self, x, logx, cdir): + for t in self: + if t is not S.Zero: + return t + + def _eval_derivative(self, x): + f = self.function.diff(x) + ind = self.ind.diff(x) + + pow_xk = self._get_pow_x(self.xk.formula) + ak = self.ak + k = ak.variables[0] + if ak.formula.has(x): + form = [] + for e, c in ak.formula.args: + temp = S.Zero + for t in Add.make_args(e): + pow_x = self._get_pow_x(t) + temp += t * (pow_xk + pow_x) + form.append((temp, c)) + form = Piecewise(*form) + ak = sequence(form.subs(k, k + 1), (k, ak.start - 1, ak.stop)) + else: + ak = sequence((ak.formula * pow_xk).subs(k, k + 1), + (k, ak.start - 1, ak.stop)) + + return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind)) + + def integrate(self, x=None, **kwargs): + """ + Integrate Formal Power Series. + + Examples + ======== + + >>> from sympy import fps, sin, integrate + >>> from sympy.abc import x + >>> f = fps(sin(x)) + >>> f.integrate(x).truncate() + -1 + x**2/2 - x**4/24 + O(x**6) + >>> integrate(f, (x, 0, 1)) + 1 - cos(1) + """ + from sympy.integrals import integrate + + if x is None: + x = self.x + elif iterable(x): + return integrate(self.function, x) + + f = integrate(self.function, x) + ind = integrate(self.ind, x) + ind += (f - ind).limit(x, 0) # constant of integration + + pow_xk = self._get_pow_x(self.xk.formula) + ak = self.ak + k = ak.variables[0] + if ak.formula.has(x): + form = [] + for e, c in ak.formula.args: + temp = S.Zero + for t in Add.make_args(e): + pow_x = self._get_pow_x(t) + temp += t / (pow_xk + pow_x + 1) + form.append((temp, c)) + form = Piecewise(*form) + ak = sequence(form.subs(k, k - 1), (k, ak.start + 1, ak.stop)) + else: + ak = sequence((ak.formula / (pow_xk + 1)).subs(k, k - 1), + (k, ak.start + 1, ak.stop)) + + return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind)) + + def product(self, other, x=None, n=6): + """ + Multiplies two Formal Power Series, using discrete convolution and + return the truncated terms upto specified order. + + Parameters + ========== + + n : Number, optional + Specifies the order of the term up to which the polynomial should + be truncated. + + Examples + ======== + + >>> from sympy import fps, sin, exp + >>> from sympy.abc import x + >>> f1 = fps(sin(x)) + >>> f2 = fps(exp(x)) + + >>> f1.product(f2, x).truncate(4) + x + x**2 + x**3/3 + O(x**4) + + See Also + ======== + + sympy.discrete.convolutions + sympy.series.formal.FormalPowerSeriesProduct + + """ + + if n is None: + return iter(self) + + other = sympify(other) + + if not isinstance(other, FormalPowerSeries): + raise ValueError("Both series should be an instance of FormalPowerSeries" + " class.") + + if self.dir != other.dir: + raise ValueError("Both series should be calculated from the" + " same direction.") + elif self.x0 != other.x0: + raise ValueError("Both series should be calculated about the" + " same point.") + + elif self.x != other.x: + raise ValueError("Both series should have the same symbol.") + + return FormalPowerSeriesProduct(self, other) + + def coeff_bell(self, n): + r""" + self.coeff_bell(n) returns a sequence of Bell polynomials of the second kind. + Note that ``n`` should be a integer. + + The second kind of Bell polynomials (are sometimes called "partial" Bell + polynomials or incomplete Bell polynomials) are defined as + + .. math:: + B_{n,k}(x_1, x_2,\dotsc x_{n-k+1}) = + \sum_{j_1+j_2+j_2+\dotsb=k \atop j_1+2j_2+3j_2+\dotsb=n} + \frac{n!}{j_1!j_2!\dotsb j_{n-k+1}!} + \left(\frac{x_1}{1!} \right)^{j_1} + \left(\frac{x_2}{2!} \right)^{j_2} \dotsb + \left(\frac{x_{n-k+1}}{(n-k+1)!} \right) ^{j_{n-k+1}}. + + * ``bell(n, k, (x1, x2, ...))`` gives Bell polynomials of the second kind, + `B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})`. + + See Also + ======== + + sympy.functions.combinatorial.numbers.bell + + """ + + inner_coeffs = [bell(n, j, tuple(self.bell_coeff_seq[:n-j+1])) for j in range(1, n+1)] + + k = Dummy('k') + return sequence(tuple(inner_coeffs), (k, 1, oo)) + + def compose(self, other, x=None, n=6): + r""" + Returns the truncated terms of the formal power series of the composed function, + up to specified ``n``. + + Explanation + =========== + + If ``f`` and ``g`` are two formal power series of two different functions, + then the coefficient sequence ``ak`` of the composed formal power series `fp` + will be as follows. + + .. math:: + \sum\limits_{k=0}^{n} b_k B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1}) + + Parameters + ========== + + n : Number, optional + Specifies the order of the term up to which the polynomial should + be truncated. + + Examples + ======== + + >>> from sympy import fps, sin, exp + >>> from sympy.abc import x + >>> f1 = fps(exp(x)) + >>> f2 = fps(sin(x)) + + >>> f1.compose(f2, x).truncate() + 1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6) + + >>> f1.compose(f2, x).truncate(8) + 1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + O(x**8) + + See Also + ======== + + sympy.functions.combinatorial.numbers.bell + sympy.series.formal.FormalPowerSeriesCompose + + References + ========== + + .. [1] Comtet, Louis: Advanced combinatorics; the art of finite and infinite expansions. Reidel, 1974. + + """ + + if n is None: + return iter(self) + + other = sympify(other) + + if not isinstance(other, FormalPowerSeries): + raise ValueError("Both series should be an instance of FormalPowerSeries" + " class.") + + if self.dir != other.dir: + raise ValueError("Both series should be calculated from the" + " same direction.") + elif self.x0 != other.x0: + raise ValueError("Both series should be calculated about the" + " same point.") + + elif self.x != other.x: + raise ValueError("Both series should have the same symbol.") + + if other._eval_term(0).as_coeff_mul(other.x)[0] is not S.Zero: + raise ValueError("The formal power series of the inner function should not have any " + "constant coefficient term.") + + return FormalPowerSeriesCompose(self, other) + + def inverse(self, x=None, n=6): + r""" + Returns the truncated terms of the inverse of the formal power series, + up to specified ``n``. + + Explanation + =========== + + If ``f`` and ``g`` are two formal power series of two different functions, + then the coefficient sequence ``ak`` of the composed formal power series ``fp`` + will be as follows. + + .. math:: + \sum\limits_{k=0}^{n} (-1)^{k} x_0^{-k-1} B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1}) + + Parameters + ========== + + n : Number, optional + Specifies the order of the term up to which the polynomial should + be truncated. + + Examples + ======== + + >>> from sympy import fps, exp, cos + >>> from sympy.abc import x + >>> f1 = fps(exp(x)) + >>> f2 = fps(cos(x)) + + >>> f1.inverse(x).truncate() + 1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + O(x**6) + + >>> f2.inverse(x).truncate(8) + 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + O(x**8) + + See Also + ======== + + sympy.functions.combinatorial.numbers.bell + sympy.series.formal.FormalPowerSeriesInverse + + References + ========== + + .. [1] Comtet, Louis: Advanced combinatorics; the art of finite and infinite expansions. Reidel, 1974. + + """ + + if n is None: + return iter(self) + + if self._eval_term(0).is_zero: + raise ValueError("Constant coefficient should exist for an inverse of a formal" + " power series to exist.") + + return FormalPowerSeriesInverse(self) + + def __add__(self, other): + other = sympify(other) + + if isinstance(other, FormalPowerSeries): + if self.dir != other.dir: + raise ValueError("Both series should be calculated from the" + " same direction.") + elif self.x0 != other.x0: + raise ValueError("Both series should be calculated about the" + " same point.") + + x, y = self.x, other.x + f = self.function + other.function.subs(y, x) + + if self.x not in f.free_symbols: + return f + + ak = self.ak + other.ak + if self.ak.start > other.ak.start: + seq = other.ak + s, e = other.ak.start, self.ak.start + else: + seq = self.ak + s, e = self.ak.start, other.ak.start + save = Add(*[z[0]*z[1] for z in zip(seq[0:(e - s)], self.xk[s:e])]) + ind = self.ind + other.ind + save + + return self.func(f, x, self.x0, self.dir, (ak, self.xk, ind)) + + elif not other.has(self.x): + f = self.function + other + ind = self.ind + other + + return self.func(f, self.x, self.x0, self.dir, + (self.ak, self.xk, ind)) + + return Add(self, other) + + def __radd__(self, other): + return self.__add__(other) + + def __neg__(self): + return self.func(-self.function, self.x, self.x0, self.dir, + (-self.ak, self.xk, -self.ind)) + + def __sub__(self, other): + return self.__add__(-other) + + def __rsub__(self, other): + return (-self).__add__(other) + + def __mul__(self, other): + other = sympify(other) + + if other.has(self.x): + return Mul(self, other) + + f = self.function * other + ak = self.ak.coeff_mul(other) + ind = self.ind * other + + return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind)) + + def __rmul__(self, other): + return self.__mul__(other) + + +class FiniteFormalPowerSeries(FormalPowerSeries): + """Base Class for Product, Compose and Inverse classes""" + + def __init__(self, *args): + pass + + @property + def ffps(self): + return self.args[0] + + @property + def gfps(self): + return self.args[1] + + @property + def f(self): + return self.ffps.function + + @property + def g(self): + return self.gfps.function + + @property + def infinite(self): + raise NotImplementedError("No infinite version for an object of" + " FiniteFormalPowerSeries class.") + + def _eval_terms(self, n): + raise NotImplementedError("(%s)._eval_terms()" % self) + + def _eval_term(self, pt): + raise NotImplementedError("By the current logic, one can get terms" + "upto a certain order, instead of getting term by term.") + + def polynomial(self, n): + return self._eval_terms(n) + + def truncate(self, n=6): + ffps = self.ffps + pt_xk = ffps.xk.coeff(n) + x, x0 = ffps.x, ffps.x0 + + return self.polynomial(n) + Order(pt_xk, (x, x0)) + + def _eval_derivative(self, x): + raise NotImplementedError + + def integrate(self, x): + raise NotImplementedError + + +class FormalPowerSeriesProduct(FiniteFormalPowerSeries): + """Represents the product of two formal power series of two functions. + + Explanation + =========== + + No computation is performed. Terms are calculated using a term by term logic, + instead of a point by point logic. + + There are two differences between a :obj:`FormalPowerSeries` object and a + :obj:`FormalPowerSeriesProduct` object. The first argument contains the two + functions involved in the product. Also, the coefficient sequence contains + both the coefficient sequence of the formal power series of the involved functions. + + See Also + ======== + + sympy.series.formal.FormalPowerSeries + sympy.series.formal.FiniteFormalPowerSeries + + """ + + def __init__(self, *args): + ffps, gfps = self.ffps, self.gfps + + k = ffps.ak.variables[0] + self.coeff1 = sequence(ffps.ak.formula, (k, 0, oo)) + + k = gfps.ak.variables[0] + self.coeff2 = sequence(gfps.ak.formula, (k, 0, oo)) + + @property + def function(self): + """Function of the product of two formal power series.""" + return self.f * self.g + + def _eval_terms(self, n): + """ + Returns the first ``n`` terms of the product formal power series. + Term by term logic is implemented here. + + Examples + ======== + + >>> from sympy import fps, sin, exp + >>> from sympy.abc import x + >>> f1 = fps(sin(x)) + >>> f2 = fps(exp(x)) + >>> fprod = f1.product(f2, x) + + >>> fprod._eval_terms(4) + x**3/3 + x**2 + x + + See Also + ======== + + sympy.series.formal.FormalPowerSeries.product + + """ + coeff1, coeff2 = self.coeff1, self.coeff2 + + aks = convolution(coeff1[:n], coeff2[:n]) + + terms = [] + for i in range(0, n): + terms.append(aks[i] * self.ffps.xk.coeff(i)) + + return Add(*terms) + + +class FormalPowerSeriesCompose(FiniteFormalPowerSeries): + """ + Represents the composed formal power series of two functions. + + Explanation + =========== + + No computation is performed. Terms are calculated using a term by term logic, + instead of a point by point logic. + + There are two differences between a :obj:`FormalPowerSeries` object and a + :obj:`FormalPowerSeriesCompose` object. The first argument contains the outer + function and the inner function involved in the omposition. Also, the + coefficient sequence contains the generic sequence which is to be multiplied + by a custom ``bell_seq`` finite sequence. The finite terms will then be added up to + get the final terms. + + See Also + ======== + + sympy.series.formal.FormalPowerSeries + sympy.series.formal.FiniteFormalPowerSeries + + """ + + @property + def function(self): + """Function for the composed formal power series.""" + f, g, x = self.f, self.g, self.ffps.x + return f.subs(x, g) + + def _eval_terms(self, n): + """ + Returns the first `n` terms of the composed formal power series. + Term by term logic is implemented here. + + Explanation + =========== + + The coefficient sequence of the :obj:`FormalPowerSeriesCompose` object is the generic sequence. + It is multiplied by ``bell_seq`` to get a sequence, whose terms are added up to get + the final terms for the polynomial. + + Examples + ======== + + >>> from sympy import fps, sin, exp + >>> from sympy.abc import x + >>> f1 = fps(exp(x)) + >>> f2 = fps(sin(x)) + >>> fcomp = f1.compose(f2, x) + + >>> fcomp._eval_terms(6) + -x**5/15 - x**4/8 + x**2/2 + x + 1 + + >>> fcomp._eval_terms(8) + x**7/90 - x**6/240 - x**5/15 - x**4/8 + x**2/2 + x + 1 + + See Also + ======== + + sympy.series.formal.FormalPowerSeries.compose + sympy.series.formal.FormalPowerSeries.coeff_bell + + """ + + ffps, gfps = self.ffps, self.gfps + terms = [ffps.zero_coeff()] + + for i in range(1, n): + bell_seq = gfps.coeff_bell(i) + seq = (ffps.bell_coeff_seq * bell_seq) + terms.append(Add(*(seq[:i])) / ffps.fact_seq[i-1] * ffps.xk.coeff(i)) + + return Add(*terms) + + +class FormalPowerSeriesInverse(FiniteFormalPowerSeries): + """ + Represents the Inverse of a formal power series. + + Explanation + =========== + + No computation is performed. Terms are calculated using a term by term logic, + instead of a point by point logic. + + There is a single difference between a :obj:`FormalPowerSeries` object and a + :obj:`FormalPowerSeriesInverse` object. The coefficient sequence contains the + generic sequence which is to be multiplied by a custom ``bell_seq`` finite sequence. + The finite terms will then be added up to get the final terms. + + See Also + ======== + + sympy.series.formal.FormalPowerSeries + sympy.series.formal.FiniteFormalPowerSeries + + """ + def __init__(self, *args): + ffps = self.ffps + k = ffps.xk.variables[0] + + inv = ffps.zero_coeff() + inv_seq = sequence(inv ** (-(k + 1)), (k, 1, oo)) + self.aux_seq = ffps.sign_seq * ffps.fact_seq * inv_seq + + @property + def function(self): + """Function for the inverse of a formal power series.""" + f = self.f + return 1 / f + + @property + def g(self): + raise ValueError("Only one function is considered while performing" + "inverse of a formal power series.") + + @property + def gfps(self): + raise ValueError("Only one function is considered while performing" + "inverse of a formal power series.") + + def _eval_terms(self, n): + """ + Returns the first ``n`` terms of the composed formal power series. + Term by term logic is implemented here. + + Explanation + =========== + + The coefficient sequence of the `FormalPowerSeriesInverse` object is the generic sequence. + It is multiplied by ``bell_seq`` to get a sequence, whose terms are added up to get + the final terms for the polynomial. + + Examples + ======== + + >>> from sympy import fps, exp, cos + >>> from sympy.abc import x + >>> f1 = fps(exp(x)) + >>> f2 = fps(cos(x)) + >>> finv1, finv2 = f1.inverse(), f2.inverse() + + >>> finv1._eval_terms(6) + -x**5/120 + x**4/24 - x**3/6 + x**2/2 - x + 1 + + >>> finv2._eval_terms(8) + 61*x**6/720 + 5*x**4/24 + x**2/2 + 1 + + See Also + ======== + + sympy.series.formal.FormalPowerSeries.inverse + sympy.series.formal.FormalPowerSeries.coeff_bell + + """ + ffps = self.ffps + terms = [ffps.zero_coeff()] + + for i in range(1, n): + bell_seq = ffps.coeff_bell(i) + seq = (self.aux_seq * bell_seq) + terms.append(Add(*(seq[:i])) / ffps.fact_seq[i-1] * ffps.xk.coeff(i)) + + return Add(*terms) + + +def fps(f, x=None, x0=0, dir=1, hyper=True, order=4, rational=True, full=False): + """ + Generates Formal Power Series of ``f``. + + Explanation + =========== + + Returns the formal series expansion of ``f`` around ``x = x0`` + with respect to ``x`` in the form of a ``FormalPowerSeries`` object. + + Formal Power Series is represented using an explicit formula + computed using different algorithms. + + See :func:`compute_fps` for the more details regarding the computation + of formula. + + Parameters + ========== + + x : Symbol, optional + If x is None and ``f`` is univariate, the univariate symbols will be + supplied, otherwise an error will be raised. + x0 : number, optional + Point to perform series expansion about. Default is 0. + dir : {1, -1, '+', '-'}, optional + If dir is 1 or '+' the series is calculated from the right and + for -1 or '-' the series is calculated from the left. For smooth + functions this flag will not alter the results. Default is 1. + hyper : {True, False}, optional + Set hyper to False to skip the hypergeometric algorithm. + By default it is set to False. + order : int, optional + Order of the derivative of ``f``, Default is 4. + rational : {True, False}, optional + Set rational to False to skip rational algorithm. By default it is set + to True. + full : {True, False}, optional + Set full to True to increase the range of rational algorithm. + See :func:`rational_algorithm` for details. By default it is set to + False. + + Examples + ======== + + >>> from sympy import fps, ln, atan, sin + >>> from sympy.abc import x, n + + Rational Functions + + >>> fps(ln(1 + x)).truncate() + x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6) + + >>> fps(atan(x), full=True).truncate() + x - x**3/3 + x**5/5 + O(x**6) + + Symbolic Functions + + >>> fps(x**n*sin(x**2), x).truncate(8) + -x**(n + 6)/6 + x**(n + 2) + O(x**(n + 8)) + + See Also + ======== + + sympy.series.formal.FormalPowerSeries + sympy.series.formal.compute_fps + """ + f = sympify(f) + + if x is None: + free = f.free_symbols + if len(free) == 1: + x = free.pop() + elif not free: + return f + else: + raise NotImplementedError("multivariate formal power series") + + result = compute_fps(f, x, x0, dir, hyper, order, rational, full) + + if result is None: + return f + + return FormalPowerSeries(f, x, x0, dir, result) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/fourier.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/fourier.py new file mode 100644 index 0000000000000000000000000000000000000000..c4ad43a75d0e1d24bfc591383f68965fd8b504c7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/fourier.py @@ -0,0 +1,811 @@ +"""Fourier Series""" + +from sympy.core.numbers import (oo, pi) +from sympy.core.symbol import Wild +from sympy.core.expr import Expr +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.singleton import S +from sympy.core.symbol import Dummy, Symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import sin, cos, sinc +from sympy.series.series_class import SeriesBase +from sympy.series.sequences import SeqFormula +from sympy.sets.sets import Interval +from sympy.utilities.iterables import is_sequence + + +__doctest_requires__ = {('fourier_series',): ['matplotlib']} + + +def fourier_cos_seq(func, limits, n): + """Returns the cos sequence in a Fourier series""" + from sympy.integrals import integrate + x, L = limits[0], limits[2] - limits[1] + cos_term = cos(2*n*pi*x / L) + formula = 2 * cos_term * integrate(func * cos_term, limits) / L + a0 = formula.subs(n, S.Zero) / 2 + return a0, SeqFormula(2 * cos_term * integrate(func * cos_term, limits) + / L, (n, 1, oo)) + + +def fourier_sin_seq(func, limits, n): + """Returns the sin sequence in a Fourier series""" + from sympy.integrals import integrate + x, L = limits[0], limits[2] - limits[1] + sin_term = sin(2*n*pi*x / L) + return SeqFormula(2 * sin_term * integrate(func * sin_term, limits) + / L, (n, 1, oo)) + + +def _process_limits(func, limits): + """ + Limits should be of the form (x, start, stop). + x should be a symbol. Both start and stop should be bounded. + + Explanation + =========== + + * If x is not given, x is determined from func. + * If limits is None. Limit of the form (x, -pi, pi) is returned. + + Examples + ======== + + >>> from sympy.series.fourier import _process_limits as pari + >>> from sympy.abc import x + >>> pari(x**2, (x, -2, 2)) + (x, -2, 2) + >>> pari(x**2, (-2, 2)) + (x, -2, 2) + >>> pari(x**2, None) + (x, -pi, pi) + """ + def _find_x(func): + free = func.free_symbols + if len(free) == 1: + return free.pop() + elif not free: + return Dummy('k') + else: + raise ValueError( + " specify dummy variables for %s. If the function contains" + " more than one free symbol, a dummy variable should be" + " supplied explicitly e.g. FourierSeries(m*n**2, (n, -pi, pi))" + % func) + + x, start, stop = None, None, None + if limits is None: + x, start, stop = _find_x(func), -pi, pi + if is_sequence(limits, Tuple): + if len(limits) == 3: + x, start, stop = limits + elif len(limits) == 2: + x = _find_x(func) + start, stop = limits + + if not isinstance(x, Symbol) or start is None or stop is None: + raise ValueError('Invalid limits given: %s' % str(limits)) + + unbounded = [S.NegativeInfinity, S.Infinity] + if start in unbounded or stop in unbounded: + raise ValueError("Both the start and end value should be bounded") + + return sympify((x, start, stop)) + + +def finite_check(f, x, L): + + def check_fx(exprs, x): + return x not in exprs.free_symbols + + def check_sincos(_expr, x, L): + if isinstance(_expr, (sin, cos)): + sincos_args = _expr.args[0] + + if sincos_args.match(a*(pi/L)*x + b) is not None: + return True + else: + return False + + from sympy.simplify.fu import TR2, TR1, sincos_to_sum + _expr = sincos_to_sum(TR2(TR1(f))) + add_coeff = _expr.as_coeff_add() + + a = Wild('a', properties=[lambda k: k.is_Integer, lambda k: k != S.Zero, ]) + b = Wild('b', properties=[lambda k: x not in k.free_symbols, ]) + + for s in add_coeff[1]: + mul_coeffs = s.as_coeff_mul()[1] + for t in mul_coeffs: + if not (check_fx(t, x) or check_sincos(t, x, L)): + return False, f + + return True, _expr + + +class FourierSeries(SeriesBase): + r"""Represents Fourier sine/cosine series. + + Explanation + =========== + + This class only represents a fourier series. + No computation is performed. + + For how to compute Fourier series, see the :func:`fourier_series` + docstring. + + See Also + ======== + + sympy.series.fourier.fourier_series + """ + def __new__(cls, *args): + args = map(sympify, args) + return Expr.__new__(cls, *args) + + @property + def function(self): + return self.args[0] + + @property + def x(self): + return self.args[1][0] + + @property + def period(self): + return (self.args[1][1], self.args[1][2]) + + @property + def a0(self): + return self.args[2][0] + + @property + def an(self): + return self.args[2][1] + + @property + def bn(self): + return self.args[2][2] + + @property + def interval(self): + return Interval(0, oo) + + @property + def start(self): + return self.interval.inf + + @property + def stop(self): + return self.interval.sup + + @property + def length(self): + return oo + + @property + def L(self): + return abs(self.period[1] - self.period[0]) / 2 + + def _eval_subs(self, old, new): + x = self.x + if old.has(x): + return self + + def truncate(self, n=3): + """ + Return the first n nonzero terms of the series. + + If ``n`` is None return an iterator. + + Parameters + ========== + + n : int or None + Amount of non-zero terms in approximation or None. + + Returns + ======= + + Expr or iterator : + Approximation of function expanded into Fourier series. + + Examples + ======== + + >>> from sympy import fourier_series, pi + >>> from sympy.abc import x + >>> s = fourier_series(x, (x, -pi, pi)) + >>> s.truncate(4) + 2*sin(x) - sin(2*x) + 2*sin(3*x)/3 - sin(4*x)/2 + + See Also + ======== + + sympy.series.fourier.FourierSeries.sigma_approximation + """ + if n is None: + return iter(self) + + terms = [] + for t in self: + if len(terms) == n: + break + if t is not S.Zero: + terms.append(t) + + return Add(*terms) + + def sigma_approximation(self, n=3): + r""" + Return :math:`\sigma`-approximation of Fourier series with respect + to order n. + + Explanation + =========== + + Sigma approximation adjusts a Fourier summation to eliminate the Gibbs + phenomenon which would otherwise occur at discontinuities. + A sigma-approximated summation for a Fourier series of a T-periodical + function can be written as + + .. math:: + s(\theta) = \frac{1}{2} a_0 + \sum _{k=1}^{m-1} + \operatorname{sinc} \Bigl( \frac{k}{m} \Bigr) \cdot + \left[ a_k \cos \Bigl( \frac{2\pi k}{T} \theta \Bigr) + + b_k \sin \Bigl( \frac{2\pi k}{T} \theta \Bigr) \right], + + where :math:`a_0, a_k, b_k, k=1,\ldots,{m-1}` are standard Fourier + series coefficients and + :math:`\operatorname{sinc} \Bigl( \frac{k}{m} \Bigr)` is a Lanczos + :math:`\sigma` factor (expressed in terms of normalized + :math:`\operatorname{sinc}` function). + + Parameters + ========== + + n : int + Highest order of the terms taken into account in approximation. + + Returns + ======= + + Expr : + Sigma approximation of function expanded into Fourier series. + + Examples + ======== + + >>> from sympy import fourier_series, pi + >>> from sympy.abc import x + >>> s = fourier_series(x, (x, -pi, pi)) + >>> s.sigma_approximation(4) + 2*sin(x)*sinc(pi/4) - 2*sin(2*x)/pi + 2*sin(3*x)*sinc(3*pi/4)/3 + + See Also + ======== + + sympy.series.fourier.FourierSeries.truncate + + Notes + ===== + + The behaviour of + :meth:`~sympy.series.fourier.FourierSeries.sigma_approximation` + is different from :meth:`~sympy.series.fourier.FourierSeries.truncate` + - it takes all nonzero terms of degree smaller than n, rather than + first n nonzero ones. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gibbs_phenomenon + .. [2] https://en.wikipedia.org/wiki/Sigma_approximation + """ + terms = [sinc(pi * i / n) * t for i, t in enumerate(self[:n]) + if t is not S.Zero] + return Add(*terms) + + def shift(self, s): + """ + Shift the function by a term independent of x. + + Explanation + =========== + + f(x) -> f(x) + s + + This is fast, if Fourier series of f(x) is already + computed. + + Examples + ======== + + >>> from sympy import fourier_series, pi + >>> from sympy.abc import x + >>> s = fourier_series(x**2, (x, -pi, pi)) + >>> s.shift(1).truncate() + -4*cos(x) + cos(2*x) + 1 + pi**2/3 + """ + s, x = sympify(s), self.x + + if x in s.free_symbols: + raise ValueError("'%s' should be independent of %s" % (s, x)) + + a0 = self.a0 + s + sfunc = self.function + s + + return self.func(sfunc, self.args[1], (a0, self.an, self.bn)) + + def shiftx(self, s): + """ + Shift x by a term independent of x. + + Explanation + =========== + + f(x) -> f(x + s) + + This is fast, if Fourier series of f(x) is already + computed. + + Examples + ======== + + >>> from sympy import fourier_series, pi + >>> from sympy.abc import x + >>> s = fourier_series(x**2, (x, -pi, pi)) + >>> s.shiftx(1).truncate() + -4*cos(x + 1) + cos(2*x + 2) + pi**2/3 + """ + s, x = sympify(s), self.x + + if x in s.free_symbols: + raise ValueError("'%s' should be independent of %s" % (s, x)) + + an = self.an.subs(x, x + s) + bn = self.bn.subs(x, x + s) + sfunc = self.function.subs(x, x + s) + + return self.func(sfunc, self.args[1], (self.a0, an, bn)) + + def scale(self, s): + """ + Scale the function by a term independent of x. + + Explanation + =========== + + f(x) -> s * f(x) + + This is fast, if Fourier series of f(x) is already + computed. + + Examples + ======== + + >>> from sympy import fourier_series, pi + >>> from sympy.abc import x + >>> s = fourier_series(x**2, (x, -pi, pi)) + >>> s.scale(2).truncate() + -8*cos(x) + 2*cos(2*x) + 2*pi**2/3 + """ + s, x = sympify(s), self.x + + if x in s.free_symbols: + raise ValueError("'%s' should be independent of %s" % (s, x)) + + an = self.an.coeff_mul(s) + bn = self.bn.coeff_mul(s) + a0 = self.a0 * s + sfunc = self.args[0] * s + + return self.func(sfunc, self.args[1], (a0, an, bn)) + + def scalex(self, s): + """ + Scale x by a term independent of x. + + Explanation + =========== + + f(x) -> f(s*x) + + This is fast, if Fourier series of f(x) is already + computed. + + Examples + ======== + + >>> from sympy import fourier_series, pi + >>> from sympy.abc import x + >>> s = fourier_series(x**2, (x, -pi, pi)) + >>> s.scalex(2).truncate() + -4*cos(2*x) + cos(4*x) + pi**2/3 + """ + s, x = sympify(s), self.x + + if x in s.free_symbols: + raise ValueError("'%s' should be independent of %s" % (s, x)) + + an = self.an.subs(x, x * s) + bn = self.bn.subs(x, x * s) + sfunc = self.function.subs(x, x * s) + + return self.func(sfunc, self.args[1], (self.a0, an, bn)) + + def _eval_as_leading_term(self, x, logx, cdir): + for t in self: + if t is not S.Zero: + return t + + def _eval_term(self, pt): + if pt == 0: + return self.a0 + return self.an.coeff(pt) + self.bn.coeff(pt) + + def __neg__(self): + return self.scale(-1) + + def __add__(self, other): + if isinstance(other, FourierSeries): + if self.period != other.period: + raise ValueError("Both the series should have same periods") + + x, y = self.x, other.x + function = self.function + other.function.subs(y, x) + + if self.x not in function.free_symbols: + return function + + an = self.an + other.an + bn = self.bn + other.bn + a0 = self.a0 + other.a0 + + return self.func(function, self.args[1], (a0, an, bn)) + + return Add(self, other) + + def __sub__(self, other): + return self.__add__(-other) + + +class FiniteFourierSeries(FourierSeries): + r"""Represents Finite Fourier sine/cosine series. + + For how to compute Fourier series, see the :func:`fourier_series` + docstring. + + Parameters + ========== + + f : Expr + Expression for finding fourier_series + + limits : ( x, start, stop) + x is the independent variable for the expression f + (start, stop) is the period of the fourier series + + exprs: (a0, an, bn) or Expr + a0 is the constant term a0 of the fourier series + an is a dictionary of coefficients of cos terms + an[k] = coefficient of cos(pi*(k/L)*x) + bn is a dictionary of coefficients of sin terms + bn[k] = coefficient of sin(pi*(k/L)*x) + + or exprs can be an expression to be converted to fourier form + + Methods + ======= + + This class is an extension of FourierSeries class. + Please refer to sympy.series.fourier.FourierSeries for + further information. + + See Also + ======== + + sympy.series.fourier.FourierSeries + sympy.series.fourier.fourier_series + """ + + def __new__(cls, f, limits, exprs): + f = sympify(f) + limits = sympify(limits) + exprs = sympify(exprs) + + if not (isinstance(exprs, Tuple) and len(exprs) == 3): # exprs is not of form (a0, an, bn) + # Converts the expression to fourier form + c, e = exprs.as_coeff_add() + from sympy.simplify.fu import TR10 + rexpr = c + Add(*[TR10(i) for i in e]) + a0, exp_ls = rexpr.expand(trig=False, power_base=False, power_exp=False, log=False).as_coeff_add() + + x = limits[0] + L = abs(limits[2] - limits[1]) / 2 + + a = Wild('a', properties=[lambda k: k.is_Integer, lambda k: k is not S.Zero, ]) + b = Wild('b', properties=[lambda k: x not in k.free_symbols, ]) + + an = {} + bn = {} + + # separates the coefficients of sin and cos terms in dictionaries an, and bn + for p in exp_ls: + t = p.match(b * cos(a * (pi / L) * x)) + q = p.match(b * sin(a * (pi / L) * x)) + if t: + an[t[a]] = t[b] + an.get(t[a], S.Zero) + elif q: + bn[q[a]] = q[b] + bn.get(q[a], S.Zero) + else: + a0 += p + + exprs = Tuple(a0, an, bn) + + return Expr.__new__(cls, f, limits, exprs) + + @property + def interval(self): + _length = 1 if self.a0 else 0 + _length += max(set(self.an.keys()).union(set(self.bn.keys()))) + 1 + return Interval(0, _length) + + @property + def length(self): + return self.stop - self.start + + def shiftx(self, s): + s, x = sympify(s), self.x + + if x in s.free_symbols: + raise ValueError("'%s' should be independent of %s" % (s, x)) + + _expr = self.truncate().subs(x, x + s) + sfunc = self.function.subs(x, x + s) + + return self.func(sfunc, self.args[1], _expr) + + def scale(self, s): + s, x = sympify(s), self.x + + if x in s.free_symbols: + raise ValueError("'%s' should be independent of %s" % (s, x)) + + _expr = self.truncate() * s + sfunc = self.function * s + + return self.func(sfunc, self.args[1], _expr) + + def scalex(self, s): + s, x = sympify(s), self.x + + if x in s.free_symbols: + raise ValueError("'%s' should be independent of %s" % (s, x)) + + _expr = self.truncate().subs(x, x * s) + sfunc = self.function.subs(x, x * s) + + return self.func(sfunc, self.args[1], _expr) + + def _eval_term(self, pt): + if pt == 0: + return self.a0 + + _term = self.an.get(pt, S.Zero) * cos(pt * (pi / self.L) * self.x) \ + + self.bn.get(pt, S.Zero) * sin(pt * (pi / self.L) * self.x) + return _term + + def __add__(self, other): + if isinstance(other, FourierSeries): + return other.__add__(fourier_series(self.function, self.args[1],\ + finite=False)) + elif isinstance(other, FiniteFourierSeries): + if self.period != other.period: + raise ValueError("Both the series should have same periods") + + x, y = self.x, other.x + function = self.function + other.function.subs(y, x) + + if self.x not in function.free_symbols: + return function + + return fourier_series(function, limits=self.args[1]) + + +def fourier_series(f, limits=None, finite=True): + r"""Computes the Fourier trigonometric series expansion. + + Explanation + =========== + + Fourier trigonometric series of $f(x)$ over the interval $(a, b)$ + is defined as: + + .. math:: + \frac{a_0}{2} + \sum_{n=1}^{\infty} + (a_n \cos(\frac{2n \pi x}{L}) + b_n \sin(\frac{2n \pi x}{L})) + + where the coefficients are: + + .. math:: + L = b - a + + .. math:: + a_0 = \frac{2}{L} \int_{a}^{b}{f(x) dx} + + .. math:: + a_n = \frac{2}{L} \int_{a}^{b}{f(x) \cos(\frac{2n \pi x}{L}) dx} + + .. math:: + b_n = \frac{2}{L} \int_{a}^{b}{f(x) \sin(\frac{2n \pi x}{L}) dx} + + The condition whether the function $f(x)$ given should be periodic + or not is more than necessary, because it is sufficient to consider + the series to be converging to $f(x)$ only in the given interval, + not throughout the whole real line. + + This also brings a lot of ease for the computation because + you do not have to make $f(x)$ artificially periodic by + wrapping it with piecewise, modulo operations, + but you can shape the function to look like the desired periodic + function only in the interval $(a, b)$, and the computed series will + automatically become the series of the periodic version of $f(x)$. + + This property is illustrated in the examples section below. + + Parameters + ========== + + limits : (sym, start, end), optional + *sym* denotes the symbol the series is computed with respect to. + + *start* and *end* denotes the start and the end of the interval + where the fourier series converges to the given function. + + Default range is specified as $-\pi$ and $\pi$. + + Returns + ======= + + FourierSeries + A symbolic object representing the Fourier trigonometric series. + + Examples + ======== + + Computing the Fourier series of $f(x) = x^2$: + + >>> from sympy import fourier_series, pi + >>> from sympy.abc import x + >>> f = x**2 + >>> s = fourier_series(f, (x, -pi, pi)) + >>> s1 = s.truncate(n=3) + >>> s1 + -4*cos(x) + cos(2*x) + pi**2/3 + + Shifting of the Fourier series: + + >>> s.shift(1).truncate() + -4*cos(x) + cos(2*x) + 1 + pi**2/3 + >>> s.shiftx(1).truncate() + -4*cos(x + 1) + cos(2*x + 2) + pi**2/3 + + Scaling of the Fourier series: + + >>> s.scale(2).truncate() + -8*cos(x) + 2*cos(2*x) + 2*pi**2/3 + >>> s.scalex(2).truncate() + -4*cos(2*x) + cos(4*x) + pi**2/3 + + Computing the Fourier series of $f(x) = x$: + + This illustrates how truncating to the higher order gives better + convergence. + + .. plot:: + :context: reset + :format: doctest + :include-source: True + + >>> from sympy import fourier_series, pi, plot + >>> from sympy.abc import x + >>> f = x + >>> s = fourier_series(f, (x, -pi, pi)) + >>> s1 = s.truncate(n = 3) + >>> s2 = s.truncate(n = 5) + >>> s3 = s.truncate(n = 7) + >>> p = plot(f, s1, s2, s3, (x, -pi, pi), show=False, legend=True) + + >>> p[0].line_color = (0, 0, 0) + >>> p[0].label = 'x' + >>> p[1].line_color = (0.7, 0.7, 0.7) + >>> p[1].label = 'n=3' + >>> p[2].line_color = (0.5, 0.5, 0.5) + >>> p[2].label = 'n=5' + >>> p[3].line_color = (0.3, 0.3, 0.3) + >>> p[3].label = 'n=7' + + >>> p.show() + + This illustrates how the series converges to different sawtooth + waves if the different ranges are specified. + + .. plot:: + :context: close-figs + :format: doctest + :include-source: True + + >>> s1 = fourier_series(x, (x, -1, 1)).truncate(10) + >>> s2 = fourier_series(x, (x, -pi, pi)).truncate(10) + >>> s3 = fourier_series(x, (x, 0, 1)).truncate(10) + >>> p = plot(x, s1, s2, s3, (x, -5, 5), show=False, legend=True) + + >>> p[0].line_color = (0, 0, 0) + >>> p[0].label = 'x' + >>> p[1].line_color = (0.7, 0.7, 0.7) + >>> p[1].label = '[-1, 1]' + >>> p[2].line_color = (0.5, 0.5, 0.5) + >>> p[2].label = '[-pi, pi]' + >>> p[3].line_color = (0.3, 0.3, 0.3) + >>> p[3].label = '[0, 1]' + + >>> p.show() + + Notes + ===== + + Computing Fourier series can be slow + due to the integration required in computing + an, bn. + + It is faster to compute Fourier series of a function + by using shifting and scaling on an already + computed Fourier series rather than computing + again. + + e.g. If the Fourier series of ``x**2`` is known + the Fourier series of ``x**2 - 1`` can be found by shifting by ``-1``. + + See Also + ======== + + sympy.series.fourier.FourierSeries + + References + ========== + + .. [1] https://mathworld.wolfram.com/FourierSeries.html + """ + f = sympify(f) + + limits = _process_limits(f, limits) + x = limits[0] + + if x not in f.free_symbols: + return f + + if finite: + L = abs(limits[2] - limits[1]) / 2 + is_finite, res_f = finite_check(f, x, L) + if is_finite: + return FiniteFourierSeries(f, limits, res_f) + + n = Dummy('n') + center = (limits[1] + limits[2]) / 2 + if center.is_zero: + neg_f = f.subs(x, -x) + if f == neg_f: + a0, an = fourier_cos_seq(f, limits, n) + bn = SeqFormula(0, (1, oo)) + return FourierSeries(f, limits, (a0, an, bn)) + elif f == -neg_f: + a0 = S.Zero + an = SeqFormula(0, (1, oo)) + bn = fourier_sin_seq(f, limits, n) + return FourierSeries(f, limits, (a0, an, bn)) + a0, an = fourier_cos_seq(f, limits, n) + bn = fourier_sin_seq(f, limits, n) + return FourierSeries(f, limits, (a0, an, bn)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/gruntz.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/gruntz.py new file mode 100644 index 0000000000000000000000000000000000000000..20ba3150e9918384141e755a39f5bacb0e76db55 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/gruntz.py @@ -0,0 +1,701 @@ +""" +Limits +====== + +Implemented according to the PhD thesis +https://www.cybertester.com/data/gruntz.pdf, which contains very thorough +descriptions of the algorithm including many examples. We summarize here +the gist of it. + +All functions are sorted according to how rapidly varying they are at +infinity using the following rules. Any two functions f and g can be +compared using the properties of L: + +L=lim log|f(x)| / log|g(x)| (for x -> oo) + +We define >, < ~ according to:: + + 1. f > g .... L=+-oo + + we say that: + - f is greater than any power of g + - f is more rapidly varying than g + - f goes to infinity/zero faster than g + + 2. f < g .... L=0 + + we say that: + - f is lower than any power of g + + 3. f ~ g .... L!=0, +-oo + + we say that: + - both f and g are bounded from above and below by suitable integral + powers of the other + +Examples +======== +:: + 2 < x < exp(x) < exp(x**2) < exp(exp(x)) + 2 ~ 3 ~ -5 + x ~ x**2 ~ x**3 ~ 1/x ~ x**m ~ -x + exp(x) ~ exp(-x) ~ exp(2x) ~ exp(x)**2 ~ exp(x+exp(-x)) + f ~ 1/f + +So we can divide all the functions into comparability classes (x and x^2 +belong to one class, exp(x) and exp(-x) belong to some other class). In +principle, we could compare any two functions, but in our algorithm, we +do not compare anything below the class 2~3~-5 (for example log(x) is +below this), so we set 2~3~-5 as the lowest comparability class. + +Given the function f, we find the list of most rapidly varying (mrv set) +subexpressions of it. This list belongs to the same comparability class. +Let's say it is {exp(x), exp(2x)}. Using the rule f ~ 1/f we find an +element "w" (either from the list or a new one) from the same +comparability class which goes to zero at infinity. In our example we +set w=exp(-x) (but we could also set w=exp(-2x) or w=exp(-3x) ...). We +rewrite the mrv set using w, in our case {1/w, 1/w^2}, and substitute it +into f. Then we expand f into a series in w:: + + f = c0*w^e0 + c1*w^e1 + ... + O(w^en), where e0oo, lim f = lim c0*w^e0, because all the other terms go to zero, +because w goes to zero faster than the ci and ei. So:: + + for e0>0, lim f = 0 + for e0<0, lim f = +-oo (the sign depends on the sign of c0) + for e0=0, lim f = lim c0 + +We need to recursively compute limits at several places of the algorithm, but +as is shown in the PhD thesis, it always finishes. + +Important functions from the implementation: + +compare(a, b, x) compares "a" and "b" by computing the limit L. +mrv(e, x) returns list of most rapidly varying (mrv) subexpressions of "e" +rewrite(e, Omega, x, wsym) rewrites "e" in terms of w +leadterm(f, x) returns the lowest power term in the series of f +mrv_leadterm(e, x) returns the lead term (c0, e0) for e +limitinf(e, x) computes lim e (for x->oo) +limit(e, z, z0) computes any limit by converting it to the case x->oo + +All the functions are really simple and straightforward except +rewrite(), which is the most difficult/complex part of the algorithm. +When the algorithm fails, the bugs are usually in the series expansion +(i.e. in SymPy) or in rewrite. + +This code is almost exact rewrite of the Maple code inside the Gruntz +thesis. + +Debugging +--------- + +Because the gruntz algorithm is highly recursive, it's difficult to +figure out what went wrong inside a debugger. Instead, turn on nice +debug prints by defining the environment variable SYMPY_DEBUG. For +example: + +[user@localhost]: SYMPY_DEBUG=True ./bin/isympy + +In [1]: limit(sin(x)/x, x, 0) +limitinf(_x*sin(1/_x), _x) = 1 ++-mrv_leadterm(_x*sin(1/_x), _x) = (1, 0) +| +-mrv(_x*sin(1/_x), _x) = set([_x]) +| | +-mrv(_x, _x) = set([_x]) +| | +-mrv(sin(1/_x), _x) = set([_x]) +| | +-mrv(1/_x, _x) = set([_x]) +| | +-mrv(_x, _x) = set([_x]) +| +-mrv_leadterm(exp(_x)*sin(exp(-_x)), _x, set([exp(_x)])) = (1, 0) +| +-rewrite(exp(_x)*sin(exp(-_x)), set([exp(_x)]), _x, _w) = (1/_w*sin(_w), -_x) +| +-sign(_x, _x) = 1 +| +-mrv_leadterm(1, _x) = (1, 0) ++-sign(0, _x) = 0 ++-limitinf(1, _x) = 1 + +And check manually which line is wrong. Then go to the source code and +debug this function to figure out the exact problem. + +""" +from functools import reduce + +from sympy.core import Basic, S, Mul, PoleError +from sympy.core.cache import cacheit +from sympy.core.function import AppliedUndef +from sympy.core.intfunc import ilcm +from sympy.core.numbers import I, oo +from sympy.core.symbol import Dummy, Wild +from sympy.core.traversal import bottom_up + +from sympy.functions import log, exp, sign as _sign +from sympy.series.order import Order +from sympy.utilities.misc import debug_decorator as debug +from sympy.utilities.timeutils import timethis + +timeit = timethis('gruntz') + + +def compare(a, b, x): + """Returns "<" if a" for a>b""" + # log(exp(...)) must always be simplified here for termination + la, lb = log(a), log(b) + if isinstance(a, Basic) and (isinstance(a, exp) or (a.is_Pow and a.base == S.Exp1)): + la = a.exp + if isinstance(b, Basic) and (isinstance(b, exp) or (b.is_Pow and b.base == S.Exp1)): + lb = b.exp + + c = limitinf(la/lb, x) + if c == 0: + return "<" + elif c.is_infinite: + return ">" + else: + return "=" + + +class SubsSet(dict): + """ + Stores (expr, dummy) pairs, and how to rewrite expr-s. + + Explanation + =========== + + The gruntz algorithm needs to rewrite certain expressions in term of a new + variable w. We cannot use subs, because it is just too smart for us. For + example:: + + > Omega=[exp(exp(_p - exp(-_p))/(1 - 1/_p)), exp(exp(_p))] + > O2=[exp(-exp(_p) + exp(-exp(-_p))*exp(_p)/(1 - 1/_p))/_w, 1/_w] + > e = exp(exp(_p - exp(-_p))/(1 - 1/_p)) - exp(exp(_p)) + > e.subs(Omega[0],O2[0]).subs(Omega[1],O2[1]) + -1/w + exp(exp(p)*exp(-exp(-p))/(1 - 1/p)) + + is really not what we want! + + So we do it the hard way and keep track of all the things we potentially + want to substitute by dummy variables. Consider the expression:: + + exp(x - exp(-x)) + exp(x) + x. + + The mrv set is {exp(x), exp(-x), exp(x - exp(-x))}. + We introduce corresponding dummy variables d1, d2, d3 and rewrite:: + + d3 + d1 + x. + + This class first of all keeps track of the mapping expr->variable, i.e. + will at this stage be a dictionary:: + + {exp(x): d1, exp(-x): d2, exp(x - exp(-x)): d3}. + + [It turns out to be more convenient this way round.] + But sometimes expressions in the mrv set have other expressions from the + mrv set as subexpressions, and we need to keep track of that as well. In + this case, d3 is really exp(x - d2), so rewrites at this stage is:: + + {d3: exp(x-d2)}. + + The function rewrite uses all this information to correctly rewrite our + expression in terms of w. In this case w can be chosen to be exp(-x), + i.e. d2. The correct rewriting then is:: + + exp(-w)/w + 1/w + x. + """ + def __init__(self): + self.rewrites = {} + + def __repr__(self): + return super().__repr__() + ', ' + self.rewrites.__repr__() + + def __getitem__(self, key): + if key not in self: + self[key] = Dummy() + return dict.__getitem__(self, key) + + def do_subs(self, e): + """Substitute the variables with expressions""" + for expr, var in self.items(): + e = e.xreplace({var: expr}) + return e + + def meets(self, s2): + """Tell whether or not self and s2 have non-empty intersection""" + return set(self.keys()).intersection(list(s2.keys())) != set() + + def union(self, s2, exps=None): + """Compute the union of self and s2, adjusting exps""" + res = self.copy() + tr = {} + for expr, var in s2.items(): + if expr in self: + if exps: + exps = exps.xreplace({var: res[expr]}) + tr[var] = res[expr] + else: + res[expr] = var + for var, rewr in s2.rewrites.items(): + res.rewrites[var] = rewr.xreplace(tr) + return res, exps + + def copy(self): + """Create a shallow copy of SubsSet""" + r = SubsSet() + r.rewrites = self.rewrites.copy() + for expr, var in self.items(): + r[expr] = var + return r + + +@debug +def mrv(e, x): + """Returns a SubsSet of most rapidly varying (mrv) subexpressions of 'e', + and e rewritten in terms of these""" + from sympy.simplify.powsimp import powsimp + e = powsimp(e, deep=True, combine='exp') + if not isinstance(e, Basic): + raise TypeError("e should be an instance of Basic") + if not e.has(x): + return SubsSet(), e + elif e == x: + s = SubsSet() + return s, s[x] + elif e.is_Mul or e.is_Add: + i, d = e.as_independent(x) # throw away x-independent terms + if d.func != e.func: + s, expr = mrv(d, x) + return s, e.func(i, expr) + a, b = d.as_two_terms() + s1, e1 = mrv(a, x) + s2, e2 = mrv(b, x) + return mrv_max1(s1, s2, e.func(i, e1, e2), x) + elif e.is_Pow and e.base != S.Exp1: + e1 = S.One + while e.is_Pow: + b1 = e.base + e1 *= e.exp + e = b1 + if b1 == 1: + return SubsSet(), b1 + if e1.has(x): + return mrv(exp(e1*log(b1)), x) + else: + s, expr = mrv(b1, x) + return s, expr**e1 + elif isinstance(e, log): + s, expr = mrv(e.args[0], x) + return s, log(expr) + elif isinstance(e, exp) or (e.is_Pow and e.base == S.Exp1): + # We know from the theory of this algorithm that exp(log(...)) may always + # be simplified here, and doing so is vital for termination. + if isinstance(e.exp, log): + return mrv(e.exp.args[0], x) + # if a product has an infinite factor the result will be + # infinite if there is no zero, otherwise NaN; here, we + # consider the result infinite if any factor is infinite + li = limitinf(e.exp, x) + if any(_.is_infinite for _ in Mul.make_args(li)): + s1 = SubsSet() + e1 = s1[e] + s2, e2 = mrv(e.exp, x) + su = s1.union(s2)[0] + su.rewrites[e1] = exp(e2) + return mrv_max3(s1, e1, s2, exp(e2), su, e1, x) + else: + s, expr = mrv(e.exp, x) + return s, exp(expr) + elif isinstance(e, AppliedUndef): + raise ValueError("MRV set computation for UndefinedFunction is not allowed") + elif e.is_Function: + l = [mrv(a, x) for a in e.args] + l2 = [s for (s, _) in l if s != SubsSet()] + if len(l2) != 1: + # e.g. something like BesselJ(x, x) + raise NotImplementedError("MRV set computation for functions in" + " several variables not implemented.") + s, ss = l2[0], SubsSet() + args = [ss.do_subs(x[1]) for x in l] + return s, e.func(*args) + elif e.is_Derivative: + raise NotImplementedError("MRV set computation for derivatives" + " not implemented yet.") + raise NotImplementedError( + "Don't know how to calculate the mrv of '%s'" % e) + + +def mrv_max3(f, expsf, g, expsg, union, expsboth, x): + """ + Computes the maximum of two sets of expressions f and g, which + are in the same comparability class, i.e. max() compares (two elements of) + f and g and returns either (f, expsf) [if f is larger], (g, expsg) + [if g is larger] or (union, expsboth) [if f, g are of the same class]. + """ + if not isinstance(f, SubsSet): + raise TypeError("f should be an instance of SubsSet") + if not isinstance(g, SubsSet): + raise TypeError("g should be an instance of SubsSet") + if f == SubsSet(): + return g, expsg + elif g == SubsSet(): + return f, expsf + elif f.meets(g): + return union, expsboth + + c = compare(list(f.keys())[0], list(g.keys())[0], x) + if c == ">": + return f, expsf + elif c == "<": + return g, expsg + else: + if c != "=": + raise ValueError("c should be =") + return union, expsboth + + +def mrv_max1(f, g, exps, x): + """Computes the maximum of two sets of expressions f and g, which + are in the same comparability class, i.e. mrv_max1() compares (two elements of) + f and g and returns the set, which is in the higher comparability class + of the union of both, if they have the same order of variation. + Also returns exps, with the appropriate substitutions made. + """ + u, b = f.union(g, exps) + return mrv_max3(f, g.do_subs(exps), g, f.do_subs(exps), + u, b, x) + + +@debug +@cacheit +@timeit +def sign(e, x): + """ + Returns a sign of an expression e(x) for x->oo. + + :: + + e > 0 for x sufficiently large ... 1 + e == 0 for x sufficiently large ... 0 + e < 0 for x sufficiently large ... -1 + + The result of this function is currently undefined if e changes sign + arbitrarily often for arbitrarily large x (e.g. sin(x)). + + Note that this returns zero only if e is *constantly* zero + for x sufficiently large. [If e is constant, of course, this is just + the same thing as the sign of e.] + """ + if not isinstance(e, Basic): + raise TypeError("e should be an instance of Basic") + + if e.is_positive: + return 1 + elif e.is_negative: + return -1 + elif e.is_zero: + return 0 + + elif not e.has(x): + from sympy.simplify import logcombine + e = logcombine(e) + return _sign(e) + elif e == x: + return 1 + elif e.is_Mul: + a, b = e.as_two_terms() + sa = sign(a, x) + if not sa: + return 0 + return sa * sign(b, x) + elif isinstance(e, exp): + return 1 + elif e.is_Pow: + if e.base == S.Exp1: + return 1 + s = sign(e.base, x) + if s == 1: + return 1 + if e.exp.is_Integer: + return s**e.exp + elif isinstance(e, log) and e.args[0].is_positive: + return sign(e.args[0] - 1, x) + + # if all else fails, do it the hard way + c0, e0 = mrv_leadterm(e, x) + return sign(c0, x) + + +@debug +@timeit +@cacheit +def limitinf(e, x): + """Limit e(x) for x-> oo.""" + # rewrite e in terms of tractable functions only + + old = e + if not e.has(x): + return e # e is a constant + from sympy.simplify.powsimp import powdenest + from sympy.calculus.util import AccumBounds + if e.has(Order): + e = e.expand().removeO() + if not x.is_positive or x.is_integer: + # We make sure that x.is_positive is True and x.is_integer is None + # so we get all the correct mathematical behavior from the expression. + # We need a fresh variable. + p = Dummy('p', positive=True) + e = e.subs(x, p) + x = p + e = e.rewrite('tractable', deep=True, limitvar=x) + e = powdenest(e) + if isinstance(e, AccumBounds): + if mrv_leadterm(e.min, x) != mrv_leadterm(e.max, x): + raise NotImplementedError + c0, e0 = mrv_leadterm(e.min, x) + else: + c0, e0 = mrv_leadterm(e, x) + sig = sign(e0, x) + if sig == 1: + return S.Zero # e0>0: lim f = 0 + elif sig == -1: # e0<0: lim f = +-oo (the sign depends on the sign of c0) + if c0.match(I*Wild("a", exclude=[I])): + return c0*oo + s = sign(c0, x) + # the leading term shouldn't be 0: + if s == 0: + raise ValueError("Leading term should not be 0") + return s*oo + elif sig == 0: + if c0 == old: + c0 = c0.cancel() + return limitinf(c0, x) # e0=0: lim f = lim c0 + else: + raise ValueError("{} could not be evaluated".format(sig)) + + +def moveup2(s, x): + r = SubsSet() + for expr, var in s.items(): + r[expr.xreplace({x: exp(x)})] = var + for var, expr in s.rewrites.items(): + r.rewrites[var] = s.rewrites[var].xreplace({x: exp(x)}) + return r + + +def moveup(l, x): + return [e.xreplace({x: exp(x)}) for e in l] + + +@debug +@timeit +@cacheit +def mrv_leadterm(e, x): + """Returns (c0, e0) for e.""" + Omega = SubsSet() + if not e.has(x): + return (e, S.Zero) + if Omega == SubsSet(): + Omega, exps = mrv(e, x) + if not Omega: + # e really does not depend on x after simplification + return exps, S.Zero + if x in Omega: + # move the whole omega up (exponentiate each term): + Omega_up = moveup2(Omega, x) + exps_up = moveup([exps], x)[0] + # NOTE: there is no need to move this down! + Omega = Omega_up + exps = exps_up + # + # The positive dummy, w, is used here so log(w*2) etc. will expand; + # a unique dummy is needed in this algorithm + # + # For limits of complex functions, the algorithm would have to be + # improved, or just find limits of Re and Im components separately. + # + w = Dummy("w", positive=True) + f, logw = rewrite(exps, Omega, x, w) + + # Ensure expressions of the form exp(log(...)) don't get simplified automatically in the previous steps. + # see: https://github.com/sympy/sympy/issues/15323#issuecomment-478639399 + f = f.replace(lambda f: f.is_Pow and f.has(x), lambda f: exp(log(f.base)*f.exp)) + + try: + lt = f.leadterm(w, logx=logw) + except (NotImplementedError, PoleError, ValueError): + n0 = 1 + _series = Order(1) + incr = S.One + while _series.is_Order: + _series = f._eval_nseries(w, n=n0+incr, logx=logw) + incr *= 2 + series = _series.expand().removeO() + try: + lt = series.leadterm(w, logx=logw) + except (NotImplementedError, PoleError, ValueError): + lt = f.as_coeff_exponent(w) + if lt[0].has(w): + base = f.as_base_exp()[0].as_coeff_exponent(w) + ex = f.as_base_exp()[1] + lt = (base[0]**ex, base[1]*ex) + return (lt[0].subs(log(w), logw), lt[1]) + + +def build_expression_tree(Omega, rewrites): + r""" Helper function for rewrite. + + We need to sort Omega (mrv set) so that we replace an expression before + we replace any expression in terms of which it has to be rewritten:: + + e1 ---> e2 ---> e3 + \ + -> e4 + + Here we can do e1, e2, e3, e4 or e1, e2, e4, e3. + To do this we assemble the nodes into a tree, and sort them by height. + + This function builds the tree, rewrites then sorts the nodes. + """ + class Node: + def __init__(self): + self.before = [] + self.expr = None + self.var = None + def ht(self): + return reduce(lambda x, y: x + y, + [x.ht() for x in self.before], 1) + nodes = {} + for expr, v in Omega: + n = Node() + n.var = v + n.expr = expr + nodes[v] = n + for _, v in Omega: + if v in rewrites: + n = nodes[v] + r = rewrites[v] + for _, v2 in Omega: + if r.has(v2): + n.before.append(nodes[v2]) + + return nodes + + +@debug +@timeit +def rewrite(e, Omega, x, wsym): + """e(x) ... the function + Omega ... the mrv set + wsym ... the symbol which is going to be used for w + + Returns the rewritten e in terms of w and log(w). See test_rewrite1() + for examples and correct results. + """ + + from sympy import AccumBounds + if not isinstance(Omega, SubsSet): + raise TypeError("Omega should be an instance of SubsSet") + if len(Omega) == 0: + raise ValueError("Length cannot be 0") + # all items in Omega must be exponentials + for t in Omega.keys(): + if not isinstance(t, exp): + raise ValueError("Value should be exp") + rewrites = Omega.rewrites + Omega = list(Omega.items()) + + nodes = build_expression_tree(Omega, rewrites) + Omega.sort(key=lambda x: nodes[x[1]].ht(), reverse=True) + + # make sure we know the sign of each exp() term; after the loop, + # g is going to be the "w" - the simplest one in the mrv set + for g, _ in Omega: + sig = sign(g.exp, x) + if sig != 1 and sig != -1 and not sig.has(AccumBounds): + raise NotImplementedError('Result depends on the sign of %s' % sig) + if sig == 1: + wsym = 1/wsym # if g goes to oo, substitute 1/w + # O2 is a list, which results by rewriting each item in Omega using "w" + O2 = [] + denominators = [] + for f, var in Omega: + c = limitinf(f.exp/g.exp, x) + if c.is_Rational: + denominators.append(c.q) + arg = f.exp + if var in rewrites: + if not isinstance(rewrites[var], exp): + raise ValueError("Value should be exp") + arg = rewrites[var].args[0] + O2.append((var, exp((arg - c*g.exp))*wsym**c)) + + # Remember that Omega contains subexpressions of "e". So now we find + # them in "e" and substitute them for our rewriting, stored in O2 + + # the following powsimp is necessary to automatically combine exponentials, + # so that the .xreplace() below succeeds: + # TODO this should not be necessary + from sympy.simplify.powsimp import powsimp + f = powsimp(e, deep=True, combine='exp') + for a, b in O2: + f = f.xreplace({a: b}) + + for _, var in Omega: + assert not f.has(var) + + # finally compute the logarithm of w (logw). + logw = g.exp + if sig == 1: + logw = -logw # log(w)->log(1/w)=-log(w) + + # Some parts of SymPy have difficulty computing series expansions with + # non-integral exponents. The following heuristic improves the situation: + exponent = reduce(ilcm, denominators, 1) + f = f.subs({wsym: wsym**exponent}) + logw /= exponent + + # bottom_up function is required for a specific case - when f is + # -exp(p/(p + 1)) + exp(-p**2/(p + 1) + p). No current simplification + # methods reduce this to 0 while not expanding polynomials. + f = bottom_up(f, lambda w: getattr(w, 'normal', lambda: w)()) + + return f, logw + + +def gruntz(e, z, z0, dir="+"): + """ + Compute the limit of e(z) at the point z0 using the Gruntz algorithm. + + Explanation + =========== + + ``z0`` can be any expression, including oo and -oo. + + For ``dir="+"`` (default) it calculates the limit from the right + (z->z0+) and for ``dir="-"`` the limit from the left (z->z0-). For infinite z0 + (oo or -oo), the dir argument does not matter. + + This algorithm is fully described in the module docstring in the gruntz.py + file. It relies heavily on the series expansion. Most frequently, gruntz() + is only used if the faster limit() function (which uses heuristics) fails. + """ + if not z.is_symbol: + raise NotImplementedError("Second argument must be a Symbol") + + # convert all limits to the limit z->oo; sign of z is handled in limitinf + r = None + if z0 in (oo, I*oo): + e0 = e + elif z0 in (-oo, -I*oo): + e0 = e.subs(z, -z) + else: + if str(dir) == "-": + e0 = e.subs(z, z0 - 1/z) + elif str(dir) == "+": + e0 = e.subs(z, z0 + 1/z) + else: + raise NotImplementedError("dir must be '+' or '-'") + + r = limitinf(e0, z) + + # This is a bit of a heuristic for nice results... we always rewrite + # tractable functions in terms of familiar intractable ones. + # It might be nicer to rewrite the exactly to what they were initially, + # but that would take some work to implement. + return r.rewrite('intractable', deep=True) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/kauers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/kauers.py new file mode 100644 index 0000000000000000000000000000000000000000..9e9645ff15ee5ae3c1d1c8709f76aed1b366f50a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/kauers.py @@ -0,0 +1,51 @@ +def finite_diff(expression, variable, increment=1): + """ + Takes as input a polynomial expression and the variable used to construct + it and returns the difference between function's value when the input is + incremented to 1 and the original function value. If you want an increment + other than one supply it as a third argument. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.series.kauers import finite_diff + >>> finite_diff(x**2, x) + 2*x + 1 + >>> finite_diff(y**3 + 2*y**2 + 3*y + 4, y) + 3*y**2 + 7*y + 6 + >>> finite_diff(x**2 + 3*x + 8, x, 2) + 4*x + 10 + >>> finite_diff(z**3 + 8*z, z, 3) + 9*z**2 + 27*z + 51 + """ + expression = expression.expand() + expression2 = expression.subs(variable, variable + increment) + expression2 = expression2.expand() + return expression2 - expression + +def finite_diff_kauers(sum): + """ + Takes as input a Sum instance and returns the difference between the sum + with the upper index incremented by 1 and the original sum. For example, + if S(n) is a sum, then finite_diff_kauers will return S(n + 1) - S(n). + + Examples + ======== + + >>> from sympy.series.kauers import finite_diff_kauers + >>> from sympy import Sum + >>> from sympy.abc import x, y, m, n, k + >>> finite_diff_kauers(Sum(k, (k, 1, n))) + n + 1 + >>> finite_diff_kauers(Sum(1/k, (k, 1, n))) + 1/(n + 1) + >>> finite_diff_kauers(Sum((x*y**2), (x, 1, n), (y, 1, m))) + (m + 1)**2*(n + 1) + >>> finite_diff_kauers(Sum((x*y), (x, 1, m), (y, 1, n))) + (m + 1)*(n + 1) + """ + function = sum.function + for l in sum.limits: + function = function.subs(l[0], l[- 1] + 1) + return function diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/limits.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/limits.py new file mode 100644 index 0000000000000000000000000000000000000000..e15f7a1243452075a76553903cabf60e43942d8c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/limits.py @@ -0,0 +1,394 @@ +from sympy.calculus.accumulationbounds import AccumBounds +from sympy.core import S, Symbol, Add, sympify, Expr, PoleError, Mul +from sympy.core.exprtools import factor_terms +from sympy.core.numbers import Float, _illegal +from sympy.core.function import AppliedUndef +from sympy.core.symbol import Dummy +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.complexes import (Abs, sign, arg, re) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.special.gamma_functions import gamma +from sympy.polys import PolynomialError, factor +from sympy.series.order import Order +from .gruntz import gruntz + +def limit(e, z, z0, dir="+"): + """Computes the limit of ``e(z)`` at the point ``z0``. + + Parameters + ========== + + e : expression, the limit of which is to be taken + + z : symbol representing the variable in the limit. + Other symbols are treated as constants. Multivariate limits + are not supported. + + z0 : the value toward which ``z`` tends. Can be any expression, + including ``oo`` and ``-oo``. + + dir : string, optional (default: "+") + The limit is bi-directional if ``dir="+-"``, from the right + (z->z0+) if ``dir="+"``, and from the left (z->z0-) if + ``dir="-"``. For infinite ``z0`` (``oo`` or ``-oo``), the ``dir`` + argument is determined from the direction of the infinity + (i.e., ``dir="-"`` for ``oo``). + + Examples + ======== + + >>> from sympy import limit, sin, oo + >>> from sympy.abc import x + >>> limit(sin(x)/x, x, 0) + 1 + >>> limit(1/x, x, 0) # default dir='+' + oo + >>> limit(1/x, x, 0, dir="-") + -oo + >>> limit(1/x, x, 0, dir='+-') + zoo + >>> limit(1/x, x, oo) + 0 + + Notes + ===== + + First we try some heuristics for easy and frequent cases like "x", "1/x", + "x**2" and similar, so that it's fast. For all other cases, we use the + Gruntz algorithm (see the gruntz() function). + + See Also + ======== + + limit_seq : returns the limit of a sequence. + """ + + return Limit(e, z, z0, dir).doit(deep=False) + + +def heuristics(e, z, z0, dir): + """Computes the limit of an expression term-wise. + Parameters are the same as for the ``limit`` function. + Works with the arguments of expression ``e`` one by one, computing + the limit of each and then combining the results. This approach + works only for simple limits, but it is fast. + """ + + rv = None + if z0 is S.Infinity: + rv = limit(e.subs(z, 1/z), z, S.Zero, "+") + if isinstance(rv, Limit): + return + elif (e.is_Mul or e.is_Add or e.is_Pow or (e.is_Function and not isinstance(e, AppliedUndef))): + r = [] + from sympy.simplify.simplify import together + for a in e.args: + l = limit(a, z, z0, dir) + if l.has(S.Infinity) and l.is_finite is None: + if isinstance(e, Add): + m = factor_terms(e) + if not isinstance(m, Mul): # try together + m = together(m) + if not isinstance(m, Mul): # try factor if the previous methods failed + m = factor(e) + if isinstance(m, Mul): + return heuristics(m, z, z0, dir) + return + return + elif isinstance(l, Limit): + return + elif l is S.NaN: + return + else: + r.append(l) + if r: + rv = e.func(*r) + if rv is S.NaN and e.is_Mul and any(isinstance(rr, AccumBounds) for rr in r): + r2 = [] + e2 = [] + for ii, rval in enumerate(r): + if isinstance(rval, AccumBounds): + r2.append(rval) + else: + e2.append(e.args[ii]) + + if len(e2) > 0: + e3 = Mul(*e2).simplify() + l = limit(e3, z, z0, dir) + rv = l * Mul(*r2) + + if rv is S.NaN: + try: + from sympy.simplify.ratsimp import ratsimp + rat_e = ratsimp(e) + except PolynomialError: + return + if rat_e is S.NaN or rat_e == e: + return + return limit(rat_e, z, z0, dir) + return rv + + +class Limit(Expr): + """Represents an unevaluated limit. + + Examples + ======== + + >>> from sympy import Limit, sin + >>> from sympy.abc import x + >>> Limit(sin(x)/x, x, 0) + Limit(sin(x)/x, x, 0, dir='+') + >>> Limit(1/x, x, 0, dir="-") + Limit(1/x, x, 0, dir='-') + + """ + + def __new__(cls, e, z, z0, dir="+"): + e = sympify(e) + z = sympify(z) + z0 = sympify(z0) + + if z0 in (S.Infinity, S.ImaginaryUnit*S.Infinity): + dir = "-" + elif z0 in (S.NegativeInfinity, S.ImaginaryUnit*S.NegativeInfinity): + dir = "+" + + if(z0.has(z)): + raise NotImplementedError("Limits approaching a variable point are" + " not supported (%s -> %s)" % (z, z0)) + if isinstance(dir, str): + dir = Symbol(dir) + elif not isinstance(dir, Symbol): + raise TypeError("direction must be of type basestring or " + "Symbol, not %s" % type(dir)) + if str(dir) not in ('+', '-', '+-'): + raise ValueError("direction must be one of '+', '-' " + "or '+-', not %s" % dir) + + obj = Expr.__new__(cls) + obj._args = (e, z, z0, dir) + return obj + + + @property + def free_symbols(self): + e = self.args[0] + isyms = e.free_symbols + isyms.difference_update(self.args[1].free_symbols) + isyms.update(self.args[2].free_symbols) + return isyms + + + def pow_heuristics(self, e): + _, z, z0, _ = self.args + b1, e1 = e.base, e.exp + if not b1.has(z): + res = limit(e1*log(b1), z, z0) + return exp(res) + + ex_lim = limit(e1, z, z0) + base_lim = limit(b1, z, z0) + + if base_lim is S.One: + if ex_lim in (S.Infinity, S.NegativeInfinity): + res = limit(e1*(b1 - 1), z, z0) + return exp(res) + if base_lim is S.NegativeInfinity and ex_lim is S.Infinity: + return S.ComplexInfinity + + + def doit(self, **hints): + """Evaluates the limit. + + Parameters + ========== + + deep : bool, optional (default: True) + Invoke the ``doit`` method of the expressions involved before + taking the limit. + + hints : optional keyword arguments + To be passed to ``doit`` methods; only used if deep is True. + """ + + e, z, z0, dir = self.args + + if str(dir) == '+-': + r = limit(e, z, z0, dir='+') + l = limit(e, z, z0, dir='-') + if isinstance(r, Limit) and isinstance(l, Limit): + if r.args[0] == l.args[0]: + return self + if r == l: + return l + if r.is_infinite and l.is_infinite: + return S.ComplexInfinity + raise ValueError("The limit does not exist since " + "left hand limit = %s and right hand limit = %s" + % (l, r)) + + if z0 is S.ComplexInfinity: + raise NotImplementedError("Limits at complex " + "infinity are not implemented") + + if z0.is_infinite: + cdir = sign(z0) + cdir = cdir/abs(cdir) + e = e.subs(z, cdir*z) + dir = "-" + z0 = S.Infinity + + if hints.get('deep', True): + e = e.doit(**hints) + z = z.doit(**hints) + z0 = z0.doit(**hints) + + if e == z: + return z0 + + if not e.has(z): + return e + + if z0 is S.NaN: + return S.NaN + + if e.has(*_illegal): + return self + + if e.is_Order: + return Order(limit(e.expr, z, z0), *e.args[1:]) + + cdir = S.Zero + if str(dir) == "+": + cdir = S.One + elif str(dir) == "-": + cdir = S.NegativeOne + + def set_signs(expr): + if not expr.args: + return expr + newargs = tuple(set_signs(arg) for arg in expr.args) + if newargs != expr.args: + expr = expr.func(*newargs) + abs_flag = isinstance(expr, Abs) + arg_flag = isinstance(expr, arg) + sign_flag = isinstance(expr, sign) + if abs_flag or sign_flag or arg_flag: + try: + sig = limit(expr.args[0], z, z0, dir) + if sig.is_zero: + sig = limit(1/expr.args[0], z, z0, dir) + except NotImplementedError: + return expr + else: + if sig.is_extended_real: + if (sig < 0) == True: + return (-expr.args[0] if abs_flag else + S.NegativeOne if sign_flag else S.Pi) + elif (sig > 0) == True: + return (expr.args[0] if abs_flag else + S.One if sign_flag else S.Zero) + return expr + + if e.has(Float): + # Convert floats like 0.5 to exact SymPy numbers like S.Half, to + # prevent rounding errors which can lead to unexpected execution + # of conditional blocks that work on comparisons + # Also see comments in https://github.com/sympy/sympy/issues/19453 + from sympy.simplify.simplify import nsimplify + e = nsimplify(e) + e = set_signs(e) + + + if e.is_meromorphic(z, z0): + if z0 is S.Infinity: + newe = e.subs(z, 1/z) + # cdir changes sign as oo- should become 0+ + cdir = -cdir + else: + newe = e.subs(z, z + z0) + try: + coeff, ex = newe.leadterm(z, cdir=cdir) + except ValueError: + pass + else: + if ex > 0: + return S.Zero + elif ex == 0: + return coeff + if cdir == 1 or not(int(ex) & 1): + return S.Infinity*sign(coeff) + elif cdir == -1: + return S.NegativeInfinity*sign(coeff) + else: + return S.ComplexInfinity + + if z0 is S.Infinity: + if e.is_Mul: + e = factor_terms(e) + dummy = Dummy('z', positive=z.is_positive, negative=z.is_negative, real=z.is_real) + newe = e.subs(z, 1/dummy) + # cdir changes sign as oo- should become 0+ + cdir = -cdir + newz = dummy + else: + newe = e.subs(z, z + z0) + newz = z + try: + coeff, ex = newe.leadterm(newz, cdir=cdir) + except (ValueError, NotImplementedError, PoleError): + # The NotImplementedError catching is for custom functions + from sympy.simplify.powsimp import powsimp + e = powsimp(e) + if e.is_Pow: + r = self.pow_heuristics(e) + if r is not None: + return r + try: + coeff = newe.as_leading_term(newz, cdir=cdir) + if coeff != newe and (coeff.has(exp) or coeff.has(S.Exp1)): + return gruntz(coeff, newz, 0, "-" if re(cdir).is_negative else "+") + except (ValueError, NotImplementedError, PoleError): + pass + else: + if isinstance(coeff, AccumBounds) and ex == S.Zero: + return coeff + if coeff.has(S.Infinity, S.NegativeInfinity, S.ComplexInfinity, S.NaN): + return self + if not coeff.has(newz): + if ex.is_positive: + return S.Zero + elif ex == 0: + return coeff + elif ex.is_negative: + if cdir == 1: + return S.Infinity*sign(coeff) + elif cdir == -1: + return S.NegativeInfinity*sign(coeff)*S.NegativeOne**(S.One + ex) + else: + return S.ComplexInfinity + else: + raise NotImplementedError("Not sure of sign of %s" % ex) + + # gruntz fails on factorials but works with the gamma function + # If no factorial term is present, e should remain unchanged. + # factorial is defined to be zero for negative inputs (which + # differs from gamma) so only rewrite for non-negative z0. + if z0.is_extended_nonnegative: + e = e.rewrite(factorial, gamma) + + l = None + + try: + r = gruntz(e, z, z0, dir) + if r is S.NaN or l is S.NaN: + raise PoleError() + except (PoleError, ValueError): + if l is not None: + raise + r = heuristics(e, z, z0, dir) + if r is None: + return self + + return r diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/limitseq.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/limitseq.py new file mode 100644 index 0000000000000000000000000000000000000000..ceac4e7b63bfc09d9dfc26c12c7d2acc8b8d44da --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/limitseq.py @@ -0,0 +1,257 @@ +"""Limits of sequences""" + +from sympy.calculus.accumulationbounds import AccumulationBounds +from sympy.core.add import Add +from sympy.core.function import PoleError +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.numbers import fibonacci +from sympy.functions.combinatorial.factorials import factorial, subfactorial +from sympy.functions.special.gamma_functions import gamma +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.miscellaneous import Max, Min +from sympy.functions.elementary.trigonometric import cos, sin +from sympy.series.limits import Limit + + +def difference_delta(expr, n=None, step=1): + """Difference Operator. + + Explanation + =========== + + Discrete analog of differential operator. Given a sequence x[n], + returns the sequence x[n + step] - x[n]. + + Examples + ======== + + >>> from sympy import difference_delta as dd + >>> from sympy.abc import n + >>> dd(n*(n + 1), n) + 2*n + 2 + >>> dd(n*(n + 1), n, 2) + 4*n + 6 + + References + ========== + + .. [1] https://reference.wolfram.com/language/ref/DifferenceDelta.html + """ + expr = sympify(expr) + + if n is None: + f = expr.free_symbols + if len(f) == 1: + n = f.pop() + elif len(f) == 0: + return S.Zero + else: + raise ValueError("Since there is more than one variable in the" + " expression, a variable must be supplied to" + " take the difference of %s" % expr) + step = sympify(step) + if step.is_number is False or step.is_finite is False: + raise ValueError("Step should be a finite number.") + + if hasattr(expr, '_eval_difference_delta'): + result = expr._eval_difference_delta(n, step) + if result: + return result + + return expr.subs(n, n + step) - expr + + +def dominant(expr, n): + """Finds the dominant term in a sum, that is a term that dominates + every other term. + + Explanation + =========== + + If limit(a/b, n, oo) is oo then a dominates b. + If limit(a/b, n, oo) is 0 then b dominates a. + Otherwise, a and b are comparable. + + If there is no unique dominant term, then returns ``None``. + + Examples + ======== + + >>> from sympy import Sum + >>> from sympy.series.limitseq import dominant + >>> from sympy.abc import n, k + >>> dominant(5*n**3 + 4*n**2 + n + 1, n) + 5*n**3 + >>> dominant(2**n + Sum(k, (k, 0, n)), n) + 2**n + + See Also + ======== + + sympy.series.limitseq.dominant + """ + terms = Add.make_args(expr.expand(func=True)) + term0 = terms[-1] + comp = [term0] # comparable terms + for t in terms[:-1]: + r = term0/t + e = r.gammasimp() + if e == r: + e = r.factor() + l = limit_seq(e, n) + if l is None: + return None + elif l.is_zero: + term0 = t + comp = [term0] + elif l not in [S.Infinity, S.NegativeInfinity]: + comp.append(t) + if len(comp) > 1: + return None + return term0 + + +def _limit_inf(expr, n): + try: + return Limit(expr, n, S.Infinity).doit(deep=False) + except (NotImplementedError, PoleError): + return None + + +def _limit_seq(expr, n, trials): + from sympy.concrete.summations import Sum + + for i in range(trials): + if not expr.has(Sum): + result = _limit_inf(expr, n) + if result is not None: + return result + + num, den = expr.as_numer_denom() + if not den.has(n) or not num.has(n): + result = _limit_inf(expr.doit(), n) + if result is not None: + return result + return None + + num, den = (difference_delta(t.expand(), n) for t in [num, den]) + expr = (num / den).gammasimp() + + if not expr.has(Sum): + result = _limit_inf(expr, n) + if result is not None: + return result + + num, den = expr.as_numer_denom() + + num = dominant(num, n) + if num is None: + return None + + den = dominant(den, n) + if den is None: + return None + + expr = (num / den).gammasimp() + + +def limit_seq(expr, n=None, trials=5): + """Finds the limit of a sequence as index ``n`` tends to infinity. + + Parameters + ========== + + expr : Expr + SymPy expression for the ``n-th`` term of the sequence + n : Symbol, optional + The index of the sequence, an integer that tends to positive + infinity. If None, inferred from the expression unless it has + multiple symbols. + trials: int, optional + The algorithm is highly recursive. ``trials`` is a safeguard from + infinite recursion in case the limit is not easily computed by the + algorithm. Try increasing ``trials`` if the algorithm returns ``None``. + + Admissible Terms + ================ + + The algorithm is designed for sequences built from rational functions, + indefinite sums, and indefinite products over an indeterminate n. Terms of + alternating sign are also allowed, but more complex oscillatory behavior is + not supported. + + Examples + ======== + + >>> from sympy import limit_seq, Sum, binomial + >>> from sympy.abc import n, k, m + >>> limit_seq((5*n**3 + 3*n**2 + 4) / (3*n**3 + 4*n - 5), n) + 5/3 + >>> limit_seq(binomial(2*n, n) / Sum(binomial(2*k, k), (k, 1, n)), n) + 3/4 + >>> limit_seq(Sum(k**2 * Sum(2**m/m, (m, 1, k)), (k, 1, n)) / (2**n*n), n) + 4 + + See Also + ======== + + sympy.series.limitseq.dominant + + References + ========== + + .. [1] Computing Limits of Sequences - Manuel Kauers + """ + + from sympy.concrete.summations import Sum + if n is None: + free = expr.free_symbols + if len(free) == 1: + n = free.pop() + elif not free: + return expr + else: + raise ValueError("Expression has more than one variable. " + "Please specify a variable.") + elif n not in expr.free_symbols: + return expr + + expr = expr.rewrite(fibonacci, S.GoldenRatio) + expr = expr.rewrite(factorial, subfactorial, gamma) + n_ = Dummy("n", integer=True, positive=True) + n1 = Dummy("n", odd=True, positive=True) + n2 = Dummy("n", even=True, positive=True) + + # If there is a negative term raised to a power involving n, or a + # trigonometric function, then consider even and odd n separately. + powers = (p.as_base_exp() for p in expr.atoms(Pow)) + if (any(b.is_negative and e.has(n) for b, e in powers) or + expr.has(cos, sin)): + L1 = _limit_seq(expr.xreplace({n: n1}), n1, trials) + if L1 is not None: + L2 = _limit_seq(expr.xreplace({n: n2}), n2, trials) + if L1 != L2: + if L1.is_comparable and L2.is_comparable: + return AccumulationBounds(Min(L1, L2), Max(L1, L2)) + else: + return None + else: + L1 = _limit_seq(expr.xreplace({n: n_}), n_, trials) + if L1 is not None: + return L1 + else: + if expr.is_Add: + limits = [limit_seq(term, n, trials) for term in expr.args] + if any(result is None for result in limits): + return None + else: + return Add(*limits) + # Maybe the absolute value is easier to deal with (though not if + # it has a Sum). If it tends to 0, the limit is 0. + elif not expr.has(Sum): + lim = _limit_seq(Abs(expr.xreplace({n: n_})), n_, trials) + if lim is not None and lim.is_zero: + return S.Zero diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/order.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/order.py new file mode 100644 index 0000000000000000000000000000000000000000..9cfd4309c2b7094ce02feab129e5f051c442d8cd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/order.py @@ -0,0 +1,522 @@ +from sympy.core import S, sympify, Expr, Dummy, Add, Mul +from sympy.core.cache import cacheit +from sympy.core.containers import Tuple +from sympy.core.function import Function, PoleError, expand_power_base, expand_log +from sympy.core.sorting import default_sort_key +from sympy.functions.elementary.exponential import exp, log +from sympy.sets.sets import Complement +from sympy.utilities.iterables import uniq, is_sequence + + +class Order(Expr): + r""" Represents the limiting behavior of some function. + + Explanation + =========== + + The order of a function characterizes the function based on the limiting + behavior of the function as it goes to some limit. Only taking the limit + point to be a number is currently supported. This is expressed in + big O notation [1]_. + + The formal definition for the order of a function `g(x)` about a point `a` + is such that `g(x) = O(f(x))` as `x \rightarrow a` if and only if there + exists a `\delta > 0` and an `M > 0` such that `|g(x)| \leq M|f(x)|` for + `|x-a| < \delta`. This is equivalent to `\limsup_{x \rightarrow a} + |g(x)/f(x)| < \infty`. + + Let's illustrate it on the following example by taking the expansion of + `\sin(x)` about 0: + + .. math :: + \sin(x) = x - x^3/3! + O(x^5) + + where in this case `O(x^5) = x^5/5! - x^7/7! + \cdots`. By the definition + of `O`, there is a `\delta > 0` and an `M` such that: + + .. math :: + |x^5/5! - x^7/7! + ....| <= M|x^5| \text{ for } |x| < \delta + + or by the alternate definition: + + .. math :: + \lim_{x \rightarrow 0} | (x^5/5! - x^7/7! + ....) / x^5| < \infty + + which surely is true, because + + .. math :: + \lim_{x \rightarrow 0} | (x^5/5! - x^7/7! + ....) / x^5| = 1/5! + + + As it is usually used, the order of a function can be intuitively thought + of representing all terms of powers greater than the one specified. For + example, `O(x^3)` corresponds to any terms proportional to `x^3, + x^4,\ldots` and any higher power. For a polynomial, this leaves terms + proportional to `x^2`, `x` and constants. + + Examples + ======== + + >>> from sympy import O, oo, cos, pi + >>> from sympy.abc import x, y + + >>> O(x + x**2) + O(x) + >>> O(x + x**2, (x, 0)) + O(x) + >>> O(x + x**2, (x, oo)) + O(x**2, (x, oo)) + + >>> O(1 + x*y) + O(1, x, y) + >>> O(1 + x*y, (x, 0), (y, 0)) + O(1, x, y) + >>> O(1 + x*y, (x, oo), (y, oo)) + O(x*y, (x, oo), (y, oo)) + + >>> O(1) in O(1, x) + True + >>> O(1, x) in O(1) + False + >>> O(x) in O(1, x) + True + >>> O(x**2) in O(x) + True + + >>> O(x)*x + O(x**2) + >>> O(x) - O(x) + O(x) + >>> O(cos(x)) + O(1) + >>> O(cos(x), (x, pi/2)) + O(x - pi/2, (x, pi/2)) + + References + ========== + + .. [1] `Big O notation `_ + + Notes + ===== + + In ``O(f(x), x)`` the expression ``f(x)`` is assumed to have a leading + term. ``O(f(x), x)`` is automatically transformed to + ``O(f(x).as_leading_term(x),x)``. + + ``O(expr*f(x), x)`` is ``O(f(x), x)`` + + ``O(expr, x)`` is ``O(1)`` + + ``O(0, x)`` is 0. + + Multivariate O is also supported: + + ``O(f(x, y), x, y)`` is transformed to + ``O(f(x, y).as_leading_term(x,y).as_leading_term(y), x, y)`` + + In the multivariate case, it is assumed the limits w.r.t. the various + symbols commute. + + If no symbols are passed then all symbols in the expression are used + and the limit point is assumed to be zero. + + """ + + is_Order = True + + __slots__ = () + + @cacheit + def __new__(cls, expr, *args, **kwargs): + expr = sympify(expr) + + if not args: + if expr.is_Order: + variables = expr.variables + point = expr.point + else: + variables = list(expr.free_symbols) + point = [S.Zero]*len(variables) + else: + args = list(args if is_sequence(args) else [args]) + variables, point = [], [] + if is_sequence(args[0]): + for a in args: + v, p = list(map(sympify, a)) + variables.append(v) + point.append(p) + else: + variables = list(map(sympify, args)) + point = [S.Zero]*len(variables) + + if not all(v.is_symbol for v in variables): + raise TypeError('Variables are not symbols, got %s' % variables) + + if len(list(uniq(variables))) != len(variables): + raise ValueError('Variables are supposed to be unique symbols, got %s' % variables) + + if expr.is_Order: + expr_vp = dict(expr.args[1:]) + new_vp = dict(expr_vp) + vp = dict(zip(variables, point)) + for v, p in vp.items(): + if v in new_vp.keys(): + if p != new_vp[v]: + raise NotImplementedError( + "Mixing Order at different points is not supported.") + else: + new_vp[v] = p + if set(expr_vp.keys()) == set(new_vp.keys()): + return expr + else: + variables = list(new_vp.keys()) + point = [new_vp[v] for v in variables] + + if expr is S.NaN: + return S.NaN + + if any(x in p.free_symbols for x in variables for p in point): + raise ValueError('Got %s as a point.' % point) + + if variables: + if any(p != point[0] for p in point): + raise NotImplementedError( + "Multivariable orders at different points are not supported.") + if point[0] in (S.Infinity, S.Infinity*S.ImaginaryUnit): + s = {k: 1/Dummy() for k in variables} + rs = {1/v: 1/k for k, v in s.items()} + ps = [S.Zero for p in point] + elif point[0] in (S.NegativeInfinity, S.NegativeInfinity*S.ImaginaryUnit): + s = {k: -1/Dummy() for k in variables} + rs = {-1/v: -1/k for k, v in s.items()} + ps = [S.Zero for p in point] + elif point[0] is not S.Zero: + s = {k: Dummy() + point[0] for k in variables} + rs = {(v - point[0]).together(): k - point[0] for k, v in s.items()} + ps = [S.Zero for p in point] + else: + s = () + rs = () + ps = list(point) + + expr = expr.subs(s) + + if expr.is_Add: + expr = expr.factor() + + if s: + args = tuple([r[0] for r in rs.items()]) + else: + args = tuple(variables) + + if len(variables) > 1: + # XXX: better way? We need this expand() to + # workaround e.g: expr = x*(x + y). + # (x*(x + y)).as_leading_term(x, y) currently returns + # x*y (wrong order term!). That's why we want to deal with + # expand()'ed expr (handled in "if expr.is_Add" branch below). + expr = expr.expand() + + old_expr = None + while old_expr != expr: + old_expr = expr + if expr.is_Add: + lst = expr.extract_leading_order(args) + expr = Add(*[f.expr for (e, f) in lst]) + + elif expr: + try: + expr = expr.as_leading_term(*args) + except PoleError: + if isinstance(expr, Function) or\ + all(isinstance(arg, Function) for arg in expr.args): + # It is not possible to simplify an expression + # containing only functions (which raise error on + # call to leading term) further + pass + else: + orders = [] + pts = tuple(zip(args, ps)) + for arg in expr.args: + try: + lt = arg.as_leading_term(*args) + except PoleError: + lt = arg + if lt not in args: + order = Order(lt) + else: + order = Order(lt, *pts) + orders.append(order) + if expr.is_Add: + new_expr = Order(Add(*orders), *pts) + if new_expr.is_Add: + new_expr = Order(Add(*[a.expr for a in new_expr.args]), *pts) + expr = new_expr.expr + elif expr.is_Mul: + expr = Mul(*[a.expr for a in orders]) + elif expr.is_Pow: + e = expr.exp + b = expr.base + expr = exp(e * log(b)) + + # It would probably be better to handle this somewhere + # else. This is needed for a testcase in which there is a + # symbol with the assumptions zero=True. + if expr.is_zero: + expr = S.Zero + else: + expr = expr.as_independent(*args, as_Add=False)[1] + + expr = expand_power_base(expr) + expr = expand_log(expr) + + if len(args) == 1: + # The definition of O(f(x)) symbol explicitly stated that + # the argument of f(x) is irrelevant. That's why we can + # combine some power exponents (only "on top" of the + # expression tree for f(x)), e.g.: + # x**p * (-x)**q -> x**(p+q) for real p, q. + x = args[0] + margs = list(Mul.make_args( + expr.as_independent(x, as_Add=False)[1])) + + for i, t in enumerate(margs): + if t.is_Pow: + b, q = t.args + if b in (x, -x) and q.is_real and not q.has(x): + margs[i] = x**q + elif b.is_Pow and not b.exp.has(x): + b, r = b.args + if b in (x, -x) and r.is_real: + margs[i] = x**(r*q) + elif b.is_Mul and b.args[0] is S.NegativeOne: + b = -b + if b.is_Pow and not b.exp.has(x): + b, r = b.args + if b in (x, -x) and r.is_real: + margs[i] = x**(r*q) + + expr = Mul(*margs) + + expr = expr.subs(rs) + + if expr.is_Order: + expr = expr.expr + + if not expr.has(*variables) and not expr.is_zero: + expr = S.One + + # create Order instance: + vp = dict(zip(variables, point)) + variables.sort(key=default_sort_key) + point = [vp[v] for v in variables] + args = (expr,) + Tuple(*zip(variables, point)) + obj = Expr.__new__(cls, *args) + return obj + + def _eval_nseries(self, x, n, logx, cdir=0): + return self + + @property + def expr(self): + return self.args[0] + + @property + def variables(self): + if self.args[1:]: + return tuple(x[0] for x in self.args[1:]) + else: + return () + + @property + def point(self): + if self.args[1:]: + return tuple(x[1] for x in self.args[1:]) + else: + return () + + @property + def free_symbols(self): + return self.expr.free_symbols | set(self.variables) + + def _eval_power(b, e): + if e.is_Number and e.is_nonnegative: + return b.func(b.expr ** e, *b.args[1:]) + if e == O(1): + return b + return + + def as_expr_variables(self, order_symbols): + if order_symbols is None: + order_symbols = self.args[1:] + else: + if (not all(o[1] == order_symbols[0][1] for o in order_symbols) and + not all(p == self.point[0] for p in self.point)): # pragma: no cover + raise NotImplementedError('Order at points other than 0 ' + 'or oo not supported, got %s as a point.' % self.point) + if order_symbols and order_symbols[0][1] != self.point[0]: + raise NotImplementedError( + "Multiplying Order at different points is not supported.") + order_symbols = dict(order_symbols) + for s, p in dict(self.args[1:]).items(): + if s not in order_symbols.keys(): + order_symbols[s] = p + order_symbols = sorted(order_symbols.items(), key=lambda x: default_sort_key(x[0])) + return self.expr, tuple(order_symbols) + + def removeO(self): + return S.Zero + + def getO(self): + return self + + @cacheit + def contains(self, expr): + r""" + Return True if expr belongs to Order(self.expr, \*self.variables). + Return False if self belongs to expr. + Return None if the inclusion relation cannot be determined + (e.g. when self and expr have different symbols). + """ + expr = sympify(expr) + if expr.is_zero: + return True + if expr is S.NaN: + return False + point = self.point[0] if self.point else S.Zero + if expr.is_Order: + if (any(p != point for p in expr.point) or + any(p != point for p in self.point)): + return None + if expr.expr == self.expr: + # O(1) + O(1), O(1) + O(1, x), etc. + return all(x in self.args[1:] for x in expr.args[1:]) + if expr.expr.is_Add: + return all(self.contains(x) for x in expr.expr.args) + if self.expr.is_Add and point.is_zero: + return any(self.func(x, *self.args[1:]).contains(expr) + for x in self.expr.args) + if self.variables and expr.variables: + common_symbols = tuple( + [s for s in self.variables if s in expr.variables]) + elif self.variables: + common_symbols = self.variables + else: + common_symbols = expr.variables + if not common_symbols: + return None + if (self.expr.is_Pow and len(self.variables) == 1 + and self.variables == expr.variables): + symbol = self.variables[0] + other = expr.expr.as_independent(symbol, as_Add=False)[1] + if (other.is_Pow and other.base == symbol and + self.expr.base == symbol): + if point.is_zero: + rv = (self.expr.exp - other.exp).is_nonpositive + if point.is_infinite: + rv = (self.expr.exp - other.exp).is_nonnegative + if rv is not None: + return rv + + from sympy.simplify.powsimp import powsimp + r = None + ratio = self.expr/expr.expr + ratio = powsimp(ratio, deep=True, combine='exp') + for s in common_symbols: + from sympy.series.limits import Limit + l = Limit(ratio, s, point).doit(heuristics=False) + if not isinstance(l, Limit): + l = l != 0 + else: + l = None + if r is None: + r = l + else: + if r != l: + return + return r + + if self.expr.is_Pow and len(self.variables) == 1: + symbol = self.variables[0] + other = expr.as_independent(symbol, as_Add=False)[1] + if (other.is_Pow and other.base == symbol and + self.expr.base == symbol): + if point.is_zero: + rv = (self.expr.exp - other.exp).is_nonpositive + if point.is_infinite: + rv = (self.expr.exp - other.exp).is_nonnegative + if rv is not None: + return rv + + obj = self.func(expr, *self.args[1:]) + return self.contains(obj) + + def __contains__(self, other): + result = self.contains(other) + if result is None: + raise TypeError('contains did not evaluate to a bool') + return result + + def _eval_subs(self, old, new): + if old in self.variables: + newexpr = self.expr.subs(old, new) + i = self.variables.index(old) + newvars = list(self.variables) + newpt = list(self.point) + if new.is_symbol: + newvars[i] = new + else: + syms = new.free_symbols + if len(syms) == 1 or old in syms: + if old in syms: + var = self.variables[i] + else: + var = syms.pop() + # First, try to substitute self.point in the "new" + # expr to see if this is a fixed point. + # E.g. O(y).subs(y, sin(x)) + from sympy import limit + if new.has(Order) and limit(new.getO().expr, var, new.getO().point[0]) == self.point[i]: + point = new.getO().point[0] + return Order(newexpr, *zip([var], [point])) + else: + point = new.subs(var, self.point[i]) + if point != self.point[i]: + from sympy.solvers.solveset import solveset + d = Dummy() + sol = solveset(old - new.subs(var, d), d) + if isinstance(sol, Complement): + e1 = sol.args[0] + e2 = sol.args[1] + sol = set(e1) - set(e2) + res = [dict(zip((d, ), sol))] + point = d.subs(res[0]).limit(old, self.point[i]) + newvars[i] = var + newpt[i] = point + elif old not in syms: + del newvars[i], newpt[i] + if not syms and new == self.point[i]: + newvars.extend(syms) + newpt.extend([S.Zero]*len(syms)) + else: + return + return Order(newexpr, *zip(newvars, newpt)) + + def _eval_conjugate(self): + expr = self.expr._eval_conjugate() + if expr is not None: + return self.func(expr, *self.args[1:]) + + def _eval_derivative(self, x): + return self.func(self.expr.diff(x), *self.args[1:]) or self + + def _eval_transpose(self): + expr = self.expr._eval_transpose() + if expr is not None: + return self.func(expr, *self.args[1:]) + + def __neg__(self): + return self + +O = Order diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/residues.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/residues.py new file mode 100644 index 0000000000000000000000000000000000000000..a426f9e799bd040eea5124f718c2fa43e5de026b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/residues.py @@ -0,0 +1,73 @@ +""" +This module implements the Residue function and related tools for working +with residues. +""" + +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.core.sympify import sympify +from sympy.utilities.timeutils import timethis + + +@timethis('residue') +def residue(expr, x, x0): + """ + Finds the residue of ``expr`` at the point x=x0. + + The residue is defined as the coefficient of ``1/(x-x0)`` in the power series + expansion about ``x=x0``. + + Examples + ======== + + >>> from sympy import Symbol, residue, sin + >>> x = Symbol("x") + >>> residue(1/x, x, 0) + 1 + >>> residue(1/x**2, x, 0) + 0 + >>> residue(2/sin(x), x, 0) + 2 + + This function is essential for the Residue Theorem [1]. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Residue_theorem + """ + # The current implementation uses series expansion to + # calculate it. A more general implementation is explained in + # the section 5.6 of the Bronstein's book {M. Bronstein: + # Symbolic Integration I, Springer Verlag (2005)}. For purely + # rational functions, the algorithm is much easier. See + # sections 2.4, 2.5, and 2.7 (this section actually gives an + # algorithm for computing any Laurent series coefficient for + # a rational function). The theory in section 2.4 will help to + # understand why the resultant works in the general algorithm. + # For the definition of a resultant, see section 1.4 (and any + # previous sections for more review). + + from sympy.series.order import Order + from sympy.simplify.radsimp import collect + expr = sympify(expr) + if x0 != 0: + expr = expr.subs(x, x + x0) + for n in (0, 1, 2, 4, 8, 16, 32): + s = expr.nseries(x, n=n) + if not s.has(Order) or s.getn() >= 0: + break + s = collect(s.removeO(), x) + if s.is_Add: + args = s.args + else: + args = [s] + res = S.Zero + for arg in args: + c, m = arg.as_coeff_mul(x) + m = Mul(*m) + if not (m in (S.One, x) or (m.is_Pow and m.exp.is_Integer)): + raise NotImplementedError('term of unexpected form: %s' % m) + if m == 1/x: + res += c + return res diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/sequences.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/sequences.py new file mode 100644 index 0000000000000000000000000000000000000000..7787515ddb05afaf34751bf451544935723d0921 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/sequences.py @@ -0,0 +1,1239 @@ +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core.containers import Tuple +from sympy.core.decorators import call_highest_priority +from sympy.core.parameters import global_parameters +from sympy.core.function import AppliedUndef, expand +from sympy.core.mul import Mul +from sympy.core.numbers import Integer +from sympy.core.relational import Eq +from sympy.core.singleton import S, Singleton +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy, Symbol, Wild +from sympy.core.sympify import sympify +from sympy.matrices import Matrix +from sympy.polys import lcm, factor +from sympy.sets.sets import Interval, Intersection +from sympy.tensor.indexed import Idx +from sympy.utilities.iterables import flatten, is_sequence, iterable + + +############################################################################### +# SEQUENCES # +############################################################################### + + +class SeqBase(Basic): + """Base class for sequences""" + + is_commutative = True + _op_priority = 15 + + @staticmethod + def _start_key(expr): + """Return start (if possible) else S.Infinity. + + adapted from Set._infimum_key + """ + try: + start = expr.start + except NotImplementedError: + start = S.Infinity + return start + + def _intersect_interval(self, other): + """Returns start and stop. + + Takes intersection over the two intervals. + """ + interval = Intersection(self.interval, other.interval) + return interval.inf, interval.sup + + @property + def gen(self): + """Returns the generator for the sequence""" + raise NotImplementedError("(%s).gen" % self) + + @property + def interval(self): + """The interval on which the sequence is defined""" + raise NotImplementedError("(%s).interval" % self) + + @property + def start(self): + """The starting point of the sequence. This point is included""" + raise NotImplementedError("(%s).start" % self) + + @property + def stop(self): + """The ending point of the sequence. This point is included""" + raise NotImplementedError("(%s).stop" % self) + + @property + def length(self): + """Length of the sequence""" + raise NotImplementedError("(%s).length" % self) + + @property + def variables(self): + """Returns a tuple of variables that are bounded""" + return () + + @property + def free_symbols(self): + """ + This method returns the symbols in the object, excluding those + that take on a specific value (i.e. the dummy symbols). + + Examples + ======== + + >>> from sympy import SeqFormula + >>> from sympy.abc import n, m + >>> SeqFormula(m*n**2, (n, 0, 5)).free_symbols + {m} + """ + return ({j for i in self.args for j in i.free_symbols + .difference(self.variables)}) + + @cacheit + def coeff(self, pt): + """Returns the coefficient at point pt""" + if pt < self.start or pt > self.stop: + raise IndexError("Index %s out of bounds %s" % (pt, self.interval)) + return self._eval_coeff(pt) + + def _eval_coeff(self, pt): + raise NotImplementedError("The _eval_coeff method should be added to" + "%s to return coefficient so it is available" + "when coeff calls it." + % self.func) + + def _ith_point(self, i): + """Returns the i'th point of a sequence. + + Explanation + =========== + + If start point is negative infinity, point is returned from the end. + Assumes the first point to be indexed zero. + + Examples + ========= + + >>> from sympy import oo + >>> from sympy.series.sequences import SeqPer + + bounded + + >>> SeqPer((1, 2, 3), (-10, 10))._ith_point(0) + -10 + >>> SeqPer((1, 2, 3), (-10, 10))._ith_point(5) + -5 + + End is at infinity + + >>> SeqPer((1, 2, 3), (0, oo))._ith_point(5) + 5 + + Starts at negative infinity + + >>> SeqPer((1, 2, 3), (-oo, 0))._ith_point(5) + -5 + """ + if self.start is S.NegativeInfinity: + initial = self.stop + else: + initial = self.start + + if self.start is S.NegativeInfinity: + step = -1 + else: + step = 1 + + return initial + i*step + + def _add(self, other): + """ + Should only be used internally. + + Explanation + =========== + + self._add(other) returns a new, term-wise added sequence if self + knows how to add with other, otherwise it returns ``None``. + + ``other`` should only be a sequence object. + + Used within :class:`SeqAdd` class. + """ + return None + + def _mul(self, other): + """ + Should only be used internally. + + Explanation + =========== + + self._mul(other) returns a new, term-wise multiplied sequence if self + knows how to multiply with other, otherwise it returns ``None``. + + ``other`` should only be a sequence object. + + Used within :class:`SeqMul` class. + """ + return None + + def coeff_mul(self, other): + """ + Should be used when ``other`` is not a sequence. Should be + defined to define custom behaviour. + + Examples + ======== + + >>> from sympy import SeqFormula + >>> from sympy.abc import n + >>> SeqFormula(n**2).coeff_mul(2) + SeqFormula(2*n**2, (n, 0, oo)) + + Notes + ===== + + '*' defines multiplication of sequences with sequences only. + """ + return Mul(self, other) + + def __add__(self, other): + """Returns the term-wise addition of 'self' and 'other'. + + ``other`` should be a sequence. + + Examples + ======== + + >>> from sympy import SeqFormula + >>> from sympy.abc import n + >>> SeqFormula(n**2) + SeqFormula(n**3) + SeqFormula(n**3 + n**2, (n, 0, oo)) + """ + if not isinstance(other, SeqBase): + raise TypeError('cannot add sequence and %s' % type(other)) + return SeqAdd(self, other) + + @call_highest_priority('__add__') + def __radd__(self, other): + return self + other + + def __sub__(self, other): + """Returns the term-wise subtraction of ``self`` and ``other``. + + ``other`` should be a sequence. + + Examples + ======== + + >>> from sympy import SeqFormula + >>> from sympy.abc import n + >>> SeqFormula(n**2) - (SeqFormula(n)) + SeqFormula(n**2 - n, (n, 0, oo)) + """ + if not isinstance(other, SeqBase): + raise TypeError('cannot subtract sequence and %s' % type(other)) + return SeqAdd(self, -other) + + @call_highest_priority('__sub__') + def __rsub__(self, other): + return (-self) + other + + def __neg__(self): + """Negates the sequence. + + Examples + ======== + + >>> from sympy import SeqFormula + >>> from sympy.abc import n + >>> -SeqFormula(n**2) + SeqFormula(-n**2, (n, 0, oo)) + """ + return self.coeff_mul(-1) + + def __mul__(self, other): + """Returns the term-wise multiplication of 'self' and 'other'. + + ``other`` should be a sequence. For ``other`` not being a + sequence see :func:`coeff_mul` method. + + Examples + ======== + + >>> from sympy import SeqFormula + >>> from sympy.abc import n + >>> SeqFormula(n**2) * (SeqFormula(n)) + SeqFormula(n**3, (n, 0, oo)) + """ + if not isinstance(other, SeqBase): + raise TypeError('cannot multiply sequence and %s' % type(other)) + return SeqMul(self, other) + + @call_highest_priority('__mul__') + def __rmul__(self, other): + return self * other + + def __iter__(self): + for i in range(self.length): + pt = self._ith_point(i) + yield self.coeff(pt) + + def __getitem__(self, index): + if isinstance(index, int): + index = self._ith_point(index) + return self.coeff(index) + elif isinstance(index, slice): + start, stop = index.start, index.stop + if start is None: + start = 0 + if stop is None: + stop = self.length + return [self.coeff(self._ith_point(i)) for i in + range(start, stop, index.step or 1)] + + def find_linear_recurrence(self,n,d=None,gfvar=None): + r""" + Finds the shortest linear recurrence that satisfies the first n + terms of sequence of order `\leq` ``n/2`` if possible. + If ``d`` is specified, find shortest linear recurrence of order + `\leq` min(d, n/2) if possible. + Returns list of coefficients ``[b(1), b(2), ...]`` corresponding to the + recurrence relation ``x(n) = b(1)*x(n-1) + b(2)*x(n-2) + ...`` + Returns ``[]`` if no recurrence is found. + If gfvar is specified, also returns ordinary generating function as a + function of gfvar. + + Examples + ======== + + >>> from sympy import sequence, sqrt, oo, lucas + >>> from sympy.abc import n, x, y + >>> sequence(n**2).find_linear_recurrence(10, 2) + [] + >>> sequence(n**2).find_linear_recurrence(10) + [3, -3, 1] + >>> sequence(2**n).find_linear_recurrence(10) + [2] + >>> sequence(23*n**4+91*n**2).find_linear_recurrence(10) + [5, -10, 10, -5, 1] + >>> sequence(sqrt(5)*(((1 + sqrt(5))/2)**n - (-(1 + sqrt(5))/2)**(-n))/5).find_linear_recurrence(10) + [1, 1] + >>> sequence(x+y*(-2)**(-n), (n, 0, oo)).find_linear_recurrence(30) + [1/2, 1/2] + >>> sequence(3*5**n + 12).find_linear_recurrence(20,gfvar=x) + ([6, -5], 3*(5 - 21*x)/((x - 1)*(5*x - 1))) + >>> sequence(lucas(n)).find_linear_recurrence(15,gfvar=x) + ([1, 1], (x - 2)/(x**2 + x - 1)) + """ + from sympy.simplify import simplify + x = [simplify(expand(t)) for t in self[:n]] + lx = len(x) + if d is None: + r = lx//2 + else: + r = min(d,lx//2) + coeffs = [] + for l in range(1, r+1): + l2 = 2*l + mlist = [] + for k in range(l): + mlist.append(x[k:k+l]) + m = Matrix(mlist) + if m.det() != 0: + y = simplify(m.LUsolve(Matrix(x[l:l2]))) + if lx == l2: + coeffs = flatten(y[::-1]) + break + mlist = [] + for k in range(l,lx-l): + mlist.append(x[k:k+l]) + m = Matrix(mlist) + if m*y == Matrix(x[l2:]): + coeffs = flatten(y[::-1]) + break + if gfvar is None: + return coeffs + else: + l = len(coeffs) + if l == 0: + return [], None + else: + n, d = x[l-1]*gfvar**(l-1), 1 - coeffs[l-1]*gfvar**l + for i in range(l-1): + n += x[i]*gfvar**i + for j in range(l-i-1): + n -= coeffs[i]*x[j]*gfvar**(i+j+1) + d -= coeffs[i]*gfvar**(i+1) + return coeffs, simplify(factor(n)/factor(d)) + +class EmptySequence(SeqBase, metaclass=Singleton): + """Represents an empty sequence. + + The empty sequence is also available as a singleton as + ``S.EmptySequence``. + + Examples + ======== + + >>> from sympy import EmptySequence, SeqPer + >>> from sympy.abc import x + >>> EmptySequence + EmptySequence + >>> SeqPer((1, 2), (x, 0, 10)) + EmptySequence + SeqPer((1, 2), (x, 0, 10)) + >>> SeqPer((1, 2)) * EmptySequence + EmptySequence + >>> EmptySequence.coeff_mul(-1) + EmptySequence + """ + + @property + def interval(self): + return S.EmptySet + + @property + def length(self): + return S.Zero + + def coeff_mul(self, coeff): + """See docstring of SeqBase.coeff_mul""" + return self + + def __iter__(self): + return iter([]) + + +class SeqExpr(SeqBase): + """Sequence expression class. + + Various sequences should inherit from this class. + + Examples + ======== + + >>> from sympy.series.sequences import SeqExpr + >>> from sympy.abc import x + >>> from sympy import Tuple + >>> s = SeqExpr(Tuple(1, 2, 3), Tuple(x, 0, 10)) + >>> s.gen + (1, 2, 3) + >>> s.interval + Interval(0, 10) + >>> s.length + 11 + + See Also + ======== + + sympy.series.sequences.SeqPer + sympy.series.sequences.SeqFormula + """ + + @property + def gen(self): + return self.args[0] + + @property + def interval(self): + return Interval(self.args[1][1], self.args[1][2]) + + @property + def start(self): + return self.interval.inf + + @property + def stop(self): + return self.interval.sup + + @property + def length(self): + return self.stop - self.start + 1 + + @property + def variables(self): + return (self.args[1][0],) + + +class SeqPer(SeqExpr): + """ + Represents a periodic sequence. + + The elements are repeated after a given period. + + Examples + ======== + + >>> from sympy import SeqPer, oo + >>> from sympy.abc import k + + >>> s = SeqPer((1, 2, 3), (0, 5)) + >>> s.periodical + (1, 2, 3) + >>> s.period + 3 + + For value at a particular point + + >>> s.coeff(3) + 1 + + supports slicing + + >>> s[:] + [1, 2, 3, 1, 2, 3] + + iterable + + >>> list(s) + [1, 2, 3, 1, 2, 3] + + sequence starts from negative infinity + + >>> SeqPer((1, 2, 3), (-oo, 0))[0:6] + [1, 2, 3, 1, 2, 3] + + Periodic formulas + + >>> SeqPer((k, k**2, k**3), (k, 0, oo))[0:6] + [0, 1, 8, 3, 16, 125] + + See Also + ======== + + sympy.series.sequences.SeqFormula + """ + + def __new__(cls, periodical, limits=None): + periodical = sympify(periodical) + + def _find_x(periodical): + free = periodical.free_symbols + if len(periodical.free_symbols) == 1: + return free.pop() + else: + return Dummy('k') + + x, start, stop = None, None, None + if limits is None: + x, start, stop = _find_x(periodical), 0, S.Infinity + if is_sequence(limits, Tuple): + if len(limits) == 3: + x, start, stop = limits + elif len(limits) == 2: + x = _find_x(periodical) + start, stop = limits + + if not isinstance(x, (Symbol, Idx)) or start is None or stop is None: + raise ValueError('Invalid limits given: %s' % str(limits)) + + if start is S.NegativeInfinity and stop is S.Infinity: + raise ValueError("Both the start and end value" + "cannot be unbounded") + + limits = sympify((x, start, stop)) + + if is_sequence(periodical, Tuple): + periodical = sympify(tuple(flatten(periodical))) + else: + raise ValueError("invalid period %s should be something " + "like e.g (1, 2) " % periodical) + + if Interval(limits[1], limits[2]) is S.EmptySet: + return S.EmptySequence + + return Basic.__new__(cls, periodical, limits) + + @property + def period(self): + return len(self.gen) + + @property + def periodical(self): + return self.gen + + def _eval_coeff(self, pt): + if self.start is S.NegativeInfinity: + idx = (self.stop - pt) % self.period + else: + idx = (pt - self.start) % self.period + return self.periodical[idx].subs(self.variables[0], pt) + + def _add(self, other): + """See docstring of SeqBase._add""" + if isinstance(other, SeqPer): + per1, lper1 = self.periodical, self.period + per2, lper2 = other.periodical, other.period + + per_length = lcm(lper1, lper2) + + new_per = [] + for x in range(per_length): + ele1 = per1[x % lper1] + ele2 = per2[x % lper2] + new_per.append(ele1 + ele2) + + start, stop = self._intersect_interval(other) + return SeqPer(new_per, (self.variables[0], start, stop)) + + def _mul(self, other): + """See docstring of SeqBase._mul""" + if isinstance(other, SeqPer): + per1, lper1 = self.periodical, self.period + per2, lper2 = other.periodical, other.period + + per_length = lcm(lper1, lper2) + + new_per = [] + for x in range(per_length): + ele1 = per1[x % lper1] + ele2 = per2[x % lper2] + new_per.append(ele1 * ele2) + + start, stop = self._intersect_interval(other) + return SeqPer(new_per, (self.variables[0], start, stop)) + + def coeff_mul(self, coeff): + """See docstring of SeqBase.coeff_mul""" + coeff = sympify(coeff) + per = [x * coeff for x in self.periodical] + return SeqPer(per, self.args[1]) + + +class SeqFormula(SeqExpr): + """ + Represents sequence based on a formula. + + Elements are generated using a formula. + + Examples + ======== + + >>> from sympy import SeqFormula, oo, Symbol + >>> n = Symbol('n') + >>> s = SeqFormula(n**2, (n, 0, 5)) + >>> s.formula + n**2 + + For value at a particular point + + >>> s.coeff(3) + 9 + + supports slicing + + >>> s[:] + [0, 1, 4, 9, 16, 25] + + iterable + + >>> list(s) + [0, 1, 4, 9, 16, 25] + + sequence starts from negative infinity + + >>> SeqFormula(n**2, (-oo, 0))[0:6] + [0, 1, 4, 9, 16, 25] + + See Also + ======== + + sympy.series.sequences.SeqPer + """ + + def __new__(cls, formula, limits=None): + formula = sympify(formula) + + def _find_x(formula): + free = formula.free_symbols + if len(free) == 1: + return free.pop() + elif not free: + return Dummy('k') + else: + raise ValueError( + " specify dummy variables for %s. If the formula contains" + " more than one free symbol, a dummy variable should be" + " supplied explicitly e.g., SeqFormula(m*n**2, (n, 0, 5))" + % formula) + + x, start, stop = None, None, None + if limits is None: + x, start, stop = _find_x(formula), 0, S.Infinity + if is_sequence(limits, Tuple): + if len(limits) == 3: + x, start, stop = limits + elif len(limits) == 2: + x = _find_x(formula) + start, stop = limits + + if not isinstance(x, (Symbol, Idx)) or start is None or stop is None: + raise ValueError('Invalid limits given: %s' % str(limits)) + + if start is S.NegativeInfinity and stop is S.Infinity: + raise ValueError("Both the start and end value " + "cannot be unbounded") + limits = sympify((x, start, stop)) + + if Interval(limits[1], limits[2]) is S.EmptySet: + return S.EmptySequence + + return Basic.__new__(cls, formula, limits) + + @property + def formula(self): + return self.gen + + def _eval_coeff(self, pt): + d = self.variables[0] + return self.formula.subs(d, pt) + + def _add(self, other): + """See docstring of SeqBase._add""" + if isinstance(other, SeqFormula): + form1, v1 = self.formula, self.variables[0] + form2, v2 = other.formula, other.variables[0] + formula = form1 + form2.subs(v2, v1) + start, stop = self._intersect_interval(other) + return SeqFormula(formula, (v1, start, stop)) + + def _mul(self, other): + """See docstring of SeqBase._mul""" + if isinstance(other, SeqFormula): + form1, v1 = self.formula, self.variables[0] + form2, v2 = other.formula, other.variables[0] + formula = form1 * form2.subs(v2, v1) + start, stop = self._intersect_interval(other) + return SeqFormula(formula, (v1, start, stop)) + + def coeff_mul(self, coeff): + """See docstring of SeqBase.coeff_mul""" + coeff = sympify(coeff) + formula = self.formula * coeff + return SeqFormula(formula, self.args[1]) + + def expand(self, *args, **kwargs): + return SeqFormula(expand(self.formula, *args, **kwargs), self.args[1]) + +class RecursiveSeq(SeqBase): + """ + A finite degree recursive sequence. + + Explanation + =========== + + That is, a sequence a(n) that depends on a fixed, finite number of its + previous values. The general form is + + a(n) = f(a(n - 1), a(n - 2), ..., a(n - d)) + + for some fixed, positive integer d, where f is some function defined by a + SymPy expression. + + Parameters + ========== + + recurrence : SymPy expression defining recurrence + This is *not* an equality, only the expression that the nth term is + equal to. For example, if :code:`a(n) = f(a(n - 1), ..., a(n - d))`, + then the expression should be :code:`f(a(n - 1), ..., a(n - d))`. + + yn : applied undefined function + Represents the nth term of the sequence as e.g. :code:`y(n)` where + :code:`y` is an undefined function and `n` is the sequence index. + + n : symbolic argument + The name of the variable that the recurrence is in, e.g., :code:`n` if + the recurrence function is :code:`y(n)`. + + initial : iterable with length equal to the degree of the recurrence + The initial values of the recurrence. + + start : start value of sequence (inclusive) + + Examples + ======== + + >>> from sympy import Function, symbols + >>> from sympy.series.sequences import RecursiveSeq + >>> y = Function("y") + >>> n = symbols("n") + >>> fib = RecursiveSeq(y(n - 1) + y(n - 2), y(n), n, [0, 1]) + + >>> fib.coeff(3) # Value at a particular point + 2 + + >>> fib[:6] # supports slicing + [0, 1, 1, 2, 3, 5] + + >>> fib.recurrence # inspect recurrence + Eq(y(n), y(n - 2) + y(n - 1)) + + >>> fib.degree # automatically determine degree + 2 + + >>> for x in zip(range(10), fib): # supports iteration + ... print(x) + (0, 0) + (1, 1) + (2, 1) + (3, 2) + (4, 3) + (5, 5) + (6, 8) + (7, 13) + (8, 21) + (9, 34) + + See Also + ======== + + sympy.series.sequences.SeqFormula + + """ + + def __new__(cls, recurrence, yn, n, initial=None, start=0): + if not isinstance(yn, AppliedUndef): + raise TypeError("recurrence sequence must be an applied undefined function" + ", found `{}`".format(yn)) + + if not isinstance(n, Basic) or not n.is_symbol: + raise TypeError("recurrence variable must be a symbol" + ", found `{}`".format(n)) + + if yn.args != (n,): + raise TypeError("recurrence sequence does not match symbol") + + y = yn.func + + k = Wild("k", exclude=(n,)) + degree = 0 + + # Find all applications of y in the recurrence and check that: + # 1. The function y is only being used with a single argument; and + # 2. All arguments are n + k for constant negative integers k. + + prev_ys = recurrence.find(y) + for prev_y in prev_ys: + if len(prev_y.args) != 1: + raise TypeError("Recurrence should be in a single variable") + + shift = prev_y.args[0].match(n + k)[k] + if not (shift.is_constant() and shift.is_integer and shift < 0): + raise TypeError("Recurrence should have constant," + " negative, integer shifts" + " (found {})".format(prev_y)) + + if -shift > degree: + degree = -shift + + if not initial: + initial = [Dummy("c_{}".format(k)) for k in range(degree)] + + if len(initial) != degree: + raise ValueError("Number of initial terms must equal degree") + + degree = Integer(degree) + start = sympify(start) + + initial = Tuple(*(sympify(x) for x in initial)) + + seq = Basic.__new__(cls, recurrence, yn, n, initial, start) + + seq.cache = {y(start + k): init for k, init in enumerate(initial)} + seq.degree = degree + + return seq + + @property + def _recurrence(self): + """Equation defining recurrence.""" + return self.args[0] + + @property + def recurrence(self): + """Equation defining recurrence.""" + return Eq(self.yn, self.args[0]) + + @property + def yn(self): + """Applied function representing the nth term""" + return self.args[1] + + @property + def y(self): + """Undefined function for the nth term of the sequence""" + return self.yn.func + + @property + def n(self): + """Sequence index symbol""" + return self.args[2] + + @property + def initial(self): + """The initial values of the sequence""" + return self.args[3] + + @property + def start(self): + """The starting point of the sequence. This point is included""" + return self.args[4] + + @property + def stop(self): + """The ending point of the sequence. (oo)""" + return S.Infinity + + @property + def interval(self): + """Interval on which sequence is defined.""" + return (self.start, S.Infinity) + + def _eval_coeff(self, index): + if index - self.start < len(self.cache): + return self.cache[self.y(index)] + + for current in range(len(self.cache), index + 1): + # Use xreplace over subs for performance. + # See issue #10697. + seq_index = self.start + current + current_recurrence = self._recurrence.xreplace({self.n: seq_index}) + new_term = current_recurrence.xreplace(self.cache) + + self.cache[self.y(seq_index)] = new_term + + return self.cache[self.y(self.start + current)] + + def __iter__(self): + index = self.start + while True: + yield self._eval_coeff(index) + index += 1 + + +def sequence(seq, limits=None): + """ + Returns appropriate sequence object. + + Explanation + =========== + + If ``seq`` is a SymPy sequence, returns :class:`SeqPer` object + otherwise returns :class:`SeqFormula` object. + + Examples + ======== + + >>> from sympy import sequence + >>> from sympy.abc import n + >>> sequence(n**2, (n, 0, 5)) + SeqFormula(n**2, (n, 0, 5)) + >>> sequence((1, 2, 3), (n, 0, 5)) + SeqPer((1, 2, 3), (n, 0, 5)) + + See Also + ======== + + sympy.series.sequences.SeqPer + sympy.series.sequences.SeqFormula + """ + seq = sympify(seq) + + if is_sequence(seq, Tuple): + return SeqPer(seq, limits) + else: + return SeqFormula(seq, limits) + + +############################################################################### +# OPERATIONS # +############################################################################### + + +class SeqExprOp(SeqBase): + """ + Base class for operations on sequences. + + Examples + ======== + + >>> from sympy.series.sequences import SeqExprOp, sequence + >>> from sympy.abc import n + >>> s1 = sequence(n**2, (n, 0, 10)) + >>> s2 = sequence((1, 2, 3), (n, 5, 10)) + >>> s = SeqExprOp(s1, s2) + >>> s.gen + (n**2, (1, 2, 3)) + >>> s.interval + Interval(5, 10) + >>> s.length + 6 + + See Also + ======== + + sympy.series.sequences.SeqAdd + sympy.series.sequences.SeqMul + """ + @property + def gen(self): + """Generator for the sequence. + + returns a tuple of generators of all the argument sequences. + """ + return tuple(a.gen for a in self.args) + + @property + def interval(self): + """Sequence is defined on the intersection + of all the intervals of respective sequences + """ + return Intersection(*(a.interval for a in self.args)) + + @property + def start(self): + return self.interval.inf + + @property + def stop(self): + return self.interval.sup + + @property + def variables(self): + """Cumulative of all the bound variables""" + return tuple(flatten([a.variables for a in self.args])) + + @property + def length(self): + return self.stop - self.start + 1 + + +class SeqAdd(SeqExprOp): + """Represents term-wise addition of sequences. + + Rules: + * The interval on which sequence is defined is the intersection + of respective intervals of sequences. + * Anything + :class:`EmptySequence` remains unchanged. + * Other rules are defined in ``_add`` methods of sequence classes. + + Examples + ======== + + >>> from sympy import EmptySequence, oo, SeqAdd, SeqPer, SeqFormula + >>> from sympy.abc import n + >>> SeqAdd(SeqPer((1, 2), (n, 0, oo)), EmptySequence) + SeqPer((1, 2), (n, 0, oo)) + >>> SeqAdd(SeqPer((1, 2), (n, 0, 5)), SeqPer((1, 2), (n, 6, 10))) + EmptySequence + >>> SeqAdd(SeqPer((1, 2), (n, 0, oo)), SeqFormula(n**2, (n, 0, oo))) + SeqAdd(SeqFormula(n**2, (n, 0, oo)), SeqPer((1, 2), (n, 0, oo))) + >>> SeqAdd(SeqFormula(n**3), SeqFormula(n**2)) + SeqFormula(n**3 + n**2, (n, 0, oo)) + + See Also + ======== + + sympy.series.sequences.SeqMul + """ + + def __new__(cls, *args, **kwargs): + evaluate = kwargs.get('evaluate', global_parameters.evaluate) + + # flatten inputs + args = list(args) + + # adapted from sympy.sets.sets.Union + def _flatten(arg): + if isinstance(arg, SeqBase): + if isinstance(arg, SeqAdd): + return sum(map(_flatten, arg.args), []) + else: + return [arg] + if iterable(arg): + return sum(map(_flatten, arg), []) + raise TypeError("Input must be Sequences or " + " iterables of Sequences") + args = _flatten(args) + + args = [a for a in args if a is not S.EmptySequence] + + # Addition of no sequences is EmptySequence + if not args: + return S.EmptySequence + + if Intersection(*(a.interval for a in args)) is S.EmptySet: + return S.EmptySequence + + # reduce using known rules + if evaluate: + return SeqAdd.reduce(args) + + args = list(ordered(args, SeqBase._start_key)) + + return Basic.__new__(cls, *args) + + @staticmethod + def reduce(args): + """Simplify :class:`SeqAdd` using known rules. + + Iterates through all pairs and ask the constituent + sequences if they can simplify themselves with any other constituent. + + Notes + ===== + + adapted from ``Union.reduce`` + + """ + new_args = True + while new_args: + for id1, s in enumerate(args): + new_args = False + for id2, t in enumerate(args): + if id1 == id2: + continue + new_seq = s._add(t) + # This returns None if s does not know how to add + # with t. Returns the newly added sequence otherwise + if new_seq is not None: + new_args = [a for a in args if a not in (s, t)] + new_args.append(new_seq) + break + if new_args: + args = new_args + break + + if len(args) == 1: + return args.pop() + else: + return SeqAdd(args, evaluate=False) + + def _eval_coeff(self, pt): + """adds up the coefficients of all the sequences at point pt""" + return sum(a.coeff(pt) for a in self.args) + + +class SeqMul(SeqExprOp): + r"""Represents term-wise multiplication of sequences. + + Explanation + =========== + + Handles multiplication of sequences only. For multiplication + with other objects see :func:`SeqBase.coeff_mul`. + + Rules: + * The interval on which sequence is defined is the intersection + of respective intervals of sequences. + * Anything \* :class:`EmptySequence` returns :class:`EmptySequence`. + * Other rules are defined in ``_mul`` methods of sequence classes. + + Examples + ======== + + >>> from sympy import EmptySequence, oo, SeqMul, SeqPer, SeqFormula + >>> from sympy.abc import n + >>> SeqMul(SeqPer((1, 2), (n, 0, oo)), EmptySequence) + EmptySequence + >>> SeqMul(SeqPer((1, 2), (n, 0, 5)), SeqPer((1, 2), (n, 6, 10))) + EmptySequence + >>> SeqMul(SeqPer((1, 2), (n, 0, oo)), SeqFormula(n**2)) + SeqMul(SeqFormula(n**2, (n, 0, oo)), SeqPer((1, 2), (n, 0, oo))) + >>> SeqMul(SeqFormula(n**3), SeqFormula(n**2)) + SeqFormula(n**5, (n, 0, oo)) + + See Also + ======== + + sympy.series.sequences.SeqAdd + """ + + def __new__(cls, *args, **kwargs): + evaluate = kwargs.get('evaluate', global_parameters.evaluate) + + # flatten inputs + args = list(args) + + # adapted from sympy.sets.sets.Union + def _flatten(arg): + if isinstance(arg, SeqBase): + if isinstance(arg, SeqMul): + return sum(map(_flatten, arg.args), []) + else: + return [arg] + elif iterable(arg): + return sum(map(_flatten, arg), []) + raise TypeError("Input must be Sequences or " + " iterables of Sequences") + args = _flatten(args) + + # Multiplication of no sequences is EmptySequence + if not args: + return S.EmptySequence + + if Intersection(*(a.interval for a in args)) is S.EmptySet: + return S.EmptySequence + + # reduce using known rules + if evaluate: + return SeqMul.reduce(args) + + args = list(ordered(args, SeqBase._start_key)) + + return Basic.__new__(cls, *args) + + @staticmethod + def reduce(args): + """Simplify a :class:`SeqMul` using known rules. + + Explanation + =========== + + Iterates through all pairs and ask the constituent + sequences if they can simplify themselves with any other constituent. + + Notes + ===== + + adapted from ``Union.reduce`` + + """ + new_args = True + while new_args: + for id1, s in enumerate(args): + new_args = False + for id2, t in enumerate(args): + if id1 == id2: + continue + new_seq = s._mul(t) + # This returns None if s does not know how to multiply + # with t. Returns the newly multiplied sequence otherwise + if new_seq is not None: + new_args = [a for a in args if a not in (s, t)] + new_args.append(new_seq) + break + if new_args: + args = new_args + break + + if len(args) == 1: + return args.pop() + else: + return SeqMul(args, evaluate=False) + + def _eval_coeff(self, pt): + """multiplies the coefficients of all the sequences at point pt""" + val = 1 + for a in self.args: + val *= a.coeff(pt) + return val diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/series.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/series.py new file mode 100644 index 0000000000000000000000000000000000000000..e9feec7d3b1987bfaa5238969f531e9f98b88b25 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/series.py @@ -0,0 +1,63 @@ +from sympy.core.sympify import sympify + + +def series(expr, x=None, x0=0, n=6, dir="+"): + """Series expansion of expr around point `x = x0`. + + Parameters + ========== + + expr : Expression + The expression whose series is to be expanded. + + x : Symbol + It is the variable of the expression to be calculated. + + x0 : Value + The value around which ``x`` is calculated. Can be any value + from ``-oo`` to ``oo``. + + n : Value + The number of terms upto which the series is to be expanded. + + dir : String, optional + The series-expansion can be bi-directional. If ``dir="+"``, + then (x->x0+). If ``dir="-"``, then (x->x0-). For infinite + ``x0`` (``oo`` or ``-oo``), the ``dir`` argument is determined + from the direction of the infinity (i.e., ``dir="-"`` for + ``oo``). + + Examples + ======== + + >>> from sympy import series, tan, oo + >>> from sympy.abc import x + >>> f = tan(x) + >>> series(f, x, 2, 6, "+") + tan(2) + (1 + tan(2)**2)*(x - 2) + (x - 2)**2*(tan(2)**3 + tan(2)) + + (x - 2)**3*(1/3 + 4*tan(2)**2/3 + tan(2)**4) + (x - 2)**4*(tan(2)**5 + + 5*tan(2)**3/3 + 2*tan(2)/3) + (x - 2)**5*(2/15 + 17*tan(2)**2/15 + + 2*tan(2)**4 + tan(2)**6) + O((x - 2)**6, (x, 2)) + + >>> series(f, x, 2, 3, "-") + tan(2) + (2 - x)*(-tan(2)**2 - 1) + (2 - x)**2*(tan(2)**3 + tan(2)) + + O((x - 2)**3, (x, 2)) + + >>> series(f, x, 2, oo, "+") + Traceback (most recent call last): + ... + TypeError: 'Infinity' object cannot be interpreted as an integer + + Returns + ======= + + Expr + Series expansion of the expression about x0 + + See Also + ======== + + sympy.core.expr.Expr.series: See the docstring of Expr.series() for complete details of this wrapper. + """ + expr = sympify(expr) + return expr.series(x, x0, n, dir) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/series_class.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/series_class.py new file mode 100644 index 0000000000000000000000000000000000000000..ff04993b266a3cbd3f767042d4325fb11edb2168 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/series/series_class.py @@ -0,0 +1,99 @@ +""" +Contains the base class for series +Made using sequences in mind +""" + +from sympy.core.expr import Expr +from sympy.core.singleton import S +from sympy.core.cache import cacheit + + +class SeriesBase(Expr): + """Base Class for series""" + + @property + def interval(self): + """The interval on which the series is defined""" + raise NotImplementedError("(%s).interval" % self) + + @property + def start(self): + """The starting point of the series. This point is included""" + raise NotImplementedError("(%s).start" % self) + + @property + def stop(self): + """The ending point of the series. This point is included""" + raise NotImplementedError("(%s).stop" % self) + + @property + def length(self): + """Length of the series expansion""" + raise NotImplementedError("(%s).length" % self) + + @property + def variables(self): + """Returns a tuple of variables that are bounded""" + return () + + @property + def free_symbols(self): + """ + This method returns the symbols in the object, excluding those + that take on a specific value (i.e. the dummy symbols). + """ + return ({j for i in self.args for j in i.free_symbols} + .difference(self.variables)) + + @cacheit + def term(self, pt): + """Term at point pt of a series""" + if pt < self.start or pt > self.stop: + raise IndexError("Index %s out of bounds %s" % (pt, self.interval)) + return self._eval_term(pt) + + def _eval_term(self, pt): + raise NotImplementedError("The _eval_term method should be added to" + "%s to return series term so it is available" + "when 'term' calls it." + % self.func) + + def _ith_point(self, i): + """ + Returns the i'th point of a series + If start point is negative infinity, point is returned from the end. + Assumes the first point to be indexed zero. + + Examples + ======== + + TODO + """ + if self.start is S.NegativeInfinity: + initial = self.stop + step = -1 + else: + initial = self.start + step = 1 + + return initial + i*step + + def __iter__(self): + i = 0 + while i < self.length: + pt = self._ith_point(i) + yield self.term(pt) + i += 1 + + def __getitem__(self, index): + if isinstance(index, int): + index = self._ith_point(index) + return self.term(index) + elif isinstance(index, slice): + start, stop = index.start, index.stop + if start is None: + start = 0 + if stop is None: + stop = self.length + return [self.term(self._ith_point(i)) for i in + range(start, stop, index.step or 1)] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b909c0b5ef03b1e1e76dfbf4288f61860575da7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/__init__.py @@ -0,0 +1,36 @@ +from .sets import (Set, Interval, Union, FiniteSet, ProductSet, + Intersection, imageset, Complement, SymmetricDifference, + DisjointUnion) + +from .fancysets import ImageSet, Range, ComplexRegion +from .contains import Contains +from .conditionset import ConditionSet +from .ordinals import Ordinal, OmegaPower, ord0 +from .powerset import PowerSet +from ..core.singleton import S +from .handlers.comparison import _eval_is_eq # noqa:F401 +Complexes = S.Complexes +EmptySet = S.EmptySet +Integers = S.Integers +Naturals = S.Naturals +Naturals0 = S.Naturals0 +Rationals = S.Rationals +Reals = S.Reals +UniversalSet = S.UniversalSet + +__all__ = [ + 'Set', 'Interval', 'Union', 'EmptySet', 'FiniteSet', 'ProductSet', + 'Intersection', 'imageset', 'Complement', 'SymmetricDifference', 'DisjointUnion', + + 'ImageSet', 'Range', 'ComplexRegion', 'Reals', + + 'Contains', + + 'ConditionSet', + + 'Ordinal', 'OmegaPower', 'ord0', + + 'PowerSet', + + 'Reals', 'Naturals', 'Naturals0', 'UniversalSet', 'Integers', 'Rationals', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/conditionset.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/conditionset.py new file mode 100644 index 0000000000000000000000000000000000000000..e847e60ce97d7e9922ce907042ace941838b0ab1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/conditionset.py @@ -0,0 +1,246 @@ +from sympy.core.singleton import S +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.function import Lambda, BadSignatureError +from sympy.core.logic import fuzzy_bool +from sympy.core.relational import Eq +from sympy.core.symbol import Dummy +from sympy.core.sympify import _sympify +from sympy.logic.boolalg import And, as_Boolean +from sympy.utilities.iterables import sift, flatten, has_dups +from sympy.utilities.exceptions import sympy_deprecation_warning +from .contains import Contains +from .sets import Set, Union, FiniteSet, SetKind + + +adummy = Dummy('conditionset') + + +class ConditionSet(Set): + r""" + Set of elements which satisfies a given condition. + + .. math:: \{x \mid \textrm{condition}(x) = \texttt{True}, x \in S\} + + Examples + ======== + + >>> from sympy import Symbol, S, ConditionSet, pi, Eq, sin, Interval + >>> from sympy.abc import x, y, z + + >>> sin_sols = ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi)) + >>> 2*pi in sin_sols + True + >>> pi/2 in sin_sols + False + >>> 3*pi in sin_sols + False + >>> 5 in ConditionSet(x, x**2 > 4, S.Reals) + True + + If the value is not in the base set, the result is false: + + >>> 5 in ConditionSet(x, x**2 > 4, Interval(2, 4)) + False + + Notes + ===== + + Symbols with assumptions should be avoided or else the + condition may evaluate without consideration of the set: + + >>> n = Symbol('n', negative=True) + >>> cond = (n > 0); cond + False + >>> ConditionSet(n, cond, S.Integers) + EmptySet + + Only free symbols can be changed by using `subs`: + + >>> c = ConditionSet(x, x < 1, {x, z}) + >>> c.subs(x, y) + ConditionSet(x, x < 1, {y, z}) + + To check if ``pi`` is in ``c`` use: + + >>> pi in c + False + + If no base set is specified, the universal set is implied: + + >>> ConditionSet(x, x < 1).base_set + UniversalSet + + Only symbols or symbol-like expressions can be used: + + >>> ConditionSet(x + 1, x + 1 < 1, S.Integers) + Traceback (most recent call last): + ... + ValueError: non-symbol dummy not recognized in condition + + When the base set is a ConditionSet, the symbols will be + unified if possible with preference for the outermost symbols: + + >>> ConditionSet(x, x < y, ConditionSet(z, z + y < 2, S.Integers)) + ConditionSet(x, (x < y) & (x + y < 2), Integers) + + """ + def __new__(cls, sym, condition, base_set=S.UniversalSet): + sym = _sympify(sym) + flat = flatten([sym]) + if has_dups(flat): + raise BadSignatureError("Duplicate symbols detected") + base_set = _sympify(base_set) + if not isinstance(base_set, Set): + raise TypeError( + 'base set should be a Set object, not %s' % base_set) + condition = _sympify(condition) + + if isinstance(condition, FiniteSet): + condition_orig = condition + temp = (Eq(lhs, 0) for lhs in condition) + condition = And(*temp) + sympy_deprecation_warning( + f""" +Using a set for the condition in ConditionSet is deprecated. Use a boolean +instead. + +In this case, replace + + {condition_orig} + +with + + {condition} +""", + deprecated_since_version='1.5', + active_deprecations_target="deprecated-conditionset-set", + ) + + condition = as_Boolean(condition) + + if condition is S.true: + return base_set + + if condition is S.false: + return S.EmptySet + + if base_set is S.EmptySet: + return S.EmptySet + + # no simple answers, so now check syms + for i in flat: + if not getattr(i, '_diff_wrt', False): + raise ValueError('`%s` is not symbol-like' % i) + + if base_set.contains(sym) is S.false: + raise TypeError('sym `%s` is not in base_set `%s`' % (sym, base_set)) + + know = None + if isinstance(base_set, FiniteSet): + sifted = sift( + base_set, lambda _: fuzzy_bool(condition.subs(sym, _))) + if sifted[None]: + know = FiniteSet(*sifted[True]) + base_set = FiniteSet(*sifted[None]) + else: + return FiniteSet(*sifted[True]) + + if isinstance(base_set, cls): + s, c, b = base_set.args + def sig(s): + return cls(s, Eq(adummy, 0)).as_dummy().sym + sa, sb = map(sig, (sym, s)) + if sa != sb: + raise BadSignatureError('sym does not match sym of base set') + reps = dict(zip(flatten([sym]), flatten([s]))) + if s == sym: + condition = And(condition, c) + base_set = b + elif not c.free_symbols & sym.free_symbols: + reps = {v: k for k, v in reps.items()} + condition = And(condition, c.xreplace(reps)) + base_set = b + elif not condition.free_symbols & s.free_symbols: + sym = sym.xreplace(reps) + condition = And(condition.xreplace(reps), c) + base_set = b + + # flatten ConditionSet(Contains(ConditionSet())) expressions + if isinstance(condition, Contains) and (sym == condition.args[0]): + if isinstance(condition.args[1], Set): + return condition.args[1].intersect(base_set) + + rv = Basic.__new__(cls, sym, condition, base_set) + return rv if know is None else Union(know, rv) + + sym = property(lambda self: self.args[0]) + condition = property(lambda self: self.args[1]) + base_set = property(lambda self: self.args[2]) + + @property + def free_symbols(self): + cond_syms = self.condition.free_symbols - self.sym.free_symbols + return cond_syms | self.base_set.free_symbols + + @property + def bound_symbols(self): + return flatten([self.sym]) + + def _contains(self, other): + def ok_sig(a, b): + tuples = [isinstance(i, Tuple) for i in (a, b)] + c = tuples.count(True) + if c == 1: + return False + if c == 0: + return True + return len(a) == len(b) and all( + ok_sig(i, j) for i, j in zip(a, b)) + if not ok_sig(self.sym, other): + return S.false + + # try doing base_cond first and return + # False immediately if it is False + base_cond = Contains(other, self.base_set) + if base_cond is S.false: + return S.false + + # Substitute other into condition. This could raise e.g. for + # ConditionSet(x, 1/x >= 0, Reals).contains(0) + lamda = Lambda((self.sym,), self.condition) + try: + lambda_cond = lamda(other) + except TypeError: + return None + else: + return And(base_cond, lambda_cond) + + def as_relational(self, other): + f = Lambda(self.sym, self.condition) + if isinstance(self.sym, Tuple): + f = f(*other) + else: + f = f(other) + return And(f, self.base_set.contains(other)) + + def _eval_subs(self, old, new): + sym, cond, base = self.args + dsym = sym.subs(old, adummy) + insym = dsym.has(adummy) + # prioritize changing a symbol in the base + newbase = base.subs(old, new) + if newbase != base: + if not insym: + cond = cond.subs(old, new) + return self.func(sym, cond, newbase) + if insym: + pass # no change of bound symbols via subs + elif getattr(new, '_diff_wrt', False): + cond = cond.subs(old, new) + else: + pass # let error about the symbol raise from __new__ + return self.func(sym, cond, base) + + def _kind(self): + return SetKind(self.sym.kind) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/contains.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/contains.py new file mode 100644 index 0000000000000000000000000000000000000000..403d4875279d718724a898efa5cba41bc7bed6ea --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/contains.py @@ -0,0 +1,63 @@ +from sympy.core import S +from sympy.core.sympify import sympify +from sympy.core.relational import Eq, Ne +from sympy.core.parameters import global_parameters +from sympy.logic.boolalg import Boolean +from sympy.utilities.misc import func_name +from .sets import Set + + +class Contains(Boolean): + """ + Asserts that x is an element of the set S. + + Examples + ======== + + >>> from sympy import Symbol, Integer, S, Contains + >>> Contains(Integer(2), S.Integers) + True + >>> Contains(Integer(-2), S.Naturals) + False + >>> i = Symbol('i', integer=True) + >>> Contains(i, S.Naturals) + Contains(i, Naturals) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Element_%28mathematics%29 + """ + def __new__(cls, x, s, evaluate=None): + x = sympify(x) + s = sympify(s) + + if evaluate is None: + evaluate = global_parameters.evaluate + + if not isinstance(s, Set): + raise TypeError('expecting Set, not %s' % func_name(s)) + + if evaluate: + # _contains can return symbolic booleans that would be returned by + # s.contains(x) but here for Contains(x, s) we only evaluate to + # true, false or return the unevaluated Contains. + result = s._contains(x) + + if isinstance(result, Boolean): + if result in (S.true, S.false): + return result + elif result is not None: + raise TypeError("_contains() should return Boolean or None") + + return super().__new__(cls, x, s) + + @property + def binary_symbols(self): + return set().union(*[i.binary_symbols + for i in self.args[1].args + if i.is_Boolean or i.is_Symbol or + isinstance(i, (Eq, Ne))]) + + def as_set(self): + return self.args[1] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/fancysets.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/fancysets.py new file mode 100644 index 0000000000000000000000000000000000000000..e0e24a2a864222d16ba1a697558b5211127fb2ad --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/fancysets.py @@ -0,0 +1,1523 @@ +from functools import reduce +from itertools import product + +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import Lambda +from sympy.core.logic import fuzzy_not, fuzzy_or, fuzzy_and +from sympy.core.mod import Mod +from sympy.core.intfunc import igcd +from sympy.core.numbers import oo, Rational, Integer +from sympy.core.relational import Eq, is_eq +from sympy.core.kind import NumberKind +from sympy.core.singleton import Singleton, S +from sympy.core.symbol import Dummy, symbols, Symbol +from sympy.core.sympify import _sympify, sympify, _sympy_converter +from sympy.functions.elementary.integers import ceiling, floor +from sympy.functions.elementary.trigonometric import sin, cos +from sympy.logic.boolalg import And, Or +from .sets import tfn, Set, Interval, Union, FiniteSet, ProductSet, SetKind +from sympy.utilities.misc import filldedent + + +class Rationals(Set, metaclass=Singleton): + """ + Represents the rational numbers. This set is also available as + the singleton ``S.Rationals``. + + Examples + ======== + + >>> from sympy import S + >>> S.Half in S.Rationals + True + >>> iterable = iter(S.Rationals) + >>> [next(iterable) for i in range(12)] + [0, 1, -1, 1/2, 2, -1/2, -2, 1/3, 3, -1/3, -3, 2/3] + """ + + is_iterable = True + _inf = S.NegativeInfinity + _sup = S.Infinity + is_empty = False + is_finite_set = False + + def _contains(self, other): + if not isinstance(other, Expr): + return S.false + return tfn[other.is_rational] + + def __iter__(self): + yield S.Zero + yield S.One + yield S.NegativeOne + d = 2 + while True: + for n in range(d): + if igcd(n, d) == 1: + yield Rational(n, d) + yield Rational(d, n) + yield Rational(-n, d) + yield Rational(-d, n) + d += 1 + + @property + def _boundary(self): + return S.Reals + + def _kind(self): + return SetKind(NumberKind) + + +class Naturals(Set, metaclass=Singleton): + """ + Represents the natural numbers (or counting numbers) which are all + positive integers starting from 1. This set is also available as + the singleton ``S.Naturals``. + + Examples + ======== + + >>> from sympy import S, Interval, pprint + >>> 5 in S.Naturals + True + >>> iterable = iter(S.Naturals) + >>> next(iterable) + 1 + >>> next(iterable) + 2 + >>> next(iterable) + 3 + >>> pprint(S.Naturals.intersect(Interval(0, 10))) + {1, 2, ..., 10} + + See Also + ======== + + Naturals0 : non-negative integers (i.e. includes 0, too) + Integers : also includes negative integers + """ + + is_iterable = True + _inf: Integer = S.One + _sup = S.Infinity + is_empty = False + is_finite_set = False + + def _contains(self, other): + if not isinstance(other, Expr): + return S.false + elif other.is_positive and other.is_integer: + return S.true + elif other.is_integer is False or other.is_positive is False: + return S.false + + def _eval_is_subset(self, other): + return Range(1, oo).is_subset(other) + + def _eval_is_superset(self, other): + return Range(1, oo).is_superset(other) + + def __iter__(self): + i = self._inf + while True: + yield i + i = i + 1 + + @property + def _boundary(self): + return self + + def as_relational(self, x): + return And(Eq(floor(x), x), x >= self.inf, x < oo) + + def _kind(self): + return SetKind(NumberKind) + + +class Naturals0(Naturals): + """Represents the whole numbers which are all the non-negative integers, + inclusive of zero. + + See Also + ======== + + Naturals : positive integers; does not include 0 + Integers : also includes the negative integers + """ + _inf = S.Zero + + def _contains(self, other): + if not isinstance(other, Expr): + return S.false + elif other.is_integer and other.is_nonnegative: + return S.true + elif other.is_integer is False or other.is_nonnegative is False: + return S.false + + def _eval_is_subset(self, other): + return Range(oo).is_subset(other) + + def _eval_is_superset(self, other): + return Range(oo).is_superset(other) + + +class Integers(Set, metaclass=Singleton): + """ + Represents all integers: positive, negative and zero. This set is also + available as the singleton ``S.Integers``. + + Examples + ======== + + >>> from sympy import S, Interval, pprint + >>> 5 in S.Naturals + True + >>> iterable = iter(S.Integers) + >>> next(iterable) + 0 + >>> next(iterable) + 1 + >>> next(iterable) + -1 + >>> next(iterable) + 2 + + >>> pprint(S.Integers.intersect(Interval(-4, 4))) + {-4, -3, ..., 4} + + See Also + ======== + + Naturals0 : non-negative integers + Integers : positive and negative integers and zero + """ + + is_iterable = True + is_empty = False + is_finite_set = False + + def _contains(self, other): + if not isinstance(other, Expr): + return S.false + return tfn[other.is_integer] + + def __iter__(self): + yield S.Zero + i = S.One + while True: + yield i + yield -i + i = i + 1 + + @property + def _inf(self): + return S.NegativeInfinity + + @property + def _sup(self): + return S.Infinity + + @property + def _boundary(self): + return self + + def _kind(self): + return SetKind(NumberKind) + + def as_relational(self, x): + return And(Eq(floor(x), x), -oo < x, x < oo) + + def _eval_is_subset(self, other): + return Range(-oo, oo).is_subset(other) + + def _eval_is_superset(self, other): + return Range(-oo, oo).is_superset(other) + + +class Reals(Interval, metaclass=Singleton): + """ + Represents all real numbers + from negative infinity to positive infinity, + including all integer, rational and irrational numbers. + This set is also available as the singleton ``S.Reals``. + + + Examples + ======== + + >>> from sympy import S, Rational, pi, I + >>> 5 in S.Reals + True + >>> Rational(-1, 2) in S.Reals + True + >>> pi in S.Reals + True + >>> 3*I in S.Reals + False + >>> S.Reals.contains(pi) + True + + + See Also + ======== + + ComplexRegion + """ + @property + def start(self): + return S.NegativeInfinity + + @property + def end(self): + return S.Infinity + + @property + def left_open(self): + return True + + @property + def right_open(self): + return True + + def __eq__(self, other): + return other == Interval(S.NegativeInfinity, S.Infinity) + + def __hash__(self): + return hash(Interval(S.NegativeInfinity, S.Infinity)) + + +class ImageSet(Set): + """ + Image of a set under a mathematical function. The transformation + must be given as a Lambda function which has as many arguments + as the elements of the set upon which it operates, e.g. 1 argument + when acting on the set of integers or 2 arguments when acting on + a complex region. + + This function is not normally called directly, but is called + from ``imageset``. + + + Examples + ======== + + >>> from sympy import Symbol, S, pi, Dummy, Lambda + >>> from sympy import FiniteSet, ImageSet, Interval + + >>> x = Symbol('x') + >>> N = S.Naturals + >>> squares = ImageSet(Lambda(x, x**2), N) # {x**2 for x in N} + >>> 4 in squares + True + >>> 5 in squares + False + + >>> FiniteSet(0, 1, 2, 3, 4, 5, 6, 7, 9, 10).intersect(squares) + {1, 4, 9} + + >>> square_iterable = iter(squares) + >>> for i in range(4): + ... next(square_iterable) + 1 + 4 + 9 + 16 + + If you want to get value for `x` = 2, 1/2 etc. (Please check whether the + `x` value is in ``base_set`` or not before passing it as args) + + >>> squares.lamda(2) + 4 + >>> squares.lamda(S(1)/2) + 1/4 + + >>> n = Dummy('n') + >>> solutions = ImageSet(Lambda(n, n*pi), S.Integers) # solutions of sin(x) = 0 + >>> dom = Interval(-1, 1) + >>> dom.intersect(solutions) + {0} + + See Also + ======== + + sympy.sets.sets.imageset + """ + def __new__(cls, flambda, *sets): + if not isinstance(flambda, Lambda): + raise ValueError('First argument must be a Lambda') + + signature = flambda.signature + + if len(signature) != len(sets): + raise ValueError('Incompatible signature') + + sets = [_sympify(s) for s in sets] + + if not all(isinstance(s, Set) for s in sets): + raise TypeError("Set arguments to ImageSet should of type Set") + + if not all(cls._check_sig(sg, st) for sg, st in zip(signature, sets)): + raise ValueError("Signature %s does not match sets %s" % (signature, sets)) + + if flambda is S.IdentityFunction and len(sets) == 1: + return sets[0] + + if not set(flambda.variables) & flambda.expr.free_symbols: + is_empty = fuzzy_or(s.is_empty for s in sets) + if is_empty == True: + return S.EmptySet + elif is_empty == False: + return FiniteSet(flambda.expr) + + return Basic.__new__(cls, flambda, *sets) + + lamda = property(lambda self: self.args[0]) + base_sets = property(lambda self: self.args[1:]) + + @property + def base_set(self): + # XXX: Maybe deprecate this? It is poorly defined in handling + # the multivariate case... + sets = self.base_sets + if len(sets) == 1: + return sets[0] + else: + return ProductSet(*sets).flatten() + + @property + def base_pset(self): + return ProductSet(*self.base_sets) + + @classmethod + def _check_sig(cls, sig_i, set_i): + if sig_i.is_symbol: + return True + elif isinstance(set_i, ProductSet): + sets = set_i.sets + if len(sig_i) != len(sets): + return False + # Recurse through the signature for nested tuples: + return all(cls._check_sig(ts, ps) for ts, ps in zip(sig_i, sets)) + else: + # XXX: Need a better way of checking whether a set is a set of + # Tuples or not. For example a FiniteSet can contain Tuples + # but so can an ImageSet or a ConditionSet. Others like + # Integers, Reals etc can not contain Tuples. We could just + # list the possibilities here... Current code for e.g. + # _contains probably only works for ProductSet. + return True # Give the benefit of the doubt + + def __iter__(self): + already_seen = set() + for i in self.base_pset: + val = self.lamda(*i) + if val in already_seen: + continue + else: + already_seen.add(val) + yield val + + def _is_multivariate(self): + return len(self.lamda.variables) > 1 + + def _contains(self, other): + from sympy.solvers.solveset import _solveset_multi + + def get_symsetmap(signature, base_sets): + '''Attempt to get a map of symbols to base_sets''' + queue = list(zip(signature, base_sets)) + symsetmap = {} + for sig, base_set in queue: + if sig.is_symbol: + symsetmap[sig] = base_set + elif base_set.is_ProductSet: + sets = base_set.sets + if len(sig) != len(sets): + raise ValueError("Incompatible signature") + # Recurse + queue.extend(zip(sig, sets)) + else: + # If we get here then we have something like sig = (x, y) and + # base_set = {(1, 2), (3, 4)}. For now we give up. + return None + + return symsetmap + + def get_equations(expr, candidate): + '''Find the equations relating symbols in expr and candidate.''' + queue = [(expr, candidate)] + for e, c in queue: + if not isinstance(e, Tuple): + yield Eq(e, c) + elif not isinstance(c, Tuple) or len(e) != len(c): + yield False + return + else: + queue.extend(zip(e, c)) + + # Get the basic objects together: + other = _sympify(other) + expr = self.lamda.expr + sig = self.lamda.signature + variables = self.lamda.variables + base_sets = self.base_sets + + # Use dummy symbols for ImageSet parameters so they don't match + # anything in other + rep = {v: Dummy(v.name) for v in variables} + variables = [v.subs(rep) for v in variables] + sig = sig.subs(rep) + expr = expr.subs(rep) + + # Map the parts of other to those in the Lambda expr + equations = [] + for eq in get_equations(expr, other): + # Unsatisfiable equation? + if eq is False: + return S.false + equations.append(eq) + + # Map the symbols in the signature to the corresponding domains + symsetmap = get_symsetmap(sig, base_sets) + if symsetmap is None: + # Can't factor the base sets to a ProductSet + return None + + # Which of the variables in the Lambda signature need to be solved for? + symss = (eq.free_symbols for eq in equations) + variables = set(variables) & reduce(set.union, symss, set()) + + # Use internal multivariate solveset + variables = tuple(variables) + base_sets = [symsetmap[v] for v in variables] + solnset = _solveset_multi(equations, variables, base_sets) + if solnset is None: + return None + return tfn[fuzzy_not(solnset.is_empty)] + + @property + def is_iterable(self): + return all(s.is_iterable for s in self.base_sets) + + def doit(self, **hints): + from sympy.sets.setexpr import SetExpr + f = self.lamda + sig = f.signature + if len(sig) == 1 and sig[0].is_symbol and isinstance(f.expr, Expr): + base_set = self.base_sets[0] + return SetExpr(base_set)._eval_func(f).set + if all(s.is_FiniteSet for s in self.base_sets): + return FiniteSet(*(f(*a) for a in product(*self.base_sets))) + return self + + def _kind(self): + return SetKind(self.lamda.expr.kind) + + +class Range(Set): + """ + Represents a range of integers. Can be called as ``Range(stop)``, + ``Range(start, stop)``, or ``Range(start, stop, step)``; when ``step`` is + not given it defaults to 1. + + ``Range(stop)`` is the same as ``Range(0, stop, 1)`` and the stop value + (just as for Python ranges) is not included in the Range values. + + >>> from sympy import Range + >>> list(Range(3)) + [0, 1, 2] + + The step can also be negative: + + >>> list(Range(10, 0, -2)) + [10, 8, 6, 4, 2] + + The stop value is made canonical so equivalent ranges always + have the same args: + + >>> Range(0, 10, 3) + Range(0, 12, 3) + + Infinite ranges are allowed. ``oo`` and ``-oo`` are never included in the + set (``Range`` is always a subset of ``Integers``). If the starting point + is infinite, then the final value is ``stop - step``. To iterate such a + range, it needs to be reversed: + + >>> from sympy import oo + >>> r = Range(-oo, 1) + >>> r[-1] + 0 + >>> next(iter(r)) + Traceback (most recent call last): + ... + TypeError: Cannot iterate over Range with infinite start + >>> next(iter(r.reversed)) + 0 + + Although ``Range`` is a :class:`Set` (and supports the normal set + operations) it maintains the order of the elements and can + be used in contexts where ``range`` would be used. + + >>> from sympy import Interval + >>> Range(0, 10, 2).intersect(Interval(3, 7)) + Range(4, 8, 2) + >>> list(_) + [4, 6] + + Although slicing of a Range will always return a Range -- possibly + empty -- an empty set will be returned from any intersection that + is empty: + + >>> Range(3)[:0] + Range(0, 0, 1) + >>> Range(3).intersect(Interval(4, oo)) + EmptySet + >>> Range(3).intersect(Range(4, oo)) + EmptySet + + Range will accept symbolic arguments but has very limited support + for doing anything other than displaying the Range: + + >>> from sympy import Symbol, pprint + >>> from sympy.abc import i, j, k + >>> Range(i, j, k).start + i + >>> Range(i, j, k).inf + Traceback (most recent call last): + ... + ValueError: invalid method for symbolic range + + Better success will be had when using integer symbols: + + >>> n = Symbol('n', integer=True) + >>> r = Range(n, n + 20, 3) + >>> r.inf + n + >>> pprint(r) + {n, n + 3, ..., n + 18} + """ + + def __new__(cls, *args): + if len(args) == 1: + if isinstance(args[0], range): + raise TypeError( + 'use sympify(%s) to convert range to Range' % args[0]) + + # expand range + slc = slice(*args) + + if slc.step == 0: + raise ValueError("step cannot be 0") + + start, stop, step = slc.start or 0, slc.stop, slc.step or 1 + try: + ok = [] + for w in (start, stop, step): + w = sympify(w) + if w in [S.NegativeInfinity, S.Infinity] or ( + w.has(Symbol) and w.is_integer != False): + ok.append(w) + elif not w.is_Integer: + if w.is_infinite: + raise ValueError('infinite symbols not allowed') + raise ValueError + else: + ok.append(w) + except ValueError: + raise ValueError(filldedent(''' + Finite arguments to Range must be integers; `imageset` can define + other cases, e.g. use `imageset(i, i/10, Range(3))` to give + [0, 1/10, 1/5].''')) + start, stop, step = ok + + null = False + if any(i.has(Symbol) for i in (start, stop, step)): + dif = stop - start + n = dif/step + if n.is_Rational: + if dif == 0: + null = True + else: # (x, x + 5, 2) or (x, 3*x, x) + n = floor(n) + end = start + n*step + if dif.is_Rational: # (x, x + 5, 2) + if (end - stop).is_negative: + end += step + else: # (x, 3*x, x) + if (end/stop - 1).is_negative: + end += step + elif n.is_extended_negative: + null = True + else: + end = stop # other methods like sup and reversed must fail + elif start.is_infinite: + span = step*(stop - start) + if span is S.NaN or span <= 0: + null = True + elif step.is_Integer and stop.is_infinite and abs(step) != 1: + raise ValueError(filldedent(''' + Step size must be %s in this case.''' % (1 if step > 0 else -1))) + else: + end = stop + else: + oostep = step.is_infinite + if oostep: + step = S.One if step > 0 else S.NegativeOne + n = ceiling((stop - start)/step) + if n <= 0: + null = True + elif oostep: + step = S.One # make it canonical + end = start + step + else: + end = start + n*step + if null: + start = end = S.Zero + step = S.One + return Basic.__new__(cls, start, end, step) + + start = property(lambda self: self.args[0]) + stop = property(lambda self: self.args[1]) + step = property(lambda self: self.args[2]) + + @property + def reversed(self): + """Return an equivalent Range in the opposite order. + + Examples + ======== + + >>> from sympy import Range + >>> Range(10).reversed + Range(9, -1, -1) + """ + if self.has(Symbol): + n = (self.stop - self.start)/self.step + if not n.is_extended_positive or not all( + i.is_integer or i.is_infinite for i in self.args): + raise ValueError('invalid method for symbolic range') + if self.start == self.stop: + return self + return self.func( + self.stop - self.step, self.start - self.step, -self.step) + + def _kind(self): + return SetKind(NumberKind) + + def _contains(self, other): + if self.start == self.stop: + return S.false + if other.is_infinite: + return S.false + if not other.is_integer: + return tfn[other.is_integer] + if self.has(Symbol): + n = (self.stop - self.start)/self.step + if not n.is_extended_positive or not all( + i.is_integer or i.is_infinite for i in self.args): + return + else: + n = self.size + if self.start.is_finite: + ref = self.start + elif self.stop.is_finite: + ref = self.stop + else: # both infinite; step is +/- 1 (enforced by __new__) + return S.true + if n == 1: + return Eq(other, self[0]) + res = (ref - other) % self.step + if res == S.Zero: + if self.has(Symbol): + d = Dummy('i') + return self.as_relational(d).subs(d, other) + return And(other >= self.inf, other <= self.sup) + elif res.is_Integer: # off sequence + return S.false + else: # symbolic/unsimplified residue modulo step + return None + + def __iter__(self): + n = self.size # validate + if not (n.has(S.Infinity) or n.has(S.NegativeInfinity) or n.is_Integer): + raise TypeError("Cannot iterate over symbolic Range") + if self.start in [S.NegativeInfinity, S.Infinity]: + raise TypeError("Cannot iterate over Range with infinite start") + elif self.start != self.stop: + i = self.start + if n.is_infinite: + while True: + yield i + i += self.step + else: + for _ in range(n): + yield i + i += self.step + + @property + def is_iterable(self): + # Check that size can be determined, used by __iter__ + dif = self.stop - self.start + n = dif/self.step + if not (n.has(S.Infinity) or n.has(S.NegativeInfinity) or n.is_Integer): + return False + if self.start in [S.NegativeInfinity, S.Infinity]: + return False + if not (n.is_extended_nonnegative and all(i.is_integer for i in self.args)): + return False + return True + + def __len__(self): + rv = self.size + if rv is S.Infinity: + raise ValueError('Use .size to get the length of an infinite Range') + return int(rv) + + @property + def size(self): + if self.start == self.stop: + return S.Zero + dif = self.stop - self.start + n = dif/self.step + if n.is_infinite: + return S.Infinity + if n.is_extended_nonnegative and all(i.is_integer for i in self.args): + return abs(floor(n)) + raise ValueError('Invalid method for symbolic Range') + + @property + def is_finite_set(self): + if self.start.is_integer and self.stop.is_integer: + return True + return self.size.is_finite + + @property + def is_empty(self): + try: + return self.size.is_zero + except ValueError: + return None + + def __bool__(self): + # this only distinguishes between definite null range + # and non-null/unknown null; getting True doesn't mean + # that it actually is not null + b = is_eq(self.start, self.stop) + if b is None: + raise ValueError('cannot tell if Range is null or not') + return not bool(b) + + def __getitem__(self, i): + ooslice = "cannot slice from the end with an infinite value" + zerostep = "slice step cannot be zero" + infinite = "slicing not possible on range with infinite start" + # if we had to take every other element in the following + # oo, ..., 6, 4, 2, 0 + # we might get oo, ..., 4, 0 or oo, ..., 6, 2 + ambiguous = "cannot unambiguously re-stride from the end " + \ + "with an infinite value" + if isinstance(i, slice): + if self.size.is_finite: # validates, too + if self.start == self.stop: + return Range(0) + start, stop, step = i.indices(self.size) + n = ceiling((stop - start)/step) + if n <= 0: + return Range(0) + canonical_stop = start + n*step + end = canonical_stop - step + ss = step*self.step + return Range(self[start], self[end] + ss, ss) + else: # infinite Range + start = i.start + stop = i.stop + if i.step == 0: + raise ValueError(zerostep) + step = i.step or 1 + ss = step*self.step + #--------------------- + # handle infinite Range + # i.e. Range(-oo, oo) or Range(oo, -oo, -1) + # -------------------- + if self.start.is_infinite and self.stop.is_infinite: + raise ValueError(infinite) + #--------------------- + # handle infinite on right + # e.g. Range(0, oo) or Range(0, -oo, -1) + # -------------------- + if self.stop.is_infinite: + # start and stop are not interdependent -- + # they only depend on step --so we use the + # equivalent reversed values + return self.reversed[ + stop if stop is None else -stop + 1: + start if start is None else -start: + step].reversed + #--------------------- + # handle infinite on the left + # e.g. Range(oo, 0, -1) or Range(-oo, 0) + # -------------------- + # consider combinations of + # start/stop {== None, < 0, == 0, > 0} and + # step {< 0, > 0} + if start is None: + if stop is None: + if step < 0: + return Range(self[-1], self.start, ss) + elif step > 1: + raise ValueError(ambiguous) + else: # == 1 + return self + elif stop < 0: + if step < 0: + return Range(self[-1], self[stop], ss) + else: # > 0 + return Range(self.start, self[stop], ss) + elif stop == 0: + if step > 0: + return Range(0) + else: # < 0 + raise ValueError(ooslice) + elif stop == 1: + if step > 0: + raise ValueError(ooslice) # infinite singleton + else: # < 0 + raise ValueError(ooslice) + else: # > 1 + raise ValueError(ooslice) + elif start < 0: + if stop is None: + if step < 0: + return Range(self[start], self.start, ss) + else: # > 0 + return Range(self[start], self.stop, ss) + elif stop < 0: + return Range(self[start], self[stop], ss) + elif stop == 0: + if step < 0: + raise ValueError(ooslice) + else: # > 0 + return Range(0) + elif stop > 0: + raise ValueError(ooslice) + elif start == 0: + if stop is None: + if step < 0: + raise ValueError(ooslice) # infinite singleton + elif step > 1: + raise ValueError(ambiguous) + else: # == 1 + return self + elif stop < 0: + if step > 1: + raise ValueError(ambiguous) + elif step == 1: + return Range(self.start, self[stop], ss) + else: # < 0 + return Range(0) + else: # >= 0 + raise ValueError(ooslice) + elif start > 0: + raise ValueError(ooslice) + else: + if self.start == self.stop: + raise IndexError('Range index out of range') + if not (all(i.is_integer or i.is_infinite + for i in self.args) and ((self.stop - self.start)/ + self.step).is_extended_positive): + raise ValueError('Invalid method for symbolic Range') + if i == 0: + if self.start.is_infinite: + raise ValueError(ooslice) + return self.start + if i == -1: + if self.stop.is_infinite: + raise ValueError(ooslice) + return self.stop - self.step + n = self.size # must be known for any other index + rv = (self.stop if i < 0 else self.start) + i*self.step + if rv.is_infinite: + raise ValueError(ooslice) + val = (rv - self.start)/self.step + rel = fuzzy_or([val.is_infinite, + fuzzy_and([val.is_nonnegative, (n-val).is_nonnegative])]) + if rel: + return rv + if rel is None: + raise ValueError('Invalid method for symbolic Range') + raise IndexError("Range index out of range") + + @property + def _inf(self): + if not self: + return S.EmptySet.inf + if self.has(Symbol): + if all(i.is_integer or i.is_infinite for i in self.args): + dif = self.stop - self.start + if self.step.is_positive and dif.is_positive: + return self.start + elif self.step.is_negative and dif.is_negative: + return self.stop - self.step + raise ValueError('invalid method for symbolic range') + if self.step > 0: + return self.start + else: + return self.stop - self.step + + @property + def _sup(self): + if not self: + return S.EmptySet.sup + if self.has(Symbol): + if all(i.is_integer or i.is_infinite for i in self.args): + dif = self.stop - self.start + if self.step.is_positive and dif.is_positive: + return self.stop - self.step + elif self.step.is_negative and dif.is_negative: + return self.start + raise ValueError('invalid method for symbolic range') + if self.step > 0: + return self.stop - self.step + else: + return self.start + + @property + def _boundary(self): + return self + + def as_relational(self, x): + """Rewrite a Range in terms of equalities and logic operators. """ + if self.start.is_infinite: + assert not self.stop.is_infinite # by instantiation + a = self.reversed.start + else: + a = self.start + step = self.step + in_seq = Eq(Mod(x - a, step), 0) + ints = And(Eq(Mod(a, 1), 0), Eq(Mod(step, 1), 0)) + n = (self.stop - self.start)/self.step + if n == 0: + return S.EmptySet.as_relational(x) + if n == 1: + return And(Eq(x, a), ints) + try: + a, b = self.inf, self.sup + except ValueError: + a = None + if a is not None: + range_cond = And( + x > a if a.is_infinite else x >= a, + x < b if b.is_infinite else x <= b) + else: + a, b = self.start, self.stop - self.step + range_cond = Or( + And(self.step >= 1, x > a if a.is_infinite else x >= a, + x < b if b.is_infinite else x <= b), + And(self.step <= -1, x < a if a.is_infinite else x <= a, + x > b if b.is_infinite else x >= b)) + return And(in_seq, ints, range_cond) + + +_sympy_converter[range] = lambda r: Range(r.start, r.stop, r.step) + +def normalize_theta_set(theta): + r""" + Normalize a Real Set `theta` in the interval `[0, 2\pi)`. It returns + a normalized value of theta in the Set. For Interval, a maximum of + one cycle $[0, 2\pi]$, is returned i.e. for theta equal to $[0, 10\pi]$, + returned normalized value would be $[0, 2\pi)$. As of now intervals + with end points as non-multiples of ``pi`` is not supported. + + Raises + ====== + + NotImplementedError + The algorithms for Normalizing theta Set are not yet + implemented. + ValueError + The input is not valid, i.e. the input is not a real set. + RuntimeError + It is a bug, please report to the github issue tracker. + + Examples + ======== + + >>> from sympy.sets.fancysets import normalize_theta_set + >>> from sympy import Interval, FiniteSet, pi + >>> normalize_theta_set(Interval(9*pi/2, 5*pi)) + Interval(pi/2, pi) + >>> normalize_theta_set(Interval(-3*pi/2, pi/2)) + Interval.Ropen(0, 2*pi) + >>> normalize_theta_set(Interval(-pi/2, pi/2)) + Union(Interval(0, pi/2), Interval.Ropen(3*pi/2, 2*pi)) + >>> normalize_theta_set(Interval(-4*pi, 3*pi)) + Interval.Ropen(0, 2*pi) + >>> normalize_theta_set(Interval(-3*pi/2, -pi/2)) + Interval(pi/2, 3*pi/2) + >>> normalize_theta_set(FiniteSet(0, pi, 3*pi)) + {0, pi} + + """ + from sympy.functions.elementary.trigonometric import _pi_coeff + + if theta.is_Interval: + interval_len = theta.measure + # one complete circle + if interval_len >= 2*S.Pi: + if interval_len == 2*S.Pi and theta.left_open and theta.right_open: + k = _pi_coeff(theta.start) + return Union(Interval(0, k*S.Pi, False, True), + Interval(k*S.Pi, 2*S.Pi, True, True)) + return Interval(0, 2*S.Pi, False, True) + + k_start, k_end = _pi_coeff(theta.start), _pi_coeff(theta.end) + + if k_start is None or k_end is None: + raise NotImplementedError("Normalizing theta without pi as coefficient is " + "not yet implemented") + new_start = k_start*S.Pi + new_end = k_end*S.Pi + + if new_start > new_end: + return Union(Interval(S.Zero, new_end, False, theta.right_open), + Interval(new_start, 2*S.Pi, theta.left_open, True)) + else: + return Interval(new_start, new_end, theta.left_open, theta.right_open) + + elif theta.is_FiniteSet: + new_theta = [] + for element in theta: + k = _pi_coeff(element) + if k is None: + raise NotImplementedError('Normalizing theta without pi as ' + 'coefficient, is not Implemented.') + else: + new_theta.append(k*S.Pi) + return FiniteSet(*new_theta) + + elif theta.is_Union: + return Union(*[normalize_theta_set(interval) for interval in theta.args]) + + elif theta.is_subset(S.Reals): + raise NotImplementedError("Normalizing theta when, it is of type %s is not " + "implemented" % type(theta)) + else: + raise ValueError(" %s is not a real set" % (theta)) + + +class ComplexRegion(Set): + r""" + Represents the Set of all Complex Numbers. It can represent a + region of Complex Plane in both the standard forms Polar and + Rectangular coordinates. + + * Polar Form + Input is in the form of the ProductSet or Union of ProductSets + of the intervals of ``r`` and ``theta``, and use the flag ``polar=True``. + + .. math:: Z = \{z \in \mathbb{C} \mid z = r\times (\cos(\theta) + I\sin(\theta)), r \in [\texttt{r}], \theta \in [\texttt{theta}]\} + + * Rectangular Form + Input is in the form of the ProductSet or Union of ProductSets + of interval of x and y, the real and imaginary parts of the Complex numbers in a plane. + Default input type is in rectangular form. + + .. math:: Z = \{z \in \mathbb{C} \mid z = x + Iy, x \in [\operatorname{re}(z)], y \in [\operatorname{im}(z)]\} + + Examples + ======== + + >>> from sympy import ComplexRegion, Interval, S, I, Union + >>> a = Interval(2, 3) + >>> b = Interval(4, 6) + >>> c1 = ComplexRegion(a*b) # Rectangular Form + >>> c1 + CartesianComplexRegion(ProductSet(Interval(2, 3), Interval(4, 6))) + + * c1 represents the rectangular region in complex plane + surrounded by the coordinates (2, 4), (3, 4), (3, 6) and + (2, 6), of the four vertices. + + >>> c = Interval(1, 8) + >>> c2 = ComplexRegion(Union(a*b, b*c)) + >>> c2 + CartesianComplexRegion(Union(ProductSet(Interval(2, 3), Interval(4, 6)), ProductSet(Interval(4, 6), Interval(1, 8)))) + + * c2 represents the Union of two rectangular regions in complex + plane. One of them surrounded by the coordinates of c1 and + other surrounded by the coordinates (4, 1), (6, 1), (6, 8) and + (4, 8). + + >>> 2.5 + 4.5*I in c1 + True + >>> 2.5 + 6.5*I in c1 + False + + >>> r = Interval(0, 1) + >>> theta = Interval(0, 2*S.Pi) + >>> c2 = ComplexRegion(r*theta, polar=True) # Polar Form + >>> c2 # unit Disk + PolarComplexRegion(ProductSet(Interval(0, 1), Interval.Ropen(0, 2*pi))) + + * c2 represents the region in complex plane inside the + Unit Disk centered at the origin. + + >>> 0.5 + 0.5*I in c2 + True + >>> 1 + 2*I in c2 + False + + >>> unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, 2*S.Pi), polar=True) + >>> upper_half_unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, S.Pi), polar=True) + >>> intersection = unit_disk.intersect(upper_half_unit_disk) + >>> intersection + PolarComplexRegion(ProductSet(Interval(0, 1), Interval(0, pi))) + >>> intersection == upper_half_unit_disk + True + + See Also + ======== + + CartesianComplexRegion + PolarComplexRegion + Complexes + + """ + is_ComplexRegion = True + + def __new__(cls, sets, polar=False): + if polar is False: + return CartesianComplexRegion(sets) + elif polar is True: + return PolarComplexRegion(sets) + else: + raise ValueError("polar should be either True or False") + + @property + def sets(self): + """ + Return raw input sets to the self. + + Examples + ======== + + >>> from sympy import Interval, ComplexRegion, Union + >>> a = Interval(2, 3) + >>> b = Interval(4, 5) + >>> c = Interval(1, 7) + >>> C1 = ComplexRegion(a*b) + >>> C1.sets + ProductSet(Interval(2, 3), Interval(4, 5)) + >>> C2 = ComplexRegion(Union(a*b, b*c)) + >>> C2.sets + Union(ProductSet(Interval(2, 3), Interval(4, 5)), ProductSet(Interval(4, 5), Interval(1, 7))) + + """ + return self.args[0] + + @property + def psets(self): + """ + Return a tuple of sets (ProductSets) input of the self. + + Examples + ======== + + >>> from sympy import Interval, ComplexRegion, Union + >>> a = Interval(2, 3) + >>> b = Interval(4, 5) + >>> c = Interval(1, 7) + >>> C1 = ComplexRegion(a*b) + >>> C1.psets + (ProductSet(Interval(2, 3), Interval(4, 5)),) + >>> C2 = ComplexRegion(Union(a*b, b*c)) + >>> C2.psets + (ProductSet(Interval(2, 3), Interval(4, 5)), ProductSet(Interval(4, 5), Interval(1, 7))) + + """ + if self.sets.is_ProductSet: + psets = () + psets = psets + (self.sets, ) + else: + psets = self.sets.args + return psets + + @property + def a_interval(self): + """ + Return the union of intervals of `x` when, self is in + rectangular form, or the union of intervals of `r` when + self is in polar form. + + Examples + ======== + + >>> from sympy import Interval, ComplexRegion, Union + >>> a = Interval(2, 3) + >>> b = Interval(4, 5) + >>> c = Interval(1, 7) + >>> C1 = ComplexRegion(a*b) + >>> C1.a_interval + Interval(2, 3) + >>> C2 = ComplexRegion(Union(a*b, b*c)) + >>> C2.a_interval + Union(Interval(2, 3), Interval(4, 5)) + + """ + a_interval = [] + for element in self.psets: + a_interval.append(element.args[0]) + + a_interval = Union(*a_interval) + return a_interval + + @property + def b_interval(self): + """ + Return the union of intervals of `y` when, self is in + rectangular form, or the union of intervals of `theta` + when self is in polar form. + + Examples + ======== + + >>> from sympy import Interval, ComplexRegion, Union + >>> a = Interval(2, 3) + >>> b = Interval(4, 5) + >>> c = Interval(1, 7) + >>> C1 = ComplexRegion(a*b) + >>> C1.b_interval + Interval(4, 5) + >>> C2 = ComplexRegion(Union(a*b, b*c)) + >>> C2.b_interval + Interval(1, 7) + + """ + b_interval = [] + for element in self.psets: + b_interval.append(element.args[1]) + + b_interval = Union(*b_interval) + return b_interval + + @property + def _measure(self): + """ + The measure of self.sets. + + Examples + ======== + + >>> from sympy import Interval, ComplexRegion, S + >>> a, b = Interval(2, 5), Interval(4, 8) + >>> c = Interval(0, 2*S.Pi) + >>> c1 = ComplexRegion(a*b) + >>> c1.measure + 12 + >>> c2 = ComplexRegion(a*c, polar=True) + >>> c2.measure + 6*pi + + """ + return self.sets._measure + + def _kind(self): + return self.args[0].kind + + @classmethod + def from_real(cls, sets): + """ + Converts given subset of real numbers to a complex region. + + Examples + ======== + + >>> from sympy import Interval, ComplexRegion + >>> unit = Interval(0,1) + >>> ComplexRegion.from_real(unit) + CartesianComplexRegion(ProductSet(Interval(0, 1), {0})) + + """ + if not sets.is_subset(S.Reals): + raise ValueError("sets must be a subset of the real line") + + return CartesianComplexRegion(sets * FiniteSet(0)) + + def _contains(self, other): + from sympy.functions import arg, Abs + + isTuple = isinstance(other, Tuple) + if isTuple and len(other) != 2: + raise ValueError('expecting Tuple of length 2') + + # If the other is not an Expression, and neither a Tuple + if not isinstance(other, (Expr, Tuple)): + return S.false + + # self in rectangular form + if not self.polar: + re, im = other if isTuple else other.as_real_imag() + return tfn[fuzzy_or(fuzzy_and([ + pset.args[0]._contains(re), + pset.args[1]._contains(im)]) + for pset in self.psets)] + + # self in polar form + elif self.polar: + if other.is_zero: + # ignore undefined complex argument + return tfn[fuzzy_or(pset.args[0]._contains(S.Zero) + for pset in self.psets)] + if isTuple: + r, theta = other + else: + r, theta = Abs(other), arg(other) + if theta.is_real and theta.is_number: + # angles in psets are normalized to [0, 2pi) + theta %= 2*S.Pi + return tfn[fuzzy_or(fuzzy_and([ + pset.args[0]._contains(r), + pset.args[1]._contains(theta)]) + for pset in self.psets)] + + +class CartesianComplexRegion(ComplexRegion): + r""" + Set representing a square region of the complex plane. + + .. math:: Z = \{z \in \mathbb{C} \mid z = x + Iy, x \in [\operatorname{re}(z)], y \in [\operatorname{im}(z)]\} + + Examples + ======== + + >>> from sympy import ComplexRegion, I, Interval + >>> region = ComplexRegion(Interval(1, 3) * Interval(4, 6)) + >>> 2 + 5*I in region + True + >>> 5*I in region + False + + See also + ======== + + ComplexRegion + PolarComplexRegion + Complexes + """ + + polar = False + variables = symbols('x, y', cls=Dummy) + + def __new__(cls, sets): + + if sets == S.Reals*S.Reals: + return S.Complexes + + if all(_a.is_FiniteSet for _a in sets.args) and (len(sets.args) == 2): + + # ** ProductSet of FiniteSets in the Complex Plane. ** + # For Cases like ComplexRegion({2, 4}*{3}), It + # would return {2 + 3*I, 4 + 3*I} + + # FIXME: This should probably be handled with something like: + # return ImageSet(Lambda((x, y), x+I*y), sets).rewrite(FiniteSet) + complex_num = [] + for x in sets.args[0]: + for y in sets.args[1]: + complex_num.append(x + S.ImaginaryUnit*y) + return FiniteSet(*complex_num) + else: + return Set.__new__(cls, sets) + + @property + def expr(self): + x, y = self.variables + return x + S.ImaginaryUnit*y + + +class PolarComplexRegion(ComplexRegion): + r""" + Set representing a polar region of the complex plane. + + .. math:: Z = \{z \in \mathbb{C} \mid z = r\times (\cos(\theta) + I\sin(\theta)), r \in [\texttt{r}], \theta \in [\texttt{theta}]\} + + Examples + ======== + + >>> from sympy import ComplexRegion, Interval, oo, pi, I + >>> rset = Interval(0, oo) + >>> thetaset = Interval(0, pi) + >>> upper_half_plane = ComplexRegion(rset * thetaset, polar=True) + >>> 1 + I in upper_half_plane + True + >>> 1 - I in upper_half_plane + False + + See also + ======== + + ComplexRegion + CartesianComplexRegion + Complexes + + """ + + polar = True + variables = symbols('r, theta', cls=Dummy) + + def __new__(cls, sets): + + new_sets = [] + # sets is Union of ProductSets + if not sets.is_ProductSet: + for k in sets.args: + new_sets.append(k) + # sets is ProductSets + else: + new_sets.append(sets) + # Normalize input theta + for k, v in enumerate(new_sets): + new_sets[k] = ProductSet(v.args[0], + normalize_theta_set(v.args[1])) + sets = Union(*new_sets) + return Set.__new__(cls, sets) + + @property + def expr(self): + r, theta = self.variables + return r*(cos(theta) + S.ImaginaryUnit*sin(theta)) + + +class Complexes(CartesianComplexRegion, metaclass=Singleton): + """ + The :class:`Set` of all complex numbers + + Examples + ======== + + >>> from sympy import S, I + >>> S.Complexes + Complexes + >>> 1 + I in S.Complexes + True + + See also + ======== + + Reals + ComplexRegion + + """ + + is_empty = False + is_finite_set = False + + # Override property from superclass since Complexes has no args + @property + def sets(self): + return ProductSet(S.Reals, S.Reals) + + def __new__(cls): + return Set.__new__(cls) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/ordinals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/ordinals.py new file mode 100644 index 0000000000000000000000000000000000000000..cfe062354cfe58a4747998e51fa0d261e67576cc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/ordinals.py @@ -0,0 +1,282 @@ +from sympy.core import Basic, Integer +import operator + + +class OmegaPower(Basic): + """ + Represents ordinal exponential and multiplication terms one of the + building blocks of the :class:`Ordinal` class. + In ``OmegaPower(a, b)``, ``a`` represents exponent and ``b`` represents multiplicity. + """ + def __new__(cls, a, b): + if isinstance(b, int): + b = Integer(b) + if not isinstance(b, Integer) or b <= 0: + raise TypeError("multiplicity must be a positive integer") + + if not isinstance(a, Ordinal): + a = Ordinal.convert(a) + + return Basic.__new__(cls, a, b) + + @property + def exp(self): + return self.args[0] + + @property + def mult(self): + return self.args[1] + + def _compare_term(self, other, op): + if self.exp == other.exp: + return op(self.mult, other.mult) + else: + return op(self.exp, other.exp) + + def __eq__(self, other): + if not isinstance(other, OmegaPower): + try: + other = OmegaPower(0, other) + except TypeError: + return NotImplemented + return self.args == other.args + + def __hash__(self): + return Basic.__hash__(self) + + def __lt__(self, other): + if not isinstance(other, OmegaPower): + try: + other = OmegaPower(0, other) + except TypeError: + return NotImplemented + return self._compare_term(other, operator.lt) + + +class Ordinal(Basic): + """ + Represents ordinals in Cantor normal form. + + Internally, this class is just a list of instances of OmegaPower. + + Examples + ======== + >>> from sympy import Ordinal, OmegaPower + >>> from sympy.sets.ordinals import omega + >>> w = omega + >>> w.is_limit_ordinal + True + >>> Ordinal(OmegaPower(w + 1, 1), OmegaPower(3, 2)) + w**(w + 1) + w**3*2 + >>> 3 + w + w + >>> (w + 1) * w + w**2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Ordinal_arithmetic + """ + def __new__(cls, *terms): + obj = super().__new__(cls, *terms) + powers = [i.exp for i in obj.args] + if not all(powers[i] >= powers[i+1] for i in range(len(powers) - 1)): + raise ValueError("powers must be in decreasing order") + return obj + + @property + def terms(self): + return self.args + + @property + def leading_term(self): + if self == ord0: + raise ValueError("ordinal zero has no leading term") + return self.terms[0] + + @property + def trailing_term(self): + if self == ord0: + raise ValueError("ordinal zero has no trailing term") + return self.terms[-1] + + @property + def is_successor_ordinal(self): + try: + return self.trailing_term.exp == ord0 + except ValueError: + return False + + @property + def is_limit_ordinal(self): + try: + return not self.trailing_term.exp == ord0 + except ValueError: + return False + + @property + def degree(self): + return self.leading_term.exp + + @classmethod + def convert(cls, integer_value): + if integer_value == 0: + return ord0 + return Ordinal(OmegaPower(0, integer_value)) + + def __eq__(self, other): + if not isinstance(other, Ordinal): + try: + other = Ordinal.convert(other) + except TypeError: + return NotImplemented + return self.terms == other.terms + + def __hash__(self): + return hash(self.args) + + def __lt__(self, other): + if not isinstance(other, Ordinal): + try: + other = Ordinal.convert(other) + except TypeError: + return NotImplemented + for term_self, term_other in zip(self.terms, other.terms): + if term_self != term_other: + return term_self < term_other + return len(self.terms) < len(other.terms) + + def __le__(self, other): + return (self == other or self < other) + + def __gt__(self, other): + return not self <= other + + def __ge__(self, other): + return not self < other + + def __str__(self): + net_str = "" + plus_count = 0 + if self == ord0: + return 'ord0' + for i in self.terms: + if plus_count: + net_str += " + " + + if i.exp == ord0: + net_str += str(i.mult) + elif i.exp == 1: + net_str += 'w' + elif len(i.exp.terms) > 1 or i.exp.is_limit_ordinal: + net_str += 'w**(%s)'%i.exp + else: + net_str += 'w**%s'%i.exp + + if not i.mult == 1 and not i.exp == ord0: + net_str += '*%s'%i.mult + + plus_count += 1 + return(net_str) + + __repr__ = __str__ + + def __add__(self, other): + if not isinstance(other, Ordinal): + try: + other = Ordinal.convert(other) + except TypeError: + return NotImplemented + if other == ord0: + return self + a_terms = list(self.terms) + b_terms = list(other.terms) + r = len(a_terms) - 1 + b_exp = other.degree + while r >= 0 and a_terms[r].exp < b_exp: + r -= 1 + if r < 0: + terms = b_terms + elif a_terms[r].exp == b_exp: + sum_term = OmegaPower(b_exp, a_terms[r].mult + other.leading_term.mult) + terms = a_terms[:r] + [sum_term] + b_terms[1:] + else: + terms = a_terms[:r+1] + b_terms + return Ordinal(*terms) + + def __radd__(self, other): + if not isinstance(other, Ordinal): + try: + other = Ordinal.convert(other) + except TypeError: + return NotImplemented + return other + self + + def __mul__(self, other): + if not isinstance(other, Ordinal): + try: + other = Ordinal.convert(other) + except TypeError: + return NotImplemented + if ord0 in (self, other): + return ord0 + a_exp = self.degree + a_mult = self.leading_term.mult + summation = [] + if other.is_limit_ordinal: + for arg in other.terms: + summation.append(OmegaPower(a_exp + arg.exp, arg.mult)) + + else: + for arg in other.terms[:-1]: + summation.append(OmegaPower(a_exp + arg.exp, arg.mult)) + b_mult = other.trailing_term.mult + summation.append(OmegaPower(a_exp, a_mult*b_mult)) + summation += list(self.terms[1:]) + return Ordinal(*summation) + + def __rmul__(self, other): + if not isinstance(other, Ordinal): + try: + other = Ordinal.convert(other) + except TypeError: + return NotImplemented + return other * self + + def __pow__(self, other): + if not self == omega: + return NotImplemented + return Ordinal(OmegaPower(other, 1)) + + +class OrdinalZero(Ordinal): + """The ordinal zero. + + OrdinalZero can be imported as ``ord0``. + """ + pass + + +class OrdinalOmega(Ordinal): + """The ordinal omega which forms the base of all ordinals in cantor normal form. + + OrdinalOmega can be imported as ``omega``. + + Examples + ======== + + >>> from sympy.sets.ordinals import omega + >>> omega + omega + w*2 + """ + def __new__(cls): + return Ordinal.__new__(cls) + + @property + def terms(self): + return (OmegaPower(1, 1),) + + +ord0 = OrdinalZero() +omega = OrdinalOmega() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/powerset.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/powerset.py new file mode 100644 index 0000000000000000000000000000000000000000..2eb3b41b9859281480bc9517a1cad0abe7a5683f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/powerset.py @@ -0,0 +1,119 @@ +from sympy.core.decorators import _sympifyit +from sympy.core.parameters import global_parameters +from sympy.core.logic import fuzzy_bool +from sympy.core.singleton import S +from sympy.core.sympify import _sympify + +from .sets import Set, FiniteSet, SetKind + + +class PowerSet(Set): + r"""A symbolic object representing a power set. + + Parameters + ========== + + arg : Set + The set to take power of. + + evaluate : bool + The flag to control evaluation. + + If the evaluation is disabled for finite sets, it can take + advantage of using subset test as a membership test. + + Notes + ===== + + Power set `\mathcal{P}(S)` is defined as a set containing all the + subsets of `S`. + + If the set `S` is a finite set, its power set would have + `2^{\left| S \right|}` elements, where `\left| S \right|` denotes + the cardinality of `S`. + + Examples + ======== + + >>> from sympy import PowerSet, S, FiniteSet + + A power set of a finite set: + + >>> PowerSet(FiniteSet(1, 2, 3)) + PowerSet({1, 2, 3}) + + A power set of an empty set: + + >>> PowerSet(S.EmptySet) + PowerSet(EmptySet) + >>> PowerSet(PowerSet(S.EmptySet)) + PowerSet(PowerSet(EmptySet)) + + A power set of an infinite set: + + >>> PowerSet(S.Reals) + PowerSet(Reals) + + Evaluating the power set of a finite set to its explicit form: + + >>> PowerSet(FiniteSet(1, 2, 3)).rewrite(FiniteSet) + FiniteSet(EmptySet, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Power_set + + .. [2] https://en.wikipedia.org/wiki/Axiom_of_power_set + """ + def __new__(cls, arg, evaluate=None): + if evaluate is None: + evaluate=global_parameters.evaluate + + arg = _sympify(arg) + + if not isinstance(arg, Set): + raise ValueError('{} must be a set.'.format(arg)) + + return super().__new__(cls, arg) + + @property + def arg(self): + return self.args[0] + + def _eval_rewrite_as_FiniteSet(self, *args, **kwargs): + arg = self.arg + if arg.is_FiniteSet: + return arg.powerset() + return None + + @_sympifyit('other', NotImplemented) + def _contains(self, other): + if not isinstance(other, Set): + return None + + return fuzzy_bool(self.arg.is_superset(other)) + + def _eval_is_subset(self, other): + if isinstance(other, PowerSet): + return self.arg.is_subset(other.arg) + + def __len__(self): + return 2 ** len(self.arg) + + def __iter__(self): + found = [S.EmptySet] + yield S.EmptySet + + for x in self.arg: + temp = [] + x = FiniteSet(x) + for y in found: + new = x + y + yield new + temp.append(new) + found.extend(temp) + + @property + def kind(self): + return SetKind(self.arg.kind) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/setexpr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/setexpr.py new file mode 100644 index 0000000000000000000000000000000000000000..94d77d5293617a620b70a945888987ce6cc61157 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/setexpr.py @@ -0,0 +1,97 @@ +from sympy.core import Expr +from sympy.core.decorators import call_highest_priority, _sympifyit +from .fancysets import ImageSet +from .sets import set_add, set_sub, set_mul, set_div, set_pow, set_function + + +class SetExpr(Expr): + """An expression that can take on values of a set. + + Examples + ======== + + >>> from sympy import Interval, FiniteSet + >>> from sympy.sets.setexpr import SetExpr + + >>> a = SetExpr(Interval(0, 5)) + >>> b = SetExpr(FiniteSet(1, 10)) + >>> (a + b).set + Union(Interval(1, 6), Interval(10, 15)) + >>> (2*a + b).set + Interval(1, 20) + """ + _op_priority = 11.0 + + def __new__(cls, setarg): + return Expr.__new__(cls, setarg) + + set = property(lambda self: self.args[0]) + + def _latex(self, printer): + return r"SetExpr\left({}\right)".format(printer._print(self.set)) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__radd__') + def __add__(self, other): + return _setexpr_apply_operation(set_add, self, other) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__add__') + def __radd__(self, other): + return _setexpr_apply_operation(set_add, other, self) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__rmul__') + def __mul__(self, other): + return _setexpr_apply_operation(set_mul, self, other) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__mul__') + def __rmul__(self, other): + return _setexpr_apply_operation(set_mul, other, self) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__rsub__') + def __sub__(self, other): + return _setexpr_apply_operation(set_sub, self, other) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__sub__') + def __rsub__(self, other): + return _setexpr_apply_operation(set_sub, other, self) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__rpow__') + def __pow__(self, other): + return _setexpr_apply_operation(set_pow, self, other) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__pow__') + def __rpow__(self, other): + return _setexpr_apply_operation(set_pow, other, self) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__rtruediv__') + def __truediv__(self, other): + return _setexpr_apply_operation(set_div, self, other) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__truediv__') + def __rtruediv__(self, other): + return _setexpr_apply_operation(set_div, other, self) + + def _eval_func(self, func): + # TODO: this could be implemented straight into `imageset`: + res = set_function(func, self.set) + if res is None: + return SetExpr(ImageSet(func, self.set)) + return SetExpr(res) + + +def _setexpr_apply_operation(op, x, y): + if isinstance(x, SetExpr): + x = x.set + if isinstance(y, SetExpr): + y = y.set + out = op(x, y) + return SetExpr(out) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/sets.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/sets.py new file mode 100644 index 0000000000000000000000000000000000000000..3c85ce87c515cfd4520dcc6b9265fe76d8c6163f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sets/sets.py @@ -0,0 +1,2804 @@ +from __future__ import annotations + +from typing import Any, Callable, TYPE_CHECKING, overload +from functools import reduce +from collections import defaultdict +from collections.abc import Mapping, Iterable +import inspect + +from sympy.core.kind import Kind, UndefinedKind, NumberKind +from sympy.core.basic import Basic +from sympy.core.containers import Tuple, TupleKind +from sympy.core.decorators import sympify_method_args, sympify_return +from sympy.core.evalf import EvalfMixin +from sympy.core.expr import Expr +from sympy.core.function import Lambda +from sympy.core.logic import (FuzzyBool, fuzzy_bool, fuzzy_or, fuzzy_and, + fuzzy_not) +from sympy.core.numbers import Float, Integer +from sympy.core.operations import LatticeOp +from sympy.core.parameters import global_parameters +from sympy.core.relational import Eq, Ne, is_lt +from sympy.core.singleton import Singleton, S +from sympy.core.sorting import ordered +from sympy.core.symbol import symbols, Symbol, Dummy, uniquely_named_symbol +from sympy.core.sympify import _sympify, sympify, _sympy_converter +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.miscellaneous import Max, Min +from sympy.logic.boolalg import And, Or, Not, Xor, true, false +from sympy.utilities.decorator import deprecated +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import (iproduct, sift, roundrobin, iterable, + subsets) +from sympy.utilities.misc import func_name, filldedent + +from mpmath import mpi, mpf + +from mpmath.libmp.libmpf import prec_to_dps + + +tfn = defaultdict(lambda: None, { + True: S.true, + S.true: S.true, + False: S.false, + S.false: S.false}) + + +@sympify_method_args +class Set(Basic, EvalfMixin): + """ + The base class for any kind of set. + + Explanation + =========== + + This is not meant to be used directly as a container of items. It does not + behave like the builtin ``set``; see :class:`FiniteSet` for that. + + Real intervals are represented by the :class:`Interval` class and unions of + sets by the :class:`Union` class. The empty set is represented by the + :class:`EmptySet` class and available as a singleton as ``S.EmptySet``. + """ + + __slots__: tuple[()] = () + + is_number = False + is_iterable = False + is_interval = False + + is_FiniteSet = False + is_Interval = False + is_ProductSet = False + is_Union = False + is_Intersection: FuzzyBool = None + is_UniversalSet: FuzzyBool = None + is_Complement: FuzzyBool = None + is_ComplexRegion = False + + is_empty: FuzzyBool = None + is_finite_set: FuzzyBool = None + + @property # type: ignore + @deprecated( + """ + The is_EmptySet attribute of Set objects is deprecated. + Use 's is S.EmptySet" or 's.is_empty' instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-is-emptyset", + ) + def is_EmptySet(self): + return None + + if TYPE_CHECKING: + + def __new__(cls, *args: Basic | complex) -> Set: + ... + + @overload # type: ignore + def subs(self, arg1: Mapping[Basic | complex, Set | complex], arg2: None=None) -> Set: ... + @overload + def subs(self, arg1: Iterable[tuple[Basic | complex, Set | complex]], arg2: None=None, **kwargs: Any) -> Set: ... + @overload + def subs(self, arg1: Set | complex, arg2: Set | complex) -> Set: ... + @overload + def subs(self, arg1: Mapping[Basic | complex, Basic | complex], arg2: None=None, **kwargs: Any) -> Basic: ... + @overload + def subs(self, arg1: Iterable[tuple[Basic | complex, Basic | complex]], arg2: None=None, **kwargs: Any) -> Basic: ... + @overload + def subs(self, arg1: Basic | complex, arg2: Basic | complex, **kwargs: Any) -> Basic: ... + + def subs(self, arg1: Mapping[Basic | complex, Basic | complex] | Basic | complex, # type: ignore + arg2: Basic | complex | None = None, **kwargs: Any) -> Basic: + ... + + def simplify(self, **kwargs) -> Set: + assert False + + def evalf(self, n: int = 15, subs: dict[Basic, Basic | float] | None = None, + maxn: int = 100, chop: bool = False, strict: bool = False, + quad: str | None = None, verbose: bool = False) -> Set: + ... + + n = evalf + + @staticmethod + def _infimum_key(expr): + """ + Return infimum (if possible) else S.Infinity. + """ + try: + infimum = expr.inf + assert infimum.is_comparable + infimum = infimum.evalf() # issue #18505 + except (NotImplementedError, + AttributeError, AssertionError, ValueError): + infimum = S.Infinity + return infimum + + def union(self, other): + """ + Returns the union of ``self`` and ``other``. + + Examples + ======== + + As a shortcut it is possible to use the ``+`` operator: + + >>> from sympy import Interval, FiniteSet + >>> Interval(0, 1).union(Interval(2, 3)) + Union(Interval(0, 1), Interval(2, 3)) + >>> Interval(0, 1) + Interval(2, 3) + Union(Interval(0, 1), Interval(2, 3)) + >>> Interval(1, 2, True, True) + FiniteSet(2, 3) + Union({3}, Interval.Lopen(1, 2)) + + Similarly it is possible to use the ``-`` operator for set differences: + + >>> Interval(0, 2) - Interval(0, 1) + Interval.Lopen(1, 2) + >>> Interval(1, 3) - FiniteSet(2) + Union(Interval.Ropen(1, 2), Interval.Lopen(2, 3)) + + """ + return Union(self, other) + + def intersect(self, other): + """ + Returns the intersection of 'self' and 'other'. + + Examples + ======== + + >>> from sympy import Interval + + >>> Interval(1, 3).intersect(Interval(1, 2)) + Interval(1, 2) + + >>> from sympy import imageset, Lambda, symbols, S + >>> n, m = symbols('n m') + >>> a = imageset(Lambda(n, 2*n), S.Integers) + >>> a.intersect(imageset(Lambda(m, 2*m + 1), S.Integers)) + EmptySet + + """ + return Intersection(self, other) + + def intersection(self, other): + """ + Alias for :meth:`intersect()` + """ + return self.intersect(other) + + def is_disjoint(self, other): + """ + Returns True if ``self`` and ``other`` are disjoint. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 2).is_disjoint(Interval(1, 2)) + False + >>> Interval(0, 2).is_disjoint(Interval(3, 4)) + True + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Disjoint_sets + """ + return self.intersect(other) == S.EmptySet + + def isdisjoint(self, other): + """ + Alias for :meth:`is_disjoint()` + """ + return self.is_disjoint(other) + + def complement(self, universe): + r""" + The complement of 'self' w.r.t the given universe. + + Examples + ======== + + >>> from sympy import Interval, S + >>> Interval(0, 1).complement(S.Reals) + Union(Interval.open(-oo, 0), Interval.open(1, oo)) + + >>> Interval(0, 1).complement(S.UniversalSet) + Complement(UniversalSet, Interval(0, 1)) + + """ + return Complement(universe, self) + + def _complement(self, other): + # this behaves as other - self + if isinstance(self, ProductSet) and isinstance(other, ProductSet): + # If self and other are disjoint then other - self == self + if len(self.sets) != len(other.sets): + return other + + # There can be other ways to represent this but this gives: + # (A x B) - (C x D) = ((A - C) x B) U (A x (B - D)) + overlaps = [] + pairs = list(zip(self.sets, other.sets)) + for n in range(len(pairs)): + sets = (o if i != n else o-s for i, (s, o) in enumerate(pairs)) + overlaps.append(ProductSet(*sets)) + return Union(*overlaps) + + elif isinstance(other, Interval): + if isinstance(self, (Interval, FiniteSet)): + return Intersection(other, self.complement(S.Reals)) + + elif isinstance(other, Union): + return Union(*(o - self for o in other.args)) + + elif isinstance(other, Complement): + return Complement(other.args[0], Union(other.args[1], self), evaluate=False) + + elif other is S.EmptySet: + return S.EmptySet + + elif isinstance(other, FiniteSet): + sifted = sift(other, lambda x: fuzzy_bool(self.contains(x))) + # ignore those that are contained in self + return Union(FiniteSet(*(sifted[False])), + Complement(FiniteSet(*(sifted[None])), self, evaluate=False) + if sifted[None] else S.EmptySet) + + def symmetric_difference(self, other): + """ + Returns symmetric difference of ``self`` and ``other``. + + Examples + ======== + + >>> from sympy import Interval, S + >>> Interval(1, 3).symmetric_difference(S.Reals) + Union(Interval.open(-oo, 1), Interval.open(3, oo)) + >>> Interval(1, 10).symmetric_difference(S.Reals) + Union(Interval.open(-oo, 1), Interval.open(10, oo)) + + >>> from sympy import S, EmptySet + >>> S.Reals.symmetric_difference(EmptySet) + Reals + + References + ========== + .. [1] https://en.wikipedia.org/wiki/Symmetric_difference + + """ + return SymmetricDifference(self, other) + + def _symmetric_difference(self, other): + return Union(Complement(self, other), Complement(other, self)) + + @property + def inf(self): + """ + The infimum of ``self``. + + Examples + ======== + + >>> from sympy import Interval, Union + >>> Interval(0, 1).inf + 0 + >>> Union(Interval(0, 1), Interval(2, 3)).inf + 0 + + """ + return self._inf + + @property + def _inf(self): + raise NotImplementedError("(%s)._inf" % self) + + @property + def sup(self): + """ + The supremum of ``self``. + + Examples + ======== + + >>> from sympy import Interval, Union + >>> Interval(0, 1).sup + 1 + >>> Union(Interval(0, 1), Interval(2, 3)).sup + 3 + + """ + return self._sup + + @property + def _sup(self): + raise NotImplementedError("(%s)._sup" % self) + + def contains(self, other): + """ + Returns a SymPy value indicating whether ``other`` is contained + in ``self``: ``true`` if it is, ``false`` if it is not, else + an unevaluated ``Contains`` expression (or, as in the case of + ConditionSet and a union of FiniteSet/Intervals, an expression + indicating the conditions for containment). + + Examples + ======== + + >>> from sympy import Interval, S + >>> from sympy.abc import x + + >>> Interval(0, 1).contains(0.5) + True + + As a shortcut it is possible to use the ``in`` operator, but that + will raise an error unless an affirmative true or false is not + obtained. + + >>> Interval(0, 1).contains(x) + (0 <= x) & (x <= 1) + >>> x in Interval(0, 1) + Traceback (most recent call last): + ... + TypeError: did not evaluate to a bool: None + + The result of 'in' is a bool, not a SymPy value + + >>> 1 in Interval(0, 2) + True + >>> _ is S.true + False + """ + from .contains import Contains + other = sympify(other, strict=True) + + c = self._contains(other) + if isinstance(c, Contains): + return c + if c is None: + return Contains(other, self, evaluate=False) + b = tfn[c] + if b is None: + return c + return b + + def _contains(self, other): + """Test if ``other`` is an element of the set ``self``. + + This is an internal method that is expected to be overridden by + subclasses of ``Set`` and will be called by the public + :func:`Set.contains` method or the :class:`Contains` expression. + + Parameters + ========== + + other: Sympified :class:`Basic` instance + The object whose membership in ``self`` is to be tested. + + Returns + ======= + + Symbolic :class:`Boolean` or ``None``. + + A return value of ``None`` indicates that it is unknown whether + ``other`` is contained in ``self``. Returning ``None`` from here + ensures that ``self.contains(other)`` or ``Contains(self, other)`` will + return an unevaluated :class:`Contains` expression. + + If not ``None`` then the returned value is a :class:`Boolean` that is + logically equivalent to the statement that ``other`` is an element of + ``self``. Usually this would be either ``S.true`` or ``S.false`` but + not always. + """ + raise NotImplementedError(f"{type(self).__name__}._contains") + + def is_subset(self, other): + """ + Returns True if ``self`` is a subset of ``other``. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 0.5).is_subset(Interval(0, 1)) + True + >>> Interval(0, 1).is_subset(Interval(0, 1, left_open=True)) + False + + """ + if not isinstance(other, Set): + raise ValueError("Unknown argument '%s'" % other) + + # Handle the trivial cases + if self == other: + return True + is_empty = self.is_empty + if is_empty is True: + return True + elif fuzzy_not(is_empty) and other.is_empty: + return False + if self.is_finite_set is False and other.is_finite_set: + return False + + # Dispatch on subclass rules + ret = self._eval_is_subset(other) + if ret is not None: + return ret + ret = other._eval_is_superset(self) + if ret is not None: + return ret + + # Use pairwise rules from multiple dispatch + from sympy.sets.handlers.issubset import is_subset_sets + ret = is_subset_sets(self, other) + if ret is not None: + return ret + + # Fall back on computing the intersection + # XXX: We shouldn't do this. A query like this should be handled + # without evaluating new Set objects. It should be the other way round + # so that the intersect method uses is_subset for evaluation. + if self.intersect(other) == self: + return True + + def _eval_is_subset(self, other): + '''Returns a fuzzy bool for whether self is a subset of other.''' + return None + + def _eval_is_superset(self, other): + '''Returns a fuzzy bool for whether self is a subset of other.''' + return None + + # This should be deprecated: + def issubset(self, other): + """ + Alias for :meth:`is_subset()` + """ + return self.is_subset(other) + + def is_proper_subset(self, other): + """ + Returns True if ``self`` is a proper subset of ``other``. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 0.5).is_proper_subset(Interval(0, 1)) + True + >>> Interval(0, 1).is_proper_subset(Interval(0, 1)) + False + + """ + if isinstance(other, Set): + return self != other and self.is_subset(other) + else: + raise ValueError("Unknown argument '%s'" % other) + + def is_superset(self, other): + """ + Returns True if ``self`` is a superset of ``other``. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 0.5).is_superset(Interval(0, 1)) + False + >>> Interval(0, 1).is_superset(Interval(0, 1, left_open=True)) + True + + """ + if isinstance(other, Set): + return other.is_subset(self) + else: + raise ValueError("Unknown argument '%s'" % other) + + # This should be deprecated: + def issuperset(self, other): + """ + Alias for :meth:`is_superset()` + """ + return self.is_superset(other) + + def is_proper_superset(self, other): + """ + Returns True if ``self`` is a proper superset of ``other``. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 1).is_proper_superset(Interval(0, 0.5)) + True + >>> Interval(0, 1).is_proper_superset(Interval(0, 1)) + False + + """ + if isinstance(other, Set): + return self != other and self.is_superset(other) + else: + raise ValueError("Unknown argument '%s'" % other) + + def _eval_powerset(self): + from .powerset import PowerSet + return PowerSet(self) + + def powerset(self): + """ + Find the Power set of ``self``. + + Examples + ======== + + >>> from sympy import EmptySet, FiniteSet, Interval + + A power set of an empty set: + + >>> A = EmptySet + >>> A.powerset() + {EmptySet} + + A power set of a finite set: + + >>> A = FiniteSet(1, 2) + >>> a, b, c = FiniteSet(1), FiniteSet(2), FiniteSet(1, 2) + >>> A.powerset() == FiniteSet(a, b, c, EmptySet) + True + + A power set of an interval: + + >>> Interval(1, 2).powerset() + PowerSet(Interval(1, 2)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Power_set + + """ + return self._eval_powerset() + + @property + def measure(self): + """ + The (Lebesgue) measure of ``self``. + + Examples + ======== + + >>> from sympy import Interval, Union + >>> Interval(0, 1).measure + 1 + >>> Union(Interval(0, 1), Interval(2, 3)).measure + 2 + + """ + return self._measure + + @property + def kind(self): + """ + The kind of a Set + + Explanation + =========== + + Any :class:`Set` will have kind :class:`SetKind` which is + parametrised by the kind of the elements of the set. For example + most sets are sets of numbers and will have kind + ``SetKind(NumberKind)``. If elements of sets are different in kind than + their kind will ``SetKind(UndefinedKind)``. See + :class:`sympy.core.kind.Kind` for an explanation of the kind system. + + Examples + ======== + + >>> from sympy import Interval, Matrix, FiniteSet, EmptySet, ProductSet, PowerSet + + >>> FiniteSet(Matrix([1, 2])).kind + SetKind(MatrixKind(NumberKind)) + + >>> Interval(1, 2).kind + SetKind(NumberKind) + + >>> EmptySet.kind + SetKind() + + A :class:`sympy.sets.powerset.PowerSet` is a set of sets: + + >>> PowerSet({1, 2, 3}).kind + SetKind(SetKind(NumberKind)) + + A :class:`ProductSet` represents the set of tuples of elements of + other sets. Its kind is :class:`sympy.core.containers.TupleKind` + parametrised by the kinds of the elements of those sets: + + >>> p = ProductSet(FiniteSet(1, 2), FiniteSet(3, 4)) + >>> list(p) + [(1, 3), (2, 3), (1, 4), (2, 4)] + >>> p.kind + SetKind(TupleKind(NumberKind, NumberKind)) + + When all elements of the set do not have same kind, the kind + will be returned as ``SetKind(UndefinedKind)``: + + >>> FiniteSet(0, Matrix([1, 2])).kind + SetKind(UndefinedKind) + + The kind of the elements of a set are given by the ``element_kind`` + attribute of ``SetKind``: + + >>> Interval(1, 2).kind.element_kind + NumberKind + + See Also + ======== + + NumberKind + sympy.core.kind.UndefinedKind + sympy.core.containers.TupleKind + MatrixKind + sympy.matrices.expressions.sets.MatrixSet + sympy.sets.conditionset.ConditionSet + Rationals + Naturals + Integers + sympy.sets.fancysets.ImageSet + sympy.sets.fancysets.Range + sympy.sets.fancysets.ComplexRegion + sympy.sets.powerset.PowerSet + sympy.sets.sets.ProductSet + sympy.sets.sets.Interval + sympy.sets.sets.Union + sympy.sets.sets.Intersection + sympy.sets.sets.Complement + sympy.sets.sets.EmptySet + sympy.sets.sets.UniversalSet + sympy.sets.sets.FiniteSet + sympy.sets.sets.SymmetricDifference + sympy.sets.sets.DisjointUnion + """ + return self._kind() + + @property + def boundary(self): + """ + The boundary or frontier of a set. + + Explanation + =========== + + A point x is on the boundary of a set S if + + 1. x is in the closure of S. + I.e. Every neighborhood of x contains a point in S. + 2. x is not in the interior of S. + I.e. There does not exist an open set centered on x contained + entirely within S. + + There are the points on the outer rim of S. If S is open then these + points need not actually be contained within S. + + For example, the boundary of an interval is its start and end points. + This is true regardless of whether or not the interval is open. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 1).boundary + {0, 1} + >>> Interval(0, 1, True, False).boundary + {0, 1} + """ + return self._boundary + + @property + def is_open(self): + """ + Property method to check whether a set is open. + + Explanation + =========== + + A set is open if and only if it has an empty intersection with its + boundary. In particular, a subset A of the reals is open if and only + if each one of its points is contained in an open interval that is a + subset of A. + + Examples + ======== + >>> from sympy import S + >>> S.Reals.is_open + True + >>> S.Rationals.is_open + False + """ + return Intersection(self, self.boundary).is_empty + + @property + def is_closed(self): + """ + A property method to check whether a set is closed. + + Explanation + =========== + + A set is closed if its complement is an open set. The closedness of a + subset of the reals is determined with respect to R and its standard + topology. + + Examples + ======== + >>> from sympy import Interval + >>> Interval(0, 1).is_closed + True + """ + return self.boundary.is_subset(self) + + @property + def closure(self): + """ + Property method which returns the closure of a set. + The closure is defined as the union of the set itself and its + boundary. + + Examples + ======== + >>> from sympy import S, Interval + >>> S.Reals.closure + Reals + >>> Interval(0, 1).closure + Interval(0, 1) + """ + return self + self.boundary + + @property + def interior(self): + """ + Property method which returns the interior of a set. + The interior of a set S consists all points of S that do not + belong to the boundary of S. + + Examples + ======== + >>> from sympy import Interval + >>> Interval(0, 1).interior + Interval.open(0, 1) + >>> Interval(0, 1).boundary.interior + EmptySet + """ + return self - self.boundary + + @property + def _boundary(self): + raise NotImplementedError() + + @property + def _measure(self): + raise NotImplementedError("(%s)._measure" % self) + + def _kind(self): + return SetKind(UndefinedKind) + + def _eval_evalf(self, prec): + dps = prec_to_dps(prec) + return self.func(*[arg.evalf(n=dps) for arg in self.args]) + + @sympify_return([('other', 'Set')], NotImplemented) + def __add__(self, other): + return self.union(other) + + @sympify_return([('other', 'Set')], NotImplemented) + def __or__(self, other): + return self.union(other) + + @sympify_return([('other', 'Set')], NotImplemented) + def __and__(self, other): + return self.intersect(other) + + @sympify_return([('other', 'Set')], NotImplemented) + def __mul__(self, other): + return ProductSet(self, other) + + @sympify_return([('other', 'Set')], NotImplemented) + def __xor__(self, other): + return SymmetricDifference(self, other) + + @sympify_return([('exp', Expr)], NotImplemented) + def __pow__(self, exp): + if not (exp.is_Integer and exp >= 0): + raise ValueError("%s: Exponent must be a positive Integer" % exp) + return ProductSet(*[self]*exp) + + @sympify_return([('other', 'Set')], NotImplemented) + def __sub__(self, other): + return Complement(self, other) + + def __contains__(self, other): + other = _sympify(other) + c = self._contains(other) + b = tfn[c] + if b is None: + # x in y must evaluate to T or F; to entertain a None + # result with Set use y.contains(x) + raise TypeError('did not evaluate to a bool: %r' % c) + return b + + +class ProductSet(Set): + """ + Represents a Cartesian Product of Sets. + + Explanation + =========== + + Returns a Cartesian product given several sets as either an iterable + or individual arguments. + + Can use ``*`` operator on any sets for convenient shorthand. + + Examples + ======== + + >>> from sympy import Interval, FiniteSet, ProductSet + >>> I = Interval(0, 5); S = FiniteSet(1, 2, 3) + >>> ProductSet(I, S) + ProductSet(Interval(0, 5), {1, 2, 3}) + + >>> (2, 2) in ProductSet(I, S) + True + + >>> Interval(0, 1) * Interval(0, 1) # The unit square + ProductSet(Interval(0, 1), Interval(0, 1)) + + >>> coin = FiniteSet('H', 'T') + >>> set(coin**2) + {(H, H), (H, T), (T, H), (T, T)} + + The Cartesian product is not commutative or associative e.g.: + + >>> I*S == S*I + False + >>> (I*I)*I == I*(I*I) + False + + Notes + ===== + + - Passes most operations down to the argument sets + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Cartesian_product + """ + is_ProductSet = True + + def __new__(cls, *sets, **assumptions): + if len(sets) == 1 and iterable(sets[0]) and not isinstance(sets[0], (Set, set)): + sympy_deprecation_warning( + """ +ProductSet(iterable) is deprecated. Use ProductSet(*iterable) instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-productset-iterable", + ) + sets = tuple(sets[0]) + + sets = [sympify(s) for s in sets] + + if not all(isinstance(s, Set) for s in sets): + raise TypeError("Arguments to ProductSet should be of type Set") + + # Nullary product of sets is *not* the empty set + if len(sets) == 0: + return FiniteSet(()) + + if S.EmptySet in sets: + return S.EmptySet + + return Basic.__new__(cls, *sets, **assumptions) + + @property + def sets(self): + return self.args + + def flatten(self): + def _flatten(sets): + for s in sets: + if s.is_ProductSet: + yield from _flatten(s.sets) + else: + yield s + return ProductSet(*_flatten(self.sets)) + + + + def _contains(self, element): + """ + ``in`` operator for ProductSets. + + Examples + ======== + + >>> from sympy import Interval + >>> (2, 3) in Interval(0, 5) * Interval(0, 5) + True + + >>> (10, 10) in Interval(0, 5) * Interval(0, 5) + False + + Passes operation on to constituent sets + """ + if element.is_Symbol: + return None + + if not isinstance(element, Tuple) or len(element) != len(self.sets): + return S.false + + return And(*[s.contains(e) for s, e in zip(self.sets, element)]) + + def as_relational(self, *symbols): + symbols = [_sympify(s) for s in symbols] + if len(symbols) != len(self.sets) or not all( + i.is_Symbol for i in symbols): + raise ValueError( + 'number of symbols must match the number of sets') + return And(*[s.as_relational(i) for s, i in zip(self.sets, symbols)]) + + @property + def _boundary(self): + return Union(*(ProductSet(*(b + b.boundary if i != j else b.boundary + for j, b in enumerate(self.sets))) + for i, a in enumerate(self.sets))) + + @property + def is_iterable(self): + """ + A property method which tests whether a set is iterable or not. + Returns True if set is iterable, otherwise returns False. + + Examples + ======== + + >>> from sympy import FiniteSet, Interval + >>> I = Interval(0, 1) + >>> A = FiniteSet(1, 2, 3, 4, 5) + >>> I.is_iterable + False + >>> A.is_iterable + True + + """ + return all(set.is_iterable for set in self.sets) + + def __iter__(self): + """ + A method which implements is_iterable property method. + If self.is_iterable returns True (both constituent sets are iterable), + then return the Cartesian Product. Otherwise, raise TypeError. + """ + return iproduct(*self.sets) + + @property + def is_empty(self): + return fuzzy_or(s.is_empty for s in self.sets) + + @property + def is_finite_set(self): + all_finite = fuzzy_and(s.is_finite_set for s in self.sets) + return fuzzy_or([self.is_empty, all_finite]) + + @property + def _measure(self): + measure = 1 + for s in self.sets: + measure *= s.measure + return measure + + def _kind(self): + return SetKind(TupleKind(*(i.kind.element_kind for i in self.args))) + + def __len__(self): + return reduce(lambda a, b: a*b, (len(s) for s in self.args)) + + def __bool__(self): + return all(self.sets) + + +class Interval(Set): + """ + Represents a real interval as a Set. + + Usage: + Returns an interval with end points ``start`` and ``end``. + + For ``left_open=True`` (default ``left_open`` is ``False``) the interval + will be open on the left. Similarly, for ``right_open=True`` the interval + will be open on the right. + + Examples + ======== + + >>> from sympy import Symbol, Interval + >>> Interval(0, 1) + Interval(0, 1) + >>> Interval.Ropen(0, 1) + Interval.Ropen(0, 1) + >>> Interval.Ropen(0, 1) + Interval.Ropen(0, 1) + >>> Interval.Lopen(0, 1) + Interval.Lopen(0, 1) + >>> Interval.open(0, 1) + Interval.open(0, 1) + + >>> a = Symbol('a', real=True) + >>> Interval(0, a) + Interval(0, a) + + Notes + ===== + - Only real end points are supported + - ``Interval(a, b)`` with $a > b$ will return the empty set + - Use the ``evalf()`` method to turn an Interval into an mpmath + ``mpi`` interval instance + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Interval_%28mathematics%29 + """ + is_Interval = True + + def __new__(cls, start, end, left_open=False, right_open=False): + + start = _sympify(start) + end = _sympify(end) + left_open = _sympify(left_open) + right_open = _sympify(right_open) + + if not all(isinstance(a, (type(true), type(false))) + for a in [left_open, right_open]): + raise NotImplementedError( + "left_open and right_open can have only true/false values, " + "got %s and %s" % (left_open, right_open)) + + # Only allow real intervals + if fuzzy_not(fuzzy_and(i.is_extended_real for i in (start, end, end-start))): + raise ValueError("Non-real intervals are not supported") + + # evaluate if possible + if is_lt(end, start): + return S.EmptySet + elif (end - start).is_negative: + return S.EmptySet + + if end == start and (left_open or right_open): + return S.EmptySet + if end == start and not (left_open or right_open): + if start is S.Infinity or start is S.NegativeInfinity: + return S.EmptySet + return FiniteSet(end) + + # Make sure infinite interval end points are open. + if start is S.NegativeInfinity: + left_open = true + if end is S.Infinity: + right_open = true + if start == S.Infinity or end == S.NegativeInfinity: + return S.EmptySet + + return Basic.__new__(cls, start, end, left_open, right_open) + + @property + def start(self): + """ + The left end point of the interval. + + This property takes the same value as the ``inf`` property. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 1).start + 0 + + """ + return self._args[0] + + @property + def end(self): + """ + The right end point of the interval. + + This property takes the same value as the ``sup`` property. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 1).end + 1 + + """ + return self._args[1] + + @property + def left_open(self): + """ + True if interval is left-open. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 1, left_open=True).left_open + True + >>> Interval(0, 1, left_open=False).left_open + False + + """ + return self._args[2] + + @property + def right_open(self): + """ + True if interval is right-open. + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(0, 1, right_open=True).right_open + True + >>> Interval(0, 1, right_open=False).right_open + False + + """ + return self._args[3] + + @classmethod + def open(cls, a, b): + """Return an interval including neither boundary.""" + return cls(a, b, True, True) + + @classmethod + def Lopen(cls, a, b): + """Return an interval not including the left boundary.""" + return cls(a, b, True, False) + + @classmethod + def Ropen(cls, a, b): + """Return an interval not including the right boundary.""" + return cls(a, b, False, True) + + @property + def _inf(self): + return self.start + + @property + def _sup(self): + return self.end + + @property + def left(self): + return self.start + + @property + def right(self): + return self.end + + @property + def is_empty(self): + if self.left_open or self.right_open: + cond = self.start >= self.end # One/both bounds open + else: + cond = self.start > self.end # Both bounds closed + return fuzzy_bool(cond) + + @property + def is_finite_set(self): + return self.measure.is_zero + + def _complement(self, other): + if other == S.Reals: + a = Interval(S.NegativeInfinity, self.start, + True, not self.left_open) + b = Interval(self.end, S.Infinity, not self.right_open, True) + return Union(a, b) + + if isinstance(other, FiniteSet): + nums = [m for m in other.args if m.is_number] + if nums == []: + return None + + return Set._complement(self, other) + + @property + def _boundary(self): + finite_points = [p for p in (self.start, self.end) + if abs(p) != S.Infinity] + return FiniteSet(*finite_points) + + def _contains(self, other): + if (not isinstance(other, Expr) or other is S.NaN + or other.is_real is False or other.has(S.ComplexInfinity)): + # if an expression has zoo it will be zoo or nan + # and neither of those is real + return false + + if self.start is S.NegativeInfinity and self.end is S.Infinity: + if other.is_real is not None: + return tfn[other.is_real] + + d = Dummy() + return self.as_relational(d).subs(d, other) + + def as_relational(self, x): + """Rewrite an interval in terms of inequalities and logic operators.""" + x = sympify(x) + if self.right_open: + right = x < self.end + else: + right = x <= self.end + if self.left_open: + left = self.start < x + else: + left = self.start <= x + return And(left, right) + + @property + def _measure(self): + return self.end - self.start + + def _kind(self): + return SetKind(NumberKind) + + def to_mpi(self, prec=53): + return mpi(mpf(self.start._eval_evalf(prec)), + mpf(self.end._eval_evalf(prec))) + + def _eval_evalf(self, prec): + return Interval(self.left._evalf(prec), self.right._evalf(prec), + left_open=self.left_open, right_open=self.right_open) + + def _is_comparable(self, other): + is_comparable = self.start.is_comparable + is_comparable &= self.end.is_comparable + is_comparable &= other.start.is_comparable + is_comparable &= other.end.is_comparable + + return is_comparable + + @property + def is_left_unbounded(self): + """Return ``True`` if the left endpoint is negative infinity. """ + return self.left is S.NegativeInfinity or self.left == Float("-inf") + + @property + def is_right_unbounded(self): + """Return ``True`` if the right endpoint is positive infinity. """ + return self.right is S.Infinity or self.right == Float("+inf") + + def _eval_Eq(self, other): + if not isinstance(other, Interval): + if isinstance(other, FiniteSet): + return false + elif isinstance(other, Set): + return None + return false + + +class Union(Set, LatticeOp): + """ + Represents a union of sets as a :class:`Set`. + + Examples + ======== + + >>> from sympy import Union, Interval + >>> Union(Interval(1, 2), Interval(3, 4)) + Union(Interval(1, 2), Interval(3, 4)) + + The Union constructor will always try to merge overlapping intervals, + if possible. For example: + + >>> Union(Interval(1, 2), Interval(2, 3)) + Interval(1, 3) + + See Also + ======== + + Intersection + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Union_%28set_theory%29 + """ + is_Union = True + + @property + def identity(self): + return S.EmptySet + + @property + def zero(self): + return S.UniversalSet + + def __new__(cls, *args, **kwargs): + evaluate = kwargs.get('evaluate', global_parameters.evaluate) + + # flatten inputs to merge intersections and iterables + args = _sympify(args) + + # Reduce sets using known rules + if evaluate: + args = list(cls._new_args_filter(args)) + return simplify_union(args) + + args = list(ordered(args, Set._infimum_key)) + + obj = Basic.__new__(cls, *args) + obj._argset = frozenset(args) + return obj + + @property + def args(self): + return self._args + + def _complement(self, universe): + # DeMorgan's Law + return Intersection(s.complement(universe) for s in self.args) + + @property + def _inf(self): + # We use Min so that sup is meaningful in combination with symbolic + # interval end points. + return Min(*[set.inf for set in self.args]) + + @property + def _sup(self): + # We use Max so that sup is meaningful in combination with symbolic + # end points. + return Max(*[set.sup for set in self.args]) + + @property + def is_empty(self): + return fuzzy_and(set.is_empty for set in self.args) + + @property + def is_finite_set(self): + return fuzzy_and(set.is_finite_set for set in self.args) + + @property + def _measure(self): + # Measure of a union is the sum of the measures of the sets minus + # the sum of their pairwise intersections plus the sum of their + # triple-wise intersections minus ... etc... + + # Sets is a collection of intersections and a set of elementary + # sets which made up those intersections (called "sos" for set of sets) + # An example element might of this list might be: + # ( {A,B,C}, A.intersect(B).intersect(C) ) + + # Start with just elementary sets ( ({A}, A), ({B}, B), ... ) + # Then get and subtract ( ({A,B}, (A int B), ... ) while non-zero + sets = [(FiniteSet(s), s) for s in self.args] + measure = 0 + parity = 1 + while sets: + # Add up the measure of these sets and add or subtract it to total + measure += parity * sum(inter.measure for sos, inter in sets) + + # For each intersection in sets, compute the intersection with every + # other set not already part of the intersection. + sets = ((sos + FiniteSet(newset), newset.intersect(intersection)) + for sos, intersection in sets for newset in self.args + if newset not in sos) + + # Clear out sets with no measure + sets = [(sos, inter) for sos, inter in sets if inter.measure != 0] + + # Clear out duplicates + sos_list = [] + sets_list = [] + for _set in sets: + if _set[0] in sos_list: + continue + else: + sos_list.append(_set[0]) + sets_list.append(_set) + sets = sets_list + + # Flip Parity - next time subtract/add if we added/subtracted here + parity *= -1 + return measure + + def _kind(self): + kinds = tuple(arg.kind for arg in self.args if arg is not S.EmptySet) + if not kinds: + return SetKind() + elif all(i == kinds[0] for i in kinds): + return kinds[0] + else: + return SetKind(UndefinedKind) + + @property + def _boundary(self): + def boundary_of_set(i): + """ The boundary of set i minus interior of all other sets """ + b = self.args[i].boundary + for j, a in enumerate(self.args): + if j != i: + b = b - a.interior + return b + return Union(*map(boundary_of_set, range(len(self.args)))) + + def _contains(self, other): + return Or(*[s.contains(other) for s in self.args]) + + def is_subset(self, other): + return fuzzy_and(s.is_subset(other) for s in self.args) + + def as_relational(self, symbol): + """Rewrite a Union in terms of equalities and logic operators. """ + if (len(self.args) == 2 and + all(isinstance(i, Interval) for i in self.args)): + # optimization to give 3 args as (x > 1) & (x < 5) & Ne(x, 3) + # instead of as 4, ((1 <= x) & (x < 3)) | ((x <= 5) & (3 < x)) + # XXX: This should be ideally be improved to handle any number of + # intervals and also not to assume that the intervals are in any + # particular sorted order. + a, b = self.args + if a.sup == b.inf and a.right_open and b.left_open: + mincond = symbol > a.inf if a.left_open else symbol >= a.inf + maxcond = symbol < b.sup if b.right_open else symbol <= b.sup + necond = Ne(symbol, a.sup) + return And(necond, mincond, maxcond) + return Or(*[i.as_relational(symbol) for i in self.args]) + + @property + def is_iterable(self): + return all(arg.is_iterable for arg in self.args) + + def __iter__(self): + return roundrobin(*(iter(arg) for arg in self.args)) + + +class Intersection(Set, LatticeOp): + """ + Represents an intersection of sets as a :class:`Set`. + + Examples + ======== + + >>> from sympy import Intersection, Interval + >>> Intersection(Interval(1, 3), Interval(2, 4)) + Interval(2, 3) + + We often use the .intersect method + + >>> Interval(1,3).intersect(Interval(2,4)) + Interval(2, 3) + + See Also + ======== + + Union + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Intersection_%28set_theory%29 + """ + is_Intersection = True + + @property + def identity(self): + return S.UniversalSet + + @property + def zero(self): + return S.EmptySet + + def __new__(cls, *args , evaluate=None): + if evaluate is None: + evaluate = global_parameters.evaluate + + # flatten inputs to merge intersections and iterables + args = list(ordered(set(_sympify(args)))) + + # Reduce sets using known rules + if evaluate: + args = list(cls._new_args_filter(args)) + return simplify_intersection(args) + + args = list(ordered(args, Set._infimum_key)) + + obj = Basic.__new__(cls, *args) + obj._argset = frozenset(args) + return obj + + @property + def args(self): + return self._args + + @property + def is_iterable(self): + return any(arg.is_iterable for arg in self.args) + + @property + def is_finite_set(self): + if fuzzy_or(arg.is_finite_set for arg in self.args): + return True + + def _kind(self): + kinds = tuple(arg.kind for arg in self.args if arg is not S.UniversalSet) + if not kinds: + return SetKind(UndefinedKind) + elif all(i == kinds[0] for i in kinds): + return kinds[0] + else: + return SetKind() + + @property + def _inf(self): + raise NotImplementedError() + + @property + def _sup(self): + raise NotImplementedError() + + def _contains(self, other): + return And(*[set.contains(other) for set in self.args]) + + def __iter__(self): + sets_sift = sift(self.args, lambda x: x.is_iterable) + + completed = False + candidates = sets_sift[True] + sets_sift[None] + + finite_candidates, others = [], [] + for candidate in candidates: + length = None + try: + length = len(candidate) + except TypeError: + others.append(candidate) + + if length is not None: + finite_candidates.append(candidate) + finite_candidates.sort(key=len) + + for s in finite_candidates + others: + other_sets = set(self.args) - {s} + other = Intersection(*other_sets, evaluate=False) + completed = True + for x in s: + try: + if x in other: + yield x + except TypeError: + completed = False + if completed: + return + + if not completed: + if not candidates: + raise TypeError("None of the constituent sets are iterable") + raise TypeError( + "The computation had not completed because of the " + "undecidable set membership is found in every candidates.") + + @staticmethod + def _handle_finite_sets(args): + '''Simplify intersection of one or more FiniteSets and other sets''' + + # First separate the FiniteSets from the others + fs_args, others = sift(args, lambda x: x.is_FiniteSet, binary=True) + + # Let the caller handle intersection of non-FiniteSets + if not fs_args: + return + + # Convert to Python sets and build the set of all elements + fs_sets = [set(fs) for fs in fs_args] + all_elements = reduce(lambda a, b: a | b, fs_sets, set()) + + # Extract elements that are definitely in or definitely not in the + # intersection. Here we check contains for all of args. + definite = set() + for e in all_elements: + inall = fuzzy_and(s.contains(e) for s in args) + if inall is True: + definite.add(e) + if inall is not None: + for s in fs_sets: + s.discard(e) + + # At this point all elements in all of fs_sets are possibly in the + # intersection. In some cases this is because they are definitely in + # the intersection of the finite sets but it's not clear if they are + # members of others. We might have {m, n}, {m}, and Reals where we + # don't know if m or n is real. We want to remove n here but it is + # possibly in because it might be equal to m. So what we do now is + # extract the elements that are definitely in the remaining finite + # sets iteratively until we end up with {n}, {}. At that point if we + # get any empty set all remaining elements are discarded. + + fs_elements = reduce(lambda a, b: a | b, fs_sets, set()) + + # Need fuzzy containment testing + fs_symsets = [FiniteSet(*s) for s in fs_sets] + + while fs_elements: + for e in fs_elements: + infs = fuzzy_and(s.contains(e) for s in fs_symsets) + if infs is True: + definite.add(e) + if infs is not None: + for n, s in enumerate(fs_sets): + # Update Python set and FiniteSet + if e in s: + s.remove(e) + fs_symsets[n] = FiniteSet(*s) + fs_elements.remove(e) + break + # If we completed the for loop without removing anything we are + # done so quit the outer while loop + else: + break + + # If any of the sets of remainder elements is empty then we discard + # all of them for the intersection. + if not all(fs_sets): + fs_sets = [set()] + + # Here we fold back the definitely included elements into each fs. + # Since they are definitely included they must have been members of + # each FiniteSet to begin with. We could instead fold these in with a + # Union at the end to get e.g. {3}|({x}&{y}) rather than {3,x}&{3,y}. + if definite: + fs_sets = [fs | definite for fs in fs_sets] + + if fs_sets == [set()]: + return S.EmptySet + + sets = [FiniteSet(*s) for s in fs_sets] + + # Any set in others is redundant if it contains all the elements that + # are in the finite sets so we don't need it in the Intersection + all_elements = reduce(lambda a, b: a | b, fs_sets, set()) + is_redundant = lambda o: all(fuzzy_bool(o.contains(e)) for e in all_elements) + others = [o for o in others if not is_redundant(o)] + + if others: + rest = Intersection(*others) + # XXX: Maybe this shortcut should be at the beginning. For large + # FiniteSets it could much more efficient to process the other + # sets first... + if rest is S.EmptySet: + return S.EmptySet + # Flatten the Intersection + if rest.is_Intersection: + sets.extend(rest.args) + else: + sets.append(rest) + + if len(sets) == 1: + return sets[0] + else: + return Intersection(*sets, evaluate=False) + + def as_relational(self, symbol): + """Rewrite an Intersection in terms of equalities and logic operators""" + return And(*[set.as_relational(symbol) for set in self.args]) + + +class Complement(Set): + r"""Represents the set difference or relative complement of a set with + another set. + + $$A - B = \{x \in A \mid x \notin B\}$$ + + + Examples + ======== + + >>> from sympy import Complement, FiniteSet + >>> Complement(FiniteSet(0, 1, 2), FiniteSet(1)) + {0, 2} + + See Also + ========= + + Intersection, Union + + References + ========== + + .. [1] https://mathworld.wolfram.com/ComplementSet.html + """ + + is_Complement = True + + def __new__(cls, a, b, evaluate=True): + a, b = map(_sympify, (a, b)) + if evaluate: + return Complement.reduce(a, b) + + return Basic.__new__(cls, a, b) + + @staticmethod + def reduce(A, B): + """ + Simplify a :class:`Complement`. + + """ + if B == S.UniversalSet or A.is_subset(B): + return S.EmptySet + + if isinstance(B, Union): + return Intersection(*(s.complement(A) for s in B.args)) + + result = B._complement(A) + if result is not None: + return result + else: + return Complement(A, B, evaluate=False) + + def _contains(self, other): + A = self.args[0] + B = self.args[1] + return And(A.contains(other), Not(B.contains(other))) + + def as_relational(self, symbol): + """Rewrite a complement in terms of equalities and logic + operators""" + A, B = self.args + + A_rel = A.as_relational(symbol) + B_rel = Not(B.as_relational(symbol)) + + return And(A_rel, B_rel) + + def _kind(self): + return self.args[0].kind + + @property + def is_iterable(self): + if self.args[0].is_iterable: + return True + + @property + def is_finite_set(self): + A, B = self.args + a_finite = A.is_finite_set + if a_finite is True: + return True + elif a_finite is False and B.is_finite_set: + return False + + def __iter__(self): + A, B = self.args + for a in A: + if a not in B: + yield a + else: + continue + + +class EmptySet(Set, metaclass=Singleton): + """ + Represents the empty set. The empty set is available as a singleton + as ``S.EmptySet``. + + Examples + ======== + + >>> from sympy import S, Interval + >>> S.EmptySet + EmptySet + + >>> Interval(1, 2).intersect(S.EmptySet) + EmptySet + + See Also + ======== + + UniversalSet + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Empty_set + """ + is_empty = True + is_finite_set = True + is_FiniteSet = True + + @property # type: ignore + @deprecated( + """ + The is_EmptySet attribute of Set objects is deprecated. + Use 's is S.EmptySet" or 's.is_empty' instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-is-emptyset", + ) + def is_EmptySet(self): + return True + + @property + def _measure(self): + return 0 + + def _contains(self, other): + return false + + def as_relational(self, symbol): + return false + + def __len__(self): + return 0 + + def __iter__(self): + return iter([]) + + def _eval_powerset(self): + return FiniteSet(self) + + @property + def _boundary(self): + return self + + def _complement(self, other): + return other + + def _kind(self): + return SetKind() + + def _symmetric_difference(self, other): + return other + + +class UniversalSet(Set, metaclass=Singleton): + """ + Represents the set of all things. + The universal set is available as a singleton as ``S.UniversalSet``. + + Examples + ======== + + >>> from sympy import S, Interval + >>> S.UniversalSet + UniversalSet + + >>> Interval(1, 2).intersect(S.UniversalSet) + Interval(1, 2) + + See Also + ======== + + EmptySet + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Universal_set + """ + + is_UniversalSet = True + is_empty = False + is_finite_set = False + + def _complement(self, other): + return S.EmptySet + + def _symmetric_difference(self, other): + return other + + @property + def _measure(self): + return S.Infinity + + def _kind(self): + return SetKind(UndefinedKind) + + def _contains(self, other): + return true + + def as_relational(self, symbol): + return true + + @property + def _boundary(self): + return S.EmptySet + + +class FiniteSet(Set): + """ + Represents a finite set of Sympy expressions. + + Examples + ======== + + >>> from sympy import FiniteSet, Symbol, Interval, Naturals0 + >>> FiniteSet(1, 2, 3, 4) + {1, 2, 3, 4} + >>> 3 in FiniteSet(1, 2, 3, 4) + True + >>> FiniteSet(1, (1, 2), Symbol('x')) + {1, x, (1, 2)} + >>> FiniteSet(Interval(1, 2), Naturals0, {1, 2}) + FiniteSet({1, 2}, Interval(1, 2), Naturals0) + >>> members = [1, 2, 3, 4] + >>> f = FiniteSet(*members) + >>> f + {1, 2, 3, 4} + >>> f - FiniteSet(2) + {1, 3, 4} + >>> f + FiniteSet(2, 5) + {1, 2, 3, 4, 5} + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Finite_set + """ + is_FiniteSet = True + is_iterable = True + is_empty = False + is_finite_set = True + + def __new__(cls, *args, **kwargs): + evaluate = kwargs.get('evaluate', global_parameters.evaluate) + if evaluate: + args = list(map(sympify, args)) + + if len(args) == 0: + return S.EmptySet + else: + args = list(map(sympify, args)) + + # keep the form of the first canonical arg + dargs = {} + for i in reversed(list(ordered(args))): + if i.is_Symbol: + dargs[i] = i + else: + try: + dargs[i.as_dummy()] = i + except TypeError: + # e.g. i = class without args like `Interval` + dargs[i] = i + _args_set = set(dargs.values()) + args = list(ordered(_args_set, Set._infimum_key)) + obj = Basic.__new__(cls, *args) + obj._args_set = _args_set + return obj + + + def __iter__(self): + return iter(self.args) + + def _complement(self, other): + if isinstance(other, Interval): + # Splitting in sub-intervals is only done for S.Reals; + # other cases that need splitting will first pass through + # Set._complement(). + nums, syms = [], [] + for m in self.args: + if m.is_number and m.is_real: + nums.append(m) + elif m.is_real == False: + pass # drop non-reals + else: + syms.append(m) # various symbolic expressions + if other == S.Reals and nums != []: + nums.sort() + intervals = [] # Build up a list of intervals between the elements + intervals += [Interval(S.NegativeInfinity, nums[0], True, True)] + for a, b in zip(nums[:-1], nums[1:]): + intervals.append(Interval(a, b, True, True)) # both open + intervals.append(Interval(nums[-1], S.Infinity, True, True)) + if syms != []: + return Complement(Union(*intervals, evaluate=False), + FiniteSet(*syms), evaluate=False) + else: + return Union(*intervals, evaluate=False) + elif nums == []: # no splitting necessary or possible: + if syms: + return Complement(other, FiniteSet(*syms), evaluate=False) + else: + return other + + elif isinstance(other, FiniteSet): + unk = [] + for i in self: + c = sympify(other.contains(i)) + if c is not S.true and c is not S.false: + unk.append(i) + unk = FiniteSet(*unk) + if unk == self: + return + not_true = [] + for i in other: + c = sympify(self.contains(i)) + if c is not S.true: + not_true.append(i) + return Complement(FiniteSet(*not_true), unk) + + return Set._complement(self, other) + + def _contains(self, other): + """ + Tests whether an element, other, is in the set. + + Explanation + =========== + + The actual test is for mathematical equality (as opposed to + syntactical equality). In the worst case all elements of the + set must be checked. + + Examples + ======== + + >>> from sympy import FiniteSet + >>> 1 in FiniteSet(1, 2) + True + >>> 5 in FiniteSet(1, 2) + False + + """ + if other in self._args_set: + return S.true + else: + # evaluate=True is needed to override evaluate=False context; + # we need Eq to do the evaluation + return Or(*[Eq(e, other, evaluate=True) for e in self.args]) + + def _eval_is_subset(self, other): + return fuzzy_and(other._contains(e) for e in self.args) + + @property + def _boundary(self): + return self + + @property + def _inf(self): + return Min(*self) + + @property + def _sup(self): + return Max(*self) + + @property + def measure(self): + return 0 + + def _kind(self): + if not self.args: + return SetKind() + elif all(i.kind == self.args[0].kind for i in self.args): + return SetKind(self.args[0].kind) + else: + return SetKind(UndefinedKind) + + def __len__(self): + return len(self.args) + + def as_relational(self, symbol): + """Rewrite a FiniteSet in terms of equalities and logic operators. """ + return Or(*[Eq(symbol, elem) for elem in self]) + + def compare(self, other): + return (hash(self) - hash(other)) + + def _eval_evalf(self, prec): + dps = prec_to_dps(prec) + return FiniteSet(*[elem.evalf(n=dps) for elem in self]) + + def _eval_simplify(self, **kwargs): + from sympy.simplify import simplify + return FiniteSet(*[simplify(elem, **kwargs) for elem in self]) + + @property + def _sorted_args(self): + return self.args + + def _eval_powerset(self): + return self.func(*[self.func(*s) for s in subsets(self.args)]) + + def _eval_rewrite_as_PowerSet(self, *args, **kwargs): + """Rewriting method for a finite set to a power set.""" + from .powerset import PowerSet + + is2pow = lambda n: bool(n and not n & (n - 1)) + if not is2pow(len(self)): + return None + + fs_test = lambda arg: isinstance(arg, Set) and arg.is_FiniteSet + if not all(fs_test(arg) for arg in args): + return None + + biggest = max(args, key=len) + for arg in subsets(biggest.args): + arg_set = FiniteSet(*arg) + if arg_set not in args: + return None + return PowerSet(biggest) + + def __ge__(self, other): + if not isinstance(other, Set): + raise TypeError("Invalid comparison of set with %s" % func_name(other)) + return other.is_subset(self) + + def __gt__(self, other): + if not isinstance(other, Set): + raise TypeError("Invalid comparison of set with %s" % func_name(other)) + return self.is_proper_superset(other) + + def __le__(self, other): + if not isinstance(other, Set): + raise TypeError("Invalid comparison of set with %s" % func_name(other)) + return self.is_subset(other) + + def __lt__(self, other): + if not isinstance(other, Set): + raise TypeError("Invalid comparison of set with %s" % func_name(other)) + return self.is_proper_subset(other) + + def __eq__(self, other): + if isinstance(other, (set, frozenset)): + return self._args_set == other + return super().__eq__(other) + + __hash__ : Callable[[Basic], Any] = Basic.__hash__ + +_sympy_converter[set] = lambda x: FiniteSet(*x) +_sympy_converter[frozenset] = lambda x: FiniteSet(*x) + + +class SymmetricDifference(Set): + """Represents the set of elements which are in either of the + sets and not in their intersection. + + Examples + ======== + + >>> from sympy import SymmetricDifference, FiniteSet + >>> SymmetricDifference(FiniteSet(1, 2, 3), FiniteSet(3, 4, 5)) + {1, 2, 4, 5} + + See Also + ======== + + Complement, Union + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Symmetric_difference + """ + + is_SymmetricDifference = True + + def __new__(cls, a, b, evaluate=True): + if evaluate: + return SymmetricDifference.reduce(a, b) + + return Basic.__new__(cls, a, b) + + @staticmethod + def reduce(A, B): + result = B._symmetric_difference(A) + if result is not None: + return result + else: + return SymmetricDifference(A, B, evaluate=False) + + def as_relational(self, symbol): + """Rewrite a symmetric_difference in terms of equalities and + logic operators""" + A, B = self.args + + A_rel = A.as_relational(symbol) + B_rel = B.as_relational(symbol) + + return Xor(A_rel, B_rel) + + @property + def is_iterable(self): + if all(arg.is_iterable for arg in self.args): + return True + + def __iter__(self): + + args = self.args + union = roundrobin(*(iter(arg) for arg in args)) + + for item in union: + count = 0 + for s in args: + if item in s: + count += 1 + + if count % 2 == 1: + yield item + + + +class DisjointUnion(Set): + """ Represents the disjoint union (also known as the external disjoint union) + of a finite number of sets. + + Examples + ======== + + >>> from sympy import DisjointUnion, FiniteSet, Interval, Union, Symbol + >>> A = FiniteSet(1, 2, 3) + >>> B = Interval(0, 5) + >>> DisjointUnion(A, B) + DisjointUnion({1, 2, 3}, Interval(0, 5)) + >>> DisjointUnion(A, B).rewrite(Union) + Union(ProductSet({1, 2, 3}, {0}), ProductSet(Interval(0, 5), {1})) + >>> C = FiniteSet(Symbol('x'), Symbol('y'), Symbol('z')) + >>> DisjointUnion(C, C) + DisjointUnion({x, y, z}, {x, y, z}) + >>> DisjointUnion(C, C).rewrite(Union) + ProductSet({x, y, z}, {0, 1}) + + References + ========== + + https://en.wikipedia.org/wiki/Disjoint_union + """ + + def __new__(cls, *sets): + dj_collection = [] + for set_i in sets: + if isinstance(set_i, Set): + dj_collection.append(set_i) + else: + raise TypeError("Invalid input: '%s', input args \ + to DisjointUnion must be Sets" % set_i) + obj = Basic.__new__(cls, *dj_collection) + return obj + + @property + def sets(self): + return self.args + + @property + def is_empty(self): + return fuzzy_and(s.is_empty for s in self.sets) + + @property + def is_finite_set(self): + all_finite = fuzzy_and(s.is_finite_set for s in self.sets) + return fuzzy_or([self.is_empty, all_finite]) + + @property + def is_iterable(self): + if self.is_empty: + return False + iter_flag = True + for set_i in self.sets: + if not set_i.is_empty: + iter_flag = iter_flag and set_i.is_iterable + return iter_flag + + def _eval_rewrite_as_Union(self, *sets, **kwargs): + """ + Rewrites the disjoint union as the union of (``set`` x {``i``}) + where ``set`` is the element in ``sets`` at index = ``i`` + """ + + dj_union = S.EmptySet + index = 0 + for set_i in sets: + if isinstance(set_i, Set): + cross = ProductSet(set_i, FiniteSet(index)) + dj_union = Union(dj_union, cross) + index = index + 1 + return dj_union + + def _contains(self, element): + """ + ``in`` operator for DisjointUnion + + Examples + ======== + + >>> from sympy import Interval, DisjointUnion + >>> D = DisjointUnion(Interval(0, 1), Interval(0, 2)) + >>> (0.5, 0) in D + True + >>> (0.5, 1) in D + True + >>> (1.5, 0) in D + False + >>> (1.5, 1) in D + True + + Passes operation on to constituent sets + """ + if not isinstance(element, Tuple) or len(element) != 2: + return S.false + + if not element[1].is_Integer: + return S.false + + if element[1] >= len(self.sets) or element[1] < 0: + return S.false + + return self.sets[element[1]]._contains(element[0]) + + def _kind(self): + if not self.args: + return SetKind() + elif all(i.kind == self.args[0].kind for i in self.args): + return self.args[0].kind + else: + return SetKind(UndefinedKind) + + def __iter__(self): + if self.is_iterable: + + iters = [] + for i, s in enumerate(self.sets): + iters.append(iproduct(s, {Integer(i)})) + + return iter(roundrobin(*iters)) + else: + raise ValueError("'%s' is not iterable." % self) + + def __len__(self): + """ + Returns the length of the disjoint union, i.e., the number of elements in the set. + + Examples + ======== + + >>> from sympy import FiniteSet, DisjointUnion, EmptySet + >>> D1 = DisjointUnion(FiniteSet(1, 2, 3, 4), EmptySet, FiniteSet(3, 4, 5)) + >>> len(D1) + 7 + >>> D2 = DisjointUnion(FiniteSet(3, 5, 7), EmptySet, FiniteSet(3, 5, 7)) + >>> len(D2) + 6 + >>> D3 = DisjointUnion(EmptySet, EmptySet) + >>> len(D3) + 0 + + Adds up the lengths of the constituent sets. + """ + + if self.is_finite_set: + size = 0 + for set in self.sets: + size += len(set) + return size + else: + raise ValueError("'%s' is not a finite set." % self) + + +def imageset(*args): + r""" + Return an image of the set under transformation ``f``. + + Explanation + =========== + + If this function cannot compute the image, it returns an + unevaluated ImageSet object. + + .. math:: + \{ f(x) \mid x \in \mathrm{self} \} + + Examples + ======== + + >>> from sympy import S, Interval, imageset, sin, Lambda + >>> from sympy.abc import x + + >>> imageset(x, 2*x, Interval(0, 2)) + Interval(0, 4) + + >>> imageset(lambda x: 2*x, Interval(0, 2)) + Interval(0, 4) + + >>> imageset(Lambda(x, sin(x)), Interval(-2, 1)) + ImageSet(Lambda(x, sin(x)), Interval(-2, 1)) + + >>> imageset(sin, Interval(-2, 1)) + ImageSet(Lambda(x, sin(x)), Interval(-2, 1)) + >>> imageset(lambda y: x + y, Interval(-2, 1)) + ImageSet(Lambda(y, x + y), Interval(-2, 1)) + + Expressions applied to the set of Integers are simplified + to show as few negatives as possible and linear expressions + are converted to a canonical form. If this is not desirable + then the unevaluated ImageSet should be used. + + >>> imageset(x, -2*x + 5, S.Integers) + ImageSet(Lambda(x, 2*x + 1), Integers) + + See Also + ======== + + sympy.sets.fancysets.ImageSet + + """ + from .fancysets import ImageSet + from .setexpr import set_function + + if len(args) < 2: + raise ValueError('imageset expects at least 2 args, got: %s' % len(args)) + + if isinstance(args[0], (Symbol, tuple)) and len(args) > 2: + f = Lambda(args[0], args[1]) + set_list = args[2:] + else: + f = args[0] + set_list = args[1:] + + if isinstance(f, Lambda): + pass + elif callable(f): + nargs = getattr(f, 'nargs', {}) + if nargs: + if len(nargs) != 1: + raise NotImplementedError(filldedent(''' + This function can take more than 1 arg + but the potentially complicated set input + has not been analyzed at this point to + know its dimensions. TODO + ''')) + N = nargs.args[0] + if N == 1: + s = 'x' + else: + s = [Symbol('x%i' % i) for i in range(1, N + 1)] + else: + s = inspect.signature(f).parameters + + dexpr = _sympify(f(*[Dummy() for i in s])) + var = tuple(uniquely_named_symbol( + Symbol(i), dexpr) for i in s) + f = Lambda(var, f(*var)) + else: + raise TypeError(filldedent(''' + expecting lambda, Lambda, or FunctionClass, + not \'%s\'.''' % func_name(f))) + + if any(not isinstance(s, Set) for s in set_list): + name = [func_name(s) for s in set_list] + raise ValueError( + 'arguments after mapping should be sets, not %s' % name) + + if len(set_list) == 1: + set = set_list[0] + try: + # TypeError if arg count != set dimensions + r = set_function(f, set) + if r is None: + raise TypeError + if not r: + return r + except TypeError: + r = ImageSet(f, set) + if isinstance(r, ImageSet): + f, set = r.args + + if f.variables[0] == f.expr: + return set + + if isinstance(set, ImageSet): + # XXX: Maybe this should just be: + # f2 = set.lambda + # fun = Lambda(f2.signature, f(*f2.expr)) + # return imageset(fun, *set.base_sets) + if len(set.lamda.variables) == 1 and len(f.variables) == 1: + x = set.lamda.variables[0] + y = f.variables[0] + return imageset( + Lambda(x, f.expr.subs(y, set.lamda.expr)), *set.base_sets) + + if r is not None: + return r + + return ImageSet(f, *set_list) + + +def is_function_invertible_in_set(func, setv): + """ + Checks whether function ``func`` is invertible when the domain is + restricted to set ``setv``. + """ + # Functions known to always be invertible: + if func in (exp, log): + return True + u = Dummy("u") + fdiff = func(u).diff(u) + # monotonous functions: + # TODO: check subsets (`func` in `setv`) + if (fdiff > 0) == True or (fdiff < 0) == True: + return True + # TODO: support more + return None + + +def simplify_union(args): + """ + Simplify a :class:`Union` using known rules. + + Explanation + =========== + + We first start with global rules like 'Merge all FiniteSets' + + Then we iterate through all pairs and ask the constituent sets if they + can simplify themselves with any other constituent. This process depends + on ``union_sets(a, b)`` functions. + """ + from sympy.sets.handlers.union import union_sets + + # ===== Global Rules ===== + if not args: + return S.EmptySet + + for arg in args: + if not isinstance(arg, Set): + raise TypeError("Input args to Union must be Sets") + + # Merge all finite sets + finite_sets = [x for x in args if x.is_FiniteSet] + if len(finite_sets) > 1: + a = (x for set in finite_sets for x in set) + finite_set = FiniteSet(*a) + args = [finite_set] + [x for x in args if not x.is_FiniteSet] + + # ===== Pair-wise Rules ===== + # Here we depend on rules built into the constituent sets + args = set(args) + new_args = True + while new_args: + for s in args: + new_args = False + for t in args - {s}: + new_set = union_sets(s, t) + # This returns None if s does not know how to intersect + # with t. Returns the newly intersected set otherwise + if new_set is not None: + if not isinstance(new_set, set): + new_set = {new_set} + new_args = (args - {s, t}).union(new_set) + break + if new_args: + args = new_args + break + + if len(args) == 1: + return args.pop() + else: + return Union(*args, evaluate=False) + + +def simplify_intersection(args): + """ + Simplify an intersection using known rules. + + Explanation + =========== + + We first start with global rules like + 'if any empty sets return empty set' and 'distribute any unions' + + Then we iterate through all pairs and ask the constituent sets if they + can simplify themselves with any other constituent + """ + + # ===== Global Rules ===== + if not args: + return S.UniversalSet + + for arg in args: + if not isinstance(arg, Set): + raise TypeError("Input args to Union must be Sets") + + # If any EmptySets return EmptySet + if S.EmptySet in args: + return S.EmptySet + + # Handle Finite sets + rv = Intersection._handle_finite_sets(args) + + if rv is not None: + return rv + + # If any of the sets are unions, return a Union of Intersections + for s in args: + if s.is_Union: + other_sets = set(args) - {s} + if len(other_sets) > 0: + other = Intersection(*other_sets) + return Union(*(Intersection(arg, other) for arg in s.args)) + else: + return Union(*s.args) + + for s in args: + if s.is_Complement: + args.remove(s) + other_sets = args + [s.args[0]] + return Complement(Intersection(*other_sets), s.args[1]) + + from sympy.sets.handlers.intersection import intersection_sets + + # At this stage we are guaranteed not to have any + # EmptySets, FiniteSets, or Unions in the intersection + + # ===== Pair-wise Rules ===== + # Here we depend on rules built into the constituent sets + args = set(args) + new_args = True + while new_args: + for s in args: + new_args = False + for t in args - {s}: + new_set = intersection_sets(s, t) + # This returns None if s does not know how to intersect + # with t. Returns the newly intersected set otherwise + + if new_set is not None: + new_args = (args - {s, t}).union({new_set}) + break + if new_args: + args = new_args + break + + if len(args) == 1: + return args.pop() + else: + return Intersection(*args, evaluate=False) + + +def _handle_finite_sets(op, x, y, commutative): + # Handle finite sets: + fs_args, other = sift([x, y], lambda x: isinstance(x, FiniteSet), binary=True) + if len(fs_args) == 2: + return FiniteSet(*[op(i, j) for i in fs_args[0] for j in fs_args[1]]) + elif len(fs_args) == 1: + sets = [_apply_operation(op, other[0], i, commutative) for i in fs_args[0]] + return Union(*sets) + else: + return None + + +def _apply_operation(op, x, y, commutative): + from .fancysets import ImageSet + d = Dummy('d') + + out = _handle_finite_sets(op, x, y, commutative) + if out is None: + out = op(x, y) + + if out is None and commutative: + out = op(y, x) + if out is None: + _x, _y = symbols("x y") + if isinstance(x, Set) and not isinstance(y, Set): + out = ImageSet(Lambda(d, op(d, y)), x).doit() + elif not isinstance(x, Set) and isinstance(y, Set): + out = ImageSet(Lambda(d, op(x, d)), y).doit() + else: + out = ImageSet(Lambda((_x, _y), op(_x, _y)), x, y) + return out + + +def set_add(x, y): + from sympy.sets.handlers.add import _set_add + return _apply_operation(_set_add, x, y, commutative=True) + + +def set_sub(x, y): + from sympy.sets.handlers.add import _set_sub + return _apply_operation(_set_sub, x, y, commutative=False) + + +def set_mul(x, y): + from sympy.sets.handlers.mul import _set_mul + return _apply_operation(_set_mul, x, y, commutative=True) + + +def set_div(x, y): + from sympy.sets.handlers.mul import _set_div + return _apply_operation(_set_div, x, y, commutative=False) + + +def set_pow(x, y): + from sympy.sets.handlers.power import _set_pow + return _apply_operation(_set_pow, x, y, commutative=False) + + +def set_function(f, x): + from sympy.sets.handlers.functions import _set_function + return _set_function(f, x) + + +class SetKind(Kind): + """ + SetKind is kind for all Sets + + Every instance of Set will have kind ``SetKind`` parametrised by the kind + of the elements of the ``Set``. The kind of the elements might be + ``NumberKind``, or ``TupleKind`` or something else. When not all elements + have the same kind then the kind of the elements will be given as + ``UndefinedKind``. + + Parameters + ========== + + element_kind: Kind (optional) + The kind of the elements of the set. In a well defined set all elements + will have the same kind. Otherwise the kind should + :class:`sympy.core.kind.UndefinedKind`. The ``element_kind`` argument is optional but + should only be omitted in the case of ``EmptySet`` whose kind is simply + ``SetKind()`` + + Examples + ======== + + >>> from sympy import Interval + >>> Interval(1, 2).kind + SetKind(NumberKind) + >>> Interval(1,2).kind.element_kind + NumberKind + + See Also + ======== + + sympy.core.kind.NumberKind + sympy.matrices.kind.MatrixKind + sympy.core.containers.TupleKind + """ + def __new__(cls, element_kind=None): + obj = super().__new__(cls, element_kind) + obj.element_kind = element_kind + return obj + + def __repr__(self): + if not self.element_kind: + return "SetKind()" + else: + return "SetKind(%s)" % self.element_kind diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0619d1c3ebbd6c6a7d663093c7ed2202114148af --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/__init__.py @@ -0,0 +1,60 @@ +"""The module helps converting SymPy expressions into shorter forms of them. + +for example: +the expression E**(pi*I) will be converted into -1 +the expression (x+x)**2 will be converted into 4*x**2 +""" +from .simplify import (simplify, hypersimp, hypersimilar, + logcombine, separatevars, posify, besselsimp, kroneckersimp, + signsimp, nsimplify) + +from .fu import FU, fu + +from .sqrtdenest import sqrtdenest + +from .cse_main import cse + +from .epathtools import epath, EPath + +from .hyperexpand import hyperexpand + +from .radsimp import collect, rcollect, radsimp, collect_const, fraction, numer, denom + +from .trigsimp import trigsimp, exptrigsimp + +from .powsimp import powsimp, powdenest + +from .combsimp import combsimp + +from .gammasimp import gammasimp + +from .ratsimp import ratsimp, ratsimpmodprime + +__all__ = [ + 'simplify', 'hypersimp', 'hypersimilar', 'logcombine', 'separatevars', + 'posify', 'besselsimp', 'kroneckersimp', 'signsimp', + 'nsimplify', + + 'FU', 'fu', + + 'sqrtdenest', + + 'cse', + + 'epath', 'EPath', + + 'hyperexpand', + + 'collect', 'rcollect', 'radsimp', 'collect_const', 'fraction', 'numer', + 'denom', + + 'trigsimp', 'exptrigsimp', + + 'powsimp', 'powdenest', + + 'combsimp', + + 'gammasimp', + + 'ratsimp', 'ratsimpmodprime', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/_cse_diff.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/_cse_diff.py new file mode 100644 index 0000000000000000000000000000000000000000..3496ad3b31a4f45312cac002429be40aa9aa0868 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/_cse_diff.py @@ -0,0 +1,291 @@ +"""Module for differentiation using CSE.""" + +from sympy import cse, Matrix, Derivative, MatrixBase +from sympy.utilities.iterables import iterable + + +def _remove_cse_from_derivative(replacements, reduced_expressions): + """ + This function is designed to postprocess the output of a common subexpression + elimination (CSE) operation. Specifically, it removes any CSE replacement + symbols from the arguments of ``Derivative`` terms in the expression. This + is necessary to ensure that the forward Jacobian function correctly handles + derivative terms. + + Parameters + ========== + + replacements : list of (Symbol, expression) pairs + Replacement symbols and relative common subexpressions that have been + replaced during a CSE operation. + + reduced_expressions : list of SymPy expressions + The reduced expressions with all the replacements from the + replacements list above. + + Returns + ======= + + processed_replacements : list of (Symbol, expression) pairs + Processed replacement list, in the same format of the + ``replacements`` input list. + + processed_reduced : list of SymPy expressions + Processed reduced list, in the same format of the + ``reduced_expressions`` input list. + """ + + def traverse(node, repl_dict): + if isinstance(node, Derivative): + return replace_all(node, repl_dict) + if not node.args: + return node + new_args = [traverse(arg, repl_dict) for arg in node.args] + return node.func(*new_args) + + def replace_all(node, repl_dict): + result = node + while True: + free_symbols = result.free_symbols + symbols_dict = {k: repl_dict[k] for k in free_symbols if k in repl_dict} + if not symbols_dict: + break + result = result.xreplace(symbols_dict) + return result + + repl_dict = dict(replacements) + processed_replacements = [ + (rep_sym, traverse(sub_exp, repl_dict)) + for rep_sym, sub_exp in replacements + ] + processed_reduced = [ + red_exp.__class__([traverse(exp, repl_dict) for exp in red_exp]) + for red_exp in reduced_expressions + ] + + return processed_replacements, processed_reduced + + +def _forward_jacobian_cse(replacements, reduced_expr, wrt): + """ + Core function to compute the Jacobian of an input Matrix of expressions + through forward accumulation. Takes directly the output of a CSE operation + (replacements and reduced_expr), and an iterable of variables (wrt) with + respect to which to differentiate the reduced expression and returns the + reduced Jacobian matrix and the ``replacements`` list. + + The function also returns a list of precomputed free symbols for each + subexpression, which are useful in the substitution process. + + Parameters + ========== + + replacements : list of (Symbol, expression) pairs + Replacement symbols and relative common subexpressions that have been + replaced during a CSE operation. + + reduced_expr : list of SymPy expressions + The reduced expressions with all the replacements from the + replacements list above. + + wrt : iterable + Iterable of expressions with respect to which to compute the + Jacobian matrix. + + Returns + ======= + + replacements : list of (Symbol, expression) pairs + Replacement symbols and relative common subexpressions that have been + replaced during a CSE operation. Compared to the input replacement list, + the output one doesn't contain replacement symbols inside + ``Derivative``'s arguments. + + jacobian : list of SymPy expressions + The list only contains one element, which is the Jacobian matrix with + elements in reduced form (replacement symbols are present). + + precomputed_fs: list + List of sets, which store the free symbols present in each sub-expression. + Useful in the substitution process. + """ + + if not isinstance(reduced_expr[0], MatrixBase): + raise TypeError("``expr`` must be of matrix type") + + if not (reduced_expr[0].shape[0] == 1 or reduced_expr[0].shape[1] == 1): + raise TypeError("``expr`` must be a row or a column matrix") + + if not iterable(wrt): + raise TypeError("``wrt`` must be an iterable of variables") + + elif not isinstance(wrt, MatrixBase): + wrt = Matrix(wrt) + + if not (wrt.shape[0] == 1 or wrt.shape[1] == 1): + raise TypeError("``wrt`` must be a row or a column matrix") + + replacements, reduced_expr = _remove_cse_from_derivative(replacements, reduced_expr) + + if replacements: + rep_sym, sub_expr = map(Matrix, zip(*replacements)) + else: + rep_sym, sub_expr = Matrix([]), Matrix([]) + + l_sub, l_wrt, l_red = len(sub_expr), len(wrt), len(reduced_expr[0]) + + f1 = reduced_expr[0].__class__.from_dok(l_red, l_wrt, + { + (i, j): diff_value + for i, r in enumerate(reduced_expr[0]) + for j, w in enumerate(wrt) + if (diff_value := r.diff(w)) != 0 + }, + ) + + if not replacements: + return [], [f1], [] + + f2 = Matrix.from_dok(l_red, l_sub, + { + (i, j): diff_value + for i, (r, fs) in enumerate([(r, r.free_symbols) for r in reduced_expr[0]]) + for j, s in enumerate(rep_sym) + if s in fs and (diff_value := r.diff(s)) != 0 + }, + ) + + rep_sym_set = set(rep_sym) + precomputed_fs = [s.free_symbols & rep_sym_set for s in sub_expr ] + + c_matrix = Matrix.from_dok(1, l_wrt, + {(0, j): diff_value for j, w in enumerate(wrt) + if (diff_value := sub_expr[0].diff(w)) != 0}) + + for i in range(1, l_sub): + + bi_matrix = Matrix.from_dok(1, i, + {(0, j): diff_value for j in range(i + 1) + if rep_sym[j] in precomputed_fs[i] + and (diff_value := sub_expr[i].diff(rep_sym[j])) != 0}) + + ai_matrix = Matrix.from_dok(1, l_wrt, + {(0, j): diff_value for j, w in enumerate(wrt) + if (diff_value := sub_expr[i].diff(w)) != 0}) + + if bi_matrix._rep.nnz(): + ci_matrix = bi_matrix.multiply(c_matrix).add(ai_matrix) + c_matrix = Matrix.vstack(c_matrix, ci_matrix) + else: + c_matrix = Matrix.vstack(c_matrix, ai_matrix) + + jacobian = f2.multiply(c_matrix).add(f1) + jacobian = [reduced_expr[0].__class__(jacobian)] + + return replacements, jacobian, precomputed_fs + + +def _forward_jacobian_norm_in_cse_out(expr, wrt): + """ + Function to compute the Jacobian of an input Matrix of expressions through + forward accumulation. Takes a sympy Matrix of expressions (expr) as input + and an iterable of variables (wrt) with respect to which to compute the + Jacobian matrix. The matrix is returned in reduced form (containing + replacement symbols) along with the ``replacements`` list. + + The function also returns a list of precomputed free symbols for each + subexpression, which are useful in the substitution process. + + Parameters + ========== + + expr : Matrix + The vector to be differentiated. + + wrt : iterable + The vector with respect to which to perform the differentiation. + Can be a matrix or an iterable of variables. + + Returns + ======= + + replacements : list of (Symbol, expression) pairs + Replacement symbols and relative common subexpressions that have been + replaced during a CSE operation. The output replacement list doesn't + contain replacement symbols inside ``Derivative``'s arguments. + + jacobian : list of SymPy expressions + The list only contains one element, which is the Jacobian matrix with + elements in reduced form (replacement symbols are present). + + precomputed_fs: list + List of sets, which store the free symbols present in each + sub-expression. Useful in the substitution process. + """ + + replacements, reduced_expr = cse(expr) + replacements, jacobian, precomputed_fs = _forward_jacobian_cse(replacements, reduced_expr, wrt) + + return replacements, jacobian, precomputed_fs + + +def _forward_jacobian(expr, wrt): + """ + Function to compute the Jacobian of an input Matrix of expressions through + forward accumulation. Takes a sympy Matrix of expressions (expr) as input + and an iterable of variables (wrt) with respect to which to compute the + Jacobian matrix. + + Explanation + =========== + + Expressions often contain repeated subexpressions. Using a tree structure, + these subexpressions are duplicated and differentiated multiple times, + leading to inefficiency. + + Instead, if a data structure called a directed acyclic graph (DAG) is used + then each of these repeated subexpressions will only exist a single time. + This function uses a combination of representing the expression as a DAG and + a forward accumulation algorithm (repeated application of the chain rule + symbolically) to more efficiently calculate the Jacobian matrix of a target + expression ``expr`` with respect to an expression or set of expressions + ``wrt``. + + Note that this function is intended to improve performance when + differentiating large expressions that contain many common subexpressions. + For small and simple expressions it is likely less performant than using + SymPy's standard differentiation functions and methods. + + Parameters + ========== + + expr : Matrix + The vector to be differentiated. + + wrt : iterable + The vector with respect to which to do the differentiation. + Can be a matrix or an iterable of variables. + + See Also + ======== + + Direct Acyclic Graph : https://en.wikipedia.org/wiki/Directed_acyclic_graph + """ + + replacements, reduced_expr = cse(expr) + + if replacements: + rep_sym, _ = map(Matrix, zip(*replacements)) + else: + rep_sym = Matrix([]) + + replacements, jacobian, precomputed_fs = _forward_jacobian_cse(replacements, reduced_expr, wrt) + + if not replacements: return jacobian[0] + + sub_rep = dict(replacements) + for i, ik in enumerate(precomputed_fs): + sub_dict = {j: sub_rep[j] for j in ik} + sub_rep[rep_sym[i]] = sub_rep[rep_sym[i]].xreplace(sub_dict) + + return jacobian[0].xreplace(sub_rep) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/combsimp.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/combsimp.py new file mode 100644 index 0000000000000000000000000000000000000000..8b0b3cefcba11b4b7759b7d3ec3c2d4415cfd849 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/combsimp.py @@ -0,0 +1,114 @@ +from sympy.core import Mul +from sympy.core.function import count_ops +from sympy.core.traversal import preorder_traversal, bottom_up +from sympy.functions.combinatorial.factorials import binomial, factorial +from sympy.functions import gamma +from sympy.simplify.gammasimp import gammasimp, _gammasimp + +from sympy.utilities.timeutils import timethis + + +@timethis('combsimp') +def combsimp(expr): + r""" + Simplify combinatorial expressions. + + Explanation + =========== + + This function takes as input an expression containing factorials, + binomials, Pochhammer symbol and other "combinatorial" functions, + and tries to minimize the number of those functions and reduce + the size of their arguments. + + The algorithm works by rewriting all combinatorial functions as + gamma functions and applying gammasimp() except simplification + steps that may make an integer argument non-integer. See docstring + of gammasimp for more information. + + Then it rewrites expression in terms of factorials and binomials by + rewriting gammas as factorials and converting (a+b)!/a!b! into + binomials. + + If expression has gamma functions or combinatorial functions + with non-integer argument, it is automatically passed to gammasimp. + + Examples + ======== + + >>> from sympy.simplify import combsimp + >>> from sympy import factorial, binomial, symbols + >>> n, k = symbols('n k', integer = True) + + >>> combsimp(factorial(n)/factorial(n - 3)) + n*(n - 2)*(n - 1) + >>> combsimp(binomial(n+1, k+1)/binomial(n, k)) + (n + 1)/(k + 1) + + """ + + expr = expr.rewrite(gamma, piecewise=False) + if any(isinstance(node, gamma) and not node.args[0].is_integer + for node in preorder_traversal(expr)): + return gammasimp(expr) + + expr = _gammasimp(expr, as_comb = True) + expr = _gamma_as_comb(expr) + return expr + + +def _gamma_as_comb(expr): + """ + Helper function for combsimp. + + Rewrites expression in terms of factorials and binomials + """ + + expr = expr.rewrite(factorial) + + def f(rv): + if not rv.is_Mul: + return rv + rvd = rv.as_powers_dict() + nd_fact_args = [[], []] # numerator, denominator + + for k in rvd: + if isinstance(k, factorial) and rvd[k].is_Integer: + if rvd[k].is_positive: + nd_fact_args[0].extend([k.args[0]]*rvd[k]) + else: + nd_fact_args[1].extend([k.args[0]]*-rvd[k]) + rvd[k] = 0 + if not nd_fact_args[0] or not nd_fact_args[1]: + return rv + + hit = False + for m in range(2): + i = 0 + while i < len(nd_fact_args[m]): + ai = nd_fact_args[m][i] + for j in range(i + 1, len(nd_fact_args[m])): + aj = nd_fact_args[m][j] + + sum = ai + aj + if sum in nd_fact_args[1 - m]: + hit = True + + nd_fact_args[1 - m].remove(sum) + del nd_fact_args[m][j] + del nd_fact_args[m][i] + + rvd[binomial(sum, ai if count_ops(ai) < + count_ops(aj) else aj)] += ( + -1 if m == 0 else 1) + break + else: + i += 1 + + if hit: + return Mul(*([k**rvd[k] for k in rvd] + [factorial(k) + for k in nd_fact_args[0]]))/Mul(*[factorial(k) + for k in nd_fact_args[1]]) + return rv + + return bottom_up(expr, f) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/cse_main.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/cse_main.py new file mode 100644 index 0000000000000000000000000000000000000000..bcd1b2e50adae8c3d3400d6c489e63a44ae1e59b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/cse_main.py @@ -0,0 +1,945 @@ +""" Tools for doing common subexpression elimination. +""" +from collections import defaultdict + +from sympy.core import Basic, Mul, Add, Pow, sympify +from sympy.core.containers import Tuple, OrderedSet +from sympy.core.exprtools import factor_terms +from sympy.core.singleton import S +from sympy.core.sorting import ordered +from sympy.core.symbol import symbols, Symbol +from sympy.matrices import (MatrixBase, Matrix, ImmutableMatrix, + SparseMatrix, ImmutableSparseMatrix) +from sympy.matrices.expressions import (MatrixExpr, MatrixSymbol, MatMul, + MatAdd, MatPow, Inverse) +from sympy.matrices.expressions.matexpr import MatrixElement +from sympy.polys.rootoftools import RootOf +from sympy.utilities.iterables import numbered_symbols, sift, \ + topological_sort, iterable + +from . import cse_opts + +# (preprocessor, postprocessor) pairs which are commonly useful. They should +# each take a SymPy expression and return a possibly transformed expression. +# When used in the function ``cse()``, the target expressions will be transformed +# by each of the preprocessor functions in order. After the common +# subexpressions are eliminated, each resulting expression will have the +# postprocessor functions transform them in *reverse* order in order to undo the +# transformation if necessary. This allows the algorithm to operate on +# a representation of the expressions that allows for more optimization +# opportunities. +# ``None`` can be used to specify no transformation for either the preprocessor or +# postprocessor. + + +basic_optimizations = [(cse_opts.sub_pre, cse_opts.sub_post), + (factor_terms, None)] + +# sometimes we want the output in a different format; non-trivial +# transformations can be put here for users +# =============================================================== + + +def reps_toposort(r): + """Sort replacements ``r`` so (k1, v1) appears before (k2, v2) + if k2 is in v1's free symbols. This orders items in the + way that cse returns its results (hence, in order to use the + replacements in a substitution option it would make sense + to reverse the order). + + Examples + ======== + + >>> from sympy.simplify.cse_main import reps_toposort + >>> from sympy.abc import x, y + >>> from sympy import Eq + >>> for l, r in reps_toposort([(x, y + 1), (y, 2)]): + ... print(Eq(l, r)) + ... + Eq(y, 2) + Eq(x, y + 1) + + """ + r = sympify(r) + E = [] + for c1, (k1, v1) in enumerate(r): + for c2, (k2, v2) in enumerate(r): + if k1 in v2.free_symbols: + E.append((c1, c2)) + return [r[i] for i in topological_sort((range(len(r)), E))] + + +def cse_separate(r, e): + """Move expressions that are in the form (symbol, expr) out of the + expressions and sort them into the replacements using the reps_toposort. + + Examples + ======== + + >>> from sympy.simplify.cse_main import cse_separate + >>> from sympy.abc import x, y, z + >>> from sympy import cos, exp, cse, Eq, symbols + >>> x0, x1 = symbols('x:2') + >>> eq = (x + 1 + exp((x + 1)/(y + 1)) + cos(y + 1)) + >>> cse([eq, Eq(x, z + 1), z - 2], postprocess=cse_separate) in [ + ... [[(x0, y + 1), (x, z + 1), (x1, x + 1)], + ... [x1 + exp(x1/x0) + cos(x0), z - 2]], + ... [[(x1, y + 1), (x, z + 1), (x0, x + 1)], + ... [x0 + exp(x0/x1) + cos(x1), z - 2]]] + ... + True + """ + d = sift(e, lambda w: w.is_Equality and w.lhs.is_Symbol) + r = r + [w.args for w in d[True]] + e = d[False] + return [reps_toposort(r), e] + + +def cse_release_variables(r, e): + """ + Return tuples giving ``(a, b)`` where ``a`` is a symbol and ``b`` is + either an expression or None. The value of None is used when a + symbol is no longer needed for subsequent expressions. + + Use of such output can reduce the memory footprint of lambdified + expressions that contain large, repeated subexpressions. + + Examples + ======== + + >>> from sympy import cse + >>> from sympy.simplify.cse_main import cse_release_variables + >>> from sympy.abc import x, y + >>> eqs = [(x + y - 1)**2, x, x + y, (x + y)/(2*x + 1) + (x + y - 1)**2, (2*x + 1)**(x + y)] + >>> defs, rvs = cse_release_variables(*cse(eqs)) + >>> for i in defs: + ... print(i) + ... + (x0, x + y) + (x1, (x0 - 1)**2) + (x2, 2*x + 1) + (_3, x0/x2 + x1) + (_4, x2**x0) + (x2, None) + (_0, x1) + (x1, None) + (_2, x0) + (x0, None) + (_1, x) + >>> print(rvs) + (_0, _1, _2, _3, _4) + """ + if not r: + return r, e + + s, p = zip(*r) + esyms = symbols('_:%d' % len(e)) + syms = list(esyms) + s = list(s) + in_use = set(s) + p = list(p) + # sort e so those with most sub-expressions appear first + e = [(e[i], syms[i]) for i in range(len(e))] + e, syms = zip(*sorted(e, + key=lambda x: -sum(p[s.index(i)].count_ops() + for i in x[0].free_symbols & in_use))) + syms = list(syms) + p += e + rv = [] + i = len(p) - 1 + while i >= 0: + _p = p.pop() + c = in_use & _p.free_symbols + if c: # sorting for canonical results + rv.extend([(s, None) for s in sorted(c, key=str)]) + if i >= len(r): + rv.append((syms.pop(), _p)) + else: + rv.append((s[i], _p)) + in_use -= c + i -= 1 + rv.reverse() + return rv, esyms + + +# ====end of cse postprocess idioms=========================== + + +def preprocess_for_cse(expr, optimizations): + """ Preprocess an expression to optimize for common subexpression + elimination. + + Parameters + ========== + + expr : SymPy expression + The target expression to optimize. + optimizations : list of (callable, callable) pairs + The (preprocessor, postprocessor) pairs. + + Returns + ======= + + expr : SymPy expression + The transformed expression. + """ + for pre, post in optimizations: + if pre is not None: + expr = pre(expr) + return expr + + +def postprocess_for_cse(expr, optimizations): + """Postprocess an expression after common subexpression elimination to + return the expression to canonical SymPy form. + + Parameters + ========== + + expr : SymPy expression + The target expression to transform. + optimizations : list of (callable, callable) pairs, optional + The (preprocessor, postprocessor) pairs. The postprocessors will be + applied in reversed order to undo the effects of the preprocessors + correctly. + + Returns + ======= + + expr : SymPy expression + The transformed expression. + """ + for pre, post in reversed(optimizations): + if post is not None: + expr = post(expr) + return expr + + +class FuncArgTracker: + """ + A class which manages a mapping from functions to arguments and an inverse + mapping from arguments to functions. + """ + + def __init__(self, funcs): + # To minimize the number of symbolic comparisons, all function arguments + # get assigned a value number. + self.value_numbers = {} + self.value_number_to_value = [] + + # Both of these maps use integer indices for arguments / functions. + self.arg_to_funcset = [] + self.func_to_argset = [] + + for func_i, func in enumerate(funcs): + func_argset = OrderedSet() + + for func_arg in func.args: + arg_number = self.get_or_add_value_number(func_arg) + func_argset.add(arg_number) + self.arg_to_funcset[arg_number].add(func_i) + + self.func_to_argset.append(func_argset) + + def get_args_in_value_order(self, argset): + """ + Return the list of arguments in sorted order according to their value + numbers. + """ + return [self.value_number_to_value[argn] for argn in sorted(argset)] + + def get_or_add_value_number(self, value): + """ + Return the value number for the given argument. + """ + nvalues = len(self.value_numbers) + value_number = self.value_numbers.setdefault(value, nvalues) + if value_number == nvalues: + self.value_number_to_value.append(value) + self.arg_to_funcset.append(OrderedSet()) + return value_number + + def stop_arg_tracking(self, func_i): + """ + Remove the function func_i from the argument to function mapping. + """ + for arg in self.func_to_argset[func_i]: + self.arg_to_funcset[arg].remove(func_i) + + + def get_common_arg_candidates(self, argset, min_func_i=0): + """Return a dict whose keys are function numbers. The entries of the dict are + the number of arguments said function has in common with + ``argset``. Entries have at least 2 items in common. All keys have + value at least ``min_func_i``. + """ + count_map = defaultdict(lambda: 0) + if not argset: + return count_map + + funcsets = [self.arg_to_funcset[arg] for arg in argset] + # As an optimization below, we handle the largest funcset separately from + # the others. + largest_funcset = max(funcsets, key=len) + + for funcset in funcsets: + if largest_funcset is funcset: + continue + for func_i in funcset: + if func_i >= min_func_i: + count_map[func_i] += 1 + + # We pick the smaller of the two containers (count_map, largest_funcset) + # to iterate over to reduce the number of iterations needed. + (smaller_funcs_container, + larger_funcs_container) = sorted( + [largest_funcset, count_map], + key=len) + + for func_i in smaller_funcs_container: + # Not already in count_map? It can't possibly be in the output, so + # skip it. + if count_map[func_i] < 1: + continue + + if func_i in larger_funcs_container: + count_map[func_i] += 1 + + return {k: v for k, v in count_map.items() if v >= 2} + + def get_subset_candidates(self, argset, restrict_to_funcset=None): + """ + Return a set of functions each of which whose argument list contains + ``argset``, optionally filtered only to contain functions in + ``restrict_to_funcset``. + """ + iarg = iter(argset) + + indices = OrderedSet( + fi for fi in self.arg_to_funcset[next(iarg)]) + + if restrict_to_funcset is not None: + indices &= restrict_to_funcset + + for arg in iarg: + indices &= self.arg_to_funcset[arg] + + return indices + + def update_func_argset(self, func_i, new_argset): + """ + Update a function with a new set of arguments. + """ + new_args = OrderedSet(new_argset) + old_args = self.func_to_argset[func_i] + + for deleted_arg in old_args - new_args: + self.arg_to_funcset[deleted_arg].remove(func_i) + for added_arg in new_args - old_args: + self.arg_to_funcset[added_arg].add(func_i) + + self.func_to_argset[func_i].clear() + self.func_to_argset[func_i].update(new_args) + + +class Unevaluated: + + def __init__(self, func, args): + self.func = func + self.args = args + + def __str__(self): + return "Uneval<{}>({})".format( + self.func, ", ".join(str(a) for a in self.args)) + + def as_unevaluated_basic(self): + return self.func(*self.args, evaluate=False) + + @property + def free_symbols(self): + return set().union(*[a.free_symbols for a in self.args]) + + __repr__ = __str__ + + +def match_common_args(func_class, funcs, opt_subs): + """ + Recognize and extract common subexpressions of function arguments within a + set of function calls. For instance, for the following function calls:: + + x + z + y + sin(x + y) + + this will extract a common subexpression of `x + y`:: + + w = x + y + w + z + sin(w) + + The function we work with is assumed to be associative and commutative. + + Parameters + ========== + + func_class: class + The function class (e.g. Add, Mul) + funcs: list of functions + A list of function calls. + opt_subs: dict + A dictionary of substitutions which this function may update. + """ + + # Sort to ensure that whole-function subexpressions come before the items + # that use them. + funcs = sorted(funcs, key=lambda f: len(f.args)) + arg_tracker = FuncArgTracker(funcs) + + changed = OrderedSet() + + for i in range(len(funcs)): + common_arg_candidates_counts = arg_tracker.get_common_arg_candidates( + arg_tracker.func_to_argset[i], min_func_i=i + 1) + + # Sort the candidates in order of match size. + # This makes us try combining smaller matches first. + common_arg_candidates = OrderedSet(sorted( + common_arg_candidates_counts.keys(), + key=lambda k: (common_arg_candidates_counts[k], k))) + + while common_arg_candidates: + j = common_arg_candidates.pop(last=False) + + com_args = arg_tracker.func_to_argset[i].intersection( + arg_tracker.func_to_argset[j]) + + if len(com_args) <= 1: + # This may happen if a set of common arguments was already + # combined in a previous iteration. + continue + + # For all sets, replace the common symbols by the function + # over them, to allow recursive matches. + + diff_i = arg_tracker.func_to_argset[i].difference(com_args) + if diff_i: + # com_func needs to be unevaluated to allow for recursive matches. + com_func = Unevaluated( + func_class, arg_tracker.get_args_in_value_order(com_args)) + com_func_number = arg_tracker.get_or_add_value_number(com_func) + arg_tracker.update_func_argset(i, diff_i | OrderedSet([com_func_number])) + changed.add(i) + else: + # Treat the whole expression as a CSE. + # + # The reason this needs to be done is somewhat subtle. Within + # tree_cse(), to_eliminate only contains expressions that are + # seen more than once. The problem is unevaluated expressions + # do not compare equal to the evaluated equivalent. So + # tree_cse() won't mark funcs[i] as a CSE if we use an + # unevaluated version. + com_func_number = arg_tracker.get_or_add_value_number(funcs[i]) + + diff_j = arg_tracker.func_to_argset[j].difference(com_args) + arg_tracker.update_func_argset(j, diff_j | OrderedSet([com_func_number])) + changed.add(j) + + for k in arg_tracker.get_subset_candidates( + com_args, common_arg_candidates): + diff_k = arg_tracker.func_to_argset[k].difference(com_args) + arg_tracker.update_func_argset(k, diff_k | OrderedSet([com_func_number])) + changed.add(k) + + if i in changed: + opt_subs[funcs[i]] = Unevaluated(func_class, + arg_tracker.get_args_in_value_order(arg_tracker.func_to_argset[i])) + + arg_tracker.stop_arg_tracking(i) + + +def opt_cse(exprs, order='canonical'): + """Find optimization opportunities in Adds, Muls, Pows and negative + coefficient Muls. + + Parameters + ========== + + exprs : list of SymPy expressions + The expressions to optimize. + order : string, 'none' or 'canonical' + The order by which Mul and Add arguments are processed. For large + expressions where speed is a concern, use the setting order='none'. + + Returns + ======= + + opt_subs : dictionary of expression substitutions + The expression substitutions which can be useful to optimize CSE. + + Examples + ======== + + >>> from sympy.simplify.cse_main import opt_cse + >>> from sympy.abc import x + >>> opt_subs = opt_cse([x**-2]) + >>> k, v = list(opt_subs.keys())[0], list(opt_subs.values())[0] + >>> print((k, v.as_unevaluated_basic())) + (x**(-2), 1/(x**2)) + """ + opt_subs = {} + + adds = OrderedSet() + muls = OrderedSet() + + seen_subexp = set() + collapsible_subexp = set() + + def _find_opts(expr): + + if not isinstance(expr, (Basic, Unevaluated)): + return + + if expr.is_Atom or expr.is_Order: + return + + if iterable(expr): + list(map(_find_opts, expr)) + return + + if expr in seen_subexp: + return expr + seen_subexp.add(expr) + + list(map(_find_opts, expr.args)) + + if not isinstance(expr, MatrixExpr) and expr.could_extract_minus_sign(): + # XXX -expr does not always work rigorously for some expressions + # containing UnevaluatedExpr. + # https://github.com/sympy/sympy/issues/24818 + if isinstance(expr, Add): + neg_expr = Add(*(-i for i in expr.args)) + else: + neg_expr = -expr + + if not neg_expr.is_Atom: + opt_subs[expr] = Unevaluated(Mul, (S.NegativeOne, neg_expr)) + seen_subexp.add(neg_expr) + expr = neg_expr + + if isinstance(expr, (Mul, MatMul)): + if len(expr.args) == 1: + collapsible_subexp.add(expr) + else: + muls.add(expr) + + elif isinstance(expr, (Add, MatAdd)): + if len(expr.args) == 1: + collapsible_subexp.add(expr) + else: + adds.add(expr) + + elif isinstance(expr, Inverse): + # Do not want to treat `Inverse` as a `MatPow` + pass + + elif isinstance(expr, (Pow, MatPow)): + base, exp = expr.base, expr.exp + if exp.could_extract_minus_sign(): + opt_subs[expr] = Unevaluated(Pow, (Pow(base, -exp), -1)) + + for e in exprs: + if isinstance(e, (Basic, Unevaluated)): + _find_opts(e) + + # Handle collapsing of multinary operations with single arguments + edges = [(s, s.args[0]) for s in collapsible_subexp + if s.args[0] in collapsible_subexp] + for e in reversed(topological_sort((collapsible_subexp, edges))): + opt_subs[e] = opt_subs.get(e.args[0], e.args[0]) + + # split muls into commutative + commutative_muls = OrderedSet() + for m in muls: + c, nc = m.args_cnc(cset=False) + if c: + c_mul = m.func(*c) + if nc: + if c_mul == 1: + new_obj = m.func(*nc) + else: + if isinstance(m, MatMul): + new_obj = m.func(c_mul, *nc, evaluate=False) + else: + new_obj = m.func(c_mul, m.func(*nc), evaluate=False) + opt_subs[m] = new_obj + if len(c) > 1: + commutative_muls.add(c_mul) + + match_common_args(Add, adds, opt_subs) + match_common_args(Mul, commutative_muls, opt_subs) + + return opt_subs + + +def tree_cse(exprs, symbols, opt_subs=None, order='canonical', ignore=()): + """Perform raw CSE on expression tree, taking opt_subs into account. + + Parameters + ========== + + exprs : list of SymPy expressions + The expressions to reduce. + symbols : infinite iterator yielding unique Symbols + The symbols used to label the common subexpressions which are pulled + out. + opt_subs : dictionary of expression substitutions + The expressions to be substituted before any CSE action is performed. + order : string, 'none' or 'canonical' + The order by which Mul and Add arguments are processed. For large + expressions where speed is a concern, use the setting order='none'. + ignore : iterable of Symbols + Substitutions containing any Symbol from ``ignore`` will be ignored. + """ + if opt_subs is None: + opt_subs = {} + + ## Find repeated sub-expressions + + to_eliminate = set() + + seen_subexp = set() + excluded_symbols = set() + + def _find_repeated(expr): + if not isinstance(expr, (Basic, Unevaluated)): + return + + if isinstance(expr, RootOf): + return + + if isinstance(expr, Basic) and ( + expr.is_Atom or + expr.is_Order or + isinstance(expr, (MatrixSymbol, MatrixElement))): + if expr.is_Symbol: + excluded_symbols.add(expr.name) + return + + if iterable(expr): + args = expr + + else: + if expr in seen_subexp: + for ign in ignore: + if ign in expr.free_symbols: + break + else: + to_eliminate.add(expr) + return + + seen_subexp.add(expr) + + if expr in opt_subs: + expr = opt_subs[expr] + + args = expr.args + + list(map(_find_repeated, args)) + + for e in exprs: + if isinstance(e, Basic): + _find_repeated(e) + + ## Rebuild tree + + # Remove symbols from the generator that conflict with names in the expressions. + symbols = (_ for _ in symbols if _.name not in excluded_symbols) + + replacements = [] + + subs = {} + + def _rebuild(expr): + if not isinstance(expr, (Basic, Unevaluated)): + return expr + + if not expr.args: + return expr + + if iterable(expr): + new_args = [_rebuild(arg) for arg in expr.args] + return expr.func(*new_args) + + if expr in subs: + return subs[expr] + + orig_expr = expr + if expr in opt_subs: + expr = opt_subs[expr] + + # If enabled, parse Muls and Adds arguments by order to ensure + # replacement order independent from hashes + if order != 'none': + if isinstance(expr, (Mul, MatMul)): + c, nc = expr.args_cnc() + if c == [1]: + args = nc + else: + args = list(ordered(c)) + nc + elif isinstance(expr, (Add, MatAdd)): + args = list(ordered(expr.args)) + else: + args = expr.args + else: + args = expr.args + + new_args = list(map(_rebuild, args)) + if isinstance(expr, Unevaluated) or new_args != args: + new_expr = expr.func(*new_args) + else: + new_expr = expr + + if orig_expr in to_eliminate: + try: + sym = next(symbols) + except StopIteration: + raise ValueError("Symbols iterator ran out of symbols.") + + if isinstance(orig_expr, MatrixExpr): + sym = MatrixSymbol(sym.name, orig_expr.rows, + orig_expr.cols) + + subs[orig_expr] = sym + replacements.append((sym, new_expr)) + return sym + + else: + return new_expr + + reduced_exprs = [] + for e in exprs: + if isinstance(e, Basic): + reduced_e = _rebuild(e) + else: + reduced_e = e + reduced_exprs.append(reduced_e) + return replacements, reduced_exprs + + +def cse(exprs, symbols=None, optimizations=None, postprocess=None, + order='canonical', ignore=(), list=True): + """ Perform common subexpression elimination on an expression. + + Parameters + ========== + + exprs : list of SymPy expressions, or a single SymPy expression + The expressions to reduce. + symbols : infinite iterator yielding unique Symbols + The symbols used to label the common subexpressions which are pulled + out. The ``numbered_symbols`` generator is useful. The default is a + stream of symbols of the form "x0", "x1", etc. This must be an + infinite iterator. + optimizations : list of (callable, callable) pairs + The (preprocessor, postprocessor) pairs of external optimization + functions. Optionally 'basic' can be passed for a set of predefined + basic optimizations. Such 'basic' optimizations were used by default + in old implementation, however they can be really slow on larger + expressions. Now, no pre or post optimizations are made by default. + postprocess : a function which accepts the two return values of cse and + returns the desired form of output from cse, e.g. if you want the + replacements reversed the function might be the following lambda: + lambda r, e: return reversed(r), e + order : string, 'none' or 'canonical' + The order by which Mul and Add arguments are processed. If set to + 'canonical', arguments will be canonically ordered. If set to 'none', + ordering will be faster but dependent on expressions hashes, thus + machine dependent and variable. For large expressions where speed is a + concern, use the setting order='none'. + ignore : iterable of Symbols + Substitutions containing any Symbol from ``ignore`` will be ignored. + list : bool, (default True) + Returns expression in list or else with same type as input (when False). + + Returns + ======= + + replacements : list of (Symbol, expression) pairs + All of the common subexpressions that were replaced. Subexpressions + earlier in this list might show up in subexpressions later in this + list. + reduced_exprs : list of SymPy expressions + The reduced expressions with all of the replacements above. + + Examples + ======== + + >>> from sympy import cse, SparseMatrix + >>> from sympy.abc import x, y, z, w + >>> cse(((w + x + y + z)*(w + y + z))/(w + x)**3) + ([(x0, y + z), (x1, w + x)], [(w + x0)*(x0 + x1)/x1**3]) + + + List of expressions with recursive substitutions: + + >>> m = SparseMatrix([x + y, x + y + z]) + >>> cse([(x+y)**2, x + y + z, y + z, x + z + y, m]) + ([(x0, x + y), (x1, x0 + z)], [x0**2, x1, y + z, x1, Matrix([ + [x0], + [x1]])]) + + Note: the type and mutability of input matrices is retained. + + >>> isinstance(_[1][-1], SparseMatrix) + True + + The user may disallow substitutions containing certain symbols: + + >>> cse([y**2*(x + 1), 3*y**2*(x + 1)], ignore=(y,)) + ([(x0, x + 1)], [x0*y**2, 3*x0*y**2]) + + The default return value for the reduced expression(s) is a list, even if there is only + one expression. The `list` flag preserves the type of the input in the output: + + >>> cse(x) + ([], [x]) + >>> cse(x, list=False) + ([], x) + """ + if not list: + return _cse_homogeneous(exprs, + symbols=symbols, optimizations=optimizations, + postprocess=postprocess, order=order, ignore=ignore) + + if isinstance(exprs, (int, float)): + exprs = sympify(exprs) + + # Handle the case if just one expression was passed. + if isinstance(exprs, (Basic, MatrixBase)): + exprs = [exprs] + + copy = exprs + temp = [] + for e in exprs: + if isinstance(e, (Matrix, ImmutableMatrix)): + temp.append(Tuple(*e.flat())) + elif isinstance(e, (SparseMatrix, ImmutableSparseMatrix)): + temp.append(Tuple(*e.todok().items())) + else: + temp.append(e) + exprs = temp + del temp + + if optimizations is None: + optimizations = [] + elif optimizations == 'basic': + optimizations = basic_optimizations + + # Preprocess the expressions to give us better optimization opportunities. + reduced_exprs = [preprocess_for_cse(e, optimizations) for e in exprs] + + if symbols is None: + symbols = numbered_symbols(cls=Symbol) + else: + # In case we get passed an iterable with an __iter__ method instead of + # an actual iterator. + symbols = iter(symbols) + + # Find other optimization opportunities. + opt_subs = opt_cse(reduced_exprs, order) + + # Main CSE algorithm. + replacements, reduced_exprs = tree_cse(reduced_exprs, symbols, opt_subs, + order, ignore) + + # Postprocess the expressions to return the expressions to canonical form. + exprs = copy + replacements = [(sym, postprocess_for_cse(subtree, optimizations)) + for sym, subtree in replacements] + reduced_exprs = [postprocess_for_cse(e, optimizations) + for e in reduced_exprs] + + # Get the matrices back + for i, e in enumerate(exprs): + if isinstance(e, (Matrix, ImmutableMatrix)): + reduced_exprs[i] = Matrix(e.rows, e.cols, reduced_exprs[i]) + if isinstance(e, ImmutableMatrix): + reduced_exprs[i] = reduced_exprs[i].as_immutable() + elif isinstance(e, (SparseMatrix, ImmutableSparseMatrix)): + m = SparseMatrix(e.rows, e.cols, {}) + for k, v in reduced_exprs[i]: + m[k] = v + if isinstance(e, ImmutableSparseMatrix): + m = m.as_immutable() + reduced_exprs[i] = m + + if postprocess is None: + return replacements, reduced_exprs + + return postprocess(replacements, reduced_exprs) + + +def _cse_homogeneous(exprs, **kwargs): + """ + Same as ``cse`` but the ``reduced_exprs`` are returned + with the same type as ``exprs`` or a sympified version of the same. + + Parameters + ========== + + exprs : an Expr, iterable of Expr or dictionary with Expr values + the expressions in which repeated subexpressions will be identified + kwargs : additional arguments for the ``cse`` function + + Returns + ======= + + replacements : list of (Symbol, expression) pairs + All of the common subexpressions that were replaced. Subexpressions + earlier in this list might show up in subexpressions later in this + list. + reduced_exprs : list of SymPy expressions + The reduced expressions with all of the replacements above. + + Examples + ======== + + >>> from sympy.simplify.cse_main import cse + >>> from sympy import cos, Tuple, Matrix + >>> from sympy.abc import x + >>> output = lambda x: type(cse(x, list=False)[1]) + >>> output(1) + + >>> output('cos(x)') + + >>> output(cos(x)) + cos + >>> output(Tuple(1, x)) + + >>> output(Matrix([[1,0], [0,1]])) + + >>> output([1, x]) + + >>> output((1, x)) + + >>> output({1, x}) + + """ + if isinstance(exprs, str): + replacements, reduced_exprs = _cse_homogeneous( + sympify(exprs), **kwargs) + return replacements, repr(reduced_exprs) + if isinstance(exprs, (list, tuple, set)): + replacements, reduced_exprs = cse(exprs, **kwargs) + return replacements, type(exprs)(reduced_exprs) + if isinstance(exprs, dict): + keys = list(exprs.keys()) # In order to guarantee the order of the elements. + replacements, values = cse([exprs[k] for k in keys], **kwargs) + reduced_exprs = dict(zip(keys, values)) + return replacements, reduced_exprs + + try: + replacements, (reduced_exprs,) = cse(exprs, **kwargs) + except TypeError: # For example 'mpf' objects + return [], exprs + else: + return replacements, reduced_exprs diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/cse_opts.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/cse_opts.py new file mode 100644 index 0000000000000000000000000000000000000000..36a59857411de740ae47423442af88b118a3395d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/cse_opts.py @@ -0,0 +1,52 @@ +""" Optimizations of the expression tree representation for better CSE +opportunities. +""" +from sympy.core import Add, Basic, Mul +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.core.traversal import preorder_traversal + + +def sub_pre(e): + """ Replace y - x with -(x - y) if -1 can be extracted from y - x. + """ + # replacing Add, A, from which -1 can be extracted with -1*-A + adds = [a for a in e.atoms(Add) if a.could_extract_minus_sign()] + reps = {} + ignore = set() + for a in adds: + na = -a + if na.is_Mul: # e.g. MatExpr + ignore.add(a) + continue + reps[a] = Mul._from_args([S.NegativeOne, na]) + + e = e.xreplace(reps) + + # repeat again for persisting Adds but mark these with a leading 1, -1 + # e.g. y - x -> 1*-1*(x - y) + if isinstance(e, Basic): + negs = {} + for a in sorted(e.atoms(Add), key=default_sort_key): + if a in ignore: + continue + if a in reps: + negs[a] = reps[a] + elif a.could_extract_minus_sign(): + negs[a] = Mul._from_args([S.One, S.NegativeOne, -a]) + e = e.xreplace(negs) + return e + + +def sub_post(e): + """ Replace 1*-1*x with -x. + """ + replacements = [] + for node in preorder_traversal(e): + if isinstance(node, Mul) and \ + node.args[0] is S.One and node.args[1] is S.NegativeOne: + replacements.append((node, -Mul._from_args(node.args[2:]))) + for node, replacement in replacements: + e = e.xreplace({node: replacement}) + + return e diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/epathtools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/epathtools.py new file mode 100644 index 0000000000000000000000000000000000000000..7be983ada63fd39d7d467acf9afd62b3a41a2d85 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/epathtools.py @@ -0,0 +1,352 @@ +"""Tools for manipulation of expressions using paths. """ + +from sympy.core import Basic + + +class EPath: + r""" + Manipulate expressions using paths. + + EPath grammar in EBNF notation:: + + literal ::= /[A-Za-z_][A-Za-z_0-9]*/ + number ::= /-?\d+/ + type ::= literal + attribute ::= literal "?" + all ::= "*" + slice ::= "[" number? (":" number? (":" number?)?)? "]" + range ::= all | slice + query ::= (type | attribute) ("|" (type | attribute))* + selector ::= range | query range? + path ::= "/" selector ("/" selector)* + + See the docstring of the epath() function. + + """ + + __slots__ = ("_path", "_epath") + + def __new__(cls, path): + """Construct new EPath. """ + if isinstance(path, EPath): + return path + + if not path: + raise ValueError("empty EPath") + + _path = path + + if path[0] == '/': + path = path[1:] + else: + raise NotImplementedError("non-root EPath") + + epath = [] + + for selector in path.split('/'): + selector = selector.strip() + + if not selector: + raise ValueError("empty selector") + + index = 0 + + for c in selector: + if c.isalnum() or c in ('_', '|', '?'): + index += 1 + else: + break + + attrs = [] + types = [] + + if index: + elements = selector[:index] + selector = selector[index:] + + for element in elements.split('|'): + element = element.strip() + + if not element: + raise ValueError("empty element") + + if element.endswith('?'): + attrs.append(element[:-1]) + else: + types.append(element) + + span = None + + if selector == '*': + pass + else: + if selector.startswith('['): + try: + i = selector.index(']') + except ValueError: + raise ValueError("expected ']', got EOL") + + _span, span = selector[1:i], [] + + if ':' not in _span: + span = int(_span) + else: + for elt in _span.split(':', 3): + if not elt: + span.append(None) + else: + span.append(int(elt)) + + span = slice(*span) + + selector = selector[i + 1:] + + if selector: + raise ValueError("trailing characters in selector") + + epath.append((attrs, types, span)) + + obj = object.__new__(cls) + + obj._path = _path + obj._epath = epath + + return obj + + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self._path) + + def _get_ordered_args(self, expr): + """Sort ``expr.args`` using printing order. """ + if expr.is_Add: + return expr.as_ordered_terms() + elif expr.is_Mul: + return expr.as_ordered_factors() + else: + return expr.args + + def _hasattrs(self, expr, attrs) -> bool: + """Check if ``expr`` has any of ``attrs``. """ + return all(hasattr(expr, attr) for attr in attrs) + + def _hastypes(self, expr, types): + """Check if ``expr`` is any of ``types``. """ + _types = [ cls.__name__ for cls in expr.__class__.mro() ] + return bool(set(_types).intersection(types)) + + def _has(self, expr, attrs, types): + """Apply ``_hasattrs`` and ``_hastypes`` to ``expr``. """ + if not (attrs or types): + return True + + if attrs and self._hasattrs(expr, attrs): + return True + + if types and self._hastypes(expr, types): + return True + + return False + + def apply(self, expr, func, args=None, kwargs=None): + """ + Modify parts of an expression selected by a path. + + Examples + ======== + + >>> from sympy.simplify.epathtools import EPath + >>> from sympy import sin, cos, E + >>> from sympy.abc import x, y, z, t + + >>> path = EPath("/*/[0]/Symbol") + >>> expr = [((x, 1), 2), ((3, y), z)] + + >>> path.apply(expr, lambda expr: expr**2) + [((x**2, 1), 2), ((3, y**2), z)] + + >>> path = EPath("/*/*/Symbol") + >>> expr = t + sin(x + 1) + cos(x + y + E) + + >>> path.apply(expr, lambda expr: 2*expr) + t + sin(2*x + 1) + cos(2*x + 2*y + E) + + """ + def _apply(path, expr, func): + if not path: + return func(expr) + else: + selector, path = path[0], path[1:] + attrs, types, span = selector + + if isinstance(expr, Basic): + if not expr.is_Atom: + args, basic = self._get_ordered_args(expr), True + else: + return expr + elif hasattr(expr, '__iter__'): + args, basic = expr, False + else: + return expr + + args = list(args) + + if span is not None: + if isinstance(span, slice): + indices = range(*span.indices(len(args))) + else: + indices = [span] + else: + indices = range(len(args)) + + for i in indices: + try: + arg = args[i] + except IndexError: + continue + + if self._has(arg, attrs, types): + args[i] = _apply(path, arg, func) + + if basic: + return expr.func(*args) + else: + return expr.__class__(args) + + _args, _kwargs = args or (), kwargs or {} + _func = lambda expr: func(expr, *_args, **_kwargs) + + return _apply(self._epath, expr, _func) + + def select(self, expr): + """ + Retrieve parts of an expression selected by a path. + + Examples + ======== + + >>> from sympy.simplify.epathtools import EPath + >>> from sympy import sin, cos, E + >>> from sympy.abc import x, y, z, t + + >>> path = EPath("/*/[0]/Symbol") + >>> expr = [((x, 1), 2), ((3, y), z)] + + >>> path.select(expr) + [x, y] + + >>> path = EPath("/*/*/Symbol") + >>> expr = t + sin(x + 1) + cos(x + y + E) + + >>> path.select(expr) + [x, x, y] + + """ + result = [] + + def _select(path, expr): + if not path: + result.append(expr) + else: + selector, path = path[0], path[1:] + attrs, types, span = selector + + if isinstance(expr, Basic): + args = self._get_ordered_args(expr) + elif hasattr(expr, '__iter__'): + args = expr + else: + return + + if span is not None: + if isinstance(span, slice): + args = args[span] + else: + try: + args = [args[span]] + except IndexError: + return + + for arg in args: + if self._has(arg, attrs, types): + _select(path, arg) + + _select(self._epath, expr) + return result + + +def epath(path, expr=None, func=None, args=None, kwargs=None): + r""" + Manipulate parts of an expression selected by a path. + + Explanation + =========== + + This function allows to manipulate large nested expressions in single + line of code, utilizing techniques to those applied in XML processing + standards (e.g. XPath). + + If ``func`` is ``None``, :func:`epath` retrieves elements selected by + the ``path``. Otherwise it applies ``func`` to each matching element. + + Note that it is more efficient to create an EPath object and use the select + and apply methods of that object, since this will compile the path string + only once. This function should only be used as a convenient shortcut for + interactive use. + + This is the supported syntax: + + * select all: ``/*`` + Equivalent of ``for arg in args:``. + * select slice: ``/[0]`` or ``/[1:5]`` or ``/[1:5:2]`` + Supports standard Python's slice syntax. + * select by type: ``/list`` or ``/list|tuple`` + Emulates ``isinstance()``. + * select by attribute: ``/__iter__?`` + Emulates ``hasattr()``. + + Parameters + ========== + + path : str | EPath + A path as a string or a compiled EPath. + expr : Basic | iterable + An expression or a container of expressions. + func : callable (optional) + A callable that will be applied to matching parts. + args : tuple (optional) + Additional positional arguments to ``func``. + kwargs : dict (optional) + Additional keyword arguments to ``func``. + + Examples + ======== + + >>> from sympy.simplify.epathtools import epath + >>> from sympy import sin, cos, E + >>> from sympy.abc import x, y, z, t + + >>> path = "/*/[0]/Symbol" + >>> expr = [((x, 1), 2), ((3, y), z)] + + >>> epath(path, expr) + [x, y] + >>> epath(path, expr, lambda expr: expr**2) + [((x**2, 1), 2), ((3, y**2), z)] + + >>> path = "/*/*/Symbol" + >>> expr = t + sin(x + 1) + cos(x + y + E) + + >>> epath(path, expr) + [x, x, y] + >>> epath(path, expr, lambda expr: 2*expr) + t + sin(2*x + 1) + cos(2*x + 2*y + E) + + """ + _epath = EPath(path) + + if expr is None: + return _epath + if func is None: + return _epath.select(expr) + else: + return _epath.apply(expr, func, args, kwargs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/fu.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/fu.py new file mode 100644 index 0000000000000000000000000000000000000000..a26706edca98385df0009a8ee41476a17d36420c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/fu.py @@ -0,0 +1,2112 @@ +from collections import defaultdict + +from sympy.core.add import Add +from sympy.core.cache import cacheit +from sympy.core.expr import Expr +from sympy.core.exprtools import Factors, gcd_terms, factor_terms +from sympy.core.function import expand_mul +from sympy.core.mul import Mul +from sympy.core.numbers import pi, I +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.core.traversal import bottom_up +from sympy.functions.combinatorial.factorials import binomial +from sympy.functions.elementary.hyperbolic import ( + cosh, sinh, tanh, coth, sech, csch, HyperbolicFunction) +from sympy.functions.elementary.trigonometric import ( + cos, sin, tan, cot, sec, csc, sqrt, TrigonometricFunction) +from sympy.ntheory.factor_ import perfect_power +from sympy.polys.polytools import factor +from sympy.strategies.tree import greedy +from sympy.strategies.core import identity, debug + +from sympy import SYMPY_DEBUG + + +# ================== Fu-like tools =========================== + + +def TR0(rv): + """Simplification of rational polynomials, trying to simplify + the expression, e.g. combine things like 3*x + 2*x, etc.... + """ + # although it would be nice to use cancel, it doesn't work + # with noncommutatives + return rv.normal().factor().expand() + + +def TR1(rv): + """Replace sec, csc with 1/cos, 1/sin + + Examples + ======== + + >>> from sympy.simplify.fu import TR1, sec, csc + >>> from sympy.abc import x + >>> TR1(2*csc(x) + sec(x)) + 1/cos(x) + 2/sin(x) + """ + + def f(rv): + if isinstance(rv, sec): + a = rv.args[0] + return S.One/cos(a) + elif isinstance(rv, csc): + a = rv.args[0] + return S.One/sin(a) + return rv + + return bottom_up(rv, f) + + +def TR2(rv): + """Replace tan and cot with sin/cos and cos/sin + + Examples + ======== + + >>> from sympy.simplify.fu import TR2 + >>> from sympy.abc import x + >>> from sympy import tan, cot, sin, cos + >>> TR2(tan(x)) + sin(x)/cos(x) + >>> TR2(cot(x)) + cos(x)/sin(x) + >>> TR2(tan(tan(x) - sin(x)/cos(x))) + 0 + + """ + + def f(rv): + if isinstance(rv, tan): + a = rv.args[0] + return sin(a)/cos(a) + elif isinstance(rv, cot): + a = rv.args[0] + return cos(a)/sin(a) + return rv + + return bottom_up(rv, f) + + +def TR2i(rv, half=False): + """Converts ratios involving sin and cos as follows:: + sin(x)/cos(x) -> tan(x) + sin(x)/(cos(x) + 1) -> tan(x/2) if half=True + + Examples + ======== + + >>> from sympy.simplify.fu import TR2i + >>> from sympy.abc import x, a + >>> from sympy import sin, cos + >>> TR2i(sin(x)/cos(x)) + tan(x) + + Powers of the numerator and denominator are also recognized + + >>> TR2i(sin(x)**2/(cos(x) + 1)**2, half=True) + tan(x/2)**2 + + The transformation does not take place unless assumptions allow + (i.e. the base must be positive or the exponent must be an integer + for both numerator and denominator) + + >>> TR2i(sin(x)**a/(cos(x) + 1)**a) + sin(x)**a/(cos(x) + 1)**a + + """ + + def f(rv): + if not rv.is_Mul: + return rv + + n, d = rv.as_numer_denom() + if n.is_Atom or d.is_Atom: + return rv + + def ok(k, e): + # initial filtering of factors + return ( + (e.is_integer or k.is_positive) and ( + k.func in (sin, cos) or (half and + k.is_Add and + len(k.args) >= 2 and + any(any(isinstance(ai, cos) or ai.is_Pow and ai.base is cos + for ai in Mul.make_args(a)) for a in k.args)))) + + n = n.as_powers_dict() + ndone = [(k, n.pop(k)) for k in list(n.keys()) if not ok(k, n[k])] + if not n: + return rv + + d = d.as_powers_dict() + ddone = [(k, d.pop(k)) for k in list(d.keys()) if not ok(k, d[k])] + if not d: + return rv + + # factoring if necessary + + def factorize(d, ddone): + newk = [] + for k in d: + if k.is_Add and len(k.args) > 1: + knew = factor(k) if half else factor_terms(k) + if knew != k: + newk.append((k, knew)) + if newk: + for i, (k, knew) in enumerate(newk): + del d[k] + newk[i] = knew + newk = Mul(*newk).as_powers_dict() + for k in newk: + v = d[k] + newk[k] + if ok(k, v): + d[k] = v + else: + ddone.append((k, v)) + del newk + factorize(n, ndone) + factorize(d, ddone) + + # joining + t = [] + for k in n: + if isinstance(k, sin): + a = cos(k.args[0], evaluate=False) + if a in d and d[a] == n[k]: + t.append(tan(k.args[0])**n[k]) + n[k] = d[a] = None + elif half: + a1 = 1 + a + if a1 in d and d[a1] == n[k]: + t.append((tan(k.args[0]/2))**n[k]) + n[k] = d[a1] = None + elif isinstance(k, cos): + a = sin(k.args[0], evaluate=False) + if a in d and d[a] == n[k]: + t.append(tan(k.args[0])**-n[k]) + n[k] = d[a] = None + elif half and k.is_Add and k.args[0] is S.One and \ + isinstance(k.args[1], cos): + a = sin(k.args[1].args[0], evaluate=False) + if a in d and d[a] == n[k] and (d[a].is_integer or \ + a.is_positive): + t.append(tan(a.args[0]/2)**-n[k]) + n[k] = d[a] = None + + if t: + rv = Mul(*(t + [b**e for b, e in n.items() if e]))/\ + Mul(*[b**e for b, e in d.items() if e]) + rv *= Mul(*[b**e for b, e in ndone])/Mul(*[b**e for b, e in ddone]) + + return rv + + return bottom_up(rv, f) + + +def TR3(rv): + """Induced formula: example sin(-a) = -sin(a) + + Examples + ======== + + >>> from sympy.simplify.fu import TR3 + >>> from sympy.abc import x, y + >>> from sympy import pi + >>> from sympy import cos + >>> TR3(cos(y - x*(y - x))) + cos(x*(x - y) + y) + >>> cos(pi/2 + x) + -sin(x) + >>> cos(30*pi/2 + x) + -cos(x) + + """ + from sympy.simplify.simplify import signsimp + + # Negative argument (already automatic for funcs like sin(-x) -> -sin(x) + # but more complicated expressions can use it, too). Also, trig angles + # between pi/4 and pi/2 are not reduced to an angle between 0 and pi/4. + # The following are automatically handled: + # Argument of type: pi/2 +/- angle + # Argument of type: pi +/- angle + # Argument of type : 2k*pi +/- angle + + def f(rv): + if not isinstance(rv, TrigonometricFunction): + return rv + rv = rv.func(signsimp(rv.args[0])) + if not isinstance(rv, TrigonometricFunction): + return rv + if (rv.args[0] - S.Pi/4).is_positive is (S.Pi/2 - rv.args[0]).is_positive is True: + fmap = {cos: sin, sin: cos, tan: cot, cot: tan, sec: csc, csc: sec} + rv = fmap[type(rv)](S.Pi/2 - rv.args[0]) + return rv + + # touch numbers iside of trig functions to let them automatically update + rv = rv.replace( + lambda x: isinstance(x, TrigonometricFunction), + lambda x: x.replace( + lambda n: n.is_number and n.is_Mul, + lambda n: n.func(*n.args))) + + return bottom_up(rv, f) + + +def TR4(rv): + """Identify values of special angles. + + a= 0 pi/6 pi/4 pi/3 pi/2 + ---------------------------------------------------- + sin(a) 0 1/2 sqrt(2)/2 sqrt(3)/2 1 + cos(a) 1 sqrt(3)/2 sqrt(2)/2 1/2 0 + tan(a) 0 sqt(3)/3 1 sqrt(3) -- + + Examples + ======== + + >>> from sympy import pi + >>> from sympy import cos, sin, tan, cot + >>> for s in (0, pi/6, pi/4, pi/3, pi/2): + ... print('%s %s %s %s' % (cos(s), sin(s), tan(s), cot(s))) + ... + 1 0 0 zoo + sqrt(3)/2 1/2 sqrt(3)/3 sqrt(3) + sqrt(2)/2 sqrt(2)/2 1 1 + 1/2 sqrt(3)/2 sqrt(3) sqrt(3)/3 + 0 1 zoo 0 + """ + # special values at 0, pi/6, pi/4, pi/3, pi/2 already handled + return rv.replace( + lambda x: + isinstance(x, TrigonometricFunction) and + (r:=x.args[0]/pi).is_Rational and r.q in (1, 2, 3, 4, 6), + lambda x: + x.func(x.args[0].func(*x.args[0].args))) + + +def _TR56(rv, f, g, h, max, pow): + """Helper for TR5 and TR6 to replace f**2 with h(g**2) + + Options + ======= + + max : controls size of exponent that can appear on f + e.g. if max=4 then f**4 will be changed to h(g**2)**2. + pow : controls whether the exponent must be a perfect power of 2 + e.g. if pow=True (and max >= 6) then f**6 will not be changed + but f**8 will be changed to h(g**2)**4 + + >>> from sympy.simplify.fu import _TR56 as T + >>> from sympy.abc import x + >>> from sympy import sin, cos + >>> h = lambda x: 1 - x + >>> T(sin(x)**3, sin, cos, h, 4, False) + (1 - cos(x)**2)*sin(x) + >>> T(sin(x)**6, sin, cos, h, 6, False) + (1 - cos(x)**2)**3 + >>> T(sin(x)**6, sin, cos, h, 6, True) + sin(x)**6 + >>> T(sin(x)**8, sin, cos, h, 10, True) + (1 - cos(x)**2)**4 + """ + + def _f(rv): + # I'm not sure if this transformation should target all even powers + # or only those expressible as powers of 2. Also, should it only + # make the changes in powers that appear in sums -- making an isolated + # change is not going to allow a simplification as far as I can tell. + if not (rv.is_Pow and rv.base.func == f): + return rv + if not rv.exp.is_real: + return rv + + if (rv.exp < 0) == True: + return rv + if (rv.exp > max) == True: + return rv + if rv.exp == 1: + return rv + if rv.exp == 2: + return h(g(rv.base.args[0])**2) + else: + if rv.exp % 2 == 1: + e = rv.exp//2 + return f(rv.base.args[0])*h(g(rv.base.args[0])**2)**e + elif rv.exp == 4: + e = 2 + elif not pow: + if rv.exp % 2: + return rv + e = rv.exp//2 + else: + p = perfect_power(rv.exp) + if not p: + return rv + e = rv.exp//2 + return h(g(rv.base.args[0])**2)**e + + return bottom_up(rv, _f) + + +def TR5(rv, max=4, pow=False): + """Replacement of sin**2 with 1 - cos(x)**2. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR5 + >>> from sympy.abc import x + >>> from sympy import sin + >>> TR5(sin(x)**2) + 1 - cos(x)**2 + >>> TR5(sin(x)**-2) # unchanged + sin(x)**(-2) + >>> TR5(sin(x)**4) + (1 - cos(x)**2)**2 + """ + return _TR56(rv, sin, cos, lambda x: 1 - x, max=max, pow=pow) + + +def TR6(rv, max=4, pow=False): + """Replacement of cos**2 with 1 - sin(x)**2. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR6 + >>> from sympy.abc import x + >>> from sympy import cos + >>> TR6(cos(x)**2) + 1 - sin(x)**2 + >>> TR6(cos(x)**-2) #unchanged + cos(x)**(-2) + >>> TR6(cos(x)**4) + (1 - sin(x)**2)**2 + """ + return _TR56(rv, cos, sin, lambda x: 1 - x, max=max, pow=pow) + + +def TR7(rv): + """Lowering the degree of cos(x)**2. + + Examples + ======== + + >>> from sympy.simplify.fu import TR7 + >>> from sympy.abc import x + >>> from sympy import cos + >>> TR7(cos(x)**2) + cos(2*x)/2 + 1/2 + >>> TR7(cos(x)**2 + 1) + cos(2*x)/2 + 3/2 + + """ + + def f(rv): + if not (rv.is_Pow and rv.base.func == cos and rv.exp == 2): + return rv + return (1 + cos(2*rv.base.args[0]))/2 + + return bottom_up(rv, f) + + +def TR8(rv, first=True): + """Converting products of ``cos`` and/or ``sin`` to a sum or + difference of ``cos`` and or ``sin`` terms. + + Examples + ======== + + >>> from sympy.simplify.fu import TR8 + >>> from sympy import cos, sin + >>> TR8(cos(2)*cos(3)) + cos(5)/2 + cos(1)/2 + >>> TR8(cos(2)*sin(3)) + sin(5)/2 + sin(1)/2 + >>> TR8(sin(2)*sin(3)) + -cos(5)/2 + cos(1)/2 + """ + + def f(rv): + if not ( + rv.is_Mul or + rv.is_Pow and + rv.base.func in (cos, sin) and + (rv.exp.is_integer or rv.base.is_positive)): + return rv + + if first: + n, d = [expand_mul(i) for i in rv.as_numer_denom()] + newn = TR8(n, first=False) + newd = TR8(d, first=False) + if newn != n or newd != d: + rv = gcd_terms(newn/newd) + if rv.is_Mul and rv.args[0].is_Rational and \ + len(rv.args) == 2 and rv.args[1].is_Add: + rv = Mul(*rv.as_coeff_Mul()) + return rv + + args = {cos: [], sin: [], None: []} + for a in Mul.make_args(rv): + if a.func in (cos, sin): + args[type(a)].append(a.args[0]) + elif (a.is_Pow and a.exp.is_Integer and a.exp > 0 and \ + a.base.func in (cos, sin)): + # XXX this is ok but pathological expression could be handled + # more efficiently as in TRmorrie + args[type(a.base)].extend([a.base.args[0]]*a.exp) + else: + args[None].append(a) + c = args[cos] + s = args[sin] + if not (c and s or len(c) > 1 or len(s) > 1): + return rv + + args = args[None] + n = min(len(c), len(s)) + for i in range(n): + a1 = s.pop() + a2 = c.pop() + args.append((sin(a1 + a2) + sin(a1 - a2))/2) + while len(c) > 1: + a1 = c.pop() + a2 = c.pop() + args.append((cos(a1 + a2) + cos(a1 - a2))/2) + if c: + args.append(cos(c.pop())) + while len(s) > 1: + a1 = s.pop() + a2 = s.pop() + args.append((-cos(a1 + a2) + cos(a1 - a2))/2) + if s: + args.append(sin(s.pop())) + return TR8(expand_mul(Mul(*args))) + + return bottom_up(rv, f) + + +def TR9(rv): + """Sum of ``cos`` or ``sin`` terms as a product of ``cos`` or ``sin``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR9 + >>> from sympy import cos, sin + >>> TR9(cos(1) + cos(2)) + 2*cos(1/2)*cos(3/2) + >>> TR9(cos(1) + 2*sin(1) + 2*sin(2)) + cos(1) + 4*sin(3/2)*cos(1/2) + + If no change is made by TR9, no re-arrangement of the + expression will be made. For example, though factoring + of common term is attempted, if the factored expression + was not changed, the original expression will be returned: + + >>> TR9(cos(3) + cos(3)*cos(2)) + cos(3) + cos(2)*cos(3) + + """ + + def f(rv): + if not rv.is_Add: + return rv + + def do(rv, first=True): + # cos(a)+/-cos(b) can be combined into a product of cosines and + # sin(a)+/-sin(b) can be combined into a product of cosine and + # sine. + # + # If there are more than two args, the pairs which "work" will + # have a gcd extractable and the remaining two terms will have + # the above structure -- all pairs must be checked to find the + # ones that work. args that don't have a common set of symbols + # are skipped since this doesn't lead to a simpler formula and + # also has the arbitrariness of combining, for example, the x + # and y term instead of the y and z term in something like + # cos(x) + cos(y) + cos(z). + + if not rv.is_Add: + return rv + + args = list(ordered(rv.args)) + if len(args) != 2: + hit = False + for i in range(len(args)): + ai = args[i] + if ai is None: + continue + for j in range(i + 1, len(args)): + aj = args[j] + if aj is None: + continue + was = ai + aj + new = do(was) + if new != was: + args[i] = new # update in place + args[j] = None + hit = True + break # go to next i + if hit: + rv = Add(*[_f for _f in args if _f]) + if rv.is_Add: + rv = do(rv) + + return rv + + # two-arg Add + split = trig_split(*args) + if not split: + return rv + gcd, n1, n2, a, b, iscos = split + + # application of rule if possible + if iscos: + if n1 == n2: + return gcd*n1*2*cos((a + b)/2)*cos((a - b)/2) + if n1 < 0: + a, b = b, a + return -2*gcd*sin((a + b)/2)*sin((a - b)/2) + else: + if n1 == n2: + return gcd*n1*2*sin((a + b)/2)*cos((a - b)/2) + if n1 < 0: + a, b = b, a + return 2*gcd*cos((a + b)/2)*sin((a - b)/2) + + return process_common_addends(rv, do) # DON'T sift by free symbols + + return bottom_up(rv, f) + + +def TR10(rv, first=True): + """Separate sums in ``cos`` and ``sin``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR10 + >>> from sympy.abc import a, b, c + >>> from sympy import cos, sin + >>> TR10(cos(a + b)) + -sin(a)*sin(b) + cos(a)*cos(b) + >>> TR10(sin(a + b)) + sin(a)*cos(b) + sin(b)*cos(a) + >>> TR10(sin(a + b + c)) + (-sin(a)*sin(b) + cos(a)*cos(b))*sin(c) + \ + (sin(a)*cos(b) + sin(b)*cos(a))*cos(c) + """ + + def f(rv): + if rv.func not in (cos, sin): + return rv + + f = rv.func + arg = rv.args[0] + if arg.is_Add: + if first: + args = list(ordered(arg.args)) + else: + args = list(arg.args) + a = args.pop() + b = Add._from_args(args) + if b.is_Add: + if f == sin: + return sin(a)*TR10(cos(b), first=False) + \ + cos(a)*TR10(sin(b), first=False) + else: + return cos(a)*TR10(cos(b), first=False) - \ + sin(a)*TR10(sin(b), first=False) + else: + if f == sin: + return sin(a)*cos(b) + cos(a)*sin(b) + else: + return cos(a)*cos(b) - sin(a)*sin(b) + return rv + + return bottom_up(rv, f) + + +def TR10i(rv): + """Sum of products to function of sum. + + Examples + ======== + + >>> from sympy.simplify.fu import TR10i + >>> from sympy import cos, sin, sqrt + >>> from sympy.abc import x + + >>> TR10i(cos(1)*cos(3) + sin(1)*sin(3)) + cos(2) + >>> TR10i(cos(1)*sin(3) + sin(1)*cos(3) + cos(3)) + cos(3) + sin(4) + >>> TR10i(sqrt(2)*cos(x)*x + sqrt(6)*sin(x)*x) + 2*sqrt(2)*x*sin(x + pi/6) + + """ + def f(rv): + if not rv.is_Add: + return rv + + def do(rv, first=True): + # args which can be expressed as A*(cos(a)*cos(b)+/-sin(a)*sin(b)) + # or B*(cos(a)*sin(b)+/-cos(b)*sin(a)) can be combined into + # A*f(a+/-b) where f is either sin or cos. + # + # If there are more than two args, the pairs which "work" will have + # a gcd extractable and the remaining two terms will have the above + # structure -- all pairs must be checked to find the ones that + # work. + + if not rv.is_Add: + return rv + + args = list(ordered(rv.args)) + if len(args) != 2: + hit = False + for i in range(len(args)): + ai = args[i] + if ai is None: + continue + for j in range(i + 1, len(args)): + aj = args[j] + if aj is None: + continue + was = ai + aj + new = do(was) + if new != was: + args[i] = new # update in place + args[j] = None + hit = True + break # go to next i + if hit: + rv = Add(*[_f for _f in args if _f]) + if rv.is_Add: + rv = do(rv) + + return rv + + # two-arg Add + split = trig_split(*args, two=True) + if not split: + return rv + gcd, n1, n2, a, b, same = split + + # identify and get c1 to be cos then apply rule if possible + if same: # coscos, sinsin + gcd = n1*gcd + if n1 == n2: + return gcd*cos(a - b) + return gcd*cos(a + b) + else: #cossin, cossin + gcd = n1*gcd + if n1 == n2: + return gcd*sin(a + b) + return gcd*sin(b - a) + + rv = process_common_addends( + rv, do, lambda x: tuple(ordered(x.free_symbols))) + + # need to check for inducible pairs in ratio of sqrt(3):1 that + # appeared in different lists when sorting by coefficient + while rv.is_Add: + byrad = defaultdict(list) + for a in rv.args: + hit = 0 + if a.is_Mul: + for ai in a.args: + if ai.is_Pow and ai.exp is S.Half and \ + ai.base.is_Integer: + byrad[ai].append(a) + hit = 1 + break + if not hit: + byrad[S.One].append(a) + + # no need to check all pairs -- just check for the onees + # that have the right ratio + args = [] + for a in byrad: + for b in [_ROOT3()*a, _invROOT3()]: + if b in byrad: + for i in range(len(byrad[a])): + if byrad[a][i] is None: + continue + for j in range(len(byrad[b])): + if byrad[b][j] is None: + continue + was = Add(byrad[a][i] + byrad[b][j]) + new = do(was) + if new != was: + args.append(new) + byrad[a][i] = None + byrad[b][j] = None + break + if args: + rv = Add(*(args + [Add(*[_f for _f in v if _f]) + for v in byrad.values()])) + else: + rv = do(rv) # final pass to resolve any new inducible pairs + break + + return rv + + return bottom_up(rv, f) + + +def TR11(rv, base=None): + """Function of double angle to product. The ``base`` argument can be used + to indicate what is the un-doubled argument, e.g. if 3*pi/7 is the base + then cosine and sine functions with argument 6*pi/7 will be replaced. + + Examples + ======== + + >>> from sympy.simplify.fu import TR11 + >>> from sympy import cos, sin, pi + >>> from sympy.abc import x + >>> TR11(sin(2*x)) + 2*sin(x)*cos(x) + >>> TR11(cos(2*x)) + -sin(x)**2 + cos(x)**2 + >>> TR11(sin(4*x)) + 4*(-sin(x)**2 + cos(x)**2)*sin(x)*cos(x) + >>> TR11(sin(4*x/3)) + 4*(-sin(x/3)**2 + cos(x/3)**2)*sin(x/3)*cos(x/3) + + If the arguments are simply integers, no change is made + unless a base is provided: + + >>> TR11(cos(2)) + cos(2) + >>> TR11(cos(4), 2) + -sin(2)**2 + cos(2)**2 + + There is a subtle issue here in that autosimplification will convert + some higher angles to lower angles + + >>> cos(6*pi/7) + cos(3*pi/7) + -cos(pi/7) + cos(3*pi/7) + + The 6*pi/7 angle is now pi/7 but can be targeted with TR11 by supplying + the 3*pi/7 base: + + >>> TR11(_, 3*pi/7) + -sin(3*pi/7)**2 + cos(3*pi/7)**2 + cos(3*pi/7) + + """ + + def f(rv): + if rv.func not in (cos, sin): + return rv + + if base: + f = rv.func + t = f(base*2) + co = S.One + if t.is_Mul: + co, t = t.as_coeff_Mul() + if t.func not in (cos, sin): + return rv + if rv.args[0] == t.args[0]: + c = cos(base) + s = sin(base) + if f is cos: + return (c**2 - s**2)/co + else: + return 2*c*s/co + return rv + + elif not rv.args[0].is_Number: + # make a change if the leading coefficient's numerator is + # divisible by 2 + c, m = rv.args[0].as_coeff_Mul(rational=True) + if c.p % 2 == 0: + arg = c.p//2*m/c.q + c = TR11(cos(arg)) + s = TR11(sin(arg)) + if rv.func == sin: + rv = 2*s*c + else: + rv = c**2 - s**2 + return rv + + return bottom_up(rv, f) + + +def _TR11(rv): + """ + Helper for TR11 to find half-arguments for sin in factors of + num/den that appear in cos or sin factors in the den/num. + + Examples + ======== + + >>> from sympy.simplify.fu import TR11, _TR11 + >>> from sympy import cos, sin + >>> from sympy.abc import x + >>> TR11(sin(x/3)/(cos(x/6))) + sin(x/3)/cos(x/6) + >>> _TR11(sin(x/3)/(cos(x/6))) + 2*sin(x/6) + >>> TR11(sin(x/6)/(sin(x/3))) + sin(x/6)/sin(x/3) + >>> _TR11(sin(x/6)/(sin(x/3))) + 1/(2*cos(x/6)) + + """ + def f(rv): + if not isinstance(rv, Expr): + return rv + + def sincos_args(flat): + # find arguments of sin and cos that + # appears as bases in args of flat + # and have Integer exponents + args = defaultdict(set) + for fi in Mul.make_args(flat): + b, e = fi.as_base_exp() + if e.is_Integer and e > 0: + if b.func in (cos, sin): + args[type(b)].add(b.args[0]) + return args + num_args, den_args = map(sincos_args, rv.as_numer_denom()) + def handle_match(rv, num_args, den_args): + # for arg in sin args of num_args, look for arg/2 + # in den_args and pass this half-angle to TR11 + # for handling in rv + for narg in num_args[sin]: + half = narg/2 + if half in den_args[cos]: + func = cos + elif half in den_args[sin]: + func = sin + else: + continue + rv = TR11(rv, half) + den_args[func].remove(half) + return rv + # sin in num, sin or cos in den + rv = handle_match(rv, num_args, den_args) + # sin in den, sin or cos in num + rv = handle_match(rv, den_args, num_args) + return rv + + return bottom_up(rv, f) + + +def TR12(rv, first=True): + """Separate sums in ``tan``. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import tan + >>> from sympy.simplify.fu import TR12 + >>> TR12(tan(x + y)) + (tan(x) + tan(y))/(-tan(x)*tan(y) + 1) + """ + + def f(rv): + if not rv.func == tan: + return rv + + arg = rv.args[0] + if arg.is_Add: + if first: + args = list(ordered(arg.args)) + else: + args = list(arg.args) + a = args.pop() + b = Add._from_args(args) + if b.is_Add: + tb = TR12(tan(b), first=False) + else: + tb = tan(b) + return (tan(a) + tb)/(1 - tan(a)*tb) + return rv + + return bottom_up(rv, f) + + +def TR12i(rv): + """Combine tan arguments as + (tan(y) + tan(x))/(tan(x)*tan(y) - 1) -> -tan(x + y). + + Examples + ======== + + >>> from sympy.simplify.fu import TR12i + >>> from sympy import tan + >>> from sympy.abc import a, b, c + >>> ta, tb, tc = [tan(i) for i in (a, b, c)] + >>> TR12i((ta + tb)/(-ta*tb + 1)) + tan(a + b) + >>> TR12i((ta + tb)/(ta*tb - 1)) + -tan(a + b) + >>> TR12i((-ta - tb)/(ta*tb - 1)) + tan(a + b) + >>> eq = (ta + tb)/(-ta*tb + 1)**2*(-3*ta - 3*tc)/(2*(ta*tc - 1)) + >>> TR12i(eq.expand()) + -3*tan(a + b)*tan(a + c)/(2*(tan(a) + tan(b) - 1)) + """ + def f(rv): + if not (rv.is_Add or rv.is_Mul or rv.is_Pow): + return rv + + n, d = rv.as_numer_denom() + if not d.args or not n.args: + return rv + + dok = {} + + def ok(di): + m = as_f_sign_1(di) + if m: + g, f, s = m + if s is S.NegativeOne and f.is_Mul and len(f.args) == 2 and \ + all(isinstance(fi, tan) for fi in f.args): + return g, f + + d_args = list(Mul.make_args(d)) + for i, di in enumerate(d_args): + m = ok(di) + if m: + g, t = m + s = Add(*[_.args[0] for _ in t.args]) + dok[s] = S.One + d_args[i] = g + continue + if di.is_Add: + di = factor(di) + if di.is_Mul: + d_args.extend(di.args) + d_args[i] = S.One + elif di.is_Pow and (di.exp.is_integer or di.base.is_positive): + m = ok(di.base) + if m: + g, t = m + s = Add(*[_.args[0] for _ in t.args]) + dok[s] = di.exp + d_args[i] = g**di.exp + else: + di = factor(di) + if di.is_Mul: + d_args.extend(di.args) + d_args[i] = S.One + if not dok: + return rv + + def ok(ni): + if ni.is_Add and len(ni.args) == 2: + a, b = ni.args + if isinstance(a, tan) and isinstance(b, tan): + return a, b + n_args = list(Mul.make_args(factor_terms(n))) + hit = False + for i, ni in enumerate(n_args): + m = ok(ni) + if not m: + m = ok(-ni) + if m: + n_args[i] = S.NegativeOne + else: + if ni.is_Add: + ni = factor(ni) + if ni.is_Mul: + n_args.extend(ni.args) + n_args[i] = S.One + continue + elif ni.is_Pow and ( + ni.exp.is_integer or ni.base.is_positive): + m = ok(ni.base) + if m: + n_args[i] = S.One + else: + ni = factor(ni) + if ni.is_Mul: + n_args.extend(ni.args) + n_args[i] = S.One + continue + else: + continue + else: + n_args[i] = S.One + hit = True + s = Add(*[_.args[0] for _ in m]) + ed = dok[s] + newed = ed.extract_additively(S.One) + if newed is not None: + if newed: + dok[s] = newed + else: + dok.pop(s) + n_args[i] *= -tan(s) + + if hit: + rv = Mul(*n_args)/Mul(*d_args)/Mul(*[(Add(*[ + tan(a) for a in i.args]) - 1)**e for i, e in dok.items()]) + + return rv + + return bottom_up(rv, f) + + +def TR13(rv): + """Change products of ``tan`` or ``cot``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR13 + >>> from sympy import tan, cot + >>> TR13(tan(3)*tan(2)) + -tan(2)/tan(5) - tan(3)/tan(5) + 1 + >>> TR13(cot(3)*cot(2)) + cot(2)*cot(5) + 1 + cot(3)*cot(5) + """ + + def f(rv): + if not rv.is_Mul: + return rv + + # XXX handle products of powers? or let power-reducing handle it? + args = {tan: [], cot: [], None: []} + for a in Mul.make_args(rv): + if a.func in (tan, cot): + args[type(a)].append(a.args[0]) + else: + args[None].append(a) + t = args[tan] + c = args[cot] + if len(t) < 2 and len(c) < 2: + return rv + args = args[None] + while len(t) > 1: + t1 = t.pop() + t2 = t.pop() + args.append(1 - (tan(t1)/tan(t1 + t2) + tan(t2)/tan(t1 + t2))) + if t: + args.append(tan(t.pop())) + while len(c) > 1: + t1 = c.pop() + t2 = c.pop() + args.append(1 + cot(t1)*cot(t1 + t2) + cot(t2)*cot(t1 + t2)) + if c: + args.append(cot(c.pop())) + return Mul(*args) + + return bottom_up(rv, f) + + +def TRmorrie(rv): + """Returns cos(x)*cos(2*x)*...*cos(2**(k-1)*x) -> sin(2**k*x)/(2**k*sin(x)) + + Examples + ======== + + >>> from sympy.simplify.fu import TRmorrie, TR8, TR3 + >>> from sympy.abc import x + >>> from sympy import Mul, cos, pi + >>> TRmorrie(cos(x)*cos(2*x)) + sin(4*x)/(4*sin(x)) + >>> TRmorrie(7*Mul(*[cos(x) for x in range(10)])) + 7*sin(12)*sin(16)*cos(5)*cos(7)*cos(9)/(64*sin(1)*sin(3)) + + Sometimes autosimplification will cause a power to be + not recognized. e.g. in the following, cos(4*pi/7) automatically + simplifies to -cos(3*pi/7) so only 2 of the 3 terms are + recognized: + + >>> TRmorrie(cos(pi/7)*cos(2*pi/7)*cos(4*pi/7)) + -sin(3*pi/7)*cos(3*pi/7)/(4*sin(pi/7)) + + A touch by TR8 resolves the expression to a Rational + + >>> TR8(_) + -1/8 + + In this case, if eq is unsimplified, the answer is obtained + directly: + + >>> eq = cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9) + >>> TRmorrie(eq) + 1/16 + + But if angles are made canonical with TR3 then the answer + is not simplified without further work: + + >>> TR3(eq) + sin(pi/18)*cos(pi/9)*cos(2*pi/9)/2 + >>> TRmorrie(_) + sin(pi/18)*sin(4*pi/9)/(8*sin(pi/9)) + >>> TR8(_) + cos(7*pi/18)/(16*sin(pi/9)) + >>> TR3(_) + 1/16 + + The original expression would have resolve to 1/16 directly with TR8, + however: + + >>> TR8(eq) + 1/16 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Morrie%27s_law + + """ + + def f(rv, first=True): + if not rv.is_Mul: + return rv + if first: + n, d = rv.as_numer_denom() + return f(n, 0)/f(d, 0) + + args = defaultdict(list) + coss = {} + other = [] + for c in rv.args: + b, e = c.as_base_exp() + if e.is_Integer and isinstance(b, cos): + co, a = b.args[0].as_coeff_Mul() + args[a].append(co) + coss[b] = e + else: + other.append(c) + + new = [] + for a in args: + c = args[a] + c.sort() + while c: + k = 0 + cc = ci = c[0] + while cc in c: + k += 1 + cc *= 2 + if k > 1: + newarg = sin(2**k*ci*a)/2**k/sin(ci*a) + # see how many times this can be taken + take = None + ccs = [] + for i in range(k): + cc /= 2 + key = cos(a*cc, evaluate=False) + ccs.append(cc) + take = min(coss[key], take or coss[key]) + # update exponent counts + for i in range(k): + cc = ccs.pop() + key = cos(a*cc, evaluate=False) + coss[key] -= take + if not coss[key]: + c.remove(cc) + new.append(newarg**take) + else: + b = cos(c.pop(0)*a) + other.append(b**coss[b]) + + if new: + rv = Mul(*(new + other + [ + cos(k*a, evaluate=False) for a in args for k in args[a]])) + + return rv + + return bottom_up(rv, f) + + +def TR14(rv, first=True): + """Convert factored powers of sin and cos identities into simpler + expressions. + + Examples + ======== + + >>> from sympy.simplify.fu import TR14 + >>> from sympy.abc import x, y + >>> from sympy import cos, sin + >>> TR14((cos(x) - 1)*(cos(x) + 1)) + -sin(x)**2 + >>> TR14((sin(x) - 1)*(sin(x) + 1)) + -cos(x)**2 + >>> p1 = (cos(x) + 1)*(cos(x) - 1) + >>> p2 = (cos(y) - 1)*2*(cos(y) + 1) + >>> p3 = (3*(cos(y) - 1))*(3*(cos(y) + 1)) + >>> TR14(p1*p2*p3*(x - 1)) + -18*(x - 1)*sin(x)**2*sin(y)**4 + + """ + + def f(rv): + if not rv.is_Mul: + return rv + + if first: + # sort them by location in numerator and denominator + # so the code below can just deal with positive exponents + n, d = rv.as_numer_denom() + if d is not S.One: + newn = TR14(n, first=False) + newd = TR14(d, first=False) + if newn != n or newd != d: + rv = newn/newd + return rv + + other = [] + process = [] + for a in rv.args: + if a.is_Pow: + b, e = a.as_base_exp() + if not (e.is_integer or b.is_positive): + other.append(a) + continue + a = b + else: + e = S.One + m = as_f_sign_1(a) + if not m or m[1].func not in (cos, sin): + if e is S.One: + other.append(a) + else: + other.append(a**e) + continue + g, f, si = m + process.append((g, e.is_Number, e, f, si, a)) + + # sort them to get like terms next to each other + process = list(ordered(process)) + + # keep track of whether there was any change + nother = len(other) + + # access keys + keys = (g, t, e, f, si, a) = list(range(6)) + + while process: + A = process.pop(0) + if process: + B = process[0] + + if A[e].is_Number and B[e].is_Number: + # both exponents are numbers + if A[f] == B[f]: + if A[si] != B[si]: + B = process.pop(0) + take = min(A[e], B[e]) + + # reinsert any remainder + # the B will likely sort after A so check it first + if B[e] != take: + rem = [B[i] for i in keys] + rem[e] -= take + process.insert(0, rem) + elif A[e] != take: + rem = [A[i] for i in keys] + rem[e] -= take + process.insert(0, rem) + + if isinstance(A[f], cos): + t = sin + else: + t = cos + other.append((-A[g]*B[g]*t(A[f].args[0])**2)**take) + continue + + elif A[e] == B[e]: + # both exponents are equal symbols + if A[f] == B[f]: + if A[si] != B[si]: + B = process.pop(0) + take = A[e] + if isinstance(A[f], cos): + t = sin + else: + t = cos + other.append((-A[g]*B[g]*t(A[f].args[0])**2)**take) + continue + + # either we are done or neither condition above applied + other.append(A[a]**A[e]) + + if len(other) != nother: + rv = Mul(*other) + + return rv + + return bottom_up(rv, f) + + +def TR15(rv, max=4, pow=False): + """Convert sin(x)**-2 to 1 + cot(x)**2. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR15 + >>> from sympy.abc import x + >>> from sympy import sin + >>> TR15(1 - 1/sin(x)**2) + -cot(x)**2 + + """ + + def f(rv): + if not (isinstance(rv, Pow) and isinstance(rv.base, sin)): + return rv + + e = rv.exp + if e % 2 == 1: + return TR15(rv.base**(e + 1))/rv.base + + ia = 1/rv + a = _TR56(ia, sin, cot, lambda x: 1 + x, max=max, pow=pow) + if a != ia: + rv = a + return rv + + return bottom_up(rv, f) + + +def TR16(rv, max=4, pow=False): + """Convert cos(x)**-2 to 1 + tan(x)**2. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR16 + >>> from sympy.abc import x + >>> from sympy import cos + >>> TR16(1 - 1/cos(x)**2) + -tan(x)**2 + + """ + + def f(rv): + if not (isinstance(rv, Pow) and isinstance(rv.base, cos)): + return rv + + e = rv.exp + if e % 2 == 1: + return TR15(rv.base**(e + 1))/rv.base + + ia = 1/rv + a = _TR56(ia, cos, tan, lambda x: 1 + x, max=max, pow=pow) + if a != ia: + rv = a + return rv + + return bottom_up(rv, f) + + +def TR111(rv): + """Convert f(x)**-i to g(x)**i where either ``i`` is an integer + or the base is positive and f, g are: tan, cot; sin, csc; or cos, sec. + + Examples + ======== + + >>> from sympy.simplify.fu import TR111 + >>> from sympy.abc import x + >>> from sympy import tan + >>> TR111(1 - 1/tan(x)**2) + 1 - cot(x)**2 + + """ + + def f(rv): + if not ( + isinstance(rv, Pow) and + (rv.base.is_positive or rv.exp.is_integer and rv.exp.is_negative)): + return rv + + if isinstance(rv.base, tan): + return cot(rv.base.args[0])**-rv.exp + elif isinstance(rv.base, sin): + return csc(rv.base.args[0])**-rv.exp + elif isinstance(rv.base, cos): + return sec(rv.base.args[0])**-rv.exp + return rv + + return bottom_up(rv, f) + + +def TR22(rv, max=4, pow=False): + """Convert tan(x)**2 to sec(x)**2 - 1 and cot(x)**2 to csc(x)**2 - 1. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR22 + >>> from sympy.abc import x + >>> from sympy import tan, cot + >>> TR22(1 + tan(x)**2) + sec(x)**2 + >>> TR22(1 + cot(x)**2) + csc(x)**2 + + """ + + def f(rv): + if not (isinstance(rv, Pow) and rv.base.func in (cot, tan)): + return rv + + rv = _TR56(rv, tan, sec, lambda x: x - 1, max=max, pow=pow) + rv = _TR56(rv, cot, csc, lambda x: x - 1, max=max, pow=pow) + return rv + + return bottom_up(rv, f) + + +def TRpower(rv): + """Convert sin(x)**n and cos(x)**n with positive n to sums. + + Examples + ======== + + >>> from sympy.simplify.fu import TRpower + >>> from sympy.abc import x + >>> from sympy import cos, sin + >>> TRpower(sin(x)**6) + -15*cos(2*x)/32 + 3*cos(4*x)/16 - cos(6*x)/32 + 5/16 + >>> TRpower(sin(x)**3*cos(2*x)**4) + (3*sin(x)/4 - sin(3*x)/4)*(cos(4*x)/2 + cos(8*x)/8 + 3/8) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Power-reduction_formulae + + """ + + def f(rv): + if not (isinstance(rv, Pow) and isinstance(rv.base, (sin, cos))): + return rv + b, n = rv.as_base_exp() + x = b.args[0] + if n.is_Integer and n.is_positive: + if n.is_odd and isinstance(b, cos): + rv = 2**(1-n)*Add(*[binomial(n, k)*cos((n - 2*k)*x) + for k in range((n + 1)/2)]) + elif n.is_odd and isinstance(b, sin): + rv = 2**(1-n)*S.NegativeOne**((n-1)/2)*Add(*[binomial(n, k)* + S.NegativeOne**k*sin((n - 2*k)*x) for k in range((n + 1)/2)]) + elif n.is_even and isinstance(b, cos): + rv = 2**(1-n)*Add(*[binomial(n, k)*cos((n - 2*k)*x) + for k in range(n/2)]) + elif n.is_even and isinstance(b, sin): + rv = 2**(1-n)*S.NegativeOne**(n/2)*Add(*[binomial(n, k)* + S.NegativeOne**k*cos((n - 2*k)*x) for k in range(n/2)]) + if n.is_even: + rv += 2**(-n)*binomial(n, n/2) + return rv + + return bottom_up(rv, f) + + +def L(rv): + """Return count of trigonometric functions in expression. + + Examples + ======== + + >>> from sympy.simplify.fu import L + >>> from sympy.abc import x + >>> from sympy import cos, sin + >>> L(cos(x)+sin(x)) + 2 + """ + return S(rv.count(TrigonometricFunction)) + + +# ============== end of basic Fu-like tools ===================== + +if SYMPY_DEBUG: + (TR0, TR1, TR2, TR3, TR4, TR5, TR6, TR7, TR8, TR9, TR10, TR11, TR12, TR13, + TR2i, TRmorrie, TR14, TR15, TR16, TR12i, TR111, TR22 + )= list(map(debug, + (TR0, TR1, TR2, TR3, TR4, TR5, TR6, TR7, TR8, TR9, TR10, TR11, TR12, TR13, + TR2i, TRmorrie, TR14, TR15, TR16, TR12i, TR111, TR22))) + + +# tuples are chains -- (f, g) -> lambda x: g(f(x)) +# lists are choices -- [f, g] -> lambda x: min(f(x), g(x), key=objective) + +CTR1 = [(TR5, TR0), (TR6, TR0), identity] + +CTR2 = (TR11, [(TR5, TR0), (TR6, TR0), TR0]) + +CTR3 = [(TRmorrie, TR8, TR0), (TRmorrie, TR8, TR10i, TR0), identity] + +CTR4 = [(TR4, TR10i), identity] + +RL1 = (TR4, TR3, TR4, TR12, TR4, TR13, TR4, TR0) + + +# XXX it's a little unclear how this one is to be implemented +# see Fu paper of reference, page 7. What is the Union symbol referring to? +# The diagram shows all these as one chain of transformations, but the +# text refers to them being applied independently. Also, a break +# if L starts to increase has not been implemented. +RL2 = [ + (TR4, TR3, TR10, TR4, TR3, TR11), + (TR5, TR7, TR11, TR4), + (CTR3, CTR1, TR9, CTR2, TR4, TR9, TR9, CTR4), + identity, + ] + + +def fu(rv, measure=lambda x: (L(x), x.count_ops())): + """Attempt to simplify expression by using transformation rules given + in the algorithm by Fu et al. + + :func:`fu` will try to minimize the objective function ``measure``. + By default this first minimizes the number of trig terms and then minimizes + the number of total operations. + + Examples + ======== + + >>> from sympy.simplify.fu import fu + >>> from sympy import cos, sin, tan, pi, S, sqrt + >>> from sympy.abc import x, y, a, b + + >>> fu(sin(50)**2 + cos(50)**2 + sin(pi/6)) + 3/2 + >>> fu(sqrt(6)*cos(x) + sqrt(2)*sin(x)) + 2*sqrt(2)*sin(x + pi/3) + + CTR1 example + + >>> eq = sin(x)**4 - cos(y)**2 + sin(y)**2 + 2*cos(x)**2 + >>> fu(eq) + cos(x)**4 - 2*cos(y)**2 + 2 + + CTR2 example + + >>> fu(S.Half - cos(2*x)/2) + sin(x)**2 + + CTR3 example + + >>> fu(sin(a)*(cos(b) - sin(b)) + cos(a)*(sin(b) + cos(b))) + sqrt(2)*sin(a + b + pi/4) + + CTR4 example + + >>> fu(sqrt(3)*cos(x)/2 + sin(x)/2) + sin(x + pi/3) + + Example 1 + + >>> fu(1-sin(2*x)**2/4-sin(y)**2-cos(x)**4) + -cos(x)**2 + cos(y)**2 + + Example 2 + + >>> fu(cos(4*pi/9)) + sin(pi/18) + >>> fu(cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9)) + 1/16 + + Example 3 + + >>> fu(tan(7*pi/18)+tan(5*pi/18)-sqrt(3)*tan(5*pi/18)*tan(7*pi/18)) + -sqrt(3) + + Objective function example + + >>> fu(sin(x)/cos(x)) # default objective function + tan(x) + >>> fu(sin(x)/cos(x), measure=lambda x: -x.count_ops()) # maximize op count + sin(x)/cos(x) + + References + ========== + + .. [1] https://www.sciencedirect.com/science/article/pii/S0895717706001609 + """ + fRL1 = greedy(RL1, measure) + fRL2 = greedy(RL2, measure) + + was = rv + rv = sympify(rv) + if not isinstance(rv, Expr): + return rv.func(*[fu(a, measure=measure) for a in rv.args]) + rv = TR1(rv) + if rv.has(tan, cot): + rv1 = fRL1(rv) + if (measure(rv1) < measure(rv)): + rv = rv1 + if rv.has(tan, cot): + rv = TR2(rv) + if rv.has(sin, cos): + rv1 = fRL2(rv) + rv2 = TR8(TRmorrie(rv1)) + rv = min([was, rv, rv1, rv2], key=measure) + return min(TR2i(rv), rv, key=measure) + + +def process_common_addends(rv, do, key2=None, key1=True): + """Apply ``do`` to addends of ``rv`` that (if ``key1=True``) share at least + a common absolute value of their coefficient and the value of ``key2`` when + applied to the argument. If ``key1`` is False ``key2`` must be supplied and + will be the only key applied. + """ + + # collect by absolute value of coefficient and key2 + absc = defaultdict(list) + if key1: + for a in rv.args: + c, a = a.as_coeff_Mul() + if c < 0: + c = -c + a = -a # put the sign on `a` + absc[(c, key2(a) if key2 else 1)].append(a) + elif key2: + for a in rv.args: + absc[(S.One, key2(a))].append(a) + else: + raise ValueError('must have at least one key') + + args = [] + hit = False + for k in absc: + v = absc[k] + c, _ = k + if len(v) > 1: + e = Add(*v, evaluate=False) + new = do(e) + if new != e: + e = new + hit = True + args.append(c*e) + else: + args.append(c*v[0]) + if hit: + rv = Add(*args) + + return rv + + +fufuncs = ''' + TR0 TR1 TR2 TR3 TR4 TR5 TR6 TR7 TR8 TR9 TR10 TR10i TR11 + TR12 TR13 L TR2i TRmorrie TR12i + TR14 TR15 TR16 TR111 TR22'''.split() +FU = dict(list(zip(fufuncs, list(map(locals().get, fufuncs))))) + + +@cacheit +def _ROOT2(): + return sqrt(2) + + +@cacheit +def _ROOT3(): + return sqrt(3) + + +@cacheit +def _invROOT3(): + return 1/sqrt(3) + + +def trig_split(a, b, two=False): + """Return the gcd, s1, s2, a1, a2, bool where + + If two is False (default) then:: + a + b = gcd*(s1*f(a1) + s2*f(a2)) where f = cos if bool else sin + else: + if bool, a + b was +/- cos(a1)*cos(a2) +/- sin(a1)*sin(a2) and equals + n1*gcd*cos(a - b) if n1 == n2 else + n1*gcd*cos(a + b) + else a + b was +/- cos(a1)*sin(a2) +/- sin(a1)*cos(a2) and equals + n1*gcd*sin(a + b) if n1 = n2 else + n1*gcd*sin(b - a) + + Examples + ======== + + >>> from sympy.simplify.fu import trig_split + >>> from sympy.abc import x, y, z + >>> from sympy import cos, sin, sqrt + + >>> trig_split(cos(x), cos(y)) + (1, 1, 1, x, y, True) + >>> trig_split(2*cos(x), -2*cos(y)) + (2, 1, -1, x, y, True) + >>> trig_split(cos(x)*sin(y), cos(y)*sin(y)) + (sin(y), 1, 1, x, y, True) + + >>> trig_split(cos(x), -sqrt(3)*sin(x), two=True) + (2, 1, -1, x, pi/6, False) + >>> trig_split(cos(x), sin(x), two=True) + (sqrt(2), 1, 1, x, pi/4, False) + >>> trig_split(cos(x), -sin(x), two=True) + (sqrt(2), 1, -1, x, pi/4, False) + >>> trig_split(sqrt(2)*cos(x), -sqrt(6)*sin(x), two=True) + (2*sqrt(2), 1, -1, x, pi/6, False) + >>> trig_split(-sqrt(6)*cos(x), -sqrt(2)*sin(x), two=True) + (-2*sqrt(2), 1, 1, x, pi/3, False) + >>> trig_split(cos(x)/sqrt(6), sin(x)/sqrt(2), two=True) + (sqrt(6)/3, 1, 1, x, pi/6, False) + >>> trig_split(-sqrt(6)*cos(x)*sin(y), -sqrt(2)*sin(x)*sin(y), two=True) + (-2*sqrt(2)*sin(y), 1, 1, x, pi/3, False) + + >>> trig_split(cos(x), sin(x)) + >>> trig_split(cos(x), sin(z)) + >>> trig_split(2*cos(x), -sin(x)) + >>> trig_split(cos(x), -sqrt(3)*sin(x)) + >>> trig_split(cos(x)*cos(y), sin(x)*sin(z)) + >>> trig_split(cos(x)*cos(y), sin(x)*sin(y)) + >>> trig_split(-sqrt(6)*cos(x), sqrt(2)*sin(x)*sin(y), two=True) + """ + a, b = [Factors(i) for i in (a, b)] + ua, ub = a.normal(b) + gcd = a.gcd(b).as_expr() + n1 = n2 = 1 + if S.NegativeOne in ua.factors: + ua = ua.quo(S.NegativeOne) + n1 = -n1 + elif S.NegativeOne in ub.factors: + ub = ub.quo(S.NegativeOne) + n2 = -n2 + a, b = [i.as_expr() for i in (ua, ub)] + + def pow_cos_sin(a, two): + """Return ``a`` as a tuple (r, c, s) such that + ``a = (r or 1)*(c or 1)*(s or 1)``. + + Three arguments are returned (radical, c-factor, s-factor) as + long as the conditions set by ``two`` are met; otherwise None is + returned. If ``two`` is True there will be one or two non-None + values in the tuple: c and s or c and r or s and r or s or c with c + being a cosine function (if possible) else a sine, and s being a sine + function (if possible) else oosine. If ``two`` is False then there + will only be a c or s term in the tuple. + + ``two`` also require that either two cos and/or sin be present (with + the condition that if the functions are the same the arguments are + different or vice versa) or that a single cosine or a single sine + be present with an optional radical. + + If the above conditions dictated by ``two`` are not met then None + is returned. + """ + c = s = None + co = S.One + if a.is_Mul: + co, a = a.as_coeff_Mul() + if len(a.args) > 2 or not two: + return None + if a.is_Mul: + args = list(a.args) + else: + args = [a] + a = args.pop(0) + if isinstance(a, cos): + c = a + elif isinstance(a, sin): + s = a + elif a.is_Pow and a.exp is S.Half: # autoeval doesn't allow -1/2 + co *= a + else: + return None + if args: + b = args[0] + if isinstance(b, cos): + if c: + s = b + else: + c = b + elif isinstance(b, sin): + if s: + c = b + else: + s = b + elif b.is_Pow and b.exp is S.Half: + co *= b + else: + return None + return co if co is not S.One else None, c, s + elif isinstance(a, cos): + c = a + elif isinstance(a, sin): + s = a + if c is None and s is None: + return + co = co if co is not S.One else None + return co, c, s + + # get the parts + m = pow_cos_sin(a, two) + if m is None: + return + coa, ca, sa = m + m = pow_cos_sin(b, two) + if m is None: + return + cob, cb, sb = m + + # check them + if (not ca) and cb or ca and isinstance(ca, sin): + coa, ca, sa, cob, cb, sb = cob, cb, sb, coa, ca, sa + n1, n2 = n2, n1 + if not two: # need cos(x) and cos(y) or sin(x) and sin(y) + c = ca or sa + s = cb or sb + if not isinstance(c, s.func): + return None + return gcd, n1, n2, c.args[0], s.args[0], isinstance(c, cos) + else: + if not coa and not cob: + if (ca and cb and sa and sb): + if isinstance(ca, sa.func) is not isinstance(cb, sb.func): + return + args = {j.args for j in (ca, sa)} + if not all(i.args in args for i in (cb, sb)): + return + return gcd, n1, n2, ca.args[0], sa.args[0], isinstance(ca, sa.func) + if ca and sa or cb and sb or \ + two and (ca is None and sa is None or cb is None and sb is None): + return + c = ca or sa + s = cb or sb + if c.args != s.args: + return + if not coa: + coa = S.One + if not cob: + cob = S.One + if coa is cob: + gcd *= _ROOT2() + return gcd, n1, n2, c.args[0], pi/4, False + elif coa/cob == _ROOT3(): + gcd *= 2*cob + return gcd, n1, n2, c.args[0], pi/3, False + elif coa/cob == _invROOT3(): + gcd *= 2*coa + return gcd, n1, n2, c.args[0], pi/6, False + + +def as_f_sign_1(e): + """If ``e`` is a sum that can be written as ``g*(a + s)`` where + ``s`` is ``+/-1``, return ``g``, ``a``, and ``s`` where ``a`` does + not have a leading negative coefficient. + + Examples + ======== + + >>> from sympy.simplify.fu import as_f_sign_1 + >>> from sympy.abc import x + >>> as_f_sign_1(x + 1) + (1, x, 1) + >>> as_f_sign_1(x - 1) + (1, x, -1) + >>> as_f_sign_1(-x + 1) + (-1, x, -1) + >>> as_f_sign_1(-x - 1) + (-1, x, 1) + >>> as_f_sign_1(2*x + 2) + (2, x, 1) + """ + if not e.is_Add or len(e.args) != 2: + return + # exact match + a, b = e.args + if a in (S.NegativeOne, S.One): + g = S.One + if b.is_Mul and b.args[0].is_Number and b.args[0] < 0: + a, b = -a, -b + g = -g + return g, b, a + # gcd match + a, b = [Factors(i) for i in e.args] + ua, ub = a.normal(b) + gcd = a.gcd(b).as_expr() + if S.NegativeOne in ua.factors: + ua = ua.quo(S.NegativeOne) + n1 = -1 + n2 = 1 + elif S.NegativeOne in ub.factors: + ub = ub.quo(S.NegativeOne) + n1 = 1 + n2 = -1 + else: + n1 = n2 = 1 + a, b = [i.as_expr() for i in (ua, ub)] + if a is S.One: + a, b = b, a + n1, n2 = n2, n1 + if n1 == -1: + gcd = -gcd + n2 = -n2 + + if b is S.One: + return gcd, a, n2 + + +def _osborne(e, d): + """Replace all hyperbolic functions with trig functions using + the Osborne rule. + + Notes + ===== + + ``d`` is a dummy variable to prevent automatic evaluation + of trigonometric/hyperbolic functions. + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function + """ + + def f(rv): + if not isinstance(rv, HyperbolicFunction): + return rv + a = rv.args[0] + a = a*d if not a.is_Add else Add._from_args([i*d for i in a.args]) + if isinstance(rv, sinh): + return I*sin(a) + elif isinstance(rv, cosh): + return cos(a) + elif isinstance(rv, tanh): + return I*tan(a) + elif isinstance(rv, coth): + return cot(a)/I + elif isinstance(rv, sech): + return sec(a) + elif isinstance(rv, csch): + return csc(a)/I + else: + raise NotImplementedError('unhandled %s' % rv.func) + + return bottom_up(e, f) + + +def _osbornei(e, d): + """Replace all trig functions with hyperbolic functions using + the Osborne rule. + + Notes + ===== + + ``d`` is a dummy variable to prevent automatic evaluation + of trigonometric/hyperbolic functions. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function + """ + + def f(rv): + if not isinstance(rv, TrigonometricFunction): + return rv + const, x = rv.args[0].as_independent(d, as_Add=True) + a = x.xreplace({d: S.One}) + const*I + if isinstance(rv, sin): + return sinh(a)/I + elif isinstance(rv, cos): + return cosh(a) + elif isinstance(rv, tan): + return tanh(a)/I + elif isinstance(rv, cot): + return coth(a)*I + elif isinstance(rv, sec): + return sech(a) + elif isinstance(rv, csc): + return csch(a)*I + else: + raise NotImplementedError('unhandled %s' % rv.func) + + return bottom_up(e, f) + + +def hyper_as_trig(rv): + """Return an expression containing hyperbolic functions in terms + of trigonometric functions. Any trigonometric functions initially + present are replaced with Dummy symbols and the function to undo + the masking and the conversion back to hyperbolics is also returned. It + should always be true that:: + + t, f = hyper_as_trig(expr) + expr == f(t) + + Examples + ======== + + >>> from sympy.simplify.fu import hyper_as_trig, fu + >>> from sympy.abc import x + >>> from sympy import cosh, sinh + >>> eq = sinh(x)**2 + cosh(x)**2 + >>> t, f = hyper_as_trig(eq) + >>> f(fu(t)) + cosh(2*x) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function + """ + from sympy.simplify.simplify import signsimp + from sympy.simplify.radsimp import collect + + # mask off trig functions + trigs = rv.atoms(TrigonometricFunction) + reps = [(t, Dummy()) for t in trigs] + masked = rv.xreplace(dict(reps)) + + # get inversion substitutions in place + reps = [(v, k) for k, v in reps] + + d = Dummy() + + return _osborne(masked, d), lambda x: collect(signsimp( + _osbornei(x, d).xreplace(dict(reps))), S.ImaginaryUnit) + + +def sincos_to_sum(expr): + """Convert products and powers of sin and cos to sums. + + Explanation + =========== + + Applied power reduction TRpower first, then expands products, and + converts products to sums with TR8. + + Examples + ======== + + >>> from sympy.simplify.fu import sincos_to_sum + >>> from sympy.abc import x + >>> from sympy import cos, sin + >>> sincos_to_sum(16*sin(x)**3*cos(2*x)**2) + 7*sin(x) - 5*sin(3*x) + 3*sin(5*x) - sin(7*x) + """ + + if not expr.has(cos, sin): + return expr + else: + return TR8(expand_mul(TRpower(expr))) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/gammasimp.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/gammasimp.py new file mode 100644 index 0000000000000000000000000000000000000000..aec20c56eb60efb8e1aadfb5bff3d1ba1ab51869 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/gammasimp.py @@ -0,0 +1,493 @@ +from sympy.core import Function, S, Mul, Pow, Add +from sympy.core.sorting import ordered, default_sort_key +from sympy.core.function import expand_func +from sympy.core.symbol import Dummy +from sympy.functions import gamma, sqrt, sin +from sympy.polys import factor, cancel +from sympy.utilities.iterables import sift, uniq + + +def gammasimp(expr): + r""" + Simplify expressions with gamma functions. + + Explanation + =========== + + This function takes as input an expression containing gamma + functions or functions that can be rewritten in terms of gamma + functions and tries to minimize the number of those functions and + reduce the size of their arguments. + + The algorithm works by rewriting all gamma functions as expressions + involving rising factorials (Pochhammer symbols) and applies + recurrence relations and other transformations applicable to rising + factorials, to reduce their arguments, possibly letting the resulting + rising factorial to cancel. Rising factorials with the second argument + being an integer are expanded into polynomial forms and finally all + other rising factorial are rewritten in terms of gamma functions. + + Then the following two steps are performed. + + 1. Reduce the number of gammas by applying the reflection theorem + gamma(x)*gamma(1-x) == pi/sin(pi*x). + 2. Reduce the number of gammas by applying the multiplication theorem + gamma(x)*gamma(x+1/n)*...*gamma(x+(n-1)/n) == C*gamma(n*x). + + It then reduces the number of prefactors by absorbing them into gammas + where possible and expands gammas with rational argument. + + All transformation rules can be found (or were derived from) here: + + .. [1] https://functions.wolfram.com/GammaBetaErf/Pochhammer/17/01/02/ + .. [2] https://functions.wolfram.com/GammaBetaErf/Pochhammer/27/01/0005/ + + Examples + ======== + + >>> from sympy.simplify import gammasimp + >>> from sympy import gamma, Symbol + >>> from sympy.abc import x + >>> n = Symbol('n', integer = True) + + >>> gammasimp(gamma(x)/gamma(x - 3)) + (x - 3)*(x - 2)*(x - 1) + >>> gammasimp(gamma(n + 3)) + gamma(n + 3) + + """ + + expr = expr.rewrite(gamma) + + # compute_ST will be looking for Functions and we don't want + # it looking for non-gamma functions: issue 22606 + # so we mask free, non-gamma functions + f = expr.atoms(Function) + # take out gammas + gammas = {i for i in f if isinstance(i, gamma)} + if not gammas: + return expr # avoid side effects like factoring + f -= gammas + # keep only those without bound symbols + f = f & expr.as_dummy().atoms(Function) + if f: + dum, fun, simp = zip(*[ + (Dummy(), fi, fi.func(*[ + _gammasimp(a, as_comb=False) for a in fi.args])) + for fi in ordered(f)]) + d = expr.xreplace(dict(zip(fun, dum))) + return _gammasimp(d, as_comb=False).xreplace(dict(zip(dum, simp))) + + return _gammasimp(expr, as_comb=False) + + +def _gammasimp(expr, as_comb): + """ + Helper function for gammasimp and combsimp. + + Explanation + =========== + + Simplifies expressions written in terms of gamma function. If + as_comb is True, it tries to preserve integer arguments. See + docstring of gammasimp for more information. This was part of + combsimp() in combsimp.py. + """ + expr = expr.replace(gamma, + lambda n: _rf(1, (n - 1).expand())) + + if as_comb: + expr = expr.replace(_rf, + lambda a, b: gamma(b + 1)) + else: + expr = expr.replace(_rf, + lambda a, b: gamma(a + b)/gamma(a)) + + def rule_gamma(expr, level=0): + """ Simplify products of gamma functions further. """ + + if expr.is_Atom: + return expr + + def gamma_rat(x): + # helper to simplify ratios of gammas + was = x.count(gamma) + xx = x.replace(gamma, lambda n: _rf(1, (n - 1).expand() + ).replace(_rf, lambda a, b: gamma(a + b)/gamma(a))) + if xx.count(gamma) < was: + x = xx + return x + + def gamma_factor(x): + # return True if there is a gamma factor in shallow args + if isinstance(x, gamma): + return True + if x.is_Add or x.is_Mul: + return any(gamma_factor(xi) for xi in x.args) + if x.is_Pow and (x.exp.is_integer or x.base.is_positive): + return gamma_factor(x.base) + return False + + # recursion step + if level == 0: + expr = expr.func(*[rule_gamma(x, level + 1) for x in expr.args]) + level += 1 + + if not expr.is_Mul: + return expr + + # non-commutative step + if level == 1: + args, nc = expr.args_cnc() + if not args: + return expr + if nc: + return rule_gamma(Mul._from_args(args), level + 1)*Mul._from_args(nc) + level += 1 + + # pure gamma handling, not factor absorption + if level == 2: + T, F = sift(expr.args, gamma_factor, binary=True) + gamma_ind = Mul(*F) + d = Mul(*T) + + nd, dd = d.as_numer_denom() + for ipass in range(2): + args = list(ordered(Mul.make_args(nd))) + for i, ni in enumerate(args): + if ni.is_Add: + ni, dd = Add(*[ + rule_gamma(gamma_rat(a/dd), level + 1) for a in ni.args] + ).as_numer_denom() + args[i] = ni + if not dd.has(gamma): + break + nd = Mul(*args) + if ipass == 0 and not gamma_factor(nd): + break + nd, dd = dd, nd # now process in reversed order + expr = gamma_ind*nd/dd + if not (expr.is_Mul and (gamma_factor(dd) or gamma_factor(nd))): + return expr + level += 1 + + # iteration until constant + if level == 3: + while True: + was = expr + expr = rule_gamma(expr, 4) + if expr == was: + return expr + + numer_gammas = [] + denom_gammas = [] + numer_others = [] + denom_others = [] + def explicate(p): + if p is S.One: + return None, [] + b, e = p.as_base_exp() + if e.is_Integer: + if isinstance(b, gamma): + return True, [b.args[0]]*e + else: + return False, [b]*e + else: + return False, [p] + + newargs = list(ordered(expr.args)) + while newargs: + n, d = newargs.pop().as_numer_denom() + isg, l = explicate(n) + if isg: + numer_gammas.extend(l) + elif isg is False: + numer_others.extend(l) + isg, l = explicate(d) + if isg: + denom_gammas.extend(l) + elif isg is False: + denom_others.extend(l) + + # =========== level 2 work: pure gamma manipulation ========= + + if not as_comb: + # Try to reduce the number of gamma factors by applying the + # reflection formula gamma(x)*gamma(1-x) = pi/sin(pi*x) + for gammas, numer, denom in [( + numer_gammas, numer_others, denom_others), + (denom_gammas, denom_others, numer_others)]: + new = [] + while gammas: + g1 = gammas.pop() + if g1.is_integer: + new.append(g1) + continue + for i, g2 in enumerate(gammas): + n = g1 + g2 - 1 + if not n.is_Integer: + continue + numer.append(S.Pi) + denom.append(sin(S.Pi*g1)) + gammas.pop(i) + if n > 0: + numer.extend(1 - g1 + k for k in range(n)) + elif n < 0: + denom.extend(-g1 - k for k in range(-n)) + break + else: + new.append(g1) + # /!\ updating IN PLACE + gammas[:] = new + + # Try to reduce the number of gammas by using the duplication + # theorem to cancel an upper and lower: gamma(2*s)/gamma(s) = + # 2**(2*s + 1)/(4*sqrt(pi))*gamma(s + 1/2). Although this could + # be done with higher argument ratios like gamma(3*x)/gamma(x), + # this would not reduce the number of gammas as in this case. + for ng, dg, no, do in [(numer_gammas, denom_gammas, numer_others, + denom_others), + (denom_gammas, numer_gammas, denom_others, + numer_others)]: + + while True: + for x in ng: + for y in dg: + n = x - 2*y + if n.is_Integer: + break + else: + continue + break + else: + break + ng.remove(x) + dg.remove(y) + if n > 0: + no.extend(2*y + k for k in range(n)) + elif n < 0: + do.extend(2*y - 1 - k for k in range(-n)) + ng.append(y + S.Half) + no.append(2**(2*y - 1)) + do.append(sqrt(S.Pi)) + + # Try to reduce the number of gamma factors by applying the + # multiplication theorem (used when n gammas with args differing + # by 1/n mod 1 are encountered). + # + # run of 2 with args differing by 1/2 + # + # >>> gammasimp(gamma(x)*gamma(x+S.Half)) + # 2*sqrt(2)*2**(-2*x - 1/2)*sqrt(pi)*gamma(2*x) + # + # run of 3 args differing by 1/3 (mod 1) + # + # >>> gammasimp(gamma(x)*gamma(x+S(1)/3)*gamma(x+S(2)/3)) + # 6*3**(-3*x - 1/2)*pi*gamma(3*x) + # >>> gammasimp(gamma(x)*gamma(x+S(1)/3)*gamma(x+S(5)/3)) + # 2*3**(-3*x - 1/2)*pi*(3*x + 2)*gamma(3*x) + # + def _run(coeffs): + # find runs in coeffs such that the difference in terms (mod 1) + # of t1, t2, ..., tn is 1/n + u = list(uniq(coeffs)) + for i in range(len(u)): + dj = ([((u[j] - u[i]) % 1, j) for j in range(i + 1, len(u))]) + for one, j in dj: + if one.p == 1 and one.q != 1: + n = one.q + got = [i] + get = list(range(1, n)) + for d, j in dj: + m = n*d + if m.is_Integer and m in get: + get.remove(m) + got.append(j) + if not get: + break + else: + continue + for i, j in enumerate(got): + c = u[j] + coeffs.remove(c) + got[i] = c + return one.q, got[0], got[1:] + + def _mult_thm(gammas, numer, denom): + # pull off and analyze the leading coefficient from each gamma arg + # looking for runs in those Rationals + + # expr -> coeff + resid -> rats[resid] = coeff + rats = {} + for g in gammas: + c, resid = g.as_coeff_Add() + rats.setdefault(resid, []).append(c) + + # look for runs in Rationals for each resid + keys = sorted(rats, key=default_sort_key) + for resid in keys: + coeffs = sorted(rats[resid]) + new = [] + while True: + run = _run(coeffs) + if run is None: + break + + # process the sequence that was found: + # 1) convert all the gamma functions to have the right + # argument (could be off by an integer) + # 2) append the factors corresponding to the theorem + # 3) append the new gamma function + + n, ui, other = run + + # (1) + for u in other: + con = resid + u - 1 + for k in range(int(u - ui)): + numer.append(con - k) + + con = n*(resid + ui) # for (2) and (3) + + # (2) + numer.append((2*S.Pi)**(S(n - 1)/2)* + n**(S.Half - con)) + # (3) + new.append(con) + + # restore resid to coeffs + rats[resid] = [resid + c for c in coeffs] + new + + # rebuild the gamma arguments + g = [] + for resid in keys: + g += rats[resid] + # /!\ updating IN PLACE + gammas[:] = g + + for l, numer, denom in [(numer_gammas, numer_others, denom_others), + (denom_gammas, denom_others, numer_others)]: + _mult_thm(l, numer, denom) + + # =========== level >= 2 work: factor absorption ========= + + if level >= 2: + # Try to absorb factors into the gammas: x*gamma(x) -> gamma(x + 1) + # and gamma(x)/(x - 1) -> gamma(x - 1) + # This code (in particular repeated calls to find_fuzzy) can be very + # slow. + def find_fuzzy(l, x): + if not l: + return + S1, T1 = compute_ST(x) + for y in l: + S2, T2 = inv[y] + if T1 != T2 or (not S1.intersection(S2) and + (S1 != set() or S2 != set())): + continue + # XXX we want some simplification (e.g. cancel or + # simplify) but no matter what it's slow. + a = len(cancel(x/y).free_symbols) + b = len(x.free_symbols) + c = len(y.free_symbols) + # TODO is there a better heuristic? + if a == 0 and (b > 0 or c > 0): + return y + + # We thus try to avoid expensive calls by building the following + # "invariants": For every factor or gamma function argument + # - the set of free symbols S + # - the set of functional components T + # We will only try to absorb if T1==T2 and (S1 intersect S2 != emptyset + # or S1 == S2 == emptyset) + inv = {} + + def compute_ST(expr): + if expr in inv: + return inv[expr] + return (expr.free_symbols, expr.atoms(Function).union( + {e.exp for e in expr.atoms(Pow)})) + + def update_ST(expr): + inv[expr] = compute_ST(expr) + for expr in numer_gammas + denom_gammas + numer_others + denom_others: + update_ST(expr) + + for gammas, numer, denom in [( + numer_gammas, numer_others, denom_others), + (denom_gammas, denom_others, numer_others)]: + new = [] + while gammas: + g = gammas.pop() + cont = True + while cont: + cont = False + y = find_fuzzy(numer, g) + if y is not None: + numer.remove(y) + if y != g: + numer.append(y/g) + update_ST(y/g) + g += 1 + cont = True + y = find_fuzzy(denom, g - 1) + if y is not None: + denom.remove(y) + if y != g - 1: + numer.append((g - 1)/y) + update_ST((g - 1)/y) + g -= 1 + cont = True + new.append(g) + # /!\ updating IN PLACE + gammas[:] = new + + # =========== rebuild expr ================================== + + return Mul(*[gamma(g) for g in numer_gammas]) \ + / Mul(*[gamma(g) for g in denom_gammas]) \ + * Mul(*numer_others) / Mul(*denom_others) + + was = factor(expr) + # (for some reason we cannot use Basic.replace in this case) + expr = rule_gamma(was) + if expr != was: + expr = factor(expr) + + expr = expr.replace(gamma, + lambda n: expand_func(gamma(n)) if n.is_Rational else gamma(n)) + + return expr + + +class _rf(Function): + @classmethod + def eval(cls, a, b): + if b.is_Integer: + if not b: + return S.One + + n = int(b) + + if n > 0: + return Mul(*[a + i for i in range(n)]) + elif n < 0: + return 1/Mul(*[a - i for i in range(1, -n + 1)]) + else: + if b.is_Add: + c, _b = b.as_coeff_Add() + + if c.is_Integer: + if c > 0: + return _rf(a, _b)*_rf(a + _b, c) + elif c < 0: + return _rf(a, _b)/_rf(a + _b + c, -c) + + if a.is_Add: + c, _a = a.as_coeff_Add() + + if c.is_Integer: + if c > 0: + return _rf(_a, b)*_rf(_a + b, c)/_rf(_a, c) + elif c < 0: + return _rf(_a, b)*_rf(_a + c, -c)/_rf(_a + b + c, -c) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/hyperexpand.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/hyperexpand.py new file mode 100644 index 0000000000000000000000000000000000000000..c070aa2e44b92794107b3e33df897813a54307b9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/hyperexpand.py @@ -0,0 +1,2494 @@ +""" +Expand Hypergeometric (and Meijer G) functions into named +special functions. + +The algorithm for doing this uses a collection of lookup tables of +hypergeometric functions, and various of their properties, to expand +many hypergeometric functions in terms of special functions. + +It is based on the following paper: + Kelly B. Roach. Meijer G Function Representations. + In: Proceedings of the 1997 International Symposium on Symbolic and + Algebraic Computation, pages 205-211, New York, 1997. ACM. + +It is described in great(er) detail in the Sphinx documentation. +""" +# SUMMARY OF EXTENSIONS FOR MEIJER G FUNCTIONS +# +# o z**rho G(ap, bq; z) = G(ap + rho, bq + rho; z) +# +# o denote z*d/dz by D +# +# o It is helpful to keep in mind that ap and bq play essentially symmetric +# roles: G(1/z) has slightly altered parameters, with ap and bq interchanged. +# +# o There are four shift operators: +# A_J = b_J - D, J = 1, ..., n +# B_J = 1 - a_j + D, J = 1, ..., m +# C_J = -b_J + D, J = m+1, ..., q +# D_J = a_J - 1 - D, J = n+1, ..., p +# +# A_J, C_J increment b_J +# B_J, D_J decrement a_J +# +# o The corresponding four inverse-shift operators are defined if there +# is no cancellation. Thus e.g. an index a_J (upper or lower) can be +# incremented if a_J != b_i for i = 1, ..., q. +# +# o Order reduction: if b_j - a_i is a non-negative integer, where +# j <= m and i > n, the corresponding quotient of gamma functions reduces +# to a polynomial. Hence the G function can be expressed using a G-function +# of lower order. +# Similarly if j > m and i <= n. +# +# Secondly, there are paired index theorems [Adamchik, The evaluation of +# integrals of Bessel functions via G-function identities]. Suppose there +# are three parameters a, b, c, where a is an a_i, i <= n, b is a b_j, +# j <= m and c is a denominator parameter (i.e. a_i, i > n or b_j, j > m). +# Suppose further all three differ by integers. +# Then the order can be reduced. +# TODO work this out in detail. +# +# o An index quadruple is called suitable if its order cannot be reduced. +# If there exists a sequence of shift operators transforming one index +# quadruple into another, we say one is reachable from the other. +# +# o Deciding if one index quadruple is reachable from another is tricky. For +# this reason, we use hand-built routines to match and instantiate formulas. +# +from collections import defaultdict +from itertools import product +from functools import reduce +from math import prod + +from sympy import SYMPY_DEBUG +from sympy.core import (S, Dummy, symbols, sympify, Tuple, expand, I, pi, Mul, + EulerGamma, oo, zoo, expand_func, Add, nan, Expr, Rational) +from sympy.core.mod import Mod +from sympy.core.sorting import default_sort_key +from sympy.functions import (exp, sqrt, root, log, lowergamma, cos, + besseli, gamma, uppergamma, expint, erf, sin, besselj, Ei, Ci, Si, Shi, + sinh, cosh, Chi, fresnels, fresnelc, polar_lift, exp_polar, floor, ceiling, + rf, factorial, lerchphi, Piecewise, re, elliptic_k, elliptic_e) +from sympy.functions.elementary.complexes import polarify, unpolarify +from sympy.functions.special.hyper import (hyper, HyperRep_atanh, + HyperRep_power1, HyperRep_power2, HyperRep_log1, HyperRep_asin1, + HyperRep_asin2, HyperRep_sqrts1, HyperRep_sqrts2, HyperRep_log2, + HyperRep_cosasin, HyperRep_sinasin, meijerg) +from sympy.matrices import Matrix, eye, zeros +from sympy.polys import apart, poly, Poly +from sympy.series import residue +from sympy.simplify.powsimp import powdenest +from sympy.utilities.iterables import sift + +# function to define "buckets" +def _mod1(x): + # TODO see if this can work as Mod(x, 1); this will require + # different handling of the "buckets" since these need to + # be sorted and that fails when there is a mixture of + # integers and expressions with parameters. With the current + # Mod behavior, Mod(k, 1) == Mod(1, 1) == 0 if k is an integer. + # Although the sorting can be done with Basic.compare, this may + # still require different handling of the sorted buckets. + if x.is_Number: + return Mod(x, 1) + c, x = x.as_coeff_Add() + return Mod(c, 1) + x + + +# leave add formulae at the top for easy reference +def add_formulae(formulae): + """ Create our knowledge base. """ + a, b, c, z = symbols('a b c, z', cls=Dummy) + + def add(ap, bq, res): + func = Hyper_Function(ap, bq) + formulae.append(Formula(func, z, res, (a, b, c))) + + def addb(ap, bq, B, C, M): + func = Hyper_Function(ap, bq) + formulae.append(Formula(func, z, None, (a, b, c), B, C, M)) + + # Luke, Y. L. (1969), The Special Functions and Their Approximations, + # Volume 1, section 6.2 + + # 0F0 + add((), (), exp(z)) + + # 1F0 + add((a, ), (), HyperRep_power1(-a, z)) + + # 2F1 + addb((a, a - S.Half), (2*a, ), + Matrix([HyperRep_power2(a, z), + HyperRep_power2(a + S.Half, z)/2]), + Matrix([[1, 0]]), + Matrix([[(a - S.Half)*z/(1 - z), (S.Half - a)*z/(1 - z)], + [a/(1 - z), a*(z - 2)/(1 - z)]])) + addb((1, 1), (2, ), + Matrix([HyperRep_log1(z), 1]), Matrix([[-1/z, 0]]), + Matrix([[0, z/(z - 1)], [0, 0]])) + addb((S.Half, 1), (S('3/2'), ), + Matrix([HyperRep_atanh(z), 1]), + Matrix([[1, 0]]), + Matrix([[Rational(-1, 2), 1/(1 - z)/2], [0, 0]])) + addb((S.Half, S.Half), (S('3/2'), ), + Matrix([HyperRep_asin1(z), HyperRep_power1(Rational(-1, 2), z)]), + Matrix([[1, 0]]), + Matrix([[Rational(-1, 2), S.Half], [0, z/(1 - z)/2]])) + addb((a, S.Half + a), (S.Half, ), + Matrix([HyperRep_sqrts1(-a, z), -HyperRep_sqrts2(-a - S.Half, z)]), + Matrix([[1, 0]]), + Matrix([[0, -a], + [z*(-2*a - 1)/2/(1 - z), S.Half - z*(-2*a - 1)/(1 - z)]])) + + # A. P. Prudnikov, Yu. A. Brychkov and O. I. Marichev (1990). + # Integrals and Series: More Special Functions, Vol. 3,. + # Gordon and Breach Science Publisher + addb([a, -a], [S.Half], + Matrix([HyperRep_cosasin(a, z), HyperRep_sinasin(a, z)]), + Matrix([[1, 0]]), + Matrix([[0, -a], [a*z/(1 - z), 1/(1 - z)/2]])) + addb([1, 1], [3*S.Half], + Matrix([HyperRep_asin2(z), 1]), Matrix([[1, 0]]), + Matrix([[(z - S.Half)/(1 - z), 1/(1 - z)/2], [0, 0]])) + + # Complete elliptic integrals K(z) and E(z), both a 2F1 function + addb([S.Half, S.Half], [S.One], + Matrix([elliptic_k(z), elliptic_e(z)]), + Matrix([[2/pi, 0]]), + Matrix([[Rational(-1, 2), -1/(2*z-2)], + [Rational(-1, 2), S.Half]])) + addb([Rational(-1, 2), S.Half], [S.One], + Matrix([elliptic_k(z), elliptic_e(z)]), + Matrix([[0, 2/pi]]), + Matrix([[Rational(-1, 2), -1/(2*z-2)], + [Rational(-1, 2), S.Half]])) + + # 3F2 + addb([Rational(-1, 2), 1, 1], [S.Half, 2], + Matrix([z*HyperRep_atanh(z), HyperRep_log1(z), 1]), + Matrix([[Rational(-2, 3), -S.One/(3*z), Rational(2, 3)]]), + Matrix([[S.Half, 0, z/(1 - z)/2], + [0, 0, z/(z - 1)], + [0, 0, 0]])) + # actually the formula for 3/2 is much nicer ... + addb([Rational(-1, 2), 1, 1], [2, 2], + Matrix([HyperRep_power1(S.Half, z), HyperRep_log2(z), 1]), + Matrix([[Rational(4, 9) - 16/(9*z), 4/(3*z), 16/(9*z)]]), + Matrix([[z/2/(z - 1), 0, 0], [1/(2*(z - 1)), 0, S.Half], [0, 0, 0]])) + + # 1F1 + addb([1], [b], Matrix([z**(1 - b) * exp(z) * lowergamma(b - 1, z), 1]), + Matrix([[b - 1, 0]]), Matrix([[1 - b + z, 1], [0, 0]])) + addb([a], [2*a], + Matrix([z**(S.Half - a)*exp(z/2)*besseli(a - S.Half, z/2) + * gamma(a + S.Half)/4**(S.Half - a), + z**(S.Half - a)*exp(z/2)*besseli(a + S.Half, z/2) + * gamma(a + S.Half)/4**(S.Half - a)]), + Matrix([[1, 0]]), + Matrix([[z/2, z/2], [z/2, (z/2 - 2*a)]])) + mz = polar_lift(-1)*z + addb([a], [a + 1], + Matrix([mz**(-a)*a*lowergamma(a, mz), a*exp(z)]), + Matrix([[1, 0]]), + Matrix([[-a, 1], [0, z]])) + # This one is redundant. + add([Rational(-1, 2)], [S.Half], exp(z) - sqrt(pi*z)*(-I)*erf(I*sqrt(z))) + + # Added to get nice results for Laplace transform of Fresnel functions + # https://functions.wolfram.com/07.22.03.6437.01 + # Basic rule + #add([1], [Rational(3, 4), Rational(5, 4)], + # sqrt(pi) * (cos(2*sqrt(polar_lift(-1)*z))*fresnelc(2*root(polar_lift(-1)*z,4)/sqrt(pi)) + + # sin(2*sqrt(polar_lift(-1)*z))*fresnels(2*root(polar_lift(-1)*z,4)/sqrt(pi))) + # / (2*root(polar_lift(-1)*z,4))) + # Manually tuned rule + addb([1], [Rational(3, 4), Rational(5, 4)], + Matrix([ sqrt(pi)*(I*sinh(2*sqrt(z))*fresnels(2*root(z, 4)*exp(I*pi/4)/sqrt(pi)) + + cosh(2*sqrt(z))*fresnelc(2*root(z, 4)*exp(I*pi/4)/sqrt(pi))) + * exp(-I*pi/4)/(2*root(z, 4)), + sqrt(pi)*root(z, 4)*(sinh(2*sqrt(z))*fresnelc(2*root(z, 4)*exp(I*pi/4)/sqrt(pi)) + + I*cosh(2*sqrt(z))*fresnels(2*root(z, 4)*exp(I*pi/4)/sqrt(pi))) + *exp(-I*pi/4)/2, + 1 ]), + Matrix([[1, 0, 0]]), + Matrix([[Rational(-1, 4), 1, Rational(1, 4)], + [ z, Rational(1, 4), 0], + [ 0, 0, 0]])) + + # 2F2 + addb([S.Half, a], [Rational(3, 2), a + 1], + Matrix([a/(2*a - 1)*(-I)*sqrt(pi/z)*erf(I*sqrt(z)), + a/(2*a - 1)*(polar_lift(-1)*z)**(-a)* + lowergamma(a, polar_lift(-1)*z), + a/(2*a - 1)*exp(z)]), + Matrix([[1, -1, 0]]), + Matrix([[Rational(-1, 2), 0, 1], [0, -a, 1], [0, 0, z]])) + # We make a "basis" of four functions instead of three, and give EulerGamma + # an extra slot (it could just be a coefficient to 1). The advantage is + # that this way Polys will not see multivariate polynomials (it treats + # EulerGamma as an indeterminate), which is *way* faster. + addb([1, 1], [2, 2], + Matrix([Ei(z) - log(z), exp(z), 1, EulerGamma]), + Matrix([[1/z, 0, 0, -1/z]]), + Matrix([[0, 1, -1, 0], [0, z, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])) + + # 0F1 + add((), (S.Half, ), cosh(2*sqrt(z))) + addb([], [b], + Matrix([gamma(b)*z**((1 - b)/2)*besseli(b - 1, 2*sqrt(z)), + gamma(b)*z**(1 - b/2)*besseli(b, 2*sqrt(z))]), + Matrix([[1, 0]]), Matrix([[0, 1], [z, (1 - b)]])) + + # 0F3 + x = 4*z**Rational(1, 4) + + def fp(a, z): + return besseli(a, x) + besselj(a, x) + + def fm(a, z): + return besseli(a, x) - besselj(a, x) + + # TODO branching + addb([], [S.Half, a, a + S.Half], + Matrix([fp(2*a - 1, z), fm(2*a, z)*z**Rational(1, 4), + fm(2*a - 1, z)*sqrt(z), fp(2*a, z)*z**Rational(3, 4)]) + * 2**(-2*a)*gamma(2*a)*z**((1 - 2*a)/4), + Matrix([[1, 0, 0, 0]]), + Matrix([[0, 1, 0, 0], + [0, S.Half - a, 1, 0], + [0, 0, S.Half, 1], + [z, 0, 0, 1 - a]])) + x = 2*(4*z)**Rational(1, 4)*exp_polar(I*pi/4) + addb([], [a, a + S.Half, 2*a], + (2*sqrt(polar_lift(-1)*z))**(1 - 2*a)*gamma(2*a)**2 * + Matrix([besselj(2*a - 1, x)*besseli(2*a - 1, x), + x*(besseli(2*a, x)*besselj(2*a - 1, x) + - besseli(2*a - 1, x)*besselj(2*a, x)), + x**2*besseli(2*a, x)*besselj(2*a, x), + x**3*(besseli(2*a, x)*besselj(2*a - 1, x) + + besseli(2*a - 1, x)*besselj(2*a, x))]), + Matrix([[1, 0, 0, 0]]), + Matrix([[0, Rational(1, 4), 0, 0], + [0, (1 - 2*a)/2, Rational(-1, 2), 0], + [0, 0, 1 - 2*a, Rational(1, 4)], + [-32*z, 0, 0, 1 - a]])) + + # 1F2 + addb([a], [a - S.Half, 2*a], + Matrix([z**(S.Half - a)*besseli(a - S.Half, sqrt(z))**2, + z**(1 - a)*besseli(a - S.Half, sqrt(z)) + *besseli(a - Rational(3, 2), sqrt(z)), + z**(Rational(3, 2) - a)*besseli(a - Rational(3, 2), sqrt(z))**2]), + Matrix([[-gamma(a + S.Half)**2/4**(S.Half - a), + 2*gamma(a - S.Half)*gamma(a + S.Half)/4**(1 - a), + 0]]), + Matrix([[1 - 2*a, 1, 0], [z/2, S.Half - a, S.Half], [0, z, 0]])) + addb([S.Half], [b, 2 - b], + pi*(1 - b)/sin(pi*b)* + Matrix([besseli(1 - b, sqrt(z))*besseli(b - 1, sqrt(z)), + sqrt(z)*(besseli(-b, sqrt(z))*besseli(b - 1, sqrt(z)) + + besseli(1 - b, sqrt(z))*besseli(b, sqrt(z))), + besseli(-b, sqrt(z))*besseli(b, sqrt(z))]), + Matrix([[1, 0, 0]]), + Matrix([[b - 1, S.Half, 0], + [z, 0, z], + [0, S.Half, -b]])) + addb([S.Half], [Rational(3, 2), Rational(3, 2)], + Matrix([Shi(2*sqrt(z))/2/sqrt(z), sinh(2*sqrt(z))/2/sqrt(z), + cosh(2*sqrt(z))]), + Matrix([[1, 0, 0]]), + Matrix([[Rational(-1, 2), S.Half, 0], [0, Rational(-1, 2), S.Half], [0, 2*z, 0]])) + + # FresnelS + # Basic rule + #add([Rational(3, 4)], [Rational(3, 2),Rational(7, 4)], 6*fresnels( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) / ( pi * (exp(pi*I/4)*root(z,4)*2/sqrt(pi))**3 ) ) + # Manually tuned rule + addb([Rational(3, 4)], [Rational(3, 2), Rational(7, 4)], + Matrix( + [ fresnels( + exp( + pi*I/4)*root( + z, 4)*2/sqrt( + pi) ) / ( + pi * (exp(pi*I/4)*root(z, 4)*2/sqrt(pi))**3 ), + sinh(2*sqrt(z))/sqrt(z), + cosh(2*sqrt(z)) ]), + Matrix([[6, 0, 0]]), + Matrix([[Rational(-3, 4), Rational(1, 16), 0], + [ 0, Rational(-1, 2), 1], + [ 0, z, 0]])) + + # FresnelC + # Basic rule + #add([Rational(1, 4)], [S.Half,Rational(5, 4)], fresnelc( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) / ( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) ) + # Manually tuned rule + addb([Rational(1, 4)], [S.Half, Rational(5, 4)], + Matrix( + [ sqrt( + pi)*exp( + -I*pi/4)*fresnelc( + 2*root(z, 4)*exp(I*pi/4)/sqrt(pi))/(2*root(z, 4)), + cosh(2*sqrt(z)), + sinh(2*sqrt(z))*sqrt(z) ]), + Matrix([[1, 0, 0]]), + Matrix([[Rational(-1, 4), Rational(1, 4), 0 ], + [ 0, 0, 1 ], + [ 0, z, S.Half]])) + + # 2F3 + # XXX with this five-parameter formula is pretty slow with the current + # Formula.find_instantiations (creates 2!*3!*3**(2+3) ~ 3000 + # instantiations ... But it's not too bad. + addb([a, a + S.Half], [2*a, b, 2*a - b + 1], + gamma(b)*gamma(2*a - b + 1) * (sqrt(z)/2)**(1 - 2*a) * + Matrix([besseli(b - 1, sqrt(z))*besseli(2*a - b, sqrt(z)), + sqrt(z)*besseli(b, sqrt(z))*besseli(2*a - b, sqrt(z)), + sqrt(z)*besseli(b - 1, sqrt(z))*besseli(2*a - b + 1, sqrt(z)), + besseli(b, sqrt(z))*besseli(2*a - b + 1, sqrt(z))]), + Matrix([[1, 0, 0, 0]]), + Matrix([[0, S.Half, S.Half, 0], + [z/2, 1 - b, 0, z/2], + [z/2, 0, b - 2*a, z/2], + [0, S.Half, S.Half, -2*a]])) + # (C/f above comment about eulergamma in the basis). + addb([1, 1], [2, 2, Rational(3, 2)], + Matrix([Chi(2*sqrt(z)) - log(2*sqrt(z)), + cosh(2*sqrt(z)), sqrt(z)*sinh(2*sqrt(z)), 1, EulerGamma]), + Matrix([[1/z, 0, 0, 0, -1/z]]), + Matrix([[0, S.Half, 0, Rational(-1, 2), 0], + [0, 0, 1, 0, 0], + [0, z, S.Half, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]])) + + # 3F3 + # This is rule: https://functions.wolfram.com/07.31.03.0134.01 + # Initial reason to add it was a nice solution for + # integrate(erf(a*z)/z**2, z) and same for erfc and erfi. + # Basic rule + # add([1, 1, a], [2, 2, a+1], (a/(z*(a-1)**2)) * + # (1 - (-z)**(1-a) * (gamma(a) - uppergamma(a,-z)) + # - (a-1) * (EulerGamma + uppergamma(0,-z) + log(-z)) + # - exp(z))) + # Manually tuned rule + addb([1, 1, a], [2, 2, a+1], + Matrix([a*(log(-z) + expint(1, -z) + EulerGamma)/(z*(a**2 - 2*a + 1)), + a*(-z)**(-a)*(gamma(a) - uppergamma(a, -z))/(a - 1)**2, + a*exp(z)/(a**2 - 2*a + 1), + a/(z*(a**2 - 2*a + 1))]), + Matrix([[1-a, 1, -1/z, 1]]), + Matrix([[-1,0,-1/z,1], + [0,-a,1,0], + [0,0,z,0], + [0,0,0,-1]])) + + +def add_meijerg_formulae(formulae): + a, b, c, z = list(map(Dummy, 'abcz')) + rho = Dummy('rho') + + def add(an, ap, bm, bq, B, C, M, matcher): + formulae.append(MeijerFormula(an, ap, bm, bq, z, [a, b, c, rho], + B, C, M, matcher)) + + def detect_uppergamma(func): + x = func.an[0] + y, z = func.bm + swapped = False + if not _mod1((x - y).simplify()): + swapped = True + (y, z) = (z, y) + if _mod1((x - z).simplify()) or x - z > 0: + return None + l = [y, x] + if swapped: + l = [x, y] + return {rho: y, a: x - y}, G_Function([x], [], l, []) + + add([a + rho], [], [rho, a + rho], [], + Matrix([gamma(1 - a)*z**rho*exp(z)*uppergamma(a, z), + gamma(1 - a)*z**(a + rho)]), + Matrix([[1, 0]]), + Matrix([[rho + z, -1], [0, a + rho]]), + detect_uppergamma) + + def detect_3113(func): + """https://functions.wolfram.com/07.34.03.0984.01""" + x = func.an[0] + u, v, w = func.bm + if _mod1((u - v).simplify()) == 0: + if _mod1((v - w).simplify()) == 0: + return + sig = (S.Half, S.Half, S.Zero) + x1, x2, y = u, v, w + else: + if _mod1((x - u).simplify()) == 0: + sig = (S.Half, S.Zero, S.Half) + x1, y, x2 = u, v, w + else: + sig = (S.Zero, S.Half, S.Half) + y, x1, x2 = u, v, w + + if (_mod1((x - x1).simplify()) != 0 or + _mod1((x - x2).simplify()) != 0 or + _mod1((x - y).simplify()) != S.Half or + x - x1 > 0 or x - x2 > 0): + return + + return {a: x}, G_Function([x], [], [x - S.Half + t for t in sig], []) + + s = sin(2*sqrt(z)) + c_ = cos(2*sqrt(z)) + S_ = Si(2*sqrt(z)) - pi/2 + C = Ci(2*sqrt(z)) + add([a], [], [a, a, a - S.Half], [], + Matrix([sqrt(pi)*z**(a - S.Half)*(c_*S_ - s*C), + sqrt(pi)*z**a*(s*S_ + c_*C), + sqrt(pi)*z**a]), + Matrix([[-2, 0, 0]]), + Matrix([[a - S.Half, -1, 0], [z, a, S.Half], [0, 0, a]]), + detect_3113) + + +def make_simp(z): + """ Create a function that simplifies rational functions in ``z``. """ + + def simp(expr): + """ Efficiently simplify the rational function ``expr``. """ + numer, denom = expr.as_numer_denom() + numer = numer.expand() + # denom = denom.expand() # is this needed? + c, numer, denom = poly(numer, z).cancel(poly(denom, z)) + return c * numer.as_expr() / denom.as_expr() + + return simp + + +def debug(*args): + if SYMPY_DEBUG: + for a in args: + print(a, end="") + print() + + +class Hyper_Function(Expr): + """ A generalized hypergeometric function. """ + + def __new__(cls, ap, bq): + obj = super().__new__(cls) + obj.ap = Tuple(*list(map(expand, ap))) + obj.bq = Tuple(*list(map(expand, bq))) + return obj + + @property + def args(self): + return (self.ap, self.bq) + + @property + def sizes(self): + return (len(self.ap), len(self.bq)) + + @property + def gamma(self): + """ + Number of upper parameters that are negative integers + + This is a transformation invariant. + """ + return sum(bool(x.is_integer and x.is_negative) for x in self.ap) + + def _hashable_content(self): + return super()._hashable_content() + (self.ap, + self.bq) + + def __call__(self, arg): + return hyper(self.ap, self.bq, arg) + + def build_invariants(self): + """ + Compute the invariant vector. + + Explanation + =========== + + The invariant vector is: + (gamma, ((s1, n1), ..., (sk, nk)), ((t1, m1), ..., (tr, mr))) + where gamma is the number of integer a < 0, + s1 < ... < sk + nl is the number of parameters a_i congruent to sl mod 1 + t1 < ... < tr + ml is the number of parameters b_i congruent to tl mod 1 + + If the index pair contains parameters, then this is not truly an + invariant, since the parameters cannot be sorted uniquely mod1. + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import Hyper_Function + >>> from sympy import S + >>> ap = (S.Half, S.One/3, S(-1)/2, -2) + >>> bq = (1, 2) + + Here gamma = 1, + k = 3, s1 = 0, s2 = 1/3, s3 = 1/2 + n1 = 1, n2 = 1, n2 = 2 + r = 1, t1 = 0 + m1 = 2: + + >>> Hyper_Function(ap, bq).build_invariants() + (1, ((0, 1), (1/3, 1), (1/2, 2)), ((0, 2),)) + """ + abuckets, bbuckets = sift(self.ap, _mod1), sift(self.bq, _mod1) + + def tr(bucket): + bucket = list(bucket.items()) + if not any(isinstance(x[0], Mod) for x in bucket): + bucket.sort(key=lambda x: default_sort_key(x[0])) + bucket = tuple([(mod, len(values)) for mod, values in bucket if + values]) + return bucket + + return (self.gamma, tr(abuckets), tr(bbuckets)) + + def difficulty(self, func): + """ Estimate how many steps it takes to reach ``func`` from self. + Return -1 if impossible. """ + if self.gamma != func.gamma: + return -1 + oabuckets, obbuckets, abuckets, bbuckets = [sift(params, _mod1) for + params in (self.ap, self.bq, func.ap, func.bq)] + + diff = 0 + for bucket, obucket in [(abuckets, oabuckets), (bbuckets, obbuckets)]: + for mod in set(list(bucket.keys()) + list(obucket.keys())): + if (mod not in bucket) or (mod not in obucket) \ + or len(bucket[mod]) != len(obucket[mod]): + return -1 + l1 = list(bucket[mod]) + l2 = list(obucket[mod]) + l1.sort() + l2.sort() + for i, j in zip(l1, l2): + diff += abs(i - j) + + return diff + + def _is_suitable_origin(self): + """ + Decide if ``self`` is a suitable origin. + + Explanation + =========== + + A function is a suitable origin iff: + * none of the ai equals bj + n, with n a non-negative integer + * none of the ai is zero + * none of the bj is a non-positive integer + + Note that this gives meaningful results only when none of the indices + are symbolic. + + """ + for a in self.ap: + for b in self.bq: + if (a - b).is_integer and (a - b).is_negative is False: + return False + for a in self.ap: + if a == 0: + return False + for b in self.bq: + if b.is_integer and b.is_nonpositive: + return False + return True + + +class G_Function(Expr): + """ A Meijer G-function. """ + + def __new__(cls, an, ap, bm, bq): + obj = super().__new__(cls) + obj.an = Tuple(*list(map(expand, an))) + obj.ap = Tuple(*list(map(expand, ap))) + obj.bm = Tuple(*list(map(expand, bm))) + obj.bq = Tuple(*list(map(expand, bq))) + return obj + + @property + def args(self): + return (self.an, self.ap, self.bm, self.bq) + + def _hashable_content(self): + return super()._hashable_content() + self.args + + def __call__(self, z): + return meijerg(self.an, self.ap, self.bm, self.bq, z) + + def compute_buckets(self): + """ + Compute buckets for the fours sets of parameters. + + Explanation + =========== + + We guarantee that any two equal Mod objects returned are actually the + same, and that the buckets are sorted by real part (an and bq + descendending, bm and ap ascending). + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import G_Function + >>> from sympy.abc import y + >>> from sympy import S + + >>> a, b = [1, 3, 2, S(3)/2], [1 + y, y, 2, y + 3] + >>> G_Function(a, b, [2], [y]).compute_buckets() + ({0: [3, 2, 1], 1/2: [3/2]}, + {0: [2], y: [y, y + 1, y + 3]}, {0: [2]}, {y: [y]}) + + """ + dicts = pan, pap, pbm, pbq = [defaultdict(list) for i in range(4)] + for dic, lis in zip(dicts, (self.an, self.ap, self.bm, self.bq)): + for x in lis: + dic[_mod1(x)].append(x) + + for dic, flip in zip(dicts, (True, False, False, True)): + for m, items in dic.items(): + x0 = items[0] + items.sort(key=lambda x: x - x0, reverse=flip) + dic[m] = items + + return tuple([dict(w) for w in dicts]) + + @property + def signature(self): + return (len(self.an), len(self.ap), len(self.bm), len(self.bq)) + + +# Dummy variable. +_x = Dummy('x') + +class Formula: + """ + This class represents hypergeometric formulae. + + Explanation + =========== + + Its data members are: + - z, the argument + - closed_form, the closed form expression + - symbols, the free symbols (parameters) in the formula + - func, the function + - B, C, M (see _compute_basis) + + Examples + ======== + + >>> from sympy.abc import a, b, z + >>> from sympy.simplify.hyperexpand import Formula, Hyper_Function + >>> func = Hyper_Function((a/2, a/3 + b, (1+a)/2), (a, b, (a+b)/7)) + >>> f = Formula(func, z, None, [a, b]) + + """ + + def _compute_basis(self, closed_form): + """ + Compute a set of functions B=(f1, ..., fn), a nxn matrix M + and a 1xn matrix C such that: + closed_form = C B + z d/dz B = M B. + """ + afactors = [_x + a for a in self.func.ap] + bfactors = [_x + b - 1 for b in self.func.bq] + expr = _x*Mul(*bfactors) - self.z*Mul(*afactors) + poly = Poly(expr, _x) + + n = poly.degree() - 1 + b = [closed_form] + for _ in range(n): + b.append(self.z*b[-1].diff(self.z)) + + self.B = Matrix(b) + self.C = Matrix([[1] + [0]*n]) + + m = eye(n) + m = m.col_insert(0, zeros(n, 1)) + l = poly.all_coeffs()[1:] + l.reverse() + self.M = m.row_insert(n, -Matrix([l])/poly.all_coeffs()[0]) + + def __init__(self, func, z, res, symbols, B=None, C=None, M=None): + z = sympify(z) + res = sympify(res) + symbols = [x for x in sympify(symbols) if func.has(x)] + + self.z = z + self.symbols = symbols + self.B = B + self.C = C + self.M = M + self.func = func + + # TODO with symbolic parameters, it could be advantageous + # (for prettier answers) to compute a basis only *after* + # instantiation + if res is not None: + self._compute_basis(res) + + @property + def closed_form(self): + return reduce(lambda s,m: s+m[0]*m[1], zip(self.C, self.B), S.Zero) + + def find_instantiations(self, func): + """ + Find substitutions of the free symbols that match ``func``. + + Return the substitution dictionaries as a list. Note that the returned + instantiations need not actually match, or be valid! + + """ + from sympy.solvers import solve + ap = func.ap + bq = func.bq + if len(ap) != len(self.func.ap) or len(bq) != len(self.func.bq): + raise TypeError('Cannot instantiate other number of parameters') + symbol_values = [] + for a in self.symbols: + if a in self.func.ap.args: + symbol_values.append(ap) + elif a in self.func.bq.args: + symbol_values.append(bq) + else: + raise ValueError("At least one of the parameters of the " + "formula must be equal to %s" % (a,)) + base_repl = [dict(list(zip(self.symbols, values))) + for values in product(*symbol_values)] + abuckets, bbuckets = [sift(params, _mod1) for params in [ap, bq]] + a_inv, b_inv = [{a: len(vals) for a, vals in bucket.items()} + for bucket in [abuckets, bbuckets]] + critical_values = [[0] for _ in self.symbols] + result = [] + _n = Dummy() + for repl in base_repl: + symb_a, symb_b = [sift(params, lambda x: _mod1(x.xreplace(repl))) + for params in [self.func.ap, self.func.bq]] + for bucket, obucket in [(abuckets, symb_a), (bbuckets, symb_b)]: + for mod in set(list(bucket.keys()) + list(obucket.keys())): + if (mod not in bucket) or (mod not in obucket) \ + or len(bucket[mod]) != len(obucket[mod]): + break + for a, vals in zip(self.symbols, critical_values): + if repl[a].free_symbols: + continue + exprs = [expr for expr in obucket[mod] if expr.has(a)] + repl0 = repl.copy() + repl0[a] += _n + for expr in exprs: + for target in bucket[mod]: + n0, = solve(expr.xreplace(repl0) - target, _n) + if n0.free_symbols: + raise ValueError("Value should not be true") + vals.append(n0) + else: + values = [] + for a, vals in zip(self.symbols, critical_values): + a0 = repl[a] + min_ = floor(min(vals)) + max_ = ceiling(max(vals)) + values.append([a0 + n for n in range(min_, max_ + 1)]) + result.extend(dict(list(zip(self.symbols, l))) for l in product(*values)) + return result + + + + +class FormulaCollection: + """ A collection of formulae to use as origins. """ + + def __init__(self): + """ Doing this globally at module init time is a pain ... """ + self.symbolic_formulae = {} + self.concrete_formulae = {} + self.formulae = [] + + add_formulae(self.formulae) + + # Now process the formulae into a helpful form. + # These dicts are indexed by (p, q). + + for f in self.formulae: + sizes = f.func.sizes + if len(f.symbols) > 0: + self.symbolic_formulae.setdefault(sizes, []).append(f) + else: + inv = f.func.build_invariants() + self.concrete_formulae.setdefault(sizes, {})[inv] = f + + def lookup_origin(self, func): + """ + Given the suitable target ``func``, try to find an origin in our + knowledge base. + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import (FormulaCollection, + ... Hyper_Function) + >>> f = FormulaCollection() + >>> f.lookup_origin(Hyper_Function((), ())).closed_form + exp(_z) + >>> f.lookup_origin(Hyper_Function([1], ())).closed_form + HyperRep_power1(-1, _z) + + >>> from sympy import S + >>> i = Hyper_Function([S('1/4'), S('3/4 + 4')], [S.Half]) + >>> f.lookup_origin(i).closed_form + HyperRep_sqrts1(-1/4, _z) + """ + inv = func.build_invariants() + sizes = func.sizes + if sizes in self.concrete_formulae and \ + inv in self.concrete_formulae[sizes]: + return self.concrete_formulae[sizes][inv] + + # We don't have a concrete formula. Try to instantiate. + if sizes not in self.symbolic_formulae: + return None # Too bad... + + possible = [] + for f in self.symbolic_formulae[sizes]: + repls = f.find_instantiations(func) + for repl in repls: + func2 = f.func.xreplace(repl) + if not func2._is_suitable_origin(): + continue + diff = func2.difficulty(func) + if diff == -1: + continue + possible.append((diff, repl, f, func2)) + + # find the nearest origin + possible.sort(key=lambda x: x[0]) + for _, repl, f, func2 in possible: + f2 = Formula(func2, f.z, None, [], f.B.subs(repl), + f.C.subs(repl), f.M.subs(repl)) + if not any(e.has(S.NaN, oo, -oo, zoo) for e in [f2.B, f2.M, f2.C]): + return f2 + + return None + + +class MeijerFormula: + """ + This class represents a Meijer G-function formula. + + Its data members are: + - z, the argument + - symbols, the free symbols (parameters) in the formula + - func, the function + - B, C, M (c/f ordinary Formula) + """ + + def __init__(self, an, ap, bm, bq, z, symbols, B, C, M, matcher): + an, ap, bm, bq = [Tuple(*list(map(expand, w))) for w in [an, ap, bm, bq]] + self.func = G_Function(an, ap, bm, bq) + self.z = z + self.symbols = symbols + self._matcher = matcher + self.B = B + self.C = C + self.M = M + + @property + def closed_form(self): + return reduce(lambda s,m: s+m[0]*m[1], zip(self.C, self.B), S.Zero) + + def try_instantiate(self, func): + """ + Try to instantiate the current formula to (almost) match func. + This uses the _matcher passed on init. + """ + if func.signature != self.func.signature: + return None + res = self._matcher(func) + if res is not None: + subs, newfunc = res + return MeijerFormula(newfunc.an, newfunc.ap, newfunc.bm, newfunc.bq, + self.z, [], + self.B.subs(subs), self.C.subs(subs), + self.M.subs(subs), None) + + +class MeijerFormulaCollection: + """ + This class holds a collection of meijer g formulae. + """ + + def __init__(self): + formulae = [] + add_meijerg_formulae(formulae) + self.formulae = defaultdict(list) + for formula in formulae: + self.formulae[formula.func.signature].append(formula) + self.formulae = dict(self.formulae) + + def lookup_origin(self, func): + """ Try to find a formula that matches func. """ + if func.signature not in self.formulae: + return None + for formula in self.formulae[func.signature]: + res = formula.try_instantiate(func) + if res is not None: + return res + + +class Operator: + """ + Base class for operators to be applied to our functions. + + Explanation + =========== + + These operators are differential operators. They are by convention + expressed in the variable D = z*d/dz (although this base class does + not actually care). + Note that when the operator is applied to an object, we typically do + *not* blindly differentiate but instead use a different representation + of the z*d/dz operator (see make_derivative_operator). + + To subclass from this, define a __init__ method that initializes a + self._poly variable. This variable stores a polynomial. By convention + the generator is z*d/dz, and acts to the right of all coefficients. + + Thus this poly + x**2 + 2*z*x + 1 + represents the differential operator + (z*d/dz)**2 + 2*z**2*d/dz. + + This class is used only in the implementation of the hypergeometric + function expansion algorithm. + """ + + def apply(self, obj, op): + """ + Apply ``self`` to the object ``obj``, where the generator is ``op``. + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import Operator + >>> from sympy.polys.polytools import Poly + >>> from sympy.abc import x, y, z + >>> op = Operator() + >>> op._poly = Poly(x**2 + z*x + y, x) + >>> op.apply(z**7, lambda f: f.diff(z)) + y*z**7 + 7*z**7 + 42*z**5 + """ + coeffs = self._poly.all_coeffs() + coeffs.reverse() + diffs = [obj] + for c in coeffs[1:]: + diffs.append(op(diffs[-1])) + r = coeffs[0]*diffs[0] + for c, d in zip(coeffs[1:], diffs[1:]): + r += c*d + return r + + +class MultOperator(Operator): + """ Simply multiply by a "constant" """ + + def __init__(self, p): + self._poly = Poly(p, _x) + + +class ShiftA(Operator): + """ Increment an upper index. """ + + def __init__(self, ai): + ai = sympify(ai) + if ai == 0: + raise ValueError('Cannot increment zero upper index.') + self._poly = Poly(_x/ai + 1, _x) + + def __str__(self): + return '' % (1/self._poly.all_coeffs()[0]) + + +class ShiftB(Operator): + """ Decrement a lower index. """ + + def __init__(self, bi): + bi = sympify(bi) + if bi == 1: + raise ValueError('Cannot decrement unit lower index.') + self._poly = Poly(_x/(bi - 1) + 1, _x) + + def __str__(self): + return '' % (1/self._poly.all_coeffs()[0] + 1) + + +class UnShiftA(Operator): + """ Decrement an upper index. """ + + def __init__(self, ap, bq, i, z): + """ Note: i counts from zero! """ + ap, bq, i = list(map(sympify, [ap, bq, i])) + + self._ap = ap + self._bq = bq + self._i = i + + ap = list(ap) + bq = list(bq) + ai = ap.pop(i) - 1 + + if ai == 0: + raise ValueError('Cannot decrement unit upper index.') + + m = Poly(z*ai, _x) + for a in ap: + m *= Poly(_x + a, _x) + + A = Dummy('A') + n = D = Poly(ai*A - ai, A) + for b in bq: + n *= D + (b - 1).as_poly(A) + + b0 = -n.nth(0) + if b0 == 0: + raise ValueError('Cannot decrement upper index: ' + 'cancels with lower') + + n = Poly(Poly(n.all_coeffs()[:-1], A).as_expr().subs(A, _x/ai + 1), _x) + + self._poly = Poly((n - m)/b0, _x) + + def __str__(self): + return '' % (self._i, + self._ap, self._bq) + + +class UnShiftB(Operator): + """ Increment a lower index. """ + + def __init__(self, ap, bq, i, z): + """ Note: i counts from zero! """ + ap, bq, i = list(map(sympify, [ap, bq, i])) + + self._ap = ap + self._bq = bq + self._i = i + + ap = list(ap) + bq = list(bq) + bi = bq.pop(i) + 1 + + if bi == 0: + raise ValueError('Cannot increment -1 lower index.') + + m = Poly(_x*(bi - 1), _x) + for b in bq: + m *= Poly(_x + b - 1, _x) + + B = Dummy('B') + D = Poly((bi - 1)*B - bi + 1, B) + n = Poly(z, B) + for a in ap: + n *= (D + a.as_poly(B)) + + b0 = n.nth(0) + if b0 == 0: + raise ValueError('Cannot increment index: cancels with upper') + + n = Poly(Poly(n.all_coeffs()[:-1], B).as_expr().subs( + B, _x/(bi - 1) + 1), _x) + + self._poly = Poly((m - n)/b0, _x) + + def __str__(self): + return '' % (self._i, + self._ap, self._bq) + + +class MeijerShiftA(Operator): + """ Increment an upper b index. """ + + def __init__(self, bi): + bi = sympify(bi) + self._poly = Poly(bi - _x, _x) + + def __str__(self): + return '' % (self._poly.all_coeffs()[1]) + + +class MeijerShiftB(Operator): + """ Decrement an upper a index. """ + + def __init__(self, bi): + bi = sympify(bi) + self._poly = Poly(1 - bi + _x, _x) + + def __str__(self): + return '' % (1 - self._poly.all_coeffs()[1]) + + +class MeijerShiftC(Operator): + """ Increment a lower b index. """ + + def __init__(self, bi): + bi = sympify(bi) + self._poly = Poly(-bi + _x, _x) + + def __str__(self): + return '' % (-self._poly.all_coeffs()[1]) + + +class MeijerShiftD(Operator): + """ Decrement a lower a index. """ + + def __init__(self, bi): + bi = sympify(bi) + self._poly = Poly(bi - 1 - _x, _x) + + def __str__(self): + return '' % (self._poly.all_coeffs()[1] + 1) + + +class MeijerUnShiftA(Operator): + """ Decrement an upper b index. """ + + def __init__(self, an, ap, bm, bq, i, z): + """ Note: i counts from zero! """ + an, ap, bm, bq, i = list(map(sympify, [an, ap, bm, bq, i])) + + self._an = an + self._ap = ap + self._bm = bm + self._bq = bq + self._i = i + + an = list(an) + ap = list(ap) + bm = list(bm) + bq = list(bq) + bi = bm.pop(i) - 1 + + m = Poly(1, _x) * prod(Poly(b - _x, _x) for b in bm) * prod(Poly(_x - b, _x) for b in bq) + + A = Dummy('A') + D = Poly(bi - A, A) + n = Poly(z, A) * prod((D + 1 - a) for a in an) * prod((-D + a - 1) for a in ap) + + b0 = n.nth(0) + if b0 == 0: + raise ValueError('Cannot decrement upper b index (cancels)') + + n = Poly(Poly(n.all_coeffs()[:-1], A).as_expr().subs(A, bi - _x), _x) + + self._poly = Poly((m - n)/b0, _x) + + def __str__(self): + return '' % (self._i, + self._an, self._ap, self._bm, self._bq) + + +class MeijerUnShiftB(Operator): + """ Increment an upper a index. """ + + def __init__(self, an, ap, bm, bq, i, z): + """ Note: i counts from zero! """ + an, ap, bm, bq, i = list(map(sympify, [an, ap, bm, bq, i])) + + self._an = an + self._ap = ap + self._bm = bm + self._bq = bq + self._i = i + + an = list(an) + ap = list(ap) + bm = list(bm) + bq = list(bq) + ai = an.pop(i) + 1 + + m = Poly(z, _x) + for a in an: + m *= Poly(1 - a + _x, _x) + for a in ap: + m *= Poly(a - 1 - _x, _x) + + B = Dummy('B') + D = Poly(B + ai - 1, B) + n = Poly(1, B) + for b in bm: + n *= (-D + b) + for b in bq: + n *= (D - b) + + b0 = n.nth(0) + if b0 == 0: + raise ValueError('Cannot increment upper a index (cancels)') + + n = Poly(Poly(n.all_coeffs()[:-1], B).as_expr().subs( + B, 1 - ai + _x), _x) + + self._poly = Poly((m - n)/b0, _x) + + def __str__(self): + return '' % (self._i, + self._an, self._ap, self._bm, self._bq) + + +class MeijerUnShiftC(Operator): + """ Decrement a lower b index. """ + # XXX this is "essentially" the same as MeijerUnShiftA. This "essentially" + # can be made rigorous using the functional equation G(1/z) = G'(z), + # where G' denotes a G function of slightly altered parameters. + # However, sorting out the details seems harder than just coding it + # again. + + def __init__(self, an, ap, bm, bq, i, z): + """ Note: i counts from zero! """ + an, ap, bm, bq, i = list(map(sympify, [an, ap, bm, bq, i])) + + self._an = an + self._ap = ap + self._bm = bm + self._bq = bq + self._i = i + + an = list(an) + ap = list(ap) + bm = list(bm) + bq = list(bq) + bi = bq.pop(i) - 1 + + m = Poly(1, _x) + for b in bm: + m *= Poly(b - _x, _x) + for b in bq: + m *= Poly(_x - b, _x) + + C = Dummy('C') + D = Poly(bi + C, C) + n = Poly(z, C) + for a in an: + n *= (D + 1 - a) + for a in ap: + n *= (-D + a - 1) + + b0 = n.nth(0) + if b0 == 0: + raise ValueError('Cannot decrement lower b index (cancels)') + + n = Poly(Poly(n.all_coeffs()[:-1], C).as_expr().subs(C, _x - bi), _x) + + self._poly = Poly((m - n)/b0, _x) + + def __str__(self): + return '' % (self._i, + self._an, self._ap, self._bm, self._bq) + + +class MeijerUnShiftD(Operator): + """ Increment a lower a index. """ + # XXX This is essentially the same as MeijerUnShiftA. + # See comment at MeijerUnShiftC. + + def __init__(self, an, ap, bm, bq, i, z): + """ Note: i counts from zero! """ + an, ap, bm, bq, i = list(map(sympify, [an, ap, bm, bq, i])) + + self._an = an + self._ap = ap + self._bm = bm + self._bq = bq + self._i = i + + an = list(an) + ap = list(ap) + bm = list(bm) + bq = list(bq) + ai = ap.pop(i) + 1 + + m = Poly(z, _x) + for a in an: + m *= Poly(1 - a + _x, _x) + for a in ap: + m *= Poly(a - 1 - _x, _x) + + B = Dummy('B') # - this is the shift operator `D_I` + D = Poly(ai - 1 - B, B) + n = Poly(1, B) + for b in bm: + n *= (-D + b) + for b in bq: + n *= (D - b) + + b0 = n.nth(0) + if b0 == 0: + raise ValueError('Cannot increment lower a index (cancels)') + + n = Poly(Poly(n.all_coeffs()[:-1], B).as_expr().subs( + B, ai - 1 - _x), _x) + + self._poly = Poly((m - n)/b0, _x) + + def __str__(self): + return '' % (self._i, + self._an, self._ap, self._bm, self._bq) + + +class ReduceOrder(Operator): + """ Reduce Order by cancelling an upper and a lower index. """ + + def __new__(cls, ai, bj): + """ For convenience if reduction is not possible, return None. """ + ai = sympify(ai) + bj = sympify(bj) + n = ai - bj + if not n.is_Integer or n < 0: + return None + if bj.is_integer and bj.is_nonpositive: + return None + + expr = Operator.__new__(cls) + + p = S.One + for k in range(n): + p *= (_x + bj + k)/(bj + k) + + expr._poly = Poly(p, _x) + expr._a = ai + expr._b = bj + + return expr + + @classmethod + def _meijer(cls, b, a, sign): + """ Cancel b + sign*s and a + sign*s + This is for meijer G functions. """ + b = sympify(b) + a = sympify(a) + n = b - a + if n.is_negative or not n.is_Integer: + return None + + expr = Operator.__new__(cls) + + p = S.One + for k in range(n): + p *= (sign*_x + a + k) + + expr._poly = Poly(p, _x) + if sign == -1: + expr._a = b + expr._b = a + else: + expr._b = Add(1, a - 1, evaluate=False) + expr._a = Add(1, b - 1, evaluate=False) + + return expr + + @classmethod + def meijer_minus(cls, b, a): + return cls._meijer(b, a, -1) + + @classmethod + def meijer_plus(cls, a, b): + return cls._meijer(1 - a, 1 - b, 1) + + def __str__(self): + return '' % \ + (self._a, self._b) + + +def _reduce_order(ap, bq, gen, key): + """ Order reduction algorithm used in Hypergeometric and Meijer G """ + ap = list(ap) + bq = list(bq) + + ap.sort(key=key) + bq.sort(key=key) + + nap = [] + # we will edit bq in place + operators = [] + for a in ap: + op = None + for i in range(len(bq)): + op = gen(a, bq[i]) + if op is not None: + bq.pop(i) + break + if op is None: + nap.append(a) + else: + operators.append(op) + + return nap, bq, operators + + +def reduce_order(func): + """ + Given the hypergeometric function ``func``, find a sequence of operators to + reduces order as much as possible. + + Explanation + =========== + + Return (newfunc, [operators]), where applying the operators to the + hypergeometric function newfunc yields func. + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import reduce_order, Hyper_Function + >>> reduce_order(Hyper_Function((1, 2), (3, 4))) + (Hyper_Function((1, 2), (3, 4)), []) + >>> reduce_order(Hyper_Function((1,), (1,))) + (Hyper_Function((), ()), []) + >>> reduce_order(Hyper_Function((2, 4), (3, 3))) + (Hyper_Function((2,), (3,)), []) + """ + nap, nbq, operators = _reduce_order(func.ap, func.bq, ReduceOrder, default_sort_key) + + return Hyper_Function(Tuple(*nap), Tuple(*nbq)), operators + + +def reduce_order_meijer(func): + """ + Given the Meijer G function parameters, ``func``, find a sequence of + operators that reduces order as much as possible. + + Return newfunc, [operators]. + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import (reduce_order_meijer, + ... G_Function) + >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [3, 4], [1, 2]))[0] + G_Function((4, 3), (5, 6), (3, 4), (2, 1)) + >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [3, 4], [1, 8]))[0] + G_Function((3,), (5, 6), (3, 4), (1,)) + >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [7, 5], [1, 5]))[0] + G_Function((3,), (), (), (1,)) + >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [7, 5], [5, 3]))[0] + G_Function((), (), (), ()) + """ + + nan, nbq, ops1 = _reduce_order(func.an, func.bq, ReduceOrder.meijer_plus, + lambda x: default_sort_key(-x)) + nbm, nap, ops2 = _reduce_order(func.bm, func.ap, ReduceOrder.meijer_minus, + default_sort_key) + + return G_Function(nan, nap, nbm, nbq), ops1 + ops2 + + +def make_derivative_operator(M, z): + """ Create a derivative operator, to be passed to Operator.apply. """ + def doit(C): + r = z*C.diff(z) + C*M + r = r.applyfunc(make_simp(z)) + return r + return doit + + +def apply_operators(obj, ops, op): + """ + Apply the list of operators ``ops`` to object ``obj``, substituting + ``op`` for the generator. + """ + res = obj + for o in reversed(ops): + res = o.apply(res, op) + return res + + +def devise_plan(target, origin, z): + """ + Devise a plan (consisting of shift and un-shift operators) to be applied + to the hypergeometric function ``target`` to yield ``origin``. + Returns a list of operators. + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import devise_plan, Hyper_Function + >>> from sympy.abc import z + + Nothing to do: + + >>> devise_plan(Hyper_Function((1, 2), ()), Hyper_Function((1, 2), ()), z) + [] + >>> devise_plan(Hyper_Function((), (1, 2)), Hyper_Function((), (1, 2)), z) + [] + + Very simple plans: + + >>> devise_plan(Hyper_Function((2,), ()), Hyper_Function((1,), ()), z) + [] + >>> devise_plan(Hyper_Function((), (2,)), Hyper_Function((), (1,)), z) + [] + + Several buckets: + + >>> from sympy import S + >>> devise_plan(Hyper_Function((1, S.Half), ()), + ... Hyper_Function((2, S('3/2')), ()), z) #doctest: +NORMALIZE_WHITESPACE + [, + ] + + A slightly more complicated plan: + + >>> devise_plan(Hyper_Function((1, 3), ()), Hyper_Function((2, 2), ()), z) + [, ] + + Another more complicated plan: (note that the ap have to be shifted first!) + + >>> devise_plan(Hyper_Function((1, -1), (2,)), Hyper_Function((3, -2), (4,)), z) + [, , + , + , ] + """ + abuckets, bbuckets, nabuckets, nbbuckets = [sift(params, _mod1) for + params in (target.ap, target.bq, origin.ap, origin.bq)] + + if len(list(abuckets.keys())) != len(list(nabuckets.keys())) or \ + len(list(bbuckets.keys())) != len(list(nbbuckets.keys())): + raise ValueError('%s not reachable from %s' % (target, origin)) + + ops = [] + + def do_shifts(fro, to, inc, dec): + ops = [] + for i in range(len(fro)): + if to[i] - fro[i] > 0: + sh = inc + ch = 1 + else: + sh = dec + ch = -1 + + while to[i] != fro[i]: + ops += [sh(fro, i)] + fro[i] += ch + + return ops + + def do_shifts_a(nal, nbk, al, aother, bother): + """ Shift us from (nal, nbk) to (al, nbk). """ + return do_shifts(nal, al, lambda p, i: ShiftA(p[i]), + lambda p, i: UnShiftA(p + aother, nbk + bother, i, z)) + + def do_shifts_b(nal, nbk, bk, aother, bother): + """ Shift us from (nal, nbk) to (nal, bk). """ + return do_shifts(nbk, bk, + lambda p, i: UnShiftB(nal + aother, p + bother, i, z), + lambda p, i: ShiftB(p[i])) + + for r in sorted(list(abuckets.keys()) + list(bbuckets.keys()), key=default_sort_key): + al = () + nal = () + bk = () + nbk = () + if r in abuckets: + al = abuckets[r] + nal = nabuckets[r] + if r in bbuckets: + bk = bbuckets[r] + nbk = nbbuckets[r] + if len(al) != len(nal) or len(bk) != len(nbk): + raise ValueError('%s not reachable from %s' % (target, origin)) + + al, nal, bk, nbk = [sorted(w, key=default_sort_key) + for w in [al, nal, bk, nbk]] + + def others(dic, key): + l = [] + for k in dic: + if k != key: + l.extend(dic[k]) + return l + aother = others(nabuckets, r) + bother = others(nbbuckets, r) + + if len(al) == 0: + # there can be no complications, just shift the bs as we please + ops += do_shifts_b([], nbk, bk, aother, bother) + elif len(bk) == 0: + # there can be no complications, just shift the as as we please + ops += do_shifts_a(nal, [], al, aother, bother) + else: + namax = nal[-1] + amax = al[-1] + + if nbk[0] - namax <= 0 or bk[0] - amax <= 0: + raise ValueError('Non-suitable parameters.') + + if namax - amax > 0: + # we are going to shift down - first do the as, then the bs + ops += do_shifts_a(nal, nbk, al, aother, bother) + ops += do_shifts_b(al, nbk, bk, aother, bother) + else: + # we are going to shift up - first do the bs, then the as + ops += do_shifts_b(nal, nbk, bk, aother, bother) + ops += do_shifts_a(nal, bk, al, aother, bother) + + nabuckets[r] = al + nbbuckets[r] = bk + + ops.reverse() + return ops + + +def try_shifted_sum(func, z): + """ Try to recognise a hypergeometric sum that starts from k > 0. """ + abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) + if len(abuckets[S.Zero]) != 1: + return None + r = abuckets[S.Zero][0] + if r <= 0: + return None + if S.Zero not in bbuckets: + return None + l = list(bbuckets[S.Zero]) + l.sort() + k = l[0] + if k <= 0: + return None + + nap = list(func.ap) + nap.remove(r) + nbq = list(func.bq) + nbq.remove(k) + k -= 1 + nap = [x - k for x in nap] + nbq = [x - k for x in nbq] + + ops = [] + for n in range(r - 1): + ops.append(ShiftA(n + 1)) + ops.reverse() + + fac = factorial(k)/z**k + fac *= Mul(*[rf(b, k) for b in nbq]) + fac /= Mul(*[rf(a, k) for a in nap]) + + ops += [MultOperator(fac)] + + p = 0 + for n in range(k): + m = z**n/factorial(n) + m *= Mul(*[rf(a, n) for a in nap]) + m /= Mul(*[rf(b, n) for b in nbq]) + p += m + + return Hyper_Function(nap, nbq), ops, -p + + +def try_polynomial(func, z): + """ Recognise polynomial cases. Returns None if not such a case. + Requires order to be fully reduced. """ + abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) + a0 = abuckets[S.Zero] + b0 = bbuckets[S.Zero] + a0.sort() + b0.sort() + al0 = [x for x in a0 if x <= 0] + bl0 = [x for x in b0 if x <= 0] + + if bl0 and all(a < bl0[-1] for a in al0): + return oo + if not al0: + return None + + a = al0[-1] + fac = 1 + res = S.One + for n in Tuple(*list(range(-a))): + fac *= z + fac /= n + 1 + fac *= Mul(*[a + n for a in func.ap]) + fac /= Mul(*[b + n for b in func.bq]) + res += fac + return res + + +def try_lerchphi(func): + """ + Try to find an expression for Hyper_Function ``func`` in terms of Lerch + Transcendents. + + Return None if no such expression can be found. + """ + # This is actually quite simple, and is described in Roach's paper, + # section 18. + # We don't need to implement the reduction to polylog here, this + # is handled by expand_func. + + # First we need to figure out if the summation coefficient is a rational + # function of the summation index, and construct that rational function. + abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) + + paired = {} + for key, value in abuckets.items(): + if key != 0 and key not in bbuckets: + return None + bvalue = bbuckets[key] + paired[key] = (list(value), list(bvalue)) + bbuckets.pop(key, None) + if bbuckets != {}: + return None + if S.Zero not in abuckets: + return None + aints, bints = paired[S.Zero] + # Account for the additional n! in denominator + paired[S.Zero] = (aints, bints + [1]) + + t = Dummy('t') + numer = S.One + denom = S.One + for key, (avalue, bvalue) in paired.items(): + if len(avalue) != len(bvalue): + return None + # Note that since order has been reduced fully, all the b are + # bigger than all the a they differ from by an integer. In particular + # if there are any negative b left, this function is not well-defined. + for a, b in zip(avalue, bvalue): + if (a - b).is_positive: + k = a - b + numer *= rf(b + t, k) + denom *= rf(b, k) + else: + k = b - a + numer *= rf(a, k) + denom *= rf(a + t, k) + + # Now do a partial fraction decomposition. + # We assemble two structures: a list monomials of pairs (a, b) representing + # a*t**b (b a non-negative integer), and a dict terms, where + # terms[a] = [(b, c)] means that there is a term b/(t-a)**c. + part = apart(numer/denom, t) + args = Add.make_args(part) + monomials = [] + terms = {} + for arg in args: + numer, denom = arg.as_numer_denom() + if not denom.has(t): + p = Poly(numer, t) + if not p.is_monomial: + raise TypeError("p should be monomial") + ((b, ), a) = p.LT() + monomials += [(a/denom, b)] + continue + if numer.has(t): + raise NotImplementedError('Need partial fraction decomposition' + ' with linear denominators') + indep, [dep] = denom.as_coeff_mul(t) + n = 1 + if dep.is_Pow: + n = dep.exp + dep = dep.base + if dep == t: + a = 0 + elif dep.is_Add: + a, tmp = dep.as_independent(t) + b = 1 + if tmp != t: + b, _ = tmp.as_independent(t) + if dep != b*t + a: + raise NotImplementedError('unrecognised form %s' % dep) + a /= b + indep *= b**n + else: + raise NotImplementedError('unrecognised form of partial fraction') + terms.setdefault(a, []).append((numer/indep, n)) + + # Now that we have this information, assemble our formula. All the + # monomials yield rational functions and go into one basis element. + # The terms[a] are related by differentiation. If the largest exponent is + # n, we need lerchphi(z, k, a) for k = 1, 2, ..., n. + # deriv maps a basis to its derivative, expressed as a C(z)-linear + # combination of other basis elements. + deriv = {} + coeffs = {} + z = Dummy('z') + monomials.sort(key=lambda x: x[1]) + mon = {0: 1/(1 - z)} + if monomials: + for k in range(monomials[-1][1]): + mon[k + 1] = z*mon[k].diff(z) + for a, n in monomials: + coeffs.setdefault(S.One, []).append(a*mon[n]) + for a, l in terms.items(): + for c, k in l: + coeffs.setdefault(lerchphi(z, k, a), []).append(c) + l.sort(key=lambda x: x[1]) + for k in range(2, l[-1][1] + 1): + deriv[lerchphi(z, k, a)] = [(-a, lerchphi(z, k, a)), + (1, lerchphi(z, k - 1, a))] + deriv[lerchphi(z, 1, a)] = [(-a, lerchphi(z, 1, a)), + (1/(1 - z), S.One)] + trans = {} + for n, b in enumerate([S.One] + list(deriv.keys())): + trans[b] = n + basis = [expand_func(b) for (b, _) in sorted(trans.items(), + key=lambda x:x[1])] + B = Matrix(basis) + C = Matrix([[0]*len(B)]) + for b, c in coeffs.items(): + C[trans[b]] = Add(*c) + M = zeros(len(B)) + for b, l in deriv.items(): + for c, b2 in l: + M[trans[b], trans[b2]] = c + return Formula(func, z, None, [], B, C, M) + + +def build_hypergeometric_formula(func): + """ + Create a formula object representing the hypergeometric function ``func``. + + """ + # We know that no `ap` are negative integers, otherwise "detect poly" + # would have kicked in. However, `ap` could be empty. In this case we can + # use a different basis. + # I'm not aware of a basis that works in all cases. + z = Dummy('z') + if func.ap: + afactors = [_x + a for a in func.ap] + bfactors = [_x + b - 1 for b in func.bq] + expr = _x*Mul(*bfactors) - z*Mul(*afactors) + poly = Poly(expr, _x) + n = poly.degree() + basis = [] + M = zeros(n) + for k in range(n): + a = func.ap[0] + k + basis += [hyper([a] + list(func.ap[1:]), func.bq, z)] + if k < n - 1: + M[k, k] = -a + M[k, k + 1] = a + B = Matrix(basis) + C = Matrix([[1] + [0]*(n - 1)]) + derivs = [eye(n)] + for k in range(n): + derivs.append(M*derivs[k]) + l = poly.all_coeffs() + l.reverse() + res = [0]*n + for k, c in enumerate(l): + for r, d in enumerate(C*derivs[k]): + res[r] += c*d + for k, c in enumerate(res): + M[n - 1, k] = -c/derivs[n - 1][0, n - 1]/poly.all_coeffs()[0] + return Formula(func, z, None, [], B, C, M) + else: + # Since there are no `ap`, none of the `bq` can be non-positive + # integers. + basis = [] + bq = list(func.bq[:]) + for i in range(len(bq)): + basis += [hyper([], bq, z)] + bq[i] += 1 + basis += [hyper([], bq, z)] + B = Matrix(basis) + n = len(B) + C = Matrix([[1] + [0]*(n - 1)]) + M = zeros(n) + M[0, n - 1] = z/Mul(*func.bq) + for k in range(1, n): + M[k, k - 1] = func.bq[k - 1] + M[k, k] = -func.bq[k - 1] + return Formula(func, z, None, [], B, C, M) + + +def hyperexpand_special(ap, bq, z): + """ + Try to find a closed-form expression for hyper(ap, bq, z), where ``z`` + is supposed to be a "special" value, e.g. 1. + + This function tries various of the classical summation formulae + (Gauss, Saalschuetz, etc). + """ + # This code is very ad-hoc. There are many clever algorithms + # (notably Zeilberger's) related to this problem. + # For now we just want a few simple cases to work. + p, q = len(ap), len(bq) + z_ = z + z = unpolarify(z) + if z == 0: + return S.One + from sympy.simplify.simplify import simplify + if p == 2 and q == 1: + # 2F1 + a, b, c = ap + bq + if z == 1: + # Gauss + return gamma(c - a - b)*gamma(c)/gamma(c - a)/gamma(c - b) + if z == -1 and simplify(b - a + c) == 1: + b, a = a, b + if z == -1 and simplify(a - b + c) == 1: + # Kummer + if b.is_integer and b.is_negative: + return 2*cos(pi*b/2)*gamma(-b)*gamma(b - a + 1) \ + /gamma(-b/2)/gamma(b/2 - a + 1) + else: + return gamma(b/2 + 1)*gamma(b - a + 1) \ + /gamma(b + 1)/gamma(b/2 - a + 1) + # TODO tons of more formulae + # investigate what algorithms exist + return hyper(ap, bq, z_) + +_collection = None + + +def _hyperexpand(func, z, ops0=[], z0=Dummy('z0'), premult=1, prem=0, + rewrite='default'): + """ + Try to find an expression for the hypergeometric function ``func``. + + Explanation + =========== + + The result is expressed in terms of a dummy variable ``z0``. Then it + is multiplied by ``premult``. Then ``ops0`` is applied. + ``premult`` must be a*z**prem for some a independent of ``z``. + """ + + if z.is_zero: + return S.One + + from sympy.simplify.simplify import simplify + + z = polarify(z, subs=False) + if rewrite == 'default': + rewrite = 'nonrepsmall' + + def carryout_plan(f, ops): + C = apply_operators(f.C.subs(f.z, z0), ops, + make_derivative_operator(f.M.subs(f.z, z0), z0)) + C = apply_operators(C, ops0, + make_derivative_operator(f.M.subs(f.z, z0) + + prem*eye(f.M.shape[0]), z0)) + + if premult == 1: + C = C.applyfunc(make_simp(z0)) + r = reduce(lambda s,m: s+m[0]*m[1], zip(C, f.B.subs(f.z, z0)), S.Zero)*premult + res = r.subs(z0, z) + if rewrite: + res = res.rewrite(rewrite) + return res + + # TODO + # The following would be possible: + # *) PFD Duplication (see Kelly Roach's paper) + # *) In a similar spirit, try_lerchphi() can be generalised considerably. + + global _collection + if _collection is None: + _collection = FormulaCollection() + + debug('Trying to expand hypergeometric function ', func) + + # First reduce order as much as possible. + func, ops = reduce_order(func) + if ops: + debug(' Reduced order to ', func) + else: + debug(' Could not reduce order.') + + # Now try polynomial cases + res = try_polynomial(func, z0) + if res is not None: + debug(' Recognised polynomial.') + p = apply_operators(res, ops, lambda f: z0*f.diff(z0)) + p = apply_operators(p*premult, ops0, lambda f: z0*f.diff(z0)) + return unpolarify(simplify(p).subs(z0, z)) + + # Try to recognise a shifted sum. + p = S.Zero + res = try_shifted_sum(func, z0) + if res is not None: + func, nops, p = res + debug(' Recognised shifted sum, reduced order to ', func) + ops += nops + + # apply the plan for poly + p = apply_operators(p, ops, lambda f: z0*f.diff(z0)) + p = apply_operators(p*premult, ops0, lambda f: z0*f.diff(z0)) + p = simplify(p).subs(z0, z) + + # Try special expansions early. + if unpolarify(z) in [1, -1] and (len(func.ap), len(func.bq)) == (2, 1): + f = build_hypergeometric_formula(func) + r = carryout_plan(f, ops).replace(hyper, hyperexpand_special) + if not r.has(hyper): + return r + p + + # Try to find a formula in our collection + formula = _collection.lookup_origin(func) + + # Now try a lerch phi formula + if formula is None: + formula = try_lerchphi(func) + + if formula is None: + debug(' Could not find an origin. ', + 'Will return answer in terms of ' + 'simpler hypergeometric functions.') + formula = build_hypergeometric_formula(func) + + debug(' Found an origin: ', formula.closed_form, ' ', formula.func) + + # We need to find the operators that convert formula into func. + ops += devise_plan(func, formula.func, z0) + + # Now carry out the plan. + r = carryout_plan(formula, ops) + p + + return powdenest(r, polar=True).replace(hyper, hyperexpand_special) + + +def devise_plan_meijer(fro, to, z): + """ + Find operators to convert G-function ``fro`` into G-function ``to``. + + Explanation + =========== + + It is assumed that ``fro`` and ``to`` have the same signatures, and that in fact + any corresponding pair of parameters differs by integers, and a direct path + is possible. I.e. if there are parameters a1 b1 c1 and a2 b2 c2 it is + assumed that a1 can be shifted to a2, etc. The only thing this routine + determines is the order of shifts to apply, nothing clever will be tried. + It is also assumed that ``fro`` is suitable. + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import (devise_plan_meijer, + ... G_Function) + >>> from sympy.abc import z + + Empty plan: + + >>> devise_plan_meijer(G_Function([1], [2], [3], [4]), + ... G_Function([1], [2], [3], [4]), z) + [] + + Very simple plans: + + >>> devise_plan_meijer(G_Function([0], [], [], []), + ... G_Function([1], [], [], []), z) + [] + >>> devise_plan_meijer(G_Function([0], [], [], []), + ... G_Function([-1], [], [], []), z) + [] + >>> devise_plan_meijer(G_Function([], [1], [], []), + ... G_Function([], [2], [], []), z) + [] + + Slightly more complicated plans: + + >>> devise_plan_meijer(G_Function([0], [], [], []), + ... G_Function([2], [], [], []), z) + [, + ] + >>> devise_plan_meijer(G_Function([0], [], [0], []), + ... G_Function([-1], [], [1], []), z) + [, ] + + Order matters: + + >>> devise_plan_meijer(G_Function([0], [], [0], []), + ... G_Function([1], [], [1], []), z) + [, ] + """ + # TODO for now, we use the following simple heuristic: inverse-shift + # when possible, shift otherwise. Give up if we cannot make progress. + + def try_shift(f, t, shifter, diff, counter): + """ Try to apply ``shifter`` in order to bring some element in ``f`` + nearer to its counterpart in ``to``. ``diff`` is +/- 1 and + determines the effect of ``shifter``. Counter is a list of elements + blocking the shift. + + Return an operator if change was possible, else None. + """ + for idx, (a, b) in enumerate(zip(f, t)): + if ( + (a - b).is_integer and (b - a)/diff > 0 and + all(a != x for x in counter)): + sh = shifter(idx) + f[idx] += diff + return sh + fan = list(fro.an) + fap = list(fro.ap) + fbm = list(fro.bm) + fbq = list(fro.bq) + ops = [] + change = True + while change: + change = False + op = try_shift(fan, to.an, + lambda i: MeijerUnShiftB(fan, fap, fbm, fbq, i, z), + 1, fbm + fbq) + if op is not None: + ops += [op] + change = True + continue + op = try_shift(fap, to.ap, + lambda i: MeijerUnShiftD(fan, fap, fbm, fbq, i, z), + 1, fbm + fbq) + if op is not None: + ops += [op] + change = True + continue + op = try_shift(fbm, to.bm, + lambda i: MeijerUnShiftA(fan, fap, fbm, fbq, i, z), + -1, fan + fap) + if op is not None: + ops += [op] + change = True + continue + op = try_shift(fbq, to.bq, + lambda i: MeijerUnShiftC(fan, fap, fbm, fbq, i, z), + -1, fan + fap) + if op is not None: + ops += [op] + change = True + continue + op = try_shift(fan, to.an, lambda i: MeijerShiftB(fan[i]), -1, []) + if op is not None: + ops += [op] + change = True + continue + op = try_shift(fap, to.ap, lambda i: MeijerShiftD(fap[i]), -1, []) + if op is not None: + ops += [op] + change = True + continue + op = try_shift(fbm, to.bm, lambda i: MeijerShiftA(fbm[i]), 1, []) + if op is not None: + ops += [op] + change = True + continue + op = try_shift(fbq, to.bq, lambda i: MeijerShiftC(fbq[i]), 1, []) + if op is not None: + ops += [op] + change = True + continue + if fan != list(to.an) or fap != list(to.ap) or fbm != list(to.bm) or \ + fbq != list(to.bq): + raise NotImplementedError('Could not devise plan.') + ops.reverse() + return ops + +_meijercollection = None + + +def _meijergexpand(func, z0, allow_hyper=False, rewrite='default', + place=None): + """ + Try to find an expression for the Meijer G function specified + by the G_Function ``func``. If ``allow_hyper`` is True, then returning + an expression in terms of hypergeometric functions is allowed. + + Currently this just does Slater's theorem. + If expansions exist both at zero and at infinity, ``place`` + can be set to ``0`` or ``zoo`` for the preferred choice. + """ + global _meijercollection + if _meijercollection is None: + _meijercollection = MeijerFormulaCollection() + if rewrite == 'default': + rewrite = None + + func0 = func + debug('Try to expand Meijer G function corresponding to ', func) + + # We will play games with analytic continuation - rather use a fresh symbol + z = Dummy('z') + + func, ops = reduce_order_meijer(func) + if ops: + debug(' Reduced order to ', func) + else: + debug(' Could not reduce order.') + + # Try to find a direct formula + f = _meijercollection.lookup_origin(func) + if f is not None: + debug(' Found a Meijer G formula: ', f.func) + ops += devise_plan_meijer(f.func, func, z) + + # Now carry out the plan. + C = apply_operators(f.C.subs(f.z, z), ops, + make_derivative_operator(f.M.subs(f.z, z), z)) + + C = C.applyfunc(make_simp(z)) + r = C*f.B.subs(f.z, z) + r = r[0].subs(z, z0) + return powdenest(r, polar=True) + + debug(" Could not find a direct formula. Trying Slater's theorem.") + + # TODO the following would be possible: + # *) Paired Index Theorems + # *) PFD Duplication + # (See Kelly Roach's paper for details on either.) + # + # TODO Also, we tend to create combinations of gamma functions that can be + # simplified. + + def can_do(pbm, pap): + """ Test if slater applies. """ + for i in pbm: + if len(pbm[i]) > 1: + l = 0 + if i in pap: + l = len(pap[i]) + if l + 1 < len(pbm[i]): + return False + return True + + def do_slater(an, bm, ap, bq, z, zfinal): + # zfinal is the value that will eventually be substituted for z. + # We pass it to _hyperexpand to improve performance. + func = G_Function(an, bm, ap, bq) + _, pbm, pap, _ = func.compute_buckets() + if not can_do(pbm, pap): + return S.Zero, False + + cond = len(an) + len(ap) < len(bm) + len(bq) + if len(an) + len(ap) == len(bm) + len(bq): + cond = abs(z) < 1 + if cond is False: + return S.Zero, False + + res = S.Zero + for m in pbm: + if len(pbm[m]) == 1: + bh = pbm[m][0] + fac = 1 + bo = list(bm) + bo.remove(bh) + for bj in bo: + fac *= gamma(bj - bh) + for aj in an: + fac *= gamma(1 + bh - aj) + for bj in bq: + fac /= gamma(1 + bh - bj) + for aj in ap: + fac /= gamma(aj - bh) + nap = [1 + bh - a for a in list(an) + list(ap)] + nbq = [1 + bh - b for b in list(bo) + list(bq)] + + k = polar_lift(S.NegativeOne**(len(ap) - len(bm))) + harg = k*zfinal + # NOTE even though k "is" +-1, this has to be t/k instead of + # t*k ... we are using polar numbers for consistency! + premult = (t/k)**bh + hyp = _hyperexpand(Hyper_Function(nap, nbq), harg, ops, + t, premult, bh, rewrite=None) + res += fac * hyp + else: + b_ = pbm[m][0] + ki = [bi - b_ for bi in pbm[m][1:]] + u = len(ki) + li = [ai - b_ for ai in pap[m][:u + 1]] + bo = list(bm) + for b in pbm[m]: + bo.remove(b) + ao = list(ap) + for a in pap[m][:u]: + ao.remove(a) + lu = li[-1] + di = [l - k for (l, k) in zip(li, ki)] + + # We first work out the integrand: + s = Dummy('s') + integrand = z**s + for b in bm: + if not Mod(b, 1) and b.is_Number: + b = int(round(b)) + integrand *= gamma(b - s) + for a in an: + integrand *= gamma(1 - a + s) + for b in bq: + integrand /= gamma(1 - b + s) + for a in ap: + integrand /= gamma(a - s) + + # Now sum the finitely many residues: + # XXX This speeds up some cases - is it a good idea? + integrand = expand_func(integrand) + for r in range(int(round(lu))): + resid = residue(integrand, s, b_ + r) + resid = apply_operators(resid, ops, lambda f: z*f.diff(z)) + res -= resid + + # Now the hypergeometric term. + au = b_ + lu + k = polar_lift(S.NegativeOne**(len(ao) + len(bo) + 1)) + harg = k*zfinal + premult = (t/k)**au + nap = [1 + au - a for a in list(an) + list(ap)] + [1] + nbq = [1 + au - b for b in list(bm) + list(bq)] + + hyp = _hyperexpand(Hyper_Function(nap, nbq), harg, ops, + t, premult, au, rewrite=None) + + C = S.NegativeOne**(lu)/factorial(lu) + for i in range(u): + C *= S.NegativeOne**di[i]/rf(lu - li[i] + 1, di[i]) + for a in an: + C *= gamma(1 - a + au) + for b in bo: + C *= gamma(b - au) + for a in ao: + C /= gamma(a - au) + for b in bq: + C /= gamma(1 - b + au) + + res += C*hyp + + return res, cond + + t = Dummy('t') + slater1, cond1 = do_slater(func.an, func.bm, func.ap, func.bq, z, z0) + + def tr(l): + return [1 - x for x in l] + + for op in ops: + op._poly = Poly(op._poly.subs({z: 1/t, _x: -_x}), _x) + slater2, cond2 = do_slater(tr(func.bm), tr(func.an), tr(func.bq), tr(func.ap), + t, 1/z0) + + slater1 = powdenest(slater1.subs(z, z0), polar=True) + slater2 = powdenest(slater2.subs(t, 1/z0), polar=True) + if not isinstance(cond2, bool): + cond2 = cond2.subs(t, 1/z) + + m = func(z) + if m.delta > 0 or \ + (m.delta == 0 and len(m.ap) == len(m.bq) and + (re(m.nu) < -1) is not False and polar_lift(z0) == polar_lift(1)): + # The condition delta > 0 means that the convergence region is + # connected. Any expression we find can be continued analytically + # to the entire convergence region. + # The conditions delta==0, p==q, re(nu) < -1 imply that G is continuous + # on the positive reals, so the values at z=1 agree. + if cond1 is not False: + cond1 = True + if cond2 is not False: + cond2 = True + + if cond1 is True: + slater1 = slater1.rewrite(rewrite or 'nonrep') + else: + slater1 = slater1.rewrite(rewrite or 'nonrepsmall') + if cond2 is True: + slater2 = slater2.rewrite(rewrite or 'nonrep') + else: + slater2 = slater2.rewrite(rewrite or 'nonrepsmall') + + if cond1 is not False and cond2 is not False: + # If one condition is False, there is no choice. + if place == 0: + cond2 = False + if place == zoo: + cond1 = False + + if not isinstance(cond1, bool): + cond1 = cond1.subs(z, z0) + if not isinstance(cond2, bool): + cond2 = cond2.subs(z, z0) + + def weight(expr, cond): + if cond is True: + c0 = 0 + elif cond is False: + c0 = 1 + else: + c0 = 2 + if expr.has(oo, zoo, -oo, nan): + # XXX this actually should not happen, but consider + # S('meijerg(((0, -1/2, 0, -1/2, 1/2), ()), ((0,), + # (-1/2, -1/2, -1/2, -1)), exp_polar(I*pi))/4') + c0 = 3 + return (c0, expr.count(hyper), expr.count_ops()) + + w1 = weight(slater1, cond1) + w2 = weight(slater2, cond2) + if min(w1, w2) <= (0, 1, oo): + if w1 < w2: + return slater1 + else: + return slater2 + if max(w1[0], w2[0]) <= 1 and max(w1[1], w2[1]) <= 1: + return Piecewise((slater1, cond1), (slater2, cond2), (func0(z0), True)) + + # We couldn't find an expression without hypergeometric functions. + # TODO it would be helpful to give conditions under which the integral + # is known to diverge. + r = Piecewise((slater1, cond1), (slater2, cond2), (func0(z0), True)) + if r.has(hyper) and not allow_hyper: + debug(' Could express using hypergeometric functions, ' + 'but not allowed.') + if not r.has(hyper) or allow_hyper: + return r + + return func0(z0) + + +def hyperexpand(f, allow_hyper=False, rewrite='default', place=None): + """ + Expand hypergeometric functions. If allow_hyper is True, allow partial + simplification (that is a result different from input, + but still containing hypergeometric functions). + + If a G-function has expansions both at zero and at infinity, + ``place`` can be set to ``0`` or ``zoo`` to indicate the + preferred choice. + + Examples + ======== + + >>> from sympy.simplify.hyperexpand import hyperexpand + >>> from sympy.functions import hyper + >>> from sympy.abc import z + >>> hyperexpand(hyper([], [], z)) + exp(z) + + Non-hyperegeometric parts of the expression and hypergeometric expressions + that are not recognised are left unchanged: + + >>> hyperexpand(1 + hyper([1, 1, 1], [], z)) + hyper((1, 1, 1), (), z) + 1 + """ + f = sympify(f) + + def do_replace(ap, bq, z): + r = _hyperexpand(Hyper_Function(ap, bq), z, rewrite=rewrite) + if r is None: + return hyper(ap, bq, z) + else: + return r + + def do_meijer(ap, bq, z): + r = _meijergexpand(G_Function(ap[0], ap[1], bq[0], bq[1]), z, + allow_hyper, rewrite=rewrite, place=place) + if not r.has(nan, zoo, oo, -oo): + return r + return f.replace(hyper, do_replace).replace(meijerg, do_meijer) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/hyperexpand_doc.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/hyperexpand_doc.py new file mode 100644 index 0000000000000000000000000000000000000000..a18377f3aede5214036fbf628825536611001584 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/hyperexpand_doc.py @@ -0,0 +1,18 @@ +""" This module cooks up a docstring when imported. Its only purpose is to + be displayed in the sphinx documentation. """ + +from sympy.core.relational import Eq +from sympy.functions.special.hyper import hyper +from sympy.printing.latex import latex +from sympy.simplify.hyperexpand import FormulaCollection + +c = FormulaCollection() + +doc = "" + +for f in c.formulae: + obj = Eq(hyper(f.func.ap, f.func.bq, f.z), + f.closed_form.rewrite('nonrepsmall')) + doc += ".. math::\n %s\n" % latex(obj) + +__doc__ = doc diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/powsimp.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/powsimp.py new file mode 100644 index 0000000000000000000000000000000000000000..f72dfeb072e0d0d4737ace310eda5c2a3a082c16 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/powsimp.py @@ -0,0 +1,718 @@ +from collections import defaultdict +from functools import reduce +from math import prod + +from sympy.core.function import expand_log, count_ops, _coeff_isneg +from sympy.core import sympify, Basic, Dummy, S, Add, Mul, Pow, expand_mul, factor_terms +from sympy.core.sorting import ordered, default_sort_key +from sympy.core.numbers import Integer, Rational, equal_valued +from sympy.core.mul import _keep_coeff +from sympy.core.rules import Transform +from sympy.functions import exp_polar, exp, log, root, polarify, unpolarify +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.polys import lcm, gcd +from sympy.ntheory.factor_ import multiplicity + + + +def powsimp(expr, deep=False, combine='all', force=False, measure=count_ops): + """ + Reduce expression by combining powers with similar bases and exponents. + + Explanation + =========== + + If ``deep`` is ``True`` then powsimp() will also simplify arguments of + functions. By default ``deep`` is set to ``False``. + + If ``force`` is ``True`` then bases will be combined without checking for + assumptions, e.g. sqrt(x)*sqrt(y) -> sqrt(x*y) which is not true + if x and y are both negative. + + You can make powsimp() only combine bases or only combine exponents by + changing combine='base' or combine='exp'. By default, combine='all', + which does both. combine='base' will only combine:: + + a a a 2x x + x * y => (x*y) as well as things like 2 => 4 + + and combine='exp' will only combine + :: + + a b (a + b) + x * x => x + + combine='exp' will strictly only combine exponents in the way that used + to be automatic. Also use deep=True if you need the old behavior. + + When combine='all', 'exp' is evaluated first. Consider the first + example below for when there could be an ambiguity relating to this. + This is done so things like the second example can be completely + combined. If you want 'base' combined first, do something like + powsimp(powsimp(expr, combine='base'), combine='exp'). + + Examples + ======== + + >>> from sympy import powsimp, exp, log, symbols + >>> from sympy.abc import x, y, z, n + >>> powsimp(x**y*x**z*y**z, combine='all') + x**(y + z)*y**z + >>> powsimp(x**y*x**z*y**z, combine='exp') + x**(y + z)*y**z + >>> powsimp(x**y*x**z*y**z, combine='base', force=True) + x**y*(x*y)**z + + >>> powsimp(x**z*x**y*n**z*n**y, combine='all', force=True) + (n*x)**(y + z) + >>> powsimp(x**z*x**y*n**z*n**y, combine='exp') + n**(y + z)*x**(y + z) + >>> powsimp(x**z*x**y*n**z*n**y, combine='base', force=True) + (n*x)**y*(n*x)**z + + >>> x, y = symbols('x y', positive=True) + >>> powsimp(log(exp(x)*exp(y))) + log(exp(x)*exp(y)) + >>> powsimp(log(exp(x)*exp(y)), deep=True) + x + y + + Radicals with Mul bases will be combined if combine='exp' + + >>> from sympy import sqrt + >>> x, y = symbols('x y') + + Two radicals are automatically joined through Mul: + + >>> a=sqrt(x*sqrt(y)) + >>> a*a**3 == a**4 + True + + But if an integer power of that radical has been + autoexpanded then Mul does not join the resulting factors: + + >>> a**4 # auto expands to a Mul, no longer a Pow + x**2*y + >>> _*a # so Mul doesn't combine them + x**2*y*sqrt(x*sqrt(y)) + >>> powsimp(_) # but powsimp will + (x*sqrt(y))**(5/2) + >>> powsimp(x*y*a) # but won't when doing so would violate assumptions + x*y*sqrt(x*sqrt(y)) + + """ + def recurse(arg, **kwargs): + _deep = kwargs.get('deep', deep) + _combine = kwargs.get('combine', combine) + _force = kwargs.get('force', force) + _measure = kwargs.get('measure', measure) + return powsimp(arg, _deep, _combine, _force, _measure) + + expr = sympify(expr) + + if (not isinstance(expr, Basic) or isinstance(expr, MatrixSymbol) or ( + expr.is_Atom or expr in (exp_polar(0), exp_polar(1)))): + return expr + + if deep or expr.is_Add or expr.is_Mul and _y not in expr.args: + expr = expr.func(*[recurse(w) for w in expr.args]) + + if expr.is_Pow: + return recurse(expr*_y, deep=False)/_y + + if not expr.is_Mul: + return expr + + # handle the Mul + if combine in ('exp', 'all'): + # Collect base/exp data, while maintaining order in the + # non-commutative parts of the product + c_powers = defaultdict(list) + nc_part = [] + newexpr = [] + coeff = S.One + for term in expr.args: + if term.is_Rational: + coeff *= term + continue + if term.is_Pow: + term = _denest_pow(term) + if term.is_commutative: + b, e = term.as_base_exp() + if deep: + b, e = [recurse(i) for i in [b, e]] + if b.is_Pow or isinstance(b, exp): + # don't let smthg like sqrt(x**a) split into x**a, 1/2 + # or else it will be joined as x**(a/2) later + b, e = b**e, S.One + c_powers[b].append(e) + else: + # This is the logic that combines exponents for equal, + # but non-commutative bases: A**x*A**y == A**(x+y). + if nc_part: + b1, e1 = nc_part[-1].as_base_exp() + b2, e2 = term.as_base_exp() + if (b1 == b2 and + e1.is_commutative and e2.is_commutative): + nc_part[-1] = Pow(b1, Add(e1, e2)) + continue + nc_part.append(term) + + # add up exponents of common bases + for b, e in ordered(iter(c_powers.items())): + # allow 2**x/4 -> 2**(x - 2); don't do this when b and e are + # Numbers since autoevaluation will undo it, e.g. + # 2**(1/3)/4 -> 2**(1/3 - 2) -> 2**(1/3)/4 + if (b and b.is_Rational and not all(ei.is_Number for ei in e) and \ + coeff is not S.One and + b not in (S.One, S.NegativeOne)): + m = multiplicity(abs(b), abs(coeff)) + if m: + e.append(m) + coeff /= b**m + c_powers[b] = Add(*e) + if coeff is not S.One: + if coeff in c_powers: + c_powers[coeff] += S.One + else: + c_powers[coeff] = S.One + + # convert to plain dictionary + c_powers = dict(c_powers) + + # check for base and inverted base pairs + be = list(c_powers.items()) + skip = set() # skip if we already saw them + for b, e in be: + if b in skip: + continue + bpos = b.is_positive or b.is_polar + if bpos: + binv = 1/b + #Special case for float 1 + if b.is_Float and equal_valued(b, 1): + c_powers[b] = S.One + continue + if b != binv and binv in c_powers: + if b.as_numer_denom()[0] is S.One: + c_powers.pop(b) + c_powers[binv] -= e + else: + skip.add(binv) + e = c_powers.pop(binv) + c_powers[b] -= e + + # check for base and negated base pairs + be = list(c_powers.items()) + _n = S.NegativeOne + for b, e in be: + if (b.is_Symbol or b.is_Add) and -b in c_powers and b in c_powers: + if (b.is_positive is not None or e.is_integer): + if e.is_integer or b.is_negative: + c_powers[-b] += c_powers.pop(b) + else: # (-b).is_positive so use its e + e = c_powers.pop(-b) + c_powers[b] += e + if _n in c_powers: + c_powers[_n] += e + else: + c_powers[_n] = e + + # filter c_powers and convert to a list + c_powers = [(b, e) for b, e in c_powers.items() if e] + + # ============================================================== + # check for Mul bases of Rational powers that can be combined with + # separated bases, e.g. x*sqrt(x*y)*sqrt(x*sqrt(x*y)) -> + # (x*sqrt(x*y))**(3/2) + # ---------------- helper functions + + def ratq(x): + '''Return Rational part of x's exponent as it appears in the bkey. + ''' + return bkey(x)[0][1] + + def bkey(b, e=None): + '''Return (b**s, c.q), c.p where e -> c*s. If e is not given then + it will be taken by using as_base_exp() on the input b. + e.g. + x**3/2 -> (x, 2), 3 + x**y -> (x**y, 1), 1 + x**(2*y/3) -> (x**y, 3), 2 + exp(x/2) -> (exp(a), 2), 1 + + ''' + if e is not None: # coming from c_powers or from below + if e.is_Integer: + return (b, S.One), e + elif e.is_Rational: + return (b, Integer(e.q)), Integer(e.p) + else: + c, m = e.as_coeff_Mul(rational=True) + if c is not S.One: + if m.is_integer: + return (b, Integer(c.q)), m*Integer(c.p) + return (b**m, Integer(c.q)), Integer(c.p) + else: + return (b**e, S.One), S.One + else: + return bkey(*b.as_base_exp()) + + def update(b): + '''Decide what to do with base, b. If its exponent is now an + integer multiple of the Rational denominator, then remove it + and put the factors of its base in the common_b dictionary or + update the existing bases if necessary. If it has been zeroed + out, simply remove the base. + ''' + newe, r = divmod(common_b[b], b[1]) + if not r: + common_b.pop(b) + if newe: + for m in Mul.make_args(b[0]**newe): + b, e = bkey(m) + if b not in common_b: + common_b[b] = 0 + common_b[b] += e + if b[1] != 1: + bases.append(b) + # ---------------- end of helper functions + + # assemble a dictionary of the factors having a Rational power + common_b = {} + done = [] + bases = [] + for b, e in c_powers: + b, e = bkey(b, e) + if b in common_b: + common_b[b] = common_b[b] + e + else: + common_b[b] = e + if b[1] != 1 and b[0].is_Mul: + bases.append(b) + bases.sort(key=default_sort_key) # this makes tie-breaking canonical + bases.sort(key=measure, reverse=True) # handle longest first + for base in bases: + if base not in common_b: # it may have been removed already + continue + b, exponent = base + last = False # True when no factor of base is a radical + qlcm = 1 # the lcm of the radical denominators + while True: + bstart = b + qstart = qlcm + + bb = [] # list of factors + ee = [] # (factor's expo. and it's current value in common_b) + for bi in Mul.make_args(b): + bib, bie = bkey(bi) + if bib not in common_b or common_b[bib] < bie: + ee = bb = [] # failed + break + ee.append([bie, common_b[bib]]) + bb.append(bib) + if ee: + # find the number of integral extractions possible + # e.g. [(1, 2), (2, 2)] -> min(2/1, 2/2) -> 1 + min1 = ee[0][1]//ee[0][0] + for i in range(1, len(ee)): + rat = ee[i][1]//ee[i][0] + if rat < 1: + break + min1 = min(min1, rat) + else: + # update base factor counts + # e.g. if ee = [(2, 5), (3, 6)] then min1 = 2 + # and the new base counts will be 5-2*2 and 6-2*3 + for i in range(len(bb)): + common_b[bb[i]] -= min1*ee[i][0] + update(bb[i]) + # update the count of the base + # e.g. x**2*y*sqrt(x*sqrt(y)) the count of x*sqrt(y) + # will increase by 4 to give bkey (x*sqrt(y), 2, 5) + common_b[base] += min1*qstart*exponent + if (last # no more radicals in base + or len(common_b) == 1 # nothing left to join with + or all(k[1] == 1 for k in common_b) # no rad's in common_b + ): + break + # see what we can exponentiate base by to remove any radicals + # so we know what to search for + # e.g. if base were x**(1/2)*y**(1/3) then we should + # exponentiate by 6 and look for powers of x and y in the ratio + # of 2 to 3 + qlcm = lcm([ratq(bi) for bi in Mul.make_args(bstart)]) + if qlcm == 1: + break # we are done + b = bstart**qlcm + qlcm *= qstart + if all(ratq(bi) == 1 for bi in Mul.make_args(b)): + last = True # we are going to be done after this next pass + # this base no longer can find anything to join with and + # since it was longer than any other we are done with it + b, q = base + done.append((b, common_b.pop(base)*Rational(1, q))) + + # update c_powers and get ready to continue with powsimp + c_powers = done + # there may be terms still in common_b that were bases that were + # identified as needing processing, so remove those, too + for (b, q), e in common_b.items(): + if (b.is_Pow or isinstance(b, exp)) and \ + q is not S.One and not b.exp.is_Rational: + b, be = b.as_base_exp() + b = b**(be/q) + else: + b = root(b, q) + c_powers.append((b, e)) + check = len(c_powers) + c_powers = dict(c_powers) + assert len(c_powers) == check # there should have been no duplicates + # ============================================================== + + # rebuild the expression + newexpr = expr.func(*(newexpr + [Pow(b, e) for b, e in c_powers.items()])) + if combine == 'exp': + return expr.func(newexpr, expr.func(*nc_part)) + else: + return recurse(expr.func(*nc_part), combine='base') * \ + recurse(newexpr, combine='base') + + elif combine == 'base': + + # Build c_powers and nc_part. These must both be lists not + # dicts because exp's are not combined. + c_powers = [] + nc_part = [] + for term in expr.args: + if term.is_commutative: + c_powers.append(list(term.as_base_exp())) + else: + nc_part.append(term) + + # Pull out numerical coefficients from exponent if assumptions allow + # e.g., 2**(2*x) => 4**x + for i in range(len(c_powers)): + b, e = c_powers[i] + if not (all(x.is_nonnegative for x in b.as_numer_denom()) or e.is_integer or force or b.is_polar): + continue + exp_c, exp_t = e.as_coeff_Mul(rational=True) + if exp_c is not S.One and exp_t is not S.One: + c_powers[i] = [Pow(b, exp_c), exp_t] + + # Combine bases whenever they have the same exponent and + # assumptions allow + # first gather the potential bases under the common exponent + c_exp = defaultdict(list) + for b, e in c_powers: + if deep: + e = recurse(e) + if e.is_Add and (b.is_positive or e.is_integer): + e = factor_terms(e) + if _coeff_isneg(e): + e = -e + b = 1/b + c_exp[e].append(b) + del c_powers + + # Merge back in the results of the above to form a new product + c_powers = defaultdict(list) + for e in c_exp: + bases = c_exp[e] + + # calculate the new base for e + + if len(bases) == 1: + new_base = bases[0] + elif e.is_integer or force: + new_base = expr.func(*bases) + else: + # see which ones can be joined + unk = [] + nonneg = [] + neg = [] + for bi in bases: + if bi.is_negative: + neg.append(bi) + elif bi.is_nonnegative: + nonneg.append(bi) + elif bi.is_polar: + nonneg.append( + bi) # polar can be treated like non-negative + else: + unk.append(bi) + if len(unk) == 1 and not neg or len(neg) == 1 and not unk: + # a single neg or a single unk can join the rest + nonneg.extend(unk + neg) + unk = neg = [] + elif neg: + # their negative signs cancel in groups of 2*q if we know + # that e = p/q else we have to treat them as unknown + israt = False + if e.is_Rational: + israt = True + else: + p, d = e.as_numer_denom() + if p.is_integer and d.is_integer: + israt = True + if israt: + neg = [-w for w in neg] + unk.extend([S.NegativeOne]*len(neg)) + else: + unk.extend(neg) + neg = [] + del israt + + # these shouldn't be joined + for b in unk: + c_powers[b].append(e) + # here is a new joined base + new_base = expr.func(*(nonneg + neg)) + # if there are positive parts they will just get separated + # again unless some change is made + + def _terms(e): + # return the number of terms of this expression + # when multiplied out -- assuming no joining of terms + if e.is_Add: + return sum(_terms(ai) for ai in e.args) + if e.is_Mul: + return prod([_terms(mi) for mi in e.args]) + return 1 + xnew_base = expand_mul(new_base, deep=False) + if len(Add.make_args(xnew_base)) < _terms(new_base): + new_base = factor_terms(xnew_base) + + c_powers[new_base].append(e) + + # break out the powers from c_powers now + c_part = [Pow(b, ei) for b, e in c_powers.items() for ei in e] + + # we're done + return expr.func(*(c_part + nc_part)) + + else: + raise ValueError("combine must be one of ('all', 'exp', 'base').") + + +def powdenest(eq, force=False, polar=False): + r""" + Collect exponents on powers as assumptions allow. + + Explanation + =========== + + Given ``(bb**be)**e``, this can be simplified as follows: + * if ``bb`` is positive, or + * ``e`` is an integer, or + * ``|be| < 1`` then this simplifies to ``bb**(be*e)`` + + Given a product of powers raised to a power, ``(bb1**be1 * + bb2**be2...)**e``, simplification can be done as follows: + + - if e is positive, the gcd of all bei can be joined with e; + - all non-negative bb can be separated from those that are negative + and their gcd can be joined with e; autosimplification already + handles this separation. + - integer factors from powers that have integers in the denominator + of the exponent can be removed from any term and the gcd of such + integers can be joined with e + + Setting ``force`` to ``True`` will make symbols that are not explicitly + negative behave as though they are positive, resulting in more + denesting. + + Setting ``polar`` to ``True`` will do simplifications on the Riemann surface of + the logarithm, also resulting in more denestings. + + When there are sums of logs in exp() then a product of powers may be + obtained e.g. ``exp(3*(log(a) + 2*log(b)))`` - > ``a**3*b**6``. + + Examples + ======== + + >>> from sympy.abc import a, b, x, y, z + >>> from sympy import Symbol, exp, log, sqrt, symbols, powdenest + + >>> powdenest((x**(2*a/3))**(3*x)) + (x**(2*a/3))**(3*x) + >>> powdenest(exp(3*x*log(2))) + 2**(3*x) + + Assumptions may prevent expansion: + + >>> powdenest(sqrt(x**2)) + sqrt(x**2) + + >>> p = symbols('p', positive=True) + >>> powdenest(sqrt(p**2)) + p + + No other expansion is done. + + >>> i, j = symbols('i,j', integer=True) + >>> powdenest((x**x)**(i + j)) # -X-> (x**x)**i*(x**x)**j + x**(x*(i + j)) + + But exp() will be denested by moving all non-log terms outside of + the function; this may result in the collapsing of the exp to a power + with a different base: + + >>> powdenest(exp(3*y*log(x))) + x**(3*y) + >>> powdenest(exp(y*(log(a) + log(b)))) + (a*b)**y + >>> powdenest(exp(3*(log(a) + log(b)))) + a**3*b**3 + + If assumptions allow, symbols can also be moved to the outermost exponent: + + >>> i = Symbol('i', integer=True) + >>> powdenest(((x**(2*i))**(3*y))**x) + ((x**(2*i))**(3*y))**x + >>> powdenest(((x**(2*i))**(3*y))**x, force=True) + x**(6*i*x*y) + + >>> powdenest(((x**(2*a/3))**(3*y/i))**x) + ((x**(2*a/3))**(3*y/i))**x + >>> powdenest((x**(2*i)*y**(4*i))**z, force=True) + (x*y**2)**(2*i*z) + + >>> n = Symbol('n', negative=True) + + >>> powdenest((x**i)**y, force=True) + x**(i*y) + >>> powdenest((n**i)**x, force=True) + (n**i)**x + + """ + from sympy.simplify.simplify import posify + + if force: + def _denest(b, e): + if not isinstance(b, (Pow, exp)): + return b.is_positive, Pow(b, e, evaluate=False) + return _denest(b.base, b.exp*e) + reps = [] + for p in eq.atoms(Pow, exp): + if isinstance(p.base, (Pow, exp)): + ok, dp = _denest(*p.args) + if ok is not False: + reps.append((p, dp)) + if reps: + eq = eq.subs(reps) + eq, reps = posify(eq) + return powdenest(eq, force=False, polar=polar).xreplace(reps) + + if polar: + eq, rep = polarify(eq) + return unpolarify(powdenest(unpolarify(eq, exponents_only=True)), rep) + + new = powsimp(eq) + return new.xreplace(Transform( + _denest_pow, filter=lambda m: m.is_Pow or isinstance(m, exp))) + +_y = Dummy('y') + + +def _denest_pow(eq): + """ + Denest powers. + + This is a helper function for powdenest that performs the actual + transformation. + """ + from sympy.simplify.simplify import logcombine + + b, e = eq.as_base_exp() + if b.is_Pow or isinstance(b, exp) and e != 1: + new = b._eval_power(e) + if new is not None: + eq = new + b, e = new.as_base_exp() + + # denest exp with log terms in exponent + if b is S.Exp1 and e.is_Mul: + logs = [] + other = [] + for ei in e.args: + if any(isinstance(ai, log) for ai in Add.make_args(ei)): + logs.append(ei) + else: + other.append(ei) + logs = logcombine(Mul(*logs)) + return Pow(exp(logs), Mul(*other)) + + _, be = b.as_base_exp() + if be is S.One and not (b.is_Mul or + b.is_Rational and b.q != 1 or + b.is_positive): + return eq + + # denest eq which is either pos**e or Pow**e or Mul**e or + # Mul(b1**e1, b2**e2) + + # handle polar numbers specially + polars, nonpolars = [], [] + for bb in Mul.make_args(b): + if bb.is_polar: + polars.append(bb.as_base_exp()) + else: + nonpolars.append(bb) + if len(polars) == 1 and not polars[0][0].is_Mul: + return Pow(polars[0][0], polars[0][1]*e)*powdenest(Mul(*nonpolars)**e) + elif polars: + return Mul(*[powdenest(bb**(ee*e)) for (bb, ee) in polars]) \ + *powdenest(Mul(*nonpolars)**e) + + if b.is_Integer: + # use log to see if there is a power here + logb = expand_log(log(b)) + if logb.is_Mul: + c, logb = logb.args + e *= c + base = logb.args[0] + return Pow(base, e) + + # if b is not a Mul or any factor is an atom then there is nothing to do + if not b.is_Mul or any(s.is_Atom for s in Mul.make_args(b)): + return eq + + # let log handle the case of the base of the argument being a Mul, e.g. + # sqrt(x**(2*i)*y**(6*i)) -> x**i*y**(3**i) if x and y are positive; we + # will take the log, expand it, and then factor out the common powers that + # now appear as coefficient. We do this manually since terms_gcd pulls out + # fractions, terms_gcd(x+x*y/2) -> x*(y + 2)/2 and we don't want the 1/2; + # gcd won't pull out numerators from a fraction: gcd(3*x, 9*x/2) -> x but + # we want 3*x. Neither work with noncommutatives. + + def nc_gcd(aa, bb): + a, b = [i.as_coeff_Mul() for i in [aa, bb]] + c = gcd(a[0], b[0]).as_numer_denom()[0] + g = Mul(*(a[1].args_cnc(cset=True)[0] & b[1].args_cnc(cset=True)[0])) + return _keep_coeff(c, g) + + glogb = expand_log(log(b)) + if glogb.is_Add: + args = glogb.args + g = reduce(nc_gcd, args) + if g != 1: + cg, rg = g.as_coeff_Mul() + glogb = _keep_coeff(cg, rg*Add(*[a/g for a in args])) + + # now put the log back together again + if isinstance(glogb, log) or not glogb.is_Mul: + if glogb.args[0].is_Pow or isinstance(glogb.args[0], exp): + glogb = _denest_pow(glogb.args[0]) + if (abs(glogb.exp) < 1) == True: + return Pow(glogb.base, glogb.exp*e) + return eq + + # the log(b) was a Mul so join any adds with logcombine + add = [] + other = [] + for a in glogb.args: + if a.is_Add: + add.append(a) + else: + other.append(a) + return Pow(exp(logcombine(Mul(*add))), e*Mul(*other)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/radsimp.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/radsimp.py new file mode 100644 index 0000000000000000000000000000000000000000..c878168ebfbc29fc632577d6325befc120c26f56 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/radsimp.py @@ -0,0 +1,1234 @@ +from collections import defaultdict + +from sympy.core import sympify, S, Mul, Derivative, Pow +from sympy.core.add import _unevaluated_Add, Add +from sympy.core.assumptions import assumptions +from sympy.core.exprtools import Factors, gcd_terms +from sympy.core.function import _mexpand, expand_mul, expand_power_base +from sympy.core.mul import _keep_coeff, _unevaluated_Mul, _mulsort +from sympy.core.numbers import Rational, zoo, nan +from sympy.core.parameters import global_parameters +from sympy.core.sorting import ordered, default_sort_key +from sympy.core.symbol import Dummy, Wild, symbols +from sympy.functions import exp, sqrt, log +from sympy.functions.elementary.complexes import Abs +from sympy.polys import gcd +from sympy.simplify.sqrtdenest import sqrtdenest +from sympy.utilities.iterables import iterable, sift + + + + +def collect(expr, syms, func=None, evaluate=None, exact=False, distribute_order_term=True): + """ + Collect additive terms of an expression. + + Explanation + =========== + + This function collects additive terms of an expression with respect + to a list of expression up to powers with rational exponents. By the + term symbol here are meant arbitrary expressions, which can contain + powers, products, sums etc. In other words symbol is a pattern which + will be searched for in the expression's terms. + + The input expression is not expanded by :func:`collect`, so user is + expected to provide an expression in an appropriate form. This makes + :func:`collect` more predictable as there is no magic happening behind the + scenes. However, it is important to note, that powers of products are + converted to products of powers using the :func:`~.expand_power_base` + function. + + There are two possible types of output. First, if ``evaluate`` flag is + set, this function will return an expression with collected terms or + else it will return a dictionary with expressions up to rational powers + as keys and collected coefficients as values. + + Examples + ======== + + >>> from sympy import S, collect, expand, factor, Wild + >>> from sympy.abc import a, b, c, x, y + + This function can collect symbolic coefficients in polynomials or + rational expressions. It will manage to find all integer or rational + powers of collection variable:: + + >>> collect(a*x**2 + b*x**2 + a*x - b*x + c, x) + c + x**2*(a + b) + x*(a - b) + + The same result can be achieved in dictionary form:: + + >>> d = collect(a*x**2 + b*x**2 + a*x - b*x + c, x, evaluate=False) + >>> d[x**2] + a + b + >>> d[x] + a - b + >>> d[S.One] + c + + You can also work with multivariate polynomials. However, remember that + this function is greedy so it will care only about a single symbol at time, + in specification order:: + + >>> collect(x**2 + y*x**2 + x*y + y + a*y, [x, y]) + x**2*(y + 1) + x*y + y*(a + 1) + + Also more complicated expressions can be used as patterns:: + + >>> from sympy import sin, log + >>> collect(a*sin(2*x) + b*sin(2*x), sin(2*x)) + (a + b)*sin(2*x) + + >>> collect(a*x*log(x) + b*(x*log(x)), x*log(x)) + x*(a + b)*log(x) + + You can use wildcards in the pattern:: + + >>> w = Wild('w1') + >>> collect(a*x**y - b*x**y, w**y) + x**y*(a - b) + + It is also possible to work with symbolic powers, although it has more + complicated behavior, because in this case power's base and symbolic part + of the exponent are treated as a single symbol:: + + >>> collect(a*x**c + b*x**c, x) + a*x**c + b*x**c + >>> collect(a*x**c + b*x**c, x**c) + x**c*(a + b) + + However if you incorporate rationals to the exponents, then you will get + well known behavior:: + + >>> collect(a*x**(2*c) + b*x**(2*c), x**c) + x**(2*c)*(a + b) + + Note also that all previously stated facts about :func:`collect` function + apply to the exponential function, so you can get:: + + >>> from sympy import exp + >>> collect(a*exp(2*x) + b*exp(2*x), exp(x)) + (a + b)*exp(2*x) + + If you are interested only in collecting specific powers of some symbols + then set ``exact`` flag to True:: + + >>> collect(a*x**7 + b*x**7, x, exact=True) + a*x**7 + b*x**7 + >>> collect(a*x**7 + b*x**7, x**7, exact=True) + x**7*(a + b) + + If you want to collect on any object containing symbols, set + ``exact`` to None: + + >>> collect(x*exp(x) + sin(x)*y + sin(x)*2 + 3*x, x, exact=None) + x*exp(x) + 3*x + (y + 2)*sin(x) + >>> collect(a*x*y + x*y + b*x + x, [x, y], exact=None) + x*y*(a + 1) + x*(b + 1) + + You can also apply this function to differential equations, where + derivatives of arbitrary order can be collected. Note that if you + collect with respect to a function or a derivative of a function, all + derivatives of that function will also be collected. Use + ``exact=True`` to prevent this from happening:: + + >>> from sympy import Derivative as D, collect, Function + >>> f = Function('f') (x) + + >>> collect(a*D(f,x) + b*D(f,x), D(f,x)) + (a + b)*Derivative(f(x), x) + + >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), f) + (a + b)*Derivative(f(x), (x, 2)) + + >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), D(f,x), exact=True) + a*Derivative(f(x), (x, 2)) + b*Derivative(f(x), (x, 2)) + + >>> collect(a*D(f,x) + b*D(f,x) + a*f + b*f, f) + (a + b)*f(x) + (a + b)*Derivative(f(x), x) + + Or you can even match both derivative order and exponent at the same time:: + + >>> collect(a*D(D(f,x),x)**2 + b*D(D(f,x),x)**2, D(f,x)) + (a + b)*Derivative(f(x), (x, 2))**2 + + Finally, you can apply a function to each of the collected coefficients. + For example you can factorize symbolic coefficients of polynomial:: + + >>> f = expand((x + a + 1)**3) + + >>> collect(f, x, factor) + x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + (a + 1)**3 + + .. note:: Arguments are expected to be in expanded form, so you might have + to call :func:`~.expand` prior to calling this function. + + See Also + ======== + + collect_const, collect_sqrt, rcollect + """ + expr = sympify(expr) + syms = [sympify(i) for i in (syms if iterable(syms) else [syms])] + + # replace syms[i] if it is not x, -x or has Wild symbols + cond = lambda x: x.is_Symbol or (-x).is_Symbol or bool( + x.atoms(Wild)) + _, nonsyms = sift(syms, cond, binary=True) + if nonsyms: + reps = dict(zip(nonsyms, [Dummy(**assumptions(i)) for i in nonsyms])) + syms = [reps.get(s, s) for s in syms] + rv = collect(expr.subs(reps), syms, + func=func, evaluate=evaluate, exact=exact, + distribute_order_term=distribute_order_term) + urep = {v: k for k, v in reps.items()} + if not isinstance(rv, dict): + return rv.xreplace(urep) + else: + return {urep.get(k, k).xreplace(urep): v.xreplace(urep) + for k, v in rv.items()} + + # see if other expressions should be considered + if exact is None: + _syms = set() + for i in Add.make_args(expr): + if not i.has_free(*syms) or i in syms: + continue + if not i.is_Mul and i not in syms: + _syms.add(i) + else: + # identify compound generators + g = i._new_rawargs(*i.as_coeff_mul(*syms)[1]) + if g not in syms: + _syms.add(g) + simple = all(i.is_Pow and i.base in syms for i in _syms) + syms = syms + list(ordered(_syms)) + if not simple: + return collect(expr, syms, + func=func, evaluate=evaluate, exact=False, + distribute_order_term=distribute_order_term) + + if evaluate is None: + evaluate = global_parameters.evaluate + + def make_expression(terms): + product = [] + + for term, rat, sym, deriv in terms: + if deriv is not None: + var, order = deriv + for _ in range(order): + term = Derivative(term, var) + + if sym is None: + if rat is S.One: + product.append(term) + else: + product.append(Pow(term, rat)) + else: + product.append(Pow(term, rat*sym)) + + return Mul(*product) + + def parse_derivative(deriv): + # scan derivatives tower in the input expression and return + # underlying function and maximal differentiation order + expr, sym, order = deriv.expr, deriv.variables[0], 1 + + for s in deriv.variables[1:]: + if s == sym: + order += 1 + else: + raise NotImplementedError( + 'Improve MV Derivative support in collect') + + while isinstance(expr, Derivative): + s0 = expr.variables[0] + + if any(s != s0 for s in expr.variables): + raise NotImplementedError( + 'Improve MV Derivative support in collect') + + if s0 == sym: + expr, order = expr.expr, order + len(expr.variables) + else: + break + + return expr, (sym, Rational(order)) + + def parse_term(expr): + """Parses expression expr and outputs tuple (sexpr, rat_expo, + sym_expo, deriv) + where: + - sexpr is the base expression + - rat_expo is the rational exponent that sexpr is raised to + - sym_expo is the symbolic exponent that sexpr is raised to + - deriv contains the derivatives of the expression + + For example, the output of x would be (x, 1, None, None) + the output of 2**x would be (2, 1, x, None). + """ + rat_expo, sym_expo = S.One, None + sexpr, deriv = expr, None + + if expr.is_Pow: + if isinstance(expr.base, Derivative): + sexpr, deriv = parse_derivative(expr.base) + else: + sexpr = expr.base + + if expr.base == S.Exp1: + arg = expr.exp + if arg.is_Rational: + sexpr, rat_expo = S.Exp1, arg + elif arg.is_Mul: + coeff, tail = arg.as_coeff_Mul(rational=True) + sexpr, rat_expo = exp(tail), coeff + + elif expr.exp.is_Number: + rat_expo = expr.exp + else: + coeff, tail = expr.exp.as_coeff_Mul() + + if coeff.is_Number: + rat_expo, sym_expo = coeff, tail + else: + sym_expo = expr.exp + elif isinstance(expr, exp): + arg = expr.exp + if arg.is_Rational: + sexpr, rat_expo = S.Exp1, arg + elif arg.is_Mul: + coeff, tail = arg.as_coeff_Mul(rational=True) + sexpr, rat_expo = exp(tail), coeff + elif isinstance(expr, Derivative): + sexpr, deriv = parse_derivative(expr) + + return sexpr, rat_expo, sym_expo, deriv + + def parse_expression(terms, pattern): + """Parse terms searching for a pattern. + Terms is a list of tuples as returned by parse_terms; + Pattern is an expression treated as a product of factors. + """ + pattern = Mul.make_args(pattern) + + if len(terms) < len(pattern): + # pattern is longer than matched product + # so no chance for positive parsing result + return None + else: + pattern = [parse_term(elem) for elem in pattern] + + terms = terms[:] # need a copy + elems, common_expo, has_deriv = [], None, False + + for elem, e_rat, e_sym, e_ord in pattern: + + if elem.is_Number and e_rat == 1 and e_sym is None: + # a constant is a match for everything + continue + + for j in range(len(terms)): + if terms[j] is None: + continue + + term, t_rat, t_sym, t_ord = terms[j] + + # keeping track of whether one of the terms had + # a derivative or not as this will require rebuilding + # the expression later + if t_ord is not None: + has_deriv = True + + if (term.match(elem) is not None and + (t_sym == e_sym or t_sym is not None and + e_sym is not None and + t_sym.match(e_sym) is not None)): + if exact is False: + # we don't have to be exact so find common exponent + # for both expression's term and pattern's element + expo = t_rat / e_rat + + if common_expo is None: + # first time + common_expo = expo + else: + # common exponent was negotiated before so + # there is no chance for a pattern match unless + # common and current exponents are equal + if common_expo != expo: + common_expo = 1 + else: + # we ought to be exact so all fields of + # interest must match in every details + if e_rat != t_rat or e_ord != t_ord: + continue + + # found common term so remove it from the expression + # and try to match next element in the pattern + elems.append(terms[j]) + terms[j] = None + + break + + else: + # pattern element not found + return None + + return [_f for _f in terms if _f], elems, common_expo, has_deriv + + if evaluate: + if expr.is_Add: + o = expr.getO() or 0 + expr = expr.func(*[ + collect(a, syms, func, True, exact, distribute_order_term) + for a in expr.args if a != o]) + o + elif expr.is_Mul: + return expr.func(*[ + collect(term, syms, func, True, exact, distribute_order_term) + for term in expr.args]) + elif expr.is_Pow: + b = collect( + expr.base, syms, func, True, exact, distribute_order_term) + return Pow(b, expr.exp) + + syms = [expand_power_base(i, deep=False) for i in syms] + + order_term = None + + if distribute_order_term: + order_term = expr.getO() + + if order_term is not None: + if order_term.has(*syms): + order_term = None + else: + expr = expr.removeO() + + summa = [expand_power_base(i, deep=False) for i in Add.make_args(expr)] + + collected, disliked = defaultdict(list), S.Zero + for product in summa: + c, nc = product.args_cnc(split_1=False) + args = list(ordered(c)) + nc + terms = [parse_term(i) for i in args] + small_first = True + + for symbol in syms: + if isinstance(symbol, Derivative) and small_first: + terms = list(reversed(terms)) + small_first = not small_first + result = parse_expression(terms, symbol) + + if result is not None: + if not symbol.is_commutative: + raise AttributeError("Can not collect noncommutative symbol") + + terms, elems, common_expo, has_deriv = result + + # when there was derivative in current pattern we + # will need to rebuild its expression from scratch + if not has_deriv: + margs = [] + for elem in elems: + if elem[2] is None: + e = elem[1] + else: + e = elem[1]*elem[2] + margs.append(Pow(elem[0], e)) + index = Mul(*margs) + else: + index = make_expression(elems) + terms = expand_power_base(make_expression(terms), deep=False) + index = expand_power_base(index, deep=False) + collected[index].append(terms) + break + else: + # none of the patterns matched + disliked += product + # add terms now for each key + collected = {k: Add(*v) for k, v in collected.items()} + + if disliked is not S.Zero: + collected[S.One] = disliked + + if order_term is not None: + for key, val in collected.items(): + collected[key] = val + order_term + + if func is not None: + collected = { + key: func(val) for key, val in collected.items()} + + if evaluate: + return Add(*[key*val for key, val in collected.items()]) + else: + return collected + + +def rcollect(expr, *vars): + """ + Recursively collect sums in an expression. + + Examples + ======== + + >>> from sympy.simplify import rcollect + >>> from sympy.abc import x, y + + >>> expr = (x**2*y + x*y + x + y)/(x + y) + + >>> rcollect(expr, y) + (x + y*(x**2 + x + 1))/(x + y) + + See Also + ======== + + collect, collect_const, collect_sqrt + """ + if expr.is_Atom or not expr.has(*vars): + return expr + else: + expr = expr.__class__(*[rcollect(arg, *vars) for arg in expr.args]) + + if expr.is_Add: + return collect(expr, vars) + else: + return expr + + +def collect_sqrt(expr, evaluate=None): + """Return expr with terms having common square roots collected together. + If ``evaluate`` is False a count indicating the number of sqrt-containing + terms will be returned and, if non-zero, the terms of the Add will be + returned, else the expression itself will be returned as a single term. + If ``evaluate`` is True, the expression with any collected terms will be + returned. + + Note: since I = sqrt(-1), it is collected, too. + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.simplify.radsimp import collect_sqrt + >>> from sympy.abc import a, b + + >>> r2, r3, r5 = [sqrt(i) for i in [2, 3, 5]] + >>> collect_sqrt(a*r2 + b*r2) + sqrt(2)*(a + b) + >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r3) + sqrt(2)*(a + b) + sqrt(3)*(a + b) + >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r5) + sqrt(3)*a + sqrt(5)*b + sqrt(2)*(a + b) + + If evaluate is False then the arguments will be sorted and + returned as a list and a count of the number of sqrt-containing + terms will be returned: + + >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r5, evaluate=False) + ((sqrt(3)*a, sqrt(5)*b, sqrt(2)*(a + b)), 3) + >>> collect_sqrt(a*sqrt(2) + b, evaluate=False) + ((b, sqrt(2)*a), 1) + >>> collect_sqrt(a + b, evaluate=False) + ((a + b,), 0) + + See Also + ======== + + collect, collect_const, rcollect + """ + if evaluate is None: + evaluate = global_parameters.evaluate + # this step will help to standardize any complex arguments + # of sqrts + coeff, expr = expr.as_content_primitive() + vars = set() + for a in Add.make_args(expr): + for m in a.args_cnc()[0]: + if m.is_number and ( + m.is_Pow and m.exp.is_Rational and m.exp.q == 2 or + m is S.ImaginaryUnit): + vars.add(m) + + # we only want radicals, so exclude Number handling; in this case + # d will be evaluated + d = collect_const(expr, *vars, Numbers=False) + hit = expr != d + + if not evaluate: + nrad = 0 + # make the evaluated args canonical + args = list(ordered(Add.make_args(d))) + for i, m in enumerate(args): + c, nc = m.args_cnc() + for ci in c: + # XXX should this be restricted to ci.is_number as above? + if ci.is_Pow and ci.exp.is_Rational and ci.exp.q == 2 or \ + ci is S.ImaginaryUnit: + nrad += 1 + break + args[i] *= coeff + if not (hit or nrad): + args = [Add(*args)] + return tuple(args), nrad + + return coeff*d + + +def collect_abs(expr): + """Return ``expr`` with arguments of multiple Abs in a term collected + under a single instance. + + Examples + ======== + + >>> from sympy.simplify.radsimp import collect_abs + >>> from sympy.abc import x + >>> collect_abs(abs(x + 1)/abs(x**2 - 1)) + Abs((x + 1)/(x**2 - 1)) + >>> collect_abs(abs(1/x)) + Abs(1/x) + """ + def _abs(mul): + c, nc = mul.args_cnc() + a = [] + o = [] + for i in c: + if isinstance(i, Abs): + a.append(i.args[0]) + elif isinstance(i, Pow) and isinstance(i.base, Abs) and i.exp.is_real: + a.append(i.base.args[0]**i.exp) + else: + o.append(i) + if len(a) < 2 and not any(i.exp.is_negative for i in a if isinstance(i, Pow)): + return mul + absarg = Mul(*a) + A = Abs(absarg) + args = [A] + args.extend(o) + if not A.has(Abs): + args.extend(nc) + return Mul(*args) + if not isinstance(A, Abs): + # reevaluate and make it unevaluated + A = Abs(absarg, evaluate=False) + args[0] = A + _mulsort(args) + args.extend(nc) # nc always go last + return Mul._from_args(args, is_commutative=not nc) + + return expr.replace( + lambda x: isinstance(x, Mul), + lambda x: _abs(x)).replace( + lambda x: isinstance(x, Pow), + lambda x: _abs(x)) + + +def collect_const(expr, *vars, Numbers=True): + """A non-greedy collection of terms with similar number coefficients in + an Add expr. If ``vars`` is given then only those constants will be + targeted. Although any Number can also be targeted, if this is not + desired set ``Numbers=False`` and no Float or Rational will be collected. + + Parameters + ========== + + expr : SymPy expression + This parameter defines the expression the expression from which + terms with similar coefficients are to be collected. A non-Add + expression is returned as it is. + + vars : variable length collection of Numbers, optional + Specifies the constants to target for collection. Can be multiple in + number. + + Numbers : bool + Specifies to target all instance of + :class:`sympy.core.numbers.Number` class. If ``Numbers=False``, then + no Float or Rational will be collected. + + Returns + ======= + + expr : Expr + Returns an expression with similar coefficient terms collected. + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.abc import s, x, y, z + >>> from sympy.simplify.radsimp import collect_const + >>> collect_const(sqrt(3) + sqrt(3)*(1 + sqrt(2))) + sqrt(3)*(sqrt(2) + 2) + >>> collect_const(sqrt(3)*s + sqrt(7)*s + sqrt(3) + sqrt(7)) + (sqrt(3) + sqrt(7))*(s + 1) + >>> s = sqrt(2) + 2 + >>> collect_const(sqrt(3)*s + sqrt(3) + sqrt(7)*s + sqrt(7)) + (sqrt(2) + 3)*(sqrt(3) + sqrt(7)) + >>> collect_const(sqrt(3)*s + sqrt(3) + sqrt(7)*s + sqrt(7), sqrt(3)) + sqrt(7) + sqrt(3)*(sqrt(2) + 3) + sqrt(7)*(sqrt(2) + 2) + + The collection is sign-sensitive, giving higher precedence to the + unsigned values: + + >>> collect_const(x - y - z) + x - (y + z) + >>> collect_const(-y - z) + -(y + z) + >>> collect_const(2*x - 2*y - 2*z, 2) + 2*(x - y - z) + >>> collect_const(2*x - 2*y - 2*z, -2) + 2*x - 2*(y + z) + + See Also + ======== + + collect, collect_sqrt, rcollect + """ + if not expr.is_Add: + return expr + + recurse = False + + if not vars: + recurse = True + vars = set() + for a in expr.args: + for m in Mul.make_args(a): + if m.is_number: + vars.add(m) + else: + vars = sympify(vars) + if not Numbers: + vars = [v for v in vars if not v.is_Number] + + vars = list(ordered(vars)) + for v in vars: + terms = defaultdict(list) + Fv = Factors(v) + for m in Add.make_args(expr): + f = Factors(m) + q, r = f.div(Fv) + if r.is_one: + # only accept this as a true factor if + # it didn't change an exponent from an Integer + # to a non-Integer, e.g. 2/sqrt(2) -> sqrt(2) + # -- we aren't looking for this sort of change + fwas = f.factors.copy() + fnow = q.factors + if not any(k in fwas and fwas[k].is_Integer and not + fnow[k].is_Integer for k in fnow): + terms[v].append(q.as_expr()) + continue + terms[S.One].append(m) + + args = [] + hit = False + uneval = False + for k in ordered(terms): + v = terms[k] + if k is S.One: + args.extend(v) + continue + + if len(v) > 1: + v = Add(*v) + hit = True + if recurse and v != expr: + vars.append(v) + else: + v = v[0] + + # be careful not to let uneval become True unless + # it must be because it's going to be more expensive + # to rebuild the expression as an unevaluated one + if Numbers and k.is_Number and v.is_Add: + args.append(_keep_coeff(k, v, sign=True)) + uneval = True + else: + args.append(k*v) + + if hit: + if uneval: + expr = _unevaluated_Add(*args) + else: + expr = Add(*args) + if not expr.is_Add: + break + + return expr + + +def radsimp(expr, symbolic=True, max_terms=4): + r""" + Rationalize the denominator by removing square roots. + + Explanation + =========== + + The expression returned from radsimp must be used with caution + since if the denominator contains symbols, it will be possible to make + substitutions that violate the assumptions of the simplification process: + that for a denominator matching a + b*sqrt(c), a != +/-b*sqrt(c). (If + there are no symbols, this assumptions is made valid by collecting terms + of sqrt(c) so the match variable ``a`` does not contain ``sqrt(c)``.) If + you do not want the simplification to occur for symbolic denominators, set + ``symbolic`` to False. + + If there are more than ``max_terms`` radical terms then the expression is + returned unchanged. + + Examples + ======== + + >>> from sympy import radsimp, sqrt, Symbol, pprint + >>> from sympy import factor_terms, fraction, signsimp + >>> from sympy.simplify.radsimp import collect_sqrt + >>> from sympy.abc import a, b, c + + >>> radsimp(1/(2 + sqrt(2))) + (2 - sqrt(2))/2 + >>> x,y = map(Symbol, 'xy') + >>> e = ((2 + 2*sqrt(2))*x + (2 + sqrt(8))*y)/(2 + sqrt(2)) + >>> radsimp(e) + sqrt(2)*(x + y) + + No simplification beyond removal of the gcd is done. One might + want to polish the result a little, however, by collecting + square root terms: + + >>> r2 = sqrt(2) + >>> r5 = sqrt(5) + >>> ans = radsimp(1/(y*r2 + x*r2 + a*r5 + b*r5)); pprint(ans) + ___ ___ ___ ___ + \/ 5 *a + \/ 5 *b - \/ 2 *x - \/ 2 *y + ------------------------------------------ + 2 2 2 2 + 5*a + 10*a*b + 5*b - 2*x - 4*x*y - 2*y + + >>> n, d = fraction(ans) + >>> pprint(factor_terms(signsimp(collect_sqrt(n))/d, radical=True)) + ___ ___ + \/ 5 *(a + b) - \/ 2 *(x + y) + ------------------------------------------ + 2 2 2 2 + 5*a + 10*a*b + 5*b - 2*x - 4*x*y - 2*y + + If radicals in the denominator cannot be removed or there is no denominator, + the original expression will be returned. + + >>> radsimp(sqrt(2)*x + sqrt(2)) + sqrt(2)*x + sqrt(2) + + Results with symbols will not always be valid for all substitutions: + + >>> eq = 1/(a + b*sqrt(c)) + >>> eq.subs(a, b*sqrt(c)) + 1/(2*b*sqrt(c)) + >>> radsimp(eq).subs(a, b*sqrt(c)) + nan + + If ``symbolic=False``, symbolic denominators will not be transformed (but + numeric denominators will still be processed): + + >>> radsimp(eq, symbolic=False) + 1/(a + b*sqrt(c)) + + """ + from sympy.core.expr import Expr + from sympy.simplify.simplify import signsimp + + syms = symbols("a:d A:D") + def _num(rterms): + # return the multiplier that will simplify the expression described + # by rterms [(sqrt arg, coeff), ... ] + a, b, c, d, A, B, C, D = syms + if len(rterms) == 2: + reps = dict(list(zip([A, a, B, b], [j for i in rterms for j in i]))) + return ( + sqrt(A)*a - sqrt(B)*b).xreplace(reps) + if len(rterms) == 3: + reps = dict(list(zip([A, a, B, b, C, c], [j for i in rterms for j in i]))) + return ( + (sqrt(A)*a + sqrt(B)*b - sqrt(C)*c)*(2*sqrt(A)*sqrt(B)*a*b - A*a**2 - + B*b**2 + C*c**2)).xreplace(reps) + elif len(rterms) == 4: + reps = dict(list(zip([A, a, B, b, C, c, D, d], [j for i in rterms for j in i]))) + return ((sqrt(A)*a + sqrt(B)*b - sqrt(C)*c - sqrt(D)*d)*(2*sqrt(A)*sqrt(B)*a*b + - A*a**2 - B*b**2 - 2*sqrt(C)*sqrt(D)*c*d + C*c**2 + + D*d**2)*(-8*sqrt(A)*sqrt(B)*sqrt(C)*sqrt(D)*a*b*c*d + A**2*a**4 - + 2*A*B*a**2*b**2 - 2*A*C*a**2*c**2 - 2*A*D*a**2*d**2 + B**2*b**4 - + 2*B*C*b**2*c**2 - 2*B*D*b**2*d**2 + C**2*c**4 - 2*C*D*c**2*d**2 + + D**2*d**4)).xreplace(reps) + elif len(rterms) == 1: + return sqrt(rterms[0][0]) + else: + raise NotImplementedError + + def ispow2(d, log2=False): + if not d.is_Pow: + return False + e = d.exp + if e.is_Rational and e.q == 2 or symbolic and denom(e) == 2: + return True + if log2: + q = 1 + if e.is_Rational: + q = e.q + elif symbolic: + d = denom(e) + if d.is_Integer: + q = d + if q != 1 and log(q, 2).is_Integer: + return True + return False + + def handle(expr): + # Handle first reduces to the case + # expr = 1/d, where d is an add, or d is base**p/2. + # We do this by recursively calling handle on each piece. + from sympy.simplify.simplify import nsimplify + + if expr.is_Atom: + return expr + elif not isinstance(expr, Expr): + return expr.func(*[handle(a) for a in expr.args]) + + n, d = fraction(expr) + + if d.is_Atom and n.is_Atom: + return expr + elif not n.is_Atom: + n = n.func(*[handle(a) for a in n.args]) + return _unevaluated_Mul(n, handle(1/d)) + elif n is not S.One: + return _unevaluated_Mul(n, handle(1/d)) + elif d.is_Mul: + return _unevaluated_Mul(*[handle(1/d) for d in d.args]) + + # By this step, expr is 1/d, and d is not a mul. + if not symbolic and d.free_symbols: + return expr + + if ispow2(d): + d2 = sqrtdenest(sqrt(d.base))**numer(d.exp) + if d2 != d: + return handle(1/d2) + elif d.is_Pow and (d.exp.is_integer or d.base.is_positive): + # (1/d**i) = (1/d)**i + return handle(1/d.base)**d.exp + + if not (d.is_Add or ispow2(d)): + return 1/d.func(*[handle(a) for a in d.args]) + + # handle 1/d treating d as an Add (though it may not be) + + keep = True # keep changes that are made + + # flatten it and collect radicals after checking for special + # conditions + d = _mexpand(d) + + # did it change? + if d.is_Atom: + return 1/d + + # is it a number that might be handled easily? + if d.is_number: + _d = nsimplify(d) + if _d.is_Number and _d.equals(d): + return 1/_d + + while True: + # collect similar terms + collected = defaultdict(list) + for m in Add.make_args(d): # d might have become non-Add + p2 = [] + other = [] + for i in Mul.make_args(m): + if ispow2(i, log2=True): + p2.append(i.base if i.exp is S.Half else i.base**(2*i.exp)) + elif i is S.ImaginaryUnit: + p2.append(S.NegativeOne) + else: + other.append(i) + collected[tuple(ordered(p2))].append(Mul(*other)) + rterms = list(ordered(list(collected.items()))) + rterms = [(Mul(*i), Add(*j)) for i, j in rterms] + nrad = len(rterms) - (1 if rterms[0][0] is S.One else 0) + if nrad < 1: + break + elif nrad > max_terms: + # there may have been invalid operations leading to this point + # so don't keep changes, e.g. this expression is troublesome + # in collecting terms so as not to raise the issue of 2834: + # r = sqrt(sqrt(5) + 5) + # eq = 1/(sqrt(5)*r + 2*sqrt(5)*sqrt(-sqrt(5) + 5) + 5*r) + keep = False + break + if len(rterms) > 4: + # in general, only 4 terms can be removed with repeated squaring + # but other considerations can guide selection of radical terms + # so that radicals are removed + if all(x.is_Integer and (y**2).is_Rational for x, y in rterms): + nd, d = rad_rationalize(S.One, Add._from_args( + [sqrt(x)*y for x, y in rterms])) + n *= nd + else: + # is there anything else that might be attempted? + keep = False + break + from sympy.simplify.powsimp import powsimp, powdenest + + num = powsimp(_num(rterms)) + n *= num + d *= num + d = powdenest(_mexpand(d), force=symbolic) + if d.has(S.Zero, nan, zoo): + return expr + if d.is_Atom: + break + + if not keep: + return expr + return _unevaluated_Mul(n, 1/d) + + if not isinstance(expr, Expr): + return expr.func(*[radsimp(a, symbolic=symbolic, max_terms=max_terms) for a in expr.args]) + + coeff, expr = expr.as_coeff_Add() + expr = expr.normal() + old = fraction(expr) + n, d = fraction(handle(expr)) + if old != (n, d): + if not d.is_Atom: + was = (n, d) + n = signsimp(n, evaluate=False) + d = signsimp(d, evaluate=False) + u = Factors(_unevaluated_Mul(n, 1/d)) + u = _unevaluated_Mul(*[k**v for k, v in u.factors.items()]) + n, d = fraction(u) + if old == (n, d): + n, d = was + n = expand_mul(n) + if d.is_Number or d.is_Add: + n2, d2 = fraction(gcd_terms(_unevaluated_Mul(n, 1/d))) + if d2.is_Number or (d2.count_ops() <= d.count_ops()): + n, d = [signsimp(i) for i in (n2, d2)] + if n.is_Mul and n.args[0].is_Number: + n = n.func(*n.args) + + return coeff + _unevaluated_Mul(n, 1/d) + + +def rad_rationalize(num, den): + """ + Rationalize ``num/den`` by removing square roots in the denominator; + num and den are sum of terms whose squares are positive rationals. + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.simplify.radsimp import rad_rationalize + >>> rad_rationalize(sqrt(3), 1 + sqrt(2)/3) + (-sqrt(3) + sqrt(6)/3, -7/9) + """ + if not den.is_Add: + return num, den + g, a, b = split_surds(den) + a = a*sqrt(g) + num = _mexpand((a - b)*num) + den = _mexpand(a**2 - b**2) + return rad_rationalize(num, den) + + +def fraction(expr, exact=False): + """Returns a pair with expression's numerator and denominator. + If the given expression is not a fraction then this function + will return the tuple (expr, 1). + + This function will not make any attempt to simplify nested + fractions or to do any term rewriting at all. + + If only one of the numerator/denominator pair is needed then + use numer(expr) or denom(expr) functions respectively. + + >>> from sympy import fraction, Rational, Symbol + >>> from sympy.abc import x, y + + >>> fraction(x/y) + (x, y) + >>> fraction(x) + (x, 1) + + >>> fraction(1/y**2) + (1, y**2) + + >>> fraction(x*y/2) + (x*y, 2) + >>> fraction(Rational(1, 2)) + (1, 2) + + This function will also work fine with assumptions: + + >>> k = Symbol('k', negative=True) + >>> fraction(x * y**k) + (x, y**(-k)) + + If we know nothing about sign of some exponent and ``exact`` + flag is unset, then the exponent's structure will + be analyzed and pretty fraction will be returned: + + >>> from sympy import exp, Mul + >>> fraction(2*x**(-y)) + (2, x**y) + + >>> fraction(exp(-x)) + (1, exp(x)) + + >>> fraction(exp(-x), exact=True) + (exp(-x), 1) + + The ``exact`` flag will also keep any unevaluated Muls from + being evaluated: + + >>> u = Mul(2, x + 1, evaluate=False) + >>> fraction(u) + (2*x + 2, 1) + >>> fraction(u, exact=True) + (2*(x + 1), 1) + """ + expr = sympify(expr) + + numer, denom = [], [] + + for term in Mul.make_args(expr): + if term.is_commutative and (term.is_Pow or isinstance(term, exp)): + b, ex = term.as_base_exp() + if ex.is_negative: + if ex is S.NegativeOne: + denom.append(b) + elif exact: + if ex.is_constant(): + denom.append(Pow(b, -ex)) + else: + numer.append(term) + else: + denom.append(Pow(b, -ex)) + elif ex.is_positive: + numer.append(term) + elif not exact and ex.is_Mul: + n, d = term.as_numer_denom() # this will cause evaluation + if n != 1: + numer.append(n) + denom.append(d) + else: + numer.append(term) + elif term.is_Rational and not term.is_Integer: + if term.p != 1: + numer.append(term.p) + denom.append(term.q) + else: + numer.append(term) + return Mul(*numer, evaluate=not exact), Mul(*denom, evaluate=not exact) + + +def numer(expr, exact=False): # default matches fraction's default + return fraction(expr, exact=exact)[0] + + +def denom(expr, exact=False): # default matches fraction's default + return fraction(expr, exact=exact)[1] + + +def fraction_expand(expr, **hints): + return expr.expand(frac=True, **hints) + + +def numer_expand(expr, **hints): + # default matches fraction's default + a, b = fraction(expr, exact=hints.get('exact', False)) + return a.expand(numer=True, **hints) / b + + +def denom_expand(expr, **hints): + # default matches fraction's default + a, b = fraction(expr, exact=hints.get('exact', False)) + return a / b.expand(denom=True, **hints) + + +expand_numer = numer_expand +expand_denom = denom_expand +expand_fraction = fraction_expand + + +def split_surds(expr): + """ + Split an expression with terms whose squares are positive rationals + into a sum of terms whose surds squared have gcd equal to g + and a sum of terms with surds squared prime with g. + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.simplify.radsimp import split_surds + >>> split_surds(3*sqrt(3) + sqrt(5)/7 + sqrt(6) + sqrt(10) + sqrt(15)) + (3, sqrt(2) + sqrt(5) + 3, sqrt(5)/7 + sqrt(10)) + """ + args = sorted(expr.args, key=default_sort_key) + coeff_muls = [x.as_coeff_Mul() for x in args] + surds = [x[1]**2 for x in coeff_muls if x[1].is_Pow] + surds.sort(key=default_sort_key) + g, b1, b2 = _split_gcd(*surds) + g2 = g + if not b2 and len(b1) >= 2: + b1n = [x/g for x in b1] + b1n = [x for x in b1n if x != 1] + # only a common factor has been factored; split again + g1, b1n, b2 = _split_gcd(*b1n) + g2 = g*g1 + a1v, a2v = [], [] + for c, s in coeff_muls: + if s.is_Pow and s.exp == S.Half: + s1 = s.base + if s1 in b1: + a1v.append(c*sqrt(s1/g2)) + else: + a2v.append(c*s) + else: + a2v.append(c*s) + a = Add(*a1v) + b = Add(*a2v) + return g2, a, b + + +def _split_gcd(*a): + """ + Split the list of integers ``a`` into a list of integers, ``a1`` having + ``g = gcd(a1)``, and a list ``a2`` whose elements are not divisible by + ``g``. Returns ``g, a1, a2``. + + Examples + ======== + + >>> from sympy.simplify.radsimp import _split_gcd + >>> _split_gcd(55, 35, 22, 14, 77, 10) + (5, [55, 35, 10], [22, 14, 77]) + """ + g = a[0] + b1 = [g] + b2 = [] + for x in a[1:]: + g1 = gcd(g, x) + if g1 == 1: + b2.append(x) + else: + g = g1 + b1.append(x) + return g, b1, b2 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/ratsimp.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/ratsimp.py new file mode 100644 index 0000000000000000000000000000000000000000..95751fab47f585d3ae2e1289f014fba0f2708224 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/ratsimp.py @@ -0,0 +1,222 @@ +from itertools import combinations_with_replacement +from sympy.core import symbols, Add, Dummy +from sympy.core.numbers import Rational +from sympy.polys import cancel, ComputationFailed, parallel_poly_from_expr, reduced, Poly +from sympy.polys.monomials import Monomial, monomial_div +from sympy.polys.polyerrors import DomainError, PolificationFailed +from sympy.utilities.misc import debug, debugf + +def ratsimp(expr): + """ + Put an expression over a common denominator, cancel and reduce. + + Examples + ======== + + >>> from sympy import ratsimp + >>> from sympy.abc import x, y + >>> ratsimp(1/x + 1/y) + (x + y)/(x*y) + """ + + f, g = cancel(expr).as_numer_denom() + try: + Q, r = reduced(f, [g], field=True, expand=False) + except ComputationFailed: + return f/g + + return Add(*Q) + cancel(r/g) + + +def ratsimpmodprime(expr, G, *gens, quick=True, polynomial=False, **args): + """ + Simplifies a rational expression ``expr`` modulo the prime ideal + generated by ``G``. ``G`` should be a Groebner basis of the + ideal. + + Examples + ======== + + >>> from sympy.simplify.ratsimp import ratsimpmodprime + >>> from sympy.abc import x, y + >>> eq = (x + y**5 + y)/(x - y) + >>> ratsimpmodprime(eq, [x*y**5 - x - y], x, y, order='lex') + (-x**2 - x*y - x - y)/(-x**2 + x*y) + + If ``polynomial`` is ``False``, the algorithm computes a rational + simplification which minimizes the sum of the total degrees of + the numerator and the denominator. + + If ``polynomial`` is ``True``, this function just brings numerator and + denominator into a canonical form. This is much faster, but has + potentially worse results. + + References + ========== + + .. [1] M. Monagan, R. Pearce, Rational Simplification Modulo a Polynomial + Ideal, https://dl.acm.org/doi/pdf/10.1145/1145768.1145809 + (specifically, the second algorithm) + """ + from sympy.solvers.solvers import solve + + debug('ratsimpmodprime', expr) + + # usual preparation of polynomials: + + num, denom = cancel(expr).as_numer_denom() + + try: + polys, opt = parallel_poly_from_expr([num, denom] + G, *gens, **args) + except PolificationFailed: + return expr + + domain = opt.domain + + if domain.has_assoc_Field: + opt.domain = domain.get_field() + else: + raise DomainError( + "Cannot compute rational simplification over %s" % domain) + + # compute only once + leading_monomials = [g.LM(opt.order) for g in polys[2:]] + tested = set() + + def staircase(n): + """ + Compute all monomials with degree less than ``n`` that are + not divisible by any element of ``leading_monomials``. + """ + if n == 0: + return [1] + S = [] + for mi in combinations_with_replacement(range(len(opt.gens)), n): + m = [0]*len(opt.gens) + for i in mi: + m[i] += 1 + if all(monomial_div(m, lmg) is None for lmg in + leading_monomials): + S.append(m) + + return [Monomial(s).as_expr(*opt.gens) for s in S] + staircase(n - 1) + + def _ratsimpmodprime(a, b, allsol, N=0, D=0): + r""" + Computes a rational simplification of ``a/b`` which minimizes + the sum of the total degrees of the numerator and the denominator. + + Explanation + =========== + + The algorithm proceeds by looking at ``a * d - b * c`` modulo + the ideal generated by ``G`` for some ``c`` and ``d`` with degree + less than ``a`` and ``b`` respectively. + The coefficients of ``c`` and ``d`` are indeterminates and thus + the coefficients of the normalform of ``a * d - b * c`` are + linear polynomials in these indeterminates. + If these linear polynomials, considered as system of + equations, have a nontrivial solution, then `\frac{a}{b} + \equiv \frac{c}{d}` modulo the ideal generated by ``G``. So, + by construction, the degree of ``c`` and ``d`` is less than + the degree of ``a`` and ``b``, so a simpler representation + has been found. + After a simpler representation has been found, the algorithm + tries to reduce the degree of the numerator and denominator + and returns the result afterwards. + + As an extension, if quick=False, we look at all possible degrees such + that the total degree is less than *or equal to* the best current + solution. We retain a list of all solutions of minimal degree, and try + to find the best one at the end. + """ + c, d = a, b + steps = 0 + + maxdeg = a.total_degree() + b.total_degree() + if quick: + bound = maxdeg - 1 + else: + bound = maxdeg + while N + D <= bound: + if (N, D) in tested: + break + tested.add((N, D)) + + M1 = staircase(N) + M2 = staircase(D) + debugf('%s / %s: %s, %s', (N, D, M1, M2)) + + Cs = symbols("c:%d" % len(M1), cls=Dummy) + Ds = symbols("d:%d" % len(M2), cls=Dummy) + ng = Cs + Ds + + c_hat = Poly( + sum(Cs[i] * M1[i] for i in range(len(M1))), opt.gens + ng) + d_hat = Poly( + sum(Ds[i] * M2[i] for i in range(len(M2))), opt.gens + ng) + + r = reduced(a * d_hat - b * c_hat, G, opt.gens + ng, + order=opt.order, polys=True)[1] + + S = Poly(r, gens=opt.gens).coeffs() + sol = solve(S, Cs + Ds, particular=True, quick=True) + + if sol and not all(s == 0 for s in sol.values()): + c = c_hat.subs(sol) + d = d_hat.subs(sol) + + # The "free" variables occurring before as parameters + # might still be in the substituted c, d, so set them + # to the value chosen before: + c = c.subs(dict(list(zip(Cs + Ds, [1] * (len(Cs) + len(Ds)))))) + d = d.subs(dict(list(zip(Cs + Ds, [1] * (len(Cs) + len(Ds)))))) + + c = Poly(c, opt.gens) + d = Poly(d, opt.gens) + if d == 0: + raise ValueError('Ideal not prime?') + + allsol.append((c_hat, d_hat, S, Cs + Ds)) + if N + D != maxdeg: + allsol = [allsol[-1]] + + break + + steps += 1 + N += 1 + D += 1 + + if steps > 0: + c, d, allsol = _ratsimpmodprime(c, d, allsol, N, D - steps) + c, d, allsol = _ratsimpmodprime(c, d, allsol, N - steps, D) + + return c, d, allsol + + # preprocessing. this improves performance a bit when deg(num) + # and deg(denom) are large: + num = reduced(num, G, opt.gens, order=opt.order)[1] + denom = reduced(denom, G, opt.gens, order=opt.order)[1] + + if polynomial: + return (num/denom).cancel() + + c, d, allsol = _ratsimpmodprime( + Poly(num, opt.gens, domain=opt.domain), Poly(denom, opt.gens, domain=opt.domain), []) + if not quick and allsol: + debugf('Looking for best minimal solution. Got: %s', len(allsol)) + newsol = [] + for c_hat, d_hat, S, ng in allsol: + sol = solve(S, ng, particular=True, quick=False) + # all values of sol should be numbers; if not, solve is broken + newsol.append((c_hat.subs(sol), d_hat.subs(sol))) + c, d = min(newsol, key=lambda x: len(x[0].terms()) + len(x[1].terms())) + + if not domain.is_Field: + cn, c = c.clear_denoms(convert=True) + dn, d = d.clear_denoms(convert=True) + r = Rational(cn, dn) + else: + r = Rational(1) + + return (c*r.q)/(d*r.p) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/simplify.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/simplify.py new file mode 100644 index 0000000000000000000000000000000000000000..8b315cc20c19fc10c37b903d16129a7f5579ecd3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/simplify.py @@ -0,0 +1,2164 @@ +from __future__ import annotations + +from typing import overload + +from collections import defaultdict + +from sympy.concrete.products import Product +from sympy.concrete.summations import Sum +from sympy.core import (Basic, S, Add, Mul, Pow, Symbol, sympify, + expand_func, Function, Dummy, Expr, factor_terms, + expand_power_exp, Eq) +from sympy.core.exprtools import factor_nc +from sympy.core.parameters import global_parameters +from sympy.core.function import (expand_log, count_ops, _mexpand, + nfloat, expand_mul, expand) +from sympy.core.numbers import Float, I, pi, Rational, equal_valued +from sympy.core.relational import Relational +from sympy.core.rules import Transform +from sympy.core.sorting import ordered +from sympy.core.sympify import _sympify +from sympy.core.traversal import bottom_up as _bottom_up, walk as _walk +from sympy.functions import gamma, exp, sqrt, log, exp_polar, re +from sympy.functions.combinatorial.factorials import CombinatorialFunction +from sympy.functions.elementary.complexes import unpolarify, Abs, sign +from sympy.functions.elementary.exponential import ExpBase +from sympy.functions.elementary.hyperbolic import HyperbolicFunction +from sympy.functions.elementary.integers import ceiling +from sympy.functions.elementary.piecewise import (Piecewise, piecewise_fold, + piecewise_simplify) +from sympy.functions.elementary.trigonometric import TrigonometricFunction +from sympy.functions.special.bessel import (BesselBase, besselj, besseli, + besselk, bessely, jn) +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.integrals.integrals import Integral +from sympy.logic.boolalg import Boolean +from sympy.matrices.expressions import (MatrixExpr, MatAdd, MatMul, + MatPow, MatrixSymbol) +from sympy.polys import together, cancel, factor +from sympy.polys.numberfields.minpoly import _is_sum_surds, _minimal_polynomial_sq +from sympy.sets.sets import Set +from sympy.simplify.combsimp import combsimp +from sympy.simplify.cse_opts import sub_pre, sub_post +from sympy.simplify.hyperexpand import hyperexpand +from sympy.simplify.powsimp import powsimp +from sympy.simplify.radsimp import radsimp, fraction, collect_abs +from sympy.simplify.sqrtdenest import sqrtdenest +from sympy.simplify.trigsimp import trigsimp, exptrigsimp +from sympy.utilities.decorator import deprecated +from sympy.utilities.iterables import has_variety, sift, subsets, iterable +from sympy.utilities.misc import as_int + +import mpmath + + +def separatevars(expr, symbols=[], dict=False, force=False): + """ + Separates variables in an expression, if possible. By + default, it separates with respect to all symbols in an + expression and collects constant coefficients that are + independent of symbols. + + Explanation + =========== + + If ``dict=True`` then the separated terms will be returned + in a dictionary keyed to their corresponding symbols. + By default, all symbols in the expression will appear as + keys; if symbols are provided, then all those symbols will + be used as keys, and any terms in the expression containing + other symbols or non-symbols will be returned keyed to the + string 'coeff'. (Passing None for symbols will return the + expression in a dictionary keyed to 'coeff'.) + + If ``force=True``, then bases of powers will be separated regardless + of assumptions on the symbols involved. + + Notes + ===== + + The order of the factors is determined by Mul, so that the + separated expressions may not necessarily be grouped together. + + Although factoring is necessary to separate variables in some + expressions, it is not necessary in all cases, so one should not + count on the returned factors being factored. + + Examples + ======== + + >>> from sympy.abc import x, y, z, alpha + >>> from sympy import separatevars, sin + >>> separatevars((x*y)**y) + (x*y)**y + >>> separatevars((x*y)**y, force=True) + x**y*y**y + + >>> e = 2*x**2*z*sin(y)+2*z*x**2 + >>> separatevars(e) + 2*x**2*z*(sin(y) + 1) + >>> separatevars(e, symbols=(x, y), dict=True) + {'coeff': 2*z, x: x**2, y: sin(y) + 1} + >>> separatevars(e, [x, y, alpha], dict=True) + {'coeff': 2*z, alpha: 1, x: x**2, y: sin(y) + 1} + + If the expression is not really separable, or is only partially + separable, separatevars will do the best it can to separate it + by using factoring. + + >>> separatevars(x + x*y - 3*x**2) + -x*(3*x - y - 1) + + If the expression is not separable then expr is returned unchanged + or (if dict=True) then None is returned. + + >>> eq = 2*x + y*sin(x) + >>> separatevars(eq) == eq + True + >>> separatevars(2*x + y*sin(x), symbols=(x, y), dict=True) is None + True + + """ + expr = sympify(expr) + if dict: + return _separatevars_dict(_separatevars(expr, force), symbols) + else: + return _separatevars(expr, force) + + +def _separatevars(expr, force): + if isinstance(expr, Abs): + arg = expr.args[0] + if arg.is_Mul and not arg.is_number: + s = separatevars(arg, dict=True, force=force) + if s is not None: + return Mul(*map(expr.func, s.values())) + else: + return expr + + if len(expr.free_symbols) < 2: + return expr + + # don't destroy a Mul since much of the work may already be done + if expr.is_Mul: + args = list(expr.args) + changed = False + for i, a in enumerate(args): + args[i] = separatevars(a, force) + changed = changed or args[i] != a + if changed: + expr = expr.func(*args) + return expr + + # get a Pow ready for expansion + if expr.is_Pow and expr.base != S.Exp1: + expr = Pow(separatevars(expr.base, force=force), expr.exp) + + # First try other expansion methods + expr = expr.expand(mul=False, multinomial=False, force=force) + + _expr, reps = posify(expr) if force else (expr, {}) + expr = factor(_expr).subs(reps) + + if not expr.is_Add: + return expr + + # Find any common coefficients to pull out + args = list(expr.args) + commonc = args[0].args_cnc(cset=True, warn=False)[0] + for i in args[1:]: + commonc &= i.args_cnc(cset=True, warn=False)[0] + commonc = Mul(*commonc) + commonc = commonc.as_coeff_Mul()[1] # ignore constants + commonc_set = commonc.args_cnc(cset=True, warn=False)[0] + + # remove them + for i, a in enumerate(args): + c, nc = a.args_cnc(cset=True, warn=False) + c = c - commonc_set + args[i] = Mul(*c)*Mul(*nc) + nonsepar = Add(*args) + + if len(nonsepar.free_symbols) > 1: + _expr = nonsepar + _expr, reps = posify(_expr) if force else (_expr, {}) + _expr = (factor(_expr)).subs(reps) + + if not _expr.is_Add: + nonsepar = _expr + + return commonc*nonsepar + + +def _separatevars_dict(expr, symbols): + if symbols: + if not all(t.is_Atom for t in symbols): + raise ValueError("symbols must be Atoms.") + symbols = list(symbols) + elif symbols is None: + return {'coeff': expr} + else: + symbols = list(expr.free_symbols) + if not symbols: + return None + + ret = {i: [] for i in symbols + ['coeff']} + + for i in Mul.make_args(expr): + expsym = i.free_symbols + intersection = set(symbols).intersection(expsym) + if len(intersection) > 1: + return None + if len(intersection) == 0: + # There are no symbols, so it is part of the coefficient + ret['coeff'].append(i) + else: + ret[intersection.pop()].append(i) + + # rebuild + for k, v in ret.items(): + ret[k] = Mul(*v) + + return ret + + +def posify(eq): + """Return ``eq`` (with generic symbols made positive) and a + dictionary containing the mapping between the old and new + symbols. + + Explanation + =========== + + Any symbol that has positive=None will be replaced with a positive dummy + symbol having the same name. This replacement will allow more symbolic + processing of expressions, especially those involving powers and + logarithms. + + A dictionary that can be sent to subs to restore ``eq`` to its original + symbols is also returned. + + >>> from sympy import posify, Symbol, log, solve + >>> from sympy.abc import x + >>> posify(x + Symbol('p', positive=True) + Symbol('n', negative=True)) + (_x + n + p, {_x: x}) + + >>> eq = 1/x + >>> log(eq).expand() + log(1/x) + >>> log(posify(eq)[0]).expand() + -log(_x) + >>> p, rep = posify(eq) + >>> log(p).expand().subs(rep) + -log(x) + + It is possible to apply the same transformations to an iterable + of expressions: + + >>> eq = x**2 - 4 + >>> solve(eq, x) + [-2, 2] + >>> eq_x, reps = posify([eq, x]); eq_x + [_x**2 - 4, _x] + >>> solve(*eq_x) + [2] + """ + eq = sympify(eq) + if not isinstance(eq, Basic) and iterable(eq): + f = type(eq) + eq = list(eq) + syms = set() + for e in eq: + syms = syms.union(e.atoms(Symbol)) + reps = {} + for s in syms: + reps.update({v: k for k, v in posify(s)[1].items()}) + for i, e in enumerate(eq): + eq[i] = e.subs(reps) + return f(eq), {r: s for s, r in reps.items()} + + reps = {s: Dummy(s.name, positive=True, **s.assumptions0) + for s in eq.free_symbols if s.is_positive is None} + eq = eq.subs(reps) + return eq, {r: s for s, r in reps.items()} + + +def hypersimp(f, k): + """Given combinatorial term f(k) simplify its consecutive term ratio + i.e. f(k+1)/f(k). The input term can be composed of functions and + integer sequences which have equivalent representation in terms + of gamma special function. + + Explanation + =========== + + The algorithm performs three basic steps: + + 1. Rewrite all functions in terms of gamma, if possible. + + 2. Rewrite all occurrences of gamma in terms of products + of gamma and rising factorial with integer, absolute + constant exponent. + + 3. Perform simplification of nested fractions, powers + and if the resulting expression is a quotient of + polynomials, reduce their total degree. + + If f(k) is hypergeometric then as result we arrive with a + quotient of polynomials of minimal degree. Otherwise None + is returned. + + For more information on the implemented algorithm refer to: + + 1. W. Koepf, Algorithms for m-fold Hypergeometric Summation, + Journal of Symbolic Computation (1995) 20, 399-417 + """ + f = sympify(f) + + g = f.subs(k, k + 1) / f + + g = g.rewrite(gamma) + if g.has(Piecewise): + g = piecewise_fold(g) + g = g.args[-1][0] + g = expand_func(g) + g = powsimp(g, deep=True, combine='exp') + + if g.is_rational_function(k): + return simplify(g, ratio=S.Infinity) + else: + return None + + +def hypersimilar(f, g, k): + """ + Returns True if ``f`` and ``g`` are hyper-similar. + + Explanation + =========== + + Similarity in hypergeometric sense means that a quotient of + f(k) and g(k) is a rational function in ``k``. This procedure + is useful in solving recurrence relations. + + For more information see hypersimp(). + + """ + f, g = list(map(sympify, (f, g))) + + h = (f/g).rewrite(gamma) + h = h.expand(func=True, basic=False) + + return h.is_rational_function(k) + + +def signsimp(expr, evaluate=None): + """Make all Add sub-expressions canonical wrt sign. + + Explanation + =========== + + If an Add subexpression, ``a``, can have a sign extracted, + as determined by could_extract_minus_sign, it is replaced + with Mul(-1, a, evaluate=False). This allows signs to be + extracted from powers and products. + + Examples + ======== + + >>> from sympy import signsimp, exp, symbols + >>> from sympy.abc import x, y + >>> i = symbols('i', odd=True) + >>> n = -1 + 1/x + >>> n/x/(-n)**2 - 1/n/x + (-1 + 1/x)/(x*(1 - 1/x)**2) - 1/(x*(-1 + 1/x)) + >>> signsimp(_) + 0 + >>> x*n + x*-n + x*(-1 + 1/x) + x*(1 - 1/x) + >>> signsimp(_) + 0 + + Since powers automatically handle leading signs + + >>> (-2)**i + -2**i + + signsimp can be used to put the base of a power with an integer + exponent into canonical form: + + >>> n**i + (-1 + 1/x)**i + + By default, signsimp does not leave behind any hollow simplification: + if making an Add canonical wrt sign didn't change the expression, the + original Add is restored. If this is not desired then the keyword + ``evaluate`` can be set to False: + + >>> e = exp(y - x) + >>> signsimp(e) == e + True + >>> signsimp(e, evaluate=False) + exp(-(x - y)) + + """ + if evaluate is None: + evaluate = global_parameters.evaluate + expr = sympify(expr) + if not isinstance(expr, (Expr, Relational)) or expr.is_Atom: + return expr + # get rid of an pre-existing unevaluation regarding sign + e = expr.replace(lambda x: x.is_Mul and -(-x) != x, lambda x: -(-x)) + e = sub_post(sub_pre(e)) + if not isinstance(e, (Expr, Relational)) or e.is_Atom: + return e + if e.is_Add: + rv = e.func(*[signsimp(a) for a in e.args]) + if not evaluate and isinstance(rv, Add + ) and rv.could_extract_minus_sign(): + return Mul(S.NegativeOne, -rv, evaluate=False) + return rv + if evaluate: + e = e.replace(lambda x: x.is_Mul and -(-x) != x, lambda x: -(-x)) + return e + + +@overload +def simplify(expr: Expr, **kwargs) -> Expr: ... +@overload +def simplify(expr: Boolean, **kwargs) -> Boolean: ... +@overload +def simplify(expr: Set, **kwargs) -> Set: ... +@overload +def simplify(expr: Basic, **kwargs) -> Basic: ... + +def simplify(expr, ratio=1.7, measure=count_ops, rational=False, inverse=False, doit=True, **kwargs): + """Simplifies the given expression. + + Explanation + =========== + + Simplification is not a well defined term and the exact strategies + this function tries can change in the future versions of SymPy. If + your algorithm relies on "simplification" (whatever it is), try to + determine what you need exactly - is it powsimp()?, radsimp()?, + together()?, logcombine()?, or something else? And use this particular + function directly, because those are well defined and thus your algorithm + will be robust. + + Nonetheless, especially for interactive use, or when you do not know + anything about the structure of the expression, simplify() tries to apply + intelligent heuristics to make the input expression "simpler". For + example: + + >>> from sympy import simplify, cos, sin + >>> from sympy.abc import x, y + >>> a = (x + x**2)/(x*sin(y)**2 + x*cos(y)**2) + >>> a + (x**2 + x)/(x*sin(y)**2 + x*cos(y)**2) + >>> simplify(a) + x + 1 + + Note that we could have obtained the same result by using specific + simplification functions: + + >>> from sympy import trigsimp, cancel + >>> trigsimp(a) + (x**2 + x)/x + >>> cancel(_) + x + 1 + + In some cases, applying :func:`simplify` may actually result in some more + complicated expression. The default ``ratio=1.7`` prevents more extreme + cases: if (result length)/(input length) > ratio, then input is returned + unmodified. The ``measure`` parameter lets you specify the function used + to determine how complex an expression is. The function should take a + single argument as an expression and return a number such that if + expression ``a`` is more complex than expression ``b``, then + ``measure(a) > measure(b)``. The default measure function is + :func:`~.count_ops`, which returns the total number of operations in the + expression. + + For example, if ``ratio=1``, ``simplify`` output cannot be longer + than input. + + :: + + >>> from sympy import sqrt, simplify, count_ops, oo + >>> root = 1/(sqrt(2)+3) + + Since ``simplify(root)`` would result in a slightly longer expression, + root is returned unchanged instead:: + + >>> simplify(root, ratio=1) == root + True + + If ``ratio=oo``, simplify will be applied anyway:: + + >>> count_ops(simplify(root, ratio=oo)) > count_ops(root) + True + + Note that the shortest expression is not necessary the simplest, so + setting ``ratio`` to 1 may not be a good idea. + Heuristically, the default value ``ratio=1.7`` seems like a reasonable + choice. + + You can easily define your own measure function based on what you feel + should represent the "size" or "complexity" of the input expression. Note + that some choices, such as ``lambda expr: len(str(expr))`` may appear to be + good metrics, but have other problems (in this case, the measure function + may slow down simplify too much for very large expressions). If you do not + know what a good metric would be, the default, ``count_ops``, is a good + one. + + For example: + + >>> from sympy import symbols, log + >>> a, b = symbols('a b', positive=True) + >>> g = log(a) + log(b) + log(a)*log(1/b) + >>> h = simplify(g) + >>> h + log(a*b**(1 - log(a))) + >>> count_ops(g) + 8 + >>> count_ops(h) + 5 + + So you can see that ``h`` is simpler than ``g`` using the count_ops metric. + However, we may not like how ``simplify`` (in this case, using + ``logcombine``) has created the ``b**(log(1/a) + 1)`` term. A simple way + to reduce this would be to give more weight to powers as operations in + ``count_ops``. We can do this by using the ``visual=True`` option: + + >>> print(count_ops(g, visual=True)) + 2*ADD + DIV + 4*LOG + MUL + >>> print(count_ops(h, visual=True)) + 2*LOG + MUL + POW + SUB + + >>> from sympy import Symbol, S + >>> def my_measure(expr): + ... POW = Symbol('POW') + ... # Discourage powers by giving POW a weight of 10 + ... count = count_ops(expr, visual=True).subs(POW, 10) + ... # Every other operation gets a weight of 1 (the default) + ... count = count.replace(Symbol, type(S.One)) + ... return count + >>> my_measure(g) + 8 + >>> my_measure(h) + 14 + >>> 15./8 > 1.7 # 1.7 is the default ratio + True + >>> simplify(g, measure=my_measure) + -log(a)*log(b) + log(a) + log(b) + + Note that because ``simplify()`` internally tries many different + simplification strategies and then compares them using the measure + function, we get a completely different result that is still different + from the input expression by doing this. + + If ``rational=True``, Floats will be recast as Rationals before simplification. + If ``rational=None``, Floats will be recast as Rationals but the result will + be recast as Floats. If rational=False(default) then nothing will be done + to the Floats. + + If ``inverse=True``, it will be assumed that a composition of inverse + functions, such as sin and asin, can be cancelled in any order. + For example, ``asin(sin(x))`` will yield ``x`` without checking whether + x belongs to the set where this relation is true. The default is + False. + + Note that ``simplify()`` automatically calls ``doit()`` on the final + expression. You can avoid this behavior by passing ``doit=False`` as + an argument. + + Also, it should be noted that simplifying a boolean expression is not + well defined. If the expression prefers automatic evaluation (such as + :obj:`~.Eq()` or :obj:`~.Or()`), simplification will return ``True`` or + ``False`` if truth value can be determined. If the expression is not + evaluated by default (such as :obj:`~.Predicate()`), simplification will + not reduce it and you should use :func:`~.refine` or :func:`~.ask` + function. This inconsistency will be resolved in future version. + + See Also + ======== + + sympy.assumptions.refine.refine : Simplification using assumptions. + sympy.assumptions.ask.ask : Query for boolean expressions using assumptions. + """ + + def shorter(*choices): + """ + Return the choice that has the fewest ops. In case of a tie, + the expression listed first is selected. + """ + if not has_variety(choices): + return choices[0] + return min(choices, key=measure) + + def done(e): + rv = e.doit() if doit else e + return shorter(rv, collect_abs(rv)) + + expr = sympify(expr, rational=rational) + kwargs = { + "ratio": kwargs.get('ratio', ratio), + "measure": kwargs.get('measure', measure), + "rational": kwargs.get('rational', rational), + "inverse": kwargs.get('inverse', inverse), + "doit": kwargs.get('doit', doit)} + # no routine for Expr needs to check for is_zero + if isinstance(expr, Expr) and expr.is_zero: + return S.Zero if not expr.is_Number else expr + + _eval_simplify = getattr(expr, '_eval_simplify', None) + if _eval_simplify is not None: + return _eval_simplify(**kwargs) + + original_expr = expr = collect_abs(signsimp(expr)) + + if not isinstance(expr, Basic) or not expr.args: # XXX: temporary hack + return expr + + if inverse and expr.has(Function): + expr = inversecombine(expr) + if not expr.args: # simplified to atomic + return expr + + # do deep simplification + handled = Add, Mul, Pow, ExpBase + expr = expr.replace( + # here, checking for x.args is not enough because Basic has + # args but Basic does not always play well with replace, e.g. + # when simultaneous is True found expressions will be masked + # off with a Dummy but not all Basic objects in an expression + # can be replaced with a Dummy + lambda x: isinstance(x, Expr) and x.args and not isinstance( + x, handled), + lambda x: x.func(*[simplify(i, **kwargs) for i in x.args]), + simultaneous=False) + if not isinstance(expr, handled): + return done(expr) + + if not expr.is_commutative: + expr = nc_simplify(expr) + + # TODO: Apply different strategies, considering expression pattern: + # is it a purely rational function? Is there any trigonometric function?... + # See also https://github.com/sympy/sympy/pull/185. + + # rationalize Floats + floats = False + if rational is not False and expr.has(Float): + floats = True + expr = nsimplify(expr, rational=True) + + expr = _bottom_up(expr, lambda w: getattr(w, 'normal', lambda: w)()) + expr = Mul(*powsimp(expr).as_content_primitive()) + _e = cancel(expr) + expr1 = shorter(_e, _mexpand(_e).cancel()) # issue 6829 + expr2 = shorter(together(expr, deep=True), together(expr1, deep=True)) + + if ratio is S.Infinity: + expr = expr2 + else: + expr = shorter(expr2, expr1, expr) + if not isinstance(expr, Basic): # XXX: temporary hack + return expr + + expr = factor_terms(expr, sign=False) + + # must come before `Piecewise` since this introduces more `Piecewise` terms + if expr.has(sign): + expr = expr.rewrite(Abs) + + # Deal with Piecewise separately to avoid recursive growth of expressions + if expr.has(Piecewise): + # Fold into a single Piecewise + expr = piecewise_fold(expr) + # Apply doit, if doit=True + expr = done(expr) + # Still a Piecewise? + if expr.has(Piecewise): + # Fold into a single Piecewise, in case doit lead to some + # expressions being Piecewise + expr = piecewise_fold(expr) + # kroneckersimp also affects Piecewise + if expr.has(KroneckerDelta): + expr = kroneckersimp(expr) + # Still a Piecewise? + if expr.has(Piecewise): + # Do not apply doit on the segments as it has already + # been done above, but simplify + expr = piecewise_simplify(expr, deep=True, doit=False) + # Still a Piecewise? + if expr.has(Piecewise): + # Try factor common terms + expr = shorter(expr, factor_terms(expr)) + # As all expressions have been simplified above with the + # complete simplify, nothing more needs to be done here + return expr + + # hyperexpand automatically only works on hypergeometric terms + # Do this after the Piecewise part to avoid recursive expansion + expr = hyperexpand(expr) + + if expr.has(KroneckerDelta): + expr = kroneckersimp(expr) + + if expr.has(BesselBase): + expr = besselsimp(expr) + + if expr.has(TrigonometricFunction, HyperbolicFunction): + expr = trigsimp(expr, deep=True) + + if expr.has(log): + expr = shorter(expand_log(expr, deep=True), logcombine(expr)) + + if expr.has(CombinatorialFunction, gamma): + # expression with gamma functions or non-integer arguments is + # automatically passed to gammasimp + expr = combsimp(expr) + + if expr.has(Sum): + expr = sum_simplify(expr, **kwargs) + + if expr.has(Integral): + expr = expr.xreplace({ + i: factor_terms(i) for i in expr.atoms(Integral)}) + + if expr.has(Product): + expr = product_simplify(expr, **kwargs) + + from sympy.physics.units import Quantity + + if expr.has(Quantity): + from sympy.physics.units.util import quantity_simplify + expr = quantity_simplify(expr) + + short = shorter(powsimp(expr, combine='exp', deep=True), powsimp(expr), expr) + short = shorter(short, cancel(short)) + short = shorter(short, factor_terms(short), expand_power_exp(expand_mul(short))) + if short.has(TrigonometricFunction, HyperbolicFunction, ExpBase, exp): + short = exptrigsimp(short) + + # get rid of hollow 2-arg Mul factorization + hollow_mul = Transform( + lambda x: Mul(*x.args), + lambda x: + x.is_Mul and + len(x.args) == 2 and + x.args[0].is_Number and + x.args[1].is_Add and + x.is_commutative) + expr = short.xreplace(hollow_mul) + + numer, denom = expr.as_numer_denom() + if denom.is_Add: + n, d = fraction(radsimp(1/denom, symbolic=False, max_terms=1)) + if n is not S.One: + expr = (numer*n).expand()/d + + if expr.could_extract_minus_sign(): + n, d = fraction(expr) + if d != 0: + expr = signsimp(-n/(-d)) + + if measure(expr) > ratio*measure(original_expr): + expr = original_expr + + # restore floats + if floats and rational is None: + expr = nfloat(expr, exponent=False) + + return done(expr) + + +def sum_simplify(s, **kwargs): + """Main function for Sum simplification""" + if not isinstance(s, Add): + s = s.xreplace({a: sum_simplify(a, **kwargs) + for a in s.atoms(Add) if a.has(Sum)}) + s = expand(s) + if not isinstance(s, Add): + return s + + terms = s.args + s_t = [] # Sum Terms + o_t = [] # Other Terms + + for term in terms: + sum_terms, other = sift(Mul.make_args(term), + lambda i: isinstance(i, Sum), binary=True) + if not sum_terms: + o_t.append(term) + continue + other = [Mul(*other)] + s_t.append(Mul(*(other + [s._eval_simplify(**kwargs) for s in sum_terms]))) + + result = Add(sum_combine(s_t), *o_t) + + return result + + +def sum_combine(s_t): + """Helper function for Sum simplification + + Attempts to simplify a list of sums, by combining limits / sum function's + returns the simplified sum + """ + used = [False] * len(s_t) + + for method in range(2): + for i, s_term1 in enumerate(s_t): + if not used[i]: + for j, s_term2 in enumerate(s_t): + if not used[j] and i != j: + temp = sum_add(s_term1, s_term2, method) + if isinstance(temp, (Sum, Mul)): + s_t[i] = temp + s_term1 = s_t[i] + used[j] = True + + result = S.Zero + for i, s_term in enumerate(s_t): + if not used[i]: + result = Add(result, s_term) + + return result + +def factor_sum(self, limits=None, radical=False, clear=False, fraction=False, sign=True): + """Return Sum with constant factors extracted. + + If ``limits`` is specified then ``self`` is the summand; the other + keywords are passed to ``factor_terms``. + + Examples + ======== + + >>> from sympy import Sum + >>> from sympy.abc import x, y + >>> from sympy.simplify.simplify import factor_sum + >>> s = Sum(x*y, (x, 1, 3)) + >>> factor_sum(s) + y*Sum(x, (x, 1, 3)) + >>> factor_sum(s.function, s.limits) + y*Sum(x, (x, 1, 3)) + """ + + # XXX deprecate in favor of direct call to factor_terms + kwargs = {"radical": radical, "clear": clear, + "fraction": fraction, "sign": sign} + expr = Sum(self, *limits) if limits else self + return factor_terms(expr, **kwargs) + + +def sum_add(self, other, method=0): + """Helper function for Sum simplification""" + #we know this is something in terms of a constant * a sum + #so we temporarily put the constants inside for simplification + #then simplify the result + def __refactor(val): + args = Mul.make_args(val) + sumv = next(x for x in args if isinstance(x, Sum)) + constant = Mul(*[x for x in args if x != sumv]) + return Sum(constant * sumv.function, *sumv.limits) + + if isinstance(self, Mul): + rself = __refactor(self) + else: + rself = self + + if isinstance(other, Mul): + rother = __refactor(other) + else: + rother = other + + if type(rself) is type(rother): + if method == 0: + if rself.limits == rother.limits: + return factor_sum(Sum(rself.function + rother.function, *rself.limits)) + elif method == 1: + if simplify(rself.function - rother.function) == 0: + if len(rself.limits) == len(rother.limits) == 1: + i = rself.limits[0][0] + x1 = rself.limits[0][1] + y1 = rself.limits[0][2] + j = rother.limits[0][0] + x2 = rother.limits[0][1] + y2 = rother.limits[0][2] + + if i == j: + if x2 == y1 + 1: + return factor_sum(Sum(rself.function, (i, x1, y2))) + elif x1 == y2 + 1: + return factor_sum(Sum(rself.function, (i, x2, y1))) + + return Add(self, other) + + +def product_simplify(s, **kwargs): + """Main function for Product simplification""" + terms = Mul.make_args(s) + p_t = [] # Product Terms + o_t = [] # Other Terms + + deep = kwargs.get('deep', True) + for term in terms: + if isinstance(term, Product): + if deep: + p_t.append(Product(term.function.simplify(**kwargs), + *term.limits)) + else: + p_t.append(term) + else: + o_t.append(term) + + used = [False] * len(p_t) + + for method in range(2): + for i, p_term1 in enumerate(p_t): + if not used[i]: + for j, p_term2 in enumerate(p_t): + if not used[j] and i != j: + tmp_prod = product_mul(p_term1, p_term2, method) + if isinstance(tmp_prod, Product): + p_t[i] = tmp_prod + used[j] = True + + result = Mul(*o_t) + + for i, p_term in enumerate(p_t): + if not used[i]: + result = Mul(result, p_term) + + return result + + +def product_mul(self, other, method=0): + """Helper function for Product simplification""" + if type(self) is type(other): + if method == 0: + if self.limits == other.limits: + return Product(self.function * other.function, *self.limits) + elif method == 1: + if simplify(self.function - other.function) == 0: + if len(self.limits) == len(other.limits) == 1: + i = self.limits[0][0] + x1 = self.limits[0][1] + y1 = self.limits[0][2] + j = other.limits[0][0] + x2 = other.limits[0][1] + y2 = other.limits[0][2] + + if i == j: + if x2 == y1 + 1: + return Product(self.function, (i, x1, y2)) + elif x1 == y2 + 1: + return Product(self.function, (i, x2, y1)) + + return Mul(self, other) + + +def _nthroot_solve(p, n, prec): + """ + helper function for ``nthroot`` + It denests ``p**Rational(1, n)`` using its minimal polynomial + """ + from sympy.solvers import solve + while n % 2 == 0: + p = sqrtdenest(sqrt(p)) + n = n // 2 + if n == 1: + return p + pn = p**Rational(1, n) + x = Symbol('x') + f = _minimal_polynomial_sq(p, n, x) + if f is None: + return None + sols = solve(f, x) + for sol in sols: + if abs(sol - pn).n() < 1./10**prec: + sol = sqrtdenest(sol) + if _mexpand(sol**n) == p: + return sol + + +def logcombine(expr, force=False): + """ + Takes logarithms and combines them using the following rules: + + - log(x) + log(y) == log(x*y) if both are positive + - a*log(x) == log(x**a) if x is positive and a is real + + If ``force`` is ``True`` then the assumptions above will be assumed to hold if + there is no assumption already in place on a quantity. For example, if + ``a`` is imaginary or the argument negative, force will not perform a + combination but if ``a`` is a symbol with no assumptions the change will + take place. + + Examples + ======== + + >>> from sympy import Symbol, symbols, log, logcombine, I + >>> from sympy.abc import a, x, y, z + >>> logcombine(a*log(x) + log(y) - log(z)) + a*log(x) + log(y) - log(z) + >>> logcombine(a*log(x) + log(y) - log(z), force=True) + log(x**a*y/z) + >>> x,y,z = symbols('x,y,z', positive=True) + >>> a = Symbol('a', real=True) + >>> logcombine(a*log(x) + log(y) - log(z)) + log(x**a*y/z) + + The transformation is limited to factors and/or terms that + contain logs, so the result depends on the initial state of + expansion: + + >>> eq = (2 + 3*I)*log(x) + >>> logcombine(eq, force=True) == eq + True + >>> logcombine(eq.expand(), force=True) + log(x**2) + I*log(x**3) + + See Also + ======== + + posify: replace all symbols with symbols having positive assumptions + sympy.core.function.expand_log: expand the logarithms of products + and powers; the opposite of logcombine + + """ + + def f(rv): + if not (rv.is_Add or rv.is_Mul): + return rv + + def gooda(a): + # bool to tell whether the leading ``a`` in ``a*log(x)`` + # could appear as log(x**a) + return (a is not S.NegativeOne and # -1 *could* go, but we disallow + (a.is_extended_real or force and a.is_extended_real is not False)) + + def goodlog(l): + # bool to tell whether log ``l``'s argument can combine with others + a = l.args[0] + return a.is_positive or force and a.is_nonpositive is not False + + other = [] + logs = [] + log1 = defaultdict(list) + for a in Add.make_args(rv): + if isinstance(a, log) and goodlog(a): + log1[()].append(([], a)) + elif not a.is_Mul: + other.append(a) + else: + ot = [] + co = [] + lo = [] + for ai in a.args: + if ai.is_Rational and ai < 0: + ot.append(S.NegativeOne) + co.append(-ai) + elif isinstance(ai, log) and goodlog(ai): + lo.append(ai) + elif gooda(ai): + co.append(ai) + else: + ot.append(ai) + if len(lo) > 1: + logs.append((ot, co, lo)) + elif lo: + log1[tuple(ot)].append((co, lo[0])) + else: + other.append(a) + + # if there is only one log in other, put it with the + # good logs + if len(other) == 1 and isinstance(other[0], log): + log1[()].append(([], other.pop())) + # if there is only one log at each coefficient and none have + # an exponent to place inside the log then there is nothing to do + if not logs and all(len(log1[k]) == 1 and log1[k][0] == [] for k in log1): + return rv + + # collapse multi-logs as far as possible in a canonical way + # TODO: see if x*log(a)+x*log(a)*log(b) -> x*log(a)*(1+log(b))? + # -- in this case, it's unambiguous, but if it were were a log(c) in + # each term then it's arbitrary whether they are grouped by log(a) or + # by log(c). So for now, just leave this alone; it's probably better to + # let the user decide + for o, e, l in logs: + l = list(ordered(l)) + e = log(l.pop(0).args[0]**Mul(*e)) + while l: + li = l.pop(0) + e = log(li.args[0]**e) + c, l = Mul(*o), e + if isinstance(l, log): # it should be, but check to be sure + log1[(c,)].append(([], l)) + else: + other.append(c*l) + + # logs that have the same coefficient can multiply + for k in list(log1.keys()): + log1[Mul(*k)] = log(logcombine(Mul(*[ + l.args[0]**Mul(*c) for c, l in log1.pop(k)]), + force=force), evaluate=False) + + # logs that have oppositely signed coefficients can divide + for k in ordered(list(log1.keys())): + if k not in log1: # already popped as -k + continue + if -k in log1: + # figure out which has the minus sign; the one with + # more op counts should be the one + num, den = k, -k + if num.count_ops() > den.count_ops(): + num, den = den, num + other.append( + num*log(log1.pop(num).args[0]/log1.pop(den).args[0], + evaluate=False)) + else: + other.append(k*log1.pop(k)) + + return Add(*other) + + return _bottom_up(expr, f) + + +def inversecombine(expr): + """Simplify the composition of a function and its inverse. + + Explanation + =========== + + No attention is paid to whether the inverse is a left inverse or a + right inverse; thus, the result will in general not be equivalent + to the original expression. + + Examples + ======== + + >>> from sympy.simplify.simplify import inversecombine + >>> from sympy import asin, sin, log, exp + >>> from sympy.abc import x + >>> inversecombine(asin(sin(x))) + x + >>> inversecombine(2*log(exp(3*x))) + 6*x + """ + + def f(rv): + if isinstance(rv, log): + if isinstance(rv.args[0], exp) or (rv.args[0].is_Pow and rv.args[0].base == S.Exp1): + rv = rv.args[0].exp + elif rv.is_Function and hasattr(rv, "inverse"): + if (len(rv.args) == 1 and len(rv.args[0].args) == 1 and + isinstance(rv.args[0], rv.inverse(argindex=1))): + rv = rv.args[0].args[0] + if rv.is_Pow and rv.base == S.Exp1: + if isinstance(rv.exp, log): + rv = rv.exp.args[0] + return rv + + return _bottom_up(expr, f) + + +def kroneckersimp(expr): + """ + Simplify expressions with KroneckerDelta. + + The only simplification currently attempted is to identify multiplicative cancellation: + + Examples + ======== + + >>> from sympy import KroneckerDelta, kroneckersimp + >>> from sympy.abc import i + >>> kroneckersimp(1 + KroneckerDelta(0, i) * KroneckerDelta(1, i)) + 1 + """ + def args_cancel(args1, args2): + for i1 in range(2): + for i2 in range(2): + a1 = args1[i1] + a2 = args2[i2] + a3 = args1[(i1 + 1) % 2] + a4 = args2[(i2 + 1) % 2] + if Eq(a1, a2) is S.true and Eq(a3, a4) is S.false: + return True + return False + + def cancel_kronecker_mul(m): + args = m.args + deltas = [a for a in args if isinstance(a, KroneckerDelta)] + for delta1, delta2 in subsets(deltas, 2): + args1 = delta1.args + args2 = delta2.args + if args_cancel(args1, args2): + return S.Zero * m # In case of oo etc + return m + + if not expr.has(KroneckerDelta): + return expr + + if expr.has(Piecewise): + expr = expr.rewrite(KroneckerDelta) + + newexpr = expr + expr = None + + while newexpr != expr: + expr = newexpr + newexpr = expr.replace(lambda e: isinstance(e, Mul), cancel_kronecker_mul) + + return expr + + +def besselsimp(expr): + """ + Simplify bessel-type functions. + + Explanation + =========== + + This routine tries to simplify bessel-type functions. Currently it only + works on the Bessel J and I functions, however. It works by looking at all + such functions in turn, and eliminating factors of "I" and "-1" (actually + their polar equivalents) in front of the argument. Then, functions of + half-integer order are rewritten using trigonometric functions and + functions of integer order (> 1) are rewritten using functions + of low order. Finally, if the expression was changed, compute + factorization of the result with factor(). + + >>> from sympy import besselj, besseli, besselsimp, polar_lift, I, S + >>> from sympy.abc import z, nu + >>> besselsimp(besselj(nu, z*polar_lift(-1))) + exp(I*pi*nu)*besselj(nu, z) + >>> besselsimp(besseli(nu, z*polar_lift(-I))) + exp(-I*pi*nu/2)*besselj(nu, z) + >>> besselsimp(besseli(S(-1)/2, z)) + sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) + >>> besselsimp(z*besseli(0, z) + z*(besseli(2, z))/2 + besseli(1, z)) + 3*z*besseli(0, z)/2 + """ + # TODO + # - better algorithm? + # - simplify (cos(pi*b)*besselj(b,z) - besselj(-b,z))/sin(pi*b) ... + # - use contiguity relations? + + def replacer(fro, to, factors): + factors = set(factors) + + def repl(nu, z): + if factors.intersection(Mul.make_args(z)): + return to(nu, z) + return fro(nu, z) + return repl + + def torewrite(fro, to): + def tofunc(nu, z): + return fro(nu, z).rewrite(to) + return tofunc + + def tominus(fro): + def tofunc(nu, z): + return exp(I*pi*nu)*fro(nu, exp_polar(-I*pi)*z) + return tofunc + + orig_expr = expr + + ifactors = [I, exp_polar(I*pi/2), exp_polar(-I*pi/2)] + expr = expr.replace( + besselj, replacer(besselj, + torewrite(besselj, besseli), ifactors)) + expr = expr.replace( + besseli, replacer(besseli, + torewrite(besseli, besselj), ifactors)) + + minusfactors = [-1, exp_polar(I*pi)] + expr = expr.replace( + besselj, replacer(besselj, tominus(besselj), minusfactors)) + expr = expr.replace( + besseli, replacer(besseli, tominus(besseli), minusfactors)) + + z0 = Dummy('z') + + def expander(fro): + def repl(nu, z): + if (nu % 1) == S.Half: + return simplify(trigsimp(unpolarify( + fro(nu, z0).rewrite(besselj).rewrite(jn).expand( + func=True)).subs(z0, z))) + elif nu.is_Integer and nu > 1: + return fro(nu, z).expand(func=True) + return fro(nu, z) + return repl + + expr = expr.replace(besselj, expander(besselj)) + expr = expr.replace(bessely, expander(bessely)) + expr = expr.replace(besseli, expander(besseli)) + expr = expr.replace(besselk, expander(besselk)) + + def _bessel_simp_recursion(expr): + + def _use_recursion(bessel, expr): + while True: + bessels = expr.find(lambda x: isinstance(x, bessel)) + try: + for ba in sorted(bessels, key=lambda x: re(x.args[0])): + a, x = ba.args + bap1 = bessel(a+1, x) + bap2 = bessel(a+2, x) + if expr.has(bap1) and expr.has(bap2): + expr = expr.subs(ba, 2*(a+1)/x*bap1 - bap2) + break + else: + return expr + except (ValueError, TypeError): + return expr + if expr.has(besselj): + expr = _use_recursion(besselj, expr) + if expr.has(bessely): + expr = _use_recursion(bessely, expr) + return expr + + expr = _bessel_simp_recursion(expr) + if expr != orig_expr: + expr = expr.factor() + + return expr + + +def nthroot(expr, n, max_len=4, prec=15): + """ + Compute a real nth-root of a sum of surds. + + Parameters + ========== + + expr : sum of surds + n : integer + max_len : maximum number of surds passed as constants to ``nsimplify`` + + Algorithm + ========= + + First ``nsimplify`` is used to get a candidate root; if it is not a + root the minimal polynomial is computed; the answer is one of its + roots. + + Examples + ======== + + >>> from sympy.simplify.simplify import nthroot + >>> from sympy import sqrt + >>> nthroot(90 + 34*sqrt(7), 3) + sqrt(7) + 3 + + """ + expr = sympify(expr) + n = sympify(n) + p = expr**Rational(1, n) + if not n.is_integer: + return p + if not _is_sum_surds(expr): + return p + surds = [] + coeff_muls = [x.as_coeff_Mul() for x in expr.args] + for x, y in coeff_muls: + if not x.is_rational: + return p + if y is S.One: + continue + if not (y.is_Pow and y.exp == S.Half and y.base.is_integer): + return p + surds.append(y) + surds.sort() + surds = surds[:max_len] + if expr < 0 and n % 2 == 1: + p = (-expr)**Rational(1, n) + a = nsimplify(p, constants=surds) + res = a if _mexpand(a**n) == _mexpand(-expr) else p + return -res + a = nsimplify(p, constants=surds) + if _mexpand(a) is not _mexpand(p) and _mexpand(a**n) == _mexpand(expr): + return _mexpand(a) + expr = _nthroot_solve(expr, n, prec) + if expr is None: + return p + return expr + + +def nsimplify(expr, constants=(), tolerance=None, full=False, rational=None, + rational_conversion='base10'): + """ + Find a simple representation for a number or, if there are free symbols or + if ``rational=True``, then replace Floats with their Rational equivalents. If + no change is made and rational is not False then Floats will at least be + converted to Rationals. + + Explanation + =========== + + For numerical expressions, a simple formula that numerically matches the + given numerical expression is sought (and the input should be possible + to evalf to a precision of at least 30 digits). + + Optionally, a list of (rationally independent) constants to + include in the formula may be given. + + A lower tolerance may be set to find less exact matches. If no tolerance + is given then the least precise value will set the tolerance (e.g. Floats + default to 15 digits of precision, so would be tolerance=10**-15). + + With ``full=True``, a more extensive search is performed + (this is useful to find simpler numbers when the tolerance + is set low). + + When converting to rational, if rational_conversion='base10' (the default), then + convert floats to rationals using their base-10 (string) representation. + When rational_conversion='exact' it uses the exact, base-2 representation. + + Examples + ======== + + >>> from sympy import nsimplify, sqrt, GoldenRatio, exp, I, pi + >>> nsimplify(4/(1+sqrt(5)), [GoldenRatio]) + -2 + 2*GoldenRatio + >>> nsimplify((1/(exp(3*pi*I/5)+1))) + 1/2 - I*sqrt(sqrt(5)/10 + 1/4) + >>> nsimplify(I**I, [pi]) + exp(-pi/2) + >>> nsimplify(pi, tolerance=0.01) + 22/7 + + >>> nsimplify(0.333333333333333, rational=True, rational_conversion='exact') + 6004799503160655/18014398509481984 + >>> nsimplify(0.333333333333333, rational=True) + 1/3 + + See Also + ======== + + sympy.core.function.nfloat + + """ + try: + return sympify(as_int(expr)) + except (TypeError, ValueError): + pass + expr = sympify(expr).xreplace({ + Float('inf'): S.Infinity, + Float('-inf'): S.NegativeInfinity, + }) + if expr is S.Infinity or expr is S.NegativeInfinity: + return expr + if rational or expr.free_symbols: + return _real_to_rational(expr, tolerance, rational_conversion) + + # SymPy's default tolerance for Rationals is 15; other numbers may have + # lower tolerances set, so use them to pick the largest tolerance if None + # was given + if tolerance is None: + tolerance = 10**-min([15] + + [mpmath.libmp.libmpf.prec_to_dps(n._prec) + for n in expr.atoms(Float)]) + # XXX should prec be set independent of tolerance or should it be computed + # from tolerance? + prec = 30 + bprec = int(prec*3.33) + + constants_dict = {} + for constant in constants: + constant = sympify(constant) + v = constant.evalf(prec) + if not v.is_Float: + raise ValueError("constants must be real-valued") + constants_dict[str(constant)] = v._to_mpmath(bprec) + + exprval = expr.evalf(prec, chop=True) + re, im = exprval.as_real_imag() + + # safety check to make sure that this evaluated to a number + if not (re.is_Number and im.is_Number): + return expr + + def nsimplify_real(x): + orig = mpmath.mp.dps + xv = x._to_mpmath(bprec) + try: + # We'll be happy with low precision if a simple fraction + if not (tolerance or full): + mpmath.mp.dps = 15 + rat = mpmath.pslq([xv, 1]) + if rat is not None: + return Rational(-int(rat[1]), int(rat[0])) + mpmath.mp.dps = prec + newexpr = mpmath.identify(xv, constants=constants_dict, + tol=tolerance, full=full) + if not newexpr: + raise ValueError + if full: + newexpr = newexpr[0] + expr = sympify(newexpr) + if x and not expr: # don't let x become 0 + raise ValueError + if expr.is_finite is False and xv not in [mpmath.inf, mpmath.ninf]: + raise ValueError + return expr + finally: + # even though there are returns above, this is executed + # before leaving + mpmath.mp.dps = orig + try: + if re: + re = nsimplify_real(re) + if im: + im = nsimplify_real(im) + except ValueError: + if rational is None: + return _real_to_rational(expr, rational_conversion=rational_conversion) + return expr + + rv = re + im*S.ImaginaryUnit + # if there was a change or rational is explicitly not wanted + # return the value, else return the Rational representation + if rv != expr or rational is False: + return rv + return _real_to_rational(expr, rational_conversion=rational_conversion) + + +def _real_to_rational(expr, tolerance=None, rational_conversion='base10'): + """ + Replace all reals in expr with rationals. + + Examples + ======== + + >>> from sympy.simplify.simplify import _real_to_rational + >>> from sympy.abc import x + + >>> _real_to_rational(.76 + .1*x**.5) + sqrt(x)/10 + 19/25 + + If rational_conversion='base10', this uses the base-10 string. If + rational_conversion='exact', the exact, base-2 representation is used. + + >>> _real_to_rational(0.333333333333333, rational_conversion='exact') + 6004799503160655/18014398509481984 + >>> _real_to_rational(0.333333333333333) + 1/3 + + """ + expr = _sympify(expr) + inf = Float('inf') + p = expr + reps = {} + reduce_num = None + if tolerance is not None and tolerance < 1: + reduce_num = ceiling(1/tolerance) + for fl in p.atoms(Float): + key = fl + if reduce_num is not None: + r = Rational(fl).limit_denominator(reduce_num) + elif (tolerance is not None and tolerance >= 1 and + fl.is_Integer is False): + r = Rational(tolerance*round(fl/tolerance) + ).limit_denominator(int(tolerance)) + else: + if rational_conversion == 'exact': + r = Rational(fl) + reps[key] = r + continue + elif rational_conversion != 'base10': + raise ValueError("rational_conversion must be 'base10' or 'exact'") + + r = nsimplify(fl, rational=False) + # e.g. log(3).n() -> log(3) instead of a Rational + if fl and not r: + r = Rational(fl) + elif not r.is_Rational: + if fl in (inf, -inf): + r = S.ComplexInfinity + elif fl < 0: + fl = -fl + d = Pow(10, int(mpmath.log(fl)/mpmath.log(10))) + r = -Rational(str(fl/d))*d + elif fl > 0: + d = Pow(10, int(mpmath.log(fl)/mpmath.log(10))) + r = Rational(str(fl/d))*d + else: + r = S.Zero + reps[key] = r + return p.subs(reps, simultaneous=True) + + +def clear_coefficients(expr, rhs=S.Zero): + """Return `p, r` where `p` is the expression obtained when Rational + additive and multiplicative coefficients of `expr` have been stripped + away in a naive fashion (i.e. without simplification). The operations + needed to remove the coefficients will be applied to `rhs` and returned + as `r`. + + Examples + ======== + + >>> from sympy.simplify.simplify import clear_coefficients + >>> from sympy.abc import x, y + >>> from sympy import Dummy + >>> expr = 4*y*(6*x + 3) + >>> clear_coefficients(expr - 2) + (y*(2*x + 1), 1/6) + + When solving 2 or more expressions like `expr = a`, + `expr = b`, etc..., it is advantageous to provide a Dummy symbol + for `rhs` and simply replace it with `a`, `b`, etc... in `r`. + + >>> rhs = Dummy('rhs') + >>> clear_coefficients(expr, rhs) + (y*(2*x + 1), _rhs/12) + >>> _[1].subs(rhs, 2) + 1/6 + """ + was = None + free = expr.free_symbols + if expr.is_Rational: + return (S.Zero, rhs - expr) + while expr and was != expr: + was = expr + m, expr = ( + expr.as_content_primitive() + if free else + factor_terms(expr).as_coeff_Mul(rational=True)) + rhs /= m + c, expr = expr.as_coeff_Add(rational=True) + rhs -= c + expr = signsimp(expr, evaluate = False) + if expr.could_extract_minus_sign(): + expr = -expr + rhs = -rhs + return expr, rhs + +def nc_simplify(expr, deep=True): + ''' + Simplify a non-commutative expression composed of multiplication + and raising to a power by grouping repeated subterms into one power. + Priority is given to simplifications that give the fewest number + of arguments in the end (for example, in a*b*a*b*c*a*b*c simplifying + to (a*b)**2*c*a*b*c gives 5 arguments while a*b*(a*b*c)**2 has 3). + If ``expr`` is a sum of such terms, the sum of the simplified terms + is returned. + + Keyword argument ``deep`` controls whether or not subexpressions + nested deeper inside the main expression are simplified. See examples + below. Setting `deep` to `False` can save time on nested expressions + that do not need simplifying on all levels. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.simplify.simplify import nc_simplify + >>> a, b, c = symbols("a b c", commutative=False) + >>> nc_simplify(a*b*a*b*c*a*b*c) + a*b*(a*b*c)**2 + >>> expr = a**2*b*a**4*b*a**4 + >>> nc_simplify(expr) + a**2*(b*a**4)**2 + >>> nc_simplify(a*b*a*b*c**2*(a*b)**2*c**2) + ((a*b)**2*c**2)**2 + >>> nc_simplify(a*b*a*b + 2*a*c*a**2*c*a**2*c*a) + (a*b)**2 + 2*(a*c*a)**3 + >>> nc_simplify(b**-1*a**-1*(a*b)**2) + a*b + >>> nc_simplify(a**-1*b**-1*c*a) + (b*a)**(-1)*c*a + >>> expr = (a*b*a*b)**2*a*c*a*c + >>> nc_simplify(expr) + (a*b)**4*(a*c)**2 + >>> nc_simplify(expr, deep=False) + (a*b*a*b)**2*(a*c)**2 + + ''' + if isinstance(expr, MatrixExpr): + expr = expr.doit(inv_expand=False) + _Add, _Mul, _Pow, _Symbol = MatAdd, MatMul, MatPow, MatrixSymbol + else: + _Add, _Mul, _Pow, _Symbol = Add, Mul, Pow, Symbol + + # =========== Auxiliary functions ======================== + def _overlaps(args): + # Calculate a list of lists m such that m[i][j] contains the lengths + # of all possible overlaps between args[:i+1] and args[i+1+j:]. + # An overlap is a suffix of the prefix that matches a prefix + # of the suffix. + # For example, let expr=c*a*b*a*b*a*b*a*b. Then m[3][0] contains + # the lengths of overlaps of c*a*b*a*b with a*b*a*b. The overlaps + # are a*b*a*b, a*b and the empty word so that m[3][0]=[4,2,0]. + # All overlaps rather than only the longest one are recorded + # because this information helps calculate other overlap lengths. + m = [[([1, 0] if a == args[0] else [0]) for a in args[1:]]] + for i in range(1, len(args)): + overlaps = [] + j = 0 + for j in range(len(args) - i - 1): + overlap = [] + for v in m[i-1][j+1]: + if j + i + 1 + v < len(args) and args[i] == args[j+i+1+v]: + overlap.append(v + 1) + overlap += [0] + overlaps.append(overlap) + m.append(overlaps) + return m + + def _reduce_inverses(_args): + # replace consecutive negative powers by an inverse + # of a product of positive powers, e.g. a**-1*b**-1*c + # will simplify to (a*b)**-1*c; + # return that new args list and the number of negative + # powers in it (inv_tot) + inv_tot = 0 # total number of inverses + inverses = [] + args = [] + for arg in _args: + if isinstance(arg, _Pow) and arg.args[1].is_extended_negative: + inverses = [arg**-1] + inverses + inv_tot += 1 + else: + if len(inverses) == 1: + args.append(inverses[0]**-1) + elif len(inverses) > 1: + args.append(_Pow(_Mul(*inverses), -1)) + inv_tot -= len(inverses) - 1 + inverses = [] + args.append(arg) + if inverses: + args.append(_Pow(_Mul(*inverses), -1)) + inv_tot -= len(inverses) - 1 + return inv_tot, tuple(args) + + def get_score(s): + # compute the number of arguments of s + # (including in nested expressions) overall + # but ignore exponents + if isinstance(s, _Pow): + return get_score(s.args[0]) + elif isinstance(s, (_Add, _Mul)): + return sum(get_score(a) for a in s.args) + return 1 + + def compare(s, alt_s): + # compare two possible simplifications and return a + # "better" one + if s != alt_s and get_score(alt_s) < get_score(s): + return alt_s + return s + # ======================================================== + + if not isinstance(expr, (_Add, _Mul, _Pow)) or expr.is_commutative: + return expr + args = expr.args[:] + if isinstance(expr, _Pow): + if deep: + return _Pow(nc_simplify(args[0]), args[1]).doit() + else: + return expr + elif isinstance(expr, _Add): + return _Add(*[nc_simplify(a, deep=deep) for a in args]).doit() + else: + # get the non-commutative part + c_args, args = expr.args_cnc() + com_coeff = Mul(*c_args) + if not equal_valued(com_coeff, 1): + return com_coeff*nc_simplify(expr/com_coeff, deep=deep) + + inv_tot, args = _reduce_inverses(args) + # if most arguments are negative, work with the inverse + # of the expression, e.g. a**-1*b*a**-1*c**-1 will become + # (c*a*b**-1*a)**-1 at the end so can work with c*a*b**-1*a + invert = False + if inv_tot > len(args)/2: + invert = True + args = [a**-1 for a in args[::-1]] + + if deep: + args = tuple(nc_simplify(a) for a in args) + + m = _overlaps(args) + + # simps will be {subterm: end} where `end` is the ending + # index of a sequence of repetitions of subterm; + # this is for not wasting time with subterms that are part + # of longer, already considered sequences + simps = {} + + post = 1 + pre = 1 + + # the simplification coefficient is the number of + # arguments by which contracting a given sequence + # would reduce the word; e.g. in a*b*a*b*c*a*b*c, + # contracting a*b*a*b to (a*b)**2 removes 3 arguments + # while a*b*c*a*b*c to (a*b*c)**2 removes 6. It's + # better to contract the latter so simplification + # with a maximum simplification coefficient will be chosen + max_simp_coeff = 0 + simp = None # information about future simplification + + for i in range(1, len(args)): + simp_coeff = 0 + l = 0 # length of a subterm + p = 0 # the power of a subterm + if i < len(args) - 1: + rep = m[i][0] + start = i # starting index of the repeated sequence + end = i+1 # ending index of the repeated sequence + if i == len(args)-1 or rep == [0]: + # no subterm is repeated at this stage, at least as + # far as the arguments are concerned - there may be + # a repetition if powers are taken into account + if (isinstance(args[i], _Pow) and + not isinstance(args[i].args[0], _Symbol)): + subterm = args[i].args[0].args + l = len(subterm) + if args[i-l:i] == subterm: + # e.g. a*b in a*b*(a*b)**2 is not repeated + # in args (= [a, b, (a*b)**2]) but it + # can be matched here + p += 1 + start -= l + if args[i+1:i+1+l] == subterm: + # e.g. a*b in (a*b)**2*a*b + p += 1 + end += l + if p: + p += args[i].args[1] + else: + continue + else: + l = rep[0] # length of the longest repeated subterm at this point + start -= l - 1 + subterm = args[start:end] + p = 2 + end += l + + if subterm in simps and simps[subterm] >= start: + # the subterm is part of a sequence that + # has already been considered + continue + + # count how many times it's repeated + while end < len(args): + if l in m[end-1][0]: + p += 1 + end += l + elif isinstance(args[end], _Pow) and args[end].args[0].args == subterm: + # for cases like a*b*a*b*(a*b)**2*a*b + p += args[end].args[1] + end += 1 + else: + break + + # see if another match can be made, e.g. + # for b*a**2 in b*a**2*b*a**3 or a*b in + # a**2*b*a*b + + pre_exp = 0 + pre_arg = 1 + if start - l >= 0 and args[start-l+1:start] == subterm[1:]: + if isinstance(subterm[0], _Pow): + pre_arg = subterm[0].args[0] + exp = subterm[0].args[1] + else: + pre_arg = subterm[0] + exp = 1 + if isinstance(args[start-l], _Pow) and args[start-l].args[0] == pre_arg: + pre_exp = args[start-l].args[1] - exp + start -= l + p += 1 + elif args[start-l] == pre_arg: + pre_exp = 1 - exp + start -= l + p += 1 + + post_exp = 0 + post_arg = 1 + if end + l - 1 < len(args) and args[end:end+l-1] == subterm[:-1]: + if isinstance(subterm[-1], _Pow): + post_arg = subterm[-1].args[0] + exp = subterm[-1].args[1] + else: + post_arg = subterm[-1] + exp = 1 + if isinstance(args[end+l-1], _Pow) and args[end+l-1].args[0] == post_arg: + post_exp = args[end+l-1].args[1] - exp + end += l + p += 1 + elif args[end+l-1] == post_arg: + post_exp = 1 - exp + end += l + p += 1 + + # Consider a*b*a**2*b*a**2*b*a: + # b*a**2 is explicitly repeated, but note + # that in this case a*b*a is also repeated + # so there are two possible simplifications: + # a*(b*a**2)**3*a**-1 or (a*b*a)**3 + # The latter is obviously simpler. + # But in a*b*a**2*b**2*a**2 the simplifications are + # a*(b*a**2)**2 and (a*b*a)**3*a in which case + # it's better to stick with the shorter subterm + if post_exp and exp % 2 == 0 and start > 0: + exp = exp/2 + _pre_exp = 1 + _post_exp = 1 + if isinstance(args[start-1], _Pow) and args[start-1].args[0] == post_arg: + _post_exp = post_exp + exp + _pre_exp = args[start-1].args[1] - exp + elif args[start-1] == post_arg: + _post_exp = post_exp + exp + _pre_exp = 1 - exp + if _pre_exp == 0 or _post_exp == 0: + if not pre_exp: + start -= 1 + post_exp = _post_exp + pre_exp = _pre_exp + pre_arg = post_arg + subterm = (post_arg**exp,) + subterm[:-1] + (post_arg**exp,) + + simp_coeff += end-start + + if post_exp: + simp_coeff -= 1 + if pre_exp: + simp_coeff -= 1 + + simps[subterm] = end + + if simp_coeff > max_simp_coeff: + max_simp_coeff = simp_coeff + simp = (start, _Mul(*subterm), p, end, l) + pre = pre_arg**pre_exp + post = post_arg**post_exp + + if simp: + subterm = _Pow(nc_simplify(simp[1], deep=deep), simp[2]) + pre = nc_simplify(_Mul(*args[:simp[0]])*pre, deep=deep) + post = post*nc_simplify(_Mul(*args[simp[3]:]), deep=deep) + simp = pre*subterm*post + if pre != 1 or post != 1: + # new simplifications may be possible but no need + # to recurse over arguments + simp = nc_simplify(simp, deep=False) + else: + simp = _Mul(*args) + + if invert: + simp = _Pow(simp, -1) + + # see if factor_nc(expr) is simplified better + if not isinstance(expr, MatrixExpr): + f_expr = factor_nc(expr) + if f_expr != expr: + alt_simp = nc_simplify(f_expr, deep=deep) + simp = compare(simp, alt_simp) + else: + simp = simp.doit(inv_expand=False) + return simp + + +def dotprodsimp(expr, withsimp=False): + """Simplification for a sum of products targeted at the kind of blowup that + occurs during summation of products. Intended to reduce expression blowup + during matrix multiplication or other similar operations. Only works with + algebraic expressions and does not recurse into non. + + Parameters + ========== + + withsimp : bool, optional + Specifies whether a flag should be returned along with the expression + to indicate roughly whether simplification was successful. It is used + in ``MatrixArithmetic._eval_pow_by_recursion`` to avoid attempting to + simplify an expression repetitively which does not simplify. + """ + + def count_ops_alg(expr): + """Optimized count algebraic operations with no recursion into + non-algebraic args that ``core.function.count_ops`` does. Also returns + whether rational functions may be present according to negative + exponents of powers or non-number fractions. + + Returns + ======= + + ops, ratfunc : int, bool + ``ops`` is the number of algebraic operations starting at the top + level expression (not recursing into non-alg children). ``ratfunc`` + specifies whether the expression MAY contain rational functions + which ``cancel`` MIGHT optimize. + """ + + ops = 0 + args = [expr] + ratfunc = False + + while args: + a = args.pop() + + if not isinstance(a, Basic): + continue + + if a.is_Rational: + if a is not S.One: # -1/3 = NEG + DIV + ops += bool (a.p < 0) + bool (a.q != 1) + + elif a.is_Mul: + if a.could_extract_minus_sign(): + ops += 1 + if a.args[0] is S.NegativeOne: + a = a.as_two_terms()[1] + else: + a = -a + + n, d = fraction(a) + + if n.is_Integer: + ops += 1 + bool (n < 0) + args.append(d) # won't be -Mul but could be Add + + elif d is not S.One: + if not d.is_Integer: + args.append(d) + ratfunc=True + + ops += 1 + args.append(n) # could be -Mul + + else: + ops += len(a.args) - 1 + args.extend(a.args) + + elif a.is_Add: + laargs = len(a.args) + negs = 0 + + for ai in a.args: + if ai.could_extract_minus_sign(): + negs += 1 + ai = -ai + args.append(ai) + + ops += laargs - (negs != laargs) # -x - y = NEG + SUB + + elif a.is_Pow: + ops += 1 + args.append(a.base) + + if not ratfunc: + ratfunc = a.exp.is_negative is not False + + return ops, ratfunc + + def nonalg_subs_dummies(expr, dummies): + """Substitute dummy variables for non-algebraic expressions to avoid + evaluation of non-algebraic terms that ``polys.polytools.cancel`` does. + """ + + if not expr.args: + return expr + + if expr.is_Add or expr.is_Mul or expr.is_Pow: + args = None + + for i, a in enumerate(expr.args): + c = nonalg_subs_dummies(a, dummies) + + if c is a: + continue + + if args is None: + args = list(expr.args) + + args[i] = c + + if args is None: + return expr + + return expr.func(*args) + + return dummies.setdefault(expr, Dummy()) + + simplified = False # doesn't really mean simplified, rather "can simplify again" + + if isinstance(expr, Basic) and (expr.is_Add or expr.is_Mul or expr.is_Pow): + expr2 = expr.expand(deep=True, modulus=None, power_base=False, + power_exp=False, mul=True, log=False, multinomial=True, basic=False) + + if expr2 != expr: + expr = expr2 + simplified = True + + exprops, ratfunc = count_ops_alg(expr) + + if exprops >= 6: # empirically tested cutoff for expensive simplification + if ratfunc: + dummies = {} + expr2 = nonalg_subs_dummies(expr, dummies) + + if expr2 is expr or count_ops_alg(expr2)[0] >= 6: # check again after substitution + expr3 = cancel(expr2) + + if expr3 != expr2: + expr = expr3.subs([(d, e) for e, d in dummies.items()]) + simplified = True + + # very special case: x/(x-1) - 1/(x-1) -> 1 + elif (exprops == 5 and expr.is_Add and expr.args [0].is_Mul and + expr.args [1].is_Mul and expr.args [0].args [-1].is_Pow and + expr.args [1].args [-1].is_Pow and + expr.args [0].args [-1].exp is S.NegativeOne and + expr.args [1].args [-1].exp is S.NegativeOne): + + expr2 = together (expr) + expr2ops = count_ops_alg(expr2)[0] + + if expr2ops < exprops: + expr = expr2 + simplified = True + + else: + simplified = True + + return (expr, simplified) if withsimp else expr + + +bottom_up = deprecated( + """ + Using bottom_up from the sympy.simplify.simplify submodule is + deprecated. + + Instead, use bottom_up from the top-level sympy namespace, like + + sympy.bottom_up + """, + deprecated_since_version="1.10", + active_deprecations_target="deprecated-traversal-functions-moved", +)(_bottom_up) + + +# XXX: This function really should either be private API or exported in the +# top-level sympy/__init__.py +walk = deprecated( + """ + Using walk from the sympy.simplify.simplify submodule is + deprecated. + + Instead, use walk from sympy.core.traversal.walk + """, + deprecated_since_version="1.10", + active_deprecations_target="deprecated-traversal-functions-moved", +)(_walk) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/sqrtdenest.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/sqrtdenest.py new file mode 100644 index 0000000000000000000000000000000000000000..d266de7e62a4b7d37a2109f7091ff91e4df7c79d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/sqrtdenest.py @@ -0,0 +1,678 @@ +from sympy.core import Add, Expr, Mul, S, sympify +from sympy.core.function import _mexpand, count_ops, expand_mul +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Dummy +from sympy.functions import root, sign, sqrt +from sympy.polys import Poly, PolynomialError + + +def is_sqrt(expr): + """Return True if expr is a sqrt, otherwise False.""" + + return expr.is_Pow and expr.exp.is_Rational and abs(expr.exp) is S.Half + + +def sqrt_depth(p) -> int: + """Return the maximum depth of any square root argument of p. + + >>> from sympy.functions.elementary.miscellaneous import sqrt + >>> from sympy.simplify.sqrtdenest import sqrt_depth + + Neither of these square roots contains any other square roots + so the depth is 1: + + >>> sqrt_depth(1 + sqrt(2)*(1 + sqrt(3))) + 1 + + The sqrt(3) is contained within a square root so the depth is + 2: + + >>> sqrt_depth(1 + sqrt(2)*sqrt(1 + sqrt(3))) + 2 + """ + if p is S.ImaginaryUnit: + return 1 + if p.is_Atom: + return 0 + if p.is_Add or p.is_Mul: + return max(sqrt_depth(x) for x in p.args) + if is_sqrt(p): + return sqrt_depth(p.base) + 1 + return 0 + + +def is_algebraic(p): + """Return True if p is comprised of only Rationals or square roots + of Rationals and algebraic operations. + + Examples + ======== + + >>> from sympy.functions.elementary.miscellaneous import sqrt + >>> from sympy.simplify.sqrtdenest import is_algebraic + >>> from sympy import cos + >>> is_algebraic(sqrt(2)*(3/(sqrt(7) + sqrt(5)*sqrt(2)))) + True + >>> is_algebraic(sqrt(2)*(3/(sqrt(7) + sqrt(5)*cos(2)))) + False + """ + + if p.is_Rational: + return True + elif p.is_Atom: + return False + elif is_sqrt(p) or p.is_Pow and p.exp.is_Integer: + return is_algebraic(p.base) + elif p.is_Add or p.is_Mul: + return all(is_algebraic(x) for x in p.args) + else: + return False + + +def _subsets(n): + """ + Returns all possible subsets of the set (0, 1, ..., n-1) except the + empty set, listed in reversed lexicographical order according to binary + representation, so that the case of the fourth root is treated last. + + Examples + ======== + + >>> from sympy.simplify.sqrtdenest import _subsets + >>> _subsets(2) + [[1, 0], [0, 1], [1, 1]] + + """ + if n == 1: + a = [[1]] + elif n == 2: + a = [[1, 0], [0, 1], [1, 1]] + elif n == 3: + a = [[1, 0, 0], [0, 1, 0], [1, 1, 0], + [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]] + else: + b = _subsets(n - 1) + a0 = [x + [0] for x in b] + a1 = [x + [1] for x in b] + a = a0 + [[0]*(n - 1) + [1]] + a1 + return a + + +def sqrtdenest(expr, max_iter=3): + """Denests sqrts in an expression that contain other square roots + if possible, otherwise returns the expr unchanged. This is based on the + algorithms of [1]. + + Examples + ======== + + >>> from sympy.simplify.sqrtdenest import sqrtdenest + >>> from sympy import sqrt + >>> sqrtdenest(sqrt(5 + 2 * sqrt(6))) + sqrt(2) + sqrt(3) + + See Also + ======== + + sympy.solvers.solvers.unrad + + References + ========== + + .. [1] https://web.archive.org/web/20210806201615/https://researcher.watson.ibm.com/researcher/files/us-fagin/symb85.pdf + + .. [2] D. J. Jeffrey and A. D. Rich, 'Symplifying Square Roots of Square Roots + by Denesting' (available at https://www.cybertester.com/data/denest.pdf) + + """ + expr = expand_mul(expr) + for i in range(max_iter): + z = _sqrtdenest0(expr) + if expr == z: + return expr + expr = z + return expr + + +def _sqrt_match(p): + """Return [a, b, r] for p.match(a + b*sqrt(r)) where, in addition to + matching, sqrt(r) also has then maximal sqrt_depth among addends of p. + + Examples + ======== + + >>> from sympy.functions.elementary.miscellaneous import sqrt + >>> from sympy.simplify.sqrtdenest import _sqrt_match + >>> _sqrt_match(1 + sqrt(2) + sqrt(2)*sqrt(3) + 2*sqrt(1+sqrt(5))) + [1 + sqrt(2) + sqrt(6), 2, 1 + sqrt(5)] + """ + from sympy.simplify.radsimp import split_surds + + p = _mexpand(p) + if p.is_Number: + res = (p, S.Zero, S.Zero) + elif p.is_Add: + pargs = sorted(p.args, key=default_sort_key) + sqargs = [x**2 for x in pargs] + if all(sq.is_Rational and sq.is_positive for sq in sqargs): + r, b, a = split_surds(p) + res = a, b, r + return list(res) + # to make the process canonical, the argument is included in the tuple + # so when the max is selected, it will be the largest arg having a + # given depth + v = [(sqrt_depth(x), x, i) for i, x in enumerate(pargs)] + nmax = max(v, key=default_sort_key) + if nmax[0] == 0: + res = [] + else: + # select r + depth, _, i = nmax + r = pargs.pop(i) + v.pop(i) + b = S.One + if r.is_Mul: + bv = [] + rv = [] + for x in r.args: + if sqrt_depth(x) < depth: + bv.append(x) + else: + rv.append(x) + b = Mul._from_args(bv) + r = Mul._from_args(rv) + # collect terms containing r + a1 = [] + b1 = [b] + for x in v: + if x[0] < depth: + a1.append(x[1]) + else: + x1 = x[1] + if x1 == r: + b1.append(1) + else: + if x1.is_Mul: + x1args = list(x1.args) + if r in x1args: + x1args.remove(r) + b1.append(Mul(*x1args)) + else: + a1.append(x[1]) + else: + a1.append(x[1]) + a = Add(*a1) + b = Add(*b1) + res = (a, b, r**2) + else: + b, r = p.as_coeff_Mul() + if is_sqrt(r): + res = (S.Zero, b, r**2) + else: + res = [] + return list(res) + + +class SqrtdenestStopIteration(StopIteration): + pass + + +def _sqrtdenest0(expr): + """Returns expr after denesting its arguments.""" + + if is_sqrt(expr): + n, d = expr.as_numer_denom() + if d is S.One: # n is a square root + if n.base.is_Add: + args = sorted(n.base.args, key=default_sort_key) + if len(args) > 2 and all((x**2).is_Integer for x in args): + try: + return _sqrtdenest_rec(n) + except SqrtdenestStopIteration: + pass + expr = sqrt(_mexpand(Add(*[_sqrtdenest0(x) for x in args]))) + return _sqrtdenest1(expr) + else: + n, d = [_sqrtdenest0(i) for i in (n, d)] + return n/d + + if isinstance(expr, Add): + cs = [] + args = [] + for arg in expr.args: + c, a = arg.as_coeff_Mul() + cs.append(c) + args.append(a) + + if all(c.is_Rational for c in cs) and all(is_sqrt(arg) for arg in args): + return _sqrt_ratcomb(cs, args) + + if isinstance(expr, Expr): + args = expr.args + if args: + return expr.func(*[_sqrtdenest0(a) for a in args]) + return expr + + +def _sqrtdenest_rec(expr): + """Helper that denests the square root of three or more surds. + + Explanation + =========== + + It returns the denested expression; if it cannot be denested it + throws SqrtdenestStopIteration + + Algorithm: expr.base is in the extension Q_m = Q(sqrt(r_1),..,sqrt(r_k)); + split expr.base = a + b*sqrt(r_k), where `a` and `b` are on + Q_(m-1) = Q(sqrt(r_1),..,sqrt(r_(k-1))); then a**2 - b**2*r_k is + on Q_(m-1); denest sqrt(a**2 - b**2*r_k) and so on. + See [1], section 6. + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.simplify.sqrtdenest import _sqrtdenest_rec + >>> _sqrtdenest_rec(sqrt(-72*sqrt(2) + 158*sqrt(5) + 498)) + -sqrt(10) + sqrt(2) + 9 + 9*sqrt(5) + >>> w=-6*sqrt(55)-6*sqrt(35)-2*sqrt(22)-2*sqrt(14)+2*sqrt(77)+6*sqrt(10)+65 + >>> _sqrtdenest_rec(sqrt(w)) + -sqrt(11) - sqrt(7) + sqrt(2) + 3*sqrt(5) + """ + from sympy.simplify.radsimp import radsimp, rad_rationalize, split_surds + if not expr.is_Pow: + return sqrtdenest(expr) + if expr.base < 0: + return sqrt(-1)*_sqrtdenest_rec(sqrt(-expr.base)) + g, a, b = split_surds(expr.base) + a = a*sqrt(g) + if a < b: + a, b = b, a + c2 = _mexpand(a**2 - b**2) + if len(c2.args) > 2: + g, a1, b1 = split_surds(c2) + a1 = a1*sqrt(g) + if a1 < b1: + a1, b1 = b1, a1 + c2_1 = _mexpand(a1**2 - b1**2) + c_1 = _sqrtdenest_rec(sqrt(c2_1)) + d_1 = _sqrtdenest_rec(sqrt(a1 + c_1)) + num, den = rad_rationalize(b1, d_1) + c = _mexpand(d_1/sqrt(2) + num/(den*sqrt(2))) + else: + c = _sqrtdenest1(sqrt(c2)) + + if sqrt_depth(c) > 1: + raise SqrtdenestStopIteration + ac = a + c + if len(ac.args) >= len(expr.args): + if count_ops(ac) >= count_ops(expr.base): + raise SqrtdenestStopIteration + d = sqrtdenest(sqrt(ac)) + if sqrt_depth(d) > 1: + raise SqrtdenestStopIteration + num, den = rad_rationalize(b, d) + r = d/sqrt(2) + num/(den*sqrt(2)) + r = radsimp(r) + return _mexpand(r) + + +def _sqrtdenest1(expr, denester=True): + """Return denested expr after denesting with simpler methods or, that + failing, using the denester.""" + + from sympy.simplify.simplify import radsimp + + if not is_sqrt(expr): + return expr + + a = expr.base + if a.is_Atom: + return expr + val = _sqrt_match(a) + if not val: + return expr + + a, b, r = val + # try a quick numeric denesting + d2 = _mexpand(a**2 - b**2*r) + if d2.is_Rational: + if d2.is_positive: + z = _sqrt_numeric_denest(a, b, r, d2) + if z is not None: + return z + else: + # fourth root case + # sqrtdenest(sqrt(3 + 2*sqrt(3))) = + # sqrt(2)*3**(1/4)/2 + sqrt(2)*3**(3/4)/2 + dr2 = _mexpand(-d2*r) + dr = sqrt(dr2) + if dr.is_Rational: + z = _sqrt_numeric_denest(_mexpand(b*r), a, r, dr2) + if z is not None: + return z/root(r, 4) + + else: + z = _sqrt_symbolic_denest(a, b, r) + if z is not None: + return z + + if not denester or not is_algebraic(expr): + return expr + + res = sqrt_biquadratic_denest(expr, a, b, r, d2) + if res: + return res + + # now call to the denester + av0 = [a, b, r, d2] + z = _denester([radsimp(expr**2)], av0, 0, sqrt_depth(expr))[0] + if av0[1] is None: + return expr + if z is not None: + if sqrt_depth(z) == sqrt_depth(expr) and count_ops(z) > count_ops(expr): + return expr + return z + return expr + + +def _sqrt_symbolic_denest(a, b, r): + """Given an expression, sqrt(a + b*sqrt(b)), return the denested + expression or None. + + Explanation + =========== + + If r = ra + rb*sqrt(rr), try replacing sqrt(rr) in ``a`` with + (y**2 - ra)/rb, and if the result is a quadratic, ca*y**2 + cb*y + cc, and + (cb + b)**2 - 4*ca*cc is 0, then sqrt(a + b*sqrt(r)) can be rewritten as + sqrt(ca*(sqrt(r) + (cb + b)/(2*ca))**2). + + Examples + ======== + + >>> from sympy.simplify.sqrtdenest import _sqrt_symbolic_denest, sqrtdenest + >>> from sympy import sqrt, Symbol + >>> from sympy.abc import x + + >>> a, b, r = 16 - 2*sqrt(29), 2, -10*sqrt(29) + 55 + >>> _sqrt_symbolic_denest(a, b, r) + sqrt(11 - 2*sqrt(29)) + sqrt(5) + + If the expression is numeric, it will be simplified: + + >>> w = sqrt(sqrt(sqrt(3) + 1) + 1) + 1 + sqrt(2) + >>> sqrtdenest(sqrt((w**2).expand())) + 1 + sqrt(2) + sqrt(1 + sqrt(1 + sqrt(3))) + + Otherwise, it will only be simplified if assumptions allow: + + >>> w = w.subs(sqrt(3), sqrt(x + 3)) + >>> sqrtdenest(sqrt((w**2).expand())) + sqrt((sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2))**2) + + Notice that the argument of the sqrt is a square. If x is made positive + then the sqrt of the square is resolved: + + >>> _.subs(x, Symbol('x', positive=True)) + sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2) + """ + + a, b, r = map(sympify, (a, b, r)) + rval = _sqrt_match(r) + if not rval: + return None + ra, rb, rr = rval + if rb: + y = Dummy('y', positive=True) + try: + newa = Poly(a.subs(sqrt(rr), (y**2 - ra)/rb), y) + except PolynomialError: + return None + if newa.degree() == 2: + ca, cb, cc = newa.all_coeffs() + cb += b + if _mexpand(cb**2 - 4*ca*cc).equals(0): + z = sqrt(ca*(sqrt(r) + cb/(2*ca))**2) + if z.is_number: + z = _mexpand(Mul._from_args(z.as_content_primitive())) + return z + + +def _sqrt_numeric_denest(a, b, r, d2): + r"""Helper that denest + $\sqrt{a + b \sqrt{r}}, d^2 = a^2 - b^2 r > 0$ + + If it cannot be denested, it returns ``None``. + """ + d = sqrt(d2) + s = a + d + # sqrt_depth(res) <= sqrt_depth(s) + 1 + # sqrt_depth(expr) = sqrt_depth(r) + 2 + # there is denesting if sqrt_depth(s) + 1 < sqrt_depth(r) + 2 + # if s**2 is Number there is a fourth root + if sqrt_depth(s) < sqrt_depth(r) + 1 or (s**2).is_Rational: + s1, s2 = sign(s), sign(b) + if s1 == s2 == -1: + s1 = s2 = 1 + res = (s1 * sqrt(a + d) + s2 * sqrt(a - d)) * sqrt(2) / 2 + return res.expand() + + +def sqrt_biquadratic_denest(expr, a, b, r, d2): + """denest expr = sqrt(a + b*sqrt(r)) + where a, b, r are linear combinations of square roots of + positive rationals on the rationals (SQRR) and r > 0, b != 0, + d2 = a**2 - b**2*r > 0 + + If it cannot denest it returns None. + + Explanation + =========== + + Search for a solution A of type SQRR of the biquadratic equation + 4*A**4 - 4*a*A**2 + b**2*r = 0 (1) + sqd = sqrt(a**2 - b**2*r) + Choosing the sqrt to be positive, the possible solutions are + A = sqrt(a/2 +/- sqd/2) + Since a, b, r are SQRR, then a**2 - b**2*r is a SQRR, + so if sqd can be denested, it is done by + _sqrtdenest_rec, and the result is a SQRR. + Similarly for A. + Examples of solutions (in both cases a and sqd are positive): + + Example of expr with solution sqrt(a/2 + sqd/2) but not + solution sqrt(a/2 - sqd/2): + expr = sqrt(-sqrt(15) - sqrt(2)*sqrt(-sqrt(5) + 5) - sqrt(3) + 8) + a = -sqrt(15) - sqrt(3) + 8; sqd = -2*sqrt(5) - 2 + 4*sqrt(3) + + Example of expr with solution sqrt(a/2 - sqd/2) but not + solution sqrt(a/2 + sqd/2): + w = 2 + r2 + r3 + (1 + r3)*sqrt(2 + r2 + 5*r3) + expr = sqrt((w**2).expand()) + a = 4*sqrt(6) + 8*sqrt(2) + 47 + 28*sqrt(3) + sqd = 29 + 20*sqrt(3) + + Define B = b/2*A; eq.(1) implies a = A**2 + B**2*r; then + expr**2 = a + b*sqrt(r) = (A + B*sqrt(r))**2 + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.simplify.sqrtdenest import _sqrt_match, sqrt_biquadratic_denest + >>> z = sqrt((2*sqrt(2) + 4)*sqrt(2 + sqrt(2)) + 5*sqrt(2) + 8) + >>> a, b, r = _sqrt_match(z**2) + >>> d2 = a**2 - b**2*r + >>> sqrt_biquadratic_denest(z, a, b, r, d2) + sqrt(2) + sqrt(sqrt(2) + 2) + 2 + """ + from sympy.simplify.radsimp import radsimp, rad_rationalize + if r <= 0 or d2 < 0 or not b or sqrt_depth(expr.base) < 2: + return None + for x in (a, b, r): + for y in x.args: + y2 = y**2 + if not y2.is_Integer or not y2.is_positive: + return None + sqd = _mexpand(sqrtdenest(sqrt(radsimp(d2)))) + if sqrt_depth(sqd) > 1: + return None + x1, x2 = [a/2 + sqd/2, a/2 - sqd/2] + # look for a solution A with depth 1 + for x in (x1, x2): + A = sqrtdenest(sqrt(x)) + if sqrt_depth(A) > 1: + continue + Bn, Bd = rad_rationalize(b, _mexpand(2*A)) + B = Bn/Bd + z = A + B*sqrt(r) + if z < 0: + z = -z + return _mexpand(z) + return None + + +def _denester(nested, av0, h, max_depth_level): + """Denests a list of expressions that contain nested square roots. + + Explanation + =========== + + Algorithm based on . + + It is assumed that all of the elements of 'nested' share the same + bottom-level radicand. (This is stated in the paper, on page 177, in + the paragraph immediately preceding the algorithm.) + + When evaluating all of the arguments in parallel, the bottom-level + radicand only needs to be denested once. This means that calling + _denester with x arguments results in a recursive invocation with x+1 + arguments; hence _denester has polynomial complexity. + + However, if the arguments were evaluated separately, each call would + result in two recursive invocations, and the algorithm would have + exponential complexity. + + This is discussed in the paper in the middle paragraph of page 179. + """ + from sympy.simplify.simplify import radsimp + if h > max_depth_level: + return None, None + if av0[1] is None: + return None, None + if (av0[0] is None and + all(n.is_Number for n in nested)): # no arguments are nested + for f in _subsets(len(nested)): # test subset 'f' of nested + p = _mexpand(Mul(*[nested[i] for i in range(len(f)) if f[i]])) + if f.count(1) > 1 and f[-1]: + p = -p + sqp = sqrt(p) + if sqp.is_Rational: + return sqp, f # got a perfect square so return its square root. + # Otherwise, return the radicand from the previous invocation. + return sqrt(nested[-1]), [0]*len(nested) + else: + R = None + if av0[0] is not None: + values = [av0[:2]] + R = av0[2] + nested2 = [av0[3], R] + av0[0] = None + else: + values = list(filter(None, [_sqrt_match(expr) for expr in nested])) + for v in values: + if v[2]: # Since if b=0, r is not defined + if R is not None: + if R != v[2]: + av0[1] = None + return None, None + else: + R = v[2] + if R is None: + # return the radicand from the previous invocation + return sqrt(nested[-1]), [0]*len(nested) + nested2 = [_mexpand(v[0]**2) - + _mexpand(R*v[1]**2) for v in values] + [R] + d, f = _denester(nested2, av0, h + 1, max_depth_level) + if not f: + return None, None + if not any(f[i] for i in range(len(nested))): + v = values[-1] + return sqrt(v[0] + _mexpand(v[1]*d)), f + else: + p = Mul(*[nested[i] for i in range(len(nested)) if f[i]]) + v = _sqrt_match(p) + if 1 in f and f.index(1) < len(nested) - 1 and f[len(nested) - 1]: + v[0] = -v[0] + v[1] = -v[1] + if not f[len(nested)]: # Solution denests with square roots + vad = _mexpand(v[0] + d) + if vad <= 0: + # return the radicand from the previous invocation. + return sqrt(nested[-1]), [0]*len(nested) + if not(sqrt_depth(vad) <= sqrt_depth(R) + 1 or + (vad**2).is_Number): + av0[1] = None + return None, None + + sqvad = _sqrtdenest1(sqrt(vad), denester=False) + if not (sqrt_depth(sqvad) <= sqrt_depth(R) + 1): + av0[1] = None + return None, None + sqvad1 = radsimp(1/sqvad) + res = _mexpand(sqvad/sqrt(2) + (v[1]*sqrt(R)*sqvad1/sqrt(2))) + return res, f + + # sign(v[1])*sqrt(_mexpand(v[1]**2*R*vad1/2))), f + else: # Solution requires a fourth root + s2 = _mexpand(v[1]*R) + d + if s2 <= 0: + return sqrt(nested[-1]), [0]*len(nested) + FR, s = root(_mexpand(R), 4), sqrt(s2) + return _mexpand(s/(sqrt(2)*FR) + v[0]*FR/(sqrt(2)*s)), f + + +def _sqrt_ratcomb(cs, args): + """Denest rational combinations of radicals. + + Based on section 5 of [1]. + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.simplify.sqrtdenest import sqrtdenest + >>> z = sqrt(1+sqrt(3)) + sqrt(3+3*sqrt(3)) - sqrt(10+6*sqrt(3)) + >>> sqrtdenest(z) + 0 + """ + from sympy.simplify.radsimp import radsimp + + # check if there exists a pair of sqrt that can be denested + def find(a): + n = len(a) + for i in range(n - 1): + for j in range(i + 1, n): + s1 = a[i].base + s2 = a[j].base + p = _mexpand(s1 * s2) + s = sqrtdenest(sqrt(p)) + if s != sqrt(p): + return s, i, j + + indices = find(args) + if indices is None: + return Add(*[c * arg for c, arg in zip(cs, args)]) + + s, i1, i2 = indices + + c2 = cs.pop(i2) + args.pop(i2) + a1 = args[i1] + + # replace a2 by s/a1 + cs[i1] += radsimp(c2 * s / a1.base) + + return _sqrt_ratcomb(cs, args) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/traversaltools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/traversaltools.py new file mode 100644 index 0000000000000000000000000000000000000000..75b0bd0d8fd198cb12640ab8a0fe63a23c81ed8f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/traversaltools.py @@ -0,0 +1,15 @@ +from sympy.core.traversal import use as _use +from sympy.utilities.decorator import deprecated + +use = deprecated( + """ + Using use from the sympy.simplify.traversaltools submodule is + deprecated. + + Instead, use use from the top-level sympy namespace, like + + sympy.use + """, + deprecated_since_version="1.10", + active_deprecations_target="deprecated-traversal-functions-moved" +)(_use) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/trigsimp.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/trigsimp.py new file mode 100644 index 0000000000000000000000000000000000000000..fe5be1444a4625e4b63b339877e441d12cfbe8de --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/simplify/trigsimp.py @@ -0,0 +1,1252 @@ +from collections import defaultdict +from functools import reduce + +from sympy.core import (sympify, Basic, S, Expr, factor_terms, + Mul, Add, bottom_up) +from sympy.core.cache import cacheit +from sympy.core.function import (count_ops, _mexpand, FunctionClass, expand, + expand_mul, _coeff_isneg, Derivative) +from sympy.core.numbers import I, Integer +from sympy.core.intfunc import igcd +from sympy.core.sorting import _nodes +from sympy.core.symbol import Dummy, symbols, Wild +from sympy.external.gmpy import SYMPY_INTS +from sympy.functions import sin, cos, exp, cosh, tanh, sinh, tan, cot, coth +from sympy.functions import atan2 +from sympy.functions.elementary.hyperbolic import HyperbolicFunction +from sympy.functions.elementary.trigonometric import TrigonometricFunction +from sympy.polys import Poly, factor, cancel, parallel_poly_from_expr +from sympy.polys.domains import ZZ +from sympy.polys.polyerrors import PolificationFailed +from sympy.polys.polytools import groebner +from sympy.simplify.cse_main import cse +from sympy.strategies.core import identity +from sympy.strategies.tree import greedy +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import debug + +def trigsimp_groebner(expr, hints=[], quick=False, order="grlex", + polynomial=False): + """ + Simplify trigonometric expressions using a groebner basis algorithm. + + Explanation + =========== + + This routine takes a fraction involving trigonometric or hyperbolic + expressions, and tries to simplify it. The primary metric is the + total degree. Some attempts are made to choose the simplest possible + expression of the minimal degree, but this is non-rigorous, and also + very slow (see the ``quick=True`` option). + + If ``polynomial`` is set to True, instead of simplifying numerator and + denominator together, this function just brings numerator and denominator + into a canonical form. This is much faster, but has potentially worse + results. However, if the input is a polynomial, then the result is + guaranteed to be an equivalent polynomial of minimal degree. + + The most important option is hints. Its entries can be any of the + following: + + - a natural number + - a function + - an iterable of the form (func, var1, var2, ...) + - anything else, interpreted as a generator + + A number is used to indicate that the search space should be increased. + A function is used to indicate that said function is likely to occur in a + simplified expression. + An iterable is used indicate that func(var1 + var2 + ...) is likely to + occur in a simplified . + An additional generator also indicates that it is likely to occur. + (See examples below). + + This routine carries out various computationally intensive algorithms. + The option ``quick=True`` can be used to suppress one particularly slow + step (at the expense of potentially more complicated results, but never at + the expense of increased total degree). + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import sin, tan, cos, sinh, cosh, tanh + >>> from sympy.simplify.trigsimp import trigsimp_groebner + + Suppose you want to simplify ``sin(x)*cos(x)``. Naively, nothing happens: + + >>> ex = sin(x)*cos(x) + >>> trigsimp_groebner(ex) + sin(x)*cos(x) + + This is because ``trigsimp_groebner`` only looks for a simplification + involving just ``sin(x)`` and ``cos(x)``. You can tell it to also try + ``2*x`` by passing ``hints=[2]``: + + >>> trigsimp_groebner(ex, hints=[2]) + sin(2*x)/2 + >>> trigsimp_groebner(sin(x)**2 - cos(x)**2, hints=[2]) + -cos(2*x) + + Increasing the search space this way can quickly become expensive. A much + faster way is to give a specific expression that is likely to occur: + + >>> trigsimp_groebner(ex, hints=[sin(2*x)]) + sin(2*x)/2 + + Hyperbolic expressions are similarly supported: + + >>> trigsimp_groebner(sinh(2*x)/sinh(x)) + 2*cosh(x) + + Note how no hints had to be passed, since the expression already involved + ``2*x``. + + The tangent function is also supported. You can either pass ``tan`` in the + hints, to indicate that tan should be tried whenever cosine or sine are, + or you can pass a specific generator: + + >>> trigsimp_groebner(sin(x)/cos(x), hints=[tan]) + tan(x) + >>> trigsimp_groebner(sinh(x)/cosh(x), hints=[tanh(x)]) + tanh(x) + + Finally, you can use the iterable form to suggest that angle sum formulae + should be tried: + + >>> ex = (tan(x) + tan(y))/(1 - tan(x)*tan(y)) + >>> trigsimp_groebner(ex, hints=[(tan, x, y)]) + tan(x + y) + """ + # TODO + # - preprocess by replacing everything by funcs we can handle + # - optionally use cot instead of tan + # - more intelligent hinting. + # For example, if the ideal is small, and we have sin(x), sin(y), + # add sin(x + y) automatically... ? + # - algebraic numbers ... + # - expressions of lowest degree are not distinguished properly + # e.g. 1 - sin(x)**2 + # - we could try to order the generators intelligently, so as to influence + # which monomials appear in the quotient basis + + # THEORY + # ------ + # Ratsimpmodprime above can be used to "simplify" a rational function + # modulo a prime ideal. "Simplify" mainly means finding an equivalent + # expression of lower total degree. + # + # We intend to use this to simplify trigonometric functions. To do that, + # we need to decide (a) which ring to use, and (b) modulo which ideal to + # simplify. In practice, (a) means settling on a list of "generators" + # a, b, c, ..., such that the fraction we want to simplify is a rational + # function in a, b, c, ..., with coefficients in ZZ (integers). + # (2) means that we have to decide what relations to impose on the + # generators. There are two practical problems: + # (1) The ideal has to be *prime* (a technical term). + # (2) The relations have to be polynomials in the generators. + # + # We typically have two kinds of generators: + # - trigonometric expressions, like sin(x), cos(5*x), etc + # - "everything else", like gamma(x), pi, etc. + # + # Since this function is trigsimp, we will concentrate on what to do with + # trigonometric expressions. We can also simplify hyperbolic expressions, + # but the extensions should be clear. + # + # One crucial point is that all *other* generators really should behave + # like indeterminates. In particular if (say) "I" is one of them, then + # in fact I**2 + 1 = 0 and we may and will compute non-sensical + # expressions. However, we can work with a dummy and add the relation + # I**2 + 1 = 0 to our ideal, then substitute back in the end. + # + # Now regarding trigonometric generators. We split them into groups, + # according to the argument of the trigonometric functions. We want to + # organise this in such a way that most trigonometric identities apply in + # the same group. For example, given sin(x), cos(2*x) and cos(y), we would + # group as [sin(x), cos(2*x)] and [cos(y)]. + # + # Our prime ideal will be built in three steps: + # (1) For each group, compute a "geometrically prime" ideal of relations. + # Geometrically prime means that it generates a prime ideal in + # CC[gens], not just ZZ[gens]. + # (2) Take the union of all the generators of the ideals for all groups. + # By the geometric primality condition, this is still prime. + # (3) Add further inter-group relations which preserve primality. + # + # Step (1) works as follows. We will isolate common factors in the + # argument, so that all our generators are of the form sin(n*x), cos(n*x) + # or tan(n*x), with n an integer. Suppose first there are no tan terms. + # The ideal [sin(x)**2 + cos(x)**2 - 1] is geometrically prime, since + # X**2 + Y**2 - 1 is irreducible over CC. + # Now, if we have a generator sin(n*x), than we can, using trig identities, + # express sin(n*x) as a polynomial in sin(x) and cos(x). We can add this + # relation to the ideal, preserving geometric primality, since the quotient + # ring is unchanged. + # Thus we have treated all sin and cos terms. + # For tan(n*x), we add a relation tan(n*x)*cos(n*x) - sin(n*x) = 0. + # (This requires of course that we already have relations for cos(n*x) and + # sin(n*x).) It is not obvious, but it seems that this preserves geometric + # primality. + # XXX A real proof would be nice. HELP! + # Sketch that is a prime ideal of + # CC[S, C, T]: + # - it suffices to show that the projective closure in CP**3 is + # irreducible + # - using the half-angle substitutions, we can express sin(x), tan(x), + # cos(x) as rational functions in tan(x/2) + # - from this, we get a rational map from CP**1 to our curve + # - this is a morphism, hence the curve is prime + # + # Step (2) is trivial. + # + # Step (3) works by adding selected relations of the form + # sin(x + y) - sin(x)*cos(y) - sin(y)*cos(x), etc. Geometric primality is + # preserved by the same argument as before. + + def parse_hints(hints): + """Split hints into (n, funcs, iterables, gens).""" + n = 1 + funcs, iterables, gens = [], [], [] + for e in hints: + if isinstance(e, (SYMPY_INTS, Integer)): + n = e + elif isinstance(e, FunctionClass): + funcs.append(e) + elif iterable(e): + iterables.append((e[0], e[1:])) + # XXX sin(x+2y)? + # Note: we go through polys so e.g. + # sin(-x) -> -sin(x) -> sin(x) + gens.extend(parallel_poly_from_expr( + [e[0](x) for x in e[1:]] + [e[0](Add(*e[1:]))])[1].gens) + else: + gens.append(e) + return n, funcs, iterables, gens + + def build_ideal(x, terms): + """ + Build generators for our ideal. ``Terms`` is an iterable with elements of + the form (fn, coeff), indicating that we have a generator fn(coeff*x). + + If any of the terms is trigonometric, sin(x) and cos(x) are guaranteed + to appear in terms. Similarly for hyperbolic functions. For tan(n*x), + sin(n*x) and cos(n*x) are guaranteed. + """ + I = [] + y = Dummy('y') + for fn, coeff in terms: + for c, s, t, rel in ( + [cos, sin, tan, cos(x)**2 + sin(x)**2 - 1], + [cosh, sinh, tanh, cosh(x)**2 - sinh(x)**2 - 1]): + if coeff == 1 and fn in [c, s]: + I.append(rel) + elif fn == t: + I.append(t(coeff*x)*c(coeff*x) - s(coeff*x)) + elif fn in [c, s]: + cn = fn(coeff*y).expand(trig=True).subs(y, x) + I.append(fn(coeff*x) - cn) + return list(set(I)) + + def analyse_gens(gens, hints): + """ + Analyse the generators ``gens``, using the hints ``hints``. + + The meaning of ``hints`` is described in the main docstring. + Return a new list of generators, and also the ideal we should + work with. + """ + # First parse the hints + n, funcs, iterables, extragens = parse_hints(hints) + debug('n=%s funcs: %s iterables: %s extragens: %s', + (funcs, iterables, extragens)) + + # We just add the extragens to gens and analyse them as before + gens = list(gens) + gens.extend(extragens) + + # remove duplicates + funcs = list(set(funcs)) + iterables = list(set(iterables)) + gens = list(set(gens)) + + # all the functions we can do anything with + allfuncs = {sin, cos, tan, sinh, cosh, tanh} + # sin(3*x) -> ((3, x), sin) + trigterms = [(g.args[0].as_coeff_mul(), g.func) for g in gens + if g.func in allfuncs] + # Our list of new generators - start with anything that we cannot + # work with (i.e. is not a trigonometric term) + freegens = [g for g in gens if g.func not in allfuncs] + newgens = [] + trigdict = {} + for (coeff, var), fn in trigterms: + trigdict.setdefault(var, []).append((coeff, fn)) + res = [] # the ideal + + for key, val in trigdict.items(): + # We have now assembeled a dictionary. Its keys are common + # arguments in trigonometric expressions, and values are lists of + # pairs (fn, coeff). x0, (fn, coeff) in trigdict means that we + # need to deal with fn(coeff*x0). We take the rational gcd of the + # coeffs, call it ``gcd``. We then use x = x0/gcd as "base symbol", + # all other arguments are integral multiples thereof. + # We will build an ideal which works with sin(x), cos(x). + # If hint tan is provided, also work with tan(x). Moreover, if + # n > 1, also work with sin(k*x) for k <= n, and similarly for cos + # (and tan if the hint is provided). Finally, any generators which + # the ideal does not work with but we need to accommodate (either + # because it was in expr or because it was provided as a hint) + # we also build into the ideal. + # This selection process is expressed in the list ``terms``. + # build_ideal then generates the actual relations in our ideal, + # from this list. + fns = [x[1] for x in val] + val = [x[0] for x in val] + gcd = reduce(igcd, val) + terms = [(fn, v/gcd) for (fn, v) in zip(fns, val)] + fs = set(funcs + fns) + for c, s, t in ([cos, sin, tan], [cosh, sinh, tanh]): + if any(x in fs for x in (c, s, t)): + fs.add(c) + fs.add(s) + for fn in fs: + terms.extend((fn, k) for k in range(1, n + 1)) + extra = [] + for fn, v in terms: + if fn == tan: + extra.append((sin, v)) + extra.append((cos, v)) + if fn in [sin, cos] and tan in fs: + extra.append((tan, v)) + if fn == tanh: + extra.append((sinh, v)) + extra.append((cosh, v)) + if fn in [sinh, cosh] and tanh in fs: + extra.append((tanh, v)) + terms.extend(extra) + x = gcd*Mul(*key) + r = build_ideal(x, terms) + res.extend(r) + newgens.extend({fn(v*x) for fn, v in terms}) + + # Add generators for compound expressions from iterables + for fn, args in iterables: + if fn == tan: + # Tan expressions are recovered from sin and cos. + iterables.extend([(sin, args), (cos, args)]) + elif fn == tanh: + # Tanh expressions are recovered from sihn and cosh. + iterables.extend([(sinh, args), (cosh, args)]) + else: + dummys = symbols('d:%i' % len(args), cls=Dummy) + expr = fn( Add(*dummys)).expand(trig=True).subs(list(zip(dummys, args))) + res.append(fn(Add(*args)) - expr) + + if myI in gens: + res.append(myI**2 + 1) + freegens.remove(myI) + newgens.append(myI) + + return res, freegens, newgens + + myI = Dummy('I') + expr = expr.subs(S.ImaginaryUnit, myI) + subs = [(myI, S.ImaginaryUnit)] + + num, denom = cancel(expr).as_numer_denom() + try: + (pnum, pdenom), opt = parallel_poly_from_expr([num, denom]) + except PolificationFailed: + return expr + debug('initial gens:', opt.gens) + ideal, freegens, gens = analyse_gens(opt.gens, hints) + debug('ideal:', ideal) + debug('new gens:', gens, " -- len", len(gens)) + debug('free gens:', freegens, " -- len", len(gens)) + # NOTE we force the domain to be ZZ to stop polys from injecting generators + # (which is usually a sign of a bug in the way we build the ideal) + if not gens: + return expr + G = groebner(ideal, order=order, gens=gens, domain=ZZ) + debug('groebner basis:', list(G), " -- len", len(G)) + + # If our fraction is a polynomial in the free generators, simplify all + # coefficients separately: + + from sympy.simplify.ratsimp import ratsimpmodprime + + if freegens and pdenom.has_only_gens(*set(gens).intersection(pdenom.gens)): + num = Poly(num, gens=gens+freegens).eject(*gens) + res = [] + for monom, coeff in num.terms(): + ourgens = set(parallel_poly_from_expr([coeff, denom])[1].gens) + # We compute the transitive closure of all generators that can + # be reached from our generators through relations in the ideal. + changed = True + while changed: + changed = False + for p in ideal: + p = Poly(p) + if not ourgens.issuperset(p.gens) and \ + not p.has_only_gens(*set(p.gens).difference(ourgens)): + changed = True + ourgens.update(p.exclude().gens) + # NOTE preserve order! + realgens = [x for x in gens if x in ourgens] + # The generators of the ideal have now been (implicitly) split + # into two groups: those involving ourgens and those that don't. + # Since we took the transitive closure above, these two groups + # live in subgrings generated by a *disjoint* set of variables. + # Any sensible groebner basis algorithm will preserve this disjoint + # structure (i.e. the elements of the groebner basis can be split + # similarly), and and the two subsets of the groebner basis then + # form groebner bases by themselves. (For the smaller generating + # sets, of course.) + ourG = [g.as_expr() for g in G.polys if + g.has_only_gens(*ourgens.intersection(g.gens))] + res.append(Mul(*[a**b for a, b in zip(freegens, monom)]) * \ + ratsimpmodprime(coeff/denom, ourG, order=order, + gens=realgens, quick=quick, domain=ZZ, + polynomial=polynomial).subs(subs)) + return Add(*res) + # NOTE The following is simpler and has less assumptions on the + # groebner basis algorithm. If the above turns out to be broken, + # use this. + return Add(*[Mul(*[a**b for a, b in zip(freegens, monom)]) * \ + ratsimpmodprime(coeff/denom, list(G), order=order, + gens=gens, quick=quick, domain=ZZ) + for monom, coeff in num.terms()]) + else: + return ratsimpmodprime( + expr, list(G), order=order, gens=freegens+gens, + quick=quick, domain=ZZ, polynomial=polynomial).subs(subs) + + +_trigs = (TrigonometricFunction, HyperbolicFunction) + + +def _trigsimp_inverse(rv): + + def check_args(x, y): + try: + return x.args[0] == y.args[0] + except IndexError: + return False + + def f(rv): + # for simple functions + g = getattr(rv, 'inverse', None) + if (g is not None and isinstance(rv.args[0], g()) and + isinstance(g()(1), TrigonometricFunction)): + return rv.args[0].args[0] + + # for atan2 simplifications, harder because atan2 has 2 args + if isinstance(rv, atan2): + y, x = rv.args + if _coeff_isneg(y): + return -f(atan2(-y, x)) + elif _coeff_isneg(x): + return S.Pi - f(atan2(y, -x)) + + if check_args(x, y): + if isinstance(y, sin) and isinstance(x, cos): + return x.args[0] + if isinstance(y, cos) and isinstance(x, sin): + return S.Pi / 2 - x.args[0] + + return rv + + return bottom_up(rv, f) + + +def trigsimp(expr, inverse=False, **opts): + """Returns a reduced expression by using known trig identities. + + Parameters + ========== + + inverse : bool, optional + If ``inverse=True``, it will be assumed that a composition of inverse + functions, such as sin and asin, can be cancelled in any order. + For example, ``asin(sin(x))`` will yield ``x`` without checking whether + x belongs to the set where this relation is true. The default is False. + Default : True + + method : string, optional + Specifies the method to use. Valid choices are: + + - ``'matching'``, default + - ``'groebner'`` + - ``'combined'`` + - ``'fu'`` + - ``'old'`` + + If ``'matching'``, simplify the expression recursively by targeting + common patterns. If ``'groebner'``, apply an experimental groebner + basis algorithm. In this case further options are forwarded to + ``trigsimp_groebner``, please refer to + its docstring. If ``'combined'``, it first runs the groebner basis + algorithm with small default parameters, then runs the ``'matching'`` + algorithm. If ``'fu'``, run the collection of trigonometric + transformations described by Fu, et al. (see the + :py:func:`~sympy.simplify.fu.fu` docstring). If ``'old'``, the original + SymPy trig simplification function is run. + opts : + Optional keyword arguments passed to the method. See each method's + function docstring for details. + + Examples + ======== + + >>> from sympy import trigsimp, sin, cos, log + >>> from sympy.abc import x + >>> e = 2*sin(x)**2 + 2*cos(x)**2 + >>> trigsimp(e) + 2 + + Simplification occurs wherever trigonometric functions are located. + + >>> trigsimp(log(e)) + log(2) + + Using ``method='groebner'`` (or ``method='combined'``) might lead to + greater simplification. + + The old trigsimp routine can be accessed as with method ``method='old'``. + + >>> from sympy import coth, tanh + >>> t = 3*tanh(x)**7 - 2/coth(x)**7 + >>> trigsimp(t, method='old') == t + True + >>> trigsimp(t) + tanh(x)**7 + + """ + from sympy.simplify.fu import fu + + expr = sympify(expr) + + _eval_trigsimp = getattr(expr, '_eval_trigsimp', None) + if _eval_trigsimp is not None: + return _eval_trigsimp(**opts) + + old = opts.pop('old', False) + if not old: + opts.pop('deep', None) + opts.pop('recursive', None) + method = opts.pop('method', 'matching') + else: + method = 'old' + + def groebnersimp(ex, **opts): + def traverse(e): + if e.is_Atom: + return e + args = [traverse(x) for x in e.args] + if e.is_Function or e.is_Pow: + args = [trigsimp_groebner(x, **opts) for x in args] + return e.func(*args) + new = traverse(ex) + if not isinstance(new, Expr): + return new + return trigsimp_groebner(new, **opts) + + trigsimpfunc = { + 'fu': (lambda x: fu(x, **opts)), + 'matching': (lambda x: futrig(x)), + 'groebner': (lambda x: groebnersimp(x, **opts)), + 'combined': (lambda x: futrig(groebnersimp(x, + polynomial=True, hints=[2, tan]))), + 'old': lambda x: trigsimp_old(x, **opts), + }[method] + + expr_simplified = trigsimpfunc(expr) + if inverse: + expr_simplified = _trigsimp_inverse(expr_simplified) + + return expr_simplified + + +def exptrigsimp(expr): + """ + Simplifies exponential / trigonometric / hyperbolic functions. + + Examples + ======== + + >>> from sympy import exptrigsimp, exp, cosh, sinh + >>> from sympy.abc import z + + >>> exptrigsimp(exp(z) + exp(-z)) + 2*cosh(z) + >>> exptrigsimp(cosh(z) - sinh(z)) + exp(-z) + """ + from sympy.simplify.fu import hyper_as_trig, TR2i + + def exp_trig(e): + # select the better of e, and e rewritten in terms of exp or trig + # functions + choices = [e] + if e.has(*_trigs): + choices.append(e.rewrite(exp)) + choices.append(e.rewrite(cos)) + return min(*choices, key=count_ops) + newexpr = bottom_up(expr, exp_trig) + + def f(rv): + if not rv.is_Mul: + return rv + commutative_part, noncommutative_part = rv.args_cnc() + # Since as_powers_dict loses order information, + # if there is more than one noncommutative factor, + # it should only be used to simplify the commutative part. + if (len(noncommutative_part) > 1): + return f(Mul(*commutative_part))*Mul(*noncommutative_part) + rvd = rv.as_powers_dict() + newd = rvd.copy() + + def signlog(expr, sign=S.One): + if expr is S.Exp1: + return sign, S.One + elif isinstance(expr, exp) or (expr.is_Pow and expr.base == S.Exp1): + return sign, expr.exp + elif sign is S.One: + return signlog(-expr, sign=-S.One) + else: + return None, None + + ee = rvd[S.Exp1] + for k in rvd: + if k.is_Add and len(k.args) == 2: + # k == c*(1 + sign*E**x) + c = k.args[0] + sign, x = signlog(k.args[1]/c) + if not x: + continue + m = rvd[k] + newd[k] -= m + if ee == -x*m/2: + # sinh and cosh + newd[S.Exp1] -= ee + ee = 0 + if sign == 1: + newd[2*c*cosh(x/2)] += m + else: + newd[-2*c*sinh(x/2)] += m + elif newd[1 - sign*S.Exp1**x] == -m: + # tanh + del newd[1 - sign*S.Exp1**x] + if sign == 1: + newd[-c/tanh(x/2)] += m + else: + newd[-c*tanh(x/2)] += m + else: + newd[1 + sign*S.Exp1**x] += m + newd[c] += m + + return Mul(*[k**newd[k] for k in newd]) + newexpr = bottom_up(newexpr, f) + + # sin/cos and sinh/cosh ratios to tan and tanh, respectively + if newexpr.has(HyperbolicFunction): + e, f = hyper_as_trig(newexpr) + newexpr = f(TR2i(e)) + if newexpr.has(TrigonometricFunction): + newexpr = TR2i(newexpr) + + # can we ever generate an I where there was none previously? + if not (newexpr.has(I) and not expr.has(I)): + expr = newexpr + return expr + +#-------------------- the old trigsimp routines --------------------- + +def trigsimp_old(expr, *, first=True, **opts): + """ + Reduces expression by using known trig identities. + + Notes + ===== + + deep: + - Apply trigsimp inside all objects with arguments + + recursive: + - Use common subexpression elimination (cse()) and apply + trigsimp recursively (this is quite expensive if the + expression is large) + + method: + - Determine the method to use. Valid choices are 'matching' (default), + 'groebner', 'combined', 'fu' and 'futrig'. If 'matching', simplify the + expression recursively by pattern matching. If 'groebner', apply an + experimental groebner basis algorithm. In this case further options + are forwarded to ``trigsimp_groebner``, please refer to its docstring. + If 'combined', first run the groebner basis algorithm with small + default parameters, then run the 'matching' algorithm. 'fu' runs the + collection of trigonometric transformations described by Fu, et al. + (see the `fu` docstring) while `futrig` runs a subset of Fu-transforms + that mimic the behavior of `trigsimp`. + + compare: + - show input and output from `trigsimp` and `futrig` when different, + but returns the `trigsimp` value. + + Examples + ======== + + >>> from sympy import trigsimp, sin, cos, log, cot + >>> from sympy.abc import x + >>> e = 2*sin(x)**2 + 2*cos(x)**2 + >>> trigsimp(e, old=True) + 2 + >>> trigsimp(log(e), old=True) + log(2*sin(x)**2 + 2*cos(x)**2) + >>> trigsimp(log(e), deep=True, old=True) + log(2) + + Using `method="groebner"` (or `"combined"`) can sometimes lead to a lot + more simplification: + + >>> e = (-sin(x) + 1)/cos(x) + cos(x)/(-sin(x) + 1) + >>> trigsimp(e, old=True) + (1 - sin(x))/cos(x) + cos(x)/(1 - sin(x)) + >>> trigsimp(e, method="groebner", old=True) + 2/cos(x) + + >>> trigsimp(1/cot(x)**2, compare=True, old=True) + futrig: tan(x)**2 + cot(x)**(-2) + + """ + old = expr + if first: + if not expr.has(*_trigs): + return expr + + trigsyms = set().union(*[t.free_symbols for t in expr.atoms(*_trigs)]) + if len(trigsyms) > 1: + from sympy.simplify.simplify import separatevars + + d = separatevars(expr) + if d.is_Mul: + d = separatevars(d, dict=True) or d + if isinstance(d, dict): + expr = 1 + for v in d.values(): + # remove hollow factoring + was = v + v = expand_mul(v) + opts['first'] = False + vnew = trigsimp(v, **opts) + if vnew == v: + vnew = was + expr *= vnew + old = expr + else: + if d.is_Add: + for s in trigsyms: + r, e = expr.as_independent(s) + if r: + opts['first'] = False + expr = r + trigsimp(e, **opts) + if not expr.is_Add: + break + old = expr + + recursive = opts.pop('recursive', False) + deep = opts.pop('deep', False) + method = opts.pop('method', 'matching') + + def groebnersimp(ex, deep, **opts): + def traverse(e): + if e.is_Atom: + return e + args = [traverse(x) for x in e.args] + if e.is_Function or e.is_Pow: + args = [trigsimp_groebner(x, **opts) for x in args] + return e.func(*args) + if deep: + ex = traverse(ex) + return trigsimp_groebner(ex, **opts) + + trigsimpfunc = { + 'matching': (lambda x, d: _trigsimp(x, d)), + 'groebner': (lambda x, d: groebnersimp(x, d, **opts)), + 'combined': (lambda x, d: _trigsimp(groebnersimp(x, + d, polynomial=True, hints=[2, tan]), + d)) + }[method] + + if recursive: + w, g = cse(expr) + g = trigsimpfunc(g[0], deep) + + for sub in reversed(w): + g = g.subs(sub[0], sub[1]) + g = trigsimpfunc(g, deep) + result = g + else: + result = trigsimpfunc(expr, deep) + + if opts.get('compare', False): + f = futrig(old) + if f != result: + print('\tfutrig:', f) + + return result + + +def _dotrig(a, b): + """Helper to tell whether ``a`` and ``b`` have the same sorts + of symbols in them -- no need to test hyperbolic patterns against + expressions that have no hyperbolics in them.""" + return a.func == b.func and ( + a.has(TrigonometricFunction) and b.has(TrigonometricFunction) or + a.has(HyperbolicFunction) and b.has(HyperbolicFunction)) + + +_trigpat = None +def _trigpats(): + global _trigpat + a, b, c = symbols('a b c', cls=Wild) + d = Wild('d', commutative=False) + + # for the simplifications like sinh/cosh -> tanh: + # DO NOT REORDER THE FIRST 14 since these are assumed to be in this + # order in _match_div_rewrite. + matchers_division = ( + (a*sin(b)**c/cos(b)**c, a*tan(b)**c, sin(b), cos(b)), + (a*tan(b)**c*cos(b)**c, a*sin(b)**c, sin(b), cos(b)), + (a*cot(b)**c*sin(b)**c, a*cos(b)**c, sin(b), cos(b)), + (a*tan(b)**c/sin(b)**c, a/cos(b)**c, sin(b), cos(b)), + (a*cot(b)**c/cos(b)**c, a/sin(b)**c, sin(b), cos(b)), + (a*cot(b)**c*tan(b)**c, a, sin(b), cos(b)), + (a*(cos(b) + 1)**c*(cos(b) - 1)**c, + a*(-sin(b)**2)**c, cos(b) + 1, cos(b) - 1), + (a*(sin(b) + 1)**c*(sin(b) - 1)**c, + a*(-cos(b)**2)**c, sin(b) + 1, sin(b) - 1), + + (a*sinh(b)**c/cosh(b)**c, a*tanh(b)**c, S.One, S.One), + (a*tanh(b)**c*cosh(b)**c, a*sinh(b)**c, S.One, S.One), + (a*coth(b)**c*sinh(b)**c, a*cosh(b)**c, S.One, S.One), + (a*tanh(b)**c/sinh(b)**c, a/cosh(b)**c, S.One, S.One), + (a*coth(b)**c/cosh(b)**c, a/sinh(b)**c, S.One, S.One), + (a*coth(b)**c*tanh(b)**c, a, S.One, S.One), + + (c*(tanh(a) + tanh(b))/(1 + tanh(a)*tanh(b)), + tanh(a + b)*c, S.One, S.One), + ) + + matchers_add = ( + (c*sin(a)*cos(b) + c*cos(a)*sin(b) + d, sin(a + b)*c + d), + (c*cos(a)*cos(b) - c*sin(a)*sin(b) + d, cos(a + b)*c + d), + (c*sin(a)*cos(b) - c*cos(a)*sin(b) + d, sin(a - b)*c + d), + (c*cos(a)*cos(b) + c*sin(a)*sin(b) + d, cos(a - b)*c + d), + (c*sinh(a)*cosh(b) + c*sinh(b)*cosh(a) + d, sinh(a + b)*c + d), + (c*cosh(a)*cosh(b) + c*sinh(a)*sinh(b) + d, cosh(a + b)*c + d), + ) + + # for cos(x)**2 + sin(x)**2 -> 1 + matchers_identity = ( + (a*sin(b)**2, a - a*cos(b)**2), + (a*tan(b)**2, a*(1/cos(b))**2 - a), + (a*cot(b)**2, a*(1/sin(b))**2 - a), + (a*sin(b + c), a*(sin(b)*cos(c) + sin(c)*cos(b))), + (a*cos(b + c), a*(cos(b)*cos(c) - sin(b)*sin(c))), + (a*tan(b + c), a*((tan(b) + tan(c))/(1 - tan(b)*tan(c)))), + + (a*sinh(b)**2, a*cosh(b)**2 - a), + (a*tanh(b)**2, a - a*(1/cosh(b))**2), + (a*coth(b)**2, a + a*(1/sinh(b))**2), + (a*sinh(b + c), a*(sinh(b)*cosh(c) + sinh(c)*cosh(b))), + (a*cosh(b + c), a*(cosh(b)*cosh(c) + sinh(b)*sinh(c))), + (a*tanh(b + c), a*((tanh(b) + tanh(c))/(1 + tanh(b)*tanh(c)))), + + ) + + # Reduce any lingering artifacts, such as sin(x)**2 changing + # to 1-cos(x)**2 when sin(x)**2 was "simpler" + artifacts = ( + (a - a*cos(b)**2 + c, a*sin(b)**2 + c, cos), + (a - a*(1/cos(b))**2 + c, -a*tan(b)**2 + c, cos), + (a - a*(1/sin(b))**2 + c, -a*cot(b)**2 + c, sin), + + (a - a*cosh(b)**2 + c, -a*sinh(b)**2 + c, cosh), + (a - a*(1/cosh(b))**2 + c, a*tanh(b)**2 + c, cosh), + (a + a*(1/sinh(b))**2 + c, a*coth(b)**2 + c, sinh), + + # same as above but with noncommutative prefactor + (a*d - a*d*cos(b)**2 + c, a*d*sin(b)**2 + c, cos), + (a*d - a*d*(1/cos(b))**2 + c, -a*d*tan(b)**2 + c, cos), + (a*d - a*d*(1/sin(b))**2 + c, -a*d*cot(b)**2 + c, sin), + + (a*d - a*d*cosh(b)**2 + c, -a*d*sinh(b)**2 + c, cosh), + (a*d - a*d*(1/cosh(b))**2 + c, a*d*tanh(b)**2 + c, cosh), + (a*d + a*d*(1/sinh(b))**2 + c, a*d*coth(b)**2 + c, sinh), + ) + + _trigpat = (a, b, c, d, matchers_division, matchers_add, + matchers_identity, artifacts) + return _trigpat + + +def _replace_mul_fpowxgpow(expr, f, g, rexp, h, rexph): + """Helper for _match_div_rewrite. + + Replace f(b_)**c_*g(b_)**(rexp(c_)) with h(b)**rexph(c) if f(b_) + and g(b_) are both positive or if c_ is an integer. + """ + # assert expr.is_Mul and expr.is_commutative and f != g + fargs = defaultdict(int) + gargs = defaultdict(int) + args = [] + for x in expr.args: + if x.is_Pow or x.func in (f, g): + b, e = x.as_base_exp() + if b.is_positive or e.is_integer: + if b.func == f: + fargs[b.args[0]] += e + continue + elif b.func == g: + gargs[b.args[0]] += e + continue + args.append(x) + common = set(fargs) & set(gargs) + hit = False + while common: + key = common.pop() + fe = fargs.pop(key) + ge = gargs.pop(key) + if fe == rexp(ge): + args.append(h(key)**rexph(fe)) + hit = True + else: + fargs[key] = fe + gargs[key] = ge + if not hit: + return expr + while fargs: + key, e = fargs.popitem() + args.append(f(key)**e) + while gargs: + key, e = gargs.popitem() + args.append(g(key)**e) + return Mul(*args) + + +_idn = lambda x: x +_midn = lambda x: -x +_one = lambda x: S.One + +def _match_div_rewrite(expr, i): + """helper for __trigsimp""" + if i == 0: + expr = _replace_mul_fpowxgpow(expr, sin, cos, + _midn, tan, _idn) + elif i == 1: + expr = _replace_mul_fpowxgpow(expr, tan, cos, + _idn, sin, _idn) + elif i == 2: + expr = _replace_mul_fpowxgpow(expr, cot, sin, + _idn, cos, _idn) + elif i == 3: + expr = _replace_mul_fpowxgpow(expr, tan, sin, + _midn, cos, _midn) + elif i == 4: + expr = _replace_mul_fpowxgpow(expr, cot, cos, + _midn, sin, _midn) + elif i == 5: + expr = _replace_mul_fpowxgpow(expr, cot, tan, + _idn, _one, _idn) + # i in (6, 7) is skipped + elif i == 8: + expr = _replace_mul_fpowxgpow(expr, sinh, cosh, + _midn, tanh, _idn) + elif i == 9: + expr = _replace_mul_fpowxgpow(expr, tanh, cosh, + _idn, sinh, _idn) + elif i == 10: + expr = _replace_mul_fpowxgpow(expr, coth, sinh, + _idn, cosh, _idn) + elif i == 11: + expr = _replace_mul_fpowxgpow(expr, tanh, sinh, + _midn, cosh, _midn) + elif i == 12: + expr = _replace_mul_fpowxgpow(expr, coth, cosh, + _midn, sinh, _midn) + elif i == 13: + expr = _replace_mul_fpowxgpow(expr, coth, tanh, + _idn, _one, _idn) + else: + return None + return expr + + +def _trigsimp(expr, deep=False): + # protect the cache from non-trig patterns; we only allow + # trig patterns to enter the cache + if expr.has(*_trigs): + return __trigsimp(expr, deep) + return expr + + +@cacheit +def __trigsimp(expr, deep=False): + """recursive helper for trigsimp""" + from sympy.simplify.fu import TR10i + + if _trigpat is None: + _trigpats() + a, b, c, d, matchers_division, matchers_add, \ + matchers_identity, artifacts = _trigpat + + if expr.is_Mul: + # do some simplifications like sin/cos -> tan: + if not expr.is_commutative: + com, nc = expr.args_cnc() + expr = _trigsimp(Mul._from_args(com), deep)*Mul._from_args(nc) + else: + for i, (pattern, simp, ok1, ok2) in enumerate(matchers_division): + if not _dotrig(expr, pattern): + continue + + newexpr = _match_div_rewrite(expr, i) + if newexpr is not None: + if newexpr != expr: + expr = newexpr + break + else: + continue + + # use SymPy matching instead + res = expr.match(pattern) + if res and res.get(c, 0): + if not res[c].is_integer: + ok = ok1.subs(res) + if not ok.is_positive: + continue + ok = ok2.subs(res) + if not ok.is_positive: + continue + # if "a" contains any of trig or hyperbolic funcs with + # argument "b" then skip the simplification + if any(w.args[0] == res[b] for w in res[a].atoms( + TrigonometricFunction, HyperbolicFunction)): + continue + # simplify and finish: + expr = simp.subs(res) + break # process below + + if expr.is_Add: + args = [] + for term in expr.args: + if not term.is_commutative: + com, nc = term.args_cnc() + nc = Mul._from_args(nc) + term = Mul._from_args(com) + else: + nc = S.One + term = _trigsimp(term, deep) + for pattern, result in matchers_identity: + res = term.match(pattern) + if res is not None: + term = result.subs(res) + break + args.append(term*nc) + if args != expr.args: + expr = Add(*args) + expr = min(expr, expand(expr), key=count_ops) + if expr.is_Add: + for pattern, result in matchers_add: + if not _dotrig(expr, pattern): + continue + expr = TR10i(expr) + if expr.has(HyperbolicFunction): + res = expr.match(pattern) + # if "d" contains any trig or hyperbolic funcs with + # argument "a" or "b" then skip the simplification; + # this isn't perfect -- see tests + if res is None or not (a in res and b in res) or any( + w.args[0] in (res[a], res[b]) for w in res[d].atoms( + TrigonometricFunction, HyperbolicFunction)): + continue + expr = result.subs(res) + break + + # Reduce any lingering artifacts, such as sin(x)**2 changing + # to 1 - cos(x)**2 when sin(x)**2 was "simpler" + for pattern, result, ex in artifacts: + if not _dotrig(expr, pattern): + continue + # Substitute a new wild that excludes some function(s) + # to help influence a better match. This is because + # sometimes, for example, 'a' would match sec(x)**2 + a_t = Wild('a', exclude=[ex]) + pattern = pattern.subs(a, a_t) + result = result.subs(a, a_t) + + m = expr.match(pattern) + was = None + while m and was != expr: + was = expr + if m[a_t] == 0 or \ + -m[a_t] in m[c].args or m[a_t] + m[c] == 0: + break + if d in m and m[a_t]*m[d] + m[c] == 0: + break + expr = result.subs(m) + m = expr.match(pattern) + m.setdefault(c, S.Zero) + + elif expr.is_Mul or expr.is_Pow or deep and expr.args: + expr = expr.func(*[_trigsimp(a, deep) for a in expr.args]) + + try: + if not expr.has(*_trigs): + raise TypeError + e = expr.atoms(exp) + new = expr.rewrite(exp, deep=deep) + if new == e: + raise TypeError + fnew = factor(new) + if fnew != new: + new = min([new, factor(new)], key=count_ops) + # if all exp that were introduced disappeared then accept it + if not (new.atoms(exp) - e): + expr = new + except TypeError: + pass + + return expr +#------------------- end of old trigsimp routines -------------------- + + +def futrig(e, *, hyper=True, **kwargs): + """Return simplified ``e`` using Fu-like transformations. + This is not the "Fu" algorithm. This is called by default + from ``trigsimp``. By default, hyperbolics subexpressions + will be simplified, but this can be disabled by setting + ``hyper=False``. + + Examples + ======== + + >>> from sympy import trigsimp, tan, sinh, tanh + >>> from sympy.simplify.trigsimp import futrig + >>> from sympy.abc import x + >>> trigsimp(1/tan(x)**2) + tan(x)**(-2) + + >>> futrig(sinh(x)/tanh(x)) + cosh(x) + + """ + from sympy.simplify.fu import hyper_as_trig + + e = sympify(e) + + if not isinstance(e, Basic): + return e + + if not e.args: + return e + + old = e + e = bottom_up(e, _futrig) + + if hyper and e.has(HyperbolicFunction): + e, f = hyper_as_trig(e) + e = f(bottom_up(e, _futrig)) + + if e != old and e.is_Mul and e.args[0].is_Rational: + # redistribute leading coeff on 2-arg Add + e = Mul(*e.as_coeff_Mul()) + return e + + +def _futrig(e): + """Helper for futrig.""" + from sympy.simplify.fu import ( + TR1, TR2, TR3, TR2i, TR10, L, TR10i, + TR8, TR6, TR15, TR16, TR111, TR5, TRmorrie, TR11, _TR11, TR14, TR22, + TR12) + + if not e.has(TrigonometricFunction): + return e + + if e.is_Mul: + coeff, e = e.as_independent(TrigonometricFunction) + else: + coeff = None + + Lops = lambda x: (L(x), x.count_ops(), _nodes(x), len(x.args), x.is_Add) + trigs = lambda x: x.has(TrigonometricFunction) + + tree = [identity, + ( + TR3, # canonical angles + TR1, # sec-csc -> cos-sin + TR12, # expand tan of sum + lambda x: _eapply(factor, x, trigs), + TR2, # tan-cot -> sin-cos + [identity, lambda x: _eapply(_mexpand, x, trigs)], + TR2i, # sin-cos ratio -> tan + lambda x: _eapply(lambda i: factor(i.normal()), x, trigs), + TR14, # factored identities + TR5, # sin-pow -> cos_pow + TR10, # sin-cos of sums -> sin-cos prod + TR11, _TR11, TR6, # reduce double angles and rewrite cos pows + lambda x: _eapply(factor, x, trigs), + TR14, # factored powers of identities + [identity, lambda x: _eapply(_mexpand, x, trigs)], + TR10i, # sin-cos products > sin-cos of sums + TRmorrie, + [identity, TR8], # sin-cos products -> sin-cos of sums + [identity, lambda x: TR2i(TR2(x))], # tan -> sin-cos -> tan + [ + lambda x: _eapply(expand_mul, TR5(x), trigs), + lambda x: _eapply( + expand_mul, TR15(x), trigs)], # pos/neg powers of sin + [ + lambda x: _eapply(expand_mul, TR6(x), trigs), + lambda x: _eapply( + expand_mul, TR16(x), trigs)], # pos/neg powers of cos + TR111, # tan, sin, cos to neg power -> cot, csc, sec + [identity, TR2i], # sin-cos ratio to tan + [identity, lambda x: _eapply( + expand_mul, TR22(x), trigs)], # tan-cot to sec-csc + TR1, TR2, TR2i, + [identity, lambda x: _eapply( + factor_terms, TR12(x), trigs)], # expand tan of sum + )] + e = greedy(tree, objective=Lops)(e) + + if coeff is not None: + e = coeff * e + + return e + + +def _is_Expr(e): + """_eapply helper to tell whether ``e`` and all its args + are Exprs.""" + if isinstance(e, Derivative): + return _is_Expr(e.expr) + if not isinstance(e, Expr): + return False + return all(_is_Expr(i) for i in e.args) + + +def _eapply(func, e, cond=None): + """Apply ``func`` to ``e`` if all args are Exprs else only + apply it to those args that *are* Exprs.""" + if not isinstance(e, Expr): + return e + if _is_Expr(e) or not e.args: + return func(e) + return e.func(*[ + _eapply(func, ei) if (cond is None or cond(ei)) else ei + for ei in e.args]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..02cfb35a765c748e70ecc36dd78d8d4432118c64 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__init__.py @@ -0,0 +1,75 @@ +"""A module for solving all kinds of equations. + + Examples + ======== + + >>> from sympy.solvers import solve + >>> from sympy.abc import x + >>> solve(((x + 1)**5).expand(), x) + [-1] +""" +from sympy.core.assumptions import check_assumptions, failing_assumptions + +from .solvers import solve, solve_linear_system, solve_linear_system_LU, \ + solve_undetermined_coeffs, nsolve, solve_linear, checksol, \ + det_quick, inv_quick + +from sympy.solvers.diophantine.diophantine import diophantine + +from .recurr import rsolve, rsolve_poly, rsolve_ratio, rsolve_hyper + +from .ode import checkodesol, classify_ode, dsolve, \ + homogeneous_order + +from .polysys import solve_poly_system, solve_triangulated, factor_system + +from .pde import pde_separate, pde_separate_add, pde_separate_mul, \ + pdsolve, classify_pde, checkpdesol + +from .deutils import ode_order + +from .inequalities import reduce_inequalities, reduce_abs_inequality, \ + reduce_abs_inequalities, solve_poly_inequality, solve_rational_inequalities, solve_univariate_inequality + +from .decompogen import decompogen + +from .solveset import solveset, linsolve, linear_eq_to_matrix, nonlinsolve, substitution + +from .simplex import lpmin, lpmax, linprog + +# This is here instead of sympy/sets/__init__.py to avoid circular import issues +from ..core.singleton import S +Complexes = S.Complexes + +__all__ = [ + 'solve', 'solve_linear_system', 'solve_linear_system_LU', + 'solve_undetermined_coeffs', 'nsolve', 'solve_linear', 'checksol', + 'det_quick', 'inv_quick', 'check_assumptions', 'failing_assumptions', + + 'diophantine', + + 'rsolve', 'rsolve_poly', 'rsolve_ratio', 'rsolve_hyper', + + 'checkodesol', 'classify_ode', 'dsolve', 'homogeneous_order', + + 'solve_poly_system', 'solve_triangulated', 'factor_system', + + 'pde_separate', 'pde_separate_add', 'pde_separate_mul', 'pdsolve', + 'classify_pde', 'checkpdesol', + + 'ode_order', + + 'reduce_inequalities', 'reduce_abs_inequality', 'reduce_abs_inequalities', + 'solve_poly_inequality', 'solve_rational_inequalities', + 'solve_univariate_inequality', + + 'decompogen', + + 'solveset', 'linsolve', 'linear_eq_to_matrix', 'nonlinsolve', + 'substitution', + + # This is here instead of sympy/sets/__init__.py to avoid circular import issues + 'Complexes', + + 'lpmin', 'lpmax', 'linprog' +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/bivariate.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/bivariate.py new file mode 100644 index 0000000000000000000000000000000000000000..72f8e266a16634fa65366e1058543dfe2171ba1c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/bivariate.py @@ -0,0 +1,509 @@ +from sympy.core.add import Add +from sympy.core.exprtools import factor_terms +from sympy.core.function import expand_log, _mexpand +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.sorting import ordered +from sympy.core.symbol import Dummy +from sympy.functions.elementary.exponential import (LambertW, exp, log) +from sympy.functions.elementary.miscellaneous import root +from sympy.polys.polyroots import roots +from sympy.polys.polytools import Poly, factor +from sympy.simplify.simplify import separatevars +from sympy.simplify.radsimp import collect +from sympy.simplify.simplify import powsimp +from sympy.solvers.solvers import solve, _invert +from sympy.utilities.iterables import uniq + + +def _filtered_gens(poly, symbol): + """process the generators of ``poly``, returning the set of generators that + have ``symbol``. If there are two generators that are inverses of each other, + prefer the one that has no denominator. + + Examples + ======== + + >>> from sympy.solvers.bivariate import _filtered_gens + >>> from sympy import Poly, exp + >>> from sympy.abc import x + >>> _filtered_gens(Poly(x + 1/x + exp(x)), x) + {x, exp(x)} + + """ + # TODO it would be good to pick the smallest divisible power + # instead of the base for something like x**4 + x**2 --> + # return x**2 not x + gens = {g for g in poly.gens if symbol in g.free_symbols} + for g in list(gens): + ag = 1/g + if g in gens and ag in gens: + if ag.as_numer_denom()[1] is not S.One: + g = ag + gens.remove(g) + return gens + + +def _mostfunc(lhs, func, X=None): + """Returns the term in lhs which contains the most of the + func-type things e.g. log(log(x)) wins over log(x) if both terms appear. + + ``func`` can be a function (exp, log, etc...) or any other SymPy object, + like Pow. + + If ``X`` is not ``None``, then the function returns the term composed with the + most ``func`` having the specified variable. + + Examples + ======== + + >>> from sympy.solvers.bivariate import _mostfunc + >>> from sympy import exp + >>> from sympy.abc import x, y + >>> _mostfunc(exp(x) + exp(exp(x) + 2), exp) + exp(exp(x) + 2) + >>> _mostfunc(exp(x) + exp(exp(y) + 2), exp) + exp(exp(y) + 2) + >>> _mostfunc(exp(x) + exp(exp(y) + 2), exp, x) + exp(x) + >>> _mostfunc(x, exp, x) is None + True + >>> _mostfunc(exp(x) + exp(x*y), exp, x) + exp(x) + """ + fterms = [tmp for tmp in lhs.atoms(func) if (not X or + X.is_Symbol and X in tmp.free_symbols or + not X.is_Symbol and tmp.has(X))] + if len(fterms) == 1: + return fterms[0] + elif fterms: + return max(list(ordered(fterms)), key=lambda x: x.count(func)) + return None + + +def _linab(arg, symbol): + """Return ``a, b, X`` assuming ``arg`` can be written as ``a*X + b`` + where ``X`` is a symbol-dependent factor and ``a`` and ``b`` are + independent of ``symbol``. + + Examples + ======== + + >>> from sympy.solvers.bivariate import _linab + >>> from sympy.abc import x, y + >>> from sympy import exp, S + >>> _linab(S(2), x) + (2, 0, 1) + >>> _linab(2*x, x) + (2, 0, x) + >>> _linab(y + y*x + 2*x, x) + (y + 2, y, x) + >>> _linab(3 + 2*exp(x), x) + (2, 3, exp(x)) + """ + arg = factor_terms(arg.expand()) + ind, dep = arg.as_independent(symbol) + if arg.is_Mul and dep.is_Add: + a, b, x = _linab(dep, symbol) + return ind*a, ind*b, x + if not arg.is_Add: + b = 0 + a, x = ind, dep + else: + b = ind + a, x = separatevars(dep).as_independent(symbol, as_Add=False) + if x.could_extract_minus_sign(): + a = -a + x = -x + return a, b, x + + +def _lambert(eq, x): + """ + Given an expression assumed to be in the form + ``F(X, a..f) = a*log(b*X + c) + d*X + f = 0`` + where X = g(x) and x = g^-1(X), return the Lambert solution, + ``x = g^-1(-c/b + (a/d)*W(d/(a*b)*exp(c*d/a/b)*exp(-f/a)))``. + """ + eq = _mexpand(expand_log(eq)) + mainlog = _mostfunc(eq, log, x) + if not mainlog: + return [] # violated assumptions + other = eq.subs(mainlog, 0) + if isinstance(-other, log): + eq = (eq - other).subs(mainlog, mainlog.args[0]) + mainlog = mainlog.args[0] + if not isinstance(mainlog, log): + return [] # violated assumptions + other = -(-other).args[0] + eq += other + if x not in other.free_symbols: + return [] # violated assumptions + d, f, X2 = _linab(other, x) + logterm = collect(eq - other, mainlog) + a = logterm.as_coefficient(mainlog) + if a is None or x in a.free_symbols: + return [] # violated assumptions + logarg = mainlog.args[0] + b, c, X1 = _linab(logarg, x) + if X1 != X2: + return [] # violated assumptions + + # invert the generator X1 so we have x(u) + u = Dummy('rhs') + xusolns = solve(X1 - u, x) + + # There are infinitely many branches for LambertW + # but only branches for k = -1 and 0 might be real. The k = 0 + # branch is real and the k = -1 branch is real if the LambertW argument + # in in range [-1/e, 0]. Since `solve` does not return infinite + # solutions we will only include the -1 branch if it tests as real. + # Otherwise, inclusion of any LambertW in the solution indicates to + # the user that there are imaginary solutions corresponding to + # different k values. + lambert_real_branches = [-1, 0] + sol = [] + + # solution of the given Lambert equation is like + # sol = -c/b + (a/d)*LambertW(arg, k), + # where arg = d/(a*b)*exp((c*d-b*f)/a/b) and k in lambert_real_branches. + # Instead of considering the single arg, `d/(a*b)*exp((c*d-b*f)/a/b)`, + # the individual `p` roots obtained when writing `exp((c*d-b*f)/a/b)` + # as `exp(A/p) = exp(A)**(1/p)`, where `p` is an Integer, are used. + + # calculating args for LambertW + num, den = ((c*d-b*f)/a/b).as_numer_denom() + p, den = den.as_coeff_Mul() + e = exp(num/den) + t = Dummy('t') + args = [d/(a*b)*t for t in roots(t**p - e, t).keys()] + + # calculating solutions from args + for arg in args: + for k in lambert_real_branches: + w = LambertW(arg, k) + if k and not w.is_real: + continue + rhs = -c/b + (a/d)*w + + sol.extend(xu.subs(u, rhs) for xu in xusolns) + return sol + + +def _solve_lambert(f, symbol, gens): + """Return solution to ``f`` if it is a Lambert-type expression + else raise NotImplementedError. + + For ``f(X, a..f) = a*log(b*X + c) + d*X - f = 0`` the solution + for ``X`` is ``X = -c/b + (a/d)*W(d/(a*b)*exp(c*d/a/b)*exp(f/a))``. + There are a variety of forms for `f(X, a..f)` as enumerated below: + + 1a1) + if B**B = R for R not in [0, 1] (since those cases would already + be solved before getting here) then log of both sides gives + log(B) + log(log(B)) = log(log(R)) and + X = log(B), a = 1, b = 1, c = 0, d = 1, f = log(log(R)) + 1a2) + if B*(b*log(B) + c)**a = R then log of both sides gives + log(B) + a*log(b*log(B) + c) = log(R) and + X = log(B), d=1, f=log(R) + 1b) + if a*log(b*B + c) + d*B = R and + X = B, f = R + 2a) + if (b*B + c)*exp(d*B + g) = R then log of both sides gives + log(b*B + c) + d*B + g = log(R) and + X = B, a = 1, f = log(R) - g + 2b) + if g*exp(d*B + h) - b*B = c then the log form is + log(g) + d*B + h - log(b*B + c) = 0 and + X = B, a = -1, f = -h - log(g) + 3) + if d*p**(a*B + g) - b*B = c then the log form is + log(d) + (a*B + g)*log(p) - log(b*B + c) = 0 and + X = B, a = -1, d = a*log(p), f = -log(d) - g*log(p) + """ + + def _solve_even_degree_expr(expr, t, symbol): + """Return the unique solutions of equations derived from + ``expr`` by replacing ``t`` with ``+/- symbol``. + + Parameters + ========== + + expr : Expr + The expression which includes a dummy variable t to be + replaced with +symbol and -symbol. + + symbol : Symbol + The symbol for which a solution is being sought. + + Returns + ======= + + List of unique solution of the two equations generated by + replacing ``t`` with positive and negative ``symbol``. + + Notes + ===== + + If ``expr = 2*log(t) + x/2` then solutions for + ``2*log(x) + x/2 = 0`` and ``2*log(-x) + x/2 = 0`` are + returned by this function. Though this may seem + counter-intuitive, one must note that the ``expr`` being + solved here has been derived from a different expression. For + an expression like ``eq = x**2*g(x) = 1``, if we take the + log of both sides we obtain ``log(x**2) + log(g(x)) = 0``. If + x is positive then this simplifies to + ``2*log(x) + log(g(x)) = 0``; the Lambert-solving routines will + return solutions for this, but we must also consider the + solutions for ``2*log(-x) + log(g(x))`` since those must also + be a solution of ``eq`` which has the same value when the ``x`` + in ``x**2`` is negated. If `g(x)` does not have even powers of + symbol then we do not want to replace the ``x`` there with + ``-x``. So the role of the ``t`` in the expression received by + this function is to mark where ``+/-x`` should be inserted + before obtaining the Lambert solutions. + + """ + nlhs, plhs = [ + expr.xreplace({t: sgn*symbol}) for sgn in (-1, 1)] + sols = _solve_lambert(nlhs, symbol, gens) + if plhs != nlhs: + sols.extend(_solve_lambert(plhs, symbol, gens)) + # uniq is needed for a case like + # 2*log(t) - log(-z**2) + log(z + log(x) + log(z)) + # where substituting t with +/-x gives all the same solution; + # uniq, rather than list(set()), is used to maintain canonical + # order + return list(uniq(sols)) + + nrhs, lhs = f.as_independent(symbol, as_Add=True) + rhs = -nrhs + + lamcheck = [tmp for tmp in gens + if (tmp.func in [exp, log] or + (tmp.is_Pow and symbol in tmp.exp.free_symbols))] + if not lamcheck: + raise NotImplementedError() + + if lhs.is_Add or lhs.is_Mul: + # replacing all even_degrees of symbol with dummy variable t + # since these will need special handling; non-Add/Mul do not + # need this handling + t = Dummy('t', **symbol.assumptions0) + lhs = lhs.replace( + lambda i: # find symbol**even + i.is_Pow and i.base == symbol and i.exp.is_even, + lambda i: # replace t**even + t**i.exp) + + if lhs.is_Add and lhs.has(t): + t_indep = lhs.subs(t, 0) + t_term = lhs - t_indep + _rhs = rhs - t_indep + if not t_term.is_Add and _rhs and not ( + t_term.has(S.ComplexInfinity, S.NaN)): + eq = expand_log(log(t_term) - log(_rhs)) + return _solve_even_degree_expr(eq, t, symbol) + elif lhs.is_Mul and rhs: + # this needs to happen whether t is present or not + lhs = expand_log(log(lhs), force=True) + rhs = log(rhs) + if lhs.has(t) and lhs.is_Add: + # it expanded from Mul to Add + eq = lhs - rhs + return _solve_even_degree_expr(eq, t, symbol) + + # restore symbol in lhs + lhs = lhs.xreplace({t: symbol}) + + lhs = powsimp(factor(lhs, deep=True)) + + # make sure we have inverted as completely as possible + r = Dummy() + i, lhs = _invert(lhs - r, symbol) + rhs = i.xreplace({r: rhs}) + + # For the first forms: + # + # 1a1) B**B = R will arrive here as B*log(B) = log(R) + # lhs is Mul so take log of both sides: + # log(B) + log(log(B)) = log(log(R)) + # 1a2) B*(b*log(B) + c)**a = R will arrive unchanged so + # lhs is Mul, so take log of both sides: + # log(B) + a*log(b*log(B) + c) = log(R) + # 1b) d*log(a*B + b) + c*B = R will arrive unchanged so + # lhs is Add, so isolate c*B and expand log of both sides: + # log(c) + log(B) = log(R - d*log(a*B + b)) + + soln = [] + if not soln: + mainlog = _mostfunc(lhs, log, symbol) + if mainlog: + if lhs.is_Mul and rhs != 0: + soln = _lambert(log(lhs) - log(rhs), symbol) + elif lhs.is_Add: + other = lhs.subs(mainlog, 0) + if other and not other.is_Add and [ + tmp for tmp in other.atoms(Pow) + if symbol in tmp.free_symbols]: + if not rhs: + diff = log(other) - log(other - lhs) + else: + diff = log(lhs - other) - log(rhs - other) + soln = _lambert(expand_log(diff), symbol) + else: + #it's ready to go + soln = _lambert(lhs - rhs, symbol) + + # For the next forms, + # + # collect on main exp + # 2a) (b*B + c)*exp(d*B + g) = R + # lhs is mul, so take log of both sides: + # log(b*B + c) + d*B = log(R) - g + # 2b) g*exp(d*B + h) - b*B = R + # lhs is add, so add b*B to both sides, + # take the log of both sides and rearrange to give + # log(R + b*B) - d*B = log(g) + h + + if not soln: + mainexp = _mostfunc(lhs, exp, symbol) + if mainexp: + lhs = collect(lhs, mainexp) + if lhs.is_Mul and rhs != 0: + soln = _lambert(expand_log(log(lhs) - log(rhs)), symbol) + elif lhs.is_Add: + # move all but mainexp-containing term to rhs + other = lhs.subs(mainexp, 0) + mainterm = lhs - other + rhs = rhs - other + if (mainterm.could_extract_minus_sign() and + rhs.could_extract_minus_sign()): + mainterm *= -1 + rhs *= -1 + diff = log(mainterm) - log(rhs) + soln = _lambert(expand_log(diff), symbol) + + # For the last form: + # + # 3) d*p**(a*B + g) - b*B = c + # collect on main pow, add b*B to both sides, + # take log of both sides and rearrange to give + # a*B*log(p) - log(b*B + c) = -log(d) - g*log(p) + if not soln: + mainpow = _mostfunc(lhs, Pow, symbol) + if mainpow and symbol in mainpow.exp.free_symbols: + lhs = collect(lhs, mainpow) + if lhs.is_Mul and rhs != 0: + # b*B = 0 + soln = _lambert(expand_log(log(lhs) - log(rhs)), symbol) + elif lhs.is_Add: + # move all but mainpow-containing term to rhs + other = lhs.subs(mainpow, 0) + mainterm = lhs - other + rhs = rhs - other + diff = log(mainterm) - log(rhs) + soln = _lambert(expand_log(diff), symbol) + + if not soln: + raise NotImplementedError('%s does not appear to have a solution in ' + 'terms of LambertW' % f) + + return list(ordered(soln)) + + +def bivariate_type(f, x, y, *, first=True): + """Given an expression, f, 3 tests will be done to see what type + of composite bivariate it might be, options for u(x, y) are:: + + x*y + x+y + x*y+x + x*y+y + + If it matches one of these types, ``u(x, y)``, ``P(u)`` and dummy + variable ``u`` will be returned. Solving ``P(u)`` for ``u`` and + equating the solutions to ``u(x, y)`` and then solving for ``x`` or + ``y`` is equivalent to solving the original expression for ``x`` or + ``y``. If ``x`` and ``y`` represent two functions in the same + variable, e.g. ``x = g(t)`` and ``y = h(t)``, then if ``u(x, y) - p`` + can be solved for ``t`` then these represent the solutions to + ``P(u) = 0`` when ``p`` are the solutions of ``P(u) = 0``. + + Only positive values of ``u`` are considered. + + Examples + ======== + + >>> from sympy import solve + >>> from sympy.solvers.bivariate import bivariate_type + >>> from sympy.abc import x, y + >>> eq = (x**2 - 3).subs(x, x + y) + >>> bivariate_type(eq, x, y) + (x + y, _u**2 - 3, _u) + >>> uxy, pu, u = _ + >>> usol = solve(pu, u); usol + [sqrt(3)] + >>> [solve(uxy - s) for s in solve(pu, u)] + [[{x: -y + sqrt(3)}]] + >>> all(eq.subs(s).equals(0) for sol in _ for s in sol) + True + + """ + + u = Dummy('u', positive=True) + + if first: + p = Poly(f, x, y) + f = p.as_expr() + _x = Dummy() + _y = Dummy() + rv = bivariate_type(Poly(f.subs({x: _x, y: _y}), _x, _y), _x, _y, first=False) + if rv: + reps = {_x: x, _y: y} + return rv[0].xreplace(reps), rv[1].xreplace(reps), rv[2] + return + + p = f + f = p.as_expr() + + # f(x*y) + args = Add.make_args(p.as_expr()) + new = [] + for a in args: + a = _mexpand(a.subs(x, u/y)) + free = a.free_symbols + if x in free or y in free: + break + new.append(a) + else: + return x*y, Add(*new), u + + def ok(f, v, c): + new = _mexpand(f.subs(v, c)) + free = new.free_symbols + return None if (x in free or y in free) else new + + # f(a*x + b*y) + new = [] + d = p.degree(x) + if p.degree(y) == d: + a = root(p.coeff_monomial(x**d), d) + b = root(p.coeff_monomial(y**d), d) + new = ok(f, x, (u - b*y)/a) + if new is not None: + return a*x + b*y, new, u + + # f(a*x*y + b*y) + new = [] + d = p.degree(x) + if p.degree(y) == d: + for itry in range(2): + a = root(p.coeff_monomial(x**d*y**d), d) + b = root(p.coeff_monomial(y**d), d) + new = ok(f, x, (u - b*y)/a/y) + if new is not None: + return a*x*y + b*y, new, u + x, y = y, x diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/decompogen.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/decompogen.py new file mode 100644 index 0000000000000000000000000000000000000000..ec1b3b683511a34e6f98b9839d112b87517390d8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/decompogen.py @@ -0,0 +1,126 @@ +from sympy.core import (Function, Pow, sympify, Expr) +from sympy.core.relational import Relational +from sympy.core.singleton import S +from sympy.polys import Poly, decompose +from sympy.utilities.misc import func_name +from sympy.functions.elementary.miscellaneous import Min, Max + + +def decompogen(f, symbol): + """ + Computes General functional decomposition of ``f``. + Given an expression ``f``, returns a list ``[f_1, f_2, ..., f_n]``, + where:: + f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n)) + + Note: This is a General decomposition function. It also decomposes + Polynomials. For only Polynomial decomposition see ``decompose`` in polys. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import decompogen, sqrt, sin, cos + >>> decompogen(sin(cos(x)), x) + [sin(x), cos(x)] + >>> decompogen(sin(x)**2 + sin(x) + 1, x) + [x**2 + x + 1, sin(x)] + >>> decompogen(sqrt(6*x**2 - 5), x) + [sqrt(x), 6*x**2 - 5] + >>> decompogen(sin(sqrt(cos(x**2 + 1))), x) + [sin(x), sqrt(x), cos(x), x**2 + 1] + >>> decompogen(x**4 + 2*x**3 - x - 1, x) + [x**2 - x - 1, x**2 + x] + + """ + f = sympify(f) + if not isinstance(f, Expr) or isinstance(f, Relational): + raise TypeError('expecting Expr but got: `%s`' % func_name(f)) + if symbol not in f.free_symbols: + return [f] + + + # ===== Simple Functions ===== # + if isinstance(f, (Function, Pow)): + if f.is_Pow and f.base == S.Exp1: + arg = f.exp + else: + arg = f.args[0] + if arg == symbol: + return [f] + return [f.subs(arg, symbol)] + decompogen(arg, symbol) + + # ===== Min/Max Functions ===== # + if isinstance(f, (Min, Max)): + args = list(f.args) + d0 = None + for i, a in enumerate(args): + if not a.has_free(symbol): + continue + d = decompogen(a, symbol) + if len(d) == 1: + d = [symbol] + d + if d0 is None: + d0 = d[1:] + elif d[1:] != d0: + # decomposition is not the same for each arg: + # mark as having no decomposition + d = [symbol] + break + args[i] = d[0] + if d[0] == symbol: + return [f] + return [f.func(*args)] + d0 + + # ===== Convert to Polynomial ===== # + fp = Poly(f) + gens = list(filter(lambda x: symbol in x.free_symbols, fp.gens)) + + if len(gens) == 1 and gens[0] != symbol: + f1 = f.subs(gens[0], symbol) + f2 = gens[0] + return [f1] + decompogen(f2, symbol) + + # ===== Polynomial decompose() ====== # + try: + return decompose(f) + except ValueError: + return [f] + + +def compogen(g_s, symbol): + """ + Returns the composition of functions. + Given a list of functions ``g_s``, returns their composition ``f``, + where: + f = g_1 o g_2 o .. o g_n + + Note: This is a General composition function. It also composes Polynomials. + For only Polynomial composition see ``compose`` in polys. + + Examples + ======== + + >>> from sympy.solvers.decompogen import compogen + >>> from sympy.abc import x + >>> from sympy import sqrt, sin, cos + >>> compogen([sin(x), cos(x)], x) + sin(cos(x)) + >>> compogen([x**2 + x + 1, sin(x)], x) + sin(x)**2 + sin(x) + 1 + >>> compogen([sqrt(x), 6*x**2 - 5], x) + sqrt(6*x**2 - 5) + >>> compogen([sin(x), sqrt(x), cos(x), x**2 + 1], x) + sin(sqrt(cos(x**2 + 1))) + >>> compogen([x**2 - x - 1, x**2 + x], x) + -x**2 - x + (x**2 + x)**2 - 1 + """ + if len(g_s) == 1: + return g_s[0] + + foo = g_s[0].subs(symbol, g_s[1]) + + if len(g_s) == 2: + return foo + + return compogen([foo] + g_s[2:], symbol) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/deutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/deutils.py new file mode 100644 index 0000000000000000000000000000000000000000..b13f37b5004fe7bce2545ad2c788ec3feae56025 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/deutils.py @@ -0,0 +1,273 @@ +"""Utility functions for classifying and solving +ordinary and partial differential equations. + +Contains +======== +_preprocess +ode_order +_desolve + +""" +from sympy.core import Pow +from sympy.core.function import Derivative, AppliedUndef +from sympy.core.relational import Equality +from sympy.core.symbol import Wild + +def _preprocess(expr, func=None, hint='_Integral'): + """Prepare expr for solving by making sure that differentiation + is done so that only func remains in unevaluated derivatives and + (if hint does not end with _Integral) that doit is applied to all + other derivatives. If hint is None, do not do any differentiation. + (Currently this may cause some simple differential equations to + fail.) + + In case func is None, an attempt will be made to autodetect the + function to be solved for. + + >>> from sympy.solvers.deutils import _preprocess + >>> from sympy import Derivative, Function + >>> from sympy.abc import x, y, z + >>> f, g = map(Function, 'fg') + + If f(x)**p == 0 and p>0 then we can solve for f(x)=0 + >>> _preprocess((f(x).diff(x)-4)**5, f(x)) + (Derivative(f(x), x) - 4, f(x)) + + Apply doit to derivatives that contain more than the function + of interest: + + >>> _preprocess(Derivative(f(x) + x, x)) + (Derivative(f(x), x) + 1, f(x)) + + Do others if the differentiation variable(s) intersect with those + of the function of interest or contain the function of interest: + + >>> _preprocess(Derivative(g(x), y, z), f(y)) + (0, f(y)) + >>> _preprocess(Derivative(f(y), z), f(y)) + (0, f(y)) + + Do others if the hint does not end in '_Integral' (the default + assumes that it does): + + >>> _preprocess(Derivative(g(x), y), f(x)) + (Derivative(g(x), y), f(x)) + >>> _preprocess(Derivative(f(x), y), f(x), hint='') + (0, f(x)) + + Do not do any derivatives if hint is None: + + >>> eq = Derivative(f(x) + 1, x) + Derivative(f(x), y) + >>> _preprocess(eq, f(x), hint=None) + (Derivative(f(x) + 1, x) + Derivative(f(x), y), f(x)) + + If it's not clear what the function of interest is, it must be given: + + >>> eq = Derivative(f(x) + g(x), x) + >>> _preprocess(eq, g(x)) + (Derivative(f(x), x) + Derivative(g(x), x), g(x)) + >>> try: _preprocess(eq) + ... except ValueError: print("A ValueError was raised.") + A ValueError was raised. + + """ + if isinstance(expr, Pow): + # if f(x)**p=0 then f(x)=0 (p>0) + if (expr.exp).is_positive: + expr = expr.base + derivs = expr.atoms(Derivative) + if not func: + funcs = set().union(*[d.atoms(AppliedUndef) for d in derivs]) + if len(funcs) != 1: + raise ValueError('The function cannot be ' + 'automatically detected for %s.' % expr) + func = funcs.pop() + fvars = set(func.args) + if hint is None: + return expr, func + reps = [(d, d.doit()) for d in derivs if not hint.endswith('_Integral') or + d.has(func) or set(d.variables) & fvars] + eq = expr.subs(reps) + return eq, func + + +def ode_order(expr, func): + """ + Returns the order of a given differential + equation with respect to func. + + This function is implemented recursively. + + Examples + ======== + + >>> from sympy import Function + >>> from sympy.solvers.deutils import ode_order + >>> from sympy.abc import x + >>> f, g = map(Function, ['f', 'g']) + >>> ode_order(f(x).diff(x, 2) + f(x).diff(x)**2 + + ... f(x).diff(x), f(x)) + 2 + >>> ode_order(f(x).diff(x, 2) + g(x).diff(x, 3), f(x)) + 2 + >>> ode_order(f(x).diff(x, 2) + g(x).diff(x, 3), g(x)) + 3 + + """ + a = Wild('a', exclude=[func]) + if expr.match(a): + return 0 + + if isinstance(expr, Derivative): + if expr.args[0] == func: + return len(expr.variables) + else: + args = expr.args[0].args + rv = len(expr.variables) + if args: + rv += max(ode_order(_, func) for _ in args) + return rv + else: + return max(ode_order(_, func) for _ in expr.args) if expr.args else 0 + + +def _desolve(eq, func=None, hint="default", ics=None, simplify=True, *, prep=True, **kwargs): + """This is a helper function to dsolve and pdsolve in the ode + and pde modules. + + If the hint provided to the function is "default", then a dict with + the following keys are returned + + 'func' - It provides the function for which the differential equation + has to be solved. This is useful when the expression has + more than one function in it. + + 'default' - The default key as returned by classifier functions in ode + and pde.py + + 'hint' - The hint given by the user for which the differential equation + is to be solved. If the hint given by the user is 'default', + then the value of 'hint' and 'default' is the same. + + 'order' - The order of the function as returned by ode_order + + 'match' - It returns the match as given by the classifier functions, for + the default hint. + + If the hint provided to the function is not "default" and is not in + ('all', 'all_Integral', 'best'), then a dict with the above mentioned keys + is returned along with the keys which are returned when dict in + classify_ode or classify_pde is set True + + If the hint given is in ('all', 'all_Integral', 'best'), then this function + returns a nested dict, with the keys, being the set of classified hints + returned by classifier functions, and the values being the dict of form + as mentioned above. + + Key 'eq' is a common key to all the above mentioned hints which returns an + expression if eq given by user is an Equality. + + See Also + ======== + classify_ode(ode.py) + classify_pde(pde.py) + """ + if isinstance(eq, Equality): + eq = eq.lhs - eq.rhs + + # preprocess the equation and find func if not given + if prep or func is None: + eq, func = _preprocess(eq, func) + prep = False + + # type is an argument passed by the solve functions in ode and pde.py + # that identifies whether the function caller is an ordinary + # or partial differential equation. Accordingly corresponding + # changes are made in the function. + type = kwargs.get('type', None) + xi = kwargs.get('xi') + eta = kwargs.get('eta') + x0 = kwargs.get('x0', 0) + terms = kwargs.get('n') + + if type == 'ode': + from sympy.solvers.ode import classify_ode, allhints + classifier = classify_ode + string = 'ODE ' + dummy = '' + + elif type == 'pde': + from sympy.solvers.pde import classify_pde, allhints + classifier = classify_pde + string = 'PDE ' + dummy = 'p' + + # Magic that should only be used internally. Prevents classify_ode from + # being called more than it needs to be by passing its results through + # recursive calls. + if kwargs.get('classify', True): + hints = classifier(eq, func, dict=True, ics=ics, xi=xi, eta=eta, + n=terms, x0=x0, hint=hint, prep=prep) + + else: + # Here is what all this means: + # + # hint: The hint method given to _desolve() by the user. + # hints: The dictionary of hints that match the DE, along with other + # information (including the internal pass-through magic). + # default: The default hint to return, the first hint from allhints + # that matches the hint; obtained from classify_ode(). + # match: Dictionary containing the match dictionary for each hint + # (the parts of the DE for solving). When going through the + # hints in "all", this holds the match string for the current + # hint. + # order: The order of the DE, as determined by ode_order(). + hints = kwargs.get('hint', + {'default': hint, + hint: kwargs['match'], + 'order': kwargs['order']}) + if not hints['default']: + # classify_ode will set hints['default'] to None if no hints match. + if hint not in allhints and hint != 'default': + raise ValueError("Hint not recognized: " + hint) + elif hint not in hints['ordered_hints'] and hint != 'default': + raise ValueError(string + str(eq) + " does not match hint " + hint) + # If dsolve can't solve the purely algebraic equation then dsolve will raise + # ValueError + elif hints['order'] == 0: + raise ValueError( + str(eq) + " is not a solvable differential equation in " + str(func)) + else: + raise NotImplementedError(dummy + "solve" + ": Cannot solve " + str(eq)) + if hint == 'default': + return _desolve(eq, func, ics=ics, hint=hints['default'], simplify=simplify, + prep=prep, x0=x0, classify=False, order=hints['order'], + match=hints[hints['default']], xi=xi, eta=eta, n=terms, type=type) + elif hint in ('all', 'all_Integral', 'best'): + retdict = {} + gethints = set(hints) - {'order', 'default', 'ordered_hints'} + if hint == 'all_Integral': + for i in hints: + if i.endswith('_Integral'): + gethints.remove(i.removesuffix('_Integral')) + # special cases + for k in ["1st_homogeneous_coeff_best", "1st_power_series", + "lie_group", "2nd_power_series_ordinary", "2nd_power_series_regular"]: + if k in gethints: + gethints.remove(k) + for i in gethints: + sol = _desolve(eq, func, ics=ics, hint=i, x0=x0, simplify=simplify, prep=prep, + classify=False, n=terms, order=hints['order'], match=hints[i], type=type) + retdict[i] = sol + retdict['all'] = True + retdict['eq'] = eq + return retdict + elif hint not in allhints: # and hint not in ('default', 'ordered_hints'): + raise ValueError("Hint not recognized: " + hint) + elif hint not in hints: + raise ValueError(string + str(eq) + " does not match hint " + hint) + else: + # Key added to identify the hint needed to solve the equation + hints['hint'] = hint + hints.update({'func': func, 'eq': eq}) + return hints diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/inequalities.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/inequalities.py new file mode 100644 index 0000000000000000000000000000000000000000..f50f7a7572ff25e8f48a4214d7b0c5ec6b5b35f3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/inequalities.py @@ -0,0 +1,986 @@ +"""Tools for solving inequalities and systems of inequalities. """ +import itertools + +from sympy.calculus.util import (continuous_domain, periodicity, + function_range) +from sympy.core import sympify +from sympy.core.exprtools import factor_terms +from sympy.core.relational import Relational, Lt, Ge, Eq +from sympy.core.symbol import Symbol, Dummy +from sympy.sets.sets import Interval, FiniteSet, Union, Intersection +from sympy.core.singleton import S +from sympy.core.function import expand_mul +from sympy.functions.elementary.complexes import Abs +from sympy.logic import And +from sympy.polys import Poly, PolynomialError, parallel_poly_from_expr +from sympy.polys.polyutils import _nsort +from sympy.solvers.solveset import solvify, solveset +from sympy.utilities.iterables import sift, iterable +from sympy.utilities.misc import filldedent + + +def solve_poly_inequality(poly, rel): + """Solve a polynomial inequality with rational coefficients. + + Examples + ======== + + >>> from sympy import solve_poly_inequality, Poly + >>> from sympy.abc import x + + >>> solve_poly_inequality(Poly(x, x, domain='ZZ'), '==') + [{0}] + + >>> solve_poly_inequality(Poly(x**2 - 1, x, domain='ZZ'), '!=') + [Interval.open(-oo, -1), Interval.open(-1, 1), Interval.open(1, oo)] + + >>> solve_poly_inequality(Poly(x**2 - 1, x, domain='ZZ'), '==') + [{-1}, {1}] + + See Also + ======== + solve_poly_inequalities + """ + if not isinstance(poly, Poly): + raise ValueError( + 'For efficiency reasons, `poly` should be a Poly instance') + if poly.as_expr().is_number: + t = Relational(poly.as_expr(), 0, rel) + if t is S.true: + return [S.Reals] + elif t is S.false: + return [S.EmptySet] + else: + raise NotImplementedError( + "could not determine truth value of %s" % t) + + reals, intervals = poly.real_roots(multiple=False), [] + + if rel == '==': + for root, _ in reals: + interval = Interval(root, root) + intervals.append(interval) + elif rel == '!=': + left = S.NegativeInfinity + + for right, _ in reals + [(S.Infinity, 1)]: + interval = Interval(left, right, True, True) + intervals.append(interval) + left = right + else: + if poly.LC() > 0: + sign = +1 + else: + sign = -1 + + eq_sign, equal = None, False + + if rel == '>': + eq_sign = +1 + elif rel == '<': + eq_sign = -1 + elif rel == '>=': + eq_sign, equal = +1, True + elif rel == '<=': + eq_sign, equal = -1, True + else: + raise ValueError("'%s' is not a valid relation" % rel) + + right, right_open = S.Infinity, True + + for left, multiplicity in reversed(reals): + if multiplicity % 2: + if sign == eq_sign: + intervals.insert( + 0, Interval(left, right, not equal, right_open)) + + sign, right, right_open = -sign, left, not equal + else: + if sign == eq_sign and not equal: + intervals.insert( + 0, Interval(left, right, True, right_open)) + right, right_open = left, True + elif sign != eq_sign and equal: + intervals.insert(0, Interval(left, left)) + + if sign == eq_sign: + intervals.insert( + 0, Interval(S.NegativeInfinity, right, True, right_open)) + + return intervals + + +def solve_poly_inequalities(polys): + """Solve polynomial inequalities with rational coefficients. + + Examples + ======== + + >>> from sympy import Poly + >>> from sympy.solvers.inequalities import solve_poly_inequalities + >>> from sympy.abc import x + >>> solve_poly_inequalities((( + ... Poly(x**2 - 3), ">"), ( + ... Poly(-x**2 + 1), ">"))) + Union(Interval.open(-oo, -sqrt(3)), Interval.open(-1, 1), Interval.open(sqrt(3), oo)) + """ + return Union(*[s for p in polys for s in solve_poly_inequality(*p)]) + + +def solve_rational_inequalities(eqs): + """Solve a system of rational inequalities with rational coefficients. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import solve_rational_inequalities, Poly + + >>> solve_rational_inequalities([[ + ... ((Poly(-x + 1), Poly(1, x)), '>='), + ... ((Poly(-x + 1), Poly(1, x)), '<=')]]) + {1} + + >>> solve_rational_inequalities([[ + ... ((Poly(x), Poly(1, x)), '!='), + ... ((Poly(-x + 1), Poly(1, x)), '>=')]]) + Union(Interval.open(-oo, 0), Interval.Lopen(0, 1)) + + See Also + ======== + solve_poly_inequality + """ + result = S.EmptySet + + for _eqs in eqs: + if not _eqs: + continue + + global_intervals = [Interval(S.NegativeInfinity, S.Infinity)] + + for (numer, denom), rel in _eqs: + numer_intervals = solve_poly_inequality(numer*denom, rel) + denom_intervals = solve_poly_inequality(denom, '==') + + intervals = [] + + for numer_interval, global_interval in itertools.product( + numer_intervals, global_intervals): + interval = numer_interval.intersect(global_interval) + + if interval is not S.EmptySet: + intervals.append(interval) + + global_intervals = intervals + + intervals = [] + + for global_interval in global_intervals: + for denom_interval in denom_intervals: + global_interval -= denom_interval + + if global_interval is not S.EmptySet: + intervals.append(global_interval) + + global_intervals = intervals + + if not global_intervals: + break + + for interval in global_intervals: + result = result.union(interval) + + return result + + +def reduce_rational_inequalities(exprs, gen, relational=True): + """Reduce a system of rational inequalities with rational coefficients. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.solvers.inequalities import reduce_rational_inequalities + + >>> x = Symbol('x', real=True) + + >>> reduce_rational_inequalities([[x**2 <= 0]], x) + Eq(x, 0) + + >>> reduce_rational_inequalities([[x + 2 > 0]], x) + -2 < x + >>> reduce_rational_inequalities([[(x + 2, ">")]], x) + -2 < x + >>> reduce_rational_inequalities([[x + 2]], x) + Eq(x, -2) + + This function find the non-infinite solution set so if the unknown symbol + is declared as extended real rather than real then the result may include + finiteness conditions: + + >>> y = Symbol('y', extended_real=True) + >>> reduce_rational_inequalities([[y + 2 > 0]], y) + (-2 < y) & (y < oo) + """ + exact = True + eqs = [] + solution = S.EmptySet # add pieces for each group + for _exprs in exprs: + if not _exprs: + continue + _eqs = [] + _sol = S.Reals + for expr in _exprs: + if isinstance(expr, tuple): + expr, rel = expr + else: + if expr.is_Relational: + expr, rel = expr.lhs - expr.rhs, expr.rel_op + else: + rel = '==' + + if expr is S.true: + numer, denom, rel = S.Zero, S.One, '==' + elif expr is S.false: + numer, denom, rel = S.One, S.One, '==' + else: + numer, denom = expr.together().as_numer_denom() + + try: + (numer, denom), opt = parallel_poly_from_expr( + (numer, denom), gen) + except PolynomialError: + raise PolynomialError(filldedent(''' + only polynomials and rational functions are + supported in this context. + ''')) + + if not opt.domain.is_Exact: + numer, denom, exact = numer.to_exact(), denom.to_exact(), False + + domain = opt.domain.get_exact() + + if not (domain.is_ZZ or domain.is_QQ): + expr = numer/denom + expr = Relational(expr, 0, rel) + _sol &= solve_univariate_inequality(expr, gen, relational=False) + else: + _eqs.append(((numer, denom), rel)) + + if _eqs: + _sol &= solve_rational_inequalities([_eqs]) + exclude = solve_rational_inequalities([[((d, d.one), '==') + for i in eqs for ((n, d), _) in i if d.has(gen)]]) + _sol -= exclude + + solution |= _sol + + if not exact and solution: + solution = solution.evalf() + + if relational: + solution = solution.as_relational(gen) + + return solution + + +def reduce_abs_inequality(expr, rel, gen): + """Reduce an inequality with nested absolute values. + + Examples + ======== + + >>> from sympy import reduce_abs_inequality, Abs, Symbol + >>> x = Symbol('x', real=True) + + >>> reduce_abs_inequality(Abs(x - 5) - 3, '<', x) + (2 < x) & (x < 8) + + >>> reduce_abs_inequality(Abs(x + 2)*3 - 13, '<', x) + (-19/3 < x) & (x < 7/3) + + See Also + ======== + + reduce_abs_inequalities + """ + if gen.is_extended_real is False: + raise TypeError(filldedent(''' + Cannot solve inequalities with absolute values containing + non-real variables. + ''')) + + def _bottom_up_scan(expr): + exprs = [] + + if expr.is_Add or expr.is_Mul: + op = expr.func + + for arg in expr.args: + _exprs = _bottom_up_scan(arg) + + if not exprs: + exprs = _exprs + else: + exprs = [(op(expr, _expr), conds + _conds) for (expr, conds), (_expr, _conds) in + itertools.product(exprs, _exprs)] + elif expr.is_Pow: + n = expr.exp + if not n.is_Integer: + raise ValueError("Only Integer Powers are allowed on Abs.") + + exprs.extend((expr**n, conds) for expr, conds in _bottom_up_scan(expr.base)) + elif isinstance(expr, Abs): + _exprs = _bottom_up_scan(expr.args[0]) + + for expr, conds in _exprs: + exprs.append(( expr, conds + [Ge(expr, 0)])) + exprs.append((-expr, conds + [Lt(expr, 0)])) + else: + exprs = [(expr, [])] + + return exprs + + mapping = {'<': '>', '<=': '>='} + inequalities = [] + + for expr, conds in _bottom_up_scan(expr): + if rel not in mapping.keys(): + expr = Relational( expr, 0, rel) + else: + expr = Relational(-expr, 0, mapping[rel]) + + inequalities.append([expr] + conds) + + return reduce_rational_inequalities(inequalities, gen) + + +def reduce_abs_inequalities(exprs, gen): + """Reduce a system of inequalities with nested absolute values. + + Examples + ======== + + >>> from sympy import reduce_abs_inequalities, Abs, Symbol + >>> x = Symbol('x', extended_real=True) + + >>> reduce_abs_inequalities([(Abs(3*x - 5) - 7, '<'), + ... (Abs(x + 25) - 13, '>')], x) + (-2/3 < x) & (x < 4) & (((-oo < x) & (x < -38)) | ((-12 < x) & (x < oo))) + + >>> reduce_abs_inequalities([(Abs(x - 4) + Abs(3*x - 5) - 7, '<')], x) + (1/2 < x) & (x < 4) + + See Also + ======== + + reduce_abs_inequality + """ + return And(*[ reduce_abs_inequality(expr, rel, gen) + for expr, rel in exprs ]) + + +def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals, continuous=False): + """Solves a real univariate inequality. + + Parameters + ========== + + expr : Relational + The target inequality + gen : Symbol + The variable for which the inequality is solved + relational : bool + A Relational type output is expected or not + domain : Set + The domain over which the equation is solved + continuous: bool + True if expr is known to be continuous over the given domain + (and so continuous_domain() does not need to be called on it) + + Raises + ====== + + NotImplementedError + The solution of the inequality cannot be determined due to limitation + in :func:`sympy.solvers.solveset.solvify`. + + Notes + ===== + + Currently, we cannot solve all the inequalities due to limitations in + :func:`sympy.solvers.solveset.solvify`. Also, the solution returned for trigonometric inequalities + are restricted in its periodic interval. + + See Also + ======== + + sympy.solvers.solveset.solvify: solver returning solveset solutions with solve's output API + + Examples + ======== + + >>> from sympy import solve_univariate_inequality, Symbol, sin, Interval, S + >>> x = Symbol('x') + + >>> solve_univariate_inequality(x**2 >= 4, x) + ((2 <= x) & (x < oo)) | ((-oo < x) & (x <= -2)) + + >>> solve_univariate_inequality(x**2 >= 4, x, relational=False) + Union(Interval(-oo, -2), Interval(2, oo)) + + >>> domain = Interval(0, S.Infinity) + >>> solve_univariate_inequality(x**2 >= 4, x, False, domain) + Interval(2, oo) + + >>> solve_univariate_inequality(sin(x) > 0, x, relational=False) + Interval.open(0, pi) + + """ + from sympy.solvers.solvers import denoms + + if domain.is_subset(S.Reals) is False: + raise NotImplementedError(filldedent(''' + Inequalities in the complex domain are + not supported. Try the real domain by + setting domain=S.Reals''')) + elif domain is not S.Reals: + rv = solve_univariate_inequality( + expr, gen, relational=False, continuous=continuous).intersection(domain) + if relational: + rv = rv.as_relational(gen) + return rv + else: + pass # continue with attempt to solve in Real domain + + # This keeps the function independent of the assumptions about `gen`. + # `solveset` makes sure this function is called only when the domain is + # real. + _gen = gen + _domain = domain + if gen.is_extended_real is False: + rv = S.EmptySet + return rv if not relational else rv.as_relational(_gen) + elif gen.is_extended_real is None: + gen = Dummy('gen', extended_real=True) + try: + expr = expr.xreplace({_gen: gen}) + except TypeError: + raise TypeError(filldedent(''' + When gen is real, the relational has a complex part + which leads to an invalid comparison like I < 0. + ''')) + + rv = None + + if expr is S.true: + rv = domain + + elif expr is S.false: + rv = S.EmptySet + + else: + e = expr.lhs - expr.rhs + period = periodicity(e, gen) + if period == S.Zero: + e = expand_mul(e) + const = expr.func(e, 0) + if const is S.true: + rv = domain + elif const is S.false: + rv = S.EmptySet + elif period is not None: + frange = function_range(e, gen, domain) + + rel = expr.rel_op + if rel in ('<', '<='): + if expr.func(frange.sup, 0): + rv = domain + elif not expr.func(frange.inf, 0): + rv = S.EmptySet + + elif rel in ('>', '>='): + if expr.func(frange.inf, 0): + rv = domain + elif not expr.func(frange.sup, 0): + rv = S.EmptySet + + inf, sup = domain.inf, domain.sup + if sup - inf is S.Infinity: + domain = Interval(0, period, False, True).intersect(_domain) + _domain = domain + + if rv is None: + n, d = e.as_numer_denom() + try: + if gen not in n.free_symbols and len(e.free_symbols) > 1: + raise ValueError + # this might raise ValueError on its own + # or it might give None... + solns = solvify(e, gen, domain) + if solns is None: + # in which case we raise ValueError + raise ValueError + except (ValueError, NotImplementedError): + # replace gen with generic x since it's + # univariate anyway + raise NotImplementedError(filldedent(''' + The inequality, %s, cannot be solved using + solve_univariate_inequality. + ''' % expr.subs(gen, Symbol('x')))) + + expanded_e = expand_mul(e) + def valid(x): + # this is used to see if gen=x satisfies the + # relational by substituting it into the + # expanded form and testing against 0, e.g. + # if expr = x*(x + 1) < 2 then e = x*(x + 1) - 2 + # and expanded_e = x**2 + x - 2; the test is + # whether a given value of x satisfies + # x**2 + x - 2 < 0 + # + # expanded_e, expr and gen used from enclosing scope + v = expanded_e.subs(gen, expand_mul(x)) + try: + r = expr.func(v, 0) + except TypeError: + r = S.false + if r in (S.true, S.false): + return r + if v.is_extended_real is False: + return S.false + else: + v = v.n(2) + if v.is_comparable: + return expr.func(v, 0) + # not comparable or couldn't be evaluated + raise NotImplementedError( + 'relationship did not evaluate: %s' % r) + + singularities = [] + for d in denoms(expr, gen): + singularities.extend(solvify(d, gen, domain)) + if not continuous: + domain = continuous_domain(expanded_e, gen, domain) + + include_x = '=' in expr.rel_op and expr.rel_op != '!=' + + try: + discontinuities = set(domain.boundary - + FiniteSet(domain.inf, domain.sup)) + # remove points that are not between inf and sup of domain + critical_points = FiniteSet(*(solns + singularities + list( + discontinuities))).intersection( + Interval(domain.inf, domain.sup, + domain.inf not in domain, domain.sup not in domain)) + if all(r.is_number for r in critical_points): + reals = _nsort(critical_points, separated=True)[0] + else: + sifted = sift(critical_points, lambda x: x.is_extended_real) + if sifted[None]: + # there were some roots that weren't known + # to be real + raise NotImplementedError + try: + reals = sifted[True] + if len(reals) > 1: + reals = sorted(reals) + except TypeError: + raise NotImplementedError + except NotImplementedError: + raise NotImplementedError('sorting of these roots is not supported') + + # If expr contains imaginary coefficients, only take real + # values of x for which the imaginary part is 0 + make_real = S.Reals + if (coeffI := expanded_e.coeff(S.ImaginaryUnit)) != S.Zero: + check = True + im_sol = FiniteSet() + try: + a = solveset(coeffI, gen, domain) + if not isinstance(a, Interval): + for z in a: + if z not in singularities and valid(z) and z.is_extended_real: + im_sol += FiniteSet(z) + else: + start, end = a.inf, a.sup + for z in _nsort(critical_points + FiniteSet(end)): + valid_start = valid(start) + if start != end: + valid_z = valid(z) + pt = _pt(start, z) + if pt not in singularities and pt.is_extended_real and valid(pt): + if valid_start and valid_z: + im_sol += Interval(start, z) + elif valid_start: + im_sol += Interval.Ropen(start, z) + elif valid_z: + im_sol += Interval.Lopen(start, z) + else: + im_sol += Interval.open(start, z) + start = z + for s in singularities: + im_sol -= FiniteSet(s) + except (TypeError): + im_sol = S.Reals + check = False + + if im_sol is S.EmptySet: + raise ValueError(filldedent(''' + %s contains imaginary parts which cannot be + made 0 for any value of %s satisfying the + inequality, leading to relations like I < 0. + ''' % (expr.subs(gen, _gen), _gen))) + + make_real = make_real.intersect(im_sol) + + sol_sets = [S.EmptySet] + + start = domain.inf + if start in domain and valid(start) and start.is_finite: + sol_sets.append(FiniteSet(start)) + + for x in reals: + end = x + + if valid(_pt(start, end)): + sol_sets.append(Interval(start, end, True, True)) + + if x in singularities: + singularities.remove(x) + else: + if x in discontinuities: + discontinuities.remove(x) + _valid = valid(x) + else: # it's a solution + _valid = include_x + if _valid: + sol_sets.append(FiniteSet(x)) + + start = end + + end = domain.sup + if end in domain and valid(end) and end.is_finite: + sol_sets.append(FiniteSet(end)) + + if valid(_pt(start, end)): + sol_sets.append(Interval.open(start, end)) + + if coeffI != S.Zero and check: + rv = (make_real).intersect(_domain) + else: + rv = Intersection( + (Union(*sol_sets)), make_real, _domain).subs(gen, _gen) + + return rv if not relational else rv.as_relational(_gen) + + +def _pt(start, end): + """Return a point between start and end""" + if not start.is_infinite and not end.is_infinite: + pt = (start + end)/2 + elif start.is_infinite and end.is_infinite: + pt = S.Zero + else: + if (start.is_infinite and start.is_extended_positive is None or + end.is_infinite and end.is_extended_positive is None): + raise ValueError('cannot proceed with unsigned infinite values') + if (end.is_infinite and end.is_extended_negative or + start.is_infinite and start.is_extended_positive): + start, end = end, start + # if possible, use a multiple of self which has + # better behavior when checking assumptions than + # an expression obtained by adding or subtracting 1 + if end.is_infinite: + if start.is_extended_positive: + pt = start*2 + elif start.is_extended_negative: + pt = start*S.Half + else: + pt = start + 1 + elif start.is_infinite: + if end.is_extended_positive: + pt = end*S.Half + elif end.is_extended_negative: + pt = end*2 + else: + pt = end - 1 + return pt + + +def _solve_inequality(ie, s, linear=False): + """Return the inequality with s isolated on the left, if possible. + If the relationship is non-linear, a solution involving And or Or + may be returned. False or True are returned if the relationship + is never True or always True, respectively. + + If `linear` is True (default is False) an `s`-dependent expression + will be isolated on the left, if possible + but it will not be solved for `s` unless the expression is linear + in `s`. Furthermore, only "safe" operations which do not change the + sense of the relationship are applied: no division by an unsigned + value is attempted unless the relationship involves Eq or Ne and + no division by a value not known to be nonzero is ever attempted. + + Examples + ======== + + >>> from sympy import Eq, Symbol + >>> from sympy.solvers.inequalities import _solve_inequality as f + >>> from sympy.abc import x, y + + For linear expressions, the symbol can be isolated: + + >>> f(x - 2 < 0, x) + x < 2 + >>> f(-x - 6 < x, x) + x > -3 + + Sometimes nonlinear relationships will be False + + >>> f(x**2 + 4 < 0, x) + False + + Or they may involve more than one region of values: + + >>> f(x**2 - 4 < 0, x) + (-2 < x) & (x < 2) + + To restrict the solution to a relational, set linear=True + and only the x-dependent portion will be isolated on the left: + + >>> f(x**2 - 4 < 0, x, linear=True) + x**2 < 4 + + Division of only nonzero quantities is allowed, so x cannot + be isolated by dividing by y: + + >>> y.is_nonzero is None # it is unknown whether it is 0 or not + True + >>> f(x*y < 1, x) + x*y < 1 + + And while an equality (or inequality) still holds after dividing by a + non-zero quantity + + >>> nz = Symbol('nz', nonzero=True) + >>> f(Eq(x*nz, 1), x) + Eq(x, 1/nz) + + the sign must be known for other inequalities involving > or <: + + >>> f(x*nz <= 1, x) + nz*x <= 1 + >>> p = Symbol('p', positive=True) + >>> f(x*p <= 1, x) + x <= 1/p + + When there are denominators in the original expression that + are removed by expansion, conditions for them will be returned + as part of the result: + + >>> f(x < x*(2/x - 1), x) + (x < 1) & Ne(x, 0) + """ + from sympy.solvers.solvers import denoms + if s not in ie.free_symbols: + return ie + if ie.rhs == s: + ie = ie.reversed + if ie.lhs == s and s not in ie.rhs.free_symbols: + return ie + + def classify(ie, s, i): + # return True or False if ie evaluates when substituting s with + # i else None (if unevaluated) or NaN (when there is an error + # in evaluating) + try: + v = ie.subs(s, i) + if v is S.NaN: + return v + elif v not in (True, False): + return + return v + except TypeError: + return S.NaN + + rv = None + oo = S.Infinity + expr = ie.lhs - ie.rhs + try: + p = Poly(expr, s) + if p.degree() == 0: + rv = ie.func(p.as_expr(), 0) + elif not linear and p.degree() > 1: + # handle in except clause + raise NotImplementedError + except (PolynomialError, NotImplementedError): + if not linear: + try: + rv = reduce_rational_inequalities([[ie]], s) + except PolynomialError: + rv = solve_univariate_inequality(ie, s) + # remove restrictions wrt +/-oo that may have been + # applied when using sets to simplify the relationship + okoo = classify(ie, s, oo) + if okoo is S.true and classify(rv, s, oo) is S.false: + rv = rv.subs(s < oo, True) + oknoo = classify(ie, s, -oo) + if (oknoo is S.true and + classify(rv, s, -oo) is S.false): + rv = rv.subs(-oo < s, True) + rv = rv.subs(s > -oo, True) + if rv is S.true: + rv = (s <= oo) if okoo is S.true else (s < oo) + if oknoo is not S.true: + rv = And(-oo < s, rv) + else: + p = Poly(expr) + + conds = [] + if rv is None: + e = p.as_expr() # this is in expanded form + # Do a safe inversion of e, moving non-s terms + # to the rhs and dividing by a nonzero factor if + # the relational is Eq/Ne; for other relationals + # the sign must also be positive or negative + rhs = 0 + b, ax = e.as_independent(s, as_Add=True) + e -= b + rhs -= b + ef = factor_terms(e) + a, e = ef.as_independent(s, as_Add=False) + if (a.is_zero != False or # don't divide by potential 0 + a.is_negative == + a.is_positive is None and # if sign is not known then + ie.rel_op not in ('!=', '==')): # reject if not Eq/Ne + e = ef + a = S.One + rhs /= a + if a.is_positive: + rv = ie.func(e, rhs) + else: + rv = ie.reversed.func(e, rhs) + + # return conditions under which the value is + # valid, too. + beginning_denoms = denoms(ie.lhs) | denoms(ie.rhs) + current_denoms = denoms(rv) + for d in beginning_denoms - current_denoms: + c = _solve_inequality(Eq(d, 0), s, linear=linear) + if isinstance(c, Eq) and c.lhs == s: + if classify(rv, s, c.rhs) is S.true: + # rv is permitting this value but it shouldn't + conds.append(~c) + for i in (-oo, oo): + if (classify(rv, s, i) is S.true and + classify(ie, s, i) is not S.true): + conds.append(s < i if i is oo else i < s) + + conds.append(rv) + return And(*conds) + + +def _reduce_inequalities(inequalities, symbols): + # helper for reduce_inequalities + + poly_part, abs_part = {}, {} + other = [] + + for inequality in inequalities: + + expr, rel = inequality.lhs, inequality.rel_op # rhs is 0 + + # check for gens using atoms which is more strict than free_symbols to + # guard against EX domain which won't be handled by + # reduce_rational_inequalities + gens = expr.atoms(Symbol) + + if len(gens) == 1: + gen = gens.pop() + else: + common = expr.free_symbols & symbols + if len(common) == 1: + gen = common.pop() + other.append(_solve_inequality(Relational(expr, 0, rel), gen)) + continue + else: + raise NotImplementedError(filldedent(''' + inequality has more than one symbol of interest. + ''')) + + if expr.is_polynomial(gen): + poly_part.setdefault(gen, []).append((expr, rel)) + else: + components = expr.find(lambda u: + u.has(gen) and ( + u.is_Function or u.is_Pow and not u.exp.is_Integer)) + if components and all(isinstance(i, Abs) for i in components): + abs_part.setdefault(gen, []).append((expr, rel)) + else: + other.append(_solve_inequality(Relational(expr, 0, rel), gen)) + + poly_reduced = [reduce_rational_inequalities([exprs], gen) for gen, exprs in poly_part.items()] + abs_reduced = [reduce_abs_inequalities(exprs, gen) for gen, exprs in abs_part.items()] + + return And(*(poly_reduced + abs_reduced + other)) + + +def reduce_inequalities(inequalities, symbols=[]): + """Reduce a system of inequalities with rational coefficients. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import reduce_inequalities + + >>> reduce_inequalities(0 <= x + 3, []) + (-3 <= x) & (x < oo) + + >>> reduce_inequalities(0 <= x + y*2 - 1, [x]) + (x < oo) & (x >= 1 - 2*y) + """ + if not iterable(inequalities): + inequalities = [inequalities] + inequalities = [sympify(i) for i in inequalities] + + gens = set().union(*[i.free_symbols for i in inequalities]) + + if not iterable(symbols): + symbols = [symbols] + symbols = (set(symbols) or gens) & gens + if any(i.is_extended_real is False for i in symbols): + raise TypeError(filldedent(''' + inequalities cannot contain symbols that are not real. + ''')) + + # make vanilla symbol real + recast = {i: Dummy(i.name, extended_real=True) + for i in gens if i.is_extended_real is None} + inequalities = [i.xreplace(recast) for i in inequalities] + symbols = {i.xreplace(recast) for i in symbols} + + # prefilter + keep = [] + for i in inequalities: + if isinstance(i, Relational): + i = i.func(i.lhs.as_expr() - i.rhs.as_expr(), 0) + elif i not in (True, False): + i = Eq(i, 0) + if i == True: + continue + elif i == False: + return S.false + if i.lhs.is_number: + raise NotImplementedError( + "could not determine truth value of %s" % i) + keep.append(i) + inequalities = keep + del keep + + # solve system + rv = _reduce_inequalities(inequalities, symbols) + + # restore original symbols and return + return rv.xreplace({v: k for k, v in recast.items()}) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/pde.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/pde.py new file mode 100644 index 0000000000000000000000000000000000000000..791ac67ae681ea952ea6e1dabacb7220d1843ebc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/pde.py @@ -0,0 +1,966 @@ +""" +This module contains pdsolve() and different helper functions that it +uses. It is heavily inspired by the ode module and hence the basic +infrastructure remains the same. + +**Functions in this module** + + These are the user functions in this module: + + - pdsolve() - Solves PDE's + - classify_pde() - Classifies PDEs into possible hints for dsolve(). + - pde_separate() - Separate variables in partial differential equation either by + additive or multiplicative separation approach. + + These are the helper functions in this module: + + - pde_separate_add() - Helper function for searching additive separable solutions. + - pde_separate_mul() - Helper function for searching multiplicative + separable solutions. + +**Currently implemented solver methods** + +The following methods are implemented for solving partial differential +equations. See the docstrings of the various pde_hint() functions for +more information on each (run help(pde)): + + - 1st order linear homogeneous partial differential equations + with constant coefficients. + - 1st order linear general partial differential equations + with constant coefficients. + - 1st order linear partial differential equations with + variable coefficients. + +""" +from functools import reduce + +from itertools import combinations_with_replacement +from sympy.simplify import simplify # type: ignore +from sympy.core import Add, S +from sympy.core.function import Function, expand, AppliedUndef, Subs +from sympy.core.relational import Equality, Eq +from sympy.core.symbol import Symbol, Wild, symbols +from sympy.functions import exp +from sympy.integrals.integrals import Integral, integrate +from sympy.utilities.iterables import has_dups, is_sequence +from sympy.utilities.misc import filldedent + +from sympy.solvers.deutils import _preprocess, ode_order, _desolve +from sympy.solvers.solvers import solve +from sympy.simplify.radsimp import collect + +import operator + + +allhints = ( + "1st_linear_constant_coeff_homogeneous", + "1st_linear_constant_coeff", + "1st_linear_constant_coeff_Integral", + "1st_linear_variable_coeff" + ) + + +def pdsolve(eq, func=None, hint='default', dict=False, solvefun=None, **kwargs): + """ + Solves any (supported) kind of partial differential equation. + + **Usage** + + pdsolve(eq, f(x,y), hint) -> Solve partial differential equation + eq for function f(x,y), using method hint. + + **Details** + + ``eq`` can be any supported partial differential equation (see + the pde docstring for supported methods). This can either + be an Equality, or an expression, which is assumed to be + equal to 0. + + ``f(x,y)`` is a function of two variables whose derivatives in that + variable make up the partial differential equation. In many + cases it is not necessary to provide this; it will be autodetected + (and an error raised if it could not be detected). + + ``hint`` is the solving method that you want pdsolve to use. Use + classify_pde(eq, f(x,y)) to get all of the possible hints for + a PDE. The default hint, 'default', will use whatever hint + is returned first by classify_pde(). See Hints below for + more options that you can use for hint. + + ``solvefun`` is the convention used for arbitrary functions returned + by the PDE solver. If not set by the user, it is set by default + to be F. + + **Hints** + + Aside from the various solving methods, there are also some + meta-hints that you can pass to pdsolve(): + + "default": + This uses whatever hint is returned first by + classify_pde(). This is the default argument to + pdsolve(). + + "all": + To make pdsolve apply all relevant classification hints, + use pdsolve(PDE, func, hint="all"). This will return a + dictionary of hint:solution terms. If a hint causes + pdsolve to raise the NotImplementedError, value of that + hint's key will be the exception object raised. The + dictionary will also include some special keys: + + - order: The order of the PDE. See also ode_order() in + deutils.py + - default: The solution that would be returned by + default. This is the one produced by the hint that + appears first in the tuple returned by classify_pde(). + + "all_Integral": + This is the same as "all", except if a hint also has a + corresponding "_Integral" hint, it only returns the + "_Integral" hint. This is useful if "all" causes + pdsolve() to hang because of a difficult or impossible + integral. This meta-hint will also be much faster than + "all", because integrate() is an expensive routine. + + See also the classify_pde() docstring for more info on hints, + and the pde docstring for a list of all supported hints. + + **Tips** + - You can declare the derivative of an unknown function this way: + + >>> from sympy import Function, Derivative + >>> from sympy.abc import x, y # x and y are the independent variables + >>> f = Function("f")(x, y) # f is a function of x and y + >>> # fx will be the partial derivative of f with respect to x + >>> fx = Derivative(f, x) + >>> # fy will be the partial derivative of f with respect to y + >>> fy = Derivative(f, y) + + - See test_pde.py for many tests, which serves also as a set of + examples for how to use pdsolve(). + - pdsolve always returns an Equality class (except for the case + when the hint is "all" or "all_Integral"). Note that it is not possible + to get an explicit solution for f(x, y) as in the case of ODE's + - Do help(pde.pde_hintname) to get help more information on a + specific hint + + + Examples + ======== + + >>> from sympy.solvers.pde import pdsolve + >>> from sympy import Function, Eq + >>> from sympy.abc import x, y + >>> f = Function('f') + >>> u = f(x, y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> eq = Eq(1 + (2*(ux/u)) + (3*(uy/u)), 0) + >>> pdsolve(eq) + Eq(f(x, y), F(3*x - 2*y)*exp(-2*x/13 - 3*y/13)) + + """ + + if not solvefun: + solvefun = Function('F') + + # See the docstring of _desolve for more details. + hints = _desolve(eq, func=func, hint=hint, simplify=True, + type='pde', **kwargs) + eq = hints.pop('eq', False) + all_ = hints.pop('all', False) + + if all_: + # TODO : 'best' hint should be implemented when adequate + # number of hints are added. + pdedict = {} + failed_hints = {} + gethints = classify_pde(eq, dict=True) + pdedict.update({'order': gethints['order'], + 'default': gethints['default']}) + for hint in hints: + try: + rv = _helper_simplify(eq, hint, hints[hint]['func'], + hints[hint]['order'], hints[hint][hint], solvefun) + except NotImplementedError as detail: + failed_hints[hint] = detail + else: + pdedict[hint] = rv + pdedict.update(failed_hints) + return pdedict + + else: + return _helper_simplify(eq, hints['hint'], hints['func'], + hints['order'], hints[hints['hint']], solvefun) + + +def _helper_simplify(eq, hint, func, order, match, solvefun): + """Helper function of pdsolve that calls the respective + pde functions to solve for the partial differential + equations. This minimizes the computation in + calling _desolve multiple times. + """ + solvefunc = globals()["pde_" + hint.removesuffix("_Integral")] + return _handle_Integral(solvefunc(eq, func, order, + match, solvefun), func, order, hint) + + +def _handle_Integral(expr, func, order, hint): + r""" + Converts a solution with integrals in it into an actual solution. + + Simplifies the integral mainly using doit() + """ + if hint.endswith("_Integral"): + return expr + + elif hint == "1st_linear_constant_coeff": + return simplify(expr.doit()) + + else: + return expr + + +def classify_pde(eq, func=None, dict=False, *, prep=True, **kwargs): + """ + Returns a tuple of possible pdsolve() classifications for a PDE. + + The tuple is ordered so that first item is the classification that + pdsolve() uses to solve the PDE by default. In general, + classifications near the beginning of the list will produce + better solutions faster than those near the end, though there are + always exceptions. To make pdsolve use a different classification, + use pdsolve(PDE, func, hint=). See also the pdsolve() + docstring for different meta-hints you can use. + + If ``dict`` is true, classify_pde() will return a dictionary of + hint:match expression terms. This is intended for internal use by + pdsolve(). Note that because dictionaries are ordered arbitrarily, + this will most likely not be in the same order as the tuple. + + You can get help on different hints by doing help(pde.pde_hintname), + where hintname is the name of the hint without "_Integral". + + See sympy.pde.allhints or the sympy.pde docstring for a list of all + supported hints that can be returned from classify_pde. + + + Examples + ======== + + >>> from sympy.solvers.pde import classify_pde + >>> from sympy import Function, Eq + >>> from sympy.abc import x, y + >>> f = Function('f') + >>> u = f(x, y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> eq = Eq(1 + (2*(ux/u)) + (3*(uy/u)), 0) + >>> classify_pde(eq) + ('1st_linear_constant_coeff_homogeneous',) + """ + + if func and len(func.args) != 2: + raise NotImplementedError("Right now only partial " + "differential equations of two variables are supported") + + if prep or func is None: + prep, func_ = _preprocess(eq, func) + if func is None: + func = func_ + + if isinstance(eq, Equality): + if eq.rhs != 0: + return classify_pde(eq.lhs - eq.rhs, func) + eq = eq.lhs + + f = func.func + x = func.args[0] + y = func.args[1] + fx = f(x,y).diff(x) + fy = f(x,y).diff(y) + + # TODO : For now pde.py uses support offered by the ode_order function + # to find the order with respect to a multi-variable function. An + # improvement could be to classify the order of the PDE on the basis of + # individual variables. + order = ode_order(eq, f(x,y)) + + # hint:matchdict or hint:(tuple of matchdicts) + # Also will contain "default": and "order":order items. + matching_hints = {'order': order} + + if not order: + if dict: + matching_hints["default"] = None + return matching_hints + return () + + eq = expand(eq) + + a = Wild('a', exclude = [f(x,y)]) + b = Wild('b', exclude = [f(x,y), fx, fy, x, y]) + c = Wild('c', exclude = [f(x,y), fx, fy, x, y]) + d = Wild('d', exclude = [f(x,y), fx, fy, x, y]) + e = Wild('e', exclude = [f(x,y), fx, fy]) + n = Wild('n', exclude = [x, y]) + # Try removing the smallest power of f(x,y) + # from the highest partial derivatives of f(x,y) + reduced_eq = eq + if eq.is_Add: + power = None + for i in set(combinations_with_replacement((x,y), order)): + coeff = eq.coeff(f(x,y).diff(*i)) + if coeff == 1: + continue + match = coeff.match(a*f(x,y)**n) + if match and match[a]: + if power is None or match[n] < power: + power = match[n] + if power: + den = f(x,y)**power + reduced_eq = Add(*[arg/den for arg in eq.args]) + + if order == 1: + reduced_eq = collect(reduced_eq, f(x, y)) + r = reduced_eq.match(b*fx + c*fy + d*f(x,y) + e) + if r: + if not r[e]: + ## Linear first-order homogeneous partial-differential + ## equation with constant coefficients + r.update({'b': b, 'c': c, 'd': d}) + matching_hints["1st_linear_constant_coeff_homogeneous"] = r + elif r[b]**2 + r[c]**2 != 0: + ## Linear first-order general partial-differential + ## equation with constant coefficients + r.update({'b': b, 'c': c, 'd': d, 'e': e}) + matching_hints["1st_linear_constant_coeff"] = r + matching_hints["1st_linear_constant_coeff_Integral"] = r + + else: + b = Wild('b', exclude=[f(x, y), fx, fy]) + c = Wild('c', exclude=[f(x, y), fx, fy]) + d = Wild('d', exclude=[f(x, y), fx, fy]) + r = reduced_eq.match(b*fx + c*fy + d*f(x,y) + e) + if r: + r.update({'b': b, 'c': c, 'd': d, 'e': e}) + matching_hints["1st_linear_variable_coeff"] = r + + # Order keys based on allhints. + rettuple = tuple(i for i in allhints if i in matching_hints) + + if dict: + # Dictionaries are ordered arbitrarily, so make note of which + # hint would come first for pdsolve(). Use an ordered dict in Py 3. + matching_hints["default"] = None + matching_hints["ordered_hints"] = rettuple + for i in allhints: + if i in matching_hints: + matching_hints["default"] = i + break + return matching_hints + return rettuple + + +def checkpdesol(pde, sol, func=None, solve_for_func=True): + """ + Checks if the given solution satisfies the partial differential + equation. + + pde is the partial differential equation which can be given in the + form of an equation or an expression. sol is the solution for which + the pde is to be checked. This can also be given in an equation or + an expression form. If the function is not provided, the helper + function _preprocess from deutils is used to identify the function. + + If a sequence of solutions is passed, the same sort of container will be + used to return the result for each solution. + + The following methods are currently being implemented to check if the + solution satisfies the PDE: + + 1. Directly substitute the solution in the PDE and check. If the + solution has not been solved for f, then it will solve for f + provided solve_for_func has not been set to False. + + If the solution satisfies the PDE, then a tuple (True, 0) is returned. + Otherwise a tuple (False, expr) where expr is the value obtained + after substituting the solution in the PDE. However if a known solution + returns False, it may be due to the inability of doit() to simplify it to zero. + + Examples + ======== + + >>> from sympy import Function, symbols + >>> from sympy.solvers.pde import checkpdesol, pdsolve + >>> x, y = symbols('x y') + >>> f = Function('f') + >>> eq = 2*f(x,y) + 3*f(x,y).diff(x) + 4*f(x,y).diff(y) + >>> sol = pdsolve(eq) + >>> assert checkpdesol(eq, sol)[0] + >>> eq = x*f(x,y) + f(x,y).diff(x) + >>> checkpdesol(eq, sol) + (False, (x*F(4*x - 3*y) - 6*F(4*x - 3*y)/25 + 4*Subs(Derivative(F(_xi_1), _xi_1), _xi_1, 4*x - 3*y))*exp(-6*x/25 - 8*y/25)) + """ + + # Converting the pde into an equation + if not isinstance(pde, Equality): + pde = Eq(pde, 0) + + # If no function is given, try finding the function present. + if func is None: + try: + _, func = _preprocess(pde.lhs) + except ValueError: + funcs = [s.atoms(AppliedUndef) for s in ( + sol if is_sequence(sol, set) else [sol])] + funcs = set().union(funcs) + if len(funcs) != 1: + raise ValueError( + 'must pass func arg to checkpdesol for this case.') + func = funcs.pop() + + # If the given solution is in the form of a list or a set + # then return a list or set of tuples. + if is_sequence(sol, set): + return type(sol)([checkpdesol( + pde, i, func=func, + solve_for_func=solve_for_func) for i in sol]) + + # Convert solution into an equation + if not isinstance(sol, Equality): + sol = Eq(func, sol) + elif sol.rhs == func: + sol = sol.reversed + + # Try solving for the function + solved = sol.lhs == func and not sol.rhs.has(func) + if solve_for_func and not solved: + solved = solve(sol, func) + if solved: + if len(solved) == 1: + return checkpdesol(pde, Eq(func, solved[0]), + func=func, solve_for_func=False) + else: + return checkpdesol(pde, [Eq(func, t) for t in solved], + func=func, solve_for_func=False) + + # try direct substitution of the solution into the PDE and simplify + if sol.lhs == func: + pde = pde.lhs - pde.rhs + s = simplify(pde.subs(func, sol.rhs).doit()) + return s is S.Zero, s + + raise NotImplementedError(filldedent(''' + Unable to test if %s is a solution to %s.''' % (sol, pde))) + + + +def pde_1st_linear_constant_coeff_homogeneous(eq, func, order, match, solvefun): + r""" + Solves a first order linear homogeneous + partial differential equation with constant coefficients. + + The general form of this partial differential equation is + + .. math:: a \frac{\partial f(x,y)}{\partial x} + + b \frac{\partial f(x,y)}{\partial y} + c f(x,y) = 0 + + where `a`, `b` and `c` are constants. + + The general solution is of the form: + + .. math:: + f(x, y) = F(- a y + b x ) e^{- \frac{c (a x + b y)}{a^2 + b^2}} + + and can be found in SymPy with ``pdsolve``:: + + >>> from sympy.solvers import pdsolve + >>> from sympy.abc import x, y, a, b, c + >>> from sympy import Function, pprint + >>> f = Function('f') + >>> u = f(x,y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> genform = a*ux + b*uy + c*u + >>> pprint(genform) + d d + a*--(f(x, y)) + b*--(f(x, y)) + c*f(x, y) + dx dy + + >>> pprint(pdsolve(genform)) + -c*(a*x + b*y) + --------------- + 2 2 + a + b + f(x, y) = F(-a*y + b*x)*e + + Examples + ======== + + >>> from sympy import pdsolve + >>> from sympy import Function, pprint + >>> from sympy.abc import x,y + >>> f = Function('f') + >>> pdsolve(f(x,y) + f(x,y).diff(x) + f(x,y).diff(y)) + Eq(f(x, y), F(x - y)*exp(-x/2 - y/2)) + >>> pprint(pdsolve(f(x,y) + f(x,y).diff(x) + f(x,y).diff(y))) + x y + - - - - + 2 2 + f(x, y) = F(x - y)*e + + References + ========== + + - Viktor Grigoryan, "Partial Differential Equations" + Math 124A - Fall 2010, pp.7 + + """ + # TODO : For now homogeneous first order linear PDE's having + # two variables are implemented. Once there is support for + # solving systems of ODE's, this can be extended to n variables. + + f = func.func + x = func.args[0] + y = func.args[1] + b = match[match['b']] + c = match[match['c']] + d = match[match['d']] + return Eq(f(x,y), exp(-S(d)/(b**2 + c**2)*(b*x + c*y))*solvefun(c*x - b*y)) + + +def pde_1st_linear_constant_coeff(eq, func, order, match, solvefun): + r""" + Solves a first order linear partial differential equation + with constant coefficients. + + The general form of this partial differential equation is + + .. math:: a \frac{\partial f(x,y)}{\partial x} + + b \frac{\partial f(x,y)}{\partial y} + + c f(x,y) = G(x,y) + + where `a`, `b` and `c` are constants and `G(x, y)` can be an arbitrary + function in `x` and `y`. + + The general solution of the PDE is: + + .. math:: + f(x, y) = \left. \left[F(\eta) + \frac{1}{a^2 + b^2} + \int\limits^{a x + b y} G\left(\frac{a \xi + b \eta}{a^2 + b^2}, + \frac{- a \eta + b \xi}{a^2 + b^2} \right) + e^{\frac{c \xi}{a^2 + b^2}}\, d\xi\right] + e^{- \frac{c \xi}{a^2 + b^2}} + \right|_{\substack{\eta=- a y + b x\\ \xi=a x + b y }}\, , + + where `F(\eta)` is an arbitrary single-valued function. The solution + can be found in SymPy with ``pdsolve``:: + + >>> from sympy.solvers import pdsolve + >>> from sympy.abc import x, y, a, b, c + >>> from sympy import Function, pprint + >>> f = Function('f') + >>> G = Function('G') + >>> u = f(x, y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> genform = a*ux + b*uy + c*u - G(x,y) + >>> pprint(genform) + d d + a*--(f(x, y)) + b*--(f(x, y)) + c*f(x, y) - G(x, y) + dx dy + >>> pprint(pdsolve(genform, hint='1st_linear_constant_coeff_Integral')) + // a*x + b*y \ \| + || / | || + || | | || + || | c*xi | || + || | ------- | || + || | 2 2 | || + || | /a*xi + b*eta -a*eta + b*xi\ a + b | || + || | G|------------, -------------|*e d(xi)| || + || | | 2 2 2 2 | | || + || | \ a + b a + b / | -c*xi || + || | | -------|| + || / | 2 2|| + || | a + b || + f(x, y) = ||F(eta) + -------------------------------------------------------|*e || + || 2 2 | || + \\ a + b / /|eta=-a*y + b*x, xi=a*x + b*y + + Examples + ======== + + >>> from sympy.solvers.pde import pdsolve + >>> from sympy import Function, pprint, exp + >>> from sympy.abc import x,y + >>> f = Function('f') + >>> eq = -2*f(x,y).diff(x) + 4*f(x,y).diff(y) + 5*f(x,y) - exp(x + 3*y) + >>> pdsolve(eq) + Eq(f(x, y), (F(4*x + 2*y)*exp(x/2) + exp(x + 4*y)/15)*exp(-y)) + + References + ========== + + - Viktor Grigoryan, "Partial Differential Equations" + Math 124A - Fall 2010, pp.7 + + """ + + # TODO : For now homogeneous first order linear PDE's having + # two variables are implemented. Once there is support for + # solving systems of ODE's, this can be extended to n variables. + xi, eta = symbols("xi eta") + f = func.func + x = func.args[0] + y = func.args[1] + b = match[match['b']] + c = match[match['c']] + d = match[match['d']] + e = -match[match['e']] + expterm = exp(-S(d)/(b**2 + c**2)*xi) + functerm = solvefun(eta) + solvedict = solve((b*x + c*y - xi, c*x - b*y - eta), x, y) + # Integral should remain as it is in terms of xi, + # doit() should be done in _handle_Integral. + genterm = (1/S(b**2 + c**2))*Integral( + (1/expterm*e).subs(solvedict), (xi, b*x + c*y)) + return Eq(f(x,y), Subs(expterm*(functerm + genterm), + (eta, xi), (c*x - b*y, b*x + c*y))) + + +def pde_1st_linear_variable_coeff(eq, func, order, match, solvefun): + r""" + Solves a first order linear partial differential equation + with variable coefficients. The general form of this partial + differential equation is + + .. math:: a(x, y) \frac{\partial f(x, y)}{\partial x} + + b(x, y) \frac{\partial f(x, y)}{\partial y} + + c(x, y) f(x, y) = G(x, y) + + where `a(x, y)`, `b(x, y)`, `c(x, y)` and `G(x, y)` are arbitrary + functions in `x` and `y`. This PDE is converted into an ODE by + making the following transformation: + + 1. `\xi` as `x` + + 2. `\eta` as the constant in the solution to the differential + equation `\frac{dy}{dx} = -\frac{b}{a}` + + Making the previous substitutions reduces it to the linear ODE + + .. math:: a(\xi, \eta)\frac{du}{d\xi} + c(\xi, \eta)u - G(\xi, \eta) = 0 + + which can be solved using ``dsolve``. + + >>> from sympy.abc import x, y + >>> from sympy import Function, pprint + >>> a, b, c, G, f= [Function(i) for i in ['a', 'b', 'c', 'G', 'f']] + >>> u = f(x,y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> genform = a(x, y)*u + b(x, y)*ux + c(x, y)*uy - G(x,y) + >>> pprint(genform) + d d + -G(x, y) + a(x, y)*f(x, y) + b(x, y)*--(f(x, y)) + c(x, y)*--(f(x, y)) + dx dy + + + Examples + ======== + + >>> from sympy.solvers.pde import pdsolve + >>> from sympy import Function, pprint + >>> from sympy.abc import x,y + >>> f = Function('f') + >>> eq = x*(u.diff(x)) - y*(u.diff(y)) + y**2*u - y**2 + >>> pdsolve(eq) + Eq(f(x, y), F(x*y)*exp(y**2/2) + 1) + + References + ========== + + - Viktor Grigoryan, "Partial Differential Equations" + Math 124A - Fall 2010, pp.7 + + """ + from sympy.solvers.ode import dsolve + + eta = symbols("eta") + f = func.func + x = func.args[0] + y = func.args[1] + b = match[match['b']] + c = match[match['c']] + d = match[match['d']] + e = -match[match['e']] + + + if not d: + # To deal with cases like b*ux = e or c*uy = e + if not (b and c): + if c: + try: + tsol = integrate(e/c, y) + except NotImplementedError: + raise NotImplementedError("Unable to find a solution" + " due to inability of integrate") + else: + return Eq(f(x,y), solvefun(x) + tsol) + if b: + try: + tsol = integrate(e/b, x) + except NotImplementedError: + raise NotImplementedError("Unable to find a solution" + " due to inability of integrate") + else: + return Eq(f(x,y), solvefun(y) + tsol) + + if not c: + # To deal with cases when c is 0, a simpler method is used. + # The PDE reduces to b*(u.diff(x)) + d*u = e, which is a linear ODE in x + plode = f(x).diff(x)*b + d*f(x) - e + sol = dsolve(plode, f(x)) + syms = sol.free_symbols - plode.free_symbols - {x, y} + rhs = _simplify_variable_coeff(sol.rhs, syms, solvefun, y) + return Eq(f(x, y), rhs) + + if not b: + # To deal with cases when b is 0, a simpler method is used. + # The PDE reduces to c*(u.diff(y)) + d*u = e, which is a linear ODE in y + plode = f(y).diff(y)*c + d*f(y) - e + sol = dsolve(plode, f(y)) + syms = sol.free_symbols - plode.free_symbols - {x, y} + rhs = _simplify_variable_coeff(sol.rhs, syms, solvefun, x) + return Eq(f(x, y), rhs) + + dummy = Function('d') + h = (c/b).subs(y, dummy(x)) + sol = dsolve(dummy(x).diff(x) - h, dummy(x)) + if isinstance(sol, list): + sol = sol[0] + solsym = sol.free_symbols - h.free_symbols - {x, y} + if len(solsym) == 1: + solsym = solsym.pop() + etat = (solve(sol, solsym)[0]).subs(dummy(x), y) + ysub = solve(eta - etat, y)[0] + deq = (b*(f(x).diff(x)) + d*f(x) - e).subs(y, ysub) + final = (dsolve(deq, f(x), hint='1st_linear')).rhs + if isinstance(final, list): + final = final[0] + finsyms = final.free_symbols - deq.free_symbols - {x, y} + rhs = _simplify_variable_coeff(final, finsyms, solvefun, etat) + return Eq(f(x, y), rhs) + + else: + raise NotImplementedError("Cannot solve the partial differential equation due" + " to inability of constantsimp") + + +def _simplify_variable_coeff(sol, syms, func, funcarg): + r""" + Helper function to replace constants by functions in 1st_linear_variable_coeff + """ + eta = Symbol("eta") + if len(syms) == 1: + sym = syms.pop() + final = sol.subs(sym, func(funcarg)) + + else: + for sym in syms: + final = sol.subs(sym, func(funcarg)) + + return simplify(final.subs(eta, funcarg)) + + +def pde_separate(eq, fun, sep, strategy='mul'): + """Separate variables in partial differential equation either by additive + or multiplicative separation approach. It tries to rewrite an equation so + that one of the specified variables occurs on a different side of the + equation than the others. + + :param eq: Partial differential equation + + :param fun: Original function F(x, y, z) + + :param sep: List of separated functions [X(x), u(y, z)] + + :param strategy: Separation strategy. You can choose between additive + separation ('add') and multiplicative separation ('mul') which is + default. + + Examples + ======== + + >>> from sympy import E, Eq, Function, pde_separate, Derivative as D + >>> from sympy.abc import x, t + >>> u, X, T = map(Function, 'uXT') + + >>> eq = Eq(D(u(x, t), x), E**(u(x, t))*D(u(x, t), t)) + >>> pde_separate(eq, u(x, t), [X(x), T(t)], strategy='add') + [exp(-X(x))*Derivative(X(x), x), exp(T(t))*Derivative(T(t), t)] + + >>> eq = Eq(D(u(x, t), x, 2), D(u(x, t), t, 2)) + >>> pde_separate(eq, u(x, t), [X(x), T(t)], strategy='mul') + [Derivative(X(x), (x, 2))/X(x), Derivative(T(t), (t, 2))/T(t)] + + See Also + ======== + pde_separate_add, pde_separate_mul + """ + + do_add = False + if strategy == 'add': + do_add = True + elif strategy == 'mul': + do_add = False + else: + raise ValueError('Unknown strategy: %s' % strategy) + + if isinstance(eq, Equality): + if eq.rhs != 0: + return pde_separate(Eq(eq.lhs - eq.rhs, 0), fun, sep, strategy) + else: + return pde_separate(Eq(eq, 0), fun, sep, strategy) + + if eq.rhs != 0: + raise ValueError("Value should be 0") + + # Handle arguments + orig_args = list(fun.args) + subs_args = [arg for s in sep for arg in s.args] + + if do_add: + functions = reduce(operator.add, sep) + else: + functions = reduce(operator.mul, sep) + + # Check whether variables match + if len(subs_args) != len(orig_args): + raise ValueError("Variable counts do not match") + # Check for duplicate arguments like [X(x), u(x, y)] + if has_dups(subs_args): + raise ValueError("Duplicate substitution arguments detected") + # Check whether the variables match + if set(orig_args) != set(subs_args): + raise ValueError("Arguments do not match") + + # Substitute original function with separated... + result = eq.lhs.subs(fun, functions).doit() + + # Divide by terms when doing multiplicative separation + if not do_add: + eq = 0 + for i in result.args: + eq += i/functions + result = eq + + svar = subs_args[0] + dvar = subs_args[1:] + return _separate(result, svar, dvar) + + +def pde_separate_add(eq, fun, sep): + """ + Helper function for searching additive separable solutions. + + Consider an equation of two independent variables x, y and a dependent + variable w, we look for the product of two functions depending on different + arguments: + + `w(x, y, z) = X(x) + y(y, z)` + + Examples + ======== + + >>> from sympy import E, Eq, Function, pde_separate_add, Derivative as D + >>> from sympy.abc import x, t + >>> u, X, T = map(Function, 'uXT') + + >>> eq = Eq(D(u(x, t), x), E**(u(x, t))*D(u(x, t), t)) + >>> pde_separate_add(eq, u(x, t), [X(x), T(t)]) + [exp(-X(x))*Derivative(X(x), x), exp(T(t))*Derivative(T(t), t)] + + """ + return pde_separate(eq, fun, sep, strategy='add') + + +def pde_separate_mul(eq, fun, sep): + """ + Helper function for searching multiplicative separable solutions. + + Consider an equation of two independent variables x, y and a dependent + variable w, we look for the product of two functions depending on different + arguments: + + `w(x, y, z) = X(x)*u(y, z)` + + Examples + ======== + + >>> from sympy import Function, Eq, pde_separate_mul, Derivative as D + >>> from sympy.abc import x, y + >>> u, X, Y = map(Function, 'uXY') + + >>> eq = Eq(D(u(x, y), x, 2), D(u(x, y), y, 2)) + >>> pde_separate_mul(eq, u(x, y), [X(x), Y(y)]) + [Derivative(X(x), (x, 2))/X(x), Derivative(Y(y), (y, 2))/Y(y)] + + """ + return pde_separate(eq, fun, sep, strategy='mul') + + +def _separate(eq, dep, others): + """Separate expression into two parts based on dependencies of variables.""" + + # FIRST PASS + # Extract derivatives depending our separable variable... + terms = set() + for term in eq.args: + if term.is_Mul: + for i in term.args: + if i.is_Derivative and not i.has(*others): + terms.add(term) + continue + elif term.is_Derivative and not term.has(*others): + terms.add(term) + # Find the factor that we need to divide by + div = set() + for term in terms: + ext, sep = term.expand().as_independent(dep) + # Failed? + if sep.has(*others): + return None + div.add(ext) + # FIXME: Find lcm() of all the divisors and divide with it, instead of + # current hack :( + # https://github.com/sympy/sympy/issues/4597 + if len(div) > 0: + # double sum required or some tests will fail + eq = Add(*[simplify(Add(*[term/i for i in div])) for term in eq.args]) + # SECOND PASS - separate the derivatives + div = set() + lhs = rhs = 0 + for term in eq.args: + # Check, whether we have already term with independent variable... + if not term.has(*others): + lhs += term + continue + # ...otherwise, try to separate + temp, sep = term.expand().as_independent(dep) + # Failed? + if sep.has(*others): + return None + # Extract the divisors + div.add(sep) + rhs -= term.expand() + # Do the division + fulldiv = reduce(operator.add, div) + lhs = simplify(lhs/fulldiv).expand() + rhs = simplify(rhs/fulldiv).expand() + # ...and check whether we were successful :) + if lhs.has(*others) or rhs.has(dep): + return None + return [lhs, rhs] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/polysys.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/polysys.py new file mode 100644 index 0000000000000000000000000000000000000000..2edc70b36c25b986c975c33fcc57535ef0b31df2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/polysys.py @@ -0,0 +1,872 @@ +"""Solvers of systems of polynomial equations. """ + +from __future__ import annotations + +from typing import Any +from collections.abc import Sequence, Iterable + +import itertools + +from sympy import Dummy +from sympy.core import S +from sympy.core.expr import Expr +from sympy.core.exprtools import factor_terms +from sympy.core.sorting import default_sort_key +from sympy.logic.boolalg import Boolean +from sympy.polys import Poly, groebner, roots +from sympy.polys.domains import ZZ +from sympy.polys.polyoptions import build_options +from sympy.polys.polytools import parallel_poly_from_expr, sqf_part +from sympy.polys.polyerrors import ( + ComputationFailed, + PolificationFailed, + CoercionFailed, + GeneratorsNeeded, + DomainError +) +from sympy.simplify import rcollect +from sympy.utilities import postfixes +from sympy.utilities.iterables import cartes +from sympy.utilities.misc import filldedent +from sympy.logic.boolalg import Or, And +from sympy.core.relational import Eq + + +class SolveFailed(Exception): + """Raised when solver's conditions were not met. """ + + +def solve_poly_system(seq, *gens, strict=False, **args): + """ + Return a list of solutions for the system of polynomial equations + or else None. + + Parameters + ========== + + seq: a list/tuple/set + Listing all the equations that are needed to be solved + gens: generators + generators of the equations in seq for which we want the + solutions + strict: a boolean (default is False) + if strict is True, NotImplementedError will be raised if + the solution is known to be incomplete (which can occur if + not all solutions are expressible in radicals) + args: Keyword arguments + Special options for solving the equations. + + + Returns + ======= + + List[Tuple] + a list of tuples with elements being solutions for the + symbols in the order they were passed as gens + None + None is returned when the computed basis contains only the ground. + + Examples + ======== + + >>> from sympy import solve_poly_system + >>> from sympy.abc import x, y + + >>> solve_poly_system([x*y - 2*y, 2*y**2 - x**2], x, y) + [(0, 0), (2, -sqrt(2)), (2, sqrt(2))] + + >>> solve_poly_system([x**5 - x + y**3, y**2 - 1], x, y, strict=True) + Traceback (most recent call last): + ... + UnsolvableFactorError + + """ + try: + polys, opt = parallel_poly_from_expr(seq, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('solve_poly_system', len(seq), exc) + + if len(polys) == len(opt.gens) == 2: + f, g = polys + + if all(i <= 2 for i in f.degree_list() + g.degree_list()): + try: + return solve_biquadratic(f, g, opt) + except SolveFailed: + pass + + return solve_generic(polys, opt, strict=strict) + + +def solve_biquadratic(f, g, opt): + """Solve a system of two bivariate quadratic polynomial equations. + + Parameters + ========== + + f: a single Expr or Poly + First equation + g: a single Expr or Poly + Second Equation + opt: an Options object + For specifying keyword arguments and generators + + Returns + ======= + + List[Tuple] + a list of tuples with elements being solutions for the + symbols in the order they were passed as gens + None + None is returned when the computed basis contains only the ground. + + Examples + ======== + + >>> from sympy import Options, Poly + >>> from sympy.abc import x, y + >>> from sympy.solvers.polysys import solve_biquadratic + >>> NewOption = Options((x, y), {'domain': 'ZZ'}) + + >>> a = Poly(y**2 - 4 + x, y, x, domain='ZZ') + >>> b = Poly(y*2 + 3*x - 7, y, x, domain='ZZ') + >>> solve_biquadratic(a, b, NewOption) + [(1/3, 3), (41/27, 11/9)] + + >>> a = Poly(y + x**2 - 3, y, x, domain='ZZ') + >>> b = Poly(-y + x - 4, y, x, domain='ZZ') + >>> solve_biquadratic(a, b, NewOption) + [(7/2 - sqrt(29)/2, -sqrt(29)/2 - 1/2), (sqrt(29)/2 + 7/2, -1/2 + \ + sqrt(29)/2)] + """ + G = groebner([f, g]) + + if len(G) == 1 and G[0].is_ground: + return None + + if len(G) != 2: + raise SolveFailed + + x, y = opt.gens + p, q = G + if not p.gcd(q).is_ground: + # not 0-dimensional + raise SolveFailed + + p = Poly(p, x, expand=False) + p_roots = [rcollect(expr, y) for expr in roots(p).keys()] + + q = q.ltrim(-1) + q_roots = list(roots(q).keys()) + + solutions = [(p_root.subs(y, q_root), q_root) for q_root, p_root in + itertools.product(q_roots, p_roots)] + + return sorted(solutions, key=default_sort_key) + + +def solve_generic(polys, opt, strict=False): + """ + Solve a generic system of polynomial equations. + + Returns all possible solutions over C[x_1, x_2, ..., x_m] of a + set F = { f_1, f_2, ..., f_n } of polynomial equations, using + Groebner basis approach. For now only zero-dimensional systems + are supported, which means F can have at most a finite number + of solutions. If the basis contains only the ground, None is + returned. + + The algorithm works by the fact that, supposing G is the basis + of F with respect to an elimination order (here lexicographic + order is used), G and F generate the same ideal, they have the + same set of solutions. By the elimination property, if G is a + reduced, zero-dimensional Groebner basis, then there exists an + univariate polynomial in G (in its last variable). This can be + solved by computing its roots. Substituting all computed roots + for the last (eliminated) variable in other elements of G, new + polynomial system is generated. Applying the above procedure + recursively, a finite number of solutions can be found. + + The ability of finding all solutions by this procedure depends + on the root finding algorithms. If no solutions were found, it + means only that roots() failed, but the system is solvable. To + overcome this difficulty use numerical algorithms instead. + + Parameters + ========== + + polys: a list/tuple/set + Listing all the polynomial equations that are needed to be solved + opt: an Options object + For specifying keyword arguments and generators + strict: a boolean + If strict is True, NotImplementedError will be raised if the solution + is known to be incomplete + + Returns + ======= + + List[Tuple] + a list of tuples with elements being solutions for the + symbols in the order they were passed as gens + None + None is returned when the computed basis contains only the ground. + + References + ========== + + .. [Buchberger01] B. Buchberger, Groebner Bases: A Short + Introduction for Systems Theorists, In: R. Moreno-Diaz, + B. Buchberger, J.L. Freire, Proceedings of EUROCAST'01, + February, 2001 + + .. [Cox97] D. Cox, J. Little, D. O'Shea, Ideals, Varieties + and Algorithms, Springer, Second Edition, 1997, pp. 112 + + Raises + ======== + + NotImplementedError + If the system is not zero-dimensional (does not have a finite + number of solutions) + + UnsolvableFactorError + If ``strict`` is True and not all solution components are + expressible in radicals + + Examples + ======== + + >>> from sympy import Poly, Options + >>> from sympy.solvers.polysys import solve_generic + >>> from sympy.abc import x, y + >>> NewOption = Options((x, y), {'domain': 'ZZ'}) + + >>> a = Poly(x - y + 5, x, y, domain='ZZ') + >>> b = Poly(x + y - 3, x, y, domain='ZZ') + >>> solve_generic([a, b], NewOption) + [(-1, 4)] + + >>> a = Poly(x - 2*y + 5, x, y, domain='ZZ') + >>> b = Poly(2*x - y - 3, x, y, domain='ZZ') + >>> solve_generic([a, b], NewOption) + [(11/3, 13/3)] + + >>> a = Poly(x**2 + y, x, y, domain='ZZ') + >>> b = Poly(x + y*4, x, y, domain='ZZ') + >>> solve_generic([a, b], NewOption) + [(0, 0), (1/4, -1/16)] + + >>> a = Poly(x**5 - x + y**3, x, y, domain='ZZ') + >>> b = Poly(y**2 - 1, x, y, domain='ZZ') + >>> solve_generic([a, b], NewOption, strict=True) + Traceback (most recent call last): + ... + UnsolvableFactorError + + """ + def _is_univariate(f): + """Returns True if 'f' is univariate in its last variable. """ + for monom in f.monoms(): + if any(monom[:-1]): + return False + + return True + + def _subs_root(f, gen, zero): + """Replace generator with a root so that the result is nice. """ + p = f.as_expr({gen: zero}) + + if f.degree(gen) >= 2: + p = p.expand(deep=False) + + return p + + def _solve_reduced_system(system, gens, entry=False): + """Recursively solves reduced polynomial systems. """ + if len(system) == len(gens) == 1: + # the below line will produce UnsolvableFactorError if + # strict=True and the solution from `roots` is incomplete + zeros = list(roots(system[0], gens[-1], strict=strict).keys()) + return [(zero,) for zero in zeros] + + basis = groebner(system, gens, polys=True) + + if len(basis) == 1 and basis[0].is_ground: + if not entry: + return [] + else: + return None + + univariate = list(filter(_is_univariate, basis)) + + if len(basis) < len(gens): + raise NotImplementedError(filldedent(''' + only zero-dimensional systems supported + (finite number of solutions) + ''')) + + if len(univariate) == 1: + f = univariate.pop() + else: + raise NotImplementedError(filldedent(''' + only zero-dimensional systems supported + (finite number of solutions) + ''')) + + gens = f.gens + gen = gens[-1] + + # the below line will produce UnsolvableFactorError if + # strict=True and the solution from `roots` is incomplete + zeros = list(roots(f.ltrim(gen), strict=strict).keys()) + + if not zeros: + return [] + + if len(basis) == 1: + return [(zero,) for zero in zeros] + + solutions = [] + + for zero in zeros: + new_system = [] + new_gens = gens[:-1] + + for b in basis[:-1]: + eq = _subs_root(b, gen, zero) + + if eq is not S.Zero: + new_system.append(eq) + + for solution in _solve_reduced_system(new_system, new_gens): + solutions.append(solution + (zero,)) + + if solutions and len(solutions[0]) != len(gens): + raise NotImplementedError(filldedent(''' + only zero-dimensional systems supported + (finite number of solutions) + ''')) + return solutions + + try: + result = _solve_reduced_system(polys, opt.gens, entry=True) + except CoercionFailed: + raise NotImplementedError + + if result is not None: + return sorted(result, key=default_sort_key) + + +def solve_triangulated(polys, *gens, **args): + """ + Solve a polynomial system using Gianni-Kalkbrenner algorithm. + + The algorithm proceeds by computing one Groebner basis in the ground + domain and then by iteratively computing polynomial factorizations in + appropriately constructed algebraic extensions of the ground domain. + + Parameters + ========== + + polys: a list/tuple/set + Listing all the equations that are needed to be solved + gens: generators + generators of the equations in polys for which we want the + solutions + args: Keyword arguments + Special options for solving the equations + + Returns + ======= + + List[Tuple] + A List of tuples. Solutions for symbols that satisfy the + equations listed in polys + + Examples + ======== + + >>> from sympy import solve_triangulated + >>> from sympy.abc import x, y, z + + >>> F = [x**2 + y + z - 1, x + y**2 + z - 1, x + y + z**2 - 1] + + >>> solve_triangulated(F, x, y, z) + [(0, 0, 1), (0, 1, 0), (1, 0, 0)] + + Using extension for algebraic solutions. + + >>> solve_triangulated(F, x, y, z, extension=True) #doctest: +NORMALIZE_WHITESPACE + [(0, 0, 1), (0, 1, 0), (1, 0, 0), + (CRootOf(x**2 + 2*x - 1, 0), CRootOf(x**2 + 2*x - 1, 0), CRootOf(x**2 + 2*x - 1, 0)), + (CRootOf(x**2 + 2*x - 1, 1), CRootOf(x**2 + 2*x - 1, 1), CRootOf(x**2 + 2*x - 1, 1))] + + References + ========== + + 1. Patrizia Gianni, Teo Mora, Algebraic Solution of System of + Polynomial Equations using Groebner Bases, AAECC-5 on Applied Algebra, + Algebraic Algorithms and Error-Correcting Codes, LNCS 356 247--257, 1989 + + """ + opt = build_options(gens, args) + + G = groebner(polys, gens, polys=True) + G = list(reversed(G)) + + extension = opt.get('extension', False) + if extension: + def _solve_univariate(f): + return [r for r, _ in f.all_roots(multiple=False, radicals=False)] + else: + domain = opt.get('domain') + + if domain is not None: + for i, g in enumerate(G): + G[i] = g.set_domain(domain) + + def _solve_univariate(f): + return list(f.ground_roots().keys()) + + f, G = G[0].ltrim(-1), G[1:] + dom = f.get_domain() + + zeros = _solve_univariate(f) + + if extension: + solutions = {((zero,), dom.algebraic_field(zero)) for zero in zeros} + else: + solutions = {((zero,), dom) for zero in zeros} + + var_seq = reversed(gens[:-1]) + vars_seq = postfixes(gens[1:]) + + for var, vars in zip(var_seq, vars_seq): + _solutions = set() + + for values, dom in solutions: + H, mapping = [], list(zip(vars, values)) + + for g in G: + _vars = (var,) + vars + + if g.has_only_gens(*_vars) and g.degree(var) != 0: + if extension: + g = g.set_domain(g.domain.unify(dom)) + h = g.ltrim(var).eval(dict(mapping)) + + if g.degree(var) == h.degree(): + H.append(h) + + p = min(H, key=lambda h: h.degree()) + zeros = _solve_univariate(p) + + for zero in zeros: + if not (zero in dom): + dom_zero = dom.algebraic_field(zero) + else: + dom_zero = dom + + _solutions.add(((zero,) + values, dom_zero)) + + solutions = _solutions + return sorted((s for s, _ in solutions), key=default_sort_key) + + +def factor_system(eqs: Sequence[Expr | complex], gens: Sequence[Expr] = (), **kwargs: Any) -> list[list[Expr]]: + """ + Factorizes a system of polynomial equations into + irreducible subsystems. + + Parameters + ========== + + eqs : list + List of expressions to be factored. + Each expression is assumed to be equal to zero. + + gens : list, optional + Generator(s) of the polynomial ring. + If not provided, all free symbols will be used. + + **kwargs : dict, optional + Same optional arguments taken by ``factor`` + + Returns + ======= + + list[list[Expr]] + A list of lists of expressions, where each sublist represents + an irreducible subsystem. When solved, each subsystem gives + one component of the solution. Only generic solutions are + returned (cases not requiring parameters to be zero). + + Examples + ======== + + >>> from sympy.solvers.polysys import factor_system, factor_system_cond + >>> from sympy.abc import x, y, a, b, c + + A simple system with multiple solutions: + + >>> factor_system([x**2 - 1, y - 1]) + [[x + 1, y - 1], [x - 1, y - 1]] + + A system with no solution: + + >>> factor_system([x, 1]) + [] + + A system where any value of the symbol(s) is a solution: + + >>> factor_system([x - x, (x + 1)**2 - (x**2 + 2*x + 1)]) + [[]] + + A system with no generic solution: + + >>> factor_system([a*x*(x-1), b*y, c], [x, y]) + [] + + If c is added to the unknowns then the system has a generic solution: + + >>> factor_system([a*x*(x-1), b*y, c], [x, y, c]) + [[x - 1, y, c], [x, y, c]] + + Alternatively :func:`factor_system_cond` can be used to get degenerate + cases as well: + + >>> factor_system_cond([a*x*(x-1), b*y, c], [x, y]) + [[x - 1, y, c], [x, y, c], [x - 1, b, c], [x, b, c], [y, a, c], [a, b, c]] + + Each of the above cases is only satisfiable in the degenerate case `c = 0`. + + The solution set of the original system represented + by eqs is the union of the solution sets of the + factorized systems. + + An empty list [] means no generic solution exists. + A list containing an empty list [[]] means any value of + the symbol(s) is a solution. + + See Also + ======== + + factor_system_cond : Returns both generic and degenerate solutions + factor_system_bool : Returns a Boolean combination representing all solutions + sympy.polys.polytools.factor : Factors a polynomial into irreducible factors + over the rational numbers + """ + + systems = _factor_system_poly_from_expr(eqs, gens, **kwargs) + systems_generic = [sys for sys in systems if not _is_degenerate(sys)] + systems_expr = [[p.as_expr() for p in system] for system in systems_generic] + return systems_expr + + +def _is_degenerate(system: list[Poly]) -> bool: + """Helper function to check if a system is degenerate""" + return any(p.is_ground for p in system) + + +def factor_system_bool(eqs: Sequence[Expr | complex], gens: Sequence[Expr] = (), **kwargs: Any) -> Boolean: + """ + Factorizes a system of polynomial equations into irreducible DNF. + + The system of expressions(eqs) is taken and a Boolean combination + of equations is returned that represents the same solution set. + The result is in disjunctive normal form (OR of ANDs). + + Parameters + ========== + + eqs : list + List of expressions to be factored. + Each expression is assumed to be equal to zero. + + gens : list, optional + Generator(s) of the polynomial ring. + If not provided, all free symbols will be used. + + **kwargs : dict, optional + Optional keyword arguments + + + Returns + ======= + + Boolean: + A Boolean combination of equations. The result is typically in + the form of a conjunction (AND) of a disjunctive normal form + with additional conditions. + + Examples + ======== + + >>> from sympy.solvers.polysys import factor_system_bool + >>> from sympy.abc import x, y, a, b, c + >>> factor_system_bool([x**2 - 1]) + Eq(x - 1, 0) | Eq(x + 1, 0) + + >>> factor_system_bool([x**2 - 1, y - 1]) + (Eq(x - 1, 0) & Eq(y - 1, 0)) | (Eq(x + 1, 0) & Eq(y - 1, 0)) + + >>> eqs = [a * (x - 1), b] + >>> factor_system_bool([a*(x - 1), b]) + (Eq(a, 0) & Eq(b, 0)) | (Eq(b, 0) & Eq(x - 1, 0)) + + >>> factor_system_bool([a*x**2 - a, b*(x + 1), c], [x]) + (Eq(c, 0) & Eq(x + 1, 0)) | (Eq(a, 0) & Eq(b, 0) & Eq(c, 0)) | (Eq(b, 0) & Eq(c, 0) & Eq(x - 1, 0)) + + >>> factor_system_bool([x**2 + 2*x + 1 - (x + 1)**2]) + True + + The result is logically equivalent to the system of equations + i.e. eqs. The function returns ``True`` when all values of + the symbol(s) is a solution and ``False`` when the system + cannot be solved. + + See Also + ======== + + factor_system : Returns factors and solvability condition separately + factor_system_cond : Returns both factors and conditions + + """ + + systems = factor_system_cond(eqs, gens, **kwargs) + return Or(*[And(*[Eq(eq, 0) for eq in sys]) for sys in systems]) + + +def factor_system_cond(eqs: Sequence[Expr | complex], gens: Sequence[Expr] = (), **kwargs: Any) -> list[list[Expr]]: + """ + Factorizes a polynomial system into irreducible components and returns + both generic and degenerate solutions. + + Parameters + ========== + + eqs : list + List of expressions to be factored. + Each expression is assumed to be equal to zero. + + gens : list, optional + Generator(s) of the polynomial ring. + If not provided, all free symbols will be used. + + **kwargs : dict, optional + Optional keyword arguments. + + Returns + ======= + + list[list[Expr]] + A list of lists of expressions, where each sublist represents + an irreducible subsystem. Includes both generic solutions and + degenerate cases requiring equality conditions on parameters. + + Examples + ======== + + >>> from sympy.solvers.polysys import factor_system_cond + >>> from sympy.abc import x, y, a, b, c + + >>> factor_system_cond([x**2 - 4, a*y, b], [x, y]) + [[x + 2, y, b], [x - 2, y, b], [x + 2, a, b], [x - 2, a, b]] + + >>> factor_system_cond([a*x*(x-1), b*y, c], [x, y]) + [[x - 1, y, c], [x, y, c], [x - 1, b, c], [x, b, c], [y, a, c], [a, b, c]] + + An empty list [] means no solution exists. + A list containing an empty list [[]] means any value of + the symbol(s) is a solution. + + See Also + ======== + + factor_system : Returns only generic solutions + factor_system_bool : Returns a Boolean combination representing all solutions + sympy.polys.polytools.factor : Factors a polynomial into irreducible factors + over the rational numbers + """ + systems_poly = _factor_system_poly_from_expr(eqs, gens, **kwargs) + systems = [[p.as_expr() for p in system] for system in systems_poly] + return systems + + +def _factor_system_poly_from_expr( + eqs: Sequence[Expr | complex], gens: Sequence[Expr], **kwargs: Any +) -> list[list[Poly]]: + """ + Convert expressions to polynomials and factor the system. + + Takes a sequence of expressions, converts them to + polynomials, and factors the resulting system. Handles both regular + polynomial systems and purely numerical cases. + """ + try: + polys, opts = parallel_poly_from_expr(eqs, *gens, **kwargs) + only_numbers = False + except (GeneratorsNeeded, PolificationFailed): + _u = Dummy('u') + polys, opts = parallel_poly_from_expr(eqs, [_u], **kwargs) + assert opts['domain'].is_Numerical + only_numbers = True + + if only_numbers: + return [[]] if all(p == 0 for p in polys) else [] + + return factor_system_poly(polys) + + +def factor_system_poly(polys: list[Poly]) -> list[list[Poly]]: + """ + Factors a system of polynomial equations into irreducible subsystems + + Core implementation that works directly with Poly instances. + + Parameters + ========== + + polys : list[Poly] + A list of Poly instances to be factored. + + Returns + ======= + + list[list[Poly]] + A list of lists of polynomials, where each sublist represents + an irreducible component of the solution. Includes both + generic and degenerate cases. + + Examples + ======== + + >>> from sympy import symbols, Poly, ZZ + >>> from sympy.solvers.polysys import factor_system_poly + >>> a, b, c, x = symbols('a b c x') + >>> p1 = Poly((a - 1)*(x - 2), x, domain=ZZ[a,b,c]) + >>> p2 = Poly((b - 3)*(x - 2), x, domain=ZZ[a,b,c]) + >>> p3 = Poly(c, x, domain=ZZ[a,b,c]) + + The equation to be solved for x is ``x - 2 = 0`` provided either + of the two conditions on the parameters ``a`` and ``b`` is nonzero + and the constant parameter ``c`` should be zero. + + >>> sys1, sys2 = factor_system_poly([p1, p2, p3]) + >>> sys1 + [Poly(x - 2, x, domain='ZZ[a,b,c]'), + Poly(c, x, domain='ZZ[a,b,c]')] + >>> sys2 + [Poly(a - 1, x, domain='ZZ[a,b,c]'), + Poly(b - 3, x, domain='ZZ[a,b,c]'), + Poly(c, x, domain='ZZ[a,b,c]')] + + An empty list [] when returned means no solution exists. + Whereas a list containing an empty list [[]] means any value is a solution. + + See Also + ======== + + factor_system : Returns only generic solutions + factor_system_bool : Returns a Boolean combination representing the solutions + factor_system_cond : Returns both generic and degenerate solutions + sympy.polys.polytools.factor : Factors a polynomial into irreducible factors + over the rational numbers + """ + if not all(isinstance(poly, Poly) for poly in polys): + raise TypeError("polys should be a list of Poly instances") + if not polys: + return [[]] + + base_domain = polys[0].domain + base_gens = polys[0].gens + if not all(poly.domain == base_domain and poly.gens == base_gens for poly in polys[1:]): + raise DomainError("All polynomials must have the same domain and generators") + + factor_sets = [] + for poly in polys: + constant, factors_mult = poly.factor_list() + + if constant.is_zero is True: + continue + elif constant.is_zero is False: + if not factors_mult: + return [] + factor_sets.append([f for f, _ in factors_mult]) + else: + constant = sqf_part(factor_terms(constant).as_coeff_Mul()[1]) + constp = Poly(constant, base_gens, domain=base_domain) + factors = [f for f, _ in factors_mult] + factors.append(constp) + factor_sets.append(factors) + + if not factor_sets: + return [[]] + + result = _factor_sets(factor_sets) + return _sort_systems(result) + + +def _factor_sets_slow(eqs: list[list]) -> set[frozenset]: + """ + Helper to find the minimal set of factorised subsystems that is + equivalent to the original system. + + The result is in DNF. + """ + if not eqs: + return {frozenset()} + systems_set = {frozenset(sys) for sys in cartes(*eqs)} + return {s1 for s1 in systems_set if not any(s1 > s2 for s2 in systems_set)} + + +def _factor_sets(eqs: list[list]) -> set[frozenset]: + """ + Helper that builds factor combinations. + """ + if not eqs: + return {frozenset()} + + current_set = min(eqs, key=len) + other_sets = [s for s in eqs if s is not current_set] + + stack = [(factor, [s for s in other_sets if factor not in s], {factor}) + for factor in current_set] + + result = set() + + while stack: + factor, remaining_sets, current_solution = stack.pop() + + if not remaining_sets: + result.add(frozenset(current_solution)) + continue + + next_set = min(remaining_sets, key=len) + next_remaining = [s for s in remaining_sets if s is not next_set] + + for next_factor in next_set: + valid_remaining = [s for s in next_remaining if next_factor not in s] + new_solution = current_solution | {next_factor} + stack.append((next_factor, valid_remaining, new_solution)) + + return {s1 for s1 in result if not any(s1 > s2 for s2 in result)} + + +def _sort_systems(systems: Iterable[Iterable[Poly]]) -> list[list[Poly]]: + """Sorts a list of lists of polynomials""" + systems_list = [sorted(s, key=_poly_sort_key, reverse=True) for s in systems] + return sorted(systems_list, key=_sys_sort_key, reverse=True) + + +def _poly_sort_key(poly): + """Sort key for polynomials""" + if poly.domain.is_FF: + poly = poly.set_domain(ZZ) + return poly.degree_list(), poly.rep.to_list() + + +def _sys_sort_key(sys): + """Sort key for lists of polynomials""" + return list(zip(*map(_poly_sort_key, sys))) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/recurr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/recurr.py new file mode 100644 index 0000000000000000000000000000000000000000..ba627bbd4cb0844f11a8743634f5f10328aadca8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/recurr.py @@ -0,0 +1,843 @@ +r""" +This module is intended for solving recurrences or, in other words, +difference equations. Currently supported are linear, inhomogeneous +equations with polynomial or rational coefficients. + +The solutions are obtained among polynomials, rational functions, +hypergeometric terms, or combinations of hypergeometric term which +are pairwise dissimilar. + +``rsolve_X`` functions were meant as a low level interface +for ``rsolve`` which would use Mathematica's syntax. + +Given a recurrence relation: + + .. math:: a_{k}(n) y(n+k) + a_{k-1}(n) y(n+k-1) + + ... + a_{0}(n) y(n) = f(n) + +where `k > 0` and `a_{i}(n)` are polynomials in `n`. To use +``rsolve_X`` we need to put all coefficients in to a list ``L`` of +`k+1` elements the following way: + + ``L = [a_{0}(n), ..., a_{k-1}(n), a_{k}(n)]`` + +where ``L[i]``, for `i=0, \ldots, k`, maps to +`a_{i}(n) y(n+i)` (`y(n+i)` is implicit). + +For example if we would like to compute `m`-th Bernoulli polynomial +up to a constant (example was taken from rsolve_poly docstring), +then we would use `b(n+1) - b(n) = m n^{m-1}` recurrence, which +has solution `b(n) = B_m + C`. + +Then ``L = [-1, 1]`` and `f(n) = m n^(m-1)` and finally for `m=4`: + +>>> from sympy import Symbol, bernoulli, rsolve_poly +>>> n = Symbol('n', integer=True) + +>>> rsolve_poly([-1, 1], 4*n**3, n) +C0 + n**4 - 2*n**3 + n**2 + +>>> bernoulli(4, n) +n**4 - 2*n**3 + n**2 - 1/30 + +For the sake of completeness, `f(n)` can be: + + [1] a polynomial -> rsolve_poly + [2] a rational function -> rsolve_ratio + [3] a hypergeometric function -> rsolve_hyper +""" +from collections import defaultdict + +from sympy.concrete import product +from sympy.core.singleton import S +from sympy.core.numbers import Rational, I +from sympy.core.symbol import Symbol, Wild, Dummy +from sympy.core.relational import Equality +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import sympify + +from sympy.simplify import simplify, hypersimp, hypersimilar # type: ignore +from sympy.solvers import solve, solve_undetermined_coeffs +from sympy.polys import Poly, quo, gcd, lcm, roots, resultant +from sympy.functions import binomial, factorial, FallingFactorial, RisingFactorial +from sympy.matrices import Matrix, casoratian +from sympy.utilities.iterables import numbered_symbols + + +def rsolve_poly(coeffs, f, n, shift=0, **hints): + r""" + Given linear recurrence operator `\operatorname{L}` of order + `k` with polynomial coefficients and inhomogeneous equation + `\operatorname{L} y = f`, where `f` is a polynomial, we seek for + all polynomial solutions over field `K` of characteristic zero. + + The algorithm performs two basic steps: + + (1) Compute degree `N` of the general polynomial solution. + (2) Find all polynomials of degree `N` or less + of `\operatorname{L} y = f`. + + There are two methods for computing the polynomial solutions. + If the degree bound is relatively small, i.e. it's smaller than + or equal to the order of the recurrence, then naive method of + undetermined coefficients is being used. This gives a system + of algebraic equations with `N+1` unknowns. + + In the other case, the algorithm performs transformation of the + initial equation to an equivalent one for which the system of + algebraic equations has only `r` indeterminates. This method is + quite sophisticated (in comparison with the naive one) and was + invented together by Abramov, Bronstein and Petkovsek. + + It is possible to generalize the algorithm implemented here to + the case of linear q-difference and differential equations. + + Lets say that we would like to compute `m`-th Bernoulli polynomial + up to a constant. For this we can use `b(n+1) - b(n) = m n^{m-1}` + recurrence, which has solution `b(n) = B_m + C`. For example: + + >>> from sympy import Symbol, rsolve_poly + >>> n = Symbol('n', integer=True) + + >>> rsolve_poly([-1, 1], 4*n**3, n) + C0 + n**4 - 2*n**3 + n**2 + + References + ========== + + .. [1] S. A. Abramov, M. Bronstein and M. Petkovsek, On polynomial + solutions of linear operator equations, in: T. Levelt, ed., + Proc. ISSAC '95, ACM Press, New York, 1995, 290-296. + + .. [2] M. Petkovsek, Hypergeometric solutions of linear recurrences + with polynomial coefficients, J. Symbolic Computation, + 14 (1992), 243-264. + + .. [3] M. Petkovsek, H. S. Wilf, D. Zeilberger, A = B, 1996. + + """ + f = sympify(f) + + if not f.is_polynomial(n): + return None + + homogeneous = f.is_zero + + r = len(coeffs) - 1 + + coeffs = [Poly(coeff, n) for coeff in coeffs] + + polys = [Poly(0, n)]*(r + 1) + terms = [(S.Zero, S.NegativeInfinity)]*(r + 1) + + for i in range(r + 1): + for j in range(i, r + 1): + polys[i] += coeffs[j]*(binomial(j, i).as_poly(n)) + + if not polys[i].is_zero: + (exp,), coeff = polys[i].LT() + terms[i] = (coeff, exp) + + d = b = terms[0][1] + + for i in range(1, r + 1): + if terms[i][1] > d: + d = terms[i][1] + + if terms[i][1] - i > b: + b = terms[i][1] - i + + d, b = int(d), int(b) + + x = Dummy('x') + + degree_poly = S.Zero + + for i in range(r + 1): + if terms[i][1] - i == b: + degree_poly += terms[i][0]*FallingFactorial(x, i) + + nni_roots = list(roots(degree_poly, x, filter='Z', + predicate=lambda r: r >= 0).keys()) + + if nni_roots: + N = [max(nni_roots)] + else: + N = [] + + if homogeneous: + N += [-b - 1] + else: + N += [f.as_poly(n).degree() - b, -b - 1] + + N = int(max(N)) + + if N < 0: + if homogeneous: + if hints.get('symbols', False): + return (S.Zero, []) + else: + return S.Zero + else: + return None + + if N <= r: + C = [] + y = E = S.Zero + + for i in range(N + 1): + C.append(Symbol('C' + str(i + shift))) + y += C[i] * n**i + + for i in range(r + 1): + E += coeffs[i].as_expr()*y.subs(n, n + i) + + solutions = solve_undetermined_coeffs(E - f, C, n) + + if solutions is not None: + _C = C + C = [c for c in C if (c not in solutions)] + result = y.subs(solutions) + else: + return None # TBD + else: + A = r + U = N + A + b + 1 + + nni_roots = list(roots(polys[r], filter='Z', + predicate=lambda r: r >= 0).keys()) + + if nni_roots != []: + a = max(nni_roots) + 1 + else: + a = S.Zero + + def _zero_vector(k): + return [S.Zero] * k + + def _one_vector(k): + return [S.One] * k + + def _delta(p, k): + B = S.One + D = p.subs(n, a + k) + + for i in range(1, k + 1): + B *= Rational(i - k - 1, i) + D += B * p.subs(n, a + k - i) + + return D + + alpha = {} + + for i in range(-A, d + 1): + I = _one_vector(d + 1) + + for k in range(1, d + 1): + I[k] = I[k - 1] * (x + i - k + 1)/k + + alpha[i] = S.Zero + + for j in range(A + 1): + for k in range(d + 1): + B = binomial(k, i + j) + D = _delta(polys[j].as_expr(), k) + + alpha[i] += I[k]*B*D + + V = Matrix(U, A, lambda i, j: int(i == j)) + + if homogeneous: + for i in range(A, U): + v = _zero_vector(A) + + for k in range(1, A + b + 1): + if i - k < 0: + break + + B = alpha[k - A].subs(x, i - k) + + for j in range(A): + v[j] += B * V[i - k, j] + + denom = alpha[-A].subs(x, i) + + for j in range(A): + V[i, j] = -v[j] / denom + else: + G = _zero_vector(U) + + for i in range(A, U): + v = _zero_vector(A) + g = S.Zero + + for k in range(1, A + b + 1): + if i - k < 0: + break + + B = alpha[k - A].subs(x, i - k) + + for j in range(A): + v[j] += B * V[i - k, j] + + g += B * G[i - k] + + denom = alpha[-A].subs(x, i) + + for j in range(A): + V[i, j] = -v[j] / denom + + G[i] = (_delta(f, i - A) - g) / denom + + P, Q = _one_vector(U), _zero_vector(A) + + for i in range(1, U): + P[i] = (P[i - 1] * (n - a - i + 1)/i).expand() + + for i in range(A): + Q[i] = Add(*[(v*p).expand() for v, p in zip(V[:, i], P)]) + + if not homogeneous: + h = Add(*[(g*p).expand() for g, p in zip(G, P)]) + + C = [Symbol('C' + str(i + shift)) for i in range(A)] + + g = lambda i: Add(*[c*_delta(q, i) for c, q in zip(C, Q)]) + + if homogeneous: + E = [g(i) for i in range(N + 1, U)] + else: + E = [g(i) + _delta(h, i) for i in range(N + 1, U)] + + if E != []: + solutions = solve(E, *C) + + if not solutions: + if homogeneous: + if hints.get('symbols', False): + return (S.Zero, []) + else: + return S.Zero + else: + return None + else: + solutions = {} + + if homogeneous: + result = S.Zero + else: + result = h + + _C = C[:] + for c, q in list(zip(C, Q)): + if c in solutions: + s = solutions[c]*q + C.remove(c) + else: + s = c*q + + result += s.expand() + + if C != _C: + # renumber so they are contiguous + result = result.xreplace(dict(zip(C, _C))) + C = _C[:len(C)] + + if hints.get('symbols', False): + return (result, C) + else: + return result + + +def rsolve_ratio(coeffs, f, n, **hints): + r""" + Given linear recurrence operator `\operatorname{L}` of order `k` + with polynomial coefficients and inhomogeneous equation + `\operatorname{L} y = f`, where `f` is a polynomial, we seek + for all rational solutions over field `K` of characteristic zero. + + This procedure accepts only polynomials, however if you are + interested in solving recurrence with rational coefficients + then use ``rsolve`` which will pre-process the given equation + and run this procedure with polynomial arguments. + + The algorithm performs two basic steps: + + (1) Compute polynomial `v(n)` which can be used as universal + denominator of any rational solution of equation + `\operatorname{L} y = f`. + + (2) Construct new linear difference equation by substitution + `y(n) = u(n)/v(n)` and solve it for `u(n)` finding all its + polynomial solutions. Return ``None`` if none were found. + + The algorithm implemented here is a revised version of the original + Abramov's algorithm, developed in 1989. The new approach is much + simpler to implement and has better overall efficiency. This + method can be easily adapted to the q-difference equations case. + + Besides finding rational solutions alone, this functions is + an important part of Hyper algorithm where it is used to find + a particular solution for the inhomogeneous part of a recurrence. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.solvers.recurr import rsolve_ratio + >>> rsolve_ratio([-2*x**3 + x**2 + 2*x - 1, 2*x**3 + x**2 - 6*x, + ... - 2*x**3 - 11*x**2 - 18*x - 9, 2*x**3 + 13*x**2 + 22*x + 8], 0, x) + C0*(2*x - 3)/(2*(x**2 - 1)) + + References + ========== + + .. [1] S. A. Abramov, Rational solutions of linear difference + and q-difference equations with polynomial coefficients, + in: T. Levelt, ed., Proc. ISSAC '95, ACM Press, New York, + 1995, 285-289 + + See Also + ======== + + rsolve_hyper + """ + f = sympify(f) + + if not f.is_polynomial(n): + return None + + coeffs = list(map(sympify, coeffs)) + + r = len(coeffs) - 1 + + A, B = coeffs[r], coeffs[0] + A = A.subs(n, n - r).expand() + + h = Dummy('h') + + res = resultant(A, B.subs(n, n + h), n) + + if not res.is_polynomial(h): + p, q = res.as_numer_denom() + res = quo(p, q, h) + + nni_roots = list(roots(res, h, filter='Z', + predicate=lambda r: r >= 0).keys()) + + if not nni_roots: + return rsolve_poly(coeffs, f, n, **hints) + else: + C, numers = S.One, [S.Zero]*(r + 1) + + for i in range(int(max(nni_roots)), -1, -1): + d = gcd(A, B.subs(n, n + i), n) + + A = quo(A, d, n) + B = quo(B, d.subs(n, n - i), n) + + C *= Mul(*[d.subs(n, n - j) for j in range(i + 1)]) + + denoms = [C.subs(n, n + i) for i in range(r + 1)] + + for i in range(r + 1): + g = gcd(coeffs[i], denoms[i], n) + + numers[i] = quo(coeffs[i], g, n) + denoms[i] = quo(denoms[i], g, n) + + for i in range(r + 1): + numers[i] *= Mul(*(denoms[:i] + denoms[i + 1:])) + + result = rsolve_poly(numers, f * Mul(*denoms), n, **hints) + + if result is not None: + if hints.get('symbols', False): + return (simplify(result[0] / C), result[1]) + else: + return simplify(result / C) + else: + return None + + +def rsolve_hyper(coeffs, f, n, **hints): + r""" + Given linear recurrence operator `\operatorname{L}` of order `k` + with polynomial coefficients and inhomogeneous equation + `\operatorname{L} y = f` we seek for all hypergeometric solutions + over field `K` of characteristic zero. + + The inhomogeneous part can be either hypergeometric or a sum + of a fixed number of pairwise dissimilar hypergeometric terms. + + The algorithm performs three basic steps: + + (1) Group together similar hypergeometric terms in the + inhomogeneous part of `\operatorname{L} y = f`, and find + particular solution using Abramov's algorithm. + + (2) Compute generating set of `\operatorname{L}` and find basis + in it, so that all solutions are linearly independent. + + (3) Form final solution with the number of arbitrary + constants equal to dimension of basis of `\operatorname{L}`. + + Term `a(n)` is hypergeometric if it is annihilated by first order + linear difference equations with polynomial coefficients or, in + simpler words, if consecutive term ratio is a rational function. + + The output of this procedure is a linear combination of fixed + number of hypergeometric terms. However the underlying method + can generate larger class of solutions - D'Alembertian terms. + + Note also that this method not only computes the kernel of the + inhomogeneous equation, but also reduces in to a basis so that + solutions generated by this procedure are linearly independent + + Examples + ======== + + >>> from sympy.solvers import rsolve_hyper + >>> from sympy.abc import x + + >>> rsolve_hyper([-1, -1, 1], 0, x) + C0*(1/2 - sqrt(5)/2)**x + C1*(1/2 + sqrt(5)/2)**x + + >>> rsolve_hyper([-1, 1], 1 + x, x) + C0 + x*(x + 1)/2 + + References + ========== + + .. [1] M. Petkovsek, Hypergeometric solutions of linear recurrences + with polynomial coefficients, J. Symbolic Computation, + 14 (1992), 243-264. + + .. [2] M. Petkovsek, H. S. Wilf, D. Zeilberger, A = B, 1996. + """ + coeffs = list(map(sympify, coeffs)) + + f = sympify(f) + + r, kernel, symbols = len(coeffs) - 1, [], set() + + if not f.is_zero: + if f.is_Add: + similar = {} + + for g in f.expand().args: + if not g.is_hypergeometric(n): + return None + + for h in similar.keys(): + if hypersimilar(g, h, n): + similar[h] += g + break + else: + similar[g] = S.Zero + + inhomogeneous = [g + h for g, h in similar.items()] + elif f.is_hypergeometric(n): + inhomogeneous = [f] + else: + return None + + for i, g in enumerate(inhomogeneous): + coeff, polys = S.One, coeffs[:] + denoms = [S.One]*(r + 1) + + s = hypersimp(g, n) + + for j in range(1, r + 1): + coeff *= s.subs(n, n + j - 1) + + p, q = coeff.as_numer_denom() + + polys[j] *= p + denoms[j] = q + + for j in range(r + 1): + polys[j] *= Mul(*(denoms[:j] + denoms[j + 1:])) + + # FIXME: The call to rsolve_ratio below should suffice (rsolve_poly + # call can be removed) but the XFAIL test_rsolve_ratio_missed must + # be fixed first. + R = rsolve_ratio(polys, Mul(*denoms), n, symbols=True) + if R is not None: + R, syms = R + if syms: + R = R.subs(zip(syms, [0]*len(syms))) + else: + R = rsolve_poly(polys, Mul(*denoms), n) + + if R: + inhomogeneous[i] *= R + else: + return None + + result = Add(*inhomogeneous) + result = simplify(result) + else: + result = S.Zero + + Z = Dummy('Z') + + p, q = coeffs[0], coeffs[r].subs(n, n - r + 1) + + p_factors = list(roots(p, n).keys()) + q_factors = list(roots(q, n).keys()) + + factors = [(S.One, S.One)] + + for p in p_factors: + for q in q_factors: + if p.is_integer and q.is_integer and p <= q: + continue + else: + factors += [(n - p, n - q)] + + p = [(n - p, S.One) for p in p_factors] + q = [(S.One, n - q) for q in q_factors] + + factors = p + factors + q + + for A, B in factors: + polys, degrees = [], [] + D = A*B.subs(n, n + r - 1) + + for i in range(r + 1): + a = Mul(*[A.subs(n, n + j) for j in range(i)]) + b = Mul(*[B.subs(n, n + j) for j in range(i, r)]) + + poly = quo(coeffs[i]*a*b, D, n) + polys.append(poly.as_poly(n)) + + if not poly.is_zero: + degrees.append(polys[i].degree()) + + if degrees: + d, poly = max(degrees), S.Zero + else: + return None + + for i in range(r + 1): + coeff = polys[i].nth(d) + + if coeff is not S.Zero: + poly += coeff * Z**i + + for z in roots(poly, Z).keys(): + if z.is_zero: + continue + + recurr_coeffs = [polys[i].as_expr()*z**i for i in range(r + 1)] + if d == 0 and 0 != Add(*[recurr_coeffs[j]*j for j in range(1, r + 1)]): + # faster inline check (than calling rsolve_poly) for a + # constant solution to a constant coefficient recurrence. + sol = [Symbol("C" + str(len(symbols)))] + else: + sol, syms = rsolve_poly(recurr_coeffs, 0, n, len(symbols), symbols=True) + sol = sol.collect(syms) + sol = [sol.coeff(s) for s in syms] + + for C in sol: + ratio = z * A * C.subs(n, n + 1) / B / C + ratio = simplify(ratio) + # If there is a nonnegative root in the denominator of the ratio, + # this indicates that the term y(n_root) is zero, and one should + # start the product with the term y(n_root + 1). + n0 = 0 + for n_root in roots(ratio.as_numer_denom()[1], n).keys(): + if n_root.has(I): + return None + elif (n0 < (n_root + 1)) == True: + n0 = n_root + 1 + K = product(ratio, (n, n0, n - 1)) + if K.has(factorial, FallingFactorial, RisingFactorial): + K = simplify(K) + + if casoratian(kernel + [K], n, zero=False) != 0: + kernel.append(K) + + kernel.sort(key=default_sort_key) + sk = list(zip(numbered_symbols('C'), kernel)) + + for C, ker in sk: + result += C * ker + + if hints.get('symbols', False): + # XXX: This returns the symbols in a non-deterministic order + symbols |= {s for s, k in sk} + return (result, list(symbols)) + else: + return result + + +def rsolve(f, y, init=None): + r""" + Solve univariate recurrence with rational coefficients. + + Given `k`-th order linear recurrence `\operatorname{L} y = f`, + or equivalently: + + .. math:: a_{k}(n) y(n+k) + a_{k-1}(n) y(n+k-1) + + \cdots + a_{0}(n) y(n) = f(n) + + where `a_{i}(n)`, for `i=0, \ldots, k`, are polynomials or rational + functions in `n`, and `f` is a hypergeometric function or a sum + of a fixed number of pairwise dissimilar hypergeometric terms in + `n`, finds all solutions or returns ``None``, if none were found. + + Initial conditions can be given as a dictionary in two forms: + + (1) ``{ n_0 : v_0, n_1 : v_1, ..., n_m : v_m}`` + (2) ``{y(n_0) : v_0, y(n_1) : v_1, ..., y(n_m) : v_m}`` + + or as a list ``L`` of values: + + ``L = [v_0, v_1, ..., v_m]`` + + where ``L[i] = v_i``, for `i=0, \ldots, m`, maps to `y(n_i)`. + + Examples + ======== + + Lets consider the following recurrence: + + .. math:: (n - 1) y(n + 2) - (n^2 + 3 n - 2) y(n + 1) + + 2 n (n + 1) y(n) = 0 + + >>> from sympy import Function, rsolve + >>> from sympy.abc import n + >>> y = Function('y') + + >>> f = (n - 1)*y(n + 2) - (n**2 + 3*n - 2)*y(n + 1) + 2*n*(n + 1)*y(n) + + >>> rsolve(f, y(n)) + 2**n*C0 + C1*factorial(n) + + >>> rsolve(f, y(n), {y(0):0, y(1):3}) + 3*2**n - 3*factorial(n) + + See Also + ======== + + rsolve_poly, rsolve_ratio, rsolve_hyper + + """ + if isinstance(f, Equality): + f = f.lhs - f.rhs + + n = y.args[0] + k = Wild('k', exclude=(n,)) + + # Preprocess user input to allow things like + # y(n) + a*(y(n + 1) + y(n - 1))/2 + f = f.expand().collect(y.func(Wild('m', integer=True))) + + h_part = defaultdict(list) + i_part = [] + for g in Add.make_args(f): + coeff, dep = g.as_coeff_mul(y.func) + if not dep: + i_part.append(coeff) + continue + for h in dep: + if h.is_Function and h.func == y.func: + result = h.args[0].match(n + k) + if result is not None: + h_part[int(result[k])].append(coeff) + continue + raise ValueError( + "'%s(%s + k)' expected, got '%s'" % (y.func, n, h)) + for k in h_part: + h_part[k] = Add(*h_part[k]) + h_part.default_factory = lambda: 0 + i_part = Add(*i_part) + + for k, coeff in h_part.items(): + h_part[k] = simplify(coeff) + + common = S.One + + if not i_part.is_zero and not i_part.is_hypergeometric(n) and \ + not (i_part.is_Add and all((x.is_hypergeometric(n) for x in i_part.expand().args))): + raise ValueError("The independent term should be a sum of hypergeometric functions, got '%s'" % i_part) + + for coeff in h_part.values(): + if coeff.is_rational_function(n): + if not coeff.is_polynomial(n): + common = lcm(common, coeff.as_numer_denom()[1], n) + else: + raise ValueError( + "Polynomial or rational function expected, got '%s'" % coeff) + + i_numer, i_denom = i_part.as_numer_denom() + + if i_denom.is_polynomial(n): + common = lcm(common, i_denom, n) + + if common is not S.One: + for k, coeff in h_part.items(): + numer, denom = coeff.as_numer_denom() + h_part[k] = numer*quo(common, denom, n) + + i_part = i_numer*quo(common, i_denom, n) + + K_min = min(h_part.keys()) + + if K_min < 0: + K = abs(K_min) + + H_part = defaultdict(lambda: S.Zero) + i_part = i_part.subs(n, n + K).expand() + common = common.subs(n, n + K).expand() + + for k, coeff in h_part.items(): + H_part[k + K] = coeff.subs(n, n + K).expand() + else: + H_part = h_part + + K_max = max(H_part.keys()) + coeffs = [H_part[i] for i in range(K_max + 1)] + + result = rsolve_hyper(coeffs, -i_part, n, symbols=True) + + if result is None: + return None + + solution, symbols = result + + if init in ({}, []): + init = None + + if symbols and init is not None: + if isinstance(init, list): + init = {i: init[i] for i in range(len(init))} + + equations = [] + + for k, v in init.items(): + try: + i = int(k) + except TypeError: + if k.is_Function and k.func == y.func: + i = int(k.args[0]) + else: + raise ValueError("Integer or term expected, got '%s'" % k) + + eq = solution.subs(n, i) - v + if eq.has(S.NaN): + eq = solution.limit(n, i) - v + equations.append(eq) + + result = solve(equations, *symbols) + + if not result: + return None + else: + solution = solution.subs(result) + + return solution diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/simplex.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/simplex.py new file mode 100644 index 0000000000000000000000000000000000000000..c8e652cb626507d7829f9bc1c78fc6f49809865f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/simplex.py @@ -0,0 +1,1104 @@ +"""Tools for optimizing a linear function for a given simplex. + +For the linear objective function ``f`` with linear constraints +expressed using `Le`, `Ge` or `Eq` can be found with ``lpmin`` or +``lpmax``. The symbols are **unbounded** unless specifically +constrained. + +As an alternative, the matrices describing the objective and the +constraints, and an optional list of bounds can be passed to +``linprog`` which will solve for the minimization of ``C*x`` +under constraints ``A*x <= b`` and/or ``Aeq*x = beq``, and +individual bounds for variables given as ``(lo, hi)``. The values +returned are **nonnegative** unless bounds are provided that +indicate otherwise. + +Errors that might be raised are UnboundedLPError when there is no +finite solution for the system or InfeasibleLPError when the +constraints represent impossible conditions (i.e. a non-existent + simplex). + +Here is a simple 1-D system: minimize `x` given that ``x >= 1``. + + >>> from sympy.solvers.simplex import lpmin, linprog + >>> from sympy.abc import x + + The function and a list with the constraint is passed directly + to `lpmin`: + + >>> lpmin(x, [x >= 1]) + (1, {x: 1}) + + For `linprog` the matrix for the objective is `[1]` and the + uivariate constraint can be passed as a bound with None acting + as infinity: + + >>> linprog([1], bounds=(1, None)) + (1, [1]) + + Or the matrices, corresponding to ``x >= 1`` expressed as + ``-x <= -1`` as required by the routine, can be passed: + + >>> linprog([1], [-1], [-1]) + (1, [1]) + + If there is no limit for the objective, an error is raised. + In this case there is a valid region of interest (simplex) + but no limit to how small ``x`` can be: + + >>> lpmin(x, []) + Traceback (most recent call last): + ... + sympy.solvers.simplex.UnboundedLPError: + Objective function can assume arbitrarily large values! + + An error is raised if there is no possible solution: + + >>> lpmin(x,[x<=1,x>=2]) + Traceback (most recent call last): + ... + sympy.solvers.simplex.InfeasibleLPError: + Inconsistent/False constraint +""" + +from sympy.core import sympify +from sympy.core.exprtools import factor_terms +from sympy.core.relational import Le, Ge, Eq +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.core.sorting import ordered +from sympy.functions.elementary.complexes import sign +from sympy.matrices.dense import Matrix, zeros +from sympy.solvers.solveset import linear_eq_to_matrix +from sympy.utilities.iterables import numbered_symbols +from sympy.utilities.misc import filldedent + + +class UnboundedLPError(Exception): + """ + A linear programming problem is said to be unbounded if its objective + function can assume arbitrarily large values. + + Example + ======= + + Suppose you want to maximize + 2x + subject to + x >= 0 + + There's no upper limit that 2x can take. + """ + + pass + + +class InfeasibleLPError(Exception): + """ + A linear programming problem is considered infeasible if its + constraint set is empty. That is, if the set of all vectors + satisfying the constraints is empty, then the problem is infeasible. + + Example + ======= + + Suppose you want to maximize + x + subject to + x >= 10 + x <= 9 + + No x can satisfy those constraints. + """ + + pass + + +def _pivot(M, i, j): + """ + The pivot element `M[i, j]` is inverted and the rest of the matrix + modified and returned as a new matrix; original is left unmodified. + + Example + ======= + + >>> from sympy.matrices.dense import Matrix + >>> from sympy.solvers.simplex import _pivot + >>> from sympy import var + >>> Matrix(3, 3, var('a:i')) + Matrix([ + [a, b, c], + [d, e, f], + [g, h, i]]) + >>> _pivot(_, 1, 0) + Matrix([ + [-a/d, -a*e/d + b, -a*f/d + c], + [ 1/d, e/d, f/d], + [-g/d, h - e*g/d, i - f*g/d]]) + """ + Mi, Mj, Mij = M[i, :], M[:, j], M[i, j] + if Mij == 0: + raise ZeroDivisionError( + "Tried to pivot about zero-valued entry.") + A = M - Mj * (Mi / Mij) + A[i, :] = Mi / Mij + A[:, j] = -Mj / Mij + A[i, j] = 1 / Mij + return A + + +def _choose_pivot_row(A, B, candidate_rows, pivot_col, Y): + # Choose row with smallest ratio + # If there are ties, pick using Bland's rule + return min(candidate_rows, key=lambda i: (B[i] / A[i, pivot_col], Y[i])) + + +def _simplex(A, B, C, D=None, dual=False): + """Return ``(o, x, y)`` obtained from the two-phase simplex method + using Bland's rule: ``o`` is the minimum value of primal, + ``Cx - D``, under constraints ``Ax <= B`` (with ``x >= 0``) and + the maximum of the dual, ``y^{T}B - D``, under constraints + ``A^{T}*y >= C^{T}`` (with ``y >= 0``). To compute the dual of + the system, pass `dual=True` and ``(o, y, x)`` will be returned. + + Note: the nonnegative constraints for ``x`` and ``y`` supercede + any values of ``A`` and ``B`` that are inconsistent with that + assumption, so if a constraint of ``x >= -1`` is represented + in ``A`` and ``B``, no value will be obtained that is negative; if + a constraint of ``x <= -1`` is represented, an error will be + raised since no solution is possible. + + This routine relies on the ability of determining whether an + expression is 0 or not. This is guaranteed if the input contains + only Float or Rational entries. It will raise a TypeError if + a relationship does not evaluate to True or False. + + Examples + ======== + + >>> from sympy.solvers.simplex import _simplex + >>> from sympy import Matrix + + Consider the simple minimization of ``f = x + y + 1`` under the + constraint that ``y + 2*x >= 4``. This is the "standard form" of + a minimization. + + In the nonnegative quadrant, this inequality describes a area above + a triangle with vertices at (0, 4), (0, 0) and (2, 0). The minimum + of ``f`` occurs at (2, 0). Define A, B, C, D for the standard + minimization: + + >>> A = Matrix([[2, 1]]) + >>> B = Matrix([4]) + >>> C = Matrix([[1, 1]]) + >>> D = Matrix([-1]) + + Confirm that this is the system of interest: + + >>> from sympy.abc import x, y + >>> X = Matrix([x, y]) + >>> (C*X - D)[0] + x + y + 1 + >>> [i >= j for i, j in zip(A*X, B)] + [2*x + y >= 4] + + Since `_simplex` will do a minimization for constraints given as + ``A*x <= B``, the signs of ``A`` and ``B`` must be negated since + the currently correspond to a greater-than inequality: + + >>> _simplex(-A, -B, C, D) + (3, [2, 0], [1/2]) + + The dual of minimizing ``f`` is maximizing ``F = c*y - d`` for + ``a*y <= b`` where ``a``, ``b``, ``c``, ``d`` are derived from the + transpose of the matrix representation of the standard minimization: + + >>> tr = lambda a, b, c, d: [i.T for i in (a, c, b, d)] + >>> a, b, c, d = tr(A, B, C, D) + + This time ``a*x <= b`` is the expected inequality for the `_simplex` + method, but to maximize ``F``, the sign of ``c`` and ``d`` must be + changed (so that minimizing the negative will give the negative of + the maximum of ``F``): + + >>> _simplex(a, b, -c, -d) + (-3, [1/2], [2, 0]) + + The negative of ``F`` and the min of ``f`` are the same. The dual + point `[1/2]` is the value of ``y`` that minimized ``F = c*y - d`` + under constraints a*x <= b``: + + >>> y = Matrix(['y']) + >>> (c*y - d)[0] + 4*y + 1 + >>> [i <= j for i, j in zip(a*y,b)] + [2*y <= 1, y <= 1] + + In this 1-dimensional dual system, the more restrictive constraint is + the first which limits ``y`` between 0 and 1/2 and the maximum of + ``F`` is attained at the nonzero value, hence is ``4*(1/2) + 1 = 3``. + + In this case the values for ``x`` and ``y`` were the same when the + dual representation was solved. This is not always the case (though + the value of the function will be the same). + + >>> l = [[1, 1], [-1, 1], [0, 1], [-1, 0]], [5, 1, 2, -1], [[1, 1]], [-1] + >>> A, B, C, D = [Matrix(i) for i in l] + >>> _simplex(A, B, -C, -D) + (-6, [3, 2], [1, 0, 0, 0]) + >>> _simplex(A, B, -C, -D, dual=True) # [5, 0] != [3, 2] + (-6, [1, 0, 0, 0], [5, 0]) + + In both cases the function has the same value: + + >>> Matrix(C)*Matrix([3, 2]) == Matrix(C)*Matrix([5, 0]) + True + + See Also + ======== + _lp - poses min/max problem in form compatible with _simplex + lpmin - minimization which calls _lp + lpmax - maximimzation which calls _lp + + References + ========== + + .. [1] Thomas S. Ferguson, LINEAR PROGRAMMING: A Concise Introduction + web.tecnico.ulisboa.pt/mcasquilho/acad/or/ftp/FergusonUCLA_lp.pdf + + """ + A, B, C, D = [Matrix(i) for i in (A, B, C, D or [0])] + if dual: + _o, d, p = _simplex(-A.T, C.T, B.T, -D) + return -_o, d, p + + if A and B: + M = Matrix([[A, B], [C, D]]) + else: + if A or B: + raise ValueError("must give A and B") + # no constraints given + M = Matrix([[C, D]]) + n = M.cols - 1 + m = M.rows - 1 + + if not all(i.is_Float or i.is_Rational for i in M): + # with literal Float and Rational we are guaranteed the + # ability of determining whether an expression is 0 or not + raise TypeError(filldedent(""" + Only rationals and floats are allowed. + """ + ) + ) + + # x variables have priority over y variables during Bland's rule + # since False < True + X = [(False, j) for j in range(n)] + Y = [(True, i) for i in range(m)] + + # Phase 1: find a feasible solution or determine none exist + + ## keep track of last pivot row and column + last = None + + while True: + B = M[:-1, -1] + A = M[:-1, :-1] + if all(B[i] >= 0 for i in range(B.rows)): + # We have found a feasible solution + break + + # Find k: first row with a negative rightmost entry + for k in range(B.rows): + if B[k] < 0: + break # use current value of k below + else: + pass # error will raise below + + # Choose pivot column, c + piv_cols = [_ for _ in range(A.cols) if A[k, _] < 0] + if not piv_cols: + raise InfeasibleLPError(filldedent(""" + The constraint set is empty!""")) + _, c = min((X[i], i) for i in piv_cols) # Bland's rule + + # Choose pivot row, r + piv_rows = [_ for _ in range(A.rows) if A[_, c] > 0 and B[_] > 0] + piv_rows.append(k) + r = _choose_pivot_row(A, B, piv_rows, c, Y) + + # check for oscillation + if (r, c) == last: + # Not sure what to do here; it looks like there will be + # oscillations; see o1 test added at this commit to + # see a system with no solution and the o2 for one + # with a solution. In the case of o2, the solution + # from linprog is the same as the one from lpmin, but + # the matrices created in the lpmin case are different + # than those created without replacements in linprog and + # the matrices in the linprog case lead to oscillations. + # If the matrices could be re-written in linprog like + # lpmin does, this behavior could be avoided and then + # perhaps the oscillating case would only occur when + # there is no solution. For now, the output is checked + # before exit if oscillations were detected and an + # error is raised there if the solution was invalid. + # + # cf section 6 of Ferguson for a non-cycling modification + last = True + break + last = r, c + + M = _pivot(M, r, c) + X[c], Y[r] = Y[r], X[c] + + # Phase 2: from a feasible solution, pivot to optimal + while True: + B = M[:-1, -1] + A = M[:-1, :-1] + C = M[-1, :-1] + + # Choose a pivot column, c + piv_cols = [_ for _ in range(n) if C[_] < 0] + if not piv_cols: + break + _, c = min((X[i], i) for i in piv_cols) # Bland's rule + + # Choose a pivot row, r + piv_rows = [_ for _ in range(m) if A[_, c] > 0] + if not piv_rows: + raise UnboundedLPError(filldedent(""" + Objective function can assume + arbitrarily large values!""")) + r = _choose_pivot_row(A, B, piv_rows, c, Y) + + M = _pivot(M, r, c) + X[c], Y[r] = Y[r], X[c] + + argmax = [None] * n + argmin_dual = [None] * m + + for i, (v, n) in enumerate(X): + if v == False: + argmax[n] = 0 + else: + argmin_dual[n] = M[-1, i] + + for i, (v, n) in enumerate(Y): + if v == True: + argmin_dual[n] = 0 + else: + argmax[n] = M[i, -1] + + if last and not all(i >= 0 for i in argmax + argmin_dual): + raise InfeasibleLPError(filldedent(""" + Oscillating system led to invalid solution. + If you believe there was a valid solution, please + report this as a bug.""")) + return -M[-1, -1], argmax, argmin_dual + + +## routines that use _simplex or support those that do + + +def _abcd(M, list=False): + """return parts of M as matrices or lists + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.solvers.simplex import _abcd + + >>> m = Matrix(3, 3, range(9)); m + Matrix([ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> a, b, c, d = _abcd(m) + >>> a + Matrix([ + [0, 1], + [3, 4]]) + >>> b + Matrix([ + [2], + [5]]) + >>> c + Matrix([[6, 7]]) + >>> d + Matrix([[8]]) + + The matrices can be returned as compact lists, too: + + >>> L = a, b, c, d = _abcd(m, list=True); L + ([[0, 1], [3, 4]], [2, 5], [[6, 7]], [8]) + """ + + def aslist(i): + l = i.tolist() + if len(l[0]) == 1: # col vector + return [i[0] for i in l] + return l + + m = M[:-1, :-1], M[:-1, -1], M[-1, :-1], M[-1:, -1:] + if not list: + return m + return tuple([aslist(i) for i in m]) + + +def _m(a, b, c, d=None): + """return Matrix([[a, b], [c, d]]) from matrices + in Matrix or list form. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.solvers.simplex import _abcd, _m + >>> m = Matrix(3, 3, range(9)) + >>> L = _abcd(m, list=True); L + ([[0, 1], [3, 4]], [2, 5], [[6, 7]], [8]) + >>> _abcd(m) + (Matrix([ + [0, 1], + [3, 4]]), Matrix([ + [2], + [5]]), Matrix([[6, 7]]), Matrix([[8]])) + >>> assert m == _m(*L) == _m(*_) + """ + a, b, c, d = [Matrix(i) for i in (a, b, c, d or [0])] + return Matrix([[a, b], [c, d]]) + + +def _primal_dual(M, factor=True): + """return primal and dual function and constraints + assuming that ``M = Matrix([[A, b], [c, d]])`` and the + function ``c*x - d`` is being minimized with ``Ax >= b`` + for nonnegative values of ``x``. The dual and its + constraints will be for maximizing `b.T*y - d` subject + to ``A.T*y <= c.T``. + + Examples + ======== + + >>> from sympy.solvers.simplex import _primal_dual, lpmin, lpmax + >>> from sympy import Matrix + + The following matrix represents the primal task of + minimizing x + y + 7 for y >= x + 1 and y >= -2*x + 3. + The dual task seeks to maximize x + 3*y + 7 with + 2*y - x <= 1 and and x + y <= 1: + + >>> M = Matrix([ + ... [-1, 1, 1], + ... [ 2, 1, 3], + ... [ 1, 1, -7]]) + >>> p, d = _primal_dual(M) + + The minimum of the primal and maximum of the dual are the same + (though they occur at different points): + + >>> lpmin(*p) + (28/3, {x1: 2/3, x2: 5/3}) + >>> lpmax(*d) + (28/3, {y1: 1/3, y2: 2/3}) + + If the equivalent (but canonical) inequalities are + desired, leave `factor=True`, otherwise the unmodified + inequalities for M will be returned. + + >>> m = Matrix([ + ... [-3, -2, 4, -2], + ... [ 2, 0, 0, -2], + ... [ 0, 1, -3, 0]]) + + >>> _primal_dual(m, False) # last condition is 2*x1 >= -2 + ((x2 - 3*x3, + [-3*x1 - 2*x2 + 4*x3 >= -2, 2*x1 >= -2]), + (-2*y1 - 2*y2, + [-3*y1 + 2*y2 <= 0, -2*y1 <= 1, 4*y1 <= -3])) + + >>> _primal_dual(m) # condition now x1 >= -1 + ((x2 - 3*x3, + [-3*x1 - 2*x2 + 4*x3 >= -2, x1 >= -1]), + (-2*y1 - 2*y2, + [-3*y1 + 2*y2 <= 0, -2*y1 <= 1, 4*y1 <= -3])) + + If you pass the transpose of the matrix, the primal will be + identified as the standard minimization problem and the + dual as the standard maximization: + + >>> _primal_dual(m.T) + ((-2*x1 - 2*x2, + [-3*x1 + 2*x2 >= 0, -2*x1 >= 1, 4*x1 >= -3]), + (y2 - 3*y3, + [-3*y1 - 2*y2 + 4*y3 <= -2, y1 <= -1])) + + A matrix must have some size or else None will be returned for + the functions: + + >>> _primal_dual(Matrix([[1, 2]])) + ((x1 - 2, []), (-2, [])) + + >>> _primal_dual(Matrix([])) + ((None, []), (None, [])) + + References + ========== + + .. [1] David Galvin, Relations between Primal and Dual + www3.nd.edu/~dgalvin1/30210/30210_F07/presentations/dual_opt.pdf + """ + if not M: + return (None, []), (None, []) + if not hasattr(M, "shape"): + if len(M) not in (3, 4): + raise ValueError("expecting Matrix or 3 or 4 lists") + M = _m(*M) + m, n = [i - 1 for i in M.shape] + A, b, c, d = _abcd(M) + d = d[0] + _ = lambda x: numbered_symbols(x, start=1) + x = Matrix([i for i, j in zip(_("x"), range(n))]) + yT = Matrix([i for i, j in zip(_("y"), range(m))]).T + + def ineq(L, r, op): + rv = [] + for r in (op(i, j) for i, j in zip(L, r)): + if r == True: + continue + elif r == False: + return [False] + if factor: + f = factor_terms(r) + if f.lhs.is_Mul and f.rhs % f.lhs.args[0] == 0: + assert len(f.lhs.args) == 2, f.lhs + k = f.lhs.args[0] + r = r.func(sign(k) * f.lhs.args[1], f.rhs // abs(k)) + rv.append(r) + return rv + + eq = lambda x, d: x[0] - d if x else -d + F = eq(c * x, d) + f = eq(yT * b, d) + return (F, ineq(A * x, b, Ge)), (f, ineq(yT * A, c, Le)) + + +def _rel_as_nonpos(constr, syms): + """return `(np, d, aux)` where `np` is a list of nonpositive + expressions that represent the given constraints (possibly + rewritten in terms of auxilliary variables) expressible with + nonnegative symbols, and `d` is a dictionary mapping a given + symbols to an expression with an auxilliary variable. In some + cases a symbol will be used as part of the change of variables, + e.g. x: x - z1 instead of x: z1 - z2. + + If any constraint is False/empty, return None. All variables in + ``constr`` are assumed to be unbounded unless explicitly indicated + otherwise with a univariate constraint, e.g. ``x >= 0`` will + restrict ``x`` to nonnegative values. + + The ``syms`` must be included so all symbols can be given an + unbounded assumption if they are not otherwise bound with + univariate conditions like ``x <= 3``. + + Examples + ======== + + >>> from sympy.solvers.simplex import _rel_as_nonpos + >>> from sympy.abc import x, y + >>> _rel_as_nonpos([x >= y, x >= 0, y >= 0], (x, y)) + ([-x + y], {}, []) + >>> _rel_as_nonpos([x >= 3, x <= 5], [x]) + ([_z1 - 2], {x: _z1 + 3}, [_z1]) + >>> _rel_as_nonpos([x <= 5], [x]) + ([], {x: 5 - _z1}, [_z1]) + >>> _rel_as_nonpos([x >= 1], [x]) + ([], {x: _z1 + 1}, [_z1]) + """ + r = {} # replacements to handle change of variables + np = [] # nonpositive expressions + aux = [] # auxilliary symbols added + ui = numbered_symbols("z", start=1, cls=Dummy) # auxilliary symbols + univariate = {} # {x: interval} for univariate constraints + unbound = [] # symbols designated as unbound + syms = set(syms) # the expected syms of the system + + # separate out univariates + for i in constr: + if i == True: + continue # ignore + if i == False: + return # no solution + if i.has(S.Infinity, S.NegativeInfinity): + raise ValueError("only finite bounds are permitted") + if isinstance(i, (Le, Ge)): + i = i.lts - i.gts + freei = i.free_symbols + if freei - syms: + raise ValueError( + "unexpected symbol(s) in constraint: %s" % (freei - syms) + ) + if len(freei) > 1: + np.append(i) + elif freei: + x = freei.pop() + if x in unbound: + continue # will handle later + ivl = Le(i, 0, evaluate=False).as_set() + if x not in univariate: + univariate[x] = ivl + else: + univariate[x] &= ivl + elif i: + return False + else: + raise TypeError(filldedent(""" + only equalities like Eq(x, y) or non-strict + inequalities like x >= y are allowed in lp, not %s""" % i)) + + # introduce auxilliary variables as needed for univariate + # inequalities + for x in syms: + i = univariate.get(x, True) + if not i: + return None # no solution possible + if i == True: + unbound.append(x) + continue + a, b = i.inf, i.sup + if a.is_infinite: + u = next(ui) + r[x] = b - u + aux.append(u) + elif b.is_infinite: + if a: + u = next(ui) + r[x] = a + u + aux.append(u) + else: + # standard nonnegative relationship + pass + else: + u = next(ui) + aux.append(u) + # shift so u = x - a => x = u + a + r[x] = u + a + # add constraint for u <= b - a + # since when u = b-a then x = u + a = b - a + a = b: + # the upper limit for x + np.append(u - (b - a)) + + # make change of variables for unbound variables + for x in unbound: + u = next(ui) + r[x] = u - x # reusing x + aux.append(u) + + return np, r, aux + + +def _lp_matrices(objective, constraints): + """return A, B, C, D, r, x+X, X for maximizing + objective = Cx - D with constraints Ax <= B, introducing + introducing auxilliary variables, X, as necessary to make + replacements of symbols as given in r, {xi: expression with Xj}, + so all variables in x+X will take on nonnegative values. + + Every univariate condition creates a semi-infinite + condition, e.g. a single ``x <= 3`` creates the + interval ``[-oo, 3]`` while ``x <= 3`` and ``x >= 2`` + create an interval ``[2, 3]``. Variables not in a univariate + expression will take on nonnegative values. + """ + + # sympify input and collect free symbols + F = sympify(objective) + np = [sympify(i) for i in constraints] + syms = set.union(*[i.free_symbols for i in [F] + np], set()) + + # change Eq(x, y) to x - y <= 0 and y - x <= 0 + for i in range(len(np)): + if isinstance(np[i], Eq): + np[i] = np[i].lhs - np[i].rhs <= 0 + np.append(-np[i].lhs <= 0) + + # convert constraints to nonpositive expressions + _ = _rel_as_nonpos(np, syms) + if _ is None: + raise InfeasibleLPError(filldedent(""" + Inconsistent/False constraint""")) + np, r, aux = _ + + # do change of variables + F = F.xreplace(r) + np = [i.xreplace(r) for i in np] + + # convert to matrices + xx = list(ordered(syms)) + aux + A, B = linear_eq_to_matrix(np, xx) + C, D = linear_eq_to_matrix([F], xx) + return A, B, C, D, r, xx, aux + + +def _lp(min_max, f, constr): + """Return the optimization (min or max) of ``f`` with the given + constraints. All variables are unbounded unless constrained. + + If `min_max` is 'max' then the results corresponding to the + maximization of ``f`` will be returned, else the minimization. + The constraints can be given as Le, Ge or Eq expressions. + + Examples + ======== + + >>> from sympy.solvers.simplex import _lp as lp + >>> from sympy import Eq + >>> from sympy.abc import x, y, z + >>> f = x + y - 2*z + >>> c = [7*x + 4*y - 7*z <= 3, 3*x - y + 10*z <= 6] + >>> c += [i >= 0 for i in (x, y, z)] + >>> lp(min, f, c) + (-6/5, {x: 0, y: 0, z: 3/5}) + + By passing max, the maximum value for f under the constraints + is returned (if possible): + + >>> lp(max, f, c) + (3/4, {x: 0, y: 3/4, z: 0}) + + Constraints that are equalities will require that the solution + also satisfy them: + + >>> lp(max, f, c + [Eq(y - 9*x, 1)]) + (5/7, {x: 0, y: 1, z: 1/7}) + + All symbols are reported, even if they are not in the objective + function: + + >>> lp(min, x, [y + x >= 3, x >= 0]) + (0, {x: 0, y: 3}) + """ + # get the matrix components for the system expressed + # in terms of only nonnegative variables + A, B, C, D, r, xx, aux = _lp_matrices(f, constr) + + how = str(min_max).lower() + if "max" in how: + # _simplex minimizes for Ax <= B so we + # have to change the sign of the function + # and negate the optimal value returned + _o, p, d = _simplex(A, B, -C, -D) + o = -_o + elif "min" in how: + o, p, d = _simplex(A, B, C, D) + else: + raise ValueError("expecting min or max") + + # restore original variables and remove aux from p + p = dict(zip(xx, p)) + if r: # p has original symbols and auxilliary symbols + # if r has x: x - z1 use values from p to update + r = {k: v.xreplace(p) for k, v in r.items()} + # then use the actual value of x (= x - z1) in p + p.update(r) + # don't show aux + p = {k: p[k] for k in ordered(p) if k not in aux} + + # not returning dual since there may be extra constraints + # when a variable has finite bounds + return o, p + + +def lpmin(f, constr): + """return minimum of linear equation ``f`` under + linear constraints expressed using Ge, Le or Eq. + + All variables are unbounded unless constrained. + + Examples + ======== + + >>> from sympy.solvers.simplex import lpmin + >>> from sympy import Eq + >>> from sympy.abc import x, y + >>> lpmin(x, [2*x - 3*y >= -1, Eq(x + 3*y, 2), x <= 2*y]) + (1/3, {x: 1/3, y: 5/9}) + + Negative values for variables are permitted unless explicitly + excluding, so minimizing ``x`` for ``x <= 3`` is an + unbounded problem while the following has a bounded solution: + + >>> lpmin(x, [x >= 0, x <= 3]) + (0, {x: 0}) + + Without indicating that ``x`` is nonnegative, there + is no minimum for this objective: + + >>> lpmin(x, [x <= 3]) + Traceback (most recent call last): + ... + sympy.solvers.simplex.UnboundedLPError: + Objective function can assume arbitrarily large values! + + See Also + ======== + linprog, lpmax + """ + return _lp(min, f, constr) + + +def lpmax(f, constr): + """return maximum of linear equation ``f`` under + linear constraints expressed using Ge, Le or Eq. + + All variables are unbounded unless constrained. + + Examples + ======== + + >>> from sympy.solvers.simplex import lpmax + >>> from sympy import Eq + >>> from sympy.abc import x, y + >>> lpmax(x, [2*x - 3*y >= -1, Eq(x+ 3*y,2), x <= 2*y]) + (4/5, {x: 4/5, y: 2/5}) + + Negative values for variables are permitted unless explicitly + excluding: + + >>> lpmax(x, [x <= -1]) + (-1, {x: -1}) + + If a non-negative constraint is added for x, there is no + possible solution: + + >>> lpmax(x, [x <= -1, x >= 0]) + Traceback (most recent call last): + ... + sympy.solvers.simplex.InfeasibleLPError: inconsistent/False constraint + + See Also + ======== + linprog, lpmin + """ + return _lp(max, f, constr) + + +def _handle_bounds(bounds): + # introduce auxiliary variables as needed for univariate + # inequalities + + def _make_list(length: int, index_value_pairs): + li = [0] * length + for idx, val in index_value_pairs: + li[idx] = val + return li + + unbound = [] + row = [] + row2 = [] + b_len = len(bounds) + for x, (a, b) in enumerate(bounds): + if a is None and b is None: + unbound.append(x) + elif a is None: + # r[x] = b - u + b_len += 1 + row.append(_make_list(b_len, [(x, 1), (-1, 1)])) + row.append(_make_list(b_len, [(x, -1), (-1, -1)])) + row2.extend([[b], [-b]]) + elif b is None: + if a: + # r[x] = a + u + b_len += 1 + row.append(_make_list(b_len, [(x, 1), (-1, -1)])) + row.append(_make_list(b_len, [(x, -1), (-1, 1)])) + row2.extend([[a], [-a]]) + else: + # standard nonnegative relationship + pass + else: + # r[x] = u + a + b_len += 1 + row.append(_make_list(b_len, [(x, 1), (-1, -1)])) + row.append(_make_list(b_len, [(x, -1), (-1, 1)])) + # u <= b - a + row.append(_make_list(b_len, [(-1, 1)])) + row2.extend([[a], [-a], [b - a]]) + + # make change of variables for unbound variables + for x in unbound: + # r[x] = u - v + b_len += 2 + row.append(_make_list(b_len, [(x, 1), (-1, 1), (-2, -1)])) + row.append(_make_list(b_len, [(x, -1), (-1, -1), (-2, 1)])) + row2.extend([[0], [0]]) + + return Matrix([r + [0]*(b_len - len(r)) for r in row]), Matrix(row2) + + +def linprog(c, A=None, b=None, A_eq=None, b_eq=None, bounds=None): + """Return the minimization of ``c*x`` with the given + constraints ``A*x <= b`` and ``A_eq*x = b_eq``. Unless bounds + are given, variables will have nonnegative values in the solution. + + If ``A`` is not given, then the dimension of the system will + be determined by the length of ``C``. + + By default, all variables will be nonnegative. If ``bounds`` + is given as a single tuple, ``(lo, hi)``, then all variables + will be constrained to be between ``lo`` and ``hi``. Use + None for a ``lo`` or ``hi`` if it is unconstrained in the + negative or positive direction, respectively, e.g. + ``(None, 0)`` indicates nonpositive values. To set + individual ranges, pass a list with length equal to the + number of columns in ``A``, each element being a tuple; if + only a few variables take on non-default values they can be + passed as a dictionary with keys giving the corresponding + column to which the variable is assigned, e.g. ``bounds={2: + (1, 4)}`` would limit the 3rd variable to have a value in + range ``[1, 4]``. + + Examples + ======== + + >>> from sympy.solvers.simplex import linprog + >>> from sympy import symbols, Eq, linear_eq_to_matrix as M, Matrix + >>> x = x1, x2, x3, x4 = symbols('x1:5') + >>> X = Matrix(x) + >>> c, d = M(5*x2 + x3 + 4*x4 - x1, x) + >>> a, b = M([5*x2 + 2*x3 + 5*x4 - (x1 + 5)], x) + >>> aeq, beq = M([Eq(3*x2 + x4, 2), Eq(-x1 + x3 + 2*x4, 1)], x) + >>> constr = [i <= j for i,j in zip(a*X, b)] + >>> constr += [Eq(i, j) for i,j in zip(aeq*X, beq)] + >>> linprog(c, a, b, aeq, beq) + (9/2, [0, 1/2, 0, 1/2]) + >>> assert all(i.subs(dict(zip(x, _[1]))) for i in constr) + + See Also + ======== + lpmin, lpmax + """ + + ## the objective + C = Matrix(c) + if C.rows != 1 and C.cols == 1: + C = C.T + if C.rows != 1: + raise ValueError("C must be a single row.") + + ## the inequalities + if not A: + if b: + raise ValueError("A and b must both be given") + # the governing equations will be simple constraints + # on variables + A, b = zeros(0, C.cols), zeros(C.cols, 1) + else: + A, b = [Matrix(i) for i in (A, b)] + + if A.cols != C.cols: + raise ValueError("number of columns in A and C must match") + + ## the equalities + if A_eq is None: + if not b_eq is None: + raise ValueError("A_eq and b_eq must both be given") + else: + A_eq, b_eq = [Matrix(i) for i in (A_eq, b_eq)] + # if x == y then x <= y and x >= y (-x <= -y) + A = A.col_join(A_eq) + A = A.col_join(-A_eq) + b = b.col_join(b_eq) + b = b.col_join(-b_eq) + + if not (bounds is None or bounds == {} or bounds == (0, None)): + ## the bounds are interpreted + if type(bounds) is tuple and len(bounds) == 2: + bounds = [bounds] * A.cols + elif len(bounds) == A.cols and all( + type(i) is tuple and len(i) == 2 for i in bounds): + pass # individual bounds + elif type(bounds) is dict and all( + type(i) is tuple and len(i) == 2 + for i in bounds.values()): + # sparse bounds + db = bounds + bounds = [(0, None)] * A.cols + while db: + i, j = db.popitem() + bounds[i] = j # IndexError if out-of-bounds indices + else: + raise ValueError("unexpected bounds %s" % bounds) + A_, b_ = _handle_bounds(bounds) + aux = A_.cols - A.cols + if A: + A = Matrix([[A, zeros(A.rows, aux)], [A_]]) + b = b.col_join(b_) + else: + A = A_ + b = b_ + C = C.row_join(zeros(1, aux)) + else: + aux = -A.cols # set so -aux will give all cols below + + o, p, d = _simplex(A, b, C) + return o, p[:-aux] # don't include aux values + +def show_linprog(c, A=None, b=None, A_eq=None, b_eq=None, bounds=None): + from sympy import symbols + ## the objective + C = Matrix(c) + if C.rows != 1 and C.cols == 1: + C = C.T + if C.rows != 1: + raise ValueError("C must be a single row.") + + ## the inequalities + if not A: + if b: + raise ValueError("A and b must both be given") + # the governing equations will be simple constraints + # on variables + A, b = zeros(0, C.cols), zeros(C.cols, 1) + else: + A, b = [Matrix(i) for i in (A, b)] + + if A.cols != C.cols: + raise ValueError("number of columns in A and C must match") + + ## the equalities + if A_eq is None: + if not b_eq is None: + raise ValueError("A_eq and b_eq must both be given") + else: + A_eq, b_eq = [Matrix(i) for i in (A_eq, b_eq)] + + if not (bounds is None or bounds == {} or bounds == (0, None)): + ## the bounds are interpreted + if type(bounds) is tuple and len(bounds) == 2: + bounds = [bounds] * A.cols + elif len(bounds) == A.cols and all( + type(i) is tuple and len(i) == 2 for i in bounds): + pass # individual bounds + elif type(bounds) is dict and all( + type(i) is tuple and len(i) == 2 + for i in bounds.values()): + # sparse bounds + db = bounds + bounds = [(0, None)] * A.cols + while db: + i, j = db.popitem() + bounds[i] = j # IndexError if out-of-bounds indices + else: + raise ValueError("unexpected bounds %s" % bounds) + + x = Matrix(symbols('x1:%s' % (A.cols+1))) + f,c = (C*x)[0], [i<=j for i,j in zip(A*x, b)] + [Eq(i,j) for i,j in zip(A_eq*x,b_eq)] + for i, (lo, hi) in enumerate(bounds): + if lo is not None: + c.append(x[i]>=lo) + if hi is not None: + c.append(x[i]<=hi) + return f,c diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/solvers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/solvers.py new file mode 100644 index 0000000000000000000000000000000000000000..ef621a84e34bde43a3181d2fd90e26fa7b05e968 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/solvers.py @@ -0,0 +1,3674 @@ +""" +This module contain solvers for all kinds of equations: + + - algebraic or transcendental, use solve() + + - recurrence, use rsolve() + + - differential, use dsolve() + + - nonlinear (numerically), use nsolve() + (you will need a good starting point) + +""" +from __future__ import annotations + +from sympy.core import (S, Add, Symbol, Dummy, Expr, Mul) +from sympy.core.assumptions import check_assumptions +from sympy.core.exprtools import factor_terms +from sympy.core.function import (expand_mul, expand_log, Derivative, + AppliedUndef, UndefinedFunction, nfloat, + Function, expand_power_exp, _mexpand, expand, + expand_func) +from sympy.core.logic import fuzzy_not, fuzzy_and +from sympy.core.numbers import Float, Rational, _illegal +from sympy.core.intfunc import integer_log, ilcm +from sympy.core.power import Pow +from sympy.core.relational import Eq, Ne +from sympy.core.sorting import ordered, default_sort_key +from sympy.core.sympify import sympify, _sympify +from sympy.core.traversal import preorder_traversal +from sympy.logic.boolalg import And, BooleanAtom + +from sympy.functions import (log, exp, LambertW, cos, sin, tan, acos, asin, atan, + Abs, re, im, arg, sqrt, atan2) +from sympy.functions.combinatorial.factorials import binomial +from sympy.functions.elementary.hyperbolic import HyperbolicFunction +from sympy.functions.elementary.piecewise import piecewise_fold, Piecewise +from sympy.functions.elementary.trigonometric import TrigonometricFunction +from sympy.integrals.integrals import Integral +from sympy.ntheory.factor_ import divisors +from sympy.simplify import (simplify, collect, powsimp, posify, # type: ignore + powdenest, nsimplify, denom, logcombine, sqrtdenest, fraction, + separatevars) +from sympy.simplify.sqrtdenest import sqrt_depth +from sympy.simplify.fu import TR1, TR2i, TR10, TR11 +from sympy.strategies.rl import rebuild +from sympy.matrices.exceptions import NonInvertibleMatrixError +from sympy.matrices import Matrix, zeros +from sympy.polys import roots, cancel, factor, Poly +from sympy.polys.solvers import sympy_eqs_to_ring, solve_lin_sys +from sympy.polys.polyerrors import GeneratorsNeeded, PolynomialError +from sympy.polys.polytools import gcd +from sympy.utilities.lambdify import lambdify +from sympy.utilities.misc import filldedent, debugf +from sympy.utilities.iterables import (connected_components, + generate_bell, uniq, iterable, is_sequence, subsets, flatten, sift) +from sympy.utilities.decorator import conserve_mpmath_dps + +from mpmath import findroot + +from sympy.solvers.polysys import solve_poly_system + +from types import GeneratorType +from collections import defaultdict +from itertools import combinations, product + +import warnings + + +def recast_to_symbols(eqs, symbols): + """ + Return (e, s, d) where e and s are versions of *eqs* and + *symbols* in which any non-Symbol objects in *symbols* have + been replaced with generic Dummy symbols and d is a dictionary + that can be used to restore the original expressions. + + Examples + ======== + + >>> from sympy.solvers.solvers import recast_to_symbols + >>> from sympy import symbols, Function + >>> x, y = symbols('x y') + >>> fx = Function('f')(x) + >>> eqs, syms = [fx + 1, x, y], [fx, y] + >>> e, s, d = recast_to_symbols(eqs, syms); (e, s, d) + ([_X0 + 1, x, y], [_X0, y], {_X0: f(x)}) + + The original equations and symbols can be restored using d: + + >>> assert [i.xreplace(d) for i in eqs] == eqs + >>> assert [d.get(i, i) for i in s] == syms + + """ + if not iterable(eqs) and iterable(symbols): + raise ValueError('Both eqs and symbols must be iterable') + orig = list(symbols) + symbols = list(ordered(symbols)) + swap_sym = {} + i = 0 + for s in symbols: + if not isinstance(s, Symbol) and s not in swap_sym: + swap_sym[s] = Dummy('X%d' % i) + i += 1 + new_f = [] + for i in eqs: + isubs = getattr(i, 'subs', None) + if isubs is not None: + new_f.append(isubs(swap_sym)) + else: + new_f.append(i) + restore = {v: k for k, v in swap_sym.items()} + return new_f, [swap_sym.get(i, i) for i in orig], restore + + +def _ispow(e): + """Return True if e is a Pow or is exp.""" + return isinstance(e, Expr) and (e.is_Pow or isinstance(e, exp)) + + +def _simple_dens(f, symbols): + # when checking if a denominator is zero, we can just check the + # base of powers with nonzero exponents since if the base is zero + # the power will be zero, too. To keep it simple and fast, we + # limit simplification to exponents that are Numbers + dens = set() + for d in denoms(f, symbols): + if d.is_Pow and d.exp.is_Number: + if d.exp.is_zero: + continue # foo**0 is never 0 + d = d.base + dens.add(d) + return dens + + +def denoms(eq, *symbols): + """ + Return (recursively) set of all denominators that appear in *eq* + that contain any symbol in *symbols*; if *symbols* are not + provided then all denominators will be returned. + + Examples + ======== + + >>> from sympy.solvers.solvers import denoms + >>> from sympy.abc import x, y, z + + >>> denoms(x/y) + {y} + + >>> denoms(x/(y*z)) + {y, z} + + >>> denoms(3/x + y/z) + {x, z} + + >>> denoms(x/2 + y/z) + {2, z} + + If *symbols* are provided then only denominators containing + those symbols will be returned: + + >>> denoms(1/x + 1/y + 1/z, y, z) + {y, z} + + """ + + pot = preorder_traversal(eq) + dens = set() + for p in pot: + # Here p might be Tuple or Relational + # Expr subtrees (e.g. lhs and rhs) will be traversed after by pot + if not isinstance(p, Expr): + continue + den = denom(p) + if den is S.One: + continue + dens.update(Mul.make_args(den)) + if not symbols: + return dens + elif len(symbols) == 1: + if iterable(symbols[0]): + symbols = symbols[0] + return {d for d in dens if any(s in d.free_symbols for s in symbols)} + + +def checksol(f, symbol, sol=None, **flags): + """ + Checks whether sol is a solution of equation f == 0. + + Explanation + =========== + + Input can be either a single symbol and corresponding value + or a dictionary of symbols and values. When given as a dictionary + and flag ``simplify=True``, the values in the dictionary will be + simplified. *f* can be a single equation or an iterable of equations. + A solution must satisfy all equations in *f* to be considered valid; + if a solution does not satisfy any equation, False is returned; if one or + more checks are inconclusive (and none are False) then None is returned. + + Examples + ======== + + >>> from sympy import checksol, symbols + >>> x, y = symbols('x,y') + >>> checksol(x**4 - 1, x, 1) + True + >>> checksol(x**4 - 1, x, 0) + False + >>> checksol(x**2 + y**2 - 5**2, {x: 3, y: 4}) + True + + To check if an expression is zero using ``checksol()``, pass it + as *f* and send an empty dictionary for *symbol*: + + >>> checksol(x**2 + x - x*(x + 1), {}) + True + + None is returned if ``checksol()`` could not conclude. + + flags: + 'numerical=True (default)' + do a fast numerical check if ``f`` has only one symbol. + 'minimal=True (default is False)' + a very fast, minimal testing. + 'warn=True (default is False)' + show a warning if checksol() could not conclude. + 'simplify=True (default)' + simplify solution before substituting into function and + simplify the function before trying specific simplifications + 'force=True (default is False)' + make positive all symbols without assumptions regarding sign. + + """ + from sympy.physics.units import Unit + + minimal = flags.get('minimal', False) + + if sol is not None: + sol = {symbol: sol} + elif isinstance(symbol, dict): + sol = symbol + else: + msg = 'Expecting (sym, val) or ({sym: val}, None) but got (%s, %s)' + raise ValueError(msg % (symbol, sol)) + + if iterable(f): + if not f: + raise ValueError('no functions to check') + return fuzzy_and(checksol(fi, sol, **flags) for fi in f) + + f = _sympify(f) + + if f.is_number: + return f.is_zero + + if isinstance(f, Poly): + f = f.as_expr() + elif isinstance(f, (Eq, Ne)): + if f.rhs in (S.true, S.false): + f = f.reversed + B, E = f.args + if isinstance(B, BooleanAtom): + f = f.subs(sol) + if not f.is_Boolean: + return + elif isinstance(f, Eq): + f = Add(f.lhs, -f.rhs, evaluate=False) + + if isinstance(f, BooleanAtom): + return bool(f) + elif not f.is_Relational and not f: + return True + + illegal = set(_illegal) + if any(sympify(v).atoms() & illegal for k, v in sol.items()): + return False + + attempt = -1 + numerical = flags.get('numerical', True) + while 1: + attempt += 1 + if attempt == 0: + val = f.subs(sol) + if isinstance(val, Mul): + val = val.as_independent(Unit)[0] + if val.atoms() & illegal: + return False + elif attempt == 1: + if not val.is_number: + if not val.is_constant(*list(sol.keys()), simplify=not minimal): + return False + # there are free symbols -- simple expansion might work + _, val = val.as_content_primitive() + val = _mexpand(val.as_numer_denom()[0], recursive=True) + elif attempt == 2: + if minimal: + return + if flags.get('simplify', True): + for k in sol: + sol[k] = simplify(sol[k]) + # start over without the failed expanded form, possibly + # with a simplified solution + val = simplify(f.subs(sol)) + if flags.get('force', True): + val, reps = posify(val) + # expansion may work now, so try again and check + exval = _mexpand(val, recursive=True) + if exval.is_number: + # we can decide now + val = exval + else: + # if there are no radicals and no functions then this can't be + # zero anymore -- can it? + pot = preorder_traversal(expand_mul(val)) + seen = set() + saw_pow_func = False + for p in pot: + if p in seen: + continue + seen.add(p) + if p.is_Pow and not p.exp.is_Integer: + saw_pow_func = True + elif p.is_Function: + saw_pow_func = True + elif isinstance(p, UndefinedFunction): + saw_pow_func = True + if saw_pow_func: + break + if saw_pow_func is False: + return False + if flags.get('force', True): + # don't do a zero check with the positive assumptions in place + val = val.subs(reps) + nz = fuzzy_not(val.is_zero) + if nz is not None: + # issue 5673: nz may be True even when False + # so these are just hacks to keep a false positive + # from being returned + + # HACK 1: LambertW (issue 5673) + if val.is_number and val.has(LambertW): + # don't eval this to verify solution since if we got here, + # numerical must be False + return None + + # add other HACKs here if necessary, otherwise we assume + # the nz value is correct + return not nz + break + if val.is_Rational: + return val == 0 + if numerical and val.is_number: + return (abs(val.n(18).n(12, chop=True)) < 1e-9) is S.true + + if flags.get('warn', False): + warnings.warn("\n\tWarning: could not verify solution %s." % sol) + # returns None if it can't conclude + # TODO: improve solution testing + + +def solve(f, *symbols, **flags): + r""" + Algebraically solves equations and systems of equations. + + Explanation + =========== + + Currently supported: + - polynomial + - transcendental + - piecewise combinations of the above + - systems of linear and polynomial equations + - systems containing relational expressions + - systems implied by undetermined coefficients + + Examples + ======== + + The default output varies according to the input and might + be a list (possibly empty), a dictionary, a list of + dictionaries or tuples, or an expression involving relationals. + For specifics regarding different forms of output that may appear, see :ref:`solve_output`. + Let it suffice here to say that to obtain a uniform output from + `solve` use ``dict=True`` or ``set=True`` (see below). + + >>> from sympy import solve, Poly, Eq, Matrix, Symbol + >>> from sympy.abc import x, y, z, a, b + + The expressions that are passed can be Expr, Equality, or Poly + classes (or lists of the same); a Matrix is considered to be a + list of all the elements of the matrix: + + >>> solve(x - 3, x) + [3] + >>> solve(Eq(x, 3), x) + [3] + >>> solve(Poly(x - 3), x) + [3] + >>> solve(Matrix([[x, x + y]]), x, y) == solve([x, x + y], x, y) + True + + If no symbols are indicated to be of interest and the equation is + univariate, a list of values is returned; otherwise, the keys in + a dictionary will indicate which (of all the variables used in + the expression(s)) variables and solutions were found: + + >>> solve(x**2 - 4) + [-2, 2] + >>> solve((x - a)*(y - b)) + [{a: x}, {b: y}] + >>> solve([x - 3, y - 1]) + {x: 3, y: 1} + >>> solve([x - 3, y**2 - 1]) + [{x: 3, y: -1}, {x: 3, y: 1}] + + If you pass symbols for which solutions are sought, the output will vary + depending on the number of symbols you passed, whether you are passing + a list of expressions or not, and whether a linear system was solved. + Uniform output is attained by using ``dict=True`` or ``set=True``. + + >>> #### *** feel free to skip to the stars below *** #### + >>> from sympy import TableForm + >>> h = [None, ';|;'.join(['e', 's', 'solve(e, s)', 'solve(e, s, dict=True)', + ... 'solve(e, s, set=True)']).split(';')] + >>> t = [] + >>> for e, s in [ + ... (x - y, y), + ... (x - y, [x, y]), + ... (x**2 - y, [x, y]), + ... ([x - 3, y -1], [x, y]), + ... ]: + ... how = [{}, dict(dict=True), dict(set=True)] + ... res = [solve(e, s, **f) for f in how] + ... t.append([e, '|', s, '|'] + [res[0], '|', res[1], '|', res[2]]) + ... + >>> # ******************************************************* # + >>> TableForm(t, headings=h, alignments="<") + e | s | solve(e, s) | solve(e, s, dict=True) | solve(e, s, set=True) + --------------------------------------------------------------------------------------- + x - y | y | [x] | [{y: x}] | ([y], {(x,)}) + x - y | [x, y] | [(y, y)] | [{x: y}] | ([x, y], {(y, y)}) + x**2 - y | [x, y] | [(x, x**2)] | [{y: x**2}] | ([x, y], {(x, x**2)}) + [x - 3, y - 1] | [x, y] | {x: 3, y: 1} | [{x: 3, y: 1}] | ([x, y], {(3, 1)}) + + * If any equation does not depend on the symbol(s) given, it will be + eliminated from the equation set and an answer may be given + implicitly in terms of variables that were not of interest: + + >>> solve([x - y, y - 3], x) + {x: y} + + When you pass all but one of the free symbols, an attempt + is made to find a single solution based on the method of + undetermined coefficients. If it succeeds, a dictionary of values + is returned. If you want an algebraic solutions for one + or more of the symbols, pass the expression to be solved in a list: + + >>> e = a*x + b - 2*x - 3 + >>> solve(e, [a, b]) + {a: 2, b: 3} + >>> solve([e], [a, b]) + {a: -b/x + (2*x + 3)/x} + + When there is no solution for any given symbol which will make all + expressions zero, the empty list is returned (or an empty set in + the tuple when ``set=True``): + + >>> from sympy import sqrt + >>> solve(3, x) + [] + >>> solve(x - 3, y) + [] + >>> solve(sqrt(x) + 1, x, set=True) + ([x], set()) + + When an object other than a Symbol is given as a symbol, it is + isolated algebraically and an implicit solution may be obtained. + This is mostly provided as a convenience to save you from replacing + the object with a Symbol and solving for that Symbol. It will only + work if the specified object can be replaced with a Symbol using the + subs method: + + >>> from sympy import exp, Function + >>> f = Function('f') + + >>> solve(f(x) - x, f(x)) + [x] + >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x)) + [x + f(x)] + >>> solve(f(x).diff(x) - f(x) - x, f(x)) + [-x + Derivative(f(x), x)] + >>> solve(x + exp(x)**2, exp(x), set=True) + ([exp(x)], {(-sqrt(-x),), (sqrt(-x),)}) + + >>> from sympy import Indexed, IndexedBase, Tuple + >>> A = IndexedBase('A') + >>> eqs = Tuple(A[1] + A[2] - 3, A[1] - A[2] + 1) + >>> solve(eqs, eqs.atoms(Indexed)) + {A[1]: 1, A[2]: 2} + + * To solve for a function within a derivative, use :func:`~.dsolve`. + + To solve for a symbol implicitly, use implicit=True: + + >>> solve(x + exp(x), x) + [-LambertW(1)] + >>> solve(x + exp(x), x, implicit=True) + [-exp(x)] + + It is possible to solve for anything in an expression that can be + replaced with a symbol using :obj:`~sympy.core.basic.Basic.subs`: + + >>> solve(x + 2 + sqrt(3), x + 2) + [-sqrt(3)] + >>> solve((x + 2 + sqrt(3), x + 4 + y), y, x + 2) + {y: -2 + sqrt(3), x + 2: -sqrt(3)} + + * Nothing heroic is done in this implicit solving so you may end up + with a symbol still in the solution: + + >>> eqs = (x*y + 3*y + sqrt(3), x + 4 + y) + >>> solve(eqs, y, x + 2) + {y: -sqrt(3)/(x + 3), x + 2: -2*x/(x + 3) - 6/(x + 3) + sqrt(3)/(x + 3)} + >>> solve(eqs, y*x, x) + {x: -y - 4, x*y: -3*y - sqrt(3)} + + * If you attempt to solve for a number, remember that the number + you have obtained does not necessarily mean that the value is + equivalent to the expression obtained: + + >>> solve(sqrt(2) - 1, 1) + [sqrt(2)] + >>> solve(x - y + 1, 1) # /!\ -1 is targeted, too + [x/(y - 1)] + >>> [_.subs(z, -1) for _ in solve((x - y + 1).subs(-1, z), 1)] + [-x + y] + + **Additional Examples** + + ``solve()`` with check=True (default) will run through the symbol tags to + eliminate unwanted solutions. If no assumptions are included, all possible + solutions will be returned: + + >>> x = Symbol("x") + >>> solve(x**2 - 1) + [-1, 1] + + By setting the ``positive`` flag, only one solution will be returned: + + >>> pos = Symbol("pos", positive=True) + >>> solve(pos**2 - 1) + [1] + + When the solutions are checked, those that make any denominator zero + are automatically excluded. If you do not want to exclude such solutions, + then use the check=False option: + + >>> from sympy import sin, limit + >>> solve(sin(x)/x) # 0 is excluded + [pi] + + If ``check=False``, then a solution to the numerator being zero is found + but the value of $x = 0$ is a spurious solution since $\sin(x)/x$ has the well + known limit (without discontinuity) of 1 at $x = 0$: + + >>> solve(sin(x)/x, check=False) + [0, pi] + + In the following case, however, the limit exists and is equal to the + value of $x = 0$ that is excluded when check=True: + + >>> eq = x**2*(1/x - z**2/x) + >>> solve(eq, x) + [] + >>> solve(eq, x, check=False) + [0] + >>> limit(eq, x, 0, '-') + 0 + >>> limit(eq, x, 0, '+') + 0 + + **Solving Relationships** + + When one or more expressions passed to ``solve`` is a relational, + a relational result is returned (and the ``dict`` and ``set`` flags + are ignored): + + >>> solve(x < 3) + (-oo < x) & (x < 3) + >>> solve([x < 3, x**2 > 4], x) + ((-oo < x) & (x < -2)) | ((2 < x) & (x < 3)) + >>> solve([x + y - 3, x > 3], x) + (3 < x) & (x < oo) & Eq(x, 3 - y) + + Although checking of assumptions on symbols in relationals + is not done, setting assumptions will affect how certain + relationals might automatically simplify: + + >>> solve(x**2 > 4) + ((-oo < x) & (x < -2)) | ((2 < x) & (x < oo)) + + >>> r = Symbol('r', real=True) + >>> solve(r**2 > 4) + (2 < r) | (r < -2) + + There is currently no algorithm in SymPy that allows you to use + relationships to resolve more than one variable. So the following + does not determine that ``q < 0`` (and trying to solve for ``r`` + and ``q`` will raise an error): + + >>> from sympy import symbols + >>> r, q = symbols('r, q', real=True) + >>> solve([r + q - 3, r > 3], r) + (3 < r) & Eq(r, 3 - q) + + You can directly call the routine that ``solve`` calls + when it encounters a relational: :func:`~.reduce_inequalities`. + It treats Expr like Equality. + + >>> from sympy import reduce_inequalities + >>> reduce_inequalities([x**2 - 4]) + Eq(x, -2) | Eq(x, 2) + + If each relationship contains only one symbol of interest, + the expressions can be processed for multiple symbols: + + >>> reduce_inequalities([0 <= x - 1, y < 3], [x, y]) + (-oo < y) & (1 <= x) & (x < oo) & (y < 3) + + But an error is raised if any relationship has more than one + symbol of interest: + + >>> reduce_inequalities([0 <= x*y - 1, y < 3], [x, y]) + Traceback (most recent call last): + ... + NotImplementedError: + inequality has more than one symbol of interest. + + **Disabling High-Order Explicit Solutions** + + When solving polynomial expressions, you might not want explicit solutions + (which can be quite long). If the expression is univariate, ``CRootOf`` + instances will be returned instead: + + >>> solve(x**3 - x + 1) + [-1/((-1/2 - sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)) - + (-1/2 - sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3, + -(-1/2 + sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3 - + 1/((-1/2 + sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)), + -(3*sqrt(69)/2 + 27/2)**(1/3)/3 - + 1/(3*sqrt(69)/2 + 27/2)**(1/3)] + >>> solve(x**3 - x + 1, cubics=False) + [CRootOf(x**3 - x + 1, 0), + CRootOf(x**3 - x + 1, 1), + CRootOf(x**3 - x + 1, 2)] + + If the expression is multivariate, no solution might be returned: + + >>> solve(x**3 - x + a, x, cubics=False) + [] + + Sometimes solutions will be obtained even when a flag is False because the + expression could be factored. In the following example, the equation can + be factored as the product of a linear and a quadratic factor so explicit + solutions (which did not require solving a cubic expression) are obtained: + + >>> eq = x**3 + 3*x**2 + x - 1 + >>> solve(eq, cubics=False) + [-1, -1 + sqrt(2), -sqrt(2) - 1] + + **Solving Equations Involving Radicals** + + Because of SymPy's use of the principle root, some solutions + to radical equations will be missed unless check=False: + + >>> from sympy import root + >>> eq = root(x**3 - 3*x**2, 3) + 1 - x + >>> solve(eq) + [] + >>> solve(eq, check=False) + [1/3] + + In the above example, there is only a single solution to the + equation. Other expressions will yield spurious roots which + must be checked manually; roots which give a negative argument + to odd-powered radicals will also need special checking: + + >>> from sympy import real_root, S + >>> eq = root(x, 3) - root(x, 5) + S(1)/7 + >>> solve(eq) # this gives 2 solutions but misses a 3rd + [CRootOf(7*x**5 - 7*x**3 + 1, 1)**15, + CRootOf(7*x**5 - 7*x**3 + 1, 2)**15] + >>> sol = solve(eq, check=False) + >>> [abs(eq.subs(x,i).n(2)) for i in sol] + [0.48, 0.e-110, 0.e-110, 0.052, 0.052] + + The first solution is negative so ``real_root`` must be used to see that it + satisfies the expression: + + >>> abs(real_root(eq.subs(x, sol[0])).n(2)) + 0.e-110 + + If the roots of the equation are not real then more care will be + necessary to find the roots, especially for higher order equations. + Consider the following expression: + + >>> expr = root(x, 3) - root(x, 5) + + We will construct a known value for this expression at x = 3 by selecting + the 1-th root for each radical: + + >>> expr1 = root(x, 3, 1) - root(x, 5, 1) + >>> v = expr1.subs(x, -3) + + The ``solve`` function is unable to find any exact roots to this equation: + + >>> eq = Eq(expr, v); eq1 = Eq(expr1, v) + >>> solve(eq, check=False), solve(eq1, check=False) + ([], []) + + The function ``unrad``, however, can be used to get a form of the equation + for which numerical roots can be found: + + >>> from sympy.solvers.solvers import unrad + >>> from sympy import nroots + >>> e, (p, cov) = unrad(eq) + >>> pvals = nroots(e) + >>> inversion = solve(cov, x)[0] + >>> xvals = [inversion.subs(p, i) for i in pvals] + + Although ``eq`` or ``eq1`` could have been used to find ``xvals``, the + solution can only be verified with ``expr1``: + + >>> z = expr - v + >>> [xi.n(chop=1e-9) for xi in xvals if abs(z.subs(x, xi).n()) < 1e-9] + [] + >>> z1 = expr1 - v + >>> [xi.n(chop=1e-9) for xi in xvals if abs(z1.subs(x, xi).n()) < 1e-9] + [-3.0] + + Parameters + ========== + + f : + - a single Expr or Poly that must be zero + - an Equality + - a Relational expression + - a Boolean + - iterable of one or more of the above + + symbols : (object(s) to solve for) specified as + - none given (other non-numeric objects will be used) + - single symbol + - denested list of symbols + (e.g., ``solve(f, x, y)``) + - ordered iterable of symbols + (e.g., ``solve(f, [x, y])``) + + flags : + dict=True (default is False) + Return list (perhaps empty) of solution mappings. + set=True (default is False) + Return list of symbols and set of tuple(s) of solution(s). + exclude=[] (default) + Do not try to solve for any of the free symbols in exclude; + if expressions are given, the free symbols in them will + be extracted automatically. + check=True (default) + If False, do not do any testing of solutions. This can be + useful if you want to include solutions that make any + denominator zero. + numerical=True (default) + Do a fast numerical check if *f* has only one symbol. + minimal=True (default is False) + A very fast, minimal testing. + warn=True (default is False) + Show a warning if ``checksol()`` could not conclude. + simplify=True (default) + Simplify all but polynomials of order 3 or greater before + returning them and (if check is not False) use the + general simplify function on the solutions and the + expression obtained when they are substituted into the + function which should be zero. + force=True (default is False) + Make positive all symbols without assumptions regarding sign. + rational=True (default) + Recast Floats as Rational; if this option is not used, the + system containing Floats may fail to solve because of issues + with polys. If rational=None, Floats will be recast as + rationals but the answer will be recast as Floats. If the + flag is False then nothing will be done to the Floats. + manual=True (default is False) + Do not use the polys/matrix method to solve a system of + equations, solve them one at a time as you might "manually." + implicit=True (default is False) + Allows ``solve`` to return a solution for a pattern in terms of + other functions that contain that pattern; this is only + needed if the pattern is inside of some invertible function + like cos, exp, etc. + particular=True (default is False) + Instructs ``solve`` to try to find a particular solution to + a linear system with as many zeros as possible; this is very + expensive. + quick=True (default is False; ``particular`` must be True) + Selects a fast heuristic to find a solution with many zeros + whereas a value of False uses the very slow method guaranteed + to find the largest number of zeros possible. + cubics=True (default) + Return explicit solutions when cubic expressions are encountered. + When False, quartics and quintics are disabled, too. + quartics=True (default) + Return explicit solutions when quartic expressions are encountered. + When False, quintics are disabled, too. + quintics=True (default) + Return explicit solutions (if possible) when quintic expressions + are encountered. + + See Also + ======== + + rsolve: For solving recurrence relationships + sympy.solvers.ode.dsolve: For solving differential equations + + """ + from .inequalities import reduce_inequalities + + # checking/recording flags + ########################################################################### + + # set solver types explicitly; as soon as one is False + # all the rest will be False + hints = ('cubics', 'quartics', 'quintics') + default = True + for k in hints: + default = flags.setdefault(k, bool(flags.get(k, default))) + + # allow solution to contain symbol if True: + implicit = flags.get('implicit', False) + + # record desire to see warnings + warn = flags.get('warn', False) + + # this flag will be needed for quick exits below, so record + # now -- but don't record `dict` yet since it might change + as_set = flags.get('set', False) + + # keeping track of how f was passed + bare_f = not iterable(f) + + # check flag usage for particular/quick which should only be used + # with systems of equations + if flags.get('quick', None) is not None: + if not flags.get('particular', None): + raise ValueError('when using `quick`, `particular` should be True') + if flags.get('particular', False) and bare_f: + raise ValueError(filldedent(""" + The 'particular/quick' flag is usually used with systems of + equations. Either pass your equation in a list or + consider using a solver like `diophantine` if you are + looking for a solution in integers.""")) + + # sympify everything, creating list of expressions and list of symbols + ########################################################################### + + def _sympified_list(w): + return list(map(sympify, w if iterable(w) else [w])) + f, symbols = (_sympified_list(w) for w in [f, symbols]) + + # preprocess symbol(s) + ########################################################################### + + ordered_symbols = None # were the symbols in a well defined order? + if not symbols: + # get symbols from equations + symbols = set().union(*[fi.free_symbols for fi in f]) + if len(symbols) < len(f): + for fi in f: + pot = preorder_traversal(fi) + for p in pot: + if isinstance(p, AppliedUndef): + if not as_set: + flags['dict'] = True # better show symbols + symbols.add(p) + pot.skip() # don't go any deeper + ordered_symbols = False + symbols = list(ordered(symbols)) # to make it canonical + else: + if len(symbols) == 1 and iterable(symbols[0]): + symbols = symbols[0] + ordered_symbols = symbols and is_sequence(symbols, + include=GeneratorType) + _symbols = list(uniq(symbols)) + if len(_symbols) != len(symbols): + ordered_symbols = False + symbols = list(ordered(symbols)) + else: + symbols = _symbols + + # check for duplicates + if len(symbols) != len(set(symbols)): + raise ValueError('duplicate symbols given') + # remove those not of interest + exclude = flags.pop('exclude', set()) + if exclude: + if isinstance(exclude, Expr): + exclude = [exclude] + exclude = set().union(*[e.free_symbols for e in sympify(exclude)]) + symbols = [s for s in symbols if s not in exclude] + + # preprocess equation(s) + ########################################################################### + + # automatically ignore True values + if isinstance(f, list): + f = [s for s in f if s is not S.true] + + # handle canonicalization of equation types + for i, fi in enumerate(f): + if isinstance(fi, (Eq, Ne)): + if 'ImmutableDenseMatrix' in [type(a).__name__ for a in fi.args]: + fi = fi.lhs - fi.rhs + else: + L, R = fi.args + if isinstance(R, BooleanAtom): + L, R = R, L + if isinstance(L, BooleanAtom): + if isinstance(fi, Ne): + L = ~L + if R.is_Relational: + fi = ~R if L is S.false else R + elif R.is_Symbol: + return L + elif R.is_Boolean and (~R).is_Symbol: + return ~L + else: + raise NotImplementedError(filldedent(''' + Unanticipated argument of Eq when other arg + is True or False. + ''')) + elif isinstance(fi, Eq): + fi = Add(fi.lhs, -fi.rhs, evaluate=False) + f[i] = fi + + # *** dispatch and handle as a system of relationals + # ************************************************** + if fi.is_Relational: + if len(symbols) != 1: + raise ValueError("can only solve for one symbol at a time") + if warn and symbols[0].assumptions0: + warnings.warn(filldedent(""" + \tWarning: assumptions about variable '%s' are + not handled currently.""" % symbols[0])) + return reduce_inequalities(f, symbols=symbols) + + # convert Poly to expression + if isinstance(fi, Poly): + f[i] = fi.as_expr() + + # rewrite hyperbolics in terms of exp if they have symbols of + # interest + f[i] = f[i].replace(lambda w: isinstance(w, HyperbolicFunction) and \ + w.has_free(*symbols), lambda w: w.rewrite(exp)) + + # if we have a Matrix, we need to iterate over its elements again + if f[i].is_Matrix: + try: + f[i] = f[i].as_explicit() + except ValueError: + raise ValueError( + "solve cannot handle matrices with symbolic shape." + ) + bare_f = False + f.extend(list(f[i])) + f[i] = S.Zero + + # if we can split it into real and imaginary parts then do so + freei = f[i].free_symbols + if freei and all(s.is_extended_real or s.is_imaginary for s in freei): + fr, fi = f[i].as_real_imag() + # accept as long as new re, im, arg or atan2 are not introduced + had = f[i].atoms(re, im, arg, atan2) + if fr and fi and fr != fi and not any( + i.atoms(re, im, arg, atan2) - had for i in (fr, fi)): + if bare_f: + bare_f = False + f[i: i + 1] = [fr, fi] + + # real/imag handling ----------------------------- + if any(isinstance(fi, (bool, BooleanAtom)) for fi in f): + if as_set: + return [], set() + return [] + + for i, fi in enumerate(f): + # Abs + while True: + was = fi + fi = fi.replace(Abs, lambda arg: + separatevars(Abs(arg)).rewrite(Piecewise) if arg.has(*symbols) + else Abs(arg)) + if was == fi: + break + + for e in fi.find(Abs): + if e.has(*symbols): + raise NotImplementedError('solving %s when the argument ' + 'is not real or imaginary.' % e) + + # arg + fi = fi.replace(arg, lambda a: arg(a).rewrite(atan2).rewrite(atan)) + + # save changes + f[i] = fi + + # see if re(s) or im(s) appear + freim = [fi for fi in f if fi.has(re, im)] + if freim: + irf = [] + for s in symbols: + if s.is_real or s.is_imaginary: + continue # neither re(x) nor im(x) will appear + # if re(s) or im(s) appear, the auxiliary equation must be present + if any(fi.has(re(s), im(s)) for fi in freim): + irf.append((s, re(s) + S.ImaginaryUnit*im(s))) + if irf: + for s, rhs in irf: + f = [fi.xreplace({s: rhs}) for fi in f] + [s - rhs] + symbols.extend([re(s), im(s)]) + if bare_f: + bare_f = False + flags['dict'] = True + # end of real/imag handling ----------------------------- + + # we can solve for non-symbol entities by replacing them with Dummy symbols + f, symbols, swap_sym = recast_to_symbols(f, symbols) + # this set of symbols (perhaps recast) is needed below + symset = set(symbols) + + # get rid of equations that have no symbols of interest; we don't + # try to solve them because the user didn't ask and they might be + # hard to solve; this means that solutions may be given in terms + # of the eliminated equations e.g. solve((x-y, y-3), x) -> {x: y} + newf = [] + for fi in f: + # let the solver handle equations that.. + # - have no symbols but are expressions + # - have symbols of interest + # - have no symbols of interest but are constant + # but when an expression is not constant and has no symbols of + # interest, it can't change what we obtain for a solution from + # the remaining equations so we don't include it; and if it's + # zero it can be removed and if it's not zero, there is no + # solution for the equation set as a whole + # + # The reason for doing this filtering is to allow an answer + # to be obtained to queries like solve((x - y, y), x); without + # this mod the return value is [] + ok = False + if fi.free_symbols & symset: + ok = True + else: + if fi.is_number: + if fi.is_Number: + if fi.is_zero: + continue + return [] + ok = True + else: + if fi.is_constant(): + ok = True + if ok: + newf.append(fi) + if not newf: + if as_set: + return symbols, set() + return [] + f = newf + del newf + + # mask off any Object that we aren't going to invert: Derivative, + # Integral, etc... so that solving for anything that they contain will + # give an implicit solution + seen = set() + non_inverts = set() + for fi in f: + pot = preorder_traversal(fi) + for p in pot: + if not isinstance(p, Expr) or isinstance(p, Piecewise): + pass + elif (isinstance(p, bool) or + not p.args or + p in symset or + p.is_Add or p.is_Mul or + p.is_Pow and not implicit or + p.is_Function and not implicit) and p.func not in (re, im): + continue + elif p not in seen: + seen.add(p) + if p.free_symbols & symset: + non_inverts.add(p) + else: + continue + pot.skip() + del seen + non_inverts = dict(list(zip(non_inverts, [Dummy() for _ in non_inverts]))) + f = [fi.subs(non_inverts) for fi in f] + + # Both xreplace and subs are needed below: xreplace to force substitution + # inside Derivative, subs to handle non-straightforward substitutions + non_inverts = [(v, k.xreplace(swap_sym).subs(swap_sym)) for k, v in non_inverts.items()] + + # rationalize Floats + floats = False + if flags.get('rational', True) is not False: + for i, fi in enumerate(f): + if fi.has(Float): + floats = True + f[i] = nsimplify(fi, rational=True) + + # capture any denominators before rewriting since + # they may disappear after the rewrite, e.g. issue 14779 + flags['_denominators'] = _simple_dens(f[0], symbols) + + # Any embedded piecewise functions need to be brought out to the + # top level so that the appropriate strategy gets selected. + # However, this is necessary only if one of the piecewise + # functions depends on one of the symbols we are solving for. + def _has_piecewise(e): + if e.is_Piecewise: + return e.has(*symbols) + return any(_has_piecewise(a) for a in e.args) + for i, fi in enumerate(f): + if _has_piecewise(fi): + f[i] = piecewise_fold(fi) + + # expand angles of sums; in general, expand_trig will allow + # more roots to be found but this is not a great solultion + # to not returning a parametric solution, otherwise + # many values can be returned that have a simple + # relationship between values + targs = {t for fi in f for t in fi.atoms(TrigonometricFunction)} + if len(targs) > 1: + add, other = sift(targs, lambda x: x.args[0].is_Add, binary=True) + add, other = [[i for i in l if i.has_free(*symbols)] for l in (add, other)] + trep = {} + for t in add: + a = t.args[0] + ind, dep = a.as_independent(*symbols) + if dep in symbols or -dep in symbols: + # don't let expansion expand wrt anything in ind + n = Dummy() if not ind.is_Number else ind + trep[t] = TR10(t.func(dep + n)).xreplace({n: ind}) + if other and len(other) <= 2: + base = gcd(*[i.args[0] for i in other]) if len(other) > 1 else other[0].args[0] + for i in other: + trep[i] = TR11(i, base) + f = [fi.xreplace(trep) for fi in f] + + # + # try to get a solution + ########################################################################### + if bare_f: + solution = None + if len(symbols) != 1: + solution = _solve_undetermined(f[0], symbols, flags) + if not solution: + solution = _solve(f[0], *symbols, **flags) + else: + linear, solution = _solve_system(f, symbols, **flags) + assert type(solution) is list + assert not solution or type(solution[0]) is dict, solution + # + # postprocessing + ########################################################################### + # capture as_dict flag now (as_set already captured) + as_dict = flags.get('dict', False) + + # define how solution will get unpacked + tuple_format = lambda s: [tuple([i.get(x, x) for x in symbols]) for i in s] + if as_dict or as_set: + unpack = None + elif bare_f: + if len(symbols) == 1: + unpack = lambda s: [i[symbols[0]] for i in s] + elif len(solution) == 1 and len(solution[0]) == len(symbols): + # undetermined linear coeffs solution + unpack = lambda s: s[0] + elif ordered_symbols: + unpack = tuple_format + else: + unpack = lambda s: s + else: + if solution: + if linear and len(solution) == 1: + # if you want the tuple solution for the linear + # case, use `set=True` + unpack = lambda s: s[0] + elif ordered_symbols: + unpack = tuple_format + else: + unpack = lambda s: s + else: + unpack = None + + # Restore masked-off objects + if non_inverts and type(solution) is list: + solution = [{k: v.subs(non_inverts) for k, v in s.items()} + for s in solution] + + # Restore original "symbols" if a dictionary is returned. + # This is not necessary for + # - the single univariate equation case + # since the symbol will have been removed from the solution; + # - the nonlinear poly_system since that only supports zero-dimensional + # systems and those results come back as a list + # + # ** unless there were Derivatives with the symbols, but those were handled + # above. + if swap_sym: + symbols = [swap_sym.get(k, k) for k in symbols] + for i, sol in enumerate(solution): + solution[i] = {swap_sym.get(k, k): v.subs(swap_sym) + for k, v in sol.items()} + + # Get assumptions about symbols, to filter solutions. + # Note that if assumptions about a solution can't be verified, it is still + # returned. + check = flags.get('check', True) + + # restore floats + if floats and solution and flags.get('rational', None) is None: + solution = nfloat(solution, exponent=False) + # nfloat might reveal more duplicates + solution = _remove_duplicate_solutions(solution) + + if check and solution: # assumption checking + warn = flags.get('warn', False) + got_None = [] # solutions for which one or more symbols gave None + no_False = [] # solutions for which no symbols gave False + for sol in solution: + v = fuzzy_and(check_assumptions(val, **symb.assumptions0) + for symb, val in sol.items()) + if v is False: + continue + no_False.append(sol) + if v is None: + got_None.append(sol) + + solution = no_False + if warn and got_None: + warnings.warn(filldedent(""" + \tWarning: assumptions concerning following solution(s) + cannot be checked:""" + '\n\t' + + ', '.join(str(s) for s in got_None))) + + # + # done + ########################################################################### + + if not solution: + if as_set: + return symbols, set() + return [] + + # make orderings canonical for list of dictionaries + if not as_set: # for set, no point in ordering + solution = [{k: s[k] for k in ordered(s)} for s in solution] + solution.sort(key=default_sort_key) + + if not (as_set or as_dict): + return unpack(solution) + + if as_dict: + return solution + + # set output: (symbols, {t1, t2, ...}) from list of dictionaries; + # include all symbols for those that like a verbose solution + # and to resolve any differences in dictionary keys. + # + # The set results can easily be used to make a verbose dict as + # k, v = solve(eqs, syms, set=True) + # sol = [dict(zip(k,i)) for i in v] + # + if ordered_symbols: + k = symbols # keep preferred order + else: + # just unify the symbols for which solutions were found + k = list(ordered(set(flatten(tuple(i.keys()) for i in solution)))) + return k, {tuple([s.get(ki, ki) for ki in k]) for s in solution} + + +def _solve_undetermined(g, symbols, flags): + """solve helper to return a list with one dict (solution) else None + + A direct call to solve_undetermined_coeffs is more flexible and + can return both multiple solutions and handle more than one independent + variable. Here, we have to be more cautious to keep from solving + something that does not look like an undetermined coeffs system -- + to minimize the surprise factor since singularities that cancel are not + prohibited in solve_undetermined_coeffs. + """ + if g.free_symbols - set(symbols): + sol = solve_undetermined_coeffs(g, symbols, **dict(flags, dict=True, set=None)) + if len(sol) == 1: + return sol + + +def _solve(f, *symbols, **flags): + """Return a checked solution for *f* in terms of one or more of the + symbols in the form of a list of dictionaries. + + If no method is implemented to solve the equation, a NotImplementedError + will be raised. In the case that conversion of an expression to a Poly + gives None a ValueError will be raised. + """ + + not_impl_msg = "No algorithms are implemented to solve equation %s" + + if len(symbols) != 1: + # look for solutions for desired symbols that are independent + # of symbols already solved for, e.g. if we solve for x = y + # then no symbol having x in its solution will be returned. + + # First solve for linear symbols (since that is easier and limits + # solution size) and then proceed with symbols appearing + # in a non-linear fashion. Ideally, if one is solving a single + # expression for several symbols, they would have to be + # appear in factors of an expression, but we do not here + # attempt factorization. XXX perhaps handling a Mul + # should come first in this routine whether there is + # one or several symbols. + nonlin_s = [] + got_s = set() + rhs_s = set() + result = [] + for s in symbols: + xi, v = solve_linear(f, symbols=[s]) + if xi == s: + # no need to check but we should simplify if desired + if flags.get('simplify', True): + v = simplify(v) + vfree = v.free_symbols + if vfree & got_s: + # was linear, but has redundant relationship + # e.g. x - y = 0 has y == x is redundant for x == y + # so ignore + continue + rhs_s |= vfree + got_s.add(xi) + result.append({xi: v}) + elif xi: # there might be a non-linear solution if xi is not 0 + nonlin_s.append(s) + if not nonlin_s: + return result + for s in nonlin_s: + try: + soln = _solve(f, s, **flags) + for sol in soln: + if sol[s].free_symbols & got_s: + # depends on previously solved symbols: ignore + continue + got_s.add(s) + result.append(sol) + except NotImplementedError: + continue + if got_s: + return result + else: + raise NotImplementedError(not_impl_msg % f) + + # solve f for a single variable + + symbol = symbols[0] + + # expand binomials only if it has the unknown symbol + f = f.replace(lambda e: isinstance(e, binomial) and e.has(symbol), + lambda e: expand_func(e)) + + # checking will be done unless it is turned off before making a + # recursive call; the variables `checkdens` and `check` are + # captured here (for reference below) in case flag value changes + flags['check'] = checkdens = check = flags.pop('check', True) + + # build up solutions if f is a Mul + if f.is_Mul: + result = set() + for m in f.args: + if m in {S.NegativeInfinity, S.ComplexInfinity, S.Infinity}: + result = set() + break + soln = _vsolve(m, symbol, **flags) + result.update(set(soln)) + result = [{symbol: v} for v in result] + if check: + # all solutions have been checked but now we must + # check that the solutions do not set denominators + # in any factor to zero + dens = flags.get('_denominators', _simple_dens(f, symbols)) + result = [s for s in result if + not any(checksol(den, s, **flags) for den in + dens)] + # set flags for quick exit at end; solutions for each + # factor were already checked and simplified + check = False + flags['simplify'] = False + + elif f.is_Piecewise: + result = set() + if any(e.is_zero for e, c in f.args): + f = f.simplify() # failure imminent w/o help + + cond = neg = True + for expr, cnd in f.args: + # the explicit condition for this expr is the current cond + # and none of the previous conditions + cond = And(neg, cnd) + neg = And(neg, ~cond) + + if expr.is_zero and cond.simplify() != False: + raise NotImplementedError(filldedent(''' + An expression is already zero when %s. + This means that in this *region* the solution + is zero but solve can only represent discrete, + not interval, solutions. If this is a spurious + interval it might be resolved with simplification + of the Piecewise conditions.''' % cond)) + candidates = _vsolve(expr, symbol, **flags) + + for candidate in candidates: + if candidate in result: + # an unconditional value was already there + continue + try: + v = cond.subs(symbol, candidate) + _eval_simplify = getattr(v, '_eval_simplify', None) + if _eval_simplify is not None: + # unconditionally take the simplification of v + v = _eval_simplify(ratio=2, measure=lambda x: 1) + except TypeError: + # incompatible type with condition(s) + continue + if v == False: + continue + if v == True: + result.add(candidate) + else: + result.add(Piecewise( + (candidate, v), + (S.NaN, True))) + # solutions already checked and simplified + # **************************************** + return [{symbol: r} for r in result] + else: + # first see if it really depends on symbol and whether there + # is only a linear solution + f_num, sol = solve_linear(f, symbols=symbols) + if f_num.is_zero or sol is S.NaN: + return [] + elif f_num.is_Symbol: + # no need to check but simplify if desired + if flags.get('simplify', True): + sol = simplify(sol) + return [{f_num: sol}] + + poly = None + # check for a single Add generator + if not f_num.is_Add: + add_args = [i for i in f_num.atoms(Add) + if symbol in i.free_symbols] + if len(add_args) == 1: + gen = add_args[0] + spart = gen.as_independent(symbol)[1].as_base_exp()[0] + if spart == symbol: + try: + poly = Poly(f_num, spart) + except PolynomialError: + pass + + result = False # no solution was obtained + msg = '' # there is no failure message + + # Poly is generally robust enough to convert anything to + # a polynomial and tell us the different generators that it + # contains, so we will inspect the generators identified by + # polys to figure out what to do. + + # try to identify a single generator that will allow us to solve this + # as a polynomial, followed (perhaps) by a change of variables if the + # generator is not a symbol + + try: + if poly is None: + poly = Poly(f_num) + if poly is None: + raise ValueError('could not convert %s to Poly' % f_num) + except GeneratorsNeeded: + simplified_f = simplify(f_num) + if simplified_f != f_num: + return _solve(simplified_f, symbol, **flags) + raise ValueError('expression appears to be a constant') + + gens = [g for g in poly.gens if g.has(symbol)] + + def _as_base_q(x): + """Return (b**e, q) for x = b**(p*e/q) where p/q is the leading + Rational of the exponent of x, e.g. exp(-2*x/3) -> (exp(x), 3) + """ + b, e = x.as_base_exp() + if e.is_Rational: + return b, e.q + if not e.is_Mul: + return x, 1 + c, ee = e.as_coeff_Mul() + if c.is_Rational and c is not S.One: # c could be a Float + return b**ee, c.q + return x, 1 + + if len(gens) > 1: + # If there is more than one generator, it could be that the + # generators have the same base but different powers, e.g. + # >>> Poly(exp(x) + 1/exp(x)) + # Poly(exp(-x) + exp(x), exp(-x), exp(x), domain='ZZ') + # + # If unrad was not disabled then there should be no rational + # exponents appearing as in + # >>> Poly(sqrt(x) + sqrt(sqrt(x))) + # Poly(sqrt(x) + x**(1/4), sqrt(x), x**(1/4), domain='ZZ') + + bases, qs = list(zip(*[_as_base_q(g) for g in gens])) + bases = set(bases) + + if len(bases) > 1 or not all(q == 1 for q in qs): + funcs = {b for b in bases if b.is_Function} + + trig = {_ for _ in funcs if + isinstance(_, TrigonometricFunction)} + other = funcs - trig + if not other and len(funcs.intersection(trig)) > 1: + newf = None + if f_num.is_Add and len(f_num.args) == 2: + # check for sin(x)**p = cos(x)**p + _args = f_num.args + t = a, b = [i.atoms(Function).intersection( + trig) for i in _args] + if all(len(i) == 1 for i in t): + a, b = [i.pop() for i in t] + if isinstance(a, cos): + a, b = b, a + _args = _args[::-1] + if isinstance(a, sin) and isinstance(b, cos + ) and a.args[0] == b.args[0]: + # sin(x) + cos(x) = 0 -> tan(x) + 1 = 0 + newf, _d = (TR2i(_args[0]/_args[1]) + 1 + ).as_numer_denom() + if not _d.is_Number: + newf = None + if newf is None: + newf = TR1(f_num).rewrite(tan) + if newf != f_num: + # don't check the rewritten form --check + # solutions in the un-rewritten form below + flags['check'] = False + result = _solve(newf, symbol, **flags) + flags['check'] = check + + # just a simple case - see if replacement of single function + # clears all symbol-dependent functions, e.g. + # log(x) - log(log(x) - 1) - 3 can be solved even though it has + # two generators. + + if result is False and funcs: + funcs = list(ordered(funcs)) # put shallowest function first + f1 = funcs[0] + t = Dummy('t') + # perform the substitution + ftry = f_num.subs(f1, t) + + # if no Functions left, we can proceed with usual solve + if not ftry.has(symbol): + cv_sols = _solve(ftry, t, **flags) + cv_inv = list(ordered(_vsolve(t - f1, symbol, **flags)))[0] + result = [{symbol: cv_inv.subs(sol)} for sol in cv_sols] + + if result is False: + msg = 'multiple generators %s' % gens + + else: + # e.g. case where gens are exp(x), exp(-x) + u = bases.pop() + t = Dummy('t') + inv = _vsolve(u - t, symbol, **flags) + if isinstance(u, (Pow, exp)): + # this will be resolved by factor in _tsolve but we might + # as well try a simple expansion here to get things in + # order so something like the following will work now without + # having to factor: + # + # >>> eq = (exp(I*(-x-2))+exp(I*(x+2))) + # >>> eq.subs(exp(x),y) # fails + # exp(I*(-x - 2)) + exp(I*(x + 2)) + # >>> eq.expand().subs(exp(x),y) # works + # y**I*exp(2*I) + y**(-I)*exp(-2*I) + def _expand(p): + b, e = p.as_base_exp() + e = expand_mul(e) + return expand_power_exp(b**e) + ftry = f_num.replace( + lambda w: w.is_Pow or isinstance(w, exp), + _expand).subs(u, t) + if not ftry.has(symbol): + soln = _solve(ftry, t, **flags) + result = [{symbol: i.subs(s)} for i in inv for s in soln] + + elif len(gens) == 1: + + # There is only one generator that we are interested in, but + # there may have been more than one generator identified by + # polys (e.g. for symbols other than the one we are interested + # in) so recast the poly in terms of our generator of interest. + # Also use composite=True with f_num since Poly won't update + # poly as documented in issue 8810. + + poly = Poly(f_num, gens[0], composite=True) + + # if we aren't on the tsolve-pass, use roots + if not flags.pop('tsolve', False): + soln = None + deg = poly.degree() + flags['tsolve'] = True + hints = ('cubics', 'quartics', 'quintics') + solvers = {h: flags.get(h) for h in hints} + soln = roots(poly, **solvers) + if sum(soln.values()) < deg: + # e.g. roots(32*x**5 + 400*x**4 + 2032*x**3 + + # 5000*x**2 + 6250*x + 3189) -> {} + # so all_roots is used and RootOf instances are + # returned *unless* the system is multivariate + # or high-order EX domain. + try: + soln = poly.all_roots() + except NotImplementedError: + if not flags.get('incomplete', True): + raise NotImplementedError( + filldedent(''' + Neither high-order multivariate polynomials + nor sorting of EX-domain polynomials is supported. + If you want to see any results, pass keyword incomplete=True to + solve; to see numerical values of roots + for univariate expressions, use nroots. + ''')) + else: + pass + else: + soln = list(soln.keys()) + + if soln is not None: + u = poly.gen + if u != symbol: + try: + t = Dummy('t') + inv = _vsolve(u - t, symbol, **flags) + soln = {i.subs(t, s) for i in inv for s in soln} + except NotImplementedError: + # perhaps _tsolve can handle f_num + soln = None + else: + check = False # only dens need to be checked + if soln is not None: + if len(soln) > 2: + # if the flag wasn't set then unset it since high-order + # results are quite long. Perhaps one could base this + # decision on a certain critical length of the + # roots. In addition, wester test M2 has an expression + # whose roots can be shown to be real with the + # unsimplified form of the solution whereas only one of + # the simplified forms appears to be real. + flags['simplify'] = flags.get('simplify', False) + if soln is not None: + result = [{symbol: v} for v in soln] + + # fallback if above fails + # ----------------------- + if result is False: + # try unrad + if flags.pop('_unrad', True): + try: + u = unrad(f_num, symbol) + except (ValueError, NotImplementedError): + u = False + if u: + eq, cov = u + if cov: + isym, ieq = cov + inv = _vsolve(ieq, symbol, **flags)[0] + rv = {inv.subs(xi) for xi in _solve(eq, isym, **flags)} + else: + try: + rv = set(_vsolve(eq, symbol, **flags)) + except NotImplementedError: + rv = None + if rv is not None: + result = [{symbol: v} for v in rv] + # if the flag wasn't set then unset it since unrad results + # can be quite long or of very high order + flags['simplify'] = flags.get('simplify', False) + else: + pass # for coverage + + # try _tsolve + if result is False: + flags.pop('tsolve', None) # allow tsolve to be used on next pass + try: + soln = _tsolve(f_num, symbol, **flags) + if soln is not None: + result = [{symbol: v} for v in soln] + except PolynomialError: + pass + # ----------- end of fallback ---------------------------- + + if result is False: + raise NotImplementedError('\n'.join([msg, not_impl_msg % f])) + + result = _remove_duplicate_solutions(result) + + if flags.get('simplify', True): + result = [{k: d[k].simplify() for k in d} for d in result] + # Simplification might reveal more duplicates + result = _remove_duplicate_solutions(result) + # we just simplified the solution so we now set the flag to + # False so the simplification doesn't happen again in checksol() + flags['simplify'] = False + + if checkdens: + # reject any result that makes any denom. affirmatively 0; + # if in doubt, keep it + dens = _simple_dens(f, symbols) + result = [r for r in result if + not any(checksol(d, r, **flags) + for d in dens)] + if check: + # keep only results if the check is not False + result = [r for r in result if + checksol(f_num, r, **flags) is not False] + return result + + +def _remove_duplicate_solutions(solutions: list[dict[Expr, Expr]] + ) -> list[dict[Expr, Expr]]: + """Remove duplicates from a list of dicts""" + solutions_set = set() + solutions_new = [] + + for sol in solutions: + solset = frozenset(sol.items()) + if solset not in solutions_set: + solutions_new.append(sol) + solutions_set.add(solset) + + return solutions_new + + +def _solve_system(exprs, symbols, **flags): + """return ``(linear, solution)`` where ``linear`` is True + if the system was linear, else False; ``solution`` + is a list of dictionaries giving solutions for the symbols + """ + if not exprs: + return False, [] + + if flags.pop('_split', True): + # Split the system into connected components + V = exprs + symsset = set(symbols) + exprsyms = {e: e.free_symbols & symsset for e in exprs} + E = [] + sym_indices = {sym: i for i, sym in enumerate(symbols)} + for n, e1 in enumerate(exprs): + for e2 in exprs[:n]: + # Equations are connected if they share a symbol + if exprsyms[e1] & exprsyms[e2]: + E.append((e1, e2)) + G = V, E + subexprs = connected_components(G) + if len(subexprs) > 1: + subsols = [] + linear = True + for subexpr in subexprs: + subsyms = set() + for e in subexpr: + subsyms |= exprsyms[e] + subsyms = sorted(subsyms, key = lambda x: sym_indices[x]) + flags['_split'] = False # skip split step + _linear, subsol = _solve_system(subexpr, subsyms, **flags) + if linear: + linear = linear and _linear + if not isinstance(subsol, list): + subsol = [subsol] + subsols.append(subsol) + # Full solution is cartesian product of subsystems + sols = [] + for soldicts in product(*subsols): + sols.append(dict(item for sd in soldicts + for item in sd.items())) + return linear, sols + + polys = [] + dens = set() + failed = [] + result = [] + solved_syms = [] + linear = True + manual = flags.get('manual', False) + checkdens = check = flags.get('check', True) + + for j, g in enumerate(exprs): + dens.update(_simple_dens(g, symbols)) + i, d = _invert(g, *symbols) + if d in symbols: + if linear: + linear = solve_linear(g, 0, [d])[0] == d + g = d - i + g = g.as_numer_denom()[0] + if manual: + failed.append(g) + continue + + poly = g.as_poly(*symbols, extension=True) + + if poly is not None: + polys.append(poly) + else: + failed.append(g) + + if polys: + if all(p.is_linear for p in polys): + n, m = len(polys), len(symbols) + matrix = zeros(n, m + 1) + + for i, poly in enumerate(polys): + for monom, coeff in poly.terms(): + try: + j = monom.index(1) + matrix[i, j] = coeff + except ValueError: + matrix[i, m] = -coeff + + # returns a dictionary ({symbols: values}) or None + if flags.pop('particular', False): + result = minsolve_linear_system(matrix, *symbols, **flags) + else: + result = solve_linear_system(matrix, *symbols, **flags) + result = [result] if result else [] + if failed: + if result: + solved_syms = list(result[0].keys()) # there is only one result dict + else: + solved_syms = [] + # linear doesn't change + else: + linear = False + if len(symbols) > len(polys): + + free = set().union(*[p.free_symbols for p in polys]) + free = list(ordered(free.intersection(symbols))) + got_s = set() + result = [] + for syms in subsets(free, min(len(free), len(polys))): + try: + # returns [], None or list of tuples + res = solve_poly_system(polys, *syms) + if res: + for r in set(res): + skip = False + for r1 in r: + if got_s and any(ss in r1.free_symbols + for ss in got_s): + # sol depends on previously + # solved symbols: discard it + skip = True + if not skip: + got_s.update(syms) + result.append(dict(list(zip(syms, r)))) + except NotImplementedError: + pass + if got_s: + solved_syms = list(got_s) + else: + failed.extend([g.as_expr() for g in polys]) + else: + try: + result = solve_poly_system(polys, *symbols) + if result: + solved_syms = symbols + result = [dict(list(zip(solved_syms, r))) for r in set(result)] + except NotImplementedError: + failed.extend([g.as_expr() for g in polys]) + solved_syms = [] + + # convert None or [] to [{}] + result = result or [{}] + + if failed: + linear = False + # For each failed equation, see if we can solve for one of the + # remaining symbols from that equation. If so, we update the + # solution set and continue with the next failed equation, + # repeating until we are done or we get an equation that can't + # be solved. + def _ok_syms(e, sort=False): + rv = e.free_symbols & legal + + # Solve first for symbols that have lower degree in the equation. + # Ideally we want to solve firstly for symbols that appear linearly + # with rational coefficients e.g. if e = x*y + z then we should + # solve for z first. + def key(sym): + ep = e.as_poly(sym) + if ep is None: + complexity = (S.Infinity, S.Infinity, S.Infinity) + else: + coeff_syms = ep.LC().free_symbols + complexity = (ep.degree(), len(coeff_syms & rv), len(coeff_syms)) + return complexity + (default_sort_key(sym),) + + if sort: + rv = sorted(rv, key=key) + return rv + + legal = set(symbols) # what we are interested in + # sort so equation with the fewest potential symbols is first + u = Dummy() # used in solution checking + for eq in ordered(failed, lambda _: len(_ok_syms(_))): + newresult = [] + bad_results = [] + hit = False + for r in result: + got_s = set() + # update eq with everything that is known so far + eq2 = eq.subs(r) + # if check is True then we see if it satisfies this + # equation, otherwise we just accept it + if check and r: + b = checksol(u, u, eq2, minimal=True) + if b is not None: + # this solution is sufficient to know whether + # it is valid or not so we either accept or + # reject it, then continue + if b: + newresult.append(r) + else: + bad_results.append(r) + continue + # search for a symbol amongst those available that + # can be solved for + ok_syms = _ok_syms(eq2, sort=True) + if not ok_syms: + if r: + newresult.append(r) + break # skip as it's independent of desired symbols + for s in ok_syms: + try: + soln = _vsolve(eq2, s, **flags) + except NotImplementedError: + continue + # put each solution in r and append the now-expanded + # result in the new result list; use copy since the + # solution for s is being added in-place + for sol in soln: + if got_s and any(ss in sol.free_symbols for ss in got_s): + # sol depends on previously solved symbols: discard it + continue + rnew = r.copy() + for k, v in r.items(): + rnew[k] = v.subs(s, sol) + # and add this new solution + rnew[s] = sol + # check that it is independent of previous solutions + iset = set(rnew.items()) + for i in newresult: + if len(i) < len(iset): + # update i with what is known + i_items_updated = {(k, v.xreplace(rnew)) for k, v in i.items()} + if not i_items_updated - iset: + # this is a superset of a known solution that + # is smaller + break + else: + # keep it + newresult.append(rnew) + hit = True + got_s.add(s) + if not hit: + raise NotImplementedError('could not solve %s' % eq2) + else: + result = newresult + for b in bad_results: + if b in result: + result.remove(b) + + if not result: + return False, [] + + # rely on linear/polynomial system solvers to simplify + # XXX the following tests show that the expressions + # returned are not the same as they would be if simplify + # were applied to this: + # sympy/solvers/ode/tests/test_systems/test__classify_linear_system + # sympy/solvers/tests/test_solvers/test_issue_4886 + # so the docs should be updated to reflect that or else + # the following should be `bool(failed) or not linear` + default_simplify = bool(failed) + if flags.get('simplify', default_simplify): + for r in result: + for k in r: + r[k] = simplify(r[k]) + flags['simplify'] = False # don't need to do so in checksol now + + if checkdens: + result = [r for r in result + if not any(checksol(d, r, **flags) for d in dens)] + + if check and not linear: + result = [r for r in result + if not any(checksol(e, r, **flags) is False for e in exprs)] + + result = [r for r in result if r] + return linear, result + + +def solve_linear(lhs, rhs=0, symbols=[], exclude=[]): + r""" + Return a tuple derived from ``f = lhs - rhs`` that is one of + the following: ``(0, 1)``, ``(0, 0)``, ``(symbol, solution)``, ``(n, d)``. + + Explanation + =========== + + ``(0, 1)`` meaning that ``f`` is independent of the symbols in *symbols* + that are not in *exclude*. + + ``(0, 0)`` meaning that there is no solution to the equation amongst the + symbols given. If the first element of the tuple is not zero, then the + function is guaranteed to be dependent on a symbol in *symbols*. + + ``(symbol, solution)`` where symbol appears linearly in the numerator of + ``f``, is in *symbols* (if given), and is not in *exclude* (if given). No + simplification is done to ``f`` other than a ``mul=True`` expansion, so the + solution will correspond strictly to a unique solution. + + ``(n, d)`` where ``n`` and ``d`` are the numerator and denominator of ``f`` + when the numerator was not linear in any symbol of interest; ``n`` will + never be a symbol unless a solution for that symbol was found (in which case + the second element is the solution, not the denominator). + + Examples + ======== + + >>> from sympy import cancel, Pow + + ``f`` is independent of the symbols in *symbols* that are not in + *exclude*: + + >>> from sympy import cos, sin, solve_linear + >>> from sympy.abc import x, y, z + >>> eq = y*cos(x)**2 + y*sin(x)**2 - y # = y*(1 - 1) = 0 + >>> solve_linear(eq) + (0, 1) + >>> eq = cos(x)**2 + sin(x)**2 # = 1 + >>> solve_linear(eq) + (0, 1) + >>> solve_linear(x, exclude=[x]) + (0, 1) + + The variable ``x`` appears as a linear variable in each of the + following: + + >>> solve_linear(x + y**2) + (x, -y**2) + >>> solve_linear(1/x - y**2) + (x, y**(-2)) + + When not linear in ``x`` or ``y`` then the numerator and denominator are + returned: + + >>> solve_linear(x**2/y**2 - 3) + (x**2 - 3*y**2, y**2) + + If the numerator of the expression is a symbol, then ``(0, 0)`` is + returned if the solution for that symbol would have set any + denominator to 0: + + >>> eq = 1/(1/x - 2) + >>> eq.as_numer_denom() + (x, 1 - 2*x) + >>> solve_linear(eq) + (0, 0) + + But automatic rewriting may cause a symbol in the denominator to + appear in the numerator so a solution will be returned: + + >>> (1/x)**-1 + x + >>> solve_linear((1/x)**-1) + (x, 0) + + Use an unevaluated expression to avoid this: + + >>> solve_linear(Pow(1/x, -1, evaluate=False)) + (0, 0) + + If ``x`` is allowed to cancel in the following expression, then it + appears to be linear in ``x``, but this sort of cancellation is not + done by ``solve_linear`` so the solution will always satisfy the + original expression without causing a division by zero error. + + >>> eq = x**2*(1/x - z**2/x) + >>> solve_linear(cancel(eq)) + (x, 0) + >>> solve_linear(eq) + (x**2*(1 - z**2), x) + + A list of symbols for which a solution is desired may be given: + + >>> solve_linear(x + y + z, symbols=[y]) + (y, -x - z) + + A list of symbols to ignore may also be given: + + >>> solve_linear(x + y + z, exclude=[x]) + (y, -x - z) + + (A solution for ``y`` is obtained because it is the first variable + from the canonically sorted list of symbols that had a linear + solution.) + + """ + if isinstance(lhs, Eq): + if rhs: + raise ValueError(filldedent(''' + If lhs is an Equality, rhs must be 0 but was %s''' % rhs)) + rhs = lhs.rhs + lhs = lhs.lhs + dens = None + eq = lhs - rhs + n, d = eq.as_numer_denom() + if not n: + return S.Zero, S.One + + free = n.free_symbols + if not symbols: + symbols = free + else: + bad = [s for s in symbols if not s.is_Symbol] + if bad: + if len(bad) == 1: + bad = bad[0] + if len(symbols) == 1: + eg = 'solve(%s, %s)' % (eq, symbols[0]) + else: + eg = 'solve(%s, *%s)' % (eq, list(symbols)) + raise ValueError(filldedent(''' + solve_linear only handles symbols, not %s. To isolate + non-symbols use solve, e.g. >>> %s <<<. + ''' % (bad, eg))) + symbols = free.intersection(symbols) + symbols = symbols.difference(exclude) + if not symbols: + return S.Zero, S.One + + # derivatives are easy to do but tricky to analyze to see if they + # are going to disallow a linear solution, so for simplicity we + # just evaluate the ones that have the symbols of interest + derivs = defaultdict(list) + for der in n.atoms(Derivative): + csym = der.free_symbols & symbols + for c in csym: + derivs[c].append(der) + + all_zero = True + for xi in sorted(symbols, key=default_sort_key): # canonical order + # if there are derivatives in this var, calculate them now + if isinstance(derivs[xi], list): + derivs[xi] = {der: der.doit() for der in derivs[xi]} + newn = n.subs(derivs[xi]) + dnewn_dxi = newn.diff(xi) + # dnewn_dxi can be nonzero if it survives differentation by any + # of its free symbols + free = dnewn_dxi.free_symbols + if dnewn_dxi and (not free or any(dnewn_dxi.diff(s) for s in free) or free == symbols): + all_zero = False + if dnewn_dxi is S.NaN: + break + if xi not in dnewn_dxi.free_symbols: + vi = -1/dnewn_dxi*(newn.subs(xi, 0)) + if dens is None: + dens = _simple_dens(eq, symbols) + if not any(checksol(di, {xi: vi}, minimal=True) is True + for di in dens): + # simplify any trivial integral + irep = [(i, i.doit()) for i in vi.atoms(Integral) if + i.function.is_number] + # do a slight bit of simplification + vi = expand_mul(vi.subs(irep)) + return xi, vi + if all_zero: + return S.Zero, S.One + if n.is_Symbol: # no solution for this symbol was found + return S.Zero, S.Zero + return n, d + + +def minsolve_linear_system(system, *symbols, **flags): + r""" + Find a particular solution to a linear system. + + Explanation + =========== + + In particular, try to find a solution with the minimal possible number + of non-zero variables using a naive algorithm with exponential complexity. + If ``quick=True``, a heuristic is used. + + """ + quick = flags.get('quick', False) + # Check if there are any non-zero solutions at all + s0 = solve_linear_system(system, *symbols, **flags) + if not s0 or all(v == 0 for v in s0.values()): + return s0 + if quick: + # We just solve the system and try to heuristically find a nice + # solution. + s = solve_linear_system(system, *symbols) + def update(determined, solution): + delete = [] + for k, v in solution.items(): + solution[k] = v.subs(determined) + if not solution[k].free_symbols: + delete.append(k) + determined[k] = solution[k] + for k in delete: + del solution[k] + determined = {} + update(determined, s) + while s: + # NOTE sort by default_sort_key to get deterministic result + k = max((k for k in s.values()), + key=lambda x: (len(x.free_symbols), default_sort_key(x))) + kfree = k.free_symbols + x = next(reversed(list(ordered(kfree)))) + if len(kfree) != 1: + determined[x] = S.Zero + else: + val = _vsolve(k, x, check=False)[0] + if not val and not any(v.subs(x, val) for v in s.values()): + determined[x] = S.One + else: + determined[x] = val + update(determined, s) + return determined + else: + # We try to select n variables which we want to be non-zero. + # All others will be assumed zero. We try to solve the modified system. + # If there is a non-trivial solution, just set the free variables to + # one. If we do this for increasing n, trying all combinations of + # variables, we will find an optimal solution. + # We speed up slightly by starting at one less than the number of + # variables the quick method manages. + N = len(symbols) + bestsol = minsolve_linear_system(system, *symbols, quick=True) + n0 = len([x for x in bestsol.values() if x != 0]) + for n in range(n0 - 1, 1, -1): + debugf('minsolve: %s', n) + thissol = None + for nonzeros in combinations(range(N), n): + subm = Matrix([system.col(i).T for i in nonzeros] + [system.col(-1).T]).T + s = solve_linear_system(subm, *[symbols[i] for i in nonzeros]) + if s and not all(v == 0 for v in s.values()): + subs = [(symbols[v], S.One) for v in nonzeros] + for k, v in s.items(): + s[k] = v.subs(subs) + for sym in symbols: + if sym not in s: + if symbols.index(sym) in nonzeros: + s[sym] = S.One + else: + s[sym] = S.Zero + thissol = s + break + if thissol is None: + break + bestsol = thissol + return bestsol + + +def solve_linear_system(system, *symbols, **flags): + r""" + Solve system of $N$ linear equations with $M$ variables, which means + both under- and overdetermined systems are supported. + + Explanation + =========== + + The possible number of solutions is zero, one, or infinite. Respectively, + this procedure will return None or a dictionary with solutions. In the + case of underdetermined systems, all arbitrary parameters are skipped. + This may cause a situation in which an empty dictionary is returned. + In that case, all symbols can be assigned arbitrary values. + + Input to this function is a $N\times M + 1$ matrix, which means it has + to be in augmented form. If you prefer to enter $N$ equations and $M$ + unknowns then use ``solve(Neqs, *Msymbols)`` instead. Note: a local + copy of the matrix is made by this routine so the matrix that is + passed will not be modified. + + The algorithm used here is fraction-free Gaussian elimination, + which results, after elimination, in an upper-triangular matrix. + Then solutions are found using back-substitution. This approach + is more efficient and compact than the Gauss-Jordan method. + + Examples + ======== + + >>> from sympy import Matrix, solve_linear_system + >>> from sympy.abc import x, y + + Solve the following system:: + + x + 4 y == 2 + -2 x + y == 14 + + >>> system = Matrix(( (1, 4, 2), (-2, 1, 14))) + >>> solve_linear_system(system, x, y) + {x: -6, y: 2} + + A degenerate system returns an empty dictionary: + + >>> system = Matrix(( (0,0,0), (0,0,0) )) + >>> solve_linear_system(system, x, y) + {} + + """ + assert system.shape[1] == len(symbols) + 1 + + # This is just a wrapper for solve_lin_sys + eqs = list(system * Matrix(symbols + (-1,))) + eqs, ring = sympy_eqs_to_ring(eqs, symbols) + sol = solve_lin_sys(eqs, ring, _raw=False) + if sol is not None: + sol = {sym:val for sym, val in sol.items() if sym != val} + return sol + + +def solve_undetermined_coeffs(equ, coeffs, *syms, **flags): + r""" + Solve a system of equations in $k$ parameters that is formed by + matching coefficients in variables ``coeffs`` that are on + factors dependent on the remaining variables (or those given + explicitly by ``syms``. + + Explanation + =========== + + The result of this function is a dictionary with symbolic values of those + parameters with respect to coefficients in $q$ -- empty if there + is no solution or coefficients do not appear in the equation -- else + None (if the system was not recognized). If there is more than one + solution, the solutions are passed as a list. The output can be modified using + the same semantics as for `solve` since the flags that are passed are sent + directly to `solve` so, for example the flag ``dict=True`` will always return a list + of solutions as dictionaries. + + This function accepts both Equality and Expr class instances. + The solving process is most efficient when symbols are specified + in addition to parameters to be determined, but an attempt to + determine them (if absent) will be made. If an expected solution is not + obtained (and symbols were not specified) try specifying them. + + Examples + ======== + + >>> from sympy import Eq, solve_undetermined_coeffs + >>> from sympy.abc import a, b, c, h, p, k, x, y + + >>> solve_undetermined_coeffs(Eq(a*x + a + b, x/2), [a, b], x) + {a: 1/2, b: -1/2} + >>> solve_undetermined_coeffs(a - 2, [a]) + {a: 2} + + The equation can be nonlinear in the symbols: + + >>> X, Y, Z = y, x**y, y*x**y + >>> eq = a*X + b*Y + c*Z - X - 2*Y - 3*Z + >>> coeffs = a, b, c + >>> syms = x, y + >>> solve_undetermined_coeffs(eq, coeffs, syms) + {a: 1, b: 2, c: 3} + + And the system can be nonlinear in coefficients, too, but if + there is only a single solution, it will be returned as a + dictionary: + + >>> eq = a*x**2 + b*x + c - ((x - h)**2 + 4*p*k)/4/p + >>> solve_undetermined_coeffs(eq, (h, p, k), x) + {h: -b/(2*a), k: (4*a*c - b**2)/(4*a), p: 1/(4*a)} + + Multiple solutions are always returned in a list: + + >>> solve_undetermined_coeffs(a**2*x + b - x, [a, b], x) + [{a: -1, b: 0}, {a: 1, b: 0}] + + Using flag ``dict=True`` (in keeping with semantics in :func:`~.solve`) + will force the result to always be a list with any solutions + as elements in that list. + + >>> solve_undetermined_coeffs(a*x - 2*x, [a], dict=True) + [{a: 2}] + """ + if not (coeffs and all(i.is_Symbol for i in coeffs)): + raise ValueError('must provide symbols for coeffs') + + if isinstance(equ, Eq): + eq = equ.lhs - equ.rhs + else: + eq = equ + + ceq = cancel(eq) + xeq = _mexpand(ceq.as_numer_denom()[0], recursive=True) + + free = xeq.free_symbols + coeffs = free & set(coeffs) + if not coeffs: + return ([], {}) if flags.get('set', None) else [] # solve(0, x) -> [] + + if not syms: + # e.g. A*exp(x) + B - (exp(x) + y) separated into parts that + # don't/do depend on coeffs gives + # -(exp(x) + y), A*exp(x) + B + # then see what symbols are common to both + # {x} = {x, A, B} - {x, y} + ind, dep = xeq.as_independent(*coeffs, as_Add=True) + dfree = dep.free_symbols + syms = dfree & ind.free_symbols + if not syms: + # but if the system looks like (a + b)*x + b - c + # then {} = {a, b, x} - c + # so calculate {x} = {a, b, x} - {a, b} + syms = dfree - set(coeffs) + if not syms: + syms = [Dummy()] + else: + if len(syms) == 1 and iterable(syms[0]): + syms = syms[0] + e, s, _ = recast_to_symbols([xeq], syms) + xeq = e[0] + syms = s + + # find the functional forms in which symbols appear + + gens = set(xeq.as_coefficients_dict(*syms).keys()) - {1} + cset = set(coeffs) + if any(g.has_xfree(cset) for g in gens): + return # a generator contained a coefficient symbol + + # make sure we are working with symbols for generators + + e, gens, _ = recast_to_symbols([xeq], list(gens)) + xeq = e[0] + + # collect coefficients in front of generators + + system = list(collect(xeq, gens, evaluate=False).values()) + + # get a solution + + soln = solve(system, coeffs, **flags) + + # unpack unless told otherwise if length is 1 + + settings = flags.get('dict', None) or flags.get('set', None) + if type(soln) is dict or settings or len(soln) != 1: + return soln + return soln[0] + + +def solve_linear_system_LU(matrix, syms): + """ + Solves the augmented matrix system using ``LUsolve`` and returns a + dictionary in which solutions are keyed to the symbols of *syms* as ordered. + + Explanation + =========== + + The matrix must be invertible. + + Examples + ======== + + >>> from sympy import Matrix, solve_linear_system_LU + >>> from sympy.abc import x, y, z + + >>> solve_linear_system_LU(Matrix([ + ... [1, 2, 0, 1], + ... [3, 2, 2, 1], + ... [2, 0, 0, 1]]), [x, y, z]) + {x: 1/2, y: 1/4, z: -1/2} + + See Also + ======== + + LUsolve + + """ + if matrix.rows != matrix.cols - 1: + raise ValueError("Rows should be equal to columns - 1") + A = matrix[:matrix.rows, :matrix.rows] + b = matrix[:, matrix.cols - 1:] + soln = A.LUsolve(b) + solutions = {} + for i in range(soln.rows): + solutions[syms[i]] = soln[i, 0] + return solutions + + +def det_perm(M): + """ + Return the determinant of *M* by using permutations to select factors. + + Explanation + =========== + + For sizes larger than 8 the number of permutations becomes prohibitively + large, or if there are no symbols in the matrix, it is better to use the + standard determinant routines (e.g., ``M.det()``.) + + See Also + ======== + + det_minor + det_quick + + """ + args = [] + s = True + n = M.rows + list_ = M.flat() + for perm in generate_bell(n): + fac = [] + idx = 0 + for j in perm: + fac.append(list_[idx + j]) + idx += n + term = Mul(*fac) # disaster with unevaluated Mul -- takes forever for n=7 + args.append(term if s else -term) + s = not s + return Add(*args) + + +def det_minor(M): + """ + Return the ``det(M)`` computed from minors without + introducing new nesting in products. + + See Also + ======== + + det_perm + det_quick + + """ + n = M.rows + if n == 2: + return M[0, 0]*M[1, 1] - M[1, 0]*M[0, 1] + else: + return sum((1, -1)[i % 2]*Add(*[M[0, i]*d for d in + Add.make_args(det_minor(M.minor_submatrix(0, i)))]) + if M[0, i] else S.Zero for i in range(n)) + + +def det_quick(M, method=None): + """ + Return ``det(M)`` assuming that either + there are lots of zeros or the size of the matrix + is small. If this assumption is not met, then the normal + Matrix.det function will be used with method = ``method``. + + See Also + ======== + + det_minor + det_perm + + """ + if any(i.has(Symbol) for i in M): + if M.rows < 8 and all(i.has(Symbol) for i in M): + return det_perm(M) + return det_minor(M) + else: + return M.det(method=method) if method else M.det() + + +def inv_quick(M): + """Return the inverse of ``M``, assuming that either + there are lots of zeros or the size of the matrix + is small. + """ + if not all(i.is_Number for i in M): + if not any(i.is_Number for i in M): + det = lambda _: det_perm(_) + else: + det = lambda _: det_minor(_) + else: + return M.inv() + n = M.rows + d = det(M) + if d == S.Zero: + raise NonInvertibleMatrixError("Matrix det == 0; not invertible") + ret = zeros(n) + s1 = -1 + for i in range(n): + s = s1 = -s1 + for j in range(n): + di = det(M.minor_submatrix(i, j)) + ret[j, i] = s*di/d + s = -s + return ret + + +# these are functions that have multiple inverse values per period +multi_inverses = { + sin: lambda x: (asin(x), S.Pi - asin(x)), + cos: lambda x: (acos(x), 2*S.Pi - acos(x)), +} + + +def _vsolve(e, s, **flags): + """return list of scalar values for the solution of e for symbol s""" + return [i[s] for i in _solve(e, s, **flags)] + + +def _tsolve(eq, sym, **flags): + """ + Helper for ``_solve`` that solves a transcendental equation with respect + to the given symbol. Various equations containing powers and logarithms, + can be solved. + + There is currently no guarantee that all solutions will be returned or + that a real solution will be favored over a complex one. + + Either a list of potential solutions will be returned or None will be + returned (in the case that no method was known to get a solution + for the equation). All other errors (like the inability to cast an + expression as a Poly) are unhandled. + + Examples + ======== + + >>> from sympy import log, ordered + >>> from sympy.solvers.solvers import _tsolve as tsolve + >>> from sympy.abc import x + + >>> list(ordered(tsolve(3**(2*x + 5) - 4, x))) + [-5/2 + log(2)/log(3), (-5*log(3)/2 + log(2) + I*pi)/log(3)] + + >>> tsolve(log(x) + 2*x, x) + [LambertW(2)/2] + + """ + if 'tsolve_saw' not in flags: + flags['tsolve_saw'] = [] + if eq in flags['tsolve_saw']: + return None + else: + flags['tsolve_saw'].append(eq) + + rhs, lhs = _invert(eq, sym) + + if lhs == sym: + return [rhs] + try: + if lhs.is_Add: + # it's time to try factoring; powdenest is used + # to try get powers in standard form for better factoring + f = factor(powdenest(lhs - rhs)) + if f.is_Mul: + return _vsolve(f, sym, **flags) + if rhs: + f = logcombine(lhs, force=flags.get('force', True)) + if f.count(log) != lhs.count(log): + if isinstance(f, log): + return _vsolve(f.args[0] - exp(rhs), sym, **flags) + return _tsolve(f - rhs, sym, **flags) + + elif lhs.is_Pow: + if lhs.exp.is_Integer: + if lhs - rhs != eq: + return _vsolve(lhs - rhs, sym, **flags) + + if sym not in lhs.exp.free_symbols: + return _vsolve(lhs.base - rhs**(1/lhs.exp), sym, **flags) + + # _tsolve calls this with Dummy before passing the actual number in. + if any(t.is_Dummy for t in rhs.free_symbols): + raise NotImplementedError # _tsolve will call here again... + + # a ** g(x) == 0 + if not rhs: + # f(x)**g(x) only has solutions where f(x) == 0 and g(x) != 0 at + # the same place + sol_base = _vsolve(lhs.base, sym, **flags) + return [s for s in sol_base if lhs.exp.subs(sym, s) != 0] # XXX use checksol here? + + # a ** g(x) == b + if not lhs.base.has(sym): + if lhs.base == 0: + return _vsolve(lhs.exp, sym, **flags) if rhs != 0 else [] + + # Gets most solutions... + if lhs.base == rhs.as_base_exp()[0]: + # handles case when bases are equal + sol = _vsolve(lhs.exp - rhs.as_base_exp()[1], sym, **flags) + else: + # handles cases when bases are not equal and exp + # may or may not be equal + f = exp(log(lhs.base)*lhs.exp) - exp(log(rhs)) + sol = _vsolve(f, sym, **flags) + + # Check for duplicate solutions + def equal(expr1, expr2): + _ = Dummy() + eq = checksol(expr1 - _, _, expr2) + if eq is None: + if nsimplify(expr1) != nsimplify(expr2): + return False + # they might be coincidentally the same + # so check more rigorously + eq = expr1.equals(expr2) # XXX expensive but necessary? + return eq + + # Guess a rational exponent + e_rat = nsimplify(log(abs(rhs))/log(abs(lhs.base))) + e_rat = simplify(posify(e_rat)[0]) + n, d = fraction(e_rat) + if expand(lhs.base**n - rhs**d) == 0: + sol = [s for s in sol if not equal(lhs.exp.subs(sym, s), e_rat)] + sol.extend(_vsolve(lhs.exp - e_rat, sym, **flags)) + + return list(set(sol)) + + # f(x) ** g(x) == c + else: + sol = [] + logform = lhs.exp*log(lhs.base) - log(rhs) + if logform != lhs - rhs: + try: + sol.extend(_vsolve(logform, sym, **flags)) + except NotImplementedError: + pass + + # Collect possible solutions and check with substitution later. + check = [] + if rhs == 1: + # f(x) ** g(x) = 1 -- g(x)=0 or f(x)=+-1 + check.extend(_vsolve(lhs.exp, sym, **flags)) + check.extend(_vsolve(lhs.base - 1, sym, **flags)) + check.extend(_vsolve(lhs.base + 1, sym, **flags)) + elif rhs.is_Rational: + for d in (i for i in divisors(abs(rhs.p)) if i != 1): + e, t = integer_log(rhs.p, d) + if not t: + continue # rhs.p != d**b + for s in divisors(abs(rhs.q)): + if s**e== rhs.q: + r = Rational(d, s) + check.extend(_vsolve(lhs.base - r, sym, **flags)) + check.extend(_vsolve(lhs.base + r, sym, **flags)) + check.extend(_vsolve(lhs.exp - e, sym, **flags)) + elif rhs.is_irrational: + b_l, e_l = lhs.base.as_base_exp() + n, d = (e_l*lhs.exp).as_numer_denom() + b, e = sqrtdenest(rhs).as_base_exp() + check = [sqrtdenest(i) for i in (_vsolve(lhs.base - b, sym, **flags))] + check.extend([sqrtdenest(i) for i in (_vsolve(lhs.exp - e, sym, **flags))]) + if e_l*d != 1: + check.extend(_vsolve(b_l**n - rhs**(e_l*d), sym, **flags)) + for s in check: + ok = checksol(eq, sym, s) + if ok is None: + ok = eq.subs(sym, s).equals(0) + if ok: + sol.append(s) + return list(set(sol)) + + elif lhs.is_Function and len(lhs.args) == 1: + if lhs.func in multi_inverses: + # sin(x) = 1/3 -> x - asin(1/3) & x - (pi - asin(1/3)) + soln = [] + for i in multi_inverses[type(lhs)](rhs): + soln.extend(_vsolve(lhs.args[0] - i, sym, **flags)) + return list(set(soln)) + elif lhs.func == LambertW: + return _vsolve(lhs.args[0] - rhs*exp(rhs), sym, **flags) + + rewrite = lhs.rewrite(exp) + rewrite = rebuild(rewrite) # avoid rewrites involving evaluate=False + if rewrite != lhs: + return _vsolve(rewrite - rhs, sym, **flags) + except NotImplementedError: + pass + + # maybe it is a lambert pattern + if flags.pop('bivariate', True): + # lambert forms may need some help being recognized, e.g. changing + # 2**(3*x) + x**3*log(2)**3 + 3*x**2*log(2)**2 + 3*x*log(2) + 1 + # to 2**(3*x) + (x*log(2) + 1)**3 + + # make generator in log have exponent of 1 + logs = eq.atoms(log) + spow = min( + {i.exp for j in logs for i in j.atoms(Pow) + if i.base == sym} or {1}) + if spow != 1: + p = sym**spow + u = Dummy('bivariate-cov') + ueq = eq.subs(p, u) + if not ueq.has_free(sym): + sol = _vsolve(ueq, u, **flags) + inv = _vsolve(p - u, sym) + return [i.subs(u, s) for i in inv for s in sol] + + g = _filtered_gens(eq.as_poly(), sym) + up_or_log = set() + for gi in g: + if isinstance(gi, (exp, log)) or (gi.is_Pow and gi.base == S.Exp1): + up_or_log.add(gi) + elif gi.is_Pow: + gisimp = powdenest(expand_power_exp(gi)) + if gisimp.is_Pow and sym in gisimp.exp.free_symbols: + up_or_log.add(gi) + eq_down = expand_log(expand_power_exp(eq)).subs( + dict(list(zip(up_or_log, [0]*len(up_or_log))))) + eq = expand_power_exp(factor(eq_down, deep=True) + (eq - eq_down)) + rhs, lhs = _invert(eq, sym) + if lhs.has(sym): + try: + poly = lhs.as_poly() + g = _filtered_gens(poly, sym) + _eq = lhs - rhs + sols = _solve_lambert(_eq, sym, g) + # use a simplified form if it satisfies eq + # and has fewer operations + for n, s in enumerate(sols): + ns = nsimplify(s) + if ns != s and ns.count_ops() <= s.count_ops(): + ok = checksol(_eq, sym, ns) + if ok is None: + ok = _eq.subs(sym, ns).equals(0) + if ok: + sols[n] = ns + return sols + except NotImplementedError: + # maybe it's a convoluted function + if len(g) == 2: + try: + gpu = bivariate_type(lhs - rhs, *g) + if gpu is None: + raise NotImplementedError + g, p, u = gpu + flags['bivariate'] = False + inversion = _tsolve(g - u, sym, **flags) + if inversion: + sol = _vsolve(p, u, **flags) + return list({i.subs(u, s) + for i in inversion for s in sol}) + except NotImplementedError: + pass + else: + pass + + if flags.pop('force', True): + flags['force'] = False + pos, reps = posify(lhs - rhs) + if rhs == S.ComplexInfinity: + return [] + for u, s in reps.items(): + if s == sym: + break + else: + u = sym + if pos.has(u): + try: + soln = _vsolve(pos, u, **flags) + return [s.subs(reps) for s in soln] + except NotImplementedError: + pass + else: + pass # here for coverage + + return # here for coverage + + +# TODO: option for calculating J numerically + +@conserve_mpmath_dps +def nsolve(*args, dict=False, **kwargs): + r""" + Solve a nonlinear equation system numerically: ``nsolve(f, [args,] x0, + modules=['mpmath'], **kwargs)``. + + Explanation + =========== + + ``f`` is a vector function of symbolic expressions representing the system. + *args* are the variables. If there is only one variable, this argument can + be omitted. ``x0`` is a starting vector close to a solution. + + Use the modules keyword to specify which modules should be used to + evaluate the function and the Jacobian matrix. Make sure to use a module + that supports matrices. For more information on the syntax, please see the + docstring of ``lambdify``. + + If the keyword arguments contain ``dict=True`` (default is False) ``nsolve`` + will return a list (perhaps empty) of solution mappings. This might be + especially useful if you want to use ``nsolve`` as a fallback to solve since + using the dict argument for both methods produces return values of + consistent type structure. Please note: to keep this consistent with + ``solve``, the solution will be returned in a list even though ``nsolve`` + (currently at least) only finds one solution at a time. + + Overdetermined systems are supported. + + Examples + ======== + + >>> from sympy import Symbol, nsolve + >>> import mpmath + >>> mpmath.mp.dps = 15 + >>> x1 = Symbol('x1') + >>> x2 = Symbol('x2') + >>> f1 = 3 * x1**2 - 2 * x2**2 - 1 + >>> f2 = x1**2 - 2 * x1 + x2**2 + 2 * x2 - 8 + >>> print(nsolve((f1, f2), (x1, x2), (-1, 1))) + Matrix([[-1.19287309935246], [1.27844411169911]]) + + For one-dimensional functions the syntax is simplified: + + >>> from sympy import sin, nsolve + >>> from sympy.abc import x + >>> nsolve(sin(x), x, 2) + 3.14159265358979 + >>> nsolve(sin(x), 2) + 3.14159265358979 + + To solve with higher precision than the default, use the prec argument: + + >>> from sympy import cos + >>> nsolve(cos(x) - x, 1) + 0.739085133215161 + >>> nsolve(cos(x) - x, 1, prec=50) + 0.73908513321516064165531208767387340401341175890076 + >>> cos(_) + 0.73908513321516064165531208767387340401341175890076 + + To solve for complex roots of real functions, a nonreal initial point + must be specified: + + >>> from sympy import I + >>> nsolve(x**2 + 2, I) + 1.4142135623731*I + + ``mpmath.findroot`` is used and you can find their more extensive + documentation, especially concerning keyword parameters and + available solvers. Note, however, that functions which are very + steep near the root, the verification of the solution may fail. In + this case you should use the flag ``verify=False`` and + independently verify the solution. + + >>> from sympy import cos, cosh + >>> f = cos(x)*cosh(x) - 1 + >>> nsolve(f, 3.14*100) + Traceback (most recent call last): + ... + ValueError: Could not find root within given tolerance. (1.39267e+230 > 2.1684e-19) + >>> ans = nsolve(f, 3.14*100, verify=False); ans + 312.588469032184 + >>> f.subs(x, ans).n(2) + 2.1e+121 + >>> (f/f.diff(x)).subs(x, ans).n(2) + 7.4e-15 + + One might safely skip the verification if bounds of the root are known + and a bisection method is used: + + >>> bounds = lambda i: (3.14*i, 3.14*(i + 1)) + >>> nsolve(f, bounds(100), solver='bisect', verify=False) + 315.730061685774 + + Alternatively, a function may be better behaved when the + denominator is ignored. Since this is not always the case, however, + the decision of what function to use is left to the discretion of + the user. + + >>> eq = x**2/(1 - x)/(1 - 2*x)**2 - 100 + >>> nsolve(eq, 0.46) + Traceback (most recent call last): + ... + ValueError: Could not find root within given tolerance. (10000 > 2.1684e-19) + Try another starting point or tweak arguments. + >>> nsolve(eq.as_numer_denom()[0], 0.46) + 0.46792545969349058 + + """ + # there are several other SymPy functions that use method= so + # guard against that here + if 'method' in kwargs: + raise ValueError(filldedent(''' + Keyword "method" should not be used in this context. When using + some mpmath solvers directly, the keyword "method" is + used, but when using nsolve (and findroot) the keyword to use is + "solver".''')) + + if 'prec' in kwargs: + import mpmath + mpmath.mp.dps = kwargs.pop('prec') + + # keyword argument to return result as a dictionary + as_dict = dict + from builtins import dict # to unhide the builtin + + # interpret arguments + if len(args) == 3: + f = args[0] + fargs = args[1] + x0 = args[2] + if iterable(fargs) and iterable(x0): + if len(x0) != len(fargs): + raise TypeError('nsolve expected exactly %i guess vectors, got %i' + % (len(fargs), len(x0))) + elif len(args) == 2: + f = args[0] + fargs = None + x0 = args[1] + if iterable(f): + raise TypeError('nsolve expected 3 arguments, got 2') + elif len(args) < 2: + raise TypeError('nsolve expected at least 2 arguments, got %i' + % len(args)) + else: + raise TypeError('nsolve expected at most 3 arguments, got %i' + % len(args)) + modules = kwargs.get('modules', ['mpmath']) + if iterable(f): + f = list(f) + for i, fi in enumerate(f): + if isinstance(fi, Eq): + f[i] = fi.lhs - fi.rhs + f = Matrix(f).T + if iterable(x0): + x0 = list(x0) + if not isinstance(f, Matrix): + # assume it's a SymPy expression + if isinstance(f, Eq): + f = f.lhs - f.rhs + elif f.is_Relational: + raise TypeError('nsolve cannot accept inequalities') + syms = f.free_symbols + if fargs is None: + fargs = syms.copy().pop() + if not (len(syms) == 1 and (fargs in syms or fargs[0] in syms)): + raise ValueError(filldedent(''' + expected a one-dimensional and numerical function''')) + + # the function is much better behaved if there is no denominator + # but sending the numerator is left to the user since sometimes + # the function is better behaved when the denominator is present + # e.g., issue 11768 + + f = lambdify(fargs, f, modules) + x = sympify(findroot(f, x0, **kwargs)) + if as_dict: + return [{fargs: x}] + return x + + if len(fargs) > f.cols: + raise NotImplementedError(filldedent(''' + need at least as many equations as variables''')) + verbose = kwargs.get('verbose', False) + if verbose: + print('f(x):') + print(f) + # derive Jacobian + J = f.jacobian(fargs) + if verbose: + print('J(x):') + print(J) + # create functions + f = lambdify(fargs, f.T, modules) + J = lambdify(fargs, J, modules) + # solve the system numerically + x = findroot(f, x0, J=J, **kwargs) + if as_dict: + return [dict(zip(fargs, [sympify(xi) for xi in x]))] + return Matrix(x) + + +def _invert(eq, *symbols, **kwargs): + """ + Return tuple (i, d) where ``i`` is independent of *symbols* and ``d`` + contains symbols. + + Explanation + =========== + + ``i`` and ``d`` are obtained after recursively using algebraic inversion + until an uninvertible ``d`` remains. If there are no free symbols then + ``d`` will be zero. Some (but not necessarily all) solutions to the + expression ``i - d`` will be related to the solutions of the original + expression. + + Examples + ======== + + >>> from sympy.solvers.solvers import _invert as invert + >>> from sympy import sqrt, cos + >>> from sympy.abc import x, y + >>> invert(x - 3) + (3, x) + >>> invert(3) + (3, 0) + >>> invert(2*cos(x) - 1) + (1/2, cos(x)) + >>> invert(sqrt(x) - 3) + (3, sqrt(x)) + >>> invert(sqrt(x) + y, x) + (-y, sqrt(x)) + >>> invert(sqrt(x) + y, y) + (-sqrt(x), y) + >>> invert(sqrt(x) + y, x, y) + (0, sqrt(x) + y) + + If there is more than one symbol in a power's base and the exponent + is not an Integer, then the principal root will be used for the + inversion: + + >>> invert(sqrt(x + y) - 2) + (4, x + y) + >>> invert(sqrt(x + y) + 2) # note +2 instead of -2 + (4, x + y) + + If the exponent is an Integer, setting ``integer_power`` to True + will force the principal root to be selected: + + >>> invert(x**2 - 4, integer_power=True) + (2, x) + + """ + eq = sympify(eq) + if eq.args: + # make sure we are working with flat eq + eq = eq.func(*eq.args) + free = eq.free_symbols + if not symbols: + symbols = free + if not free & set(symbols): + return eq, S.Zero + + dointpow = bool(kwargs.get('integer_power', False)) + + lhs = eq + rhs = S.Zero + while True: + was = lhs + while True: + indep, dep = lhs.as_independent(*symbols) + + # dep + indep == rhs + if lhs.is_Add: + # this indicates we have done it all + if indep.is_zero: + break + + lhs = dep + rhs -= indep + + # dep * indep == rhs + else: + # this indicates we have done it all + if indep is S.One: + break + + lhs = dep + rhs /= indep + + # collect like-terms in symbols + if lhs.is_Add: + terms = {} + for a in lhs.args: + i, d = a.as_independent(*symbols) + terms.setdefault(d, []).append(i) + if any(len(v) > 1 for v in terms.values()): + args = [] + for d, i in terms.items(): + if len(i) > 1: + args.append(Add(*i)*d) + else: + args.append(i[0]*d) + lhs = Add(*args) + + # if it's a two-term Add with rhs = 0 and two powers we can get the + # dependent terms together, e.g. 3*f(x) + 2*g(x) -> f(x)/g(x) = -2/3 + if lhs.is_Add and not rhs and len(lhs.args) == 2 and \ + not lhs.is_polynomial(*symbols): + a, b = ordered(lhs.args) + ai, ad = a.as_independent(*symbols) + bi, bd = b.as_independent(*symbols) + if any(_ispow(i) for i in (ad, bd)): + a_base, a_exp = ad.as_base_exp() + b_base, b_exp = bd.as_base_exp() + if a_base == b_base and a_exp.extract_additively(b_exp) is None: + # a = -b and exponents do not have canceling terms/factors + # e.g. if exponents were 3*x and x then the ratio would have + # an exponent of 2*x: one of the roots would be lost + rat = powsimp(powdenest(ad/bd)) + lhs = rat + rhs = -bi/ai + else: + rat = ad/bd + _lhs = powsimp(ad/bd) + if _lhs != rat: + lhs = _lhs + rhs = -bi/ai + elif ai == -bi: + if isinstance(ad, Function) and ad.func == bd.func: + if len(ad.args) == len(bd.args) == 1: + lhs = ad.args[0] - bd.args[0] + elif len(ad.args) == len(bd.args): + # should be able to solve + # f(x, y) - f(2 - x, 0) == 0 -> x == 1 + raise NotImplementedError( + 'equal function with more than 1 argument') + else: + raise ValueError( + 'function with different numbers of args') + + elif lhs.is_Mul and any(_ispow(a) for a in lhs.args): + lhs = powsimp(powdenest(lhs)) + + if lhs.is_Function: + if hasattr(lhs, 'inverse') and lhs.inverse() is not None and len(lhs.args) == 1: + # -1 + # f(x) = g -> x = f (g) + # + # /!\ inverse should not be defined if there are multiple values + # for the function -- these are handled in _tsolve + # + rhs = lhs.inverse()(rhs) + lhs = lhs.args[0] + elif isinstance(lhs, atan2): + y, x = lhs.args + lhs = 2*atan(y/(sqrt(x**2 + y**2) + x)) + elif lhs.func == rhs.func: + if len(lhs.args) == len(rhs.args) == 1: + lhs = lhs.args[0] + rhs = rhs.args[0] + elif len(lhs.args) == len(rhs.args): + # should be able to solve + # f(x, y) == f(2, 3) -> x == 2 + # f(x, x + y) == f(2, 3) -> x == 2 + raise NotImplementedError( + 'equal function with more than 1 argument') + else: + raise ValueError( + 'function with different numbers of args') + + + if rhs and lhs.is_Pow and lhs.exp.is_Integer and lhs.exp < 0: + lhs = 1/lhs + rhs = 1/rhs + + # base**a = b -> base = b**(1/a) if + # a is an Integer and dointpow=True (this gives real branch of root) + # a is not an Integer and the equation is multivariate and the + # base has more than 1 symbol in it + # The rationale for this is that right now the multi-system solvers + # doesn't try to resolve generators to see, for example, if the whole + # system is written in terms of sqrt(x + y) so it will just fail, so we + # do that step here. + if lhs.is_Pow and ( + lhs.exp.is_Integer and dointpow or not lhs.exp.is_Integer and + len(symbols) > 1 and len(lhs.base.free_symbols & set(symbols)) > 1): + rhs = rhs**(1/lhs.exp) + lhs = lhs.base + + if lhs == was: + break + return rhs, lhs + + +def unrad(eq, *syms, **flags): + """ + Remove radicals with symbolic arguments and return (eq, cov), + None, or raise an error. + + Explanation + =========== + + None is returned if there are no radicals to remove. + + NotImplementedError is raised if there are radicals and they cannot be + removed or if the relationship between the original symbols and the + change of variable needed to rewrite the system as a polynomial cannot + be solved. + + Otherwise the tuple, ``(eq, cov)``, is returned where: + + *eq*, ``cov`` + *eq* is an equation without radicals (in the symbol(s) of + interest) whose solutions are a superset of the solutions to the + original expression. *eq* might be rewritten in terms of a new + variable; the relationship to the original variables is given by + ``cov`` which is a list containing ``v`` and ``v**p - b`` where + ``p`` is the power needed to clear the radical and ``b`` is the + radical now expressed as a polynomial in the symbols of interest. + For example, for sqrt(2 - x) the tuple would be + ``(c, c**2 - 2 + x)``. The solutions of *eq* will contain + solutions to the original equation (if there are any). + + *syms* + An iterable of symbols which, if provided, will limit the focus of + radical removal: only radicals with one or more of the symbols of + interest will be cleared. All free symbols are used if *syms* is not + set. + + *flags* are used internally for communication during recursive calls. + Two options are also recognized: + + ``take``, when defined, is interpreted as a single-argument function + that returns True if a given Pow should be handled. + + Radicals can be removed from an expression if: + + * All bases of the radicals are the same; a change of variables is + done in this case. + * If all radicals appear in one term of the expression. + * There are only four terms with sqrt() factors or there are less than + four terms having sqrt() factors. + * There are only two terms with radicals. + + Examples + ======== + + >>> from sympy.solvers.solvers import unrad + >>> from sympy.abc import x + >>> from sympy import sqrt, Rational, root + + >>> unrad(sqrt(x)*x**Rational(1, 3) + 2) + (x**5 - 64, []) + >>> unrad(sqrt(x) + root(x + 1, 3)) + (-x**3 + x**2 + 2*x + 1, []) + >>> eq = sqrt(x) + root(x, 3) - 2 + >>> unrad(eq) + (_p**3 + _p**2 - 2, [_p, _p**6 - x]) + + """ + + uflags = {"check": False, "simplify": False} + + def _cov(p, e): + if cov: + # XXX - uncovered + oldp, olde = cov + if Poly(e, p).degree(p) in (1, 2): + cov[:] = [p, olde.subs(oldp, _vsolve(e, p, **uflags)[0])] + else: + raise NotImplementedError + else: + cov[:] = [p, e] + + def _canonical(eq, cov): + if cov: + # change symbol to vanilla so no solutions are eliminated + p, e = cov + rep = {p: Dummy(p.name)} + eq = eq.xreplace(rep) + cov = [p.xreplace(rep), e.xreplace(rep)] + + # remove constants and powers of factors since these don't change + # the location of the root; XXX should factor or factor_terms be used? + eq = factor_terms(_mexpand(eq.as_numer_denom()[0], recursive=True), clear=True) + if eq.is_Mul: + args = [] + for f in eq.args: + if f.is_number: + continue + if f.is_Pow: + args.append(f.base) + else: + args.append(f) + eq = Mul(*args) # leave as Mul for more efficient solving + + # make the sign canonical + margs = list(Mul.make_args(eq)) + changed = False + for i, m in enumerate(margs): + if m.could_extract_minus_sign(): + margs[i] = -m + changed = True + if changed: + eq = Mul(*margs, evaluate=False) + + return eq, cov + + def _Q(pow): + # return leading Rational of denominator of Pow's exponent + c = pow.as_base_exp()[1].as_coeff_Mul()[0] + if not c.is_Rational: + return S.One + return c.q + + # define the _take method that will determine whether a term is of interest + def _take(d): + # return True if coefficient of any factor's exponent's den is not 1 + for pow in Mul.make_args(d): + if not pow.is_Pow: + continue + if _Q(pow) == 1: + continue + if pow.free_symbols & syms: + return True + return False + _take = flags.setdefault('_take', _take) + + if isinstance(eq, Eq): + eq = eq.lhs - eq.rhs # XXX legacy Eq as Eqn support + elif not isinstance(eq, Expr): + return + + cov, nwas, rpt = [flags.setdefault(k, v) for k, v in + sorted({"cov": [], "n": None, "rpt": 0}.items())] + + # preconditioning + eq = powdenest(factor_terms(eq, radical=True, clear=True)) + eq = eq.as_numer_denom()[0] + eq = _mexpand(eq, recursive=True) + if eq.is_number: + return + + # see if there are radicals in symbols of interest + syms = set(syms) or eq.free_symbols # _take uses this + poly = eq.as_poly() + gens = [g for g in poly.gens if _take(g)] + if not gens: + return + + # recast poly in terms of eigen-gens + poly = eq.as_poly(*gens) + + # not a polynomial e.g. 1 + sqrt(x)*exp(sqrt(x)) with gen sqrt(x) + if poly is None: + return + + # - an exponent has a symbol of interest (don't handle) + if any(g.exp.has(*syms) for g in gens): + return + + def _rads_bases_lcm(poly): + # if all the bases are the same or all the radicals are in one + # term, `lcm` will be the lcm of the denominators of the + # exponents of the radicals + lcm = 1 + rads = set() + bases = set() + for g in poly.gens: + q = _Q(g) + if q != 1: + rads.add(g) + lcm = ilcm(lcm, q) + bases.add(g.base) + return rads, bases, lcm + rads, bases, lcm = _rads_bases_lcm(poly) + + covsym = Dummy('p', nonnegative=True) + + # only keep in syms symbols that actually appear in radicals; + # and update gens + newsyms = set() + for r in rads: + newsyms.update(syms & r.free_symbols) + if newsyms != syms: + syms = newsyms + # get terms together that have common generators + drad = dict(zip(rads, range(len(rads)))) + rterms = {(): []} + args = Add.make_args(poly.as_expr()) + for t in args: + if _take(t): + common = set(t.as_poly().gens).intersection(rads) + key = tuple(sorted([drad[i] for i in common])) + else: + key = () + rterms.setdefault(key, []).append(t) + others = Add(*rterms.pop(())) + rterms = [Add(*rterms[k]) for k in rterms.keys()] + + # the output will depend on the order terms are processed, so + # make it canonical quickly + rterms = list(reversed(list(ordered(rterms)))) + + ok = False # we don't have a solution yet + depth = sqrt_depth(eq) + + if len(rterms) == 1 and not (rterms[0].is_Add and lcm > 2): + eq = rterms[0]**lcm - ((-others)**lcm) + ok = True + else: + if len(rterms) == 1 and rterms[0].is_Add: + rterms = list(rterms[0].args) + if len(bases) == 1: + b = bases.pop() + if len(syms) > 1: + x = b.free_symbols + else: + x = syms + x = list(ordered(x))[0] + try: + inv = _vsolve(covsym**lcm - b, x, **uflags) + if not inv: + raise NotImplementedError + eq = poly.as_expr().subs(b, covsym**lcm).subs(x, inv[0]) + _cov(covsym, covsym**lcm - b) + return _canonical(eq, cov) + except NotImplementedError: + pass + + if len(rterms) == 2: + if not others: + eq = rterms[0]**lcm - (-rterms[1])**lcm + ok = True + elif not log(lcm, 2).is_Integer: + # the lcm-is-power-of-two case is handled below + r0, r1 = rterms + if flags.get('_reverse', False): + r1, r0 = r0, r1 + i0 = _rads0, _bases0, lcm0 = _rads_bases_lcm(r0.as_poly()) + i1 = _rads1, _bases1, lcm1 = _rads_bases_lcm(r1.as_poly()) + for reverse in range(2): + if reverse: + i0, i1 = i1, i0 + r0, r1 = r1, r0 + _rads1, _, lcm1 = i1 + _rads1 = Mul(*_rads1) + t1 = _rads1**lcm1 + c = covsym**lcm1 - t1 + for x in syms: + try: + sol = _vsolve(c, x, **uflags) + if not sol: + raise NotImplementedError + neweq = r0.subs(x, sol[0]) + covsym*r1/_rads1 + \ + others + tmp = unrad(neweq, covsym) + if tmp: + eq, newcov = tmp + if newcov: + newp, newc = newcov + _cov(newp, c.subs(covsym, + _vsolve(newc, covsym, **uflags)[0])) + else: + _cov(covsym, c) + else: + eq = neweq + _cov(covsym, c) + ok = True + break + except NotImplementedError: + if reverse: + raise NotImplementedError( + 'no successful change of variable found') + else: + pass + if ok: + break + elif len(rterms) == 3: + # two cube roots and another with order less than 5 + # (so an analytical solution can be found) or a base + # that matches one of the cube root bases + info = [_rads_bases_lcm(i.as_poly()) for i in rterms] + RAD = 0 + BASES = 1 + LCM = 2 + if info[0][LCM] != 3: + info.append(info.pop(0)) + rterms.append(rterms.pop(0)) + elif info[1][LCM] != 3: + info.append(info.pop(1)) + rterms.append(rterms.pop(1)) + if info[0][LCM] == info[1][LCM] == 3: + if info[1][BASES] != info[2][BASES]: + info[0], info[1] = info[1], info[0] + rterms[0], rterms[1] = rterms[1], rterms[0] + if info[1][BASES] == info[2][BASES]: + eq = rterms[0]**3 + (rterms[1] + rterms[2] + others)**3 + ok = True + elif info[2][LCM] < 5: + # a*root(A, 3) + b*root(B, 3) + others = c + a, b, c, d, A, B = [Dummy(i) for i in 'abcdAB'] + # zz represents the unraded expression into which the + # specifics for this case are substituted + zz = (c - d)*(A**3*a**9 + 3*A**2*B*a**6*b**3 - + 3*A**2*a**6*c**3 + 9*A**2*a**6*c**2*d - 9*A**2*a**6*c*d**2 + + 3*A**2*a**6*d**3 + 3*A*B**2*a**3*b**6 + 21*A*B*a**3*b**3*c**3 - + 63*A*B*a**3*b**3*c**2*d + 63*A*B*a**3*b**3*c*d**2 - + 21*A*B*a**3*b**3*d**3 + 3*A*a**3*c**6 - 18*A*a**3*c**5*d + + 45*A*a**3*c**4*d**2 - 60*A*a**3*c**3*d**3 + 45*A*a**3*c**2*d**4 - + 18*A*a**3*c*d**5 + 3*A*a**3*d**6 + B**3*b**9 - 3*B**2*b**6*c**3 + + 9*B**2*b**6*c**2*d - 9*B**2*b**6*c*d**2 + 3*B**2*b**6*d**3 + + 3*B*b**3*c**6 - 18*B*b**3*c**5*d + 45*B*b**3*c**4*d**2 - + 60*B*b**3*c**3*d**3 + 45*B*b**3*c**2*d**4 - 18*B*b**3*c*d**5 + + 3*B*b**3*d**6 - c**9 + 9*c**8*d - 36*c**7*d**2 + 84*c**6*d**3 - + 126*c**5*d**4 + 126*c**4*d**5 - 84*c**3*d**6 + 36*c**2*d**7 - + 9*c*d**8 + d**9) + def _t(i): + b = Mul(*info[i][RAD]) + return cancel(rterms[i]/b), Mul(*info[i][BASES]) + aa, AA = _t(0) + bb, BB = _t(1) + cc = -rterms[2] + dd = others + eq = zz.xreplace(dict(zip( + (a, A, b, B, c, d), + (aa, AA, bb, BB, cc, dd)))) + ok = True + # handle power-of-2 cases + if not ok: + if log(lcm, 2).is_Integer and (not others and + len(rterms) == 4 or len(rterms) < 4): + def _norm2(a, b): + return a**2 + b**2 + 2*a*b + + if len(rterms) == 4: + # (r0+r1)**2 - (r2+r3)**2 + r0, r1, r2, r3 = rterms + eq = _norm2(r0, r1) - _norm2(r2, r3) + ok = True + elif len(rterms) == 3: + # (r1+r2)**2 - (r0+others)**2 + r0, r1, r2 = rterms + eq = _norm2(r1, r2) - _norm2(r0, others) + ok = True + elif len(rterms) == 2: + # r0**2 - (r1+others)**2 + r0, r1 = rterms + eq = r0**2 - _norm2(r1, others) + ok = True + + new_depth = sqrt_depth(eq) if ok else depth + rpt += 1 # XXX how many repeats with others unchanging is enough? + if not ok or ( + nwas is not None and len(rterms) == nwas and + new_depth is not None and new_depth == depth and + rpt > 3): + raise NotImplementedError('Cannot remove all radicals') + + flags.update({"cov": cov, "n": len(rterms), "rpt": rpt}) + neq = unrad(eq, *syms, **flags) + if neq: + eq, cov = neq + eq, cov = _canonical(eq, cov) + return eq, cov + + +# delayed imports +from sympy.solvers.bivariate import ( + bivariate_type, _solve_lambert, _filtered_gens) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/solveset.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/solveset.py new file mode 100644 index 0000000000000000000000000000000000000000..0ae242d9c8c4c0d1c1c46cd968a0c5e547ff0f66 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/solveset.py @@ -0,0 +1,4131 @@ +""" +This module contains functions to: + + - solve a single equation for a single variable, in any domain either real or complex. + + - solve a single transcendental equation for a single variable in any domain either real or complex. + (currently supports solving in real domain only) + + - solve a system of linear equations with N variables and M equations. + + - solve a system of Non Linear Equations with N variables and M equations +""" +from sympy.core.sympify import sympify +from sympy.core import (S, Pow, Dummy, pi, Expr, Wild, Mul, + Add, Basic) +from sympy.core.containers import Tuple +from sympy.core.function import (Lambda, expand_complex, AppliedUndef, + expand_log, _mexpand, expand_trig, nfloat) +from sympy.core.mod import Mod +from sympy.core.numbers import I, Number, Rational, oo +from sympy.core.intfunc import integer_log +from sympy.core.relational import Eq, Ne, Relational +from sympy.core.sorting import default_sort_key, ordered +from sympy.core.symbol import Symbol, _uniquely_named_symbol +from sympy.core.sympify import _sympify +from sympy.core.traversal import preorder_traversal +from sympy.external.gmpy import gcd as number_gcd, lcm as number_lcm +from sympy.polys.matrices.linsolve import _linear_eq_to_dict +from sympy.polys.polyroots import UnsolvableFactorError +from sympy.simplify.simplify import simplify, fraction, trigsimp, nsimplify +from sympy.simplify import powdenest, logcombine +from sympy.functions import (log, tan, cot, sin, cos, sec, csc, exp, + acos, asin, atan, acot, acsc, asec, + piecewise_fold, Piecewise) +from sympy.functions.combinatorial.numbers import totient +from sympy.functions.elementary.complexes import Abs, arg, re, im +from sympy.functions.elementary.hyperbolic import (HyperbolicFunction, + sinh, cosh, tanh, coth, sech, csch, + asinh, acosh, atanh, acoth, asech, acsch) +from sympy.functions.elementary.miscellaneous import real_root +from sympy.functions.elementary.trigonometric import TrigonometricFunction +from sympy.logic.boolalg import And, BooleanTrue +from sympy.sets import (FiniteSet, imageset, Interval, Intersection, + Union, ConditionSet, ImageSet, Complement, Contains) +from sympy.sets.sets import Set, ProductSet +from sympy.matrices import zeros, Matrix, MatrixBase +from sympy.ntheory.factor_ import divisors +from sympy.ntheory.residue_ntheory import discrete_log, nthroot_mod +from sympy.polys import (roots, Poly, degree, together, PolynomialError, + RootOf, factor, lcm, gcd) +from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.polytools import invert, groebner, poly +from sympy.polys.solvers import (sympy_eqs_to_ring, solve_lin_sys, + PolyNonlinearError) +from sympy.polys.matrices.linsolve import _linsolve +from sympy.solvers.solvers import (checksol, denoms, unrad, + _simple_dens, recast_to_symbols) +from sympy.solvers.polysys import solve_poly_system +from sympy.utilities import filldedent +from sympy.utilities.iterables import (numbered_symbols, has_dups, + is_sequence, iterable) +from sympy.calculus.util import periodicity, continuous_domain, function_range + + +from types import GeneratorType + + +class NonlinearError(ValueError): + """Raised when unexpectedly encountering nonlinear equations""" + pass + + +def _masked(f, *atoms): + """Return ``f``, with all objects given by ``atoms`` replaced with + Dummy symbols, ``d``, and the list of replacements, ``(d, e)``, + where ``e`` is an object of type given by ``atoms`` in which + any other instances of atoms have been recursively replaced with + Dummy symbols, too. The tuples are ordered so that if they are + applied in sequence, the origin ``f`` will be restored. + + Examples + ======== + + >>> from sympy import cos + >>> from sympy.abc import x + >>> from sympy.solvers.solveset import _masked + + >>> f = cos(cos(x) + 1) + >>> f, reps = _masked(cos(1 + cos(x)), cos) + >>> f + _a1 + >>> reps + [(_a1, cos(_a0 + 1)), (_a0, cos(x))] + >>> for d, e in reps: + ... f = f.xreplace({d: e}) + >>> f + cos(cos(x) + 1) + """ + sym = numbered_symbols('a', cls=Dummy, real=True) + mask = [] + for a in ordered(f.atoms(*atoms)): + for i in mask: + a = a.replace(*i) + mask.append((a, next(sym))) + for i, (o, n) in enumerate(mask): + f = f.replace(o, n) + mask[i] = (n, o) + mask = list(reversed(mask)) + return f, mask + + +def _invert(f_x, y, x, domain=S.Complexes): + r""" + Reduce the complex valued equation $f(x) = y$ to a set of equations + + $$\left\{g(x) = h_1(y),\ g(x) = h_2(y),\ \dots,\ g(x) = h_n(y) \right\}$$ + + where $g(x)$ is a simpler function than $f(x)$. The return value is a tuple + $(g(x), \mathrm{set}_h)$, where $g(x)$ is a function of $x$ and $\mathrm{set}_h$ is + the set of function $\left\{h_1(y), h_2(y), \dots, h_n(y)\right\}$. + Here, $y$ is not necessarily a symbol. + + $\mathrm{set}_h$ contains the functions, along with the information + about the domain in which they are valid, through set + operations. For instance, if :math:`y = |x| - n` is inverted + in the real domain, then $\mathrm{set}_h$ is not simply + $\{-n, n\}$ as the nature of `n` is unknown; rather, it is: + + $$ \left(\left[0, \infty\right) \cap \left\{n\right\}\right) \cup + \left(\left(-\infty, 0\right] \cap \left\{- n\right\}\right)$$ + + By default, the complex domain is used which means that inverting even + seemingly simple functions like $\exp(x)$ will give very different + results from those obtained in the real domain. + (In the case of $\exp(x)$, the inversion via $\log$ is multi-valued + in the complex domain, having infinitely many branches.) + + If you are working with real values only (or you are not sure which + function to use) you should probably set the domain to + ``S.Reals`` (or use ``invert_real`` which does that automatically). + + + Examples + ======== + + >>> from sympy.solvers.solveset import invert_complex, invert_real + >>> from sympy.abc import x, y + >>> from sympy import exp + + When does exp(x) == y? + + >>> invert_complex(exp(x), y, x) + (x, ImageSet(Lambda(_n, I*(2*_n*pi + arg(y)) + log(Abs(y))), Integers)) + >>> invert_real(exp(x), y, x) + (x, Intersection({log(y)}, Reals)) + + When does exp(x) == 1? + + >>> invert_complex(exp(x), 1, x) + (x, ImageSet(Lambda(_n, 2*_n*I*pi), Integers)) + >>> invert_real(exp(x), 1, x) + (x, {0}) + + See Also + ======== + invert_real, invert_complex + """ + x = sympify(x) + if not x.is_Symbol: + raise ValueError("x must be a symbol") + f_x = sympify(f_x) + if x not in f_x.free_symbols: + raise ValueError("Inverse of constant function doesn't exist") + y = sympify(y) + if x in y.free_symbols: + raise ValueError("y should be independent of x ") + + if domain.is_subset(S.Reals): + x1, s = _invert_real(f_x, FiniteSet(y), x) + else: + x1, s = _invert_complex(f_x, FiniteSet(y), x) + + # f couldn't be inverted completely; return unmodified. + if x1 != x: + return x1, s + + # Avoid adding gratuitous intersections with S.Complexes. Actual + # conditions should be handled by the respective inverters. + if domain is S.Complexes: + return x1, s + + if isinstance(s, FiniteSet): + return x1, s.intersect(domain) + + # "Fancier" solution sets like those obtained by inversion of trigonometric + # functions already include general validity conditions (i.e. conditions on + # the domain of the respective inverse functions), so we should avoid adding + # blanket intersections with S.Reals. But subsets of R (or C) must still be + # accounted for. + if domain is S.Reals: + return x1, s + else: + return x1, s.intersect(domain) + + +invert_complex = _invert + + +def invert_real(f_x, y, x): + """ + Inverts a real-valued function. Same as :func:`invert_complex`, but sets + the domain to ``S.Reals`` before inverting. + """ + return _invert(f_x, y, x, S.Reals) + + +def _invert_real(f, g_ys, symbol): + """Helper function for _invert.""" + + if f == symbol or g_ys is S.EmptySet: + return (symbol, g_ys) + + n = Dummy('n', real=True) + + if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1): + return _invert_real(f.exp, + imageset(Lambda(n, log(n)), g_ys), + symbol) + + if hasattr(f, 'inverse') and f.inverse() is not None and not isinstance(f, ( + TrigonometricFunction, + HyperbolicFunction, + )): + if len(f.args) > 1: + raise ValueError("Only functions with one argument are supported.") + return _invert_real(f.args[0], + imageset(Lambda(n, f.inverse()(n)), g_ys), + symbol) + + if isinstance(f, Abs): + return _invert_abs(f.args[0], g_ys, symbol) + + if f.is_Add: + # f = g + h + g, h = f.as_independent(symbol) + if g is not S.Zero: + return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol) + + if f.is_Mul: + # f = g*h + g, h = f.as_independent(symbol) + + if g is not S.One: + return _invert_real(h, imageset(Lambda(n, n/g), g_ys), symbol) + + if f.is_Pow: + base, expo = f.args + base_has_sym = base.has(symbol) + expo_has_sym = expo.has(symbol) + + if not expo_has_sym: + + if expo.is_rational: + num, den = expo.as_numer_denom() + + if den % 2 == 0 and num % 2 == 1 and den.is_zero is False: + # Here we have f(x)**(num/den) = y + # where den is nonzero and even and y is an element + # of the set g_ys. + # den is even, so we are only interested in the cases + # where both f(x) and y are positive. + # Restricting y to be positive (using the set g_ys_pos) + # means that y**(den/num) is always positive. + # Therefore it isn't necessary to also constrain f(x) + # to be positive because we are only going to + # find solutions of f(x) = y**(d/n) + # where the rhs is already required to be positive. + root = Lambda(n, real_root(n, expo)) + g_ys_pos = g_ys & Interval(0, oo) + res = imageset(root, g_ys_pos) + _inv, _set = _invert_real(base, res, symbol) + return (_inv, _set) + + if den % 2 == 1: + root = Lambda(n, real_root(n, expo)) + res = imageset(root, g_ys) + if num % 2 == 0: + neg_res = imageset(Lambda(n, -n), res) + return _invert_real(base, res + neg_res, symbol) + if num % 2 == 1: + return _invert_real(base, res, symbol) + + elif expo.is_irrational: + root = Lambda(n, real_root(n, expo)) + g_ys_pos = g_ys & Interval(0, oo) + res = imageset(root, g_ys_pos) + return _invert_real(base, res, symbol) + + else: + # indeterminate exponent, e.g. Float or parity of + # num, den of rational could not be determined + pass # use default return + + if not base_has_sym: + rhs = g_ys.args[0] + if base.is_positive: + return _invert_real(expo, + imageset(Lambda(n, log(n, base, evaluate=False)), g_ys), symbol) + elif base.is_negative: + s, b = integer_log(rhs, base) + if b: + return _invert_real(expo, FiniteSet(s), symbol) + else: + return (expo, S.EmptySet) + elif base.is_zero: + one = Eq(rhs, 1) + if one == S.true: + # special case: 0**x - 1 + return _invert_real(expo, FiniteSet(0), symbol) + elif one == S.false: + return (expo, S.EmptySet) + + if isinstance(f, (TrigonometricFunction, HyperbolicFunction)): + return _invert_trig_hyp_real(f, g_ys, symbol) + + return (f, g_ys) + + +# Dictionaries of inverses will be cached after first use. +_trig_inverses = None +_hyp_inverses = None + +def _invert_trig_hyp_real(f, g_ys, symbol): + """Helper function for inverting trigonometric and hyperbolic functions. + + This helper only handles inversion over the reals. + + For trigonometric functions only finite `g_ys` sets are implemented. + + For hyperbolic functions the set `g_ys` is checked against the domain of the + respective inverse functions. Infinite `g_ys` sets are also supported. + """ + + if isinstance(f, HyperbolicFunction): + n = Dummy('n', real=True) + + if isinstance(f, sinh): + # asinh is defined over R. + return _invert_real(f.args[0], imageset(n, asinh(n), g_ys), symbol) + + if isinstance(f, cosh): + g_ys_dom = g_ys.intersect(Interval(1, oo)) + if isinstance(g_ys_dom, Intersection): + # could not properly resolve domain check + if isinstance(g_ys, FiniteSet): + # If g_ys is a `FiniteSet`` it should be sufficient to just + # let the calling `_invert_real()` add an intersection with + # `S.Reals` (or a subset `domain`) to ensure that only valid + # (real) solutions are returned. + # This avoids adding "too many" Intersections or + # ConditionSets in the returned set. + g_ys_dom = g_ys + else: + return (f, g_ys) + return _invert_real(f.args[0], Union( + imageset(n, acosh(n), g_ys_dom), + imageset(n, -acosh(n), g_ys_dom)), symbol) + + if isinstance(f, sech): + g_ys_dom = g_ys.intersect(Interval.Lopen(0, 1)) + if isinstance(g_ys_dom, Intersection): + if isinstance(g_ys, FiniteSet): + g_ys_dom = g_ys + else: + return (f, g_ys) + return _invert_real(f.args[0], Union( + imageset(n, asech(n), g_ys_dom), + imageset(n, -asech(n), g_ys_dom)), symbol) + + if isinstance(f, tanh): + g_ys_dom = g_ys.intersect(Interval.open(-1, 1)) + if isinstance(g_ys_dom, Intersection): + if isinstance(g_ys, FiniteSet): + g_ys_dom = g_ys + else: + return (f, g_ys) + return _invert_real(f.args[0], + imageset(n, atanh(n), g_ys_dom), symbol) + + if isinstance(f, coth): + g_ys_dom = g_ys - Interval(-1, 1) + if isinstance(g_ys_dom, Complement): + if isinstance(g_ys, FiniteSet): + g_ys_dom = g_ys + else: + return (f, g_ys) + return _invert_real(f.args[0], + imageset(n, acoth(n), g_ys_dom), symbol) + + if isinstance(f, csch): + g_ys_dom = g_ys - FiniteSet(0) + if isinstance(g_ys_dom, Complement): + if isinstance(g_ys, FiniteSet): + g_ys_dom = g_ys + else: + return (f, g_ys) + return _invert_real(f.args[0], + imageset(n, acsch(n), g_ys_dom), symbol) + + elif isinstance(f, TrigonometricFunction) and isinstance(g_ys, FiniteSet): + def _get_trig_inverses(func): + global _trig_inverses + if _trig_inverses is None: + _trig_inverses = { + sin : ((asin, lambda y: pi-asin(y)), 2*pi, Interval(-1, 1)), + cos : ((acos, lambda y: -acos(y)), 2*pi, Interval(-1, 1)), + tan : ((atan,), pi, S.Reals), + cot : ((acot,), pi, S.Reals), + sec : ((asec, lambda y: -asec(y)), 2*pi, + Union(Interval(-oo, -1), Interval(1, oo))), + csc : ((acsc, lambda y: pi-acsc(y)), 2*pi, + Union(Interval(-oo, -1), Interval(1, oo)))} + return _trig_inverses[func] + + invs, period, rng = _get_trig_inverses(f.func) + n = Dummy('n', integer=True) + def create_return_set(g): + # returns ConditionSet that will be part of the final (x, set) tuple + invsimg = Union(*[ + imageset(n, period*n + inv(g), S.Integers) for inv in invs]) + inv_f, inv_g_ys = _invert_real(f.args[0], invsimg, symbol) + if inv_f == symbol: # inversion successful + conds = rng.contains(g) + return ConditionSet(symbol, conds, inv_g_ys) + else: + return ConditionSet(symbol, Eq(f, g), S.Reals) + + retset = Union(*[create_return_set(g) for g in g_ys]) + return (symbol, retset) + + else: + return (f, g_ys) + + +def _invert_trig_hyp_complex(f, g_ys, symbol): + """Helper function for inverting trigonometric and hyperbolic functions. + + This helper only handles inversion over the complex numbers. + Only finite `g_ys` sets are implemented. + + Handling of singularities is only implemented for hyperbolic equations. + In case of a symbolic element g in g_ys a ConditionSet may be returned. + """ + + if isinstance(f, TrigonometricFunction) and isinstance(g_ys, FiniteSet): + def inv(trig): + if isinstance(trig, (sin, csc)): + F = asin if isinstance(trig, sin) else acsc + return ( + lambda a: 2*n*pi + F(a), + lambda a: 2*n*pi + pi - F(a)) + if isinstance(trig, (cos, sec)): + F = acos if isinstance(trig, cos) else asec + return ( + lambda a: 2*n*pi + F(a), + lambda a: 2*n*pi - F(a)) + if isinstance(trig, (tan, cot)): + return (lambda a: n*pi + trig.inverse()(a),) + + n = Dummy('n', integer=True) + invs = S.EmptySet + for L in inv(f): + invs += Union(*[imageset(Lambda(n, L(g)), S.Integers) for g in g_ys]) + return _invert_complex(f.args[0], invs, symbol) + + elif isinstance(f, HyperbolicFunction) and isinstance(g_ys, FiniteSet): + # There are two main options regarding singularities / domain checking + # for symbolic elements in g_ys: + # 1. Add a "catch-all" intersection with S.Complexes. + # 2. ConditionSets. + # At present ConditionSets seem to work better and have the additional + # benefit of representing the precise conditions that must be satisfied. + # The conditions are also rather straightforward. (At most two isolated + # points.) + def _get_hyp_inverses(func): + global _hyp_inverses + if _hyp_inverses is None: + _hyp_inverses = { + sinh : ((asinh, lambda y: I*pi-asinh(y)), 2*I*pi, ()), + cosh : ((acosh, lambda y: -acosh(y)), 2*I*pi, ()), + tanh : ((atanh,), I*pi, (-1, 1)), + coth : ((acoth,), I*pi, (-1, 1)), + sech : ((asech, lambda y: -asech(y)), 2*I*pi, (0, )), + csch : ((acsch, lambda y: I*pi-acsch(y)), 2*I*pi, (0, ))} + return _hyp_inverses[func] + + # invs: iterable of main inverses, e.g. (acosh, -acosh). + # excl: iterable of singularities to be checked for. + invs, period, excl = _get_hyp_inverses(f.func) + n = Dummy('n', integer=True) + def create_return_set(g): + # returns ConditionSet that will be part of the final (x, set) tuple + invsimg = Union(*[ + imageset(n, period*n + inv(g), S.Integers) for inv in invs]) + inv_f, inv_g_ys = _invert_complex(f.args[0], invsimg, symbol) + if inv_f == symbol: # inversion successful + conds = And(*[Ne(g, e) for e in excl]) + return ConditionSet(symbol, conds, inv_g_ys) + else: + return ConditionSet(symbol, Eq(f, g), S.Complexes) + + retset = Union(*[create_return_set(g) for g in g_ys]) + return (symbol, retset) + + else: + return (f, g_ys) + + +def _invert_complex(f, g_ys, symbol): + """Helper function for _invert.""" + + if f == symbol or g_ys is S.EmptySet: + return (symbol, g_ys) + + n = Dummy('n') + + if f.is_Add: + # f = g + h + g, h = f.as_independent(symbol) + if g is not S.Zero: + return _invert_complex(h, imageset(Lambda(n, n - g), g_ys), symbol) + + if f.is_Mul: + # f = g*h + g, h = f.as_independent(symbol) + + if g is not S.One: + if g in {S.NegativeInfinity, S.ComplexInfinity, S.Infinity}: + return (h, S.EmptySet) + return _invert_complex(h, imageset(Lambda(n, n/g), g_ys), symbol) + + if f.is_Pow: + base, expo = f.args + # special case: g**r = 0 + # Could be improved like `_invert_real` to handle more general cases. + if expo.is_Rational and g_ys == FiniteSet(0): + if expo.is_positive: + return _invert_complex(base, g_ys, symbol) + + if hasattr(f, 'inverse') and f.inverse() is not None and \ + not isinstance(f, TrigonometricFunction) and \ + not isinstance(f, HyperbolicFunction) and \ + not isinstance(f, exp): + if len(f.args) > 1: + raise ValueError("Only functions with one argument are supported.") + return _invert_complex(f.args[0], + imageset(Lambda(n, f.inverse()(n)), g_ys), symbol) + + if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1): + if isinstance(g_ys, ImageSet): + # can solve up to `(d*exp(exp(...(exp(a*x + b))...) + c)` format. + # Further can be improved to `(d*exp(exp(...(exp(a*x**n + b*x**(n-1) + ... + f))...) + c)`. + g_ys_expr = g_ys.lamda.expr + g_ys_vars = g_ys.lamda.variables + k = Dummy('k{}'.format(len(g_ys_vars))) + g_ys_vars_1 = (k,) + g_ys_vars + exp_invs = Union(*[imageset(Lambda((g_ys_vars_1,), (I*(2*k*pi + arg(g_ys_expr)) + + log(Abs(g_ys_expr)))), S.Integers**(len(g_ys_vars_1)))]) + return _invert_complex(f.exp, exp_invs, symbol) + + elif isinstance(g_ys, FiniteSet): + exp_invs = Union(*[imageset(Lambda(n, I*(2*n*pi + arg(g_y)) + + log(Abs(g_y))), S.Integers) + for g_y in g_ys if g_y != 0]) + return _invert_complex(f.exp, exp_invs, symbol) + + if isinstance(f, (TrigonometricFunction, HyperbolicFunction)): + return _invert_trig_hyp_complex(f, g_ys, symbol) + + return (f, g_ys) + + +def _invert_abs(f, g_ys, symbol): + """Helper function for inverting absolute value functions. + + Returns the complete result of inverting an absolute value + function along with the conditions which must also be satisfied. + + If it is certain that all these conditions are met, a :class:`~.FiniteSet` + of all possible solutions is returned. If any condition cannot be + satisfied, an :class:`~.EmptySet` is returned. Otherwise, a + :class:`~.ConditionSet` of the solutions, with all the required conditions + specified, is returned. + + """ + if not g_ys.is_FiniteSet: + # this could be used for FiniteSet, but the + # results are more compact if they aren't, e.g. + # ConditionSet(x, Contains(n, Interval(0, oo)), {-n, n}) vs + # Union(Intersection(Interval(0, oo), {n}), Intersection(Interval(-oo, 0), {-n})) + # for the solution of abs(x) - n + pos = Intersection(g_ys, Interval(0, S.Infinity)) + parg = _invert_real(f, pos, symbol) + narg = _invert_real(-f, pos, symbol) + if parg[0] != narg[0]: + raise NotImplementedError + return parg[0], Union(narg[1], parg[1]) + + # check conditions: all these must be true. If any are unknown + # then return them as conditions which must be satisfied + unknown = [] + for a in g_ys.args: + ok = a.is_nonnegative if a.is_Number else a.is_positive + if ok is None: + unknown.append(a) + elif not ok: + return symbol, S.EmptySet + if unknown: + conditions = And(*[Contains(i, Interval(0, oo)) + for i in unknown]) + else: + conditions = True + n = Dummy('n', real=True) + # this is slightly different than above: instead of solving + # +/-f on positive values, here we solve for f on +/- g_ys + g_x, values = _invert_real(f, Union( + imageset(Lambda(n, n), g_ys), + imageset(Lambda(n, -n), g_ys)), symbol) + return g_x, ConditionSet(g_x, conditions, values) + + +def domain_check(f, symbol, p): + """Returns False if point p is infinite or any subexpression of f + is infinite or becomes so after replacing symbol with p. If none of + these conditions is met then True will be returned. + + Examples + ======== + + >>> from sympy import Mul, oo + >>> from sympy.abc import x + >>> from sympy.solvers.solveset import domain_check + >>> g = 1/(1 + (1/(x + 1))**2) + >>> domain_check(g, x, -1) + False + >>> domain_check(x**2, x, 0) + True + >>> domain_check(1/x, x, oo) + False + + * The function relies on the assumption that the original form + of the equation has not been changed by automatic simplification. + + >>> domain_check(x/x, x, 0) # x/x is automatically simplified to 1 + True + + * To deal with automatic evaluations use evaluate=False: + + >>> domain_check(Mul(x, 1/x, evaluate=False), x, 0) + False + """ + f, p = sympify(f), sympify(p) + if p.is_infinite: + return False + return _domain_check(f, symbol, p) + + +def _domain_check(f, symbol, p): + # helper for domain check + if f.is_Atom and f.is_finite: + return True + elif f.subs(symbol, p).is_infinite: + return False + elif isinstance(f, Piecewise): + # Check the cases of the Piecewise in turn. There might be invalid + # expressions in later cases that don't apply e.g. + # solveset(Piecewise((0, Eq(x, 0)), (1/x, True)), x) + for expr, cond in f.args: + condsubs = cond.subs(symbol, p) + if condsubs is S.false: + continue + elif condsubs is S.true: + return _domain_check(expr, symbol, p) + else: + # We don't know which case of the Piecewise holds. On this + # basis we cannot decide whether any solution is in or out of + # the domain. Ideally this function would allow returning a + # symbolic condition for the validity of the solution that + # could be handled in the calling code. In the mean time we'll + # give this particular solution the benefit of the doubt and + # let it pass. + return True + else: + # TODO : We should not blindly recurse through all args of arbitrary expressions like this + return all(_domain_check(g, symbol, p) + for g in f.args) + + +def _is_finite_with_finite_vars(f, domain=S.Complexes): + """ + Return True if the given expression is finite. For symbols that + do not assign a value for `complex` and/or `real`, the domain will + be used to assign a value; symbols that do not assign a value + for `finite` will be made finite. All other assumptions are + left unmodified. + """ + def assumptions(s): + A = s.assumptions0 + A.setdefault('finite', A.get('finite', True)) + if domain.is_subset(S.Reals): + # if this gets set it will make complex=True, too + A.setdefault('real', True) + else: + # don't change 'real' because being complex implies + # nothing about being real + A.setdefault('complex', True) + return A + + reps = {s: Dummy(**assumptions(s)) for s in f.free_symbols} + return f.xreplace(reps).is_finite + + +def _is_function_class_equation(func_class, f, symbol): + """ Tests whether the equation is an equation of the given function class. + + The given equation belongs to the given function class if it is + comprised of functions of the function class which are multiplied by + or added to expressions independent of the symbol. In addition, the + arguments of all such functions must be linear in the symbol as well. + + Examples + ======== + + >>> from sympy.solvers.solveset import _is_function_class_equation + >>> from sympy import tan, sin, tanh, sinh, exp + >>> from sympy.abc import x + >>> from sympy.functions.elementary.trigonometric import TrigonometricFunction + >>> from sympy.functions.elementary.hyperbolic import HyperbolicFunction + >>> _is_function_class_equation(TrigonometricFunction, exp(x) + tan(x), x) + False + >>> _is_function_class_equation(TrigonometricFunction, tan(x) + sin(x), x) + True + >>> _is_function_class_equation(TrigonometricFunction, tan(x**2), x) + False + >>> _is_function_class_equation(TrigonometricFunction, tan(x + 2), x) + True + >>> _is_function_class_equation(HyperbolicFunction, tanh(x) + sinh(x), x) + True + """ + if f.is_Mul or f.is_Add: + return all(_is_function_class_equation(func_class, arg, symbol) + for arg in f.args) + + if f.is_Pow: + if not f.exp.has(symbol): + return _is_function_class_equation(func_class, f.base, symbol) + else: + return False + + if not f.has(symbol): + return True + + if isinstance(f, func_class): + try: + g = Poly(f.args[0], symbol) + return g.degree() <= 1 + except PolynomialError: + return False + else: + return False + + +def _solve_as_rational(f, symbol, domain): + """ solve rational functions""" + f = together(_mexpand(f, recursive=True), deep=True) + g, h = fraction(f) + if not h.has(symbol): + try: + return _solve_as_poly(g, symbol, domain) + except NotImplementedError: + # The polynomial formed from g could end up having + # coefficients in a ring over which finding roots + # isn't implemented yet, e.g. ZZ[a] for some symbol a + return ConditionSet(symbol, Eq(f, 0), domain) + except CoercionFailed: + # contained oo, zoo or nan + return S.EmptySet + else: + valid_solns = _solveset(g, symbol, domain) + invalid_solns = _solveset(h, symbol, domain) + return valid_solns - invalid_solns + + +class _SolveTrig1Error(Exception): + """Raised when _solve_trig1 heuristics do not apply""" + +def _solve_trig(f, symbol, domain): + """Function to call other helpers to solve trigonometric equations """ + # If f is composed of a single trig function (potentially appearing multiple + # times) we should solve by either inverting directly or inverting after a + # suitable change of variable. + # + # _solve_trig is currently only called by _solveset for trig/hyperbolic + # functions of an argument linear in x. Inverting a symbolic argument should + # include a guard against division by zero in order to have a result that is + # consistent with similar processing done by _solve_trig1. + # (Ideally _invert should add these conditions by itself.) + trig_expr, count = None, 0 + for expr in preorder_traversal(f): + if isinstance(expr, (TrigonometricFunction, + HyperbolicFunction)) and expr.has(symbol): + if not trig_expr: + trig_expr, count = expr, 1 + elif expr == trig_expr: + count += 1 + else: + trig_expr, count = False, 0 + break + if count == 1: + # direct inversion + x, sol = _invert(f, 0, symbol, domain) + if x == symbol: + cond = True + if trig_expr.free_symbols - {symbol}: + a, h = trig_expr.args[0].as_independent(symbol, as_Add=True) + m, h = h.as_independent(symbol, as_Add=False) + num, den = m.as_numer_denom() + cond = Ne(num, 0) & Ne(den, 0) + return ConditionSet(symbol, cond, sol) + else: + return ConditionSet(symbol, Eq(f, 0), domain) + elif count: + # solve by change of variable + y = Dummy('y') + f_cov = f.subs(trig_expr, y) + sol_cov = solveset(f_cov, y, domain) + if isinstance(sol_cov, FiniteSet): + return Union( + *[_solve_trig(trig_expr-s, symbol, domain) for s in sol_cov]) + + sol = None + try: + # multiple trig/hyp functions; solve by rewriting to exp + sol = _solve_trig1(f, symbol, domain) + except _SolveTrig1Error: + try: + # multiple trig/hyp functions; solve by rewriting to tan(x/2) + sol = _solve_trig2(f, symbol, domain) + except ValueError: + raise NotImplementedError(filldedent(''' + Solution to this kind of trigonometric equations + is yet to be implemented''')) + return sol + + +def _solve_trig1(f, symbol, domain): + """Primary solver for trigonometric and hyperbolic equations + + Returns either the solution set as a ConditionSet (auto-evaluated to a + union of ImageSets if no variables besides 'symbol' are involved) or + raises _SolveTrig1Error if f == 0 cannot be solved. + + Notes + ===== + Algorithm: + 1. Do a change of variable x -> mu*x in arguments to trigonometric and + hyperbolic functions, in order to reduce them to small integers. (This + step is crucial to keep the degrees of the polynomials of step 4 low.) + 2. Rewrite trigonometric/hyperbolic functions as exponentials. + 3. Proceed to a 2nd change of variable, replacing exp(I*x) or exp(x) by y. + 4. Solve the resulting rational equation. + 5. Use invert_complex or invert_real to return to the original variable. + 6. If the coefficients of 'symbol' were symbolic in nature, add the + necessary consistency conditions in a ConditionSet. + + """ + # Prepare change of variable + x = Dummy('x') + if _is_function_class_equation(HyperbolicFunction, f, symbol): + cov = exp(x) + inverter = invert_real if domain.is_subset(S.Reals) else invert_complex + else: + cov = exp(I*x) + inverter = invert_complex + + f = trigsimp(f) + f_original = f + trig_functions = f.atoms(TrigonometricFunction, HyperbolicFunction) + trig_arguments = [e.args[0] for e in trig_functions] + # trigsimp may have reduced the equation to an expression + # that is independent of 'symbol' (e.g. cos**2+sin**2) + if not any(a.has(symbol) for a in trig_arguments): + return solveset(f_original, symbol, domain) + + denominators = [] + numerators = [] + for ar in trig_arguments: + try: + poly_ar = Poly(ar, symbol) + except PolynomialError: + raise _SolveTrig1Error("trig argument is not a polynomial") + if poly_ar.degree() > 1: # degree >1 still bad + raise _SolveTrig1Error("degree of variable must not exceed one") + if poly_ar.degree() == 0: # degree 0, don't care + continue + c = poly_ar.all_coeffs()[0] # got the coefficient of 'symbol' + numerators.append(fraction(c)[0]) + denominators.append(fraction(c)[1]) + + mu = lcm(denominators)/gcd(numerators) + f = f.subs(symbol, mu*x) + f = f.rewrite(exp) + f = together(f) + g, h = fraction(f) + y = Dummy('y') + g, h = g.expand(), h.expand() + g, h = g.subs(cov, y), h.subs(cov, y) + if g.has(x) or h.has(x): + raise _SolveTrig1Error("change of variable not possible") + + solns = solveset_complex(g, y) - solveset_complex(h, y) + if isinstance(solns, ConditionSet): + raise _SolveTrig1Error("polynomial has ConditionSet solution") + + if isinstance(solns, FiniteSet): + if any(isinstance(s, RootOf) for s in solns): + raise _SolveTrig1Error("polynomial results in RootOf object") + # revert the change of variable + cov = cov.subs(x, symbol/mu) + result = Union(*[inverter(cov, s, symbol)[1] for s in solns]) + # In case of symbolic coefficients, the solution set is only valid + # if numerator and denominator of mu are non-zero. + if mu.has(Symbol): + syms = (mu).atoms(Symbol) + munum, muden = fraction(mu) + condnum = munum.as_independent(*syms, as_Add=False)[1] + condden = muden.as_independent(*syms, as_Add=False)[1] + cond = And(Ne(condnum, 0), Ne(condden, 0)) + else: + cond = True + # Actual conditions are returned as part of the ConditionSet. Adding an + # intersection with C would only complicate some solution sets due to + # current limitations of intersection code. (e.g. #19154) + if domain is S.Complexes: + # This is a slight abuse of ConditionSet. Ideally this should + # be some kind of "PiecewiseSet". (See #19507 discussion) + return ConditionSet(symbol, cond, result) + else: + return ConditionSet(symbol, cond, Intersection(result, domain)) + elif solns is S.EmptySet: + return S.EmptySet + else: + raise _SolveTrig1Error("polynomial solutions must form FiniteSet") + + +def _solve_trig2(f, symbol, domain): + """Secondary helper to solve trigonometric equations, + called when first helper fails """ + f = trigsimp(f) + f_original = f + trig_functions = f.atoms(sin, cos, tan, sec, cot, csc) + trig_arguments = [e.args[0] for e in trig_functions] + denominators = [] + numerators = [] + + # todo: This solver can be extended to hyperbolics if the + # analogous change of variable to tanh (instead of tan) + # is used. + if not trig_functions: + return ConditionSet(symbol, Eq(f_original, 0), domain) + + # todo: The pre-processing below (extraction of numerators, denominators, + # gcd, lcm, mu, etc.) should be updated to the enhanced version in + # _solve_trig1. (See #19507) + for ar in trig_arguments: + try: + poly_ar = Poly(ar, symbol) + except PolynomialError: + raise ValueError("give up, we cannot solve if this is not a polynomial in x") + if poly_ar.degree() > 1: # degree >1 still bad + raise ValueError("degree of variable inside polynomial should not exceed one") + if poly_ar.degree() == 0: # degree 0, don't care + continue + c = poly_ar.all_coeffs()[0] # got the coefficient of 'symbol' + try: + numerators.append(Rational(c).p) + denominators.append(Rational(c).q) + except TypeError: + return ConditionSet(symbol, Eq(f_original, 0), domain) + + x = Dummy('x') + + mu = Rational(2)*number_lcm(*denominators)/number_gcd(*numerators) + f = f.subs(symbol, mu*x) + f = f.rewrite(tan) + f = expand_trig(f) + f = together(f) + + g, h = fraction(f) + y = Dummy('y') + g, h = g.expand(), h.expand() + g, h = g.subs(tan(x), y), h.subs(tan(x), y) + + if g.has(x) or h.has(x): + return ConditionSet(symbol, Eq(f_original, 0), domain) + solns = solveset(g, y, S.Reals) - solveset(h, y, S.Reals) + + if isinstance(solns, FiniteSet): + result = Union(*[invert_real(tan(symbol/mu), s, symbol)[1] + for s in solns]) + dsol = invert_real(tan(symbol/mu), oo, symbol)[1] + if degree(h) > degree(g): # If degree(denom)>degree(num) then there + result = Union(result, dsol) # would be another sol at Lim(denom-->oo) + return Intersection(result, domain) + elif solns is S.EmptySet: + return S.EmptySet + else: + return ConditionSet(symbol, Eq(f_original, 0), S.Reals) + + +def _solve_as_poly(f, symbol, domain=S.Complexes): + """ + Solve the equation using polynomial techniques if it already is a + polynomial equation or, with a change of variables, can be made so. + """ + result = None + if f.is_polynomial(symbol): + solns = roots(f, symbol, cubics=True, quartics=True, + quintics=True, domain='EX') + num_roots = sum(solns.values()) + if degree(f, symbol) <= num_roots: + result = FiniteSet(*solns.keys()) + else: + poly = Poly(f, symbol) + solns = poly.all_roots() + if poly.degree() <= len(solns): + result = FiniteSet(*solns) + else: + result = ConditionSet(symbol, Eq(f, 0), domain) + else: + poly = Poly(f) + if poly is None: + result = ConditionSet(symbol, Eq(f, 0), domain) + gens = [g for g in poly.gens if g.has(symbol)] + + if len(gens) == 1: + poly = Poly(poly, gens[0]) + gen = poly.gen + deg = poly.degree() + poly = Poly(poly.as_expr(), poly.gen, composite=True) + poly_solns = FiniteSet(*roots(poly, cubics=True, quartics=True, + quintics=True).keys()) + + if len(poly_solns) < deg: + result = ConditionSet(symbol, Eq(f, 0), domain) + + if gen != symbol: + y = Dummy('y') + inverter = invert_real if domain.is_subset(S.Reals) else invert_complex + lhs, rhs_s = inverter(gen, y, symbol) + if lhs == symbol: + result = Union(*[rhs_s.subs(y, s) for s in poly_solns]) + if isinstance(result, FiniteSet) and isinstance(gen, Pow + ) and gen.base.is_Rational: + result = FiniteSet(*[expand_log(i) for i in result]) + else: + result = ConditionSet(symbol, Eq(f, 0), domain) + else: + result = ConditionSet(symbol, Eq(f, 0), domain) + + if result is not None: + if isinstance(result, FiniteSet): + # this is to simplify solutions like -sqrt(-I) to sqrt(2)/2 + # - sqrt(2)*I/2. We are not expanding for solution with symbols + # or undefined functions because that makes the solution more complicated. + # For example, expand_complex(a) returns re(a) + I*im(a) + if all(s.atoms(Symbol, AppliedUndef) == set() and not isinstance(s, RootOf) + for s in result): + s = Dummy('s') + result = imageset(Lambda(s, expand_complex(s)), result) + if isinstance(result, FiniteSet) and domain != S.Complexes: + # Avoid adding gratuitous intersections with S.Complexes. Actual + # conditions should be handled elsewhere. + result = result.intersection(domain) + return result + else: + return ConditionSet(symbol, Eq(f, 0), domain) + + +def _solve_radical(f, unradf, symbol, solveset_solver): + """ Helper function to solve equations with radicals """ + res = unradf + eq, cov = res if res else (f, []) + if not cov: + result = solveset_solver(eq, symbol) - \ + Union(*[solveset_solver(g, symbol) for g in denoms(f, symbol)]) + else: + y, yeq = cov + if not solveset_solver(y - I, y): + yreal = Dummy('yreal', real=True) + yeq = yeq.xreplace({y: yreal}) + eq = eq.xreplace({y: yreal}) + y = yreal + g_y_s = solveset_solver(yeq, symbol) + f_y_sols = solveset_solver(eq, y) + result = Union(*[imageset(Lambda(y, g_y), f_y_sols) + for g_y in g_y_s]) + + def check_finiteset(solutions): + f_set = [] # solutions for FiniteSet + c_set = [] # solutions for ConditionSet + for s in solutions: + if checksol(f, symbol, s): + f_set.append(s) + else: + c_set.append(s) + return FiniteSet(*f_set) + ConditionSet(symbol, Eq(f, 0), FiniteSet(*c_set)) + + def check_set(solutions): + if solutions is S.EmptySet: + return solutions + elif isinstance(solutions, ConditionSet): + # XXX: Maybe the base set should be checked? + return solutions + elif isinstance(solutions, FiniteSet): + return check_finiteset(solutions) + elif isinstance(solutions, Complement): + A, B = solutions.args + return Complement(check_set(A), B) + elif isinstance(solutions, Union): + return Union(*[check_set(s) for s in solutions.args]) + else: + # XXX: There should be more cases checked here. The cases above + # are all those that come up in the test suite for now. + return solutions + + solution_set = check_set(result) + + return solution_set + + +def _solve_abs(f, symbol, domain): + """ Helper function to solve equation involving absolute value function """ + if not domain.is_subset(S.Reals): + raise ValueError(filldedent(''' + Absolute values cannot be inverted in the + complex domain.''')) + p, q, r = Wild('p'), Wild('q'), Wild('r') + pattern_match = f.match(p*Abs(q) + r) or {} + f_p, f_q, f_r = [pattern_match.get(i, S.Zero) for i in (p, q, r)] + + if not (f_p.is_zero or f_q.is_zero): + domain = continuous_domain(f_q, symbol, domain) + from .inequalities import solve_univariate_inequality + q_pos_cond = solve_univariate_inequality(f_q >= 0, symbol, + relational=False, domain=domain, continuous=True) + q_neg_cond = q_pos_cond.complement(domain) + + sols_q_pos = solveset_real(f_p*f_q + f_r, + symbol).intersect(q_pos_cond) + sols_q_neg = solveset_real(f_p*(-f_q) + f_r, + symbol).intersect(q_neg_cond) + return Union(sols_q_pos, sols_q_neg) + else: + return ConditionSet(symbol, Eq(f, 0), domain) + + +def solve_decomposition(f, symbol, domain): + """ + Function to solve equations via the principle of "Decomposition + and Rewriting". + + Examples + ======== + >>> from sympy import exp, sin, Symbol, pprint, S + >>> from sympy.solvers.solveset import solve_decomposition as sd + >>> x = Symbol('x') + >>> f1 = exp(2*x) - 3*exp(x) + 2 + >>> sd(f1, x, S.Reals) + {0, log(2)} + >>> f2 = sin(x)**2 + 2*sin(x) + 1 + >>> pprint(sd(f2, x, S.Reals), use_unicode=False) + 3*pi + {2*n*pi + ---- | n in Integers} + 2 + >>> f3 = sin(x + 2) + >>> pprint(sd(f3, x, S.Reals), use_unicode=False) + {2*n*pi - 2 | n in Integers} U {2*n*pi - 2 + pi | n in Integers} + + """ + from sympy.solvers.decompogen import decompogen + # decompose the given function + g_s = decompogen(f, symbol) + # `y_s` represents the set of values for which the function `g` is to be + # solved. + # `solutions` represent the solutions of the equations `g = y_s` or + # `g = 0` depending on the type of `y_s`. + # As we are interested in solving the equation: f = 0 + y_s = FiniteSet(0) + for g in g_s: + frange = function_range(g, symbol, domain) + y_s = Intersection(frange, y_s) + result = S.EmptySet + if isinstance(y_s, FiniteSet): + for y in y_s: + solutions = solveset(Eq(g, y), symbol, domain) + if not isinstance(solutions, ConditionSet): + result += solutions + + else: + if isinstance(y_s, ImageSet): + iter_iset = (y_s,) + + elif isinstance(y_s, Union): + iter_iset = y_s.args + + elif y_s is S.EmptySet: + # y_s is not in the range of g in g_s, so no solution exists + #in the given domain + return S.EmptySet + + for iset in iter_iset: + new_solutions = solveset(Eq(iset.lamda.expr, g), symbol, domain) + dummy_var = tuple(iset.lamda.expr.free_symbols)[0] + (base_set,) = iset.base_sets + if isinstance(new_solutions, FiniteSet): + new_exprs = new_solutions + + elif isinstance(new_solutions, Intersection): + if isinstance(new_solutions.args[1], FiniteSet): + new_exprs = new_solutions.args[1] + + for new_expr in new_exprs: + result += ImageSet(Lambda(dummy_var, new_expr), base_set) + + if result is S.EmptySet: + return ConditionSet(symbol, Eq(f, 0), domain) + + y_s = result + + return y_s + + +def _solveset(f, symbol, domain, _check=False): + """Helper for solveset to return a result from an expression + that has already been sympify'ed and is known to contain the + given symbol.""" + # _check controls whether the answer is checked or not + from sympy.simplify.simplify import signsimp + + if isinstance(f, BooleanTrue): + return domain + + orig_f = f + if f.is_Mul: + coeff, f = f.as_independent(symbol, as_Add=False) + if coeff in {S.ComplexInfinity, S.NegativeInfinity, S.Infinity}: + f = together(orig_f) + elif f.is_Add: + a, h = f.as_independent(symbol) + m, h = h.as_independent(symbol, as_Add=False) + if m not in {S.ComplexInfinity, S.Zero, S.Infinity, + S.NegativeInfinity}: + f = a/m + h # XXX condition `m != 0` should be added to soln + + # assign the solvers to use + solver = lambda f, x, domain=domain: _solveset(f, x, domain) + inverter = lambda f, rhs, symbol: _invert(f, rhs, symbol, domain) + + result = S.EmptySet + + if f.expand().is_zero: + return domain + elif not f.has(symbol): + return S.EmptySet + elif f.is_Mul and all(_is_finite_with_finite_vars(m, domain) + for m in f.args): + # if f(x) and g(x) are both finite we can say that the solution of + # f(x)*g(x) == 0 is same as Union(f(x) == 0, g(x) == 0) is not true in + # general. g(x) can grow to infinitely large for the values where + # f(x) == 0. To be sure that we are not silently allowing any + # wrong solutions we are using this technique only if both f and g are + # finite for a finite input. + result = Union(*[solver(m, symbol) for m in f.args]) + elif (_is_function_class_equation(TrigonometricFunction, f, symbol) or \ + _is_function_class_equation(HyperbolicFunction, f, symbol)): + result = _solve_trig(f, symbol, domain) + elif isinstance(f, arg): + a = f.args[0] + result = Intersection(_solveset(re(a) > 0, symbol, domain), + _solveset(im(a), symbol, domain)) + elif f.is_Piecewise: + expr_set_pairs = f.as_expr_set_pairs(domain) + for (expr, in_set) in expr_set_pairs: + if in_set.is_Relational: + in_set = in_set.as_set() + solns = solver(expr, symbol, in_set) + result += solns + elif isinstance(f, Eq): + result = solver(Add(f.lhs, -f.rhs, evaluate=False), symbol, domain) + + elif f.is_Relational: + from .inequalities import solve_univariate_inequality + try: + result = solve_univariate_inequality( + f, symbol, domain=domain, relational=False) + except NotImplementedError: + result = ConditionSet(symbol, f, domain) + return result + elif _is_modular(f, symbol): + result = _solve_modular(f, symbol, domain) + else: + lhs, rhs_s = inverter(f, 0, symbol) + if lhs == symbol: + # do some very minimal simplification since + # repeated inversion may have left the result + # in a state that other solvers (e.g. poly) + # would have simplified; this is done here + # rather than in the inverter since here it + # is only done once whereas there it would + # be repeated for each step of the inversion + if isinstance(rhs_s, FiniteSet): + rhs_s = FiniteSet(*[Mul(* + signsimp(i).as_content_primitive()) + for i in rhs_s]) + result = rhs_s + + elif isinstance(rhs_s, FiniteSet): + for equation in [lhs - rhs for rhs in rhs_s]: + if equation == f: + u = unrad(f, symbol) + if u: + result += _solve_radical(equation, u, + symbol, + solver) + elif equation.has(Abs): + result += _solve_abs(f, symbol, domain) + else: + result_rational = _solve_as_rational(equation, symbol, domain) + if not isinstance(result_rational, ConditionSet): + result += result_rational + else: + # may be a transcendental type equation + t_result = _transolve(equation, symbol, domain) + if isinstance(t_result, ConditionSet): + # might need factoring; this is expensive so we + # have delayed until now. To avoid recursion + # errors look for a non-trivial factoring into + # a product of symbol dependent terms; I think + # that something that factors as a Pow would + # have already been recognized by now. + factored = equation.factor() + if factored.is_Mul and equation != factored: + _, dep = factored.as_independent(symbol) + if not dep.is_Add: + # non-trivial factoring of equation + # but use form with constants + # in case they need special handling + t_results = [] + for fac in Mul.make_args(factored): + if fac.has(symbol): + t_results.append(solver(fac, symbol)) + t_result = Union(*t_results) + result += t_result + else: + result += solver(equation, symbol) + + elif rhs_s is not S.EmptySet: + result = ConditionSet(symbol, Eq(f, 0), domain) + + if isinstance(result, ConditionSet): + if isinstance(f, Expr): + num, den = f.as_numer_denom() + if den.has(symbol): + _result = _solveset(num, symbol, domain) + if not isinstance(_result, ConditionSet): + singularities = _solveset(den, symbol, domain) + result = _result - singularities + + if _check: + if isinstance(result, ConditionSet): + # it wasn't solved or has enumerated all conditions + # -- leave it alone + return result + + # whittle away all but the symbol-containing core + # to use this for testing + if isinstance(orig_f, Expr): + fx = orig_f.as_independent(symbol, as_Add=True)[1] + fx = fx.as_independent(symbol, as_Add=False)[1] + else: + fx = orig_f + + if isinstance(result, FiniteSet): + # check the result for invalid solutions + result = FiniteSet(*[s for s in result + if isinstance(s, RootOf) + or domain_check(fx, symbol, s)]) + + return result + + +def _is_modular(f, symbol): + """ + Helper function to check below mentioned types of modular equations. + ``A - Mod(B, C) = 0`` + + A -> This can or cannot be a function of symbol. + B -> This is surely a function of symbol. + C -> It is an integer. + + Parameters + ========== + + f : Expr + The equation to be checked. + + symbol : Symbol + The concerned variable for which the equation is to be checked. + + Examples + ======== + + >>> from sympy import symbols, exp, Mod + >>> from sympy.solvers.solveset import _is_modular as check + >>> x, y = symbols('x y') + >>> check(Mod(x, 3) - 1, x) + True + >>> check(Mod(x, 3) - 1, y) + False + >>> check(Mod(x, 3)**2 - 5, x) + False + >>> check(Mod(x, 3)**2 - y, x) + False + >>> check(exp(Mod(x, 3)) - 1, x) + False + >>> check(Mod(3, y) - 1, y) + False + """ + + if not f.has(Mod): + return False + + # extract modterms from f. + modterms = list(f.atoms(Mod)) + + return (len(modterms) == 1 and # only one Mod should be present + modterms[0].args[0].has(symbol) and # B-> function of symbol + modterms[0].args[1].is_integer and # C-> to be an integer. + any(isinstance(term, Mod) + for term in list(_term_factors(f))) # free from other funcs + ) + + +def _invert_modular(modterm, rhs, n, symbol): + """ + Helper function to invert modular equation. + ``Mod(a, m) - rhs = 0`` + + Generally it is inverted as (a, ImageSet(Lambda(n, m*n + rhs), S.Integers)). + More simplified form will be returned if possible. + + If it is not invertible then (modterm, rhs) is returned. + + The following cases arise while inverting equation ``Mod(a, m) - rhs = 0``: + + 1. If a is symbol then m*n + rhs is the required solution. + + 2. If a is an instance of ``Add`` then we try to find two symbol independent + parts of a and the symbol independent part gets transferred to the other + side and again the ``_invert_modular`` is called on the symbol + dependent part. + + 3. If a is an instance of ``Mul`` then same as we done in ``Add`` we separate + out the symbol dependent and symbol independent parts and transfer the + symbol independent part to the rhs with the help of invert and again the + ``_invert_modular`` is called on the symbol dependent part. + + 4. If a is an instance of ``Pow`` then two cases arise as following: + + - If a is of type (symbol_indep)**(symbol_dep) then the remainder is + evaluated with the help of discrete_log function and then the least + period is being found out with the help of totient function. + period*n + remainder is the required solution in this case. + For reference: (https://en.wikipedia.org/wiki/Euler's_theorem) + + - If a is of type (symbol_dep)**(symbol_indep) then we try to find all + primitive solutions list with the help of nthroot_mod function. + m*n + rem is the general solution where rem belongs to solutions list + from nthroot_mod function. + + Parameters + ========== + + modterm, rhs : Expr + The modular equation to be inverted, ``modterm - rhs = 0`` + + symbol : Symbol + The variable in the equation to be inverted. + + n : Dummy + Dummy variable for output g_n. + + Returns + ======= + + A tuple (f_x, g_n) is being returned where f_x is modular independent function + of symbol and g_n being set of values f_x can have. + + Examples + ======== + + >>> from sympy import symbols, exp, Mod, Dummy, S + >>> from sympy.solvers.solveset import _invert_modular as invert_modular + >>> x, y = symbols('x y') + >>> n = Dummy('n') + >>> invert_modular(Mod(exp(x), 7), S(5), n, x) + (Mod(exp(x), 7), 5) + >>> invert_modular(Mod(x, 7), S(5), n, x) + (x, ImageSet(Lambda(_n, 7*_n + 5), Integers)) + >>> invert_modular(Mod(3*x + 8, 7), S(5), n, x) + (x, ImageSet(Lambda(_n, 7*_n + 6), Integers)) + >>> invert_modular(Mod(x**4, 7), S(5), n, x) + (x, EmptySet) + >>> invert_modular(Mod(2**(x**2 + x + 1), 7), S(2), n, x) + (x**2 + x + 1, ImageSet(Lambda(_n, 3*_n + 1), Naturals0)) + + """ + a, m = modterm.args + + if rhs.is_integer is False: + return symbol, S.EmptySet + + if rhs.is_real is False or any(term.is_real is False + for term in list(_term_factors(a))): + # Check for complex arguments + return modterm, rhs + + if abs(rhs) >= abs(m): + # if rhs has value greater than value of m. + return symbol, S.EmptySet + + if a == symbol: + return symbol, ImageSet(Lambda(n, m*n + rhs), S.Integers) + + if a.is_Add: + # g + h = a + g, h = a.as_independent(symbol) + if g is not S.Zero: + x_indep_term = rhs - Mod(g, m) + return _invert_modular(Mod(h, m), Mod(x_indep_term, m), n, symbol) + + if a.is_Mul: + # g*h = a + g, h = a.as_independent(symbol) + if g is not S.One: + x_indep_term = rhs*invert(g, m) + return _invert_modular(Mod(h, m), Mod(x_indep_term, m), n, symbol) + + if a.is_Pow: + # base**expo = a + base, expo = a.args + if expo.has(symbol) and not base.has(symbol): + # remainder -> solution independent of n of equation. + # m, rhs are made coprime by dividing number_gcd(m, rhs) + if not m.is_Integer and rhs.is_Integer and a.base.is_Integer: + return modterm, rhs + + mdiv = m.p // number_gcd(m.p, rhs.p) + try: + remainder = discrete_log(mdiv, rhs.p, a.base.p) + except ValueError: # log does not exist + return modterm, rhs + # period -> coefficient of n in the solution and also referred as + # the least period of expo in which it is repeats itself. + # (a**(totient(m)) - 1) divides m. Here is link of theorem: + # (https://en.wikipedia.org/wiki/Euler's_theorem) + period = totient(m) + for p in divisors(period): + # there might a lesser period exist than totient(m). + if pow(a.base, p, m / number_gcd(m.p, a.base.p)) == 1: + period = p + break + # recursion is not applied here since _invert_modular is currently + # not smart enough to handle infinite rhs as here expo has infinite + # rhs = ImageSet(Lambda(n, period*n + remainder), S.Naturals0). + return expo, ImageSet(Lambda(n, period*n + remainder), S.Naturals0) + elif base.has(symbol) and not expo.has(symbol): + try: + remainder_list = nthroot_mod(rhs, expo, m, all_roots=True) + if remainder_list == []: + return symbol, S.EmptySet + except (ValueError, NotImplementedError): + return modterm, rhs + g_n = S.EmptySet + for rem in remainder_list: + g_n += ImageSet(Lambda(n, m*n + rem), S.Integers) + return base, g_n + + return modterm, rhs + + +def _solve_modular(f, symbol, domain): + r""" + Helper function for solving modular equations of type ``A - Mod(B, C) = 0``, + where A can or cannot be a function of symbol, B is surely a function of + symbol and C is an integer. + + Currently ``_solve_modular`` is only able to solve cases + where A is not a function of symbol. + + Parameters + ========== + + f : Expr + The modular equation to be solved, ``f = 0`` + + symbol : Symbol + The variable in the equation to be solved. + + domain : Set + A set over which the equation is solved. It has to be a subset of + Integers. + + Returns + ======= + + A set of integer solutions satisfying the given modular equation. + A ``ConditionSet`` if the equation is unsolvable. + + Examples + ======== + + >>> from sympy.solvers.solveset import _solve_modular as solve_modulo + >>> from sympy import S, Symbol, sin, Intersection, Interval, Mod + >>> x = Symbol('x') + >>> solve_modulo(Mod(5*x - 8, 7) - 3, x, S.Integers) + ImageSet(Lambda(_n, 7*_n + 5), Integers) + >>> solve_modulo(Mod(5*x - 8, 7) - 3, x, S.Reals) # domain should be subset of integers. + ConditionSet(x, Eq(Mod(5*x + 6, 7) - 3, 0), Reals) + >>> solve_modulo(-7 + Mod(x, 5), x, S.Integers) + EmptySet + >>> solve_modulo(Mod(12**x, 21) - 18, x, S.Integers) + ImageSet(Lambda(_n, 6*_n + 2), Naturals0) + >>> solve_modulo(Mod(sin(x), 7) - 3, x, S.Integers) # not solvable + ConditionSet(x, Eq(Mod(sin(x), 7) - 3, 0), Integers) + >>> solve_modulo(3 - Mod(x, 5), x, Intersection(S.Integers, Interval(0, 100))) + Intersection(ImageSet(Lambda(_n, 5*_n + 3), Integers), Range(0, 101, 1)) + """ + # extract modterm and g_y from f + unsolved_result = ConditionSet(symbol, Eq(f, 0), domain) + modterm = list(f.atoms(Mod))[0] + rhs = -S.One*(f.subs(modterm, S.Zero)) + if f.as_coefficients_dict()[modterm].is_negative: + # checks if coefficient of modterm is negative in main equation. + rhs *= -S.One + + if not domain.is_subset(S.Integers): + return unsolved_result + + if rhs.has(symbol): + # TODO Case: A-> function of symbol, can be extended here + # in future. + return unsolved_result + + n = Dummy('n', integer=True) + f_x, g_n = _invert_modular(modterm, rhs, n, symbol) + + if f_x == modterm and g_n == rhs: + return unsolved_result + + if f_x == symbol: + if domain is not S.Integers: + return domain.intersect(g_n) + return g_n + + if isinstance(g_n, ImageSet): + lamda_expr = g_n.lamda.expr + lamda_vars = g_n.lamda.variables + base_sets = g_n.base_sets + sol_set = _solveset(f_x - lamda_expr, symbol, S.Integers) + if isinstance(sol_set, FiniteSet): + tmp_sol = S.EmptySet + for sol in sol_set: + tmp_sol += ImageSet(Lambda(lamda_vars, sol), *base_sets) + sol_set = tmp_sol + else: + sol_set = ImageSet(Lambda(lamda_vars, sol_set), *base_sets) + return domain.intersect(sol_set) + + return unsolved_result + + +def _term_factors(f): + """ + Iterator to get the factors of all terms present + in the given equation. + + Parameters + ========== + f : Expr + Equation that needs to be addressed + + Returns + ======= + Factors of all terms present in the equation. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.solvers.solveset import _term_factors + >>> x = symbols('x') + >>> list(_term_factors(-2 - x**2 + x*(x + 1))) + [-2, -1, x**2, x, x + 1] + """ + for add_arg in Add.make_args(f): + yield from Mul.make_args(add_arg) + + +def _solve_exponential(lhs, rhs, symbol, domain): + r""" + Helper function for solving (supported) exponential equations. + + Exponential equations are the sum of (currently) at most + two terms with one or both of them having a power with a + symbol-dependent exponent. + + For example + + .. math:: 5^{2x + 3} - 5^{3x - 1} + + .. math:: 4^{5 - 9x} - e^{2 - x} + + Parameters + ========== + + lhs, rhs : Expr + The exponential equation to be solved, `lhs = rhs` + + symbol : Symbol + The variable in which the equation is solved + + domain : Set + A set over which the equation is solved. + + Returns + ======= + + A set of solutions satisfying the given equation. + A ``ConditionSet`` if the equation is unsolvable or + if the assumptions are not properly defined, in that case + a different style of ``ConditionSet`` is returned having the + solution(s) of the equation with the desired assumptions. + + Examples + ======== + + >>> from sympy.solvers.solveset import _solve_exponential as solve_expo + >>> from sympy import symbols, S + >>> x = symbols('x', real=True) + >>> a, b = symbols('a b') + >>> solve_expo(2**x + 3**x - 5**x, 0, x, S.Reals) # not solvable + ConditionSet(x, Eq(2**x + 3**x - 5**x, 0), Reals) + >>> solve_expo(a**x - b**x, 0, x, S.Reals) # solvable but incorrect assumptions + ConditionSet(x, (a > 0) & (b > 0), {0}) + >>> solve_expo(3**(2*x) - 2**(x + 3), 0, x, S.Reals) + {-3*log(2)/(-2*log(3) + log(2))} + >>> solve_expo(2**x - 4**x, 0, x, S.Reals) + {0} + + * Proof of correctness of the method + + The logarithm function is the inverse of the exponential function. + The defining relation between exponentiation and logarithm is: + + .. math:: {\log_b x} = y \enspace if \enspace b^y = x + + Therefore if we are given an equation with exponent terms, we can + convert every term to its corresponding logarithmic form. This is + achieved by taking logarithms and expanding the equation using + logarithmic identities so that it can easily be handled by ``solveset``. + + For example: + + .. math:: 3^{2x} = 2^{x + 3} + + Taking log both sides will reduce the equation to + + .. math:: (2x)\log(3) = (x + 3)\log(2) + + This form can be easily handed by ``solveset``. + """ + unsolved_result = ConditionSet(symbol, Eq(lhs - rhs, 0), domain) + newlhs = powdenest(lhs) + if lhs != newlhs: + # it may also be advantageous to factor the new expr + neweq = factor(newlhs - rhs) + if neweq != (lhs - rhs): + return _solveset(neweq, symbol, domain) # try again with _solveset + + if not (isinstance(lhs, Add) and len(lhs.args) == 2): + # solving for the sum of more than two powers is possible + # but not yet implemented + return unsolved_result + + if rhs != 0: + return unsolved_result + + a, b = list(ordered(lhs.args)) + a_term = a.as_independent(symbol)[1] + b_term = b.as_independent(symbol)[1] + + a_base, a_exp = a_term.as_base_exp() + b_base, b_exp = b_term.as_base_exp() + + if domain.is_subset(S.Reals): + conditions = And( + a_base > 0, + b_base > 0, + Eq(im(a_exp), 0), + Eq(im(b_exp), 0)) + else: + conditions = And( + Ne(a_base, 0), + Ne(b_base, 0)) + + L, R = (expand_log(log(i), force=True) for i in (a, -b)) + solutions = _solveset(L - R, symbol, domain) + + return ConditionSet(symbol, conditions, solutions) + + +def _is_exponential(f, symbol): + r""" + Return ``True`` if one or more terms contain ``symbol`` only in + exponents, else ``False``. + + Parameters + ========== + + f : Expr + The equation to be checked + + symbol : Symbol + The variable in which the equation is checked + + Examples + ======== + + >>> from sympy import symbols, cos, exp + >>> from sympy.solvers.solveset import _is_exponential as check + >>> x, y = symbols('x y') + >>> check(y, y) + False + >>> check(x**y - 1, y) + True + >>> check(x**y*2**y - 1, y) + True + >>> check(exp(x + 3) + 3**x, x) + True + >>> check(cos(2**x), x) + False + + * Philosophy behind the helper + + The function extracts each term of the equation and checks if it is + of exponential form w.r.t ``symbol``. + """ + rv = False + for expr_arg in _term_factors(f): + if symbol not in expr_arg.free_symbols: + continue + if (isinstance(expr_arg, Pow) and + symbol not in expr_arg.base.free_symbols or + isinstance(expr_arg, exp)): + rv = True # symbol in exponent + else: + return False # dependent on symbol in non-exponential way + return rv + + +def _solve_logarithm(lhs, rhs, symbol, domain): + r""" + Helper to solve logarithmic equations which are reducible + to a single instance of `\log`. + + Logarithmic equations are (currently) the equations that contains + `\log` terms which can be reduced to a single `\log` term or + a constant using various logarithmic identities. + + For example: + + .. math:: \log(x) + \log(x - 4) + + can be reduced to: + + .. math:: \log(x(x - 4)) + + Parameters + ========== + + lhs, rhs : Expr + The logarithmic equation to be solved, `lhs = rhs` + + symbol : Symbol + The variable in which the equation is solved + + domain : Set + A set over which the equation is solved. + + Returns + ======= + + A set of solutions satisfying the given equation. + A ``ConditionSet`` if the equation is unsolvable. + + Examples + ======== + + >>> from sympy import symbols, log, S + >>> from sympy.solvers.solveset import _solve_logarithm as solve_log + >>> x = symbols('x') + >>> f = log(x - 3) + log(x + 3) + >>> solve_log(f, 0, x, S.Reals) + {-sqrt(10), sqrt(10)} + + * Proof of correctness + + A logarithm is another way to write exponent and is defined by + + .. math:: {\log_b x} = y \enspace if \enspace b^y = x + + When one side of the equation contains a single logarithm, the + equation can be solved by rewriting the equation as an equivalent + exponential equation as defined above. But if one side contains + more than one logarithm, we need to use the properties of logarithm + to condense it into a single logarithm. + + Take for example + + .. math:: \log(2x) - 15 = 0 + + contains single logarithm, therefore we can directly rewrite it to + exponential form as + + .. math:: x = \frac{e^{15}}{2} + + But if the equation has more than one logarithm as + + .. math:: \log(x - 3) + \log(x + 3) = 0 + + we use logarithmic identities to convert it into a reduced form + + Using, + + .. math:: \log(a) + \log(b) = \log(ab) + + the equation becomes, + + .. math:: \log((x - 3)(x + 3)) + + This equation contains one logarithm and can be solved by rewriting + to exponents. + """ + new_lhs = logcombine(lhs, force=True) + new_f = new_lhs - rhs + + return _solveset(new_f, symbol, domain) + + +def _is_logarithmic(f, symbol): + r""" + Return ``True`` if the equation is in the form + `a\log(f(x)) + b\log(g(x)) + ... + c` else ``False``. + + Parameters + ========== + + f : Expr + The equation to be checked + + symbol : Symbol + The variable in which the equation is checked + + Returns + ======= + + ``True`` if the equation is logarithmic otherwise ``False``. + + Examples + ======== + + >>> from sympy import symbols, tan, log + >>> from sympy.solvers.solveset import _is_logarithmic as check + >>> x, y = symbols('x y') + >>> check(log(x + 2) - log(x + 3), x) + True + >>> check(tan(log(2*x)), x) + False + >>> check(x*log(x), x) + False + >>> check(x + log(x), x) + False + >>> check(y + log(x), x) + True + + * Philosophy behind the helper + + The function extracts each term and checks whether it is + logarithmic w.r.t ``symbol``. + """ + rv = False + for term in Add.make_args(f): + saw_log = False + for term_arg in Mul.make_args(term): + if symbol not in term_arg.free_symbols: + continue + if isinstance(term_arg, log): + if saw_log: + return False # more than one log in term + saw_log = True + else: + return False # dependent on symbol in non-log way + if saw_log: + rv = True + return rv + + +def _is_lambert(f, symbol): + r""" + If this returns ``False`` then the Lambert solver (``_solve_lambert``) will not be called. + + Explanation + =========== + + Quick check for cases that the Lambert solver might be able to handle. + + 1. Equations containing more than two operands and `symbol`s involving any of + `Pow`, `exp`, `HyperbolicFunction`,`TrigonometricFunction`, `log` terms. + + 2. In `Pow`, `exp` the exponent should have `symbol` whereas for + `HyperbolicFunction`,`TrigonometricFunction`, `log` should contain `symbol`. + + 3. For `HyperbolicFunction`,`TrigonometricFunction` the number of trigonometric functions in + equation should be less than number of symbols. (since `A*cos(x) + B*sin(x) - c` + is not the Lambert type). + + Some forms of lambert equations are: + 1. X**X = C + 2. X*(B*log(X) + D)**A = C + 3. A*log(B*X + A) + d*X = C + 4. (B*X + A)*exp(d*X + g) = C + 5. g*exp(B*X + h) - B*X = C + 6. A*D**(E*X + g) - B*X = C + 7. A*cos(X) + B*sin(X) - D*X = C + 8. A*cosh(X) + B*sinh(X) - D*X = C + + Where X is any variable, + A, B, C, D, E are any constants, + g, h are linear functions or log terms. + + Parameters + ========== + + f : Expr + The equation to be checked + + symbol : Symbol + The variable in which the equation is checked + + Returns + ======= + + If this returns ``False`` then the Lambert solver (``_solve_lambert``) will not be called. + + Examples + ======== + + >>> from sympy.solvers.solveset import _is_lambert + >>> from sympy import symbols, cosh, sinh, log + >>> x = symbols('x') + + >>> _is_lambert(3*log(x) - x*log(3), x) + True + >>> _is_lambert(log(log(x - 3)) + log(x-3), x) + True + >>> _is_lambert(cosh(x) - sinh(x), x) + False + >>> _is_lambert((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1), x) + True + + See Also + ======== + + _solve_lambert + + """ + term_factors = list(_term_factors(f.expand())) + + # total number of symbols in equation + no_of_symbols = len([arg for arg in term_factors if arg.has(symbol)]) + # total number of trigonometric terms in equation + no_of_trig = len([arg for arg in term_factors \ + if arg.has(HyperbolicFunction, TrigonometricFunction)]) + + if f.is_Add and no_of_symbols >= 2: + # `log`, `HyperbolicFunction`, `TrigonometricFunction` should have symbols + # and no_of_trig < no_of_symbols + lambert_funcs = (log, HyperbolicFunction, TrigonometricFunction) + if any(isinstance(arg, lambert_funcs)\ + for arg in term_factors if arg.has(symbol)): + if no_of_trig < no_of_symbols: + return True + # here, `Pow`, `exp` exponent should have symbols + elif any(isinstance(arg, (Pow, exp)) \ + for arg in term_factors if (arg.as_base_exp()[1]).has(symbol)): + return True + return False + + +def _transolve(f, symbol, domain): + r""" + Function to solve transcendental equations. It is a helper to + ``solveset`` and should be used internally. ``_transolve`` + currently supports the following class of equations: + + - Exponential equations + - Logarithmic equations + + Parameters + ========== + + f : Any transcendental equation that needs to be solved. + This needs to be an expression, which is assumed + to be equal to ``0``. + + symbol : The variable for which the equation is solved. + This needs to be of class ``Symbol``. + + domain : A set over which the equation is solved. + This needs to be of class ``Set``. + + Returns + ======= + + Set + A set of values for ``symbol`` for which ``f`` is equal to + zero. An ``EmptySet`` is returned if ``f`` does not have solutions + in respective domain. A ``ConditionSet`` is returned as unsolved + object if algorithms to evaluate complete solution are not + yet implemented. + + How to use ``_transolve`` + ========================= + + ``_transolve`` should not be used as an independent function, because + it assumes that the equation (``f``) and the ``symbol`` comes from + ``solveset`` and might have undergone a few modification(s). + To use ``_transolve`` as an independent function the equation (``f``) + and the ``symbol`` should be passed as they would have been by + ``solveset``. + + Examples + ======== + + >>> from sympy.solvers.solveset import _transolve as transolve + >>> from sympy.solvers.solvers import _tsolve as tsolve + >>> from sympy import symbols, S, pprint + >>> x = symbols('x', real=True) # assumption added + >>> transolve(5**(x - 3) - 3**(2*x + 1), x, S.Reals) + {-(log(3) + 3*log(5))/(-log(5) + 2*log(3))} + + How ``_transolve`` works + ======================== + + ``_transolve`` uses two types of helper functions to solve equations + of a particular class: + + Identifying helpers: To determine whether a given equation + belongs to a certain class of equation or not. Returns either + ``True`` or ``False``. + + Solving helpers: Once an equation is identified, a corresponding + helper either solves the equation or returns a form of the equation + that ``solveset`` might better be able to handle. + + * Philosophy behind the module + + The purpose of ``_transolve`` is to take equations which are not + already polynomial in their generator(s) and to either recast them + as such through a valid transformation or to solve them outright. + A pair of helper functions for each class of supported + transcendental functions are employed for this purpose. One + identifies the transcendental form of an equation and the other + either solves it or recasts it into a tractable form that can be + solved by ``solveset``. + For example, an equation in the form `ab^{f(x)} - cd^{g(x)} = 0` + can be transformed to + `\log(a) + f(x)\log(b) - \log(c) - g(x)\log(d) = 0` + (under certain assumptions) and this can be solved with ``solveset`` + if `f(x)` and `g(x)` are in polynomial form. + + How ``_transolve`` is better than ``_tsolve`` + ============================================= + + 1) Better output + + ``_transolve`` provides expressions in a more simplified form. + + Consider a simple exponential equation + + >>> f = 3**(2*x) - 2**(x + 3) + >>> pprint(transolve(f, x, S.Reals), use_unicode=False) + -3*log(2) + {------------------} + -2*log(3) + log(2) + >>> pprint(tsolve(f, x), use_unicode=False) + / 3 \ + | --------| + | log(2/9)| + [-log\2 /] + + 2) Extensible + + The API of ``_transolve`` is designed such that it is easily + extensible, i.e. the code that solves a given class of + equations is encapsulated in a helper and not mixed in with + the code of ``_transolve`` itself. + + 3) Modular + + ``_transolve`` is designed to be modular i.e, for every class of + equation a separate helper for identification and solving is + implemented. This makes it easy to change or modify any of the + method implemented directly in the helpers without interfering + with the actual structure of the API. + + 4) Faster Computation + + Solving equation via ``_transolve`` is much faster as compared to + ``_tsolve``. In ``solve``, attempts are made computing every possibility + to get the solutions. This series of attempts makes solving a bit + slow. In ``_transolve``, computation begins only after a particular + type of equation is identified. + + How to add new class of equations + ================================= + + Adding a new class of equation solver is a three-step procedure: + + - Identify the type of the equations + + Determine the type of the class of equations to which they belong: + it could be of ``Add``, ``Pow``, etc. types. Separate internal functions + are used for each type. Write identification and solving helpers + and use them from within the routine for the given type of equation + (after adding it, if necessary). Something like: + + .. code-block:: python + + def add_type(lhs, rhs, x): + .... + if _is_exponential(lhs, x): + new_eq = _solve_exponential(lhs, rhs, x) + .... + rhs, lhs = eq.as_independent(x) + if lhs.is_Add: + result = add_type(lhs, rhs, x) + + - Define the identification helper. + + - Define the solving helper. + + Apart from this, a few other things needs to be taken care while + adding an equation solver: + + - Naming conventions: + Name of the identification helper should be as + ``_is_class`` where class will be the name or abbreviation + of the class of equation. The solving helper will be named as + ``_solve_class``. + For example: for exponential equations it becomes + ``_is_exponential`` and ``_solve_expo``. + - The identifying helpers should take two input parameters, + the equation to be checked and the variable for which a solution + is being sought, while solving helpers would require an additional + domain parameter. + - Be sure to consider corner cases. + - Add tests for each helper. + - Add a docstring to your helper that describes the method + implemented. + The documentation of the helpers should identify: + + - the purpose of the helper, + - the method used to identify and solve the equation, + - a proof of correctness + - the return values of the helpers + """ + + def add_type(lhs, rhs, symbol, domain): + """ + Helper for ``_transolve`` to handle equations of + ``Add`` type, i.e. equations taking the form as + ``a*f(x) + b*g(x) + .... = c``. + For example: 4**x + 8**x = 0 + """ + result = ConditionSet(symbol, Eq(lhs - rhs, 0), domain) + + # check if it is exponential type equation + if _is_exponential(lhs, symbol): + result = _solve_exponential(lhs, rhs, symbol, domain) + # check if it is logarithmic type equation + elif _is_logarithmic(lhs, symbol): + result = _solve_logarithm(lhs, rhs, symbol, domain) + + return result + + result = ConditionSet(symbol, Eq(f, 0), domain) + + # invert_complex handles the call to the desired inverter based + # on the domain specified. + lhs, rhs_s = invert_complex(f, 0, symbol, domain) + + if isinstance(rhs_s, FiniteSet): + assert (len(rhs_s.args)) == 1 + rhs = rhs_s.args[0] + + if lhs.is_Add: + result = add_type(lhs, rhs, symbol, domain) + else: + result = rhs_s + + return result + + +def solveset(f, symbol=None, domain=S.Complexes): + r"""Solves a given inequality or equation with set as output + + Parameters + ========== + + f : Expr or a relational. + The target equation or inequality + symbol : Symbol + The variable for which the equation is solved + domain : Set + The domain over which the equation is solved + + Returns + ======= + + Set + A set of values for `symbol` for which `f` is True or is equal to + zero. An :class:`~.EmptySet` is returned if `f` is False or nonzero. + A :class:`~.ConditionSet` is returned as unsolved object if algorithms + to evaluate complete solution are not yet implemented. + + ``solveset`` claims to be complete in the solution set that it returns. + + Raises + ====== + + NotImplementedError + The algorithms to solve inequalities in complex domain are + not yet implemented. + ValueError + The input is not valid. + RuntimeError + It is a bug, please report to the github issue tracker. + + + Notes + ===== + + Python interprets 0 and 1 as False and True, respectively, but + in this function they refer to solutions of an expression. So 0 and 1 + return the domain and EmptySet, respectively, while True and False + return the opposite (as they are assumed to be solutions of relational + expressions). + + + See Also + ======== + + solveset_real: solver for real domain + solveset_complex: solver for complex domain + + Examples + ======== + + >>> from sympy import exp, sin, Symbol, pprint, S, Eq + >>> from sympy.solvers.solveset import solveset, solveset_real + + * The default domain is complex. Not specifying a domain will lead + to the solving of the equation in the complex domain (and this + is not affected by the assumptions on the symbol): + + >>> x = Symbol('x') + >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) + {2*n*I*pi | n in Integers} + + >>> x = Symbol('x', real=True) + >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) + {2*n*I*pi | n in Integers} + + * If you want to use ``solveset`` to solve the equation in the + real domain, provide a real domain. (Using ``solveset_real`` + does this automatically.) + + >>> R = S.Reals + >>> x = Symbol('x') + >>> solveset(exp(x) - 1, x, R) + {0} + >>> solveset_real(exp(x) - 1, x) + {0} + + The solution is unaffected by assumptions on the symbol: + + >>> p = Symbol('p', positive=True) + >>> pprint(solveset(p**2 - 4)) + {-2, 2} + + When a :class:`~.ConditionSet` is returned, symbols with assumptions that + would alter the set are replaced with more generic symbols: + + >>> i = Symbol('i', imaginary=True) + >>> solveset(Eq(i**2 + i*sin(i), 1), i, domain=S.Reals) + ConditionSet(_R, Eq(_R**2 + _R*sin(_R) - 1, 0), Reals) + + * Inequalities can be solved over the real domain only. Use of a complex + domain leads to a NotImplementedError. + + >>> solveset(exp(x) > 1, x, R) + Interval.open(0, oo) + + """ + f = sympify(f) + symbol = sympify(symbol) + + if f is S.true: + return domain + + if f is S.false: + return S.EmptySet + + if not isinstance(f, (Expr, Relational, Number)): + raise ValueError("%s is not a valid SymPy expression" % f) + + if not isinstance(symbol, (Expr, Relational)) and symbol is not None: + raise ValueError("%s is not a valid SymPy symbol" % (symbol,)) + + if not isinstance(domain, Set): + raise ValueError("%s is not a valid domain" %(domain)) + + free_symbols = f.free_symbols + + if f.has(Piecewise): + f = piecewise_fold(f) + + if symbol is None and not free_symbols: + b = Eq(f, 0) + if b is S.true: + return domain + elif b is S.false: + return S.EmptySet + else: + raise NotImplementedError(filldedent(''' + relationship between value and 0 is unknown: %s''' % b)) + + if symbol is None: + if len(free_symbols) == 1: + symbol = free_symbols.pop() + elif free_symbols: + raise ValueError(filldedent(''' + The independent variable must be specified for a + multivariate equation.''')) + elif not isinstance(symbol, Symbol): + f, s, swap = recast_to_symbols([f], [symbol]) + # the xreplace will be needed if a ConditionSet is returned + return solveset(f[0], s[0], domain).xreplace(swap) + + # solveset should ignore assumptions on symbols + newsym = None + if domain.is_subset(S.Reals): + if symbol._assumptions_orig != {'real': True}: + newsym = Dummy('R', real=True) + elif domain.is_subset(S.Complexes): + if symbol._assumptions_orig != {'complex': True}: + newsym = Dummy('C', complex=True) + + if newsym is not None: + rv = solveset(f.xreplace({symbol: newsym}), newsym, domain) + # try to use the original symbol if possible + try: + _rv = rv.xreplace({newsym: symbol}) + except TypeError: + _rv = rv + if rv.dummy_eq(_rv): + rv = _rv + return rv + + # Abs has its own handling method which avoids the + # rewriting property that the first piece of abs(x) + # is for x >= 0 and the 2nd piece for x < 0 -- solutions + # can look better if the 2nd condition is x <= 0. Since + # the solution is a set, duplication of results is not + # an issue, e.g. {y, -y} when y is 0 will be {0} + f, mask = _masked(f, Abs) + f = f.rewrite(Piecewise) # everything that's not an Abs + for d, e in mask: + # everything *in* an Abs + e = e.func(e.args[0].rewrite(Piecewise)) + f = f.xreplace({d: e}) + f = piecewise_fold(f) + + return _solveset(f, symbol, domain, _check=True) + + +def solveset_real(f, symbol): + return solveset(f, symbol, S.Reals) + + +def solveset_complex(f, symbol): + return solveset(f, symbol, S.Complexes) + + +def _solveset_multi(eqs, syms, domains): + '''Basic implementation of a multivariate solveset. + + For internal use (not ready for public consumption)''' + + rep = {} + for sym, dom in zip(syms, domains): + if dom is S.Reals: + rep[sym] = Symbol(sym.name, real=True) + eqs = [eq.subs(rep) for eq in eqs] + syms = [sym.subs(rep) for sym in syms] + + syms = tuple(syms) + + if len(eqs) == 0: + return ProductSet(*domains) + + if len(syms) == 1: + sym = syms[0] + domain = domains[0] + solsets = [solveset(eq, sym, domain) for eq in eqs] + solset = Intersection(*solsets) + return ImageSet(Lambda((sym,), (sym,)), solset).doit() + + eqs = sorted(eqs, key=lambda eq: len(eq.free_symbols & set(syms))) + + for n, eq in enumerate(eqs): + sols = [] + all_handled = True + for sym in syms: + if sym not in eq.free_symbols: + continue + sol = solveset(eq, sym, domains[syms.index(sym)]) + + if isinstance(sol, FiniteSet): + i = syms.index(sym) + symsp = syms[:i] + syms[i+1:] + domainsp = domains[:i] + domains[i+1:] + eqsp = eqs[:n] + eqs[n+1:] + for s in sol: + eqsp_sub = [eq.subs(sym, s) for eq in eqsp] + sol_others = _solveset_multi(eqsp_sub, symsp, domainsp) + fun = Lambda((symsp,), symsp[:i] + (s,) + symsp[i:]) + sols.append(ImageSet(fun, sol_others).doit()) + else: + all_handled = False + if all_handled: + return Union(*sols) + + +def solvify(f, symbol, domain): + """Solves an equation using solveset and returns the solution in accordance + with the `solve` output API. + + Returns + ======= + + We classify the output based on the type of solution returned by `solveset`. + + Solution | Output + ---------------------------------------- + FiniteSet | list + + ImageSet, | list (if `f` is periodic) + Union | + + Union | list (with FiniteSet) + + EmptySet | empty list + + Others | None + + + Raises + ====== + + NotImplementedError + A ConditionSet is the input. + + Examples + ======== + + >>> from sympy.solvers.solveset import solvify + >>> from sympy.abc import x + >>> from sympy import S, tan, sin, exp + >>> solvify(x**2 - 9, x, S.Reals) + [-3, 3] + >>> solvify(sin(x) - 1, x, S.Reals) + [pi/2] + >>> solvify(tan(x), x, S.Reals) + [0] + >>> solvify(exp(x) - 1, x, S.Complexes) + + >>> solvify(exp(x) - 1, x, S.Reals) + [0] + + """ + solution_set = solveset(f, symbol, domain) + result = None + if solution_set is S.EmptySet: + result = [] + + elif isinstance(solution_set, ConditionSet): + raise NotImplementedError('solveset is unable to solve this equation.') + + elif isinstance(solution_set, FiniteSet): + result = list(solution_set) + + else: + period = periodicity(f, symbol) + if period is not None: + solutions = S.EmptySet + iter_solutions = () + if isinstance(solution_set, ImageSet): + iter_solutions = (solution_set,) + elif isinstance(solution_set, Union): + if all(isinstance(i, ImageSet) for i in solution_set.args): + iter_solutions = solution_set.args + + for solution in iter_solutions: + solutions += solution.intersect(Interval(0, period, False, True)) + + if isinstance(solutions, FiniteSet): + result = list(solutions) + + else: + solution = solution_set.intersect(domain) + if isinstance(solution, Union): + # concerned about only FiniteSet with Union but not about ImageSet + # if required could be extend + if any(isinstance(i, FiniteSet) for i in solution.args): + result = [sol for soln in solution.args \ + for sol in soln.args if isinstance(soln,FiniteSet)] + else: + return None + + elif isinstance(solution, FiniteSet): + result += solution + + return result + + +############################################################################### +################################ LINSOLVE ##################################### +############################################################################### + + +def linear_coeffs(eq, *syms, dict=False): + """Return a list whose elements are the coefficients of the + corresponding symbols in the sum of terms in ``eq``. + The additive constant is returned as the last element of the + list. + + Raises + ====== + + NonlinearError + The equation contains a nonlinear term + ValueError + duplicate or unordered symbols are passed + + Parameters + ========== + + dict - (default False) when True, return coefficients as a + dictionary with coefficients keyed to syms that were present; + key 1 gives the constant term + + Examples + ======== + + >>> from sympy.solvers.solveset import linear_coeffs + >>> from sympy.abc import x, y, z + >>> linear_coeffs(3*x + 2*y - 1, x, y) + [3, 2, -1] + + It is not necessary to expand the expression: + + >>> linear_coeffs(x + y*(z*(x*3 + 2) + 3), x) + [3*y*z + 1, y*(2*z + 3)] + + When nonlinear is detected, an error will be raised: + + * even if they would cancel after expansion (so the + situation does not pass silently past the caller's + attention) + + >>> eq = 1/x*(x - 1) + 1/x + >>> linear_coeffs(eq.expand(), x) + [0, 1] + >>> linear_coeffs(eq, x) + Traceback (most recent call last): + ... + NonlinearError: + nonlinear in given generators + + * when there are cross terms + + >>> linear_coeffs(x*(y + 1), x, y) + Traceback (most recent call last): + ... + NonlinearError: + symbol-dependent cross-terms encountered + + * when there are terms that contain an expression + dependent on the symbols that is not linear + + >>> linear_coeffs(x**2, x) + Traceback (most recent call last): + ... + NonlinearError: + nonlinear in given generators + """ + eq = _sympify(eq) + if len(syms) == 1 and iterable(syms[0]) and not isinstance(syms[0], Basic): + raise ValueError('expecting unpacked symbols, *syms') + symset = set(syms) + if len(symset) != len(syms): + raise ValueError('duplicate symbols given') + try: + d, c = _linear_eq_to_dict([eq], symset) + d = d[0] + c = c[0] + except PolyNonlinearError as err: + raise NonlinearError(str(err)) + if dict: + if c: + d[S.One] = c + return d + rv = [S.Zero]*(len(syms) + 1) + rv[-1] = c + for i, k in enumerate(syms): + if k not in d: + continue + rv[i] = d[k] + return rv + + +def linear_eq_to_matrix(equations, *symbols): + r""" + Converts a given System of Equations into Matrix form. Here ``equations`` + must be a linear system of equations in ``symbols``. Element ``M[i, j]`` + corresponds to the coefficient of the jth symbol in the ith equation. + + The Matrix form corresponds to the augmented matrix form. For example: + + .. math:: + + 4x + 2y + 3z & = 1 \\ + 3x + y + z & = -6 \\ + 2x + 4y + 9z & = 2 + + This system will return :math:`A` and :math:`b` as: + + .. math:: + + A = \left[\begin{array}{ccc} + 4 & 2 & 3 \\ + 3 & 1 & 1 \\ + 2 & 4 & 9 + \end{array}\right] \\ + + .. math:: + + b = \left[\begin{array}{c} + 1 \\ -6 \\ 2 + \end{array}\right] + + The only simplification performed is to convert + ``Eq(a, b)`` :math:`\Rightarrow a - b`. + + Raises + ====== + + NonlinearError + The equations contain a nonlinear term. + ValueError + The symbols are not given or are not unique. + + Examples + ======== + + >>> from sympy import linear_eq_to_matrix, symbols + >>> c, x, y, z = symbols('c, x, y, z') + + The coefficients (numerical or symbolic) of the symbols will + be returned as matrices: + + >>> eqns = [c*x + z - 1 - c, y + z, x - y] + >>> A, b = linear_eq_to_matrix(eqns, [x, y, z]) + >>> A + Matrix([ + [c, 0, 1], + [0, 1, 1], + [1, -1, 0]]) + >>> b + Matrix([ + [c + 1], + [ 0], + [ 0]]) + + This routine does not simplify expressions and will raise an error + if nonlinearity is encountered: + + >>> eqns = [ + ... (x**2 - 3*x)/(x - 3) - 3, + ... y**2 - 3*y - y*(y - 4) + x - 4] + >>> linear_eq_to_matrix(eqns, [x, y]) + Traceback (most recent call last): + ... + NonlinearError: + symbol-dependent term can be ignored using `strict=False` + + Simplifying these equations will discard the removable singularity in the + first and reveal the linear structure of the second: + + >>> [e.simplify() for e in eqns] + [x - 3, x + y - 4] + + Any such simplification needed to eliminate nonlinear terms must be done + *before* calling this routine. + + """ + if not symbols: + raise ValueError(filldedent(''' + Symbols must be given, for which coefficients + are to be found. + ''')) + + # Check if 'symbols' is a set and raise an error if it is + if isinstance(symbols[0], set): + raise TypeError( + "Unordered 'set' type is not supported as input for symbols.") + + if hasattr(symbols[0], '__iter__'): + symbols = symbols[0] + + if has_dups(symbols): + raise ValueError('Symbols must be unique') + + equations = sympify(equations) + if isinstance(equations, MatrixBase): + equations = list(equations) + elif isinstance(equations, (Expr, Eq)): + equations = [equations] + elif not is_sequence(equations): + raise ValueError(filldedent(''' + Equation(s) must be given as a sequence, Expr, + Eq or Matrix. + ''')) + + # construct the dictionaries + try: + eq, c = _linear_eq_to_dict(equations, symbols) + except PolyNonlinearError as err: + raise NonlinearError(str(err)) + # prepare output matrices + n, m = shape = len(eq), len(symbols) + ix = dict(zip(symbols, range(m))) + A = zeros(*shape) + for row, d in enumerate(eq): + for k in d: + col = ix[k] + A[row, col] = d[k] + b = Matrix(n, 1, [-i for i in c]) + return A, b + + +def linsolve(system, *symbols): + r""" + Solve system of $N$ linear equations with $M$ variables; both + underdetermined and overdetermined systems are supported. + The possible number of solutions is zero, one or infinite. + Zero solutions throws a ValueError, whereas infinite + solutions are represented parametrically in terms of the given + symbols. For unique solution a :class:`~.FiniteSet` of ordered tuples + is returned. + + All standard input formats are supported: + For the given set of equations, the respective input types + are given below: + + .. math:: 3x + 2y - z = 1 + .. math:: 2x - 2y + 4z = -2 + .. math:: 2x - y + 2z = 0 + + * Augmented matrix form, ``system`` given below: + + $$ \text{system} = \left[{array}{cccc} + 3 & 2 & -1 & 1\\ + 2 & -2 & 4 & -2\\ + 2 & -1 & 2 & 0 + \end{array}\right] $$ + + :: + + system = Matrix([[3, 2, -1, 1], [2, -2, 4, -2], [2, -1, 2, 0]]) + + * List of equations form + + :: + + system = [3x + 2y - z - 1, 2x - 2y + 4z + 2, 2x - y + 2z] + + * Input $A$ and $b$ in matrix form (from $Ax = b$) are given as: + + $$ A = \left[\begin{array}{ccc} + 3 & 2 & -1 \\ + 2 & -2 & 4 \\ + 2 & -1 & 2 + \end{array}\right] \ \ b = \left[\begin{array}{c} + 1 \\ -2 \\ 0 + \end{array}\right] $$ + + :: + + A = Matrix([[3, 2, -1], [2, -2, 4], [2, -1, 2]]) + b = Matrix([[1], [-2], [0]]) + system = (A, b) + + Symbols can always be passed but are actually only needed + when 1) a system of equations is being passed and 2) the + system is passed as an underdetermined matrix and one wants + to control the name of the free variables in the result. + An error is raised if no symbols are used for case 1, but if + no symbols are provided for case 2, internally generated symbols + will be provided. When providing symbols for case 2, there should + be at least as many symbols are there are columns in matrix A. + + The algorithm used here is Gauss-Jordan elimination, which + results, after elimination, in a row echelon form matrix. + + Returns + ======= + + A FiniteSet containing an ordered tuple of values for the + unknowns for which the `system` has a solution. (Wrapping + the tuple in FiniteSet is used to maintain a consistent + output format throughout solveset.) + + Returns EmptySet, if the linear system is inconsistent. + + Raises + ====== + + ValueError + The input is not valid. + The symbols are not given. + + Examples + ======== + + >>> from sympy import Matrix, linsolve, symbols + >>> x, y, z = symbols("x, y, z") + >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]]) + >>> b = Matrix([3, 6, 9]) + >>> A + Matrix([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 10]]) + >>> b + Matrix([ + [3], + [6], + [9]]) + >>> linsolve((A, b), [x, y, z]) + {(-1, 2, 0)} + + * Parametric Solution: In case the system is underdetermined, the + function will return a parametric solution in terms of the given + symbols. Those that are free will be returned unchanged. e.g. in + the system below, `z` is returned as the solution for variable z; + it can take on any value. + + >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> b = Matrix([3, 6, 9]) + >>> linsolve((A, b), x, y, z) + {(z - 1, 2 - 2*z, z)} + + If no symbols are given, internally generated symbols will be used. + The ``tau0`` in the third position indicates (as before) that the third + variable -- whatever it is named -- can take on any value: + + >>> linsolve((A, b)) + {(tau0 - 1, 2 - 2*tau0, tau0)} + + * List of equations as input + + >>> Eqns = [3*x + 2*y - z - 1, 2*x - 2*y + 4*z + 2, - x + y/2 - z] + >>> linsolve(Eqns, x, y, z) + {(1, -2, -2)} + + * Augmented matrix as input + + >>> aug = Matrix([[2, 1, 3, 1], [2, 6, 8, 3], [6, 8, 18, 5]]) + >>> aug + Matrix([ + [2, 1, 3, 1], + [2, 6, 8, 3], + [6, 8, 18, 5]]) + >>> linsolve(aug, x, y, z) + {(3/10, 2/5, 0)} + + * Solve for symbolic coefficients + + >>> a, b, c, d, e, f = symbols('a, b, c, d, e, f') + >>> eqns = [a*x + b*y - c, d*x + e*y - f] + >>> linsolve(eqns, x, y) + {((-b*f + c*e)/(a*e - b*d), (a*f - c*d)/(a*e - b*d))} + + * A degenerate system returns solution as set of given + symbols. + + >>> system = Matrix(([0, 0, 0], [0, 0, 0], [0, 0, 0])) + >>> linsolve(system, x, y) + {(x, y)} + + * For an empty system linsolve returns empty set + + >>> linsolve([], x) + EmptySet + + * An error is raised if any nonlinearity is detected, even + if it could be removed with expansion + + >>> linsolve([x*(1/x - 1)], x) + Traceback (most recent call last): + ... + NonlinearError: nonlinear term: 1/x + + >>> linsolve([x*(y + 1)], x, y) + Traceback (most recent call last): + ... + NonlinearError: nonlinear cross-term: x*(y + 1) + + >>> linsolve([x**2 - 1], x) + Traceback (most recent call last): + ... + NonlinearError: nonlinear term: x**2 + """ + if not system: + return S.EmptySet + + # If second argument is an iterable + if symbols and hasattr(symbols[0], '__iter__'): + symbols = symbols[0] + sym_gen = isinstance(symbols, GeneratorType) + dup_msg = 'duplicate symbols given' + + + b = None # if we don't get b the input was bad + # unpack system + + if hasattr(system, '__iter__'): + + # 1). (A, b) + if len(system) == 2 and isinstance(system[0], MatrixBase): + A, b = system + + # 2). (eq1, eq2, ...) + if not isinstance(system[0], MatrixBase): + if sym_gen or not symbols: + raise ValueError(filldedent(''' + When passing a system of equations, the explicit + symbols for which a solution is being sought must + be given as a sequence, too. + ''')) + if len(set(symbols)) != len(symbols): + raise ValueError(dup_msg) + + # + # Pass to the sparse solver implemented in polys. It is important + # that we do not attempt to convert the equations to a matrix + # because that would be very inefficient for large sparse systems + # of equations. + # + eqs = system + eqs = [sympify(eq) for eq in eqs] + try: + sol = _linsolve(eqs, symbols) + except PolyNonlinearError as exc: + # e.g. cos(x) contains an element of the set of generators + raise NonlinearError(str(exc)) + + if sol is None: + return S.EmptySet + + sol = FiniteSet(Tuple(*(sol.get(sym, sym) for sym in symbols))) + return sol + + elif isinstance(system, MatrixBase) and not ( + symbols and not isinstance(symbols, GeneratorType) and + isinstance(symbols[0], MatrixBase)): + # 3). A augmented with b + A, b = system[:, :-1], system[:, -1:] + + if b is None: + raise ValueError("Invalid arguments") + if sym_gen: + symbols = [next(symbols) for i in range(A.cols)] + symset = set(symbols) + if any(symset & (A.free_symbols | b.free_symbols)): + raise ValueError(filldedent(''' + At least one of the symbols provided + already appears in the system to be solved. + One way to avoid this is to use Dummy symbols in + the generator, e.g. numbered_symbols('%s', cls=Dummy) + ''' % symbols[0].name.rstrip('1234567890'))) + elif len(symset) != len(symbols): + raise ValueError(dup_msg) + + if not symbols: + symbols = [Dummy() for _ in range(A.cols)] + name = _uniquely_named_symbol('tau', (A, b), + compare=lambda i: str(i).rstrip('1234567890')).name + gen = numbered_symbols(name) + else: + gen = None + + # This is just a wrapper for solve_lin_sys + eqs = [] + rows = A.tolist() + for rowi, bi in zip(rows, b): + terms = [elem * sym for elem, sym in zip(rowi, symbols) if elem] + terms.append(-bi) + eqs.append(Add(*terms)) + + eqs, ring = sympy_eqs_to_ring(eqs, symbols) + sol = solve_lin_sys(eqs, ring, _raw=False) + if sol is None: + return S.EmptySet + #sol = {sym:val for sym, val in sol.items() if sym != val} + sol = FiniteSet(Tuple(*(sol.get(sym, sym) for sym in symbols))) + + if gen is not None: + solsym = sol.free_symbols + rep = {sym: next(gen) for sym in symbols if sym in solsym} + sol = sol.subs(rep) + + return sol + + +############################################################################## +# ------------------------------nonlinsolve ---------------------------------# +############################################################################## + + +def _return_conditionset(eqs, symbols): + # return conditionset + eqs = (Eq(lhs, 0) for lhs in eqs) + condition_set = ConditionSet( + Tuple(*symbols), And(*eqs), S.Complexes**len(symbols)) + return condition_set + + +def substitution(system, symbols, result=[{}], known_symbols=[], + exclude=[], all_symbols=None): + r""" + Solves the `system` using substitution method. It is used in + :func:`~.nonlinsolve`. This will be called from :func:`~.nonlinsolve` when any + equation(s) is non polynomial equation. + + Parameters + ========== + + system : list of equations + The target system of equations + symbols : list of symbols to be solved. + The variable(s) for which the system is solved + known_symbols : list of solved symbols + Values are known for these variable(s) + result : An empty list or list of dict + If No symbol values is known then empty list otherwise + symbol as keys and corresponding value in dict. + exclude : Set of expression. + Mostly denominator expression(s) of the equations of the system. + Final solution should not satisfy these expressions. + all_symbols : known_symbols + symbols(unsolved). + + Returns + ======= + + A FiniteSet of ordered tuple of values of `all_symbols` for which the + `system` has solution. Order of values in the tuple is same as symbols + present in the parameter `all_symbols`. If parameter `all_symbols` is None + then same as symbols present in the parameter `symbols`. + + Please note that general FiniteSet is unordered, the solution returned + here is not simply a FiniteSet of solutions, rather it is a FiniteSet of + ordered tuple, i.e. the first & only argument to FiniteSet is a tuple of + solutions, which is ordered, & hence the returned solution is ordered. + + Also note that solution could also have been returned as an ordered tuple, + FiniteSet is just a wrapper `{}` around the tuple. It has no other + significance except for the fact it is just used to maintain a consistent + output format throughout the solveset. + + Raises + ====== + + ValueError + The input is not valid. + The symbols are not given. + AttributeError + The input symbols are not :class:`~.Symbol` type. + + Examples + ======== + + >>> from sympy import symbols, substitution + >>> x, y = symbols('x, y', real=True) + >>> substitution([x + y], [x], [{y: 1}], [y], set([]), [x, y]) + {(-1, 1)} + + * When you want a soln not satisfying $x + 1 = 0$ + + >>> substitution([x + y], [x], [{y: 1}], [y], set([x + 1]), [y, x]) + EmptySet + >>> substitution([x + y], [x], [{y: 1}], [y], set([x - 1]), [y, x]) + {(1, -1)} + >>> substitution([x + y - 1, y - x**2 + 5], [x, y]) + {(-3, 4), (2, -1)} + + * Returns both real and complex solution + + >>> x, y, z = symbols('x, y, z') + >>> from sympy import exp, sin + >>> substitution([exp(x) - sin(y), y**2 - 4], [x, y]) + {(ImageSet(Lambda(_n, I*(2*_n*pi + pi) + log(sin(2))), Integers), -2), + (ImageSet(Lambda(_n, 2*_n*I*pi + log(sin(2))), Integers), 2)} + + >>> eqs = [z**2 + exp(2*x) - sin(y), -3 + exp(-y)] + >>> substitution(eqs, [y, z]) + {(-log(3), -sqrt(-exp(2*x) - sin(log(3)))), + (-log(3), sqrt(-exp(2*x) - sin(log(3)))), + (ImageSet(Lambda(_n, 2*_n*I*pi - log(3)), Integers), + ImageSet(Lambda(_n, -sqrt(-exp(2*x) + sin(2*_n*I*pi - log(3)))), Integers)), + (ImageSet(Lambda(_n, 2*_n*I*pi - log(3)), Integers), + ImageSet(Lambda(_n, sqrt(-exp(2*x) + sin(2*_n*I*pi - log(3)))), Integers))} + + """ + + if not system: + return S.EmptySet + + for i, e in enumerate(system): + if isinstance(e, Eq): + system[i] = e.lhs - e.rhs + + if not symbols: + msg = ('Symbols must be given, for which solution of the ' + 'system is to be found.') + raise ValueError(filldedent(msg)) + + if not is_sequence(symbols): + msg = ('symbols should be given as a sequence, e.g. a list.' + 'Not type %s: %s') + raise TypeError(filldedent(msg % (type(symbols), symbols))) + + if not getattr(symbols[0], 'is_Symbol', False): + msg = ('Iterable of symbols must be given as ' + 'second argument, not type %s: %s') + raise ValueError(filldedent(msg % (type(symbols[0]), symbols[0]))) + + # By default `all_symbols` will be same as `symbols` + if all_symbols is None: + all_symbols = symbols + + old_result = result + # storing complements and intersection for particular symbol + complements = {} + intersections = {} + + # when total_solveset_call equals total_conditionset + # it means that solveset failed to solve all eqs. + total_conditionset = -1 + total_solveset_call = -1 + + def _unsolved_syms(eq, sort=False): + """Returns the unsolved symbol present + in the equation `eq`. + """ + free = eq.free_symbols + unsolved = (free - set(known_symbols)) & set(all_symbols) + if sort: + unsolved = list(unsolved) + unsolved.sort(key=default_sort_key) + return unsolved + + # sort such that equation with the fewest potential symbols is first. + # means eq with less number of variable first in the list. + eqs_in_better_order = list( + ordered(system, lambda _: len(_unsolved_syms(_)))) + + def add_intersection_complement(result, intersection_dict, complement_dict): + # If solveset has returned some intersection/complement + # for any symbol, it will be added in the final solution. + final_result = [] + for res in result: + res_copy = res + for key_res, value_res in res.items(): + intersect_set, complement_set = None, None + for key_sym, value_sym in intersection_dict.items(): + if key_sym == key_res: + intersect_set = value_sym + for key_sym, value_sym in complement_dict.items(): + if key_sym == key_res: + complement_set = value_sym + if intersect_set or complement_set: + new_value = FiniteSet(value_res) + if intersect_set and intersect_set != S.Complexes: + new_value = Intersection(new_value, intersect_set) + if complement_set: + new_value = Complement(new_value, complement_set) + if new_value is S.EmptySet: + res_copy = None + break + elif new_value.is_FiniteSet and len(new_value) == 1: + res_copy[key_res] = set(new_value).pop() + else: + res_copy[key_res] = new_value + + if res_copy is not None: + final_result.append(res_copy) + return final_result + + def _extract_main_soln(sym, sol, soln_imageset): + """Separate the Complements, Intersections, ImageSet lambda expr and + its base_set. This function returns the unmasked sol from different classes + of sets and also returns the appended ImageSet elements in a + soln_imageset dict: `{unmasked element: ImageSet}`. + """ + # if there is union, then need to check + # Complement, Intersection, Imageset. + # Order should not be changed. + if isinstance(sol, ConditionSet): + # extracts any solution in ConditionSet + sol = sol.base_set + + if isinstance(sol, Complement): + # extract solution and complement + complements[sym] = sol.args[1] + sol = sol.args[0] + # complement will be added at the end + # using `add_intersection_complement` method + + # if there is union of Imageset or other in soln. + # no testcase is written for this if block + if isinstance(sol, Union): + sol_args = sol.args + sol = S.EmptySet + # We need in sequence so append finteset elements + # and then imageset or other. + for sol_arg2 in sol_args: + if isinstance(sol_arg2, FiniteSet): + sol += sol_arg2 + else: + # ImageSet, Intersection, complement then + # append them directly + sol += FiniteSet(sol_arg2) + + if isinstance(sol, Intersection): + # Interval/Set will be at 0th index always + if sol.args[0] not in (S.Reals, S.Complexes): + # Sometimes solveset returns soln with intersection + # S.Reals or S.Complexes. We don't consider that + # intersection. + intersections[sym] = sol.args[0] + sol = sol.args[1] + # after intersection and complement Imageset should + # be checked. + if isinstance(sol, ImageSet): + soln_imagest = sol + expr2 = sol.lamda.expr + sol = FiniteSet(expr2) + soln_imageset[expr2] = soln_imagest + + if not isinstance(sol, FiniteSet): + sol = FiniteSet(sol) + return sol, soln_imageset + + def _check_exclude(rnew, imgset_yes): + rnew_ = rnew + if imgset_yes: + # replace all dummy variables (Imageset lambda variables) + # with zero before `checksol`. Considering fundamental soln + # for `checksol`. + rnew_copy = rnew.copy() + dummy_n = imgset_yes[0] + for key_res, value_res in rnew_copy.items(): + rnew_copy[key_res] = value_res.subs(dummy_n, 0) + rnew_ = rnew_copy + # satisfy_exclude == true if it satisfies the expr of `exclude` list. + try: + # something like : `Mod(-log(3), 2*I*pi)` can't be + # simplified right now, so `checksol` returns `TypeError`. + # when this issue is fixed this try block should be + # removed. Mod(-log(3), 2*I*pi) == -log(3) + satisfy_exclude = any( + checksol(d, rnew_) for d in exclude) + except TypeError: + satisfy_exclude = None + return satisfy_exclude + + def _restore_imgset(rnew, original_imageset, newresult): + restore_sym = set(rnew.keys()) & \ + set(original_imageset.keys()) + for key_sym in restore_sym: + img = original_imageset[key_sym] + rnew[key_sym] = img + if rnew not in newresult: + newresult.append(rnew) + + def _append_eq(eq, result, res, delete_soln, n=None): + u = Dummy('u') + if n: + eq = eq.subs(n, 0) + satisfy = eq if eq in (True, False) else checksol(u, u, eq, minimal=True) + if satisfy is False: + delete_soln = True + res = {} + else: + result.append(res) + return result, res, delete_soln + + def _append_new_soln(rnew, sym, sol, imgset_yes, soln_imageset, + original_imageset, newresult, eq=None): + """If `rnew` (A dict ) contains valid soln + append it to `newresult` list. + `imgset_yes` is (base, dummy_var) if there was imageset in previously + calculated result(otherwise empty tuple). `original_imageset` is dict + of imageset expr and imageset from this result. + `soln_imageset` dict of imageset expr and imageset of new soln. + """ + satisfy_exclude = _check_exclude(rnew, imgset_yes) + delete_soln = False + # soln should not satisfy expr present in `exclude` list. + if not satisfy_exclude: + local_n = None + # if it is imageset + if imgset_yes: + local_n = imgset_yes[0] + base = imgset_yes[1] + if sym and sol: + # when `sym` and `sol` is `None` means no new + # soln. In that case we will append rnew directly after + # substituting original imagesets in rnew values if present + # (second last line of this function using _restore_imgset) + dummy_list = list(sol.atoms(Dummy)) + # use one dummy `n` which is in + # previous imageset + local_n_list = [ + local_n for i in range( + 0, len(dummy_list))] + + dummy_zip = zip(dummy_list, local_n_list) + lam = Lambda(local_n, sol.subs(dummy_zip)) + rnew[sym] = ImageSet(lam, base) + if eq is not None: + newresult, rnew, delete_soln = _append_eq( + eq, newresult, rnew, delete_soln, local_n) + elif eq is not None: + newresult, rnew, delete_soln = _append_eq( + eq, newresult, rnew, delete_soln) + elif sol in soln_imageset.keys(): + rnew[sym] = soln_imageset[sol] + # restore original imageset + _restore_imgset(rnew, original_imageset, newresult) + else: + newresult.append(rnew) + elif satisfy_exclude: + delete_soln = True + rnew = {} + _restore_imgset(rnew, original_imageset, newresult) + return newresult, delete_soln + + def _new_order_result(result, eq): + # separate first, second priority. `res` that makes `eq` value equals + # to zero, should be used first then other result(second priority). + # If it is not done then we may miss some soln. + first_priority = [] + second_priority = [] + for res in result: + if not any(isinstance(val, ImageSet) for val in res.values()): + if eq.subs(res) == 0: + first_priority.append(res) + else: + second_priority.append(res) + if first_priority or second_priority: + return first_priority + second_priority + return result + + def _solve_using_known_values(result, solver): + """Solves the system using already known solution + (result contains the dict ). + solver is :func:`~.solveset_complex` or :func:`~.solveset_real`. + """ + # stores imageset . + soln_imageset = {} + total_solvest_call = 0 + total_conditionst = 0 + + # sort equations so the one with the fewest potential + # symbols appears first + for index, eq in enumerate(eqs_in_better_order): + newresult = [] + # if imageset, expr is used to solve for other symbol + imgset_yes = False + for res in result: + original_imageset = {} + got_symbol = set() # symbols solved in one iteration + # find the imageset and use its expr. + for k, v in res.items(): + if isinstance(v, ImageSet): + res[k] = v.lamda.expr + original_imageset[k] = v + dummy_n = v.lamda.expr.atoms(Dummy).pop() + (base,) = v.base_sets + imgset_yes = (dummy_n, base) + assert not isinstance(v, FiniteSet) # if so, internal error + # update eq with everything that is known so far + eq2 = eq.subs(res).expand() + if imgset_yes and not eq2.has(imgset_yes[0]): + # The substituted equation simplified in such a way that + # it's no longer necessary to encapsulate a potential new + # solution in an ImageSet. (E.g. at the previous step some + # {n*2*pi} was found as partial solution for one of the + # unknowns, but its main solution expression n*2*pi has now + # been substituted in a trigonometric function.) + imgset_yes = False + + unsolved_syms = _unsolved_syms(eq2, sort=True) + if not unsolved_syms: + if res: + newresult, delete_res = _append_new_soln( + res, None, None, imgset_yes, soln_imageset, + original_imageset, newresult, eq2) + if delete_res: + # `delete_res` is true, means substituting `res` in + # eq2 doesn't return `zero` or deleting the `res` + # (a soln) since it satisfies expr of `exclude` + # list. + result.remove(res) + continue # skip as it's independent of desired symbols + depen1, depen2 = eq2.as_independent(*unsolved_syms) + if (depen1.has(Abs) or depen2.has(Abs)) and solver == solveset_complex: + # Absolute values cannot be inverted in the + # complex domain + continue + soln_imageset = {} + for sym in unsolved_syms: + not_solvable = False + try: + soln = solver(eq2, sym) + total_solvest_call += 1 + soln_new = S.EmptySet + if isinstance(soln, Complement): + # separate solution and complement + complements[sym] = soln.args[1] + soln = soln.args[0] + # complement will be added at the end + if isinstance(soln, Intersection): + # Interval will be at 0th index always + if soln.args[0] != Interval(-oo, oo): + # sometimes solveset returns soln + # with intersection S.Reals, to confirm that + # soln is in domain=S.Reals + intersections[sym] = soln.args[0] + soln_new += soln.args[1] + soln = soln_new if soln_new else soln + if index > 0 and solver == solveset_real: + # one symbol's real soln, another symbol may have + # corresponding complex soln. + if not isinstance(soln, (ImageSet, ConditionSet)): + soln += solveset_complex(eq2, sym) # might give ValueError with Abs + except (NotImplementedError, ValueError): + # If solveset is not able to solve equation `eq2`. Next + # time we may get soln using next equation `eq2` + continue + if isinstance(soln, ConditionSet): + if soln.base_set in (S.Reals, S.Complexes): + soln = S.EmptySet + # don't do `continue` we may get soln + # in terms of other symbol(s) + not_solvable = True + total_conditionst += 1 + else: + soln = soln.base_set + + if soln is not S.EmptySet: + soln, soln_imageset = _extract_main_soln( + sym, soln, soln_imageset) + + for sol in soln: + # sol is not a `Union` since we checked it + # before this loop + sol, soln_imageset = _extract_main_soln( + sym, sol, soln_imageset) + sol = set(sol).pop() # XXX what if there are more solutions? + free = sol.free_symbols + if got_symbol and any( + ss in free for ss in got_symbol + ): + # sol depends on previously solved symbols + # then continue + continue + rnew = res.copy() + # put each solution in res and append the new result + # in the new result list (solution for symbol `s`) + # along with old results. + for k, v in res.items(): + if isinstance(v, Expr) and isinstance(sol, Expr): + # if any unsolved symbol is present + # Then subs known value + rnew[k] = v.subs(sym, sol) + # and add this new solution + if sol in soln_imageset.keys(): + # replace all lambda variables with 0. + imgst = soln_imageset[sol] + rnew[sym] = imgst.lamda( + *[0 for i in range(0, len( + imgst.lamda.variables))]) + else: + rnew[sym] = sol + newresult, delete_res = _append_new_soln( + rnew, sym, sol, imgset_yes, soln_imageset, + original_imageset, newresult) + if delete_res: + # deleting the `res` (a soln) since it satisfies + # eq of `exclude` list + result.remove(res) + # solution got for sym + if not not_solvable: + got_symbol.add(sym) + # next time use this new soln + if newresult: + result = newresult + return result, total_solvest_call, total_conditionst + + new_result_real, solve_call1, cnd_call1 = _solve_using_known_values( + old_result, solveset_real) + new_result_complex, solve_call2, cnd_call2 = _solve_using_known_values( + old_result, solveset_complex) + + # If total_solveset_call is equal to total_conditionset + # then solveset failed to solve all of the equations. + # In this case we return a ConditionSet here. + total_conditionset += (cnd_call1 + cnd_call2) + total_solveset_call += (solve_call1 + solve_call2) + + if total_conditionset == total_solveset_call and total_solveset_call != -1: + return _return_conditionset(eqs_in_better_order, all_symbols) + + # don't keep duplicate solutions + filtered_complex = [] + for i in list(new_result_complex): + for j in list(new_result_real): + if i.keys() != j.keys(): + continue + if all(a.dummy_eq(b) for a, b in zip(i.values(), j.values()) \ + if not (isinstance(a, int) and isinstance(b, int))): + break + else: + filtered_complex.append(i) + # overall result + result = new_result_real + filtered_complex + + result_all_variables = [] + result_infinite = [] + for res in result: + if not res: + # means {None : None} + continue + # If length < len(all_symbols) means infinite soln. + # Some or all the soln is dependent on 1 symbol. + # eg. {x: y+2} then final soln {x: y+2, y: y} + if len(res) < len(all_symbols): + solved_symbols = res.keys() + unsolved = list(filter( + lambda x: x not in solved_symbols, all_symbols)) + for unsolved_sym in unsolved: + res[unsolved_sym] = unsolved_sym + result_infinite.append(res) + if res not in result_all_variables: + result_all_variables.append(res) + + if result_infinite: + # we have general soln + # eg : [{x: -1, y : 1}, {x : -y, y: y}] then + # return [{x : -y, y : y}] + result_all_variables = result_infinite + if intersections or complements: + result_all_variables = add_intersection_complement( + result_all_variables, intersections, complements) + + # convert to ordered tuple + result = S.EmptySet + for r in result_all_variables: + temp = [r[symb] for symb in all_symbols] + result += FiniteSet(tuple(temp)) + return result + + +def _solveset_work(system, symbols): + soln = solveset(system[0], symbols[0]) + if isinstance(soln, FiniteSet): + _soln = FiniteSet(*[(s,) for s in soln]) + return _soln + else: + return FiniteSet(tuple(FiniteSet(soln))) + + +def _handle_positive_dimensional(polys, symbols, denominators): + from sympy.polys.polytools import groebner + # substitution method where new system is groebner basis of the system + _symbols = list(symbols) + _symbols.sort(key=default_sort_key) + basis = groebner(polys, _symbols, polys=True) + new_system = [] + for poly_eq in basis: + new_system.append(poly_eq.as_expr()) + result = [{}] + result = substitution( + new_system, symbols, result, [], + denominators) + return result + + +def _handle_zero_dimensional(polys, symbols, system): + # solve 0 dimensional poly system using `solve_poly_system` + result = solve_poly_system(polys, *symbols) + # May be some extra soln is added because + # we used `unrad` in `_separate_poly_nonpoly`, so + # need to check and remove if it is not a soln. + result_update = S.EmptySet + for res in result: + dict_sym_value = dict(list(zip(symbols, res))) + if all(checksol(eq, dict_sym_value) for eq in system): + result_update += FiniteSet(res) + return result_update + + +def _separate_poly_nonpoly(system, symbols): + polys = [] + polys_expr = [] + nonpolys = [] + # unrad_changed stores a list of expressions containing + # radicals that were processed using unrad + # this is useful if solutions need to be checked later. + unrad_changed = [] + denominators = set() + poly = None + for eq in system: + # Store denom expressions that contain symbols + denominators.update(_simple_dens(eq, symbols)) + # Convert equality to expression + if isinstance(eq, Eq): + eq = eq.lhs - eq.rhs + # try to remove sqrt and rational power + without_radicals = unrad(simplify(eq), *symbols) + if without_radicals: + unrad_changed.append(eq) + eq_unrad, cov = without_radicals + if not cov: + eq = eq_unrad + if isinstance(eq, Expr): + eq = eq.as_numer_denom()[0] + poly = eq.as_poly(*symbols, extension=True) + elif simplify(eq).is_number: + continue + if poly is not None: + polys.append(poly) + polys_expr.append(poly.as_expr()) + else: + nonpolys.append(eq) + return polys, polys_expr, nonpolys, denominators, unrad_changed + + +def _handle_poly(polys, symbols): + # _handle_poly(polys, symbols) -> (poly_sol, poly_eqs) + # + # We will return possible solution information to nonlinsolve as well as a + # new system of polynomial equations to be solved if we cannot solve + # everything directly here. The new system of polynomial equations will be + # a lex-order Groebner basis for the original system. The lex basis + # hopefully separate some of the variables and equations and give something + # easier for substitution to work with. + + # The format for representing solution sets in nonlinsolve and substitution + # is a list of dicts. These are the special cases: + no_information = [{}] # No equations solved yet + no_solutions = [] # The system is inconsistent and has no solutions. + + # If there is no need to attempt further solution of these equations then + # we return no equations: + no_equations = [] + + inexact = any(not p.domain.is_Exact for p in polys) + if inexact: + # The use of Groebner over RR is likely to result incorrectly in an + # inconsistent Groebner basis. So, convert any float coefficients to + # Rational before computing the Groebner basis. + polys = [poly(nsimplify(p, rational=True)) for p in polys] + + # Compute a Groebner basis in grevlex order wrt the ordering given. We will + # try to convert this to lex order later. Usually it seems to be more + # efficient to compute a lex order basis by computing a grevlex basis and + # converting to lex with fglm. + basis = groebner(polys, symbols, order='grevlex', polys=False) + + # + # No solutions (inconsistent equations)? + # + if 1 in basis: + + # No solutions: + poly_sol = no_solutions + poly_eqs = no_equations + + # + # Finite number of solutions (zero-dimensional case) + # + elif basis.is_zero_dimensional: + + # Convert Groebner basis to lex ordering + basis = basis.fglm('lex') + + # Convert polynomial coefficients back to float before calling + # solve_poly_system + if inexact: + basis = [nfloat(p) for p in basis] + + # Solve the zero-dimensional case using solve_poly_system if possible. + # If some polynomials have factors that cannot be solved in radicals + # then this will fail. Using solve_poly_system(..., strict=True) + # ensures that we either get a complete solution set in radicals or + # UnsolvableFactorError will be raised. + try: + result = solve_poly_system(basis, *symbols, strict=True) + except UnsolvableFactorError: + # Failure... not fully solvable in radicals. Return the lex-order + # basis for substitution to handle. + poly_sol = no_information + poly_eqs = list(basis) + else: + # Success! We have a finite solution set and solve_poly_system has + # succeeded in finding all solutions. Return the solutions and also + # an empty list of remaining equations to be solved. + poly_sol = [dict(zip(symbols, res)) for res in result] + poly_eqs = no_equations + + # + # Infinite families of solutions (positive-dimensional case) + # + else: + # In this case the grevlex basis cannot be converted to lex using the + # fglm method and also solve_poly_system cannot solve the equations. We + # would like to return a lex basis but since we can't use fglm we + # compute the lex basis directly here. The time required to recompute + # the basis is generally significantly less than the time required by + # substitution to solve the new system. + poly_sol = no_information + poly_eqs = list(groebner(polys, symbols, order='lex', polys=False)) + + if inexact: + poly_eqs = [nfloat(p) for p in poly_eqs] + + return poly_sol, poly_eqs + + +def nonlinsolve(system, *symbols): + r""" + Solve system of $N$ nonlinear equations with $M$ variables, which means both + under and overdetermined systems are supported. Positive dimensional + system is also supported (A system with infinitely many solutions is said + to be positive-dimensional). In a positive dimensional system the solution will + be dependent on at least one symbol. Returns both real solution + and complex solution (if they exist). + + Parameters + ========== + + system : list of equations + The target system of equations + symbols : list of Symbols + symbols should be given as a sequence eg. list + + Returns + ======= + + A :class:`~.FiniteSet` of ordered tuple of values of `symbols` for which the `system` + has solution. Order of values in the tuple is same as symbols present in + the parameter `symbols`. + + Please note that general :class:`~.FiniteSet` is unordered, the solution + returned here is not simply a :class:`~.FiniteSet` of solutions, rather it + is a :class:`~.FiniteSet` of ordered tuple, i.e. the first and only + argument to :class:`~.FiniteSet` is a tuple of solutions, which is + ordered, and, hence ,the returned solution is ordered. + + Also note that solution could also have been returned as an ordered tuple, + FiniteSet is just a wrapper ``{}`` around the tuple. It has no other + significance except for the fact it is just used to maintain a consistent + output format throughout the solveset. + + For the given set of equations, the respective input types + are given below: + + .. math:: xy - 1 = 0 + .. math:: 4x^2 + y^2 - 5 = 0 + + :: + + system = [x*y - 1, 4*x**2 + y**2 - 5] + symbols = [x, y] + + Raises + ====== + + ValueError + The input is not valid. + The symbols are not given. + AttributeError + The input symbols are not `Symbol` type. + + Examples + ======== + + >>> from sympy import symbols, nonlinsolve + >>> x, y, z = symbols('x, y, z', real=True) + >>> nonlinsolve([x*y - 1, 4*x**2 + y**2 - 5], [x, y]) + {(-1, -1), (-1/2, -2), (1/2, 2), (1, 1)} + + 1. Positive dimensional system and complements: + + >>> from sympy import pprint + >>> from sympy.polys.polytools import is_zero_dimensional + >>> a, b, c, d = symbols('a, b, c, d', extended_real=True) + >>> eq1 = a + b + c + d + >>> eq2 = a*b + b*c + c*d + d*a + >>> eq3 = a*b*c + b*c*d + c*d*a + d*a*b + >>> eq4 = a*b*c*d - 1 + >>> system = [eq1, eq2, eq3, eq4] + >>> is_zero_dimensional(system) + False + >>> pprint(nonlinsolve(system, [a, b, c, d]), use_unicode=False) + -1 1 1 -1 + {(---, -d, -, {d} \ {0}), (-, -d, ---, {d} \ {0})} + d d d d + >>> nonlinsolve([(x+y)**2 - 4, x + y - 2], [x, y]) + {(2 - y, y)} + + 2. If some of the equations are non-polynomial then `nonlinsolve` + will call the ``substitution`` function and return real and complex solutions, + if present. + + >>> from sympy import exp, sin + >>> nonlinsolve([exp(x) - sin(y), y**2 - 4], [x, y]) + {(ImageSet(Lambda(_n, I*(2*_n*pi + pi) + log(sin(2))), Integers), -2), + (ImageSet(Lambda(_n, 2*_n*I*pi + log(sin(2))), Integers), 2)} + + 3. If system is non-linear polynomial and zero-dimensional then it + returns both solution (real and complex solutions, if present) using + :func:`~.solve_poly_system`: + + >>> from sympy import sqrt + >>> nonlinsolve([x**2 - 2*y**2 -2, x*y - 2], [x, y]) + {(-2, -1), (2, 1), (-sqrt(2)*I, sqrt(2)*I), (sqrt(2)*I, -sqrt(2)*I)} + + 4. ``nonlinsolve`` can solve some linear (zero or positive dimensional) + system (because it uses the :func:`sympy.polys.polytools.groebner` function to get the + groebner basis and then uses the ``substitution`` function basis as the + new `system`). But it is not recommended to solve linear system using + ``nonlinsolve``, because :func:`~.linsolve` is better for general linear systems. + + >>> nonlinsolve([x + 2*y -z - 3, x - y - 4*z + 9, y + z - 4], [x, y, z]) + {(3*z - 5, 4 - z, z)} + + 5. System having polynomial equations and only real solution is + solved using :func:`~.solve_poly_system`: + + >>> e1 = sqrt(x**2 + y**2) - 10 + >>> e2 = sqrt(y**2 + (-x + 10)**2) - 3 + >>> nonlinsolve((e1, e2), (x, y)) + {(191/20, -3*sqrt(391)/20), (191/20, 3*sqrt(391)/20)} + >>> nonlinsolve([x**2 + 2/y - 2, x + y - 3], [x, y]) + {(1, 2), (1 - sqrt(5), 2 + sqrt(5)), (1 + sqrt(5), 2 - sqrt(5))} + >>> nonlinsolve([x**2 + 2/y - 2, x + y - 3], [y, x]) + {(2, 1), (2 - sqrt(5), 1 + sqrt(5)), (2 + sqrt(5), 1 - sqrt(5))} + + 6. It is better to use symbols instead of trigonometric functions or + :class:`~.Function`. For example, replace $\sin(x)$ with a symbol, replace + $f(x)$ with a symbol and so on. Get a solution from ``nonlinsolve`` and then + use :func:`~.solveset` to get the value of $x$. + + How nonlinsolve is better than old solver ``_solve_system`` : + ============================================================= + + 1. A positive dimensional system solver: nonlinsolve can return + solution for positive dimensional system. It finds the + Groebner Basis of the positive dimensional system(calling it as + basis) then we can start solving equation(having least number of + variable first in the basis) using solveset and substituting that + solved solutions into other equation(of basis) to get solution in + terms of minimum variables. Here the important thing is how we + are substituting the known values and in which equations. + + 2. Real and complex solutions: nonlinsolve returns both real + and complex solution. If all the equations in the system are polynomial + then using :func:`~.solve_poly_system` both real and complex solution is returned. + If all the equations in the system are not polynomial equation then goes to + ``substitution`` method with this polynomial and non polynomial equation(s), + to solve for unsolved variables. Here to solve for particular variable + solveset_real and solveset_complex is used. For both real and complex + solution ``_solve_using_known_values`` is used inside ``substitution`` + (``substitution`` will be called when any non-polynomial equation is present). + If a solution is valid its general solution is added to the final result. + + 3. :class:`~.Complement` and :class:`~.Intersection` will be added: + nonlinsolve maintains dict for complements and intersections. If solveset + find complements or/and intersections with any interval or set during the + execution of ``substitution`` function, then complement or/and + intersection for that variable is added before returning final solution. + + """ + if not system: + return S.EmptySet + + if not symbols: + msg = ('Symbols must be given, for which solution of the ' + 'system is to be found.') + raise ValueError(filldedent(msg)) + + if hasattr(symbols[0], '__iter__'): + symbols = symbols[0] + + if not is_sequence(symbols) or not symbols: + msg = ('Symbols must be given, for which solution of the ' + 'system is to be found.') + raise IndexError(filldedent(msg)) + + symbols = list(map(_sympify, symbols)) + system, symbols, swap = recast_to_symbols(system, symbols) + if swap: + soln = nonlinsolve(system, symbols) + return FiniteSet(*[tuple(i.xreplace(swap) for i in s) for s in soln]) + + if len(system) == 1 and len(symbols) == 1: + return _solveset_work(system, symbols) + + # main code of def nonlinsolve() starts from here + + polys, polys_expr, nonpolys, denominators, unrad_changed = \ + _separate_poly_nonpoly(system, symbols) + + poly_eqs = [] + poly_sol = [{}] + + if polys: + poly_sol, poly_eqs = _handle_poly(polys, symbols) + if poly_sol and poly_sol[0]: + poly_syms = set().union(*(eq.free_symbols for eq in polys)) + unrad_syms = set().union(*(eq.free_symbols for eq in unrad_changed)) + if unrad_syms == poly_syms and unrad_changed: + # if all the symbols have been solved by _handle_poly + # and unrad has been used then check solutions + poly_sol = [sol for sol in poly_sol if checksol(unrad_changed, sol)] + + # Collect together the unsolved polynomials with the non-polynomial + # equations. + remaining = poly_eqs + nonpolys + + # to_tuple converts a solution dictionary to a tuple containing the + # value for each symbol + to_tuple = lambda sol: tuple(sol[s] for s in symbols) + + if not remaining: + # If there is nothing left to solve then return the solution from + # solve_poly_system directly. + return FiniteSet(*map(to_tuple, poly_sol)) + else: + # Here we handle: + # + # 1. The Groebner basis if solve_poly_system failed. + # 2. The Groebner basis in the positive-dimensional case. + # 3. Any non-polynomial equations + # + # If solve_poly_system did succeed then we pass those solutions in as + # preliminary results. + subs_res = substitution(remaining, symbols, result=poly_sol, exclude=denominators) + + if not isinstance(subs_res, FiniteSet): + return subs_res + + # check solutions produced by substitution. Currently, checking is done for + # only those solutions which have non-Set variable values. + if unrad_changed: + result = [dict(zip(symbols, sol)) for sol in subs_res.args] + correct_sols = [sol for sol in result if any(isinstance(v, Set) for v in sol) + or checksol(unrad_changed, sol) != False] + return FiniteSet(*map(to_tuple, correct_sols)) + else: + return subs_res diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..adb79261954924305c1837555d7d47cd53b8430b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__init__.py @@ -0,0 +1,202 @@ +""" +SymPy statistics module + +Introduces a random variable type into the SymPy language. + +Random variables may be declared using prebuilt functions such as +Normal, Exponential, Coin, Die, etc... or built with functions like FiniteRV. + +Queries on random expressions can be made using the functions + +========================= ============================= + Expression Meaning +------------------------- ----------------------------- + ``P(condition)`` Probability + ``E(expression)`` Expected value + ``H(expression)`` Entropy + ``variance(expression)`` Variance + ``density(expression)`` Probability Density Function + ``sample(expression)`` Produce a realization + ``where(condition)`` Where the condition is true +========================= ============================= + +Examples +======== + +>>> from sympy.stats import P, E, variance, Die, Normal +>>> from sympy import simplify +>>> X, Y = Die('X', 6), Die('Y', 6) # Define two six sided dice +>>> Z = Normal('Z', 0, 1) # Declare a Normal random variable with mean 0, std 1 +>>> P(X>3) # Probability X is greater than 3 +1/2 +>>> E(X+Y) # Expectation of the sum of two dice +7 +>>> variance(X+Y) # Variance of the sum of two dice +35/6 +>>> simplify(P(Z>1)) # Probability of Z being greater than 1 +1/2 - erf(sqrt(2)/2)/2 + + +One could also create custom distribution and define custom random variables +as follows: + +1. If you want to create a Continuous Random Variable: + +>>> from sympy.stats import ContinuousRV, P, E +>>> from sympy import exp, Symbol, Interval, oo +>>> x = Symbol('x') +>>> pdf = exp(-x) # pdf of the Continuous Distribution +>>> Z = ContinuousRV(x, pdf, set=Interval(0, oo)) +>>> E(Z) +1 +>>> P(Z > 5) +exp(-5) + +1.1 To create an instance of Continuous Distribution: + +>>> from sympy.stats import ContinuousDistributionHandmade +>>> from sympy import Lambda +>>> dist = ContinuousDistributionHandmade(Lambda(x, pdf), set=Interval(0, oo)) +>>> dist.pdf(x) +exp(-x) + +2. If you want to create a Discrete Random Variable: + +>>> from sympy.stats import DiscreteRV, P, E +>>> from sympy import Symbol, S +>>> p = S(1)/2 +>>> x = Symbol('x', integer=True, positive=True) +>>> pdf = p*(1 - p)**(x - 1) +>>> D = DiscreteRV(x, pdf, set=S.Naturals) +>>> E(D) +2 +>>> P(D > 3) +1/8 + +2.1 To create an instance of Discrete Distribution: + +>>> from sympy.stats import DiscreteDistributionHandmade +>>> from sympy import Lambda +>>> dist = DiscreteDistributionHandmade(Lambda(x, pdf), set=S.Naturals) +>>> dist.pdf(x) +2**(1 - x)/2 + +3. If you want to create a Finite Random Variable: + +>>> from sympy.stats import FiniteRV, P, E +>>> from sympy import Rational, Eq +>>> pmf = {1: Rational(1, 3), 2: Rational(1, 6), 3: Rational(1, 4), 4: Rational(1, 4)} +>>> X = FiniteRV('X', pmf) +>>> E(X) +29/12 +>>> P(X > 3) +1/4 + +3.1 To create an instance of Finite Distribution: + +>>> from sympy.stats import FiniteDistributionHandmade +>>> dist = FiniteDistributionHandmade(pmf) +>>> dist.pmf(x) +Lambda(x, Piecewise((1/3, Eq(x, 1)), (1/6, Eq(x, 2)), (1/4, Eq(x, 3) | Eq(x, 4)), (0, True))) +""" + +__all__ = [ + 'P', 'E', 'H', 'density', 'where', 'given', 'sample', 'cdf','median', + 'characteristic_function', 'pspace', 'sample_iter', 'variance', 'std', + 'skewness', 'kurtosis', 'covariance', 'dependent', 'entropy', 'independent', + 'random_symbols', 'correlation', 'factorial_moment', 'moment', 'cmoment', + 'sampling_density', 'moment_generating_function', 'smoment', 'quantile', + 'coskewness', 'sample_stochastic_process', + + 'FiniteRV', 'DiscreteUniform', 'Die', 'Bernoulli', 'Coin', 'Binomial', + 'BetaBinomial', 'Hypergeometric', 'Rademacher', 'IdealSoliton', 'RobustSoliton', + 'FiniteDistributionHandmade', + + 'ContinuousRV', 'Arcsin', 'Benini', 'Beta', 'BetaNoncentral', 'BetaPrime', + 'BoundedPareto', 'Cauchy', 'Chi', 'ChiNoncentral', 'ChiSquared', 'Dagum', 'Davis', 'Erlang', + 'ExGaussian', 'Exponential', 'ExponentialPower', 'FDistribution', + 'FisherZ', 'Frechet', 'Gamma', 'GammaInverse', 'Gompertz', 'Gumbel', + 'Kumaraswamy', 'Laplace', 'Levy', 'Logistic','LogCauchy', 'LogLogistic', 'LogitNormal', 'LogNormal', 'Lomax', + 'Moyal', 'Maxwell', 'Nakagami', 'Normal', 'GaussianInverse', 'Pareto', 'PowerFunction', + 'QuadraticU', 'RaisedCosine', 'Rayleigh','Reciprocal', 'StudentT', 'ShiftedGompertz', + 'Trapezoidal', 'Triangular', 'Uniform', 'UniformSum', 'VonMises', 'Wald', + 'Weibull', 'WignerSemicircle', 'ContinuousDistributionHandmade', + + 'FlorySchulz', 'Geometric','Hermite', 'Logarithmic', 'NegativeBinomial', 'Poisson', 'Skellam', + 'YuleSimon', 'Zeta', 'DiscreteRV', 'DiscreteDistributionHandmade', + + 'JointRV', 'Dirichlet', 'GeneralizedMultivariateLogGamma', + 'GeneralizedMultivariateLogGammaOmega', 'Multinomial', 'MultivariateBeta', + 'MultivariateEwens', 'MultivariateT', 'NegativeMultinomial', + 'NormalGamma', 'MultivariateNormal', 'MultivariateLaplace', 'marginal_distribution', + + 'StochasticProcess', 'DiscreteTimeStochasticProcess', + 'DiscreteMarkovChain', 'TransitionMatrixOf', 'StochasticStateSpaceOf', + 'GeneratorMatrixOf', 'ContinuousMarkovChain', 'BernoulliProcess', + 'PoissonProcess', 'WienerProcess', 'GammaProcess', + + 'CircularEnsemble', 'CircularUnitaryEnsemble', + 'CircularOrthogonalEnsemble', 'CircularSymplecticEnsemble', + 'GaussianEnsemble', 'GaussianUnitaryEnsemble', + 'GaussianOrthogonalEnsemble', 'GaussianSymplecticEnsemble', + 'joint_eigen_distribution', 'JointEigenDistribution', + 'level_spacing_distribution', + + 'MatrixGamma', 'Wishart', 'MatrixNormal', 'MatrixStudentT', + + 'Probability', 'Expectation', 'Variance', 'Covariance', 'Moment', + 'CentralMoment', + + 'ExpectationMatrix', 'VarianceMatrix', 'CrossCovarianceMatrix' + +] +from .rv_interface import (P, E, H, density, where, given, sample, cdf, median, + characteristic_function, pspace, sample_iter, variance, std, skewness, + kurtosis, covariance, dependent, entropy, independent, random_symbols, + correlation, factorial_moment, moment, cmoment, sampling_density, + moment_generating_function, smoment, quantile, coskewness, + sample_stochastic_process) + +from .frv_types import (FiniteRV, DiscreteUniform, Die, Bernoulli, Coin, + Binomial, BetaBinomial, Hypergeometric, Rademacher, + FiniteDistributionHandmade, IdealSoliton, RobustSoliton) + +from .crv_types import (ContinuousRV, Arcsin, Benini, Beta, BetaNoncentral, + BetaPrime, BoundedPareto, Cauchy, Chi, ChiNoncentral, ChiSquared, + Dagum, Davis, Erlang, ExGaussian, Exponential, ExponentialPower, + FDistribution, FisherZ, Frechet, Gamma, GammaInverse, GaussianInverse, + Gompertz, Gumbel, Kumaraswamy, Laplace, Levy, Logistic, LogCauchy, + LogLogistic, LogitNormal, LogNormal, Lomax, Maxwell, Moyal, Nakagami, + Normal, Pareto, QuadraticU, RaisedCosine, Rayleigh, Reciprocal, + StudentT, PowerFunction, ShiftedGompertz, Trapezoidal, Triangular, + Uniform, UniformSum, VonMises, Wald, Weibull, WignerSemicircle, + ContinuousDistributionHandmade) + +from .drv_types import (FlorySchulz, Geometric, Hermite, Logarithmic, NegativeBinomial, Poisson, + Skellam, YuleSimon, Zeta, DiscreteRV, DiscreteDistributionHandmade) + +from .joint_rv_types import (JointRV, Dirichlet, + GeneralizedMultivariateLogGamma, GeneralizedMultivariateLogGammaOmega, + Multinomial, MultivariateBeta, MultivariateEwens, MultivariateT, + NegativeMultinomial, NormalGamma, MultivariateNormal, MultivariateLaplace, + marginal_distribution) + +from .stochastic_process_types import (StochasticProcess, + DiscreteTimeStochasticProcess, DiscreteMarkovChain, + TransitionMatrixOf, StochasticStateSpaceOf, GeneratorMatrixOf, + ContinuousMarkovChain, BernoulliProcess, PoissonProcess, WienerProcess, + GammaProcess) + +from .random_matrix_models import (CircularEnsemble, CircularUnitaryEnsemble, + CircularOrthogonalEnsemble, CircularSymplecticEnsemble, + GaussianEnsemble, GaussianUnitaryEnsemble, GaussianOrthogonalEnsemble, + GaussianSymplecticEnsemble, joint_eigen_distribution, + JointEigenDistribution, level_spacing_distribution) + +from .matrix_distributions import MatrixGamma, Wishart, MatrixNormal, MatrixStudentT + +from .symbolic_probability import (Probability, Expectation, Variance, + Covariance, Moment, CentralMoment) + +from .symbolic_multivariate_probability import (ExpectationMatrix, VarianceMatrix, + CrossCovarianceMatrix) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/compound_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/compound_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..27555f4233fe691bac303800a87736205acbdee6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/compound_rv.py @@ -0,0 +1,223 @@ +from sympy.concrete.summations import Sum +from sympy.core.basic import Basic +from sympy.core.function import Lambda +from sympy.core.symbol import Dummy +from sympy.integrals.integrals import Integral +from sympy.stats.rv import (NamedArgsMixin, random_symbols, _symbol_converter, + PSpace, RandomSymbol, is_random, Distribution) +from sympy.stats.crv import ContinuousDistribution, SingleContinuousPSpace +from sympy.stats.drv import DiscreteDistribution, SingleDiscretePSpace +from sympy.stats.frv import SingleFiniteDistribution, SingleFinitePSpace +from sympy.stats.crv_types import ContinuousDistributionHandmade +from sympy.stats.drv_types import DiscreteDistributionHandmade +from sympy.stats.frv_types import FiniteDistributionHandmade + + +class CompoundPSpace(PSpace): + """ + A temporary Probability Space for the Compound Distribution. After + Marginalization, this returns the corresponding Probability Space of the + parent distribution. + """ + + def __new__(cls, s, distribution): + s = _symbol_converter(s) + if isinstance(distribution, ContinuousDistribution): + return SingleContinuousPSpace(s, distribution) + if isinstance(distribution, DiscreteDistribution): + return SingleDiscretePSpace(s, distribution) + if isinstance(distribution, SingleFiniteDistribution): + return SingleFinitePSpace(s, distribution) + if not isinstance(distribution, CompoundDistribution): + raise ValueError("%s should be an isinstance of " + "CompoundDistribution"%(distribution)) + return Basic.__new__(cls, s, distribution) + + @property + def value(self): + return RandomSymbol(self.symbol, self) + + @property + def symbol(self): + return self.args[0] + + @property + def is_Continuous(self): + return self.distribution.is_Continuous + + @property + def is_Finite(self): + return self.distribution.is_Finite + + @property + def is_Discrete(self): + return self.distribution.is_Discrete + + @property + def distribution(self): + return self.args[1] + + @property + def pdf(self): + return self.distribution.pdf(self.symbol) + + @property + def set(self): + return self.distribution.set + + @property + def domain(self): + return self._get_newpspace().domain + + def _get_newpspace(self, evaluate=False): + x = Dummy('x') + parent_dist = self.distribution.args[0] + func = Lambda(x, self.distribution.pdf(x, evaluate)) + new_pspace = self._transform_pspace(self.symbol, parent_dist, func) + if new_pspace is not None: + return new_pspace + message = ("Compound Distribution for %s is not implemented yet" % str(parent_dist)) + raise NotImplementedError(message) + + def _transform_pspace(self, sym, dist, pdf): + """ + This function returns the new pspace of the distribution using handmade + Distributions and their corresponding pspace. + """ + pdf = Lambda(sym, pdf(sym)) + _set = dist.set + if isinstance(dist, ContinuousDistribution): + return SingleContinuousPSpace(sym, ContinuousDistributionHandmade(pdf, _set)) + elif isinstance(dist, DiscreteDistribution): + return SingleDiscretePSpace(sym, DiscreteDistributionHandmade(pdf, _set)) + elif isinstance(dist, SingleFiniteDistribution): + dens = {k: pdf(k) for k in _set} + return SingleFinitePSpace(sym, FiniteDistributionHandmade(dens)) + + def compute_density(self, expr, *, compound_evaluate=True, **kwargs): + new_pspace = self._get_newpspace(compound_evaluate) + expr = expr.subs({self.value: new_pspace.value}) + return new_pspace.compute_density(expr, **kwargs) + + def compute_cdf(self, expr, *, compound_evaluate=True, **kwargs): + new_pspace = self._get_newpspace(compound_evaluate) + expr = expr.subs({self.value: new_pspace.value}) + return new_pspace.compute_cdf(expr, **kwargs) + + def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): + new_pspace = self._get_newpspace(evaluate) + expr = expr.subs({self.value: new_pspace.value}) + if rvs: + rvs = rvs.subs({self.value: new_pspace.value}) + if isinstance(new_pspace, SingleFinitePSpace): + return new_pspace.compute_expectation(expr, rvs, **kwargs) + return new_pspace.compute_expectation(expr, rvs, evaluate, **kwargs) + + def probability(self, condition, *, compound_evaluate=True, **kwargs): + new_pspace = self._get_newpspace(compound_evaluate) + condition = condition.subs({self.value: new_pspace.value}) + return new_pspace.probability(condition) + + def conditional_space(self, condition, *, compound_evaluate=True, **kwargs): + new_pspace = self._get_newpspace(compound_evaluate) + condition = condition.subs({self.value: new_pspace.value}) + return new_pspace.conditional_space(condition) + + +class CompoundDistribution(Distribution, NamedArgsMixin): + """ + Class for Compound Distributions. + + Parameters + ========== + + dist : Distribution + Distribution must contain a random parameter + + Examples + ======== + + >>> from sympy.stats.compound_rv import CompoundDistribution + >>> from sympy.stats.crv_types import NormalDistribution + >>> from sympy.stats import Normal + >>> from sympy.abc import x + >>> X = Normal('X', 2, 4) + >>> N = NormalDistribution(X, 4) + >>> C = CompoundDistribution(N) + >>> C.set + Interval(-oo, oo) + >>> C.pdf(x, evaluate=True).simplify() + exp(-x**2/64 + x/16 - 1/16)/(8*sqrt(pi)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Compound_probability_distribution + + """ + + def __new__(cls, dist): + if not isinstance(dist, (ContinuousDistribution, + SingleFiniteDistribution, DiscreteDistribution)): + message = "Compound Distribution for %s is not implemented yet" % str(dist) + raise NotImplementedError(message) + if not cls._compound_check(dist): + return dist + return Basic.__new__(cls, dist) + + @property + def set(self): + return self.args[0].set + + @property + def is_Continuous(self): + return isinstance(self.args[0], ContinuousDistribution) + + @property + def is_Finite(self): + return isinstance(self.args[0], SingleFiniteDistribution) + + @property + def is_Discrete(self): + return isinstance(self.args[0], DiscreteDistribution) + + def pdf(self, x, evaluate=False): + dist = self.args[0] + randoms = [rv for rv in dist.args if is_random(rv)] + if isinstance(dist, SingleFiniteDistribution): + y = Dummy('y', integer=True, negative=False) + expr = dist.pmf(y) + else: + y = Dummy('y') + expr = dist.pdf(y) + for rv in randoms: + expr = self._marginalise(expr, rv, evaluate) + return Lambda(y, expr)(x) + + def _marginalise(self, expr, rv, evaluate): + if isinstance(rv.pspace.distribution, SingleFiniteDistribution): + rv_dens = rv.pspace.distribution.pmf(rv) + else: + rv_dens = rv.pspace.distribution.pdf(rv) + rv_dom = rv.pspace.domain.set + if rv.pspace.is_Discrete or rv.pspace.is_Finite: + expr = Sum(expr*rv_dens, (rv, rv_dom._inf, + rv_dom._sup)) + else: + expr = Integral(expr*rv_dens, (rv, rv_dom._inf, + rv_dom._sup)) + if evaluate: + return expr.doit() + return expr + + @classmethod + def _compound_check(self, dist): + """ + Checks if the given distribution contains random parameters. + """ + randoms = [] + for arg in dist.args: + randoms.extend(random_symbols(arg)) + if len(randoms) == 0: + return False + return True diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/crv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/crv.py new file mode 100644 index 0000000000000000000000000000000000000000..0a5184029679f663c83d81aa6c1b6ca4d948c70f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/crv.py @@ -0,0 +1,570 @@ +""" +Continuous Random Variables Module + +See Also +======== +sympy.stats.crv_types +sympy.stats.rv +sympy.stats.frv +""" + + +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core.function import Lambda, PoleError +from sympy.core.numbers import (I, nan, oo) +from sympy.core.relational import (Eq, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, symbols) +from sympy.core.sympify import _sympify, sympify +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.delta_functions import DiracDelta +from sympy.integrals.integrals import (Integral, integrate) +from sympy.logic.boolalg import (And, Or) +from sympy.polys.polyerrors import PolynomialError +from sympy.polys.polytools import poly +from sympy.series.series import series +from sympy.sets.sets import (FiniteSet, Intersection, Interval, Union) +from sympy.solvers.solveset import solveset +from sympy.solvers.inequalities import reduce_rational_inequalities +from sympy.stats.rv import (RandomDomain, SingleDomain, ConditionalDomain, is_random, + ProductDomain, PSpace, SinglePSpace, random_symbols, NamedArgsMixin, Distribution) + + +class ContinuousDomain(RandomDomain): + """ + A domain with continuous support + + Represented using symbols and Intervals. + """ + is_Continuous = True + + def as_boolean(self): + raise NotImplementedError("Not Implemented for generic Domains") + + +class SingleContinuousDomain(ContinuousDomain, SingleDomain): + """ + A univariate domain with continuous support + + Represented using a single symbol and interval. + """ + def compute_expectation(self, expr, variables=None, **kwargs): + if variables is None: + variables = self.symbols + if not variables: + return expr + if frozenset(variables) != frozenset(self.symbols): + raise ValueError("Values should be equal") + # assumes only intervals + return Integral(expr, (self.symbol, self.set), **kwargs) + + def as_boolean(self): + return self.set.as_relational(self.symbol) + + +class ProductContinuousDomain(ProductDomain, ContinuousDomain): + """ + A collection of independent domains with continuous support + """ + + def compute_expectation(self, expr, variables=None, **kwargs): + if variables is None: + variables = self.symbols + for domain in self.domains: + domain_vars = frozenset(variables) & frozenset(domain.symbols) + if domain_vars: + expr = domain.compute_expectation(expr, domain_vars, **kwargs) + return expr + + def as_boolean(self): + return And(*[domain.as_boolean() for domain in self.domains]) + + +class ConditionalContinuousDomain(ContinuousDomain, ConditionalDomain): + """ + A domain with continuous support that has been further restricted by a + condition such as $x > 3$. + """ + + def compute_expectation(self, expr, variables=None, **kwargs): + if variables is None: + variables = self.symbols + if not variables: + return expr + # Extract the full integral + fullintgrl = self.fulldomain.compute_expectation(expr, variables) + # separate into integrand and limits + integrand, limits = fullintgrl.function, list(fullintgrl.limits) + + conditions = [self.condition] + while conditions: + cond = conditions.pop() + if cond.is_Boolean: + if isinstance(cond, And): + conditions.extend(cond.args) + elif isinstance(cond, Or): + raise NotImplementedError("Or not implemented here") + elif cond.is_Relational: + if cond.is_Equality: + # Add the appropriate Delta to the integrand + integrand *= DiracDelta(cond.lhs - cond.rhs) + else: + symbols = cond.free_symbols & set(self.symbols) + if len(symbols) != 1: # Can't handle x > y + raise NotImplementedError( + "Multivariate Inequalities not yet implemented") + # Can handle x > 0 + symbol = symbols.pop() + # Find the limit with x, such as (x, -oo, oo) + for i, limit in enumerate(limits): + if limit[0] == symbol: + # Make condition into an Interval like [0, oo] + cintvl = reduce_rational_inequalities_wrap( + cond, symbol) + # Make limit into an Interval like [-oo, oo] + lintvl = Interval(limit[1], limit[2]) + # Intersect them to get [0, oo] + intvl = cintvl.intersect(lintvl) + # Put back into limits list + limits[i] = (symbol, intvl.left, intvl.right) + else: + raise TypeError( + "Condition %s is not a relational or Boolean" % cond) + + return Integral(integrand, *limits, **kwargs) + + def as_boolean(self): + return And(self.fulldomain.as_boolean(), self.condition) + + @property + def set(self): + if len(self.symbols) == 1: + return (self.fulldomain.set & reduce_rational_inequalities_wrap( + self.condition, tuple(self.symbols)[0])) + else: + raise NotImplementedError( + "Set of Conditional Domain not Implemented") + + +class ContinuousDistribution(Distribution): + def __call__(self, *args): + return self.pdf(*args) + + +class SingleContinuousDistribution(ContinuousDistribution, NamedArgsMixin): + """ Continuous distribution of a single variable. + + Explanation + =========== + + Serves as superclass for Normal/Exponential/UniformDistribution etc.... + + Represented by parameters for each of the specific classes. E.g + NormalDistribution is represented by a mean and standard deviation. + + Provides methods for pdf, cdf, and sampling. + + See Also + ======== + + sympy.stats.crv_types.* + """ + + set = Interval(-oo, oo) + + def __new__(cls, *args): + args = list(map(sympify, args)) + return Basic.__new__(cls, *args) + + @staticmethod + def check(*args): + pass + + @cacheit + def compute_cdf(self, **kwargs): + """ Compute the CDF from the PDF. + + Returns a Lambda. + """ + x, z = symbols('x, z', real=True, cls=Dummy) + left_bound = self.set.start + + # CDF is integral of PDF from left bound to z + pdf = self.pdf(x) + cdf = integrate(pdf.doit(), (x, left_bound, z), **kwargs) + # CDF Ensure that CDF left of left_bound is zero + cdf = Piecewise((cdf, z >= left_bound), (0, True)) + return Lambda(z, cdf) + + def _cdf(self, x): + return None + + def cdf(self, x, **kwargs): + """ Cumulative density function """ + if len(kwargs) == 0: + cdf = self._cdf(x) + if cdf is not None: + return cdf + return self.compute_cdf(**kwargs)(x) + + @cacheit + def compute_characteristic_function(self, **kwargs): + """ Compute the characteristic function from the PDF. + + Returns a Lambda. + """ + x, t = symbols('x, t', real=True, cls=Dummy) + pdf = self.pdf(x) + cf = integrate(exp(I*t*x)*pdf, (x, self.set)) + return Lambda(t, cf) + + def _characteristic_function(self, t): + return None + + def characteristic_function(self, t, **kwargs): + """ Characteristic function """ + if len(kwargs) == 0: + cf = self._characteristic_function(t) + if cf is not None: + return cf + return self.compute_characteristic_function(**kwargs)(t) + + @cacheit + def compute_moment_generating_function(self, **kwargs): + """ Compute the moment generating function from the PDF. + + Returns a Lambda. + """ + x, t = symbols('x, t', real=True, cls=Dummy) + pdf = self.pdf(x) + mgf = integrate(exp(t * x) * pdf, (x, self.set)) + return Lambda(t, mgf) + + def _moment_generating_function(self, t): + return None + + def moment_generating_function(self, t, **kwargs): + """ Moment generating function """ + if not kwargs: + mgf = self._moment_generating_function(t) + if mgf is not None: + return mgf + return self.compute_moment_generating_function(**kwargs)(t) + + def expectation(self, expr, var, evaluate=True, **kwargs): + """ Expectation of expression over distribution """ + if evaluate: + try: + p = poly(expr, var) + if p.is_zero: + return S.Zero + t = Dummy('t', real=True) + mgf = self._moment_generating_function(t) + if mgf is None: + return integrate(expr * self.pdf(var), (var, self.set), **kwargs) + deg = p.degree() + taylor = poly(series(mgf, t, 0, deg + 1).removeO(), t) + result = 0 + for k in range(deg+1): + result += p.coeff_monomial(var ** k) * taylor.coeff_monomial(t ** k) * factorial(k) + return result + except PolynomialError: + return integrate(expr * self.pdf(var), (var, self.set), **kwargs) + else: + return Integral(expr * self.pdf(var), (var, self.set), **kwargs) + + @cacheit + def compute_quantile(self, **kwargs): + """ Compute the Quantile from the PDF. + + Returns a Lambda. + """ + x, p = symbols('x, p', real=True, cls=Dummy) + left_bound = self.set.start + + pdf = self.pdf(x) + cdf = integrate(pdf, (x, left_bound, x), **kwargs) + quantile = solveset(cdf - p, x, self.set) + return Lambda(p, Piecewise((quantile, (p >= 0) & (p <= 1) ), (nan, True))) + + def _quantile(self, x): + return None + + def quantile(self, x, **kwargs): + """ Cumulative density function """ + if len(kwargs) == 0: + quantile = self._quantile(x) + if quantile is not None: + return quantile + return self.compute_quantile(**kwargs)(x) + + +class ContinuousPSpace(PSpace): + """ Continuous Probability Space + + Represents the likelihood of an event space defined over a continuum. + + Represented with a ContinuousDomain and a PDF (Lambda-Like) + """ + + is_Continuous = True + is_real = True + + @property + def pdf(self): + return self.density(*self.domain.symbols) + + def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): + if rvs is None: + rvs = self.values + else: + rvs = frozenset(rvs) + + expr = expr.xreplace({rv: rv.symbol for rv in rvs}) + + domain_symbols = frozenset(rv.symbol for rv in rvs) + + return self.domain.compute_expectation(self.pdf * expr, + domain_symbols, **kwargs) + + def compute_density(self, expr, **kwargs): + # Common case Density(X) where X in self.values + if expr in self.values: + # Marginalize all other random symbols out of the density + randomsymbols = tuple(set(self.values) - frozenset([expr])) + symbols = tuple(rs.symbol for rs in randomsymbols) + pdf = self.domain.compute_expectation(self.pdf, symbols, **kwargs) + return Lambda(expr.symbol, pdf) + + z = Dummy('z', real=True) + return Lambda(z, self.compute_expectation(DiracDelta(expr - z), **kwargs)) + + @cacheit + def compute_cdf(self, expr, **kwargs): + if not self.domain.set.is_Interval: + raise ValueError( + "CDF not well defined on multivariate expressions") + + d = self.compute_density(expr, **kwargs) + x, z = symbols('x, z', real=True, cls=Dummy) + left_bound = self.domain.set.start + + # CDF is integral of PDF from left bound to z + cdf = integrate(d(x), (x, left_bound, z), **kwargs) + # CDF Ensure that CDF left of left_bound is zero + cdf = Piecewise((cdf, z >= left_bound), (0, True)) + return Lambda(z, cdf) + + @cacheit + def compute_characteristic_function(self, expr, **kwargs): + if not self.domain.set.is_Interval: + raise NotImplementedError("Characteristic function of multivariate expressions not implemented") + + d = self.compute_density(expr, **kwargs) + x, t = symbols('x, t', real=True, cls=Dummy) + cf = integrate(exp(I*t*x)*d(x), (x, -oo, oo), **kwargs) + return Lambda(t, cf) + + @cacheit + def compute_moment_generating_function(self, expr, **kwargs): + if not self.domain.set.is_Interval: + raise NotImplementedError("Moment generating function of multivariate expressions not implemented") + + d = self.compute_density(expr, **kwargs) + x, t = symbols('x, t', real=True, cls=Dummy) + mgf = integrate(exp(t * x) * d(x), (x, -oo, oo), **kwargs) + return Lambda(t, mgf) + + @cacheit + def compute_quantile(self, expr, **kwargs): + if not self.domain.set.is_Interval: + raise ValueError( + "Quantile not well defined on multivariate expressions") + + d = self.compute_cdf(expr, **kwargs) + x = Dummy('x', real=True) + p = Dummy('p', positive=True) + + quantile = solveset(d(x) - p, x, self.set) + + return Lambda(p, quantile) + + def probability(self, condition, **kwargs): + z = Dummy('z', real=True) + cond_inv = False + if isinstance(condition, Ne): + condition = Eq(condition.args[0], condition.args[1]) + cond_inv = True + # Univariate case can be handled by where + try: + domain = self.where(condition) + rv = [rv for rv in self.values if rv.symbol == domain.symbol][0] + # Integrate out all other random variables + pdf = self.compute_density(rv, **kwargs) + # return S.Zero if `domain` is empty set + if domain.set is S.EmptySet or isinstance(domain.set, FiniteSet): + return S.Zero if not cond_inv else S.One + if isinstance(domain.set, Union): + return sum( + Integral(pdf(z), (z, subset), **kwargs) for subset in + domain.set.args if isinstance(subset, Interval)) + # Integrate out the last variable over the special domain + return Integral(pdf(z), (z, domain.set), **kwargs) + + # Other cases can be turned into univariate case + # by computing a density handled by density computation + except NotImplementedError: + from sympy.stats.rv import density + expr = condition.lhs - condition.rhs + if not is_random(expr): + dens = self.density + comp = condition.rhs + else: + dens = density(expr, **kwargs) + comp = 0 + if not isinstance(dens, ContinuousDistribution): + from sympy.stats.crv_types import ContinuousDistributionHandmade + dens = ContinuousDistributionHandmade(dens, set=self.domain.set) + # Turn problem into univariate case + space = SingleContinuousPSpace(z, dens) + result = space.probability(condition.__class__(space.value, comp)) + return result if not cond_inv else S.One - result + + def where(self, condition): + rvs = frozenset(random_symbols(condition)) + if not (len(rvs) == 1 and rvs.issubset(self.values)): + raise NotImplementedError( + "Multiple continuous random variables not supported") + rv = tuple(rvs)[0] + interval = reduce_rational_inequalities_wrap(condition, rv) + interval = interval.intersect(self.domain.set) + return SingleContinuousDomain(rv.symbol, interval) + + def conditional_space(self, condition, normalize=True, **kwargs): + condition = condition.xreplace({rv: rv.symbol for rv in self.values}) + domain = ConditionalContinuousDomain(self.domain, condition) + if normalize: + # create a clone of the variable to + # make sure that variables in nested integrals are different + # from the variables outside the integral + # this makes sure that they are evaluated separately + # and in the correct order + replacement = {rv: Dummy(str(rv)) for rv in self.symbols} + norm = domain.compute_expectation(self.pdf, **kwargs) + pdf = self.pdf / norm.xreplace(replacement) + # XXX: Converting set to tuple. The order matters to Lambda though + # so we shouldn't be starting with a set here... + density = Lambda(tuple(domain.symbols), pdf) + + return ContinuousPSpace(domain, density) + + +class SingleContinuousPSpace(ContinuousPSpace, SinglePSpace): + """ + A continuous probability space over a single univariate variable. + + These consist of a Symbol and a SingleContinuousDistribution + + This class is normally accessed through the various random variable + functions, Normal, Exponential, Uniform, etc.... + """ + + @property + def set(self): + return self.distribution.set + + @property + def domain(self): + return SingleContinuousDomain(sympify(self.symbol), self.set) + + def sample(self, size=(), library='scipy', seed=None): + """ + Internal sample method. + + Returns dictionary mapping RandomSymbol to realization value. + """ + return {self.value: self.distribution.sample(size, library=library, seed=seed)} + + def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): + rvs = rvs or (self.value,) + if self.value not in rvs: + return expr + + expr = _sympify(expr) + expr = expr.xreplace({rv: rv.symbol for rv in rvs}) + + x = self.value.symbol + try: + return self.distribution.expectation(expr, x, evaluate=evaluate, **kwargs) + except PoleError: + return Integral(expr * self.pdf, (x, self.set), **kwargs) + + def compute_cdf(self, expr, **kwargs): + if expr == self.value: + z = Dummy("z", real=True) + return Lambda(z, self.distribution.cdf(z, **kwargs)) + else: + return ContinuousPSpace.compute_cdf(self, expr, **kwargs) + + def compute_characteristic_function(self, expr, **kwargs): + if expr == self.value: + t = Dummy("t", real=True) + return Lambda(t, self.distribution.characteristic_function(t, **kwargs)) + else: + return ContinuousPSpace.compute_characteristic_function(self, expr, **kwargs) + + def compute_moment_generating_function(self, expr, **kwargs): + if expr == self.value: + t = Dummy("t", real=True) + return Lambda(t, self.distribution.moment_generating_function(t, **kwargs)) + else: + return ContinuousPSpace.compute_moment_generating_function(self, expr, **kwargs) + + def compute_density(self, expr, **kwargs): + # https://en.wikipedia.org/wiki/Random_variable#Functions_of_random_variables + if expr == self.value: + return self.density + y = Dummy('y', real=True) + + gs = solveset(expr - y, self.value, S.Reals) + + if isinstance(gs, Intersection): + if len(gs.args) == 2 and gs.args[0] is S.Reals: + gs = gs.args[1] + if not gs.is_FiniteSet: + raise ValueError("Can not solve %s for %s" % (expr, self.value)) + fx = self.compute_density(self.value) + fy = sum(fx(g) * abs(g.diff(y)) for g in gs) + return Lambda(y, fy) + + def compute_quantile(self, expr, **kwargs): + + if expr == self.value: + p = Dummy("p", real=True) + return Lambda(p, self.distribution.quantile(p, **kwargs)) + else: + return ContinuousPSpace.compute_quantile(self, expr, **kwargs) + +def _reduce_inequalities(conditions, var, **kwargs): + try: + return reduce_rational_inequalities(conditions, var, **kwargs) + except PolynomialError: + raise ValueError("Reduction of condition failed %s\n" % conditions[0]) + + +def reduce_rational_inequalities_wrap(condition, var): + if condition.is_Relational: + return _reduce_inequalities([[condition]], var, relational=False) + if isinstance(condition, Or): + return Union(*[_reduce_inequalities([[arg]], var, relational=False) + for arg in condition.args]) + if isinstance(condition, And): + intervals = [_reduce_inequalities([[arg]], var, relational=False) + for arg in condition.args] + I = intervals[0] + for i in intervals: + I = I.intersect(i) + return I diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/crv_types.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/crv_types.py new file mode 100644 index 0000000000000000000000000000000000000000..073e7350fdf80aac39ecd1dd607488a8b76187e3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/crv_types.py @@ -0,0 +1,4732 @@ +""" +Continuous Random Variables - Prebuilt variables + +Contains +======== +Arcsin +Benini +Beta +BetaNoncentral +BetaPrime +BoundedPareto +Cauchy +Chi +ChiNoncentral +ChiSquared +Dagum +Davis +Erlang +ExGaussian +Exponential +ExponentialPower +FDistribution +FisherZ +Frechet +Gamma +GammaInverse +Gumbel +Gompertz +Kumaraswamy +Laplace +Levy +LogCauchy +Logistic +LogLogistic +LogitNormal +LogNormal +Lomax +Maxwell +Moyal +Nakagami +Normal +Pareto +PowerFunction +QuadraticU +RaisedCosine +Rayleigh +Reciprocal +ShiftedGompertz +StudentT +Trapezoidal +Triangular +Uniform +UniformSum +VonMises +Wald +Weibull +WignerSemicircle +""" + + + +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.trigonometric import (atan, cos, sin, tan) +from sympy.functions.special.bessel import (besseli, besselj, besselk) +from sympy.functions.special.beta_functions import beta as beta_fn +from sympy.concrete.summations import Sum +from sympy.core.basic import Basic +from sympy.core.function import Lambda +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import (Eq, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import (binomial, factorial) +from sympy.functions.elementary.complexes import (Abs, sign) +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.hyperbolic import sinh +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.miscellaneous import sqrt, Max, Min +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import asin +from sympy.functions.special.error_functions import (erf, erfc, erfi, erfinv, expint) +from sympy.functions.special.gamma_functions import (gamma, lowergamma, uppergamma) +from sympy.functions.special.zeta_functions import zeta +from sympy.functions.special.hyper import hyper +from sympy.integrals.integrals import integrate +from sympy.logic.boolalg import And +from sympy.sets.sets import Interval +from sympy.matrices import MatrixBase +from sympy.stats.crv import SingleContinuousPSpace, SingleContinuousDistribution +from sympy.stats.rv import _value_check, is_random + +oo = S.Infinity + +__all__ = ['ContinuousRV', +'Arcsin', +'Benini', +'Beta', +'BetaNoncentral', +'BetaPrime', +'BoundedPareto', +'Cauchy', +'Chi', +'ChiNoncentral', +'ChiSquared', +'Dagum', +'Davis', +'Erlang', +'ExGaussian', +'Exponential', +'ExponentialPower', +'FDistribution', +'FisherZ', +'Frechet', +'Gamma', +'GammaInverse', +'Gompertz', +'Gumbel', +'Kumaraswamy', +'Laplace', +'Levy', +'LogCauchy', +'Logistic', +'LogLogistic', +'LogitNormal', +'LogNormal', +'Lomax', +'Maxwell', +'Moyal', +'Nakagami', +'Normal', +'GaussianInverse', +'Pareto', +'PowerFunction', +'QuadraticU', +'RaisedCosine', +'Rayleigh', +'Reciprocal', +'StudentT', +'ShiftedGompertz', +'Trapezoidal', +'Triangular', +'Uniform', +'UniformSum', +'VonMises', +'Wald', +'Weibull', +'WignerSemicircle', +] + + +@is_random.register(MatrixBase) +def _(x): + return any(is_random(i) for i in x) + +def rv(symbol, cls, args, **kwargs): + args = list(map(sympify, args)) + dist = cls(*args) + if kwargs.pop('check', True): + dist.check(*args) + pspace = SingleContinuousPSpace(symbol, dist) + if any(is_random(arg) for arg in args): + from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution + pspace = CompoundPSpace(symbol, CompoundDistribution(dist)) + return pspace.value + + +class ContinuousDistributionHandmade(SingleContinuousDistribution): + _argnames = ('pdf',) + + def __new__(cls, pdf, set=Interval(-oo, oo)): + return Basic.__new__(cls, pdf, set) + + @property + def set(self): + return self.args[1] + + @staticmethod + def check(pdf, set): + x = Dummy('x') + val = integrate(pdf(x), (x, set)) + _value_check(Eq(val, 1) != S.false, "The pdf on the given set is incorrect.") + + +def ContinuousRV(symbol, density, set=Interval(-oo, oo), **kwargs): + """ + Create a Continuous Random Variable given the following: + + Parameters + ========== + + symbol : Symbol + Represents name of the random variable. + density : Expression containing symbol + Represents probability density function. + set : set/Interval + Represents the region where the pdf is valid, by default is real line. + check : bool + If True, it will check whether the given density + integrates to 1 over the given set. If False, it + will not perform this check. Default is False. + + + Returns + ======= + + RandomSymbol + + Many common continuous random variable types are already implemented. + This function should be necessary only very rarely. + + + Examples + ======== + + >>> from sympy import Symbol, sqrt, exp, pi + >>> from sympy.stats import ContinuousRV, P, E + + >>> x = Symbol("x") + + >>> pdf = sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) # Normal distribution + >>> X = ContinuousRV(x, pdf) + + >>> E(X) + 0 + >>> P(X>0) + 1/2 + """ + pdf = Piecewise((density, set.as_relational(symbol)), (0, True)) + pdf = Lambda(symbol, pdf) + # have a default of False while `rv` should have a default of True + kwargs['check'] = kwargs.pop('check', False) + return rv(symbol.name, ContinuousDistributionHandmade, (pdf, set), **kwargs) + +######################################## +# Continuous Probability Distributions # +######################################## + +#------------------------------------------------------------------------------- +# Arcsin distribution ---------------------------------------------------------- + + +class ArcsinDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + @property + def set(self): + return Interval(self.a, self.b) + + def pdf(self, x): + a, b = self.a, self.b + return 1/(pi*sqrt((x - a)*(b - x))) + + def _cdf(self, x): + a, b = self.a, self.b + return Piecewise( + (S.Zero, x < a), + (2*asin(sqrt((x - a)/(b - a)))/pi, x <= b), + (S.One, True)) + + +def Arcsin(name, a=0, b=1): + r""" + Create a Continuous Random Variable with an arcsin distribution. + + The density of the arcsin distribution is given by + + .. math:: + f(x) := \frac{1}{\pi\sqrt{(x-a)(b-x)}} + + with :math:`x \in (a,b)`. It must hold that :math:`-\infty < a < b < \infty`. + + Parameters + ========== + + a : Real number, the left interval boundary + b : Real number, the right interval boundary + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Arcsin, density, cdf + >>> from sympy import Symbol + + >>> a = Symbol("a", real=True) + >>> b = Symbol("b", real=True) + >>> z = Symbol("z") + + >>> X = Arcsin("x", a, b) + + >>> density(X)(z) + 1/(pi*sqrt((-a + z)*(b - z))) + + >>> cdf(X)(z) + Piecewise((0, a > z), + (2*asin(sqrt((-a + z)/(-a + b)))/pi, b >= z), + (1, True)) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Arcsine_distribution + + """ + + return rv(name, ArcsinDistribution, (a, b)) + +#------------------------------------------------------------------------------- +# Benini distribution ---------------------------------------------------------- + + +class BeniniDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta', 'sigma') + + @staticmethod + def check(alpha, beta, sigma): + _value_check(alpha > 0, "Shape parameter Alpha must be positive.") + _value_check(beta > 0, "Shape parameter Beta must be positive.") + _value_check(sigma > 0, "Scale parameter Sigma must be positive.") + + @property + def set(self): + return Interval(self.sigma, oo) + + def pdf(self, x): + alpha, beta, sigma = self.alpha, self.beta, self.sigma + return (exp(-alpha*log(x/sigma) - beta*log(x/sigma)**2) + *(alpha/x + 2*beta*log(x/sigma)/x)) + + def _moment_generating_function(self, t): + raise NotImplementedError('The moment generating function of the ' + 'Benini distribution does not exist.') + +def Benini(name, alpha, beta, sigma): + r""" + Create a Continuous Random Variable with a Benini distribution. + + The density of the Benini distribution is given by + + .. math:: + f(x) := e^{-\alpha\log{\frac{x}{\sigma}} + -\beta\log^2\left[{\frac{x}{\sigma}}\right]} + \left(\frac{\alpha}{x}+\frac{2\beta\log{\frac{x}{\sigma}}}{x}\right) + + This is a heavy-tailed distribution and is also known as the log-Rayleigh + distribution. + + Parameters + ========== + + alpha : Real number, `\alpha > 0`, a shape + beta : Real number, `\beta > 0`, a shape + sigma : Real number, `\sigma > 0`, a scale + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Benini, density, cdf + >>> from sympy import Symbol, pprint + + >>> alpha = Symbol("alpha", positive=True) + >>> beta = Symbol("beta", positive=True) + >>> sigma = Symbol("sigma", positive=True) + >>> z = Symbol("z") + + >>> X = Benini("x", alpha, beta, sigma) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + / / z \\ / z \ 2/ z \ + | 2*beta*log|-----|| - alpha*log|-----| - beta*log |-----| + |alpha \sigma/| \sigma/ \sigma/ + |----- + -----------------|*e + \ z z / + + >>> cdf(X)(z) + Piecewise((1 - exp(-alpha*log(z/sigma) - beta*log(z/sigma)**2), sigma <= z), + (0, True)) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Benini_distribution + .. [2] https://reference.wolfram.com/legacy/v8/ref/BeniniDistribution.html + + """ + + return rv(name, BeniniDistribution, (alpha, beta, sigma)) + +#------------------------------------------------------------------------------- +# Beta distribution ------------------------------------------------------------ + + +class BetaDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta') + + set = Interval(0, 1) + + @staticmethod + def check(alpha, beta): + _value_check(alpha > 0, "Shape parameter Alpha must be positive.") + _value_check(beta > 0, "Shape parameter Beta must be positive.") + + def pdf(self, x): + alpha, beta = self.alpha, self.beta + return x**(alpha - 1) * (1 - x)**(beta - 1) / beta_fn(alpha, beta) + + def _characteristic_function(self, t): + return hyper((self.alpha,), (self.alpha + self.beta,), I*t) + + def _moment_generating_function(self, t): + return hyper((self.alpha,), (self.alpha + self.beta,), t) + + +def Beta(name, alpha, beta): + r""" + Create a Continuous Random Variable with a Beta distribution. + + The density of the Beta distribution is given by + + .. math:: + f(x) := \frac{x^{\alpha-1}(1-x)^{\beta-1}} {\mathrm{B}(\alpha,\beta)} + + with :math:`x \in [0,1]`. + + Parameters + ========== + + alpha : Real number, `\alpha > 0`, a shape + beta : Real number, `\beta > 0`, a shape + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Beta, density, E, variance + >>> from sympy import Symbol, simplify, pprint, factor + + >>> alpha = Symbol("alpha", positive=True) + >>> beta = Symbol("beta", positive=True) + >>> z = Symbol("z") + + >>> X = Beta("x", alpha, beta) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + alpha - 1 beta - 1 + z *(1 - z) + -------------------------- + B(alpha, beta) + + >>> simplify(E(X)) + alpha/(alpha + beta) + + >>> factor(simplify(variance(X))) + alpha*beta/((alpha + beta)**2*(alpha + beta + 1)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Beta_distribution + .. [2] https://mathworld.wolfram.com/BetaDistribution.html + + """ + + return rv(name, BetaDistribution, (alpha, beta)) + +#------------------------------------------------------------------------------- +# Noncentral Beta distribution ------------------------------------------------------------ + + +class BetaNoncentralDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta', 'lamda') + + set = Interval(0, 1) + + @staticmethod + def check(alpha, beta, lamda): + _value_check(alpha > 0, "Shape parameter Alpha must be positive.") + _value_check(beta > 0, "Shape parameter Beta must be positive.") + _value_check(lamda >= 0, "Noncentrality parameter Lambda must be positive") + + def pdf(self, x): + alpha, beta, lamda = self.alpha, self.beta, self.lamda + k = Dummy("k") + return Sum(exp(-lamda / 2) * (lamda / 2)**k * x**(alpha + k - 1) *( + 1 - x)**(beta - 1) / (factorial(k) * beta_fn(alpha + k, beta)), (k, 0, oo)) + +def BetaNoncentral(name, alpha, beta, lamda): + r""" + Create a Continuous Random Variable with a Type I Noncentral Beta distribution. + + The density of the Noncentral Beta distribution is given by + + .. math:: + f(x) := \sum_{k=0}^\infty e^{-\lambda/2}\frac{(\lambda/2)^k}{k!} + \frac{x^{\alpha+k-1}(1-x)^{\beta-1}}{\mathrm{B}(\alpha+k,\beta)} + + with :math:`x \in [0,1]`. + + Parameters + ========== + + alpha : Real number, `\alpha > 0`, a shape + beta : Real number, `\beta > 0`, a shape + lamda : Real number, `\lambda \geq 0`, noncentrality parameter + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import BetaNoncentral, density, cdf + >>> from sympy import Symbol, pprint + + >>> alpha = Symbol("alpha", positive=True) + >>> beta = Symbol("beta", positive=True) + >>> lamda = Symbol("lamda", nonnegative=True) + >>> z = Symbol("z") + + >>> X = BetaNoncentral("x", alpha, beta, lamda) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + oo + _____ + \ ` + \ -lamda + \ k ------- + \ k + alpha - 1 /lamda\ beta - 1 2 + ) z *|-----| *(1 - z) *e + / \ 2 / + / ------------------------------------------------ + / B(k + alpha, beta)*k! + /____, + k = 0 + + Compute cdf with specific 'x', 'alpha', 'beta' and 'lamda' values as follows: + + >>> cdf(BetaNoncentral("x", 1, 1, 1), evaluate=False)(2).doit() + 2*exp(1/2) + + The argument evaluate=False prevents an attempt at evaluation + of the sum for general x, before the argument 2 is passed. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Noncentral_beta_distribution + .. [2] https://reference.wolfram.com/language/ref/NoncentralBetaDistribution.html + + """ + + return rv(name, BetaNoncentralDistribution, (alpha, beta, lamda)) + + +#------------------------------------------------------------------------------- +# Beta prime distribution ------------------------------------------------------ + + +class BetaPrimeDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta') + + @staticmethod + def check(alpha, beta): + _value_check(alpha > 0, "Shape parameter Alpha must be positive.") + _value_check(beta > 0, "Shape parameter Beta must be positive.") + + set = Interval(0, oo) + + def pdf(self, x): + alpha, beta = self.alpha, self.beta + return x**(alpha - 1)*(1 + x)**(-alpha - beta)/beta_fn(alpha, beta) + +def BetaPrime(name, alpha, beta): + r""" + Create a continuous random variable with a Beta prime distribution. + + The density of the Beta prime distribution is given by + + .. math:: + f(x) := \frac{x^{\alpha-1} (1+x)^{-\alpha -\beta}}{B(\alpha,\beta)} + + with :math:`x > 0`. + + Parameters + ========== + + alpha : Real number, `\alpha > 0`, a shape + beta : Real number, `\beta > 0`, a shape + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import BetaPrime, density + >>> from sympy import Symbol, pprint + + >>> alpha = Symbol("alpha", positive=True) + >>> beta = Symbol("beta", positive=True) + >>> z = Symbol("z") + + >>> X = BetaPrime("x", alpha, beta) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + alpha - 1 -alpha - beta + z *(z + 1) + ------------------------------- + B(alpha, beta) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Beta_prime_distribution + .. [2] https://mathworld.wolfram.com/BetaPrimeDistribution.html + + """ + + return rv(name, BetaPrimeDistribution, (alpha, beta)) + +#------------------------------------------------------------------------------- +# Bounded Pareto Distribution -------------------------------------------------- +class BoundedParetoDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'left', 'right') + + @property + def set(self): + return Interval(self.left, self.right) + + @staticmethod + def check(alpha, left, right): + _value_check (alpha.is_positive, "Shape must be positive.") + _value_check (left.is_positive, "Left value should be positive.") + _value_check (right > left, "Right should be greater than left.") + + def pdf(self, x): + alpha, left, right = self.alpha, self.left, self.right + num = alpha * (left**alpha) * x**(- alpha -1) + den = 1 - (left/right)**alpha + return num/den + +def BoundedPareto(name, alpha, left, right): + r""" + Create a continuous random variable with a Bounded Pareto distribution. + + The density of the Bounded Pareto distribution is given by + + .. math:: + f(x) := \frac{\alpha L^{\alpha}x^{-\alpha-1}}{1-(\frac{L}{H})^{\alpha}} + + Parameters + ========== + + alpha : Real Number, `\alpha > 0` + Shape parameter + left : Real Number, `left > 0` + Location parameter + right : Real Number, `right > left` + Location parameter + + Examples + ======== + + >>> from sympy.stats import BoundedPareto, density, cdf, E + >>> from sympy import symbols + >>> L, H = symbols('L, H', positive=True) + >>> X = BoundedPareto('X', 2, L, H) + >>> x = symbols('x') + >>> density(X)(x) + 2*L**2/(x**3*(1 - L**2/H**2)) + >>> cdf(X)(x) + Piecewise((-H**2*L**2/(x**2*(H**2 - L**2)) + H**2/(H**2 - L**2), L <= x), (0, True)) + >>> E(X).simplify() + 2*H*L/(H + L) + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Pareto_distribution#Bounded_Pareto_distribution + + """ + return rv (name, BoundedParetoDistribution, (alpha, left, right)) + +# ------------------------------------------------------------------------------ +# Cauchy distribution ---------------------------------------------------------- + + +class CauchyDistribution(SingleContinuousDistribution): + _argnames = ('x0', 'gamma') + + @staticmethod + def check(x0, gamma): + _value_check(gamma > 0, "Scale parameter Gamma must be positive.") + _value_check(x0.is_real, "Location parameter must be real.") + + def pdf(self, x): + return 1/(pi*self.gamma*(1 + ((x - self.x0)/self.gamma)**2)) + + def _cdf(self, x): + x0, gamma = self.x0, self.gamma + return (1/pi)*atan((x - x0)/gamma) + S.Half + + def _characteristic_function(self, t): + return exp(self.x0 * I * t - self.gamma * Abs(t)) + + def _moment_generating_function(self, t): + raise NotImplementedError("The moment generating function for the " + "Cauchy distribution does not exist.") + + def _quantile(self, p): + return self.x0 + self.gamma*tan(pi*(p - S.Half)) + + +def Cauchy(name, x0, gamma): + r""" + Create a continuous random variable with a Cauchy distribution. + + The density of the Cauchy distribution is given by + + .. math:: + f(x) := \frac{1}{\pi \gamma [1 + {(\frac{x-x_0}{\gamma})}^2]} + + Parameters + ========== + + x0 : Real number, the location + gamma : Real number, `\gamma > 0`, a scale + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Cauchy, density + >>> from sympy import Symbol + + >>> x0 = Symbol("x0") + >>> gamma = Symbol("gamma", positive=True) + >>> z = Symbol("z") + + >>> X = Cauchy("x", x0, gamma) + + >>> density(X)(z) + 1/(pi*gamma*(1 + (-x0 + z)**2/gamma**2)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Cauchy_distribution + .. [2] https://mathworld.wolfram.com/CauchyDistribution.html + + """ + + return rv(name, CauchyDistribution, (x0, gamma)) + +#------------------------------------------------------------------------------- +# Chi distribution ------------------------------------------------------------- + + +class ChiDistribution(SingleContinuousDistribution): + _argnames = ('k',) + + @staticmethod + def check(k): + _value_check(k > 0, "Number of degrees of freedom (k) must be positive.") + _value_check(k.is_integer, "Number of degrees of freedom (k) must be an integer.") + + set = Interval(0, oo) + + def pdf(self, x): + return 2**(1 - self.k/2)*x**(self.k - 1)*exp(-x**2/2)/gamma(self.k/2) + + def _characteristic_function(self, t): + k = self.k + + part_1 = hyper((k/2,), (S.Half,), -t**2/2) + part_2 = I*t*sqrt(2)*gamma((k+1)/2)/gamma(k/2) + part_3 = hyper(((k+1)/2,), (Rational(3, 2),), -t**2/2) + return part_1 + part_2*part_3 + + def _moment_generating_function(self, t): + k = self.k + + part_1 = hyper((k / 2,), (S.Half,), t ** 2 / 2) + part_2 = t * sqrt(2) * gamma((k + 1) / 2) / gamma(k / 2) + part_3 = hyper(((k + 1) / 2,), (S(3) / 2,), t ** 2 / 2) + return part_1 + part_2 * part_3 + +def Chi(name, k): + r""" + Create a continuous random variable with a Chi distribution. + + The density of the Chi distribution is given by + + .. math:: + f(x) := \frac{2^{1-k/2}x^{k-1}e^{-x^2/2}}{\Gamma(k/2)} + + with :math:`x \geq 0`. + + Parameters + ========== + + k : Positive integer, The number of degrees of freedom + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Chi, density, E + >>> from sympy import Symbol, simplify + + >>> k = Symbol("k", integer=True) + >>> z = Symbol("z") + + >>> X = Chi("x", k) + + >>> density(X)(z) + 2**(1 - k/2)*z**(k - 1)*exp(-z**2/2)/gamma(k/2) + + >>> simplify(E(X)) + sqrt(2)*gamma(k/2 + 1/2)/gamma(k/2) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Chi_distribution + .. [2] https://mathworld.wolfram.com/ChiDistribution.html + + """ + + return rv(name, ChiDistribution, (k,)) + +#------------------------------------------------------------------------------- +# Non-central Chi distribution ------------------------------------------------- + + +class ChiNoncentralDistribution(SingleContinuousDistribution): + _argnames = ('k', 'l') + + @staticmethod + def check(k, l): + _value_check(k > 0, "Number of degrees of freedom (k) must be positive.") + _value_check(k.is_integer, "Number of degrees of freedom (k) must be an integer.") + _value_check(l > 0, "Shift parameter Lambda must be positive.") + + set = Interval(0, oo) + + def pdf(self, x): + k, l = self.k, self.l + return exp(-(x**2+l**2)/2)*x**k*l / (l*x)**(k/2) * besseli(k/2-1, l*x) + +def ChiNoncentral(name, k, l): + r""" + Create a continuous random variable with a non-central Chi distribution. + + Explanation + =========== + + The density of the non-central Chi distribution is given by + + .. math:: + f(x) := \frac{e^{-(x^2+\lambda^2)/2} x^k\lambda} + {(\lambda x)^{k/2}} I_{k/2-1}(\lambda x) + + with `x \geq 0`. Here, `I_\nu (x)` is the + :ref:`modified Bessel function of the first kind `. + + Parameters + ========== + + k : A positive Integer, $k > 0$ + The number of degrees of freedom. + lambda : Real number, `\lambda > 0` + Shift parameter. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import ChiNoncentral, density + >>> from sympy import Symbol + + >>> k = Symbol("k", integer=True) + >>> l = Symbol("l") + >>> z = Symbol("z") + + >>> X = ChiNoncentral("x", k, l) + + >>> density(X)(z) + l*z**k*exp(-l**2/2 - z**2/2)*besseli(k/2 - 1, l*z)/(l*z)**(k/2) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Noncentral_chi_distribution + """ + + return rv(name, ChiNoncentralDistribution, (k, l)) + +#------------------------------------------------------------------------------- +# Chi squared distribution ----------------------------------------------------- + + +class ChiSquaredDistribution(SingleContinuousDistribution): + _argnames = ('k',) + + @staticmethod + def check(k): + _value_check(k > 0, "Number of degrees of freedom (k) must be positive.") + _value_check(k.is_integer, "Number of degrees of freedom (k) must be an integer.") + + set = Interval(0, oo) + + def pdf(self, x): + k = self.k + return 1/(2**(k/2)*gamma(k/2))*x**(k/2 - 1)*exp(-x/2) + + def _cdf(self, x): + k = self.k + return Piecewise( + (S.One/gamma(k/2)*lowergamma(k/2, x/2), x >= 0), + (0, True) + ) + + def _characteristic_function(self, t): + return (1 - 2*I*t)**(-self.k/2) + + def _moment_generating_function(self, t): + return (1 - 2*t)**(-self.k/2) + + +def ChiSquared(name, k): + r""" + Create a continuous random variable with a Chi-squared distribution. + + Explanation + =========== + + The density of the Chi-squared distribution is given by + + .. math:: + f(x) := \frac{1}{2^{\frac{k}{2}}\Gamma\left(\frac{k}{2}\right)} + x^{\frac{k}{2}-1} e^{-\frac{x}{2}} + + with :math:`x \geq 0`. + + Parameters + ========== + + k : Positive integer + The number of degrees of freedom. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import ChiSquared, density, E, variance, moment + >>> from sympy import Symbol + + >>> k = Symbol("k", integer=True, positive=True) + >>> z = Symbol("z") + + >>> X = ChiSquared("x", k) + + >>> density(X)(z) + z**(k/2 - 1)*exp(-z/2)/(2**(k/2)*gamma(k/2)) + + >>> E(X) + k + + >>> variance(X) + 2*k + + >>> moment(X, 3) + k**3 + 6*k**2 + 8*k + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Chi_squared_distribution + .. [2] https://mathworld.wolfram.com/Chi-SquaredDistribution.html + """ + + return rv(name, ChiSquaredDistribution, (k, )) + +#------------------------------------------------------------------------------- +# Dagum distribution ----------------------------------------------------------- + + +class DagumDistribution(SingleContinuousDistribution): + _argnames = ('p', 'a', 'b') + + set = Interval(0, oo) + + @staticmethod + def check(p, a, b): + _value_check(p > 0, "Shape parameter p must be positive.") + _value_check(a > 0, "Shape parameter a must be positive.") + _value_check(b > 0, "Scale parameter b must be positive.") + + def pdf(self, x): + p, a, b = self.p, self.a, self.b + return a*p/x*((x/b)**(a*p)/(((x/b)**a + 1)**(p + 1))) + + def _cdf(self, x): + p, a, b = self.p, self.a, self.b + return Piecewise(((S.One + (S(x)/b)**-a)**-p, x>=0), + (S.Zero, True)) + +def Dagum(name, p, a, b): + r""" + Create a continuous random variable with a Dagum distribution. + + Explanation + =========== + + The density of the Dagum distribution is given by + + .. math:: + f(x) := \frac{a p}{x} \left( \frac{\left(\tfrac{x}{b}\right)^{a p}} + {\left(\left(\tfrac{x}{b}\right)^a + 1 \right)^{p+1}} \right) + + with :math:`x > 0`. + + Parameters + ========== + + p : Real number + `p > 0`, a shape. + a : Real number + `a > 0`, a shape. + b : Real number + `b > 0`, a scale. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Dagum, density, cdf + >>> from sympy import Symbol + + >>> p = Symbol("p", positive=True) + >>> a = Symbol("a", positive=True) + >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") + + >>> X = Dagum("x", p, a, b) + + >>> density(X)(z) + a*p*(z/b)**(a*p)*((z/b)**a + 1)**(-p - 1)/z + + >>> cdf(X)(z) + Piecewise(((1 + (z/b)**(-a))**(-p), z >= 0), (0, True)) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Dagum_distribution + + """ + + return rv(name, DagumDistribution, (p, a, b)) + +#------------------------------------------------------------------------------- +# Davis distribution ----------------------------------------------------------- + +class DavisDistribution(SingleContinuousDistribution): + _argnames = ('b', 'n', 'mu') + + set = Interval(0, oo) + + @staticmethod + def check(b, n, mu): + _value_check(b > 0, "Scale parameter b must be positive.") + _value_check(n > 1, "Shape parameter n must be above 1.") + _value_check(mu > 0, "Location parameter mu must be positive.") + + def pdf(self, x): + b, n, mu = self.b, self.n, self.mu + dividend = b**n*(x - mu)**(-1-n) + divisor = (exp(b/(x-mu))-1)*(gamma(n)*zeta(n)) + return dividend/divisor + + +def Davis(name, b, n, mu): + r""" Create a continuous random variable with Davis distribution. + + Explanation + =========== + + The density of Davis distribution is given by + + .. math:: + f(x; \mu; b, n) := \frac{b^{n}(x - \mu)^{1-n}}{ \left( e^{\frac{b}{x-\mu}} - 1 \right) \Gamma(n)\zeta(n)} + + with :math:`x \in [0,\infty]`. + + Davis distribution is a generalization of the Planck's law of radiation from statistical physics. It is used for modeling income distribution. + + Parameters + ========== + b : Real number + `p > 0`, a scale. + n : Real number + `n > 1`, a shape. + mu : Real number + `mu > 0`, a location. + + Returns + ======= + + RandomSymbol + + Examples + ======== + >>> from sympy.stats import Davis, density + >>> from sympy import Symbol + >>> b = Symbol("b", positive=True) + >>> n = Symbol("n", positive=True) + >>> mu = Symbol("mu", positive=True) + >>> z = Symbol("z") + >>> X = Davis("x", b, n, mu) + >>> density(X)(z) + b**n*(-mu + z)**(-n - 1)/((exp(b/(-mu + z)) - 1)*gamma(n)*zeta(n)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Davis_distribution + .. [2] https://reference.wolfram.com/language/ref/DavisDistribution.html + + """ + return rv(name, DavisDistribution, (b, n, mu)) + + +#------------------------------------------------------------------------------- +# Erlang distribution ---------------------------------------------------------- + + +def Erlang(name, k, l): + r""" + Create a continuous random variable with an Erlang distribution. + + Explanation + =========== + + The density of the Erlang distribution is given by + + .. math:: + f(x) := \frac{\lambda^k x^{k-1} e^{-\lambda x}}{(k-1)!} + + with :math:`x \in [0,\infty]`. + + Parameters + ========== + + k : Positive integer + l : Real number, `\lambda > 0`, the rate + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Erlang, density, cdf, E, variance + >>> from sympy import Symbol, simplify, pprint + + >>> k = Symbol("k", integer=True, positive=True) + >>> l = Symbol("l", positive=True) + >>> z = Symbol("z") + + >>> X = Erlang("x", k, l) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + k k - 1 -l*z + l *z *e + --------------- + Gamma(k) + + >>> C = cdf(X)(z) + >>> pprint(C, use_unicode=False) + /lowergamma(k, l*z) + |------------------ for z > 0 + < Gamma(k) + | + \ 0 otherwise + + + >>> E(X) + k/l + + >>> simplify(variance(X)) + k/l**2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Erlang_distribution + .. [2] https://mathworld.wolfram.com/ErlangDistribution.html + + """ + + return rv(name, GammaDistribution, (k, S.One/l)) + +# ------------------------------------------------------------------------------- +# ExGaussian distribution ----------------------------------------------------- + + +class ExGaussianDistribution(SingleContinuousDistribution): + _argnames = ('mean', 'std', 'rate') + + set = Interval(-oo, oo) + + @staticmethod + def check(mean, std, rate): + _value_check( + std > 0, "Standard deviation of ExGaussian must be positive.") + _value_check(rate > 0, "Rate of ExGaussian must be positive.") + + def pdf(self, x): + mean, std, rate = self.mean, self.std, self.rate + term1 = rate/2 + term2 = exp(rate * (2 * mean + rate * std**2 - 2*x)/2) + term3 = erfc((mean + rate*std**2 - x)/(sqrt(2)*std)) + return term1*term2*term3 + + def _cdf(self, x): + from sympy.stats import cdf + mean, std, rate = self.mean, self.std, self.rate + u = rate*(x - mean) + v = rate*std + GaussianCDF1 = cdf(Normal('x', 0, v))(u) + GaussianCDF2 = cdf(Normal('x', v**2, v))(u) + + return GaussianCDF1 - exp(-u + (v**2/2) + log(GaussianCDF2)) + + def _characteristic_function(self, t): + mean, std, rate = self.mean, self.std, self.rate + term1 = (1 - I*t/rate)**(-1) + term2 = exp(I*mean*t - std**2*t**2/2) + return term1 * term2 + + def _moment_generating_function(self, t): + mean, std, rate = self.mean, self.std, self.rate + term1 = (1 - t/rate)**(-1) + term2 = exp(mean*t + std**2*t**2/2) + return term1*term2 + + +def ExGaussian(name, mean, std, rate): + r""" + Create a continuous random variable with an Exponentially modified + Gaussian (EMG) distribution. + + Explanation + =========== + + The density of the exponentially modified Gaussian distribution is given by + + .. math:: + f(x) := \frac{\lambda}{2}e^{\frac{\lambda}{2}(2\mu+\lambda\sigma^2-2x)} + \text{erfc}(\frac{\mu + \lambda\sigma^2 - x}{\sqrt{2}\sigma}) + + with $x > 0$. Note that the expected value is `1/\lambda`. + + Parameters + ========== + + name : A string giving a name for this distribution + mean : A Real number, the mean of Gaussian component + std : A positive Real number, + :math: `\sigma^2 > 0` the variance of Gaussian component + rate : A positive Real number, + :math: `\lambda > 0` the rate of Exponential component + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import ExGaussian, density, cdf, E + >>> from sympy.stats import variance, skewness + >>> from sympy import Symbol, pprint, simplify + + >>> mean = Symbol("mu") + >>> std = Symbol("sigma", positive=True) + >>> rate = Symbol("lamda", positive=True) + >>> z = Symbol("z") + >>> X = ExGaussian("x", mean, std, rate) + + >>> pprint(density(X)(z), use_unicode=False) + / 2 \ + lamda*\lamda*sigma + 2*mu - 2*z/ + --------------------------------- / ___ / 2 \\ + 2 |\/ 2 *\lamda*sigma + mu - z/| + lamda*e *erfc|-----------------------------| + \ 2*sigma / + ---------------------------------------------------------------------------- + 2 + + >>> cdf(X)(z) + -(erf(sqrt(2)*(-lamda**2*sigma**2 + lamda*(-mu + z))/(2*lamda*sigma))/2 + 1/2)*exp(lamda**2*sigma**2/2 - lamda*(-mu + z)) + erf(sqrt(2)*(-mu + z)/(2*sigma))/2 + 1/2 + + >>> E(X) + (lamda*mu + 1)/lamda + + >>> simplify(variance(X)) + sigma**2 + lamda**(-2) + + >>> simplify(skewness(X)) + 2/(lamda**2*sigma**2 + 1)**(3/2) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Exponentially_modified_Gaussian_distribution + """ + return rv(name, ExGaussianDistribution, (mean, std, rate)) + +#------------------------------------------------------------------------------- +# Exponential distribution ----------------------------------------------------- + + +class ExponentialDistribution(SingleContinuousDistribution): + _argnames = ('rate',) + + set = Interval(0, oo) + + @staticmethod + def check(rate): + _value_check(rate > 0, "Rate must be positive.") + + def pdf(self, x): + return self.rate * exp(-self.rate*x) + + def _cdf(self, x): + return Piecewise( + (S.One - exp(-self.rate*x), x >= 0), + (0, True), + ) + + def _characteristic_function(self, t): + rate = self.rate + return rate / (rate - I*t) + + def _moment_generating_function(self, t): + rate = self.rate + return rate / (rate - t) + + def _quantile(self, p): + return -log(1-p)/self.rate + + +def Exponential(name, rate): + r""" + Create a continuous random variable with an Exponential distribution. + + Explanation + =========== + + The density of the exponential distribution is given by + + .. math:: + f(x) := \lambda \exp(-\lambda x) + + with $x > 0$. Note that the expected value is `1/\lambda`. + + Parameters + ========== + + rate : A positive Real number, `\lambda > 0`, the rate (or inverse scale/inverse mean) + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Exponential, density, cdf, E + >>> from sympy.stats import variance, std, skewness, quantile + >>> from sympy import Symbol + + >>> l = Symbol("lambda", positive=True) + >>> z = Symbol("z") + >>> p = Symbol("p") + >>> X = Exponential("x", l) + + >>> density(X)(z) + lambda*exp(-lambda*z) + + >>> cdf(X)(z) + Piecewise((1 - exp(-lambda*z), z >= 0), (0, True)) + + >>> quantile(X)(p) + -log(1 - p)/lambda + + >>> E(X) + 1/lambda + + >>> variance(X) + lambda**(-2) + + >>> skewness(X) + 2 + + >>> X = Exponential('x', 10) + + >>> density(X)(z) + 10*exp(-10*z) + + >>> E(X) + 1/10 + + >>> std(X) + 1/10 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Exponential_distribution + .. [2] https://mathworld.wolfram.com/ExponentialDistribution.html + + """ + + return rv(name, ExponentialDistribution, (rate, )) + + +# ------------------------------------------------------------------------------- +# Exponential Power distribution ----------------------------------------------------- + +class ExponentialPowerDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'alpha', 'beta') + + set = Interval(-oo, oo) + + @staticmethod + def check(mu, alpha, beta): + _value_check(alpha > 0, "Scale parameter alpha must be positive.") + _value_check(beta > 0, "Shape parameter beta must be positive.") + + def pdf(self, x): + mu, alpha, beta = self.mu, self.alpha, self.beta + num = beta*exp(-(Abs(x - mu)/alpha)**beta) + den = 2*alpha*gamma(1/beta) + return num/den + + def _cdf(self, x): + mu, alpha, beta = self.mu, self.alpha, self.beta + num = lowergamma(1/beta, (Abs(x - mu) / alpha)**beta) + den = 2*gamma(1/beta) + return sign(x - mu)*num/den + S.Half + + +def ExponentialPower(name, mu, alpha, beta): + r""" + Create a Continuous Random Variable with Exponential Power distribution. + This distribution is known also as Generalized Normal + distribution version 1. + + Explanation + =========== + + The density of the Exponential Power distribution is given by + + .. math:: + f(x) := \frac{\beta}{2\alpha\Gamma(\frac{1}{\beta})} + e^{{-(\frac{|x - \mu|}{\alpha})^{\beta}}} + + with :math:`x \in [ - \infty, \infty ]`. + + Parameters + ========== + + mu : Real number + A location. + alpha : Real number,`\alpha > 0` + A scale. + beta : Real number, `\beta > 0` + A shape. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import ExponentialPower, density, cdf + >>> from sympy import Symbol, pprint + >>> z = Symbol("z") + >>> mu = Symbol("mu") + >>> alpha = Symbol("alpha", positive=True) + >>> beta = Symbol("beta", positive=True) + >>> X = ExponentialPower("x", mu, alpha, beta) + >>> pprint(density(X)(z), use_unicode=False) + beta + /|mu - z|\ + -|--------| + \ alpha / + beta*e + --------------------- + / 1 \ + 2*alpha*Gamma|----| + \beta/ + >>> cdf(X)(z) + 1/2 + lowergamma(1/beta, (Abs(mu - z)/alpha)**beta)*sign(-mu + z)/(2*gamma(1/beta)) + + References + ========== + + .. [1] https://reference.wolfram.com/language/ref/ExponentialPowerDistribution.html + .. [2] https://en.wikipedia.org/wiki/Generalized_normal_distribution#Version_1 + + """ + return rv(name, ExponentialPowerDistribution, (mu, alpha, beta)) + + +#------------------------------------------------------------------------------- +# F distribution --------------------------------------------------------------- + + +class FDistributionDistribution(SingleContinuousDistribution): + _argnames = ('d1', 'd2') + + set = Interval(0, oo) + + @staticmethod + def check(d1, d2): + _value_check((d1 > 0, d1.is_integer), + "Degrees of freedom d1 must be positive integer.") + _value_check((d2 > 0, d2.is_integer), + "Degrees of freedom d2 must be positive integer.") + + def pdf(self, x): + d1, d2 = self.d1, self.d2 + return (sqrt((d1*x)**d1*d2**d2 / (d1*x+d2)**(d1+d2)) + / (x * beta_fn(d1/2, d2/2))) + + def _moment_generating_function(self, t): + raise NotImplementedError('The moment generating function for the ' + 'F-distribution does not exist.') + +def FDistribution(name, d1, d2): + r""" + Create a continuous random variable with a F distribution. + + Explanation + =========== + + The density of the F distribution is given by + + .. math:: + f(x) := \frac{\sqrt{\frac{(d_1 x)^{d_1} d_2^{d_2}} + {(d_1 x + d_2)^{d_1 + d_2}}}} + {x \mathrm{B} \left(\frac{d_1}{2}, \frac{d_2}{2}\right)} + + with :math:`x > 0`. + + Parameters + ========== + + d1 : `d_1 > 0`, where `d_1` is the degrees of freedom (`n_1 - 1`) + d2 : `d_2 > 0`, where `d_2` is the degrees of freedom (`n_2 - 1`) + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import FDistribution, density + >>> from sympy import Symbol, pprint + + >>> d1 = Symbol("d1", positive=True) + >>> d2 = Symbol("d2", positive=True) + >>> z = Symbol("z") + + >>> X = FDistribution("x", d1, d2) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + d2 + -- ______________________________ + 2 / d1 -d1 - d2 + d2 *\/ (d1*z) *(d1*z + d2) + -------------------------------------- + /d1 d2\ + z*B|--, --| + \2 2 / + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/F-distribution + .. [2] https://mathworld.wolfram.com/F-Distribution.html + + """ + + return rv(name, FDistributionDistribution, (d1, d2)) + +#------------------------------------------------------------------------------- +# Fisher Z distribution -------------------------------------------------------- + +class FisherZDistribution(SingleContinuousDistribution): + _argnames = ('d1', 'd2') + + set = Interval(-oo, oo) + + @staticmethod + def check(d1, d2): + _value_check(d1 > 0, "Degree of freedom d1 must be positive.") + _value_check(d2 > 0, "Degree of freedom d2 must be positive.") + + def pdf(self, x): + d1, d2 = self.d1, self.d2 + return (2*d1**(d1/2)*d2**(d2/2) / beta_fn(d1/2, d2/2) * + exp(d1*x) / (d1*exp(2*x)+d2)**((d1+d2)/2)) + +def FisherZ(name, d1, d2): + r""" + Create a Continuous Random Variable with an Fisher's Z distribution. + + Explanation + =========== + + The density of the Fisher's Z distribution is given by + + .. math:: + f(x) := \frac{2d_1^{d_1/2} d_2^{d_2/2}} {\mathrm{B}(d_1/2, d_2/2)} + \frac{e^{d_1z}}{\left(d_1e^{2z}+d_2\right)^{\left(d_1+d_2\right)/2}} + + + .. TODO - What is the difference between these degrees of freedom? + + Parameters + ========== + + d1 : `d_1 > 0` + Degree of freedom. + d2 : `d_2 > 0` + Degree of freedom. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import FisherZ, density + >>> from sympy import Symbol, pprint + + >>> d1 = Symbol("d1", positive=True) + >>> d2 = Symbol("d2", positive=True) + >>> z = Symbol("z") + + >>> X = FisherZ("x", d1, d2) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + d1 d2 + d1 d2 - -- - -- + -- -- 2 2 + 2 2 / 2*z \ d1*z + 2*d1 *d2 *\d1*e + d2/ *e + ----------------------------------------- + /d1 d2\ + B|--, --| + \2 2 / + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Fisher%27s_z-distribution + .. [2] https://mathworld.wolfram.com/Fishersz-Distribution.html + + """ + + return rv(name, FisherZDistribution, (d1, d2)) + +#------------------------------------------------------------------------------- +# Frechet distribution --------------------------------------------------------- + +class FrechetDistribution(SingleContinuousDistribution): + _argnames = ('a', 's', 'm') + + set = Interval(0, oo) + + @staticmethod + def check(a, s, m): + _value_check(a > 0, "Shape parameter alpha must be positive.") + _value_check(s > 0, "Scale parameter s must be positive.") + + def __new__(cls, a, s=1, m=0): + a, s, m = list(map(sympify, (a, s, m))) + return Basic.__new__(cls, a, s, m) + + def pdf(self, x): + a, s, m = self.a, self.s, self.m + return a/s * ((x-m)/s)**(-1-a) * exp(-((x-m)/s)**(-a)) + + def _cdf(self, x): + a, s, m = self.a, self.s, self.m + return Piecewise((exp(-((x-m)/s)**(-a)), x >= m), + (S.Zero, True)) + +def Frechet(name, a, s=1, m=0): + r""" + Create a continuous random variable with a Frechet distribution. + + Explanation + =========== + + The density of the Frechet distribution is given by + + .. math:: + f(x) := \frac{\alpha}{s} \left(\frac{x-m}{s}\right)^{-1-\alpha} + e^{-(\frac{x-m}{s})^{-\alpha}} + + with :math:`x \geq m`. + + Parameters + ========== + + a : Real number, :math:`a \in \left(0, \infty\right)` the shape + s : Real number, :math:`s \in \left(0, \infty\right)` the scale + m : Real number, :math:`m \in \left(-\infty, \infty\right)` the minimum + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Frechet, density, cdf + >>> from sympy import Symbol + + >>> a = Symbol("a", positive=True) + >>> s = Symbol("s", positive=True) + >>> m = Symbol("m", real=True) + >>> z = Symbol("z") + + >>> X = Frechet("x", a, s, m) + + >>> density(X)(z) + a*((-m + z)/s)**(-a - 1)*exp(-1/((-m + z)/s)**a)/s + + >>> cdf(X)(z) + Piecewise((exp(-1/((-m + z)/s)**a), m <= z), (0, True)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Fr%C3%A9chet_distribution + + """ + + return rv(name, FrechetDistribution, (a, s, m)) + +#------------------------------------------------------------------------------- +# Gamma distribution ----------------------------------------------------------- + + +class GammaDistribution(SingleContinuousDistribution): + _argnames = ('k', 'theta') + + set = Interval(0, oo) + + @staticmethod + def check(k, theta): + _value_check(k > 0, "k must be positive") + _value_check(theta > 0, "Theta must be positive") + + def pdf(self, x): + k, theta = self.k, self.theta + return x**(k - 1) * exp(-x/theta) / (gamma(k)*theta**k) + + def _cdf(self, x): + k, theta = self.k, self.theta + return Piecewise( + (lowergamma(k, S(x)/theta)/gamma(k), x > 0), + (S.Zero, True)) + + def _characteristic_function(self, t): + return (1 - self.theta*I*t)**(-self.k) + + def _moment_generating_function(self, t): + return (1- self.theta*t)**(-self.k) + + +def Gamma(name, k, theta): + r""" + Create a continuous random variable with a Gamma distribution. + + Explanation + =========== + + The density of the Gamma distribution is given by + + .. math:: + f(x) := \frac{1}{\Gamma(k) \theta^k} x^{k - 1} e^{-\frac{x}{\theta}} + + with :math:`x \in [0,1]`. + + Parameters + ========== + + k : Real number, `k > 0`, a shape + theta : Real number, `\theta > 0`, a scale + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Gamma, density, cdf, E, variance + >>> from sympy import Symbol, pprint, simplify + + >>> k = Symbol("k", positive=True) + >>> theta = Symbol("theta", positive=True) + >>> z = Symbol("z") + + >>> X = Gamma("x", k, theta) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + -z + ----- + -k k - 1 theta + theta *z *e + --------------------- + Gamma(k) + + >>> C = cdf(X, meijerg=True)(z) + >>> pprint(C, use_unicode=False) + / / z \ + |k*lowergamma|k, -----| + | \ theta/ + <---------------------- for z >= 0 + | Gamma(k + 1) + | + \ 0 otherwise + + >>> E(X) + k*theta + + >>> V = simplify(variance(X)) + >>> pprint(V, use_unicode=False) + 2 + k*theta + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gamma_distribution + .. [2] https://mathworld.wolfram.com/GammaDistribution.html + + """ + + return rv(name, GammaDistribution, (k, theta)) + +#------------------------------------------------------------------------------- +# Inverse Gamma distribution --------------------------------------------------- + + +class GammaInverseDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + set = Interval(0, oo) + + @staticmethod + def check(a, b): + _value_check(a > 0, "alpha must be positive") + _value_check(b > 0, "beta must be positive") + + def pdf(self, x): + a, b = self.a, self.b + return b**a/gamma(a) * x**(-a-1) * exp(-b/x) + + def _cdf(self, x): + a, b = self.a, self.b + return Piecewise((uppergamma(a,b/x)/gamma(a), x > 0), + (S.Zero, True)) + + def _characteristic_function(self, t): + a, b = self.a, self.b + return 2 * (-I*b*t)**(a/2) * besselk(a, sqrt(-4*I*b*t)) / gamma(a) + + def _moment_generating_function(self, t): + raise NotImplementedError('The moment generating function for the ' + 'gamma inverse distribution does not exist.') + +def GammaInverse(name, a, b): + r""" + Create a continuous random variable with an inverse Gamma distribution. + + Explanation + =========== + + The density of the inverse Gamma distribution is given by + + .. math:: + f(x) := \frac{\beta^\alpha}{\Gamma(\alpha)} x^{-\alpha - 1} + \exp\left(\frac{-\beta}{x}\right) + + with :math:`x > 0`. + + Parameters + ========== + + a : Real number, `a > 0`, a shape + b : Real number, `b > 0`, a scale + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import GammaInverse, density, cdf + >>> from sympy import Symbol, pprint + + >>> a = Symbol("a", positive=True) + >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") + + >>> X = GammaInverse("x", a, b) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + -b + --- + a -a - 1 z + b *z *e + --------------- + Gamma(a) + + >>> cdf(X)(z) + Piecewise((uppergamma(a, b/z)/gamma(a), z > 0), (0, True)) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Inverse-gamma_distribution + + """ + + return rv(name, GammaInverseDistribution, (a, b)) + + +#------------------------------------------------------------------------------- +# Gumbel distribution (Maximum and Minimum) -------------------------------------------------------- + + +class GumbelDistribution(SingleContinuousDistribution): + _argnames = ('beta', 'mu', 'minimum') + + set = Interval(-oo, oo) + + @staticmethod + def check(beta, mu, minimum): + _value_check(beta > 0, "Scale parameter beta must be positive.") + + def pdf(self, x): + beta, mu = self.beta, self.mu + z = (x - mu)/beta + f_max = (1/beta)*exp(-z - exp(-z)) + f_min = (1/beta)*exp(z - exp(z)) + return Piecewise((f_min, self.minimum), (f_max, not self.minimum)) + + def _cdf(self, x): + beta, mu = self.beta, self.mu + z = (x - mu)/beta + F_max = exp(-exp(-z)) + F_min = 1 - exp(-exp(z)) + return Piecewise((F_min, self.minimum), (F_max, not self.minimum)) + + def _characteristic_function(self, t): + cf_max = gamma(1 - I*self.beta*t) * exp(I*self.mu*t) + cf_min = gamma(1 + I*self.beta*t) * exp(I*self.mu*t) + return Piecewise((cf_min, self.minimum), (cf_max, not self.minimum)) + + def _moment_generating_function(self, t): + mgf_max = gamma(1 - self.beta*t) * exp(self.mu*t) + mgf_min = gamma(1 + self.beta*t) * exp(self.mu*t) + return Piecewise((mgf_min, self.minimum), (mgf_max, not self.minimum)) + +def Gumbel(name, beta, mu, minimum=False): + r""" + Create a Continuous Random Variable with Gumbel distribution. + + Explanation + =========== + + The density of the Gumbel distribution is given by + + For Maximum + + .. math:: + f(x) := \dfrac{1}{\beta} \exp \left( -\dfrac{x-\mu}{\beta} + - \exp \left( -\dfrac{x - \mu}{\beta} \right) \right) + + with :math:`x \in [ - \infty, \infty ]`. + + For Minimum + + .. math:: + f(x) := \frac{e^{- e^{\frac{- \mu + x}{\beta}} + \frac{- \mu + x}{\beta}}}{\beta} + + with :math:`x \in [ - \infty, \infty ]`. + + Parameters + ========== + + mu : Real number, `\mu`, a location + beta : Real number, `\beta > 0`, a scale + minimum : Boolean, by default ``False``, set to ``True`` for enabling minimum distribution + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Gumbel, density, cdf + >>> from sympy import Symbol + >>> x = Symbol("x") + >>> mu = Symbol("mu") + >>> beta = Symbol("beta", positive=True) + >>> X = Gumbel("x", beta, mu) + >>> density(X)(x) + exp(-exp(-(-mu + x)/beta) - (-mu + x)/beta)/beta + >>> cdf(X)(x) + exp(-exp(-(-mu + x)/beta)) + + References + ========== + + .. [1] https://mathworld.wolfram.com/GumbelDistribution.html + .. [2] https://en.wikipedia.org/wiki/Gumbel_distribution + .. [3] https://web.archive.org/web/20200628222206/http://www.mathwave.com/help/easyfit/html/analyses/distributions/gumbel_max.html + .. [4] https://web.archive.org/web/20200628222212/http://www.mathwave.com/help/easyfit/html/analyses/distributions/gumbel_min.html + + """ + return rv(name, GumbelDistribution, (beta, mu, minimum)) + +#------------------------------------------------------------------------------- +# Gompertz distribution -------------------------------------------------------- + +class GompertzDistribution(SingleContinuousDistribution): + _argnames = ('b', 'eta') + + set = Interval(0, oo) + + @staticmethod + def check(b, eta): + _value_check(b > 0, "b must be positive") + _value_check(eta > 0, "eta must be positive") + + def pdf(self, x): + eta, b = self.eta, self.b + return b*eta*exp(b*x)*exp(eta)*exp(-eta*exp(b*x)) + + def _cdf(self, x): + eta, b = self.eta, self.b + return 1 - exp(eta)*exp(-eta*exp(b*x)) + + def _moment_generating_function(self, t): + eta, b = self.eta, self.b + return eta * exp(eta) * expint(t/b, eta) + +def Gompertz(name, b, eta): + r""" + Create a Continuous Random Variable with Gompertz distribution. + + Explanation + =========== + + The density of the Gompertz distribution is given by + + .. math:: + f(x) := b \eta e^{b x} e^{\eta} \exp \left(-\eta e^{bx} \right) + + with :math:`x \in [0, \infty)`. + + Parameters + ========== + + b : Real number, `b > 0`, a scale + eta : Real number, `\eta > 0`, a shape + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Gompertz, density + >>> from sympy import Symbol + + >>> b = Symbol("b", positive=True) + >>> eta = Symbol("eta", positive=True) + >>> z = Symbol("z") + + >>> X = Gompertz("x", b, eta) + + >>> density(X)(z) + b*eta*exp(eta)*exp(b*z)*exp(-eta*exp(b*z)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gompertz_distribution + + """ + return rv(name, GompertzDistribution, (b, eta)) + +#------------------------------------------------------------------------------- +# Kumaraswamy distribution ----------------------------------------------------- + + +class KumaraswamyDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + set = Interval(0, oo) + + @staticmethod + def check(a, b): + _value_check(a > 0, "a must be positive") + _value_check(b > 0, "b must be positive") + + def pdf(self, x): + a, b = self.a, self.b + return a * b * x**(a-1) * (1-x**a)**(b-1) + + def _cdf(self, x): + a, b = self.a, self.b + return Piecewise( + (S.Zero, x < S.Zero), + (1 - (1 - x**a)**b, x <= S.One), + (S.One, True)) + +def Kumaraswamy(name, a, b): + r""" + Create a Continuous Random Variable with a Kumaraswamy distribution. + + Explanation + =========== + + The density of the Kumaraswamy distribution is given by + + .. math:: + f(x) := a b x^{a-1} (1-x^a)^{b-1} + + with :math:`x \in [0,1]`. + + Parameters + ========== + + a : Real number, `a > 0`, a shape + b : Real number, `b > 0`, a shape + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Kumaraswamy, density, cdf + >>> from sympy import Symbol, pprint + + >>> a = Symbol("a", positive=True) + >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") + + >>> X = Kumaraswamy("x", a, b) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + b - 1 + a - 1 / a\ + a*b*z *\1 - z / + + >>> cdf(X)(z) + Piecewise((0, z < 0), (1 - (1 - z**a)**b, z <= 1), (1, True)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Kumaraswamy_distribution + + """ + + return rv(name, KumaraswamyDistribution, (a, b)) + +#------------------------------------------------------------------------------- +# Laplace distribution --------------------------------------------------------- + + +class LaplaceDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'b') + + set = Interval(-oo, oo) + + @staticmethod + def check(mu, b): + _value_check(b > 0, "Scale parameter b must be positive.") + _value_check(mu.is_real, "Location parameter mu should be real") + + def pdf(self, x): + mu, b = self.mu, self.b + return 1/(2*b)*exp(-Abs(x - mu)/b) + + def _cdf(self, x): + mu, b = self.mu, self.b + return Piecewise( + (S.Half*exp((x - mu)/b), x < mu), + (S.One - S.Half*exp(-(x - mu)/b), x >= mu) + ) + + def _characteristic_function(self, t): + return exp(self.mu*I*t) / (1 + self.b**2*t**2) + + def _moment_generating_function(self, t): + return exp(self.mu*t) / (1 - self.b**2*t**2) + +def Laplace(name, mu, b): + r""" + Create a continuous random variable with a Laplace distribution. + + Explanation + =========== + + The density of the Laplace distribution is given by + + .. math:: + f(x) := \frac{1}{2 b} \exp \left(-\frac{|x-\mu|}b \right) + + Parameters + ========== + + mu : Real number or a list/matrix, the location (mean) or the + location vector + b : Real number or a positive definite matrix, representing a scale + or the covariance matrix. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Laplace, density, cdf + >>> from sympy import Symbol, pprint + + >>> mu = Symbol("mu") + >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") + + >>> X = Laplace("x", mu, b) + + >>> density(X)(z) + exp(-Abs(mu - z)/b)/(2*b) + + >>> cdf(X)(z) + Piecewise((exp((-mu + z)/b)/2, mu > z), (1 - exp((mu - z)/b)/2, True)) + + >>> L = Laplace('L', [1, 2], [[1, 0], [0, 1]]) + >>> pprint(density(L)(1, 2), use_unicode=False) + 5 / ____\ + e *besselk\0, \/ 35 / + --------------------- + pi + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Laplace_distribution + .. [2] https://mathworld.wolfram.com/LaplaceDistribution.html + + """ + + if isinstance(mu, (list, MatrixBase)) and\ + isinstance(b, (list, MatrixBase)): + from sympy.stats.joint_rv_types import MultivariateLaplace + return MultivariateLaplace(name, mu, b) + + return rv(name, LaplaceDistribution, (mu, b)) + +#------------------------------------------------------------------------------- +# Levy distribution --------------------------------------------------------- + + +class LevyDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'c') + + @property + def set(self): + return Interval(self.mu, oo) + + @staticmethod + def check(mu, c): + _value_check(c > 0, "c (scale parameter) must be positive") + _value_check(mu.is_real, "mu (location parameter) must be real") + + def pdf(self, x): + mu, c = self.mu, self.c + return sqrt(c/(2*pi))*exp(-c/(2*(x - mu)))/((x - mu)**(S.One + S.Half)) + + def _cdf(self, x): + mu, c = self.mu, self.c + return erfc(sqrt(c/(2*(x - mu)))) + + def _characteristic_function(self, t): + mu, c = self.mu, self.c + return exp(I * mu * t - sqrt(-2 * I * c * t)) + + def _moment_generating_function(self, t): + raise NotImplementedError('The moment generating function of Levy distribution does not exist.') + +def Levy(name, mu, c): + r""" + Create a continuous random variable with a Levy distribution. + + The density of the Levy distribution is given by + + .. math:: + f(x) := \sqrt(\frac{c}{2 \pi}) \frac{\exp -\frac{c}{2 (x - \mu)}}{(x - \mu)^{3/2}} + + Parameters + ========== + + mu : Real number + The location parameter. + c : Real number, `c > 0` + A scale parameter. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Levy, density, cdf + >>> from sympy import Symbol + + >>> mu = Symbol("mu", real=True) + >>> c = Symbol("c", positive=True) + >>> z = Symbol("z") + + >>> X = Levy("x", mu, c) + + >>> density(X)(z) + sqrt(2)*sqrt(c)*exp(-c/(-2*mu + 2*z))/(2*sqrt(pi)*(-mu + z)**(3/2)) + + >>> cdf(X)(z) + erfc(sqrt(c)*sqrt(1/(-2*mu + 2*z))) + + References + ========== + .. [1] https://en.wikipedia.org/wiki/L%C3%A9vy_distribution + .. [2] https://mathworld.wolfram.com/LevyDistribution.html + """ + + return rv(name, LevyDistribution, (mu, c)) + +#------------------------------------------------------------------------------- +# Log-Cauchy distribution -------------------------------------------------------- + + +class LogCauchyDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'sigma') + + set = Interval.open(0, oo) + + @staticmethod + def check(mu, sigma): + _value_check((sigma > 0) != False, "Scale parameter Gamma must be positive.") + _value_check(mu.is_real != False, "Location parameter must be real.") + + def pdf(self, x): + mu, sigma = self.mu, self.sigma + return 1/(x*pi)*(sigma/((log(x) - mu)**2 + sigma**2)) + + def _cdf(self, x): + mu, sigma = self.mu, self.sigma + return (1/pi)*atan((log(x) - mu)/sigma) + S.Half + + def _characteristic_function(self, t): + raise NotImplementedError("The characteristic function for the " + "Log-Cauchy distribution does not exist.") + + def _moment_generating_function(self, t): + raise NotImplementedError("The moment generating function for the " + "Log-Cauchy distribution does not exist.") + +def LogCauchy(name, mu, sigma): + r""" + Create a continuous random variable with a Log-Cauchy distribution. + The density of the Log-Cauchy distribution is given by + + .. math:: + f(x) := \frac{1}{\pi x} \frac{\sigma}{(log(x)-\mu^2) + \sigma^2} + + Parameters + ========== + + mu : Real number, the location + + sigma : Real number, `\sigma > 0`, a scale + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import LogCauchy, density, cdf + >>> from sympy import Symbol, S + + >>> mu = 2 + >>> sigma = S.One / 5 + >>> z = Symbol("z") + + >>> X = LogCauchy("x", mu, sigma) + + >>> density(X)(z) + 1/(5*pi*z*((log(z) - 2)**2 + 1/25)) + + >>> cdf(X)(z) + atan(5*log(z) - 10)/pi + 1/2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Log-Cauchy_distribution + """ + + return rv(name, LogCauchyDistribution, (mu, sigma)) + + +#------------------------------------------------------------------------------- +# Logistic distribution -------------------------------------------------------- + + +class LogisticDistribution(SingleContinuousDistribution): + _argnames = ('mu', 's') + + set = Interval(-oo, oo) + + @staticmethod + def check(mu, s): + _value_check(s > 0, "Scale parameter s must be positive.") + + def pdf(self, x): + mu, s = self.mu, self.s + return exp(-(x - mu)/s)/(s*(1 + exp(-(x - mu)/s))**2) + + def _cdf(self, x): + mu, s = self.mu, self.s + return S.One/(1 + exp(-(x - mu)/s)) + + def _characteristic_function(self, t): + return Piecewise((exp(I*t*self.mu) * pi*self.s*t / sinh(pi*self.s*t), Ne(t, 0)), (S.One, True)) + + def _moment_generating_function(self, t): + return exp(self.mu*t) * beta_fn(1 - self.s*t, 1 + self.s*t) + + def _quantile(self, p): + return self.mu - self.s*log(-S.One + S.One/p) + +def Logistic(name, mu, s): + r""" + Create a continuous random variable with a logistic distribution. + + Explanation + =========== + + The density of the logistic distribution is given by + + .. math:: + f(x) := \frac{e^{-(x-\mu)/s}} {s\left(1+e^{-(x-\mu)/s}\right)^2} + + Parameters + ========== + + mu : Real number, the location (mean) + s : Real number, `s > 0`, a scale + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Logistic, density, cdf + >>> from sympy import Symbol + + >>> mu = Symbol("mu", real=True) + >>> s = Symbol("s", positive=True) + >>> z = Symbol("z") + + >>> X = Logistic("x", mu, s) + + >>> density(X)(z) + exp((mu - z)/s)/(s*(exp((mu - z)/s) + 1)**2) + + >>> cdf(X)(z) + 1/(exp((mu - z)/s) + 1) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Logistic_distribution + .. [2] https://mathworld.wolfram.com/LogisticDistribution.html + + """ + + return rv(name, LogisticDistribution, (mu, s)) + +#------------------------------------------------------------------------------- +# Log-logistic distribution -------------------------------------------------------- + + +class LogLogisticDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta') + + set = Interval(0, oo) + + @staticmethod + def check(alpha, beta): + _value_check(alpha > 0, "Scale parameter Alpha must be positive.") + _value_check(beta > 0, "Shape parameter Beta must be positive.") + + def pdf(self, x): + a, b = self.alpha, self.beta + return ((b/a)*(x/a)**(b - 1))/(1 + (x/a)**b)**2 + + def _cdf(self, x): + a, b = self.alpha, self.beta + return 1/(1 + (x/a)**(-b)) + + def _quantile(self, p): + a, b = self.alpha, self.beta + return a*((p/(1 - p))**(1/b)) + + def expectation(self, expr, var, **kwargs): + a, b = self.args + return Piecewise((S.NaN, b <= 1), (pi*a/(b*sin(pi/b)), True)) + +def LogLogistic(name, alpha, beta): + r""" + Create a continuous random variable with a log-logistic distribution. + The distribution is unimodal when ``beta > 1``. + + Explanation + =========== + + The density of the log-logistic distribution is given by + + .. math:: + f(x) := \frac{(\frac{\beta}{\alpha})(\frac{x}{\alpha})^{\beta - 1}} + {(1 + (\frac{x}{\alpha})^{\beta})^2} + + Parameters + ========== + + alpha : Real number, `\alpha > 0`, scale parameter and median of distribution + beta : Real number, `\beta > 0`, a shape parameter + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import LogLogistic, density, cdf, quantile + >>> from sympy import Symbol, pprint + + >>> alpha = Symbol("alpha", positive=True) + >>> beta = Symbol("beta", positive=True) + >>> p = Symbol("p") + >>> z = Symbol("z", positive=True) + + >>> X = LogLogistic("x", alpha, beta) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + beta - 1 + / z \ + beta*|-----| + \alpha/ + ------------------------ + 2 + / beta \ + |/ z \ | + alpha*||-----| + 1| + \\alpha/ / + + >>> cdf(X)(z) + 1/(1 + (z/alpha)**(-beta)) + + >>> quantile(X)(p) + alpha*(p/(1 - p))**(1/beta) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Log-logistic_distribution + + """ + + return rv(name, LogLogisticDistribution, (alpha, beta)) + +#------------------------------------------------------------------------------- +#Logit-Normal distribution------------------------------------------------------ + +class LogitNormalDistribution(SingleContinuousDistribution): + _argnames = ('mu', 's') + set = Interval.open(0, 1) + + @staticmethod + def check(mu, s): + _value_check((s ** 2).is_real is not False and s ** 2 > 0, "Squared scale parameter s must be positive.") + _value_check(mu.is_real is not False, "Location parameter must be real") + + def _logit(self, x): + return log(x / (1 - x)) + + def pdf(self, x): + mu, s = self.mu, self.s + return exp(-(self._logit(x) - mu)**2/(2*s**2))*(S.One/sqrt(2*pi*(s**2)))*(1/(x*(1 - x))) + + def _cdf(self, x): + mu, s = self.mu, self.s + return (S.One/2)*(1 + erf((self._logit(x) - mu)/(sqrt(2*s**2)))) + + +def LogitNormal(name, mu, s): + r""" + Create a continuous random variable with a Logit-Normal distribution. + + The density of the logistic distribution is given by + + .. math:: + f(x) := \frac{1}{s \sqrt{2 \pi}} \frac{1}{x(1 - x)} e^{- \frac{(logit(x) - \mu)^2}{s^2}} + where logit(x) = \log(\frac{x}{1 - x}) + Parameters + ========== + + mu : Real number, the location (mean) + s : Real number, `s > 0`, a scale + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import LogitNormal, density, cdf + >>> from sympy import Symbol,pprint + + >>> mu = Symbol("mu", real=True) + >>> s = Symbol("s", positive=True) + >>> z = Symbol("z") + >>> X = LogitNormal("x",mu,s) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + 2 + / / z \\ + -|-mu + log|-----|| + \ \1 - z// + --------------------- + 2 + ___ 2*s + \/ 2 *e + ---------------------------- + ____ + 2*\/ pi *s*z*(1 - z) + + >>> density(X)(z) + sqrt(2)*exp(-(-mu + log(z/(1 - z)))**2/(2*s**2))/(2*sqrt(pi)*s*z*(1 - z)) + + >>> cdf(X)(z) + erf(sqrt(2)*(-mu + log(z/(1 - z)))/(2*s))/2 + 1/2 + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Logit-normal_distribution + + """ + + return rv(name, LogitNormalDistribution, (mu, s)) + +#------------------------------------------------------------------------------- +# Log Normal distribution ------------------------------------------------------ + + +class LogNormalDistribution(SingleContinuousDistribution): + _argnames = ('mean', 'std') + + set = Interval(0, oo) + + @staticmethod + def check(mean, std): + _value_check(std > 0, "Parameter std must be positive.") + + def pdf(self, x): + mean, std = self.mean, self.std + return exp(-(log(x) - mean)**2 / (2*std**2)) / (x*sqrt(2*pi)*std) + + def _cdf(self, x): + mean, std = self.mean, self.std + return Piecewise( + (S.Half + S.Half*erf((log(x) - mean)/sqrt(2)/std), x > 0), + (S.Zero, True) + ) + + def _moment_generating_function(self, t): + raise NotImplementedError('Moment generating function of the log-normal distribution is not defined.') + + +def LogNormal(name, mean, std): + r""" + Create a continuous random variable with a log-normal distribution. + + Explanation + =========== + + The density of the log-normal distribution is given by + + .. math:: + f(x) := \frac{1}{x\sqrt{2\pi\sigma^2}} + e^{-\frac{\left(\ln x-\mu\right)^2}{2\sigma^2}} + + with :math:`x \geq 0`. + + Parameters + ========== + + mu : Real number + The log-scale. + sigma : Real number + A shape. ($\sigma^2 > 0$) + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import LogNormal, density + >>> from sympy import Symbol, pprint + + >>> mu = Symbol("mu", real=True) + >>> sigma = Symbol("sigma", positive=True) + >>> z = Symbol("z") + + >>> X = LogNormal("x", mu, sigma) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + 2 + -(-mu + log(z)) + ----------------- + 2 + ___ 2*sigma + \/ 2 *e + ------------------------ + ____ + 2*\/ pi *sigma*z + + + >>> X = LogNormal('x', 0, 1) # Mean 0, standard deviation 1 + + >>> density(X)(z) + sqrt(2)*exp(-log(z)**2/2)/(2*sqrt(pi)*z) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Lognormal + .. [2] https://mathworld.wolfram.com/LogNormalDistribution.html + + """ + + return rv(name, LogNormalDistribution, (mean, std)) + +#------------------------------------------------------------------------------- +# Lomax Distribution ----------------------------------------------------------- + +class LomaxDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'lamda',) + set = Interval(0, oo) + + @staticmethod + def check(alpha, lamda): + _value_check(alpha.is_real, "Shape parameter should be real.") + _value_check(lamda.is_real, "Scale parameter should be real.") + _value_check(alpha.is_positive, "Shape parameter should be positive.") + _value_check(lamda.is_positive, "Scale parameter should be positive.") + + def pdf(self, x): + lamba, alpha = self.lamda, self.alpha + return (alpha/lamba) * (S.One + x/lamba)**(-alpha-1) + +def Lomax(name, alpha, lamda): + r""" + Create a continuous random variable with a Lomax distribution. + + Explanation + =========== + + The density of the Lomax distribution is given by + + .. math:: + f(x) := \frac{\alpha}{\lambda}\left[1+\frac{x}{\lambda}\right]^{-(\alpha+1)} + + Parameters + ========== + + alpha : Real Number, `\alpha > 0` + Shape parameter + lamda : Real Number, `\lambda > 0` + Scale parameter + + Examples + ======== + + >>> from sympy.stats import Lomax, density, cdf, E + >>> from sympy import symbols + >>> a, l = symbols('a, l', positive=True) + >>> X = Lomax('X', a, l) + >>> x = symbols('x') + >>> density(X)(x) + a*(1 + x/l)**(-a - 1)/l + >>> cdf(X)(x) + Piecewise((1 - 1/(1 + x/l)**a, x >= 0), (0, True)) + >>> a = 2 + >>> X = Lomax('X', a, l) + >>> E(X) + l + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Lomax_distribution + + """ + return rv(name, LomaxDistribution, (alpha, lamda)) + +#------------------------------------------------------------------------------- +# Maxwell distribution --------------------------------------------------------- + + +class MaxwellDistribution(SingleContinuousDistribution): + _argnames = ('a',) + + set = Interval(0, oo) + + @staticmethod + def check(a): + _value_check(a > 0, "Parameter a must be positive.") + + def pdf(self, x): + a = self.a + return sqrt(2/pi)*x**2*exp(-x**2/(2*a**2))/a**3 + + def _cdf(self, x): + a = self.a + return erf(sqrt(2)*x/(2*a)) - sqrt(2)*x*exp(-x**2/(2*a**2))/(sqrt(pi)*a) + +def Maxwell(name, a): + r""" + Create a continuous random variable with a Maxwell distribution. + + Explanation + =========== + + The density of the Maxwell distribution is given by + + .. math:: + f(x) := \sqrt{\frac{2}{\pi}} \frac{x^2 e^{-x^2/(2a^2)}}{a^3} + + with :math:`x \geq 0`. + + .. TODO - what does the parameter mean? + + Parameters + ========== + + a : Real number, `a > 0` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Maxwell, density, E, variance + >>> from sympy import Symbol, simplify + + >>> a = Symbol("a", positive=True) + >>> z = Symbol("z") + + >>> X = Maxwell("x", a) + + >>> density(X)(z) + sqrt(2)*z**2*exp(-z**2/(2*a**2))/(sqrt(pi)*a**3) + + >>> E(X) + 2*sqrt(2)*a/sqrt(pi) + + >>> simplify(variance(X)) + a**2*(-8 + 3*pi)/pi + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Maxwell_distribution + .. [2] https://mathworld.wolfram.com/MaxwellDistribution.html + + """ + + return rv(name, MaxwellDistribution, (a, )) + +#------------------------------------------------------------------------------- +# Moyal Distribution ----------------------------------------------------------- +class MoyalDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'sigma') + + @staticmethod + def check(mu, sigma): + _value_check(mu.is_real, "Location parameter must be real.") + _value_check(sigma.is_real and sigma > 0, "Scale parameter must be real\ + and positive.") + + def pdf(self, x): + mu, sigma = self.mu, self.sigma + num = exp(-(exp(-(x - mu)/sigma) + (x - mu)/(sigma))/2) + den = (sqrt(2*pi) * sigma) + return num/den + + def _characteristic_function(self, t): + mu, sigma = self.mu, self.sigma + term1 = exp(I*t*mu) + term2 = (2**(-I*sigma*t) * gamma(Rational(1, 2) - I*t*sigma)) + return (term1 * term2)/sqrt(pi) + + def _moment_generating_function(self, t): + mu, sigma = self.mu, self.sigma + term1 = exp(t*mu) + term2 = (2**(-1*sigma*t) * gamma(Rational(1, 2) - t*sigma)) + return (term1 * term2)/sqrt(pi) + +def Moyal(name, mu, sigma): + r""" + Create a continuous random variable with a Moyal distribution. + + Explanation + =========== + + The density of the Moyal distribution is given by + + .. math:: + f(x) := \frac{\exp-\frac{1}{2}\exp-\frac{x-\mu}{\sigma}-\frac{x-\mu}{2\sigma}}{\sqrt{2\pi}\sigma} + + with :math:`x \in \mathbb{R}`. + + Parameters + ========== + + mu : Real number + Location parameter + sigma : Real positive number + Scale parameter + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Moyal, density, cdf + >>> from sympy import Symbol, simplify + >>> mu = Symbol("mu", real=True) + >>> sigma = Symbol("sigma", positive=True, real=True) + >>> z = Symbol("z") + >>> X = Moyal("x", mu, sigma) + >>> density(X)(z) + sqrt(2)*exp(-exp((mu - z)/sigma)/2 - (-mu + z)/(2*sigma))/(2*sqrt(pi)*sigma) + >>> simplify(cdf(X)(z)) + 1 - erf(sqrt(2)*exp((mu - z)/(2*sigma))/2) + + References + ========== + + .. [1] https://reference.wolfram.com/language/ref/MoyalDistribution.html + .. [2] https://www.stat.rice.edu/~dobelman/textfiles/DistributionsHandbook.pdf + + """ + + return rv(name, MoyalDistribution, (mu, sigma)) + +#------------------------------------------------------------------------------- +# Nakagami distribution -------------------------------------------------------- + + +class NakagamiDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'omega') + + set = Interval(0, oo) + + @staticmethod + def check(mu, omega): + _value_check(mu >= S.Half, "Shape parameter mu must be greater than equal to 1/2.") + _value_check(omega > 0, "Spread parameter omega must be positive.") + + def pdf(self, x): + mu, omega = self.mu, self.omega + return 2*mu**mu/(gamma(mu)*omega**mu)*x**(2*mu - 1)*exp(-mu/omega*x**2) + + def _cdf(self, x): + mu, omega = self.mu, self.omega + return Piecewise( + (lowergamma(mu, (mu/omega)*x**2)/gamma(mu), x > 0), + (S.Zero, True)) + +def Nakagami(name, mu, omega): + r""" + Create a continuous random variable with a Nakagami distribution. + + Explanation + =========== + + The density of the Nakagami distribution is given by + + .. math:: + f(x) := \frac{2\mu^\mu}{\Gamma(\mu)\omega^\mu} x^{2\mu-1} + \exp\left(-\frac{\mu}{\omega}x^2 \right) + + with :math:`x > 0`. + + Parameters + ========== + + mu : Real number, `\mu \geq \frac{1}{2}`, a shape + omega : Real number, `\omega > 0`, the spread + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Nakagami, density, E, variance, cdf + >>> from sympy import Symbol, simplify, pprint + + >>> mu = Symbol("mu", positive=True) + >>> omega = Symbol("omega", positive=True) + >>> z = Symbol("z") + + >>> X = Nakagami("x", mu, omega) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + 2 + -mu*z + ------- + mu -mu 2*mu - 1 omega + 2*mu *omega *z *e + ---------------------------------- + Gamma(mu) + + >>> simplify(E(X)) + sqrt(mu)*sqrt(omega)*gamma(mu + 1/2)/gamma(mu + 1) + + >>> V = simplify(variance(X)) + >>> pprint(V, use_unicode=False) + 2 + omega*Gamma (mu + 1/2) + omega - ----------------------- + Gamma(mu)*Gamma(mu + 1) + + >>> cdf(X)(z) + Piecewise((lowergamma(mu, mu*z**2/omega)/gamma(mu), z > 0), + (0, True)) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Nakagami_distribution + + """ + + return rv(name, NakagamiDistribution, (mu, omega)) + +#------------------------------------------------------------------------------- +# Normal distribution ---------------------------------------------------------- + + +class NormalDistribution(SingleContinuousDistribution): + _argnames = ('mean', 'std') + + @staticmethod + def check(mean, std): + _value_check(std > 0, "Standard deviation must be positive") + + def pdf(self, x): + return exp(-(x - self.mean)**2 / (2*self.std**2)) / (sqrt(2*pi)*self.std) + + def _cdf(self, x): + mean, std = self.mean, self.std + return erf(sqrt(2)*(-mean + x)/(2*std))/2 + S.Half + + def _characteristic_function(self, t): + mean, std = self.mean, self.std + return exp(I*mean*t - std**2*t**2/2) + + def _moment_generating_function(self, t): + mean, std = self.mean, self.std + return exp(mean*t + std**2*t**2/2) + + def _quantile(self, p): + mean, std = self.mean, self.std + return mean + std*sqrt(2)*erfinv(2*p - 1) + + +def Normal(name, mean, std): + r""" + Create a continuous random variable with a Normal distribution. + + Explanation + =========== + + The density of the Normal distribution is given by + + .. math:: + f(x) := \frac{1}{\sigma\sqrt{2\pi}} e^{ -\frac{(x-\mu)^2}{2\sigma^2} } + + Parameters + ========== + + mu : Real number or a list representing the mean or the mean vector + sigma : Real number or a positive definite square matrix, + :math:`\sigma^2 > 0`, the variance + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Normal, density, E, std, cdf, skewness, quantile, marginal_distribution + >>> from sympy import Symbol, simplify, pprint + + >>> mu = Symbol("mu") + >>> sigma = Symbol("sigma", positive=True) + >>> z = Symbol("z") + >>> y = Symbol("y") + >>> p = Symbol("p") + >>> X = Normal("x", mu, sigma) + + >>> density(X)(z) + sqrt(2)*exp(-(-mu + z)**2/(2*sigma**2))/(2*sqrt(pi)*sigma) + + >>> C = simplify(cdf(X))(z) # it needs a little more help... + >>> pprint(C, use_unicode=False) + / ___ \ + |\/ 2 *(-mu + z)| + erf|---------------| + \ 2*sigma / 1 + -------------------- + - + 2 2 + + >>> quantile(X)(p) + mu + sqrt(2)*sigma*erfinv(2*p - 1) + + >>> simplify(skewness(X)) + 0 + + >>> X = Normal("x", 0, 1) # Mean 0, standard deviation 1 + >>> density(X)(z) + sqrt(2)*exp(-z**2/2)/(2*sqrt(pi)) + + >>> E(2*X + 1) + 1 + + >>> simplify(std(2*X + 1)) + 2 + + >>> m = Normal('X', [1, 2], [[2, 1], [1, 2]]) + >>> pprint(density(m)(y, z), use_unicode=False) + 2 2 + y y*z z + - -- + --- - -- + z - 1 + ___ 3 3 3 + \/ 3 *e + ------------------------------ + 6*pi + + >>> marginal_distribution(m, m[0])(1) + 1/(2*sqrt(pi)) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Normal_distribution + .. [2] https://mathworld.wolfram.com/NormalDistributionFunction.html + + """ + + if isinstance(mean, list) or getattr(mean, 'is_Matrix', False) and\ + isinstance(std, list) or getattr(std, 'is_Matrix', False): + from sympy.stats.joint_rv_types import MultivariateNormal + return MultivariateNormal(name, mean, std) + return rv(name, NormalDistribution, (mean, std)) + + +#------------------------------------------------------------------------------- +# Inverse Gaussian distribution ---------------------------------------------------------- + + +class GaussianInverseDistribution(SingleContinuousDistribution): + _argnames = ('mean', 'shape') + + @property + def set(self): + return Interval(0, oo) + + @staticmethod + def check(mean, shape): + _value_check(shape > 0, "Shape parameter must be positive") + _value_check(mean > 0, "Mean must be positive") + + def pdf(self, x): + mu, s = self.mean, self.shape + return exp(-s*(x - mu)**2 / (2*x*mu**2)) * sqrt(s/(2*pi*x**3)) + + def _cdf(self, x): + from sympy.stats import cdf + mu, s = self.mean, self.shape + stdNormalcdf = cdf(Normal('x', 0, 1)) + + first_term = stdNormalcdf(sqrt(s/x) * ((x/mu) - S.One)) + second_term = exp(2*s/mu) * stdNormalcdf(-sqrt(s/x)*(x/mu + S.One)) + + return first_term + second_term + + def _characteristic_function(self, t): + mu, s = self.mean, self.shape + return exp((s/mu)*(1 - sqrt(1 - (2*mu**2*I*t)/s))) + + def _moment_generating_function(self, t): + mu, s = self.mean, self.shape + return exp((s/mu)*(1 - sqrt(1 - (2*mu**2*t)/s))) + + +def GaussianInverse(name, mean, shape): + r""" + Create a continuous random variable with an Inverse Gaussian distribution. + Inverse Gaussian distribution is also known as Wald distribution. + + Explanation + =========== + + The density of the Inverse Gaussian distribution is given by + + .. math:: + f(x) := \sqrt{\frac{\lambda}{2\pi x^3}} e^{-\frac{\lambda(x-\mu)^2}{2x\mu^2}} + + Parameters + ========== + + mu : + Positive number representing the mean. + lambda : + Positive number representing the shape parameter. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import GaussianInverse, density, E, std, skewness + >>> from sympy import Symbol, pprint + + >>> mu = Symbol("mu", positive=True) + >>> lamda = Symbol("lambda", positive=True) + >>> z = Symbol("z", positive=True) + >>> X = GaussianInverse("x", mu, lamda) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + 2 + -lambda*(-mu + z) + ------------------- + 2 + ___ ________ 2*mu *z + \/ 2 *\/ lambda *e + ------------------------------------- + ____ 3/2 + 2*\/ pi *z + + >>> E(X) + mu + + >>> std(X).expand() + mu**(3/2)/sqrt(lambda) + + >>> skewness(X).expand() + 3*sqrt(mu)/sqrt(lambda) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Inverse_Gaussian_distribution + .. [2] https://mathworld.wolfram.com/InverseGaussianDistribution.html + + """ + + return rv(name, GaussianInverseDistribution, (mean, shape)) + +Wald = GaussianInverse + +#------------------------------------------------------------------------------- +# Pareto distribution ---------------------------------------------------------- + + +class ParetoDistribution(SingleContinuousDistribution): + _argnames = ('xm', 'alpha') + + @property + def set(self): + return Interval(self.xm, oo) + + @staticmethod + def check(xm, alpha): + _value_check(xm > 0, "Xm must be positive") + _value_check(alpha > 0, "Alpha must be positive") + + def pdf(self, x): + xm, alpha = self.xm, self.alpha + return alpha * xm**alpha / x**(alpha + 1) + + def _cdf(self, x): + xm, alpha = self.xm, self.alpha + return Piecewise( + (S.One - xm**alpha/x**alpha, x>=xm), + (0, True), + ) + + def _moment_generating_function(self, t): + xm, alpha = self.xm, self.alpha + return alpha * (-xm*t)**alpha * uppergamma(-alpha, -xm*t) + + def _characteristic_function(self, t): + xm, alpha = self.xm, self.alpha + return alpha * (-I * xm * t) ** alpha * uppergamma(-alpha, -I * xm * t) + + +def Pareto(name, xm, alpha): + r""" + Create a continuous random variable with the Pareto distribution. + + Explanation + =========== + + The density of the Pareto distribution is given by + + .. math:: + f(x) := \frac{\alpha\,x_m^\alpha}{x^{\alpha+1}} + + with :math:`x \in [x_m,\infty]`. + + Parameters + ========== + + xm : Real number, `x_m > 0`, a scale + alpha : Real number, `\alpha > 0`, a shape + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Pareto, density + >>> from sympy import Symbol + + >>> xm = Symbol("xm", positive=True) + >>> beta = Symbol("beta", positive=True) + >>> z = Symbol("z") + + >>> X = Pareto("x", xm, beta) + + >>> density(X)(z) + beta*xm**beta*z**(-beta - 1) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Pareto_distribution + .. [2] https://mathworld.wolfram.com/ParetoDistribution.html + + """ + + return rv(name, ParetoDistribution, (xm, alpha)) + +#------------------------------------------------------------------------------- +# PowerFunction distribution --------------------------------------------------- + + +class PowerFunctionDistribution(SingleContinuousDistribution): + _argnames=('alpha','a','b') + + @property + def set(self): + return Interval(self.a, self.b) + + @staticmethod + def check(alpha, a, b): + _value_check(a.is_real, "Continuous Boundary parameter should be real.") + _value_check(b.is_real, "Continuous Boundary parameter should be real.") + _value_check(a < b, " 'a' the left Boundary must be smaller than 'b' the right Boundary." ) + _value_check(alpha.is_positive, "Continuous Shape parameter should be positive.") + + def pdf(self, x): + alpha, a, b = self.alpha, self.a, self.b + num = alpha*(x - a)**(alpha - 1) + den = (b - a)**alpha + return num/den + +def PowerFunction(name, alpha, a, b): + r""" + Creates a continuous random variable with a Power Function Distribution. + + Explanation + =========== + + The density of PowerFunction distribution is given by + + .. math:: + f(x) := \frac{{\alpha}(x - a)^{\alpha - 1}}{(b - a)^{\alpha}} + + with :math:`x \in [a,b]`. + + Parameters + ========== + + alpha : Positive number, `0 < \alpha`, the shape parameter + a : Real number, :math:`-\infty < a`, the left boundary + b : Real number, :math:`a < b < \infty`, the right boundary + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import PowerFunction, density, cdf, E, variance + >>> from sympy import Symbol + >>> alpha = Symbol("alpha", positive=True) + >>> a = Symbol("a", real=True) + >>> b = Symbol("b", real=True) + >>> z = Symbol("z") + + >>> X = PowerFunction("X", 2, a, b) + + >>> density(X)(z) + (-2*a + 2*z)/(-a + b)**2 + + >>> cdf(X)(z) + Piecewise((a**2/(a**2 - 2*a*b + b**2) - 2*a*z/(a**2 - 2*a*b + b**2) + + z**2/(a**2 - 2*a*b + b**2), a <= z), (0, True)) + + >>> alpha = 2 + >>> a = 0 + >>> b = 1 + >>> Y = PowerFunction("Y", alpha, a, b) + + >>> E(Y) + 2/3 + + >>> variance(Y) + 1/18 + + References + ========== + + .. [1] https://web.archive.org/web/20200204081320/http://www.mathwave.com/help/easyfit/html/analyses/distributions/power_func.html + + """ + return rv(name, PowerFunctionDistribution, (alpha, a, b)) + +#------------------------------------------------------------------------------- +# QuadraticU distribution ------------------------------------------------------ + + +class QuadraticUDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + @property + def set(self): + return Interval(self.a, self.b) + + @staticmethod + def check(a, b): + _value_check(b > a, "Parameter b must be in range (%s, oo)."%(a)) + + def pdf(self, x): + a, b = self.a, self.b + alpha = 12 / (b-a)**3 + beta = (a+b) / 2 + return Piecewise( + (alpha * (x-beta)**2, And(a<=x, x<=b)), + (S.Zero, True)) + + def _moment_generating_function(self, t): + a, b = self.a, self.b + return -3 * (exp(a*t) * (4 + (a**2 + 2*a*(-2 + b) + b**2) * t) \ + - exp(b*t) * (4 + (-4*b + (a + b)**2) * t)) / ((a-b)**3 * t**2) + + def _characteristic_function(self, t): + a, b = self.a, self.b + return -3*I*(exp(I*a*t*exp(I*b*t)) * (4*I - (-4*b + (a+b)**2)*t)) \ + / ((a-b)**3 * t**2) + + +def QuadraticU(name, a, b): + r""" + Create a Continuous Random Variable with a U-quadratic distribution. + + Explanation + =========== + + The density of the U-quadratic distribution is given by + + .. math:: + f(x) := \alpha (x-\beta)^2 + + with :math:`x \in [a,b]`. + + Parameters + ========== + + a : Real number + b : Real number, :math:`a < b` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import QuadraticU, density + >>> from sympy import Symbol, pprint + + >>> a = Symbol("a", real=True) + >>> b = Symbol("b", real=True) + >>> z = Symbol("z") + + >>> X = QuadraticU("x", a, b) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + / 2 + | / a b \ + |12*|- - - - + z| + | \ 2 2 / + <----------------- for And(b >= z, a <= z) + | 3 + | (-a + b) + | + \ 0 otherwise + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/U-quadratic_distribution + + """ + + return rv(name, QuadraticUDistribution, (a, b)) + +#------------------------------------------------------------------------------- +# RaisedCosine distribution ---------------------------------------------------- + + +class RaisedCosineDistribution(SingleContinuousDistribution): + _argnames = ('mu', 's') + + @property + def set(self): + return Interval(self.mu - self.s, self.mu + self.s) + + @staticmethod + def check(mu, s): + _value_check(s > 0, "s must be positive") + + def pdf(self, x): + mu, s = self.mu, self.s + return Piecewise( + ((1+cos(pi*(x-mu)/s)) / (2*s), And(mu-s<=x, x<=mu+s)), + (S.Zero, True)) + + def _characteristic_function(self, t): + mu, s = self.mu, self.s + return Piecewise((exp(-I*pi*mu/s)/2, Eq(t, -pi/s)), + (exp(I*pi*mu/s)/2, Eq(t, pi/s)), + (pi**2*sin(s*t)*exp(I*mu*t) / (s*t*(pi**2 - s**2*t**2)), True)) + + def _moment_generating_function(self, t): + mu, s = self.mu, self.s + return pi**2 * sinh(s*t) * exp(mu*t) / (s*t*(pi**2 + s**2*t**2)) + +def RaisedCosine(name, mu, s): + r""" + Create a Continuous Random Variable with a raised cosine distribution. + + Explanation + =========== + + The density of the raised cosine distribution is given by + + .. math:: + f(x) := \frac{1}{2s}\left(1+\cos\left(\frac{x-\mu}{s}\pi\right)\right) + + with :math:`x \in [\mu-s,\mu+s]`. + + Parameters + ========== + + mu : Real number + s : Real number, `s > 0` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import RaisedCosine, density + >>> from sympy import Symbol, pprint + + >>> mu = Symbol("mu", real=True) + >>> s = Symbol("s", positive=True) + >>> z = Symbol("z") + + >>> X = RaisedCosine("x", mu, s) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + / /pi*(-mu + z)\ + |cos|------------| + 1 + | \ s / + <--------------------- for And(z >= mu - s, z <= mu + s) + | 2*s + | + \ 0 otherwise + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Raised_cosine_distribution + + """ + + return rv(name, RaisedCosineDistribution, (mu, s)) + +#------------------------------------------------------------------------------- +# Rayleigh distribution -------------------------------------------------------- + + +class RayleighDistribution(SingleContinuousDistribution): + _argnames = ('sigma',) + + set = Interval(0, oo) + + @staticmethod + def check(sigma): + _value_check(sigma > 0, "Scale parameter sigma must be positive.") + + def pdf(self, x): + sigma = self.sigma + return x/sigma**2*exp(-x**2/(2*sigma**2)) + + def _cdf(self, x): + sigma = self.sigma + return 1 - exp(-(x**2/(2*sigma**2))) + + def _characteristic_function(self, t): + sigma = self.sigma + return 1 - sigma*t*exp(-sigma**2*t**2/2) * sqrt(pi/2) * (erfi(sigma*t/sqrt(2)) - I) + + def _moment_generating_function(self, t): + sigma = self.sigma + return 1 + sigma*t*exp(sigma**2*t**2/2) * sqrt(pi/2) * (erf(sigma*t/sqrt(2)) + 1) + + +def Rayleigh(name, sigma): + r""" + Create a continuous random variable with a Rayleigh distribution. + + Explanation + =========== + + The density of the Rayleigh distribution is given by + + .. math :: + f(x) := \frac{x}{\sigma^2} e^{-x^2/2\sigma^2} + + with :math:`x > 0`. + + Parameters + ========== + + sigma : Real number, `\sigma > 0` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Rayleigh, density, E, variance + >>> from sympy import Symbol + + >>> sigma = Symbol("sigma", positive=True) + >>> z = Symbol("z") + + >>> X = Rayleigh("x", sigma) + + >>> density(X)(z) + z*exp(-z**2/(2*sigma**2))/sigma**2 + + >>> E(X) + sqrt(2)*sqrt(pi)*sigma/2 + + >>> variance(X) + -pi*sigma**2/2 + 2*sigma**2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Rayleigh_distribution + .. [2] https://mathworld.wolfram.com/RayleighDistribution.html + + """ + + return rv(name, RayleighDistribution, (sigma, )) + +#------------------------------------------------------------------------------- +# Reciprocal distribution -------------------------------------------------------- + +class ReciprocalDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + @property + def set(self): + return Interval(self.a, self.b) + + @staticmethod + def check(a, b): + _value_check(a > 0, "Parameter > 0. a = %s"%a) + _value_check((a < b), + "Parameter b must be in range (%s, +oo]. b = %s"%(a, b)) + + def pdf(self, x): + a, b = self.a, self.b + return 1/(x*(log(b) - log(a))) + + +def Reciprocal(name, a, b): + r"""Creates a continuous random variable with a reciprocal distribution. + + + Parameters + ========== + + a : Real number, :math:`0 < a` + b : Real number, :math:`a < b` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Reciprocal, density, cdf + >>> from sympy import symbols + >>> a, b, x = symbols('a, b, x', positive=True) + >>> R = Reciprocal('R', a, b) + + >>> density(R)(x) + 1/(x*(-log(a) + log(b))) + >>> cdf(R)(x) + Piecewise((log(a)/(log(a) - log(b)) - log(x)/(log(a) - log(b)), a <= x), (0, True)) + + Reference + ========= + + .. [1] https://en.wikipedia.org/wiki/Reciprocal_distribution + + """ + return rv(name, ReciprocalDistribution, (a, b)) + + +#------------------------------------------------------------------------------- +# Shifted Gompertz distribution ------------------------------------------------ + + +class ShiftedGompertzDistribution(SingleContinuousDistribution): + _argnames = ('b', 'eta') + + set = Interval(0, oo) + + @staticmethod + def check(b, eta): + _value_check(b > 0, "b must be positive") + _value_check(eta > 0, "eta must be positive") + + def pdf(self, x): + b, eta = self.b, self.eta + return b*exp(-b*x)*exp(-eta*exp(-b*x))*(1+eta*(1-exp(-b*x))) + +def ShiftedGompertz(name, b, eta): + r""" + Create a continuous random variable with a Shifted Gompertz distribution. + + Explanation + =========== + + The density of the Shifted Gompertz distribution is given by + + .. math:: + f(x) := b e^{-b x} e^{-\eta \exp(-b x)} \left[1 + \eta(1 - e^(-bx)) \right] + + with :math:`x \in [0, \infty)`. + + Parameters + ========== + + b : Real number, `b > 0`, a scale + eta : Real number, `\eta > 0`, a shape + + Returns + ======= + + RandomSymbol + + Examples + ======== + >>> from sympy.stats import ShiftedGompertz, density + >>> from sympy import Symbol + + >>> b = Symbol("b", positive=True) + >>> eta = Symbol("eta", positive=True) + >>> x = Symbol("x") + + >>> X = ShiftedGompertz("x", b, eta) + + >>> density(X)(x) + b*(eta*(1 - exp(-b*x)) + 1)*exp(-b*x)*exp(-eta*exp(-b*x)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Shifted_Gompertz_distribution + + """ + return rv(name, ShiftedGompertzDistribution, (b, eta)) + +#------------------------------------------------------------------------------- +# StudentT distribution -------------------------------------------------------- + + +class StudentTDistribution(SingleContinuousDistribution): + _argnames = ('nu',) + + set = Interval(-oo, oo) + + @staticmethod + def check(nu): + _value_check(nu > 0, "Degrees of freedom nu must be positive.") + + def pdf(self, x): + nu = self.nu + return 1/(sqrt(nu)*beta_fn(S.Half, nu/2))*(1 + x**2/nu)**(-(nu + 1)/2) + + def _cdf(self, x): + nu = self.nu + return S.Half + x*gamma((nu+1)/2)*hyper((S.Half, (nu+1)/2), + (Rational(3, 2),), -x**2/nu)/(sqrt(pi*nu)*gamma(nu/2)) + + def _moment_generating_function(self, t): + raise NotImplementedError('The moment generating function for the Student-T distribution is undefined.') + + +def StudentT(name, nu): + r""" + Create a continuous random variable with a student's t distribution. + + Explanation + =========== + + The density of the student's t distribution is given by + + .. math:: + f(x) := \frac{\Gamma \left(\frac{\nu+1}{2} \right)} + {\sqrt{\nu\pi}\Gamma \left(\frac{\nu}{2} \right)} + \left(1+\frac{x^2}{\nu} \right)^{-\frac{\nu+1}{2}} + + Parameters + ========== + + nu : Real number, `\nu > 0`, the degrees of freedom + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import StudentT, density, cdf + >>> from sympy import Symbol, pprint + + >>> nu = Symbol("nu", positive=True) + >>> z = Symbol("z") + + >>> X = StudentT("x", nu) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + nu 1 + - -- - - + 2 2 + / 2\ + | z | + |1 + --| + \ nu/ + ----------------- + ____ / nu\ + \/ nu *B|1/2, --| + \ 2 / + + >>> cdf(X)(z) + 1/2 + z*gamma(nu/2 + 1/2)*hyper((1/2, nu/2 + 1/2), (3/2,), + -z**2/nu)/(sqrt(pi)*sqrt(nu)*gamma(nu/2)) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Student_t-distribution + .. [2] https://mathworld.wolfram.com/Studentst-Distribution.html + + """ + + return rv(name, StudentTDistribution, (nu, )) + +#------------------------------------------------------------------------------- +# Trapezoidal distribution ------------------------------------------------------ + + +class TrapezoidalDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b', 'c', 'd') + + @property + def set(self): + return Interval(self.a, self.d) + + @staticmethod + def check(a, b, c, d): + _value_check(a < d, "Lower bound parameter a < %s. a = %s"%(d, a)) + _value_check((a <= b, b < c), + "Level start parameter b must be in range [%s, %s). b = %s"%(a, c, b)) + _value_check((b < c, c <= d), + "Level end parameter c must be in range (%s, %s]. c = %s"%(b, d, c)) + _value_check(d >= c, "Upper bound parameter d > %s. d = %s"%(c, d)) + + def pdf(self, x): + a, b, c, d = self.a, self.b, self.c, self.d + return Piecewise( + (2*(x-a) / ((b-a)*(d+c-a-b)), And(a <= x, x < b)), + (2 / (d+c-a-b), And(b <= x, x < c)), + (2*(d-x) / ((d-c)*(d+c-a-b)), And(c <= x, x <= d)), + (S.Zero, True)) + +def Trapezoidal(name, a, b, c, d): + r""" + Create a continuous random variable with a trapezoidal distribution. + + Explanation + =========== + + The density of the trapezoidal distribution is given by + + .. math:: + f(x) := \begin{cases} + 0 & \mathrm{for\ } x < a, \\ + \frac{2(x-a)}{(b-a)(d+c-a-b)} & \mathrm{for\ } a \le x < b, \\ + \frac{2}{d+c-a-b} & \mathrm{for\ } b \le x < c, \\ + \frac{2(d-x)}{(d-c)(d+c-a-b)} & \mathrm{for\ } c \le x < d, \\ + 0 & \mathrm{for\ } d < x. + \end{cases} + + Parameters + ========== + + a : Real number, :math:`a < d` + b : Real number, :math:`a \le b < c` + c : Real number, :math:`b < c \le d` + d : Real number + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Trapezoidal, density + >>> from sympy import Symbol, pprint + + >>> a = Symbol("a") + >>> b = Symbol("b") + >>> c = Symbol("c") + >>> d = Symbol("d") + >>> z = Symbol("z") + + >>> X = Trapezoidal("x", a,b,c,d) + + >>> pprint(density(X)(z), use_unicode=False) + / -2*a + 2*z + |------------------------- for And(a <= z, b > z) + |(-a + b)*(-a - b + c + d) + | + | 2 + | -------------- for And(b <= z, c > z) + < -a - b + c + d + | + | 2*d - 2*z + |------------------------- for And(d >= z, c <= z) + |(-c + d)*(-a - b + c + d) + | + \ 0 otherwise + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Trapezoidal_distribution + + """ + return rv(name, TrapezoidalDistribution, (a, b, c, d)) + +#------------------------------------------------------------------------------- +# Triangular distribution ------------------------------------------------------ + + +class TriangularDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b', 'c') + + @property + def set(self): + return Interval(self.a, self.b) + + @staticmethod + def check(a, b, c): + _value_check(b > a, "Parameter b > %s. b = %s"%(a, b)) + _value_check((a <= c, c <= b), + "Parameter c must be in range [%s, %s]. c = %s"%(a, b, c)) + + def pdf(self, x): + a, b, c = self.a, self.b, self.c + return Piecewise( + (2*(x - a)/((b - a)*(c - a)), And(a <= x, x < c)), + (2/(b - a), Eq(x, c)), + (2*(b - x)/((b - a)*(b - c)), And(c < x, x <= b)), + (S.Zero, True)) + + def _characteristic_function(self, t): + a, b, c = self.a, self.b, self.c + return -2 *((b-c) * exp(I*a*t) - (b-a) * exp(I*c*t) + (c-a) * exp(I*b*t)) / ((b-a)*(c-a)*(b-c)*t**2) + + def _moment_generating_function(self, t): + a, b, c = self.a, self.b, self.c + return 2 * ((b - c) * exp(a * t) - (b - a) * exp(c * t) + (c - a) * exp(b * t)) / ( + (b - a) * (c - a) * (b - c) * t ** 2) + + +def Triangular(name, a, b, c): + r""" + Create a continuous random variable with a triangular distribution. + + Explanation + =========== + + The density of the triangular distribution is given by + + .. math:: + f(x) := \begin{cases} + 0 & \mathrm{for\ } x < a, \\ + \frac{2(x-a)}{(b-a)(c-a)} & \mathrm{for\ } a \le x < c, \\ + \frac{2}{b-a} & \mathrm{for\ } x = c, \\ + \frac{2(b-x)}{(b-a)(b-c)} & \mathrm{for\ } c < x \le b, \\ + 0 & \mathrm{for\ } b < x. + \end{cases} + + Parameters + ========== + + a : Real number, :math:`a \in \left(-\infty, \infty\right)` + b : Real number, :math:`a < b` + c : Real number, :math:`a \leq c \leq b` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Triangular, density + >>> from sympy import Symbol, pprint + + >>> a = Symbol("a") + >>> b = Symbol("b") + >>> c = Symbol("c") + >>> z = Symbol("z") + + >>> X = Triangular("x", a,b,c) + + >>> pprint(density(X)(z), use_unicode=False) + / -2*a + 2*z + |----------------- for And(a <= z, c > z) + |(-a + b)*(-a + c) + | + | 2 + | ------ for c = z + < -a + b + | + | 2*b - 2*z + |---------------- for And(b >= z, c < z) + |(-a + b)*(b - c) + | + \ 0 otherwise + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Triangular_distribution + .. [2] https://mathworld.wolfram.com/TriangularDistribution.html + + """ + + return rv(name, TriangularDistribution, (a, b, c)) + +#------------------------------------------------------------------------------- +# Uniform distribution --------------------------------------------------------- + + +class UniformDistribution(SingleContinuousDistribution): + _argnames = ('left', 'right') + + @property + def set(self): + return Interval(self.left, self.right) + + @staticmethod + def check(left, right): + _value_check(left < right, "Lower limit should be less than Upper limit.") + + def pdf(self, x): + left, right = self.left, self.right + return Piecewise( + (S.One/(right - left), And(left <= x, x <= right)), + (S.Zero, True) + ) + + def _cdf(self, x): + left, right = self.left, self.right + return Piecewise( + (S.Zero, x < left), + ((x - left)/(right - left), x <= right), + (S.One, True) + ) + + def _characteristic_function(self, t): + left, right = self.left, self.right + return Piecewise(((exp(I*t*right) - exp(I*t*left)) / (I*t*(right - left)), Ne(t, 0)), + (S.One, True)) + + def _moment_generating_function(self, t): + left, right = self.left, self.right + return Piecewise(((exp(t*right) - exp(t*left)) / (t * (right - left)), Ne(t, 0)), + (S.One, True)) + + def expectation(self, expr, var, **kwargs): + kwargs['evaluate'] = True + result = SingleContinuousDistribution.expectation(self, expr, var, **kwargs) + result = result.subs({Max(self.left, self.right): self.right, + Min(self.left, self.right): self.left}) + return result + + +def Uniform(name, left, right): + r""" + Create a continuous random variable with a uniform distribution. + + Explanation + =========== + + The density of the uniform distribution is given by + + .. math:: + f(x) := \begin{cases} + \frac{1}{b - a} & \text{for } x \in [a,b] \\ + 0 & \text{otherwise} + \end{cases} + + with :math:`x \in [a,b]`. + + Parameters + ========== + + a : Real number, :math:`-\infty < a`, the left boundary + b : Real number, :math:`a < b < \infty`, the right boundary + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Uniform, density, cdf, E, variance + >>> from sympy import Symbol, simplify + + >>> a = Symbol("a", negative=True) + >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") + + >>> X = Uniform("x", a, b) + + >>> density(X)(z) + Piecewise((1/(-a + b), (b >= z) & (a <= z)), (0, True)) + + >>> cdf(X)(z) + Piecewise((0, a > z), ((-a + z)/(-a + b), b >= z), (1, True)) + + >>> E(X) + a/2 + b/2 + + >>> simplify(variance(X)) + a**2/12 - a*b/6 + b**2/12 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29 + .. [2] https://mathworld.wolfram.com/UniformDistribution.html + + """ + + return rv(name, UniformDistribution, (left, right)) + +#------------------------------------------------------------------------------- +# UniformSum distribution ------------------------------------------------------ + + +class UniformSumDistribution(SingleContinuousDistribution): + _argnames = ('n',) + + @property + def set(self): + return Interval(0, self.n) + + @staticmethod + def check(n): + _value_check((n > 0, n.is_integer), + "Parameter n must be positive integer.") + + def pdf(self, x): + n = self.n + k = Dummy("k") + return 1/factorial( + n - 1)*Sum((-1)**k*binomial(n, k)*(x - k)**(n - 1), (k, 0, floor(x))) + + def _cdf(self, x): + n = self.n + k = Dummy("k") + return Piecewise((S.Zero, x < 0), + (1/factorial(n)*Sum((-1)**k*binomial(n, k)*(x - k)**(n), + (k, 0, floor(x))), x <= n), + (S.One, True)) + + def _characteristic_function(self, t): + return ((exp(I*t) - 1) / (I*t))**self.n + + def _moment_generating_function(self, t): + return ((exp(t) - 1) / t)**self.n + +def UniformSum(name, n): + r""" + Create a continuous random variable with an Irwin-Hall distribution. + + Explanation + =========== + + The probability distribution function depends on a single parameter + $n$ which is an integer. + + The density of the Irwin-Hall distribution is given by + + .. math :: + f(x) := \frac{1}{(n-1)!}\sum_{k=0}^{\left\lfloor x\right\rfloor}(-1)^k + \binom{n}{k}(x-k)^{n-1} + + Parameters + ========== + + n : A positive integer, `n > 0` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import UniformSum, density, cdf + >>> from sympy import Symbol, pprint + + >>> n = Symbol("n", integer=True) + >>> z = Symbol("z") + + >>> X = UniformSum("x", n) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + floor(z) + ___ + \ ` + \ k n - 1 /n\ + ) (-1) *(-k + z) *| | + / \k/ + /__, + k = 0 + -------------------------------- + (n - 1)! + + >>> cdf(X)(z) + Piecewise((0, z < 0), (Sum((-1)**_k*(-_k + z)**n*binomial(n, _k), + (_k, 0, floor(z)))/factorial(n), n >= z), (1, True)) + + + Compute cdf with specific 'x' and 'n' values as follows : + >>> cdf(UniformSum("x", 5), evaluate=False)(2).doit() + 9/40 + + The argument evaluate=False prevents an attempt at evaluation + of the sum for general n, before the argument 2 is passed. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Uniform_sum_distribution + .. [2] https://mathworld.wolfram.com/UniformSumDistribution.html + + """ + + return rv(name, UniformSumDistribution, (n, )) + +#------------------------------------------------------------------------------- +# VonMises distribution -------------------------------------------------------- + + +class VonMisesDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'k') + + set = Interval(0, 2*pi) + + @staticmethod + def check(mu, k): + _value_check(k > 0, "k must be positive") + + def pdf(self, x): + mu, k = self.mu, self.k + return exp(k*cos(x-mu)) / (2*pi*besseli(0, k)) + +def VonMises(name, mu, k): + r""" + Create a Continuous Random Variable with a von Mises distribution. + + Explanation + =========== + + The density of the von Mises distribution is given by + + .. math:: + f(x) := \frac{e^{\kappa\cos(x-\mu)}}{2\pi I_0(\kappa)} + + with :math:`x \in [0,2\pi]`. + + Parameters + ========== + + mu : Real number + Measure of location. + k : Real number + Measure of concentration. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import VonMises, density + >>> from sympy import Symbol, pprint + + >>> mu = Symbol("mu") + >>> k = Symbol("k", positive=True) + >>> z = Symbol("z") + + >>> X = VonMises("x", mu, k) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + k*cos(mu - z) + e + ------------------ + 2*pi*besseli(0, k) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Von_Mises_distribution + .. [2] https://mathworld.wolfram.com/vonMisesDistribution.html + + """ + + return rv(name, VonMisesDistribution, (mu, k)) + +#------------------------------------------------------------------------------- +# Weibull distribution --------------------------------------------------------- + + +class WeibullDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta') + + set = Interval(0, oo) + + @staticmethod + def check(alpha, beta): + _value_check(alpha > 0, "Alpha must be positive") + _value_check(beta > 0, "Beta must be positive") + + def pdf(self, x): + alpha, beta = self.alpha, self.beta + return beta * (x/alpha)**(beta - 1) * exp(-(x/alpha)**beta) / alpha + + +def Weibull(name, alpha, beta): + r""" + Create a continuous random variable with a Weibull distribution. + + Explanation + =========== + + The density of the Weibull distribution is given by + + .. math:: + f(x) := \begin{cases} + \frac{k}{\lambda}\left(\frac{x}{\lambda}\right)^{k-1} + e^{-(x/\lambda)^{k}} & x\geq0\\ + 0 & x<0 + \end{cases} + + Parameters + ========== + + lambda : Real number, $\lambda > 0$, a scale + k : Real number, $k > 0$, a shape + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Weibull, density, E, variance + >>> from sympy import Symbol, simplify + + >>> l = Symbol("lambda", positive=True) + >>> k = Symbol("k", positive=True) + >>> z = Symbol("z") + + >>> X = Weibull("x", l, k) + + >>> density(X)(z) + k*(z/lambda)**(k - 1)*exp(-(z/lambda)**k)/lambda + + >>> simplify(E(X)) + lambda*gamma(1 + 1/k) + + >>> simplify(variance(X)) + lambda**2*(-gamma(1 + 1/k)**2 + gamma(1 + 2/k)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Weibull_distribution + .. [2] https://mathworld.wolfram.com/WeibullDistribution.html + + """ + + return rv(name, WeibullDistribution, (alpha, beta)) + +#------------------------------------------------------------------------------- +# Wigner semicircle distribution ----------------------------------------------- + + +class WignerSemicircleDistribution(SingleContinuousDistribution): + _argnames = ('R',) + + @property + def set(self): + return Interval(-self.R, self.R) + + @staticmethod + def check(R): + _value_check(R > 0, "Radius R must be positive.") + + def pdf(self, x): + R = self.R + return 2/(pi*R**2)*sqrt(R**2 - x**2) + + def _characteristic_function(self, t): + return Piecewise((2 * besselj(1, self.R*t) / (self.R*t), Ne(t, 0)), + (S.One, True)) + + def _moment_generating_function(self, t): + return Piecewise((2 * besseli(1, self.R*t) / (self.R*t), Ne(t, 0)), + (S.One, True)) + +def WignerSemicircle(name, R): + r""" + Create a continuous random variable with a Wigner semicircle distribution. + + Explanation + =========== + + The density of the Wigner semicircle distribution is given by + + .. math:: + f(x) := \frac2{\pi R^2}\,\sqrt{R^2-x^2} + + with :math:`x \in [-R,R]`. + + Parameters + ========== + + R : Real number, `R > 0`, the radius + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import WignerSemicircle, density, E + >>> from sympy import Symbol + + >>> R = Symbol("R", positive=True) + >>> z = Symbol("z") + + >>> X = WignerSemicircle("x", R) + + >>> density(X)(z) + 2*sqrt(R**2 - z**2)/(pi*R**2) + + >>> E(X) + 0 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Wigner_semicircle_distribution + .. [2] https://mathworld.wolfram.com/WignersSemicircleLaw.html + + """ + + return rv(name, WignerSemicircleDistribution, (R,)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/drv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/drv.py new file mode 100644 index 0000000000000000000000000000000000000000..dea14f2dfd1078c223c61bb5cd1373105e72ea28 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/drv.py @@ -0,0 +1,350 @@ +from sympy.concrete.summations import (Sum, summation) +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core.function import Lambda +from sympy.core.numbers import I +from sympy.core.relational import (Eq, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, symbols) +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.piecewise import Piecewise +from sympy.logic.boolalg import And +from sympy.polys.polytools import poly +from sympy.series.series import series + +from sympy.polys.polyerrors import PolynomialError +from sympy.stats.crv import reduce_rational_inequalities_wrap +from sympy.stats.rv import (NamedArgsMixin, SinglePSpace, SingleDomain, + random_symbols, PSpace, ConditionalDomain, RandomDomain, + ProductDomain, Distribution) +from sympy.stats.symbolic_probability import Probability +from sympy.sets.fancysets import Range, FiniteSet +from sympy.sets.sets import Union +from sympy.sets.contains import Contains +from sympy.utilities import filldedent +from sympy.core.sympify import _sympify + + +class DiscreteDistribution(Distribution): + def __call__(self, *args): + return self.pdf(*args) + + +class SingleDiscreteDistribution(DiscreteDistribution, NamedArgsMixin): + """ Discrete distribution of a single variable. + + Serves as superclass for PoissonDistribution etc.... + + Provides methods for pdf, cdf, and sampling + + See Also: + sympy.stats.crv_types.* + """ + + set = S.Integers + + def __new__(cls, *args): + args = list(map(sympify, args)) + return Basic.__new__(cls, *args) + + @staticmethod + def check(*args): + pass + + @cacheit + def compute_cdf(self, **kwargs): + """ Compute the CDF from the PDF. + + Returns a Lambda. + """ + x = symbols('x', integer=True, cls=Dummy) + z = symbols('z', real=True, cls=Dummy) + left_bound = self.set.inf + + # CDF is integral of PDF from left bound to z + pdf = self.pdf(x) + cdf = summation(pdf, (x, left_bound, floor(z)), **kwargs) + # CDF Ensure that CDF left of left_bound is zero + cdf = Piecewise((cdf, z >= left_bound), (0, True)) + return Lambda(z, cdf) + + def _cdf(self, x): + return None + + def cdf(self, x, **kwargs): + """ Cumulative density function """ + if not kwargs: + cdf = self._cdf(x) + if cdf is not None: + return cdf + return self.compute_cdf(**kwargs)(x) + + @cacheit + def compute_characteristic_function(self, **kwargs): + """ Compute the characteristic function from the PDF. + + Returns a Lambda. + """ + x, t = symbols('x, t', real=True, cls=Dummy) + pdf = self.pdf(x) + cf = summation(exp(I*t*x)*pdf, (x, self.set.inf, self.set.sup)) + return Lambda(t, cf) + + def _characteristic_function(self, t): + return None + + def characteristic_function(self, t, **kwargs): + """ Characteristic function """ + if not kwargs: + cf = self._characteristic_function(t) + if cf is not None: + return cf + return self.compute_characteristic_function(**kwargs)(t) + + @cacheit + def compute_moment_generating_function(self, **kwargs): + t = Dummy('t', real=True) + x = Dummy('x', integer=True) + pdf = self.pdf(x) + mgf = summation(exp(t*x)*pdf, (x, self.set.inf, self.set.sup)) + return Lambda(t, mgf) + + def _moment_generating_function(self, t): + return None + + def moment_generating_function(self, t, **kwargs): + if not kwargs: + mgf = self._moment_generating_function(t) + if mgf is not None: + return mgf + return self.compute_moment_generating_function(**kwargs)(t) + + @cacheit + def compute_quantile(self, **kwargs): + """ Compute the Quantile from the PDF. + + Returns a Lambda. + """ + x = Dummy('x', integer=True) + p = Dummy('p', real=True) + left_bound = self.set.inf + pdf = self.pdf(x) + cdf = summation(pdf, (x, left_bound, x), **kwargs) + set = ((x, p <= cdf), ) + return Lambda(p, Piecewise(*set)) + + def _quantile(self, x): + return None + + def quantile(self, x, **kwargs): + """ Cumulative density function """ + if not kwargs: + quantile = self._quantile(x) + if quantile is not None: + return quantile + return self.compute_quantile(**kwargs)(x) + + def expectation(self, expr, var, evaluate=True, **kwargs): + """ Expectation of expression over distribution """ + # TODO: support discrete sets with non integer stepsizes + + if evaluate: + try: + p = poly(expr, var) + + t = Dummy('t', real=True) + + mgf = self.moment_generating_function(t) + deg = p.degree() + taylor = poly(series(mgf, t, 0, deg + 1).removeO(), t) + result = 0 + for k in range(deg+1): + result += p.coeff_monomial(var ** k) * taylor.coeff_monomial(t ** k) * factorial(k) + + return result + + except PolynomialError: + return summation(expr * self.pdf(var), + (var, self.set.inf, self.set.sup), **kwargs) + + else: + return Sum(expr * self.pdf(var), + (var, self.set.inf, self.set.sup), **kwargs) + + def __call__(self, *args): + return self.pdf(*args) + + +class DiscreteDomain(RandomDomain): + """ + A domain with discrete support with step size one. + Represented using symbols and Range. + """ + is_Discrete = True + +class SingleDiscreteDomain(DiscreteDomain, SingleDomain): + def as_boolean(self): + return Contains(self.symbol, self.set) + + +class ConditionalDiscreteDomain(DiscreteDomain, ConditionalDomain): + """ + Domain with discrete support of step size one, that is restricted by + some condition. + """ + @property + def set(self): + rv = self.symbols + if len(self.symbols) > 1: + raise NotImplementedError(filldedent(''' + Multivariate conditional domains are not yet implemented.''')) + rv = list(rv)[0] + return reduce_rational_inequalities_wrap(self.condition, + rv).intersect(self.fulldomain.set) + + +class DiscretePSpace(PSpace): + is_real = True + is_Discrete = True + + @property + def pdf(self): + return self.density(*self.symbols) + + def where(self, condition): + rvs = random_symbols(condition) + assert all(r.symbol in self.symbols for r in rvs) + if len(rvs) > 1: + raise NotImplementedError(filldedent('''Multivariate discrete + random variables are not yet supported.''')) + conditional_domain = reduce_rational_inequalities_wrap(condition, + rvs[0]) + conditional_domain = conditional_domain.intersect(self.domain.set) + return SingleDiscreteDomain(rvs[0].symbol, conditional_domain) + + def probability(self, condition): + complement = isinstance(condition, Ne) + if complement: + condition = Eq(condition.args[0], condition.args[1]) + try: + _domain = self.where(condition).set + if condition == False or _domain is S.EmptySet: + return S.Zero + if condition == True or _domain == self.domain.set: + return S.One + prob = self.eval_prob(_domain) + except NotImplementedError: + from sympy.stats.rv import density + expr = condition.lhs - condition.rhs + dens = density(expr) + if not isinstance(dens, DiscreteDistribution): + from sympy.stats.drv_types import DiscreteDistributionHandmade + dens = DiscreteDistributionHandmade(dens) + z = Dummy('z', real=True) + space = SingleDiscretePSpace(z, dens) + prob = space.probability(condition.__class__(space.value, 0)) + if prob is None: + prob = Probability(condition) + return prob if not complement else S.One - prob + + def eval_prob(self, _domain): + sym = list(self.symbols)[0] + if isinstance(_domain, Range): + n = symbols('n', integer=True) + inf, sup, step = (r for r in _domain.args) + summand = ((self.pdf).replace( + sym, n*step)) + rv = summation(summand, + (n, inf/step, (sup)/step - 1)).doit() + return rv + elif isinstance(_domain, FiniteSet): + pdf = Lambda(sym, self.pdf) + rv = sum(pdf(x) for x in _domain) + return rv + elif isinstance(_domain, Union): + rv = sum(self.eval_prob(x) for x in _domain.args) + return rv + + def conditional_space(self, condition): + # XXX: Converting from set to tuple. The order matters to Lambda + # though so we should be starting with a set... + density = Lambda(tuple(self.symbols), self.pdf/self.probability(condition)) + condition = condition.xreplace({rv: rv.symbol for rv in self.values}) + domain = ConditionalDiscreteDomain(self.domain, condition) + return DiscretePSpace(domain, density) + +class ProductDiscreteDomain(ProductDomain, DiscreteDomain): + def as_boolean(self): + return And(*[domain.as_boolean for domain in self.domains]) + +class SingleDiscretePSpace(DiscretePSpace, SinglePSpace): + """ Discrete probability space over a single univariate variable """ + is_real = True + + @property + def set(self): + return self.distribution.set + + @property + def domain(self): + return SingleDiscreteDomain(self.symbol, self.set) + + def sample(self, size=(), library='scipy', seed=None): + """ + Internal sample method. + + Returns dictionary mapping RandomSymbol to realization value. + """ + return {self.value: self.distribution.sample(size, library=library, seed=seed)} + + def compute_expectation(self, expr, rvs=None, evaluate=True, **kwargs): + rvs = rvs or (self.value,) + if self.value not in rvs: + return expr + + expr = _sympify(expr) + expr = expr.xreplace({rv: rv.symbol for rv in rvs}) + + x = self.value.symbol + try: + return self.distribution.expectation(expr, x, evaluate=evaluate, + **kwargs) + except NotImplementedError: + return Sum(expr * self.pdf, (x, self.set.inf, self.set.sup), + **kwargs) + + def compute_cdf(self, expr, **kwargs): + if expr == self.value: + x = Dummy("x", real=True) + return Lambda(x, self.distribution.cdf(x, **kwargs)) + else: + raise NotImplementedError() + + def compute_density(self, expr, **kwargs): + if expr == self.value: + return self.distribution + raise NotImplementedError() + + def compute_characteristic_function(self, expr, **kwargs): + if expr == self.value: + t = Dummy("t", real=True) + return Lambda(t, self.distribution.characteristic_function(t, **kwargs)) + else: + raise NotImplementedError() + + def compute_moment_generating_function(self, expr, **kwargs): + if expr == self.value: + t = Dummy("t", real=True) + return Lambda(t, self.distribution.moment_generating_function(t, **kwargs)) + else: + raise NotImplementedError() + + def compute_quantile(self, expr, **kwargs): + if expr == self.value: + p = Dummy("p", real=True) + return Lambda(p, self.distribution.quantile(p, **kwargs)) + else: + raise NotImplementedError() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/drv_types.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/drv_types.py new file mode 100644 index 0000000000000000000000000000000000000000..84920d31c0083828efc2cd3f752d2c48f5430102 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/drv_types.py @@ -0,0 +1,849 @@ +""" + +Contains +======== +FlorySchulz +Geometric +Hermite +Logarithmic +NegativeBinomial +Poisson +Skellam +YuleSimon +Zeta +""" + + + +from sympy.concrete.summations import Sum +from sympy.core.basic import Basic +from sympy.core.function import Lambda +from sympy.core.numbers import I +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import (binomial, factorial, FallingFactorial) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.bessel import besseli +from sympy.functions.special.beta_functions import beta +from sympy.functions.special.hyper import hyper +from sympy.functions.special.zeta_functions import (polylog, zeta) +from sympy.stats.drv import SingleDiscreteDistribution, SingleDiscretePSpace +from sympy.stats.rv import _value_check, is_random + + +__all__ = ['FlorySchulz', +'Geometric', +'Hermite', +'Logarithmic', +'NegativeBinomial', +'Poisson', +'Skellam', +'YuleSimon', +'Zeta' +] + + +def rv(symbol, cls, *args, **kwargs): + args = list(map(sympify, args)) + dist = cls(*args) + if kwargs.pop('check', True): + dist.check(*args) + pspace = SingleDiscretePSpace(symbol, dist) + if any(is_random(arg) for arg in args): + from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution + pspace = CompoundPSpace(symbol, CompoundDistribution(dist)) + return pspace.value + + +class DiscreteDistributionHandmade(SingleDiscreteDistribution): + _argnames = ('pdf',) + + def __new__(cls, pdf, set=S.Integers): + return Basic.__new__(cls, pdf, set) + + @property + def set(self): + return self.args[1] + + @staticmethod + def check(pdf, set): + x = Dummy('x') + val = Sum(pdf(x), (x, set._inf, set._sup)).doit() + _value_check(Eq(val, 1) != S.false, "The pdf is incorrect on the given set.") + + + +def DiscreteRV(symbol, density, set=S.Integers, **kwargs): + """ + Create a Discrete Random Variable given the following: + + Parameters + ========== + + symbol : Symbol + Represents name of the random variable. + density : Expression containing symbol + Represents probability density function. + set : set + Represents the region where the pdf is valid, by default is real line. + check : bool + If True, it will check whether the given density + integrates to 1 over the given set. If False, it + will not perform this check. Default is False. + + Examples + ======== + + >>> from sympy.stats import DiscreteRV, P, E + >>> from sympy import Rational, Symbol + >>> x = Symbol('x') + >>> n = 10 + >>> density = Rational(1, 10) + >>> X = DiscreteRV(x, density, set=set(range(n))) + >>> E(X) + 9/2 + >>> P(X>3) + 3/5 + + Returns + ======= + + RandomSymbol + + """ + set = sympify(set) + pdf = Piecewise((density, set.as_relational(symbol)), (0, True)) + pdf = Lambda(symbol, pdf) + # have a default of False while `rv` should have a default of True + kwargs['check'] = kwargs.pop('check', False) + return rv(symbol.name, DiscreteDistributionHandmade, pdf, set, **kwargs) + + +#------------------------------------------------------------------------------- +# Flory-Schulz distribution ------------------------------------------------------------ + +class FlorySchulzDistribution(SingleDiscreteDistribution): + _argnames = ('a',) + set = S.Naturals + + @staticmethod + def check(a): + _value_check((0 < a, a < 1), "a must be between 0 and 1") + + def pdf(self, k): + a = self.a + return (a**2 * k * (1 - a)**(k - 1)) + + def _characteristic_function(self, t): + a = self.a + return a**2*exp(I*t)/((1 + (a - 1)*exp(I*t))**2) + + def _moment_generating_function(self, t): + a = self.a + return a**2*exp(t)/((1 + (a - 1)*exp(t))**2) + + +def FlorySchulz(name, a): + r""" + Create a discrete random variable with a FlorySchulz distribution. + + The density of the FlorySchulz distribution is given by + + .. math:: + f(k) := (a^2) k (1 - a)^{k-1} + + Parameters + ========== + + a : A real number between 0 and 1 + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density, E, variance, FlorySchulz + >>> from sympy import Symbol, S + + >>> a = S.One / 5 + >>> z = Symbol("z") + + >>> X = FlorySchulz("x", a) + + >>> density(X)(z) + (4/5)**(z - 1)*z/25 + + >>> E(X) + 9 + + >>> variance(X) + 40 + + References + ========== + + https://en.wikipedia.org/wiki/Flory%E2%80%93Schulz_distribution + """ + return rv(name, FlorySchulzDistribution, a) + + +#------------------------------------------------------------------------------- +# Geometric distribution ------------------------------------------------------------ + +class GeometricDistribution(SingleDiscreteDistribution): + _argnames = ('p',) + set = S.Naturals + + @staticmethod + def check(p): + _value_check((0 < p, p <= 1), "p must be between 0 and 1") + + def pdf(self, k): + return (1 - self.p)**(k - 1) * self.p + + def _characteristic_function(self, t): + p = self.p + return p * exp(I*t) / (1 - (1 - p)*exp(I*t)) + + def _moment_generating_function(self, t): + p = self.p + return p * exp(t) / (1 - (1 - p) * exp(t)) + + +def Geometric(name, p): + r""" + Create a discrete random variable with a Geometric distribution. + + Explanation + =========== + + The density of the Geometric distribution is given by + + .. math:: + f(k) := p (1 - p)^{k - 1} + + Parameters + ========== + + p : A probability between 0 and 1 + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Geometric, density, E, variance + >>> from sympy import Symbol, S + + >>> p = S.One / 5 + >>> z = Symbol("z") + + >>> X = Geometric("x", p) + + >>> density(X)(z) + (4/5)**(z - 1)/5 + + >>> E(X) + 5 + + >>> variance(X) + 20 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Geometric_distribution + .. [2] https://mathworld.wolfram.com/GeometricDistribution.html + + """ + return rv(name, GeometricDistribution, p) + + +#------------------------------------------------------------------------------- +# Hermite distribution --------------------------------------------------------- + + +class HermiteDistribution(SingleDiscreteDistribution): + _argnames = ('a1', 'a2') + set = S.Naturals0 + + @staticmethod + def check(a1, a2): + _value_check(a1.is_nonnegative, 'Parameter a1 must be >= 0.') + _value_check(a2.is_nonnegative, 'Parameter a2 must be >= 0.') + + def pdf(self, k): + a1, a2 = self.a1, self.a2 + term1 = exp(-(a1 + a2)) + j = Dummy("j", integer=True) + num = a1**(k - 2*j) * a2**j + den = factorial(k - 2*j) * factorial(j) + return term1 * Sum(num/den, (j, 0, k//2)).doit() + + def _moment_generating_function(self, t): + a1, a2 = self.a1, self.a2 + term1 = a1 * (exp(t) - 1) + term2 = a2 * (exp(2*t) - 1) + return exp(term1 + term2) + + def _characteristic_function(self, t): + a1, a2 = self.a1, self.a2 + term1 = a1 * (exp(I*t) - 1) + term2 = a2 * (exp(2*I*t) - 1) + return exp(term1 + term2) + +def Hermite(name, a1, a2): + r""" + Create a discrete random variable with a Hermite distribution. + + Explanation + =========== + + The density of the Hermite distribution is given by + + .. math:: + f(x):= e^{-a_1 -a_2}\sum_{j=0}^{\left \lfloor x/2 \right \rfloor} + \frac{a_{1}^{x-2j}a_{2}^{j}}{(x-2j)!j!} + + Parameters + ========== + + a1 : A Positive number greater than equal to 0. + a2 : A Positive number greater than equal to 0. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Hermite, density, E, variance + >>> from sympy import Symbol + + >>> a1 = Symbol("a1", positive=True) + >>> a2 = Symbol("a2", positive=True) + >>> x = Symbol("x") + + >>> H = Hermite("H", a1=5, a2=4) + + >>> density(H)(2) + 33*exp(-9)/2 + + >>> E(H) + 13 + + >>> variance(H) + 21 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hermite_distribution + + """ + + return rv(name, HermiteDistribution, a1, a2) + + +#------------------------------------------------------------------------------- +# Logarithmic distribution ------------------------------------------------------------ + +class LogarithmicDistribution(SingleDiscreteDistribution): + _argnames = ('p',) + + set = S.Naturals + + @staticmethod + def check(p): + _value_check((p > 0, p < 1), "p should be between 0 and 1") + + def pdf(self, k): + p = self.p + return (-1) * p**k / (k * log(1 - p)) + + def _characteristic_function(self, t): + p = self.p + return log(1 - p * exp(I*t)) / log(1 - p) + + def _moment_generating_function(self, t): + p = self.p + return log(1 - p * exp(t)) / log(1 - p) + + +def Logarithmic(name, p): + r""" + Create a discrete random variable with a Logarithmic distribution. + + Explanation + =========== + + The density of the Logarithmic distribution is given by + + .. math:: + f(k) := \frac{-p^k}{k \ln{(1 - p)}} + + Parameters + ========== + + p : A value between 0 and 1 + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Logarithmic, density, E, variance + >>> from sympy import Symbol, S + + >>> p = S.One / 5 + >>> z = Symbol("z") + + >>> X = Logarithmic("x", p) + + >>> density(X)(z) + -1/(5**z*z*log(4/5)) + + >>> E(X) + -1/(-4*log(5) + 8*log(2)) + + >>> variance(X) + -1/((-4*log(5) + 8*log(2))*(-2*log(5) + 4*log(2))) + 1/(-64*log(2)*log(5) + 64*log(2)**2 + 16*log(5)**2) - 10/(-32*log(5) + 64*log(2)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Logarithmic_distribution + .. [2] https://mathworld.wolfram.com/LogarithmicDistribution.html + + """ + return rv(name, LogarithmicDistribution, p) + + +#------------------------------------------------------------------------------- +# Negative binomial distribution ------------------------------------------------------------ + +class NegativeBinomialDistribution(SingleDiscreteDistribution): + _argnames = ('r', 'p') + set = S.Naturals0 + + @staticmethod + def check(r, p): + _value_check(r > 0, 'r should be positive') + _value_check((p > 0, p < 1), 'p should be between 0 and 1') + + def pdf(self, k): + r = self.r + p = self.p + + return binomial(k + r - 1, k) * (1 - p)**k * p**r + + def _characteristic_function(self, t): + r = self.r + p = self.p + + return (p / (1 - (1 - p) * exp(I*t)))**r + + def _moment_generating_function(self, t): + r = self.r + p = self.p + + return (p / (1 - (1 - p) * exp(t)))**r + +def NegativeBinomial(name, r, p): + r""" + Create a discrete random variable with a Negative Binomial distribution. + + Explanation + =========== + + The density of the Negative Binomial distribution is given by + + .. math:: + f(k) := \binom{k + r - 1}{k} (1 - p)^k p^r + + Parameters + ========== + + r : A positive value + Number of successes until the experiment is stopped. + p : A value between 0 and 1 + Probability of success. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import NegativeBinomial, density, E, variance + >>> from sympy import Symbol, S + + >>> r = 5 + >>> p = S.One / 3 + >>> z = Symbol("z") + + >>> X = NegativeBinomial("x", r, p) + + >>> density(X)(z) + (2/3)**z*binomial(z + 4, z)/243 + + >>> E(X) + 10 + + >>> variance(X) + 30 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Negative_binomial_distribution + .. [2] https://mathworld.wolfram.com/NegativeBinomialDistribution.html + + """ + return rv(name, NegativeBinomialDistribution, r, p) + + +#------------------------------------------------------------------------------- +# Poisson distribution ------------------------------------------------------------ + +class PoissonDistribution(SingleDiscreteDistribution): + _argnames = ('lamda',) + + set = S.Naturals0 + + @staticmethod + def check(lamda): + _value_check(lamda > 0, "Lambda must be positive") + + def pdf(self, k): + return self.lamda**k / factorial(k) * exp(-self.lamda) + + def _characteristic_function(self, t): + return exp(self.lamda * (exp(I*t) - 1)) + + def _moment_generating_function(self, t): + return exp(self.lamda * (exp(t) - 1)) + + def expectation(self, expr, var, evaluate=True, **kwargs): + if evaluate: + if expr == var: + return self.lamda + if ( + isinstance(expr, FallingFactorial) + and expr.args[1].is_integer + and expr.args[1].is_positive + and expr.args[0] == var + ): + return self.lamda ** expr.args[1] + return super().expectation(expr, var, evaluate, **kwargs) + +def Poisson(name, lamda): + r""" + Create a discrete random variable with a Poisson distribution. + + Explanation + =========== + + The density of the Poisson distribution is given by + + .. math:: + f(k) := \frac{\lambda^{k} e^{- \lambda}}{k!} + + Parameters + ========== + + lamda : Positive number, a rate + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Poisson, density, E, variance + >>> from sympy import Symbol, simplify + + >>> rate = Symbol("lambda", positive=True) + >>> z = Symbol("z") + + >>> X = Poisson("x", rate) + + >>> density(X)(z) + lambda**z*exp(-lambda)/factorial(z) + + >>> E(X) + lambda + + >>> simplify(variance(X)) + lambda + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Poisson_distribution + .. [2] https://mathworld.wolfram.com/PoissonDistribution.html + + """ + return rv(name, PoissonDistribution, lamda) + + +# ----------------------------------------------------------------------------- +# Skellam distribution -------------------------------------------------------- + + +class SkellamDistribution(SingleDiscreteDistribution): + _argnames = ('mu1', 'mu2') + set = S.Integers + + @staticmethod + def check(mu1, mu2): + _value_check(mu1 >= 0, 'Parameter mu1 must be >= 0') + _value_check(mu2 >= 0, 'Parameter mu2 must be >= 0') + + def pdf(self, k): + (mu1, mu2) = (self.mu1, self.mu2) + term1 = exp(-(mu1 + mu2)) * (mu1 / mu2) ** (k / 2) + term2 = besseli(k, 2 * sqrt(mu1 * mu2)) + return term1 * term2 + + def _cdf(self, x): + raise NotImplementedError( + "Skellam doesn't have closed form for the CDF.") + + def _characteristic_function(self, t): + (mu1, mu2) = (self.mu1, self.mu2) + return exp(-(mu1 + mu2) + mu1 * exp(I * t) + mu2 * exp(-I * t)) + + def _moment_generating_function(self, t): + (mu1, mu2) = (self.mu1, self.mu2) + return exp(-(mu1 + mu2) + mu1 * exp(t) + mu2 * exp(-t)) + + +def Skellam(name, mu1, mu2): + r""" + Create a discrete random variable with a Skellam distribution. + + Explanation + =========== + + The Skellam is the distribution of the difference N1 - N2 + of two statistically independent random variables N1 and N2 + each Poisson-distributed with respective expected values mu1 and mu2. + + The density of the Skellam distribution is given by + + .. math:: + f(k) := e^{-(\mu_1+\mu_2)}(\frac{\mu_1}{\mu_2})^{k/2}I_k(2\sqrt{\mu_1\mu_2}) + + Parameters + ========== + + mu1 : A non-negative value + mu2 : A non-negative value + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Skellam, density, E, variance + >>> from sympy import Symbol, pprint + + >>> z = Symbol("z", integer=True) + >>> mu1 = Symbol("mu1", positive=True) + >>> mu2 = Symbol("mu2", positive=True) + >>> X = Skellam("x", mu1, mu2) + + >>> pprint(density(X)(z), use_unicode=False) + z + - + 2 + /mu1\ -mu1 - mu2 / _____ _____\ + |---| *e *besseli\z, 2*\/ mu1 *\/ mu2 / + \mu2/ + >>> E(X) + mu1 - mu2 + >>> variance(X).expand() + mu1 + mu2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Skellam_distribution + + """ + return rv(name, SkellamDistribution, mu1, mu2) + + +#------------------------------------------------------------------------------- +# Yule-Simon distribution ------------------------------------------------------------ + +class YuleSimonDistribution(SingleDiscreteDistribution): + _argnames = ('rho',) + set = S.Naturals + + @staticmethod + def check(rho): + _value_check(rho > 0, 'rho should be positive') + + def pdf(self, k): + rho = self.rho + return rho * beta(k, rho + 1) + + def _cdf(self, x): + return Piecewise((1 - floor(x) * beta(floor(x), self.rho + 1), x >= 1), (0, True)) + + def _characteristic_function(self, t): + rho = self.rho + return rho * hyper((1, 1), (rho + 2,), exp(I*t)) * exp(I*t) / (rho + 1) + + def _moment_generating_function(self, t): + rho = self.rho + return rho * hyper((1, 1), (rho + 2,), exp(t)) * exp(t) / (rho + 1) + + +def YuleSimon(name, rho): + r""" + Create a discrete random variable with a Yule-Simon distribution. + + Explanation + =========== + + The density of the Yule-Simon distribution is given by + + .. math:: + f(k) := \rho B(k, \rho + 1) + + Parameters + ========== + + rho : A positive value + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import YuleSimon, density, E, variance + >>> from sympy import Symbol, simplify + + >>> p = 5 + >>> z = Symbol("z") + + >>> X = YuleSimon("x", p) + + >>> density(X)(z) + 5*beta(z, 6) + + >>> simplify(E(X)) + 5/4 + + >>> simplify(variance(X)) + 25/48 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Yule%E2%80%93Simon_distribution + + """ + return rv(name, YuleSimonDistribution, rho) + + +#------------------------------------------------------------------------------- +# Zeta distribution ------------------------------------------------------------ + +class ZetaDistribution(SingleDiscreteDistribution): + _argnames = ('s',) + set = S.Naturals + + @staticmethod + def check(s): + _value_check(s > 1, 's should be greater than 1') + + def pdf(self, k): + s = self.s + return 1 / (k**s * zeta(s)) + + def _characteristic_function(self, t): + return polylog(self.s, exp(I*t)) / zeta(self.s) + + def _moment_generating_function(self, t): + return polylog(self.s, exp(t)) / zeta(self.s) + + +def Zeta(name, s): + r""" + Create a discrete random variable with a Zeta distribution. + + Explanation + =========== + + The density of the Zeta distribution is given by + + .. math:: + f(k) := \frac{1}{k^s \zeta{(s)}} + + Parameters + ========== + + s : A value greater than 1 + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import Zeta, density, E, variance + >>> from sympy import Symbol + + >>> s = 5 + >>> z = Symbol("z") + + >>> X = Zeta("x", s) + + >>> density(X)(z) + 1/(z**5*zeta(5)) + + >>> E(X) + pi**4/(90*zeta(5)) + + >>> variance(X) + -pi**8/(8100*zeta(5)**2) + zeta(3)/zeta(5) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Zeta_distribution + + """ + return rv(name, ZetaDistribution, s) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/error_prop.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/error_prop.py new file mode 100644 index 0000000000000000000000000000000000000000..e6cacb894307fe60cbf096c7760e6ed57f385a91 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/error_prop.py @@ -0,0 +1,100 @@ +"""Tools for arithmetic error propagation.""" + +from itertools import repeat, combinations + +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import exp +from sympy.simplify.simplify import simplify +from sympy.stats.symbolic_probability import RandomSymbol, Variance, Covariance +from sympy.stats.rv import is_random + +_arg0_or_var = lambda var: var.args[0] if len(var.args) > 0 else var + + +def variance_prop(expr, consts=(), include_covar=False): + r"""Symbolically propagates variance (`\sigma^2`) for expressions. + This is computed as as seen in [1]_. + + Parameters + ========== + + expr : Expr + A SymPy expression to compute the variance for. + consts : sequence of Symbols, optional + Represents symbols that are known constants in the expr, + and thus have zero variance. All symbols not in consts are + assumed to be variant. + include_covar : bool, optional + Flag for whether or not to include covariances, default=False. + + Returns + ======= + + var_expr : Expr + An expression for the total variance of the expr. + The variance for the original symbols (e.g. x) are represented + via instance of the Variance symbol (e.g. Variance(x)). + + Examples + ======== + + >>> from sympy import symbols, exp + >>> from sympy.stats.error_prop import variance_prop + >>> x, y = symbols('x y') + + >>> variance_prop(x + y) + Variance(x) + Variance(y) + + >>> variance_prop(x * y) + x**2*Variance(y) + y**2*Variance(x) + + >>> variance_prop(exp(2*x)) + 4*exp(4*x)*Variance(x) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Propagation_of_uncertainty + + """ + args = expr.args + if len(args) == 0: + if expr in consts: + return S.Zero + elif is_random(expr): + return Variance(expr).doit() + elif isinstance(expr, Symbol): + return Variance(RandomSymbol(expr)).doit() + else: + return S.Zero + nargs = len(args) + var_args = list(map(variance_prop, args, repeat(consts, nargs), + repeat(include_covar, nargs))) + if isinstance(expr, Add): + var_expr = Add(*var_args) + if include_covar: + terms = [2 * Covariance(_arg0_or_var(x), _arg0_or_var(y)).expand() \ + for x, y in combinations(var_args, 2)] + var_expr += Add(*terms) + elif isinstance(expr, Mul): + terms = [v/a**2 for a, v in zip(args, var_args)] + var_expr = simplify(expr**2 * Add(*terms)) + if include_covar: + terms = [2*Covariance(_arg0_or_var(x), _arg0_or_var(y)).expand()/(a*b) \ + for (a, b), (x, y) in zip(combinations(args, 2), + combinations(var_args, 2))] + var_expr += Add(*terms) + elif isinstance(expr, Pow): + b = args[1] + v = var_args[0] * (expr * b / args[0])**2 + var_expr = simplify(v) + elif isinstance(expr, exp): + var_expr = simplify(var_args[0] * expr**2) + else: + # unknown how to proceed, return variance of whole expr. + var_expr = Variance(expr) + return var_expr diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/frv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/frv.py new file mode 100644 index 0000000000000000000000000000000000000000..498d7e4006b2b8db306a0905ed67578021e220a8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/frv.py @@ -0,0 +1,512 @@ +""" +Finite Discrete Random Variables Module + +See Also +======== +sympy.stats.frv_types +sympy.stats.rv +sympy.stats.crv +""" +from itertools import product + +from sympy.concrete.summations import Sum +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core.function import Lambda +from sympy.core.mul import Mul +from sympy.core.numbers import (I, nan) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol) +from sympy.core.sympify import sympify +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.piecewise import Piecewise +from sympy.logic.boolalg import (And, Or) +from sympy.sets.sets import Intersection +from sympy.core.containers import Dict +from sympy.core.logic import Logic +from sympy.core.relational import Relational +from sympy.core.sympify import _sympify +from sympy.sets.sets import FiniteSet +from sympy.stats.rv import (RandomDomain, ProductDomain, ConditionalDomain, + PSpace, IndependentProductPSpace, SinglePSpace, random_symbols, + sumsets, rv_subs, NamedArgsMixin, Density, Distribution) + + +class FiniteDensity(dict): + """ + A domain with Finite Density. + """ + def __call__(self, item): + """ + Make instance of a class callable. + + If item belongs to current instance of a class, return it. + + Otherwise, return 0. + """ + item = sympify(item) + if item in self: + return self[item] + else: + return 0 + + @property + def dict(self): + """ + Return item as dictionary. + """ + return dict(self) + +class FiniteDomain(RandomDomain): + """ + A domain with discrete finite support + + Represented using a FiniteSet. + """ + is_Finite = True + + @property + def symbols(self): + return FiniteSet(sym for sym, val in self.elements) + + @property + def elements(self): + return self.args[0] + + @property + def dict(self): + return FiniteSet(*[Dict(dict(el)) for el in self.elements]) + + def __contains__(self, other): + return other in self.elements + + def __iter__(self): + return self.elements.__iter__() + + def as_boolean(self): + return Or(*[And(*[Eq(sym, val) for sym, val in item]) for item in self]) + + +class SingleFiniteDomain(FiniteDomain): + """ + A FiniteDomain over a single symbol/set + + Example: The possibilities of a *single* die roll. + """ + + def __new__(cls, symbol, set): + if not isinstance(set, FiniteSet) and \ + not isinstance(set, Intersection): + set = FiniteSet(*set) + return Basic.__new__(cls, symbol, set) + + @property + def symbol(self): + return self.args[0] + + @property + def symbols(self): + return FiniteSet(self.symbol) + + @property + def set(self): + return self.args[1] + + @property + def elements(self): + return FiniteSet(*[frozenset(((self.symbol, elem), )) for elem in self.set]) + + def __iter__(self): + return (frozenset(((self.symbol, elem),)) for elem in self.set) + + def __contains__(self, other): + sym, val = tuple(other)[0] + return sym == self.symbol and val in self.set + + +class ProductFiniteDomain(ProductDomain, FiniteDomain): + """ + A Finite domain consisting of several other FiniteDomains + + Example: The possibilities of the rolls of three independent dice + """ + + def __iter__(self): + proditer = product(*self.domains) + return (sumsets(items) for items in proditer) + + @property + def elements(self): + return FiniteSet(*self) + + +class ConditionalFiniteDomain(ConditionalDomain, ProductFiniteDomain): + """ + A FiniteDomain that has been restricted by a condition + + Example: The possibilities of a die roll under the condition that the + roll is even. + """ + + def __new__(cls, domain, condition): + """ + Create a new instance of ConditionalFiniteDomain class + """ + if condition is True: + return domain + cond = rv_subs(condition) + return Basic.__new__(cls, domain, cond) + + def _test(self, elem): + """ + Test the value. If value is boolean, return it. If value is equality + relational (two objects are equal), return it with left-hand side + being equal to right-hand side. Otherwise, raise ValueError exception. + """ + val = self.condition.xreplace(dict(elem)) + if val in [True, False]: + return val + elif val.is_Equality: + return val.lhs == val.rhs + raise ValueError("Undecidable if %s" % str(val)) + + def __contains__(self, other): + return other in self.fulldomain and self._test(other) + + def __iter__(self): + return (elem for elem in self.fulldomain if self._test(elem)) + + @property + def set(self): + if isinstance(self.fulldomain, SingleFiniteDomain): + return FiniteSet(*[elem for elem in self.fulldomain.set + if frozenset(((self.fulldomain.symbol, elem),)) in self]) + else: + raise NotImplementedError( + "Not implemented on multi-dimensional conditional domain") + + def as_boolean(self): + return FiniteDomain.as_boolean(self) + + +class SingleFiniteDistribution(Distribution, NamedArgsMixin): + def __new__(cls, *args): + args = list(map(sympify, args)) + return Basic.__new__(cls, *args) + + @staticmethod + def check(*args): + pass + + @property # type: ignore + @cacheit + def dict(self): + if self.is_symbolic: + return Density(self) + return {k: self.pmf(k) for k in self.set} + + def pmf(self, *args): # to be overridden by specific distribution + raise NotImplementedError() + + @property + def set(self): # to be overridden by specific distribution + raise NotImplementedError() + + values = property(lambda self: self.dict.values) + items = property(lambda self: self.dict.items) + is_symbolic = property(lambda self: False) + __iter__ = property(lambda self: self.dict.__iter__) + __getitem__ = property(lambda self: self.dict.__getitem__) + + def __call__(self, *args): + return self.pmf(*args) + + def __contains__(self, other): + return other in self.set + + +#============================================= +#========= Probability Space =============== +#============================================= + + +class FinitePSpace(PSpace): + """ + A Finite Probability Space + + Represents the probabilities of a finite number of events. + """ + is_Finite = True + + def __new__(cls, domain, density): + density = {sympify(key): sympify(val) + for key, val in density.items()} + public_density = Dict(density) + + obj = PSpace.__new__(cls, domain, public_density) + obj._density = density + return obj + + def prob_of(self, elem): + elem = sympify(elem) + density = self._density + if isinstance(list(density.keys())[0], FiniteSet): + return density.get(elem, S.Zero) + return density.get(tuple(elem)[0][1], S.Zero) + + def where(self, condition): + assert all(r.symbol in self.symbols for r in random_symbols(condition)) + return ConditionalFiniteDomain(self.domain, condition) + + def compute_density(self, expr): + expr = rv_subs(expr, self.values) + d = FiniteDensity() + for elem in self.domain: + val = expr.xreplace(dict(elem)) + prob = self.prob_of(elem) + d[val] = d.get(val, S.Zero) + prob + return d + + @cacheit + def compute_cdf(self, expr): + d = self.compute_density(expr) + cum_prob = S.Zero + cdf = [] + for key in sorted(d): + prob = d[key] + cum_prob += prob + cdf.append((key, cum_prob)) + + return dict(cdf) + + @cacheit + def sorted_cdf(self, expr, python_float=False): + cdf = self.compute_cdf(expr) + items = list(cdf.items()) + sorted_items = sorted(items, key=lambda val_cumprob: val_cumprob[1]) + if python_float: + sorted_items = [(v, float(cum_prob)) + for v, cum_prob in sorted_items] + return sorted_items + + @cacheit + def compute_characteristic_function(self, expr): + d = self.compute_density(expr) + t = Dummy('t', real=True) + + return Lambda(t, sum(exp(I*k*t)*v for k,v in d.items())) + + @cacheit + def compute_moment_generating_function(self, expr): + d = self.compute_density(expr) + t = Dummy('t', real=True) + + return Lambda(t, sum(exp(k*t)*v for k,v in d.items())) + + def compute_expectation(self, expr, rvs=None, **kwargs): + rvs = rvs or self.values + expr = rv_subs(expr, rvs) + probs = [self.prob_of(elem) for elem in self.domain] + if isinstance(expr, (Logic, Relational)): + parse_domain = [tuple(elem)[0][1] for elem in self.domain] + bools = [expr.xreplace(dict(elem)) for elem in self.domain] + else: + parse_domain = [expr.xreplace(dict(elem)) for elem in self.domain] + bools = [True for elem in self.domain] + return sum(Piecewise((prob * elem, blv), (S.Zero, True)) + for prob, elem, blv in zip(probs, parse_domain, bools)) + + def compute_quantile(self, expr): + cdf = self.compute_cdf(expr) + p = Dummy('p', real=True) + set = ((nan, (p < 0) | (p > 1)),) + for key, value in cdf.items(): + set = set + ((key, p <= value), ) + return Lambda(p, Piecewise(*set)) + + def probability(self, condition): + cond_symbols = frozenset(rs.symbol for rs in random_symbols(condition)) + cond = rv_subs(condition) + if not cond_symbols.issubset(self.symbols): + raise ValueError("Cannot compare foreign random symbols, %s" + %(str(cond_symbols - self.symbols))) + if isinstance(condition, Relational) and \ + (not cond.free_symbols.issubset(self.domain.free_symbols)): + rv = condition.lhs if isinstance(condition.rhs, Symbol) else condition.rhs + return sum(Piecewise( + (self.prob_of(elem), condition.subs(rv, list(elem)[0][1])), + (S.Zero, True)) for elem in self.domain) + return sympify(sum(self.prob_of(elem) for elem in self.where(condition))) + + def conditional_space(self, condition): + domain = self.where(condition) + prob = self.probability(condition) + density = {key: val / prob + for key, val in self._density.items() if domain._test(key)} + return FinitePSpace(domain, density) + + def sample(self, size=(), library='scipy', seed=None): + """ + Internal sample method + + Returns dictionary mapping RandomSymbol to realization value. + """ + return {self.value: self.distribution.sample(size, library, seed)} + + +class SingleFinitePSpace(SinglePSpace, FinitePSpace): + """ + A single finite probability space + + Represents the probabilities of a set of random events that can be + attributed to a single variable/symbol. + + This class is implemented by many of the standard FiniteRV types such as + Die, Bernoulli, Coin, etc.... + """ + @property + def domain(self): + return SingleFiniteDomain(self.symbol, self.distribution.set) + + @property + def _is_symbolic(self): + """ + Helper property to check if the distribution + of the random variable is having symbolic + dimension. + """ + return self.distribution.is_symbolic + + @property + def distribution(self): + return self.args[1] + + def pmf(self, expr): + return self.distribution.pmf(expr) + + @property # type: ignore + @cacheit + def _density(self): + return {FiniteSet((self.symbol, val)): prob + for val, prob in self.distribution.dict.items()} + + @cacheit + def compute_characteristic_function(self, expr): + if self._is_symbolic: + d = self.compute_density(expr) + t = Dummy('t', real=True) + ki = Dummy('ki') + return Lambda(t, Sum(d(ki)*exp(I*ki*t), (ki, self.args[1].low, self.args[1].high))) + expr = rv_subs(expr, self.values) + return FinitePSpace(self.domain, self.distribution).compute_characteristic_function(expr) + + @cacheit + def compute_moment_generating_function(self, expr): + if self._is_symbolic: + d = self.compute_density(expr) + t = Dummy('t', real=True) + ki = Dummy('ki') + return Lambda(t, Sum(d(ki)*exp(ki*t), (ki, self.args[1].low, self.args[1].high))) + expr = rv_subs(expr, self.values) + return FinitePSpace(self.domain, self.distribution).compute_moment_generating_function(expr) + + def compute_quantile(self, expr): + if self._is_symbolic: + raise NotImplementedError("Computing quantile for random variables " + "with symbolic dimension because the bounds of searching the required " + "value is undetermined.") + expr = rv_subs(expr, self.values) + return FinitePSpace(self.domain, self.distribution).compute_quantile(expr) + + def compute_density(self, expr): + if self._is_symbolic: + rv = list(random_symbols(expr))[0] + k = Dummy('k', integer=True) + cond = True if not isinstance(expr, (Relational, Logic)) \ + else expr.subs(rv, k) + return Lambda(k, + Piecewise((self.pmf(k), And(k >= self.args[1].low, + k <= self.args[1].high, cond)), (S.Zero, True))) + expr = rv_subs(expr, self.values) + return FinitePSpace(self.domain, self.distribution).compute_density(expr) + + def compute_cdf(self, expr): + if self._is_symbolic: + d = self.compute_density(expr) + k = Dummy('k') + ki = Dummy('ki') + return Lambda(k, Sum(d(ki), (ki, self.args[1].low, k))) + expr = rv_subs(expr, self.values) + return FinitePSpace(self.domain, self.distribution).compute_cdf(expr) + + def compute_expectation(self, expr, rvs=None, **kwargs): + if self._is_symbolic: + rv = random_symbols(expr)[0] + k = Dummy('k', integer=True) + expr = expr.subs(rv, k) + cond = True if not isinstance(expr, (Relational, Logic)) \ + else expr + func = self.pmf(k) * k if cond != True else self.pmf(k) * expr + return Sum(Piecewise((func, cond), (S.Zero, True)), + (k, self.distribution.low, self.distribution.high)).doit() + + expr = _sympify(expr) + expr = rv_subs(expr, rvs) + return FinitePSpace(self.domain, self.distribution).compute_expectation(expr, rvs, **kwargs) + + def probability(self, condition): + if self._is_symbolic: + #TODO: Implement the mechanism for handling queries for symbolic sized distributions. + raise NotImplementedError("Currently, probability queries are not " + "supported for random variables with symbolic sized distributions.") + condition = rv_subs(condition) + return FinitePSpace(self.domain, self.distribution).probability(condition) + + def conditional_space(self, condition): + """ + This method is used for transferring the + computation to probability method because + conditional space of random variables with + symbolic dimensions is currently not possible. + """ + if self._is_symbolic: + self + domain = self.where(condition) + prob = self.probability(condition) + density = {key: val / prob + for key, val in self._density.items() if domain._test(key)} + return FinitePSpace(domain, density) + + +class ProductFinitePSpace(IndependentProductPSpace, FinitePSpace): + """ + A collection of several independent finite probability spaces + """ + @property + def domain(self): + return ProductFiniteDomain(*[space.domain for space in self.spaces]) + + @property # type: ignore + @cacheit + def _density(self): + proditer = product(*[iter(space._density.items()) + for space in self.spaces]) + d = {} + for items in proditer: + elems, probs = list(zip(*items)) + elem = sumsets(elems) + prob = Mul(*probs) + d[elem] = d.get(elem, S.Zero) + prob + return Dict(d) + + @property # type: ignore + @cacheit + def density(self): + return Dict(self._density) + + def probability(self, condition): + return FinitePSpace.probability(self, condition) + + def compute_density(self, expr): + return FinitePSpace.compute_density(self, expr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/frv_types.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/frv_types.py new file mode 100644 index 0000000000000000000000000000000000000000..bde656c219791c287ff445d5d215e3759271e923 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/frv_types.py @@ -0,0 +1,873 @@ +""" +Finite Discrete Random Variables - Prebuilt variable types + +Contains +======== +FiniteRV +DiscreteUniform +Die +Bernoulli +Coin +Binomial +BetaBinomial +Hypergeometric +Rademacher +IdealSoliton +RobustSoliton +""" + + +from sympy.core.cache import cacheit +from sympy.core.function import Lambda +from sympy.core.numbers import (Integer, Rational) +from sympy.core.relational import (Eq, Ge, Gt, Le, Lt) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol) +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import binomial +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.piecewise import Piecewise +from sympy.logic.boolalg import Or +from sympy.sets.contains import Contains +from sympy.sets.fancysets import Range +from sympy.sets.sets import (Intersection, Interval) +from sympy.functions.special.beta_functions import beta as beta_fn +from sympy.stats.frv import (SingleFiniteDistribution, + SingleFinitePSpace) +from sympy.stats.rv import _value_check, Density, is_random +from sympy.utilities.iterables import multiset +from sympy.utilities.misc import filldedent + + +__all__ = ['FiniteRV', +'DiscreteUniform', +'Die', +'Bernoulli', +'Coin', +'Binomial', +'BetaBinomial', +'Hypergeometric', +'Rademacher', +'IdealSoliton', +'RobustSoliton', +] + +def rv(name, cls, *args, **kwargs): + args = list(map(sympify, args)) + dist = cls(*args) + if kwargs.pop('check', True): + dist.check(*args) + pspace = SingleFinitePSpace(name, dist) + if any(is_random(arg) for arg in args): + from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution + pspace = CompoundPSpace(name, CompoundDistribution(dist)) + return pspace.value + +class FiniteDistributionHandmade(SingleFiniteDistribution): + + @property + def dict(self): + return self.args[0] + + def pmf(self, x): + x = Symbol('x') + return Lambda(x, Piecewise(*( + [(v, Eq(k, x)) for k, v in self.dict.items()] + [(S.Zero, True)]))) + + @property + def set(self): + return set(self.dict.keys()) + + @staticmethod + def check(density): + for p in density.values(): + _value_check((p >= 0, p <= 1), + "Probability at a point must be between 0 and 1.") + val = sum(density.values()) + _value_check(Eq(val, 1) != S.false, "Total Probability must be 1.") + +def FiniteRV(name, density, **kwargs): + r""" + Create a Finite Random Variable given a dict representing the density. + + Parameters + ========== + + name : Symbol + Represents name of the random variable. + density : dict + Dictionary containing the pdf of finite distribution + check : bool + If True, it will check whether the given density + integrates to 1 over the given set. If False, it + will not perform this check. Default is False. + + Examples + ======== + + >>> from sympy.stats import FiniteRV, P, E + + >>> density = {0: .1, 1: .2, 2: .3, 3: .4} + >>> X = FiniteRV('X', density) + + >>> E(X) + 2.00000000000000 + >>> P(X >= 2) + 0.700000000000000 + + Returns + ======= + + RandomSymbol + + """ + # have a default of False while `rv` should have a default of True + kwargs['check'] = kwargs.pop('check', False) + return rv(name, FiniteDistributionHandmade, density, **kwargs) + +class DiscreteUniformDistribution(SingleFiniteDistribution): + + @staticmethod + def check(*args): + # not using _value_check since there is a + # suggestion for the user + if len(set(args)) != len(args): + weights = multiset(args) + n = Integer(len(args)) + for k in weights: + weights[k] /= n + raise ValueError(filldedent(""" + Repeated args detected but set expected. For a + distribution having different weights for each + item use the following:""") + ( + '\nS("FiniteRV(%s, %s)")' % ("'X'", weights))) + + @property + def p(self): + return Rational(1, len(self.args)) + + @property # type: ignore + @cacheit + def dict(self): + return dict.fromkeys(self.set, self.p) + + @property + def set(self): + return set(self.args) + + def pmf(self, x): + if x in self.args: + return self.p + else: + return S.Zero + + +def DiscreteUniform(name, items): + r""" + Create a Finite Random Variable representing a uniform distribution over + the input set. + + Parameters + ========== + + items : list/tuple + Items over which Uniform distribution is to be made + + Examples + ======== + + >>> from sympy.stats import DiscreteUniform, density + >>> from sympy import symbols + + >>> X = DiscreteUniform('X', symbols('a b c')) # equally likely over a, b, c + >>> density(X).dict + {a: 1/3, b: 1/3, c: 1/3} + + >>> Y = DiscreteUniform('Y', list(range(5))) # distribution over a range + >>> density(Y).dict + {0: 1/5, 1: 1/5, 2: 1/5, 3: 1/5, 4: 1/5} + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Discrete_uniform_distribution + .. [2] https://mathworld.wolfram.com/DiscreteUniformDistribution.html + + """ + return rv(name, DiscreteUniformDistribution, *items) + + +class DieDistribution(SingleFiniteDistribution): + _argnames = ('sides',) + + @staticmethod + def check(sides): + _value_check((sides.is_positive, sides.is_integer), + "number of sides must be a positive integer.") + + @property + def is_symbolic(self): + return not self.sides.is_number + + @property + def high(self): + return self.sides + + @property + def low(self): + return S.One + + @property + def set(self): + if self.is_symbolic: + return Intersection(S.Naturals0, Interval(0, self.sides)) + return set(map(Integer, range(1, self.sides + 1))) + + def pmf(self, x): + x = sympify(x) + if not (x.is_number or x.is_Symbol or is_random(x)): + raise ValueError("'x' expected as an argument of type 'number', 'Symbol', or " + "'RandomSymbol' not %s" % (type(x))) + cond = Ge(x, 1) & Le(x, self.sides) & Contains(x, S.Integers) + return Piecewise((S.One/self.sides, cond), (S.Zero, True)) + +def Die(name, sides=6): + r""" + Create a Finite Random Variable representing a fair die. + + Parameters + ========== + + sides : Integer + Represents the number of sides of the Die, by default is 6 + + Examples + ======== + + >>> from sympy.stats import Die, density + >>> from sympy import Symbol + + >>> D6 = Die('D6', 6) # Six sided Die + >>> density(D6).dict + {1: 1/6, 2: 1/6, 3: 1/6, 4: 1/6, 5: 1/6, 6: 1/6} + + >>> D4 = Die('D4', 4) # Four sided Die + >>> density(D4).dict + {1: 1/4, 2: 1/4, 3: 1/4, 4: 1/4} + + >>> n = Symbol('n', positive=True, integer=True) + >>> Dn = Die('Dn', n) # n sided Die + >>> density(Dn).dict + Density(DieDistribution(n)) + >>> density(Dn).dict.subs(n, 4).doit() + {1: 1/4, 2: 1/4, 3: 1/4, 4: 1/4} + + Returns + ======= + + RandomSymbol + """ + + return rv(name, DieDistribution, sides) + + +class BernoulliDistribution(SingleFiniteDistribution): + _argnames = ('p', 'succ', 'fail') + + @staticmethod + def check(p, succ, fail): + _value_check((p >= 0, p <= 1), + "p should be in range [0, 1].") + + @property + def set(self): + return {self.succ, self.fail} + + def pmf(self, x): + if isinstance(self.succ, Symbol) and isinstance(self.fail, Symbol): + return Piecewise((self.p, x == self.succ), + (1 - self.p, x == self.fail), + (S.Zero, True)) + return Piecewise((self.p, Eq(x, self.succ)), + (1 - self.p, Eq(x, self.fail)), + (S.Zero, True)) + + +def Bernoulli(name, p, succ=1, fail=0): + r""" + Create a Finite Random Variable representing a Bernoulli process. + + Parameters + ========== + + p : Rational number between 0 and 1 + Represents probability of success + succ : Integer/symbol/string + Represents event of success + fail : Integer/symbol/string + Represents event of failure + + Examples + ======== + + >>> from sympy.stats import Bernoulli, density + >>> from sympy import S + + >>> X = Bernoulli('X', S(3)/4) # 1-0 Bernoulli variable, probability = 3/4 + >>> density(X).dict + {0: 1/4, 1: 3/4} + + >>> X = Bernoulli('X', S.Half, 'Heads', 'Tails') # A fair coin toss + >>> density(X).dict + {Heads: 1/2, Tails: 1/2} + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Bernoulli_distribution + .. [2] https://mathworld.wolfram.com/BernoulliDistribution.html + + """ + + return rv(name, BernoulliDistribution, p, succ, fail) + + +def Coin(name, p=S.Half): + r""" + Create a Finite Random Variable representing a Coin toss. + + This is an equivalent of a Bernoulli random variable with + "H" and "T" as success and failure events respectively. + + Parameters + ========== + + p : Rational Number between 0 and 1 + Represents probability of getting "Heads", by default is Half + + Examples + ======== + + >>> from sympy.stats import Coin, density + >>> from sympy import Rational + + >>> C = Coin('C') # A fair coin toss + >>> density(C).dict + {H: 1/2, T: 1/2} + + >>> C2 = Coin('C2', Rational(3, 5)) # An unfair coin + >>> density(C2).dict + {H: 3/5, T: 2/5} + + Returns + ======= + + RandomSymbol + + See Also + ======== + + sympy.stats.Binomial + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Coin_flipping + + """ + return rv(name, BernoulliDistribution, p, 'H', 'T') + + +class BinomialDistribution(SingleFiniteDistribution): + _argnames = ('n', 'p', 'succ', 'fail') + + @staticmethod + def check(n, p, succ, fail): + _value_check((n.is_integer, n.is_nonnegative), + "'n' must be nonnegative integer.") + _value_check((p <= 1, p >= 0), + "p should be in range [0, 1].") + + @property + def high(self): + return self.n + + @property + def low(self): + return S.Zero + + @property + def is_symbolic(self): + return not self.n.is_number + + @property + def set(self): + if self.is_symbolic: + return Intersection(S.Naturals0, Interval(0, self.n)) + return set(self.dict.keys()) + + def pmf(self, x): + n, p = self.n, self.p + x = sympify(x) + if not (x.is_number or x.is_Symbol or is_random(x)): + raise ValueError("'x' expected as an argument of type 'number', 'Symbol', or " + "'RandomSymbol' not %s" % (type(x))) + cond = Ge(x, 0) & Le(x, n) & Contains(x, S.Integers) + return Piecewise((binomial(n, x) * p**x * (1 - p)**(n - x), cond), (S.Zero, True)) + + @property # type: ignore + @cacheit + def dict(self): + if self.is_symbolic: + return Density(self) + return {k*self.succ + (self.n-k)*self.fail: self.pmf(k) + for k in range(0, self.n + 1)} + + +def Binomial(name, n, p, succ=1, fail=0): + r""" + Create a Finite Random Variable representing a binomial distribution. + + Parameters + ========== + + n : Positive Integer + Represents number of trials + p : Rational Number between 0 and 1 + Represents probability of success + succ : Integer/symbol/string + Represents event of success, by default is 1 + fail : Integer/symbol/string + Represents event of failure, by default is 0 + + Examples + ======== + + >>> from sympy.stats import Binomial, density + >>> from sympy import S, Symbol + + >>> X = Binomial('X', 4, S.Half) # Four "coin flips" + >>> density(X).dict + {0: 1/16, 1: 1/4, 2: 3/8, 3: 1/4, 4: 1/16} + + >>> n = Symbol('n', positive=True, integer=True) + >>> p = Symbol('p', positive=True) + >>> X = Binomial('X', n, S.Half) # n "coin flips" + >>> density(X).dict + Density(BinomialDistribution(n, 1/2, 1, 0)) + >>> density(X).dict.subs(n, 4).doit() + {0: 1/16, 1: 1/4, 2: 3/8, 3: 1/4, 4: 1/16} + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Binomial_distribution + .. [2] https://mathworld.wolfram.com/BinomialDistribution.html + + """ + + return rv(name, BinomialDistribution, n, p, succ, fail) + +#------------------------------------------------------------------------------- +# Beta-binomial distribution ---------------------------------------------------------- + +class BetaBinomialDistribution(SingleFiniteDistribution): + _argnames = ('n', 'alpha', 'beta') + + @staticmethod + def check(n, alpha, beta): + _value_check((n.is_integer, n.is_nonnegative), + "'n' must be nonnegative integer. n = %s." % str(n)) + _value_check((alpha > 0), + "'alpha' must be: alpha > 0 . alpha = %s" % str(alpha)) + _value_check((beta > 0), + "'beta' must be: beta > 0 . beta = %s" % str(beta)) + + @property + def high(self): + return self.n + + @property + def low(self): + return S.Zero + + @property + def is_symbolic(self): + return not self.n.is_number + + @property + def set(self): + if self.is_symbolic: + return Intersection(S.Naturals0, Interval(0, self.n)) + return set(map(Integer, range(self.n + 1))) + + def pmf(self, k): + n, a, b = self.n, self.alpha, self.beta + return binomial(n, k) * beta_fn(k + a, n - k + b) / beta_fn(a, b) + + +def BetaBinomial(name, n, alpha, beta): + r""" + Create a Finite Random Variable representing a Beta-binomial distribution. + + Parameters + ========== + + n : Positive Integer + Represents number of trials + alpha : Real positive number + beta : Real positive number + + Examples + ======== + + >>> from sympy.stats import BetaBinomial, density + + >>> X = BetaBinomial('X', 2, 1, 1) + >>> density(X).dict + {0: 1/3, 1: 2*beta(2, 2), 2: 1/3} + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Beta-binomial_distribution + .. [2] https://mathworld.wolfram.com/BetaBinomialDistribution.html + + """ + + return rv(name, BetaBinomialDistribution, n, alpha, beta) + + +class HypergeometricDistribution(SingleFiniteDistribution): + _argnames = ('N', 'm', 'n') + + @staticmethod + def check(n, N, m): + _value_check((N.is_integer, N.is_nonnegative), + "'N' must be nonnegative integer. N = %s." % str(N)) + _value_check((n.is_integer, n.is_nonnegative), + "'n' must be nonnegative integer. n = %s." % str(n)) + _value_check((m.is_integer, m.is_nonnegative), + "'m' must be nonnegative integer. m = %s." % str(m)) + + @property + def is_symbolic(self): + return not all(x.is_number for x in (self.N, self.m, self.n)) + + @property + def high(self): + return Piecewise((self.n, Lt(self.n, self.m) != False), (self.m, True)) + + @property + def low(self): + return Piecewise((0, Gt(0, self.n + self.m - self.N) != False), (self.n + self.m - self.N, True)) + + @property + def set(self): + N, m, n = self.N, self.m, self.n + if self.is_symbolic: + return Intersection(S.Naturals0, Interval(self.low, self.high)) + return set(range(max(0, n + m - N), min(n, m) + 1)) + + def pmf(self, k): + N, m, n = self.N, self.m, self.n + return S(binomial(m, k) * binomial(N - m, n - k))/binomial(N, n) + + +def Hypergeometric(name, N, m, n): + r""" + Create a Finite Random Variable representing a hypergeometric distribution. + + Parameters + ========== + + N : Positive Integer + Represents finite population of size N. + m : Positive Integer + Represents number of trials with required feature. + n : Positive Integer + Represents numbers of draws. + + + Examples + ======== + + >>> from sympy.stats import Hypergeometric, density + + >>> X = Hypergeometric('X', 10, 5, 3) # 10 marbles, 5 white (success), 3 draws + >>> density(X).dict + {0: 1/12, 1: 5/12, 2: 5/12, 3: 1/12} + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hypergeometric_distribution + .. [2] https://mathworld.wolfram.com/HypergeometricDistribution.html + + """ + return rv(name, HypergeometricDistribution, N, m, n) + + +class RademacherDistribution(SingleFiniteDistribution): + + @property + def set(self): + return {-1, 1} + + @property + def pmf(self): + k = Dummy('k') + return Lambda(k, Piecewise((S.Half, Or(Eq(k, -1), Eq(k, 1))), (S.Zero, True))) + +def Rademacher(name): + r""" + Create a Finite Random Variable representing a Rademacher distribution. + + Examples + ======== + + >>> from sympy.stats import Rademacher, density + + >>> X = Rademacher('X') + >>> density(X).dict + {-1: 1/2, 1: 1/2} + + Returns + ======= + + RandomSymbol + + See Also + ======== + + sympy.stats.Bernoulli + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Rademacher_distribution + + """ + return rv(name, RademacherDistribution) + +class IdealSolitonDistribution(SingleFiniteDistribution): + _argnames = ('k',) + + @staticmethod + def check(k): + _value_check(k.is_integer and k.is_positive, + "'k' must be a positive integer.") + + @property + def low(self): + return S.One + + @property + def high(self): + return self.k + + @property + def set(self): + return set(map(Integer, range(1, self.k + 1))) + + @property # type: ignore + @cacheit + def dict(self): + if self.k.is_Symbol: + return Density(self) + d = {1: Rational(1, self.k)} + d.update({i: Rational(1, i*(i - 1)) for i in range(2, self.k + 1)}) + return d + + def pmf(self, x): + x = sympify(x) + if not (x.is_number or x.is_Symbol or is_random(x)): + raise ValueError("'x' expected as an argument of type 'number', 'Symbol', or " + "'RandomSymbol' not %s" % (type(x))) + cond1 = Eq(x, 1) & x.is_integer + cond2 = Ge(x, 1) & Le(x, self.k) & x.is_integer + return Piecewise((1/self.k, cond1), (1/(x*(x - 1)), cond2), (S.Zero, True)) + +def IdealSoliton(name, k): + r""" + Create a Finite Random Variable of Ideal Soliton Distribution + + Parameters + ========== + + k : Positive Integer + Represents the number of input symbols in an LT (Luby Transform) code. + + Examples + ======== + + >>> from sympy.stats import IdealSoliton, density, P, E + >>> sol = IdealSoliton('sol', 5) + >>> density(sol).dict + {1: 1/5, 2: 1/2, 3: 1/6, 4: 1/12, 5: 1/20} + >>> density(sol).set + {1, 2, 3, 4, 5} + + >>> from sympy import Symbol + >>> k = Symbol('k', positive=True, integer=True) + >>> sol = IdealSoliton('sol', k) + >>> density(sol).dict + Density(IdealSolitonDistribution(k)) + >>> density(sol).dict.subs(k, 10).doit() + {1: 1/10, 2: 1/2, 3: 1/6, 4: 1/12, 5: 1/20, 6: 1/30, 7: 1/42, 8: 1/56, 9: 1/72, 10: 1/90} + + >>> E(sol.subs(k, 10)) + 7381/2520 + + >>> P(sol.subs(k, 4) > 2) + 1/4 + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Soliton_distribution#Ideal_distribution + .. [2] https://pages.cs.wisc.edu/~suman/courses/740/papers/luby02lt.pdf + + """ + return rv(name, IdealSolitonDistribution, k) + +class RobustSolitonDistribution(SingleFiniteDistribution): + _argnames= ('k', 'delta', 'c') + + @staticmethod + def check(k, delta, c): + _value_check(k.is_integer and k.is_positive, + "'k' must be a positive integer") + _value_check(Gt(delta, 0) and Le(delta, 1), + "'delta' must be a real number in the interval (0,1)") + _value_check(c.is_positive, + "'c' must be a positive real number.") + + @property + def R(self): + return self.c * log(self.k/self.delta) * self.k**0.5 + + @property + def Z(self): + z = 0 + for i in Range(1, round(self.k/self.R)): + z += (1/i) + z += log(self.R/self.delta) + return 1 + z * self.R/self.k + + @property + def low(self): + return S.One + + @property + def high(self): + return self.k + + @property + def set(self): + return set(map(Integer, range(1, self.k + 1))) + + @property + def is_symbolic(self): + return not (self.k.is_number and self.c.is_number and self.delta.is_number) + + def pmf(self, x): + x = sympify(x) + if not (x.is_number or x.is_Symbol or is_random(x)): + raise ValueError("'x' expected as an argument of type 'number', 'Symbol', or " + "'RandomSymbol' not %s" % (type(x))) + + cond1 = Eq(x, 1) & x.is_integer + cond2 = Ge(x, 1) & Le(x, self.k) & x.is_integer + rho = Piecewise((Rational(1, self.k), cond1), (Rational(1, x*(x-1)), cond2), (S.Zero, True)) + + cond1 = Ge(x, 1) & Le(x, round(self.k/self.R)-1) + cond2 = Eq(x, round(self.k/self.R)) + tau = Piecewise((self.R/(self.k * x), cond1), (self.R * log(self.R/self.delta)/self.k, cond2), (S.Zero, True)) + + return (rho + tau)/self.Z + +def RobustSoliton(name, k, delta, c): + r''' + Create a Finite Random Variable of Robust Soliton Distribution + + Parameters + ========== + + k : Positive Integer + Represents the number of input symbols in an LT (Luby Transform) code. + delta : Positive Rational Number + Represents the failure probability. Must be in the interval (0,1). + c : Positive Rational Number + Constant of proportionality. Values close to 1 are recommended + + Examples + ======== + + >>> from sympy.stats import RobustSoliton, density, P, E + >>> robSol = RobustSoliton('robSol', 5, 0.5, 0.01) + >>> density(robSol).dict + {1: 0.204253668152708, 2: 0.490631107897393, 3: 0.165210624506162, 4: 0.0834387731899302, 5: 0.0505633404760675} + >>> density(robSol).set + {1, 2, 3, 4, 5} + + >>> from sympy import Symbol + >>> k = Symbol('k', positive=True, integer=True) + >>> c = Symbol('c', positive=True) + >>> robSol = RobustSoliton('robSol', k, 0.5, c) + >>> density(robSol).dict + Density(RobustSolitonDistribution(k, 0.5, c)) + >>> density(robSol).dict.subs(k, 10).subs(c, 0.03).doit() + {1: 0.116641095387194, 2: 0.467045731687165, 3: 0.159984123349381, 4: 0.0821431680681869, 5: 0.0505765646770100, + 6: 0.0345781523420719, 7: 0.0253132820710503, 8: 0.0194459129233227, 9: 0.0154831166726115, 10: 0.0126733075238887} + + >>> E(robSol.subs(k, 10).subs(c, 0.05)) + 2.91358846104106 + + >>> P(robSol.subs(k, 4).subs(c, 0.1) > 2) + 0.243650614389834 + + Returns + ======= + + RandomSymbol + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Soliton_distribution#Robust_distribution + .. [2] https://www.inference.org.uk/mackay/itprnn/ps/588.596.pdf + .. [3] https://pages.cs.wisc.edu/~suman/courses/740/papers/luby02lt.pdf + + ''' + return rv(name, RobustSolitonDistribution, k, delta, c) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/joint_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/joint_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..d147942f08b998e167b246628360fa27fc8ef348 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/joint_rv.py @@ -0,0 +1,426 @@ +""" +Joint Random Variables Module + +See Also +======== +sympy.stats.rv +sympy.stats.frv +sympy.stats.crv +sympy.stats.drv +""" +from math import prod + +from sympy.core.basic import Basic +from sympy.core.function import Lambda +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol) +from sympy.core.sympify import sympify +from sympy.sets.sets import ProductSet +from sympy.tensor.indexed import Indexed +from sympy.concrete.products import Product +from sympy.concrete.summations import Sum, summation +from sympy.core.containers import Tuple +from sympy.integrals.integrals import Integral, integrate +from sympy.matrices import ImmutableMatrix, matrix2numpy, list2numpy +from sympy.stats.crv import SingleContinuousDistribution, SingleContinuousPSpace +from sympy.stats.drv import SingleDiscreteDistribution, SingleDiscretePSpace +from sympy.stats.rv import (ProductPSpace, NamedArgsMixin, Distribution, + ProductDomain, RandomSymbol, random_symbols, + SingleDomain, _symbol_converter) +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import filldedent +from sympy.external import import_module + +# __all__ = ['marginal_distribution'] + +class JointPSpace(ProductPSpace): + """ + Represents a joint probability space. Represented using symbols for + each component and a distribution. + """ + def __new__(cls, sym, dist): + if isinstance(dist, SingleContinuousDistribution): + return SingleContinuousPSpace(sym, dist) + if isinstance(dist, SingleDiscreteDistribution): + return SingleDiscretePSpace(sym, dist) + sym = _symbol_converter(sym) + return Basic.__new__(cls, sym, dist) + + @property + def set(self): + return self.domain.set + + @property + def symbol(self): + return self.args[0] + + @property + def distribution(self): + return self.args[1] + + @property + def value(self): + return JointRandomSymbol(self.symbol, self) + + @property + def component_count(self): + _set = self.distribution.set + if isinstance(_set, ProductSet): + return S(len(_set.args)) + elif isinstance(_set, Product): + return _set.limits[0][-1] + return S.One + + @property + def pdf(self): + sym = [Indexed(self.symbol, i) for i in range(self.component_count)] + return self.distribution(*sym) + + @property + def domain(self): + rvs = random_symbols(self.distribution) + if not rvs: + return SingleDomain(self.symbol, self.distribution.set) + return ProductDomain(*[rv.pspace.domain for rv in rvs]) + + def component_domain(self, index): + return self.set.args[index] + + def marginal_distribution(self, *indices): + count = self.component_count + if count.atoms(Symbol): + raise ValueError("Marginal distributions cannot be computed " + "for symbolic dimensions. It is a work under progress.") + orig = [Indexed(self.symbol, i) for i in range(count)] + all_syms = [Symbol(str(i)) for i in orig] + replace_dict = dict(zip(all_syms, orig)) + sym = tuple(Symbol(str(Indexed(self.symbol, i))) for i in indices) + limits = [[i,] for i in all_syms if i not in sym] + index = 0 + for i in range(count): + if i not in indices: + limits[index].append(self.distribution.set.args[i]) + limits[index] = tuple(limits[index]) + index += 1 + if self.distribution.is_Continuous: + f = Lambda(sym, integrate(self.distribution(*all_syms), *limits)) + elif self.distribution.is_Discrete: + f = Lambda(sym, summation(self.distribution(*all_syms), *limits)) + return f.xreplace(replace_dict) + + def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): + syms = tuple(self.value[i] for i in range(self.component_count)) + rvs = rvs or syms + if not any(i in rvs for i in syms): + return expr + expr = expr*self.pdf + for rv in rvs: + if isinstance(rv, Indexed): + expr = expr.xreplace({rv: Indexed(str(rv.base), rv.args[1])}) + elif isinstance(rv, RandomSymbol): + expr = expr.xreplace({rv: rv.symbol}) + if self.value in random_symbols(expr): + raise NotImplementedError(filldedent(''' + Expectations of expression with unindexed joint random symbols + cannot be calculated yet.''')) + limits = tuple((Indexed(str(rv.base),rv.args[1]), + self.distribution.set.args[rv.args[1]]) for rv in syms) + return Integral(expr, *limits) + + def where(self, condition): + raise NotImplementedError() + + def compute_density(self, expr): + raise NotImplementedError() + + def sample(self, size=(), library='scipy', seed=None): + """ + Internal sample method + + Returns dictionary mapping RandomSymbol to realization value. + """ + return {RandomSymbol(self.symbol, self): self.distribution.sample(size, + library=library, seed=seed)} + + def probability(self, condition): + raise NotImplementedError() + + +class SampleJointScipy: + """Returns the sample from scipy of the given distribution""" + def __new__(cls, dist, size, seed=None): + return cls._sample_scipy(dist, size, seed) + + @classmethod + def _sample_scipy(cls, dist, size, seed): + """Sample from SciPy.""" + + import numpy + if seed is None or isinstance(seed, int): + rand_state = numpy.random.default_rng(seed=seed) + else: + rand_state = seed + from scipy import stats as scipy_stats + scipy_rv_map = { + 'MultivariateNormalDistribution': lambda dist, size: scipy_stats.multivariate_normal.rvs( + mean=matrix2numpy(dist.mu).flatten(), + cov=matrix2numpy(dist.sigma), size=size, random_state=rand_state), + 'MultivariateBetaDistribution': lambda dist, size: scipy_stats.dirichlet.rvs( + alpha=list2numpy(dist.alpha, float).flatten(), size=size, random_state=rand_state), + 'MultinomialDistribution': lambda dist, size: scipy_stats.multinomial.rvs( + n=int(dist.n), p=list2numpy(dist.p, float).flatten(), size=size, random_state=rand_state) + } + + sample_shape = { + 'MultivariateNormalDistribution': lambda dist: matrix2numpy(dist.mu).flatten().shape, + 'MultivariateBetaDistribution': lambda dist: list2numpy(dist.alpha).flatten().shape, + 'MultinomialDistribution': lambda dist: list2numpy(dist.p).flatten().shape + } + + dist_list = scipy_rv_map.keys() + + if dist.__class__.__name__ not in dist_list: + return None + + samples = scipy_rv_map[dist.__class__.__name__](dist, size) + return samples.reshape(size + sample_shape[dist.__class__.__name__](dist)) + +class SampleJointNumpy: + """Returns the sample from numpy of the given distribution""" + + def __new__(cls, dist, size, seed=None): + return cls._sample_numpy(dist, size, seed) + + @classmethod + def _sample_numpy(cls, dist, size, seed): + """Sample from NumPy.""" + + import numpy + if seed is None or isinstance(seed, int): + rand_state = numpy.random.default_rng(seed=seed) + else: + rand_state = seed + numpy_rv_map = { + 'MultivariateNormalDistribution': lambda dist, size: rand_state.multivariate_normal( + mean=matrix2numpy(dist.mu, float).flatten(), + cov=matrix2numpy(dist.sigma, float), size=size), + 'MultivariateBetaDistribution': lambda dist, size: rand_state.dirichlet( + alpha=list2numpy(dist.alpha, float).flatten(), size=size), + 'MultinomialDistribution': lambda dist, size: rand_state.multinomial( + n=int(dist.n), pvals=list2numpy(dist.p, float).flatten(), size=size) + } + + sample_shape = { + 'MultivariateNormalDistribution': lambda dist: matrix2numpy(dist.mu).flatten().shape, + 'MultivariateBetaDistribution': lambda dist: list2numpy(dist.alpha).flatten().shape, + 'MultinomialDistribution': lambda dist: list2numpy(dist.p).flatten().shape + } + + dist_list = numpy_rv_map.keys() + + if dist.__class__.__name__ not in dist_list: + return None + + samples = numpy_rv_map[dist.__class__.__name__](dist, prod(size)) + return samples.reshape(size + sample_shape[dist.__class__.__name__](dist)) + +class SampleJointPymc: + """Returns the sample from pymc of the given distribution""" + + def __new__(cls, dist, size, seed=None): + return cls._sample_pymc(dist, size, seed) + + @classmethod + def _sample_pymc(cls, dist, size, seed): + """Sample from PyMC.""" + + try: + import pymc + except ImportError: + import pymc3 as pymc + pymc_rv_map = { + 'MultivariateNormalDistribution': lambda dist: + pymc.MvNormal('X', mu=matrix2numpy(dist.mu, float).flatten(), + cov=matrix2numpy(dist.sigma, float), shape=(1, dist.mu.shape[0])), + 'MultivariateBetaDistribution': lambda dist: + pymc.Dirichlet('X', a=list2numpy(dist.alpha, float).flatten()), + 'MultinomialDistribution': lambda dist: + pymc.Multinomial('X', n=int(dist.n), + p=list2numpy(dist.p, float).flatten(), shape=(1, len(dist.p))) + } + + sample_shape = { + 'MultivariateNormalDistribution': lambda dist: matrix2numpy(dist.mu).flatten().shape, + 'MultivariateBetaDistribution': lambda dist: list2numpy(dist.alpha).flatten().shape, + 'MultinomialDistribution': lambda dist: list2numpy(dist.p).flatten().shape + } + + dist_list = pymc_rv_map.keys() + + if dist.__class__.__name__ not in dist_list: + return None + + import logging + logging.getLogger("pymc3").setLevel(logging.ERROR) + with pymc.Model(): + pymc_rv_map[dist.__class__.__name__](dist) + samples = pymc.sample(draws=prod(size), chains=1, progressbar=False, random_seed=seed, return_inferencedata=False, compute_convergence_checks=False)[:]['X'] + return samples.reshape(size + sample_shape[dist.__class__.__name__](dist)) + + +_get_sample_class_jrv = { + 'scipy': SampleJointScipy, + 'pymc3': SampleJointPymc, + 'pymc': SampleJointPymc, + 'numpy': SampleJointNumpy +} + +class JointDistribution(Distribution, NamedArgsMixin): + """ + Represented by the random variables part of the joint distribution. + Contains methods for PDF, CDF, sampling, marginal densities, etc. + """ + + _argnames = ('pdf', ) + + def __new__(cls, *args): + args = list(map(sympify, args)) + for i in range(len(args)): + if isinstance(args[i], list): + args[i] = ImmutableMatrix(args[i]) + return Basic.__new__(cls, *args) + + @property + def domain(self): + return ProductDomain(self.symbols) + + @property + def pdf(self): + return self.density.args[1] + + def cdf(self, other): + if not isinstance(other, dict): + raise ValueError("%s should be of type dict, got %s"%(other, type(other))) + rvs = other.keys() + _set = self.domain.set.sets + expr = self.pdf(tuple(i.args[0] for i in self.symbols)) + for i in range(len(other)): + if rvs[i].is_Continuous: + density = Integral(expr, (rvs[i], _set[i].inf, + other[rvs[i]])) + elif rvs[i].is_Discrete: + density = Sum(expr, (rvs[i], _set[i].inf, + other[rvs[i]])) + return density + + def sample(self, size=(), library='scipy', seed=None): + """ A random realization from the distribution """ + + libraries = ('scipy', 'numpy', 'pymc3', 'pymc') + if library not in libraries: + raise NotImplementedError("Sampling from %s is not supported yet." + % str(library)) + if not import_module(library): + raise ValueError("Failed to import %s" % library) + + samps = _get_sample_class_jrv[library](self, size, seed=seed) + + if samps is not None: + return samps + raise NotImplementedError( + "Sampling for %s is not currently implemented from %s" + % (self.__class__.__name__, library) + ) + + def __call__(self, *args): + return self.pdf(*args) + +class JointRandomSymbol(RandomSymbol): + """ + Representation of random symbols with joint probability distributions + to allow indexing." + """ + def __getitem__(self, key): + if isinstance(self.pspace, JointPSpace): + if (self.pspace.component_count <= key) == True: + raise ValueError("Index keys for %s can only up to %s." % + (self.name, self.pspace.component_count - 1)) + return Indexed(self, key) + + + +class MarginalDistribution(Distribution): + """ + Represents the marginal distribution of a joint probability space. + + Initialised using a probability distribution and random variables(or + their indexed components) which should be a part of the resultant + distribution. + """ + + def __new__(cls, dist, *rvs): + if len(rvs) == 1 and iterable(rvs[0]): + rvs = tuple(rvs[0]) + if not all(isinstance(rv, (Indexed, RandomSymbol)) for rv in rvs): + raise ValueError(filldedent('''Marginal distribution can be + intitialised only in terms of random variables or indexed random + variables''')) + rvs = Tuple.fromiter(rv for rv in rvs) + if not isinstance(dist, JointDistribution) and len(random_symbols(dist)) == 0: + return dist + return Basic.__new__(cls, dist, rvs) + + def check(self): + pass + + @property + def set(self): + rvs = [i for i in self.args[1] if isinstance(i, RandomSymbol)] + return ProductSet(*[rv.pspace.set for rv in rvs]) + + @property + def symbols(self): + rvs = self.args[1] + return {rv.pspace.symbol for rv in rvs} + + def pdf(self, *x): + expr, rvs = self.args[0], self.args[1] + marginalise_out = [i for i in random_symbols(expr) if i not in rvs] + if isinstance(expr, JointDistribution): + count = len(expr.domain.args) + x = Dummy('x', real=True) + syms = tuple(Indexed(x, i) for i in count) + expr = expr.pdf(syms) + else: + syms = tuple(rv.pspace.symbol if isinstance(rv, RandomSymbol) else rv.args[0] for rv in rvs) + return Lambda(syms, self.compute_pdf(expr, marginalise_out))(*x) + + def compute_pdf(self, expr, rvs): + for rv in rvs: + lpdf = 1 + if isinstance(rv, RandomSymbol): + lpdf = rv.pspace.pdf + expr = self.marginalise_out(expr*lpdf, rv) + return expr + + def marginalise_out(self, expr, rv): + from sympy.concrete.summations import Sum + if isinstance(rv, RandomSymbol): + dom = rv.pspace.set + elif isinstance(rv, Indexed): + dom = rv.base.component_domain( + rv.pspace.component_domain(rv.args[1])) + expr = expr.xreplace({rv: rv.pspace.symbol}) + if rv.pspace.is_Continuous: + #TODO: Modify to support integration + #for all kinds of sets. + expr = Integral(expr, (rv.pspace.symbol, dom)) + elif rv.pspace.is_Discrete: + #incorporate this into `Sum`/`summation` + if dom in (S.Integers, S.Naturals, S.Naturals0): + dom = (dom.inf, dom.sup) + expr = Sum(expr, (rv.pspace.symbol, dom)) + return expr + + def __call__(self, *args): + return self.pdf(*args) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/joint_rv_types.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/joint_rv_types.py new file mode 100644 index 0000000000000000000000000000000000000000..6cee9f9aa30897593ffb7c7b930a55a38f0c518a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/joint_rv_types.py @@ -0,0 +1,945 @@ +from sympy.concrete.products import Product +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.function import Lambda +from sympy.core.mul import Mul +from sympy.core.numbers import (Integer, Rational, pi) +from sympy.core.power import Pow +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import (rf, factorial) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.bessel import besselk +from sympy.functions.special.gamma_functions import gamma +from sympy.matrices.dense import (Matrix, ones) +from sympy.sets.fancysets import Range +from sympy.sets.sets import (Intersection, Interval) +from sympy.tensor.indexed import (Indexed, IndexedBase) +from sympy.matrices import ImmutableMatrix, MatrixSymbol +from sympy.matrices.expressions.determinant import det +from sympy.matrices.expressions.matexpr import MatrixElement +from sympy.stats.joint_rv import JointDistribution, JointPSpace, MarginalDistribution +from sympy.stats.rv import _value_check, random_symbols + +__all__ = ['JointRV', +'MultivariateNormal', +'MultivariateLaplace', +'Dirichlet', +'GeneralizedMultivariateLogGamma', +'GeneralizedMultivariateLogGammaOmega', +'Multinomial', +'MultivariateBeta', +'MultivariateEwens', +'MultivariateT', +'NegativeMultinomial', +'NormalGamma' +] + +def multivariate_rv(cls, sym, *args): + args = list(map(sympify, args)) + dist = cls(*args) + args = dist.args + dist.check(*args) + return JointPSpace(sym, dist).value + + +def marginal_distribution(rv, *indices): + """ + Marginal distribution function of a joint random variable. + + Parameters + ========== + + rv : A random variable with a joint probability distribution. + indices : Component indices or the indexed random symbol + for which the joint distribution is to be calculated + + Returns + ======= + + A Lambda expression in `sym`. + + Examples + ======== + + >>> from sympy.stats import MultivariateNormal, marginal_distribution + >>> m = MultivariateNormal('X', [1, 2], [[2, 1], [1, 2]]) + >>> marginal_distribution(m, m[0])(1) + 1/(2*sqrt(pi)) + + """ + indices = list(indices) + for i in range(len(indices)): + if isinstance(indices[i], Indexed): + indices[i] = indices[i].args[1] + prob_space = rv.pspace + if not indices: + raise ValueError( + "At least one component for marginal density is needed.") + if hasattr(prob_space.distribution, '_marginal_distribution'): + return prob_space.distribution._marginal_distribution(indices, rv.symbol) + return prob_space.marginal_distribution(*indices) + + +class JointDistributionHandmade(JointDistribution): + + _argnames = ('pdf',) + is_Continuous = True + + @property + def set(self): + return self.args[1] + + +def JointRV(symbol, pdf, _set=None): + """ + Create a Joint Random Variable where each of its component is continuous, + given the following: + + Parameters + ========== + + symbol : Symbol + Represents name of the random variable. + pdf : A PDF in terms of indexed symbols of the symbol given + as the first argument + + NOTE + ==== + + As of now, the set for each component for a ``JointRV`` is + equal to the set of all integers, which cannot be changed. + + Examples + ======== + + >>> from sympy import exp, pi, Indexed, S + >>> from sympy.stats import density, JointRV + >>> x1, x2 = (Indexed('x', i) for i in (1, 2)) + >>> pdf = exp(-x1**2/2 + x1 - x2**2/2 - S(1)/2)/(2*pi) + >>> N1 = JointRV('x', pdf) #Multivariate Normal distribution + >>> density(N1)(1, 2) + exp(-2)/(2*pi) + + Returns + ======= + + RandomSymbol + + """ + #TODO: Add support for sets provided by the user + symbol = sympify(symbol) + syms = [i for i in pdf.free_symbols if isinstance(i, Indexed) + and i.base == IndexedBase(symbol)] + syms = tuple(sorted(syms, key = lambda index: index.args[1])) + _set = S.Reals**len(syms) + pdf = Lambda(syms, pdf) + dist = JointDistributionHandmade(pdf, _set) + jrv = JointPSpace(symbol, dist).value + rvs = random_symbols(pdf) + if len(rvs) != 0: + dist = MarginalDistribution(dist, (jrv,)) + return JointPSpace(symbol, dist).value + return jrv + +#------------------------------------------------------------------------------- +# Multivariate Normal distribution --------------------------------------------- + +class MultivariateNormalDistribution(JointDistribution): + _argnames = ('mu', 'sigma') + + is_Continuous=True + + @property + def set(self): + k = self.mu.shape[0] + return S.Reals**k + + @staticmethod + def check(mu, sigma): + _value_check(mu.shape[0] == sigma.shape[0], + "Size of the mean vector and covariance matrix are incorrect.") + #check if covariance matrix is positive semi definite or not. + if not isinstance(sigma, MatrixSymbol): + _value_check(sigma.is_positive_semidefinite, + "The covariance matrix must be positive semi definite. ") + + def pdf(self, *args): + mu, sigma = self.mu, self.sigma + k = mu.shape[0] + if len(args) == 1 and args[0].is_Matrix: + args = args[0] + else: + args = ImmutableMatrix(args) + x = args - mu + density = S.One/sqrt((2*pi)**(k)*det(sigma))*exp( + Rational(-1, 2)*x.transpose()*(sigma.inv()*x)) + return MatrixElement(density, 0, 0) + + def _marginal_distribution(self, indices, sym): + sym = ImmutableMatrix([Indexed(sym, i) for i in indices]) + _mu, _sigma = self.mu, self.sigma + k = self.mu.shape[0] + for i in range(k): + if i not in indices: + _mu = _mu.row_del(i) + _sigma = _sigma.col_del(i) + _sigma = _sigma.row_del(i) + return Lambda(tuple(sym), S.One/sqrt((2*pi)**(len(_mu))*det(_sigma))*exp( + Rational(-1, 2)*(_mu - sym).transpose()*(_sigma.inv()*\ + (_mu - sym)))[0]) + +def MultivariateNormal(name, mu, sigma): + r""" + Creates a continuous random variable with Multivariate Normal + Distribution. + + The density of the multivariate normal distribution can be found at [1]. + + Parameters + ========== + + mu : List representing the mean or the mean vector + sigma : Positive semidefinite square matrix + Represents covariance Matrix. + If `\sigma` is noninvertible then only sampling is supported currently + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import MultivariateNormal, density, marginal_distribution + >>> from sympy import symbols, MatrixSymbol + >>> X = MultivariateNormal('X', [3, 4], [[2, 1], [1, 2]]) + >>> y, z = symbols('y z') + >>> density(X)(y, z) + sqrt(3)*exp(-y**2/3 + y*z/3 + 2*y/3 - z**2/3 + 5*z/3 - 13/3)/(6*pi) + >>> density(X)(1, 2) + sqrt(3)*exp(-4/3)/(6*pi) + >>> marginal_distribution(X, X[1])(y) + exp(-(y - 4)**2/4)/(2*sqrt(pi)) + >>> marginal_distribution(X, X[0])(y) + exp(-(y - 3)**2/4)/(2*sqrt(pi)) + + The example below shows that it is also possible to use + symbolic parameters to define the MultivariateNormal class. + + >>> n = symbols('n', integer=True, positive=True) + >>> Sg = MatrixSymbol('Sg', n, n) + >>> mu = MatrixSymbol('mu', n, 1) + >>> obs = MatrixSymbol('obs', n, 1) + >>> X = MultivariateNormal('X', mu, Sg) + + The density of a multivariate normal can be + calculated using a matrix argument, as shown below. + + >>> density(X)(obs) + (exp(((1/2)*mu.T - (1/2)*obs.T)*Sg**(-1)*(-mu + obs))/sqrt((2*pi)**n*Determinant(Sg)))[0, 0] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Multivariate_normal_distribution + + """ + return multivariate_rv(MultivariateNormalDistribution, name, mu, sigma) + +#------------------------------------------------------------------------------- +# Multivariate Laplace distribution -------------------------------------------- + +class MultivariateLaplaceDistribution(JointDistribution): + _argnames = ('mu', 'sigma') + is_Continuous=True + + @property + def set(self): + k = self.mu.shape[0] + return S.Reals**k + + @staticmethod + def check(mu, sigma): + _value_check(mu.shape[0] == sigma.shape[0], + "Size of the mean vector and covariance matrix are incorrect.") + # check if covariance matrix is positive definite or not. + if not isinstance(sigma, MatrixSymbol): + _value_check(sigma.is_positive_definite, + "The covariance matrix must be positive definite. ") + + def pdf(self, *args): + mu, sigma = self.mu, self.sigma + mu_T = mu.transpose() + k = S(mu.shape[0]) + sigma_inv = sigma.inv() + args = ImmutableMatrix(args) + args_T = args.transpose() + x = (mu_T*sigma_inv*mu)[0] + y = (args_T*sigma_inv*args)[0] + v = 1 - k/2 + return (2 * (y/(2 + x))**(v/2) * besselk(v, sqrt((2 + x)*y)) * + exp((args_T * sigma_inv * mu)[0]) / + ((2 * pi)**(k/2) * sqrt(det(sigma)))) + + +def MultivariateLaplace(name, mu, sigma): + """ + Creates a continuous random variable with Multivariate Laplace + Distribution. + + The density of the multivariate Laplace distribution can be found at [1]. + + Parameters + ========== + + mu : List representing the mean or the mean vector + sigma : Positive definite square matrix + Represents covariance Matrix + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import MultivariateLaplace, density + >>> from sympy import symbols + >>> y, z = symbols('y z') + >>> X = MultivariateLaplace('X', [2, 4], [[3, 1], [1, 3]]) + >>> density(X)(y, z) + sqrt(2)*exp(y/4 + 5*z/4)*besselk(0, sqrt(15*y*(3*y/8 - z/8)/2 + 15*z*(-y/8 + 3*z/8)/2))/(4*pi) + >>> density(X)(1, 2) + sqrt(2)*exp(11/4)*besselk(0, sqrt(165)/4)/(4*pi) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Multivariate_Laplace_distribution + + """ + return multivariate_rv(MultivariateLaplaceDistribution, name, mu, sigma) + +#------------------------------------------------------------------------------- +# Multivariate StudentT distribution ------------------------------------------- + +class MultivariateTDistribution(JointDistribution): + _argnames = ('mu', 'shape_mat', 'dof') + is_Continuous=True + + @property + def set(self): + k = self.mu.shape[0] + return S.Reals**k + + @staticmethod + def check(mu, sigma, v): + _value_check(mu.shape[0] == sigma.shape[0], + "Size of the location vector and shape matrix are incorrect.") + # check if covariance matrix is positive definite or not. + if not isinstance(sigma, MatrixSymbol): + _value_check(sigma.is_positive_definite, + "The shape matrix must be positive definite. ") + + def pdf(self, *args): + mu, sigma = self.mu, self.shape_mat + v = S(self.dof) + k = S(mu.shape[0]) + sigma_inv = sigma.inv() + args = ImmutableMatrix(args) + x = args - mu + return gamma((k + v)/2)/(gamma(v/2)*(v*pi)**(k/2)*sqrt(det(sigma)))\ + *(1 + 1/v*(x.transpose()*sigma_inv*x)[0])**((-v - k)/2) + +def MultivariateT(syms, mu, sigma, v): + """ + Creates a joint random variable with multivariate T-distribution. + + Parameters + ========== + + syms : A symbol/str + For identifying the random variable. + mu : A list/matrix + Representing the location vector + sigma : The shape matrix for the distribution + + Examples + ======== + + >>> from sympy.stats import density, MultivariateT + >>> from sympy import Symbol + + >>> x = Symbol("x") + >>> X = MultivariateT("x", [1, 1], [[1, 0], [0, 1]], 2) + + >>> density(X)(1, 2) + 2/(9*pi) + + Returns + ======= + + RandomSymbol + + """ + return multivariate_rv(MultivariateTDistribution, syms, mu, sigma, v) + + +#------------------------------------------------------------------------------- +# Multivariate Normal Gamma distribution --------------------------------------- + +class NormalGammaDistribution(JointDistribution): + + _argnames = ('mu', 'lamda', 'alpha', 'beta') + is_Continuous=True + + @staticmethod + def check(mu, lamda, alpha, beta): + _value_check(mu.is_real, "Location must be real.") + _value_check(lamda > 0, "Lambda must be positive") + _value_check(alpha > 0, "alpha must be positive") + _value_check(beta > 0, "beta must be positive") + + @property + def set(self): + return S.Reals*Interval(0, S.Infinity) + + def pdf(self, x, tau): + beta, alpha, lamda = self.beta, self.alpha, self.lamda + mu = self.mu + + return beta**alpha*sqrt(lamda)/(gamma(alpha)*sqrt(2*pi))*\ + tau**(alpha - S.Half)*exp(-1*beta*tau)*\ + exp(-1*(lamda*tau*(x - mu)**2)/S(2)) + + def _marginal_distribution(self, indices, *sym): + if len(indices) == 2: + return self.pdf(*sym) + if indices[0] == 0: + #For marginal over `x`, return non-standardized Student-T's + #distribution + x = sym[0] + v, mu, sigma = self.alpha - S.Half, self.mu, \ + S(self.beta)/(self.lamda * self.alpha) + return Lambda(sym, gamma((v + 1)/2)/(gamma(v/2)*sqrt(pi*v)*sigma)*\ + (1 + 1/v*((x - mu)/sigma)**2)**((-v -1)/2)) + #For marginal over `tau`, return Gamma distribution as per construction + from sympy.stats.crv_types import GammaDistribution + return Lambda(sym, GammaDistribution(self.alpha, self.beta)(sym[0])) + +def NormalGamma(sym, mu, lamda, alpha, beta): + """ + Creates a bivariate joint random variable with multivariate Normal gamma + distribution. + + Parameters + ========== + + sym : A symbol/str + For identifying the random variable. + mu : A real number + The mean of the normal distribution + lamda : A positive integer + Parameter of joint distribution + alpha : A positive integer + Parameter of joint distribution + beta : A positive integer + Parameter of joint distribution + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density, NormalGamma + >>> from sympy import symbols + + >>> X = NormalGamma('x', 0, 1, 2, 3) + >>> y, z = symbols('y z') + + >>> density(X)(y, z) + 9*sqrt(2)*z**(3/2)*exp(-3*z)*exp(-y**2*z/2)/(2*sqrt(pi)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Normal-gamma_distribution + + """ + return multivariate_rv(NormalGammaDistribution, sym, mu, lamda, alpha, beta) + +#------------------------------------------------------------------------------- +# Multivariate Beta/Dirichlet distribution ------------------------------------- + +class MultivariateBetaDistribution(JointDistribution): + + _argnames = ('alpha',) + is_Continuous = True + + @staticmethod + def check(alpha): + _value_check(len(alpha) >= 2, "At least two categories should be passed.") + for a_k in alpha: + _value_check((a_k > 0) != False, "Each concentration parameter" + " should be positive.") + + @property + def set(self): + k = len(self.alpha) + return Interval(0, 1)**k + + def pdf(self, *syms): + alpha = self.alpha + B = Mul.fromiter(map(gamma, alpha))/gamma(Add(*alpha)) + return Mul.fromiter(sym**(a_k - 1) for a_k, sym in zip(alpha, syms))/B + +def MultivariateBeta(syms, *alpha): + """ + Creates a continuous random variable with Dirichlet/Multivariate Beta + Distribution. + + The density of the Dirichlet distribution can be found at [1]. + + Parameters + ========== + + alpha : Positive real numbers + Signifies concentration numbers. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density, MultivariateBeta, marginal_distribution + >>> from sympy import Symbol + >>> a1 = Symbol('a1', positive=True) + >>> a2 = Symbol('a2', positive=True) + >>> B = MultivariateBeta('B', [a1, a2]) + >>> C = MultivariateBeta('C', a1, a2) + >>> x = Symbol('x') + >>> y = Symbol('y') + >>> density(B)(x, y) + x**(a1 - 1)*y**(a2 - 1)*gamma(a1 + a2)/(gamma(a1)*gamma(a2)) + >>> marginal_distribution(C, C[0])(x) + x**(a1 - 1)*gamma(a1 + a2)/(a2*gamma(a1)*gamma(a2)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Dirichlet_distribution + .. [2] https://mathworld.wolfram.com/DirichletDistribution.html + + """ + if not isinstance(alpha[0], list): + alpha = (list(alpha),) + return multivariate_rv(MultivariateBetaDistribution, syms, alpha[0]) + +Dirichlet = MultivariateBeta + +#------------------------------------------------------------------------------- +# Multivariate Ewens distribution ---------------------------------------------- + +class MultivariateEwensDistribution(JointDistribution): + + _argnames = ('n', 'theta') + is_Discrete = True + is_Continuous = False + + @staticmethod + def check(n, theta): + _value_check((n > 0), + "sample size should be positive integer.") + _value_check(theta.is_positive, "mutation rate should be positive.") + + @property + def set(self): + if not isinstance(self.n, Integer): + i = Symbol('i', integer=True, positive=True) + return Product(Intersection(S.Naturals0, Interval(0, self.n//i)), + (i, 1, self.n)) + prod_set = Range(0, self.n + 1) + for i in range(2, self.n + 1): + prod_set *= Range(0, self.n//i + 1) + return prod_set.flatten() + + def pdf(self, *syms): + n, theta = self.n, self.theta + condi = isinstance(self.n, Integer) + if not (isinstance(syms[0], IndexedBase) or condi): + raise ValueError("Please use IndexedBase object for syms as " + "the dimension is symbolic") + term_1 = factorial(n)/rf(theta, n) + if condi: + term_2 = Mul.fromiter(theta**syms[j]/((j+1)**syms[j]*factorial(syms[j])) + for j in range(n)) + cond = Eq(sum((k + 1)*syms[k] for k in range(n)), n) + return Piecewise((term_1 * term_2, cond), (0, True)) + syms = syms[0] + j, k = symbols('j, k', positive=True, integer=True) + term_2 = Product(theta**syms[j]/((j+1)**syms[j]*factorial(syms[j])), + (j, 0, n - 1)) + cond = Eq(Sum((k + 1)*syms[k], (k, 0, n - 1)), n) + return Piecewise((term_1 * term_2, cond), (0, True)) + + +def MultivariateEwens(syms, n, theta): + """ + Creates a discrete random variable with Multivariate Ewens + Distribution. + + The density of the said distribution can be found at [1]. + + Parameters + ========== + + n : Positive integer + Size of the sample or the integer whose partitions are considered + theta : Positive real number + Denotes Mutation rate + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density, marginal_distribution, MultivariateEwens + >>> from sympy import Symbol + >>> a1 = Symbol('a1', positive=True) + >>> a2 = Symbol('a2', positive=True) + >>> ed = MultivariateEwens('E', 2, 1) + >>> density(ed)(a1, a2) + Piecewise((1/(2**a2*factorial(a1)*factorial(a2)), Eq(a1 + 2*a2, 2)), (0, True)) + >>> marginal_distribution(ed, ed[0])(a1) + Piecewise((1/factorial(a1), Eq(a1, 2)), (0, True)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Ewens%27s_sampling_formula + .. [2] https://www.jstor.org/stable/24780825 + """ + return multivariate_rv(MultivariateEwensDistribution, syms, n, theta) + +#------------------------------------------------------------------------------- +# Generalized Multivariate Log Gamma distribution ------------------------------ + +class GeneralizedMultivariateLogGammaDistribution(JointDistribution): + + _argnames = ('delta', 'v', 'lamda', 'mu') + is_Continuous=True + + def check(self, delta, v, l, mu): + _value_check((delta >= 0, delta <= 1), "delta must be in range [0, 1].") + _value_check((v > 0), "v must be positive") + for lk in l: + _value_check((lk > 0), "lamda must be a positive vector.") + for muk in mu: + _value_check((muk > 0), "mu must be a positive vector.") + _value_check(len(l) > 1,"the distribution should have at least" + " two random variables.") + + @property + def set(self): + return S.Reals**len(self.lamda) + + def pdf(self, *y): + d, v, l, mu = self.delta, self.v, self.lamda, self.mu + n = Symbol('n', negative=False, integer=True) + k = len(l) + sterm1 = Pow((1 - d), n)/\ + ((gamma(v + n)**(k - 1))*gamma(v)*gamma(n + 1)) + sterm2 = Mul.fromiter(mui*li**(-v - n) for mui, li in zip(mu, l)) + term1 = sterm1 * sterm2 + sterm3 = (v + n) * sum(mui * yi for mui, yi in zip(mu, y)) + sterm4 = sum(exp(mui * yi)/li for (mui, yi, li) in zip(mu, y, l)) + term2 = exp(sterm3 - sterm4) + return Pow(d, v) * Sum(term1 * term2, (n, 0, S.Infinity)) + +def GeneralizedMultivariateLogGamma(syms, delta, v, lamda, mu): + """ + Creates a joint random variable with generalized multivariate log gamma + distribution. + + The joint pdf can be found at [1]. + + Parameters + ========== + + syms : list/tuple/set of symbols for identifying each component + delta : A constant in range $[0, 1]$ + v : Positive real number + lamda : List of positive real numbers + mu : List of positive real numbers + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density + >>> from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGamma + >>> from sympy import symbols, S + >>> v = 1 + >>> l, mu = [1, 1, 1], [1, 1, 1] + >>> d = S.Half + >>> y = symbols('y_1:4', positive=True) + >>> Gd = GeneralizedMultivariateLogGamma('G', d, v, l, mu) + >>> density(Gd)(y[0], y[1], y[2]) + Sum(exp((n + 1)*(y_1 + y_2 + y_3) - exp(y_1) - exp(y_2) - + exp(y_3))/(2**n*gamma(n + 1)**3), (n, 0, oo))/2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Generalized_multivariate_log-gamma_distribution + .. [2] https://www.researchgate.net/publication/234137346_On_a_multivariate_log-gamma_distribution_and_the_use_of_the_distribution_in_the_Bayesian_analysis + + Note + ==== + + If the GeneralizedMultivariateLogGamma is too long to type use, + + >>> from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGamma as GMVLG + >>> Gd = GMVLG('G', d, v, l, mu) + + If you want to pass the matrix omega instead of the constant delta, then use + ``GeneralizedMultivariateLogGammaOmega``. + + """ + return multivariate_rv(GeneralizedMultivariateLogGammaDistribution, + syms, delta, v, lamda, mu) + +def GeneralizedMultivariateLogGammaOmega(syms, omega, v, lamda, mu): + """ + Extends GeneralizedMultivariateLogGamma. + + Parameters + ========== + + syms : list/tuple/set of symbols + For identifying each component + omega : A square matrix + Every element of square matrix must be absolute value of + square root of correlation coefficient + v : Positive real number + lamda : List of positive real numbers + mu : List of positive real numbers + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density + >>> from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGammaOmega + >>> from sympy import Matrix, symbols, S + >>> omega = Matrix([[1, S.Half, S.Half], [S.Half, 1, S.Half], [S.Half, S.Half, 1]]) + >>> v = 1 + >>> l, mu = [1, 1, 1], [1, 1, 1] + >>> G = GeneralizedMultivariateLogGammaOmega('G', omega, v, l, mu) + >>> y = symbols('y_1:4', positive=True) + >>> density(G)(y[0], y[1], y[2]) + sqrt(2)*Sum((1 - sqrt(2)/2)**n*exp((n + 1)*(y_1 + y_2 + y_3) - exp(y_1) - + exp(y_2) - exp(y_3))/gamma(n + 1)**3, (n, 0, oo))/2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Generalized_multivariate_log-gamma_distribution + .. [2] https://www.researchgate.net/publication/234137346_On_a_multivariate_log-gamma_distribution_and_the_use_of_the_distribution_in_the_Bayesian_analysis + + Notes + ===== + + If the GeneralizedMultivariateLogGammaOmega is too long to type use, + + >>> from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGammaOmega as GMVLGO + >>> G = GMVLGO('G', omega, v, l, mu) + + """ + _value_check((omega.is_square, isinstance(omega, Matrix)), "omega must be a" + " square matrix") + for val in omega.values(): + _value_check((val >= 0, val <= 1), + "all values in matrix must be between 0 and 1(both inclusive).") + _value_check(omega.diagonal().equals(ones(1, omega.shape[0])), + "all the elements of diagonal should be 1.") + _value_check((omega.shape[0] == len(lamda), len(lamda) == len(mu)), + "lamda, mu should be of same length and omega should " + " be of shape (length of lamda, length of mu)") + _value_check(len(lamda) > 1,"the distribution should have at least" + " two random variables.") + delta = Pow(Rational(omega.det()), Rational(1, len(lamda) - 1)) + return GeneralizedMultivariateLogGamma(syms, delta, v, lamda, mu) + + +#------------------------------------------------------------------------------- +# Multinomial distribution ----------------------------------------------------- + +class MultinomialDistribution(JointDistribution): + + _argnames = ('n', 'p') + is_Continuous=False + is_Discrete = True + + @staticmethod + def check(n, p): + _value_check(n > 0, + "number of trials must be a positive integer") + for p_k in p: + _value_check((p_k >= 0, p_k <= 1), + "probability must be in range [0, 1]") + _value_check(Eq(sum(p), 1), + "probabilities must sum to 1") + + @property + def set(self): + return Intersection(S.Naturals0, Interval(0, self.n))**len(self.p) + + def pdf(self, *x): + n, p = self.n, self.p + term_1 = factorial(n)/Mul.fromiter(factorial(x_k) for x_k in x) + term_2 = Mul.fromiter(p_k**x_k for p_k, x_k in zip(p, x)) + return Piecewise((term_1 * term_2, Eq(sum(x), n)), (0, True)) + +def Multinomial(syms, n, *p): + """ + Creates a discrete random variable with Multinomial Distribution. + + The density of the said distribution can be found at [1]. + + Parameters + ========== + + n : Positive integer + Represents number of trials + p : List of event probabilities + Must be in the range of $[0, 1]$. + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density, Multinomial, marginal_distribution + >>> from sympy import symbols + >>> x1, x2, x3 = symbols('x1, x2, x3', nonnegative=True, integer=True) + >>> p1, p2, p3 = symbols('p1, p2, p3', positive=True) + >>> M = Multinomial('M', 3, p1, p2, p3) + >>> density(M)(x1, x2, x3) + Piecewise((6*p1**x1*p2**x2*p3**x3/(factorial(x1)*factorial(x2)*factorial(x3)), + Eq(x1 + x2 + x3, 3)), (0, True)) + >>> marginal_distribution(M, M[0])(x1).subs(x1, 1) + 3*p1*p2**2 + 6*p1*p2*p3 + 3*p1*p3**2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Multinomial_distribution + .. [2] https://mathworld.wolfram.com/MultinomialDistribution.html + + """ + if not isinstance(p[0], list): + p = (list(p), ) + return multivariate_rv(MultinomialDistribution, syms, n, p[0]) + +#------------------------------------------------------------------------------- +# Negative Multinomial Distribution -------------------------------------------- + +class NegativeMultinomialDistribution(JointDistribution): + + _argnames = ('k0', 'p') + is_Continuous=False + is_Discrete = True + + @staticmethod + def check(k0, p): + _value_check(k0 > 0, + "number of failures must be a positive integer") + for p_k in p: + _value_check((p_k >= 0, p_k <= 1), + "probability must be in range [0, 1].") + _value_check(sum(p) <= 1, + "success probabilities must not be greater than 1.") + + @property + def set(self): + return Range(0, S.Infinity)**len(self.p) + + def pdf(self, *k): + k0, p = self.k0, self.p + term_1 = (gamma(k0 + sum(k))*(1 - sum(p))**k0)/gamma(k0) + term_2 = Mul.fromiter(pi**ki/factorial(ki) for pi, ki in zip(p, k)) + return term_1 * term_2 + +def NegativeMultinomial(syms, k0, *p): + """ + Creates a discrete random variable with Negative Multinomial Distribution. + + The density of the said distribution can be found at [1]. + + Parameters + ========== + + k0 : positive integer + Represents number of failures before the experiment is stopped + p : List of event probabilities + Must be in the range of $[0, 1]$ + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density, NegativeMultinomial, marginal_distribution + >>> from sympy import symbols + >>> x1, x2, x3 = symbols('x1, x2, x3', nonnegative=True, integer=True) + >>> p1, p2, p3 = symbols('p1, p2, p3', positive=True) + >>> N = NegativeMultinomial('M', 3, p1, p2, p3) + >>> N_c = NegativeMultinomial('M', 3, 0.1, 0.1, 0.1) + >>> density(N)(x1, x2, x3) + p1**x1*p2**x2*p3**x3*(-p1 - p2 - p3 + 1)**3*gamma(x1 + x2 + + x3 + 3)/(2*factorial(x1)*factorial(x2)*factorial(x3)) + >>> marginal_distribution(N_c, N_c[0])(1).evalf().round(2) + 0.25 + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Negative_multinomial_distribution + .. [2] https://mathworld.wolfram.com/NegativeBinomialDistribution.html + + """ + if not isinstance(p[0], list): + p = (list(p), ) + return multivariate_rv(NegativeMultinomialDistribution, syms, k0, p[0]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/matrix_distributions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/matrix_distributions.py new file mode 100644 index 0000000000000000000000000000000000000000..9a43c0226bc25702211a910ebbe30e280ad0cf50 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/matrix_distributions.py @@ -0,0 +1,610 @@ +from math import prod + +from sympy.core.basic import Basic +from sympy.core.numbers import pi +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp +from sympy.functions.special.gamma_functions import multigamma +from sympy.core.sympify import sympify, _sympify +from sympy.matrices import (ImmutableMatrix, Inverse, Trace, Determinant, + MatrixSymbol, MatrixBase, Transpose, MatrixSet, + matrix2numpy) +from sympy.stats.rv import (_value_check, RandomMatrixSymbol, NamedArgsMixin, PSpace, + _symbol_converter, MatrixDomain, Distribution) +from sympy.external import import_module + + +################################################################################ +#------------------------Matrix Probability Space------------------------------# +################################################################################ +class MatrixPSpace(PSpace): + """ + Represents probability space for + Matrix Distributions. + """ + def __new__(cls, sym, distribution, dim_n, dim_m): + sym = _symbol_converter(sym) + dim_n, dim_m = _sympify(dim_n), _sympify(dim_m) + if not (dim_n.is_integer and dim_m.is_integer): + raise ValueError("Dimensions should be integers") + return Basic.__new__(cls, sym, distribution, dim_n, dim_m) + + distribution = property(lambda self: self.args[1]) + symbol = property(lambda self: self.args[0]) + + @property + def domain(self): + return MatrixDomain(self.symbol, self.distribution.set) + + @property + def value(self): + return RandomMatrixSymbol(self.symbol, self.args[2], self.args[3], self) + + @property + def values(self): + return {self.value} + + def compute_density(self, expr, *args): + rms = expr.atoms(RandomMatrixSymbol) + if len(rms) > 1 or (not isinstance(expr, RandomMatrixSymbol)): + raise NotImplementedError("Currently, no algorithm has been " + "implemented to handle general expressions containing " + "multiple matrix distributions.") + return self.distribution.pdf(expr) + + def sample(self, size=(), library='scipy', seed=None): + """ + Internal sample method + + Returns dictionary mapping RandomMatrixSymbol to realization value. + """ + return {self.value: self.distribution.sample(size, library=library, seed=seed)} + + +def rv(symbol, cls, args): + args = list(map(sympify, args)) + dist = cls(*args) + dist.check(*args) + dim = dist.dimension + pspace = MatrixPSpace(symbol, dist, dim[0], dim[1]) + return pspace.value + + +class SampleMatrixScipy: + """Returns the sample from scipy of the given distribution""" + def __new__(cls, dist, size, seed=None): + return cls._sample_scipy(dist, size, seed) + + @classmethod + def _sample_scipy(cls, dist, size, seed): + """Sample from SciPy.""" + + from scipy import stats as scipy_stats + import numpy + scipy_rv_map = { + 'WishartDistribution': lambda dist, size, rand_state: scipy_stats.wishart.rvs( + df=int(dist.n), scale=matrix2numpy(dist.scale_matrix, float), size=size), + 'MatrixNormalDistribution': lambda dist, size, rand_state: scipy_stats.matrix_normal.rvs( + mean=matrix2numpy(dist.location_matrix, float), + rowcov=matrix2numpy(dist.scale_matrix_1, float), + colcov=matrix2numpy(dist.scale_matrix_2, float), size=size, random_state=rand_state) + } + + sample_shape = { + 'WishartDistribution': lambda dist: dist.scale_matrix.shape, + 'MatrixNormalDistribution' : lambda dist: dist.location_matrix.shape + } + + dist_list = scipy_rv_map.keys() + + if dist.__class__.__name__ not in dist_list: + return None + + if seed is None or isinstance(seed, int): + rand_state = numpy.random.default_rng(seed=seed) + else: + rand_state = seed + samp = scipy_rv_map[dist.__class__.__name__](dist, prod(size), rand_state) + return samp.reshape(size + sample_shape[dist.__class__.__name__](dist)) + + +class SampleMatrixNumpy: + """Returns the sample from numpy of the given distribution""" + + ### TODO: Add tests after adding matrix distributions in numpy_rv_map + def __new__(cls, dist, size, seed=None): + return cls._sample_numpy(dist, size, seed) + + @classmethod + def _sample_numpy(cls, dist, size, seed): + """Sample from NumPy.""" + + numpy_rv_map = { + } + + sample_shape = { + } + + dist_list = numpy_rv_map.keys() + + if dist.__class__.__name__ not in dist_list: + return None + + import numpy + if seed is None or isinstance(seed, int): + rand_state = numpy.random.default_rng(seed=seed) + else: + rand_state = seed + samp = numpy_rv_map[dist.__class__.__name__](dist, prod(size), rand_state) + return samp.reshape(size + sample_shape[dist.__class__.__name__](dist)) + + +class SampleMatrixPymc: + """Returns the sample from pymc of the given distribution""" + + def __new__(cls, dist, size, seed=None): + return cls._sample_pymc(dist, size, seed) + + @classmethod + def _sample_pymc(cls, dist, size, seed): + """Sample from PyMC.""" + + try: + import pymc + except ImportError: + import pymc3 as pymc + pymc_rv_map = { + 'MatrixNormalDistribution': lambda dist: pymc.MatrixNormal('X', + mu=matrix2numpy(dist.location_matrix, float), + rowcov=matrix2numpy(dist.scale_matrix_1, float), + colcov=matrix2numpy(dist.scale_matrix_2, float), + shape=dist.location_matrix.shape), + 'WishartDistribution': lambda dist: pymc.WishartBartlett('X', + nu=int(dist.n), S=matrix2numpy(dist.scale_matrix, float)) + } + + sample_shape = { + 'WishartDistribution': lambda dist: dist.scale_matrix.shape, + 'MatrixNormalDistribution' : lambda dist: dist.location_matrix.shape + } + + dist_list = pymc_rv_map.keys() + + if dist.__class__.__name__ not in dist_list: + return None + import logging + logging.getLogger("pymc").setLevel(logging.ERROR) + with pymc.Model(): + pymc_rv_map[dist.__class__.__name__](dist) + samps = pymc.sample(draws=prod(size), chains=1, progressbar=False, random_seed=seed, return_inferencedata=False, compute_convergence_checks=False)['X'] + return samps.reshape(size + sample_shape[dist.__class__.__name__](dist)) + +_get_sample_class_matrixrv = { + 'scipy': SampleMatrixScipy, + 'pymc3': SampleMatrixPymc, + 'pymc': SampleMatrixPymc, + 'numpy': SampleMatrixNumpy +} + +################################################################################ +#-------------------------Matrix Distribution----------------------------------# +################################################################################ + +class MatrixDistribution(Distribution, NamedArgsMixin): + """ + Abstract class for Matrix Distribution. + """ + def __new__(cls, *args): + args = [ImmutableMatrix(arg) if isinstance(arg, list) + else _sympify(arg) for arg in args] + return Basic.__new__(cls, *args) + + @staticmethod + def check(*args): + pass + + def __call__(self, expr): + if isinstance(expr, list): + expr = ImmutableMatrix(expr) + return self.pdf(expr) + + def sample(self, size=(), library='scipy', seed=None): + """ + Internal sample method + + Returns dictionary mapping RandomSymbol to realization value. + """ + + libraries = ['scipy', 'numpy', 'pymc3', 'pymc'] + if library not in libraries: + raise NotImplementedError("Sampling from %s is not supported yet." + % str(library)) + if not import_module(library): + raise ValueError("Failed to import %s" % library) + + samps = _get_sample_class_matrixrv[library](self, size, seed) + + if samps is not None: + return samps + raise NotImplementedError( + "Sampling for %s is not currently implemented from %s" + % (self.__class__.__name__, library) + ) + +################################################################################ +#------------------------Matrix Distribution Types-----------------------------# +################################################################################ + +#------------------------------------------------------------------------------- +# Matrix Gamma distribution ---------------------------------------------------- + +class MatrixGammaDistribution(MatrixDistribution): + + _argnames = ('alpha', 'beta', 'scale_matrix') + + @staticmethod + def check(alpha, beta, scale_matrix): + if not isinstance(scale_matrix, MatrixSymbol): + _value_check(scale_matrix.is_positive_definite, "The shape " + "matrix must be positive definite.") + _value_check(scale_matrix.is_square, "Should " + "be square matrix") + _value_check(alpha.is_positive, "Shape parameter should be positive.") + _value_check(beta.is_positive, "Scale parameter should be positive.") + + @property + def set(self): + k = self.scale_matrix.shape[0] + return MatrixSet(k, k, S.Reals) + + @property + def dimension(self): + return self.scale_matrix.shape + + def pdf(self, x): + alpha, beta, scale_matrix = self.alpha, self.beta, self.scale_matrix + p = scale_matrix.shape[0] + if isinstance(x, list): + x = ImmutableMatrix(x) + if not isinstance(x, (MatrixBase, MatrixSymbol)): + raise ValueError("%s should be an isinstance of Matrix " + "or MatrixSymbol" % str(x)) + sigma_inv_x = - Inverse(scale_matrix)*x / beta + term1 = exp(Trace(sigma_inv_x))/((beta**(p*alpha)) * multigamma(alpha, p)) + term2 = (Determinant(scale_matrix))**(-alpha) + term3 = (Determinant(x))**(alpha - S(p + 1)/2) + return term1 * term2 * term3 + +def MatrixGamma(symbol, alpha, beta, scale_matrix): + """ + Creates a random variable with Matrix Gamma Distribution. + + The density of the said distribution can be found at [1]. + + Parameters + ========== + + alpha: Positive Real number + Shape Parameter + beta: Positive Real number + Scale Parameter + scale_matrix: Positive definite real square matrix + Scale Matrix + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density, MatrixGamma + >>> from sympy import MatrixSymbol, symbols + >>> a, b = symbols('a b', positive=True) + >>> M = MatrixGamma('M', a, b, [[2, 1], [1, 2]]) + >>> X = MatrixSymbol('X', 2, 2) + >>> density(M)(X).doit() + exp(Trace(Matrix([ + [-2/3, 1/3], + [ 1/3, -2/3]])*X)/b)*Determinant(X)**(a - 3/2)/(3**a*sqrt(pi)*b**(2*a)*gamma(a)*gamma(a - 1/2)) + >>> density(M)([[1, 0], [0, 1]]).doit() + exp(-4/(3*b))/(3**a*sqrt(pi)*b**(2*a)*gamma(a)*gamma(a - 1/2)) + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Matrix_gamma_distribution + + """ + if isinstance(scale_matrix, list): + scale_matrix = ImmutableMatrix(scale_matrix) + return rv(symbol, MatrixGammaDistribution, (alpha, beta, scale_matrix)) + +#------------------------------------------------------------------------------- +# Wishart Distribution --------------------------------------------------------- + +class WishartDistribution(MatrixDistribution): + + _argnames = ('n', 'scale_matrix') + + @staticmethod + def check(n, scale_matrix): + if not isinstance(scale_matrix, MatrixSymbol): + _value_check(scale_matrix.is_positive_definite, "The shape " + "matrix must be positive definite.") + _value_check(scale_matrix.is_square, "Should " + "be square matrix") + _value_check(n.is_positive, "Shape parameter should be positive.") + + @property + def set(self): + k = self.scale_matrix.shape[0] + return MatrixSet(k, k, S.Reals) + + @property + def dimension(self): + return self.scale_matrix.shape + + def pdf(self, x): + n, scale_matrix = self.n, self.scale_matrix + p = scale_matrix.shape[0] + if isinstance(x, list): + x = ImmutableMatrix(x) + if not isinstance(x, (MatrixBase, MatrixSymbol)): + raise ValueError("%s should be an isinstance of Matrix " + "or MatrixSymbol" % str(x)) + sigma_inv_x = - Inverse(scale_matrix)*x / S(2) + term1 = exp(Trace(sigma_inv_x))/((2**(p*n/S(2))) * multigamma(n/S(2), p)) + term2 = (Determinant(scale_matrix))**(-n/S(2)) + term3 = (Determinant(x))**(S(n - p - 1)/2) + return term1 * term2 * term3 + +def Wishart(symbol, n, scale_matrix): + """ + Creates a random variable with Wishart Distribution. + + The density of the said distribution can be found at [1]. + + Parameters + ========== + + n: Positive Real number + Represents degrees of freedom + scale_matrix: Positive definite real square matrix + Scale Matrix + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy.stats import density, Wishart + >>> from sympy import MatrixSymbol, symbols + >>> n = symbols('n', positive=True) + >>> W = Wishart('W', n, [[2, 1], [1, 2]]) + >>> X = MatrixSymbol('X', 2, 2) + >>> density(W)(X).doit() + exp(Trace(Matrix([ + [-1/3, 1/6], + [ 1/6, -1/3]])*X))*Determinant(X)**(n/2 - 3/2)/(2**n*3**(n/2)*sqrt(pi)*gamma(n/2)*gamma(n/2 - 1/2)) + >>> density(W)([[1, 0], [0, 1]]).doit() + exp(-2/3)/(2**n*3**(n/2)*sqrt(pi)*gamma(n/2)*gamma(n/2 - 1/2)) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Wishart_distribution + + """ + if isinstance(scale_matrix, list): + scale_matrix = ImmutableMatrix(scale_matrix) + return rv(symbol, WishartDistribution, (n, scale_matrix)) + +#------------------------------------------------------------------------------- +# Matrix Normal distribution --------------------------------------------------- + +class MatrixNormalDistribution(MatrixDistribution): + + _argnames = ('location_matrix', 'scale_matrix_1', 'scale_matrix_2') + + @staticmethod + def check(location_matrix, scale_matrix_1, scale_matrix_2): + if not isinstance(scale_matrix_1, MatrixSymbol): + _value_check(scale_matrix_1.is_positive_definite, "The shape " + "matrix must be positive definite.") + if not isinstance(scale_matrix_2, MatrixSymbol): + _value_check(scale_matrix_2.is_positive_definite, "The shape " + "matrix must be positive definite.") + _value_check(scale_matrix_1.is_square, "Scale matrix 1 should be " + "be square matrix") + _value_check(scale_matrix_2.is_square, "Scale matrix 2 should be " + "be square matrix") + n = location_matrix.shape[0] + p = location_matrix.shape[1] + _value_check(scale_matrix_1.shape[0] == n, "Scale matrix 1 should be" + " of shape %s x %s"% (str(n), str(n))) + _value_check(scale_matrix_2.shape[0] == p, "Scale matrix 2 should be" + " of shape %s x %s"% (str(p), str(p))) + + @property + def set(self): + n, p = self.location_matrix.shape + return MatrixSet(n, p, S.Reals) + + @property + def dimension(self): + return self.location_matrix.shape + + def pdf(self, x): + M, U, V = self.location_matrix, self.scale_matrix_1, self.scale_matrix_2 + n, p = M.shape + if isinstance(x, list): + x = ImmutableMatrix(x) + if not isinstance(x, (MatrixBase, MatrixSymbol)): + raise ValueError("%s should be an isinstance of Matrix " + "or MatrixSymbol" % str(x)) + term1 = Inverse(V)*Transpose(x - M)*Inverse(U)*(x - M) + num = exp(-Trace(term1)/S(2)) + den = (2*pi)**(S(n*p)/2) * Determinant(U)**(S(p)/2) * Determinant(V)**(S(n)/2) + return num/den + +def MatrixNormal(symbol, location_matrix, scale_matrix_1, scale_matrix_2): + """ + Creates a random variable with Matrix Normal Distribution. + + The density of the said distribution can be found at [1]. + + Parameters + ========== + + location_matrix: Real ``n x p`` matrix + Represents degrees of freedom + scale_matrix_1: Positive definite matrix + Scale Matrix of shape ``n x n`` + scale_matrix_2: Positive definite matrix + Scale Matrix of shape ``p x p`` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy import MatrixSymbol + >>> from sympy.stats import density, MatrixNormal + >>> M = MatrixNormal('M', [[1, 2]], [1], [[1, 0], [0, 1]]) + >>> X = MatrixSymbol('X', 1, 2) + >>> density(M)(X).doit() + exp(-Trace((Matrix([ + [-1], + [-2]]) + X.T)*(Matrix([[-1, -2]]) + X))/2)/(2*pi) + >>> density(M)([[3, 4]]).doit() + exp(-4)/(2*pi) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Matrix_normal_distribution + + """ + if isinstance(location_matrix, list): + location_matrix = ImmutableMatrix(location_matrix) + if isinstance(scale_matrix_1, list): + scale_matrix_1 = ImmutableMatrix(scale_matrix_1) + if isinstance(scale_matrix_2, list): + scale_matrix_2 = ImmutableMatrix(scale_matrix_2) + args = (location_matrix, scale_matrix_1, scale_matrix_2) + return rv(symbol, MatrixNormalDistribution, args) + +#------------------------------------------------------------------------------- +# Matrix Student's T distribution --------------------------------------------------- + +class MatrixStudentTDistribution(MatrixDistribution): + + _argnames = ('nu', 'location_matrix', 'scale_matrix_1', 'scale_matrix_2') + + @staticmethod + def check(nu, location_matrix, scale_matrix_1, scale_matrix_2): + if not isinstance(scale_matrix_1, MatrixSymbol): + _value_check(scale_matrix_1.is_positive_definite != False, "The shape " + "matrix must be positive definite.") + if not isinstance(scale_matrix_2, MatrixSymbol): + _value_check(scale_matrix_2.is_positive_definite != False, "The shape " + "matrix must be positive definite.") + _value_check(scale_matrix_1.is_square != False, "Scale matrix 1 should be " + "be square matrix") + _value_check(scale_matrix_2.is_square != False, "Scale matrix 2 should be " + "be square matrix") + n = location_matrix.shape[0] + p = location_matrix.shape[1] + _value_check(scale_matrix_1.shape[0] == p, "Scale matrix 1 should be" + " of shape %s x %s" % (str(p), str(p))) + _value_check(scale_matrix_2.shape[0] == n, "Scale matrix 2 should be" + " of shape %s x %s" % (str(n), str(n))) + _value_check(nu.is_positive != False, "Degrees of freedom must be positive") + + @property + def set(self): + n, p = self.location_matrix.shape + return MatrixSet(n, p, S.Reals) + + @property + def dimension(self): + return self.location_matrix.shape + + def pdf(self, x): + from sympy.matrices.dense import eye + if isinstance(x, list): + x = ImmutableMatrix(x) + if not isinstance(x, (MatrixBase, MatrixSymbol)): + raise ValueError("%s should be an isinstance of Matrix " + "or MatrixSymbol" % str(x)) + nu, M, Omega, Sigma = self.nu, self.location_matrix, self.scale_matrix_1, self.scale_matrix_2 + n, p = M.shape + + K = multigamma((nu + n + p - 1)/2, p) * Determinant(Omega)**(-n/2) * Determinant(Sigma)**(-p/2) \ + / ((pi)**(n*p/2) * multigamma((nu + p - 1)/2, p)) + return K * (Determinant(eye(n) + Inverse(Sigma)*(x - M)*Inverse(Omega)*Transpose(x - M))) \ + **(-(nu + n + p -1)/2) + + + +def MatrixStudentT(symbol, nu, location_matrix, scale_matrix_1, scale_matrix_2): + """ + Creates a random variable with Matrix Gamma Distribution. + + The density of the said distribution can be found at [1]. + + Parameters + ========== + + nu: Positive Real number + degrees of freedom + location_matrix: Positive definite real square matrix + Location Matrix of shape ``n x p`` + scale_matrix_1: Positive definite real square matrix + Scale Matrix of shape ``p x p`` + scale_matrix_2: Positive definite real square matrix + Scale Matrix of shape ``n x n`` + + Returns + ======= + + RandomSymbol + + Examples + ======== + + >>> from sympy import MatrixSymbol,symbols + >>> from sympy.stats import density, MatrixStudentT + >>> v = symbols('v',positive=True) + >>> M = MatrixStudentT('M', v, [[1, 2]], [[1, 0], [0, 1]], [1]) + >>> X = MatrixSymbol('X', 1, 2) + >>> density(M)(X) + gamma(v/2 + 1)*Determinant((Matrix([[-1, -2]]) + X)*(Matrix([ + [-1], + [-2]]) + X.T) + Matrix([[1]]))**(-v/2 - 1)/(pi**1.0*gamma(v/2)*Determinant(Matrix([[1]]))**1.0*Determinant(Matrix([ + [1, 0], + [0, 1]]))**0.5) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Matrix_t-distribution + + """ + if isinstance(location_matrix, list): + location_matrix = ImmutableMatrix(location_matrix) + if isinstance(scale_matrix_1, list): + scale_matrix_1 = ImmutableMatrix(scale_matrix_1) + if isinstance(scale_matrix_2, list): + scale_matrix_2 = ImmutableMatrix(scale_matrix_2) + args = (nu, location_matrix, scale_matrix_1, scale_matrix_2) + return rv(symbol, MatrixStudentTDistribution, args) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/random_matrix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/random_matrix.py new file mode 100644 index 0000000000000000000000000000000000000000..fdd25cb9ad23fed9d3a85982b24bef33d04928f0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/random_matrix.py @@ -0,0 +1,30 @@ +from sympy.core.basic import Basic +from sympy.stats.rv import PSpace, _symbol_converter, RandomMatrixSymbol + +class RandomMatrixPSpace(PSpace): + """ + Represents probability space for + random matrices. It contains the mechanics + for handling the API calls for random matrices. + """ + def __new__(cls, sym, model=None): + sym = _symbol_converter(sym) + if model: + return Basic.__new__(cls, sym, model) + else: + return Basic.__new__(cls, sym) + + @property + def model(self): + try: + return self.args[1] + except IndexError: + return None + + def compute_density(self, expr, *args): + rms = expr.atoms(RandomMatrixSymbol) + if len(rms) > 2 or (not isinstance(expr, RandomMatrixSymbol)): + raise NotImplementedError("Currently, no algorithm has been " + "implemented to handle general expressions containing " + "multiple random matrices.") + return self.model.density(expr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/random_matrix_models.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/random_matrix_models.py new file mode 100644 index 0000000000000000000000000000000000000000..6327a248ea5919c0bbb0ffc2c984105e04fe20e9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/random_matrix_models.py @@ -0,0 +1,457 @@ +from sympy.concrete.products import Product +from sympy.concrete.summations import Sum +from sympy.core.basic import Basic +from sympy.core.function import Lambda +from sympy.core.numbers import (I, pi) +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import exp +from sympy.functions.special.gamma_functions import gamma +from sympy.integrals.integrals import Integral +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.matrices.expressions.trace import Trace +from sympy.tensor.indexed import IndexedBase +from sympy.core.sympify import _sympify +from sympy.stats.rv import _symbol_converter, Density, RandomMatrixSymbol, is_random +from sympy.stats.joint_rv_types import JointDistributionHandmade +from sympy.stats.random_matrix import RandomMatrixPSpace +from sympy.tensor.array import ArrayComprehension + +__all__ = [ + 'CircularEnsemble', + 'CircularUnitaryEnsemble', + 'CircularOrthogonalEnsemble', + 'CircularSymplecticEnsemble', + 'GaussianEnsemble', + 'GaussianUnitaryEnsemble', + 'GaussianOrthogonalEnsemble', + 'GaussianSymplecticEnsemble', + 'joint_eigen_distribution', + 'JointEigenDistribution', + 'level_spacing_distribution' +] + +@is_random.register(RandomMatrixSymbol) +def _(x): + return True + + +class RandomMatrixEnsembleModel(Basic): + """ + Base class for random matrix ensembles. + It acts as an umbrella and contains + the methods common to all the ensembles + defined in sympy.stats.random_matrix_models. + """ + def __new__(cls, sym, dim=None): + sym, dim = _symbol_converter(sym), _sympify(dim) + if dim.is_integer == False: + raise ValueError("Dimension of the random matrices must be " + "integers, received %s instead."%(dim)) + return Basic.__new__(cls, sym, dim) + + symbol = property(lambda self: self.args[0]) + dimension = property(lambda self: self.args[1]) + + def density(self, expr): + return Density(expr) + + def __call__(self, expr): + return self.density(expr) + +class GaussianEnsembleModel(RandomMatrixEnsembleModel): + """ + Abstract class for Gaussian ensembles. + Contains the properties common to all the + gaussian ensembles. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Random_matrix#Gaussian_ensembles + .. [2] https://arxiv.org/pdf/1712.07903.pdf + """ + def _compute_normalization_constant(self, beta, n): + """ + Helper function for computing normalization + constant for joint probability density of eigen + values of Gaussian ensembles. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Selberg_integral#Mehta's_integral + """ + n = S(n) + prod_term = lambda j: gamma(1 + beta*S(j)/2)/gamma(S.One + beta/S(2)) + j = Dummy('j', integer=True, positive=True) + term1 = Product(prod_term(j), (j, 1, n)).doit() + term2 = (2/(beta*n))**(beta*n*(n - 1)/4 + n/2) + term3 = (2*pi)**(n/2) + return term1 * term2 * term3 + + def _compute_joint_eigen_distribution(self, beta): + """ + Helper function for computing the joint + probability distribution of eigen values + of the random matrix. + """ + n = self.dimension + Zbn = self._compute_normalization_constant(beta, n) + l = IndexedBase('l') + i = Dummy('i', integer=True, positive=True) + j = Dummy('j', integer=True, positive=True) + k = Dummy('k', integer=True, positive=True) + term1 = exp((-S(n)/2) * Sum(l[k]**2, (k, 1, n)).doit()) + sub_term = Lambda(i, Product(Abs(l[j] - l[i])**beta, (j, i + 1, n))) + term2 = Product(sub_term(i).doit(), (i, 1, n - 1)).doit() + syms = ArrayComprehension(l[k], (k, 1, n)).doit() + return Lambda(tuple(syms), (term1 * term2)/Zbn) + +class GaussianUnitaryEnsembleModel(GaussianEnsembleModel): + @property + def normalization_constant(self): + n = self.dimension + return 2**(S(n)/2) * pi**(S(n**2)/2) + + def density(self, expr): + n, ZGUE = self.dimension, self.normalization_constant + h_pspace = RandomMatrixPSpace('P', model=self) + H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) + return Lambda(H, exp(-S(n)/2 * Trace(H**2))/ZGUE)(expr) + + def joint_eigen_distribution(self): + return self._compute_joint_eigen_distribution(S(2)) + + def level_spacing_distribution(self): + s = Dummy('s') + f = (32/pi**2)*(s**2)*exp((-4/pi)*s**2) + return Lambda(s, f) + +class GaussianOrthogonalEnsembleModel(GaussianEnsembleModel): + @property + def normalization_constant(self): + n = self.dimension + _H = MatrixSymbol('_H', n, n) + return Integral(exp(-S(n)/4 * Trace(_H**2))) + + def density(self, expr): + n, ZGOE = self.dimension, self.normalization_constant + h_pspace = RandomMatrixPSpace('P', model=self) + H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) + return Lambda(H, exp(-S(n)/4 * Trace(H**2))/ZGOE)(expr) + + def joint_eigen_distribution(self): + return self._compute_joint_eigen_distribution(S.One) + + def level_spacing_distribution(self): + s = Dummy('s') + f = (pi/2)*s*exp((-pi/4)*s**2) + return Lambda(s, f) + +class GaussianSymplecticEnsembleModel(GaussianEnsembleModel): + @property + def normalization_constant(self): + n = self.dimension + _H = MatrixSymbol('_H', n, n) + return Integral(exp(-S(n) * Trace(_H**2))) + + def density(self, expr): + n, ZGSE = self.dimension, self.normalization_constant + h_pspace = RandomMatrixPSpace('P', model=self) + H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) + return Lambda(H, exp(-S(n) * Trace(H**2))/ZGSE)(expr) + + def joint_eigen_distribution(self): + return self._compute_joint_eigen_distribution(S(4)) + + def level_spacing_distribution(self): + s = Dummy('s') + f = ((S(2)**18)/((S(3)**6)*(pi**3)))*(s**4)*exp((-64/(9*pi))*s**2) + return Lambda(s, f) + +def GaussianEnsemble(sym, dim): + sym, dim = _symbol_converter(sym), _sympify(dim) + model = GaussianEnsembleModel(sym, dim) + rmp = RandomMatrixPSpace(sym, model=model) + return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) + +def GaussianUnitaryEnsemble(sym, dim): + """ + Represents Gaussian Unitary Ensembles. + + Examples + ======== + + >>> from sympy.stats import GaussianUnitaryEnsemble as GUE, density + >>> from sympy import MatrixSymbol + >>> G = GUE('U', 2) + >>> X = MatrixSymbol('X', 2, 2) + >>> density(G)(X) + exp(-Trace(X**2))/(2*pi**2) + """ + sym, dim = _symbol_converter(sym), _sympify(dim) + model = GaussianUnitaryEnsembleModel(sym, dim) + rmp = RandomMatrixPSpace(sym, model=model) + return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) + +def GaussianOrthogonalEnsemble(sym, dim): + """ + Represents Gaussian Orthogonal Ensembles. + + Examples + ======== + + >>> from sympy.stats import GaussianOrthogonalEnsemble as GOE, density + >>> from sympy import MatrixSymbol + >>> G = GOE('U', 2) + >>> X = MatrixSymbol('X', 2, 2) + >>> density(G)(X) + exp(-Trace(X**2)/2)/Integral(exp(-Trace(_H**2)/2), _H) + """ + sym, dim = _symbol_converter(sym), _sympify(dim) + model = GaussianOrthogonalEnsembleModel(sym, dim) + rmp = RandomMatrixPSpace(sym, model=model) + return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) + +def GaussianSymplecticEnsemble(sym, dim): + """ + Represents Gaussian Symplectic Ensembles. + + Examples + ======== + + >>> from sympy.stats import GaussianSymplecticEnsemble as GSE, density + >>> from sympy import MatrixSymbol + >>> G = GSE('U', 2) + >>> X = MatrixSymbol('X', 2, 2) + >>> density(G)(X) + exp(-2*Trace(X**2))/Integral(exp(-2*Trace(_H**2)), _H) + """ + sym, dim = _symbol_converter(sym), _sympify(dim) + model = GaussianSymplecticEnsembleModel(sym, dim) + rmp = RandomMatrixPSpace(sym, model=model) + return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) + +class CircularEnsembleModel(RandomMatrixEnsembleModel): + """ + Abstract class for Circular ensembles. + Contains the properties and methods + common to all the circular ensembles. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Circular_ensemble + """ + def density(self, expr): + # TODO : Add support for Lie groups(as extensions of sympy.diffgeom) + # and define measures on them + raise NotImplementedError("Support for Haar measure hasn't been " + "implemented yet, therefore the density of " + "%s cannot be computed."%(self)) + + def _compute_joint_eigen_distribution(self, beta): + """ + Helper function to compute the joint distribution of phases + of the complex eigen values of matrices belonging to any + circular ensembles. + """ + n = self.dimension + Zbn = ((2*pi)**n)*(gamma(beta*n/2 + 1)/S(gamma(beta/2 + 1))**n) + t = IndexedBase('t') + i, j, k = (Dummy('i', integer=True), Dummy('j', integer=True), + Dummy('k', integer=True)) + syms = ArrayComprehension(t[i], (i, 1, n)).doit() + f = Product(Product(Abs(exp(I*t[k]) - exp(I*t[j]))**beta, (j, k + 1, n)).doit(), + (k, 1, n - 1)).doit() + return Lambda(tuple(syms), f/Zbn) + +class CircularUnitaryEnsembleModel(CircularEnsembleModel): + def joint_eigen_distribution(self): + return self._compute_joint_eigen_distribution(S(2)) + +class CircularOrthogonalEnsembleModel(CircularEnsembleModel): + def joint_eigen_distribution(self): + return self._compute_joint_eigen_distribution(S.One) + +class CircularSymplecticEnsembleModel(CircularEnsembleModel): + def joint_eigen_distribution(self): + return self._compute_joint_eigen_distribution(S(4)) + +def CircularEnsemble(sym, dim): + sym, dim = _symbol_converter(sym), _sympify(dim) + model = CircularEnsembleModel(sym, dim) + rmp = RandomMatrixPSpace(sym, model=model) + return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) + +def CircularUnitaryEnsemble(sym, dim): + """ + Represents Circular Unitary Ensembles. + + Examples + ======== + + >>> from sympy.stats import CircularUnitaryEnsemble as CUE + >>> from sympy.stats import joint_eigen_distribution + >>> C = CUE('U', 1) + >>> joint_eigen_distribution(C) + Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k]))**2, (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) + + Note + ==== + + As can be seen above in the example, density of CiruclarUnitaryEnsemble + is not evaluated because the exact definition is based on haar measure of + unitary group which is not unique. + """ + sym, dim = _symbol_converter(sym), _sympify(dim) + model = CircularUnitaryEnsembleModel(sym, dim) + rmp = RandomMatrixPSpace(sym, model=model) + return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) + +def CircularOrthogonalEnsemble(sym, dim): + """ + Represents Circular Orthogonal Ensembles. + + Examples + ======== + + >>> from sympy.stats import CircularOrthogonalEnsemble as COE + >>> from sympy.stats import joint_eigen_distribution + >>> C = COE('O', 1) + >>> joint_eigen_distribution(C) + Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k])), (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) + + Note + ==== + + As can be seen above in the example, density of CiruclarOrthogonalEnsemble + is not evaluated because the exact definition is based on haar measure of + unitary group which is not unique. + """ + sym, dim = _symbol_converter(sym), _sympify(dim) + model = CircularOrthogonalEnsembleModel(sym, dim) + rmp = RandomMatrixPSpace(sym, model=model) + return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) + +def CircularSymplecticEnsemble(sym, dim): + """ + Represents Circular Symplectic Ensembles. + + Examples + ======== + + >>> from sympy.stats import CircularSymplecticEnsemble as CSE + >>> from sympy.stats import joint_eigen_distribution + >>> C = CSE('S', 1) + >>> joint_eigen_distribution(C) + Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k]))**4, (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) + + Note + ==== + + As can be seen above in the example, density of CiruclarSymplecticEnsemble + is not evaluated because the exact definition is based on haar measure of + unitary group which is not unique. + """ + sym, dim = _symbol_converter(sym), _sympify(dim) + model = CircularSymplecticEnsembleModel(sym, dim) + rmp = RandomMatrixPSpace(sym, model=model) + return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) + +def joint_eigen_distribution(mat): + """ + For obtaining joint probability distribution + of eigen values of random matrix. + + Parameters + ========== + + mat: RandomMatrixSymbol + The matrix symbol whose eigen values are to be considered. + + Returns + ======= + + Lambda + + Examples + ======== + + >>> from sympy.stats import GaussianUnitaryEnsemble as GUE + >>> from sympy.stats import joint_eigen_distribution + >>> U = GUE('U', 2) + >>> joint_eigen_distribution(U) + Lambda((l[1], l[2]), exp(-l[1]**2 - l[2]**2)*Product(Abs(l[_i] - l[_j])**2, (_j, _i + 1, 2), (_i, 1, 1))/pi) + """ + if not isinstance(mat, RandomMatrixSymbol): + raise ValueError("%s is not of type, RandomMatrixSymbol."%(mat)) + return mat.pspace.model.joint_eigen_distribution() + +def JointEigenDistribution(mat): + """ + Creates joint distribution of eigen values of matrices with random + expressions. + + Parameters + ========== + + mat: Matrix + The matrix under consideration. + + Returns + ======= + + JointDistributionHandmade + + Examples + ======== + + >>> from sympy.stats import Normal, JointEigenDistribution + >>> from sympy import Matrix + >>> A = [[Normal('A00', 0, 1), Normal('A01', 0, 1)], + ... [Normal('A10', 0, 1), Normal('A11', 0, 1)]] + >>> JointEigenDistribution(Matrix(A)) + JointDistributionHandmade(-sqrt(A00**2 - 2*A00*A11 + 4*A01*A10 + A11**2)/2 + + A00/2 + A11/2, sqrt(A00**2 - 2*A00*A11 + 4*A01*A10 + A11**2)/2 + A00/2 + A11/2) + + """ + eigenvals = mat.eigenvals(multiple=True) + if not all(is_random(eigenval) for eigenval in set(eigenvals)): + raise ValueError("Eigen values do not have any random expression, " + "joint distribution cannot be generated.") + return JointDistributionHandmade(*eigenvals) + +def level_spacing_distribution(mat): + """ + For obtaining distribution of level spacings. + + Parameters + ========== + + mat: RandomMatrixSymbol + The random matrix symbol whose eigen values are + to be considered for finding the level spacings. + + Returns + ======= + + Lambda + + Examples + ======== + + >>> from sympy.stats import GaussianUnitaryEnsemble as GUE + >>> from sympy.stats import level_spacing_distribution + >>> U = GUE('U', 2) + >>> level_spacing_distribution(U) + Lambda(_s, 32*_s**2*exp(-4*_s**2/pi)/pi**2) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Random_matrix#Distribution_of_level_spacings + """ + return mat.pspace.model.level_spacing_distribution() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/rv.py new file mode 100644 index 0000000000000000000000000000000000000000..75ab54deb551b7ff3d4d06f37482a1f16a789ba6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/rv.py @@ -0,0 +1,1798 @@ +""" +Main Random Variables Module + +Defines abstract random variable type. +Contains interfaces for probability space object (PSpace) as well as standard +operators, P, E, sample, density, where, quantile + +See Also +======== + +sympy.stats.crv +sympy.stats.frv +sympy.stats.rv_interface +""" + +from __future__ import annotations +from functools import singledispatch +from math import prod + +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import (Function, Lambda) +from sympy.core.logic import fuzzy_and +from sympy.core.mul import Mul +from sympy.core.relational import (Eq, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol) +from sympy.core.sympify import sympify +from sympy.functions.special.delta_functions import DiracDelta +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.logic.boolalg import (And, Or) +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.tensor.indexed import Indexed +from sympy.utilities.lambdify import lambdify +from sympy.core.relational import Relational +from sympy.core.sympify import _sympify +from sympy.sets.sets import FiniteSet, ProductSet, Intersection +from sympy.solvers.solveset import solveset +from sympy.external import import_module +from sympy.utilities.decorator import doctest_depends_on +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import iterable + + +__doctest_requires__ = {('sample',): ['scipy']} + + +x = Symbol('x') + + +@singledispatch +def is_random(x): + return False + + +@is_random.register(Basic) +def _(x): + atoms = x.free_symbols + return any(is_random(i) for i in atoms) + + +class RandomDomain(Basic): + """ + Represents a set of variables and the values which they can take. + + See Also + ======== + + sympy.stats.crv.ContinuousDomain + sympy.stats.frv.FiniteDomain + """ + + is_ProductDomain = False + is_Finite = False + is_Continuous = False + is_Discrete = False + + def __new__(cls, symbols, *args): + symbols = FiniteSet(*symbols) + return Basic.__new__(cls, symbols, *args) + + @property + def symbols(self): + return self.args[0] + + @property + def set(self): + return self.args[1] + + def __contains__(self, other): + raise NotImplementedError() + + def compute_expectation(self, expr): + raise NotImplementedError() + + +class SingleDomain(RandomDomain): + """ + A single variable and its domain. + + See Also + ======== + + sympy.stats.crv.SingleContinuousDomain + sympy.stats.frv.SingleFiniteDomain + """ + def __new__(cls, symbol, set): + assert symbol.is_Symbol + return Basic.__new__(cls, symbol, set) + + @property + def symbol(self): + return self.args[0] + + @property + def symbols(self): + return FiniteSet(self.symbol) + + def __contains__(self, other): + if len(other) != 1: + return False + sym, val = tuple(other)[0] + return self.symbol == sym and val in self.set + + +class MatrixDomain(RandomDomain): + """ + A Random Matrix variable and its domain. + + """ + def __new__(cls, symbol, set): + symbol, set = _symbol_converter(symbol), _sympify(set) + return Basic.__new__(cls, symbol, set) + + @property + def symbol(self): + return self.args[0] + + @property + def symbols(self): + return FiniteSet(self.symbol) + + +class ConditionalDomain(RandomDomain): + """ + A RandomDomain with an attached condition. + + See Also + ======== + + sympy.stats.crv.ConditionalContinuousDomain + sympy.stats.frv.ConditionalFiniteDomain + """ + def __new__(cls, fulldomain, condition): + condition = condition.xreplace({rs: rs.symbol + for rs in random_symbols(condition)}) + return Basic.__new__(cls, fulldomain, condition) + + @property + def symbols(self): + return self.fulldomain.symbols + + @property + def fulldomain(self): + return self.args[0] + + @property + def condition(self): + return self.args[1] + + @property + def set(self): + raise NotImplementedError("Set of Conditional Domain not Implemented") + + def as_boolean(self): + return And(self.fulldomain.as_boolean(), self.condition) + + +class PSpace(Basic): + """ + A Probability Space. + + Explanation + =========== + + Probability Spaces encode processes that equal different values + probabilistically. These underly Random Symbols which occur in SymPy + expressions and contain the mechanics to evaluate statistical statements. + + See Also + ======== + + sympy.stats.crv.ContinuousPSpace + sympy.stats.frv.FinitePSpace + """ + + is_Finite: bool | None = None # Fails test if not set to None + is_Continuous: bool | None = None # Fails test if not set to None + is_Discrete: bool | None = None # Fails test if not set to None + is_real: bool | None + + @property + def domain(self): + return self.args[0] + + @property + def density(self): + return self.args[1] + + @property + def values(self): + return frozenset(RandomSymbol(sym, self) for sym in self.symbols) + + @property + def symbols(self): + return self.domain.symbols + + def where(self, condition): + raise NotImplementedError() + + def compute_density(self, expr): + raise NotImplementedError() + + def sample(self, size=(), library='scipy', seed=None): + raise NotImplementedError() + + def probability(self, condition): + raise NotImplementedError() + + def compute_expectation(self, expr): + raise NotImplementedError() + + +class SinglePSpace(PSpace): + """ + Represents the probabilities of a set of random events that can be + attributed to a single variable/symbol. + """ + def __new__(cls, s, distribution): + s = _symbol_converter(s) + return Basic.__new__(cls, s, distribution) + + @property + def value(self): + return RandomSymbol(self.symbol, self) + + @property + def symbol(self): + return self.args[0] + + @property + def distribution(self): + return self.args[1] + + @property + def pdf(self): + return self.distribution.pdf(self.symbol) + + +class RandomSymbol(Expr): + """ + Random Symbols represent ProbabilitySpaces in SymPy Expressions. + In principle they can take on any value that their symbol can take on + within the associated PSpace with probability determined by the PSpace + Density. + + Explanation + =========== + + Random Symbols contain pspace and symbol properties. + The pspace property points to the represented Probability Space + The symbol is a standard SymPy Symbol that is used in that probability space + for example in defining a density. + + You can form normal SymPy expressions using RandomSymbols and operate on + those expressions with the Functions + + E - Expectation of a random expression + P - Probability of a condition + density - Probability Density of an expression + given - A new random expression (with new random symbols) given a condition + + An object of the RandomSymbol type should almost never be created by the + user. They tend to be created instead by the PSpace class's value method. + Traditionally a user does not even do this but instead calls one of the + convenience functions Normal, Exponential, Coin, Die, FiniteRV, etc.... + """ + + def __new__(cls, symbol, pspace=None): + from sympy.stats.joint_rv import JointRandomSymbol + if pspace is None: + # Allow single arg, representing pspace == PSpace() + pspace = PSpace() + symbol = _symbol_converter(symbol) + if not isinstance(pspace, PSpace): + raise TypeError("pspace variable should be of type PSpace") + if cls == JointRandomSymbol and isinstance(pspace, SinglePSpace): + cls = RandomSymbol + return Basic.__new__(cls, symbol, pspace) + + is_finite = True + is_symbol = True + is_Atom = True + + _diff_wrt = True + + pspace = property(lambda self: self.args[1]) + symbol = property(lambda self: self.args[0]) + name = property(lambda self: self.symbol.name) + + def _eval_is_positive(self): + return self.symbol.is_positive + + def _eval_is_integer(self): + return self.symbol.is_integer + + def _eval_is_real(self): + return self.symbol.is_real or self.pspace.is_real + + @property + def is_commutative(self): + return self.symbol.is_commutative + + @property + def free_symbols(self): + return {self} + +class RandomIndexedSymbol(RandomSymbol): + + def __new__(cls, idx_obj, pspace=None): + if pspace is None: + # Allow single arg, representing pspace == PSpace() + pspace = PSpace() + if not isinstance(idx_obj, (Indexed, Function)): + raise TypeError("An Function or Indexed object is expected not %s"%(idx_obj)) + return Basic.__new__(cls, idx_obj, pspace) + + symbol = property(lambda self: self.args[0]) + name = property(lambda self: str(self.args[0])) + + @property + def key(self): + if isinstance(self.symbol, Indexed): + return self.symbol.args[1] + elif isinstance(self.symbol, Function): + return self.symbol.args[0] + + @property + def free_symbols(self): + if self.key.free_symbols: + free_syms = self.key.free_symbols + free_syms.add(self) + return free_syms + return {self} + + @property + def pspace(self): + return self.args[1] + +class RandomMatrixSymbol(RandomSymbol, MatrixSymbol): # type: ignore + def __new__(cls, symbol, n, m, pspace=None): + n, m = _sympify(n), _sympify(m) + symbol = _symbol_converter(symbol) + if pspace is None: + # Allow single arg, representing pspace == PSpace() + pspace = PSpace() + return Basic.__new__(cls, symbol, n, m, pspace) + + symbol = property(lambda self: self.args[0]) + pspace = property(lambda self: self.args[3]) + + +class ProductPSpace(PSpace): + """ + Abstract class for representing probability spaces with multiple random + variables. + + See Also + ======== + + sympy.stats.rv.IndependentProductPSpace + sympy.stats.joint_rv.JointPSpace + """ + pass + +class IndependentProductPSpace(ProductPSpace): + """ + A probability space resulting from the merger of two independent probability + spaces. + + Often created using the function, pspace. + """ + + def __new__(cls, *spaces): + rs_space_dict = {} + for space in spaces: + for value in space.values: + rs_space_dict[value] = space + + symbols = FiniteSet(*[val.symbol for val in rs_space_dict.keys()]) + + # Overlapping symbols + from sympy.stats.joint_rv import MarginalDistribution + from sympy.stats.compound_rv import CompoundDistribution + if len(symbols) < sum(len(space.symbols) for space in spaces if not + isinstance(space.distribution, ( + CompoundDistribution, MarginalDistribution))): + raise ValueError("Overlapping Random Variables") + + if all(space.is_Finite for space in spaces): + from sympy.stats.frv import ProductFinitePSpace + cls = ProductFinitePSpace + + obj = Basic.__new__(cls, *FiniteSet(*spaces)) + + return obj + + @property + def pdf(self): + p = Mul(*[space.pdf for space in self.spaces]) + return p.subs({rv: rv.symbol for rv in self.values}) + + @property + def rs_space_dict(self): + d = {} + for space in self.spaces: + for value in space.values: + d[value] = space + return d + + @property + def symbols(self): + return FiniteSet(*[val.symbol for val in self.rs_space_dict.keys()]) + + @property + def spaces(self): + return FiniteSet(*self.args) + + @property + def values(self): + return sumsets(space.values for space in self.spaces) + + def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): + rvs = rvs or self.values + rvs = frozenset(rvs) + for space in self.spaces: + expr = space.compute_expectation(expr, rvs & space.values, evaluate=False, **kwargs) + if evaluate and hasattr(expr, 'doit'): + return expr.doit(**kwargs) + return expr + + @property + def domain(self): + return ProductDomain(*[space.domain for space in self.spaces]) + + @property + def density(self): + raise NotImplementedError("Density not available for ProductSpaces") + + def sample(self, size=(), library='scipy', seed=None): + return {k: v for space in self.spaces + for k, v in space.sample(size=size, library=library, seed=seed).items()} + + + def probability(self, condition, **kwargs): + cond_inv = False + if isinstance(condition, Ne): + condition = Eq(condition.args[0], condition.args[1]) + cond_inv = True + elif isinstance(condition, And): # they are independent + return Mul(*[self.probability(arg) for arg in condition.args]) + elif isinstance(condition, Or): # they are independent + return Add(*[self.probability(arg) for arg in condition.args]) + expr = condition.lhs - condition.rhs + rvs = random_symbols(expr) + dens = self.compute_density(expr) + if any(pspace(rv).is_Continuous for rv in rvs): + from sympy.stats.crv import SingleContinuousPSpace + from sympy.stats.crv_types import ContinuousDistributionHandmade + if expr in self.values: + # Marginalize all other random symbols out of the density + randomsymbols = tuple(set(self.values) - frozenset([expr])) + symbols = tuple(rs.symbol for rs in randomsymbols) + pdf = self.domain.integrate(self.pdf, symbols, **kwargs) + return Lambda(expr.symbol, pdf) + dens = ContinuousDistributionHandmade(dens) + z = Dummy('z', real=True) + space = SingleContinuousPSpace(z, dens) + result = space.probability(condition.__class__(space.value, 0)) + else: + from sympy.stats.drv import SingleDiscretePSpace + from sympy.stats.drv_types import DiscreteDistributionHandmade + dens = DiscreteDistributionHandmade(dens) + z = Dummy('z', integer=True) + space = SingleDiscretePSpace(z, dens) + result = space.probability(condition.__class__(space.value, 0)) + return result if not cond_inv else S.One - result + + def compute_density(self, expr, **kwargs): + rvs = random_symbols(expr) + if any(pspace(rv).is_Continuous for rv in rvs): + z = Dummy('z', real=True) + expr = self.compute_expectation(DiracDelta(expr - z), + **kwargs) + else: + z = Dummy('z', integer=True) + expr = self.compute_expectation(KroneckerDelta(expr, z), + **kwargs) + return Lambda(z, expr) + + def compute_cdf(self, expr, **kwargs): + raise ValueError("CDF not well defined on multivariate expressions") + + def conditional_space(self, condition, normalize=True, **kwargs): + rvs = random_symbols(condition) + condition = condition.xreplace({rv: rv.symbol for rv in self.values}) + pspaces = [pspace(rv) for rv in rvs] + if any(ps.is_Continuous for ps in pspaces): + from sympy.stats.crv import (ConditionalContinuousDomain, + ContinuousPSpace) + space = ContinuousPSpace + domain = ConditionalContinuousDomain(self.domain, condition) + elif any(ps.is_Discrete for ps in pspaces): + from sympy.stats.drv import (ConditionalDiscreteDomain, + DiscretePSpace) + space = DiscretePSpace + domain = ConditionalDiscreteDomain(self.domain, condition) + elif all(ps.is_Finite for ps in pspaces): + from sympy.stats.frv import FinitePSpace + return FinitePSpace.conditional_space(self, condition) + if normalize: + replacement = {rv: Dummy(str(rv)) for rv in self.symbols} + norm = domain.compute_expectation(self.pdf, **kwargs) + pdf = self.pdf / norm.xreplace(replacement) + # XXX: Converting symbols from set to tuple. The order matters to + # Lambda though so we shouldn't be starting with a set here... + density = Lambda(tuple(domain.symbols), pdf) + + return space(domain, density) + +class ProductDomain(RandomDomain): + """ + A domain resulting from the merger of two independent domains. + + See Also + ======== + sympy.stats.crv.ProductContinuousDomain + sympy.stats.frv.ProductFiniteDomain + """ + is_ProductDomain = True + + def __new__(cls, *domains): + # Flatten any product of products + domains2 = [] + for domain in domains: + if not domain.is_ProductDomain: + domains2.append(domain) + else: + domains2.extend(domain.domains) + domains2 = FiniteSet(*domains2) + + if all(domain.is_Finite for domain in domains2): + from sympy.stats.frv import ProductFiniteDomain + cls = ProductFiniteDomain + if all(domain.is_Continuous for domain in domains2): + from sympy.stats.crv import ProductContinuousDomain + cls = ProductContinuousDomain + if all(domain.is_Discrete for domain in domains2): + from sympy.stats.drv import ProductDiscreteDomain + cls = ProductDiscreteDomain + + return Basic.__new__(cls, *domains2) + + @property + def sym_domain_dict(self): + return {symbol: domain for domain in self.domains + for symbol in domain.symbols} + + @property + def symbols(self): + return FiniteSet(*[sym for domain in self.domains + for sym in domain.symbols]) + + @property + def domains(self): + return self.args + + @property + def set(self): + return ProductSet(*(domain.set for domain in self.domains)) + + def __contains__(self, other): + # Split event into each subdomain + for domain in self.domains: + # Collect the parts of this event which associate to this domain + elem = frozenset([item for item in other + if sympify(domain.symbols.contains(item[0])) + is S.true]) + # Test this sub-event + if elem not in domain: + return False + # All subevents passed + return True + + def as_boolean(self): + return And(*[domain.as_boolean() for domain in self.domains]) + + +def random_symbols(expr): + """ + Returns all RandomSymbols within a SymPy Expression. + """ + atoms = getattr(expr, 'atoms', None) + if atoms is not None: + comp = lambda rv: rv.symbol.name + l = list(atoms(RandomSymbol)) + return sorted(l, key=comp) + else: + return [] + + +def pspace(expr): + """ + Returns the underlying Probability Space of a random expression. + + For internal use. + + Examples + ======== + + >>> from sympy.stats import pspace, Normal + >>> X = Normal('X', 0, 1) + >>> pspace(2*X + 1) == X.pspace + True + """ + expr = sympify(expr) + if isinstance(expr, RandomSymbol) and expr.pspace is not None: + return expr.pspace + if expr.has(RandomMatrixSymbol): + rm = list(expr.atoms(RandomMatrixSymbol))[0] + return rm.pspace + + rvs = random_symbols(expr) + if not rvs: + raise ValueError("Expression containing Random Variable expected, not %s" % (expr)) + # If only one space present + if all(rv.pspace == rvs[0].pspace for rv in rvs): + return rvs[0].pspace + from sympy.stats.compound_rv import CompoundPSpace + from sympy.stats.stochastic_process import StochasticPSpace + for rv in rvs: + if isinstance(rv.pspace, (CompoundPSpace, StochasticPSpace)): + return rv.pspace + # Otherwise make a product space + return IndependentProductPSpace(*[rv.pspace for rv in rvs]) + + +def sumsets(sets): + """ + Union of sets + """ + return frozenset().union(*sets) + + +def rs_swap(a, b): + """ + Build a dictionary to swap RandomSymbols based on their underlying symbol. + + i.e. + if ``X = ('x', pspace1)`` + and ``Y = ('x', pspace2)`` + then ``X`` and ``Y`` match and the key, value pair + ``{X:Y}`` will appear in the result + + Inputs: collections a and b of random variables which share common symbols + Output: dict mapping RVs in a to RVs in b + """ + d = {} + for rsa in a: + d[rsa] = [rsb for rsb in b if rsa.symbol == rsb.symbol][0] + return d + + +def given(expr, condition=None, **kwargs): + r""" Conditional Random Expression. + + Explanation + =========== + + From a random expression and a condition on that expression creates a new + probability space from the condition and returns the same expression on that + conditional probability space. + + Examples + ======== + + >>> from sympy.stats import given, density, Die + >>> X = Die('X', 6) + >>> Y = given(X, X > 3) + >>> density(Y).dict + {4: 1/3, 5: 1/3, 6: 1/3} + + Following convention, if the condition is a random symbol then that symbol + is considered fixed. + + >>> from sympy.stats import Normal + >>> from sympy import pprint + >>> from sympy.abc import z + + >>> X = Normal('X', 0, 1) + >>> Y = Normal('Y', 0, 1) + >>> pprint(density(X + Y, Y)(z), use_unicode=False) + 2 + -(-Y + z) + ----------- + ___ 2 + \/ 2 *e + ------------------ + ____ + 2*\/ pi + """ + + if not is_random(condition) or pspace_independent(expr, condition): + return expr + + if isinstance(condition, RandomSymbol): + condition = Eq(condition, condition.symbol) + + condsymbols = random_symbols(condition) + if (isinstance(condition, Eq) and len(condsymbols) == 1 and + not isinstance(pspace(expr).domain, ConditionalDomain)): + rv = tuple(condsymbols)[0] + + results = solveset(condition, rv) + if isinstance(results, Intersection) and S.Reals in results.args: + results = list(results.args[1]) + + sums = 0 + for res in results: + temp = expr.subs(rv, res) + if temp == True: + return True + if temp != False: + # XXX: This seems nonsensical but preserves existing behaviour + # after the change that Relational is no longer a subclass of + # Expr. Here expr is sometimes Relational and sometimes Expr + # but we are trying to add them with +=. This needs to be + # fixed somehow. + if sums == 0 and isinstance(expr, Relational): + sums = expr.subs(rv, res) + else: + sums += expr.subs(rv, res) + if sums == 0: + return False + return sums + + # Get full probability space of both the expression and the condition + fullspace = pspace(Tuple(expr, condition)) + # Build new space given the condition + space = fullspace.conditional_space(condition, **kwargs) + # Dictionary to swap out RandomSymbols in expr with new RandomSymbols + # That point to the new conditional space + swapdict = rs_swap(fullspace.values, space.values) + # Swap random variables in the expression + expr = expr.xreplace(swapdict) + return expr + + +def expectation(expr, condition=None, numsamples=None, evaluate=True, **kwargs): + """ + Returns the expected value of a random expression. + + Parameters + ========== + + expr : Expr containing RandomSymbols + The expression of which you want to compute the expectation value + given : Expr containing RandomSymbols + A conditional expression. E(X, X>0) is expectation of X given X > 0 + numsamples : int + Enables sampling and approximates the expectation with this many samples + evalf : Bool (defaults to True) + If sampling return a number rather than a complex expression + evaluate : Bool (defaults to True) + In case of continuous systems return unevaluated integral + + Examples + ======== + + >>> from sympy.stats import E, Die + >>> X = Die('X', 6) + >>> E(X) + 7/2 + >>> E(2*X + 1) + 8 + + >>> E(X, X > 3) # Expectation of X given that it is above 3 + 5 + """ + + if not is_random(expr): # expr isn't random? + return expr + kwargs['numsamples'] = numsamples + from sympy.stats.symbolic_probability import Expectation + if evaluate: + return Expectation(expr, condition).doit(**kwargs) + return Expectation(expr, condition) + + +def probability(condition, given_condition=None, numsamples=None, + evaluate=True, **kwargs): + """ + Probability that a condition is true, optionally given a second condition. + + Parameters + ========== + + condition : Combination of Relationals containing RandomSymbols + The condition of which you want to compute the probability + given_condition : Combination of Relationals containing RandomSymbols + A conditional expression. P(X > 1, X > 0) is expectation of X > 1 + given X > 0 + numsamples : int + Enables sampling and approximates the probability with this many samples + evaluate : Bool (defaults to True) + In case of continuous systems return unevaluated integral + + Examples + ======== + + >>> from sympy.stats import P, Die + >>> from sympy import Eq + >>> X, Y = Die('X', 6), Die('Y', 6) + >>> P(X > 3) + 1/2 + >>> P(Eq(X, 5), X > 2) # Probability that X == 5 given that X > 2 + 1/4 + >>> P(X > Y) + 5/12 + """ + + kwargs['numsamples'] = numsamples + from sympy.stats.symbolic_probability import Probability + if evaluate: + return Probability(condition, given_condition).doit(**kwargs) + return Probability(condition, given_condition) + + +class Density(Basic): + expr = property(lambda self: self.args[0]) + + def __new__(cls, expr, condition = None): + expr = _sympify(expr) + if condition is None: + obj = Basic.__new__(cls, expr) + else: + condition = _sympify(condition) + obj = Basic.__new__(cls, expr, condition) + return obj + + @property + def condition(self): + if len(self.args) > 1: + return self.args[1] + else: + return None + + def doit(self, evaluate=True, **kwargs): + from sympy.stats.random_matrix import RandomMatrixPSpace + from sympy.stats.joint_rv import JointPSpace + from sympy.stats.matrix_distributions import MatrixPSpace + from sympy.stats.compound_rv import CompoundPSpace + from sympy.stats.frv import SingleFiniteDistribution + expr, condition = self.expr, self.condition + + if isinstance(expr, SingleFiniteDistribution): + return expr.dict + if condition is not None: + # Recompute on new conditional expr + expr = given(expr, condition, **kwargs) + if not random_symbols(expr): + return Lambda(x, DiracDelta(x - expr)) + if isinstance(expr, RandomSymbol): + if isinstance(expr.pspace, (SinglePSpace, JointPSpace, MatrixPSpace)) and \ + hasattr(expr.pspace, 'distribution'): + return expr.pspace.distribution + elif isinstance(expr.pspace, RandomMatrixPSpace): + return expr.pspace.model + if isinstance(pspace(expr), CompoundPSpace): + kwargs['compound_evaluate'] = evaluate + result = pspace(expr).compute_density(expr, **kwargs) + + if evaluate and hasattr(result, 'doit'): + return result.doit() + else: + return result + + +def density(expr, condition=None, evaluate=True, numsamples=None, **kwargs): + """ + Probability density of a random expression, optionally given a second + condition. + + Explanation + =========== + + This density will take on different forms for different types of + probability spaces. Discrete variables produce Dicts. Continuous + variables produce Lambdas. + + Parameters + ========== + + expr : Expr containing RandomSymbols + The expression of which you want to compute the density value + condition : Relational containing RandomSymbols + A conditional expression. density(X > 1, X > 0) is density of X > 1 + given X > 0 + numsamples : int + Enables sampling and approximates the density with this many samples + + Examples + ======== + + >>> from sympy.stats import density, Die, Normal + >>> from sympy import Symbol + + >>> x = Symbol('x') + >>> D = Die('D', 6) + >>> X = Normal(x, 0, 1) + + >>> density(D).dict + {1: 1/6, 2: 1/6, 3: 1/6, 4: 1/6, 5: 1/6, 6: 1/6} + >>> density(2*D).dict + {2: 1/6, 4: 1/6, 6: 1/6, 8: 1/6, 10: 1/6, 12: 1/6} + >>> density(X)(x) + sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) + """ + + if numsamples: + return sampling_density(expr, condition, numsamples=numsamples, + **kwargs) + + return Density(expr, condition).doit(evaluate=evaluate, **kwargs) + + +def cdf(expr, condition=None, evaluate=True, **kwargs): + """ + Cumulative Distribution Function of a random expression. + + optionally given a second condition. + + Explanation + =========== + + This density will take on different forms for different types of + probability spaces. + Discrete variables produce Dicts. + Continuous variables produce Lambdas. + + Examples + ======== + + >>> from sympy.stats import density, Die, Normal, cdf + + >>> D = Die('D', 6) + >>> X = Normal('X', 0, 1) + + >>> density(D).dict + {1: 1/6, 2: 1/6, 3: 1/6, 4: 1/6, 5: 1/6, 6: 1/6} + >>> cdf(D) + {1: 1/6, 2: 1/3, 3: 1/2, 4: 2/3, 5: 5/6, 6: 1} + >>> cdf(3*D, D > 2) + {9: 1/4, 12: 1/2, 15: 3/4, 18: 1} + + >>> cdf(X) + Lambda(_z, erf(sqrt(2)*_z/2)/2 + 1/2) + """ + if condition is not None: # If there is a condition + # Recompute on new conditional expr + return cdf(given(expr, condition, **kwargs), **kwargs) + + # Otherwise pass work off to the ProbabilitySpace + result = pspace(expr).compute_cdf(expr, **kwargs) + + if evaluate and hasattr(result, 'doit'): + return result.doit() + else: + return result + + +def characteristic_function(expr, condition=None, evaluate=True, **kwargs): + """ + Characteristic function of a random expression, optionally given a second condition. + + Returns a Lambda. + + Examples + ======== + + >>> from sympy.stats import Normal, DiscreteUniform, Poisson, characteristic_function + + >>> X = Normal('X', 0, 1) + >>> characteristic_function(X) + Lambda(_t, exp(-_t**2/2)) + + >>> Y = DiscreteUniform('Y', [1, 2, 7]) + >>> characteristic_function(Y) + Lambda(_t, exp(7*_t*I)/3 + exp(2*_t*I)/3 + exp(_t*I)/3) + + >>> Z = Poisson('Z', 2) + >>> characteristic_function(Z) + Lambda(_t, exp(2*exp(_t*I) - 2)) + """ + if condition is not None: + return characteristic_function(given(expr, condition, **kwargs), **kwargs) + + result = pspace(expr).compute_characteristic_function(expr, **kwargs) + + if evaluate and hasattr(result, 'doit'): + return result.doit() + else: + return result + +def moment_generating_function(expr, condition=None, evaluate=True, **kwargs): + if condition is not None: + return moment_generating_function(given(expr, condition, **kwargs), **kwargs) + + result = pspace(expr).compute_moment_generating_function(expr, **kwargs) + + if evaluate and hasattr(result, 'doit'): + return result.doit() + else: + return result + +def where(condition, given_condition=None, **kwargs): + """ + Returns the domain where a condition is True. + + Examples + ======== + + >>> from sympy.stats import where, Die, Normal + >>> from sympy import And + + >>> D1, D2 = Die('a', 6), Die('b', 6) + >>> a, b = D1.symbol, D2.symbol + >>> X = Normal('x', 0, 1) + + >>> where(X**2<1) + Domain: (-1 < x) & (x < 1) + + >>> where(X**2<1).set + Interval.open(-1, 1) + + >>> where(And(D1<=D2, D2<3)) + Domain: (Eq(a, 1) & Eq(b, 1)) | (Eq(a, 1) & Eq(b, 2)) | (Eq(a, 2) & Eq(b, 2)) + """ + if given_condition is not None: # If there is a condition + # Recompute on new conditional expr + return where(given(condition, given_condition, **kwargs), **kwargs) + + # Otherwise pass work off to the ProbabilitySpace + return pspace(condition).where(condition, **kwargs) + + +@doctest_depends_on(modules=('scipy',)) +def sample(expr, condition=None, size=(), library='scipy', + numsamples=1, seed=None, **kwargs): + """ + A realization of the random expression. + + Parameters + ========== + + expr : Expression of random variables + Expression from which sample is extracted + condition : Expr containing RandomSymbols + A conditional expression + size : int, tuple + Represents size of each sample in numsamples + library : str + - 'scipy' : Sample using scipy + - 'numpy' : Sample using numpy + - 'pymc' : Sample using PyMC + + Choose any of the available options to sample from as string, + by default is 'scipy' + numsamples : int + Number of samples, each with size as ``size``. + + .. deprecated:: 1.9 + + The ``numsamples`` parameter is deprecated and is only provided for + compatibility with v1.8. Use a list comprehension or an additional + dimension in ``size`` instead. See + :ref:`deprecated-sympy-stats-numsamples` for details. + + seed : + An object to be used as seed by the given external library for sampling `expr`. + Following is the list of possible types of object for the supported libraries, + + - 'scipy': int, numpy.random.RandomState, numpy.random.Generator + - 'numpy': int, numpy.random.RandomState, numpy.random.Generator + - 'pymc': int + + Optional, by default None, in which case seed settings + related to the given library will be used. + No modifications to environment's global seed settings + are done by this argument. + + Returns + ======= + + sample: float/list/numpy.ndarray + one sample or a collection of samples of the random expression. + + - sample(X) returns float/numpy.float64/numpy.int64 object. + - sample(X, size=int/tuple) returns numpy.ndarray object. + + Examples + ======== + + >>> from sympy.stats import Die, sample, Normal, Geometric + >>> X, Y, Z = Die('X', 6), Die('Y', 6), Die('Z', 6) # Finite Random Variable + >>> die_roll = sample(X + Y + Z) + >>> die_roll # doctest: +SKIP + 3 + >>> N = Normal('N', 3, 4) # Continuous Random Variable + >>> samp = sample(N) + >>> samp in N.pspace.domain.set + True + >>> samp = sample(N, N>0) + >>> samp > 0 + True + >>> samp_list = sample(N, size=4) + >>> [sam in N.pspace.domain.set for sam in samp_list] + [True, True, True, True] + >>> sample(N, size = (2,3)) # doctest: +SKIP + array([[5.42519758, 6.40207856, 4.94991743], + [1.85819627, 6.83403519, 1.9412172 ]]) + >>> G = Geometric('G', 0.5) # Discrete Random Variable + >>> samp_list = sample(G, size=3) + >>> samp_list # doctest: +SKIP + [1, 3, 2] + >>> [sam in G.pspace.domain.set for sam in samp_list] + [True, True, True] + >>> MN = Normal("MN", [3, 4], [[2, 1], [1, 2]]) # Joint Random Variable + >>> samp_list = sample(MN, size=4) + >>> samp_list # doctest: +SKIP + [array([2.85768055, 3.38954165]), + array([4.11163337, 4.3176591 ]), + array([0.79115232, 1.63232916]), + array([4.01747268, 3.96716083])] + >>> [tuple(sam) in MN.pspace.domain.set for sam in samp_list] + [True, True, True, True] + + .. versionchanged:: 1.7.0 + sample used to return an iterator containing the samples instead of value. + + .. versionchanged:: 1.9.0 + sample returns values or array of values instead of an iterator and numsamples is deprecated. + + """ + + iterator = sample_iter(expr, condition, size=size, library=library, + numsamples=numsamples, seed=seed) + + if numsamples != 1: + sympy_deprecation_warning( + f""" + The numsamples parameter to sympy.stats.sample() is deprecated. + Either use a list comprehension, like + + [sample(...) for i in range({numsamples})] + + or add a dimension to size, like + + sample(..., size={(numsamples,) + size}) + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-sympy-stats-numsamples", + ) + return [next(iterator) for i in range(numsamples)] + + return next(iterator) + + +def quantile(expr, evaluate=True, **kwargs): + r""" + Return the :math:`p^{th}` order quantile of a probability distribution. + + Explanation + =========== + + Quantile is defined as the value at which the probability of the random + variable is less than or equal to the given probability. + + .. math:: + Q(p) = \inf\{x \in (-\infty, \infty) : p \le F(x)\} + + Examples + ======== + + >>> from sympy.stats import quantile, Die, Exponential + >>> from sympy import Symbol, pprint + >>> p = Symbol("p") + + >>> l = Symbol("lambda", positive=True) + >>> X = Exponential("x", l) + >>> quantile(X)(p) + -log(1 - p)/lambda + + >>> D = Die("d", 6) + >>> pprint(quantile(D)(p), use_unicode=False) + /nan for Or(p > 1, p < 0) + | + | 1 for p <= 1/6 + | + | 2 for p <= 1/3 + | + < 3 for p <= 1/2 + | + | 4 for p <= 2/3 + | + | 5 for p <= 5/6 + | + \ 6 for p <= 1 + + """ + result = pspace(expr).compute_quantile(expr, **kwargs) + + if evaluate and hasattr(result, 'doit'): + return result.doit() + else: + return result + +def sample_iter(expr, condition=None, size=(), library='scipy', + numsamples=S.Infinity, seed=None, **kwargs): + + """ + Returns an iterator of realizations from the expression given a condition. + + Parameters + ========== + + expr: Expr + Random expression to be realized + condition: Expr, optional + A conditional expression + size : int, tuple + Represents size of each sample in numsamples + numsamples: integer, optional + Length of the iterator (defaults to infinity) + seed : + An object to be used as seed by the given external library for sampling `expr`. + Following is the list of possible types of object for the supported libraries, + + - 'scipy': int, numpy.random.RandomState, numpy.random.Generator + - 'numpy': int, numpy.random.RandomState, numpy.random.Generator + - 'pymc': int + + Optional, by default None, in which case seed settings + related to the given library will be used. + No modifications to environment's global seed settings + are done by this argument. + + Examples + ======== + + >>> from sympy.stats import Normal, sample_iter + >>> X = Normal('X', 0, 1) + >>> expr = X*X + 3 + >>> iterator = sample_iter(expr, numsamples=3) # doctest: +SKIP + >>> list(iterator) # doctest: +SKIP + [12, 4, 7] + + Returns + ======= + + sample_iter: iterator object + iterator object containing the sample/samples of given expr + + See Also + ======== + + sample + sampling_P + sampling_E + + """ + from sympy.stats.joint_rv import JointRandomSymbol + if not import_module(library): + raise ValueError("Failed to import %s" % library) + + if condition is not None: + ps = pspace(Tuple(expr, condition)) + else: + ps = pspace(expr) + + rvs = list(ps.values) + if isinstance(expr, JointRandomSymbol): + expr = expr.subs({expr: RandomSymbol(expr.symbol, expr.pspace)}) + else: + sub = {} + for arg in expr.args: + if isinstance(arg, JointRandomSymbol): + sub[arg] = RandomSymbol(arg.symbol, arg.pspace) + expr = expr.subs(sub) + + def fn_subs(*args): + return expr.subs(dict(zip(rvs, args))) + + def given_fn_subs(*args): + if condition is not None: + return condition.subs(dict(zip(rvs, args))) + return False + + if library in ('pymc', 'pymc3'): + # Currently unable to lambdify in pymc + # TODO : Remove when lambdify accepts 'pymc' as module + fn = lambdify(rvs, expr, **kwargs) + else: + fn = lambdify(rvs, expr, modules=library, **kwargs) + + + if condition is not None: + given_fn = lambdify(rvs, condition, **kwargs) + + def return_generator_infinite(): + count = 0 + _size = (1,)+((size,) if isinstance(size, int) else size) + while count < numsamples: + d = ps.sample(size=_size, library=library, seed=seed) # a dictionary that maps RVs to values + args = [d[rv][0] for rv in rvs] + + if condition is not None: # Check that these values satisfy the condition + # TODO: Replace the try-except block with only given_fn(*args) + # once lambdify works with unevaluated SymPy objects. + try: + gd = given_fn(*args) + except (NameError, TypeError): + gd = given_fn_subs(*args) + if gd != True and gd != False: + raise ValueError( + "Conditions must not contain free symbols") + if not gd: # If the values don't satisfy then try again + continue + + yield fn(*args) + count += 1 + + def return_generator_finite(): + faulty = True + while faulty: + d = ps.sample(size=(numsamples,) + ((size,) if isinstance(size, int) else size), + library=library, seed=seed) # a dictionary that maps RVs to values + + faulty = False + count = 0 + while count < numsamples and not faulty: + args = [d[rv][count] for rv in rvs] + if condition is not None: # Check that these values satisfy the condition + # TODO: Replace the try-except block with only given_fn(*args) + # once lambdify works with unevaluated SymPy objects. + try: + gd = given_fn(*args) + except (NameError, TypeError): + gd = given_fn_subs(*args) + if gd != True and gd != False: + raise ValueError( + "Conditions must not contain free symbols") + if not gd: # If the values don't satisfy then try again + faulty = True + + count += 1 + + count = 0 + while count < numsamples: + args = [d[rv][count] for rv in rvs] + # TODO: Replace the try-except block with only fn(*args) + # once lambdify works with unevaluated SymPy objects. + try: + yield fn(*args) + except (NameError, TypeError): + yield fn_subs(*args) + count += 1 + + if numsamples is S.Infinity: + return return_generator_infinite() + + return return_generator_finite() + +def sample_iter_lambdify(expr, condition=None, size=(), + numsamples=S.Infinity, seed=None, **kwargs): + + return sample_iter(expr, condition=condition, size=size, + numsamples=numsamples, seed=seed, **kwargs) + +def sample_iter_subs(expr, condition=None, size=(), + numsamples=S.Infinity, seed=None, **kwargs): + + return sample_iter(expr, condition=condition, size=size, + numsamples=numsamples, seed=seed, **kwargs) + + +def sampling_P(condition, given_condition=None, library='scipy', numsamples=1, + evalf=True, seed=None, **kwargs): + """ + Sampling version of P. + + See Also + ======== + + P + sampling_E + sampling_density + + """ + + count_true = 0 + count_false = 0 + samples = sample_iter(condition, given_condition, library=library, + numsamples=numsamples, seed=seed, **kwargs) + + for sample in samples: + if sample: + count_true += 1 + else: + count_false += 1 + + result = S(count_true) / numsamples + if evalf: + return result.evalf() + else: + return result + + +def sampling_E(expr, given_condition=None, library='scipy', numsamples=1, + evalf=True, seed=None, **kwargs): + """ + Sampling version of E. + + See Also + ======== + + P + sampling_P + sampling_density + """ + samples = list(sample_iter(expr, given_condition, library=library, + numsamples=numsamples, seed=seed, **kwargs)) + result = Add(*samples) / numsamples + + if evalf: + return result.evalf() + else: + return result + +def sampling_density(expr, given_condition=None, library='scipy', + numsamples=1, seed=None, **kwargs): + """ + Sampling version of density. + + See Also + ======== + density + sampling_P + sampling_E + """ + + results = {} + for result in sample_iter(expr, given_condition, library=library, + numsamples=numsamples, seed=seed, **kwargs): + results[result] = results.get(result, 0) + 1 + + return results + + +def dependent(a, b): + """ + Dependence of two random expressions. + + Two expressions are independent if knowledge of one does not change + computations on the other. + + Examples + ======== + + >>> from sympy.stats import Normal, dependent, given + >>> from sympy import Tuple, Eq + + >>> X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) + >>> dependent(X, Y) + False + >>> dependent(2*X + Y, -Y) + True + >>> X, Y = given(Tuple(X, Y), Eq(X + Y, 3)) + >>> dependent(X, Y) + True + + See Also + ======== + + independent + """ + if pspace_independent(a, b): + return False + + z = Symbol('z', real=True) + # Dependent if density is unchanged when one is given information about + # the other + return (density(a, Eq(b, z)) != density(a) or + density(b, Eq(a, z)) != density(b)) + + +def independent(a, b): + """ + Independence of two random expressions. + + Two expressions are independent if knowledge of one does not change + computations on the other. + + Examples + ======== + + >>> from sympy.stats import Normal, independent, given + >>> from sympy import Tuple, Eq + + >>> X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) + >>> independent(X, Y) + True + >>> independent(2*X + Y, -Y) + False + >>> X, Y = given(Tuple(X, Y), Eq(X + Y, 3)) + >>> independent(X, Y) + False + + See Also + ======== + + dependent + """ + return not dependent(a, b) + + +def pspace_independent(a, b): + """ + Tests for independence between a and b by checking if their PSpaces have + overlapping symbols. This is a sufficient but not necessary condition for + independence and is intended to be used internally. + + Notes + ===== + + pspace_independent(a, b) implies independent(a, b) + independent(a, b) does not imply pspace_independent(a, b) + """ + a_symbols = set(pspace(b).symbols) + b_symbols = set(pspace(a).symbols) + + if len(set(random_symbols(a)).intersection(random_symbols(b))) != 0: + return False + + if len(a_symbols.intersection(b_symbols)) == 0: + return True + return None + + +def rv_subs(expr, symbols=None): + """ + Given a random expression replace all random variables with their symbols. + + If symbols keyword is given restrict the swap to only the symbols listed. + """ + if symbols is None: + symbols = random_symbols(expr) + if not symbols: + return expr + swapdict = {rv: rv.symbol for rv in symbols} + return expr.subs(swapdict) + + +class NamedArgsMixin: + _argnames: tuple[str, ...] = () + + def __getattr__(self, attr): + try: + return self.args[self._argnames.index(attr)] + except ValueError: + raise AttributeError("'%s' object has no attribute '%s'" % ( + type(self).__name__, attr)) + + +class Distribution(Basic): + + def sample(self, size=(), library='scipy', seed=None): + """ A random realization from the distribution """ + + module = import_module(library) + if library in {'scipy', 'numpy', 'pymc3', 'pymc'} and module is None: + raise ValueError("Failed to import %s" % library) + + if library == 'scipy': + # scipy does not require map as it can handle using custom distributions. + # However, we will still use a map where we can. + + # TODO: do this for drv.py and frv.py if necessary. + # TODO: add more distributions here if there are more + # See links below referring to sections beginning with "A common parametrization..." + # I will remove all these comments if everything is ok. + + from sympy.stats.sampling.sample_scipy import do_sample_scipy + import numpy + if seed is None or isinstance(seed, int): + rand_state = numpy.random.default_rng(seed=seed) + else: + rand_state = seed + samps = do_sample_scipy(self, size, rand_state) + + elif library == 'numpy': + from sympy.stats.sampling.sample_numpy import do_sample_numpy + import numpy + if seed is None or isinstance(seed, int): + rand_state = numpy.random.default_rng(seed=seed) + else: + rand_state = seed + _size = None if size == () else size + samps = do_sample_numpy(self, _size, rand_state) + elif library in ('pymc', 'pymc3'): + from sympy.stats.sampling.sample_pymc import do_sample_pymc + import logging + logging.getLogger("pymc").setLevel(logging.ERROR) + try: + import pymc + except ImportError: + import pymc3 as pymc + + with pymc.Model(): + if do_sample_pymc(self) is not None: + samps = pymc.sample(draws=prod(size), chains=1, compute_convergence_checks=False, + progressbar=False, random_seed=seed, return_inferencedata=False)[:]['X'] + samps = samps.reshape(size) + else: + samps = None + + else: + raise NotImplementedError("Sampling from %s is not supported yet." + % str(library)) + + if samps is not None: + return samps + raise NotImplementedError( + "Sampling for %s is not currently implemented from %s" + % (self, library)) + + +def _value_check(condition, message): + """ + Raise a ValueError with message if condition is False, else + return True if all conditions were True, else False. + + Examples + ======== + + >>> from sympy.stats.rv import _value_check + >>> from sympy.abc import a, b, c + >>> from sympy import And, Dummy + + >>> _value_check(2 < 3, '') + True + + Here, the condition is not False, but it does not evaluate to True + so False is returned (but no error is raised). So checking if the + return value is True or False will tell you if all conditions were + evaluated. + + >>> _value_check(a < b, '') + False + + In this case the condition is False so an error is raised: + + >>> r = Dummy(real=True) + >>> _value_check(r < r - 1, 'condition is not true') + Traceback (most recent call last): + ... + ValueError: condition is not true + + If no condition of many conditions must be False, they can be + checked by passing them as an iterable: + + >>> _value_check((a < 0, b < 0, c < 0), '') + False + + The iterable can be a generator, too: + + >>> _value_check((i < 0 for i in (a, b, c)), '') + False + + The following are equivalent to the above but do not pass + an iterable: + + >>> all(_value_check(i < 0, '') for i in (a, b, c)) + False + >>> _value_check(And(a < 0, b < 0, c < 0), '') + False + """ + if not iterable(condition): + condition = [condition] + truth = fuzzy_and(condition) + if truth == False: + raise ValueError(message) + return truth == True + +def _symbol_converter(sym): + """ + Casts the parameter to Symbol if it is 'str' + otherwise no operation is performed on it. + + Parameters + ========== + + sym + The parameter to be converted. + + Returns + ======= + + Symbol + the parameter converted to Symbol. + + Raises + ====== + + TypeError + If the parameter is not an instance of both str and + Symbol. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.stats.rv import _symbol_converter + >>> s = _symbol_converter('s') + >>> isinstance(s, Symbol) + True + >>> _symbol_converter(1) + Traceback (most recent call last): + ... + TypeError: 1 is neither a Symbol nor a string + >>> r = Symbol('r') + >>> isinstance(r, Symbol) + True + """ + if isinstance(sym, str): + sym = Symbol(sym) + if not isinstance(sym, Symbol): + raise TypeError("%s is neither a Symbol nor a string"%(sym)) + return sym + +def sample_stochastic_process(process): + """ + This function is used to sample from stochastic process. + + Parameters + ========== + + process: StochasticProcess + Process used to extract the samples. It must be an instance of + StochasticProcess + + Examples + ======== + + >>> from sympy.stats import sample_stochastic_process, DiscreteMarkovChain + >>> from sympy import Matrix + >>> T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]]) + >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T) + >>> next(sample_stochastic_process(Y)) in Y.state_space + True + >>> next(sample_stochastic_process(Y)) # doctest: +SKIP + 0 + >>> next(sample_stochastic_process(Y)) # doctest: +SKIP + 2 + + Returns + ======= + + sample: iterator object + iterator object containing the sample of given process + + """ + from sympy.stats.stochastic_process_types import StochasticProcess + if not isinstance(process, StochasticProcess): + raise ValueError("Process must be an instance of Stochastic Process") + return process.sample() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/rv_interface.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/rv_interface.py new file mode 100644 index 0000000000000000000000000000000000000000..16d65b83634cdb04ef7e5046175848cdf380434b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/rv_interface.py @@ -0,0 +1,519 @@ +from sympy.sets import FiniteSet +from sympy.core.numbers import Rational +from sympy.core.relational import Eq +from sympy.core.symbol import Dummy +from sympy.functions.combinatorial.factorials import FallingFactorial +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import piecewise_fold +from sympy.integrals.integrals import Integral +from sympy.solvers.solveset import solveset +from .rv import (probability, expectation, density, where, given, pspace, cdf, PSpace, + characteristic_function, sample, sample_iter, random_symbols, independent, dependent, + sampling_density, moment_generating_function, quantile, is_random, + sample_stochastic_process) + + +__all__ = ['P', 'E', 'H', 'density', 'where', 'given', 'sample', 'cdf', + 'characteristic_function', 'pspace', 'sample_iter', 'variance', 'std', + 'skewness', 'kurtosis', 'covariance', 'dependent', 'entropy', 'median', + 'independent', 'random_symbols', 'correlation', 'factorial_moment', + 'moment', 'cmoment', 'sampling_density', 'moment_generating_function', + 'smoment', 'quantile', 'sample_stochastic_process'] + + + +def moment(X, n, c=0, condition=None, *, evaluate=True, **kwargs): + """ + Return the nth moment of a random expression about c. + + .. math:: + moment(X, c, n) = E((X-c)^{n}) + + Default value of c is 0. + + Examples + ======== + + >>> from sympy.stats import Die, moment, E + >>> X = Die('X', 6) + >>> moment(X, 1, 6) + -5/2 + >>> moment(X, 2) + 91/6 + >>> moment(X, 1) == E(X) + True + """ + from sympy.stats.symbolic_probability import Moment + if evaluate: + return Moment(X, n, c, condition).doit() + return Moment(X, n, c, condition).rewrite(Integral) + + +def variance(X, condition=None, **kwargs): + """ + Variance of a random expression. + + .. math:: + variance(X) = E((X-E(X))^{2}) + + Examples + ======== + + >>> from sympy.stats import Die, Bernoulli, variance + >>> from sympy import simplify, Symbol + + >>> X = Die('X', 6) + >>> p = Symbol('p') + >>> B = Bernoulli('B', p, 1, 0) + + >>> variance(2*X) + 35/3 + + >>> simplify(variance(B)) + p*(1 - p) + """ + if is_random(X) and pspace(X) == PSpace(): + from sympy.stats.symbolic_probability import Variance + return Variance(X, condition) + + return cmoment(X, 2, condition, **kwargs) + + +def standard_deviation(X, condition=None, **kwargs): + r""" + Standard Deviation of a random expression + + .. math:: + std(X) = \sqrt(E((X-E(X))^{2})) + + Examples + ======== + + >>> from sympy.stats import Bernoulli, std + >>> from sympy import Symbol, simplify + + >>> p = Symbol('p') + >>> B = Bernoulli('B', p, 1, 0) + + >>> simplify(std(B)) + sqrt(p*(1 - p)) + """ + return sqrt(variance(X, condition, **kwargs)) +std = standard_deviation + +def entropy(expr, condition=None, **kwargs): + """ + Calculates entropy of a probability distribution. + + Parameters + ========== + + expression : the random expression whose entropy is to be calculated + condition : optional, to specify conditions on random expression + b: base of the logarithm, optional + By default, it is taken as Euler's number + + Returns + ======= + + result : Entropy of the expression, a constant + + Examples + ======== + + >>> from sympy.stats import Normal, Die, entropy + >>> X = Normal('X', 0, 1) + >>> entropy(X) + log(2)/2 + 1/2 + log(pi)/2 + + >>> D = Die('D', 4) + >>> entropy(D) + log(4) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Entropy_%28information_theory%29 + .. [2] https://www.crmarsh.com/static/pdf/Charles_Marsh_Continuous_Entropy.pdf + .. [3] https://kconrad.math.uconn.edu/blurbs/analysis/entropypost.pdf + """ + pdf = density(expr, condition, **kwargs) + base = kwargs.get('b', exp(1)) + if isinstance(pdf, dict): + return sum(-prob*log(prob, base) for prob in pdf.values()) + return expectation(-log(pdf(expr), base)) + +def covariance(X, Y, condition=None, **kwargs): + """ + Covariance of two random expressions. + + Explanation + =========== + + The expectation that the two variables will rise and fall together + + .. math:: + covariance(X,Y) = E((X-E(X)) (Y-E(Y))) + + Examples + ======== + + >>> from sympy.stats import Exponential, covariance + >>> from sympy import Symbol + + >>> rate = Symbol('lambda', positive=True, real=True) + >>> X = Exponential('X', rate) + >>> Y = Exponential('Y', rate) + + >>> covariance(X, X) + lambda**(-2) + >>> covariance(X, Y) + 0 + >>> covariance(X, Y + rate*X) + 1/lambda + """ + if (is_random(X) and pspace(X) == PSpace()) or (is_random(Y) and pspace(Y) == PSpace()): + from sympy.stats.symbolic_probability import Covariance + return Covariance(X, Y, condition) + + return expectation( + (X - expectation(X, condition, **kwargs)) * + (Y - expectation(Y, condition, **kwargs)), + condition, **kwargs) + + +def correlation(X, Y, condition=None, **kwargs): + r""" + Correlation of two random expressions, also known as correlation + coefficient or Pearson's correlation. + + Explanation + =========== + + The normalized expectation that the two variables will rise + and fall together + + .. math:: + correlation(X,Y) = E((X-E(X))(Y-E(Y)) / (\sigma_x \sigma_y)) + + Examples + ======== + + >>> from sympy.stats import Exponential, correlation + >>> from sympy import Symbol + + >>> rate = Symbol('lambda', positive=True, real=True) + >>> X = Exponential('X', rate) + >>> Y = Exponential('Y', rate) + + >>> correlation(X, X) + 1 + >>> correlation(X, Y) + 0 + >>> correlation(X, Y + rate*X) + 1/sqrt(1 + lambda**(-2)) + """ + return covariance(X, Y, condition, **kwargs)/(std(X, condition, **kwargs) + * std(Y, condition, **kwargs)) + + +def cmoment(X, n, condition=None, *, evaluate=True, **kwargs): + """ + Return the nth central moment of a random expression about its mean. + + .. math:: + cmoment(X, n) = E((X - E(X))^{n}) + + Examples + ======== + + >>> from sympy.stats import Die, cmoment, variance + >>> X = Die('X', 6) + >>> cmoment(X, 3) + 0 + >>> cmoment(X, 2) + 35/12 + >>> cmoment(X, 2) == variance(X) + True + """ + from sympy.stats.symbolic_probability import CentralMoment + if evaluate: + return CentralMoment(X, n, condition).doit() + return CentralMoment(X, n, condition).rewrite(Integral) + + +def smoment(X, n, condition=None, **kwargs): + r""" + Return the nth Standardized moment of a random expression. + + .. math:: + smoment(X, n) = E(((X - \mu)/\sigma_X)^{n}) + + Examples + ======== + + >>> from sympy.stats import skewness, Exponential, smoment + >>> from sympy import Symbol + >>> rate = Symbol('lambda', positive=True, real=True) + >>> Y = Exponential('Y', rate) + >>> smoment(Y, 4) + 9 + >>> smoment(Y, 4) == smoment(3*Y, 4) + True + >>> smoment(Y, 3) == skewness(Y) + True + """ + sigma = std(X, condition, **kwargs) + return (1/sigma)**n*cmoment(X, n, condition, **kwargs) + +def skewness(X, condition=None, **kwargs): + r""" + Measure of the asymmetry of the probability distribution. + + Explanation + =========== + + Positive skew indicates that most of the values lie to the right of + the mean. + + .. math:: + skewness(X) = E(((X - E(X))/\sigma_X)^{3}) + + Parameters + ========== + + condition : Expr containing RandomSymbols + A conditional expression. skewness(X, X>0) is skewness of X given X > 0 + + Examples + ======== + + >>> from sympy.stats import skewness, Exponential, Normal + >>> from sympy import Symbol + >>> X = Normal('X', 0, 1) + >>> skewness(X) + 0 + >>> skewness(X, X > 0) # find skewness given X > 0 + (-sqrt(2)/sqrt(pi) + 4*sqrt(2)/pi**(3/2))/(1 - 2/pi)**(3/2) + + >>> rate = Symbol('lambda', positive=True, real=True) + >>> Y = Exponential('Y', rate) + >>> skewness(Y) + 2 + """ + return smoment(X, 3, condition=condition, **kwargs) + +def kurtosis(X, condition=None, **kwargs): + r""" + Characterizes the tails/outliers of a probability distribution. + + Explanation + =========== + + Kurtosis of any univariate normal distribution is 3. Kurtosis less than + 3 means that the distribution produces fewer and less extreme outliers + than the normal distribution. + + .. math:: + kurtosis(X) = E(((X - E(X))/\sigma_X)^{4}) + + Parameters + ========== + + condition : Expr containing RandomSymbols + A conditional expression. kurtosis(X, X>0) is kurtosis of X given X > 0 + + Examples + ======== + + >>> from sympy.stats import kurtosis, Exponential, Normal + >>> from sympy import Symbol + >>> X = Normal('X', 0, 1) + >>> kurtosis(X) + 3 + >>> kurtosis(X, X > 0) # find kurtosis given X > 0 + (-4/pi - 12/pi**2 + 3)/(1 - 2/pi)**2 + + >>> rate = Symbol('lamda', positive=True, real=True) + >>> Y = Exponential('Y', rate) + >>> kurtosis(Y) + 9 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Kurtosis + .. [2] https://mathworld.wolfram.com/Kurtosis.html + """ + return smoment(X, 4, condition=condition, **kwargs) + + +def factorial_moment(X, n, condition=None, **kwargs): + """ + The factorial moment is a mathematical quantity defined as the expectation + or average of the falling factorial of a random variable. + + .. math:: + factorial-moment(X, n) = E(X(X - 1)(X - 2)...(X - n + 1)) + + Parameters + ========== + + n: A natural number, n-th factorial moment. + + condition : Expr containing RandomSymbols + A conditional expression. + + Examples + ======== + + >>> from sympy.stats import factorial_moment, Poisson, Binomial + >>> from sympy import Symbol, S + >>> lamda = Symbol('lamda') + >>> X = Poisson('X', lamda) + >>> factorial_moment(X, 2) + lamda**2 + >>> Y = Binomial('Y', 2, S.Half) + >>> factorial_moment(Y, 2) + 1/2 + >>> factorial_moment(Y, 2, Y > 1) # find factorial moment for Y > 1 + 2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Factorial_moment + .. [2] https://mathworld.wolfram.com/FactorialMoment.html + """ + return expectation(FallingFactorial(X, n), condition=condition, **kwargs) + +def median(X, evaluate=True, **kwargs): + r""" + Calculates the median of the probability distribution. + + Explanation + =========== + + Mathematically, median of Probability distribution is defined as all those + values of `m` for which the following condition is satisfied + + .. math:: + P(X\leq m) \geq \frac{1}{2} \text{ and} \text{ } P(X\geq m)\geq \frac{1}{2} + + Parameters + ========== + + X: The random expression whose median is to be calculated. + + Returns + ======= + + The FiniteSet or an Interval which contains the median of the + random expression. + + Examples + ======== + + >>> from sympy.stats import Normal, Die, median + >>> N = Normal('N', 3, 1) + >>> median(N) + {3} + >>> D = Die('D') + >>> median(D) + {3, 4} + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Median#Probability_distributions + + """ + if not is_random(X): + return X + + from sympy.stats.crv import ContinuousPSpace + from sympy.stats.drv import DiscretePSpace + from sympy.stats.frv import FinitePSpace + + if isinstance(pspace(X), FinitePSpace): + cdf = pspace(X).compute_cdf(X) + result = [] + for key, value in cdf.items(): + if value>= Rational(1, 2) and (1 - value) + \ + pspace(X).probability(Eq(X, key)) >= Rational(1, 2): + result.append(key) + return FiniteSet(*result) + if isinstance(pspace(X), (ContinuousPSpace, DiscretePSpace)): + cdf = pspace(X).compute_cdf(X) + x = Dummy('x') + result = solveset(piecewise_fold(cdf(x) - Rational(1, 2)), x, pspace(X).set) + return result + raise NotImplementedError("The median of %s is not implemented."%str(pspace(X))) + + +def coskewness(X, Y, Z, condition=None, **kwargs): + r""" + Calculates the co-skewness of three random variables. + + Explanation + =========== + + Mathematically Coskewness is defined as + + .. math:: + coskewness(X,Y,Z)=\frac{E[(X-E[X]) * (Y-E[Y]) * (Z-E[Z])]} {\sigma_{X}\sigma_{Y}\sigma_{Z}} + + Parameters + ========== + + X : RandomSymbol + Random Variable used to calculate coskewness + Y : RandomSymbol + Random Variable used to calculate coskewness + Z : RandomSymbol + Random Variable used to calculate coskewness + condition : Expr containing RandomSymbols + A conditional expression + + Examples + ======== + + >>> from sympy.stats import coskewness, Exponential, skewness + >>> from sympy import symbols + >>> p = symbols('p', positive=True) + >>> X = Exponential('X', p) + >>> Y = Exponential('Y', 2*p) + >>> coskewness(X, Y, Y) + 0 + >>> coskewness(X, Y + X, Y + 2*X) + 16*sqrt(85)/85 + >>> coskewness(X + 2*Y, Y + X, Y + 2*X, X > 3) + 9*sqrt(170)/85 + >>> coskewness(Y, Y, Y) == skewness(Y) + True + >>> coskewness(X, Y + p*X, Y + 2*p*X) + 4/(sqrt(1 + 1/(4*p**2))*sqrt(4 + 1/(4*p**2))) + + Returns + ======= + + coskewness : The coskewness of the three random variables + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Coskewness + + """ + num = expectation((X - expectation(X, condition, **kwargs)) \ + * (Y - expectation(Y, condition, **kwargs)) \ + * (Z - expectation(Z, condition, **kwargs)), condition, **kwargs) + den = std(X, condition, **kwargs) * std(Y, condition, **kwargs) \ + * std(Z, condition, **kwargs) + return num/den + + +P = probability +E = expectation +H = entropy diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/stochastic_process.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/stochastic_process.py new file mode 100644 index 0000000000000000000000000000000000000000..bfb0e759c66be892ae38ddda004dfe928f683fee --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/stochastic_process.py @@ -0,0 +1,66 @@ +from sympy.core.basic import Basic +from sympy.stats.joint_rv import ProductPSpace +from sympy.stats.rv import ProductDomain, _symbol_converter, Distribution + + +class StochasticPSpace(ProductPSpace): + """ + Represents probability space of stochastic processes + and their random variables. Contains mechanics to do + computations for queries of stochastic processes. + + Explanation + =========== + + Initialized by symbol, the specific process and + distribution(optional) if the random indexed symbols + of the process follows any specific distribution, like, + in Bernoulli Process, each random indexed symbol follows + Bernoulli distribution. For processes with memory, this + parameter should not be passed. + """ + + def __new__(cls, sym, process, distribution=None): + sym = _symbol_converter(sym) + from sympy.stats.stochastic_process_types import StochasticProcess + if not isinstance(process, StochasticProcess): + raise TypeError("`process` must be an instance of StochasticProcess.") + if distribution is None: + distribution = Distribution() + return Basic.__new__(cls, sym, process, distribution) + + @property + def process(self): + """ + The associated stochastic process. + """ + return self.args[1] + + @property + def domain(self): + return ProductDomain(self.process.index_set, + self.process.state_space) + + @property + def symbol(self): + return self.args[0] + + @property + def distribution(self): + return self.args[2] + + def probability(self, condition, given_condition=None, evaluate=True, **kwargs): + """ + Transfers the task of handling queries to the specific stochastic + process because every process has their own logic of handling such + queries. + """ + return self.process.probability(condition, given_condition, evaluate, **kwargs) + + def compute_expectation(self, expr, condition=None, evaluate=True, **kwargs): + """ + Transfers the task of handling queries to the specific stochastic + process because every process has their own logic of handling such + queries. + """ + return self.process.expectation(expr, condition, evaluate, **kwargs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/stochastic_process_types.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/stochastic_process_types.py new file mode 100644 index 0000000000000000000000000000000000000000..7387cd3dbcf6defb3b7e475f542d04ecef6fecf6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/stochastic_process_types.py @@ -0,0 +1,2383 @@ +from __future__ import annotations +import random +import itertools +from typing import Sequence as tSequence +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import (Function, Lambda) +from sympy.core.mul import Mul +from sympy.core.intfunc import igcd +from sympy.core.numbers import (Integer, Rational, oo, pi) +from sympy.core.relational import (Eq, Ge, Gt, Le, Lt, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol) +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.integers import ceiling +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.gamma_functions import gamma +from sympy.logic.boolalg import (And, Not, Or) +from sympy.matrices.exceptions import NonSquareMatrixError +from sympy.matrices.dense import (Matrix, eye, ones, zeros) +from sympy.matrices.expressions.blockmatrix import BlockMatrix +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.matrices.expressions.special import Identity +from sympy.matrices.immutable import ImmutableMatrix +from sympy.sets.conditionset import ConditionSet +from sympy.sets.contains import Contains +from sympy.sets.fancysets import Range +from sympy.sets.sets import (FiniteSet, Intersection, Interval, Set, Union) +from sympy.solvers.solveset import linsolve +from sympy.tensor.indexed import (Indexed, IndexedBase) +from sympy.core.relational import Relational +from sympy.logic.boolalg import Boolean +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import strongly_connected_components +from sympy.stats.joint_rv import JointDistribution +from sympy.stats.joint_rv_types import JointDistributionHandmade +from sympy.stats.rv import (RandomIndexedSymbol, random_symbols, RandomSymbol, + _symbol_converter, _value_check, pspace, given, + dependent, is_random, sample_iter, Distribution, + Density) +from sympy.stats.stochastic_process import StochasticPSpace +from sympy.stats.symbolic_probability import Probability, Expectation +from sympy.stats.frv_types import Bernoulli, BernoulliDistribution, FiniteRV +from sympy.stats.drv_types import Poisson, PoissonDistribution +from sympy.stats.crv_types import Normal, NormalDistribution, Gamma, GammaDistribution +from sympy.core.sympify import _sympify, sympify + +EmptySet = S.EmptySet + +__all__ = [ + 'StochasticProcess', + 'DiscreteTimeStochasticProcess', + 'DiscreteMarkovChain', + 'TransitionMatrixOf', + 'StochasticStateSpaceOf', + 'GeneratorMatrixOf', + 'ContinuousMarkovChain', + 'BernoulliProcess', + 'PoissonProcess', + 'WienerProcess', + 'GammaProcess' +] + + +@is_random.register(Indexed) +def _(x): + return is_random(x.base) + +@is_random.register(RandomIndexedSymbol) # type: ignore +def _(x): + return True + +def _set_converter(itr): + """ + Helper function for converting list/tuple/set to Set. + If parameter is not an instance of list/tuple/set then + no operation is performed. + + Returns + ======= + + Set + The argument converted to Set. + + + Raises + ====== + + TypeError + If the argument is not an instance of list/tuple/set. + """ + if isinstance(itr, (list, tuple, set)): + itr = FiniteSet(*itr) + if not isinstance(itr, Set): + raise TypeError("%s is not an instance of list/tuple/set."%(itr)) + return itr + +def _state_converter(itr: tSequence) -> Tuple | Range: + """ + Helper function for converting list/tuple/set/Range/Tuple/FiniteSet + to tuple/Range. + """ + itr_ret: Tuple | Range + + if isinstance(itr, (Tuple, set, FiniteSet)): + itr_ret = Tuple(*(sympify(i) if isinstance(i, str) else i for i in itr)) + + elif isinstance(itr, (list, tuple)): + # check if states are unique + if len(set(itr)) != len(itr): + raise ValueError('The state space must have unique elements.') + itr_ret = Tuple(*(sympify(i) if isinstance(i, str) else i for i in itr)) + + elif isinstance(itr, Range): + # the only ordered set in SymPy I know of + # try to convert to tuple + try: + itr_ret = Tuple(*(sympify(i) if isinstance(i, str) else i for i in itr)) + except (TypeError, ValueError): + itr_ret = itr + + else: + raise TypeError("%s is not an instance of list/tuple/set/Range/Tuple/FiniteSet." % (itr)) + return itr_ret + +def _sym_sympify(arg): + """ + Converts an arbitrary expression to a type that can be used inside SymPy. + As generally strings are unwise to use in the expressions, + it returns the Symbol of argument if the string type argument is passed. + + Parameters + ========= + + arg: The parameter to be converted to be used in SymPy. + + Returns + ======= + + The converted parameter. + + """ + if isinstance(arg, str): + return Symbol(arg) + else: + return _sympify(arg) + +def _matrix_checks(matrix): + if not isinstance(matrix, (Matrix, MatrixSymbol, ImmutableMatrix)): + raise TypeError("Transition probabilities either should " + "be a Matrix or a MatrixSymbol.") + if matrix.shape[0] != matrix.shape[1]: + raise NonSquareMatrixError("%s is not a square matrix"%(matrix)) + if isinstance(matrix, Matrix): + matrix = ImmutableMatrix(matrix.tolist()) + return matrix + +class StochasticProcess(Basic): + """ + Base class for all the stochastic processes whether + discrete or continuous. + + Parameters + ========== + + sym: Symbol or str + state_space: Set + The state space of the stochastic process, by default S.Reals. + For discrete sets it is zero indexed. + + See Also + ======== + + DiscreteTimeStochasticProcess + """ + + index_set = S.Reals + + def __new__(cls, sym, state_space=S.Reals, **kwargs): + sym = _symbol_converter(sym) + state_space = _set_converter(state_space) + return Basic.__new__(cls, sym, state_space) + + @property + def symbol(self): + return self.args[0] + + @property + def state_space(self) -> FiniteSet | Range: + if not isinstance(self.args[1], (FiniteSet, Range)): + assert isinstance(self.args[1], Tuple) + return FiniteSet(*self.args[1]) + return self.args[1] + + def _deprecation_warn_distribution(self): + sympy_deprecation_warning( + """ + Calling the distribution method with a RandomIndexedSymbol + argument, like X.distribution(X(t)) is deprecated. Instead, call + distribution() with the given timestamp, like + + X.distribution(t) + """, + deprecated_since_version="1.7.1", + active_deprecations_target="deprecated-distribution-randomindexedsymbol", + stacklevel=4, + ) + + def distribution(self, key=None): + if key is None: + self._deprecation_warn_distribution() + return Distribution() + + def density(self, x): + return Density() + + def __call__(self, time): + """ + Overridden in ContinuousTimeStochasticProcess. + """ + raise NotImplementedError("Use [] for indexing discrete time stochastic process.") + + def __getitem__(self, time): + """ + Overridden in DiscreteTimeStochasticProcess. + """ + raise NotImplementedError("Use () for indexing continuous time stochastic process.") + + def probability(self, condition): + raise NotImplementedError() + + def joint_distribution(self, *args): + """ + Computes the joint distribution of the random indexed variables. + + Parameters + ========== + + args: iterable + The finite list of random indexed variables/the key of a stochastic + process whose joint distribution has to be computed. + + Returns + ======= + + JointDistribution + The joint distribution of the list of random indexed variables. + An unevaluated object is returned if it is not possible to + compute the joint distribution. + + Raises + ====== + + ValueError: When the arguments passed are not of type RandomIndexSymbol + or Number. + """ + args = list(args) + for i, arg in enumerate(args): + if S(arg).is_Number: + if self.index_set.is_subset(S.Integers): + args[i] = self.__getitem__(arg) + else: + args[i] = self.__call__(arg) + elif not isinstance(arg, RandomIndexedSymbol): + raise ValueError("Expected a RandomIndexedSymbol or " + "key not %s"%(type(arg))) + + if args[0].pspace.distribution == Distribution(): + return JointDistribution(*args) + density = Lambda(tuple(args), + expr=Mul.fromiter(arg.pspace.process.density(arg) for arg in args)) + return JointDistributionHandmade(density) + + def expectation(self, condition, given_condition): + raise NotImplementedError("Abstract method for expectation queries.") + + def sample(self): + raise NotImplementedError("Abstract method for sampling queries.") + +class DiscreteTimeStochasticProcess(StochasticProcess): + """ + Base class for all discrete stochastic processes. + """ + def __getitem__(self, time): + """ + For indexing discrete time stochastic processes. + + Returns + ======= + + RandomIndexedSymbol + """ + time = sympify(time) + if not time.is_symbol and time not in self.index_set: + raise IndexError("%s is not in the index set of %s"%(time, self.symbol)) + idx_obj = Indexed(self.symbol, time) + pspace_obj = StochasticPSpace(self.symbol, self, self.distribution(time)) + return RandomIndexedSymbol(idx_obj, pspace_obj) + +class ContinuousTimeStochasticProcess(StochasticProcess): + """ + Base class for all continuous time stochastic process. + """ + def __call__(self, time): + """ + For indexing continuous time stochastic processes. + + Returns + ======= + + RandomIndexedSymbol + """ + time = sympify(time) + if not time.is_symbol and time not in self.index_set: + raise IndexError("%s is not in the index set of %s"%(time, self.symbol)) + func_obj = Function(self.symbol)(time) + pspace_obj = StochasticPSpace(self.symbol, self, self.distribution(time)) + return RandomIndexedSymbol(func_obj, pspace_obj) + +class TransitionMatrixOf(Boolean): + """ + Assumes that the matrix is the transition matrix + of the process. + """ + + def __new__(cls, process, matrix): + if not isinstance(process, DiscreteMarkovChain): + raise ValueError("Currently only DiscreteMarkovChain " + "support TransitionMatrixOf.") + matrix = _matrix_checks(matrix) + return Basic.__new__(cls, process, matrix) + + process = property(lambda self: self.args[0]) + matrix = property(lambda self: self.args[1]) + +class GeneratorMatrixOf(TransitionMatrixOf): + """ + Assumes that the matrix is the generator matrix + of the process. + """ + + def __new__(cls, process, matrix): + if not isinstance(process, ContinuousMarkovChain): + raise ValueError("Currently only ContinuousMarkovChain " + "support GeneratorMatrixOf.") + matrix = _matrix_checks(matrix) + return Basic.__new__(cls, process, matrix) + +class StochasticStateSpaceOf(Boolean): + + def __new__(cls, process, state_space): + if not isinstance(process, (DiscreteMarkovChain, ContinuousMarkovChain)): + raise ValueError("Currently only DiscreteMarkovChain and ContinuousMarkovChain " + "support StochasticStateSpaceOf.") + state_space = _state_converter(state_space) + if isinstance(state_space, Range): + ss_size = ceiling((state_space.stop - state_space.start) / state_space.step) + else: + ss_size = len(state_space) + state_index = Range(ss_size) + return Basic.__new__(cls, process, state_index) + + process = property(lambda self: self.args[0]) + state_index = property(lambda self: self.args[1]) + +class MarkovProcess(StochasticProcess): + """ + Contains methods that handle queries + common to Markov processes. + """ + + @property + def number_of_states(self) -> Integer | Symbol: + """ + The number of states in the Markov Chain. + """ + return _sympify(self.args[2].shape[0]) # type: ignore + + @property + def _state_index(self): + """ + Returns state index as Range. + """ + return self.args[1] + + @classmethod + def _sanity_checks(cls, state_space, trans_probs): + # Try to never have None as state_space or trans_probs. + # This helps a lot if we get it done at the start. + if (state_space is None) and (trans_probs is None): + _n = Dummy('n', integer=True, nonnegative=True) + state_space = _state_converter(Range(_n)) + trans_probs = _matrix_checks(MatrixSymbol('_T', _n, _n)) + + elif state_space is None: + trans_probs = _matrix_checks(trans_probs) + state_space = _state_converter(Range(trans_probs.shape[0])) + + elif trans_probs is None: + state_space = _state_converter(state_space) + if isinstance(state_space, Range): + _n = ceiling((state_space.stop - state_space.start) / state_space.step) + else: + _n = len(state_space) + trans_probs = MatrixSymbol('_T', _n, _n) + + else: + state_space = _state_converter(state_space) + trans_probs = _matrix_checks(trans_probs) + # Range object doesn't want to give a symbolic size + # so we do it ourselves. + if isinstance(state_space, Range): + ss_size = ceiling((state_space.stop - state_space.start) / state_space.step) + else: + ss_size = len(state_space) + if ss_size != trans_probs.shape[0]: + raise ValueError('The size of the state space and the number of ' + 'rows of the transition matrix must be the same.') + + return state_space, trans_probs + + def _extract_information(self, given_condition): + """ + Helper function to extract information, like, + transition matrix/generator matrix, state space, etc. + """ + if isinstance(self, DiscreteMarkovChain): + trans_probs = self.transition_probabilities + state_index = self._state_index + elif isinstance(self, ContinuousMarkovChain): + trans_probs = self.generator_matrix + state_index = self._state_index + if isinstance(given_condition, And): + gcs = given_condition.args + given_condition = S.true + for gc in gcs: + if isinstance(gc, TransitionMatrixOf): + trans_probs = gc.matrix + if isinstance(gc, StochasticStateSpaceOf): + state_index = gc.state_index + if isinstance(gc, Relational): + given_condition = given_condition & gc + if isinstance(given_condition, TransitionMatrixOf): + trans_probs = given_condition.matrix + given_condition = S.true + if isinstance(given_condition, StochasticStateSpaceOf): + state_index = given_condition.state_index + given_condition = S.true + return trans_probs, state_index, given_condition + + def _check_trans_probs(self, trans_probs, row_sum=1): + """ + Helper function for checking the validity of transition + probabilities. + """ + if not isinstance(trans_probs, MatrixSymbol): + rows = trans_probs.tolist() + for row in rows: + if (sum(row) - row_sum) != 0: + raise ValueError("Values in a row must sum to %s. " + "If you are using Float or floats then please use Rational."%(row_sum)) + + def _work_out_state_index(self, state_index, given_condition, trans_probs): + """ + Helper function to extract state space if there + is a random symbol in the given condition. + """ + # if given condition is None, then there is no need to work out + # state_space from random variables + if given_condition != None: + rand_var = list(given_condition.atoms(RandomSymbol) - + given_condition.atoms(RandomIndexedSymbol)) + if len(rand_var) == 1: + state_index = rand_var[0].pspace.set + + # `not None` is `True`. So the old test fails for symbolic sizes. + # Need to build the statement differently. + sym_cond = not self.number_of_states.is_Integer + cond1 = not sym_cond and len(state_index) != trans_probs.shape[0] + if cond1: + raise ValueError("state space is not compatible with the transition probabilities.") + if not isinstance(trans_probs.shape[0], Symbol): + state_index = FiniteSet(*range(trans_probs.shape[0])) + return state_index + + @cacheit + def _preprocess(self, given_condition, evaluate): + """ + Helper function for pre-processing the information. + """ + is_insufficient = False + + if not evaluate: # avoid pre-processing if the result is not to be evaluated + return (True, None, None, None) + + # extracting transition matrix and state space + trans_probs, state_index, given_condition = self._extract_information(given_condition) + + # given_condition does not have sufficient information + # for computations + if trans_probs is None or \ + given_condition is None: + is_insufficient = True + else: + # checking transition probabilities + if isinstance(self, DiscreteMarkovChain): + self._check_trans_probs(trans_probs, row_sum=1) + elif isinstance(self, ContinuousMarkovChain): + self._check_trans_probs(trans_probs, row_sum=0) + + # working out state space + state_index = self._work_out_state_index(state_index, given_condition, trans_probs) + + return is_insufficient, trans_probs, state_index, given_condition + + def replace_with_index(self, condition): + if isinstance(condition, Relational): + lhs, rhs = condition.lhs, condition.rhs + if not isinstance(lhs, RandomIndexedSymbol): + lhs, rhs = rhs, lhs + condition = type(condition)(self.index_of.get(lhs, lhs), + self.index_of.get(rhs, rhs)) + return condition + + def probability(self, condition, given_condition=None, evaluate=True, **kwargs): + """ + Handles probability queries for Markov process. + + Parameters + ========== + + condition: Relational + given_condition: Relational/And + + Returns + ======= + Probability + If the information is not sufficient. + Expr + In all other cases. + + Note + ==== + Any information passed at the time of query overrides + any information passed at the time of object creation like + transition probabilities, state space. + Pass the transition matrix using TransitionMatrixOf, + generator matrix using GeneratorMatrixOf and state space + using StochasticStateSpaceOf in given_condition using & or And. + """ + check, mat, state_index, new_given_condition = \ + self._preprocess(given_condition, evaluate) + + rv = list(condition.atoms(RandomIndexedSymbol)) + symbolic = False + for sym in rv: + if sym.key.is_symbol: + symbolic = True + break + + if check: + return Probability(condition, new_given_condition) + + if isinstance(self, ContinuousMarkovChain): + trans_probs = self.transition_probabilities(mat) + elif isinstance(self, DiscreteMarkovChain): + trans_probs = mat + condition = self.replace_with_index(condition) + given_condition = self.replace_with_index(given_condition) + new_given_condition = self.replace_with_index(new_given_condition) + + if isinstance(condition, Relational): + if isinstance(new_given_condition, And): + gcs = new_given_condition.args + else: + gcs = (new_given_condition, ) + min_key_rv = list(new_given_condition.atoms(RandomIndexedSymbol)) + + if len(min_key_rv): + min_key_rv = min_key_rv[0] + for r in rv: + if min_key_rv.key.is_symbol or r.key.is_symbol: + continue + if min_key_rv.key > r.key: + return Probability(condition) + else: + min_key_rv = None + return Probability(condition) + + if symbolic: + return self._symbolic_probability(condition, new_given_condition, rv, min_key_rv) + + if len(rv) > 1: + rv[0] = condition.lhs + rv[1] = condition.rhs + if rv[0].key < rv[1].key: + rv[0], rv[1] = rv[1], rv[0] + if isinstance(condition, Gt): + condition = Lt(condition.lhs, condition.rhs) + elif isinstance(condition, Lt): + condition = Gt(condition.lhs, condition.rhs) + elif isinstance(condition, Ge): + condition = Le(condition.lhs, condition.rhs) + elif isinstance(condition, Le): + condition = Ge(condition.lhs, condition.rhs) + s = Rational(0, 1) + n = len(self.state_space) + + if isinstance(condition, (Eq, Ne)): + for i in range(0, n): + s += self.probability(Eq(rv[0], i), Eq(rv[1], i)) * self.probability(Eq(rv[1], i), new_given_condition) + return s if isinstance(condition, Eq) else 1 - s + else: + upper = 0 + greater = False + if isinstance(condition, (Ge, Lt)): + upper = 1 + if isinstance(condition, (Ge, Gt)): + greater = True + + for i in range(0, n): + if i <= n//2: + for j in range(0, i + upper): + s += self.probability(Eq(rv[0], i), Eq(rv[1], j)) * self.probability(Eq(rv[1], j), new_given_condition) + else: + s += self.probability(Eq(rv[0], i), new_given_condition) + for j in range(i + upper, n): + s -= self.probability(Eq(rv[0], i), Eq(rv[1], j)) * self.probability(Eq(rv[1], j), new_given_condition) + return s if greater else 1 - s + + rv = rv[0] + states = condition.as_set() + prob, gstate = {}, None + for gc in gcs: + if gc.has(min_key_rv): + if gc.has(Probability): + p, gp = (gc.rhs, gc.lhs) if isinstance(gc.lhs, Probability) \ + else (gc.lhs, gc.rhs) + gr = gp.args[0] + gset = Intersection(gr.as_set(), state_index) + gstate = list(gset)[0] + prob[gset] = p + else: + _, gstate = (gc.lhs.key, gc.rhs) if isinstance(gc.lhs, RandomIndexedSymbol) \ + else (gc.rhs.key, gc.lhs) + + if not all(k in self.index_set for k in (rv.key, min_key_rv.key)): + raise IndexError("The timestamps of the process are not in it's index set.") + states = Intersection(states, state_index) if not isinstance(self.number_of_states, Symbol) else states + for state in Union(states, FiniteSet(gstate)): + if not state.is_Integer or Ge(state, mat.shape[0]) is True: + raise IndexError("No information is available for (%s, %s) in " + "transition probabilities of shape, (%s, %s). " + "State space is zero indexed." + %(gstate, state, mat.shape[0], mat.shape[1])) + if prob: + gstates = Union(*prob.keys()) + if len(gstates) == 1: + gstate = list(gstates)[0] + gprob = list(prob.values())[0] + prob[gstates] = gprob + elif len(gstates) == len(state_index) - 1: + gstate = list(state_index - gstates)[0] + gprob = S.One - sum(prob.values()) + prob[state_index - gstates] = gprob + else: + raise ValueError("Conflicting information.") + else: + gprob = S.One + + if min_key_rv == rv: + return sum(prob[FiniteSet(state)] for state in states) + if isinstance(self, ContinuousMarkovChain): + return gprob * sum(trans_probs(rv.key - min_key_rv.key).__getitem__((gstate, state)) + for state in states) + if isinstance(self, DiscreteMarkovChain): + return gprob * sum((trans_probs**(rv.key - min_key_rv.key)).__getitem__((gstate, state)) + for state in states) + + if isinstance(condition, Not): + expr = condition.args[0] + return S.One - self.probability(expr, given_condition, evaluate, **kwargs) + + if isinstance(condition, And): + compute_later, state2cond, conds = [], {}, condition.args + for expr in conds: + if isinstance(expr, Relational): + ris = list(expr.atoms(RandomIndexedSymbol))[0] + if state2cond.get(ris, None) is None: + state2cond[ris] = S.true + state2cond[ris] &= expr + else: + compute_later.append(expr) + ris = [] + for ri in state2cond: + ris.append(ri) + cset = Intersection(state2cond[ri].as_set(), state_index) + if len(cset) == 0: + return S.Zero + state2cond[ri] = cset.as_relational(ri) + sorted_ris = sorted(ris, key=lambda ri: ri.key) + prod = self.probability(state2cond[sorted_ris[0]], given_condition, evaluate, **kwargs) + for i in range(1, len(sorted_ris)): + ri, prev_ri = sorted_ris[i], sorted_ris[i-1] + if not isinstance(state2cond[ri], Eq): + raise ValueError("The process is in multiple states at %s, unable to determine the probability."%(ri)) + mat_of = TransitionMatrixOf(self, mat) if isinstance(self, DiscreteMarkovChain) else GeneratorMatrixOf(self, mat) + prod *= self.probability(state2cond[ri], state2cond[prev_ri] + & mat_of + & StochasticStateSpaceOf(self, state_index), + evaluate, **kwargs) + for expr in compute_later: + prod *= self.probability(expr, given_condition, evaluate, **kwargs) + return prod + + if isinstance(condition, Or): + return sum(self.probability(expr, given_condition, evaluate, **kwargs) + for expr in condition.args) + + raise NotImplementedError("Mechanism for handling (%s, %s) queries hasn't been " + "implemented yet."%(condition, given_condition)) + + def _symbolic_probability(self, condition, new_given_condition, rv, min_key_rv): + #Function to calculate probability for queries with symbols + if isinstance(condition, Relational): + curr_state = new_given_condition.rhs if isinstance(new_given_condition.lhs, RandomIndexedSymbol) \ + else new_given_condition.lhs + next_state = condition.rhs if isinstance(condition.lhs, RandomIndexedSymbol) \ + else condition.lhs + + if isinstance(condition, (Eq, Ne)): + if isinstance(self, DiscreteMarkovChain): + P = self.transition_probabilities**(rv[0].key - min_key_rv.key) + else: + P = exp(self.generator_matrix*(rv[0].key - min_key_rv.key)) + prob = P[curr_state, next_state] if isinstance(condition, Eq) else 1 - P[curr_state, next_state] + return Piecewise((prob, rv[0].key > min_key_rv.key), (Probability(condition), True)) + else: + upper = 1 + greater = False + if isinstance(condition, (Ge, Lt)): + upper = 0 + if isinstance(condition, (Ge, Gt)): + greater = True + k = Dummy('k') + condition = Eq(condition.lhs, k) if isinstance(condition.lhs, RandomIndexedSymbol)\ + else Eq(condition.rhs, k) + total = Sum(self.probability(condition, new_given_condition), (k, next_state + upper, self.state_space._sup)) + return Piecewise((total, rv[0].key > min_key_rv.key), (Probability(condition), True)) if greater\ + else Piecewise((1 - total, rv[0].key > min_key_rv.key), (Probability(condition), True)) + else: + return Probability(condition, new_given_condition) + + def expectation(self, expr, condition=None, evaluate=True, **kwargs): + """ + Handles expectation queries for markov process. + + Parameters + ========== + + expr: RandomIndexedSymbol, Relational, Logic + Condition for which expectation has to be computed. Must + contain a RandomIndexedSymbol of the process. + condition: Relational, Logic + The given conditions under which computations should be done. + + Returns + ======= + + Expectation + Unevaluated object if computations cannot be done due to + insufficient information. + Expr + In all other cases when the computations are successful. + + Note + ==== + + Any information passed at the time of query overrides + any information passed at the time of object creation like + transition probabilities, state space. + + Pass the transition matrix using TransitionMatrixOf, + generator matrix using GeneratorMatrixOf and state space + using StochasticStateSpaceOf in given_condition using & or And. + """ + + check, mat, state_index, condition = \ + self._preprocess(condition, evaluate) + + if check: + return Expectation(expr, condition) + + rvs = random_symbols(expr) + if isinstance(expr, Expr) and isinstance(condition, Eq) \ + and len(rvs) == 1: + # handle queries similar to E(f(X[i]), Eq(X[i-m], )) + condition=self.replace_with_index(condition) + state_index=self.replace_with_index(state_index) + rv = list(rvs)[0] + lhsg, rhsg = condition.lhs, condition.rhs + if not isinstance(lhsg, RandomIndexedSymbol): + lhsg, rhsg = (rhsg, lhsg) + if rhsg not in state_index: + raise ValueError("%s state is not in the state space."%(rhsg)) + if rv.key < lhsg.key: + raise ValueError("Incorrect given condition is given, expectation " + "time %s < time %s"%(rv.key, rv.key)) + mat_of = TransitionMatrixOf(self, mat) if isinstance(self, DiscreteMarkovChain) else GeneratorMatrixOf(self, mat) + cond = condition & mat_of & \ + StochasticStateSpaceOf(self, state_index) + func = lambda s: self.probability(Eq(rv, s), cond) * expr.subs(rv, self._state_index[s]) + return sum(func(s) for s in state_index) + + raise NotImplementedError("Mechanism for handling (%s, %s) queries hasn't been " + "implemented yet."%(expr, condition)) + +class DiscreteMarkovChain(DiscreteTimeStochasticProcess, MarkovProcess): + """ + Represents a finite discrete time-homogeneous Markov chain. + + This type of Markov Chain can be uniquely characterised by + its (ordered) state space and its one-step transition probability + matrix. + + Parameters + ========== + + sym: + The name given to the Markov Chain + state_space: + Optional, by default, Range(n) + trans_probs: + Optional, by default, MatrixSymbol('_T', n, n) + + Examples + ======== + + >>> from sympy.stats import DiscreteMarkovChain, TransitionMatrixOf, P, E + >>> from sympy import Matrix, MatrixSymbol, Eq, symbols + >>> T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]]) + >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T) + >>> YS = DiscreteMarkovChain("Y") + + >>> Y.state_space + {0, 1, 2} + >>> Y.transition_probabilities + Matrix([ + [0.5, 0.2, 0.3], + [0.2, 0.5, 0.3], + [0.2, 0.3, 0.5]]) + >>> TS = MatrixSymbol('T', 3, 3) + >>> P(Eq(YS[3], 2), Eq(YS[1], 1) & TransitionMatrixOf(YS, TS)) + T[0, 2]*T[1, 0] + T[1, 1]*T[1, 2] + T[1, 2]*T[2, 2] + >>> P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) + 0.36 + + Probabilities will be calculated based on indexes rather + than state names. For example, with the Sunny-Cloudy-Rainy + model with string state names: + + >>> from sympy.core.symbol import Str + >>> Y = DiscreteMarkovChain("Y", [Str('Sunny'), Str('Cloudy'), Str('Rainy')], T) + >>> P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) + 0.36 + + This gives the same answer as the ``[0, 1, 2]`` state space. + Currently, there is no support for state names within probability + and expectation statements. Here is a work-around using ``Str``: + + >>> P(Eq(Str('Rainy'), Y[3]), Eq(Y[1], Str('Cloudy'))).round(2) + 0.36 + + Symbol state names can also be used: + + >>> sunny, cloudy, rainy = symbols('Sunny, Cloudy, Rainy') + >>> Y = DiscreteMarkovChain("Y", [sunny, cloudy, rainy], T) + >>> P(Eq(Y[3], rainy), Eq(Y[1], cloudy)).round(2) + 0.36 + + Expectations will be calculated as follows: + + >>> E(Y[3], Eq(Y[1], cloudy)) + 0.38*Cloudy + 0.36*Rainy + 0.26*Sunny + + Probability of expressions with multiple RandomIndexedSymbols + can also be calculated provided there is only 1 RandomIndexedSymbol + in the given condition. It is always better to use Rational instead + of floating point numbers for the probabilities in the + transition matrix to avoid errors. + + >>> from sympy import Gt, Le, Rational + >>> T = Matrix([[Rational(5, 10), Rational(3, 10), Rational(2, 10)], [Rational(2, 10), Rational(7, 10), Rational(1, 10)], [Rational(3, 10), Rational(3, 10), Rational(4, 10)]]) + >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T) + >>> P(Eq(Y[3], Y[1]), Eq(Y[0], 0)).round(3) + 0.409 + >>> P(Gt(Y[3], Y[1]), Eq(Y[0], 0)).round(2) + 0.36 + >>> P(Le(Y[15], Y[10]), Eq(Y[8], 2)).round(7) + 0.6963328 + + Symbolic probability queries are also supported + + >>> a, b, c, d = symbols('a b c d') + >>> T = Matrix([[Rational(1, 10), Rational(4, 10), Rational(5, 10)], [Rational(3, 10), Rational(4, 10), Rational(3, 10)], [Rational(7, 10), Rational(2, 10), Rational(1, 10)]]) + >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T) + >>> query = P(Eq(Y[a], b), Eq(Y[c], d)) + >>> query.subs({a:10, b:2, c:5, d:1}).round(4) + 0.3096 + >>> P(Eq(Y[10], 2), Eq(Y[5], 1)).evalf().round(4) + 0.3096 + >>> query_gt = P(Gt(Y[a], b), Eq(Y[c], d)) + >>> query_gt.subs({a:21, b:0, c:5, d:0}).evalf().round(5) + 0.64705 + >>> P(Gt(Y[21], 0), Eq(Y[5], 0)).round(5) + 0.64705 + + There is limited support for arbitrarily sized states: + + >>> n = symbols('n', nonnegative=True, integer=True) + >>> T = MatrixSymbol('T', n, n) + >>> Y = DiscreteMarkovChain("Y", trans_probs=T) + >>> Y.state_space + Range(0, n, 1) + >>> query = P(Eq(Y[a], b), Eq(Y[c], d)) + >>> query.subs({a:10, b:2, c:5, d:1}) + (T**5)[1, 2] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Markov_chain#Discrete-time_Markov_chain + .. [2] https://web.archive.org/web/20201230182007/https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf + """ + index_set = S.Naturals0 + + def __new__(cls, sym, state_space=None, trans_probs=None): + sym = _symbol_converter(sym) + + state_space, trans_probs = MarkovProcess._sanity_checks(state_space, trans_probs) + + obj = Basic.__new__(cls, sym, state_space, trans_probs) # type: ignore + indices = {} + if isinstance(obj.number_of_states, Integer): + for index, state in enumerate(obj._state_index): + indices[state] = index + obj.index_of = indices + return obj + + @property + def transition_probabilities(self): + """ + Transition probabilities of discrete Markov chain, + either an instance of Matrix or MatrixSymbol. + """ + return self.args[2] + + def communication_classes(self) -> list[tuple[list[Basic], Boolean, Integer]]: + """ + Returns the list of communication classes that partition + the states of the markov chain. + + A communication class is defined to be a set of states + such that every state in that set is reachable from + every other state in that set. Due to its properties + this forms a class in the mathematical sense. + Communication classes are also known as recurrence + classes. + + Returns + ======= + + classes + The ``classes`` are a list of tuples. Each + tuple represents a single communication class + with its properties. The first element in the + tuple is the list of states in the class, the + second element is whether the class is recurrent + and the third element is the period of the + communication class. + + Examples + ======== + + >>> from sympy.stats import DiscreteMarkovChain + >>> from sympy import Matrix + >>> T = Matrix([[0, 1, 0], + ... [1, 0, 0], + ... [1, 0, 0]]) + >>> X = DiscreteMarkovChain('X', [1, 2, 3], T) + >>> classes = X.communication_classes() + >>> for states, is_recurrent, period in classes: + ... states, is_recurrent, period + ([1, 2], True, 2) + ([3], False, 1) + + From this we can see that states ``1`` and ``2`` + communicate, are recurrent and have a period + of 2. We can also see state ``3`` is transient + with a period of 1. + + Notes + ===== + + The algorithm used is of order ``O(n**2)`` where + ``n`` is the number of states in the markov chain. + It uses Tarjan's algorithm to find the classes + themselves and then it uses a breadth-first search + algorithm to find each class's periodicity. + Most of the algorithm's components approach ``O(n)`` + as the matrix becomes more and more sparse. + + References + ========== + + .. [1] https://web.archive.org/web/20220207032113/https://www.columbia.edu/~ww2040/4701Sum07/4701-06-Notes-MCII.pdf + .. [2] https://cecas.clemson.edu/~shierd/Shier/markov.pdf + .. [3] https://www.proquest.com/openview/4adc6a51d8371be5b0e4c7dff287fc70/1?pq-origsite=gscholar&cbl=2026366&diss=y + .. [4] https://www.mathworks.com/help/econ/dtmc.classify.html + """ + n = self.number_of_states + T = self.transition_probabilities + + if isinstance(T, MatrixSymbol): + raise NotImplementedError("Cannot perform the operation with a symbolic matrix.") + + # begin Tarjan's algorithm + V = Range(n) + # don't use state names. Rather use state + # indexes since we use them for matrix + # indexing here and later onward + E = [(i, j) for i in V for j in V if T[i, j] != 0] + classes = strongly_connected_components((V, E)) + # end Tarjan's algorithm + + recurrence = [] + periods = [] + for class_ in classes: + # begin recurrent check (similar to self._check_trans_probs()) + submatrix = T[class_, class_] # get the submatrix with those states + is_recurrent = S.true + rows = submatrix.tolist() + for row in rows: + if (sum(row) - 1) != 0: + is_recurrent = S.false + break + recurrence.append(is_recurrent) + # end recurrent check + + # begin breadth-first search + non_tree_edge_values: set[int] = set() + visited = {class_[0]} + newly_visited = {class_[0]} + level = {class_[0]: 0} + current_level = 0 + done = False # imitate a do-while loop + while not done: # runs at most len(class_) times + done = len(visited) == len(class_) + current_level += 1 + + # this loop and the while loop above run a combined len(class_) number of times. + # so this triple nested loop runs through each of the n states once. + for i in newly_visited: + + # the loop below runs len(class_) number of times + # complexity is around about O(n * avg(len(class_))) + newly_visited = {j for j in class_ if T[i, j] != 0} + + new_tree_edges = newly_visited.difference(visited) + for j in new_tree_edges: + level[j] = current_level + + new_non_tree_edges = newly_visited.intersection(visited) + new_non_tree_edge_values = {level[i]-level[j]+1 for j in new_non_tree_edges} + + non_tree_edge_values = non_tree_edge_values.union(new_non_tree_edge_values) + visited = visited.union(new_tree_edges) + + # igcd needs at least 2 arguments + positive_ntev = {val_e for val_e in non_tree_edge_values if val_e > 0} + if len(positive_ntev) == 0: + periods.append(len(class_)) + elif len(positive_ntev) == 1: + periods.append(positive_ntev.pop()) + else: + periods.append(igcd(*positive_ntev)) + # end breadth-first search + + # convert back to the user's state names + classes = [[_sympify(self._state_index[i]) for i in class_] for class_ in classes] + return list(zip(classes, recurrence, map(Integer,periods))) + + def fundamental_matrix(self): + """ + Each entry fundamental matrix can be interpreted as + the expected number of times the chains is in state j + if it started in state i. + + References + ========== + + .. [1] https://lips.cs.princeton.edu/the-fundamental-matrix-of-a-finite-markov-chain/ + + """ + _, _, _, Q = self.decompose() + + if Q.shape[0] > 0: # if non-ergodic + I = eye(Q.shape[0]) + if (I - Q).det() == 0: + raise ValueError("The fundamental matrix doesn't exist.") + return (I - Q).inv().as_immutable() + else: # if ergodic + P = self.transition_probabilities + I = eye(P.shape[0]) + w = self.fixed_row_vector() + W = Matrix([list(w) for i in range(0, P.shape[0])]) + if (I - P + W).det() == 0: + raise ValueError("The fundamental matrix doesn't exist.") + return (I - P + W).inv().as_immutable() + + def absorbing_probabilities(self): + """ + Computes the absorbing probabilities, i.e. + the ij-th entry of the matrix denotes the + probability of Markov chain being absorbed + in state j starting from state i. + """ + _, _, R, _ = self.decompose() + N = self.fundamental_matrix() + if R is None or N is None: + return None + return N*R + + def absorbing_probabilites(self): + sympy_deprecation_warning( + """ + DiscreteMarkovChain.absorbing_probabilites() is deprecated. Use + absorbing_probabilities() instead (note the spelling difference). + """, + deprecated_since_version="1.7", + active_deprecations_target="deprecated-absorbing_probabilites", + ) + return self.absorbing_probabilities() + + def is_regular(self): + tuples = self.communication_classes() + if len(tuples) == 0: + return S.false # not defined for a 0x0 matrix + classes, _, periods = list(zip(*tuples)) + return And(len(classes) == 1, periods[0] == 1) + + def is_ergodic(self): + tuples = self.communication_classes() + if len(tuples) == 0: + return S.false # not defined for a 0x0 matrix + classes, _, _ = list(zip(*tuples)) + return S(len(classes) == 1) + + def is_absorbing_state(self, state): + trans_probs = self.transition_probabilities + if isinstance(trans_probs, ImmutableMatrix) and \ + state < trans_probs.shape[0]: + return S(trans_probs[state, state]) is S.One + + def is_absorbing_chain(self): + states, A, B, C = self.decompose() + r = A.shape[0] + return And(r > 0, A == Identity(r).as_explicit()) + + def stationary_distribution(self, condition_set=False) -> ImmutableMatrix | ConditionSet | Lambda: + r""" + The stationary distribution is any row vector, p, that solves p = pP, + is row stochastic and each element in p must be nonnegative. + That means in matrix form: :math:`(P-I)^T p^T = 0` and + :math:`(1, \dots, 1) p = 1` + where ``P`` is the one-step transition matrix. + + All time-homogeneous Markov Chains with a finite state space + have at least one stationary distribution. In addition, if + a finite time-homogeneous Markov Chain is irreducible, the + stationary distribution is unique. + + Parameters + ========== + + condition_set : bool + If the chain has a symbolic size or transition matrix, + it will return a ``Lambda`` if ``False`` and return a + ``ConditionSet`` if ``True``. + + Examples + ======== + + >>> from sympy.stats import DiscreteMarkovChain + >>> from sympy import Matrix, S + + An irreducible Markov Chain + + >>> T = Matrix([[S(1)/2, S(1)/2, 0], + ... [S(4)/5, S(1)/5, 0], + ... [1, 0, 0]]) + >>> X = DiscreteMarkovChain('X', trans_probs=T) + >>> X.stationary_distribution() + Matrix([[8/13, 5/13, 0]]) + + A reducible Markov Chain + + >>> T = Matrix([[S(1)/2, S(1)/2, 0], + ... [S(4)/5, S(1)/5, 0], + ... [0, 0, 1]]) + >>> X = DiscreteMarkovChain('X', trans_probs=T) + >>> X.stationary_distribution() + Matrix([[8/13 - 8*tau0/13, 5/13 - 5*tau0/13, tau0]]) + + >>> Y = DiscreteMarkovChain('Y') + >>> Y.stationary_distribution() + Lambda((wm, _T), Eq(wm*_T, wm)) + + >>> Y.stationary_distribution(condition_set=True) + ConditionSet(wm, Eq(wm*_T, wm)) + + References + ========== + + .. [1] https://www.probabilitycourse.com/chapter11/11_2_6_stationary_and_limiting_distributions.php + .. [2] https://web.archive.org/web/20210508104430/https://galton.uchicago.edu/~yibi/teaching/stat317/2014/Lectures/Lecture4_6up.pdf + + See Also + ======== + + sympy.stats.DiscreteMarkovChain.limiting_distribution + """ + trans_probs = self.transition_probabilities + n = self.number_of_states + + if n == 0: + return ImmutableMatrix(Matrix([[]])) + + # symbolic matrix version + if isinstance(trans_probs, MatrixSymbol): + wm = MatrixSymbol('wm', 1, n) + if condition_set: + return ConditionSet(wm, Eq(wm * trans_probs, wm)) + else: + return Lambda((wm, trans_probs), Eq(wm * trans_probs, wm)) + + # numeric matrix version + a = Matrix(trans_probs - Identity(n)).T + a[0, 0:n] = ones(1, n) # type: ignore + b = zeros(n, 1) + b[0, 0] = 1 + + soln = list(linsolve((a, b)))[0] + return ImmutableMatrix([soln]) + + def fixed_row_vector(self): + """ + A wrapper for ``stationary_distribution()``. + """ + return self.stationary_distribution() + + @property + def limiting_distribution(self): + """ + The fixed row vector is the limiting + distribution of a discrete Markov chain. + """ + return self.fixed_row_vector() + + def decompose(self) -> tuple[list[Basic], ImmutableMatrix, ImmutableMatrix, ImmutableMatrix]: + """ + Decomposes the transition matrix into submatrices with + special properties. + + The transition matrix can be decomposed into 4 submatrices: + - A - the submatrix from recurrent states to recurrent states. + - B - the submatrix from transient to recurrent states. + - C - the submatrix from transient to transient states. + - O - the submatrix of zeros for recurrent to transient states. + + Returns + ======= + + states, A, B, C + ``states`` - a list of state names with the first being + the recurrent states and the last being + the transient states in the order + of the row names of A and then the row names of C. + ``A`` - the submatrix from recurrent states to recurrent states. + ``B`` - the submatrix from transient to recurrent states. + ``C`` - the submatrix from transient to transient states. + + Examples + ======== + + >>> from sympy.stats import DiscreteMarkovChain + >>> from sympy import Matrix, S + + One can decompose this chain for example: + + >>> T = Matrix([[S(1)/2, S(1)/2, 0, 0, 0], + ... [S(2)/5, S(1)/5, S(2)/5, 0, 0], + ... [0, 0, 1, 0, 0], + ... [0, 0, S(1)/2, S(1)/2, 0], + ... [S(1)/2, 0, 0, 0, S(1)/2]]) + >>> X = DiscreteMarkovChain('X', trans_probs=T) + >>> states, A, B, C = X.decompose() + >>> states + [2, 0, 1, 3, 4] + + >>> A # recurrent to recurrent + Matrix([[1]]) + + >>> B # transient to recurrent + Matrix([ + [ 0], + [2/5], + [1/2], + [ 0]]) + + >>> C # transient to transient + Matrix([ + [1/2, 1/2, 0, 0], + [2/5, 1/5, 0, 0], + [ 0, 0, 1/2, 0], + [1/2, 0, 0, 1/2]]) + + This means that state 2 is the only absorbing state + (since A is a 1x1 matrix). B is a 4x1 matrix since + the 4 remaining transient states all merge into recurrent + state 2. And C is the 4x4 matrix that shows how the + transient states 0, 1, 3, 4 all interact. + + See Also + ======== + + sympy.stats.DiscreteMarkovChain.communication_classes + sympy.stats.DiscreteMarkovChain.canonical_form + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Absorbing_Markov_chain + .. [2] https://people.brandeis.edu/~igusa/Math56aS08/Math56a_S08_notes015.pdf + """ + trans_probs = self.transition_probabilities + + classes = self.communication_classes() + r_states = [] + t_states = [] + + for states, recurrent, period in classes: + if recurrent: + r_states += states + else: + t_states += states + + states = r_states + t_states + indexes = [self.index_of[state] for state in states] # type: ignore + + A = Matrix(len(r_states), len(r_states), + lambda i, j: trans_probs[indexes[i], indexes[j]]) + + B = Matrix(len(t_states), len(r_states), + lambda i, j: trans_probs[indexes[len(r_states) + i], indexes[j]]) + + C = Matrix(len(t_states), len(t_states), + lambda i, j: trans_probs[indexes[len(r_states) + i], indexes[len(r_states) + j]]) + + return states, A.as_immutable(), B.as_immutable(), C.as_immutable() + + def canonical_form(self) -> tuple[list[Basic], ImmutableMatrix]: + """ + Reorders the one-step transition matrix + so that recurrent states appear first and transient + states appear last. Other representations include inserting + transient states first and recurrent states last. + + Returns + ======= + + states, P_new + ``states`` is the list that describes the order of the + new states in the matrix + so that the ith element in ``states`` is the state of the + ith row of A. + ``P_new`` is the new transition matrix in canonical form. + + Examples + ======== + + >>> from sympy.stats import DiscreteMarkovChain + >>> from sympy import Matrix, S + + You can convert your chain into canonical form: + + >>> T = Matrix([[S(1)/2, S(1)/2, 0, 0, 0], + ... [S(2)/5, S(1)/5, S(2)/5, 0, 0], + ... [0, 0, 1, 0, 0], + ... [0, 0, S(1)/2, S(1)/2, 0], + ... [S(1)/2, 0, 0, 0, S(1)/2]]) + >>> X = DiscreteMarkovChain('X', list(range(1, 6)), trans_probs=T) + >>> states, new_matrix = X.canonical_form() + >>> states + [3, 1, 2, 4, 5] + + >>> new_matrix + Matrix([ + [ 1, 0, 0, 0, 0], + [ 0, 1/2, 1/2, 0, 0], + [2/5, 2/5, 1/5, 0, 0], + [1/2, 0, 0, 1/2, 0], + [ 0, 1/2, 0, 0, 1/2]]) + + The new states are [3, 1, 2, 4, 5] and you can + create a new chain with this and its canonical + form will remain the same (since it is already + in canonical form). + + >>> X = DiscreteMarkovChain('X', states, new_matrix) + >>> states, new_matrix = X.canonical_form() + >>> states + [3, 1, 2, 4, 5] + + >>> new_matrix + Matrix([ + [ 1, 0, 0, 0, 0], + [ 0, 1/2, 1/2, 0, 0], + [2/5, 2/5, 1/5, 0, 0], + [1/2, 0, 0, 1/2, 0], + [ 0, 1/2, 0, 0, 1/2]]) + + This is not limited to absorbing chains: + + >>> T = Matrix([[0, 5, 5, 0, 0], + ... [0, 0, 0, 10, 0], + ... [5, 0, 5, 0, 0], + ... [0, 10, 0, 0, 0], + ... [0, 3, 0, 3, 4]])/10 + >>> X = DiscreteMarkovChain('X', trans_probs=T) + >>> states, new_matrix = X.canonical_form() + >>> states + [1, 3, 0, 2, 4] + + >>> new_matrix + Matrix([ + [ 0, 1, 0, 0, 0], + [ 1, 0, 0, 0, 0], + [ 1/2, 0, 0, 1/2, 0], + [ 0, 0, 1/2, 1/2, 0], + [3/10, 3/10, 0, 0, 2/5]]) + + See Also + ======== + + sympy.stats.DiscreteMarkovChain.communication_classes + sympy.stats.DiscreteMarkovChain.decompose + + References + ========== + + .. [1] https://onlinelibrary.wiley.com/doi/pdf/10.1002/9780470316887.app1 + .. [2] http://www.columbia.edu/~ww2040/6711F12/lect1023big.pdf + """ + states, A, B, C = self.decompose() + O = zeros(A.shape[0], C.shape[1]) + return states, BlockMatrix([[A, O], [B, C]]).as_explicit() + + def sample(self): + """ + Returns + ======= + + sample: iterator object + iterator object containing the sample + + """ + if not isinstance(self.transition_probabilities, (Matrix, ImmutableMatrix)): + raise ValueError("Transition Matrix must be provided for sampling") + Tlist = self.transition_probabilities.tolist() + samps = [random.choice(list(self.state_space))] + yield samps[0] + time = 1 + densities = {} + for state in self.state_space: + states = list(self.state_space) + densities[state] = {states[i]: Tlist[state][i] + for i in range(len(states))} + while time < S.Infinity: + samps.append((next(sample_iter(FiniteRV("_", densities[samps[time - 1]]))))) + yield samps[time] + time += 1 + +class ContinuousMarkovChain(ContinuousTimeStochasticProcess, MarkovProcess): + """ + Represents continuous time Markov chain. + + Parameters + ========== + + sym : Symbol/str + state_space : Set + Optional, by default, S.Reals + gen_mat : Matrix/ImmutableMatrix/MatrixSymbol + Optional, by default, None + + Examples + ======== + + >>> from sympy.stats import ContinuousMarkovChain, P + >>> from sympy import Matrix, S, Eq, Gt + >>> G = Matrix([[-S(1), S(1)], [S(1), -S(1)]]) + >>> C = ContinuousMarkovChain('C', state_space=[0, 1], gen_mat=G) + >>> C.limiting_distribution() + Matrix([[1/2, 1/2]]) + >>> C.state_space + {0, 1} + >>> C.generator_matrix + Matrix([ + [-1, 1], + [ 1, -1]]) + + Probability queries are supported + + >>> P(Eq(C(1.96), 0), Eq(C(0.78), 1)).round(5) + 0.45279 + >>> P(Gt(C(1.7), 0), Eq(C(0.82), 1)).round(5) + 0.58602 + + Probability of expressions with multiple RandomIndexedSymbols + can also be calculated provided there is only 1 RandomIndexedSymbol + in the given condition. It is always better to use Rational instead + of floating point numbers for the probabilities in the + generator matrix to avoid errors. + + >>> from sympy import Gt, Le, Rational + >>> G = Matrix([[-S(1), Rational(1, 10), Rational(9, 10)], [Rational(2, 5), -S(1), Rational(3, 5)], [Rational(1, 2), Rational(1, 2), -S(1)]]) + >>> C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G) + >>> P(Eq(C(3.92), C(1.75)), Eq(C(0.46), 0)).round(5) + 0.37933 + >>> P(Gt(C(3.92), C(1.75)), Eq(C(0.46), 0)).round(5) + 0.34211 + >>> P(Le(C(1.57), C(3.14)), Eq(C(1.22), 1)).round(4) + 0.7143 + + Symbolic probability queries are also supported + + >>> from sympy import symbols + >>> a,b,c,d = symbols('a b c d') + >>> G = Matrix([[-S(1), Rational(1, 10), Rational(9, 10)], [Rational(2, 5), -S(1), Rational(3, 5)], [Rational(1, 2), Rational(1, 2), -S(1)]]) + >>> C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G) + >>> query = P(Eq(C(a), b), Eq(C(c), d)) + >>> query.subs({a:3.65, b:2, c:1.78, d:1}).evalf().round(10) + 0.4002723175 + >>> P(Eq(C(3.65), 2), Eq(C(1.78), 1)).round(10) + 0.4002723175 + >>> query_gt = P(Gt(C(a), b), Eq(C(c), d)) + >>> query_gt.subs({a:43.2, b:0, c:3.29, d:2}).evalf().round(10) + 0.6832579186 + >>> P(Gt(C(43.2), 0), Eq(C(3.29), 2)).round(10) + 0.6832579186 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Markov_chain#Continuous-time_Markov_chain + .. [2] https://u.math.biu.ac.il/~amirgi/CTMCnotes.pdf + """ + index_set = S.Reals + + def __new__(cls, sym, state_space=None, gen_mat=None): + sym = _symbol_converter(sym) + state_space, gen_mat = MarkovProcess._sanity_checks(state_space, gen_mat) + obj = Basic.__new__(cls, sym, state_space, gen_mat) + indices = {} + if isinstance(obj.number_of_states, Integer): + for index, state in enumerate(obj.state_space): + indices[state] = index + obj.index_of = indices + return obj + + @property + def generator_matrix(self): + return self.args[2] + + @cacheit + def transition_probabilities(self, gen_mat=None): + t = Dummy('t') + if isinstance(gen_mat, (Matrix, ImmutableMatrix)) and \ + gen_mat.is_diagonalizable(): + # for faster computation use diagonalized generator matrix + Q, D = gen_mat.diagonalize() + return Lambda(t, Q*exp(t*D)*Q.inv()) + if gen_mat != None: + return Lambda(t, exp(t*gen_mat)) + + def limiting_distribution(self): + gen_mat = self.generator_matrix + if gen_mat is None: + return None + if isinstance(gen_mat, MatrixSymbol): + wm = MatrixSymbol('wm', 1, gen_mat.shape[0]) + return Lambda((wm, gen_mat), Eq(wm*gen_mat, wm)) + w = IndexedBase('w') + wi = [w[i] for i in range(gen_mat.shape[0])] + wm = Matrix([wi]) + eqs = (wm*gen_mat).tolist()[0] + eqs.append(sum(wi) - 1) + soln = list(linsolve(eqs, wi))[0] + return ImmutableMatrix([soln]) + + +class BernoulliProcess(DiscreteTimeStochasticProcess): + """ + The Bernoulli process consists of repeated + independent Bernoulli process trials with the same parameter `p`. + It's assumed that the probability `p` applies to every + trial and that the outcomes of each trial + are independent of all the rest. Therefore Bernoulli Process + is Discrete State and Discrete Time Stochastic Process. + + Parameters + ========== + + sym : Symbol/str + success : Integer/str + The event which is considered to be success. Default: 1. + failure: Integer/str + The event which is considered to be failure. Default: 0. + p : Real Number between 0 and 1 + Represents the probability of getting success. + + Examples + ======== + + >>> from sympy.stats import BernoulliProcess, P, E + >>> from sympy import Eq, Gt + >>> B = BernoulliProcess("B", p=0.7, success=1, failure=0) + >>> B.state_space + {0, 1} + >>> B.p.round(2) + 0.70 + >>> B.success + 1 + >>> B.failure + 0 + >>> X = B[1] + B[2] + B[3] + >>> P(Eq(X, 0)).round(2) + 0.03 + >>> P(Eq(X, 2)).round(2) + 0.44 + >>> P(Eq(X, 4)).round(2) + 0 + >>> P(Gt(X, 1)).round(2) + 0.78 + >>> P(Eq(B[1], 0) & Eq(B[2], 1) & Eq(B[3], 0) & Eq(B[4], 1)).round(2) + 0.04 + >>> B.joint_distribution(B[1], B[2]) + JointDistributionHandmade(Lambda((B[1], B[2]), Piecewise((0.7, Eq(B[1], 1)), + (0.3, Eq(B[1], 0)), (0, True))*Piecewise((0.7, Eq(B[2], 1)), (0.3, Eq(B[2], 0)), + (0, True)))) + >>> E(2*B[1] + B[2]).round(2) + 2.10 + >>> P(B[1] < 1).round(2) + 0.30 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Bernoulli_process + .. [2] https://mathcs.clarku.edu/~djoyce/ma217/bernoulli.pdf + + """ + + index_set = S.Naturals0 + + def __new__(cls, sym, p, success=1, failure=0): + _value_check(p >= 0 and p <= 1, 'Value of p must be between 0 and 1.') + sym = _symbol_converter(sym) + p = _sympify(p) + success = _sym_sympify(success) + failure = _sym_sympify(failure) + return Basic.__new__(cls, sym, p, success, failure) + + @property + def symbol(self): + return self.args[0] + + @property + def p(self): + return self.args[1] + + @property + def success(self): + return self.args[2] + + @property + def failure(self): + return self.args[3] + + @property + def state_space(self): + return _set_converter([self.success, self.failure]) + + def distribution(self, key=None): + if key is None: + self._deprecation_warn_distribution() + return BernoulliDistribution(self.p) + return BernoulliDistribution(self.p, self.success, self.failure) + + def simple_rv(self, rv): + return Bernoulli(rv.name, p=self.p, + succ=self.success, fail=self.failure) + + def expectation(self, expr, condition=None, evaluate=True, **kwargs): + """ + Computes expectation. + + Parameters + ========== + + expr : RandomIndexedSymbol, Relational, Logic + Condition for which expectation has to be computed. Must + contain a RandomIndexedSymbol of the process. + condition : Relational, Logic + The given conditions under which computations should be done. + + Returns + ======= + + Expectation of the RandomIndexedSymbol. + + """ + + return _SubstituteRV._expectation(expr, condition, evaluate, **kwargs) + + def probability(self, condition, given_condition=None, evaluate=True, **kwargs): + """ + Computes probability. + + Parameters + ========== + + condition : Relational + Condition for which probability has to be computed. Must + contain a RandomIndexedSymbol of the process. + given_condition : Relational, Logic + The given conditions under which computations should be done. + + Returns + ======= + + Probability of the condition. + + """ + + return _SubstituteRV._probability(condition, given_condition, evaluate, **kwargs) + + def density(self, x): + return Piecewise((self.p, Eq(x, self.success)), + (1 - self.p, Eq(x, self.failure)), + (S.Zero, True)) + +class _SubstituteRV: + """ + Internal class to handle the queries of expectation and probability + by substitution. + """ + + @staticmethod + def _rvindexed_subs(expr, condition=None): + """ + Substitutes the RandomIndexedSymbol with the RandomSymbol with + same name, distribution and probability as RandomIndexedSymbol. + + Parameters + ========== + + expr: RandomIndexedSymbol, Relational, Logic + Condition for which expectation has to be computed. Must + contain a RandomIndexedSymbol of the process. + condition: Relational, Logic + The given conditions under which computations should be done. + + """ + + rvs_expr = random_symbols(expr) + if len(rvs_expr) != 0: + swapdict_expr = {} + for rv in rvs_expr: + if isinstance(rv, RandomIndexedSymbol): + newrv = rv.pspace.process.simple_rv(rv) # substitute with equivalent simple rv + swapdict_expr[rv] = newrv + expr = expr.subs(swapdict_expr) + rvs_cond = random_symbols(condition) + if len(rvs_cond)!=0: + swapdict_cond = {} + for rv in rvs_cond: + if isinstance(rv, RandomIndexedSymbol): + newrv = rv.pspace.process.simple_rv(rv) + swapdict_cond[rv] = newrv + condition = condition.subs(swapdict_cond) + return expr, condition + + @classmethod + def _expectation(self, expr, condition=None, evaluate=True, **kwargs): + """ + Internal method for computing expectation of indexed RV. + + Parameters + ========== + + expr: RandomIndexedSymbol, Relational, Logic + Condition for which expectation has to be computed. Must + contain a RandomIndexedSymbol of the process. + condition: Relational, Logic + The given conditions under which computations should be done. + + Returns + ======= + + Expectation of the RandomIndexedSymbol. + + """ + new_expr, new_condition = self._rvindexed_subs(expr, condition) + + if not is_random(new_expr): + return new_expr + new_pspace = pspace(new_expr) + if new_condition is not None: + new_expr = given(new_expr, new_condition) + if new_expr.is_Add: # As E is Linear + return Add(*[new_pspace.compute_expectation( + expr=arg, evaluate=evaluate, **kwargs) + for arg in new_expr.args]) + return new_pspace.compute_expectation( + new_expr, evaluate=evaluate, **kwargs) + + @classmethod + def _probability(self, condition, given_condition=None, evaluate=True, **kwargs): + """ + Internal method for computing probability of indexed RV + + Parameters + ========== + + condition: Relational + Condition for which probability has to be computed. Must + contain a RandomIndexedSymbol of the process. + given_condition: Relational/And + The given conditions under which computations should be done. + + Returns + ======= + + Probability of the condition. + + """ + new_condition, new_givencondition = self._rvindexed_subs(condition, given_condition) + + if isinstance(new_givencondition, RandomSymbol): + condrv = random_symbols(new_condition) + if len(condrv) == 1 and condrv[0] == new_givencondition: + return BernoulliDistribution(self._probability(new_condition), 0, 1) + + if any(dependent(rv, new_givencondition) for rv in condrv): + return Probability(new_condition, new_givencondition) + else: + return self._probability(new_condition) + + if new_givencondition is not None and \ + not isinstance(new_givencondition, (Relational, Boolean)): + raise ValueError("%s is not a relational or combination of relationals" + % (new_givencondition)) + if new_givencondition == False or new_condition == False: + return S.Zero + if new_condition == True: + return S.One + if not isinstance(new_condition, (Relational, Boolean)): + raise ValueError("%s is not a relational or combination of relationals" + % (new_condition)) + + if new_givencondition is not None: # If there is a condition + # Recompute on new conditional expr + return self._probability(given(new_condition, new_givencondition, **kwargs), **kwargs) + result = pspace(new_condition).probability(new_condition, **kwargs) + if evaluate and hasattr(result, 'doit'): + return result.doit() + else: + return result + +def get_timerv_swaps(expr, condition): + """ + Finds the appropriate interval for each time stamp in expr by parsing + the given condition and returns intervals for each timestamp and + dictionary that maps variable time-stamped Random Indexed Symbol to its + corresponding Random Indexed variable with fixed time stamp. + + Parameters + ========== + + expr: SymPy Expression + Expression containing Random Indexed Symbols with variable time stamps + condition: Relational/Boolean Expression + Expression containing time bounds of variable time stamps in expr + + Examples + ======== + + >>> from sympy.stats.stochastic_process_types import get_timerv_swaps, PoissonProcess + >>> from sympy import symbols, Contains, Interval + >>> x, t, d = symbols('x t d', positive=True) + >>> X = PoissonProcess("X", 3) + >>> get_timerv_swaps(x*X(t), Contains(t, Interval.Lopen(0, 1))) + ([Interval.Lopen(0, 1)], {X(t): X(1)}) + >>> get_timerv_swaps((X(t)**2 + X(d)**2), Contains(t, Interval.Lopen(0, 1)) + ... & Contains(d, Interval.Ropen(1, 4))) # doctest: +SKIP + ([Interval.Ropen(1, 4), Interval.Lopen(0, 1)], {X(d): X(3), X(t): X(1)}) + + Returns + ======= + + intervals: list + List of Intervals/FiniteSet on which each time stamp is defined + rv_swap: dict + Dictionary mapping variable time Random Indexed Symbol to constant time + Random Indexed Variable + + """ + + if not isinstance(condition, (Relational, Boolean)): + raise ValueError("%s is not a relational or combination of relationals" + % (condition)) + expr_syms = list(expr.atoms(RandomIndexedSymbol)) + if isinstance(condition, (And, Or)): + given_cond_args = condition.args + else: # single condition + given_cond_args = (condition, ) + rv_swap = {} + intervals = [] + for expr_sym in expr_syms: + for arg in given_cond_args: + if arg.has(expr_sym.key) and isinstance(expr_sym.key, Symbol): + intv = _set_converter(arg.args[1]) + diff_key = intv._sup - intv._inf + if diff_key == oo: + raise ValueError("%s should have finite bounds" % str(expr_sym.name)) + elif diff_key == S.Zero: # has singleton set + diff_key = intv._sup + rv_swap[expr_sym] = expr_sym.subs({expr_sym.key: diff_key}) + intervals.append(intv) + return intervals, rv_swap + + +class CountingProcess(ContinuousTimeStochasticProcess): + """ + This class handles the common methods of the Counting Processes + such as Poisson, Wiener and Gamma Processes + """ + index_set = _set_converter(Interval(0, oo)) + + @property + def symbol(self): + return self.args[0] + + def expectation(self, expr, condition=None, evaluate=True, **kwargs): + """ + Computes expectation + + Parameters + ========== + + expr: RandomIndexedSymbol, Relational, Logic + Condition for which expectation has to be computed. Must + contain a RandomIndexedSymbol of the process. + condition: Relational, Boolean + The given conditions under which computations should be done, i.e, + the intervals on which each variable time stamp in expr is defined + + Returns + ======= + + Expectation of the given expr + + """ + if condition is not None: + intervals, rv_swap = get_timerv_swaps(expr, condition) + # they are independent when they have non-overlapping intervals + if len(intervals) == 1 or all(Intersection(*intv_comb) == EmptySet + for intv_comb in itertools.combinations(intervals, 2)): + if expr.is_Add: + return Add.fromiter(self.expectation(arg, condition) + for arg in expr.args) + expr = expr.subs(rv_swap) + else: + return Expectation(expr, condition) + + return _SubstituteRV._expectation(expr, evaluate=evaluate, **kwargs) + + def _solve_argwith_tworvs(self, arg): + if arg.args[0].key >= arg.args[1].key or isinstance(arg, Eq): + diff_key = abs(arg.args[0].key - arg.args[1].key) + rv = arg.args[0] + arg = arg.__class__(rv.pspace.process(diff_key), 0) + else: + diff_key = arg.args[1].key - arg.args[0].key + rv = arg.args[1] + arg = arg.__class__(rv.pspace.process(diff_key), 0) + return arg + + def _solve_numerical(self, condition, given_condition=None): + if isinstance(condition, And): + args_list = list(condition.args) + else: + args_list = [condition] + if given_condition is not None: + if isinstance(given_condition, And): + args_list.extend(list(given_condition.args)) + else: + args_list.extend([given_condition]) + # sort the args based on timestamp to get the independent increments in + # each segment using all the condition args as well as given_condition args + args_list = sorted(args_list, key=lambda x: x.args[0].key) + result = [] + cond_args = list(condition.args) if isinstance(condition, And) else [condition] + if args_list[0] in cond_args and not (is_random(args_list[0].args[0]) + and is_random(args_list[0].args[1])): + result.append(_SubstituteRV._probability(args_list[0])) + + if is_random(args_list[0].args[0]) and is_random(args_list[0].args[1]): + arg = self._solve_argwith_tworvs(args_list[0]) + result.append(_SubstituteRV._probability(arg)) + + for i in range(len(args_list) - 1): + curr, nex = args_list[i], args_list[i + 1] + diff_key = nex.args[0].key - curr.args[0].key + working_set = curr.args[0].pspace.process.state_space + if curr.args[1] > nex.args[1]: #impossible condition so return 0 + result.append(0) + break + if isinstance(curr, Eq): + working_set = Intersection(working_set, Interval.Lopen(curr.args[1], oo)) + else: + working_set = Intersection(working_set, curr.as_set()) + if isinstance(nex, Eq): + working_set = Intersection(working_set, Interval(-oo, nex.args[1])) + else: + working_set = Intersection(working_set, nex.as_set()) + if working_set == EmptySet: + rv = Eq(curr.args[0].pspace.process(diff_key), 0) + result.append(_SubstituteRV._probability(rv)) + else: + if working_set.is_finite_set: + if isinstance(curr, Eq) and isinstance(nex, Eq): + rv = Eq(curr.args[0].pspace.process(diff_key), len(working_set)) + result.append(_SubstituteRV._probability(rv)) + elif isinstance(curr, Eq) ^ isinstance(nex, Eq): + result.append(Add.fromiter(_SubstituteRV._probability(Eq( + curr.args[0].pspace.process(diff_key), x)) + for x in range(len(working_set)))) + else: + n = len(working_set) + result.append(Add.fromiter((n - x)*_SubstituteRV._probability(Eq( + curr.args[0].pspace.process(diff_key), x)) for x in range(n))) + else: + result.append(_SubstituteRV._probability( + curr.args[0].pspace.process(diff_key) <= working_set._sup - working_set._inf)) + return Mul.fromiter(result) + + + def probability(self, condition, given_condition=None, evaluate=True, **kwargs): + """ + Computes probability. + + Parameters + ========== + + condition: Relational + Condition for which probability has to be computed. Must + contain a RandomIndexedSymbol of the process. + given_condition: Relational, Boolean + The given conditions under which computations should be done, i.e, + the intervals on which each variable time stamp in expr is defined + + Returns + ======= + + Probability of the condition + + """ + check_numeric = True + if isinstance(condition, (And, Or)): + cond_args = condition.args + else: + cond_args = (condition, ) + # check that condition args are numeric or not + if not all(arg.args[0].key.is_number for arg in cond_args): + check_numeric = False + if given_condition is not None: + check_given_numeric = True + if isinstance(given_condition, (And, Or)): + given_cond_args = given_condition.args + else: + given_cond_args = (given_condition, ) + # check that given condition args are numeric or not + if given_condition.has(Contains): + check_given_numeric = False + # Handle numerical queries + if check_numeric and check_given_numeric: + res = [] + if isinstance(condition, Or): + res.append(Add.fromiter(self._solve_numerical(arg, given_condition) + for arg in condition.args)) + if isinstance(given_condition, Or): + res.append(Add.fromiter(self._solve_numerical(condition, arg) + for arg in given_condition.args)) + if res: + return Add.fromiter(res) + return self._solve_numerical(condition, given_condition) + + # No numeric queries, go by Contains?... then check that all the + # given condition are in form of `Contains` + if not all(arg.has(Contains) for arg in given_cond_args): + raise ValueError("If given condition is passed with `Contains`, then " + "please pass the evaluated condition with its corresponding information " + "in terms of intervals of each time stamp to be passed in given condition.") + + intervals, rv_swap = get_timerv_swaps(condition, given_condition) + # they are independent when they have non-overlapping intervals + if len(intervals) == 1 or all(Intersection(*intv_comb) == EmptySet + for intv_comb in itertools.combinations(intervals, 2)): + if isinstance(condition, And): + return Mul.fromiter(self.probability(arg, given_condition) + for arg in condition.args) + elif isinstance(condition, Or): + return Add.fromiter(self.probability(arg, given_condition) + for arg in condition.args) + condition = condition.subs(rv_swap) + else: + return Probability(condition, given_condition) + if check_numeric: + return self._solve_numerical(condition) + return _SubstituteRV._probability(condition, evaluate=evaluate, **kwargs) + +class PoissonProcess(CountingProcess): + """ + The Poisson process is a counting process. It is usually used in scenarios + where we are counting the occurrences of certain events that appear + to happen at a certain rate, but completely at random. + + Parameters + ========== + + sym : Symbol/str + lamda : Positive number + Rate of the process, ``lambda > 0`` + + Examples + ======== + + >>> from sympy.stats import PoissonProcess, P, E + >>> from sympy import symbols, Eq, Ne, Contains, Interval + >>> X = PoissonProcess("X", lamda=3) + >>> X.state_space + Naturals0 + >>> X.lamda + 3 + >>> t1, t2 = symbols('t1 t2', positive=True) + >>> P(X(t1) < 4) + (9*t1**3/2 + 9*t1**2/2 + 3*t1 + 1)*exp(-3*t1) + >>> P(Eq(X(t1), 2) | Ne(X(t1), 4), Contains(t1, Interval.Ropen(2, 4))) + 1 - 36*exp(-6) + >>> P(Eq(X(t1), 2) & Eq(X(t2), 3), Contains(t1, Interval.Lopen(0, 2)) + ... & Contains(t2, Interval.Lopen(2, 4))) + 648*exp(-12) + >>> E(X(t1)) + 3*t1 + >>> E(X(t1)**2 + 2*X(t2), Contains(t1, Interval.Lopen(0, 1)) + ... & Contains(t2, Interval.Lopen(1, 2))) + 18 + >>> P(X(3) < 1, Eq(X(1), 0)) + exp(-6) + >>> P(Eq(X(4), 3), Eq(X(2), 3)) + exp(-6) + >>> P(X(2) <= 3, X(1) > 1) + 5*exp(-3) + + Merging two Poisson Processes + + >>> Y = PoissonProcess("Y", lamda=4) + >>> Z = X + Y + >>> Z.lamda + 7 + + Splitting a Poisson Process into two independent Poisson Processes + + >>> N, M = Z.split(l1=2, l2=5) + >>> N.lamda, M.lamda + (2, 5) + + References + ========== + + .. [1] https://www.probabilitycourse.com/chapter11/11_0_0_intro.php + .. [2] https://en.wikipedia.org/wiki/Poisson_point_process + + """ + + def __new__(cls, sym, lamda): + _value_check(lamda > 0, 'lamda should be a positive number.') + sym = _symbol_converter(sym) + lamda = _sympify(lamda) + return Basic.__new__(cls, sym, lamda) + + @property + def lamda(self): + return self.args[1] + + @property + def state_space(self): + return S.Naturals0 + + def distribution(self, key): + if isinstance(key, RandomIndexedSymbol): + self._deprecation_warn_distribution() + return PoissonDistribution(self.lamda*key.key) + return PoissonDistribution(self.lamda*key) + + def density(self, x): + return (self.lamda*x.key)**x / factorial(x) * exp(-(self.lamda*x.key)) + + def simple_rv(self, rv): + return Poisson(rv.name, lamda=self.lamda*rv.key) + + def __add__(self, other): + if not isinstance(other, PoissonProcess): + raise ValueError("Only instances of Poisson Process can be merged") + return PoissonProcess(Dummy(self.symbol.name + other.symbol.name), + self.lamda + other.lamda) + + def split(self, l1, l2): + if _sympify(l1 + l2) != self.lamda: + raise ValueError("Sum of l1 and l2 should be %s" % str(self.lamda)) + return PoissonProcess(Dummy("l1"), l1), PoissonProcess(Dummy("l2"), l2) + +class WienerProcess(CountingProcess): + """ + The Wiener process is a real valued continuous-time stochastic process. + In physics it is used to study Brownian motion and it is often also called + Brownian motion due to its historical connection with physical process of the + same name originally observed by Scottish botanist Robert Brown. + + Parameters + ========== + + sym : Symbol/str + + Examples + ======== + + >>> from sympy.stats import WienerProcess, P, E + >>> from sympy import symbols, Contains, Interval + >>> X = WienerProcess("X") + >>> X.state_space + Reals + >>> t1, t2 = symbols('t1 t2', positive=True) + >>> P(X(t1) < 7).simplify() + erf(7*sqrt(2)/(2*sqrt(t1)))/2 + 1/2 + >>> P((X(t1) > 2) | (X(t1) < 4), Contains(t1, Interval.Ropen(2, 4))).simplify() + -erf(1)/2 + erf(2)/2 + 1 + >>> E(X(t1)) + 0 + >>> E(X(t1) + 2*X(t2), Contains(t1, Interval.Lopen(0, 1)) + ... & Contains(t2, Interval.Lopen(1, 2))) + 0 + + References + ========== + + .. [1] https://www.probabilitycourse.com/chapter11/11_4_0_brownian_motion_wiener_process.php + .. [2] https://en.wikipedia.org/wiki/Wiener_process + + """ + def __new__(cls, sym): + sym = _symbol_converter(sym) + return Basic.__new__(cls, sym) + + @property + def state_space(self): + return S.Reals + + def distribution(self, key): + if isinstance(key, RandomIndexedSymbol): + self._deprecation_warn_distribution() + return NormalDistribution(0, sqrt(key.key)) + return NormalDistribution(0, sqrt(key)) + + def density(self, x): + return exp(-x**2/(2*x.key)) / (sqrt(2*pi)*sqrt(x.key)) + + def simple_rv(self, rv): + return Normal(rv.name, 0, sqrt(rv.key)) + + +class GammaProcess(CountingProcess): + r""" + A Gamma process is a random process with independent gamma distributed + increments. It is a pure-jump increasing Levy process. + + Parameters + ========== + + sym : Symbol/str + lamda : Positive number + Jump size of the process, ``lamda > 0`` + gamma : Positive number + Rate of jump arrivals, `\gamma > 0` + + Examples + ======== + + >>> from sympy.stats import GammaProcess, E, P, variance + >>> from sympy import symbols, Contains, Interval, Not + >>> t, d, x, l, g = symbols('t d x l g', positive=True) + >>> X = GammaProcess("X", l, g) + >>> E(X(t)) + g*t/l + >>> variance(X(t)).simplify() + g*t/l**2 + >>> X = GammaProcess('X', 1, 2) + >>> P(X(t) < 1).simplify() + lowergamma(2*t, 1)/gamma(2*t) + >>> P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & + ... Contains(d, Interval.Lopen(7, 8))).simplify() + -4*exp(-3) + 472*exp(-8)/3 + 1 + >>> E(X(2) + x*E(X(5))) + 10*x + 4 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gamma_process + + """ + def __new__(cls, sym, lamda, gamma): + _value_check(lamda > 0, 'lamda should be a positive number') + _value_check(gamma > 0, 'gamma should be a positive number') + sym = _symbol_converter(sym) + gamma = _sympify(gamma) + lamda = _sympify(lamda) + return Basic.__new__(cls, sym, lamda, gamma) + + @property + def lamda(self): + return self.args[1] + + @property + def gamma(self): + return self.args[2] + + @property + def state_space(self): + return _set_converter(Interval(0, oo)) + + def distribution(self, key): + if isinstance(key, RandomIndexedSymbol): + self._deprecation_warn_distribution() + return GammaDistribution(self.gamma*key.key, 1/self.lamda) + return GammaDistribution(self.gamma*key, 1/self.lamda) + + def density(self, x): + k = self.gamma*x.key + theta = 1/self.lamda + return x**(k - 1) * exp(-x/theta) / (gamma(k)*theta**k) + + def simple_rv(self, rv): + return Gamma(rv.name, self.gamma*rv.key, 1/self.lamda) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/symbolic_multivariate_probability.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/symbolic_multivariate_probability.py new file mode 100644 index 0000000000000000000000000000000000000000..bbe8776e58e82489e29734cea48c9138bc512f34 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/symbolic_multivariate_probability.py @@ -0,0 +1,308 @@ +import itertools + +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.function import expand as _expand +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.matrices.exceptions import ShapeError +from sympy.matrices.expressions.matexpr import MatrixExpr +from sympy.matrices.expressions.matmul import MatMul +from sympy.matrices.expressions.special import ZeroMatrix +from sympy.stats.rv import RandomSymbol, is_random +from sympy.core.sympify import _sympify +from sympy.stats.symbolic_probability import Variance, Covariance, Expectation + + +class ExpectationMatrix(Expectation, MatrixExpr): + """ + Expectation of a random matrix expression. + + Examples + ======== + + >>> from sympy.stats import ExpectationMatrix, Normal + >>> from sympy.stats.rv import RandomMatrixSymbol + >>> from sympy import symbols, MatrixSymbol, Matrix + >>> k = symbols("k") + >>> A, B = MatrixSymbol("A", k, k), MatrixSymbol("B", k, k) + >>> X, Y = RandomMatrixSymbol("X", k, 1), RandomMatrixSymbol("Y", k, 1) + >>> ExpectationMatrix(X) + ExpectationMatrix(X) + >>> ExpectationMatrix(A*X).shape + (k, 1) + + To expand the expectation in its expression, use ``expand()``: + + >>> ExpectationMatrix(A*X + B*Y).expand() + A*ExpectationMatrix(X) + B*ExpectationMatrix(Y) + >>> ExpectationMatrix((X + Y)*(X - Y).T).expand() + ExpectationMatrix(X*X.T) - ExpectationMatrix(X*Y.T) + ExpectationMatrix(Y*X.T) - ExpectationMatrix(Y*Y.T) + + To evaluate the ``ExpectationMatrix``, use ``doit()``: + + >>> N11, N12 = Normal('N11', 11, 1), Normal('N12', 12, 1) + >>> N21, N22 = Normal('N21', 21, 1), Normal('N22', 22, 1) + >>> M11, M12 = Normal('M11', 1, 1), Normal('M12', 2, 1) + >>> M21, M22 = Normal('M21', 3, 1), Normal('M22', 4, 1) + >>> x1 = Matrix([[N11, N12], [N21, N22]]) + >>> x2 = Matrix([[M11, M12], [M21, M22]]) + >>> ExpectationMatrix(x1 + x2).doit() + Matrix([ + [12, 14], + [24, 26]]) + + """ + def __new__(cls, expr, condition=None): + expr = _sympify(expr) + if condition is None: + if not is_random(expr): + return expr + obj = Expr.__new__(cls, expr) + else: + condition = _sympify(condition) + obj = Expr.__new__(cls, expr, condition) + + obj._shape = expr.shape + obj._condition = condition + return obj + + @property + def shape(self): + return self._shape + + def expand(self, **hints): + expr = self.args[0] + condition = self._condition + if not is_random(expr): + return expr + + if isinstance(expr, Add): + return Add.fromiter(Expectation(a, condition=condition).expand() + for a in expr.args) + + expand_expr = _expand(expr) + if isinstance(expand_expr, Add): + return Add.fromiter(Expectation(a, condition=condition).expand() + for a in expand_expr.args) + + elif isinstance(expr, (Mul, MatMul)): + rv = [] + nonrv = [] + postnon = [] + + for a in expr.args: + if is_random(a): + if rv: + rv.extend(postnon) + else: + nonrv.extend(postnon) + postnon = [] + rv.append(a) + elif a.is_Matrix: + postnon.append(a) + else: + nonrv.append(a) + + # In order to avoid infinite-looping (MatMul may call .doit() again), + # do not rebuild + if len(nonrv) == 0: + return self + return Mul.fromiter(nonrv)*Expectation(Mul.fromiter(rv), + condition=condition)*Mul.fromiter(postnon) + + return self + +class VarianceMatrix(Variance, MatrixExpr): + """ + Variance of a random matrix probability expression. Also known as + Covariance matrix, auto-covariance matrix, dispersion matrix, + or variance-covariance matrix. + + Examples + ======== + + >>> from sympy.stats import VarianceMatrix + >>> from sympy.stats.rv import RandomMatrixSymbol + >>> from sympy import symbols, MatrixSymbol + >>> k = symbols("k") + >>> A, B = MatrixSymbol("A", k, k), MatrixSymbol("B", k, k) + >>> X, Y = RandomMatrixSymbol("X", k, 1), RandomMatrixSymbol("Y", k, 1) + >>> VarianceMatrix(X) + VarianceMatrix(X) + >>> VarianceMatrix(X).shape + (k, k) + + To expand the variance in its expression, use ``expand()``: + + >>> VarianceMatrix(A*X).expand() + A*VarianceMatrix(X)*A.T + >>> VarianceMatrix(A*X + B*Y).expand() + 2*A*CrossCovarianceMatrix(X, Y)*B.T + A*VarianceMatrix(X)*A.T + B*VarianceMatrix(Y)*B.T + """ + def __new__(cls, arg, condition=None): + arg = _sympify(arg) + + if 1 not in arg.shape: + raise ShapeError("Expression is not a vector") + + shape = (arg.shape[0], arg.shape[0]) if arg.shape[1] == 1 else (arg.shape[1], arg.shape[1]) + + if condition: + obj = Expr.__new__(cls, arg, condition) + else: + obj = Expr.__new__(cls, arg) + + obj._shape = shape + obj._condition = condition + return obj + + @property + def shape(self): + return self._shape + + def expand(self, **hints): + arg = self.args[0] + condition = self._condition + + if not is_random(arg): + return ZeroMatrix(*self.shape) + + if isinstance(arg, RandomSymbol): + return self + elif isinstance(arg, Add): + rv = [] + for a in arg.args: + if is_random(a): + rv.append(a) + variances = Add(*(Variance(xv, condition).expand() for xv in rv)) + map_to_covar = lambda x: 2*Covariance(*x, condition=condition).expand() + covariances = Add(*map(map_to_covar, itertools.combinations(rv, 2))) + return variances + covariances + elif isinstance(arg, (Mul, MatMul)): + nonrv = [] + rv = [] + for a in arg.args: + if is_random(a): + rv.append(a) + else: + nonrv.append(a) + if len(rv) == 0: + return ZeroMatrix(*self.shape) + # Avoid possible infinite loops with MatMul: + if len(nonrv) == 0: + return self + # Variance of many multiple matrix products is not implemented: + if len(rv) > 1: + return self + return Mul.fromiter(nonrv)*Variance(Mul.fromiter(rv), + condition)*(Mul.fromiter(nonrv)).transpose() + + # this expression contains a RandomSymbol somehow: + return self + +class CrossCovarianceMatrix(Covariance, MatrixExpr): + """ + Covariance of a random matrix probability expression. + + Examples + ======== + + >>> from sympy.stats import CrossCovarianceMatrix + >>> from sympy.stats.rv import RandomMatrixSymbol + >>> from sympy import symbols, MatrixSymbol + >>> k = symbols("k") + >>> A, B = MatrixSymbol("A", k, k), MatrixSymbol("B", k, k) + >>> C, D = MatrixSymbol("C", k, k), MatrixSymbol("D", k, k) + >>> X, Y = RandomMatrixSymbol("X", k, 1), RandomMatrixSymbol("Y", k, 1) + >>> Z, W = RandomMatrixSymbol("Z", k, 1), RandomMatrixSymbol("W", k, 1) + >>> CrossCovarianceMatrix(X, Y) + CrossCovarianceMatrix(X, Y) + >>> CrossCovarianceMatrix(X, Y).shape + (k, k) + + To expand the covariance in its expression, use ``expand()``: + + >>> CrossCovarianceMatrix(X + Y, Z).expand() + CrossCovarianceMatrix(X, Z) + CrossCovarianceMatrix(Y, Z) + >>> CrossCovarianceMatrix(A*X, Y).expand() + A*CrossCovarianceMatrix(X, Y) + >>> CrossCovarianceMatrix(A*X, B.T*Y).expand() + A*CrossCovarianceMatrix(X, Y)*B + >>> CrossCovarianceMatrix(A*X + B*Y, C.T*Z + D.T*W).expand() + A*CrossCovarianceMatrix(X, W)*D + A*CrossCovarianceMatrix(X, Z)*C + B*CrossCovarianceMatrix(Y, W)*D + B*CrossCovarianceMatrix(Y, Z)*C + + """ + def __new__(cls, arg1, arg2, condition=None): + arg1 = _sympify(arg1) + arg2 = _sympify(arg2) + + if (1 not in arg1.shape) or (1 not in arg2.shape) or (arg1.shape[1] != arg2.shape[1]): + raise ShapeError("Expression is not a vector") + + shape = (arg1.shape[0], arg2.shape[0]) if arg1.shape[1] == 1 and arg2.shape[1] == 1 \ + else (1, 1) + + if condition: + obj = Expr.__new__(cls, arg1, arg2, condition) + else: + obj = Expr.__new__(cls, arg1, arg2) + + obj._shape = shape + obj._condition = condition + return obj + + @property + def shape(self): + return self._shape + + def expand(self, **hints): + arg1 = self.args[0] + arg2 = self.args[1] + condition = self._condition + + if arg1 == arg2: + return VarianceMatrix(arg1, condition).expand() + + if not is_random(arg1) or not is_random(arg2): + return ZeroMatrix(*self.shape) + + if isinstance(arg1, RandomSymbol) and isinstance(arg2, RandomSymbol): + return CrossCovarianceMatrix(arg1, arg2, condition) + + coeff_rv_list1 = self._expand_single_argument(arg1.expand()) + coeff_rv_list2 = self._expand_single_argument(arg2.expand()) + + addends = [a*CrossCovarianceMatrix(r1, r2, condition=condition)*b.transpose() + for (a, r1) in coeff_rv_list1 for (b, r2) in coeff_rv_list2] + return Add.fromiter(addends) + + @classmethod + def _expand_single_argument(cls, expr): + # return (coefficient, random_symbol) pairs: + if isinstance(expr, RandomSymbol): + return [(S.One, expr)] + elif isinstance(expr, Add): + outval = [] + for a in expr.args: + if isinstance(a, (Mul, MatMul)): + outval.append(cls._get_mul_nonrv_rv_tuple(a)) + elif is_random(a): + outval.append((S.One, a)) + + return outval + elif isinstance(expr, (Mul, MatMul)): + return [cls._get_mul_nonrv_rv_tuple(expr)] + elif is_random(expr): + return [(S.One, expr)] + + @classmethod + def _get_mul_nonrv_rv_tuple(cls, m): + rv = [] + nonrv = [] + for a in m.args: + if is_random(a): + rv.append(a) + else: + nonrv.append(a) + return (Mul.fromiter(nonrv), Mul.fromiter(rv)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/symbolic_probability.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/symbolic_probability.py new file mode 100644 index 0000000000000000000000000000000000000000..5d0b971a8691f82de15258d4c460129059eaf436 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/symbolic_probability.py @@ -0,0 +1,698 @@ +import itertools +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.function import expand as _expand +from sympy.core.mul import Mul +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.integrals.integrals import Integral +from sympy.logic.boolalg import Not +from sympy.core.parameters import global_parameters +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import _sympify +from sympy.core.relational import Relational +from sympy.logic.boolalg import Boolean +from sympy.stats import variance, covariance +from sympy.stats.rv import (RandomSymbol, pspace, dependent, + given, sampling_E, RandomIndexedSymbol, is_random, + PSpace, sampling_P, random_symbols) + +__all__ = ['Probability', 'Expectation', 'Variance', 'Covariance'] + + +@is_random.register(Expr) +def _(x): + atoms = x.free_symbols + if len(atoms) == 1 and next(iter(atoms)) == x: + return False + return any(is_random(i) for i in atoms) + +@is_random.register(RandomSymbol) # type: ignore +def _(x): + return True + + +class Probability(Expr): + """ + Symbolic expression for the probability. + + Examples + ======== + + >>> from sympy.stats import Probability, Normal + >>> from sympy import Integral + >>> X = Normal("X", 0, 1) + >>> prob = Probability(X > 1) + >>> prob + Probability(X > 1) + + Integral representation: + + >>> prob.rewrite(Integral) + Integral(sqrt(2)*exp(-_z**2/2)/(2*sqrt(pi)), (_z, 1, oo)) + + Evaluation of the integral: + + >>> prob.evaluate_integral() + sqrt(2)*(-sqrt(2)*sqrt(pi)*erf(sqrt(2)/2) + sqrt(2)*sqrt(pi))/(4*sqrt(pi)) + """ + + is_commutative = True + + def __new__(cls, prob, condition=None, **kwargs): + prob = _sympify(prob) + if condition is None: + obj = Expr.__new__(cls, prob) + else: + condition = _sympify(condition) + obj = Expr.__new__(cls, prob, condition) + obj._condition = condition + return obj + + def doit(self, **hints): + condition = self.args[0] + given_condition = self._condition + numsamples = hints.get('numsamples', False) + evaluate = hints.get('evaluate', True) + + if isinstance(condition, Not): + return S.One - self.func(condition.args[0], given_condition, + evaluate=evaluate).doit(**hints) + + if condition.has(RandomIndexedSymbol): + return pspace(condition).probability(condition, given_condition, + evaluate=evaluate) + + if isinstance(given_condition, RandomSymbol): + condrv = random_symbols(condition) + if len(condrv) == 1 and condrv[0] == given_condition: + from sympy.stats.frv_types import BernoulliDistribution + return BernoulliDistribution(self.func(condition).doit(**hints), 0, 1) + if any(dependent(rv, given_condition) for rv in condrv): + return Probability(condition, given_condition) + else: + return Probability(condition).doit() + + if given_condition is not None and \ + not isinstance(given_condition, (Relational, Boolean)): + raise ValueError("%s is not a relational or combination of relationals" + % (given_condition)) + + if given_condition == False or condition is S.false: + return S.Zero + if not isinstance(condition, (Relational, Boolean)): + raise ValueError("%s is not a relational or combination of relationals" + % (condition)) + if condition is S.true: + return S.One + + if numsamples: + return sampling_P(condition, given_condition, numsamples=numsamples) + if given_condition is not None: # If there is a condition + # Recompute on new conditional expr + return Probability(given(condition, given_condition)).doit() + + # Otherwise pass work off to the ProbabilitySpace + if pspace(condition) == PSpace(): + return Probability(condition, given_condition) + + result = pspace(condition).probability(condition) + if hasattr(result, 'doit') and evaluate: + return result.doit() + else: + return result + + def _eval_rewrite_as_Integral(self, arg, condition=None, **kwargs): + return self.func(arg, condition=condition).doit(evaluate=False) + + _eval_rewrite_as_Sum = _eval_rewrite_as_Integral + + def evaluate_integral(self): + return self.rewrite(Integral).doit() + + +class Expectation(Expr): + """ + Symbolic expression for the expectation. + + Examples + ======== + + >>> from sympy.stats import Expectation, Normal, Probability, Poisson + >>> from sympy import symbols, Integral, Sum + >>> mu = symbols("mu") + >>> sigma = symbols("sigma", positive=True) + >>> X = Normal("X", mu, sigma) + >>> Expectation(X) + Expectation(X) + >>> Expectation(X).evaluate_integral().simplify() + mu + + To get the integral expression of the expectation: + + >>> Expectation(X).rewrite(Integral) + Integral(sqrt(2)*X*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)) + + The same integral expression, in more abstract terms: + + >>> Expectation(X).rewrite(Probability) + Integral(x*Probability(Eq(X, x)), (x, -oo, oo)) + + To get the Summation expression of the expectation for discrete random variables: + + >>> lamda = symbols('lamda', positive=True) + >>> Z = Poisson('Z', lamda) + >>> Expectation(Z).rewrite(Sum) + Sum(Z*lamda**Z*exp(-lamda)/factorial(Z), (Z, 0, oo)) + + This class is aware of some properties of the expectation: + + >>> from sympy.abc import a + >>> Expectation(a*X) + Expectation(a*X) + >>> Y = Normal("Y", 1, 2) + >>> Expectation(X + Y) + Expectation(X + Y) + + To expand the ``Expectation`` into its expression, use ``expand()``: + + >>> Expectation(X + Y).expand() + Expectation(X) + Expectation(Y) + >>> Expectation(a*X + Y).expand() + a*Expectation(X) + Expectation(Y) + >>> Expectation(a*X + Y) + Expectation(a*X + Y) + >>> Expectation((X + Y)*(X - Y)).expand() + Expectation(X**2) - Expectation(Y**2) + + To evaluate the ``Expectation``, use ``doit()``: + + >>> Expectation(X + Y).doit() + mu + 1 + >>> Expectation(X + Expectation(Y + Expectation(2*X))).doit() + 3*mu + 1 + + To prevent evaluating nested ``Expectation``, use ``doit(deep=False)`` + + >>> Expectation(X + Expectation(Y)).doit(deep=False) + mu + Expectation(Expectation(Y)) + >>> Expectation(X + Expectation(Y + Expectation(2*X))).doit(deep=False) + mu + Expectation(Expectation(Expectation(2*X) + Y)) + + """ + + def __new__(cls, expr, condition=None, **kwargs): + expr = _sympify(expr) + if expr.is_Matrix: + from sympy.stats.symbolic_multivariate_probability import ExpectationMatrix + return ExpectationMatrix(expr, condition) + if condition is None: + if not is_random(expr): + return expr + obj = Expr.__new__(cls, expr) + else: + condition = _sympify(condition) + obj = Expr.__new__(cls, expr, condition) + obj._condition = condition + return obj + + def _eval_is_commutative(self): + return(self.args[0].is_commutative) + + def expand(self, **hints): + expr = self.args[0] + condition = self._condition + + if not is_random(expr): + return expr + + if isinstance(expr, Add): + return Add.fromiter(Expectation(a, condition=condition).expand() + for a in expr.args) + + expand_expr = _expand(expr) + if isinstance(expand_expr, Add): + return Add.fromiter(Expectation(a, condition=condition).expand() + for a in expand_expr.args) + + elif isinstance(expr, Mul): + rv = [] + nonrv = [] + for a in expr.args: + if is_random(a): + rv.append(a) + else: + nonrv.append(a) + return Mul.fromiter(nonrv)*Expectation(Mul.fromiter(rv), condition=condition) + + return self + + def doit(self, **hints): + deep = hints.get('deep', True) + condition = self._condition + expr = self.args[0] + numsamples = hints.get('numsamples', False) + evaluate = hints.get('evaluate', True) + + if deep: + expr = expr.doit(**hints) + + if not is_random(expr) or isinstance(expr, Expectation): # expr isn't random? + return expr + if numsamples: # Computing by monte carlo sampling? + evalf = hints.get('evalf', True) + return sampling_E(expr, condition, numsamples=numsamples, evalf=evalf) + + if expr.has(RandomIndexedSymbol): + return pspace(expr).compute_expectation(expr, condition) + + # Create new expr and recompute E + if condition is not None: # If there is a condition + return self.func(given(expr, condition)).doit(**hints) + + # A few known statements for efficiency + + if expr.is_Add: # We know that E is Linear + return Add(*[self.func(arg, condition).doit(**hints) + if not isinstance(arg, Expectation) else self.func(arg, condition) + for arg in expr.args]) + if expr.is_Mul: + if expr.atoms(Expectation): + return expr + + if pspace(expr) == PSpace(): + return self.func(expr) + # Otherwise case is simple, pass work off to the ProbabilitySpace + result = pspace(expr).compute_expectation(expr, evaluate=evaluate) + if hasattr(result, 'doit') and evaluate: + return result.doit(**hints) + else: + return result + + + def _eval_rewrite_as_Probability(self, arg, condition=None, **kwargs): + rvs = arg.atoms(RandomSymbol) + if len(rvs) > 1: + raise NotImplementedError() + if len(rvs) == 0: + return arg + + rv = rvs.pop() + if rv.pspace is None: + raise ValueError("Probability space not known") + + symbol = rv.symbol + if symbol.name[0].isupper(): + symbol = Symbol(symbol.name.lower()) + else : + symbol = Symbol(symbol.name + "_1") + + if rv.pspace.is_Continuous: + return Integral(arg.replace(rv, symbol)*Probability(Eq(rv, symbol), condition), (symbol, rv.pspace.domain.set.inf, rv.pspace.domain.set.sup)) + else: + if rv.pspace.is_Finite: + raise NotImplementedError + else: + return Sum(arg.replace(rv, symbol)*Probability(Eq(rv, symbol), condition), (symbol, rv.pspace.domain.set.inf, rv.pspace.set.sup)) + + def _eval_rewrite_as_Integral(self, arg, condition=None, evaluate=False, **kwargs): + return self.func(arg, condition=condition).doit(deep=False, evaluate=evaluate) + + _eval_rewrite_as_Sum = _eval_rewrite_as_Integral # For discrete this will be Sum + + def evaluate_integral(self): + return self.rewrite(Integral).doit() + + evaluate_sum = evaluate_integral + +class Variance(Expr): + """ + Symbolic expression for the variance. + + Examples + ======== + + >>> from sympy import symbols, Integral + >>> from sympy.stats import Normal, Expectation, Variance, Probability + >>> mu = symbols("mu", positive=True) + >>> sigma = symbols("sigma", positive=True) + >>> X = Normal("X", mu, sigma) + >>> Variance(X) + Variance(X) + >>> Variance(X).evaluate_integral() + sigma**2 + + Integral representation of the underlying calculations: + + >>> Variance(X).rewrite(Integral) + Integral(sqrt(2)*(X - Integral(sqrt(2)*X*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)))**2*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)) + + Integral representation, without expanding the PDF: + + >>> Variance(X).rewrite(Probability) + -Integral(x*Probability(Eq(X, x)), (x, -oo, oo))**2 + Integral(x**2*Probability(Eq(X, x)), (x, -oo, oo)) + + Rewrite the variance in terms of the expectation + + >>> Variance(X).rewrite(Expectation) + -Expectation(X)**2 + Expectation(X**2) + + Some transformations based on the properties of the variance may happen: + + >>> from sympy.abc import a + >>> Y = Normal("Y", 0, 1) + >>> Variance(a*X) + Variance(a*X) + + To expand the variance in its expression, use ``expand()``: + + >>> Variance(a*X).expand() + a**2*Variance(X) + >>> Variance(X + Y) + Variance(X + Y) + >>> Variance(X + Y).expand() + 2*Covariance(X, Y) + Variance(X) + Variance(Y) + + """ + def __new__(cls, arg, condition=None, **kwargs): + arg = _sympify(arg) + + if arg.is_Matrix: + from sympy.stats.symbolic_multivariate_probability import VarianceMatrix + return VarianceMatrix(arg, condition) + if condition is None: + obj = Expr.__new__(cls, arg) + else: + condition = _sympify(condition) + obj = Expr.__new__(cls, arg, condition) + obj._condition = condition + return obj + + def _eval_is_commutative(self): + return self.args[0].is_commutative + + def expand(self, **hints): + arg = self.args[0] + condition = self._condition + + if not is_random(arg): + return S.Zero + + if isinstance(arg, RandomSymbol): + return self + elif isinstance(arg, Add): + rv = [] + for a in arg.args: + if is_random(a): + rv.append(a) + variances = Add(*(Variance(xv, condition).expand() for xv in rv)) + map_to_covar = lambda x: 2*Covariance(*x, condition=condition).expand() + covariances = Add(*map(map_to_covar, itertools.combinations(rv, 2))) + return variances + covariances + elif isinstance(arg, Mul): + nonrv = [] + rv = [] + for a in arg.args: + if is_random(a): + rv.append(a) + else: + nonrv.append(a**2) + if len(rv) == 0: + return S.Zero + return Mul.fromiter(nonrv)*Variance(Mul.fromiter(rv), condition) + + # this expression contains a RandomSymbol somehow: + return self + + def _eval_rewrite_as_Expectation(self, arg, condition=None, **kwargs): + e1 = Expectation(arg**2, condition) + e2 = Expectation(arg, condition)**2 + return e1 - e2 + + def _eval_rewrite_as_Probability(self, arg, condition=None, **kwargs): + return self.rewrite(Expectation).rewrite(Probability) + + def _eval_rewrite_as_Integral(self, arg, condition=None, **kwargs): + return variance(self.args[0], self._condition, evaluate=False) + + _eval_rewrite_as_Sum = _eval_rewrite_as_Integral + + def evaluate_integral(self): + return self.rewrite(Integral).doit() + + +class Covariance(Expr): + """ + Symbolic expression for the covariance. + + Examples + ======== + + >>> from sympy.stats import Covariance + >>> from sympy.stats import Normal + >>> X = Normal("X", 3, 2) + >>> Y = Normal("Y", 0, 1) + >>> Z = Normal("Z", 0, 1) + >>> W = Normal("W", 0, 1) + >>> cexpr = Covariance(X, Y) + >>> cexpr + Covariance(X, Y) + + Evaluate the covariance, `X` and `Y` are independent, + therefore zero is the result: + + >>> cexpr.evaluate_integral() + 0 + + Rewrite the covariance expression in terms of expectations: + + >>> from sympy.stats import Expectation + >>> cexpr.rewrite(Expectation) + Expectation(X*Y) - Expectation(X)*Expectation(Y) + + In order to expand the argument, use ``expand()``: + + >>> from sympy.abc import a, b, c, d + >>> Covariance(a*X + b*Y, c*Z + d*W) + Covariance(a*X + b*Y, c*Z + d*W) + >>> Covariance(a*X + b*Y, c*Z + d*W).expand() + a*c*Covariance(X, Z) + a*d*Covariance(W, X) + b*c*Covariance(Y, Z) + b*d*Covariance(W, Y) + + This class is aware of some properties of the covariance: + + >>> Covariance(X, X).expand() + Variance(X) + >>> Covariance(a*X, b*Y).expand() + a*b*Covariance(X, Y) + """ + + def __new__(cls, arg1, arg2, condition=None, **kwargs): + arg1 = _sympify(arg1) + arg2 = _sympify(arg2) + + if arg1.is_Matrix or arg2.is_Matrix: + from sympy.stats.symbolic_multivariate_probability import CrossCovarianceMatrix + return CrossCovarianceMatrix(arg1, arg2, condition) + + if kwargs.pop('evaluate', global_parameters.evaluate): + arg1, arg2 = sorted([arg1, arg2], key=default_sort_key) + + if condition is None: + obj = Expr.__new__(cls, arg1, arg2) + else: + condition = _sympify(condition) + obj = Expr.__new__(cls, arg1, arg2, condition) + obj._condition = condition + return obj + + def _eval_is_commutative(self): + return self.args[0].is_commutative + + def expand(self, **hints): + arg1 = self.args[0] + arg2 = self.args[1] + condition = self._condition + + if arg1 == arg2: + return Variance(arg1, condition).expand() + + if not is_random(arg1): + return S.Zero + if not is_random(arg2): + return S.Zero + + arg1, arg2 = sorted([arg1, arg2], key=default_sort_key) + + if isinstance(arg1, RandomSymbol) and isinstance(arg2, RandomSymbol): + return Covariance(arg1, arg2, condition) + + coeff_rv_list1 = self._expand_single_argument(arg1.expand()) + coeff_rv_list2 = self._expand_single_argument(arg2.expand()) + + addends = [a*b*Covariance(*sorted([r1, r2], key=default_sort_key), condition=condition) + for (a, r1) in coeff_rv_list1 for (b, r2) in coeff_rv_list2] + return Add.fromiter(addends) + + @classmethod + def _expand_single_argument(cls, expr): + # return (coefficient, random_symbol) pairs: + if isinstance(expr, RandomSymbol): + return [(S.One, expr)] + elif isinstance(expr, Add): + outval = [] + for a in expr.args: + if isinstance(a, Mul): + outval.append(cls._get_mul_nonrv_rv_tuple(a)) + elif is_random(a): + outval.append((S.One, a)) + + return outval + elif isinstance(expr, Mul): + return [cls._get_mul_nonrv_rv_tuple(expr)] + elif is_random(expr): + return [(S.One, expr)] + + @classmethod + def _get_mul_nonrv_rv_tuple(cls, m): + rv = [] + nonrv = [] + for a in m.args: + if is_random(a): + rv.append(a) + else: + nonrv.append(a) + return (Mul.fromiter(nonrv), Mul.fromiter(rv)) + + def _eval_rewrite_as_Expectation(self, arg1, arg2, condition=None, **kwargs): + e1 = Expectation(arg1*arg2, condition) + e2 = Expectation(arg1, condition)*Expectation(arg2, condition) + return e1 - e2 + + def _eval_rewrite_as_Probability(self, arg1, arg2, condition=None, **kwargs): + return self.rewrite(Expectation).rewrite(Probability) + + def _eval_rewrite_as_Integral(self, arg1, arg2, condition=None, **kwargs): + return covariance(self.args[0], self.args[1], self._condition, evaluate=False) + + _eval_rewrite_as_Sum = _eval_rewrite_as_Integral + + def evaluate_integral(self): + return self.rewrite(Integral).doit() + + +class Moment(Expr): + """ + Symbolic class for Moment + + Examples + ======== + + >>> from sympy import Symbol, Integral + >>> from sympy.stats import Normal, Expectation, Probability, Moment + >>> mu = Symbol('mu', real=True) + >>> sigma = Symbol('sigma', positive=True) + >>> X = Normal('X', mu, sigma) + >>> M = Moment(X, 3, 1) + + To evaluate the result of Moment use `doit`: + + >>> M.doit() + mu**3 - 3*mu**2 + 3*mu*sigma**2 + 3*mu - 3*sigma**2 - 1 + + Rewrite the Moment expression in terms of Expectation: + + >>> M.rewrite(Expectation) + Expectation((X - 1)**3) + + Rewrite the Moment expression in terms of Probability: + + >>> M.rewrite(Probability) + Integral((x - 1)**3*Probability(Eq(X, x)), (x, -oo, oo)) + + Rewrite the Moment expression in terms of Integral: + + >>> M.rewrite(Integral) + Integral(sqrt(2)*(X - 1)**3*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)) + + """ + def __new__(cls, X, n, c=0, condition=None, **kwargs): + X = _sympify(X) + n = _sympify(n) + c = _sympify(c) + if condition is not None: + condition = _sympify(condition) + return super().__new__(cls, X, n, c, condition) + else: + return super().__new__(cls, X, n, c) + + def doit(self, **hints): + return self.rewrite(Expectation).doit(**hints) + + def _eval_rewrite_as_Expectation(self, X, n, c=0, condition=None, **kwargs): + return Expectation((X - c)**n, condition) + + def _eval_rewrite_as_Probability(self, X, n, c=0, condition=None, **kwargs): + return self.rewrite(Expectation).rewrite(Probability) + + def _eval_rewrite_as_Integral(self, X, n, c=0, condition=None, **kwargs): + return self.rewrite(Expectation).rewrite(Integral) + + +class CentralMoment(Expr): + """ + Symbolic class Central Moment + + Examples + ======== + + >>> from sympy import Symbol, Integral + >>> from sympy.stats import Normal, Expectation, Probability, CentralMoment + >>> mu = Symbol('mu', real=True) + >>> sigma = Symbol('sigma', positive=True) + >>> X = Normal('X', mu, sigma) + >>> CM = CentralMoment(X, 4) + + To evaluate the result of CentralMoment use `doit`: + + >>> CM.doit().simplify() + 3*sigma**4 + + Rewrite the CentralMoment expression in terms of Expectation: + + >>> CM.rewrite(Expectation) + Expectation((-Expectation(X) + X)**4) + + Rewrite the CentralMoment expression in terms of Probability: + + >>> CM.rewrite(Probability) + Integral((x - Integral(x*Probability(True), (x, -oo, oo)))**4*Probability(Eq(X, x)), (x, -oo, oo)) + + Rewrite the CentralMoment expression in terms of Integral: + + >>> CM.rewrite(Integral) + Integral(sqrt(2)*(X - Integral(sqrt(2)*X*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)))**4*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)) + + """ + def __new__(cls, X, n, condition=None, **kwargs): + X = _sympify(X) + n = _sympify(n) + if condition is not None: + condition = _sympify(condition) + return super().__new__(cls, X, n, condition) + else: + return super().__new__(cls, X, n) + + def doit(self, **hints): + return self.rewrite(Expectation).doit(**hints) + + def _eval_rewrite_as_Expectation(self, X, n, condition=None, **kwargs): + mu = Expectation(X, condition, **kwargs) + return Moment(X, n, mu, condition, **kwargs).rewrite(Expectation) + + def _eval_rewrite_as_Probability(self, X, n, condition=None, **kwargs): + return self.rewrite(Expectation).rewrite(Probability) + + def _eval_rewrite_as_Integral(self, X, n, condition=None, **kwargs): + return self.rewrite(Expectation).rewrite(Integral) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bb4c5aa8afe6fd818e136ec0797b7429e2da76cf --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/__init__.py @@ -0,0 +1,50 @@ +""" Rewrite Rules + +DISCLAIMER: This module is experimental. The interface is subject to change. + +A rule is a function that transforms one expression into another + + Rule :: Expr -> Expr + +A strategy is a function that says how a rule should be applied to a syntax +tree. In general strategies take rules and produce a new rule + + Strategy :: [Rules], Other-stuff -> Rule + +This allows developers to separate a mathematical transformation from the +algorithmic details of applying that transformation. The goal is to separate +the work of mathematical programming from algorithmic programming. + +Submodules + +strategies.rl - some fundamental rules +strategies.core - generic non-SymPy specific strategies +strategies.traverse - strategies that traverse a SymPy tree +strategies.tools - some conglomerate strategies that do depend on SymPy +""" + +from . import rl +from . import traverse +from .rl import rm_id, unpack, flatten, sort, glom, distribute, rebuild +from .util import new +from .core import ( + condition, debug, chain, null_safe, do_one, exhaust, minimize, tryit) +from .tools import canon, typed +from . import branch + +__all__ = [ + 'rl', + + 'traverse', + + 'rm_id', 'unpack', 'flatten', 'sort', 'glom', 'distribute', 'rebuild', + + 'new', + + 'condition', 'debug', 'chain', 'null_safe', 'do_one', 'exhaust', + 'minimize', 'tryit', + + 'canon', 'typed', + + 'branch', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/core.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/core.py new file mode 100644 index 0000000000000000000000000000000000000000..75b75cb5f2e0693eea98a7b1c9b3e7f036ec26f6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/core.py @@ -0,0 +1,151 @@ +""" Generic SymPy-Independent Strategies """ +from __future__ import annotations +from collections.abc import Callable, Mapping +from typing import TypeVar +from sys import stdout + + +_S = TypeVar('_S') +_T = TypeVar('_T') + + +def identity(x: _T) -> _T: + return x + + +def exhaust(rule: Callable[[_T], _T]) -> Callable[[_T], _T]: + """ Apply a rule repeatedly until it has no effect """ + def exhaustive_rl(expr: _T) -> _T: + new, old = rule(expr), expr + while new != old: + new, old = rule(new), new + return new + return exhaustive_rl + + +def memoize(rule: Callable[[_S], _T]) -> Callable[[_S], _T]: + """Memoized version of a rule + + Notes + ===== + + This cache can grow infinitely, so it is not recommended to use this + than ``functools.lru_cache`` unless you need very heavy computation. + """ + cache: dict[_S, _T] = {} + + def memoized_rl(expr: _S) -> _T: + if expr in cache: + return cache[expr] + else: + result = rule(expr) + cache[expr] = result + return result + return memoized_rl + + +def condition( + cond: Callable[[_T], bool], rule: Callable[[_T], _T] +) -> Callable[[_T], _T]: + """ Only apply rule if condition is true """ + def conditioned_rl(expr: _T) -> _T: + if cond(expr): + return rule(expr) + return expr + return conditioned_rl + + +def chain(*rules: Callable[[_T], _T]) -> Callable[[_T], _T]: + """ + Compose a sequence of rules so that they apply to the expr sequentially + """ + def chain_rl(expr: _T) -> _T: + for rule in rules: + expr = rule(expr) + return expr + return chain_rl + + +def debug(rule, file=None): + """ Print out before and after expressions each time rule is used """ + if file is None: + file = stdout + + def debug_rl(*args, **kwargs): + expr = args[0] + result = rule(*args, **kwargs) + if result != expr: + file.write("Rule: %s\n" % rule.__name__) + file.write("In: %s\nOut: %s\n\n" % (expr, result)) + return result + return debug_rl + + +def null_safe(rule: Callable[[_T], _T | None]) -> Callable[[_T], _T]: + """ Return original expr if rule returns None """ + def null_safe_rl(expr: _T) -> _T: + result = rule(expr) + if result is None: + return expr + return result + return null_safe_rl + + +def tryit(rule: Callable[[_T], _T], exception) -> Callable[[_T], _T]: + """ Return original expr if rule raises exception """ + def try_rl(expr: _T) -> _T: + try: + return rule(expr) + except exception: + return expr + return try_rl + + +def do_one(*rules: Callable[[_T], _T]) -> Callable[[_T], _T]: + """ Try each of the rules until one works. Then stop. """ + def do_one_rl(expr: _T) -> _T: + for rl in rules: + result = rl(expr) + if result != expr: + return result + return expr + return do_one_rl + + +def switch( + key: Callable[[_S], _T], + ruledict: Mapping[_T, Callable[[_S], _S]] +) -> Callable[[_S], _S]: + """ Select a rule based on the result of key called on the function """ + def switch_rl(expr: _S) -> _S: + rl = ruledict.get(key(expr), identity) + return rl(expr) + return switch_rl + + +# XXX Untyped default argument for minimize function +# where python requires SupportsRichComparison type +def _identity(x): + return x + + +def minimize( + *rules: Callable[[_S], _T], + objective=_identity +) -> Callable[[_S], _T]: + """ Select result of rules that minimizes objective + + >>> from sympy.strategies import minimize + >>> inc = lambda x: x + 1 + >>> dec = lambda x: x - 1 + >>> rl = minimize(inc, dec) + >>> rl(4) + 3 + + >>> rl = minimize(inc, dec, objective=lambda x: -x) # maximize + >>> rl(4) + 5 + """ + def minrule(expr: _S) -> _T: + return min([rule(expr) for rule in rules], key=objective) + return minrule diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/rl.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/rl.py new file mode 100644 index 0000000000000000000000000000000000000000..e84ee90582fafcf36fd4205a58b05b650875a9a5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/rl.py @@ -0,0 +1,176 @@ +""" Generic Rules for SymPy + +This file assumes knowledge of Basic and little else. +""" +from sympy.utilities.iterables import sift +from .util import new + + +# Functions that create rules +def rm_id(isid, new=new): + """ Create a rule to remove identities. + + isid - fn :: x -> Bool --- whether or not this element is an identity. + + Examples + ======== + + >>> from sympy.strategies import rm_id + >>> from sympy import Basic, S + >>> remove_zeros = rm_id(lambda x: x==0) + >>> remove_zeros(Basic(S(1), S(0), S(2))) + Basic(1, 2) + >>> remove_zeros(Basic(S(0), S(0))) # If only identities then we keep one + Basic(0) + + See Also: + unpack + """ + def ident_remove(expr): + """ Remove identities """ + ids = list(map(isid, expr.args)) + if sum(ids) == 0: # No identities. Common case + return expr + elif sum(ids) != len(ids): # there is at least one non-identity + return new(expr.__class__, + *[arg for arg, x in zip(expr.args, ids) if not x]) + else: + return new(expr.__class__, expr.args[0]) + + return ident_remove + + +def glom(key, count, combine): + """ Create a rule to conglomerate identical args. + + Examples + ======== + + >>> from sympy.strategies import glom + >>> from sympy import Add + >>> from sympy.abc import x + + >>> key = lambda x: x.as_coeff_Mul()[1] + >>> count = lambda x: x.as_coeff_Mul()[0] + >>> combine = lambda cnt, arg: cnt * arg + >>> rl = glom(key, count, combine) + + >>> rl(Add(x, -x, 3*x, 2, 3, evaluate=False)) + 3*x + 5 + + Wait, how are key, count and combine supposed to work? + + >>> key(2*x) + x + >>> count(2*x) + 2 + >>> combine(2, x) + 2*x + """ + def conglomerate(expr): + """ Conglomerate together identical args x + x -> 2x """ + groups = sift(expr.args, key) + counts = {k: sum(map(count, args)) for k, args in groups.items()} + newargs = [combine(cnt, mat) for mat, cnt in counts.items()] + if set(newargs) != set(expr.args): + return new(type(expr), *newargs) + else: + return expr + + return conglomerate + + +def sort(key, new=new): + """ Create a rule to sort by a key function. + + Examples + ======== + + >>> from sympy.strategies import sort + >>> from sympy import Basic, S + >>> sort_rl = sort(str) + >>> sort_rl(Basic(S(3), S(1), S(2))) + Basic(1, 2, 3) + """ + + def sort_rl(expr): + return new(expr.__class__, *sorted(expr.args, key=key)) + return sort_rl + + +def distribute(A, B): + """ Turns an A containing Bs into a B of As + + where A, B are container types + + >>> from sympy.strategies import distribute + >>> from sympy import Add, Mul, symbols + >>> x, y = symbols('x,y') + >>> dist = distribute(Mul, Add) + >>> expr = Mul(2, x+y, evaluate=False) + >>> expr + 2*(x + y) + >>> dist(expr) + 2*x + 2*y + """ + + def distribute_rl(expr): + for i, arg in enumerate(expr.args): + if isinstance(arg, B): + first, b, tail = expr.args[:i], expr.args[i], expr.args[i + 1:] + return B(*[A(*(first + (arg,) + tail)) for arg in b.args]) + return expr + return distribute_rl + + +def subs(a, b): + """ Replace expressions exactly """ + def subs_rl(expr): + if expr == a: + return b + else: + return expr + return subs_rl + + +# Functions that are rules +def unpack(expr): + """ Rule to unpack singleton args + + >>> from sympy.strategies import unpack + >>> from sympy import Basic, S + >>> unpack(Basic(S(2))) + 2 + """ + if len(expr.args) == 1: + return expr.args[0] + else: + return expr + + +def flatten(expr, new=new): + """ Flatten T(a, b, T(c, d), T2(e)) to T(a, b, c, d, T2(e)) """ + cls = expr.__class__ + args = [] + for arg in expr.args: + if arg.__class__ == cls: + args.extend(arg.args) + else: + args.append(arg) + return new(expr.__class__, *args) + + +def rebuild(expr): + """ Rebuild a SymPy tree. + + Explanation + =========== + + This function recursively calls constructors in the expression tree. + This forces canonicalization and removes ugliness introduced by the use of + Basic.__new__ + """ + if expr.is_Atom: + return expr + else: + return expr.func(*list(map(rebuild, expr.args))) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/tools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/tools.py new file mode 100644 index 0000000000000000000000000000000000000000..e6a94c16db57206d7c83c8a5e13930c4cffdde47 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/tools.py @@ -0,0 +1,53 @@ +from . import rl +from .core import do_one, exhaust, switch +from .traverse import top_down + + +def subs(d, **kwargs): + """ Full simultaneous exact substitution. + + Examples + ======== + + >>> from sympy.strategies.tools import subs + >>> from sympy import Basic, S + >>> mapping = {S(1): S(4), S(4): S(1), Basic(S(5)): Basic(S(6), S(7))} + >>> expr = Basic(S(1), Basic(S(2), S(3)), Basic(S(4), Basic(S(5)))) + >>> subs(mapping)(expr) + Basic(4, Basic(2, 3), Basic(1, Basic(6, 7))) + """ + if d: + return top_down(do_one(*map(rl.subs, *zip(*d.items()))), **kwargs) + else: + return lambda x: x + + +def canon(*rules, **kwargs): + """ Strategy for canonicalization. + + Explanation + =========== + + Apply each rule in a bottom_up fashion through the tree. + Do each one in turn. + Keep doing this until there is no change. + """ + return exhaust(top_down(exhaust(do_one(*rules)), **kwargs)) + + +def typed(ruletypes): + """ Apply rules based on the expression type + + inputs: + ruletypes -- a dict mapping {Type: rule} + + Examples + ======== + + >>> from sympy.strategies import rm_id, typed + >>> from sympy import Add, Mul + >>> rm_zeros = rm_id(lambda x: x==0) + >>> rm_ones = rm_id(lambda x: x==1) + >>> remove_idents = typed({Add: rm_zeros, Mul: rm_ones}) + """ + return switch(type, ruletypes) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/traverse.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/traverse.py new file mode 100644 index 0000000000000000000000000000000000000000..869361f443742b5b7346c9c970f103b955e8473e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/traverse.py @@ -0,0 +1,37 @@ +"""Strategies to Traverse a Tree.""" +from sympy.strategies.util import basic_fns +from sympy.strategies.core import chain, do_one + + +def top_down(rule, fns=basic_fns): + """Apply a rule down a tree running it on the top nodes first.""" + return chain(rule, lambda expr: sall(top_down(rule, fns), fns)(expr)) + + +def bottom_up(rule, fns=basic_fns): + """Apply a rule down a tree running it on the bottom nodes first.""" + return chain(lambda expr: sall(bottom_up(rule, fns), fns)(expr), rule) + + +def top_down_once(rule, fns=basic_fns): + """Apply a rule down a tree - stop on success.""" + return do_one(rule, lambda expr: sall(top_down(rule, fns), fns)(expr)) + + +def bottom_up_once(rule, fns=basic_fns): + """Apply a rule up a tree - stop on success.""" + return do_one(lambda expr: sall(bottom_up(rule, fns), fns)(expr), rule) + + +def sall(rule, fns=basic_fns): + """Strategic all - apply rule to args.""" + op, new, children, leaf = map(fns.get, ('op', 'new', 'children', 'leaf')) + + def all_rl(expr): + if leaf(expr): + return expr + else: + args = map(rule, children(expr)) + return new(op(expr), *args) + + return all_rl diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/tree.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/tree.py new file mode 100644 index 0000000000000000000000000000000000000000..c2006fde4fc5d09f3d38baae4d7335b4cbd971b7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/tree.py @@ -0,0 +1,139 @@ +from functools import partial +from sympy.strategies import chain, minimize +from sympy.strategies.core import identity +import sympy.strategies.branch as branch +from sympy.strategies.branch import yieldify + + +def treeapply(tree, join, leaf=identity): + """ Apply functions onto recursive containers (tree). + + Explanation + =========== + + join - a dictionary mapping container types to functions + e.g. ``{list: minimize, tuple: chain}`` + + Keys are containers/iterables. Values are functions [a] -> a. + + Examples + ======== + + >>> from sympy.strategies.tree import treeapply + >>> tree = [(3, 2), (4, 1)] + >>> treeapply(tree, {list: max, tuple: min}) + 2 + + >>> add = lambda *args: sum(args) + >>> def mul(*args): + ... total = 1 + ... for arg in args: + ... total *= arg + ... return total + >>> treeapply(tree, {list: mul, tuple: add}) + 25 + """ + for typ in join: + if isinstance(tree, typ): + return join[typ](*map(partial(treeapply, join=join, leaf=leaf), + tree)) + return leaf(tree) + + +def greedy(tree, objective=identity, **kwargs): + """ Execute a strategic tree. Select alternatives greedily + + Trees + ----- + + Nodes in a tree can be either + + function - a leaf + list - a selection among operations + tuple - a sequence of chained operations + + Textual examples + ---------------- + + Text: Run f, then run g, e.g. ``lambda x: g(f(x))`` + Code: ``(f, g)`` + + Text: Run either f or g, whichever minimizes the objective + Code: ``[f, g]`` + + Textx: Run either f or g, whichever is better, then run h + Code: ``([f, g], h)`` + + Text: Either expand then simplify or try factor then foosimp. Finally print + Code: ``([(expand, simplify), (factor, foosimp)], print)`` + + Objective + --------- + + "Better" is determined by the objective keyword. This function makes + choices to minimize the objective. It defaults to the identity. + + Examples + ======== + + >>> from sympy.strategies.tree import greedy + >>> inc = lambda x: x + 1 + >>> dec = lambda x: x - 1 + >>> double = lambda x: 2*x + + >>> tree = [inc, (dec, double)] # either inc or dec-then-double + >>> fn = greedy(tree) + >>> fn(4) # lowest value comes from the inc + 5 + >>> fn(1) # lowest value comes from dec then double + 0 + + This function selects between options in a tuple. The result is chosen + that minimizes the objective function. + + >>> fn = greedy(tree, objective=lambda x: -x) # maximize + >>> fn(4) # highest value comes from the dec then double + 6 + >>> fn(1) # highest value comes from the inc + 2 + + Greediness + ---------- + + This is a greedy algorithm. In the example: + + ([a, b], c) # do either a or b, then do c + + the choice between running ``a`` or ``b`` is made without foresight to c + """ + optimize = partial(minimize, objective=objective) + return treeapply(tree, {list: optimize, tuple: chain}, **kwargs) + + +def allresults(tree, leaf=yieldify): + """ Execute a strategic tree. Return all possibilities. + + Returns a lazy iterator of all possible results + + Exhaustiveness + -------------- + + This is an exhaustive algorithm. In the example + + ([a, b], [c, d]) + + All of the results from + + (a, c), (b, c), (a, d), (b, d) + + are returned. This can lead to combinatorial blowup. + + See sympy.strategies.greedy for details on input + """ + return treeapply(tree, {list: branch.multiplex, tuple: branch.chain}, + leaf=leaf) + + +def brute(tree, objective=identity, **kwargs): + return lambda expr: min(tuple(allresults(tree, **kwargs)(expr)), + key=objective) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/util.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/util.py new file mode 100644 index 0000000000000000000000000000000000000000..13aab5f6a49650c5ded9cd913c23c6682f18d40a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/strategies/util.py @@ -0,0 +1,17 @@ +from sympy.core.basic import Basic + +new = Basic.__new__ + + +def assoc(d, k, v): + d = d.copy() + d[k] = v + return d + + +basic_fns = {'op': type, + 'new': Basic.__new__, + 'leaf': lambda x: not isinstance(x, Basic) or x.is_Atom, + 'children': lambda x: x.args} + +expr_fns = assoc(basic_fns, 'new', lambda op, *args: op(*args)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a832614b1d48e26bf01e16f040f34dd412e8e32b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/__init__.py @@ -0,0 +1,23 @@ +"""A module to manipulate symbolic objects with indices including tensors + +""" +from .indexed import IndexedBase, Idx, Indexed +from .index_methods import get_contraction_structure, get_indices +from .functions import shape +from .array import (MutableDenseNDimArray, ImmutableDenseNDimArray, + MutableSparseNDimArray, ImmutableSparseNDimArray, NDimArray, tensorproduct, + tensorcontraction, tensordiagonal, derive_by_array, permutedims, Array, + DenseNDimArray, SparseNDimArray,) + +__all__ = [ + 'IndexedBase', 'Idx', 'Indexed', + + 'get_contraction_structure', 'get_indices', + + 'shape', + + 'MutableDenseNDimArray', 'ImmutableDenseNDimArray', + 'MutableSparseNDimArray', 'ImmutableSparseNDimArray', 'NDimArray', + 'tensorproduct', 'tensorcontraction', 'tensordiagonal', 'derive_by_array', 'permutedims', + 'Array', 'DenseNDimArray', 'SparseNDimArray', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/functions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/functions.py new file mode 100644 index 0000000000000000000000000000000000000000..f14599d69152db1713f21c9dd785683901c5eeb9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/functions.py @@ -0,0 +1,154 @@ +from collections.abc import Iterable +from functools import singledispatch + +from sympy.core.expr import Expr +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.core.sympify import sympify +from sympy.core.parameters import global_parameters + + +class TensorProduct(Expr): + """ + Generic class for tensor products. + """ + is_number = False + + def __new__(cls, *args, **kwargs): + from sympy.tensor.array import NDimArray, tensorproduct, Array + from sympy.matrices.expressions.matexpr import MatrixExpr + from sympy.matrices.matrixbase import MatrixBase + from sympy.strategies import flatten + + args = [sympify(arg) for arg in args] + evaluate = kwargs.get("evaluate", global_parameters.evaluate) + + if not evaluate: + obj = Expr.__new__(cls, *args) + return obj + + arrays = [] + other = [] + scalar = S.One + for arg in args: + if isinstance(arg, (Iterable, MatrixBase, NDimArray)): + arrays.append(Array(arg)) + elif isinstance(arg, (MatrixExpr,)): + other.append(arg) + else: + scalar *= arg + + coeff = scalar*tensorproduct(*arrays) + if len(other) == 0: + return coeff + if coeff != 1: + newargs = [coeff] + other + else: + newargs = other + obj = Expr.__new__(cls, *newargs, **kwargs) + return flatten(obj) + + def rank(self): + return len(self.shape) + + def _get_args_shapes(self): + from sympy.tensor.array import Array + return [i.shape if hasattr(i, "shape") else Array(i).shape for i in self.args] + + @property + def shape(self): + shape_list = self._get_args_shapes() + return sum(shape_list, ()) + + def __getitem__(self, index): + index = iter(index) + return Mul.fromiter( + arg.__getitem__(tuple(next(index) for i in shp)) + for arg, shp in zip(self.args, self._get_args_shapes()) + ) + + +@singledispatch +def shape(expr): + """ + Return the shape of the *expr* as a tuple. *expr* should represent + suitable object such as matrix or array. + + Parameters + ========== + + expr : SymPy object having ``MatrixKind`` or ``ArrayKind``. + + Raises + ====== + + NoShapeError : Raised when object with wrong kind is passed. + + Examples + ======== + + This function returns the shape of any object representing matrix or array. + + >>> from sympy import shape, Array, ImmutableDenseMatrix, Integral + >>> from sympy.abc import x + >>> A = Array([1, 2]) + >>> shape(A) + (2,) + >>> shape(Integral(A, x)) + (2,) + >>> M = ImmutableDenseMatrix([1, 2]) + >>> shape(M) + (2, 1) + >>> shape(Integral(M, x)) + (2, 1) + + You can support new type by dispatching. + + >>> from sympy import Expr + >>> class NewExpr(Expr): + ... pass + >>> @shape.register(NewExpr) + ... def _(expr): + ... return shape(expr.args[0]) + >>> shape(NewExpr(M)) + (2, 1) + + If unsuitable expression is passed, ``NoShapeError()`` will be raised. + + >>> shape(Integral(x, x)) + Traceback (most recent call last): + ... + sympy.tensor.functions.NoShapeError: shape() called on non-array object: Integral(x, x) + + Notes + ===== + + Array-like classes (such as ``Matrix`` or ``NDimArray``) has ``shape`` + property which returns its shape, but it cannot be used for non-array + classes containing array. This function returns the shape of any + registered object representing array. + + """ + if hasattr(expr, "shape"): + return expr.shape + raise NoShapeError( + "%s does not have shape, or its type is not registered to shape()." % expr) + + +class NoShapeError(Exception): + """ + Raised when ``shape()`` is called on non-array object. + + This error can be imported from ``sympy.tensor.functions``. + + Examples + ======== + + >>> from sympy import shape + >>> from sympy.abc import x + >>> shape(x) + Traceback (most recent call last): + ... + sympy.tensor.functions.NoShapeError: shape() called on non-array object: x + """ + pass diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/index_methods.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/index_methods.py new file mode 100644 index 0000000000000000000000000000000000000000..12f707b60b4ad0bcadc35a222d9abe0cc5e033fc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/index_methods.py @@ -0,0 +1,469 @@ +"""Module with functions operating on IndexedBase, Indexed and Idx objects + + - Check shape conformance + - Determine indices in resulting expression + + etc. + + Methods in this module could be implemented by calling methods on Expr + objects instead. When things stabilize this could be a useful + refactoring. +""" + +from functools import reduce + +from sympy.core.function import Function +from sympy.functions import exp, Piecewise +from sympy.tensor.indexed import Idx, Indexed +from sympy.utilities import sift + +from collections import OrderedDict + +class IndexConformanceException(Exception): + pass + +def _unique_and_repeated(inds): + """ + Returns the unique and repeated indices. Also note, from the examples given below + that the order of indices is maintained as given in the input. + + Examples + ======== + + >>> from sympy.tensor.index_methods import _unique_and_repeated + >>> _unique_and_repeated([2, 3, 1, 3, 0, 4, 0]) + ([2, 1, 4], [3, 0]) + """ + uniq = OrderedDict() + for i in inds: + if i in uniq: + uniq[i] = 0 + else: + uniq[i] = 1 + return sift(uniq, lambda x: uniq[x], binary=True) + +def _remove_repeated(inds): + """ + Removes repeated objects from sequences + + Returns a set of the unique objects and a tuple of all that have been + removed. + + Examples + ======== + + >>> from sympy.tensor.index_methods import _remove_repeated + >>> l1 = [1, 2, 3, 2] + >>> _remove_repeated(l1) + ({1, 3}, (2,)) + + """ + u, r = _unique_and_repeated(inds) + return set(u), tuple(r) + + +def _get_indices_Mul(expr, return_dummies=False): + """Determine the outer indices of a Mul object. + + Examples + ======== + + >>> from sympy.tensor.index_methods import _get_indices_Mul + >>> from sympy.tensor.indexed import IndexedBase, Idx + >>> i, j, k = map(Idx, ['i', 'j', 'k']) + >>> x = IndexedBase('x') + >>> y = IndexedBase('y') + >>> _get_indices_Mul(x[i, k]*y[j, k]) + ({i, j}, {}) + >>> _get_indices_Mul(x[i, k]*y[j, k], return_dummies=True) + ({i, j}, {}, (k,)) + + """ + + inds = list(map(get_indices, expr.args)) + inds, syms = list(zip(*inds)) + + inds = list(map(list, inds)) + inds = list(reduce(lambda x, y: x + y, inds)) + inds, dummies = _remove_repeated(inds) + + symmetry = {} + for s in syms: + for pair in s: + if pair in symmetry: + symmetry[pair] *= s[pair] + else: + symmetry[pair] = s[pair] + + if return_dummies: + return inds, symmetry, dummies + else: + return inds, symmetry + + +def _get_indices_Pow(expr): + """Determine outer indices of a power or an exponential. + + A power is considered a universal function, so that the indices of a Pow is + just the collection of indices present in the expression. This may be + viewed as a bit inconsistent in the special case: + + x[i]**2 = x[i]*x[i] (1) + + The above expression could have been interpreted as the contraction of x[i] + with itself, but we choose instead to interpret it as a function + + lambda y: y**2 + + applied to each element of x (a universal function in numpy terms). In + order to allow an interpretation of (1) as a contraction, we need + contravariant and covariant Idx subclasses. (FIXME: this is not yet + implemented) + + Expressions in the base or exponent are subject to contraction as usual, + but an index that is present in the exponent, will not be considered + contractable with its own base. Note however, that indices in the same + exponent can be contracted with each other. + + Examples + ======== + + >>> from sympy.tensor.index_methods import _get_indices_Pow + >>> from sympy import Pow, exp, IndexedBase, Idx + >>> A = IndexedBase('A') + >>> x = IndexedBase('x') + >>> i, j, k = map(Idx, ['i', 'j', 'k']) + >>> _get_indices_Pow(exp(A[i, j]*x[j])) + ({i}, {}) + >>> _get_indices_Pow(Pow(x[i], x[i])) + ({i}, {}) + >>> _get_indices_Pow(Pow(A[i, j]*x[j], x[i])) + ({i}, {}) + + """ + base, exp = expr.as_base_exp() + binds, bsyms = get_indices(base) + einds, esyms = get_indices(exp) + + inds = binds | einds + + # FIXME: symmetries from power needs to check special cases, else nothing + symmetries = {} + + return inds, symmetries + + +def _get_indices_Add(expr): + """Determine outer indices of an Add object. + + In a sum, each term must have the same set of outer indices. A valid + expression could be + + x(i)*y(j) - x(j)*y(i) + + But we do not allow expressions like: + + x(i)*y(j) - z(j)*z(j) + + FIXME: Add support for Numpy broadcasting + + Examples + ======== + + >>> from sympy.tensor.index_methods import _get_indices_Add + >>> from sympy.tensor.indexed import IndexedBase, Idx + >>> i, j, k = map(Idx, ['i', 'j', 'k']) + >>> x = IndexedBase('x') + >>> y = IndexedBase('y') + >>> _get_indices_Add(x[i] + x[k]*y[i, k]) + ({i}, {}) + + """ + + inds = list(map(get_indices, expr.args)) + inds, syms = list(zip(*inds)) + + # allow broadcast of scalars + non_scalars = [x for x in inds if x != set()] + if not non_scalars: + return set(), {} + + if not all(x == non_scalars[0] for x in non_scalars[1:]): + raise IndexConformanceException("Indices are not consistent: %s" % expr) + if not reduce(lambda x, y: x != y or y, syms): + symmetries = syms[0] + else: + # FIXME: search for symmetries + symmetries = {} + + return non_scalars[0], symmetries + + +def get_indices(expr): + """Determine the outer indices of expression ``expr`` + + By *outer* we mean indices that are not summation indices. Returns a set + and a dict. The set contains outer indices and the dict contains + information about index symmetries. + + Examples + ======== + + >>> from sympy.tensor.index_methods import get_indices + >>> from sympy import symbols + >>> from sympy.tensor import IndexedBase + >>> x, y, A = map(IndexedBase, ['x', 'y', 'A']) + >>> i, j, a, z = symbols('i j a z', integer=True) + + The indices of the total expression is determined, Repeated indices imply a + summation, for instance the trace of a matrix A: + + >>> get_indices(A[i, i]) + (set(), {}) + + In the case of many terms, the terms are required to have identical + outer indices. Else an IndexConformanceException is raised. + + >>> get_indices(x[i] + A[i, j]*y[j]) + ({i}, {}) + + :Exceptions: + + An IndexConformanceException means that the terms ar not compatible, e.g. + + >>> get_indices(x[i] + y[j]) #doctest: +SKIP + (...) + IndexConformanceException: Indices are not consistent: x(i) + y(j) + + .. warning:: + The concept of *outer* indices applies recursively, starting on the deepest + level. This implies that dummies inside parenthesis are assumed to be + summed first, so that the following expression is handled gracefully: + + >>> get_indices((x[i] + A[i, j]*y[j])*x[j]) + ({i, j}, {}) + + This is correct and may appear convenient, but you need to be careful + with this as SymPy will happily .expand() the product, if requested. The + resulting expression would mix the outer ``j`` with the dummies inside + the parenthesis, which makes it a different expression. To be on the + safe side, it is best to avoid such ambiguities by using unique indices + for all contractions that should be held separate. + + """ + # We call ourself recursively to determine indices of sub expressions. + + # break recursion + if isinstance(expr, Indexed): + c = expr.indices + inds, dummies = _remove_repeated(c) + return inds, {} + elif expr is None: + return set(), {} + elif isinstance(expr, Idx): + return {expr}, {} + elif expr.is_Atom: + return set(), {} + + + # recurse via specialized functions + else: + if expr.is_Mul: + return _get_indices_Mul(expr) + elif expr.is_Add: + return _get_indices_Add(expr) + elif expr.is_Pow or isinstance(expr, exp): + return _get_indices_Pow(expr) + + elif isinstance(expr, Piecewise): + # FIXME: No support for Piecewise yet + return set(), {} + elif isinstance(expr, Function): + # Support ufunc like behaviour by returning indices from arguments. + # Functions do not interpret repeated indices across arguments + # as summation + ind0 = set() + for arg in expr.args: + ind, sym = get_indices(arg) + ind0 |= ind + return ind0, sym + + # this test is expensive, so it should be at the end + elif not expr.has(Indexed): + return set(), {} + raise NotImplementedError( + "FIXME: No specialized handling of type %s" % type(expr)) + + +def get_contraction_structure(expr): + """Determine dummy indices of ``expr`` and describe its structure + + By *dummy* we mean indices that are summation indices. + + The structure of the expression is determined and described as follows: + + 1) A conforming summation of Indexed objects is described with a dict where + the keys are summation indices and the corresponding values are sets + containing all terms for which the summation applies. All Add objects + in the SymPy expression tree are described like this. + + 2) For all nodes in the SymPy expression tree that are *not* of type Add, the + following applies: + + If a node discovers contractions in one of its arguments, the node + itself will be stored as a key in the dict. For that key, the + corresponding value is a list of dicts, each of which is the result of a + recursive call to get_contraction_structure(). The list contains only + dicts for the non-trivial deeper contractions, omitting dicts with None + as the one and only key. + + .. Note:: The presence of expressions among the dictionary keys indicates + multiple levels of index contractions. A nested dict displays nested + contractions and may itself contain dicts from a deeper level. In + practical calculations the summation in the deepest nested level must be + calculated first so that the outer expression can access the resulting + indexed object. + + Examples + ======== + + >>> from sympy.tensor.index_methods import get_contraction_structure + >>> from sympy import default_sort_key + >>> from sympy.tensor import IndexedBase, Idx + >>> x, y, A = map(IndexedBase, ['x', 'y', 'A']) + >>> i, j, k, l = map(Idx, ['i', 'j', 'k', 'l']) + >>> get_contraction_structure(x[i]*y[i] + A[j, j]) + {(i,): {x[i]*y[i]}, (j,): {A[j, j]}} + >>> get_contraction_structure(x[i]*y[j]) + {None: {x[i]*y[j]}} + + A multiplication of contracted factors results in nested dicts representing + the internal contractions. + + >>> d = get_contraction_structure(x[i, i]*y[j, j]) + >>> sorted(d.keys(), key=default_sort_key) + [None, x[i, i]*y[j, j]] + + In this case, the product has no contractions: + + >>> d[None] + {x[i, i]*y[j, j]} + + Factors are contracted "first": + + >>> sorted(d[x[i, i]*y[j, j]], key=default_sort_key) + [{(i,): {x[i, i]}}, {(j,): {y[j, j]}}] + + A parenthesized Add object is also returned as a nested dictionary. The + term containing the parenthesis is a Mul with a contraction among the + arguments, so it will be found as a key in the result. It stores the + dictionary resulting from a recursive call on the Add expression. + + >>> d = get_contraction_structure(x[i]*(y[i] + A[i, j]*x[j])) + >>> sorted(d.keys(), key=default_sort_key) + [(A[i, j]*x[j] + y[i])*x[i], (i,)] + >>> d[(i,)] + {(A[i, j]*x[j] + y[i])*x[i]} + >>> d[x[i]*(A[i, j]*x[j] + y[i])] + [{None: {y[i]}, (j,): {A[i, j]*x[j]}}] + + Powers with contractions in either base or exponent will also be found as + keys in the dictionary, mapping to a list of results from recursive calls: + + >>> d = get_contraction_structure(A[j, j]**A[i, i]) + >>> d[None] + {A[j, j]**A[i, i]} + >>> nested_contractions = d[A[j, j]**A[i, i]] + >>> nested_contractions[0] + {(j,): {A[j, j]}} + >>> nested_contractions[1] + {(i,): {A[i, i]}} + + The description of the contraction structure may appear complicated when + represented with a string in the above examples, but it is easy to iterate + over: + + >>> from sympy import Expr + >>> for key in d: + ... if isinstance(key, Expr): + ... continue + ... for term in d[key]: + ... if term in d: + ... # treat deepest contraction first + ... pass + ... # treat outermost contactions here + + """ + + # We call ourself recursively to inspect sub expressions. + + if isinstance(expr, Indexed): + junk, key = _remove_repeated(expr.indices) + return {key or None: {expr}} + elif expr.is_Atom: + return {None: {expr}} + elif expr.is_Mul: + junk, junk, key = _get_indices_Mul(expr, return_dummies=True) + result = {key or None: {expr}} + # recurse on every factor + nested = [] + for fac in expr.args: + facd = get_contraction_structure(fac) + if not (None in facd and len(facd) == 1): + nested.append(facd) + if nested: + result[expr] = nested + return result + elif expr.is_Pow or isinstance(expr, exp): + # recurse in base and exp separately. If either has internal + # contractions we must include ourselves as a key in the returned dict + b, e = expr.as_base_exp() + dbase = get_contraction_structure(b) + dexp = get_contraction_structure(e) + + dicts = [] + for d in dbase, dexp: + if not (None in d and len(d) == 1): + dicts.append(d) + result = {None: {expr}} + if dicts: + result[expr] = dicts + return result + elif expr.is_Add: + # Note: we just collect all terms with identical summation indices, We + # do nothing to identify equivalent terms here, as this would require + # substitutions or pattern matching in expressions of unknown + # complexity. + result = {} + for term in expr.args: + # recurse on every term + d = get_contraction_structure(term) + for key in d: + if key in result: + result[key] |= d[key] + else: + result[key] = d[key] + return result + + elif isinstance(expr, Piecewise): + # FIXME: No support for Piecewise yet + return {None: expr} + elif isinstance(expr, Function): + # Collect non-trivial contraction structures in each argument + # We do not report repeated indices in separate arguments as a + # contraction + deeplist = [] + for arg in expr.args: + deep = get_contraction_structure(arg) + if not (None in deep and len(deep) == 1): + deeplist.append(deep) + d = {None: {expr}} + if deeplist: + d[expr] = deeplist + return d + + # this test is expensive, so it should be at the end + elif not expr.has(Indexed): + return {None: {expr}} + raise NotImplementedError( + "FIXME: No specialized handling of type %s" % type(expr)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/indexed.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/indexed.py new file mode 100644 index 0000000000000000000000000000000000000000..feddad21e52bbab2e1243beafdb11f30b2eded4d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/indexed.py @@ -0,0 +1,793 @@ +r"""Module that defines indexed objects. + +The classes ``IndexedBase``, ``Indexed``, and ``Idx`` represent a +matrix element ``M[i, j]`` as in the following diagram:: + + 1) The Indexed class represents the entire indexed object. + | + ___|___ + ' ' + M[i, j] + / \__\______ + | | + | | + | 2) The Idx class represents indices; each Idx can + | optionally contain information about its range. + | + 3) IndexedBase represents the 'stem' of an indexed object, here `M`. + The stem used by itself is usually taken to represent the entire + array. + +There can be any number of indices on an Indexed object. No +transformation properties are implemented in these Base objects, but +implicit contraction of repeated indices is supported. + +Note that the support for complicated (i.e. non-atomic) integer +expressions as indices is limited. (This should be improved in +future releases.) + +Examples +======== + +To express the above matrix element example you would write: + +>>> from sympy import symbols, IndexedBase, Idx +>>> M = IndexedBase('M') +>>> i, j = symbols('i j', cls=Idx) +>>> M[i, j] +M[i, j] + +Repeated indices in a product implies a summation, so to express a +matrix-vector product in terms of Indexed objects: + +>>> x = IndexedBase('x') +>>> M[i, j]*x[j] +M[i, j]*x[j] + +If the indexed objects will be converted to component based arrays, e.g. +with the code printers or the autowrap framework, you also need to provide +(symbolic or numerical) dimensions. This can be done by passing an +optional shape parameter to IndexedBase upon construction: + +>>> dim1, dim2 = symbols('dim1 dim2', integer=True) +>>> A = IndexedBase('A', shape=(dim1, 2*dim1, dim2)) +>>> A.shape +(dim1, 2*dim1, dim2) +>>> A[i, j, 3].shape +(dim1, 2*dim1, dim2) + +If an IndexedBase object has no shape information, it is assumed that the +array is as large as the ranges of its indices: + +>>> n, m = symbols('n m', integer=True) +>>> i = Idx('i', m) +>>> j = Idx('j', n) +>>> M[i, j].shape +(m, n) +>>> M[i, j].ranges +[(0, m - 1), (0, n - 1)] + +The above can be compared with the following: + +>>> A[i, 2, j].shape +(dim1, 2*dim1, dim2) +>>> A[i, 2, j].ranges +[(0, m - 1), None, (0, n - 1)] + +To analyze the structure of indexed expressions, you can use the methods +get_indices() and get_contraction_structure(): + +>>> from sympy.tensor import get_indices, get_contraction_structure +>>> get_indices(A[i, j, j]) +({i}, {}) +>>> get_contraction_structure(A[i, j, j]) +{(j,): {A[i, j, j]}} + +See the appropriate docstrings for a detailed explanation of the output. +""" + +# TODO: (some ideas for improvement) +# +# o test and guarantee numpy compatibility +# - implement full support for broadcasting +# - strided arrays +# +# o more functions to analyze indexed expressions +# - identify standard constructs, e.g matrix-vector product in a subexpression +# +# o functions to generate component based arrays (numpy and sympy.Matrix) +# - generate a single array directly from Indexed +# - convert simple sub-expressions +# +# o sophisticated indexing (possibly in subclasses to preserve simplicity) +# - Idx with range smaller than dimension of Indexed +# - Idx with stepsize != 1 +# - Idx with step determined by function call +from collections.abc import Iterable + +from sympy.core.numbers import Number +from sympy.core.assumptions import StdFactKB +from sympy.core import Expr, Tuple, sympify, S +from sympy.core.symbol import _filter_assumptions, Symbol +from sympy.core.logic import fuzzy_bool, fuzzy_not +from sympy.core.sympify import _sympify +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.multipledispatch import dispatch +from sympy.utilities.iterables import is_sequence, NotIterable +from sympy.utilities.misc import filldedent + + +class IndexException(Exception): + pass + + +class Indexed(Expr): + """Represents a mathematical object with indices. + + >>> from sympy import Indexed, IndexedBase, Idx, symbols + >>> i, j = symbols('i j', cls=Idx) + >>> Indexed('A', i, j) + A[i, j] + + It is recommended that ``Indexed`` objects be created by indexing ``IndexedBase``: + ``IndexedBase('A')[i, j]`` instead of ``Indexed(IndexedBase('A'), i, j)``. + + >>> A = IndexedBase('A') + >>> a_ij = A[i, j] # Prefer this, + >>> b_ij = Indexed(A, i, j) # over this. + >>> a_ij == b_ij + True + + """ + is_Indexed = True + is_symbol = True + is_Atom = True + + def __new__(cls, base, *args, **kw_args): + from sympy.tensor.array.ndim_array import NDimArray + from sympy.matrices.matrixbase import MatrixBase + + if not args: + raise IndexException("Indexed needs at least one index.") + if isinstance(base, (str, Symbol)): + base = IndexedBase(base) + elif not hasattr(base, '__getitem__') and not isinstance(base, IndexedBase): + raise TypeError(filldedent(""" + The base can only be replaced with a string, Symbol, + IndexedBase or an object with a method for getting + items (i.e. an object with a `__getitem__` method). + """)) + args = list(map(sympify, args)) + if isinstance(base, (NDimArray, Iterable, Tuple, MatrixBase)) and all(i.is_number for i in args): + if len(args) == 1: + return base[args[0]] + else: + return base[args] + + base = _sympify(base) + + obj = Expr.__new__(cls, base, *args, **kw_args) + + IndexedBase._set_assumptions(obj, base.assumptions0) + + return obj + + def _hashable_content(self): + return super()._hashable_content() + tuple(sorted(self.assumptions0.items())) + + @property + def name(self): + return str(self) + + @property + def _diff_wrt(self): + """Allow derivatives with respect to an ``Indexed`` object.""" + return True + + def _eval_derivative(self, wrt): + from sympy.tensor.array.ndim_array import NDimArray + + if isinstance(wrt, Indexed) and wrt.base == self.base: + if len(self.indices) != len(wrt.indices): + msg = "Different # of indices: d({!s})/d({!s})".format(self, + wrt) + raise IndexException(msg) + result = S.One + for index1, index2 in zip(self.indices, wrt.indices): + result *= KroneckerDelta(index1, index2) + return result + elif isinstance(self.base, NDimArray): + from sympy.tensor.array import derive_by_array + return Indexed(derive_by_array(self.base, wrt), *self.args[1:]) + else: + if Tuple(self.indices).has(wrt): + return S.NaN + return S.Zero + + @property + def assumptions0(self): + return {k: v for k, v in self._assumptions.items() if v is not None} + + @property + def base(self): + """Returns the ``IndexedBase`` of the ``Indexed`` object. + + Examples + ======== + + >>> from sympy import Indexed, IndexedBase, Idx, symbols + >>> i, j = symbols('i j', cls=Idx) + >>> Indexed('A', i, j).base + A + >>> B = IndexedBase('B') + >>> B == B[i, j].base + True + + """ + return self.args[0] + + @property + def indices(self): + """ + Returns the indices of the ``Indexed`` object. + + Examples + ======== + + >>> from sympy import Indexed, Idx, symbols + >>> i, j = symbols('i j', cls=Idx) + >>> Indexed('A', i, j).indices + (i, j) + + """ + return self.args[1:] + + @property + def rank(self): + """ + Returns the rank of the ``Indexed`` object. + + Examples + ======== + + >>> from sympy import Indexed, Idx, symbols + >>> i, j, k, l, m = symbols('i:m', cls=Idx) + >>> Indexed('A', i, j).rank + 2 + >>> q = Indexed('A', i, j, k, l, m) + >>> q.rank + 5 + >>> q.rank == len(q.indices) + True + + """ + return len(self.args) - 1 + + @property + def shape(self): + """Returns a list with dimensions of each index. + + Dimensions is a property of the array, not of the indices. Still, if + the ``IndexedBase`` does not define a shape attribute, it is assumed + that the ranges of the indices correspond to the shape of the array. + + >>> from sympy import IndexedBase, Idx, symbols + >>> n, m = symbols('n m', integer=True) + >>> i = Idx('i', m) + >>> j = Idx('j', m) + >>> A = IndexedBase('A', shape=(n, n)) + >>> B = IndexedBase('B') + >>> A[i, j].shape + (n, n) + >>> B[i, j].shape + (m, m) + """ + + if self.base.shape: + return self.base.shape + sizes = [] + for i in self.indices: + upper = getattr(i, 'upper', None) + lower = getattr(i, 'lower', None) + if None in (upper, lower): + raise IndexException(filldedent(""" + Range is not defined for all indices in: %s""" % self)) + try: + size = upper - lower + 1 + except TypeError: + raise IndexException(filldedent(""" + Shape cannot be inferred from Idx with + undefined range: %s""" % self)) + sizes.append(size) + return Tuple(*sizes) + + @property + def ranges(self): + """Returns a list of tuples with lower and upper range of each index. + + If an index does not define the data members upper and lower, the + corresponding slot in the list contains ``None`` instead of a tuple. + + Examples + ======== + + >>> from sympy import Indexed,Idx, symbols + >>> Indexed('A', Idx('i', 2), Idx('j', 4), Idx('k', 8)).ranges + [(0, 1), (0, 3), (0, 7)] + >>> Indexed('A', Idx('i', 3), Idx('j', 3), Idx('k', 3)).ranges + [(0, 2), (0, 2), (0, 2)] + >>> x, y, z = symbols('x y z', integer=True) + >>> Indexed('A', x, y, z).ranges + [None, None, None] + + """ + ranges = [] + sentinel = object() + for i in self.indices: + upper = getattr(i, 'upper', sentinel) + lower = getattr(i, 'lower', sentinel) + if sentinel not in (upper, lower): + ranges.append((lower, upper)) + else: + ranges.append(None) + return ranges + + def _sympystr(self, p): + indices = list(map(p.doprint, self.indices)) + return "%s[%s]" % (p.doprint(self.base), ", ".join(indices)) + + @property + def free_symbols(self): + base_free_symbols = self.base.free_symbols + indices_free_symbols = { + fs for i in self.indices for fs in i.free_symbols} + if base_free_symbols: + return {self} | base_free_symbols | indices_free_symbols + else: + return indices_free_symbols + + @property + def expr_free_symbols(self): + from sympy.utilities.exceptions import sympy_deprecation_warning + sympy_deprecation_warning(""" + The expr_free_symbols property is deprecated. Use free_symbols to get + the free symbols of an expression. + """, + deprecated_since_version="1.9", + active_deprecations_target="deprecated-expr-free-symbols") + + return {self} + + +class IndexedBase(Expr, NotIterable): + """Represent the base or stem of an indexed object + + The IndexedBase class represent an array that contains elements. The main purpose + of this class is to allow the convenient creation of objects of the Indexed + class. The __getitem__ method of IndexedBase returns an instance of + Indexed. Alone, without indices, the IndexedBase class can be used as a + notation for e.g. matrix equations, resembling what you could do with the + Symbol class. But, the IndexedBase class adds functionality that is not + available for Symbol instances: + + - An IndexedBase object can optionally store shape information. This can + be used in to check array conformance and conditions for numpy + broadcasting. (TODO) + - An IndexedBase object implements syntactic sugar that allows easy symbolic + representation of array operations, using implicit summation of + repeated indices. + - The IndexedBase object symbolizes a mathematical structure equivalent + to arrays, and is recognized as such for code generation and automatic + compilation and wrapping. + + >>> from sympy.tensor import IndexedBase, Idx + >>> from sympy import symbols + >>> A = IndexedBase('A'); A + A + >>> type(A) + + + When an IndexedBase object receives indices, it returns an array with named + axes, represented by an Indexed object: + + >>> i, j = symbols('i j', integer=True) + >>> A[i, j, 2] + A[i, j, 2] + >>> type(A[i, j, 2]) + + + The IndexedBase constructor takes an optional shape argument. If given, + it overrides any shape information in the indices. (But not the index + ranges!) + + >>> m, n, o, p = symbols('m n o p', integer=True) + >>> i = Idx('i', m) + >>> j = Idx('j', n) + >>> A[i, j].shape + (m, n) + >>> B = IndexedBase('B', shape=(o, p)) + >>> B[i, j].shape + (o, p) + + Assumptions can be specified with keyword arguments the same way as for Symbol: + + >>> A_real = IndexedBase('A', real=True) + >>> A_real.is_real + True + >>> A != A_real + True + + Assumptions can also be inherited if a Symbol is used to initialize the IndexedBase: + + >>> I = symbols('I', integer=True) + >>> C_inherit = IndexedBase(I) + >>> C_explicit = IndexedBase('I', integer=True) + >>> C_inherit == C_explicit + True + """ + is_symbol = True + is_Atom = True + + @staticmethod + def _set_assumptions(obj, assumptions): + """Set assumptions on obj, making sure to apply consistent values.""" + tmp_asm_copy = assumptions.copy() + is_commutative = fuzzy_bool(assumptions.get('commutative', True)) + assumptions['commutative'] = is_commutative + obj._assumptions = StdFactKB(assumptions) + obj._assumptions._generator = tmp_asm_copy # Issue #8873 + + def __new__(cls, label, shape=None, *, offset=S.Zero, strides=None, **kw_args): + from sympy.matrices.matrixbase import MatrixBase + from sympy.tensor.array.ndim_array import NDimArray + + assumptions, kw_args = _filter_assumptions(kw_args) + if isinstance(label, str): + label = Symbol(label, **assumptions) + elif isinstance(label, Symbol): + assumptions = label._merge(assumptions) + elif isinstance(label, (MatrixBase, NDimArray)): + return label + elif isinstance(label, Iterable): + return _sympify(label) + else: + label = _sympify(label) + + if is_sequence(shape): + shape = Tuple(*shape) + elif shape is not None: + shape = Tuple(shape) + + if shape is not None: + obj = Expr.__new__(cls, label, shape) + else: + obj = Expr.__new__(cls, label) + obj._shape = shape + obj._offset = offset + obj._strides = strides + obj._name = str(label) + + IndexedBase._set_assumptions(obj, assumptions) + return obj + + @property + def name(self): + return self._name + + def _hashable_content(self): + return super()._hashable_content() + tuple(sorted(self.assumptions0.items())) + + @property + def assumptions0(self): + return {k: v for k, v in self._assumptions.items() if v is not None} + + def __getitem__(self, indices, **kw_args): + if is_sequence(indices): + # Special case needed because M[*my_tuple] is a syntax error. + if self.shape and len(self.shape) != len(indices): + raise IndexException("Rank mismatch.") + return Indexed(self, *indices, **kw_args) + else: + if self.shape and len(self.shape) != 1: + raise IndexException("Rank mismatch.") + return Indexed(self, indices, **kw_args) + + @property + def shape(self): + """Returns the shape of the ``IndexedBase`` object. + + Examples + ======== + + >>> from sympy import IndexedBase, Idx + >>> from sympy.abc import x, y + >>> IndexedBase('A', shape=(x, y)).shape + (x, y) + + Note: If the shape of the ``IndexedBase`` is specified, it will override + any shape information given by the indices. + + >>> A = IndexedBase('A', shape=(x, y)) + >>> B = IndexedBase('B') + >>> i = Idx('i', 2) + >>> j = Idx('j', 1) + >>> A[i, j].shape + (x, y) + >>> B[i, j].shape + (2, 1) + + """ + return self._shape + + @property + def strides(self): + """Returns the strided scheme for the ``IndexedBase`` object. + + Normally this is a tuple denoting the number of + steps to take in the respective dimension when traversing + an array. For code generation purposes strides='C' and + strides='F' can also be used. + + strides='C' would mean that code printer would unroll + in row-major order and 'F' means unroll in column major + order. + + """ + + return self._strides + + @property + def offset(self): + """Returns the offset for the ``IndexedBase`` object. + + This is the value added to the resulting index when the + 2D Indexed object is unrolled to a 1D form. Used in code + generation. + + Examples + ========== + >>> from sympy.printing import ccode + >>> from sympy.tensor import IndexedBase, Idx + >>> from sympy import symbols + >>> l, m, n, o = symbols('l m n o', integer=True) + >>> A = IndexedBase('A', strides=(l, m, n), offset=o) + >>> i, j, k = map(Idx, 'ijk') + >>> ccode(A[i, j, k]) + 'A[l*i + m*j + n*k + o]' + + """ + return self._offset + + @property + def label(self): + """Returns the label of the ``IndexedBase`` object. + + Examples + ======== + + >>> from sympy import IndexedBase + >>> from sympy.abc import x, y + >>> IndexedBase('A', shape=(x, y)).label + A + + """ + return self.args[0] + + def _sympystr(self, p): + return p.doprint(self.label) + + +class Idx(Expr): + """Represents an integer index as an ``Integer`` or integer expression. + + There are a number of ways to create an ``Idx`` object. The constructor + takes two arguments: + + ``label`` + An integer or a symbol that labels the index. + ``range`` + Optionally you can specify a range as either + + * ``Symbol`` or integer: This is interpreted as a dimension. Lower and + upper bounds are set to ``0`` and ``range - 1``, respectively. + * ``tuple``: The two elements are interpreted as the lower and upper + bounds of the range, respectively. + + Note: bounds of the range are assumed to be either integer or infinite (oo + and -oo are allowed to specify an unbounded range). If ``n`` is given as a + bound, then ``n.is_integer`` must not return false. + + For convenience, if the label is given as a string it is automatically + converted to an integer symbol. (Note: this conversion is not done for + range or dimension arguments.) + + Examples + ======== + + >>> from sympy import Idx, symbols, oo + >>> n, i, L, U = symbols('n i L U', integer=True) + + If a string is given for the label an integer ``Symbol`` is created and the + bounds are both ``None``: + + >>> idx = Idx('qwerty'); idx + qwerty + >>> idx.lower, idx.upper + (None, None) + + Both upper and lower bounds can be specified: + + >>> idx = Idx(i, (L, U)); idx + i + >>> idx.lower, idx.upper + (L, U) + + When only a single bound is given it is interpreted as the dimension + and the lower bound defaults to 0: + + >>> idx = Idx(i, n); idx.lower, idx.upper + (0, n - 1) + >>> idx = Idx(i, 4); idx.lower, idx.upper + (0, 3) + >>> idx = Idx(i, oo); idx.lower, idx.upper + (0, oo) + + """ + + is_integer = True + is_finite = True + is_real = True + is_symbol = True + is_Atom = True + _diff_wrt = True + + def __new__(cls, label, range=None, **kw_args): + + if isinstance(label, str): + label = Symbol(label, integer=True) + label, range = list(map(sympify, (label, range))) + + if label.is_Number: + if not label.is_integer: + raise TypeError("Index is not an integer number.") + return label + + if not label.is_integer: + raise TypeError("Idx object requires an integer label.") + + elif is_sequence(range): + if len(range) != 2: + raise ValueError(filldedent(""" + Idx range tuple must have length 2, but got %s""" % len(range))) + for bound in range: + if (bound.is_integer is False and bound is not S.Infinity + and bound is not S.NegativeInfinity): + raise TypeError("Idx object requires integer bounds.") + args = label, Tuple(*range) + elif isinstance(range, Expr): + if range is not S.Infinity and fuzzy_not(range.is_integer): + raise TypeError("Idx object requires an integer dimension.") + args = label, Tuple(0, range - 1) + elif range: + raise TypeError(filldedent(""" + The range must be an ordered iterable or + integer SymPy expression.""")) + else: + args = label, + + obj = Expr.__new__(cls, *args, **kw_args) + obj._assumptions["finite"] = True + obj._assumptions["real"] = True + return obj + + @property + def label(self): + """Returns the label (Integer or integer expression) of the Idx object. + + Examples + ======== + + >>> from sympy import Idx, Symbol + >>> x = Symbol('x', integer=True) + >>> Idx(x).label + x + >>> j = Symbol('j', integer=True) + >>> Idx(j).label + j + >>> Idx(j + 1).label + j + 1 + + """ + return self.args[0] + + @property + def lower(self): + """Returns the lower bound of the ``Idx``. + + Examples + ======== + + >>> from sympy import Idx + >>> Idx('j', 2).lower + 0 + >>> Idx('j', 5).lower + 0 + >>> Idx('j').lower is None + True + + """ + try: + return self.args[1][0] + except IndexError: + return + + @property + def upper(self): + """Returns the upper bound of the ``Idx``. + + Examples + ======== + + >>> from sympy import Idx + >>> Idx('j', 2).upper + 1 + >>> Idx('j', 5).upper + 4 + >>> Idx('j').upper is None + True + + """ + try: + return self.args[1][1] + except IndexError: + return + + def _sympystr(self, p): + return p.doprint(self.label) + + @property + def name(self): + return self.label.name if self.label.is_Symbol else str(self.label) + + @property + def free_symbols(self): + return {self} + + +@dispatch(Idx, Idx) +def _eval_is_ge(lhs, rhs): # noqa:F811 + + other_upper = rhs if rhs.upper is None else rhs.upper + other_lower = rhs if rhs.lower is None else rhs.lower + + if lhs.lower is not None and (lhs.lower >= other_upper) == True: + return True + if lhs.upper is not None and (lhs.upper < other_lower) == True: + return False + return None + + +@dispatch(Idx, Number) # type:ignore +def _eval_is_ge(lhs, rhs): # noqa:F811 + + other_upper = rhs + other_lower = rhs + + if lhs.lower is not None and (lhs.lower >= other_upper) == True: + return True + if lhs.upper is not None and (lhs.upper < other_lower) == True: + return False + return None + + +@dispatch(Number, Idx) # type:ignore +def _eval_is_ge(lhs, rhs): # noqa:F811 + + other_upper = lhs + other_lower = lhs + + if rhs.upper is not None and (rhs.upper <= other_lower) == True: + return True + if rhs.lower is not None and (rhs.lower > other_upper) == True: + return False + return None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/tensor.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/tensor.py new file mode 100644 index 0000000000000000000000000000000000000000..579e7c7a86c2a1f18ab889af32ce0053a729ff5f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/tensor.py @@ -0,0 +1,5265 @@ +""" +This module defines tensors with abstract index notation. + +The abstract index notation has been first formalized by Penrose. + +Tensor indices are formal objects, with a tensor type; there is no +notion of index range, it is only possible to assign the dimension, +used to trace the Kronecker delta; the dimension can be a Symbol. + +The Einstein summation convention is used. +The covariant indices are indicated with a minus sign in front of the index. + +For instance the tensor ``t = p(a)*A(b,c)*q(-c)`` has the index ``c`` +contracted. + +A tensor expression ``t`` can be called; called with its +indices in sorted order it is equal to itself: +in the above example ``t(a, b) == t``; +one can call ``t`` with different indices; ``t(c, d) == p(c)*A(d,a)*q(-a)``. + +The contracted indices are dummy indices, internally they have no name, +the indices being represented by a graph-like structure. + +Tensors are put in canonical form using ``canon_bp``, which uses +the Butler-Portugal algorithm for canonicalization using the monoterm +symmetries of the tensors. + +If there is a (anti)symmetric metric, the indices can be raised and +lowered when the tensor is put in canonical form. +""" + +from __future__ import annotations +from typing import Any +from functools import reduce +from math import prod + +from abc import abstractmethod, ABC +from collections import defaultdict +import operator +import itertools + +from sympy.core.numbers import (Integer, Rational) +from sympy.combinatorics import Permutation +from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, \ + bsgs_direct_product, canonicalize, riemann_bsgs +from sympy.core import Basic, Expr, sympify, Add, Mul, S +from sympy.core.cache import clear_cache +from sympy.core.containers import Tuple, Dict +from sympy.core.function import WildFunction +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Symbol, symbols, Wild +from sympy.core.sympify import CantSympify, _sympify +from sympy.core.operations import AssocOp +from sympy.external.gmpy import SYMPY_INTS +from sympy.matrices import eye +from sympy.utilities.exceptions import (sympy_deprecation_warning, + SymPyDeprecationWarning, + ignore_warnings) +from sympy.utilities.decorator import memoize_property, deprecated +from sympy.utilities.iterables import sift + + +def deprecate_data(): + sympy_deprecation_warning( + """ + The data attribute of TensorIndexType is deprecated. Use The + replace_with_arrays() method instead. + """, + deprecated_since_version="1.4", + active_deprecations_target="deprecated-tensorindextype-attrs", + stacklevel=4, + ) + +def deprecate_fun_eval(): + sympy_deprecation_warning( + """ + The Tensor.fun_eval() method is deprecated. Use + Tensor.substitute_indices() instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensor-fun-eval", + stacklevel=4, + ) + + +def deprecate_call(): + sympy_deprecation_warning( + """ + Calling a tensor like Tensor(*indices) is deprecated. Use + Tensor.substitute_indices() instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensor-fun-eval", + stacklevel=4, + ) + + +class _IndexStructure(CantSympify): + """ + This class handles the indices (free and dummy ones). It contains the + algorithms to manage the dummy indices replacements and contractions of + free indices under multiplications of tensor expressions, as well as stuff + related to canonicalization sorting, getting the permutation of the + expression and so on. It also includes tools to get the ``TensorIndex`` + objects corresponding to the given index structure. + """ + + def __init__(self, free, dum, index_types, indices, canon_bp=False): + self.free = free + self.dum = dum + self.index_types = index_types + self.indices = indices + self._ext_rank = len(self.free) + 2*len(self.dum) + self.dum.sort(key=lambda x: x[0]) + + @staticmethod + def from_indices(*indices): + """ + Create a new ``_IndexStructure`` object from a list of ``indices``. + + Explanation + =========== + + ``indices`` ``TensorIndex`` objects, the indices. Contractions are + detected upon construction. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, _IndexStructure + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> m0, m1, m2, m3 = tensor_indices('m0,m1,m2,m3', Lorentz) + >>> _IndexStructure.from_indices(m0, m1, -m1, m3) + _IndexStructure([(m0, 0), (m3, 3)], [(1, 2)], [Lorentz, Lorentz, Lorentz, Lorentz]) + """ + + free, dum = _IndexStructure._free_dum_from_indices(*indices) + index_types = [i.tensor_index_type for i in indices] + indices = _IndexStructure._replace_dummy_names(indices, free, dum) + return _IndexStructure(free, dum, index_types, indices) + + @staticmethod + def from_components_free_dum(components, free, dum): + index_types = [] + for component in components: + index_types.extend(component.index_types) + indices = _IndexStructure.generate_indices_from_free_dum_index_types(free, dum, index_types) + return _IndexStructure(free, dum, index_types, indices) + + @staticmethod + def _free_dum_from_indices(*indices): + """ + Convert ``indices`` into ``free``, ``dum`` for single component tensor. + + Explanation + =========== + + ``free`` list of tuples ``(index, pos, 0)``, + where ``pos`` is the position of index in + the list of indices formed by the component tensors + + ``dum`` list of tuples ``(pos_contr, pos_cov, 0, 0)`` + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, \ + _IndexStructure + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> m0, m1, m2, m3 = tensor_indices('m0,m1,m2,m3', Lorentz) + >>> _IndexStructure._free_dum_from_indices(m0, m1, -m1, m3) + ([(m0, 0), (m3, 3)], [(1, 2)]) + """ + n = len(indices) + if n == 1: + return [(indices[0], 0)], [] + + # find the positions of the free indices and of the dummy indices + free = [True]*len(indices) + index_dict = {} + dum = [] + for i, index in enumerate(indices): + name = index.name + typ = index.tensor_index_type + contr = index.is_up + if (name, typ) in index_dict: + # found a pair of dummy indices + is_contr, pos = index_dict[(name, typ)] + # check consistency and update free + if is_contr: + if contr: + raise ValueError('two equal contravariant indices in slots %d and %d' %(pos, i)) + else: + free[pos] = False + free[i] = False + else: + if contr: + free[pos] = False + free[i] = False + else: + raise ValueError('two equal covariant indices in slots %d and %d' %(pos, i)) + if contr: + dum.append((i, pos)) + else: + dum.append((pos, i)) + else: + index_dict[(name, typ)] = index.is_up, i + + free = [(index, i) for i, index in enumerate(indices) if free[i]] + free.sort() + return free, dum + + def get_indices(self): + """ + Get a list of indices, creating new tensor indices to complete dummy indices. + """ + return self.indices[:] + + @staticmethod + def generate_indices_from_free_dum_index_types(free, dum, index_types): + indices = [None]*(len(free)+2*len(dum)) + for idx, pos in free: + indices[pos] = idx + + generate_dummy_name = _IndexStructure._get_generator_for_dummy_indices(free) + for pos1, pos2 in dum: + typ1 = index_types[pos1] + indname = generate_dummy_name(typ1) + indices[pos1] = TensorIndex(indname, typ1, True) + indices[pos2] = TensorIndex(indname, typ1, False) + + return _IndexStructure._replace_dummy_names(indices, free, dum) + + @staticmethod + def _get_generator_for_dummy_indices(free): + cdt = defaultdict(int) + # if the free indices have names with dummy_name, start with an + # index higher than those for the dummy indices + # to avoid name collisions + for indx, ipos in free: + if indx.name.split('_')[0] == indx.tensor_index_type.dummy_name: + cdt[indx.tensor_index_type] = max(cdt[indx.tensor_index_type], int(indx.name.split('_')[1]) + 1) + + def dummy_name_gen(tensor_index_type): + nd = str(cdt[tensor_index_type]) + cdt[tensor_index_type] += 1 + return tensor_index_type.dummy_name + '_' + nd + + return dummy_name_gen + + @staticmethod + def _replace_dummy_names(indices, free, dum): + dum.sort(key=lambda x: x[0]) + new_indices = list(indices) + assert len(indices) == len(free) + 2*len(dum) + generate_dummy_name = _IndexStructure._get_generator_for_dummy_indices(free) + for ipos1, ipos2 in dum: + typ1 = new_indices[ipos1].tensor_index_type + indname = generate_dummy_name(typ1) + new_indices[ipos1] = TensorIndex(indname, typ1, True) + new_indices[ipos2] = TensorIndex(indname, typ1, False) + return new_indices + + def get_free_indices(self) -> list[TensorIndex]: + """ + Get a list of free indices. + """ + # get sorted indices according to their position: + free = sorted(self.free, key=lambda x: x[1]) + return [i[0] for i in free] + + def __str__(self): + return "_IndexStructure({}, {}, {})".format(self.free, self.dum, self.index_types) + + def __repr__(self): + return self.__str__() + + def _get_sorted_free_indices_for_canon(self): + sorted_free = self.free[:] + sorted_free.sort(key=lambda x: x[0]) + return sorted_free + + def _get_sorted_dum_indices_for_canon(self): + return sorted(self.dum, key=lambda x: x[0]) + + def _get_lexicographically_sorted_index_types(self): + permutation = self.indices_canon_args()[0] + index_types = [None]*self._ext_rank + for i, it in enumerate(self.index_types): + index_types[permutation(i)] = it + return index_types + + def _get_lexicographically_sorted_indices(self): + permutation = self.indices_canon_args()[0] + indices = [None]*self._ext_rank + for i, it in enumerate(self.indices): + indices[permutation(i)] = it + return indices + + def perm2tensor(self, g, is_canon_bp=False): + """ + Returns a ``_IndexStructure`` instance corresponding to the permutation ``g``. + + Explanation + =========== + + ``g`` permutation corresponding to the tensor in the representation + used in canonicalization + + ``is_canon_bp`` if True, then ``g`` is the permutation + corresponding to the canonical form of the tensor + """ + sorted_free = [i[0] for i in self._get_sorted_free_indices_for_canon()] + lex_index_types = self._get_lexicographically_sorted_index_types() + lex_indices = self._get_lexicographically_sorted_indices() + nfree = len(sorted_free) + rank = self._ext_rank + dum = [[None]*2 for i in range((rank - nfree)//2)] + free = [] + + index_types = [None]*rank + indices = [None]*rank + for i in range(rank): + gi = g[i] + index_types[i] = lex_index_types[gi] + indices[i] = lex_indices[gi] + if gi < nfree: + ind = sorted_free[gi] + assert index_types[i] == sorted_free[gi].tensor_index_type + free.append((ind, i)) + else: + j = gi - nfree + idum, cov = divmod(j, 2) + if cov: + dum[idum][1] = i + else: + dum[idum][0] = i + dum = [tuple(x) for x in dum] + + return _IndexStructure(free, dum, index_types, indices) + + def indices_canon_args(self): + """ + Returns ``(g, dummies, msym, v)``, the entries of ``canonicalize`` + + See ``canonicalize`` in ``tensor_can.py`` in combinatorics module. + """ + # to be called after sorted_components + from sympy.combinatorics.permutations import _af_new + n = self._ext_rank + g = [None]*n + [n, n+1] + + # Converts the symmetry of the metric into msym from .canonicalize() + # method in the combinatorics module + def metric_symmetry_to_msym(metric): + if metric is None: + return None + sym = metric.symmetry + if sym == TensorSymmetry.fully_symmetric(2): + return 0 + if sym == TensorSymmetry.fully_symmetric(-2): + return 1 + return None + + # ordered indices: first the free indices, ordered by types + # then the dummy indices, ordered by types and contravariant before + # covariant + # g[position in tensor] = position in ordered indices + for i, (indx, ipos) in enumerate(self._get_sorted_free_indices_for_canon()): + g[ipos] = i + pos = len(self.free) + j = len(self.free) + dummies = [] + prev = None + a = [] + msym = [] + for ipos1, ipos2 in self._get_sorted_dum_indices_for_canon(): + g[ipos1] = j + g[ipos2] = j + 1 + j += 2 + typ = self.index_types[ipos1] + if typ != prev: + if a: + dummies.append(a) + a = [pos, pos + 1] + prev = typ + msym.append(metric_symmetry_to_msym(typ.metric)) + else: + a.extend([pos, pos + 1]) + pos += 2 + if a: + dummies.append(a) + + return _af_new(g), dummies, msym + + +def components_canon_args(components): + numtyp = [] + prev = None + for t in components: + if t == prev: + numtyp[-1][1] += 1 + else: + prev = t + numtyp.append([prev, 1]) + v = [] + for h, n in numtyp: + if h.comm in (0, 1): + comm = h.comm + else: + comm = TensorManager.get_comm(h.comm, h.comm) + v.append((h.symmetry.base, h.symmetry.generators, n, comm)) + return v + + +class _TensorDataLazyEvaluator(CantSympify): + """ + EXPERIMENTAL: do not rely on this class, it may change without deprecation + warnings in future versions of SymPy. + + Explanation + =========== + + This object contains the logic to associate components data to a tensor + expression. Components data are set via the ``.data`` property of tensor + expressions, is stored inside this class as a mapping between the tensor + expression and the ``ndarray``. + + Computations are executed lazily: whereas the tensor expressions can have + contractions, tensor products, and additions, components data are not + computed until they are accessed by reading the ``.data`` property + associated to the tensor expression. + """ + _substitutions_dict: dict[Any, Any] = {} + _substitutions_dict_tensmul: dict[Any, Any] = {} + + def __getitem__(self, key): + dat = self._get(key) + if dat is None: + return None + + from .array import NDimArray + if not isinstance(dat, NDimArray): + return dat + + if dat.rank() == 0: + return dat[()] + elif dat.rank() == 1 and len(dat) == 1: + return dat[0] + return dat + + def _get(self, key): + """ + Retrieve ``data`` associated with ``key``. + + Explanation + =========== + + This algorithm looks into ``self._substitutions_dict`` for all + ``TensorHead`` in the ``TensExpr`` (or just ``TensorHead`` if key is a + TensorHead instance). It reconstructs the components data that the + tensor expression should have by performing on components data the + operations that correspond to the abstract tensor operations applied. + + Metric tensor is handled in a different manner: it is pre-computed in + ``self._substitutions_dict_tensmul``. + """ + if key in self._substitutions_dict: + return self._substitutions_dict[key] + + if isinstance(key, TensorHead): + return None + + if isinstance(key, Tensor): + # special case to handle metrics. Metric tensors cannot be + # constructed through contraction by the metric, their + # components show if they are a matrix or its inverse. + signature = tuple([i.is_up for i in key.get_indices()]) + srch = (key.component,) + signature + if srch in self._substitutions_dict_tensmul: + return self._substitutions_dict_tensmul[srch] + array_list = [self.data_from_tensor(key)] + return self.data_contract_dum(array_list, key.dum, key.ext_rank) + + if isinstance(key, TensMul): + tensmul_args = key.args + if len(tensmul_args) == 1 and len(tensmul_args[0].components) == 1: + # special case to handle metrics. Metric tensors cannot be + # constructed through contraction by the metric, their + # components show if they are a matrix or its inverse. + signature = tuple([i.is_up for i in tensmul_args[0].get_indices()]) + srch = (tensmul_args[0].components[0],) + signature + if srch in self._substitutions_dict_tensmul: + return self._substitutions_dict_tensmul[srch] + #data_list = [self.data_from_tensor(i) for i in tensmul_args if isinstance(i, TensExpr)] + data_list = [self.data_from_tensor(i) if isinstance(i, Tensor) else i.data for i in tensmul_args if isinstance(i, TensExpr)] + coeff = prod([i for i in tensmul_args if not isinstance(i, TensExpr)]) + if all(i is None for i in data_list): + return None + if any(i is None for i in data_list): + raise ValueError("Mixing tensors with associated components "\ + "data with tensors without components data") + data_result = self.data_contract_dum(data_list, key.dum, key.ext_rank) + return coeff*data_result + + if isinstance(key, TensAdd): + data_list = [] + free_args_list = [] + for arg in key.args: + if isinstance(arg, TensExpr): + data_list.append(arg.data) + free_args_list.append([x[0] for x in arg.free]) + else: + data_list.append(arg) + free_args_list.append([]) + if all(i is None for i in data_list): + return None + if any(i is None for i in data_list): + raise ValueError("Mixing tensors with associated components "\ + "data with tensors without components data") + + sum_list = [] + from .array import permutedims + for data, free_args in zip(data_list, free_args_list): + if len(free_args) < 2: + sum_list.append(data) + else: + free_args_pos = {y: x for x, y in enumerate(free_args)} + axes = [free_args_pos[arg] for arg in key.free_args] + sum_list.append(permutedims(data, axes)) + return reduce(lambda x, y: x+y, sum_list) + + return None + + @staticmethod + def data_contract_dum(ndarray_list, dum, ext_rank): + from .array import tensorproduct, tensorcontraction, MutableDenseNDimArray + arrays = list(map(MutableDenseNDimArray, ndarray_list)) + prodarr = tensorproduct(*arrays) + return tensorcontraction(prodarr, *dum) + + def data_tensorhead_from_tensmul(self, data, tensmul, tensorhead): + """ + This method is used when assigning components data to a ``TensMul`` + object, it converts components data to a fully contravariant ndarray, + which is then stored according to the ``TensorHead`` key. + """ + if data is None: + return None + + return self._correct_signature_from_indices( + data, + tensmul.get_indices(), + tensmul.free, + tensmul.dum, + True) + + def data_from_tensor(self, tensor): + """ + This method corrects the components data to the right signature + (covariant/contravariant) using the metric associated with each + ``TensorIndexType``. + """ + tensorhead = tensor.component + + if tensorhead.data is None: + return None + + return self._correct_signature_from_indices( + tensorhead.data, + tensor.get_indices(), + tensor.free, + tensor.dum) + + def _assign_data_to_tensor_expr(self, key, data): + if isinstance(key, TensAdd): + raise ValueError('cannot assign data to TensAdd') + # here it is assumed that `key` is a `TensMul` instance. + if len(key.components) != 1: + raise ValueError('cannot assign data to TensMul with multiple components') + tensorhead = key.components[0] + newdata = self.data_tensorhead_from_tensmul(data, key, tensorhead) + return tensorhead, newdata + + def _check_permutations_on_data(self, tens, data): + from .array import permutedims + from .array.arrayop import Flatten + + if isinstance(tens, TensorHead): + rank = tens.rank + generators = tens.symmetry.generators + elif isinstance(tens, Tensor): + rank = tens.rank + generators = tens.components[0].symmetry.generators + elif isinstance(tens, TensorIndexType): + rank = tens.metric.rank + generators = tens.metric.symmetry.generators + + # Every generator is a permutation, check that by permuting the array + # by that permutation, the array will be the same, except for a + # possible sign change if the permutation admits it. + for gener in generators: + sign_change = +1 if (gener(rank) == rank) else -1 + data_swapped = data + last_data = data + permute_axes = list(map(gener, range(rank))) + # the order of a permutation is the number of times to get the + # identity by applying that permutation. + for i in range(gener.order()-1): + data_swapped = permutedims(data_swapped, permute_axes) + # if any value in the difference array is non-zero, raise an error: + if any(Flatten(last_data - sign_change*data_swapped)): + raise ValueError("Component data symmetry structure error") + last_data = data_swapped + + def __setitem__(self, key, value): + """ + Set the components data of a tensor object/expression. + + Explanation + =========== + + Components data are transformed to the all-contravariant form and stored + with the corresponding ``TensorHead`` object. If a ``TensorHead`` object + cannot be uniquely identified, it will raise an error. + """ + data = _TensorDataLazyEvaluator.parse_data(value) + self._check_permutations_on_data(key, data) + + # TensorHead and TensorIndexType can be assigned data directly, while + # TensMul must first convert data to a fully contravariant form, and + # assign it to its corresponding TensorHead single component. + if not isinstance(key, (TensorHead, TensorIndexType)): + key, data = self._assign_data_to_tensor_expr(key, data) + + if isinstance(key, TensorHead): + for dim, indextype in zip(data.shape, key.index_types): + if indextype.data is None: + raise ValueError("index type {} has no components data"\ + " associated (needed to raise/lower index)".format(indextype)) + if not indextype.dim.is_number: + continue + if dim != indextype.dim: + raise ValueError("wrong dimension of ndarray") + self._substitutions_dict[key] = data + + def __delitem__(self, key): + del self._substitutions_dict[key] + + def __contains__(self, key): + return key in self._substitutions_dict + + def add_metric_data(self, metric, data): + """ + Assign data to the ``metric`` tensor. The metric tensor behaves in an + anomalous way when raising and lowering indices. + + Explanation + =========== + + A fully covariant metric is the inverse transpose of the fully + contravariant metric (it is meant matrix inverse). If the metric is + symmetric, the transpose is not necessary and mixed + covariant/contravariant metrics are Kronecker deltas. + """ + # hard assignment, data should not be added to `TensorHead` for metric: + # the problem with `TensorHead` is that the metric is anomalous, i.e. + # raising and lowering the index means considering the metric or its + # inverse, this is not the case for other tensors. + self._substitutions_dict_tensmul[metric, True, True] = data + inverse_transpose = self.inverse_transpose_matrix(data) + # in symmetric spaces, the transpose is the same as the original matrix, + # the full covariant metric tensor is the inverse transpose, so this + # code will be able to handle non-symmetric metrics. + self._substitutions_dict_tensmul[metric, False, False] = inverse_transpose + # now mixed cases, these are identical to the unit matrix if the metric + # is symmetric. + m = data.tomatrix() + invt = inverse_transpose.tomatrix() + self._substitutions_dict_tensmul[metric, True, False] = m * invt + self._substitutions_dict_tensmul[metric, False, True] = invt * m + + @staticmethod + def _flip_index_by_metric(data, metric, pos): + from .array import tensorproduct, tensorcontraction + + mdim = metric.rank() + ddim = data.rank() + + if pos == 0: + data = tensorcontraction( + tensorproduct( + metric, + data + ), + (1, mdim+pos) + ) + else: + data = tensorcontraction( + tensorproduct( + data, + metric + ), + (pos, ddim) + ) + return data + + @staticmethod + def inverse_matrix(ndarray): + m = ndarray.tomatrix().inv() + return _TensorDataLazyEvaluator.parse_data(m) + + @staticmethod + def inverse_transpose_matrix(ndarray): + m = ndarray.tomatrix().inv().T + return _TensorDataLazyEvaluator.parse_data(m) + + @staticmethod + def _correct_signature_from_indices(data, indices, free, dum, inverse=False): + """ + Utility function to correct the values inside the components data + ndarray according to whether indices are covariant or contravariant. + + It uses the metric matrix to lower values of covariant indices. + """ + # change the ndarray values according covariantness/contravariantness of the indices + # use the metric + for i, indx in enumerate(indices): + if not indx.is_up and not inverse: + data = _TensorDataLazyEvaluator._flip_index_by_metric(data, indx.tensor_index_type.data, i) + elif not indx.is_up and inverse: + data = _TensorDataLazyEvaluator._flip_index_by_metric( + data, + _TensorDataLazyEvaluator.inverse_matrix(indx.tensor_index_type.data), + i + ) + return data + + @staticmethod + def _sort_data_axes(old, new): + from .array import permutedims + + new_data = old.data.copy() + + old_free = [i[0] for i in old.free] + new_free = [i[0] for i in new.free] + + for i in range(len(new_free)): + for j in range(i, len(old_free)): + if old_free[j] == new_free[i]: + old_free[i], old_free[j] = old_free[j], old_free[i] + new_data = permutedims(new_data, (i, j)) + break + return new_data + + @staticmethod + def add_rearrange_tensmul_parts(new_tensmul, old_tensmul): + def sorted_compo(): + return _TensorDataLazyEvaluator._sort_data_axes(old_tensmul, new_tensmul) + + _TensorDataLazyEvaluator._substitutions_dict[new_tensmul] = sorted_compo() + + @staticmethod + def parse_data(data): + """ + Transform ``data`` to array. The parameter ``data`` may + contain data in various formats, e.g. nested lists, SymPy ``Matrix``, + and so on. + + Examples + ======== + + >>> from sympy.tensor.tensor import _TensorDataLazyEvaluator + >>> _TensorDataLazyEvaluator.parse_data([1, 3, -6, 12]) + [1, 3, -6, 12] + + >>> _TensorDataLazyEvaluator.parse_data([[1, 2], [4, 7]]) + [[1, 2], [4, 7]] + """ + from .array import MutableDenseNDimArray + + if not isinstance(data, MutableDenseNDimArray): + if len(data) == 2 and hasattr(data[0], '__call__'): + data = MutableDenseNDimArray(data[0], data[1]) + else: + data = MutableDenseNDimArray(data) + return data + +_tensor_data_substitution_dict = _TensorDataLazyEvaluator() + + +class _TensorManager: + """ + Class to manage tensor properties. + + Notes + ===== + + Tensors belong to tensor commutation groups; each group has a label + ``comm``; there are predefined labels: + + ``0`` tensors commuting with any other tensor + + ``1`` tensors anticommuting among themselves + + ``2`` tensors not commuting, apart with those with ``comm=0`` + + Other groups can be defined using ``set_comm``; tensors in those + groups commute with those with ``comm=0``; by default they + do not commute with any other group. + """ + def __init__(self): + self._comm_init() + + def _comm_init(self): + self._comm = [{} for i in range(3)] + for i in range(3): + self._comm[0][i] = 0 + self._comm[i][0] = 0 + self._comm[1][1] = 1 + self._comm[2][1] = None + self._comm[1][2] = None + self._comm_symbols2i = {0:0, 1:1, 2:2} + self._comm_i2symbol = {0:0, 1:1, 2:2} + + @property + def comm(self): + return self._comm + + def comm_symbols2i(self, i): + """ + Get the commutation group number corresponding to ``i``. + + ``i`` can be a symbol or a number or a string. + + If ``i`` is not already defined its commutation group number + is set. + """ + if i not in self._comm_symbols2i: + n = len(self._comm) + self._comm.append({}) + self._comm[n][0] = 0 + self._comm[0][n] = 0 + self._comm_symbols2i[i] = n + self._comm_i2symbol[n] = i + return n + return self._comm_symbols2i[i] + + def comm_i2symbol(self, i): + """ + Returns the symbol corresponding to the commutation group number. + """ + return self._comm_i2symbol[i] + + def set_comm(self, i, j, c): + """ + Set the commutation parameter ``c`` for commutation groups ``i, j``. + + Parameters + ========== + + i, j : symbols representing commutation groups + + c : group commutation number + + Notes + ===== + + ``i, j`` can be symbols, strings or numbers, + apart from ``0, 1`` and ``2`` which are reserved respectively + for commuting, anticommuting tensors and tensors not commuting + with any other group apart with the commuting tensors. + For the remaining cases, use this method to set the commutation rules; + by default ``c=None``. + + The group commutation number ``c`` is assigned in correspondence + to the group commutation symbols; it can be + + 0 commuting + + 1 anticommuting + + None no commutation property + + Examples + ======== + + ``G`` and ``GH`` do not commute with themselves and commute with + each other; A is commuting. + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, TensorManager, TensorSymmetry + >>> Lorentz = TensorIndexType('Lorentz') + >>> i0,i1,i2,i3,i4 = tensor_indices('i0:5', Lorentz) + >>> A = TensorHead('A', [Lorentz]) + >>> G = TensorHead('G', [Lorentz], TensorSymmetry.no_symmetry(1), 'Gcomm') + >>> GH = TensorHead('GH', [Lorentz], TensorSymmetry.no_symmetry(1), 'GHcomm') + >>> TensorManager.set_comm('Gcomm', 'GHcomm', 0) + >>> (GH(i1)*G(i0)).canon_bp() + G(i0)*GH(i1) + >>> (G(i1)*G(i0)).canon_bp() + G(i1)*G(i0) + >>> (G(i1)*A(i0)).canon_bp() + A(i0)*G(i1) + """ + if c not in (0, 1, None): + raise ValueError('`c` can assume only the values 0, 1 or None') + + i = sympify(i) + j = sympify(j) + + if i not in self._comm_symbols2i: + n = len(self._comm) + self._comm.append({}) + self._comm[n][0] = 0 + self._comm[0][n] = 0 + self._comm_symbols2i[i] = n + self._comm_i2symbol[n] = i + if j not in self._comm_symbols2i: + n = len(self._comm) + self._comm.append({}) + self._comm[0][n] = 0 + self._comm[n][0] = 0 + self._comm_symbols2i[j] = n + self._comm_i2symbol[n] = j + ni = self._comm_symbols2i[i] + nj = self._comm_symbols2i[j] + self._comm[ni][nj] = c + self._comm[nj][ni] = c + + """ + Cached sympy functions (e.g. expand) may have cached the results of + expressions involving tensors, but those results may not be valid after + changing the commutation properties. To stay on the safe side, we clear + the cache of all functions. + """ + clear_cache() + + def set_comms(self, *args): + """ + Set the commutation group numbers ``c`` for symbols ``i, j``. + + Parameters + ========== + + args : sequence of ``(i, j, c)`` + """ + for i, j, c in args: + self.set_comm(i, j, c) + + def get_comm(self, i, j): + """ + Return the commutation parameter for commutation group numbers ``i, j`` + + see ``_TensorManager.set_comm`` + """ + return self._comm[i].get(j, 0 if i == 0 or j == 0 else None) + + def clear(self): + """ + Clear the TensorManager. + """ + self._comm_init() + + +TensorManager = _TensorManager() + + +class TensorIndexType(Basic): + """ + A TensorIndexType is characterized by its name and its metric. + + Parameters + ========== + + name : name of the tensor type + dummy_name : name of the head of dummy indices + dim : dimension, it can be a symbol or an integer or ``None`` + eps_dim : dimension of the epsilon tensor + metric_symmetry : integer that denotes metric symmetry or ``None`` for no metric + metric_name : string with the name of the metric tensor + + Attributes + ========== + + ``metric`` : the metric tensor + ``delta`` : ``Kronecker delta`` + ``epsilon`` : the ``Levi-Civita epsilon`` tensor + ``data`` : (deprecated) a property to add ``ndarray`` values, to work in a specified basis. + + Notes + ===== + + The possible values of the ``metric_symmetry`` parameter are: + + ``1`` : metric tensor is fully symmetric + ``0`` : metric tensor possesses no index symmetry + ``-1`` : metric tensor is fully antisymmetric + ``None``: there is no metric tensor (metric equals to ``None``) + + The metric is assumed to be symmetric by default. It can also be set + to a custom tensor by the ``.set_metric()`` method. + + If there is a metric the metric is used to raise and lower indices. + + In the case of non-symmetric metric, the following raising and + lowering conventions will be adopted: + + ``psi(a) = g(a, b)*psi(-b); chi(-a) = chi(b)*g(-b, -a)`` + + From these it is easy to find: + + ``g(-a, b) = delta(-a, b)`` + + where ``delta(-a, b) = delta(b, -a)`` is the ``Kronecker delta`` + (see ``TensorIndex`` for the conventions on indices). + For antisymmetric metrics there is also the following equality: + + ``g(a, -b) = -delta(a, -b)`` + + If there is no metric it is not possible to raise or lower indices; + e.g. the index of the defining representation of ``SU(N)`` + is 'covariant' and the conjugate representation is + 'contravariant'; for ``N > 2`` they are linearly independent. + + ``eps_dim`` is by default equal to ``dim``, if the latter is an integer; + else it can be assigned (for use in naive dimensional regularization); + if ``eps_dim`` is not an integer ``epsilon`` is ``None``. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> Lorentz.metric + metric(Lorentz,Lorentz) + """ + + def __new__(cls, name, dummy_name=None, dim=None, eps_dim=None, + metric_symmetry=1, metric_name='metric', **kwargs): + if 'dummy_fmt' in kwargs: + dummy_fmt = kwargs['dummy_fmt'] + sympy_deprecation_warning( + f""" + The dummy_fmt keyword to TensorIndexType is deprecated. Use + dummy_name={dummy_fmt} instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensorindextype-dummy-fmt", + ) + dummy_name = dummy_fmt + + if isinstance(name, str): + name = Symbol(name) + + if dummy_name is None: + dummy_name = str(name)[0] + if isinstance(dummy_name, str): + dummy_name = Symbol(dummy_name) + + if dim is None: + dim = Symbol("dim_" + dummy_name.name) + else: + dim = sympify(dim) + + if eps_dim is None: + eps_dim = dim + else: + eps_dim = sympify(eps_dim) + + metric_symmetry = sympify(metric_symmetry) + + if isinstance(metric_name, str): + metric_name = Symbol(metric_name) + + if 'metric' in kwargs: + SymPyDeprecationWarning( + """ + The 'metric' keyword argument to TensorIndexType is + deprecated. Use the 'metric_symmetry' keyword argument or the + TensorIndexType.set_metric() method instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensorindextype-metric", + ) + metric = kwargs.get('metric') + if metric is not None: + if metric in (True, False, 0, 1): + metric_name = 'metric' + #metric_antisym = metric + else: + metric_name = metric.name + #metric_antisym = metric.antisym + + if metric: + metric_symmetry = -1 + else: + metric_symmetry = 1 + + obj = Basic.__new__(cls, name, dummy_name, dim, eps_dim, + metric_symmetry, metric_name) + + obj._autogenerated = [] + return obj + + @property + def name(self): + return self.args[0].name + + @property + def dummy_name(self): + return self.args[1].name + + @property + def dim(self): + return self.args[2] + + @property + def eps_dim(self): + return self.args[3] + + @memoize_property + def metric(self): + metric_symmetry = self.args[4] + metric_name = self.args[5] + if metric_symmetry is None: + return None + + if metric_symmetry == 0: + symmetry = TensorSymmetry.no_symmetry(2) + elif metric_symmetry == 1: + symmetry = TensorSymmetry.fully_symmetric(2) + elif metric_symmetry == -1: + symmetry = TensorSymmetry.fully_symmetric(-2) + + return TensorHead(metric_name, [self]*2, symmetry) + + @memoize_property + def delta(self): + return TensorHead('KD', [self]*2, TensorSymmetry.fully_symmetric(2)) + + @memoize_property + def epsilon(self): + if not isinstance(self.eps_dim, (SYMPY_INTS, Integer)): + return None + symmetry = TensorSymmetry.fully_symmetric(-self.eps_dim) + return TensorHead('Eps', [self]*self.eps_dim, symmetry) + + def set_metric(self, tensor): + self._metric = tensor + + def __lt__(self, other): + return self.name < other.name + + def __str__(self): + return self.name + + __repr__ = __str__ + + # Everything below this line is deprecated + + @property + def data(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return _tensor_data_substitution_dict[self] + + @data.setter + def data(self, data): + deprecate_data() + # This assignment is a bit controversial, should metric components be assigned + # to the metric only or also to the TensorIndexType object? The advantage here + # is the ability to assign a 1D array and transform it to a 2D diagonal array. + from .array import MutableDenseNDimArray + + data = _TensorDataLazyEvaluator.parse_data(data) + if data.rank() > 2: + raise ValueError("data have to be of rank 1 (diagonal metric) or 2.") + if data.rank() == 1: + if self.dim.is_number: + nda_dim = data.shape[0] + if nda_dim != self.dim: + raise ValueError("Dimension mismatch") + + dim = data.shape[0] + newndarray = MutableDenseNDimArray.zeros(dim, dim) + for i, val in enumerate(data): + newndarray[i, i] = val + data = newndarray + dim1, dim2 = data.shape + if dim1 != dim2: + raise ValueError("Non-square matrix tensor.") + if self.dim.is_number: + if self.dim != dim1: + raise ValueError("Dimension mismatch") + _tensor_data_substitution_dict[self] = data + _tensor_data_substitution_dict.add_metric_data(self.metric, data) + with ignore_warnings(SymPyDeprecationWarning): + delta = self.get_kronecker_delta() + i1 = TensorIndex('i1', self) + i2 = TensorIndex('i2', self) + with ignore_warnings(SymPyDeprecationWarning): + delta(i1, -i2).data = _TensorDataLazyEvaluator.parse_data(eye(dim1)) + + @data.deleter + def data(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + if self in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[self] + if self.metric in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[self.metric] + + @deprecated( + """ + The TensorIndexType.get_kronecker_delta() method is deprecated. Use + the TensorIndexType.delta attribute instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensorindextype-methods", + ) + def get_kronecker_delta(self): + sym2 = TensorSymmetry(get_symmetric_group_sgs(2)) + delta = TensorHead('KD', [self]*2, sym2) + return delta + + @deprecated( + """ + The TensorIndexType.get_epsilon() method is deprecated. Use + the TensorIndexType.epsilon attribute instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensorindextype-methods", + ) + def get_epsilon(self): + if not isinstance(self._eps_dim, (SYMPY_INTS, Integer)): + return None + sym = TensorSymmetry(get_symmetric_group_sgs(self._eps_dim, 1)) + epsilon = TensorHead('Eps', [self]*self._eps_dim, sym) + return epsilon + + def _components_data_full_destroy(self): + """ + EXPERIMENTAL: do not rely on this API method. + + This destroys components data associated to the ``TensorIndexType``, if + any, specifically: + + * metric tensor data + * Kronecker tensor data + """ + if self in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[self] + + def delete_tensmul_data(key): + if key in _tensor_data_substitution_dict._substitutions_dict_tensmul: + del _tensor_data_substitution_dict._substitutions_dict_tensmul[key] + + # delete metric data: + delete_tensmul_data((self.metric, True, True)) + delete_tensmul_data((self.metric, True, False)) + delete_tensmul_data((self.metric, False, True)) + delete_tensmul_data((self.metric, False, False)) + + # delete delta tensor data: + delta = self.get_kronecker_delta() + if delta in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[delta] + + +class TensorIndex(Basic): + """ + Represents a tensor index + + Parameters + ========== + + name : name of the index, or ``True`` if you want it to be automatically assigned + tensor_index_type : ``TensorIndexType`` of the index + is_up : flag for contravariant index (is_up=True by default) + + Attributes + ========== + + ``name`` + ``tensor_index_type`` + ``is_up`` + + Notes + ===== + + Tensor indices are contracted with the Einstein summation convention. + + An index can be in contravariant or in covariant form; in the latter + case it is represented prepending a ``-`` to the index name. Adding + ``-`` to a covariant (is_up=False) index makes it contravariant. + + Dummy indices have a name with head given by + ``tensor_inde_type.dummy_name`` with underscore and a number. + + Similar to ``symbols`` multiple contravariant indices can be created + at once using ``tensor_indices(s, typ)``, where ``s`` is a string + of names. + + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, TensorIndex, TensorHead, tensor_indices + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> mu = TensorIndex('mu', Lorentz, is_up=False) + >>> nu, rho = tensor_indices('nu, rho', Lorentz) + >>> A = TensorHead('A', [Lorentz, Lorentz]) + >>> A(mu, nu) + A(-mu, nu) + >>> A(-mu, -rho) + A(mu, -rho) + >>> A(mu, -mu) + A(-L_0, L_0) + """ + def __new__(cls, name, tensor_index_type, is_up=True): + if isinstance(name, str): + name_symbol = Symbol(name) + elif isinstance(name, Symbol): + name_symbol = name + elif name is True: + name = "_i{}".format(len(tensor_index_type._autogenerated)) + name_symbol = Symbol(name) + tensor_index_type._autogenerated.append(name_symbol) + else: + raise ValueError("invalid name") + + is_up = sympify(is_up) + return Basic.__new__(cls, name_symbol, tensor_index_type, is_up) + + @property + def name(self): + return self.args[0].name + + @property + def tensor_index_type(self): + return self.args[1] + + @property + def is_up(self): + return self.args[2] + + def _print(self): + s = self.name + if not self.is_up: + s = '-%s' % s + return s + + def __lt__(self, other): + return ((self.tensor_index_type, self.name) < + (other.tensor_index_type, other.name)) + + def __neg__(self): + t1 = TensorIndex(self.name, self.tensor_index_type, + (not self.is_up)) + return t1 + + +def tensor_indices(s, typ): + """ + Returns list of tensor indices given their names and their types. + + Parameters + ========== + + s : string of comma separated names of indices + + typ : ``TensorIndexType`` of the indices + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz) + """ + if isinstance(s, str): + a = [x.name for x in symbols(s, seq=True)] + else: + raise ValueError('expecting a string') + + tilist = [TensorIndex(i, typ) for i in a] + if len(tilist) == 1: + return tilist[0] + return tilist + + +class TensorSymmetry(Basic): + """ + Monoterm symmetry of a tensor (i.e. any symmetric or anti-symmetric + index permutation). For the relevant terminology see ``tensor_can.py`` + section of the combinatorics module. + + Parameters + ========== + + bsgs : tuple ``(base, sgs)`` BSGS of the symmetry of the tensor + + Attributes + ========== + + ``base`` : base of the BSGS + ``generators`` : generators of the BSGS + ``rank`` : rank of the tensor + + Notes + ===== + + A tensor can have an arbitrary monoterm symmetry provided by its BSGS. + Multiterm symmetries, like the cyclic symmetry of the Riemann tensor + (i.e., Bianchi identity), are not covered. See combinatorics module for + information on how to generate BSGS for a general index permutation group. + Simple symmetries can be generated using built-in methods. + + See Also + ======== + + sympy.combinatorics.tensor_can.get_symmetric_group_sgs + + Examples + ======== + + Define a symmetric tensor of rank 2 + + >>> from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, TensorHead + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> sym = TensorSymmetry(get_symmetric_group_sgs(2)) + >>> T = TensorHead('T', [Lorentz]*2, sym) + + Note, that the same can also be done using built-in TensorSymmetry methods + + >>> sym2 = TensorSymmetry.fully_symmetric(2) + >>> sym == sym2 + True + """ + def __new__(cls, *args, **kw_args): + if len(args) == 1: + base, generators = args[0] + elif len(args) == 2: + base, generators = args + else: + raise TypeError("bsgs required, either two separate parameters or one tuple") + + if not isinstance(base, Tuple): + base = Tuple(*base) + if not isinstance(generators, Tuple): + generators = Tuple(*generators) + + return Basic.__new__(cls, base, generators, **kw_args) + + @property + def base(self): + return self.args[0] + + @property + def generators(self): + return self.args[1] + + @property + def rank(self): + return self.generators[0].size - 2 + + @classmethod + def fully_symmetric(cls, rank): + """ + Returns a fully symmetric (antisymmetric if ``rank``<0) + TensorSymmetry object for ``abs(rank)`` indices. + """ + if rank > 0: + bsgs = get_symmetric_group_sgs(rank, False) + elif rank < 0: + bsgs = get_symmetric_group_sgs(-rank, True) + elif rank == 0: + bsgs = ([], [Permutation(1)]) + return TensorSymmetry(bsgs) + + @classmethod + def direct_product(cls, *args): + """ + Returns a TensorSymmetry object that is being a direct product of + fully (anti-)symmetric index permutation groups. + + Notes + ===== + + Some examples for different values of ``(*args)``: + ``(1)`` vector, equivalent to ``TensorSymmetry.fully_symmetric(1)`` + ``(2)`` tensor with 2 symmetric indices, equivalent to ``.fully_symmetric(2)`` + ``(-2)`` tensor with 2 antisymmetric indices, equivalent to ``.fully_symmetric(-2)`` + ``(2, -2)`` tensor with the first 2 indices commuting and the last 2 anticommuting + ``(1, 1, 1)`` tensor with 3 indices without any symmetry + """ + base, sgs = [], [Permutation(1)] + for arg in args: + if arg > 0: + bsgs2 = get_symmetric_group_sgs(arg, False) + elif arg < 0: + bsgs2 = get_symmetric_group_sgs(-arg, True) + else: + continue + base, sgs = bsgs_direct_product(base, sgs, *bsgs2) + + return TensorSymmetry(base, sgs) + + @classmethod + def riemann(cls): + """ + Returns a monotorem symmetry of the Riemann tensor + """ + return TensorSymmetry(riemann_bsgs) + + @classmethod + def no_symmetry(cls, rank): + """ + TensorSymmetry object for ``rank`` indices with no symmetry + """ + return TensorSymmetry([], [Permutation(rank+1)]) + + +@deprecated( + """ + The tensorsymmetry() function is deprecated. Use the TensorSymmetry + constructor instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensorsymmetry", +) +def tensorsymmetry(*args): + """ + Returns a ``TensorSymmetry`` object. This method is deprecated, use + ``TensorSymmetry.direct_product()`` or ``.riemann()`` instead. + + Explanation + =========== + + One can represent a tensor with any monoterm slot symmetry group + using a BSGS. + + ``args`` can be a BSGS + ``args[0]`` base + ``args[1]`` sgs + + Usually tensors are in (direct products of) representations + of the symmetric group; + ``args`` can be a list of lists representing the shapes of Young tableaux + + Notes + ===== + + For instance: + ``[[1]]`` vector + ``[[1]*n]`` symmetric tensor of rank ``n`` + ``[[n]]`` antisymmetric tensor of rank ``n`` + ``[[2, 2]]`` monoterm slot symmetry of the Riemann tensor + ``[[1],[1]]`` vector*vector + ``[[2],[1],[1]`` (antisymmetric tensor)*vector*vector + + Notice that with the shape ``[2, 2]`` we associate only the monoterm + symmetries of the Riemann tensor; this is an abuse of notation, + since the shape ``[2, 2]`` corresponds usually to the irreducible + representation characterized by the monoterm symmetries and by the + cyclic symmetry. + """ + from sympy.combinatorics import Permutation + + def tableau2bsgs(a): + if len(a) == 1: + # antisymmetric vector + n = a[0] + bsgs = get_symmetric_group_sgs(n, 1) + else: + if all(x == 1 for x in a): + # symmetric vector + n = len(a) + bsgs = get_symmetric_group_sgs(n) + elif a == [2, 2]: + bsgs = riemann_bsgs + else: + raise NotImplementedError + return bsgs + + if not args: + return TensorSymmetry(Tuple(), Tuple(Permutation(1))) + + if len(args) == 2 and isinstance(args[1][0], Permutation): + return TensorSymmetry(args) + base, sgs = tableau2bsgs(args[0]) + for a in args[1:]: + basex, sgsx = tableau2bsgs(a) + base, sgs = bsgs_direct_product(base, sgs, basex, sgsx) + return TensorSymmetry(Tuple(base, sgs)) + +@deprecated( + "TensorType is deprecated. Use tensor_heads() instead.", + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensortype", +) +class TensorType(Basic): + """ + Class of tensor types. Deprecated, use tensor_heads() instead. + + Parameters + ========== + + index_types : list of ``TensorIndexType`` of the tensor indices + symmetry : ``TensorSymmetry`` of the tensor + + Attributes + ========== + + ``index_types`` + ``symmetry`` + ``types`` : list of ``TensorIndexType`` without repetitions + """ + is_commutative = False + + def __new__(cls, index_types, symmetry, **kw_args): + assert symmetry.rank == len(index_types) + obj = Basic.__new__(cls, Tuple(*index_types), symmetry, **kw_args) + return obj + + @property + def index_types(self): + return self.args[0] + + @property + def symmetry(self): + return self.args[1] + + @property + def types(self): + return sorted(set(self.index_types), key=lambda x: x.name) + + def __str__(self): + return 'TensorType(%s)' % ([str(x) for x in self.index_types]) + + def __call__(self, s, comm=0): + """ + Return a TensorHead object or a list of TensorHead objects. + + Parameters + ========== + + s : name or string of names. + + comm : Commutation group. + + see ``_TensorManager.set_comm`` + """ + if isinstance(s, str): + names = [x.name for x in symbols(s, seq=True)] + else: + raise ValueError('expecting a string') + if len(names) == 1: + return TensorHead(names[0], self.index_types, self.symmetry, comm) + else: + return [TensorHead(name, self.index_types, self.symmetry, comm) for name in names] + + +@deprecated( + """ + The tensorhead() function is deprecated. Use tensor_heads() instead. + """, + deprecated_since_version="1.5", + active_deprecations_target="deprecated-tensorhead", +) +def tensorhead(name, typ, sym=None, comm=0): + """ + Function generating tensorhead(s). This method is deprecated, + use TensorHead constructor or tensor_heads() instead. + + Parameters + ========== + + name : name or sequence of names (as in ``symbols``) + + typ : index types + + sym : same as ``*args`` in ``tensorsymmetry`` + + comm : commutation group number + see ``_TensorManager.set_comm`` + """ + if sym is None: + sym = [[1] for i in range(len(typ))] + with ignore_warnings(SymPyDeprecationWarning): + sym = tensorsymmetry(*sym) + return TensorHead(name, typ, sym, comm) + + +class TensorHead(Basic): + """ + Tensor head of the tensor. + + Parameters + ========== + + name : name of the tensor + index_types : list of TensorIndexType + symmetry : TensorSymmetry of the tensor + comm : commutation group number + + Attributes + ========== + + ``name`` + ``index_types`` + ``rank`` : total number of indices + ``symmetry`` + ``comm`` : commutation group + + Notes + ===== + + Similar to ``symbols`` multiple TensorHeads can be created using + ``tensorhead(s, typ, sym=None, comm=0)`` function, where ``s`` + is the string of names and ``sym`` is the monoterm tensor symmetry + (see ``tensorsymmetry``). + + A ``TensorHead`` belongs to a commutation group, defined by a + symbol on number ``comm`` (see ``_TensorManager.set_comm``); + tensors in a commutation group have the same commutation properties; + by default ``comm`` is ``0``, the group of the commuting tensors. + + Examples + ======== + + Define a fully antisymmetric tensor of rank 2: + + >>> from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorSymmetry + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> asym2 = TensorSymmetry.fully_symmetric(-2) + >>> A = TensorHead('A', [Lorentz, Lorentz], asym2) + + Examples with ndarray values, the components data assigned to the + ``TensorHead`` object are assumed to be in a fully-contravariant + representation. In case it is necessary to assign components data which + represents the values of a non-fully covariant tensor, see the other + examples. + + >>> from sympy.tensor.tensor import tensor_indices + >>> from sympy import diag + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> i0, i1 = tensor_indices('i0:2', Lorentz) + + Specify a replacement dictionary to keep track of the arrays to use for + replacements in the tensorial expression. The ``TensorIndexType`` is + associated to the metric used for contractions (in fully covariant form): + + >>> repl = {Lorentz: diag(1, -1, -1, -1)} + + Let's see some examples of working with components with the electromagnetic + tensor: + + >>> from sympy import symbols + >>> Ex, Ey, Ez, Bx, By, Bz = symbols('E_x E_y E_z B_x B_y B_z') + >>> c = symbols('c', positive=True) + + Let's define `F`, an antisymmetric tensor: + + >>> F = TensorHead('F', [Lorentz, Lorentz], asym2) + + Let's update the dictionary to contain the matrix to use in the + replacements: + + >>> repl.update({F(-i0, -i1): [ + ... [0, Ex/c, Ey/c, Ez/c], + ... [-Ex/c, 0, -Bz, By], + ... [-Ey/c, Bz, 0, -Bx], + ... [-Ez/c, -By, Bx, 0]]}) + + Now it is possible to retrieve the contravariant form of the Electromagnetic + tensor: + + >>> F(i0, i1).replace_with_arrays(repl, [i0, i1]) + [[0, -E_x/c, -E_y/c, -E_z/c], [E_x/c, 0, -B_z, B_y], [E_y/c, B_z, 0, -B_x], [E_z/c, -B_y, B_x, 0]] + + and the mixed contravariant-covariant form: + + >>> F(i0, -i1).replace_with_arrays(repl, [i0, -i1]) + [[0, E_x/c, E_y/c, E_z/c], [E_x/c, 0, B_z, -B_y], [E_y/c, -B_z, 0, B_x], [E_z/c, B_y, -B_x, 0]] + + Energy-momentum of a particle may be represented as: + + >>> from sympy import symbols + >>> P = TensorHead('P', [Lorentz], TensorSymmetry.no_symmetry(1)) + >>> E, px, py, pz = symbols('E p_x p_y p_z', positive=True) + >>> repl.update({P(i0): [E, px, py, pz]}) + + The contravariant and covariant components are, respectively: + + >>> P(i0).replace_with_arrays(repl, [i0]) + [E, p_x, p_y, p_z] + >>> P(-i0).replace_with_arrays(repl, [-i0]) + [E, -p_x, -p_y, -p_z] + + The contraction of a 1-index tensor by itself: + + >>> expr = P(i0)*P(-i0) + >>> expr.replace_with_arrays(repl, []) + E**2 - p_x**2 - p_y**2 - p_z**2 + """ + is_commutative = False + + def __new__(cls, name, index_types, symmetry=None, comm=0): + if isinstance(name, str): + name_symbol = Symbol(name) + elif isinstance(name, Symbol): + name_symbol = name + else: + raise ValueError("invalid name") + + if symmetry is None: + symmetry = TensorSymmetry.no_symmetry(len(index_types)) + else: + assert symmetry.rank == len(index_types) + + obj = Basic.__new__(cls, name_symbol, Tuple(*index_types), symmetry, sympify(comm)) + return obj + + @property + def name(self): + return self.args[0].name + + @property + def index_types(self): + return list(self.args[1]) + + @property + def symmetry(self): + return self.args[2] + + @property + def comm(self): + return TensorManager.comm_symbols2i(self.args[3]) + + @property + def rank(self): + return len(self.index_types) + + def __lt__(self, other): + return (self.name, self.index_types) < (other.name, other.index_types) + + def commutes_with(self, other): + """ + Returns ``0`` if ``self`` and ``other`` commute, ``1`` if they anticommute. + + Returns ``None`` if ``self`` and ``other`` neither commute nor anticommute. + """ + r = TensorManager.get_comm(self.comm, other.comm) + return r + + def _print(self): + return '%s(%s)' %(self.name, ','.join([str(x) for x in self.index_types])) + + def __call__(self, *indices, **kw_args): + """ + Returns a tensor with indices. + + Explanation + =========== + + There is a special behavior in case of indices denoted by ``True``, + they are considered auto-matrix indices, their slots are automatically + filled, and confer to the tensor the behavior of a matrix or vector + upon multiplication with another tensor containing auto-matrix indices + of the same ``TensorIndexType``. This means indices get summed over the + same way as in matrix multiplication. For matrix behavior, define two + auto-matrix indices, for vector behavior define just one. + + Indices can also be strings, in which case the attribute + ``index_types`` is used to convert them to proper ``TensorIndex``. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorSymmetry, TensorHead + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> a, b = tensor_indices('a,b', Lorentz) + >>> A = TensorHead('A', [Lorentz]*2, TensorSymmetry.no_symmetry(2)) + >>> t = A(a, -b) + >>> t + A(a, -b) + + """ + + updated_indices = [] + for idx, typ in zip(indices, self.index_types): + if isinstance(idx, str): + idx = idx.strip().replace(" ", "") + if idx.startswith('-'): + updated_indices.append(TensorIndex(idx[1:], typ, + is_up=False)) + else: + updated_indices.append(TensorIndex(idx, typ)) + else: + updated_indices.append(idx) + + updated_indices += indices[len(updated_indices):] + + tensor = Tensor(self, updated_indices, **kw_args) + return tensor.doit() + + # Everything below this line is deprecated + + def __pow__(self, other): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + if self.data is None: + raise ValueError("No power on abstract tensors.") + from .array import tensorproduct, tensorcontraction + metrics = [_.data for _ in self.index_types] + + marray = self.data + marraydim = marray.rank() + for metric in metrics: + marray = tensorproduct(marray, metric, marray) + marray = tensorcontraction(marray, (0, marraydim), (marraydim+1, marraydim+2)) + + return marray ** (other * S.Half) + + @property + def data(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return _tensor_data_substitution_dict[self] + + @data.setter + def data(self, data): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + _tensor_data_substitution_dict[self] = data + + @data.deleter + def data(self): + deprecate_data() + if self in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[self] + + def __iter__(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return self.data.__iter__() + + def _components_data_full_destroy(self): + """ + EXPERIMENTAL: do not rely on this API method. + + Destroy components data associated to the ``TensorHead`` object, this + checks for attached components data, and destroys components data too. + """ + # do not garbage collect Kronecker tensor (it should be done by + # ``TensorIndexType`` garbage collection) + deprecate_data() + if self.name == "KD": + return + + # the data attached to a tensor must be deleted only by the TensorHead + # destructor. If the TensorHead is deleted, it means that there are no + # more instances of that tensor anywhere. + if self in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[self] + + +def tensor_heads(s, index_types, symmetry=None, comm=0): + """ + Returns a sequence of TensorHeads from a string `s` + """ + if isinstance(s, str): + names = [x.name for x in symbols(s, seq=True)] + else: + raise ValueError('expecting a string') + + thlist = [TensorHead(name, index_types, symmetry, comm) for name in names] + if len(thlist) == 1: + return thlist[0] + return thlist + + +class TensExpr(Expr, ABC): + """ + Abstract base class for tensor expressions + + Notes + ===== + + A tensor expression is an expression formed by tensors; + currently the sums of tensors are distributed. + + A ``TensExpr`` can be a ``TensAdd`` or a ``TensMul``. + + ``TensMul`` objects are formed by products of component tensors, + and include a coefficient, which is a SymPy expression. + + + In the internal representation contracted indices are represented + by ``(ipos1, ipos2, icomp1, icomp2)``, where ``icomp1`` is the position + of the component tensor with contravariant index, ``ipos1`` is the + slot which the index occupies in that component tensor. + + Contracted indices are therefore nameless in the internal representation. + """ + + _op_priority = 12.0 + is_commutative = False + + def __neg__(self): + return self*S.NegativeOne + + def __abs__(self): + raise NotImplementedError + + def __add__(self, other): + return TensAdd(self, other).doit(deep=False) + + def __radd__(self, other): + return TensAdd(other, self).doit(deep=False) + + def __sub__(self, other): + return TensAdd(self, -other).doit(deep=False) + + def __rsub__(self, other): + return TensAdd(other, -self).doit(deep=False) + + def __mul__(self, other): + """ + Multiply two tensors using Einstein summation convention. + + Explanation + =========== + + If the two tensors have an index in common, one contravariant + and the other covariant, in their product the indices are summed + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> g = Lorentz.metric + >>> p, q = tensor_heads('p,q', [Lorentz]) + >>> t1 = p(m0) + >>> t2 = q(-m0) + >>> t1*t2 + p(L_0)*q(-L_0) + """ + return TensMul(self, other).doit(deep=False) + + def __rmul__(self, other): + return TensMul(other, self).doit(deep=False) + + def __truediv__(self, other): + other = _sympify(other) + if isinstance(other, TensExpr): + raise ValueError('cannot divide by a tensor') + return TensMul(self, S.One/other).doit(deep=False) + + def __rtruediv__(self, other): + raise ValueError('cannot divide by a tensor') + + def __pow__(self, other): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + if self.data is None: + raise ValueError("No power without ndarray data.") + from .array import tensorproduct, tensorcontraction + free = self.free + marray = self.data + mdim = marray.rank() + for metric in free: + marray = tensorcontraction( + tensorproduct( + marray, + metric[0].tensor_index_type.data, + marray), + (0, mdim), (mdim+1, mdim+2) + ) + return marray ** (other * S.Half) + + def __rpow__(self, other): + raise NotImplementedError + + @property + @abstractmethod + def nocoeff(self): + raise NotImplementedError("abstract method") + + @property + @abstractmethod + def coeff(self): + raise NotImplementedError("abstract method") + + @abstractmethod + def get_indices(self): + raise NotImplementedError("abstract method") + + @abstractmethod + def get_free_indices(self) -> list[TensorIndex]: + raise NotImplementedError("abstract method") + + @abstractmethod + def _replace_indices(self, repl: dict[TensorIndex, TensorIndex]) -> TensExpr: + raise NotImplementedError("abstract method") + + def fun_eval(self, *index_tuples): + deprecate_fun_eval() + return self.substitute_indices(*index_tuples) + + def get_matrix(self): + """ + DEPRECATED: do not use. + + Returns ndarray components data as a matrix, if components data are + available and ndarray dimension does not exceed 2. + """ + from sympy.matrices.dense import Matrix + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + if 0 < self.rank <= 2: + rows = self.data.shape[0] + columns = self.data.shape[1] if self.rank == 2 else 1 + if self.rank == 2: + mat_list = [] * rows + for i in range(rows): + mat_list.append([]) + for j in range(columns): + mat_list[i].append(self[i, j]) + else: + mat_list = [None] * rows + for i in range(rows): + mat_list[i] = self[i] + return Matrix(mat_list) + else: + raise NotImplementedError( + "missing multidimensional reduction to matrix.") + + @staticmethod + def _get_indices_permutation(indices1, indices2): + return [indices1.index(i) for i in indices2] + + def _get_free_indices_set(self): + indset = set() + for arg in self.args: + if isinstance(arg, TensExpr): + indset.update(arg._get_free_indices_set()) + return indset + + def _get_dummy_indices_set(self): + indset = set() + for arg in self.args: + if isinstance(arg, TensExpr): + indset.update(arg._get_dummy_indices_set()) + return indset + + def _get_indices_set(self): + indset = set() + for arg in self.args: + if isinstance(arg, TensExpr): + indset.update(arg._get_indices_set()) + return indset + + @property + def _iterate_dummy_indices(self): + dummy_set = self._get_dummy_indices_set() + + def recursor(expr, pos): + if isinstance(expr, TensorIndex): + if expr in dummy_set: + yield (expr, pos) + elif isinstance(expr, (Tuple, TensExpr)): + for p, arg in enumerate(expr.args): + yield from recursor(arg, pos+(p,)) + + return recursor(self, ()) + + @property + def _iterate_free_indices(self): + free_set = self._get_free_indices_set() + + def recursor(expr, pos): + if isinstance(expr, TensorIndex): + if expr in free_set: + yield (expr, pos) + elif isinstance(expr, (Tuple, TensExpr)): + for p, arg in enumerate(expr.args): + yield from recursor(arg, pos+(p,)) + + return recursor(self, ()) + + @property + def _iterate_indices(self): + def recursor(expr, pos): + if isinstance(expr, TensorIndex): + yield (expr, pos) + elif isinstance(expr, (Tuple, TensExpr)): + for p, arg in enumerate(expr.args): + yield from recursor(arg, pos+(p,)) + + return recursor(self, ()) + + @staticmethod + def _contract_and_permute_with_metric(metric, array, pos, dim): + # TODO: add possibility of metric after (spinors) + from .array import tensorcontraction, tensorproduct, permutedims + + array = tensorcontraction(tensorproduct(metric, array), (1, 2+pos)) + permu = list(range(dim)) + permu[0], permu[pos] = permu[pos], permu[0] + return permutedims(array, permu) + + @staticmethod + def _match_indices_with_other_tensor(array, free_ind1, free_ind2, replacement_dict): + from .array import permutedims + + index_types1 = [i.tensor_index_type for i in free_ind1] + + # Check if variance of indices needs to be fixed: + pos2up = [] + pos2down = [] + free2remaining = free_ind2[:] + for pos1, index1 in enumerate(free_ind1): + if index1 in free2remaining: + pos2 = free2remaining.index(index1) + free2remaining[pos2] = None + continue + if -index1 in free2remaining: + pos2 = free2remaining.index(-index1) + free2remaining[pos2] = None + free_ind2[pos2] = index1 + if index1.is_up: + pos2up.append(pos2) + else: + pos2down.append(pos2) + else: + index2 = free2remaining[pos1] + if index2 is None: + raise ValueError("incompatible indices: %s and %s" % (free_ind1, free_ind2)) + free2remaining[pos1] = None + free_ind2[pos1] = index1 + if index1.is_up ^ index2.is_up: + if index1.is_up: + pos2up.append(pos1) + else: + pos2down.append(pos1) + + if len(set(free_ind1) & set(free_ind2)) < len(free_ind1): + raise ValueError("incompatible indices: %s and %s" % (free_ind1, free_ind2)) + + # Raise indices: + for pos in pos2up: + index_type_pos = index_types1[pos] + if index_type_pos not in replacement_dict: + raise ValueError("No metric provided to lower index") + metric = replacement_dict[index_type_pos] + metric_inverse = _TensorDataLazyEvaluator.inverse_matrix(metric) + array = TensExpr._contract_and_permute_with_metric(metric_inverse, array, pos, len(free_ind1)) + # Lower indices: + for pos in pos2down: + index_type_pos = index_types1[pos] + if index_type_pos not in replacement_dict: + raise ValueError("No metric provided to lower index") + metric = replacement_dict[index_type_pos] + array = TensExpr._contract_and_permute_with_metric(metric, array, pos, len(free_ind1)) + + if free_ind1: + permutation = TensExpr._get_indices_permutation(free_ind2, free_ind1) + array = permutedims(array, permutation) + + if hasattr(array, "rank") and array.rank() == 0: + array = array[()] + + return free_ind2, array + + def replace_with_arrays(self, replacement_dict, indices=None): + """ + Replace the tensorial expressions with arrays. The final array will + correspond to the N-dimensional array with indices arranged according + to ``indices``. + + Parameters + ========== + + replacement_dict + dictionary containing the replacement rules for tensors. + indices + the index order with respect to which the array is read. The + original index order will be used if no value is passed. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices + >>> from sympy.tensor.tensor import TensorHead + >>> from sympy import symbols, diag + + >>> L = TensorIndexType("L") + >>> i, j = tensor_indices("i j", L) + >>> A = TensorHead("A", [L]) + >>> A(i).replace_with_arrays({A(i): [1, 2]}, [i]) + [1, 2] + + Since 'indices' is optional, we can also call replace_with_arrays by + this way if no specific index order is needed: + + >>> A(i).replace_with_arrays({A(i): [1, 2]}) + [1, 2] + + >>> expr = A(i)*A(j) + >>> expr.replace_with_arrays({A(i): [1, 2]}) + [[1, 2], [2, 4]] + + For contractions, specify the metric of the ``TensorIndexType``, which + in this case is ``L``, in its covariant form: + + >>> expr = A(i)*A(-i) + >>> expr.replace_with_arrays({A(i): [1, 2], L: diag(1, -1)}) + -3 + + Symmetrization of an array: + + >>> H = TensorHead("H", [L, L]) + >>> a, b, c, d = symbols("a b c d") + >>> expr = H(i, j)/2 + H(j, i)/2 + >>> expr.replace_with_arrays({H(i, j): [[a, b], [c, d]]}) + [[a, b/2 + c/2], [b/2 + c/2, d]] + + Anti-symmetrization of an array: + + >>> expr = H(i, j)/2 - H(j, i)/2 + >>> repl = {H(i, j): [[a, b], [c, d]]} + >>> expr.replace_with_arrays(repl) + [[0, b/2 - c/2], [-b/2 + c/2, 0]] + + The same expression can be read as the transpose by inverting ``i`` and + ``j``: + + >>> expr.replace_with_arrays(repl, [j, i]) + [[0, -b/2 + c/2], [b/2 - c/2, 0]] + """ + from .array import Array + + indices = indices or [] + remap = {k.args[0] if k.is_up else -k.args[0]: k for k in self.get_free_indices()} + for i, index in enumerate(indices): + if isinstance(index, (Symbol, Mul)): + if index in remap: + indices[i] = remap[index] + else: + indices[i] = -remap[-index] + + replacement_dict = {tensor: Array(array) for tensor, array in replacement_dict.items()} + + # Check dimensions of replaced arrays: + for tensor, array in replacement_dict.items(): + if isinstance(tensor, TensorIndexType): + expected_shape = [tensor.dim for i in range(2)] + else: + expected_shape = [index_type.dim for index_type in tensor.index_types] + if len(expected_shape) != array.rank() or (not all(dim1 == dim2 if + dim1.is_number else True for dim1, dim2 in zip(expected_shape, + array.shape))): + raise ValueError("shapes for tensor %s expected to be %s, "\ + "replacement array shape is %s" % (tensor, expected_shape, + array.shape)) + + ret_indices, array = self._extract_data(replacement_dict) + + last_indices, array = self._match_indices_with_other_tensor(array, indices, ret_indices, replacement_dict) + return array + + def _check_add_Sum(self, expr, index_symbols): + from sympy.concrete.summations import Sum + indices = self.get_indices() + dum = self.dum + sum_indices = [ (index_symbols[i], 0, + indices[i].tensor_index_type.dim-1) for i, j in dum] + if sum_indices: + expr = Sum(expr, *sum_indices) + return expr + + def _expand_partial_derivative(self): + # simply delegate the _expand_partial_derivative() to + # its arguments to expand a possibly found PartialDerivative + return self.func(*[ + a._expand_partial_derivative() + if isinstance(a, TensExpr) else a + for a in self.args]) + + def _matches_simple(self, expr, repl_dict=None, old=False): + """ + Matches assuming there are no wild objects in self. + """ + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + if not isinstance(expr, TensExpr): + if len(self.get_free_indices()) > 0: + #self has indices, but expr does not. + return None + elif set(self.get_free_indices()) != set(expr.get_free_indices()): + #If there are no wilds and the free indices are not the same, they cannot match. + return None + + if canon_bp(self - expr) == S.Zero: + return repl_dict + else: + return None + + +class TensAdd(TensExpr, AssocOp): + """ + Sum of tensors. + + Parameters + ========== + + free_args : list of the free indices + + Attributes + ========== + + ``args`` : tuple of addends + ``rank`` : rank of the tensor + ``free_args`` : list of the free indices in sorted order + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_heads, tensor_indices + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> a, b = tensor_indices('a,b', Lorentz) + >>> p, q = tensor_heads('p,q', [Lorentz]) + >>> t = p(a) + q(a); t + p(a) + q(a) + + Examples with components data added to the tensor expression: + + >>> from sympy import symbols, diag + >>> x, y, z, t = symbols("x y z t") + >>> repl = {} + >>> repl[Lorentz] = diag(1, -1, -1, -1) + >>> repl[p(a)] = [1, 2, 3, 4] + >>> repl[q(a)] = [x, y, z, t] + + The following are: 2**2 - 3**2 - 2**2 - 7**2 ==> -58 + + >>> expr = p(a) + q(a) + >>> expr.replace_with_arrays(repl, [a]) + [x + 1, y + 2, z + 3, t + 4] + """ + + def __new__(cls, *args, **kw_args): + args = [_sympify(x) for x in args if x] + args = TensAdd._tensAdd_flatten(args) + args.sort(key=default_sort_key) + if not args: + return S.Zero + if len(args) == 1: + return args[0] + + return Basic.__new__(cls, *args, **kw_args) + + @property + def coeff(self): + return S.One + + @property + def nocoeff(self): + return self + + def get_free_indices(self) -> list[TensorIndex]: + return self.free_indices + + def _replace_indices(self, repl: dict[TensorIndex, TensorIndex]) -> TensExpr: + newargs = [arg._replace_indices(repl) if isinstance(arg, TensExpr) else arg for arg in self.args] + return self.func(*newargs) + + @memoize_property + def rank(self): + if isinstance(self.args[0], TensExpr): + return self.args[0].rank + else: + return 0 + + @memoize_property + def free_args(self): + if isinstance(self.args[0], TensExpr): + return self.args[0].free_args + else: + return [] + + @memoize_property + def free_indices(self): + if isinstance(self.args[0], TensExpr): + return self.args[0].get_free_indices() + else: + return set() + + def doit(self, **hints) -> Expr: + deep = hints.get('deep', True) + if deep: + args = [arg.doit(**hints) for arg in self.args] + else: + args = self.args # type: ignore + + # if any of the args are zero (after doit), drop them. Otherwise, _tensAdd_check will complain about non-matching indices, even though the TensAdd is correctly formed. + args = [arg for arg in args if arg != S.Zero] + + if len(args) == 0: + return S.Zero + elif len(args) == 1: + return args[0] + + # now check that all addends have the same indices: + TensAdd._tensAdd_check(args) + + # Collect terms appearing more than once, differing by their coefficients: + args = TensAdd._tensAdd_collect_terms(args) + + # collect canonicalized terms + def sort_key(t): + if not isinstance(t, TensExpr): + return [], [], [] + if hasattr(t, "_index_structure") and hasattr(t, "components"): + x = get_index_structure(t) + return t.components, x.free, x.dum + return [], [], [] + args.sort(key=sort_key) + + if not args: + return S.Zero + # it there is only a component tensor return it + if len(args) == 1: + return args[0] + + obj = self.func(*args) + return obj + + @staticmethod + def _tensAdd_flatten(args): + # flatten TensAdd, coerce terms which are not tensors to tensors + a = [] + for x in args: + if isinstance(x, (Add, TensAdd)): + a.extend(list(x.args)) + else: + a.append(x) + args = [x for x in a if x.coeff] + return args + + @staticmethod + def _tensAdd_check(args): + # check that all addends have the same free indices + + def get_indices_set(x: Expr) -> set[TensorIndex]: + if isinstance(x, TensExpr): + return set(x.get_free_indices()) + return set() + + indices0 = get_indices_set(args[0]) + list_indices = [get_indices_set(arg) for arg in args[1:]] + if not all(x == indices0 for x in list_indices): + raise ValueError('all tensors must have the same indices') + + @staticmethod + def _tensAdd_collect_terms(args): + # collect TensMul terms differing at most by their coefficient + terms_dict = defaultdict(list) + scalars = S.Zero + if isinstance(args[0], TensExpr): + free_indices = set(args[0].get_free_indices()) + else: + free_indices = set() + + for arg in args: + if not isinstance(arg, TensExpr): + if free_indices != set(): + raise ValueError("wrong valence") + scalars += arg + continue + if free_indices != set(arg.get_free_indices()): + raise ValueError("wrong valence") + # TODO: what is the part which is not a coeff? + # needs an implementation similar to .as_coeff_Mul() + terms_dict[arg.nocoeff].append(arg.coeff) + + new_args = [TensMul(Add(*coeff), t).doit(deep=False) for t, coeff in terms_dict.items() if Add(*coeff) != 0] + if isinstance(scalars, Add): + new_args = list(scalars.args) + new_args + elif scalars != 0: + new_args = [scalars] + new_args + return new_args + + def get_indices(self): + indices = [] + for arg in self.args: + indices.extend([i for i in get_indices(arg) if i not in indices]) + return indices + + + def __call__(self, *indices): + deprecate_call() + free_args = self.free_args + indices = list(indices) + if [x.tensor_index_type for x in indices] != [x.tensor_index_type for x in free_args]: + raise ValueError('incompatible types') + if indices == free_args: + return self + index_tuples = list(zip(free_args, indices)) + a = [x.func(*x.substitute_indices(*index_tuples).args) for x in self.args] + res = TensAdd(*a).doit(deep=False) + return res + + def canon_bp(self): + """ + Canonicalize using the Butler-Portugal algorithm for canonicalization + under monoterm symmetries. + """ + expr = self.expand() + if isinstance(expr, self.func): + args = [canon_bp(x) for x in expr.args] + res = TensAdd(*args).doit(deep=False) + return res + else: + return canon_bp(expr) + + def equals(self, other): + other = _sympify(other) + if isinstance(other, TensMul) and other.coeff == 0: + return all(x.coeff == 0 for x in self.args) + if isinstance(other, TensExpr): + if self.rank != other.rank: + return False + if isinstance(other, TensAdd): + if set(self.args) != set(other.args): + return False + else: + return True + t = self - other + if not isinstance(t, TensExpr): + return t == 0 + else: + if isinstance(t, TensMul): + return t.coeff == 0 + else: + return all(x.coeff == 0 for x in t.args) + + def __getitem__(self, item): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return self.data[item] + + def contract_delta(self, delta): + args = [x.contract_delta(delta) if isinstance(x, TensExpr) else x for x in self.args] + t = TensAdd(*args).doit(deep=False) + return canon_bp(t) + + def contract_metric(self, g): + """ + Raise or lower indices with the metric ``g``. + + Parameters + ========== + + g : metric + + contract_all : if True, eliminate all ``g`` which are contracted + + Notes + ===== + + see the ``TensorIndexType`` docstring for the contraction conventions + """ + + args = [contract_metric(x, g) for x in self.args] + t = TensAdd(*args).doit(deep=False) + return canon_bp(t) + + def substitute_indices(self, *index_tuples): + new_args = [] + for arg in self.args: + if isinstance(arg, TensExpr): + arg = arg.substitute_indices(*index_tuples) + new_args.append(arg) + return TensAdd(*new_args).doit(deep=False) + + def _print(self): + a = [] + args = self.args + for x in args: + a.append(str(x)) + s = ' + '.join(a) + s = s.replace('+ -', '- ') + return s + + def _extract_data(self, replacement_dict): + from sympy.tensor.array import Array, permutedims + args_indices, arrays = zip(*[ + arg._extract_data(replacement_dict) if + isinstance(arg, TensExpr) else ([], arg) for arg in self.args + ]) + arrays = [Array(i) for i in arrays] + ref_indices = args_indices[0] + for i in range(1, len(args_indices)): + indices = args_indices[i] + array = arrays[i] + permutation = TensMul._get_indices_permutation(indices, ref_indices) + arrays[i] = permutedims(array, permutation) + return ref_indices, sum(arrays, Array.zeros(*array.shape)) + + @property + def data(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return _tensor_data_substitution_dict[self.expand()] + + @data.setter + def data(self, data): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + _tensor_data_substitution_dict[self] = data + + @data.deleter + def data(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + if self in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[self] + + def __iter__(self): + deprecate_data() + if not self.data: + raise ValueError("No iteration on abstract tensors") + return self.data.flatten().__iter__() + + def _eval_rewrite_as_Indexed(self, *args, **kwargs): + return Add.fromiter(args) + + def _eval_partial_derivative(self, s): + # Evaluation like Add + list_addends = [] + for a in self.args: + if isinstance(a, TensExpr): + list_addends.append(a._eval_partial_derivative(s)) + # do not call diff if s is no symbol + elif s._diff_wrt: + list_addends.append(a._eval_derivative(s)) + + return self.func(*list_addends).doit(deep=False) + + def matches(self, expr, repl_dict=None, old=False): + expr = sympify(expr) + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + if not isinstance(expr, TensAdd): + return None + + if len(_get_wilds(self)) == 0: + return self._matches_simple(expr, repl_dict, old) + + def siftkey(arg): + wildatoms = _get_wilds(arg) + wildatom_types = sift(wildatoms, type) + if len(wildatoms) == 0: + return "nonwild" + elif WildTensor in wildatom_types.keys(): + for w in wildatom_types["WildTensor"]: + if len(w.get_indices()) == 0: + return "indexless_wildtensor" + return "wildtensor" + else: + return "otherwild" + + query_sifted = sift(self.args, siftkey) + expr_sifted = sift(expr.args, siftkey) + + #First try to match the terms without WildTensors + matched_e_tensors = [] #Used to make sure that the same tensor in expr is not matched with more than one tensor in self. + for q_tensor in query_sifted["nonwild"]: + matched_this_q = False + for e_tensor in expr_sifted["nonwild"]: + if e_tensor in matched_e_tensors: + continue + + m = q_tensor.matches(e_tensor, repl_dict=repl_dict, old=old) + if m is None: + continue + else: + matched_this_q = True + repl_dict.update(m) + matched_e_tensors.append(e_tensor) + break + + if not matched_this_q: + return None + + remaining_e_tensors = [t for t in expr_sifted["nonwild"] if t not in matched_e_tensors] + for w in query_sifted["otherwild"]: + for e in remaining_e_tensors: + m = w.matches(e) + if m is not None: + matched_e_tensors.append(e) + if w in repl_dict.keys(): + repl_dict[w] += m.pop(w) + repl_dict.update(m) + + remaining_e_tensors = [t for t in expr_sifted["nonwild"] if t not in matched_e_tensors] + for w in query_sifted["wildtensor"]: + for e in remaining_e_tensors: + m = w.matches(e) + if m is not None: + matched_e_tensors.append(e) + if w.component in repl_dict.keys(): + repl_dict[w.component] += m.pop(w.component) + repl_dict.update(m) + + remaining_e_tensors = [t for t in expr_sifted["nonwild"] if t not in matched_e_tensors] + for w in query_sifted["indexless_wildtensor"]: + for e in remaining_e_tensors: + m = w.matches(e) + if m is not None: + matched_e_tensors.append(e) + if w.component in repl_dict.keys(): + repl_dict[w.component] += m.pop(w.component) + repl_dict.update(m) + + remaining_e_tensors = [t for t in expr_sifted["nonwild"] if t not in matched_e_tensors] + if len(remaining_e_tensors) > 0: + return None + else: + return repl_dict + + +class Tensor(TensExpr): + """ + Base tensor class, i.e. this represents a tensor, the single unit to be + put into an expression. + + Explanation + =========== + + This object is usually created from a ``TensorHead``, by attaching indices + to it. Indices preceded by a minus sign are considered contravariant, + otherwise covariant. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead + >>> Lorentz = TensorIndexType("Lorentz", dummy_name="L") + >>> mu, nu = tensor_indices('mu nu', Lorentz) + >>> A = TensorHead("A", [Lorentz, Lorentz]) + >>> A(mu, -nu) + A(mu, -nu) + >>> A(mu, -mu) + A(L_0, -L_0) + + It is also possible to use symbols instead of inidices (appropriate indices + are then generated automatically). + + >>> from sympy import Symbol + >>> x = Symbol('x') + >>> A(x, mu) + A(x, mu) + >>> A(x, -x) + A(L_0, -L_0) + + """ + + is_commutative = False + + _index_structure: _IndexStructure + args: tuple[TensorHead, Tuple] + + def __new__(cls, tensor_head, indices, *, is_canon_bp=False, **kw_args): + indices = cls._parse_indices(tensor_head, indices) + obj = Basic.__new__(cls, tensor_head, Tuple(*indices), **kw_args) + obj._index_structure = _IndexStructure.from_indices(*indices) + obj._free = obj._index_structure.free[:] + obj._dum = obj._index_structure.dum[:] + obj._ext_rank = obj._index_structure._ext_rank + obj._coeff = S.One + obj._nocoeff = obj + obj._component = tensor_head + obj._components = [tensor_head] + if tensor_head.rank != len(indices): + raise ValueError("wrong number of indices") + obj.is_canon_bp = is_canon_bp + obj._index_map = Tensor._build_index_map(indices, obj._index_structure) + return obj + + @property + def free(self): + return self._free + + @property + def dum(self): + return self._dum + + @property + def ext_rank(self): + return self._ext_rank + + @property + def coeff(self): + return self._coeff + + @property + def nocoeff(self): + return self._nocoeff + + @property + def component(self): + return self._component + + @property + def components(self): + return self._components + + @property + def head(self): + return self.args[0] + + @property + def indices(self): + return self.args[1] + + @property + def free_indices(self): + return set(self._index_structure.get_free_indices()) + + @property + def index_types(self): + return self.head.index_types + + @property + def rank(self): + return len(self.free_indices) + + @staticmethod + def _build_index_map(indices, index_structure): + index_map = {} + for idx in indices: + index_map[idx] = (indices.index(idx),) + return index_map + + def doit(self, **hints): + args, indices, free, dum = TensMul._tensMul_contract_indices([self]) + return args[0] + + @staticmethod + def _parse_indices(tensor_head, indices): + if not isinstance(indices, (tuple, list, Tuple)): + raise TypeError("indices should be an array, got %s" % type(indices)) + indices = list(indices) + for i, index in enumerate(indices): + if isinstance(index, Symbol): + indices[i] = TensorIndex(index, tensor_head.index_types[i], True) + elif isinstance(index, Mul): + c, e = index.as_coeff_Mul() + if c == -1 and isinstance(e, Symbol): + indices[i] = TensorIndex(e, tensor_head.index_types[i], False) + else: + raise ValueError("index not understood: %s" % index) + elif not isinstance(index, TensorIndex): + raise TypeError("wrong type for index: %s is %s" % (index, type(index))) + return indices + + def _set_new_index_structure(self, im, is_canon_bp=False): + indices = im.get_indices() + return self._set_indices(*indices, is_canon_bp=is_canon_bp) + + def _set_indices(self, *indices, is_canon_bp=False, **kw_args): + if len(indices) != self.ext_rank: + raise ValueError("indices length mismatch") + return self.func(self.args[0], indices, is_canon_bp=is_canon_bp).doit() + + def _get_free_indices_set(self): + return {i[0] for i in self._index_structure.free} + + def _get_dummy_indices_set(self): + dummy_pos = set(itertools.chain(*self._index_structure.dum)) + return {idx for i, idx in enumerate(self.args[1]) if i in dummy_pos} + + def _get_indices_set(self): + return set(self.args[1].args) + + @property + def free_in_args(self): + return [(ind, pos, 0) for ind, pos in self.free] + + @property + def dum_in_args(self): + return [(p1, p2, 0, 0) for p1, p2 in self.dum] + + @property + def free_args(self): + return sorted([x[0] for x in self.free]) + + def commutes_with(self, other): + """ + :param other: + :return: + 0 commute + 1 anticommute + None neither commute nor anticommute + """ + if not isinstance(other, TensExpr): + return 0 + elif isinstance(other, Tensor): + return self.component.commutes_with(other.component) + return NotImplementedError + + def perm2tensor(self, g, is_canon_bp=False): + """ + Returns the tensor corresponding to the permutation ``g``. + + For further details, see the method in ``TIDS`` with the same name. + """ + return perm2tensor(self, g, is_canon_bp) + + def canon_bp(self): + if self.is_canon_bp: + return self + expr = self.expand() + g, dummies, msym = expr._index_structure.indices_canon_args() + v = components_canon_args([expr.component]) + can = canonicalize(g, dummies, msym, *v) + if can == 0: + return S.Zero + tensor = self.perm2tensor(can, True) + return tensor + + def split(self): + return [self] + + def sorted_components(self): + return self + + def get_indices(self) -> list[TensorIndex]: + """ + Get a list of indices, corresponding to those of the tensor. + """ + return list(self.args[1]) + + def get_free_indices(self) -> list[TensorIndex]: + """ + Get a list of free indices, corresponding to those of the tensor. + """ + return self._index_structure.get_free_indices() + + def _replace_indices(self, repl: dict[TensorIndex, TensorIndex]) -> TensExpr: + # TODO: this could be optimized by only swapping the indices + # instead of visiting the whole expression tree: + return self.xreplace(repl) + + def as_base_exp(self): + return self, S.One + + def substitute_indices(self, *index_tuples): + """ + Return a tensor with free indices substituted according to ``index_tuples``. + + ``index_types`` list of tuples ``(old_index, new_index)``. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads, TensorSymmetry + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) + >>> A, B = tensor_heads('A,B', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) + >>> t = A(i, k)*B(-k, -j); t + A(i, L_0)*B(-L_0, -j) + >>> t.substitute_indices((i, k),(-j, l)) + A(k, L_0)*B(-L_0, l) + """ + indices = [] + for index in self.indices: + for ind_old, ind_new in index_tuples: + if (index.name == ind_old.name and index.tensor_index_type == + ind_old.tensor_index_type): + if index.is_up == ind_old.is_up: + indices.append(ind_new) + else: + indices.append(-ind_new) + break + else: + indices.append(index) + return self.head(*indices) + + def _get_symmetrized_forms(self): + """ + Return a list giving all possible permutations of self that are allowed by its symmetries. + """ + comp = self.component + gens = comp.symmetry.generators + rank = comp.rank + + old_perms = None + new_perms = {self} + while new_perms != old_perms: + old_perms = new_perms.copy() + for tens in old_perms: + for gen in gens: + inds = tens.get_indices() + per = [gen.apply(i) for i in range(0,rank)] + sign = (-1)**(gen.apply(rank) - rank) + ind_map = dict(zip(inds, [inds[i] for i in per])) + new_perms.add( sign * tens._replace_indices(ind_map) ) + + return new_perms + + def matches(self, expr, repl_dict=None, old=False): + expr = sympify(expr) + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + #simple checks + if self == expr: + return repl_dict + if not isinstance(expr, Tensor): + return None + if self.head != expr.head: + return None + + #Now consider all index symmetries of expr, and see if any of them allow a match. + for new_expr in expr._get_symmetrized_forms(): + m = self._matches(new_expr, repl_dict, old=old) + if m is not None: + repl_dict.update(m) + return repl_dict + + return None + + def _matches(self, expr, repl_dict=None, old=False): + """ + This does not account for index symmetries of expr + """ + expr = sympify(expr) + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + #simple checks + if self == expr: + return repl_dict + if not isinstance(expr, Tensor): + return None + if self.head != expr.head: + return None + + s_indices = self.get_indices() + e_indices = expr.get_indices() + + if len(s_indices) != len(e_indices): + return None + + for i in range(len(s_indices)): + s_ind = s_indices[i] + m = s_ind.matches(e_indices[i]) + if m is None: + return None + elif -s_ind in repl_dict.keys() and -repl_dict[-s_ind] != m[s_ind]: + return None + else: + repl_dict.update(m) + + return repl_dict + + def __call__(self, *indices): + deprecate_call() + free_args = self.free_args + indices = list(indices) + if [x.tensor_index_type for x in indices] != [x.tensor_index_type for x in free_args]: + raise ValueError('incompatible types') + if indices == free_args: + return self + t = self.substitute_indices(*list(zip(free_args, indices))) + + # object is rebuilt in order to make sure that all contracted indices + # get recognized as dummies, but only if there are contracted indices. + if len({i if i.is_up else -i for i in indices}) != len(indices): + return t.func(*t.args) + return t + + # TODO: put this into TensExpr? + def __iter__(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return self.data.__iter__() + + # TODO: put this into TensExpr? + def __getitem__(self, item): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return self.data[item] + + def _extract_data(self, replacement_dict): + from .array import Array + for k, v in replacement_dict.items(): + if isinstance(k, Tensor) and k.args[0] == self.args[0]: + other = k + array = v + break + else: + raise ValueError("%s not found in %s" % (self, replacement_dict)) + + # TODO: inefficient, this should be done at root level only: + replacement_dict = {k: Array(v) for k, v in replacement_dict.items()} + array = Array(array) + + dum1 = self.dum + dum2 = other.dum + + if len(dum2) > 0: + for pair in dum2: + # allow `dum2` if the contained values are also in `dum1`. + if pair not in dum1: + raise NotImplementedError("%s with contractions is not implemented" % other) + # Remove elements in `dum2` from `dum1`: + dum1 = [pair for pair in dum1 if pair not in dum2] + if len(dum1) > 0: + indices1 = self.get_indices() + indices2 = other.get_indices() + repl = {} + for p1, p2 in dum1: + repl[indices2[p2]] = -indices2[p1] + for pos in (p1, p2): + if indices1[pos].is_up ^ indices2[pos].is_up: + metric = replacement_dict[indices1[pos].tensor_index_type] + if indices1[pos].is_up: + metric = _TensorDataLazyEvaluator.inverse_matrix(metric) + array = self._contract_and_permute_with_metric(metric, array, pos, len(indices2)) + other = other.xreplace(repl).doit() + array = _TensorDataLazyEvaluator.data_contract_dum([array], dum1, len(indices2)) + + free_ind1 = self.get_free_indices() + free_ind2 = other.get_free_indices() + + return self._match_indices_with_other_tensor(array, free_ind1, free_ind2, replacement_dict) + + @property + def data(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return _tensor_data_substitution_dict[self] + + @data.setter + def data(self, data): + deprecate_data() + # TODO: check data compatibility with properties of tensor. + with ignore_warnings(SymPyDeprecationWarning): + _tensor_data_substitution_dict[self] = data + + @data.deleter + def data(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + if self in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[self] + if self.metric in _tensor_data_substitution_dict: + del _tensor_data_substitution_dict[self.metric] + + def _print(self): + indices = [str(ind) for ind in self.indices] + component = self.component + if component.rank > 0: + return ('%s(%s)' % (component.name, ', '.join(indices))) + else: + return ('%s' % component.name) + + def equals(self, other): + if other == 0: + return self.coeff == 0 + other = _sympify(other) + if not isinstance(other, TensExpr): + assert not self.components + return S.One == other + + def _get_compar_comp(self): + t = self.canon_bp() + r = (t.coeff, tuple(t.components), \ + tuple(sorted(t.free)), tuple(sorted(t.dum))) + return r + + return _get_compar_comp(self) == _get_compar_comp(other) + + def contract_metric(self, g): + # if metric is not the same, ignore this step: + if self.component != g: + return self + # in case there are free components, do not perform anything: + if len(self.free) != 0: + return self + + #antisym = g.index_types[0].metric_antisym + if g.symmetry == TensorSymmetry.fully_symmetric(-2): + antisym = 1 + elif g.symmetry == TensorSymmetry.fully_symmetric(2): + antisym = 0 + elif g.symmetry == TensorSymmetry.no_symmetry(2): + antisym = None + else: + raise NotImplementedError + sign = S.One + typ = g.index_types[0] + + if not antisym: + # g(i, -i) + sign = sign*typ.dim + else: + # g(i, -i) + sign = sign*typ.dim + + dp0, dp1 = self.dum[0] + if dp0 < dp1: + # g(i, -i) = -D with antisymmetric metric + sign = -sign + + return sign + + def contract_delta(self, metric): + return self.contract_metric(metric) + + def _eval_rewrite_as_Indexed(self, tens, indices, **kwargs): + from sympy.tensor.indexed import Indexed + # TODO: replace .args[0] with .name: + index_symbols = [i.args[0] for i in self.get_indices()] + expr = Indexed(tens.args[0], *index_symbols) + return self._check_add_Sum(expr, index_symbols) + + def _eval_partial_derivative(self, s: Tensor) -> Expr: + + if not isinstance(s, Tensor): + return S.Zero + else: + + # @a_i/@a_k = delta_i^k + # @a_i/@a^k = g_ij delta^j_k + # @a^i/@a^k = delta^i_k + # @a^i/@a_k = g^ij delta_j^k + # TODO: if there is no metric present, the derivative should be zero? + + if self.head != s.head: + return S.Zero + + # if heads are the same, provide delta and/or metric products + # for every free index pair in the appropriate tensor + # assumed that the free indices are in proper order + # A contravariante index in the derivative becomes covariant + # after performing the derivative and vice versa + + kronecker_delta_list = [1] + + # not guarantee a correct index order + + for (count, (iself, iother)) in enumerate(zip(self.get_free_indices(), s.get_free_indices())): + if iself.tensor_index_type != iother.tensor_index_type: + raise ValueError("index types not compatible") + else: + tensor_index_type = iself.tensor_index_type + tensor_metric = tensor_index_type.metric + dummy = TensorIndex("d_" + str(count), tensor_index_type, + is_up=iself.is_up) + if iself.is_up == iother.is_up: + kroneckerdelta = tensor_index_type.delta(iself, -iother) + else: + kroneckerdelta = ( + TensMul(tensor_metric(iself, dummy), + tensor_index_type.delta(-dummy, -iother)) + ) + kronecker_delta_list.append(kroneckerdelta) + return TensMul.fromiter(kronecker_delta_list).doit(deep=False) + # doit necessary to rename dummy indices accordingly + + +class TensMul(TensExpr, AssocOp): + """ + Product of tensors. + + Parameters + ========== + + coeff : SymPy coefficient of the tensor + args + + Attributes + ========== + + ``components`` : list of ``TensorHead`` of the component tensors + ``types`` : list of nonrepeated ``TensorIndexType`` + ``free`` : list of ``(ind, ipos, icomp)``, see Notes + ``dum`` : list of ``(ipos1, ipos2, icomp1, icomp2)``, see Notes + ``ext_rank`` : rank of the tensor counting the dummy indices + ``rank`` : rank of the tensor + ``coeff`` : SymPy coefficient of the tensor + ``free_args`` : list of the free indices in sorted order + ``is_canon_bp`` : ``True`` if the tensor in in canonical form + + Notes + ===== + + ``args[0]`` list of ``TensorHead`` of the component tensors. + + ``args[1]`` list of ``(ind, ipos, icomp)`` + where ``ind`` is a free index, ``ipos`` is the slot position + of ``ind`` in the ``icomp``-th component tensor. + + ``args[2]`` list of tuples representing dummy indices. + ``(ipos1, ipos2, icomp1, icomp2)`` indicates that the contravariant + dummy index is the ``ipos1``-th slot position in the ``icomp1``-th + component tensor; the corresponding covariant index is + in the ``ipos2`` slot position in the ``icomp2``-th component tensor. + + """ + identity = S.One + + _index_structure: _IndexStructure + + def __new__(cls, *args, **kw_args): + is_canon_bp = kw_args.get('is_canon_bp', False) + args = list(map(_sympify, args)) + + """ + If the internal dummy indices in one arg conflict with the free indices + of the remaining args, we need to rename those internal dummy indices. + """ + free = [get_free_indices(arg) for arg in args] + free = set(itertools.chain(*free)) #flatten free + newargs = [] + for arg in args: + dum_this = set(get_dummy_indices(arg)) + dum_other = [get_dummy_indices(a) for a in newargs] + dum_other = set(itertools.chain(*dum_other)) #flatten dum_other + free_this = set(get_free_indices(arg)) + if len(dum_this.intersection(free)) > 0: + exclude = free_this.union(free, dum_other) + newarg = TensMul._dedupe_indices(arg, exclude) + else: + newarg = arg + newargs.append(newarg) + + args = newargs + + # Flatten: + args = [i for arg in args for i in (arg.args if isinstance(arg, (TensMul, Mul)) else [arg])] + + args, indices, free, dum = TensMul._tensMul_contract_indices(args, replace_indices=False) + + # Data for indices: + index_types = [i.tensor_index_type for i in indices] + index_structure = _IndexStructure(free, dum, index_types, indices, canon_bp=is_canon_bp) + + obj = TensExpr.__new__(cls, *args) + obj._indices = indices + obj._index_types = index_types.copy() + obj._index_structure = index_structure + obj._free = index_structure.free[:] + obj._dum = index_structure.dum[:] + obj._free_indices = {x[0] for x in obj.free} + obj._rank = len(obj.free) + obj._ext_rank = len(obj._index_structure.free) + 2*len(obj._index_structure.dum) + obj._coeff = S.One + obj._is_canon_bp = is_canon_bp + return obj + + index_types = property(lambda self: self._index_types) + free = property(lambda self: self._free) + dum = property(lambda self: self._dum) + free_indices = property(lambda self: self._free_indices) + rank = property(lambda self: self._rank) + ext_rank = property(lambda self: self._ext_rank) + + @staticmethod + def _indices_to_free_dum(args_indices): + free2pos1 = {} + free2pos2 = {} + dummy_data = [] + indices = [] + + # Notation for positions (to better understand the code): + # `pos1`: position in the `args`. + # `pos2`: position in the indices. + + # Example: + # A(i, j)*B(k, m, n)*C(p) + # `pos1` of `n` is 1 because it's in `B` (second `args` of TensMul). + # `pos2` of `n` is 4 because it's the fifth overall index. + + # Counter for the index position wrt the whole expression: + pos2 = 0 + + for pos1, arg_indices in enumerate(args_indices): + + for index in arg_indices: + if not isinstance(index, TensorIndex): + raise TypeError("expected TensorIndex") + if -index in free2pos1: + # Dummy index detected: + other_pos1 = free2pos1.pop(-index) + other_pos2 = free2pos2.pop(-index) + if index.is_up: + dummy_data.append((index, pos1, other_pos1, pos2, other_pos2)) + else: + dummy_data.append((-index, other_pos1, pos1, other_pos2, pos2)) + indices.append(index) + elif index in free2pos1: + raise ValueError("Repeated index: %s" % index) + else: + free2pos1[index] = pos1 + free2pos2[index] = pos2 + indices.append(index) + pos2 += 1 + + free = list(free2pos2.items()) + free_names = [i.name for i in free2pos2.keys()] + + dummy_data.sort(key=lambda x: x[3]) + return indices, free, free_names, dummy_data + + @staticmethod + def _dummy_data_to_dum(dummy_data): + return [(p2a, p2b) for (i, p1a, p1b, p2a, p2b) in dummy_data] + + @staticmethod + def _tensMul_contract_indices(args, replace_indices=True): + replacements = [{} for _ in args] + + #_index_order = all(_has_index_order(arg) for arg in args) + + args_indices = [get_indices(arg) for arg in args] + indices, free, free_names, dummy_data = TensMul._indices_to_free_dum(args_indices) + + cdt = defaultdict(int) + + def dummy_name_gen(tensor_index_type): + nd = str(cdt[tensor_index_type]) + cdt[tensor_index_type] += 1 + return tensor_index_type.dummy_name + '_' + nd + + if replace_indices: + for old_index, pos1cov, pos1contra, pos2cov, pos2contra in dummy_data: + index_type = old_index.tensor_index_type + while True: + dummy_name = dummy_name_gen(index_type) + if dummy_name not in free_names: + break + dummy = old_index.func(dummy_name, index_type, *old_index.args[2:]) + replacements[pos1cov][old_index] = dummy + replacements[pos1contra][-old_index] = -dummy + indices[pos2cov] = dummy + indices[pos2contra] = -dummy + args = [ + arg._replace_indices(repl) if isinstance(arg, TensExpr) else arg + for arg, repl in zip(args, replacements)] + + """ + The order of indices might've changed due to the replacements (e.g. if one of the args is a TensAdd, replacing an index can change the sort order of the terms, thus changing the order of indices returned by its get_indices() method). + To stay on the safe side, we calculate these quantities again. + """ + args_indices = [get_indices(arg) for arg in args] + indices, free, free_names, dummy_data = TensMul._indices_to_free_dum(args_indices) + + dum = TensMul._dummy_data_to_dum(dummy_data) + return args, indices, free, dum + + @staticmethod + def _get_components_from_args(args): + """ + Get a list of ``Tensor`` objects having the same ``TIDS`` if multiplied + by one another. + """ + components = [] + for arg in args: + if not isinstance(arg, TensExpr): + continue + if isinstance(arg, TensAdd): + continue + components.extend(arg.components) + return components + + @staticmethod + def _rebuild_tensors_list(args, index_structure): + indices = index_structure.get_indices() + #tensors = [None for i in components] # pre-allocate list + ind_pos = 0 + for i, arg in enumerate(args): + if not isinstance(arg, TensExpr): + continue + prev_pos = ind_pos + ind_pos += arg.ext_rank + args[i] = Tensor(arg.component, indices[prev_pos:ind_pos]) + + def doit(self, **hints): + is_canon_bp = self._is_canon_bp + deep = hints.get('deep', True) + if deep: + args = [arg.doit(**hints) for arg in self.args] + + """ + There may now be conflicts between dummy indices of different args + (each arg's doit method does not have any information about which + dummy indices are already used in the other args), so we + deduplicate them. + """ + rule = dict(zip(self.args, args)) + rule = self._dedupe_indices_in_rule(rule) + args = [rule[a] for a in self.args] + + else: + args = self.args + + args = [arg for arg in args if arg != self.identity] + + # Extract non-tensor coefficients: + coeff = reduce(lambda a, b: a*b, [arg for arg in args if not isinstance(arg, TensExpr)], S.One) + args = [arg for arg in args if isinstance(arg, TensExpr)] + + if len(args) == 0: + return coeff + + if coeff != self.identity: + args = [coeff] + args + if coeff == 0: + return S.Zero + + if len(args) == 1: + return args[0] + + args, indices, free, dum = TensMul._tensMul_contract_indices(args) + + # Data for indices: + index_types = [i.tensor_index_type for i in indices] + index_structure = _IndexStructure(free, dum, index_types, indices, canon_bp=is_canon_bp) + + obj = self.func(*args) + obj._index_types = index_types + obj._index_structure = index_structure + obj._ext_rank = len(obj._index_structure.free) + 2*len(obj._index_structure.dum) + obj._coeff = coeff + obj._is_canon_bp = is_canon_bp + return obj + + # TODO: this method should be private + # TODO: should this method be renamed _from_components_free_dum ? + @staticmethod + def from_data(coeff, components, free, dum, **kw_args): + return TensMul(coeff, *TensMul._get_tensors_from_components_free_dum(components, free, dum), **kw_args).doit(deep=False) + + @staticmethod + def _get_tensors_from_components_free_dum(components, free, dum): + """ + Get a list of ``Tensor`` objects by distributing ``free`` and ``dum`` indices on the ``components``. + """ + index_structure = _IndexStructure.from_components_free_dum(components, free, dum) + indices = index_structure.get_indices() + tensors = [None for i in components] # pre-allocate list + + # distribute indices on components to build a list of tensors: + ind_pos = 0 + for i, component in enumerate(components): + prev_pos = ind_pos + ind_pos += component.rank + tensors[i] = Tensor(component, indices[prev_pos:ind_pos]) + return tensors + + def _get_free_indices_set(self): + return {i[0] for i in self.free} + + def _get_dummy_indices_set(self): + dummy_pos = set(itertools.chain(*self.dum)) + return {idx for i, idx in enumerate(self._index_structure.get_indices()) if i in dummy_pos} + + def _get_position_offset_for_indices(self): + arg_offset = [None for i in range(self.ext_rank)] + counter = 0 + for arg in self.args: + if not isinstance(arg, TensExpr): + continue + for j in range(arg.ext_rank): + arg_offset[j + counter] = counter + counter += arg.ext_rank + return arg_offset + + @property + def free_args(self): + return sorted([x[0] for x in self.free]) + + @property + def components(self): + return self._get_components_from_args(self.args) + + @property + def free_in_args(self): + arg_offset = self._get_position_offset_for_indices() + argpos = self._get_indices_to_args_pos() + return [(ind, pos-arg_offset[pos], argpos[pos]) for (ind, pos) in self.free] + + @property + def coeff(self): + # return Mul.fromiter([c for c in self.args if not isinstance(c, TensExpr)]) + return self._coeff + + @property + def nocoeff(self): + return self.func(*self.args, 1/self.coeff).doit(deep=False) + + @property + def dum_in_args(self): + arg_offset = self._get_position_offset_for_indices() + argpos = self._get_indices_to_args_pos() + return [(p1-arg_offset[p1], p2-arg_offset[p2], argpos[p1], argpos[p2]) for p1, p2 in self.dum] + + def equals(self, other): + if other == 0: + return self.coeff == 0 + other = _sympify(other) + if not isinstance(other, TensExpr): + assert not self.components + return self.coeff == other + + return self.canon_bp() == other.canon_bp() + + def get_indices(self): + """ + Returns the list of indices of the tensor. + + Explanation + =========== + + The indices are listed in the order in which they appear in the + component tensors. + The dummy indices are given a name which does not collide with + the names of the free indices. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> g = Lorentz.metric + >>> p, q = tensor_heads('p,q', [Lorentz]) + >>> t = p(m1)*g(m0,m2) + >>> t.get_indices() + [m1, m0, m2] + >>> t2 = p(m1)*g(-m1, m2) + >>> t2.get_indices() + [L_0, -L_0, m2] + """ + return self._indices + + def get_free_indices(self) -> list[TensorIndex]: + """ + Returns the list of free indices of the tensor. + + Explanation + =========== + + The indices are listed in the order in which they appear in the + component tensors. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> g = Lorentz.metric + >>> p, q = tensor_heads('p,q', [Lorentz]) + >>> t = p(m1)*g(m0,m2) + >>> t.get_free_indices() + [m1, m0, m2] + >>> t2 = p(m1)*g(-m1, m2) + >>> t2.get_free_indices() + [m2] + """ + return self._index_structure.get_free_indices() + + def _replace_indices(self, repl: dict[TensorIndex, TensorIndex]) -> TensExpr: + return self.func(*[arg._replace_indices(repl) if isinstance(arg, TensExpr) else arg for arg in self.args]) + + def split(self): + """ + Returns a list of tensors, whose product is ``self``. + + Explanation + =========== + + Dummy indices contracted among different tensor components + become free indices with the same name as the one used to + represent the dummy indices. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads, TensorSymmetry + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz) + >>> A, B = tensor_heads('A,B', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) + >>> t = A(a,b)*B(-b,c) + >>> t + A(a, L_0)*B(-L_0, c) + >>> t.split() + [A(a, L_0), B(-L_0, c)] + """ + if self.args == (): + return [self] + splitp = [] + res = 1 + for arg in self.args: + if isinstance(arg, Tensor): + splitp.append(res*arg) + res = 1 + else: + res *= arg + return splitp + + def _eval_expand_mul(self, **hints): + args1 = [arg.args if isinstance(arg, (Add, TensAdd)) else (arg,) for arg in self.args] + return TensAdd(*[ + TensMul(*i).doit(deep=False) for i in itertools.product(*args1)] + ) + + def __neg__(self): + return TensMul(S.NegativeOne, self, is_canon_bp=self._is_canon_bp).doit(deep=False) + + def __getitem__(self, item): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + return self.data[item] + + def _get_args_for_traditional_printer(self): + args = list(self.args) + if self.coeff.could_extract_minus_sign(): + # expressions like "-A(a)" + sign = "-" + if args[0] == S.NegativeOne: + args = args[1:] + else: + args[0] = -args[0] + else: + sign = "" + return sign, args + + def _sort_args_for_sorted_components(self): + """ + Returns the ``args`` sorted according to the components commutation + properties. + + Explanation + =========== + + The sorting is done taking into account the commutation group + of the component tensors. + """ + cv = [arg for arg in self.args if isinstance(arg, TensExpr)] + sign = 1 + n = len(cv) - 1 + for i in range(n): + for j in range(n, i, -1): + c = cv[j-1].commutes_with(cv[j]) + # if `c` is `None`, it does neither commute nor anticommute, skip: + if c not in (0, 1): + continue + typ1 = sorted(set(cv[j-1].component.index_types), key=lambda x: x.name) + typ2 = sorted(set(cv[j].component.index_types), key=lambda x: x.name) + if (typ1, cv[j-1].component.name) > (typ2, cv[j].component.name): + cv[j-1], cv[j] = cv[j], cv[j-1] + # if `c` is 1, the anticommute, so change sign: + if c: + sign = -sign + + coeff = sign * self.coeff + if coeff != 1: + return [coeff] + cv + return cv + + def sorted_components(self): + """ + Returns a tensor product with sorted components. + """ + return TensMul(*self._sort_args_for_sorted_components()).doit(deep=False) + + def perm2tensor(self, g, is_canon_bp=False): + """ + Returns the tensor corresponding to the permutation ``g`` + + For further details, see the method in ``TIDS`` with the same name. + """ + return perm2tensor(self, g, is_canon_bp=is_canon_bp) + + def canon_bp(self): + """ + Canonicalize using the Butler-Portugal algorithm for canonicalization + under monoterm symmetries. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, TensorSymmetry + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(-2)) + >>> t = A(m0,-m1)*A(m1,-m0) + >>> t.canon_bp() + -A(L_0, L_1)*A(-L_0, -L_1) + >>> t = A(m0,-m1)*A(m1,-m2)*A(m2,-m0) + >>> t.canon_bp() + 0 + """ + if self._is_canon_bp: + return self + expr = self.expand() + if isinstance(expr, TensAdd): + return expr.canon_bp() + if not expr.components: + return expr + expr = expr.doit(deep=False) #make sure self.coeff is populated correctly + t = expr.sorted_components() + g, dummies, msym = t._index_structure.indices_canon_args() + v = components_canon_args(t.components) + can = canonicalize(g, dummies, msym, *v) + if can == 0: + return S.Zero + tmul = t.perm2tensor(can, True) + return tmul + + def contract_delta(self, delta): + t = self.contract_metric(delta) + return t + + def _get_indices_to_args_pos(self): + """ + Get a dict mapping the index position to TensMul's argument number. + """ + pos_map = {} + pos_counter = 0 + for arg_i, arg in enumerate(self.args): + if not isinstance(arg, TensExpr): + continue + assert isinstance(arg, Tensor) + for i in range(arg.ext_rank): + pos_map[pos_counter] = arg_i + pos_counter += 1 + return pos_map + + def contract_metric(self, g): + """ + Raise or lower indices with the metric ``g``. + + Parameters + ========== + + g : metric + + Notes + ===== + + See the ``TensorIndexType`` docstring for the contraction conventions. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> g = Lorentz.metric + >>> p, q = tensor_heads('p,q', [Lorentz]) + >>> t = p(m0)*q(m1)*g(-m0, -m1) + >>> t.canon_bp() + metric(L_0, L_1)*p(-L_0)*q(-L_1) + >>> t.contract_metric(g).canon_bp() + p(L_0)*q(-L_0) + """ + expr = self.expand().doit(deep=False) + if self != expr: + expr = canon_bp(expr) + return contract_metric(expr, g) + pos_map = self._get_indices_to_args_pos() + args = list(self.args) + + #antisym = g.index_types[0].metric_antisym + if g.symmetry == TensorSymmetry.fully_symmetric(-2): + antisym = 1 + elif g.symmetry == TensorSymmetry.fully_symmetric(2): + antisym = 0 + elif g.symmetry == TensorSymmetry.no_symmetry(2): + antisym = None + else: + raise NotImplementedError + + # list of positions of the metric ``g`` inside ``args`` + gpos = [i for i, x in enumerate(self.args) if isinstance(x, Tensor) and x.component == g] + if not gpos: + return self + + # Sign is either 1 or -1, to correct the sign after metric contraction + # (for spinor indices). + sign = 1 + dum = self.dum[:] + free = self.free[:] + elim = set() + for gposx in gpos: + if gposx in elim: + continue + free1 = [x for x in free if pos_map[x[1]] == gposx] + dum1 = [x for x in dum if pos_map[x[0]] == gposx or pos_map[x[1]] == gposx] + if not dum1: + continue + elim.add(gposx) + # subs with the multiplication neutral element, that is, remove it: + args[gposx] = 1 + if len(dum1) == 2: + if not antisym: + dum10, dum11 = dum1 + if pos_map[dum10[1]] == gposx: + # the index with pos p0 contravariant + p0 = dum10[0] + else: + # the index with pos p0 is covariant + p0 = dum10[1] + if pos_map[dum11[1]] == gposx: + # the index with pos p1 is contravariant + p1 = dum11[0] + else: + # the index with pos p1 is covariant + p1 = dum11[1] + + dum.append((p0, p1)) + else: + dum10, dum11 = dum1 + # change the sign to bring the indices of the metric to contravariant + # form; change the sign if dum10 has the metric index in position 0 + if pos_map[dum10[1]] == gposx: + # the index with pos p0 is contravariant + p0 = dum10[0] + if dum10[1] == 1: + sign = -sign + else: + # the index with pos p0 is covariant + p0 = dum10[1] + if dum10[0] == 0: + sign = -sign + if pos_map[dum11[1]] == gposx: + # the index with pos p1 is contravariant + p1 = dum11[0] + sign = -sign + else: + # the index with pos p1 is covariant + p1 = dum11[1] + + dum.append((p0, p1)) + + elif len(dum1) == 1: + if not antisym: + dp0, dp1 = dum1[0] + if pos_map[dp0] == pos_map[dp1]: + # g(i, -i) + typ = g.index_types[0] + sign = sign*typ.dim + + else: + # g(i0, i1)*p(-i1) + if pos_map[dp0] == gposx: + p1 = dp1 + else: + p1 = dp0 + + ind, p = free1[0] + free.append((ind, p1)) + else: + dp0, dp1 = dum1[0] + if pos_map[dp0] == pos_map[dp1]: + # g(i, -i) + typ = g.index_types[0] + sign = sign*typ.dim + + if dp0 < dp1: + # g(i, -i) = -D with antisymmetric metric + sign = -sign + else: + # g(i0, i1)*p(-i1) + if pos_map[dp0] == gposx: + p1 = dp1 + if dp0 == 0: + sign = -sign + else: + p1 = dp0 + ind, p = free1[0] + free.append((ind, p1)) + dum = [x for x in dum if x not in dum1] + free = [x for x in free if x not in free1] + + # shift positions: + shift = 0 + shifts = [0]*len(args) + for i in range(len(args)): + if i in elim: + shift += 2 + continue + shifts[i] = shift + free = [(ind, p - shifts[pos_map[p]]) for (ind, p) in free if pos_map[p] not in elim] + dum = [(p0 - shifts[pos_map[p0]], p1 - shifts[pos_map[p1]]) for p0, p1 in dum if pos_map[p0] not in elim and pos_map[p1] not in elim] + + res = ( sign*TensMul(*args) ).doit(deep=False) + if not isinstance(res, TensExpr): + return res + im = _IndexStructure.from_components_free_dum(res.components, free, dum) + return res._set_new_index_structure(im) + + def _set_new_index_structure(self, im, is_canon_bp=False): + indices = im.get_indices() + return self._set_indices(*indices, is_canon_bp=is_canon_bp) + + def _set_indices(self, *indices, is_canon_bp=False, **kw_args): + if len(indices) != self.ext_rank: + raise ValueError("indices length mismatch") + args = list(self.args) + pos = 0 + for i, arg in enumerate(args): + if not isinstance(arg, TensExpr): + continue + assert isinstance(arg, Tensor) + ext_rank = arg.ext_rank + args[i] = arg._set_indices(*indices[pos:pos+ext_rank]) + pos += ext_rank + return TensMul(*args, is_canon_bp=is_canon_bp).doit(deep=False) + + @staticmethod + def _index_replacement_for_contract_metric(args, free, dum): + for arg in args: + if not isinstance(arg, TensExpr): + continue + assert isinstance(arg, Tensor) + + def substitute_indices(self, *index_tuples): + new_args = [] + for arg in self.args: + if isinstance(arg, TensExpr): + arg = arg.substitute_indices(*index_tuples) + new_args.append(arg) + return TensMul(*new_args).doit(deep=False) + + def __call__(self, *indices): + deprecate_call() + free_args = self.free_args + indices = list(indices) + if [x.tensor_index_type for x in indices] != [x.tensor_index_type for x in free_args]: + raise ValueError('incompatible types') + if indices == free_args: + return self + t = self.substitute_indices(*list(zip(free_args, indices))) + + # object is rebuilt in order to make sure that all contracted indices + # get recognized as dummies, but only if there are contracted indices. + if len({i if i.is_up else -i for i in indices}) != len(indices): + return t.func(*t.args) + return t + + def _extract_data(self, replacement_dict): + args_indices, arrays = zip(*[arg._extract_data(replacement_dict) for arg in self.args if isinstance(arg, TensExpr)]) + coeff = reduce(operator.mul, [a for a in self.args if not isinstance(a, TensExpr)], S.One) + indices, free, free_names, dummy_data = TensMul._indices_to_free_dum(args_indices) + dum = TensMul._dummy_data_to_dum(dummy_data) + ext_rank = self.ext_rank + free.sort(key=lambda x: x[1]) + free_indices = [i[0] for i in free] + return free_indices, coeff*_TensorDataLazyEvaluator.data_contract_dum(arrays, dum, ext_rank) + + @property + def data(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + dat = _tensor_data_substitution_dict[self.expand()] + return dat + + @data.setter + def data(self, data): + deprecate_data() + raise ValueError("Not possible to set component data to a tensor expression") + + @data.deleter + def data(self): + deprecate_data() + raise ValueError("Not possible to delete component data to a tensor expression") + + def __iter__(self): + deprecate_data() + with ignore_warnings(SymPyDeprecationWarning): + if self.data is None: + raise ValueError("No iteration on abstract tensors") + return self.data.__iter__() + + @staticmethod + def _dedupe_indices(new, exclude): + """ + exclude: set + new: TensExpr + + If ``new`` has any dummy indices that are in ``exclude``, return a version + of new with those indices replaced. If no replacements are needed, + return None + + """ + exclude = set(exclude) + dums_new = set(get_dummy_indices(new)) + free_new = set(get_free_indices(new)) + + conflicts = dums_new.intersection(exclude) + if len(conflicts) == 0: + return None + + """ + ``exclude_for_gen`` is to be passed to ``_IndexStructure._get_generator_for_dummy_indices()``. + Since the latter does not use the index position for anything, we just + set it as ``None`` here. + """ + exclude.update(dums_new) + exclude.update(free_new) + exclude_for_gen = [(i, None) for i in exclude] + gen = _IndexStructure._get_generator_for_dummy_indices(exclude_for_gen) + repl = {} + for d in conflicts: + if -d in repl.keys(): + continue + newname = gen(d.tensor_index_type) + new_d = d.func(newname, *d.args[1:]) + repl[d] = new_d + repl[-d] = -new_d + + if len(repl) == 0: + return None + + new_renamed = new._replace_indices(repl) + return new_renamed + + def _dedupe_indices_in_rule(self, rule): + """ + rule: dict + + This applies TensMul._dedupe_indices on all values of rule. + + """ + index_rules = {k:v for k,v in rule.items() if isinstance(k, TensorIndex)} + other_rules = {k:v for k,v in rule.items() if k not in index_rules.keys()} + exclude = set(self.get_indices()) + + newrule = {} + newrule.update(index_rules) + exclude.update(index_rules.keys()) + exclude.update(index_rules.values()) + for old, new in other_rules.items(): + new_renamed = TensMul._dedupe_indices(new, exclude) + if old == new or new_renamed is None: + newrule[old] = new + else: + newrule[old] = new_renamed + exclude.update(get_indices(new_renamed)) + return newrule + + def _eval_subs(self, old, new): + """ + If new is an index which is already present in self as a dummy, the dummies in self should be renamed. + """ + + if not isinstance(new, TensorIndex): + return None + + exclude = {new} + self_renamed = self._dedupe_indices(self, exclude) + if self_renamed is None: + return None + else: + return self_renamed._subs(old, new).doit(deep=False) + + def _eval_rewrite_as_Indexed(self, *args, **kwargs): + from sympy.concrete.summations import Sum + index_symbols = [i.args[0] for i in self.get_indices()] + args = [arg.args[0] if isinstance(arg, Sum) else arg for arg in args] + expr = Mul.fromiter(args) + return self._check_add_Sum(expr, index_symbols) + + def _eval_partial_derivative(self, s): + # Evaluation like Mul + terms = [] + for i, arg in enumerate(self.args): + # checking whether some tensor instance is differentiated + # or some other thing is necessary, but ugly + if isinstance(arg, TensExpr): + d = arg._eval_partial_derivative(s) + else: + # do not call diff is s is no symbol + if s._diff_wrt: + d = arg._eval_derivative(s) + else: + d = S.Zero + if d: + terms.append(TensMul.fromiter(self.args[:i] + (d,) + self.args[i + 1:]).doit(deep=False)) + return TensAdd.fromiter(terms).doit(deep=False) + + + def _matches_commutative(self, expr, repl_dict=None, old=False): + """ + Match assuming all tensors commute. But note that we are not assuming anything about their symmetry under index permutations. + """ + #Take care of the various possible types for expr. + if not isinstance(expr, TensMul): + if isinstance(expr, (TensExpr, Expr)): + expr = TensMul(expr) + else: + return None + + #The code that follows assumes expr is a TensMul + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + #Make sure that none of the dummy indices in self, expr conflict with the values already present in repl_dict. This may happen due to automatic index relabelling when rem_query and rem_expr are formed later on in this function (it calls itself recursively). + indices = [k for k in repl_dict.values() if isinstance(k ,TensorIndex)] + + def dedupe(expr): + renamed = TensMul._dedupe_indices(expr, indices) + if renamed is not None: + return renamed + else: + return expr + + self = dedupe(self) + expr = dedupe(expr) + + #Find the non-tensor part of expr. This need not be the same as expr.coeff when expr.doit() has not been called. + expr_coeff = reduce(lambda a, b: a*b, [arg for arg in expr.args if not isinstance(arg, TensExpr)], S.One) + + # handle simple patterns + if self == expr: + return repl_dict + + if len(_get_wilds(self)) == 0: + return self._matches_simple(expr, repl_dict, old) + + def siftkey(arg): + if isinstance(arg, WildTensor): + return "WildTensor" + elif isinstance(arg, (Tensor, TensExpr)): + return "Tensor" + else: + return "coeff" + + query_sifted = sift(self.args, siftkey) + expr_sifted = sift(expr.args, siftkey) + + #Sanity checks + if "coeff" in query_sifted.keys(): + if TensMul(*query_sifted["coeff"]).doit(deep=False) != self.coeff: + raise NotImplementedError(f"Found something that we do not know to handle: {query_sifted['coeff']}") + if "coeff" in expr_sifted.keys(): + if TensMul(*expr_sifted["coeff"]).doit(deep=False) != expr_coeff: + raise NotImplementedError(f"Found something that we do not know to handle: {expr_sifted['coeff']}") + + query_tens_heads = {tuple(getattr(x, "components", [])) for x in query_sifted["Tensor"]} #We use getattr because, e.g. TensAdd does not have the 'components' attribute. + expr_tens_heads = {tuple(getattr(x, "components", [])) for x in expr_sifted["Tensor"]} + if not query_tens_heads.issubset(expr_tens_heads): + #Some tensorheads in self are not present in the expr + return None + + #Try to match all non-wild tensors of self with tensors that compose expr + if len(query_sifted["Tensor"]) > 0: + q_tensor = query_sifted["Tensor"][0] + """ + We need to iterate over all possible symmetrized forms of q_tensor since the matches given by some of them may map dummy indices to free indices; the information about which indices are dummy/free will only be available later, when we are doing rem_q.matches(rem_e) + """ + for q_tens in q_tensor._get_symmetrized_forms(): + for e in expr_sifted["Tensor"]: + if isinstance(q_tens, TensMul): + #q_tensor got a minus sign due to this permutation. + sign = -1 + else: + sign = 1 + + """ + _matches is used here since we are already iterating over index permutations of q_tensor. Also note that the sign is removed from q_tensor, and will later be put into rem_q. + """ + m = (sign*q_tens)._matches(e) + if m is None: + continue + + rem_query = self.func(sign, *[a for a in self.args if a != q_tensor]).doit(deep=False) + rem_expr = expr.func(*[a for a in expr.args if a != e]).doit(deep=False) + tmp_repl = {} + tmp_repl.update(repl_dict) + tmp_repl.update(m) + rem_m = rem_query.matches(rem_expr, repl_dict=tmp_repl) + if rem_m is not None: + #Check that contracted indices are not mapped to different indices. + internally_consistent = True + for k in rem_m.keys(): + if isinstance(k,TensorIndex): + if -k in rem_m.keys() and rem_m[-k] != -rem_m[k]: + internally_consistent = False + break + if internally_consistent: + repl_dict.update(rem_m) + return repl_dict + + return None + + #Try to match WildTensor instances which have indices + matched_e_tensors = [] + remaining_e_tensors = expr_sifted["Tensor"] + indexless_wilds, wilds = sift(query_sifted["WildTensor"], lambda x: len(x.get_free_indices()) == 0, binary=True) + + for w in wilds: + free_this_wild = set(w.get_free_indices()) + tensors_to_try = [] + for t in remaining_e_tensors: + free = t.get_free_indices() + shares_indices_with_wild = True + for i in free: + if all(j.matches(i) is None for j in free_this_wild): + #The index i matches none of the indices in free_this_wild + shares_indices_with_wild = False + if shares_indices_with_wild: + tensors_to_try.append(t) + + m = w.matches(TensMul(*tensors_to_try).doit(deep=False) ) + if m is None: + return None + else: + for tens in tensors_to_try: + matched_e_tensors.append(tens) + repl_dict.update(m) + + #Try to match indexless WildTensor instances + remaining_e_tensors = [t for t in expr_sifted["Tensor"] if t not in matched_e_tensors] + if len(indexless_wilds) > 0: + #If there are any remaining tensors, match them with the indexless WildTensor + m = indexless_wilds[0].matches( TensMul(1,*remaining_e_tensors).doit(deep=False) ) + if m is None: + return None + else: + repl_dict.update(m) + elif len(remaining_e_tensors) > 0: + return None + + #Try to match the non-tensorial coefficient + m = self.coeff.matches(expr_coeff, old=old) + if m is None: + return None + else: + repl_dict.update(m) + + return repl_dict + + def matches(self, expr, repl_dict=None, old=False): + expr = sympify(expr) + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + commute = all(arg.component.comm == 0 for arg in expr.args if isinstance(arg, Tensor)) + if commute: + return self._matches_commutative(expr, repl_dict, old) + else: + raise NotImplementedError("Tensor matching not implemented for non-commuting tensors") + +class TensorElement(TensExpr): + """ + Tensor with evaluated components. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorSymmetry + >>> from sympy import symbols + >>> L = TensorIndexType("L") + >>> i, j, k = symbols("i j k") + >>> A = TensorHead("A", [L, L], TensorSymmetry.fully_symmetric(2)) + >>> A(i, j).get_free_indices() + [i, j] + + If we want to set component ``i`` to a specific value, use the + ``TensorElement`` class: + + >>> from sympy.tensor.tensor import TensorElement + >>> te = TensorElement(A(i, j), {i: 2}) + + As index ``i`` has been accessed (``{i: 2}`` is the evaluation of its 3rd + element), the free indices will only contain ``j``: + + >>> te.get_free_indices() + [j] + """ + + def __new__(cls, expr, index_map): + if not isinstance(expr, Tensor): + # remap + if not isinstance(expr, TensExpr): + raise TypeError("%s is not a tensor expression" % expr) + return expr.func(*[TensorElement(arg, index_map) for arg in expr.args]) + expr_free_indices = expr.get_free_indices() + name_translation = {i.args[0]: i for i in expr_free_indices} + index_map = {name_translation.get(index, index): value for index, value in index_map.items()} + index_map = {index: value for index, value in index_map.items() if index in expr_free_indices} + if len(index_map) == 0: + return expr + free_indices = [i for i in expr_free_indices if i not in index_map.keys()] + index_map = Dict(index_map) + obj = TensExpr.__new__(cls, expr, index_map) + obj._free_indices = free_indices + return obj + + @property + def free(self): + return [(index, i) for i, index in enumerate(self.get_free_indices())] + + @property + def dum(self): + # TODO: inherit dummies from expr + return [] + + @property + def expr(self): + return self._args[0] + + @property + def index_map(self): + return self._args[1] + + @property + def coeff(self): + return S.One + + @property + def nocoeff(self): + return self + + def get_free_indices(self): + return self._free_indices + + def _replace_indices(self, repl: dict[TensorIndex, TensorIndex]) -> TensExpr: + # TODO: can be improved: + return self.xreplace(repl) + + def get_indices(self): + return self.get_free_indices() + + def _extract_data(self, replacement_dict): + ret_indices, array = self.expr._extract_data(replacement_dict) + index_map = self.index_map + slice_tuple = tuple(index_map.get(i, slice(None)) for i in ret_indices) + ret_indices = [i for i in ret_indices if i not in index_map] + array = array.__getitem__(slice_tuple) + return ret_indices, array + + +class WildTensorHead(TensorHead): + """ + A wild object that is used to create ``WildTensor`` instances + + Explanation + =========== + + Examples + ======== + >>> from sympy.tensor.tensor import TensorHead, TensorIndex, WildTensorHead, TensorIndexType + >>> R3 = TensorIndexType('R3', dim=3) + >>> p = TensorIndex('p', R3) + >>> q = TensorIndex('q', R3) + + A WildTensorHead can be created without specifying a ``TensorIndexType`` + + >>> W = WildTensorHead("W") + + Calling it with a ``TensorIndex`` creates a ``WildTensor`` instance. + + >>> type(W(p)) + + + The ``TensorIndexType`` is automatically detected from the index that is passed + + >>> W(p).component + W(R3) + + Calling it with no indices returns an object that can match tensors with any number of indices. + + >>> K = TensorHead('K', [R3]) + >>> Q = TensorHead('Q', [R3, R3]) + >>> W().matches(K(p)) + {W: K(p)} + >>> W().matches(Q(p,q)) + {W: Q(p, q)} + + If you want to ignore the order of indices while matching, pass ``unordered_indices=True``. + + >>> U = WildTensorHead("U", unordered_indices=True) + >>> W(p,q).matches(Q(q,p)) + >>> U(p,q).matches(Q(q,p)) + {U(R3,R3): _WildTensExpr(Q(q, p))} + + Parameters + ========== + name : name of the tensor + unordered_indices : whether the order of the indices matters for matching + (default: False) + + See also + ======== + ``WildTensor`` + ``TensorHead`` + + """ + def __new__(cls, name, index_types=None, symmetry=None, comm=0, unordered_indices=False): + if isinstance(name, str): + name_symbol = Symbol(name) + elif isinstance(name, Symbol): + name_symbol = name + else: + raise ValueError("invalid name") + + if index_types is None: + index_types = [] + + if symmetry is None: + symmetry = TensorSymmetry.no_symmetry(len(index_types)) + else: + assert symmetry.rank == len(index_types) + + if symmetry != TensorSymmetry.no_symmetry(len(index_types)): + raise NotImplementedError("Wild matching based on symmetry is not implemented.") + + obj = Basic.__new__(cls, name_symbol, Tuple(*index_types), sympify(symmetry), sympify(comm), sympify(unordered_indices)) + + return obj + + @property + def unordered_indices(self): + return self.args[4] + + def __call__(self, *indices, **kwargs): + tensor = WildTensor(self, indices, **kwargs) + return tensor.doit() + + +class WildTensor(Tensor): + """ + A wild object which matches ``Tensor`` instances + + Explanation + =========== + This is instantiated by attaching indices to a ``WildTensorHead`` instance. + + Examples + ======== + >>> from sympy.tensor.tensor import TensorHead, TensorIndex, WildTensorHead, TensorIndexType + >>> W = WildTensorHead("W") + >>> R3 = TensorIndexType('R3', dim=3) + >>> p = TensorIndex('p', R3) + >>> q = TensorIndex('q', R3) + >>> K = TensorHead('K', [R3]) + >>> Q = TensorHead('Q', [R3, R3]) + + Matching also takes the indices into account + >>> W(p).matches(K(p)) + {W(R3): _WildTensExpr(K(p))} + >>> W(p).matches(K(q)) + >>> W(p).matches(K(-p)) + + If you want to match objects with any number of indices, just use a ``WildTensor`` with no indices. + >>> W().matches(K(p)) + {W: K(p)} + >>> W().matches(Q(p,q)) + {W: Q(p, q)} + + See Also + ======== + ``WildTensorHead`` + ``Tensor`` + + """ + def __new__(cls, tensor_head, indices, **kw_args): + is_canon_bp = kw_args.pop("is_canon_bp", False) + + if tensor_head.func == TensorHead: + """ + If someone tried to call WildTensor by supplying a TensorHead (not a WildTensorHead), return a normal tensor instead. This is helpful when using subs on an expression to replace occurrences of a WildTensorHead with a TensorHead. + """ + return Tensor(tensor_head, indices, is_canon_bp=is_canon_bp, **kw_args) + elif tensor_head.func == _WildTensExpr: + return tensor_head(*indices) + + indices = cls._parse_indices(tensor_head, indices) + index_types = [ind.tensor_index_type for ind in indices] + tensor_head = tensor_head.func( + tensor_head.name, + index_types, + symmetry=None, + comm=tensor_head.comm, + unordered_indices=tensor_head.unordered_indices, + ) + + obj = Basic.__new__(cls, tensor_head, Tuple(*indices)) + obj.name = tensor_head.name + obj._index_structure = _IndexStructure.from_indices(*indices) + obj._free = obj._index_structure.free[:] + obj._dum = obj._index_structure.dum[:] + obj._ext_rank = obj._index_structure._ext_rank + obj._coeff = S.One + obj._nocoeff = obj + obj._component = tensor_head + obj._components = [tensor_head] + if tensor_head.rank != len(indices): + raise ValueError("wrong number of indices") + obj.is_canon_bp = is_canon_bp + obj._index_map = obj._build_index_map(indices, obj._index_structure) + + return obj + + + def matches(self, expr, repl_dict=None, old=False): + if not isinstance(expr, TensExpr) and expr != S(1): + return None + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + if len(self.indices) > 0: + if not hasattr(expr, "get_free_indices"): + return None + expr_indices = expr.get_free_indices() + if len(expr_indices) != len(self.indices): + return None + if self._component.unordered_indices: + m = self._match_indices_ignoring_order(expr) + if m is None: + return None + else: + repl_dict.update(m) + else: + for i in range(len(expr_indices)): + m = self.indices[i].matches(expr_indices[i]) + if m is None: + return None + else: + repl_dict.update(m) + + repl_dict[self.component] = _WildTensExpr(expr) + else: + #If no indices were passed to the WildTensor, it may match tensors with any number of indices. + repl_dict[self] = expr + + return repl_dict + + def _match_indices_ignoring_order(self, expr, repl_dict=None, old=False): + """ + Helper method for matches. Checks if the indices of self and expr + match disregarding index ordering. + """ + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + def siftkey(ind): + if isinstance(ind, WildTensorIndex): + if ind.ignore_updown: + return "wild, updown" + else: + return "wild" + else: + return "nonwild" + + indices_sifted = sift(self.indices, siftkey) + + matched_indices = [] + expr_indices_remaining = expr.get_indices() + for ind in indices_sifted["nonwild"]: + matched_this_ind = False + for e_ind in expr_indices_remaining: + if e_ind in matched_indices: + continue + m = ind.matches(e_ind) + if m is not None: + matched_this_ind = True + repl_dict.update(m) + matched_indices.append(e_ind) + break + if not matched_this_ind: + return None + + expr_indices_remaining = [i for i in expr_indices_remaining if i not in matched_indices] + for ind in indices_sifted["wild"]: + matched_this_ind = False + for e_ind in expr_indices_remaining: + m = ind.matches(e_ind) + if m is not None: + if -ind in repl_dict.keys() and -repl_dict[-ind] != m[ind]: + return None + matched_this_ind = True + repl_dict.update(m) + matched_indices.append(e_ind) + break + if not matched_this_ind: + return None + + expr_indices_remaining = [i for i in expr_indices_remaining if i not in matched_indices] + for ind in indices_sifted["wild, updown"]: + matched_this_ind = False + for e_ind in expr_indices_remaining: + m = ind.matches(e_ind) + if m is not None: + if -ind in repl_dict.keys() and -repl_dict[-ind] != m[ind]: + return None + matched_this_ind = True + repl_dict.update(m) + matched_indices.append(e_ind) + break + if not matched_this_ind: + return None + + if len(matched_indices) < len(self.indices): + return None + else: + return repl_dict + +class WildTensorIndex(TensorIndex): + """ + A wild object that matches TensorIndex instances. + + Examples + ======== + >>> from sympy.tensor.tensor import TensorIndex, TensorIndexType, WildTensorIndex + >>> R3 = TensorIndexType('R3', dim=3) + >>> p = TensorIndex("p", R3) + + By default, covariant indices only match with covariant indices (and + similarly for contravariant) + + >>> q = WildTensorIndex("q", R3) + >>> (q).matches(p) + {q: p} + >>> (q).matches(-p) + + If you want matching to ignore whether the index is co/contra-variant, set + ignore_updown=True + + >>> r = WildTensorIndex("r", R3, ignore_updown=True) + >>> (r).matches(-p) + {r: -p} + >>> (r).matches(p) + {r: p} + + Parameters + ========== + name : name of the index (string), or ``True`` if you want it to be + automatically assigned + tensor_index_type : ``TensorIndexType`` of the index + is_up : flag for contravariant index (is_up=True by default) + ignore_updown : bool, Whether this should match both co- and contra-variant + indices (default:False) + """ + def __new__(cls, name, tensor_index_type, is_up=True, ignore_updown=False): + if isinstance(name, str): + name_symbol = Symbol(name) + elif isinstance(name, Symbol): + name_symbol = name + elif name is True: + name = "_i{}".format(len(tensor_index_type._autogenerated)) + name_symbol = Symbol(name) + tensor_index_type._autogenerated.append(name_symbol) + else: + raise ValueError("invalid name") + + is_up = sympify(is_up) + ignore_updown = sympify(ignore_updown) + return Basic.__new__(cls, name_symbol, tensor_index_type, is_up, ignore_updown) + + @property + def ignore_updown(self): + return self.args[3] + + def __neg__(self): + t1 = WildTensorIndex(self.name, self.tensor_index_type, + (not self.is_up), self.ignore_updown) + return t1 + + def matches(self, expr, repl_dict=None, old=False): + if not isinstance(expr, TensorIndex): + return None + if self.tensor_index_type != expr.tensor_index_type: + return None + if not self.ignore_updown: + if self.is_up != expr.is_up: + return None + + if repl_dict is None: + repl_dict = {} + else: + repl_dict = repl_dict.copy() + + repl_dict[self] = expr + return repl_dict + + +class _WildTensExpr(Basic): + """ + INTERNAL USE ONLY + + This is an object that helps with replacement of WildTensors in expressions. + When this object is set as the tensor_head of a WildTensor, it replaces the + WildTensor by a TensExpr (passed when initializing this object). + + Examples + ======== + >>> from sympy.tensor.tensor import WildTensorHead, TensorIndex, TensorHead, TensorIndexType + >>> W = WildTensorHead("W") + >>> R3 = TensorIndexType('R3', dim=3) + >>> p = TensorIndex('p', R3) + >>> q = TensorIndex('q', R3) + >>> K = TensorHead('K', [R3]) + >>> print( ( K(p) ).replace( W(p), W(q)*W(-q)*W(p) ) ) + K(R_0)*K(-R_0)*K(p) + + """ + def __init__(self, expr): + if not isinstance(expr, TensExpr): + raise TypeError("_WildTensExpr expects a TensExpr as argument") + self.expr = expr + + def __call__(self, *indices): + return self.expr._replace_indices(dict(zip(self.expr.get_free_indices(), indices))) + + def __neg__(self): + return self.func(self.expr*S.NegativeOne) + + def __abs__(self): + raise NotImplementedError + + def __add__(self, other): + if other.func != self.func: + raise TypeError(f"Cannot add {self.func} to {other.func}") + return self.func(self.expr+other.expr) + + def __radd__(self, other): + if other.func != self.func: + raise TypeError(f"Cannot add {self.func} to {other.func}") + return self.func(other.expr+self.expr) + + def __sub__(self, other): + return self + (-other) + + def __rsub__(self, other): + return other + (-self) + + def __mul__(self, other): + raise NotImplementedError + + def __rmul__(self, other): + raise NotImplementedError + + def __truediv__(self, other): + raise NotImplementedError + + def __rtruediv__(self, other): + raise NotImplementedError + + def __pow__(self, other): + raise NotImplementedError + + def __rpow__(self, other): + raise NotImplementedError + + +def canon_bp(p): + """ + Butler-Portugal canonicalization. See ``tensor_can.py`` from the + combinatorics module for the details. + """ + if isinstance(p, TensExpr): + return p.canon_bp() + return p + + +def tensor_mul(*a): + """ + product of tensors + """ + if not a: + return TensMul.from_data(S.One, [], [], []) + t = a[0] + for tx in a[1:]: + t = t*tx + return t + + +def riemann_cyclic_replace(t_r): + """ + replace Riemann tensor with an equivalent expression + + ``R(m,n,p,q) -> 2/3*R(m,n,p,q) - 1/3*R(m,q,n,p) + 1/3*R(m,p,n,q)`` + + """ + free = sorted(t_r.free, key=lambda x: x[1]) + m, n, p, q = [x[0] for x in free] + t0 = t_r*Rational(2, 3) + t1 = -t_r.substitute_indices((m,m),(n,q),(p,n),(q,p))*Rational(1, 3) + t2 = t_r.substitute_indices((m,m),(n,p),(p,n),(q,q))*Rational(1, 3) + t3 = t0 + t1 + t2 + return t3 + +def riemann_cyclic(t2): + """ + Replace each Riemann tensor with an equivalent expression + satisfying the cyclic identity. + + This trick is discussed in the reference guide to Cadabra. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, riemann_cyclic, TensorSymmetry + >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') + >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) + >>> R = TensorHead('R', [Lorentz]*4, TensorSymmetry.riemann()) + >>> t = R(i,j,k,l)*(R(-i,-j,-k,-l) - 2*R(-i,-k,-j,-l)) + >>> riemann_cyclic(t) + 0 + """ + t2 = t2.expand() + if isinstance(t2, (TensMul, Tensor)): + args = [t2] + else: + args = t2.args + a1 = [x.split() for x in args] + a2 = [[riemann_cyclic_replace(tx) for tx in y] for y in a1] + a3 = [tensor_mul(*v) for v in a2] + t3 = TensAdd(*a3).doit(deep=False) + if not t3: + return t3 + else: + return canon_bp(t3) + + +def get_lines(ex, index_type): + """ + Returns ``(lines, traces, rest)`` for an index type, + where ``lines`` is the list of list of positions of a matrix line, + ``traces`` is the list of list of traced matrix lines, + ``rest`` is the rest of the elements of the tensor. + """ + def _join_lines(a): + i = 0 + while i < len(a): + x = a[i] + xend = x[-1] + xstart = x[0] + hit = True + while hit: + hit = False + for j in range(i + 1, len(a)): + if j >= len(a): + break + if a[j][0] == xend: + hit = True + x.extend(a[j][1:]) + xend = x[-1] + a.pop(j) + continue + if a[j][0] == xstart: + hit = True + a[i] = reversed(a[j][1:]) + x + x = a[i] + xstart = a[i][0] + a.pop(j) + continue + if a[j][-1] == xend: + hit = True + x.extend(reversed(a[j][:-1])) + xend = x[-1] + a.pop(j) + continue + if a[j][-1] == xstart: + hit = True + a[i] = a[j][:-1] + x + x = a[i] + xstart = x[0] + a.pop(j) + continue + i += 1 + return a + + arguments = ex.args + dt = {} + for c in ex.args: + if not isinstance(c, TensExpr): + continue + if c in dt: + continue + index_types = c.index_types + a = [] + for i in range(len(index_types)): + if index_types[i] is index_type: + a.append(i) + if len(a) > 2: + raise ValueError('at most two indices of type %s allowed' % index_type) + if len(a) == 2: + dt[c] = a + #dum = ex.dum + lines = [] + traces = [] + traces1 = [] + #indices_to_args_pos = ex._get_indices_to_args_pos() + # TODO: add a dum_to_components_map ? + for p0, p1, c0, c1 in ex.dum_in_args: + if arguments[c0] not in dt: + continue + if c0 == c1: + traces.append([c0]) + continue + ta0 = dt[arguments[c0]] + ta1 = dt[arguments[c1]] + if p0 not in ta0: + continue + if ta0.index(p0) == ta1.index(p1): + # case gamma(i,s0,-s1) in c0, gamma(j,-s0,s2) in c1; + # to deal with this case one could add to the position + # a flag for transposition; + # one could write [(c0, False), (c1, True)] + raise NotImplementedError + # if p0 == ta0[1] then G in pos c0 is mult on the right by G in c1 + # if p0 == ta0[0] then G in pos c1 is mult on the right by G in c0 + ta0 = dt[arguments[c0]] + b0, b1 = (c0, c1) if p0 == ta0[1] else (c1, c0) + lines1 = lines.copy() + for line in lines: + if line[-1] == b0: + if line[0] == b1: + n = line.index(min(line)) + traces1.append(line) + traces.append(line[n:] + line[:n]) + else: + line.append(b1) + break + elif line[0] == b1: + line.insert(0, b0) + break + else: + lines1.append([b0, b1]) + + lines = [x for x in lines1 if x not in traces1] + lines = _join_lines(lines) + rest = [] + for line in lines: + for y in line: + rest.append(y) + for line in traces: + for y in line: + rest.append(y) + rest = [x for x in range(len(arguments)) if x not in rest] + + return lines, traces, rest + + +def get_free_indices(t): + if not isinstance(t, TensExpr): + return () + return t.get_free_indices() + + +def get_indices(t): + if not isinstance(t, TensExpr): + return () + return t.get_indices() + +def get_dummy_indices(t): + if not isinstance(t, TensExpr): + return () + inds = t.get_indices() + free = t.get_free_indices() + return [i for i in inds if i not in free] + +def get_index_structure(t): + if isinstance(t, TensExpr): + return t._index_structure + return _IndexStructure([], [], [], []) + + +def get_coeff(t): + if isinstance(t, Tensor): + return S.One + if isinstance(t, TensMul): + return t.coeff + if isinstance(t, TensExpr): + raise ValueError("no coefficient associated to this tensor expression") + return t + +def contract_metric(t, g): + if isinstance(t, TensExpr): + return t.contract_metric(g) + return t + +def perm2tensor(t, g, is_canon_bp=False): + """ + Returns the tensor corresponding to the permutation ``g`` + + For further details, see the method in ``TIDS`` with the same name. + """ + if not isinstance(t, TensExpr): + return t + elif isinstance(t, (Tensor, TensMul)): + nim = get_index_structure(t).perm2tensor(g, is_canon_bp=is_canon_bp) + res = t._set_new_index_structure(nim, is_canon_bp=is_canon_bp) + if g[-1] != len(g) - 1: + return -res + + return res + raise NotImplementedError() + + +def substitute_indices(t, *index_tuples): + if not isinstance(t, TensExpr): + return t + return t.substitute_indices(*index_tuples) + + +def _get_wilds(expr): + return list(expr.atoms(Wild, WildFunction, WildTensor, WildTensorIndex, WildTensorHead)) + + +def get_postprocessor(cls): + def _postprocessor(expr): + tens_class = {Mul: TensMul, Add: TensAdd}[cls] + if any(isinstance(a, TensExpr) for a in expr.args): + return tens_class(*expr.args) + else: + return expr + + return _postprocessor + +Basic._constructor_postprocessor_mapping[TensExpr] = { + "Mul": [get_postprocessor(Mul)], +} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/toperators.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/toperators.py new file mode 100644 index 0000000000000000000000000000000000000000..1bdd67c4f4a7e86b9821ee55b1d2f9bde29c96a8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/tensor/toperators.py @@ -0,0 +1,256 @@ +from sympy import permutedims +from sympy.core.numbers import Number +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.tensor.tensor import Tensor, TensExpr, TensAdd, TensMul + + +class PartialDerivative(TensExpr): + """ + Partial derivative for tensor expressions. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, TensorHead + >>> from sympy.tensor.toperators import PartialDerivative + >>> from sympy import symbols + >>> L = TensorIndexType("L") + >>> A = TensorHead("A", [L]) + >>> B = TensorHead("B", [L]) + >>> i, j, k = symbols("i j k") + + >>> expr = PartialDerivative(A(i), A(j)) + >>> expr + PartialDerivative(A(i), A(j)) + + The ``PartialDerivative`` object behaves like a tensorial expression: + + >>> expr.get_indices() + [i, -j] + + Notice that the deriving variables have opposite valence than the + printed one: ``A(j)`` is printed as covariant, but the index of the + derivative is actually contravariant, i.e. ``-j``. + + Indices can be contracted: + + >>> expr = PartialDerivative(A(i), A(i)) + >>> expr + PartialDerivative(A(L_0), A(L_0)) + >>> expr.get_indices() + [L_0, -L_0] + + The method ``.get_indices()`` always returns all indices (even the + contracted ones). If only uncontracted indices are needed, call + ``.get_free_indices()``: + + >>> expr.get_free_indices() + [] + + Nested partial derivatives are flattened: + + >>> expr = PartialDerivative(PartialDerivative(A(i), A(j)), A(k)) + >>> expr + PartialDerivative(A(i), A(j), A(k)) + >>> expr.get_indices() + [i, -j, -k] + + Replace a derivative with array values: + + >>> from sympy.abc import x, y + >>> from sympy import sin, log + >>> compA = [sin(x), log(x)*y**3] + >>> compB = [x, y] + >>> expr = PartialDerivative(A(i), B(j)) + >>> expr.replace_with_arrays({A(i): compA, B(i): compB}) + [[cos(x), 0], [y**3/x, 3*y**2*log(x)]] + + The returned array is indexed by `(i, -j)`. + + Be careful that other SymPy modules put the indices of the deriving + variables before the indices of the derivand in the derivative result. + For example: + + >>> expr.get_free_indices() + [i, -j] + + >>> from sympy import Matrix, Array + >>> Matrix(compA).diff(Matrix(compB)).reshape(2, 2) + [[cos(x), y**3/x], [0, 3*y**2*log(x)]] + >>> Array(compA).diff(Array(compB)) + [[cos(x), y**3/x], [0, 3*y**2*log(x)]] + + These are the transpose of the result of ``PartialDerivative``, + as the matrix and the array modules put the index `-j` before `i` in the + derivative result. An array read with index order `(-j, i)` is indeed the + transpose of the same array read with index order `(i, -j)`. By specifying + the index order to ``.replace_with_arrays`` one can get a compatible + expression: + + >>> expr.replace_with_arrays({A(i): compA, B(i): compB}, [-j, i]) + [[cos(x), y**3/x], [0, 3*y**2*log(x)]] + """ + + def __new__(cls, expr, *variables): + + # Flatten: + if isinstance(expr, PartialDerivative): + variables = expr.variables + variables + expr = expr.expr + + args, indices, free, dum = cls._contract_indices_for_derivative( + S(expr), variables) + + obj = TensExpr.__new__(cls, *args) + + obj._indices = indices + obj._free = free + obj._dum = dum + return obj + + @property + def coeff(self): + return S.One + + @property + def nocoeff(self): + return self + + @classmethod + def _contract_indices_for_derivative(cls, expr, variables): + variables_opposite_valence = [] + + for i in variables: + if isinstance(i, Tensor): + i_free_indices = i.get_free_indices() + variables_opposite_valence.append( + i.xreplace({k: -k for k in i_free_indices})) + elif isinstance(i, Symbol): + variables_opposite_valence.append(i) + + args, indices, free, dum = TensMul._tensMul_contract_indices( + [expr] + variables_opposite_valence, replace_indices=True) + + for i in range(1, len(args)): + args_i = args[i] + if isinstance(args_i, Tensor): + i_indices = args[i].get_free_indices() + args[i] = args[i].xreplace({k: -k for k in i_indices}) + + return args, indices, free, dum + + def doit(self, **hints): + args, indices, free, dum = self._contract_indices_for_derivative(self.expr, self.variables) + + obj = self.func(*args) + obj._indices = indices + obj._free = free + obj._dum = dum + + return obj + + def _expand_partial_derivative(self): + args, indices, free, dum = self._contract_indices_for_derivative(self.expr, self.variables) + + obj = self.func(*args) + obj._indices = indices + obj._free = free + obj._dum = dum + + result = obj + + if not args[0].free_symbols: + return S.Zero + elif isinstance(obj.expr, TensAdd): + # take care of sums of multi PDs + result = obj.expr.func(*[ + self.func(a, *obj.variables)._expand_partial_derivative() + for a in result.expr.args]) + elif isinstance(obj.expr, TensMul): + # take care of products of multi PDs + if len(obj.variables) == 1: + # derivative with respect to single variable + terms = [] + mulargs = list(obj.expr.args) + for ind in range(len(mulargs)): + if not isinstance(sympify(mulargs[ind]), Number): + # a number coefficient is not considered for + # expansion of PartialDerivative + d = self.func(mulargs[ind], *obj.variables)._expand_partial_derivative() + terms.append(TensMul(*(mulargs[:ind] + + [d] + + mulargs[(ind + 1):]))) + result = TensAdd.fromiter(terms) + else: + # derivative with respect to multiple variables + # decompose: + # partial(expr, (u, v)) + # = partial(partial(expr, u).doit(), v).doit() + result = obj.expr # init with expr + for v in obj.variables: + result = self.func(result, v)._expand_partial_derivative() + # then throw PD on it + + return result + + def _perform_derivative(self): + result = self.expr + for v in self.variables: + if isinstance(result, TensExpr): + result = result._eval_partial_derivative(v) + else: + if v._diff_wrt: + result = result._eval_derivative(v) + else: + result = S.Zero + return result + + def get_indices(self): + return self._indices + + def get_free_indices(self): + free = sorted(self._free, key=lambda x: x[1]) + return [i[0] for i in free] + + def _replace_indices(self, repl): + expr = self.expr.xreplace(repl) + mirrored = {-k: -v for k, v in repl.items()} + variables = [i.xreplace(mirrored) for i in self.variables] + return self.func(expr, *variables) + + @property + def expr(self): + return self.args[0] + + @property + def variables(self): + return self.args[1:] + + def _extract_data(self, replacement_dict): + from .array import derive_by_array, tensorcontraction + indices, array = self.expr._extract_data(replacement_dict) + for variable in self.variables: + var_indices, var_array = variable._extract_data(replacement_dict) + var_indices = [-i for i in var_indices] + coeff_array, var_array = zip(*[i.as_coeff_Mul() for i in var_array]) + dim_before = len(array.shape) + array = derive_by_array(array, var_array) + dim_after = len(array.shape) + dim_increase = dim_after - dim_before + array = permutedims(array, [i + dim_increase for i in range(dim_before)] + list(range(dim_increase))) + array = array.as_mutable() + varindex = var_indices[0] + # Remove coefficients of base vector: + coeff_index = [0] + [slice(None) for i in range(len(indices))] + for i, coeff in enumerate(coeff_array): + coeff_index[0] = i + array[tuple(coeff_index)] /= coeff + if -varindex in indices: + pos = indices.index(-varindex) + array = tensorcontraction(array, (0, pos+1)) + indices.pop(pos) + else: + indices.append(varindex) + return indices, array diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..aa66402955e7d5d2b27cccc6627b42d33f4cd855 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/__init__.py @@ -0,0 +1,10 @@ +"""This module contains code for running the tests in SymPy.""" + + +from .runtests import doctest +from .runtests_pytest import test + + +__all__ = [ + 'test', 'doctest', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/matrices.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/matrices.py new file mode 100644 index 0000000000000000000000000000000000000000..236a384366df7f69d0d92f43f7e007e95c12388c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/matrices.py @@ -0,0 +1,8 @@ +def allclose(A, B, rtol=1e-05, atol=1e-08): + if len(A) != len(B): + return False + + for x, y in zip(A, B): + if abs(x-y) > atol + rtol * max(abs(x), abs(y)): + return False + return True diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/pytest.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/pytest.py new file mode 100644 index 0000000000000000000000000000000000000000..498515a2d3c0a167a5f7067753736898cfa64799 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/pytest.py @@ -0,0 +1,392 @@ +"""py.test hacks to support XFAIL/XPASS""" + +import platform +import sys +import re +import functools +import os +import contextlib +import warnings +import inspect +import pathlib +from typing import Any, Callable + +from sympy.utilities.exceptions import SymPyDeprecationWarning +# Imported here for backwards compatibility. Note: do not import this from +# here in library code (importing sympy.pytest in library code will break the +# pytest integration). +from sympy.utilities.exceptions import ignore_warnings # noqa:F401 + +ON_CI = os.getenv('CI', None) == "true" + +try: + import pytest + USE_PYTEST = getattr(sys, '_running_pytest', False) +except ImportError: + USE_PYTEST = False + +IS_WASM: bool = sys.platform == 'emscripten' or platform.machine() in ["wasm32", "wasm64"] + +raises: Callable[[Any, Any], Any] +XFAIL: Callable[[Any], Any] +skip: Callable[[Any], Any] +SKIP: Callable[[Any], Any] +slow: Callable[[Any], Any] +tooslow: Callable[[Any], Any] +nocache_fail: Callable[[Any], Any] + + +if USE_PYTEST: + raises = pytest.raises + skip = pytest.skip + XFAIL = pytest.mark.xfail + SKIP = pytest.mark.skip + slow = pytest.mark.slow + tooslow = pytest.mark.tooslow + nocache_fail = pytest.mark.nocache_fail + from _pytest.outcomes import Failed + +else: + # Not using pytest so define the things that would have been imported from + # there. + + # _pytest._code.code.ExceptionInfo + class ExceptionInfo: + def __init__(self, value): + self.value = value + + def __repr__(self): + return "".format(self.value) + + + def raises(expectedException, code=None): + """ + Tests that ``code`` raises the exception ``expectedException``. + + ``code`` may be a callable, such as a lambda expression or function + name. + + If ``code`` is not given or None, ``raises`` will return a context + manager for use in ``with`` statements; the code to execute then + comes from the scope of the ``with``. + + ``raises()`` does nothing if the callable raises the expected exception, + otherwise it raises an AssertionError. + + Examples + ======== + + >>> from sympy.testing.pytest import raises + + >>> raises(ZeroDivisionError, lambda: 1/0) + + >>> raises(ZeroDivisionError, lambda: 1/2) + Traceback (most recent call last): + ... + Failed: DID NOT RAISE + + >>> with raises(ZeroDivisionError): + ... n = 1/0 + >>> with raises(ZeroDivisionError): + ... n = 1/2 + Traceback (most recent call last): + ... + Failed: DID NOT RAISE + + Note that you cannot test multiple statements via + ``with raises``: + + >>> with raises(ZeroDivisionError): + ... n = 1/0 # will execute and raise, aborting the ``with`` + ... n = 9999/0 # never executed + + This is just what ``with`` is supposed to do: abort the + contained statement sequence at the first exception and let + the context manager deal with the exception. + + To test multiple statements, you'll need a separate ``with`` + for each: + + >>> with raises(ZeroDivisionError): + ... n = 1/0 # will execute and raise + >>> with raises(ZeroDivisionError): + ... n = 9999/0 # will also execute and raise + + """ + if code is None: + return RaisesContext(expectedException) + elif callable(code): + try: + code() + except expectedException as e: + return ExceptionInfo(e) + raise Failed("DID NOT RAISE") + elif isinstance(code, str): + raise TypeError( + '\'raises(xxx, "code")\' has been phased out; ' + 'change \'raises(xxx, "expression")\' ' + 'to \'raises(xxx, lambda: expression)\', ' + '\'raises(xxx, "statement")\' ' + 'to \'with raises(xxx): statement\'') + else: + raise TypeError( + 'raises() expects a callable for the 2nd argument.') + + class RaisesContext: + def __init__(self, expectedException): + self.expectedException = expectedException + + def __enter__(self): + return None + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is None: + raise Failed("DID NOT RAISE") + return issubclass(exc_type, self.expectedException) + + class XFail(Exception): + pass + + class XPass(Exception): + pass + + class Skipped(Exception): + pass + + class Failed(Exception): # type: ignore + pass + + def XFAIL(func): + def wrapper(): + try: + func() + except Exception as e: + message = str(e) + if message != "Timeout": + raise XFail(func.__name__) + else: + raise Skipped("Timeout") + raise XPass(func.__name__) + + wrapper = functools.update_wrapper(wrapper, func) + return wrapper + + def skip(str): + raise Skipped(str) + + def SKIP(reason): + """Similar to ``skip()``, but this is a decorator. """ + def wrapper(func): + def func_wrapper(): + raise Skipped(reason) + + func_wrapper = functools.update_wrapper(func_wrapper, func) + return func_wrapper + + return wrapper + + def slow(func): + func._slow = True + + def func_wrapper(): + func() + + func_wrapper = functools.update_wrapper(func_wrapper, func) + func_wrapper.__wrapped__ = func + return func_wrapper + + def tooslow(func): + func._slow = True + func._tooslow = True + + def func_wrapper(): + skip("Too slow") + + func_wrapper = functools.update_wrapper(func_wrapper, func) + func_wrapper.__wrapped__ = func + return func_wrapper + + def nocache_fail(func): + "Dummy decorator for marking tests that fail when cache is disabled" + return func + +@contextlib.contextmanager +def warns(warningcls, *, match='', test_stacklevel=True): + ''' + Like raises but tests that warnings are emitted. + + >>> from sympy.testing.pytest import warns + >>> import warnings + + >>> with warns(UserWarning): + ... warnings.warn('deprecated', UserWarning, stacklevel=2) + + >>> with warns(UserWarning): + ... pass + Traceback (most recent call last): + ... + Failed: DID NOT WARN. No warnings of type UserWarning\ + was emitted. The list of emitted warnings is: []. + + ``test_stacklevel`` makes it check that the ``stacklevel`` parameter to + ``warn()`` is set so that the warning shows the user line of code (the + code under the warns() context manager). Set this to False if this is + ambiguous or if the context manager does not test the direct user code + that emits the warning. + + If the warning is a ``SymPyDeprecationWarning``, this additionally tests + that the ``active_deprecations_target`` is a real target in the + ``active-deprecations.md`` file. + + ''' + # Absorbs all warnings in warnrec + with warnings.catch_warnings(record=True) as warnrec: + # Any warning other than the one we are looking for is an error + warnings.simplefilter("error") + warnings.filterwarnings("always", category=warningcls) + # Now run the test + yield warnrec + + # Raise if expected warning not found + if not any(issubclass(w.category, warningcls) for w in warnrec): + msg = ('Failed: DID NOT WARN.' + ' No warnings of type %s was emitted.' + ' The list of emitted warnings is: %s.' + ) % (warningcls, [w.message for w in warnrec]) + raise Failed(msg) + + # We don't include the match in the filter above because it would then + # fall to the error filter, so we instead manually check that it matches + # here + for w in warnrec: + # Should always be true due to the filters above + assert issubclass(w.category, warningcls) + if not re.compile(match, re.IGNORECASE).match(str(w.message)): + raise Failed(f"Failed: WRONG MESSAGE. A warning with of the correct category ({warningcls.__name__}) was issued, but it did not match the given match regex ({match!r})") + + if test_stacklevel: + for f in inspect.stack(): + thisfile = f.filename + file = os.path.split(thisfile)[1] + if file.startswith('test_'): + break + elif file == 'doctest.py': + # skip the stacklevel testing in the doctests of this + # function + return + else: + raise RuntimeError("Could not find the file for the given warning to test the stacklevel") + for w in warnrec: + if w.filename != thisfile: + msg = f'''\ +Failed: Warning has the wrong stacklevel. The warning stacklevel needs to be +set so that the line of code shown in the warning message is user code that +calls the deprecated code (the current stacklevel is showing code from +{w.filename} (line {w.lineno}), expected {thisfile})'''.replace('\n', ' ') + raise Failed(msg) + + if warningcls == SymPyDeprecationWarning: + this_file = pathlib.Path(__file__) + active_deprecations_file = (this_file.parent.parent.parent / 'doc' / + 'src' / 'explanation' / + 'active-deprecations.md') + if not active_deprecations_file.exists(): + # We can only test that the active_deprecations_target works if we are + # in the git repo. + return + targets = [] + for w in warnrec: + targets.append(w.message.active_deprecations_target) + text = pathlib.Path(active_deprecations_file).read_text(encoding="utf-8") + for target in targets: + if f'({target})=' not in text: + raise Failed(f"The active deprecations target {target!r} does not appear to be a valid target in the active-deprecations.md file ({active_deprecations_file}).") + +def _both_exp_pow(func): + """ + Decorator used to run the test twice: the first time `e^x` is represented + as ``Pow(E, x)``, the second time as ``exp(x)`` (exponential object is not + a power). + + This is a temporary trick helping to manage the elimination of the class + ``exp`` in favor of a replacement by ``Pow(E, ...)``. + """ + from sympy.core.parameters import _exp_is_pow + + def func_wrap(): + with _exp_is_pow(True): + func() + with _exp_is_pow(False): + func() + + wrapper = functools.update_wrapper(func_wrap, func) + return wrapper + + +@contextlib.contextmanager +def warns_deprecated_sympy(): + ''' + Shorthand for ``warns(SymPyDeprecationWarning)`` + + This is the recommended way to test that ``SymPyDeprecationWarning`` is + emitted for deprecated features in SymPy. To test for other warnings use + ``warns``. To suppress warnings without asserting that they are emitted + use ``ignore_warnings``. + + .. note:: + + ``warns_deprecated_sympy()`` is only intended for internal use in the + SymPy test suite to test that a deprecation warning triggers properly. + All other code in the SymPy codebase, including documentation examples, + should not use deprecated behavior. + + If you are a user of SymPy and you want to disable + SymPyDeprecationWarnings, use ``warnings`` filters (see + :ref:`silencing-sympy-deprecation-warnings`). + + >>> from sympy.testing.pytest import warns_deprecated_sympy + >>> from sympy.utilities.exceptions import sympy_deprecation_warning + >>> with warns_deprecated_sympy(): + ... sympy_deprecation_warning("Don't use", + ... deprecated_since_version="1.0", + ... active_deprecations_target="active-deprecations") + + >>> with warns_deprecated_sympy(): + ... pass + Traceback (most recent call last): + ... + Failed: DID NOT WARN. No warnings of type \ + SymPyDeprecationWarning was emitted. The list of emitted warnings is: []. + + .. note:: + + Sometimes the stacklevel test will fail because the same warning is + emitted multiple times. In this case, you can use + :func:`sympy.utilities.exceptions.ignore_warnings` in the code to + prevent the ``SymPyDeprecationWarning`` from being emitted again + recursively. In rare cases it is impossible to have a consistent + ``stacklevel`` for deprecation warnings because different ways of + calling a function will produce different call stacks.. In those cases, + use ``warns(SymPyDeprecationWarning)`` instead. + + See Also + ======== + sympy.utilities.exceptions.SymPyDeprecationWarning + sympy.utilities.exceptions.sympy_deprecation_warning + sympy.utilities.decorator.deprecated + + ''' + with warns(SymPyDeprecationWarning): + yield + + +def skip_under_pyodide(message): + """Decorator to skip a test if running under Pyodide/WASM.""" + def decorator(test_func): + @functools.wraps(test_func) + def test_wrapper(): + if IS_WASM: + skip(message) + return test_func() + return test_wrapper + return decorator diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/quality_unicode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/quality_unicode.py new file mode 100644 index 0000000000000000000000000000000000000000..d43623ff5112610e377347f50c6a40a15810644b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/quality_unicode.py @@ -0,0 +1,102 @@ +import re +import fnmatch + + +message_unicode_B = \ + "File contains a unicode character : %s, line %s. " \ + "But not in the whitelist. " \ + "Add the file to the whitelist in " + __file__ +message_unicode_D = \ + "File does not contain a unicode character : %s." \ + "but is in the whitelist. " \ + "Remove the file from the whitelist in " + __file__ + + +encoding_header_re = re.compile( + r'^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)') + +# Whitelist pattern for files which can have unicode. +unicode_whitelist = [ + # Author names can include non-ASCII characters + r'*/bin/authors_update.py', + r'*/bin/mailmap_check.py', + + # These files have functions and test functions for unicode input and + # output. + r'*/sympy/testing/tests/test_code_quality.py', + r'*/sympy/physics/vector/tests/test_printing.py', + r'*/physics/quantum/tests/test_printing.py', + r'*/sympy/vector/tests/test_printing.py', + r'*/sympy/parsing/tests/test_sympy_parser.py', + r'*/sympy/printing/pretty/stringpict.py', + r'*/sympy/printing/pretty/tests/test_pretty.py', + r'*/sympy/printing/tests/test_conventions.py', + r'*/sympy/printing/tests/test_preview.py', + r'*/liealgebras/type_g.py', + r'*/liealgebras/weyl_group.py', + r'*/liealgebras/tests/test_type_G.py', + + # wigner.py and polarization.py have unicode doctests. These probably + # don't need to be there but some of the examples that are there are + # pretty ugly without use_unicode (matrices need to be wrapped across + # multiple lines etc) + r'*/sympy/physics/wigner.py', + r'*/sympy/physics/optics/polarization.py', + + # joint.py uses some unicode for variable names in the docstrings + r'*/sympy/physics/mechanics/joint.py', + + # lll method has unicode in docstring references and author name + r'*/sympy/polys/matrices/domainmatrix.py', + r'*/sympy/matrices/repmatrix.py', + + # Explanation of symbols uses greek letters + r'*/sympy/core/symbol.py', +] + +unicode_strict_whitelist = [ + r'*/sympy/parsing/latex/_antlr/__init__.py', + # test_mathematica.py uses some unicode for testing Greek characters are working #24055 + r'*/sympy/parsing/tests/test_mathematica.py', +] + + +def _test_this_file_encoding( + fname, test_file, + unicode_whitelist=unicode_whitelist, + unicode_strict_whitelist=unicode_strict_whitelist): + """Test helper function for unicode test + + The test may have to operate on filewise manner, so it had moved + to a separate process. + """ + has_unicode = False + + is_in_whitelist = False + is_in_strict_whitelist = False + for patt in unicode_whitelist: + if fnmatch.fnmatch(fname, patt): + is_in_whitelist = True + break + for patt in unicode_strict_whitelist: + if fnmatch.fnmatch(fname, patt): + is_in_strict_whitelist = True + is_in_whitelist = True + break + + if is_in_whitelist: + for idx, line in enumerate(test_file): + try: + line.encode(encoding='ascii') + except (UnicodeEncodeError, UnicodeDecodeError): + has_unicode = True + + if not has_unicode and not is_in_strict_whitelist: + assert False, message_unicode_D % fname + + else: + for idx, line in enumerate(test_file): + try: + line.encode(encoding='ascii') + except (UnicodeEncodeError, UnicodeDecodeError): + assert False, message_unicode_B % (fname, idx + 1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/randtest.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/randtest.py new file mode 100644 index 0000000000000000000000000000000000000000..3ce2c8c031eec1c886532daba32c96d83e9cf85c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/randtest.py @@ -0,0 +1,19 @@ +""" +.. deprecated:: 1.10 + + ``sympy.testing.randtest`` functions have been moved to + :mod:`sympy.core.random`. + +""" +from sympy.utilities.exceptions import sympy_deprecation_warning + +sympy_deprecation_warning("The sympy.testing.randtest submodule is deprecated. Use sympy.core.random instead.", + deprecated_since_version="1.10", + active_deprecations_target="deprecated-sympy-testing-randtest") + +from sympy.core.random import ( # noqa:F401 + random_complex_number, + verify_numerically, + test_derivative_numerically, + _randrange, + _randint) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/runtests.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/runtests.py new file mode 100644 index 0000000000000000000000000000000000000000..e2650e4e6dabaaa07fc25c76cce3d9d28723b0d5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/runtests.py @@ -0,0 +1,2409 @@ +""" +This is our testing framework. + +Goals: + +* it should be compatible with py.test and operate very similarly + (or identically) +* does not require any external dependencies +* preferably all the functionality should be in this file only +* no magic, just import the test file and execute the test functions, that's it +* portable + +""" + +import os +import sys +import platform +import inspect +import traceback +import pdb +import re +import linecache +import time +from fnmatch import fnmatch +from timeit import default_timer as clock +import doctest as pdoctest # avoid clashing with our doctest() function +from doctest import DocTestFinder, DocTestRunner +import random +import subprocess +import shutil +import signal +import stat +import tempfile +import warnings +from contextlib import contextmanager +from inspect import unwrap +from pathlib import Path + +from sympy.core.cache import clear_cache +from sympy.external import import_module +from sympy.external.gmpy import GROUND_TYPES + +IS_WINDOWS = (os.name == 'nt') +ON_CI = os.getenv('CI', None) + +# empirically generated list of the proportion of time spent running +# an even split of tests. This should periodically be regenerated. +# A list of [.6, .1, .3] would mean that if the tests are evenly split +# into '1/3', '2/3', '3/3', the first split would take 60% of the time, +# the second 10% and the third 30%. These lists are normalized to sum +# to 1, so [60, 10, 30] has the same behavior as [6, 1, 3] or [.6, .1, .3]. +# +# This list can be generated with the code: +# from time import time +# import sympy +# import os +# os.environ["CI"] = 'true' # Mock CI to get more correct densities +# delays, num_splits = [], 30 +# for i in range(1, num_splits + 1): +# tic = time() +# sympy.test(split='{}/{}'.format(i, num_splits), time_balance=False) # Add slow=True for slow tests +# delays.append(time() - tic) +# tot = sum(delays) +# print([round(x / tot, 4) for x in delays]) +SPLIT_DENSITY = [ + 0.0059, 0.0027, 0.0068, 0.0011, 0.0006, + 0.0058, 0.0047, 0.0046, 0.004, 0.0257, + 0.0017, 0.0026, 0.004, 0.0032, 0.0016, + 0.0015, 0.0004, 0.0011, 0.0016, 0.0014, + 0.0077, 0.0137, 0.0217, 0.0074, 0.0043, + 0.0067, 0.0236, 0.0004, 0.1189, 0.0142, + 0.0234, 0.0003, 0.0003, 0.0047, 0.0006, + 0.0013, 0.0004, 0.0008, 0.0007, 0.0006, + 0.0139, 0.0013, 0.0007, 0.0051, 0.002, + 0.0004, 0.0005, 0.0213, 0.0048, 0.0016, + 0.0012, 0.0014, 0.0024, 0.0015, 0.0004, + 0.0005, 0.0007, 0.011, 0.0062, 0.0015, + 0.0021, 0.0049, 0.0006, 0.0006, 0.0011, + 0.0006, 0.0019, 0.003, 0.0044, 0.0054, + 0.0057, 0.0049, 0.0016, 0.0006, 0.0009, + 0.0006, 0.0012, 0.0006, 0.0149, 0.0532, + 0.0076, 0.0041, 0.0024, 0.0135, 0.0081, + 0.2209, 0.0459, 0.0438, 0.0488, 0.0137, + 0.002, 0.0003, 0.0008, 0.0039, 0.0024, + 0.0005, 0.0004, 0.003, 0.056, 0.0026] +SPLIT_DENSITY_SLOW = [0.0086, 0.0004, 0.0568, 0.0003, 0.0032, 0.0005, 0.0004, 0.0013, 0.0016, 0.0648, 0.0198, 0.1285, 0.098, 0.0005, 0.0064, 0.0003, 0.0004, 0.0026, 0.0007, 0.0051, 0.0089, 0.0024, 0.0033, 0.0057, 0.0005, 0.0003, 0.001, 0.0045, 0.0091, 0.0006, 0.0005, 0.0321, 0.0059, 0.1105, 0.216, 0.1489, 0.0004, 0.0003, 0.0006, 0.0483] + +class Skipped(Exception): + pass + +class TimeOutError(Exception): + pass + +class DependencyError(Exception): + pass + + +def _indent(s, indent=4): + """ + Add the given number of space characters to the beginning of + every non-blank line in ``s``, and return the result. + If the string ``s`` is Unicode, it is encoded using the stdout + encoding and the ``backslashreplace`` error handler. + """ + # This regexp matches the start of non-blank lines: + return re.sub('(?m)^(?!$)', indent*' ', s) + + +pdoctest._indent = _indent # type: ignore + +# override reporter to maintain windows and python3 + + +def _report_failure(self, out, test, example, got): + """ + Report that the given example failed. + """ + s = self._checker.output_difference(example, got, self.optionflags) + s = s.encode('raw_unicode_escape').decode('utf8', 'ignore') + out(self._failure_header(test, example) + s) + + +if IS_WINDOWS: + DocTestRunner.report_failure = _report_failure # type: ignore + + +def convert_to_native_paths(lst): + """ + Converts a list of '/' separated paths into a list of + native (os.sep separated) paths and converts to lowercase + if the system is case insensitive. + """ + newlst = [] + for rv in lst: + rv = os.path.join(*rv.split("/")) + # on windows the slash after the colon is dropped + if sys.platform == "win32": + pos = rv.find(':') + if pos != -1: + if rv[pos + 1] != '\\': + rv = rv[:pos + 1] + '\\' + rv[pos + 1:] + newlst.append(os.path.normcase(rv)) + return newlst + + +def get_sympy_dir(): + """ + Returns the root SymPy directory and set the global value + indicating whether the system is case sensitive or not. + """ + this_file = os.path.abspath(__file__) + sympy_dir = os.path.join(os.path.dirname(this_file), "..", "..") + sympy_dir = os.path.normpath(sympy_dir) + return os.path.normcase(sympy_dir) + + +def setup_pprint(disable_line_wrap=True): + from sympy.interactive.printing import init_printing + from sympy.printing.pretty.pretty import pprint_use_unicode + import sympy.interactive.printing as interactive_printing + from sympy.printing.pretty import stringpict + + # Prevent init_printing() in doctests from affecting other doctests + interactive_printing.NO_GLOBAL = True + + # force pprint to be in ascii mode in doctests + use_unicode_prev = pprint_use_unicode(False) + + # disable line wrapping for pprint() outputs + wrap_line_prev = stringpict._GLOBAL_WRAP_LINE + if disable_line_wrap: + stringpict._GLOBAL_WRAP_LINE = False + + # hook our nice, hash-stable strprinter + init_printing(pretty_print=False) + + return use_unicode_prev, wrap_line_prev + + +@contextmanager +def raise_on_deprecated(): + """Context manager to make DeprecationWarning raise an error + + This is to catch SymPyDeprecationWarning from library code while running + tests and doctests. It is important to use this context manager around + each individual test/doctest in case some tests modify the warning + filters. + """ + with warnings.catch_warnings(): + warnings.filterwarnings('error', '.*', DeprecationWarning, module='sympy.*') + yield + + +def run_in_subprocess_with_hash_randomization( + function, function_args=(), + function_kwargs=None, command=sys.executable, + module='sympy.testing.runtests', force=False): + """ + Run a function in a Python subprocess with hash randomization enabled. + + If hash randomization is not supported by the version of Python given, it + returns False. Otherwise, it returns the exit value of the command. The + function is passed to sys.exit(), so the return value of the function will + be the return value. + + The environment variable PYTHONHASHSEED is used to seed Python's hash + randomization. If it is set, this function will return False, because + starting a new subprocess is unnecessary in that case. If it is not set, + one is set at random, and the tests are run. Note that if this + environment variable is set when Python starts, hash randomization is + automatically enabled. To force a subprocess to be created even if + PYTHONHASHSEED is set, pass ``force=True``. This flag will not force a + subprocess in Python versions that do not support hash randomization (see + below), because those versions of Python do not support the ``-R`` flag. + + ``function`` should be a string name of a function that is importable from + the module ``module``, like "_test". The default for ``module`` is + "sympy.testing.runtests". ``function_args`` and ``function_kwargs`` + should be a repr-able tuple and dict, respectively. The default Python + command is sys.executable, which is the currently running Python command. + + This function is necessary because the seed for hash randomization must be + set by the environment variable before Python starts. Hence, in order to + use a predetermined seed for tests, we must start Python in a separate + subprocess. + + Hash randomization was added in the minor Python versions 2.6.8, 2.7.3, + 3.1.5, and 3.2.3, and is enabled by default in all Python versions after + and including 3.3.0. + + Examples + ======== + + >>> from sympy.testing.runtests import ( + ... run_in_subprocess_with_hash_randomization) + >>> # run the core tests in verbose mode + >>> run_in_subprocess_with_hash_randomization("_test", + ... function_args=("core",), + ... function_kwargs={'verbose': True}) # doctest: +SKIP + # Will return 0 if sys.executable supports hash randomization and tests + # pass, 1 if they fail, and False if it does not support hash + # randomization. + + """ + cwd = get_sympy_dir() + # Note, we must return False everywhere, not None, as subprocess.call will + # sometimes return None. + + # First check if the Python version supports hash randomization + # If it does not have this support, it won't recognize the -R flag + p = subprocess.Popen([command, "-RV"], stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, cwd=cwd) + p.communicate() + if p.returncode != 0: + return False + + hash_seed = os.getenv("PYTHONHASHSEED") + if not hash_seed: + os.environ["PYTHONHASHSEED"] = str(random.randrange(2**32)) + else: + if not force: + return False + + function_kwargs = function_kwargs or {} + + # Now run the command + commandstring = ("import sys; from %s import %s;sys.exit(%s(*%s, **%s))" % + (module, function, function, repr(function_args), + repr(function_kwargs))) + + try: + p = subprocess.Popen([command, "-R", "-c", commandstring], cwd=cwd) + p.communicate() + except KeyboardInterrupt: + p.wait() + finally: + # Put the environment variable back, so that it reads correctly for + # the current Python process. + if hash_seed is None: + del os.environ["PYTHONHASHSEED"] + else: + os.environ["PYTHONHASHSEED"] = hash_seed + return p.returncode + + +def run_all_tests(test_args=(), test_kwargs=None, + doctest_args=(), doctest_kwargs=None, + examples_args=(), examples_kwargs=None): + """ + Run all tests. + + Right now, this runs the regular tests (bin/test), the doctests + (bin/doctest), and the examples (examples/all.py). + + This is what ``setup.py test`` uses. + + You can pass arguments and keyword arguments to the test functions that + support them (for now, test, doctest, and the examples). See the + docstrings of those functions for a description of the available options. + + For example, to run the solvers tests with colors turned off: + + >>> from sympy.testing.runtests import run_all_tests + >>> run_all_tests(test_args=("solvers",), + ... test_kwargs={"colors:False"}) # doctest: +SKIP + + """ + tests_successful = True + + test_kwargs = test_kwargs or {} + doctest_kwargs = doctest_kwargs or {} + examples_kwargs = examples_kwargs or {'quiet': True} + + try: + # Regular tests + if not test(*test_args, **test_kwargs): + # some regular test fails, so set the tests_successful + # flag to false and continue running the doctests + tests_successful = False + + # Doctests + print() + if not doctest(*doctest_args, **doctest_kwargs): + tests_successful = False + + # Examples + print() + sys.path.append("examples") # examples/all.py + from all import run_examples # type: ignore + if not run_examples(*examples_args, **examples_kwargs): + tests_successful = False + + if tests_successful: + return + else: + # Return nonzero exit code + sys.exit(1) + except KeyboardInterrupt: + print() + print("DO *NOT* COMMIT!") + sys.exit(1) + + +def test(*paths, subprocess=True, rerun=0, **kwargs): + """ + Run tests in the specified test_*.py files. + + Tests in a particular test_*.py file are run if any of the given strings + in ``paths`` matches a part of the test file's path. If ``paths=[]``, + tests in all test_*.py files are run. + + Notes: + + - If sort=False, tests are run in random order (not default). + - Paths can be entered in native system format or in unix, + forward-slash format. + - Files that are on the blacklist can be tested by providing + their path; they are only excluded if no paths are given. + + **Explanation of test results** + + ====== =============================================================== + Output Meaning + ====== =============================================================== + . passed + F failed + X XPassed (expected to fail but passed) + f XFAILed (expected to fail and indeed failed) + s skipped + w slow + T timeout (e.g., when ``--timeout`` is used) + K KeyboardInterrupt (when running the slow tests with ``--slow``, + you can interrupt one of them without killing the test runner) + ====== =============================================================== + + + Colors have no additional meaning and are used just to facilitate + interpreting the output. + + Examples + ======== + + >>> import sympy + + Run all tests: + + >>> sympy.test() # doctest: +SKIP + + Run one file: + + >>> sympy.test("sympy/core/tests/test_basic.py") # doctest: +SKIP + >>> sympy.test("_basic") # doctest: +SKIP + + Run all tests in sympy/functions/ and some particular file: + + >>> sympy.test("sympy/core/tests/test_basic.py", + ... "sympy/functions") # doctest: +SKIP + + Run all tests in sympy/core and sympy/utilities: + + >>> sympy.test("/core", "/util") # doctest: +SKIP + + Run specific test from a file: + + >>> sympy.test("sympy/core/tests/test_basic.py", + ... kw="test_equality") # doctest: +SKIP + + Run specific test from any file: + + >>> sympy.test(kw="subs") # doctest: +SKIP + + Run the tests with verbose mode on: + + >>> sympy.test(verbose=True) # doctest: +SKIP + + Do not sort the test output: + + >>> sympy.test(sort=False) # doctest: +SKIP + + Turn on post-mortem pdb: + + >>> sympy.test(pdb=True) # doctest: +SKIP + + Turn off colors: + + >>> sympy.test(colors=False) # doctest: +SKIP + + Force colors, even when the output is not to a terminal (this is useful, + e.g., if you are piping to ``less -r`` and you still want colors) + + >>> sympy.test(force_colors=False) # doctest: +SKIP + + The traceback verboseness can be set to "short" or "no" (default is + "short") + + >>> sympy.test(tb='no') # doctest: +SKIP + + The ``split`` option can be passed to split the test run into parts. The + split currently only splits the test files, though this may change in the + future. ``split`` should be a string of the form 'a/b', which will run + part ``a`` of ``b``. For instance, to run the first half of the test suite: + + >>> sympy.test(split='1/2') # doctest: +SKIP + + The ``time_balance`` option can be passed in conjunction with ``split``. + If ``time_balance=True`` (the default for ``sympy.test``), SymPy will attempt + to split the tests such that each split takes equal time. This heuristic + for balancing is based on pre-recorded test data. + + >>> sympy.test(split='1/2', time_balance=True) # doctest: +SKIP + + You can disable running the tests in a separate subprocess using + ``subprocess=False``. This is done to support seeding hash randomization, + which is enabled by default in the Python versions where it is supported. + If subprocess=False, hash randomization is enabled/disabled according to + whether it has been enabled or not in the calling Python process. + However, even if it is enabled, the seed cannot be printed unless it is + called from a new Python process. + + Hash randomization was added in the minor Python versions 2.6.8, 2.7.3, + 3.1.5, and 3.2.3, and is enabled by default in all Python versions after + and including 3.3.0. + + If hash randomization is not supported ``subprocess=False`` is used + automatically. + + >>> sympy.test(subprocess=False) # doctest: +SKIP + + To set the hash randomization seed, set the environment variable + ``PYTHONHASHSEED`` before running the tests. This can be done from within + Python using + + >>> import os + >>> os.environ['PYTHONHASHSEED'] = '42' # doctest: +SKIP + + Or from the command line using + + $ PYTHONHASHSEED=42 ./bin/test + + If the seed is not set, a random seed will be chosen. + + Note that to reproduce the same hash values, you must use both the same seed + as well as the same architecture (32-bit vs. 64-bit). + + """ + # count up from 0, do not print 0 + print_counter = lambda i : (print("rerun %d" % (rerun-i)) + if rerun-i else None) + + if subprocess: + # loop backwards so last i is 0 + for i in range(rerun, -1, -1): + print_counter(i) + ret = run_in_subprocess_with_hash_randomization("_test", + function_args=paths, function_kwargs=kwargs) + if ret is False: + break + val = not bool(ret) + # exit on the first failure or if done + if not val or i == 0: + return val + + # rerun even if hash randomization is not supported + for i in range(rerun, -1, -1): + print_counter(i) + val = not bool(_test(*paths, **kwargs)) + if not val or i == 0: + return val + + +def _test(*paths, + verbose=False, tb="short", kw=None, pdb=False, colors=True, + force_colors=False, sort=True, seed=None, timeout=False, + fail_on_timeout=False, slow=False, enhance_asserts=False, split=None, + time_balance=True, blacklist=(), + fast_threshold=None, slow_threshold=None): + """ + Internal function that actually runs the tests. + + All keyword arguments from ``test()`` are passed to this function except for + ``subprocess``. + + Returns 0 if tests passed and 1 if they failed. See the docstring of + ``test()`` for more information. + """ + kw = kw or () + # ensure that kw is a tuple + if isinstance(kw, str): + kw = (kw,) + post_mortem = pdb + if seed is None: + seed = random.randrange(100000000) + if ON_CI and timeout is False: + timeout = 595 + fail_on_timeout = True + if ON_CI: + blacklist = list(blacklist) + ['sympy/plotting/pygletplot/tests'] + blacklist = convert_to_native_paths(blacklist) + r = PyTestReporter(verbose=verbose, tb=tb, colors=colors, + force_colors=force_colors, split=split) + # This won't strictly run the test for the corresponding file, but it is + # good enough for copying and pasting the failing test. + _paths = [] + for path in paths: + if '::' in path: + path, _kw = path.split('::', 1) + kw += (_kw,) + _paths.append(path) + paths = _paths + + t = SymPyTests(r, kw, post_mortem, seed, + fast_threshold=fast_threshold, + slow_threshold=slow_threshold) + + test_files = t.get_test_files('sympy') + + not_blacklisted = [f for f in test_files + if not any(b in f for b in blacklist)] + + if len(paths) == 0: + matched = not_blacklisted + else: + paths = convert_to_native_paths(paths) + matched = [] + for f in not_blacklisted: + basename = os.path.basename(f) + for p in paths: + if p in f or fnmatch(basename, p): + matched.append(f) + break + + density = None + if time_balance: + if slow: + density = SPLIT_DENSITY_SLOW + else: + density = SPLIT_DENSITY + + if split: + matched = split_list(matched, split, density=density) + + t._testfiles.extend(matched) + + return int(not t.test(sort=sort, timeout=timeout, slow=slow, + enhance_asserts=enhance_asserts, fail_on_timeout=fail_on_timeout)) + + +def doctest(*paths, subprocess=True, rerun=0, **kwargs): + r""" + Runs doctests in all \*.py files in the SymPy directory which match + any of the given strings in ``paths`` or all tests if paths=[]. + + Notes: + + - Paths can be entered in native system format or in unix, + forward-slash format. + - Files that are on the blacklist can be tested by providing + their path; they are only excluded if no paths are given. + + Examples + ======== + + >>> import sympy + + Run all tests: + + >>> sympy.doctest() # doctest: +SKIP + + Run one file: + + >>> sympy.doctest("sympy/core/basic.py") # doctest: +SKIP + >>> sympy.doctest("polynomial.rst") # doctest: +SKIP + + Run all tests in sympy/functions/ and some particular file: + + >>> sympy.doctest("/functions", "basic.py") # doctest: +SKIP + + Run any file having polynomial in its name, doc/src/modules/polynomial.rst, + sympy/functions/special/polynomials.py, and sympy/polys/polynomial.py: + + >>> sympy.doctest("polynomial") # doctest: +SKIP + + The ``split`` option can be passed to split the test run into parts. The + split currently only splits the test files, though this may change in the + future. ``split`` should be a string of the form 'a/b', which will run + part ``a`` of ``b``. Note that the regular doctests and the Sphinx + doctests are split independently. For instance, to run the first half of + the test suite: + + >>> sympy.doctest(split='1/2') # doctest: +SKIP + + The ``subprocess`` and ``verbose`` options are the same as with the function + ``test()`` (see the docstring of that function for more information) except + that ``verbose`` may also be set equal to ``2`` in order to print + individual doctest lines, as they are being tested. + """ + # count up from 0, do not print 0 + print_counter = lambda i : (print("rerun %d" % (rerun-i)) + if rerun-i else None) + + if subprocess: + # loop backwards so last i is 0 + for i in range(rerun, -1, -1): + print_counter(i) + ret = run_in_subprocess_with_hash_randomization("_doctest", + function_args=paths, function_kwargs=kwargs) + if ret is False: + break + val = not bool(ret) + # exit on the first failure or if done + if not val or i == 0: + return val + + # rerun even if hash randomization is not supported + for i in range(rerun, -1, -1): + print_counter(i) + val = not bool(_doctest(*paths, **kwargs)) + if not val or i == 0: + return val + + +def _get_doctest_blacklist(): + '''Get the default blacklist for the doctests''' + blacklist = [] + + blacklist.extend([ + "doc/src/modules/plotting.rst", # generates live plots + "doc/src/modules/physics/mechanics/autolev_parser.rst", + "sympy/codegen/array_utils.py", # raises deprecation warning + "sympy/core/compatibility.py", # backwards compatibility shim, importing it triggers a deprecation warning + "sympy/core/trace.py", # backwards compatibility shim, importing it triggers a deprecation warning + "sympy/galgebra.py", # no longer part of SymPy + "sympy/parsing/autolev/_antlr/autolevlexer.py", # generated code + "sympy/parsing/autolev/_antlr/autolevlistener.py", # generated code + "sympy/parsing/autolev/_antlr/autolevparser.py", # generated code + "sympy/parsing/latex/_antlr/latexlexer.py", # generated code + "sympy/parsing/latex/_antlr/latexparser.py", # generated code + "sympy/plotting/pygletplot/__init__.py", # crashes on some systems + "sympy/plotting/pygletplot/plot.py", # crashes on some systems + "sympy/printing/ccode.py", # backwards compatibility shim, importing it breaks the codegen doctests + "sympy/printing/cxxcode.py", # backwards compatibility shim, importing it breaks the codegen doctests + "sympy/printing/fcode.py", # backwards compatibility shim, importing it breaks the codegen doctests + "sympy/testing/randtest.py", # backwards compatibility shim, importing it triggers a deprecation warning + "sympy/this.py", # prints text + ]) + # autolev parser tests + num = 12 + for i in range (1, num+1): + blacklist.append("sympy/parsing/autolev/test-examples/ruletest" + str(i) + ".py") + blacklist.extend(["sympy/parsing/autolev/test-examples/pydy-example-repo/mass_spring_damper.py", + "sympy/parsing/autolev/test-examples/pydy-example-repo/chaos_pendulum.py", + "sympy/parsing/autolev/test-examples/pydy-example-repo/double_pendulum.py", + "sympy/parsing/autolev/test-examples/pydy-example-repo/non_min_pendulum.py"]) + + if import_module('numpy') is None: + blacklist.extend([ + "sympy/plotting/experimental_lambdify.py", + "sympy/plotting/plot_implicit.py", + "examples/advanced/autowrap_integrators.py", + "examples/advanced/autowrap_ufuncify.py", + "examples/intermediate/sample.py", + "examples/intermediate/mplot2d.py", + "examples/intermediate/mplot3d.py", + "doc/src/modules/numeric-computation.rst", + "doc/src/explanation/best-practices.md", + "doc/src/tutorials/physics/biomechanics/biomechanical-model-example.rst", + "doc/src/tutorials/physics/biomechanics/biomechanics.rst", + ]) + else: + if import_module('matplotlib') is None: + blacklist.extend([ + "examples/intermediate/mplot2d.py", + "examples/intermediate/mplot3d.py" + ]) + else: + # Use a non-windowed backend, so that the tests work on CI + import matplotlib + matplotlib.use('Agg') + + if ON_CI or import_module('pyglet') is None: + blacklist.extend(["sympy/plotting/pygletplot"]) + + if import_module('aesara') is None: + blacklist.extend([ + "sympy/printing/aesaracode.py", + "doc/src/modules/numeric-computation.rst", + ]) + + if import_module('cupy') is None: + blacklist.extend([ + "doc/src/modules/numeric-computation.rst", + ]) + + if import_module('jax') is None: + blacklist.extend([ + "doc/src/modules/numeric-computation.rst", + ]) + + if import_module('antlr4') is None: + blacklist.extend([ + "sympy/parsing/autolev/__init__.py", + "sympy/parsing/latex/_parse_latex_antlr.py", + ]) + + if import_module('lfortran') is None: + #throws ImportError when lfortran not installed + blacklist.extend([ + "sympy/parsing/sym_expr.py", + ]) + + if import_module("scipy") is None: + # throws ModuleNotFoundError when scipy not installed + blacklist.extend([ + "doc/src/guides/solving/solve-numerically.md", + "doc/src/guides/solving/solve-ode.md", + ]) + + if import_module("numpy") is None: + # throws ModuleNotFoundError when numpy not installed + blacklist.extend([ + "doc/src/guides/solving/solve-ode.md", + "doc/src/guides/solving/solve-numerically.md", + ]) + + # disabled because of doctest failures in asmeurer's bot + blacklist.extend([ + "sympy/utilities/autowrap.py", + "examples/advanced/autowrap_integrators.py", + "examples/advanced/autowrap_ufuncify.py" + ]) + + blacklist.extend([ + "sympy/conftest.py", # Depends on pytest + ]) + + # These are deprecated stubs to be removed: + blacklist.extend([ + "sympy/utilities/tmpfiles.py", + "sympy/utilities/pytest.py", + "sympy/utilities/runtests.py", + "sympy/utilities/quality_unicode.py", + "sympy/utilities/randtest.py", + ]) + + blacklist = convert_to_native_paths(blacklist) + return blacklist + + +def _doctest(*paths, **kwargs): + """ + Internal function that actually runs the doctests. + + All keyword arguments from ``doctest()`` are passed to this function + except for ``subprocess``. + + Returns 0 if tests passed and 1 if they failed. See the docstrings of + ``doctest()`` and ``test()`` for more information. + """ + from sympy.printing.pretty.pretty import pprint_use_unicode + from sympy.printing.pretty import stringpict + + normal = kwargs.get("normal", False) + verbose = kwargs.get("verbose", False) + colors = kwargs.get("colors", True) + force_colors = kwargs.get("force_colors", False) + blacklist = kwargs.get("blacklist", []) + split = kwargs.get('split', None) + + blacklist.extend(_get_doctest_blacklist()) + + # Use a non-windowed backend, so that the tests work on CI + if import_module('matplotlib') is not None: + import matplotlib + matplotlib.use('Agg') + + # Disable warnings for external modules + import sympy.external + sympy.external.importtools.WARN_OLD_VERSION = False + sympy.external.importtools.WARN_NOT_INSTALLED = False + + # Disable showing up of plots + from sympy.plotting.plot import unset_show + unset_show() + + r = PyTestReporter(verbose, split=split, colors=colors,\ + force_colors=force_colors) + t = SymPyDocTests(r, normal) + + test_files = t.get_test_files('sympy') + test_files.extend(t.get_test_files('examples', init_only=False)) + + not_blacklisted = [f for f in test_files + if not any(b in f for b in blacklist)] + if len(paths) == 0: + matched = not_blacklisted + else: + # take only what was requested...but not blacklisted items + # and allow for partial match anywhere or fnmatch of name + paths = convert_to_native_paths(paths) + matched = [] + for f in not_blacklisted: + basename = os.path.basename(f) + for p in paths: + if p in f or fnmatch(basename, p): + matched.append(f) + break + + matched.sort() + + if split: + matched = split_list(matched, split) + + t._testfiles.extend(matched) + + # run the tests and record the result for this *py portion of the tests + if t._testfiles: + failed = not t.test() + else: + failed = False + + # N.B. + # -------------------------------------------------------------------- + # Here we test *.rst and *.md files at or below doc/src. Code from these + # must be self supporting in terms of imports since there is no importing + # of necessary modules by doctest.testfile. If you try to pass *.py files + # through this they might fail because they will lack the needed imports + # and smarter parsing that can be done with source code. + # + test_files_rst = t.get_test_files('doc/src', '*.rst', init_only=False) + test_files_md = t.get_test_files('doc/src', '*.md', init_only=False) + test_files = test_files_rst + test_files_md + test_files.sort() + + not_blacklisted = [f for f in test_files + if not any(b in f for b in blacklist)] + + if len(paths) == 0: + matched = not_blacklisted + else: + # Take only what was requested as long as it's not on the blacklist. + # Paths were already made native in *py tests so don't repeat here. + # There's no chance of having a *py file slip through since we + # only have *rst files in test_files. + matched = [] + for f in not_blacklisted: + basename = os.path.basename(f) + for p in paths: + if p in f or fnmatch(basename, p): + matched.append(f) + break + + if split: + matched = split_list(matched, split) + + first_report = True + for rst_file in matched: + if not os.path.isfile(rst_file): + continue + old_displayhook = sys.displayhook + try: + use_unicode_prev, wrap_line_prev = setup_pprint() + out = sympytestfile( + rst_file, module_relative=False, encoding='utf-8', + optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE | + pdoctest.IGNORE_EXCEPTION_DETAIL) + finally: + # make sure we return to the original displayhook in case some + # doctest has changed that + sys.displayhook = old_displayhook + # The NO_GLOBAL flag overrides the no_global flag to init_printing + # if True + import sympy.interactive.printing as interactive_printing + interactive_printing.NO_GLOBAL = False + pprint_use_unicode(use_unicode_prev) + stringpict._GLOBAL_WRAP_LINE = wrap_line_prev + + rstfailed, tested = out + if tested: + failed = rstfailed or failed + if first_report: + first_report = False + msg = 'rst/md doctests start' + if not t._testfiles: + r.start(msg=msg) + else: + r.write_center(msg) + print() + # use as the id, everything past the first 'sympy' + file_id = rst_file[rst_file.find('sympy') + len('sympy') + 1:] + print(file_id, end=" ") + # get at least the name out so it is know who is being tested + wid = r.terminal_width - len(file_id) - 1 # update width + test_file = '[%s]' % (tested) + report = '[%s]' % (rstfailed or 'OK') + print(''.join( + [test_file, ' '*(wid - len(test_file) - len(report)), report]) + ) + + # the doctests for *py will have printed this message already if there was + # a failure, so now only print it if there was intervening reporting by + # testing the *rst as evidenced by first_report no longer being True. + if not first_report and failed: + print() + print("DO *NOT* COMMIT!") + + return int(failed) + +sp = re.compile(r'([0-9]+)/([1-9][0-9]*)') + +def split_list(l, split, density=None): + """ + Splits a list into part a of b + + split should be a string of the form 'a/b'. For instance, '1/3' would give + the split one of three. + + If the length of the list is not divisible by the number of splits, the + last split will have more items. + + `density` may be specified as a list. If specified, + tests will be balanced so that each split has as equal-as-possible + amount of mass according to `density`. + + >>> from sympy.testing.runtests import split_list + >>> a = list(range(10)) + >>> split_list(a, '1/3') + [0, 1, 2] + >>> split_list(a, '2/3') + [3, 4, 5] + >>> split_list(a, '3/3') + [6, 7, 8, 9] + """ + m = sp.match(split) + if not m: + raise ValueError("split must be a string of the form a/b where a and b are ints") + i, t = map(int, m.groups()) + + if not density: + return l[(i - 1)*len(l)//t : i*len(l)//t] + + # normalize density + tot = sum(density) + density = [x / tot for x in density] + + def density_inv(x): + """Interpolate the inverse to the cumulative + distribution function given by density""" + if x <= 0: + return 0 + if x >= sum(density): + return 1 + + # find the first time the cumulative sum surpasses x + # and linearly interpolate + cumm = 0 + for i, d in enumerate(density): + cumm += d + if cumm >= x: + break + frac = (d - (cumm - x)) / d + return (i + frac) / len(density) + + lower_frac = density_inv((i - 1) / t) + higher_frac = density_inv(i / t) + return l[int(lower_frac*len(l)) : int(higher_frac*len(l))] + +from collections import namedtuple +SymPyTestResults = namedtuple('SymPyTestResults', 'failed attempted') + +def sympytestfile(filename, module_relative=True, name=None, package=None, + globs=None, verbose=None, report=True, optionflags=0, + extraglobs=None, raise_on_error=False, + parser=pdoctest.DocTestParser(), encoding=None): + + """ + Test examples in the given file. Return (#failures, #tests). + + Optional keyword arg ``module_relative`` specifies how filenames + should be interpreted: + + - If ``module_relative`` is True (the default), then ``filename`` + specifies a module-relative path. By default, this path is + relative to the calling module's directory; but if the + ``package`` argument is specified, then it is relative to that + package. To ensure os-independence, ``filename`` should use + "/" characters to separate path segments, and should not + be an absolute path (i.e., it may not begin with "/"). + + - If ``module_relative`` is False, then ``filename`` specifies an + os-specific path. The path may be absolute or relative (to + the current working directory). + + Optional keyword arg ``name`` gives the name of the test; by default + use the file's basename. + + Optional keyword argument ``package`` is a Python package or the + name of a Python package whose directory should be used as the + base directory for a module relative filename. If no package is + specified, then the calling module's directory is used as the base + directory for module relative filenames. It is an error to + specify ``package`` if ``module_relative`` is False. + + Optional keyword arg ``globs`` gives a dict to be used as the globals + when executing examples; by default, use {}. A copy of this dict + is actually used for each docstring, so that each docstring's + examples start with a clean slate. + + Optional keyword arg ``extraglobs`` gives a dictionary that should be + merged into the globals that are used to execute examples. By + default, no extra globals are used. + + Optional keyword arg ``verbose`` prints lots of stuff if true, prints + only failures if false; by default, it's true iff "-v" is in sys.argv. + + Optional keyword arg ``report`` prints a summary at the end when true, + else prints nothing at the end. In verbose mode, the summary is + detailed, else very brief (in fact, empty if all tests passed). + + Optional keyword arg ``optionflags`` or's together module constants, + and defaults to 0. Possible values (see the docs for details): + + - DONT_ACCEPT_TRUE_FOR_1 + - DONT_ACCEPT_BLANKLINE + - NORMALIZE_WHITESPACE + - ELLIPSIS + - SKIP + - IGNORE_EXCEPTION_DETAIL + - REPORT_UDIFF + - REPORT_CDIFF + - REPORT_NDIFF + - REPORT_ONLY_FIRST_FAILURE + + Optional keyword arg ``raise_on_error`` raises an exception on the + first unexpected exception or failure. This allows failures to be + post-mortem debugged. + + Optional keyword arg ``parser`` specifies a DocTestParser (or + subclass) that should be used to extract tests from the files. + + Optional keyword arg ``encoding`` specifies an encoding that should + be used to convert the file to unicode. + + Advanced tomfoolery: testmod runs methods of a local instance of + class doctest.Tester, then merges the results into (or creates) + global Tester instance doctest.master. Methods of doctest.master + can be called directly too, if you want to do something unusual. + Passing report=0 to testmod is especially useful then, to delay + displaying a summary. Invoke doctest.master.summarize(verbose) + when you're done fiddling. + """ + if package and not module_relative: + raise ValueError("Package may only be specified for module-" + "relative paths.") + + # Relativize the path + text, filename = pdoctest._load_testfile( + filename, package, module_relative, encoding) + + # If no name was given, then use the file's name. + if name is None: + name = os.path.basename(filename) + + # Assemble the globals. + if globs is None: + globs = {} + else: + globs = globs.copy() + if extraglobs is not None: + globs.update(extraglobs) + if '__name__' not in globs: + globs['__name__'] = '__main__' + + if raise_on_error: + runner = pdoctest.DebugRunner(verbose=verbose, optionflags=optionflags) + else: + runner = SymPyDocTestRunner(verbose=verbose, optionflags=optionflags) + runner._checker = SymPyOutputChecker() + + # Read the file, convert it to a test, and run it. + test = parser.get_doctest(text, globs, name, filename, 0) + runner.run(test) + + if report: + runner.summarize() + + if pdoctest.master is None: + pdoctest.master = runner + else: + pdoctest.master.merge(runner) + + return SymPyTestResults(runner.failures, runner.tries) + + +class SymPyTests: + + def __init__(self, reporter, kw="", post_mortem=False, + seed=None, fast_threshold=None, slow_threshold=None): + self._post_mortem = post_mortem + self._kw = kw + self._count = 0 + self._root_dir = get_sympy_dir() + self._reporter = reporter + self._reporter.root_dir(self._root_dir) + self._testfiles = [] + self._seed = seed if seed is not None else random.random() + + # Defaults in seconds, from human / UX design limits + # http://www.nngroup.com/articles/response-times-3-important-limits/ + # + # These defaults are *NOT* set in stone as we are measuring different + # things, so others feel free to come up with a better yardstick :) + if fast_threshold: + self._fast_threshold = float(fast_threshold) + else: + self._fast_threshold = 8 + if slow_threshold: + self._slow_threshold = float(slow_threshold) + else: + self._slow_threshold = 10 + + def test(self, sort=False, timeout=False, slow=False, + enhance_asserts=False, fail_on_timeout=False): + """ + Runs the tests returning True if all tests pass, otherwise False. + + If sort=False run tests in random order. + """ + if sort: + self._testfiles.sort() + elif slow: + pass + else: + random.seed(self._seed) + random.shuffle(self._testfiles) + self._reporter.start(self._seed) + for f in self._testfiles: + try: + self.test_file(f, sort, timeout, slow, + enhance_asserts, fail_on_timeout) + except KeyboardInterrupt: + print(" interrupted by user") + self._reporter.finish() + raise + return self._reporter.finish() + + def _enhance_asserts(self, source): + from ast import (NodeTransformer, Compare, Name, Store, Load, Tuple, + Assign, BinOp, Str, Mod, Assert, parse, fix_missing_locations) + + ops = {"Eq": '==', "NotEq": '!=', "Lt": '<', "LtE": '<=', + "Gt": '>', "GtE": '>=', "Is": 'is', "IsNot": 'is not', + "In": 'in', "NotIn": 'not in'} + + class Transform(NodeTransformer): + def visit_Assert(self, stmt): + if isinstance(stmt.test, Compare): + compare = stmt.test + values = [compare.left] + compare.comparators + names = [ "_%s" % i for i, _ in enumerate(values) ] + names_store = [ Name(n, Store()) for n in names ] + names_load = [ Name(n, Load()) for n in names ] + target = Tuple(names_store, Store()) + value = Tuple(values, Load()) + assign = Assign([target], value) + new_compare = Compare(names_load[0], compare.ops, names_load[1:]) + msg_format = "\n%s " + "\n%s ".join([ ops[op.__class__.__name__] for op in compare.ops ]) + "\n%s" + msg = BinOp(Str(msg_format), Mod(), Tuple(names_load, Load())) + test = Assert(new_compare, msg, lineno=stmt.lineno, col_offset=stmt.col_offset) + return [assign, test] + else: + return stmt + + tree = parse(source) + new_tree = Transform().visit(tree) + return fix_missing_locations(new_tree) + + def test_file(self, filename, sort=True, timeout=False, slow=False, + enhance_asserts=False, fail_on_timeout=False): + reporter = self._reporter + funcs = [] + try: + gl = {'__file__': filename} + try: + open_file = lambda: open(filename, encoding="utf8") + + with open_file() as f: + source = f.read() + if self._kw: + for l in source.splitlines(): + if l.lstrip().startswith('def '): + if any(l.lower().find(k.lower()) != -1 for k in self._kw): + break + else: + return + + if enhance_asserts: + try: + source = self._enhance_asserts(source) + except ImportError: + pass + + code = compile(source, filename, "exec", flags=0, dont_inherit=True) + exec(code, gl) + except (SystemExit, KeyboardInterrupt): + raise + except ImportError: + reporter.import_error(filename, sys.exc_info()) + return + except Exception: + reporter.test_exception(sys.exc_info()) + + clear_cache() + self._count += 1 + random.seed(self._seed) + disabled = gl.get("disabled", False) + if not disabled: + # we need to filter only those functions that begin with 'test_' + # We have to be careful about decorated functions. As long as + # the decorator uses functools.wraps, we can detect it. + funcs = [] + for f in gl: + if (f.startswith("test_") and (inspect.isfunction(gl[f]) + or inspect.ismethod(gl[f]))): + func = gl[f] + # Handle multiple decorators + while hasattr(func, '__wrapped__'): + func = func.__wrapped__ + + if inspect.getsourcefile(func) == filename: + funcs.append(gl[f]) + if slow: + funcs = [f for f in funcs if getattr(f, '_slow', False)] + # Sorting of XFAILed functions isn't fixed yet :-( + funcs.sort(key=lambda x: inspect.getsourcelines(x)[1]) + i = 0 + while i < len(funcs): + if inspect.isgeneratorfunction(funcs[i]): + # some tests can be generators, that return the actual + # test functions. We unpack it below: + f = funcs.pop(i) + for fg in f(): + func = fg[0] + args = fg[1:] + fgw = lambda: func(*args) + funcs.insert(i, fgw) + i += 1 + else: + i += 1 + # drop functions that are not selected with the keyword expression: + funcs = [x for x in funcs if self.matches(x)] + + if not funcs: + return + except Exception: + reporter.entering_filename(filename, len(funcs)) + raise + + reporter.entering_filename(filename, len(funcs)) + if not sort: + random.shuffle(funcs) + + for f in funcs: + start = time.time() + reporter.entering_test(f) + try: + if getattr(f, '_slow', False) and not slow: + raise Skipped("Slow") + with raise_on_deprecated(): + if timeout: + self._timeout(f, timeout, fail_on_timeout) + else: + random.seed(self._seed) + f() + except KeyboardInterrupt: + if getattr(f, '_slow', False): + reporter.test_skip("KeyboardInterrupt") + else: + raise + except Exception: + if timeout: + signal.alarm(0) # Disable the alarm. It could not be handled before. + t, v, tr = sys.exc_info() + if t is AssertionError: + reporter.test_fail((t, v, tr)) + if self._post_mortem: + pdb.post_mortem(tr) + elif t.__name__ == "Skipped": + reporter.test_skip(v) + elif t.__name__ == "XFail": + reporter.test_xfail() + elif t.__name__ == "XPass": + reporter.test_xpass(v) + else: + reporter.test_exception((t, v, tr)) + if self._post_mortem: + pdb.post_mortem(tr) + else: + reporter.test_pass() + taken = time.time() - start + if taken > self._slow_threshold: + filename = os.path.relpath(filename, reporter._root_dir) + reporter.slow_test_functions.append( + (filename + "::" + f.__name__, taken)) + if getattr(f, '_slow', False) and slow: + if taken < self._fast_threshold: + filename = os.path.relpath(filename, reporter._root_dir) + reporter.fast_test_functions.append( + (filename + "::" + f.__name__, taken)) + reporter.leaving_filename() + + def _timeout(self, function, timeout, fail_on_timeout): + def callback(x, y): + signal.alarm(0) + if fail_on_timeout: + raise TimeOutError("Timed out after %d seconds" % timeout) + else: + raise Skipped("Timeout") + signal.signal(signal.SIGALRM, callback) + signal.alarm(timeout) # Set an alarm with a given timeout + function() + signal.alarm(0) # Disable the alarm + + def matches(self, x): + """ + Does the keyword expression self._kw match "x"? Returns True/False. + + Always returns True if self._kw is "". + """ + if not self._kw: + return True + for kw in self._kw: + if x.__name__.lower().find(kw.lower()) != -1: + return True + return False + + def get_test_files(self, dir, pat='test_*.py'): + """ + Returns the list of test_*.py (default) files at or below directory + ``dir`` relative to the SymPy home directory. + """ + dir = os.path.join(self._root_dir, convert_to_native_paths([dir])[0]) + + g = [] + for path, folders, files in os.walk(dir): + g.extend([os.path.join(path, f) for f in files if fnmatch(f, pat)]) + + return sorted([os.path.normcase(gi) for gi in g]) + + +class SymPyDocTests: + + def __init__(self, reporter, normal): + self._count = 0 + self._root_dir = get_sympy_dir() + self._reporter = reporter + self._reporter.root_dir(self._root_dir) + self._normal = normal + + self._testfiles = [] + + def test(self): + """ + Runs the tests and returns True if all tests pass, otherwise False. + """ + self._reporter.start() + for f in self._testfiles: + try: + self.test_file(f) + except KeyboardInterrupt: + print(" interrupted by user") + self._reporter.finish() + raise + return self._reporter.finish() + + def test_file(self, filename): + clear_cache() + + from io import StringIO + import sympy.interactive.printing as interactive_printing + from sympy.printing.pretty.pretty import pprint_use_unicode + from sympy.printing.pretty import stringpict + + rel_name = filename[len(self._root_dir) + 1:] + dirname, file = os.path.split(filename) + module = rel_name.replace(os.sep, '.')[:-3] + + if rel_name.startswith("examples"): + # Examples files do not have __init__.py files, + # So we have to temporarily extend sys.path to import them + sys.path.insert(0, dirname) + module = file[:-3] # remove ".py" + try: + module = pdoctest._normalize_module(module) + tests = SymPyDocTestFinder().find(module) + except (SystemExit, KeyboardInterrupt): + raise + except ImportError: + self._reporter.import_error(filename, sys.exc_info()) + return + finally: + if rel_name.startswith("examples"): + del sys.path[0] + + tests = [test for test in tests if len(test.examples) > 0] + # By default tests are sorted by alphabetical order by function name. + # We sort by line number so one can edit the file sequentially from + # bottom to top. However, if there are decorated functions, their line + # numbers will be too large and for now one must just search for these + # by text and function name. + tests.sort(key=lambda x: -x.lineno) + + if not tests: + return + self._reporter.entering_filename(filename, len(tests)) + for test in tests: + assert len(test.examples) != 0 + + if self._reporter._verbose: + self._reporter.write("\n{} ".format(test.name)) + + # check if there are external dependencies which need to be met + if '_doctest_depends_on' in test.globs: + try: + self._check_dependencies(**test.globs['_doctest_depends_on']) + except DependencyError as e: + self._reporter.test_skip(v=str(e)) + continue + + runner = SymPyDocTestRunner(verbose=self._reporter._verbose==2, + optionflags=pdoctest.ELLIPSIS | + pdoctest.NORMALIZE_WHITESPACE | + pdoctest.IGNORE_EXCEPTION_DETAIL) + runner._checker = SymPyOutputChecker() + old = sys.stdout + new = old if self._reporter._verbose==2 else StringIO() + sys.stdout = new + # If the testing is normal, the doctests get importing magic to + # provide the global namespace. If not normal (the default) then + # then must run on their own; all imports must be explicit within + # a function's docstring. Once imported that import will be + # available to the rest of the tests in a given function's + # docstring (unless clear_globs=True below). + if not self._normal: + test.globs = {} + # if this is uncommented then all the test would get is what + # comes by default with a "from sympy import *" + #exec('from sympy import *') in test.globs + old_displayhook = sys.displayhook + use_unicode_prev, wrap_line_prev = setup_pprint() + + try: + f, t = runner.run(test, + out=new.write, clear_globs=False) + except KeyboardInterrupt: + raise + finally: + sys.stdout = old + if f > 0: + self._reporter.doctest_fail(test.name, new.getvalue()) + else: + self._reporter.test_pass() + sys.displayhook = old_displayhook + interactive_printing.NO_GLOBAL = False + pprint_use_unicode(use_unicode_prev) + stringpict._GLOBAL_WRAP_LINE = wrap_line_prev + + self._reporter.leaving_filename() + + def get_test_files(self, dir, pat='*.py', init_only=True): + r""" + Returns the list of \*.py files (default) from which docstrings + will be tested which are at or below directory ``dir``. By default, + only those that have an __init__.py in their parent directory + and do not start with ``test_`` will be included. + """ + def importable(x): + """ + Checks if given pathname x is an importable module by checking for + __init__.py file. + + Returns True/False. + + Currently we only test if the __init__.py file exists in the + directory with the file "x" (in theory we should also test all the + parent dirs). + """ + init_py = os.path.join(os.path.dirname(x), "__init__.py") + return os.path.exists(init_py) + + dir = os.path.join(self._root_dir, convert_to_native_paths([dir])[0]) + + g = [] + for path, folders, files in os.walk(dir): + g.extend([os.path.join(path, f) for f in files + if not f.startswith('test_') and fnmatch(f, pat)]) + if init_only: + # skip files that are not importable (i.e. missing __init__.py) + g = [x for x in g if importable(x)] + + return [os.path.normcase(gi) for gi in g] + + def _check_dependencies(self, + executables=(), + modules=(), + disable_viewers=(), + python_version=(3, 5), + ground_types=None): + """ + Checks if the dependencies for the test are installed. + + Raises ``DependencyError`` it at least one dependency is not installed. + """ + + for executable in executables: + if not shutil.which(executable): + raise DependencyError("Could not find %s" % executable) + + for module in modules: + if module == 'matplotlib': + matplotlib = import_module( + 'matplotlib', + import_kwargs={'fromlist': + ['pyplot', 'cm', 'collections']}, + min_module_version='1.0.0', catch=(RuntimeError,)) + if matplotlib is None: + raise DependencyError("Could not import matplotlib") + else: + if not import_module(module): + raise DependencyError("Could not import %s" % module) + + if disable_viewers: + tempdir = tempfile.mkdtemp() + os.environ['PATH'] = '%s:%s' % (tempdir, os.environ['PATH']) + + vw = ('#!/usr/bin/env python3\n' + 'import sys\n' + 'if len(sys.argv) <= 1:\n' + ' exit("wrong number of args")\n') + + for viewer in disable_viewers: + Path(os.path.join(tempdir, viewer)).write_text(vw) + + # make the file executable + os.chmod(os.path.join(tempdir, viewer), + stat.S_IREAD | stat.S_IWRITE | stat.S_IXUSR) + + if python_version: + if sys.version_info < python_version: + raise DependencyError("Requires Python >= " + '.'.join(map(str, python_version))) + + if ground_types is not None: + if GROUND_TYPES not in ground_types: + raise DependencyError("Requires ground_types in " + str(ground_types)) + + if 'pyglet' in modules: + # monkey-patch pyglet s.t. it does not open a window during + # doctesting + import pyglet + class DummyWindow: + def __init__(self, *args, **kwargs): + self.has_exit = True + self.width = 600 + self.height = 400 + + def set_vsync(self, x): + pass + + def switch_to(self): + pass + + def push_handlers(self, x): + pass + + def close(self): + pass + + pyglet.window.Window = DummyWindow + + +class SymPyDocTestFinder(DocTestFinder): + """ + A class used to extract the DocTests that are relevant to a given + object, from its docstring and the docstrings of its contained + objects. Doctests can currently be extracted from the following + object types: modules, functions, classes, methods, staticmethods, + classmethods, and properties. + + Modified from doctest's version to look harder for code that + appears comes from a different module. For example, the @vectorize + decorator makes it look like functions come from multidimensional.py + even though their code exists elsewhere. + """ + + def _find(self, tests, obj, name, module, source_lines, globs, seen): + """ + Find tests for the given object and any contained objects, and + add them to ``tests``. + """ + if self._verbose: + print('Finding tests in %s' % name) + + # If we've already processed this object, then ignore it. + if id(obj) in seen: + return + seen[id(obj)] = 1 + + # Make sure we don't run doctests for classes outside of sympy, such + # as in numpy or scipy. + if inspect.isclass(obj): + if obj.__module__.split('.')[0] != 'sympy': + return + + # Find a test for this object, and add it to the list of tests. + test = self._get_test(obj, name, module, globs, source_lines) + if test is not None: + tests.append(test) + + if not self._recurse: + return + + # Look for tests in a module's contained objects. + if inspect.ismodule(obj): + for rawname, val in obj.__dict__.items(): + # Recurse to functions & classes. + if inspect.isfunction(val) or inspect.isclass(val): + # Make sure we don't run doctests functions or classes + # from different modules + if val.__module__ != module.__name__: + continue + + assert self._from_module(module, val), \ + "%s is not in module %s (rawname %s)" % (val, module, rawname) + + try: + valname = '%s.%s' % (name, rawname) + self._find(tests, val, valname, module, + source_lines, globs, seen) + except KeyboardInterrupt: + raise + + # Look for tests in a module's __test__ dictionary. + for valname, val in getattr(obj, '__test__', {}).items(): + if not isinstance(valname, str): + raise ValueError("SymPyDocTestFinder.find: __test__ keys " + "must be strings: %r" % + (type(valname),)) + if not (inspect.isfunction(val) or inspect.isclass(val) or + inspect.ismethod(val) or inspect.ismodule(val) or + isinstance(val, str)): + raise ValueError("SymPyDocTestFinder.find: __test__ values " + "must be strings, functions, methods, " + "classes, or modules: %r" % + (type(val),)) + valname = '%s.__test__.%s' % (name, valname) + self._find(tests, val, valname, module, source_lines, + globs, seen) + + + # Look for tests in a class's contained objects. + if inspect.isclass(obj): + for valname, val in obj.__dict__.items(): + # Special handling for staticmethod/classmethod. + if isinstance(val, staticmethod): + val = getattr(obj, valname) + if isinstance(val, classmethod): + val = getattr(obj, valname).__func__ + + + # Recurse to methods, properties, and nested classes. + if ((inspect.isfunction(unwrap(val)) or + inspect.isclass(val) or + isinstance(val, property)) and + self._from_module(module, val)): + # Make sure we don't run doctests functions or classes + # from different modules + if isinstance(val, property): + if hasattr(val.fget, '__module__'): + if val.fget.__module__ != module.__name__: + continue + else: + if val.__module__ != module.__name__: + continue + + assert self._from_module(module, val), \ + "%s is not in module %s (valname %s)" % ( + val, module, valname) + + valname = '%s.%s' % (name, valname) + self._find(tests, val, valname, module, source_lines, + globs, seen) + + def _get_test(self, obj, name, module, globs, source_lines): + """ + Return a DocTest for the given object, if it defines a docstring; + otherwise, return None. + """ + + lineno = None + + # Extract the object's docstring. If it does not have one, + # then return None (no test for this object). + if isinstance(obj, str): + # obj is a string in the case for objects in the polys package. + # Note that source_lines is a binary string (compiled polys + # modules), which can't be handled by _find_lineno so determine + # the line number here. + + docstring = obj + + matches = re.findall(r"line \d+", name) + assert len(matches) == 1, \ + "string '%s' does not contain lineno " % name + + # NOTE: this is not the exact linenumber but its better than no + # lineno ;) + lineno = int(matches[0][5:]) + + else: + docstring = getattr(obj, '__doc__', '') + if docstring is None: + docstring = '' + if not isinstance(docstring, str): + docstring = str(docstring) + + # Don't bother if the docstring is empty. + if self._exclude_empty and not docstring: + return None + + # check that properties have a docstring because _find_lineno + # assumes it + if isinstance(obj, property): + if obj.fget.__doc__ is None: + return None + + # Find the docstring's location in the file. + if lineno is None: + obj = unwrap(obj) + # handling of properties is not implemented in _find_lineno so do + # it here + if hasattr(obj, 'func_closure') and obj.func_closure is not None: + tobj = obj.func_closure[0].cell_contents + elif isinstance(obj, property): + tobj = obj.fget + else: + tobj = obj + lineno = self._find_lineno(tobj, source_lines) + + if lineno is None: + return None + + # Return a DocTest for this object. + if module is None: + filename = None + else: + filename = getattr(module, '__file__', module.__name__) + if filename[-4:] in (".pyc", ".pyo"): + filename = filename[:-1] + + globs['_doctest_depends_on'] = getattr(obj, '_doctest_depends_on', {}) + + return self._parser.get_doctest(docstring, globs, name, + filename, lineno) + + +class SymPyDocTestRunner(DocTestRunner): + """ + A class used to run DocTest test cases, and accumulate statistics. + The ``run`` method is used to process a single DocTest case. It + returns a tuple ``(f, t)``, where ``t`` is the number of test cases + tried, and ``f`` is the number of test cases that failed. + + Modified from the doctest version to not reset the sys.displayhook (see + issue 5140). + + See the docstring of the original DocTestRunner for more information. + """ + + def run(self, test, compileflags=None, out=None, clear_globs=True): + """ + Run the examples in ``test``, and display the results using the + writer function ``out``. + + The examples are run in the namespace ``test.globs``. If + ``clear_globs`` is true (the default), then this namespace will + be cleared after the test runs, to help with garbage + collection. If you would like to examine the namespace after + the test completes, then use ``clear_globs=False``. + + ``compileflags`` gives the set of flags that should be used by + the Python compiler when running the examples. If not + specified, then it will default to the set of future-import + flags that apply to ``globs``. + + The output of each example is checked using + ``SymPyDocTestRunner.check_output``, and the results are + formatted by the ``SymPyDocTestRunner.report_*`` methods. + """ + self.test = test + + # Remove ``` from the end of example, which may appear in Markdown + # files + for example in test.examples: + example.want = example.want.replace('```\n', '') + example.exc_msg = example.exc_msg and example.exc_msg.replace('```\n', '') + + + if compileflags is None: + compileflags = pdoctest._extract_future_flags(test.globs) + + save_stdout = sys.stdout + if out is None: + out = save_stdout.write + sys.stdout = self._fakeout + + # Patch pdb.set_trace to restore sys.stdout during interactive + # debugging (so it's not still redirected to self._fakeout). + # Note that the interactive output will go to *our* + # save_stdout, even if that's not the real sys.stdout; this + # allows us to write test cases for the set_trace behavior. + save_set_trace = pdb.set_trace + self.debugger = pdoctest._OutputRedirectingPdb(save_stdout) + self.debugger.reset() + pdb.set_trace = self.debugger.set_trace + + # Patch linecache.getlines, so we can see the example's source + # when we're inside the debugger. + self.save_linecache_getlines = pdoctest.linecache.getlines + linecache.getlines = self.__patched_linecache_getlines + + # Fail for deprecation warnings + with raise_on_deprecated(): + try: + return self.__run(test, compileflags, out) + finally: + sys.stdout = save_stdout + pdb.set_trace = save_set_trace + linecache.getlines = self.save_linecache_getlines + if clear_globs: + test.globs.clear() + + +# We have to override the name mangled methods. +monkeypatched_methods = [ + 'patched_linecache_getlines', + 'run', + 'record_outcome' +] +for method in monkeypatched_methods: + oldname = '_DocTestRunner__' + method + newname = '_SymPyDocTestRunner__' + method + setattr(SymPyDocTestRunner, newname, getattr(DocTestRunner, oldname)) + + +class SymPyOutputChecker(pdoctest.OutputChecker): + """ + Compared to the OutputChecker from the stdlib our OutputChecker class + supports numerical comparison of floats occurring in the output of the + doctest examples + """ + + def __init__(self): + # NOTE OutputChecker is an old-style class with no __init__ method, + # so we can't call the base class version of __init__ here + + got_floats = r'(\d+\.\d*|\.\d+)' + + # floats in the 'want' string may contain ellipses + want_floats = got_floats + r'(\.{3})?' + + front_sep = r'\s|\+|\-|\*|,' + back_sep = front_sep + r'|j|e' + + fbeg = r'^%s(?=%s|$)' % (got_floats, back_sep) + fmidend = r'(?<=%s)%s(?=%s|$)' % (front_sep, got_floats, back_sep) + self.num_got_rgx = re.compile(r'(%s|%s)' %(fbeg, fmidend)) + + fbeg = r'^%s(?=%s|$)' % (want_floats, back_sep) + fmidend = r'(?<=%s)%s(?=%s|$)' % (front_sep, want_floats, back_sep) + self.num_want_rgx = re.compile(r'(%s|%s)' %(fbeg, fmidend)) + + def check_output(self, want, got, optionflags): + """ + Return True iff the actual output from an example (`got`) + matches the expected output (`want`). These strings are + always considered to match if they are identical; but + depending on what option flags the test runner is using, + several non-exact match types are also possible. See the + documentation for `TestRunner` for more information about + option flags. + """ + # Handle the common case first, for efficiency: + # if they're string-identical, always return true. + if got == want: + return True + + # TODO parse integers as well ? + # Parse floats and compare them. If some of the parsed floats contain + # ellipses, skip the comparison. + matches = self.num_got_rgx.finditer(got) + numbers_got = [match.group(1) for match in matches] # list of strs + matches = self.num_want_rgx.finditer(want) + numbers_want = [match.group(1) for match in matches] # list of strs + if len(numbers_got) != len(numbers_want): + return False + + if len(numbers_got) > 0: + nw_ = [] + for ng, nw in zip(numbers_got, numbers_want): + if '...' in nw: + nw_.append(ng) + continue + else: + nw_.append(nw) + + if abs(float(ng)-float(nw)) > 1e-5: + return False + + got = self.num_got_rgx.sub(r'%s', got) + got = got % tuple(nw_) + + # can be used as a special sequence to signify a + # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. + if not (optionflags & pdoctest.DONT_ACCEPT_BLANKLINE): + # Replace in want with a blank line. + want = re.sub(r'(?m)^%s\s*?$' % re.escape(pdoctest.BLANKLINE_MARKER), + '', want) + # If a line in got contains only spaces, then remove the + # spaces. + got = re.sub(r'(?m)^\s*?$', '', got) + if got == want: + return True + + # This flag causes doctest to ignore any differences in the + # contents of whitespace strings. Note that this can be used + # in conjunction with the ELLIPSIS flag. + if optionflags & pdoctest.NORMALIZE_WHITESPACE: + got = ' '.join(got.split()) + want = ' '.join(want.split()) + if got == want: + return True + + # The ELLIPSIS flag says to let the sequence "..." in `want` + # match any substring in `got`. + if optionflags & pdoctest.ELLIPSIS: + if pdoctest._ellipsis_match(want, got): + return True + + # We didn't find any match; return false. + return False + + +class Reporter: + """ + Parent class for all reporters. + """ + pass + + +class PyTestReporter(Reporter): + """ + Py.test like reporter. Should produce output identical to py.test. + """ + + def __init__(self, verbose=False, tb="short", colors=True, + force_colors=False, split=None): + self._verbose = verbose + self._tb_style = tb + self._colors = colors + self._force_colors = force_colors + self._xfailed = 0 + self._xpassed = [] + self._failed = [] + self._failed_doctest = [] + self._passed = 0 + self._skipped = 0 + self._exceptions = [] + self._terminal_width = None + self._default_width = 80 + self._split = split + self._active_file = '' + self._active_f = None + + # TODO: Should these be protected? + self.slow_test_functions = [] + self.fast_test_functions = [] + + # this tracks the x-position of the cursor (useful for positioning + # things on the screen), without the need for any readline library: + self._write_pos = 0 + self._line_wrap = False + + def root_dir(self, dir): + self._root_dir = dir + + @property + def terminal_width(self): + if self._terminal_width is not None: + return self._terminal_width + + def findout_terminal_width(): + if sys.platform == "win32": + # Windows support is based on: + # + # http://code.activestate.com/recipes/ + # 440694-determine-size-of-console-window-on-windows/ + + from ctypes import windll, create_string_buffer + + h = windll.kernel32.GetStdHandle(-12) + csbi = create_string_buffer(22) + res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) + + if res: + import struct + (_, _, _, _, _, left, _, right, _, _, _) = \ + struct.unpack("hhhhHhhhhhh", csbi.raw) + return right - left + else: + return self._default_width + + if hasattr(sys.stdout, 'isatty') and not sys.stdout.isatty(): + return self._default_width # leave PIPEs alone + + try: + process = subprocess.Popen(['stty', '-a'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + stdout = stdout.decode("utf-8") + except OSError: + pass + else: + # We support the following output formats from stty: + # + # 1) Linux -> columns 80 + # 2) OS X -> 80 columns + # 3) Solaris -> columns = 80 + + re_linux = r"columns\s+(?P\d+);" + re_osx = r"(?P\d+)\s*columns;" + re_solaris = r"columns\s+=\s+(?P\d+);" + + for regex in (re_linux, re_osx, re_solaris): + match = re.search(regex, stdout) + + if match is not None: + columns = match.group('columns') + + try: + width = int(columns) + except ValueError: + pass + if width != 0: + return width + + return self._default_width + + width = findout_terminal_width() + self._terminal_width = width + + return width + + def write(self, text, color="", align="left", width=None, + force_colors=False): + """ + Prints a text on the screen. + + It uses sys.stdout.write(), so no readline library is necessary. + + Parameters + ========== + + color : choose from the colors below, "" means default color + align : "left"/"right", "left" is a normal print, "right" is aligned on + the right-hand side of the screen, filled with spaces if + necessary + width : the screen width + + """ + color_templates = ( + ("Black", "0;30"), + ("Red", "0;31"), + ("Green", "0;32"), + ("Brown", "0;33"), + ("Blue", "0;34"), + ("Purple", "0;35"), + ("Cyan", "0;36"), + ("LightGray", "0;37"), + ("DarkGray", "1;30"), + ("LightRed", "1;31"), + ("LightGreen", "1;32"), + ("Yellow", "1;33"), + ("LightBlue", "1;34"), + ("LightPurple", "1;35"), + ("LightCyan", "1;36"), + ("White", "1;37"), + ) + + colors = {} + + for name, value in color_templates: + colors[name] = value + c_normal = '\033[0m' + c_color = '\033[%sm' + + if width is None: + width = self.terminal_width + + if align == "right": + if self._write_pos + len(text) > width: + # we don't fit on the current line, create a new line + self.write("\n") + self.write(" "*(width - self._write_pos - len(text))) + + if not self._force_colors and hasattr(sys.stdout, 'isatty') and not \ + sys.stdout.isatty(): + # the stdout is not a terminal, this for example happens if the + # output is piped to less, e.g. "bin/test | less". In this case, + # the terminal control sequences would be printed verbatim, so + # don't use any colors. + color = "" + elif sys.platform == "win32": + # Windows consoles don't support ANSI escape sequences + color = "" + elif not self._colors: + color = "" + + if self._line_wrap: + if text[0] != "\n": + sys.stdout.write("\n") + + # Avoid UnicodeEncodeError when printing out test failures + if IS_WINDOWS: + text = text.encode('raw_unicode_escape').decode('utf8', 'ignore') + elif not sys.stdout.encoding.lower().startswith('utf'): + text = text.encode(sys.stdout.encoding, 'backslashreplace' + ).decode(sys.stdout.encoding) + + if color == "": + sys.stdout.write(text) + else: + sys.stdout.write("%s%s%s" % + (c_color % colors[color], text, c_normal)) + sys.stdout.flush() + l = text.rfind("\n") + if l == -1: + self._write_pos += len(text) + else: + self._write_pos = len(text) - l - 1 + self._line_wrap = self._write_pos >= width + self._write_pos %= width + + def write_center(self, text, delim="="): + width = self.terminal_width + if text != "": + text = " %s " % text + idx = (width - len(text)) // 2 + t = delim*idx + text + delim*(width - idx - len(text)) + self.write(t + "\n") + + def write_exception(self, e, val, tb): + # remove the first item, as that is always runtests.py + tb = tb.tb_next + t = traceback.format_exception(e, val, tb) + self.write("".join(t)) + + def start(self, seed=None, msg="test process starts"): + self.write_center(msg) + executable = sys.executable + v = tuple(sys.version_info) + python_version = "%s.%s.%s-%s-%s" % v + implementation = platform.python_implementation() + if implementation == 'PyPy': + implementation += " %s.%s.%s-%s-%s" % sys.pypy_version_info + self.write("executable: %s (%s) [%s]\n" % + (executable, python_version, implementation)) + from sympy.utilities.misc import ARCH + self.write("architecture: %s\n" % ARCH) + from sympy.core.cache import USE_CACHE + self.write("cache: %s\n" % USE_CACHE) + version = '' + if GROUND_TYPES =='gmpy': + import gmpy2 as gmpy + version = gmpy.version() + self.write("ground types: %s %s\n" % (GROUND_TYPES, version)) + numpy = import_module('numpy') + self.write("numpy: %s\n" % (None if not numpy else numpy.__version__)) + if seed is not None: + self.write("random seed: %d\n" % seed) + from sympy.utilities.misc import HASH_RANDOMIZATION + self.write("hash randomization: ") + hash_seed = os.getenv("PYTHONHASHSEED") or '0' + if HASH_RANDOMIZATION and (hash_seed == "random" or int(hash_seed)): + self.write("on (PYTHONHASHSEED=%s)\n" % hash_seed) + else: + self.write("off\n") + if self._split: + self.write("split: %s\n" % self._split) + self.write('\n') + self._t_start = clock() + + def finish(self): + self._t_end = clock() + self.write("\n") + global text, linelen + text = "tests finished: %d passed, " % self._passed + linelen = len(text) + + def add_text(mytext): + global text, linelen + """Break new text if too long.""" + if linelen + len(mytext) > self.terminal_width: + text += '\n' + linelen = 0 + text += mytext + linelen += len(mytext) + + if len(self._failed) > 0: + add_text("%d failed, " % len(self._failed)) + if len(self._failed_doctest) > 0: + add_text("%d failed, " % len(self._failed_doctest)) + if self._skipped > 0: + add_text("%d skipped, " % self._skipped) + if self._xfailed > 0: + add_text("%d expected to fail, " % self._xfailed) + if len(self._xpassed) > 0: + add_text("%d expected to fail but passed, " % len(self._xpassed)) + if len(self._exceptions) > 0: + add_text("%d exceptions, " % len(self._exceptions)) + add_text("in %.2f seconds" % (self._t_end - self._t_start)) + + if self.slow_test_functions: + self.write_center('slowest tests', '_') + sorted_slow = sorted(self.slow_test_functions, key=lambda r: r[1]) + for slow_func_name, taken in sorted_slow: + print('%s - Took %.3f seconds' % (slow_func_name, taken)) + + if self.fast_test_functions: + self.write_center('unexpectedly fast tests', '_') + sorted_fast = sorted(self.fast_test_functions, + key=lambda r: r[1]) + for fast_func_name, taken in sorted_fast: + print('%s - Took %.3f seconds' % (fast_func_name, taken)) + + if len(self._xpassed) > 0: + self.write_center("xpassed tests", "_") + for e in self._xpassed: + self.write("%s: %s\n" % (e[0], e[1])) + self.write("\n") + + if self._tb_style != "no" and len(self._exceptions) > 0: + for e in self._exceptions: + filename, f, (t, val, tb) = e + self.write_center("", "_") + if f is None: + s = "%s" % filename + else: + s = "%s:%s" % (filename, f.__name__) + self.write_center(s, "_") + self.write_exception(t, val, tb) + self.write("\n") + + if self._tb_style != "no" and len(self._failed) > 0: + for e in self._failed: + filename, f, (t, val, tb) = e + self.write_center("", "_") + self.write_center("%s::%s" % (filename, f.__name__), "_") + self.write_exception(t, val, tb) + self.write("\n") + + if self._tb_style != "no" and len(self._failed_doctest) > 0: + for e in self._failed_doctest: + filename, msg = e + self.write_center("", "_") + self.write_center("%s" % filename, "_") + self.write(msg) + self.write("\n") + + self.write_center(text) + ok = len(self._failed) == 0 and len(self._exceptions) == 0 and \ + len(self._failed_doctest) == 0 + if not ok: + self.write("DO *NOT* COMMIT!\n") + return ok + + def entering_filename(self, filename, n): + rel_name = filename[len(self._root_dir) + 1:] + self._active_file = rel_name + self._active_file_error = False + self.write(rel_name) + self.write("[%d] " % n) + + def leaving_filename(self): + self.write(" ") + if self._active_file_error: + self.write("[FAIL]", "Red", align="right") + else: + self.write("[OK]", "Green", align="right") + self.write("\n") + if self._verbose: + self.write("\n") + + def entering_test(self, f): + self._active_f = f + if self._verbose: + self.write("\n" + f.__name__ + " ") + + def test_xfail(self): + self._xfailed += 1 + self.write("f", "Green") + + def test_xpass(self, v): + message = str(v) + self._xpassed.append((self._active_file, message)) + self.write("X", "Green") + + def test_fail(self, exc_info): + self._failed.append((self._active_file, self._active_f, exc_info)) + self.write("F", "Red") + self._active_file_error = True + + def doctest_fail(self, name, error_msg): + # the first line contains "******", remove it: + error_msg = "\n".join(error_msg.split("\n")[1:]) + self._failed_doctest.append((name, error_msg)) + self.write("F", "Red") + self._active_file_error = True + + def test_pass(self, char="."): + self._passed += 1 + if self._verbose: + self.write("ok", "Green") + else: + self.write(char, "Green") + + def test_skip(self, v=None): + char = "s" + self._skipped += 1 + if v is not None: + message = str(v) + if message == "KeyboardInterrupt": + char = "K" + elif message == "Timeout": + char = "T" + elif message == "Slow": + char = "w" + if self._verbose: + if v is not None: + self.write(message + ' ', "Blue") + else: + self.write(" - ", "Blue") + self.write(char, "Blue") + + def test_exception(self, exc_info): + self._exceptions.append((self._active_file, self._active_f, exc_info)) + if exc_info[0] is TimeOutError: + self.write("T", "Red") + else: + self.write("E", "Red") + self._active_file_error = True + + def import_error(self, filename, exc_info): + self._exceptions.append((filename, None, exc_info)) + rel_name = filename[len(self._root_dir) + 1:] + self.write(rel_name) + self.write("[?] Failed to import", "Red") + self.write(" ") + self.write("[FAIL]", "Red", align="right") + self.write("\n") diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/runtests_pytest.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/runtests_pytest.py new file mode 100644 index 0000000000000000000000000000000000000000..635f27864ca86571128e6c9a055199dfbde1ed63 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/runtests_pytest.py @@ -0,0 +1,461 @@ +"""Backwards compatible functions for running tests from SymPy using pytest. + +SymPy historically had its own testing framework that aimed to: +- be compatible with pytest; +- operate similarly (or identically) to pytest; +- not require any external dependencies; +- have all the functionality in one file only; +- have no magic, just import the test file and execute the test functions; and +- be portable. + +To reduce the maintenance burden of developing an independent testing framework +and to leverage the benefits of existing Python testing infrastructure, SymPy +now uses pytest (and various of its plugins) to run the test suite. + +To maintain backwards compatibility with the legacy testing interface of SymPy, +which implemented functions that allowed users to run the tests on their +installed version of SymPy, the functions in this module are implemented to +match the existing API while thinly wrapping pytest. + +These two key functions are `test` and `doctest`. + +""" + +import functools +import importlib.util +import os +import pathlib +import re +from fnmatch import fnmatch +from typing import List, Optional, Tuple + +try: + import pytest +except ImportError: + + class NoPytestError(Exception): + """Raise when an internal test helper function is called with pytest.""" + + class pytest: # type: ignore + """Shadow to support pytest features when pytest can't be imported.""" + + @staticmethod + def main(*args, **kwargs): + msg = 'pytest must be installed to run tests via this function' + raise NoPytestError(msg) + +from sympy.testing.runtests import test as test_sympy + + +TESTPATHS_DEFAULT = ( + pathlib.Path('sympy'), + pathlib.Path('doc', 'src'), +) +BLACKLIST_DEFAULT = ( + 'sympy/integrals/rubi/rubi_tests/tests', +) + + +class PytestPluginManager: + """Module names for pytest plugins used by SymPy.""" + PYTEST: str = 'pytest' + RANDOMLY: str = 'pytest_randomly' + SPLIT: str = 'pytest_split' + TIMEOUT: str = 'pytest_timeout' + XDIST: str = 'xdist' + + @functools.cached_property + def has_pytest(self) -> bool: + return bool(importlib.util.find_spec(self.PYTEST)) + + @functools.cached_property + def has_randomly(self) -> bool: + return bool(importlib.util.find_spec(self.RANDOMLY)) + + @functools.cached_property + def has_split(self) -> bool: + return bool(importlib.util.find_spec(self.SPLIT)) + + @functools.cached_property + def has_timeout(self) -> bool: + return bool(importlib.util.find_spec(self.TIMEOUT)) + + @functools.cached_property + def has_xdist(self) -> bool: + return bool(importlib.util.find_spec(self.XDIST)) + + +split_pattern = re.compile(r'([1-9][0-9]*)/([1-9][0-9]*)') + + +@functools.lru_cache +def sympy_dir() -> pathlib.Path: + """Returns the root SymPy directory.""" + return pathlib.Path(__file__).parents[2] + + +def update_args_with_paths( + paths: List[str], + keywords: Optional[Tuple[str]], + args: List[str], +) -> List[str]: + """Appends valid paths and flags to the args `list` passed to `pytest.main`. + + The are three different types of "path" that a user may pass to the `paths` + positional arguments, all of which need to be handled slightly differently: + + 1. Nothing is passed + The paths to the `testpaths` defined in `pytest.ini` need to be appended + to the arguments list. + 2. Full, valid paths are passed + These paths need to be validated but can then be directly appended to + the arguments list. + 3. Partial paths are passed. + The `testpaths` defined in `pytest.ini` need to be recursed and any + matches be appended to the arguments list. + + """ + + def find_paths_matching_partial(partial_paths): + partial_path_file_patterns = [] + for partial_path in partial_paths: + if len(partial_path) >= 4: + has_test_prefix = partial_path[:4] == 'test' + has_py_suffix = partial_path[-3:] == '.py' + elif len(partial_path) >= 3: + has_test_prefix = False + has_py_suffix = partial_path[-3:] == '.py' + else: + has_test_prefix = False + has_py_suffix = False + if has_test_prefix and has_py_suffix: + partial_path_file_patterns.append(partial_path) + elif has_test_prefix: + partial_path_file_patterns.append(f'{partial_path}*.py') + elif has_py_suffix: + partial_path_file_patterns.append(f'test*{partial_path}') + else: + partial_path_file_patterns.append(f'test*{partial_path}*.py') + matches = [] + for testpath in valid_testpaths_default: + for path, dirs, files in os.walk(testpath, topdown=True): + zipped = zip(partial_paths, partial_path_file_patterns) + for (partial_path, partial_path_file) in zipped: + if fnmatch(path, f'*{partial_path}*'): + matches.append(str(pathlib.Path(path))) + dirs[:] = [] + else: + for file in files: + if fnmatch(file, partial_path_file): + matches.append(str(pathlib.Path(path, file))) + return matches + + def is_tests_file(filepath: str) -> bool: + path = pathlib.Path(filepath) + if not path.is_file(): + return False + if not path.parts[-1].startswith('test_'): + return False + if not path.suffix == '.py': + return False + return True + + def find_tests_matching_keywords(keywords, filepath): + matches = [] + source = pathlib.Path(filepath).read_text(encoding='utf-8') + for line in source.splitlines(): + if line.lstrip().startswith('def '): + for kw in keywords: + if line.lower().find(kw.lower()) != -1: + test_name = line.split(' ')[1].split('(')[0] + full_test_path = filepath + '::' + test_name + matches.append(full_test_path) + return matches + + valid_testpaths_default = [] + for testpath in TESTPATHS_DEFAULT: + absolute_testpath = pathlib.Path(sympy_dir(), testpath) + if absolute_testpath.exists(): + valid_testpaths_default.append(str(absolute_testpath)) + + candidate_paths = [] + if paths: + full_paths = [] + partial_paths = [] + for path in paths: + if pathlib.Path(path).exists(): + full_paths.append(str(pathlib.Path(sympy_dir(), path))) + else: + partial_paths.append(path) + matched_paths = find_paths_matching_partial(partial_paths) + candidate_paths.extend(full_paths) + candidate_paths.extend(matched_paths) + else: + candidate_paths.extend(valid_testpaths_default) + + if keywords is not None and keywords != (): + matches = [] + for path in candidate_paths: + if is_tests_file(path): + test_matches = find_tests_matching_keywords(keywords, path) + matches.extend(test_matches) + else: + for root, dirnames, filenames in os.walk(path): + for filename in filenames: + absolute_filepath = str(pathlib.Path(root, filename)) + if is_tests_file(absolute_filepath): + test_matches = find_tests_matching_keywords( + keywords, + absolute_filepath, + ) + matches.extend(test_matches) + args.extend(matches) + else: + args.extend(candidate_paths) + + return args + + +def make_absolute_path(partial_path: str) -> str: + """Convert a partial path to an absolute path. + + A path such a `sympy/core` might be needed. However, absolute paths should + be used in the arguments to pytest in all cases as it avoids errors that + arise from nonexistent paths. + + This function assumes that partial_paths will be passed in such that they + begin with the explicit `sympy` directory, i.e. `sympy/...`. + + """ + + def is_valid_partial_path(partial_path: str) -> bool: + """Assumption that partial paths are defined from the `sympy` root.""" + return pathlib.Path(partial_path).parts[0] == 'sympy' + + if not is_valid_partial_path(partial_path): + msg = ( + f'Partial path {dir(partial_path)} is invalid, partial paths are ' + f'expected to be defined with the `sympy` directory as the root.' + ) + raise ValueError(msg) + + absolute_path = str(pathlib.Path(sympy_dir(), partial_path)) + return absolute_path + + +def test(*paths, subprocess=True, rerun=0, **kwargs): + """Interface to run tests via pytest compatible with SymPy's test runner. + + Explanation + =========== + + Note that a `pytest.ExitCode`, which is an `enum`, is returned. This is + different to the legacy SymPy test runner which would return a `bool`. If + all tests successfully pass the `pytest.ExitCode.OK` with value `0` is + returned, whereas the legacy SymPy test runner would return `True`. In any + other scenario, a non-zero `enum` value is returned, whereas the legacy + SymPy test runner would return `False`. Users need to, therefore, be careful + if treating the pytest exit codes as booleans because + `bool(pytest.ExitCode.OK)` evaluates to `False`, the opposite of legacy + behaviour. + + Examples + ======== + + >>> import sympy # doctest: +SKIP + + Run one file: + + >>> sympy.test('sympy/core/tests/test_basic.py') # doctest: +SKIP + >>> sympy.test('_basic') # doctest: +SKIP + + Run all tests in sympy/functions/ and some particular file: + + >>> sympy.test("sympy/core/tests/test_basic.py", + ... "sympy/functions") # doctest: +SKIP + + Run all tests in sympy/core and sympy/utilities: + + >>> sympy.test("/core", "/util") # doctest: +SKIP + + Run specific test from a file: + + >>> sympy.test("sympy/core/tests/test_basic.py", + ... kw="test_equality") # doctest: +SKIP + + Run specific test from any file: + + >>> sympy.test(kw="subs") # doctest: +SKIP + + Run the tests using the legacy SymPy runner: + + >>> sympy.test(use_sympy_runner=True) # doctest: +SKIP + + Note that this option is slated for deprecation in the near future and is + only currently provided to ensure users have an alternative option while the + pytest-based runner receives real-world testing. + + Parameters + ========== + paths : first n positional arguments of strings + Paths, both partial and absolute, describing which subset(s) of the test + suite are to be run. + subprocess : bool, default is True + Legacy option, is currently ignored. + rerun : int, default is 0 + Legacy option, is ignored. + use_sympy_runner : bool or None, default is None + Temporary option to invoke the legacy SymPy test runner instead of + `pytest.main`. Will be removed in the near future. + verbose : bool, default is False + Sets the verbosity of the pytest output. Using `True` will add the + `--verbose` option to the pytest call. + tb : str, 'auto', 'long', 'short', 'line', 'native', or 'no' + Sets the traceback print mode of pytest using the `--tb` option. + kw : str + Only run tests which match the given substring expression. An expression + is a Python evaluatable expression where all names are substring-matched + against test names and their parent classes. Example: -k 'test_method or + test_other' matches all test functions and classes whose name contains + 'test_method' or 'test_other', while -k 'not test_method' matches those + that don't contain 'test_method' in their names. -k 'not test_method and + not test_other' will eliminate the matches. Additionally keywords are + matched to classes and functions containing extra names in their + 'extra_keyword_matches' set, as well as functions which have names + assigned directly to them. The matching is case-insensitive. + pdb : bool, default is False + Start the interactive Python debugger on errors or `KeyboardInterrupt`. + colors : bool, default is True + Color terminal output. + force_colors : bool, default is False + Legacy option, is ignored. + sort : bool, default is True + Run the tests in sorted order. pytest uses a sorted test order by + default. Requires pytest-randomly. + seed : int + Seed to use for random number generation. Requires pytest-randomly. + timeout : int, default is 0 + Timeout in seconds before dumping the stacks. 0 means no timeout. + Requires pytest-timeout. + fail_on_timeout : bool, default is False + Legacy option, is currently ignored. + slow : bool, default is False + Run the subset of tests marked as `slow`. + enhance_asserts : bool, default is False + Legacy option, is currently ignored. + split : string in form `/` or None, default is None + Used to split the tests up. As an example, if `split='2/3' is used then + only the middle third of tests are run. Requires pytest-split. + time_balance : bool, default is True + Legacy option, is currently ignored. + blacklist : iterable of test paths as strings, default is BLACKLIST_DEFAULT + Blacklisted test paths are ignored using the `--ignore` option. Paths + may be partial or absolute. If partial then they are matched against + all paths in the pytest tests path. + parallel : bool, default is False + Parallelize the test running using pytest-xdist. If `True` then pytest + will automatically detect the number of CPU cores available and use them + all. Requires pytest-xdist. + store_durations : bool, False + Store test durations into the file `.test_durations`. The is used by + `pytest-split` to help determine more even splits when more than one + test group is being used. Requires pytest-split. + + """ + # NOTE: to be removed alongside SymPy test runner + if kwargs.get('use_sympy_runner', False): + kwargs.pop('parallel', False) + kwargs.pop('store_durations', False) + kwargs.pop('use_sympy_runner', True) + if kwargs.get('slow') is None: + kwargs['slow'] = False + return test_sympy(*paths, subprocess=True, rerun=0, **kwargs) + + pytest_plugin_manager = PytestPluginManager() + if not pytest_plugin_manager.has_pytest: + pytest.main() + + args = [] + + if kwargs.get('verbose', False): + args.append('--verbose') + + if tb := kwargs.get('tb'): + args.extend(['--tb', tb]) + + if kwargs.get('pdb'): + args.append('--pdb') + + if not kwargs.get('colors', True): + args.extend(['--color', 'no']) + + if seed := kwargs.get('seed'): + if not pytest_plugin_manager.has_randomly: + msg = '`pytest-randomly` plugin required to control random seed.' + raise ModuleNotFoundError(msg) + args.extend(['--randomly-seed', str(seed)]) + + if kwargs.get('sort', True) and pytest_plugin_manager.has_randomly: + args.append('--randomly-dont-reorganize') + elif not kwargs.get('sort', True) and not pytest_plugin_manager.has_randomly: + msg = '`pytest-randomly` plugin required to randomize test order.' + raise ModuleNotFoundError(msg) + + if timeout := kwargs.get('timeout', None): + if not pytest_plugin_manager.has_timeout: + msg = '`pytest-timeout` plugin required to apply timeout to tests.' + raise ModuleNotFoundError(msg) + args.extend(['--timeout', str(int(timeout))]) + + # Skip slow tests by default and always skip tooslow tests + if kwargs.get('slow', False): + args.extend(['-m', 'slow and not tooslow']) + else: + args.extend(['-m', 'not slow and not tooslow']) + + if (split := kwargs.get('split')) is not None: + if not pytest_plugin_manager.has_split: + msg = '`pytest-split` plugin required to run tests as groups.' + raise ModuleNotFoundError(msg) + match = split_pattern.match(split) + if not match: + msg = ('split must be a string of the form a/b where a and b are ' + 'positive nonzero ints') + raise ValueError(msg) + group, splits = map(str, match.groups()) + args.extend(['--group', group, '--splits', splits]) + if group > splits: + msg = (f'cannot have a group number {group} with only {splits} ' + 'splits') + raise ValueError(msg) + + if blacklist := kwargs.get('blacklist', BLACKLIST_DEFAULT): + for path in blacklist: + args.extend(['--ignore', make_absolute_path(path)]) + + if kwargs.get('parallel', False): + if not pytest_plugin_manager.has_xdist: + msg = '`pytest-xdist` plugin required to run tests in parallel.' + raise ModuleNotFoundError(msg) + args.extend(['-n', 'auto']) + + if kwargs.get('store_durations', False): + if not pytest_plugin_manager.has_split: + msg = '`pytest-split` plugin required to store test durations.' + raise ModuleNotFoundError(msg) + args.append('--store-durations') + + if (keywords := kwargs.get('kw')) is not None: + keywords = tuple(str(kw) for kw in keywords) + else: + keywords = () + + args = update_args_with_paths(paths, keywords, args) + exit_code = pytest.main(args) + return exit_code + + +def doctest(): + """Interface to run doctests via pytest compatible with SymPy's test runner. + """ + raise NotImplementedError diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/tmpfiles.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/tmpfiles.py new file mode 100644 index 0000000000000000000000000000000000000000..1d5c69cb58aa11f77679855f3df21f03a10d3b2b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/testing/tmpfiles.py @@ -0,0 +1,46 @@ +""" +This module adds context manager for temporary files generated by the tests. +""" + +import shutil +import os + + +class TmpFileManager: + """ + A class to track record of every temporary files created by the tests. + """ + tmp_files = set('') + tmp_folders = set('') + + @classmethod + def tmp_file(cls, name=''): + cls.tmp_files.add(name) + return name + + @classmethod + def tmp_folder(cls, name=''): + cls.tmp_folders.add(name) + return name + + @classmethod + def cleanup(cls): + while cls.tmp_files: + file = cls.tmp_files.pop() + if os.path.isfile(file): + os.remove(file) + while cls.tmp_folders: + folder = cls.tmp_folders.pop() + shutil.rmtree(folder) + +def cleanup_tmp_files(test_func): + """ + A decorator to help test codes remove temporary files after the tests. + """ + def wrapper_function(): + try: + test_func() + finally: + TmpFileManager.cleanup() + + return wrapper_function diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5c166f9163785f4aa5744324eb817bef79b33525 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__init__.py @@ -0,0 +1,15 @@ +""" Unification in SymPy + +See sympy.unify.core docstring for algorithmic details + +See http://matthewrocklin.com/blog/work/2012/11/01/Unification/ for discussion +""" + +from .usympy import unify, rebuild +from .rewrite import rewriterule + +__all__ = [ + 'unify', 'rebuild', + + 'rewriterule', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d187ac603c037695c17caddaf036ea98203d60d2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/core.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5604736191267c4a0c6e437281c8634ea234e79a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/core.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/rewrite.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/rewrite.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..078f0d8d04695206bc3c41d68c0d8c9ebda8eb67 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/rewrite.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/usympy.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/usympy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea1ec6fee7241853747e35b95c38b8b5448c0721 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/__pycache__/usympy.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/core.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/core.py new file mode 100644 index 0000000000000000000000000000000000000000..5359d0bbd376e9fa9efacff1d90c0bf51414cebf --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/core.py @@ -0,0 +1,234 @@ +""" Generic Unification algorithm for expression trees with lists of children + +This implementation is a direct translation of + +Artificial Intelligence: A Modern Approach by Stuart Russel and Peter Norvig +Second edition, section 9.2, page 276 + +It is modified in the following ways: + +1. We allow associative and commutative Compound expressions. This results in + combinatorial blowup. +2. We explore the tree lazily. +3. We provide generic interfaces to symbolic algebra libraries in Python. + +A more traditional version can be found here +http://aima.cs.berkeley.edu/python/logic.html +""" + +from sympy.utilities.iterables import kbins + +class Compound: + """ A little class to represent an interior node in the tree + + This is analogous to SymPy.Basic for non-Atoms + """ + def __init__(self, op, args): + self.op = op + self.args = args + + def __eq__(self, other): + return (type(self) is type(other) and self.op == other.op and + self.args == other.args) + + def __hash__(self): + return hash((type(self), self.op, self.args)) + + def __str__(self): + return "%s[%s]" % (str(self.op), ', '.join(map(str, self.args))) + +class Variable: + """ A Wild token """ + def __init__(self, arg): + self.arg = arg + + def __eq__(self, other): + return type(self) is type(other) and self.arg == other.arg + + def __hash__(self): + return hash((type(self), self.arg)) + + def __str__(self): + return "Variable(%s)" % str(self.arg) + +class CondVariable: + """ A wild token that matches conditionally. + + arg - a wild token. + valid - an additional constraining function on a match. + """ + def __init__(self, arg, valid): + self.arg = arg + self.valid = valid + + def __eq__(self, other): + return (type(self) is type(other) and + self.arg == other.arg and + self.valid == other.valid) + + def __hash__(self): + return hash((type(self), self.arg, self.valid)) + + def __str__(self): + return "CondVariable(%s)" % str(self.arg) + +def unify(x, y, s=None, **fns): + """ Unify two expressions. + + Parameters + ========== + + x, y - expression trees containing leaves, Compounds and Variables. + s - a mapping of variables to subtrees. + + Returns + ======= + + lazy sequence of mappings {Variable: subtree} + + Examples + ======== + + >>> from sympy.unify.core import unify, Compound, Variable + >>> expr = Compound("Add", ("x", "y")) + >>> pattern = Compound("Add", ("x", Variable("a"))) + >>> next(unify(expr, pattern, {})) + {Variable(a): 'y'} + """ + s = s or {} + + if x == y: + yield s + elif isinstance(x, (Variable, CondVariable)): + yield from unify_var(x, y, s, **fns) + elif isinstance(y, (Variable, CondVariable)): + yield from unify_var(y, x, s, **fns) + elif isinstance(x, Compound) and isinstance(y, Compound): + is_commutative = fns.get('is_commutative', lambda x: False) + is_associative = fns.get('is_associative', lambda x: False) + for sop in unify(x.op, y.op, s, **fns): + if is_associative(x) and is_associative(y): + a, b = (x, y) if len(x.args) < len(y.args) else (y, x) + if is_commutative(x) and is_commutative(y): + combs = allcombinations(a.args, b.args, 'commutative') + else: + combs = allcombinations(a.args, b.args, 'associative') + for aaargs, bbargs in combs: + aa = [unpack(Compound(a.op, arg)) for arg in aaargs] + bb = [unpack(Compound(b.op, arg)) for arg in bbargs] + yield from unify(aa, bb, sop, **fns) + elif len(x.args) == len(y.args): + yield from unify(x.args, y.args, sop, **fns) + + elif is_args(x) and is_args(y) and len(x) == len(y): + if len(x) == 0: + yield s + else: + for shead in unify(x[0], y[0], s, **fns): + yield from unify(x[1:], y[1:], shead, **fns) + +def unify_var(var, x, s, **fns): + if var in s: + yield from unify(s[var], x, s, **fns) + elif occur_check(var, x): + pass + elif isinstance(var, CondVariable) and var.valid(x): + yield assoc(s, var, x) + elif isinstance(var, Variable): + yield assoc(s, var, x) + +def occur_check(var, x): + """ var occurs in subtree owned by x? """ + if var == x: + return True + elif isinstance(x, Compound): + return occur_check(var, x.args) + elif is_args(x): + if any(occur_check(var, xi) for xi in x): return True + return False + +def assoc(d, key, val): + """ Return copy of d with key associated to val """ + d = d.copy() + d[key] = val + return d + +def is_args(x): + """ Is x a traditional iterable? """ + return type(x) in (tuple, list, set) + +def unpack(x): + if isinstance(x, Compound) and len(x.args) == 1: + return x.args[0] + else: + return x + +def allcombinations(A, B, ordered): + """ + Restructure A and B to have the same number of elements. + + Parameters + ========== + + ordered must be either 'commutative' or 'associative'. + + A and B can be rearranged so that the larger of the two lists is + reorganized into smaller sublists. + + Examples + ======== + + >>> from sympy.unify.core import allcombinations + >>> for x in allcombinations((1, 2, 3), (5, 6), 'associative'): print(x) + (((1,), (2, 3)), ((5,), (6,))) + (((1, 2), (3,)), ((5,), (6,))) + + >>> for x in allcombinations((1, 2, 3), (5, 6), 'commutative'): print(x) + (((1,), (2, 3)), ((5,), (6,))) + (((1, 2), (3,)), ((5,), (6,))) + (((1,), (3, 2)), ((5,), (6,))) + (((1, 3), (2,)), ((5,), (6,))) + (((2,), (1, 3)), ((5,), (6,))) + (((2, 1), (3,)), ((5,), (6,))) + (((2,), (3, 1)), ((5,), (6,))) + (((2, 3), (1,)), ((5,), (6,))) + (((3,), (1, 2)), ((5,), (6,))) + (((3, 1), (2,)), ((5,), (6,))) + (((3,), (2, 1)), ((5,), (6,))) + (((3, 2), (1,)), ((5,), (6,))) + """ + + if ordered == "commutative": + ordered = 11 + if ordered == "associative": + ordered = None + sm, bg = (A, B) if len(A) < len(B) else (B, A) + for part in kbins(list(range(len(bg))), len(sm), ordered=ordered): + if bg == B: + yield tuple((a,) for a in A), partition(B, part) + else: + yield partition(A, part), tuple((b,) for b in B) + +def partition(it, part): + """ Partition a tuple/list into pieces defined by indices. + + Examples + ======== + + >>> from sympy.unify.core import partition + >>> partition((10, 20, 30, 40), [[0, 1, 2], [3]]) + ((10, 20, 30), (40,)) + """ + return type(it)([index(it, ind) for ind in part]) + +def index(it, ind): + """ Fancy indexing into an indexable iterable (tuple, list). + + Examples + ======== + + >>> from sympy.unify.core import index + >>> index([10, 20, 30], (1, 2, 0)) + [20, 30, 10] + """ + return type(it)([it[i] for i in ind]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/rewrite.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/rewrite.py new file mode 100644 index 0000000000000000000000000000000000000000..95a6fa5ffd6a3fde94d17ee845c03bb2b44cf009 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/rewrite.py @@ -0,0 +1,55 @@ +""" Functions to support rewriting of SymPy expressions """ + +from sympy.core.expr import Expr +from sympy.assumptions import ask +from sympy.strategies.tools import subs +from sympy.unify.usympy import rebuild, unify + +def rewriterule(source, target, variables=(), condition=None, assume=None): + """ Rewrite rule. + + Transform expressions that match source into expressions that match target + treating all ``variables`` as wilds. + + Examples + ======== + + >>> from sympy.abc import w, x, y, z + >>> from sympy.unify.rewrite import rewriterule + >>> from sympy import default_sort_key + >>> rl = rewriterule(x + y, x**y, [x, y]) + >>> sorted(rl(z + 3), key=default_sort_key) + [3**z, z**3] + + Use ``condition`` to specify additional requirements. Inputs are taken in + the same order as is found in variables. + + >>> rl = rewriterule(x + y, x**y, [x, y], lambda x, y: x.is_integer) + >>> list(rl(z + 3)) + [3**z] + + Use ``assume`` to specify additional requirements using new assumptions. + + >>> from sympy.assumptions import Q + >>> rl = rewriterule(x + y, x**y, [x, y], assume=Q.integer(x)) + >>> list(rl(z + 3)) + [3**z] + + Assumptions for the local context are provided at rule runtime + + >>> list(rl(w + z, Q.integer(z))) + [z**w] + """ + + def rewrite_rl(expr, assumptions=True): + for match in unify(source, expr, {}, variables=variables): + if (condition and + not condition(*[match.get(var, var) for var in variables])): + continue + if (assume and not ask(assume.xreplace(match), assumptions)): + continue + expr2 = subs(match)(target) + if isinstance(expr2, Expr): + expr2 = rebuild(expr2) + yield expr2 + return rewrite_rl diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b950b902c299f4beb55f5d5c373e7d7a31093402 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_rewrite.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_rewrite.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc1acd9ed2a192cac04a5b35fc0ff09e446aeb8a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_rewrite.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_sympy.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_sympy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f77288a16d63929e3926306616509594857df9bc Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_sympy.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_unify.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_unify.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed34d69c389c698ad768f34ce8b68d1f6411bbe8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/__pycache__/test_unify.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_rewrite.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_rewrite.py new file mode 100644 index 0000000000000000000000000000000000000000..7b73e2856d5f6380c576220fa2780324df98091a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_rewrite.py @@ -0,0 +1,74 @@ +from sympy.unify.rewrite import rewriterule +from sympy.core.basic import Basic +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.trigonometric import sin +from sympy.abc import x, y +from sympy.strategies.rl import rebuild +from sympy.assumptions import Q + +p, q = Symbol('p'), Symbol('q') + +def test_simple(): + rl = rewriterule(Basic(p, S(1)), Basic(p, S(2)), variables=(p,)) + assert list(rl(Basic(S(3), S(1)))) == [Basic(S(3), S(2))] + + p1 = p**2 + p2 = p**3 + rl = rewriterule(p1, p2, variables=(p,)) + + expr = x**2 + assert list(rl(expr)) == [x**3] + +def test_simple_variables(): + rl = rewriterule(Basic(x, S(1)), Basic(x, S(2)), variables=(x,)) + assert list(rl(Basic(S(3), S(1)))) == [Basic(S(3), S(2))] + + rl = rewriterule(x**2, x**3, variables=(x,)) + assert list(rl(y**2)) == [y**3] + +def test_moderate(): + p1 = p**2 + q**3 + p2 = (p*q)**4 + rl = rewriterule(p1, p2, (p, q)) + + expr = x**2 + y**3 + assert list(rl(expr)) == [(x*y)**4] + +def test_sincos(): + p1 = sin(p)**2 + sin(p)**2 + p2 = 1 + rl = rewriterule(p1, p2, (p, q)) + + assert list(rl(sin(x)**2 + sin(x)**2)) == [1] + assert list(rl(sin(y)**2 + sin(y)**2)) == [1] + +def test_Exprs_ok(): + rl = rewriterule(p+q, q+p, (p, q)) + next(rl(x+y)).is_commutative + str(next(rl(x+y))) + +def test_condition_simple(): + rl = rewriterule(x, x+1, [x], lambda x: x < 10) + assert not list(rl(S(15))) + assert rebuild(next(rl(S(5)))) == 6 + + +def test_condition_multiple(): + rl = rewriterule(x + y, x**y, [x,y], lambda x, y: x.is_integer) + + a = Symbol('a') + b = Symbol('b', integer=True) + expr = a + b + assert list(rl(expr)) == [b**a] + + c = Symbol('c', integer=True) + d = Symbol('d', integer=True) + assert set(rl(c + d)) == {c**d, d**c} + +def test_assumptions(): + rl = rewriterule(x + y, x**y, [x, y], assume=Q.integer(x)) + + a, b = map(Symbol, 'ab') + expr = a + b + assert list(rl(expr, Q.integer(b))) == [b**a] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_sympy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_sympy.py new file mode 100644 index 0000000000000000000000000000000000000000..eca3933a91abfabdbad96f626e4da761a41b3fd2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_sympy.py @@ -0,0 +1,162 @@ +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.logic.boolalg import And +from sympy.core.symbol import Str +from sympy.unify.core import Compound, Variable +from sympy.unify.usympy import (deconstruct, construct, unify, is_associative, + is_commutative) +from sympy.abc import x, y, z, n + +def test_deconstruct(): + expr = Basic(S(1), S(2), S(3)) + expected = Compound(Basic, (1, 2, 3)) + assert deconstruct(expr) == expected + + assert deconstruct(1) == 1 + assert deconstruct(x) == x + assert deconstruct(x, variables=(x,)) == Variable(x) + assert deconstruct(Add(1, x, evaluate=False)) == Compound(Add, (1, x)) + assert deconstruct(Add(1, x, evaluate=False), variables=(x,)) == \ + Compound(Add, (1, Variable(x))) + +def test_construct(): + expr = Compound(Basic, (S(1), S(2), S(3))) + expected = Basic(S(1), S(2), S(3)) + assert construct(expr) == expected + +def test_nested(): + expr = Basic(S(1), Basic(S(2)), S(3)) + cmpd = Compound(Basic, (S(1), Compound(Basic, Tuple(2)), S(3))) + assert deconstruct(expr) == cmpd + assert construct(cmpd) == expr + +def test_unify(): + expr = Basic(S(1), S(2), S(3)) + a, b, c = map(Symbol, 'abc') + pattern = Basic(a, b, c) + assert list(unify(expr, pattern, {}, (a, b, c))) == [{a: 1, b: 2, c: 3}] + assert list(unify(expr, pattern, variables=(a, b, c))) == \ + [{a: 1, b: 2, c: 3}] + +def test_unify_variables(): + assert list(unify(Basic(S(1), S(2)), Basic(S(1), x), {}, variables=(x,))) == [{x: 2}] + +def test_s_input(): + expr = Basic(S(1), S(2)) + a, b = map(Symbol, 'ab') + pattern = Basic(a, b) + assert list(unify(expr, pattern, {}, (a, b))) == [{a: 1, b: 2}] + assert list(unify(expr, pattern, {a: 5}, (a, b))) == [] + +def iterdicteq(a, b): + a = tuple(a) + b = tuple(b) + return len(a) == len(b) and all(x in b for x in a) + +def test_unify_commutative(): + expr = Add(1, 2, 3, evaluate=False) + a, b, c = map(Symbol, 'abc') + pattern = Add(a, b, c, evaluate=False) + + result = tuple(unify(expr, pattern, {}, (a, b, c))) + expected = ({a: 1, b: 2, c: 3}, + {a: 1, b: 3, c: 2}, + {a: 2, b: 1, c: 3}, + {a: 2, b: 3, c: 1}, + {a: 3, b: 1, c: 2}, + {a: 3, b: 2, c: 1}) + + assert iterdicteq(result, expected) + +def test_unify_iter(): + expr = Add(1, 2, 3, evaluate=False) + a, b, c = map(Symbol, 'abc') + pattern = Add(a, c, evaluate=False) + assert is_associative(deconstruct(pattern)) + assert is_commutative(deconstruct(pattern)) + + result = list(unify(expr, pattern, {}, (a, c))) + expected = [{a: 1, c: Add(2, 3, evaluate=False)}, + {a: 1, c: Add(3, 2, evaluate=False)}, + {a: 2, c: Add(1, 3, evaluate=False)}, + {a: 2, c: Add(3, 1, evaluate=False)}, + {a: 3, c: Add(1, 2, evaluate=False)}, + {a: 3, c: Add(2, 1, evaluate=False)}, + {a: Add(1, 2, evaluate=False), c: 3}, + {a: Add(2, 1, evaluate=False), c: 3}, + {a: Add(1, 3, evaluate=False), c: 2}, + {a: Add(3, 1, evaluate=False), c: 2}, + {a: Add(2, 3, evaluate=False), c: 1}, + {a: Add(3, 2, evaluate=False), c: 1}] + + assert iterdicteq(result, expected) + +def test_hard_match(): + from sympy.functions.elementary.trigonometric import (cos, sin) + expr = sin(x) + cos(x)**2 + p, q = map(Symbol, 'pq') + pattern = sin(p) + cos(p)**2 + assert list(unify(expr, pattern, {}, (p, q))) == [{p: x}] + +def test_matrix(): + from sympy.matrices.expressions.matexpr import MatrixSymbol + X = MatrixSymbol('X', n, n) + Y = MatrixSymbol('Y', 2, 2) + Z = MatrixSymbol('Z', 2, 3) + assert list(unify(X, Y, {}, variables=[n, Str('X')])) == [{Str('X'): Str('Y'), n: 2}] + assert list(unify(X, Z, {}, variables=[n, Str('X')])) == [] + +def test_non_frankenAdds(): + # the is_commutative property used to fail because of Basic.__new__ + # This caused is_commutative and str calls to fail + expr = x+y*2 + rebuilt = construct(deconstruct(expr)) + # Ensure that we can run these commands without causing an error + str(rebuilt) + rebuilt.is_commutative + +def test_FiniteSet_commutivity(): + from sympy.sets.sets import FiniteSet + a, b, c, x, y = symbols('a,b,c,x,y') + s = FiniteSet(a, b, c) + t = FiniteSet(x, y) + variables = (x, y) + assert {x: FiniteSet(a, c), y: b} in tuple(unify(s, t, variables=variables)) + +def test_FiniteSet_complex(): + from sympy.sets.sets import FiniteSet + a, b, c, x, y, z = symbols('a,b,c,x,y,z') + expr = FiniteSet(Basic(S(1), x), y, Basic(x, z)) + pattern = FiniteSet(a, Basic(x, b)) + variables = a, b + expected = ({b: 1, a: FiniteSet(y, Basic(x, z))}, + {b: z, a: FiniteSet(y, Basic(S(1), x))}) + assert iterdicteq(unify(expr, pattern, variables=variables), expected) + + +def test_and(): + variables = x, y + expected = ({x: z > 0, y: n < 3},) + assert iterdicteq(unify((z>0) & (n<3), And(x, y), variables=variables), + expected) + +def test_Union(): + from sympy.sets.sets import Interval + assert list(unify(Interval(0, 1) + Interval(10, 11), + Interval(0, 1) + Interval(12, 13), + variables=(Interval(12, 13),))) + +def test_is_commutative(): + assert is_commutative(deconstruct(x+y)) + assert is_commutative(deconstruct(x*y)) + assert not is_commutative(deconstruct(x**y)) + +def test_commutative_in_commutative(): + from sympy.abc import a,b,c,d + from sympy.functions.elementary.trigonometric import (cos, sin) + eq = sin(3)*sin(4)*sin(5) + 4*cos(3)*cos(4) + pat = a*cos(b)*cos(c) + d*sin(b)*sin(c) + assert next(unify(eq, pat, variables=(a,b,c,d))) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_unify.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_unify.py new file mode 100644 index 0000000000000000000000000000000000000000..31153242576e1ff55dd3097efbc985aced5d574a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/tests/test_unify.py @@ -0,0 +1,88 @@ +from sympy.unify.core import Compound, Variable, CondVariable, allcombinations +from sympy.unify import core + +a,b,c = 'a', 'b', 'c' +w,x,y,z = map(Variable, 'wxyz') + +C = Compound + +def is_associative(x): + return isinstance(x, Compound) and (x.op in ('Add', 'Mul', 'CAdd', 'CMul')) +def is_commutative(x): + return isinstance(x, Compound) and (x.op in ('CAdd', 'CMul')) + + +def unify(a, b, s={}): + return core.unify(a, b, s=s, is_associative=is_associative, + is_commutative=is_commutative) + +def test_basic(): + assert list(unify(a, x, {})) == [{x: a}] + assert list(unify(a, x, {x: 10})) == [] + assert list(unify(1, x, {})) == [{x: 1}] + assert list(unify(a, a, {})) == [{}] + assert list(unify((w, x), (y, z), {})) == [{w: y, x: z}] + assert list(unify(x, (a, b), {})) == [{x: (a, b)}] + + assert list(unify((a, b), (x, x), {})) == [] + assert list(unify((y, z), (x, x), {}))!= [] + assert list(unify((a, (b, c)), (a, (x, y)), {})) == [{x: b, y: c}] + +def test_ops(): + assert list(unify(C('Add', (a,b,c)), C('Add', (a,x,y)), {})) == \ + [{x:b, y:c}] + assert list(unify(C('Add', (C('Mul', (1,2)), b,c)), C('Add', (x,y,c)), {})) == \ + [{x: C('Mul', (1,2)), y:b}] + +def test_associative(): + c1 = C('Add', (1,2,3)) + c2 = C('Add', (x,y)) + assert tuple(unify(c1, c2, {})) == ({x: 1, y: C('Add', (2, 3))}, + {x: C('Add', (1, 2)), y: 3}) + +def test_commutative(): + c1 = C('CAdd', (1,2,3)) + c2 = C('CAdd', (x,y)) + result = list(unify(c1, c2, {})) + assert {x: 1, y: C('CAdd', (2, 3))} in result + assert ({x: 2, y: C('CAdd', (1, 3))} in result or + {x: 2, y: C('CAdd', (3, 1))} in result) + +def _test_combinations_assoc(): + assert set(allcombinations((1,2,3), (a,b), True)) == \ + {(((1, 2), (3,)), (a, b)), (((1,), (2, 3)), (a, b))} + +def _test_combinations_comm(): + assert set(allcombinations((1,2,3), (a,b), None)) == \ + {(((1,), (2, 3)), ('a', 'b')), (((2,), (3, 1)), ('a', 'b')), + (((3,), (1, 2)), ('a', 'b')), (((1, 2), (3,)), ('a', 'b')), + (((2, 3), (1,)), ('a', 'b')), (((3, 1), (2,)), ('a', 'b'))} + +def test_allcombinations(): + assert set(allcombinations((1,2), (1,2), 'commutative')) ==\ + {(((1,),(2,)), ((1,),(2,))), (((1,),(2,)), ((2,),(1,)))} + + +def test_commutativity(): + c1 = Compound('CAdd', (a, b)) + c2 = Compound('CAdd', (x, y)) + assert is_commutative(c1) and is_commutative(c2) + assert len(list(unify(c1, c2, {}))) == 2 + + +def test_CondVariable(): + expr = C('CAdd', (1, 2)) + x = Variable('x') + y = CondVariable('y', lambda a: a % 2 == 0) + z = CondVariable('z', lambda a: a > 3) + pattern = C('CAdd', (x, y)) + assert list(unify(expr, pattern, {})) == \ + [{x: 1, y: 2}] + + z = CondVariable('z', lambda a: a > 3) + pattern = C('CAdd', (z, y)) + + assert list(unify(expr, pattern, {})) == [] + +def test_defaultdict(): + assert next(unify(Variable('x'), 'foo')) == {Variable('x'): 'foo'} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/usympy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/usympy.py new file mode 100644 index 0000000000000000000000000000000000000000..3942b35ec549e5dbd08a3cf1cad2b2ecea733c7a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/unify/usympy.py @@ -0,0 +1,124 @@ +""" SymPy interface to Unification engine + +See sympy.unify for module level docstring +See sympy.unify.core for algorithmic docstring """ + +from sympy.core import Basic, Add, Mul, Pow +from sympy.core.operations import AssocOp, LatticeOp +from sympy.matrices import MatAdd, MatMul, MatrixExpr +from sympy.sets.sets import Union, Intersection, FiniteSet +from sympy.unify.core import Compound, Variable, CondVariable +from sympy.unify import core + +basic_new_legal = [MatrixExpr] +eval_false_legal = [AssocOp, Pow, FiniteSet] +illegal = [LatticeOp] + +def sympy_associative(op): + assoc_ops = (AssocOp, MatAdd, MatMul, Union, Intersection, FiniteSet) + return any(issubclass(op, aop) for aop in assoc_ops) + +def sympy_commutative(op): + comm_ops = (Add, MatAdd, Union, Intersection, FiniteSet) + return any(issubclass(op, cop) for cop in comm_ops) + +def is_associative(x): + return isinstance(x, Compound) and sympy_associative(x.op) + +def is_commutative(x): + if not isinstance(x, Compound): + return False + if sympy_commutative(x.op): + return True + if issubclass(x.op, Mul): + return all(construct(arg).is_commutative for arg in x.args) + +def mk_matchtype(typ): + def matchtype(x): + return (isinstance(x, typ) or + isinstance(x, Compound) and issubclass(x.op, typ)) + return matchtype + +def deconstruct(s, variables=()): + """ Turn a SymPy object into a Compound """ + if s in variables: + return Variable(s) + if isinstance(s, (Variable, CondVariable)): + return s + if not isinstance(s, Basic) or s.is_Atom: + return s + return Compound(s.__class__, + tuple(deconstruct(arg, variables) for arg in s.args)) + +def construct(t): + """ Turn a Compound into a SymPy object """ + if isinstance(t, (Variable, CondVariable)): + return t.arg + if not isinstance(t, Compound): + return t + if any(issubclass(t.op, cls) for cls in eval_false_legal): + return t.op(*map(construct, t.args), evaluate=False) + elif any(issubclass(t.op, cls) for cls in basic_new_legal): + return Basic.__new__(t.op, *map(construct, t.args)) + else: + return t.op(*map(construct, t.args)) + +def rebuild(s): + """ Rebuild a SymPy expression. + + This removes harm caused by Expr-Rules interactions. + """ + return construct(deconstruct(s)) + +def unify(x, y, s=None, variables=(), **kwargs): + """ Structural unification of two expressions/patterns. + + Examples + ======== + + >>> from sympy.unify.usympy import unify + >>> from sympy import Basic, S + >>> from sympy.abc import x, y, z, p, q + + >>> next(unify(Basic(S(1), S(2)), Basic(S(1), x), variables=[x])) + {x: 2} + + >>> expr = 2*x + y + z + >>> pattern = 2*p + q + >>> next(unify(expr, pattern, {}, variables=(p, q))) + {p: x, q: y + z} + + Unification supports commutative and associative matching + + >>> expr = x + y + z + >>> pattern = p + q + >>> len(list(unify(expr, pattern, {}, variables=(p, q)))) + 12 + + Symbols not indicated to be variables are treated as literal, + else they are wild-like and match anything in a sub-expression. + + >>> expr = x*y*z + 3 + >>> pattern = x*y + 3 + >>> next(unify(expr, pattern, {}, variables=[x, y])) + {x: y, y: x*z} + + The x and y of the pattern above were in a Mul and matched factors + in the Mul of expr. Here, a single symbol matches an entire term: + + >>> expr = x*y + 3 + >>> pattern = p + 3 + >>> next(unify(expr, pattern, {}, variables=[p])) + {p: x*y} + + """ + decons = lambda x: deconstruct(x, variables) + s = s or {} + s = {decons(k): decons(v) for k, v in s.items()} + + ds = core.unify(decons(x), decons(y), s, + is_associative=is_associative, + is_commutative=is_commutative, + **kwargs) + for d in ds: + yield {construct(k): construct(v) for k, v in d.items()} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8f35da4a84396618a33a12c3c6b5cf58e9d4742c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/__init__.py @@ -0,0 +1,30 @@ +"""This module contains some general purpose utilities that are used across +SymPy. +""" +from .iterables import (flatten, group, take, subsets, + variations, numbered_symbols, cartes, capture, dict_merge, + prefixes, postfixes, sift, topological_sort, unflatten, + has_dups, has_variety, reshape, rotations) + +from .misc import filldedent + +from .lambdify import lambdify + +from .decorator import threaded, xthreaded, public, memoize_property + +from .timeutils import timed + +__all__ = [ + 'flatten', 'group', 'take', 'subsets', 'variations', 'numbered_symbols', + 'cartes', 'capture', 'dict_merge', 'prefixes', 'postfixes', 'sift', + 'topological_sort', 'unflatten', 'has_dups', 'has_variety', 'reshape', + 'rotations', + + 'filldedent', + + 'lambdify', + + 'threaded', 'xthreaded', 'public', 'memoize_property', + + 'timed', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/autowrap.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/autowrap.py new file mode 100644 index 0000000000000000000000000000000000000000..b6c33b2f0f72f89b5680f910929618a821e924c3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/autowrap.py @@ -0,0 +1,1178 @@ +"""Module for compiling codegen output, and wrap the binary for use in +python. + +.. note:: To use the autowrap module it must first be imported + + >>> from sympy.utilities.autowrap import autowrap + +This module provides a common interface for different external backends, such +as f2py, fwrap, Cython, SWIG(?) etc. (Currently only f2py and Cython are +implemented) The goal is to provide access to compiled binaries of acceptable +performance with a one-button user interface, e.g., + + >>> from sympy.abc import x,y + >>> expr = (x - y)**25 + >>> flat = expr.expand() + >>> binary_callable = autowrap(flat) + >>> binary_callable(2, 3) + -1.0 + +Although a SymPy user might primarily be interested in working with +mathematical expressions and not in the details of wrapping tools +needed to evaluate such expressions efficiently in numerical form, +the user cannot do so without some understanding of the +limits in the target language. For example, the expanded expression +contains large coefficients which result in loss of precision when +computing the expression: + + >>> binary_callable(3, 2) + 0.0 + >>> binary_callable(4, 5), binary_callable(5, 4) + (-22925376.0, 25165824.0) + +Wrapping the unexpanded expression gives the expected behavior: + + >>> e = autowrap(expr) + >>> e(4, 5), e(5, 4) + (-1.0, 1.0) + +The callable returned from autowrap() is a binary Python function, not a +SymPy object. If it is desired to use the compiled function in symbolic +expressions, it is better to use binary_function() which returns a SymPy +Function object. The binary callable is attached as the _imp_ attribute and +invoked when a numerical evaluation is requested with evalf(), or with +lambdify(). + + >>> from sympy.utilities.autowrap import binary_function + >>> f = binary_function('f', expr) + >>> 2*f(x, y) + y + y + 2*f(x, y) + >>> (2*f(x, y) + y).evalf(2, subs={x: 1, y:2}) + 0.e-110 + +When is this useful? + + 1) For computations on large arrays, Python iterations may be too slow, + and depending on the mathematical expression, it may be difficult to + exploit the advanced index operations provided by NumPy. + + 2) For *really* long expressions that will be called repeatedly, the + compiled binary should be significantly faster than SymPy's .evalf() + + 3) If you are generating code with the codegen utility in order to use + it in another project, the automatic Python wrappers let you test the + binaries immediately from within SymPy. + + 4) To create customized ufuncs for use with numpy arrays. + See *ufuncify*. + +When is this module NOT the best approach? + + 1) If you are really concerned about speed or memory optimizations, + you will probably get better results by working directly with the + wrapper tools and the low level code. However, the files generated + by this utility may provide a useful starting point and reference + code. Temporary files will be left intact if you supply the keyword + tempdir="path/to/files/". + + 2) If the array computation can be handled easily by numpy, and you + do not need the binaries for another project. + +""" + +import sys +import os +import shutil +import tempfile +from pathlib import Path +from subprocess import STDOUT, CalledProcessError, check_output +from string import Template +from warnings import warn + +from sympy.core.cache import cacheit +from sympy.core.function import Lambda +from sympy.core.relational import Eq +from sympy.core.symbol import Dummy, Symbol +from sympy.tensor.indexed import Idx, IndexedBase +from sympy.utilities.codegen import (make_routine, get_code_generator, + OutputArgument, InOutArgument, + InputArgument, CodeGenArgumentListError, + Result, ResultBase, C99CodeGen) +from sympy.utilities.iterables import iterable +from sympy.utilities.lambdify import implemented_function +from sympy.utilities.decorator import doctest_depends_on + +_doctest_depends_on = {'exe': ('f2py', 'gfortran', 'gcc'), + 'modules': ('numpy',)} + + +class CodeWrapError(Exception): + pass + + +class CodeWrapper: + """Base Class for code wrappers""" + _filename = "wrapped_code" + _module_basename = "wrapper_module" + _module_counter = 0 + + @property + def filename(self): + return "%s_%s" % (self._filename, CodeWrapper._module_counter) + + @property + def module_name(self): + return "%s_%s" % (self._module_basename, CodeWrapper._module_counter) + + def __init__(self, generator, filepath=None, flags=[], verbose=False): + """ + generator -- the code generator to use + """ + self.generator = generator + self.filepath = filepath + self.flags = flags + self.quiet = not verbose + + @property + def include_header(self): + return bool(self.filepath) + + @property + def include_empty(self): + return bool(self.filepath) + + def _generate_code(self, main_routine, routines): + routines.append(main_routine) + self.generator.write( + routines, self.filename, True, self.include_header, + self.include_empty) + + def wrap_code(self, routine, helpers=None): + helpers = helpers or [] + if self.filepath: + workdir = os.path.abspath(self.filepath) + else: + workdir = tempfile.mkdtemp("_sympy_compile") + if not os.access(workdir, os.F_OK): + os.mkdir(workdir) + oldwork = os.getcwd() + os.chdir(workdir) + try: + sys.path.append(workdir) + self._generate_code(routine, helpers) + self._prepare_files(routine) + self._process_files(routine) + mod = __import__(self.module_name) + finally: + sys.path.remove(workdir) + CodeWrapper._module_counter += 1 + os.chdir(oldwork) + if not self.filepath: + try: + shutil.rmtree(workdir) + except OSError: + # Could be some issues on Windows + pass + + return self._get_wrapped_function(mod, routine.name) + + def _process_files(self, routine): + command = self.command + command.extend(self.flags) + try: + retoutput = check_output(command, stderr=STDOUT) + except CalledProcessError as e: + raise CodeWrapError( + "Error while executing command: %s. Command output is:\n%s" % ( + " ".join(command), e.output.decode('utf-8'))) + if not self.quiet: + print(retoutput) + + +class DummyWrapper(CodeWrapper): + """Class used for testing independent of backends """ + + template = """# dummy module for testing of SymPy +def %(name)s(): + return "%(expr)s" +%(name)s.args = "%(args)s" +%(name)s.returns = "%(retvals)s" +""" + + def _prepare_files(self, routine): + return + + def _generate_code(self, routine, helpers): + with open('%s.py' % self.module_name, 'w') as f: + printed = ", ".join( + [str(res.expr) for res in routine.result_variables]) + # convert OutputArguments to return value like f2py + args = filter(lambda x: not isinstance( + x, OutputArgument), routine.arguments) + retvals = [] + for val in routine.result_variables: + if isinstance(val, Result): + retvals.append('nameless') + else: + retvals.append(val.result_var) + + print(DummyWrapper.template % { + 'name': routine.name, + 'expr': printed, + 'args': ", ".join([str(a.name) for a in args]), + 'retvals': ", ".join([str(val) for val in retvals]) + }, end="", file=f) + + def _process_files(self, routine): + return + + @classmethod + def _get_wrapped_function(cls, mod, name): + return getattr(mod, name) + + +class CythonCodeWrapper(CodeWrapper): + """Wrapper that uses Cython""" + + setup_template = """\ +from setuptools import setup +from setuptools import Extension +from Cython.Build import cythonize +cy_opts = {cythonize_options} +{np_import} +ext_mods = [Extension( + {ext_args}, + include_dirs={include_dirs}, + library_dirs={library_dirs}, + libraries={libraries}, + extra_compile_args={extra_compile_args}, + extra_link_args={extra_link_args} +)] +setup(ext_modules=cythonize(ext_mods, **cy_opts)) +""" + + _cythonize_options = {'compiler_directives':{'language_level' : "3"}} + + pyx_imports = ( + "import numpy as np\n" + "cimport numpy as np\n\n") + + pyx_header = ( + "cdef extern from '{header_file}.h':\n" + " {prototype}\n\n") + + pyx_func = ( + "def {name}_c({arg_string}):\n" + "\n" + "{declarations}" + "{body}") + + std_compile_flag = '-std=c99' + + def __init__(self, *args, **kwargs): + """Instantiates a Cython code wrapper. + + The following optional parameters get passed to ``setuptools.Extension`` + for building the Python extension module. Read its documentation to + learn more. + + Parameters + ========== + include_dirs : [list of strings] + A list of directories to search for C/C++ header files (in Unix + form for portability). + library_dirs : [list of strings] + A list of directories to search for C/C++ libraries at link time. + libraries : [list of strings] + A list of library names (not filenames or paths) to link against. + extra_compile_args : [list of strings] + Any extra platform- and compiler-specific information to use when + compiling the source files in 'sources'. For platforms and + compilers where "command line" makes sense, this is typically a + list of command-line arguments, but for other platforms it could be + anything. Note that the attribute ``std_compile_flag`` will be + appended to this list. + extra_link_args : [list of strings] + Any extra platform- and compiler-specific information to use when + linking object files together to create the extension (or to create + a new static Python interpreter). Similar interpretation as for + 'extra_compile_args'. + cythonize_options : [dictionary] + Keyword arguments passed on to cythonize. + + """ + + self._include_dirs = kwargs.pop('include_dirs', []) + self._library_dirs = kwargs.pop('library_dirs', []) + self._libraries = kwargs.pop('libraries', []) + self._extra_compile_args = kwargs.pop('extra_compile_args', []) + self._extra_compile_args.append(self.std_compile_flag) + self._extra_link_args = kwargs.pop('extra_link_args', []) + self._cythonize_options = kwargs.pop('cythonize_options', self._cythonize_options) + + self._need_numpy = False + + super().__init__(*args, **kwargs) + + @property + def command(self): + command = [sys.executable, "setup.py", "build_ext", "--inplace"] + return command + + def _prepare_files(self, routine, build_dir=os.curdir): + # NOTE : build_dir is used for testing purposes. + pyxfilename = self.module_name + '.pyx' + codefilename = "%s.%s" % (self.filename, self.generator.code_extension) + + # pyx + with open(os.path.join(build_dir, pyxfilename), 'w') as f: + self.dump_pyx([routine], f, self.filename) + + # setup.py + ext_args = [repr(self.module_name), repr([pyxfilename, codefilename])] + if self._need_numpy: + np_import = 'import numpy as np\n' + self._include_dirs.append('np.get_include()') + else: + np_import = '' + + includes = str(self._include_dirs).replace("'np.get_include()'", + 'np.get_include()') + code = self.setup_template.format( + ext_args=", ".join(ext_args), + np_import=np_import, + include_dirs=includes, + library_dirs=self._library_dirs, + libraries=self._libraries, + extra_compile_args=self._extra_compile_args, + extra_link_args=self._extra_link_args, + cythonize_options=self._cythonize_options) + Path(os.path.join(build_dir, 'setup.py')).write_text(code) + + @classmethod + def _get_wrapped_function(cls, mod, name): + return getattr(mod, name + '_c') + + def dump_pyx(self, routines, f, prefix): + """Write a Cython file with Python wrappers + + This file contains all the definitions of the routines in c code and + refers to the header file. + + Arguments + --------- + routines + List of Routine instances + f + File-like object to write the file to + prefix + The filename prefix, used to refer to the proper header file. + Only the basename of the prefix is used. + """ + headers = [] + functions = [] + for routine in routines: + prototype = self.generator.get_prototype(routine) + + # C Function Header Import + headers.append(self.pyx_header.format(header_file=prefix, + prototype=prototype)) + + # Partition the C function arguments into categories + py_rets, py_args, py_loc, py_inf = self._partition_args(routine.arguments) + + # Function prototype + name = routine.name + arg_string = ", ".join(self._prototype_arg(arg) for arg in py_args) + + # Local Declarations + local_decs = [] + for arg, val in py_inf.items(): + proto = self._prototype_arg(arg) + mat, ind = [self._string_var(v) for v in val] + local_decs.append(" cdef {} = {}.shape[{}]".format(proto, mat, ind)) + local_decs.extend([" cdef {}".format(self._declare_arg(a)) for a in py_loc]) + declarations = "\n".join(local_decs) + if declarations: + declarations = declarations + "\n" + + # Function Body + args_c = ", ".join([self._call_arg(a) for a in routine.arguments]) + rets = ", ".join([self._string_var(r.name) for r in py_rets]) + if routine.results: + body = ' return %s(%s)' % (routine.name, args_c) + if rets: + body = body + ', ' + rets + else: + body = ' %s(%s)\n' % (routine.name, args_c) + body = body + ' return ' + rets + + functions.append(self.pyx_func.format(name=name, arg_string=arg_string, + declarations=declarations, body=body)) + + # Write text to file + if self._need_numpy: + # Only import numpy if required + f.write(self.pyx_imports) + f.write('\n'.join(headers)) + f.write('\n'.join(functions)) + + def _partition_args(self, args): + """Group function arguments into categories.""" + py_args = [] + py_returns = [] + py_locals = [] + py_inferred = {} + for arg in args: + if isinstance(arg, OutputArgument): + py_returns.append(arg) + py_locals.append(arg) + elif isinstance(arg, InOutArgument): + py_returns.append(arg) + py_args.append(arg) + else: + py_args.append(arg) + # Find arguments that are array dimensions. These can be inferred + # locally in the Cython code. + if isinstance(arg, (InputArgument, InOutArgument)) and arg.dimensions: + dims = [d[1] + 1 for d in arg.dimensions] + sym_dims = [(i, d) for (i, d) in enumerate(dims) if + isinstance(d, Symbol)] + for (i, d) in sym_dims: + py_inferred[d] = (arg.name, i) + for arg in args: + if arg.name in py_inferred: + py_inferred[arg] = py_inferred.pop(arg.name) + # Filter inferred arguments from py_args + py_args = [a for a in py_args if a not in py_inferred] + return py_returns, py_args, py_locals, py_inferred + + def _prototype_arg(self, arg): + mat_dec = "np.ndarray[{mtype}, ndim={ndim}] {name}" + np_types = {'double': 'np.double_t', + 'int': 'np.int_t'} + t = arg.get_datatype('c') + if arg.dimensions: + self._need_numpy = True + ndim = len(arg.dimensions) + mtype = np_types[t] + return mat_dec.format(mtype=mtype, ndim=ndim, name=self._string_var(arg.name)) + else: + return "%s %s" % (t, self._string_var(arg.name)) + + def _declare_arg(self, arg): + proto = self._prototype_arg(arg) + if arg.dimensions: + shape = '(' + ','.join(self._string_var(i[1] + 1) for i in arg.dimensions) + ')' + return proto + " = np.empty({shape})".format(shape=shape) + else: + return proto + " = 0" + + def _call_arg(self, arg): + if arg.dimensions: + t = arg.get_datatype('c') + return "<{}*> {}.data".format(t, self._string_var(arg.name)) + elif isinstance(arg, ResultBase): + return "&{}".format(self._string_var(arg.name)) + else: + return self._string_var(arg.name) + + def _string_var(self, var): + printer = self.generator.printer.doprint + return printer(var) + + +class F2PyCodeWrapper(CodeWrapper): + """Wrapper that uses f2py""" + + def __init__(self, *args, **kwargs): + + ext_keys = ['include_dirs', 'library_dirs', 'libraries', + 'extra_compile_args', 'extra_link_args'] + msg = ('The compilation option kwarg {} is not supported with the f2py ' + 'backend.') + + for k in ext_keys: + if k in kwargs.keys(): + warn(msg.format(k)) + kwargs.pop(k, None) + + super().__init__(*args, **kwargs) + + @property + def command(self): + filename = self.filename + '.' + self.generator.code_extension + args = ['-c', '-m', self.module_name, filename] + command = [sys.executable, "-c", "import numpy.f2py as f2py2e;f2py2e.main()"]+args + return command + + def _prepare_files(self, routine): + pass + + @classmethod + def _get_wrapped_function(cls, mod, name): + return getattr(mod, name) + + +# Here we define a lookup of backends -> tuples of languages. For now, each +# tuple is of length 1, but if a backend supports more than one language, +# the most preferable language is listed first. +_lang_lookup = {'CYTHON': ('C99', 'C89', 'C'), + 'F2PY': ('F95',), + 'NUMPY': ('C99', 'C89', 'C'), + 'DUMMY': ('F95',)} # Dummy here just for testing + + +def _infer_language(backend): + """For a given backend, return the top choice of language""" + langs = _lang_lookup.get(backend.upper(), False) + if not langs: + raise ValueError("Unrecognized backend: " + backend) + return langs[0] + + +def _validate_backend_language(backend, language): + """Throws error if backend and language are incompatible""" + langs = _lang_lookup.get(backend.upper(), False) + if not langs: + raise ValueError("Unrecognized backend: " + backend) + if language.upper() not in langs: + raise ValueError(("Backend {} and language {} are " + "incompatible").format(backend, language)) + + +@cacheit +@doctest_depends_on(exe=('f2py', 'gfortran'), modules=('numpy',)) +def autowrap(expr, language=None, backend='f2py', tempdir=None, args=None, + flags=None, verbose=False, helpers=None, code_gen=None, **kwargs): + """Generates Python callable binaries based on the math expression. + + Parameters + ========== + + expr + The SymPy expression that should be wrapped as a binary routine. + language : string, optional + If supplied, (options: 'C' or 'F95'), specifies the language of the + generated code. If ``None`` [default], the language is inferred based + upon the specified backend. + backend : string, optional + Backend used to wrap the generated code. Either 'f2py' [default], + or 'cython'. + tempdir : string, optional + Path to directory for temporary files. If this argument is supplied, + the generated code and the wrapper input files are left intact in the + specified path. + args : iterable, optional + An ordered iterable of symbols. Specifies the argument sequence for the + function. + flags : iterable, optional + Additional option flags that will be passed to the backend. + verbose : bool, optional + If True, autowrap will not mute the command line backends. This can be + helpful for debugging. + helpers : 3-tuple or iterable of 3-tuples, optional + Used to define auxiliary functions needed for the main expression. + Each tuple should be of the form (name, expr, args) where: + + - name : str, the function name + - expr : sympy expression, the function + - args : iterable, the function arguments (can be any iterable of symbols) + + code_gen : CodeGen instance + An instance of a CodeGen subclass. Overrides ``language``. + include_dirs : [string] + A list of directories to search for C/C++ header files (in Unix form + for portability). + library_dirs : [string] + A list of directories to search for C/C++ libraries at link time. + libraries : [string] + A list of library names (not filenames or paths) to link against. + extra_compile_args : [string] + Any extra platform- and compiler-specific information to use when + compiling the source files in 'sources'. For platforms and compilers + where "command line" makes sense, this is typically a list of + command-line arguments, but for other platforms it could be anything. + extra_link_args : [string] + Any extra platform- and compiler-specific information to use when + linking object files together to create the extension (or to create a + new static Python interpreter). Similar interpretation as for + 'extra_compile_args'. + + Examples + ======== + + Basic usage: + + >>> from sympy.abc import x, y, z + >>> from sympy.utilities.autowrap import autowrap + >>> expr = ((x - y + z)**(13)).expand() + >>> binary_func = autowrap(expr) + >>> binary_func(1, 4, 2) + -1.0 + + Using helper functions: + + >>> from sympy.abc import x, t + >>> from sympy import Function + >>> helper_func = Function('helper_func') # Define symbolic function + >>> expr = 3*x + helper_func(t) # Main expression using helper function + >>> # Define helper_func(x) = 4*x using f2py backend + >>> binary_func = autowrap(expr, args=[x, t], + ... helpers=('helper_func', 4*x, [x])) + >>> binary_func(2, 5) # 3*2 + helper_func(5) = 6 + 20 + 26.0 + >>> # Same example using cython backend + >>> binary_func = autowrap(expr, args=[x, t], backend='cython', + ... helpers=[('helper_func', 4*x, [x])]) + >>> binary_func(2, 5) # 3*2 + helper_func(5) = 6 + 20 + 26.0 + + Type handling example: + + >>> import numpy as np + >>> expr = x + y + >>> f_cython = autowrap(expr, backend='cython') + >>> f_cython(1, 2) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: Argument '_x' has incorrect type (expected numpy.ndarray, got int) + >>> f_cython(np.array([1.0]), np.array([2.0])) + array([ 3.]) + + """ + if language: + if not isinstance(language, type): + _validate_backend_language(backend, language) + else: + language = _infer_language(backend) + + # two cases 1) helpers is an iterable of 3-tuples and 2) helpers is a + # 3-tuple + if iterable(helpers) and len(helpers) != 0 and iterable(helpers[0]): + helpers = helpers if helpers else () + else: + helpers = [helpers] if helpers else () + args = list(args) if iterable(args, exclude=set) else args + + if code_gen is None: + code_gen = get_code_generator(language, "autowrap") + + CodeWrapperClass = { + 'F2PY': F2PyCodeWrapper, + 'CYTHON': CythonCodeWrapper, + 'DUMMY': DummyWrapper + }[backend.upper()] + code_wrapper = CodeWrapperClass(code_gen, tempdir, flags if flags else (), + verbose, **kwargs) + + helps = [] + for name_h, expr_h, args_h in helpers: + helps.append(code_gen.routine(name_h, expr_h, args_h)) + + for name_h, expr_h, args_h in helpers: + if expr.has(expr_h): + name_h = binary_function(name_h, expr_h, backend='dummy') + expr = expr.subs(expr_h, name_h(*args_h)) + try: + routine = code_gen.routine('autofunc', expr, args) + except CodeGenArgumentListError as e: + # if all missing arguments are for pure output, we simply attach them + # at the end and try again, because the wrappers will silently convert + # them to return values anyway. + new_args = [] + for missing in e.missing_args: + if not isinstance(missing, OutputArgument): + raise + new_args.append(missing.name) + routine = code_gen.routine('autofunc', expr, args + new_args) + + return code_wrapper.wrap_code(routine, helpers=helps) + + +@doctest_depends_on(exe=('f2py', 'gfortran'), modules=('numpy',)) +def binary_function(symfunc, expr, **kwargs): + """Returns a SymPy function with expr as binary implementation + + This is a convenience function that automates the steps needed to + autowrap the SymPy expression and attaching it to a Function object + with implemented_function(). + + Parameters + ========== + + symfunc : SymPy Function + The function to bind the callable to. + expr : SymPy Expression + The expression used to generate the function. + kwargs : dict + Any kwargs accepted by autowrap. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.utilities.autowrap import binary_function + >>> expr = ((x - y)**(25)).expand() + >>> f = binary_function('f', expr) + >>> type(f) + + >>> 2*f(x, y) + 2*f(x, y) + >>> f(x, y).evalf(2, subs={x: 1, y: 2}) + -1.0 + + """ + binary = autowrap(expr, **kwargs) + return implemented_function(symfunc, binary) + +################################################################# +# UFUNCIFY # +################################################################# + +_ufunc_top = Template("""\ +#include "Python.h" +#include "math.h" +#include "numpy/ndarraytypes.h" +#include "numpy/ufuncobject.h" +#include "numpy/halffloat.h" +#include ${include_file} + +static PyMethodDef ${module}Methods[] = { + {NULL, NULL, 0, NULL} +};""") + +_ufunc_outcalls = Template("*((double *)out${outnum}) = ${funcname}(${call_args});") + +_ufunc_body = Template("""\ +#ifdef NPY_1_19_API_VERSION +static void ${funcname}_ufunc(char **args, const npy_intp *dimensions, const npy_intp* steps, void* data) +#else +static void ${funcname}_ufunc(char **args, npy_intp *dimensions, npy_intp* steps, void* data) +#endif +{ + npy_intp i; + npy_intp n = dimensions[0]; + ${declare_args} + ${declare_steps} + for (i = 0; i < n; i++) { + ${outcalls} + ${step_increments} + } +} +PyUFuncGenericFunction ${funcname}_funcs[1] = {&${funcname}_ufunc}; +static char ${funcname}_types[${n_types}] = ${types} +static void *${funcname}_data[1] = {NULL};""") + +_ufunc_bottom = Template("""\ +#if PY_VERSION_HEX >= 0x03000000 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "${module}", + NULL, + -1, + ${module}Methods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit_${module}(void) +{ + PyObject *m, *d; + ${function_creation} + m = PyModule_Create(&moduledef); + if (!m) { + return NULL; + } + import_array(); + import_umath(); + d = PyModule_GetDict(m); + ${ufunc_init} + return m; +} +#else +PyMODINIT_FUNC init${module}(void) +{ + PyObject *m, *d; + ${function_creation} + m = Py_InitModule("${module}", ${module}Methods); + if (m == NULL) { + return; + } + import_array(); + import_umath(); + d = PyModule_GetDict(m); + ${ufunc_init} +} +#endif\ +""") + +_ufunc_init_form = Template("""\ +ufunc${ind} = PyUFunc_FromFuncAndData(${funcname}_funcs, ${funcname}_data, ${funcname}_types, 1, ${n_in}, ${n_out}, + PyUFunc_None, "${module}", ${docstring}, 0); + PyDict_SetItemString(d, "${funcname}", ufunc${ind}); + Py_DECREF(ufunc${ind});""") + +_ufunc_setup = Template("""\ +from setuptools.extension import Extension +from setuptools import setup + +from numpy import get_include + +if __name__ == "__main__": + setup(ext_modules=[ + Extension('${module}', + sources=['${module}.c', '${filename}.c'], + include_dirs=[get_include()])]) +""") + + +class UfuncifyCodeWrapper(CodeWrapper): + """Wrapper for Ufuncify""" + + def __init__(self, *args, **kwargs): + + ext_keys = ['include_dirs', 'library_dirs', 'libraries', + 'extra_compile_args', 'extra_link_args'] + msg = ('The compilation option kwarg {} is not supported with the numpy' + ' backend.') + + for k in ext_keys: + if k in kwargs.keys(): + warn(msg.format(k)) + kwargs.pop(k, None) + + super().__init__(*args, **kwargs) + + @property + def command(self): + command = [sys.executable, "setup.py", "build_ext", "--inplace"] + return command + + def wrap_code(self, routines, helpers=None): + # This routine overrides CodeWrapper because we can't assume funcname == routines[0].name + # Therefore we have to break the CodeWrapper private API. + # There isn't an obvious way to extend multi-expr support to + # the other autowrap backends, so we limit this change to ufuncify. + helpers = helpers if helpers is not None else [] + # We just need a consistent name + funcname = 'wrapped_' + str(id(routines) + id(helpers)) + + workdir = self.filepath or tempfile.mkdtemp("_sympy_compile") + if not os.access(workdir, os.F_OK): + os.mkdir(workdir) + oldwork = os.getcwd() + os.chdir(workdir) + try: + sys.path.append(workdir) + self._generate_code(routines, helpers) + self._prepare_files(routines, funcname) + self._process_files(routines) + mod = __import__(self.module_name) + finally: + sys.path.remove(workdir) + CodeWrapper._module_counter += 1 + os.chdir(oldwork) + if not self.filepath: + try: + shutil.rmtree(workdir) + except OSError: + # Could be some issues on Windows + pass + + return self._get_wrapped_function(mod, funcname) + + def _generate_code(self, main_routines, helper_routines): + all_routines = main_routines + helper_routines + self.generator.write( + all_routines, self.filename, True, self.include_header, + self.include_empty) + + def _prepare_files(self, routines, funcname): + + # C + codefilename = self.module_name + '.c' + with open(codefilename, 'w') as f: + self.dump_c(routines, f, self.filename, funcname=funcname) + + # setup.py + with open('setup.py', 'w') as f: + self.dump_setup(f) + + @classmethod + def _get_wrapped_function(cls, mod, name): + return getattr(mod, name) + + def dump_setup(self, f): + setup = _ufunc_setup.substitute(module=self.module_name, + filename=self.filename) + f.write(setup) + + def dump_c(self, routines, f, prefix, funcname=None): + """Write a C file with Python wrappers + + This file contains all the definitions of the routines in c code. + + Arguments + --------- + routines + List of Routine instances + f + File-like object to write the file to + prefix + The filename prefix, used to name the imported module. + funcname + Name of the main function to be returned. + """ + if funcname is None: + if len(routines) == 1: + funcname = routines[0].name + else: + msg = 'funcname must be specified for multiple output routines' + raise ValueError(msg) + functions = [] + function_creation = [] + ufunc_init = [] + module = self.module_name + include_file = "\"{}.h\"".format(prefix) + top = _ufunc_top.substitute(include_file=include_file, module=module) + + name = funcname + + # Partition the C function arguments into categories + # Here we assume all routines accept the same arguments + r_index = 0 + py_in, _ = self._partition_args(routines[0].arguments) + n_in = len(py_in) + n_out = len(routines) + + # Declare Args + form = "char *{0}{1} = args[{2}];" + arg_decs = [form.format('in', i, i) for i in range(n_in)] + arg_decs.extend([form.format('out', i, i+n_in) for i in range(n_out)]) + declare_args = '\n '.join(arg_decs) + + # Declare Steps + form = "npy_intp {0}{1}_step = steps[{2}];" + step_decs = [form.format('in', i, i) for i in range(n_in)] + step_decs.extend([form.format('out', i, i+n_in) for i in range(n_out)]) + declare_steps = '\n '.join(step_decs) + + # Call Args + form = "*(double *)in{0}" + call_args = ', '.join([form.format(a) for a in range(n_in)]) + + # Step Increments + form = "{0}{1} += {0}{1}_step;" + step_incs = [form.format('in', i) for i in range(n_in)] + step_incs.extend([form.format('out', i, i) for i in range(n_out)]) + step_increments = '\n '.join(step_incs) + + # Types + n_types = n_in + n_out + types = "{" + ', '.join(["NPY_DOUBLE"]*n_types) + "};" + + # Docstring + docstring = '"Created in SymPy with Ufuncify"' + + # Function Creation + function_creation.append("PyObject *ufunc{};".format(r_index)) + + # Ufunc initialization + init_form = _ufunc_init_form.substitute(module=module, + funcname=name, + docstring=docstring, + n_in=n_in, n_out=n_out, + ind=r_index) + ufunc_init.append(init_form) + + outcalls = [_ufunc_outcalls.substitute( + outnum=i, call_args=call_args, funcname=routines[i].name) for i in + range(n_out)] + + body = _ufunc_body.substitute(module=module, funcname=name, + declare_args=declare_args, + declare_steps=declare_steps, + call_args=call_args, + step_increments=step_increments, + n_types=n_types, types=types, + outcalls='\n '.join(outcalls)) + functions.append(body) + + body = '\n\n'.join(functions) + ufunc_init = '\n '.join(ufunc_init) + function_creation = '\n '.join(function_creation) + bottom = _ufunc_bottom.substitute(module=module, + ufunc_init=ufunc_init, + function_creation=function_creation) + text = [top, body, bottom] + f.write('\n\n'.join(text)) + + def _partition_args(self, args): + """Group function arguments into categories.""" + py_in = [] + py_out = [] + for arg in args: + if isinstance(arg, OutputArgument): + py_out.append(arg) + elif isinstance(arg, InOutArgument): + raise ValueError("Ufuncify doesn't support InOutArguments") + else: + py_in.append(arg) + return py_in, py_out + + +@cacheit +@doctest_depends_on(exe=('f2py', 'gfortran', 'gcc'), modules=('numpy',)) +def ufuncify(args, expr, language=None, backend='numpy', tempdir=None, + flags=None, verbose=False, helpers=None, **kwargs): + """Generates a binary function that supports broadcasting on numpy arrays. + + Parameters + ========== + + args : iterable + Either a Symbol or an iterable of symbols. Specifies the argument + sequence for the function. + expr + A SymPy expression that defines the element wise operation. + language : string, optional + If supplied, (options: 'C' or 'F95'), specifies the language of the + generated code. If ``None`` [default], the language is inferred based + upon the specified backend. + backend : string, optional + Backend used to wrap the generated code. Either 'numpy' [default], + 'cython', or 'f2py'. + tempdir : string, optional + Path to directory for temporary files. If this argument is supplied, + the generated code and the wrapper input files are left intact in + the specified path. + flags : iterable, optional + Additional option flags that will be passed to the backend. + verbose : bool, optional + If True, autowrap will not mute the command line backends. This can + be helpful for debugging. + helpers : 3-tuple or iterable of 3-tuples, optional + Used to define auxiliary functions needed for the main expression. + Each tuple should be of the form (name, expr, args) where: + + - name : str, the function name + - expr : sympy expression, the function + - args : iterable, the function arguments (can be any iterable of symbols) + + kwargs : dict + These kwargs will be passed to autowrap if the `f2py` or `cython` + backend is used and ignored if the `numpy` backend is used. + + Notes + ===== + + The default backend ('numpy') will create actual instances of + ``numpy.ufunc``. These support ndimensional broadcasting, and implicit type + conversion. Use of the other backends will result in a "ufunc-like" + function, which requires equal length 1-dimensional arrays for all + arguments, and will not perform any type conversions. + + References + ========== + + .. [1] https://numpy.org/doc/stable/reference/ufuncs.html + + Examples + ======== + + Basic usage: + + >>> from sympy.utilities.autowrap import ufuncify + >>> from sympy.abc import x, y + >>> import numpy as np + >>> f = ufuncify((x, y), y + x**2) + >>> type(f) + + >>> f([1, 2, 3], 2) + array([ 3., 6., 11.]) + >>> f(np.arange(5), 3) + array([ 3., 4., 7., 12., 19.]) + + Using helper functions: + + >>> from sympy import Function + >>> helper_func = Function('helper_func') # Define symbolic function + >>> expr = x**2 + y*helper_func(x) # Main expression using helper function + >>> # Define helper_func(x) = x**3 + >>> f = ufuncify((x, y), expr, helpers=[('helper_func', x**3, [x])]) + >>> f([1, 2], [3, 4]) + array([ 4., 36.]) + + Type handling with different backends: + + For the 'f2py' and 'cython' backends, inputs are required to be equal length + 1-dimensional arrays. The 'f2py' backend will perform type conversion, but + the Cython backend will error if the inputs are not of the expected type. + + >>> f_fortran = ufuncify((x, y), y + x**2, backend='f2py') + >>> f_fortran(1, 2) + array([ 3.]) + >>> f_fortran(np.array([1, 2, 3]), np.array([1.0, 2.0, 3.0])) + array([ 2., 6., 12.]) + >>> f_cython = ufuncify((x, y), y + x**2, backend='Cython') + >>> f_cython(1, 2) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: Argument '_x' has incorrect type (expected numpy.ndarray, got int) + >>> f_cython(np.array([1.0]), np.array([2.0])) + array([ 3.]) + + """ + + if isinstance(args, Symbol): + args = (args,) + else: + args = tuple(args) + + if language: + _validate_backend_language(backend, language) + else: + language = _infer_language(backend) + + helpers = helpers if helpers else () + flags = flags if flags else () + + if backend.upper() == 'NUMPY': + # maxargs is set by numpy compile-time constant NPY_MAXARGS + # If a future version of numpy modifies or removes this restriction + # this variable should be changed or removed + maxargs = 32 + helps = [] + for name, expr, args in helpers: + helps.append(make_routine(name, expr, args)) + code_wrapper = UfuncifyCodeWrapper(C99CodeGen("ufuncify"), tempdir, + flags, verbose) + if not isinstance(expr, (list, tuple)): + expr = [expr] + if len(expr) == 0: + raise ValueError('Expression iterable has zero length') + if len(expr) + len(args) > maxargs: + msg = ('Cannot create ufunc with more than {0} total arguments: ' + 'got {1} in, {2} out') + raise ValueError(msg.format(maxargs, len(args), len(expr))) + routines = [make_routine('autofunc{}'.format(idx), exprx, args) for + idx, exprx in enumerate(expr)] + return code_wrapper.wrap_code(routines, helpers=helps) + else: + # Dummies are used for all added expressions to prevent name clashes + # within the original expression. + y = IndexedBase(Dummy('y')) + m = Dummy('m', integer=True) + i = Idx(Dummy('i', integer=True), m) + f_dummy = Dummy('f') + f = implemented_function('%s_%d' % (f_dummy.name, f_dummy.dummy_index), Lambda(args, expr)) + # For each of the args create an indexed version. + indexed_args = [IndexedBase(Dummy(str(a))) for a in args] + # Order the arguments (out, args, dim) + args = [y] + indexed_args + [m] + args_with_indices = [a[i] for a in indexed_args] + return autowrap(Eq(y[i], f(*args_with_indices)), language, backend, + tempdir, args, flags, verbose, helpers, **kwargs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/codegen.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/codegen.py new file mode 100644 index 0000000000000000000000000000000000000000..9ac8772fc000d707ae33c67eaa44b4c281157ab0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/codegen.py @@ -0,0 +1,2237 @@ +""" +module for generating C, C++, Fortran77, Fortran90, Julia, Rust +and Octave/Matlab routines that evaluate SymPy expressions. +This module is work in progress. +Only the milestones with a '+' character in the list below have been completed. + +--- How is sympy.utilities.codegen different from sympy.printing.ccode? --- + +We considered the idea to extend the printing routines for SymPy functions in +such a way that it prints complete compilable code, but this leads to a few +unsurmountable issues that can only be tackled with dedicated code generator: + +- For C, one needs both a code and a header file, while the printing routines + generate just one string. This code generator can be extended to support + .pyf files for f2py. + +- SymPy functions are not concerned with programming-technical issues, such + as input, output and input-output arguments. Other examples are contiguous + or non-contiguous arrays, including headers of other libraries such as gsl + or others. + +- It is highly interesting to evaluate several SymPy functions in one C + routine, eventually sharing common intermediate results with the help + of the cse routine. This is more than just printing. + +- From the programming perspective, expressions with constants should be + evaluated in the code generator as much as possible. This is different + for printing. + +--- Basic assumptions --- + +* A generic Routine data structure describes the routine that must be + translated into C/Fortran/... code. This data structure covers all + features present in one or more of the supported languages. + +* Descendants from the CodeGen class transform multiple Routine instances + into compilable code. Each derived class translates into a specific + language. + +* In many cases, one wants a simple workflow. The friendly functions in the + last part are a simple api on top of the Routine/CodeGen stuff. They are + easier to use, but are less powerful. + +--- Milestones --- + ++ First working version with scalar input arguments, generating C code, + tests ++ Friendly functions that are easier to use than the rigorous + Routine/CodeGen workflow. ++ Integer and Real numbers as input and output ++ Output arguments ++ InputOutput arguments ++ Sort input/output arguments properly ++ Contiguous array arguments (numpy matrices) ++ Also generate .pyf code for f2py (in autowrap module) ++ Isolate constants and evaluate them beforehand in double precision ++ Fortran 90 ++ Octave/Matlab + +- Common Subexpression Elimination +- User defined comments in the generated code +- Optional extra include lines for libraries/objects that can eval special + functions +- Test other C compilers and libraries: gcc, tcc, libtcc, gcc+gsl, ... +- Contiguous array arguments (SymPy matrices) +- Non-contiguous array arguments (SymPy matrices) +- ccode must raise an error when it encounters something that cannot be + translated into c. ccode(integrate(sin(x)/x, x)) does not make sense. +- Complex numbers as input and output +- A default complex datatype +- Include extra information in the header: date, user, hostname, sha1 + hash, ... +- Fortran 77 +- C++ +- Python +- Julia +- Rust +- ... + +""" + +import os +import textwrap +from io import StringIO + +from sympy import __version__ as sympy_version +from sympy.core import Symbol, S, Tuple, Equality, Function, Basic +from sympy.printing.c import c_code_printers +from sympy.printing.codeprinter import AssignmentError +from sympy.printing.fortran import FCodePrinter +from sympy.printing.julia import JuliaCodePrinter +from sympy.printing.octave import OctaveCodePrinter +from sympy.printing.rust import RustCodePrinter +from sympy.tensor import Idx, Indexed, IndexedBase +from sympy.matrices import (MatrixSymbol, ImmutableMatrix, MatrixBase, + MatrixExpr, MatrixSlice) +from sympy.utilities.iterables import is_sequence + + +__all__ = [ + # description of routines + "Routine", "DataType", "default_datatypes", "get_default_datatype", + "Argument", "InputArgument", "OutputArgument", "Result", + # routines -> code + "CodeGen", "CCodeGen", "FCodeGen", "JuliaCodeGen", "OctaveCodeGen", + "RustCodeGen", + # friendly functions + "codegen", "make_routine", +] + + +# +# Description of routines +# + + +class Routine: + """Generic description of evaluation routine for set of expressions. + + A CodeGen class can translate instances of this class into code in a + particular language. The routine specification covers all the features + present in these languages. The CodeGen part must raise an exception + when certain features are not present in the target language. For + example, multiple return values are possible in Python, but not in C or + Fortran. Another example: Fortran and Python support complex numbers, + while C does not. + + """ + + def __init__(self, name, arguments, results, local_vars, global_vars): + """Initialize a Routine instance. + + Parameters + ========== + + name : string + Name of the routine. + + arguments : list of Arguments + These are things that appear in arguments of a routine, often + appearing on the right-hand side of a function call. These are + commonly InputArguments but in some languages, they can also be + OutputArguments or InOutArguments (e.g., pass-by-reference in C + code). + + results : list of Results + These are the return values of the routine, often appearing on + the left-hand side of a function call. The difference between + Results and OutputArguments and when you should use each is + language-specific. + + local_vars : list of Results + These are variables that will be defined at the beginning of the + function. + + global_vars : list of Symbols + Variables which will not be passed into the function. + + """ + + # extract all input symbols and all symbols appearing in an expression + input_symbols = set() + symbols = set() + for arg in arguments: + if isinstance(arg, OutputArgument): + symbols.update(arg.expr.free_symbols - arg.expr.atoms(Indexed)) + elif isinstance(arg, InputArgument): + input_symbols.add(arg.name) + elif isinstance(arg, InOutArgument): + input_symbols.add(arg.name) + symbols.update(arg.expr.free_symbols - arg.expr.atoms(Indexed)) + else: + raise ValueError("Unknown Routine argument: %s" % arg) + + for r in results: + if not isinstance(r, Result): + raise ValueError("Unknown Routine result: %s" % r) + symbols.update(r.expr.free_symbols - r.expr.atoms(Indexed)) + + local_symbols = set() + for r in local_vars: + if isinstance(r, Result): + symbols.update(r.expr.free_symbols - r.expr.atoms(Indexed)) + local_symbols.add(r.name) + else: + local_symbols.add(r) + + symbols = {s.label if isinstance(s, Idx) else s for s in symbols} + + # Check that all symbols in the expressions are covered by + # InputArguments/InOutArguments---subset because user could + # specify additional (unused) InputArguments or local_vars. + notcovered = symbols.difference( + input_symbols.union(local_symbols).union(global_vars)) + if notcovered != set(): + raise ValueError("Symbols needed for output are not in input " + + ", ".join([str(x) for x in notcovered])) + + self.name = name + self.arguments = arguments + self.results = results + self.local_vars = local_vars + self.global_vars = global_vars + + def __str__(self): + return self.__class__.__name__ + "({name!r}, {arguments}, {results}, {local_vars}, {global_vars})".format(**self.__dict__) + + __repr__ = __str__ + + @property + def variables(self): + """Returns a set of all variables possibly used in the routine. + + For routines with unnamed return values, the dummies that may or + may not be used will be included in the set. + + """ + v = set(self.local_vars) + v.update(arg.name for arg in self.arguments) + v.update(res.result_var for res in self.results) + return v + + @property + def result_variables(self): + """Returns a list of OutputArgument, InOutArgument and Result. + + If return values are present, they are at the end of the list. + """ + args = [arg for arg in self.arguments if isinstance( + arg, (OutputArgument, InOutArgument))] + args.extend(self.results) + return args + + +class DataType: + """Holds strings for a certain datatype in different languages.""" + def __init__(self, cname, fname, pyname, jlname, octname, rsname): + self.cname = cname + self.fname = fname + self.pyname = pyname + self.jlname = jlname + self.octname = octname + self.rsname = rsname + + +default_datatypes = { + "int": DataType("int", "INTEGER*4", "int", "", "", "i32"), + "float": DataType("double", "REAL*8", "float", "", "", "f64"), + "complex": DataType("double", "COMPLEX*16", "complex", "", "", "float") #FIXME: + # complex is only supported in fortran, python, julia, and octave. + # So to not break c or rust code generation, we stick with double or + # float, respectively (but actually should raise an exception for + # explicitly complex variables (x.is_complex==True)) +} + + +COMPLEX_ALLOWED = False +def get_default_datatype(expr, complex_allowed=None): + """Derives an appropriate datatype based on the expression.""" + if complex_allowed is None: + complex_allowed = COMPLEX_ALLOWED + if complex_allowed: + final_dtype = "complex" + else: + final_dtype = "float" + if expr.is_integer: + return default_datatypes["int"] + elif expr.is_real: + return default_datatypes["float"] + elif isinstance(expr, MatrixBase): + #check all entries + dt = "int" + for element in expr: + if dt == "int" and not element.is_integer: + dt = "float" + if dt == "float" and not element.is_real: + return default_datatypes[final_dtype] + return default_datatypes[dt] + else: + return default_datatypes[final_dtype] + + +class Variable: + """Represents a typed variable.""" + + def __init__(self, name, datatype=None, dimensions=None, precision=None): + """Return a new variable. + + Parameters + ========== + + name : Symbol or MatrixSymbol + + datatype : optional + When not given, the data type will be guessed based on the + assumptions on the symbol argument. + + dimensions : sequence containing tuples, optional + If present, the argument is interpreted as an array, where this + sequence of tuples specifies (lower, upper) bounds for each + index of the array. + + precision : int, optional + Controls the precision of floating point constants. + + """ + if not isinstance(name, (Symbol, MatrixSymbol)): + raise TypeError("The first argument must be a SymPy symbol.") + if datatype is None: + datatype = get_default_datatype(name) + elif not isinstance(datatype, DataType): + raise TypeError("The (optional) `datatype' argument must be an " + "instance of the DataType class.") + if dimensions and not isinstance(dimensions, (tuple, list)): + raise TypeError( + "The dimensions argument must be a sequence of tuples") + + self._name = name + self._datatype = { + 'C': datatype.cname, + 'FORTRAN': datatype.fname, + 'JULIA': datatype.jlname, + 'OCTAVE': datatype.octname, + 'PYTHON': datatype.pyname, + 'RUST': datatype.rsname, + } + self.dimensions = dimensions + self.precision = precision + + def __str__(self): + return "%s(%r)" % (self.__class__.__name__, self.name) + + __repr__ = __str__ + + @property + def name(self): + return self._name + + def get_datatype(self, language): + """Returns the datatype string for the requested language. + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.utilities.codegen import Variable + >>> x = Variable(Symbol('x')) + >>> x.get_datatype('c') + 'double' + >>> x.get_datatype('fortran') + 'REAL*8' + + """ + try: + return self._datatype[language.upper()] + except KeyError: + raise CodeGenError("Has datatypes for languages: %s" % + ", ".join(self._datatype)) + + +class Argument(Variable): + """An abstract Argument data structure: a name and a data type. + + This structure is refined in the descendants below. + + """ + pass + + +class InputArgument(Argument): + pass + + +class ResultBase: + """Base class for all "outgoing" information from a routine. + + Objects of this class stores a SymPy expression, and a SymPy object + representing a result variable that will be used in the generated code + only if necessary. + + """ + def __init__(self, expr, result_var): + self.expr = expr + self.result_var = result_var + + def __str__(self): + return "%s(%r, %r)" % (self.__class__.__name__, self.expr, + self.result_var) + + __repr__ = __str__ + + +class OutputArgument(Argument, ResultBase): + """OutputArgument are always initialized in the routine.""" + + def __init__(self, name, result_var, expr, datatype=None, dimensions=None, precision=None): + """Return a new variable. + + Parameters + ========== + + name : Symbol, MatrixSymbol + The name of this variable. When used for code generation, this + might appear, for example, in the prototype of function in the + argument list. + + result_var : Symbol, Indexed + Something that can be used to assign a value to this variable. + Typically the same as `name` but for Indexed this should be e.g., + "y[i]" whereas `name` should be the Symbol "y". + + expr : object + The expression that should be output, typically a SymPy + expression. + + datatype : optional + When not given, the data type will be guessed based on the + assumptions on the symbol argument. + + dimensions : sequence containing tuples, optional + If present, the argument is interpreted as an array, where this + sequence of tuples specifies (lower, upper) bounds for each + index of the array. + + precision : int, optional + Controls the precision of floating point constants. + + """ + + Argument.__init__(self, name, datatype, dimensions, precision) + ResultBase.__init__(self, expr, result_var) + + def __str__(self): + return "%s(%r, %r, %r)" % (self.__class__.__name__, self.name, self.result_var, self.expr) + + __repr__ = __str__ + + +class InOutArgument(Argument, ResultBase): + """InOutArgument are never initialized in the routine.""" + + def __init__(self, name, result_var, expr, datatype=None, dimensions=None, precision=None): + if not datatype: + datatype = get_default_datatype(expr) + Argument.__init__(self, name, datatype, dimensions, precision) + ResultBase.__init__(self, expr, result_var) + __init__.__doc__ = OutputArgument.__init__.__doc__ + + + def __str__(self): + return "%s(%r, %r, %r)" % (self.__class__.__name__, self.name, self.expr, + self.result_var) + + __repr__ = __str__ + + +class Result(Variable, ResultBase): + """An expression for a return value. + + The name result is used to avoid conflicts with the reserved word + "return" in the Python language. It is also shorter than ReturnValue. + + These may or may not need a name in the destination (e.g., "return(x*y)" + might return a value without ever naming it). + + """ + + def __init__(self, expr, name=None, result_var=None, datatype=None, + dimensions=None, precision=None): + """Initialize a return value. + + Parameters + ========== + + expr : SymPy expression + + name : Symbol, MatrixSymbol, optional + The name of this return variable. When used for code generation, + this might appear, for example, in the prototype of function in a + list of return values. A dummy name is generated if omitted. + + result_var : Symbol, Indexed, optional + Something that can be used to assign a value to this variable. + Typically the same as `name` but for Indexed this should be e.g., + "y[i]" whereas `name` should be the Symbol "y". Defaults to + `name` if omitted. + + datatype : optional + When not given, the data type will be guessed based on the + assumptions on the expr argument. + + dimensions : sequence containing tuples, optional + If present, this variable is interpreted as an array, + where this sequence of tuples specifies (lower, upper) + bounds for each index of the array. + + precision : int, optional + Controls the precision of floating point constants. + + """ + # Basic because it is the base class for all types of expressions + if not isinstance(expr, (Basic, MatrixBase)): + raise TypeError("The first argument must be a SymPy expression.") + + if name is None: + name = 'result_%d' % abs(hash(expr)) + + if datatype is None: + #try to infer data type from the expression + datatype = get_default_datatype(expr) + + if isinstance(name, str): + if isinstance(expr, (MatrixBase, MatrixExpr)): + name = MatrixSymbol(name, *expr.shape) + else: + name = Symbol(name) + + if result_var is None: + result_var = name + + Variable.__init__(self, name, datatype=datatype, + dimensions=dimensions, precision=precision) + ResultBase.__init__(self, expr, result_var) + + def __str__(self): + return "%s(%r, %r, %r)" % (self.__class__.__name__, self.expr, self.name, + self.result_var) + + __repr__ = __str__ + + +# +# Transformation of routine objects into code +# + +class CodeGen: + """Abstract class for the code generators.""" + + printer = None # will be set to an instance of a CodePrinter subclass + + def _indent_code(self, codelines): + return self.printer.indent_code(codelines) + + def _printer_method_with_settings(self, method, settings=None, *args, **kwargs): + settings = settings or {} + ori = {k: self.printer._settings[k] for k in settings} + for k, v in settings.items(): + self.printer._settings[k] = v + result = getattr(self.printer, method)(*args, **kwargs) + for k, v in ori.items(): + self.printer._settings[k] = v + return result + + def _get_symbol(self, s): + """Returns the symbol as fcode prints it.""" + if self.printer._settings['human']: + expr_str = self.printer.doprint(s) + else: + constants, not_supported, expr_str = self.printer.doprint(s) + if constants or not_supported: + raise ValueError("Failed to print %s" % str(s)) + return expr_str.strip() + + def __init__(self, project="project", cse=False): + """Initialize a code generator. + + Derived classes will offer more options that affect the generated + code. + + """ + self.project = project + self.cse = cse + + def routine(self, name, expr, argument_sequence=None, global_vars=None): + """Creates an Routine object that is appropriate for this language. + + This implementation is appropriate for at least C/Fortran. Subclasses + can override this if necessary. + + Here, we assume at most one return value (the l-value) which must be + scalar. Additional outputs are OutputArguments (e.g., pointers on + right-hand-side or pass-by-reference). Matrices are always returned + via OutputArguments. If ``argument_sequence`` is None, arguments will + be ordered alphabetically, but with all InputArguments first, and then + OutputArgument and InOutArguments. + + """ + + if self.cse: + from sympy.simplify.cse_main import cse + + if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): + if not expr: + raise ValueError("No expression given") + for e in expr: + if not e.is_Equality: + raise CodeGenError("Lists of expressions must all be Equalities. {} is not.".format(e)) + + # create a list of right hand sides and simplify them + rhs = [e.rhs for e in expr] + common, simplified = cse(rhs) + + # pack the simplified expressions back up with their left hand sides + expr = [Equality(e.lhs, rhs) for e, rhs in zip(expr, simplified)] + else: + if isinstance(expr, Equality): + common, simplified = cse(expr.rhs) #, ignore=in_out_args) + expr = Equality(expr.lhs, simplified[0]) + else: + common, simplified = cse(expr) + expr = simplified + + local_vars = [Result(b,a) for a,b in common] + local_symbols = {a for a,_ in common} + local_expressions = Tuple(*[b for _,b in common]) + else: + local_expressions = Tuple() + + if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): + if not expr: + raise ValueError("No expression given") + expressions = Tuple(*expr) + else: + expressions = Tuple(expr) + + if self.cse: + if {i.label for i in expressions.atoms(Idx)} != set(): + raise CodeGenError("CSE and Indexed expressions do not play well together yet") + else: + # local variables for indexed expressions + local_vars = {i.label for i in expressions.atoms(Idx)} + local_symbols = local_vars + + # global variables + global_vars = set() if global_vars is None else set(global_vars) + + # symbols that should be arguments + symbols = (expressions.free_symbols | local_expressions.free_symbols) - local_symbols - global_vars + new_symbols = set() + new_symbols.update(symbols) + + for symbol in symbols: + if isinstance(symbol, Idx): + new_symbols.remove(symbol) + new_symbols.update(symbol.args[1].free_symbols) + if isinstance(symbol, Indexed): + new_symbols.remove(symbol) + symbols = new_symbols + + # Decide whether to use output argument or return value + return_val = [] + output_args = [] + for expr in expressions: + if isinstance(expr, Equality): + out_arg = expr.lhs + expr = expr.rhs + if isinstance(out_arg, Indexed): + dims = tuple([ (S.Zero, dim - 1) for dim in out_arg.shape]) + symbol = out_arg.base.label + elif isinstance(out_arg, Symbol): + dims = [] + symbol = out_arg + elif isinstance(out_arg, MatrixSymbol): + dims = tuple([ (S.Zero, dim - 1) for dim in out_arg.shape]) + symbol = out_arg + else: + raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol " + "can define output arguments.") + + if expr.has(symbol): + output_args.append( + InOutArgument(symbol, out_arg, expr, dimensions=dims)) + else: + output_args.append( + OutputArgument(symbol, out_arg, expr, dimensions=dims)) + + # remove duplicate arguments when they are not local variables + if symbol not in local_vars: + # avoid duplicate arguments + symbols.remove(symbol) + elif isinstance(expr, (ImmutableMatrix, MatrixSlice)): + # Create a "dummy" MatrixSymbol to use as the Output arg + out_arg = MatrixSymbol('out_%s' % abs(hash(expr)), *expr.shape) + dims = tuple([(S.Zero, dim - 1) for dim in out_arg.shape]) + output_args.append( + OutputArgument(out_arg, out_arg, expr, dimensions=dims)) + else: + return_val.append(Result(expr)) + + arg_list = [] + + # setup input argument list + + # helper to get dimensions for data for array-like args + def dimensions(s): + return [(S.Zero, dim - 1) for dim in s.shape] + + array_symbols = {} + for array in expressions.atoms(Indexed) | local_expressions.atoms(Indexed): + array_symbols[array.base.label] = array + for array in expressions.atoms(MatrixSymbol) | local_expressions.atoms(MatrixSymbol): + array_symbols[array] = array + + for symbol in sorted(symbols, key=str): + if symbol in array_symbols: + array = array_symbols[symbol] + metadata = {'dimensions': dimensions(array)} + else: + metadata = {} + + arg_list.append(InputArgument(symbol, **metadata)) + + output_args.sort(key=lambda x: str(x.name)) + arg_list.extend(output_args) + + if argument_sequence is not None: + # if the user has supplied IndexedBase instances, we'll accept that + new_sequence = [] + for arg in argument_sequence: + if isinstance(arg, IndexedBase): + new_sequence.append(arg.label) + else: + new_sequence.append(arg) + argument_sequence = new_sequence + + missing = [x for x in arg_list if x.name not in argument_sequence] + if missing: + msg = "Argument list didn't specify: {0} " + msg = msg.format(", ".join([str(m.name) for m in missing])) + raise CodeGenArgumentListError(msg, missing) + + # create redundant arguments to produce the requested sequence + name_arg_dict = {x.name: x for x in arg_list} + new_args = [] + for symbol in argument_sequence: + try: + new_args.append(name_arg_dict[symbol]) + except KeyError: + if isinstance(symbol, (IndexedBase, MatrixSymbol)): + metadata = {'dimensions': dimensions(symbol)} + else: + metadata = {} + new_args.append(InputArgument(symbol, **metadata)) + arg_list = new_args + + return Routine(name, arg_list, return_val, local_vars, global_vars) + + def write(self, routines, prefix, to_files=False, header=True, empty=True): + """Writes all the source code files for the given routines. + + The generated source is returned as a list of (filename, contents) + tuples, or is written to files (see below). Each filename consists + of the given prefix, appended with an appropriate extension. + + Parameters + ========== + + routines : list + A list of Routine instances to be written + + prefix : string + The prefix for the output files + + to_files : bool, optional + When True, the output is written to files. Otherwise, a list + of (filename, contents) tuples is returned. [default: False] + + header : bool, optional + When True, a header comment is included on top of each source + file. [default: True] + + empty : bool, optional + When True, empty lines are included to structure the source + files. [default: True] + + """ + if to_files: + for dump_fn in self.dump_fns: + filename = "%s.%s" % (prefix, dump_fn.extension) + with open(filename, "w") as f: + dump_fn(self, routines, f, prefix, header, empty) + else: + result = [] + for dump_fn in self.dump_fns: + filename = "%s.%s" % (prefix, dump_fn.extension) + contents = StringIO() + dump_fn(self, routines, contents, prefix, header, empty) + result.append((filename, contents.getvalue())) + return result + + def dump_code(self, routines, f, prefix, header=True, empty=True): + """Write the code by calling language specific methods. + + The generated file contains all the definitions of the routines in + low-level code and refers to the header file if appropriate. + + Parameters + ========== + + routines : list + A list of Routine instances. + + f : file-like + Where to write the file. + + prefix : string + The filename prefix, used to refer to the proper header file. + Only the basename of the prefix is used. + + header : bool, optional + When True, a header comment is included on top of each source + file. [default : True] + + empty : bool, optional + When True, empty lines are included to structure the source + files. [default : True] + + """ + + code_lines = self._preprocessor_statements(prefix) + + for routine in routines: + if empty: + code_lines.append("\n") + code_lines.extend(self._get_routine_opening(routine)) + code_lines.extend(self._declare_arguments(routine)) + code_lines.extend(self._declare_globals(routine)) + code_lines.extend(self._declare_locals(routine)) + if empty: + code_lines.append("\n") + code_lines.extend(self._call_printer(routine)) + if empty: + code_lines.append("\n") + code_lines.extend(self._get_routine_ending(routine)) + + code_lines = self._indent_code(''.join(code_lines)) + + if header: + code_lines = ''.join(self._get_header() + [code_lines]) + + if code_lines: + f.write(code_lines) + + +class CodeGenError(Exception): + pass + + +class CodeGenArgumentListError(Exception): + @property + def missing_args(self): + return self.args[1] + + +header_comment = """Code generated with SymPy %(version)s + +See http://www.sympy.org/ for more information. + +This file is part of '%(project)s' +""" + + +class CCodeGen(CodeGen): + """Generator for C code. + + The .write() method inherited from CodeGen will output a code file and + an interface file, .c and .h respectively. + + """ + + code_extension = "c" + interface_extension = "h" + standard = 'c99' + + def __init__(self, project="project", printer=None, + preprocessor_statements=None, cse=False): + super().__init__(project=project, cse=cse) + self.printer = printer or c_code_printers[self.standard.lower()]() + + self.preprocessor_statements = preprocessor_statements + if preprocessor_statements is None: + self.preprocessor_statements = ['#include '] + + def _get_header(self): + """Writes a common header for the generated files.""" + code_lines = [] + code_lines.append("/" + "*"*78 + '\n') + tmp = header_comment % {"version": sympy_version, + "project": self.project} + for line in tmp.splitlines(): + code_lines.append(" *%s*\n" % line.center(76)) + code_lines.append(" " + "*"*78 + "/\n") + return code_lines + + def get_prototype(self, routine): + """Returns a string for the function prototype of the routine. + + If the routine has multiple result objects, an CodeGenError is + raised. + + See: https://en.wikipedia.org/wiki/Function_prototype + + """ + if len(routine.results) > 1: + raise CodeGenError("C only supports a single or no return value.") + elif len(routine.results) == 1: + ctype = routine.results[0].get_datatype('C') + else: + ctype = "void" + + type_args = [] + for arg in routine.arguments: + name = self.printer.doprint(arg.name) + if arg.dimensions or isinstance(arg, ResultBase): + type_args.append((arg.get_datatype('C'), "*%s" % name)) + else: + type_args.append((arg.get_datatype('C'), name)) + arguments = ", ".join([ "%s %s" % t for t in type_args]) + return "%s %s(%s)" % (ctype, routine.name, arguments) + + def _preprocessor_statements(self, prefix): + code_lines = [] + code_lines.append('#include "{}.h"'.format(os.path.basename(prefix))) + code_lines.extend(self.preprocessor_statements) + code_lines = ['{}\n'.format(l) for l in code_lines] + return code_lines + + def _get_routine_opening(self, routine): + prototype = self.get_prototype(routine) + return ["%s {\n" % prototype] + + def _declare_arguments(self, routine): + # arguments are declared in prototype + return [] + + def _declare_globals(self, routine): + # global variables are not explicitly declared within C functions + return [] + + def _declare_locals(self, routine): + + # Compose a list of symbols to be dereferenced in the function + # body. These are the arguments that were passed by a reference + # pointer, excluding arrays. + dereference = [] + for arg in routine.arguments: + if isinstance(arg, ResultBase) and not arg.dimensions: + dereference.append(arg.name) + + code_lines = [] + for result in routine.local_vars: + + # local variables that are simple symbols such as those used as indices into + # for loops are defined declared elsewhere. + if not isinstance(result, Result): + continue + + if result.name != result.result_var: + raise CodeGen("Result variable and name should match: {}".format(result)) + assign_to = result.name + t = result.get_datatype('c') + if isinstance(result.expr, (MatrixBase, MatrixExpr)): + dims = result.expr.shape + code_lines.append("{} {}[{}];\n".format(t, str(assign_to), dims[0]*dims[1])) + prefix = "" + else: + prefix = "const {} ".format(t) + + constants, not_c, c_expr = self._printer_method_with_settings( + 'doprint', {"human": False, "dereference": dereference, "strict": False}, + result.expr, assign_to=assign_to) + + for name, value in sorted(constants, key=str): + code_lines.append("double const %s = %s;\n" % (name, value)) + + code_lines.append("{}{}\n".format(prefix, c_expr)) + + return code_lines + + def _call_printer(self, routine): + code_lines = [] + + # Compose a list of symbols to be dereferenced in the function + # body. These are the arguments that were passed by a reference + # pointer, excluding arrays. + dereference = [] + for arg in routine.arguments: + if isinstance(arg, ResultBase) and not arg.dimensions: + dereference.append(arg.name) + + return_val = None + for result in routine.result_variables: + if isinstance(result, Result): + assign_to = routine.name + "_result" + t = result.get_datatype('c') + code_lines.append("{} {};\n".format(t, str(assign_to))) + return_val = assign_to + else: + assign_to = result.result_var + + try: + constants, not_c, c_expr = self._printer_method_with_settings( + 'doprint', {"human": False, "dereference": dereference, "strict": False}, + result.expr, assign_to=assign_to) + except AssignmentError: + assign_to = result.result_var + code_lines.append( + "%s %s;\n" % (result.get_datatype('c'), str(assign_to))) + constants, not_c, c_expr = self._printer_method_with_settings( + 'doprint', {"human": False, "dereference": dereference, "strict": False}, + result.expr, assign_to=assign_to) + + for name, value in sorted(constants, key=str): + code_lines.append("double const %s = %s;\n" % (name, value)) + code_lines.append("%s\n" % c_expr) + + if return_val: + code_lines.append(" return %s;\n" % return_val) + return code_lines + + def _get_routine_ending(self, routine): + return ["}\n"] + + def dump_c(self, routines, f, prefix, header=True, empty=True): + self.dump_code(routines, f, prefix, header, empty) + dump_c.extension = code_extension # type: ignore + dump_c.__doc__ = CodeGen.dump_code.__doc__ + + def dump_h(self, routines, f, prefix, header=True, empty=True): + """Writes the C header file. + + This file contains all the function declarations. + + Parameters + ========== + + routines : list + A list of Routine instances. + + f : file-like + Where to write the file. + + prefix : string + The filename prefix, used to construct the include guards. + Only the basename of the prefix is used. + + header : bool, optional + When True, a header comment is included on top of each source + file. [default : True] + + empty : bool, optional + When True, empty lines are included to structure the source + files. [default : True] + + """ + if header: + print(''.join(self._get_header()), file=f) + guard_name = "%s__%s__H" % (self.project.replace( + " ", "_").upper(), prefix.replace("/", "_").upper()) + # include guards + if empty: + print(file=f) + print("#ifndef %s" % guard_name, file=f) + print("#define %s" % guard_name, file=f) + if empty: + print(file=f) + # declaration of the function prototypes + for routine in routines: + prototype = self.get_prototype(routine) + print("%s;" % prototype, file=f) + # end if include guards + if empty: + print(file=f) + print("#endif", file=f) + if empty: + print(file=f) + dump_h.extension = interface_extension # type: ignore + + # This list of dump functions is used by CodeGen.write to know which dump + # functions it has to call. + dump_fns = [dump_c, dump_h] + +class C89CodeGen(CCodeGen): + standard = 'C89' + +class C99CodeGen(CCodeGen): + standard = 'C99' + +class FCodeGen(CodeGen): + """Generator for Fortran 95 code + + The .write() method inherited from CodeGen will output a code file and + an interface file, .f90 and .h respectively. + + """ + + code_extension = "f90" + interface_extension = "h" + + def __init__(self, project='project', printer=None): + super().__init__(project) + self.printer = printer or FCodePrinter() + + def _get_header(self): + """Writes a common header for the generated files.""" + code_lines = [] + code_lines.append("!" + "*"*78 + '\n') + tmp = header_comment % {"version": sympy_version, + "project": self.project} + for line in tmp.splitlines(): + code_lines.append("!*%s*\n" % line.center(76)) + code_lines.append("!" + "*"*78 + '\n') + return code_lines + + def _preprocessor_statements(self, prefix): + return [] + + def _get_routine_opening(self, routine): + """Returns the opening statements of the fortran routine.""" + code_list = [] + if len(routine.results) > 1: + raise CodeGenError( + "Fortran only supports a single or no return value.") + elif len(routine.results) == 1: + result = routine.results[0] + code_list.append(result.get_datatype('fortran')) + code_list.append("function") + else: + code_list.append("subroutine") + + args = ", ".join("%s" % self._get_symbol(arg.name) + for arg in routine.arguments) + + call_sig = "{}({})\n".format(routine.name, args) + # Fortran 95 requires all lines be less than 132 characters, so wrap + # this line before appending. + call_sig = ' &\n'.join(textwrap.wrap(call_sig, + width=60, + break_long_words=False)) + '\n' + code_list.append(call_sig) + code_list = [' '.join(code_list)] + code_list.append('implicit none\n') + return code_list + + def _declare_arguments(self, routine): + # argument type declarations + code_list = [] + array_list = [] + scalar_list = [] + for arg in routine.arguments: + + if isinstance(arg, InputArgument): + typeinfo = "%s, intent(in)" % arg.get_datatype('fortran') + elif isinstance(arg, InOutArgument): + typeinfo = "%s, intent(inout)" % arg.get_datatype('fortran') + elif isinstance(arg, OutputArgument): + typeinfo = "%s, intent(out)" % arg.get_datatype('fortran') + else: + raise CodeGenError("Unknown Argument type: %s" % type(arg)) + + fprint = self._get_symbol + + if arg.dimensions: + # fortran arrays start at 1 + dimstr = ", ".join(["%s:%s" % ( + fprint(dim[0] + 1), fprint(dim[1] + 1)) + for dim in arg.dimensions]) + typeinfo += ", dimension(%s)" % dimstr + array_list.append("%s :: %s\n" % (typeinfo, fprint(arg.name))) + else: + scalar_list.append("%s :: %s\n" % (typeinfo, fprint(arg.name))) + + # scalars first, because they can be used in array declarations + code_list.extend(scalar_list) + code_list.extend(array_list) + + return code_list + + def _declare_globals(self, routine): + # Global variables not explicitly declared within Fortran 90 functions. + # Note: a future F77 mode may need to generate "common" blocks. + return [] + + def _declare_locals(self, routine): + code_list = [] + for var in sorted(routine.local_vars, key=str): + typeinfo = get_default_datatype(var) + code_list.append("%s :: %s\n" % ( + typeinfo.fname, self._get_symbol(var))) + return code_list + + def _get_routine_ending(self, routine): + """Returns the closing statements of the fortran routine.""" + if len(routine.results) == 1: + return ["end function\n"] + else: + return ["end subroutine\n"] + + def get_interface(self, routine): + """Returns a string for the function interface. + + The routine should have a single result object, which can be None. + If the routine has multiple result objects, a CodeGenError is + raised. + + See: https://en.wikipedia.org/wiki/Function_prototype + + """ + prototype = [ "interface\n" ] + prototype.extend(self._get_routine_opening(routine)) + prototype.extend(self._declare_arguments(routine)) + prototype.extend(self._get_routine_ending(routine)) + prototype.append("end interface\n") + + return "".join(prototype) + + def _call_printer(self, routine): + declarations = [] + code_lines = [] + for result in routine.result_variables: + if isinstance(result, Result): + assign_to = routine.name + elif isinstance(result, (OutputArgument, InOutArgument)): + assign_to = result.result_var + + constants, not_fortran, f_expr = self._printer_method_with_settings( + 'doprint', {"human": False, "source_format": 'free', "standard": 95, "strict": False}, + result.expr, assign_to=assign_to) + + for obj, v in sorted(constants, key=str): + t = get_default_datatype(obj) + declarations.append( + "%s, parameter :: %s = %s\n" % (t.fname, obj, v)) + for obj in sorted(not_fortran, key=str): + t = get_default_datatype(obj) + if isinstance(obj, Function): + name = obj.func + else: + name = obj + declarations.append("%s :: %s\n" % (t.fname, name)) + + code_lines.append("%s\n" % f_expr) + return declarations + code_lines + + def _indent_code(self, codelines): + return self._printer_method_with_settings( + 'indent_code', {"human": False, "source_format": 'free', "strict": False}, codelines) + + def dump_f95(self, routines, f, prefix, header=True, empty=True): + # check that symbols are unique with ignorecase + for r in routines: + lowercase = {str(x).lower() for x in r.variables} + orig_case = {str(x) for x in r.variables} + if len(lowercase) < len(orig_case): + raise CodeGenError("Fortran ignores case. Got symbols: %s" % + (", ".join([str(var) for var in r.variables]))) + self.dump_code(routines, f, prefix, header, empty) + dump_f95.extension = code_extension # type: ignore + dump_f95.__doc__ = CodeGen.dump_code.__doc__ + + def dump_h(self, routines, f, prefix, header=True, empty=True): + """Writes the interface to a header file. + + This file contains all the function declarations. + + Parameters + ========== + + routines : list + A list of Routine instances. + + f : file-like + Where to write the file. + + prefix : string + The filename prefix. + + header : bool, optional + When True, a header comment is included on top of each source + file. [default : True] + + empty : bool, optional + When True, empty lines are included to structure the source + files. [default : True] + + """ + if header: + print(''.join(self._get_header()), file=f) + if empty: + print(file=f) + # declaration of the function prototypes + for routine in routines: + prototype = self.get_interface(routine) + f.write(prototype) + if empty: + print(file=f) + dump_h.extension = interface_extension # type: ignore + + # This list of dump functions is used by CodeGen.write to know which dump + # functions it has to call. + dump_fns = [dump_f95, dump_h] + + +class JuliaCodeGen(CodeGen): + """Generator for Julia code. + + The .write() method inherited from CodeGen will output a code file + .jl. + + """ + + code_extension = "jl" + + def __init__(self, project='project', printer=None): + super().__init__(project) + self.printer = printer or JuliaCodePrinter() + + def routine(self, name, expr, argument_sequence, global_vars): + """Specialized Routine creation for Julia.""" + + if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): + if not expr: + raise ValueError("No expression given") + expressions = Tuple(*expr) + else: + expressions = Tuple(expr) + + # local variables + local_vars = {i.label for i in expressions.atoms(Idx)} + + # global variables + global_vars = set() if global_vars is None else set(global_vars) + + # symbols that should be arguments + old_symbols = expressions.free_symbols - local_vars - global_vars + symbols = set() + for s in old_symbols: + if isinstance(s, Idx): + symbols.update(s.args[1].free_symbols) + elif not isinstance(s, Indexed): + symbols.add(s) + + # Julia supports multiple return values + return_vals = [] + output_args = [] + for (i, expr) in enumerate(expressions): + if isinstance(expr, Equality): + out_arg = expr.lhs + expr = expr.rhs + symbol = out_arg + if isinstance(out_arg, Indexed): + dims = tuple([ (S.One, dim) for dim in out_arg.shape]) + symbol = out_arg.base.label + output_args.append(InOutArgument(symbol, out_arg, expr, dimensions=dims)) + if not isinstance(out_arg, (Indexed, Symbol, MatrixSymbol)): + raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol " + "can define output arguments.") + + return_vals.append(Result(expr, name=symbol, result_var=out_arg)) + if not expr.has(symbol): + # this is a pure output: remove from the symbols list, so + # it doesn't become an input. + symbols.remove(symbol) + + else: + # we have no name for this output + return_vals.append(Result(expr, name='out%d' % (i+1))) + + # setup input argument list + output_args.sort(key=lambda x: str(x.name)) + arg_list = list(output_args) + array_symbols = {} + for array in expressions.atoms(Indexed): + array_symbols[array.base.label] = array + for array in expressions.atoms(MatrixSymbol): + array_symbols[array] = array + + for symbol in sorted(symbols, key=str): + arg_list.append(InputArgument(symbol)) + + if argument_sequence is not None: + # if the user has supplied IndexedBase instances, we'll accept that + new_sequence = [] + for arg in argument_sequence: + if isinstance(arg, IndexedBase): + new_sequence.append(arg.label) + else: + new_sequence.append(arg) + argument_sequence = new_sequence + + missing = [x for x in arg_list if x.name not in argument_sequence] + if missing: + msg = "Argument list didn't specify: {0} " + msg = msg.format(", ".join([str(m.name) for m in missing])) + raise CodeGenArgumentListError(msg, missing) + + # create redundant arguments to produce the requested sequence + name_arg_dict = {x.name: x for x in arg_list} + new_args = [] + for symbol in argument_sequence: + try: + new_args.append(name_arg_dict[symbol]) + except KeyError: + new_args.append(InputArgument(symbol)) + arg_list = new_args + + return Routine(name, arg_list, return_vals, local_vars, global_vars) + + def _get_header(self): + """Writes a common header for the generated files.""" + code_lines = [] + tmp = header_comment % {"version": sympy_version, + "project": self.project} + for line in tmp.splitlines(): + if line == '': + code_lines.append("#\n") + else: + code_lines.append("# %s\n" % line) + return code_lines + + def _preprocessor_statements(self, prefix): + return [] + + def _get_routine_opening(self, routine): + """Returns the opening statements of the routine.""" + code_list = [] + code_list.append("function ") + + # Inputs + args = [] + for arg in routine.arguments: + if isinstance(arg, OutputArgument): + raise CodeGenError("Julia: invalid argument of type %s" % + str(type(arg))) + if isinstance(arg, (InputArgument, InOutArgument)): + args.append("%s" % self._get_symbol(arg.name)) + args = ", ".join(args) + code_list.append("%s(%s)\n" % (routine.name, args)) + code_list = [ "".join(code_list) ] + + return code_list + + def _declare_arguments(self, routine): + return [] + + def _declare_globals(self, routine): + return [] + + def _declare_locals(self, routine): + return [] + + def _get_routine_ending(self, routine): + outs = [] + for result in routine.results: + if isinstance(result, Result): + # Note: name not result_var; want `y` not `y[i]` for Indexed + s = self._get_symbol(result.name) + else: + raise CodeGenError("unexpected object in Routine results") + outs.append(s) + return ["return " + ", ".join(outs) + "\nend\n"] + + def _call_printer(self, routine): + declarations = [] + code_lines = [] + for result in routine.results: + if isinstance(result, Result): + assign_to = result.result_var + else: + raise CodeGenError("unexpected object in Routine results") + + constants, not_supported, jl_expr = self._printer_method_with_settings( + 'doprint', {"human": False, "strict": False}, result.expr, assign_to=assign_to) + + for obj, v in sorted(constants, key=str): + declarations.append( + "%s = %s\n" % (obj, v)) + for obj in sorted(not_supported, key=str): + if isinstance(obj, Function): + name = obj.func + else: + name = obj + declarations.append( + "# unsupported: %s\n" % (name)) + code_lines.append("%s\n" % (jl_expr)) + return declarations + code_lines + + def _indent_code(self, codelines): + # Note that indenting seems to happen twice, first + # statement-by-statement by JuliaPrinter then again here. + p = JuliaCodePrinter({'human': False, "strict": False}) + return p.indent_code(codelines) + + def dump_jl(self, routines, f, prefix, header=True, empty=True): + self.dump_code(routines, f, prefix, header, empty) + + dump_jl.extension = code_extension # type: ignore + dump_jl.__doc__ = CodeGen.dump_code.__doc__ + + # This list of dump functions is used by CodeGen.write to know which dump + # functions it has to call. + dump_fns = [dump_jl] + + +class OctaveCodeGen(CodeGen): + """Generator for Octave code. + + The .write() method inherited from CodeGen will output a code file + .m. + + Octave .m files usually contain one function. That function name should + match the filename (``prefix``). If you pass multiple ``name_expr`` pairs, + the latter ones are presumed to be private functions accessed by the + primary function. + + You should only pass inputs to ``argument_sequence``: outputs are ordered + according to their order in ``name_expr``. + + """ + + code_extension = "m" + + def __init__(self, project='project', printer=None): + super().__init__(project) + self.printer = printer or OctaveCodePrinter() + + def routine(self, name, expr, argument_sequence, global_vars): + """Specialized Routine creation for Octave.""" + + # FIXME: this is probably general enough for other high-level + # languages, perhaps its the C/Fortran one that is specialized! + + if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): + if not expr: + raise ValueError("No expression given") + expressions = Tuple(*expr) + else: + expressions = Tuple(expr) + + # local variables + local_vars = {i.label for i in expressions.atoms(Idx)} + + # global variables + global_vars = set() if global_vars is None else set(global_vars) + + # symbols that should be arguments + old_symbols = expressions.free_symbols - local_vars - global_vars + symbols = set() + for s in old_symbols: + if isinstance(s, Idx): + symbols.update(s.args[1].free_symbols) + elif not isinstance(s, Indexed): + symbols.add(s) + + # Octave supports multiple return values + return_vals = [] + for (i, expr) in enumerate(expressions): + if isinstance(expr, Equality): + out_arg = expr.lhs + expr = expr.rhs + symbol = out_arg + if isinstance(out_arg, Indexed): + symbol = out_arg.base.label + if not isinstance(out_arg, (Indexed, Symbol, MatrixSymbol)): + raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol " + "can define output arguments.") + + return_vals.append(Result(expr, name=symbol, result_var=out_arg)) + if not expr.has(symbol): + # this is a pure output: remove from the symbols list, so + # it doesn't become an input. + symbols.remove(symbol) + + else: + # we have no name for this output + return_vals.append(Result(expr, name='out%d' % (i+1))) + + # setup input argument list + arg_list = [] + array_symbols = {} + for array in expressions.atoms(Indexed): + array_symbols[array.base.label] = array + for array in expressions.atoms(MatrixSymbol): + array_symbols[array] = array + + for symbol in sorted(symbols, key=str): + arg_list.append(InputArgument(symbol)) + + if argument_sequence is not None: + # if the user has supplied IndexedBase instances, we'll accept that + new_sequence = [] + for arg in argument_sequence: + if isinstance(arg, IndexedBase): + new_sequence.append(arg.label) + else: + new_sequence.append(arg) + argument_sequence = new_sequence + + missing = [x for x in arg_list if x.name not in argument_sequence] + if missing: + msg = "Argument list didn't specify: {0} " + msg = msg.format(", ".join([str(m.name) for m in missing])) + raise CodeGenArgumentListError(msg, missing) + + # create redundant arguments to produce the requested sequence + name_arg_dict = {x.name: x for x in arg_list} + new_args = [] + for symbol in argument_sequence: + try: + new_args.append(name_arg_dict[symbol]) + except KeyError: + new_args.append(InputArgument(symbol)) + arg_list = new_args + + return Routine(name, arg_list, return_vals, local_vars, global_vars) + + def _get_header(self): + """Writes a common header for the generated files.""" + code_lines = [] + tmp = header_comment % {"version": sympy_version, + "project": self.project} + for line in tmp.splitlines(): + if line == '': + code_lines.append("%\n") + else: + code_lines.append("%% %s\n" % line) + return code_lines + + def _preprocessor_statements(self, prefix): + return [] + + def _get_routine_opening(self, routine): + """Returns the opening statements of the routine.""" + code_list = [] + code_list.append("function ") + + # Outputs + outs = [] + for result in routine.results: + if isinstance(result, Result): + # Note: name not result_var; want `y` not `y(i)` for Indexed + s = self._get_symbol(result.name) + else: + raise CodeGenError("unexpected object in Routine results") + outs.append(s) + if len(outs) > 1: + code_list.append("[" + (", ".join(outs)) + "]") + else: + code_list.append("".join(outs)) + code_list.append(" = ") + + # Inputs + args = [] + for arg in routine.arguments: + if isinstance(arg, (OutputArgument, InOutArgument)): + raise CodeGenError("Octave: invalid argument of type %s" % + str(type(arg))) + if isinstance(arg, InputArgument): + args.append("%s" % self._get_symbol(arg.name)) + args = ", ".join(args) + code_list.append("%s(%s)\n" % (routine.name, args)) + code_list = [ "".join(code_list) ] + + return code_list + + def _declare_arguments(self, routine): + return [] + + def _declare_globals(self, routine): + if not routine.global_vars: + return [] + s = " ".join(sorted([self._get_symbol(g) for g in routine.global_vars])) + return ["global " + s + "\n"] + + def _declare_locals(self, routine): + return [] + + def _get_routine_ending(self, routine): + return ["end\n"] + + def _call_printer(self, routine): + declarations = [] + code_lines = [] + for result in routine.results: + if isinstance(result, Result): + assign_to = result.result_var + else: + raise CodeGenError("unexpected object in Routine results") + + constants, not_supported, oct_expr = self._printer_method_with_settings( + 'doprint', {"human": False, "strict": False}, result.expr, assign_to=assign_to) + + for obj, v in sorted(constants, key=str): + declarations.append( + " %s = %s; %% constant\n" % (obj, v)) + for obj in sorted(not_supported, key=str): + if isinstance(obj, Function): + name = obj.func + else: + name = obj + declarations.append( + " %% unsupported: %s\n" % (name)) + code_lines.append("%s\n" % (oct_expr)) + return declarations + code_lines + + def _indent_code(self, codelines): + return self._printer_method_with_settings( + 'indent_code', {"human": False, "strict": False}, codelines) + + def dump_m(self, routines, f, prefix, header=True, empty=True, inline=True): + # Note used to call self.dump_code() but we need more control for header + + code_lines = self._preprocessor_statements(prefix) + + for i, routine in enumerate(routines): + if i > 0: + if empty: + code_lines.append("\n") + code_lines.extend(self._get_routine_opening(routine)) + if i == 0: + if routine.name != prefix: + raise ValueError('Octave function name should match prefix') + if header: + code_lines.append("%" + prefix.upper() + + " Autogenerated by SymPy\n") + code_lines.append(''.join(self._get_header())) + code_lines.extend(self._declare_arguments(routine)) + code_lines.extend(self._declare_globals(routine)) + code_lines.extend(self._declare_locals(routine)) + if empty: + code_lines.append("\n") + code_lines.extend(self._call_printer(routine)) + if empty: + code_lines.append("\n") + code_lines.extend(self._get_routine_ending(routine)) + + code_lines = self._indent_code(''.join(code_lines)) + + if code_lines: + f.write(code_lines) + + dump_m.extension = code_extension # type: ignore + dump_m.__doc__ = CodeGen.dump_code.__doc__ + + # This list of dump functions is used by CodeGen.write to know which dump + # functions it has to call. + dump_fns = [dump_m] + +class RustCodeGen(CodeGen): + """Generator for Rust code. + + The .write() method inherited from CodeGen will output a code file + .rs + + """ + + code_extension = "rs" + + def __init__(self, project="project", printer=None): + super().__init__(project=project) + self.printer = printer or RustCodePrinter() + + def routine(self, name, expr, argument_sequence, global_vars): + """Specialized Routine creation for Rust.""" + + if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): + if not expr: + raise ValueError("No expression given") + expressions = Tuple(*expr) + else: + expressions = Tuple(expr) + + # local variables + local_vars = {i.label for i in expressions.atoms(Idx)} + + # global variables + global_vars = set() if global_vars is None else set(global_vars) + + # symbols that should be arguments + symbols = expressions.free_symbols - local_vars - global_vars - expressions.atoms(Indexed) + + # Rust supports multiple return values + return_vals = [] + output_args = [] + for (i, expr) in enumerate(expressions): + if isinstance(expr, Equality): + out_arg = expr.lhs + expr = expr.rhs + symbol = out_arg + if isinstance(out_arg, Indexed): + dims = tuple([ (S.One, dim) for dim in out_arg.shape]) + symbol = out_arg.base.label + output_args.append(InOutArgument(symbol, out_arg, expr, dimensions=dims)) + if not isinstance(out_arg, (Indexed, Symbol, MatrixSymbol)): + raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol " + "can define output arguments.") + + return_vals.append(Result(expr, name=symbol, result_var=out_arg)) + if not expr.has(symbol): + # this is a pure output: remove from the symbols list, so + # it doesn't become an input. + symbols.remove(symbol) + + else: + # we have no name for this output + return_vals.append(Result(expr, name='out%d' % (i+1))) + + # setup input argument list + output_args.sort(key=lambda x: str(x.name)) + arg_list = list(output_args) + array_symbols = {} + for array in expressions.atoms(Indexed): + array_symbols[array.base.label] = array + for array in expressions.atoms(MatrixSymbol): + array_symbols[array] = array + + for symbol in sorted(symbols, key=str): + arg_list.append(InputArgument(symbol)) + + if argument_sequence is not None: + # if the user has supplied IndexedBase instances, we'll accept that + new_sequence = [] + for arg in argument_sequence: + if isinstance(arg, IndexedBase): + new_sequence.append(arg.label) + else: + new_sequence.append(arg) + argument_sequence = new_sequence + + missing = [x for x in arg_list if x.name not in argument_sequence] + if missing: + msg = "Argument list didn't specify: {0} " + msg = msg.format(", ".join([str(m.name) for m in missing])) + raise CodeGenArgumentListError(msg, missing) + + # create redundant arguments to produce the requested sequence + name_arg_dict = {x.name: x for x in arg_list} + new_args = [] + for symbol in argument_sequence: + try: + new_args.append(name_arg_dict[symbol]) + except KeyError: + new_args.append(InputArgument(symbol)) + arg_list = new_args + + return Routine(name, arg_list, return_vals, local_vars, global_vars) + + + def _get_header(self): + """Writes a common header for the generated files.""" + code_lines = [] + code_lines.append("/*\n") + tmp = header_comment % {"version": sympy_version, + "project": self.project} + for line in tmp.splitlines(): + code_lines.append((" *%s" % line.center(76)).rstrip() + "\n") + code_lines.append(" */\n") + return code_lines + + def get_prototype(self, routine): + """Returns a string for the function prototype of the routine. + + If the routine has multiple result objects, an CodeGenError is + raised. + + See: https://en.wikipedia.org/wiki/Function_prototype + + """ + results = [i.get_datatype('Rust') for i in routine.results] + + if len(results) == 1: + rstype = " -> " + results[0] + elif len(routine.results) > 1: + rstype = " -> (" + ", ".join(results) + ")" + else: + rstype = "" + + type_args = [] + for arg in routine.arguments: + name = self.printer.doprint(arg.name) + if arg.dimensions or isinstance(arg, ResultBase): + type_args.append(("*%s" % name, arg.get_datatype('Rust'))) + else: + type_args.append((name, arg.get_datatype('Rust'))) + arguments = ", ".join([ "%s: %s" % t for t in type_args]) + return "fn %s(%s)%s" % (routine.name, arguments, rstype) + + def _preprocessor_statements(self, prefix): + code_lines = [] + # code_lines.append("use std::f64::consts::*;\n") + return code_lines + + def _get_routine_opening(self, routine): + prototype = self.get_prototype(routine) + return ["%s {\n" % prototype] + + def _declare_arguments(self, routine): + # arguments are declared in prototype + return [] + + def _declare_globals(self, routine): + # global variables are not explicitly declared within C functions + return [] + + def _declare_locals(self, routine): + # loop variables are declared in loop statement + return [] + + def _call_printer(self, routine): + + code_lines = [] + declarations = [] + returns = [] + + # Compose a list of symbols to be dereferenced in the function + # body. These are the arguments that were passed by a reference + # pointer, excluding arrays. + dereference = [] + for arg in routine.arguments: + if isinstance(arg, ResultBase) and not arg.dimensions: + dereference.append(arg.name) + + for result in routine.results: + if isinstance(result, Result): + assign_to = result.result_var + returns.append(str(result.result_var)) + else: + raise CodeGenError("unexpected object in Routine results") + + constants, not_supported, rs_expr = self._printer_method_with_settings( + 'doprint', {"human": False, "strict": False}, result.expr, assign_to=assign_to) + + for name, value in sorted(constants, key=str): + declarations.append("const %s: f64 = %s;\n" % (name, value)) + + for obj in sorted(not_supported, key=str): + if isinstance(obj, Function): + name = obj.func + else: + name = obj + declarations.append("// unsupported: %s\n" % (name)) + + code_lines.append("let %s\n" % rs_expr) + + if len(returns) > 1: + returns = ['(' + ', '.join(returns) + ')'] + + returns.append('\n') + + return declarations + code_lines + returns + + def _get_routine_ending(self, routine): + return ["}\n"] + + def dump_rs(self, routines, f, prefix, header=True, empty=True): + self.dump_code(routines, f, prefix, header, empty) + + dump_rs.extension = code_extension # type: ignore + dump_rs.__doc__ = CodeGen.dump_code.__doc__ + + # This list of dump functions is used by CodeGen.write to know which dump + # functions it has to call. + dump_fns = [dump_rs] + + + + +def get_code_generator(language, project=None, standard=None, printer = None): + if language == 'C': + if standard is None: + pass + elif standard.lower() == 'c89': + language = 'C89' + elif standard.lower() == 'c99': + language = 'C99' + CodeGenClass = {"C": CCodeGen, "C89": C89CodeGen, "C99": C99CodeGen, + "F95": FCodeGen, "JULIA": JuliaCodeGen, + "OCTAVE": OctaveCodeGen, + "RUST": RustCodeGen}.get(language.upper()) + if CodeGenClass is None: + raise ValueError("Language '%s' is not supported." % language) + return CodeGenClass(project, printer) + + +# +# Friendly functions +# + + +def codegen(name_expr, language=None, prefix=None, project="project", + to_files=False, header=True, empty=True, argument_sequence=None, + global_vars=None, standard=None, code_gen=None, printer=None): + """Generate source code for expressions in a given language. + + Parameters + ========== + + name_expr : tuple, or list of tuples + A single (name, expression) tuple or a list of (name, expression) + tuples. Each tuple corresponds to a routine. If the expression is + an equality (an instance of class Equality) the left hand side is + considered an output argument. If expression is an iterable, then + the routine will have multiple outputs. + + language : string, + A string that indicates the source code language. This is case + insensitive. Currently, 'C', 'F95' and 'Octave' are supported. + 'Octave' generates code compatible with both Octave and Matlab. + + prefix : string, optional + A prefix for the names of the files that contain the source code. + Language-dependent suffixes will be appended. If omitted, the name + of the first name_expr tuple is used. + + project : string, optional + A project name, used for making unique preprocessor instructions. + [default: "project"] + + to_files : bool, optional + When True, the code will be written to one or more files with the + given prefix, otherwise strings with the names and contents of + these files are returned. [default: False] + + header : bool, optional + When True, a header is written on top of each source file. + [default: True] + + empty : bool, optional + When True, empty lines are used to structure the code. + [default: True] + + argument_sequence : iterable, optional + Sequence of arguments for the routine in a preferred order. A + CodeGenError is raised if required arguments are missing. + Redundant arguments are used without warning. If omitted, + arguments will be ordered alphabetically, but with all input + arguments first, and then output or in-out arguments. + + global_vars : iterable, optional + Sequence of global variables used by the routine. Variables + listed here will not show up as function arguments. + + standard : string, optional + + code_gen : CodeGen instance, optional + An instance of a CodeGen subclass. Overrides ``language``. + + printer : Printer instance, optional + An instance of a Printer subclass. + + Examples + ======== + + >>> from sympy.utilities.codegen import codegen + >>> from sympy.abc import x, y, z + >>> [(c_name, c_code), (h_name, c_header)] = codegen( + ... ("f", x+y*z), "C89", "test", header=False, empty=False) + >>> print(c_name) + test.c + >>> print(c_code) + #include "test.h" + #include + double f(double x, double y, double z) { + double f_result; + f_result = x + y*z; + return f_result; + } + + >>> print(h_name) + test.h + >>> print(c_header) + #ifndef PROJECT__TEST__H + #define PROJECT__TEST__H + double f(double x, double y, double z); + #endif + + + Another example using Equality objects to give named outputs. Here the + filename (prefix) is taken from the first (name, expr) pair. + + >>> from sympy.abc import f, g + >>> from sympy import Eq + >>> [(c_name, c_code), (h_name, c_header)] = codegen( + ... [("myfcn", x + y), ("fcn2", [Eq(f, 2*x), Eq(g, y)])], + ... "C99", header=False, empty=False) + >>> print(c_name) + myfcn.c + >>> print(c_code) + #include "myfcn.h" + #include + double myfcn(double x, double y) { + double myfcn_result; + myfcn_result = x + y; + return myfcn_result; + } + void fcn2(double x, double y, double *f, double *g) { + (*f) = 2*x; + (*g) = y; + } + + + If the generated function(s) will be part of a larger project where various + global variables have been defined, the 'global_vars' option can be used + to remove the specified variables from the function signature + + >>> from sympy.utilities.codegen import codegen + >>> from sympy.abc import x, y, z + >>> [(f_name, f_code), header] = codegen( + ... ("f", x+y*z), "F95", header=False, empty=False, + ... argument_sequence=(x, y), global_vars=(z,)) + >>> print(f_code) + REAL*8 function f(x, y) + implicit none + REAL*8, intent(in) :: x + REAL*8, intent(in) :: y + f = x + y*z + end function + + + """ + + # Initialize the code generator. + if language is None: + if code_gen is None: + raise ValueError("Need either language or code_gen") + else: + if code_gen is not None: + raise ValueError("You cannot specify both language and code_gen.") + code_gen = get_code_generator(language, project, standard, printer) + + if isinstance(name_expr[0], str): + # single tuple is given, turn it into a singleton list with a tuple. + name_expr = [name_expr] + + if prefix is None: + prefix = name_expr[0][0] + + # Construct Routines appropriate for this code_gen from (name, expr) pairs. + routines = [] + for name, expr in name_expr: + routines.append(code_gen.routine(name, expr, argument_sequence, + global_vars)) + + # Write the code. + return code_gen.write(routines, prefix, to_files, header, empty) + + +def make_routine(name, expr, argument_sequence=None, + global_vars=None, language="F95"): + """A factory that makes an appropriate Routine from an expression. + + Parameters + ========== + + name : string + The name of this routine in the generated code. + + expr : expression or list/tuple of expressions + A SymPy expression that the Routine instance will represent. If + given a list or tuple of expressions, the routine will be + considered to have multiple return values and/or output arguments. + + argument_sequence : list or tuple, optional + List arguments for the routine in a preferred order. If omitted, + the results are language dependent, for example, alphabetical order + or in the same order as the given expressions. + + global_vars : iterable, optional + Sequence of global variables used by the routine. Variables + listed here will not show up as function arguments. + + language : string, optional + Specify a target language. The Routine itself should be + language-agnostic but the precise way one is created, error + checking, etc depend on the language. [default: "F95"]. + + Notes + ===== + + A decision about whether to use output arguments or return values is made + depending on both the language and the particular mathematical expressions. + For an expression of type Equality, the left hand side is typically made + into an OutputArgument (or perhaps an InOutArgument if appropriate). + Otherwise, typically, the calculated expression is made a return values of + the routine. + + Examples + ======== + + >>> from sympy.utilities.codegen import make_routine + >>> from sympy.abc import x, y, f, g + >>> from sympy import Eq + >>> r = make_routine('test', [Eq(f, 2*x), Eq(g, x + y)]) + >>> [arg.result_var for arg in r.results] + [] + >>> [arg.name for arg in r.arguments] + [x, y, f, g] + >>> [arg.name for arg in r.result_variables] + [f, g] + >>> r.local_vars + set() + + Another more complicated example with a mixture of specified and + automatically-assigned names. Also has Matrix output. + + >>> from sympy import Matrix + >>> r = make_routine('fcn', [x*y, Eq(f, 1), Eq(g, x + g), Matrix([[x, 2]])]) + >>> [arg.result_var for arg in r.results] # doctest: +SKIP + [result_5397460570204848505] + >>> [arg.expr for arg in r.results] + [x*y] + >>> [arg.name for arg in r.arguments] # doctest: +SKIP + [x, y, f, g, out_8598435338387848786] + + We can examine the various arguments more closely: + + >>> from sympy.utilities.codegen import (InputArgument, OutputArgument, + ... InOutArgument) + >>> [a.name for a in r.arguments if isinstance(a, InputArgument)] + [x, y] + + >>> [a.name for a in r.arguments if isinstance(a, OutputArgument)] # doctest: +SKIP + [f, out_8598435338387848786] + >>> [a.expr for a in r.arguments if isinstance(a, OutputArgument)] + [1, Matrix([[x, 2]])] + + >>> [a.name for a in r.arguments if isinstance(a, InOutArgument)] + [g] + >>> [a.expr for a in r.arguments if isinstance(a, InOutArgument)] + [g + x] + + """ + + # initialize a new code generator + code_gen = get_code_generator(language) + + return code_gen.routine(name, expr, argument_sequence, global_vars) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/decorator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/decorator.py new file mode 100644 index 0000000000000000000000000000000000000000..82636c35e9f235a1d23aa7df5182418db3ef6b4f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/decorator.py @@ -0,0 +1,339 @@ +"""Useful utility decorators. """ + +from typing import TypeVar +import sys +import types +import inspect +from functools import wraps, update_wrapper + +from sympy.utilities.exceptions import sympy_deprecation_warning + + +T = TypeVar('T') +"""A generic type""" + + +def threaded_factory(func, use_add): + """A factory for ``threaded`` decorators. """ + from sympy.core import sympify + from sympy.matrices import MatrixBase + from sympy.utilities.iterables import iterable + + @wraps(func) + def threaded_func(expr, *args, **kwargs): + if isinstance(expr, MatrixBase): + return expr.applyfunc(lambda f: func(f, *args, **kwargs)) + elif iterable(expr): + try: + return expr.__class__([func(f, *args, **kwargs) for f in expr]) + except TypeError: + return expr + else: + expr = sympify(expr) + + if use_add and expr.is_Add: + return expr.__class__(*[ func(f, *args, **kwargs) for f in expr.args ]) + elif expr.is_Relational: + return expr.__class__(func(expr.lhs, *args, **kwargs), + func(expr.rhs, *args, **kwargs)) + else: + return func(expr, *args, **kwargs) + + return threaded_func + + +def threaded(func): + """Apply ``func`` to sub--elements of an object, including :class:`~.Add`. + + This decorator is intended to make it uniformly possible to apply a + function to all elements of composite objects, e.g. matrices, lists, tuples + and other iterable containers, or just expressions. + + This version of :func:`threaded` decorator allows threading over + elements of :class:`~.Add` class. If this behavior is not desirable + use :func:`xthreaded` decorator. + + Functions using this decorator must have the following signature:: + + @threaded + def function(expr, *args, **kwargs): + + """ + return threaded_factory(func, True) + + +def xthreaded(func): + """Apply ``func`` to sub--elements of an object, excluding :class:`~.Add`. + + This decorator is intended to make it uniformly possible to apply a + function to all elements of composite objects, e.g. matrices, lists, tuples + and other iterable containers, or just expressions. + + This version of :func:`threaded` decorator disallows threading over + elements of :class:`~.Add` class. If this behavior is not desirable + use :func:`threaded` decorator. + + Functions using this decorator must have the following signature:: + + @xthreaded + def function(expr, *args, **kwargs): + + """ + return threaded_factory(func, False) + + +def conserve_mpmath_dps(func): + """After the function finishes, resets the value of ``mpmath.mp.dps`` to + the value it had before the function was run.""" + import mpmath + + def func_wrapper(*args, **kwargs): + dps = mpmath.mp.dps + try: + return func(*args, **kwargs) + finally: + mpmath.mp.dps = dps + + func_wrapper = update_wrapper(func_wrapper, func) + return func_wrapper + + +class no_attrs_in_subclass: + """Don't 'inherit' certain attributes from a base class + + >>> from sympy.utilities.decorator import no_attrs_in_subclass + + >>> class A(object): + ... x = 'test' + + >>> A.x = no_attrs_in_subclass(A, A.x) + + >>> class B(A): + ... pass + + >>> hasattr(A, 'x') + True + >>> hasattr(B, 'x') + False + + """ + def __init__(self, cls, f): + self.cls = cls + self.f = f + + def __get__(self, instance, owner=None): + if owner == self.cls: + if hasattr(self.f, '__get__'): + return self.f.__get__(instance, owner) + return self.f + raise AttributeError + + +def doctest_depends_on(exe=None, modules=None, disable_viewers=None, + python_version=None, ground_types=None): + """ + Adds metadata about the dependencies which need to be met for doctesting + the docstrings of the decorated objects. + + ``exe`` should be a list of executables + + ``modules`` should be a list of modules + + ``disable_viewers`` should be a list of viewers for :func:`~sympy.printing.preview.preview` to disable + + ``python_version`` should be the minimum Python version required, as a tuple + (like ``(3, 0)``) + """ + dependencies = {} + if exe is not None: + dependencies['executables'] = exe + if modules is not None: + dependencies['modules'] = modules + if disable_viewers is not None: + dependencies['disable_viewers'] = disable_viewers + if python_version is not None: + dependencies['python_version'] = python_version + if ground_types is not None: + dependencies['ground_types'] = ground_types + + def skiptests(): + from sympy.testing.runtests import DependencyError, SymPyDocTests, PyTestReporter # lazy import + r = PyTestReporter() + t = SymPyDocTests(r, None) + try: + t._check_dependencies(**dependencies) + except DependencyError: + return True # Skip doctests + else: + return False # Run doctests + + def depends_on_deco(fn): + fn._doctest_depends_on = dependencies + fn.__doctest_skip__ = skiptests + + if inspect.isclass(fn): + fn._doctest_depdends_on = no_attrs_in_subclass( + fn, fn._doctest_depends_on) + fn.__doctest_skip__ = no_attrs_in_subclass( + fn, fn.__doctest_skip__) + return fn + + return depends_on_deco + + +def public(obj: T) -> T: + """ + Append ``obj``'s name to global ``__all__`` variable (call site). + + By using this decorator on functions or classes you achieve the same goal + as by filling ``__all__`` variables manually, you just do not have to repeat + yourself (object's name). You also know if object is public at definition + site, not at some random location (where ``__all__`` was set). + + Note that in multiple decorator setup (in almost all cases) ``@public`` + decorator must be applied before any other decorators, because it relies + on the pointer to object's global namespace. If you apply other decorators + first, ``@public`` may end up modifying the wrong namespace. + + Examples + ======== + + >>> from sympy.utilities.decorator import public + + >>> __all__ # noqa: F821 + Traceback (most recent call last): + ... + NameError: name '__all__' is not defined + + >>> @public + ... def some_function(): + ... pass + + >>> __all__ # noqa: F821 + ['some_function'] + + """ + if isinstance(obj, types.FunctionType): + ns = obj.__globals__ + name = obj.__name__ + elif isinstance(obj, (type(type), type)): + ns = sys.modules[obj.__module__].__dict__ + name = obj.__name__ + else: + raise TypeError("expected a function or a class, got %s" % obj) + + if "__all__" not in ns: + ns["__all__"] = [name] + else: + ns["__all__"].append(name) + + return obj + + +def memoize_property(propfunc): + """Property decorator that caches the value of potentially expensive + ``propfunc`` after the first evaluation. The cached value is stored in + the corresponding property name with an attached underscore.""" + attrname = '_' + propfunc.__name__ + sentinel = object() + + @wraps(propfunc) + def accessor(self): + val = getattr(self, attrname, sentinel) + if val is sentinel: + val = propfunc(self) + setattr(self, attrname, val) + return val + + return property(accessor) + + +def deprecated(message, *, deprecated_since_version, + active_deprecations_target, stacklevel=3): + ''' + Mark a function as deprecated. + + This decorator should be used if an entire function or class is + deprecated. If only a certain functionality is deprecated, you should use + :func:`~.warns_deprecated_sympy` directly. This decorator is just a + convenience. There is no functional difference between using this + decorator and calling ``warns_deprecated_sympy()`` at the top of the + function. + + The decorator takes the same arguments as + :func:`~.warns_deprecated_sympy`. See its + documentation for details on what the keywords to this decorator do. + + See the :ref:`deprecation-policy` document for details on when and how + things should be deprecated in SymPy. + + Examples + ======== + + >>> from sympy.utilities.decorator import deprecated + >>> from sympy import simplify + >>> @deprecated("""\ + ... The simplify_this(expr) function is deprecated. Use simplify(expr) + ... instead.""", deprecated_since_version="1.1", + ... active_deprecations_target='simplify-this-deprecation') + ... def simplify_this(expr): + ... """ + ... Simplify ``expr``. + ... + ... .. deprecated:: 1.1 + ... + ... The ``simplify_this`` function is deprecated. Use :func:`simplify` + ... instead. See its documentation for more information. See + ... :ref:`simplify-this-deprecation` for details. + ... + ... """ + ... return simplify(expr) + >>> from sympy.abc import x + >>> simplify_this(x*(x + 1) - x**2) # doctest: +SKIP + :1: SymPyDeprecationWarning: + + The simplify_this(expr) function is deprecated. Use simplify(expr) + instead. + + See https://docs.sympy.org/latest/explanation/active-deprecations.html#simplify-this-deprecation + for details. + + This has been deprecated since SymPy version 1.1. It + will be removed in a future version of SymPy. + + simplify_this(x) + x + + See Also + ======== + sympy.utilities.exceptions.SymPyDeprecationWarning + sympy.utilities.exceptions.sympy_deprecation_warning + sympy.utilities.exceptions.ignore_warnings + sympy.testing.pytest.warns_deprecated_sympy + + ''' + decorator_kwargs = {"deprecated_since_version": deprecated_since_version, + "active_deprecations_target": active_deprecations_target} + def deprecated_decorator(wrapped): + if hasattr(wrapped, '__mro__'): # wrapped is actually a class + class wrapper(wrapped): + __doc__ = wrapped.__doc__ + __module__ = wrapped.__module__ + _sympy_deprecated_func = wrapped + if '__new__' in wrapped.__dict__: + def __new__(cls, *args, **kwargs): + sympy_deprecation_warning(message, **decorator_kwargs, stacklevel=stacklevel) + return super().__new__(cls, *args, **kwargs) + else: + def __init__(self, *args, **kwargs): + sympy_deprecation_warning(message, **decorator_kwargs, stacklevel=stacklevel) + super().__init__(*args, **kwargs) + wrapper.__name__ = wrapped.__name__ + else: + @wraps(wrapped) + def wrapper(*args, **kwargs): + sympy_deprecation_warning(message, **decorator_kwargs, stacklevel=stacklevel) + return wrapped(*args, **kwargs) + wrapper._sympy_deprecated_func = wrapped + return wrapper + return deprecated_decorator diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/enumerative.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/enumerative.py new file mode 100644 index 0000000000000000000000000000000000000000..dcdabf064ad6291282b5905e7aed0ba9eb412d1a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/enumerative.py @@ -0,0 +1,1155 @@ +""" +Algorithms and classes to support enumerative combinatorics. + +Currently just multiset partitions, but more could be added. + +Terminology (following Knuth, algorithm 7.1.2.5M TAOCP) +*multiset* aaabbcccc has a *partition* aaabc | bccc + +The submultisets, aaabc and bccc of the partition are called +*parts*, or sometimes *vectors*. (Knuth notes that multiset +partitions can be thought of as partitions of vectors of integers, +where the ith element of the vector gives the multiplicity of +element i.) + +The values a, b and c are *components* of the multiset. These +correspond to elements of a set, but in a multiset can be present +with a multiplicity greater than 1. + +The algorithm deserves some explanation. + +Think of the part aaabc from the multiset above. If we impose an +ordering on the components of the multiset, we can represent a part +with a vector, in which the value of the first element of the vector +corresponds to the multiplicity of the first component in that +part. Thus, aaabc can be represented by the vector [3, 1, 1]. We +can also define an ordering on parts, based on the lexicographic +ordering of the vector (leftmost vector element, i.e., the element +with the smallest component number, is the most significant), so +that [3, 1, 1] > [3, 1, 0] and [3, 1, 1] > [2, 1, 4]. The ordering +on parts can be extended to an ordering on partitions: First, sort +the parts in each partition, left-to-right in decreasing order. Then +partition A is greater than partition B if A's leftmost/greatest +part is greater than B's leftmost part. If the leftmost parts are +equal, compare the second parts, and so on. + +In this ordering, the greatest partition of a given multiset has only +one part. The least partition is the one in which the components +are spread out, one per part. + +The enumeration algorithms in this file yield the partitions of the +argument multiset in decreasing order. The main data structure is a +stack of parts, corresponding to the current partition. An +important invariant is that the parts on the stack are themselves in +decreasing order. This data structure is decremented to find the +next smaller partition. Most often, decrementing the partition will +only involve adjustments to the smallest parts at the top of the +stack, much as adjacent integers *usually* differ only in their last +few digits. + +Knuth's algorithm uses two main operations on parts: + +Decrement - change the part so that it is smaller in the + (vector) lexicographic order, but reduced by the smallest amount possible. + For example, if the multiset has vector [5, + 3, 1], and the bottom/greatest part is [4, 2, 1], this part would + decrement to [4, 2, 0], while [4, 0, 0] would decrement to [3, 3, + 1]. A singleton part is never decremented -- [1, 0, 0] is not + decremented to [0, 3, 1]. Instead, the decrement operator needs + to fail for this case. In Knuth's pseudocode, the decrement + operator is step m5. + +Spread unallocated multiplicity - Once a part has been decremented, + it cannot be the rightmost part in the partition. There is some + multiplicity that has not been allocated, and new parts must be + created above it in the stack to use up this multiplicity. To + maintain the invariant that the parts on the stack are in + decreasing order, these new parts must be less than or equal to + the decremented part. + For example, if the multiset is [5, 3, 1], and its most + significant part has just been decremented to [5, 3, 0], the + spread operation will add a new part so that the stack becomes + [[5, 3, 0], [0, 0, 1]]. If the most significant part (for the + same multiset) has been decremented to [2, 0, 0] the stack becomes + [[2, 0, 0], [2, 0, 0], [1, 3, 1]]. In the pseudocode, the spread + operation for one part is step m2. The complete spread operation + is a loop of steps m2 and m3. + +In order to facilitate the spread operation, Knuth stores, for each +component of each part, not just the multiplicity of that component +in the part, but also the total multiplicity available for this +component in this part or any lesser part above it on the stack. + +One added twist is that Knuth does not represent the part vectors as +arrays. Instead, he uses a sparse representation, in which a +component of a part is represented as a component number (c), plus +the multiplicity of the component in that part (v) as well as the +total multiplicity available for that component (u). This saves +time that would be spent skipping over zeros. + +""" + +class PartComponent: + """Internal class used in support of the multiset partitions + enumerators and the associated visitor functions. + + Represents one component of one part of the current partition. + + A stack of these, plus an auxiliary frame array, f, represents a + partition of the multiset. + + Knuth's pseudocode makes c, u, and v separate arrays. + """ + + __slots__ = ('c', 'u', 'v') + + def __init__(self): + self.c = 0 # Component number + self.u = 0 # The as yet unpartitioned amount in component c + # *before* it is allocated by this triple + self.v = 0 # Amount of c component in the current part + # (v<=u). An invariant of the representation is + # that the next higher triple for this component + # (if there is one) will have a value of u-v in + # its u attribute. + + def __repr__(self): + "for debug/algorithm animation purposes" + return 'c:%d u:%d v:%d' % (self.c, self.u, self.v) + + def __eq__(self, other): + """Define value oriented equality, which is useful for testers""" + return (isinstance(other, self.__class__) and + self.c == other.c and + self.u == other.u and + self.v == other.v) + + def __ne__(self, other): + """Defined for consistency with __eq__""" + return not self == other + + +# This function tries to be a faithful implementation of algorithm +# 7.1.2.5M in Volume 4A, Combinatoral Algorithms, Part 1, of The Art +# of Computer Programming, by Donald Knuth. This includes using +# (mostly) the same variable names, etc. This makes for rather +# low-level Python. + +# Changes from Knuth's pseudocode include +# - use PartComponent struct/object instead of 3 arrays +# - make the function a generator +# - map (with some difficulty) the GOTOs to Python control structures. +# - Knuth uses 1-based numbering for components, this code is 0-based +# - renamed variable l to lpart. +# - flag variable x takes on values True/False instead of 1/0 +# +def multiset_partitions_taocp(multiplicities): + """Enumerates partitions of a multiset. + + Parameters + ========== + + multiplicities + list of integer multiplicities of the components of the multiset. + + Yields + ====== + + state + Internal data structure which encodes a particular partition. + This output is then usually processed by a visitor function + which combines the information from this data structure with + the components themselves to produce an actual partition. + + Unless they wish to create their own visitor function, users will + have little need to look inside this data structure. But, for + reference, it is a 3-element list with components: + + f + is a frame array, which is used to divide pstack into parts. + + lpart + points to the base of the topmost part. + + pstack + is an array of PartComponent objects. + + The ``state`` output offers a peek into the internal data + structures of the enumeration function. The client should + treat this as read-only; any modification of the data + structure will cause unpredictable (and almost certainly + incorrect) results. Also, the components of ``state`` are + modified in place at each iteration. Hence, the visitor must + be called at each loop iteration. Accumulating the ``state`` + instances and processing them later will not work. + + Examples + ======== + + >>> from sympy.utilities.enumerative import list_visitor + >>> from sympy.utilities.enumerative import multiset_partitions_taocp + >>> # variables components and multiplicities represent the multiset 'abb' + >>> components = 'ab' + >>> multiplicities = [1, 2] + >>> states = multiset_partitions_taocp(multiplicities) + >>> list(list_visitor(state, components) for state in states) + [[['a', 'b', 'b']], + [['a', 'b'], ['b']], + [['a'], ['b', 'b']], + [['a'], ['b'], ['b']]] + + See Also + ======== + + sympy.utilities.iterables.multiset_partitions: Takes a multiset + as input and directly yields multiset partitions. It + dispatches to a number of functions, including this one, for + implementation. Most users will find it more convenient to + use than multiset_partitions_taocp. + + """ + + # Important variables. + # m is the number of components, i.e., number of distinct elements + m = len(multiplicities) + # n is the cardinality, total number of elements whether or not distinct + n = sum(multiplicities) + + # The main data structure, f segments pstack into parts. See + # list_visitor() for example code indicating how this internal + # state corresponds to a partition. + + # Note: allocation of space for stack is conservative. Knuth's + # exercise 7.2.1.5.68 gives some indication of how to tighten this + # bound, but this is not implemented. + pstack = [PartComponent() for i in range(n * m + 1)] + f = [0] * (n + 1) + + # Step M1 in Knuth (Initialize) + # Initial state - entire multiset in one part. + for j in range(m): + ps = pstack[j] + ps.c = j + ps.u = multiplicities[j] + ps.v = multiplicities[j] + + # Other variables + f[0] = 0 + a = 0 + lpart = 0 + f[1] = m + b = m # in general, current stack frame is from a to b - 1 + + while True: + while True: + # Step M2 (Subtract v from u) + k = b + x = False + for j in range(a, b): + pstack[k].u = pstack[j].u - pstack[j].v + if pstack[k].u == 0: + x = True + elif not x: + pstack[k].c = pstack[j].c + pstack[k].v = min(pstack[j].v, pstack[k].u) + x = pstack[k].u < pstack[j].v + k = k + 1 + else: # x is True + pstack[k].c = pstack[j].c + pstack[k].v = pstack[k].u + k = k + 1 + # Note: x is True iff v has changed + + # Step M3 (Push if nonzero.) + if k > b: + a = b + b = k + lpart = lpart + 1 + f[lpart + 1] = b + # Return to M2 + else: + break # Continue to M4 + + # M4 Visit a partition + state = [f, lpart, pstack] + yield state + + # M5 (Decrease v) + while True: + j = b-1 + while (pstack[j].v == 0): + j = j - 1 + if j == a and pstack[j].v == 1: + # M6 (Backtrack) + if lpart == 0: + return + lpart = lpart - 1 + b = a + a = f[lpart] + # Return to M5 + else: + pstack[j].v = pstack[j].v - 1 + for k in range(j + 1, b): + pstack[k].v = pstack[k].u + break # GOTO M2 + +# --------------- Visitor functions for multiset partitions --------------- +# A visitor takes the partition state generated by +# multiset_partitions_taocp or other enumerator, and produces useful +# output (such as the actual partition). + + +def factoring_visitor(state, primes): + """Use with multiset_partitions_taocp to enumerate the ways a + number can be expressed as a product of factors. For this usage, + the exponents of the prime factors of a number are arguments to + the partition enumerator, while the corresponding prime factors + are input here. + + Examples + ======== + + To enumerate the factorings of a number we can think of the elements of the + partition as being the prime factors and the multiplicities as being their + exponents. + + >>> from sympy.utilities.enumerative import factoring_visitor + >>> from sympy.utilities.enumerative import multiset_partitions_taocp + >>> from sympy import factorint + >>> primes, multiplicities = zip(*factorint(24).items()) + >>> primes + (2, 3) + >>> multiplicities + (3, 1) + >>> states = multiset_partitions_taocp(multiplicities) + >>> list(factoring_visitor(state, primes) for state in states) + [[24], [8, 3], [12, 2], [4, 6], [4, 2, 3], [6, 2, 2], [2, 2, 2, 3]] + """ + f, lpart, pstack = state + factoring = [] + for i in range(lpart + 1): + factor = 1 + for ps in pstack[f[i]: f[i + 1]]: + if ps.v > 0: + factor *= primes[ps.c] ** ps.v + factoring.append(factor) + return factoring + + +def list_visitor(state, components): + """Return a list of lists to represent the partition. + + Examples + ======== + + >>> from sympy.utilities.enumerative import list_visitor + >>> from sympy.utilities.enumerative import multiset_partitions_taocp + >>> states = multiset_partitions_taocp([1, 2, 1]) + >>> s = next(states) + >>> list_visitor(s, 'abc') # for multiset 'a b b c' + [['a', 'b', 'b', 'c']] + >>> s = next(states) + >>> list_visitor(s, [1, 2, 3]) # for multiset '1 2 2 3 + [[1, 2, 2], [3]] + """ + f, lpart, pstack = state + + partition = [] + for i in range(lpart+1): + part = [] + for ps in pstack[f[i]:f[i+1]]: + if ps.v > 0: + part.extend([components[ps.c]] * ps.v) + partition.append(part) + + return partition + + +class MultisetPartitionTraverser(): + """ + Has methods to ``enumerate`` and ``count`` the partitions of a multiset. + + This implements a refactored and extended version of Knuth's algorithm + 7.1.2.5M [AOCP]_." + + The enumeration methods of this class are generators and return + data structures which can be interpreted by the same visitor + functions used for the output of ``multiset_partitions_taocp``. + + Examples + ======== + + >>> from sympy.utilities.enumerative import MultisetPartitionTraverser + >>> m = MultisetPartitionTraverser() + >>> m.count_partitions([4,4,4,2]) + 127750 + >>> m.count_partitions([3,3,3]) + 686 + + See Also + ======== + + multiset_partitions_taocp + sympy.utilities.iterables.multiset_partitions + + References + ========== + + .. [AOCP] Algorithm 7.1.2.5M in Volume 4A, Combinatoral Algorithms, + Part 1, of The Art of Computer Programming, by Donald Knuth. + + .. [Factorisatio] On a Problem of Oppenheim concerning + "Factorisatio Numerorum" E. R. Canfield, Paul Erdos, Carl + Pomerance, JOURNAL OF NUMBER THEORY, Vol. 17, No. 1. August + 1983. See section 7 for a description of an algorithm + similar to Knuth's. + + .. [Yorgey] Generating Multiset Partitions, Brent Yorgey, The + Monad.Reader, Issue 8, September 2007. + + """ + + def __init__(self): + self.debug = False + # TRACING variables. These are useful for gathering + # statistics on the algorithm itself, but have no particular + # benefit to a user of the code. + self.k1 = 0 + self.k2 = 0 + self.p1 = 0 + self.pstack = None + self.f = None + self.lpart = 0 + self.discarded = 0 + # dp_stack is list of lists of (part_key, start_count) pairs + self.dp_stack = [] + + # dp_map is map part_key-> count, where count represents the + # number of multiset which are descendants of a part with this + # key, **or any of its decrements** + + # Thus, when we find a part in the map, we add its count + # value to the running total, cut off the enumeration, and + # backtrack + + if not hasattr(self, 'dp_map'): + self.dp_map = {} + + def db_trace(self, msg): + """Useful for understanding/debugging the algorithms. Not + generally activated in end-user code.""" + if self.debug: + # XXX: animation_visitor is undefined... Clearly this does not + # work and was not tested. Previous code in comments below. + raise RuntimeError + #letters = 'abcdefghijklmnopqrstuvwxyz' + #state = [self.f, self.lpart, self.pstack] + #print("DBG:", msg, + # ["".join(part) for part in list_visitor(state, letters)], + # animation_visitor(state)) + + # + # Helper methods for enumeration + # + def _initialize_enumeration(self, multiplicities): + """Allocates and initializes the partition stack. + + This is called from the enumeration/counting routines, so + there is no need to call it separately.""" + + num_components = len(multiplicities) + # cardinality is the total number of elements, whether or not distinct + cardinality = sum(multiplicities) + + # pstack is the partition stack, which is segmented by + # f into parts. + self.pstack = [PartComponent() for i in + range(num_components * cardinality + 1)] + self.f = [0] * (cardinality + 1) + + # Initial state - entire multiset in one part. + for j in range(num_components): + ps = self.pstack[j] + ps.c = j + ps.u = multiplicities[j] + ps.v = multiplicities[j] + + self.f[0] = 0 + self.f[1] = num_components + self.lpart = 0 + + # The decrement_part() method corresponds to step M5 in Knuth's + # algorithm. This is the base version for enum_all(). Modified + # versions of this method are needed if we want to restrict + # sizes of the partitions produced. + def decrement_part(self, part): + """Decrements part (a subrange of pstack), if possible, returning + True iff the part was successfully decremented. + + If you think of the v values in the part as a multi-digit + integer (least significant digit on the right) this is + basically decrementing that integer, but with the extra + constraint that the leftmost digit cannot be decremented to 0. + + Parameters + ========== + + part + The part, represented as a list of PartComponent objects, + which is to be decremented. + + """ + plen = len(part) + for j in range(plen - 1, -1, -1): + if j == 0 and part[j].v > 1 or j > 0 and part[j].v > 0: + # found val to decrement + part[j].v -= 1 + # Reset trailing parts back to maximum + for k in range(j + 1, plen): + part[k].v = part[k].u + return True + return False + + # Version to allow number of parts to be bounded from above. + # Corresponds to (a modified) step M5. + def decrement_part_small(self, part, ub): + """Decrements part (a subrange of pstack), if possible, returning + True iff the part was successfully decremented. + + Parameters + ========== + + part + part to be decremented (topmost part on the stack) + + ub + the maximum number of parts allowed in a partition + returned by the calling traversal. + + Notes + ===== + + The goal of this modification of the ordinary decrement method + is to fail (meaning that the subtree rooted at this part is to + be skipped) when it can be proved that this part can only have + child partitions which are larger than allowed by ``ub``. If a + decision is made to fail, it must be accurate, otherwise the + enumeration will miss some partitions. But, it is OK not to + capture all the possible failures -- if a part is passed that + should not be, the resulting too-large partitions are filtered + by the enumeration one level up. However, as is usual in + constrained enumerations, failing early is advantageous. + + The tests used by this method catch the most common cases, + although this implementation is by no means the last word on + this problem. The tests include: + + 1) ``lpart`` must be less than ``ub`` by at least 2. This is because + once a part has been decremented, the partition + will gain at least one child in the spread step. + + 2) If the leading component of the part is about to be + decremented, check for how many parts will be added in + order to use up the unallocated multiplicity in that + leading component, and fail if this number is greater than + allowed by ``ub``. (See code for the exact expression.) This + test is given in the answer to Knuth's problem 7.2.1.5.69. + + 3) If there is *exactly* enough room to expand the leading + component by the above test, check the next component (if + it exists) once decrementing has finished. If this has + ``v == 0``, this next component will push the expansion over the + limit by 1, so fail. + """ + if self.lpart >= ub - 1: + self.p1 += 1 # increment to keep track of usefulness of tests + return False + plen = len(part) + for j in range(plen - 1, -1, -1): + # Knuth's mod, (answer to problem 7.2.1.5.69) + if j == 0 and (part[0].v - 1)*(ub - self.lpart) < part[0].u: + self.k1 += 1 + return False + + if j == 0 and part[j].v > 1 or j > 0 and part[j].v > 0: + # found val to decrement + part[j].v -= 1 + # Reset trailing parts back to maximum + for k in range(j + 1, plen): + part[k].v = part[k].u + + # Have now decremented part, but are we doomed to + # failure when it is expanded? Check one oddball case + # that turns out to be surprisingly common - exactly + # enough room to expand the leading component, but no + # room for the second component, which has v=0. + if (plen > 1 and part[1].v == 0 and + (part[0].u - part[0].v) == + ((ub - self.lpart - 1) * part[0].v)): + self.k2 += 1 + self.db_trace("Decrement fails test 3") + return False + return True + return False + + def decrement_part_large(self, part, amt, lb): + """Decrements part, while respecting size constraint. + + A part can have no children which are of sufficient size (as + indicated by ``lb``) unless that part has sufficient + unallocated multiplicity. When enforcing the size constraint, + this method will decrement the part (if necessary) by an + amount needed to ensure sufficient unallocated multiplicity. + + Returns True iff the part was successfully decremented. + + Parameters + ========== + + part + part to be decremented (topmost part on the stack) + + amt + Can only take values 0 or 1. A value of 1 means that the + part must be decremented, and then the size constraint is + enforced. A value of 0 means just to enforce the ``lb`` + size constraint. + + lb + The partitions produced by the calling enumeration must + have more parts than this value. + + """ + + if amt == 1: + # In this case we always need to decrement, *before* + # enforcing the "sufficient unallocated multiplicity" + # constraint. Easiest for this is just to call the + # regular decrement method. + if not self.decrement_part(part): + return False + + # Next, perform any needed additional decrementing to respect + # "sufficient unallocated multiplicity" (or fail if this is + # not possible). + min_unalloc = lb - self.lpart + if min_unalloc <= 0: + return True + total_mult = sum(pc.u for pc in part) + total_alloc = sum(pc.v for pc in part) + if total_mult <= min_unalloc: + return False + + deficit = min_unalloc - (total_mult - total_alloc) + if deficit <= 0: + return True + + for i in range(len(part) - 1, -1, -1): + if i == 0: + if part[0].v > deficit: + part[0].v -= deficit + return True + else: + return False # This shouldn't happen, due to above check + else: + if part[i].v >= deficit: + part[i].v -= deficit + return True + else: + deficit -= part[i].v + part[i].v = 0 + + def decrement_part_range(self, part, lb, ub): + """Decrements part (a subrange of pstack), if possible, returning + True iff the part was successfully decremented. + + Parameters + ========== + + part + part to be decremented (topmost part on the stack) + + ub + the maximum number of parts allowed in a partition + returned by the calling traversal. + + lb + The partitions produced by the calling enumeration must + have more parts than this value. + + Notes + ===== + + Combines the constraints of _small and _large decrement + methods. If returns success, part has been decremented at + least once, but perhaps by quite a bit more if needed to meet + the lb constraint. + """ + + # Constraint in the range case is just enforcing both the + # constraints from _small and _large cases. Note the 0 as the + # second argument to the _large call -- this is the signal to + # decrement only as needed to for constraint enforcement. The + # short circuiting and left-to-right order of the 'and' + # operator is important for this to work correctly. + return self.decrement_part_small(part, ub) and \ + self.decrement_part_large(part, 0, lb) + + def spread_part_multiplicity(self): + """Returns True if a new part has been created, and + adjusts pstack, f and lpart as needed. + + Notes + ===== + + Spreads unallocated multiplicity from the current top part + into a new part created above the current on the stack. This + new part is constrained to be less than or equal to the old in + terms of the part ordering. + + This call does nothing (and returns False) if the current top + part has no unallocated multiplicity. + + """ + j = self.f[self.lpart] # base of current top part + k = self.f[self.lpart + 1] # ub of current; potential base of next + base = k # save for later comparison + + changed = False # Set to true when the new part (so far) is + # strictly less than (as opposed to less than + # or equal) to the old. + for j in range(self.f[self.lpart], self.f[self.lpart + 1]): + self.pstack[k].u = self.pstack[j].u - self.pstack[j].v + if self.pstack[k].u == 0: + changed = True + else: + self.pstack[k].c = self.pstack[j].c + if changed: # Put all available multiplicity in this part + self.pstack[k].v = self.pstack[k].u + else: # Still maintaining ordering constraint + if self.pstack[k].u < self.pstack[j].v: + self.pstack[k].v = self.pstack[k].u + changed = True + else: + self.pstack[k].v = self.pstack[j].v + k = k + 1 + if k > base: + # Adjust for the new part on stack + self.lpart = self.lpart + 1 + self.f[self.lpart + 1] = k + return True + return False + + def top_part(self): + """Return current top part on the stack, as a slice of pstack. + + """ + return self.pstack[self.f[self.lpart]:self.f[self.lpart + 1]] + + # Same interface and functionality as multiset_partitions_taocp(), + # but some might find this refactored version easier to follow. + def enum_all(self, multiplicities): + """Enumerate the partitions of a multiset. + + Examples + ======== + + >>> from sympy.utilities.enumerative import list_visitor + >>> from sympy.utilities.enumerative import MultisetPartitionTraverser + >>> m = MultisetPartitionTraverser() + >>> states = m.enum_all([2,2]) + >>> list(list_visitor(state, 'ab') for state in states) + [[['a', 'a', 'b', 'b']], + [['a', 'a', 'b'], ['b']], + [['a', 'a'], ['b', 'b']], + [['a', 'a'], ['b'], ['b']], + [['a', 'b', 'b'], ['a']], + [['a', 'b'], ['a', 'b']], + [['a', 'b'], ['a'], ['b']], + [['a'], ['a'], ['b', 'b']], + [['a'], ['a'], ['b'], ['b']]] + + See Also + ======== + + multiset_partitions_taocp: + which provides the same result as this method, but is + about twice as fast. Hence, enum_all is primarily useful + for testing. Also see the function for a discussion of + states and visitors. + + """ + self._initialize_enumeration(multiplicities) + while True: + while self.spread_part_multiplicity(): + pass + + # M4 Visit a partition + state = [self.f, self.lpart, self.pstack] + yield state + + # M5 (Decrease v) + while not self.decrement_part(self.top_part()): + # M6 (Backtrack) + if self.lpart == 0: + return + self.lpart -= 1 + + def enum_small(self, multiplicities, ub): + """Enumerate multiset partitions with no more than ``ub`` parts. + + Equivalent to enum_range(multiplicities, 0, ub) + + Parameters + ========== + + multiplicities + list of multiplicities of the components of the multiset. + + ub + Maximum number of parts + + Examples + ======== + + >>> from sympy.utilities.enumerative import list_visitor + >>> from sympy.utilities.enumerative import MultisetPartitionTraverser + >>> m = MultisetPartitionTraverser() + >>> states = m.enum_small([2,2], 2) + >>> list(list_visitor(state, 'ab') for state in states) + [[['a', 'a', 'b', 'b']], + [['a', 'a', 'b'], ['b']], + [['a', 'a'], ['b', 'b']], + [['a', 'b', 'b'], ['a']], + [['a', 'b'], ['a', 'b']]] + + The implementation is based, in part, on the answer given to + exercise 69, in Knuth [AOCP]_. + + See Also + ======== + + enum_all, enum_large, enum_range + + """ + + # Keep track of iterations which do not yield a partition. + # Clearly, we would like to keep this number small. + self.discarded = 0 + if ub <= 0: + return + self._initialize_enumeration(multiplicities) + while True: + while self.spread_part_multiplicity(): + self.db_trace('spread 1') + if self.lpart >= ub: + self.discarded += 1 + self.db_trace(' Discarding') + self.lpart = ub - 2 + break + else: + # M4 Visit a partition + state = [self.f, self.lpart, self.pstack] + yield state + + # M5 (Decrease v) + while not self.decrement_part_small(self.top_part(), ub): + self.db_trace("Failed decrement, going to backtrack") + # M6 (Backtrack) + if self.lpart == 0: + return + self.lpart -= 1 + self.db_trace("Backtracked to") + self.db_trace("decrement ok, about to expand") + + def enum_large(self, multiplicities, lb): + """Enumerate the partitions of a multiset with lb < num(parts) + + Equivalent to enum_range(multiplicities, lb, sum(multiplicities)) + + Parameters + ========== + + multiplicities + list of multiplicities of the components of the multiset. + + lb + Number of parts in the partition must be greater than + this lower bound. + + + Examples + ======== + + >>> from sympy.utilities.enumerative import list_visitor + >>> from sympy.utilities.enumerative import MultisetPartitionTraverser + >>> m = MultisetPartitionTraverser() + >>> states = m.enum_large([2,2], 2) + >>> list(list_visitor(state, 'ab') for state in states) + [[['a', 'a'], ['b'], ['b']], + [['a', 'b'], ['a'], ['b']], + [['a'], ['a'], ['b', 'b']], + [['a'], ['a'], ['b'], ['b']]] + + See Also + ======== + + enum_all, enum_small, enum_range + + """ + self.discarded = 0 + if lb >= sum(multiplicities): + return + self._initialize_enumeration(multiplicities) + self.decrement_part_large(self.top_part(), 0, lb) + while True: + good_partition = True + while self.spread_part_multiplicity(): + if not self.decrement_part_large(self.top_part(), 0, lb): + # Failure here should be rare/impossible + self.discarded += 1 + good_partition = False + break + + # M4 Visit a partition + if good_partition: + state = [self.f, self.lpart, self.pstack] + yield state + + # M5 (Decrease v) + while not self.decrement_part_large(self.top_part(), 1, lb): + # M6 (Backtrack) + if self.lpart == 0: + return + self.lpart -= 1 + + def enum_range(self, multiplicities, lb, ub): + + """Enumerate the partitions of a multiset with + ``lb < num(parts) <= ub``. + + In particular, if partitions with exactly ``k`` parts are + desired, call with ``(multiplicities, k - 1, k)``. This + method generalizes enum_all, enum_small, and enum_large. + + Examples + ======== + + >>> from sympy.utilities.enumerative import list_visitor + >>> from sympy.utilities.enumerative import MultisetPartitionTraverser + >>> m = MultisetPartitionTraverser() + >>> states = m.enum_range([2,2], 1, 2) + >>> list(list_visitor(state, 'ab') for state in states) + [[['a', 'a', 'b'], ['b']], + [['a', 'a'], ['b', 'b']], + [['a', 'b', 'b'], ['a']], + [['a', 'b'], ['a', 'b']]] + + """ + # combine the constraints of the _large and _small + # enumerations. + self.discarded = 0 + if ub <= 0 or lb >= sum(multiplicities): + return + self._initialize_enumeration(multiplicities) + self.decrement_part_large(self.top_part(), 0, lb) + while True: + good_partition = True + while self.spread_part_multiplicity(): + self.db_trace("spread 1") + if not self.decrement_part_large(self.top_part(), 0, lb): + # Failure here - possible in range case? + self.db_trace(" Discarding (large cons)") + self.discarded += 1 + good_partition = False + break + elif self.lpart >= ub: + self.discarded += 1 + good_partition = False + self.db_trace(" Discarding small cons") + self.lpart = ub - 2 + break + + # M4 Visit a partition + if good_partition: + state = [self.f, self.lpart, self.pstack] + yield state + + # M5 (Decrease v) + while not self.decrement_part_range(self.top_part(), lb, ub): + self.db_trace("Failed decrement, going to backtrack") + # M6 (Backtrack) + if self.lpart == 0: + return + self.lpart -= 1 + self.db_trace("Backtracked to") + self.db_trace("decrement ok, about to expand") + + def count_partitions_slow(self, multiplicities): + """Returns the number of partitions of a multiset whose elements + have the multiplicities given in ``multiplicities``. + + Primarily for comparison purposes. It follows the same path as + enumerate, and counts, rather than generates, the partitions. + + See Also + ======== + + count_partitions + Has the same calling interface, but is much faster. + + """ + # number of partitions so far in the enumeration + self.pcount = 0 + self._initialize_enumeration(multiplicities) + while True: + while self.spread_part_multiplicity(): + pass + + # M4 Visit (count) a partition + self.pcount += 1 + + # M5 (Decrease v) + while not self.decrement_part(self.top_part()): + # M6 (Backtrack) + if self.lpart == 0: + return self.pcount + self.lpart -= 1 + + def count_partitions(self, multiplicities): + """Returns the number of partitions of a multiset whose components + have the multiplicities given in ``multiplicities``. + + For larger counts, this method is much faster than calling one + of the enumerators and counting the result. Uses dynamic + programming to cut down on the number of nodes actually + explored. The dictionary used in order to accelerate the + counting process is stored in the ``MultisetPartitionTraverser`` + object and persists across calls. If the user does not + expect to call ``count_partitions`` for any additional + multisets, the object should be cleared to save memory. On + the other hand, the cache built up from one count run can + significantly speed up subsequent calls to ``count_partitions``, + so it may be advantageous not to clear the object. + + Examples + ======== + + >>> from sympy.utilities.enumerative import MultisetPartitionTraverser + >>> m = MultisetPartitionTraverser() + >>> m.count_partitions([9,8,2]) + 288716 + >>> m.count_partitions([2,2]) + 9 + >>> del m + + Notes + ===== + + If one looks at the workings of Knuth's algorithm M [AOCP]_, it + can be viewed as a traversal of a binary tree of parts. A + part has (up to) two children, the left child resulting from + the spread operation, and the right child from the decrement + operation. The ordinary enumeration of multiset partitions is + an in-order traversal of this tree, and with the partitions + corresponding to paths from the root to the leaves. The + mapping from paths to partitions is a little complicated, + since the partition would contain only those parts which are + leaves or the parents of a spread link, not those which are + parents of a decrement link. + + For counting purposes, it is sufficient to count leaves, and + this can be done with a recursive in-order traversal. The + number of leaves of a subtree rooted at a particular part is a + function only of that part itself, so memoizing has the + potential to speed up the counting dramatically. + + This method follows a computational approach which is similar + to the hypothetical memoized recursive function, but with two + differences: + + 1) This method is iterative, borrowing its structure from the + other enumerations and maintaining an explicit stack of + parts which are in the process of being counted. (There + may be multisets which can be counted reasonably quickly by + this implementation, but which would overflow the default + Python recursion limit with a recursive implementation.) + + 2) Instead of using the part data structure directly, a more + compact key is constructed. This saves space, but more + importantly coalesces some parts which would remain + separate with physical keys. + + Unlike the enumeration functions, there is currently no _range + version of count_partitions. If someone wants to stretch + their brain, it should be possible to construct one by + memoizing with a histogram of counts rather than a single + count, and combining the histograms. + """ + # number of partitions so far in the enumeration + self.pcount = 0 + + # dp_stack is list of lists of (part_key, start_count) pairs + self.dp_stack = [] + + self._initialize_enumeration(multiplicities) + pkey = part_key(self.top_part()) + self.dp_stack.append([(pkey, 0), ]) + while True: + while self.spread_part_multiplicity(): + pkey = part_key(self.top_part()) + if pkey in self.dp_map: + # Already have a cached value for the count of the + # subtree rooted at this part. Add it to the + # running counter, and break out of the spread + # loop. The -1 below is to compensate for the + # leaf that this code path would otherwise find, + # and which gets incremented for below. + + self.pcount += (self.dp_map[pkey] - 1) + self.lpart -= 1 + break + else: + self.dp_stack.append([(pkey, self.pcount), ]) + + # M4 count a leaf partition + self.pcount += 1 + + # M5 (Decrease v) + while not self.decrement_part(self.top_part()): + # M6 (Backtrack) + for key, oldcount in self.dp_stack.pop(): + self.dp_map[key] = self.pcount - oldcount + if self.lpart == 0: + return self.pcount + self.lpart -= 1 + + # At this point have successfully decremented the part on + # the stack and it does not appear in the cache. It needs + # to be added to the list at the top of dp_stack + pkey = part_key(self.top_part()) + self.dp_stack[-1].append((pkey, self.pcount),) + + +def part_key(part): + """Helper for MultisetPartitionTraverser.count_partitions that + creates a key for ``part``, that only includes information which can + affect the count for that part. (Any irrelevant information just + reduces the effectiveness of dynamic programming.) + + Notes + ===== + + This member function is a candidate for future exploration. There + are likely symmetries that can be exploited to coalesce some + ``part_key`` values, and thereby save space and improve + performance. + + """ + # The component number is irrelevant for counting partitions, so + # leave it out of the memo key. + rval = [] + for ps in part: + rval.append(ps.u) + rval.append(ps.v) + return tuple(rval) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/exceptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..f764a31371ed109d69102777bd9ec0dfb3d75380 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/exceptions.py @@ -0,0 +1,271 @@ +""" +General SymPy exceptions and warnings. +""" + +import warnings +import contextlib + +from textwrap import dedent + + +class SymPyDeprecationWarning(DeprecationWarning): + r""" + A warning for deprecated features of SymPy. + + See the :ref:`deprecation-policy` document for details on when and how + things should be deprecated in SymPy. + + Note that simply constructing this class will not cause a warning to be + issued. To do that, you must call the :func`sympy_deprecation_warning` + function. For this reason, it is not recommended to ever construct this + class directly. + + Explanation + =========== + + The ``SymPyDeprecationWarning`` class is a subclass of + ``DeprecationWarning`` that is used for all deprecations in SymPy. A + special subclass is used so that we can automatically augment the warning + message with additional metadata about the version the deprecation was + introduced in and a link to the documentation. This also allows users to + explicitly filter deprecation warnings from SymPy using ``warnings`` + filters (see :ref:`silencing-sympy-deprecation-warnings`). + + Additionally, ``SymPyDeprecationWarning`` is enabled to be shown by + default, unlike normal ``DeprecationWarning``\s, which are only shown by + default in interactive sessions. This ensures that deprecation warnings in + SymPy will actually be seen by users. + + See the documentation of :func:`sympy_deprecation_warning` for a + description of the parameters to this function. + + To mark a function as deprecated, you can use the :func:`@deprecated + ` decorator. + + See Also + ======== + sympy.utilities.exceptions.sympy_deprecation_warning + sympy.utilities.exceptions.ignore_warnings + sympy.utilities.decorator.deprecated + sympy.testing.pytest.warns_deprecated_sympy + + """ + def __init__(self, message, *, deprecated_since_version, active_deprecations_target): + + super().__init__(message, deprecated_since_version, + active_deprecations_target) + self.message = message + if not isinstance(deprecated_since_version, str): + raise TypeError(f"'deprecated_since_version' should be a string, got {deprecated_since_version!r}") + self.deprecated_since_version = deprecated_since_version + self.active_deprecations_target = active_deprecations_target + if any(i in active_deprecations_target for i in '()='): + raise ValueError("active_deprecations_target be the part inside of the '(...)='") + + self.full_message = f""" + +{dedent(message).strip()} + +See https://docs.sympy.org/latest/explanation/active-deprecations.html#{active_deprecations_target} +for details. + +This has been deprecated since SymPy version {deprecated_since_version}. It +will be removed in a future version of SymPy. +""" + + def __str__(self): + return self.full_message + + def __repr__(self): + return f"{self.__class__.__name__}({self.message!r}, deprecated_since_version={self.deprecated_since_version!r}, active_deprecations_target={self.active_deprecations_target!r})" + + def __eq__(self, other): + return isinstance(other, SymPyDeprecationWarning) and self.args == other.args + + # Make pickling work. The by default, it tries to recreate the expression + # from its args, but this doesn't work because of our keyword-only + # arguments. + @classmethod + def _new(cls, message, deprecated_since_version, + active_deprecations_target): + return cls(message, deprecated_since_version=deprecated_since_version, active_deprecations_target=active_deprecations_target) + + def __reduce__(self): + return (self._new, (self.message, self.deprecated_since_version, self.active_deprecations_target)) + +# Python by default hides DeprecationWarnings, which we do not want. +warnings.simplefilter("once", SymPyDeprecationWarning) + +def sympy_deprecation_warning(message, *, deprecated_since_version, + active_deprecations_target, stacklevel=3): + r''' + Warn that a feature is deprecated in SymPy. + + See the :ref:`deprecation-policy` document for details on when and how + things should be deprecated in SymPy. + + To mark an entire function or class as deprecated, you can use the + :func:`@deprecated ` decorator. + + Parameters + ========== + + message : str + The deprecation message. This may span multiple lines and contain + code examples. Messages should be wrapped to 80 characters. The + message is automatically dedented and leading and trailing whitespace + stripped. Messages may include dynamic content based on the user + input, but avoid using ``str(expression)`` if an expression can be + arbitrary, as it might be huge and make the warning message + unreadable. + + deprecated_since_version : str + The version of SymPy the feature has been deprecated since. For new + deprecations, this should be the version in `sympy/release.py + `_ + without the ``.dev``. If the next SymPy version ends up being + different from this, the release manager will need to update any + ``SymPyDeprecationWarning``\s using the incorrect version. This + argument is required and must be passed as a keyword argument. + (example: ``deprecated_since_version="1.10"``). + + active_deprecations_target : str + The Sphinx target corresponding to the section for the deprecation in + the :ref:`active-deprecations` document (see + ``doc/src/explanation/active-deprecations.md``). This is used to + automatically generate a URL to the page in the warning message. This + argument is required and must be passed as a keyword argument. + (example: ``active_deprecations_target="deprecated-feature-abc"``) + + stacklevel : int, default: 3 + The ``stacklevel`` parameter that is passed to ``warnings.warn``. If + you create a wrapper that calls this function, this should be + increased so that the warning message shows the user line of code that + produced the warning. Note that in some cases there will be multiple + possible different user code paths that could result in the warning. + In that case, just choose the smallest common stacklevel. + + Examples + ======== + + >>> from sympy.utilities.exceptions import sympy_deprecation_warning + >>> def is_this_zero(x, y=0): + ... """ + ... Determine if x = 0. + ... + ... Parameters + ... ========== + ... + ... x : Expr + ... The expression to check. + ... + ... y : Expr, optional + ... If provided, check if x = y. + ... + ... .. deprecated:: 1.1 + ... + ... The ``y`` argument to ``is_this_zero`` is deprecated. Use + ... ``is_this_zero(x - y)`` instead. + ... + ... """ + ... from sympy import simplify + ... + ... if y != 0: + ... sympy_deprecation_warning(""" + ... The y argument to is_zero() is deprecated. Use is_zero(x - y) instead.""", + ... deprecated_since_version="1.1", + ... active_deprecations_target='is-this-zero-y-deprecation') + ... return simplify(x - y) == 0 + >>> is_this_zero(0) + True + >>> is_this_zero(1, 1) # doctest: +SKIP + :1: SymPyDeprecationWarning: + + The y argument to is_zero() is deprecated. Use is_zero(x - y) instead. + + See https://docs.sympy.org/latest/explanation/active-deprecations.html#is-this-zero-y-deprecation + for details. + + This has been deprecated since SymPy version 1.1. It + will be removed in a future version of SymPy. + + is_this_zero(1, 1) + True + + See Also + ======== + + sympy.utilities.exceptions.SymPyDeprecationWarning + sympy.utilities.exceptions.ignore_warnings + sympy.utilities.decorator.deprecated + sympy.testing.pytest.warns_deprecated_sympy + + ''' + w = SymPyDeprecationWarning(message, + deprecated_since_version=deprecated_since_version, + active_deprecations_target=active_deprecations_target) + warnings.warn(w, stacklevel=stacklevel) + + +@contextlib.contextmanager +def ignore_warnings(warningcls): + ''' + Context manager to suppress warnings during tests. + + .. note:: + + Do not use this with SymPyDeprecationWarning in the tests. + warns_deprecated_sympy() should be used instead. + + This function is useful for suppressing warnings during tests. The warns + function should be used to assert that a warning is raised. The + ignore_warnings function is useful in situation when the warning is not + guaranteed to be raised (e.g. on importing a module) or if the warning + comes from third-party code. + + This function is also useful to prevent the same or similar warnings from + being issue twice due to recursive calls. + + When the warning is coming (reliably) from SymPy the warns function should + be preferred to ignore_warnings. + + >>> from sympy.utilities.exceptions import ignore_warnings + >>> import warnings + + Here's a warning: + + >>> with warnings.catch_warnings(): # reset warnings in doctest + ... warnings.simplefilter('error') + ... warnings.warn('deprecated', UserWarning) + Traceback (most recent call last): + ... + UserWarning: deprecated + + Let's suppress it with ignore_warnings: + + >>> with warnings.catch_warnings(): # reset warnings in doctest + ... warnings.simplefilter('error') + ... with ignore_warnings(UserWarning): + ... warnings.warn('deprecated', UserWarning) + + (No warning emitted) + + See Also + ======== + sympy.utilities.exceptions.SymPyDeprecationWarning + sympy.utilities.exceptions.sympy_deprecation_warning + sympy.utilities.decorator.deprecated + sympy.testing.pytest.warns_deprecated_sympy + + ''' + # Absorbs all warnings in warnrec + with warnings.catch_warnings(record=True) as warnrec: + # Make sure our warning doesn't get filtered + warnings.simplefilter("always", warningcls) + # Now run the test + yield + + # Reissue any warnings that we aren't testing for + for w in warnrec: + if not issubclass(w.category, warningcls): + warnings.warn_explicit(w.message, w.category, w.filename, w.lineno) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/iterables.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/iterables.py new file mode 100644 index 0000000000000000000000000000000000000000..cc5c1152f03b10f62f9dd04c842b6fc74b0b9242 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/iterables.py @@ -0,0 +1,3179 @@ +from collections import Counter, defaultdict, OrderedDict +from itertools import ( + chain, combinations, combinations_with_replacement, cycle, islice, + permutations, product, groupby +) +# For backwards compatibility +from itertools import product as cartes # noqa: F401 +from operator import gt + + + +# this is the logical location of these functions +from sympy.utilities.enumerative import ( + multiset_partitions_taocp, list_visitor, MultisetPartitionTraverser) + +from sympy.utilities.misc import as_int +from sympy.utilities.decorator import deprecated + + +def is_palindromic(s, i=0, j=None): + """ + Return True if the sequence is the same from left to right as it + is from right to left in the whole sequence (default) or in the + Python slice ``s[i: j]``; else False. + + Examples + ======== + + >>> from sympy.utilities.iterables import is_palindromic + >>> is_palindromic([1, 0, 1]) + True + >>> is_palindromic('abcbb') + False + >>> is_palindromic('abcbb', 1) + False + + Normal Python slicing is performed in place so there is no need to + create a slice of the sequence for testing: + + >>> is_palindromic('abcbb', 1, -1) + True + >>> is_palindromic('abcbb', -4, -1) + True + + See Also + ======== + + sympy.ntheory.digits.is_palindromic: tests integers + + """ + i, j, _ = slice(i, j).indices(len(s)) + m = (j - i)//2 + # if length is odd, middle element will be ignored + return all(s[i + k] == s[j - 1 - k] for k in range(m)) + + +def flatten(iterable, levels=None, cls=None): # noqa: F811 + """ + Recursively denest iterable containers. + + >>> from sympy import flatten + + >>> flatten([1, 2, 3]) + [1, 2, 3] + >>> flatten([1, 2, [3]]) + [1, 2, 3] + >>> flatten([1, [2, 3], [4, 5]]) + [1, 2, 3, 4, 5] + >>> flatten([1.0, 2, (1, None)]) + [1.0, 2, 1, None] + + If you want to denest only a specified number of levels of + nested containers, then set ``levels`` flag to the desired + number of levels:: + + >>> ls = [[(-2, -1), (1, 2)], [(0, 0)]] + + >>> flatten(ls, levels=1) + [(-2, -1), (1, 2), (0, 0)] + + If cls argument is specified, it will only flatten instances of that + class, for example: + + >>> from sympy import Basic, S + >>> class MyOp(Basic): + ... pass + ... + >>> flatten([MyOp(S(1), MyOp(S(2), S(3)))], cls=MyOp) + [1, 2, 3] + + adapted from https://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks + """ + from sympy.tensor.array import NDimArray + if levels is not None: + if not levels: + return iterable + elif levels > 0: + levels -= 1 + else: + raise ValueError( + "expected non-negative number of levels, got %s" % levels) + + if cls is None: + def reducible(x): + return is_sequence(x, set) + else: + def reducible(x): + return isinstance(x, cls) + + result = [] + + for el in iterable: + if reducible(el): + if hasattr(el, 'args') and not isinstance(el, NDimArray): + el = el.args + result.extend(flatten(el, levels=levels, cls=cls)) + else: + result.append(el) + + return result + + +def unflatten(iter, n=2): + """Group ``iter`` into tuples of length ``n``. Raise an error if + the length of ``iter`` is not a multiple of ``n``. + """ + if n < 1 or len(iter) % n: + raise ValueError('iter length is not a multiple of %i' % n) + return list(zip(*(iter[i::n] for i in range(n)))) + + +def reshape(seq, how): + """Reshape the sequence according to the template in ``how``. + + Examples + ======== + + >>> from sympy.utilities import reshape + >>> seq = list(range(1, 9)) + + >>> reshape(seq, [4]) # lists of 4 + [[1, 2, 3, 4], [5, 6, 7, 8]] + + >>> reshape(seq, (4,)) # tuples of 4 + [(1, 2, 3, 4), (5, 6, 7, 8)] + + >>> reshape(seq, (2, 2)) # tuples of 4 + [(1, 2, 3, 4), (5, 6, 7, 8)] + + >>> reshape(seq, (2, [2])) # (i, i, [i, i]) + [(1, 2, [3, 4]), (5, 6, [7, 8])] + + >>> reshape(seq, ((2,), [2])) # etc.... + [((1, 2), [3, 4]), ((5, 6), [7, 8])] + + >>> reshape(seq, (1, [2], 1)) + [(1, [2, 3], 4), (5, [6, 7], 8)] + + >>> reshape(tuple(seq), ([[1], 1, (2,)],)) + (([[1], 2, (3, 4)],), ([[5], 6, (7, 8)],)) + + >>> reshape(tuple(seq), ([1], 1, (2,))) + (([1], 2, (3, 4)), ([5], 6, (7, 8))) + + >>> reshape(list(range(12)), [2, [3], {2}, (1, (3,), 1)]) + [[0, 1, [2, 3, 4], {5, 6}, (7, (8, 9, 10), 11)]] + + """ + m = sum(flatten(how)) + n, rem = divmod(len(seq), m) + if m < 0 or rem: + raise ValueError('template must sum to positive number ' + 'that divides the length of the sequence') + i = 0 + container = type(how) + rv = [None]*n + for k in range(len(rv)): + _rv = [] + for hi in how: + if isinstance(hi, int): + _rv.extend(seq[i: i + hi]) + i += hi + else: + n = sum(flatten(hi)) + hi_type = type(hi) + _rv.append(hi_type(reshape(seq[i: i + n], hi)[0])) + i += n + rv[k] = container(_rv) + return type(seq)(rv) + + +def group(seq, multiple=True): + """ + Splits a sequence into a list of lists of equal, adjacent elements. + + Examples + ======== + + >>> from sympy import group + + >>> group([1, 1, 1, 2, 2, 3]) + [[1, 1, 1], [2, 2], [3]] + >>> group([1, 1, 1, 2, 2, 3], multiple=False) + [(1, 3), (2, 2), (3, 1)] + >>> group([1, 1, 3, 2, 2, 1], multiple=False) + [(1, 2), (3, 1), (2, 2), (1, 1)] + + See Also + ======== + + multiset + + """ + if multiple: + return [(list(g)) for _, g in groupby(seq)] + return [(k, len(list(g))) for k, g in groupby(seq)] + + +def _iproduct2(iterable1, iterable2): + '''Cartesian product of two possibly infinite iterables''' + + it1 = iter(iterable1) + it2 = iter(iterable2) + + elems1 = [] + elems2 = [] + + sentinel = object() + def append(it, elems): + e = next(it, sentinel) + if e is not sentinel: + elems.append(e) + + n = 0 + append(it1, elems1) + append(it2, elems2) + + while n <= len(elems1) + len(elems2): + for m in range(n-len(elems1)+1, len(elems2)): + yield (elems1[n-m], elems2[m]) + n += 1 + append(it1, elems1) + append(it2, elems2) + + +def iproduct(*iterables): + ''' + Cartesian product of iterables. + + Generator of the Cartesian product of iterables. This is analogous to + itertools.product except that it works with infinite iterables and will + yield any item from the infinite product eventually. + + Examples + ======== + + >>> from sympy.utilities.iterables import iproduct + >>> sorted(iproduct([1,2], [3,4])) + [(1, 3), (1, 4), (2, 3), (2, 4)] + + With an infinite iterator: + + >>> from sympy import S + >>> (3,) in iproduct(S.Integers) + True + >>> (3, 4) in iproduct(S.Integers, S.Integers) + True + + .. seealso:: + + `itertools.product + `_ + ''' + if len(iterables) == 0: + yield () + return + elif len(iterables) == 1: + for e in iterables[0]: + yield (e,) + elif len(iterables) == 2: + yield from _iproduct2(*iterables) + else: + first, others = iterables[0], iterables[1:] + for ef, eo in _iproduct2(first, iproduct(*others)): + yield (ef,) + eo + + +def multiset(seq): + """Return the hashable sequence in multiset form with values being the + multiplicity of the item in the sequence. + + Examples + ======== + + >>> from sympy.utilities.iterables import multiset + >>> multiset('mississippi') + {'i': 4, 'm': 1, 'p': 2, 's': 4} + + See Also + ======== + + group + + """ + return dict(Counter(seq).items()) + + + + +def ibin(n, bits=None, str=False): + """Return a list of length ``bits`` corresponding to the binary value + of ``n`` with small bits to the right (last). If bits is omitted, the + length will be the number required to represent ``n``. If the bits are + desired in reversed order, use the ``[::-1]`` slice of the returned list. + + If a sequence of all bits-length lists starting from ``[0, 0,..., 0]`` + through ``[1, 1, ..., 1]`` are desired, pass a non-integer for bits, e.g. + ``'all'``. + + If the bit *string* is desired pass ``str=True``. + + Examples + ======== + + >>> from sympy.utilities.iterables import ibin + >>> ibin(2) + [1, 0] + >>> ibin(2, 4) + [0, 0, 1, 0] + + If all lists corresponding to 0 to 2**n - 1, pass a non-integer + for bits: + + >>> bits = 2 + >>> for i in ibin(2, 'all'): + ... print(i) + (0, 0) + (0, 1) + (1, 0) + (1, 1) + + If a bit string is desired of a given length, use str=True: + + >>> n = 123 + >>> bits = 10 + >>> ibin(n, bits, str=True) + '0001111011' + >>> ibin(n, bits, str=True)[::-1] # small bits left + '1101111000' + >>> list(ibin(3, 'all', str=True)) + ['000', '001', '010', '011', '100', '101', '110', '111'] + + """ + if n < 0: + raise ValueError("negative numbers are not allowed") + n = as_int(n) + + if bits is None: + bits = 0 + else: + try: + bits = as_int(bits) + except ValueError: + bits = -1 + else: + if n.bit_length() > bits: + raise ValueError( + "`bits` must be >= {}".format(n.bit_length())) + + if not str: + if bits >= 0: + return [1 if i == "1" else 0 for i in bin(n)[2:].rjust(bits, "0")] + else: + return variations(range(2), n, repetition=True) + else: + if bits >= 0: + return bin(n)[2:].rjust(bits, "0") + else: + return (bin(i)[2:].rjust(n, "0") for i in range(2**n)) + + +def variations(seq, n, repetition=False): + r"""Returns an iterator over the n-sized variations of ``seq`` (size N). + ``repetition`` controls whether items in ``seq`` can appear more than once; + + Examples + ======== + + ``variations(seq, n)`` will return `\frac{N!}{(N - n)!}` permutations without + repetition of ``seq``'s elements: + + >>> from sympy import variations + >>> list(variations([1, 2], 2)) + [(1, 2), (2, 1)] + + ``variations(seq, n, True)`` will return the `N^n` permutations obtained + by allowing repetition of elements: + + >>> list(variations([1, 2], 2, repetition=True)) + [(1, 1), (1, 2), (2, 1), (2, 2)] + + If you ask for more items than are in the set you get the empty set unless + you allow repetitions: + + >>> list(variations([0, 1], 3, repetition=False)) + [] + >>> list(variations([0, 1], 3, repetition=True))[:4] + [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)] + + .. seealso:: + + `itertools.permutations + `_, + `itertools.product + `_ + """ + if not repetition: + seq = tuple(seq) + if len(seq) < n: + return iter(()) # 0 length iterator + return permutations(seq, n) + else: + if n == 0: + return iter(((),)) # yields 1 empty tuple + else: + return product(seq, repeat=n) + + +def subsets(seq, k=None, repetition=False): + r"""Generates all `k`-subsets (combinations) from an `n`-element set, ``seq``. + + A `k`-subset of an `n`-element set is any subset of length exactly `k`. The + number of `k`-subsets of an `n`-element set is given by ``binomial(n, k)``, + whereas there are `2^n` subsets all together. If `k` is ``None`` then all + `2^n` subsets will be returned from shortest to longest. + + Examples + ======== + + >>> from sympy import subsets + + ``subsets(seq, k)`` will return the + `\frac{n!}{k!(n - k)!}` `k`-subsets (combinations) + without repetition, i.e. once an item has been removed, it can no + longer be "taken": + + >>> list(subsets([1, 2], 2)) + [(1, 2)] + >>> list(subsets([1, 2])) + [(), (1,), (2,), (1, 2)] + >>> list(subsets([1, 2, 3], 2)) + [(1, 2), (1, 3), (2, 3)] + + + ``subsets(seq, k, repetition=True)`` will return the + `\frac{(n - 1 + k)!}{k!(n - 1)!}` + combinations *with* repetition: + + >>> list(subsets([1, 2], 2, repetition=True)) + [(1, 1), (1, 2), (2, 2)] + + If you ask for more items than are in the set you get the empty set unless + you allow repetitions: + + >>> list(subsets([0, 1], 3, repetition=False)) + [] + >>> list(subsets([0, 1], 3, repetition=True)) + [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)] + + """ + if k is None: + if not repetition: + return chain.from_iterable((combinations(seq, k) + for k in range(len(seq) + 1))) + else: + return chain.from_iterable((combinations_with_replacement(seq, k) + for k in range(len(seq) + 1))) + else: + if not repetition: + return combinations(seq, k) + else: + return combinations_with_replacement(seq, k) + + +def filter_symbols(iterator, exclude): + """ + Only yield elements from `iterator` that do not occur in `exclude`. + + Parameters + ========== + + iterator : iterable + iterator to take elements from + + exclude : iterable + elements to exclude + + Returns + ======= + + iterator : iterator + filtered iterator + """ + exclude = set(exclude) + for s in iterator: + if s not in exclude: + yield s + +def numbered_symbols(prefix='x', cls=None, start=0, exclude=(), *args, **assumptions): + """ + Generate an infinite stream of Symbols consisting of a prefix and + increasing subscripts provided that they do not occur in ``exclude``. + + Parameters + ========== + + prefix : str, optional + The prefix to use. By default, this function will generate symbols of + the form "x0", "x1", etc. + + cls : class, optional + The class to use. By default, it uses ``Symbol``, but you can also use ``Wild`` + or ``Dummy``. + + start : int, optional + The start number. By default, it is 0. + + exclude : list, tuple, set of cls, optional + Symbols to be excluded. + + *args, **kwargs + Additional positional and keyword arguments are passed to the *cls* class. + + Returns + ======= + + sym : Symbol + The subscripted symbols. + """ + exclude = set(exclude or []) + if cls is None: + # We can't just make the default cls=Symbol because it isn't + # imported yet. + from sympy.core import Symbol + cls = Symbol + + while True: + name = '%s%s' % (prefix, start) + s = cls(name, *args, **assumptions) + if s not in exclude: + yield s + start += 1 + + +def capture(func): + """Return the printed output of func(). + + ``func`` should be a function without arguments that produces output with + print statements. + + >>> from sympy.utilities.iterables import capture + >>> from sympy import pprint + >>> from sympy.abc import x + >>> def foo(): + ... print('hello world!') + ... + >>> 'hello' in capture(foo) # foo, not foo() + True + >>> capture(lambda: pprint(2/x)) + '2\\n-\\nx\\n' + + """ + from io import StringIO + import sys + + stdout = sys.stdout + sys.stdout = file = StringIO() + try: + func() + finally: + sys.stdout = stdout + return file.getvalue() + + +def sift(seq, keyfunc, binary=False): + """ + Sift the sequence, ``seq`` according to ``keyfunc``. + + Returns + ======= + + When ``binary`` is ``False`` (default), the output is a dictionary + where elements of ``seq`` are stored in a list keyed to the value + of keyfunc for that element. If ``binary`` is True then a tuple + with lists ``T`` and ``F`` are returned where ``T`` is a list + containing elements of seq for which ``keyfunc`` was ``True`` and + ``F`` containing those elements for which ``keyfunc`` was ``False``; + a ValueError is raised if the ``keyfunc`` is not binary. + + Examples + ======== + + >>> from sympy.utilities import sift + >>> from sympy.abc import x, y + >>> from sympy import sqrt, exp, pi, Tuple + + >>> sift(range(5), lambda x: x % 2) + {0: [0, 2, 4], 1: [1, 3]} + + sift() returns a defaultdict() object, so any key that has no matches will + give []. + + >>> sift([x], lambda x: x.is_commutative) + {True: [x]} + >>> _[False] + [] + + Sometimes you will not know how many keys you will get: + + >>> sift([sqrt(x), exp(x), (y**x)**2], + ... lambda x: x.as_base_exp()[0]) + {E: [exp(x)], x: [sqrt(x)], y: [y**(2*x)]} + + Sometimes you expect the results to be binary; the + results can be unpacked by setting ``binary`` to True: + + >>> sift(range(4), lambda x: x % 2, binary=True) + ([1, 3], [0, 2]) + >>> sift(Tuple(1, pi), lambda x: x.is_rational, binary=True) + ([1], [pi]) + + A ValueError is raised if the predicate was not actually binary + (which is a good test for the logic where sifting is used and + binary results were expected): + + >>> unknown = exp(1) - pi # the rationality of this is unknown + >>> args = Tuple(1, pi, unknown) + >>> sift(args, lambda x: x.is_rational, binary=True) + Traceback (most recent call last): + ... + ValueError: keyfunc gave non-binary output + + The non-binary sifting shows that there were 3 keys generated: + + >>> set(sift(args, lambda x: x.is_rational).keys()) + {None, False, True} + + If you need to sort the sifted items it might be better to use + ``ordered`` which can economically apply multiple sort keys + to a sequence while sorting. + + See Also + ======== + + ordered + + """ + if not binary: + m = defaultdict(list) + for i in seq: + m[keyfunc(i)].append(i) + return m + sift = F, T = [], [] + for i in seq: + try: + sift[keyfunc(i)].append(i) + except (IndexError, TypeError): + raise ValueError('keyfunc gave non-binary output') + return T, F + + +def take(iter, n): + """Return ``n`` items from ``iter`` iterator. """ + return [ value for _, value in zip(range(n), iter) ] + + +def dict_merge(*dicts): + """Merge dictionaries into a single dictionary. """ + merged = {} + + for dict in dicts: + merged.update(dict) + + return merged + + +def common_prefix(*seqs): + """Return the subsequence that is a common start of sequences in ``seqs``. + + >>> from sympy.utilities.iterables import common_prefix + >>> common_prefix(list(range(3))) + [0, 1, 2] + >>> common_prefix(list(range(3)), list(range(4))) + [0, 1, 2] + >>> common_prefix([1, 2, 3], [1, 2, 5]) + [1, 2] + >>> common_prefix([1, 2, 3], [1, 3, 5]) + [1] + """ + if not all(seqs): + return [] + elif len(seqs) == 1: + return seqs[0] + i = 0 + for i in range(min(len(s) for s in seqs)): + if not all(seqs[j][i] == seqs[0][i] for j in range(len(seqs))): + break + else: + i += 1 + return seqs[0][:i] + + +def common_suffix(*seqs): + """Return the subsequence that is a common ending of sequences in ``seqs``. + + >>> from sympy.utilities.iterables import common_suffix + >>> common_suffix(list(range(3))) + [0, 1, 2] + >>> common_suffix(list(range(3)), list(range(4))) + [] + >>> common_suffix([1, 2, 3], [9, 2, 3]) + [2, 3] + >>> common_suffix([1, 2, 3], [9, 7, 3]) + [3] + """ + + if not all(seqs): + return [] + elif len(seqs) == 1: + return seqs[0] + i = 0 + for i in range(-1, -min(len(s) for s in seqs) - 1, -1): + if not all(seqs[j][i] == seqs[0][i] for j in range(len(seqs))): + break + else: + i -= 1 + if i == -1: + return [] + else: + return seqs[0][i + 1:] + + +def prefixes(seq): + """ + Generate all prefixes of a sequence. + + Examples + ======== + + >>> from sympy.utilities.iterables import prefixes + + >>> list(prefixes([1,2,3,4])) + [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]] + + """ + n = len(seq) + + for i in range(n): + yield seq[:i + 1] + + +def postfixes(seq): + """ + Generate all postfixes of a sequence. + + Examples + ======== + + >>> from sympy.utilities.iterables import postfixes + + >>> list(postfixes([1,2,3,4])) + [[4], [3, 4], [2, 3, 4], [1, 2, 3, 4]] + + """ + n = len(seq) + + for i in range(n): + yield seq[n - i - 1:] + + +def topological_sort(graph, key=None): + r""" + Topological sort of graph's vertices. + + Parameters + ========== + + graph : tuple[list, list[tuple[T, T]] + A tuple consisting of a list of vertices and a list of edges of + a graph to be sorted topologically. + + key : callable[T] (optional) + Ordering key for vertices on the same level. By default the natural + (e.g. lexicographic) ordering is used (in this case the base type + must implement ordering relations). + + Examples + ======== + + Consider a graph:: + + +---+ +---+ +---+ + | 7 |\ | 5 | | 3 | + +---+ \ +---+ +---+ + | _\___/ ____ _/ | + | / \___/ \ / | + V V V V | + +----+ +---+ | + | 11 | | 8 | | + +----+ +---+ | + | | \____ ___/ _ | + | \ \ / / \ | + V \ V V / V V + +---+ \ +---+ | +----+ + | 2 | | | 9 | | | 10 | + +---+ | +---+ | +----+ + \________/ + + where vertices are integers. This graph can be encoded using + elementary Python's data structures as follows:: + + >>> V = [2, 3, 5, 7, 8, 9, 10, 11] + >>> E = [(7, 11), (7, 8), (5, 11), (3, 8), (3, 10), + ... (11, 2), (11, 9), (11, 10), (8, 9)] + + To compute a topological sort for graph ``(V, E)`` issue:: + + >>> from sympy.utilities.iterables import topological_sort + + >>> topological_sort((V, E)) + [3, 5, 7, 8, 11, 2, 9, 10] + + If specific tie breaking approach is needed, use ``key`` parameter:: + + >>> topological_sort((V, E), key=lambda v: -v) + [7, 5, 11, 3, 10, 8, 9, 2] + + Only acyclic graphs can be sorted. If the input graph has a cycle, + then ``ValueError`` will be raised:: + + >>> topological_sort((V, E + [(10, 7)])) + Traceback (most recent call last): + ... + ValueError: cycle detected + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Topological_sorting + + """ + V, E = graph + + L = [] + S = set(V) + E = list(E) + + S.difference_update(u for v, u in E) + + if key is None: + def key(value): + return value + + S = sorted(S, key=key, reverse=True) + + while S: + node = S.pop() + L.append(node) + + for u, v in list(E): + if u == node: + E.remove((u, v)) + + for _u, _v in E: + if v == _v: + break + else: + kv = key(v) + + for i, s in enumerate(S): + ks = key(s) + + if kv > ks: + S.insert(i, v) + break + else: + S.append(v) + + if E: + raise ValueError("cycle detected") + else: + return L + + +def strongly_connected_components(G): + r""" + Strongly connected components of a directed graph in reverse topological + order. + + + Parameters + ========== + + G : tuple[list, list[tuple[T, T]] + A tuple consisting of a list of vertices and a list of edges of + a graph whose strongly connected components are to be found. + + + Examples + ======== + + Consider a directed graph (in dot notation):: + + digraph { + A -> B + A -> C + B -> C + C -> B + B -> D + } + + .. graphviz:: + + digraph { + A -> B + A -> C + B -> C + C -> B + B -> D + } + + where vertices are the letters A, B, C and D. This graph can be encoded + using Python's elementary data structures as follows:: + + >>> V = ['A', 'B', 'C', 'D'] + >>> E = [('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'B'), ('B', 'D')] + + The strongly connected components of this graph can be computed as + + >>> from sympy.utilities.iterables import strongly_connected_components + + >>> strongly_connected_components((V, E)) + [['D'], ['B', 'C'], ['A']] + + This also gives the components in reverse topological order. + + Since the subgraph containing B and C has a cycle they must be together in + a strongly connected component. A and D are connected to the rest of the + graph but not in a cyclic manner so they appear as their own strongly + connected components. + + + Notes + ===== + + The vertices of the graph must be hashable for the data structures used. + If the vertices are unhashable replace them with integer indices. + + This function uses Tarjan's algorithm to compute the strongly connected + components in `O(|V|+|E|)` (linear) time. + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Strongly_connected_component + .. [2] https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + + + See Also + ======== + + sympy.utilities.iterables.connected_components + + """ + # Map from a vertex to its neighbours + V, E = G + Gmap = {vi: [] for vi in V} + for v1, v2 in E: + Gmap[v1].append(v2) + return _strongly_connected_components(V, Gmap) + + +def _strongly_connected_components(V, Gmap): + """More efficient internal routine for strongly_connected_components""" + # + # Here V is an iterable of vertices and Gmap is a dict mapping each vertex + # to a list of neighbours e.g.: + # + # V = [0, 1, 2, 3] + # Gmap = {0: [2, 3], 1: [0]} + # + # For a large graph these data structures can often be created more + # efficiently then those expected by strongly_connected_components() which + # in this case would be + # + # V = [0, 1, 2, 3] + # Gmap = [(0, 2), (0, 3), (1, 0)] + # + # XXX: Maybe this should be the recommended function to use instead... + # + + # Non-recursive Tarjan's algorithm: + lowlink = {} + indices = {} + stack = OrderedDict() + callstack = [] + components = [] + nomore = object() + + def start(v): + index = len(stack) + indices[v] = lowlink[v] = index + stack[v] = None + callstack.append((v, iter(Gmap[v]))) + + def finish(v1): + # Finished a component? + if lowlink[v1] == indices[v1]: + component = [stack.popitem()[0]] + while component[-1] is not v1: + component.append(stack.popitem()[0]) + components.append(component[::-1]) + v2, _ = callstack.pop() + if callstack: + v1, _ = callstack[-1] + lowlink[v1] = min(lowlink[v1], lowlink[v2]) + + for v in V: + if v in indices: + continue + start(v) + while callstack: + v1, it1 = callstack[-1] + v2 = next(it1, nomore) + # Finished children of v1? + if v2 is nomore: + finish(v1) + # Recurse on v2 + elif v2 not in indices: + start(v2) + elif v2 in stack: + lowlink[v1] = min(lowlink[v1], indices[v2]) + + # Reverse topological sort order: + return components + + +def connected_components(G): + r""" + Connected components of an undirected graph or weakly connected components + of a directed graph. + + + Parameters + ========== + + G : tuple[list, list[tuple[T, T]] + A tuple consisting of a list of vertices and a list of edges of + a graph whose connected components are to be found. + + + Examples + ======== + + + Given an undirected graph:: + + graph { + A -- B + C -- D + } + + .. graphviz:: + + graph { + A -- B + C -- D + } + + We can find the connected components using this function if we include + each edge in both directions:: + + >>> from sympy.utilities.iterables import connected_components + + >>> V = ['A', 'B', 'C', 'D'] + >>> E = [('A', 'B'), ('B', 'A'), ('C', 'D'), ('D', 'C')] + >>> connected_components((V, E)) + [['A', 'B'], ['C', 'D']] + + The weakly connected components of a directed graph can found the same + way. + + + Notes + ===== + + The vertices of the graph must be hashable for the data structures used. + If the vertices are unhashable replace them with integer indices. + + This function uses Tarjan's algorithm to compute the connected components + in `O(|V|+|E|)` (linear) time. + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Component_%28graph_theory%29 + .. [2] https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + + + See Also + ======== + + sympy.utilities.iterables.strongly_connected_components + + """ + # Duplicate edges both ways so that the graph is effectively undirected + # and return the strongly connected components: + V, E = G + E_undirected = [] + for v1, v2 in E: + E_undirected.extend([(v1, v2), (v2, v1)]) + return strongly_connected_components((V, E_undirected)) + + +def rotate_left(x, y): + """ + Left rotates a list x by the number of steps specified + in y. + + Examples + ======== + + >>> from sympy.utilities.iterables import rotate_left + >>> a = [0, 1, 2] + >>> rotate_left(a, 1) + [1, 2, 0] + """ + if len(x) == 0: + return [] + y = y % len(x) + return x[y:] + x[:y] + + +def rotate_right(x, y): + """ + Right rotates a list x by the number of steps specified + in y. + + Examples + ======== + + >>> from sympy.utilities.iterables import rotate_right + >>> a = [0, 1, 2] + >>> rotate_right(a, 1) + [2, 0, 1] + """ + if len(x) == 0: + return [] + y = len(x) - y % len(x) + return x[y:] + x[:y] + + +def least_rotation(x, key=None): + ''' + Returns the number of steps of left rotation required to + obtain lexicographically minimal string/list/tuple, etc. + + Examples + ======== + + >>> from sympy.utilities.iterables import least_rotation, rotate_left + >>> a = [3, 1, 5, 1, 2] + >>> least_rotation(a) + 3 + >>> rotate_left(a, _) + [1, 2, 3, 1, 5] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Lexicographically_minimal_string_rotation + + ''' + from sympy.functions.elementary.miscellaneous import Id + if key is None: key = Id + S = x + x # Concatenate string to it self to avoid modular arithmetic + f = [-1] * len(S) # Failure function + k = 0 # Least rotation of string found so far + for j in range(1,len(S)): + sj = S[j] + i = f[j-k-1] + while i != -1 and sj != S[k+i+1]: + if key(sj) < key(S[k+i+1]): + k = j-i-1 + i = f[i] + if sj != S[k+i+1]: + if key(sj) < key(S[k]): + k = j + f[j-k] = -1 + else: + f[j-k] = i+1 + return k + + +def multiset_combinations(m, n, g=None): + """ + Return the unique combinations of size ``n`` from multiset ``m``. + + Examples + ======== + + >>> from sympy.utilities.iterables import multiset_combinations + >>> from itertools import combinations + >>> [''.join(i) for i in multiset_combinations('baby', 3)] + ['abb', 'aby', 'bby'] + + >>> def count(f, s): return len(list(f(s, 3))) + + The number of combinations depends on the number of letters; the + number of unique combinations depends on how the letters are + repeated. + + >>> s1 = 'abracadabra' + >>> s2 = 'banana tree' + >>> count(combinations, s1), count(multiset_combinations, s1) + (165, 23) + >>> count(combinations, s2), count(multiset_combinations, s2) + (165, 54) + + """ + from sympy.core.sorting import ordered + if g is None: + if isinstance(m, dict): + if any(as_int(v) < 0 for v in m.values()): + raise ValueError('counts cannot be negative') + N = sum(m.values()) + if n > N: + return + g = [[k, m[k]] for k in ordered(m)] + else: + m = list(m) + N = len(m) + if n > N: + return + try: + m = multiset(m) + g = [(k, m[k]) for k in ordered(m)] + except TypeError: + m = list(ordered(m)) + g = [list(i) for i in group(m, multiple=False)] + del m + else: + # not checking counts since g is intended for internal use + N = sum(v for k, v in g) + if n > N or not n: + yield [] + else: + for i, (k, v) in enumerate(g): + if v >= n: + yield [k]*n + v = n - 1 + for v in range(min(n, v), 0, -1): + for j in multiset_combinations(None, n - v, g[i + 1:]): + rv = [k]*v + j + if len(rv) == n: + yield rv + +def multiset_permutations(m, size=None, g=None): + """ + Return the unique permutations of multiset ``m``. + + Examples + ======== + + >>> from sympy.utilities.iterables import multiset_permutations + >>> from sympy import factorial + >>> [''.join(i) for i in multiset_permutations('aab')] + ['aab', 'aba', 'baa'] + >>> factorial(len('banana')) + 720 + >>> len(list(multiset_permutations('banana'))) + 60 + """ + from sympy.core.sorting import ordered + if g is None: + if isinstance(m, dict): + if any(as_int(v) < 0 for v in m.values()): + raise ValueError('counts cannot be negative') + g = [[k, m[k]] for k in ordered(m)] + else: + m = list(ordered(m)) + g = [list(i) for i in group(m, multiple=False)] + del m + do = [gi for gi in g if gi[1] > 0] + SUM = sum(gi[1] for gi in do) + if not do or size is not None and (size > SUM or size < 1): + if not do and size is None or size == 0: + yield [] + return + elif size == 1: + for k, v in do: + yield [k] + elif len(do) == 1: + k, v = do[0] + v = v if size is None else (size if size <= v else 0) + yield [k for i in range(v)] + elif all(v == 1 for k, v in do): + for p in permutations([k for k, v in do], size): + yield list(p) + else: + size = size if size is not None else SUM + for i, (k, v) in enumerate(do): + do[i][1] -= 1 + for j in multiset_permutations(None, size - 1, do): + if j: + yield [k] + j + do[i][1] += 1 + + +def _partition(seq, vector, m=None): + """ + Return the partition of seq as specified by the partition vector. + + Examples + ======== + + >>> from sympy.utilities.iterables import _partition + >>> _partition('abcde', [1, 0, 1, 2, 0]) + [['b', 'e'], ['a', 'c'], ['d']] + + Specifying the number of bins in the partition is optional: + + >>> _partition('abcde', [1, 0, 1, 2, 0], 3) + [['b', 'e'], ['a', 'c'], ['d']] + + The output of _set_partitions can be passed as follows: + + >>> output = (3, [1, 0, 1, 2, 0]) + >>> _partition('abcde', *output) + [['b', 'e'], ['a', 'c'], ['d']] + + See Also + ======== + + combinatorics.partitions.Partition.from_rgs + + """ + if m is None: + m = max(vector) + 1 + elif isinstance(vector, int): # entered as m, vector + vector, m = m, vector + p = [[] for i in range(m)] + for i, v in enumerate(vector): + p[v].append(seq[i]) + return p + + +def _set_partitions(n): + """Cycle through all partitions of n elements, yielding the + current number of partitions, ``m``, and a mutable list, ``q`` + such that ``element[i]`` is in part ``q[i]`` of the partition. + + NOTE: ``q`` is modified in place and generally should not be changed + between function calls. + + Examples + ======== + + >>> from sympy.utilities.iterables import _set_partitions, _partition + >>> for m, q in _set_partitions(3): + ... print('%s %s %s' % (m, q, _partition('abc', q, m))) + 1 [0, 0, 0] [['a', 'b', 'c']] + 2 [0, 0, 1] [['a', 'b'], ['c']] + 2 [0, 1, 0] [['a', 'c'], ['b']] + 2 [0, 1, 1] [['a'], ['b', 'c']] + 3 [0, 1, 2] [['a'], ['b'], ['c']] + + Notes + ===== + + This algorithm is similar to, and solves the same problem as, + Algorithm 7.2.1.5H, from volume 4A of Knuth's The Art of Computer + Programming. Knuth uses the term "restricted growth string" where + this code refers to a "partition vector". In each case, the meaning is + the same: the value in the ith element of the vector specifies to + which part the ith set element is to be assigned. + + At the lowest level, this code implements an n-digit big-endian + counter (stored in the array q) which is incremented (with carries) to + get the next partition in the sequence. A special twist is that a + digit is constrained to be at most one greater than the maximum of all + the digits to the left of it. The array p maintains this maximum, so + that the code can efficiently decide when a digit can be incremented + in place or whether it needs to be reset to 0 and trigger a carry to + the next digit. The enumeration starts with all the digits 0 (which + corresponds to all the set elements being assigned to the same 0th + part), and ends with 0123...n, which corresponds to each set element + being assigned to a different, singleton, part. + + This routine was rewritten to use 0-based lists while trying to + preserve the beauty and efficiency of the original algorithm. + + References + ========== + + .. [1] Nijenhuis, Albert and Wilf, Herbert. (1978) Combinatorial Algorithms, + 2nd Ed, p 91, algorithm "nexequ". Available online from + https://www.math.upenn.edu/~wilf/website/CombAlgDownld.html (viewed + November 17, 2012). + + """ + p = [0]*n + q = [0]*n + nc = 1 + yield nc, q + while nc != n: + m = n + while 1: + m -= 1 + i = q[m] + if p[i] != 1: + break + q[m] = 0 + i += 1 + q[m] = i + m += 1 + nc += m - n + p[0] += n - m + if i == nc: + p[nc] = 0 + nc += 1 + p[i - 1] -= 1 + p[i] += 1 + yield nc, q + + +def multiset_partitions(multiset, m=None): + """ + Return unique partitions of the given multiset (in list form). + If ``m`` is None, all multisets will be returned, otherwise only + partitions with ``m`` parts will be returned. + + If ``multiset`` is an integer, a range [0, 1, ..., multiset - 1] + will be supplied. + + Examples + ======== + + >>> from sympy.utilities.iterables import multiset_partitions + >>> list(multiset_partitions([1, 2, 3, 4], 2)) + [[[1, 2, 3], [4]], [[1, 2, 4], [3]], [[1, 2], [3, 4]], + [[1, 3, 4], [2]], [[1, 3], [2, 4]], [[1, 4], [2, 3]], + [[1], [2, 3, 4]]] + >>> list(multiset_partitions([1, 2, 3, 4], 1)) + [[[1, 2, 3, 4]]] + + Only unique partitions are returned and these will be returned in a + canonical order regardless of the order of the input: + + >>> a = [1, 2, 2, 1] + >>> ans = list(multiset_partitions(a, 2)) + >>> a.sort() + >>> list(multiset_partitions(a, 2)) == ans + True + >>> a = range(3, 1, -1) + >>> (list(multiset_partitions(a)) == + ... list(multiset_partitions(sorted(a)))) + True + + If m is omitted then all partitions will be returned: + + >>> list(multiset_partitions([1, 1, 2])) + [[[1, 1, 2]], [[1, 1], [2]], [[1, 2], [1]], [[1], [1], [2]]] + >>> list(multiset_partitions([1]*3)) + [[[1, 1, 1]], [[1], [1, 1]], [[1], [1], [1]]] + + Counting + ======== + + The number of partitions of a set is given by the bell number: + + >>> from sympy import bell + >>> len(list(multiset_partitions(5))) == bell(5) == 52 + True + + The number of partitions of length k from a set of size n is given by the + Stirling Number of the 2nd kind: + + >>> from sympy.functions.combinatorial.numbers import stirling + >>> stirling(5, 2) == len(list(multiset_partitions(5, 2))) == 15 + True + + These comments on counting apply to *sets*, not multisets. + + Notes + ===== + + When all the elements are the same in the multiset, the order + of the returned partitions is determined by the ``partitions`` + routine. If one is counting partitions then it is better to use + the ``nT`` function. + + See Also + ======== + + partitions + sympy.combinatorics.partitions.Partition + sympy.combinatorics.partitions.IntegerPartition + sympy.functions.combinatorial.numbers.nT + + """ + # This function looks at the supplied input and dispatches to + # several special-case routines as they apply. + if isinstance(multiset, int): + n = multiset + if m and m > n: + return + multiset = list(range(n)) + if m == 1: + yield [multiset[:]] + return + + # If m is not None, it can sometimes be faster to use + # MultisetPartitionTraverser.enum_range() even for inputs + # which are sets. Since the _set_partitions code is quite + # fast, this is only advantageous when the overall set + # partitions outnumber those with the desired number of parts + # by a large factor. (At least 60.) Such a switch is not + # currently implemented. + for nc, q in _set_partitions(n): + if m is None or nc == m: + rv = [[] for i in range(nc)] + for i in range(n): + rv[q[i]].append(multiset[i]) + yield rv + return + + if len(multiset) == 1 and isinstance(multiset, str): + multiset = [multiset] + + if not has_variety(multiset): + # Only one component, repeated n times. The resulting + # partitions correspond to partitions of integer n. + n = len(multiset) + if m and m > n: + return + if m == 1: + yield [multiset[:]] + return + x = multiset[:1] + for size, p in partitions(n, m, size=True): + if m is None or size == m: + rv = [] + for k in sorted(p): + rv.extend([x*k]*p[k]) + yield rv + else: + from sympy.core.sorting import ordered + multiset = list(ordered(multiset)) + n = len(multiset) + if m and m > n: + return + if m == 1: + yield [multiset[:]] + return + + # Split the information of the multiset into two lists - + # one of the elements themselves, and one (of the same length) + # giving the number of repeats for the corresponding element. + elements, multiplicities = zip(*group(multiset, False)) + + if len(elements) < len(multiset): + # General case - multiset with more than one distinct element + # and at least one element repeated more than once. + if m: + mpt = MultisetPartitionTraverser() + for state in mpt.enum_range(multiplicities, m-1, m): + yield list_visitor(state, elements) + else: + for state in multiset_partitions_taocp(multiplicities): + yield list_visitor(state, elements) + else: + # Set partitions case - no repeated elements. Pretty much + # same as int argument case above, with same possible, but + # currently unimplemented optimization for some cases when + # m is not None + for nc, q in _set_partitions(n): + if m is None or nc == m: + rv = [[] for i in range(nc)] + for i in range(n): + rv[q[i]].append(i) + yield [[multiset[j] for j in i] for i in rv] + + +def partitions(n, m=None, k=None, size=False): + """Generate all partitions of positive integer, n. + + Each partition is represented as a dictionary, mapping an integer + to the number of copies of that integer in the partition. For example, + the first partition of 4 returned is {4: 1}, "4: one of them". + + Parameters + ========== + n : int + m : int, optional + limits number of parts in partition (mnemonic: m, maximum parts) + k : int, optional + limits the numbers that are kept in the partition (mnemonic: k, keys) + size : bool, default: False + If ``True``, (M, P) is returned where M is the sum of the + multiplicities and P is the generated partition. + If ``False``, only the generated partition is returned. + + Examples + ======== + + >>> from sympy.utilities.iterables import partitions + + The numbers appearing in the partition (the key of the returned dict) + are limited with k: + + >>> for p in partitions(6, k=2): # doctest: +SKIP + ... print(p) + {2: 3} + {1: 2, 2: 2} + {1: 4, 2: 1} + {1: 6} + + The maximum number of parts in the partition (the sum of the values in + the returned dict) are limited with m (default value, None, gives + partitions from 1 through n): + + >>> for p in partitions(6, m=2): # doctest: +SKIP + ... print(p) + ... + {6: 1} + {1: 1, 5: 1} + {2: 1, 4: 1} + {3: 2} + + References + ========== + + .. [1] modified from Tim Peter's version to allow for k and m values: + https://code.activestate.com/recipes/218332-generator-for-integer-partitions/ + + See Also + ======== + + sympy.combinatorics.partitions.Partition + sympy.combinatorics.partitions.IntegerPartition + + """ + if (n <= 0 or + m is not None and m < 1 or + k is not None and k < 1 or + m and k and m*k < n): + # the empty set is the only way to handle these inputs + # and returning {} to represent it is consistent with + # the counting convention, e.g. nT(0) == 1. + if size: + yield 0, {} + else: + yield {} + return + + if m is None: + m = n + else: + m = min(m, n) + k = min(k or n, n) + + n, m, k = as_int(n), as_int(m), as_int(k) + q, r = divmod(n, k) + ms = {k: q} + keys = [k] # ms.keys(), from largest to smallest + if r: + ms[r] = 1 + keys.append(r) + room = m - q - bool(r) + if size: + yield sum(ms.values()), ms.copy() + else: + yield ms.copy() + + while keys != [1]: + # Reuse any 1's. + if keys[-1] == 1: + del keys[-1] + reuse = ms.pop(1) + room += reuse + else: + reuse = 0 + + while 1: + # Let i be the smallest key larger than 1. Reuse one + # instance of i. + i = keys[-1] + newcount = ms[i] = ms[i] - 1 + reuse += i + if newcount == 0: + del keys[-1], ms[i] + room += 1 + + # Break the remainder into pieces of size i-1. + i -= 1 + q, r = divmod(reuse, i) + need = q + bool(r) + if need > room: + if not keys: + return + continue + + ms[i] = q + keys.append(i) + if r: + ms[r] = 1 + keys.append(r) + break + room -= need + if size: + yield sum(ms.values()), ms.copy() + else: + yield ms.copy() + + +def ordered_partitions(n, m=None, sort=True): + """Generates ordered partitions of integer *n*. + + Parameters + ========== + n : int + m : int, optional + The default value gives partitions of all sizes else only + those with size m. In addition, if *m* is not None then + partitions are generated *in place* (see examples). + sort : bool, default: True + Controls whether partitions are + returned in sorted order when *m* is not None; when False, + the partitions are returned as fast as possible with elements + sorted, but when m|n the partitions will not be in + ascending lexicographical order. + + Examples + ======== + + >>> from sympy.utilities.iterables import ordered_partitions + + All partitions of 5 in ascending lexicographical: + + >>> for p in ordered_partitions(5): + ... print(p) + [1, 1, 1, 1, 1] + [1, 1, 1, 2] + [1, 1, 3] + [1, 2, 2] + [1, 4] + [2, 3] + [5] + + Only partitions of 5 with two parts: + + >>> for p in ordered_partitions(5, 2): + ... print(p) + [1, 4] + [2, 3] + + When ``m`` is given, a given list objects will be used more than + once for speed reasons so you will not see the correct partitions + unless you make a copy of each as it is generated: + + >>> [p for p in ordered_partitions(7, 3)] + [[1, 1, 1], [1, 1, 1], [1, 1, 1], [2, 2, 2]] + >>> [list(p) for p in ordered_partitions(7, 3)] + [[1, 1, 5], [1, 2, 4], [1, 3, 3], [2, 2, 3]] + + When ``n`` is a multiple of ``m``, the elements are still sorted + but the partitions themselves will be *unordered* if sort is False; + the default is to return them in ascending lexicographical order. + + >>> for p in ordered_partitions(6, 2): + ... print(p) + [1, 5] + [2, 4] + [3, 3] + + But if speed is more important than ordering, sort can be set to + False: + + >>> for p in ordered_partitions(6, 2, sort=False): + ... print(p) + [1, 5] + [3, 3] + [2, 4] + + References + ========== + + .. [1] Generating Integer Partitions, [online], + Available: https://jeromekelleher.net/generating-integer-partitions.html + .. [2] Jerome Kelleher and Barry O'Sullivan, "Generating All + Partitions: A Comparison Of Two Encodings", [online], + Available: https://arxiv.org/pdf/0909.2331v2.pdf + """ + if n < 1 or m is not None and m < 1: + # the empty set is the only way to handle these inputs + # and returning {} to represent it is consistent with + # the counting convention, e.g. nT(0) == 1. + yield [] + return + + if m is None: + # The list `a`'s leading elements contain the partition in which + # y is the biggest element and x is either the same as y or the + # 2nd largest element; v and w are adjacent element indices + # to which x and y are being assigned, respectively. + a = [1]*n + y = -1 + v = n + while v > 0: + v -= 1 + x = a[v] + 1 + while y >= 2 * x: + a[v] = x + y -= x + v += 1 + w = v + 1 + while x <= y: + a[v] = x + a[w] = y + yield a[:w + 1] + x += 1 + y -= 1 + a[v] = x + y + y = a[v] - 1 + yield a[:w] + elif m == 1: + yield [n] + elif n == m: + yield [1]*n + else: + # recursively generate partitions of size m + for b in range(1, n//m + 1): + a = [b]*m + x = n - b*m + if not x: + if sort: + yield a + elif not sort and x <= m: + for ax in ordered_partitions(x, sort=False): + mi = len(ax) + a[-mi:] = [i + b for i in ax] + yield a + a[-mi:] = [b]*mi + else: + for mi in range(1, m): + for ax in ordered_partitions(x, mi, sort=True): + a[-mi:] = [i + b for i in ax] + yield a + a[-mi:] = [b]*mi + + +def binary_partitions(n): + """ + Generates the binary partition of *n*. + + A binary partition consists only of numbers that are + powers of two. Each step reduces a `2^{k+1}` to `2^k` and + `2^k`. Thus 16 is converted to 8 and 8. + + Examples + ======== + + >>> from sympy.utilities.iterables import binary_partitions + >>> for i in binary_partitions(5): + ... print(i) + ... + [4, 1] + [2, 2, 1] + [2, 1, 1, 1] + [1, 1, 1, 1, 1] + + References + ========== + + .. [1] TAOCP 4, section 7.2.1.5, problem 64 + + """ + from math import ceil, log2 + power = int(2**(ceil(log2(n)))) + acc = 0 + partition = [] + while power: + if acc + power <= n: + partition.append(power) + acc += power + power >>= 1 + + last_num = len(partition) - 1 - (n & 1) + while last_num >= 0: + yield partition + if partition[last_num] == 2: + partition[last_num] = 1 + partition.append(1) + last_num -= 1 + continue + partition.append(1) + partition[last_num] >>= 1 + x = partition[last_num + 1] = partition[last_num] + last_num += 1 + while x > 1: + if x <= len(partition) - last_num - 1: + del partition[-x + 1:] + last_num += 1 + partition[last_num] = x + else: + x >>= 1 + yield [1]*n + + +def has_dups(seq): + """Return True if there are any duplicate elements in ``seq``. + + Examples + ======== + + >>> from sympy import has_dups, Dict, Set + >>> has_dups((1, 2, 1)) + True + >>> has_dups(range(3)) + False + >>> all(has_dups(c) is False for c in (set(), Set(), dict(), Dict())) + True + """ + from sympy.core.containers import Dict + from sympy.sets.sets import Set + if isinstance(seq, (dict, set, Dict, Set)): + return False + unique = set() + try: + return any(True for s in seq if s in unique or unique.add(s)) + except TypeError: + return len(seq) != len(list(uniq(seq))) + + +def has_variety(seq): + """Return True if there are any different elements in ``seq``. + + Examples + ======== + + >>> from sympy import has_variety + + >>> has_variety((1, 2, 1)) + True + >>> has_variety((1, 1, 1)) + False + """ + for i, s in enumerate(seq): + if i == 0: + sentinel = s + else: + if s != sentinel: + return True + return False + + +def uniq(seq, result=None): + """ + Yield unique elements from ``seq`` as an iterator. The second + parameter ``result`` is used internally; it is not necessary + to pass anything for this. + + Note: changing the sequence during iteration will raise a + RuntimeError if the size of the sequence is known; if you pass + an iterator and advance the iterator you will change the + output of this routine but there will be no warning. + + Examples + ======== + + >>> from sympy.utilities.iterables import uniq + >>> dat = [1, 4, 1, 5, 4, 2, 1, 2] + >>> type(uniq(dat)) in (list, tuple) + False + + >>> list(uniq(dat)) + [1, 4, 5, 2] + >>> list(uniq(x for x in dat)) + [1, 4, 5, 2] + >>> list(uniq([[1], [2, 1], [1]])) + [[1], [2, 1]] + """ + try: + n = len(seq) + except TypeError: + n = None + def check(): + # check that size of seq did not change during iteration; + # if n == None the object won't support size changing, e.g. + # an iterator can't be changed + if n is not None and len(seq) != n: + raise RuntimeError('sequence changed size during iteration') + try: + seen = set() + result = result or [] + for i, s in enumerate(seq): + if not (s in seen or seen.add(s)): + yield s + check() + except TypeError: + if s not in result: + yield s + check() + result.append(s) + if hasattr(seq, '__getitem__'): + yield from uniq(seq[i + 1:], result) + else: + yield from uniq(seq, result) + + +def generate_bell(n): + """Return permutations of [0, 1, ..., n - 1] such that each permutation + differs from the last by the exchange of a single pair of neighbors. + The ``n!`` permutations are returned as an iterator. In order to obtain + the next permutation from a random starting permutation, use the + ``next_trotterjohnson`` method of the Permutation class (which generates + the same sequence in a different manner). + + Examples + ======== + + >>> from itertools import permutations + >>> from sympy.utilities.iterables import generate_bell + >>> from sympy import zeros, Matrix + + This is the sort of permutation used in the ringing of physical bells, + and does not produce permutations in lexicographical order. Rather, the + permutations differ from each other by exactly one inversion, and the + position at which the swapping occurs varies periodically in a simple + fashion. Consider the first few permutations of 4 elements generated + by ``permutations`` and ``generate_bell``: + + >>> list(permutations(range(4)))[:5] + [(0, 1, 2, 3), (0, 1, 3, 2), (0, 2, 1, 3), (0, 2, 3, 1), (0, 3, 1, 2)] + >>> list(generate_bell(4))[:5] + [(0, 1, 2, 3), (0, 1, 3, 2), (0, 3, 1, 2), (3, 0, 1, 2), (3, 0, 2, 1)] + + Notice how the 2nd and 3rd lexicographical permutations have 3 elements + out of place whereas each "bell" permutation always has only two + elements out of place relative to the previous permutation (and so the + signature (+/-1) of a permutation is opposite of the signature of the + previous permutation). + + How the position of inversion varies across the elements can be seen + by tracing out where the largest number appears in the permutations: + + >>> m = zeros(4, 24) + >>> for i, p in enumerate(generate_bell(4)): + ... m[:, i] = Matrix([j - 3 for j in list(p)]) # make largest zero + >>> m.print_nonzero('X') + [XXX XXXXXX XXXXXX XXX] + [XX XX XXXX XX XXXX XX XX] + [X XXXX XX XXXX XX XXXX X] + [ XXXXXX XXXXXX XXXXXX ] + + See Also + ======== + + sympy.combinatorics.permutations.Permutation.next_trotterjohnson + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Method_ringing + + .. [2] https://stackoverflow.com/questions/4856615/recursive-permutation/4857018 + + .. [3] https://web.archive.org/web/20160313023044/http://programminggeeks.com/bell-algorithm-for-permutation/ + + .. [4] https://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm + + .. [5] Generating involutions, derangements, and relatives by ECO + Vincent Vajnovszki, DMTCS vol 1 issue 12, 2010 + + """ + n = as_int(n) + if n < 1: + raise ValueError('n must be a positive integer') + if n == 1: + yield (0,) + elif n == 2: + yield (0, 1) + yield (1, 0) + elif n == 3: + yield from [(0, 1, 2), (0, 2, 1), (2, 0, 1), (2, 1, 0), (1, 2, 0), (1, 0, 2)] + else: + m = n - 1 + op = [0] + [-1]*m + l = list(range(n)) + while True: + yield tuple(l) + # find biggest element with op + big = None, -1 # idx, value + for i in range(n): + if op[i] and l[i] > big[1]: + big = i, l[i] + i, _ = big + if i is None: + break # there are no ops left + # swap it with neighbor in the indicated direction + j = i + op[i] + l[i], l[j] = l[j], l[i] + op[i], op[j] = op[j], op[i] + # if it landed at the end or if the neighbor in the same + # direction is bigger then turn off op + if j == 0 or j == m or l[j + op[j]] > l[j]: + op[j] = 0 + # any element bigger to the left gets +1 op + for i in range(j): + if l[i] > l[j]: + op[i] = 1 + # any element bigger to the right gets -1 op + for i in range(j + 1, n): + if l[i] > l[j]: + op[i] = -1 + + +def generate_involutions(n): + """ + Generates involutions. + + An involution is a permutation that when multiplied + by itself equals the identity permutation. In this + implementation the involutions are generated using + Fixed Points. + + Alternatively, an involution can be considered as + a permutation that does not contain any cycles with + a length that is greater than two. + + Examples + ======== + + >>> from sympy.utilities.iterables import generate_involutions + >>> list(generate_involutions(3)) + [(0, 1, 2), (0, 2, 1), (1, 0, 2), (2, 1, 0)] + >>> len(list(generate_involutions(4))) + 10 + + References + ========== + + .. [1] https://mathworld.wolfram.com/PermutationInvolution.html + + """ + idx = list(range(n)) + for p in permutations(idx): + for i in idx: + if p[p[i]] != i: + break + else: + yield p + + +def multiset_derangements(s): + """Generate derangements of the elements of s *in place*. + + Examples + ======== + + >>> from sympy.utilities.iterables import multiset_derangements, uniq + + Because the derangements of multisets (not sets) are generated + in place, copies of the return value must be made if a collection + of derangements is desired or else all values will be the same: + + >>> list(uniq([i for i in multiset_derangements('1233')])) + [[None, None, None, None]] + >>> [i.copy() for i in multiset_derangements('1233')] + [['3', '3', '1', '2'], ['3', '3', '2', '1']] + >>> [''.join(i) for i in multiset_derangements('1233')] + ['3312', '3321'] + """ + from sympy.core.sorting import ordered + # create multiset dictionary of hashable elements or else + # remap elements to integers + try: + ms = multiset(s) + except TypeError: + # give each element a canonical integer value + key = dict(enumerate(ordered(uniq(s)))) + h = [] + for si in s: + for k in key: + if key[k] == si: + h.append(k) + break + for i in multiset_derangements(h): + yield [key[j] for j in i] + return + + mx = max(ms.values()) # max repetition of any element + n = len(s) # the number of elements + + ## special cases + + # 1) one element has more than half the total cardinality of s: no + # derangements are possible. + if mx*2 > n: + return + + # 2) all elements appear once: singletons + if len(ms) == n: + yield from _set_derangements(s) + return + + # find the first element that is repeated the most to place + # in the following two special cases where the selection + # is unambiguous: either there are two elements with multiplicity + # of mx or else there is only one with multiplicity mx + for M in ms: + if ms[M] == mx: + break + + inonM = [i for i in range(n) if s[i] != M] # location of non-M + iM = [i for i in range(n) if s[i] == M] # locations of M + rv = [None]*n + + # 3) half are the same + if 2*mx == n: + # M goes into non-M locations + for i in inonM: + rv[i] = M + # permutations of non-M go to M locations + for p in multiset_permutations([s[i] for i in inonM]): + for i, pi in zip(iM, p): + rv[i] = pi + yield rv + # clean-up (and encourages proper use of routine) + rv[:] = [None]*n + return + + # 4) single repeat covers all but 1 of the non-repeats: + # if there is one repeat then the multiset of the values + # of ms would be {mx: 1, 1: n - mx}, i.e. there would + # be n - mx + 1 values with the condition that n - 2*mx = 1 + if n - 2*mx == 1 and len(ms.values()) == n - mx + 1: + for i, i1 in enumerate(inonM): + ifill = inonM[:i] + inonM[i+1:] + for j in ifill: + rv[j] = M + for p in permutations([s[j] for j in ifill]): + rv[i1] = s[i1] + for j, pi in zip(iM, p): + rv[j] = pi + k = i1 + for j in iM: + rv[j], rv[k] = rv[k], rv[j] + yield rv + k = j + # clean-up (and encourages proper use of routine) + rv[:] = [None]*n + return + + ## general case is handled with 3 helpers: + # 1) `finish_derangements` will place the last two elements + # which have arbitrary multiplicities, e.g. for multiset + # {c: 3, a: 2, b: 2}, the last two elements are a and b + # 2) `iopen` will tell where a given element can be placed + # 3) `do` will recursively place elements into subsets of + # valid locations + + def finish_derangements(): + """Place the last two elements into the partially completed + derangement, and yield the results. + """ + + a = take[1][0] # penultimate element + a_ct = take[1][1] + b = take[0][0] # last element to be placed + b_ct = take[0][1] + + # split the indexes of the not-already-assigned elements of rv into + # three categories + forced_a = [] # positions which must have an a + forced_b = [] # positions which must have a b + open_free = [] # positions which could take either + for i in range(len(s)): + if rv[i] is None: + if s[i] == a: + forced_b.append(i) + elif s[i] == b: + forced_a.append(i) + else: + open_free.append(i) + + if len(forced_a) > a_ct or len(forced_b) > b_ct: + # No derangement possible + return + + for i in forced_a: + rv[i] = a + for i in forced_b: + rv[i] = b + for a_place in combinations(open_free, a_ct - len(forced_a)): + for a_pos in a_place: + rv[a_pos] = a + for i in open_free: + if rv[i] is None: # anything not in the subset is set to b + rv[i] = b + yield rv + # Clean up/undo the final placements + for i in open_free: + rv[i] = None + + # additional cleanup - clear forced_a, forced_b + for i in forced_a: + rv[i] = None + for i in forced_b: + rv[i] = None + + def iopen(v): + # return indices at which element v can be placed in rv: + # locations which are not already occupied if that location + # does not already contain v in the same location of s + return [i for i in range(n) if rv[i] is None and s[i] != v] + + def do(j): + if j == 1: + # handle the last two elements (regardless of multiplicity) + # with a special method + yield from finish_derangements() + else: + # place the mx elements of M into a subset of places + # into which it can be replaced + M, mx = take[j] + for i in combinations(iopen(M), mx): + # place M + for ii in i: + rv[ii] = M + # recursively place the next element + yield from do(j - 1) + # mark positions where M was placed as once again + # open for placement of other elements + for ii in i: + rv[ii] = None + + # process elements in order of canonically decreasing multiplicity + take = sorted(ms.items(), key=lambda x:(x[1], x[0])) + yield from do(len(take) - 1) + rv[:] = [None]*n + + +def random_derangement(t, choice=None, strict=True): + """Return a list of elements in which none are in the same positions + as they were originally. If an element fills more than half of the positions + then an error will be raised since no derangement is possible. To obtain + a derangement of as many items as possible--with some of the most numerous + remaining in their original positions--pass `strict=False`. To produce a + pseudorandom derangment, pass a pseudorandom selector like `choice` (see + below). + + Examples + ======== + + >>> from sympy.utilities.iterables import random_derangement + >>> t = 'SymPy: a CAS in pure Python' + >>> d = random_derangement(t) + >>> all(i != j for i, j in zip(d, t)) + True + + A predictable result can be obtained by using a pseudorandom + generator for the choice: + + >>> from sympy.core.random import seed, choice as c + >>> seed(1) + >>> d = [''.join(random_derangement(t, c)) for i in range(5)] + >>> assert len(set(d)) != 1 # we got different values + + By reseeding, the same sequence can be obtained: + + >>> seed(1) + >>> d2 = [''.join(random_derangement(t, c)) for i in range(5)] + >>> assert d == d2 + """ + if choice is None: + import secrets + choice = secrets.choice + def shuffle(rv): + '''Knuth shuffle''' + for i in range(len(rv) - 1, 0, -1): + x = choice(rv[:i + 1]) + j = rv.index(x) + rv[i], rv[j] = rv[j], rv[i] + def pick(rv, n): + '''shuffle rv and return the first n values + ''' + shuffle(rv) + return rv[:n] + ms = multiset(t) + tot = len(t) + ms = sorted(ms.items(), key=lambda x: x[1]) + # if there are not enough spaces for the most + # plentiful element to move to then some of them + # will have to stay in place + M, mx = ms[-1] + n = len(t) + xs = 2*mx - tot + if xs > 0: + if strict: + raise ValueError('no derangement possible') + opts = [i for (i, c) in enumerate(t) if c == ms[-1][0]] + pick(opts, xs) + stay = sorted(opts[:xs]) + rv = list(t) + for i in reversed(stay): + rv.pop(i) + rv = random_derangement(rv, choice) + for i in stay: + rv.insert(i, ms[-1][0]) + return ''.join(rv) if type(t) is str else rv + # the normal derangement calculated from here + if n == len(ms): + # approx 1/3 will succeed + rv = list(t) + while True: + shuffle(rv) + if all(i != j for i,j in zip(rv, t)): + break + else: + # general case + rv = [None]*n + while True: + j = 0 + while j > -len(ms): # do most numerous first + j -= 1 + e, c = ms[j] + opts = [i for i in range(n) if rv[i] is None and t[i] != e] + if len(opts) < c: + for i in range(n): + rv[i] = None + break # try again + pick(opts, c) + for i in range(c): + rv[opts[i]] = e + else: + return rv + return rv + + +def _set_derangements(s): + """ + yield derangements of items in ``s`` which are assumed to contain + no repeated elements + """ + if len(s) < 2: + return + if len(s) == 2: + yield [s[1], s[0]] + return + if len(s) == 3: + yield [s[1], s[2], s[0]] + yield [s[2], s[0], s[1]] + return + for p in permutations(s): + if not any(i == j for i, j in zip(p, s)): + yield list(p) + + +def generate_derangements(s): + """ + Return unique derangements of the elements of iterable ``s``. + + Examples + ======== + + >>> from sympy.utilities.iterables import generate_derangements + >>> list(generate_derangements([0, 1, 2])) + [[1, 2, 0], [2, 0, 1]] + >>> list(generate_derangements([0, 1, 2, 2])) + [[2, 2, 0, 1], [2, 2, 1, 0]] + >>> list(generate_derangements([0, 1, 1])) + [] + + See Also + ======== + + sympy.functions.combinatorial.factorials.subfactorial + + """ + if not has_dups(s): + yield from _set_derangements(s) + else: + for p in multiset_derangements(s): + yield list(p) + + +def necklaces(n, k, free=False): + """ + A routine to generate necklaces that may (free=True) or may not + (free=False) be turned over to be viewed. The "necklaces" returned + are comprised of ``n`` integers (beads) with ``k`` different + values (colors). Only unique necklaces are returned. + + Examples + ======== + + >>> from sympy.utilities.iterables import necklaces, bracelets + >>> def show(s, i): + ... return ''.join(s[j] for j in i) + + The "unrestricted necklace" is sometimes also referred to as a + "bracelet" (an object that can be turned over, a sequence that can + be reversed) and the term "necklace" is used to imply a sequence + that cannot be reversed. So ACB == ABC for a bracelet (rotate and + reverse) while the two are different for a necklace since rotation + alone cannot make the two sequences the same. + + (mnemonic: Bracelets can be viewed Backwards, but Not Necklaces.) + + >>> B = [show('ABC', i) for i in bracelets(3, 3)] + >>> N = [show('ABC', i) for i in necklaces(3, 3)] + >>> set(N) - set(B) + {'ACB'} + + >>> list(necklaces(4, 2)) + [(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 1), + (0, 1, 0, 1), (0, 1, 1, 1), (1, 1, 1, 1)] + + >>> [show('.o', i) for i in bracelets(4, 2)] + ['....', '...o', '..oo', '.o.o', '.ooo', 'oooo'] + + References + ========== + + .. [1] https://mathworld.wolfram.com/Necklace.html + + .. [2] Frank Ruskey, Carla Savage, and Terry Min Yih Wang, + Generating necklaces, Journal of Algorithms 13 (1992), 414-430; + https://doi.org/10.1016/0196-6774(92)90047-G + + """ + # The FKM algorithm + if k == 0 and n > 0: + return + a = [0]*n + yield tuple(a) + if n == 0: + return + while True: + i = n - 1 + while a[i] == k - 1: + i -= 1 + if i == -1: + return + a[i] += 1 + for j in range(n - i - 1): + a[j + i + 1] = a[j] + if n % (i + 1) == 0 and (not free or all(a <= a[j::-1] + a[-1:j:-1] for j in range(n - 1))): + # No need to test j = n - 1. + yield tuple(a) + + +def bracelets(n, k): + """Wrapper to necklaces to return a free (unrestricted) necklace.""" + return necklaces(n, k, free=True) + + +def generate_oriented_forest(n): + """ + This algorithm generates oriented forests. + + An oriented graph is a directed graph having no symmetric pair of directed + edges. A forest is an acyclic graph, i.e., it has no cycles. A forest can + also be described as a disjoint union of trees, which are graphs in which + any two vertices are connected by exactly one simple path. + + Examples + ======== + + >>> from sympy.utilities.iterables import generate_oriented_forest + >>> list(generate_oriented_forest(4)) + [[0, 1, 2, 3], [0, 1, 2, 2], [0, 1, 2, 1], [0, 1, 2, 0], \ + [0, 1, 1, 1], [0, 1, 1, 0], [0, 1, 0, 1], [0, 1, 0, 0], [0, 0, 0, 0]] + + References + ========== + + .. [1] T. Beyer and S.M. Hedetniemi: constant time generation of + rooted trees, SIAM J. Computing Vol. 9, No. 4, November 1980 + + .. [2] https://stackoverflow.com/questions/1633833/oriented-forest-taocp-algorithm-in-python + + """ + P = list(range(-1, n)) + while True: + yield P[1:] + if P[n] > 0: + P[n] = P[P[n]] + else: + for p in range(n - 1, 0, -1): + if P[p] != 0: + target = P[p] - 1 + for q in range(p - 1, 0, -1): + if P[q] == target: + break + offset = p - q + for i in range(p, n + 1): + P[i] = P[i - offset] + break + else: + break + + +def minlex(seq, directed=True, key=None): + r""" + Return the rotation of the sequence in which the lexically smallest + elements appear first, e.g. `cba \rightarrow acb`. + + The sequence returned is a tuple, unless the input sequence is a string + in which case a string is returned. + + If ``directed`` is False then the smaller of the sequence and the + reversed sequence is returned, e.g. `cba \rightarrow abc`. + + If ``key`` is not None then it is used to extract a comparison key from each element in iterable. + + Examples + ======== + + >>> from sympy.combinatorics.polyhedron import minlex + >>> minlex((1, 2, 0)) + (0, 1, 2) + >>> minlex((1, 0, 2)) + (0, 2, 1) + >>> minlex((1, 0, 2), directed=False) + (0, 1, 2) + + >>> minlex('11010011000', directed=True) + '00011010011' + >>> minlex('11010011000', directed=False) + '00011001011' + + >>> minlex(('bb', 'aaa', 'c', 'a')) + ('a', 'bb', 'aaa', 'c') + >>> minlex(('bb', 'aaa', 'c', 'a'), key=len) + ('c', 'a', 'bb', 'aaa') + + """ + from sympy.functions.elementary.miscellaneous import Id + if key is None: key = Id + best = rotate_left(seq, least_rotation(seq, key=key)) + if not directed: + rseq = seq[::-1] + rbest = rotate_left(rseq, least_rotation(rseq, key=key)) + best = min(best, rbest, key=key) + + # Convert to tuple, unless we started with a string. + return tuple(best) if not isinstance(seq, str) else best + + +def runs(seq, op=gt): + """Group the sequence into lists in which successive elements + all compare the same with the comparison operator, ``op``: + op(seq[i + 1], seq[i]) is True from all elements in a run. + + Examples + ======== + + >>> from sympy.utilities.iterables import runs + >>> from operator import ge + >>> runs([0, 1, 2, 2, 1, 4, 3, 2, 2]) + [[0, 1, 2], [2], [1, 4], [3], [2], [2]] + >>> runs([0, 1, 2, 2, 1, 4, 3, 2, 2], op=ge) + [[0, 1, 2, 2], [1, 4], [3], [2, 2]] + """ + cycles = [] + seq = iter(seq) + try: + run = [next(seq)] + except StopIteration: + return [] + while True: + try: + ei = next(seq) + except StopIteration: + break + if op(ei, run[-1]): + run.append(ei) + continue + else: + cycles.append(run) + run = [ei] + if run: + cycles.append(run) + return cycles + + +def sequence_partitions(l, n, /): + r"""Returns the partition of sequence $l$ into $n$ bins + + Explanation + =========== + + Given the sequence $l_1 \cdots l_m \in V^+$ where + $V^+$ is the Kleene plus of $V$ + + The set of $n$ partitions of $l$ is defined as: + + .. math:: + \{(s_1, \cdots, s_n) | s_1 \in V^+, \cdots, s_n \in V^+, + s_1 \cdots s_n = l_1 \cdots l_m\} + + Parameters + ========== + + l : Sequence[T] + A nonempty sequence of any Python objects + + n : int + A positive integer + + Yields + ====== + + out : list[Sequence[T]] + A list of sequences with concatenation equals $l$. + This should conform with the type of $l$. + + Examples + ======== + + >>> from sympy.utilities.iterables import sequence_partitions + >>> for out in sequence_partitions([1, 2, 3, 4], 2): + ... print(out) + [[1], [2, 3, 4]] + [[1, 2], [3, 4]] + [[1, 2, 3], [4]] + + Notes + ===== + + This is modified version of EnricoGiampieri's partition generator + from https://stackoverflow.com/questions/13131491/partition-n-items-into-k-bins-in-python-lazily + + See Also + ======== + + sequence_partitions_empty + """ + # Asserting l is nonempty is done only for sanity check + if n == 1 and l: + yield [l] + return + for i in range(1, len(l)): + for part in sequence_partitions(l[i:], n - 1): + yield [l[:i]] + part + + +def sequence_partitions_empty(l, n, /): + r"""Returns the partition of sequence $l$ into $n$ bins with + empty sequence + + Explanation + =========== + + Given the sequence $l_1 \cdots l_m \in V^*$ where + $V^*$ is the Kleene star of $V$ + + The set of $n$ partitions of $l$ is defined as: + + .. math:: + \{(s_1, \cdots, s_n) | s_1 \in V^*, \cdots, s_n \in V^*, + s_1 \cdots s_n = l_1 \cdots l_m\} + + There are more combinations than :func:`sequence_partitions` because + empty sequence can fill everywhere, so we try to provide different + utility for this. + + Parameters + ========== + + l : Sequence[T] + A sequence of any Python objects (can be possibly empty) + + n : int + A positive integer + + Yields + ====== + + out : list[Sequence[T]] + A list of sequences with concatenation equals $l$. + This should conform with the type of $l$. + + Examples + ======== + + >>> from sympy.utilities.iterables import sequence_partitions_empty + >>> for out in sequence_partitions_empty([1, 2, 3, 4], 2): + ... print(out) + [[], [1, 2, 3, 4]] + [[1], [2, 3, 4]] + [[1, 2], [3, 4]] + [[1, 2, 3], [4]] + [[1, 2, 3, 4], []] + + See Also + ======== + + sequence_partitions + """ + if n < 1: + return + if n == 1: + yield [l] + return + for i in range(0, len(l) + 1): + for part in sequence_partitions_empty(l[i:], n - 1): + yield [l[:i]] + part + + +def kbins(l, k, ordered=None): + """ + Return sequence ``l`` partitioned into ``k`` bins. + + Examples + ======== + + The default is to give the items in the same order, but grouped + into k partitions without any reordering: + + >>> from sympy.utilities.iterables import kbins + >>> for p in kbins(list(range(5)), 2): + ... print(p) + ... + [[0], [1, 2, 3, 4]] + [[0, 1], [2, 3, 4]] + [[0, 1, 2], [3, 4]] + [[0, 1, 2, 3], [4]] + + The ``ordered`` flag is either None (to give the simple partition + of the elements) or is a 2 digit integer indicating whether the order of + the bins and the order of the items in the bins matters. Given:: + + A = [[0], [1, 2]] + B = [[1, 2], [0]] + C = [[2, 1], [0]] + D = [[0], [2, 1]] + + the following values for ``ordered`` have the shown meanings:: + + 00 means A == B == C == D + 01 means A == B + 10 means A == D + 11 means A == A + + >>> for ordered_flag in [None, 0, 1, 10, 11]: + ... print('ordered = %s' % ordered_flag) + ... for p in kbins(list(range(3)), 2, ordered=ordered_flag): + ... print(' %s' % p) + ... + ordered = None + [[0], [1, 2]] + [[0, 1], [2]] + ordered = 0 + [[0, 1], [2]] + [[0, 2], [1]] + [[0], [1, 2]] + ordered = 1 + [[0], [1, 2]] + [[0], [2, 1]] + [[1], [0, 2]] + [[1], [2, 0]] + [[2], [0, 1]] + [[2], [1, 0]] + ordered = 10 + [[0, 1], [2]] + [[2], [0, 1]] + [[0, 2], [1]] + [[1], [0, 2]] + [[0], [1, 2]] + [[1, 2], [0]] + ordered = 11 + [[0], [1, 2]] + [[0, 1], [2]] + [[0], [2, 1]] + [[0, 2], [1]] + [[1], [0, 2]] + [[1, 0], [2]] + [[1], [2, 0]] + [[1, 2], [0]] + [[2], [0, 1]] + [[2, 0], [1]] + [[2], [1, 0]] + [[2, 1], [0]] + + See Also + ======== + + partitions, multiset_partitions + + """ + if ordered is None: + yield from sequence_partitions(l, k) + elif ordered == 11: + for pl in multiset_permutations(l): + pl = list(pl) + yield from sequence_partitions(pl, k) + elif ordered == 00: + yield from multiset_partitions(l, k) + elif ordered == 10: + for p in multiset_partitions(l, k): + for perm in permutations(p): + yield list(perm) + elif ordered == 1: + for kgot, p in partitions(len(l), k, size=True): + if kgot != k: + continue + for li in multiset_permutations(l): + rv = [] + i = j = 0 + li = list(li) + for size, multiplicity in sorted(p.items()): + for m in range(multiplicity): + j = i + size + rv.append(li[i: j]) + i = j + yield rv + else: + raise ValueError( + 'ordered must be one of 00, 01, 10 or 11, not %s' % ordered) + + +def permute_signs(t): + """Return iterator in which the signs of non-zero elements + of t are permuted. + + Examples + ======== + + >>> from sympy.utilities.iterables import permute_signs + >>> list(permute_signs((0, 1, 2))) + [(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2)] + """ + for signs in product(*[(1, -1)]*(len(t) - t.count(0))): + signs = list(signs) + yield type(t)([i*signs.pop() if i else i for i in t]) + + +def signed_permutations(t): + """Return iterator in which the signs of non-zero elements + of t and the order of the elements are permuted and all + returned values are unique. + + Examples + ======== + + >>> from sympy.utilities.iterables import signed_permutations + >>> list(signed_permutations((0, 1, 2))) + [(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2), (0, 2, 1), + (0, -2, 1), (0, 2, -1), (0, -2, -1), (1, 0, 2), (-1, 0, 2), + (1, 0, -2), (-1, 0, -2), (1, 2, 0), (-1, 2, 0), (1, -2, 0), + (-1, -2, 0), (2, 0, 1), (-2, 0, 1), (2, 0, -1), (-2, 0, -1), + (2, 1, 0), (-2, 1, 0), (2, -1, 0), (-2, -1, 0)] + """ + return (type(t)(i) for j in multiset_permutations(t) + for i in permute_signs(j)) + + +def rotations(s, dir=1): + """Return a generator giving the items in s as list where + each subsequent list has the items rotated to the left (default) + or right (``dir=-1``) relative to the previous list. + + Examples + ======== + + >>> from sympy import rotations + >>> list(rotations([1,2,3])) + [[1, 2, 3], [2, 3, 1], [3, 1, 2]] + >>> list(rotations([1,2,3], -1)) + [[1, 2, 3], [3, 1, 2], [2, 3, 1]] + """ + seq = list(s) + for i in range(len(seq)): + yield seq + seq = rotate_left(seq, dir) + + +def roundrobin(*iterables): + """roundrobin recipe taken from itertools documentation: + https://docs.python.org/3/library/itertools.html#itertools-recipes + + roundrobin('ABC', 'D', 'EF') --> A D E B F C + + Recipe credited to George Sakkis + """ + nexts = cycle(iter(it).__next__ for it in iterables) + + pending = len(iterables) + while pending: + try: + for nxt in nexts: + yield nxt() + except StopIteration: + pending -= 1 + nexts = cycle(islice(nexts, pending)) + + + +class NotIterable: + """ + Use this as mixin when creating a class which is not supposed to + return true when iterable() is called on its instances because + calling list() on the instance, for example, would result in + an infinite loop. + """ + pass + + +def iterable(i, exclude=(str, dict, NotIterable)): + """ + Return a boolean indicating whether ``i`` is SymPy iterable. + True also indicates that the iterator is finite, e.g. you can + call list(...) on the instance. + + When SymPy is working with iterables, it is almost always assuming + that the iterable is not a string or a mapping, so those are excluded + by default. If you want a pure Python definition, make exclude=None. To + exclude multiple items, pass them as a tuple. + + You can also set the _iterable attribute to True or False on your class, + which will override the checks here, including the exclude test. + + As a rule of thumb, some SymPy functions use this to check if they should + recursively map over an object. If an object is technically iterable in + the Python sense but does not desire this behavior (e.g., because its + iteration is not finite, or because iteration might induce an unwanted + computation), it should disable it by setting the _iterable attribute to False. + + See also: is_sequence + + Examples + ======== + + >>> from sympy.utilities.iterables import iterable + >>> from sympy import Tuple + >>> things = [[1], (1,), set([1]), Tuple(1), (j for j in [1, 2]), {1:2}, '1', 1] + >>> for i in things: + ... print('%s %s' % (iterable(i), type(i))) + True <... 'list'> + True <... 'tuple'> + True <... 'set'> + True + True <... 'generator'> + False <... 'dict'> + False <... 'str'> + False <... 'int'> + + >>> iterable({}, exclude=None) + True + >>> iterable({}, exclude=str) + True + >>> iterable("no", exclude=str) + False + + """ + if hasattr(i, '_iterable'): + return i._iterable + try: + iter(i) + except TypeError: + return False + if exclude: + return not isinstance(i, exclude) + return True + + +def is_sequence(i, include=None): + """ + Return a boolean indicating whether ``i`` is a sequence in the SymPy + sense. If anything that fails the test below should be included as + being a sequence for your application, set 'include' to that object's + type; multiple types should be passed as a tuple of types. + + Note: although generators can generate a sequence, they often need special + handling to make sure their elements are captured before the generator is + exhausted, so these are not included by default in the definition of a + sequence. + + See also: iterable + + Examples + ======== + + >>> from sympy.utilities.iterables import is_sequence + >>> from types import GeneratorType + >>> is_sequence([]) + True + >>> is_sequence(set()) + False + >>> is_sequence('abc') + False + >>> is_sequence('abc', include=str) + True + >>> generator = (c for c in 'abc') + >>> is_sequence(generator) + False + >>> is_sequence(generator, include=(str, GeneratorType)) + True + + """ + return (hasattr(i, '__getitem__') and + iterable(i) or + bool(include) and + isinstance(i, include)) + + +@deprecated( + """ + Using postorder_traversal from the sympy.utilities.iterables submodule is + deprecated. + + Instead, use postorder_traversal from the top-level sympy namespace, like + + sympy.postorder_traversal + """, + deprecated_since_version="1.10", + active_deprecations_target="deprecated-traversal-functions-moved") +def postorder_traversal(node, keys=None): + from sympy.core.traversal import postorder_traversal as _postorder_traversal + return _postorder_traversal(node, keys=keys) + + +@deprecated( + """ + Using interactive_traversal from the sympy.utilities.iterables submodule + is deprecated. + + Instead, use interactive_traversal from the top-level sympy namespace, + like + + sympy.interactive_traversal + """, + deprecated_since_version="1.10", + active_deprecations_target="deprecated-traversal-functions-moved") +def interactive_traversal(expr): + from sympy.interactive.traversal import interactive_traversal as _interactive_traversal + return _interactive_traversal(expr) + + +@deprecated( + """ + Importing default_sort_key from sympy.utilities.iterables is deprecated. + Use from sympy import default_sort_key instead. + """, + deprecated_since_version="1.10", +active_deprecations_target="deprecated-sympy-core-compatibility", +) +def default_sort_key(*args, **kwargs): + from sympy import default_sort_key as _default_sort_key + return _default_sort_key(*args, **kwargs) + + +@deprecated( + """ + Importing default_sort_key from sympy.utilities.iterables is deprecated. + Use from sympy import default_sort_key instead. + """, + deprecated_since_version="1.10", +active_deprecations_target="deprecated-sympy-core-compatibility", +) +def ordered(*args, **kwargs): + from sympy import ordered as _ordered + return _ordered(*args, **kwargs) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/lambdify.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/lambdify.py new file mode 100644 index 0000000000000000000000000000000000000000..6807fdaec10963a60ba88d6e1ec6b2951c19241e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/lambdify.py @@ -0,0 +1,1592 @@ +""" +This module provides convenient functions to transform SymPy expressions to +lambda functions which can be used to calculate numerical values very fast. +""" + +from __future__ import annotations +from typing import Any + +import builtins +import inspect +import keyword +import textwrap +import linecache +import weakref + +# Required despite static analysis claiming it is not used +from sympy.external import import_module # noqa:F401 +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.decorator import doctest_depends_on +from sympy.utilities.iterables import (is_sequence, iterable, + NotIterable, flatten) +from sympy.utilities.misc import filldedent + + +__doctest_requires__ = {('lambdify',): ['numpy', 'tensorflow']} + + +# Default namespaces, letting us define translations that can't be defined +# by simple variable maps, like I => 1j +MATH_DEFAULT: dict[str, Any] = {} +CMATH_DEFAULT: dict[str,Any] = {} +MPMATH_DEFAULT: dict[str, Any] = {} +NUMPY_DEFAULT: dict[str, Any] = {"I": 1j} +SCIPY_DEFAULT: dict[str, Any] = {"I": 1j} +CUPY_DEFAULT: dict[str, Any] = {"I": 1j} +JAX_DEFAULT: dict[str, Any] = {"I": 1j} +TENSORFLOW_DEFAULT: dict[str, Any] = {} +TORCH_DEFAULT: dict[str, Any] = {"I": 1j} +SYMPY_DEFAULT: dict[str, Any] = {} +NUMEXPR_DEFAULT: dict[str, Any] = {} + +# These are the namespaces the lambda functions will use. +# These are separate from the names above because they are modified +# throughout this file, whereas the defaults should remain unmodified. + +MATH = MATH_DEFAULT.copy() +CMATH = CMATH_DEFAULT.copy() +MPMATH = MPMATH_DEFAULT.copy() +NUMPY = NUMPY_DEFAULT.copy() +SCIPY = SCIPY_DEFAULT.copy() +CUPY = CUPY_DEFAULT.copy() +JAX = JAX_DEFAULT.copy() +TENSORFLOW = TENSORFLOW_DEFAULT.copy() +TORCH = TORCH_DEFAULT.copy() +SYMPY = SYMPY_DEFAULT.copy() +NUMEXPR = NUMEXPR_DEFAULT.copy() + + +# Mappings between SymPy and other modules function names. +MATH_TRANSLATIONS = { + "ceiling": "ceil", + "E": "e", + "ln": "log", +} + +CMATH_TRANSLATIONS: dict[str, str] = {} + +# NOTE: This dictionary is reused in Function._eval_evalf to allow subclasses +# of Function to automatically evalf. +MPMATH_TRANSLATIONS = { + "Abs": "fabs", + "elliptic_k": "ellipk", + "elliptic_f": "ellipf", + "elliptic_e": "ellipe", + "elliptic_pi": "ellippi", + "ceiling": "ceil", + "chebyshevt": "chebyt", + "chebyshevu": "chebyu", + "assoc_legendre": "legenp", + "E": "e", + "I": "j", + "ln": "log", + #"lowergamma":"lower_gamma", + "oo": "inf", + #"uppergamma":"upper_gamma", + "LambertW": "lambertw", + "MutableDenseMatrix": "matrix", + "ImmutableDenseMatrix": "matrix", + "conjugate": "conj", + "dirichlet_eta": "altzeta", + "Ei": "ei", + "Shi": "shi", + "Chi": "chi", + "Si": "si", + "Ci": "ci", + "RisingFactorial": "rf", + "FallingFactorial": "ff", + "betainc_regularized": "betainc", +} + +NUMPY_TRANSLATIONS: dict[str, str] = { + "Heaviside": "heaviside", +} +SCIPY_TRANSLATIONS: dict[str, str] = { + "jn" : "spherical_jn", + "yn" : "spherical_yn" +} +CUPY_TRANSLATIONS: dict[str, str] = {} +JAX_TRANSLATIONS: dict[str, str] = {} + +TENSORFLOW_TRANSLATIONS: dict[str, str] = {} +TORCH_TRANSLATIONS: dict[str, str] = {} + +NUMEXPR_TRANSLATIONS: dict[str, str] = {} + +# Available modules: +MODULES = { + "math": (MATH, MATH_DEFAULT, MATH_TRANSLATIONS, ("from math import *",)), + "cmath": (CMATH, CMATH_DEFAULT, CMATH_TRANSLATIONS, ("import cmath; from cmath import *",)), + "mpmath": (MPMATH, MPMATH_DEFAULT, MPMATH_TRANSLATIONS, ("from mpmath import *",)), + "numpy": (NUMPY, NUMPY_DEFAULT, NUMPY_TRANSLATIONS, ("import numpy; from numpy import *; from numpy.linalg import *",)), + "scipy": (SCIPY, SCIPY_DEFAULT, SCIPY_TRANSLATIONS, ("import scipy; import numpy; from scipy.special import *",)), + "cupy": (CUPY, CUPY_DEFAULT, CUPY_TRANSLATIONS, ("import cupy",)), + "jax": (JAX, JAX_DEFAULT, JAX_TRANSLATIONS, ("import jax",)), + "tensorflow": (TENSORFLOW, TENSORFLOW_DEFAULT, TENSORFLOW_TRANSLATIONS, ("import tensorflow",)), + "torch": (TORCH, TORCH_DEFAULT, TORCH_TRANSLATIONS, ("import torch",)), + "sympy": (SYMPY, SYMPY_DEFAULT, {}, ( + "from sympy.functions import *", + "from sympy.matrices import *", + "from sympy import Integral, pi, oo, nan, zoo, E, I",)), + "numexpr" : (NUMEXPR, NUMEXPR_DEFAULT, NUMEXPR_TRANSLATIONS, + ("import_module('numexpr')", )), +} + + +def _import(module, reload=False): + """ + Creates a global translation dictionary for module. + + The argument module has to be one of the following strings: "math","cmath" + "mpmath", "numpy", "sympy", "tensorflow", "jax". + These dictionaries map names of Python functions to their equivalent in + other modules. + """ + try: + namespace, namespace_default, translations, import_commands = MODULES[ + module] + except KeyError: + raise NameError( + "'%s' module cannot be used for lambdification" % module) + + # Clear namespace or exit + if namespace != namespace_default: + # The namespace was already generated, don't do it again if not forced. + if reload: + namespace.clear() + namespace.update(namespace_default) + else: + return + + for import_command in import_commands: + if import_command.startswith('import_module'): + module = eval(import_command) + + if module is not None: + namespace.update(module.__dict__) + continue + else: + try: + exec(import_command, {}, namespace) + continue + except ImportError: + pass + + raise ImportError( + "Cannot import '%s' with '%s' command" % (module, import_command)) + + # Add translated names to namespace + for sympyname, translation in translations.items(): + namespace[sympyname] = namespace[translation] + + # For computing the modulus of a SymPy expression we use the builtin abs + # function, instead of the previously used fabs function for all + # translation modules. This is because the fabs function in the math + # module does not accept complex valued arguments. (see issue 9474). The + # only exception, where we don't use the builtin abs function is the + # mpmath translation module, because mpmath.fabs returns mpf objects in + # contrast to abs(). + if 'Abs' not in namespace: + namespace['Abs'] = abs + +# Used for dynamically generated filenames that are inserted into the +# linecache. +_lambdify_generated_counter = 1 + + +@doctest_depends_on(modules=('numpy', 'scipy', 'tensorflow',), python_version=(3,)) +def lambdify(args, expr, modules=None, printer=None, use_imps=True, + dummify=False, cse=False, docstring_limit=1000): + """Convert a SymPy expression into a function that allows for fast + numeric evaluation. + + .. warning:: + This function uses ``exec``, and thus should not be used on + unsanitized input. + + .. deprecated:: 1.7 + Passing a set for the *args* parameter is deprecated as sets are + unordered. Use an ordered iterable such as a list or tuple. + + Explanation + =========== + + For example, to convert the SymPy expression ``sin(x) + cos(x)`` to an + equivalent NumPy function that numerically evaluates it: + + >>> from sympy import sin, cos, symbols, lambdify + >>> import numpy as np + >>> x = symbols('x') + >>> expr = sin(x) + cos(x) + >>> expr + sin(x) + cos(x) + >>> f = lambdify(x, expr, 'numpy') + >>> a = np.array([1, 2]) + >>> f(a) + [1.38177329 0.49315059] + + The primary purpose of this function is to provide a bridge from SymPy + expressions to numerical libraries such as NumPy, SciPy, NumExpr, mpmath, + and tensorflow. In general, SymPy functions do not work with objects from + other libraries, such as NumPy arrays, and functions from numeric + libraries like NumPy or mpmath do not work on SymPy expressions. + ``lambdify`` bridges the two by converting a SymPy expression to an + equivalent numeric function. + + The basic workflow with ``lambdify`` is to first create a SymPy expression + representing whatever mathematical function you wish to evaluate. This + should be done using only SymPy functions and expressions. Then, use + ``lambdify`` to convert this to an equivalent function for numerical + evaluation. For instance, above we created ``expr`` using the SymPy symbol + ``x`` and SymPy functions ``sin`` and ``cos``, then converted it to an + equivalent NumPy function ``f``, and called it on a NumPy array ``a``. + + Parameters + ========== + + args : List[Symbol] + A variable or a list of variables whose nesting represents the + nesting of the arguments that will be passed to the function. + + Variables can be symbols, undefined functions, or matrix symbols. + + >>> from sympy import Eq + >>> from sympy.abc import x, y, z + + The list of variables should match the structure of how the + arguments will be passed to the function. Simply enclose the + parameters as they will be passed in a list. + + To call a function like ``f(x)`` then ``[x]`` + should be the first argument to ``lambdify``; for this + case a single ``x`` can also be used: + + >>> f = lambdify(x, x + 1) + >>> f(1) + 2 + >>> f = lambdify([x], x + 1) + >>> f(1) + 2 + + To call a function like ``f(x, y)`` then ``[x, y]`` will + be the first argument of the ``lambdify``: + + >>> f = lambdify([x, y], x + y) + >>> f(1, 1) + 2 + + To call a function with a single 3-element tuple like + ``f((x, y, z))`` then ``[(x, y, z)]`` will be the first + argument of the ``lambdify``: + + >>> f = lambdify([(x, y, z)], Eq(z**2, x**2 + y**2)) + >>> f((3, 4, 5)) + True + + If two args will be passed and the first is a scalar but + the second is a tuple with two arguments then the items + in the list should match that structure: + + >>> f = lambdify([x, (y, z)], x + y + z) + >>> f(1, (2, 3)) + 6 + + expr : Expr + An expression, list of expressions, or matrix to be evaluated. + + Lists may be nested. + If the expression is a list, the output will also be a list. + + >>> f = lambdify(x, [x, [x + 1, x + 2]]) + >>> f(1) + [1, [2, 3]] + + If it is a matrix, an array will be returned (for the NumPy module). + + >>> from sympy import Matrix + >>> f = lambdify(x, Matrix([x, x + 1])) + >>> f(1) + [[1] + [2]] + + Note that the argument order here (variables then expression) is used + to emulate the Python ``lambda`` keyword. ``lambdify(x, expr)`` works + (roughly) like ``lambda x: expr`` + (see :ref:`lambdify-how-it-works` below). + + modules : str, optional + Specifies the numeric library to use. + + If not specified, *modules* defaults to: + + - ``["scipy", "numpy"]`` if SciPy is installed + - ``["numpy"]`` if only NumPy is installed + - ``["math","cmath", "mpmath", "sympy"]`` if neither is installed. + + That is, SymPy functions are replaced as far as possible by + either ``scipy`` or ``numpy`` functions if available, and Python's + standard library ``math`` and ``cmath``, or ``mpmath`` functions otherwise. + + *modules* can be one of the following types: + + - The strings ``"math"``, ``"cmath"``, ``"mpmath"``, ``"numpy"``, ``"numexpr"``, + ``"scipy"``, ``"sympy"``, or ``"tensorflow"`` or ``"jax"``. This uses the + corresponding printer and namespace mapping for that module. + - A module (e.g., ``math``). This uses the global namespace of the + module. If the module is one of the above known modules, it will + also use the corresponding printer and namespace mapping + (i.e., ``modules=numpy`` is equivalent to ``modules="numpy"``). + - A dictionary that maps names of SymPy functions to arbitrary + functions + (e.g., ``{'sin': custom_sin}``). + - A list that contains a mix of the arguments above, with higher + priority given to entries appearing first + (e.g., to use the NumPy module but override the ``sin`` function + with a custom version, you can use + ``[{'sin': custom_sin}, 'numpy']``). + + dummify : bool, optional + Whether or not the variables in the provided expression that are not + valid Python identifiers are substituted with dummy symbols. + + This allows for undefined functions like ``Function('f')(t)`` to be + supplied as arguments. By default, the variables are only dummified + if they are not valid Python identifiers. + + Set ``dummify=True`` to replace all arguments with dummy symbols + (if ``args`` is not a string) - for example, to ensure that the + arguments do not redefine any built-in names. + + cse : bool, or callable, optional + Large expressions can be computed more efficiently when + common subexpressions are identified and precomputed before + being used multiple time. Finding the subexpressions will make + creation of the 'lambdify' function slower, however. + + When ``True``, ``sympy.simplify.cse`` is used, otherwise (the default) + the user may pass a function matching the ``cse`` signature. + + docstring_limit : int or None + When lambdifying large expressions, a significant proportion of the time + spent inside ``lambdify`` is spent producing a string representation of + the expression for use in the automatically generated docstring of the + returned function. For expressions containing hundreds or more nodes the + resulting docstring often becomes so long and dense that it is difficult + to read. To reduce the runtime of lambdify, the rendering of the full + expression inside the docstring can be disabled. + + When ``None``, the full expression is rendered in the docstring. When + ``0`` or a negative ``int``, an ellipsis is rendering in the docstring + instead of the expression. When a strictly positive ``int``, if the + number of nodes in the expression exceeds ``docstring_limit`` an + ellipsis is rendered in the docstring, otherwise a string representation + of the expression is rendered as normal. The default is ``1000``. + + Examples + ======== + + >>> from sympy.utilities.lambdify import implemented_function + >>> from sympy import sqrt, sin, Matrix + >>> from sympy import Function + >>> from sympy.abc import w, x, y, z + + >>> f = lambdify(x, x**2) + >>> f(2) + 4 + >>> f = lambdify((x, y, z), [z, y, x]) + >>> f(1,2,3) + [3, 2, 1] + >>> f = lambdify(x, sqrt(x)) + >>> f(4) + 2.0 + >>> f = lambdify((x, y), sin(x*y)**2) + >>> f(0, 5) + 0.0 + >>> row = lambdify((x, y), Matrix((x, x + y)).T, modules='sympy') + >>> row(1, 2) + Matrix([[1, 3]]) + + ``lambdify`` can be used to translate SymPy expressions into mpmath + functions. This may be preferable to using ``evalf`` (which uses mpmath on + the backend) in some cases. + + >>> f = lambdify(x, sin(x), 'mpmath') + >>> f(1) + 0.8414709848078965 + + Tuple arguments are handled and the lambdified function should + be called with the same type of arguments as were used to create + the function: + + >>> f = lambdify((x, (y, z)), x + y) + >>> f(1, (2, 4)) + 3 + + The ``flatten`` function can be used to always work with flattened + arguments: + + >>> from sympy.utilities.iterables import flatten + >>> args = w, (x, (y, z)) + >>> vals = 1, (2, (3, 4)) + >>> f = lambdify(flatten(args), w + x + y + z) + >>> f(*flatten(vals)) + 10 + + Functions present in ``expr`` can also carry their own numerical + implementations, in a callable attached to the ``_imp_`` attribute. This + can be used with undefined functions using the ``implemented_function`` + factory: + + >>> f = implemented_function(Function('f'), lambda x: x+1) + >>> func = lambdify(x, f(x)) + >>> func(4) + 5 + + ``lambdify`` always prefers ``_imp_`` implementations to implementations + in other namespaces, unless the ``use_imps`` input parameter is False. + + Usage with Tensorflow: + + >>> import tensorflow as tf + >>> from sympy import Max, sin, lambdify + >>> from sympy.abc import x + + >>> f = Max(x, sin(x)) + >>> func = lambdify(x, f, 'tensorflow') + + After tensorflow v2, eager execution is enabled by default. + If you want to get the compatible result across tensorflow v1 and v2 + as same as this tutorial, run this line. + + >>> tf.compat.v1.enable_eager_execution() + + If you have eager execution enabled, you can get the result out + immediately as you can use numpy. + + If you pass tensorflow objects, you may get an ``EagerTensor`` + object instead of value. + + >>> result = func(tf.constant(1.0)) + >>> print(result) + tf.Tensor(1.0, shape=(), dtype=float32) + >>> print(result.__class__) + + + You can use ``.numpy()`` to get the numpy value of the tensor. + + >>> result.numpy() + 1.0 + + >>> var = tf.Variable(2.0) + >>> result = func(var) # also works for tf.Variable and tf.Placeholder + >>> result.numpy() + 2.0 + + And it works with any shape array. + + >>> tensor = tf.constant([[1.0, 2.0], [3.0, 4.0]]) + >>> result = func(tensor) + >>> result.numpy() + [[1. 2.] + [3. 4.]] + + Notes + ===== + + - For functions involving large array calculations, numexpr can provide a + significant speedup over numpy. Please note that the available functions + for numexpr are more limited than numpy but can be expanded with + ``implemented_function`` and user defined subclasses of Function. If + specified, numexpr may be the only option in modules. The official list + of numexpr functions can be found at: + https://numexpr.readthedocs.io/en/latest/user_guide.html#supported-functions + + - In the above examples, the generated functions can accept scalar + values or numpy arrays as arguments. However, in some cases + the generated function relies on the input being a numpy array: + + >>> import numpy + >>> from sympy import Piecewise + >>> from sympy.testing.pytest import ignore_warnings + >>> f = lambdify(x, Piecewise((x, x <= 1), (1/x, x > 1)), "numpy") + + >>> with ignore_warnings(RuntimeWarning): + ... f(numpy.array([-1, 0, 1, 2])) + [-1. 0. 1. 0.5] + + >>> f(0) + Traceback (most recent call last): + ... + ZeroDivisionError: division by zero + + In such cases, the input should be wrapped in a numpy array: + + >>> with ignore_warnings(RuntimeWarning): + ... float(f(numpy.array([0]))) + 0.0 + + Or if numpy functionality is not required another module can be used: + + >>> f = lambdify(x, Piecewise((x, x <= 1), (1/x, x > 1)), "math") + >>> f(0) + 0 + + .. _lambdify-how-it-works: + + How it works + ============ + + When using this function, it helps a great deal to have an idea of what it + is doing. At its core, lambdify is nothing more than a namespace + translation, on top of a special printer that makes some corner cases work + properly. + + To understand lambdify, first we must properly understand how Python + namespaces work. Say we had two files. One called ``sin_cos_sympy.py``, + with + + .. code:: python + + # sin_cos_sympy.py + + from sympy.functions.elementary.trigonometric import (cos, sin) + + def sin_cos(x): + return sin(x) + cos(x) + + + and one called ``sin_cos_numpy.py`` with + + .. code:: python + + # sin_cos_numpy.py + + from numpy import sin, cos + + def sin_cos(x): + return sin(x) + cos(x) + + The two files define an identical function ``sin_cos``. However, in the + first file, ``sin`` and ``cos`` are defined as the SymPy ``sin`` and + ``cos``. In the second, they are defined as the NumPy versions. + + If we were to import the first file and use the ``sin_cos`` function, we + would get something like + + >>> from sin_cos_sympy import sin_cos # doctest: +SKIP + >>> sin_cos(1) # doctest: +SKIP + cos(1) + sin(1) + + On the other hand, if we imported ``sin_cos`` from the second file, we + would get + + >>> from sin_cos_numpy import sin_cos # doctest: +SKIP + >>> sin_cos(1) # doctest: +SKIP + 1.38177329068 + + In the first case we got a symbolic output, because it used the symbolic + ``sin`` and ``cos`` functions from SymPy. In the second, we got a numeric + result, because ``sin_cos`` used the numeric ``sin`` and ``cos`` functions + from NumPy. But notice that the versions of ``sin`` and ``cos`` that were + used was not inherent to the ``sin_cos`` function definition. Both + ``sin_cos`` definitions are exactly the same. Rather, it was based on the + names defined at the module where the ``sin_cos`` function was defined. + + The key point here is that when function in Python references a name that + is not defined in the function, that name is looked up in the "global" + namespace of the module where that function is defined. + + Now, in Python, we can emulate this behavior without actually writing a + file to disk using the ``exec`` function. ``exec`` takes a string + containing a block of Python code, and a dictionary that should contain + the global variables of the module. It then executes the code "in" that + dictionary, as if it were the module globals. The following is equivalent + to the ``sin_cos`` defined in ``sin_cos_sympy.py``: + + >>> import sympy + >>> module_dictionary = {'sin': sympy.sin, 'cos': sympy.cos} + >>> exec(''' + ... def sin_cos(x): + ... return sin(x) + cos(x) + ... ''', module_dictionary) + >>> sin_cos = module_dictionary['sin_cos'] + >>> sin_cos(1) + cos(1) + sin(1) + + and similarly with ``sin_cos_numpy``: + + >>> import numpy + >>> module_dictionary = {'sin': numpy.sin, 'cos': numpy.cos} + >>> exec(''' + ... def sin_cos(x): + ... return sin(x) + cos(x) + ... ''', module_dictionary) + >>> sin_cos = module_dictionary['sin_cos'] + >>> sin_cos(1) + 1.38177329068 + + So now we can get an idea of how ``lambdify`` works. The name "lambdify" + comes from the fact that we can think of something like ``lambdify(x, + sin(x) + cos(x), 'numpy')`` as ``lambda x: sin(x) + cos(x)``, where + ``sin`` and ``cos`` come from the ``numpy`` namespace. This is also why + the symbols argument is first in ``lambdify``, as opposed to most SymPy + functions where it comes after the expression: to better mimic the + ``lambda`` keyword. + + ``lambdify`` takes the input expression (like ``sin(x) + cos(x)``) and + + 1. Converts it to a string + 2. Creates a module globals dictionary based on the modules that are + passed in (by default, it uses the NumPy module) + 3. Creates the string ``"def func({vars}): return {expr}"``, where ``{vars}`` is the + list of variables separated by commas, and ``{expr}`` is the string + created in step 1., then ``exec``s that string with the module globals + namespace and returns ``func``. + + In fact, functions returned by ``lambdify`` support inspection. So you can + see exactly how they are defined by using ``inspect.getsource``, or ``??`` if you + are using IPython or the Jupyter notebook. + + >>> f = lambdify(x, sin(x) + cos(x)) + >>> import inspect + >>> print(inspect.getsource(f)) + def _lambdifygenerated(x): + return sin(x) + cos(x) + + This shows us the source code of the function, but not the namespace it + was defined in. We can inspect that by looking at the ``__globals__`` + attribute of ``f``: + + >>> f.__globals__['sin'] + + >>> f.__globals__['cos'] + + >>> f.__globals__['sin'] is numpy.sin + True + + This shows us that ``sin`` and ``cos`` in the namespace of ``f`` will be + ``numpy.sin`` and ``numpy.cos``. + + Note that there are some convenience layers in each of these steps, but at + the core, this is how ``lambdify`` works. Step 1 is done using the + ``LambdaPrinter`` printers defined in the printing module (see + :mod:`sympy.printing.lambdarepr`). This allows different SymPy expressions + to define how they should be converted to a string for different modules. + You can change which printer ``lambdify`` uses by passing a custom printer + in to the ``printer`` argument. + + Step 2 is augmented by certain translations. There are default + translations for each module, but you can provide your own by passing a + list to the ``modules`` argument. For instance, + + >>> def mysin(x): + ... print('taking the sin of', x) + ... return numpy.sin(x) + ... + >>> f = lambdify(x, sin(x), [{'sin': mysin}, 'numpy']) + >>> f(1) + taking the sin of 1 + 0.8414709848078965 + + The globals dictionary is generated from the list by merging the + dictionary ``{'sin': mysin}`` and the module dictionary for NumPy. The + merging is done so that earlier items take precedence, which is why + ``mysin`` is used above instead of ``numpy.sin``. + + If you want to modify the way ``lambdify`` works for a given function, it + is usually easiest to do so by modifying the globals dictionary as such. + In more complicated cases, it may be necessary to create and pass in a + custom printer. + + Finally, step 3 is augmented with certain convenience operations, such as + the addition of a docstring. + + Understanding how ``lambdify`` works can make it easier to avoid certain + gotchas when using it. For instance, a common mistake is to create a + lambdified function for one module (say, NumPy), and pass it objects from + another (say, a SymPy expression). + + For instance, say we create + + >>> from sympy.abc import x + >>> f = lambdify(x, x + 1, 'numpy') + + Now if we pass in a NumPy array, we get that array plus 1 + + >>> import numpy + >>> a = numpy.array([1, 2]) + >>> f(a) + [2 3] + + But what happens if you make the mistake of passing in a SymPy expression + instead of a NumPy array: + + >>> f(x + 1) + x + 2 + + This worked, but it was only by accident. Now take a different lambdified + function: + + >>> from sympy import sin + >>> g = lambdify(x, x + sin(x), 'numpy') + + This works as expected on NumPy arrays: + + >>> g(a) + [1.84147098 2.90929743] + + But if we try to pass in a SymPy expression, it fails + + >>> g(x + 1) + Traceback (most recent call last): + ... + TypeError: loop of ufunc does not support argument 0 of type Add which has + no callable sin method + + Now, let's look at what happened. The reason this fails is that ``g`` + calls ``numpy.sin`` on the input expression, and ``numpy.sin`` does not + know how to operate on a SymPy object. **As a general rule, NumPy + functions do not know how to operate on SymPy expressions, and SymPy + functions do not know how to operate on NumPy arrays. This is why lambdify + exists: to provide a bridge between SymPy and NumPy.** + + However, why is it that ``f`` did work? That's because ``f`` does not call + any functions, it only adds 1. So the resulting function that is created, + ``def _lambdifygenerated(x): return x + 1`` does not depend on the globals + namespace it is defined in. Thus it works, but only by accident. A future + version of ``lambdify`` may remove this behavior. + + Be aware that certain implementation details described here may change in + future versions of SymPy. The API of passing in custom modules and + printers will not change, but the details of how a lambda function is + created may change. However, the basic idea will remain the same, and + understanding it will be helpful to understanding the behavior of + lambdify. + + **In general: you should create lambdified functions for one module (say, + NumPy), and only pass it input types that are compatible with that module + (say, NumPy arrays).** Remember that by default, if the ``module`` + argument is not provided, ``lambdify`` creates functions using the NumPy + and SciPy namespaces. + """ + from sympy.core.symbol import Symbol + from sympy.core.expr import Expr + + # If the user hasn't specified any modules, use what is available. + if modules is None: + try: + _import("scipy") + except ImportError: + try: + _import("numpy") + except ImportError: + # Use either numpy (if available) or python.math where possible. + # XXX: This leads to different behaviour on different systems and + # might be the reason for irreproducible errors. + modules = ["math", "mpmath", "sympy"] + else: + modules = ["numpy"] + else: + modules = ["numpy", "scipy"] + + # Get the needed namespaces. + namespaces = [] + # First find any function implementations + if use_imps: + namespaces.append(_imp_namespace(expr)) + # Check for dict before iterating + if isinstance(modules, (dict, str)) or not hasattr(modules, '__iter__'): + namespaces.append(modules) + else: + # consistency check + if _module_present('numexpr', modules) and len(modules) > 1: + raise TypeError("numexpr must be the only item in 'modules'") + namespaces += list(modules) + # fill namespace with first having highest priority + namespace = {} + for m in namespaces[::-1]: + buf = _get_namespace(m) + namespace.update(buf) + + if hasattr(expr, "atoms"): + #Try if you can extract symbols from the expression. + #Move on if expr.atoms in not implemented. + syms = expr.atoms(Symbol) + for term in syms: + namespace.update({str(term): term}) + + if printer is None: + if _module_present('mpmath', namespaces): + from sympy.printing.pycode import MpmathPrinter as Printer # type: ignore + elif _module_present('scipy', namespaces): + from sympy.printing.numpy import SciPyPrinter as Printer # type: ignore + elif _module_present('numpy', namespaces): + from sympy.printing.numpy import NumPyPrinter as Printer # type: ignore + elif _module_present('cupy', namespaces): + from sympy.printing.numpy import CuPyPrinter as Printer # type: ignore + elif _module_present('jax', namespaces): + from sympy.printing.numpy import JaxPrinter as Printer # type: ignore + elif _module_present('numexpr', namespaces): + from sympy.printing.lambdarepr import NumExprPrinter as Printer # type: ignore + elif _module_present('tensorflow', namespaces): + from sympy.printing.tensorflow import TensorflowPrinter as Printer # type: ignore + elif _module_present('torch', namespaces): + from sympy.printing.pytorch import TorchPrinter as Printer # type: ignore + elif _module_present('sympy', namespaces): + from sympy.printing.pycode import SymPyPrinter as Printer # type: ignore + elif _module_present('cmath', namespaces): + from sympy.printing.pycode import CmathPrinter as Printer # type: ignore + else: + from sympy.printing.pycode import PythonCodePrinter as Printer # type: ignore + user_functions = {} + for m in namespaces[::-1]: + if isinstance(m, dict): + for k in m: + user_functions[k] = k + printer = Printer({'fully_qualified_modules': False, 'inline': True, + 'allow_unknown_functions': True, + 'user_functions': user_functions}) + + if isinstance(args, set): + sympy_deprecation_warning( + """ +Passing the function arguments to lambdify() as a set is deprecated. This +leads to unpredictable results since sets are unordered. Instead, use a list +or tuple for the function arguments. + """, + deprecated_since_version="1.6.3", + active_deprecations_target="deprecated-lambdify-arguments-set", + ) + + # Get the names of the args, for creating a docstring + iterable_args = (args,) if isinstance(args, Expr) else args + names = [] + + # Grab the callers frame, for getting the names by inspection (if needed) + callers_local_vars = inspect.currentframe().f_back.f_locals.items() # type: ignore + for n, var in enumerate(iterable_args): + if hasattr(var, 'name'): + names.append(var.name) + else: + # It's an iterable. Try to get name by inspection of calling frame. + name_list = [var_name for var_name, var_val in callers_local_vars + if var_val is var] + if len(name_list) == 1: + names.append(name_list[0]) + else: + # Cannot infer name with certainty. arg_# will have to do. + names.append('arg_' + str(n)) + + # Create the function definition code and execute it + funcname = '_lambdifygenerated' + if _module_present('tensorflow', namespaces): + funcprinter = _TensorflowEvaluatorPrinter(printer, dummify) + else: + funcprinter = _EvaluatorPrinter(printer, dummify) + + if cse == True: + from sympy.simplify.cse_main import cse as _cse + cses, _expr = _cse(expr, list=False) + elif callable(cse): + cses, _expr = cse(expr) + else: + cses, _expr = (), expr + funcstr = funcprinter.doprint(funcname, iterable_args, _expr, cses=cses) + + # Collect the module imports from the code printers. + imp_mod_lines = [] + for mod, keys in (getattr(printer, 'module_imports', None) or {}).items(): + for k in keys: + if k not in namespace: + ln = "from %s import %s" % (mod, k) + try: + exec(ln, {}, namespace) + except ImportError: + # Tensorflow 2.0 has issues with importing a specific + # function from its submodule. + # https://github.com/tensorflow/tensorflow/issues/33022 + ln = "%s = %s.%s" % (k, mod, k) + exec(ln, {}, namespace) + imp_mod_lines.append(ln) + + # Provide lambda expression with builtins, and compatible implementation of range + namespace.update({'builtins':builtins, 'range':range}) + + funclocals = {} + global _lambdify_generated_counter + filename = '' % _lambdify_generated_counter + _lambdify_generated_counter += 1 + c = compile(funcstr, filename, 'exec') + exec(c, namespace, funclocals) + # mtime has to be None or else linecache.checkcache will remove it + linecache.cache[filename] = (len(funcstr), None, funcstr.splitlines(True), filename) # type: ignore + + # Remove the entry from the linecache when the object is garbage collected + def cleanup_linecache(filename): + def _cleanup(): + if filename in linecache.cache: + del linecache.cache[filename] + return _cleanup + + func = funclocals[funcname] + + weakref.finalize(func, cleanup_linecache(filename)) + + # Apply the docstring + sig = "func({})".format(", ".join(str(i) for i in names)) + sig = textwrap.fill(sig, subsequent_indent=' '*8) + if _too_large_for_docstring(expr, docstring_limit): + expr_str = "EXPRESSION REDACTED DUE TO LENGTH, (see lambdify's `docstring_limit`)" + src_str = "SOURCE CODE REDACTED DUE TO LENGTH, (see lambdify's `docstring_limit`)" + else: + expr_str = str(expr) + if len(expr_str) > 78: + expr_str = textwrap.wrap(expr_str, 75)[0] + '...' + src_str = funcstr + func.__doc__ = ( + "Created with lambdify. Signature:\n\n" + "{sig}\n\n" + "Expression:\n\n" + "{expr}\n\n" + "Source code:\n\n" + "{src}\n\n" + "Imported modules:\n\n" + "{imp_mods}" + ).format(sig=sig, expr=expr_str, src=src_str, imp_mods='\n'.join(imp_mod_lines)) + return func + +def _module_present(modname, modlist): + if modname in modlist: + return True + for m in modlist: + if hasattr(m, '__name__') and m.__name__ == modname: + return True + return False + +def _get_namespace(m): + """ + This is used by _lambdify to parse its arguments. + """ + if isinstance(m, str): + _import(m) + return MODULES[m][0] + elif isinstance(m, dict): + return m + elif hasattr(m, "__dict__"): + return m.__dict__ + else: + raise TypeError("Argument must be either a string, dict or module but it is: %s" % m) + + +def _recursive_to_string(doprint, arg): + """Functions in lambdify accept both SymPy types and non-SymPy types such as python + lists and tuples. This method ensures that we only call the doprint method of the + printer with SymPy types (so that the printer safely can use SymPy-methods).""" + from sympy.matrices.matrixbase import MatrixBase + from sympy.core.basic import Basic + + if isinstance(arg, (Basic, MatrixBase)): + return doprint(arg) + elif iterable(arg): + if isinstance(arg, list): + left, right = "[", "]" + elif isinstance(arg, tuple): + left, right = "(", ",)" + if not arg: + return "()" + else: + raise NotImplementedError("unhandled type: %s, %s" % (type(arg), arg)) + return left +', '.join(_recursive_to_string(doprint, e) for e in arg) + right + elif isinstance(arg, str): + return arg + else: + return doprint(arg) + + +def lambdastr(args, expr, printer=None, dummify=None): + """ + Returns a string that can be evaluated to a lambda function. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.utilities.lambdify import lambdastr + >>> lambdastr(x, x**2) + 'lambda x: (x**2)' + >>> lambdastr((x,y,z), [z,y,x]) + 'lambda x,y,z: ([z, y, x])' + + Although tuples may not appear as arguments to lambda in Python 3, + lambdastr will create a lambda function that will unpack the original + arguments so that nested arguments can be handled: + + >>> lambdastr((x, (y, z)), x + y) + 'lambda _0,_1: (lambda x,y,z: (x + y))(_0,_1[0],_1[1])' + """ + # Transforming everything to strings. + from sympy.matrices import DeferredVector + from sympy.core.basic import Basic + from sympy.core.function import (Derivative, Function) + from sympy.core.symbol import (Dummy, Symbol) + from sympy.core.sympify import sympify + + if printer is not None: + if inspect.isfunction(printer): + lambdarepr = printer + else: + if inspect.isclass(printer): + lambdarepr = lambda expr: printer().doprint(expr) + else: + lambdarepr = lambda expr: printer.doprint(expr) + else: + #XXX: This has to be done here because of circular imports + from sympy.printing.lambdarepr import lambdarepr + + def sub_args(args, dummies_dict): + if isinstance(args, str): + return args + elif isinstance(args, DeferredVector): + return str(args) + elif iterable(args): + dummies = flatten([sub_args(a, dummies_dict) for a in args]) + return ",".join(str(a) for a in dummies) + else: + # replace these with Dummy symbols + if isinstance(args, (Function, Symbol, Derivative)): + dummies = Dummy() + dummies_dict.update({args : dummies}) + return str(dummies) + else: + return str(args) + + def sub_expr(expr, dummies_dict): + expr = sympify(expr) + # dict/tuple are sympified to Basic + if isinstance(expr, Basic): + expr = expr.xreplace(dummies_dict) + # list is not sympified to Basic + elif isinstance(expr, list): + expr = [sub_expr(a, dummies_dict) for a in expr] + return expr + + # Transform args + def isiter(l): + return iterable(l, exclude=(str, DeferredVector, NotIterable)) + + def flat_indexes(iterable): + n = 0 + + for el in iterable: + if isiter(el): + for ndeep in flat_indexes(el): + yield (n,) + ndeep + else: + yield (n,) + + n += 1 + + if dummify is None: + dummify = any(isinstance(a, Basic) and + a.atoms(Function, Derivative) for a in ( + args if isiter(args) else [args])) + + if isiter(args) and any(isiter(i) for i in args): + dum_args = [str(Dummy(str(i))) for i in range(len(args))] + + indexed_args = ','.join([ + dum_args[ind[0]] + ''.join(["[%s]" % k for k in ind[1:]]) + for ind in flat_indexes(args)]) + + lstr = lambdastr(flatten(args), expr, printer=printer, dummify=dummify) + + return 'lambda %s: (%s)(%s)' % (','.join(dum_args), lstr, indexed_args) + + dummies_dict = {} + if dummify: + args = sub_args(args, dummies_dict) + else: + if isinstance(args, str): + pass + elif iterable(args, exclude=DeferredVector): + args = ",".join(str(a) for a in args) + + # Transform expr + if dummify: + if isinstance(expr, str): + pass + else: + expr = sub_expr(expr, dummies_dict) + expr = _recursive_to_string(lambdarepr, expr) + return "lambda %s: (%s)" % (args, expr) + +class _EvaluatorPrinter: + def __init__(self, printer=None, dummify=False): + self._dummify = dummify + + #XXX: This has to be done here because of circular imports + from sympy.printing.lambdarepr import LambdaPrinter + + if printer is None: + printer = LambdaPrinter() + + if inspect.isfunction(printer): + self._exprrepr = printer + else: + if inspect.isclass(printer): + printer = printer() + + self._exprrepr = printer.doprint + + #if hasattr(printer, '_print_Symbol'): + # symbolrepr = printer._print_Symbol + + #if hasattr(printer, '_print_Dummy'): + # dummyrepr = printer._print_Dummy + + # Used to print the generated function arguments in a standard way + self._argrepr = LambdaPrinter().doprint + + def doprint(self, funcname, args, expr, *, cses=()): + """ + Returns the function definition code as a string. + """ + from sympy.core.symbol import Dummy + + funcbody = [] + + if not iterable(args): + args = [args] + + if cses: + cses = list(cses) + subvars, subexprs = zip(*cses) + exprs = [expr] + list(subexprs) + argstrs, exprs = self._preprocess(args, exprs, cses=cses) + expr, subexprs = exprs[0], exprs[1:] + cses = zip(subvars, subexprs) + else: + argstrs, expr = self._preprocess(args, expr) + + # Generate argument unpacking and final argument list + funcargs = [] + unpackings = [] + + for argstr in argstrs: + if iterable(argstr): + funcargs.append(self._argrepr(Dummy())) + unpackings.extend(self._print_unpacking(argstr, funcargs[-1])) + else: + funcargs.append(argstr) + + funcsig = 'def {}({}):'.format(funcname, ', '.join(funcargs)) + + # Wrap input arguments before unpacking + funcbody.extend(self._print_funcargwrapping(funcargs)) + + funcbody.extend(unpackings) + + for s, e in cses: + if e is None: + funcbody.append('del {}'.format(self._exprrepr(s))) + else: + funcbody.append('{} = {}'.format(self._exprrepr(s), self._exprrepr(e))) + + # Subs may appear in expressions generated by .diff() + subs_assignments = [] + expr = self._handle_Subs(expr, out=subs_assignments) + for lhs, rhs in subs_assignments: + funcbody.append('{} = {}'.format(self._exprrepr(lhs), self._exprrepr(rhs))) + + str_expr = _recursive_to_string(self._exprrepr, expr) + + if '\n' in str_expr: + str_expr = '({})'.format(str_expr) + funcbody.append('return {}'.format(str_expr)) + + funclines = [funcsig] + funclines.extend([' ' + line for line in funcbody]) + + return '\n'.join(funclines) + '\n' + + @classmethod + def _is_safe_ident(cls, ident): + return isinstance(ident, str) and ident.isidentifier() \ + and not keyword.iskeyword(ident) + + def _preprocess(self, args, expr, cses=(), _dummies_dict=None): + """Preprocess args, expr to replace arguments that do not map + to valid Python identifiers. + + Returns string form of args, and updated expr. + """ + from sympy.core.basic import Basic + from sympy.core.sorting import ordered + from sympy.core.function import (Derivative, Function) + from sympy.core.symbol import Dummy, uniquely_named_symbol + from sympy.matrices import DeferredVector + from sympy.core.expr import Expr + + # Args of type Dummy can cause name collisions with args + # of type Symbol. Force dummify of everything in this + # situation. + dummify = self._dummify or any( + isinstance(arg, Dummy) for arg in flatten(args)) + + argstrs = [None]*len(args) + if _dummies_dict is None: + _dummies_dict = {} + + def update_dummies(arg, dummy): + _dummies_dict[arg] = dummy + for repl, sub in cses: + arg = arg.xreplace({sub: repl}) + _dummies_dict[arg] = dummy + + for arg, i in reversed(list(ordered(zip(args, range(len(args)))))): + if iterable(arg): + s, expr = self._preprocess(arg, expr, cses=cses, _dummies_dict=_dummies_dict) + elif isinstance(arg, DeferredVector): + s = str(arg) + elif isinstance(arg, Basic) and arg.is_symbol: + s = str(arg) + if dummify or not self._is_safe_ident(s): + dummy = Dummy() + if isinstance(expr, Expr): + dummy = uniquely_named_symbol( + dummy.name, expr, modify=lambda s: '_' + s) + s = self._argrepr(dummy) + update_dummies(arg, dummy) + expr = self._subexpr(expr, _dummies_dict) + elif dummify or isinstance(arg, (Function, Derivative)): + dummy = Dummy() + s = self._argrepr(dummy) + update_dummies(arg, dummy) + expr = self._subexpr(expr, _dummies_dict) + else: + s = str(arg) + argstrs[i] = s + return argstrs, expr + + def _subexpr(self, expr, dummies_dict): + from sympy.matrices import DeferredVector + from sympy.core.sympify import sympify + + expr = sympify(expr) + xreplace = getattr(expr, 'xreplace', None) + if xreplace is not None: + expr = xreplace(dummies_dict) + else: + if isinstance(expr, DeferredVector): + pass + elif isinstance(expr, dict): + k = [self._subexpr(sympify(a), dummies_dict) for a in expr.keys()] + v = [self._subexpr(sympify(a), dummies_dict) for a in expr.values()] + expr = dict(zip(k, v)) + elif isinstance(expr, tuple): + expr = tuple(self._subexpr(sympify(a), dummies_dict) for a in expr) + elif isinstance(expr, list): + expr = [self._subexpr(sympify(a), dummies_dict) for a in expr] + return expr + + def _print_funcargwrapping(self, args): + """Generate argument wrapping code. + + args is the argument list of the generated function (strings). + + Return value is a list of lines of code that will be inserted at + the beginning of the function definition. + """ + return [] + + def _print_unpacking(self, unpackto, arg): + """Generate argument unpacking code. + + arg is the function argument to be unpacked (a string), and + unpackto is a list or nested lists of the variable names (strings) to + unpack to. + """ + def unpack_lhs(lvalues): + return '[{}]'.format(', '.join( + unpack_lhs(val) if iterable(val) else val for val in lvalues)) + + return ['{} = {}'.format(unpack_lhs(unpackto), arg)] + + def _handle_Subs(self, expr, out): + """Any instance of Subs is extracted and returned as assignment pairs.""" + from sympy.core.basic import Basic + from sympy.core.function import Subs + from sympy.core.symbol import Dummy + from sympy.matrices.matrixbase import MatrixBase + + def _replace(ex, variables, point): + safe = {} + for lhs, rhs in zip(variables, point): + dummy = Dummy() + safe[lhs] = dummy + out.append((dummy, rhs)) + return ex.xreplace(safe) + + if isinstance(expr, (Basic, MatrixBase)): + expr = expr.replace(Subs, _replace) + elif iterable(expr): + expr = type(expr)([self._handle_Subs(e, out) for e in expr]) + return expr + +class _TensorflowEvaluatorPrinter(_EvaluatorPrinter): + def _print_unpacking(self, lvalues, rvalue): + """Generate argument unpacking code. + + This method is used when the input value is not iterable, + but can be indexed (see issue #14655). + """ + + def flat_indexes(elems): + n = 0 + + for el in elems: + if iterable(el): + for ndeep in flat_indexes(el): + yield (n,) + ndeep + else: + yield (n,) + + n += 1 + + indexed = ', '.join('{}[{}]'.format(rvalue, ']['.join(map(str, ind))) + for ind in flat_indexes(lvalues)) + + return ['[{}] = [{}]'.format(', '.join(flatten(lvalues)), indexed)] + +def _imp_namespace(expr, namespace=None): + """ Return namespace dict with function implementations + + We need to search for functions in anything that can be thrown at + us - that is - anything that could be passed as ``expr``. Examples + include SymPy expressions, as well as tuples, lists and dicts that may + contain SymPy expressions. + + Parameters + ---------- + expr : object + Something passed to lambdify, that will generate valid code from + ``str(expr)``. + namespace : None or mapping + Namespace to fill. None results in new empty dict + + Returns + ------- + namespace : dict + dict with keys of implemented function names within ``expr`` and + corresponding values being the numerical implementation of + function + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.utilities.lambdify import implemented_function, _imp_namespace + >>> from sympy import Function + >>> f = implemented_function(Function('f'), lambda x: x+1) + >>> g = implemented_function(Function('g'), lambda x: x*10) + >>> namespace = _imp_namespace(f(g(x))) + >>> sorted(namespace.keys()) + ['f', 'g'] + """ + # Delayed import to avoid circular imports + from sympy.core.function import FunctionClass + if namespace is None: + namespace = {} + # tuples, lists, dicts are valid expressions + if is_sequence(expr): + for arg in expr: + _imp_namespace(arg, namespace) + return namespace + elif isinstance(expr, dict): + for key, val in expr.items(): + # functions can be in dictionary keys + _imp_namespace(key, namespace) + _imp_namespace(val, namespace) + return namespace + # SymPy expressions may be Functions themselves + func = getattr(expr, 'func', None) + if isinstance(func, FunctionClass): + imp = getattr(func, '_imp_', None) + if imp is not None: + name = expr.func.__name__ + if name in namespace and namespace[name] != imp: + raise ValueError('We found more than one ' + 'implementation with name ' + '"%s"' % name) + namespace[name] = imp + # and / or they may take Functions as arguments + if hasattr(expr, 'args'): + for arg in expr.args: + _imp_namespace(arg, namespace) + return namespace + + +def implemented_function(symfunc, implementation): + """ Add numerical ``implementation`` to function ``symfunc``. + + ``symfunc`` can be an ``UndefinedFunction`` instance, or a name string. + In the latter case we create an ``UndefinedFunction`` instance with that + name. + + Be aware that this is a quick workaround, not a general method to create + special symbolic functions. If you want to create a symbolic function to be + used by all the machinery of SymPy you should subclass the ``Function`` + class. + + Parameters + ---------- + symfunc : ``str`` or ``UndefinedFunction`` instance + If ``str``, then create new ``UndefinedFunction`` with this as + name. If ``symfunc`` is an Undefined function, create a new function + with the same name and the implemented function attached. + implementation : callable + numerical implementation to be called by ``evalf()`` or ``lambdify`` + + Returns + ------- + afunc : sympy.FunctionClass instance + function with attached implementation + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.utilities.lambdify import implemented_function + >>> from sympy import lambdify + >>> f = implemented_function('f', lambda x: x+1) + >>> lam_f = lambdify(x, f(x)) + >>> lam_f(4) + 5 + """ + # Delayed import to avoid circular imports + from sympy.core.function import UndefinedFunction + # if name, create function to hold implementation + kwargs = {} + if isinstance(symfunc, UndefinedFunction): + kwargs = symfunc._kwargs + symfunc = symfunc.__name__ + if isinstance(symfunc, str): + # Keyword arguments to UndefinedFunction are added as attributes to + # the created class. + symfunc = UndefinedFunction( + symfunc, _imp_=staticmethod(implementation), **kwargs) + elif not isinstance(symfunc, UndefinedFunction): + raise ValueError(filldedent(''' + symfunc should be either a string or + an UndefinedFunction instance.''')) + return symfunc + + +def _too_large_for_docstring(expr, limit): + """Decide whether an ``Expr`` is too large to be fully rendered in a + ``lambdify`` docstring. + + This is a fast alternative to ``count_ops``, which can become prohibitively + slow for large expressions, because in this instance we only care whether + ``limit`` is exceeded rather than counting the exact number of nodes in the + expression. + + Parameters + ========== + expr : ``Expr``, (nested) ``list`` of ``Expr``, or ``Matrix`` + The same objects that can be passed to the ``expr`` argument of + ``lambdify``. + limit : ``int`` or ``None`` + The threshold above which an expression contains too many nodes to be + usefully rendered in the docstring. If ``None`` then there is no limit. + + Returns + ======= + bool + ``True`` if the number of nodes in the expression exceeds the limit, + ``False`` otherwise. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.utilities.lambdify import _too_large_for_docstring + >>> expr = x + >>> _too_large_for_docstring(expr, None) + False + >>> _too_large_for_docstring(expr, 100) + False + >>> _too_large_for_docstring(expr, 1) + False + >>> _too_large_for_docstring(expr, 0) + True + >>> _too_large_for_docstring(expr, -1) + True + + Does this split it? + + >>> expr = [x, y, z] + >>> _too_large_for_docstring(expr, None) + False + >>> _too_large_for_docstring(expr, 100) + False + >>> _too_large_for_docstring(expr, 1) + True + >>> _too_large_for_docstring(expr, 0) + True + >>> _too_large_for_docstring(expr, -1) + True + + >>> expr = [x, [y], z, [[x+y], [x*y*z, [x+y+z]]]] + >>> _too_large_for_docstring(expr, None) + False + >>> _too_large_for_docstring(expr, 100) + False + >>> _too_large_for_docstring(expr, 1) + True + >>> _too_large_for_docstring(expr, 0) + True + >>> _too_large_for_docstring(expr, -1) + True + + >>> expr = ((x + y + z)**5).expand() + >>> _too_large_for_docstring(expr, None) + False + >>> _too_large_for_docstring(expr, 100) + True + >>> _too_large_for_docstring(expr, 1) + True + >>> _too_large_for_docstring(expr, 0) + True + >>> _too_large_for_docstring(expr, -1) + True + + >>> from sympy import Matrix + >>> expr = Matrix([[(x + y + z), ((x + y + z)**2).expand(), + ... ((x + y + z)**3).expand(), ((x + y + z)**4).expand()]]) + >>> _too_large_for_docstring(expr, None) + False + >>> _too_large_for_docstring(expr, 1000) + False + >>> _too_large_for_docstring(expr, 100) + True + >>> _too_large_for_docstring(expr, 1) + True + >>> _too_large_for_docstring(expr, 0) + True + >>> _too_large_for_docstring(expr, -1) + True + + """ + # Must be imported here to avoid a circular import error + from sympy.core.traversal import postorder_traversal + + if limit is None: + return False + + i = 0 + for _ in postorder_traversal(expr): + i += 1 + if i > limit: + return True + return False diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/magic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/magic.py new file mode 100644 index 0000000000000000000000000000000000000000..e853a0ad9a85bc252dcb24e8a1ecbfca422ac3fd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/magic.py @@ -0,0 +1,12 @@ +"""Functions that involve magic. """ + +def pollute(names, objects): + """Pollute the global namespace with symbols -> objects mapping. """ + from inspect import currentframe + frame = currentframe().f_back.f_back + + try: + for name, obj in zip(names, objects): + frame.f_globals[name] = obj + finally: + del frame # break cyclic dependencies as stated in inspect docs diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/matchpy_connector.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/matchpy_connector.py new file mode 100644 index 0000000000000000000000000000000000000000..35aa013294b93bbcfe4a1bf4ec96b629ea5a468f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/matchpy_connector.py @@ -0,0 +1,340 @@ +""" +The objects in this module allow the usage of the MatchPy pattern matching +library on SymPy expressions. +""" +import re +from typing import List, Callable, NamedTuple, Any, Dict + +from sympy.core.sympify import _sympify +from sympy.external import import_module +from sympy.functions import (log, sin, cos, tan, cot, csc, sec, erf, gamma, uppergamma) +from sympy.functions.elementary.hyperbolic import acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch +from sympy.functions.elementary.trigonometric import atan, acsc, asin, acot, acos, asec +from sympy.functions.special.error_functions import fresnelc, fresnels, erfc, erfi, Ei +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.expr import Expr +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.relational import (Equality, Unequality) +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import exp +from sympy.integrals.integrals import Integral +from sympy.printing.repr import srepr +from sympy.utilities.decorator import doctest_depends_on + + +matchpy = import_module("matchpy") + + +__doctest_requires__ = {('*',): ['matchpy']} + + +if matchpy: + from matchpy import Operation, CommutativeOperation, AssociativeOperation, OneIdentityOperation + from matchpy.expressions.functions import op_iter, create_operation_expression, op_len + + Operation.register(Integral) + Operation.register(Pow) + OneIdentityOperation.register(Pow) + + Operation.register(Add) + OneIdentityOperation.register(Add) + CommutativeOperation.register(Add) + AssociativeOperation.register(Add) + + Operation.register(Mul) + OneIdentityOperation.register(Mul) + CommutativeOperation.register(Mul) + AssociativeOperation.register(Mul) + + Operation.register(Equality) + CommutativeOperation.register(Equality) + Operation.register(Unequality) + CommutativeOperation.register(Unequality) + + Operation.register(exp) + Operation.register(log) + Operation.register(gamma) + Operation.register(uppergamma) + Operation.register(fresnels) + Operation.register(fresnelc) + Operation.register(erf) + Operation.register(Ei) + Operation.register(erfc) + Operation.register(erfi) + Operation.register(sin) + Operation.register(cos) + Operation.register(tan) + Operation.register(cot) + Operation.register(csc) + Operation.register(sec) + Operation.register(sinh) + Operation.register(cosh) + Operation.register(tanh) + Operation.register(coth) + Operation.register(csch) + Operation.register(sech) + Operation.register(asin) + Operation.register(acos) + Operation.register(atan) + Operation.register(acot) + Operation.register(acsc) + Operation.register(asec) + Operation.register(asinh) + Operation.register(acosh) + Operation.register(atanh) + Operation.register(acoth) + Operation.register(acsch) + Operation.register(asech) + + @op_iter.register(Integral) # type: ignore + def _(operation): + return iter((operation._args[0],) + operation._args[1]) + + @op_iter.register(Basic) # type: ignore + def _(operation): + return iter(operation._args) + + @op_len.register(Integral) # type: ignore + def _(operation): + return 1 + len(operation._args[1]) + + @op_len.register(Basic) # type: ignore + def _(operation): + return len(operation._args) + + @create_operation_expression.register(Basic) + def sympy_op_factory(old_operation, new_operands, variable_name=True): + return type(old_operation)(*new_operands) + + +if matchpy: + from matchpy import Wildcard +else: + class Wildcard: # type: ignore + def __init__(self, min_length, fixed_size, variable_name, optional): + self.min_count = min_length + self.fixed_size = fixed_size + self.variable_name = variable_name + self.optional = optional + + +@doctest_depends_on(modules=('matchpy',)) +class _WildAbstract(Wildcard, Symbol): + min_length: int # abstract field required in subclasses + fixed_size: bool # abstract field required in subclasses + + def __init__(self, variable_name=None, optional=None, **assumptions): + min_length = self.min_length + fixed_size = self.fixed_size + if optional is not None: + optional = _sympify(optional) + Wildcard.__init__(self, min_length, fixed_size, str(variable_name), optional) + + def __getstate__(self): + return { + "min_length": self.min_length, + "fixed_size": self.fixed_size, + "min_count": self.min_count, + "variable_name": self.variable_name, + "optional": self.optional, + } + + def __new__(cls, variable_name=None, optional=None, **assumptions): + cls._sanitize(assumptions, cls) + return _WildAbstract.__xnew__(cls, variable_name, optional, **assumptions) + + def __getnewargs__(self): + return self.variable_name, self.optional + + @staticmethod + def __xnew__(cls, variable_name=None, optional=None, **assumptions): + obj = Symbol.__xnew__(cls, variable_name, **assumptions) + return obj + + def _hashable_content(self): + if self.optional: + return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name, self.optional) + else: + return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name) + + def __copy__(self) -> '_WildAbstract': + return type(self)(variable_name=self.variable_name, optional=self.optional) + + def __repr__(self): + return str(self) + + def __str__(self): + return self.name + + +@doctest_depends_on(modules=('matchpy',)) +class WildDot(_WildAbstract): + min_length = 1 + fixed_size = True + + +@doctest_depends_on(modules=('matchpy',)) +class WildPlus(_WildAbstract): + min_length = 1 + fixed_size = False + + +@doctest_depends_on(modules=('matchpy',)) +class WildStar(_WildAbstract): + min_length = 0 + fixed_size = False + + +def _get_srepr(expr): + s = srepr(expr) + s = re.sub(r"WildDot\('(\w+)'\)", r"\1", s) + s = re.sub(r"WildPlus\('(\w+)'\)", r"*\1", s) + s = re.sub(r"WildStar\('(\w+)'\)", r"*\1", s) + return s + + +class ReplacementInfo(NamedTuple): + replacement: Any + info: Any + + +@doctest_depends_on(modules=('matchpy',)) +class Replacer: + """ + Replacer object to perform multiple pattern matching and subexpression + replacements in SymPy expressions. + + Examples + ======== + + Example to construct a simple first degree equation solver: + + >>> from sympy.utilities.matchpy_connector import WildDot, Replacer + >>> from sympy import Equality, Symbol + >>> x = Symbol("x") + >>> a_ = WildDot("a_", optional=1) + >>> b_ = WildDot("b_", optional=0) + + The lines above have defined two wildcards, ``a_`` and ``b_``, the + coefficients of the equation `a x + b = 0`. The optional values specified + indicate which expression to return in case no match is found, they are + necessary in equations like `a x = 0` and `x + b = 0`. + + Create two constraints to make sure that ``a_`` and ``b_`` will not match + any expression containing ``x``: + + >>> from matchpy import CustomConstraint + >>> free_x_a = CustomConstraint(lambda a_: not a_.has(x)) + >>> free_x_b = CustomConstraint(lambda b_: not b_.has(x)) + + Now create the rule replacer with the constraints: + + >>> replacer = Replacer(common_constraints=[free_x_a, free_x_b]) + + Add the matching rule: + + >>> replacer.add(Equality(a_*x + b_, 0), -b_/a_) + + Let's try it: + + >>> replacer.replace(Equality(3*x + 4, 0)) + -4/3 + + Notice that it will not match equations expressed with other patterns: + + >>> eq = Equality(3*x, 4) + >>> replacer.replace(eq) + Eq(3*x, 4) + + In order to extend the matching patterns, define another one (we also need + to clear the cache, because the previous result has already been memorized + and the pattern matcher will not iterate again if given the same expression) + + >>> replacer.add(Equality(a_*x, b_), b_/a_) + >>> replacer._matcher.clear() + >>> replacer.replace(eq) + 4/3 + """ + + def __init__(self, common_constraints: list = [], lambdify: bool = False, info: bool = False): + self._matcher = matchpy.ManyToOneMatcher() + self._common_constraint = common_constraints + self._lambdify = lambdify + self._info = info + self._wildcards: Dict[str, Wildcard] = {} + + def _get_lambda(self, lambda_str: str) -> Callable[..., Expr]: + exec("from sympy import *") + return eval(lambda_str, locals()) + + def _get_custom_constraint(self, constraint_expr: Expr, condition_template: str) -> Callable[..., Expr]: + wilds = [x.name for x in constraint_expr.atoms(_WildAbstract)] + lambdaargs = ', '.join(wilds) + fullexpr = _get_srepr(constraint_expr) + condition = condition_template.format(fullexpr) + return matchpy.CustomConstraint( + self._get_lambda(f"lambda {lambdaargs}: ({condition})")) + + def _get_custom_constraint_nonfalse(self, constraint_expr: Expr) -> Callable[..., Expr]: + return self._get_custom_constraint(constraint_expr, "({}) != False") + + def _get_custom_constraint_true(self, constraint_expr: Expr) -> Callable[..., Expr]: + return self._get_custom_constraint(constraint_expr, "({}) == True") + + def add(self, expr: Expr, replacement, conditions_true: List[Expr] = [], + conditions_nonfalse: List[Expr] = [], info: Any = None) -> None: + expr = _sympify(expr) + replacement = _sympify(replacement) + constraints = self._common_constraint[:] + constraint_conditions_true = [ + self._get_custom_constraint_true(cond) for cond in conditions_true] + constraint_conditions_nonfalse = [ + self._get_custom_constraint_nonfalse(cond) for cond in conditions_nonfalse] + constraints.extend(constraint_conditions_true) + constraints.extend(constraint_conditions_nonfalse) + pattern = matchpy.Pattern(expr, *constraints) + if self._lambdify: + lambda_str = f"lambda {', '.join((x.name for x in expr.atoms(_WildAbstract)))}: {_get_srepr(replacement)}" + lambda_expr = self._get_lambda(lambda_str) + replacement = lambda_expr + else: + self._wildcards.update({str(i): i for i in expr.atoms(Wildcard)}) + if self._info: + replacement = ReplacementInfo(replacement, info) + self._matcher.add(pattern, replacement) + + def replace(self, expression, max_count: int = -1): + # This method partly rewrites the .replace method of ManyToOneReplacer + # in MatchPy. + # License: https://github.com/HPAC/matchpy/blob/master/LICENSE + infos = [] + replaced = True + replace_count = 0 + while replaced and (max_count < 0 or replace_count < max_count): + replaced = False + for subexpr, pos in matchpy.preorder_iter_with_position(expression): + try: + replacement_data, subst = next(iter(self._matcher.match(subexpr))) + if self._info: + replacement = replacement_data.replacement + infos.append(replacement_data.info) + else: + replacement = replacement_data + + if self._lambdify: + result = replacement(**subst) + else: + result = replacement.xreplace({self._wildcards[k]: v for k, v in subst.items()}) + + expression = matchpy.functions.replace(expression, pos, result) + replaced = True + break + except StopIteration: + pass + replace_count += 1 + if self._info: + return expression, infos + else: + return expression diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/memoization.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/memoization.py new file mode 100644 index 0000000000000000000000000000000000000000..b638dfe244628096108ea689b664782f6538b7b8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/memoization.py @@ -0,0 +1,76 @@ +from functools import wraps + + +def recurrence_memo(initial): + """ + Memo decorator for sequences defined by recurrence + + Examples + ======== + + >>> from sympy.utilities.memoization import recurrence_memo + >>> @recurrence_memo([1]) # 0! = 1 + ... def factorial(n, prev): + ... return n * prev[-1] + >>> factorial(4) + 24 + >>> factorial(3) # use cache values + 6 + >>> factorial.cache_length() # cache length can be obtained + 5 + >>> factorial.fetch_item(slice(2, 4)) + [2, 6] + + """ + cache = initial + + def decorator(f): + @wraps(f) + def g(n): + L = len(cache) + if n < L: + return cache[n] + for i in range(L, n + 1): + cache.append(f(i, cache)) + return cache[-1] + g.cache_length = lambda: len(cache) + g.fetch_item = lambda x: cache[x] + return g + return decorator + + +def assoc_recurrence_memo(base_seq): + """ + Memo decorator for associated sequences defined by recurrence starting from base + + base_seq(n) -- callable to get base sequence elements + + XXX works only for Pn0 = base_seq(0) cases + XXX works only for m <= n cases + """ + + cache = [] + + def decorator(f): + @wraps(f) + def g(n, m): + L = len(cache) + if n < L: + return cache[n][m] + + for i in range(L, n + 1): + # get base sequence + F_i0 = base_seq(i) + F_i_cache = [F_i0] + cache.append(F_i_cache) + + # XXX only works for m <= n cases + # generate assoc sequence + for j in range(1, i + 1): + F_ij = f(i, j, cache) + F_i_cache.append(F_ij) + + return cache[n][m] + + return g + return decorator diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/misc.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/misc.py new file mode 100644 index 0000000000000000000000000000000000000000..741b983f03272890b22f2545f67b141767507634 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/misc.py @@ -0,0 +1,564 @@ +"""Miscellaneous stuff that does not really fit anywhere else.""" + +from __future__ import annotations + +import operator +import sys +import os +import re as _re +import struct +from textwrap import fill, dedent + + +class Undecidable(ValueError): + # an error to be raised when a decision cannot be made definitively + # where a definitive answer is needed + pass + + +def filldedent(s, w=70, **kwargs): + """ + Strips leading and trailing empty lines from a copy of ``s``, then dedents, + fills and returns it. + + Empty line stripping serves to deal with docstrings like this one that + start with a newline after the initial triple quote, inserting an empty + line at the beginning of the string. + + Additional keyword arguments will be passed to ``textwrap.fill()``. + + See Also + ======== + strlines, rawlines + + """ + return '\n' + fill(dedent(str(s)).strip('\n'), width=w, **kwargs) + + +def strlines(s, c=64, short=False): + """Return a cut-and-pastable string that, when printed, is + equivalent to the input. The lines will be surrounded by + parentheses and no line will be longer than c (default 64) + characters. If the line contains newlines characters, the + `rawlines` result will be returned. If ``short`` is True + (default is False) then if there is one line it will be + returned without bounding parentheses. + + Examples + ======== + + >>> from sympy.utilities.misc import strlines + >>> q = 'this is a long string that should be broken into shorter lines' + >>> print(strlines(q, 40)) + ( + 'this is a long string that should be b' + 'roken into shorter lines' + ) + >>> q == ( + ... 'this is a long string that should be b' + ... 'roken into shorter lines' + ... ) + True + + See Also + ======== + filldedent, rawlines + """ + if not isinstance(s, str): + raise ValueError('expecting string input') + if '\n' in s: + return rawlines(s) + q = '"' if repr(s).startswith('"') else "'" + q = (q,)*2 + if '\\' in s: # use r-string + m = '(\nr%s%%s%s\n)' % q + j = '%s\nr%s' % q + c -= 3 + else: + m = '(\n%s%%s%s\n)' % q + j = '%s\n%s' % q + c -= 2 + out = [] + while s: + out.append(s[:c]) + s=s[c:] + if short and len(out) == 1: + return (m % out[0]).splitlines()[1] # strip bounding (\n...\n) + return m % j.join(out) + + +def rawlines(s): + """Return a cut-and-pastable string that, when printed, is equivalent + to the input. Use this when there is more than one line in the + string. The string returned is formatted so it can be indented + nicely within tests; in some cases it is wrapped in the dedent + function which has to be imported from textwrap. + + Examples + ======== + + Note: because there are characters in the examples below that need + to be escaped because they are themselves within a triple quoted + docstring, expressions below look more complicated than they would + be if they were printed in an interpreter window. + + >>> from sympy.utilities.misc import rawlines + >>> from sympy import TableForm + >>> s = str(TableForm([[1, 10]], headings=(None, ['a', 'bee']))) + >>> print(rawlines(s)) + ( + 'a bee\\n' + '-----\\n' + '1 10 ' + ) + >>> print(rawlines('''this + ... that''')) + dedent('''\\ + this + that''') + + >>> print(rawlines('''this + ... that + ... ''')) + dedent('''\\ + this + that + ''') + + >>> s = \"\"\"this + ... is a triple ''' + ... \"\"\" + >>> print(rawlines(s)) + dedent(\"\"\"\\ + this + is a triple ''' + \"\"\") + + >>> print(rawlines('''this + ... that + ... ''')) + ( + 'this\\n' + 'that\\n' + ' ' + ) + + See Also + ======== + filldedent, strlines + """ + lines = s.split('\n') + if len(lines) == 1: + return repr(lines[0]) + triple = ["'''" in s, '"""' in s] + if any(li.endswith(' ') for li in lines) or '\\' in s or all(triple): + rv = [] + # add on the newlines + trailing = s.endswith('\n') + last = len(lines) - 1 + for i, li in enumerate(lines): + if i != last or trailing: + rv.append(repr(li + '\n')) + else: + rv.append(repr(li)) + return '(\n %s\n)' % '\n '.join(rv) + else: + rv = '\n '.join(lines) + if triple[0]: + return 'dedent("""\\\n %s""")' % rv + else: + return "dedent('''\\\n %s''')" % rv + +ARCH = str(struct.calcsize('P') * 8) + "-bit" + + +# XXX: PyPy does not support hash randomization +HASH_RANDOMIZATION = getattr(sys.flags, 'hash_randomization', False) + +_debug_tmp: list[str] = [] +_debug_iter = 0 + +def debug_decorator(func): + """If SYMPY_DEBUG is True, it will print a nice execution tree with + arguments and results of all decorated functions, else do nothing. + """ + from sympy import SYMPY_DEBUG + + if not SYMPY_DEBUG: + return func + + def maketree(f, *args, **kw): + global _debug_tmp, _debug_iter + oldtmp = _debug_tmp + _debug_tmp = [] + _debug_iter += 1 + + def tree(subtrees): + def indent(s, variant=1): + x = s.split("\n") + r = "+-%s\n" % x[0] + for a in x[1:]: + if a == "": + continue + if variant == 1: + r += "| %s\n" % a + else: + r += " %s\n" % a + return r + if len(subtrees) == 0: + return "" + f = [] + for a in subtrees[:-1]: + f.append(indent(a)) + f.append(indent(subtrees[-1], 2)) + return ''.join(f) + + # If there is a bug and the algorithm enters an infinite loop, enable the + # following lines. It will print the names and parameters of all major functions + # that are called, *before* they are called + #from functools import reduce + #print("%s%s %s%s" % (_debug_iter, reduce(lambda x, y: x + y, \ + # map(lambda x: '-', range(1, 2 + _debug_iter))), f.__name__, args)) + + r = f(*args, **kw) + + _debug_iter -= 1 + s = "%s%s = %s\n" % (f.__name__, args, r) + if _debug_tmp != []: + s += tree(_debug_tmp) + _debug_tmp = oldtmp + _debug_tmp.append(s) + if _debug_iter == 0: + print(_debug_tmp[0]) + _debug_tmp = [] + return r + + def decorated(*args, **kwargs): + return maketree(func, *args, **kwargs) + + return decorated + + +def debug(*args): + """ + Print ``*args`` if SYMPY_DEBUG is True, else do nothing. + """ + from sympy import SYMPY_DEBUG + if SYMPY_DEBUG: + print(*args, file=sys.stderr) + + +def debugf(string, args): + """ + Print ``string%args`` if SYMPY_DEBUG is True, else do nothing. This is + intended for debug messages using formatted strings. + """ + from sympy import SYMPY_DEBUG + if SYMPY_DEBUG: + print(string%args, file=sys.stderr) + + +def find_executable(executable, path=None): + """Try to find 'executable' in the directories listed in 'path' (a + string listing directories separated by 'os.pathsep'; defaults to + os.environ['PATH']). Returns the complete filename or None if not + found + """ + from .exceptions import sympy_deprecation_warning + sympy_deprecation_warning( + """ + sympy.utilities.misc.find_executable() is deprecated. Use the standard + library shutil.which() function instead. + """, + deprecated_since_version="1.7", + active_deprecations_target="deprecated-find-executable", + ) + if path is None: + path = os.environ['PATH'] + paths = path.split(os.pathsep) + extlist = [''] + if os.name == 'os2': + (base, ext) = os.path.splitext(executable) + # executable files on OS/2 can have an arbitrary extension, but + # .exe is automatically appended if no dot is present in the name + if not ext: + executable = executable + ".exe" + elif sys.platform == 'win32': + pathext = os.environ['PATHEXT'].lower().split(os.pathsep) + (base, ext) = os.path.splitext(executable) + if ext.lower() not in pathext: + extlist = pathext + for ext in extlist: + execname = executable + ext + if os.path.isfile(execname): + return execname + else: + for p in paths: + f = os.path.join(p, execname) + if os.path.isfile(f): + return f + + return None + + +def func_name(x, short=False): + """Return function name of `x` (if defined) else the `type(x)`. + If short is True and there is a shorter alias for the result, + return the alias. + + Examples + ======== + + >>> from sympy.utilities.misc import func_name + >>> from sympy import Matrix + >>> from sympy.abc import x + >>> func_name(Matrix.eye(3)) + 'MutableDenseMatrix' + >>> func_name(x < 1) + 'StrictLessThan' + >>> func_name(x < 1, short=True) + 'Lt' + """ + alias = { + 'GreaterThan': 'Ge', + 'StrictGreaterThan': 'Gt', + 'LessThan': 'Le', + 'StrictLessThan': 'Lt', + 'Equality': 'Eq', + 'Unequality': 'Ne', + } + typ = type(x) + if str(typ).startswith(">> from sympy.utilities.misc import _replace + >>> f = _replace(dict(foo='bar', d='t')) + >>> f('food') + 'bart' + >>> f = _replace({}) + >>> f('food') + 'food' + """ + if not reps: + return lambda x: x + D = lambda match: reps[match.group(0)] + pattern = _re.compile("|".join( + [_re.escape(k) for k, v in reps.items()]), _re.MULTILINE) + return lambda string: pattern.sub(D, string) + + +def replace(string, *reps): + """Return ``string`` with all keys in ``reps`` replaced with + their corresponding values, longer strings first, irrespective + of the order they are given. ``reps`` may be passed as tuples + or a single mapping. + + Examples + ======== + + >>> from sympy.utilities.misc import replace + >>> replace('foo', {'oo': 'ar', 'f': 'b'}) + 'bar' + >>> replace("spamham sha", ("spam", "eggs"), ("sha","md5")) + 'eggsham md5' + + There is no guarantee that a unique answer will be + obtained if keys in a mapping overlap (i.e. are the same + length and have some identical sequence at the + beginning/end): + + >>> reps = [ + ... ('ab', 'x'), + ... ('bc', 'y')] + >>> replace('abc', *reps) in ('xc', 'ay') + True + + References + ========== + + .. [1] https://stackoverflow.com/questions/6116978/how-to-replace-multiple-substrings-of-a-string + """ + if len(reps) == 1: + kv = reps[0] + if isinstance(kv, dict): + reps = kv + else: + return string.replace(*kv) + else: + reps = dict(reps) + return _replace(reps)(string) + + +def translate(s, a, b=None, c=None): + """Return ``s`` where characters have been replaced or deleted. + + SYNTAX + ====== + + translate(s, None, deletechars): + all characters in ``deletechars`` are deleted + translate(s, map [,deletechars]): + all characters in ``deletechars`` (if provided) are deleted + then the replacements defined by map are made; if the keys + of map are strings then the longer ones are handled first. + Multicharacter deletions should have a value of ''. + translate(s, oldchars, newchars, deletechars) + all characters in ``deletechars`` are deleted + then each character in ``oldchars`` is replaced with the + corresponding character in ``newchars`` + + Examples + ======== + + >>> from sympy.utilities.misc import translate + >>> abc = 'abc' + >>> translate(abc, None, 'a') + 'bc' + >>> translate(abc, {'a': 'x'}, 'c') + 'xb' + >>> translate(abc, {'abc': 'x', 'a': 'y'}) + 'x' + + >>> translate('abcd', 'ac', 'AC', 'd') + 'AbC' + + There is no guarantee that a unique answer will be + obtained if keys in a mapping overlap are the same + length and have some identical sequences at the + beginning/end: + + >>> translate(abc, {'ab': 'x', 'bc': 'y'}) in ('xc', 'ay') + True + """ + + mr = {} + if a is None: + if c is not None: + raise ValueError('c should be None when a=None is passed, instead got %s' % c) + if b is None: + return s + c = b + a = b = '' + else: + if isinstance(a, dict): + short = {} + for k in list(a.keys()): + if len(k) == 1 and len(a[k]) == 1: + short[k] = a.pop(k) + mr = a + c = b + if short: + a, b = [''.join(i) for i in list(zip(*short.items()))] + else: + a = b = '' + elif len(a) != len(b): + raise ValueError('oldchars and newchars have different lengths') + + if c: + val = str.maketrans('', '', c) + s = s.translate(val) + s = replace(s, mr) + n = str.maketrans(a, b) + return s.translate(n) + + +def ordinal(num): + """Return ordinal number string of num, e.g. 1 becomes 1st. + """ + # modified from https://codereview.stackexchange.com/questions/41298/producing-ordinal-numbers + n = as_int(num) + k = abs(n) % 100 + if 11 <= k <= 13: + suffix = 'th' + elif k % 10 == 1: + suffix = 'st' + elif k % 10 == 2: + suffix = 'nd' + elif k % 10 == 3: + suffix = 'rd' + else: + suffix = 'th' + return str(n) + suffix + + +def as_int(n, strict=True): + """ + Convert the argument to a builtin integer. + + The return value is guaranteed to be equal to the input. ValueError is + raised if the input has a non-integral value. When ``strict`` is True, this + uses `__index__ `_ + and when it is False it uses ``int``. + + + Examples + ======== + + >>> from sympy.utilities.misc import as_int + >>> from sympy import sqrt, S + + The function is primarily concerned with sanitizing input for + functions that need to work with builtin integers, so anything that + is unambiguously an integer should be returned as an int: + + >>> as_int(S(3)) + 3 + + Floats, being of limited precision, are not assumed to be exact and + will raise an error unless the ``strict`` flag is False. This + precision issue becomes apparent for large floating point numbers: + + >>> big = 1e23 + >>> type(big) is float + True + >>> big == int(big) + True + >>> as_int(big) + Traceback (most recent call last): + ... + ValueError: ... is not an integer + >>> as_int(big, strict=False) + 99999999999999991611392 + + Input that might be a complex representation of an integer value is + also rejected by default: + + >>> one = sqrt(3 + 2*sqrt(2)) - sqrt(2) + >>> int(one) == 1 + True + >>> as_int(one) + Traceback (most recent call last): + ... + ValueError: ... is not an integer + """ + if strict: + try: + if isinstance(n, bool): + raise TypeError + return operator.index(n) + except TypeError: + raise ValueError('%s is not an integer' % (n,)) + else: + try: + result = int(n) + except TypeError: + raise ValueError('%s is not an integer' % (n,)) + if n - result: + raise ValueError('%s is not an integer' % (n,)) + return result diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/pkgdata.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/pkgdata.py new file mode 100644 index 0000000000000000000000000000000000000000..8bf2065759362ee09a252d4736bd612b8d271e72 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/pkgdata.py @@ -0,0 +1,33 @@ +# This module is deprecated and will be removed. + +import sys +import os +from io import StringIO + +from sympy.utilities.decorator import deprecated + + +@deprecated( + """ + The sympy.utilities.pkgdata module and its get_resource function are + deprecated. Use the stdlib importlib.resources module instead. + """, + deprecated_since_version="1.12", + active_deprecations_target="pkgdata", +) +def get_resource(identifier, pkgname=__name__): + + mod = sys.modules[pkgname] + fn = getattr(mod, '__file__', None) + if fn is None: + raise OSError("%r has no __file__!") + path = os.path.join(os.path.dirname(fn), identifier) + loader = getattr(mod, '__loader__', None) + if loader is not None: + try: + data = loader.get_data(path) + except (OSError, AttributeError): + pass + else: + return StringIO(data.decode('utf-8')) + return open(os.path.normpath(path), 'rb') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/pytest.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/pytest.py new file mode 100644 index 0000000000000000000000000000000000000000..75494c8e987c7b89bddf18febe09fdc3df2b194e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/pytest.py @@ -0,0 +1,12 @@ +""" +.. deprecated:: 1.6 + + sympy.utilities.pytest has been renamed to sympy.testing.pytest. +""" +from sympy.utilities.exceptions import sympy_deprecation_warning + +sympy_deprecation_warning("The sympy.utilities.pytest submodule is deprecated. Use sympy.testing.pytest instead.", + deprecated_since_version="1.6", + active_deprecations_target="deprecated-sympy-utilities-submodules") + +from sympy.testing.pytest import * # noqa:F401,F403 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/randtest.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/randtest.py new file mode 100644 index 0000000000000000000000000000000000000000..1bd3472ed8a89198d9e78e125f16dae1a56f6bad --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/randtest.py @@ -0,0 +1,12 @@ +""" +.. deprecated:: 1.6 + + sympy.utilities.randtest has been renamed to sympy.core.random. +""" +from sympy.utilities.exceptions import sympy_deprecation_warning + +sympy_deprecation_warning("The sympy.utilities.randtest submodule is deprecated. Use sympy.core.random instead.", + deprecated_since_version="1.6", + active_deprecations_target="deprecated-sympy-utilities-submodules") + +from sympy.core.random import * # noqa:F401,F403 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/runtests.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/runtests.py new file mode 100644 index 0000000000000000000000000000000000000000..bb9f760f070be528e8cd51ab38e00bc944dda9ac --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/runtests.py @@ -0,0 +1,13 @@ +""" +.. deprecated:: 1.6 + + sympy.utilities.runtests has been renamed to sympy.testing.runtests. +""" + +from sympy.utilities.exceptions import sympy_deprecation_warning + +sympy_deprecation_warning("The sympy.utilities.runtests submodule is deprecated. Use sympy.testing.runtests instead.", + deprecated_since_version="1.6", + active_deprecations_target="deprecated-sympy-utilities-submodules") + +from sympy.testing.runtests import * # noqa: F401,F403 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/source.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/source.py new file mode 100644 index 0000000000000000000000000000000000000000..71692b4aaad07df70b63d7e1eaa86c402ad03c4f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/source.py @@ -0,0 +1,40 @@ +""" +This module adds several functions for interactive source code inspection. +""" + + +def get_class(lookup_view): + """ + Convert a string version of a class name to the object. + + For example, get_class('sympy.core.Basic') will return + class Basic located in module sympy.core + """ + if isinstance(lookup_view, str): + mod_name, func_name = get_mod_func(lookup_view) + if func_name != '': + lookup_view = getattr( + __import__(mod_name, {}, {}, ['*']), func_name) + if not callable(lookup_view): + raise AttributeError( + "'%s.%s' is not a callable." % (mod_name, func_name)) + return lookup_view + + +def get_mod_func(callback): + """ + splits the string path to a class into a string path to the module + and the name of the class. + + Examples + ======== + + >>> from sympy.utilities.source import get_mod_func + >>> get_mod_func('sympy.core.basic.Basic') + ('sympy.core.basic', 'Basic') + + """ + dot = callback.rfind('.') + if dot == -1: + return callback, '' + return callback[:dot], callback[dot + 1:] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/timeutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/timeutils.py new file mode 100644 index 0000000000000000000000000000000000000000..1caae825103335f3e8afedeaf741cff2b0414fb2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/timeutils.py @@ -0,0 +1,75 @@ +"""Simple tools for timing functions' execution, when IPython is not available. """ + + +import timeit +import math + + +_scales = [1e0, 1e3, 1e6, 1e9] +_units = ['s', 'ms', '\N{GREEK SMALL LETTER MU}s', 'ns'] + + +def timed(func, setup="pass", limit=None): + """Adaptively measure execution time of a function. """ + timer = timeit.Timer(func, setup=setup) + repeat, number = 3, 1 + + for i in range(1, 10): + if timer.timeit(number) >= 0.2: + break + elif limit is not None and number >= limit: + break + else: + number *= 10 + + time = min(timer.repeat(repeat, number)) / number + + if time > 0.0: + order = min(-int(math.floor(math.log10(time)) // 3), 3) + else: + order = 3 + + return (number, time, time*_scales[order], _units[order]) + + +# Code for doing inline timings of recursive algorithms. + +def __do_timings(): + import os + res = os.getenv('SYMPY_TIMINGS', '') + res = [x.strip() for x in res.split(',')] + return set(res) + +_do_timings = __do_timings() +_timestack = None + + +def _print_timestack(stack, level=1): + print('-'*level, '%.2f %s%s' % (stack[2], stack[0], stack[3])) + for s in stack[1]: + _print_timestack(s, level + 1) + + +def timethis(name): + def decorator(func): + if name not in _do_timings: + return func + + def wrapper(*args, **kwargs): + from time import time + global _timestack + oldtimestack = _timestack + _timestack = [func.func_name, [], 0, args] + t1 = time() + r = func(*args, **kwargs) + t2 = time() + _timestack[2] = t2 - t1 + if oldtimestack is not None: + oldtimestack[1].append(_timestack) + _timestack = oldtimestack + else: + _print_timestack(_timestack) + _timestack = None + return r + return wrapper + return decorator diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/tmpfiles.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/tmpfiles.py new file mode 100644 index 0000000000000000000000000000000000000000..81c97efbf9d67cc20f25ff251abc94c2f5bafe06 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/utilities/tmpfiles.py @@ -0,0 +1,12 @@ +""" +.. deprecated:: 1.6 + + sympy.utilities.tmpfiles has been renamed to sympy.testing.tmpfiles. +""" +from sympy.utilities.exceptions import sympy_deprecation_warning + +sympy_deprecation_warning("The sympy.utilities.tmpfiles submodule is deprecated. Use sympy.testing.tmpfiles instead.", + deprecated_since_version="1.6", + active_deprecations_target="deprecated-sympy-utilities-submodules") + +from sympy.testing.tmpfiles import * # noqa:F401,F403 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f6757bbeb35022481b1cf183373ecccd19779faa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/__init__.py @@ -0,0 +1,50 @@ +from sympy.vector.coordsysrect import CoordSys3D +from sympy.vector.vector import (Vector, VectorAdd, VectorMul, + BaseVector, VectorZero, Cross, Dot, cross, dot) +from sympy.vector.dyadic import (Dyadic, DyadicAdd, DyadicMul, + BaseDyadic, DyadicZero) +from sympy.vector.scalar import BaseScalar +from sympy.vector.deloperator import Del +from sympy.vector.functions import (express, matrix_to_vector, + laplacian, is_conservative, + is_solenoidal, scalar_potential, + directional_derivative, + scalar_potential_difference) +from sympy.vector.point import Point +from sympy.vector.orienters import (AxisOrienter, BodyOrienter, + SpaceOrienter, QuaternionOrienter) +from sympy.vector.operators import Gradient, Divergence, Curl, Laplacian, gradient, curl, divergence +from sympy.vector.implicitregion import ImplicitRegion +from sympy.vector.parametricregion import (ParametricRegion, parametric_region_list) +from sympy.vector.integrals import (ParametricIntegral, vector_integrate) +from sympy.vector.kind import VectorKind + +__all__ = [ + 'Vector', 'VectorAdd', 'VectorMul', 'BaseVector', 'VectorZero', 'Cross', + 'Dot', 'cross', 'dot', + + 'VectorKind', + + 'Dyadic', 'DyadicAdd', 'DyadicMul', 'BaseDyadic', 'DyadicZero', + + 'BaseScalar', + + 'Del', + + 'CoordSys3D', + + 'express', 'matrix_to_vector', 'laplacian', 'is_conservative', + 'is_solenoidal', 'scalar_potential', 'directional_derivative', + 'scalar_potential_difference', + + 'Point', + + 'AxisOrienter', 'BodyOrienter', 'SpaceOrienter', 'QuaternionOrienter', + + 'Gradient', 'Divergence', 'Curl', 'Laplacian', 'gradient', 'curl', + 'divergence', + + 'ParametricRegion', 'parametric_region_list', 'ImplicitRegion', + + 'ParametricIntegral', 'vector_integrate', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/basisdependent.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/basisdependent.py new file mode 100644 index 0000000000000000000000000000000000000000..53e4efc0bf839fb5a5de2d1af1487683fabd8cf1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/basisdependent.py @@ -0,0 +1,374 @@ +from __future__ import annotations +from typing import TYPE_CHECKING + +from sympy.simplify import simplify as simp, trigsimp as tsimp # type: ignore +from sympy.core.decorators import call_highest_priority, _sympifyit +from sympy.core.assumptions import StdFactKB +from sympy.core.function import diff as df +from sympy.integrals.integrals import Integral +from sympy.polys.polytools import factor as fctr +from sympy.core import S, Add, Mul +from sympy.core.expr import Expr + +if TYPE_CHECKING: + from sympy.vector.vector import BaseVector + + +class BasisDependent(Expr): + """ + Super class containing functionality common to vectors and + dyadics. + Named so because the representation of these quantities in + sympy.vector is dependent on the basis they are expressed in. + """ + + zero: BasisDependentZero + + @call_highest_priority('__radd__') + def __add__(self, other): + return self._add_func(self, other) + + @call_highest_priority('__add__') + def __radd__(self, other): + return self._add_func(other, self) + + @call_highest_priority('__rsub__') + def __sub__(self, other): + return self._add_func(self, -other) + + @call_highest_priority('__sub__') + def __rsub__(self, other): + return self._add_func(other, -self) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__rmul__') + def __mul__(self, other): + return self._mul_func(self, other) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__mul__') + def __rmul__(self, other): + return self._mul_func(other, self) + + def __neg__(self): + return self._mul_func(S.NegativeOne, self) + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__rtruediv__') + def __truediv__(self, other): + return self._div_helper(other) + + @call_highest_priority('__truediv__') + def __rtruediv__(self, other): + return TypeError("Invalid divisor for division") + + def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): + """ + Implements the SymPy evalf routine for this quantity. + + evalf's documentation + ===================== + + """ + options = {'subs':subs, 'maxn':maxn, 'chop':chop, 'strict':strict, + 'quad':quad, 'verbose':verbose} + vec = self.zero + for k, v in self.components.items(): + vec += v.evalf(n, **options) * k + return vec + + evalf.__doc__ += Expr.evalf.__doc__ # type: ignore + + n = evalf # type: ignore + + def simplify(self, **kwargs): + """ + Implements the SymPy simplify routine for this quantity. + + simplify's documentation + ======================== + + """ + simp_components = [simp(v, **kwargs) * k for + k, v in self.components.items()] + return self._add_func(*simp_components) + + simplify.__doc__ += simp.__doc__ # type: ignore + + def trigsimp(self, **opts): + """ + Implements the SymPy trigsimp routine, for this quantity. + + trigsimp's documentation + ======================== + + """ + trig_components = [tsimp(v, **opts) * k for + k, v in self.components.items()] + return self._add_func(*trig_components) + + trigsimp.__doc__ += tsimp.__doc__ # type: ignore + + def _eval_simplify(self, **kwargs): + return self.simplify(**kwargs) + + def _eval_trigsimp(self, **opts): + return self.trigsimp(**opts) + + def _eval_derivative(self, wrt): + return self.diff(wrt) + + def _eval_Integral(self, *symbols, **assumptions): + integral_components = [Integral(v, *symbols, **assumptions) * k + for k, v in self.components.items()] + return self._add_func(*integral_components) + + def as_numer_denom(self): + """ + Returns the expression as a tuple wrt the following + transformation - + + expression -> a/b -> a, b + + """ + return self, S.One + + def factor(self, *args, **kwargs): + """ + Implements the SymPy factor routine, on the scalar parts + of a basis-dependent expression. + + factor's documentation + ======================== + + """ + fctr_components = [fctr(v, *args, **kwargs) * k for + k, v in self.components.items()] + return self._add_func(*fctr_components) + + factor.__doc__ += fctr.__doc__ # type: ignore + + def as_coeff_Mul(self, rational=False): + """Efficiently extract the coefficient of a product.""" + return (S.One, self) + + def as_coeff_add(self, *deps): + """Efficiently extract the coefficient of a summation.""" + return 0, tuple(x * self.components[x] for x in self.components) + + def diff(self, *args, **kwargs): + """ + Implements the SymPy diff routine, for vectors. + + diff's documentation + ======================== + + """ + for x in args: + if isinstance(x, BasisDependent): + raise TypeError("Invalid arg for differentiation") + diff_components = [df(v, *args, **kwargs) * k for + k, v in self.components.items()] + return self._add_func(*diff_components) + + diff.__doc__ += df.__doc__ # type: ignore + + def doit(self, **hints): + """Calls .doit() on each term in the Dyadic""" + doit_components = [self.components[x].doit(**hints) * x + for x in self.components] + return self._add_func(*doit_components) + + +class BasisDependentAdd(BasisDependent, Add): + """ + Denotes sum of basis dependent quantities such that they cannot + be expressed as base or Mul instances. + """ + + def __new__(cls, *args, **options): + components = {} + + # Check each arg and simultaneously learn the components + for arg in args: + if not isinstance(arg, cls._expr_type): + if isinstance(arg, Mul): + arg = cls._mul_func(*(arg.args)) + elif isinstance(arg, Add): + arg = cls._add_func(*(arg.args)) + else: + raise TypeError(str(arg) + + " cannot be interpreted correctly") + # If argument is zero, ignore + if arg == cls.zero: + continue + # Else, update components accordingly + for x in arg.components: + components[x] = components.get(x, 0) + arg.components[x] + + temp = list(components.keys()) + for x in temp: + if components[x] == 0: + del components[x] + + # Handle case of zero vector + if len(components) == 0: + return cls.zero + + # Build object + newargs = [x * components[x] for x in components] + obj = super().__new__(cls, *newargs, **options) + if isinstance(obj, Mul): + return cls._mul_func(*obj.args) + assumptions = {'commutative': True} + obj._assumptions = StdFactKB(assumptions) + obj._components = components + obj._sys = (list(components.keys()))[0]._sys + + return obj + + +class BasisDependentMul(BasisDependent, Mul): + """ + Denotes product of base- basis dependent quantity with a scalar. + """ + + def __new__(cls, *args, **options): + obj = cls._new(*args, **options) + return obj + + def _new_rawargs(self, *args): + # XXX: This is needed because Add.flatten() uses it but the default + # implementation does not work for Vectors because they assign + # attributes outside of .args. + return type(self)(*args) + + @classmethod + def _new(cls, *args, **options): + from sympy.vector import Cross, Dot, Curl, Gradient + count = 0 + measure_number = S.One + zeroflag = False + extra_args = [] + + # Determine the component and check arguments + # Also keep a count to ensure two vectors aren't + # being multiplied + for arg in args: + if isinstance(arg, cls._zero_func): + count += 1 + zeroflag = True + elif arg == S.Zero: + zeroflag = True + elif isinstance(arg, (cls._base_func, cls._mul_func)): + count += 1 + expr = arg._base_instance + measure_number *= arg._measure_number + elif isinstance(arg, cls._add_func): + count += 1 + expr = arg + elif isinstance(arg, (Cross, Dot, Curl, Gradient)): + extra_args.append(arg) + else: + measure_number *= arg + # Make sure incompatible types weren't multiplied + if count > 1: + raise ValueError("Invalid multiplication") + elif count == 0: + return Mul(*args, **options) + # Handle zero vector case + if zeroflag: + return cls.zero + + # If one of the args was a VectorAdd, return an + # appropriate VectorAdd instance + if isinstance(expr, cls._add_func): + newargs = [cls._mul_func(measure_number, x) for + x in expr.args] + return cls._add_func(*newargs) + + obj = super().__new__(cls, measure_number, + expr._base_instance, + *extra_args, + **options) + if isinstance(obj, Add): + return cls._add_func(*obj.args) + obj._base_instance = expr._base_instance + obj._measure_number = measure_number + assumptions = {'commutative': True} + obj._assumptions = StdFactKB(assumptions) + obj._components = {expr._base_instance: measure_number} + obj._sys = expr._base_instance._sys + + return obj + + def _sympystr(self, printer): + measure_str = printer._print(self._measure_number) + if ('(' in measure_str or '-' in measure_str or + '+' in measure_str): + measure_str = '(' + measure_str + ')' + return measure_str + '*' + printer._print(self._base_instance) + + +class BasisDependentZero(BasisDependent): + """ + Class to denote a zero basis dependent instance. + """ + components: dict['BaseVector', Expr] = {} + _latex_form: str + + def __new__(cls): + obj = super().__new__(cls) + # Pre-compute a specific hash value for the zero vector + # Use the same one always + obj._hash = (S.Zero, cls).__hash__() + return obj + + def __hash__(self): + return self._hash + + @call_highest_priority('__req__') + def __eq__(self, other): + return isinstance(other, self._zero_func) + + __req__ = __eq__ + + @call_highest_priority('__radd__') + def __add__(self, other): + if isinstance(other, self._expr_type): + return other + else: + raise TypeError("Invalid argument types for addition") + + @call_highest_priority('__add__') + def __radd__(self, other): + if isinstance(other, self._expr_type): + return other + else: + raise TypeError("Invalid argument types for addition") + + @call_highest_priority('__rsub__') + def __sub__(self, other): + if isinstance(other, self._expr_type): + return -other + else: + raise TypeError("Invalid argument types for subtraction") + + @call_highest_priority('__sub__') + def __rsub__(self, other): + if isinstance(other, self._expr_type): + return other + else: + raise TypeError("Invalid argument types for subtraction") + + def __neg__(self): + return self + + def normalize(self): + """ + Returns the normalized version of this vector. + """ + return self + + def _sympystr(self, printer): + return '0' diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/coordsysrect.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/coordsysrect.py new file mode 100644 index 0000000000000000000000000000000000000000..55539fb19dc4221de69437111f44d6a6cc70b3e4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/coordsysrect.py @@ -0,0 +1,1031 @@ +from collections.abc import Callable + +from sympy.core.basic import Basic +from sympy.core.cache import cacheit +from sympy.core import S, Dummy, Lambda +from sympy.core.symbol import Str +from sympy.core.symbol import symbols +from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix +from sympy.matrices.matrixbase import MatrixBase +from sympy.solvers import solve +from sympy.vector.scalar import BaseScalar +from sympy.core.containers import Tuple +from sympy.core.function import diff +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (acos, atan2, cos, sin) +from sympy.matrices.dense import eye +from sympy.matrices.immutable import ImmutableDenseMatrix +from sympy.simplify.simplify import simplify +from sympy.simplify.trigsimp import trigsimp +import sympy.vector +from sympy.vector.orienters import (Orienter, AxisOrienter, BodyOrienter, + SpaceOrienter, QuaternionOrienter) + + +class CoordSys3D(Basic): + """ + Represents a coordinate system in 3-D space. + """ + + def __new__(cls, name, transformation=None, parent=None, location=None, + rotation_matrix=None, vector_names=None, variable_names=None): + """ + The orientation/location parameters are necessary if this system + is being defined at a certain orientation or location wrt another. + + Parameters + ========== + + name : str + The name of the new CoordSys3D instance. + + transformation : Lambda, Tuple, str + Transformation defined by transformation equations or chosen + from predefined ones. + + location : Vector + The position vector of the new system's origin wrt the parent + instance. + + rotation_matrix : SymPy ImmutableMatrix + The rotation matrix of the new coordinate system with respect + to the parent. In other words, the output of + new_system.rotation_matrix(parent). + + parent : CoordSys3D + The coordinate system wrt which the orientation/location + (or both) is being defined. + + vector_names, variable_names : iterable(optional) + Iterables of 3 strings each, with custom names for base + vectors and base scalars of the new system respectively. + Used for simple str printing. + + """ + + name = str(name) + Vector = sympy.vector.Vector + Point = sympy.vector.Point + + if not isinstance(name, str): + raise TypeError("name should be a string") + + if transformation is not None: + if (location is not None) or (rotation_matrix is not None): + raise ValueError("specify either `transformation` or " + "`location`/`rotation_matrix`") + if isinstance(transformation, (Tuple, tuple, list)): + if isinstance(transformation[0], MatrixBase): + rotation_matrix = transformation[0] + location = transformation[1] + else: + transformation = Lambda(transformation[0], + transformation[1]) + elif isinstance(transformation, Callable): + x1, x2, x3 = symbols('x1 x2 x3', cls=Dummy) + transformation = Lambda((x1, x2, x3), + transformation(x1, x2, x3)) + elif isinstance(transformation, str): + transformation = Str(transformation) + elif isinstance(transformation, (Str, Lambda)): + pass + else: + raise TypeError("transformation: " + "wrong type {}".format(type(transformation))) + + # If orientation information has been provided, store + # the rotation matrix accordingly + if rotation_matrix is None: + rotation_matrix = ImmutableDenseMatrix(eye(3)) + else: + if not isinstance(rotation_matrix, MatrixBase): + raise TypeError("rotation_matrix should be an Immutable" + + "Matrix instance") + rotation_matrix = rotation_matrix.as_immutable() + + # If location information is not given, adjust the default + # location as Vector.zero + if parent is not None: + if not isinstance(parent, CoordSys3D): + raise TypeError("parent should be a " + + "CoordSys3D/None") + if location is None: + location = Vector.zero + else: + if not isinstance(location, Vector): + raise TypeError("location should be a Vector") + # Check that location does not contain base + # scalars + for x in location.free_symbols: + if isinstance(x, BaseScalar): + raise ValueError("location should not contain" + + " BaseScalars") + origin = parent.origin.locate_new(name + '.origin', + location) + else: + location = Vector.zero + origin = Point(name + '.origin') + + if transformation is None: + transformation = Tuple(rotation_matrix, location) + + if isinstance(transformation, Tuple): + lambda_transformation = CoordSys3D._compose_rotation_and_translation( + transformation[0], + transformation[1], + parent + ) + r, l = transformation + l = l._projections + lambda_lame = CoordSys3D._get_lame_coeff('cartesian') + lambda_inverse = lambda x, y, z: r.inv()*Matrix( + [x-l[0], y-l[1], z-l[2]]) + elif isinstance(transformation, Str): + trname = transformation.name + lambda_transformation = CoordSys3D._get_transformation_lambdas(trname) + if parent is not None: + if parent.lame_coefficients() != (S.One, S.One, S.One): + raise ValueError('Parent for pre-defined coordinate ' + 'system should be Cartesian.') + lambda_lame = CoordSys3D._get_lame_coeff(trname) + lambda_inverse = CoordSys3D._set_inv_trans_equations(trname) + elif isinstance(transformation, Lambda): + if not CoordSys3D._check_orthogonality(transformation): + raise ValueError("The transformation equation does not " + "create orthogonal coordinate system") + lambda_transformation = transformation + lambda_lame = CoordSys3D._calculate_lame_coeff(lambda_transformation) + lambda_inverse = None + else: + lambda_transformation = lambda x, y, z: transformation(x, y, z) + lambda_lame = CoordSys3D._get_lame_coeff(transformation) + lambda_inverse = None + + if variable_names is None: + if isinstance(transformation, Lambda): + variable_names = ["x1", "x2", "x3"] + elif isinstance(transformation, Str): + if transformation.name == 'spherical': + variable_names = ["r", "theta", "phi"] + elif transformation.name == 'cylindrical': + variable_names = ["r", "theta", "z"] + else: + variable_names = ["x", "y", "z"] + else: + variable_names = ["x", "y", "z"] + if vector_names is None: + vector_names = ["i", "j", "k"] + + # All systems that are defined as 'roots' are unequal, unless + # they have the same name. + # Systems defined at same orientation/position wrt the same + # 'parent' are equal, irrespective of the name. + # This is true even if the same orientation is provided via + # different methods like Axis/Body/Space/Quaternion. + # However, coincident systems may be seen as unequal if + # positioned/oriented wrt different parents, even though + # they may actually be 'coincident' wrt the root system. + if parent is not None: + obj = super().__new__( + cls, Str(name), transformation, parent) + else: + obj = super().__new__( + cls, Str(name), transformation) + obj._name = name + # Initialize the base vectors + + _check_strings('vector_names', vector_names) + vector_names = list(vector_names) + latex_vects = [(r'\mathbf{\hat{%s}_{%s}}' % (x, name)) for + x in vector_names] + pretty_vects = ['%s_%s' % (x, name) for x in vector_names] + + obj._vector_names = vector_names + + v1 = BaseVector(0, obj, pretty_vects[0], latex_vects[0]) + v2 = BaseVector(1, obj, pretty_vects[1], latex_vects[1]) + v3 = BaseVector(2, obj, pretty_vects[2], latex_vects[2]) + + obj._base_vectors = (v1, v2, v3) + + # Initialize the base scalars + + _check_strings('variable_names', vector_names) + variable_names = list(variable_names) + latex_scalars = [(r"\mathbf{{%s}_{%s}}" % (x, name)) for + x in variable_names] + pretty_scalars = ['%s_%s' % (x, name) for x in variable_names] + + obj._variable_names = variable_names + obj._vector_names = vector_names + + x1 = BaseScalar(0, obj, pretty_scalars[0], latex_scalars[0]) + x2 = BaseScalar(1, obj, pretty_scalars[1], latex_scalars[1]) + x3 = BaseScalar(2, obj, pretty_scalars[2], latex_scalars[2]) + + obj._base_scalars = (x1, x2, x3) + + obj._transformation = transformation + obj._transformation_lambda = lambda_transformation + obj._lame_coefficients = lambda_lame(x1, x2, x3) + obj._transformation_from_parent_lambda = lambda_inverse + + setattr(obj, variable_names[0], x1) + setattr(obj, variable_names[1], x2) + setattr(obj, variable_names[2], x3) + + setattr(obj, vector_names[0], v1) + setattr(obj, vector_names[1], v2) + setattr(obj, vector_names[2], v3) + + # Assign params + obj._parent = parent + if obj._parent is not None: + obj._root = obj._parent._root + else: + obj._root = obj + + obj._parent_rotation_matrix = rotation_matrix + obj._origin = origin + + # Return the instance + return obj + + def _sympystr(self, printer): + return self._name + + def __iter__(self): + return iter(self.base_vectors()) + + @staticmethod + def _check_orthogonality(equations): + """ + Helper method for _connect_to_cartesian. It checks if + set of transformation equations create orthogonal curvilinear + coordinate system + + Parameters + ========== + + equations : Lambda + Lambda of transformation equations + + """ + + x1, x2, x3 = symbols("x1, x2, x3", cls=Dummy) + equations = equations(x1, x2, x3) + v1 = Matrix([diff(equations[0], x1), + diff(equations[1], x1), diff(equations[2], x1)]) + + v2 = Matrix([diff(equations[0], x2), + diff(equations[1], x2), diff(equations[2], x2)]) + + v3 = Matrix([diff(equations[0], x3), + diff(equations[1], x3), diff(equations[2], x3)]) + + if any(simplify(i[0] + i[1] + i[2]) == 0 for i in (v1, v2, v3)): + return False + else: + if simplify(v1.dot(v2)) == 0 and simplify(v2.dot(v3)) == 0 \ + and simplify(v3.dot(v1)) == 0: + return True + else: + return False + + @staticmethod + def _set_inv_trans_equations(curv_coord_name): + """ + Store information about inverse transformation equations for + pre-defined coordinate systems. + + Parameters + ========== + + curv_coord_name : str + Name of coordinate system + + """ + if curv_coord_name == 'cartesian': + return lambda x, y, z: (x, y, z) + + if curv_coord_name == 'spherical': + return lambda x, y, z: ( + sqrt(x**2 + y**2 + z**2), + acos(z/sqrt(x**2 + y**2 + z**2)), + atan2(y, x) + ) + if curv_coord_name == 'cylindrical': + return lambda x, y, z: ( + sqrt(x**2 + y**2), + atan2(y, x), + z + ) + raise ValueError('Wrong set of parameters.' + 'Type of coordinate system is defined') + + def _calculate_inv_trans_equations(self): + """ + Helper method for set_coordinate_type. It calculates inverse + transformation equations for given transformations equations. + + """ + x1, x2, x3 = symbols("x1, x2, x3", cls=Dummy, reals=True) + x, y, z = symbols("x, y, z", cls=Dummy) + + equations = self._transformation(x1, x2, x3) + + solved = solve([equations[0] - x, + equations[1] - y, + equations[2] - z], (x1, x2, x3), dict=True)[0] + solved = solved[x1], solved[x2], solved[x3] + self._transformation_from_parent_lambda = \ + lambda x1, x2, x3: tuple(i.subs(list(zip((x, y, z), (x1, x2, x3)))) for i in solved) + + @staticmethod + def _get_lame_coeff(curv_coord_name): + """ + Store information about Lame coefficients for pre-defined + coordinate systems. + + Parameters + ========== + + curv_coord_name : str + Name of coordinate system + + """ + if isinstance(curv_coord_name, str): + if curv_coord_name == 'cartesian': + return lambda x, y, z: (S.One, S.One, S.One) + if curv_coord_name == 'spherical': + return lambda r, theta, phi: (S.One, r, r*sin(theta)) + if curv_coord_name == 'cylindrical': + return lambda r, theta, h: (S.One, r, S.One) + raise ValueError('Wrong set of parameters.' + ' Type of coordinate system is not defined') + return CoordSys3D._calculate_lame_coefficients(curv_coord_name) + + @staticmethod + def _calculate_lame_coeff(equations): + """ + It calculates Lame coefficients + for given transformations equations. + + Parameters + ========== + + equations : Lambda + Lambda of transformation equations. + + """ + return lambda x1, x2, x3: ( + sqrt(diff(equations(x1, x2, x3)[0], x1)**2 + + diff(equations(x1, x2, x3)[1], x1)**2 + + diff(equations(x1, x2, x3)[2], x1)**2), + sqrt(diff(equations(x1, x2, x3)[0], x2)**2 + + diff(equations(x1, x2, x3)[1], x2)**2 + + diff(equations(x1, x2, x3)[2], x2)**2), + sqrt(diff(equations(x1, x2, x3)[0], x3)**2 + + diff(equations(x1, x2, x3)[1], x3)**2 + + diff(equations(x1, x2, x3)[2], x3)**2) + ) + + def _inverse_rotation_matrix(self): + """ + Returns inverse rotation matrix. + """ + return simplify(self._parent_rotation_matrix**-1) + + @staticmethod + def _get_transformation_lambdas(curv_coord_name): + """ + Store information about transformation equations for pre-defined + coordinate systems. + + Parameters + ========== + + curv_coord_name : str + Name of coordinate system + + """ + if isinstance(curv_coord_name, str): + if curv_coord_name == 'cartesian': + return lambda x, y, z: (x, y, z) + if curv_coord_name == 'spherical': + return lambda r, theta, phi: ( + r*sin(theta)*cos(phi), + r*sin(theta)*sin(phi), + r*cos(theta) + ) + if curv_coord_name == 'cylindrical': + return lambda r, theta, h: ( + r*cos(theta), + r*sin(theta), + h + ) + raise ValueError('Wrong set of parameters.' + 'Type of coordinate system is defined') + + @classmethod + def _rotation_trans_equations(cls, matrix, equations): + """ + Returns the transformation equations obtained from rotation matrix. + + Parameters + ========== + + matrix : Matrix + Rotation matrix + + equations : tuple + Transformation equations + + """ + return tuple(matrix * Matrix(equations)) + + @property + def origin(self): + return self._origin + + def base_vectors(self): + return self._base_vectors + + def base_scalars(self): + return self._base_scalars + + def lame_coefficients(self): + return self._lame_coefficients + + def transformation_to_parent(self): + return self._transformation_lambda(*self.base_scalars()) + + def transformation_from_parent(self): + if self._parent is None: + raise ValueError("no parent coordinate system, use " + "`transformation_from_parent_function()`") + return self._transformation_from_parent_lambda( + *self._parent.base_scalars()) + + def transformation_from_parent_function(self): + return self._transformation_from_parent_lambda + + def rotation_matrix(self, other): + """ + Returns the direction cosine matrix(DCM), also known as the + 'rotation matrix' of this coordinate system with respect to + another system. + + If v_a is a vector defined in system 'A' (in matrix format) + and v_b is the same vector defined in system 'B', then + v_a = A.rotation_matrix(B) * v_b. + + A SymPy Matrix is returned. + + Parameters + ========== + + other : CoordSys3D + The system which the DCM is generated to. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import symbols + >>> q1 = symbols('q1') + >>> N = CoordSys3D('N') + >>> A = N.orient_new_axis('A', q1, N.i) + >>> N.rotation_matrix(A) + Matrix([ + [1, 0, 0], + [0, cos(q1), -sin(q1)], + [0, sin(q1), cos(q1)]]) + + """ + from sympy.vector.functions import _path + if not isinstance(other, CoordSys3D): + raise TypeError(str(other) + + " is not a CoordSys3D") + # Handle special cases + if other == self: + return eye(3) + elif other == self._parent: + return self._parent_rotation_matrix + elif other._parent == self: + return other._parent_rotation_matrix.T + # Else, use tree to calculate position + rootindex, path = _path(self, other) + result = eye(3) + for i in range(rootindex): + result *= path[i]._parent_rotation_matrix + for i in range(rootindex + 1, len(path)): + result *= path[i]._parent_rotation_matrix.T + return result + + @cacheit + def position_wrt(self, other): + """ + Returns the position vector of the origin of this coordinate + system with respect to another Point/CoordSys3D. + + Parameters + ========== + + other : Point/CoordSys3D + If other is a Point, the position of this system's origin + wrt it is returned. If its an instance of CoordSyRect, + the position wrt its origin is returned. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> N = CoordSys3D('N') + >>> N1 = N.locate_new('N1', 10 * N.i) + >>> N.position_wrt(N1) + (-10)*N.i + + """ + return self.origin.position_wrt(other) + + def scalar_map(self, other): + """ + Returns a dictionary which expresses the coordinate variables + (base scalars) of this frame in terms of the variables of + otherframe. + + Parameters + ========== + + otherframe : CoordSys3D + The other system to map the variables to. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import Symbol + >>> A = CoordSys3D('A') + >>> q = Symbol('q') + >>> B = A.orient_new_axis('B', q, A.k) + >>> A.scalar_map(B) + {A.x: B.x*cos(q) - B.y*sin(q), A.y: B.x*sin(q) + B.y*cos(q), A.z: B.z} + + """ + + origin_coords = tuple(self.position_wrt(other).to_matrix(other)) + relocated_scalars = [x - origin_coords[i] + for i, x in enumerate(other.base_scalars())] + + vars_matrix = (self.rotation_matrix(other) * + Matrix(relocated_scalars)) + return {x: trigsimp(vars_matrix[i]) + for i, x in enumerate(self.base_scalars())} + + def locate_new(self, name, position, vector_names=None, + variable_names=None): + """ + Returns a CoordSys3D with its origin located at the given + position wrt this coordinate system's origin. + + Parameters + ========== + + name : str + The name of the new CoordSys3D instance. + + position : Vector + The position vector of the new system's origin wrt this + one. + + vector_names, variable_names : iterable(optional) + Iterables of 3 strings each, with custom names for base + vectors and base scalars of the new system respectively. + Used for simple str printing. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> A = CoordSys3D('A') + >>> B = A.locate_new('B', 10 * A.i) + >>> B.origin.position_wrt(A.origin) + 10*A.i + + """ + if variable_names is None: + variable_names = self._variable_names + if vector_names is None: + vector_names = self._vector_names + + return CoordSys3D(name, location=position, + vector_names=vector_names, + variable_names=variable_names, + parent=self) + + def orient_new(self, name, orienters, location=None, + vector_names=None, variable_names=None): + """ + Creates a new CoordSys3D oriented in the user-specified way + with respect to this system. + + Please refer to the documentation of the orienter classes + for more information about the orientation procedure. + + Parameters + ========== + + name : str + The name of the new CoordSys3D instance. + + orienters : iterable/Orienter + An Orienter or an iterable of Orienters for orienting the + new coordinate system. + If an Orienter is provided, it is applied to get the new + system. + If an iterable is provided, the orienters will be applied + in the order in which they appear in the iterable. + + location : Vector(optional) + The location of the new coordinate system's origin wrt this + system's origin. If not specified, the origins are taken to + be coincident. + + vector_names, variable_names : iterable(optional) + Iterables of 3 strings each, with custom names for base + vectors and base scalars of the new system respectively. + Used for simple str printing. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import symbols + >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') + >>> N = CoordSys3D('N') + + Using an AxisOrienter + + >>> from sympy.vector import AxisOrienter + >>> axis_orienter = AxisOrienter(q1, N.i + 2 * N.j) + >>> A = N.orient_new('A', (axis_orienter, )) + + Using a BodyOrienter + + >>> from sympy.vector import BodyOrienter + >>> body_orienter = BodyOrienter(q1, q2, q3, '123') + >>> B = N.orient_new('B', (body_orienter, )) + + Using a SpaceOrienter + + >>> from sympy.vector import SpaceOrienter + >>> space_orienter = SpaceOrienter(q1, q2, q3, '312') + >>> C = N.orient_new('C', (space_orienter, )) + + Using a QuaternionOrienter + + >>> from sympy.vector import QuaternionOrienter + >>> q_orienter = QuaternionOrienter(q0, q1, q2, q3) + >>> D = N.orient_new('D', (q_orienter, )) + """ + if variable_names is None: + variable_names = self._variable_names + if vector_names is None: + vector_names = self._vector_names + + if isinstance(orienters, Orienter): + if isinstance(orienters, AxisOrienter): + final_matrix = orienters.rotation_matrix(self) + else: + final_matrix = orienters.rotation_matrix() + # TODO: trigsimp is needed here so that the matrix becomes + # canonical (scalar_map also calls trigsimp; without this, you can + # end up with the same CoordinateSystem that compares differently + # due to a differently formatted matrix). However, this is + # probably not so good for performance. + final_matrix = trigsimp(final_matrix) + else: + final_matrix = Matrix(eye(3)) + for orienter in orienters: + if isinstance(orienter, AxisOrienter): + final_matrix *= orienter.rotation_matrix(self) + else: + final_matrix *= orienter.rotation_matrix() + + return CoordSys3D(name, rotation_matrix=final_matrix, + vector_names=vector_names, + variable_names=variable_names, + location=location, + parent=self) + + def orient_new_axis(self, name, angle, axis, location=None, + vector_names=None, variable_names=None): + """ + Axis rotation is a rotation about an arbitrary axis by + some angle. The angle is supplied as a SymPy expr scalar, and + the axis is supplied as a Vector. + + Parameters + ========== + + name : string + The name of the new coordinate system + + angle : Expr + The angle by which the new system is to be rotated + + axis : Vector + The axis around which the rotation has to be performed + + location : Vector(optional) + The location of the new coordinate system's origin wrt this + system's origin. If not specified, the origins are taken to + be coincident. + + vector_names, variable_names : iterable(optional) + Iterables of 3 strings each, with custom names for base + vectors and base scalars of the new system respectively. + Used for simple str printing. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import symbols + >>> q1 = symbols('q1') + >>> N = CoordSys3D('N') + >>> B = N.orient_new_axis('B', q1, N.i + 2 * N.j) + + """ + if variable_names is None: + variable_names = self._variable_names + if vector_names is None: + vector_names = self._vector_names + + orienter = AxisOrienter(angle, axis) + return self.orient_new(name, orienter, + location=location, + vector_names=vector_names, + variable_names=variable_names) + + def orient_new_body(self, name, angle1, angle2, angle3, + rotation_order, location=None, + vector_names=None, variable_names=None): + """ + Body orientation takes this coordinate system through three + successive simple rotations. + + Body fixed rotations include both Euler Angles and + Tait-Bryan Angles, see https://en.wikipedia.org/wiki/Euler_angles. + + Parameters + ========== + + name : string + The name of the new coordinate system + + angle1, angle2, angle3 : Expr + Three successive angles to rotate the coordinate system by + + rotation_order : string + String defining the order of axes for rotation + + location : Vector(optional) + The location of the new coordinate system's origin wrt this + system's origin. If not specified, the origins are taken to + be coincident. + + vector_names, variable_names : iterable(optional) + Iterables of 3 strings each, with custom names for base + vectors and base scalars of the new system respectively. + Used for simple str printing. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import symbols + >>> q1, q2, q3 = symbols('q1 q2 q3') + >>> N = CoordSys3D('N') + + A 'Body' fixed rotation is described by three angles and + three body-fixed rotation axes. To orient a coordinate system D + with respect to N, each sequential rotation is always about + the orthogonal unit vectors fixed to D. For example, a '123' + rotation will specify rotations about N.i, then D.j, then + D.k. (Initially, D.i is same as N.i) + Therefore, + + >>> D = N.orient_new_body('D', q1, q2, q3, '123') + + is same as + + >>> D = N.orient_new_axis('D', q1, N.i) + >>> D = D.orient_new_axis('D', q2, D.j) + >>> D = D.orient_new_axis('D', q3, D.k) + + Acceptable rotation orders are of length 3, expressed in XYZ or + 123, and cannot have a rotation about about an axis twice in a row. + + >>> B = N.orient_new_body('B', q1, q2, q3, '123') + >>> B = N.orient_new_body('B', q1, q2, 0, 'ZXZ') + >>> B = N.orient_new_body('B', 0, 0, 0, 'XYX') + + """ + + orienter = BodyOrienter(angle1, angle2, angle3, rotation_order) + return self.orient_new(name, orienter, + location=location, + vector_names=vector_names, + variable_names=variable_names) + + def orient_new_space(self, name, angle1, angle2, angle3, + rotation_order, location=None, + vector_names=None, variable_names=None): + """ + Space rotation is similar to Body rotation, but the rotations + are applied in the opposite order. + + Parameters + ========== + + name : string + The name of the new coordinate system + + angle1, angle2, angle3 : Expr + Three successive angles to rotate the coordinate system by + + rotation_order : string + String defining the order of axes for rotation + + location : Vector(optional) + The location of the new coordinate system's origin wrt this + system's origin. If not specified, the origins are taken to + be coincident. + + vector_names, variable_names : iterable(optional) + Iterables of 3 strings each, with custom names for base + vectors and base scalars of the new system respectively. + Used for simple str printing. + + See Also + ======== + + CoordSys3D.orient_new_body : method to orient via Euler + angles + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import symbols + >>> q1, q2, q3 = symbols('q1 q2 q3') + >>> N = CoordSys3D('N') + + To orient a coordinate system D with respect to N, each + sequential rotation is always about N's orthogonal unit vectors. + For example, a '123' rotation will specify rotations about + N.i, then N.j, then N.k. + Therefore, + + >>> D = N.orient_new_space('D', q1, q2, q3, '312') + + is same as + + >>> B = N.orient_new_axis('B', q1, N.i) + >>> C = B.orient_new_axis('C', q2, N.j) + >>> D = C.orient_new_axis('D', q3, N.k) + + """ + + orienter = SpaceOrienter(angle1, angle2, angle3, rotation_order) + return self.orient_new(name, orienter, + location=location, + vector_names=vector_names, + variable_names=variable_names) + + def orient_new_quaternion(self, name, q0, q1, q2, q3, location=None, + vector_names=None, variable_names=None): + """ + Quaternion orientation orients the new CoordSys3D with + Quaternions, defined as a finite rotation about lambda, a unit + vector, by some amount theta. + + This orientation is described by four parameters: + + q0 = cos(theta/2) + + q1 = lambda_x sin(theta/2) + + q2 = lambda_y sin(theta/2) + + q3 = lambda_z sin(theta/2) + + Quaternion does not take in a rotation order. + + Parameters + ========== + + name : string + The name of the new coordinate system + + q0, q1, q2, q3 : Expr + The quaternions to rotate the coordinate system by + + location : Vector(optional) + The location of the new coordinate system's origin wrt this + system's origin. If not specified, the origins are taken to + be coincident. + + vector_names, variable_names : iterable(optional) + Iterables of 3 strings each, with custom names for base + vectors and base scalars of the new system respectively. + Used for simple str printing. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import symbols + >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') + >>> N = CoordSys3D('N') + >>> B = N.orient_new_quaternion('B', q0, q1, q2, q3) + + """ + + orienter = QuaternionOrienter(q0, q1, q2, q3) + return self.orient_new(name, orienter, + location=location, + vector_names=vector_names, + variable_names=variable_names) + + def create_new(self, name, transformation, variable_names=None, vector_names=None): + """ + Returns a CoordSys3D which is connected to self by transformation. + + Parameters + ========== + + name : str + The name of the new CoordSys3D instance. + + transformation : Lambda, Tuple, str + Transformation defined by transformation equations or chosen + from predefined ones. + + vector_names, variable_names : iterable(optional) + Iterables of 3 strings each, with custom names for base + vectors and base scalars of the new system respectively. + Used for simple str printing. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> a = CoordSys3D('a') + >>> b = a.create_new('b', transformation='spherical') + >>> b.transformation_to_parent() + (b.r*sin(b.theta)*cos(b.phi), b.r*sin(b.phi)*sin(b.theta), b.r*cos(b.theta)) + >>> b.transformation_from_parent() + (sqrt(a.x**2 + a.y**2 + a.z**2), acos(a.z/sqrt(a.x**2 + a.y**2 + a.z**2)), atan2(a.y, a.x)) + + """ + return CoordSys3D(name, parent=self, transformation=transformation, + variable_names=variable_names, vector_names=vector_names) + + def __init__(self, name, location=None, rotation_matrix=None, + parent=None, vector_names=None, variable_names=None, + latex_vects=None, pretty_vects=None, latex_scalars=None, + pretty_scalars=None, transformation=None): + # Dummy initializer for setting docstring + pass + + __init__.__doc__ = __new__.__doc__ + + @staticmethod + def _compose_rotation_and_translation(rot, translation, parent): + r = lambda x, y, z: CoordSys3D._rotation_trans_equations(rot, (x, y, z)) + if parent is None: + return r + + dx, dy, dz = [translation.dot(i) for i in parent.base_vectors()] + t = lambda x, y, z: ( + x + dx, + y + dy, + z + dz, + ) + return lambda x, y, z: t(*r(x, y, z)) + + +def _check_strings(arg_name, arg): + errorstr = arg_name + " must be an iterable of 3 string-types" + if len(arg) != 3: + raise ValueError(errorstr) + for s in arg: + if not isinstance(s, str): + raise TypeError(errorstr) + + +# Delayed import to avoid cyclic import problems: +from sympy.vector.vector import BaseVector diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/deloperator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/deloperator.py new file mode 100644 index 0000000000000000000000000000000000000000..51c3c0caf42b5e5d372bd65907d8bae2bd563562 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/deloperator.py @@ -0,0 +1,121 @@ +from sympy.core import Basic +from sympy.vector.operators import gradient, divergence, curl + + +class Del(Basic): + """ + Represents the vector differential operator, usually represented in + mathematical expressions as the 'nabla' symbol. + """ + + def __new__(cls): + obj = super().__new__(cls) + obj._name = "delop" + return obj + + def gradient(self, scalar_field, doit=False): + """ + Returns the gradient of the given scalar field, as a + Vector instance. + + Parameters + ========== + + scalar_field : SymPy expression + The scalar field to calculate the gradient of. + + doit : bool + If True, the result is returned after calling .doit() on + each component. Else, the returned expression contains + Derivative instances + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Del + >>> C = CoordSys3D('C') + >>> delop = Del() + >>> delop.gradient(9) + 0 + >>> delop(C.x*C.y*C.z).doit() + C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k + + """ + + return gradient(scalar_field, doit=doit) + + __call__ = gradient + __call__.__doc__ = gradient.__doc__ + + def dot(self, vect, doit=False): + """ + Represents the dot product between this operator and a given + vector - equal to the divergence of the vector field. + + Parameters + ========== + + vect : Vector + The vector whose divergence is to be calculated. + + doit : bool + If True, the result is returned after calling .doit() on + each component. Else, the returned expression contains + Derivative instances + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Del + >>> delop = Del() + >>> C = CoordSys3D('C') + >>> delop.dot(C.x*C.i) + Derivative(C.x, C.x) + >>> v = C.x*C.y*C.z * (C.i + C.j + C.k) + >>> (delop & v).doit() + C.x*C.y + C.x*C.z + C.y*C.z + + """ + return divergence(vect, doit=doit) + + __and__ = dot + __and__.__doc__ = dot.__doc__ + + def cross(self, vect, doit=False): + """ + Represents the cross product between this operator and a given + vector - equal to the curl of the vector field. + + Parameters + ========== + + vect : Vector + The vector whose curl is to be calculated. + + doit : bool + If True, the result is returned after calling .doit() on + each component. Else, the returned expression contains + Derivative instances + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Del + >>> C = CoordSys3D('C') + >>> delop = Del() + >>> v = C.x*C.y*C.z * (C.i + C.j + C.k) + >>> delop.cross(v, doit = True) + (-C.x*C.y + C.x*C.z)*C.i + (C.x*C.y - C.y*C.z)*C.j + + (-C.x*C.z + C.y*C.z)*C.k + >>> (delop ^ C.i).doit() + 0 + + """ + + return curl(vect, doit=doit) + + __xor__ = cross + __xor__.__doc__ = cross.__doc__ + + def _sympystr(self, printer): + return self._name diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/dyadic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/dyadic.py new file mode 100644 index 0000000000000000000000000000000000000000..980c6e6dad90ac095b7bd6d4228f507a7831b39f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/dyadic.py @@ -0,0 +1,285 @@ +from __future__ import annotations + +from sympy.vector.basisdependent import (BasisDependent, BasisDependentAdd, + BasisDependentMul, BasisDependentZero) +from sympy.core import S, Pow +from sympy.core.expr import AtomicExpr +from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix +import sympy.vector + + +class Dyadic(BasisDependent): + """ + Super class for all Dyadic-classes. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Dyadic_tensor + .. [2] Kane, T., Levinson, D. Dynamics Theory and Applications. 1985 + McGraw-Hill + + """ + + _op_priority = 13.0 + + _expr_type: type[Dyadic] + _mul_func: type[Dyadic] + _add_func: type[Dyadic] + _zero_func: type[Dyadic] + _base_func: type[Dyadic] + zero: DyadicZero + + @property + def components(self): + """ + Returns the components of this dyadic in the form of a + Python dictionary mapping BaseDyadic instances to the + corresponding measure numbers. + + """ + # The '_components' attribute is defined according to the + # subclass of Dyadic the instance belongs to. + return self._components + + def dot(self, other): + """ + Returns the dot product(also called inner product) of this + Dyadic, with another Dyadic or Vector. + If 'other' is a Dyadic, this returns a Dyadic. Else, it returns + a Vector (unless an error is encountered). + + Parameters + ========== + + other : Dyadic/Vector + The other Dyadic or Vector to take the inner product with + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> N = CoordSys3D('N') + >>> D1 = N.i.outer(N.j) + >>> D2 = N.j.outer(N.j) + >>> D1.dot(D2) + (N.i|N.j) + >>> D1.dot(N.j) + N.i + + """ + + Vector = sympy.vector.Vector + if isinstance(other, BasisDependentZero): + return Vector.zero + elif isinstance(other, Vector): + outvec = Vector.zero + for k, v in self.components.items(): + vect_dot = k.args[1].dot(other) + outvec += vect_dot * v * k.args[0] + return outvec + elif isinstance(other, Dyadic): + outdyad = Dyadic.zero + for k1, v1 in self.components.items(): + for k2, v2 in other.components.items(): + vect_dot = k1.args[1].dot(k2.args[0]) + outer_product = k1.args[0].outer(k2.args[1]) + outdyad += vect_dot * v1 * v2 * outer_product + return outdyad + else: + raise TypeError("Inner product is not defined for " + + str(type(other)) + " and Dyadics.") + + def __and__(self, other): + return self.dot(other) + + __and__.__doc__ = dot.__doc__ + + def cross(self, other): + """ + Returns the cross product between this Dyadic, and a Vector, as a + Vector instance. + + Parameters + ========== + + other : Vector + The Vector that we are crossing this Dyadic with + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> N = CoordSys3D('N') + >>> d = N.i.outer(N.i) + >>> d.cross(N.j) + (N.i|N.k) + + """ + + Vector = sympy.vector.Vector + if other == Vector.zero: + return Dyadic.zero + elif isinstance(other, Vector): + outdyad = Dyadic.zero + for k, v in self.components.items(): + cross_product = k.args[1].cross(other) + outer = k.args[0].outer(cross_product) + outdyad += v * outer + return outdyad + else: + raise TypeError(str(type(other)) + " not supported for " + + "cross with dyadics") + + def __xor__(self, other): + return self.cross(other) + + __xor__.__doc__ = cross.__doc__ + + def to_matrix(self, system, second_system=None): + """ + Returns the matrix form of the dyadic with respect to one or two + coordinate systems. + + Parameters + ========== + + system : CoordSys3D + The coordinate system that the rows and columns of the matrix + correspond to. If a second system is provided, this + only corresponds to the rows of the matrix. + second_system : CoordSys3D, optional, default=None + The coordinate system that the columns of the matrix correspond + to. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> N = CoordSys3D('N') + >>> v = N.i + 2*N.j + >>> d = v.outer(N.i) + >>> d.to_matrix(N) + Matrix([ + [1, 0, 0], + [2, 0, 0], + [0, 0, 0]]) + >>> from sympy import Symbol + >>> q = Symbol('q') + >>> P = N.orient_new_axis('P', q, N.k) + >>> d.to_matrix(N, P) + Matrix([ + [ cos(q), -sin(q), 0], + [2*cos(q), -2*sin(q), 0], + [ 0, 0, 0]]) + + """ + + if second_system is None: + second_system = system + + return Matrix([i.dot(self).dot(j) for i in system for j in + second_system]).reshape(3, 3) + + def _div_helper(one, other): + """ Helper for division involving dyadics """ + if isinstance(one, Dyadic) and isinstance(other, Dyadic): + raise TypeError("Cannot divide two dyadics") + elif isinstance(one, Dyadic): + return DyadicMul(one, Pow(other, S.NegativeOne)) + else: + raise TypeError("Cannot divide by a dyadic") + + +class BaseDyadic(Dyadic, AtomicExpr): + """ + Class to denote a base dyadic tensor component. + """ + + def __new__(cls, vector1, vector2): + Vector = sympy.vector.Vector + BaseVector = sympy.vector.BaseVector + VectorZero = sympy.vector.VectorZero + # Verify arguments + if not isinstance(vector1, (BaseVector, VectorZero)) or \ + not isinstance(vector2, (BaseVector, VectorZero)): + raise TypeError("BaseDyadic cannot be composed of non-base " + + "vectors") + # Handle special case of zero vector + elif vector1 == Vector.zero or vector2 == Vector.zero: + return Dyadic.zero + # Initialize instance + obj = super().__new__(cls, vector1, vector2) + obj._base_instance = obj + obj._measure_number = 1 + obj._components = {obj: S.One} + obj._sys = vector1._sys + obj._pretty_form = ('(' + vector1._pretty_form + '|' + + vector2._pretty_form + ')') + obj._latex_form = (r'\left(' + vector1._latex_form + r"{\middle|}" + + vector2._latex_form + r'\right)') + + return obj + + def _sympystr(self, printer): + return "({}|{})".format( + printer._print(self.args[0]), printer._print(self.args[1])) + + def _sympyrepr(self, printer): + return "BaseDyadic({}, {})".format( + printer._print(self.args[0]), printer._print(self.args[1])) + + +class DyadicMul(BasisDependentMul, Dyadic): + """ Products of scalars and BaseDyadics """ + + def __new__(cls, *args, **options): + obj = BasisDependentMul.__new__(cls, *args, **options) + return obj + + @property + def base_dyadic(self): + """ The BaseDyadic involved in the product. """ + return self._base_instance + + @property + def measure_number(self): + """ The scalar expression involved in the definition of + this DyadicMul. + """ + return self._measure_number + + +class DyadicAdd(BasisDependentAdd, Dyadic): + """ Class to hold dyadic sums """ + + def __new__(cls, *args, **options): + obj = BasisDependentAdd.__new__(cls, *args, **options) + return obj + + def _sympystr(self, printer): + items = list(self.components.items()) + items.sort(key=lambda x: x[0].__str__()) + return " + ".join(printer._print(k * v) for k, v in items) + + +class DyadicZero(BasisDependentZero, Dyadic): + """ + Class to denote a zero dyadic + """ + + _op_priority = 13.1 + _pretty_form = '(0|0)' + _latex_form = r'(\mathbf{\hat{0}}|\mathbf{\hat{0}})' + + def __new__(cls): + obj = BasisDependentZero.__new__(cls) + return obj + + +Dyadic._expr_type = Dyadic +Dyadic._mul_func = DyadicMul +Dyadic._add_func = DyadicAdd +Dyadic._zero_func = DyadicZero +Dyadic._base_func = BaseDyadic +Dyadic.zero = DyadicZero() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/functions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/functions.py new file mode 100644 index 0000000000000000000000000000000000000000..b78df8ae2e182f3e571ca7fa8bfabd39bf99d26e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/functions.py @@ -0,0 +1,513 @@ +from sympy.vector.coordsysrect import CoordSys3D +from sympy.vector.deloperator import Del +from sympy.vector.scalar import BaseScalar +from sympy.vector.vector import Vector, BaseVector +from sympy.vector.operators import gradient, curl, divergence +from sympy.core.function import diff +from sympy.core.singleton import S +from sympy.integrals.integrals import integrate +from sympy.core import sympify +from sympy.vector.dyadic import Dyadic + + +def express(expr, system, system2=None, variables=False): + """ + Global function for 'express' functionality. + + Re-expresses a Vector, Dyadic or scalar(sympyfiable) in the given + coordinate system. + + If 'variables' is True, then the coordinate variables (base scalars) + of other coordinate systems present in the vector/scalar field or + dyadic are also substituted in terms of the base scalars of the + given system. + + Parameters + ========== + + expr : Vector/Dyadic/scalar(sympyfiable) + The expression to re-express in CoordSys3D 'system' + + system: CoordSys3D + The coordinate system the expr is to be expressed in + + system2: CoordSys3D + The other coordinate system required for re-expression + (only for a Dyadic Expr) + + variables : boolean + Specifies whether to substitute the coordinate variables present + in expr, in terms of those of parameter system + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import Symbol, cos, sin + >>> N = CoordSys3D('N') + >>> q = Symbol('q') + >>> B = N.orient_new_axis('B', q, N.k) + >>> from sympy.vector import express + >>> express(B.i, N) + (cos(q))*N.i + (sin(q))*N.j + >>> express(N.x, B, variables=True) + B.x*cos(q) - B.y*sin(q) + >>> d = N.i.outer(N.i) + >>> express(d, B, N) == (cos(q))*(B.i|N.i) + (-sin(q))*(B.j|N.i) + True + + """ + + if expr in (0, Vector.zero): + return expr + + if not isinstance(system, CoordSys3D): + raise TypeError("system should be a CoordSys3D \ + instance") + + if isinstance(expr, Vector): + if system2 is not None: + raise ValueError("system2 should not be provided for \ + Vectors") + # Given expr is a Vector + if variables: + # If variables attribute is True, substitute + # the coordinate variables in the Vector + system_list = {x.system for x in expr.atoms(BaseScalar, BaseVector)} - {system} + subs_dict = {} + for f in system_list: + subs_dict.update(f.scalar_map(system)) + expr = expr.subs(subs_dict) + # Re-express in this coordinate system + outvec = Vector.zero + parts = expr.separate() + for x in parts: + if x != system: + temp = system.rotation_matrix(x) * parts[x].to_matrix(x) + outvec += matrix_to_vector(temp, system) + else: + outvec += parts[x] + return outvec + + elif isinstance(expr, Dyadic): + if system2 is None: + system2 = system + if not isinstance(system2, CoordSys3D): + raise TypeError("system2 should be a CoordSys3D \ + instance") + outdyad = Dyadic.zero + var = variables + for k, v in expr.components.items(): + outdyad += (express(v, system, variables=var) * + (express(k.args[0], system, variables=var) | + express(k.args[1], system2, variables=var))) + + return outdyad + + else: + if system2 is not None: + raise ValueError("system2 should not be provided for \ + Vectors") + if variables: + # Given expr is a scalar field + system_set = set() + expr = sympify(expr) + # Substitute all the coordinate variables + for x in expr.atoms(BaseScalar): + if x.system != system: + system_set.add(x.system) + subs_dict = {} + for f in system_set: + subs_dict.update(f.scalar_map(system)) + return expr.subs(subs_dict) + return expr + + +def directional_derivative(field, direction_vector): + """ + Returns the directional derivative of a scalar or vector field computed + along a given vector in coordinate system which parameters are expressed. + + Parameters + ========== + + field : Vector or Scalar + The scalar or vector field to compute the directional derivative of + + direction_vector : Vector + The vector to calculated directional derivative along them. + + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, directional_derivative + >>> R = CoordSys3D('R') + >>> f1 = R.x*R.y*R.z + >>> v1 = 3*R.i + 4*R.j + R.k + >>> directional_derivative(f1, v1) + R.x*R.y + 4*R.x*R.z + 3*R.y*R.z + >>> f2 = 5*R.x**2*R.z + >>> directional_derivative(f2, v1) + 5*R.x**2 + 30*R.x*R.z + + """ + from sympy.vector.operators import _get_coord_systems + coord_sys = _get_coord_systems(field) + if len(coord_sys) > 0: + # TODO: This gets a random coordinate system in case of multiple ones: + coord_sys = next(iter(coord_sys)) + field = express(field, coord_sys, variables=True) + i, j, k = coord_sys.base_vectors() + x, y, z = coord_sys.base_scalars() + out = Vector.dot(direction_vector, i) * diff(field, x) + out += Vector.dot(direction_vector, j) * diff(field, y) + out += Vector.dot(direction_vector, k) * diff(field, z) + if out == 0 and isinstance(field, Vector): + out = Vector.zero + return out + elif isinstance(field, Vector): + return Vector.zero + else: + return S.Zero + + +def laplacian(expr): + """ + Return the laplacian of the given field computed in terms of + the base scalars of the given coordinate system. + + Parameters + ========== + + expr : SymPy Expr or Vector + expr denotes a scalar or vector field. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, laplacian + >>> R = CoordSys3D('R') + >>> f = R.x**2*R.y**5*R.z + >>> laplacian(f) + 20*R.x**2*R.y**3*R.z + 2*R.y**5*R.z + >>> f = R.x**2*R.i + R.y**3*R.j + R.z**4*R.k + >>> laplacian(f) + 2*R.i + 6*R.y*R.j + 12*R.z**2*R.k + + """ + + delop = Del() + if expr.is_Vector: + return (gradient(divergence(expr)) - curl(curl(expr))).doit() + return delop.dot(delop(expr)).doit() + + +def is_conservative(field): + """ + Checks if a field is conservative. + + Parameters + ========== + + field : Vector + The field to check for conservative property + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy.vector import is_conservative + >>> R = CoordSys3D('R') + >>> is_conservative(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) + True + >>> is_conservative(R.z*R.j) + False + + """ + + # Field is conservative irrespective of system + # Take the first coordinate system in the result of the + # separate method of Vector + if not isinstance(field, Vector): + raise TypeError("field should be a Vector") + if field == Vector.zero: + return True + return curl(field).simplify() == Vector.zero + + +def is_solenoidal(field): + """ + Checks if a field is solenoidal. + + Parameters + ========== + + field : Vector + The field to check for solenoidal property + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy.vector import is_solenoidal + >>> R = CoordSys3D('R') + >>> is_solenoidal(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) + True + >>> is_solenoidal(R.y * R.j) + False + + """ + + # Field is solenoidal irrespective of system + # Take the first coordinate system in the result of the + # separate method in Vector + if not isinstance(field, Vector): + raise TypeError("field should be a Vector") + if field == Vector.zero: + return True + return divergence(field).simplify() is S.Zero + + +def scalar_potential(field, coord_sys): + """ + Returns the scalar potential function of a field in a given + coordinate system (without the added integration constant). + + Parameters + ========== + + field : Vector + The vector field whose scalar potential function is to be + calculated + + coord_sys : CoordSys3D + The coordinate system to do the calculation in + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy.vector import scalar_potential, gradient + >>> R = CoordSys3D('R') + >>> scalar_potential(R.k, R) == R.z + True + >>> scalar_field = 2*R.x**2*R.y*R.z + >>> grad_field = gradient(scalar_field) + >>> scalar_potential(grad_field, R) + 2*R.x**2*R.y*R.z + + """ + + # Check whether field is conservative + if not is_conservative(field): + raise ValueError("Field is not conservative") + if field == Vector.zero: + return S.Zero + # Express the field exntirely in coord_sys + # Substitute coordinate variables also + if not isinstance(coord_sys, CoordSys3D): + raise TypeError("coord_sys must be a CoordSys3D") + field = express(field, coord_sys, variables=True) + dimensions = coord_sys.base_vectors() + scalars = coord_sys.base_scalars() + # Calculate scalar potential function + temp_function = integrate(field.dot(dimensions[0]), scalars[0]) + for i, dim in enumerate(dimensions[1:]): + partial_diff = diff(temp_function, scalars[i + 1]) + partial_diff = field.dot(dim) - partial_diff + temp_function += integrate(partial_diff, scalars[i + 1]) + return temp_function + + +def scalar_potential_difference(field, coord_sys, point1, point2): + """ + Returns the scalar potential difference between two points in a + certain coordinate system, wrt a given field. + + If a scalar field is provided, its values at the two points are + considered. If a conservative vector field is provided, the values + of its scalar potential function at the two points are used. + + Returns (potential at point2) - (potential at point1) + + The position vectors of the two Points are calculated wrt the + origin of the coordinate system provided. + + Parameters + ========== + + field : Vector/Expr + The field to calculate wrt + + coord_sys : CoordSys3D + The coordinate system to do the calculations in + + point1 : Point + The initial Point in given coordinate system + + position2 : Point + The second Point in the given coordinate system + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy.vector import scalar_potential_difference + >>> R = CoordSys3D('R') + >>> P = R.origin.locate_new('P', R.x*R.i + R.y*R.j + R.z*R.k) + >>> vectfield = 4*R.x*R.y*R.i + 2*R.x**2*R.j + >>> scalar_potential_difference(vectfield, R, R.origin, P) + 2*R.x**2*R.y + >>> Q = R.origin.locate_new('O', 3*R.i + R.j + 2*R.k) + >>> scalar_potential_difference(vectfield, R, P, Q) + -2*R.x**2*R.y + 18 + + """ + + if not isinstance(coord_sys, CoordSys3D): + raise TypeError("coord_sys must be a CoordSys3D") + if isinstance(field, Vector): + # Get the scalar potential function + scalar_fn = scalar_potential(field, coord_sys) + else: + # Field is a scalar + scalar_fn = field + # Express positions in required coordinate system + origin = coord_sys.origin + position1 = express(point1.position_wrt(origin), coord_sys, + variables=True) + position2 = express(point2.position_wrt(origin), coord_sys, + variables=True) + # Get the two positions as substitution dicts for coordinate variables + subs_dict1 = {} + subs_dict2 = {} + scalars = coord_sys.base_scalars() + for i, x in enumerate(coord_sys.base_vectors()): + subs_dict1[scalars[i]] = x.dot(position1) + subs_dict2[scalars[i]] = x.dot(position2) + return scalar_fn.subs(subs_dict2) - scalar_fn.subs(subs_dict1) + + +def matrix_to_vector(matrix, system): + """ + Converts a vector in matrix form to a Vector instance. + + It is assumed that the elements of the Matrix represent the + measure numbers of the components of the vector along basis + vectors of 'system'. + + Parameters + ========== + + matrix : SymPy Matrix, Dimensions: (3, 1) + The matrix to be converted to a vector + + system : CoordSys3D + The coordinate system the vector is to be defined in + + Examples + ======== + + >>> from sympy import ImmutableMatrix as Matrix + >>> m = Matrix([1, 2, 3]) + >>> from sympy.vector import CoordSys3D, matrix_to_vector + >>> C = CoordSys3D('C') + >>> v = matrix_to_vector(m, C) + >>> v + C.i + 2*C.j + 3*C.k + >>> v.to_matrix(C) == m + True + + """ + + outvec = Vector.zero + vects = system.base_vectors() + for i, x in enumerate(matrix): + outvec += x * vects[i] + return outvec + + +def _path(from_object, to_object): + """ + Calculates the 'path' of objects starting from 'from_object' + to 'to_object', along with the index of the first common + ancestor in the tree. + + Returns (index, list) tuple. + """ + + if from_object._root != to_object._root: + raise ValueError("No connecting path found between " + + str(from_object) + " and " + str(to_object)) + + other_path = [] + obj = to_object + while obj._parent is not None: + other_path.append(obj) + obj = obj._parent + other_path.append(obj) + object_set = set(other_path) + from_path = [] + obj = from_object + while obj not in object_set: + from_path.append(obj) + obj = obj._parent + index = len(from_path) + from_path.extend(other_path[other_path.index(obj)::-1]) + return index, from_path + + +def orthogonalize(*vlist, orthonormal=False): + """ + Takes a sequence of independent vectors and orthogonalizes them + using the Gram - Schmidt process. Returns a list of + orthogonal or orthonormal vectors. + + Parameters + ========== + + vlist : sequence of independent vectors to be made orthogonal. + + orthonormal : Optional parameter + Set to True if the vectors returned should be + orthonormal. + Default: False + + Examples + ======== + + >>> from sympy.vector.coordsysrect import CoordSys3D + >>> from sympy.vector.functions import orthogonalize + >>> C = CoordSys3D('C') + >>> i, j, k = C.base_vectors() + >>> v1 = i + 2*j + >>> v2 = 2*i + 3*j + >>> orthogonalize(v1, v2) + [C.i + 2*C.j, 2/5*C.i + (-1/5)*C.j] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Gram-Schmidt_process + + """ + + if not all(isinstance(vec, Vector) for vec in vlist): + raise TypeError('Each element must be of Type Vector') + + ortho_vlist = [] + for i, term in enumerate(vlist): + for j in range(i): + term -= ortho_vlist[j].projection(vlist[i]) + # TODO : The following line introduces a performance issue + # and needs to be changed once a good solution for issue #10279 is + # found. + if term.equals(Vector.zero): + raise ValueError("Vector set not linearly independent") + ortho_vlist.append(term) + + if orthonormal: + ortho_vlist = [vec.normalize() for vec in ortho_vlist] + + return ortho_vlist diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/implicitregion.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/implicitregion.py new file mode 100644 index 0000000000000000000000000000000000000000..ed2d55a1be8b1eaca71d08b632a94886a2b0269c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/implicitregion.py @@ -0,0 +1,506 @@ +from sympy.core.numbers import Rational +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.complexes import sign +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.polys.polytools import gcd +from sympy.sets.sets import Complement +from sympy.core import Basic, Tuple, diff, expand, Eq, Integer +from sympy.core.sorting import ordered +from sympy.core.symbol import _symbol +from sympy.solvers import solveset, nonlinsolve, diophantine +from sympy.polys import total_degree +from sympy.geometry import Point +from sympy.ntheory.factor_ import core + + +class ImplicitRegion(Basic): + """ + Represents an implicit region in space. + + Examples + ======== + + >>> from sympy import Eq + >>> from sympy.abc import x, y, z, t + >>> from sympy.vector import ImplicitRegion + + >>> ImplicitRegion((x, y), x**2 + y**2 - 4) + ImplicitRegion((x, y), x**2 + y**2 - 4) + >>> ImplicitRegion((x, y), Eq(y*x, 1)) + ImplicitRegion((x, y), x*y - 1) + + >>> parabola = ImplicitRegion((x, y), y**2 - 4*x) + >>> parabola.degree + 2 + >>> parabola.equation + -4*x + y**2 + >>> parabola.rational_parametrization(t) + (4/t**2, 4/t) + + >>> r = ImplicitRegion((x, y, z), Eq(z, x**2 + y**2)) + >>> r.variables + (x, y, z) + >>> r.singular_points() + EmptySet + >>> r.regular_point() + (-10, -10, 200) + + Parameters + ========== + + variables : tuple to map variables in implicit equation to base scalars. + + equation : An expression or Eq denoting the implicit equation of the region. + + """ + def __new__(cls, variables, equation): + if not isinstance(variables, Tuple): + variables = Tuple(*variables) + + if isinstance(equation, Eq): + equation = equation.lhs - equation.rhs + + return super().__new__(cls, variables, equation) + + @property + def variables(self): + return self.args[0] + + @property + def equation(self): + return self.args[1] + + @property + def degree(self): + return total_degree(self.equation) + + def regular_point(self): + """ + Returns a point on the implicit region. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.vector import ImplicitRegion + >>> circle = ImplicitRegion((x, y), (x + 2)**2 + (y - 3)**2 - 16) + >>> circle.regular_point() + (-2, -1) + >>> parabola = ImplicitRegion((x, y), x**2 - 4*y) + >>> parabola.regular_point() + (0, 0) + >>> r = ImplicitRegion((x, y, z), (x + y + z)**4) + >>> r.regular_point() + (-10, -10, 20) + + References + ========== + + - Erik Hillgarter, "Rational Points on Conics", Diploma Thesis, RISC-Linz, + J. Kepler Universitat Linz, 1996. Available: + https://www3.risc.jku.at/publications/download/risc_1355/Rational%20Points%20on%20Conics.pdf + + """ + equation = self.equation + + if len(self.variables) == 1: + return (list(solveset(equation, self.variables[0], domain=S.Reals))[0],) + elif len(self.variables) == 2: + + if self.degree == 2: + coeffs = a, b, c, d, e, f = conic_coeff(self.variables, equation) + + if b**2 == 4*a*c: + x_reg, y_reg = self._regular_point_parabola(*coeffs) + else: + x_reg, y_reg = self._regular_point_ellipse(*coeffs) + return x_reg, y_reg + + if len(self.variables) == 3: + x, y, z = self.variables + + for x_reg in range(-10, 10): + for y_reg in range(-10, 10): + if not solveset(equation.subs({x: x_reg, y: y_reg}), self.variables[2], domain=S.Reals).is_empty: + return (x_reg, y_reg, list(solveset(equation.subs({x: x_reg, y: y_reg})))[0]) + + if len(self.singular_points()) != 0: + return list[self.singular_points()][0] + + raise NotImplementedError() + + def _regular_point_parabola(self, a, b, c, d, e, f): + ok = (a, d) != (0, 0) and (c, e) != (0, 0) and b**2 == 4*a*c and (a, c) != (0, 0) + + if not ok: + raise ValueError("Rational Point on the conic does not exist") + + if a != 0: + d_dash, f_dash = (4*a*e - 2*b*d, 4*a*f - d**2) + if d_dash != 0: + y_reg = -f_dash/d_dash + x_reg = -(d + b*y_reg)/(2*a) + else: + ok = False + elif c != 0: + d_dash, f_dash = (4*c*d - 2*b*e, 4*c*f - e**2) + if d_dash != 0: + x_reg = -f_dash/d_dash + y_reg = -(e + b*x_reg)/(2*c) + else: + ok = False + + if ok: + return x_reg, y_reg + else: + raise ValueError("Rational Point on the conic does not exist") + + def _regular_point_ellipse(self, a, b, c, d, e, f): + D = 4*a*c - b**2 + ok = D + + if not ok: + raise ValueError("Rational Point on the conic does not exist") + + if a == 0 and c == 0: + K = -1 + L = 4*(d*e - b*f) + elif c != 0: + K = D + L = 4*c**2*d**2 - 4*b*c*d*e + 4*a*c*e**2 + 4*b**2*c*f - 16*a*c**2*f + else: + K = D + L = 4*a**2*e**2 - 4*b*a*d*e + 4*b**2*a*f + + ok = L != 0 and not(K > 0 and L < 0) + if not ok: + raise ValueError("Rational Point on the conic does not exist") + + K = Rational(K).limit_denominator(10**12) + L = Rational(L).limit_denominator(10**12) + + k1, k2 = K.p, K.q + l1, l2 = L.p, L.q + g = gcd(k2, l2) + + a1 = (l2*k2)/g + b1 = (k1*l2)/g + c1 = -(l1*k2)/g + a2 = sign(a1)*core(abs(a1), 2) + r1 = sqrt(a1/a2) + b2 = sign(b1)*core(abs(b1), 2) + r2 = sqrt(b1/b2) + c2 = sign(c1)*core(abs(c1), 2) + r3 = sqrt(c1/c2) + + g = gcd(gcd(a2, b2), c2) + a2 = a2/g + b2 = b2/g + c2 = c2/g + + g1 = gcd(a2, b2) + a2 = a2/g1 + b2 = b2/g1 + c2 = c2*g1 + + g2 = gcd(a2,c2) + a2 = a2/g2 + b2 = b2*g2 + c2 = c2/g2 + + g3 = gcd(b2, c2) + a2 = a2*g3 + b2 = b2/g3 + c2 = c2/g3 + + x, y, z = symbols("x y z") + eq = a2*x**2 + b2*y**2 + c2*z**2 + + solutions = diophantine(eq) + + if len(solutions) == 0: + raise ValueError("Rational Point on the conic does not exist") + + flag = False + for sol in solutions: + syms = Tuple(*sol).free_symbols + rep = dict.fromkeys(syms, 3) + sol_z = sol[2] + + if sol_z == 0: + flag = True + continue + + if not isinstance(sol_z, (int, Integer)): + syms_z = sol_z.free_symbols + + if len(syms_z) == 1: + p = next(iter(syms_z)) + p_values = Complement(S.Integers, solveset(Eq(sol_z, 0), p, S.Integers)) + rep[p] = next(iter(p_values)) + + if len(syms_z) == 2: + p, q = list(ordered(syms_z)) + + for i in S.Integers: + subs_sol_z = sol_z.subs(p, i) + q_values = Complement(S.Integers, solveset(Eq(subs_sol_z, 0), q, S.Integers)) + + if not q_values.is_empty: + rep[p] = i + rep[q] = next(iter(q_values)) + break + + if len(syms) != 0: + x, y, z = tuple(s.subs(rep) for s in sol) + else: + x, y, z = sol + flag = False + break + + if flag: + raise ValueError("Rational Point on the conic does not exist") + + x = (x*g3)/r1 + y = (y*g2)/r2 + z = (z*g1)/r3 + x = x/z + y = y/z + + if a == 0 and c == 0: + x_reg = (x + y - 2*e)/(2*b) + y_reg = (x - y - 2*d)/(2*b) + elif c != 0: + x_reg = (x - 2*d*c + b*e)/K + y_reg = (y - b*x_reg - e)/(2*c) + else: + y_reg = (x - 2*e*a + b*d)/K + x_reg = (y - b*y_reg - d)/(2*a) + + return x_reg, y_reg + + def singular_points(self): + """ + Returns a set of singular points of the region. + + The singular points are those points on the region + where all partial derivatives vanish. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.vector import ImplicitRegion + >>> I = ImplicitRegion((x, y), (y-1)**2 -x**3 + 2*x**2 -x) + >>> I.singular_points() + {(1, 1)} + + """ + eq_list = [self.equation] + for var in self.variables: + eq_list += [diff(self.equation, var)] + + return nonlinsolve(eq_list, list(self.variables)) + + def multiplicity(self, point): + """ + Returns the multiplicity of a singular point on the region. + + A singular point (x,y) of region is said to be of multiplicity m + if all the partial derivatives off to order m - 1 vanish there. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.vector import ImplicitRegion + >>> I = ImplicitRegion((x, y, z), x**2 + y**3 - z**4) + >>> I.singular_points() + {(0, 0, 0)} + >>> I.multiplicity((0, 0, 0)) + 2 + + """ + if isinstance(point, Point): + point = point.args + + modified_eq = self.equation + + for i, var in enumerate(self.variables): + modified_eq = modified_eq.subs(var, var + point[i]) + modified_eq = expand(modified_eq) + + if len(modified_eq.args) != 0: + terms = modified_eq.args + m = min(total_degree(term) for term in terms) + else: + terms = modified_eq + m = total_degree(terms) + + return m + + def rational_parametrization(self, parameters=('t', 's'), reg_point=None): + """ + Returns the rational parametrization of implicit region. + + Examples + ======== + + >>> from sympy import Eq + >>> from sympy.abc import x, y, z, s, t + >>> from sympy.vector import ImplicitRegion + + >>> parabola = ImplicitRegion((x, y), y**2 - 4*x) + >>> parabola.rational_parametrization() + (4/t**2, 4/t) + + >>> circle = ImplicitRegion((x, y), Eq(x**2 + y**2, 4)) + >>> circle.rational_parametrization() + (4*t/(t**2 + 1), 4*t**2/(t**2 + 1) - 2) + + >>> I = ImplicitRegion((x, y), x**3 + x**2 - y**2) + >>> I.rational_parametrization() + (t**2 - 1, t*(t**2 - 1)) + + >>> cubic_curve = ImplicitRegion((x, y), x**3 + x**2 - y**2) + >>> cubic_curve.rational_parametrization(parameters=(t)) + (t**2 - 1, t*(t**2 - 1)) + + >>> sphere = ImplicitRegion((x, y, z), x**2 + y**2 + z**2 - 4) + >>> sphere.rational_parametrization(parameters=(t, s)) + (-2 + 4/(s**2 + t**2 + 1), 4*s/(s**2 + t**2 + 1), 4*t/(s**2 + t**2 + 1)) + + For some conics, regular_points() is unable to find a point on curve. + To calulcate the parametric representation in such cases, user need + to determine a point on the region and pass it using reg_point. + + >>> c = ImplicitRegion((x, y), (x - 1/2)**2 + (y)**2 - (1/4)**2) + >>> c.rational_parametrization(reg_point=(3/4, 0)) + (0.75 - 0.5/(t**2 + 1), -0.5*t/(t**2 + 1)) + + References + ========== + + - Christoph M. Hoffmann, "Conversion Methods between Parametric and + Implicit Curves and Surfaces", Purdue e-Pubs, 1990. Available: + https://docs.lib.purdue.edu/cgi/viewcontent.cgi?article=1827&context=cstech + + """ + equation = self.equation + degree = self.degree + + if degree == 1: + if len(self.variables) == 1: + return (equation,) + elif len(self.variables) == 2: + x, y = self.variables + y_par = list(solveset(equation, y))[0] + return x, y_par + else: + raise NotImplementedError() + + point = () + + # Finding the (n - 1) fold point of the monoid of degree + if degree == 2: + # For degree 2 curves, either a regular point or a singular point can be used. + if reg_point is not None: + # Using point provided by the user as regular point + point = reg_point + else: + if len(self.singular_points()) != 0: + point = list(self.singular_points())[0] + else: + point = self.regular_point() + + if len(self.singular_points()) != 0: + singular_points = self.singular_points() + for spoint in singular_points: + syms = Tuple(*spoint).free_symbols + rep = dict.fromkeys(syms, 2) + + if len(syms) != 0: + spoint = tuple(s.subs(rep) for s in spoint) + + if self.multiplicity(spoint) == degree - 1: + point = spoint + break + + if len(point) == 0: + # The region in not a monoid + raise NotImplementedError() + + modified_eq = equation + + # Shifting the region such that fold point moves to origin + for i, var in enumerate(self.variables): + modified_eq = modified_eq.subs(var, var + point[i]) + modified_eq = expand(modified_eq) + + hn = hn_1 = 0 + for term in modified_eq.args: + if total_degree(term) == degree: + hn += term + else: + hn_1 += term + + hn_1 = -1*hn_1 + + if not isinstance(parameters, tuple): + parameters = (parameters,) + + if len(self.variables) == 2: + + parameter1 = parameters[0] + if parameter1 == 's': + # To avoid name conflict between parameters + s = _symbol('s_', real=True) + else: + s = _symbol('s', real=True) + t = _symbol(parameter1, real=True) + + hn = hn.subs({self.variables[0]: s, self.variables[1]: t}) + hn_1 = hn_1.subs({self.variables[0]: s, self.variables[1]: t}) + + x_par = (s*(hn_1/hn)).subs(s, 1) + point[0] + y_par = (t*(hn_1/hn)).subs(s, 1) + point[1] + + return x_par, y_par + + elif len(self.variables) == 3: + + parameter1, parameter2 = parameters + if 'r' in parameters: + # To avoid name conflict between parameters + r = _symbol('r_', real=True) + else: + r = _symbol('r', real=True) + s = _symbol(parameter2, real=True) + t = _symbol(parameter1, real=True) + + hn = hn.subs({self.variables[0]: r, self.variables[1]: s, self.variables[2]: t}) + hn_1 = hn_1.subs({self.variables[0]: r, self.variables[1]: s, self.variables[2]: t}) + + x_par = (r*(hn_1/hn)).subs(r, 1) + point[0] + y_par = (s*(hn_1/hn)).subs(r, 1) + point[1] + z_par = (t*(hn_1/hn)).subs(r, 1) + point[2] + + return x_par, y_par, z_par + + raise NotImplementedError() + +def conic_coeff(variables, equation): + if total_degree(equation) != 2: + raise ValueError() + x = variables[0] + y = variables[1] + + equation = expand(equation) + a = equation.coeff(x**2) + b = equation.coeff(x*y) + c = equation.coeff(y**2) + d = equation.coeff(x, 1).coeff(y, 0) + e = equation.coeff(y, 1).coeff(x, 0) + f = equation.coeff(x, 0).coeff(y, 0) + return a, b, c, d, e, f diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/integrals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/integrals.py new file mode 100644 index 0000000000000000000000000000000000000000..a6451c182f214b20b1105eb0a4dc243455c9d126 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/integrals.py @@ -0,0 +1,206 @@ +from sympy.core import Basic, diff +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.matrices import Matrix +from sympy.integrals import Integral, integrate +from sympy.geometry.entity import GeometryEntity +from sympy.simplify.simplify import simplify +from sympy.utilities.iterables import topological_sort +from sympy.vector import (CoordSys3D, Vector, ParametricRegion, + parametric_region_list, ImplicitRegion) +from sympy.vector.operators import _get_coord_systems + + +class ParametricIntegral(Basic): + """ + Represents integral of a scalar or vector field + over a Parametric Region + + Examples + ======== + + >>> from sympy import cos, sin, pi + >>> from sympy.vector import CoordSys3D, ParametricRegion, ParametricIntegral + >>> from sympy.abc import r, t, theta, phi + + >>> C = CoordSys3D('C') + >>> curve = ParametricRegion((3*t - 2, t + 1), (t, 1, 2)) + >>> ParametricIntegral(C.x, curve) + 5*sqrt(10)/2 + >>> length = ParametricIntegral(1, curve) + >>> length + sqrt(10) + >>> semisphere = ParametricRegion((2*sin(phi)*cos(theta), 2*sin(phi)*sin(theta), 2*cos(phi)),\ + (theta, 0, 2*pi), (phi, 0, pi/2)) + >>> ParametricIntegral(C.z, semisphere) + 8*pi + + >>> ParametricIntegral(C.j + C.k, ParametricRegion((r*cos(theta), r*sin(theta)), r, theta)) + 0 + + """ + + def __new__(cls, field, parametricregion): + + coord_set = _get_coord_systems(field) + + if len(coord_set) == 0: + coord_sys = CoordSys3D('C') + elif len(coord_set) > 1: + raise ValueError + else: + coord_sys = next(iter(coord_set)) + + if parametricregion.dimensions == 0: + return S.Zero + + base_vectors = coord_sys.base_vectors() + base_scalars = coord_sys.base_scalars() + + parametricfield = field + + r = Vector.zero + for i in range(len(parametricregion.definition)): + r += base_vectors[i]*parametricregion.definition[i] + + if len(coord_set) != 0: + for i in range(len(parametricregion.definition)): + parametricfield = parametricfield.subs(base_scalars[i], parametricregion.definition[i]) + + if parametricregion.dimensions == 1: + parameter = parametricregion.parameters[0] + + r_diff = diff(r, parameter) + lower, upper = parametricregion.limits[parameter][0], parametricregion.limits[parameter][1] + + if isinstance(parametricfield, Vector): + integrand = simplify(r_diff.dot(parametricfield)) + else: + integrand = simplify(r_diff.magnitude()*parametricfield) + + result = integrate(integrand, (parameter, lower, upper)) + + elif parametricregion.dimensions == 2: + u, v = cls._bounds_case(parametricregion.parameters, parametricregion.limits) + + r_u = diff(r, u) + r_v = diff(r, v) + normal_vector = simplify(r_u.cross(r_v)) + + if isinstance(parametricfield, Vector): + integrand = parametricfield.dot(normal_vector) + else: + integrand = parametricfield*normal_vector.magnitude() + + integrand = simplify(integrand) + + lower_u, upper_u = parametricregion.limits[u][0], parametricregion.limits[u][1] + lower_v, upper_v = parametricregion.limits[v][0], parametricregion.limits[v][1] + + result = integrate(integrand, (u, lower_u, upper_u), (v, lower_v, upper_v)) + + else: + variables = cls._bounds_case(parametricregion.parameters, parametricregion.limits) + coeff = Matrix(parametricregion.definition).jacobian(variables).det() + integrand = simplify(parametricfield*coeff) + + l = [(var, parametricregion.limits[var][0], parametricregion.limits[var][1]) for var in variables] + result = integrate(integrand, *l) + + if not isinstance(result, Integral): + return result + else: + return super().__new__(cls, field, parametricregion) + + @classmethod + def _bounds_case(cls, parameters, limits): + + V = list(limits.keys()) + E = [] + + for p in V: + lower_p = limits[p][0] + upper_p = limits[p][1] + + lower_p = lower_p.atoms() + upper_p = upper_p.atoms() + E.extend((p, q) for q in V if p != q and + (lower_p.issuperset({q}) or upper_p.issuperset({q}))) + + if not E: + return parameters + else: + return topological_sort((V, E), key=default_sort_key) + + @property + def field(self): + return self.args[0] + + @property + def parametricregion(self): + return self.args[1] + + +def vector_integrate(field, *region): + """ + Compute the integral of a vector/scalar field + over a a region or a set of parameters. + + Examples + ======== + >>> from sympy.vector import CoordSys3D, ParametricRegion, vector_integrate + >>> from sympy.abc import x, y, t + >>> C = CoordSys3D('C') + + >>> region = ParametricRegion((t, t**2), (t, 1, 5)) + >>> vector_integrate(C.x*C.i, region) + 12 + + Integrals over some objects of geometry module can also be calculated. + + >>> from sympy.geometry import Point, Circle, Triangle + >>> c = Circle(Point(0, 2), 5) + >>> vector_integrate(C.x**2 + C.y**2, c) + 290*pi + >>> triangle = Triangle(Point(-2, 3), Point(2, 3), Point(0, 5)) + >>> vector_integrate(3*C.x**2*C.y*C.i + C.j, triangle) + -8 + + Integrals over some simple implicit regions can be computed. But in most cases, + it takes too long to compute over them. This is due to the expressions of parametric + representation becoming large. + + >>> from sympy.vector import ImplicitRegion + >>> c2 = ImplicitRegion((x, y), (x - 2)**2 + (y - 1)**2 - 9) + >>> vector_integrate(1, c2) + 6*pi + + Integral of fields with respect to base scalars: + + >>> vector_integrate(12*C.y**3, (C.y, 1, 3)) + 240 + >>> vector_integrate(C.x**2*C.z, C.x) + C.x**3*C.z/3 + >>> vector_integrate(C.x*C.i - C.y*C.k, C.x) + (Integral(C.x, C.x))*C.i + (Integral(-C.y, C.x))*C.k + >>> _.doit() + C.x**2/2*C.i + (-C.x*C.y)*C.k + + """ + if len(region) == 1: + if isinstance(region[0], ParametricRegion): + return ParametricIntegral(field, region[0]) + + if isinstance(region[0], ImplicitRegion): + region = parametric_region_list(region[0])[0] + return vector_integrate(field, region) + + if isinstance(region[0], GeometryEntity): + regions_list = parametric_region_list(region[0]) + + result = 0 + for reg in regions_list: + result += vector_integrate(field, reg) + return result + + return integrate(field, *region) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/kind.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/kind.py new file mode 100644 index 0000000000000000000000000000000000000000..c6c04896b34c9c92c3fb340d94985df859e5877d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/kind.py @@ -0,0 +1,67 @@ +#sympy.vector.kind + +from sympy.core.kind import Kind, _NumberKind, NumberKind +from sympy.core.mul import Mul + +class VectorKind(Kind): + """ + Kind for all vector objects in SymPy. + + Parameters + ========== + + element_kind : Kind + Kind of the element. Default is + :class:`sympy.core.kind.NumberKind`, + which means that the vector contains only numbers. + + Examples + ======== + + Any instance of Vector class has kind ``VectorKind``: + + >>> from sympy.vector.coordsysrect import CoordSys3D + >>> Sys = CoordSys3D('Sys') + >>> Sys.i.kind + VectorKind(NumberKind) + + Operations between instances of Vector keep also have the kind ``VectorKind``: + + >>> from sympy.core.add import Add + >>> v1 = Sys.i * 2 + Sys.j * 3 + Sys.k * 4 + >>> v2 = Sys.i * Sys.x + Sys.j * Sys.y + Sys.k * Sys.z + >>> v1.kind + VectorKind(NumberKind) + >>> v2.kind + VectorKind(NumberKind) + >>> Add(v1, v2).kind + VectorKind(NumberKind) + + Subclasses of Vector also have the kind ``VectorKind``, such as + Cross, VectorAdd, VectorMul or VectorZero. + + See Also + ======== + + sympy.core.kind.Kind + sympy.matrices.kind.MatrixKind + + """ + def __new__(cls, element_kind=NumberKind): + obj = super().__new__(cls, element_kind) + obj.element_kind = element_kind + return obj + + def __repr__(self): + return "VectorKind(%s)" % self.element_kind + +@Mul._kind_dispatcher.register(_NumberKind, VectorKind) +def num_vec_mul(k1, k2): + """ + The result of a multiplication between a number and a Vector should be of VectorKind. + The element kind is selected by recursive dispatching. + """ + if not isinstance(k2, VectorKind): + k1, k2 = k2, k1 + elemk = Mul._kind_dispatcher(k1, k2.element_kind) + return VectorKind(elemk) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/operators.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/operators.py new file mode 100644 index 0000000000000000000000000000000000000000..3ca42d20302f972cef66e0b4a35ac75606b2da94 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/operators.py @@ -0,0 +1,335 @@ +import collections +from sympy.core.expr import Expr +from sympy.core import sympify, S, preorder_traversal +from sympy.vector.coordsysrect import CoordSys3D +from sympy.vector.vector import Vector, VectorMul, VectorAdd, Cross, Dot +from sympy.core.function import Derivative +from sympy.core.add import Add +from sympy.core.mul import Mul + + +def _get_coord_systems(expr): + g = preorder_traversal(expr) + ret = set() + for i in g: + if isinstance(i, CoordSys3D): + ret.add(i) + g.skip() + return frozenset(ret) + + +def _split_mul_args_wrt_coordsys(expr): + d = collections.defaultdict(lambda: S.One) + for i in expr.args: + d[_get_coord_systems(i)] *= i + return list(d.values()) + + +class Gradient(Expr): + """ + Represents unevaluated Gradient. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Gradient + >>> R = CoordSys3D('R') + >>> s = R.x*R.y*R.z + >>> Gradient(s) + Gradient(R.x*R.y*R.z) + + """ + + def __new__(cls, expr): + expr = sympify(expr) + obj = Expr.__new__(cls, expr) + obj._expr = expr + return obj + + def doit(self, **hints): + return gradient(self._expr, doit=True) + + +class Divergence(Expr): + """ + Represents unevaluated Divergence. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Divergence + >>> R = CoordSys3D('R') + >>> v = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k + >>> Divergence(v) + Divergence(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) + + """ + + def __new__(cls, expr): + expr = sympify(expr) + obj = Expr.__new__(cls, expr) + obj._expr = expr + return obj + + def doit(self, **hints): + return divergence(self._expr, doit=True) + + +class Curl(Expr): + """ + Represents unevaluated Curl. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Curl + >>> R = CoordSys3D('R') + >>> v = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k + >>> Curl(v) + Curl(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) + + """ + + def __new__(cls, expr): + expr = sympify(expr) + obj = Expr.__new__(cls, expr) + obj._expr = expr + return obj + + def doit(self, **hints): + return curl(self._expr, doit=True) + + +def curl(vect, doit=True): + """ + Returns the curl of a vector field computed wrt the base scalars + of the given coordinate system. + + Parameters + ========== + + vect : Vector + The vector operand + + doit : bool + If True, the result is returned after calling .doit() on + each component. Else, the returned expression contains + Derivative instances + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, curl + >>> R = CoordSys3D('R') + >>> v1 = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k + >>> curl(v1) + 0 + >>> v2 = R.x*R.y*R.z*R.i + >>> curl(v2) + R.x*R.y*R.j + (-R.x*R.z)*R.k + + """ + + coord_sys = _get_coord_systems(vect) + + if len(coord_sys) == 0: + return Vector.zero + elif len(coord_sys) == 1: + coord_sys = next(iter(coord_sys)) + i, j, k = coord_sys.base_vectors() + x, y, z = coord_sys.base_scalars() + h1, h2, h3 = coord_sys.lame_coefficients() + vectx = vect.dot(i) + vecty = vect.dot(j) + vectz = vect.dot(k) + outvec = Vector.zero + outvec += (Derivative(vectz * h3, y) - + Derivative(vecty * h2, z)) * i / (h2 * h3) + outvec += (Derivative(vectx * h1, z) - + Derivative(vectz * h3, x)) * j / (h1 * h3) + outvec += (Derivative(vecty * h2, x) - + Derivative(vectx * h1, y)) * k / (h2 * h1) + + if doit: + return outvec.doit() + return outvec + else: + if isinstance(vect, (Add, VectorAdd)): + from sympy.vector import express + try: + cs = next(iter(coord_sys)) + args = [express(i, cs, variables=True) for i in vect.args] + except ValueError: + args = vect.args + return VectorAdd.fromiter(curl(i, doit=doit) for i in args) + elif isinstance(vect, (Mul, VectorMul)): + vector = [i for i in vect.args if isinstance(i, (Vector, Cross, Gradient))][0] + scalar = Mul.fromiter(i for i in vect.args if not isinstance(i, (Vector, Cross, Gradient))) + res = Cross(gradient(scalar), vector).doit() + scalar*curl(vector, doit=doit) + if doit: + return res.doit() + return res + elif isinstance(vect, (Cross, Curl, Gradient)): + return Curl(vect) + else: + raise ValueError("Invalid argument for curl") + + +def divergence(vect, doit=True): + """ + Returns the divergence of a vector field computed wrt the base + scalars of the given coordinate system. + + Parameters + ========== + + vector : Vector + The vector operand + + doit : bool + If True, the result is returned after calling .doit() on + each component. Else, the returned expression contains + Derivative instances + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, divergence + >>> R = CoordSys3D('R') + >>> v1 = R.x*R.y*R.z * (R.i+R.j+R.k) + + >>> divergence(v1) + R.x*R.y + R.x*R.z + R.y*R.z + >>> v2 = 2*R.y*R.z*R.j + >>> divergence(v2) + 2*R.z + + """ + coord_sys = _get_coord_systems(vect) + if len(coord_sys) == 0: + return S.Zero + elif len(coord_sys) == 1: + if isinstance(vect, (Cross, Curl, Gradient)): + return Divergence(vect) + # TODO: is case of many coord systems, this gets a random one: + coord_sys = next(iter(coord_sys)) + i, j, k = coord_sys.base_vectors() + x, y, z = coord_sys.base_scalars() + h1, h2, h3 = coord_sys.lame_coefficients() + vx = _diff_conditional(vect.dot(i), x, h2, h3) \ + / (h1 * h2 * h3) + vy = _diff_conditional(vect.dot(j), y, h3, h1) \ + / (h1 * h2 * h3) + vz = _diff_conditional(vect.dot(k), z, h1, h2) \ + / (h1 * h2 * h3) + res = vx + vy + vz + if doit: + return res.doit() + return res + else: + if isinstance(vect, (Add, VectorAdd)): + return Add.fromiter(divergence(i, doit=doit) for i in vect.args) + elif isinstance(vect, (Mul, VectorMul)): + vector = [i for i in vect.args if isinstance(i, (Vector, Cross, Gradient))][0] + scalar = Mul.fromiter(i for i in vect.args if not isinstance(i, (Vector, Cross, Gradient))) + res = Dot(vector, gradient(scalar)) + scalar*divergence(vector, doit=doit) + if doit: + return res.doit() + return res + elif isinstance(vect, (Cross, Curl, Gradient)): + return Divergence(vect) + else: + raise ValueError("Invalid argument for divergence") + + +def gradient(scalar_field, doit=True): + """ + Returns the vector gradient of a scalar field computed wrt the + base scalars of the given coordinate system. + + Parameters + ========== + + scalar_field : SymPy Expr + The scalar field to compute the gradient of + + doit : bool + If True, the result is returned after calling .doit() on + each component. Else, the returned expression contains + Derivative instances + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, gradient + >>> R = CoordSys3D('R') + >>> s1 = R.x*R.y*R.z + >>> gradient(s1) + R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k + >>> s2 = 5*R.x**2*R.z + >>> gradient(s2) + 10*R.x*R.z*R.i + 5*R.x**2*R.k + + """ + coord_sys = _get_coord_systems(scalar_field) + + if len(coord_sys) == 0: + return Vector.zero + elif len(coord_sys) == 1: + coord_sys = next(iter(coord_sys)) + h1, h2, h3 = coord_sys.lame_coefficients() + i, j, k = coord_sys.base_vectors() + x, y, z = coord_sys.base_scalars() + vx = Derivative(scalar_field, x) / h1 + vy = Derivative(scalar_field, y) / h2 + vz = Derivative(scalar_field, z) / h3 + + if doit: + return (vx * i + vy * j + vz * k).doit() + return vx * i + vy * j + vz * k + else: + if isinstance(scalar_field, (Add, VectorAdd)): + return VectorAdd.fromiter(gradient(i) for i in scalar_field.args) + if isinstance(scalar_field, (Mul, VectorMul)): + s = _split_mul_args_wrt_coordsys(scalar_field) + return VectorAdd.fromiter(scalar_field / i * gradient(i) for i in s) + return Gradient(scalar_field) + + +class Laplacian(Expr): + """ + Represents unevaluated Laplacian. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Laplacian + >>> R = CoordSys3D('R') + >>> v = 3*R.x**3*R.y**2*R.z**3 + >>> Laplacian(v) + Laplacian(3*R.x**3*R.y**2*R.z**3) + + """ + + def __new__(cls, expr): + expr = sympify(expr) + obj = Expr.__new__(cls, expr) + obj._expr = expr + return obj + + def doit(self, **hints): + from sympy.vector.functions import laplacian + return laplacian(self._expr) + + +def _diff_conditional(expr, base_scalar, coeff_1, coeff_2): + """ + First re-expresses expr in the system that base_scalar belongs to. + If base_scalar appears in the re-expressed form, differentiates + it wrt base_scalar. + Else, returns 0 + """ + from sympy.vector.functions import express + new_expr = express(expr, base_scalar.system, variables=True) + arg = coeff_1 * coeff_2 * new_expr + return Derivative(arg, base_scalar) if arg else S.Zero diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/orienters.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/orienters.py new file mode 100644 index 0000000000000000000000000000000000000000..0c22089e568bc817c943c1beecebde0fea46b6ae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/orienters.py @@ -0,0 +1,398 @@ +from sympy.core.basic import Basic +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.matrices.dense import (eye, rot_axis1, rot_axis2, rot_axis3) +from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix +from sympy.core.cache import cacheit +from sympy.core.symbol import Str +import sympy.vector + + +class Orienter(Basic): + """ + Super-class for all orienter classes. + """ + + def rotation_matrix(self): + """ + The rotation matrix corresponding to this orienter + instance. + """ + return self._parent_orient + + +class AxisOrienter(Orienter): + """ + Class to denote an axis orienter. + """ + + def __new__(cls, angle, axis): + if not isinstance(axis, sympy.vector.Vector): + raise TypeError("axis should be a Vector") + angle = sympify(angle) + + obj = super().__new__(cls, angle, axis) + obj._angle = angle + obj._axis = axis + + return obj + + def __init__(self, angle, axis): + """ + Axis rotation is a rotation about an arbitrary axis by + some angle. The angle is supplied as a SymPy expr scalar, and + the axis is supplied as a Vector. + + Parameters + ========== + + angle : Expr + The angle by which the new system is to be rotated + + axis : Vector + The axis around which the rotation has to be performed + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import symbols + >>> q1 = symbols('q1') + >>> N = CoordSys3D('N') + >>> from sympy.vector import AxisOrienter + >>> orienter = AxisOrienter(q1, N.i + 2 * N.j) + >>> B = N.orient_new('B', (orienter, )) + + """ + # Dummy initializer for docstrings + pass + + @cacheit + def rotation_matrix(self, system): + """ + The rotation matrix corresponding to this orienter + instance. + + Parameters + ========== + + system : CoordSys3D + The coordinate system wrt which the rotation matrix + is to be computed + """ + + axis = sympy.vector.express(self.axis, system).normalize() + axis = axis.to_matrix(system) + theta = self.angle + parent_orient = ((eye(3) - axis * axis.T) * cos(theta) + + Matrix([[0, -axis[2], axis[1]], + [axis[2], 0, -axis[0]], + [-axis[1], axis[0], 0]]) * sin(theta) + + axis * axis.T) + parent_orient = parent_orient.T + return parent_orient + + @property + def angle(self): + return self._angle + + @property + def axis(self): + return self._axis + + +class ThreeAngleOrienter(Orienter): + """ + Super-class for Body and Space orienters. + """ + + def __new__(cls, angle1, angle2, angle3, rot_order): + if isinstance(rot_order, Str): + rot_order = rot_order.name + + approved_orders = ('123', '231', '312', '132', '213', + '321', '121', '131', '212', '232', + '313', '323', '') + original_rot_order = rot_order + rot_order = str(rot_order).upper() + if not (len(rot_order) == 3): + raise TypeError('rot_order should be a str of length 3') + rot_order = [i.replace('X', '1') for i in rot_order] + rot_order = [i.replace('Y', '2') for i in rot_order] + rot_order = [i.replace('Z', '3') for i in rot_order] + rot_order = ''.join(rot_order) + if rot_order not in approved_orders: + raise TypeError('Invalid rot_type parameter') + a1 = int(rot_order[0]) + a2 = int(rot_order[1]) + a3 = int(rot_order[2]) + angle1 = sympify(angle1) + angle2 = sympify(angle2) + angle3 = sympify(angle3) + if cls._in_order: + parent_orient = (_rot(a1, angle1) * + _rot(a2, angle2) * + _rot(a3, angle3)) + else: + parent_orient = (_rot(a3, angle3) * + _rot(a2, angle2) * + _rot(a1, angle1)) + parent_orient = parent_orient.T + + obj = super().__new__( + cls, angle1, angle2, angle3, Str(rot_order)) + obj._angle1 = angle1 + obj._angle2 = angle2 + obj._angle3 = angle3 + obj._rot_order = original_rot_order + obj._parent_orient = parent_orient + + return obj + + @property + def angle1(self): + return self._angle1 + + @property + def angle2(self): + return self._angle2 + + @property + def angle3(self): + return self._angle3 + + @property + def rot_order(self): + return self._rot_order + + +class BodyOrienter(ThreeAngleOrienter): + """ + Class to denote a body-orienter. + """ + + _in_order = True + + def __new__(cls, angle1, angle2, angle3, rot_order): + obj = ThreeAngleOrienter.__new__(cls, angle1, angle2, angle3, + rot_order) + return obj + + def __init__(self, angle1, angle2, angle3, rot_order): + """ + Body orientation takes this coordinate system through three + successive simple rotations. + + Body fixed rotations include both Euler Angles and + Tait-Bryan Angles, see https://en.wikipedia.org/wiki/Euler_angles. + + Parameters + ========== + + angle1, angle2, angle3 : Expr + Three successive angles to rotate the coordinate system by + + rotation_order : string + String defining the order of axes for rotation + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, BodyOrienter + >>> from sympy import symbols + >>> q1, q2, q3 = symbols('q1 q2 q3') + >>> N = CoordSys3D('N') + + A 'Body' fixed rotation is described by three angles and + three body-fixed rotation axes. To orient a coordinate system D + with respect to N, each sequential rotation is always about + the orthogonal unit vectors fixed to D. For example, a '123' + rotation will specify rotations about N.i, then D.j, then + D.k. (Initially, D.i is same as N.i) + Therefore, + + >>> body_orienter = BodyOrienter(q1, q2, q3, '123') + >>> D = N.orient_new('D', (body_orienter, )) + + is same as + + >>> from sympy.vector import AxisOrienter + >>> axis_orienter1 = AxisOrienter(q1, N.i) + >>> D = N.orient_new('D', (axis_orienter1, )) + >>> axis_orienter2 = AxisOrienter(q2, D.j) + >>> D = D.orient_new('D', (axis_orienter2, )) + >>> axis_orienter3 = AxisOrienter(q3, D.k) + >>> D = D.orient_new('D', (axis_orienter3, )) + + Acceptable rotation orders are of length 3, expressed in XYZ or + 123, and cannot have a rotation about about an axis twice in a row. + + >>> body_orienter1 = BodyOrienter(q1, q2, q3, '123') + >>> body_orienter2 = BodyOrienter(q1, q2, 0, 'ZXZ') + >>> body_orienter3 = BodyOrienter(0, 0, 0, 'XYX') + + """ + # Dummy initializer for docstrings + pass + + +class SpaceOrienter(ThreeAngleOrienter): + """ + Class to denote a space-orienter. + """ + + _in_order = False + + def __new__(cls, angle1, angle2, angle3, rot_order): + obj = ThreeAngleOrienter.__new__(cls, angle1, angle2, angle3, + rot_order) + return obj + + def __init__(self, angle1, angle2, angle3, rot_order): + """ + Space rotation is similar to Body rotation, but the rotations + are applied in the opposite order. + + Parameters + ========== + + angle1, angle2, angle3 : Expr + Three successive angles to rotate the coordinate system by + + rotation_order : string + String defining the order of axes for rotation + + See Also + ======== + + BodyOrienter : Orienter to orient systems wrt Euler angles. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, SpaceOrienter + >>> from sympy import symbols + >>> q1, q2, q3 = symbols('q1 q2 q3') + >>> N = CoordSys3D('N') + + To orient a coordinate system D with respect to N, each + sequential rotation is always about N's orthogonal unit vectors. + For example, a '123' rotation will specify rotations about + N.i, then N.j, then N.k. + Therefore, + + >>> space_orienter = SpaceOrienter(q1, q2, q3, '312') + >>> D = N.orient_new('D', (space_orienter, )) + + is same as + + >>> from sympy.vector import AxisOrienter + >>> axis_orienter1 = AxisOrienter(q1, N.i) + >>> B = N.orient_new('B', (axis_orienter1, )) + >>> axis_orienter2 = AxisOrienter(q2, N.j) + >>> C = B.orient_new('C', (axis_orienter2, )) + >>> axis_orienter3 = AxisOrienter(q3, N.k) + >>> D = C.orient_new('C', (axis_orienter3, )) + + """ + # Dummy initializer for docstrings + pass + + +class QuaternionOrienter(Orienter): + """ + Class to denote a quaternion-orienter. + """ + + def __new__(cls, q0, q1, q2, q3): + q0 = sympify(q0) + q1 = sympify(q1) + q2 = sympify(q2) + q3 = sympify(q3) + parent_orient = (Matrix([[q0 ** 2 + q1 ** 2 - q2 ** 2 - + q3 ** 2, + 2 * (q1 * q2 - q0 * q3), + 2 * (q0 * q2 + q1 * q3)], + [2 * (q1 * q2 + q0 * q3), + q0 ** 2 - q1 ** 2 + + q2 ** 2 - q3 ** 2, + 2 * (q2 * q3 - q0 * q1)], + [2 * (q1 * q3 - q0 * q2), + 2 * (q0 * q1 + q2 * q3), + q0 ** 2 - q1 ** 2 - + q2 ** 2 + q3 ** 2]])) + parent_orient = parent_orient.T + + obj = super().__new__(cls, q0, q1, q2, q3) + obj._q0 = q0 + obj._q1 = q1 + obj._q2 = q2 + obj._q3 = q3 + obj._parent_orient = parent_orient + + return obj + + def __init__(self, angle1, angle2, angle3, rot_order): + """ + Quaternion orientation orients the new CoordSys3D with + Quaternions, defined as a finite rotation about lambda, a unit + vector, by some amount theta. + + This orientation is described by four parameters: + + q0 = cos(theta/2) + + q1 = lambda_x sin(theta/2) + + q2 = lambda_y sin(theta/2) + + q3 = lambda_z sin(theta/2) + + Quaternion does not take in a rotation order. + + Parameters + ========== + + q0, q1, q2, q3 : Expr + The quaternions to rotate the coordinate system by + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy import symbols + >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') + >>> N = CoordSys3D('N') + >>> from sympy.vector import QuaternionOrienter + >>> q_orienter = QuaternionOrienter(q0, q1, q2, q3) + >>> B = N.orient_new('B', (q_orienter, )) + + """ + # Dummy initializer for docstrings + pass + + @property + def q0(self): + return self._q0 + + @property + def q1(self): + return self._q1 + + @property + def q2(self): + return self._q2 + + @property + def q3(self): + return self._q3 + + +def _rot(axis, angle): + """DCM for simple axis 1, 2 or 3 rotations. """ + if axis == 1: + return Matrix(rot_axis1(angle).T) + elif axis == 2: + return Matrix(rot_axis2(angle).T) + elif axis == 3: + return Matrix(rot_axis3(angle).T) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/parametricregion.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/parametricregion.py new file mode 100644 index 0000000000000000000000000000000000000000..5246769dabe208fe630f7c33b2da3ef4e11b3f67 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/parametricregion.py @@ -0,0 +1,189 @@ +from functools import singledispatch +from sympy.core.numbers import pi +from sympy.functions.elementary.trigonometric import tan +from sympy.simplify import trigsimp +from sympy.core import Basic, Tuple +from sympy.core.symbol import _symbol +from sympy.solvers import solve +from sympy.geometry import Point, Segment, Curve, Ellipse, Polygon +from sympy.vector import ImplicitRegion + + +class ParametricRegion(Basic): + """ + Represents a parametric region in space. + + Examples + ======== + + >>> from sympy import cos, sin, pi + >>> from sympy.abc import r, theta, t, a, b, x, y + >>> from sympy.vector import ParametricRegion + + >>> ParametricRegion((t, t**2), (t, -1, 2)) + ParametricRegion((t, t**2), (t, -1, 2)) + >>> ParametricRegion((x, y), (x, 3, 4), (y, 5, 6)) + ParametricRegion((x, y), (x, 3, 4), (y, 5, 6)) + >>> ParametricRegion((r*cos(theta), r*sin(theta)), (r, -2, 2), (theta, 0, pi)) + ParametricRegion((r*cos(theta), r*sin(theta)), (r, -2, 2), (theta, 0, pi)) + >>> ParametricRegion((a*cos(t), b*sin(t)), t) + ParametricRegion((a*cos(t), b*sin(t)), t) + + >>> circle = ParametricRegion((r*cos(theta), r*sin(theta)), r, (theta, 0, pi)) + >>> circle.parameters + (r, theta) + >>> circle.definition + (r*cos(theta), r*sin(theta)) + >>> circle.limits + {theta: (0, pi)} + + Dimension of a parametric region determines whether a region is a curve, surface + or volume region. It does not represent its dimensions in space. + + >>> circle.dimensions + 1 + + Parameters + ========== + + definition : tuple to define base scalars in terms of parameters. + + bounds : Parameter or a tuple of length 3 to define parameter and corresponding lower and upper bound. + + """ + def __new__(cls, definition, *bounds): + parameters = () + limits = {} + + if not isinstance(bounds, Tuple): + bounds = Tuple(*bounds) + + for bound in bounds: + if isinstance(bound, (tuple, Tuple)): + if len(bound) != 3: + raise ValueError("Tuple should be in the form (parameter, lowerbound, upperbound)") + parameters += (bound[0],) + limits[bound[0]] = (bound[1], bound[2]) + else: + parameters += (bound,) + + if not isinstance(definition, (tuple, Tuple)): + definition = (definition,) + + obj = super().__new__(cls, Tuple(*definition), *bounds) + obj._parameters = parameters + obj._limits = limits + + return obj + + @property + def definition(self): + return self.args[0] + + @property + def limits(self): + return self._limits + + @property + def parameters(self): + return self._parameters + + @property + def dimensions(self): + return len(self.limits) + + +@singledispatch +def parametric_region_list(reg): + """ + Returns a list of ParametricRegion objects representing the geometric region. + + Examples + ======== + + >>> from sympy.abc import t + >>> from sympy.vector import parametric_region_list + >>> from sympy.geometry import Point, Curve, Ellipse, Segment, Polygon + + >>> p = Point(2, 5) + >>> parametric_region_list(p) + [ParametricRegion((2, 5))] + + >>> c = Curve((t**3, 4*t), (t, -3, 4)) + >>> parametric_region_list(c) + [ParametricRegion((t**3, 4*t), (t, -3, 4))] + + >>> e = Ellipse(Point(1, 3), 2, 3) + >>> parametric_region_list(e) + [ParametricRegion((2*cos(t) + 1, 3*sin(t) + 3), (t, 0, 2*pi))] + + >>> s = Segment(Point(1, 3), Point(2, 6)) + >>> parametric_region_list(s) + [ParametricRegion((t + 1, 3*t + 3), (t, 0, 1))] + + >>> p1, p2, p3, p4 = [(0, 1), (2, -3), (5, 3), (-2, 3)] + >>> poly = Polygon(p1, p2, p3, p4) + >>> parametric_region_list(poly) + [ParametricRegion((2*t, 1 - 4*t), (t, 0, 1)), ParametricRegion((3*t + 2, 6*t - 3), (t, 0, 1)),\ + ParametricRegion((5 - 7*t, 3), (t, 0, 1)), ParametricRegion((2*t - 2, 3 - 2*t), (t, 0, 1))] + + """ + raise ValueError("SymPy cannot determine parametric representation of the region.") + + +@parametric_region_list.register(Point) +def _(obj): + return [ParametricRegion(obj.args)] + + +@parametric_region_list.register(Curve) # type: ignore +def _(obj): + definition = obj.arbitrary_point(obj.parameter).args + bounds = obj.limits + return [ParametricRegion(definition, bounds)] + + +@parametric_region_list.register(Ellipse) # type: ignore +def _(obj, parameter='t'): + definition = obj.arbitrary_point(parameter).args + t = _symbol(parameter, real=True) + bounds = (t, 0, 2*pi) + return [ParametricRegion(definition, bounds)] + + +@parametric_region_list.register(Segment) # type: ignore +def _(obj, parameter='t'): + t = _symbol(parameter, real=True) + definition = obj.arbitrary_point(t).args + + for i in range(0, 3): + lower_bound = solve(definition[i] - obj.points[0].args[i], t) + upper_bound = solve(definition[i] - obj.points[1].args[i], t) + + if len(lower_bound) == 1 and len(upper_bound) == 1: + bounds = t, lower_bound[0], upper_bound[0] + break + + definition_tuple = obj.arbitrary_point(parameter).args + return [ParametricRegion(definition_tuple, bounds)] + + +@parametric_region_list.register(Polygon) # type: ignore +def _(obj, parameter='t'): + l = [parametric_region_list(side, parameter)[0] for side in obj.sides] + return l + + +@parametric_region_list.register(ImplicitRegion) # type: ignore +def _(obj, parameters=('t', 's')): + definition = obj.rational_parametrization(parameters) + bounds = [] + + for i in range(len(obj.variables) - 1): + # Each parameter is replaced by its tangent to simplify integration + parameter = _symbol(parameters[i], real=True) + definition = [trigsimp(elem.subs(parameter, tan(parameter/2))) for elem in definition] + bounds.append((parameter, 0, 2*pi),) + + definition = Tuple(*definition) + return [ParametricRegion(definition, *bounds)] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/point.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/point.py new file mode 100644 index 0000000000000000000000000000000000000000..442ea4e8edc0e33c4f83f774ea3f11a01725ac3a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/point.py @@ -0,0 +1,148 @@ +from sympy.core.basic import Basic +from sympy.core.symbol import Str +from sympy.vector.vector import Vector +from sympy.vector.coordsysrect import CoordSys3D +from sympy.vector.functions import _path +from sympy.core.cache import cacheit + + +class Point(Basic): + """ + Represents a point in 3-D space. + """ + + def __new__(cls, name, position=Vector.zero, parent_point=None): + name = str(name) + # Check the args first + if not isinstance(position, Vector): + raise TypeError( + "position should be an instance of Vector, not %s" % type( + position)) + if (not isinstance(parent_point, Point) and + parent_point is not None): + raise TypeError( + "parent_point should be an instance of Point, not %s" % type( + parent_point)) + # Super class construction + if parent_point is None: + obj = super().__new__(cls, Str(name), position) + else: + obj = super().__new__(cls, Str(name), position, parent_point) + # Decide the object parameters + obj._name = name + obj._pos = position + if parent_point is None: + obj._parent = None + obj._root = obj + else: + obj._parent = parent_point + obj._root = parent_point._root + # Return object + return obj + + @cacheit + def position_wrt(self, other): + """ + Returns the position vector of this Point with respect to + another Point/CoordSys3D. + + Parameters + ========== + + other : Point/CoordSys3D + If other is a Point, the position of this Point wrt it is + returned. If its an instance of CoordSyRect, the position + wrt its origin is returned. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> N = CoordSys3D('N') + >>> p1 = N.origin.locate_new('p1', 10 * N.i) + >>> N.origin.position_wrt(p1) + (-10)*N.i + + """ + + if (not isinstance(other, Point) and + not isinstance(other, CoordSys3D)): + raise TypeError(str(other) + + "is not a Point or CoordSys3D") + if isinstance(other, CoordSys3D): + other = other.origin + # Handle special cases + if other == self: + return Vector.zero + elif other == self._parent: + return self._pos + elif other._parent == self: + return -1 * other._pos + # Else, use point tree to calculate position + rootindex, path = _path(self, other) + result = Vector.zero + for i in range(rootindex): + result += path[i]._pos + for i in range(rootindex + 1, len(path)): + result -= path[i]._pos + return result + + def locate_new(self, name, position): + """ + Returns a new Point located at the given position wrt this + Point. + Thus, the position vector of the new Point wrt this one will + be equal to the given 'position' parameter. + + Parameters + ========== + + name : str + Name of the new point + + position : Vector + The position vector of the new Point wrt this one + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> N = CoordSys3D('N') + >>> p1 = N.origin.locate_new('p1', 10 * N.i) + >>> p1.position_wrt(N.origin) + 10*N.i + + """ + return Point(name, position, self) + + def express_coordinates(self, coordinate_system): + """ + Returns the Cartesian/rectangular coordinates of this point + wrt the origin of the given CoordSys3D instance. + + Parameters + ========== + + coordinate_system : CoordSys3D + The coordinate system to express the coordinates of this + Point in. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> N = CoordSys3D('N') + >>> p1 = N.origin.locate_new('p1', 10 * N.i) + >>> p2 = p1.locate_new('p2', 5 * N.j) + >>> p2.express_coordinates(N) + (10, 5, 0) + + """ + + # Determine the position vector + pos_vect = self.position_wrt(coordinate_system.origin) + # Express it in the given coordinate system + return tuple(pos_vect.to_matrix(coordinate_system)) + + def _sympystr(self, printer): + return self._name diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/scalar.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/scalar.py new file mode 100644 index 0000000000000000000000000000000000000000..bcfb56cf177b9378a24f81ca1e6524fe048a5f94 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/scalar.py @@ -0,0 +1,72 @@ +from sympy.core import AtomicExpr, Symbol, S +from sympy.core.sympify import _sympify +from sympy.printing.pretty.stringpict import prettyForm +from sympy.printing.precedence import PRECEDENCE +from sympy.core.kind import NumberKind + + +class BaseScalar(AtomicExpr): + """ + A coordinate symbol/base scalar. + + Ideally, users should not instantiate this class. + + """ + + kind = NumberKind + + def __new__(cls, index, system, pretty_str=None, latex_str=None): + from sympy.vector.coordsysrect import CoordSys3D + if pretty_str is None: + pretty_str = "x{}".format(index) + elif isinstance(pretty_str, Symbol): + pretty_str = pretty_str.name + if latex_str is None: + latex_str = "x_{}".format(index) + elif isinstance(latex_str, Symbol): + latex_str = latex_str.name + + index = _sympify(index) + system = _sympify(system) + obj = super().__new__(cls, index, system) + if not isinstance(system, CoordSys3D): + raise TypeError("system should be a CoordSys3D") + if index not in range(0, 3): + raise ValueError("Invalid index specified.") + # The _id is used for equating purposes, and for hashing + obj._id = (index, system) + obj._name = obj.name = system._name + '.' + system._variable_names[index] + obj._pretty_form = '' + pretty_str + obj._latex_form = latex_str + obj._system = system + + return obj + + is_commutative = True + is_symbol = True + + @property + def free_symbols(self): + return {self} + + _diff_wrt = True + + def _eval_derivative(self, s): + if self == s: + return S.One + return S.Zero + + def _latex(self, printer=None): + return self._latex_form + + def _pretty(self, printer=None): + return prettyForm(self._pretty_form) + + precedence = PRECEDENCE['Atom'] + + @property + def system(self): + return self._system + + def _sympystr(self, printer): + return self._name diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/vector.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/vector.py new file mode 100644 index 0000000000000000000000000000000000000000..c035ef48d2edd511f6cdbca19e965d99a2c8c66e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/vector/vector.py @@ -0,0 +1,714 @@ +from __future__ import annotations +from itertools import product + +from sympy.core import Add, Basic +from sympy.core.assumptions import StdFactKB +from sympy.core.expr import AtomicExpr, Expr +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import sympify +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix +from sympy.vector.basisdependent import (BasisDependentZero, + BasisDependent, BasisDependentMul, BasisDependentAdd) +from sympy.vector.coordsysrect import CoordSys3D +from sympy.vector.dyadic import Dyadic, BaseDyadic, DyadicAdd +from sympy.vector.kind import VectorKind + + +class Vector(BasisDependent): + """ + Super class for all Vector classes. + Ideally, neither this class nor any of its subclasses should be + instantiated by the user. + """ + + is_scalar = False + is_Vector = True + _op_priority = 12.0 + + _expr_type: type[Vector] + _mul_func: type[Vector] + _add_func: type[Vector] + _zero_func: type[Vector] + _base_func: type[Vector] + zero: VectorZero + + kind: VectorKind = VectorKind() + + @property + def components(self): + """ + Returns the components of this vector in the form of a + Python dictionary mapping BaseVector instances to the + corresponding measure numbers. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> C = CoordSys3D('C') + >>> v = 3*C.i + 4*C.j + 5*C.k + >>> v.components + {C.i: 3, C.j: 4, C.k: 5} + + """ + # The '_components' attribute is defined according to the + # subclass of Vector the instance belongs to. + return self._components + + def magnitude(self): + """ + Returns the magnitude of this vector. + """ + return sqrt(self & self) + + def normalize(self): + """ + Returns the normalized version of this vector. + """ + return self / self.magnitude() + + def equals(self, other): + """ + Check if ``self`` and ``other`` are identically equal vectors. + + Explanation + =========== + + Checks if two vector expressions are equal for all possible values of + the symbols present in the expressions. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy.abc import x, y + >>> from sympy import pi + >>> C = CoordSys3D('C') + + Compare vectors that are equal or not: + + >>> C.i.equals(C.j) + False + >>> C.i.equals(C.i) + True + + These two vectors are equal if `x = y` but are not identically equal + as expressions since for some values of `x` and `y` they are unequal: + + >>> v1 = x*C.i + C.j + >>> v2 = y*C.i + C.j + >>> v1.equals(v1) + True + >>> v1.equals(v2) + False + + Vectors from different coordinate systems can be compared: + + >>> D = C.orient_new_axis('D', pi/2, C.i) + >>> D.j.equals(C.j) + False + >>> D.j.equals(C.k) + True + + Parameters + ========== + + other: Vector + The other vector expression to compare with. + + Returns + ======= + + ``True``, ``False`` or ``None``. A return value of ``True`` indicates + that the two vectors are identically equal. A return value of ``False`` + indicates that they are not. In some cases it is not possible to + determine if the two vectors are identically equal and ``None`` is + returned. + + See Also + ======== + + sympy.core.expr.Expr.equals + """ + diff = self - other + diff_mag2 = diff.dot(diff) + return diff_mag2.equals(0) + + def dot(self, other): + """ + Returns the dot product of this Vector, either with another + Vector, or a Dyadic, or a Del operator. + If 'other' is a Vector, returns the dot product scalar (SymPy + expression). + If 'other' is a Dyadic, the dot product is returned as a Vector. + If 'other' is an instance of Del, returns the directional + derivative operator as a Python function. If this function is + applied to a scalar expression, it returns the directional + derivative of the scalar field wrt this Vector. + + Parameters + ========== + + other: Vector/Dyadic/Del + The Vector or Dyadic we are dotting with, or a Del operator . + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Del + >>> C = CoordSys3D('C') + >>> delop = Del() + >>> C.i.dot(C.j) + 0 + >>> C.i & C.i + 1 + >>> v = 3*C.i + 4*C.j + 5*C.k + >>> v.dot(C.k) + 5 + >>> (C.i & delop)(C.x*C.y*C.z) + C.y*C.z + >>> d = C.i.outer(C.i) + >>> C.i.dot(d) + C.i + + """ + + # Check special cases + if isinstance(other, Dyadic): + if isinstance(self, VectorZero): + return Vector.zero + outvec = Vector.zero + for k, v in other.components.items(): + vect_dot = k.args[0].dot(self) + outvec += vect_dot * v * k.args[1] + return outvec + from sympy.vector.deloperator import Del + if not isinstance(other, (Del, Vector)): + raise TypeError(str(other) + " is not a vector, dyadic or " + + "del operator") + + # Check if the other is a del operator + if isinstance(other, Del): + def directional_derivative(field): + from sympy.vector.functions import directional_derivative + return directional_derivative(field, self) + return directional_derivative + + return dot(self, other) + + def __and__(self, other): + return self.dot(other) + + __and__.__doc__ = dot.__doc__ + + def cross(self, other): + """ + Returns the cross product of this Vector with another Vector or + Dyadic instance. + The cross product is a Vector, if 'other' is a Vector. If 'other' + is a Dyadic, this returns a Dyadic instance. + + Parameters + ========== + + other: Vector/Dyadic + The Vector or Dyadic we are crossing with. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> C = CoordSys3D('C') + >>> C.i.cross(C.j) + C.k + >>> C.i ^ C.i + 0 + >>> v = 3*C.i + 4*C.j + 5*C.k + >>> v ^ C.i + 5*C.j + (-4)*C.k + >>> d = C.i.outer(C.i) + >>> C.j.cross(d) + (-1)*(C.k|C.i) + + """ + + # Check special cases + if isinstance(other, Dyadic): + if isinstance(self, VectorZero): + return Dyadic.zero + outdyad = Dyadic.zero + for k, v in other.components.items(): + cross_product = self.cross(k.args[0]) + outer = cross_product.outer(k.args[1]) + outdyad += v * outer + return outdyad + + return cross(self, other) + + def __xor__(self, other): + return self.cross(other) + + __xor__.__doc__ = cross.__doc__ + + def outer(self, other): + """ + Returns the outer product of this vector with another, in the + form of a Dyadic instance. + + Parameters + ========== + + other : Vector + The Vector with respect to which the outer product is to + be computed. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> N = CoordSys3D('N') + >>> N.i.outer(N.j) + (N.i|N.j) + + """ + + # Handle the special cases + if not isinstance(other, Vector): + raise TypeError("Invalid operand for outer product") + elif (isinstance(self, VectorZero) or + isinstance(other, VectorZero)): + return Dyadic.zero + + # Iterate over components of both the vectors to generate + # the required Dyadic instance + args = [(v1 * v2) * BaseDyadic(k1, k2) for (k1, v1), (k2, v2) + in product(self.components.items(), other.components.items())] + + return DyadicAdd(*args) + + def projection(self, other, scalar=False): + """ + Returns the vector or scalar projection of the 'other' on 'self'. + + Examples + ======== + + >>> from sympy.vector.coordsysrect import CoordSys3D + >>> C = CoordSys3D('C') + >>> i, j, k = C.base_vectors() + >>> v1 = i + j + k + >>> v2 = 3*i + 4*j + >>> v1.projection(v2) + 7/3*C.i + 7/3*C.j + 7/3*C.k + >>> v1.projection(v2, scalar=True) + 7/3 + + """ + if self.equals(Vector.zero): + return S.Zero if scalar else Vector.zero + + if scalar: + return self.dot(other) / self.dot(self) + else: + return self.dot(other) / self.dot(self) * self + + @property + def _projections(self): + """ + Returns the components of this vector but the output includes + also zero values components. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Vector + >>> C = CoordSys3D('C') + >>> v1 = 3*C.i + 4*C.j + 5*C.k + >>> v1._projections + (3, 4, 5) + >>> v2 = C.x*C.y*C.z*C.i + >>> v2._projections + (C.x*C.y*C.z, 0, 0) + >>> v3 = Vector.zero + >>> v3._projections + (0, 0, 0) + """ + + from sympy.vector.operators import _get_coord_systems + if isinstance(self, VectorZero): + return (S.Zero, S.Zero, S.Zero) + base_vec = next(iter(_get_coord_systems(self))).base_vectors() + return tuple([self.dot(i) for i in base_vec]) + + def __or__(self, other): + return self.outer(other) + + __or__.__doc__ = outer.__doc__ + + def to_matrix(self, system): + """ + Returns the matrix form of this vector with respect to the + specified coordinate system. + + Parameters + ========== + + system : CoordSys3D + The system wrt which the matrix form is to be computed + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> C = CoordSys3D('C') + >>> from sympy.abc import a, b, c + >>> v = a*C.i + b*C.j + c*C.k + >>> v.to_matrix(C) + Matrix([ + [a], + [b], + [c]]) + + """ + + return Matrix([self.dot(unit_vec) for unit_vec in + system.base_vectors()]) + + def separate(self): + """ + The constituents of this vector in different coordinate systems, + as per its definition. + + Returns a dict mapping each CoordSys3D to the corresponding + constituent Vector. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> R1 = CoordSys3D('R1') + >>> R2 = CoordSys3D('R2') + >>> v = R1.i + R2.i + >>> v.separate() == {R1: R1.i, R2: R2.i} + True + + """ + + parts = {} + for vect, measure in self.components.items(): + parts[vect.system] = (parts.get(vect.system, Vector.zero) + + vect * measure) + return parts + + def _div_helper(one, other): + """ Helper for division involving vectors. """ + if isinstance(one, Vector) and isinstance(other, Vector): + raise TypeError("Cannot divide two vectors") + elif isinstance(one, Vector): + if other == S.Zero: + raise ValueError("Cannot divide a vector by zero") + return VectorMul(one, Pow(other, S.NegativeOne)) + else: + raise TypeError("Invalid division involving a vector") + +# The following is adapted from the matrices.expressions.matexpr file + +def get_postprocessor(cls): + def _postprocessor(expr): + vec_class = {Add: VectorAdd}[cls] + vectors = [] + for term in expr.args: + if isinstance(term.kind, VectorKind): + vectors.append(term) + + if vec_class == VectorAdd: + return VectorAdd(*vectors).doit(deep=False) + return _postprocessor + + +Basic._constructor_postprocessor_mapping[Vector] = { + "Add": [get_postprocessor(Add)], +} + +class BaseVector(Vector, AtomicExpr): + """ + Class to denote a base vector. + + """ + + def __new__(cls, index, system, pretty_str=None, latex_str=None): + if pretty_str is None: + pretty_str = "x{}".format(index) + if latex_str is None: + latex_str = "x_{}".format(index) + pretty_str = str(pretty_str) + latex_str = str(latex_str) + # Verify arguments + if index not in range(0, 3): + raise ValueError("index must be 0, 1 or 2") + if not isinstance(system, CoordSys3D): + raise TypeError("system should be a CoordSys3D") + name = system._vector_names[index] + # Initialize an object + obj = super().__new__(cls, S(index), system) + # Assign important attributes + obj._base_instance = obj + obj._components = {obj: S.One} + obj._measure_number = S.One + obj._name = system._name + '.' + name + obj._pretty_form = '' + pretty_str + obj._latex_form = latex_str + obj._system = system + # The _id is used for printing purposes + obj._id = (index, system) + assumptions = {'commutative': True} + obj._assumptions = StdFactKB(assumptions) + + # This attr is used for re-expression to one of the systems + # involved in the definition of the Vector. Applies to + # VectorMul and VectorAdd too. + obj._sys = system + + return obj + + @property + def system(self): + return self._system + + def _sympystr(self, printer): + return self._name + + def _sympyrepr(self, printer): + index, system = self._id + return printer._print(system) + '.' + system._vector_names[index] + + @property + def free_symbols(self): + return {self} + + def _eval_conjugate(self): + return self + + +class VectorAdd(BasisDependentAdd, Vector): + """ + Class to denote sum of Vector instances. + """ + + def __new__(cls, *args, **options): + obj = BasisDependentAdd.__new__(cls, *args, **options) + return obj + + def _sympystr(self, printer): + ret_str = '' + items = list(self.separate().items()) + items.sort(key=lambda x: x[0].__str__()) + for system, vect in items: + base_vects = system.base_vectors() + for x in base_vects: + if x in vect.components: + temp_vect = self.components[x] * x + ret_str += printer._print(temp_vect) + " + " + return ret_str[:-3] + + +class VectorMul(BasisDependentMul, Vector): + """ + Class to denote products of scalars and BaseVectors. + """ + + def __new__(cls, *args, **options): + obj = BasisDependentMul.__new__(cls, *args, **options) + return obj + + @property + def base_vector(self): + """ The BaseVector involved in the product. """ + return self._base_instance + + @property + def measure_number(self): + """ The scalar expression involved in the definition of + this VectorMul. + """ + return self._measure_number + + +class VectorZero(BasisDependentZero, Vector): + """ + Class to denote a zero vector + """ + + _op_priority = 12.1 + _pretty_form = '0' + _latex_form = r'\mathbf{\hat{0}}' + + def __new__(cls): + obj = BasisDependentZero.__new__(cls) + return obj + + +class Cross(Vector): + """ + Represents unevaluated Cross product. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Cross + >>> R = CoordSys3D('R') + >>> v1 = R.i + R.j + R.k + >>> v2 = R.x * R.i + R.y * R.j + R.z * R.k + >>> Cross(v1, v2) + Cross(R.i + R.j + R.k, R.x*R.i + R.y*R.j + R.z*R.k) + >>> Cross(v1, v2).doit() + (-R.y + R.z)*R.i + (R.x - R.z)*R.j + (-R.x + R.y)*R.k + + """ + + def __new__(cls, expr1, expr2): + expr1 = sympify(expr1) + expr2 = sympify(expr2) + if default_sort_key(expr1) > default_sort_key(expr2): + return -Cross(expr2, expr1) + obj = Expr.__new__(cls, expr1, expr2) + obj._expr1 = expr1 + obj._expr2 = expr2 + return obj + + def doit(self, **hints): + return cross(self._expr1, self._expr2) + + +class Dot(Expr): + """ + Represents unevaluated Dot product. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D, Dot + >>> from sympy import symbols + >>> R = CoordSys3D('R') + >>> a, b, c = symbols('a b c') + >>> v1 = R.i + R.j + R.k + >>> v2 = a * R.i + b * R.j + c * R.k + >>> Dot(v1, v2) + Dot(R.i + R.j + R.k, a*R.i + b*R.j + c*R.k) + >>> Dot(v1, v2).doit() + a + b + c + + """ + + def __new__(cls, expr1, expr2): + expr1 = sympify(expr1) + expr2 = sympify(expr2) + expr1, expr2 = sorted([expr1, expr2], key=default_sort_key) + obj = Expr.__new__(cls, expr1, expr2) + obj._expr1 = expr1 + obj._expr2 = expr2 + return obj + + def doit(self, **hints): + return dot(self._expr1, self._expr2) + + +def cross(vect1, vect2): + """ + Returns cross product of two vectors. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy.vector.vector import cross + >>> R = CoordSys3D('R') + >>> v1 = R.i + R.j + R.k + >>> v2 = R.x * R.i + R.y * R.j + R.z * R.k + >>> cross(v1, v2) + (-R.y + R.z)*R.i + (R.x - R.z)*R.j + (-R.x + R.y)*R.k + + """ + if isinstance(vect1, Add): + return VectorAdd.fromiter(cross(i, vect2) for i in vect1.args) + if isinstance(vect2, Add): + return VectorAdd.fromiter(cross(vect1, i) for i in vect2.args) + if isinstance(vect1, BaseVector) and isinstance(vect2, BaseVector): + if vect1._sys == vect2._sys: + n1 = vect1.args[0] + n2 = vect2.args[0] + if n1 == n2: + return Vector.zero + n3 = ({0,1,2}.difference({n1, n2})).pop() + sign = 1 if ((n1 + 1) % 3 == n2) else -1 + return sign*vect1._sys.base_vectors()[n3] + from .functions import express + try: + v = express(vect1, vect2._sys) + except ValueError: + return Cross(vect1, vect2) + else: + return cross(v, vect2) + if isinstance(vect1, VectorZero) or isinstance(vect2, VectorZero): + return Vector.zero + if isinstance(vect1, VectorMul): + v1, m1 = next(iter(vect1.components.items())) + return m1*cross(v1, vect2) + if isinstance(vect2, VectorMul): + v2, m2 = next(iter(vect2.components.items())) + return m2*cross(vect1, v2) + + return Cross(vect1, vect2) + + +def dot(vect1, vect2): + """ + Returns dot product of two vectors. + + Examples + ======== + + >>> from sympy.vector import CoordSys3D + >>> from sympy.vector.vector import dot + >>> R = CoordSys3D('R') + >>> v1 = R.i + R.j + R.k + >>> v2 = R.x * R.i + R.y * R.j + R.z * R.k + >>> dot(v1, v2) + R.x + R.y + R.z + + """ + if isinstance(vect1, Add): + return Add.fromiter(dot(i, vect2) for i in vect1.args) + if isinstance(vect2, Add): + return Add.fromiter(dot(vect1, i) for i in vect2.args) + if isinstance(vect1, BaseVector) and isinstance(vect2, BaseVector): + if vect1._sys == vect2._sys: + return S.One if vect1 == vect2 else S.Zero + from .functions import express + try: + v = express(vect2, vect1._sys) + except ValueError: + return Dot(vect1, vect2) + else: + return dot(vect1, v) + if isinstance(vect1, VectorZero) or isinstance(vect2, VectorZero): + return S.Zero + if isinstance(vect1, VectorMul): + v1, m1 = next(iter(vect1.components.items())) + return m1*dot(v1, vect2) + if isinstance(vect2, VectorMul): + v2, m2 = next(iter(vect2.components.items())) + return m2*dot(vect1, v2) + + return Dot(vect1, vect2) + + +Vector._expr_type = Vector +Vector._mul_func = VectorMul +Vector._add_func = VectorAdd +Vector._zero_func = VectorZero +Vector._base_func = BaseVector +Vector.zero = VectorZero()